[
  {
    "path": ".angulardoc.json",
    "content": "{\n  \"repoId\": \"8f466ce7-4b75-4048-8b8a-cad5bf173aa0\",\n  \"lastSync\": 0\n}"
  },
  {
    "path": ".earthlyignore",
    "content": "# Ignore angular outputs.\ndesktop/angular/node_modules\ndesktop/angular/dist\ndesktop/angular/dist-lib\ndesktop/angular/dist-extension\ndesktop/angular/.angular\n\n# Ignore tauri outputs.\ndesktop/tauri/src-tauri/target\n\n#######################\n# Copy from .gitignore:\n\n# Compiled binaries\n# *.exe\n# dist/\n\n# Dist dir\n# dist\n\n# Custom dev deops\ngo.mod.*\n\n# vendor dir\nvendor\n\n# testing\ntesting\nspn/testing/simple/testdata\n\n# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# OS specifics\n.DS_Store\n\n# Custom dev scripts\nwin_dev_*\ngo.work\ngo.work.sum\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Treat all Go files in this repo as binary, with no git magic updating\n# line endings. Windows users contributing to Go will need to use a\n# modern version of git and editors capable of LF line endings.\n\n*.go -text diff=golang\n\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: safing\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": " \n# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser\nblank_issues_enabled: true  # default: true\ncontact_links:\n\n- name: \"Ask Questions on Discord\"\n  url: https://safing.io/discord\n  about: Get help from our great community\n\n- name: \"Wiki and FAQ\"\n  url: https://wiki.safing.io/\n  about: Learn more about Portmaster in our Wiki\n\n- name: \"Contribution Guideline\"\n  url: https://docs.safing.io/portmaster/guides/contribute\n  about: Learn how to best contribute and make sure your work is aligned with Safing’s current goals and focus\n\n- name: \"Code of Conduct\"\n  url: https://docs.safing.io/community/code-of-conduct\n  about: Be nice to other community members\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/report-bug.md",
    "content": "---\nname: \"🐞 Report a Bug\"\nabout: Report a bug encountered while using the Portmaster\nlabels: bug\n---\n\n<!--\nPlease disclose security related issues privately to support@safing.io.\n-->\n\n**Pre-Submit Checklist**:\n\n- Check applicable sources for existing issues:\n  - [Windows Known Issues](https://docs.safing.io/portmaster/install/windows#known-issues)\n  - [Linux Known Issues](https://docs.safing.io/portmaster/install/linux#compatibility)\n  - [Github Issues](https://github.com/safing/portmaster/issues?q=is%3Aissue+label%3Abug)\n\n**What happened**:\n\n\n\n**What did you expect to happen?**:\n\n\n\n**How did you reproduce it?**:\n\n\n\n**Debug Information**:\n\n<!--\nPaste debug information below:\n- General issue: Click on \"Copy Debug Information\" on the Settings page.\n- App related issue: Click on \"Copy Debug Information\" in the dropdown menu of an app in the Monitor view.\n\n⚠ Please remove sensitive/private information from the \"Unexpected Logs\" and \"Network Connections\" sections.\nThis is easiest to do in the preview mode.\n\nAdditional logs can be found here:\n- Linux: `/var/lib/portmaster/log`\n- Windows: `%PROGRAMDATA%\\Portmaster\\logs`\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/report-compatibility.md",
    "content": "---\nname: \"📝 Make a Compatibility Report\"\nabout: Report Portmaster in/compatibility with Linux Distros, VPN Clients or general Software\nlabels: \"in/compatibility\"\n---\n\n**Pre-Submit Checklist**:\n\n- Check applicable sources for existing issues:\n  - [Linux Compatibility](https://docs.safing.io/portmaster/install/linux#compatibility)\n  - [VPN Compatibility](https://docs.safing.io/portmaster/install/status/vpn-compatibility)\n  - [Github Issues](https://github.com/safing/portmaster/issues?q=is%3Aissue+label%3Ain%2Fcompatibility)\n\n**What worked?**\n\n\n\n**What did not work?**\n\n\n\n**Debug Information**:\n\n<!--\nPaste debug information below if reporting a problem:\n- General issue: Click on \"Copy Debug Information\" on the Settings page.\n- App related issue: Click on \"Copy Debug Information\" in the dropdown menu of an app in the Monitor view.\n\n⚠ Please remove sensitive/private information from the \"Unexpected Logs\" and \"Network Connections\" sections.\nThis is easiest to do in the preview mode.\n\nIf needed, additional logs can be found here:\n- Linux: `/var/lib/portmaster/log`\n- Windows: `%PROGRAMDATA%\\Portmaster\\logs`\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/suggest-feature.md",
    "content": "---\nname: \"💡 Suggest an Improvement or Feature\"\nabout: Suggest an enhancement or a new feature for the Portmaster\nlabels: suggestion\n---\n\n**What would you like to add or change?**:\n\n\n\n**Why do you and others need this?**:\n\n\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"gomod\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n\n  - package-ecosystem: \"npm\"\n    directory: \"/desktop/angular\"\n    schedule:\n      interval: \"daily\"\n\n  - package-ecosystem: \"cargo\"\n    directory: \"/desktop/tauri\"\n    schedule:\n      interval: \"daily\""
  },
  {
    "path": ".github/label-actions.yml",
    "content": "# Configuration for Label Actions - https://github.com/dessant/label-actions\n\ncommunity support:\n  comment: |\n    Hey @{issue-author}, thank you for raising this issue with us.\n\n    After a first review we noticed that this does not seem to be a technical issue, but rather a configuration issue or general question about how Portmaster works.\n\n    Thus, we invite the community to help with configuration and/or answering this questions.\n\n    If you are in a hurry or haven't received an answer, a good place to ask is in [our Discord community](https://discord.gg/safing).\n\n    If your problem or question has been resolved or answered, please come back and give an update here for other users encountering the same and then close this issue.\n\n    If you are a paying subscriber and want this issue to be checked out by Safing, please send us a message [on Discord](https://discord.gg/safing) or [via Email](mailto:support@safing.io) with your username and the link to this issue, so we can prioritize accordingly.\n\nneeds debug info:\n  comment: |\n    Hey @{issue-author}, thank you for raising this issue with us.\n\n    After a first review we noticed that we will require the Debug Info for further investigation. However, you haven't supplied any Debug Info in your report.\n\n    Please [collect Debug Info](https://wiki.safing.io/en/FAQ/DebugInfo) from Portmaster _while_ the reported issue is present.\n\nin/compatibility:\n  comment: |\n    Hey @{issue-author}, thank you for reporting on a compatibility.\n\n    We keep a list of compatible software and user provided guides for improving compatibility [in the wiki - please have a look there](https://wiki.safing.io/en/Portmaster/App/Compatibility).\n    If you can't find your software in the list, then a good starting point is our guide on [How do I make software compatible with Portmaster](https://wiki.safing.io/en/FAQ/MakeSoftwareCompatibleWithPortmaster).\n\n    If you have managed to establish compatibility with an application, please share your findings here. This will greatly help other users encountering the same issues.\n\nfixed:\n  comment: |\n    This issue has been fixed by the recently referenced commit or PR.\n\n    However, the fix is not released yet.\n    \n    It is expected to go into the [Beta Release Channel](https://wiki.safing.io/en/FAQ/SwitchReleaseChannel) for testing within the next two weeks and will be available for everyone within the next four weeks. While this is the typical timeline we work with, things are subject to change.\n"
  },
  {
    "path": ".github/workflows/angular.yml",
    "content": "name: Angular\n\non:\n  push:\n    paths:\n      - 'desktop/angular/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\n  pull_request:\n    paths:\n      - 'desktop/angular/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\njobs:\n  lint:\n    name: Lint\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: desktop/angular\n\n    steps:\n    - name: Check out code\n      uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3\n      with:\n        node-version: 18\n\n    - run: npm install\n\n    - uses: sibiraj-s/action-eslint@bcf41bb9abce43cdbad51ab9b3da2eddaa17eab3 # v3\n      with:\n        annotations: true\n        extensions: 'ts,html'\n        working-directory: desktop/angular\n\n  test:\n    name: Build\n    runs-on: ubuntu-latest\n    steps:\n    - uses: earthly/actions-setup@43211c7a0eae5344d6d79fb4aaf209c8f8866203 # v1\n      with:\n        version: v0.8.0\n    - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Log in to the Container registry\n      uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Build angular projects\n      run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +angular-ci\n"
  },
  {
    "path": ".github/workflows/go.yml",
    "content": "name: Go\n\non:\n  push:\n    paths:\n      - '**.go'\n      - 'cmds/**'\n      - 'runtime/**'\n      - 'service/**'\n      - 'spn/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\n  pull_request:\n    paths:\n      - '**.go'\n      - 'cmds/**'\n      - 'runtime/**'\n      - 'service/**'\n      - 'spn/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\njobs:\n  lint:\n    name: Linter\n    runs-on: ubuntu-latest\n    steps:\n    - name: Check out code\n      uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Setup Go\n      uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5\n      with:\n        go-version: '^1.21'\n        cache: false\n\n    - name: Run golangci-lint\n      uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6\n      with:\n        version: v1.64.6\n        only-new-issues: true\n        args: -c ./.golangci.yml --timeout 15m\n\n    - name: Run go vet\n      run: go vet ./...\n\n  test:\n    name: Test & Build\n    runs-on: ubuntu-latest\n    steps:\n    - uses: earthly/actions-setup@43211c7a0eae5344d6d79fb4aaf209c8f8866203 # v1\n      with:\n        version: v0.8.0\n    - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Log in to the Container registry\n      uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Run Go Tests & Build\n      run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +go-ci\n"
  },
  {
    "path": ".github/workflows/issues-first-greet.yml",
    "content": "# This workflow responds to first time posters with a greeting message.\n# Docs: https://github.com/actions/first-interaction\nname: Greet New Users\n\n# This workflow is triggered when a new issue is created.\non:\n  issues:\n    types: opened\n\npermissions:\n  contents: read\n  issues: write\n\njobs:\n  greet:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/first-interaction@2ec0f0fd78838633cd1c1342e4536d49ef72be54 # v1\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n          # Respond to first time issue raisers.\n          issue-message: |\n            Greetings and welcome to our community! As this is the first issue you opened here, we wanted to share some useful infos with you:\n            \n            - 🗣️ Our community on [Discord](https://discord.gg/safing) is super helpful and active. We also have an AI-enabled support bot that knows Portmaster well and can give you immediate help.\n            - 📖 The [Wiki](https://wiki.safing.io/) answers all common questions and has many important details. If you can't find an answer there, let us know, so we can add anything that's missing.\n"
  },
  {
    "path": ".github/workflows/issues-label-actions.yml",
    "content": "# This workflow responds with a message when certain labels are added to an issue or PR.\n# Docs: https://github.com/dessant/label-actions\nname: Label Actions\n\n# This workflow is triggered when a label is added to an issue.\non:\n  issues:\n    types: labeled\n\npermissions:\n  contents: read\n  issues: write\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: dessant/label-actions@ade7bcd4c1b30de6ba8e556cc31301fd4f79ca65 # v3\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          config-path: \".github/label-actions.yml\"\n          process-only: \"issues\"\n"
  },
  {
    "path": ".github/workflows/issues-stale.yml",
    "content": "# This workflow warns and then closes stale issues and PRs.\n# Docs: https://github.com/actions/stale\nname: Close Stale Issues \n\non:\n  schedule:\n    - cron: \"17 5 * * 1-5\" # run at 5:17 (UTC) on Monday to Friday\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  issues: write\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n          # Increase max operations.\n          # When using GITHUB_TOKEN, the rate limit is 1,000 requests per hour per repository.\n          operations-per-run: 500\n          # Handle stale issues\n          stale-issue-label: 'stale'\n          # Exemptions\n          exempt-all-issue-assignees: true\n          exempt-issue-labels: 'support,dependencies,pinned,security'\n          # Mark as stale\n          days-before-issue-stale: 63 # 2 months / 9 weeks\n          stale-issue-message: |\n            This issue has been automatically marked as inactive because it has not had activity in the past two months.\n            \n            If no further activity occurs, this issue will be automatically closed in one week in order to increase our focus on active topics.\n          # Close\n          days-before-issue-close: 7 # 1 week\n          close-issue-message: |\n            This issue has been automatically closed because it has not had recent activity. Thank you for your contributions.\n\n            If the issue has not been resolved, you can [find more information in our Wiki](https://wiki.safing.io/) or [continue the conversation on our Discord](https://discord.gg/safing).\n          # TODO: Handle stale PRs\n          days-before-pr-stale: 36500 # 100 years - effectively disabled.\n"
  },
  {
    "path": ".github/workflows/kext.yml",
    "content": "name: Windows Kernel Extension\n\non:\n  push:\n    paths:\n      - 'windows_kext/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\n  pull_request:\n    paths:\n      - 'windows_kext/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    steps:\n    - uses: earthly/actions-setup@43211c7a0eae5344d6d79fb4aaf209c8f8866203 # v1\n      with:\n        version: v0.8.0\n    - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Log in to the Container registry\n      uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Build Kernel Extension\n      run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +kext-ci\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release v2.X\n\non:\n  push:\n    branches:\n      - main\n      - development\n\n    tags:        \n      - v*\n  workflow_dispatch:\n\njobs:\n  release-prep:\n    name: Prep\n    runs-on: ubuntu-latest\n    steps:\n    - uses: earthly/actions-setup@43211c7a0eae5344d6d79fb4aaf209c8f8866203 # v1\n      with:\n        version: v0.8.0\n    - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Log in to the Container registry\n      uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Build all artifacts\n      run: earthly --remote-cache=ghcr.io/safing/build-cache --push +release-prep\n\n    - name: Upload Dist\n      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n      with:\n        path: ./dist/\n        if-no-files-found: error\n\n  installer-linux:\n    #JOB DISABLED FOR NOW\n    if: false\n    name: Installer linux\n    runs-on: ubuntu-latest\n    needs: release-prep\n    steps:\n    - uses: earthly/actions-setup@43211c7a0eae5344d6d79fb4aaf209c8f8866203 # v1\n      with:\n        version: v0.8.0\n    - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Log in to the Container registry\n      uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Build linux installers\n      run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +installer-linux\n      # --ci include --no-output flag\n\n    - name: Upload Installers\n      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n      with:\n        path: ./dist/linux_amd64/\n        if-no-files-found: error\n\n  installer-windows:\n    #JOB DISABLED FOR NOW\n    if: false\n    name: Installer windows\n    runs-on: windows-latest\n    needs: release-prep\n    steps:\n    - name: Checkout Repository\n      uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Download Dist\n      uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n      with:\n        path: dist/\n\n    - name: Build windows artifacts\n      run: powershell -NoProfile -File ./packaging/windows/generate_windows_installers.ps1\n\n    - name: Upload Installers\n      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n      with:\n        path: ./dist/windows_amd64/\n        if-no-files-found: error\n"
  },
  {
    "path": ".github/workflows/tauri.yml",
    "content": "name: Tauri\n\non:\n  push:\n    paths:\n      - 'desktop/tauri/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\n  pull_request:\n    paths:\n      - 'desktop/tauri/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    steps:\n    - uses: earthly/actions-setup@43211c7a0eae5344d6d79fb4aaf209c8f8866203 # v1\n      with:\n        version: v0.8.0\n    - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Log in to the Container registry\n      uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Build tauri project\n      run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +tauri-ci\n\n  lint:\n    name: Linter\n    runs-on: ubuntu-latest\n    steps:\n    - uses: earthly/actions-setup@43211c7a0eae5344d6d79fb4aaf209c8f8866203 # v1\n      with:\n        version: v0.8.0\n    - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n    - name: Log in to the Container registry\n      uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n      with:\n        registry: ghcr.io\n        username: ${{ github.actor }}\n        password: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Build tauri project\n      run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +tauri-lint\n"
  },
  {
    "path": ".github/workflows/windows-dll.yml",
    "content": "name: Windows Portmaster Core DLL\n\non:\n  push:\n    paths:\n      - 'windows_core_dll/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\n  pull_request:\n    paths:\n      - 'windows_core_dll/**'\n    branches:\n      - main\n      - development\n      - v1-legacy\n      - v1-legacy-develop\n\n  workflow_dispatch:\n\njobs:\n  build:\n    name: Build\n    runs-on: windows-latest\n    steps:\n    - name: Checkout Repository\n      uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n    - name: Add msbuild to PATH\n      uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2\n    - name: Build DLL\n      run: msbuild windows_core_dll\\windows_core_dll.sln -t:rebuild -property:Configuration=Release\n    - name: Verify DLL\n      shell: powershell\n      run: |\n        if (!(Test-Path \"windows_core_dll/x64/Release/portmaster-core.dll\")) {\n          Write-Error \"DLL build failed: portmaster-core.dll not found\"\n          exit 1\n        }\n    - name: Upload artifacts\n      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n      with:\n        name: portmaster-core-dll\n        path: windows_core_dll/x64/Release/portmaster-core.dll\n"
  },
  {
    "path": ".gitignore",
    "content": "# Compiled binaries\n*.exe\ndist/\n\n# Dist dir\ndist\npackaging/_precompiled/\n\n# Custom dev deops\ngo.mod.*\n\n# vendor dir\nvendor\n\n# testing\ntestdata\n\n# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n*.test\n*.prof\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# OS specifics\n.DS_Store\n\n# Custom dev scripts\nwin_dev_*\ngo.work\ngo.work.sum\n\n# Kext releases\nwindows_kext/release/kext_release_*.zip\nwindows_core_dll/.vs/windows_core_dll\n\n#windows_core_dll\nwindows_core_dll/x64/\nwindows_core_dll/portmaster-core/x64/\n\n#Tauri-generated files\ndesktop/tauri/src-tauri/gen/\n\n#Binaries used for installer gereneration for Windows\ndesktop/tauri/src-tauri/binary/\ndesktop/tauri/src-tauri/intel/\nwindows_kext/test/_testcert/\nwindows_kext/test/_out/\nwindows_kext/test/_delme/\n"
  },
  {
    "path": ".golangci.yml",
    "content": "# Docs:\n# https://golangci-lint.run/usage/linters/\n\nlinters:\n  enable-all: true\n  disable:\n    - containedctx\n    - contextcheck\n    - cyclop\n    - depguard\n    - exhaustruct\n    - forbidigo\n    - funlen\n    - gochecknoglobals\n    - gochecknoinits\n    - gocognit\n    - gocyclo\n    - gomoddirectives\n    - interfacebloat\n    - ireturn\n    - lll\n    - mnd\n    - musttag\n    - nestif\n    - nilnil\n    - nlreturn\n    - noctx\n    - nolintlint\n    - nonamedreturns\n    - perfsprint # TODO(ppacher): we should re-enanble this one to avoid costly fmt.* calls in the hot-path\n    - revive\n    - tagliatelle\n    - testifylint\n    - testpackage\n    - varnamelen\n    - whitespace\n    - wrapcheck\n    - wsl\n    - gci\n    - tenv # Deprecated\n\nlinters-settings:\n  revive:\n    # See https://github.com/mgechev/revive#available-rules for details.\n    enable-all-rules: true\n  goimports:\n    local-prefixes: github.com/safing\n  godox:\n    # report any comments starting with keywords, this is useful for TODO or FIXME comments that\n    # might be left in the code accidentally and should be resolved before merging\n    keywords:\n      - FIXME\n  gosec:\n    # To specify a set of rules to explicitly exclude.\n    # Available rules: https://github.com/securego/gosec#available-rules\n    excludes:\n      - G204 # Variables in commands.\n      - G304 # Variables in file paths.\n      - G505 # We need crypto/sha1 for non-security stuff. Using `nolint:` triggers another linter.\n\nissues:\n  exclude-use-default: false\n  exclude-rules:\n    - text: \"a blank import .*\"\n      linters:\n        - golint\n    - text: \"ST1000: at least one file in a package should have a package comment.*\"\n      linters:\n        - stylecheck\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: go\n\ngo:\n- 1.x\n\nos:\n  - linux\n  - windows\n\nbranches:\n  only:\n    - master\n    - develop\n    - /^feature\\/travis\\/.+$/ # feature/travis/*\n    - /^fix\\/travis\\/.+$/ # fix/travis/*\n\naddons:\n  apt:\n    update: true\n\nbefore_install:\n  - if [ \"$TRAVIS_OS_NAME\" = \"linux\" ]; then sudo apt-get -y install libnetfilter-queue-dev; fi\n\ninstall:\n  - go get -d -u github.com/golang/dep\n  - go install github.com/golang/dep/cmd/dep\n  - ./.ci-inject-internal-deps.sh\n  - dep ensure\n  - ./test install\n\nscript: ./test --scripted\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"portmaster-core\",\n            \"type\": \"go\",\n            \"request\": \"launch\",\n            \"mode\": \"auto\",\n            \"program\": \"${workspaceFolder}/cmds/portmaster-core\",\n\n\n\n            \"windows\": {\n                \"args\": [\"--bin-dir=C:\\\\Program Files\\\\Portmaster\", \"--log-stdout\", \"--log\", \"trace\"]                \n            },\n            \"linux\": {\n                \"console\": \"integratedTerminal\", // required to debug as root\n                \"asRoot\": true, // required to debug as root\n\n                \"args\": [\"--bin-dir=/usr/lib/portmaster\", \"--log-stdout\", \"--log\", \"trace\"]\n                \n            },            \n        },\n        {\n            \"name\": \"portmaster-core (NO INTERCEPTION)\",\n            \"type\": \"go\",\n            \"request\": \"launch\",\n            \"mode\": \"auto\",\n            \"program\": \"${workspaceFolder}/cmds/portmaster-core\",\n\n            \"windows\": {\n                \"args\": [\"--bin-dir=C:\\\\Program Files\\\\Portmaster\", \"--log-stdout\", \"--log\", \"trace\", \"--disable-interception=true\"]\n            },\n            \"linux\": {\n                \"console\": \"integratedTerminal\", // required to debug as root\n                \"asRoot\": true, // required to debug as root\n                \n                \"args\": [\"--bin-dir=/usr/lib/portmaster\", \"--log-stdout\", \"--log\", \"trace\", \"--disable-interception=true\"]\n            },\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"cSpell.words\": [\n        \"netenv\",\n        \"safing\",\n        \"Warningf\"\n    ]\n}"
  },
  {
    "path": "AUTHORS",
    "content": "All files in this repository (unless otherwise noted) are authored, owned and copyrighted by Safing ICS Technologies GmbH (Austria).\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at coc@safing.io. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "Earthfile",
    "content": "VERSION 0.8\n\n# Custom argument: \"custom_version\" to manually set the version of the build (and ignore Git Tag value)\n# Usage example: earthly --build-arg custom_version=\"1.2.3\" +<target>\nARG --global custom_version = \"\"\n\nARG --global go_version = 1.24\nARG --global node_version = 18\nARG --global rust_version = 1.89\nARG --global tauri_version = \"2.2.5\"\nARG --global golangci_lint_version = 1.64.6\n\nARG --global go_builder_image = \"golang:${go_version}-alpine\"\nARG --global node_builder_image = \"node:${node_version}\"\nARG --global rust_builder_image = \"rust:${rust_version}-bookworm\"\nARG --global work_image = \"alpine\"\n\nARG --global outputDir = \"./dist\"\n\n# Architectures:\n# The list of rust targets we support. They will be automatically converted\n# to GOOS, GOARCH and GOARM when building go binaries. See the +RUST_TO_GO_ARCH_STRING\n# helper method at the bottom of the file.\n#\n# Linux:\n# x86_64-unknown-linux-gnu\n# aarch64-unknown-linux-gnu\n# armv7-unknown-linux-gnueabihf\n# arm-unknown-linux-gnueabi\n#\n# Windows:\n# x86_64-pc-windows-gnu\n# aarch64-pc-windows-gnu\n#\n# Mac:\n# x86_64-apple-darwin\n# aarch64-apple-darwin\n\n# Import the earthly rust lib since it already provides some useful\n# build-targets and methods to initialize the rust toolchain.\nIMPORT github.com/earthly/lib/rust:3.0.2 AS rust\n\nbuild:\n    # Build all Golang binaries:\n    # ./dist/linux_amd64/portmaster-core\n    # ./dist/linux_amd64/portmaster-start\n    # ./dist/linux_arm64/portmaster-core\n    # ./dist/linux_arm64/portmaster-start\n    # ./dist/windows_amd64/portmaster-core.exe\n    # ./dist/windows_amd64/portmaster-start.exe\n    # ./dist/windows_arm64/portmaster-core.exe\n    # ./dist/windows_arm64/portmaster-start.exe\n    BUILD +go-build --GOOS=\"linux\"   --GOARCH=\"amd64\"\n    BUILD +go-build --GOOS=\"linux\"   --GOARCH=\"arm64\"\n    BUILD +go-build --GOOS=\"windows\" --GOARCH=\"amd64\"\n    BUILD +go-build --GOOS=\"windows\" --GOARCH=\"arm64\"\n\n    # Build the Angular UI:\n    # ./dist/all/portmaster-ui.zip\n    BUILD +angular-release\n\n    # Build Tauri app binaries:\n    # ./dist/linux_amd64/portmaster-app\n    # ./dist/windows_amd64/portmaster-app\n    BUILD +tauri-build --target=\"x86_64-unknown-linux-gnu\"\n    BUILD +tauri-build --target=\"x86_64-pc-windows-gnu\"\n\n    # TODO(vladimir): Build bundles\n    # ./dist/linux_amd64/Portmaster-0.1.0-1.x86_64.rpm\n    # ./dist/linux_amd64/Portmaster_0.1.0_amd64.deb\n    # Bild Tauri bundle for Windows:\n\n    # Build UI assets:\n    # ./dist/all/assets.zip\n    BUILD +assets\n\nbuild-spn:\n    BUILD +go-build --CMDS=\"hub\" --GOOS=\"linux\"   --GOARCH=\"amd64\"\n    BUILD +go-build --CMDS=\"hub\" --GOOS=\"linux\"   --GOARCH=\"arm64\"\n    # TODO: Add other platforms\n\ngo-ci:\n    BUILD +go-build --GOOS=\"linux\"   --GOARCH=\"amd64\"\n    BUILD +go-build --GOOS=\"linux\"   --GOARCH=\"arm64\"\n    BUILD +go-build --GOOS=\"windows\" --GOARCH=\"amd64\"\n    BUILD +go-build --GOOS=\"windows\" --GOARCH=\"arm64\"\n    BUILD +go-test\n\nangular-ci:\n    BUILD +angular-release\n\ntauri-ci:\n    BUILD +tauri-build --target=\"x86_64-unknown-linux-gnu\"\n    BUILD +tauri-build --target=\"x86_64-pc-windows-gnu\"\n\nkext-ci:\n    BUILD +kext-build\n\nrelease:\n    LOCALLY\n\n    IF ! git diff --quiet\n        RUN echo -e \"\\033[1;31m Refusing to release a dirty git repository. Please commit your local changes first! \\033[0m\" ; exit 1\n    END\n\n    BUILD +build\n\ngo-deps:\n    FROM ${go_builder_image}\n    WORKDIR /go-workdir\n\n    # We need the git cli to extract version information for go-builds\n    RUN apk add git\n\n    # These cache dirs will be used in later test and build targets\n    # to persist cached go packages.\n    #\n    # NOTE: cache only gets persisted on successful builds. A test\n    # failure will prevent the go cache from being persisted.\n    ENV GOCACHE = \"/.go-cache\"\n    ENV GOMODCACHE = \"/.go-mod-cache\"\n\n    # Copying only go.mod and go.sum means that the cache for this\n    # target will only be busted when go.mod/go.sum change. This\n    # means that we can cache the results of 'go mod download'.\n    COPY go.mod .\n    COPY go.sum .\n    RUN go mod download\n\n    # Explicitly cache here.\n    SAVE IMAGE --cache-hint\n\ngo-base:\n    FROM +go-deps\n\n    # Copy the full repo, as Go embeds whether the state is clean.\n    COPY . .\n    \n    # Set version information: VERSION, SOURCE, BUILD_TIME and VERSION_SemVer\n    DO +SET_VERSION_INFO \n\n    # Explicitly cache here.\n    SAVE IMAGE --cache-hint\n\n# updates all go dependencies and runs go mod tidy, saving go.mod and go.sum locally.\ngo-update-deps:\n    FROM +go-base\n\n    RUN go get -u ./..\n    RUN go mod tidy\n    SAVE ARTIFACT --keep-ts go.mod AS LOCAL go.mod\n    SAVE ARTIFACT --keep-ts --if-exists go.sum AS LOCAL go.sum\n\n# mod-tidy runs 'go mod tidy', saving go.mod and go.sum locally.\nmod-tidy:\n    FROM +go-base\n\n    RUN go mod tidy\n    SAVE ARTIFACT --keep-ts go.mod AS LOCAL go.mod\n    SAVE ARTIFACT --keep-ts --if-exists go.sum AS LOCAL go.sum\n\n# go-build runs 'go build ./cmds/...', saving artifacts locally.\n# If --CMDS is not set, it defaults to building portmaster-start, portmaster-core and hub\ngo-build:\n    FROM +go-base\n\n    # Arguments for cross-compilation.\n    ARG GOOS=linux\n    ARG GOARCH=amd64\n    ARG GOARM\n    ARG CMDS=portmaster-core\n\n    CACHE --sharing shared \"$GOCACHE\"\n    CACHE --sharing shared \"$GOMODCACHE\"\n\n    RUN mkdir /tmp/build\n\n    # Fall back to build all binaries when none is specified.\n    IF [ \"${CMDS}\" = \"\" ]\n        LET CMDS=$(ls -1 \"./cmds/\")\n    END\n\n    # Build all go binaries from the specified in CMDS\n    FOR bin IN $CMDS\n        # Add special build options.\n        IF [ \"${GOOS}\" = \"windows\" ] &&  [ \"${bin}\" = \"portmaster-start\" ]\n            # Windows, portmaster-start\n            ENV CGO_ENABLED = \"1\"\n            ENV EXTRA_LD_FLAGS = \"-H windowsgui\"\n        ELSE\n            # Defaults\n            ENV CGO_ENABLED = \"0\"\n            ENV EXTRA_LD_FLAGS = \"\"\n        END\n\n        RUN --no-cache go build -ldflags=\"${EXTRA_LD_FLAGS} -X github.com/safing/portmaster/base/info.version=${VERSION} -X github.com/safing/portmaster/base/info.buildSource=${SOURCE} -X github.com/safing/portmaster/base/info.buildTime=${BUILD_TIME}\" -o \"/tmp/build/\" ./cmds/${bin}\n    END\n\n    DO +GO_ARCH_STRING --goos=\"${GOOS}\" --goarch=\"${GOARCH}\" --goarm=\"${GOARM}\"\n    FOR bin IN $(ls -1 \"/tmp/build/\")\n        SAVE ARTIFACT --keep-ts \"/tmp/build/${bin}\" AS LOCAL \"${outputDir}/${GO_ARCH_STRING}/${bin}\"\n    END\n\n    SAVE ARTIFACT --keep-ts \"/tmp/build/\" ./output\n\nspn-image:\n    # Use minimal image as base.\n    FROM alpine\n\n    # Copy the static executable.\n    COPY (+go-build/output/portmaster-start --GOARCH=amd64 --GOOS=linux --CMDS=portmaster-start) /init/portmaster-start\n\n    # Copy the init script\n    COPY spn/tools/container-init.sh /init.sh\n\n    # Run the hub.\n    ENTRYPOINT [\"/init.sh\"]\n\n    # Get version.\n    LET version = \"$(/init/portmaster-start version --short | tr ' ' -)\"\n    RUN echo \"Version: ${version}\"\n\n    # Save dev image\n    SAVE IMAGE \"spn:latest\"\n    SAVE IMAGE \"spn:${version}\"\n    SAVE IMAGE \"ghcr.io/safing/spn:latest\"\n    SAVE IMAGE \"ghcr.io/safing/spn:${version}\"\n\n# Test one or more go packages.\n# Test are always run as -short, as \"long\" tests require a full desktop system.\n# Run `earthly +go-test` to test all packages\n# Run `earthly +go-test --PKG=\"service/firewall\"` to only test a specific package.\n# Run `earthly +go-test --TESTFLAGS=\"-args arg1\"` to add custom flags to go test (-args in this case)\ngo-test:\n    FROM +go-base\n\n    ARG GOOS=linux\n    ARG GOARCH=amd64\n    ARG GOARM\n    ARG TESTFLAGS\n    ARG PKG=\"...\"\n\n    CACHE --sharing shared \"$GOCACHE\"\n    CACHE --sharing shared \"$GOMODCACHE\"\n\n    FOR pkg IN $(go list -e \"./${PKG}\")\n        RUN --no-cache go test -cover -short ${pkg} ${TESTFLAGS}\n    END\n\ngo-test-all:\n    FROM ${work_image}\n    ARG --required architectures\n\n    FOR arch IN ${architectures}\n        DO +RUST_TO_GO_ARCH_STRING --rustTarget=\"${arch}\"\n        BUILD +go-test --GOARCH=\"${GOARCH}\" --GOOS=\"${GOOS}\" --GOARM=\"${GOARM}\"\n    END\n\ngo-lint:\n    FROM +go-base\n\n    RUN go install github.com/golangci/golangci-lint/cmd/golangci-lint@v${golangci_lint_version}\n    RUN golangci-lint run -c ./.golangci.yml --timeout 15m --show-stats\n\n# Builds portmaster-start, portmaster-core, hub and notifier for all supported platforms\ngo-release:\n    FROM ${work_image}\n    ARG --required architectures\n\n    FOR arch IN ${architectures}\n        DO +RUST_TO_GO_ARCH_STRING --rustTarget=\"${arch}\"\n\n        IF [ -z GOARCH ]\n            RUN echo \"Failed to extract GOARCH for ${arch}\"; exit 1\n        END\n\n        IF [ -z GOOS ]\n            RUN echo \"Failed to extract GOOS for ${arch}\"; exit 1\n        END\n\n        BUILD +go-build --GOARCH=\"${GOARCH}\" --GOOS=\"${GOOS}\" --GOARM=\"${GOARM}\"\n    END\n\n# Builds all binaries from the cmds/ folder for linux/windows AMD64\n# Most utility binaries are never needed on other platforms.\ngo-build-utils:\n    BUILD +go-build --CMDS=\"\" --GOARCH=amd64 --GOOS=linux\n    BUILD +go-build --CMDS=\"\" --GOARCH=amd64 --GOOS=windows\n\n# Prepares the angular project by installing dependencies\nangular-deps:\n    FROM ${node_builder_image}\n    WORKDIR /app/ui\n\n    RUN apt update && apt install zip\n\n    COPY desktop/angular/package.json .\n    COPY desktop/angular/package-lock.json .\n\n    RUN npm install\n\n# Copies the UI folder into the working container\n# and builds the shared libraries in the specified configuration (production or development)\nangular-base:\n    FROM +angular-deps\n    ARG configuration=\"production\"\n\n    COPY desktop/angular/ .\n    # Remove symlink and copy assets directly.\n    RUN rm ./assets\n    # COPY assets/data ./assets # Do not include the assets folder into portmaster.zip, we use the assets.zip instead\n\n    IF [ \"${configuration}\" = \"production\" ]\n        RUN --no-cache npm run build-libs\n    ELSE\n        RUN --no-cache npm run build-libs:dev\n    END\n\n    # Explicitly cache here.\n    SAVE IMAGE --cache-hint\n\n# Build an angualr project, zip it and save artifacts locally\nangular-project:\n    ARG --required project\n    ARG --required dist\n    ARG configuration=\"production\"\n    ARG baseHref=\"/\"\n\n    FROM +angular-base --configuration=\"${configuration}\"\n\n    IF [ \"${configuration}\" = \"production\" ]\n        ENV NODE_ENV=\"production\"\n    END\n\n    RUN --no-cache ./node_modules/.bin/ng build --configuration ${configuration} --base-href ${baseHref} \"${project}\"\n\n    RUN --no-cache cwd=$(pwd) && cd \"${dist}\" && zip -r \"${cwd}/${project}.zip\" ./\n    SAVE ARTIFACT --keep-ts \"${dist}\" \"./output/${project}\"\n\n    # Save portmaster UI as local artifact.\n    IF [ \"${project}\" = \"portmaster\" ]\n        SAVE ARTIFACT --keep-ts \"./${project}.zip\" AS LOCAL ${outputDir}/all/${project}-ui.zip\n        SAVE ARTIFACT --keep-ts \"./${project}.zip\" output/${project}.zip\n    END\n\n# Build the angular projects (portmaster-UI and tauri-builtin) in dev mode\nangular-dev:\n    BUILD +angular-project --project=portmaster --dist=./dist --configuration=development --baseHref=/ui/modules/portmaster/\n    BUILD +angular-project --project=tauri-builtin --dist=./dist/tauri-builtin --configuration=development --baseHref=/\n\n# Build the angular projects (portmaster-UI and tauri-builtin) in production mode\nangular-release:\n    BUILD +angular-project --project=portmaster --dist=./dist --configuration=production --baseHref=/ui/modules/portmaster/\n    BUILD +angular-project --project=tauri-builtin --dist=./dist/tauri-builtin --configuration=production --baseHref=/\n\nassets:\n    FROM ${work_image}\n    RUN apk add zip\n\n    WORKDIR /app/assets\n    COPY --keep-ts ./assets/data .\n    RUN zip -r -9 -db -X assets.zip *\n\n    SAVE ARTIFACT --keep-ts \"assets.zip\" AS LOCAL \"${outputDir}/all/assets.zip\"\n\n# A base target for rust to prepare the build container\nrust-base:\n    FROM ${rust_builder_image}\n\n    RUN apt-get update -qq\n\n    # Tools and libraries required for cross-compilation\n    RUN apt-get install --no-install-recommends -qq \\\n        autoconf \\\n        autotools-dev \\\n        libtool-bin \\\n        clang \\\n        cmake \\\n        bsdmainutils \\\n        gcc-multilib \\\n        linux-libc-dev \\\n        linux-libc-dev-amd64-cross \\\n        build-essential \\\n        curl \\\n        wget \\\n        file \\\n        libsoup-3.0-dev \\\n        libwebkit2gtk-4.1-dev \\\n        gcc-mingw-w64-x86-64 \\\n        zip\n\n    # Install library dependencies for all supported architectures\n    # required for succesfully linking.\n    RUN apt-get install --no-install-recommends -qq \\\n        libsoup-3.0-0 \\\n        libwebkit2gtk-4.1-0 \\\n        libssl3 \\\n        libayatana-appindicator3-1 \\\n        librsvg2-bin \\\n        libgtk-3-0 \\\n        libjavascriptcoregtk-4.1-0  \\\n        libssl-dev \\\n        libayatana-appindicator3-dev \\\n        librsvg2-dev \\\n        libgtk-3-dev \\\n        libjavascriptcoregtk-4.1-dev  \n\n    # Add some required rustup components\n    RUN rustup component add clippy\n    RUN rustup component add rustfmt\n\n    DO rust+INIT --keep_fingerprints=true\n\n    # For now we need tauri-cli 2.0.0 for bulding\n    DO rust+CARGO --args=\"install tauri-cli --version 2.2.7 --locked\"\n\n    # Explicitly cache here.\n    SAVE IMAGE --cache-hint\n\ntauri-src:\n    FROM +rust-base\n\n    WORKDIR /app/tauri\n\n    # --keep-ts is necessary to ensure that the timestamps of the source files\n    # are preserved such that Rust's incremental compilation works correctly.\n    COPY --keep-ts ./desktop/tauri/ .\n    COPY assets/data ./../../assets/data\n    COPY packaging ./../../packaging\n    COPY (+angular-project/output/tauri-builtin --project=tauri-builtin --dist=./dist/tauri-builtin --configuration=production --baseHref=\"/\") ./../angular/dist/tauri-builtin\n\n    WORKDIR /app/tauri/src-tauri\n\n    # Explicitly cache here.\n    SAVE IMAGE --cache-hint\n\ntauri-build:\n    FROM +tauri-src\n    \n    ARG --required target\n\n    ARG output=\".*/release/([^\\./]+|([^\\./]+\\.(dll|exe)))\"\n    DO +RUST_TO_GO_ARCH_STRING --rustTarget=\"${target}\"\n    RUN echo \"GOOS=${GOOS} GOARCH=${GOARCH} GOARM=${GOARM} GO_ARCH_STRING=${GO_ARCH_STRING}\"\n\n    DO rust+SET_CACHE_MOUNTS_ENV\n    RUN rustup target add \"${target}\"\n\n    # Build\n    RUN --mount=$EARTHLY_RUST_TARGET_CACHE cargo tauri build  --ci --target=\"${target}\" --no-bundle\n    DO rust+COPY_OUTPUT --output=\"${output}\"\n\n    # BUG(cross-compilation):\n    #\n    # The above command seems to correctly compile for all architectures we want to support but fails during\n    # linking since the target libaries are not available for the requested platforms. Maybe we need to download\n    # the, manually ...\n    #\n    # The earthly rust lib also has support for using cross-rs for cross-compilation but that fails due to the\n    # fact that cross-rs base docker images used for building are heavily outdated (latest = ubunut:16.0, main = ubuntu:20.04)\n    # which does not ship recent enough glib versions (our glib dependency needs glib>2.70 but ubunut:20.04 only ships 2.64)\n    #\n    # The following would use the CROSS function from the earthly lib, this \n    # DO rust+CROSS --target=\"${target}\"\n\n    RUN echo output: $(ls -R \"target/${target}/release\")\n\n    # Binaries\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/portmaster\" AS LOCAL \"${outputDir}/${GO_ARCH_STRING}/portmaster\"\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/portmaster.exe\" AS LOCAL \"${outputDir}/${GO_ARCH_STRING}/portmaster.exe\"\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/WebView2Loader.dll\" AS LOCAL \"${outputDir}/${GO_ARCH_STRING}/WebView2Loader.dll\"\n\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/portmaster\" ./output/portmaster\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/portmaster.exe\" ./output/portmaster.exe\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/WebView2Loader.dll\" ./output/WebView2Loader.dll\n\n\ntauri-release:\n    FROM ${work_image}\n    ARG --required architectures\n\n    FOR arch IN ${architectures}\n        BUILD +tauri-build --target=\"${arch}\"\n    END\n\ntauri-lint:\n    FROM +rust-base\n    ARG target=\"x86_64-unknown-linux-gnu\"\n\n    WORKDIR /app\n    # Copy static files that are embedded inside the executable.\n    COPY --keep-ts ./assets ./assets\n\n    # Copy all the rust code\n    COPY --keep-ts ./desktop/tauri ./desktop/tauri\n\n    # Create a empty ui dir so it will satisfy the build.\n    RUN mkdir -p ./desktop/angular/dist/tauri-builtin\n\n    SAVE IMAGE --cache-hint\n\n    # Run the linter.\n    WORKDIR /app/desktop/tauri/src-tauri\n    RUN --mount=$EARTHLY_RUST_TARGET_CACHE cargo clippy --all-targets --all-features -- -D warnings\n\nrelease-prep:\n    FROM +rust-base\n\n    WORKDIR /app\n\n    # Linux specific\n    COPY (+tauri-build/output/portmaster --target=\"x86_64-unknown-linux-gnu\") ./output/binary/linux_amd64/portmaster\n    COPY (+go-build/output/portmaster-core --GOARCH=amd64 --GOOS=linux --CMDS=portmaster-core) ./output/binary/linux_amd64/portmaster-core\n\n    # Windows specific\n    COPY (+tauri-build/output/portmaster.exe --target=\"x86_64-pc-windows-gnu\") ./output/binary/windows_amd64/portmaster.exe\n    COPY (+tauri-build/output/WebView2Loader.dll --target=\"x86_64-pc-windows-gnu\") ./output/binary/windows_amd64/WebView2Loader.dll\n    COPY (+go-build/output/portmaster-core.exe --GOARCH=amd64 --GOOS=windows --CMDS=portmaster-core) ./output/binary/windows_amd64/portmaster-core.exe\n\n    # All platforms\n    COPY (+assets/assets.zip) ./output/binary/all/assets.zip\n    COPY (+angular-project/output/portmaster.zip --project=portmaster --dist=./dist --configuration=production --baseHref=/ui/modules/portmaster/) ./output/binary/all/portmaster.zip\n\n    # Build update manager\n    COPY (+go-build/output/updatemgr --GOARCH=amd64 --GOOS=linux --CMDS=updatemgr) ./updatemgr\n    # Get \"portmaster-kext.sys\" and \"portmaster-core.dll\" from current stable release\n    RUN mkdir -p ./output/downloaded/windows_amd64 && ./updatemgr download https://updates.safing.io/stable.v3.json --platform windows_amd64 ./output/downloaded/windows_amd64\n    RUN find ./output/downloaded/windows_amd64 -type f ! -name \"portmaster-kext.sys\" ! -name \"portmaster-core.dll\" -delete  # We are only interested in the KEXT and core DLL. Remove the rest.\n    # Get intel artifacts\n    RUN mkdir -p ./output/intel && ./updatemgr download https://updates.safing.io/intel.v3.json ./output/intel\n    \n    # Save all artifacts to output folder (on host)\n    SAVE ARTIFACT --keep-ts \"output/binary/all/*\"           AS LOCAL \"${outputDir}/binary/all/\"\n    SAVE ARTIFACT --keep-ts \"output/binary/linux_amd64/*\"   AS LOCAL \"${outputDir}/binary/linux_amd64/\"\n    SAVE ARTIFACT --keep-ts \"output/binary/windows_amd64/*\" AS LOCAL \"${outputDir}/binary/windows_amd64/\"\n    SAVE ARTIFACT --keep-ts \"output/intel/*\"                AS LOCAL \"${outputDir}/intel/\"\n    SAVE ARTIFACT --keep-ts \"output/downloaded/*\"           AS LOCAL \"${outputDir}/downloaded/\" # KEXT and core DLL: artifacts from the current stable release\n\n    # Save all artifacts to the container output folder so other containers can access it.\n    SAVE ARTIFACT --keep-ts \"output/binary/all/*\"           \"output/binary/all/\"\n    SAVE ARTIFACT --keep-ts \"output/binary/linux_amd64/*\"   \"output/binary/linux_amd64/\"\n    SAVE ARTIFACT --keep-ts \"output/binary/windows_amd64/*\" \"output/binary/windows_amd64/\"\n    SAVE ARTIFACT --keep-ts \"output/intel/*\"                \"output/intel/\"\n    SAVE ARTIFACT --keep-ts \"output/downloaded/*\"           \"output/downloaded/\"\n\n    # IMPORTANT: COPYING PRECOMPILED LOCAL FILES!\n    # If \"packaging/_precompiled\" foledr exists, it's contents has priority to be used; it's files will overwrite the ones from the build!\n    # Expected structure:\n    # - packaging/_precompiled/binary/...    \n    # - packaging/_precompiled/intel    \n    #   Careful! If there are any files in the '_precompiled/intel' folder, the final 'intel/index.json' may be broken due to incorrect hash values!\n    COPY --if-exists --keep-ts ./packaging/_precompiled/binary  ./packaging/precompiled/binary\n    COPY --if-exists --keep-ts ./packaging/_precompiled/intel   ./packaging/precompiled/intel\n    IF --no-cache [ -d ./packaging/precompiled ]\n        RUN --no-cache echo \"[ !!! ATTENTION  !!! ] PRECOMPILED FILES IN USE:\" && find ./packaging/precompiled -type f;\n        IF --no-cache [ -d ./packaging/precompiled/intel ]\n            RUN --no-cache echo \"[!!! ATTENTION !!!] ENSURE THAT 'intel/index.json' CONTAINS THE CORRECT HASHES!\"\n        END        \n        RUN --no-cache echo \"Script paused. Press Enter to continue...\" && read\n        SAVE ARTIFACT --if-exists --keep-ts \"packaging/precompiled/intel/*\"  AS LOCAL \"${outputDir}/intel/\"     # save to host\n        SAVE ARTIFACT --if-exists --keep-ts \"packaging/precompiled/binary/*\" AS LOCAL \"${outputDir}/binary/\"    # save to host\n        SAVE ARTIFACT --if-exists --keep-ts \"packaging/precompiled/intel/*\"           \"output/intel/\"           # save to container (so other containers can access it)\n        SAVE ARTIFACT --if-exists --keep-ts \"packaging/precompiled/binary/*\"          \"output/binary/\"          # save to container (so other containers can access it)\n    END\n\ninstaller-linux:\n    FROM +rust-base\n    # ARG --required target\n    ARG target=\"x86_64-unknown-linux-gnu\"\n\n    WORKDIR /app/tauri\n    COPY --keep-ts ./desktop/tauri/ .\n    COPY assets/data ./../../assets/data\n    COPY packaging ./../../packaging\n\n    WORKDIR /app/tauri/src-tauri\n\n    SAVE IMAGE --cache-hint\n\n    DO +RUST_TO_GO_ARCH_STRING --rustTarget=\"${target}\"\n\n    # Build and copy the binaries\n    RUN mkdir -p target/${target}/release\n    COPY (+release-prep/output/binary/linux_amd64/portmaster) ./target/${target}/release/portmaster\n\n    RUN mkdir -p binary\n    COPY (+release-prep/output/binary/linux_amd64/portmaster-core) ./binary/portmaster-core\n    COPY (+release-prep/output/binary/all/portmaster.zip) ./binary/portmaster.zip\n    COPY (+release-prep/output/binary/all/assets.zip) ./binary/assets.zip\n\n    # Download the intel data\n    RUN mkdir -p intel\n    COPY (+release-prep/output/intel/*) ./intel/\n\n    # Init version information: VERSION, SOURCE, BUILD_TIME and VERSION_SemVer\n    DO +SET_VERSION_INFO \n    # Set version in Cargo.toml if it's a valid SemVer (required for using in the installer file names)\n    RUN if [ -n \"$VERSION_SemVer\" ]; then sed -i 's/^version = \".*\"/version = \"'\"$VERSION_SemVer\"'\"/g' Cargo.toml; fi\n    \n    # build the installers\n    RUN cargo tauri bundle --ci --target=\"${target}\"\n\n    # Installers\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/bundle/deb/*.deb\" AS LOCAL \"${outputDir}/${GO_ARCH_STRING}/\"\n    SAVE ARTIFACT --if-exists --keep-ts \"target/${target}/release/bundle/rpm/*.rpm\" AS LOCAL \"${outputDir}/${GO_ARCH_STRING}/\"\n\nall-artifacts:\n    BUILD +release-prep\n    BUILD +installer-linux\n\nkext-build:\n    FROM ${rust_builder_image}\n\n    # Install architecture target\n    DO rust+INIT --keep_fingerprints=true\n\n    # Build kext\n    WORKDIR /app/kext\n    # --keep-ts is necessary to ensure that the timestamps of the source files\n    # are preserved such that Rust's incremental compilation works correctly.\n    COPY --keep-ts ./windows_kext/ .\n\n    # Add target architecture\n    RUN rustup target add x86_64-pc-windows-msvc\n    \n    # Build using special earthly lib\n    WORKDIR /app/kext/release\n    DO rust+CARGO --args=\"run\"\n\n    SAVE ARTIFACT --keep-ts \"portmaster-kext-release-bundle.zip\" AS LOCAL \"${outputDir}/windows_amd64/portmaster-kext-release-bundle.zip\"\n\n\n# Takes GOOS, GOARCH and optionally GOARM and creates a string representation for file-names.\n# in the form of ${GOOS}_{GOARCH} if GOARM is empty, otherwise ${GOOS}_${GOARCH}v${GOARM}.\n# Thats the same format as expected and served by our update server.\n#\n# The result is available as GO_ARCH_STRING environment variable in the build context.\nGO_ARCH_STRING:\n    FUNCTION\n    ARG --required goos\n    ARG --required goarch\n    ARG goarm\n\n    LET result = \"${goos}_${goarch}\"\n    IF [ \"${goarm}\" != \"\" ]\n        SET result = \"${goos}_${goarch}v${goarm}\"\n    END\n\n    ENV GO_ARCH_STRING=\"${result}\"\n\n# Takes a rust target (--rustTarget) and extracts architecture and OS and arm version\n# and finally calls GO_ARCH_STRING.\n#\n# The result is available as GO_ARCH_STRING environment variable in the build context.\n# It also exports GOOS, GOARCH and GOARM environment variables.\nRUST_TO_GO_ARCH_STRING:\n    FUNCTION\n    ARG --required rustTarget\n\n    LET goos=\"\"\n    IF [ -z \"${rustTarget##*linux*}\" ]\n        SET goos=\"linux\"\n    ELSE IF [ -z \"${rustTarget##*windows*}\" ]\n        SET goos=\"windows\"\n    ELSE IF [ -z \"${rustTarget##*darwin*}\" ]\n        SET goos=\"darwin\"\n    ELSE\n        RUN echo \"GOOS not detected\"; \\\n            exit 1;\n    END\n\n    LET goarch=\"\"\n    LET goarm=\"\"\n    IF [ -z \"${rustTarget##*x86_64*}\" ]\n        SET goarch=\"amd64\"\n    ELSE IF [ -z \"${rustTarget##*arm*}\" ]\n        SET goarch=\"arm\"\n        SET goarm=\"6\"\n\n        IF [ -z \"${rustTarget##*v7*}\" ]\n            SET goarm=\"7\"\n        END\n    ELSE IF [ -z \"${rustTarget##*aarch64*}\" ]\n        SET goarch=\"arm64\"\n    ELSE\n        RUN echo \"GOARCH not detected\"; \\\n            exit 1;\n    END\n\n    ENV GOOS=\"${goos}\"\n    ENV GOARCH=\"${goarch}\"\n    ENV GOARM=\"${goarm}\"\n\n    DO +GO_ARCH_STRING --goos=\"${goos}\" --goarch=\"${goarch}\" --goarm=\"${goarm}\"\n\n# Takes an architecture or GOOS string and sets the BINEXT env var.\nBIN_EXT:\n    FUNCTION\n    ARG --required arch\n\n    LET binext=\"\"\n    IF [ -z \"${arch##*windows*}\" ]\n        SET binext=\".exe\"\n    END\n    ENV BINEXT=\"${goos}\"\n\n# Function to set the version-related environment variables (variables: VERSION, SOURCE, BUILD_TIME and VERSION_SemVer)\n# Call example:\n#    DO +SET_VERSION_INFO\nSET_VERSION_INFO:\n    FUNCTION\n    ARG gitDir=\"/tmp/git-info\"\n    \n    # Check if already initialized and skip the rest if true\n    IF [ -n \"$BUILD_TIME\" ]\n        #RUN echo \"Version info already initialized\"       \n    ELSE\n        # Make sure git is installed in the image\n        RUN which git || apk add --no-cache git\n        # Create a temporary directory for git information only\n        RUN mkdir -p ${gitDir}        \n        # Copy only the .git directory to the temporary location\n        COPY --dir .git ${gitDir}/.git\n        \n        # Check if custom version was provided via command line\n        IF [ -n \"$custom_version\" ]\n            ENV VERSION=\"${custom_version}\"\n            RUN echo \"Using custom version from command line: $VERSION\"\n        ELSE\n            # Get version from git tags without changing workdir\n            LET version = \"$(git --git-dir=${gitDir}/.git tag --points-at || true)\"\n            IF [ -z \"${version}\" ]\n                LET dev_version = \"$(git --git-dir=${gitDir}/.git describe --tags --first-parent --abbrev=0 || true)\"\n                IF [ -n \"${dev_version}\" ]\n                    SET version = \"${dev_version}_dev_build\"\n                END\n            END\n            IF [ -z \"${version}\" ]\n                SET version = \"dev_build\"\n            END\n            ENV VERSION=\"${version}\"\n            RUN echo \"Version: $VERSION\"\n        END\n\n        # Create cleaned version without 'v' prefix and without suffix starting with '_'\n        # Only set VERSION_SemVer if it matches semantic versioning format\n        LET version_clean = \"$(echo \"${VERSION}\" | sed -E 's/^[vV]//' | sed -E 's/_.*$//')\"    \n        IF [ $(echo \"${version_clean}\" | grep -E '^[0-9]+\\.[0-9]+\\.[0-9]+([.-].*)?$') ]\n            ENV VERSION_SemVer=\"${version_clean}\"\n            RUN echo \"VERSION_SemVer: $VERSION_SemVer\"\n        ELSE\n            RUN echo \"VERSION_SemVer: [Empty - not a valid SemVer in Git Tag] - !!! WARNING !!!\"\n        END\n\n        # Get source information without changing workdir\n        LET source = \"$( (git --git-dir=${gitDir}/.git remote -v | cut -f2 | cut -d\" \" -f1 | head -n 1) || echo \"unknown\" )\"\n        ENV SOURCE=\"${source}\"\n        RUN echo \"Source: $SOURCE\"\n\n        # Get build time\n        LET build_time = \"$(date -u \"+%Y-%m-%dT%H:%M:%SZ\" || echo \"unknown\")\"\n        ENV BUILD_TIME = \"${build_time}\"\n        RUN echo \"Build Time: $BUILD_TIME\"\n    END"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "# Get Peace of Mind <br> with [Easy Privacy](https://safing.io/)\n\nPortmaster is a free and open-source application firewall that does the heavy lifting for you.\nRestore privacy and take back control over all your computer's network activity.\n\nWith great defaults your privacy improves without any effort. And if you want to configure and control everything down to the last detail - Portmaster has you covered too. Developed in the EU 🇪🇺, Austria.\n\n__[Download for Free](https://safing.io/download/)__\n\n__[About Us](https://safing.io/about/)__\n\n![Portmaster User Interface](https://safing.io/assets/img/page-specific/landing/portmaster-thumbnail.png?)\n\n_seen on:_  \n\n[<img src=\"https://safing.io/assets/img/external/heise_online.svg\" height=\"35\">](https://www.heise.de/tests/Datenschutz-Firewall-Portmaster-im-Test-9611687.html)\n&nbsp;&nbsp;&nbsp;\n[![ghacks.net](https://safing.io/assets/img/external/ghacks.png)](https://www.ghacks.net/2022/11/08/portmaster-1-0-released-open-source-application-firewall/)\n&nbsp;&nbsp;&nbsp;\n[![Techlore](https://safing.io/assets/img/external/techlore.png)](https://www.youtube.com/watch?v=E8cTRhGtmcM)\n&nbsp;&nbsp;&nbsp;\n[![Lifehacker](https://safing.io/assets/img/external/logos/lifehacker.webp)](https://lifehacker.com/the-lesser-known-apps-everyone-should-install-on-a-new-1850223434)\n\n## [Features](https://safing.io/features/)\n\n1. Monitor All Network Activity\n2. Full Control: Block Anything\n3. Automatically Block Trackers & Malware\n4. Set Global & Per‑App Settings\n5. Secure DNS (Doh/DoT)\n6. Record and Search Network Activity ([$](https://safing.io/pricing/))\n7. Per-App Bandwidth Usage ([$](https://safing.io/pricing/))\n8. [SPN, our Next-Gen Privacy Network](https://safing.io/spn/) ([$$](https://safing.io/pricing/))\n\n# Technical Introduction\n\nPortmaster is a privacy suite for your Windows and Linux desktop.\n\n### Base Technology\n\n- Portmaster integrates into network stack using nfqueue on Linux and a kernel driver (WFP) on Windows.\n- Packets are intercepted at the raw packet level - every packet is seen and can be stopped.\n- Ownership of connections is found using eBPF and `/proc` on Linux and a kernel driver and the IP Helper API (`iphlpapi.dll`) on Windows.\n- Most settings can be defined per app, which can be matched in different ways.\n- Support for special processes with weird or concealed paths/actors:\n  - Snap, AppImage and Script support on Linux\n  - Windows Store apps and svchost.exe system services support on Windows\n- Everything is 100% local on your device. (except the SPN, naturally)\n  - Updates are fully signed and downloaded automatically.\n  - Intelligence data (block lists, geoip) is downloaded and applied automatically.\n- The Portmaster Core Service runs as a system service, the UI elements (App, Notifier) run in user context.\n- The main UI still uses electron as a wrapper :/ - but this will change in the future. You can also open the UI in the browser\n\n### Feature: Secure DNS\n\n- Portmaster intercepts \"astray\" DNS queries and reroutes them to itself for seamless integration.\n- DNS queries are resolved by the default or configured DoT/DoH resolvers.\n- Full support for split horizon and horizon validation to defend against rebinding attacks.\n\n### Feature: Privacy Filter\n\n- Define allowed network scopes: Localhost, LAN, Internet, P2P, Inbound.\n- Easy rules based on Internet entities: Domain, IP, Country and more.\n- Filter Lists block common malware, ad, tracker domains etc.\n\n### Feature: Network History ($)\n\n- Record connections and their details in a local database and search all of it later\n- Auto-delete old history or delete on demand\n\n### Feature: Bandwidth Visibility ($)\n\n- Monitor bandwidth usage per connection and app\n\n### Feature: SPN - Safing Privacy Network ($$)\n\n- A Privacy Network aimed at use cases \"between\" VPN and Tor.\n- Uses onion encryption over multiple hops just like Tor.\n- Routes are chosen to cover most distance within the network to increase privacy.\n- Exits are chosen near the destination server. This automatically geo-unblocks in many cases.\n- Exclude apps and domains/entities from using SPN.\n- Change routing algorithm and focus per app.\n- Nodes are hosted by Safing (company behind Portmaster) and the community.\n- Speeds are pretty decent (>100MBit/s).\n- Further Reading: [SPN Whitepaper](https://safing.io/files/whitepaper/Gate17.pdf)\n\n## Documentation\n\nAll details and guides in the dedicated [wiki](https://wiki.safing.io/)\n\n- [Getting Started](https://wiki.safing.io/en/Portmaster/App)\n- Install\n  - [on Windows](https://wiki.safing.io/en/Portmaster/Install/Windows)\n  - [on Linux](https://wiki.safing.io/en/Portmaster/Install/Linux)\n- [Contribute](https://wiki.safing.io/en/Contribute)\n- [VPN Compatibility](https://wiki.safing.io/en/Portmaster/App/Compatibility#vpn-compatibly)\n- [Software Compatibility](https://wiki.safing.io/en/Portmaster/App/Compatibility)\n- [Architecture](https://wiki.safing.io/en/Portmaster/Architecture)\n- [Settings Handbook](https://docs.safing.io/portmaster/settings)\n- [Portmaster Developer API](https://docs.safing.io/portmaster/api)\n\n# Build Portmaster Yourself (WIP)\n\n1. [Install Earthly CLI](https://earthly.dev/get-earthly)\n2. [Install Docker Engine](https://docs.docker.com/engine/install/)\n3. Run `earthly +release`\n4. Find artifacts in `./dist`\n"
  },
  {
    "path": "TESTING.md",
    "content": "# Testing Portmaster\n\nThis page documents ways to test if Portmaster works as intended.\n\n⚠ Work in Progress. Currently we are just collecting helpful things we find.\n\n## Websites for Testing:\n\n- <http://icmpcheck.popcount.org/>: Check \n  - ICMP path MTU packet delivery\n  - IP fragmented packet delivery\n"
  },
  {
    "path": "TRADEMARKS",
    "content": "The names \"Safing\", \"Portmaster\", \"Gate17\" and their logos are trademarks owned by Safing ICS Technologies GmbH (Austria).\n\nAlthough our code is free, it is very important that we strictly enforce our trademark rights, in order to be able to protect our users against people who use the marks to commit fraud. This means that, while you have considerable freedom to redistribute and modify our software, there are tight restrictions on your ability to use our names and logos in ways which fall in the domain of trademark law, even when built into binaries that we provide.\n\nThis file is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. Parts of it were taken from https://www.mozilla.org/en-US/foundation/licensing/.\n"
  },
  {
    "path": "assets/data/favicons/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig><msapplication><tile><square70x70logo src=\"/assets/favicons/ms-icon-70x70.png\"/><square150x150logo src=\"/assets/favicons/ms-icon-150x150.png\"/><square310x310logo src=\"/assets/favicons/ms-icon-310x310.png\"/><TileColor>#121213</TileColor></tile></msapplication></browserconfig>\n"
  },
  {
    "path": "assets/data/favicons/head.html",
    "content": "<link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"/assets/favicons/apple-icon-57x57.png\">\n<link rel=\"apple-touch-icon\" sizes=\"60x60\" href=\"/assets/favicons/apple-icon-60x60.png\">\n<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"/assets/favicons/apple-icon-72x72.png\">\n<link rel=\"apple-touch-icon\" sizes=\"76x76\" href=\"/assets/favicons/apple-icon-76x76.png\">\n<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"/assets/favicons/apple-icon-114x114.png\">\n<link rel=\"apple-touch-icon\" sizes=\"120x120\" href=\"/assets/favicons/apple-icon-120x120.png\">\n<link rel=\"apple-touch-icon\" sizes=\"144x144\" href=\"/assets/favicons/apple-icon-144x144.png\">\n<link rel=\"apple-touch-icon\" sizes=\"152x152\" href=\"/assets/favicons/apple-icon-152x152.png\">\n<link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"/assets/favicons/apple-icon-180x180.png\">\n<link rel=\"icon\" type=\"image/png\" sizes=\"192x192\"  href=\"/assets/favicons/android-icon-192x192.png\">\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/assets/favicons/favicon-32x32.png\">\n<link rel=\"icon\" type=\"image/png\" sizes=\"96x96\" href=\"/assets/favicons/favicon-96x96.png\">\n<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/assets/favicons/favicon-16x16.png\">\n<link rel=\"manifest\" href=\"/assets/favicons/manifest.json\">\n<meta name=\"msapplication-TileColor\" content=\"#121213\">\n<meta name=\"msapplication-TileImage\" content=\"/assets/favicons/ms-icon-144x144.png\">\n<meta name=\"theme-color\" content=\"#121213\">\n"
  },
  {
    "path": "assets/data/favicons/manifest.json",
    "content": "{\n \"name\": \"App\",\n \"icons\": [\n  {\n   \"src\": \"\\/assets\\/favicons\\/android-icon-36x36.png\",\n   \"sizes\": \"36x36\",\n   \"type\": \"image\\/png\",\n   \"density\": \"0.75\"\n  },\n  {\n   \"src\": \"\\/assets\\/favicons\\/android-icon-48x48.png\",\n   \"sizes\": \"48x48\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.0\"\n  },\n  {\n   \"src\": \"\\/assets\\/favicons\\/android-icon-72x72.png\",\n   \"sizes\": \"72x72\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.5\"\n  },\n  {\n   \"src\": \"\\/assets\\/favicons\\/android-icon-96x96.png\",\n   \"sizes\": \"96x96\",\n   \"type\": \"image\\/png\",\n   \"density\": \"2.0\"\n  },\n  {\n   \"src\": \"\\/assets\\/favicons\\/android-icon-144x144.png\",\n   \"sizes\": \"144x144\",\n   \"type\": \"image\\/png\",\n   \"density\": \"3.0\"\n  },\n  {\n   \"src\": \"\\/assets\\/favicons\\/android-icon-192x192.png\",\n   \"sizes\": \"192x192\",\n   \"type\": \"image\\/png\",\n   \"density\": \"4.0\"\n  }\n ]\n}\n"
  },
  {
    "path": "assets/data/fonts/Roboto-300/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/Roboto-300italic/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/Roboto-500/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/Roboto-500italic/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/Roboto-700/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/Roboto-700italic/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/Roboto-italic/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/Roboto-regular/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "assets/data/fonts/roboto-slimfix.css",
    "content": "@font-face {\n  font-family: 'Roboto';\n  font-weight: 400;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-300/Roboto-300.eot');\n  src: url('/assets/fonts/Roboto-300/Roboto-300.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Light'),\n       local('Roboto-300'),\n       url('/assets/fonts/Roboto-300/Roboto-300.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-300/Roboto-300.woff') format('woff'),\n       url('/assets/fonts/Roboto-300/Roboto-300.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-300/Roboto-300.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 500;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-regular/Roboto-regular.eot');\n  src: url('/assets/fonts/Roboto-regular/Roboto-regular.eot?#iefix') format('embedded-opentype'),\n       local('Roboto'),\n       local('Roboto-regular'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.woff') format('woff'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 700;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-500/Roboto-500.eot');\n  src: url('/assets/fonts/Roboto-500/Roboto-500.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Medium'),\n       local('Roboto-500'),\n       url('/assets/fonts/Roboto-500/Roboto-500.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-500/Roboto-500.woff') format('woff'),\n       url('/assets/fonts/Roboto-500/Roboto-500.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-500/Roboto-500.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 900;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-700/Roboto-700.eot');\n  src: url('/assets/fonts/Roboto-700/Roboto-700.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Bold'),\n       local('Roboto-700'),\n       url('/assets/fonts/Roboto-700/Roboto-700.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-700/Roboto-700.woff') format('woff'),\n       url('/assets/fonts/Roboto-700/Roboto-700.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-700/Roboto-700.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 400;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-300italic/Roboto-300italic.eot');\n  src: url('/assets/fonts/Roboto-300italic/Roboto-300italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Light Italic'),\n       local('Roboto-300italic'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 500;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-italic/Roboto-italic.eot');\n  src: url('/assets/fonts/Roboto-italic/Roboto-italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Italic'),\n       local('Roboto-italic'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 700;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-500italic/Roboto-500italic.eot');\n  src: url('/assets/fonts/Roboto-500italic/Roboto-500italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Medium Italic'),\n       local('Roboto-500italic'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 900;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-700italic/Roboto-700italic.eot');\n  src: url('/assets/fonts/Roboto-700italic/Roboto-700italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Bold Italic'),\n       local('Roboto-700italic'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.svg#Roboto') format('svg');\n}\n"
  },
  {
    "path": "assets/data/fonts/roboto.css",
    "content": "@font-face {\n  font-family: 'Roboto';\n  font-weight: 300;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-300/Roboto-300.eot');\n  src: url('/assets/fonts/Roboto-300/Roboto-300.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Light'),\n       local('Roboto-300'),\n       url('/assets/fonts/Roboto-300/Roboto-300.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-300/Roboto-300.woff') format('woff'),\n       url('/assets/fonts/Roboto-300/Roboto-300.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-300/Roboto-300.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 400;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-regular/Roboto-regular.eot');\n  src: url('/assets/fonts/Roboto-regular/Roboto-regular.eot?#iefix') format('embedded-opentype'),\n       local('Roboto'),\n       local('Roboto-regular'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.woff') format('woff'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-regular/Roboto-regular.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 500;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-500/Roboto-500.eot');\n  src: url('/assets/fonts/Roboto-500/Roboto-500.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Medium'),\n       local('Roboto-500'),\n       url('/assets/fonts/Roboto-500/Roboto-500.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-500/Roboto-500.woff') format('woff'),\n       url('/assets/fonts/Roboto-500/Roboto-500.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-500/Roboto-500.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 700;\n  font-style: normal;\n  src: url('/assets/fonts/Roboto-700/Roboto-700.eot');\n  src: url('/assets/fonts/Roboto-700/Roboto-700.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Bold'),\n       local('Roboto-700'),\n       url('/assets/fonts/Roboto-700/Roboto-700.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-700/Roboto-700.woff') format('woff'),\n       url('/assets/fonts/Roboto-700/Roboto-700.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-700/Roboto-700.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 300;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-300italic/Roboto-300italic.eot');\n  src: url('/assets/fonts/Roboto-300italic/Roboto-300italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Light Italic'),\n       local('Roboto-300italic'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-300italic/Roboto-300italic.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 400;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-italic/Roboto-italic.eot');\n  src: url('/assets/fonts/Roboto-italic/Roboto-italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Italic'),\n       local('Roboto-italic'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-italic/Roboto-italic.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 500;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-500italic/Roboto-500italic.eot');\n  src: url('/assets/fonts/Roboto-500italic/Roboto-500italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Medium Italic'),\n       local('Roboto-500italic'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-500italic/Roboto-500italic.svg#Roboto') format('svg');\n}\n\n@font-face {\n  font-family: 'Roboto';\n  font-weight: 700;\n  font-style: italic;\n  src: url('/assets/fonts/Roboto-700italic/Roboto-700italic.eot');\n  src: url('/assets/fonts/Roboto-700italic/Roboto-700italic.eot?#iefix') format('embedded-opentype'),\n       local('Roboto Bold Italic'),\n       local('Roboto-700italic'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.woff2') format('woff2'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.woff') format('woff'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.ttf') format('truetype'),\n       url('/assets/fonts/Roboto-700italic/Roboto-700italic.svg#Roboto') format('svg');\n}\n"
  },
  {
    "path": "assets/data/icons/README.md",
    "content": "# .ICOs\n\nconverted using https://www.icoconverter.com/\n"
  },
  {
    "path": "assets/data/icons/generate_ico.sh",
    "content": "#!/bin/sh\n\n# Traymenu icons. Sometimes the wrong size is selected, so leave just one.\nconvert pm_dark_green_512.png -resize 64x64 pm_dark_green_64.png\nconvert pm_dark_blue_512.png -resize 64x64 pm_dark_blue_64.png\nconvert pm_dark_red_512.png -resize 64x64 pm_dark_red_64.png\nconvert pm_dark_yellow_512.png -resize 64x64 pm_dark_yellow_64.png\nconvert pm_light_blue_512.png -resize 64x64 pm_light_blue_64.png\nconvert pm_light_green_512.png -resize 64x64 pm_light_green_64.png\nconvert pm_light_red_512.png -resize 64x64 pm_light_red_64.png\nconvert pm_light_yellow_512.png -resize 64x64 pm_light_yellow_64.png\n\nconvert pm_dark_512.png -colors 256 -define icon:auto-resize=64,48,32,16 pm_dark.ico\nconvert pm_light_512.png -colors 256 -define icon:auto-resize=64,48,32,16 pm_light.ico\n"
  },
  {
    "path": "assets/data/img/flags/LICENSE.txt",
    "content": "Copyright (c) 2017 Go Squared Ltd. http://www.gosquared.com/\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "assets/data/world-50m.json",
    "content": "{\"type\":\"Topology\",\"objects\":{\"land\":{\"type\":\"MultiPolygon\",\"arcs\":[[[0]],[[1]],[[2]],[[3]],[[4]],[[5]],[[6]],[[7]],[[8]],[[9]],[[10]],[[11]],[[12]],[[13]],[[14]],[[15]],[[16]],[[17]],[[18]],[[19]],[[20]],[[21]],[[22]],[[23]],[[24]],[[25]],[[26]],[[27]],[[28]],[[29]],[[30]],[[31]],[[32]],[[33]],[[34]],[[35]],[[36]],[[37]],[[38]],[[39]],[[40]],[[41]],[[42]],[[43]],[[44]],[[45]],[[46]],[[47]],[[48]],[[49]],[[50]],[[51]],[[52]],[[53]],[[54]],[[55]],[[56]],[[57]],[[58]],[[59]],[[60]],[[61]],[[62,63]],[[64,65,66]],[[67]],[[68,69,70,71,72]],[[73,74,75,76,77]],[[78]],[[79]],[[80]],[[81]],[[82]],[[83]],[[84]],[[85]],[[86]],[[87]],[[88]],[[89]],[[90]],[[91]],[[92]],[[93]],[[94]],[[95]],[[96]],[[97]],[[98,99]],[[100]],[[101]],[[102]],[[103]],[[104]],[[105]],[[106]],[[107]],[[108]],[[109]],[[110]],[[111]],[[112]],[[113]],[[114]],[[115,116]],[[117]],[[118]],[[119]],[[120]],[[121]],[[122]],[[123]],[[124]],[[125]],[[126]],[[127]],[[128]],[[129]],[[130]],[[131]],[[132]],[[133],[134]],[[135]],[[136]],[[137]],[[138]],[[139]],[[140]],[[141]],[[142]],[[143]],[[144]],[[145]],[[146]],[[147]],[[148]],[[149]],[[150]],[[151]],[[152]],[[153]],[[154]],[[155]],[[156]],[[157]],[[158]],[[159]],[[160]],[[161]],[[162]],[[163]],[[164]],[[165]],[[166]],[[167]],[[168]],[[169]],[[170]],[[171]],[[172]],[[173]],[[174]],[[175]],[[176]],[[177]],[[178]],[[179]],[[180]],[[181]],[[182]],[[183]],[[184]],[[185]],[[186]],[[187]],[[188]],[[189]],[[190]],[[191]],[[192]],[[193]],[[194]],[[195]],[[196]],[[197]],[[198]],[[199]],[[200]],[[201]],[[202]],[[203]],[[204]],[[205]],[[206,207,208,209,210,211,212]],[[213]],[[214]],[[215]],[[216]],[[217]],[[218]],[[219]],[[220]],[[221]],[[222]],[[223]],[[224]],[[225]],[[226]],[[227]],[[228]],[[229,230,231,232]],[[233],[234]],[[235]],[[236]],[[237]],[[238]],[[239]],[[240]],[[241]],[[242]],[[243]],[[244]],[[245]],[[246]],[[247]],[[248]],[[249]],[[250]],[[251]],[[252]],[[253]],[[254]],[[255]],[[256]],[[257]],[[258]],[[259]],[[260,261,262,263,264,265,266]],[[267]],[[268,269,270,271]],[[272]],[[273]],[[274,275,276,277,278,279,280,281,282,283]],[[284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306]],[[307]],[[308,309]],[[310]],[[311]],[[312]],[[313]],[[314]],[[315]],[[316]],[[317]],[[318]],[[319]],[[320]],[[321]],[[322]],[[323,324]],[[325]],[[326]],[[327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946],[947],[948],[949],[950],[951],[952,953,954,955],[956],[957,958],[959],[960],[961,962,963,964,965,966],[967],[968],[969],[970],[971],[972],[973],[974],[975,976],[977],[978],[979],[980],[981],[982],[983,984,985,986],[987],[988],[989],[990],[991],[992],[993],[994],[995],[996],[997],[998],[999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014],[1015],[1016],[1017],[1018],[1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029],[1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094],[1095],[1096],[1097],[1098],[1099],[1100],[1101],[1102],[1103],[1104],[1105],[1106],[1107],[1108],[1109],[1110],[1111],[1112],[1113],[1114],[1115],[1116],[1117],[1118],[1119],[1120],[1121],[1122],[1123],[1124],[1125],[1126],[1127],[1128],[1129],[1130],[1131],[1132],[1133],[1134],[1135],[1136],[1137],[1138],[1139],[1140],[1141]],[[1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272],[1273,1274,1275,1276,1277],[1278,1279,1280,1281,1282],[1283,1284,1285,1286,1287],[1288],[1289],[1290,1291,1292,1293],[1294,1295,1296,1297,1298,1299],[1300],[1301,1302,1303,1304],[1305],[1306,1307,1308,1309,1310,1311,1312,1313],[1314],[1315,1316,1317],[1318],[1319],[1320],[1321],[1322],[1323],[1324],[1325],[1326],[1327],[1328],[1329],[1330],[1331],[1332],[1333],[1334],[1335],[1336],[1337],[1338],[1339],[1340],[1341],[1342],[1343],[1344],[1345],[1346],[1347],[1348],[1349],[1350],[1351,1352,1353,1354],[1355],[1356],[1357],[1358],[1359],[1360,1361,1362,1363],[1364],[1365],[1366],[1367],[1368],[1369,1370,1371,1372,1373,1374,1375,1376],[1377],[1378],[1379,1380,1381,1382],[1383,1384,1385,1386],[1387],[1388],[1389],[1390],[1391],[1392],[1393],[1394],[1395],[1396,1397,1398,1399],[1400],[1401],[1402],[1403],[1404],[1405],[1406],[1407],[1408],[1409],[1410],[1411],[1412],[1413],[1414],[1415],[1416],[1417],[1418],[1419],[1420],[1421],[1422],[1423],[1424],[1425],[1426],[1427],[1428]],[[1429]],[[1430]],[[1431]],[[1432]],[[1433]],[[1434]],[[1435]],[[1436]],[[1437]],[[1438]],[[1439]],[[1440]],[[1441]],[[1442]],[[1443]],[[1444]],[[1445]],[[1446]],[[1447]],[[1448,1449]],[[1450]],[[1451]],[[1452]],[[1453]],[[1454]],[[1455]],[[1456,1457,1458]],[[1459]],[[1460]],[[1461]],[[1462]],[[1463]],[[1464]],[[1465]],[[1466]],[[1467]],[[1468]],[[1469]],[[1470]],[[1471],[1472]],[[1473,1474,1475,1476,1477,1478]],[[1479]],[[1480,1481,1482,1483,1484,1485,1486,1487,1488,1489]],[[1490,1491,1492,1493,1494,1495,1496,1497]],[[1498]],[[1499]],[[1500,1501]],[[1502]],[[1503,1504,1505]],[[1506]],[[1507,1508]],[[1509,1510,1511,1512]],[[1513,1514,1515,1516]],[[1517,1518,1519,1520]],[[1521,1522,1523]],[[1524,1525,1526]],[[1527,1528,1529,1530,1531,1532,1533]],[[1534]],[[1535]],[[1536,1537,1538,1539,1540]],[[1541]],[[1542]],[[1543]],[[1544,1545]],[[1546]],[[1547,1548,1549,1550,1551,1552]],[[1553]],[[1554]],[[1555,1556,1557,1558,1559,1560,1561,1562]],[[1563,1564,1565]],[[1566,1567,1568]],[[1569]],[[1570,1571,1572]],[[1573,1574,1575]],[[1576]],[[1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587]],[[1588]],[[1589,1590,1591,1592,1593,1594]],[[1595,1596,1597,1598,1599]],[[1600]],[[1601,1602,1603]],[[1604,1605,1606]],[[1607]],[[1608]],[[1609]],[[1610]],[[1611]],[[1612]],[[1613,1614,1615,1616]],[[1617,1618,1619,1620,1621]],[[1622]],[[1623,1624,1625]],[[1626,1627,1628]],[[1629]],[[1630,1631,1632]],[[1633]],[[1634,1635,1636]],[[1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664]],[[1665]],[[1666]],[[1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688]],[[1689]],[[1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702]],[[1703,1704,1705]],[[1706,1707,1708]],[[1709]],[[1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720]],[[1721]],[[1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791]],[[1792,1793,1794,1795,1796]],[[1797,1798,1799]],[[1800,1801]],[[1802,1803,1804,1805]],[[1806,1807]],[[1808]],[[1809]],[[1810]],[[1811,1812,1813,1814]],[[1815,1816,1817]],[[1818,1819]],[[1820,1821,1822,1823]],[[1824,1825,1826,1827,1828,1829,1830]],[[1831,1832,1833]],[[1834]],[[1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851]],[[1852]],[[1853]],[[1854,1855,1856,1857]],[[1858,1859,1860,1861,1862,1863,1864,1865]],[[1866,1867]],[[1868,1869,1870]],[[1871,1872]],[[1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990],[1991],[1992]],[[1993]],[[1994,1995]],[[1996]],[[1997,1998,1999,2000]],[[2001]],[[2002]],[[2003]],[[2004]],[[2005,2006,2007,2008,2009,2010,2011]],[[2012,2013]],[[2014]],[[2015,2016]],[[2017]],[[2018]],[[2019]],[[2020]],[[2021]],[[2022]],[[2023]],[[2024]],[[2025]],[[2026]],[[2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073]],[[2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090]],[[2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112]],[[2113]],[[2114]],[[2115,2116,2117,2118]],[[2119]],[[2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130]],[[2131,2132,2133,2134,2135,2136,2137,2138]],[[2139]],[[2140]],[[2141]],[[2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156]],[[2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196],[2197]],[[2198]],[[2199]],[[2200]],[[2201,2202,2203,2204]],[[2205]],[[2206]],[[2207,2208]],[[2209]],[[2210]],[[2211]],[[2212,2213,2214]],[[2215,2216,2217,2218]],[[2219,2220,2221,2222,2223]],[[2224]],[[2225]],[[2226]],[[2227]]]},\"countries\":{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Afghanistan\",\"name\":\"Afghanistan\",\"postal\":\"AF\",\"pop_est\":28400000,\"iso_a2\":\"AF\",\"iso_a3\":\"AFG\"},\"id\":4,\"arcs\":[[2228,2229,2230,2231,2232,2233,2234]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Angola\",\"name\":\"Angola\",\"postal\":\"AO\",\"pop_est\":12799293,\"iso_a2\":\"AO\",\"iso_a3\":\"AGO\"},\"id\":24,\"arcs\":[[[2235,2236,1193,2237]],[[1195,2238,2239]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Albania\",\"name\":\"Albania\",\"postal\":\"AL\",\"pop_est\":3639453,\"iso_a2\":\"AL\",\"iso_a3\":\"ALB\"},\"id\":8,\"arcs\":[[2240,2241,2242,1236,2243,2244,1385,2245,2246]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"United Arab Emirates\",\"name\":\"United Arab Emirates\",\"postal\":\"AE\",\"pop_est\":4798491,\"iso_a2\":\"AE\",\"iso_a3\":\"ARE\"},\"id\":784,\"arcs\":[[1176,2247,2248,1174,2249]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Argentina\",\"name\":\"Argentina\",\"postal\":\"AR\",\"pop_est\":40913584,\"iso_a2\":\"AR\",\"iso_a3\":\"ARG\"},\"id\":32,\"arcs\":[[[31]],[[2250,115]],[[2251,2252,2253,670,2254,2255]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Armenia\",\"name\":\"Armenia\",\"postal\":\"ARM\",\"pop_est\":2967004,\"iso_a2\":\"AM\",\"iso_a3\":\"ARM\"},\"id\":51,\"arcs\":[[2256,2257,2258,2259,2260]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Antarctica\",\"name\":\"Antarctica\",\"postal\":\"AQ\",\"pop_est\":3802,\"iso_a2\":\"AQ\",\"iso_a3\":\"ATA\"},\"id\":10,\"arcs\":[[[2]],[[7]],[[8]],[[6]],[[5]],[[9]],[[11]],[[3]],[[10]],[[4]],[[0]],[[1]],[[12]],[[16]],[[17]],[[15]],[[14]],[[13]],[[19]],[[20]],[[18]],[[21]],[[22]],[[34]],[[33]],[[36]],[[37]],[[38]],[[35]],[[39]],[[40]],[[41]],[[42]],[[43]],[[32]],[[44]],[[23]],[[25]],[[24]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"French Southern and Antarctic Lands\",\"name\":\"Fr. S. Antarctic Lands\",\"postal\":\"TF\",\"pop_est\":140,\"iso_a2\":\"TF\",\"iso_a3\":\"ATF\"},\"id\":260,\"arcs\":[[119]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Australia\",\"name\":\"Australia\",\"postal\":\"AU\",\"pop_est\":21262641,\"iso_a2\":\"AU\",\"iso_a3\":\"AUS\"},\"id\":36,\"arcs\":[[[132]],[[127]],[[128]],[[129]],[[135]],[[136]],[[148]],[[239]],[[242]],[[243]],[[233]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Austria\",\"name\":\"Austria\",\"postal\":\"A\",\"pop_est\":8210281,\"iso_a2\":\"AT\",\"iso_a3\":\"AUT\"},\"id\":40,\"arcs\":[[2261,2262,2263,2264,2265,2266,2267,1363,2268,2269,2270]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Azerbaijan\",\"name\":\"Azerbaijan\",\"postal\":\"AZ\",\"pop_est\":8238672,\"iso_a2\":\"AZ\",\"iso_a3\":\"AZE\"},\"id\":31,\"arcs\":[[[2271,2272,-2258]],[[1274,2273,-2261,2274,2275]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Burundi\",\"name\":\"Burundi\",\"postal\":\"BI\",\"pop_est\":8988091,\"iso_a2\":\"BI\",\"iso_a3\":\"BDI\"},\"id\":108,\"arcs\":[[2276,2277,1309,2278,2279,2280]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Belgium\",\"name\":\"Belgium\",\"postal\":\"B\",\"pop_est\":10414336,\"iso_a2\":\"BE\",\"iso_a3\":\"BEL\"},\"id\":56,\"arcs\":[[2281,2282,2283,2284,2285,1249,2286,2287]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Benin\",\"name\":\"Benin\",\"postal\":\"BJ\",\"pop_est\":8791832,\"iso_a2\":\"BJ\",\"iso_a3\":\"BEN\"},\"id\":204,\"arcs\":[[2288,1201,2289,2290,2291]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Burkina Faso\",\"name\":\"Burkina Faso\",\"postal\":\"BF\",\"pop_est\":15746232,\"iso_a2\":\"BF\",\"iso_a3\":\"BFA\"},\"id\":854,\"arcs\":[[2292,-2291,2293,2294,2295,2296]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Bangladesh\",\"name\":\"Bangladesh\",\"postal\":\"BD\",\"pop_est\":156050883,\"iso_a2\":\"BD\",\"iso_a3\":\"BGD\"},\"id\":50,\"arcs\":[[[1430]],[[2297,1164,2298]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Bulgaria\",\"name\":\"Bulgaria\",\"postal\":\"BG\",\"pop_est\":7204687,\"iso_a2\":\"BG\",\"iso_a3\":\"BGR\"},\"id\":100,\"arcs\":[[1233,2299,2300,2301,2302,2303]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"The Bahamas\",\"name\":\"Bahamas\",\"postal\":\"BS\",\"pop_est\":309156,\"iso_a2\":\"BS\",\"iso_a3\":\"BHS\"},\"id\":44,\"arcs\":[[[67]],[[1429]],[[1431]],[[1437]],[[1434]],[[1433]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Bosnia and Herzegovina\",\"name\":\"Bosnia and Herz.\",\"postal\":\"BiH\",\"pop_est\":4613414,\"iso_a2\":\"BA\",\"iso_a3\":\"BIH\"},\"id\":70,\"arcs\":[[2304,2305,2306,1239,2307]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Belarus\",\"name\":\"Belarus\",\"postal\":\"BY\",\"pop_est\":9648533,\"iso_a2\":\"BY\",\"iso_a3\":\"BLR\"},\"id\":112,\"arcs\":[[2308,2309,2310,2311,2312]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Belize\",\"name\":\"Belize\",\"postal\":\"BZ\",\"pop_est\":307899,\"iso_a2\":\"BZ\",\"iso_a3\":\"BLZ\"},\"id\":84,\"arcs\":[[2313,2314,657]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Bolivia\",\"name\":\"Bolivia\",\"postal\":\"BO\",\"pop_est\":9775246,\"iso_a2\":\"BO\",\"iso_a3\":\"BOL\"},\"id\":68,\"arcs\":[[2315,-2256,2316,2317,2318,964,2319,2320,2321]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Brazil\",\"name\":\"Brazil\",\"postal\":\"BR\",\"pop_est\":198739269,\"iso_a2\":\"BR\",\"iso_a3\":\"BRA\"},\"id\":76,\"arcs\":[[[193]],[[194]],[[156]],[[247]],[[249]],[[251]],[[2322,2323,668,2324,2325,955,2326,2327,-2253,2328,2329,2330,-2322,2331,2332,2333,2334]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Brunei\",\"name\":\"Brunei\",\"postal\":\"BN\",\"pop_est\":388190,\"iso_a2\":\"BN\",\"iso_a3\":\"BRN\"},\"id\":96,\"arcs\":[[[265,2335]],[[2336,2337,264]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Bhutan\",\"name\":\"Bhutan\",\"postal\":\"BT\",\"pop_est\":691141,\"iso_a2\":\"BT\",\"iso_a3\":\"BTN\"},\"id\":64,\"arcs\":[[2338,2339]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Botswana\",\"name\":\"Botswana\",\"postal\":\"BW\",\"pop_est\":1990876,\"iso_a2\":\"BW\",\"iso_a3\":\"BWA\"},\"id\":72,\"arcs\":[[2340,2341,2342]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Central African Republic\",\"name\":\"Central African Rep.\",\"postal\":\"CF\",\"pop_est\":4511488,\"iso_a2\":\"CF\",\"iso_a3\":\"CAF\"},\"id\":140,\"arcs\":[[2343,2344,2345,2346,2347,2348]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Canada\",\"name\":\"Canada\",\"postal\":\"CA\",\"pop_est\":33487208,\"iso_a2\":\"CA\",\"iso_a3\":\"CAN\"},\"id\":124,\"arcs\":[[[1500,1501]],[[2216,2217,2218,2215]],[[1490,1491,1492,1493,1494,1495,1496,1497]],[[1480,1481,1482,1483,1484,1485,1486,1487,1488,1489]],[[500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,2349,2350,2351,986,2352,2353,2354,2355,2356,2357,2358,2359]],[[1473,1474,1475,1476,1477,1478]],[[2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156]],[[2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196]],[[2201,2202,2203,2204]],[[1513,1514,1515,1516]],[[1517,1518,1519,1520]],[[1524,1525,1526]],[[1527,1528,1529,1530,1531,1532,1533]],[[1563,1564,1565]],[[1994,1995]],[[1800,1801]],[[1854,1855,1856,1857]],[[1820,1821,1822,1823]],[[1858,1859,1860,1861,2360,1863,1864,1865]],[[1831,1832,1833]],[[1834]],[[1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851]],[[1868,1869,1870]],[[1871,1872]],[[1806,1807]],[[1815,1816,1817]],[[1802,1803,1804,1805]],[[1818,1819]],[[1811,1812,1813,1814]],[[2012,2013]],[[2015,2016]],[[2005,2006,2007,2008,2009,2010,2011]],[[2361,2362,2363,1000,1001,1002,1003,1004,1005,1006,1007,2364,2365,1027,1028,1029,1019,1020,2366,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,2377,2378,2379,2380,2381,2382,2383,2384,2385,2386,2387,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499]],[[2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073]],[[2115,2116,2117,2118]],[[2131,2132,2133,2134,2135,2136,2137,2138]],[[1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990]],[[2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112]],[[2026]],[[2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130]],[[2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090]],[[1613,1614,1615,1616]],[[1617,1618,1619,1620,1621]],[[1689]],[[1703,1704,1705]],[[1706,1707,1708]],[[1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702]],[[1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664]],[[1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688]],[[1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720]],[[1626,1627,1628]],[[1633]],[[1634,1635,1636]],[[1623,1624,1625]],[[1630,1631,1632]],[[267]],[[268,269,270,271]],[[274,275,276,277,278,279,280,281,282,283]],[[308,309]],[[284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306]],[[1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Switzerland\",\"name\":\"Switzerland\",\"postal\":\"CH\",\"pop_est\":7604467,\"iso_a2\":\"CH\",\"iso_a3\":\"CHE\"},\"id\":756,\"arcs\":[[1362,-2268,2388,-2266,2389,2390,2391,2392,2393]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Chile\",\"name\":\"Chile\",\"postal\":\"CL\",\"pop_est\":16601707,\"iso_a2\":\"CL\",\"iso_a3\":\"CHL\"},\"id\":152,\"arcs\":[[[30]],[[29]],[[28]],[[27]],[[114]],[[113]],[[-2251,116]],[[149]],[[121]],[[117]],[[122]],[[120]],[[118]],[[123]],[[125]],[[124]],[[131]],[[-2255,671,2394,-2317]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"China\",\"name\":\"China\",\"postal\":\"CN\",\"pop_est\":1338612970,\"iso_a2\":\"CN\",\"iso_a3\":\"CHN\"},\"id\":156,\"arcs\":[[[101]],[[1441]],[[2395,1352,2396,2397,2398,1152,2399,1155,2400,1157,2401,2402,2403,2404,-2340,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,-2229,2420,2421,2422,2423,2424,2425]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Ivory Coast\",\"name\":\"Côte d'Ivoire\",\"postal\":\"CI\",\"pop_est\":20617068,\"iso_a2\":\"CI\",\"iso_a3\":\"CIV\"},\"id\":384,\"arcs\":[[-2296,2426,1206,2427,2428,2429]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Cameroon\",\"name\":\"Cameroon\",\"postal\":\"CM\",\"pop_est\":18879301,\"iso_a2\":\"CM\",\"iso_a3\":\"CMR\"},\"id\":120,\"arcs\":[[-2348,2430,2431,2432,1199,2433,2434,2435]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Democratic Republic of the Congo\",\"name\":\"Dem. Rep. Congo\",\"postal\":\"DRC\",\"pop_est\":68692542,\"iso_a2\":\"CD\",\"iso_a3\":\"COD\"},\"id\":180,\"arcs\":[[2436,2437,2438,1316,2439,2440,1304,2441,2442,2443,2444,1290,2445,2446,-2280,2447,1311,2448,2449,-2238,1194,-2240,2450,-2346]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Republic of Congo\",\"name\":\"Congo\",\"postal\":\"CG\",\"pop_est\":4012809,\"iso_a2\":\"CG\",\"iso_a3\":\"COG\"},\"id\":178,\"arcs\":[[-2451,-2239,1196,2451,-2431,-2347]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Colombia\",\"name\":\"Colombia\",\"postal\":\"CO\",\"pop_est\":45644023,\"iso_a2\":\"CO\",\"iso_a3\":\"COL\"},\"id\":170,\"arcs\":[[2452,-2333,2453,2454,674,2455,663]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Comoros\",\"name\":\"Comoros\",\"postal\":\"KM\",\"pop_est\":752438,\"iso_a2\":\"KM\",\"iso_a3\":\"COM\"},\"id\":174,\"arcs\":[[[238]],[[240]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Cape Verde\",\"name\":\"Cape Verde\",\"postal\":\"CV\",\"pop_est\":429474,\"iso_a2\":\"CV\",\"iso_a3\":\"CPV\"},\"id\":132,\"arcs\":[[[81]],[[83]],[[86]],[[85]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Costa Rica\",\"name\":\"Costa Rica\",\"postal\":\"CR\",\"pop_est\":4253877,\"iso_a2\":\"CR\",\"iso_a3\":\"CRI\"},\"id\":188,\"arcs\":[[661,2456,676,2457]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Cuba\",\"name\":\"Cuba\",\"postal\":\"CU\",\"pop_est\":11451652,\"iso_a2\":\"CU\",\"iso_a3\":\"CUB\"},\"id\":192,\"arcs\":[[[325]],[[326]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Northern Cyprus\",\"name\":\"N. Cyprus\",\"postal\":\"CN\",\"pop_est\":265100,\"iso_a2\":\"-99\",\"iso_a3\":\"-99\"},\"id\":-99,\"arcs\":[[2458,1449]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Cyprus\",\"name\":\"Cyprus\",\"postal\":\"CY\",\"pop_est\":531640,\"iso_a2\":\"CY\",\"iso_a3\":\"CYP\"},\"id\":196,\"arcs\":[[-2459,1448]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Czech Republic\",\"name\":\"Czech Rep.\",\"postal\":\"CZ\",\"pop_est\":10211904,\"iso_a2\":\"CZ\",\"iso_a3\":\"CZE\"},\"id\":203,\"arcs\":[[2459,2460,-2271,2461]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Germany\",\"name\":\"Germany\",\"postal\":\"D\",\"pop_est\":82329758,\"iso_a2\":\"DE\",\"iso_a3\":\"DEU\"},\"id\":276,\"arcs\":[[[2206]],[[2462,1256,2463,2464,-2462,-2270,2465,1361,-2394,-2393,-2392,2466,2467,-2284,2468,1252,2469,2470]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Djibouti\",\"name\":\"Djibouti\",\"postal\":\"DJ\",\"pop_est\":516055,\"iso_a2\":\"DJ\",\"iso_a3\":\"DJI\"},\"id\":262,\"arcs\":[[2471,2472,2473,1185]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Dominica\",\"name\":\"Dominica\",\"postal\":\"DM\",\"pop_est\":72660,\"iso_a2\":\"DM\",\"iso_a3\":\"DMA\"},\"id\":212,\"arcs\":[[80]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Denmark\",\"name\":\"Denmark\",\"postal\":\"DK\",\"pop_est\":5500510,\"iso_a2\":\"DK\",\"iso_a3\":\"DNK\"},\"id\":208,\"arcs\":[[[1534]],[[1542]],[[1546]],[[1543]],[[2474,-2471,2475,1254]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Dominican Republic\",\"name\":\"Dominican Rep.\",\"postal\":\"DO\",\"pop_est\":9650054,\"iso_a2\":\"DO\",\"iso_a3\":\"DOM\"},\"id\":214,\"arcs\":[[2476,98]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Algeria\",\"name\":\"Algeria\",\"postal\":\"DZ\",\"pop_est\":34178188,\"iso_a2\":\"DZ\",\"iso_a3\":\"DZA\"},\"id\":12,\"arcs\":[[2477,2478,2479,2480,2481,2482,2483,1220]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Ecuador\",\"name\":\"Ecuador\",\"postal\":\"EC\",\"pop_est\":14573101,\"iso_a2\":\"EC\",\"iso_a3\":\"ECU\"},\"id\":218,\"arcs\":[[[173]],[[195]],[[188]],[[2484,673,-2455]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Egypt\",\"name\":\"Egypt\",\"postal\":\"EG\",\"pop_est\":83082869,\"iso_a2\":\"EG\",\"iso_a3\":\"EGY\"},\"id\":818,\"arcs\":[[2485,2486,1182,2487,2488,1223]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Eritrea\",\"name\":\"Eritrea\",\"postal\":\"ER\",\"pop_est\":5647168,\"iso_a2\":\"ER\",\"iso_a3\":\"ERI\"},\"id\":232,\"arcs\":[[[1184,-2474,2489,2490]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Spain\",\"name\":\"Spain\",\"postal\":\"E\",\"pop_est\":40525002,\"iso_a2\":\"ES\",\"iso_a3\":\"ESP\"},\"id\":724,\"arcs\":[[[1443]],[[1445]],[[1446]],[[1438]],[[1460]],[[1465]],[[2491,-2493,2493,1245,2494,1247]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Estonia\",\"name\":\"Estonia\",\"postal\":\"EST\",\"pop_est\":1299371,\"iso_a2\":\"EE\",\"iso_a3\":\"EST\"},\"id\":233,\"arcs\":[[[1609]],[[1554]],[[2495,2496,1397,2497,2498,2499,1268]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Ethiopia\",\"name\":\"Ethiopia\",\"postal\":\"ET\",\"pop_est\":85237338,\"iso_a2\":\"ET\",\"iso_a3\":\"ETH\"},\"id\":231,\"arcs\":[[-2473,2500,2501,2502,2503,2504,-2490]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Finland\",\"name\":\"Finland\",\"postal\":\"FIN\",\"pop_est\":5250275,\"iso_a2\":\"FI\",\"iso_a3\":\"FIN\"},\"id\":246,\"arcs\":[[2505,1270,2506,2507]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Fiji\",\"name\":\"Fiji\",\"postal\":\"FJ\",\"pop_est\":944720,\"iso_a2\":\"FJ\",\"iso_a3\":\"FJI\"},\"id\":242,\"arcs\":[[[142]],[[146]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Falkland Islands\",\"name\":\"Falkland Is.\",\"postal\":\"FK\",\"pop_est\":3140,\"iso_a2\":\"FK\",\"iso_a3\":\"FLK\"},\"id\":238,\"arcs\":[[[151]],[[150]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"France\",\"name\":\"France\",\"postal\":\"F\",\"pop_est\":64057792,\"iso_a2\":\"FR\",\"iso_a3\":\"FRA\"},\"id\":250,\"arcs\":[[[139]],[[-2324,2508,667]],[[87]],[[82]],[[84]],[[1459]],[[2509,-2467,-2391,2510,2511,1244,-2494,-2513,-2492,1248,-2286]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Faroe Islands\",\"name\":\"Faeroe Is.\",\"postal\":\"FO\",\"pop_est\":48856,\"iso_a2\":\"FO\",\"iso_a3\":\"FRO\"},\"id\":234,\"arcs\":[[1853]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Gabon\",\"name\":\"Gabon\",\"postal\":\"GA\",\"pop_est\":1514993,\"iso_a2\":\"GA\",\"iso_a3\":\"GAB\"},\"id\":266,\"arcs\":[[-2452,1197,2513,-2432]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"United Kingdom\",\"name\":\"United Kingdom\",\"postal\":\"GB\",\"pop_est\":62262000,\"iso_a2\":\"GB\",\"iso_a3\":\"GBR\"},\"id\":826,\"arcs\":[[[2205]],[[2514,2208]],[[1553]],[[1569]],[[1600]],[[1607]],[[2209]],[[1993]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Georgia\",\"name\":\"Georgia\",\"postal\":\"GE\",\"pop_est\":4615807,\"iso_a2\":\"GE\",\"iso_a3\":\"GEO\"},\"id\":268,\"arcs\":[[-2275,-2260,2515,1229,2516]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Ghana\",\"name\":\"Ghana\",\"postal\":\"GH\",\"pop_est\":23832495,\"iso_a2\":\"GH\",\"iso_a3\":\"GHA\"},\"id\":288,\"arcs\":[[2517,1203,2518,1205,-2427,-2295]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Guinea\",\"name\":\"Guinea\",\"postal\":\"GN\",\"pop_est\":10057975,\"iso_a2\":\"GN\",\"iso_a3\":\"GIN\"},\"id\":324,\"arcs\":[[2519,-2429,2520,2521,1209,2522,2523]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Gambia\",\"name\":\"Gambia\",\"postal\":\"GM\",\"pop_est\":1782893,\"iso_a2\":\"GM\",\"iso_a3\":\"GMB\"},\"id\":270,\"arcs\":[[1212,2524]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Guinea Bissau\",\"name\":\"Guinea-Bissau\",\"postal\":\"GW\",\"pop_est\":1533964,\"iso_a2\":\"GW\",\"iso_a3\":\"GNB\"},\"id\":624,\"arcs\":[[1210,2525,-2523]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Equatorial Guinea\",\"name\":\"Eq. Guinea\",\"postal\":\"GQ\",\"pop_est\":650702,\"iso_a2\":\"GQ\",\"iso_a3\":\"GNQ\"},\"id\":226,\"arcs\":[[[1198,-2433,-2514]],[[106]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Greece\",\"name\":\"Greece\",\"postal\":\"GR\",\"pop_est\":10737428,\"iso_a2\":\"GR\",\"iso_a3\":\"GRC\"},\"id\":300,\"arcs\":[[[1451]],[[1447]],[[1454]],[[1455]],[[1462]],[[1463]],[[1461]],[[1464]],[[1235,-2243,2526,-2301,2527]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Greenland\",\"name\":\"Greenland\",\"postal\":\"GL\",\"pop_est\":57600,\"iso_a2\":\"GL\",\"iso_a3\":\"GRL\"},\"id\":304,\"arcs\":[[[2017]],[[2018]],[[2003]],[[2025]],[[1622]],[[1709]],[[307]],[[312]],[[2113]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Guatemala\",\"name\":\"Guatemala\",\"postal\":\"GT\",\"pop_est\":13276517,\"iso_a2\":\"GT\",\"iso_a3\":\"GTM\"},\"id\":320,\"arcs\":[[-2314,658,2528,2529,680,2530]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Guam\",\"name\":\"Guam\",\"postal\":\"GU\",\"pop_est\":178430,\"iso_a2\":\"GU\",\"iso_a3\":\"GUM\"},\"id\":316,\"arcs\":[[88]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Guyana\",\"name\":\"Guyana\",\"postal\":\"GY\",\"pop_est\":772298,\"iso_a2\":\"GY\",\"iso_a3\":\"GUY\"},\"id\":328,\"arcs\":[[2531,-2335,2532,665]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Hong Kong S.A.R.\",\"name\":\"Hong Kong\",\"postal\":\"HK\",\"pop_est\":7061200,\"iso_a2\":\"HK\",\"iso_a3\":\"HKG\"},\"id\":344,\"arcs\":[[-2400,2533,1154]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Honduras\",\"name\":\"Honduras\",\"postal\":\"HN\",\"pop_est\":7792854,\"iso_a2\":\"HN\",\"iso_a3\":\"HND\"},\"id\":340,\"arcs\":[[2534,678,2535,-2529,659]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Croatia\",\"name\":\"Croatia\",\"postal\":\"HR\",\"pop_est\":4489409,\"iso_a2\":\"HR\",\"iso_a3\":\"HRV\"},\"id\":191,\"arcs\":[[[-2307,2536,1238]],[[2537,-2308,1240,2538,2539]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Haiti\",\"name\":\"Haiti\",\"postal\":\"HT\",\"pop_est\":9035536,\"iso_a2\":\"HT\",\"iso_a3\":\"HTI\"},\"id\":332,\"arcs\":[[[-2477,99]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Hungary\",\"name\":\"Hungary\",\"postal\":\"HU\",\"pop_est\":9905596,\"iso_a2\":\"HU\",\"iso_a3\":\"HUN\"},\"id\":348,\"arcs\":[[2540,2541,2542,-2540,2543,-2263,2544]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Indonesia\",\"name\":\"Indonesia\",\"postal\":\"INDO\",\"pop_est\":240271522,\"iso_a2\":\"ID\",\"iso_a3\":\"IDN\"},\"id\":360,\"arcs\":[[[245]],[[203]],[[2545,207,2546,2547,2548,210,2549,2550]],[[214]],[[219]],[[218]],[[223]],[[220]],[[216]],[[213]],[[217]],[[225]],[[226]],[[228]],[[153]],[[155]],[[227]],[[164]],[[167]],[[169]],[[157]],[[171]],[[158]],[[162]],[[159]],[[160]],[[175]],[[176]],[[177]],[[178]],[[179]],[[182]],[[181]],[[183]],[[180]],[[185]],[[184]],[[187]],[[190]],[[189]],[[192]],[[191]],[[2551,2552,2553,2554,232]],[[197]],[[196]],[[198]],[[248]],[[253]],[[254]],[[255]],[[256]],[[252]],[[257]],[[186]],[[102]],[[259]],[[103]],[[104]],[[107]],[[2555,261,2556]],[[105]],[[258]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Isle of Man\",\"name\":\"Isle of Man\",\"postal\":\"IM\",\"pop_est\":76512,\"iso_a2\":\"IM\",\"iso_a3\":\"IMN\"},\"id\":833,\"arcs\":[[2200]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"India\",\"name\":\"India\",\"postal\":\"IND\",\"pop_est\":1166079220,\"iso_a2\":\"IN\",\"iso_a3\":\"IND\"},\"id\":356,\"arcs\":[[[111]],[[52]],[[92]],[[-2412,2557,-2410,2558,-2408,2559,-2406,-2339,-2405,2560,-2299,1165,2561,2562,2563,-2417,2564,-2415,2565,-2413]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Ireland\",\"name\":\"Ireland\",\"postal\":\"IRL\",\"pop_est\":4203200,\"iso_a2\":\"IE\",\"iso_a3\":\"IRL\"},\"id\":372,\"arcs\":[[2207,-2515]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Iran\",\"name\":\"Iran\",\"postal\":\"IRN\",\"pop_est\":66429284,\"iso_a2\":\"IR\",\"iso_a3\":\"IRN\"},\"id\":364,\"arcs\":[[[1435]],[[-2257,-2274,1275,2566,-2232,2567,2568,2569,1168,2570,2571,-2272]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Iraq\",\"name\":\"Iraq\",\"postal\":\"IRQ\",\"pop_est\":31129225,\"iso_a2\":\"IQ\",\"iso_a3\":\"IRQ\"},\"id\":368,\"arcs\":[[-2571,1169,2572,2573,2574,2575,2576]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Iceland\",\"name\":\"Iceland\",\"postal\":\"IS\",\"pop_est\":306694,\"iso_a2\":\"IS\",\"iso_a3\":\"ISL\"},\"id\":352,\"arcs\":[[1852]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Israel\",\"name\":\"Israel\",\"postal\":\"IS\",\"pop_est\":7233701,\"iso_a2\":\"IL\",\"iso_a3\":\"ISR\"},\"id\":376,\"arcs\":[[2577,2578,2579,2580,2581,1181,-2487,2582,1225,2583,2584]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Italy\",\"name\":\"Italy\",\"postal\":\"I\",\"pop_est\":58126212,\"iso_a2\":\"IT\",\"iso_a3\":\"ITA\"},\"id\":380,\"arcs\":[[[1452]],[[1466]],[[2585,1242,-2511,-2390,-2265]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Jamaica\",\"name\":\"Jamaica\",\"postal\":\"J\",\"pop_est\":2825928,\"iso_a2\":\"JM\",\"iso_a3\":\"JAM\"},\"id\":388,\"arcs\":[[97]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Jordan\",\"name\":\"Jordan\",\"postal\":\"J\",\"pop_est\":6342948,\"iso_a2\":\"JO\",\"iso_a3\":\"JOR\"},\"id\":400,\"arcs\":[[2586,1180,-2582,-2581,-2580,2587,2588,-2578,2589,-2575]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Japan\",\"name\":\"Japan\",\"postal\":\"J\",\"pop_est\":127078679,\"iso_a2\":\"JP\",\"iso_a3\":\"JPN\"},\"id\":392,\"arcs\":[[[1432]],[[1444]],[[1467]],[[1470]],[[1450]],[[1453]],[[1471]],[[1499]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Siachen Glacier\",\"name\":\"Siachen Glacier\",\"postal\":\"SG\",\"pop_est\":6000,\"iso_a2\":\"-99\",\"iso_a3\":\"-99\"},\"id\":-99,\"arcs\":[[-2563,2590,-2419]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Kazakhstan\",\"name\":\"Kazakhstan\",\"postal\":\"KZ\",\"pop_est\":15399437,\"iso_a2\":\"KZ\",\"iso_a3\":\"KAZ\"},\"id\":398,\"arcs\":[[[2591,2592,2593,1372]],[[-2423,2594,2595,2596,1376,2597,2598,2599,1277,2600]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Kenya\",\"name\":\"Kenya\",\"postal\":\"KE\",\"pop_est\":39002772,\"iso_a2\":\"KE\",\"iso_a3\":\"KEN\"},\"id\":404,\"arcs\":[[2601,1188,2602,2603,1299,2604,2605,2606,-2503]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Kyrgyzstan\",\"name\":\"Kyrgyzstan\",\"postal\":\"KG\",\"pop_est\":5431747,\"iso_a2\":\"KG\",\"iso_a3\":\"KGZ\"},\"id\":417,\"arcs\":[[-2422,2607,2608,-2595]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Cambodia\",\"name\":\"Cambodia\",\"postal\":\"KH\",\"pop_est\":14494293,\"iso_a2\":\"KH\",\"iso_a3\":\"KHM\"},\"id\":116,\"arcs\":[[1159,2609,2610,2611]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"South Korea\",\"name\":\"Korea\",\"postal\":\"KR\",\"pop_est\":48508972,\"iso_a2\":\"KR\",\"iso_a3\":\"KOR\"},\"id\":410,\"arcs\":[[[1469]],[[1150,2612]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Kosovo\",\"name\":\"Kosovo\",\"postal\":\"KO\",\"pop_est\":1804838,\"iso_a2\":\"-99\",\"iso_a3\":\"-99\"},\"id\":-99,\"arcs\":[[2613,-2241,2614,2615]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Kuwait\",\"name\":\"Kuwait\",\"postal\":\"KW\",\"pop_est\":2691158,\"iso_a2\":\"KW\",\"iso_a3\":\"KWT\"},\"id\":414,\"arcs\":[[[1442]],[[2616,-2573,1170]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Laos\",\"name\":\"Lao PDR\",\"postal\":\"LA\",\"pop_est\":6834942,\"iso_a2\":\"LA\",\"iso_a3\":\"LAO\"},\"id\":418,\"arcs\":[[2617,-2611,2618,2619,-2403]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Lebanon\",\"name\":\"Lebanon\",\"postal\":\"LB\",\"pop_est\":4017095,\"iso_a2\":\"LB\",\"iso_a3\":\"LBN\"},\"id\":422,\"arcs\":[[-2584,1226,2620]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Liberia\",\"name\":\"Liberia\",\"postal\":\"LR\",\"pop_est\":3441790,\"iso_a2\":\"LR\",\"iso_a3\":\"LBR\"},\"id\":430,\"arcs\":[[-2428,1207,2621,-2521]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Libya\",\"name\":\"Libya\",\"postal\":\"LY\",\"pop_est\":6310434,\"iso_a2\":\"LY\",\"iso_a3\":\"LBY\"},\"id\":434,\"arcs\":[[-2489,2622,2623,2624,-2479,2625,1222]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Sri Lanka\",\"name\":\"Sri Lanka\",\"postal\":\"LK\",\"pop_est\":21324791,\"iso_a2\":\"LK\",\"iso_a3\":\"LKA\"},\"id\":144,\"arcs\":[[108]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Lesotho\",\"name\":\"Lesotho\",\"postal\":\"LS\",\"pop_est\":2130819,\"iso_a2\":\"LS\",\"iso_a3\":\"LSO\"},\"id\":426,\"arcs\":[[2626]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Lithuania\",\"name\":\"Lithuania\",\"postal\":\"LT\",\"pop_est\":3555179,\"iso_a2\":\"LT\",\"iso_a3\":\"LTU\"},\"id\":440,\"arcs\":[[-2312,2627,2628,2629,1266,2630]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Luxembourg\",\"name\":\"Luxembourg\",\"postal\":\"L\",\"pop_est\":491775,\"iso_a2\":\"LU\",\"iso_a3\":\"LUX\"},\"id\":442,\"arcs\":[[-2468,-2510,-2285]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Latvia\",\"name\":\"Latvia\",\"postal\":\"LV\",\"pop_est\":2231503,\"iso_a2\":\"LV\",\"iso_a3\":\"LVA\"},\"id\":428,\"arcs\":[[2631,-2313,-2631,1267,-2500]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Morocco\",\"name\":\"Morocco\",\"postal\":\"MA\",\"pop_est\":34859364,\"iso_a2\":\"MA\",\"iso_a3\":\"MAR\"},\"id\":504,\"arcs\":[[-2484,2632,2633,1217,2634,1219]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Moldova\",\"name\":\"Moldova\",\"postal\":\"MD\",\"pop_est\":4320748,\"iso_a2\":\"MD\",\"iso_a3\":\"MDA\"},\"id\":498,\"arcs\":[[2635,2636]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Madagascar\",\"name\":\"Madagascar\",\"postal\":\"MG\",\"pop_est\":20653556,\"iso_a2\":\"MG\",\"iso_a3\":\"MDG\"},\"id\":450,\"arcs\":[[235]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Mexico\",\"name\":\"Mexico\",\"postal\":\"MX\",\"pop_est\":111211789,\"iso_a2\":\"MX\",\"iso_a3\":\"MEX\"},\"id\":484,\"arcs\":[[[1439]],[[1440]],[[2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,656,-2315,-2531,681,2655,2656,2657]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Macedonia\",\"name\":\"Macedonia\",\"postal\":\"MK\",\"pop_est\":2066718,\"iso_a2\":\"MK\",\"iso_a3\":\"MKD\"},\"id\":807,\"arcs\":[[-2302,-2527,-2242,-2614,2658]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Mali\",\"name\":\"Mali\",\"postal\":\"ML\",\"pop_est\":12666987,\"iso_a2\":\"ML\",\"iso_a3\":\"MLI\"},\"id\":466,\"arcs\":[[2659,-2297,-2430,-2520,2660,2661,-2481]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Myanmar\",\"name\":\"Myanmar\",\"postal\":\"MM\",\"pop_est\":48137741,\"iso_a2\":\"MM\",\"iso_a3\":\"MMR\"},\"id\":104,\"arcs\":[[[-2620,2662,1163,-2298,-2561,-2404]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Montenegro\",\"name\":\"Montenegro\",\"postal\":\"ME\",\"pop_est\":672180,\"iso_a2\":\"ME\",\"iso_a3\":\"MNE\"},\"id\":499,\"arcs\":[[2663,-2615,-2247,2664,1383,2665,-2244,1237,-2537,-2306]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Mongolia\",\"name\":\"Mongolia\",\"postal\":\"MN\",\"pop_est\":3041142,\"iso_a2\":\"MN\",\"iso_a3\":\"MNG\"},\"id\":496,\"arcs\":[[-2425,2666]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Mozambique\",\"name\":\"Mozambique\",\"postal\":\"MZ\",\"pop_est\":21669278,\"iso_a2\":\"MZ\",\"iso_a3\":\"MOZ\"},\"id\":508,\"arcs\":[[2667,2668,2669,2670,2671,2672,2673,1284,2674,2675,1190]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Mauritania\",\"name\":\"Mauritania\",\"postal\":\"MR\",\"pop_est\":3129486,\"iso_a2\":\"MR\",\"iso_a3\":\"MRT\"},\"id\":478,\"arcs\":[[2676,1214,2677,-2482,-2662]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Mauritius\",\"name\":\"Mauritius\",\"postal\":\"MU\",\"pop_est\":1284264,\"iso_a2\":\"MU\",\"iso_a3\":\"MUS\"},\"id\":480,\"arcs\":[[141]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Malawi\",\"name\":\"Malawi\",\"postal\":\"MW\",\"pop_est\":14268711,\"iso_a2\":\"MW\",\"iso_a3\":\"MWI\"},\"id\":454,\"arcs\":[[1287,2678,-2673,2679,2680]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Malaysia\",\"name\":\"Malaysia\",\"postal\":\"MY\",\"pop_est\":25715819,\"iso_a2\":\"MY\",\"iso_a3\":\"MYS\"},\"id\":458,\"arcs\":[[[1161,2681]],[[2682,-2557,262,2683,-2337,-2336,266]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Namibia\",\"name\":\"Namibia\",\"postal\":\"NA\",\"pop_est\":2108665,\"iso_a2\":\"NA\",\"iso_a3\":\"NAM\"},\"id\":516,\"arcs\":[[2684,-2343,2685,1192,-2237]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"New Caledonia\",\"name\":\"New Caledonia\",\"postal\":\"NC\",\"pop_est\":227436,\"iso_a2\":\"NC\",\"iso_a3\":\"NCL\"},\"id\":540,\"arcs\":[[[140]],[[138]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Niger\",\"name\":\"Niger\",\"postal\":\"NE\",\"pop_est\":15306252,\"iso_a2\":\"NE\",\"iso_a3\":\"NER\"},\"id\":562,\"arcs\":[[2686,2687,-2292,-2293,-2660,-2480,-2625]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Nigeria\",\"name\":\"Nigeria\",\"postal\":\"NG\",\"pop_est\":149229090,\"iso_a2\":\"NG\",\"iso_a3\":\"NGA\"},\"id\":566,\"arcs\":[[2688,-2434,1200,-2289,-2688]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Nicaragua\",\"name\":\"Nicaragua\",\"postal\":\"NI\",\"pop_est\":5891199,\"iso_a2\":\"NI\",\"iso_a3\":\"NIC\"},\"id\":558,\"arcs\":[[660,-2458,677,-2535]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Netherlands\",\"name\":\"Netherlands\",\"postal\":\"NL\",\"pop_est\":16715999,\"iso_a2\":\"NL\",\"iso_a3\":\"NLD\"},\"id\":528,\"arcs\":[[[-2287,1250]],[[2224]],[[1251,-2469,-2283,2689,-2288],[1388]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Norway\",\"name\":\"Norway\",\"postal\":\"N\",\"pop_est\":4676305,\"iso_a2\":\"NO\",\"iso_a3\":\"NOR\"},\"id\":578,\"arcs\":[[[1810]],[[1809]],[[2014]],[[2019]],[[2002]],[[2690,-2508,2691,1143]],[[2021]],[[1629]],[[1721]],[[313]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Nepal\",\"name\":\"Nepal\",\"postal\":\"NP\",\"pop_est\":28563377,\"iso_a2\":\"NP\",\"iso_a3\":\"NPL\"},\"id\":524,\"arcs\":[[-2560,-2407]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"New Zealand\",\"name\":\"New Zealand\",\"postal\":\"NZ\",\"pop_est\":4213418,\"iso_a2\":\"NZ\",\"iso_a3\":\"NZL\"},\"id\":554,\"arcs\":[[[126]],[[45]],[[130]],[[133]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Oman\",\"name\":\"Oman\",\"postal\":\"OM\",\"pop_est\":3418085,\"iso_a2\":\"OM\",\"iso_a3\":\"OMN\"},\"id\":512,\"arcs\":[[[78]],[[1177,2692,2693,-2248]],[[-2250,1175]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Pakistan\",\"name\":\"Pakistan\",\"postal\":\"PK\",\"pop_est\":176242949,\"iso_a2\":\"PK\",\"iso_a3\":\"PAK\"},\"id\":586,\"arcs\":[[-2591,-2562,1166,2694,-2569,-2230,-2420]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Panama\",\"name\":\"Panama\",\"postal\":\"PA\",\"pop_est\":3360474,\"iso_a2\":\"PA\",\"iso_a3\":\"PAN\"},\"id\":591,\"arcs\":[[[56]],[[-2456,675,-2457,662]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Peru\",\"name\":\"Peru\",\"postal\":\"PE\",\"pop_est\":29546963,\"iso_a2\":\"PE\",\"iso_a3\":\"PER\"},\"id\":604,\"arcs\":[[-2332,-2321,2695,966,2696,962,2697,-2318,-2395,672,-2485,-2454]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Philippines\",\"name\":\"Philippines\",\"postal\":\"PH\",\"pop_est\":97976603,\"iso_a2\":\"PH\",\"iso_a3\":\"PHL\"},\"id\":608,\"arcs\":[[[110]],[[109]],[[112]],[[59]],[[49]],[[60]],[[61]],[[58]],[[53]],[[54]],[[79]],[[55]],[[89]],[[90]],[[93]],[[94]],[[95]],[[96]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Papua New Guinea\",\"name\":\"Papua New Guinea\",\"postal\":\"PG\",\"pop_est\":6057263,\"iso_a2\":\"PG\",\"iso_a3\":\"PNG\"},\"id\":598,\"arcs\":[[[244]],[[202]],[[200]],[[201]],[[204]],[[166]],[[163]],[[165]],[[170]],[[2698,-2554,2699,2700,230]],[[161]],[[172]],[[174]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Poland\",\"name\":\"Poland\",\"postal\":\"PL\",\"pop_est\":38482919,\"iso_a2\":\"PL\",\"iso_a3\":\"POL\"},\"id\":616,\"arcs\":[[2701,-2628,-2311,2702,2703,-2460,-2465,2704,1258,2705,-2707,1261]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Puerto Rico\",\"name\":\"Puerto Rico\",\"postal\":\"PR\",\"pop_est\":3971020,\"iso_a2\":\"PR\",\"iso_a3\":\"PRI\"},\"id\":630,\"arcs\":[[100]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"North Korea\",\"name\":\"Dem. Rep. Korea\",\"postal\":\"KP\",\"pop_est\":22665345,\"iso_a2\":\"KP\",\"iso_a3\":\"PRK\"},\"id\":408,\"arcs\":[[2707,1149,-2613,1151,-2399]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Portugal\",\"name\":\"Portugal\",\"postal\":\"P\",\"pop_est\":10707924,\"iso_a2\":\"PT\",\"iso_a3\":\"PRT\"},\"id\":620,\"arcs\":[[[1468]],[[1246,-2495]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Paraguay\",\"name\":\"Paraguay\",\"postal\":\"PY\",\"pop_est\":6995655,\"iso_a2\":\"PY\",\"iso_a3\":\"PRY\"},\"id\":600,\"arcs\":[[-2331,-2330,-2329,-2252,-2316]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Palestine\",\"name\":\"Palestine\",\"postal\":\"PAL\",\"pop_est\":4119083,\"iso_a2\":\"PS\",\"iso_a3\":\"PSE\"},\"id\":275,\"arcs\":[[[-2588,-2579,-2589]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"French Polynesia\",\"name\":\"Fr. Polynesia\",\"postal\":\"PF\",\"pop_est\":287032,\"iso_a2\":\"PF\",\"iso_a3\":\"PYF\"},\"id\":258,\"arcs\":[[[143]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Qatar\",\"name\":\"Qatar\",\"postal\":\"QA\",\"pop_est\":833285,\"iso_a2\":\"QA\",\"iso_a3\":\"QAT\"},\"id\":634,\"arcs\":[[2708,1172]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Romania\",\"name\":\"Romania\",\"postal\":\"RO\",\"pop_est\":22215421,\"iso_a2\":\"RO\",\"iso_a3\":\"ROU\"},\"id\":642,\"arcs\":[[2709,1232,-2304,2710,-2542,2711,-2636]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Russia\",\"name\":\"Russia\",\"postal\":\"RUS\",\"pop_est\":140041247,\"iso_a2\":\"RU\",\"iso_a3\":\"RUS\"},\"id\":643,\"arcs\":[[[1498]],[[1502]],[[1479]],[[2141]],[[2198]],[[1535]],[[2712,-2629,-2702,1262,2713,1264]],[[1541]],[[1608]],[[2714,1867]],[[1808]],[[2004]],[[2001]],[[2020]],[[2022]],[[1996]],[[2715,1998,2716,2000]],[[2024]],[[2023]],[[2114]],[[2139]],[[2119]],[[1610]],[[1611]],[[1612]],[[1666]],[[1665]],[[2140]],[[2717,1148,-2708,-2398,2718,1354,2719,-2426,-2667,-2424,-2601,1273,-2276,-2517,1230,2720,-2309,-2632,-2499,2721,1399,2722,-2496,1269,-2506,-2691,1144,2723,1146]],[[272]],[[310]],[[273]],[[311]],[[316]],[[317]],[[318]],[[314]],[[319]],[[321]],[[320]],[[315]],[[322]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Rwanda\",\"name\":\"Rwanda\",\"postal\":\"RW\",\"pop_est\":10473282,\"iso_a2\":\"RW\",\"iso_a3\":\"RWA\"},\"id\":646,\"arcs\":[[2724,-2281,-2447,2725,1292,2726,-2444,2727]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Western Sahara\",\"name\":\"W. Sahara\",\"postal\":\"WS\",\"pop_est\":-99,\"iso_a2\":\"EH\",\"iso_a3\":\"ESH\"},\"id\":732,\"arcs\":[[-2483,-2678,1215,2728,-2633]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Saudi Arabia\",\"name\":\"Saudi Arabia\",\"postal\":\"SA\",\"pop_est\":28686633,\"iso_a2\":\"SA\",\"iso_a3\":\"SAU\"},\"id\":682,\"arcs\":[[[-2617,1171,-2709,1173,-2249,-2694,2729,1179,-2587,-2574]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Sudan\",\"name\":\"Sudan\",\"postal\":\"SD\",\"pop_est\":25946220,\"iso_a2\":\"SD\",\"iso_a3\":\"SDN\"},\"id\":729,\"arcs\":[[1183,-2491,-2505,2730,-2344,2731,-2623,-2488]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"South Sudan\",\"name\":\"S. Sudan\",\"postal\":\"SS\",\"pop_est\":10625176,\"iso_a2\":\"SS\",\"iso_a3\":\"SSD\"},\"id\":728,\"arcs\":[[-2504,-2607,2732,-2437,-2345,-2731]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Senegal\",\"name\":\"Senegal\",\"postal\":\"SN\",\"pop_est\":13711597,\"iso_a2\":\"SN\",\"iso_a3\":\"SEN\"},\"id\":686,\"arcs\":[[-2661,-2524,-2526,1211,-2525,1213,-2677]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"South Georgia and South Sandwich Islands\",\"name\":\"S. Geo. and S. Sandw. Is.\",\"postal\":\"GS\",\"pop_est\":30,\"iso_a2\":\"GS\",\"iso_a3\":\"SGS\"},\"id\":239,\"arcs\":[[26]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Solomon Islands\",\"name\":\"Solomon Is.\",\"postal\":\"SB\",\"pop_est\":595613,\"iso_a2\":\"SB\",\"iso_a3\":\"SLB\"},\"id\":90,\"arcs\":[[[241]],[[246]],[[199]],[[215]],[[205]],[[221]],[[224]],[[222]],[[152]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Sierra Leone\",\"name\":\"Sierra Leone\",\"postal\":\"SL\",\"pop_est\":6440053,\"iso_a2\":\"SL\",\"iso_a3\":\"SLE\"},\"id\":694,\"arcs\":[[[57]],[[-2622,1208,-2522]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"El Salvador\",\"name\":\"El Salvador\",\"postal\":\"SV\",\"pop_est\":7185218,\"iso_a2\":\"SV\",\"iso_a3\":\"SLV\"},\"id\":222,\"arcs\":[[-2536,679,-2530]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Somaliland\",\"name\":\"Somaliland\",\"postal\":\"SL\",\"pop_est\":3500000,\"iso_a2\":\"-99\",\"iso_a3\":\"-99\"},\"id\":-99,\"arcs\":[[2733,-2501,-2472,1186]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Somalia\",\"name\":\"Somalia\",\"postal\":\"SO\",\"pop_est\":9832017,\"iso_a2\":\"SO\",\"iso_a3\":\"SOM\"},\"id\":706,\"arcs\":[[-2602,-2502,-2734,1187]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Republic of Serbia\",\"name\":\"Serbia\",\"postal\":\"RS\",\"pop_est\":7379339,\"iso_a2\":\"RS\",\"iso_a3\":\"SRB\"},\"id\":688,\"arcs\":[[-2711,-2303,-2659,-2616,-2664,-2305,-2538,-2543]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Sao Tome and Principe\",\"name\":\"São Tomé and Principe\",\"postal\":\"ST\",\"pop_est\":212679,\"iso_a2\":\"ST\",\"iso_a3\":\"STP\"},\"id\":678,\"arcs\":[[250]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Suriname\",\"name\":\"Suriname\",\"postal\":\"SR\",\"pop_est\":481267,\"iso_a2\":\"SR\",\"iso_a3\":\"SUR\"},\"id\":740,\"arcs\":[[-2509,-2323,-2532,666]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Slovakia\",\"name\":\"Slovakia\",\"postal\":\"SK\",\"pop_est\":5463046,\"iso_a2\":\"SK\",\"iso_a3\":\"SVK\"},\"id\":703,\"arcs\":[[2734,-2545,-2262,-2461,-2704]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Slovenia\",\"name\":\"Slovenia\",\"postal\":\"SLO\",\"pop_est\":2005692,\"iso_a2\":\"SI\",\"iso_a3\":\"SVN\"},\"id\":705,\"arcs\":[[-2539,1241,-2586,-2264,-2544]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Sweden\",\"name\":\"Sweden\",\"postal\":\"S\",\"pop_est\":9059651,\"iso_a2\":\"SE\",\"iso_a3\":\"SWE\"},\"id\":752,\"arcs\":[[[1588]],[[1576]],[[1271,2735,1142,-2692,-2507]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Swaziland\",\"name\":\"Swaziland\",\"postal\":\"SW\",\"pop_est\":1123913,\"iso_a2\":\"SZ\",\"iso_a3\":\"SWZ\"},\"id\":748,\"arcs\":[[-2669,2736]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Syria\",\"name\":\"Syria\",\"postal\":\"SYR\",\"pop_est\":20178485,\"iso_a2\":\"SY\",\"iso_a3\":\"SYR\"},\"id\":760,\"arcs\":[[-2576,-2590,-2585,-2621,1227,2737]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Chad\",\"name\":\"Chad\",\"postal\":\"TD\",\"pop_est\":10329208,\"iso_a2\":\"TD\",\"iso_a3\":\"TCD\"},\"id\":148,\"arcs\":[[-2732,-2349,-2436,-2435,-2689,-2687,-2624]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Togo\",\"name\":\"Togo\",\"postal\":\"TG\",\"pop_est\":6019877,\"iso_a2\":\"TG\",\"iso_a3\":\"TGO\"},\"id\":768,\"arcs\":[[-2290,1202,-2518,-2294]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Thailand\",\"name\":\"Thailand\",\"postal\":\"TH\",\"pop_est\":65905410,\"iso_a2\":\"TH\",\"iso_a3\":\"THA\"},\"id\":764,\"arcs\":[[[-2619,-2610,1160,-2682,1162,-2663]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Tajikistan\",\"name\":\"Tajikistan\",\"postal\":\"TJ\",\"pop_est\":7349145,\"iso_a2\":\"TJ\",\"iso_a3\":\"TJK\"},\"id\":762,\"arcs\":[[-2608,-2421,-2235,2738]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Turkmenistan\",\"name\":\"Turkmenistan\",\"postal\":\"TM\",\"pop_est\":4884887,\"iso_a2\":\"TM\",\"iso_a3\":\"TKM\"},\"id\":795,\"arcs\":[[-2233,-2567,1276,-2600,2739,2740,1382,2741,2742]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"East Timor\",\"name\":\"Timor-Leste\",\"postal\":\"TL\",\"pop_est\":1131612,\"iso_a2\":\"TL\",\"iso_a3\":\"TLS\"},\"id\":626,\"arcs\":[[[2743,2744,-2548]],[[2745,-2551,2746,212]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Trinidad and Tobago\",\"name\":\"Trinidad and Tobago\",\"postal\":\"TT\",\"pop_est\":1310000,\"iso_a2\":\"TT\",\"iso_a3\":\"TTO\"},\"id\":780,\"arcs\":[[48]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Tunisia\",\"name\":\"Tunisia\",\"postal\":\"TN\",\"pop_est\":10486339,\"iso_a2\":\"TN\",\"iso_a3\":\"TUN\"},\"id\":788,\"arcs\":[[[-2626,-2478,1221]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Turkey\",\"name\":\"Turkey\",\"postal\":\"TR\",\"pop_est\":76805524,\"iso_a2\":\"TR\",\"iso_a3\":\"TUR\"},\"id\":792,\"arcs\":[[[-2516,-2259,-2273,-2572,-2577,-2738,1228]],[[1234,-2528,-2300]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Taiwan\",\"name\":\"Taiwan\",\"postal\":\"TW\",\"pop_est\":22974347,\"iso_a2\":\"TW\",\"iso_a3\":\"TWN\"},\"id\":158,\"arcs\":[[1436]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"United Republic of Tanzania\",\"name\":\"Tanzania\",\"postal\":\"TZ\",\"pop_est\":41048532,\"iso_a2\":\"TZ\",\"iso_a3\":\"TZA\"},\"id\":834,\"arcs\":[[[154]],[[168]],[[2210]],[[2211]],[[2747,1297,2748,-2603,1189,-2676,2749,1286,-2681,2750,2751,1307,2752,-2277,-2725,2753]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Uganda\",\"name\":\"Uganda\",\"postal\":\"UG\",\"pop_est\":32369558,\"iso_a2\":\"UG\",\"iso_a3\":\"UGA\"},\"id\":800,\"arcs\":[[[2754,1295,2755,-2754,-2728,-2443,2756,1302,2757,-2440,1317,2758,-2438,-2733,-2606]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Ukraine\",\"name\":\"Ukraine\",\"postal\":\"UA\",\"pop_est\":45700395,\"iso_a2\":\"UA\",\"iso_a3\":\"UKR\"},\"id\":804,\"arcs\":[[1231,-2710,-2637,-2712,-2541,-2735,-2703,-2310,-2721]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Uruguay\",\"name\":\"Uruguay\",\"postal\":\"UY\",\"pop_est\":3494382,\"iso_a2\":\"UY\",\"iso_a3\":\"URY\"},\"id\":858,\"arcs\":[[2759,953,2760,-2325,669,-2254,-2328]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"United States of America\",\"name\":\"United States\",\"postal\":\"US\",\"pop_est\":313973000,\"iso_a2\":\"US\",\"iso_a3\":\"USA\"},\"id\":840,\"arcs\":[[[73,74,75,76,77]],[[62,63]],[[64,65,66]],[[68,69,70,71,72]],[[323,324]],[[1456,1457,1458]],[[2212,2213,2214]],[[2220,2221,2222,2223,2219]],[[-2374,-2373,-2372,-2371,-2370,-2369,2761,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1030,1031,1032,1033,1034,1035,1036,1037,1038,-2367,1021,1022,1023,1024,1025,1026,-2366,2762,1009,1010,1011,1012,1013,1014,2763,-2363,-2362,-2360,-2359,-2358,-2357,-2356,-2355,-2354,2764,984,2765,-2351,-2350,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,-2655,-2654,-2653,-2652,-2651,-2650,-2649,-2648,-2647,-2646,-2645,-2644,-2643,-2642,-2641,-2640,-2639,-2638,-2658,-2657,-2656,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,-2377,-2376,-2375]],[[1506]],[[1503,1504,1505]],[[1507,1508]],[[2199]],[[1509,1510,1511,1512]],[[1521,1522,1523]],[[1536,1537,1538,1539,1540]],[[1544,1545]],[[1547,1548,1549,1550,1551,1552]],[[1555,1556,1557,1558,1559,1560,1561,1562]],[[1566,1567,1568]],[[1570,1571,1572]],[[1595,1596,1597,1598,1599]],[[1589,1590,1591,1592,1593,1594]],[[1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587]],[[1604,1605,1606]],[[1601,1602,1603]],[[1573,1574,1575]],[[1797,1798,1799]],[[1792,1793,1794,1795,1796]],[[1824,1825,1826,1827,1828,1829,1830]],[[867,868,869,870,871,872,-2388,-2387,-2386,-2385,-2384,-2383,-2382,-2381,-2380,-2379,-2378,745,746,2766,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Uzbekistan\",\"name\":\"Uzbekistan\",\"postal\":\"UZ\",\"pop_est\":27606007,\"iso_a2\":\"UZ\",\"iso_a3\":\"UZB\"},\"id\":860,\"arcs\":[[[2767,-2593,2768,1374,2769,-2596,-2609,-2739,-2234,-2743,2770,1380,2771,-2740,-2599,2772,1370]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Venezuela\",\"name\":\"Venezuela\",\"postal\":\"VE\",\"pop_est\":26814843,\"iso_a2\":\"VE\",\"iso_a3\":\"VEN\"},\"id\":862,\"arcs\":[[[51]],[[-2533,-2334,-2453,664]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Vietnam\",\"name\":\"Vietnam\",\"postal\":\"VN\",\"pop_est\":86967524,\"iso_a2\":\"VN\",\"iso_a3\":\"VNM\"},\"id\":704,\"arcs\":[[[50]],[[1158,-2612,-2618,-2402]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Vanuatu\",\"name\":\"Vanuatu\",\"postal\":\"VU\",\"pop_est\":218519,\"iso_a2\":\"VU\",\"iso_a3\":\"VUT\"},\"id\":548,\"arcs\":[[[137]],[[144]],[[147]],[[145]],[[236]],[[237]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Samoa\",\"name\":\"Samoa\",\"postal\":\"WS\",\"pop_est\":219998,\"iso_a2\":\"WS\",\"iso_a3\":\"WSM\"},\"id\":882,\"arcs\":[[[46]],[[47]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"admin\":\"Yemen\",\"name\":\"Yemen\",\"postal\":\"YE\",\"pop_est\":23822783,\"iso_a2\":\"YE\",\"iso_a3\":\"YEM\"},\"id\":887,\"arcs\":[[[91]],[[1178,-2730,-2693]]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"South Africa\",\"name\":\"South Africa\",\"postal\":\"ZA\",\"pop_est\":49052489,\"iso_a2\":\"ZA\",\"iso_a3\":\"ZAF\"},\"id\":710,\"arcs\":[[-2670,-2737,-2668,1191,-2686,-2342,2773],[-2627]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Zambia\",\"name\":\"Zambia\",\"postal\":\"ZM\",\"pop_est\":11862740,\"iso_a2\":\"ZM\",\"iso_a3\":\"ZMB\"},\"id\":894,\"arcs\":[[2774,-2751,-2680,-2672,2775,2776,1279,2777,-2685,-2236,-2450,2778,1313]]},{\"type\":\"Polygon\",\"properties\":{\"admin\":\"Zimbabwe\",\"name\":\"Zimbabwe\",\"postal\":\"ZW\",\"pop_est\":12619600,\"iso_a2\":\"ZW\",\"iso_a3\":\"ZWE\"},\"id\":716,\"arcs\":[[-2776,-2671,-2774,-2341,-2778,1280,2779,1282]]}]},\"states\":{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Alberta\",\"postal\":\"AB\",\"admin\":\"Canada\"},\"arcs\":[[2780,2781,2782,2783]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"British Columbia\",\"postal\":\"BC\",\"admin\":\"Canada\"},\"arcs\":[[[2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798]],[[2799,2800,2801,2802]],[[2803,2804,2805,2806]],[[2807,2808,2809]],[[2810,2811,2812,2813,2814,2815,2816]],[[2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,-2782,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,736,2850,2851,2852,2853,2854,2855,2856,2857]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Manitoba\",\"postal\":\"MB\",\"admin\":\"Canada\"},\"arcs\":[[2858,2859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"New Brunswick\",\"postal\":\"NB\",\"admin\":\"Canada\"},\"arcs\":[[2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Newfoundland and Labrador\",\"postal\":\"NL\",\"admin\":\"Canada\"},\"arcs\":[[[2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931]],[[2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Nova Scotia\",\"postal\":\"NS\",\"admin\":\"Canada\"},\"arcs\":[[[-2876,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991]],[[2992,2993,2994,2995,2996,2997,2998,2999]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Northwest Territories\",\"postal\":\"NT\",\"admin\":\"Canada\"},\"arcs\":[[[3000,3001,-2783,-2828,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026]],[[3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051]],[[3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068]],[[3069]],[[3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088]],[[3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099]],[[3100,3101,3102]],[[3103,3104,3105]],[[3106]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Nunavut\",\"postal\":\"NU\",\"admin\":\"Canada\"},\"arcs\":[[[3107,3108,3109,3110]],[[3111,3112,3113]],[[3114,3115]],[[3116,3117]],[[3118,3119,3120,3121]],[[3122,3123,3124,3125]],[[3126,3127,3128,3129,3130,3131]],[[3132,3133,3134]],[[3135]],[[3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152]],[[3153,3154,3155]],[[3156,3157]],[[3158,3159]],[[3160,3161,3162]],[[3163,3164,3165,3166]],[[3167,3168]],[[3169,3170,3171,3172]],[[3173,3174]],[[3175,3176]],[[3177,3178,3179,3180,3181,3182,3183]],[[-2863,-3001,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,936,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280]],[[-3028,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305]],[[3306,3307,3308,3309]],[[3310,3311,3312,3313,3314,3315,3316,3317]],[[3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435]],[[2091,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456]],[[3457]],[[3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3468]],[[3469,3470,3471,3472]],[[3473,3474,3475,3476,3477]],[[3478,3479,3480]],[[3481,3482,3483]],[[3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495,3496]],[[-3071,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508]],[[3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530]],[[3531,3532,3533]],[[3534]],[[3535,3536,3537]],[[3538,3539,3540,3541]],[[3542,3543,3544,3545,3546,3547,3548,3549,3550,3551]],[[3552,3553]],[[3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576]],[[3577,3578,3579,3580,3581,3582,3583,1729,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645]]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Ontario\",\"postal\":\"ON\",\"admin\":\"Canada\"},\"arcs\":[[[3646,3647,3648,3649]],[[3650,3651,3652]],[[3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,-2859,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Prince Edward Island\",\"postal\":\"PE\",\"admin\":\"Canada\"},\"arcs\":[[3716,3717,3718,3719,3720,3721,3722,3723,3724,3725]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Québec\",\"postal\":\"QC\",\"admin\":\"Canada\"},\"arcs\":[[[3726,3727]],[[-2884,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747]],[[1473,3748,3749,3750,3751,3752]],[[-2933,3753,3754,3755,3756,482,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,-3654,3774,-3653,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,430,3806,3807,3808,3809,3810,3811,3812,3813,3814]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Saskatchewan\",\"postal\":\"SK\",\"admin\":\"Canada\"},\"arcs\":[[3815,3816,-2784,-3002,-2862]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"CA\",\"name\":\"Yukon\",\"postal\":\"YT\",\"admin\":\"Canada\"},\"arcs\":[[-3003,-2827,3817,3818,3819,3820,3821]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Alaska\",\"postal\":\"AK\",\"admin\":\"United States of America\"},\"arcs\":[[[3822]],[[3823,3824,3825]],[[3826,3827]],[[3828,3829,3830,3831]],[[3832,3833,3834]],[[3835,3836,3837,3838,3839]],[[3840,3841]],[[3842,3843,3844,3845,1551,3846]],[[3847,3848,3849,3850,3851,3852,3853,3854]],[[3855,3856,3857]],[[3858,3859,3860]],[[3861,3862,3863,3864,3865]],[[3866,3867,3868,3869,3870,3871]],[[3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882]],[[3883,3884,3885]],[[3886,3887,3888]],[[3889,3890,3891]],[[3892,3893,3894]],[[3895,3896,3897,3898,3899]],[[3900,3901,3902,3903,3904,3905,3906]],[[-3820,-3819,-3818,-2826,-2825,-2824,-2823,-2822,-2821,-2820,-2819,-2818,3907,3908,3909,3910,3911,3912,3913,3914,755,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Alabama\",\"postal\":\"AL\",\"admin\":\"United States of America\"},\"arcs\":[[4032,4033,4034,4035,4036,4037,4038,4039]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Arkansas\",\"postal\":\"AR\",\"admin\":\"United States of America\"},\"arcs\":[[4040,4041,4042,4043,4044,4045]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Arizona\",\"postal\":\"AZ\",\"admin\":\"United States of America\"},\"arcs\":[[4046,4047,4048,4049,4050,4051,4052,4053]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"California\",\"postal\":\"CA\",\"admin\":\"United States of America\"},\"arcs\":[[4054,4055,-4052,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Colorado\",\"postal\":\"CO\",\"admin\":\"United States of America\"},\"arcs\":[[4074,4075,4076,4077,4078,4079]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Connecticut\",\"postal\":\"CT\",\"admin\":\"United States of America\"},\"arcs\":[[4080,4081,4082,4083,4084]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Delaware\",\"postal\":\"DE\",\"admin\":\"United States of America\"},\"arcs\":[[4085,4086,4087,4088,4089]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Florida\",\"postal\":\"FL\",\"admin\":\"United States of America\"},\"arcs\":[[4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,622,4111,4112,4113,4114,4115,4116,-4040,4117]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Georgia\",\"postal\":\"GA\",\"admin\":\"United States of America\"},\"arcs\":[[4118,4119,4120,-4118,-4039,4121,4122,4123]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Hawaii\",\"postal\":\"HI\",\"admin\":\"United States of America\"},\"arcs\":[[[4124,4125,4126,4127,4128]],[[4129,4130]],[[4131,4132,4133]],[[4134,4135,4136,4137,4138]],[[4139,4140]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Iowa\",\"postal\":\"IA\",\"admin\":\"United States of America\"},\"arcs\":[[4141,4142,4143,4144,4145,4146]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Idaho\",\"postal\":\"ID\",\"admin\":\"United States of America\"},\"arcs\":[[4147,4148,4149,4150,4151,-2830,4152]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Illinois\",\"postal\":\"IL\",\"admin\":\"United States of America\"},\"arcs\":[[4153,4154,4155,4156,4157,-4142,4158]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Indiana\",\"postal\":\"IN\",\"admin\":\"United States of America\"},\"arcs\":[[4159,4160,-4156,4161,4162]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Kansas\",\"postal\":\"KS\",\"admin\":\"United States of America\"},\"arcs\":[[4163,-4075,4164,4165]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Kentucky\",\"postal\":\"KY\",\"admin\":\"United States of America\"},\"arcs\":[[4166,4167,4168,4169,-4157,-4161,4170]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Louisiana\",\"postal\":\"LA\",\"admin\":\"United States of America\"},\"arcs\":[[4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,-4043,4185]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Massachusetts\",\"postal\":\"MA\",\"admin\":\"United States of America\"},\"arcs\":[[4186,-4085,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Maryland\",\"postal\":\"MD\",\"admin\":\"United States of America\"},\"arcs\":[[-4089,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Maine\",\"postal\":\"ME\",\"admin\":\"United States of America\"},\"arcs\":[[-2881,-2880,4212,4213,4214,4215,4216,4217,4218,4219,4220,-3732,-3731,-3730,-3729,-2883,-2882]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Michigan\",\"postal\":\"MI\",\"admin\":\"United States of America\"},\"arcs\":[[[-3672,4221,4222,4223,-4163,4224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242]],[[4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256]],[[4257,4258,4259,4260,4261]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Minnesota\",\"postal\":\"MN\",\"admin\":\"United States of America\"},\"arcs\":[[4262,4263,4264,-4146,4265,4266,-2860,-3703,-3702,-3701,-3700,-3699,-3698]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Missouri\",\"postal\":\"MO\",\"admin\":\"United States of America\"},\"arcs\":[[-4158,-4170,4267,-4046,4268,-4166,4269,-4143]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Mississippi\",\"postal\":\"MS\",\"admin\":\"United States of America\"},\"arcs\":[[4270,4271,-4186,-4042,4272,-4037]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Montana\",\"postal\":\"MT\",\"admin\":\"United States of America\"},\"arcs\":[[4273,4274,-4153,-2829,-2781,-3817,4275]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"North Carolina\",\"postal\":\"NC\",\"admin\":\"United States of America\"},\"arcs\":[[4276,-4123,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"North Dakota\",\"postal\":\"ND\",\"admin\":\"United States of America\"},\"arcs\":[[4291,-4276,-3816,-2861,-4267]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Nebraska\",\"postal\":\"NE\",\"admin\":\"United States of America\"},\"arcs\":[[-4144,-4270,-4165,-4080,4292,4293]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"New Hampshire\",\"postal\":\"NH\",\"admin\":\"United States of America\"},\"arcs\":[[4294,-4190,4295,-3734,-3733,-4221]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"New Jersey\",\"postal\":\"NJ\",\"admin\":\"United States of America\"},\"arcs\":[[4296,4297,4298,4299,4300,4301]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"New Mexico\",\"postal\":\"NM\",\"admin\":\"United States of America\"},\"arcs\":[[4302,4303,4304,4305,-4047,-4077,4306]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Nevada\",\"postal\":\"NV\",\"admin\":\"United States of America\"},\"arcs\":[[-4053,-4056,4307,-4150,4308]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"New York\",\"postal\":\"NY\",\"admin\":\"United States of America\"},\"arcs\":[[[4309,4310,4311]],[[4312,-4188,-4084,4313,-4298,4314,4315,4316,-3666,4317,4318,4319,4320,4321,4322,-3657,-3656,-3736]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Ohio\",\"postal\":\"OH\",\"admin\":\"United States of America\"},\"arcs\":[[4323,-4171,-4160,-4224,4324,4325,4326,4327,4328]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Oklahoma\",\"postal\":\"OK\",\"admin\":\"United States of America\"},\"arcs\":[[-4045,4329,-4307,-4076,-4164,-4269]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Oregon\",\"postal\":\"OR\",\"admin\":\"United States of America\"},\"arcs\":[[4330,-4151,-4308,-4055,4331,4332,4333,4334,4335,4336]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Pennsylvania\",\"postal\":\"PA\",\"admin\":\"United States of America\"},\"arcs\":[[-4297,4337,-4090,-4212,4338,-4329,4339,-4315]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Rhode Island\",\"postal\":\"RI\",\"admin\":\"United States of America\"},\"arcs\":[[4340,4341,-4081,-4187]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"South Carolina\",\"postal\":\"SC\",\"admin\":\"United States of America\"},\"arcs\":[[4342,4343,4344,4345,4346,-4124,-4277]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"South Dakota\",\"postal\":\"SD\",\"admin\":\"United States of America\"},\"arcs\":[[-4266,-4145,-4294,4347,-4274,-4292]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Tennessee\",\"postal\":\"TN\",\"admin\":\"United States of America\"},\"arcs\":[[4348,-4278,-4122,-4038,-4273,-4041,-4268,-4169]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Texas\",\"postal\":\"TX\",\"admin\":\"United States of America\"},\"arcs\":[[-4044,-4185,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,-4303,-4330]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Utah\",\"postal\":\"UT\",\"admin\":\"United States of America\"},\"arcs\":[[4371,-4078,-4054,-4309,-4149]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Virginia\",\"postal\":\"VA\",\"admin\":\"United States of America\"},\"arcs\":[[[-4200,4372,4373,4374]],[[-4210,4375,4376,4377,4378,4379,4380,4381,4382,-4279,-4349,-4168,4383]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Vermont\",\"postal\":\"VT\",\"admin\":\"United States of America\"},\"arcs\":[[-4189,-4313,-3735,-4296]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Washington\",\"postal\":\"WA\",\"admin\":\"United States of America\"},\"arcs\":[[-4331,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,-2832,-2831,-4152]]},{\"type\":\"MultiPolygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Wisconsin\",\"postal\":\"WI\",\"admin\":\"United States of America\"},\"arcs\":[[[4397,4398,4399]],[[-4244,4400,4401,4402,4403,-4159,-4147,-4265,4404,4405,4406,4407]]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"West Virginia\",\"postal\":\"WV\",\"admin\":\"United States of America\"},\"arcs\":[[-4211,-4384,-4167,-4324,-4339]]},{\"type\":\"Polygon\",\"properties\":{\"iso_a2\":\"US\",\"name\":\"Wyoming\",\"postal\":\"WY\",\"admin\":\"United States of America\"},\"arcs\":[[-4293,-4079,-4372,-4148,-4275,-4348]]}]},\"cities\":{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"San Bernardino\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[174161,706874]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Bridgeport\",\"adm0name\":\"United States of America\",\"adm1name\":\"Connecticut\",\"iso_a2\":\"US\"},\"coordinates\":[296661,748698]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Rochester\",\"adm0name\":\"United States of America\",\"adm1name\":\"New York\",\"iso_a2\":\"US\"},\"coordinates\":[284383,760490]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Manchester\",\"adm0name\":\"United Kingdom\",\"adm1name\":\"Manchester\",\"iso_a2\":\"GB\"},\"coordinates\":[493750,821690]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Gujranwala\",\"adm0name\":\"Pakistan\",\"adm1name\":\"Punjab\",\"iso_a2\":\"PK\"},\"coordinates\":[706063,695262]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Incheon\",\"adm0name\":\"South Korea\",\"adm1name\":\"Inch'on-gwangyoksi\",\"iso_a2\":\"KR\"},\"coordinates\":[851778,726754]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Benin City\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Edo\",\"iso_a2\":\"NG\"},\"coordinates\":[515605,542293]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Xiamen\",\"adm0name\":\"China\",\"adm1name\":\"Fujian\",\"iso_a2\":\"CN\"},\"coordinates\":[827994,649581]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Nanchong\",\"adm0name\":\"China\",\"adm1name\":\"Sichuan\",\"iso_a2\":\"CN\"},\"coordinates\":[794799,687086]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Neijiang\",\"adm0name\":\"China\",\"adm1name\":\"Sichuan\",\"iso_a2\":\"CN\"},\"coordinates\":[791800,679976]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Nanyang\",\"adm0name\":\"China\",\"adm1name\":\"Henan\",\"iso_a2\":\"CN\"},\"coordinates\":[812577,700238]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jinxi\",\"adm0name\":\"China\",\"adm1name\":\"Liaoning\",\"iso_a2\":\"CN\"},\"coordinates\":[835632,746152]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Yantai\",\"adm0name\":\"China\",\"adm1name\":\"Shandong\",\"iso_a2\":\"CN\"},\"coordinates\":[837216,727075]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Zaozhuang\",\"adm0name\":\"China\",\"adm1name\":\"Shandong\",\"iso_a2\":\"CN\"},\"coordinates\":[826578,711374]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Suzhou\",\"adm0name\":\"China\",\"adm1name\":\"Jiangsu\",\"iso_a2\":\"CN\"},\"coordinates\":[835050,690167]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Xuzhou\",\"adm0name\":\"China\",\"adm1name\":\"Jiangsu\",\"iso_a2\":\"CN\"},\"coordinates\":[825494,707819]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Wuxi\",\"adm0name\":\"China\",\"adm1name\":\"Jiangsu\",\"iso_a2\":\"CN\"},\"coordinates\":[834161,691823]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jilin\",\"adm0name\":\"China\",\"adm1name\":\"Jilin\",\"iso_a2\":\"CN\"},\"coordinates\":[851522,764516]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Chandigarh\",\"adm0name\":\"India\",\"adm1name\":\"Chandigarh\",\"iso_a2\":\"IN\"},\"coordinates\":[713272,686728]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jammu\",\"adm0name\":\"India\",\"adm1name\":\"Jammu and Kashmir\",\"iso_a2\":\"IN\"},\"coordinates\":[707901,698528]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Sholapur\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[710827,609416]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Aurangabad\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[709217,622600]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Nasik\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[704938,623220]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Dispur\",\"adm0name\":\"India\",\"adm1name\":\"Assam\",\"iso_a2\":\"IN\"},\"coordinates\":[754907,659606]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jullundur\",\"adm0name\":\"India\",\"adm1name\":\"Punjab\",\"iso_a2\":\"IN\"},\"coordinates\":[709907,690371]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Allahabad\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[727327,655536]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Moradabad\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[718763,675601]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ghaziabad\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[715017,674526]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Agra\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[716703,665699]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Aligarh\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[716832,669974]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Meerut\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[715827,676540]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Dhanbad\",\"adm0name\":\"India\",\"adm1name\":\"Jharkhand\",\"iso_a2\":\"IN\"},\"coordinates\":[740049,645733]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Gwalior\",\"adm0name\":\"India\",\"adm1name\":\"Madhya Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[717160,660127]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Vadodara\",\"adm0name\":\"India\",\"adm1name\":\"Dadra and Nagar Haveli\",\"iso_a2\":\"IN\"},\"coordinates\":[703271,636904]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Rajkot\",\"adm0name\":\"India\",\"adm1name\":\"Dadra and Nagar Haveli\",\"iso_a2\":\"IN\"},\"coordinates\":[696661,636904]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Durazno\",\"adm0name\":\"Uruguay\",\"adm1name\":\"Durazno\",\"iso_a2\":\"UY\"},\"coordinates\":[343027,306781]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"International Falls\",\"adm0name\":\"United States of America\",\"adm1name\":\"Minnesota\",\"iso_a2\":\"US\"},\"coordinates\":[240525,792652]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"St. Paul\",\"adm0name\":\"United States of America\",\"adm1name\":\"Minnesota\",\"iso_a2\":\"US\"},\"coordinates\":[241431,770986]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Billings\",\"adm0name\":\"United States of America\",\"adm1name\":\"Montana\",\"iso_a2\":\"US\"},\"coordinates\":[198500,775987]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Great Falls\",\"adm0name\":\"United States of America\",\"adm1name\":\"Montana\",\"iso_a2\":\"US\"},\"coordinates\":[190833,786130]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Missoula\",\"adm0name\":\"United States of America\",\"adm1name\":\"Montana\",\"iso_a2\":\"US\"},\"coordinates\":[183352,782409]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Minot\",\"adm0name\":\"United States of America\",\"adm1name\":\"North Dakota\",\"iso_a2\":\"US\"},\"coordinates\":[218622,790468]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Fargo\",\"adm0name\":\"United States of America\",\"adm1name\":\"North Dakota\",\"iso_a2\":\"US\"},\"coordinates\":[231140,782439]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Hilo\",\"adm0name\":\"United States of America\",\"adm1name\":\"Hawaii\",\"iso_a2\":\"US\"},\"coordinates\":[69194,621429]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Olympia\",\"adm0name\":\"United States of America\",\"adm1name\":\"Washington\",\"iso_a2\":\"US\"},\"coordinates\":[158613,783392]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Spokane\",\"adm0name\":\"United States of America\",\"adm1name\":\"Washington\",\"iso_a2\":\"US\"},\"coordinates\":[173833,787136]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Vancouver\",\"adm0name\":\"United States of America\",\"adm1name\":\"Washington\",\"iso_a2\":\"US\"},\"coordinates\":[159333,775052]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Flagstaff\",\"adm0name\":\"United States of America\",\"adm1name\":\"Arizona\",\"iso_a2\":\"US\"},\"coordinates\":[189860,713247]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Tucson\",\"adm0name\":\"United States of America\",\"adm1name\":\"Arizona\",\"iso_a2\":\"US\"},\"coordinates\":[191967,695526]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Santa Barbara\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[167444,708726]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Fresno\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[167297,722427]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Eureka\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[155146,746448]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Colorado Springs\",\"adm0name\":\"United States of America\",\"adm1name\":\"Colorado\",\"iso_a2\":\"US\"},\"coordinates\":[208911,734959]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Reno\",\"adm0name\":\"United States of America\",\"adm1name\":\"Nevada\",\"iso_a2\":\"US\"},\"coordinates\":[167166,738910]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Elko\",\"adm0name\":\"United States of America\",\"adm1name\":\"Nevada\",\"iso_a2\":\"US\"},\"coordinates\":[178438,746627]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Albuquerque\",\"adm0name\":\"United States of America\",\"adm1name\":\"New Mexico\",\"iso_a2\":\"US\"},\"coordinates\":[203773,712695]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Salem\",\"adm0name\":\"United States of America\",\"adm1name\":\"Oregon\",\"iso_a2\":\"US\"},\"coordinates\":[158267,770891]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Casper\",\"adm0name\":\"United States of America\",\"adm1name\":\"Wyoming\",\"iso_a2\":\"US\"},\"coordinates\":[204687,758678]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Topeka\",\"adm0name\":\"United States of America\",\"adm1name\":\"Kansas\",\"iso_a2\":\"US\"},\"coordinates\":[234250,736067]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Kansas City\",\"adm0name\":\"United States of America\",\"adm1name\":\"Missouri\",\"iso_a2\":\"US\"},\"coordinates\":[237205,736416]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Tulsa\",\"adm0name\":\"United States of America\",\"adm1name\":\"Oklahoma\",\"iso_a2\":\"US\"},\"coordinates\":[233527,718708]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Sioux Falls\",\"adm0name\":\"United States of America\",\"adm1name\":\"South Dakota\",\"iso_a2\":\"US\"},\"coordinates\":[231305,762727]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Shreveport\",\"adm0name\":\"United States of America\",\"adm1name\":\"Louisiana\",\"iso_a2\":\"US\"},\"coordinates\":[239528,697262]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Baton Rouge\",\"adm0name\":\"United States of America\",\"adm1name\":\"Louisiana\",\"iso_a2\":\"US\"},\"coordinates\":[246833,685164]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ft. Worth\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[229610,698684]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Corpus Christi\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[229439,669078]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Austin\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[228487,684044]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Amarillo\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[217139,713436]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"El Paso\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[204133,693008]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Laredo\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[223591,667676]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Merida\",\"adm0name\":\"Venezuela\",\"adm1name\":\"Mérida\",\"iso_a2\":\"VE\"},\"coordinates\":[302417,554483]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Burlington\",\"adm0name\":\"United States of America\",\"adm1name\":\"Vermont\",\"iso_a2\":\"US\"},\"coordinates\":[296631,768212]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Montgomery\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alabama\",\"iso_a2\":\"US\"},\"coordinates\":[260335,696442]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Tallahassee\",\"adm0name\":\"United States of America\",\"adm1name\":\"Florida\",\"iso_a2\":\"US\"},\"coordinates\":[265888,685117]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Orlando\",\"adm0name\":\"United States of America\",\"adm1name\":\"Florida\",\"iso_a2\":\"US\"},\"coordinates\":[273939,673635]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jacksonville\",\"adm0name\":\"United States of America\",\"adm1name\":\"Florida\",\"iso_a2\":\"US\"},\"coordinates\":[273133,684418]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Savannah\",\"adm0name\":\"United States of America\",\"adm1name\":\"Georgia\",\"iso_a2\":\"US\"},\"coordinates\":[274695,694425]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Columbia\",\"adm0name\":\"United States of America\",\"adm1name\":\"South Carolina\",\"iso_a2\":\"US\"},\"coordinates\":[275277,706385]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Indianapolis\",\"adm0name\":\"United States of America\",\"adm1name\":\"Indiana\",\"iso_a2\":\"US\"},\"coordinates\":[260633,740225]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Wilmington\",\"adm0name\":\"United States of America\",\"adm1name\":\"North Carolina\",\"iso_a2\":\"US\"},\"coordinates\":[283486,707484]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Knoxville\",\"adm0name\":\"United States of America\",\"adm1name\":\"Tennessee\",\"iso_a2\":\"US\"},\"coordinates\":[266888,717820]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Richmond\",\"adm0name\":\"United States of America\",\"adm1name\":\"Virginia\",\"iso_a2\":\"US\"},\"coordinates\":[284855,727192]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Charleston\",\"adm0name\":\"United States of America\",\"adm1name\":\"West Virginia\",\"iso_a2\":\"US\"},\"coordinates\":[273243,731919]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Baltimore\",\"adm0name\":\"United States of America\",\"adm1name\":\"Maryland\",\"iso_a2\":\"US\"},\"coordinates\":[287161,737560]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Syracuse\",\"adm0name\":\"United States of America\",\"adm1name\":\"New York\",\"iso_a2\":\"US\"},\"coordinates\":[288472,759765]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Puerto Ayacucho\",\"adm0name\":\"Venezuela\",\"adm1name\":\"Amazonas\",\"iso_a2\":\"VE\"},\"coordinates\":[312156,538272]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Port-of-Spain\",\"adm0name\":\"Trinidad and Tobago\",\"adm1name\":\"Port of Spain\",\"iso_a2\":\"TT\"},\"coordinates\":[329119,567824]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Augusta\",\"adm0name\":\"United States of America\",\"adm1name\":\"Maine\",\"iso_a2\":\"US\"},\"coordinates\":[306167,767233]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Sault Ste. Marie\",\"adm0name\":\"United States of America\",\"adm1name\":\"Michigan\",\"iso_a2\":\"US\"},\"coordinates\":[265708,780176]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Atakpame\",\"adm0name\":\"Togo\",\"adm1name\":\"Plateaux\",\"iso_a2\":\"TG\"},\"coordinates\":[503110,549328]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Sousse\",\"adm0name\":\"Tunisia\",\"adm1name\":\"Sousse\",\"iso_a2\":\"TN\"},\"coordinates\":[529513,716990]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Taizz\",\"adm0name\":\"Yemen\",\"adm1name\":\"Ta`izz\",\"iso_a2\":\"YE\"},\"coordinates\":[622326,585327]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Sitka\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[124090,842768]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Lvov\",\"adm0name\":\"Ukraine\",\"adm1name\":\"L'viv\",\"iso_a2\":\"UA\"},\"coordinates\":[566750,799962]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Odessa\",\"adm0name\":\"Ukraine\",\"adm1name\":\"Odessa\",\"iso_a2\":\"UA\"},\"coordinates\":[585299,780156]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Zhytomyr\",\"adm0name\":\"Ukraine\",\"adm1name\":\"Zhytomyr\",\"iso_a2\":\"UA\"},\"coordinates\":[579616,802395]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Dnipropetrovsk\",\"adm0name\":\"Ukraine\",\"adm1name\":\"Dnipropetrovs'k\",\"iso_a2\":\"UA\"},\"coordinates\":[597216,791946]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Donetsk\",\"adm0name\":\"Ukraine\",\"adm1name\":\"Donets'k\",\"iso_a2\":\"UA\"},\"coordinates\":[605077,789102]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Kharkiv\",\"adm0name\":\"Ukraine\",\"adm1name\":\"Kharkiv\",\"iso_a2\":\"UA\"},\"coordinates\":[600689,800951]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Turkmenbasy\",\"adm0name\":\"Turkmenistan\",\"adm1name\":\"Balkan\",\"iso_a2\":\"TM\"},\"coordinates\":[647137,741831]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Bukhara\",\"adm0name\":\"Uzbekistan\",\"adm1name\":\"Bukhoro\",\"iso_a2\":\"UZ\"},\"coordinates\":[678972,740392]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Nukus\",\"adm0name\":\"Uzbekistan\",\"adm1name\":\"Karakalpakstan\",\"iso_a2\":\"UZ\"},\"coordinates\":[665596,756329]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Turkmenabat\",\"adm0name\":\"Turkmenistan\",\"adm1name\":\"Chardzhou\",\"iso_a2\":\"TM\"},\"coordinates\":[676610,736423]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Mary\",\"adm0name\":\"Turkmenistan\",\"adm1name\":\"Mary\",\"iso_a2\":\"TM\"},\"coordinates\":[671759,727476]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Andijon\",\"adm0name\":\"Uzbekistan\",\"adm1name\":\"Andijon\",\"iso_a2\":\"UZ\"},\"coordinates\":[700944,746376]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Haiphong\",\"adm0name\":\"Vietnam\",\"adm1name\":\"Qu?ng Ninh\",\"iso_a2\":\"VN\"},\"coordinates\":[796328,628135]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Da Nang\",\"adm0name\":\"Vietnam\",\"adm1name\":\"Ðà N?ng\",\"iso_a2\":\"VN\"},\"coordinates\":[800693,599864]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Kabwe\",\"adm0name\":\"Zambia\",\"adm1name\":\"Central\",\"iso_a2\":\"ZM\"},\"coordinates\":[579027,419168]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Mufulira\",\"adm0name\":\"Zambia\",\"adm1name\":\"Copperbelt\",\"iso_a2\":\"ZM\"},\"coordinates\":[578499,430365]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Kitwe\",\"adm0name\":\"Zambia\",\"adm1name\":\"Copperbelt\",\"iso_a2\":\"ZM\"},\"coordinates\":[578388,428825]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Livingstone\",\"adm0name\":\"Zambia\",\"adm1name\":\"Southern\",\"iso_a2\":\"ZM\"},\"coordinates\":[571833,398907]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Chitungwiza\",\"adm0name\":\"Zimbabwe\",\"adm1name\":\"Harare\",\"iso_a2\":\"ZW\"},\"coordinates\":[586388,398077]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Douala\",\"adm0name\":\"Cameroon\",\"adm1name\":\"Littoral\",\"iso_a2\":\"CM\"},\"coordinates\":[526967,528784]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Birmingham\",\"adm0name\":\"United Kingdom\",\"adm1name\":\"West Midlands\",\"iso_a2\":\"GB\"},\"coordinates\":[494661,815614]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Belfast\",\"adm0name\":\"United Kingdom\",\"adm1name\":\"Belfast\",\"iso_a2\":\"GB\"},\"coordinates\":[483444,828192]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Izmir\",\"adm0name\":\"Turkey\",\"adm1name\":\"Izmir\",\"iso_a2\":\"TR\"},\"coordinates\":[575416,732442]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Bursa\",\"adm0name\":\"Turkey\",\"adm1name\":\"Bursa\",\"iso_a2\":\"TR\"},\"coordinates\":[580744,742892]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Samsun\",\"adm0name\":\"Turkey\",\"adm1name\":\"Samsun\",\"iso_a2\":\"TR\"},\"coordinates\":[600954,749278]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Konya\",\"adm0name\":\"Turkey\",\"adm1name\":\"Konya\",\"iso_a2\":\"TR\"},\"coordinates\":[590203,729117]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Adana\",\"adm0name\":\"Turkey\",\"adm1name\":\"Adana\",\"iso_a2\":\"TR\"},\"coordinates\":[598105,723904]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Gulu\",\"adm0name\":\"Uganda\",\"adm1name\":\"Aswa\",\"iso_a2\":\"UG\"},\"coordinates\":[589666,521187]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Kigali\",\"adm0name\":\"Rwanda\",\"adm1name\":\"Kigali City\",\"iso_a2\":\"RW\"},\"coordinates\":[583496,493155]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Cottica\",\"adm0name\":\"Suriname\",\"adm1name\":\"Sipaliwini\",\"iso_a2\":\"SR\"},\"coordinates\":[349352,527527]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Cordoba\",\"adm0name\":\"Spain\",\"adm1name\":\"Andalucía\",\"iso_a2\":\"ES\"},\"coordinates\":[486749,729135]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Maradi\",\"adm0name\":\"Niger\",\"adm1name\":\"Maradi\",\"iso_a2\":\"NE\"},\"coordinates\":[519712,584648]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Tahoua\",\"adm0name\":\"Niger\",\"adm1name\":\"Tahoua\",\"iso_a2\":\"NE\"},\"coordinates\":[514610,592991]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Constanta\",\"adm0name\":\"Romania\",\"adm1name\":\"Constanta\",\"iso_a2\":\"RO\"},\"coordinates\":[579472,766594]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Luleå\",\"adm0name\":\"Sweden\",\"adm1name\":\"Norrbotten\",\"iso_a2\":\"SE\"},\"coordinates\":[561551,893341]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Sundsvall\",\"adm0name\":\"Sweden\",\"adm1name\":\"Västernorrland\",\"iso_a2\":\"SE\"},\"coordinates\":[548101,874403]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Iasi\",\"adm0name\":\"Romania\",\"adm1name\":\"Iasi\",\"iso_a2\":\"RO\"},\"coordinates\":[576596,784163]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Surat Thani\",\"adm0name\":\"Thailand\",\"adm1name\":\"Surat Thani\",\"iso_a2\":\"TH\"},\"coordinates\":[775944,558926]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Chiang Mai\",\"adm0name\":\"Thailand\",\"adm1name\":\"Chiang Mai\",\"iso_a2\":\"TH\"},\"coordinates\":[774944,616096]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Nakhon Ratchasima\",\"adm0name\":\"Thailand\",\"adm1name\":\"Nakhon Ratchasima\",\"iso_a2\":\"TH\"},\"coordinates\":[783611,593584]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Mbabane\",\"adm0name\":\"Swaziland\",\"adm1name\":\"Hhohho\",\"iso_a2\":\"SZ\"},\"coordinates\":[586481,348805]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Piura\",\"adm0name\":\"Peru\",\"adm1name\":\"Piura\",\"iso_a2\":\"PE\"},\"coordinates\":[276028,473851]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Arequipa\",\"adm0name\":\"Peru\",\"adm1name\":\"Arequipa\",\"iso_a2\":\"PE\"},\"coordinates\":[301300,407449]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Chimbote\",\"adm0name\":\"Peru\",\"adm1name\":\"Ancash\",\"iso_a2\":\"PE\"},\"coordinates\":[281750,450982]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Pucallpa\",\"adm0name\":\"Peru\",\"adm1name\":\"Ucayali\",\"iso_a2\":\"PE\"},\"coordinates\":[292958,455136]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Iquitos\",\"adm0name\":\"Peru\",\"adm1name\":\"Loreto\",\"iso_a2\":\"PE\"},\"coordinates\":[296527,482500]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Huancayo\",\"adm0name\":\"Peru\",\"adm1name\":\"Junín\",\"iso_a2\":\"PE\"},\"coordinates\":[291110,433149]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Ciudad del Este\",\"adm0name\":\"Paraguay\",\"adm1name\":\"Alto Paraná\",\"iso_a2\":\"PY\"},\"coordinates\":[348289,353544]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Ponta Delgada\",\"adm0name\":\"Portugal\",\"adm1name\":\"Azores\",\"iso_a2\":\"PT\"},\"coordinates\":[428704,728355]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Vigo\",\"adm0name\":\"Spain\",\"adm1name\":\"Galicia\",\"iso_a2\":\"ES\"},\"coordinates\":[475750,754847]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Bilbao\",\"adm0name\":\"Spain\",\"adm1name\":\"País Vasco\",\"iso_a2\":\"ES\"},\"coordinates\":[491861,760950]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Kaolack\",\"adm0name\":\"Senegal\",\"adm1name\":\"Kaolack\",\"iso_a2\":\"SM\"},\"coordinates\":[455277,588548]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Kaedi\",\"adm0name\":\"Senegal\",\"adm1name\":\"Matam\",\"iso_a2\":\"SM\"},\"coordinates\":[462500,600397]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Geneina\",\"adm0name\":\"Sudan\",\"adm1name\":\"West Darfur\",\"iso_a2\":\"SD\"},\"coordinates\":[562333,584401]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Medina\",\"adm0name\":\"Saudi Arabia\",\"adm1name\":\"Al Madinah\",\"iso_a2\":\"SA\"},\"coordinates\":[609939,649878]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Tabuk\",\"adm0name\":\"Saudi Arabia\",\"adm1name\":\"Tabuk\",\"iso_a2\":\"SA\"},\"coordinates\":[601541,672875]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Juba\",\"adm0name\":\"South Sudan\",\"adm1name\":\"Central Equatoria\",\"iso_a2\":\"SS\"},\"coordinates\":[587722,533332]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Malakal\",\"adm0name\":\"South Sudan\",\"adm1name\":\"Upper Nile\",\"iso_a2\":\"SS\"},\"coordinates\":[587933,561218]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Omdurman\",\"adm0name\":\"Sudan\",\"adm1name\":\"Khartoum\",\"iso_a2\":\"SD\"},\"coordinates\":[590222,597237]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"El Obeid\",\"adm0name\":\"Sudan\",\"adm1name\":\"North Kurdufan\",\"iso_a2\":\"SD\"},\"coordinates\":[583935,582821]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"The Hague\",\"adm0name\":\"Netherlands\",\"adm1name\":\"Zuid-Holland\",\"iso_a2\":\"NL\"},\"coordinates\":[511860,813263]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Kristiansand\",\"adm0name\":\"Norway\",\"adm1name\":\"Vest-Agder\",\"iso_a2\":\"NO\"},\"coordinates\":[522222,849323]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Ljubljana\",\"adm0name\":\"Slovenia\",\"adm1name\":\"Osrednjeslovenska\",\"iso_a2\":\"SI\"},\"coordinates\":[540318,777570]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Bratislava\",\"adm0name\":\"Slovakia\",\"adm1name\":\"Bratislavský\",\"iso_a2\":\"SK\"},\"coordinates\":[547547,789979]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Hammerfest\",\"adm0name\":\"Norway\",\"adm1name\":\"Finnmark\",\"iso_a2\":\"NO\"},\"coordinates\":[565800,923346]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Doha\",\"adm0name\":\"Qatar\",\"adm1name\":\"Ad Dawhah\",\"iso_a2\":\"QA\"},\"coordinates\":[643147,654526]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Quetta\",\"adm0name\":\"Pakistan\",\"adm1name\":\"Baluchistan\",\"iso_a2\":\"PK\"},\"coordinates\":[686175,683766]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Larkana\",\"adm0name\":\"Pakistan\",\"adm1name\":\"Sind\",\"iso_a2\":\"PK\"},\"coordinates\":[689463,668005]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Springbok\",\"adm0name\":\"South Africa\",\"adm1name\":\"Northern Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[549675,328958]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Upington\",\"adm0name\":\"South Africa\",\"adm1name\":\"Northern Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[558972,336107]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Worcester\",\"adm0name\":\"South Africa\",\"adm1name\":\"Western Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[553999,305418]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"George\",\"adm0name\":\"South Africa\",\"adm1name\":\"Western Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[562360,303582]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Tete\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Tete\",\"iso_a2\":\"MZ\"},\"coordinates\":[593277,408919]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Pemba\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Cabo Delgado\",\"iso_a2\":\"MZ\"},\"coordinates\":[612589,427799]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Nampula\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Nampula\",\"iso_a2\":\"MZ\"},\"coordinates\":[609147,415044]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Welkom\",\"adm0name\":\"South Africa\",\"adm1name\":\"Orange Free State\",\"iso_a2\":\"ZA\"},\"coordinates\":[574249,339011]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Xai-Xai\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Gaza\",\"iso_a2\":\"MZ\"},\"coordinates\":[593443,356369]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Goroka\",\"adm0name\":\"Papua New Guinea\",\"adm1name\":\"Eastern Highlands\",\"iso_a2\":\"PG\"},\"coordinates\":[903848,468677]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Mt. Hagen\",\"adm0name\":\"Papua New Guinea\",\"adm1name\":\"Western Highlands\",\"iso_a2\":\"PG\"},\"coordinates\":[900601,469980]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Rabaul\",\"adm0name\":\"Papua New Guinea\",\"adm1name\":\"East New Britain\",\"iso_a2\":\"PG\"},\"coordinates\":[922620,479802]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Lae\",\"adm0name\":\"Papua New Guinea\",\"adm1name\":\"Morobe\",\"iso_a2\":\"PG\"},\"coordinates\":[908305,464828]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"David\",\"adm0name\":\"Panama\",\"adm1name\":\"Chiriquí\",\"iso_a2\":\"PA\"},\"coordinates\":[271018,554680]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Oujda\",\"adm0name\":\"Morocco\",\"adm1name\":\"Oriental\",\"iso_a2\":\"MA\"},\"coordinates\":[494694,710237]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Safi\",\"adm0name\":\"Morocco\",\"adm1name\":\"Doukkala - Abda\",\"iso_a2\":\"MA\"},\"coordinates\":[474333,696195]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Podgorica\",\"adm0name\":\"Montenegro\",\"adm1name\":\"Podgorica\",\"iso_a2\":\"ME\"},\"coordinates\":[553517,756305]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Quelimane\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Zambezia\",\"iso_a2\":\"MZ\"},\"coordinates\":[602472,398787]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"East London\",\"adm0name\":\"South Africa\",\"adm1name\":\"Eastern Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[577416,309388]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Middelburg\",\"adm0name\":\"South Africa\",\"adm1name\":\"Eastern Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[569472,318097]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Naltchik\",\"adm0name\":\"Russia\",\"adm1name\":\"Kabardin-Balkar\",\"iso_a2\":\"RU\"},\"coordinates\":[621161,762420]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Stavropol\",\"adm0name\":\"Russia\",\"adm1name\":\"Stavropol'\",\"iso_a2\":\"RU\"},\"coordinates\":[616610,771613]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ugolnye Kopi\",\"adm0name\":\"Russia\",\"adm1name\":\"Chukchi Autonomous Okrug\",\"iso_a2\":\"RU\"},\"coordinates\":[993610,888227]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kaliningrad\",\"adm0name\":\"Russia\",\"adm1name\":\"Kaliningrad\",\"iso_a2\":\"RU\"},\"coordinates\":[556937,828785]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Pskov\",\"adm0name\":\"Russia\",\"adm1name\":\"Pskov\",\"iso_a2\":\"RU\"},\"coordinates\":[578694,847328]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Bryansk\",\"adm0name\":\"Russia\",\"adm1name\":\"Bryansk\",\"iso_a2\":\"RU\"},\"coordinates\":[595638,820254]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Smolensk\",\"adm0name\":\"Russia\",\"adm1name\":\"Smolensk\",\"iso_a2\":\"RU\"},\"coordinates\":[589020,829274]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Petrozavodsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Karelia\",\"iso_a2\":\"RU\"},\"coordinates\":[595222,871144]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Tver\",\"adm0name\":\"Russia\",\"adm1name\":\"Tver'\",\"iso_a2\":\"RU\"},\"coordinates\":[599693,841581]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Vologda\",\"adm0name\":\"Russia\",\"adm1name\":\"Vologda\",\"iso_a2\":\"RU\"},\"coordinates\":[610888,855504]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Yaroslavl\",\"adm0name\":\"Russia\",\"adm1name\":\"Yaroslavl'\",\"iso_a2\":\"RU\"},\"coordinates\":[610749,846084]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Rostov\",\"adm0name\":\"Russia\",\"adm1name\":\"Rostov\",\"iso_a2\":\"RU\"},\"coordinates\":[610307,784568]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Sochi\",\"adm0name\":\"Russia\",\"adm1name\":\"Krasnodar\",\"iso_a2\":\"RU\"},\"coordinates\":[610360,762964]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Krasnodar\",\"adm0name\":\"Russia\",\"adm1name\":\"Krasnodar\",\"iso_a2\":\"RU\"},\"coordinates\":[608333,771435]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Penza\",\"adm0name\":\"Russia\",\"adm1name\":\"Penza\",\"iso_a2\":\"RU\"},\"coordinates\":[624999,819779]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ryazan\",\"adm0name\":\"Russia\",\"adm1name\":\"Ryazan'\",\"iso_a2\":\"RU\"},\"coordinates\":[610333,828311]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Voronezh\",\"adm0name\":\"Russia\",\"adm1name\":\"Voronezh\",\"iso_a2\":\"RU\"},\"coordinates\":[609077,811201]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Magnitogorsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Chelyabinsk\",\"iso_a2\":\"RU\"},\"coordinates\":[663833,821217]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Chelyabinsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Chelyabinsk\",\"iso_a2\":\"RU\"},\"coordinates\":[670657,831492]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Vorkuta\",\"adm0name\":\"Russia\",\"adm1name\":\"Komi\",\"iso_a2\":\"RU\"},\"coordinates\":[677805,904617]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kirov\",\"adm0name\":\"Russia\",\"adm1name\":\"Kirov\",\"iso_a2\":\"RU\"},\"coordinates\":[637971,851831]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Nizhny Tagil\",\"adm0name\":\"Russia\",\"adm1name\":\"Sverdlovsk\",\"iso_a2\":\"RU\"},\"coordinates\":[666597,847862]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Astrakhan\",\"adm0name\":\"Russia\",\"adm1name\":\"Astrakhan'\",\"iso_a2\":\"RU\"},\"coordinates\":[633486,779307]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Orenburg\",\"adm0name\":\"Russia\",\"adm1name\":\"Orenburg\",\"iso_a2\":\"RU\"},\"coordinates\":[653083,811485]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Saratov\",\"adm0name\":\"Russia\",\"adm1name\":\"Saratov\",\"iso_a2\":\"RU\"},\"coordinates\":[627855,810312]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ulyanovsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Ul'yanovsk\",\"iso_a2\":\"RU\"},\"coordinates\":[634471,826592]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Omsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Omsk\",\"iso_a2\":\"RU\"},\"coordinates\":[703882,830514]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Tyumen\",\"adm0name\":\"Russia\",\"adm1name\":\"Tyumen'\",\"iso_a2\":\"RU\"},\"coordinates\":[682027,843241]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Novokuznetsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Kemerovo\",\"iso_a2\":\"RU\"},\"coordinates\":[741986,823156]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kemerovo\",\"adm0name\":\"Russia\",\"adm1name\":\"Kemerovo\",\"iso_a2\":\"RU\"},\"coordinates\":[739139,832576]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Groznyy\",\"adm0name\":\"Russia\",\"adm1name\":\"Chechnya\",\"iso_a2\":\"RU\"},\"coordinates\":[626940,761357]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Kandy\",\"adm0name\":\"Sri Lanka\",\"adm1name\":\"Kandy\",\"iso_a2\":\"LK\"},\"coordinates\":[724082,547847]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Sri Jawewardenepura Kotte\",\"adm0name\":\"Sri Lanka\",\"adm1name\":\"Colombo\",\"iso_a2\":\"LK\"},\"coordinates\":[722082,545596]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Daejeon\",\"adm0name\":\"South Korea\",\"adm1name\":\"Daejeon\",\"iso_a2\":\"KR\"},\"coordinates\":[853952,719997]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Gwangju\",\"adm0name\":\"South Korea\",\"adm1name\":\"Kwangju-gwangyoksi\",\"iso_a2\":\"KR\"},\"coordinates\":[852523,713097]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Busan\",\"adm0name\":\"South Korea\",\"adm1name\":\"Busan\",\"iso_a2\":\"KR\"},\"coordinates\":[858355,712648]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Zamboanga\",\"adm0name\":\"Philippines\",\"adm1name\":\"Zamboanga del Sur\",\"iso_a2\":\"PH\"},\"coordinates\":[839105,545725]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Laoag\",\"adm0name\":\"Philippines\",\"adm1name\":\"Ilocos Norte\",\"iso_a2\":\"PH\"},\"coordinates\":[834981,612535]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Baguio City\",\"adm0name\":\"Philippines\",\"adm1name\":\"Benguet\",\"iso_a2\":\"PH\"},\"coordinates\":[834915,602056]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"General Santos\",\"adm0name\":\"Philippines\",\"adm1name\":\"South Cotabato\",\"iso_a2\":\"PH\"},\"coordinates\":[847707,540920]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ust-Ulimsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Irkutsk\",\"iso_a2\":\"RU\"},\"coordinates\":[785092,848276]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Angarsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Irkutsk\",\"iso_a2\":\"RU\"},\"coordinates\":[788666,816107]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Abakan\",\"adm0name\":\"Russia\",\"adm1name\":\"Krasnoyarsk\",\"iso_a2\":\"RU\"},\"coordinates\":[754013,822882]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Norilsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Taymyr\",\"iso_a2\":\"RU\"},\"coordinates\":[745068,915519]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Khatanga\",\"adm0name\":\"Russia\",\"adm1name\":\"Taymyr\",\"iso_a2\":\"RU\"},\"coordinates\":[784624,931522]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kyzyl\",\"adm0name\":\"Russia\",\"adm1name\":\"Tuva\",\"iso_a2\":\"RU\"},\"coordinates\":[762175,811051]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ulan Ude\",\"adm0name\":\"Russia\",\"adm1name\":\"Buryat\",\"iso_a2\":\"RU\"},\"coordinates\":[798958,811752]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Blagoveshchensk\",\"adm0name\":\"Russia\",\"adm1name\":\"Amur\",\"iso_a2\":\"RU\"},\"coordinates\":[854259,802519]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Bukachacha\",\"adm0name\":\"Russia\",\"adm1name\":\"Chita\",\"iso_a2\":\"RU\"},\"coordinates\":[824768,818614]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Dalnegorsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Primor'ye\",\"iso_a2\":\"RU\"},\"coordinates\":[876436,768575]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ambarchik\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[950925,917361]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Batagay\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[873985,905542]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Chokurdakh\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[910817,923092]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ust Nera\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[897777,887239]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Lensk\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[819296,864481]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Aldan\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[848303,851908]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Mirnyy\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[816558,875232]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Zhigansk\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[842697,900291]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Okhotsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Khabarovsk\",\"iso_a2\":\"RU\"},\"coordinates\":[897824,856529]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Khabarovsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Khabarovsk\",\"iso_a2\":\"RU\"},\"coordinates\":[875333,791786]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Okha\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakhalin\",\"iso_a2\":\"RU\"},\"coordinates\":[897076,822113]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Yuzhno Sakhalinsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakhalin\",\"iso_a2\":\"RU\"},\"coordinates\":[896500,782959]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Mexicali\",\"adm0name\":\"Mexico\",\"adm1name\":\"Baja California\",\"iso_a2\":\"MX\"},\"coordinates\":[179216,698162]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"La Paz\",\"adm0name\":\"Mexico\",\"adm1name\":\"Baja California Sur\",\"iso_a2\":\"MX\"},\"coordinates\":[193556,647733]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Torreon\",\"adm0name\":\"Mexico\",\"adm1name\":\"Coahuila\",\"iso_a2\":\"MX\"},\"coordinates\":[212716,656217]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Culiacan\",\"adm0name\":\"Mexico\",\"adm1name\":\"Sinaloa\",\"iso_a2\":\"MX\"},\"coordinates\":[201716,651833]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Nogales\",\"adm0name\":\"Mexico\",\"adm1name\":\"Sonora\",\"iso_a2\":\"MX\"},\"coordinates\":[191820,690182]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Hermosillo\",\"adm0name\":\"Mexico\",\"adm1name\":\"Sonora\",\"iso_a2\":\"MX\"},\"coordinates\":[191794,677112]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Guaymas\",\"adm0name\":\"Mexico\",\"adm1name\":\"Sonora\",\"iso_a2\":\"MX\"},\"coordinates\":[191972,670187]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"San Luis Potosi\",\"adm0name\":\"Mexico\",\"adm1name\":\"San Luis Potosí\",\"iso_a2\":\"MX\"},\"coordinates\":[219439,636074]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Matamoros\",\"adm0name\":\"Mexico\",\"adm1name\":\"Tamaulipas\",\"iso_a2\":\"MX\"},\"coordinates\":[229166,658042]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Nuevo Laredo\",\"adm0name\":\"Mexico\",\"adm1name\":\"Tamaulipas\",\"iso_a2\":\"MX\"},\"coordinates\":[223472,667639]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Colima\",\"adm0name\":\"Mexico\",\"adm1name\":\"Colima\",\"iso_a2\":\"MX\"},\"coordinates\":[211889,618644]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Campeche\",\"adm0name\":\"Mexico\",\"adm1name\":\"Campeche\",\"iso_a2\":\"MX\"},\"coordinates\":[248611,622199]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Oaxaca\",\"adm0name\":\"Mexico\",\"adm1name\":\"Oaxaca\",\"iso_a2\":\"MX\"},\"coordinates\":[231472,605923]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Leon\",\"adm0name\":\"Mexico\",\"adm1name\":\"Guanajuato\",\"iso_a2\":\"MX\"},\"coordinates\":[217495,630031]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Maiduguri\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Borno\",\"iso_a2\":\"NG\"},\"coordinates\":[536550,574933]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Port Harcourt\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Rivers\",\"iso_a2\":\"NG\"},\"coordinates\":[519466,533225]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Makurdi\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Benue\",\"iso_a2\":\"NG\"},\"coordinates\":[523694,550513]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ibadan\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Oyo\",\"iso_a2\":\"NG\"},\"coordinates\":[510910,548451]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Ogbomosho\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Oyo\",\"iso_a2\":\"NG\"},\"coordinates\":[511772,552894]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Warri\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Delta\",\"iso_a2\":\"NG\"},\"coordinates\":[515999,537420]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kaduna\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Kaduna\",\"iso_a2\":\"NG\"},\"coordinates\":[520661,567054]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Gdansk\",\"adm0name\":\"Poland\",\"adm1name\":\"Pomeranian\",\"iso_a2\":\"PL\"},\"coordinates\":[551777,826770]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Kraków\",\"adm0name\":\"Poland\",\"adm1name\":\"Lesser Poland\",\"iso_a2\":\"PL\"},\"coordinates\":[555438,801306]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Dalandzadgad\",\"adm0name\":\"Mongolia\",\"adm1name\":\"Ömnögovi\",\"iso_a2\":\"MN\"},\"coordinates\":[790111,762926]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Wonsan\",\"adm0name\":\"North Korea\",\"adm1name\":\"Kangwon-do\",\"iso_a2\":\"KP\"},\"coordinates\":[853974,736721]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Sinuiju\",\"adm0name\":\"North Korea\",\"adm1name\":\"P'yongan-bukto\",\"iso_a2\":\"KP\"},\"coordinates\":[845613,742204]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Dund-Us\",\"adm0name\":\"Mongolia\",\"adm1name\":\"Hovd\",\"iso_a2\":\"MN\"},\"coordinates\":[754536,789189]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Choybalsan\",\"adm0name\":\"Mongolia\",\"adm1name\":\"Dornod\",\"iso_a2\":\"MN\"},\"coordinates\":[818071,789486]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Lüderitz\",\"adm0name\":\"Namibia\",\"adm1name\":\"Karas\",\"iso_a2\":\"NA\"},\"coordinates\":[542109,346842]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Walvis Bay\",\"adm0name\":\"Namibia\",\"adm1name\":\"Erongo\",\"iso_a2\":\"NA\"},\"coordinates\":[540292,368707]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Mwanza\",\"adm0name\":\"Tanzania\",\"adm1name\":\"Mwanza\",\"iso_a2\":\"TZ\"},\"coordinates\":[591472,489788]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Morogoro\",\"adm0name\":\"Tanzania\",\"adm1name\":\"Morogoro\",\"iso_a2\":\"TZ\"},\"coordinates\":[604610,464312]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Dodoma\",\"adm0name\":\"Tanzania\",\"adm1name\":\"Dodoma\",\"iso_a2\":\"TZ\"},\"coordinates\":[599305,468084]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Arusha\",\"adm0name\":\"Tanzania\",\"adm1name\":\"Arusha\",\"iso_a2\":\"TZ\"},\"coordinates\":[601861,484811]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Napier\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Gisborne\",\"iso_a2\":\"NZ\"},\"coordinates\":[991429,270760]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Manukau\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Auckland\",\"iso_a2\":\"NZ\"},\"coordinates\":[985790,285513]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Hamilton\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Auckland\",\"iso_a2\":\"NZ\"},\"coordinates\":[986944,280950]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Blenheim\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Marlborough\",\"iso_a2\":\"NZ\"},\"coordinates\":[983220,258728]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Dunedin\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Otago\",\"iso_a2\":\"NZ\"},\"coordinates\":[973555,232904]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Bern\",\"adm0name\":\"Switzerland\",\"adm1name\":\"Bern\",\"iso_a2\":\"CH\"},\"coordinates\":[520741,782673]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Malmö\",\"adm0name\":\"Sweden\",\"adm1name\":\"Skåne\",\"iso_a2\":\"SE\"},\"coordinates\":[536203,834018]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Laayoune\",\"adm0name\":\"Morocco\",\"adm1name\":\"Laâyoune - Boujdour - Sakia El Hamra\",\"iso_a2\":\"MA\"},\"coordinates\":[463333,665566]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ternate\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Maluku Utara\",\"iso_a2\":\"ID\"},\"coordinates\":[853785,509415]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ambon\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Maluku\",\"iso_a2\":\"ID\"},\"coordinates\":[856110,482698]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Raba\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Nusa Tenggara Barat\",\"iso_a2\":\"ID\"},\"coordinates\":[829907,454656]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jayapura\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Papua\",\"iso_a2\":\"ID\"},\"coordinates\":[890832,489710]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Florence\",\"adm0name\":\"Italy\",\"adm1name\":\"Toscana\",\"iso_a2\":\"IT\"},\"coordinates\":[531250,764090]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Catania\",\"adm0name\":\"Italy\",\"adm1name\":\"Sicily\",\"iso_a2\":\"IT\"},\"coordinates\":[541888,726884]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Pristina\",\"adm0name\":\"Kosovo\",\"adm1name\":\"Pristina\",\"iso_a2\":\"-99\"},\"coordinates\":[558793,757494]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Meru\",\"adm0name\":\"Kenya\",\"adm1name\":\"Eastern\",\"iso_a2\":\"KE\"},\"coordinates\":[604555,505072]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Eldoret\",\"adm0name\":\"Kenya\",\"adm1name\":\"Rift Valley\",\"iso_a2\":\"KE\"},\"coordinates\":[597971,507798]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Banda Aceh\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Aceh\",\"iso_a2\":\"ID\"},\"coordinates\":[764777,537597]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"George Town\",\"adm0name\":\"Malaysia\",\"adm1name\":\"Pulau Pinang\",\"iso_a2\":\"MY\"},\"coordinates\":[778692,536790]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Zhangye\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[779027,735356]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Wuwei\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[785113,729420]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Dunhuang\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[762949,742540]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Tianshui\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[794216,709715]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Dulan\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[772962,718985]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Golmud\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[763564,720465]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Yulin\",\"adm0name\":\"China\",\"adm1name\":\"Guangxi\",\"iso_a2\":\"CN\"},\"coordinates\":[805966,638799]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Bose\",\"adm0name\":\"China\",\"adm1name\":\"Guangxi\",\"iso_a2\":\"CN\"},\"coordinates\":[796147,646309]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Wuzhou\",\"adm0name\":\"China\",\"adm1name\":\"Guangxi\",\"iso_a2\":\"CN\"},\"coordinates\":[809222,643823]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Lupanshui\",\"adm0name\":\"China\",\"adm1name\":\"Guizhou\",\"iso_a2\":\"CN\"},\"coordinates\":[791198,662286]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Quanzhou\",\"adm0name\":\"China\",\"adm1name\":\"Fujian\",\"iso_a2\":\"CN\"},\"coordinates\":[829382,652248]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Hefei\",\"adm0name\":\"China\",\"adm1name\":\"Anhui\",\"iso_a2\":\"CN\"},\"coordinates\":[825772,693423]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Suzhou\",\"adm0name\":\"China\",\"adm1name\":\"Anhui\",\"iso_a2\":\"CN\"},\"coordinates\":[824935,704004]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Zhanjiang\",\"adm0name\":\"China\",\"adm1name\":\"Guangdong\",\"iso_a2\":\"CN\"},\"coordinates\":[806605,630327]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Shaoguan\",\"adm0name\":\"China\",\"adm1name\":\"Guangdong\",\"iso_a2\":\"CN\"},\"coordinates\":[815499,651643]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Balikpapan\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Kalimantan Timur\",\"iso_a2\":\"ID\"},\"coordinates\":[824527,497311]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Kuching\",\"adm0name\":\"Malaysia\",\"adm1name\":\"Sarawak\",\"iso_a2\":\"MY\"},\"coordinates\":[806472,513781]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Antsiranana\",\"adm0name\":\"Madagascar\",\"adm1name\":\"Antsiranana\",\"iso_a2\":\"MG\"},\"coordinates\":[636976,431985]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Fianarantsoa\",\"adm0name\":\"Madagascar\",\"adm1name\":\"Fianarantsoa\",\"iso_a2\":\"MG\"},\"coordinates\":[630786,377736]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Mahajanga\",\"adm0name\":\"Madagascar\",\"adm1name\":\"Mahajanga\",\"iso_a2\":\"MG\"},\"coordinates\":[628736,411881]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Toliara\",\"adm0name\":\"Madagascar\",\"adm1name\":\"Toliary\",\"iso_a2\":\"MG\"},\"coordinates\":[621360,366340]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Surakarta\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Jawa Tengah\",\"iso_a2\":\"ID\"},\"coordinates\":[807846,459899]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Bandar Lampung\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Lampung\",\"iso_a2\":\"ID\"},\"coordinates\":[792411,472559]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Tanjungpandan\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Bangka-Belitung\",\"iso_a2\":\"ID\"},\"coordinates\":[799027,488425]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Malang\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Jawa Timur\",\"iso_a2\":\"ID\"},\"coordinates\":[812800,457451]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Kupang\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Nusa Tenggara Timur\",\"iso_a2\":\"ID\"},\"coordinates\":[843285,444414]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Parepare\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Sulawesi Selatan\",\"iso_a2\":\"ID\"},\"coordinates\":[832314,480920]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Cuenca\",\"adm0name\":\"Ecuador\",\"adm1name\":\"Azuay\",\"iso_a2\":\"EC\"},\"coordinates\":[280555,487536]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Santa Cruz\",\"adm0name\":\"Ecuador\",\"adm1name\":\"Galápagos\",\"iso_a2\":\"EC\"},\"coordinates\":[249027,501557]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Puerto Limon\",\"adm0name\":\"Costa Rica\",\"adm1name\":\"Limón\",\"iso_a2\":\"CR\"},\"coordinates\":[269351,563962]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Santiago de Cuba\",\"adm0name\":\"Cuba\",\"adm1name\":\"Santiago de Cuba\",\"iso_a2\":\"CU\"},\"coordinates\":[289385,623354]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Santiago\",\"adm0name\":\"Dominican Republic\",\"adm1name\":\"Santiago\",\"iso_a2\":\"DO\"},\"coordinates\":[303694,620244]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Manizales\",\"adm0name\":\"Colombia\",\"adm1name\":\"Caldas\",\"iso_a2\":\"CO\"},\"coordinates\":[290222,534695]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Pasto\",\"adm0name\":\"Colombia\",\"adm1name\":\"Nariño\",\"iso_a2\":\"CO\"},\"coordinates\":[285330,511907]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Barranquilla\",\"adm0name\":\"Colombia\",\"adm1name\":\"Atlántico\",\"iso_a2\":\"CO\"},\"coordinates\":[292217,569660]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Roseau\",\"adm0name\":\"Dominica\",\"adm1name\":\"Saint George\",\"iso_a2\":\"DM\"},\"coordinates\":[329480,595367]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Mbandaka\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Équateur\",\"iso_a2\":\"CD\"},\"coordinates\":[550722,504955]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Moundou\",\"adm0name\":\"Chad\",\"adm1name\":\"Logone Oriental\",\"iso_a2\":\"TD\"},\"coordinates\":[544694,555371]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Suez\",\"adm0name\":\"Egypt\",\"adm1name\":\"As Suways\",\"iso_a2\":\"EG\"},\"coordinates\":[590416,682480]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Bur Said\",\"adm0name\":\"Egypt\",\"adm1name\":\"Bur Sa`id\",\"iso_a2\":\"EG\"},\"coordinates\":[589694,689915]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"El Faiyum\",\"adm0name\":\"Egypt\",\"adm1name\":\"Al Fayyum\",\"iso_a2\":\"EG\"},\"coordinates\":[585666,678363]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Aswan\",\"adm0name\":\"Egypt\",\"adm1name\":\"Aswan\",\"iso_a2\":\"EG\"},\"coordinates\":[591385,647422]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Asyut\",\"adm0name\":\"Egypt\",\"adm1name\":\"Asyut\",\"iso_a2\":\"EG\"},\"coordinates\":[586610,665803]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Kisangani\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Orientale\",\"iso_a2\":\"CD\"},\"coordinates\":[570055,507798]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Assab\",\"adm0name\":\"Eritrea\",\"adm1name\":\"Debubawi Keyih Bahri\",\"iso_a2\":\"ER\"},\"coordinates\":[618694,581794]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Djibouti\",\"adm0name\":\"Djibouti\",\"adm1name\":\"Djibouti\",\"iso_a2\":\"DJ\"},\"coordinates\":[619855,573411]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Dresden\",\"adm0name\":\"Germany\",\"adm1name\":\"Sachsen\",\"iso_a2\":\"DE\"},\"coordinates\":[538194,807160]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Xigaze\",\"adm0name\":\"China\",\"adm1name\":\"Xizang\",\"iso_a2\":\"CN\"},\"coordinates\":[746897,678007]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Shache\",\"adm0name\":\"China\",\"adm1name\":\"Xinjiang Uygur\",\"iso_a2\":\"CN\"},\"coordinates\":[714583,732371]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Yining\",\"adm0name\":\"China\",\"adm1name\":\"Xinjiang Uygur\",\"iso_a2\":\"CN\"},\"coordinates\":[725971,764800]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Altay\",\"adm0name\":\"China\",\"adm1name\":\"Xinjiang Uygur\",\"iso_a2\":\"CN\"},\"coordinates\":[744768,788301]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Putrajaya\",\"adm0name\":\"Malaysia\",\"adm1name\":\"Selangor\",\"iso_a2\":\"MY\"},\"coordinates\":[782504,521981]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Shizuishan\",\"adm0name\":\"China\",\"adm1name\":\"Ningxia Hui\",\"iso_a2\":\"CN\"},\"coordinates\":[796580,737152]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Yulin\",\"adm0name\":\"China\",\"adm1name\":\"Shaanxi\",\"iso_a2\":\"CN\"},\"coordinates\":[804814,731525]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ankang\",\"adm0name\":\"China\",\"adm1name\":\"Shaanxi\",\"iso_a2\":\"CN\"},\"coordinates\":[802832,698328]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Houma\",\"adm0name\":\"China\",\"adm1name\":\"Shanxi\",\"iso_a2\":\"CN\"},\"coordinates\":[808916,715746]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Yueyang\",\"adm0name\":\"China\",\"adm1name\":\"Hunan\",\"iso_a2\":\"CN\"},\"coordinates\":[814160,678790]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Hengyang\",\"adm0name\":\"China\",\"adm1name\":\"Hunan\",\"iso_a2\":\"CN\"},\"coordinates\":[812744,663978]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Mianyang\",\"adm0name\":\"China\",\"adm1name\":\"Sichuan\",\"iso_a2\":\"CN\"},\"coordinates\":[791022,691171]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Xichang\",\"adm0name\":\"China\",\"adm1name\":\"Sichuan\",\"iso_a2\":\"CN\"},\"coordinates\":[784166,669891]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Baoshan\",\"adm0name\":\"China\",\"adm1name\":\"Yunnan\",\"iso_a2\":\"CN\"},\"coordinates\":[775415,653540]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Gejiu\",\"adm0name\":\"China\",\"adm1name\":\"Yunnan\",\"iso_a2\":\"CN\"},\"coordinates\":[786527,643230]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Shijianzhuang\",\"adm0name\":\"China\",\"adm1name\":\"Hebei\",\"iso_a2\":\"CN\"},\"coordinates\":[817993,730154]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Handan\",\"adm0name\":\"China\",\"adm1name\":\"Hebei\",\"iso_a2\":\"CN\"},\"coordinates\":[817993,721445]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Anshan\",\"adm0name\":\"China\",\"adm1name\":\"Liaoning\",\"iso_a2\":\"CN\"},\"coordinates\":[841494,748312]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Dalian\",\"adm0name\":\"China\",\"adm1name\":\"Liaoning\",\"iso_a2\":\"CN\"},\"coordinates\":[837855,735325]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Qingdao\",\"adm0name\":\"China\",\"adm1name\":\"Shandong\",\"iso_a2\":\"CN\"},\"coordinates\":[834244,718542]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Linyi\",\"adm0name\":\"China\",\"adm1name\":\"Shandong\",\"iso_a2\":\"CN\"},\"coordinates\":[828688,712559]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Huaiyin\",\"adm0name\":\"China\",\"adm1name\":\"Jiangsu\",\"iso_a2\":\"CN\"},\"coordinates\":[830633,703671]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Wenzhou\",\"adm0name\":\"China\",\"adm1name\":\"Zhejiang\",\"iso_a2\":\"CN\"},\"coordinates\":[835133,670731]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ningbo\",\"adm0name\":\"China\",\"adm1name\":\"Zhejiang\",\"iso_a2\":\"CN\"},\"coordinates\":[837632,681751]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Fukuoka\",\"adm0name\":\"Japan\",\"adm1name\":\"Fukuoka\",\"iso_a2\":\"JP\"},\"coordinates\":[862243,703760]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Miyazaki\",\"adm0name\":\"Japan\",\"adm1name\":\"Miyazaki\",\"iso_a2\":\"JP\"},\"coordinates\":[865050,693815]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Naha\",\"adm0name\":\"Japan\",\"adm1name\":\"Okinawa\",\"iso_a2\":\"JP\"},\"coordinates\":[854647,659980]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kochi\",\"adm0name\":\"Japan\",\"adm1name\":\"Kochi\",\"iso_a2\":\"JP\"},\"coordinates\":[870937,703556]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Gorontalo\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Gorontalo\",\"iso_a2\":\"ID\"},\"coordinates\":[841861,507976]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Tongliao\",\"adm0name\":\"China\",\"adm1name\":\"Nei Mongol\",\"iso_a2\":\"CN\"},\"coordinates\":[839633,763153]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Hohhot\",\"adm0name\":\"China\",\"adm1name\":\"Nei Mongol\",\"iso_a2\":\"CN\"},\"coordinates\":[810161,746565]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Chifeng\",\"adm0name\":\"China\",\"adm1name\":\"Nei Mongol\",\"iso_a2\":\"CN\"},\"coordinates\":[830410,755155]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ulanhot\",\"adm0name\":\"China\",\"adm1name\":\"Nei Mongol\",\"iso_a2\":\"CN\"},\"coordinates\":[839110,777716]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Hailar\",\"adm0name\":\"China\",\"adm1name\":\"Nei Mongol\",\"iso_a2\":\"CN\"},\"coordinates\":[832499,796200]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jiamusi\",\"adm0name\":\"China\",\"adm1name\":\"Heilongjiang\",\"iso_a2\":\"CN\"},\"coordinates\":[862077,782171]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Beian\",\"adm0name\":\"China\",\"adm1name\":\"Heilongjiang\",\"iso_a2\":\"CN\"},\"coordinates\":[851338,790507]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Daqing\",\"adm0name\":\"China\",\"adm1name\":\"Heilongjiang\",\"iso_a2\":\"CN\"},\"coordinates\":[847216,780690]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jixi\",\"adm0name\":\"China\",\"adm1name\":\"Heilongjiang\",\"iso_a2\":\"CN\"},\"coordinates\":[863800,773106]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Nagoya\",\"adm0name\":\"Japan\",\"adm1name\":\"Aichi\",\"iso_a2\":\"JP\"},\"coordinates\":[880313,713003]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Nagano\",\"adm0name\":\"Japan\",\"adm1name\":\"Nagano\",\"iso_a2\":\"JP\"},\"coordinates\":[883805,721849]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kushiro\",\"adm0name\":\"Japan\",\"adm1name\":\"Hokkaido\",\"iso_a2\":\"JP\"},\"coordinates\":[901040,759320]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Hakodate\",\"adm0name\":\"Japan\",\"adm1name\":\"Hokkaido\",\"iso_a2\":\"JP\"},\"coordinates\":[890943,752329]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kyoto\",\"adm0name\":\"Japan\",\"adm1name\":\"Kyoto\",\"iso_a2\":\"JP\"},\"coordinates\":[877077,712262]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Sendai\",\"adm0name\":\"Japan\",\"adm1name\":\"Miyagi\",\"iso_a2\":\"JP\"},\"coordinates\":[891720,731559]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Sakata\",\"adm0name\":\"Japan\",\"adm1name\":\"Yamagata\",\"iso_a2\":\"JP\"},\"coordinates\":[888471,735297]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Bandundu\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Bandundu\",\"iso_a2\":\"CD\"},\"coordinates\":[548277,485107]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Kananga\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Kasaï-Occidental\",\"iso_a2\":\"CD\"},\"coordinates\":[562216,469833]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Kasongo\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Maniema\",\"iso_a2\":\"CD\"},\"coordinates\":[574055,478353]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Mbuji-Mayi\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Kasaï-Oriental\",\"iso_a2\":\"CD\"},\"coordinates\":[565549,468293]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Kalemie\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Katanga\",\"iso_a2\":\"CD\"},\"coordinates\":[581110,469566]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Butembo\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Nord-Kivu\",\"iso_a2\":\"CD\"},\"coordinates\":[581332,505487]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Goma\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Nord-Kivu\",\"iso_a2\":\"CD\"},\"coordinates\":[581171,494771]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Mzuzu\",\"adm0name\":\"Malawi\",\"adm1name\":\"Mzimba\",\"iso_a2\":\"MW\"},\"coordinates\":[594500,436823]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Blantyre\",\"adm0name\":\"Malawi\",\"adm1name\":\"Blantyre\",\"iso_a2\":\"MW\"},\"coordinates\":[597193,411170]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Quetzaltenango\",\"adm0name\":\"Guatemala\",\"adm1name\":\"Quezaltenango\",\"iso_a2\":\"GT\"},\"coordinates\":[245778,592576]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Banjul\",\"adm0name\":\"The Gambia\",\"adm1name\":\"Banjul\",\"iso_a2\":\"GM\"},\"coordinates\":[453912,584424]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Faridabad\",\"adm0name\":\"India\",\"adm1name\":\"Haryana\",\"iso_a2\":\"IN\"},\"coordinates\":[714762,673180]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Srinagar\",\"adm0name\":\"India\",\"adm1name\":\"Jammu and Kashmir\",\"iso_a2\":\"IN\"},\"coordinates\":[707813,706752]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Vijayawada\",\"adm0name\":\"India\",\"adm1name\":\"Andhra Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[723966,602600]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Thiruvananthapuram\",\"adm0name\":\"India\",\"adm1name\":\"Kerala\",\"iso_a2\":\"IN\"},\"coordinates\":[713744,555086]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Kochi\",\"adm0name\":\"India\",\"adm1name\":\"Kerala\",\"iso_a2\":\"IN\"},\"coordinates\":[711727,564062]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Cuttack\",\"adm0name\":\"India\",\"adm1name\":\"Orissa\",\"iso_a2\":\"IN\"},\"coordinates\":[738583,625991]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Hubli\",\"adm0name\":\"India\",\"adm1name\":\"Karnataka\",\"iso_a2\":\"IN\"},\"coordinates\":[708674,595728]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Mangalore\",\"adm0name\":\"India\",\"adm1name\":\"Karnataka\",\"iso_a2\":\"IN\"},\"coordinates\":[707916,581143]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Mysore\",\"adm0name\":\"India\",\"adm1name\":\"Karnataka\",\"iso_a2\":\"IN\"},\"coordinates\":[712938,577658]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Gulbarga\",\"adm0name\":\"India\",\"adm1name\":\"Karnataka\",\"iso_a2\":\"IN\"},\"coordinates\":[713388,607506]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Kolhapur\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[706166,603655]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Nanded\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[714721,618289]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Akola\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[713916,627412]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Guwahati\",\"adm0name\":\"India\",\"adm1name\":\"Assam\",\"iso_a2\":\"IN\"},\"coordinates\":[754911,659712]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Kayes\",\"adm0name\":\"Congo (Brazzaville)\",\"adm1name\":\"Bouenza\",\"iso_a2\":\"CG\"},\"coordinates\":[536888,479953]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Franceville\",\"adm0name\":\"Gabon\",\"adm1name\":\"Haut-Ogooué\",\"iso_a2\":\"GA\"},\"coordinates\":[537731,495041]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Bordeaux\",\"adm0name\":\"France\",\"adm1name\":\"Aquitaine\",\"iso_a2\":\"FR\"},\"coordinates\":[498342,770440]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Marseille\",\"adm0name\":\"France\",\"adm1name\":\"Provence-Alpes-Côte-d'Azur\",\"iso_a2\":\"FR\"},\"coordinates\":[514925,761198]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Le Havre\",\"adm0name\":\"France\",\"adm1name\":\"Haute-Normandie\",\"iso_a2\":\"FR\"},\"coordinates\":[500291,798007]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Gao\",\"adm0name\":\"Mali\",\"adm1name\":\"Gao\",\"iso_a2\":\"ML\"},\"coordinates\":[499860,601088]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Coihaique\",\"adm0name\":\"Chile\",\"adm1name\":\"Aisén del General Carlos Ibáñez del Campo\",\"iso_a2\":\"CL\"},\"coordinates\":[299806,234740]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Arica\",\"adm0name\":\"Chile\",\"adm1name\":\"Arica y Parinacota\",\"iso_a2\":\"CL\"},\"coordinates\":[304750,395115]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Copiapo\",\"adm0name\":\"Chile\",\"adm1name\":\"Atacama\",\"iso_a2\":\"CL\"},\"coordinates\":[304610,342624]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"La Serena\",\"adm0name\":\"Chile\",\"adm1name\":\"Coquimbo\",\"iso_a2\":\"CL\"},\"coordinates\":[302083,327576]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Los Angeles\",\"adm0name\":\"Chile\",\"adm1name\":\"Bío-Bío\",\"iso_a2\":\"CL\"},\"coordinates\":[299000,282787]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Narsarsuaq\",\"adm0name\":\"Greenland\",\"adm1name\":\"Kommune Kujalleq\",\"iso_a2\":\"GL\"},\"coordinates\":[373843,867096]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Sisimiut\",\"adm0name\":\"Greenland\",\"adm1name\":\"Qeqqata Kommunia\",\"iso_a2\":\"GL\"},\"coordinates\":[350925,901360]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Upernavik\",\"adm0name\":\"Greenland\",\"adm1name\":\"Qaasuitsup Kommunia\",\"iso_a2\":\"GL\"},\"coordinates\":[344051,935480]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Qaanaaq\",\"adm0name\":\"Greenland\",\"adm1name\":\"Qaasuitsup Kommunia\",\"iso_a2\":\"GL\"},\"coordinates\":[307410,963764]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Nouadhibou\",\"adm0name\":\"Mauritania\",\"adm1name\":\"Dakhlet Nouadhibou\",\"iso_a2\":\"MR\"},\"coordinates\":[452622,628538]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Kayes\",\"adm0name\":\"Mali\",\"adm1name\":\"Kayes\",\"iso_a2\":\"ML\"},\"coordinates\":[468221,590325]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Ayoun el Atrous\",\"adm0name\":\"Mauritania\",\"adm1name\":\"Hodh el Gharbi\",\"iso_a2\":\"MR\"},\"coordinates\":[473287,603457]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Segou\",\"adm0name\":\"Mali\",\"adm1name\":\"Ségou\",\"iso_a2\":\"ML\"},\"coordinates\":[482611,584342]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Skopje\",\"adm0name\":\"Macedonia\",\"adm1name\":\"Centar\",\"iso_a2\":\"MK\"},\"coordinates\":[559537,753544]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Al Jawf\",\"adm0name\":\"Libya\",\"adm1name\":\"Al Kufrah\",\"iso_a2\":\"LY\"},\"coordinates\":[564694,648089]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Tmassah\",\"adm0name\":\"Libya\",\"adm1name\":\"Murzuq\",\"iso_a2\":\"LY\"},\"coordinates\":[543888,660925]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Misratah\",\"adm0name\":\"Libya\",\"adm1name\":\"Misratah\",\"iso_a2\":\"LY\"},\"coordinates\":[541944,696550]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Zuwarah\",\"adm0name\":\"Libya\",\"adm1name\":\"An Nuqat al Khams\",\"iso_a2\":\"LY\"},\"coordinates\":[533553,699835]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Kirkuk\",\"adm0name\":\"Iraq\",\"adm1name\":\"At-Ta'mim\",\"iso_a2\":\"IQ\"},\"coordinates\":[623311,714871]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Mosul\",\"adm0name\":\"Iraq\",\"adm1name\":\"Ninawa\",\"iso_a2\":\"IQ\"},\"coordinates\":[619841,720053]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"An Najaf\",\"adm0name\":\"Iraq\",\"adm1name\":\"An-Najaf\",\"iso_a2\":\"IQ\"},\"coordinates\":[623153,694302]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Bahir Dar\",\"adm0name\":\"Ethiopia\",\"adm1name\":\"Amhara\",\"iso_a2\":\"ET\"},\"coordinates\":[603842,573441]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Mekele\",\"adm0name\":\"Ethiopia\",\"adm1name\":\"Tigray\",\"iso_a2\":\"ET\"},\"coordinates\":[609638,584697]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Dire Dawa\",\"adm0name\":\"Ethiopia\",\"adm1name\":\"Dire Dawa\",\"iso_a2\":\"ET\"},\"coordinates\":[616277,561532]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Rovaniemi\",\"adm0name\":\"Finland\",\"adm1name\":\"Lapland\",\"iso_a2\":\"FI\"},\"coordinates\":[571433,898693]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Vaasa\",\"adm0name\":\"Finland\",\"adm1name\":\"Western Finland\",\"iso_a2\":\"FI\"},\"coordinates\":[560000,878550]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Tampere\",\"adm0name\":\"Finland\",\"adm1name\":\"Pirkanmaa\",\"iso_a2\":\"FI\"},\"coordinates\":[565972,869071]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Aqtobe\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Aqtöbe\",\"iso_a2\":\"KZ\"},\"coordinates\":[658805,802598]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Rudny\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Qostanay\",\"iso_a2\":\"KZ\"},\"coordinates\":[675360,818432]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Qyzylorda\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Qyzylorda\",\"iso_a2\":\"KZ\"},\"coordinates\":[681846,770133]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Atyrau\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Atyrau\",\"iso_a2\":\"KZ\"},\"coordinates\":[644221,783834]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Ekibastuz\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Pavlodar\",\"iso_a2\":\"KZ\"},\"coordinates\":[709222,811189]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Pavlodar\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Pavlodar\",\"iso_a2\":\"KZ\"},\"coordinates\":[713750,814566]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Semey\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"East Kazakhstan\",\"iso_a2\":\"KZ\"},\"coordinates\":[722985,803517]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Oskemen\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"East Kazakhstan\",\"iso_a2\":\"KZ\"},\"coordinates\":[729486,800881]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Yazd\",\"adm0name\":\"Iran\",\"adm1name\":\"Yazd\",\"iso_a2\":\"IR\"},\"coordinates\":[651028,693826]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Ahvaz\",\"adm0name\":\"Iran\",\"adm1name\":\"Khuzestan\",\"iso_a2\":\"IR\"},\"coordinates\":[635327,690046]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Basra\",\"adm0name\":\"Iraq\",\"adm1name\":\"Al-Basrah\",\"iso_a2\":\"IQ\"},\"coordinates\":[632809,685504]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Bandar-e-Abbas\",\"adm0name\":\"Iran\",\"adm1name\":\"Hormozgan\",\"iso_a2\":\"IR\"},\"coordinates\":[656311,665886]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Hamadan\",\"adm0name\":\"Iran\",\"adm1name\":\"Hamadan\",\"iso_a2\":\"IR\"},\"coordinates\":[634763,710864]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Tabriz\",\"adm0name\":\"Iran\",\"adm1name\":\"East Azarbaijan\",\"iso_a2\":\"IR\"},\"coordinates\":[628608,730369]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ludhiana\",\"adm0name\":\"India\",\"adm1name\":\"Punjab\",\"iso_a2\":\"IN\"},\"coordinates\":[710750,687959]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Kota\",\"adm0name\":\"India\",\"adm1name\":\"Rajasthan\",\"iso_a2\":\"IN\"},\"coordinates\":[710647,653906]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jodhpur\",\"adm0name\":\"India\",\"adm1name\":\"Rajasthan\",\"iso_a2\":\"IN\"},\"coordinates\":[702818,660493]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Shymkent\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"South Kazakhstan\",\"iso_a2\":\"KZ\"},\"coordinates\":[693319,755440]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Taraz\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Zhambyl\",\"iso_a2\":\"KZ\"},\"coordinates\":[698236,758876]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Lucknow\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[724758,663830]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Saharanpur\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[715416,682273]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ranchi\",\"adm0name\":\"India\",\"adm1name\":\"Jharkhand\",\"iso_a2\":\"IN\"},\"coordinates\":[737021,643183]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Bhagalpur\",\"adm0name\":\"India\",\"adm1name\":\"Bihar\",\"iso_a2\":\"IN\"},\"coordinates\":[741610,654191]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Raipur\",\"adm0name\":\"India\",\"adm1name\":\"Chhattisgarh\",\"iso_a2\":\"IN\"},\"coordinates\":[726757,630534]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Jabalpur\",\"adm0name\":\"India\",\"adm1name\":\"Madhya Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[722091,642028]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Indore\",\"adm0name\":\"India\",\"adm1name\":\"Madhya Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[710730,639303]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Pondicherry\",\"adm0name\":\"India\",\"adm1name\":\"Puducherry\",\"iso_a2\":\"IN\"},\"coordinates\":[721749,575425]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Salem\",\"adm0name\":\"India\",\"adm1name\":\"Tamil Nadu\",\"iso_a2\":\"IN\"},\"coordinates\":[717160,573867]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Tiruchirappalli\",\"adm0name\":\"India\",\"adm1name\":\"Tamil Nadu\",\"iso_a2\":\"IN\"},\"coordinates\":[718577,568772]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Pointe-Noire\",\"adm0name\":\"Congo (Brazzaville)\",\"adm1name\":\"Kouilou\",\"iso_a2\":\"CG\"},\"coordinates\":[533000,476457]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Kankan\",\"adm0name\":\"Guinea\",\"adm1name\":\"Kankan\",\"iso_a2\":\"GN\"},\"coordinates\":[474138,566272]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Nzerekore\",\"adm0name\":\"Guinea\",\"adm1name\":\"Nzerekore\",\"iso_a2\":\"GN\"},\"coordinates\":[475472,550691]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Bouake\",\"adm0name\":\"Ivory Coast\",\"adm1name\":\"Vallée du Bandama\",\"iso_a2\":\"CI\"},\"coordinates\":[486027,550276]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"St.-Denis\",\"adm0name\":\"France\",\"adm1name\":\"La Réunion\",\"iso_a2\":\"RE\"},\"coordinates\":[654022,381021]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Rio Branco\",\"adm0name\":\"Brazil\",\"adm1name\":\"Acre\",\"iso_a2\":\"BR\"},\"coordinates\":[311666,445671]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"São Luís\",\"adm0name\":\"Brazil\",\"adm1name\":\"Maranhão\",\"iso_a2\":\"BR\"},\"coordinates\":[377034,489822]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Porto Velho\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rondônia\",\"iso_a2\":\"BR\"},\"coordinates\":[322500,452878]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Alvorada\",\"adm0name\":\"Brazil\",\"adm1name\":\"Tocantins\",\"iso_a2\":\"BR\"},\"coordinates\":[363661,430839]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Corumba\",\"adm0name\":\"Brazil\",\"adm1name\":\"Mato Grosso do Sul\",\"iso_a2\":\"BR\"},\"coordinates\":[339861,392057]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Belo Horizonte\",\"adm0name\":\"Brazil\",\"adm1name\":\"Minas Gerais\",\"iso_a2\":\"BR\"},\"coordinates\":[378008,386743]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Montes Claros\",\"adm0name\":\"Brazil\",\"adm1name\":\"Minas Gerais\",\"iso_a2\":\"BR\"},\"coordinates\":[378166,405660]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Uberlandia\",\"adm0name\":\"Brazil\",\"adm1name\":\"Minas Gerais\",\"iso_a2\":\"BR\"},\"coordinates\":[365888,392745]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Colider\",\"adm0name\":\"Brazil\",\"adm1name\":\"Mato Grosso\",\"iso_a2\":\"BR\"},\"coordinates\":[345970,440630]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Alta Floresta\",\"adm0name\":\"Brazil\",\"adm1name\":\"Mato Grosso\",\"iso_a2\":\"BR\"},\"coordinates\":[344694,446065]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Cuiaba\",\"adm0name\":\"Brazil\",\"adm1name\":\"Mato Grosso\",\"iso_a2\":\"BR\"},\"coordinates\":[344203,412487]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Pelotas\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rio Grande do Sul\",\"iso_a2\":\"BR\"},\"coordinates\":[354639,316616]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Caxias do Sul\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rio Grande do Sul\",\"iso_a2\":\"BR\"},\"coordinates\":[357860,331842]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ponta Grossa\",\"adm0name\":\"Brazil\",\"adm1name\":\"Paraná\",\"iso_a2\":\"BR\"},\"coordinates\":[360666,356072]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Teresina\",\"adm0name\":\"Brazil\",\"adm1name\":\"Piauí\",\"iso_a2\":\"BR\"},\"coordinates\":[381161,474543]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Maceio\",\"adm0name\":\"Brazil\",\"adm1name\":\"Alagoas\",\"iso_a2\":\"BR\"},\"coordinates\":[400745,447735]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Vitoria da Conquista\",\"adm0name\":\"Brazil\",\"adm1name\":\"Bahia\",\"iso_a2\":\"BR\"},\"coordinates\":[386555,416739]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Barreiras\",\"adm0name\":\"Brazil\",\"adm1name\":\"Bahia\",\"iso_a2\":\"BR\"},\"coordinates\":[375000,432794]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Vila Velha\",\"adm0name\":\"Brazil\",\"adm1name\":\"Espírito Santo\",\"iso_a2\":\"BR\"},\"coordinates\":[388005,384050]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Natal\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rio Grande do Norte\",\"iso_a2\":\"BR\"},\"coordinates\":[402105,470485]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Thompson\",\"adm0name\":\"Canada\",\"adm1name\":\"Manitoba\",\"iso_a2\":\"CA\"},\"coordinates\":[228148,835005]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Brandon\",\"adm0name\":\"Canada\",\"adm1name\":\"Manitoba\",\"iso_a2\":\"CA\"},\"coordinates\":[222361,799952]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Fort Smith\",\"adm0name\":\"Canada\",\"adm1name\":\"Alberta\",\"iso_a2\":\"CA\"},\"coordinates\":[189212,860185]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Fort McMurray\",\"adm0name\":\"Canada\",\"adm1name\":\"Alberta\",\"iso_a2\":\"CA\"},\"coordinates\":[190601,840831]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Peace River\",\"adm0name\":\"Canada\",\"adm1name\":\"Alberta\",\"iso_a2\":\"CA\"},\"coordinates\":[174213,837869]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Fort St. John\",\"adm0name\":\"Canada\",\"adm1name\":\"British Columbia\",\"iso_a2\":\"CA\"},\"coordinates\":[164352,837967]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Iqaluit\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[309722,882404]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Cambridge Bay\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[208240,914197]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kugluktuk\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[180207,906387]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Chesterfield Inlet\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[248055,879962]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Arviat\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[238726,866752]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Taloyoak\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[240185,916664]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Igloolik\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[272796,915024]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Dawson City\",\"adm0name\":\"Canada\",\"adm1name\":\"Yukon\",\"iso_a2\":\"CA\"},\"coordinates\":[112731,884277]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Timmins\",\"adm0name\":\"Canada\",\"adm1name\":\"Ontario\",\"iso_a2\":\"CA\"},\"coordinates\":[274074,791855]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"North Bay\",\"adm0name\":\"Canada\",\"adm1name\":\"Ontario\",\"iso_a2\":\"CA\"},\"coordinates\":[279305,779019]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kuujjuarapik\",\"adm0name\":\"Canada\",\"adm1name\":\"Québec\",\"iso_a2\":\"CA\"},\"coordinates\":[283983,832229]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Kuujjuaq\",\"adm0name\":\"Canada\",\"adm1name\":\"Québec\",\"iso_a2\":\"CA\"},\"coordinates\":[310000,848928]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Sydney\",\"adm0name\":\"Canada\",\"adm1name\":\"Nova Scotia\",\"iso_a2\":\"CA\"},\"coordinates\":[332833,777634]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Labrador City\",\"adm0name\":\"Canada\",\"adm1name\":\"Newfoundland and Labrador\",\"iso_a2\":\"CA\"},\"coordinates\":[314122,818366]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Ebolowa\",\"adm0name\":\"Cameroon\",\"adm1name\":\"Sud\",\"iso_a2\":\"CM\"},\"coordinates\":[530972,521898]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Bambari\",\"adm0name\":\"Central African Republic\",\"adm1name\":\"Ouaka\",\"iso_a2\":\"CF\"},\"coordinates\":[557408,538854]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Venice\",\"adm0name\":\"Italy\",\"adm1name\":\"Veneto\",\"iso_a2\":\"IT\"},\"coordinates\":[534263,773916]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"El Calafate\",\"adm0name\":\"Argentina\",\"adm1name\":\"Santa Cruz\",\"iso_a2\":\"AR\"},\"coordinates\":[299166,206520]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"San Juan\",\"adm0name\":\"Argentina\",\"adm1name\":\"San Juan\",\"iso_a2\":\"AR\"},\"coordinates\":[309667,317800]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Rawson\",\"adm0name\":\"Argentina\",\"adm1name\":\"Chubut\",\"iso_a2\":\"AR\"},\"coordinates\":[319167,248188]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Neuquen\",\"adm0name\":\"Argentina\",\"adm1name\":\"Neuquén\",\"iso_a2\":\"AR\"},\"coordinates\":[310944,273959]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Trinidad\",\"adm0name\":\"Bolivia\",\"adm1name\":\"El Beni\",\"iso_a2\":\"BO\"},\"coordinates\":[319722,416838]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Santa Rosa\",\"adm0name\":\"Argentina\",\"adm1name\":\"La Pampa\",\"iso_a2\":\"AR\"},\"coordinates\":[321389,287763]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"San Carlos de Bariloche\",\"adm0name\":\"Argentina\",\"adm1name\":\"Río Negro\",\"iso_a2\":\"AR\"},\"coordinates\":[301944,260926]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Salta\",\"adm0name\":\"Argentina\",\"adm1name\":\"Salta\",\"iso_a2\":\"AR\"},\"coordinates\":[318286,357889]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Tucumán\",\"adm0name\":\"Argentina\",\"adm1name\":\"Tucumán\",\"iso_a2\":\"AR\"},\"coordinates\":[318837,345858]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Formosa\",\"adm0name\":\"Argentina\",\"adm1name\":\"Formosa\",\"iso_a2\":\"AR\"},\"coordinates\":[338380,349657]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Santa Fe\",\"adm0name\":\"Argentina\",\"adm1name\":\"Santa Fe\",\"iso_a2\":\"AR\"},\"coordinates\":[331416,317363]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Rosario\",\"adm0name\":\"Argentina\",\"adm1name\":\"Santa Fe\",\"iso_a2\":\"AR\"},\"coordinates\":[331477,309511]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Campinas\",\"adm0name\":\"Brazil\",\"adm1name\":\"São Paulo\",\"iso_a2\":\"BR\"},\"coordinates\":[369161,369059]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Sorocaba\",\"adm0name\":\"Brazil\",\"adm1name\":\"São Paulo\",\"iso_a2\":\"BR\"},\"coordinates\":[368139,365552]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Ribeirao Preto\",\"adm0name\":\"Brazil\",\"adm1name\":\"São Paulo\",\"iso_a2\":\"BR\"},\"coordinates\":[367139,379296]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":1,\"name\":\"Petrolina\",\"adm0name\":\"Brazil\",\"adm1name\":\"Pernambuco\",\"iso_a2\":\"BR\"},\"coordinates\":[387472,449145]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Bamenda\",\"adm0name\":\"Cameroon\",\"adm1name\":\"Nord-Ouest\",\"iso_a2\":\"CM\"},\"coordinates\":[528194,540027]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Garoua\",\"adm0name\":\"Cameroon\",\"adm1name\":\"Nord\",\"iso_a2\":\"CM\"},\"coordinates\":[537194,559815]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Herat\",\"adm0name\":\"Afghanistan\",\"adm1name\":\"Hirat\",\"iso_a2\":\"AF\"},\"coordinates\":[672694,708103]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Mazar-e Sharif\",\"adm0name\":\"Afghanistan\",\"adm1name\":\"Balkh\",\"iso_a2\":\"AF\"},\"coordinates\":[686388,722144]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Battambang\",\"adm0name\":\"Cambodia\",\"adm1name\":\"Batdâmbâng\",\"iso_a2\":\"KH\"},\"coordinates\":[786666,582327]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Siem Reap\",\"adm0name\":\"Cambodia\",\"adm1name\":\"Siemréab\",\"iso_a2\":\"KH\"},\"coordinates\":[788471,583907]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Malanje\",\"adm0name\":\"Angola\",\"adm1name\":\"Malanje\",\"iso_a2\":\"AO\"},\"coordinates\":[545389,448198]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Benguela\",\"adm0name\":\"Angola\",\"adm1name\":\"Benguela\",\"iso_a2\":\"AO\"},\"coordinates\":[537242,430198]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Lubango\",\"adm0name\":\"Angola\",\"adm1name\":\"Huíla\",\"iso_a2\":\"AO\"},\"coordinates\":[537471,416383]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Namibe\",\"adm0name\":\"Angola\",\"adm1name\":\"Namibe\",\"iso_a2\":\"AO\"},\"coordinates\":[533778,414725]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Tarija\",\"adm0name\":\"Bolivia\",\"adm1name\":\"Tarija\",\"iso_a2\":\"BO\"},\"coordinates\":[320138,377243]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Bridgetown\",\"adm0name\":\"Barbados\",\"adm1name\":\"Saint Michael\",\"iso_a2\":\"BB\"},\"coordinates\":[334399,582339]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Annaba\",\"adm0name\":\"Algeria\",\"adm1name\":\"Annaba\",\"iso_a2\":\"DZ\"},\"coordinates\":[521555,723448]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Parakou\",\"adm0name\":\"Benin\",\"adm1name\":\"Borgou\",\"iso_a2\":\"BJ\"},\"coordinates\":[507278,560052]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Porto-Novo\",\"adm0name\":\"Benin\",\"adm1name\":\"Ouémé\",\"iso_a2\":\"BJ\"},\"coordinates\":[507268,543127]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Constantine\",\"adm0name\":\"Algeria\",\"adm1name\":\"Constantine\",\"iso_a2\":\"DZ\"},\"coordinates\":[518332,720130]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":6,\"name\":\"Brest\",\"adm0name\":\"Belarus\",\"adm1name\":\"Brest\",\"iso_a2\":\"BY\"},\"coordinates\":[565833,813381]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Khulna\",\"adm0name\":\"Bangladesh\",\"adm1name\":\"Khulna\",\"iso_a2\":\"BD\"},\"coordinates\":[748772,640043]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Francistown\",\"adm0name\":\"Botswana\",\"adm1name\":\"Central\",\"iso_a2\":\"BW\"},\"coordinates\":[576388,379296]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Mahalapye\",\"adm0name\":\"Botswana\",\"adm1name\":\"Central\",\"iso_a2\":\"BW\"},\"coordinates\":[574500,367862]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":7,\"name\":\"Serowe\",\"adm0name\":\"Botswana\",\"adm1name\":\"Central\",\"iso_a2\":\"BW\"},\"coordinates\":[574194,372068]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Katherine\",\"adm0name\":\"Australia\",\"adm1name\":\"Northern Territory\",\"iso_a2\":\"AU\"},\"coordinates\":[867406,419010]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Busselton\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[820412,305321]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Mandurah\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[821519,312034]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Broome\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[839530,398304]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Kalgoorlie\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[837388,322627]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Albany\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[827476,297261]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Port Hedland\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[829460,384389]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Karratha\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[824638,381901]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Geraldton\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[818332,334291]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Griffith\",\"adm0name\":\"Australia\",\"adm1name\":\"New South Wales\",\"iso_a2\":\"AU\"},\"coordinates\":[905665,301567]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Orange\",\"adm0name\":\"Australia\",\"adm1name\":\"New South Wales\",\"iso_a2\":\"AU\"},\"coordinates\":[914166,307551]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Dubbo\",\"adm0name\":\"Australia\",\"adm1name\":\"New South Wales\",\"iso_a2\":\"AU\"},\"coordinates\":[912769,313595]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Armidale\",\"adm0name\":\"Australia\",\"adm1name\":\"New South Wales\",\"iso_a2\":\"AU\"},\"coordinates\":[921297,323948]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Broken Hill\",\"adm0name\":\"Australia\",\"adm1name\":\"New South Wales\",\"iso_a2\":\"AU\"},\"coordinates\":[892869,315431]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Port Lincoln\",\"adm0name\":\"Australia\",\"adm1name\":\"South Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[877407,298942]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Whyalla\",\"adm0name\":\"Australia\",\"adm1name\":\"South Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[882114,309062]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Portland\",\"adm0name\":\"Australia\",\"adm1name\":\"Victoria\",\"iso_a2\":\"AU\"},\"coordinates\":[893305,277573]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Bendigo\",\"adm0name\":\"Australia\",\"adm1name\":\"Victoria\",\"iso_a2\":\"AU\"},\"coordinates\":[900777,286934]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Wangaratta\",\"adm0name\":\"Australia\",\"adm1name\":\"Victoria\",\"iso_a2\":\"AU\"},\"coordinates\":[906388,289304]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Windorah\",\"adm0name\":\"Australia\",\"adm1name\":\"Queensland\",\"iso_a2\":\"AU\"},\"coordinates\":[896250,354039]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Mount Isa\",\"adm0name\":\"Australia\",\"adm1name\":\"Queensland\",\"iso_a2\":\"AU\"},\"coordinates\":[887471,381939]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Rockhampton\",\"adm0name\":\"Australia\",\"adm1name\":\"Queensland\",\"iso_a2\":\"AU\"},\"coordinates\":[918110,366299]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Cairns\",\"adm0name\":\"Australia\",\"adm1name\":\"Queensland\",\"iso_a2\":\"AU\"},\"coordinates\":[904897,404666]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Gold Coast\",\"adm0name\":\"Australia\",\"adm1name\":\"Queensland\",\"iso_a2\":\"AU\"},\"coordinates\":[926245,338350]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":3,\"name\":\"Devonport\",\"adm0name\":\"Australia\",\"adm1name\":\"Tasmania\",\"iso_a2\":\"AU\"},\"coordinates\":[906475,260673]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Bobo Dioulasso\",\"adm0name\":\"Burkina Faso\",\"adm1name\":\"Houet\",\"iso_a2\":\"BF\"},\"coordinates\":[488083,570952]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":2,\"name\":\"Rajshahi\",\"adm0name\":\"Bangladesh\",\"adm1name\":\"Rajshahi\",\"iso_a2\":\"BD\"},\"coordinates\":[746118,649137]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Mandalay\",\"adm0name\":\"Myanmar\",\"adm1name\":\"Mandalay\",\"iso_a2\":\"MM\"},\"coordinates\":[766897,634889]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":5,\"name\":\"Sittwe\",\"adm0name\":\"Myanmar\",\"adm1name\":\"Rakhine\",\"iso_a2\":\"MM\"},\"coordinates\":[758000,624035]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Bujumbura\",\"adm0name\":\"Burundi\",\"adm1name\":\"Bujumbura Mairie\",\"iso_a2\":\"BI\"},\"coordinates\":[581555,484715]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Pago Pago\",\"adm0name\":\"American Samoa\",\"iso_a2\":\"AS\"},\"coordinates\":[25815,420136]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Kingstown\",\"adm0name\":\"Saint Vincent and the Grenadines\",\"iso_a2\":\"VC\"},\"coordinates\":[329966,582614]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Castries\",\"adm0name\":\"Saint Lucia\",\"iso_a2\":\"LC\"},\"coordinates\":[330555,587671]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Basseterre\",\"adm0name\":\"Saint Kitts and Nevis\",\"iso_a2\":\"KN\"},\"coordinates\":[325786,607222]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Las Palmas\",\"adm0name\":\"Spain\",\"iso_a2\":\"ES\"},\"coordinates\":[457138,671194]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Berbera\",\"adm0name\":\"Somaliland\",\"iso_a2\":\"-99\"},\"coordinates\":[625045,566542]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Port Louis\",\"adm0name\":\"Mauritius\",\"iso_a2\":\"MU\"},\"coordinates\":[659722,385241]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Gaza\",\"adm0name\":\"Palestine\",\"iso_a2\":\"PS\"},\"coordinates\":[595680,691515]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Saint George's\",\"adm0name\":\"Grenada\",\"iso_a2\":\"GD\"},\"coordinates\":[328495,576122]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Papeete\",\"adm0name\":\"French Polynesia\",\"iso_a2\":\"PF\"},\"coordinates\":[84537,400842]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Manama\",\"adm0name\":\"Bahrain\",\"iso_a2\":\"BH\"},\"coordinates\":[640508,660152]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Freeport\",\"adm0name\":\"The Bahamas\",\"iso_a2\":\"BS\"},\"coordinates\":[281389,661912]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":0,\"name\":\"Saint John's\",\"adm0name\":\"Antigua and Barbuda\",\"iso_a2\":\"AG\"},\"coordinates\":[328194,606132]},{\"type\":\"Point\",\"properties\":{\"scalerank\":4,\"labelrank\":8,\"name\":\"Taichung\",\"adm0name\":\"Taiwan\",\"adm1name\":\"Taichung City\",\"iso_a2\":\"TW\"},\"coordinates\":[835226,647805]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Kozhikode\",\"adm0name\":\"India\",\"adm1name\":\"Kerala\",\"iso_a2\":\"IN\"},\"coordinates\":[710466,571381]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Bhubaneshwar\",\"adm0name\":\"India\",\"adm1name\":\"Orissa\",\"iso_a2\":\"IN\"},\"coordinates\":[738403,624820]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Jamshedpur\",\"adm0name\":\"India\",\"adm1name\":\"Jharkhand\",\"iso_a2\":\"IN\"},\"coordinates\":[739431,639733]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Montevideo\",\"adm0name\":\"Uruguay\",\"adm1name\":\"Montevideo\",\"iso_a2\":\"UY\"},\"coordinates\":[343963,298213]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Helena\",\"adm0name\":\"United States of America\",\"adm1name\":\"Montana\",\"iso_a2\":\"US\"},\"coordinates\":[188791,780754]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Bismarck\",\"adm0name\":\"United States of America\",\"adm1name\":\"North Dakota\",\"iso_a2\":\"US\"},\"coordinates\":[220046,782031]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Boise\",\"adm0name\":\"United States of America\",\"adm1name\":\"Idaho\",\"iso_a2\":\"US\"},\"coordinates\":[177146,763074]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"San Jose\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[161523,725711]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Sacramento\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[162578,733265]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Las Vegas\",\"adm0name\":\"United States of America\",\"adm1name\":\"Nevada\",\"iso_a2\":\"US\"},\"coordinates\":[179939,719253]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Santa Fe\",\"adm0name\":\"United States of America\",\"adm1name\":\"New Mexico\",\"iso_a2\":\"US\"},\"coordinates\":[205729,716142]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Portland\",\"adm0name\":\"United States of America\",\"adm1name\":\"Oregon\",\"iso_a2\":\"US\"},\"coordinates\":[159217,774410]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Salt Lake City\",\"adm0name\":\"United States of America\",\"adm1name\":\"Utah\",\"iso_a2\":\"US\"},\"coordinates\":[189078,746298]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Cheyenne\",\"adm0name\":\"United States of America\",\"adm1name\":\"Wyoming\",\"iso_a2\":\"US\"},\"coordinates\":[208834,748449]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Des Moines\",\"adm0name\":\"United States of America\",\"adm1name\":\"Iowa\",\"iso_a2\":\"US\"},\"coordinates\":[239944,751055]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Omaha\",\"adm0name\":\"United States of America\",\"adm1name\":\"Nebraska\",\"iso_a2\":\"US\"},\"coordinates\":[233305,749041]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Oklahoma City\",\"adm0name\":\"United States of America\",\"adm1name\":\"Oklahoma\",\"iso_a2\":\"US\"},\"coordinates\":[229109,714869]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Pierre\",\"adm0name\":\"United States of America\",\"adm1name\":\"South Dakota\",\"iso_a2\":\"US\"},\"coordinates\":[221248,767575]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"San Antonio\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[226363,679425]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"San Cristobal\",\"adm0name\":\"Venezuela\",\"adm1name\":\"Táchira\",\"iso_a2\":\"VE\"},\"coordinates\":[299305,550750]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Valencia\",\"adm0name\":\"Venezuela\",\"adm1name\":\"Carabobo\",\"iso_a2\":\"VE\"},\"coordinates\":[311161,565336]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Jackson\",\"adm0name\":\"United States of America\",\"adm1name\":\"Mississippi\",\"iso_a2\":\"US\"},\"coordinates\":[249486,696070]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Raleigh\",\"adm0name\":\"United States of America\",\"adm1name\":\"North Carolina\",\"iso_a2\":\"US\"},\"coordinates\":[281542,716923]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Cleveland\",\"adm0name\":\"United States of America\",\"adm1name\":\"Ohio\",\"iso_a2\":\"US\"},\"coordinates\":[273064,750415]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Cincinnati\",\"adm0name\":\"United States of America\",\"adm1name\":\"Ohio\",\"iso_a2\":\"US\"},\"coordinates\":[265392,736741]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Nashville\",\"adm0name\":\"United States of America\",\"adm1name\":\"Tennessee\",\"iso_a2\":\"US\"},\"coordinates\":[258939,719016]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Memphis\",\"adm0name\":\"United States of America\",\"adm1name\":\"Tennessee\",\"iso_a2\":\"US\"},\"coordinates\":[249994,712796]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Norfolk\",\"adm0name\":\"United States of America\",\"adm1name\":\"Virginia\",\"iso_a2\":\"US\"},\"coordinates\":[288111,723033]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Milwaukee\",\"adm0name\":\"United States of America\",\"adm1name\":\"Wisconsin\",\"iso_a2\":\"US\"},\"coordinates\":[255773,759792]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Buffalo\",\"adm0name\":\"United States of America\",\"adm1name\":\"New York\",\"iso_a2\":\"US\"},\"coordinates\":[280884,758769]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Pittsburgh\",\"adm0name\":\"United States of America\",\"adm1name\":\"Pennsylvania\",\"iso_a2\":\"US\"},\"coordinates\":[277772,744254]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Ciudad Guayana\",\"adm0name\":\"Venezuela\",\"adm1name\":\"Bolívar\",\"iso_a2\":\"VE\"},\"coordinates\":[326055,554305]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Lome\",\"adm0name\":\"Togo\",\"adm1name\":\"Maritime\",\"iso_a2\":\"TG\"},\"coordinates\":[503390,541057]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Tunis\",\"adm0name\":\"Tunisia\",\"adm1name\":\"Tunis\",\"iso_a2\":\"TN\"},\"coordinates\":[528276,722753]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Kodiak\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[76648,847091]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Cold Bay\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[48014,831747]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Bethel\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[50678,864884]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Point Hope\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[36644,909640]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Barrow\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[64476,927075]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Nome\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[40538,886881]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Valdez\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[93477,866914]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Juneau\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[126611,850197]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Fairbanks\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[89693,888841]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Prudhoe Bay\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[87030,921160]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Sevastapol\",\"adm0name\":\"Ukraine\",\"adm1name\":\"Crimea\",\"iso_a2\":\"UA\"},\"coordinates\":[592958,768948]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Abu Dhabi\",\"adm0name\":\"United Arab Emirates\",\"adm1name\":\"Abu Dhabi\",\"iso_a2\":\"AE\"},\"coordinates\":[651018,649669]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Ashgabat\",\"adm0name\":\"Turkmenistan\",\"adm1name\":\"Ahal\",\"iso_a2\":\"TM\"},\"coordinates\":[662175,729550]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Samarqand\",\"adm0name\":\"Uzbekistan\",\"adm1name\":\"Samarkand\",\"iso_a2\":\"UZ\"},\"coordinates\":[685958,739740]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Lusaka\",\"adm0name\":\"Zambia\",\"adm1name\":\"Lusaka\",\"iso_a2\":\"ZM\"},\"coordinates\":[578559,413393]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Harare\",\"adm0name\":\"Zimbabwe\",\"adm1name\":\"Harare\",\"iso_a2\":\"ZW\"},\"coordinates\":[586230,399168]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Bulawayo\",\"adm0name\":\"Zimbabwe\",\"adm1name\":\"Bulawayo\",\"iso_a2\":\"ZW\"},\"coordinates\":[579388,385221]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Dili\",\"adm0name\":\"East Timor\",\"adm1name\":\"Dili\",\"iso_a2\":\"TL\"},\"coordinates\":[848831,454008]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Port Vila\",\"adm0name\":\"Vanuatu\",\"adm1name\":\"Shefa\",\"iso_a2\":\"VU\"},\"coordinates\":[967545,399657]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Tegucigalpa\",\"adm0name\":\"Honduras\",\"adm1name\":\"Francisco Morazán\",\"iso_a2\":\"HN\"},\"coordinates\":[257724,588276]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Georgetown\",\"adm0name\":\"Guyana\",\"adm1name\":\"East Berbice-Corentyne\",\"iso_a2\":\"GY\"},\"coordinates\":[338424,545015]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Reykjavík\",\"adm0name\":\"Iceland\",\"adm1name\":\"Suðurnes\",\"iso_a2\":\"IS\"},\"coordinates\":[439028,884771]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Port-au-Prince\",\"adm0name\":\"Haiti\",\"adm1name\":\"Ouest\",\"iso_a2\":\"HT\"},\"coordinates\":[299061,614574]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Glasgow\",\"adm0name\":\"United Kingdom\",\"adm1name\":\"Glasgow\",\"iso_a2\":\"GB\"},\"coordinates\":[488187,835753]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Kampala\",\"adm0name\":\"Uganda\",\"adm1name\":\"Kampala\",\"iso_a2\":\"UG\"},\"coordinates\":[590503,506605]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Aden\",\"adm0name\":\"Yemen\",\"adm1name\":\"`Adan\",\"iso_a2\":\"YE\"},\"coordinates\":[625025,580430]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Paramaribo\",\"adm0name\":\"Suriname\",\"adm1name\":\"Paramaribo\",\"iso_a2\":\"SR\"},\"coordinates\":[346758,539286]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Seville\",\"adm0name\":\"Spain\",\"adm1name\":\"Andalucía\",\"iso_a2\":\"ES\"},\"coordinates\":[483389,726322]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Zinder\",\"adm0name\":\"Niger\",\"adm1name\":\"Zinder\",\"iso_a2\":\"NE\"},\"coordinates\":[524953,586474]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Niamey\",\"adm0name\":\"Niger\",\"adm1name\":\"Niamey\",\"iso_a2\":\"NE\"},\"coordinates\":[505874,584808]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Port Sudan\",\"adm0name\":\"Sudan\",\"adm1name\":\"Red Sea\",\"iso_a2\":\"SD\"},\"coordinates\":[603378,620930]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Dushanbe\",\"adm0name\":\"Tajikistan\",\"adm1name\":\"Tadzhikistan Territories\",\"iso_a2\":\"TJ\"},\"coordinates\":[691038,733164]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Cusco\",\"adm0name\":\"Peru\",\"adm1name\":\"Cusco\",\"iso_a2\":\"PE\"},\"coordinates\":[300077,424589]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Tacna\",\"adm0name\":\"Peru\",\"adm1name\":\"Tacna\",\"iso_a2\":\"PE\"},\"coordinates\":[304861,398077]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Trujillo\",\"adm0name\":\"Peru\",\"adm1name\":\"La Libertad\",\"iso_a2\":\"PE\"},\"coordinates\":[280499,456610]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Ica\",\"adm0name\":\"Peru\",\"adm1name\":\"Ica\",\"iso_a2\":\"PE\"},\"coordinates\":[289651,421372]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Asuncion\",\"adm0name\":\"Paraguay\",\"adm1name\":\"Asunción\",\"iso_a2\":\"PY\"},\"coordinates\":[339879,354861]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Managua\",\"adm0name\":\"Nicaragua\",\"adm1name\":\"Managua\",\"iso_a2\":\"NI\"},\"coordinates\":[260359,576729]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Freetown\",\"adm0name\":\"Sierra Leone\",\"adm1name\":\"Western\",\"iso_a2\":\"SL\"},\"coordinates\":[463233,554909]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Agadez\",\"adm0name\":\"Niger\",\"adm1name\":\"Agadez\",\"iso_a2\":\"NE\"},\"coordinates\":[522174,605409]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Niyala\",\"adm0name\":\"Sudan\",\"adm1name\":\"South Darfur\",\"iso_a2\":\"SD\"},\"coordinates\":[569138,576166]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Wau\",\"adm0name\":\"South Sudan\",\"adm1name\":\"West Bahr-al-Ghazal\",\"iso_a2\":\"SS\"},\"coordinates\":[577750,550335]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Dongola\",\"adm0name\":\"Sudan\",\"adm1name\":\"Northern\",\"iso_a2\":\"SD\"},\"coordinates\":[584676,618269]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Kassala\",\"adm0name\":\"Sudan\",\"adm1name\":\"Kassala\",\"iso_a2\":\"SD\"},\"coordinates\":[601083,596309]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Tromsø\",\"adm0name\":\"Norway\",\"adm1name\":\"Troms\",\"iso_a2\":\"NO\"},\"coordinates\":[552755,917266]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Trondheim\",\"adm0name\":\"Norway\",\"adm1name\":\"Sør-Trøndelag\",\"iso_a2\":\"NO\"},\"coordinates\":[528934,880426]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Bergen\",\"adm0name\":\"Norway\",\"adm1name\":\"Hordaland\",\"iso_a2\":\"NO\"},\"coordinates\":[514790,862501]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Islamabad\",\"adm0name\":\"Pakistan\",\"adm1name\":\"F.C.T.\",\"iso_a2\":\"PK\"},\"coordinates\":[703235,704383]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Multan\",\"adm0name\":\"Pakistan\",\"adm1name\":\"Punjab\",\"iso_a2\":\"PK\"},\"coordinates\":[698480,683647]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Hyderabad\",\"adm0name\":\"Pakistan\",\"adm1name\":\"Sind\",\"iso_a2\":\"PK\"},\"coordinates\":[689924,655091]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Peshawar\",\"adm0name\":\"Pakistan\",\"adm1name\":\"N.W.F.P.\",\"iso_a2\":\"PK\"},\"coordinates\":[698702,706190]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Kathmandu\",\"adm0name\":\"Nepal\",\"adm1name\":\"Bhaktapur\",\"iso_a2\":\"NP\"},\"coordinates\":[736984,668935]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Nacala\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Nampula\",\"iso_a2\":\"MZ\"},\"coordinates\":[613096,418702]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Bloemfontein\",\"adm0name\":\"South Africa\",\"adm1name\":\"Orange Free State\",\"iso_a2\":\"ZA\"},\"coordinates\":[572860,332197]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Pretoria\",\"adm0name\":\"South Africa\",\"adm1name\":\"Gauteng\",\"iso_a2\":\"ZA\"},\"coordinates\":[578409,352429]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Port Moresby\",\"adm0name\":\"Papua New Guinea\",\"adm1name\":\"Central\",\"iso_a2\":\"PG\"},\"coordinates\":[908867,448644]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Honiara\",\"adm0name\":\"Solomon Islands\",\"adm1name\":\"Guadalcanal\",\"iso_a2\":\"SB\"},\"coordinates\":[944304,448802]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Panama City\",\"adm0name\":\"Panama\",\"adm1name\":\"Panama\",\"iso_a2\":\"PA\"},\"coordinates\":[279069,557859]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Fez\",\"adm0name\":\"Morocco\",\"adm1name\":\"Fès - Boulemane\",\"iso_a2\":\"MA\"},\"coordinates\":[486104,706483]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Rabat\",\"adm0name\":\"Morocco\",\"adm1name\":\"Rabat - Salé - Zemmour - Zaer\",\"iso_a2\":\"MA\"},\"coordinates\":[481009,706298]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Marrakesh\",\"adm0name\":\"Morocco\",\"adm1name\":\"Marrakech - Tensift - Al Haouz\",\"iso_a2\":\"MA\"},\"coordinates\":[477772,692119]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Chisinau\",\"adm0name\":\"Moldova\",\"adm1name\":\"Chisinau\",\"iso_a2\":\"MD\"},\"coordinates\":[580159,783196]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Beira\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Sofala\",\"iso_a2\":\"MZ\"},\"coordinates\":[596860,387294]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Port Elizabeth\",\"adm0name\":\"South Africa\",\"adm1name\":\"Eastern Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[571105,303474]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Maputo\",\"adm0name\":\"Mozambique\",\"adm1name\":\"Maputo\",\"iso_a2\":\"MZ\"},\"coordinates\":[590520,350958]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Tomsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Tomsk\",\"iso_a2\":\"RU\"},\"coordinates\":[736041,839419]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Anadyr\",\"adm0name\":\"Russia\",\"adm1name\":\"Chukchi Autonomous Okrug\",\"iso_a2\":\"RU\"},\"coordinates\":[992986,888248]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Murmansk\",\"adm0name\":\"Russia\",\"adm1name\":\"Murmansk\",\"iso_a2\":\"RU\"},\"coordinates\":[591944,913327]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Archangel\",\"adm0name\":\"Russia\",\"adm1name\":\"Arkhangel'sk\",\"iso_a2\":\"RU\"},\"coordinates\":[612625,887289]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Nizhny Novgorod\",\"adm0name\":\"Russia\",\"adm1name\":\"Nizhegorod\",\"iso_a2\":\"RU\"},\"coordinates\":[622217,838471]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Volgograd\",\"adm0name\":\"Russia\",\"adm1name\":\"Volgograd\",\"iso_a2\":\"RU\"},\"coordinates\":[623605,793308]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Ufa\",\"adm0name\":\"Russia\",\"adm1name\":\"Bashkortostan\",\"iso_a2\":\"RU\"},\"coordinates\":[655660,829329]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Yekaterinburg\",\"adm0name\":\"Russia\",\"adm1name\":\"Sverdlovsk\",\"iso_a2\":\"RU\"},\"coordinates\":[668327,841534]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Samara\",\"adm0name\":\"Russia\",\"adm1name\":\"Samara\",\"iso_a2\":\"RU\"},\"coordinates\":[639303,819880]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Kazan\",\"adm0name\":\"Russia\",\"adm1name\":\"Tatarstan\",\"iso_a2\":\"RU\"},\"coordinates\":[636456,835017]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Surgut\",\"adm0name\":\"Russia\",\"adm1name\":\"Khanty-Mansiy\",\"iso_a2\":\"RU\"},\"coordinates\":[703958,867649]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Barnaul\",\"adm0name\":\"Russia\",\"adm1name\":\"Altay\",\"iso_a2\":\"RU\"},\"coordinates\":[732624,820816]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Novosibirsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Novosibirsk\",\"iso_a2\":\"RU\"},\"coordinates\":[730438,830751]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Mogadishu\",\"adm0name\":\"Somalia\",\"adm1name\":\"Banaadir\",\"iso_a2\":\"SO\"},\"coordinates\":[626013,516973]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Muscat\",\"adm0name\":\"Oman\",\"adm1name\":\"Muscat\",\"iso_a2\":\"OM\"},\"coordinates\":[662758,644613]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Colombo\",\"adm0name\":\"Sri Lanka\",\"adm1name\":\"Colombo\",\"iso_a2\":\"LK\"},\"coordinates\":[721827,545785]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Cebu\",\"adm0name\":\"Philippines\",\"adm1name\":\"Cebu\",\"iso_a2\":\"PH\"},\"coordinates\":[844161,565868]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Iloilo\",\"adm0name\":\"Philippines\",\"adm1name\":\"Iloilo\",\"iso_a2\":\"PH\"},\"coordinates\":[840402,568139]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Davao\",\"adm0name\":\"Philippines\",\"adm1name\":\"Davao Del Sur\",\"iso_a2\":\"PH\"},\"coordinates\":[848966,546852]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Bratsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Irkutsk\",\"iso_a2\":\"RU\"},\"coordinates\":[782263,837417]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Irkutsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Irkutsk\",\"iso_a2\":\"RU\"},\"coordinates\":[789569,814685]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Krasnoyarsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Krasnoyarsk\",\"iso_a2\":\"RU\"},\"coordinates\":[757955,836581]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Dickson\",\"adm0name\":\"Russia\",\"adm1name\":\"Taymyr\",\"iso_a2\":\"RU\"},\"coordinates\":[723736,940205]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Chita\",\"adm0name\":\"Russia\",\"adm1name\":\"Chita\",\"iso_a2\":\"RU\"},\"coordinates\":[815180,813115]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Vladivostok\",\"adm0name\":\"Russia\",\"adm1name\":\"Primor'ye\",\"iso_a2\":\"RU\"},\"coordinates\":[866416,760239]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Nizhneyansk\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[877962,927920]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Yakutsk\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[860374,872240]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Tiksi\",\"adm0name\":\"Russia\",\"adm1name\":\"Sakha (Yakutia)\",\"iso_a2\":\"RU\"},\"coordinates\":[857874,929067]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Magadan\",\"adm0name\":\"Russia\",\"adm1name\":\"Maga Buryatdan\",\"iso_a2\":\"RU\"},\"coordinates\":[918916,857666]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Tijuana\",\"adm0name\":\"Mexico\",\"adm1name\":\"Baja California\",\"iso_a2\":\"MX\"},\"coordinates\":[174772,697273]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Chihuahua\",\"adm0name\":\"Mexico\",\"adm1name\":\"Chihuahua\",\"iso_a2\":\"MX\"},\"coordinates\":[205314,674434]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Mazatlan\",\"adm0name\":\"Mexico\",\"adm1name\":\"Sinaloa\",\"iso_a2\":\"MX\"},\"coordinates\":[204388,642289]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Tampico\",\"adm0name\":\"Mexico\",\"adm1name\":\"Tamaulipas\",\"iso_a2\":\"MX\"},\"coordinates\":[228139,636832]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Acapulco\",\"adm0name\":\"Mexico\",\"adm1name\":\"Guerrero\",\"iso_a2\":\"MX\"},\"coordinates\":[222456,604544]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Veracruz\",\"adm0name\":\"Mexico\",\"adm1name\":\"Veracruz\",\"iso_a2\":\"MX\"},\"coordinates\":[232889,618332]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Tuxtla Gutierrez\",\"adm0name\":\"Mexico\",\"adm1name\":\"Chiapas\",\"iso_a2\":\"MX\"},\"coordinates\":[241250,603952]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Cancun\",\"adm0name\":\"Mexico\",\"adm1name\":\"Quintana Roo\",\"iso_a2\":\"MX\"},\"coordinates\":[258805,630138]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Merida\",\"adm0name\":\"Mexico\",\"adm1name\":\"Yucatán\",\"iso_a2\":\"MX\"},\"coordinates\":[251059,628944]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Enugu\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Enugu\",\"iso_a2\":\"NG\"},\"coordinates\":[520833,542930]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Sokoto\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Sokoto\",\"iso_a2\":\"NG\"},\"coordinates\":[514555,582090]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Perm\",\"adm0name\":\"Russia\",\"adm1name\":\"Perm'\",\"iso_a2\":\"RU\"},\"coordinates\":[656244,848347]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Erdenet\",\"adm0name\":\"Mongolia\",\"adm1name\":\"Orhon\",\"iso_a2\":\"MN\"},\"coordinates\":[789217,795331]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Ulaanbaatar\",\"adm0name\":\"Mongolia\",\"adm1name\":\"Ulaanbaatar\",\"iso_a2\":\"MN\"},\"coordinates\":[796984,788609]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Wellington\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Manawatu-Wanganui\",\"iso_a2\":\"NZ\"},\"coordinates\":[985509,260037]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Mbeya\",\"adm0name\":\"Tanzania\",\"adm1name\":\"Mbeya\",\"iso_a2\":\"TZ\"},\"coordinates\":[592861,452049]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Windhoek\",\"adm0name\":\"Namibia\",\"adm1name\":\"Khomas\",\"iso_a2\":\"NA\"},\"coordinates\":[547454,371002]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Grootfontein\",\"adm0name\":\"Namibia\",\"adm1name\":\"Otjozondjupa\",\"iso_a2\":\"NA\"},\"coordinates\":[550323,388796]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Zanzibar\",\"adm0name\":\"Tanzania\",\"adm1name\":\"Zanzibar West\",\"iso_a2\":\"TZ\"},\"coordinates\":[608889,468223]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Christchurch\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Canterbury\",\"iso_a2\":\"NZ\"},\"coordinates\":[979527,246796]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Valencia\",\"adm0name\":\"Spain\",\"adm1name\":\"Comunidad Valenciana\",\"iso_a2\":\"ES\"},\"coordinates\":[498883,738656]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Palana\",\"adm0name\":\"Russia\",\"adm1name\":\"Kamchatka\",\"iso_a2\":\"RU\"},\"coordinates\":[944305,854757]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Petropavlovsk Kamchatskiy\",\"adm0name\":\"Russia\",\"adm1name\":\"Kamchatka\",\"iso_a2\":\"RU\"},\"coordinates\":[940619,819080]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Abuja\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Federal Capital Territory\",\"iso_a2\":\"NG\"},\"coordinates\":[520920,558542]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Padang\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Sumatera Barat\",\"iso_a2\":\"ID\"},\"coordinates\":[778771,499041]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Bissau\",\"adm0name\":\"Guinea Bissau\",\"adm1name\":\"Bissau\",\"iso_a2\":\"GW\"},\"coordinates\":[456670,575011]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Palermo\",\"adm0name\":\"Italy\",\"adm1name\":\"Sicily\",\"iso_a2\":\"IT\"},\"coordinates\":[537078,730599]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Amman\",\"adm0name\":\"Jordan\",\"adm1name\":\"Amman\",\"iso_a2\":\"JO\"},\"coordinates\":[599808,694015]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Vilnius\",\"adm0name\":\"Lithuania\",\"adm1name\":\"Vilniaus\",\"iso_a2\":\"LT\"},\"coordinates\":[570324,828686]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Riga\",\"adm0name\":\"Latvia\",\"adm1name\":\"Riga\",\"iso_a2\":\"LV\"},\"coordinates\":[566943,842115]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Bishkek\",\"adm0name\":\"Kyrgyzstan\",\"adm1name\":\"Bishkek\",\"iso_a2\":\"KG\"},\"coordinates\":[707175,758728]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Jiayuguan\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[773055,740629]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Xining\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[782688,721682]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Guilin\",\"adm0name\":\"China\",\"adm1name\":\"Guangxi\",\"iso_a2\":\"CN\"},\"coordinates\":[806327,654499]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Huainan\",\"adm0name\":\"China\",\"adm1name\":\"Anhui\",\"iso_a2\":\"CN\"},\"coordinates\":[824938,698043]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Shantou\",\"adm0name\":\"China\",\"adm1name\":\"Guangdong\",\"iso_a2\":\"CN\"},\"coordinates\":[824077,643183]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Tarakan\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Kalimantan Timur\",\"iso_a2\":\"ID\"},\"coordinates\":[826757,524268]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Mombasa\",\"adm0name\":\"Kenya\",\"adm1name\":\"Coast\",\"iso_a2\":\"KE\"},\"coordinates\":[610243,480793]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Maseru\",\"adm0name\":\"Lesotho\",\"adm1name\":\"Maseru\",\"iso_a2\":\"LS\"},\"coordinates\":[576342,331032]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Antananarivo\",\"adm0name\":\"Madagascar\",\"adm1name\":\"Antananarivo\",\"iso_a2\":\"MG\"},\"coordinates\":[631985,392658]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Semarang\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Jawa Tengah\",\"iso_a2\":\"ID\"},\"coordinates\":[806717,463455]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Palembang\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Sumatera Selatan\",\"iso_a2\":\"ID\"},\"coordinates\":[790966,487074]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Bandjarmasin\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Kalimantan Selatan\",\"iso_a2\":\"ID\"},\"coordinates\":[818277,484989]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Ujungpandang\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Sulawesi Selatan\",\"iso_a2\":\"ID\"},\"coordinates\":[831749,474277]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Lyon\",\"adm0name\":\"France\",\"adm1name\":\"Rhône-Alpes\",\"iso_a2\":\"FR\"},\"coordinates\":[513411,775891]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Quito\",\"adm0name\":\"Ecuador\",\"adm1name\":\"Pichincha\",\"iso_a2\":\"EC\"},\"coordinates\":[281939,503455]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"San Jose\",\"adm0name\":\"Costa Rica\",\"adm1name\":\"San José\",\"iso_a2\":\"CR\"},\"coordinates\":[266428,563588]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"San Salvador\",\"adm0name\":\"El Salvador\",\"adm1name\":\"San Salvador\",\"iso_a2\":\"SV\"},\"coordinates\":[252208,585953]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Kingston\",\"adm0name\":\"Jamaica\",\"adm1name\":\"Kingston\",\"iso_a2\":\"JM\"},\"coordinates\":[286756,611221]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Cartagena\",\"adm0name\":\"Colombia\",\"adm1name\":\"Bolívar\",\"iso_a2\":\"CO\"},\"coordinates\":[290232,566341]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Mitu\",\"adm0name\":\"Colombia\",\"adm1name\":\"Vaupés\",\"iso_a2\":\"CO\"},\"coordinates\":[305073,511816]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Bumba\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Équateur\",\"iso_a2\":\"CD\"},\"coordinates\":[562388,517692]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Ndjamena\",\"adm0name\":\"Chad\",\"adm1name\":\"Hadjer-Lamis\",\"iso_a2\":\"TD\"},\"coordinates\":[541797,576492]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Abeche\",\"adm0name\":\"Chad\",\"adm1name\":\"Ouaddaï\",\"iso_a2\":\"TD\"},\"coordinates\":[557860,586711]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Malabo\",\"adm0name\":\"Equatorial Guinea\",\"adm1name\":\"Bioko Norte\",\"iso_a2\":\"GQ\"},\"coordinates\":[524398,526934]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Luxor\",\"adm0name\":\"Egypt\",\"adm1name\":\"Qina\",\"iso_a2\":\"EG\"},\"coordinates\":[590694,656975]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Asmara\",\"adm0name\":\"Eritrea\",\"adm1name\":\"Anseba\",\"iso_a2\":\"ER\"},\"coordinates\":[608148,595558]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Zagreb\",\"adm0name\":\"Croatia\",\"adm1name\":\"Grad Zagreb\",\"iso_a2\":\"HR\"},\"coordinates\":[544444,776057]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Tallinn\",\"adm0name\":\"Estonia\",\"adm1name\":\"Harju\",\"iso_a2\":\"EE\"},\"coordinates\":[568688,856830]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Lhasa\",\"adm0name\":\"China\",\"adm1name\":\"Xizang\",\"iso_a2\":\"CN\"},\"coordinates\":[753055,680348]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Hami\",\"adm0name\":\"China\",\"adm1name\":\"Xinjiang Uygur\",\"iso_a2\":\"CN\"},\"coordinates\":[759763,758443]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Hotan\",\"adm0name\":\"China\",\"adm1name\":\"Xinjiang Uygur\",\"iso_a2\":\"CN\"},\"coordinates\":[722018,724513]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Kashgar\",\"adm0name\":\"China\",\"adm1name\":\"Xinjiang Uygur\",\"iso_a2\":\"CN\"},\"coordinates\":[711027,738593]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Yinchuan\",\"adm0name\":\"China\",\"adm1name\":\"Ningxia Hui\",\"iso_a2\":\"CN\"},\"coordinates\":[795197,732631]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Pingxiang\",\"adm0name\":\"China\",\"adm1name\":\"Jiangxi\",\"iso_a2\":\"CN\"},\"coordinates\":[816244,668362]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Nagasaki\",\"adm0name\":\"Japan\",\"adm1name\":\"Nagasaki\",\"iso_a2\":\"JP\"},\"coordinates\":[860790,698831]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Qiqihar\",\"adm0name\":\"China\",\"adm1name\":\"Heilongjiang\",\"iso_a2\":\"CN\"},\"coordinates\":[844410,785222]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Kikwit\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Bandundu\",\"iso_a2\":\"CD\"},\"coordinates\":[552361,474917]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Matadi\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Bas-Congo\",\"iso_a2\":\"CD\"},\"coordinates\":[537360,470257]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Kolwezi\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Katanga\",\"iso_a2\":\"CD\"},\"coordinates\":[570756,441226]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Lubumbashi\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Katanga\",\"iso_a2\":\"CD\"},\"coordinates\":[576327,435531]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Lilongwe\",\"adm0name\":\"Malawi\",\"adm1name\":\"Lilongwe\",\"iso_a2\":\"MW\"},\"coordinates\":[593842,421873]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Guatemala\",\"adm0name\":\"Guatemala\",\"adm1name\":\"Guatemala\",\"iso_a2\":\"GT\"},\"coordinates\":[248530,591351]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Cayenne\",\"adm0name\":\"France\",\"adm1name\":\"Guinaa\",\"iso_a2\":\"GF\"},\"coordinates\":[354639,533942]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Libreville\",\"adm0name\":\"Gabon\",\"adm1name\":\"Estuaire\",\"iso_a2\":\"GA\"},\"coordinates\":[526271,507000]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Vishakhapatnam\",\"adm0name\":\"India\",\"adm1name\":\"Andhra Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[731396,609769]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Suva\",\"adm0name\":\"Fiji\",\"adm1name\":\"Central\",\"iso_a2\":\"FJ\"},\"coordinates\":[995670,397289]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Port-Gentil\",\"adm0name\":\"Gabon\",\"adm1name\":\"Ogooué-Maritime\",\"iso_a2\":\"GA\"},\"coordinates\":[524389,500451]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Timbuktu\",\"adm0name\":\"Mali\",\"adm1name\":\"Timbuktu\",\"iso_a2\":\"ML\"},\"coordinates\":[491620,604050]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Punta Arenas\",\"adm0name\":\"Chile\",\"adm1name\":\"Magallanes y Antártica Chilena\",\"iso_a2\":\"CL\"},\"coordinates\":[302944,189744]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Iquique\",\"adm0name\":\"Chile\",\"adm1name\":\"Tarapacá\",\"iso_a2\":\"CL\"},\"coordinates\":[305194,384747]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Antofagasta\",\"adm0name\":\"Chile\",\"adm1name\":\"Antofagasta\",\"iso_a2\":\"CL\"},\"coordinates\":[304444,364604]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Valparaiso\",\"adm0name\":\"Chile\",\"adm1name\":\"Valparaíso\",\"iso_a2\":\"CL\"},\"coordinates\":[301047,308939]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Valdivia\",\"adm0name\":\"Chile\",\"adm1name\":\"Los Ríos\",\"iso_a2\":\"CL\"},\"coordinates\":[296541,268953]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Concepcion\",\"adm0name\":\"Chile\",\"adm1name\":\"Bío-Bío\",\"iso_a2\":\"CL\"},\"coordinates\":[297083,286520]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Puerto Montt\",\"adm0name\":\"Chile\",\"adm1name\":\"Los Lagos\",\"iso_a2\":\"CL\"},\"coordinates\":[297416,259030]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Nuuk\",\"adm0name\":\"Greenland\",\"adm1name\":\"Kommuneqarfik Sermersooq\",\"iso_a2\":\"GL\"},\"coordinates\":[356298,885057]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Nouakchott\",\"adm0name\":\"Mauritania\",\"adm1name\":\"Nouakchott\",\"iso_a2\":\"MR\"},\"coordinates\":[455623,611869]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Bamako\",\"adm0name\":\"Mali\",\"adm1name\":\"Bamako\",\"iso_a2\":\"ML\"},\"coordinates\":[477771,579673]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Atar\",\"adm0name\":\"Mauritania\",\"adm1name\":\"Adrar\",\"iso_a2\":\"MR\"},\"coordinates\":[463750,626267]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Djenne\",\"adm0name\":\"Mali\",\"adm1name\":\"Mopti\",\"iso_a2\":\"ML\"},\"coordinates\":[487360,587067]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Sabha\",\"adm0name\":\"Libya\",\"adm1name\":\"Sabha\",\"iso_a2\":\"LY\"},\"coordinates\":[540092,664874]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Banghazi\",\"adm0name\":\"Libya\",\"adm1name\":\"Benghazi\",\"iso_a2\":\"LY\"},\"coordinates\":[555735,695002]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Thessaloniki\",\"adm0name\":\"Greece\",\"adm1name\":\"Kentriki Makedonia\",\"iso_a2\":\"GR\"},\"coordinates\":[563564,745831]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Beirut\",\"adm0name\":\"Lebanon\",\"adm1name\":\"Beirut\",\"iso_a2\":\"LB\"},\"coordinates\":[598632,705401]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Tbilisi\",\"adm0name\":\"Georgia\",\"adm1name\":\"Tbilisi\",\"iso_a2\":\"GE\"},\"coordinates\":[624412,751926]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Gonder\",\"adm0name\":\"Ethiopia\",\"adm1name\":\"Amhara\",\"iso_a2\":\"ET\"},\"coordinates\":[604055,579425]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Astana\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Aqmola\",\"iso_a2\":\"KZ\"},\"coordinates\":[698409,807937]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Qaraghandy\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Qaraghandy\",\"iso_a2\":\"KZ\"},\"coordinates\":[703096,800258]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Almaty\",\"adm0name\":\"Kazakhstan\",\"adm1name\":\"Almaty\",\"iso_a2\":\"KZ\"},\"coordinates\":[713646,761406]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Isfahan\",\"adm0name\":\"Iran\",\"adm1name\":\"Esfahan\",\"iso_a2\":\"IR\"},\"coordinates\":[643606,698458]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Shiraz\",\"adm0name\":\"Iran\",\"adm1name\":\"Fars\",\"iso_a2\":\"IR\"},\"coordinates\":[646022,680270]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Amritsar\",\"adm0name\":\"India\",\"adm1name\":\"Punjab\",\"iso_a2\":\"IN\"},\"coordinates\":[707966,692178]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Varanasi\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[730549,654795]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Asansol\",\"adm0name\":\"India\",\"adm1name\":\"West Bengal\",\"iso_a2\":\"IN\"},\"coordinates\":[741614,645039]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Bhilai\",\"adm0name\":\"India\",\"adm1name\":\"Chhattisgarh\",\"iso_a2\":\"IN\"},\"coordinates\":[726197,630426]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Bhopal\",\"adm0name\":\"India\",\"adm1name\":\"Madhya Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[715022,642472]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Madurai\",\"adm0name\":\"India\",\"adm1name\":\"Tamil Nadu\",\"iso_a2\":\"IN\"},\"coordinates\":[716994,563499]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Coimbatore\",\"adm0name\":\"India\",\"adm1name\":\"Tamil Nadu\",\"iso_a2\":\"IN\"},\"coordinates\":[713744,569897]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Vientiane\",\"adm0name\":\"Laos\",\"adm1name\":\"Vientiane [prefecture]\",\"iso_a2\":\"LA\"},\"coordinates\":[784999,611160]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Brazzaville\",\"adm0name\":\"Congo (Brazzaville)\",\"adm1name\":\"Pool\",\"iso_a2\":\"CG\"},\"coordinates\":[542451,479495]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Conakry\",\"adm0name\":\"Guinea\",\"adm1name\":\"Conakry\",\"iso_a2\":\"GN\"},\"coordinates\":[461993,561198]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Yamoussoukro\",\"adm0name\":\"Ivory Coast\",\"adm1name\":\"Lacs\",\"iso_a2\":\"CI\"},\"coordinates\":[485346,545112]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Cruzeiro do Sul\",\"adm0name\":\"Brazil\",\"adm1name\":\"Acre\",\"iso_a2\":\"BR\"},\"coordinates\":[298138,459513]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Leticia\",\"adm0name\":\"Colombia\",\"adm1name\":\"Amazonas\",\"iso_a2\":\"CO\"},\"coordinates\":[305679,479827]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Manaus\",\"adm0name\":\"Brazil\",\"adm1name\":\"Amazonas\",\"iso_a2\":\"BR\"},\"coordinates\":[333328,486363]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Caxias\",\"adm0name\":\"Brazil\",\"adm1name\":\"Maranhão\",\"iso_a2\":\"BR\"},\"coordinates\":[379583,476084]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Santarem\",\"adm0name\":\"Brazil\",\"adm1name\":\"Pará\",\"iso_a2\":\"BR\"},\"coordinates\":[348055,490302]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Maraba\",\"adm0name\":\"Brazil\",\"adm1name\":\"Pará\",\"iso_a2\":\"BR\"},\"coordinates\":[363566,473022]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Vilhena\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rondônia\",\"iso_a2\":\"BR\"},\"coordinates\":[333009,429378]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Ji-Parana\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rondônia\",\"iso_a2\":\"BR\"},\"coordinates\":[327870,440536]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Campo Grande\",\"adm0name\":\"Brazil\",\"adm1name\":\"Mato Grosso do Sul\",\"iso_a2\":\"BR\"},\"coordinates\":[348282,383573]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Florianopolis\",\"adm0name\":\"Brazil\",\"adm1name\":\"Santa Catarina\",\"iso_a2\":\"BR\"},\"coordinates\":[365216,341333]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Feira de Santana\",\"adm0name\":\"Brazil\",\"adm1name\":\"Bahia\",\"iso_a2\":\"BR\"},\"coordinates\":[391750,432142]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Winnipeg\",\"adm0name\":\"Canada\",\"adm1name\":\"Manitoba\",\"iso_a2\":\"CA\"},\"coordinates\":[230094,800247]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Churchill\",\"adm0name\":\"Canada\",\"adm1name\":\"Manitoba\",\"iso_a2\":\"CA\"},\"coordinates\":[238427,852873]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Regina\",\"adm0name\":\"Canada\",\"adm1name\":\"Saskatchewan\",\"iso_a2\":\"CA\"},\"coordinates\":[209397,803606]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Saskatoon\",\"adm0name\":\"Canada\",\"adm1name\":\"Saskatchewan\",\"iso_a2\":\"CA\"},\"coordinates\":[203694,813796]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Calgary\",\"adm0name\":\"Canada\",\"adm1name\":\"Alberta\",\"iso_a2\":\"CA\"},\"coordinates\":[183106,807367]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Prince Rupert\",\"adm0name\":\"Canada\",\"adm1name\":\"British Columbia\",\"iso_a2\":\"CA\"},\"coordinates\":[137973,826514]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Victoria\",\"adm0name\":\"Canada\",\"adm1name\":\"British Columbia\",\"iso_a2\":\"CA\"},\"coordinates\":[157361,791657]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Arctic Bay\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[263425,937400]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Resolute\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[236389,947175]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Repulse Bay\",\"adm0name\":\"Canada\",\"adm1name\":\"Nunavut\",\"iso_a2\":\"CA\"},\"coordinates\":[260325,898868]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Yellowknife\",\"adm0name\":\"Canada\",\"adm1name\":\"Northwest Territories\",\"iso_a2\":\"CA\"},\"coordinates\":[182230,874652]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Fort Good Hope\",\"adm0name\":\"Canada\",\"adm1name\":\"Northwest Territories\",\"iso_a2\":\"CA\"},\"coordinates\":[142685,897311]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Whitehorse\",\"adm0name\":\"Canada\",\"adm1name\":\"Yukon\",\"iso_a2\":\"CA\"},\"coordinates\":[124861,864430]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Boa Vista\",\"adm0name\":\"Brazil\",\"adm1name\":\"Roraima\",\"iso_a2\":\"BR\"},\"coordinates\":[331483,521401]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":1,\"name\":\"Macapá\",\"adm0name\":\"Brazil\",\"adm1name\":\"Amapá\",\"iso_a2\":\"BR\"},\"coordinates\":[358194,504913]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Ottawa\",\"adm0name\":\"Canada\",\"adm1name\":\"Ontario\",\"iso_a2\":\"CA\"},\"coordinates\":[289716,773798]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Fort Severn\",\"adm0name\":\"Canada\",\"adm1name\":\"Ontario\",\"iso_a2\":\"CA\"},\"coordinates\":[256528,836387]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Thunder Bay\",\"adm0name\":\"Canada\",\"adm1name\":\"Ontario\",\"iso_a2\":\"CA\"},\"coordinates\":[252014,791734]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Québec\",\"adm0name\":\"Canada\",\"adm1name\":\"Québec\",\"iso_a2\":\"CA\"},\"coordinates\":[302095,782218]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Halifax\",\"adm0name\":\"Canada\",\"adm1name\":\"Nova Scotia\",\"iso_a2\":\"CA\"},\"coordinates\":[323333,769244]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"St. Johns\",\"adm0name\":\"Canada\",\"adm1name\":\"Newfoundland and Labrador\",\"iso_a2\":\"CA\"},\"coordinates\":[353663,786632]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Nain\",\"adm0name\":\"Canada\",\"adm1name\":\"Newfoundland and Labrador\",\"iso_a2\":\"CA\"},\"coordinates\":[328650,839729]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":2,\"name\":\"Charlottetown\",\"adm0name\":\"Canada\",\"adm1name\":\"Prince Edward Island\",\"iso_a2\":\"CA\"},\"coordinates\":[324635,778719]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Ndele\",\"adm0name\":\"Central African Republic\",\"adm1name\":\"Bamingui-Bangoran\",\"iso_a2\":\"CF\"},\"coordinates\":[557369,554537]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Belgrade\",\"adm0name\":\"Serbia\",\"adm1name\":\"Grad Beograd\",\"iso_a2\":\"RS\"},\"coordinates\":[556849,770254]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Obo\",\"adm0name\":\"Central African Republic\",\"adm1name\":\"Haut-Mbomou\",\"iso_a2\":\"CF\"},\"coordinates\":[573611,536709]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Bandar Seri Begawan\",\"adm0name\":\"Brunei\",\"adm1name\":\"Brunei and Muara\",\"iso_a2\":\"BN\"},\"coordinates\":[819259,533648]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Puerto Deseado\",\"adm0name\":\"Argentina\",\"adm1name\":\"Santa Cruz\",\"iso_a2\":\"AR\"},\"coordinates\":[316944,221825]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Rio Gallegos\",\"adm0name\":\"Argentina\",\"adm1name\":\"Santa Cruz\",\"iso_a2\":\"AR\"},\"coordinates\":[307731,198818]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Comodoro Rivadavia\",\"adm0name\":\"Argentina\",\"adm1name\":\"Chubut\",\"iso_a2\":\"AR\"},\"coordinates\":[312500,232962]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Mendoza\",\"adm0name\":\"Argentina\",\"adm1name\":\"Mendoza\",\"iso_a2\":\"AR\"},\"coordinates\":[308837,309913]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Sucre\",\"adm0name\":\"Bolivia\",\"adm1name\":\"Chuquisaca\",\"iso_a2\":\"BO\"},\"coordinates\":[318723,391910]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Riberalta\",\"adm0name\":\"Bolivia\",\"adm1name\":\"El Beni\",\"iso_a2\":\"BO\"},\"coordinates\":[316388,439649]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Bahia Blanca\",\"adm0name\":\"Argentina\",\"adm1name\":\"Ciudad de Buenos Aires\",\"iso_a2\":\"AR\"},\"coordinates\":[327041,275203]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Mar del Plata\",\"adm0name\":\"Argentina\",\"adm1name\":\"Ciudad de Buenos Aires\",\"iso_a2\":\"AR\"},\"coordinates\":[340055,279587]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Córdoba\",\"adm0name\":\"Argentina\",\"adm1name\":\"Córdoba\",\"iso_a2\":\"AR\"},\"coordinates\":[321710,318701]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Posadas\",\"adm0name\":\"Argentina\",\"adm1name\":\"Misiones\",\"iso_a2\":\"AR\"},\"coordinates\":[344763,342637]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Belmopan\",\"adm0name\":\"Belize\",\"adm1name\":\"Cayo\",\"iso_a2\":\"BZ\"},\"coordinates\":[253425,606926]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Bangui\",\"adm0name\":\"Central African Republic\",\"adm1name\":\"Bangui\",\"iso_a2\":\"CF\"},\"coordinates\":[551550,530587]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Maroua\",\"adm0name\":\"Cameroon\",\"adm1name\":\"Extrême-Nord\",\"iso_a2\":\"CM\"},\"coordinates\":[539790,567490]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Yaounde\",\"adm0name\":\"Cameroon\",\"adm1name\":\"Centre\",\"iso_a2\":\"CM\"},\"coordinates\":[531985,527636]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Tirana\",\"adm0name\":\"Albania\",\"adm1name\":\"Durrës\",\"iso_a2\":\"AL\"},\"coordinates\":[555051,749560]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Yerevan\",\"adm0name\":\"Armenia\",\"adm1name\":\"Erevan\",\"iso_a2\":\"AM\"},\"coordinates\":[623642,742780]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Baku\",\"adm0name\":\"Azerbaijan\",\"adm1name\":\"Baki\",\"iso_a2\":\"AZ\"},\"coordinates\":[638500,744048]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Kandahar\",\"adm0name\":\"Afghanistan\",\"adm1name\":\"Kandahar\",\"iso_a2\":\"AF\"},\"coordinates\":[682485,691989]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Phnom Penh\",\"adm0name\":\"Cambodia\",\"adm1name\":\"Phnom Penh\",\"iso_a2\":\"KH\"},\"coordinates\":[791428,573156]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Menongue\",\"adm0name\":\"Angola\",\"adm1name\":\"Cuando Cubango\",\"iso_a2\":\"AO\"},\"coordinates\":[549166,417825]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Huambo\",\"adm0name\":\"Angola\",\"adm1name\":\"Huambo\",\"iso_a2\":\"AO\"},\"coordinates\":[543772,429192]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"La Paz\",\"adm0name\":\"Bolivia\",\"adm1name\":\"La Paz\",\"iso_a2\":\"BO\"},\"coordinates\":[310688,406987]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Santa Cruz\",\"adm0name\":\"Bolivia\",\"adm1name\":\"Santa Cruz\",\"iso_a2\":\"BO\"},\"coordinates\":[324366,399546]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Oran\",\"adm0name\":\"Algeria\",\"adm1name\":\"Oran\",\"iso_a2\":\"DZ\"},\"coordinates\":[498272,716291]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Cotonou\",\"adm0name\":\"Benin\",\"adm1name\":\"Ouémé\",\"iso_a2\":\"BJ\"},\"coordinates\":[506994,542646]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Tamanrasset\",\"adm0name\":\"Algeria\",\"adm1name\":\"Tamanghasset\",\"iso_a2\":\"DZ\"},\"coordinates\":[515341,639705]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Ghardaia\",\"adm0name\":\"Algeria\",\"adm1name\":\"Ghardaïa\",\"iso_a2\":\"DZ\"},\"coordinates\":[510194,697202]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Sofia\",\"adm0name\":\"Bulgaria\",\"adm1name\":\"Grad Sofiya\",\"iso_a2\":\"BG\"},\"coordinates\":[564762,757604]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":6,\"name\":\"Minsk\",\"adm0name\":\"Belarus\",\"adm1name\":\"Minsk\",\"iso_a2\":\"BY\"},\"coordinates\":[576568,824056]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Thimphu\",\"adm0name\":\"Bhutan\",\"adm1name\":\"Thimphu\",\"iso_a2\":\"BT\"},\"coordinates\":[748997,667480]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":7,\"name\":\"Gaborone\",\"adm0name\":\"Botswana\",\"adm1name\":\"South-East\",\"iso_a2\":\"BW\"},\"coordinates\":[571977,358701]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Darwin\",\"adm0name\":\"Australia\",\"adm1name\":\"Northern Territory\",\"iso_a2\":\"AU\"},\"coordinates\":[863471,431104]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Alice Springs\",\"adm0name\":\"Australia\",\"adm1name\":\"Northern Territory\",\"iso_a2\":\"AU\"},\"coordinates\":[871888,364302]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Canberra\",\"adm0name\":\"Australia\",\"adm1name\":\"Australian Capital Territory\",\"iso_a2\":\"AU\"},\"coordinates\":[914247,295685]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Newcastle\",\"adm0name\":\"Australia\",\"adm1name\":\"New South Wales\",\"iso_a2\":\"AU\"},\"coordinates\":[921708,310126]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Adelaide\",\"adm0name\":\"Australia\",\"adm1name\":\"South Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[884994,297758]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Townsville\",\"adm0name\":\"Australia\",\"adm1name\":\"Queensland\",\"iso_a2\":\"AU\"},\"coordinates\":[907694,390672]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Brisbane\",\"adm0name\":\"Australia\",\"adm1name\":\"Queensland\",\"iso_a2\":\"AU\"},\"coordinates\":[925091,342073]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":3,\"name\":\"Hobart\",\"adm0name\":\"Australia\",\"adm1name\":\"Tasmania\",\"iso_a2\":\"AU\"},\"coordinates\":[909152,250854]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Ouagadougou\",\"adm0name\":\"Burkina Faso\",\"adm1name\":\"Kadiogo\",\"iso_a2\":\"BF\"},\"coordinates\":[495759,578016]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Sarajevo\",\"adm0name\":\"Bosnia and Herzegovina\",\"adm1name\":\"Sarajevo\",\"iso_a2\":\"BA\"},\"coordinates\":[551063,764505]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":5,\"name\":\"Naypyidaw\",\"adm0name\":\"Myanmar\",\"adm1name\":\"Mandalay\",\"iso_a2\":\"MM\"},\"coordinates\":[766990,621835]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"San Juan\",\"adm0name\":\"Puerto Rico\",\"iso_a2\":\"PR\"},\"coordinates\":[316305,613964]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Stanley\",\"adm0name\":\"Falkland Islands\",\"iso_a2\":\"FK\"},\"coordinates\":[339306,198423]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Hamilton\",\"adm0name\":\"Bermuda\",\"iso_a2\":\"BM\"},\"coordinates\":[320044,696043]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Nukualofa\",\"adm0name\":\"Tonga\",\"iso_a2\":\"TO\"},\"coordinates\":[13276,379483]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Hargeysa\",\"adm0name\":\"Somaliland\",\"iso_a2\":\"-99\"},\"coordinates\":[622403,561355]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Victoria\",\"adm0name\":\"Seychelles\",\"iso_a2\":\"SC\"},\"coordinates\":[654027,477366]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Sao Tome\",\"adm0name\":\"Sao Tome and Principe\",\"iso_a2\":\"ST\"},\"coordinates\":[518703,506692]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Apia\",\"adm0name\":\"Samoa\",\"iso_a2\":\"WS\"},\"coordinates\":[22948,422713]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Valletta\",\"adm0name\":\"Malta\",\"iso_a2\":\"MT\"},\"coordinates\":[540318,717403]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Male\",\"adm0name\":\"Maldives\",\"iso_a2\":\"MV\"},\"coordinates\":[704166,529403]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Jerusalem\",\"adm0name\":\"Israel\",\"adm1name\":\"Jerusalem\",\"iso_a2\":\"IL\"},\"coordinates\":[597795,692987]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Praia\",\"adm0name\":\"Cape Verde\",\"iso_a2\":\"CV\"},\"coordinates\":[434676,593090]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Nassau\",\"adm0name\":\"The Bahamas\",\"iso_a2\":\"BS\"},\"coordinates\":[285138,653322]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":0,\"name\":\"Nicosia\",\"adm0name\":\"Cyprus\",\"iso_a2\":\"CY\"},\"coordinates\":[592684,713060]},{\"type\":\"Point\",\"properties\":{\"scalerank\":3,\"labelrank\":8,\"name\":\"Kaohsiung\",\"adm0name\":\"Taiwan\",\"adm1name\":\"Kaohsiung City\",\"iso_a2\":\"TW\"},\"coordinates\":[834073,638807]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Shenzhen\",\"adm0name\":\"China\",\"adm1name\":\"Guangdong\",\"iso_a2\":\"CN\"},\"coordinates\":[816999,638339]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Zibo\",\"adm0name\":\"China\",\"adm1name\":\"Shandong\",\"iso_a2\":\"CN\"},\"coordinates\":[827911,722749]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Minneapolis\",\"adm0name\":\"United States of America\",\"adm1name\":\"Minnesota\",\"iso_a2\":\"US\"},\"coordinates\":[240962,771210]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Honolulu\",\"adm0name\":\"United States of America\",\"adm1name\":\"Hawaii\",\"iso_a2\":\"US\"},\"coordinates\":[61500,630960]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Seattle\",\"adm0name\":\"United States of America\",\"adm1name\":\"Washington\",\"iso_a2\":\"US\"},\"coordinates\":[160161,786555]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Phoenix\",\"adm0name\":\"United States of America\",\"adm1name\":\"Arizona\",\"iso_a2\":\"US\"},\"coordinates\":[188689,703435]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"San Diego\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[174494,699169]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"St. Louis\",\"adm0name\":\"United States of America\",\"adm1name\":\"Missouri\",\"iso_a2\":\"US\"},\"coordinates\":[249328,733620]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"New Orleans\",\"adm0name\":\"United States of America\",\"adm1name\":\"Louisiana\",\"iso_a2\":\"US\"},\"coordinates\":[249883,682432]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Dallas\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[230995,699169]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Maracaibo\",\"adm0name\":\"Venezuela\",\"adm1name\":\"Zulia\",\"iso_a2\":\"VE\"},\"coordinates\":[300939,568298]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Boston\",\"adm0name\":\"United States of America\",\"adm1name\":\"Massachusetts\",\"iso_a2\":\"US\"},\"coordinates\":[302578,755511]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Tampa\",\"adm0name\":\"United States of America\",\"adm1name\":\"Florida\",\"iso_a2\":\"US\"},\"coordinates\":[270943,670299]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Philadelphia\",\"adm0name\":\"United States of America\",\"adm1name\":\"Pennsylvania\",\"iso_a2\":\"US\"},\"coordinates\":[291189,741707]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Detroit\",\"adm0name\":\"United States of America\",\"adm1name\":\"Michigan\",\"iso_a2\":\"US\"},\"coordinates\":[269217,755511]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Anchorage\",\"adm0name\":\"United States of America\",\"adm1name\":\"Alaska\",\"iso_a2\":\"US\"},\"coordinates\":[83611,867412]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Hanoi\",\"adm0name\":\"Vietnam\",\"adm1name\":\"Thái Nguyên\",\"iso_a2\":\"VN\"},\"coordinates\":[794022,629340]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Ho Chi Minh City\",\"adm0name\":\"Vietnam\",\"adm1name\":\"H? Chí Minh city\",\"iso_a2\":\"VN\"},\"coordinates\":[796369,568595]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Ankara\",\"adm0name\":\"Turkey\",\"adm1name\":\"Ankara\",\"iso_a2\":\"TR\"},\"coordinates\":[591284,741276]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Budapest\",\"adm0name\":\"Hungary\",\"adm1name\":\"Budapest\",\"iso_a2\":\"HU\"},\"coordinates\":[553003,786140]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Sanaa\",\"adm0name\":\"Yemen\",\"adm1name\":\"Amanat Al Asimah\",\"iso_a2\":\"YE\"},\"coordinates\":[622791,595697]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Barcelona\",\"adm0name\":\"Spain\",\"adm1name\":\"Cataluña\",\"iso_a2\":\"ES\"},\"coordinates\":[506059,749902]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Bucharest\",\"adm0name\":\"Romania\",\"adm1name\":\"Bucharest\",\"iso_a2\":\"RO\"},\"coordinates\":[572494,767972]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Aleppo\",\"adm0name\":\"Syria\",\"adm1name\":\"Aleppo (Halab)\",\"iso_a2\":\"SY\"},\"coordinates\":[603244,719372]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Damascus\",\"adm0name\":\"Syria\",\"adm1name\":\"Damascus\",\"iso_a2\":\"SY\"},\"coordinates\":[600827,703198]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":7,\"name\":\"Zürich\",\"adm0name\":\"Switzerland\",\"adm1name\":\"Zürich\",\"iso_a2\":\"CH\"},\"coordinates\":[523744,785429]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Lisbon\",\"adm0name\":\"Portugal\",\"adm1name\":\"Lisboa\",\"iso_a2\":\"PT\"},\"coordinates\":[474591,734139]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Khartoum\",\"adm0name\":\"Sudan\",\"adm1name\":\"Khartoum\",\"iso_a2\":\"SD\"},\"coordinates\":[590367,597079]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Jeddah\",\"adm0name\":\"Saudi Arabia\",\"adm1name\":\"Makkah\",\"iso_a2\":\"SA\"},\"coordinates\":[608936,632204]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Makkah\",\"adm0name\":\"Saudi Arabia\",\"adm1name\":\"Makkah\",\"iso_a2\":\"SA\"},\"coordinates\":[610605,631690]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":7,\"name\":\"Oslo\",\"adm0name\":\"Norway\",\"adm1name\":\"Oslo\",\"iso_a2\":\"NO\"},\"coordinates\":[529855,859702]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Lahore\",\"adm0name\":\"Pakistan\",\"adm1name\":\"Punjab\",\"iso_a2\":\"PK\"},\"coordinates\":[706522,691704]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Karachi\",\"adm0name\":\"Pakistan\",\"adm1name\":\"Sind\",\"iso_a2\":\"PK\"},\"coordinates\":[686077,652070]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Durban\",\"adm0name\":\"South Africa\",\"adm1name\":\"KwaZulu-Natal\",\"iso_a2\":\"ZA\"},\"coordinates\":[586050,327795]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"St. Petersburg\",\"adm0name\":\"Russia\",\"adm1name\":\"City of St. Petersburg\",\"iso_a2\":\"RU\"},\"coordinates\":[584205,859834]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Guadalajara\",\"adm0name\":\"Mexico\",\"adm1name\":\"Jalisco\",\"iso_a2\":\"MX\"},\"coordinates\":[212967,627187]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Puebla\",\"adm0name\":\"Mexico\",\"adm1name\":\"Puebla\",\"iso_a2\":\"MX\"},\"coordinates\":[227216,617589]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Kano\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Kano\",\"iso_a2\":\"NG\"},\"coordinates\":[523661,575822]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Warsaw\",\"adm0name\":\"Poland\",\"adm1name\":\"Masovian\",\"iso_a2\":\"PL\"},\"coordinates\":[558328,814281]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Pyongyang\",\"adm0name\":\"North Korea\",\"adm1name\":\"P'yongyang\",\"iso_a2\":\"KP\"},\"coordinates\":[849312,735898]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Dar es Salaam\",\"adm0name\":\"Tanzania\",\"adm1name\":\"Dar-Es-Salaam\",\"iso_a2\":\"TZ\"},\"coordinates\":[609072,464442]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Medan\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Sumatera Utara\",\"iso_a2\":\"ID\"},\"coordinates\":[774021,525938]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"Dublin\",\"adm0name\":\"Ireland\",\"adm1name\":\"Dublin\",\"iso_a2\":\"IE\"},\"coordinates\":[482636,820698]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"Monrovia\",\"adm0name\":\"Liberia\",\"adm1name\":\"Montserrado\",\"iso_a2\":\"LR\"},\"coordinates\":[470001,542128]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Naples\",\"adm0name\":\"Italy\",\"adm1name\":\"Campania\",\"iso_a2\":\"IT\"},\"coordinates\":[539564,746684]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Milan\",\"adm0name\":\"Italy\",\"adm1name\":\"Lombardia\",\"iso_a2\":\"IT\"},\"coordinates\":[525564,774114]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Kuala Lumpur\",\"adm0name\":\"Malaysia\",\"adm1name\":\"Selangor\",\"iso_a2\":\"MY\"},\"coordinates\":[782494,523489]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Lanzhou\",\"adm0name\":\"China\",\"adm1name\":\"Gansu\",\"iso_a2\":\"CN\"},\"coordinates\":[788304,718341]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Nanning\",\"adm0name\":\"China\",\"adm1name\":\"Guangxi\",\"iso_a2\":\"CN\"},\"coordinates\":[800883,639925]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Guiyang\",\"adm0name\":\"China\",\"adm1name\":\"Guizhou\",\"iso_a2\":\"CN\"},\"coordinates\":[796439,662201]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Chongqing\",\"adm0name\":\"China\",\"adm1name\":\"Chongqing\",\"iso_a2\":\"CN\"},\"coordinates\":[796091,679885]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Fuzhou\",\"adm0name\":\"China\",\"adm1name\":\"Fujian\",\"iso_a2\":\"CN\"},\"coordinates\":[831382,659239]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Guangzhou\",\"adm0name\":\"China\",\"adm1name\":\"Guangdong\",\"iso_a2\":\"CN\"},\"coordinates\":[814786,641850]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Dongguan\",\"adm0name\":\"China\",\"adm1name\":\"Guangdong\",\"iso_a2\":\"CN\"},\"coordinates\":[815951,641281]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Bandung\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Jawa Barat\",\"iso_a2\":\"ID\"},\"coordinates\":[798799,463554]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Surabaya\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Jawa Timur\",\"iso_a2\":\"ID\"},\"coordinates\":[813191,461781]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":7,\"name\":\"Guayaquil\",\"adm0name\":\"Ecuador\",\"adm1name\":\"Guayas\",\"iso_a2\":\"EC\"},\"coordinates\":[277994,491576]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Medellin\",\"adm0name\":\"Colombia\",\"adm1name\":\"Antioquia\",\"iso_a2\":\"CO\"},\"coordinates\":[290064,541905]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Cali\",\"adm0name\":\"Colombia\",\"adm1name\":\"Valle del Cauca\",\"iso_a2\":\"CO\"},\"coordinates\":[287494,524872]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Havana\",\"adm0name\":\"Cuba\",\"adm1name\":\"Ciudad de la Habana\",\"iso_a2\":\"CU\"},\"coordinates\":[271205,641773]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Alexandria\",\"adm0name\":\"Egypt\",\"adm1name\":\"Al Iskandariyah\",\"iso_a2\":\"EG\"},\"coordinates\":[583188,689572]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Frankfurt\",\"adm0name\":\"Germany\",\"adm1name\":\"Hessen\",\"iso_a2\":\"DE\"},\"coordinates\":[524097,801532]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Hamburg\",\"adm0name\":\"Germany\",\"adm1name\":\"Hamburg\",\"iso_a2\":\"DE\"},\"coordinates\":[527772,821983]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Munich\",\"adm0name\":\"Germany\",\"adm1name\":\"Bayern\",\"iso_a2\":\"DE\"},\"coordinates\":[532147,789872]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":7,\"name\":\"Prague\",\"adm0name\":\"Czech Republic\",\"adm1name\":\"Prague\",\"iso_a2\":\"CZ\"},\"coordinates\":[540177,801445]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"Kuwait\",\"adm0name\":\"Kuwait\",\"adm1name\":\"Al Kuwayt\",\"iso_a2\":\"KW\"},\"coordinates\":[633267,678728]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Xian\",\"adm0name\":\"China\",\"adm1name\":\"Shaanxi\",\"iso_a2\":\"CN\"},\"coordinates\":[802479,707789]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Taiyuan\",\"adm0name\":\"China\",\"adm1name\":\"Shanxi\",\"iso_a2\":\"CN\"},\"coordinates\":[812619,729117]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Wuhan\",\"adm0name\":\"China\",\"adm1name\":\"Hubei\",\"iso_a2\":\"CN\"},\"coordinates\":[817411,685898]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Changsha\",\"adm0name\":\"China\",\"adm1name\":\"Hunan\",\"iso_a2\":\"CN\"},\"coordinates\":[813800,671798]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Kunming\",\"adm0name\":\"China\",\"adm1name\":\"Yunnan\",\"iso_a2\":\"CN\"},\"coordinates\":[785216,653255]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Zhengzhou\",\"adm0name\":\"China\",\"adm1name\":\"Henan\",\"iso_a2\":\"CN\"},\"coordinates\":[815730,710633]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Shenyeng\",\"adm0name\":\"China\",\"adm1name\":\"Liaoning\",\"iso_a2\":\"CN\"},\"coordinates\":[842910,752400]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Jinan\",\"adm0name\":\"China\",\"adm1name\":\"Shandong\",\"iso_a2\":\"CN\"},\"coordinates\":[824980,722008]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Tianjin\",\"adm0name\":\"China\",\"adm1name\":\"Tianjin\",\"iso_a2\":\"CN\"},\"coordinates\":[825549,736553]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Nanchang\",\"adm0name\":\"China\",\"adm1name\":\"Jiangxi\",\"iso_a2\":\"CN\"},\"coordinates\":[821883,674642]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Nanjing\",\"adm0name\":\"China\",\"adm1name\":\"Jiangsu\",\"iso_a2\":\"CN\"},\"coordinates\":[829938,694608]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Hangzhou\",\"adm0name\":\"China\",\"adm1name\":\"Zhejiang\",\"iso_a2\":\"CN\"},\"coordinates\":[833799,683943]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Hiroshima\",\"adm0name\":\"Japan\",\"adm1name\":\"Hiroshima\",\"iso_a2\":\"JP\"},\"coordinates\":[867890,708458]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Changchun\",\"adm0name\":\"China\",\"adm1name\":\"Jilin\",\"iso_a2\":\"CN\"},\"coordinates\":[848161,764605]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Baotou\",\"adm0name\":\"China\",\"adm1name\":\"Nei Mongol\",\"iso_a2\":\"CN\"},\"coordinates\":[805055,745571]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Harbin\",\"adm0name\":\"China\",\"adm1name\":\"Heilongjiang\",\"iso_a2\":\"CN\"},\"coordinates\":[851800,775772]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Sapporo\",\"adm0name\":\"Japan\",\"adm1name\":\"Hokkaido\",\"iso_a2\":\"JP\"},\"coordinates\":[892605,759924]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"Santo Domingo\",\"adm0name\":\"Dominican Republic\",\"adm1name\":\"Distrito Nacional\",\"iso_a2\":\"DO\"},\"coordinates\":[305828,614153]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Accra\",\"adm0name\":\"Ghana\",\"adm1name\":\"Greater Accra\",\"iso_a2\":\"GH\"},\"coordinates\":[499392,537610]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Delhi\",\"adm0name\":\"India\",\"adm1name\":\"Delhi\",\"iso_a2\":\"IN\"},\"coordinates\":[714522,674583]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Hyderabad\",\"adm0name\":\"India\",\"adm1name\":\"Andhra Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[717993,607814]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Pune\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[705133,614509]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Nagpur\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[719688,630149]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":7,\"name\":\"Tripoli\",\"adm0name\":\"Libya\",\"adm1name\":\"Tajura' wa an Nawahi al Arba\",\"iso_a2\":\"LY\"},\"coordinates\":[536611,699587]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"Tel Aviv-Yafo\",\"adm0name\":\"Israel\",\"adm1name\":\"Tel Aviv\",\"iso_a2\":\"IL\"},\"coordinates\":[596577,694785]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":7,\"name\":\"Helsinki\",\"adm0name\":\"Finland\",\"adm1name\":\"Southern Finland\",\"iso_a2\":\"FI\"},\"coordinates\":[569256,861236]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Mashhad\",\"adm0name\":\"Iran\",\"adm1name\":\"Razavi Khorasan\",\"iso_a2\":\"IR\"},\"coordinates\":[665466,719608]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Jaipur\",\"adm0name\":\"India\",\"adm1name\":\"Rajasthan\",\"iso_a2\":\"IN\"},\"coordinates\":[710577,664222]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Kanpur\",\"adm0name\":\"India\",\"adm1name\":\"Uttar Pradesh\",\"iso_a2\":\"IN\"},\"coordinates\":[723105,661490]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Patna\",\"adm0name\":\"India\",\"adm1name\":\"Bihar\",\"iso_a2\":\"IN\"},\"coordinates\":[736466,656543]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Chennai\",\"adm0name\":\"India\",\"adm1name\":\"Tamil Nadu\",\"iso_a2\":\"IN\"},\"coordinates\":[722994,582279]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Ahmedabad\",\"adm0name\":\"India\",\"adm1name\":\"Dadra and Nagar Haveli\",\"iso_a2\":\"IN\"},\"coordinates\":[701605,641169]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Surat\",\"adm0name\":\"India\",\"adm1name\":\"Dadra and Nagar Haveli\",\"iso_a2\":\"IN\"},\"coordinates\":[702327,630327]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"København\",\"adm0name\":\"Denmark\",\"adm1name\":\"Hovedstaden\",\"iso_a2\":\"DK\"},\"coordinates\":[534893,834594]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"Abidjan\",\"adm0name\":\"Ivory Coast\",\"adm1name\":\"Lagunes\",\"iso_a2\":\"CI\"},\"coordinates\":[488772,536247]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Belem\",\"adm0name\":\"Brazil\",\"adm1name\":\"Pará\",\"iso_a2\":\"BR\"},\"coordinates\":[365327,496138]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Brasilia\",\"adm0name\":\"Brazil\",\"adm1name\":\"Distrito Federal\",\"iso_a2\":\"BR\"},\"coordinates\":[366894,411221]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Porto Alegre\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rio Grande do Sul\",\"iso_a2\":\"BR\"},\"coordinates\":[357772,326699]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Curitiba\",\"adm0name\":\"Brazil\",\"adm1name\":\"Paraná\",\"iso_a2\":\"BR\"},\"coordinates\":[362994,354129]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Fortaleza\",\"adm0name\":\"Brazil\",\"adm1name\":\"Ceará\",\"iso_a2\":\"BR\"},\"coordinates\":[392828,482512]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Salvador\",\"adm0name\":\"Brazil\",\"adm1name\":\"Bahia\",\"iso_a2\":\"BR\"},\"coordinates\":[393106,427888]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Edmonton\",\"adm0name\":\"Canada\",\"adm1name\":\"Alberta\",\"iso_a2\":\"CA\"},\"coordinates\":[184717,821983]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Montréal\",\"adm0name\":\"Canada\",\"adm1name\":\"Québec\",\"iso_a2\":\"CA\"},\"coordinates\":[295596,774292]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Goiania\",\"adm0name\":\"Brazil\",\"adm1name\":\"Goiás\",\"iso_a2\":\"BR\"},\"coordinates\":[363050,405672]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":1,\"name\":\"Recife\",\"adm0name\":\"Brazil\",\"adm1name\":\"Pernambuco\",\"iso_a2\":\"BR\"},\"coordinates\":[403006,456885]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":8,\"name\":\"Brussels\",\"adm0name\":\"Belgium\",\"adm1name\":\"Brussels\",\"iso_a2\":\"BE\"},\"coordinates\":[512031,805888]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Dhaka\",\"adm0name\":\"Bangladesh\",\"adm1name\":\"Dhaka\",\"iso_a2\":\"BD\"},\"coordinates\":[751129,645275]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":6,\"name\":\"Luanda\",\"adm0name\":\"Angola\",\"adm1name\":\"Luanda\",\"iso_a2\":\"AO\"},\"coordinates\":[536756,452367]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Algiers\",\"adm0name\":\"Algeria\",\"adm1name\":\"Alger\",\"iso_a2\":\"DZ\"},\"coordinates\":[508468,722530]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":2,\"name\":\"Chittagong\",\"adm0name\":\"Bangladesh\",\"adm1name\":\"Chittagong\",\"iso_a2\":\"BD\"},\"coordinates\":[754993,637022]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":3,\"name\":\"Perth\",\"adm0name\":\"Australia\",\"adm1name\":\"Western Australia\",\"iso_a2\":\"AU\"},\"coordinates\":[821772,315413]},{\"type\":\"Point\",\"properties\":{\"scalerank\":2,\"labelrank\":5,\"name\":\"Rangoon\",\"adm0name\":\"Myanmar\",\"adm1name\":\"Yangon\",\"iso_a2\":\"MM\"},\"coordinates\":[767123,604161]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"San Francisco\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[159952,728479]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Denver\",\"adm0name\":\"United States of America\",\"adm1name\":\"Colorado\",\"iso_a2\":\"US\"},\"coordinates\":[208372,740162]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Houston\",\"adm0name\":\"United States of America\",\"adm1name\":\"Texas\",\"iso_a2\":\"US\"},\"coordinates\":[235161,681396]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Miami\",\"adm0name\":\"United States of America\",\"adm1name\":\"Florida\",\"iso_a2\":\"US\"},\"coordinates\":[277150,657506]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Atlanta\",\"adm0name\":\"United States of America\",\"adm1name\":\"Georgia\",\"iso_a2\":\"US\"},\"coordinates\":[265550,705153]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Chicago\",\"adm0name\":\"United States of America\",\"adm1name\":\"Illinois\",\"iso_a2\":\"US\"},\"coordinates\":[256244,752549]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":6,\"name\":\"Caracas\",\"adm0name\":\"Venezuela\",\"adm1name\":\"Distrito Capital\",\"iso_a2\":\"VE\"},\"coordinates\":[314114,566941]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Kiev\",\"adm0name\":\"Ukraine\",\"adm1name\":\"Kiev\",\"iso_a2\":\"UA\"},\"coordinates\":[584762,803519]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":8,\"name\":\"Dubai\",\"adm0name\":\"United Arab Emirates\",\"adm1name\":\"Dubay\",\"iso_a2\":\"AE\"},\"coordinates\":[653549,654203]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":6,\"name\":\"Tashkent\",\"adm0name\":\"Uzbekistan\",\"adm1name\":\"Tashkent\",\"iso_a2\":\"UZ\"},\"coordinates\":[692480,749478]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Madrid\",\"adm0name\":\"Spain\",\"adm1name\":\"Comunidad de Madrid\",\"iso_a2\":\"ES\"},\"coordinates\":[489762,744077]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":7,\"name\":\"Geneva\",\"adm0name\":\"Switzerland\",\"adm1name\":\"Genève\",\"iso_a2\":\"CH\"},\"coordinates\":[517055,778486]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":7,\"name\":\"Stockholm\",\"adm0name\":\"Sweden\",\"adm1name\":\"Stockholm\",\"iso_a2\":\"SE\"},\"coordinates\":[550264,856349]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Bangkok\",\"adm0name\":\"Thailand\",\"adm1name\":\"Bangkok Metropolis\",\"iso_a2\":\"TH\"},\"coordinates\":[779207,586190]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Lima\",\"adm0name\":\"Peru\",\"adm1name\":\"Lima\",\"iso_a2\":\"PE\"},\"coordinates\":[285967,433351]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":8,\"name\":\"Dakar\",\"adm0name\":\"Senegal\",\"adm1name\":\"Dakar\",\"iso_a2\":\"SM\"},\"coordinates\":[451458,591912]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Johannesburg\",\"adm0name\":\"South Africa\",\"adm1name\":\"Gauteng\",\"iso_a2\":\"ZA\"},\"coordinates\":[577855,349685]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":8,\"name\":\"Amsterdam\",\"adm0name\":\"Netherlands\",\"adm1name\":\"Noord-Holland\",\"iso_a2\":\"NL\"},\"coordinates\":[513651,814873]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Casablanca\",\"adm0name\":\"Morocco\",\"adm1name\":\"Grand Casablanca\",\"iso_a2\":\"MA\"},\"coordinates\":[478837,703790]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Seoul\",\"adm0name\":\"South Korea\",\"adm1name\":\"Seoul\",\"iso_a2\":\"KR\"},\"coordinates\":[852771,727288]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Manila\",\"adm0name\":\"Philippines\",\"adm1name\":\"Metropolitan Manila\",\"iso_a2\":\"PH\"},\"coordinates\":[836056,591250]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":2,\"name\":\"Monterrey\",\"adm0name\":\"Mexico\",\"adm1name\":\"Nuevo León\",\"iso_a2\":\"MX\"},\"coordinates\":[221300,656809]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":8,\"name\":\"Auckland\",\"adm0name\":\"New Zealand\",\"adm1name\":\"Auckland\",\"iso_a2\":\"NZ\"},\"coordinates\":[985452,286413]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Berlin\",\"adm0name\":\"Germany\",\"adm1name\":\"Berlin\",\"iso_a2\":\"DE\"},\"coordinates\":[537221,815891]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Urumqi\",\"adm0name\":\"China\",\"adm1name\":\"Xinjiang Uygur\",\"iso_a2\":\"CN\"},\"coordinates\":[743258,764249]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Chengdu\",\"adm0name\":\"China\",\"adm1name\":\"Sichuan\",\"iso_a2\":\"CN\"},\"coordinates\":[789078,686432]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":2,\"name\":\"Osaka\",\"adm0name\":\"Japan\",\"adm1name\":\"Osaka\",\"iso_a2\":\"JP\"},\"coordinates\":[876272,710604]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Kinshasa\",\"adm0name\":\"Congo (Kinshasa)\",\"adm1name\":\"Kinshasa City\",\"iso_a2\":\"CD\"},\"coordinates\":[542536,479077]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"New Delhi\",\"adm0name\":\"India\",\"adm1name\":\"Delhi\",\"iso_a2\":\"IN\"},\"coordinates\":[714444,674156]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":1,\"name\":\"Bangalore\",\"adm0name\":\"India\",\"adm1name\":\"Karnataka\",\"iso_a2\":\"IN\"},\"coordinates\":[715438,581569]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":6,\"name\":\"Athens\",\"adm0name\":\"Greece\",\"adm1name\":\"Attiki\",\"iso_a2\":\"GR\"},\"coordinates\":[565920,729759]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Baghdad\",\"adm0name\":\"Iraq\",\"adm1name\":\"Baghdad\",\"iso_a2\":\"IQ\"},\"coordinates\":[623310,702242]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Addis Ababa\",\"adm0name\":\"Ethiopia\",\"adm1name\":\"Addis Ababa\",\"iso_a2\":\"ET\"},\"coordinates\":[607494,558246]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Tehran\",\"adm0name\":\"Iran\",\"adm1name\":\"Tehran\",\"iso_a2\":\"IR\"},\"coordinates\":[642839,716065]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":2,\"name\":\"Vancouver\",\"adm0name\":\"Canada\",\"adm1name\":\"British Columbia\",\"iso_a2\":\"CA\"},\"coordinates\":[157990,796647]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":2,\"name\":\"Toronto\",\"adm0name\":\"Canada\",\"adm1name\":\"Ontario\",\"iso_a2\":\"CA\"},\"coordinates\":[279383,763627]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Buenos Aires\",\"adm0name\":\"Argentina\",\"adm1name\":\"Ciudad de Buenos Aires\",\"iso_a2\":\"AR\"},\"coordinates\":[337779,299727]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":5,\"name\":\"Kabul\",\"adm0name\":\"Afghanistan\",\"adm1name\":\"Kabul\",\"iso_a2\":\"AF\"},\"coordinates\":[692169,709221]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":7,\"name\":\"Vienna\",\"adm0name\":\"Austria\",\"adm1name\":\"Wien\",\"iso_a2\":\"AT\"},\"coordinates\":[545457,790287]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":3,\"name\":\"Melbourne\",\"adm0name\":\"Australia\",\"adm1name\":\"Victoria\",\"iso_a2\":\"AU\"},\"coordinates\":[902702,280666]},{\"type\":\"Point\",\"properties\":{\"scalerank\":1,\"labelrank\":8,\"name\":\"Taipei\",\"adm0name\":\"Taiwan\",\"adm1name\":\"Taipei City\",\"iso_a2\":\"TW\"},\"coordinates\":[837688,653040]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Los Angeles\",\"adm0name\":\"United States of America\",\"adm1name\":\"California\",\"iso_a2\":\"US\"},\"coordinates\":[171717,706100]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Washington, D.C.\",\"adm0name\":\"United States of America\",\"adm1name\":\"District of Columbia\",\"iso_a2\":\"US\"},\"coordinates\":[286079,735187]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"New York\",\"adm0name\":\"United States of America\",\"adm1name\":\"New York\",\"iso_a2\":\"US\"},\"coordinates\":[294495,746150]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":5,\"name\":\"London\",\"adm0name\":\"United Kingdom\",\"adm1name\":\"Westminster\",\"iso_a2\":\"GB\"},\"coordinates\":[499670,809838]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":5,\"name\":\"Istanbul\",\"adm0name\":\"Turkey\",\"adm1name\":\"Istanbul\",\"iso_a2\":\"TR\"},\"coordinates\":[580577,748253]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":5,\"name\":\"Riyadh\",\"adm0name\":\"Saudi Arabia\",\"adm1name\":\"Ar Riyad\",\"iso_a2\":\"SA\"},\"coordinates\":[629918,650712]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":3,\"name\":\"Cape Town\",\"adm0name\":\"South Africa\",\"adm1name\":\"Western Cape\",\"iso_a2\":\"ZA\"},\"coordinates\":[551202,303771]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":2,\"name\":\"Moscow\",\"adm0name\":\"Russia\",\"adm1name\":\"Moskva\",\"iso_a2\":\"RU\"},\"coordinates\":[604482,835030]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":2,\"name\":\"Mexico City\",\"adm0name\":\"Mexico\",\"adm1name\":\"Distrito Federal\",\"iso_a2\":\"MX\"},\"coordinates\":[224631,619915]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":2,\"name\":\"Lagos\",\"adm0name\":\"Nigeria\",\"adm1name\":\"Lagos\",\"iso_a2\":\"NG\"},\"coordinates\":[509415,542902]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":3,\"name\":\"Rome\",\"adm0name\":\"Italy\",\"adm1name\":\"Lazio\",\"iso_a2\":\"IT\"},\"coordinates\":[534670,752939]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Beijing\",\"adm0name\":\"China\",\"adm1name\":\"Beijing\",\"iso_a2\":\"CN\"},\"coordinates\":[823294,741286]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":5,\"name\":\"Nairobi\",\"adm0name\":\"Kenya\",\"adm1name\":\"Nairobi\",\"iso_a2\":\"KE\"},\"coordinates\":[602262,497125]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Jakarta\",\"adm0name\":\"Indonesia\",\"adm1name\":\"Jakarta Raya\",\"iso_a2\":\"ID\"},\"coordinates\":[796742,468148]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":5,\"name\":\"Bogota\",\"adm0name\":\"Colombia\",\"adm1name\":\"Bogota\",\"iso_a2\":\"CO\"},\"coordinates\":[294207,531960]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":3,\"name\":\"Cairo\",\"adm0name\":\"Egypt\",\"adm1name\":\"Al Qahirah\",\"iso_a2\":\"EG\"},\"coordinates\":[586799,682758]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Shanghai\",\"adm0name\":\"China\",\"adm1name\":\"Shanghai\",\"iso_a2\":\"CN\"},\"coordinates\":[837317,689669]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":2,\"name\":\"Tokyo\",\"adm0name\":\"Japan\",\"adm1name\":\"Tokyo\",\"iso_a2\":\"JP\"},\"coordinates\":[888192,716142]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Mumbai\",\"adm0name\":\"India\",\"adm1name\":\"Maharashtra\",\"iso_a2\":\"IN\"},\"coordinates\":[702374,617394]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":3,\"name\":\"Paris\",\"adm0name\":\"France\",\"adm1name\":\"Île-de-France\",\"iso_a2\":\"FR\"},\"coordinates\":[506476,794237]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":3,\"name\":\"Santiago\",\"adm0name\":\"Chile\",\"adm1name\":\"Región Metropolitana de Santiago\",\"iso_a2\":\"CL\"},\"coordinates\":[303697,306556]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Kolkata\",\"adm0name\":\"India\",\"adm1name\":\"West Bengal\",\"iso_a2\":\"IN\"},\"coordinates\":[745340,637999]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Rio de Janeiro\",\"adm0name\":\"Brazil\",\"adm1name\":\"Rio de Janeiro\",\"iso_a2\":\"BR\"},\"coordinates\":[379925,368910]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":1,\"name\":\"Sao Paulo\",\"adm0name\":\"Brazil\",\"adm1name\":\"São Paulo\",\"iso_a2\":\"BR\"},\"coordinates\":[370480,365156]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":3,\"name\":\"Sydney\",\"adm0name\":\"Australia\",\"adm1name\":\"New South Wales\",\"iso_a2\":\"AU\"},\"coordinates\":[919952,303771]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":0,\"name\":\"Singapore\",\"adm0name\":\"Singapore\",\"iso_a2\":\"SG\"},\"coordinates\":[788482,512389]},{\"type\":\"Point\",\"properties\":{\"scalerank\":0,\"labelrank\":0,\"name\":\"Hong Kong\",\"adm0name\":\"Hong Kong S.A.R.\",\"iso_a2\":\"HK\"},\"coordinates\":[817174,636873]}]}},\"arcs\":[[[85470,47819],[-4327,823],[2549,633],[1778,-1456]],[[135926,62848],[-3045,936],[3281,69],[-236,-1005]],[[54258,21344],[-9164,857],[3638,778],[5526,-1635]],[[965673,41772],[-3773,-978],[-481,1285],[4254,-307]],[[964121,46628],[6302,-1202],[-5445,-735],[-1844,-1198],[-1422,1933],[2409,1202]],[[405738,34787],[-7075,156],[2628,1209],[4447,-1365]],[[313161,34004],[-3575,90],[1434,1245],[2141,-1335]],[[334072,28722],[-2358,-3579],[-10237,1183],[-4755,2157],[12074,239],[-141,1922],[5030,1437],[387,-3359]],[[316184,30299],[-4542,3151],[4985,-464],[1416,-1955],[-1859,-732]],[[58185,31902],[-3469,-220],[-10900,3103],[279,1928],[2416,1619],[4480,-1060],[5441,-2972],[1753,-2398]],[[374381,37806],[4168,-45],[2102,-3902],[-1562,-4233],[-15721,-2674],[-1627,-838],[-12193,-508],[-513,1781],[2648,2728],[3047,-191],[5438,3920],[-1094,1165],[1427,4014],[3162,3306],[6265,1552],[3599,-570],[4781,-2400],[-384,-1842],[-3543,-1263]],[[304627,32657],[-4026,1396],[3443,3321],[8515,3087],[2085,-125],[-7008,-4897],[-3009,-2782]],[[146206,62619],[-2132,1749],[2510,-580],[-378,-1169]],[[149084,70536],[2927,-2396],[3427,-1125],[571,-2044],[-2879,102],[-6552,2931],[-99,2426],[2605,106]],[[442757,66979],[329,-3590],[-2221,2981],[1967,2192],[-75,-1583]],[[165121,67753],[789,-1381],[-2196,-2064],[-4990,-31],[652,2234],[-1354,1679],[7099,-437]],[[175726,65330],[-1773,486],[2764,1288],[-991,-1774]],[[167919,65653],[-704,1752],[2341,30],[-1637,-1782]],[[227524,78675],[1407,176],[346,-1810],[1641,1998],[2068,-264],[-1873,-2157],[3305,1133],[94,-2024],[-1323,-990],[-6544,175],[-4965,1629],[-5749,813],[380,889],[5676,880],[698,-1240],[3382,1673],[1457,-881]],[[293460,71648],[-612,-3038],[-3684,1650],[-324,1466],[1780,1570],[2508,-435],[332,-1213]],[[246776,71151],[-1415,3309],[2396,79],[-981,-3388]],[[492964,85456],[1224,-315],[-1920,-2052],[-2094,2867],[2790,-500]],[[295259,86241],[-1384,-1711],[-5476,-1234],[-900,1132],[5678,2100],[2082,-287]],[[331597,134082],[2154,-324],[-1032,-773],[-1122,1097]],[[346762,142020],[-615,875],[1989,-263],[-1374,-612]],[[338949,137923],[941,-643],[-3790,-1122],[890,1194],[1959,571]],[[396935,184408],[2158,-1100],[1466,-3035],[-797,-612],[-1169,2107],[-2754,2105],[1096,535]],[[301693,184601],[1024,-467],[-337,-1554],[-917,846],[-1320,-412],[-728,1500],[594,965],[1684,-878]],[[302801,179654],[1594,-243],[38,-1520],[-1488,614],[-144,1149]],[[306380,179352],[2229,-586],[1717,-1406],[651,-2298],[-3469,2828],[-319,-1650],[-1578,1759],[769,1353]],[[313667,177961],[-2751,-400],[-642,1425],[2933,19],[460,-1044]],[[320696,180552],[2039,-51],[-2284,-1052],[245,1103]],[[341609,129267],[-3451,-2313],[-2179,-2791],[726,-1717],[-1874,1058],[-1395,-508],[-3047,-3257],[-1787,-37],[349,-1175],[-1577,-865],[1081,-1407],[-1525,-1607],[1294,-1653],[2573,1177],[965,-347],[-1286,-2116],[-1121,1137],[-1232,-897],[-2240,348],[-63,-2623],[-1536,2467],[-1375,-83],[-903,-2230],[897,-1298],[-2587,397],[-947,-2416],[-1156,-666],[-545,-4764],[2065,-225],[-1544,-998],[584,-1459],[3231,-1115],[783,1786],[946,-3389],[2793,-3213],[1360,-3174],[-1158,-1450],[2425,-745],[-1267,-2429],[1800,194],[457,-2810],[-2251,-1870],[2070,555],[496,-1517],[-3393,-1171],[4270,-326],[-31,-2093],[1690,-5031],[-2665,-315],[-2575,1070],[1032,-2087],[2106,-663],[-67,-1532],[-2598,-957],[2929,-1237],[-631,-1407],[-3401,220],[853,-2498],[-2168,746],[-3378,-1584],[1927,-885],[-2913,-825],[2545,-940],[-8353,-3329],[-8150,-1998],[-2197,-1800],[-4731,-581],[-9638,1015],[-5338,-287],[2615,-3822],[2394,-1180],[7041,-689],[-1110,-1801],[-4335,-1679],[-8139,1406],[-7943,1116],[-2331,-791],[11134,-3252],[-1212,-1842],[-6731,-459],[-6434,2433],[-3207,-290],[1397,-1855],[4442,-1929],[2136,-2381],[1120,1072],[11082,-29],[1299,-1786],[-1462,-1638],[-8618,-553],[4123,-1006],[4913,426],[3252,-4193],[6131,-680],[5588,1767],[2163,-1407],[15247,-3939],[-3239,-2255],[2769,-2775],[11279,1090],[-5213,-2019],[4265,-3381],[-1082,-1441],[5760,-694],[6007,3662],[9354,3791],[15626,1826],[5841,-325],[229,-3344],[6962,1430],[6210,5761],[7394,2462],[4340,-1077],[5229,2449],[16661,2835],[14135,653],[-165,1725],[-15693,1016],[-1018,2583],[-7440,-388],[-9014,2692],[162,1813],[3037,3740],[2810,2439],[5591,1573],[8693,4678],[7985,2447],[4971,1126],[7877,497],[2629,1133],[6063,360],[-1235,1121],[4029,5380],[4517,-435],[3053,2783],[-3264,-47],[-2139,1786],[2563,3243],[3542,-156],[65,2310],[3025,-308],[4754,2204],[1497,3028],[-3305,1707],[-565,1328],[1912,346],[1926,-1356],[2601,2544],[-182,1210],[2412,-1467],[1623,-2955],[2591,748],[-445,3592],[5382,1348],[968,-853],[-1472,-2780],[9182,30],[2215,-667],[2630,994],[1458,-2647],[3828,3022],[4929,1792],[6954,1448],[6356,954],[766,818],[2351,-695],[1718,1719],[5727,-3230],[1383,-224],[3790,4224],[2103,-1715],[5512,114],[2161,712],[345,-1147],[3932,-847],[855,1483],[2122,-19],[191,-3609],[5015,349],[1762,3465],[1836,-1282],[-367,-993],[2070,-993],[2291,2403],[1200,-261],[1447,-2627],[4839,-755],[6702,2586],[3033,1676],[3821,440],[3451,1334],[1023,2230],[-1172,3259],[1539,2280],[2976,-77],[-1054,-2352],[2173,28],[2114,-3476],[3783,173],[1100,-939],[2860,-80],[1986,-1077],[2349,3438],[441,2716],[3525,2323],[3545,1323],[1141,1354],[5222,1297],[805,800],[3916,899],[446,2070],[2342,-835],[-794,-970],[4253,-1312],[-49,1621],[1636,1741],[-2095,1085],[2172,605],[3627,-1499],[-612,4443],[4311,2516],[4965,954],[3544,-340],[2118,-970],[4098,-3159],[-2888,-76],[682,-2060],[-657,-1724],[2047,1235],[2044,250],[3083,-1276],[1426,-1514],[3420,591],[6127,-1555],[2809,826],[12858,-2259],[3024,869],[1571,-4273],[-1244,-1616],[265,-2930],[-2009,-838],[489,-2924],[-2512,172],[-2528,-2582],[1869,-887],[3000,580],[637,-627],[-1048,-3579],[-2321,-2110],[-1681,-3625],[-2397,-7146],[2091,-539],[1804,1271],[1245,3381],[3153,833],[4783,4447],[1745,5434],[2376,1842],[172,1775],[3111,2091],[4116,-889],[1298,1881],[5351,3002],[2524,4686],[1560,940],[7581,2544],[3576,515],[3280,2894],[3405,-277],[6304,2209],[4773,-206],[3675,1306],[2922,562],[5252,-1077],[2432,1115],[1948,-767],[4332,778],[1719,-638],[1495,828],[1670,-1205],[5640,1853],[1626,2411],[3332,509],[3547,-728],[6766,-2503],[2178,-355],[1706,-1146],[4661,-1449],[3220,2279],[790,2650],[6090,1640],[1697,-769],[1742,-2551],[2704,-1189],[902,-1247],[-1004,-1521],[-3563,-1089],[99,-1358],[7463,2333],[6254,-577],[3917,954],[-3040,-1277],[-410,-1015],[6541,1657],[1931,1371],[5592,1533],[2498,-239],[2139,1638],[2221,-789],[2433,-3279],[2472,-402],[2240,459],[1400,3394],[3363,1643],[2442,-264],[4482,916],[2040,-1159],[307,-1183],[2951,2071],[3338,-1847],[933,588],[3474,-1210],[3060,-179],[1829,-837],[5758,-542],[1985,-1221],[2897,807],[502,-1269],[1973,-300],[-1887,-3867],[686,-625],[2608,1622],[2354,11],[2368,-2017],[738,-2395],[3786,-581],[7255,486],[195,-2248],[3909,205],[1488,-753],[1732,758],[222,2246],[1153,-404],[3668,-3594],[5447,-1684],[1254,758],[5142,-2021],[1183,-2684],[2298,-2028],[1076,-3019],[2395,-842],[-686,2039],[1765,1897],[1872,-1873],[2929,653],[6177,-911],[2618,-864],[1674,-2210],[5528,-2650],[759,1254],[1177,-2665],[-1764,-470],[-490,-3867],[-3692,1281],[3083,-2039],[-788,-1906],[-6637,-574],[1278,-1122],[-1721,-1230],[-3155,-287],[-1426,-1698],[-604,2942],[-1055,-1043],[72,-2782],[1465,-3349],[-4355,178],[-1305,813],[-1837,-2351],[-196,-2037],[-4508,-993],[2758,-413],[2533,-2617],[-146,-5329],[2379,-4958],[2227,-1783],[-1232,-2017],[1807,-543],[2192,1620],[683,-1562],[3875,-1260],[-6732,-503],[-5542,-1744],[-2450,2089],[539,-2873],[-2113,303],[-3595,-5214],[1840,-898],[-5515,-2446],[5469,-9],[-201,-5425],[6531,-3114],[2386,-1902],[-6658,-1793],[9622,802],[10723,-4212],[-1382,-1756],[7520,-437],[3056,-1235],[21397,-3698],[-975899,-1624],[13312,-1639],[11050,-486],[17983,-1689],[-1464,2223],[-18283,1673],[-3840,4281],[-7229,-28],[-4485,2139],[-13607,3256],[6236,312],[9455,-2260],[6113,167],[4921,-1581],[13891,-447],[5600,1164],[-697,1285],[6167,882],[6804,3147],[-4743,3015],[2114,1425],[-8545,2257],[1401,929],[23349,1550],[-6814,3241],[986,1206],[5287,469],[391,1749],[-6429,1364],[-4446,1801],[-8662,1639],[-3498,1952],[6044,2229],[-8259,352],[-3428,2496],[798,3681],[5561,304],[6393,-717],[1248,-1120],[4837,-59],[5559,-2202],[4339,1985],[-1156,2117],[8042,-2268],[-205,4378],[-4416,1840],[-3502,-326],[-2925,758],[3706,1547],[6763,-1896],[-1382,1923],[7801,3176],[3457,432],[4044,-1512],[-969,1186],[4255,1972],[5758,814],[2970,-378],[892,1797],[2406,863],[5241,-957],[3961,511],[6273,-746],[5355,1020],[6971,29],[4067,-346],[11702,700],[2836,1553],[9862,-371],[874,2764],[3562,-593],[-1672,-5291],[6706,1123],[-305,3096],[1738,484],[2426,-1059],[19,-2037],[-3230,-2505],[6086,-305],[7369,-943],[4771,1357],[8870,-72],[1859,-1745],[6893,1374],[-5321,1880],[986,2118],[-3148,174],[-1288,2736],[-2921,829],[990,1585],[3959,-834],[5803,865],[-3124,1236],[-7374,484],[-1943,2973],[2810,349],[-127,-1346],[12213,-273],[5167,-1634],[2544,527],[2751,-550],[5570,797],[3667,-834],[1737,2023],[2651,523],[594,1164],[2591,-981],[-625,-2195],[2829,220],[1008,-959],[3435,959],[2279,-1836],[7771,-2103],[2430,703],[129,2508],[2572,-588],[-294,2783],[2557,-861],[3094,-2761],[4326,565],[-551,-2273],[4877,1217],[3603,-362],[2964,1491],[11411,2029],[3206,1606],[2331,4409],[-1757,3338],[-123,2779],[-1066,3768],[-1431,2382],[-846,3480],[3712,118],[1102,1489],[-1154,1777],[1659,3678],[-991,1278],[1236,2948],[-2172,-119],[-18,2574],[1495,758],[1342,-1529],[-152,2974],[1887,538],[639,3049],[5054,3881],[-667,1785],[772,862],[1948,-628],[-169,1166],[4133,2002],[2133,3147],[3761,1497],[1772,1593],[4118,1929],[1025,-868]],[[291702,91617],[1526,-1313],[-1142,-1361],[-2438,493],[126,1270],[1928,911]],[[574603,87746],[-2366,49],[821,1781],[1545,-1830]],[[305413,94809],[1762,-2334],[3003,-7541],[263,-5724],[-2689,-4219],[-3706,-771],[-5067,-32],[-1997,1551],[1300,788],[4849,-542],[-2847,1455],[2991,1270],[-3995,1571],[-1857,-1661],[-1959,514],[-1008,-1985],[-3770,1728],[168,1561],[2502,-139],[568,1513],[5488,284],[-2358,1232],[3728,-107],[1456,949],[3788,421],[-3386,898],[-32,1334],[2036,1042],[1971,-218],[-1970,1411],[-2202,-217],[-2037,1346],[308,3237],[-875,2499],[4558,1257],[1016,-2371]],[[545062,89959],[-1454,1389],[2573,136],[-1119,-1525]],[[300040,91791],[-2198,317],[141,1374],[2057,-1691]],[[327784,91653],[-1583,3208],[2088,-1160],[-505,-2048]],[[311143,104968],[-2536,-1599],[-503,2021],[2074,3560],[1404,1054],[-383,-2416],[779,-682],[-835,-1938]],[[780503,115614],[-1975,438],[1703,1334],[272,-1772]],[[324498,122769],[956,-605],[-2508,-1556],[-1480,811],[2185,2590],[847,-1240]],[[326873,123038],[-1170,-280],[1161,2714],[751,-739],[-742,-1695]],[[339316,125233],[1657,-257],[-125,-1598],[-1602,-201],[-1462,1576],[1311,1947],[221,-1467]],[[345755,130448],[-2362,-1562],[-19,1204],[2381,358]],[[10618,245580],[-434,-1826],[-1428,1329],[1862,497]],[[23739,421499],[-1273,266],[-371,856],[1226,-132],[418,-990]],[[21295,424942],[302,-2008],[-863,75],[-674,1628],[1235,305]],[[330522,564757],[-2484,-386],[1130,1182],[96,1602],[-474,950],[1994,835],[-322,-1010],[60,-3173]],[[849139,563455],[-543,1210],[478,1904],[65,-3114]],[[789066,566277],[-128,-2142],[-468,2025],[596,117]],[[322640,570662],[-189,-1442],[-1347,557],[1536,885]],[[756952,567249],[-417,1163],[437,867],[-20,-2030]],[[846040,571919],[987,176],[231,-3479],[667,-3091],[-738,614],[108,-1981],[-683,799],[17,3634],[-948,842],[-319,3624],[678,-1138]],[[840266,573530],[1840,-471],[-394,-2483],[-685,-1734],[-1590,-1190],[-581,-975],[-68,2449],[388,4569],[-389,1507],[1479,-1672]],[[847887,578938],[822,-1994],[-83,-3834],[551,-2248],[-1307,-116],[-879,2448],[-91,1286],[-1388,2776],[-251,1928],[2626,-246]],[[273324,548160],[-691,714],[342,994],[349,-1708]],[[465204,548773],[-1181,797],[934,393],[247,-1190]],[[825863,554717],[108,1623],[1486,3123],[639,628],[2525,5965],[731,1306],[-72,1607],[667,2969],[71,-2329],[438,-2379],[-1110,-1777],[-260,-1130],[-1136,-858],[-965,-3911],[-1237,-2245],[-1885,-2592]],[[846093,562701],[-650,-930],[-1178,-37],[-329,1146],[988,1883],[1123,-643],[46,-1419]],[[842029,558417],[-1578,2481],[-421,1250],[167,1586],[1068,743],[-108,2469],[462,2268],[760,636],[863,-1263],[-1126,-5430],[406,-3005],[-493,-1735]],[[842694,560701],[45,3066],[903,3001],[909,4739],[35,-4076],[-275,-1594],[-858,-1756],[-759,-3380]],[[65314,628731],[1381,-1039]],[[66695,627692],[-1247,-825],[-134,1864]],[[63295,630407],[1393,-358]],[[64688,630049],[-410,-585]],[[64278,629464],[-983,943]],[[297147,630270],[-382,-1263],[-1379,-247],[383,1501],[1378,9]],[[61668,631836],[456,-883]],[[62124,630953],[-1320,65]],[[60804,631018],[-453,1580]],[[60351,632598],[863,688]],[[61214,633286],[454,-1450]],[[67829,617353],[-833,346],[-465,4026],[635,1565]],[[67166,623290],[-33,1550]],[[67133,624840],[1759,-1667],[1095,-2784]],[[69987,620389],[-1404,-1566]],[[68583,618823],[-754,-1470]],[[663116,624502],[-224,703],[675,2033],[185,-974],[-636,-1762]],[[833610,576804],[595,-920],[-843,-25],[248,945]],[[329773,595059],[-554,1636],[447,355],[107,-1991]],[[434877,593631],[-948,408],[71,1386],[877,-1794]],[[328918,599549],[-472,327],[31,1737],[544,-500],[-103,-1564]],[[436338,600914],[626,-404],[-355,-1084],[-271,1488]],[[329646,600873],[-541,-14],[141,1651],[400,-1637]],[[430083,605116],[-464,856],[993,22],[-529,-878]],[[433089,603196],[-652,-766],[-151,1094],[803,-328]],[[331038,590589],[-1093,1836],[836,-409],[257,-1427]],[[902059,583271],[-257,1004],[809,839],[-552,-1843]],[[843655,577513],[901,-1899],[14,-1270],[-1429,2631],[-1037,-1605],[218,3897],[1333,-1754]],[[839149,577913],[-474,-140],[616,1904],[-142,-1764]],[[649342,579583],[1178,161],[899,-659],[-1060,-1138],[-1475,-109],[-785,1131],[609,1082],[634,-468]],[[757562,573062],[-524,1998],[447,2022],[451,6775],[570,1110],[32,-1738],[-521,-1836],[288,-2392],[-743,-5939]],[[835289,584576],[1384,-280],[889,-1784],[50,-2921],[-845,-2484],[-874,1735],[-439,2714],[-1007,3242],[842,-222]],[[838651,584936],[555,-457],[-304,-1530],[-488,733],[237,1254]],[[845425,585481],[-874,183],[517,2455],[534,-1224],[-177,-1414]],[[836392,615002],[2067,-1895],[836,1133],[426,-497],[-414,-3828],[328,-2141],[695,-1602],[-1067,-5569],[-1499,-1490],[32,-1561],[-596,-2046],[842,-3478],[-130,-1516],[422,-2178],[1142,-1088],[-33,1291],[808,1032],[1015,-424],[1043,-2982],[247,1862],[1492,-1553],[-855,-911],[748,-2230],[-95,-941],[994,-443],[-230,-2777],[-507,727],[198,1343],[-1771,756],[-411,2356],[-1578,2760],[-353,-124],[575,-3753],[-1673,3171],[-819,884],[-1595,-1762],[-1008,1448],[-567,-475],[-55,2272],[847,1808],[-94,1319],[-846,980],[15,-2358],[-417,-177],[-991,2357],[-529,5845],[-340,1011],[170,1885],[915,-1652],[638,1030],[-234,1823],[287,2526],[-139,4044],[669,5152],[1395,636]],[[285385,614067],[2532,-1810],[386,-1412],[-872,-280],[-912,637],[-978,-1534],[-1564,963],[-848,1859],[-613,159],[215,1363],[954,439],[1700,-384]],[[300613,621536],[615,1050],[1677,110],[2291,-1646],[479,212],[604,-2208],[1151,169],[-829,-1243],[2608,-1262],[960,-1738],[-1061,-2329],[-594,1123],[-2322,211],[-1145,-1136],[-1283,500],[-1064,-373],[-1022,-3715],[-1035,2328]],[[300643,611589],[-810,1122],[-2268,-455],[-1413,589],[-1388,-1240],[-1484,1803],[532,1875],[1767,-831],[2228,-519],[1227,1423],[-1287,2350],[299,2189],[-1925,1289],[774,1452],[1335,-17],[1159,-926],[1224,-157]],[[316307,613993],[1390,-376],[23,-824],[-973,-1588],[-3405,118],[106,2992],[2859,-322]],[[808024,623158],[347,-1993],[-533,-578],[-694,-2287],[-336,-2512],[-2588,-3138],[-2272,1878],[-183,2207],[161,2551],[1619,2505],[107,849],[3787,1378],[585,-860]],[[782522,517031],[-293,-2149],[-423,2086],[716,63]],[[856816,516873],[-656,1455],[1067,1778],[59,-2210],[-470,-1023]],[[767954,518699],[-1820,1751],[-7,1543],[1698,-2375],[129,-919]],[[852267,528613],[-164,3048],[455,-1522],[-291,-1526]],[[524265,526983],[585,-775],[-673,-2393],[-637,243],[725,2925]],[[800877,526576],[-599,88],[-269,2003],[551,936],[531,-1270],[-214,-1757]],[[722171,562852],[753,-97],[1273,-2547],[1838,-5539],[175,-1852],[1217,-4921],[-35,-2293],[-622,-2820],[-715,-1092],[-1822,-1551],[-1270,182],[-477,849],[-655,4006],[-421,7325],[280,-93],[712,6195],[58,2856],[-289,1392]],[[839146,542801],[-790,1099],[694,752],[638,-603],[-542,-1248]],[[836553,540712],[645,-436],[-1280,-627],[635,1063]],[[760805,545187],[-572,2089],[486,138],[86,-2227]],[[850016,559939],[520,-263],[351,-2559],[-495,-1288],[621,-850],[195,-3857],[375,-921],[32,-2545],[-1083,-2341],[-7,-3217],[-1014,6065],[-1176,-3185],[520,-1955],[222,-2886],[-1056,-2052],[-54,2375],[-647,-963],[-2285,2149],[-375,1014],[-257,3491],[615,2386],[-662,1589],[-1321,849],[-283,-2372],[-818,1735],[-704,-1014],[-143,1144],[-816,-294],[-894,-3961],[-589,-213],[466,4990],[570,1291],[1832,1138],[59,1054],[1158,1806],[1152,-1603],[-267,-2218],[1235,1015],[704,2232],[778,-257],[381,2425],[757,-613],[191,938],[803,-73],[-236,3877],[297,533],[1348,-2596]],[[293373,191181],[2597,-1316],[-2276,373],[-321,943]],[[297435,187868],[1994,-1930],[-993,-1578],[-1099,46],[541,1191],[-1503,-469],[-26,1273],[-1476,1087],[1107,804],[1455,-424]],[[309361,192779],[809,-1466],[-416,-2138],[909,-269],[424,-1527],[1984,-2877],[2941,-2866],[2935,-857],[-464,-1184],[-3236,-913],[-1165,634],[-3583,637],[-1203,-214]],[[309296,179739],[-2314,-31],[-659,870],[-2149,-578],[-3916,1864],[3356,866],[-469,2753],[934,1521],[421,-2130],[-694,-110],[1280,-2214],[1186,435],[1358,-1491],[580,893],[-2622,1763],[-446,2062],[2212,1665],[-790,864],[-1260,-497],[-1027,1255],[2672,4235],[920,-1043],[1492,88]],[[291370,215386],[-1109,-2334],[-314,2042],[1423,292]],[[292868,216836],[-988,-204],[-764,3862],[1030,736],[722,-4394]],[[692179,213769],[973,802],[366,-1722],[1815,1223],[654,-847],[-471,-1377],[-1307,505],[-376,-838],[1464,-553],[-645,-741],[-2561,1059],[-1028,-720],[-37,3468],[799,2426],[354,-2685]],[[290249,215820],[-391,1050],[251,3053],[470,303],[647,-3572],[-977,-834]],[[291514,206740],[-1095,-280],[340,1964],[1252,-581],[-497,-1103]],[[293121,213543],[-329,-5088],[-1015,2806],[-294,-1892],[-1344,362],[1288,3087],[-272,1106],[1085,2241],[630,-293],[251,-2329]],[[293575,234020],[-1047,171],[1054,2902],[-7,-3073]],[[295179,241703],[-688,-593],[711,-3699],[-1033,-1222],[-1441,4013],[1446,1532],[547,1508],[458,-1539]],[[297260,239419],[-1010,-314],[-264,1138],[659,1814],[1232,-1269],[-617,-1369]],[[967067,227084],[268,-1231],[-1997,-1118],[728,3310],[1001,-961]],[[911110,269175],[825,-1352],[-531,-1637],[-941,2321],[647,668]],[[899799,267051],[58,3154],[534,-2192],[-592,-962]],[[882212,292985],[1250,-98],[-1663,-1893],[-1925,247],[-323,1684],[1931,926],[730,-866]],[[980875,260159],[1729,1721],[1569,-181],[-648,-2429],[594,-1843],[-2050,-4606],[-900,-2717],[-1351,-2240],[919,-3080],[-2461,-127],[-2048,-1421],[-856,-4987],[-1205,-4186],[211,-1106],[-992,-415],[-2036,-3618],[-1633,-468],[-1990,150],[-536,1439],[-1408,1004],[-2641,-29],[-607,2288],[1326,1658],[-712,-70],[810,2487],[3725,6172],[1222,534],[5375,6307],[1419,3113],[650,3597],[1456,2073],[358,2948],[1392,2542],[967,-1955],[352,-2555]],[[295074,247915],[-1706,677],[494,2092],[480,6418],[1414,-598],[158,-3377],[-884,-707],[980,-2078],[-936,-2427]],[[902895,263078],[668,100],[2874,-2332],[1867,1014],[1292,-55],[1427,1315],[901,-992],[24,-6475],[-244,415],[-804,-3569],[157,-3464],[-542,-373],[-590,2218],[-628,-479],[-1315,-4065],[-904,615],[-1403,-227],[-136,1013],[-1408,2663],[-802,4122],[882,-732],[-1669,4208],[-748,3930],[201,1828],[900,-678]],[[981302,297748],[1597,-542],[1323,-1306],[723,-3193],[-526,70],[1142,-3174],[-222,-3150],[1603,-901],[675,-1233],[-227,4300],[1154,-2856],[449,-3809],[2034,-1712],[1572,-600],[1870,2583],[1464,-813],[-746,-5090],[-810,-1013],[-187,-3065],[-1392,939],[-1260,-1697],[433,-1811],[-744,-2871],[-2387,-6253],[-1869,-2354],[-401,1145],[-1473,758],[1465,3956],[254,1969],[-680,1997],[-2986,2625],[-356,2012],[1644,1226],[554,1052],[327,3314],[591,2495],[-950,4187],[-1103,3587],[591,-649],[-25,2144],[-1320,1314],[77,-934],[-2301,5750],[205,1120],[-1346,3324],[716,-474],[848,-2367]],[[989070,274777],[-712,800],[-39,-1605],[751,805]],[[814396,350367],[-607,1599],[50,1558],[557,-3157]],[[925214,352158],[-109,3303],[566,1604],[301,-833],[-758,-4074]],[[970372,392507],[-965,408],[435,1423],[530,-1831]],[[956117,384770],[648,-214],[2100,-2884],[1308,-2951],[1780,-2193],[1775,-2683],[-468,-1694],[-1659,1700],[-224,785],[-2372,2554],[-874,1396],[-2105,4796],[91,1388]],[[654992,378293],[-1207,389],[-143,2190],[974,-13],[376,-2566]],[[965001,379352],[-1022,1410],[476,1475],[546,-2885]],[[660142,383355],[-745,-111],[7,1630],[752,1414],[377,-1319],[-391,-1614]],[[995222,401798],[865,-1656],[211,-2544],[-1411,-1003],[-868,-28],[-1461,1051],[-159,1268],[983,2383],[1840,529]],[[85218,399912],[-715,-265],[-90,1205],[805,-940]],[[967903,400788],[220,-1515],[-1018,519],[798,996]],[[967490,407932],[-1022,639],[653,871],[369,-1510]],[[999997,408927],[-1056,-2128],[-142,-1301],[1007,1350],[-8,-1333],[-1412,-367],[-603,556],[-1377,-1561],[-581,1115],[2929,3187],[1243,482]],[[967907,405311],[-737,-148],[49,1245],[688,-1097]],[[887521,406531],[-968,-999],[370,1625],[598,-626]],[[292158,198837],[809,-2144],[-889,-1651],[-704,2853],[784,942]],[[336527,200971],[2427,-678],[384,-1926],[-2348,-1344],[85,-965],[-1508,483],[-555,-1720],[-487,2267],[1420,1421],[582,2462]],[[332538,199833],[2828,204],[-1815,-3211],[-2125,-1297],[-764,777],[2009,1690],[-917,2454],[784,-617]],[[937461,461289],[-1069,40],[-1789,3604],[61,629],[1731,-2063],[1066,-2210]],[[816234,462622],[-1038,-670],[-1196,39],[-873,824],[395,1024],[3074,159],[-362,-1376]],[[609712,468136],[213,-1261],[-916,666],[-142,2038],[324,1239],[521,-2682]],[[873713,466550],[-503,-2207],[-824,269],[302,3514],[1025,-1576]],[[359296,503937],[-758,-1160],[-191,1316],[949,-156]],[[840680,473499],[-1007,-298],[240,3272],[925,881],[161,-1868],[-319,-1987]],[[856320,482947],[-826,-571],[106,1008],[720,-437]],[[852391,486423],[1017,-1796],[7,-1434],[-1509,-1129],[-1412,1447],[-421,2423],[2318,489]],[[860429,487739],[1734,-732],[1336,-3442],[-152,-1703],[-2182,2269],[-489,875],[-1044,-747],[-1990,904],[-923,-684],[-798,1532],[-587,-2065],[-118,1682],[890,2109],[3414,447],[909,-445]],[[924903,476538],[-792,1528],[-227,2983],[-1129,2898],[-3795,4698],[-2,829],[3762,-4961],[2325,-4120],[322,-1463],[-464,-2392]],[[823064,481800],[-583,-1101],[-209,2098],[275,2135],[424,524],[93,-3656]],[[933215,465101],[-662,-1042],[-1043,836],[-394,2453],[-1167,1996],[-146,3118],[1012,-1043],[1036,-3108],[989,-1396],[375,-1814]],[[874296,470906],[25,-2747],[-874,-973],[-800,1869],[1286,3441],[363,-1590]],[[929575,472530],[-298,1907],[520,-634],[-222,-1273]],[[911181,470199],[-679,1180],[820,-136],[-141,-1044]],[[869239,469751],[523,3503],[14,-1573],[-537,-1930]],[[610736,475651],[-34,-2071],[-573,-669],[74,2616],[533,124]],[[839007,472500],[-651,1077],[437,1070],[214,-2147]],[[921986,479261],[561,501],[801,-761],[-16,-2314],[-395,-1325],[-679,-290],[360,-2092],[-771,-1232],[-973,73],[-794,-2176],[-2224,-2112],[-2155,-83],[-751,1258],[-710,-295],[-2015,2149],[-157,1304],[1817,357],[683,-523],[1994,742],[229,2446],[170,-2335],[535,-632],[1817,662],[1038,2747],[957,456],[-353,3461],[1031,14]],[[842164,477754],[-552,-3760],[615,-520],[-1083,-2356],[-631,750],[504,1982],[501,4547],[646,-643]],[[917878,488947],[-752,10],[-567,1104],[738,531],[581,-1645]],[[277412,487103],[-256,1303],[874,163],[-618,-1466]],[[908520,493104],[924,-385],[-538,-929],[-1833,-158],[305,1390],[1142,82]],[[778958,485860],[-614,1162],[115,1206],[499,-2368]],[[800575,486958],[-639,-1329],[-331,803],[-677,-729],[143,3810],[1135,-182],[600,-1380],[-231,-993]],[[778344,488478],[-525,-466],[-9,1833],[534,-1367]],[[777341,490836],[-656,507],[221,1150],[435,-1657]],[[850152,490195],[-534,2216],[361,387],[173,-2603]],[[876315,495287],[2021,-375],[1920,-857],[-1845,-557],[-2058,1335],[-38,454]],[[862092,494702],[182,-1665],[-475,-452],[-1418,1072],[1711,1045]],[[850066,494114],[854,-196],[-2497,-684],[245,814],[1398,66]],[[847137,494613],[974,-620],[-2507,-1155],[-103,1882],[1636,-107]],[[855980,494879],[-1643,-402],[-471,495],[707,1851],[1407,-1944]],[[794571,494827],[889,-4713],[1257,-643],[-574,-1908],[153,-1045],[-1856,1463],[-591,3813],[-1814,822],[1257,3056],[901,129],[378,-974]],[[846913,510614],[-1282,-3109],[-1872,-978],[-1356,125],[-508,943],[-3446,-291],[-1156,345],[-1147,-315],[-868,432],[-976,-388],[-616,-1674],[-317,-2150],[234,-2688],[1167,-2307],[416,-1959],[1018,-216],[1349,3264],[1251,-460],[862,1044],[1691,11],[785,1093],[579,-461],[-5,-2107],[-913,781],[-672,-556],[-836,-2261],[-2188,-3051],[-1029,-493],[1389,-2284],[1528,-5150],[-404,-2487],[1734,-2894],[56,-1422],[-2176,-1132],[-113,-1490],[-1347,190],[-283,1057],[365,2893],[-1956,3181],[390,2304],[-178,2943],[-935,15],[-1110,-2282],[507,-3877],[-206,-2242],[160,-3149],[-391,-3133],[419,-2636],[-1329,80],[-651,-686],[-948,1591],[655,5931],[33,2307],[-566,3311],[-1181,-368],[-506,2257],[-80,2320],[857,1671],[638,3278],[-36,3089],[552,2971],[566,1339],[369,-1073],[-340,4582],[929,4627],[738,1722],[541,-982],[1098,2793],[1467,-441],[421,-868],[2347,-295],[1265,-996],[1071,462],[1581,-532],[1186,1090],[1988,4022],[679,-1179],[-958,-3002]],[[842256,497778],[70,-1292],[859,308],[-860,-1420],[-241,1615],[-723,-1675],[49,2398],[846,66]],[[246466,504866],[1312,-4604],[-294,-1117],[-1294,-453],[-241,1287],[937,1426],[-690,1611],[270,1850]],[[775454,494184],[-804,677],[-757,2759],[742,1672],[1106,-4219],[-287,-889]],[[804750,497722],[-785,-359],[134,1516],[651,-1157]],[[876063,500858],[1418,-441],[1338,-2182],[-736,-728],[-754,578],[-1266,2773]],[[863893,496923],[-610,356],[-303,1752],[1113,-50],[-200,-2058]],[[356020,496222],[796,4646],[811,642],[259,-743],[-321,-2103],[-1545,-2442]],[[362142,503359],[1422,389],[1469,-403],[579,-718],[-445,-2655],[-1081,-4037],[-677,412],[-170,-1107],[-758,522],[-829,-1652],[-1952,14],[-765,4607],[383,4370],[1103,926],[1721,-668]],[[249070,500146],[-577,563],[758,1137],[-181,-1700]],[[854352,502828],[105,-1727],[765,-1175],[-1161,15],[-381,2786],[672,101]],[[790205,502734],[322,-781],[-630,-1138],[-295,1157],[603,762]],[[863369,504693],[1288,-863],[-54,-1280],[-700,30],[-1065,1628],[185,-1249],[-1255,516],[161,640],[1440,578]],[[943750,449782],[612,-952],[1066,69],[1290,-2614],[-2681,423],[-644,1535],[357,1539]],[[918134,449344],[722,-423],[293,-1478],[-1271,254],[256,1647]],[[917625,448471],[-654,782],[584,579],[70,-1361]],[[919668,445353],[599,376],[-182,-1410],[-755,605],[-508,2272],[846,-1843]],[[833367,449176],[774,-1617],[591,-155],[913,-2154],[-1093,-1519],[-817,556],[-1511,2527],[-1433,394],[-351,1111],[630,800],[2297,57]],[[923974,451638],[933,-1480],[-685,253],[-248,1227]],[[946525,455461],[690,-1766],[-148,-1107],[595,-965],[453,-3719],[-1245,2564],[-770,4909],[425,84]],[[847805,449005],[-589,-957]],[[847216,448048],[-1585,-3456],[-1583,-1156],[-593,193],[-152,2040],[333,2085],[744,1433]],[[844380,449187],[613,692]],[[844993,449879],[1049,597]],[[846042,450476],[873,1108]],[[846915,451584],[381,648]],[[847296,452232],[420,1251],[1740,923],[2265,193],[963,852],[915,-645],[-1058,-1722],[-1479,-1436],[-2707,-1885],[-550,-758]],[[828450,455439],[2071,-118],[394,-1958],[-1809,-1116],[-277,1078],[-524,-983],[-3135,-1532],[-759,549],[130,2808],[916,979],[1117,-351],[664,-1687],[1191,707],[-1167,1480],[-165,1141],[1006,161],[347,-1158]],[[824001,453685],[-732,-1867],[-1396,611],[561,479],[-44,1822],[947,1382],[924,-1083],[-260,-1344]],[[937191,453094],[-491,880],[464,854],[27,-1734]],[[841063,453697],[-1913,-788],[-1230,-912],[-658,496],[-1054,-714],[-1346,792],[-1782,-330],[25,2443],[1923,1213],[2317,-1999],[1450,726],[823,-1005],[1988,2802],[76,-1050],[-619,-1674]],[[820688,456402],[712,-1494],[-1029,-1234],[-271,-1078],[-1095,2187],[-636,296],[-383,1535],[2702,-212]],[[844234,455707],[-1032,-1744],[-897,215],[1516,2015],[413,-486]],[[845239,455369],[-613,-1316],[-262,1170],[875,146]],[[846042,456487],[1526,-379],[-78,-877],[-1812,-544],[364,1800]],[[938231,455887],[155,-2192],[-726,2027],[-904,-266],[558,1956],[917,-1525]],[[944108,454156],[-2598,2924],[-1351,2939],[769,-353],[1042,-1774],[2038,-2508],[100,-1228]],[[885819,455018],[-923,472],[648,802],[275,-1274]],[[935243,457777],[-352,2068],[689,-882],[-337,-1186]],[[852224,459289],[-914,-1674],[-1010,394],[-861,-596],[492,1903],[661,-257],[1100,799],[532,-569]],[[884820,455700],[-665,-779],[-1690,-39],[-7,886],[895,3677],[800,1203],[1317,285],[610,-1811],[-564,-2151],[-696,-1271]],[[798260,469125],[814,-1233],[1745,-292],[1063,-3113],[4857,-929],[863,2814],[653,217],[506,-1382],[1072,123],[1520,-1452],[1255,-197],[709,-2239],[0,-1469],[1261,-982],[2284,505],[1038,-1556],[-159,-3019],[546,-2159],[-3695,2861],[-1596,-726],[-3247,617],[-2508,922],[-1579,1534],[-2103,1100],[-1501,224],[-804,-770],[-1484,432],[-1757,1495],[-2305,611],[178,1865],[-2877,1613],[843,1923],[226,2018],[574,1198],[2084,-1092],[614,1151],[910,-613]],[[864792,457323],[-664,798],[481,2337],[1065,2120],[-51,-3042],[-831,-2213]],[[890964,489271],[993,-25]],[[891957,489246],[3074,-2798],[1926,-1404],[1677,-655],[1409,-2089],[1283,-246],[1695,-3103],[685,-214],[1201,-2594],[-60,-3432],[1828,-1269],[1753,-1793],[951,-187],[1181,-2160],[121,-2056],[-2018,-351],[-440,-1227],[637,-2662],[1484,-2952],[1118,-1346],[334,-2670],[567,-832],[367,-2116],[1846,-114],[-124,-1990],[758,-1074],[1382,-431],[-589,-858],[313,-1227],[2203,-1447],[-614,-297],[558,-1248],[-909,-811],[-842,459],[-729,1329],[-3808,993],[-1707,683],[-1002,2343],[-1087,1699],[-147,1945],[-743,202],[-1842,5623],[-846,734],[-2097,891],[-304,1009],[-985,381],[-790,-1170],[-909,539],[123,-1601],[-1178,-336],[265,-1183],[-1441,-656],[-1074,231],[1120,-1198],[780,-1939],[-72,-943],[-1998,-2173],[-1160,934],[-3045,-303]],[[892036,450086],[-580,807]],[[891456,450893],[-2749,5829],[-1526,-521],[-1471,261],[645,3305],[-945,1989],[835,302],[-1245,1717],[734,310],[-1183,3050],[-396,2337],[-639,1618],[-15,1249],[-2698,3204],[-1307,626],[-1776,1705],[-2178,475],[-1226,1513],[-132,1425],[-1223,53],[-812,758],[-891,2687],[-1124,-4135],[-778,-193],[-596,2317],[322,905],[-329,1518],[-2167,2999],[721,641],[1373,-645],[1293,2081],[1161,-646],[822,925],[48,1712],[-2665,-1011],[-1819,180],[-789,1492],[-259,2552],[-1768,985],[-827,-187],[726,3374],[1519,898],[901,1479],[1379,565],[2355,-2176],[1394,-108],[757,-3354],[-393,-2432],[139,-2809],[845,-3775],[465,1751],[208,-2351],[392,145],[538,-2513],[1249,-70],[2102,4515],[407,1835],[1259,448],[910,1020],[-131,1094],[1895,2119],[2344,-1824],[3166,-3302],[2314,-577],[347,-956]],[[897718,433893],[-190,-2068],[809,-1993],[514,-4761],[-106,-1763],[577,-3600],[571,-676],[1420,1368],[486,-1543],[1777,-2670],[-45,-3161],[518,-3435],[-89,-2071],[1322,-3935],[622,-3347],[-260,-3778],[836,-1664],[-101,-1703],[512,-1408],[2604,-1773],[1381,-2909],[1902,-1635],[790,-1990],[-559,-587],[1448,-3229],[692,-2687],[394,-4022],[1052,-1736],[282,2288],[1291,-2338],[620,-101],[220,-5225],[1827,-3284],[1116,-1117],[630,-2350],[907,-1214],[551,-2367],[720,-1363],[18,-1520],[680,-1632],[-224,-2013],[91,-5276],[1274,-6198],[80,-3637],[-712,-2583],[-211,-3567],[-672,-3974],[-240,-5163],[-1068,-3619],[-247,-2331],[-1826,-2737],[-1448,-4028],[-32,-2048],[-889,-2194],[-750,-5218],[-341,-216],[-1034,-3669],[-653,-5995],[-76,-4047],[-1762,-1621],[-2878,-169],[-1071,-613],[-1337,-1688],[-1496,-2633],[-1568,-215],[484,-833],[-185,-1808],[-671,1658],[-2115,1957],[-290,1764],[-925,-1559],[445,2426],[-636,1134],[-1376,-1404],[748,-433],[-1565,-1495],[-1563,-2124],[-2575,2187],[-2463,1068],[-836,-546],[-1148,1698],[-1066,288],[-2342,4636],[204,3458],[-859,3350],[-1609,3057],[622,1383],[-1864,-1749],[-937,176],[907,3486],[-59,1545],[-1113,3518],[-1104,-5766],[-2245,-573],[363,1919],[1047,15],[285,4456],[1217,3448],[-221,2242],[390,631],[-560,1605],[-969,-2194],[-569,-2582],[-2241,-2373],[-1500,-3738],[300,-1676],[-975,25],[-1158,2132],[609,-8],[-735,3995],[-824,1661],[-271,1766],[-1361,967],[-558,2467],[372,1186],[-1897,2166],[-942,-5],[-1263,1348],[-1508,-302],[-1371,1842],[-1604,1188],[-1002,-641],[-1814,147],[-3288,-732],[-2440,-2155],[-2078,-1171],[-3896,-195],[-3219,-3470],[-1756,-1461],[-1322,-4189],[-1229,-900],[-1195,578],[-1741,-599],[-249,696],[-1823,282],[-2740,-808],[-1568,-68],[-1121,-2332],[-1542,-661],[-2111,-3003],[-1537,-658],[-2959,651],[-1472,1143],[-724,1593],[-1994,1601],[-40,4387],[521,-759],[927,664],[466,2005],[43,8877],[-1449,5252],[-507,3507],[-98,4636],[-919,3329],[-252,1948],[-1035,2739],[-380,4344],[-885,2960],[-1046,2550],[156,1847],[535,-2681],[753,1339],[-733,1383],[-538,2283],[883,-696],[1048,-3335],[348,617],[-4,2595],[-1510,5181],[-703,3207],[376,4164],[567,1864],[105,2338],[-311,2286],[765,4139],[459,654],[50,-3877],[655,839],[626,2366],[712,1222],[1659,1447],[1541,2733],[1933,2231],[1943,-400],[2202,2049],[1534,671],[981,1581],[1337,-255],[1695,763],[1896,1448],[837,1109],[871,2201],[945,3729],[1465,2606],[-344,406],[-214,3880],[755,2034],[801,1082],[695,2079],[476,-2525],[1169,-3898],[153,3037],[445,832],[-800,2235],[664,1766],[361,-1124],[752,613],[902,-334],[340,1312],[-542,2106],[161,1568],[863,1234],[868,-930],[-622,1668],[650,761],[785,-519],[-491,2400],[1114,1372],[863,-798],[815,3649],[1071,-942],[927,2470],[2137,-2672],[1464,-3298],[-361,-3423],[514,184],[-221,1513],[840,1511],[1613,-571],[438,-1634],[143,1711],[1021,-1590],[6,1711],[588,130],[-417,1503],[-889,1084],[920,2443],[359,2412],[1169,1604],[-255,2042],[1262,3119],[681,-752],[18,1130],[1160,1774],[407,-1239],[2264,538],[439,-646],[608,1540],[123,2288],[-553,933],[-949,-55],[-894,1359],[1253,399],[1166,-1786],[951,312],[445,-1498],[1997,-748],[924,-1041],[1371,137],[1355,-1405],[1957,2345],[-611,-1929],[653,-4],[897,-1668],[26,1789],[751,1031],[1131,-2324],[-1140,-2574],[-212,-2612],[-463,518],[-1019,-986],[173,-2997],[-295,-2031],[-1328,-3585],[348,-1436],[1874,-2387],[239,-987],[1148,-683],[2775,-3245],[1504,-2875],[2125,-1072],[662,-2544],[2188,-2215],[1320,462],[886,1245],[377,2369],[703,2183],[536,3416],[110,2750],[483,3251],[-286,3475],[200,1879],[-339,2105],[481,3189],[-89,1871],[852,832],[-644,2678],[730,2694],[603,5627],[800,1417],[1057,-3552],[99,-3048],[851,-789]],[[858420,409078],[-1074,-97],[-319,-2064],[567,-1663],[189,2004],[637,1820]],[[637606,431064],[1109,-3794],[656,-5734],[171,-4098],[687,-3872],[-760,-3406],[-879,2979],[-674,-648],[174,-3021],[329,-1060],[-177,-3313],[-633,-1291],[-284,-1859],[113,-3269],[-2419,-15161],[-712,-5281],[-1229,-6617],[-973,-8346],[-1057,-5407],[-1247,-2148],[-1583,-477],[-1807,-1972],[-1092,119],[-839,1238],[-1298,640],[-862,1365],[-966,3779],[-115,3649],[211,1258],[-901,3811],[-365,4959],[654,4105],[829,1050],[308,1857],[912,2880],[459,2711],[122,2923],[-583,2094],[-16,1982],[-536,2678],[-169,5314],[1228,4081],[152,2877],[1203,253],[716,1135],[1198,-57],[283,1058],[1754,594],[1529,2868],[418,-1144],[167,1615],[963,2647],[237,-1712],[797,2650],[-106,1037],[617,2426],[123,2158],[599,-730],[1503,2678],[316,1964],[-344,2755],[1169,2318],[920,-2088]],[[965034,409358],[1178,-2096],[-1076,-624],[-694,3969],[592,-1249]],[[963182,416876],[179,-1958],[737,1314],[344,-3259],[-1226,-862],[-641,4627],[607,138]],[[623545,433141],[79,-1630],[-791,1097],[712,533]],[[879762,422936],[499,-2898],[-1552,482],[248,2055],[805,361]],[[620738,434208],[-665,886],[462,2033],[203,-2919]],[[946044,434821],[-1591,1293],[-9,638],[1600,-1931]],[[862386,435524],[408,-814],[-1319,-47],[60,2056],[517,832],[334,-2027]],[[862828,437320],[1124,247],[681,856],[751,-1463],[-222,-895],[-1411,-2006],[-1219,1829],[-398,2387],[694,-955]],[[926487,436727],[-435,-494],[-488,1395],[923,-901]],[[841524,440086],[-287,873],[1460,1700],[130,-1045],[-1303,-1528]],[[949208,443178],[1084,-394],[743,-2189],[-694,-7],[-1626,1529],[-647,2145],[1140,-1084]],[[362655,504051],[-1073,110],[1194,895],[-121,-1005]],[[791051,503675],[-922,-79],[267,1226],[655,-1147]],[[361838,506306],[-280,-1548],[-1390,216],[185,1116],[1485,216]],[[518498,505431],[-531,633],[607,1049],[-76,-1682]],[[359927,505541],[-549,-502],[758,3125],[-209,-2623]],[[770781,513396],[1251,-2909],[-154,-2047],[-534,-192],[-1680,4913],[1117,235]],[[786187,509140],[-1594,847],[265,1426],[1329,-2273]],[[786573,509872],[-1291,1088],[245,662],[1046,-1750]],[[790514,511922],[-28,-2276],[-593,2071],[621,205]],[[784519,510583],[-552,2119],[596,-673],[-44,-1446]],[[784699,513362],[21,-760],[-1169,993],[-101,752],[1249,-985]],[[768033,535698],[974,267],[1957,-406],[1002,-1931],[945,-2757],[164,-1906],[3958,-5390],[2014,-5485],[1195,-1831],[-164,1744],[605,87],[1196,-3342],[856,-425],[1034,-2148],[867,-2841],[1056,-378],[602,-1324],[-1434,-1633],[2019,1648],[562,-85],[855,-2567],[-995,-1414],[7,-2025],[805,-2092],[1777,-899],[430,-4627],[916,-1621],[-491,-1733],[187,-1098],[806,1264],[1545,-797],[1284,-3639],[-397,-1800],[81,-2506],[-277,-1954],[156,-5016],[-197,-3951],[-549,-729],[-748,1481],[-744,-1161],[-1228,1334],[-105,-2276],[-2140,4887],[-2534,3608],[-1060,1887],[-1138,3276],[-1525,2560],[-1278,3432],[-751,2629],[20,1242],[-1025,3763],[-495,2800],[-1245,3038],[-729,2466],[-1219,1477],[-1006,6771],[-645,2414],[-2399,2703],[-305,2893],[-554,762],[-1174,3554],[-1456,1429],[-2639,5599],[-801,3096],[527,2043],[1237,-678],[811,-1304],[997,-385]],[[854812,509742],[412,-95],[768,2870],[1475,1516],[39,-2761],[-1121,-1360],[-106,-849],[974,-1088],[801,-1977],[-2546,1514],[-267,-1027],[251,-3239],[767,-2863],[-576,151],[-985,2750],[48,3140],[-426,1194],[145,2124],[-521,2392],[588,3506],[1124,2105],[-416,-2169],[347,-2969],[-997,-1883],[222,-982]],[[826676,529600],[-104,-224]],[[826572,529376],[-280,-510],[866,-2292],[-1682,-298],[502,-2638],[716,-766],[1268,-4423],[-771,-1724],[809,-1926],[1551,-2268],[961,-1995],[-1250,-999],[-940,360],[-792,1329],[33,-1584],[-494,-602],[-619,-2925],[-165,-3316],[277,-2649],[-895,-918],[-2680,-5089],[413,0],[292,-4300],[-491,-65],[-265,-3584],[-836,-2775],[-3508,-3405],[-466,4698],[-221,-623],[-1011,1202],[-795,-1050],[-516,1543],[-742,-301],[-859,1855],[-174,-1503],[-1030,-1264],[-876,471],[-1286,-1253],[2,2816],[-1264,732],[-1216,-814],[-989,1064],[-754,-556],[-633,6154],[-319,496],[165,2749],[-644,2296],[-1434,1654],[-415,2767],[377,1755],[-869,1922],[-108,2597],[472,4157],[841,2529],[696,622]],[[804524,516729],[987,-1836],[1014,12],[2081,-1888],[471,4377],[-72,1754],[559,-322],[0,1497],[790,1301],[2804,1284],[854,797],[1115,3173],[1328,2978],[360,2071]],[[816815,531927],[345,-11]],[[817160,531916],[1018,792],[1253,1764],[87,-727]],[[819518,533745],[315,0]],[[819833,533745],[652,196],[575,1549],[-452,1297],[513,1127],[536,-398],[949,3515],[990,2323],[708,2699],[454,-1881],[598,1832],[459,-1730],[978,-1204],[-79,-3157],[1074,667],[310,-1131],[1331,-1602],[1746,-1063],[-253,-1849],[-1278,-809],[-1143,147],[-209,-950],[1046,-1933],[-178,-828],[-1360,-665],[-742,518],[-382,-815]],[[190458,968527],[-4765,717],[7618,2063],[2826,-2488],[-5679,-292]],[[232764,969972],[3660,-1102],[-556,-2089],[-5284,-1107]],[[230584,965674],[-3516,3693]],[[227068,969367],[120,2224]],[[227188,971591],[5576,-1619]],[[785790,974253],[-1312,-2479],[3501,1864],[4092,-1962],[463,-1890],[-4426,-1432],[-6987,-393],[-3116,-1285],[-2208,374],[4412,4417],[890,2493],[3018,1337],[1673,-1044]],[[771316,979611],[-62,-2356],[2624,1727],[4069,-1630],[-1727,-5585],[-5233,-46],[-7679,1540],[-1590,1871],[-3189,551],[5324,3564],[7463,364]],[[215066,972034],[2424,1181],[5817,-2936],[-394,-1660]],[[222913,968619],[1625,-2642]],[[224538,965977],[-3944,205]],[[220594,966182],[-1356,1790],[-4603,1051]],[[214635,969023],[-4425,-602],[-1865,1475]],[[208345,969896],[3420,6]],[[211765,969902],[-1076,2786]],[[210689,972688],[-1849,-1082]],[[208840,971606],[-1995,1335],[411,1725]],[[207256,974666],[6871,-549],[939,-2083]],[[244762,985385],[3451,-3194]],[[248213,982191],[8245,-1313]],[[256458,980878],[-687,-1627]],[[255771,979251],[2624,-1204],[-882,-1861]],[[257513,976186],[4576,185]],[[262089,976371],[995,-2388]],[[263084,973983],[-6467,-3153]],[[256617,970830],[-3122,-546]],[[253495,970284],[-137,-2320]],[[253358,967964],[-3461,2456]],[[249897,970420],[1472,-2391]],[[251369,968029],[-6645,199]],[[244724,968228],[-6288,4486]],[[238436,972714],[7831,2173]],[[246267,974887],[-4106,527]],[[242161,975414],[-6338,-948]],[[235823,974466],[-4639,5012]],[[231184,979478],[5909,-516],[-4783,1448]],[[232310,980410],[2276,435]],[[234586,980845],[-1622,1924],[6125,-783]],[[239089,981986],[-4409,1652]],[[234680,983638],[680,964],[7938,1644]],[[243298,986246],[1464,-861]],[[451076,977642],[-3846,679],[4238,522],[-392,-1201]],[[225579,978561],[-137,-1445],[-3477,1075]],[[221965,978191],[1004,1336],[2610,-966]],[[757453,976808],[-4327,1302],[834,855],[6603,-857],[-3110,-1300]],[[658551,980752],[4,-1518],[-3767,60],[3763,1458]],[[375376,991018],[-5243,1567],[980,2038],[4581,-1724],[-318,-1881]],[[558049,980153],[3866,-1188],[5578,1843],[7120,-1187],[938,-1501],[-4326,-2983],[-4704,-1237],[-3006,1289],[-5568,-83],[-3296,1145],[3082,933],[-5720,72],[-1304,998],[3022,1109],[753,2051],[3565,-1261]],[[639661,984167],[3960,-1420],[-7799,-1886],[226,-1224],[-3736,-300],[-2745,1116],[10094,3714]],[[768129,985046],[3624,-1644],[-1824,-3301],[-9173,-1369],[-6524,2065],[4830,2564],[-548,1168],[7598,1730],[2017,-1213]],[[660989,979403],[-2448,2197],[3904,-173],[-1456,-2024]],[[631783,983731],[-3613,-2411],[-3435,975],[7048,1436]],[[672688,983619],[-3102,-2466],[-4852,610],[799,1748],[7155,108]],[[651996,985285],[8265,-1918],[-5505,-918],[-4572,1045],[1812,1791]],[[676038,982821],[-2371,721],[6338,2224],[1765,-1579],[-5732,-1366]],[[662839,984844],[660,-1553],[-4580,1408],[3920,145]],[[660583,987833],[-998,-2432],[-4817,313],[5815,2119]],[[57298,634654],[-1158,649],[1215,1053]],[[57355,636356],[-57,-1702]],[[270661,632517],[-809,-757],[-637,2059],[1022,586],[424,-1888]],[[272673,641945],[1831,-612],[1468,257],[2704,-2133],[1113,-1987],[1637,-242],[2916,-3373],[388,440],[2360,-3479],[2921,-1717],[-130,-1547],[2112,-491],[1026,-1577],[960,-547],[-237,-1259],[-2883,-1105],[-2411,572],[-4324,-795],[449,1343],[1249,1927],[-349,1400],[-2132,424],[-1371,2005],[-405,2736],[-518,612],[-1017,-391],[-2003,1124],[-1636,1901],[-1285,-63],[-2374,873],[-726,1111],[891,468],[-407,1258],[-2318,61],[-1782,-2763],[-1448,-313],[-362,-1345],[-1310,-989],[490,1766],[-97,1805],[879,1701],[2186,1786],[3212,1321],[733,-163]],[[241809,926906],[-91,-2428]],[[241718,924478],[2771,-3358]],[[244489,921120],[20,-1462]],[[244509,919658],[-2531,-2195]],[[241978,917463],[2711,-811],[3769,-159]],[[248458,916493],[-1896,-1297]],[[246562,915196],[2137,-2499]],[[248699,912697],[-293,-2305]],[[248406,910392],[1025,-1287],[1495,4485]],[[250926,913590],[1694,1491],[2820,-2692],[523,-3228],[-1372,126],[420,-3095]],[[255011,906192],[2581,-3447]],[[257592,902745],[2028,1968]],[[259620,904713],[1623,3296]],[[261243,908009],[1207,4132]],[[262450,912141],[1821,1802],[-1457,935]],[[262814,914878],[-79,3659],[3260,-87]],[[265995,918450],[1601,-800]],[[267596,917650],[3587,-343],[-1058,-874]],[[270125,916433],[3962,-2218]],[[274087,914215],[-1748,-1400]],[[272339,912815],[1879,-1341]],[[274218,911474],[-3531,-1249]],[[270687,910225],[1600,-3463]],[[272287,906762],[1962,-2382]],[[274249,904380],[-548,-2311],[-3261,-2857]],[[270440,899212],[-2449,-1296]],[[267991,897916],[-1103,1838],[-2571,2071]],[[264317,901825],[2833,-4376]],[[267150,897449],[-1813,-656]],[[265337,896793],[-2677,2121]],[[262660,898914],[-3309,-35]],[[259351,898879],[1640,-3014],[-3468,-3956],[-1884,-35],[-4943,3478]],[[250696,895352],[-3500,176],[3393,-1357],[2261,-2301]],[[252850,891870],[5407,-890]],[[258257,890980],[-703,-2203]],[[257554,888777],[-2293,-3809]],[[255261,884968],[-1977,-1132]],[[253284,883836],[-3751,-80]],[[249533,883756],[-215,-1996],[-1945,-320],[-2489,650],[3041,-2050]],[[247925,880040],[-345,-2403],[-1605,-840]],[[245975,876797],[-2534,90],[981,-1652]],[[244422,875235],[-1510,36]],[[242912,875271],[66,-2240]],[[242978,873031],[-2928,-1341]],[[240050,871690],[750,-1036]],[[240800,870654],[-2080,-2662]],[[238720,867992],[-21,-1061],[-1607,-4281]],[[237092,862650],[-386,-2742],[-7,-4061]],[[236699,855847],[319,-2357]],[[237018,853490],[1073,-913]],[[238091,852577],[-125,-2480]],[[237966,850097],[767,2741]],[[238733,852838],[2161,-22]],[[240894,852816],[2329,-8777]],[[243223,844039],[-794,-2022]],[[242429,842017],[4484,1823]],[[246913,843840],[1442,-99]],[[248355,843741],[2226,-1441]],[[250581,842300],[2340,-771]],[[252921,841529],[2426,-2274]],[[255347,839255],[1427,-2435]],[[256774,836820],[5235,-2697]],[[262009,834123],[1710,-1869]],[[263719,832254],[3196,172]],[[266915,832426],[3703,-983]],[[270618,831443],[995,-1986],[-552,-2712],[768,-3188]],[[271829,823557],[-331,-5075]],[[271498,818482],[1914,-3518]],[[273412,814964],[61,-774]],[[273473,814190],[2477,-2833]],[[275950,811357],[499,-2672],[1041,-145]],[[277490,808540],[1081,-979]],[[278571,807561],[1044,3024],[828,-973]],[[280443,809612],[381,-1561]],[[280824,808051],[478,1760],[-685,1399]],[[280617,811210],[1350,3072]],[[281967,814282],[-644,2225]],[[281323,816507],[-1082,6455]],[[280241,822962],[469,729]],[[280710,823691],[-2003,5079],[2100,1089],[2829,2104],[1572,1889]],[[285208,833852],[1874,3270]],[[287082,837122],[363,3553]],[[287445,840675],[-148,2809]],[[287297,843484],[-1622,4963]],[[285675,848447],[-3773,3931]],[[281902,852378],[157,1131]],[[282059,853509],[1939,3002]],[[283998,856511],[96,1753]],[[284094,858264],[1096,715]],[[285190,858979],[55,1456]],[[285245,860435],[-1331,3540]],[[283914,863975],[522,1098]],[[284436,865073],[-1607,-36]],[[282829,865037],[1853,4366]],[[284682,869403],[-1203,1219]],[[283479,870622],[-335,3516]],[[283144,874138],[1932,1287]],[[285076,875425],[4321,-1521]],[[289397,873904],[3253,-620]],[[292650,873284],[2822,1440]],[[295472,874724],[3900,-3689]],[[299372,871035],[2231,-3985],[3176,-535],[511,-1116],[1732,774],[-927,-6315]],[[306095,859858],[629,-1599],[-285,-1975]],[[306439,856284],[783,-23]],[[307222,856261],[-366,-2776]],[[306856,853485],[2936,-271]],[[309792,853214],[669,-2514]],[[310461,850700],[1845,-1100]],[[312306,849600],[2672,1987]],[[314978,851587],[2782,3329]],[[317760,854916],[556,4055]],[[318316,858971],[1319,2706]],[[319635,861677],[1421,-477],[-969,-944]],[[320087,860256],[1347,308]],[[321434,860564],[2066,-4332]],[[323500,856232],[94,-1290]],[[323594,854942],[1756,-2623]],[[325350,852319],[-1433,-1304],[2172,261]],[[326089,851276],[-1036,-2388]],[[325053,848888],[1374,360]],[[326427,849248],[1631,-1734]],[[328058,847514],[-192,-1478],[-1352,-888]],[[326514,845148],[1677,-478]],[[328191,844670],[-351,-790]],[[327840,843880],[1788,-1406],[-105,-1954]],[[329523,840520],[-1919,107]],[[327604,840627],[1770,-2004]],[[329374,838623],[-67,-2163],[1715,-223]],[[331022,836237],[1364,-1026]],[[332386,835211],[413,-1800]],[[332799,833411],[-1180,-2492]],[[331619,830919],[2384,1477]],[[334003,832396],[2116,-949]],[[336119,831447],[602,-1843]],[[336721,829604],[2272,222]],[[338993,829826],[1550,-1809]],[[340543,828017],[-2075,-1304]],[[338468,826713],[-1338,-1782]],[[337130,824931],[-3305,-1274]],[[333825,823657],[-1407,-3367]],[[332418,820290],[2798,2237]],[[335216,822527],[1861,1979],[2011,745]],[[339088,825251],[-733,738]],[[338355,825989],[2156,-387]],[[340511,825602],[780,-2198]],[[341291,823404],[-1090,-1138],[544,-774]],[[340745,821492],[1363,1602]],[[342108,823094],[2030,-901]],[[344138,822193],[867,-2225]],[[345005,819968],[-117,-4172]],[[344888,815796],[403,-2191]],[[345291,813605],[-3558,-4029],[-2204,-189],[-2058,-775]],[[337471,808612],[-1820,-3052]],[[335651,805560],[-2541,-3112]],[[333110,802448],[-3360,-312]],[[329750,802136],[-1208,-580]],[[328542,801556],[-541,763]],[[328001,802319],[-2211,408]],[[325790,802727],[-5979,-155]],[[319811,802572],[-1113,263]],[[318698,802835],[-3408,-641]],[[315290,802194],[-1238,-1292],[-1197,-3822]],[[312855,797080],[-1900,-543],[-2425,-2535]],[[308530,794002],[-2069,-3731]],[[306461,790271],[-2296,918],[2015,-1517]],[[306180,789672],[-362,-1575]],[[305818,788097],[-2223,-4102],[-1561,-2038]],[[302034,781957],[-1700,-646]],[[300334,781311],[-3059,-2827]],[[297275,778484],[-1377,-2793]],[[295898,775691],[-1559,-1400]],[[294339,774291],[178,-929]],[[294517,773362],[-2042,-2022]],[[292475,771340],[3197,2496]],[[295672,773836],[1107,3465]],[[296779,777301],[3496,3685],[1777,736]],[[302052,781722],[2060,1637]],[[304112,783359],[4257,7361]],[[308369,790720],[3962,3441]],[[312331,794161],[3840,2117],[1819,314]],[[317990,796592],[1909,-441]],[[319899,796151],[1596,-1599]],[[321495,794552],[-242,-2954]],[[321253,791598],[-2529,-2381],[-1854,993]],[[316870,790210],[-2160,-986]],[[314710,789224],[2375,-660]],[[317085,788564],[508,-1273]],[[317593,787291],[1847,891],[829,-721]],[[320269,787461],[-581,-2111]],[[319688,785350],[-1130,-1585]],[[318558,783765],[1354,-239],[-206,-1024]],[[319706,782502],[1012,-3836],[1737,-442]],[[322455,778224],[-390,-856],[2121,-1596]],[[324186,775772],[1645,-67],[605,-704]],[[326436,775001],[1465,1460]],[[327901,776461],[1287,-1074]],[[329188,775387],[1280,-2341]],[[330468,773046],[-4118,-2655]],[[326350,770391],[-2201,-1192]],[[324149,769199],[-827,242]],[[323322,769441],[-437,-1166]],[[322885,768275],[-662,939],[-2397,-4604]],[[319826,764610],[-2432,-1819]],[[317394,762791],[-1077,1499]],[[316317,764290],[73,3279]],[[316390,767569],[1610,2165]],[[318000,769734],[-380,163]],[[317620,769897],[3683,3252]],[[321303,773149],[-65,-1013]],[[321238,772136],[2739,1343],[-4291,59]],[[319686,773538],[1662,2730]],[[321348,776268],[-4361,-3630]],[[316987,772638],[-2744,-922]],[[314243,771716],[-701,605]],[[313542,772321],[-185,-2926]],[[313357,769395],[-1799,-588]],[[311558,768807],[-605,-1137]],[[310953,767670],[-1094,730]],[[309859,768400],[-227,-1475],[-1192,1038]],[[308440,767963],[-297,-1992]],[[308143,765971],[-2055,-1928]],[[306088,764043],[-436,491],[-2133,-4651]],[[303519,759883],[-7,-2374]],[[303512,757509],[-863,-2003]],[[302649,755506],[855,-606],[622,-2521]],[[304126,752379],[1425,135]],[[305551,752514],[147,-883]],[[305698,751631],[-1968,-846],[-122,1070]],[[303608,751855],[-1299,-1336]],[[302309,750519],[-615,1812],[-149,-2023]],[[301545,750308],[-2282,-960],[-1832,-39]],[[297431,749309],[-1829,-1560],[-1788,-2452],[-41,-899]],[[293773,744398],[789,-757],[-607,-3565],[-1718,-4294]],[[292237,735782],[-2027,2893]],[[290210,738675],[285,1774],[965,1148]],[[291460,741597],[-1426,-2030]],[[290034,739567],[543,-3247]],[[290577,736320],[990,-3492],[-1557,-5167]],[[290010,727661],[-1114,-2176]],[[288896,725485],[939,4088]],[[289835,729573],[-532,105]],[[289303,729678],[-106,2275],[-896,34]],[[288301,731987],[-146,1414]],[[288155,733401],[731,10]],[[288886,733411],[-652,3495]],[[288234,736906],[1008,1891],[-1523,-1693],[-223,-4105]],[[287496,732999],[130,-2125]],[[287626,730874],[-2186,1904]],[[285440,732778],[-200,-582]],[[285240,732196],[2122,-1790]],[[287362,730406],[793,-1190]],[[288155,729216],[2,-3179]],[[288157,726037],[-965,-204]],[[287192,725833],[910,-1599]],[[288102,724234],[-323,-965]],[[287779,723269],[1111,135],[324,-4366]],[[289214,719038],[-2343,-1292]],[[286871,717746],[2650,-342]],[[289521,717404],[-4,-1498]],[[289517,715906],[-1111,-1735]],[[288406,714171],[-996,914]],[[287410,715085],[-1228,-296],[1282,-1114]],[[287464,713675],[-11,-2922]],[[287453,710753],[-1714,-411]],[[285739,710342],[-1714,-2505]],[[284025,707837],[-491,-2046]],[[283534,705791],[-1328,-131],[-1210,-1146]],[[280996,704514],[-1078,-3193]],[[279918,701321],[-2201,-3349]],[[277717,697972],[-947,-706]],[[276770,697266],[-1416,-2791]],[[275354,694475],[-669,-895]],[[274685,693580],[-487,-3641],[-425,-381]],[[273773,689558],[-173,-2774]],[[273600,686784],[707,-5555]],[[274307,681229],[971,-4407]],[[275278,676822],[1044,-3340]],[[276322,673482],[-873,1609],[249,-2232]],[[275698,672859],[1451,-6955]],[[277149,665904],[514,-3782],[-327,-4090]],[[277336,658032],[-578,-3241]],[[276758,654791],[-1026,-1036]],[[275732,653755],[-1039,-109]],[[274693,653646],[-8,1358]],[[274685,655004],[-699,2748],[-974,901]],[[273012,658653],[-419,2677]],[[272593,661330],[-481,693]],[[272112,662023],[-76,2012]],[[272036,664035],[-620,-123]],[[271416,663912],[-960,3873]],[[270456,667785],[653,1842],[-497,729],[-226,-1423]],[[270386,668933],[-507,756]],[[269879,669689],[508,3791]],[[270387,673480],[25,2380]],[[270412,675860],[-1775,3343],[-1122,2809]],[[267515,682012],[-971,1054]],[[266544,683066],[-941,-1164]],[[265603,681902],[-2600,-1346]],[[263003,680556],[-97,1158]],[[262906,681714],[-1117,1726]],[[261789,683440],[-1941,1375]],[[259848,684815],[-3710,-636]],[[256138,684179],[-614,2384]],[[255524,686563],[-345,-1940]],[[255179,684623],[-2138,287]],[[253041,684910],[-1154,-414],[-744,-1062],[-1769,1264],[-522,-1416]],[[248852,683282],[661,-659]],[[249513,682623],[1216,846]],[[250729,683469],[1064,-2083],[-1018,-1191]],[[250775,680195],[576,-1180]],[[251351,679015],[1383,-1287]],[[252734,677728],[-939,-786],[-1454,2298],[-487,-158]],[[249854,679082],[-446,-1934]],[[249408,677148],[-463,1127]],[[248945,678275],[-1031,-974],[-1498,937],[127,998],[-1802,2243]],[[244741,681479],[-1021,-1654]],[[243720,679825],[-1140,239],[-1402,1077],[-1967,184]],[[239211,681325],[250,991]],[[239461,682316],[-849,-1818]],[[238612,680498],[-1885,-726]],[[236727,679772],[101,1198],[-781,-283]],[[236047,680687],[374,-1965]],[[236421,678722],[-1070,-2410]],[[235351,676312],[-1612,-1917]],[[233739,674395],[-2185,406],[609,-1490]],[[232163,673311],[-1703,-2153]],[[230460,671158],[-707,-2508]],[[229753,668650],[-739,-4166],[424,-3382]],[[229438,661102],[711,-2577]],[[230149,658525],[-218,-2228],[-784,-3382],[-447,-3701],[-527,-10459],[611,-6048],[1434,-5857],[1848,-4415],[463,-3117],[1301,-3490],[1776,-319],[1065,-1103],[700,-2013],[992,121],[1769,1394],[1854,226],[486,847],[2045,617],[474,-1453],[748,-83],[718,995],[-448,1572],[1937,2740],[128,2237],[516,1078],[65,3818],[364,2684],[1481,1571],[2614,827],[2076,1195],[2446,-1000],[340,1034],[845,-1184],[-112,-3179],[-990,-2239],[-684,-2400],[98,-1206],[-710,-1549],[730,-318],[-650,-1369],[438,-382],[-978,-6036],[-564,1513],[68,1863],[-733,-2171]],[[254734,614156],[551,-2078],[-485,-3032],[-115,-5789],[-1061,-2281],[-552,-2116]],[[253072,598860],[807,-749],[26,1103],[1016,-1311]],[[254921,597903],[1695,1071],[1975,-874],[1529,124],[1591,1301],[834,-612],[1417,535],[1150,-1113],[828,122],[1392,-3568],[317,877],[1358,-2223]],[[269007,593543],[-402,-1132],[318,-2737],[-624,-2035],[-431,-4006],[-30,-3870],[-489,-979],[205,-2829],[-412,-968],[492,-1297],[-601,-2026],[628,-2268]],[[267661,569396],[538,-2674],[1861,-4718],[596,-550]],[[270656,561454],[536,-878],[352,-2352],[1288,-440],[1182,-1047],[1434,632],[1976,1912],[1528,2298],[2980,-1135],[1171,-1007],[1968,-3424]],[[285071,556013],[1756,-3888],[-495,3387],[1788,2461],[392,1638],[1378,1095],[-113,1655],[650,5220],[1671,2955],[1084,-715],[149,-1326],[949,3409],[2071,-266],[1644,2467],[1241,1049],[387,1774],[1170,1371],[1256,-502],[347,-1712],[-507,-1093]],[[301889,574992],[-1770,-1729],[996,-4999],[-184,-1673],[-1245,-3722],[978,-2843],[206,-1559],[1080,314],[589,1319],[92,2119],[-927,3305],[-439,3051],[208,1099],[3436,2422],[965,423],[189,1349],[-1043,-281],[-261,1548],[785,1729],[482,-1080],[553,-3055],[1108,229],[1124,-514],[1192,-1604],[719,-3959],[745,-123],[2452,821],[2061,128],[1098,-2218],[2008,-1112],[773,166],[1840,2131],[904,594],[-1209,457],[2226,48],[2206,631],[2286,-52],[-1390,-1150],[-1482,-92],[576,-1175],[-96,-1641],[627,711],[540,-2329],[558,1196],[801,-1492],[673,957],[777,-1549],[1436,-1614],[-724,-1573],[-540,-2932],[-1031,-17],[874,-1108],[1397,1077],[1280,217],[896,-471]],[[333284,555367],[2271,-2812],[1593,-3133],[415,-1304],[-379,-4877],[552,2066],[1201,-387],[2201,-4080],[-13,-3251]],[[341125,537589],[625,2633],[2862,-1170],[309,985],[2763,158],[2165,-1069],[-283,-2660]],[[349566,536466],[858,2508],[1091,-1296],[1542,-820],[2337,-4193],[362,-1666],[395,796],[369,-3017]],[[356520,528778],[293,1479],[909,-1288],[465,-4809],[1038,-6348],[611,-2256],[1394,-1005],[162,-2944],[-1099,-1939],[-1450,-3930],[-1296,-1526],[-337,-1822],[-829,-2189],[-51,-1518],[-832,-2254],[-580,216],[-1208,-1121],[1991,-207],[2923,3845],[-63,-1052],[633,-3830],[797,-1504],[1122,1088],[777,-560],[1126,1153],[-583,-5125],[869,4031],[611,514],[780,2026],[687,-748],[37,2776],[930,2417],[1991,656],[1630,-906],[539,-1131],[1106,-360],[1596,-1875],[516,-50],[360,-2140],[702,1487],[1181,-1655],[316,-1818],[-347,-1900],[631,1216],[-794,-5771],[788,1172],[359,2424],[562,248],[-241,-1873],[722,1339],[1327,483],[208,746],[1232,-527],[1909,-1937],[1037,269],[1549,-1123],[2344,832],[1417,-390],[4135,-5071],[1186,-2956],[1174,-2226],[901,-716],[354,-1181],[1622,-1097],[1696,256],[1195,-446],[873,-2590],[687,-4899],[508,-5301],[-81,-4047],[-898,-5683],[-508,-1778],[-1408,-3208],[-1530,-4216],[-1498,-1993],[-1318,-4010],[-768,-3571],[-1531,-4409],[-720,-666],[-534,1971],[-446,-985],[46,-2116],[-706,-2612],[225,-3039],[-142,-3281],[497,-7164],[-679,-5328],[-251,-3272],[170,-2299],[-924,-1697],[-703,-3848],[111,-3780],[-837,-2749],[-1097,-4903],[-1092,-1994],[-717,-3552],[165,-2457],[-374,-972],[-1620,-1334],[-763,-1606],[-172,-2171],[-2544,-118],[-355,1444],[-384,-1587],[-1783,478],[-2142,-859],[187,-1295],[-1060,-636],[-1424,-2495],[-1411,42],[-2486,-2612],[-750,-1522],[-2054,-2987],[-907,-2483],[-554,856],[-804,-1300],[808,-627],[-400,-1295],[-369,-5255],[344,-2921],[-246,-2144],[61,-3067],[-497,-2961],[-1310,-1753],[-1319,-2915],[-798,-2593],[-739,-3702],[-890,-2796],[-1478,-3452],[-2465,-3759],[-66,1686],[1062,330],[1407,2576],[35,1309],[1311,2457],[120,2768],[-1420,-755],[-850,-4078],[-1413,-1962],[-614,-2972],[183,-1672],[-595,-1612],[-863,-4135],[-1995,-3581]],[[351748,304813],[-1152,-3781],[-1065,-1720],[-2038,-1553],[-2141,931],[-1235,-783],[-2048,1370],[-877,1329],[-1829,-148],[-1586,3347],[102,4325],[781,1710],[-330,2500]],[[338330,312340],[84,-2889],[-705,-902],[-340,-3270],[429,-3137],[-369,-611],[672,-2295],[1444,-1250],[1278,-1741],[402,-1881],[-542,-1270],[247,-2511],[1575,-1673],[72,-2517],[-2010,-5292],[-420,-2021],[-1756,-2074],[-4581,-2384],[-3566,-917],[-1362,-35],[-2145,865],[221,-2313],[670,-773],[-216,-2676],[-432,-414],[-389,-2729],[502,-1888],[-413,-1281],[-1567,-1296],[-2261,-240],[-2999,1993],[-779,-396],[319,-4067],[-113,-2387],[1520,-1779],[-164,-865],[1306,125],[-355,1048],[1203,618],[554,-1733],[-268,-2363],[-1217,-332],[-538,1713],[-906,242],[-1046,-1348],[1966,-1244],[-1851,-1924],[-828,-1993],[125,-2481],[-340,-2539],[-796,-1090],[25,-2053],[-1532,255],[-2087,-1733],[-1709,-4223],[-18,-2223],[2184,-3913],[2162,-521],[724,-1488],[-545,-2854],[345,-678],[-1620,-2377],[-1777,-1691],[-1811,-3667],[-274,-3627],[-1316,-1455],[-1140,2086],[683,-2402],[-1438,-1330],[-726,-3621],[476,-2683],[-919,-671],[1232,-918],[1315,-3804]],[[309879,194532],[-2215,896],[-888,-1280],[-3429,-2057],[-558,-5987],[-839,-617],[-2435,1488],[-365,2243],[1570,125],[1627,2293],[-647,481],[-2973,-2904],[-252,-1222],[-1400,1288],[1047,2929],[3235,851],[-3148,452],[-1327,-3229],[-1452,1405],[1123,769],[-2149,402],[-781,3089],[1281,-689],[417,927],[1519,-309],[1800,2170],[-2483,-1815],[-2259,2307],[741,371],[94,1697],[-2552,1590],[-778,2262],[1136,114],[115,1784],[1262,-2471],[13,1734],[-1234,1726],[822,1300],[119,2195],[1109,-116],[-1319,1322],[-43,3594],[585,2171],[-842,-216],[-306,2754],[2708,30],[-295,2006],[-625,-1623],[-1138,-89],[-845,1433],[1379,3080],[-431,2336],[-463,-578],[-1848,1693],[-1420,-61],[2034,2669],[-395,1687],[2525,640],[334,2069],[590,-172],[-712,-4058],[1074,1612],[-322,-3067],[413,474],[188,3084],[-379,1759],[1468,747],[-674,686],[229,1540],[1732,1446],[209,1764],[-1670,1586],[745,3182],[-290,1045],[620,2411],[258,4425],[985,-785],[-192,2682],[-901,428],[428,1477],[-959,686],[-630,-1405],[-1370,228],[-641,3698],[823,6137],[720,1737],[511,3346],[-850,5081],[188,1934],[-547,2025],[167,3022],[1071,128],[272,2835],[676,1765],[697,4767],[1111,2900],[614,5515],[940,3038],[-218,3303],[419,744],[474,3452],[-668,7212],[-21,4971],[747,1110],[235,2923],[-565,4285],[925,3250],[371,3854],[1128,8282],[-186,3230],[745,3623],[-358,3130],[240,5110],[265,1279],[-543,1170],[69,1845],[643,1234],[678,8031],[-304,4548],[136,5452],[-751,8647]],[[304393,396029],[-2552,3929],[-542,2300],[-1608,1728],[-990,1745],[-907,554],[-2864,2735],[-894,1424],[-2659,2965],[-1193,3037],[-1112,1575],[-1229,4565],[535,2060],[-1801,6912],[-890,1708],[-188,2352],[-1147,2225],[-286,2672],[-1248,4430],[-1602,8720],[-695,2411],[-1014,2220],[-1068,4555],[-968,2471],[-2866,3512],[140,1448],[581,316],[-792,3507],[164,825],[-633,2123],[148,2057],[1346,3503],[1317,2033]],[[276876,484646],[1119,1764],[533,3027],[-769,1335],[-772,-2091],[-1884,3066],[535,667],[-87,4107],[-280,1804],[968,1368],[199,2841],[969,2146],[301,2467],[-176,2219],[964,1156],[2338,1341],[111,1476]],[[280945,513339],[-460,998],[645,1333],[601,-444],[-112,3158],[1381,1074],[1250,2315],[1647,6128],[-973,872],[391,3918],[-320,4114],[-369,716],[792,1440],[-611,2350],[304,1942],[-1503,4294]],[[283608,547547],[-747,1863],[-699,3064],[855,1888],[-2702,3658],[-986,53],[-683,-919],[-175,-1513],[-1718,-1818],[-248,-1254],[1241,-3418],[-1188,-1334],[-1129,-325],[-868,3758],[-170,-1383],[-792,594],[-620,2467],[-1411,1027],[-1234,65],[-555,-1489]],[[269779,552531],[-786,3066],[-854,703],[495,-1782],[-1229,1235],[269,2494],[-717,1428],[-2121,2193],[-156,1498],[-1522,2116],[1046,-2581],[-633,-1417],[-556,1358],[-862,542],[-572,2936],[454,2055],[-669,904],[454,975]],[[261820,570254],[-601,1595],[-1412,2411],[-795,2479],[-2533,4425],[917,448]],[[257396,581612],[-422,2214],[-903,274]],[[256071,584100],[-324,-1295],[-2600,608],[-1141,1154],[-1462,486],[-809,1045]],[[249735,586098],[-1421,1141],[-1498,-20],[-1869,1793],[-1156,1879]],[[243791,590891],[-1594,3514],[-3075,5421],[-2071,878],[-664,1278],[-1566,-2624],[-2081,-1668],[-826,-244],[-1873,1525],[-1582,341],[-1067,1419],[-1060,583],[-672,1363],[-2579,1095],[-927,1190],[-2287,1659],[-2090,2672],[-686,1604],[-2368,833],[-2062,1555],[-1307,2980],[-2850,2850],[-1510,3949],[-520,2427],[1136,1146],[-645,1170],[710,2030],[78,2201],[-618,755],[-605,2191],[9,2008],[-405,1781],[-1696,3365],[-1896,4861],[-1229,2038],[43,765],[-1221,745],[-712,2132],[478,359],[-1987,2304],[-772,333],[395,1499],[-861,-835],[-523,797],[-113,1810],[627,1615],[-786,2400],[-756,-44],[-525,2230],[-1483,1442],[-383,1962],[238,1246],[-1643,609],[-973,2471],[-579,513],[-1338,3248],[-171,1485],[-1430,4241],[-1034,4787],[177,2286],[-1603,987],[-900,1680],[-560,-723],[-2178,2330],[399,-1502],[-257,-2907],[691,-3848],[-45,-1593],[770,-2416],[1714,-2742],[710,-2611],[818,-758],[310,-1700],[620,-519],[380,-3544],[1124,-1793],[904,-2632],[392,-2373],[187,1192],[627,-1020],[659,-3449],[112,-1989],[716,-1557],[991,-4374],[51,-2649],[811,-1428],[290,1446],[667,-1007],[1672,-4114],[-103,-1572],[-1293,-1949],[-452,709],[-769,3551],[-2934,4290],[-1815,3028],[47,3840],[-893,4299],[-1788,2188],[-375,2151],[-1230,-1333],[-673,1453],[-1679,1491],[-263,1261],[-1379,2434],[1296,-343],[748,527],[700,3278],[-269,1062],[-2357,4615],[-1888,2203],[-394,3242],[-501,657],[-184,2309],[-1667,4507],[115,1695],[-631,867],[-778,3175]],[[174644,697459],[-943,4516],[-1703,2527],[-916,129]],[[171082,704631],[-267,1620],[-1770,561]],[[169045,706812],[-1284,1813]],[[167761,708625],[-2431,318]],[[165330,708943],[-454,642]],[[164876,709585],[31,2941]],[[164907,712526],[-630,1712]],[[164277,714238],[-2825,5721],[-10,3601]],[[161442,723560],[-1429,1591]],[[160013,725151],[-330,3344],[1232,-1740]],[[160915,726755],[-875,2858],[1857,435]],[[161897,730048],[-2130,443],[-104,-1673]],[[159663,728818],[-1141,1357],[-525,2333]],[[157997,732508],[-1611,2713],[-511,5649],[-1220,2318]],[[154655,743188],[-132,1417]],[[154523,744605],[663,2836]],[[155186,747441],[179,2455]],[[155365,749896],[-796,4376]],[[154569,754272],[-513,4088],[1086,5207]],[[155142,763567],[249,6434]],[[155391,770001],[361,4735]],[[155752,774736],[49,3585]],[[155801,778321],[1918,-169]],[[157719,778152],[-677,696]],[[157042,778848],[-1689,49]],[[155353,778897],[-108,4478]],[[155245,783375],[-734,3693]],[[154511,787068],[-681,1455]],[[153830,788523],[-247,2821]],[[153583,791344],[2040,-1255]],[[155623,790089],[2642,-516]],[[158265,789573],[683,333]],[[158948,789906],[557,-5003]],[[159505,784903],[623,465],[-108,2659],[419,1127],[-1186,2693]],[[159253,791847],[344,1760]],[[159597,793607],[-677,1367]],[[158920,794974],[-724,0]],[[158196,794974],[-795,2762]],[[157401,797736],[-1545,209]],[[155856,797945],[-35,2883]],[[155821,800828],[-659,-1117]],[[155162,799711],[-753,-87],[-1027,1435]],[[153382,801059],[-768,2925]],[[152614,803984],[-3864,212],[1534,798]],[[150284,804994],[-1721,237]],[[148563,805231],[-319,1130]],[[148244,806361],[-1182,-282]],[[147062,806079],[-1807,1681]],[[145255,807760],[176,1939]],[[145431,809699],[-623,1758]],[[144808,811457],[214,3046]],[[145022,814503],[-863,-2968]],[[144159,811535],[-708,2195]],[[143451,813730],[699,4431]],[[144150,818161],[-721,-480]],[[143429,817681],[-797,2477],[-1191,731]],[[141441,820889],[-93,1622],[1590,-1307]],[[142938,821204],[-1159,2494]],[[141779,823698],[-903,-2657]],[[140876,821041],[-776,-838],[-2144,2799]],[[137956,823002],[811,2426],[-1073,1704],[2414,6170]],[[140108,833302],[-1178,-614]],[[138930,832688],[-111,3136]],[[138819,835824],[-33,-3497]],[[138786,832327],[-492,-1612]],[[138294,830715],[-1003,-1519]],[[137291,829196],[-763,226],[-550,2074]],[[135978,831496],[591,1033]],[[136569,832529],[-848,3942]],[[135721,836471],[-1788,-716]],[[133933,835755],[-554,-2023]],[[133379,833732],[-667,1102],[1054,2601]],[[133766,837435],[-2970,5257]],[[130796,842692],[-1535,739]],[[129261,843431],[-245,3098]],[[129016,846529],[-1818,3185],[-1265,901]],[[125933,850615],[-1300,2714],[-643,3415],[-387,-1286],[1259,-5305]],[[124862,850153],[-2288,517],[-760,2339]],[[121814,853009],[-2340,1455]],[[119474,854464],[2577,-3446],[-1447,-1231]],[[120604,849787],[-2671,1992]],[[117933,851779],[-2246,2998]],[[115687,854777],[-4019,2719]],[[111668,857496],[796,900],[-18,1888],[-1937,-1719]],[[110509,858565],[-1741,131]],[[108768,858696],[-2296,1310]],[[106472,860006],[-3544,753]],[[102928,860759],[-3338,-478],[-2094,1888]],[[97496,862169],[584,1979]],[[98080,864148],[-1548,-1712],[-1808,581]],[[94724,863017],[-2054,2483]],[[92670,865500],[155,1366]],[[92825,866866],[-2243,-1243],[-1708,299],[704,1484]],[[89578,867406],[-2237,-2466],[1647,-1883]],[[88988,863057],[-1297,-2937]],[[87691,860120],[-2679,691]],[[85012,860811],[-563,-1987]],[[84449,858824],[-2732,-1219]],[[81717,857605],[-980,-1869]],[[80737,855736],[-2232,-359],[-311,1290],[1251,652],[-1261,1574]],[[78184,858893],[1116,2491]],[[79300,861384],[265,3083],[2543,1781],[2357,-176]],[[84465,866072],[-980,1780],[-1852,41],[-3117,-2313]],[[78516,865580],[-46,-923],[-2510,-3061]],[[75960,861596],[-292,-1880]],[[75668,859716],[-1255,-464]],[[74413,859252],[-2436,-2840]],[[71977,856412],[-250,-1231]],[[71727,855181],[2343,-1763]],[[74070,853418],[-1904,-2162]],[[72166,851256],[-630,-1976]],[[71536,849280],[-2112,-849],[-2141,-2654]],[[67283,845777],[-1945,-1424]],[[65338,844353],[-420,-1884]],[[64918,842469],[-3444,-2160],[-1857,-1836]],[[59617,838473],[-700,-2064]],[[58917,836409],[-2649,-848]],[[56268,835561],[-2100,-1816],[-2726,-826]],[[51442,832919],[60,1370]],[[51502,834289],[-1708,-2902]],[[49794,831387],[-1299,613],[-369,-1458],[-1835,-933]],[[46291,829609],[156,1675]],[[46447,831284],[1035,437]],[[47482,831721],[2081,3103]],[[49563,834824],[2616,1788]],[[52179,836612],[2565,-1280]],[[54744,835332],[-686,1192],[658,1823]],[[54716,838347],[3644,3235]],[[58360,841582],[3480,4076]],[[61840,845658],[594,5174]],[[62434,850832],[1060,2703]],[[63494,853535],[-2444,-1407]],[[61050,852128],[-2094,1554]],[[58956,853682],[-36,-2735]],[[58920,850947],[-817,171],[-1633,2615]],[[56470,853733],[-694,-540]],[[55776,853193],[-1229,1370]],[[54547,854563],[-2774,-2261]],[[51773,852302],[-2177,-150]],[[49596,852152],[1169,889],[-831,2901]],[[49934,855942],[541,1805],[-1646,4120]],[[48829,861867],[788,2379],[-1521,-2468],[319,-1655],[-3712,-1083],[-2099,2944],[-1920,1407],[1524,2078]],[[42208,865469],[2985,-1789]],[[45193,863680],[860,991]],[[46053,864671],[-4875,1234]],[[41178,865905],[833,718]],[[42011,866623],[-2265,1262],[-1324,2079]],[[38422,869964],[1541,1295]],[[39963,871259],[-262,1369]],[[39701,872628],[1425,2211],[1153,45]],[[42279,874884],[-183,1894]],[[42096,876778],[2048,2730],[2081,-1279]],[[46225,878229],[2049,1303],[939,1561]],[[49213,881093],[3288,170],[891,1546]],[[53392,882809],[-581,2562]],[[52811,885371],[-1186,1629]],[[51625,887000],[1341,313]],[[52966,887313],[-707,2043],[-1591,-638]],[[50668,888718],[-2910,-2619]],[[47758,886099],[-2518,1268]],[[45240,887367],[-3294,-756]],[[41946,886611],[-3455,724]],[[38491,887335],[-757,2036]],[[37734,889371],[-1425,1365],[2031,880]],[[38340,891616],[-3351,690],[-1901,1397]],[[33088,893703],[2816,1300]],[[35904,895003],[4514,3156]],[[40418,898159],[4783,1224]],[[45201,899383],[-850,-2375]],[[44351,897008],[940,-780],[5219,-179]],[[50510,896049],[1003,1348],[-1036,531]],[[50477,897928],[-2165,3101]],[[48312,901029],[1639,-653]],[[49951,900376],[300,-1330]],[[50251,899046],[3496,-1106]],[[53747,897940],[1079,1182]],[[54826,899122],[-1672,583],[-1483,-705]],[[51671,899000],[-1273,880]],[[50398,899880],[651,1653]],[[51049,901533],[-3832,284]],[[47217,901817],[-1997,997]],[[45220,902814],[-1123,2436],[-3503,2600]],[[40594,907850],[-3890,1860],[1128,389],[476,2725]],[[38308,912824],[5296,304],[3170,2675],[580,2193],[2441,2391],[2993,846]],[[52788,921233],[4671,3400],[3655,-196],[4246,3331],[6320,-3593]],[[71680,924175],[2673,779],[2778,-724]],[[77131,924230],[-661,-929]],[[76470,923301],[3461,-1391]],[[79931,921910],[5432,486],[4343,-1680],[5230,-340],[1738,-896]],[[96674,919480],[5497,638],[5029,-2744]],[[107200,917374],[1127,-14]],[[108327,917360],[5056,-801],[2927,-2154]],[[116310,914405],[7684,-2700]],[[123994,911705],[-1429,1308],[514,2335]],[[123079,915348],[4976,1286],[-762,-1632]],[[127293,915002],[2808,1073]],[[130101,916075],[898,1283]],[[130999,917358],[4733,1519]],[[135732,918877],[1772,1400]],[[137504,920277],[2361,-862]],[[139865,919415],[-3643,-2166],[-2508,-490]],[[133714,916759],[-4211,-3927]],[[129503,912832],[1868,-424],[-35,1565]],[[131336,913973],[2585,2091],[2153,-21]],[[136074,916043],[118,-1301],[1714,2648],[3456,1339]],[[141362,918729],[384,-1004]],[[141746,917725],[3576,3246],[-853,1857]],[[144469,922828],[2368,-1982]],[[146837,920846],[1462,-3015],[3403,-2258]],[[151702,915573],[516,2842]],[[152218,918415],[2103,1669],[888,-2492]],[[155209,917592],[-837,-1840]],[[154372,915752],[2268,-13]],[[156640,915739],[1622,2564]],[[158262,918303],[4151,-203]],[[162413,918100],[3441,-2104],[3955,-969]],[[169809,915027],[2149,-1268],[5654,-1220],[1190,803]],[[178802,913342],[3382,-1855],[1248,-1543]],[[183432,909944],[-2225,-763],[-1858,-2181]],[[179349,907000],[4868,-1198]],[[184217,905802],[3463,-90]],[[187680,905712],[4527,874],[1954,948]],[[194161,907534],[1310,-1538]],[[195471,905996],[2882,-840]],[[198353,905156],[1843,-2750]],[[200196,902406],[-1574,-204]],[[198622,902202],[2182,-2087],[233,1559]],[[201037,901674],[1306,-719]],[[202343,900955],[-2266,5037]],[[200077,905992],[587,1778],[3713,998]],[[204377,908768],[1785,1931]],[[206162,910699],[-2297,-1002]],[[203865,909697],[-2809,-156]],[[201056,909541],[-318,-933]],[[200738,908608],[-2645,614]],[[198093,909222],[1036,1975]],[[199129,911197],[5970,1833],[1735,-1193]],[[206834,911837],[309,-1542]],[[207143,910295],[3430,-2530]],[[210573,907765],[1999,496]],[[212572,908261],[2172,-1797],[3159,-703]],[[217903,905761],[3052,868]],[[220955,906629],[3637,-686],[2041,494]],[[226633,906437],[2659,-1127]],[[229292,905310],[690,1410]],[[229982,906720],[-2511,285],[-1500,2729]],[[225971,909734],[3444,788],[1904,-2579]],[[231319,907943],[2097,1113]],[[233416,909056],[-1115,-4119]],[[232301,904937],[639,-1671]],[[232940,903266],[1171,265]],[[234111,903531],[1016,-1990]],[[235127,901541],[265,1670]],[[235392,903211],[-1089,2813]],[[234303,906024],[528,1682]],[[234831,907706],[1666,121],[3381,3503]],[[239878,911330],[-2552,1651]],[[237326,912981],[1336,1328]],[[238662,914309],[-527,1892],[-4941,2227]],[[233194,918428],[-1376,2940],[1852,1313]],[[233670,922681],[-1862,1539],[398,2754]],[[232206,926974],[2336,374],[-854,1401]],[[233688,928749],[1864,1958]],[[235552,930707],[1789,446]],[[237341,931153],[4468,-4247]],[[300051,207169],[-2273,162],[-1078,1268],[-288,-1355],[935,-2423],[-49,1561],[2753,787]],[[299149,209912],[125,889],[-1858,1013],[-276,-1382],[2009,-520]],[[302316,229071],[-1891,1251],[-1754,-1661],[-682,497],[-140,-2140],[1434,1704],[1323,512],[1710,-163]],[[309232,235614],[-815,831],[338,-2143],[477,1312]],[[297313,260123],[1023,603],[-694,1240],[-329,-1843]],[[352392,311289],[-108,-176]],[[352284,311113],[-1241,-2707],[224,-2392]],[[351267,306014],[47,-79]],[[351314,305935],[328,2335],[1093,2133],[674,-457],[498,2232],[-353,1780],[-1162,-2669]],[[327139,322385],[-161,1110],[-989,404],[-932,-1013],[701,-1336],[1381,835]],[[349258,362140],[-575,-4635],[-661,-1153],[536,-871],[-254,-1439]],[[348304,354042],[1138,1142],[-491,355],[329,3186],[-22,3415]],[[357177,383706],[1398,630],[-63,1361],[-1365,-992],[30,-999]],[[375077,393444],[-787,942],[-393,-2275],[1180,1333]],[[307956,408551],[363,-118]],[[308319,408433],[-123,-1621]],[[308196,406812],[119,-148]],[[308315,406664],[1162,1474],[-670,661],[92,1293],[-1567,2729]],[[307332,412821],[-125,120]],[[307207,412941],[-782,1344],[-698,-797],[-202,-2544],[1566,-1193],[-100,-903],[965,-297]],[[386332,449873],[-955,-620],[1,-1374],[-2042,457],[-987,-1134],[-18,-1639],[-573,-510],[-130,-2422],[-562,101],[197,-1444],[-1153,-2421],[1101,-162],[107,1778],[988,2462],[591,-1433],[-573,2822],[1189,2400],[2077,501],[251,1197],[713,268],[-222,1173]],[[361918,478518],[-11,-1010],[1199,-4197],[-183,2487],[-773,6122],[-664,-2804],[432,-598]],[[347518,533051],[241,742],[-889,541],[-578,-2791],[1280,431],[-54,1077]],[[264404,571429],[-1236,3095],[-1495,1921],[-282,-2397],[1061,-2885],[1724,-1068],[228,1334]],[[260823,577661],[-529,957],[-819,-406],[762,-1350],[586,799]],[[253117,597801],[-1417,-1326],[859,-263],[558,1589]],[[214693,624354],[-509,739],[-1329,-346],[1629,-807],[209,414]],[[229370,654923],[-756,-1152],[-164,-7372],[197,3327],[723,5197]],[[223732,665013],[790,-2918]],[[224522,662095],[147,1097],[-937,1821]],[[276031,664008],[-361,1749],[-824,-1134],[869,-1739],[316,1124]],[[178856,701850],[-936,1451],[-314,-514],[758,-1695],[492,758]],[[256497,710969],[1819,-777],[-1046,1001],[-773,-224]],[[184345,716995],[-1002,2446],[-638,-1149],[-571,1110],[-1069,-685],[1689,-686],[611,942],[980,-1978]],[[255397,721963],[-173,-1865],[581,-993],[-408,2858]],[[193423,729241],[-1653,-4426],[1470,3320],[183,1106]],[[311702,775814],[-211,-115]],[[311491,775699],[1149,-785]],[[312640,774914],[-32,205]],[[312608,775119],[-906,695]],[[276535,778914],[1280,-720],[1530,442],[-605,728],[-2205,-450]],[[287558,783985],[198,1824],[-1143,423],[945,-2247]],[[285352,786669],[38,-1448],[902,834],[-940,614]],[[305332,797621],[505,623],[-1163,1887],[-1107,-2007],[556,-676],[646,1365],[563,-1192]],[[255471,800710],[-1691,1871],[-706,-1305],[-186,-3291],[694,508],[1473,-716],[416,2933]],[[204952,786635],[-300,2367],[-1680,-1540],[-2177,-222],[2364,-334],[1329,1284],[464,-1555]],[[216258,786530],[2076,-365],[547,822],[-2660,-124],[-373,1705],[-374,-2070],[784,32]],[[292969,791821],[1197,-526],[-1333,1584],[62,966],[-2380,-2160],[2023,-479],[431,615]],[[299848,791779],[775,925],[-1541,348],[766,-1273]],[[241895,791656],[1342,-252],[-997,1806],[-1634,-469],[1900,-587],[-611,-498]],[[277277,793902],[869,-1058],[1584,-150],[-1498,1579],[-955,-371]],[[236909,794206],[1774,1729],[-1590,1716],[1090,153],[-791,2728],[-137,-1229],[-1568,-600],[125,-942],[1165,961],[-1591,-2895],[-35,-1486],[1558,-135]],[[289481,768262],[-51,62]],[[289430,768324],[-700,-759]],[[288730,767565],[-2596,-1733],[313,-777]],[[286447,765055],[-914,-398]],[[285533,764657],[-1043,963]],[[284490,765620],[-4103,-1205]],[[280387,764415],[-1412,-1521],[-570,-1532]],[[278405,761362],[1213,-722]],[[279618,760640],[345,264]],[[279963,760904],[445,254]],[[280408,761158],[2439,649]],[[282847,761807],[1794,-755],[1535,60]],[[286176,761112],[2069,1618],[-157,1767]],[[288088,764497],[604,887]],[[288692,765384],[-782,637]],[[287910,766021],[1571,2241]],[[296185,766268],[405,1760],[224,3722],[-656,-811],[27,-4671]],[[279310,767227],[793,829],[-583,1473],[-210,-2302]],[[221420,771418],[-171,4958],[-770,-1223],[788,-1524],[153,-2211]],[[188961,747632],[-2295,3939],[-448,-1716],[1643,-4008],[1100,1785]],[[269232,755176],[1352,232]],[[270584,755408],[-154,1442]],[[270430,756850],[-395,631]],[[270035,757481],[-1858,-5463],[2711,-2040]],[[270888,749978],[2103,669]],[[272991,750647],[1374,1537]],[[274365,752184],[2483,1602],[3126,3047],[921,1445]],[[280895,758278],[-523,1818]],[[280372,760096],[25,-1444]],[[280397,758652],[-3232,-520]],[[277165,758132],[-641,-953],[-2648,97],[-1340,-2209],[-1992,-1373],[-1399,271],[87,1211]],[[264522,776026],[3593,-2701]],[[268115,773325],[515,-1768],[-3,-2116]],[[268627,769441],[-101,-1826]],[[268526,767615],[-1523,-2444]],[[267003,765171],[399,-1990]],[[267402,763181],[979,1761]],[[268381,764942],[1210,848]],[[269591,765790],[788,-1261]],[[270379,764529],[684,-4957]],[[271063,759572],[1758,1833],[212,4762]],[[273033,766167],[1140,2761],[54,1145],[-1164,2733],[1113,-15]],[[274176,772791],[103,-1306]],[[274279,771485],[1011,-1465]],[[275290,770020],[1860,-1609]],[[277150,768411],[327,1762]],[[277477,770173],[1086,-270],[-1024,2062]],[[277539,771965],[124,1381]],[[277663,773346],[-857,337]],[[276806,773683],[-1300,3269],[-2164,92]],[[273342,777044],[-52,905]],[[273290,777949],[-3917,367],[-2962,1064]],[[266411,779380],[-204,1195]],[[266207,780575],[-931,-470]],[[265276,780105],[321,2503]],[[265597,782608],[-1074,776]],[[264523,783384],[492,1679],[-1166,1888],[443,1843]],[[264292,788794],[-2565,120],[-905,1422],[-812,3086]],[[260010,793422],[-2298,265]],[[257712,793687],[-2889,1172]],[[254823,794859],[85,-2231]],[[254908,792628],[-749,1398]],[[254159,794026],[-755,-1481]],[[253404,792545],[-1184,-783]],[[252220,791762],[-963,-2595]],[[251257,789167],[-159,-126]],[[251098,789041],[-3757,-2772]],[[247341,786269],[-3076,-4176],[1571,-312]],[[245836,781781],[1536,1111]],[[247372,782892],[581,-1569]],[[247953,781323],[744,-620],[3094,1764],[1957,2074]],[[253748,784541],[560,-2551]],[[254308,781990],[647,889]],[[254955,782879],[1606,-740],[777,-1790],[2002,-423],[1404,1385]],[[260744,781311],[3234,497]],[[263978,781808],[-185,-1570]],[[263793,780238],[1964,-86]],[[265757,780152],[279,-1823]],[[266036,778329],[689,-1315],[-1813,540],[-473,-1056]],[[264439,776498],[-1622,1388],[-3271,-1340]],[[259546,776546],[-1141,-944]],[[258405,775602],[-23,1149]],[[258382,776751],[-2355,-5774],[-386,-2314]],[[255641,768663],[1013,1747]],[[256654,770410],[742,-421]],[[257396,769989],[-1568,-9070],[335,-2911],[-45,-3211]],[[256118,754797],[1069,-3288],[943,77],[1224,1433]],[[259354,753019],[925,2999]],[[260279,756018],[215,2861]],[[260494,758879],[-889,4365]],[[259605,763244],[64,2586]],[[259669,765830],[620,1522]],[[260289,767352],[163,2308],[1724,2799],[187,-2494],[482,2993]],[[262845,772958],[1135,685]],[[263980,773643],[-40,2219]],[[263940,775862],[582,164]],[[304140,818688],[-1150,-344],[1394,-1772],[-244,2116]],[[65144,846949],[-1377,-1292],[582,-619],[795,1911]],[[66775,847565],[-2377,1168],[-43,-804],[2420,-364]],[[204838,846536],[-2252,-1307],[-60,-1422],[2764,1356],[-452,1373]],[[159718,836983],[-4078,-138],[-2403,3863],[2182,-4682],[2444,-3138],[-1641,2784],[123,902],[1602,-244],[1771,653]],[[294473,836638],[-896,1402],[-1408,66],[1583,-1987],[721,519]],[[287370,837457],[1688,160],[-1186,2129],[-502,-2289]],[[226959,845332],[-1977,-3354],[-895,360],[-623,-1640],[1940,770],[1679,1606],[709,1631],[-833,627]],[[217431,847801],[-739,1057],[-2498,-3777],[890,-3675],[-1994,-3118],[2283,1800],[1750,3923],[-717,578],[1529,2656],[-504,556]],[[224031,819892],[-1513,331],[-906,2234],[-20,2267],[993,1014],[-1359,95],[100,-3610],[-1444,-985],[2419,-1946],[1424,-267],[306,867]],[[288610,823079],[-1655,-222],[1641,2468],[-731,426],[-1104,-1648],[-2553,-1367],[1384,-1103],[3449,1143],[-435,-1247],[3825,2261],[-3126,-11],[-695,-700]],[[238232,823064],[293,934],[-2229,-387],[1936,-547]],[[307358,825126],[-1409,1693],[-785,-1418],[2194,-275]],[[249008,823252],[2079,32],[-1092,680],[-987,-712]],[[324512,825405],[-1589,-197],[-1719,3075],[-270,-2147],[-2602,-1459],[-1492,1564],[-1366,3216],[-533,-1128],[360,-2072],[598,1214],[2607,-3549],[-532,-2308],[1414,-406],[-675,2221],[1942,1945],[2048,-1578],[1809,1609]],[[239103,829583],[-1539,-201],[-796,-2306],[3100,2177],[-765,330]],[[210011,831510],[-625,870],[-1711,-523],[0,-1552],[2336,1205]],[[296716,831144],[381,-900],[2277,1985],[-2658,-1085]],[[200587,831811],[341,3160],[-1051,-1398],[710,-1762]],[[198441,839505],[801,-1889],[-1089,-3686],[1506,2928],[134,1892],[-1352,755]],[[72301,858817],[-990,131],[-4216,-1503],[284,-1203],[3138,692],[1784,1883]],[[189398,851653],[-1446,1288],[-156,-1182],[1679,-1461],[-77,1355]],[[214341,850290],[-320,1200],[-1828,-734],[-127,-2899],[1236,-540],[-55,1497],[1094,1476]],[[196575,855010],[3878,528],[1660,785],[-6410,1314],[-4764,-5137],[519,-1174],[1843,746],[1460,2225],[1814,713]],[[45922,862634],[-1068,118],[227,-1580],[841,1462]],[[237151,884822],[-4381,983],[1163,-1590],[3218,607]],[[200152,884438],[1232,-1804],[1100,618],[-602,1404],[-1730,-218]],[[197160,876811],[-4173,820],[-2413,-1321],[-2524,-3480],[-3534,-686],[-2077,2354],[-1088,-236],[-1597,1370],[-2081,700],[2129,-1535],[-52,-1359],[1818,-2182],[-2561,-761],[-1090,-3303],[-2260,868],[-1431,-1376],[5015,-1535],[4558,940],[432,1804],[1965,529],[2115,1386],[1725,2991],[2287,2467],[2858,615],[-4271,-195],[1696,1256],[3781,-660],[773,529]],[[227864,875283],[1455,-753],[-604,2622],[-2211,-210],[1360,-1659]],[[174114,879194],[-2171,2142],[-1464,-1382],[2469,-1326],[1166,566]],[[223316,877713],[1289,-177],[-572,1443],[-717,-1266]],[[216848,879267],[-278,-1756],[2068,-1532],[1129,1719],[-638,1275],[1133,2222],[-3414,-1928]],[[75167,922797],[-1865,997],[-1794,-452],[1671,-1071],[1988,526]],[[235418,889826],[-1894,-1],[1059,-1426],[835,1427]],[[170371,889803],[926,-1297],[190,2480],[-1558,109],[442,-1292]],[[183061,892047],[4868,-1480],[-3543,1706],[-1325,-226]],[[172660,898241],[-5222,-665],[-2009,496],[1003,1534],[2743,1510],[-2168,714],[-5842,-2330],[-8562,-2301],[683,-1816],[882,1255],[3065,-105],[1057,709],[4826,-967],[-4470,-3583],[97,-1239],[-1648,-959],[3904,-918],[1368,2385],[2457,1431],[313,-1871],[-2558,-2428],[670,-314],[4694,3443],[-1244,1057],[1024,1162],[4406,-528],[-460,1256],[1442,2062],[-451,1010]],[[205669,860170],[-968,611],[-187,-1600],[1155,989]],[[215141,862093],[1461,-2328],[380,1831],[-1041,2430],[-800,-1933]],[[180383,862136],[-2062,-446],[1417,-860],[645,1306]],[[211567,863464],[469,1666],[-2297,-644],[1828,-1022]],[[246263,806680],[1135,-86],[1416,976],[-493,565],[-2058,-1455]],[[227891,803055],[-791,2144],[-1435,1635],[524,1471],[-1651,3160],[-1053,-372],[1063,-1009],[428,-2393],[1539,-5501],[1376,865]],[[297500,807728],[-464,1449],[-2292,-2425],[-666,-3424],[3422,4400]],[[310402,809224],[-777,2114],[-1676,-587],[-28,-2263],[1127,-2089],[1084,1348],[270,1477]],[[223127,810497],[-459,3731],[448,3890],[-2325,1609],[-1629,-536],[773,-1941],[439,1346],[1102,-643],[766,-1808],[-463,-2670],[306,-2135],[1042,-843]],[[232297,805260],[230,3092],[-1539,3645],[-982,4778],[-2150,7742],[-137,2549],[-772,-2633],[1109,-1345],[-2860,764],[-863,-3896],[1196,-2873],[1726,-2635],[1012,-2317],[909,1444],[685,-1585],[-8,-2498],[522,1313],[897,-656],[-665,-1799],[140,-4678],[985,40],[565,1548]],[[549943,856209],[1470,468],[-621,-1769],[-4158,-3105],[-647,-4580],[-77,-4409],[-1475,-5009],[-3563,-524],[-1386,-1786],[-115,-2583],[-3578,87],[257,1673],[-1309,3550],[1046,1924],[-1283,1709],[-1907,4808],[-1288,4490],[-210,3570],[535,-247]],[[531634,854476],[-1539,872],[-736,2390],[-1083,-3423],[-1559,-375],[-4034,-4745],[-1945,-736],[-2530,608],[-2356,2371],[-263,2898],[1352,-846],[-409,2542],[1256,1551],[-2893,-2338],[-641,356],[481,2466],[2520,1121],[-1338,185],[2188,3226],[-1013,-363],[-1830,-3085],[-1066,-935],[369,5343],[-653,2776],[2710,469],[2933,-155],[-1065,684],[-3701,-584],[-893,1928],[933,308],[-1141,1334],[598,2662],[3360,2673],[3717,-152],[985,1100],[-3515,-417],[635,1522],[3033,790],[1331,1316],[-504,1315],[3607,530],[784,-1359],[2170,391],[-97,970],[1793,1065],[-178,1447],[-1033,-1651],[-2808,-1472],[-859,1617],[2641,3694],[2662,1931],[-96,1372],[1862,1204],[315,2306],[2350,3925],[257,2429],[2493,2835],[3683,755],[-2654,55],[1340,1886],[1399,-731],[-449,1862],[-1451,-535],[742,1664],[2665,1616],[702,-2026],[1087,4379],[2052,1029],[5018,5619],[6210,1572],[-214,1305],[3691,837],[1593,-2260],[337,1506],[2891,2692],[957,1816],[2788,-920],[-1374,-1782],[-638,-2626],[4064,4762],[217,-2979],[2696,2473],[115,1562],[2209,-687],[-629,-4073],[1232,2796],[1369,599],[5116,-3473],[-2828,-1055],[-3180,289],[2278,-998],[96,-1165],[3428,20]],[[585749,918146],[1619,-556],[1477,1564],[2659,-1195],[-2125,-461],[559,-1156],[3629,-1000],[6038,-702],[5202,-2960],[1943,-1993],[7045,-3805],[1090,-2984],[-472,-2272],[-1854,-2249],[-3423,-1864],[-2477,-401],[-8011,1964],[-1914,1276],[-4651,1378],[-610,1440],[-2875,442],[3672,-3732],[398,-1198],[2089,-617],[1871,-2137],[-1055,-2777],[1103,-2428],[183,-2524],[2160,-1076],[1994,-2224],[2992,-1123],[1747,1259],[-326,1744],[-2139,523],[-1820,2600],[985,1926],[1792,-380],[1337,-1361],[4857,-1786],[1908,1194],[-1796,3384],[51,1470],[2431,2165],[2178,948],[2041,2348],[2841,-617],[2420,-2411],[1067,3929],[-547,2535],[-1415,917],[1231,4391],[-157,1964],[-2125,1667],[4650,-181],[2261,-582],[2218,-3738],[-3227,-540],[-1637,-2410],[1730,-980],[1177,-1969],[1407,-313],[3232,1041],[608,3603],[2786,872],[5447,3665],[4181,1530],[4050,2297],[358,-3321],[-1862,-994],[4447,-389],[1546,2168],[1738,480],[3009,-562],[2906,1989],[2456,689],[870,-1586],[-754,-1742],[2218,-132],[-4,1685],[1648,134],[1234,1527],[-2119,3579],[2348,1544],[6515,-1044],[7565,-3785]],[[683568,913720],[921,-525]],[[684489,913195],[1628,-440],[3802,-3313],[2137,3770],[-1660,97],[-1492,3039],[-3338,1062],[1335,6394],[-1284,348],[264,2874],[3755,2373],[2138,5847],[1684,1349],[5153,96],[3644,-1317],[-521,-3626],[-1979,-3149],[1859,-2350],[330,-4111],[-641,-1080],[161,-7077],[791,-1571],[2044,-1426],[-1135,-2330],[36,-1874],[-4447,-6544],[-1700,-1258],[-2951,1762],[-2399,-339],[503,-1242],[3181,-1401],[4382,-565],[1390,1860],[3818,2575],[785,2481],[1930,2087],[-1050,3876],[523,1958],[5221,1346],[2165,-3014],[-178,-4094],[1390,-1121],[3465,-1],[-3706,964],[213,2598],[917,408],[-956,3814],[-4583,1967],[-3295,-856],[-2326,143],[-1159,3510],[2176,5162],[-3492,5133],[1626,2370],[3668,1777],[-571,3952],[1619,-92],[1033,-2964],[-1372,-2860],[235,-2794],[2162,-730],[4109,-301],[2772,-1030],[-1042,1614],[-2032,268],[-3247,1682],[-777,1866],[2331,726],[1887,-1131],[1894,653],[-2114,1421],[2809,1202],[2609,-86],[3724,-1726],[2079,-2032],[4097,15],[-190,-1948],[-1652,-948],[-179,-4244],[1696,2437],[448,-2219],[-968,-2149],[2928,1948],[-1624,3301],[1167,2908],[-3855,3810],[-3768,1485],[-882,3542],[205,2858],[8226,581],[8462,1349],[1218,-415],[-3340,-1963],[3592,723],[248,1562],[-2852,3226],[2908,-352],[-3997,1668],[2391,220],[2833,2650],[6982,2734],[9347,1558],[-1606,1308],[4455,456],[4166,-414],[1172,-1130],[6013,2082],[3232,-632],[-2833,2042],[5662,264],[405,2757],[5948,3767],[2455,616],[5222,-1431],[-1417,-1488],[-3284,-805],[7609,-399],[1356,-639],[-2197,-2093],[2737,-375],[1121,1235],[8576,27],[5992,-2794],[1261,-4744],[-2226,-2581],[-8568,-4106],[-4558,-3720],[-2580,-434],[-3005,-1853],[-1335,-2793],[2138,1794],[3535,200],[5847,1772],[2813,1531],[-3098,-48],[1413,1747],[5238,-1828],[3524,-363],[-719,-1115],[6058,1441],[8645,-669],[-55,-2033],[3667,-1586],[9472,-142],[1282,1412],[-880,2012],[3009,1315],[6012,-2489],[1330,1261],[5159,-2117],[-805,-1749],[1810,-1125],[-2311,-1007],[2759,-1301],[-1324,-1398],[-3143,2100],[5440,-7788],[3876,-2235],[1124,940],[3033,6073],[2145,-2577],[3546,-617],[3283,1443],[5443,-2391],[762,2010],[3031,-719],[2152,277],[-955,3003],[1372,1252],[-2661,-274],[1180,1971],[4106,538],[-1031,1795],[3759,-1002],[4040,-134],[7603,-1516],[-5788,-1087],[6736,258],[-2457,-569],[264,-2725],[4048,3445],[6221,-970],[1054,-1902],[-2313,-280],[2813,-1688],[4226,-1327],[2574,-2681],[3570,269],[5836,1278],[5950,-333],[4697,-2309],[773,-2014],[-483,-3109],[2995,-1057],[347,-3011],[1472,-1143],[-79,2810],[2330,1597],[4955,416],[982,-653],[6586,-647],[2067,1424],[1449,-965],[425,-1812],[2799,-1137],[831,-1739],[2578,233],[1271,1302],[-1147,3188],[-1171,256],[905,2850],[5757,-825],[1994,-856],[7863,216],[2269,-1270],[5343,-1533],[3200,-2392]],[[999999,913406],[0,-23201]],[[999999,890205],[-1534,-1453],[-2578,-1298],[-2142,676],[-1582,1760],[-307,-1347],[-2798,1032],[1860,-1991],[1824,884],[126,-1953],[1446,-1316],[767,842],[1169,-2365],[396,-2517],[1497,-2075],[663,-2979],[-1249,-2174],[-3060,1343],[-2019,308],[-7159,-3859],[-3033,-1372],[-1366,-1833],[-765,369],[-1287,-2412],[-4957,-3714],[-715,-2781],[-1023,602],[-2100,3133],[-3025,-131],[-3260,-1581],[-1757,-2575],[-543,633],[600,2995],[-3521,-2288],[-182,-1409],[-1784,1169],[-1657,-100],[-1028,-1222],[-381,-3154],[-746,-1674],[-2397,-3393],[-504,-2194],[1408,-1841],[698,1066],[1377,-1536],[-1207,-1950],[65,-3236],[1259,-732],[221,-2698],[-801,-1113],[-1164,1112],[1139,1715],[-1527,-727],[-1121,-1834],[-988,-4334],[1045,-3589],[-1055,-1299],[-2647,50],[-1940,-2088],[-641,-2401],[504,-3875],[-1220,639],[-2714,-2157],[-404,-3368],[-1000,-2934],[-3766,-4979],[-567,2028],[-496,7096],[-739,2945],[-1330,11009],[-181,2867],[449,4287],[739,3691],[2072,2708],[690,1859],[-515,1670],[1830,304],[600,1306],[1512,33],[2295,2362],[2252,4166],[2798,2961],[2496,3111],[694,1588],[2693,2150],[2048,793],[-435,644],[1255,1886],[561,5617],[1087,1057],[2217,139],[-3169,1200],[-2567,-862],[-895,-4499],[-1713,-767],[-4518,-5384],[-1646,-680],[570,2293],[-1635,-408],[258,1985],[1206,2972],[-2125,-438],[-1321,1202],[-2796,-1000],[-1669,269],[-2193,-1887],[-139,-1232],[-2157,-2935],[-2451,-2372],[-1884,-3219],[-397,-1806],[2825,-997],[-19,-1008],[-1950,157],[-1242,-836],[-1806,825],[-1329,-1633],[-1338,517],[-2983,-896],[-572,1229],[3166,835],[-2152,1781],[-2274,191],[-2846,1268],[-2349,-1410],[325,-1479],[-1824,779],[-2064,-863],[-2715,1116],[-1682,-1532],[-1047,1274],[-6562,-256],[-3241,-2195],[-752,-1507],[-2972,-3159],[-661,-2361],[-4957,-5024],[-2696,-4895],[-4212,-4663],[-2536,-2423],[-14,-1255],[1651,-875],[2626,220],[-217,-4839],[1211,104],[-164,1818],[2052,-1077],[-1703,-2178],[1435,-111],[2308,1531],[352,2969],[1733,-752],[1077,498],[1777,-2752],[2931,-3724],[-614,-999],[-31,-3833],[875,-1126],[-328,-1526],[-1207,-1782],[-680,-2297],[-587,-4066],[114,-5627],[-963,-6354],[-2217,-3770],[-1031,-2986],[-1152,-1933],[-694,-3043],[-1809,-4295],[-2450,-3835],[-1837,-4040],[-743,-685],[-1087,-3191],[-979,-1832],[-3949,-4122],[-1526,-788],[-1253,1060],[-1126,44],[17,2549],[-1231,-1294],[-199,949],[-1768,-3728],[-1247,180],[-62,-2097]],[[863019,755336],[-639,-4],[-1947,-3493],[-132,-5065],[-3900,-4866],[-2046,-1504],[-482,-3402],[1088,-733],[1634,-2729]],[[856595,733540],[678,-2651],[1990,-5341],[385,-3155],[-196,-4087],[472,-9],[-428,-3275],[-569,-1872],[-1953,-479],[-186,-1366],[-1133,898],[-892,-399],[-229,-1566],[-855,-1345],[-216,1729],[-971,-1873],[-1017,-739],[-741,2127],[721,146],[-647,2703],[548,2920],[636,722],[-493,2354],[-145,3126],[-752,1049],[1001,881],[1057,-672],[-588,1703],[-312,3485]],[[851760,728554],[-733,572],[-704,-803],[-965,1436],[-1143,-1543],[-1026,1224],[718,743],[-1544,429],[1046,2533],[673,643],[-424,1222],[700,2469],[-134,1412],[-1627,1371],[-380,-847],[-768,2304]],[[845449,741719],[-712,-966],[-2983,-992],[-1936,-1821],[-1902,-2969],[-1351,-790],[-159,1121],[1593,1113],[385,1646],[-1508,-11],[671,2726],[788,626],[1316,3503],[-1155,1779],[-1901,351],[-1932,-3972],[-2466,-1945],[-1018,-2930],[-869,-1431],[-1706,-589],[-713,946],[-712,-547],[-630,-3017],[1269,-2617],[2569,-833],[415,-2027],[-379,-2189],[1381,-1223],[3612,4201],[2473,-2213],[1156,406],[1696,-747],[-1091,-3371],[-949,745],[-2619,-2142],[-858,-2545],[-1740,-1820],[-1737,-3316],[-634,-3276],[2779,-2505],[843,-4073],[1016,-3683],[-48,-2104],[1521,-1715],[7,-982],[1191,-1815],[95,-1163],[-2480,983],[-1260,1401],[-933,-828],[1475,104],[2626,-3934],[604,-2386],[-974,-450],[-1471,-1675],[-490,-1206],[-1032,196],[510,-1508],[1461,998],[1440,-1911],[1125,-644],[-1601,-2286],[1208,719],[-65,-2790],[-557,719],[-749,-741],[603,-715],[-527,-2187],[353,-1628],[-1399,-451],[-1420,-4205],[-132,-1555],[-725,-1311],[-534,-2520],[-568,-363],[-161,1398],[-518,-1334],[676,-1700],[-1162,-1656],[433,-303],[-73,-3765],[-1240,274],[-658,-2876],[-756,-553],[-213,-1512],[-1314,277],[-86,-2257],[-1190,-2425],[-448,22],[-2325,-2883],[-441,-2417],[-608,210],[-2093,-1555],[-840,583],[-950,-1188],[-562,821],[-271,-1341],[-800,71]],[[817405,638260],[69,-246]],[[817474,638014],[-64,-1208],[-701,1282]],[[816709,638088],[-1100,2071],[2,1576],[-803,-1277],[616,-1884],[65,-1758]],[[815489,636816],[-446,-704]],[[815043,636112],[-2304,-2379],[-1784,431],[-948,-1721],[-1628,-281],[-1249,-1763],[-434,735],[-640,-2841],[919,-2016],[-1078,-1508],[-920,2121],[-308,3020],[693,2068],[-1075,340],[-1284,-579],[-1671,2751],[126,-1382],[-1535,-968]],[[799923,632140],[-1563,-1322],[-682,-1991],[-1336,305],[194,-1571],[-654,-2643],[-1483,-2073],[-1006,-5763],[740,-2748],[1697,-3294],[-56,-1344],[1948,-4868],[1816,-3409],[543,51],[1791,-5021],[409,-626],[732,-3921],[607,-5093],[-88,-3419],[422,-1916],[59,-2111],[-628,274],[-56,-5457],[-589,-2301],[-461,-124],[-1526,-2258],[-2805,-3175],[-708,1553],[-291,-1645],[-1216,-501],[892,-1077],[-527,-1521],[-1275,2144],[1030,-2372],[-360,-1571],[-1519,2634],[782,-1938],[155,-1640],[-1854,-1799],[-1073,-2749],[-956,-187],[208,5975],[687,1747],[-180,986],[-1012,607],[-659,1430]],[[790072,566398],[-1359,1039],[-1124,107],[527,1691],[-527,1520],[-1054,-1380],[-77,3240],[-531,1458]],[[785927,574073],[-944,2940],[-150,-555],[-1405,2504],[-863,933],[-774,-418],[-1616,567],[276,4250],[-852,529],[-1773,-996],[201,-1822],[-350,-2106],[70,-3077],[-1005,-4194],[-390,-3396],[-895,-3376],[-11,-3470],[647,-3083],[917,596],[502,-1193],[156,-2617],[885,-2386],[484,-4894],[-822,1693],[738,-3201],[1651,-1937],[1334,26],[837,-2314],[837,-1377]],[[783612,541699],[665,-416],[540,-1834],[1244,-2000],[1204,-3997],[147,-2707],[-296,-3698],[254,-1472],[-39,-3481],[1035,-2089],[1129,-5081],[-117,-2121],[-1338,502],[-596,-711],[-342,1283],[-1750,1832],[-3976,6100],[12,2182],[-1624,4224],[-280,4064],[-728,5542],[-25,2349],[-623,2712]],[[778108,542882],[-1175,2576],[-276,2837],[-662,98],[-855,3055],[-1311,2704],[-438,-983],[-508,1450],[370,5139],[920,5332]],[[774173,565090],[-389,-921],[-272,3797],[586,1843],[183,3583],[-292,869],[167,2884],[-335,5549],[-918,3387],[-266,-509],[-137,3044],[-800,4132],[-283,6023],[-350,853],[137,2596],[-716,387],[-549,3193],[-578,1513],[-171,-1697],[-796,-2767],[-2387,-2339],[-1038,-2644],[-156,1839],[-1084,-1273],[-138,2159],[-643,-1649],[162,2929],[-1378,-2265],[1014,9200],[-439,3746],[-943,3836],[-129,2596],[-321,-2297],[-622,754],[-590,2030],[922,-776],[481,1199],[-1766,3658],[-1001,98],[180,1793],[-956,-486],[-1107,2940]],[[756455,627897],[-745,2269],[-133,3021],[-509,3223],[-957,3887],[-914,-1604],[-571,-101],[-974,3181],[-444,-2263],[429,-2924],[-997,-2539],[-443,340],[384,1596],[-710,-793],[-200,2161],[-194,-2394],[-1273,-1554],[-722,898],[-118,1306]],[[747364,635607],[1,-2601],[-852,-413],[-287,3185],[-158,-2739],[-1466,204],[387,2639],[-1439,-2880],[-1605,-905],[-669,-1564],[322,-3179],[-625,-2292],[-1308,-2333],[-1957,-1342],[-320,1202],[-825,-1629],[774,34],[-1863,-2969],[-1852,-4934],[-1250,-1320],[-1266,-2730],[-1681,-1985],[-865,-2002],[-64,-2229],[-1380,-1365],[-1322,45],[-854,-3428],[-923,809],[-980,-1091],[-667,-3773],[311,-2939],[-150,-2166],[642,-5041],[-315,-3976],[-1031,-4156],[-290,-2450],[264,-2242],[-29,-5179],[-1243,-99],[-1096,-3690],[-46,-2456],[-1550,-969],[-637,-1268],[-367,-3000],[-1507,-1814],[-1530,1949],[-1148,2935],[-637,3255],[-227,2814],[289,-30],[-1178,5107],[-552,3422],[-1464,4122],[-1184,6042],[-277,3497],[-801,4900],[-1203,3437],[-48,1909],[-1266,3894],[-385,2403],[-504,6884],[-793,6287],[375,2003],[-475,-270],[-98,3224],[-366,1844],[593,4338],[-187,3282],[-557,2042],[1136,1408],[-1331,-18],[436,1632],[-1093,1287],[-748,-2169],[602,-1730],[-663,-2224],[-2752,-2469],[-848,9],[-1645,2098],[-3107,6530],[-70,1117],[814,-592],[2502,1702],[731,2356],[-2155,-1252],[-1191,530],[-1653,2023],[-620,2260],[998,1663],[-1505,-1512],[-194,1543]],[[689347,646059],[-1380,-275],[-997,2156],[-383,3443],[-1301,622],[-13,2164],[-750,2068],[-2080,-1304],[-2509,-284],[-326,-730],[-1409,885],[-1653,117],[-182,-843],[-2552,260],[-715,-710],[-1588,19]],[[671509,653647],[-584,340]],[[670925,653987],[-336,-554],[-2079,1067],[-2911,718],[-1583,83],[-689,813],[-1344,156],[-2721,1248],[-640,3435],[-339,3164],[-470,1093],[-1269,654],[-1961,-1320],[-2095,-2493],[-697,-283],[-1105,1112],[-1504,172],[-697,1289],[-2120,2252],[-599,1737],[-1237,1231],[-1012,122],[-1076,1697],[-1120,5518],[-557,497],[-71,1620],[-1335,2969],[-271,1643],[-1435,-1005],[-1391,1647],[-1410,-2041]],[[634851,682228],[-1577,121]],[[633274,682349],[457,-2431],[-1161,-922],[906,-364],[1086,-4814]],[[634562,673818],[920,-3459],[65,-1391],[1223,-1372],[466,-1847],[1614,-2085],[552,-2512],[-426,-1742],[1462,-6068],[685,-1762]],[[641123,651580],[-116,3883],[668,3180],[720,1018],[780,-1486],[-161,-2238],[324,-2232],[-483,-2842],[-445,-362]],[[642410,650501],[117,-1580],[718,-322]],[[643245,648599],[938,-1782],[958,59],[1103,944],[3459,-460],[1399,1192],[972,3153],[976,1370],[1179,2705],[1163,1752],[386,1592]],[[655778,659124],[971,1567],[-367,-4008]],[[656382,656683],[251,-3978]],[[656633,652705],[701,-3015],[1609,-3244],[3773,-1654],[2659,-6310],[800,-412],[-65,-1712],[-1190,-4272],[-1321,-2287],[-1171,-4182],[-1032,968],[-669,-1932],[-408,-3776],[268,-3494],[-1764,-678],[-1448,-1868],[-290,-2497],[-779,-1274],[-2198,-637],[-622,-1527],[112,-1209],[-643,-2030],[-2766,-198],[-1273,-1454],[-1457,-661]],[[647459,603350],[-2105,-2103],[-427,-1994],[121,-1786],[-1705,-1888],[-2991,-1769],[-1000,-1109],[-2270,-1263],[-838,-1074],[-1055,-2407],[-1884,-13],[-1618,-2289],[-1719,-1162],[-3143,-751],[-1718,-3098],[-1169,8],[-721,-877],[-1190,-312],[-1263,1318],[-676,2536],[141,2209],[-538,2199],[-189,3222],[-844,6515],[340,2236],[-112,2013]],[[618886,601711],[-279,2163],[-876,2284],[-248,1852],[-1511,2670],[-1446,4696],[-315,2393],[-992,3988],[-1884,3025],[-1298,1491],[-1444,4696],[148,1236],[-442,2149],[300,3028],[-246,2235],[-1996,6760],[-1025,1625],[-1046,630],[-1006,3130],[-89,2791],[-1751,4821],[-747,2903],[-1857,4962],[-1113,3569],[-1567,673],[454,2126],[475,5014]],[[597085,678621],[63,1193]],[[597148,679814],[-192,-460]],[[596956,679354],[-467,-1225],[-935,-7432],[-499,-1492],[-1277,1679],[-1424,3081],[-477,2994],[-985,2658],[-432,2679],[-572,-2033],[570,-1448],[185,-2335],[740,-2530],[1803,-3952],[7,-1722],[954,-3306],[183,-2372],[1684,-5675],[1747,-7204],[1638,-3184],[-675,-101],[-50,-2833],[486,-2940],[1477,-1881],[1783,-3744]],[[602420,635036],[154,-2431],[791,-2373],[-51,-6311],[153,-3192],[619,-4513],[1252,-1565],[777,-1816],[1133,-1448]],[[607248,611387],[839,-3424],[642,-4135],[434,-4787],[1352,-4717],[217,2046],[945,-2703],[2701,-2333],[1339,-3775],[1630,-2343],[428,-2222],[1103,-2063],[890,-922]],[[619768,580009],[814,-3073],[-382,-1306],[-1314,-1363],[-721,-1393],[1033,487],[929,-514]],[[620127,572847],[1686,-4239],[1482,-2098],[1546,39],[2427,2365],[2079,-533],[2333,2536],[1706,-205],[1820,1086],[734,-381]],[[635940,571417],[3254,1605],[1895,2692],[1285,-906],[-474,-2933],[157,-4022],[677,-1601],[-1262,-302],[-292,-5376],[-1098,-3454],[-908,-3824],[-697,-1405],[-252,-1795],[-1146,-3964],[-832,-4840],[-1111,-4024],[-1153,-3209],[-719,-2700],[-3046,-7176],[-2299,-4802],[-3141,-3941],[-1632,-2482],[-2403,-4558],[-4133,-9448],[-1242,-4279]],[[615368,494673],[-405,-1018],[-1381,-926],[91,-1009],[-773,-2048],[-1172,-882],[-297,-3331],[-1735,-7274],[-747,-1268]],[[608949,476917],[-1118,-7022],[152,-2688],[1662,-3242],[205,-861],[-716,-2926],[424,-2925],[-381,-2561],[409,-2957],[528,-1478],[396,-4278],[1888,-3258]],[[612398,442721],[412,-1168],[-581,-3972],[358,-3985],[-123,-2888],[260,-850],[-99,-4901],[280,-6374],[478,422],[47,-1919],[-603,-1920],[-164,-2121],[-1250,-2997],[-734,-2703],[-1673,-2115],[-439,-1068],[-2609,-1600],[-2502,-2944],[-2548,-6240],[-1877,-2196],[-1954,-3844],[-534,-55],[-141,-3859],[771,-1973],[792,-5004],[321,-4761],[307,1954],[227,-4967],[-569,-4947],[476,-156],[-288,-2054],[-784,-2193],[-1524,-1658],[-3500,-2605],[-1542,-2272],[-561,-2131],[718,-1564],[295,1093],[-191,-4536]],[[591350,345650],[-976,-8001],[-692,-2499],[-1410,-1869],[-1230,-2613],[-2907,-9432],[-3980,-7845],[-2765,-4500],[-2175,-2769],[-1800,-1412],[-1222,286],[-976,-1776],[-1765,222],[-488,-1157],[-3449,1089],[-882,-569],[-1984,421],[-856,-350],[-1269,-1798],[-2024,47],[-1473,-583],[-1415,-1911],[-1071,192],[-1491,2389],[-741,-83],[-63,1516],[-1269,-476],[314,1781],[-566,2762],[-1139,3520],[1110,1039],[167,3138],[-278,2251],[-1482,4286],[-1356,5446],[-664,4126],[-1396,4656]],[[545687,335174],[-2024,3861],[-1048,3432],[-1038,6330],[-341,3509],[-22,4103],[-932,4925],[-77,5455],[-196,1855],[340,1573],[-567,3037],[-968,2502],[-1452,5041],[-784,4337],[-1972,7452],[-1007,2286],[-889,3195],[-91,4457]],[[532619,402524],[211,3230],[-189,5168],[603,1172],[868,5904],[750,7107],[964,2430],[238,1493],[1205,1513],[1023,4192],[173,4493],[-351,2493],[-505,1261],[-917,4251],[-585,3881],[1001,2138],[54,1881],[-1434,6741],[-108,1642],[-839,2159],[-608,2949],[2127,1349]],[[536300,469971],[-1824,-720],[-550,1349]],[[533926,470600],[-101,2571],[-441,1898]],[[533384,475069],[-669,2598],[-1798,3848]],[[530917,481515],[-2174,5350],[-1634,2931],[-1279,3647],[-730,3520],[785,-1915],[568,200],[-1274,1777],[-676,3495],[876,800],[445,1316],[14,3790],[1375,-1447],[568,893],[-1264,598],[-615,1518],[814,145],[-75,2698]],[[526641,510831],[-569,636],[1169,4669],[-17,2234]],[[527224,518370],[410,4588],[-1090,4260],[510,326],[-711,1263],[-162,-852],[-1181,1003],[-228,2738],[-955,-164],[-51,1357]],[[523766,532889],[-895,902],[165,-2073],[-2802,-59],[-753,-890],[-2602,-632],[-1358,2112],[-568,2855],[7,1616],[-1458,3700],[-1193,1909],[-849,372],[-3944,-250]],[[507516,542451],[-3010,-903]],[[504506,541548],[-1210,-755]],[[503296,540793],[-658,-1653],[-1917,-314],[-1691,-1520],[-1246,-1624],[-2336,-1456],[-1009,-1294],[-1103,989],[-1987,944]],[[491349,534865],[76,235]],[[491425,535100],[187,14]],[[491612,535114],[-606,1212],[-305,-1213],[-2146,1061],[230,-471],[-2396,-544],[-344,387],[-2473,-1142],[-2803,-2207],[-1728,-1701]],[[479041,530496],[-1983,1414],[-2426,2753],[-3179,6061],[-1413,1377],[-177,918],[-1229,1322],[-600,1294]],[[468034,545635],[-627,1078],[-2091,1764],[-68,1655],[-1030,1131],[-210,1711],[-533,410],[-400,4945]],[[463075,558329],[65,719],[-1077,2776],[-91,1710],[-2047,1899],[-970,4048],[-743,50]],[[458212,569531],[-31,1196],[-940,446],[-116,4303],[-1068,-1067],[-387,1162],[-877,110],[-124,981],[-1091,1251]],[[453578,577913],[-143,4202]],[[453435,582115],[-172,1641],[746,-225],[3107,1067],[-1937,-207],[-848,-564],[-338,1387]],[[453993,585214],[-1143,4834],[-540,1407],[-1021,678],[1080,989],[843,2204],[856,3225]],[[454068,598551],[-2,2657],[526,3789],[744,3670],[134,2026],[-151,3752],[-357,2856],[-836,2125],[642,2519],[202,2611],[-609,2515],[-535,-108],[-705,2678],[-478,-1659]],[[452643,627982],[108,3383]],[[452751,631365],[217,3098]],[[452968,634463],[1591,4114],[411,2982],[1124,3861],[-259,562],[2390,4173],[508,1913],[170,3155],[1057,5033],[2329,2852],[888,4144]],[[463177,667252],[223,1310]],[[463400,668562],[630,1531],[2675,1275],[1544,1497],[970,1965],[1651,2081],[1760,4409],[516,1778],[40,2004],[-618,1602],[185,4187],[1281,3920],[283,2880],[1804,3642],[819,1109],[2053,1575],[1837,1948],[1522,4781],[1190,5982],[1797,693],[-167,-933],[1390,-2749],[1410,-709],[1768,702],[1353,-242],[650,996],[368,-1656],[1723,-140]],[[493834,712690],[851,-59],[1603,1600],[1163,1802],[1365,1144],[1317,231],[1297,2140],[2062,1528],[3711,480],[1053,1089],[2241,662],[2719,1],[1852,-1309],[2290,1557],[660,874],[1225,-985],[768,1024],[1961,-1398],[1851,479]],[[523823,723550],[3088,2388],[1412,-797],[600,-2808],[1782,2018],[202,-1175],[-1670,-3263],[181,-2584],[1149,-1501],[322,-2332],[-1626,-4120],[-1306,-1974],[262,-2142],[1566,-1988],[1005,287],[328,-1859],[839,-398]],[[531957,701302],[2153,-1916],[1316,-341],[1472,673],[2649,-1382],[767,-1009],[1843,-710],[507,-1371],[381,-2980],[582,-1365],[1159,-959],[1829,-295],[1577,-789],[2336,-1802],[2073,-2885],[986,-14],[1172,1187],[1215,3497],[-624,4378],[542,2377],[1388,2141],[2819,2116],[1532,-113],[2509,-1775],[544,-2399],[1420,-326],[922,-886],[1540,40],[947,-786],[349,-1352]],[[569862,692256],[644,-843],[1419,641],[3763,-1440],[1999,-1662],[1520,-278],[1548,-1304],[3675,3716],[1685,31],[140,763],[1312,-790],[1013,493],[-328,-1475],[919,-1183],[616,967],[777,-1110],[3609,665],[821,839]],[[594994,690286],[776,1554]],[[595770,691840],[558,1842],[1195,7038]],[[597523,700720],[1398,5619],[100,1280],[912,2257]],[[599933,709876],[-92,3523],[-496,2060],[356,2044]],[[599701,717503],[-227,2330],[1049,2068],[-388,1491],[-1421,-1858],[-2600,1111],[-2518,-3569],[-2500,-866],[-1158,875],[-989,2084],[-1859,1574],[-1968,383],[-446,-3290],[-2207,-910],[-1516,1425],[-292,1755],[-2040,702],[-1800,-814],[1629,2100],[-2481,-56],[517,855],[-878,1334],[-392,1769],[429,1724],[-2616,1769],[619,2087],[226,-1250],[1399,-17],[-930,1741],[694,1050],[-921,2402],[403,1604],[-1983,-566],[189,3096],[1547,2430],[1518,328],[530,-803],[4388,617],[-270,1223],[2464,637],[-1334,422],[-887,1174],[285,1265],[2143,-416],[1182,273],[1292,-664],[1236,135],[564,1259],[2357,2426],[2985,1706],[3804,-360],[711,631],[809,-1983],[2094,-273],[354,-1516],[918,-972],[745,598],[801,-1061],[3652,-1540],[2904,1078],[2330,-859],[1929,1482],[1529,1812]],[[615305,750685],[703,2681],[-762,4084],[-1812,2395],[-2384,2111]],[[611050,761956],[-3503,5143],[-1489,780],[-916,1654],[-1222,217],[-574,1401],[-1539,916],[807,967],[1961,517],[61,1641],[959,2333],[1327,253],[-2016,3233],[2041,163],[-174,885],[2375,1733],[-272,967],[-2726,-1051]],[[606150,783708],[-1863,-100],[-566,-935],[-2945,-1529],[-1257,-203],[-1519,-2044],[-138,955],[-1058,-1485],[481,-2897],[1487,-2311],[1701,843],[1124,-353],[-505,-1944],[-1453,-356],[-1105,552],[-1069,-1754],[-1030,27],[-2241,-2485],[-1276,983],[290,3224],[-1768,1484],[-1141,330],[3214,3218],[-1285,1355],[-2015,-546],[-1936,1428],[2217,1723],[-2905,291],[-2044,-667],[-1604,-4060],[-1715,-1092],[290,-2503]],[[582516,772857],[-412,-2468],[-1415,-508],[-1,996],[-1118,-3732],[-167,-3279]],[[579403,763866],[-333,-2091],[-921,37],[-569,-1241],[-112,-2585],[-1122,-1669],[1471,-2956]],[[577817,753361],[922,-2978],[1975,-1402],[-769,-1514],[-1690,631],[-1868,-637],[-671,-1694],[-1350,-1121],[-1581,-2504],[142,1418],[1495,1848],[-1907,-91],[-185,684]],[[572330,746001],[-2596,1587],[-865,-812],[-878,534],[-1096,-1325],[-888,141],[289,-1951],[-562,-1154],[-979,-43],[-1896,1653],[-103,-2717],[1934,-4432],[-1249,-179],[352,-1349],[-1025,-832],[1823,-1358],[1983,-2288],[246,-3350],[-1319,1783],[-1512,-783],[1258,-2596],[-910,-630],[-1211,1234],[748,-3118],[-33,-2888],[-564,1527],[-1122,-499],[-821,1937],[-522,-1728],[-860,2036],[-32,2726],[-1204,1855],[738,2029],[1170,779],[3043,-2191],[635,1290],[-2020,1555],[-2637,-694],[-998,375],[-926,3696],[-1330,1888],[-832,2265]],[[555559,739974],[-416,1979],[-1020,986],[-388,2442],[323,1843],[-57,2912],[380,2149],[-653,484]],[[553728,752769],[-2291,3340]],[[551437,756109],[-2361,2750]],[[549076,758859],[-229,244]],[[548847,759103],[-1894,2690],[-1415,895],[-1134,-140],[-2396,4366],[966,90],[-1599,2575],[-113,2217],[-1505,1523],[-964,-2975],[-934,1614],[-143,2422]],[[537716,774380],[394,419]],[[538110,774799],[-254,1086],[-3761,-1925],[-135,-1212],[827,-1620],[-764,-1455],[411,-2954],[819,-1357],[2425,-2509],[1239,-5224],[2377,-3774],[841,-702],[2209,32],[520,-1072],[-385,-1914],[3030,-2211],[2365,-2411],[1475,-3261],[-395,-1679],[-738,685],[-591,2033],[-2603,1054],[-1106,-3545],[188,-1308],[1436,-1530],[167,-2267],[-1710,-1678],[-38,-1811],[-1357,-2768],[-923,-16],[688,4582],[624,276],[-481,3522],[-920,3771],[-2060,1474],[-515,2544],[-1842,941],[-1025,2420],[-1791,48],[-1272,1338],[-2760,4846],[-947,804],[-1633,3039],[-1835,6419],[-2107,1774],[-1454,611],[-1901,-2982],[-1634,-900]],[[520814,764013],[-644,-421]],[[520170,763592],[-2132,-3121],[-1050,-574],[-1970,925],[-964,1280],[-1197,-341],[-1600,1220],[-2205,-2369],[-575,-1646],[443,-2868]],[[508920,756098],[102,-2884],[-3237,-3892],[-2916,-1335],[-3078,-7027],[-701,-2109],[340,-2709],[1129,-1798],[-1619,-1917],[-737,-1681],[-487,-3383],[-1404,-117],[-1306,-1945],[-1083,-2887],[-6054,-162],[-853,-1254],[-1382,-490],[-1261,-2357],[-1154,963],[-1254,4539],[-1089,1420],[-1449,-88]],[[479427,724985],[-1189,-1029],[-2121,685],[-1111,-528],[510,2361],[-186,6019],[-923,8],[215,1746],[-939,-71],[276,3599],[629,1210],[726,3773],[642,5036],[-618,4755],[280,646]],[[475618,753195],[240,1973],[-656,3107],[-856,1057],[1004,2118],[1736,621],[-23,833],[1553,1093],[1211,-1006],[4434,-72],[3174,-988],[2552,615],[1552,-876],[474,491],[1495,-749],[1507,470]],[[495015,761882],[860,927],[664,5901],[458,5762],[873,-1292],[-736,2528],[-319,3379],[-1778,1205],[-1140,3840],[615,875],[-1466,8],[210,941],[-4092,2172],[-1143,-86],[-1018,1283],[970,772],[-1087,2192],[4136,1783],[1499,-1801],[684,661],[2971,25],[-525,906],[-49,2351],[-759,2852],[1660,-21],[334,-1732],[2708,-540],[1613,898],[-640,1509],[2941,1748],[965,1505],[-38,2885],[926,1491],[1701,631]],[[507013,807440],[2292,1662]],[[509305,809102],[2434,52]],[[511739,809154],[-2159,914],[2038,411],[-655,1187],[1488,2953],[544,2967],[3844,3539],[2094,202],[1059,-942]],[[519992,820385],[243,2365],[2012,54],[1342,-1044],[352,2136],[998,304],[-73,3208],[-750,1921]],[[524116,829329],[-57,1149]],[[524059,830478],[-126,2562],[-1344,1075],[88,5966],[1409,-658],[280,1359],[-1356,754],[930,1534],[2599,718],[1134,2065],[1586,915],[-26,-2916],[-670,-3689],[1564,-587],[29,-1339],[-1493,-489],[-377,-2060],[-1645,-2204],[-381,-2688],[699,-660]],[[526959,830136],[112,-716]],[[527071,829420],[1105,-1889],[1633,-1020],[783,373],[-265,-2274],[1338,-301],[1977,1326],[1289,1771],[1259,-333],[1165,-1601],[767,73],[393,-1776],[1068,-720]],[[539583,823049],[660,-355]],[[540243,822694],[-380,1107]],[[539863,823801],[-496,92]],[[539367,823893],[109,450]],[[539476,824343],[5485,2015],[1038,1561],[1950,1041],[2949,643],[962,-2413],[851,-485],[1745,652]],[[554456,827357],[1028,2738],[1516,437],[1054,1728]],[[558054,832260],[-112,-611]],[[557942,831649],[-735,-1191],[1650,-280],[95,1022]],[[558952,831200],[37,968]],[[558989,832168],[-528,4734]],[[558461,836902],[70,4464],[1826,4428],[2294,908],[2035,-3759],[1789,-482],[1311,1874],[-224,3233]],[[567562,847568],[574,2866],[-2116,39],[-932,3317],[174,1629],[2461,1641],[2954,287],[182,699],[4070,-1117],[2883,200]],[[577812,857129],[4,1425],[2592,616],[556,1013],[2709,-748],[-1115,1906],[-1811,-23],[-1183,1090],[-362,1789],[-1987,-836]],[[577215,863361],[-1544,15],[-4404,-1218],[-3649,-1723],[-2442,-333],[-1657,1361],[-1123,-1106],[339,2081],[-3191,1279],[-210,2198],[682,3698],[-972,2359],[-423,3752],[1520,2466],[-294,978],[2152,629],[590,1999],[1990,1471],[2860,3668],[777,1693],[2028,351],[166,3667],[-3312,1931]],[[567098,894577],[-2925,-414],[-2045,636],[-312,-1452],[-1912,-1123],[42,-1465],[-1229,-2086],[1059,-2047],[-2102,-3527],[-3913,-2313],[-2077,-1772],[-398,-1673],[-1577,-387],[394,-1363],[-1296,-886],[-1222,-5185],[334,-5184],[1958,-658],[2309,-3023],[509,-1909],[-2795,-2357]],[[549900,856389],[-432,1148],[-1213,-340],[-2217,687],[-1193,-972],[2137,-11],[1086,-1029],[1875,337]],[[636756,779239],[-2981,-3555],[-1749,-1226],[-1238,-4225],[-913,-950],[1684,-3929],[410,-2866],[-127,-2813],[3082,-7052]],[[634924,752623],[1483,-3216],[333,-1632],[1526,-2620],[596,-43],[1043,-1761],[-1242,219],[-1021,-725],[-977,-6644],[-517,364],[-452,-1888],[50,-2251]],[[635746,732426],[589,-4549],[1081,-1013],[1835,-530],[1118,-2331],[1626,-1606],[1788,-759],[1189,43],[3289,1463],[1655,-299],[-155,3112]],[[649761,725957],[-252,3462],[172,5546],[-502,2047],[-1522,329],[219,2035],[1021,-365],[-322,2147],[-1636,19],[-457,2880],[583,3788],[560,-1262],[1306,-39],[412,-905],[1705,163],[924,1173],[-328,1791],[-1381,1931],[-690,3387],[-1895,16],[-540,-697],[-300,-4539],[-1022,3379]],[[645816,752243],[-89,1897],[374,3908],[-1766,535],[-958,1824],[-890,93],[17,1826],[-1308,4208],[-1388,787],[-93,1517],[1563,280],[1898,-579],[-1349,1662],[-49,1000],[1043,2237],[3098,241],[1859,-395],[-1185,1427],[1004,3666],[97,2829],[-706,1690],[-1202,215],[-1105,-895],[-2520,1603],[-2108,-1367],[-1165,-1452],[-1812,-682],[-320,-1079]],[[579890,406773],[-220,141]],[[579670,406914],[-1105,-546],[-671,-1286],[-690,-10],[-2147,-6749]],[[575057,398323],[576,1214]],[[575633,399537],[498,1027]],[[576131,400564],[826,2210],[951,844],[287,1338],[1698,181],[628,1169],[-631,467]],[[596829,424051],[8,920]],[[596837,424971],[-448,7467],[713,2757]],[[597102,435195],[-55,1606]],[[597047,436801],[-915,2270],[165,1707],[-397,4516],[-565,1769],[-903,1399],[-117,-964]],[[594315,447498],[86,-2168],[765,-2509],[-181,-705],[342,-6592],[-719,-2188],[41,-1803],[711,-3505],[-25,-2578],[835,-2199],[-59,-2417],[712,855],[1187,-2077],[-633,3686],[-548,753]],[[583319,439012],[-188,1258],[-1007,-1653],[65,-1400],[914,550],[216,1245]],[[590316,457091],[-1354,2401],[-631,-116],[447,-1971],[1538,-314]],[[581104,494978],[-351,228],[-450,-2385],[-164,-2606]],[[580139,490215],[167,89]],[[580306,490304],[1242,2470],[-300,1659]],[[581248,494433],[-144,545]],[[594373,505981],[-82,25]],[[594291,506006],[-1283,3],[-822,1245],[-139,-1043],[-2578,-1442],[-719,-834],[122,-1120],[-754,-2779],[125,-863]],[[588243,499173],[42,-439]],[[588285,498734],[229,-485],[-558,-4978],[429,-5130],[1171,3050],[1584,-1374],[713,620],[968,-717],[1092,2009],[-1480,404],[689,756],[-629,442],[819,952],[209,1512],[615,-40],[118,1925]],[[594254,497680],[365,913]],[[594619,498593],[45,2690],[383,818],[1656,983],[-266,1090],[-1202,-1532],[-841,2220],[-21,1119]],[[550098,499048],[149,1643],[-772,44],[623,-1687]],[[582340,501712],[626,1212]],[[582966,502924],[-236,1073]],[[582730,503997],[-387,11]],[[582343,504008],[-409,-359],[-361,-2723],[767,786]],[[580912,453401],[-726,882],[-1388,-3483],[-94,-2068],[1006,317],[1202,4352]],[[586662,453459],[-41,293]],[[586621,453752],[-1610,6282],[-212,3670],[-1086,2711],[-477,-209],[-675,1517],[627,2047],[-544,2923],[168,1754],[-569,1196],[94,2477]],[[582337,478120],[31,410]],[[582368,478530],[-801,3341],[-183,2968]],[[581384,484839],[-285,99]],[[581099,484938],[-369,-5798],[532,1280],[-362,-2874],[-21,-3186],[709,-2918],[-506,-1768],[893,-4769],[1766,-3432],[410,-3397],[794,-1827]],[[584945,456249],[-19,-482]],[[584926,455767],[-303,-1397],[928,-402],[684,-1335],[427,826]],[[593018,514450],[-202,523],[-1153,-1089],[-1262,-151],[1988,-1771],[-373,1661],[1002,827]],[[586953,517904],[-123,-430]],[[586830,517474],[-2165,-4070],[-5,-1348]],[[584660,512056],[322,-1170],[1043,2878],[1196,2183],[-268,1957]],[[605708,543686],[-517,-515],[-73,-2474],[733,2227],[-143,762]],[[500755,544260],[92,2515],[-132,4775],[-564,-668],[-1498,2472],[-1767,4265],[904,-3637],[1675,-2135],[-283,-1706],[850,-738],[478,-1638],[-200,-2189],[-850,-921],[-1222,72],[2049,-2460],[468,1993]],[[601901,519752],[-90,1900],[-625,906],[-572,2734],[-131,6867],[-621,-468],[-287,-4607],[330,-2413],[1272,-3754],[308,-1698],[416,533]],[[513014,566127],[-597,1548],[-7,-3130],[530,-1266],[74,2848]],[[790472,578337],[-362,1765],[-571,235],[-705,2460],[-782,165],[298,-1542],[1254,-2269],[868,-814]],[[540322,581615],[423,1277],[-906,-197],[-187,-1535],[670,455]],[[603570,574593],[283,-961],[568,2872],[-365,1103],[-1012,-223],[-261,-2127],[787,-664]],[[785773,614477],[-978,844],[245,-1141],[733,297]],[[589539,639047],[271,-551],[1877,3887],[-268,2056],[-1140,-4893],[-926,179],[-1993,-3425],[-939,-3194],[577,837],[905,2959],[1140,2091],[496,54]],[[752585,676072],[-1025,1705],[79,-2453],[946,748]],[[824182,677333],[-1536,690],[124,2955],[-646,-2607],[368,-1217],[1202,-1253],[488,1432]],[[835004,688893],[-392,-39],[-672,2672],[-642,-830],[-27,-1781],[1157,-714],[576,692]],[[750960,685556],[1857,1866],[-196,502],[-1819,-456],[158,-1912]],[[632245,686535],[-2077,1346],[-107,-1133],[2184,-213]],[[738577,687953],[-1352,630],[-67,-767],[1247,-724],[172,861]],[[748104,693080],[-970,734],[-1117,-439],[1587,-1436],[500,1141]],[[831685,699001],[-162,1684],[-748,-1323],[910,-361]],[[749194,703001],[333,-1261],[388,1327],[-721,-66]],[[621884,698374],[-912,2321],[-189,-2590],[862,-635],[239,904]],[[741047,689360],[-98,1041],[-960,-2790],[1058,1749]],[[731194,691121],[-361,1115],[-731,-517],[1092,-598]],[[827614,691459],[-1739,1048],[424,-1368],[1315,320]],[[770743,711929],[-1115,128],[456,-1016],[659,888]],[[771908,711114],[-346,1481],[-599,-1257],[945,-224]],[[779868,722801],[-1328,2011],[-885,400],[-850,-1816],[857,-1378],[2071,-529],[135,1312]],[[626850,728317],[-640,381],[-219,2714],[-698,0],[719,-6148],[475,-543],[895,1727],[-532,1869]],[[619412,731894],[916,848],[-73,1920],[-2128,-401],[-480,-1454],[1470,-136],[295,-777]],[[592937,734903],[-423,1618],[-409,-2100],[1042,-1478],[390,1123],[-600,837]],[[750778,745730],[-534,277],[670,-3123],[-136,2846]],[[624971,744746],[897,-2169],[941,273],[-774,1684],[-1064,212]],[[688863,749129],[401,-1223],[890,346],[-1291,877]],[[829457,701243],[710,1093],[-1035,1086],[-870,-1953],[24,-1928],[1171,1702]],[[620169,704535],[573,1320],[-1115,1822],[542,-3142]],[[868915,771622],[-4,576]],[[868911,772198],[-637,875],[-1411,-56]],[[866863,773017],[-184,-432]],[[866679,772585],[179,-2794],[823,-1261],[1234,3092]],[[728146,775844],[-613,3476],[-1063,599],[-286,-2349],[1962,-1726]],[[719418,781676],[-2373,-910],[-4556,241],[-1862,1081],[-1109,-477],[-2226,87],[-1475,-1921],[-313,-1431],[-1495,-3136],[1878,-3895],[-53,3183],[525,674],[-32,2094],[1371,615],[324,1592],[1433,1380],[576,-606],[1742,282],[2404,-597],[904,269],[1633,-929],[2424,160],[922,2078],[-642,166]],[[598330,772830],[-1552,3481],[-238,1599],[-2940,519],[1851,-1185],[1771,-2191],[248,-1615],[860,-608]],[[519093,779803],[-793,572],[-699,-995],[1492,423]],[[598060,786080],[-477,2063],[-370,-1496],[-2947,-274],[-691,-4032],[1396,3312],[1118,595],[1023,-674],[948,506]],[[527029,786288],[-240,234]],[[526789,786522],[-1282,617]],[[525507,787139],[1032,-944]],[[526539,786195],[490,93]],[[825635,792558],[1620,3199],[-490,1285],[-1798,-2969],[668,-1515]],[[757740,790146],[-2251,-998],[622,-1428],[1629,2426]],[[734765,788675],[-2596,2000],[-262,2671],[340,1138],[1998,1271],[-1664,2431],[446,1097],[-1459,-559],[2041,-2300],[-1745,-2249],[-101,-3485],[-1101,-120],[3342,-3218],[761,1323]],[[760553,795780],[-1500,966],[-1096,-395],[1480,-1392],[1116,821]],[[592130,795130],[-1395,3067],[-92,-920],[-2031,776],[2414,-2351],[1104,-572]],[[662809,774782],[-63,-283]],[[662746,774499],[-880,-3290],[-81,-2711],[618,-374],[836,1696],[-121,4023]],[[663118,773843],[104,375]],[[663222,774218],[640,1702],[1079,-1224],[186,-2401]],[[665127,772295],[-179,-732]],[[664948,771563],[-498,-1754],[1691,-3336],[620,1333],[58,2571]],[[666819,770377],[23,2136]],[[666842,772513],[-175,2227],[-643,9],[218,1988],[1582,-394],[2240,2499],[162,813],[-1538,1592],[-1140,68],[-663,-1693],[1804,3],[-214,-1962],[-2400,103],[-1211,-2325],[-46,1648],[-1706,-751],[-303,-1556]],[[742708,752661],[-166,982],[-1185,542],[-376,-1675],[1727,151]],[[703585,752117],[-1682,832],[-17,-1401],[1699,569]],[[660075,754430],[-215,659]],[[659860,755089],[-770,252],[-497,-1984]],[[658593,753357],[-112,-1155]],[[658481,752202],[812,-1186],[1311,750],[-529,2664]],[[553592,755111],[-214,-628]],[[553378,754483],[495,-417]],[[553873,754066],[-86,1194]],[[553787,755260],[-195,-149]],[[717506,757030],[-149,861],[-2533,-379],[-3085,-1239],[102,-788],[1829,-813],[1647,-51],[2189,2409]],[[516297,816124],[-1241,1845],[-1057,-3142],[1265,-546],[1033,1843]],[[703851,819125],[51,1726],[-1161,44],[1110,-1770]],[[634409,825632],[1183,-1358],[145,-1724],[943,-1659],[1879,699],[-2208,287],[365,2372],[1415,1722],[-1964,-1244],[-1308,1336],[874,1313],[401,3009],[1077,272],[1377,1644],[3786,1378],[-3237,-375],[-2032,-734],[-1385,-1939],[-318,-1994],[-914,-462],[-79,-2543]],[[554900,827208],[1780,1468],[-1158,167],[-1782,-2619],[1160,984]],[[787591,822480],[-1194,3030],[438,1154],[-296,2720],[582,2473],[-947,5896],[-1558,234],[-2102,-1663],[761,-2664],[18,2978],[1444,772],[1153,-552],[976,-4508],[-665,-3079],[514,-1751],[-596,-2483],[754,-2311],[277,-3377],[441,3131]],[[713185,829568],[-35,-687],[2794,-326],[857,1577],[-1329,746],[-2287,-1310]],[[607446,848975],[857,2297],[-657,304],[-3077,3613],[-399,-1849],[1374,100],[216,-1895],[-2564,1819],[3079,-4609],[1171,220]],[[587585,849699],[-646,1460],[-1172,-1555],[1818,95]],[[576897,854139],[-443,162]],[[576454,854301],[-1548,-1193],[1826,-4688]],[[576732,848420],[152,25]],[[576884,848445],[395,2763],[-382,2931]],[[541480,852979],[-1184,-1323],[-1071,-3768],[344,-681],[1911,5772]],[[545566,856089],[-2918,-151],[1284,-796],[1634,947]],[[538995,854750],[20,1368],[-2508,170],[280,-2440],[-1181,897],[-539,-4145],[1156,1315],[2108,700],[664,2135]],[[574388,886199],[1329,-1605],[1852,1547],[-3181,58]],[[808666,875704],[-89,-3371],[864,42],[70,3529],[-604,2084],[1769,920],[-988,-1704],[1908,-641],[736,1839],[-1092,1421],[-2668,-1308],[-1701,923],[-963,1693],[843,-3241],[1968,-830],[-53,-1356]],[[601163,868433],[-2027,3839],[141,2843],[-3354,2343],[246,-1205],[2030,-1123],[560,-1699],[-1394,-144],[-1142,1644],[-29,-4945],[2298,-1770],[1032,-2898],[1572,2012],[67,1103]],[[575103,870033],[-456,1418],[-1619,-283],[2075,-1135]],[[565308,868591],[687,2172],[1572,1448],[-398,753],[-1313,-1732],[-548,-2641]],[[574860,877079],[-457,-1440],[-2353,-868],[458,2157],[-1308,-1179],[806,-1433],[-2040,-5057],[865,-1794],[573,2204],[-180,2069],[654,1513],[3076,2356],[-94,1472]],[[581993,872761],[1135,1841],[-1847,695],[192,-2281],[-3509,461],[-859,2011],[1692,22],[-591,2050],[-2474,1261],[823,-1749],[-36,-2598],[978,-1509],[2521,-1952],[-1514,-494],[-577,-1386],[-660,1288],[-1517,-2391],[2228,-540],[-349,-980],[2557,1064],[-381,2511],[1023,-550],[1885,1843],[-720,1383]],[[597257,880953],[-1849,2047],[1683,-3970],[166,1923]],[[592892,880587],[-374,-949],[2109,-325],[-1735,1274]],[[583315,879692],[-2504,1663],[836,-2316],[1169,-221],[1433,-1873],[-934,2747]],[[590325,892960],[-1483,2117],[-1322,-558],[2805,-1559]],[[550002,895031],[-92,1328],[-1727,-154],[1819,-1174]],[[580190,897575],[-2219,-1640],[1544,169],[675,1471]],[[755379,910475],[-7289,-911],[1729,-560],[6655,1098],[-1095,373]],[[744889,916455],[-2083,2995],[881,-2910],[1202,-85]],[[780618,942300],[1406,549],[-1870,3023],[3704,-1323],[-412,1551],[8865,1674],[-2125,1828],[-648,-1651],[-2725,-820],[-4020,-206],[-4747,1302],[1105,-1681],[-2744,-1047],[3870,-856],[341,-2343]],[[579019,915436],[-3570,-2388],[840,-960],[2478,660],[252,2688]],[[748524,915745],[1750,953],[4056,-718],[-3761,1228],[-3777,-1505],[1732,42]],[[589764,898704],[-271,1975],[-1256,137],[1527,-2112]],[[584338,890689],[964,-760],[2410,692],[-3374,68]],[[603422,861159],[2045,-467],[-643,1444],[-1402,-977]],[[582879,867448],[1589,-1766],[1945,-4630],[961,-1418],[679,1946],[2225,-351],[1233,2762],[-1159,2814],[-2642,1894],[-2011,2000],[-2820,-3251]],[[779963,809216],[-1131,409],[-518,-5760],[697,440],[952,4911]],[[756434,802727],[791,-1756],[2112,1637],[-1302,2231],[-1826,-1453],[225,-659]],[[692465,805016],[-1413,-1035],[-246,-1466],[1570,-68],[-579,1015],[668,1554]],[[805177,833755],[-802,1378],[-1061,-1398],[-62,-2025],[-3079,-7966],[-1466,-2430],[-1286,-1172],[-1723,-3464],[-1088,-858],[-2485,-3589],[-3818,-1032],[1665,-1374],[1211,-59],[2699,1251],[1080,1513],[354,2173],[4538,2709],[1981,3088],[750,253],[-264,2743],[1133,362],[866,1690],[-183,1343],[1040,6864]],[[292109,640353],[-1063,1606],[183,1013],[880,-2619]],[[752159,635584],[-729,-143],[459,1554],[-494,3009],[472,-131],[544,-1945],[-252,-2344]],[[284284,648382],[233,-3023],[-549,79],[-635,2768],[951,176]],[[856273,662620],[-854,-1163],[-828,-2143],[211,2010],[1460,2654],[11,-1358]],[[285484,658185],[54,3465],[-910,2455],[1298,-2211],[-442,-3709]],[[281964,663072],[1525,90],[-2020,-1408],[495,1318]],[[656077,664210],[-649,-1303],[-1687,-315],[2408,2105],[-72,-487]],[[836135,638730],[-470,-4119],[-718,2555],[-710,1103],[-704,3598],[241,3313],[1308,4559],[1141,3284],[1536,1437],[932,-1787],[-805,-4998],[-450,-4183],[-505,-2710],[-796,-2052]],[[284045,651095],[-4,-1445],[-833,-1043],[-1084,2015],[766,2339],[512,370],[643,-2236]],[[450460,673524],[-463,1570],[712,168],[-249,-1738]],[[188325,676558],[-210,-1398],[-654,463],[122,1897],[742,-962]],[[185678,676836],[-1180,2138],[-19,947],[1070,-1606],[129,-1479]],[[838507,691292],[-1462,897],[355,668],[1107,-1565]],[[634098,680225],[-539,1034],[287,1066],[252,-2100]],[[457220,671475],[32,-1616],[-892,-536],[76,2191],[784,-39]],[[859589,671840],[-799,241],[1458,1587],[-659,-1828]],[[454626,672853],[-899,-2209],[-687,1970],[2184,1117],[-598,-878]],[[460564,671605],[674,3389],[352,-926],[-279,-1965],[-747,-498]],[[577340,717578],[-351,1436],[1432,1552],[-400,-2182],[-681,-806]],[[594456,712459],[-2952,-2899],[-1368,910],[-367,1326],[1099,1290]],[[590868,713086],[636,1300],[1436,-323],[2790,1526],[-1447,-1786],[173,-1344]],[[874812,707856],[-735,35],[935,1481],[-200,-1516]],[[566256,715245],[1279,-1017],[1135,362],[2095,-703],[748,-969],[1175,429],[212,-1009],[-4012,-653],[-253,916],[-2292,930],[-934,1004],[847,710]],[[543268,731152],[-1325,-4513],[541,-2638],[-505,-1929],[-1697,657],[-997,1807],[-659,-18],[-4083,4261],[830,2152],[467,-878],[715,921],[1449,-1123],[2290,265],[944,747],[2030,289]],[[884288,728792],[-272,1022],[715,1904],[198,-1484],[-641,-1442]],[[557256,732117],[414,-1853],[-980,1577],[566,276]],[[572483,731138],[-689,2109],[873,-197],[-184,-1912]],[[300269,747979],[-3587,-2408]],[[296682,745571],[-2327,-92]],[[294355,745479],[1273,1664],[4641,836]],[[526334,758316],[195,-4003],[-1012,-4413],[-1052,1205],[-672,4558],[409,1138],[2132,1515]],[[508736,740452],[844,-171],[-1045,-2725],[-1949,1847],[2188,2117],[-38,-1068]],[[555771,738334],[-1191,1739],[527,556],[664,-2295]],[[565042,735526],[1899,-1704],[491,-2672],[-1436,1073],[-1407,2370],[-1061,411],[1514,522]],[[573361,737722],[483,-1765],[-1176,-33],[-879,1032],[1572,766]],[[570660,741596],[-224,-1038],[-831,1135],[1055,-97]],[[511926,740758],[-1253,797],[1065,332],[188,-1129]],[[526755,746921],[481,-2266],[-523,-6785],[-363,-1273],[-1194,591],[-486,-1933],[-647,81],[-640,1653],[359,3754],[-211,2686],[-782,2127],[96,1550],[965,-374],[1824,2411],[1121,-2222]],[[864373,703794],[1134,295],[355,-889],[-481,-1352],[998,-116],[222,-2433],[-679,-1487],[-1097,-7039],[-1811,-2308],[289,1504],[-373,2662],[-184,-3198],[-1078,671],[337,1834],[-355,2899],[1238,3131],[-717,2804],[-708,73],[133,-1502],[-967,-746],[-685,3027],[222,762],[1957,1597],[331,1186],[1304,221],[615,-1596]],[[452247,699446],[1382,-656],[-1327,-214],[-55,870]],[[850907,701549],[29,1403],[1566,324],[-78,-1031],[-1517,-696]],[[873214,707667],[778,-176],[282,-2406],[-1005,-1257],[-543,-2139],[-1527,1562],[-961,-894],[-858,-3069],[-931,-471],[-408,913],[-229,3044],[-909,-535],[1549,2073],[392,1792],[971,-386],[1245,532],[344,1305],[1027,717],[783,-605]],[[892303,749827],[628,190],[20,-4701],[929,-1896],[502,-2646],[-214,-4344],[-674,-808],[-530,-3381],[-997,-393],[-501,-2300],[301,-2858],[-190,-2756],[-946,-2958],[-16,-2628],[701,-1980],[-1157,-1272],[-114,-1441],[-1378,-2177],[-261,2353],[722,1444],[-699,697],[-552,-3057],[-1074,805],[-454,-2600],[-690,-1303],[-97,2107],[-626,661],[-1078,-2904],[-1794,403],[-1338,-483],[592,1124],[-1084,198],[-91,1503],[-886,-2259],[891,-2099],[-1455,-872],[-1149,-3644],[-1287,-50],[-771,2042],[-209,2313],[791,1256],[-1791,1569],[-1477,-400],[-667,-1010],[-2294,-1332],[-2512,-447],[-255,-2300],[-1127,1264],[-2282,-452],[237,2469],[971,122],[1395,1856],[2964,4650],[1259,-311],[2327,477],[2667,1231],[424,-1313],[981,-132],[1153,1567],[-247,1321],[1922,4452],[404,3792],[1331,829],[-1107,-2074],[257,-1984],[905,-396],[477,1074],[2238,1581],[1570,3706],[1432,1769],[1766,7515],[51,2004],[-679,761],[567,2590],[-254,1680],[914,1246],[372,2494],[671,-204],[143,-1790],[1221,-65],[226,2141],[-1109,-621],[379,2173],[812,-788]],[[877937,714367],[-468,-2295],[903,1565],[-435,730]],[[328330,795571],[-1162,-87]],[[327168,795484],[-3740,1896]],[[323428,797380],[-886,1532]],[[322542,798912],[-1542,1007],[857,675]],[[321857,800594],[3536,-1399],[2892,-2500]],[[328285,796695],[45,-1124]],[[915797,775121],[-60,1171],[1897,2214],[568,-30],[-2405,-3355]],[[323107,780571],[1533,-828]],[[324640,779743],[2683,385]],[[327323,780128],[389,-389],[-2374,-2489]],[[325338,777250],[-485,1590]],[[324853,778840],[-622,-690]],[[324231,778150],[-1339,1448],[-978,163]],[[321914,779761],[-770,1278]],[[321144,781039],[1096,2492]],[[322240,783531],[-262,-1695]],[[321978,781836],[1129,-1265]],[[331391,775898],[539,2552]],[[331930,778450],[1778,-263]],[[333708,778187],[103,-1152]],[[333811,777035],[-1550,-1839]],[[332261,775196],[-2494,-479]],[[329767,774717],[-588,2178],[1737,5066]],[[330916,781961],[1283,1226]],[[332199,783187],[213,-1397],[-681,-3528],[-1340,-2777],[1000,413]],[[906131,768341],[1001,-340],[-1266,-1152],[-1459,-2374],[1724,3866]],[[899511,766086],[2706,-1047],[1512,2332],[-671,-3374],[666,-2736],[1367,494],[-911,-1254],[-2429,-1347],[-1837,-389],[-1500,-2739],[-536,-2481],[-2024,1527],[-1823,1903],[-1236,-191],[-1169,-1213],[-1404,1287],[-459,-1334],[2322,-3135],[-1364,62],[-1420,-2324],[-426,908],[314,1993],[-799,2812],[196,1550],[1653,2374],[-261,1500],[2511,-614],[281,2626],[686,2232],[382,4129],[-553,2604],[985,2095],[2129,-4091],[1623,-2502],[1489,-1657]],[[295648,774097],[-1094,-164]],[[294554,773933],[1345,1560],[-251,-1396]],[[912776,773199],[-1906,-1939],[-710,-78],[-1251,-2510],[-861,-884],[969,2677],[1775,2189],[1984,545]],[[9463,811999],[432,-667]],[[9895,811332],[-1456,-891]],[[8439,810441],[1024,1558]],[[6513,810872],[1645,1335],[-236,-1097],[-1409,-238]],[[13068,812920],[2748,1149]],[[15816,814069],[-104,-820],[-2644,-329]],[[33432,820758],[-3061,-3029]],[[30371,817729],[1969,3695]],[[32340,821424],[1032,595]],[[33372,822019],[60,-1261]],[[134017,819872],[828,-2926]],[[134845,816946],[-375,-732]],[[134470,816214],[1025,-2515],[-2620,3729],[58,1281],[-1119,819]],[[131814,819528],[2203,344]],[[142910,818356],[118,-2495]],[[143028,815861],[-470,-1356],[-187,2806]],[[142371,817311],[-426,-530],[-772,2038]],[[141173,818819],[401,1553],[1336,-2016]],[[34659,820350],[-795,281],[1868,1201]],[[35732,821832],[440,2586]],[[36172,824418],[1857,-1573],[-1281,-1312],[-2089,-1183]],[[139308,819707],[-1857,2230]],[[137451,821937],[1590,-639]],[[139041,821298],[267,-1591]],[[131512,825393],[1448,-552]],[[132960,824841],[1295,634]],[[134255,825475],[-953,-5192]],[[133302,820283],[-2316,1437]],[[130986,821720],[-577,1603]],[[130409,823323],[11,2256]],[[130420,825579],[1092,-186]],[[531559,829920],[1050,-499],[-783,-1059],[-1172,856],[905,702]],[[883167,831111],[738,-350],[-1514,-2253],[-551,1304],[318,1916],[1009,-617]],[[45900,830448],[327,-1453]],[[46227,828995],[-4071,-1875]],[[42156,827120],[-178,1117],[994,1619]],[[42972,829856],[1839,938]],[[44811,830794],[1089,-346]],[[962916,829609],[-14,-859],[-2483,3557],[1457,103],[1040,-2801]],[[541910,830692],[-1121,476],[225,1152],[896,-1628]],[[534913,835213],[-983,-1888],[-980,-4110],[-579,2453],[-1021,105],[-854,3064],[1378,1314],[958,-1456],[130,1602],[1978,569],[-27,-1653]],[[129708,833783],[-959,-1626]],[[128749,832157],[44,1600],[915,26]],[[529569,834175],[390,-2823],[-2213,177],[-356,2087],[2179,559]],[[136169,833460],[-581,-1676]],[[135588,831784],[-721,1199]],[[134867,832983],[-874,-1440],[-232,1485]],[[133761,833028],[614,2461]],[[134375,835489],[988,732]],[[135363,836221],[806,-2761]],[[482975,836075],[-490,-1917],[-389,1335],[879,582]],[[563676,853234],[-1059,-811],[-1350,1503],[1475,815],[934,-1507]],[[128983,838496],[1009,-115]],[[129992,838381],[2860,-4972]],[[132852,833409],[-1162,-96]],[[131690,833313],[1708,-1515],[-438,-2939]],[[132960,828859],[-1800,1990]],[[131160,830849],[-892,1846]],[[130268,832695],[195,1361],[-1797,1157]],[[128666,835213],[317,3283]],[[280734,838063],[-2959,-1979]],[[277775,836084],[2024,3959]],[[279799,840043],[935,-1980]],[[132963,836150],[-1464,799]],[[131499,836949],[779,2491]],[[132278,839440],[868,-1507],[-183,-1783]],[[483950,838526],[-1108,-330],[205,2116],[903,-1786]],[[127916,837243],[-665,-301]],[[127251,836942],[-512,4513]],[[126739,841455],[641,555],[1123,-1671],[-587,-3096]],[[76620,850469],[855,-1179],[-1868,-861]],[[75607,848429],[-1666,423],[1500,1950]],[[75441,850802],[1179,-333]],[[552990,847363],[-730,-768],[261,-1825],[-2115,-2831],[-27,3770],[1113,1623],[1498,31]],[[75283,847292],[1304,11]],[[76587,847303],[590,-1474]],[[77177,845829],[-2940,-2078]],[[74237,843751],[-1341,-2179],[-1352,1686]],[[71544,843258],[-47,-1370]],[[71497,841888],[-1237,2510]],[[70260,844398],[475,1327]],[[70735,845725],[1404,422]],[[72139,846147],[349,1121]],[[72488,847268],[1055,-526],[1011,1426]],[[74554,848168],[729,-876]],[[545912,838208],[-323,1649],[1703,4598],[257,-149],[-1637,-6098]],[[125084,844493],[969,-3752]],[[126053,840741],[-93,-2907]],[[125960,837834],[-614,2625],[-1265,896],[363,1217]],[[124444,842572],[-838,1284],[-863,-1390]],[[122743,842466],[69,1825]],[[122812,844291],[1226,1278],[1046,-1076]],[[129538,842431],[1145,-729]],[[130683,841702],[-719,-2463]],[[129964,839239],[-1084,-3]],[[128880,839236],[-1046,3232]],[[127834,842468],[1704,-37]],[[482931,845403],[1218,-1399],[-676,-1326],[-2254,2354],[1428,1237],[284,-866]],[[125887,849293],[1223,-106],[-74,-1536]],[[127036,847651],[948,-3245]],[[127984,844406],[-1849,-1451],[291,2312],[-1170,4625],[631,-599]],[[123296,848287],[1697,351]],[[124993,848638],[197,-3377]],[[125190,845261],[-1573,1073],[-539,-1435],[-2435,3271],[685,1462],[1486,294],[482,-1639]],[[482781,850488],[-630,-2027],[-1476,-1606],[-153,2835],[2151,1624],[108,-826]],[[954541,851909],[350,2440],[2254,1221],[120,-1988],[-2724,-1673]],[[562826,852016],[1876,-816],[-1563,-1498],[-1507,-452],[-904,2031],[2098,735]],[[891694,943123],[-2524,1095],[2077,531],[447,-1626]],[[814964,945499],[-1680,-1810],[-3553,1529],[1614,1161],[3619,-880]],[[907764,951248],[4547,253],[119,-836],[4524,-315],[1507,-1627],[-2915,-1019],[-4179,314],[-5400,2207],[1797,1023]],[[210778,949266],[-2132,660]],[[208646,949926],[1503,1671]],[[210149,951597],[1956,-1581]],[[212105,950016],[-1327,-750]],[[240159,949216],[-12,-1995]],[[240147,947221],[-3196,-291]],[[236951,946930],[-5173,2064],[2469,3189]],[[234247,952183],[3455,383]],[[237702,952566],[2457,-3350]],[[449998,951464],[1151,-2456],[-3013,53],[-514,1881],[2376,522]],[[183799,965371],[-3325,1261]],[[180474,966632],[1941,652]],[[182415,967284],[1384,-1913]],[[250463,962485],[-3651,709],[-5,1308]],[[246807,964502],[2715,-79]],[[249522,964423],[941,-1938]],[[560022,970354],[4190,-3580],[4959,-1392],[-5833,-2848],[-192,1561],[-4675,-583],[1676,2859],[-3585,3503],[3460,480]],[[193893,964006],[-4872,-1067]],[[189021,962939],[-3367,1103],[-63,2262]],[[185591,966304],[5502,1043],[4304,-54],[-3358,-1451],[1854,-1836]],[[209605,962901],[-1869,-922],[-2364,3218],[4233,-2296]],[[234765,965592],[5282,-126]],[[240047,965466],[176,-1756],[-6854,57]],[[233369,963767],[1396,1825]],[[200410,955317],[-468,-1498]],[[199942,953819],[3136,-133]],[[203078,953686],[1376,1646]],[[204454,955332],[2543,-1863]],[[206997,953469],[-1060,-3283]],[[205937,950186],[-3586,-1567],[-4660,816]],[[197691,949435],[-5861,-2524],[-4385,-1315]],[[187445,945596],[-2762,79]],[[184683,945675],[-1718,1990]],[[182965,947665],[3602,1240],[3235,261]],[[189802,949166],[1770,1228],[-7438,-937]],[[184134,949457],[-847,2167]],[[183287,951624],[-1209,-2052]],[[182078,949572],[-3547,-710]],[[178531,948862],[-5198,1799]],[[173333,950661],[1238,1192]],[[174571,951853],[2992,119]],[[177563,951972],[2654,1261],[-5287,-618]],[[174930,952615],[1909,1655]],[[176839,954270],[-755,1141],[2858,2156]],[[178942,957567],[3852,83]],[[182794,957650],[1029,-1449]],[[183823,956201],[3128,-31],[4569,-3869]],[[191520,952301],[5461,-249],[-1970,2112]],[[195011,954164],[1016,1458]],[[196027,955622],[-2333,1824],[2588,2032]],[[196282,959478],[2421,-133],[-127,-1769]],[[198576,957576],[1834,-2259]],[[889023,953962],[2131,-1174],[1859,3000],[2709,-1385],[3404,-235],[4359,-1648],[-1033,-1876],[-2398,-1329],[-3584,1736],[758,1909],[-2545,5],[1474,-3125],[1420,-965],[-1820,-888],[-1349,1012],[-4776,-855],[-1839,585],[-1407,-1713],[-2797,835],[-2429,1933],[141,3707],[4586,2650],[3136,-2179]],[[877634,951478],[-1379,-120],[685,2700],[694,-2580]],[[238068,960381],[3611,-1730]],[[241679,958651],[4696,358],[5273,-2913]],[[251648,956096],[-5202,-173]],[[246446,955923],[5762,-2357],[-1225,-1167],[2026,-659]],[[253009,951740],[4609,971],[3302,-685]],[[260920,952026],[5935,1877]],[[266855,953903],[4940,71]],[[271795,953974],[5088,-1196]],[[276883,952778],[1910,-2546]],[[278793,950232],[-2009,-875],[2656,-794]],[[279440,948563],[-2434,-1991]],[[277006,946572],[-4253,-622]],[[272753,945950],[-9035,772]],[[263718,946722],[-425,-523],[-8913,-145]],[[254380,946054],[231,1722]],[[254611,947776],[-4179,-1399],[-5881,1449]],[[244551,947826],[-1293,3277]],[[243258,951103],[995,1846],[-2842,4124],[-6062,-532]],[[235349,956541],[-4365,2738]],[[230984,959279],[243,1454]],[[231227,960733],[3111,545]],[[234338,961278],[3730,-897]],[[168348,952708],[4562,2934],[350,-868],[-2743,-2669],[-2169,603]],[[228608,957739],[1014,-6202]],[[229622,951537],[-940,-1733]],[[228682,949804],[-2484,-698]],[[226198,949106],[-4627,-9]],[[221571,949097],[-1380,2007]],[[220191,951104],[3167,1830]],[[223358,952934],[-8195,-840]],[[215163,952094],[1662,2193]],[[216825,954287],[235,3289]],[[217060,957576],[5106,-2959]],[[222166,954617],[-2419,3175]],[[219747,957792],[6056,1294]],[[225803,959086],[2805,-1347]],[[216034,955063],[-3020,-1484],[-2878,2477]],[[210136,956056],[4908,588]],[[215044,956644],[990,-1581]],[[211047,958429],[2699,-788]],[[213746,957641],[-3387,-733]],[[210359,956908],[688,1521]],[[448381,955226],[-1397,2299],[981,1254],[416,-3553]],[[179024,963052],[-2040,-1550]],[[176984,961502],[181,-2906],[-2593,-1855]],[[174572,956741],[-2406,880]],[[172166,957621],[666,2001]],[[172832,959622],[-2809,-1607]],[[170023,958015],[-1046,-2290],[-989,1266],[-1080,-2852]],[[166908,954139],[-3074,957]],[[163834,955096],[-3836,-451]],[[159998,954645],[97,2707],[2089,239],[7010,5116]],[[169194,962707],[5031,50],[2544,1359]],[[176769,964116],[2255,-1064]],[[546629,978121],[3249,-1200],[3148,-3242],[2981,-67],[3406,-2402],[-4500,-696],[-3693,-3541],[-4830,-8566],[-6149,3672],[-1155,2163],[8228,1383],[-501,675],[-6247,-859],[-2565,1550],[8601,1910],[16,1855],[-3792,-1128],[-263,1824],[-2377,-626],[475,-1545],[-4133,-1051],[-3823,2839],[1391,1114],[-1930,2245],[-1033,-911],[-950,3951],[6037,-660],[2550,-2047],[1767,2719],[4725,-4843],[-1329,4150],[2696,1334]],[[306975,996546],[8048,-431]],[[315023,996115],[-2237,-1635]],[[312786,994480],[6922,1379],[5055,-1988]],[[324763,993871],[4467,-581]],[[329230,993290],[-1943,-2511]],[[327287,990779],[-6660,-1834],[-5699,-695]],[[314928,988250],[-4700,-2105]],[[310228,986145],[7173,1381]],[[317401,987526],[699,-1242]],[[318100,986284],[-8741,-3591]],[[309359,982693],[-7659,-5431],[-5790,-32],[17,-1548]],[[295927,975682],[-4981,-439]],[[290946,975243],[-4554,541]],[[286392,975784],[6573,-2724],[-11248,133]],[[281717,973193],[1942,-786]],[[283659,972407],[4519,382]],[[288178,972789],[5063,-1675]],[[293241,971114],[-1237,-1062]],[[292004,970052],[-4153,-140],[3278,-1146]],[[291129,968766],[-1868,-1883],[-5963,-378]],[[283298,966505],[-177,-2530]],[[283121,963975],[-2203,-1105]],[[280918,962870],[-6244,-373]],[[274674,962497],[4934,-659]],[[279608,961838],[334,-1317]],[[279942,960521],[2589,247]],[[282531,960768],[12,-2408],[-6683,-2339]],[[275860,956021],[-1334,1992]],[[274526,958013],[-3776,1247],[824,-1525]],[[271574,957735],[-4590,-75]],[[266984,957660],[-3488,-880]],[[263496,956780],[-2707,772]],[[260789,957552],[-6334,-177]],[[254455,957375],[-3261,515]],[[251194,957890],[195,1984],[3060,1641]],[[254449,961515],[4295,418],[-3453,3228]],[[255291,965161],[2992,1025]],[[258283,966186],[3971,-2555]],[[262254,963631],[2361,-592]],[[264615,963039],[2664,1016]],[[267279,964055],[-4194,157]],[[263085,964212],[-717,2184]],[[262368,966396],[1453,2279]],[[263821,968675],[-3315,-1370]],[[260506,967305],[827,1550]],[[261333,968855],[-4533,-984],[2067,3540]],[[258867,971411],[5011,818]],[[263878,972229],[4812,-841]],[[268690,971388],[2313,790]],[[271003,972178],[-3158,889],[-4206,3309],[-3697,1380]],[[259942,977756],[316,2809]],[[260258,980565],[7176,-535],[5189,-3001]],[[272623,977029],[2349,-174],[-5420,3465]],[[269552,980320],[8084,1485]],[[277636,981805],[8891,2071]],[[286527,983876],[-4724,256],[733,1459],[-7556,-3038]],[[274980,982553],[-8525,-584],[-9038,672]],[[257417,982641],[-4421,805]],[[252996,983446],[1412,1150]],[[254408,984596],[-4262,1025],[4079,2322]],[[254225,987943],[-8122,80]],[[246103,988023],[2535,1771]],[[248638,989794],[7920,1232]],[[256558,991026],[7206,-606]],[[263764,990420],[-4267,1210],[4678,1554]],[[264175,993184],[15200,-3524]],[[279375,989660],[-8407,3393]],[[270968,993053],[4004,2085],[6281,-591]],[[281253,994547],[-3906,1373]],[[277347,995920],[20398,1008],[9230,-382]],[[38512,862457],[1128,-411],[383,-2376]],[[40023,859670],[-1431,-816],[-2868,1381]],[[35724,860235],[-825,1173]],[[34899,861408],[1666,62]],[[36565,861470],[1947,987]],[[89622,859078],[1542,3229]],[[91164,862307],[539,-616]],[[91703,861691],[-2081,-2613]],[[319909,868276],[-1665,1681]],[[318244,869957],[1784,75],[-119,-1756]],[[291239,908966],[74,-4127]],[[291313,904839],[-1814,-1504],[-3402,-98]],[[286097,903237],[-836,2602],[1571,3111]],[[286832,908950],[2427,625],[1980,-609]],[[295495,906299],[-2644,266],[-369,1412],[3531,-575]],[[296013,907402],[-518,-1103]],[[639625,914604],[-1775,-1932],[-2665,-750],[-1078,1820],[979,2346],[1650,444],[2889,-1928]],[[543778,910905],[1580,1867],[528,-1442],[-1685,-1444],[-4597,-1176],[3208,2518],[196,2533],[1138,1390],[-368,-4246]],[[542241,913167],[42,-1936],[-1948,99],[1906,1837]],[[279970,912589],[-542,459]],[[279428,913048],[2248,2652]],[[281676,915700],[1021,-396]],[[282697,915304],[-2727,-2715]],[[259456,906015],[-1011,2159]],[[258445,908174],[1496,493]],[[259941,908667],[-485,-2652]],[[291997,909646],[-1442,1047],[1157,724]],[[291712,911417],[285,-1771]],[[304619,875284],[-1192,285]],[[303427,875569],[-1024,1666]],[[302403,877235],[1923,-856]],[[304326,876379],[293,-1095]],[[23714,881749],[2868,349]],[[26582,882098],[2786,-2077],[1975,-223]],[[31343,879798],[-377,-826]],[[30966,878972],[-2572,-459]],[[28394,878513],[-2080,1691]],[[26314,880204],[-3512,269]],[[22802,880473],[912,1276]],[[284615,879658],[-1122,-1024]],[[283493,878634],[-1569,1996]],[[281924,880630],[2232,-120],[459,-852]],[[285098,881443],[641,554],[1267,-1706],[-1908,1152]],[[264112,891353],[853,1104],[7118,-4758]],[[272083,887699],[1039,-2557],[-630,-1075]],[[272492,884067],[2983,348]],[[275475,884415],[1463,-1942]],[[276938,882473],[-2067,-1781]],[[274871,880692],[-3699,1453]],[[271172,882145],[-248,1304]],[[270924,883449],[-2853,1020]],[[268071,884469],[-650,-1693]],[[267421,882776],[-2513,-2986]],[[264908,879790],[-2396,-1008]],[[262512,878782],[-860,3361],[-2894,-777]],[[258758,881366],[-950,574]],[[257808,881940],[2603,2753],[-340,2541]],[[260071,887234],[1146,6745]],[[261217,893979],[1131,1269]],[[262348,895248],[1764,-3895]],[[456824,897085],[1909,906],[-723,-1653],[769,-1905],[3246,-1371],[250,-2408],[-2684,-4130],[-4204,-1983],[-1611,-1456],[-3266,-903],[-2327,-1815],[-4289,883],[-2913,2249],[-3778,-581],[-379,1079],[1907,308],[1139,1934],[-2279,2353],[-4331,405],[5928,1098],[-1615,1054],[1748,1308],[-2939,788],[-2771,-1024],[-1542,550],[953,1536],[2296,-57],[-1255,1892],[1995,-517],[1593,521],[-1873,1701],[1927,432],[2831,-2396],[-70,-3268],[840,-1229],[1083,2319],[792,-516],[272,2739],[2485,-1546],[220,1797],[1681,552],[1885,-2007],[-550,1940],[2074,-1144],[1103,1413],[1125,-422],[577,1867],[1543,402],[1228,-1695]],[[481580,873383],[-254,-1407],[-1249,1749],[1503,-342]],[[279041,874472],[614,-2284]],[[279655,872188],[-957,-2261],[-1657,1029]],[[277041,870956],[677,3109]],[[277718,874065],[1323,407]],[[272221,877686],[-315,-1789]],[[271906,875897],[-2506,-2620]],[[269400,873277],[-1897,-294]],[[267503,872983],[-173,848]],[[267330,873831],[-420,723]],[[266910,874554],[36,302]],[[266946,874856],[1453,2538]],[[268399,877394],[3822,292]],[[0,890205],[0,1449]],[[0,891654],[0,21752],[3127,-1359],[505,-1232],[9297,-5142],[1377,-1952],[-210,-4298],[1476,-1654],[1079,2575],[-1228,1921],[2133,247],[1253,-1043],[3980,-218],[4310,-4517],[1295,-155],[-2118,-1646],[-349,-1445],[-2180,1024],[1101,-1448],[-2368,-319],[-2434,1096],[1587,-1516],[-3,-2233],[-2184,-1017],[-28,-3431],[-2755,898],[-880,1118],[-2993,976],[-1273,1235],[-666,2726],[-2674,845],[-3483,-763],[-2214,5101],[-1880,-1943],[1199,-2969],[-1799,-2663]],[[264792,893213],[-1282,1457]],[[263510,894670],[549,1112]],[[264059,895782],[733,-2569]],[[267428,894527],[-1090,-148]],[[266338,894379],[-803,2127],[1893,-1979]],[[259474,925417],[4151,836]],[[263625,926253],[624,-889]],[[264249,925364],[584,3462]],[[264833,928826],[-3477,2372]],[[261356,931198],[1405,1352],[2929,-960],[-2749,2184]],[[262941,933774],[-843,2092],[1739,3324],[3435,482]],[[267272,939672],[3118,1852],[3482,-563],[3142,-5266],[-2651,-2571]],[[274363,933124],[1030,-2371],[2268,2860]],[[277661,933613],[3730,-253],[2703,-1016]],[[284094,932344],[-1734,2489],[4047,714]],[[286407,935547],[4442,-1421]],[[290849,934126],[1086,-2253]],[[291935,931873],[1695,-297]],[[293630,931576],[-308,-2239]],[[293322,929337],[4172,32],[4572,-1873]],[[302066,927496],[-664,-1520],[1952,-12]],[[303354,925964],[381,-1376]],[[303735,924588],[-1724,-2195]],[[302011,922393],[3684,2042]],[[305695,924435],[4421,-1908]],[[310116,922527],[-1557,-1872]],[[308559,920655],[485,-1573],[1732,2211]],[[310776,921293],[2102,-1660]],[[312878,919633],[395,-1800]],[[313273,917833],[-2479,139]],[[310794,917972],[-1108,-1048]],[[309686,916924],[4839,-1425]],[[314525,915499],[-89,-1090]],[[314436,914409],[-3154,565]],[[311282,914974],[518,-1241]],[[311800,913733],[-795,-2890]],[[311005,910843],[3678,-624]],[[314683,910219],[-325,-1362]],[[314358,908857],[1718,384],[-559,-2228],[3991,824]],[[319508,907837],[2280,-2491]],[[321788,905346],[889,-2126]],[[322677,903220],[2211,-172],[-1837,-2445]],[[323051,900603],[4814,1165],[1858,-2195]],[[329723,899573],[-1564,-1989]],[[328159,897584],[-1918,557]],[[326241,898141],[1560,-2201]],[[327801,895940],[-1663,-5]],[[326138,895935],[-191,-2337]],[[325947,893598],[-1885,-138],[-747,-4080]],[[323315,889380],[-803,1074]],[[322512,890454],[-1832,43]],[[320680,890497],[-2351,3836]],[[318329,894333],[1103,1858]],[[319432,896191],[-2282,-478]],[[317150,895713],[-2671,3310]],[[314479,899023],[-1444,83],[-11,-1576],[-1548,1105]],[[311476,898635],[1904,-2700]],[[313380,895935],[-2983,-568],[3164,-2952],[-578,-496]],[[312983,891919],[1831,-2268],[2023,-521]],[[316837,889130],[2400,-2661]],[[319237,886469],[-265,-2421]],[[318972,884048],[1365,0]],[[320337,884048],[456,-4527],[-1882,2964]],[[318911,882485],[396,-3137]],[[319307,879348],[1016,-1969]],[[320323,877379],[-1331,179]],[[318992,877558],[313,-1697]],[[319305,875861],[-3261,2732],[-529,-474]],[[315515,878119],[-2126,1645]],[[313389,879764],[-1982,2540]],[[311407,882304],[474,-1842]],[[311881,880462],[-2142,1793],[-1159,-131]],[[308580,882124],[2138,-3146],[1293,-466]],[[312011,878512],[4710,-5241]],[[316721,873271],[-768,-2018]],[[315953,871253],[-3287,1676]],[[312666,872929],[-2607,497],[-1955,1008]],[[308104,874434],[-1285,2010],[-1920,112]],[[304899,876556],[-2826,1654],[-1998,2293],[1436,489],[-2131,1165]],[[299380,882157],[-3390,4234]],[[295990,886391],[-4091,2183]],[[291899,888574],[767,-1392],[-6156,-1892],[-2597,767]],[[283913,886057],[-1065,1485]],[[282848,887542],[219,1905]],[[283067,889447],[2041,1524]],[[285108,890971],[95,1520]],[[285203,892491],[4162,-1339],[333,524]],[[289698,891676],[5994,1005]],[[295692,892681],[-543,1668],[-1910,2206],[3424,3318],[2726,3289]],[[299389,903162],[-3020,6597]],[[296369,909759],[-937,-434]],[[295432,909325],[-894,1684],[-1267,6],[-1375,2388],[-4128,-1721]],[[287768,911682],[-427,1878]],[[287341,913560],[1676,127]],[[289017,913687],[463,1704]],[[289480,915391],[-1725,727]],[[287755,916118],[-292,1438]],[[287463,917556],[-2996,958]],[[284467,918514],[-697,2378]],[[283770,920892],[-1223,-106]],[[282547,920786],[-2176,2219],[-781,-1370],[1272,-2340],[-2018,-490]],[[278844,918805],[-5399,1283]],[[273445,920088],[-1608,-1600]],[[271837,918488],[-2646,964]],[[269191,919452],[-2133,-244]],[[267058,919208],[-6842,1081]],[[260216,920289],[-839,1516]],[[259377,921805],[-3546,-884]],[[255831,920921],[-2632,1606]],[[253199,922527],[-1688,3192]],[[251511,925719],[4475,-695]],[[255986,925024],[1957,398]],[[257943,925422],[-2033,1167],[-3353,470]],[[252557,927059],[-2129,1211]],[[250428,928270],[-498,2703]],[[249930,930973],[453,2745]],[[250383,933718],[1662,3893],[4288,3874]],[[256333,941485],[2641,658]],[[258974,942143],[4608,-153]],[[263582,941990],[377,-672],[-3088,-2574],[-1508,-2308]],[[259363,936436],[1647,-6515]],[[261010,929921],[2814,-2475]],[[263824,927446],[-4350,-2029]],[[301559,899263],[867,-1573],[-276,-2234],[1790,1987],[2847,-459],[185,2188],[-2702,1022],[-1976,1627],[-735,-2558]],[[303757,887946],[-344,2276],[-2683,2000],[626,-2975],[-1076,-1051],[1111,-705],[1617,1086],[749,-631]],[[496366,863369],[710,-551],[-621,-1955],[-1077,995],[988,1511]],[[310717,863514],[897,-667]],[[311614,862847],[-1518,-1158],[621,1825]],[[996837,924325],[82,2397],[3080,1817],[0,-3227],[-3162,-987]],[[0,925312],[0,1133]],[[0,926445],[0,1276]],[[0,927721],[0,818]],[[0,928539],[4572,-51],[2283,-1576],[-804,-1158],[-4681,-855],[-1370,413]],[[970001,916943],[-3922,1519],[1581,1060],[2825,-789],[-484,-1790]],[[565112,924262],[-3005,-1783],[-1012,843],[4017,940]],[[429354,924887],[84,-1591],[-2421,-1176],[-919,587],[-3593,-589],[525,2626],[2036,-204],[3214,1072],[1074,-725]],[[948519,912918],[-918,1240],[595,1534],[323,-2774]],[[232499,915545],[1985,-3018]],[[234484,912527],[-2266,-2158]],[[232218,910369],[-2974,431]],[[229244,910800],[-2357,1773],[-3112,444]],[[223775,913017],[-41,1265],[2777,1204]],[[226511,915486],[522,2488],[1326,635]],[[228359,918609],[4140,-3064]],[[286124,914356],[-898,1615]],[[285226,915971],[1805,-297],[-907,-1318]],[[548619,917037],[1392,-541],[-149,-1818],[-2193,-1020],[-442,1990],[1392,1389]],[[277839,916524],[-2223,991]],[[275616,917515],[3289,791],[-1066,-1782]],[[358295,916778],[-935,1790],[1865,-37],[-930,-1753]],[[353524,919101],[1905,-814],[-187,-1885],[-4071,-1377],[-685,1680],[-3040,1027],[1658,1353],[-1370,1466],[1233,757],[2768,-568],[1789,-1639]],[[553486,919822],[936,-570],[-2243,-2318],[-1209,1120],[2398,2841],[118,-1073]],[[667917,919042],[-28,-1237],[-4132,989],[-1333,2215],[1479,1176],[4014,-3143]],[[475129,924399],[1694,1784],[948,-586],[-2642,-1198]],[[647614,926786],[-329,-1618],[-2148,1873],[2477,-255]],[[720837,935555],[-2348,1009],[1411,1197],[937,-2206]],[[715645,933003],[-2018,38],[1869,1974],[2184,-880],[-2035,-1132]],[[347175,935965],[-1408,-1320],[-1920,892],[3328,428]],[[223930,942411],[4686,1360],[-1247,-1303],[-3439,-57]],[[182061,934716],[2661,676]],[[184722,935392],[811,1698]],[[185533,937090],[5384,-1584]],[[190917,935506],[-1737,-2119]],[[189180,933387],[2097,55],[2596,1753]],[[193873,935195],[-1264,2056],[1812,-146],[3639,-2869],[1355,-4433]],[[199415,929803],[2513,851],[-1083,1508]],[[200845,932162],[-1507,5667]],[[199338,937829],[581,1439]],[[199919,939268],[2995,-431],[3162,-1572]],[[206076,937265],[4064,-9341]],[[210140,927924],[-611,-1954]],[[209529,925970],[1711,-2023]],[[211240,923947],[2511,-637],[4131,-3081],[1444,-144]],[[219326,920085],[298,-2344],[-3608,753]],[[216016,918494],[-1075,-1723]],[[214941,916771],[-2050,794]],[[212891,917565],[747,-2805]],[[213638,914760],[1787,1566],[1309,-410],[329,-2270],[-2883,-1187]],[[214180,912459],[-6141,574]],[[208039,913033],[240,953]],[[208279,913986],[-3115,478]],[[205164,914464],[-1439,1645],[-2169,-2592]],[[201556,913517],[-4184,-1436],[-6569,-1290]],[[190803,910791],[-5047,-284]],[[185756,910507],[-1359,2040]],[[184397,912547],[-214,2113]],[[184183,914660],[-4069,413]],[[180114,915073],[-3763,947]],[[176351,916020],[-1640,2248],[-87,1754]],[[174624,920022],[7064,1258],[5428,-517]],[[187116,920763],[2793,495]],[[189909,921258],[-5902,2263]],[[184007,923521],[-6204,-619]],[[177803,922902],[-4434,256]],[[173369,923158],[-1880,1534],[1250,1600],[5340,1323]],[[178079,927615],[846,975]],[[178925,928590],[-5934,-923]],[[172991,927667],[-54,1592],[-3127,163]],[[169810,929422],[-213,1770]],[[169597,931192],[2032,1642]],[[171629,932834],[-448,1607]],[[171181,934441],[2286,1760]],[[173467,936201],[8093,3209]],[[181560,939410],[1318,-609]],[[182878,938801],[152,-2422]],[[183030,936379],[-969,-1663]],[[167398,943794],[1680,-502]],[[169078,943292],[1633,1284]],[[170711,944576],[2859,-77]],[[173570,944499],[5567,-3631]],[[179137,940868],[177,-1066]],[[179314,939802],[-9763,-4471]],[[169551,935331],[-1239,-1918],[-2145,-876],[-1221,-4188]],[[164946,928349],[-3139,-361]],[[161807,927988],[-3299,-2114],[-2974,3493]],[[155534,929367],[-4875,2725]],[[150659,932092],[2154,2668]],[[152813,934760],[419,2893]],[[153232,937653],[2887,4099]],[[156119,941752],[-2498,3437]],[[153621,945189],[9391,1077]],[[163012,946266],[4869,-1760]],[[167881,944506],[-483,-712]],[[222216,942806],[2345,-1271]],[[224561,941535],[4378,925]],[[228939,942460],[1612,-1309],[-753,-1657]],[[229798,939494],[-3234,-2290]],[[226564,937204],[2670,-48]],[[229234,937156],[880,-2070]],[[230114,935086],[1713,331]],[[231827,935417],[-705,-2280]],[[231122,933137],[507,-2844]],[[231629,930293],[-2691,-1209]],[[228938,929084],[-2435,850]],[[226503,929934],[723,-1969]],[[227226,927965],[-2690,-436],[-3965,4650]],[[220571,932179],[-3138,964],[-2749,2773]],[[214684,935916],[2198,1623]],[[216882,937539],[1588,-1840]],[[218470,935699],[2405,158]],[[220875,935857],[1078,1127]],[[221953,936984],[-951,1726]],[[221002,938710],[-2810,1045]],[[218192,939755],[1488,2218]],[[219680,941973],[2536,833]],[[416796,999793],[11551,-1800],[-17216,-1041],[13863,-107],[5218,547],[1814,-1672],[8193,-1670],[-6503,-1827],[-15882,-746],[-643,-1219],[12951,271],[2377,-1778],[3304,1841],[4904,337],[532,-2213],[-5350,-4552],[3170,731],[5321,3046],[7111,-987],[5278,2582],[9341,-1093],[1845,-1333],[-8263,-3915],[-6270,-1125],[2287,-863],[-2586,-1359],[-7113,351],[-1971,-2692],[2375,-711],[580,-3145],[-5225,-3538],[-2199,-4529],[2458,718],[3811,-1143],[-3306,-592],[1247,-1484],[5257,-908],[-475,-2589],[-6755,644],[-2598,-1858],[1279,-1832],[3648,-268],[1651,-2733],[232,-3126],[-2942,500],[-3608,-2031],[2378,485],[879,-1926],[1739,1463],[2112,-2937],[-401,-1158],[-4890,-1025],[-3346,1038],[-3,-1320],[5467,-1275],[-396,-2105],[-4654,-1321],[-2230,452],[-3249,2478],[-1760,-1500],[-5450,-2312],[6017,1789],[1912,-146],[5174,-2843],[-714,-4733],[-4933,2246],[-1558,3193],[-5632,-1907],[5240,906],[290,-2555],[7519,-4104],[-1509,-1447],[2086,-132],[637,-5640],[-3244,-526],[-3059,698],[-2140,3960],[-3676,2064],[-3393,-233],[3748,-549],[43,-1519],[-2710,-1382],[-4404,337],[649,-1826],[-1310,-1317],[5647,-474],[-2924,-1613],[5642,1355],[6546,-1414],[2469,67],[-2028,-1901],[-6039,-3225],[267,-565],[-3469,-2743],[-8078,-2390],[-1720,76],[-2062,-1148],[-2246,63],[-2522,1829],[453,-2643],[-2757,-2160],[-2624,-5335],[-3019,-2818],[-1886,1131],[658,-1785],[-2081,-1831],[-1898,240],[-1920,-1649],[-686,691],[1972,3639],[-1281,-370],[-2458,-3774],[-4318,-605],[1705,-1076],[-1877,-1730],[-2308,309],[2506,-3679],[-1665,-1529],[642,-2942],[-1384,-1252],[-163,-1422],[-2641,-3435],[-2454,155],[2191,-899],[-468,-2463],[587,-1751],[-593,-1039],[-1093,-5417],[-1607,-1911],[480,-2273],[-2762,-1358],[-934,1081],[-2572,1116],[-3,1434],[-1851,1012],[548,3349],[-2848,-2160],[-3696,234],[-1991,2497],[-1273,3631],[1532,1122],[-2208,-480],[195,1387],[-2127,1425],[-197,2066],[-2996,4860],[-664,3334],[1323,2105],[3083,849],[-1667,556],[-1887,-1033],[-1449,-2396],[-474,1168],[-708,6194],[-2363,785],[257,2271],[-794,421],[3711,2719],[2153,2273],[-4558,-3851],[-1924,-512],[-56,1536],[1657,2447],[-2350,1829],[238,1675],[3145,1964],[4125,-671],[591,1008],[-3823,180],[-3862,-1706],[1621,3903],[4318,-907],[1083,1603],[-3253,-633],[-2791,468],[955,1857],[2046,535],[1450,-906],[1476,1135],[1470,5839],[1190,1712],[-5452,264],[-2135,1439],[-2753,710],[-1435,1645],[1014,716],[3789,-413],[3548,-1843],[411,4026],[-4531,361],[717,1905],[-1918,459],[-104,1606],[-1349,-2317],[-3815,-190],[-920,1184],[978,2866],[-795,2032],[2254,1115],[146,1368],[-2652,1424],[1098,885],[-2241,1752],[485,1999],[-2158,1918],[1252,1823],[-6522,5086],[243,1799],[-7941,2908],[-5733,946],[-4092,-989],[-5953,-123],[1056,-1033],[-4094,531],[-3710,1967],[3502,1650],[-6161,769],[-1171,2180],[5235,118],[1074,872],[6118,-369],[-839,2375],[-7389,-1268],[-7538,2783],[-2092,1526],[1174,1835],[9450,2092],[4198,1538],[4207,92],[1522,1232],[2431,4719],[-3516,-668],[-3697,843],[404,1461],[8623,3812],[2314,-1012],[431,1970],[4076,-501],[557,3324],[5483,1849],[12599,2042],[3178,-1718],[2240,1542],[5225,-2527],[3759,136],[-4024,3211],[5913,-324],[9917,-3416],[2107,119],[816,3076],[-3649,2116],[11439,316],[-9982,634],[-1074,781],[6681,1464],[4748,-970],[2620,1371],[5774,-1975],[1251,2883],[21874,470]],[[653666,939029],[3082,-635],[-960,-2440],[-2022,-1922],[-162,-3137],[2071,-3494],[2366,-2480],[2029,-1174],[-1332,-828],[-7069,539],[-3382,1145],[2145,1494],[-2200,2464],[-4309,-297],[-1038,1691],[399,1744],[1860,347],[3105,4663],[-478,1367],[4461,1423],[1434,-470]],[[202996,940045],[854,1278]],[[203850,941323],[3059,416],[2400,-897]],[[209309,940842],[183,-1543]],[[209492,939299],[-2102,-2601],[-4394,3347]],[[894957,942510],[3218,-1938],[410,-1911],[-5262,383],[-3378,1020],[1956,2267],[3056,179]],[[241192,944080],[2634,-1117]],[[243826,942963],[3152,218],[2037,-834]],[[249015,942347],[-4898,-6603],[-5815,18]],[[238302,935762],[1822,-1989]],[[240124,933773],[-1340,-2325]],[[238784,931448],[-3209,-8]],[[235575,931440],[-985,4468]],[[234590,935908],[-237,5414]],[[234353,941322],[2598,-189]],[[236951,941133],[-951,2135]],[[236000,943268],[5192,812]],[[279063,941080],[3474,67]],[[282537,941147],[3000,-985]],[[285537,940162],[2547,-2480]],[[288084,937682],[-308,-1542],[-3987,451]],[[283789,936591],[-4624,-835]],[[279165,935756],[-1897,2777]],[[277268,938533],[-1780,924]],[[275488,939457],[171,2234],[3404,-611]],[[696316,937765],[-2094,-63],[637,2135],[2197,413],[1905,-2017],[-2645,-468]],[[688236,956383],[-4119,-1504],[-13684,-3964],[-2374,-2429],[-3890,-2353],[-1573,-51],[-259,-2192],[-4105,-4516],[-1482,-411],[-3954,928],[-1964,-611],[-1491,2461],[2444,1146],[2609,3958],[2546,1951],[1636,2529],[1442,-252],[3540,3042],[5725,1283],[721,1248],[4916,-268],[8032,2230],[4644,2338],[2641,-439],[1151,-2138],[-3152,-1986]],[[933113,802729],[-1883,-1229],[-69,1204],[1283,609],[1157,2200],[-488,-2784]],[[146674,804734],[4765,-1918],[2331,-5262],[1797,-1212]],[[155567,796342],[1386,-3803],[-272,-1472]],[[156681,791067],[-3041,1562],[-1198,969]],[[152442,793598],[753,1585]],[[153195,795183],[-1696,-517]],[[151499,794666],[-511,1450]],[[150988,796116],[-1665,1522],[-289,1292]],[[149034,798930],[-2506,2827]],[[146528,801757],[-1706,-61]],[[144822,801696],[-116,1881]],[[144706,803577],[1165,-240],[57,1057]],[[145928,804394],[-1647,-501]],[[144281,803893],[-798,1456]],[[143483,805349],[1189,689]],[[144672,806038],[2002,-1304]],[[345948,810042],[-1590,-1232],[443,-2495],[-2285,-5023]],[[342516,801292],[-356,-2642]],[[342160,798650],[1598,2823]],[[343758,801473],[238,-888]],[[343996,800585],[1754,338]],[[345750,800923],[-1417,-1733]],[[344333,799190],[-131,-1497],[2445,178]],[[346647,797871],[-104,-1672]],[[346543,796199],[2153,1955],[16,-1114],[1405,593],[940,-712]],[[351057,796921],[128,-1069]],[[351185,795852],[-1091,-2574],[744,-160]],[[350838,793118],[-1027,-1546]],[[349811,791572],[2807,1423]],[[352618,792995],[-218,-1523],[-1316,-1152]],[[351084,790320],[-700,-2418]],[[350384,787902],[716,-812]],[[351100,787090],[892,1988],[1158,682]],[[353150,789760],[-860,-2725]],[[352290,787035],[147,-1173],[945,1863],[357,-1304]],[[353739,786421],[-1155,-5143],[-1519,-7]],[[351065,781271],[-55,2711]],[[351010,783982],[-1493,-1524]],[[349517,782458],[846,3001]],[[350363,785459],[-896,2801]],[[349467,788260],[-1030,-2871]],[[348437,785389],[-817,58]],[[347620,785447],[-1275,-2839]],[[346345,782608],[-1470,-189],[18,1172],[964,527]],[[345857,784118],[1727,2431],[-1380,533],[-190,-946],[-1187,171]],[[344827,786307],[12,1712]],[[344839,788019],[-1010,-875]],[[343829,787144],[-2031,-574]],[[341798,786570],[-3835,606]],[[337963,787176],[-2177,-629]],[[335786,786547],[-431,2517]],[[335355,789064],[2616,3120]],[[337971,792184],[-1073,450],[869,2880]],[[337767,795514],[1177,861]],[[338944,796375],[-99,1854],[1994,6850],[1521,3414]],[[342360,808493],[2013,1738],[1575,-189]],[[341569,796584],[-2717,-3564],[704,54],[2013,3510]],[[896558,826971],[596,-1498],[-161,-2055],[849,-2951],[278,-4044],[-467,-3138],[834,-3629],[1001,-7042],[1267,-5754],[969,-2942],[-1376,2332],[-1092,614],[-1743,-671],[-1474,-6675],[-49,-1980],[1246,-3053],[590,-2534],[744,-254],[264,-2318],[-414,-1968],[-414,3143],[-1957,840],[-1391,-4644],[-686,3163],[579,4083],[-207,2651],[603,2523],[-875,4365],[766,4852],[-197,5604],[377,4192],[-1346,3044],[-171,3179],[396,1674],[56,4643],[1952,641],[500,2656],[-1032,2280],[1185,671]],[[980032,818789],[1734,-952],[-1392,-593],[-1224,1101],[882,444]],[[487744,825735],[-1037,-665],[769,1798],[268,-1133]],[[275745,817216],[-3632,1793]],[[272113,819009],[533,807]],[[272646,819816],[1977,116]],[[274623,819932],[1122,-2716]],[[488342,820617],[-491,-1109],[-540,1495],[1031,-386]],[[538081,826905],[-958,-811],[-522,1768],[684,919],[796,-1876]],[[482727,825162],[530,-6881],[-827,-4031],[-3340,-876],[-381,-705],[-3192,-2340],[-2838,-601],[710,1220],[-1503,-526],[1450,1622],[-1348,-612],[-819,579],[1685,2259],[-401,1894],[1116,1253],[599,1874],[-2271,2671],[724,3240],[-556,963],[4197,-98],[1145,2367],[-1752,239],[1359,2756],[2065,281],[868,-603]],[[479947,831107],[3027,743],[1519,-3282],[-68,-2316],[-1698,-1090]],[[491362,851389],[-286,-1151],[-2160,-2146],[-401,-2258],[2032,772],[3691,-35],[823,-1236],[-2263,-5523],[-1728,-1051],[1561,-389],[-1972,-1722],[2120,-2],[1256,-736],[1366,-1971],[1010,-4719],[3354,-3886],[-337,-570],[1560,-5105],[-861,-1507],[2805,316],[1670,-1216],[249,-1687],[-1311,-3695],[-1451,-685],[-183,-2033],[2024,-139],[-48,-1073],[-1215,-1517],[-2098,-966],[-2751,15],[-1754,779],[-1720,-1740],[-2676,672],[-1126,-500],[-1080,-2388],[-1053,958],[-1543,-594],[-1381,-1595],[-325,1332],[2109,3140],[1097,2442],[2921,99],[1953,3174],[-2388,-2076],[-3632,2057],[-838,-660],[-1000,1505],[2442,1879],[1119,2040],[-336,2214],[-1616,-648],[1589,2446],[2625,1041],[669,2003],[160,2634],[-829,-293],[-1120,2013],[375,2939],[-1455,-1083],[-3271,454],[1275,3814],[-598,1172],[132,2086],[-1505,-1666],[-1061,-2414],[440,4103],[1170,4164],[-1289,-1339],[-1334,1102],[1585,3049],[-128,3843],[1667,2259],[-162,1526],[5593,679],[-157,-707]],[[589039,490923],[-572,-747],[-84,1557],[656,-810]],[[592152,491925],[-899,584],[683,564],[216,-1148]],[[258356,772744],[-801,-2405]],[[257555,770339],[-323,707]],[[257232,771046],[1124,1698]],[[268828,776662],[1113,441]],[[269941,777103],[234,-736],[2217,752]],[[272392,777119],[160,-2629]],[[272552,774490],[-3724,2172]],[[256275,785735],[-1336,-1321]],[[254939,784414],[-604,-1184]],[[254335,783230],[-490,967]],[[253845,784197],[615,1271]],[[254460,785468],[1815,267]],[[516113,815548],[-838,-971],[-918,455],[1358,1238],[398,-722]],[[189596,872516],[-2362,-2950],[-1044,1470],[3406,1480]],[[581880,871836],[-1354,-975],[-795,1658],[1719,282],[430,-965]],[[309615,809192],[-402,-1402],[-1162,1505],[715,1124],[849,-1227]],[[708031,725294],[-1442,-438],[470,-803]],[[707059,724053],[-1499,-1179],[-646,387],[-3185,-349],[-2784,-2329],[-1209,-2336],[673,-1235],[536,-3855],[-1819,-3866],[239,-2848],[-1766,-588],[-1170,600],[-352,-913],[1156,-3132],[-1011,-1519],[-1163,-548],[-722,-3475],[105,-2943],[-1140,-1792],[-754,999],[-1212,0],[-1619,-1756],[443,-963],[-1252,-747],[-1008,520],[-1464,-2331],[-612,-6378],[-3004,-1636],[-1595,30],[-1174,-1023],[-1475,629],[-3031,-532],[-4536,2668]],[[669009,681613],[724,1598]],[[669733,683211],[1889,4168],[-344,3262],[-2332,668],[24,4468],[-747,5264],[990,2176],[-1128,792],[-70,2701],[1122,1331],[-454,1178],[625,803],[864,5722]],[[670172,715744],[779,-959],[1226,-83],[900,-1617],[2080,1629],[144,2209],[2094,1148],[1802,1945],[848,4688],[2051,706],[584,1884],[2103,-1308]],[[684783,725986],[1519,-81],[1917,-963]],[[688219,724942],[857,-1318],[2480,2224],[846,-1284],[631,2634],[2109,659],[-102,1541],[1845,3152],[1047,-885],[63,-2302],[760,87],[-331,-4773],[457,-2338],[568,-228],[3915,4231],[1415,61],[80,-1108],[1417,1088],[1110,-124],[645,-965]],[[566573,440308],[223,-3162],[-210,-1365],[56,-4659],[-303,-2233],[224,-1122],[-5511,-74],[2,-17504],[475,-3801],[429,-547],[2988,-5635]],[[564946,400206],[-5455,-2133],[-1865,-113],[-979,784],[-3657,413],[-996,678],[-893,1800],[-7308,58],[-5077,5],[-1484,2257],[-840,238],[-1537,-1453],[-1483,262],[-753,-478]],[[536300,469971],[3696,-165],[5324,160],[1118,-2226],[-24,-1364],[765,-4655],[1532,-4849],[3103,828],[1910,-181],[519,4871],[369,636],[2606,604],[25,-2030],[3176,-164],[252,-684],[-171,-2633],[321,-2818],[-184,-4902],[75,-2523],[948,-2644],[303,-3855],[-358,-1191],[280,-1789],[784,819],[1655,-111],[676,583],[1205,-221],[368,841]],[[533384,475069],[1017,2282],[1379,1031],[533,-1124]],[[536313,477258],[-1726,-2587],[145,-3699],[-806,-372]],[[555733,756786],[1170,-1918],[225,-2072]],[[557128,752796],[-215,-3561],[700,-2177],[620,-328]],[[558233,746730],[186,-1133],[-1038,-3206],[-962,-818],[-289,-1931],[-571,332]],[[553728,752769],[-3,1422]],[[553725,754191],[148,-125]],[[553787,755260],[-14,-11]],[[553773,755249],[822,2019],[1138,-482]],[[656633,652705],[-901,-1424],[-745,766],[-96,-3705],[623,-1063],[-1215,-426],[-109,-1581],[-858,-4087],[-39,-1959]],[[653293,639226],[-226,-489],[-7081,1844],[-2674,6790],[-67,1228]],[[655778,659124],[179,-2205],[425,-236]],[[309296,179739],[65,13040]],[[325969,372995],[1214,-2244],[794,-2648],[3023,-4732],[2632,-1395],[1443,-2135],[2799,-2994],[1510,-1049],[718,-1999],[-1777,-5378],[32,-1472],[-1251,-3354],[102,-701],[1213,243],[4809,-1661],[758,1376],[1249,-553],[416,1569],[2054,2949],[410,2035],[172,4341]],[[348289,353193],[1281,314],[732,-864],[611,-3295],[-464,-5309],[-1358,-1791],[-1524,-1041],[-627,-1585],[-1733,-1999],[-1389,-3158],[-1981,-5081],[-1862,-3513]],[[339975,325871],[-732,-2389],[172,-1585],[-992,-6008],[-93,-3549]],[[309879,194532],[-49,393],[-4164,1672],[-5440,110],[-1359,2659],[188,5089],[-2258,-334],[-967,3631],[-209,3213],[319,1594],[906,79],[427,1919],[1020,1089],[17,1621],[876,1719],[-625,2090],[478,2273],[1225,1724],[-98,2195],[680,1497],[-501,2476],[678,1225],[-318,2221],[1090,2064],[-1676,2601],[1933,168],[135,1907],[-1687,344],[388,2687],[-624,2900],[343,1619],[-1014,1048],[61,4098],[1010,1166],[-418,2671],[-58,5681],[658,2112],[-342,939],[775,3402],[316,3654],[1317,1465],[-213,4131],[-387,1652],[137,3839],[-205,1604],[379,1895],[1808,2737],[-182,4358],[501,3515],[661,2560],[554,453],[-116,2920],[207,2652],[-556,73],[-416,4738],[-1154,5345],[182,2495],[995,4195],[570,486],[79,3490],[-275,2637],[552,1308],[475,4086],[1341,2896],[911,4568],[1390,745],[-654,3019],[463,2161],[-516,3958],[600,2332],[-493,1506],[866,2641],[2483,2122],[965,6117],[-517,1064]],[[313347,369511],[1342,3587],[963,607],[403,1844],[1247,-1760],[1982,-19],[1256,-746],[778,-3548],[970,4473],[438,398],[2709,48],[534,-1400]],[[629140,735218],[-1045,-171]],[[628095,735047],[-1011,4059],[-1605,45],[-392,1153],[-731,-365]],[[624356,739939],[-1331,1995],[-1609,748],[-391,1871],[426,1405],[-786,2296]],[[620665,748254],[4338,1089]],[[625003,749343],[1628,-2630],[-587,-1238],[1635,-2395],[-1069,-1518],[1728,-2269],[490,-1257],[312,-2818]],[[547091,792639],[-243,-1257],[783,-2256]],[[547631,789126],[-224,-1768],[-1433,236],[-271,-4387],[-1001,-852]],[[544702,782355],[-376,-1098],[-2658,-307],[-1381,-1238],[-2232,611]],[[538055,780323],[-3644,1082],[-608,2248],[-2569,-631],[-609,-1058],[-1590,402]],[[529035,782366],[-2424,1140]],[[526611,783506],[-146,1264]],[[526465,784770],[74,1425]],[[527029,786288],[-98,96]],[[526931,786384],[1715,-1361],[327,1349],[1529,-847],[3412,1897],[1324,-290],[912,-1134],[-555,4045],[2391,2146],[388,1445]],[[538374,793634],[651,-975],[1784,-19],[780,2279],[3014,-1357],[1168,269],[1320,-1192]],[[628095,735047],[-1763,761],[-1840,3816]],[[624492,739624],[-136,315]],[[635746,732426],[-767,-144],[-1582,2417],[608,947],[-294,1975],[517,514],[-907,1688],[-619,-210],[-3562,-4395]],[[625003,749343],[777,940],[1422,-1334],[1847,-913],[596,1283],[-1362,2193],[688,1386]],[[628971,752898],[888,-464],[1421,-2948],[1667,-606],[1977,3743]],[[584871,490497],[-360,-1430],[252,-1635],[737,-400],[28,-1715],[-1015,-1862],[-771,-2941],[-1390,-2187]],[[582352,478327],[16,203]],[[581384,484839],[-244,85]],[[581140,484924],[38,1702],[-583,1975]],[[580595,488601],[135,697],[909,-1220],[1328,546],[172,2233],[1732,-360]],[[515815,805530],[552,-132]],[[516367,805398],[282,-12]],[[516649,805386],[1030,-2573],[-689,-1157]],[[516990,801656],[-1035,-1192],[126,-2260]],[[516081,798204],[-784,-162],[-1776,1643],[-21,2060],[-1901,-1041],[-3,1696],[-1410,464],[-1556,2693],[-742,-400],[-875,2283]],[[509305,809102],[1534,-1008],[900,1060]],[[511739,809154],[770,523],[2704,-1124],[973,-945],[-371,-2078]],[[509987,574011],[-300,-1782],[636,-1871],[328,-2798],[-718,-2009],[-52,-2138],[-645,-764],[-778,-4115],[-751,-209],[-246,-6960],[246,-6885],[-191,-2029]],[[504506,541548],[432,461],[-556,2327],[131,1836],[-69,12162],[-488,1392],[-262,4218],[-1528,2148],[335,3754]],[[502501,569846],[1462,2689],[1538,-170],[1135,2836]],[[506636,575201],[-65,1924],[1423,864],[1993,-3978]],[[500603,593059],[-148,-2454],[1262,-4703],[1619,-2049],[-591,43],[-3,-1913],[1605,-2408],[1413,465],[423,-1468],[-374,-1115],[827,-2256]],[[502501,569846],[-1157,-7],[-1535,732]],[[499809,570571],[-641,304],[-1117,-1054],[-5912,56],[-236,-2406],[356,-1128],[57,-4407],[195,-1047]],[[492511,560889],[-336,-329],[-1131,2782],[-1816,-3],[-1262,-1476],[-1772,1684],[-361,1846],[-1177,1093]],[[484656,566486],[92,3651],[530,969],[32,3685],[1362,1210],[1026,1810],[-145,1982],[705,720],[-284,1927],[772,1561],[1320,-1116],[762,513],[287,2323],[781,40],[120,1607],[1158,1915],[955,-626],[389,1707],[571,175],[1995,1976],[803,1352],[1457,69],[1259,-877]],[[757152,634925],[157,-3980],[-836,791],[-419,-869],[401,-2970]],[[747364,635607],[-862,7959],[-482,1409],[461,3297],[-1633,1510],[-339,842],[351,1699],[454,-195],[397,1817],[1205,35],[-336,1754],[-880,497],[-1021,1860],[1204,3729],[457,-1339],[2409,-1697],[192,1247],[566,-1625],[-24,-3768],[1737,-875],[4473,69],[1163,-1335],[-603,-290],[-521,-3085],[-519,-1061],[-1416,-603],[-574,-2565],[430,-3295],[845,-739],[884,3110],[-23,1075],[879,-15],[321,-4470],[361,-1443],[232,-4191]],[[577817,753361],[-1332,-286],[-666,940],[-1888,-679],[-818,-1471]],[[573113,751865],[-708,-257],[248,-1412],[-2511,-1133],[-2036,1830],[-2453,-982],[-1998,-299]],[[563655,749612],[249,2255],[-469,1639],[-1369,1898]],[[562066,755404],[499,753],[-158,2377],[1417,2048],[-1173,1579],[-372,3276],[790,1365]],[[563069,766802],[899,-947],[-305,-1443],[849,234],[6313,-1203],[1996,1993],[2420,949],[2215,-1068],[460,-976],[1487,-475]],[[552797,770541],[949,71],[-547,-3427],[1200,-1535],[-941,-464],[675,-1549],[-816,-1009]],[[553317,762628],[-466,-1427],[-979,-366],[-640,-1554],[-21,-2421]],[[551211,756860],[-2135,1999]],[[548847,759103],[-865,3006],[-1556,1974],[-1387,2584],[-233,1533],[-1094,1730],[143,2448],[1404,-1008],[659,1230],[3561,-820],[2361,-4],[957,-1235]],[[578188,837332],[1797,-1187],[1612,-22],[297,-1505],[2088,951],[1870,-1630],[197,-3078],[-497,-1583],[895,-799],[785,-2681],[1079,-829],[-105,-1454],[1933,-697],[706,-2112],[-1562,-1453],[-2012,622],[-442,-1063],[768,-1294],[117,-2880],[517,-1252]],[[588231,813386],[-2174,-324],[-1244,-2665],[32,-1963],[-1066,1260],[-2262,-563],[-585,1389],[-951,-633],[-1693,578],[-2538,33],[-356,822],[-3380,955],[-4343,-272],[-2101,-2070]],[[565570,809933],[131,3095],[-1266,1283],[1800,2413],[118,2152],[-1118,5405]],[[565235,824281],[3565,206],[2164,2116],[867,3481],[2545,2096],[-883,411],[377,1926]],[[573870,834517],[1275,965],[1457,-188],[1586,2038]],[[253072,598860],[-954,23],[211,11377]],[[252329,610260],[78,924],[908,-31],[788,2846],[631,157]],[[338445,385253],[-57,2053],[-2529,3151],[-2546,-67],[-4860,-2061],[-445,-2429],[-998,-3004],[-1,-2984],[-1040,-6917]],[[313347,369511],[-1901,-7],[-303,4537],[-550,2598],[-29,1886],[-936,2231],[94,1845],[-681,910],[130,4369],[654,1708],[-1404,2753],[-349,5437],[-609,636],[-549,2589]],[[306914,401003],[-317,1812],[518,663],[1114,3294]],[[308229,406772],[86,-108]],[[307332,412821],[-12,12]],[[307320,412833],[534,1615],[-562,1622],[388,2167],[985,2360],[-538,3056],[252,1105],[13,3652],[815,2240],[-2481,9184]],[[306726,439834],[2028,-352],[336,-660],[915,614],[907,1871],[972,119],[387,1049],[1308,1404],[1060,1739],[1295,885],[2410,673],[230,-3202],[-352,-1975],[323,-2598],[5,-2456],[915,-3174],[1331,-1634],[258,-1119],[2319,-469],[664,-955],[775,65],[839,-1944],[1637,-809],[1073,-2321],[1980,213],[1585,-1778],[89,-2340],[488,-2570],[71,-2786],[-861,-56],[947,-2259],[185,-4679],[4549,-350],[535,261],[-348,-2168],[208,-3460],[1565,-1647],[718,-4544],[-629,-4749],[-920,-3931],[752,-1393],[-830,-1096]],[[343103,516223],[1286,-592],[290,1169],[-594,1540],[537,1287],[571,-655],[2088,1135],[1007,-1605]],[[348288,518502],[1350,-1219],[1007,1385],[2230,-1015],[734,1068],[1972,7928],[939,2129]],[[351748,304813],[-452,1152]],[[351296,305965],[18,-30]],[[352392,311289],[-83,-134]],[[352309,311155],[-1203,1592],[-444,2051],[-1275,1195],[-1020,2192],[-1852,1538],[-841,2071],[-1243,-1204],[-476,2670],[-1824,3088],[-1060,-1043],[-1096,566]],[[348289,353193],[15,849]],[[348304,354042],[381,1259],[573,6839]],[[349258,362140],[-996,1501],[-992,-960],[-1066,-98],[-477,2430],[-221,5388],[-643,2156],[-946,156],[-570,1117],[-1506,-1058],[-2830,960],[349,6583],[-915,4938]],[[306726,439834],[-1061,129],[-1199,-762],[-695,286],[15,9077],[-1669,-2890],[-2622,-223],[-548,2924],[-2307,585],[654,2478],[-1597,3834],[-629,2426],[153,912],[-783,1342],[783,1462],[-105,2390],[1438,2025],[292,1301],[-278,1457],[710,2747],[258,3034],[523,329],[2372,3334],[2420,912],[483,1049],[1097,138],[460,-895],[759,385]],[[305650,479620],[1571,18018],[-742,4221],[-1120,2035],[47,4251],[1616,897],[827,-561],[31,1355],[-551,1185],[-1363,-27],[10,3846],[4644,65],[-48,1584],[567,-1389],[1362,2105],[410,-131],[727,-2787],[-10,-2401],[605,77]],[[314233,511963],[1595,-2791],[1723,1371],[578,-1731],[1027,2469],[1034,861],[1713,2168],[220,1690],[1782,1884],[13,1122],[-1832,671],[31,1638],[-503,2388],[-6,2267],[-1658,3821],[1562,-545],[650,-1251],[2019,-41],[906,-1945],[567,468],[145,2044],[838,822],[715,-345],[1664,1122],[761,1357],[770,109],[1107,2721],[-382,1229]],[[331272,535536],[1666,218],[421,-924],[-439,-3256],[1237,-901],[423,-2652],[-843,-2050],[65,-1412],[-453,-3906],[664,-2463],[-3,-2213],[1459,-3108],[1024,-1021],[974,479],[475,1795],[2073,691],[1321,1836],[784,-787],[983,361]],[[819833,533745],[518,-3074],[-610,57],[-223,3017]],[[819518,533745],[-778,-1076],[260,-1925],[-644,-2187],[-1513,3369]],[[816843,531926],[317,-10]],[[754532,669180],[-103,-1199],[1100,-637],[230,-3171],[-1116,-669],[-2589,-179],[-1094,703],[-1617,-1119],[-2517,1540],[94,2101]],[[746920,666550],[1793,4688],[1234,1207],[1020,-398],[12,-970],[2014,-627],[411,574],[1055,-708],[73,-1136]],[[570163,399300],[-97,-721],[1492,-4348],[1131,-5268],[1417,-2100],[1509,-1499],[164,-1972],[1164,-308],[-84,-3161],[1045,-3014],[2755,-1412],[193,-1507],[716,-760]],[[581568,373230],[-652,-114],[-806,-1586],[-1749,-1260],[-888,-2253],[-2510,-3737],[-422,-3177],[-1064,-2025],[-1499,-976],[-912,-5088],[-390,-641],[-1932,-610],[-2373,1283],[-1744,1980],[-1075,-1133],[-663,-3633],[-1526,-3016],[-1235,-1623],[-2518,31],[-314,2400],[523,1652],[-61,1477],[-1244,5248],[-1013,1499]],[[555501,357928],[-9,16450],[2760,0],[9,21810],[2881,712],[3024,1120],[552,-106],[783,-2521],[2162,2813],[477,-441],[1051,1370],[972,165]],[[563500,569410],[1256,-3150],[928,-3348],[-66,-2857],[-429,-1338],[192,-1771],[1694,-890]],[[567075,556056],[401,-2217],[1560,-911],[1095,-2447],[-159,-1216],[1941,-2692],[1314,-2545],[-148,-1067],[571,-2287],[1581,-1732],[889,-3956]],[[576120,534986],[-801,526],[-814,-803],[-3603,1479],[-766,-1703],[-1343,-560],[-1239,380],[-2507,-1961],[-837,437],[-1000,-535],[-927,-3032],[-2042,868],[-415,-217],[-2721,1291],[-921,2174],[-1166,1538],[-849,227],[-1201,-1399],[-1392,-3755],[119,-4616]],[[551695,525325],[-378,856],[-871,-729],[-2008,1094],[-2124,-885],[-492,-1933],[-77,-2234],[-792,-3328]],[[544953,518166],[-333,3783],[-801,1295],[-1795,4145],[-295,3150],[-871,1819],[-406,3640],[150,3467],[-516,1028],[856,1428],[1407,5829],[651,1541]],[[543000,549291],[1013,-287],[1483,1234],[463,1078],[665,-1864],[2402,2563],[2617,458],[1436,3527],[-612,1384],[714,748],[1453,29],[1871,629],[1198,1650],[1363,3371],[1283,2322],[-54,1234],[935,1469],[1252,1028],[1018,-454]],[[313542,772321],[-966,631]],[[312576,772952],[63,1967]],[[312639,774919],[-31,200]],[[311702,775814],[-38,-22]],[[311664,775792],[-16,7865],[-1191,1559],[-1648,-845]],[[308809,784371],[-1151,1538]],[[307658,785909],[-2124,-4467]],[[305534,781442],[-802,-4756],[-1671,-3814]],[[303061,772872],[-1193,164]],[[301868,773036],[-528,-1674]],[[301340,771362],[-8865,-22]],[[267330,873831],[-420,723]],[[292475,771340],[-1307,-619]],[[291168,770721],[-1718,-2421]],[[289450,768300],[-20,24]],[[279963,760904],[422,241]],[[280385,761145],[-13,-1049]],[[270430,756850],[633,2722]],[[251257,789167],[-84,-67]],[[251173,789100],[-3508,1179]],[[247665,790279],[-1884,-843]],[[245781,789436],[-4105,3279]],[[241676,792715],[-1975,-511]],[[239701,792204],[-2537,1286]],[[237164,793490],[-255,716]],[[236909,794206],[-395,2614],[-834,385],[-19,-2240],[-6577,10],[-10660,-1]],[[218424,794974],[-4738,0],[-7106,0],[-10660,0],[-8290,0],[-5922,0],[-5922,0],[-8292,0]],[[167494,794974],[-8574,0]],[[138819,835824],[-202,1310]],[[138617,837134],[-4105,2900]],[[134512,840034],[-691,-52]],[[133821,839982],[-576,2586],[-4969,9944],[-3121,3456]],[[125155,855968],[-298,1719]],[[124857,857687],[-1180,1271],[-2349,-1115]],[[121328,857843],[-714,-2681],[-2388,-1476]],[[118226,853686],[-430,1914]],[[117796,855600],[-4423,5079],[295,1541],[-2484,-951]],[[111184,861269],[-2857,694]],[[108327,861963],[0,55397]],[[526465,784770],[146,-1264]],[[529035,782366],[-61,-1865],[-955,295],[-410,-1411],[-1912,-444],[-826,-2706],[-1620,3644],[-1618,-3101],[-2130,24]],[[519503,776802],[-732,2903],[-913,87],[-951,-1680],[-73,1667],[2612,5298],[146,989],[1562,611]],[[521154,786677],[3515,378]],[[524669,787055],[685,84]],[[525354,787139],[153,0]],[[304393,396029],[1367,827],[206,2976],[948,1171]],[[868915,771709],[-4,489]],[[866863,773017],[-131,-309]],[[866732,772708],[-479,546],[-1125,-2031],[-1011,-439],[480,-4967],[17,-3784],[-536,-3144],[-1788,-1038],[284,-1135]],[[862574,756716],[-796,2111],[-950,631],[-496,-3100],[-1128,-364],[-1084,-2223],[-2440,-301],[683,-2516],[-499,-1028],[-2588,842],[-767,1479],[-841,-830],[-307,-1676],[-1392,-2686],[-3055,-2636],[-1465,-2700]],[[817405,638260],[-696,-172]],[[815489,636816],[-446,-704]],[[799923,632140],[-474,813],[-1252,-215],[-958,1686],[-952,506],[-354,2468],[678,2272],[-662,767],[-1942,85],[-1576,2503],[-1141,-1238],[-192,-1334],[-1177,-1227],[-883,286],[-386,-1268],[-819,1444],[-414,-1094],[-475,990],[-819,-1845],[-1356,1706],[-1082,-2143]],[[783687,637302],[-1267,492],[-408,-1236],[589,-2531],[-88,-4007],[-1335,436],[-237,2037]],[[780941,632493],[-51,1058],[-1637,-1706],[-879,29],[-657,1413],[-169,1934],[-2013,580],[534,4142],[-123,1605],[-1325,565],[-88,2566],[-420,1288],[425,1474],[-2270,-149],[-1256,-915],[350,1302],[-442,2138],[800,4503],[981,2031],[1258,1375],[295,4483],[-224,5860],[-1139,537],[-395,2839],[-1558,2179],[-599,-1731]],[[770339,671893],[-2000,1433],[-891,-283],[831,2083],[-404,1700],[-759,-835],[494,1778],[-846,1406],[-1443,-1426],[-266,-901],[-1807,720],[-407,809],[-2002,-3017],[-1933,-1258],[-242,-1117],[-1160,-1512],[-104,-1174],[-1907,-1295],[-961,176]],[[746920,666550],[-396,1219],[277,2055],[-632,1322],[-1420,-1311]],[[744749,669835],[-2690,-191],[-1631,1463],[-406,-928],[-915,918],[-347,-920],[-765,2068],[-1544,229],[101,1636],[-1235,20],[-1349,1873],[-354,1826],[-1438,-215],[-1189,2542],[-837,419],[-1932,2558],[-321,1254],[-1739,64],[-450,-1448],[-680,422]],[[725028,683425],[-912,1483],[-1363,910],[-741,1898]],[[722012,687716],[-22,32]],[[721990,687748],[-1520,1101]],[[720470,688849],[-85,152]],[[720385,689001],[-645,1760],[-875,-646],[-201,3519]],[[718664,693634],[-916,3746],[865,457],[606,-1415],[834,846]],[[720053,697268],[-8,373]],[[720045,697641],[-226,3602]],[[719819,701243],[-63,322]],[[719756,701565],[-863,1620],[-136,3483],[605,833],[-833,1717],[-1080,805],[-749,3537],[-560,1383]],[[716140,714943],[-31,68]],[[716109,715011],[-981,-120],[-1888,1102]],[[713240,715993],[-598,1335],[-1121,-344],[-675,1538],[193,1741],[-372,1584],[-1156,524],[-215,1038],[-2237,644]],[[708031,725294],[631,913],[-623,1278],[-415,5383],[-1298,887],[-1322,-313],[-17,2341],[-455,2647]],[[704532,738430],[786,934],[214,2587],[2361,1788],[66,880],[1994,662],[261,-1774],[2230,851],[954,3157],[3611,553],[664,1753],[2586,2436],[2562,1479],[-18,934]],[[722803,754670],[-124,2817],[1040,1232],[-414,1005],[1099,702],[-1196,5543],[279,3844],[-1273,303],[172,1240],[2205,727],[2330,1304],[826,-1111],[1360,-226],[288,1889],[-711,459],[1953,9870],[2740,-1276],[1807,11],[332,-841],[1941,1380],[477,1133],[-363,3916],[621,2780],[2222,852],[566,2845],[1582,456]],[[742562,795524],[1366,453]],[[743928,795977],[-198,-1664],[657,-1934],[1493,-1010],[1474,-2263],[1426,8],[2089,-1942],[509,-2316],[1038,-1959],[455,-2521],[-89,-2922],[-945,-3025],[599,-1951],[1963,-707],[3343,-242],[2414,-798],[2932,-3260],[1773,-431],[1561,-6349],[1315,-2879],[2278,411],[6283,-1313],[1434,647],[4806,-1253],[719,-1481],[3056,-1244],[1773,-1508],[2185,744],[0,-1293],[1345,-374],[597,844],[4370,3263],[3892,939],[3533,51],[2659,1883],[1686,3363],[2571,2192],[-1475,3886],[609,2724],[768,1404],[1427,-35],[515,-833],[2750,-1019],[1232,1167],[1352,2500],[3233,555],[1555,2001],[894,2926],[2140,427],[2709,2104],[1488,256],[2396,-915],[532,1493],[-519,1731],[-1748,2986],[-1621,1955],[-2027,23],[-1161,-1989],[-1639,1288],[-1471,-68],[-924,-1014],[-946,1529],[1100,4410],[2026,6721]],[[824119,799896],[3306,-1839],[1606,1961],[2246,1315],[-268,2012],[2508,7077],[1708,2206],[-70,3518],[-1635,391],[75,915],[1693,2279],[4538,1855],[3898,153],[2976,-2233],[730,413],[1594,-956],[1844,-3806],[1368,-5297],[332,-2403],[1061,-2324],[-2,-1506],[789,-1449],[-243,-1989],[1381,-1805],[1956,186],[1156,-1410],[1050,159],[1939,-2946],[992,-180],[697,-3080],[-256,-1266],[808,-2584],[2173,-65],[2158,521],[402,1058],[2116,889],[2291,1637],[751,-306],[523,-3592],[-1623,-2448],[96,-1032],[-932,-3727],[-15,-1488],[-1876,-4461],[-201,-2157],[-844,-383]],[[492511,560889],[-141,-2202],[406,-1832],[263,-3506],[-789,-1640],[-545,-4307],[-694,-2356],[98,-2719],[662,-4178],[468,-254],[-61,-2649],[-566,-132]],[[479041,530496],[-66,4321],[385,1445],[-67,3062],[-952,792],[-254,1539],[-1986,1617],[752,1741],[100,1614],[-527,2870]],[[476426,549497],[707,-10],[598,3484],[-665,645],[53,1196],[1544,-268],[-750,2230],[480,1742],[-327,1985],[-670,473],[2,3118],[405,832]],[[477803,564924],[915,1570],[1926,-1488],[763,1026],[109,1819],[685,-498],[406,898],[55,-2635],[575,-500],[530,1153],[889,217]],[[544953,518166],[-344,-3518],[-883,1414],[-2331,576],[-1162,845],[-3307,40]],[[536926,517523],[-203,562],[-5200,257],[-55,-784]],[[531468,517558],[-3747,1],[-497,811]],[[523766,532889],[681,2620],[720,4809],[1666,3097],[333,1352],[1010,1400],[941,-623],[344,1018],[1184,-2164],[336,-1540],[1106,1537],[79,1135],[782,1348],[-261,923],[690,1881],[604,4103],[473,1856],[1119,1724],[342,3198],[683,671],[262,2942],[738,3370],[991,3170],[1854,2087],[187,3651],[-300,1123],[-893,507],[-371,4116]],[[539066,582200],[1256,-585]],[[540322,581615],[681,-1920],[889,-4800],[-143,-4336],[684,-4480],[1052,-2071],[-2275,-392],[-1646,226],[-739,-1708],[986,-2891],[2178,-3828],[908,-4180],[103,-1944]],[[576120,534986],[1069,-2752],[1122,-1744],[654,-155],[832,1072],[1179,-692],[883,1325],[576,-148],[1439,-3584],[871,-867],[917,-2043]],[[585662,525398],[-235,-2660],[258,-1154],[-328,-2320],[1484,-1752]],[[586841,517512],[-11,-38]],[[584660,512056],[-1486,-2485],[-23,-1897],[-698,-3669]],[[582453,504005],[-110,3]],[[582340,501712],[2,5]],[[582342,501717],[-184,-5222]],[[582158,496495],[-988,-1767]],[[581170,494728],[-66,250]],[[580139,490215],[21,11]],[[580160,490226],[435,-1625]],[[581140,484924],[-41,14]],[[584945,456249],[-9,-232]],[[584936,456017],[-4664,-1572],[55,-1274],[-1437,-3106],[637,-3593],[25,-4964],[-783,-4821],[349,-1950],[1616,-3180],[1009,-488],[367,1355],[654,279],[0,-7331],[-670,852],[-1499,-710],[-1824,5254],[-2290,1699],[-936,3496],[-686,-1740],[-981,-434],[-1584,486],[-1880,1582],[-83,2288],[-2734,-798],[-42,1776],[-982,1185]],[[536313,477258],[950,-1200],[751,881],[88,1388],[622,-179],[1160,1097],[145,-3151],[826,-299],[2478,5041],[757,573],[762,2785],[196,2570],[-6,5051],[904,2000],[1205,4149],[845,831],[1317,2669],[-80,1609],[454,3031],[41,5237],[432,2469],[40,2835],[1163,5398],[332,3282]],[[530917,481515],[1039,2346],[958,-1045],[236,2240],[-1101,2855],[188,2927],[1275,-414],[1061,489],[-40,2376],[1004,-17],[551,-2260],[1314,-486],[747,1522],[425,-1938],[557,-8],[824,3418],[199,2825],[-125,2613],[194,2096],[-1723,2459],[68,2335],[563,2047],[964,1630],[-704,3310],[-916,287],[-1603,-1053],[-309,2412],[363,3042]],[[301889,574992],[-1773,-1158],[-807,-2784],[-548,-487],[-1176,-3691],[-381,-4160],[-972,-3331],[828,194],[728,-892],[363,-2852],[692,-1455],[-74,-5493],[654,-501],[875,-2251],[2443,24],[995,524],[1555,-858],[1822,-4758],[2687,128],[2511,505],[357,-1281],[-1071,-4473],[-84,-4524],[538,-3807],[973,-2657],[-1454,-3099],[600,-588],[1133,-2390],[930,-6914]],[[305650,479620],[-1038,2498],[-1099,196],[1837,6109],[-61,546],[-2274,2604],[-1340,-684],[-988,1074],[-644,-1030],[-1142,-606],[-1366,121],[-742,772],[-118,2654],[-832,813],[-466,2631],[-1617,1649],[-477,2310],[-1066,2255],[-1341,553]],[[290876,504085],[-1653,1527],[-1198,1762],[-510,-1262],[-1182,196],[-1396,926],[-125,1254],[-2346,2427],[-1521,2424]],[[283608,547547],[469,2853],[404,-994],[1085,2544],[-784,3116],[289,947]],[[270656,561454],[-1045,-756],[-1,-2305],[553,-642],[-488,-1252],[154,-1699],[-450,-815],[400,-1454]],[[261820,570254],[343,725],[1978,-1417],[578,633],[980,-428],[500,-1182],[992,-220],[470,1031]],[[594456,712459],[-1330,-157],[-394,735],[-1864,49]],[[541137,806029],[512,920],[1002,-1200],[2959,-1412],[-582,-888],[1302,-1932],[863,826],[-304,1127],[2763,-2695],[1910,-550],[749,-2184]],[[552311,798041],[-1865,-1501],[-1117,-2187],[-1584,-162],[-654,-1552]],[[538374,793634],[-3286,4113],[-987,3444],[489,1821],[5323,3251],[1224,-234]],[[527054,829528],[17,-108]],[[539583,823049],[24,-14]],[[539607,823035],[433,-2642],[-766,-2078],[1335,-2395],[370,-2647],[-419,-1477],[1152,-3435],[-575,-2332]],[[526931,786384],[-142,138]],[[521154,786677],[-87,2795],[705,3387],[823,2000],[-1899,1057],[-1987,51],[-1086,1730]],[[517623,797697],[397,2049],[-1030,1910]],[[516649,805386],[-276,1385],[830,2990],[-680,1620],[2204,880],[815,2780],[450,5344]],[[524116,829329],[-32,661]],[[524084,829990],[2970,-462]],[[620127,572847],[-898,-2965]],[[619229,569882],[-1014,483],[-2109,-595],[-89,3606],[1700,5198]],[[617717,578574],[810,-533],[1241,1968]],[[526959,830136],[95,-608]],[[524084,829990],[-25,488]],[[300643,611589],[18,1790],[-662,1520],[714,800],[239,2357],[-339,3480]],[[523823,723550],[-1021,-2619],[388,-754],[-286,-2947],[412,-3949],[-412,-2784],[-2033,-3872],[-38,-1469],[642,-3341],[1333,-2025],[340,-2270],[1974,-2792],[1318,-10918]],[[526440,683810],[-579,-677],[917,-2836],[562,-3966],[-75,-2410],[279,-4589],[-468,-2695],[408,-2861],[-97,-1753],[-1023,-1293],[-119,-1579],[1534,-4355],[76,-1665],[633,-2726],[1195,-235],[2363,-1543],[1198,-4579]],[[533244,644048],[-5754,-7235],[-6708,-8434],[-4570,-8259],[-4469,-1992]],[[511743,618128],[-2297,-915],[-819,958],[417,1545],[-146,2244],[-2215,1625],[-519,1089],[-1483,774],[-207,1050],[-1236,1551],[-57,1687],[-7683,10714],[-8895,12352]],[[486603,652802],[-6023,7672],[-4701,5897]],[[475879,666371],[0,2195]],[[475879,668566],[64,6293],[2709,3738],[1639,1633],[1277,-334],[374,1424],[2922,876],[1335,3012],[1793,1383],[1939,2174],[-580,782],[19,2750],[2248,1021],[240,1234],[1340,518],[3259,-243],[582,2247],[-1234,2425],[-470,2613],[-323,8491],[-1178,2087]],[[290876,504085],[-949,-96],[1008,-2562],[38,-2349],[-440,163],[-452,-3596],[-1442,-3565],[-1637,-2546],[-3282,-2482],[-1346,-2462],[-207,-2249],[-721,-3252],[-19,-1403],[-1084,-2536],[-707,372],[-854,2801],[-1392,942],[-678,-993],[-351,2335],[919,1136],[-404,2903]],[[594994,690286],[131,-677]],[[595125,689609],[1831,-10255]],[[602420,635036],[-6380,-3],[-8723,-3],[-5194,-4],[-6367,2],[-6367,2]],[[569389,635030],[0,42574],[-705,6331],[687,3116],[-336,3308],[827,1897]],[[617717,578574],[-1184,2464],[-520,1787],[-1117,1871],[-1648,3819],[-1522,1699],[-1916,625],[-927,-339],[-344,881],[-1583,-1207],[-1723,2535],[-869,-4166],[-872,1805],[-647,-1077],[-1389,-90]],[[601456,589181],[-271,5185],[264,700],[1089,6197],[-73,1946],[337,2573],[1117,16],[1032,2348],[1308,751],[989,2490]],[[495015,761882],[1066,-991],[-194,-1001],[3281,-1456],[717,-807],[1868,3],[182,921],[2032,-1477]],[[504739,756526],[-772,548]],[[504739,756526],[906,-888],[1720,-77],[1555,537]],[[479427,724985],[-272,2406],[1337,2720],[-890,2445],[959,3549],[-485,467],[-1009,3118],[1386,311],[629,3727],[-328,3946],[1989,3098],[-917,832],[-211,1599],[-1469,229],[-712,-873],[-2281,368],[32,1409],[-1567,-1141]],[[577812,857129],[-955,-2975]],[[576857,854154],[-403,147]],[[576732,848420],[54,9]],[[576786,848429],[-809,-2889]],[[575977,845540],[-2276,17],[-1504,1820],[-2445,1334],[-2190,-1143]],[[619229,569882],[-731,-2239],[506,-2478],[944,-1914],[836,-2966],[1501,-2331],[8209,-5859],[2778,0]],[[633272,552095],[-4320,-8885],[-4118,-9392],[-2643,228],[-2398,-1813],[-928,-2088],[-2132,-913],[-389,-949]],[[616344,528283],[-1842,-203],[-1266,1953],[-2564,-2498],[-966,-2342],[-3912,1141],[-3279,4519],[-2288,226],[-886,2123],[-50,3175],[-1324,879]],[[597967,537256],[-518,1071],[-1031,5849],[-1796,3350],[-1106,2638],[-1222,531],[-593,1130],[616,2636],[1997,279],[392,822],[-45,5209]],[[594661,560771],[593,3930],[-44,2389],[822,2086],[999,-91],[503,5639],[1343,4270],[1421,1120],[291,3227],[495,2103],[372,3737]],[[580460,913634],[-1375,-3161],[595,-1770],[1830,-758],[1765,-2211],[-2478,-4251],[2267,-5213],[534,-2425],[-767,-669],[-598,-3557],[1302,-1205],[98,-2364],[1099,-2046],[-1388,-1619],[3269,-3194],[981,-1912],[-690,-1883],[-4432,-6052],[-5257,-5983]],[[567098,894577],[-1122,2286],[658,3670],[-1445,3788],[474,2989],[-2379,2586],[-2181,768],[-3820,3059]],[[557283,913723],[2777,1385],[2192,-3263],[2536,-420],[1473,929],[3020,-1259],[2242,2351],[731,3925],[1427,1554],[3790,869],[3477,-2312],[533,-1175],[-1021,-2673]],[[348288,518502],[595,797],[574,2112],[-22,1898],[591,2674],[-1001,2752],[-274,2553],[-7,3131],[822,2047]],[[516081,798204],[1542,-507]],[[519503,776802],[-598,-1279],[964,-1831],[-1459,-1676],[1119,-2377],[-521,-1220],[345,-1367],[1860,-682],[-399,-2357]],[[520814,764013],[-644,-421]],[[503967,757074],[772,-548]],[[526641,510831],[4846,-191],[-19,6918]],[[482727,825162],[-1199,-177],[-1111,2071],[-849,-1701],[-2120,1737],[2499,4015]],[[620665,748254],[-1810,2705],[-893,-734],[-2657,460]],[[611050,761956],[478,888],[1383,-212],[2590,-1865],[2329,30],[3788,-2827],[485,-1069],[2538,1124],[2379,-1667],[-247,-1599],[2198,-1861]],[[499809,570571],[30,-2873],[1218,-2007],[-410,-4908],[822,-623],[-112,-3003],[-323,-546],[877,-2696],[-290,-939],[142,-4693],[-305,-2978],[588,-2360],[1250,-2152]],[[491349,534865],[76,235]],[[468362,578206],[-313,-1219],[547,-1085],[1034,1124],[710,-1811],[1118,1855],[1262,-1008],[1284,1262],[-104,1239],[980,-369],[624,-2843],[-10,-1476],[1151,-1700],[-713,-2077],[907,-267],[295,-3275],[669,-1632]],[[476426,549497],[-616,595],[-504,-2347],[-633,-278],[-962,1185],[263,1325],[-414,4186],[-695,1117],[-1431,-293]],[[471434,554987],[-1191,-888],[588,2087],[-528,3713],[-1431,3931],[-1959,90],[-1640,-775],[-706,-2895],[-756,-1599],[-736,-322]],[[458212,569531],[1002,3368],[1159,897],[1480,451],[-15,1621],[-586,998],[669,797],[-58,2140]],[[461863,579803],[1795,-239],[197,-924],[2002,-886],[2505,452]],[[453993,585214],[2924,-6],[1115,1338],[2174,-1917],[967,326],[361,-1234],[-1109,-589],[-2512,1900],[-375,-951],[-1467,-420],[-56,-999],[-2263,-14],[-317,-533]],[[453578,577913],[3158,803],[1052,1123],[4075,-36]],[[558233,746730],[1699,113],[983,1413],[1567,66],[1173,1290]],[[573113,751865],[844,-1865],[-817,-966],[1,-1684],[-811,-1349]],[[254921,597903],[-2078,-3474],[-683,-1639],[139,-1535],[-529,-1131]],[[251770,590124],[-2061,-3444],[26,-582]],[[243791,590891],[444,3133],[-311,1461],[1252,4439],[3582,15],[83,1886],[-815,1878],[-1942,3246],[1158,-21],[10,3342],[5077,-10]],[[341125,537589],[-378,-3130],[-1056,-173],[-954,-4853],[616,-2938],[787,-1914],[683,144],[261,-2929],[1404,-5014],[615,-559]],[[331272,535536],[-1763,4177],[689,1820],[-47,2846],[1188,437],[897,1049],[193,1117],[-855,457],[-239,1704],[571,1863],[1337,1424],[558,1495],[-517,1442]],[[817405,638260],[69,-246]],[[269007,593543],[-716,89],[-1256,-1266],[-1862,-954],[-897,1045],[-836,-1686],[-130,-1264],[-1607,-2769],[-704,1219],[-811,-1660],[-1115,-39],[64,-2666],[-968,-1908],[-773,-72]],[[256071,584100],[275,2450],[-1210,1034],[-921,-788],[-1772,3057],[-673,271]],[[551211,756860],[226,-751]],[[552514,776837],[644,-4357],[-361,-1939]],[[537716,774380],[2200,-210],[456,970],[869,-1054],[1368,-2],[-173,1574],[966,601],[31,2172],[2445,1773]],[[545878,780204],[2472,-3252],[1114,-952],[1531,-221],[1519,1058]],[[561477,791492],[1770,-1752],[299,-963]],[[563546,788777],[-1628,-1299],[-3475,-8801],[-2216,-792]],[[556227,777885],[-1975,276],[-1738,-1324]],[[545878,780204],[-1176,2151]],[[547631,789126],[1707,-1397],[2673,100],[188,1263],[3074,777],[1209,973],[434,1370],[2671,151],[876,-1269],[1014,398]],[[847411,448364],[-195,-316]],[[844380,449187],[165,186]],[[844545,449373],[683,-512],[450,1407]],[[845678,450268],[364,208]],[[846915,451584],[90,154]],[[847005,451738],[631,-1069],[-477,-428],[252,-1877]],[[890964,489271],[628,-15]],[[891592,489256],[0,-1148]],[[891592,488108],[4,-20988],[-314,-2334],[315,-979],[3,-13114]],[[891600,450693],[-144,200]],[[826595,529426],[-23,-50]],[[804524,516729],[69,-2445],[2367,-4460],[1200,920],[2311,-106],[857,853],[298,1752],[806,711],[1298,47],[126,-651],[1760,-1311],[779,1175],[1787,195],[791,3039],[-123,1602],[1091,1616],[-258,1883],[1023,1145],[310,2437],[7,2921],[910,2429],[3346,-69],[1316,-986]],[[720385,689001],[85,-152]],[[721990,687748],[22,-32]],[[725028,683425],[-1281,-1568],[-817,-2823],[-512,-3514],[3051,-2934],[1899,-2772],[375,277],[2070,-2339],[1547,-877],[1497,41],[728,672],[1442,-1141],[209,-1527],[1688,-1777],[765,585],[469,-1185],[1747,-387],[931,-826],[874,713],[754,-1156],[2132,414],[296,1746],[-492,2424],[349,4364]],[[770339,671893],[36,-1660],[-1211,-1741],[385,-3210],[-1035,1405],[-1677,-724],[-434,-1009],[-2157,-2663],[10,-3294],[-1606,-4726],[426,-1154],[-1152,-4306],[-459,-2639],[-2279,862],[299,-2014],[-137,-3255],[-559,-596],[-238,-1859],[232,-2121],[-549,-2112],[-765,754],[-317,-906]],[[689347,646059],[1553,636],[11,1783],[2308,44],[436,-595],[2308,1455],[470,-1068],[911,960],[10,1704],[-1099,4356],[-10,1446],[-1066,234],[-457,1206],[157,3326],[-1907,1973],[272,2193],[1601,3995],[720,1043],[927,-1754],[3147,1384],[1310,4676],[1560,1641],[1328,5365],[1188,942],[250,2026],[1223,2714],[815,836],[-320,895],[-22,3124],[638,1397],[1429,1135],[221,823],[-1877,1420],[15,1414],[-857,66],[-142,1321],[-859,1484],[433,1569],[-414,1666],[682,1196],[-824,170],[-389,1816],[420,1944],[942,663],[3914,-1554],[921,988],[1538,391],[1261,2216]],[[714023,712724],[2086,2287]],[[716109,715011],[31,-68]],[[719756,701565],[63,-322]],[[720045,697641],[8,-373]],[[649761,725957],[2308,938],[918,2374],[1397,1168],[1806,-156],[589,1043],[2091,-196],[395,-1341],[3056,-2082],[1055,266],[1350,-1024],[724,-1965],[1390,-1280],[774,-1927],[2162,29],[396,-6060]],[[669733,683211],[-724,-1598]],[[669009,681613],[1319,-2879],[846,-3442],[742,-1452],[2424,-2041],[1,-5639],[1122,13],[384,-758],[-381,-2719],[-2024,-619],[-556,-1209],[-1026,-679],[-559,-2805],[-224,-3357]],[[671077,654027],[-152,-40]],[[634851,682228],[-455,1586],[-1022,1395],[-12,3106],[-920,74],[0,2359],[418,2334],[-1274,3728],[-694,254],[-2067,2741],[-735,168],[92,1611],[-740,2253],[-1340,2139],[113,2632],[668,2271],[1266,1950],[-452,2349],[545,1756],[-1233,96],[-1005,1058],[-918,3026],[-739,3652]],[[624347,724766],[-566,3567],[-972,969],[609,2658],[-1132,6047],[1017,265],[549,2052],[640,-700]],[[633274,682349],[-850,668],[-1551,-795],[-580,-2511],[-1040,-2615]],[[629253,677096],[-486,-193],[-4555,770],[-5163,7712],[-2176,3466],[-4737,5087],[-3399,1099]],[[608737,695037],[283,1342],[-527,842],[-789,5208]],[[607704,702429],[5322,5687],[826,574],[577,2014],[60,3076],[383,2087],[-301,2565],[475,2614],[1033,489],[1584,3030]],[[617663,724565],[1155,1560],[2949,-879],[491,533],[746,-1987],[1343,974]],[[599409,698654],[-656,-2011]],[[598753,696643],[-995,823],[-659,-2213],[688,-2435],[-919,-2092],[1605,489]],[[598473,691215],[-77,-912]],[[598396,690303],[-61,-562]],[[598335,689741],[107,-581],[-830,-4216],[-464,-5130]],[[595125,689609],[645,2231]],[[597523,700720],[841,-48],[1272,2110]],[[599636,702782],[123,-2857],[-350,-1271]],[[538055,780323],[-894,-1532],[707,-500],[-175,-2032],[417,-1460]],[[608737,695037],[-509,-768],[-5566,-2982],[2838,-5874],[-963,-1106],[-456,-1886],[-1984,-764],[-775,-2197],[-1280,-1805],[-2957,966]],[[598473,691215],[301,1695]],[[598774,692910],[-21,3733]],[[599409,698654],[1624,-2062],[1240,-413],[5431,6250]],[[714023,712724],[-783,3269]],[[665127,772295],[-32,-131]],[[665095,772164],[-1906,1936]],[[663189,774100],[33,118]],[[722803,754670],[-801,1322],[-1197,263],[-1010,1885],[-1673,527],[-7596,404],[-428,-701],[-1633,532],[-2329,1990],[-1814,-1407],[-176,-3518],[-2055,1356],[-2601,1092],[-1556,-525],[-860,-2873]],[[697074,755017],[-1475,-1007],[-890,-1529],[-2863,-2687],[-1335,-2907],[46,-1282],[-1536,885],[-311,2294],[-3406,-103],[-586,4833],[-1359,59],[252,5841],[-825,-674],[-853,2568],[-1641,2395],[-1284,-969],[-3434,455],[-3380,-805],[-2304,4008],[-424,1334],[-2646,2687]],[[666820,770413],[22,2100]],[[662809,774782],[-59,-262]],[[662750,774520],[-391,14],[-6872,-3247],[5,-21758]],[[655492,749529],[-1200,-353],[-822,1158],[-960,2731],[-2175,2465],[-2419,-766],[-2100,-2521]],[[636756,779239],[-1728,1359],[-14,1181],[984,52],[-2360,5751],[-2271,-26],[-800,3220],[-954,757],[116,2330],[866,1735],[-590,1592],[528,2877],[929,2493],[1053,619],[2024,-3256],[1136,1095],[-606,3552],[1940,1416],[485,1372],[2080,1221],[1520,2605],[1529,-1504],[2740,1220],[667,-1182],[2131,4],[1954,-2175],[1690,-2696],[214,2002],[2264,-2348],[710,2],[1927,2473],[1445,270],[1196,-1044],[1102,1201],[1445,-166],[1457,-2187],[2580,-666],[396,1287],[2742,-615],[1243,981],[543,2184],[-617,1257],[-2495,1239],[-1109,1928],[1680,1033],[859,1445],[-492,2073],[681,1350],[2574,-171],[112,973],[-2265,1062],[933,1399],[-1543,583],[984,2533],[1653,-609],[3181,941],[3853,1653],[1935,-118],[887,1534],[2071,261],[4085,1215],[3567,3064],[3347,-1346],[1544,845],[1243,-4181],[-257,-2293],[676,-320],[2591,675],[375,-1824],[606,1007],[2935,-1213],[-776,-699],[-77,-2116],[1353,980],[1368,-783],[279,946],[3347,2717],[3279,1993],[-726,-2961],[3135,-3338],[2142,-4388],[2758,-6785],[1437,-4257],[1216,1017],[68,1404],[1193,582],[538,-1853],[1096,-1356],[2856,-73],[2398,1581],[1633,-1302],[1050,-3172],[1851,-1053],[840,-2737],[2470,-594],[1203,654],[1968,-3103]],[[616344,528283],[-1506,-4598],[-1048,-2293],[39,-21831],[1509,-4159],[30,-729]],[[608949,476917],[-3957,6031],[-524,1269],[98,2458],[-9967,11867]],[[594599,498542],[20,51]],[[594373,505981],[-1,1]],[[594372,505982],[1410,4908],[850,1118],[493,2445],[-165,4955],[-1272,4051],[-153,3128],[-633,720],[-525,2413]],[[594377,529720],[3590,7536]],[[704532,738430],[-2755,-373],[-1139,-1057],[-1178,403],[-932,1944],[-2048,-1128],[-348,896],[-3639,-235],[26,2629],[1833,1384],[1346,-906],[1407,1123]],[[697105,743110],[963,285],[1077,-797],[1219,1696],[629,-219],[2098,2277],[-1368,579],[-1267,1718],[-794,126],[-593,2051],[-713,-2400],[-1739,749],[-1671,1830],[1836,2655],[1074,849],[-782,508]],[[785927,574073],[-548,2269],[52,1994],[-711,1444],[-499,5154],[631,271],[1005,3264],[807,1161],[4388,564],[819,-1187],[304,704]],[[792175,589711],[464,-1402],[503,276],[1036,-1373],[612,738],[-406,1742],[1453,1393],[884,-1561],[1943,2313]],[[798664,591837],[-522,-3427],[761,-4081],[-362,-2414],[223,-2905],[-450,-1656],[-651,98],[-635,-1182],[-1435,-765],[-4,-1485],[-1129,357],[-429,-729],[13,-2018],[866,-1671],[-11,-1288],[-1136,1156],[-2035,-611],[-477,-2088],[-1179,-730]],[[851760,728554],[1487,3097],[2416,23],[932,1866]],[[559895,755010],[-1396,-451],[-1371,-1763]],[[555733,756786],[778,1663]],[[556511,758449],[1164,2552],[1743,-3005],[1006,-484],[-529,-2502]],[[634562,673818],[-2142,-58],[-662,2704],[-2505,632]],[[783687,637302],[1263,-2814],[314,-1435],[706,114],[-273,-2461],[704,-2217],[1472,-1153],[1160,1446],[1475,-1745],[-598,-1216],[697,-396],[859,-2112],[-1060,-2414],[-1430,383],[-377,-1986],[2278,-3179],[1196,-903],[-169,-1190],[1035,-1753],[647,-2467],[2253,-4643],[538,-2933],[1945,-2465],[-640,-1425],[1354,-3242],[-480,-1631],[108,-1628]],[[792175,589711],[812,1089],[104,4922],[303,2009],[-600,1703],[-997,1024],[-824,2887],[182,3867],[-1371,3054],[-1037,2981],[-1836,530],[-658,-2251],[-1207,-1156],[-1432,2235],[-2767,-4331],[-546,618],[568,2664],[-174,2213],[655,3377],[-207,3384],[-1629,-287],[-632,1518],[404,1970],[-626,1761],[-543,-410]],[[778117,625082],[353,2451],[876,561],[533,2889],[1062,1510]],[[599933,709876],[1269,-93],[422,-2324],[-1785,-3280],[-203,-1397]],[[468034,545635],[666,1931],[1723,3121],[213,1847],[503,512],[295,1941]],[[569389,635030],[-2,-11809],[-2776,-39],[0,-2958]],[[566611,620224],[-5322,5606],[-6655,7008],[-3992,4205],[-6242,6574],[-2792,-2660]],[[541608,640957],[-2079,-2238],[-2082,3328],[-4203,2001]],[[526440,683810],[1046,935],[892,2346],[-281,4032],[1976,3654],[1885,1973],[-1,4552]],[[579824,326379],[-958,-270],[-1038,-2931],[-737,251],[-1012,1683],[-936,3862],[675,857],[1225,3432],[2472,2123],[1877,-3010],[248,-1066],[-813,-3847],[-1003,-1084]],[[565235,824281],[-87,1206],[-1909,1264]],[[563239,826751],[181,2854],[-734,1307],[-1374,27],[-2324,1188]],[[558988,832127],[1,41]],[[558461,836902],[2884,1994],[4801,-459],[855,-385],[2174,793],[463,-1171],[1433,-416],[2799,-2741]],[[575977,845540],[1236,-1251],[-437,-2793],[1288,-1777],[124,-2387]],[[475879,668566],[-373,0],[63,-3174],[-1718,-191],[-894,-1348],[-1434,0],[-1865,886],[-1305,-753],[152,-1481],[-1056,-3135],[-868,-434],[-1112,-7111],[-1750,-2545],[-694,-2488],[-1278,-1128],[-695,-2251],[-556,-6520],[-1138,-2662],[-583,-2430],[-2528,237],[-3478,-415]],[[452769,631623],[199,2840]],[[463177,667252],[223,1310]],[[578367,773986],[-313,3094],[402,2835],[-479,3122],[-2042,3919],[-989,3053],[-1005,621]],[[573941,790630],[2584,1290],[1693,-1419],[2595,-1556],[186,-3080],[1082,-1236],[63,-1676],[849,-800],[-111,-2835],[-1921,1046],[-608,-609],[57,-2217],[-2043,-3552]],[[187598,692927],[3952,-2631]],[[191550,690296],[7854,31]],[[199404,690327],[7,2665]],[[199411,692992],[4885,-54],[549,-1336]],[[204845,691602],[2722,-4369]],[[207567,687233],[825,-955],[1319,-5737]],[[209711,680541],[1093,-1727]],[[210804,678814],[2369,-2281]],[[213173,676533],[1089,1522]],[[214262,678055],[364,2286]],[[214626,680341],[1292,1347],[1947,-368],[1471,-2067]],[[219336,679253],[1056,-2321]],[[220392,676932],[1008,-4389]],[[221400,672543],[2196,-4617]],[[223596,667926],[136,-2913]],[[223732,665013],[790,-2918]],[[224522,662095],[178,-694],[2848,-2266],[2011,-1149]],[[229559,657986],[590,539]],[[174644,697459],[6675,1079]],[[181319,698538],[-308,-1227]],[[181011,697311],[6587,-4384]],[[559895,755010],[2171,394]],[[511743,618128],[19,-12717],[-314,-3783],[-679,-3570],[-1035,-2363],[-6123,-498],[-945,-1691],[-2063,-447]],[[468362,578206],[-2,3185],[-680,2535],[-546,-320],[-619,1879],[98,3398],[-581,1493],[-145,2076]],[[465887,592452],[488,-377],[644,1480],[313,2550],[847,1184],[1409,-2810],[699,1609],[2098,-290],[2123,725],[10179,1],[424,4660],[-747,1693],[-1105,20579],[-1576,29341],[4920,5]],[[778117,625082],[-645,639],[-1198,-364],[119,-1039],[-1336,-864],[-289,-1593],[-1882,-487],[-623,348],[-550,-1715],[-308,-3129],[133,-1843],[-747,-750],[409,-1208],[446,-3608],[1795,-4180],[109,-1443],[944,-3266],[-627,-771],[-75,-3834],[-1040,-1182],[153,-2307],[900,-2694],[1010,-1837],[564,-1974],[-81,-3633],[825,-3291],[584,-4543],[-1180,-4004],[-1202,-2633],[-152,-2787]],[[553317,762628],[992,-1902],[2202,-2277]],[[553773,755249],[-181,-138]],[[553378,754483],[347,-292]],[[743928,795977],[1051,1713],[2266,126],[1793,1450],[-28,1099],[2809,1892],[4721,3802],[2079,-1541],[3189,-282],[1010,-3156],[1380,-523],[2057,458],[3149,-770],[619,-901],[2486,2057],[489,2697],[-1262,2679],[338,2151],[2628,4555],[2857,-2143],[1521,-174],[2533,-1620],[2029,-588],[492,-4553],[1097,-1172],[2636,-1472],[4864,1984],[2318,-1001],[1370,48],[1450,-1915],[1985,-383],[238,-1960],[1612,-1606],[1731,71],[2675,-974],[1744,-25],[1414,1124],[2064,405],[2710,1136],[302,1073],[3146,2827],[1240,-241],[1475,-1687],[1232,-405],[1158,772],[1524,-1108]],[[591350,345650],[-2148,58]],[[589202,345708],[-146,4865],[-311,359]],[[588745,350932],[104,8869],[-517,3368],[-706,2428],[-716,6400]],[[586910,371997],[3009,6323],[296,3684],[542,1166],[928,3806],[-637,2873],[-169,2291],[768,3807],[-125,9758],[-1958,1562],[-843,118],[-700,1272],[-1254,1129],[-2218,168],[-116,2086]],[[584433,412040],[-456,3868],[1226,1014],[7024,4773]],[[592227,421695],[1207,-3286],[1934,945],[479,-1123],[99,-4142],[-813,-3497],[409,-1846],[2486,-5319],[-342,3180],[531,2368],[1103,605],[382,6911],[-127,1308],[-1666,4587],[-1075,2219]],[[596834,424605],[3,366]],[[597102,435195],[7,928]],[[597109,436123],[1865,-23],[429,765],[1128,-1290],[909,-270],[983,859],[1390,-825],[2232,2558],[876,-797],[842,1092],[1463,630],[1853,1788],[1319,2111]],[[465887,592452],[-1606,2569],[-1936,5341],[-869,24],[-1199,2560],[-1918,573],[-2160,-1137],[-1308,274],[-823,-4105]],[[452643,627982],[233,3099],[10967,28],[-217,6885],[-200,1523],[374,1464],[1143,1606],[1658,1163],[20,14976],[9261,0],[-3,7645]],[[596829,424051],[5,554]],[[592227,421695],[-583,-52],[-889,2440],[821,2283],[150,3522],[1045,834],[-404,2235],[-72,3422],[426,2234],[-329,1566],[1105,1795],[-362,2108],[-604,1165],[-321,2439],[-766,1297]],[[591444,448983],[1391,-1188],[1480,-297]],[[778108,542882],[160,1362],[1714,-1455],[721,-1088],[-199,-2794],[366,-795],[1229,1605],[883,-488],[630,2470]],[[826676,529600],[-81,-174]],[[816815,531927],[28,-1]],[[564946,400206],[2484,945],[1826,-369],[907,-1482]],[[555501,357928],[0,-21769],[-859,-312],[-1416,-2576],[-897,412],[-2044,-15],[-1819,1028],[-173,2044],[-915,1908],[-835,-2494],[-856,-980]],[[541608,640957],[537,-6364],[26,-2362],[1182,-3371],[-56,-1309],[1005,-2549],[-594,-2364],[-724,-17748],[-3074,-6862],[-2554,-8113],[439,-4006]],[[537795,585909],[-785,-200],[-1858,-2039],[-533,-1380],[-2920,1540],[-1258,106],[-2151,-601],[-1580,-2722],[-2403,578],[-1821,2269],[-851,277],[-2033,-2001],[-702,637],[-1161,2938],[-2484,1595],[-695,-685],[-1162,15],[-1878,-1789],[-554,-4045],[-837,-1452],[-142,-4939]],[[537795,585909],[1271,-3709]],[[516367,805398],[-552,132]],[[585749,918146],[-25,-1452],[-1759,565],[-3505,-3625]],[[557283,913723],[-1404,-95],[563,-1581],[-971,-2356],[-4420,1221],[-1283,-3540],[-1645,823],[-3325,-4017],[767,-2197],[-2724,-3348],[169,-1089],[-2613,-1047],[-176,-4904],[-2304,-4266],[1187,-696],[-325,-2666],[-1836,360],[-1770,-796],[-1840,-3844],[606,-1724],[-288,-2421],[525,-1815],[-412,-3346],[2015,-2183],[-549,-1811],[-1080,-260],[818,-3270],[-285,-2038],[-2237,-3048],[-105,-3947],[-707,654]],[[647459,603350],[-990,3862],[-2087,10047]],[[644382,617259],[8332,5923],[1844,11884],[-1265,4160]],[[671509,653647],[-432,380]],[[307320,412833],[-113,108]],[[307956,408551],[363,-118]],[[308196,406812],[33,-40]],[[892036,450086],[-436,607]],[[891592,488108],[0,1148]],[[891592,489256],[365,-10]],[[554456,827357],[1677,-227],[7106,-379]],[[565570,809933],[1390,-3987],[-370,-2577],[-725,-194],[-2951,-4966],[446,-3071],[-753,308]],[[562607,795446],[-2497,2010],[-2844,-120],[-2387,-1110],[-875,2330],[-812,-1171],[-881,656]],[[539607,823035],[636,-341]],[[539863,823801],[-381,71]],[[539476,824343],[6,-471]],[[862574,756716],[445,-1380]],[[642410,650501],[-838,-197],[-449,1276]],[[578367,773986],[1523,-1281],[1786,1099],[840,-947]],[[563069,766802],[-576,2775],[-1124,-973],[-2042,1895],[372,1543],[-1993,2145],[2,1573],[-1481,2125]],[[563546,788777],[905,815],[2709,-1058],[1114,148],[874,-1263],[1585,1143],[1941,484],[1267,1584]],[[558952,831200],[36,927]],[[558054,832260],[-112,-611]],[[0,890205],[0,1449]],[[0,925312],[0,1133]],[[0,927721],[0,818]],[[999999,913406],[0,-23201]],[[866732,772708],[-53,-123]],[[868915,771622],[0,87]],[[606150,783708],[203,2771],[1703,1754],[2321,-62],[617,2513],[-870,1909],[956,1541],[-840,928],[1065,1139],[-109,2350],[-695,-147],[-1683,1682],[-712,-185],[-1833,1349],[-588,-784],[-1733,2911],[-2232,-1198],[-3355,1957],[-277,2988],[-688,945],[-2306,240],[-314,2579],[769,599],[-1841,3344],[-3409,-214],[-625,-1153],[-1443,-78]],[[576786,848429],[98,16]],[[576897,854139],[-40,15]],[[683568,913720],[921,-525]],[[584749,498394],[841,-2938],[45,-4593],[-764,-366]],[[580160,490226],[146,78]],[[581248,494433],[-78,295]],[[582158,496495],[981,-486],[1194,2342],[416,43]],[[452751,631365],[18,258]],[[644382,617259],[-7737,-2221],[-2834,-2751],[-1646,-4198],[-383,-1993],[-1295,-939],[-815,1867],[-1033,-221],[-2510,524],[-718,638],[-2756,-171],[-664,-438],[-1386,1135],[-631,-929],[-72,-3969],[-1016,-1882]],[[594661,560771],[-520,4],[189,2270],[-186,2095],[-2000,3858],[-275,4392],[351,3708],[-1326,34],[41,-1264],[-1846,-18],[731,-1722],[191,-3900],[-1309,-2341],[-772,-2615],[-1195,-2500],[-1348,-335],[-2046,3168],[-1104,-1258],[-368,-1756],[-1315,-939],[-431,-1683],[-2210,15],[-453,1606],[-2254,84],[-1453,-522],[-1833,4011],[-259,1290],[-2031,-751],[-783,-3075],[-703,-5260],[-1069,-1311]],[[563500,569410],[173,2519],[-1017,1924],[-567,5870],[-1464,771],[1119,3194],[-335,2374],[1118,2352],[-357,2507],[804,1019],[726,2604],[5,2198],[475,1004],[2440,460],[-9,22018]],[[594377,529720],[-1352,-2756],[-1367,741],[-1837,-1031],[-499,-1055],[-995,1627],[-883,-724],[-910,623],[-872,-1747]],[[635940,571417],[-2,-10703],[-2666,-8619]],[[562607,795446],[-1130,-3954]],[[549900,856389],[43,-180]],[[589202,345708],[-328,130],[-101,-2893],[-1358,61],[-1128,1086],[-748,2062],[25,2078],[1122,3377],[578,574],[1481,-1251]],[[599701,717503],[725,-490],[616,1999],[726,372],[-276,1323],[337,2045],[2160,-943],[2098,1530],[1597,-1235],[1639,-69],[1833,856],[1915,1610],[2249,-51],[2092,1110],[251,-995]],[[688219,724942],[154,1865],[1332,3234],[108,1214],[-792,2556],[155,1735],[-1186,275],[-908,1384],[1026,2247],[2067,-502],[1288,3553],[967,366],[-191,2183],[577,1366],[830,-831],[2024,2171],[860,-1681],[-1023,-1695],[751,-1495],[847,223]],[[655492,749529],[2891,-348],[-150,3513],[346,518]],[[658579,753212],[-98,-1010]],[[660075,754430],[-26,79]],[[660049,754509],[1142,1924],[1269,-1012],[-929,1844],[1216,891],[2394,-2837],[1131,-26],[290,-2019],[638,-711],[-285,-2577],[1015,-1053],[2427,-157],[467,479],[1128,-1080],[2077,-7318],[4200,-5361],[4028,-4236],[679,178],[2145,-1994],[-298,-3458]],[[844545,449373],[448,506]],[[844993,449879],[685,389]],[[847805,449005],[-394,-641]],[[847005,451738],[291,494]],[[588280,498780],[5,-46]],[[594254,497680],[345,862]],[[597109,436123],[-62,678]],[[591444,448983],[-1352,1488],[-1363,606],[-1133,2019],[-969,612]],[[586627,453708],[-6,44]],[[582337,478120],[15,207]],[[584749,498394],[930,386],[2601,0]],[[594372,505982],[-81,24]],[[588243,499173],[37,-393]],[[582342,501717],[624,1207]],[[582730,503997],[-277,8]],[[586953,517904],[-112,-392]],[[352309,311155],[-25,-42]],[[351267,306014],[29,-49]],[[251173,789100],[-75,-59]],[[280385,761145],[23,13]],[[289481,768262],[-31,38]],[[311664,775792],[-173,-93]],[[312640,774914],[-1,5]],[[138294,830715],[-1003,-1519]],[[663118,773843],[71,257]],[[665095,772164],[-147,-601]],[[666819,770377],[1,36]],[[660049,754509],[-189,580]],[[658593,753357],[-14,-145]],[[662750,774520],[-4,-21]],[[581568,373230],[829,282],[2214,-1082],[1267,227],[1032,-660]],[[586662,453459],[-35,249]],[[584433,412040],[-2524,-318],[-1700,-2010],[-319,-2939]],[[579890,406773],[-220,141]],[[575057,398323],[-669,-492],[-1240,665],[-1306,-134],[-1679,938]],[[584936,456017],[-10,-250]],[[575633,399537],[498,1027]],[[194446,794974],[-11287,0]],[[183159,794974],[-1817,3409],[182,2469],[-384,2214],[-1158,1154],[-2198,3412],[-1879,3917],[-663,-456],[-1133,2619],[-1142,1346],[-1360,18],[-273,1708],[-1344,2838],[-2555,1459],[-771,2631],[2,36479]],[[166666,860191],[12153,0],[5208,0],[10417,0]],[[194444,860191],[2,-65217]],[[146674,804734],[4763,-1918],[2332,-5262],[1798,-1212]],[[155567,796342],[1385,-3802],[-271,-1473]],[[156681,791067],[-4239,2531]],[[152442,793598],[753,1585]],[[153195,795183],[-1696,-517]],[[151499,794666],[-511,1450]],[[150988,796116],[-1665,1521],[-289,1293]],[[149034,798930],[-2506,2827]],[[146528,801757],[-1706,-61]],[[144822,801696],[-116,1881]],[[144706,803577],[1164,-240],[58,1057]],[[145928,804394],[-1647,-501]],[[144281,803893],[-798,1456]],[[143483,805349],[1189,689]],[[144672,806038],[2002,-1304]],[[134017,819872],[828,-2926]],[[134845,816946],[-375,-732]],[[134470,816214],[1025,-2515],[-2622,3729],[60,1281],[-1119,819]],[[131814,819528],[2203,344]],[[142910,818356],[118,-2495]],[[143028,815861],[-470,-1357],[-187,2807]],[[142371,817311],[-427,-530],[-771,2038]],[[141173,818819],[401,1551],[1336,-2014]],[[139308,819707],[-1857,2230]],[[137451,821937],[1590,-639]],[[139041,821298],[267,-1591]],[[131512,825393],[1448,-552]],[[132960,824841],[1295,634]],[[134255,825475],[-953,-5192]],[[133302,820283],[-2316,1437]],[[130986,821720],[-577,1603]],[[130409,823323],[11,2256]],[[130420,825579],[1092,-186]],[[138819,835824],[-202,1310]],[[138617,837134],[-4105,2900]],[[134512,840034],[-691,-52]],[[133821,839982],[-576,2586],[-4971,9944],[-3119,3456]],[[125155,855968],[-298,1719]],[[124857,857687],[-1180,1273],[-2349,-1117]],[[121328,857843],[-713,-2681],[-2389,-1476]],[[118226,853686],[-430,1914]],[[117796,855600],[-4064,4594]],[[113732,860194],[7956,-3],[7932,0],[5287,0],[7932,0],[5287,0],[7932,0]],[[156058,860191],[10608,0]],[[183159,794974],[-5516,0]],[[177643,794974],[-2753,0]],[[174890,794974],[-7396,0]],[[167494,794974],[-8574,0]],[[158920,794974],[-724,0]],[[158196,794974],[-795,2762]],[[157401,797736],[-1545,209]],[[155856,797945],[-35,2883]],[[155821,800828],[-659,-1117]],[[155162,799711],[-1780,1348]],[[153382,801059],[-768,2925]],[[152614,803984],[-3864,212],[1534,798]],[[150284,804994],[-1721,237]],[[148563,805231],[-319,1130]],[[148244,806361],[-1182,-282]],[[147062,806079],[-1807,1681]],[[145255,807760],[176,1939]],[[145431,809699],[-623,1758]],[[144808,811457],[214,3046]],[[145022,814503],[-863,-2968]],[[144159,811535],[-708,2195]],[[143451,813730],[699,4431]],[[143429,817681],[-797,2476],[-1191,732]],[[141441,820889],[-93,1622],[1590,-1307]],[[142938,821204],[-1159,2494]],[[141779,823698],[-903,-2657]],[[140876,821041],[-776,-838],[-2144,2799]],[[137956,823002],[813,2426],[-1076,1704],[2415,6170]],[[140108,833302],[-1178,-614]],[[138930,832688],[-111,3136]],[[252921,841529],[-12978,-18385],[-4259,-5483],[-5,-20456]],[[235679,797205],[-18,-2238],[-5733,8]],[[229928,794975],[-4397,-1],[-7107,0]],[[218424,794974],[-987,22745],[-773,17686],[-2,24786]],[[216662,860191],[11248,0],[8834,3]],[[236744,860194],[-45,-4347]],[[236699,855847],[319,-2357]],[[237018,853490],[1073,-913]],[[238091,852577],[-125,-2480]],[[237966,850097],[767,2741]],[[238733,852838],[2161,-22]],[[240894,852816],[2329,-8777]],[[243223,844039],[-794,-2022]],[[242429,842017],[4484,1823]],[[246913,843840],[1442,-99]],[[248355,843741],[2226,-1441]],[[250581,842300],[2340,-771]],[[322136,777316],[-788,-1048]],[[321348,776268],[-4361,-3630]],[[316987,772638],[-2744,-922]],[[314243,771716],[-701,605]],[[313542,772321],[-966,631]],[[312576,772952],[64,1967],[-976,873]],[[311664,775792],[-17,7865],[-1191,1559],[-1647,-845]],[[308809,784371],[-625,541]],[[308184,784912],[1874,1744],[3,2015],[2125,410],[689,-850],[1835,993]],[[314710,789224],[2375,-660]],[[317085,788564],[508,-1273]],[[317593,787291],[1846,893],[830,-723]],[[320269,787461],[-581,-2111]],[[319688,785350],[-1130,-1585]],[[318558,783765],[1355,-239],[-207,-1024]],[[319706,782502],[1012,-3837],[1737,-441]],[[322455,778224],[-319,-908]],[[345948,810042],[-1590,-1233],[641,-1748],[-2483,-5769]],[[342516,801292],[-356,-2642]],[[342160,798650],[1598,2823]],[[343758,801473],[238,-888]],[[343996,800585],[1754,338]],[[345750,800923],[-1417,-1733]],[[344333,799190],[-131,-1498],[2445,179]],[[346647,797871],[-104,-1672]],[[346543,796199],[2153,1954],[2361,-1232]],[[351057,796921],[128,-1069]],[[351185,795852],[-1633,-2094],[1286,-640]],[[350838,793118],[-1027,-1546]],[[349811,791572],[2807,1423]],[[352618,792995],[-218,-1524],[-1316,-1151]],[[351084,790320],[-700,-2418]],[[350384,787902],[716,-812]],[[351100,787090],[892,1987],[1158,683]],[[353150,789760],[-860,-2725]],[[352290,787035],[147,-1173],[945,1861],[357,-1302]],[[353739,786421],[-1156,-5144],[-1518,-6]],[[351065,781271],[-55,2711]],[[351010,783982],[-1493,-1524]],[[349517,782458],[846,3001]],[[350363,785459],[-896,2801]],[[349467,788260],[-1030,-2871]],[[348437,785389],[-817,58]],[[347620,785447],[-1275,-2839]],[[346345,782608],[-1314,-228],[-138,1210],[964,528]],[[345857,784118],[1728,2431],[-1380,533],[-190,-946],[-1188,171]],[[344827,786307],[12,1712]],[[344839,788019],[-1010,-875]],[[343829,787144],[-2031,-574]],[[341798,786570],[-3835,606]],[[337963,787176],[-2177,-629]],[[335786,786547],[-431,2517]],[[335355,789064],[2616,3120]],[[337971,792184],[-1072,450],[868,2880]],[[337767,795514],[1177,861]],[[338944,796375],[-100,1854],[1994,6850],[1522,3414]],[[342360,808493],[2013,1739],[1575,-190]],[[341388,809491],[-2,3304],[-11295,-1],[-6776,0],[-1264,2706],[1811,1369],[-728,2441],[-1408,-1692],[133,-3724],[-444,-2714],[-2352,2525],[-2496,-269],[-1188,1375],[453,3291],[-2132,-841],[361,3400],[-1442,1614],[-834,2561],[683,1201],[-302,1601],[1306,653],[-798,2486],[2184,-1408],[-342,3138],[3051,-3456],[3708,-111],[1638,-676],[667,3290],[1109,1021],[-2479,4488],[-299,3517],[580,1175],[793,4957],[-1188,351],[-906,2275],[1454,1721],[-619,1078],[1438,533],[-3487,1171],[1153,410],[-143,3137],[-1037,72],[424,2165],[-596,853],[738,1519]],[[320515,861997],[-428,-1741]],[[320087,860256],[1347,308]],[[321434,860564],[2066,-4332]],[[323500,856232],[94,-1290]],[[323594,854942],[1756,-2623]],[[325350,852319],[-1433,-1302],[2172,259]],[[326089,851276],[-1036,-2388]],[[325053,848888],[1374,360]],[[326427,849248],[1631,-1734]],[[328058,847514],[-191,-1478],[-1353,-888]],[[326514,845148],[1677,-478]],[[328191,844670],[-351,-790]],[[327840,843880],[1788,-1407],[-105,-1953]],[[329523,840520],[-1919,107]],[[327604,840627],[1770,-2004]],[[329374,838623],[-68,-2163],[1716,-223]],[[331022,836237],[1364,-1026]],[[332386,835211],[413,-1800]],[[332799,833411],[-1180,-2492]],[[331619,830919],[2384,1477]],[[334003,832396],[2116,-949]],[[336119,831447],[602,-1843]],[[336721,829604],[2272,222]],[[338993,829826],[1550,-1809]],[[340543,828017],[-2075,-1304]],[[338468,826713],[-1338,-1782]],[[337130,824931],[-3305,-1274]],[[333825,823657],[-1407,-3367]],[[332418,820290],[2798,2237]],[[335216,822527],[1861,1980],[2011,744]],[[339088,825251],[-733,738]],[[338355,825989],[2156,-387]],[[340511,825602],[780,-2198]],[[341291,823404],[-1089,-1138],[543,-774]],[[340745,821492],[1363,1602]],[[342108,823094],[2030,-901]],[[344138,822193],[867,-2225]],[[345005,819968],[-117,-4172]],[[344888,815796],[403,-2191]],[[345291,813605],[-3903,-4114]],[[322136,777316],[2050,-1544]],[[324186,775772],[1645,-68],[605,-703]],[[326436,775001],[1465,1460]],[[327901,776461],[1287,-1074]],[[329188,775387],[1280,-2341]],[[330468,773046],[-4118,-2655]],[[326350,770391],[-2201,-1192]],[[324149,769199],[-827,242]],[[323322,769441],[-437,-1166]],[[322885,768275],[-662,938],[-2397,-4603]],[[319826,764610],[-2432,-1819]],[[317394,762791],[-1077,1499]],[[316317,764290],[73,3279]],[[316390,767569],[1610,2165]],[[318000,769734],[-380,163]],[[317620,769897],[3683,3252]],[[321303,773149],[-65,-1013]],[[321238,772136],[2739,1342],[-4291,60]],[[319686,773538],[1662,2730]],[[331391,775898],[539,2552]],[[331930,778450],[1778,-263]],[[333708,778187],[103,-1152]],[[333811,777035],[-1550,-1839]],[[332261,775196],[-2494,-479]],[[329767,774717],[-587,2177],[1736,5067]],[[330916,781961],[1283,1226]],[[332199,783187],[212,-1397],[-681,-3528],[-1467,-1348],[128,-1430],[1000,414]],[[164773,916863],[10,-9267],[10642,-6944],[4258,-2777],[7806,-5092],[5096,-31],[3202,-3521],[1510,-733],[12107,-2039],[7265,-1224],[-7,-25044]],[[216662,860191],[-12497,0],[-9721,0]],[[156058,860191],[-2168,3915],[46,1723],[-2210,-955],[-4198,24],[-508,3401],[-2558,2023],[-1576,2404],[-1967,292],[161,2057],[-1411,1885],[248,1402],[-1401,1233],[803,1241],[-2265,2753],[-1240,2668],[-4151,2518],[686,1260],[-1134,1103],[1576,2209],[-1164,2556],[-2708,-394],[-129,3572],[-1167,2600],[-5751,2],[-120,3019],[-768,1376],[6,6805]],[[120990,912883],[3004,-1178]],[[123994,911705],[-1429,1307],[514,2336]],[[123079,915348],[4976,1286],[-762,-1632]],[[127293,915002],[2808,1073]],[[130101,916075],[898,1283]],[[130999,917358],[4733,1519]],[[135732,918877],[1772,1400]],[[137504,920277],[2361,-862]],[[139865,919415],[-3643,-2167],[-2508,-489]],[[133714,916759],[-4211,-3927]],[[129503,912832],[1868,-425],[-35,1566]],[[131336,913973],[2585,2089],[2153,-19]],[[136074,916043],[119,-1301],[1714,2648],[3455,1339]],[[141362,918729],[384,-1004]],[[141746,917725],[3576,3246],[-853,1857]],[[144469,922828],[2368,-1982]],[[146837,920846],[1462,-3015],[3403,-2258]],[[151702,915573],[516,2842]],[[152218,918415],[2102,1669],[889,-2492]],[[155209,917592],[-837,-1840]],[[154372,915752],[2268,-13]],[[156640,915739],[1622,2564]],[[158262,918303],[4151,-203]],[[162413,918100],[2360,-1237]],[[194439,937095],[5,-17659],[-8004,0],[-11594,6],[552,-2089]],[[175398,917353],[-774,2669]],[[174624,920022],[7063,1258],[5429,-517]],[[187116,920763],[2793,495]],[[189909,921258],[-5902,2263]],[[184007,923521],[-6204,-619]],[[177803,922902],[-4434,256]],[[173369,923158],[-1880,1533],[1249,1601],[5341,1323]],[[178079,927615],[846,975]],[[178925,928590],[-5934,-923]],[[172991,927667],[-54,1592],[-3127,163]],[[169810,929422],[-213,1770]],[[169597,931192],[2032,1642]],[[171629,932834],[-448,1607]],[[171181,934441],[2286,1760]],[[173467,936201],[8093,3209]],[[181560,939410],[1318,-609]],[[182878,938801],[152,-2422]],[[183030,936379],[-969,-1663]],[[182061,934716],[2661,676]],[[184722,935392],[811,1698]],[[185533,937090],[5384,-1584]],[[190917,935506],[-1737,-2119]],[[189180,933387],[4693,1808]],[[193873,935195],[-1266,2056],[1832,-156]],[[167398,943794],[1680,-502]],[[169078,943292],[1633,1284]],[[170711,944576],[2859,-77]],[[173570,944499],[5567,-3631]],[[179137,940868],[177,-1066]],[[179314,939802],[-9763,-4471]],[[169551,935331],[-1240,-1918],[-2144,-875],[-1221,-4189]],[[164946,928349],[-3139,-361]],[[161807,927988],[-3297,-2114],[-2976,3493]],[[155534,929367],[-4875,2725]],[[150659,932092],[2154,2668]],[[152813,934760],[419,2893]],[[153232,937653],[2887,4099]],[[156119,941752],[-2498,3437]],[[153621,945189],[9391,1077]],[[163012,946266],[4869,-1760]],[[167881,944506],[-483,-712]],[[168348,952708],[4561,2933],[-1599,-3156],[-2962,223]],[[194437,952245],[0,-4077]],[[194437,948168],[-6992,-2572]],[[187445,945596],[-2762,79]],[[184683,945675],[-1718,1990]],[[182965,947665],[3601,1240],[3236,261]],[[189802,949166],[1770,1229],[-7438,-938]],[[184134,949457],[-847,2167]],[[183287,951624],[-1209,-2052]],[[182078,949572],[-3547,-710]],[[178531,948862],[-5198,1799]],[[173333,950661],[1238,1192]],[[174571,951853],[2992,119]],[[177563,951972],[2654,1260],[-5287,-617]],[[174930,952615],[1909,1655]],[[176839,954270],[-756,1141],[2859,2156]],[[178942,957567],[3852,83]],[[182794,957650],[1029,-1449]],[[183823,956201],[3128,-30],[4569,-3870]],[[191520,952301],[2917,-56]],[[179024,963052],[-2040,-1550]],[[176984,961502],[181,-2907],[-2593,-1854]],[[174572,956741],[-2406,880]],[[172166,957621],[666,2001]],[[172832,959622],[-2809,-1607]],[[170023,958015],[-1047,-2290],[-986,1266],[-1082,-2852]],[[166908,954139],[-3074,957]],[[163834,955096],[-3836,-451]],[[159998,954645],[97,2708],[2088,238],[7011,5116]],[[169194,962707],[5030,50],[2545,1359]],[[176769,964116],[2255,-1064]],[[183799,965371],[-3325,1261]],[[180474,966632],[1941,652]],[[182415,967284],[1384,-1913]],[[193893,964006],[-4872,-1067]],[[189021,962939],[-3367,1102],[-63,2263]],[[185591,966304],[8843,1052],[-541,-3350]],[[190458,968527],[-4765,716],[7619,2064],[1122,-2577],[-3976,-203]],[[275745,817216],[-3632,1793]],[[272113,819009],[533,807]],[[272646,819816],[1977,116]],[[274623,819932],[1122,-2716]],[[280734,838063],[-2959,-1979]],[[277775,836084],[2024,3959]],[[279799,840043],[935,-1980]],[[310717,863514],[897,-667]],[[311614,862847],[-1153,-1236],[256,1903]],[[319909,868276],[-1665,1681]],[[318244,869957],[1785,75],[-120,-1756]],[[279041,874472],[614,-2284]],[[279655,872188],[-958,-2261],[-1656,1029]],[[277041,870956],[677,3109]],[[277718,874065],[1323,407]],[[304619,875284],[-1192,285]],[[303427,875569],[-1024,1666]],[[302403,877235],[1923,-856]],[[304326,876379],[293,-1095]],[[272221,877686],[-315,-1789]],[[271906,875897],[-2506,-2620]],[[269400,873277],[-1897,-294]],[[267503,872983],[-557,1873]],[[266946,874856],[1453,2538]],[[268399,877394],[3822,292]],[[284615,879658],[-1122,-1024]],[[283493,878634],[-1569,1996]],[[281924,880630],[1751,115],[940,-1087]],[[285098,881443],[642,556],[1267,-1708],[-1909,1152]],[[264112,891353],[853,1103],[7118,-4757]],[[272083,887699],[1039,-2559],[-630,-1073]],[[272492,884067],[2983,348]],[[275475,884415],[1463,-1942]],[[276938,882473],[-2067,-1781]],[[274871,880692],[-3699,1453]],[[271172,882145],[-248,1304]],[[270924,883449],[-2853,1020]],[[268071,884469],[-650,-1693]],[[267421,882776],[-2513,-2986]],[[264908,879790],[-2396,-1008]],[[262512,878782],[-858,3361],[-2896,-777]],[[258758,881366],[-950,574]],[[257808,881940],[2603,2752],[-340,2542]],[[260071,887234],[1146,6745]],[[261217,893979],[1131,1269]],[[262348,895248],[1764,-3895]],[[264792,893213],[-1282,1457]],[[263510,894670],[549,1112]],[[264059,895782],[733,-2569]],[[267428,894527],[-1090,-148]],[[266338,894379],[-802,2127],[1892,-1979]],[[295495,906299],[-2644,265],[-370,1413],[3532,-575]],[[296013,907402],[-518,-1103]],[[259456,906015],[-1011,2159]],[[258445,908174],[1496,493]],[[259941,908667],[-485,-2652]],[[291239,908966],[74,-4127]],[[291313,904839],[-1813,-1504],[-3403,-98]],[[286097,903237],[-836,2600],[1571,3113]],[[286832,908950],[2957,540],[1450,-524]],[[291997,909646],[-1443,1047],[1158,724]],[[291712,911417],[285,-1771]],[[279970,912589],[-542,459]],[[279428,913048],[2248,2652]],[[281676,915700],[1021,-396]],[[282697,915304],[-2727,-2715]],[[286124,914356],[-898,1615]],[[285226,915971],[1591,-74],[-693,-1541]],[[277839,916524],[-2223,991]],[[275616,917515],[3743,655],[-1520,-1646]],[[232499,915545],[1985,-3018]],[[234484,912527],[-2266,-2158]],[[232218,910369],[-2974,431]],[[229244,910800],[-5469,2217]],[[223775,913017],[-41,1263],[2777,1206]],[[226511,915486],[521,2488],[1327,635]],[[228359,918609],[975,-1297],[3165,-1767]],[[164773,916863],[2302,-1330],[2734,-506]],[[169809,915027],[2148,-1269],[5655,-1220],[1190,804]],[[178802,913342],[3380,-1855],[1250,-1543]],[[183432,909944],[-2225,-764],[-1858,-2180]],[[179349,907000],[4868,-1198]],[[184217,905802],[3463,-90]],[[187680,905712],[4529,875],[1952,947]],[[194161,907534],[1310,-1538]],[[195471,905996],[2882,-840]],[[198353,905156],[1843,-2750]],[[200196,902406],[-1574,-204]],[[198622,902202],[2183,-2087],[232,1559]],[[201037,901674],[1306,-719]],[[202343,900955],[-2266,5037]],[[200077,905992],[587,1779],[3713,997]],[[204377,908768],[1785,1931]],[[206162,910699],[-2297,-1002]],[[203865,909697],[-2809,-156]],[[201056,909541],[-318,-933]],[[200738,908608],[-2645,614]],[[198093,909222],[1036,1975]],[[199129,911197],[5969,1833],[1736,-1193]],[[206834,911837],[309,-1542]],[[207143,910295],[3430,-2530]],[[210573,907765],[1999,496]],[[212572,908261],[2172,-1799],[3159,-701]],[[217903,905761],[3052,868]],[[220955,906629],[3637,-687],[2041,495]],[[226633,906437],[2659,-1127]],[[229292,905310],[690,1410]],[[229982,906720],[-2512,285],[-1499,2729]],[[225971,909734],[3444,787],[1904,-2578]],[[231319,907943],[2097,1113]],[[233416,909056],[-1115,-4119]],[[232301,904937],[639,-1671]],[[232940,903266],[1171,265]],[[234111,903531],[1016,-1990]],[[235127,901541],[265,1670]],[[235392,903211],[-1089,2813]],[[234831,907706],[1666,120],[3381,3504]],[[239878,911330],[-2552,1651]],[[237326,912981],[1336,1328]],[[238662,914309],[-525,1891],[-4943,2228]],[[233194,918428],[-1377,2939],[1853,1314]],[[233670,922681],[-1862,1538],[398,2755]],[[232206,926974],[2338,374],[-856,1401]],[[233688,928749],[1864,1958]],[[235552,930707],[1789,446]],[[237341,931153],[4468,-4247]],[[241809,926906],[-91,-2428]],[[241718,924478],[2771,-3358]],[[244489,921120],[20,-1462]],[[244509,919658],[-2531,-2195]],[[241978,917463],[2711,-812],[3769,-158]],[[248458,916493],[-1896,-1297]],[[246562,915196],[2137,-2499]],[[248699,912697],[-293,-2305]],[[248406,910392],[1109,-1212],[1411,4410]],[[250926,913590],[1694,1490],[2821,-2691],[413,-3339],[-1262,237],[419,-3095]],[[255011,906192],[2581,-3447]],[[257592,902745],[2028,1968]],[[259620,904713],[1623,3296]],[[261243,908009],[1207,4132]],[[262450,912141],[1821,1801],[-1457,936]],[[262814,914878],[-78,3659],[3259,-87]],[[265995,918450],[1601,-800]],[[267596,917650],[3586,-343],[-1057,-874]],[[270125,916433],[3962,-2218]],[[274087,914215],[-1748,-1400]],[[272339,912815],[1879,-1341]],[[274218,911474],[-3531,-1249]],[[270687,910225],[1600,-3463]],[[272287,906762],[1962,-2382]],[[274249,904380],[-548,-2310],[-3261,-2858]],[[270440,899212],[-2449,-1296]],[[267991,897916],[-1103,1836],[-2571,2073]],[[264317,901825],[2833,-4376]],[[267150,897449],[-1813,-656]],[[265337,896793],[-2677,2121]],[[262660,898914],[-3309,-35]],[[259351,898879],[1640,-3015],[-3467,-3955],[-1885,-36],[-4943,3479]],[[250696,895352],[-3501,175],[3393,-1356],[2262,-2301]],[[252850,891870],[5407,-890]],[[258257,890980],[-703,-2203]],[[257554,888777],[-2293,-3809]],[[255261,884968],[-1977,-1132]],[[253284,883836],[-3751,-80]],[[249533,883756],[-215,-1995],[-1573,-362],[-2862,691],[3042,-2050]],[[247925,880040],[-86,-2251],[-1864,-992]],[[245975,876797],[-2534,90],[981,-1652]],[[244422,875235],[-1510,36]],[[242912,875271],[66,-2240]],[[242978,873031],[-2928,-1341]],[[240050,871690],[750,-1036]],[[240800,870654],[-2080,-2662]],[[238720,867992],[-21,-1061],[-1607,-4281]],[[237092,862650],[-348,-2456]],[[194439,937095],[3463,-2553],[1513,-4739]],[[199415,929803],[2511,850],[-1081,1509]],[[200845,932162],[-1507,5667]],[[199338,937829],[581,1439]],[[199919,939268],[2995,-430],[3162,-1573]],[[206076,937265],[4064,-9341]],[[210140,927924],[-611,-1954]],[[209529,925970],[1711,-2023]],[[211240,923947],[2511,-638],[4131,-3081],[1444,-143]],[[219326,920085],[299,-2344],[-3609,753]],[[216016,918494],[-1075,-1723]],[[214941,916771],[-2050,794]],[[212891,917565],[747,-2805]],[[213638,914760],[2608,1633],[818,-2747],[-2884,-1187]],[[214180,912459],[-6141,574]],[[208039,913033],[240,953]],[[208279,913986],[-3115,478]],[[205164,914464],[-1441,1644],[-2167,-2591]],[[201556,913517],[-4184,-1435],[-6569,-1291]],[[190803,910791],[-5047,-284]],[[185756,910507],[-1359,2040]],[[184397,912547],[-214,2113]],[[184183,914660],[-4069,413]],[[180114,915073],[-3763,947]],[[176351,916020],[-953,1333]],[[202996,940045],[854,1278]],[[203850,941323],[3059,415],[2400,-896]],[[209309,940842],[183,-1543]],[[209492,939299],[-1963,-2571],[-4533,3317]],[[279063,941080],[3474,67]],[[282537,941147],[3000,-985]],[[285537,940162],[2547,-2480]],[[288084,937682],[-308,-1543],[-3987,452]],[[283789,936591],[-4624,-835]],[[279165,935756],[-1897,2777]],[[277268,938533],[-1780,924]],[[275488,939457],[171,2235],[3404,-612]],[[259474,925417],[4151,836]],[[263625,926253],[624,-889]],[[264249,925364],[584,3462]],[[264833,928826],[-3477,2372]],[[261356,931198],[1405,1353],[2929,-962],[-2749,2185]],[[262941,933774],[-843,2091],[1740,3325],[3434,482]],[[267272,939672],[3118,1852],[3481,-563],[3144,-5266],[-2652,-2571]],[[274363,933124],[1030,-2372],[2268,2861]],[[277661,933613],[3730,-255],[2703,-1014]],[[284094,932344],[-2036,2147],[4349,1056]],[[286407,935547],[4442,-1421]],[[290849,934126],[1086,-2253]],[[291935,931873],[1695,-297]],[[293630,931576],[-308,-2239]],[[293322,929337],[4172,31],[4572,-1872]],[[302066,927496],[-663,-1520],[1951,-12]],[[303354,925964],[381,-1376]],[[303735,924588],[-1724,-2195]],[[302011,922393],[3684,2042]],[[305695,924435],[4421,-1908]],[[310116,922527],[-1557,-1872]],[[308559,920655],[485,-1575],[1732,2213]],[[310776,921293],[2102,-1660]],[[312878,919633],[395,-1800]],[[313273,917833],[-2479,139]],[[310794,917972],[-1108,-1048]],[[309686,916924],[4839,-1425]],[[314525,915499],[-89,-1090]],[[314436,914409],[-3154,565]],[[311282,914974],[518,-1241]],[[311800,913733],[-795,-2890]],[[311005,910843],[3678,-624]],[[314683,910219],[-325,-1362]],[[314358,908857],[1719,384],[-560,-2229],[3991,825]],[[319508,907837],[2280,-2491]],[[321788,905346],[889,-2126]],[[322677,903220],[2211,-173],[-1837,-2444]],[[323051,900603],[4814,1166],[1858,-2196]],[[329723,899573],[-1564,-1989]],[[328159,897584],[-1918,557]],[[326241,898141],[1560,-2201]],[[327801,895940],[-1663,-5]],[[326138,895935],[-191,-2337]],[[325947,893598],[-1885,-137],[-747,-4081]],[[323315,889380],[-803,1074]],[[322512,890454],[-1832,43]],[[320680,890497],[-2351,3836]],[[318329,894333],[1103,1858]],[[319432,896191],[-2282,-478]],[[317150,895713],[-2671,3310]],[[314479,899023],[-1455,-1493],[-1548,1105]],[[311476,898635],[1904,-2700]],[[313380,895935],[-2982,-568],[3163,-2952],[-578,-496]],[[312983,891919],[1832,-2268],[2022,-521]],[[316837,889130],[2400,-2661]],[[319237,886469],[-265,-2421]],[[318972,884048],[1365,0]],[[320337,884048],[456,-4526],[-1882,2963]],[[318911,882485],[396,-3137]],[[319307,879348],[1016,-1969]],[[320323,877379],[-1331,179]],[[318992,877558],[313,-1697]],[[319305,875861],[-3261,2731],[-529,-473]],[[315515,878119],[-2126,1645]],[[313389,879764],[-1982,2540]],[[311407,882304],[474,-1842]],[[311881,880462],[-2142,1793],[-1159,-131]],[[308580,882124],[2138,-3145],[1293,-467]],[[312011,878512],[4710,-5241]],[[316721,873271],[-768,-2018]],[[315953,871253],[-3287,1676]],[[312666,872929],[-2607,498],[-1955,1007]],[[308104,874434],[-1285,2011],[-1920,111]],[[304899,876556],[-2826,1653],[-1998,2296],[1436,487],[-2131,1165]],[[299380,882157],[-3390,4234]],[[295990,886391],[-4091,2183]],[[291899,888574],[767,-1391],[-5788,-1869],[-2965,743]],[[283913,886057],[-1065,1485]],[[282848,887542],[219,1905]],[[283067,889447],[2041,1524]],[[285108,890971],[95,1520]],[[285203,892491],[4162,-1340],[333,525]],[[289698,891676],[5994,1005]],[[295692,892681],[-542,1668],[-1911,2205],[3203,3175],[2947,3433]],[[299389,903162],[-3020,6597]],[[296369,909759],[-937,-434]],[[295432,909325],[-2788,2445],[-574,2124],[-4302,-2212]],[[287768,911682],[-427,1878]],[[287341,913560],[1676,127]],[[289017,913687],[463,1704]],[[289480,915391],[-1725,727]],[[287755,916118],[-292,1438]],[[287463,917556],[-2996,958]],[[284467,918514],[-697,2378]],[[283770,920892],[-1223,-106]],[[282547,920786],[-2176,2217],[-781,-1369],[1272,-2338],[-2018,-491]],[[278844,918805],[-5399,1283]],[[273445,920088],[-1608,-1600]],[[271837,918488],[-2646,964]],[[269191,919452],[-2133,-244]],[[267058,919208],[-6842,1081]],[[260216,920289],[-839,1516]],[[259377,921805],[-3546,-884]],[[255831,920921],[-2632,1606]],[[253199,922527],[-1688,3192]],[[251511,925719],[4475,-695]],[[255986,925024],[1957,398]],[[257943,925422],[-2033,1166],[-3353,471]],[[252557,927059],[-2129,1211]],[[250428,928270],[-498,2703]],[[249930,930973],[453,2745]],[[250383,933718],[1662,3892],[4288,3875]],[[256333,941485],[2641,658]],[[258974,942143],[4608,-153]],[[263582,941990],[-4219,-5554]],[[259363,936436],[1647,-6515]],[[261010,929921],[2814,-2475]],[[263824,927446],[-4350,-2029]],[[224561,941535],[4378,925]],[[228939,942460],[1612,-1311],[-753,-1655]],[[229798,939494],[-3234,-2290]],[[226564,937204],[2670,-48]],[[229234,937156],[880,-2070]],[[230114,935086],[1713,331]],[[231827,935417],[-705,-2280]],[[231122,933137],[507,-2844]],[[231629,930293],[-2691,-1209]],[[228938,929084],[-2435,850]],[[226503,929934],[723,-1969]],[[227226,927965],[-2690,-437],[-3965,4651]],[[220571,932179],[-3137,964],[-2750,2773]],[[214684,935916],[2198,1623]],[[216882,937539],[1588,-1840]],[[218470,935699],[2405,158]],[[220875,935857],[1078,1127]],[[221953,936984],[-951,1726]],[[221002,938710],[-2810,1045]],[[218192,939755],[1488,2218]],[[219680,941973],[2536,833]],[[223930,942411],[4686,1359],[-1589,-1423],[-3097,64]],[[241192,944080],[2634,-1117]],[[243826,942963],[5189,-616]],[[249015,942347],[-4898,-6604],[-5815,19]],[[238302,935762],[1822,-1989]],[[240124,933773],[-1340,-2325]],[[238784,931448],[-3209,-8]],[[235575,931440],[-985,4468]],[[234590,935908],[-237,5414]],[[234353,941322],[2598,-189]],[[236951,941133],[-951,2135]],[[236000,943268],[5192,812]],[[210778,949266],[-2132,660]],[[208646,949926],[1503,1671]],[[210149,951597],[1956,-1581]],[[212105,950016],[-1327,-750]],[[240159,949216],[-12,-1995]],[[240147,947221],[-3196,-291]],[[236951,946930],[-5173,2063],[2469,3190]],[[234247,952183],[3455,383]],[[237702,952566],[2457,-3350]],[[216034,955063],[-3020,-1485],[-2878,2478]],[[210136,956056],[4908,588]],[[215044,956644],[990,-1581]],[[211047,958429],[2699,-788]],[[213746,957641],[-3387,-733]],[[210359,956908],[688,1521]],[[228608,957739],[1014,-6202]],[[229622,951537],[-940,-1733]],[[228682,949804],[-2484,-698]],[[226198,949106],[-4627,-9]],[[221571,949097],[-1380,2007]],[[220191,951104],[3167,1830]],[[223358,952934],[-8195,-840]],[[215163,952094],[1662,2193]],[[216825,954287],[235,3289]],[[217060,957576],[5106,-2959]],[[222166,954617],[-2419,3175]],[[219747,957792],[6056,1294]],[[225803,959086],[2805,-1347]],[[194437,952245],[2939,947],[-2365,972]],[[195011,954164],[1016,1458]],[[196027,955622],[-1592,2195],[1847,1661]],[[196282,959478],[2420,-133],[-126,-1769]],[[198576,957576],[1834,-2259]],[[200410,955317],[-468,-1498]],[[199942,953819],[3136,-133]],[[203078,953686],[1376,1646]],[[204454,955332],[2543,-1863]],[[206997,953469],[-1060,-3283]],[[205937,950186],[-3585,-1567],[-4661,816]],[[197691,949435],[-3254,-1267]],[[238068,960381],[3611,-1730]],[[241679,958651],[4696,357],[5273,-2912]],[[251648,956096],[-5202,-173]],[[246446,955923],[5762,-2358],[-1225,-1167],[2026,-658]],[[253009,951740],[4609,970],[3302,-684]],[[260920,952026],[5935,1877]],[[266855,953903],[4940,71]],[[271795,953974],[5088,-1196]],[[276883,952778],[1910,-2546]],[[278793,950232],[-2009,-876],[2656,-793]],[[279440,948563],[-2434,-1991]],[[277006,946572],[-4253,-622]],[[272753,945950],[-9035,772]],[[263718,946722],[-2484,-641],[-6854,-27]],[[254380,946054],[231,1722]],[[254611,947776],[-4179,-1400],[-5881,1450]],[[244551,947826],[-1293,3277]],[[243258,951103],[995,1844],[-2842,4126],[-6062,-532]],[[235349,956541],[-4365,2738]],[[230984,959279],[243,1454]],[[231227,960733],[3111,545]],[[234338,961278],[3730,-897]],[[250463,962485],[-3651,710],[-5,1307]],[[246807,964502],[2715,-79]],[[249522,964423],[941,-1938]],[[209605,962901],[-1869,-923],[-2364,3220],[4233,-2297]],[[234765,965592],[5282,-126]],[[240047,965466],[176,-1756],[-6854,57]],[[233369,963767],[1396,1825]],[[232764,969972],[3660,-1103],[-556,-2089],[-5284,-1106]],[[230584,965674],[-3516,3693]],[[227068,969367],[120,2224]],[[227188,971591],[5576,-1619]],[[215066,972034],[2424,1183],[5817,-2939],[-394,-1659]],[[222913,968619],[1625,-2642]],[[224538,965977],[-3944,205]],[[220594,966182],[-1356,1790],[-4603,1051]],[[214635,969023],[-4425,-603],[-1865,1476]],[[208345,969896],[3420,6]],[[211765,969902],[-1076,2786]],[[210689,972688],[-1849,-1082]],[[208840,971606],[-1995,1336],[411,1724]],[[207256,974666],[5449,-48],[2361,-2584]],[[225579,978561],[-137,-1446],[-3477,1076]],[[221965,978191],[1003,1336],[2611,-966]],[[244762,985385],[3451,-3194]],[[248213,982191],[8245,-1313]],[[256458,980878],[-687,-1627]],[[255771,979251],[2624,-1206],[-882,-1859]],[[257513,976186],[4576,185]],[[262089,976371],[995,-2388]],[[263084,973983],[-6467,-3153]],[[256617,970830],[-3122,-546]],[[253495,970284],[-137,-2320]],[[253358,967964],[-3461,2456]],[[249897,970420],[1472,-2391]],[[251369,968029],[-6645,199]],[[244724,968228],[-6288,4486]],[[238436,972714],[7831,2173]],[[246267,974887],[-4106,527]],[[242161,975414],[-6338,-948]],[[235823,974466],[-4639,5012]],[[231184,979478],[5911,-516],[-4785,1448]],[[232310,980410],[2276,435]],[[234586,980845],[-1622,1924],[6125,-783]],[[239089,981986],[-4409,1652]],[[234680,983638],[680,965],[7938,1643]],[[243298,986246],[1464,-861]],[[306975,996546],[8048,-431]],[[315023,996115],[-2237,-1635]],[[312786,994480],[6923,1379],[5054,-1988]],[[324763,993871],[4467,-581]],[[329230,993290],[-1943,-2511]],[[327287,990779],[-6660,-1835],[-5699,-694]],[[314928,988250],[-4700,-2105]],[[317401,987526],[699,-1242]],[[318100,986284],[-8741,-3591]],[[309359,982693],[-7659,-5433],[-5791,-30],[18,-1548]],[[295927,975682],[-4981,-439]],[[290946,975243],[-4554,541]],[[286392,975784],[6574,-2724],[-11249,133]],[[281717,973193],[1942,-786]],[[283659,972407],[4519,382]],[[288178,972789],[5063,-1675]],[[293241,971114],[-1237,-1062]],[[292004,970052],[-4271,-198],[3396,-1088]],[[291129,968766],[-1868,-1884],[-5963,-377]],[[283298,966505],[-177,-2530]],[[283121,963975],[-2203,-1105]],[[280918,962870],[-6244,-373]],[[274674,962497],[4934,-659]],[[279608,961838],[334,-1317]],[[279942,960521],[2589,247]],[[282531,960768],[12,-2409],[-6683,-2338]],[[275860,956021],[-1334,1992]],[[274526,958013],[-3776,1247],[824,-1525]],[[271574,957735],[-4590,-75]],[[266984,957660],[-3488,-880]],[[263496,956780],[-2707,772]],[[260789,957552],[-6334,-177]],[[254455,957375],[-3261,515]],[[251194,957890],[196,1984],[3059,1641]],[[254449,961515],[4294,418],[-3452,3228]],[[255291,965161],[2992,1025]],[[258283,966186],[3971,-2555]],[[262254,963631],[2361,-592]],[[264615,963039],[2664,1016]],[[267279,964055],[-4194,157]],[[263085,964212],[-717,2184]],[[262368,966396],[1453,2279]],[[263821,968675],[-3315,-1370]],[[260506,967305],[827,1550]],[[261333,968855],[-4533,-984],[2067,3540]],[[258867,971411],[5011,818]],[[263878,972229],[4812,-841]],[[268690,971388],[2313,790]],[[271003,972178],[-3159,889],[-4205,3308],[-3697,1381]],[[259942,977756],[316,2809]],[[260258,980565],[7176,-537],[5189,-2999]],[[272623,977029],[2348,-174],[-5419,3465]],[[269552,980320],[8084,1485]],[[277636,981805],[8891,2071]],[[286527,983876],[-4725,256],[735,1458],[-7557,-3037]],[[274980,982553],[-8526,-584],[-9037,672]],[[257417,982641],[-4421,805]],[[252996,983446],[1412,1150]],[[254408,984596],[-4262,1024],[4079,2323]],[[254225,987943],[-8122,80]],[[246103,988023],[2535,1771]],[[248638,989794],[7920,1232]],[[256558,991026],[7206,-606]],[[263764,990420],[-4267,1212],[4678,1552]],[[264175,993184],[15200,-3524]],[[279375,989660],[-8407,3393]],[[270968,993053],[4003,2085],[6282,-591]],[[281253,994547],[-3906,1373]],[[277347,995920],[20398,1007],[9230,-381]],[[269941,777103],[157,-702],[2294,718]],[[272392,777119],[160,-2629]],[[272552,774490],[-3724,2172]],[[268828,776662],[1113,441]],[[279110,806663],[-539,898]],[[278571,807561],[536,2530]],[[279107,810091],[3,-3428]],[[279112,806382],[18,-19952],[412,-3135],[1622,-3722],[3051,-1226],[1248,-1677],[1138,-142],[1139,-2271],[1415,-451],[2888,1315],[1299,-440],[156,-2093]],[[293498,772588],[-1023,-1248]],[[292475,771340],[-1307,-619]],[[291168,770721],[-1718,-2421]],[[289450,768300],[-720,-735]],[[288730,767565],[-2939,-1148],[656,-1362]],[[286447,765055],[-914,-398]],[[285533,764657],[-1043,963]],[[284490,765620],[-4103,-1205]],[[280387,764415],[-1412,-1521],[-570,-1532]],[[278405,761362],[1213,-722]],[[279618,760640],[767,504]],[[280385,761144],[-13,-1048]],[[280372,760096],[25,-1444]],[[280397,758652],[-3232,-520]],[[277165,758132],[-641,-954],[-2648,99],[-1284,-2203],[-2162,-1310],[-1286,200],[88,1212]],[[269232,755176],[1352,232]],[[270584,755408],[-154,1442]],[[270430,756850],[633,2721]],[[271063,759571],[1757,1834],[213,4762]],[[273033,766167],[1195,3039],[-1165,3598],[1113,-13]],[[274176,772791],[103,-1306]],[[274279,771485],[1011,-1465]],[[275290,770020],[1860,-1609]],[[277150,768411],[327,1762]],[[277477,770173],[1085,-270],[-1023,2062]],[[277539,771965],[124,1381]],[[277663,773346],[-857,337]],[[276806,773683],[-1300,3268],[-2164,93]],[[273342,777044],[-52,905]],[[273290,777949],[-3917,366],[-2962,1065]],[[266411,779380],[-204,1195]],[[266207,780575],[-931,-470]],[[265276,780105],[321,2503]],[[265597,782608],[-1074,776]],[[264523,783384],[493,1680],[-1167,1886],[443,1844]],[[264292,788794],[-2563,120],[-908,1422],[-811,3086]],[[260010,793422],[-2298,265]],[[257712,793687],[-2889,1172]],[[254823,794859],[85,-2231]],[[254908,792628],[-749,1398]],[[254159,794026],[-755,-1481]],[[253404,792545],[-1184,-783]],[[252220,791762],[-1047,-2662]],[[251173,789100],[-3508,1179]],[[247665,790279],[-1884,-843]],[[245781,789436],[-4105,3279]],[[241676,792715],[-1975,-511]],[[239701,792204],[-2537,1286]],[[237164,793490],[-650,3328],[-835,387]],[[252921,841529],[2426,-2274]],[[255347,839255],[1427,-2435]],[[256774,836820],[5235,-2697]],[[262009,834123],[1710,-1869]],[[263719,832254],[3196,172]],[[266915,832426],[3703,-983]],[[270618,831443],[994,-1986],[-551,-2711],[768,-3189]],[[271829,823557],[-331,-5075]],[[271498,818482],[1914,-3518]],[[273412,814964],[61,-774]],[[273473,814190],[2477,-2833]],[[275950,811357],[499,-2673],[1041,-144]],[[277490,808540],[1622,-2158]],[[323107,780571],[1533,-828]],[[324640,779743],[2683,385]],[[327323,780128],[388,-389],[-2373,-2489]],[[325338,777250],[-485,1590]],[[324853,778840],[-622,-690]],[[324231,778150],[-1339,1447],[-978,164]],[[321914,779761],[-770,1278]],[[321144,781039],[1096,2492]],[[322240,783531],[-262,-1695]],[[321978,781836],[1129,-1265]],[[295648,774097],[-1094,-164]],[[294554,773933],[1345,1559],[-251,-1395]],[[308184,784912],[-526,997]],[[307658,785909],[-2124,-4467]],[[305534,781442],[-802,-4757],[-1671,-3813]],[[303061,772872],[-518,187]],[[302543,773059],[-675,-23]],[[301868,773036],[-528,-1674]],[[301340,771362],[-5096,-12]],[[296244,771350],[-3769,-10]],[[292475,771340],[3197,2496]],[[295672,773836],[1107,3465]],[[296779,777301],[3496,3684],[1777,737]],[[302052,781722],[2060,1637]],[[304112,783359],[4257,7361]],[[308369,790720],[3962,3441]],[[312331,794161],[3840,2116],[1819,315]],[[317990,796592],[1909,-441]],[[319899,796151],[1596,-1599]],[[321495,794552],[-242,-2954]],[[321253,791598],[-2530,-2381],[-1853,993]],[[316870,790210],[-2160,-986]],[[327168,795484],[-3740,1896]],[[323428,797380],[-886,1532]],[[322542,798912],[-1543,1007],[858,675]],[[321857,800594],[3536,-1400],[2892,-2499]],[[328285,796695],[45,-1124]],[[341388,809491],[-3917,-879]],[[337471,808612],[-1820,-3052]],[[335651,805560],[-2541,-3112]],[[333110,802448],[-3360,-312]],[[328542,801556],[-541,763]],[[328001,802319],[-2211,408]],[[325790,802727],[-5979,-155]],[[319811,802572],[-1113,263]],[[318698,802835],[-3408,-641]],[[315290,802194],[-1238,-1291],[-1197,-3823]],[[312855,797080],[-1901,-543],[-2424,-2535]],[[308530,794002],[-2069,-3731]],[[306461,790271],[-2297,918],[2016,-1517]],[[306180,789672],[-362,-1575]],[[305818,788097],[-2223,-4104],[-1561,-2036]],[[302034,781957],[-1700,-646]],[[300334,781311],[-3059,-2827]],[[297275,778484],[-1377,-2793]],[[295898,775691],[-1559,-1400]],[[294339,774291],[178,-929]],[[294517,773362],[-1019,-774]],[[279112,806382],[-2,281]],[[279107,810091],[1336,-479]],[[280443,809612],[381,-1561]],[[280824,808051],[477,1760],[-684,1399]],[[280617,811210],[1350,3072]],[[281967,814282],[-644,2225]],[[281323,816507],[-1082,6455]],[[280241,822962],[469,729]],[[280710,823691],[-2003,5078],[2101,1090],[2827,2104],[1573,1889]],[[285208,833852],[1874,3270]],[[287082,837122],[363,3553]],[[287445,840675],[-148,2809]],[[287297,843484],[-1622,4963]],[[285675,848447],[-3773,3931]],[[281902,852378],[157,1131]],[[282059,853509],[1939,3002]],[[283998,856511],[96,1753]],[[284094,858264],[1096,715]],[[285190,858979],[55,1456]],[[285245,860435],[-1331,3540]],[[283914,863975],[522,1098]],[[284436,865073],[-1607,-36]],[[282829,865037],[1853,4366]],[[284682,869403],[-1203,1219]],[[283479,870622],[-335,3516]],[[283144,874138],[1932,1287]],[[285076,875425],[4321,-1521]],[[289397,873904],[3253,-620]],[[292650,873284],[2822,1440]],[[295472,874724],[3900,-3689]],[[299372,871035],[2231,-3984],[3177,-536],[510,-1116],[1732,775],[-927,-6316]],[[306095,859858],[628,-1598],[-284,-1976]],[[307222,856261],[-366,-2776]],[[306856,853485],[2936,-271]],[[309792,853214],[669,-2514]],[[310461,850700],[1845,-1100]],[[312306,849600],[2672,1987]],[[314978,851587],[2782,3329]],[[317760,854916],[556,4055]],[[318316,858971],[1319,2706]],[[319635,861677],[880,320]],[[218424,794974],[-7407,0]],[[211017,794974],[-9175,0],[-7396,0]],[[113732,860194],[-65,2027],[-2483,-952]],[[111184,861269],[-2857,694]],[[108327,861963],[0,55397]],[[108327,917360],[5057,-801],[2926,-2154]],[[116310,914405],[4680,-1522]],[[6513,810872],[1645,1335],[-238,-1097],[-1407,-238]],[[9463,811999],[432,-667]],[[9895,811332],[-1456,-891]],[[8439,810441],[1024,1558]],[[13068,812920],[2748,1149]],[[15816,814069],[-1032,-1074],[-1716,-75]],[[33432,820758],[-3061,-3029]],[[30371,817729],[1969,3695]],[[32340,821424],[1032,595]],[[33372,822019],[60,-1261]],[[34659,820350],[-795,281],[1868,1201]],[[35732,821832],[440,2586]],[[36172,824418],[2075,-180],[-1499,-2705],[-2089,-1183]],[[45900,830448],[327,-1453]],[[46227,828995],[-4071,-1875]],[[42156,827120],[-178,1117],[994,1619]],[[42972,829856],[1839,938]],[[44811,830794],[1089,-346]],[[129708,833783],[-959,-1626]],[[128749,832157],[44,1600],[915,26]],[[136169,833460],[-581,-1676]],[[135588,831784],[-721,1199]],[[134867,832983],[-875,-1440],[-231,1485]],[[133761,833028],[614,2461]],[[135363,836221],[806,-2761]],[[128983,838496],[1009,-115]],[[129992,838381],[2860,-4972]],[[132852,833409],[-1162,-96]],[[131690,833313],[1708,-1515],[-438,-2939]],[[132960,828859],[-1800,1990]],[[131160,830849],[-892,1846]],[[130268,832695],[193,1360],[-1795,1158]],[[128666,835213],[317,3283]],[[132963,836150],[-1464,799]],[[131499,836949],[779,2491]],[[132278,839440],[685,-3290]],[[127916,837243],[-665,-301]],[[127251,836942],[-512,4513]],[[126739,841455],[1067,36],[374,-1556],[-264,-2692]],[[129538,842431],[1145,-729]],[[130683,841702],[-719,-2463]],[[129964,839239],[-1084,-3]],[[128880,839236],[-1046,3232]],[[127834,842468],[1704,-37]],[[125084,844493],[969,-3752]],[[126053,840741],[-93,-2907]],[[125960,837834],[-614,2624],[-1265,897],[363,1217]],[[124444,842572],[-838,1283],[-863,-1389]],[[122743,842466],[69,1825]],[[122812,844291],[1226,1279],[1046,-1077]],[[75283,847292],[1304,11]],[[76587,847303],[590,-1474]],[[77177,845829],[-2940,-2078]],[[74237,843751],[-1341,-2179],[-1352,1686]],[[71544,843258],[-47,-1370]],[[71497,841888],[-1237,2510]],[[70260,844398],[475,1327]],[[70735,845725],[1404,422]],[[72139,846147],[349,1121]],[[72488,847268],[1156,-527],[910,1427]],[[74554,848168],[729,-876]],[[123296,848287],[1697,351]],[[124993,848638],[197,-3377]],[[125190,845261],[-1573,1074],[-541,-1436],[-2434,3271],[684,1462],[1644,151],[326,-1496]],[[125887,849293],[1223,-104],[-74,-1538]],[[127036,847651],[948,-3245]],[[127984,844406],[-1851,-1451],[292,2312],[-1240,5017],[702,-991]],[[76620,850469],[853,-1179],[-1866,-861]],[[75607,848429],[-1668,423],[1502,1950]],[[75441,850802],[1179,-333]],[[89622,859078],[1542,3229]],[[91164,862307],[539,-616]],[[91703,861691],[-2081,-2613]],[[38512,862457],[1126,-411],[385,-2376]],[[40023,859670],[-1431,-816],[-2868,1381]],[[35724,860235],[-825,1173]],[[34899,861408],[1666,62]],[[36565,861470],[1947,987]],[[23714,881749],[2868,349]],[[26582,882098],[2784,-2077],[1977,-223]],[[31343,879798],[-377,-826]],[[30966,878972],[-2572,-459]],[[28394,878513],[-2080,1691]],[[26314,880204],[-3512,269]],[[22802,880473],[912,1276]],[[138819,835824],[-33,-3497]],[[138786,832327],[-1496,-3131],[-762,226],[-550,2074]],[[135978,831496],[591,1033]],[[136569,832529],[-848,3942]],[[135721,836471],[-1788,-716]],[[133933,835755],[-554,-2023]],[[133379,833732],[-667,1102],[1054,2601]],[[133766,837435],[-2970,5257]],[[129261,843431],[-245,3098]],[[129016,846529],[-1819,3187],[-1264,899]],[[125933,850615],[-1300,2714],[-645,3415],[-384,-1286],[1258,-5305]],[[124862,850153],[-2289,517],[-759,2339]],[[121814,853009],[-2340,1455]],[[119474,854464],[2577,-3447],[-1447,-1230]],[[120604,849787],[-2671,1992]],[[117933,851779],[-2246,2998]],[[115687,854777],[-4019,2719]],[[111668,857496],[1302,1960],[-524,830],[-1937,-1721]],[[110509,858565],[-1741,131]],[[108768,858696],[-2296,1310]],[[106472,860006],[-3544,753]],[[102928,860759],[-3338,-478],[-2094,1888]],[[97496,862169],[584,1979]],[[98080,864148],[-1548,-1711],[-1808,580]],[[94724,863017],[-2054,2483]],[[92670,865500],[155,1366]],[[92825,866866],[-2245,-1243],[-1707,299],[705,1484]],[[89578,867406],[-2239,-2466],[1649,-1883]],[[88988,863057],[-1297,-2937]],[[87691,860120],[-2679,691]],[[85012,860811],[-563,-1987]],[[84449,858824],[-2732,-1219]],[[81717,857605],[-980,-1869]],[[80737,855736],[-2234,-359],[-309,1290],[1251,652],[-1261,1574]],[[78184,858893],[1116,2491]],[[79300,861384],[265,3084],[2541,1780],[2359,-176]],[[84465,866072],[-980,1780],[-1853,41],[-3116,-2313]],[[78516,865580],[-46,-924],[-2510,-3060]],[[75960,861596],[-292,-1880]],[[75668,859716],[-1255,-464]],[[74413,859252],[-2436,-2840]],[[71977,856412],[-250,-1231]],[[71727,855181],[2343,-1763]],[[74070,853418],[-1904,-2162]],[[72166,851256],[-630,-1976]],[[71536,849280],[-2112,-851],[-2141,-2652]],[[67283,845777],[-1945,-1424]],[[65338,844353],[-420,-1884]],[[64918,842469],[-3444,-2160],[-1857,-1836]],[[59617,838473],[-700,-2064]],[[58917,836409],[-2649,-848]],[[56268,835561],[-2100,-1816],[-2726,-826]],[[51442,832919],[60,1370]],[[51502,834289],[-1708,-2902]],[[49794,831387],[-1300,613],[-368,-1458],[-1835,-933]],[[46291,829609],[156,1675]],[[46447,831284],[1035,437]],[[47482,831721],[2081,3103]],[[49563,834824],[2616,1788]],[[52179,836612],[2565,-1280]],[[54744,835332],[-655,948],[627,2067]],[[54716,838347],[3644,3235]],[[58360,841582],[3480,4076]],[[61840,845658],[594,5174]],[[62434,850832],[1060,2703]],[[63494,853535],[-2444,-1407]],[[61050,852128],[-2094,1554]],[[58956,853682],[-36,-2735]],[[58920,850947],[-817,171],[-1633,2615]],[[56470,853733],[-694,-540]],[[55776,853193],[-1229,1370]],[[54547,854563],[-2774,-2261]],[[51773,852302],[-2177,-150]],[[49596,852152],[1169,889],[-831,2901]],[[49934,855942],[541,1805],[-1646,4120]],[[48829,861867],[786,2379],[-1519,-2469],[317,-1654],[-3710,-1084],[-2099,2945],[-1921,1407],[1525,2078]],[[42208,865469],[2985,-1789]],[[45193,863680],[860,991]],[[46053,864671],[-4875,1234]],[[41178,865905],[833,718]],[[42011,866623],[-2265,1263],[-1324,2078]],[[38422,869964],[1541,1295]],[[39963,871259],[-262,1369]],[[39701,872628],[1425,2210],[1153,46]],[[42279,874884],[-183,1894]],[[42096,876778],[2050,2730],[2079,-1279]],[[46225,878229],[2048,1303],[940,1561]],[[49213,881093],[3286,170],[893,1546]],[[53392,882809],[-581,2562]],[[52811,885371],[-1186,1629]],[[51625,887000],[1341,313]],[[52966,887313],[-708,2043],[-1590,-638]],[[50668,888718],[-2910,-2619]],[[47758,886099],[-2518,1268]],[[45240,887367],[-3294,-756]],[[41946,886611],[-3455,724]],[[38491,887335],[-757,2036]],[[37734,889371],[-1426,1365],[2032,880]],[[38340,891616],[-3353,690],[-1899,1397]],[[33088,893703],[2816,1300]],[[35904,895003],[4514,3156]],[[40418,898159],[4783,1224]],[[45201,899383],[-850,-2375]],[[44351,897008],[938,-782],[5221,-177]],[[50510,896049],[1001,1348],[-1034,531]],[[50477,897928],[-2165,3101]],[[48312,901029],[1639,-653]],[[49951,900376],[300,-1330]],[[50251,899046],[3496,-1106]],[[53747,897940],[1079,1182]],[[54826,899122],[-1671,583],[-1484,-705]],[[51671,899000],[-1273,880]],[[50398,899880],[651,1653]],[[51049,901533],[-3832,284]],[[47217,901817],[-1997,997]],[[45220,902814],[-1125,2436],[-3501,2600]],[[40594,907850],[-3890,1860],[1128,388],[476,2726]],[[38308,912824],[5295,304],[3169,2674],[582,2193],[2440,2392],[2994,846]],[[52788,921233],[4671,3400],[3655,-197],[4246,3333],[6320,-3594]],[[71680,924175],[2673,778],[2778,-723]],[[77131,924230],[-661,-929]],[[76470,923301],[3461,-1391]],[[79931,921910],[5430,486],[4345,-1681],[5228,-339],[1740,-896]],[[96674,919480],[5497,637],[5029,-2743]],[[107200,917374],[1127,-14]],[[256972,684688],[-834,-509]],[[256138,684179],[-614,2384]],[[255524,686563],[-345,-1940]],[[255179,684623],[-734,25]],[[254445,684648],[-241,9003],[1116,18025],[-246,391]],[[255074,712067],[-48,154],[7130,-143]],[[262156,712078],[1175,-12113],[753,-4205],[-540,-2169],[324,-5206]],[[263868,688385],[-7184,-6],[478,-1950],[-190,-1741]],[[250820,718007],[-663,-1911],[-553,-3346],[-420,-671]],[[249184,712079],[-949,-3479],[-1208,-2604],[-383,-1769],[162,-3909]],[[246806,700318],[-8032,-23]],[[238774,700295],[-17,3214],[-1213,556]],[[237544,704065],[125,10302],[-498,6598]],[[237171,720965],[6963,0],[5415,0],[240,-1210],[-848,-1801],[1879,53]],[[197092,723926],[-3,-33609]],[[197089,690317],[-5539,-21]],[[191550,690296],[-3952,2631]],[[187598,692927],[-6587,4384]],[[181011,697311],[308,1227]],[[181319,698538],[688,750],[-632,1942],[544,4349],[1065,2267],[-681,1197],[-666,2977]],[[181637,712020],[55,2143],[-347,4338],[1868,573],[8,4872]],[[183221,723946],[5202,-7],[8669,-13]],[[154920,753549],[5885,-2],[5859,0]],[[166664,753547],[2,-17775],[5205,-7749],[5485,-8879],[4281,-7124]],[[181319,698538],[-6676,-1079],[-942,4515],[-1702,2528],[-917,129]],[[171082,704631],[-267,1621],[-1770,560]],[[169045,706812],[-1284,1813]],[[167761,708625],[-2431,318]],[[165330,708943],[-454,642]],[[164876,709585],[31,2941]],[[164907,712526],[-630,1712]],[[164277,714238],[-2826,5721],[-9,3601]],[[161442,723560],[-1429,1591]],[[160013,725151],[-331,3345],[1233,-1741]],[[160915,726755],[-875,2857],[1857,436]],[[161897,730048],[-2131,443],[-103,-1673]],[[159663,728818],[-1141,1356],[-525,2334]],[[157997,732508],[-1611,2714],[-511,5649],[-1220,2317]],[[154655,743188],[-132,1417]],[[154523,744605],[663,2836]],[[155186,747441],[179,2455]],[[155365,749896],[-445,3653]],[[216598,741701],[33,-17775]],[[216631,723926],[-2745,0]],[[213886,723926],[-5248,0],[-7347,0],[-4199,0]],[[197092,723926],[1,23698]],[[197093,747624],[8724,0],[5234,0]],[[211051,747624],[5546,-1],[1,-5922]],[[300553,753615],[-115,-4008]],[[300438,749607],[-3007,-298]],[[297431,749309],[-1960,-1738]],[[295471,747571],[416,6302]],[[295887,753873],[4666,-258]],[[290497,740602],[-463,-1035]],[[290034,739567],[543,-3247]],[[290577,736320],[985,-3774]],[[291562,732546],[-1860,-4],[-215,7508]],[[289487,740050],[1010,552]],[[273600,686784],[707,-5555]],[[274307,681229],[971,-4407]],[[275278,676822],[1044,-3340]],[[276322,673482],[-873,1608],[249,-2231]],[[275698,672859],[1451,-6955]],[[277149,665904],[514,-3783],[-327,-4089]],[[277336,658032],[-578,-3241]],[[276758,654791],[-1026,-1036]],[[275732,653755],[-1039,-109]],[[274693,653646],[-8,1358]],[[274685,655004],[-699,2747],[-974,902]],[[273012,658653],[-419,2677]],[[272593,661330],[-481,693]],[[272112,662023],[-76,2012]],[[272036,664035],[-620,-123]],[[271416,663912],[-960,3873]],[[270456,667785],[653,1841],[-497,729],[-226,-1422]],[[270386,668933],[-507,756]],[[269879,669689],[508,3791]],[[270387,673480],[25,2380]],[[270412,675860],[-1775,3344],[-1122,2808]],[[266544,683066],[-941,-1164]],[[265603,681902],[-2600,-1346]],[[263003,680556],[-97,1158]],[[262906,681714],[-1117,1726]],[[261789,683440],[-1941,1375]],[[259848,684815],[-2876,-127]],[[263868,688385],[343,-1663],[7345,-921],[494,-954],[351,2459],[1199,-522]],[[275354,694475],[-669,-895]],[[274685,693580],[-486,-3642],[-426,-380]],[[273773,689558],[-173,-2774]],[[262156,712078],[3609,-75]],[[265765,712003],[3360,78]],[[269125,712081],[-669,-1736],[1411,-1608],[718,-2485],[1621,-2930],[1433,-3479],[1153,-4894],[562,-474]],[[67829,617353],[-833,347],[-465,4024],[635,1566]],[[67166,623290],[-33,1550]],[[67133,624840],[1759,-1668],[1095,-2783]],[[69987,620389],[-1404,-1566]],[[68583,618823],[-754,-1470]],[[65314,628731],[1381,-1039]],[[66695,627692],[-1247,-826],[-134,1865]],[[63295,630407],[1393,-358]],[[64688,630049],[-410,-585]],[[64278,629464],[-983,943]],[[61668,631836],[456,-883]],[[62124,630953],[-1320,65]],[[60804,631018],[-453,1580]],[[60351,632598],[863,688]],[[61214,633286],[454,-1450]],[[57298,634654],[-1158,648],[1215,1054]],[[57355,636356],[-57,-1702]],[[248192,756583],[1342,-2445],[-500,-2774],[-1946,-1558],[262,-2094],[-1356,-3769]],[[245994,743943],[-804,1453],[-5606,-69],[-5598,-66]],[[233986,745261],[-894,7225],[-1095,4087]],[[231997,756573],[-391,1293],[467,4571]],[[232073,762437],[4516,2],[9952,6]],[[246541,762445],[488,-4229],[1163,-1633]],[[191524,768349],[3,-14800]],[[191527,753549],[-8312,2]],[[183215,753551],[-8261,-4]],[[174954,753547],[-10,10711],[301,2067],[-806,1652],[1813,6046],[79,1571],[-1045,1660]],[[175286,777254],[-356,2530],[-40,15190]],[[177643,794974],[-1,-5855],[875,-1768],[87,-1592],[981,-1046],[2077,-3560],[696,44],[-495,-6470],[643,-521],[986,1149],[1678,-5175],[942,-1941],[2134,476],[2032,-94],[450,1184],[796,-1456]],[[256077,756489],[41,-1692]],[[256118,754797],[767,-2866]],[[256885,751931],[-25,-16700],[-293,-2170],[-659,-1467],[-469,-2998]],[[255439,728596],[-182,-1509],[-1076,-1007],[64,-1635],[-1596,560],[-300,-1130]],[[252349,723875],[-924,1307],[-101,2558],[-1806,2515],[-558,1426],[687,3098],[-1491,918],[-710,2366],[-1407,2606],[-45,3274]],[[248192,756583],[7885,-94]],[[264455,751775],[-71,-15460]],[[264384,736315],[58,-1614],[-1789,-808],[-38,-905],[-1792,-3190],[-586,1018],[-650,-1461],[-890,350],[-756,-1013],[-642,701],[-1860,-797]],[[256885,751931],[1830,194]],[[258715,752125],[5739,-4],[1,-346]],[[237172,723926],[-5135,0],[-6419,0],[-8987,0]],[[216598,741701],[7569,0],[6405,0],[4575,3]],[[235147,741704],[1158,-829],[-355,-2089],[1210,-2279],[12,-12581]],[[270520,732502],[66,-2065],[858,-2444],[875,-874]],[[272319,727119],[-1990,-2379],[-1302,-2226],[-1437,-932]],[[267590,721582],[-175,-108],[-7714,462],[-3699,-124],[-611,-854],[-3865,1]],[[251526,720959],[817,1278],[6,1638]],[[264384,736315],[1288,-249],[363,-1094],[1493,-1278],[2248,360],[744,-1552]],[[251331,683591],[-1957,1106],[-522,-1415]],[[248852,683282],[661,-659]],[[249513,682623],[1216,846]],[[250729,683469],[1064,-2084],[-1018,-1190]],[[250775,680195],[576,-1180]],[[251351,679015],[1383,-1287]],[[252734,677728],[-939,-786],[-1454,2297],[-487,-157]],[[249854,679082],[-446,-1934]],[[249408,677148],[-463,1127]],[[248945,678275],[-1032,-973],[-1497,937],[127,996],[-1802,2244]],[[244741,681479],[-1021,-1654]],[[243720,679825],[-1141,239],[-1400,1077],[-1968,184]],[[239211,681325],[250,991]],[[239461,682316],[205,3442],[527,2891],[-1425,5646],[6,6000]],[[246806,700318],[0,-2316],[561,-2280],[-941,-2110],[-921,-3596],[-107,-1630],[5336,-4],[-277,-1602],[874,-3189]],[[302128,751805],[-426,1839],[-1149,-29]],[[295887,753873],[631,4128]],[[296518,758001],[2185,-130]],[[298703,757871],[3159,-165],[1454,1032]],[[303316,758738],[196,-1229]],[[303512,757509],[-863,-2003]],[[302649,755506],[856,-606],[621,-2521]],[[304126,752379],[1425,135]],[[305551,752514],[147,-883]],[[305698,751631],[-1968,-847],[-122,1071]],[[303608,751855],[-1299,-1336]],[[302309,750519],[-181,1286]],[[291562,732546],[-940,-2552]],[[290622,729994],[-787,-421]],[[289835,729573],[-532,105]],[[289303,729678],[-105,2275],[-897,34]],[[288301,731987],[-146,1414]],[[288155,733401],[731,10]],[[288886,733411],[-652,3495]],[[288234,736906],[1007,1892],[-1521,-1694],[-224,-4105]],[[287496,732999],[130,-2125]],[[287626,730874],[-2186,1904]],[[285440,732778],[587,2337]],[[286027,735115],[-1935,2708]],[[284092,737823],[-357,1501],[-905,509],[-873,-902],[-784,552],[-1973,-2463],[29,3033]],[[279229,740053],[10258,-3]],[[313542,772321],[-185,-2926]],[[313357,769395],[-1799,-588]],[[311558,768807],[-605,-1137]],[[310953,767670],[-1094,730]],[[309859,768400],[-228,-1475],[-1191,1038]],[[308440,767963],[-297,-1992]],[[308143,765971],[-2055,-1928]],[[306088,764043],[-436,492],[-2133,-4652]],[[303519,759883],[-618,1892],[-358,11284]],[[270430,756850],[-395,631]],[[270035,757481],[-1853,-5444]],[[268182,752037],[-3727,-262]],[[258715,752125],[639,894]],[[259354,753019],[925,2999]],[[260279,756018],[215,2861]],[[260494,758879],[-889,4365]],[[259605,763244],[64,2586]],[[259669,765830],[620,1522]],[[260289,767352],[164,2308],[1723,2801],[186,-2496],[483,2993]],[[262845,772958],[1135,685]],[[263980,773643],[-40,2219]],[[263940,775862],[582,164]],[[264522,776026],[3593,-2701]],[[268115,773325],[512,-3884]],[[268627,769441],[-101,-1826]],[[268526,767615],[-1523,-2444]],[[267003,765171],[399,-1990]],[[267402,763181],[979,1761]],[[268381,764942],[1210,848]],[[269591,765790],[788,-1261]],[[270379,764529],[684,-4958]],[[256650,771959],[-721,1537],[157,1886],[-952,1536],[-5464,2348],[-802,1488]],[[248868,780754],[2923,1713],[1957,2074]],[[253748,784541],[560,-2551]],[[254308,781990],[647,889]],[[254955,782879],[1606,-741],[777,-1790],[2002,-424],[1404,1387]],[[260744,781311],[3234,497]],[[263978,781808],[-185,-1570]],[[263793,780238],[1964,-86]],[[265757,780152],[279,-1823]],[[266036,778329],[906,-1200],[-1723,81],[-780,-712]],[[264439,776498],[-1881,1381],[-3012,-1333]],[[259546,776546],[-1141,-944]],[[258405,775602],[-23,1149]],[[258382,776751],[-1732,-4792]],[[254939,784414],[-604,-1184]],[[254335,783230],[-490,967]],[[253845,784197],[615,1271]],[[254460,785468],[1815,267]],[[256275,785735],[-1336,-1321]],[[251173,789100],[-3832,-2831]],[[247341,786269],[-3194,-4511]],[[244147,781758],[-513,-602],[-3,-3414],[-1114,-1040],[-553,-1861],[516,-598],[-256,-4170],[3935,-4735],[382,-2893]],[[232073,762437],[0,10641],[-1088,1770],[803,2055]],[[231788,776903],[-640,4178],[-200,5571],[-742,3466],[-278,4857]],[[251526,720959],[-706,-2952]],[[237171,720965],[1,2961]],[[235147,741704],[-1161,3557]],[[254445,684648],[-1404,262]],[[253041,684910],[-1710,-1319]],[[249184,712079],[5890,-12]],[[211080,776905],[-72,-5581]],[[211008,771324],[-4871,0],[-8525,0],[-6087,0],[-1,-2975]],[[211017,794974],[63,-18069]],[[281766,705417],[-3026,5452],[-3141,189],[-842,1937],[-3524,272],[-2108,-1186]],[[265765,712003],[104,1260],[1155,1860],[2447,1692],[285,896],[2323,1014],[882,1378],[208,1511]],[[273169,721614],[3063,-141],[6030,-100],[6720,-109]],[[288982,721264],[232,-2226]],[[289214,719038],[-2343,-1292]],[[286871,717746],[2650,-342]],[[289521,717404],[-4,-1498]],[[289517,715906],[-1111,-1735]],[[288406,714171],[-996,914]],[[287410,715085],[-1228,-297],[1282,-1113]],[[287464,713675],[-11,-2922]],[[287453,710753],[-1714,-411]],[[285739,710342],[-1714,-2505]],[[284025,707837],[-491,-2046]],[[283534,705791],[-1768,-374]],[[231788,776903],[-9060,0],[-7118,0],[-4530,2]],[[211051,747624],[-20,11852]],[[211031,759476],[9614,0],[5906,-2],[827,-881],[2514,49],[2105,-2069]],[[303519,759883],[-203,-1145]],[[298703,757871],[-230,926],[457,3807],[983,4571],[967,885],[460,3302]],[[291460,741597],[943,1013],[-1262,2615],[184,2389],[1177,2122]],[[292502,749736],[2192,-2162]],[[294694,747574],[-921,-3176]],[[293773,744398],[789,-758],[-607,-3565],[-1718,-4293]],[[292237,735782],[-2027,2893]],[[290210,738675],[284,1774],[966,1148]],[[213888,720966],[-116,-3],[-66,-26647],[-10007,-11],[619,-1378]],[[204318,692927],[-4907,65]],[[199411,692992],[-7,-2665]],[[199404,690327],[-2315,-10]],[[213886,723926],[2,-2960]],[[166664,753547],[8290,0]],[[183215,753551],[6,-29605]],[[300269,747979],[-3587,-2408]],[[296682,745571],[-2327,-92]],[[294355,745479],[1273,1665],[4641,835]],[[296244,771350],[86,-4365],[-195,-4089],[400,-151],[-17,-4744]],[[295471,747571],[-991,-1425],[214,1428]],[[292502,749736],[-899,1159],[-913,2639],[-4595,6],[-7659,10],[0,1627]],[[278436,755177],[2459,3101]],[[280895,758278],[-523,1818]],[[280385,761144],[2462,663]],[[282847,761807],[1794,-755],[1535,60]],[[286176,761112],[2069,1617],[-157,1768]],[[288088,764497],[604,887]],[[288692,765384],[-782,637]],[[287910,766021],[1540,2279]],[[276336,745528],[-1234,-6373],[-1928,-1773],[-626,-2238],[-329,693],[-881,-3149],[-818,-186]],[[268182,752037],[2706,-2059]],[[270888,749978],[2103,669]],[[272991,750647],[1374,1537]],[[274365,752184],[1967,1298]],[[276332,753482],[4,-7954]],[[237544,704065],[-2094,1826],[-1955,-437],[-1037,-1017],[-1841,1344],[-393,-1204],[-1503,1512],[-506,-676],[-711,1594],[-1098,-333],[-1924,869],[-483,1308],[-756,-401],[-1019,1174],[-9,11341],[-8327,1]],[[157719,778152],[775,-229],[601,-2614],[1453,-490],[1500,753],[1715,-468],[1927,510],[3699,1630],[5897,10]],[[154920,753549],[-351,723]],[[154569,754272],[-513,4087],[1086,5208]],[[155142,763567],[249,6434]],[[155391,770001],[361,4735]],[[155752,774736],[49,3585]],[[155801,778321],[1918,-169]],[[291460,741597],[-963,-995]],[[279229,740053],[-2895,-2],[2,5477]],[[276332,753482],[2104,1695]],[[302128,751805],[-583,-1497]],[[301545,750308],[-1107,-701]],[[281766,705417],[-770,-903]],[[280996,704514],[-1078,-3193]],[[279918,701321],[-2201,-3349]],[[277717,697972],[-947,-706]],[[276770,697266],[-1416,-2791]],[[211031,759476],[-23,11848]],[[267590,721582],[5579,32]],[[239461,682316],[-849,-1818]],[[238612,680498],[-1885,-726]],[[236727,679772],[101,1197],[-781,-282]],[[236047,680687],[374,-1965]],[[236421,678722],[-1070,-2410]],[[235351,676312],[-1612,-1917]],[[233739,674395],[-2185,405],[609,-1489]],[[232163,673311],[-1703,-2153]],[[230460,671158],[-707,-2508]],[[229753,668650],[-739,-4166],[424,-3382]],[[229438,661102],[711,-2578],[-590,-538]],[[229559,657986],[-2011,1148],[-2847,2266],[-933,3494],[-172,3032]],[[223596,667926],[-2196,4617]],[[221400,672543],[-1008,4389]],[[220392,676932],[-2171,4196],[-2508,523],[-1087,-1310]],[[214626,680341],[-364,-2286]],[[214262,678055],[-1089,-1522]],[[213173,676533],[-2369,2281]],[[210804,678814],[-1093,1727]],[[209711,680541],[-1319,5736],[-825,956]],[[207567,687233],[-2722,4369]],[[204845,691602],[-527,1325]],[[191527,753549],[0,-5925],[5566,0]],[[290622,729994],[-612,-2333]],[[290010,727661],[-1114,-2176]],[[288896,725485],[939,4088]],[[286027,735115],[-787,-2919]],[[285240,732196],[2122,-1790]],[[287362,730406],[793,-1190]],[[288155,729216],[2,-3179]],[[288157,726037],[-965,-204]],[[287192,725833],[910,-1599]],[[288102,724234],[-323,-965]],[[287779,723269],[1111,136],[92,-2141]],[[272319,727119],[1112,-1954],[1725,545],[1743,1231],[86,992],[1910,5332],[993,-596],[553,1856],[1683,2198],[314,1724],[1351,-1816],[303,1192]],[[157719,778152],[-677,696]],[[157042,778848],[-1689,49]],[[155353,778897],[-108,4478]],[[155245,783375],[-734,3693]],[[154511,787068],[-681,1455]],[[153830,788523],[-247,2821]],[[153583,791344],[2040,-1255]],[[155623,790089],[2642,-516]],[[158265,789573],[683,333]],[[158948,789906],[557,-5003]],[[159505,784903],[623,464],[-109,2660],[419,1128],[-1185,2692]],[[159253,791847],[344,1760]],[[159597,793607],[-677,1367]],[[258356,772744],[-801,-2405]],[[257555,770339],[-323,707]],[[257232,771046],[1124,1698]],[[256650,771959],[-1009,-3296]],[[255641,768663],[1013,1747]],[[256654,770410],[742,-421]],[[257396,769989],[-1568,-9070],[249,-4430]],[[244147,781758],[1689,23]],[[245836,781781],[1536,1111]],[[247372,782892],[581,-1569]],[[247953,781323],[915,-569]]],\"transform\":{\"scale\":[0.00036000036000036,0.00016879196566696583],\"translate\":[-180,-85.19218750000006]}}\n"
  },
  {
    "path": "assets/icons.go",
    "content": "package assets\n\nimport (\n\t_ \"embed\"\n)\n\n//go:embed data/icons/pm_light_512.png\nvar PNG []byte\n"
  },
  {
    "path": "assets/icons_default.go",
    "content": "//go:build !windows\n\npackage assets\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"image\"\n\t\"image/png\"\n\n\t\"golang.org/x/image/draw\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// Colored Icon IDs.\nconst (\n\tGreenID  = 0\n\tYellowID = 1\n\tRedID    = 2\n\tBlueID   = 3\n)\n\n// Icons.\nvar (\n\t//go:embed data/icons/pm_light_green_512.png\n\tGreenPNG []byte\n\n\t//go:embed data/icons/pm_light_yellow_512.png\n\tYellowPNG []byte\n\n\t//go:embed data/icons/pm_light_red_512.png\n\tRedPNG []byte\n\n\t//go:embed data/icons/pm_light_blue_512.png\n\tBluePNG []byte\n\n\t// ColoredIcons holds all the icons as .PNGs.\n\tColoredIcons [4][]byte\n)\n\nfunc init() {\n\tsetColoredIcons()\n}\n\nfunc setColoredIcons() {\n\tColoredIcons = [4][]byte{\n\t\tGreenID:  GreenPNG,\n\t\tYellowID: YellowPNG,\n\t\tRedID:    RedPNG,\n\t\tBlueID:   BluePNG,\n\t}\n}\n\n// ScaleColoredIconsTo scales all colored icons to the given size.\n// It must be called before any colored icons are used.\n// It does nothing on Windows.\nfunc ScaleColoredIconsTo(pixelSize int) {\n\t// Scale colored icons only.\n\tGreenPNG = quickScalePNG(GreenPNG, pixelSize)\n\tYellowPNG = quickScalePNG(YellowPNG, pixelSize)\n\tRedPNG = quickScalePNG(RedPNG, pixelSize)\n\tBluePNG = quickScalePNG(BluePNG, pixelSize)\n\n\t// Repopulate colored icons.\n\tsetColoredIcons()\n}\n\nfunc quickScalePNG(imgData []byte, pixelSize int) []byte {\n\tscaledImage, err := scalePNGTo(imgData, pixelSize)\n\tif err != nil {\n\t\tlog.Warningf(\"failed to scale image (using original): %s\", err)\n\t\treturn imgData\n\t}\n\treturn scaledImage\n}\n\nfunc scalePNGTo(imgData []byte, pixelSize int) ([]byte, error) {\n\timg, err := png.Decode(bytes.NewReader(imgData))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode image: %w\", err)\n\t}\n\n\t// Return data unprocessed if image already has the correct size.\n\tif img.Bounds().Dx() == pixelSize {\n\t\treturn imgData, nil\n\t}\n\n\t// Scale image to given size.\n\trectangle := image.Rect(0, 0, pixelSize, pixelSize)\n\tscaledImage := image.NewRGBA(rectangle)\n\tdraw.CatmullRom.Scale(scaledImage, rectangle, img, img.Bounds(), draw.Over, nil)\n\n\t// Encode scaled image.\n\tscaledImgBuffer := new(bytes.Buffer)\n\terr = png.Encode(scaledImgBuffer, scaledImage)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to encode image: %w\", err)\n\t}\n\n\treturn scaledImgBuffer.Bytes(), nil\n}\n"
  },
  {
    "path": "assets/icons_windows.go",
    "content": "package assets\n\nimport (\n\t_ \"embed\"\n)\n\n// Colored Icon IDs.\nconst (\n\tGreenID  = 0\n\tYellowID = 1\n\tRedID    = 2\n\tBlueID   = 3\n)\n\n// Icons.\nvar (\n\t//go:embed data/icons/pm_light_green_256.png\n\tGreenICO []byte\n\n\t//go:embed data/icons/pm_light_yellow_256.png\n\tYellowICO []byte\n\n\t//go:embed data/icons/pm_light_red_256.png\n\tRedICO []byte\n\n\t//go:embed data/icons/pm_light_blue_256.png\n\tBlueICO []byte\n\n\t// ColoredIcons holds all the icons as .ICOs\n\tColoredIcons = [4][]byte{\n\t\tGreenID:  GreenICO,\n\t\tYellowID: YellowICO,\n\t\tRedID:    RedICO,\n\t\tBlueID:   BlueICO,\n\t}\n)\n\n// ScaleColoredIconsTo scales all colored icons to the given size.\n// It must be called before any colored icons are used.\n// It does nothing on Windows.\nfunc ScaleColoredIconsTo(pixelSize int) {}\n"
  },
  {
    "path": "base/.gitignore",
    "content": "portbase\napitest\nmisc\n\ngo.mod.*\nvendor\ngo.work\ngo.work.sum\n"
  },
  {
    "path": "base/README.md",
    "content": "> **Check out our main project at [safing/portmaster](https://github.com/safing/portmaster)**\n\n# Portbase\n\nPortbase helps you quickly take off with your project. It gives you all the basic needs you would have for a service (_not_ tool!).\nHere is what is included:\n\n- `log`: really fast and beautiful logging\n- `modules`: a multi stage, dependency aware boot process for your software, also manages tasks\n- `config`: simple, live updating and extremely fast configuration storage\n- `info`: easily tag your builds with versions, commit hashes, and so on\n- `formats`: some handy data encoding libs\n- `rng`: a feedable CSPRNG for great randomness\n- `database`: intelligent and syncable database with hooks and easy integration with structs, uses buckets with different backends\n- `api`: a websocket interface to the database, can be extended with custom http handlers\n\nBefore you continue, a word about this project. It was created to hold the base code for both Portmaster and Gate17. This is also what it will be developed for. If you have a great idea on how to improve portbase, please, by all means, raise an issue and tell us about it, but please also don't be surprised or offended if we ask you to create your own fork to do what you need. Portbase isn't for everyone, it's quite specific to our needs, but we decided to make it easily available to others.\n\nPortbase is actively maintained, please raise issues.\n\n## log\n\nThe main goal of this logging package is to be as fast as possible. Logs are sent to a channel only with minimal processing beforehand, so that the service can continue with the important work and write the logs later.\n\nSecond, is beauty, both in form what information is provided and how.\n\nYou can use flags to change the log level on a source file basis.\n\n## modules <small>requires `log`</small>\n\npackages may register themselves as modules, to take part in the multi stage boot and coordinated shutdown.\n\nRegistering only requires a name/key and the `prep()`, `start()` and `stop()` functions.\n\nThis is how modules are booted:\n\n- `init()` available: ~~flags~~, ~~config~~, ~~logging~~, ~~dependencies~~\n  - register flags (with the stdlib `flag` library)\n  - register module\n- `module.prep()` available: flags, ~~config~~, ~~logging~~, ~~dependencies~~\n  - react to flags\n  - register config variables\n  - if an error occurs, return it\n  - return ErrCleanExit for a clean, successful exit. (eg. you only printed a version)\n- `module.start()` available: flags, config, logging, dependencies\n  - start tasks and workers\n  - do not log errors while starting, but return them\n- `module.stop()` available: flags, config, logging, dependencies\n  - stop all work (ie. goroutines)\n  - do not log errors while stopping, but return them\n\nYou can start tasks and workers from your module that are then integrated into the module system and will allow for insights and better control of them in the future.\n\n## config <small>requires `log`</small>\n\nThe config package stores the configuration in json strings. This may sound a bit weird, but it's very practical.\n\nThere are three layers of configuration - in order of priority: user configuration, default configuration and the fallback values supplied when registering a config variable.\n\nWhen using config variables, you get a function that checks if your config variable is still up to date every time. If it did not change, it's _extremely_ fast. But if it, it will fetch the current value, which takes a short while, but does not happen often.\n\n    // This is how you would get a string config variable function.\n    myVar := GetAsString(\"my_config_var\", \"default\")\n    // You then use myVar() directly every time, except when you must guarantee the same value between two calls\n    if myVar() != \"default\" {\n      log.Infof(\"my_config_var is set to %s\", myVar())\n    }\n    // no error handling needed! :)\n\nWARNING: While these config variable functions are _extremely_ fast, they are _NOT_ thread/goroutine safe! (Use the `Concurrent` wrapper for that!)\n\n## info\n\nInfo provides a easy way to store your version and build information within the binary. If you use the `build` script to build the program, it will automatically set build information so that you can easily find out when and from which commit a binary was built.\n\nThe `build` script extracts information from the host and the git repo and then calls `go build` with some additional arguments.\n\n## formats/varint\n\nThis is just a convenience wrapper around `encoding/binary`, because we use varints a lot.\n\n## formats/dsd <small>requires `formats/varint`</small>\n\nDSD stands for dynamically structured data. In short, this a generic packer that reacts to the supplied data type.\n\n- structs are usually json encoded\n- []bytes and strings stay the same\n\nThis makes it easier / more efficient to store different data types in a k/v data storage.\n\n## rng <small>requires `log`, `config`</small>\n\nThis package provides a CSPRNG based on the [Fortuna](https://en.wikipedia.org/wiki/Fortuna_(PRNG)) CSPRNG, devised by Bruce Schneier and Niels Ferguson. Implemented by Jochen Voss, published [on Github](https://github.com/seehuhn/fortuna).\n\nOnly the Generator is used from the `fortuna` package. The feeding system implemented here is configurable and is focused with efficiency in mind.\n\nWhile you can feed the RNG yourself, it has two feeders by default:\n- It starts with a seed from `crypto/rand` and periodically reseeds from there\n- A really simple tickfeeder which extracts entropy from the internal go scheduler using goroutines and is meant to be used under load.\n\n## database <small>requires `log`</small>\n_introduction to be written_\n\n## api <small>requires `log`, `database`, `config`</small>\n_introduction to be written_\n\n## The main program\n\nIf you build everything with modules, your main program should be similar to this - just use an empty import for the modules you need:\n\n    import (\n      \"os\"\n      \"os/signal\"\n      \"syscall\"\n\n      \"github.com/safing/portmaster/base/info\"\n      \"github.com/safing/portmaster/base/log\"\n      \"github.com/safing/portmaster/base/modules\"\n\n      // include packages here\n      _ \"path/to/my/custom/module\"\n    )\n\n    func main() {\n\n    \t// Set Info\n    \tinfo.Set(\"MySoftware\", \"1.0.0\")\n\n    \t// Start\n    \terr := modules.Start()\n    \tif err != nil {\n    \t\tif err == modules.ErrCleanExit {\n    \t\t\tos.Exit(0)\n    \t\t} else {\n    \t\t\tos.Exit(1)\n    \t\t}\n    \t}\n\n    \t// Shutdown\n    \t// catch interrupt for clean shutdown\n    \tsignalCh := make(chan os.Signal)\n    \tsignal.Notify(\n    \t\tsignalCh,\n    \t\tos.Interrupt,\n    \t\tsyscall.SIGHUP,\n    \t\tsyscall.SIGINT,\n    \t\tsyscall.SIGTERM,\n    \t\tsyscall.SIGQUIT,\n    \t)\n    \tselect {\n    \tcase <-signalCh:\n    \t\tlog.Warning(\"main: program was interrupted\")\n    \t\tmodules.Shutdown()\n    \tcase <-modules.ShuttingDown():\n    \t}\n\n    }\n"
  },
  {
    "path": "base/api/api_bridge.go",
    "content": "package api\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"path\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\nconst (\n\tendpointBridgeRemoteAddress = \"websocket-bridge\"\n\tapiDatabaseName             = \"api\"\n)\n\nfunc registerEndpointBridgeDB() error {\n\tif _, err := database.Register(&database.Database{\n\t\tName:        apiDatabaseName,\n\t\tDescription: \"API Bridge\",\n\t\tStorageType: \"injected\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\t_, err := database.InjectDatabase(\"api\", &endpointBridgeStorage{})\n\treturn err\n}\n\ntype endpointBridgeStorage struct {\n\tstorage.InjectBase\n}\n\n// EndpointBridgeRequest holds a bridged request API request.\ntype EndpointBridgeRequest struct {\n\trecord.Base\n\tsync.Mutex\n\n\tMethod   string\n\tPath     string\n\tQuery    map[string]string\n\tData     []byte\n\tMimeType string\n}\n\n// EndpointBridgeResponse holds a bridged request API response.\ntype EndpointBridgeResponse struct {\n\trecord.Base\n\tsync.Mutex\n\n\tMimeType string\n\tBody     string\n}\n\n// Get returns a database record.\nfunc (ebs *endpointBridgeStorage) Get(key string) (record.Record, error) {\n\tif key == \"\" {\n\t\treturn nil, database.ErrNotFound\n\t}\n\n\treturn callAPI(&EndpointBridgeRequest{\n\t\tMethod: http.MethodGet,\n\t\tPath:   key,\n\t})\n}\n\n// Get returns the metadata of a database record.\nfunc (ebs *endpointBridgeStorage) GetMeta(key string) (*record.Meta, error) {\n\t// This interface is an API, always return a fresh copy.\n\tm := &record.Meta{}\n\tm.Update()\n\treturn m, nil\n}\n\n// Put stores a record in the database.\nfunc (ebs *endpointBridgeStorage) Put(r record.Record) (record.Record, error) {\n\tif r.DatabaseKey() == \"\" {\n\t\treturn nil, database.ErrNotFound\n\t}\n\n\t// Prepare data.\n\tvar ebr *EndpointBridgeRequest\n\tif r.IsWrapped() {\n\t\t// Only allocate a new struct, if we need it.\n\t\tebr = &EndpointBridgeRequest{}\n\t\terr := record.Unwrap(r, ebr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tvar ok bool\n\t\tebr, ok = r.(*EndpointBridgeRequest)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"record not of type *EndpointBridgeRequest, but %T\", r)\n\t\t}\n\t}\n\n\t// Override path with key to mitigate sneaky stuff.\n\tebr.Path = r.DatabaseKey()\n\treturn callAPI(ebr)\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (ebs *endpointBridgeStorage) ReadOnly() bool {\n\treturn false\n}\n\nfunc callAPI(ebr *EndpointBridgeRequest) (record.Record, error) {\n\t// Add API prefix to path.\n\trequestURL := path.Join(apiV1Path, ebr.Path)\n\t// Check if path is correct. (Defense in depth)\n\tif !strings.HasPrefix(requestURL, apiV1Path) {\n\t\treturn nil, fmt.Errorf(\"bridged request for %q violates scope\", ebr.Path)\n\t}\n\n\t// Apply default Method.\n\tif ebr.Method == \"\" {\n\t\tif len(ebr.Data) > 0 {\n\t\t\tebr.Method = http.MethodPost\n\t\t} else {\n\t\t\tebr.Method = http.MethodGet\n\t\t}\n\t}\n\n\t// Build URL.\n\tu, err := url.ParseRequestURI(requestURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build bridged request url: %w\", err)\n\t}\n\t// Build query values.\n\tif ebr.Query != nil && len(ebr.Query) > 0 {\n\t\tquery := url.Values{}\n\t\tfor k, v := range ebr.Query {\n\t\t\tquery.Set(k, v)\n\t\t}\n\t\tu.RawQuery = query.Encode()\n\t}\n\n\t// Create request and response objects.\n\tr := httptest.NewRequest(ebr.Method, u.String(), bytes.NewBuffer(ebr.Data))\n\tr.RemoteAddr = endpointBridgeRemoteAddress\n\tif ebr.MimeType != \"\" {\n\t\tr.Header.Set(\"Content-Type\", ebr.MimeType)\n\t}\n\tw := httptest.NewRecorder()\n\t// Let the API handle the request.\n\tserver.Handler.ServeHTTP(w, r)\n\tswitch w.Code {\n\tcase 200:\n\t\t// Everything okay, continue.\n\tcase 500:\n\t\t// A Go error was returned internally.\n\t\t// We can safely return this as an error.\n\t\treturn nil, fmt.Errorf(\"bridged api call failed: %s\", w.Body.String())\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"bridged api call returned unexpected error code %d\", w.Code)\n\t}\n\n\tresponse := &EndpointBridgeResponse{\n\t\tMimeType: w.Header().Get(\"Content-Type\"),\n\t\tBody:     w.Body.String(),\n\t}\n\tresponse.SetKey(apiDatabaseName + \":\" + ebr.Path)\n\tresponse.UpdateMeta()\n\n\treturn response, nil\n}\n"
  },
  {
    "path": "base/api/auth_wrapper.go",
    "content": "package api\n\nimport \"net/http\"\n\n// WrapInAuthHandler wraps a simple http.HandlerFunc into a handler that\n// exposes the required API permissions for this handler.\nfunc WrapInAuthHandler(fn http.HandlerFunc, read, write Permission) http.Handler {\n\treturn &wrappedAuthenticatedHandler{\n\t\tHandlerFunc: fn,\n\t\tread:        read,\n\t\twrite:       write,\n\t}\n}\n\ntype wrappedAuthenticatedHandler struct {\n\thttp.HandlerFunc\n\n\tread  Permission\n\twrite Permission\n}\n\n// ReadPermission returns the read permission for the handler.\nfunc (wah *wrappedAuthenticatedHandler) ReadPermission(r *http.Request) Permission {\n\treturn wah.read\n}\n\n// WritePermission returns the write permission for the handler.\nfunc (wah *wrappedAuthenticatedHandler) WritePermission(r *http.Request) Permission {\n\treturn wah.write\n}\n"
  },
  {
    "path": "base/api/authentication.go",
    "content": "package api\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nconst (\n\tsessionCookieName = \"Portmaster-API-Token\"\n\tsessionCookieTTL  = 5 * time.Minute\n)\n\nvar (\n\tapiKeys     = make(map[string]*AuthToken)\n\tapiKeysLock sync.Mutex\n\n\tauthFnSet = abool.New()\n\tauthFn    AuthenticatorFunc\n\n\tsessions     = make(map[string]*session)\n\tsessionsLock sync.Mutex\n\n\t// ErrAPIAccessDeniedMessage should be wrapped by errors returned by\n\t// AuthenticatorFunc in order to signify a blocked request, including a error\n\t// message for the user. This is an empty message on purpose, as to allow the\n\t// function to define the full text of the error shown to the user.\n\tErrAPIAccessDeniedMessage = errors.New(\"\")\n)\n\n// Permission defines an API requests permission.\ntype Permission int8\n\nconst (\n\t// NotFound declares that the operation does not exist.\n\tNotFound Permission = -2\n\n\t// Dynamic declares that the operation requires permission to be processed,\n\t// but anyone can execute the operation, as it reacts to permissions itself.\n\tDynamic Permission = -1\n\n\t// NotSupported declares that the operation is not supported.\n\tNotSupported Permission = 0\n\n\t// PermitAnyone declares that anyone can execute the operation without any\n\t// authentication.\n\tPermitAnyone Permission = 1\n\n\t// PermitUser declares that the operation may be executed by authenticated\n\t// third party applications that are categorized as representing a simple\n\t// user and is limited in access.\n\tPermitUser Permission = 2\n\n\t// PermitAdmin declares that the operation may be executed by authenticated\n\t// third party applications that are categorized as representing an\n\t// administrator and has broad in access.\n\tPermitAdmin Permission = 3\n\n\t// PermitSelf declares that the operation may only be executed by the\n\t// software itself and its own (first party) components.\n\tPermitSelf Permission = 4\n)\n\n// AuthenticatorFunc is a function that can be set as the authenticator for the\n// API endpoint. If none is set, all requests will have full access.\n// The returned AuthToken represents the permissions that the request has.\ntype AuthenticatorFunc func(r *http.Request, s *http.Server) (*AuthToken, error)\n\n// AuthToken represents either a set of required or granted permissions.\n// All attributes must be set when the struct is built and must not be changed\n// later. Functions may be called at any time.\n// The Write permission implicitly also includes reading.\ntype AuthToken struct {\n\tRead       Permission\n\tWrite      Permission\n\tValidUntil *time.Time\n}\n\ntype session struct {\n\tsync.Mutex\n\n\ttoken      *AuthToken\n\tvalidUntil time.Time\n}\n\n// Expired returns whether the session has expired.\nfunc (sess *session) Expired() bool {\n\tsess.Lock()\n\tdefer sess.Unlock()\n\n\treturn time.Now().After(sess.validUntil)\n}\n\n// Refresh refreshes the validity of the session with the given TTL.\nfunc (sess *session) Refresh(ttl time.Duration) {\n\tsess.Lock()\n\tdefer sess.Unlock()\n\n\tsess.validUntil = time.Now().Add(ttl)\n}\n\n// AuthenticatedHandler defines the handler interface to specify custom\n// permission for an API handler. The returned permission is the required\n// permission for the request to proceed.\ntype AuthenticatedHandler interface {\n\tReadPermission(r *http.Request) Permission\n\tWritePermission(r *http.Request) Permission\n}\n\n// SetAuthenticator sets an authenticator function for the API endpoint. If none is set, all requests will be permitted.\nfunc SetAuthenticator(fn AuthenticatorFunc) error {\n\tif module.online.Load() {\n\t\treturn ErrAuthenticationImmutable\n\t}\n\n\tif !authFnSet.SetToIf(false, true) {\n\t\treturn ErrAuthenticationAlreadySet\n\t}\n\n\tauthFn = fn\n\treturn nil\n}\n\nfunc authenticateRequest(w http.ResponseWriter, r *http.Request, targetHandler http.Handler, readMethod bool) *AuthToken {\n\ttracer := log.Tracer(r.Context())\n\n\t// Get required permission for target handler.\n\trequiredPermission := PermitSelf\n\tif authdHandler, ok := targetHandler.(AuthenticatedHandler); ok {\n\t\tif readMethod {\n\t\t\trequiredPermission = authdHandler.ReadPermission(r)\n\t\t} else {\n\t\t\trequiredPermission = authdHandler.WritePermission(r)\n\t\t}\n\t}\n\n\t// Check if we need to do any authentication at all.\n\tswitch requiredPermission { //nolint:exhaustive\n\tcase NotFound:\n\t\t// Not found.\n\t\ttracer.Debug(\"api: no API endpoint registered for this path\")\n\t\thttp.Error(w, \"Not found.\", http.StatusNotFound)\n\t\treturn nil\n\tcase NotSupported:\n\t\t// A read or write permission can be marked as not supported.\n\t\ttracer.Trace(\"api: authenticated handler reported: not supported\")\n\t\thttp.Error(w, \"Method not allowed.\", http.StatusMethodNotAllowed)\n\t\treturn nil\n\tcase PermitAnyone:\n\t\t// Don't process permissions, as we don't need them.\n\t\ttracer.Tracef(\"api: granted %s access to public handler\", r.RemoteAddr)\n\t\treturn &AuthToken{\n\t\t\tRead:  PermitAnyone,\n\t\t\tWrite: PermitAnyone,\n\t\t}\n\tcase Dynamic:\n\t\t// Continue processing permissions, but treat as PermitAnyone.\n\t\trequiredPermission = PermitAnyone\n\t}\n\n\t// The required permission must match the request permission values after\n\t// handling the specials.\n\tif requiredPermission < PermitAnyone || requiredPermission > PermitSelf {\n\t\ttracer.Warningf(\n\t\t\t\"api: handler returned invalid permission: %s (%d)\",\n\t\t\trequiredPermission,\n\t\t\trequiredPermission,\n\t\t)\n\t\thttp.Error(w, \"Internal server error during authentication.\", http.StatusInternalServerError)\n\t\treturn nil\n\t}\n\n\t// Authenticate request.\n\ttoken, handled := checkAuth(w, r, requiredPermission > PermitAnyone)\n\tswitch {\n\tcase handled:\n\t\treturn nil\n\tcase token == nil:\n\t\t// Use default permissions.\n\t\ttoken = &AuthToken{\n\t\t\tRead:  PermitAnyone,\n\t\t\tWrite: PermitAnyone,\n\t\t}\n\t}\n\n\t// Get effective permission for request.\n\tvar requestPermission Permission\n\tif readMethod {\n\t\trequestPermission = token.Read\n\t} else {\n\t\trequestPermission = token.Write\n\t}\n\n\t// Check for valid request permission.\n\tif requestPermission < PermitAnyone || requestPermission > PermitSelf {\n\t\ttracer.Warningf(\n\t\t\t\"api: authenticator returned invalid permission: %s (%d)\",\n\t\t\trequestPermission,\n\t\t\trequestPermission,\n\t\t)\n\t\thttp.Error(w, \"Internal server error during authentication.\", http.StatusInternalServerError)\n\t\treturn nil\n\t}\n\n\t// Check permission.\n\tif requestPermission < requiredPermission {\n\t\t// If the token is strictly public, return an authentication request.\n\t\tif token.Read == PermitAnyone && token.Write == PermitAnyone {\n\t\t\tw.Header().Set(\n\t\t\t\t\"WWW-Authenticate\",\n\t\t\t\t`Bearer realm=\"Portmaster API\" domain=\"/\"`,\n\t\t\t)\n\t\t\thttp.Error(w, \"Authorization required.\", http.StatusUnauthorized)\n\t\t\treturn nil\n\t\t}\n\n\t\t// Otherwise just inform of insufficient permissions.\n\t\thttp.Error(w, \"Insufficient permissions.\", http.StatusForbidden)\n\t\treturn nil\n\t}\n\n\ttracer.Tracef(\"api: granted %s access to protected handler\", r.RemoteAddr)\n\n\t// Make a copy of the AuthToken in order mitigate the handler poisoning the\n\t// token, as changes would apply to future requests.\n\treturn &AuthToken{\n\t\tRead:  token.Read,\n\t\tWrite: token.Write,\n\t}\n}\n\nfunc checkAuth(w http.ResponseWriter, r *http.Request, authRequired bool) (token *AuthToken, handled bool) {\n\t// Return highest possible permissions in dev mode.\n\tif devMode() {\n\t\treturn &AuthToken{\n\t\t\tRead:  PermitSelf,\n\t\t\tWrite: PermitSelf,\n\t\t}, false\n\t}\n\n\t// Database Bridge Access.\n\tif r.RemoteAddr == endpointBridgeRemoteAddress {\n\t\treturn &AuthToken{\n\t\t\tRead:  dbCompatibilityPermission,\n\t\t\tWrite: dbCompatibilityPermission,\n\t\t}, false\n\t}\n\n\t// Check for valid API key.\n\ttoken = checkAPIKey(r)\n\tif token != nil {\n\t\treturn token, false\n\t}\n\n\t// Check for valid session cookie.\n\ttoken = checkSessionCookie(r)\n\tif token != nil {\n\t\treturn token, false\n\t}\n\n\t// Check if an external authentication method is available.\n\tif !authFnSet.IsSet() {\n\t\treturn nil, false\n\t}\n\n\t// Authenticate externally.\n\ttoken, err := authFn(r, server)\n\tif err != nil {\n\t\t// Check if the authentication process failed internally.\n\t\tif !errors.Is(err, ErrAPIAccessDeniedMessage) {\n\t\t\tlog.Tracer(r.Context()).Errorf(\"api: authenticator failed: %s\", err)\n\t\t\thttp.Error(w, \"Internal server error during authentication.\", http.StatusInternalServerError)\n\t\t\treturn nil, true\n\t\t}\n\n\t\t// Return authentication failure message if authentication is required.\n\t\tif authRequired {\n\t\t\tlog.Tracer(r.Context()).Warningf(\"api: denying api access from %s\", r.RemoteAddr)\n\t\t\thttp.Error(w, err.Error(), http.StatusForbidden)\n\t\t\treturn nil, true\n\t\t}\n\n\t\treturn nil, false\n\t}\n\n\t// Abort if no token is returned.\n\tif token == nil {\n\t\treturn nil, false\n\t}\n\n\t// Create session cookie for authenticated request.\n\terr = createSession(w, r, token)\n\tif err != nil {\n\t\tlog.Tracer(r.Context()).Warningf(\"api: failed to create session: %s\", err)\n\t}\n\treturn token, false\n}\n\nfunc checkAPIKey(r *http.Request) *AuthToken {\n\t// Get API key from request.\n\tkey := r.Header.Get(\"Authorization\")\n\tif key == \"\" {\n\t\treturn nil\n\t}\n\n\t// Parse API key.\n\tswitch {\n\tcase strings.HasPrefix(key, \"Bearer \"):\n\t\tkey = strings.TrimPrefix(key, \"Bearer \")\n\tcase strings.HasPrefix(key, \"Basic \"):\n\t\tuser, pass, _ := r.BasicAuth()\n\t\tkey = user + pass\n\tdefault:\n\t\tlog.Tracer(r.Context()).Tracef(\n\t\t\t\"api: provided api key type %s is unsupported\", strings.Split(key, \" \")[0],\n\t\t)\n\t\treturn nil\n\t}\n\n\tapiKeysLock.Lock()\n\tdefer apiKeysLock.Unlock()\n\n\t// Check if the provided API key exists.\n\ttoken, ok := apiKeys[key]\n\tif !ok {\n\t\tlog.Tracer(r.Context()).Tracef(\n\t\t\t\"api: provided api key %s... is unknown\", key[:4],\n\t\t)\n\t\treturn nil\n\t}\n\n\t// Abort if the token is expired.\n\tif token.ValidUntil != nil && time.Now().After(*token.ValidUntil) {\n\t\tlog.Tracer(r.Context()).Warningf(\"api: denying api access from %s using expired token\", r.RemoteAddr)\n\t\treturn nil\n\t}\n\n\treturn token\n}\n\nfunc updateAPIKeys() {\n\tapiKeysLock.Lock()\n\tdefer apiKeysLock.Unlock()\n\n\tlog.Debug(\"api: importing possibly updated API keys from config\")\n\n\t// Delete current keys.\n\tfor k := range apiKeys {\n\t\tdelete(apiKeys, k)\n\t}\n\n\t// whether or not we found expired API keys that should be removed\n\t// from the setting\n\thasExpiredKeys := false\n\n\t// a list of valid API keys. Used when hasExpiredKeys is set to true.\n\t// in that case we'll update the setting to only contain validAPIKeys\n\tvalidAPIKeys := []string{}\n\n\t// Parse new keys.\n\tfor _, key := range configuredAPIKeys() {\n\t\tu, err := url.Parse(key)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"api: failed to parse configured API key %s: %s\", key, err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif u.Path == \"\" {\n\t\t\tlog.Errorf(\"api: malformed API key %s: missing path section\", key)\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create token with default permissions.\n\t\ttoken := &AuthToken{\n\t\t\tRead:  PermitAnyone,\n\t\t\tWrite: PermitAnyone,\n\t\t}\n\n\t\t// Update with configured permissions.\n\t\tq := u.Query()\n\t\t// Parse read permission.\n\t\treadPermission, err := parseAPIPermission(q.Get(\"read\"))\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"api: invalid API key %s: %s\", key, err)\n\t\t\tcontinue\n\t\t}\n\t\ttoken.Read = readPermission\n\t\t// Parse write permission.\n\t\twritePermission, err := parseAPIPermission(q.Get(\"write\"))\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"api: invalid API key %s: %s\", key, err)\n\t\t\tcontinue\n\t\t}\n\t\ttoken.Write = writePermission\n\n\t\texpireStr := q.Get(\"expires\")\n\t\tif expireStr != \"\" {\n\t\t\tvalidUntil, err := time.Parse(time.RFC3339, expireStr)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(\"api: invalid API key %s: %s\", key, err)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// continue to the next token if this one is already invalid\n\t\t\tif time.Now().After(validUntil) {\n\t\t\t\t// mark the key as expired so we'll remove it from the setting afterwards\n\t\t\t\thasExpiredKeys = true\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttoken.ValidUntil = &validUntil\n\t\t}\n\n\t\t// Save token.\n\t\tapiKeys[u.Path] = token\n\t\tvalidAPIKeys = append(validAPIKeys, key)\n\t}\n\n\tif hasExpiredKeys {\n\t\tmodule.mgr.Go(\"api key cleanup\", func(ctx *mgr.WorkerCtx) error {\n\t\t\tif err := config.SetConfigOption(CfgAPIKeys, validAPIKeys); err != nil {\n\t\t\t\tlog.Errorf(\"api: failed to remove expired API keys: %s\", err)\n\t\t\t} else {\n\t\t\t\tlog.Infof(\"api: removed expired API keys from %s\", CfgAPIKeys)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\nfunc checkSessionCookie(r *http.Request) *AuthToken {\n\t// Get session cookie from request.\n\tc, err := r.Cookie(sessionCookieName)\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\t// Check if session cookie is registered.\n\tsessionsLock.Lock()\n\tsess, ok := sessions[c.Value]\n\tsessionsLock.Unlock()\n\tif !ok {\n\t\tlog.Tracer(r.Context()).Tracef(\"api: provided session cookie %s is unknown\", c.Value)\n\t\treturn nil\n\t}\n\n\t// Check if session is still valid.\n\tif sess.Expired() {\n\t\tlog.Tracer(r.Context()).Tracef(\"api: provided session cookie %s has expired\", c.Value)\n\t\treturn nil\n\t}\n\n\t// Refresh session and return.\n\tsess.Refresh(sessionCookieTTL)\n\tlog.Tracer(r.Context()).Tracef(\"api: session cookie %s is valid, refreshing\", c.Value)\n\treturn sess.token\n}\n\nfunc createSession(w http.ResponseWriter, r *http.Request, token *AuthToken) error {\n\t// Generate new session key.\n\tsecret, err := rng.Bytes(32) // 256 bit\n\tif err != nil {\n\t\treturn err\n\t}\n\tsessionKey := base64.RawURLEncoding.EncodeToString(secret)\n\n\t// Set token cookie in response.\n\thttp.SetCookie(w, &http.Cookie{\n\t\tName:     sessionCookieName,\n\t\tValue:    sessionKey,\n\t\tPath:     \"/\",\n\t\tHttpOnly: true,\n\t\tSameSite: http.SameSiteStrictMode,\n\t})\n\n\t// Create session.\n\tsess := &session{\n\t\ttoken: token,\n\t}\n\tsess.Refresh(sessionCookieTTL)\n\n\t// Save session.\n\tsessionsLock.Lock()\n\tdefer sessionsLock.Unlock()\n\tsessions[sessionKey] = sess\n\tlog.Tracer(r.Context()).Debug(\"api: issued session cookie\")\n\n\treturn nil\n}\n\nfunc cleanSessions(_ *mgr.WorkerCtx) error {\n\tsessionsLock.Lock()\n\tdefer sessionsLock.Unlock()\n\n\tfor sessionKey, sess := range sessions {\n\t\tif sess.Expired() {\n\t\t\tdelete(sessions, sessionKey)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc deleteSession(sessionKey string) {\n\tsessionsLock.Lock()\n\tdefer sessionsLock.Unlock()\n\n\tdelete(sessions, sessionKey)\n}\n\nfunc getEffectiveMethod(r *http.Request) (eMethod string, readMethod bool, ok bool) {\n\tmethod := r.Method\n\n\t// Get CORS request method if OPTIONS request.\n\tif r.Method == http.MethodOptions {\n\t\tmethod = r.Header.Get(\"Access-Control-Request-Method\")\n\t\tif method == \"\" {\n\t\t\treturn \"\", false, false\n\t\t}\n\t}\n\n\tswitch method {\n\tcase http.MethodGet, http.MethodHead:\n\t\treturn http.MethodGet, true, true\n\tcase http.MethodPost, http.MethodPut, http.MethodDelete:\n\t\treturn method, false, true\n\tdefault:\n\t\treturn \"\", false, false\n\t}\n}\n\nfunc parseAPIPermission(s string) (Permission, error) {\n\tswitch strings.ToLower(s) {\n\tcase \"\", \"anyone\":\n\t\treturn PermitAnyone, nil\n\tcase \"user\":\n\t\treturn PermitUser, nil\n\tcase \"admin\":\n\t\treturn PermitAdmin, nil\n\tdefault:\n\t\treturn PermitAnyone, fmt.Errorf(\"invalid permission: %s\", s)\n\t}\n}\n\nfunc (p Permission) String() string {\n\tswitch p {\n\tcase NotSupported:\n\t\treturn \"NotSupported\"\n\tcase Dynamic:\n\t\treturn \"Dynamic\"\n\tcase PermitAnyone:\n\t\treturn \"PermitAnyone\"\n\tcase PermitUser:\n\t\treturn \"PermitUser\"\n\tcase PermitAdmin:\n\t\treturn \"PermitAdmin\"\n\tcase PermitSelf:\n\t\treturn \"PermitSelf\"\n\tcase NotFound:\n\t\treturn \"NotFound\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\n// Role returns a string representation of the permission role.\nfunc (p Permission) Role() string {\n\tswitch p {\n\tcase PermitAnyone:\n\t\treturn \"Anyone\"\n\tcase PermitUser:\n\t\treturn \"User\"\n\tcase PermitAdmin:\n\t\treturn \"Admin\"\n\tcase PermitSelf:\n\t\treturn \"Self\"\n\tcase Dynamic, NotFound, NotSupported:\n\t\treturn \"Invalid\"\n\tdefault:\n\t\treturn \"Invalid\"\n\t}\n}\n"
  },
  {
    "path": "base/api/authentication_test.go",
    "content": "package api\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar testToken = new(AuthToken)\n\nfunc testAuthenticator(r *http.Request, s *http.Server) (*AuthToken, error) {\n\tswitch {\n\tcase testToken.Read == -127 || testToken.Write == -127:\n\t\treturn nil, errors.New(\"test error\")\n\tcase testToken.Read == -128 || testToken.Write == -128:\n\t\treturn nil, fmt.Errorf(\"%wdenied\", ErrAPIAccessDeniedMessage)\n\tdefault:\n\t\treturn testToken, nil\n\t}\n}\n\ntype testAuthHandler struct {\n\tRead  Permission\n\tWrite Permission\n}\n\nfunc (ah *testAuthHandler) ReadPermission(r *http.Request) Permission {\n\treturn ah.Read\n}\n\nfunc (ah *testAuthHandler) WritePermission(r *http.Request) Permission {\n\treturn ah.Write\n}\n\nfunc (ah *testAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\t// Check if request is as expected.\n\tar := GetAPIRequest(r)\n\tswitch {\n\tcase ar == nil:\n\t\thttp.Error(w, \"ar == nil\", http.StatusInternalServerError)\n\tcase ar.AuthToken == nil:\n\t\thttp.Error(w, \"ar.AuthToken == nil\", http.StatusInternalServerError)\n\tdefault:\n\t\thttp.Error(w, \"auth success\", http.StatusOK)\n\t}\n}\n\nfunc makeAuthTestPath(reading bool, p Permission) string {\n\tif reading {\n\t\treturn fmt.Sprintf(\"/test/auth/read/%s\", p)\n\t}\n\treturn fmt.Sprintf(\"/test/auth/write/%s\", p)\n}\n\nfunc TestPermissions(t *testing.T) {\n\tt.Parallel()\n\n\ttestHandler := &mainHandler{\n\t\tmux: mainMux,\n\t}\n\n\t// Define permissions that need testing.\n\tpermissionsToTest := []Permission{\n\t\tNotSupported,\n\t\tPermitAnyone,\n\t\tPermitUser,\n\t\tPermitAdmin,\n\t\tPermitSelf,\n\t\tDynamic,\n\t\tNotFound,\n\t\t100,  // Test a too high value.\n\t\t-100, // Test a too low value.\n\t\t-127, // Simulate authenticator failure.\n\t\t-128, // Simulate authentication denied message.\n\t}\n\n\t// Register test handlers.\n\tfor _, p := range permissionsToTest {\n\t\tRegisterHandler(makeAuthTestPath(true, p), &testAuthHandler{Read: p})\n\t\tRegisterHandler(makeAuthTestPath(false, p), &testAuthHandler{Write: p})\n\t}\n\n\t// Test all the combinations.\n\tfor _, requestPerm := range permissionsToTest {\n\t\tfor _, handlerPerm := range permissionsToTest {\n\t\t\tfor _, method := range []string{\n\t\t\t\thttp.MethodGet,\n\t\t\t\thttp.MethodHead,\n\t\t\t\thttp.MethodPost,\n\t\t\t\thttp.MethodPut,\n\t\t\t\thttp.MethodDelete,\n\t\t\t} {\n\n\t\t\t\t// Set request permission for test requests.\n\t\t\t\t_, reading, _ := getEffectiveMethod(&http.Request{Method: method})\n\t\t\t\tif reading {\n\t\t\t\t\ttestToken.Read = requestPerm\n\t\t\t\t\ttestToken.Write = NotSupported\n\t\t\t\t} else {\n\t\t\t\t\ttestToken.Read = NotSupported\n\t\t\t\t\ttestToken.Write = requestPerm\n\t\t\t\t}\n\n\t\t\t\t// Evaluate expected result.\n\t\t\t\tvar expectSuccess bool\n\t\t\t\tswitch {\n\t\t\t\tcase handlerPerm == PermitAnyone:\n\t\t\t\t\t// This is fast-tracked. There are not additional checks.\n\t\t\t\t\texpectSuccess = true\n\t\t\t\tcase handlerPerm == Dynamic:\n\t\t\t\t\t// This is turned into PermitAnyone in the authenticator.\n\t\t\t\t\t// But authentication is still processed and the result still gets\n\t\t\t\t\t// sanity checked!\n\t\t\t\t\tif requestPerm >= PermitAnyone &&\n\t\t\t\t\t\trequestPerm <= PermitSelf {\n\t\t\t\t\t\texpectSuccess = true\n\t\t\t\t\t}\n\t\t\t\t\t// Another special case is when the handler requires permission to be\n\t\t\t\t\t// processed but the authenticator fails to authenticate the request.\n\t\t\t\t\t// In this case, a fallback token with PermitAnyone is used.\n\t\t\t\t\tif requestPerm == -128 {\n\t\t\t\t\t\t// -128 is used to simulate a permission denied message.\n\t\t\t\t\t\texpectSuccess = true\n\t\t\t\t\t}\n\t\t\t\tcase handlerPerm <= NotSupported:\n\t\t\t\t\t// Invalid handler permission.\n\t\t\t\tcase handlerPerm > PermitSelf:\n\t\t\t\t\t// Invalid handler permission.\n\t\t\t\tcase requestPerm <= NotSupported:\n\t\t\t\t\t// Invalid request permission.\n\t\t\t\tcase requestPerm > PermitSelf:\n\t\t\t\t\t// Invalid request permission.\n\t\t\t\tcase requestPerm < handlerPerm:\n\t\t\t\t\t// Valid, but insufficient request permission.\n\t\t\t\tdefault:\n\t\t\t\t\texpectSuccess = true\n\t\t\t\t}\n\n\t\t\t\tif expectSuccess {\n\t\t\t\t\t// Test for success.\n\t\t\t\t\tif !assert.HTTPBodyContains(\n\t\t\t\t\t\tt,\n\t\t\t\t\t\ttestHandler.ServeHTTP,\n\t\t\t\t\t\tmethod,\n\t\t\t\t\t\tmakeAuthTestPath(reading, handlerPerm),\n\t\t\t\t\t\tnil,\n\t\t\t\t\t\t\"auth success\",\n\t\t\t\t\t) {\n\t\t\t\t\t\tt.Errorf(\n\t\t\t\t\t\t\t\"%s with %s (%d) to handler %s (%d)\",\n\t\t\t\t\t\t\tmethod,\n\t\t\t\t\t\t\trequestPerm, requestPerm,\n\t\t\t\t\t\t\thandlerPerm, handlerPerm,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Test for error.\n\t\t\t\t\tif !assert.HTTPError(t,\n\t\t\t\t\t\ttestHandler.ServeHTTP,\n\t\t\t\t\t\tmethod,\n\t\t\t\t\t\tmakeAuthTestPath(reading, handlerPerm),\n\t\t\t\t\t\tnil,\n\t\t\t\t\t) {\n\t\t\t\t\t\tt.Errorf(\n\t\t\t\t\t\t\t\"%s with %s (%d) to handler %s (%d)\",\n\t\t\t\t\t\t\tmethod,\n\t\t\t\t\t\t\trequestPerm, requestPerm,\n\t\t\t\t\t\t\thandlerPerm, handlerPerm,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestPermissionDefinitions(t *testing.T) {\n\tt.Parallel()\n\n\tif NotSupported != 0 {\n\t\tt.Fatalf(\"NotSupported must be zero, was %v\", NotSupported)\n\t}\n}\n"
  },
  {
    "path": "base/api/client/api.go",
    "content": "package client\n\n// Get sends a get command to the API.\nfunc (c *Client) Get(key string, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestGet, key, nil)\n\treturn op\n}\n\n// Query sends a query command to the API.\nfunc (c *Client) Query(query string, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestQuery, query, nil)\n\treturn op\n}\n\n// Sub sends a sub command to the API.\nfunc (c *Client) Sub(query string, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestSub, query, nil)\n\treturn op\n}\n\n// Qsub sends a qsub command to the API.\nfunc (c *Client) Qsub(query string, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestQsub, query, nil)\n\treturn op\n}\n\n// Create sends a create command to the API.\nfunc (c *Client) Create(key string, value interface{}, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestCreate, key, value)\n\treturn op\n}\n\n// Update sends an update command to the API.\nfunc (c *Client) Update(key string, value interface{}, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestUpdate, key, value)\n\treturn op\n}\n\n// Insert sends an insert command to the API.\nfunc (c *Client) Insert(key string, value interface{}, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestInsert, key, value)\n\treturn op\n}\n\n// Delete sends a delete command to the API.\nfunc (c *Client) Delete(key string, handleFunc func(*Message)) *Operation {\n\top := c.NewOperation(handleFunc)\n\top.Send(msgRequestDelete, key, nil)\n\treturn op\n}\n"
  },
  {
    "path": "base/api/client/client.go",
    "content": "package client\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst (\n\tbackOffTimer = 1 * time.Second\n\n\tofflineSignal uint8 = 0\n\tonlineSignal  uint8 = 1\n)\n\n// The Client enables easy interaction with the API.\ntype Client struct {\n\tsync.Mutex\n\n\tserver string\n\n\tonlineSignal   chan struct{}\n\tofflineSignal  chan struct{}\n\tshutdownSignal chan struct{}\n\tlastSignal     uint8\n\n\tsend   chan *Message\n\tresend chan *Message\n\trecv   chan *Message\n\n\toperations map[string]*Operation\n\tnextOpID   uint64\n\n\tlastError string\n}\n\n// NewClient returns a new Client.\nfunc NewClient(server string) *Client {\n\tc := &Client{\n\t\tserver:         server,\n\t\tonlineSignal:   make(chan struct{}),\n\t\tofflineSignal:  make(chan struct{}),\n\t\tshutdownSignal: make(chan struct{}),\n\t\tlastSignal:     offlineSignal,\n\t\tsend:           make(chan *Message, 100),\n\t\tresend:         make(chan *Message, 1),\n\t\trecv:           make(chan *Message, 100),\n\t\toperations:     make(map[string]*Operation),\n\t}\n\tgo c.handler()\n\treturn c\n}\n\n// Connect connects to the API once.\nfunc (c *Client) Connect() error {\n\tdefer c.signalOffline()\n\n\terr := c.wsConnect()\n\tif err != nil && err.Error() != c.lastError {\n\t\tlog.Errorf(\"client: error connecting to Portmaster: %s\", err)\n\t\tc.lastError = err.Error()\n\t}\n\treturn err\n}\n\n// StayConnected calls Connect again whenever the connection is lost.\nfunc (c *Client) StayConnected() {\n\tlog.Infof(\"client: connecting to Portmaster at %s\", c.server)\n\n\t_ = c.Connect()\n\tfor {\n\t\tselect {\n\t\tcase <-time.After(backOffTimer):\n\t\t\tlog.Infof(\"client: reconnecting...\")\n\t\t\t_ = c.Connect()\n\t\tcase <-c.shutdownSignal:\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Shutdown shuts the client down.\nfunc (c *Client) Shutdown() {\n\tselect {\n\tcase <-c.shutdownSignal:\n\tdefault:\n\t\tclose(c.shutdownSignal)\n\t}\n}\n\nfunc (c *Client) signalOnline() {\n\tc.Lock()\n\tdefer c.Unlock()\n\tif c.lastSignal == offlineSignal {\n\t\tlog.Infof(\"client: went online\")\n\t\tc.offlineSignal = make(chan struct{})\n\t\tclose(c.onlineSignal)\n\t\tc.lastSignal = onlineSignal\n\n\t\t// resend unsent request\n\t\tfor _, op := range c.operations {\n\t\t\tif op.resuscitationEnabled.IsSet() && op.request.sent != nil && op.request.sent.SetToIf(true, false) {\n\t\t\t\top.client.send <- op.request\n\t\t\t\tlog.Infof(\"client: resuscitated %s %s %s\", op.request.OpID, op.request.Type, op.request.Key)\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nfunc (c *Client) signalOffline() {\n\tc.Lock()\n\tdefer c.Unlock()\n\tif c.lastSignal == onlineSignal {\n\t\tlog.Infof(\"client: went offline\")\n\t\tc.onlineSignal = make(chan struct{})\n\t\tclose(c.offlineSignal)\n\t\tc.lastSignal = offlineSignal\n\n\t\t// signal offline status to operations\n\t\tfor _, op := range c.operations {\n\t\t\top.handle(&Message{\n\t\t\t\tOpID: op.ID,\n\t\t\t\tType: MsgOffline,\n\t\t\t})\n\t\t}\n\n\t}\n}\n\n// Online returns a closed channel read if the client is connected to the API.\nfunc (c *Client) Online() <-chan struct{} {\n\tc.Lock()\n\tdefer c.Unlock()\n\treturn c.onlineSignal\n}\n\n// Offline returns a closed channel read if the client is not connected to the API.\nfunc (c *Client) Offline() <-chan struct{} {\n\tc.Lock()\n\tdefer c.Unlock()\n\treturn c.offlineSignal\n}\n\nfunc (c *Client) handler() {\n\tfor {\n\t\tselect {\n\n\t\tcase m := <-c.recv:\n\n\t\t\tif m == nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tc.Lock()\n\t\t\top, ok := c.operations[m.OpID]\n\t\t\tc.Unlock()\n\n\t\t\tif ok {\n\t\t\t\tlog.Tracef(\"client: [%s] received %s msg: %s\", m.OpID, m.Type, m.Key)\n\t\t\t\top.handle(m)\n\t\t\t} else {\n\t\t\t\tlog.Tracef(\"client: received message for unknown operation %s\", m.OpID)\n\t\t\t}\n\n\t\tcase <-c.shutdownSignal:\n\t\t\treturn\n\n\t\t}\n\t}\n}\n\n// Operation represents a single operation by a client.\ntype Operation struct {\n\tID                   string\n\trequest              *Message\n\tclient               *Client\n\thandleFunc           func(*Message)\n\thandler              chan *Message\n\tresuscitationEnabled *abool.AtomicBool\n}\n\nfunc (op *Operation) handle(m *Message) {\n\tif op.handleFunc != nil {\n\t\top.handleFunc(m)\n\t} else {\n\t\tselect {\n\t\tcase op.handler <- m:\n\t\tdefault:\n\t\t\tlog.Warningf(\"client: handler channel of operation %s overflowed\", op.ID)\n\t\t}\n\t}\n}\n\n// Cancel the operation.\nfunc (op *Operation) Cancel() {\n\top.client.Lock()\n\tdefer op.client.Unlock()\n\tdelete(op.client.operations, op.ID)\n\tclose(op.handler)\n}\n\n// Send sends a request to the API.\nfunc (op *Operation) Send(command, text string, data interface{}) {\n\top.request = &Message{\n\t\tOpID:  op.ID,\n\t\tType:  command,\n\t\tKey:   text,\n\t\tValue: data,\n\t\tsent:  abool.NewBool(false),\n\t}\n\tlog.Tracef(\"client: [%s] sending %s msg: %s\", op.request.OpID, op.request.Type, op.request.Key)\n\top.client.send <- op.request\n}\n\n// EnableResuscitation will resend the request after reconnecting to the API.\nfunc (op *Operation) EnableResuscitation() {\n\top.resuscitationEnabled.Set()\n}\n\n// NewOperation returns a new operation.\nfunc (c *Client) NewOperation(handleFunc func(*Message)) *Operation {\n\tc.Lock()\n\tdefer c.Unlock()\n\n\tc.nextOpID++\n\top := &Operation{\n\t\tID:                   fmt.Sprintf(\"#%d\", c.nextOpID),\n\t\tclient:               c,\n\t\thandleFunc:           handleFunc,\n\t\thandler:              make(chan *Message, 100),\n\t\tresuscitationEnabled: abool.NewBool(false),\n\t}\n\tc.operations[op.ID] = op\n\treturn op\n}\n"
  },
  {
    "path": "base/api/client/const.go",
    "content": "package client\n\n// Message Types.\nconst (\n\tmsgRequestGet    = \"get\"\n\tmsgRequestQuery  = \"query\"\n\tmsgRequestSub    = \"sub\"\n\tmsgRequestQsub   = \"qsub\"\n\tmsgRequestCreate = \"create\"\n\tmsgRequestUpdate = \"update\"\n\tmsgRequestInsert = \"insert\"\n\tmsgRequestDelete = \"delete\"\n\n\tMsgOk      = \"ok\"\n\tMsgError   = \"error\"\n\tMsgDone    = \"done\"\n\tMsgSuccess = \"success\"\n\tMsgUpdate  = \"upd\"\n\tMsgNew     = \"new\"\n\tMsgDelete  = \"del\"\n\tMsgWarning = \"warning\"\n\n\tMsgOffline = \"offline\" // special message type for signaling the handler that the connection was lost\n\n\tapiSeperator = \"|\"\n)\n\nvar apiSeperatorBytes = []byte(apiSeperator)\n"
  },
  {
    "path": "base/api/client/message.go",
    "content": "package client\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// ErrMalformedMessage is returned when a malformed message was encountered.\nvar ErrMalformedMessage = errors.New(\"malformed message\")\n\n// Message is an API message.\ntype Message struct {\n\tOpID     string\n\tType     string\n\tKey      string\n\tRawValue []byte\n\tValue    interface{}\n\tsent     *abool.AtomicBool\n}\n\n// ParseMessage parses the given raw data and returns a Message.\nfunc ParseMessage(data []byte) (*Message, error) {\n\tparts := bytes.SplitN(data, apiSeperatorBytes, 4)\n\tif len(parts) < 2 {\n\t\treturn nil, ErrMalformedMessage\n\t}\n\n\tm := &Message{\n\t\tOpID: string(parts[0]),\n\t\tType: string(parts[1]),\n\t}\n\n\tswitch m.Type {\n\tcase MsgOk, MsgUpdate, MsgNew:\n\t\t// parse key and data\n\t\t//    127|ok|<key>|<data>\n\t\t//    127|upd|<key>|<data>\n\t\t//    127|new|<key>|<data>\n\t\tif len(parts) != 4 {\n\t\t\treturn nil, ErrMalformedMessage\n\t\t}\n\t\tm.Key = string(parts[2])\n\t\tm.RawValue = parts[3]\n\tcase MsgDelete:\n\t\t// parse key\n\t\t//    127|del|<key>\n\t\tif len(parts) != 3 {\n\t\t\treturn nil, ErrMalformedMessage\n\t\t}\n\t\tm.Key = string(parts[2])\n\tcase MsgWarning, MsgError:\n\t\t// parse message\n\t\t//    127|error|<message>\n\t\t//    127|warning|<message> // error with single record, operation continues\n\t\tif len(parts) != 3 {\n\t\t\treturn nil, ErrMalformedMessage\n\t\t}\n\t\tm.Key = string(parts[2])\n\tcase MsgDone, MsgSuccess:\n\t\t// nothing more to do\n\t\t//    127|success\n\t\t//    127|done\n\t}\n\n\treturn m, nil\n}\n\n// Pack serializes a message into a []byte slice.\nfunc (m *Message) Pack() ([]byte, error) {\n\tc := container.New([]byte(m.OpID), apiSeperatorBytes, []byte(m.Type))\n\n\tif m.Key != \"\" {\n\t\tc.Append(apiSeperatorBytes)\n\t\tc.Append([]byte(m.Key))\n\t\tif len(m.RawValue) > 0 {\n\t\t\tc.Append(apiSeperatorBytes)\n\t\t\tc.Append(m.RawValue)\n\t\t} else if m.Value != nil {\n\t\t\tvar err error\n\t\t\tm.RawValue, err = dsd.Dump(m.Value, dsd.JSON)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tc.Append(apiSeperatorBytes)\n\t\t\tc.Append(m.RawValue)\n\t\t}\n\t}\n\n\treturn c.CompileData(), nil\n}\n"
  },
  {
    "path": "base/api/client/websocket.go",
    "content": "package client\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\ntype wsState struct {\n\twsConn     *websocket.Conn\n\twg         sync.WaitGroup\n\tfailing    *abool.AtomicBool\n\tfailSignal chan struct{}\n}\n\nfunc (c *Client) wsConnect() error {\n\tstate := &wsState{\n\t\tfailing:    abool.NewBool(false),\n\t\tfailSignal: make(chan struct{}),\n\t}\n\n\tvar err error\n\tstate.wsConn, _, err = websocket.DefaultDialer.Dial(fmt.Sprintf(\"ws://%s/api/database/v1\", c.server), nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc.signalOnline()\n\n\tstate.wg.Add(2)\n\tgo c.wsReader(state)\n\tgo c.wsWriter(state)\n\n\t// wait for end of connection\n\tselect {\n\tcase <-state.failSignal:\n\tcase <-c.shutdownSignal:\n\t\tstate.Error(\"\")\n\t}\n\t_ = state.wsConn.Close()\n\tstate.wg.Wait()\n\n\treturn nil\n}\n\nfunc (c *Client) wsReader(state *wsState) {\n\tdefer state.wg.Done()\n\tfor {\n\t\t_, data, err := state.wsConn.ReadMessage()\n\t\tlog.Tracef(\"client: read message\")\n\t\tif err != nil {\n\t\t\tif !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {\n\t\t\t\tstate.Error(fmt.Sprintf(\"client: read error: %s\", err))\n\t\t\t} else {\n\t\t\t\tstate.Error(\"client: connection closed by server\")\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tlog.Tracef(\"client: received message: %s\", string(data))\n\t\tm, err := ParseMessage(data)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"client: failed to parse message: %s\", err)\n\t\t} else {\n\t\t\tselect {\n\t\t\tcase c.recv <- m:\n\t\t\tcase <-state.failSignal:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (c *Client) wsWriter(state *wsState) {\n\tdefer state.wg.Done()\n\tfor {\n\t\tselect {\n\t\tcase <-state.failSignal:\n\t\t\treturn\n\t\tcase m := <-c.resend:\n\t\t\tdata, err := m.Pack()\n\t\t\tif err == nil {\n\t\t\t\terr = state.wsConn.WriteMessage(websocket.BinaryMessage, data)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tstate.Error(fmt.Sprintf(\"client: write error: %s\", err))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.Tracef(\"client: sent message: %s\", string(data))\n\t\t\tif m.sent != nil {\n\t\t\t\tm.sent.Set()\n\t\t\t}\n\t\tcase m := <-c.send:\n\t\t\tdata, err := m.Pack()\n\t\t\tif err == nil {\n\t\t\t\terr = state.wsConn.WriteMessage(websocket.BinaryMessage, data)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tc.resend <- m\n\t\t\t\tstate.Error(fmt.Sprintf(\"client: write error: %s\", err))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlog.Tracef(\"client: sent message: %s\", string(data))\n\t\t\tif m.sent != nil {\n\t\t\t\tm.sent.Set()\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (state *wsState) Error(message string) {\n\tif state.failing.SetToIf(false, true) {\n\t\tclose(state.failSignal)\n\t\tif message != \"\" {\n\t\t\tlog.Warning(message)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/api/config.go",
    "content": "package api\n\nimport (\n\t\"flag\"\n\n\t\"github.com/safing/portmaster/base/config\"\n)\n\n// Config Keys.\nconst (\n\tCfgDefaultListenAddressKey = \"core/listenAddress\"\n\tCfgAPIKeys                 = \"core/apiKeys\"\n)\n\nvar (\n\tlistenAddressFlag    string\n\tlistenAddressConfig  config.StringOption\n\tdefaultListenAddress string\n\n\tconfiguredAPIKeys config.StringArrayOption\n\n\tdevMode config.BoolOption\n)\n\nfunc init() {\n\tflag.StringVar(\n\t\t&listenAddressFlag,\n\t\t\"api-address\",\n\t\t\"\",\n\t\t\"set api listen address; configuration is stronger\",\n\t)\n}\n\nfunc getDefaultListenAddress() string {\n\t// check if overridden\n\tif listenAddressFlag != \"\" {\n\t\treturn listenAddressFlag\n\t}\n\t// return internal default\n\treturn defaultListenAddress\n}\n\nfunc registerConfig() error {\n\terr := config.Register(&config.Option{\n\t\tName:            \"API Listen Address\",\n\t\tKey:             CfgDefaultListenAddressKey,\n\t\tDescription:     \"Defines the IP address and port on which the internal API listens.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelDeveloper,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tDefaultValue:    getDefaultListenAddress(),\n\t\tValidationRegex: \"^([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}:[0-9]{1,5}|\\\\[[:0-9A-Fa-f]+\\\\]:[0-9]{1,5})$\",\n\t\tRequiresRestart: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: 513,\n\t\t\tconfig.CategoryAnnotation:     \"Development\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tlistenAddressConfig = config.GetAsString(CfgDefaultListenAddressKey, getDefaultListenAddress())\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"API Keys\",\n\t\tKey:            CfgAPIKeys,\n\t\tDescription:    \"Define API keys for privileged access to the API. Every entry is a separate API key with respective permissions. Format is `<key>?read=<perm>&write=<perm>`. Permissions are `anyone`, `user` and `admin`, and may be omitted.\",\n\t\tSensitive:      true,\n\t\tOptType:        config.OptTypeStringArray,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: 514,\n\t\t\tconfig.CategoryAnnotation:     \"Development\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tconfiguredAPIKeys = config.GetAsStringArray(CfgAPIKeys, []string{})\n\n\tdevMode = config.Concurrent.GetAsBool(config.CfgDevModeKey, false)\n\n\treturn nil\n}\n\n// SetDefaultAPIListenAddress sets the default listen address for the API.\nfunc SetDefaultAPIListenAddress(address string) {\n\tdefaultListenAddress = address\n}\n"
  },
  {
    "path": "base/api/database.go",
    "content": "package api\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/tevino/abool\"\n\t\"github.com/tidwall/gjson\"\n\t\"github.com/tidwall/sjson\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n\t\"github.com/safing/structures/varint\"\n)\n\nconst (\n\tdbMsgTypeOk      = \"ok\"\n\tdbMsgTypeError   = \"error\"\n\tdbMsgTypeDone    = \"done\"\n\tdbMsgTypeSuccess = \"success\"\n\tdbMsgTypeUpd     = \"upd\"\n\tdbMsgTypeNew     = \"new\"\n\tdbMsgTypeDel     = \"del\"\n\tdbMsgTypeWarning = \"warning\"\n\n\tdbAPISeperator = \"|\"\n\temptyString    = \"\"\n)\n\nvar (\n\tdbAPISeperatorBytes       = []byte(dbAPISeperator)\n\tdbCompatibilityPermission = PermitAdmin\n)\n\nfunc init() {\n\tRegisterHandler(\"/api/database/v1\", WrapInAuthHandler(\n\t\tstartDatabaseWebsocketAPI,\n\t\t// Default to admin read/write permissions until the database gets support\n\t\t// for api permissions.\n\t\tdbCompatibilityPermission,\n\t\tdbCompatibilityPermission,\n\t))\n}\n\n// DatabaseAPI is a generic database API interface.\ntype DatabaseAPI struct {\n\tqueriesLock sync.Mutex\n\tqueries     map[string]*iterator.Iterator\n\n\tsubsLock sync.Mutex\n\tsubs     map[string]*database.Subscription\n\n\tshutdownSignal chan struct{}\n\tshuttingDown   *abool.AtomicBool\n\tdb             *database.Interface\n\n\tsendBytes func(data []byte)\n}\n\n// DatabaseWebsocketAPI is a database websocket API interface.\ntype DatabaseWebsocketAPI struct {\n\tDatabaseAPI\n\n\tsendQueue chan []byte\n\tconn      *websocket.Conn\n}\n\nfunc allowAnyOrigin(r *http.Request) bool {\n\treturn true\n}\n\n// CreateDatabaseAPI creates a new database interface.\nfunc CreateDatabaseAPI(sendFunction func(data []byte)) DatabaseAPI {\n\treturn DatabaseAPI{\n\t\tqueries:        make(map[string]*iterator.Iterator),\n\t\tsubs:           make(map[string]*database.Subscription),\n\t\tshutdownSignal: make(chan struct{}),\n\t\tshuttingDown:   abool.NewBool(false),\n\t\tdb:             database.NewInterface(nil),\n\t\tsendBytes:      sendFunction,\n\t}\n}\n\nfunc startDatabaseWebsocketAPI(w http.ResponseWriter, r *http.Request) {\n\tupgrader := websocket.Upgrader{\n\t\tCheckOrigin:     allowAnyOrigin,\n\t\tReadBufferSize:  1024,\n\t\tWriteBufferSize: 65536,\n\t}\n\twsConn, err := upgrader.Upgrade(w, r, nil)\n\tif err != nil {\n\t\terrMsg := fmt.Sprintf(\"could not upgrade: %s\", err)\n\t\tlog.Error(errMsg)\n\t\thttp.Error(w, errMsg, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tnewDBAPI := &DatabaseWebsocketAPI{\n\t\tDatabaseAPI: DatabaseAPI{\n\t\t\tqueries:        make(map[string]*iterator.Iterator),\n\t\t\tsubs:           make(map[string]*database.Subscription),\n\t\t\tshutdownSignal: make(chan struct{}),\n\t\t\tshuttingDown:   abool.NewBool(false),\n\t\t\tdb:             database.NewInterface(nil),\n\t\t},\n\n\t\tsendQueue: make(chan []byte, 100),\n\t\tconn:      wsConn,\n\t}\n\n\tnewDBAPI.sendBytes = func(data []byte) {\n\t\tnewDBAPI.sendQueue <- data\n\t}\n\n\tmodule.mgr.Go(\"database api handler\", newDBAPI.handler)\n\tmodule.mgr.Go(\"database api writer\", newDBAPI.writer)\n\n\tlog.Tracer(r.Context()).Infof(\"api request: init websocket %s %s\", r.RemoteAddr, r.RequestURI)\n}\n\nfunc (api *DatabaseWebsocketAPI) handler(_ *mgr.WorkerCtx) error {\n\tdefer func() {\n\t\t_ = api.shutdown(nil)\n\t}()\n\n\tfor {\n\t\t_, msg, err := api.conn.ReadMessage()\n\t\tif err != nil {\n\t\t\treturn api.shutdown(err)\n\t\t}\n\n\t\tapi.Handle(msg)\n\t}\n}\n\nfunc (api *DatabaseWebsocketAPI) writer(ctx *mgr.WorkerCtx) error {\n\tdefer func() {\n\t\t_ = api.shutdown(nil)\n\t}()\n\n\tvar data []byte\n\tvar err error\n\n\tfor {\n\t\tselect {\n\t\t// prioritize direct writes\n\t\tcase data = <-api.sendQueue:\n\t\t\tif len(data) == 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-api.shutdownSignal:\n\t\t\treturn nil\n\t\t}\n\n\t\t// log.Tracef(\"api: sending %s\", string(*msg))\n\t\terr = api.conn.WriteMessage(websocket.BinaryMessage, data)\n\t\tif err != nil {\n\t\t\treturn api.shutdown(err)\n\t\t}\n\t}\n}\n\nfunc (api *DatabaseWebsocketAPI) shutdown(err error) error {\n\t// Check if we are the first to shut down.\n\tif !api.shuttingDown.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Check the given error.\n\tif err != nil {\n\t\tif websocket.IsCloseError(err,\n\t\t\twebsocket.CloseNormalClosure,\n\t\t\twebsocket.CloseGoingAway,\n\t\t\twebsocket.CloseAbnormalClosure,\n\t\t) {\n\t\t\tlog.Infof(\"api: websocket connection to %s closed\", api.conn.RemoteAddr())\n\t\t} else {\n\t\t\tlog.Warningf(\"api: websocket connection error with %s: %s\", api.conn.RemoteAddr(), err)\n\t\t}\n\t}\n\n\t// Trigger shutdown.\n\tclose(api.shutdownSignal)\n\t_ = api.conn.Close()\n\treturn nil\n}\n\n// Handle handles a message for the database API.\nfunc (api *DatabaseAPI) Handle(msg []byte) {\n\t// 123|get|<key>\n\t//    123|ok|<key>|<data>\n\t//    123|error|<message>\n\t// 124|query|<query>\n\t//    124|ok|<key>|<data>\n\t//    124|done\n\t//    124|error|<message>\n\t//    124|warning|<message> // error with single record, operation continues\n\t// 124|cancel\n\t// 125|sub|<query>\n\t//    125|upd|<key>|<data>\n\t//    125|new|<key>|<data>\n\t//    127|del|<key>\n\t//    125|warning|<message> // error with single record, operation continues\n\t// 125|cancel\n\t// 127|qsub|<query>\n\t//    127|ok|<key>|<data>\n\t//    127|done\n\t//    127|error|<message>\n\t//    127|upd|<key>|<data>\n\t//    127|new|<key>|<data>\n\t//    127|del|<key>\n\t//    127|warning|<message> // error with single record, operation continues\n\t// 127|cancel\n\n\t// 128|create|<key>|<data>\n\t//    128|success\n\t//    128|error|<message>\n\t// 129|update|<key>|<data>\n\t//    129|success\n\t//    129|error|<message>\n\t// 130|insert|<key>|<data>\n\t//    130|success\n\t//    130|error|<message>\n\t// 131|delete|<key>\n\t//    131|success\n\t//    131|error|<message>\n\n\tparts := bytes.SplitN(msg, []byte(\"|\"), 3)\n\n\t// Handle special command \"cancel\"\n\tif len(parts) == 2 && string(parts[1]) == \"cancel\" {\n\t\t// 124|cancel\n\t\t// 125|cancel\n\t\t// 127|cancel\n\t\tgo api.handleCancel(parts[0])\n\t\treturn\n\t}\n\n\tif len(parts) != 3 {\n\t\tapi.send(nil, dbMsgTypeError, \"bad request: malformed message\", nil)\n\t\treturn\n\t}\n\n\tswitch string(parts[1]) {\n\tcase \"get\":\n\t\t// 123|get|<key>\n\t\tgo api.handleGet(parts[0], string(parts[2]))\n\tcase \"query\":\n\t\t// 124|query|<query>\n\t\tgo api.handleQuery(parts[0], string(parts[2]))\n\tcase \"sub\":\n\t\t// 125|sub|<query>\n\t\tgo api.handleSub(parts[0], string(parts[2]))\n\tcase \"qsub\":\n\t\t// 127|qsub|<query>\n\t\tgo api.handleQsub(parts[0], string(parts[2]))\n\tcase \"create\", \"update\", \"insert\":\n\t\t// split key and payload\n\t\tdataParts := bytes.SplitN(parts[2], []byte(\"|\"), 2)\n\t\tif len(dataParts) != 2 {\n\t\t\tapi.send(nil, dbMsgTypeError, \"bad request: malformed message\", nil)\n\t\t\treturn\n\t\t}\n\n\t\tswitch string(parts[1]) {\n\t\tcase \"create\":\n\t\t\t// 128|create|<key>|<data>\n\t\t\tgo api.handlePut(parts[0], string(dataParts[0]), dataParts[1], true)\n\t\tcase \"update\":\n\t\t\t// 129|update|<key>|<data>\n\t\t\tgo api.handlePut(parts[0], string(dataParts[0]), dataParts[1], false)\n\t\tcase \"insert\":\n\t\t\t// 130|insert|<key>|<data>\n\t\t\tgo api.handleInsert(parts[0], string(dataParts[0]), dataParts[1])\n\t\t}\n\tcase \"delete\":\n\t\t// 131|delete|<key>\n\t\tgo api.handleDelete(parts[0], string(parts[2]))\n\tdefault:\n\t\tapi.send(parts[0], dbMsgTypeError, \"bad request: unknown method\", nil)\n\t}\n}\n\nfunc (api *DatabaseAPI) send(opID []byte, msgType string, msgOrKey string, data []byte) {\n\tc := container.New(opID)\n\tc.Append(dbAPISeperatorBytes)\n\tc.Append([]byte(msgType))\n\n\tif msgOrKey != emptyString {\n\t\tc.Append(dbAPISeperatorBytes)\n\t\tc.Append([]byte(msgOrKey))\n\t}\n\n\tif len(data) > 0 {\n\t\tc.Append(dbAPISeperatorBytes)\n\t\tc.Append(data)\n\t}\n\n\tapi.sendBytes(c.CompileData())\n}\n\nfunc (api *DatabaseAPI) handleGet(opID []byte, key string) {\n\t// 123|get|<key>\n\t//    123|ok|<key>|<data>\n\t//    123|error|<message>\n\n\tvar data []byte\n\n\tr, err := api.db.Get(key)\n\tif err == nil {\n\t\tdata, err = MarshalRecord(r, true)\n\t}\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\tapi.send(opID, dbMsgTypeOk, r.Key(), data)\n}\n\nfunc (api *DatabaseAPI) handleQuery(opID []byte, queryText string) {\n\t// 124|query|<query>\n\t//    124|ok|<key>|<data>\n\t//    124|done\n\t//    124|warning|<message>\n\t//    124|error|<message>\n\t//    124|warning|<message> // error with single record, operation continues\n\t// 124|cancel\n\n\tvar err error\n\n\tq, err := query.ParseQuery(queryText)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\n\tapi.processQuery(opID, q)\n}\n\nfunc (api *DatabaseAPI) processQuery(opID []byte, q *query.Query) (ok bool) {\n\tit, err := api.db.Query(q)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn false\n\t}\n\n\t// Save query iterator.\n\tapi.queriesLock.Lock()\n\tapi.queries[string(opID)] = it\n\tapi.queriesLock.Unlock()\n\n\t// Remove query iterator after it ended.\n\tdefer func() {\n\t\tapi.queriesLock.Lock()\n\t\tdefer api.queriesLock.Unlock()\n\t\tdelete(api.queries, string(opID))\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-api.shutdownSignal:\n\t\t\t// cancel query and return\n\t\t\tit.Cancel()\n\t\t\treturn false\n\t\tcase r := <-it.Next:\n\t\t\t// process query feed\n\t\t\tif r != nil {\n\t\t\t\t// process record\n\t\t\t\tdata, err := MarshalRecord(r, true)\n\t\t\t\tif err != nil {\n\t\t\t\t\tapi.send(opID, dbMsgTypeWarning, err.Error(), nil)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tapi.send(opID, dbMsgTypeOk, r.Key(), data)\n\t\t\t} else {\n\t\t\t\t// sub feed ended\n\t\t\t\tif it.Err() != nil {\n\t\t\t\t\tapi.send(opID, dbMsgTypeError, it.Err().Error(), nil)\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tapi.send(opID, dbMsgTypeDone, emptyString, nil)\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n}\n\n// func (api *DatabaseWebsocketAPI) runQuery()\n\nfunc (api *DatabaseAPI) handleSub(opID []byte, queryText string) {\n\t// 125|sub|<query>\n\t//    125|upd|<key>|<data>\n\t//    125|new|<key>|<data>\n\t//    125|delete|<key>\n\t//    125|warning|<message> // error with single record, operation continues\n\t// 125|cancel\n\tvar err error\n\n\tq, err := query.ParseQuery(queryText)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\n\tsub, ok := api.registerSub(opID, q)\n\tif !ok {\n\t\treturn\n\t}\n\tapi.processSub(opID, sub)\n}\n\nfunc (api *DatabaseAPI) registerSub(opID []byte, q *query.Query) (sub *database.Subscription, ok bool) {\n\tvar err error\n\tsub, err = api.db.Subscribe(q)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn nil, false\n\t}\n\n\treturn sub, true\n}\n\nfunc (api *DatabaseAPI) processSub(opID []byte, sub *database.Subscription) {\n\t// Save subscription.\n\tapi.subsLock.Lock()\n\tapi.subs[string(opID)] = sub\n\tapi.subsLock.Unlock()\n\n\t// Remove subscription after it ended.\n\tdefer func() {\n\t\tapi.subsLock.Lock()\n\t\tdefer api.subsLock.Unlock()\n\t\tdelete(api.subs, string(opID))\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-api.shutdownSignal:\n\t\t\t// cancel sub and return\n\t\t\t_ = sub.Cancel()\n\t\t\treturn\n\t\tcase r := <-sub.Feed:\n\t\t\t// process sub feed\n\t\t\tif r != nil {\n\t\t\t\t// process record\n\t\t\t\tdata, err := MarshalRecord(r, true)\n\t\t\t\tif err != nil {\n\t\t\t\t\tapi.send(opID, dbMsgTypeWarning, err.Error(), nil)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// TODO: use upd, new and delete msgTypes\n\t\t\t\tr.Lock()\n\t\t\t\tisDeleted := r.Meta().IsDeleted()\n\t\t\t\tisNew := r.Meta().Created == r.Meta().Modified\n\t\t\t\tr.Unlock()\n\t\t\t\tswitch {\n\t\t\t\tcase isDeleted:\n\t\t\t\t\tapi.send(opID, dbMsgTypeDel, r.Key(), nil)\n\t\t\t\tcase isNew:\n\t\t\t\t\tapi.send(opID, dbMsgTypeNew, r.Key(), data)\n\t\t\t\tdefault:\n\t\t\t\t\tapi.send(opID, dbMsgTypeUpd, r.Key(), data)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// sub feed ended\n\t\t\t\tapi.send(opID, dbMsgTypeDone, \"\", nil)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (api *DatabaseAPI) handleQsub(opID []byte, queryText string) {\n\t// 127|qsub|<query>\n\t//    127|ok|<key>|<data>\n\t//    127|done\n\t//    127|error|<message>\n\t//    127|upd|<key>|<data>\n\t//    127|new|<key>|<data>\n\t//    127|delete|<key>\n\t//    127|warning|<message> // error with single record, operation continues\n\t// 127|cancel\n\n\tvar err error\n\n\tq, err := query.ParseQuery(queryText)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\n\tsub, ok := api.registerSub(opID, q)\n\tif !ok {\n\t\treturn\n\t}\n\tok = api.processQuery(opID, q)\n\tif !ok {\n\t\treturn\n\t}\n\tapi.processSub(opID, sub)\n}\n\nfunc (api *DatabaseAPI) handleCancel(opID []byte) {\n\tapi.cancelQuery(opID)\n\tapi.cancelSub(opID)\n}\n\nfunc (api *DatabaseAPI) cancelQuery(opID []byte) {\n\tapi.queriesLock.Lock()\n\tdefer api.queriesLock.Unlock()\n\n\t// Get subscription from api.\n\tit, ok := api.queries[string(opID)]\n\tif !ok {\n\t\t// Fail silently as quries end by themselves when finished.\n\t\treturn\n\t}\n\n\t// End query.\n\tit.Cancel()\n\n\t// The query handler will end the communication with a done message.\n}\n\nfunc (api *DatabaseAPI) cancelSub(opID []byte) {\n\tapi.subsLock.Lock()\n\tdefer api.subsLock.Unlock()\n\n\t// Get subscription from api.\n\tsub, ok := api.subs[string(opID)]\n\tif !ok {\n\t\tapi.send(opID, dbMsgTypeError, \"could not find subscription\", nil)\n\t\treturn\n\t}\n\n\t// End subscription.\n\terr := sub.Cancel()\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, fmt.Sprintf(\"failed to cancel subscription: %s\", err), nil)\n\t}\n\n\t// The subscription handler will end the communication with a done message.\n}\n\nfunc (api *DatabaseAPI) handlePut(opID []byte, key string, data []byte, create bool) {\n\t// 128|create|<key>|<data>\n\t//    128|success\n\t//    128|error|<message>\n\n\t// 129|update|<key>|<data>\n\t//    129|success\n\t//    129|error|<message>\n\n\tif len(data) < 2 {\n\t\tapi.send(opID, dbMsgTypeError, \"bad request: malformed message\", nil)\n\t\treturn\n\t}\n\n\t// TODO - staged for deletion: remove transition code\n\t// if data[0] != dsd.JSON {\n\t// \ttypedData := make([]byte, len(data)+1)\n\t// \ttypedData[0] = dsd.JSON\n\t// \tcopy(typedData[1:], data)\n\t// \tdata = typedData\n\t// }\n\n\tr, err := record.NewWrapper(key, nil, data[0], data[1:])\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\n\tif create {\n\t\terr = api.db.PutNew(r)\n\t} else {\n\t\terr = api.db.Put(r)\n\t}\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\tapi.send(opID, dbMsgTypeSuccess, emptyString, nil)\n}\n\nfunc (api *DatabaseAPI) handleInsert(opID []byte, key string, data []byte) {\n\t// 130|insert|<key>|<data>\n\t//    130|success\n\t//    130|error|<message>\n\n\tr, err := api.db.Get(key)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\n\tacc := r.GetAccessor(r)\n\n\tresult := gjson.ParseBytes(data)\n\tanythingPresent := false\n\tvar insertError error\n\tresult.ForEach(func(key gjson.Result, value gjson.Result) bool {\n\t\tanythingPresent = true\n\t\tif !key.Exists() {\n\t\t\tinsertError = errors.New(\"values must be in a map\")\n\t\t\treturn false\n\t\t}\n\t\tif key.Type != gjson.String {\n\t\t\tinsertError = errors.New(\"keys must be strings\")\n\t\t\treturn false\n\t\t}\n\t\tif !value.Exists() {\n\t\t\tinsertError = errors.New(\"non-existent value\")\n\t\t\treturn false\n\t\t}\n\t\tinsertError = acc.Set(key.String(), value.Value())\n\t\treturn insertError == nil\n\t})\n\n\tif insertError != nil {\n\t\tapi.send(opID, dbMsgTypeError, insertError.Error(), nil)\n\t\treturn\n\t}\n\tif !anythingPresent {\n\t\tapi.send(opID, dbMsgTypeError, \"could not find any valid values\", nil)\n\t\treturn\n\t}\n\n\terr = api.db.Put(r)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\n\tapi.send(opID, dbMsgTypeSuccess, emptyString, nil)\n}\n\nfunc (api *DatabaseAPI) handleDelete(opID []byte, key string) {\n\t// 131|delete|<key>\n\t//    131|success\n\t//    131|error|<message>\n\n\terr := api.db.Delete(key)\n\tif err != nil {\n\t\tapi.send(opID, dbMsgTypeError, err.Error(), nil)\n\t\treturn\n\t}\n\tapi.send(opID, dbMsgTypeSuccess, emptyString, nil)\n}\n\n// MarshalRecord locks and marshals the given record, additionally adding\n// metadata and returning it as json.\nfunc MarshalRecord(r record.Record, withDSDIdentifier bool) ([]byte, error) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\t// Pour record into JSON.\n\tjsonData, err := r.Marshal(r, dsd.JSON)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Remove JSON identifier for manual editing.\n\tjsonData = bytes.TrimPrefix(jsonData, varint.Pack8(dsd.JSON))\n\n\t// Add metadata.\n\tjsonData, err = sjson.SetBytes(jsonData, \"_meta\", r.Meta())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Add database key.\n\tjsonData, err = sjson.SetBytes(jsonData, \"_meta.Key\", r.Key())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Add JSON identifier again.\n\tif withDSDIdentifier {\n\t\tformatID := varint.Pack8(dsd.JSON)\n\t\tfinalData := make([]byte, 0, len(formatID)+len(jsonData))\n\t\tfinalData = append(finalData, formatID...)\n\t\tfinalData = append(finalData, jsonData...)\n\t\treturn finalData, nil\n\t}\n\treturn jsonData, nil\n}\n"
  },
  {
    "path": "base/api/doc.go",
    "content": "/*\nPackage api provides an API for integration with other components of the same software package and also third party components.\n\nIt provides direct database access as well as a simpler way to register API endpoints. You can of course also register raw `http.Handler`s directly.\n\nOptional authentication guards registered handlers. This is achieved by attaching functions to the `http.Handler`s that are registered, which allow them to specify the required permissions for the handler.\n\nThe permissions are divided into the roles and assume a single user per host. The Roles are User, Admin and Self. User roles are expected to have mostly read access and react to notifications or system events, like a system tray program. The Admin role is meant for advanced components that also change settings, but are restricted so they cannot break the software. Self is reserved for internal use with full access.\n*/\npackage api\n"
  },
  {
    "path": "base/api/endpoints.go",
    "content": "package api\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// Endpoint describes an API Endpoint.\n// Path and at least one permission are required.\n// As is exactly one function.\ntype Endpoint struct { //nolint:maligned\n\t// Name is the human reabable name of the endpoint.\n\tName string\n\t// Description is the human readable description and documentation of the endpoint.\n\tDescription string\n\t// Parameters is the parameter documentation.\n\tParameters []Parameter `json:\",omitempty\"`\n\n\t// Path describes the URL path of the endpoint.\n\tPath string\n\n\t// MimeType defines the content type of the returned data.\n\tMimeType string\n\n\t// Read defines the required read permission.\n\tRead Permission `json:\",omitempty\"`\n\n\t// ReadMethod sets the required read method for the endpoint.\n\t// Available methods are:\n\t// GET: Returns data only, no action is taken, nothing is changed.\n\t// If omitted, defaults to GET.\n\t//\n\t// This field is currently being introduced and will only warn and not deny\n\t// access if the write method does not match.\n\tReadMethod string `json:\",omitempty\"`\n\n\t// Write defines the required write permission.\n\tWrite Permission `json:\",omitempty\"`\n\n\t// WriteMethod sets the required write method for the endpoint.\n\t// Available methods are:\n\t// POST: Create a new resource; Change a status; Execute a function\n\t// PUT: Update an existing resource\n\t// DELETE: Remove an existing resource\n\t// If omitted, defaults to POST.\n\t//\n\t// This field is currently being introduced and will only warn and not deny\n\t// access if the write method does not match.\n\tWriteMethod string `json:\",omitempty\"`\n\n\t// ActionFunc is for simple actions with a return message for the user.\n\tActionFunc ActionFunc `json:\"-\"`\n\n\t// DataFunc is for returning raw data that the caller for further processing.\n\tDataFunc DataFunc `json:\"-\"`\n\n\t// StructFunc is for returning any kind of struct.\n\tStructFunc StructFunc `json:\"-\"`\n\n\t// RecordFunc is for returning a database record. It will be properly locked\n\t// and marshalled including metadata.\n\tRecordFunc RecordFunc `json:\"-\"`\n\n\t// HandlerFunc is the raw http handler.\n\tHandlerFunc http.HandlerFunc `json:\"-\"`\n}\n\n// Parameter describes a parameterized variation of an endpoint.\ntype Parameter struct {\n\tMethod      string\n\tField       string\n\tValue       string\n\tDescription string\n}\n\n// HTTPStatusProvider is an interface for errors to provide a custom HTTP\n// status code.\ntype HTTPStatusProvider interface {\n\tHTTPStatus() int\n}\n\n// HTTPStatusError represents an error with an HTTP status code.\ntype HTTPStatusError struct {\n\terr  error\n\tcode int\n}\n\n// Error returns the error message.\nfunc (e *HTTPStatusError) Error() string {\n\treturn e.err.Error()\n}\n\n// Unwrap return the wrapped error.\nfunc (e *HTTPStatusError) Unwrap() error {\n\treturn e.err\n}\n\n// HTTPStatus returns the HTTP status code this error.\nfunc (e *HTTPStatusError) HTTPStatus() int {\n\treturn e.code\n}\n\n// ErrorWithStatus adds the HTTP status code to the error.\nfunc ErrorWithStatus(err error, code int) error {\n\treturn &HTTPStatusError{\n\t\terr:  err,\n\t\tcode: code,\n\t}\n}\n\ntype (\n\t// ActionFunc is for simple actions with a return message for the user.\n\tActionFunc func(ar *Request) (msg string, err error)\n\n\t// DataFunc is for returning raw data that the caller for further processing.\n\tDataFunc func(ar *Request) (data []byte, err error)\n\n\t// StructFunc is for returning any kind of struct.\n\tStructFunc func(ar *Request) (i interface{}, err error)\n\n\t// RecordFunc is for returning a database record. It will be properly locked\n\t// and marshalled including metadata.\n\tRecordFunc func(ar *Request) (r record.Record, err error)\n)\n\n// MIME Types.\nconst (\n\tMimeTypeJSON string = \"application/json\"\n\tMimeTypeText string = \"text/plain\"\n\n\tapiV1Path = \"/api/v1/\"\n)\n\nfunc init() {\n\tRegisterHandler(apiV1Path+\"{endpointPath:.+}\", &endpointHandler{})\n}\n\nvar (\n\tendpoints     = make(map[string]*Endpoint)\n\tendpointsMux  = mux.NewRouter()\n\tendpointsLock sync.RWMutex\n\n\t// ErrInvalidEndpoint is returned when an invalid endpoint is registered.\n\tErrInvalidEndpoint = errors.New(\"endpoint is invalid\")\n\n\t// ErrAlreadyRegistered is returned when there already is an endpoint with\n\t// the same path registered.\n\tErrAlreadyRegistered = errors.New(\"an endpoint for this path is already registered\")\n)\n\nfunc getAPIContext(r *http.Request) (apiEndpoint *Endpoint, apiRequest *Request) {\n\t// Get request context and check if we already have an action cached.\n\tapiRequest = GetAPIRequest(r)\n\tif apiRequest == nil {\n\t\treturn nil, nil\n\t}\n\tvar ok bool\n\tapiEndpoint, ok = apiRequest.HandlerCache.(*Endpoint)\n\tif ok {\n\t\treturn apiEndpoint, apiRequest\n\t}\n\n\tendpointsLock.RLock()\n\tdefer endpointsLock.RUnlock()\n\n\t// Get handler for request.\n\t// Gorilla does not support handling this on our own very well.\n\t// See github.com/gorilla/mux.ServeHTTP for reference.\n\tvar match mux.RouteMatch\n\tvar handler http.Handler\n\tif endpointsMux.Match(r, &match) {\n\t\thandler = match.Handler\n\t\tapiRequest.Route = match.Route\n\t\t// Add/Override variables instead of replacing.\n\t\tfor k, v := range match.Vars {\n\t\t\tapiRequest.URLVars[k] = v\n\t\t}\n\t} else {\n\t\treturn nil, apiRequest\n\t}\n\n\tapiEndpoint, ok = handler.(*Endpoint)\n\tif ok {\n\t\t// Cache for next operation.\n\t\tapiRequest.HandlerCache = apiEndpoint\n\t}\n\treturn apiEndpoint, apiRequest\n}\n\n// RegisterEndpoint registers a new endpoint. An error will be returned if it\n// does not pass the sanity checks.\nfunc RegisterEndpoint(e Endpoint) error {\n\tif err := e.check(); err != nil {\n\t\treturn fmt.Errorf(\"%w: %w\", ErrInvalidEndpoint, err)\n\t}\n\n\tendpointsLock.Lock()\n\tdefer endpointsLock.Unlock()\n\n\t_, ok := endpoints[e.Path]\n\tif ok {\n\t\treturn ErrAlreadyRegistered\n\t}\n\n\tendpoints[e.Path] = &e\n\tendpointsMux.Handle(apiV1Path+e.Path, &e)\n\treturn nil\n}\n\n// GetEndpointByPath returns the endpoint registered with the given path.\nfunc GetEndpointByPath(path string) (*Endpoint, error) {\n\tendpointsLock.Lock()\n\tdefer endpointsLock.Unlock()\n\tendpoint, ok := endpoints[path]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"no registered endpoint on path: %q\", path)\n\t}\n\n\treturn endpoint, nil\n}\n\nfunc (e *Endpoint) check() error {\n\t// Check path.\n\tif strings.TrimSpace(e.Path) == \"\" {\n\t\treturn errors.New(\"path is missing\")\n\t}\n\n\t// Check permissions.\n\tif e.Read < Dynamic || e.Read > PermitSelf {\n\t\treturn errors.New(\"invalid read permission\")\n\t}\n\tif e.Write < Dynamic || e.Write > PermitSelf {\n\t\treturn errors.New(\"invalid write permission\")\n\t}\n\n\t// Check methods.\n\tif e.Read != NotSupported {\n\t\tswitch e.ReadMethod {\n\t\tcase http.MethodGet:\n\t\t\t// All good.\n\t\tcase \"\":\n\t\t\t// Set to default.\n\t\t\te.ReadMethod = http.MethodGet\n\t\tdefault:\n\t\t\treturn errors.New(\"invalid read method\")\n\t\t}\n\t} else {\n\t\te.ReadMethod = \"\"\n\t}\n\tif e.Write != NotSupported {\n\t\tswitch e.WriteMethod {\n\t\tcase http.MethodPost,\n\t\t\thttp.MethodPut,\n\t\t\thttp.MethodDelete:\n\t\t\t// All good.\n\t\tcase \"\":\n\t\t\t// Set to default.\n\t\t\te.WriteMethod = http.MethodPost\n\t\tdefault:\n\t\t\treturn errors.New(\"invalid write method\")\n\t\t}\n\t} else {\n\t\te.WriteMethod = \"\"\n\t}\n\n\t// Check functions.\n\tvar defaultMimeType string\n\tfnCnt := 0\n\tif e.ActionFunc != nil {\n\t\tfnCnt++\n\t\tdefaultMimeType = MimeTypeText\n\t}\n\tif e.DataFunc != nil {\n\t\tfnCnt++\n\t\tdefaultMimeType = MimeTypeText\n\t}\n\tif e.StructFunc != nil {\n\t\tfnCnt++\n\t\tdefaultMimeType = MimeTypeJSON\n\t}\n\tif e.RecordFunc != nil {\n\t\tfnCnt++\n\t\tdefaultMimeType = MimeTypeJSON\n\t}\n\tif e.HandlerFunc != nil {\n\t\tfnCnt++\n\t\tdefaultMimeType = MimeTypeText\n\t}\n\tif fnCnt != 1 {\n\t\treturn errors.New(\"only one function may be set\")\n\t}\n\n\t// Set default mime type.\n\tif e.MimeType == \"\" {\n\t\te.MimeType = defaultMimeType\n\t}\n\n\treturn nil\n}\n\n// ExportEndpoints exports the registered endpoints. The returned data must be\n// treated as immutable.\nfunc ExportEndpoints() []*Endpoint {\n\tendpointsLock.RLock()\n\tdefer endpointsLock.RUnlock()\n\n\t// Copy the map into a slice.\n\teps := make([]*Endpoint, 0, len(endpoints))\n\tfor _, ep := range endpoints {\n\t\teps = append(eps, ep)\n\t}\n\n\tsort.Sort(sortByPath(eps))\n\treturn eps\n}\n\ntype sortByPath []*Endpoint\n\nfunc (eps sortByPath) Len() int           { return len(eps) }\nfunc (eps sortByPath) Less(i, j int) bool { return eps[i].Path < eps[j].Path }\nfunc (eps sortByPath) Swap(i, j int)      { eps[i], eps[j] = eps[j], eps[i] }\n\ntype endpointHandler struct{}\n\nvar _ AuthenticatedHandler = &endpointHandler{} // Compile time interface check.\n\n// ReadPermission returns the read permission for the handler.\nfunc (eh *endpointHandler) ReadPermission(r *http.Request) Permission {\n\tapiEndpoint, _ := getAPIContext(r)\n\tif apiEndpoint != nil {\n\t\treturn apiEndpoint.Read\n\t}\n\treturn NotFound\n}\n\n// WritePermission returns the write permission for the handler.\nfunc (eh *endpointHandler) WritePermission(r *http.Request) Permission {\n\tapiEndpoint, _ := getAPIContext(r)\n\tif apiEndpoint != nil {\n\t\treturn apiEndpoint.Write\n\t}\n\treturn NotFound\n}\n\n// ServeHTTP handles the http request.\nfunc (eh *endpointHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tapiEndpoint, apiRequest := getAPIContext(r)\n\tif apiEndpoint == nil || apiRequest == nil {\n\t\thttp.NotFound(w, r)\n\t\treturn\n\t}\n\n\tapiEndpoint.ServeHTTP(w, r)\n}\n\n// ServeHTTP handles the http request.\nfunc (e *Endpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\t_, apiRequest := getAPIContext(r)\n\tif apiRequest == nil {\n\t\thttp.NotFound(w, r)\n\t\treturn\n\t}\n\n\t// Return OPTIONS request before starting to handle normal requests.\n\tif r.Method == http.MethodOptions {\n\t\tw.WriteHeader(http.StatusNoContent)\n\t\treturn\n\t}\n\n\teMethod, readMethod, ok := getEffectiveMethod(r)\n\tif !ok {\n\t\thttp.Error(w, \"unsupported method for the actions API\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\tif readMethod {\n\t\tif eMethod != e.ReadMethod {\n\t\t\tlog.Tracer(r.Context()).Warningf(\n\t\t\t\t\"api: method %q does not match required read method %q%s\",\n\t\t\t\tr.Method,\n\t\t\t\te.ReadMethod,\n\t\t\t\t\" - this will be an error and abort the request in the future\",\n\t\t\t)\n\t\t}\n\t} else {\n\t\tif eMethod != e.WriteMethod {\n\t\t\tlog.Tracer(r.Context()).Warningf(\n\t\t\t\t\"api: method %q does not match required write method %q%s\",\n\t\t\t\tr.Method,\n\t\t\t\te.WriteMethod,\n\t\t\t\t\" - this will be an error and abort the request in the future\",\n\t\t\t)\n\t\t}\n\t}\n\n\tswitch eMethod {\n\tcase http.MethodGet, http.MethodDelete:\n\t\t// Nothing to do for these.\n\tcase http.MethodPost, http.MethodPut:\n\t\t// Read body data.\n\t\tinputData, ok := readBody(w, r)\n\t\tif !ok {\n\t\t\treturn\n\t\t}\n\t\tapiRequest.InputData = inputData\n\n\t\t// restore request body for any http.HandlerFunc below\n\t\tr.Body = io.NopCloser(bytes.NewReader(inputData))\n\tdefault:\n\t\t// Defensive.\n\t\thttp.Error(w, \"unsupported method for the actions API\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\t// Add response headers to request struct so that the endpoint can work with them.\n\tapiRequest.ResponseHeader = w.Header()\n\n\t// Execute action function and get response data\n\tvar responseData []byte\n\tvar err error\n\n\tswitch {\n\tcase e.ActionFunc != nil:\n\t\tvar msg string\n\t\tmsg, err = e.ActionFunc(apiRequest)\n\t\tif !strings.HasSuffix(msg, \"\\n\") {\n\t\t\tmsg += \"\\n\"\n\t\t}\n\t\tif err == nil {\n\t\t\tresponseData = []byte(msg)\n\t\t}\n\n\tcase e.DataFunc != nil:\n\t\tresponseData, err = e.DataFunc(apiRequest)\n\n\tcase e.StructFunc != nil:\n\t\tvar v interface{}\n\t\tv, err = e.StructFunc(apiRequest)\n\t\tif err == nil && v != nil {\n\t\t\tvar mimeType string\n\t\t\tresponseData, mimeType, _, err = dsd.MimeDump(v, r.Header.Get(\"Accept\"))\n\t\t\tif err == nil {\n\t\t\t\tw.Header().Set(\"Content-Type\", mimeType)\n\t\t\t}\n\t\t}\n\n\tcase e.RecordFunc != nil:\n\t\tvar rec record.Record\n\t\trec, err = e.RecordFunc(apiRequest)\n\t\tif err == nil && r != nil {\n\t\t\tresponseData, err = MarshalRecord(rec, false)\n\t\t}\n\n\tcase e.HandlerFunc != nil:\n\t\te.HandlerFunc(w, r)\n\t\treturn\n\n\tdefault:\n\t\thttp.Error(w, \"missing handler\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Check for handler error.\n\tif err != nil {\n\t\tvar statusProvider HTTPStatusProvider\n\t\tif errors.As(err, &statusProvider) {\n\t\t\thttp.Error(w, err.Error(), statusProvider.HTTPStatus())\n\t\t} else {\n\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t}\n\t\treturn\n\t}\n\n\t// Return no content if there is none, or if request is HEAD.\n\tif len(responseData) == 0 || r.Method == http.MethodHead {\n\t\tw.WriteHeader(http.StatusNoContent)\n\t\treturn\n\t}\n\n\t// Set content type if not yet set.\n\tif w.Header().Get(\"Content-Type\") == \"\" {\n\t\tw.Header().Set(\"Content-Type\", e.MimeType+\"; charset=utf-8\")\n\t}\n\n\t// Write response.\n\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(responseData)))\n\tw.WriteHeader(http.StatusOK)\n\t_, err = w.Write(responseData)\n\tif err != nil {\n\t\tlog.Tracer(r.Context()).Warningf(\"api: failed to write response: %s\", err)\n\t}\n}\n\nfunc readBody(w http.ResponseWriter, r *http.Request) (inputData []byte, ok bool) {\n\t// Check for too long content in order to prevent death.\n\tif r.ContentLength > 20000000 { // 20MB\n\t\thttp.Error(w, \"too much input data\", http.StatusRequestEntityTooLarge)\n\t\treturn nil, false\n\t}\n\n\t// Read and close body.\n\tinputData, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\thttp.Error(w, \"failed to read body\"+err.Error(), http.StatusInternalServerError)\n\t\treturn nil, false\n\t}\n\treturn inputData, true\n}\n"
  },
  {
    "path": "base/api/endpoints_config.go",
    "content": "package api\n\nimport (\n\t\"github.com/safing/portmaster/base/config\"\n)\n\nfunc registerConfigEndpoints() error {\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"config/options\",\n\t\tRead:        PermitAnyone,\n\t\tMimeType:    MimeTypeJSON,\n\t\tStructFunc:  listConfig,\n\t\tName:        \"Export Configuration Options\",\n\t\tDescription: \"Returns a list of all registered configuration options and their metadata. This does not include the current active or default settings.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc listConfig(ar *Request) (i interface{}, err error) {\n\treturn config.ExportOptions(), nil\n}\n"
  },
  {
    "path": "base/api/endpoints_debug.go",
    "content": "package api\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"runtime/pprof\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n)\n\nfunc registerDebugEndpoints() error {\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"ping\",\n\t\tRead:        PermitAnyone,\n\t\tActionFunc:  ping,\n\t\tName:        \"Ping\",\n\t\tDescription: \"Pong.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"ready\",\n\t\tRead:        PermitAnyone,\n\t\tActionFunc:  ready,\n\t\tName:        \"Ready\",\n\t\tDescription: \"Check if Portmaster has completed starting and is ready.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"debug/stack\",\n\t\tRead:        PermitAnyone,\n\t\tDataFunc:    getStack,\n\t\tName:        \"Get Goroutine Stack\",\n\t\tDescription: \"Returns the current goroutine stack.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"debug/stack/print\",\n\t\tRead:        PermitAnyone,\n\t\tActionFunc:  printStack,\n\t\tName:        \"Print Goroutine Stack\",\n\t\tDescription: \"Prints the current goroutine stack to stdout.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:     \"debug/cpu\",\n\t\tMimeType: \"application/octet-stream\",\n\t\tRead:     PermitAnyone,\n\t\tDataFunc: handleCPUProfile,\n\t\tName:     \"Get CPU Profile\",\n\t\tDescription: strings.ReplaceAll(`Gather and return the CPU profile.\nThis data needs to gathered over a period of time, which is specified using the duration parameter.\n\nYou can easily view this data in your browser with this command (with Go installed):\n\"go tool pprof -http :8888 http://127.0.0.1:817/api/v1/debug/cpu\"\n`, `\"`, \"`\"),\n\t\tParameters: []Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"duration\",\n\t\t\tValue:       \"10s\",\n\t\t\tDescription: \"Specify the formatting style. The default is simple markdown formatting.\",\n\t\t}},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:     \"debug/heap\",\n\t\tMimeType: \"application/octet-stream\",\n\t\tRead:     PermitAnyone,\n\t\tDataFunc: handleHeapProfile,\n\t\tName:     \"Get Heap Profile\",\n\t\tDescription: strings.ReplaceAll(`Gather and return the heap memory profile.\n\t\t\n\t\tYou can easily view this data in your browser with this command (with Go installed):\n\t\t\"go tool pprof -http :8888 http://127.0.0.1:817/api/v1/debug/heap\"\n\t\t`, `\"`, \"`\"),\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:     \"debug/allocs\",\n\t\tMimeType: \"application/octet-stream\",\n\t\tRead:     PermitAnyone,\n\t\tDataFunc: handleAllocsProfile,\n\t\tName:     \"Get Allocs Profile\",\n\t\tDescription: strings.ReplaceAll(`Gather and return the memory allocation profile.\n\t\t\n\t\tYou can easily view this data in your browser with this command (with Go installed):\n\t\t\"go tool pprof -http :8888 http://127.0.0.1:817/api/v1/debug/allocs\"\n\t\t`, `\"`, \"`\"),\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"debug/info\",\n\t\tRead:        PermitAnyone,\n\t\tDataFunc:    debugInfo,\n\t\tName:        \"Get Debug Information\",\n\t\tDescription: \"Returns debugging information, including the version and platform info, errors, logs and the current goroutine stack.\",\n\t\tParameters: []Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"style\",\n\t\t\tValue:       \"github\",\n\t\t\tDescription: \"Specify the formatting style. The default is simple markdown formatting.\",\n\t\t}},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// ping responds with pong.\nfunc ping(ar *Request) (msg string, err error) {\n\treturn \"Pong.\", nil\n}\n\n// ready checks if Portmaster has completed starting.\nfunc ready(ar *Request) (msg string, err error) {\n\tif module.instance.Ready() {\n\t\treturn \"\", ErrorWithStatus(errors.New(\"portmaster is not ready, reload (F5) to try again\"), http.StatusTooEarly)\n\t}\n\treturn \"Portmaster is ready.\", nil\n}\n\n// getStack returns the current goroutine stack.\nfunc getStack(_ *Request) (data []byte, err error) {\n\tbuf := &bytes.Buffer{}\n\terr = pprof.Lookup(\"goroutine\").WriteTo(buf, 1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn buf.Bytes(), nil\n}\n\n// printStack prints the current goroutine stack to stderr.\nfunc printStack(_ *Request) (msg string, err error) {\n\t_, err = fmt.Fprint(log.GlobalWriter, \"===== PRINTING STACK =====\\n\")\n\tif err == nil {\n\t\terr = pprof.Lookup(\"goroutine\").WriteTo(os.Stderr, 1)\n\t}\n\tif err == nil {\n\t\t_, err = fmt.Fprint(log.GlobalWriter, \"===== END OF STACK =====\\n\")\n\t}\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn \"stack printed to stdout\", nil\n}\n\n// handleCPUProfile returns the CPU profile.\nfunc handleCPUProfile(ar *Request) (data []byte, err error) {\n\t// Parse duration.\n\tduration := 10 * time.Second\n\tif durationOption := ar.Request.URL.Query().Get(\"duration\"); durationOption != \"\" {\n\t\tparsedDuration, err := time.ParseDuration(durationOption)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse duration: %w\", err)\n\t\t}\n\t\tduration = parsedDuration\n\t}\n\n\t// Indicate download and filename.\n\tar.ResponseHeader.Set(\n\t\t\"Content-Disposition\",\n\t\tfmt.Sprintf(`attachment; filename=\"portmaster-cpu-profile_v%s.pprof\"`, info.Version()),\n\t)\n\n\t// Start CPU profiling.\n\tbuf := new(bytes.Buffer)\n\tif err := pprof.StartCPUProfile(buf); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to start cpu profile: %w\", err)\n\t}\n\n\t// Wait for the specified duration.\n\tselect {\n\tcase <-time.After(duration):\n\tcase <-ar.Context().Done():\n\t\tpprof.StopCPUProfile()\n\t\treturn nil, context.Canceled\n\t}\n\n\t// Stop CPU profiling and return data.\n\tpprof.StopCPUProfile()\n\treturn buf.Bytes(), nil\n}\n\n// handleHeapProfile returns the Heap profile.\nfunc handleHeapProfile(ar *Request) (data []byte, err error) {\n\t// Indicate download and filename.\n\tar.ResponseHeader.Set(\n\t\t\"Content-Disposition\",\n\t\tfmt.Sprintf(`attachment; filename=\"portmaster-memory-heap-profile_v%s.pprof\"`, info.Version()),\n\t)\n\n\tbuf := new(bytes.Buffer)\n\tif err := pprof.Lookup(\"heap\").WriteTo(buf, 0); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write heap profile: %w\", err)\n\t}\n\treturn buf.Bytes(), nil\n}\n\n// handleAllocsProfile returns the Allocs profile.\nfunc handleAllocsProfile(ar *Request) (data []byte, err error) {\n\t// Indicate download and filename.\n\tar.ResponseHeader.Set(\n\t\t\"Content-Disposition\",\n\t\tfmt.Sprintf(`attachment; filename=\"portmaster-memory-allocs-profile_v%s.pprof\"`, info.Version()),\n\t)\n\n\tbuf := new(bytes.Buffer)\n\tif err := pprof.Lookup(\"allocs\").WriteTo(buf, 0); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write allocs profile: %w\", err)\n\t}\n\treturn buf.Bytes(), nil\n}\n\n// debugInfo returns the debugging information for support requests.\nfunc debugInfo(ar *Request) (data []byte, err error) {\n\t// Create debug information helper.\n\tdi := new(debug.Info)\n\tdi.Style = ar.Request.URL.Query().Get(\"style\")\n\n\t// Add debug information.\n\tdi.AddVersionInfo()\n\tdi.AddPlatformInfo(ar.Context())\n\tdi.AddLastUnexpectedLogs()\n\tdi.AddGoroutineStack()\n\n\t// Return data.\n\treturn di.Bytes(), nil\n}\n"
  },
  {
    "path": "base/api/endpoints_meta.go",
    "content": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"net/http\"\n)\n\nfunc registerMetaEndpoints() error {\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"endpoints\",\n\t\tRead:        PermitAnyone,\n\t\tMimeType:    MimeTypeJSON,\n\t\tDataFunc:    listEndpoints,\n\t\tName:        \"Export API Endpoints\",\n\t\tDescription: \"Returns a list of all registered endpoints and their metadata.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"auth/permissions\",\n\t\tRead:        Dynamic,\n\t\tStructFunc:  permissions,\n\t\tName:        \"View Current Permissions\",\n\t\tDescription: \"Returns the current permissions assigned to the request.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"auth/bearer\",\n\t\tRead:        Dynamic,\n\t\tHandlerFunc: authBearer,\n\t\tName:        \"Request HTTP Bearer Auth\",\n\t\tDescription: \"Returns an HTTP Bearer Auth request, if not authenticated.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"auth/basic\",\n\t\tRead:        Dynamic,\n\t\tHandlerFunc: authBasic,\n\t\tName:        \"Request HTTP Basic Auth\",\n\t\tDescription: \"Returns an HTTP Basic Auth request, if not authenticated.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := RegisterEndpoint(Endpoint{\n\t\tPath:        \"auth/reset\",\n\t\tRead:        PermitAnyone,\n\t\tHandlerFunc: authReset,\n\t\tName:        \"Reset Authenticated Session\",\n\t\tDescription: \"Resets authentication status internally and in the browser.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc listEndpoints(ar *Request) (data []byte, err error) {\n\tdata, err = json.Marshal(ExportEndpoints())\n\treturn\n}\n\nfunc permissions(ar *Request) (i interface{}, err error) {\n\tif ar.AuthToken == nil {\n\t\treturn nil, errors.New(\"authentication token missing\")\n\t}\n\n\treturn struct {\n\t\tRead      Permission\n\t\tWrite     Permission\n\t\tReadRole  string\n\t\tWriteRole string\n\t}{\n\t\tRead:      ar.AuthToken.Read,\n\t\tWrite:     ar.AuthToken.Write,\n\t\tReadRole:  ar.AuthToken.Read.Role(),\n\t\tWriteRole: ar.AuthToken.Write.Role(),\n\t}, nil\n}\n\nfunc authBearer(w http.ResponseWriter, r *http.Request) {\n\t// Check if authenticated by checking read permission.\n\tar := GetAPIRequest(r)\n\tif ar.AuthToken.Read != PermitAnyone {\n\t\tTextResponse(w, r, \"Authenticated.\")\n\t\treturn\n\t}\n\n\t// Respond with desired authentication header.\n\tw.Header().Set(\n\t\t\"WWW-Authenticate\",\n\t\t`Bearer realm=\"Portmaster API\" domain=\"/\"`,\n\t)\n\thttp.Error(w, \"Authorization required.\", http.StatusUnauthorized)\n}\n\nfunc authBasic(w http.ResponseWriter, r *http.Request) {\n\t// Check if authenticated by checking read permission.\n\tar := GetAPIRequest(r)\n\tif ar.AuthToken.Read != PermitAnyone {\n\t\tTextResponse(w, r, \"Authenticated.\")\n\t\treturn\n\t}\n\n\t// Respond with desired authentication header.\n\tw.Header().Set(\n\t\t\"WWW-Authenticate\",\n\t\t`Basic realm=\"Portmaster API\" domain=\"/\"`,\n\t)\n\thttp.Error(w, \"Authorization required.\", http.StatusUnauthorized)\n}\n\nfunc authReset(w http.ResponseWriter, r *http.Request) {\n\t// Get session cookie from request and delete session if exists.\n\tc, err := r.Cookie(sessionCookieName)\n\tif err == nil {\n\t\tdeleteSession(c.Value)\n\t}\n\n\t// Delete session and cookie.\n\thttp.SetCookie(w, &http.Cookie{\n\t\tName:   sessionCookieName,\n\t\tMaxAge: -1, // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'\n\t})\n\n\t// Request client to also reset all data.\n\tw.Header().Set(\"Clear-Site-Data\", \"*\")\n\n\t// Set HTTP Auth Realm without requesting authorization.\n\tw.Header().Set(\"WWW-Authenticate\", `None realm=\"Portmaster API\"`)\n\n\t// Reply with 401 Unauthorized in order to clear HTTP Basic Auth data.\n\thttp.Error(w, \"Session deleted.\", http.StatusUnauthorized)\n}\n"
  },
  {
    "path": "base/api/endpoints_test.go",
    "content": "package api\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nconst (\n\tsuccessMsg = \"endpoint api success\"\n\tfailedMsg  = \"endpoint api failed\"\n)\n\ntype actionTestRecord struct {\n\trecord.Base\n\tsync.Mutex\n\tMsg string\n}\n\nfunc TestEndpoints(t *testing.T) {\n\tt.Parallel()\n\n\ttestHandler := &mainHandler{\n\t\tmux: mainMux,\n\t}\n\n\t// ActionFn\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/action\",\n\t\tRead: PermitAnyone,\n\t\tActionFunc: func(_ *Request) (msg string, err error) {\n\t\t\treturn successMsg, nil\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/action\", nil, successMsg)\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/action-err\",\n\t\tRead: PermitAnyone,\n\t\tActionFunc: func(_ *Request) (msg string, err error) {\n\t\t\treturn \"\", errors.New(failedMsg)\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/action-err\", nil, failedMsg)\n\n\t// DataFn\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/data\",\n\t\tRead: PermitAnyone,\n\t\tDataFunc: func(_ *Request) (data []byte, err error) {\n\t\t\treturn []byte(successMsg), nil\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/data\", nil, successMsg)\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/data-err\",\n\t\tRead: PermitAnyone,\n\t\tDataFunc: func(_ *Request) (data []byte, err error) {\n\t\t\treturn nil, errors.New(failedMsg)\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/data-err\", nil, failedMsg)\n\n\t// StructFn\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/struct\",\n\t\tRead: PermitAnyone,\n\t\tStructFunc: func(_ *Request) (i interface{}, err error) {\n\t\t\treturn &actionTestRecord{\n\t\t\t\tMsg: successMsg,\n\t\t\t}, nil\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/struct\", nil, successMsg)\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/struct-err\",\n\t\tRead: PermitAnyone,\n\t\tStructFunc: func(_ *Request) (i interface{}, err error) {\n\t\t\treturn nil, errors.New(failedMsg)\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/struct-err\", nil, failedMsg)\n\n\t// RecordFn\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/record\",\n\t\tRead: PermitAnyone,\n\t\tRecordFunc: func(_ *Request) (r record.Record, err error) {\n\t\t\tr = &actionTestRecord{\n\t\t\t\tMsg: successMsg,\n\t\t\t}\n\t\t\tr.CreateMeta()\n\t\t\treturn r, nil\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/record\", nil, successMsg)\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/record-err\",\n\t\tRead: PermitAnyone,\n\t\tRecordFunc: func(_ *Request) (r record.Record, err error) {\n\t\t\treturn nil, errors.New(failedMsg)\n\t\t},\n\t}))\n\tassert.HTTPBodyContains(t, testHandler.ServeHTTP, \"GET\", apiV1Path+\"test/record-err\", nil, failedMsg)\n}\n\nfunc TestActionRegistration(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Error(t, RegisterEndpoint(Endpoint{}))\n\n\tassert.Error(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/err\",\n\t\tRead: NotFound,\n\t}))\n\tassert.Error(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/err\",\n\t\tRead: PermitSelf + 1,\n\t}))\n\n\tassert.Error(t, RegisterEndpoint(Endpoint{\n\t\tPath:  \"test/err\",\n\t\tWrite: NotFound,\n\t}))\n\tassert.Error(t, RegisterEndpoint(Endpoint{\n\t\tPath:  \"test/err\",\n\t\tWrite: PermitSelf + 1,\n\t}))\n\n\tassert.Error(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/err\",\n\t}))\n\n\tassert.Error(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/err\",\n\t\tActionFunc: func(_ *Request) (msg string, err error) {\n\t\t\treturn successMsg, nil\n\t\t},\n\t\tDataFunc: func(_ *Request) (data []byte, err error) {\n\t\t\treturn []byte(successMsg), nil\n\t\t},\n\t}))\n\n\tassert.NoError(t, RegisterEndpoint(Endpoint{\n\t\tPath: \"test/err\",\n\t\tActionFunc: func(_ *Request) (msg string, err error) {\n\t\t\treturn successMsg, nil\n\t\t},\n\t}))\n}\n"
  },
  {
    "path": "base/api/enriched-response.go",
    "content": "package api\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"net\"\n\t\"net/http\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// LoggingResponseWriter is a wrapper for http.ResponseWriter for better request logging.\ntype LoggingResponseWriter struct {\n\tResponseWriter http.ResponseWriter\n\tRequest        *http.Request\n\tStatus         int\n}\n\n// NewLoggingResponseWriter wraps a http.ResponseWriter.\nfunc NewLoggingResponseWriter(w http.ResponseWriter, r *http.Request) *LoggingResponseWriter {\n\treturn &LoggingResponseWriter{\n\t\tResponseWriter: w,\n\t\tRequest:        r,\n\t}\n}\n\n// Header wraps the original Header method.\nfunc (lrw *LoggingResponseWriter) Header() http.Header {\n\treturn lrw.ResponseWriter.Header()\n}\n\n// Write wraps the original Write method.\nfunc (lrw *LoggingResponseWriter) Write(b []byte) (int, error) {\n\treturn lrw.ResponseWriter.Write(b)\n}\n\n// WriteHeader wraps the original WriteHeader method to extract information.\nfunc (lrw *LoggingResponseWriter) WriteHeader(code int) {\n\tlrw.Status = code\n\tlrw.ResponseWriter.WriteHeader(code)\n}\n\n// Hijack wraps the original Hijack method, if available.\nfunc (lrw *LoggingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {\n\thijacker, ok := lrw.ResponseWriter.(http.Hijacker)\n\tif ok {\n\t\tc, b, err := hijacker.Hijack()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tlog.Tracer(lrw.Request.Context()).Infof(\"api request: %s HIJ %s\", lrw.Request.RemoteAddr, lrw.Request.RequestURI)\n\t\treturn c, b, nil\n\t}\n\treturn nil, nil, errors.New(\"response does not implement http.Hijacker\")\n}\n\n// RequestLogger is a logging middleware.\nfunc RequestLogger(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tlog.Tracer(r.Context()).Tracef(\"api request: %s ___ %s\", r.RemoteAddr, r.RequestURI)\n\t\tlrw := NewLoggingResponseWriter(w, r)\n\t\tnext.ServeHTTP(lrw, r)\n\t\tif lrw.Status != 0 {\n\t\t\t// request may have been hijacked\n\t\t\tlog.Tracer(r.Context()).Infof(\"api request: %s %d %s\", lrw.Request.RemoteAddr, lrw.Status, lrw.Request.RequestURI)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "base/api/init_test.go",
    "content": "package api\n\nimport (\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/config\"\n)\n\ntype testInstance struct {\n\tconfig *config.Config\n}\n\nvar _ instance = &testInstance{}\n\nfunc (stub *testInstance) Config() *config.Config {\n\treturn stub.config\n}\n\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\n\nfunc (stub *testInstance) Ready() bool {\n\treturn true\n}\n\nfunc TestMain(m *testing.M) {\n\tSetDefaultAPIListenAddress(\"0.0.0.0:8080\")\n\tinstance := &testInstance{}\n\tvar err error\n\tmodule, err = New(instance)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\terr = SetAuthenticator(testAuthenticator)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tm.Run()\n}\n"
  },
  {
    "path": "base/api/main.go",
    "content": "package api\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"flag\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar exportEndpoints bool\n\n// API Errors.\nvar (\n\tErrAuthenticationAlreadySet = errors.New(\"the authentication function has already been set\")\n\tErrAuthenticationImmutable  = errors.New(\"the authentication function can only be set before the api has started\")\n)\n\nfunc init() {\n\tflag.BoolVar(&exportEndpoints, \"export-api-endpoints\", false, \"export api endpoint registry and exit\")\n}\n\nfunc prep() error {\n\t// Register endpoints.\n\tif err := registerConfig(); err != nil {\n\t\treturn err\n\t}\n\tif err := registerDebugEndpoints(); err != nil {\n\t\treturn err\n\t}\n\tif err := registerConfigEndpoints(); err != nil {\n\t\treturn err\n\t}\n\tif err := registerMetaEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\tif exportEndpoints {\n\t\tmodule.instance.SetCmdLineOperation(exportEndpointsCmd)\n\t\treturn mgr.ErrExecuteCmdLineOp\n\t}\n\n\tif getDefaultListenAddress() == \"\" {\n\t\treturn errors.New(\"no default listen address for api available\")\n\t}\n\n\treturn nil\n}\n\nfunc start() error {\n\tstartServer()\n\n\tupdateAPIKeys()\n\tmodule.instance.Config().EventConfigChange.AddCallback(\"update API keys\",\n\t\tfunc(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\t\tupdateAPIKeys()\n\t\t\treturn false, nil\n\t\t})\n\n\t// start api auth token cleaner\n\tif authFnSet.IsSet() {\n\t\t_ = module.mgr.Repeat(\"clean api sessions\", 5*time.Minute, cleanSessions)\n\t}\n\n\treturn registerEndpointBridgeDB()\n}\n\nfunc stop() error {\n\treturn stopServer()\n}\n\nfunc exportEndpointsCmd() error {\n\tdata, err := json.MarshalIndent(ExportEndpoints(), \"\", \"  \")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = os.Stdout.Write(data)\n\treturn err\n}\n"
  },
  {
    "path": "base/api/module.go",
    "content": "package api\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// API is the HTTP/Websockets API module.\ntype API struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tonline atomic.Bool\n}\n\nfunc (api *API) Manager() *mgr.Manager {\n\treturn api.mgr\n}\n\n// Start starts the module.\nfunc (api *API) Start() error {\n\tif err := start(); err != nil {\n\t\treturn err\n\t}\n\n\tapi.online.Store(true)\n\treturn nil\n}\n\n// Stop stops the module.\nfunc (api *API) Stop() error {\n\tdefer api.online.Store(false)\n\treturn stop()\n}\n\nvar (\n\tshimLoaded atomic.Bool\n\tmodule     *API\n)\n\n// New returns a new UI module.\nfunc New(instance instance) (*API, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"API\")\n\tmodule = &API{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tConfig() *config.Config\n\tSetCmdLineOperation(f func() error)\n\tReady() bool\n}\n"
  },
  {
    "path": "base/api/request.go",
    "content": "package api\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// Request is a support struct to pool more request related information.\ntype Request struct {\n\t// Request is the http request.\n\t*http.Request\n\n\t// InputData contains the request body for write operations.\n\tInputData []byte\n\n\t// Route of this request.\n\tRoute *mux.Route\n\n\t// URLVars contains the URL variables extracted by the gorilla mux.\n\tURLVars map[string]string\n\n\t// AuthToken is the request-side authentication token assigned.\n\tAuthToken *AuthToken\n\n\t// ResponseHeader holds the response header.\n\tResponseHeader http.Header\n\n\t// HandlerCache can be used by handlers to cache data between handlers within a request.\n\tHandlerCache interface{}\n}\n\n// apiRequestContextKey is a key used for the context key/value storage.\ntype apiRequestContextKey struct{}\n\n// RequestContextKey is the key used to add the API request to the context.\nvar RequestContextKey = apiRequestContextKey{}\n\n// GetAPIRequest returns the API Request of the given http request.\nfunc GetAPIRequest(r *http.Request) *Request {\n\tar, ok := r.Context().Value(RequestContextKey).(*Request)\n\tif ok {\n\t\treturn ar\n\t}\n\treturn nil\n}\n\n// TextResponse writes a text response.\nfunc TextResponse(w http.ResponseWriter, r *http.Request, text string) {\n\tw.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tw.Header().Set(\"X-Content-Type-Options\", \"nosniff\")\n\tw.WriteHeader(http.StatusOK)\n\t_, err := fmt.Fprintln(w, text)\n\tif err != nil {\n\t\tlog.Tracer(r.Context()).Warningf(\"api: failed to write text response: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "base/api/router.go",
    "content": "package api\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// EnableServer defines if the HTTP server should be started.\nvar EnableServer = true\n\nvar (\n\t// mainMux is the main mux router.\n\tmainMux = mux.NewRouter()\n\n\t// server is the main server.\n\tserver = &http.Server{\n\t\tReadHeaderTimeout: 10 * time.Second,\n\t}\n\thandlerLock sync.RWMutex\n\n\tallowedDevCORSOrigins = []string{\n\t\t\"127.0.0.1\",\n\t\t\"localhost\",\n\t}\n)\n\n// RegisterHandler registers a handler with the API endpoint.\nfunc RegisterHandler(path string, handler http.Handler) *mux.Route {\n\thandlerLock.Lock()\n\tdefer handlerLock.Unlock()\n\treturn mainMux.Handle(path, handler)\n}\n\n// RegisterHandleFunc registers a handle function with the API endpoint.\nfunc RegisterHandleFunc(path string, handleFunc func(http.ResponseWriter, *http.Request)) *mux.Route {\n\thandlerLock.Lock()\n\tdefer handlerLock.Unlock()\n\treturn mainMux.HandleFunc(path, handleFunc)\n}\n\nfunc startServer() {\n\t// Check if server is enabled.\n\tif !EnableServer {\n\t\treturn\n\t}\n\n\t// Configure server.\n\tserver.Addr = listenAddressConfig()\n\tserver.Handler = &mainHandler{\n\t\t// TODO: mainMux should not be modified anymore.\n\t\tmux: mainMux,\n\t}\n\n\t// Start server manager.\n\tmodule.mgr.Go(\"http server manager\", serverManager)\n}\n\nfunc stopServer() error {\n\t// Check if server is enabled.\n\tif !EnableServer {\n\t\treturn nil\n\t}\n\n\tif server.Addr != \"\" {\n\t\treturn server.Shutdown(context.Background())\n\t}\n\n\treturn nil\n}\n\n// Serve starts serving the API endpoint.\nfunc serverManager(ctx *mgr.WorkerCtx) error {\n\t// start serving\n\tlog.Infof(\"api: starting to listen on %s\", server.Addr)\n\tbackoffDuration := 10 * time.Second\n\tfor {\n\t\terr := module.mgr.Do(\"http server\", func(ctx *mgr.WorkerCtx) error {\n\t\t\terr := server.ListenAndServe()\n\t\t\t// return on shutdown error\n\t\t\tif errors.Is(err, http.ErrServerClosed) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn err\n\t\t})\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\t\t// log error and restart\n\t\tlog.Errorf(\"api: http endpoint failed: %s - restarting in %s\", err, backoffDuration)\n\t\ttime.Sleep(backoffDuration)\n\t}\n}\n\ntype mainHandler struct {\n\tmux *mux.Router\n}\n\nfunc (mh *mainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\t_ = module.mgr.Do(\"http request\", func(_ *mgr.WorkerCtx) error {\n\t\treturn mh.handle(w, r)\n\t})\n}\n\nfunc (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error {\n\t// Setup context trace logging.\n\tctx, tracer := log.AddTracer(r.Context())\n\t// Add request context.\n\tapiRequest := &Request{\n\t\tRequest: r,\n\t}\n\tctx = context.WithValue(ctx, RequestContextKey, apiRequest)\n\t// Add context back to request.\n\tr = r.WithContext(ctx)\n\tlrw := NewLoggingResponseWriter(w, r)\n\n\ttracer.Tracef(\"api request: %s ___ %s %s\", r.RemoteAddr, lrw.Request.Method, r.RequestURI)\n\tdefer func() {\n\t\t// Log request status.\n\t\tif lrw.Status != 0 {\n\t\t\t// If lrw.Status is 0, the request may have been hijacked.\n\t\t\ttracer.Debugf(\"api request: %s %d %s %s\", lrw.Request.RemoteAddr, lrw.Status, lrw.Request.Method, lrw.Request.RequestURI)\n\t\t}\n\t\ttracer.Submit()\n\t}()\n\n\t// Add security headers.\n\tw.Header().Set(\"Referrer-Policy\", \"same-origin\")\n\tw.Header().Set(\"X-Content-Type-Options\", \"nosniff\")\n\tw.Header().Set(\"X-Frame-Options\", \"deny\")\n\tw.Header().Set(\"X-XSS-Protection\", \"1; mode=block\")\n\tw.Header().Set(\"X-DNS-Prefetch-Control\", \"off\")\n\n\t// Add CSP Header in production mode.\n\tif !devMode() {\n\t\tw.Header().Set(\n\t\t\t\"Content-Security-Policy\",\n\t\t\t\"default-src 'self'; \"+\n\t\t\t\t\"connect-src https://*.safing.io 'self'; \"+\n\t\t\t\t\"style-src 'self' 'unsafe-inline'; \"+\n\t\t\t\t\"img-src 'self' data: blob:\",\n\t\t)\n\t}\n\n\t// Check Cross-Origin Requests.\n\torigin := r.Header.Get(\"Origin\")\n\tisPreflighCheck := false\n\tif origin != \"\" {\n\n\t\t// Parse origin URL.\n\t\toriginURL, err := url.Parse(origin)\n\t\tif err != nil {\n\t\t\ttracer.Warningf(\"api: denied request from %s: failed to parse origin header: %s\", r.RemoteAddr, err)\n\t\t\thttp.Error(lrw, \"Invalid Origin.\", http.StatusForbidden)\n\t\t\treturn nil\n\t\t}\n\n\t\t// Check if the Origin matches the Host.\n\t\tswitch {\n\t\tcase originURL.Host == r.Host:\n\t\t\t// Origin (with port) matches Host.\n\t\tcase originURL.Hostname() == r.Host:\n\t\t\t// Origin (without port) matches Host.\n\t\tcase originURL.Scheme == \"chrome-extension\":\n\t\t\t// Allow access for the browser extension\n\t\t\t// TODO(ppacher):\n\t\t\t// This currently allows access from any browser extension.\n\t\t\t// Can we reduce that to only our browser extension?\n\t\t\t// Also, what do we need to support Firefox?\n\t\tcase devMode() &&\n\t\t\tutils.StringInSlice(allowedDevCORSOrigins, originURL.Hostname()):\n\t\t\t// We are in dev mode and the request is coming from the allowed\n\t\t\t// development origins.\n\t\tdefault:\n\t\t\t// Origin and Host do NOT match!\n\t\t\ttracer.Warningf(\"api: denied request from %s: Origin (`%s`) and Host (`%s`) do not match\", r.RemoteAddr, origin, r.Host)\n\t\t\thttp.Error(lrw, \"Cross-Origin Request Denied.\", http.StatusForbidden)\n\t\t\treturn nil\n\n\t\t\t// If the Host header has a port, and the Origin does not, requests will\n\t\t\t// also end up here, as we cannot properly check for equality.\n\t\t}\n\n\t\t// Add Cross-Site Headers now as we need them in any case now.\n\t\tw.Header().Set(\"Access-Control-Allow-Origin\", origin)\n\t\tw.Header().Set(\"Access-Control-Allow-Methods\", \"*\")\n\t\tw.Header().Set(\"Access-Control-Allow-Headers\", \"*\")\n\t\tw.Header().Set(\"Access-Control-Allow-Credentials\", \"true\")\n\t\tw.Header().Set(\"Access-Control-Expose-Headers\", \"*\")\n\t\tw.Header().Set(\"Access-Control-Max-Age\", \"60\")\n\t\tw.Header().Add(\"Vary\", \"Origin\")\n\n\t\t// if there's a Access-Control-Request-Method header this is a Preflight check.\n\t\t// In that case, we will just check if the preflighMethod is allowed and then return\n\t\t// success here\n\t\tif preflighMethod := r.Header.Get(\"Access-Control-Request-Method\"); r.Method == http.MethodOptions && preflighMethod != \"\" {\n\t\t\tisPreflighCheck = true\n\t\t}\n\t}\n\n\t// Clean URL.\n\tcleanedRequestPath := cleanRequestPath(r.URL.Path)\n\n\t// If the cleaned URL differs from the original one, redirect to there.\n\tif r.URL.Path != cleanedRequestPath {\n\t\tredirURL := *r.URL\n\t\tredirURL.Path = cleanedRequestPath\n\t\thttp.Redirect(lrw, r, redirURL.String(), http.StatusMovedPermanently)\n\t\treturn nil\n\t}\n\n\t// Get handler for request.\n\t// Gorilla does not support handling this on our own very well.\n\t// See github.com/gorilla/mux.ServeHTTP for reference.\n\tvar match mux.RouteMatch\n\tvar handler http.Handler\n\tif mh.mux.Match(r, &match) {\n\t\thandler = match.Handler\n\t\tapiRequest.Route = match.Route\n\t\tapiRequest.URLVars = match.Vars\n\t}\n\tswitch {\n\tcase match.MatchErr == nil:\n\t\t// All good.\n\tcase errors.Is(match.MatchErr, mux.ErrMethodMismatch):\n\t\thttp.Error(lrw, \"Method not allowed.\", http.StatusMethodNotAllowed)\n\t\treturn nil\n\tdefault:\n\t\ttracer.Debug(\"api: no handler registered for this path\")\n\t\thttp.Error(lrw, \"Not found.\", http.StatusNotFound)\n\t\treturn nil\n\t}\n\n\t// Be sure that URLVars always is a map.\n\tif apiRequest.URLVars == nil {\n\t\tapiRequest.URLVars = make(map[string]string)\n\t}\n\n\t// Check method.\n\t_, readMethod, ok := getEffectiveMethod(r)\n\tif !ok {\n\t\thttp.Error(lrw, \"Method not allowed.\", http.StatusMethodNotAllowed)\n\t\treturn nil\n\t}\n\n\t// At this point we know the method is allowed and there's a handler for the request.\n\t// If this is just a CORS-Preflight, we'll accept the request with StatusOK now.\n\t// There's no point in trying to authenticate the request because the Browser will\n\t// not send authentication along a preflight check.\n\tif isPreflighCheck && handler != nil {\n\t\tlrw.WriteHeader(http.StatusOK)\n\t\treturn nil\n\t}\n\n\t// Check authentication.\n\tapiRequest.AuthToken = authenticateRequest(lrw, r, handler, readMethod)\n\tif apiRequest.AuthToken == nil {\n\t\t// Authenticator already replied.\n\t\treturn nil\n\t}\n\n\t// Check if we have a handler.\n\tif handler == nil {\n\t\thttp.Error(lrw, \"Not found.\", http.StatusNotFound)\n\t\treturn nil\n\t}\n\n\t// Format panics in handler.\n\tdefer func() {\n\t\tif panicValue := recover(); panicValue != nil {\n\t\t\t// Log failure.\n\t\t\tlog.Errorf(\"api: handler panic: %s\", panicValue)\n\t\t\t// Respond with a server error.\n\t\t\tif devMode() {\n\t\t\t\thttp.Error(\n\t\t\t\t\tlrw,\n\t\t\t\t\tfmt.Sprintf(\n\t\t\t\t\t\t\"Internal Server Error: %s\\n\\n%s\",\n\t\t\t\t\t\tpanicValue,\n\t\t\t\t\t\tdebug.Stack(),\n\t\t\t\t\t),\n\t\t\t\t\thttp.StatusInternalServerError,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\thttp.Error(lrw, \"Internal Server Error.\", http.StatusInternalServerError)\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Handle with registered handler.\n\thandler.ServeHTTP(lrw, r)\n\n\treturn nil\n}\n\n// cleanRequestPath cleans and returns a request URL.\nfunc cleanRequestPath(requestPath string) string {\n\t// If the request URL is empty, return a request for \"root\".\n\tif requestPath == \"\" || requestPath == \"/\" {\n\t\treturn \"/\"\n\t}\n\t// If the request URL does not start with a slash, prepend it.\n\tif !strings.HasPrefix(requestPath, \"/\") {\n\t\trequestPath = \"/\" + requestPath\n\t}\n\n\t// Clean path to remove any relative parts.\n\tcleanedRequestPath := path.Clean(requestPath)\n\t// Because path.Clean removes a trailing slash, we need to add it back here\n\t// if the original URL had one.\n\tif strings.HasSuffix(requestPath, \"/\") {\n\t\tcleanedRequestPath += \"/\"\n\t}\n\n\treturn cleanedRequestPath\n}\n"
  },
  {
    "path": "base/api/testclient/root/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<!-- <script src=\"https://cdn.jsdelivr.net/sockjs/1/sockjs.min.js\"></script> -->\n</head>\n<body>\n\t<script type=\"text/javascript\">\n\n\t\tvar ws = new WebSocket('ws://127.0.0.1:18/api/database/v1')\n\n\t\tws.onopen = function () {\n\t    console.log('open');\n\t\t};\n\n\t\tws.onerror = function (error) {\n\t\t\tconsole.log('error');\n\t\t  console.log(error);\n\t\t};\n\n\t\tws.onmessage = function (e) {\n\t\t\treader = new FileReader()\n\t\t\treader.onload = function(e) {\n\t\t\t\tconsole.log(e.target.result)\n      }\n\t\t\treader.readAsText(e.data)\n\t\t};\n\n\t\tfunction send(text) {\n\t\t\tws.send(text)\n\t\t}\n\n\t\t// var sock = new SockJS(\"http://localhost:8080/api/v1\");\n\t\t//\n\t\t// sock.onopen = function() {\n\t\t//     console.log('open');\n\t\t// };\n\t\t//\n\t\t// sock.onmessage = function(e) {\n\t\t//     console.log('message received: ', e.data);\n\t\t// };\n\t\t//\n\t\t// sock.onclose = function(e) {\n\t\t//     console.log('close', e);\n\t\t// };\n\t</script>\n\tyeeee\n</body>\n</html>\n"
  },
  {
    "path": "base/api/testclient/serve.go",
    "content": "package testclient\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/safing/portmaster/base/api\"\n)\n\nfunc init() {\n\tapi.RegisterHandler(\"/test/\", http.StripPrefix(\"/test/\", http.FileServer(http.Dir(\"./api/testclient/root/\"))))\n}\n"
  },
  {
    "path": "base/apprise/notify.go",
    "content": "package apprise\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\n// Notifier sends messsages to an Apprise API.\ntype Notifier struct {\n\t// URL defines the Apprise API endpoint.\n\tURL string\n\n\t// DefaultType defines the default message type.\n\tDefaultType MsgType\n\n\t// DefaultTag defines the default message tag.\n\tDefaultTag string\n\n\t// DefaultFormat defines the default message format.\n\tDefaultFormat MsgFormat\n\n\t// AllowUntagged defines if untagged messages are allowed,\n\t// which are sent to all configured apprise endpoints.\n\tAllowUntagged bool\n\n\tclient     *http.Client\n\tclientLock sync.Mutex\n}\n\n// Message represents the message to be sent to the Apprise API.\ntype Message struct {\n\t// Title is an optional title to go along with the body.\n\tTitle string `json:\"title,omitempty\"`\n\n\t// Body is the main message content. This is the only required field.\n\tBody string `json:\"body\"`\n\n\t// Type defines the message type you want to send as.\n\t// The valid options are info, success, warning, and failure.\n\t// If no type is specified then info is the default value used.\n\tType MsgType `json:\"type,omitempty\"`\n\n\t// Tag is used to notify only those tagged accordingly.\n\t// Use a comma (,) to OR your tags and a space ( ) to AND them.\n\tTag string `json:\"tag,omitempty\"`\n\n\t// Format optionally identifies the text format of the data you're feeding Apprise.\n\t// The valid options are text, markdown, html.\n\t// The default value if nothing is specified is text.\n\tFormat MsgFormat `json:\"format,omitempty\"`\n}\n\n// MsgType defines the message type.\ntype MsgType string\n\n// Message Types.\nconst (\n\tTypeInfo    MsgType = \"info\"\n\tTypeSuccess MsgType = \"success\"\n\tTypeWarning MsgType = \"warning\"\n\tTypeFailure MsgType = \"failure\"\n)\n\n// MsgFormat defines the message format.\ntype MsgFormat string\n\n// Message Formats.\nconst (\n\tFormatText     MsgFormat = \"text\"\n\tFormatMarkdown MsgFormat = \"markdown\"\n\tFormatHTML     MsgFormat = \"html\"\n)\n\ntype errorResponse struct {\n\tError string `json:\"error\"`\n}\n\n// Send sends a message to the Apprise API.\nfunc (n *Notifier) Send(ctx context.Context, m *Message) error {\n\t// Check if the message has a body.\n\tif m.Body == \"\" {\n\t\treturn errors.New(\"the message must have a body\")\n\t}\n\n\t// Apply notifier defaults.\n\tn.applyDefaults(m)\n\n\t// Check if the message is tagged.\n\tif m.Tag == \"\" && !n.AllowUntagged {\n\t\treturn errors.New(\"the message must have a tag\")\n\t}\n\n\t// Marshal the message to JSON.\n\tpayload, err := json.Marshal(m)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal message: %w\", err)\n\t}\n\n\t// Create request.\n\trequest, err := http.NewRequestWithContext(ctx, http.MethodPost, n.URL, bytes.NewReader(payload))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create request: %w\", err)\n\t}\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\n\t// Send message to API.\n\tresp, err := n.getClient().Do(request)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to send message: %w\", err)\n\t}\n\tdefer resp.Body.Close() //nolint:errcheck,gosec\n\tswitch resp.StatusCode {\n\tcase http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:\n\t\treturn nil\n\tdefault:\n\t\t// Try to tease body contents.\n\t\tif body, err := io.ReadAll(resp.Body); err == nil && len(body) > 0 {\n\t\t\t// Try to parse json response.\n\t\t\terrorResponse := &errorResponse{}\n\t\t\tif err := json.Unmarshal(body, errorResponse); err == nil && errorResponse.Error != \"\" {\n\t\t\t\treturn fmt.Errorf(\"failed to send message: apprise returned %q with an error message: %s\", resp.Status, errorResponse.Error)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to send message: %s (body teaser: %s)\", resp.Status, utils.SafeFirst16Bytes(body))\n\t\t}\n\t\treturn fmt.Errorf(\"failed to send message: %s\", resp.Status)\n\t}\n}\n\nfunc (n *Notifier) applyDefaults(m *Message) {\n\tif m.Type == \"\" {\n\t\tm.Type = n.DefaultType\n\t}\n\tif m.Tag == \"\" {\n\t\tm.Tag = n.DefaultTag\n\t}\n\tif m.Format == \"\" {\n\t\tm.Format = n.DefaultFormat\n\t}\n}\n\n// SetClient sets a custom http client for accessing the Apprise API.\nfunc (n *Notifier) SetClient(client *http.Client) {\n\tn.clientLock.Lock()\n\tdefer n.clientLock.Unlock()\n\n\tn.client = client\n}\n\nfunc (n *Notifier) getClient() *http.Client {\n\tn.clientLock.Lock()\n\tdefer n.clientLock.Unlock()\n\n\t// Create client if needed.\n\tif n.client == nil {\n\t\tn.client = &http.Client{}\n\t}\n\n\treturn n.client\n}\n"
  },
  {
    "path": "base/config/basic_config.go",
    "content": "package config\n\nimport (\n\t\"flag\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// Configuration Keys.\nvar (\n\tCfgDevModeKey  = \"core/devMode\"\n\tdefaultDevMode bool\n\n\tCfgLogLevel     = \"core/log/level\"\n\tdefaultLogLevel = log.InfoLevel.String()\n\tlogLevel        StringOption\n)\n\nfunc init() {\n\tflag.BoolVar(&defaultDevMode, \"devmode\", false, \"enable development mode; configuration is stronger\")\n}\n\nfunc registerBasicOptions() error {\n\t// Get the default log level from the log package.\n\tdefaultLogLevel = log.GetLogLevel().Name()\n\n\t// Register logging setting.\n\t// The log package cannot do that, as it would trigger and import loop.\n\tif err := Register(&Option{\n\t\tName:           \"Log Level\",\n\t\tKey:            CfgLogLevel,\n\t\tDescription:    \"Configure the logging level.\",\n\t\tOptType:        OptTypeString,\n\t\tExpertiseLevel: ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   ReleaseLevelStable,\n\t\tDefaultValue:   defaultLogLevel,\n\t\tAnnotations: Annotations{\n\t\t\tDisplayOrderAnnotation: 513,\n\t\t\tDisplayHintAnnotation:  DisplayHintOneOf,\n\t\t\tCategoryAnnotation:     \"Development\",\n\t\t},\n\t\tPossibleValues: []PossibleValue{\n\t\t\t{\n\t\t\t\tName:        \"Critical\",\n\t\t\t\tValue:       \"critical\",\n\t\t\t\tDescription: \"The critical level only logs errors that lead to a partial, but imminent failure.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Error\",\n\t\t\t\tValue:       \"error\",\n\t\t\t\tDescription: \"The error level logs errors that potentially break functionality. Everything logged by the critical level is included here too.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Warning\",\n\t\t\t\tValue:       \"warning\",\n\t\t\t\tDescription: \"The warning level logs minor errors and worse. Everything logged by the error level is included here too.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Info\",\n\t\t\t\tValue:       \"info\",\n\t\t\t\tDescription: \"The info level logs the main events that are going on and are interesting to the user. Everything logged by the warning level is included here too.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Debug\",\n\t\t\t\tValue:       \"debug\",\n\t\t\t\tDescription: \"The debug level logs some additional debugging details. Everything logged by the info level is included here too.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Trace\",\n\t\t\t\tValue:       \"trace\",\n\t\t\t\tDescription: \"The trace level logs loads of detailed information as well as operation and request traces. Everything logged by the debug level is included here too.\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\tlogLevel = GetAsString(CfgLogLevel, defaultLogLevel)\n\n\t// Register to hook to update the log level.\n\tmodule.EventConfigChange.AddCallback(\"update log level\", setLogLevel)\n\n\treturn Register(&Option{\n\t\tName:           \"Development Mode\",\n\t\tKey:            CfgDevModeKey,\n\t\tDescription:    \"In Development Mode, security restrictions are lifted/softened to enable unrestricted access for debugging and testing purposes.\",\n\t\tOptType:        OptTypeBool,\n\t\tExpertiseLevel: ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   ReleaseLevelStable,\n\t\tDefaultValue:   defaultDevMode,\n\t\tAnnotations: Annotations{\n\t\t\tDisplayOrderAnnotation: 512,\n\t\t\tCategoryAnnotation:     \"Development\",\n\t\t},\n\t})\n}\n\nfunc loadLogLevel() error {\n\treturn setDefaultConfigOption(CfgLogLevel, log.GetLogLevel().Name(), false)\n}\n\nfunc setLogLevel(_ *mgr.WorkerCtx, _ struct{}) (cancel bool, err error) {\n\tlog.SetLogLevel(log.ParseLevel(logLevel()))\n\n\treturn false, nil\n}\n"
  },
  {
    "path": "base/config/database.go",
    "content": "package config\n\nimport (\n\t\"errors\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar dbController *database.Controller\n\n// StorageInterface provices a storage.Interface to the configuration manager.\ntype StorageInterface struct {\n\tstorage.InjectBase\n}\n\n// Get returns a database record.\nfunc (s *StorageInterface) Get(key string) (record.Record, error) {\n\topt, err := GetOption(key)\n\tif err != nil {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\treturn opt.Export()\n}\n\n// Put stores a record in the database.\nfunc (s *StorageInterface) Put(r record.Record) (record.Record, error) {\n\tif r.Meta().Deleted > 0 {\n\t\treturn r, setConfigOption(r.DatabaseKey(), nil, false)\n\t}\n\n\tacc := r.GetAccessor(r)\n\tif acc == nil {\n\t\treturn nil, errors.New(\"invalid data\")\n\t}\n\n\tval, ok := acc.Get(\"Value\")\n\tif !ok || val == nil {\n\t\terr := setConfigOption(r.DatabaseKey(), nil, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn s.Get(r.DatabaseKey())\n\t}\n\n\toption, err := GetOption(r.DatabaseKey())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar value interface{}\n\tswitch option.OptType {\n\tcase OptTypeString:\n\t\tvalue, ok = acc.GetString(\"Value\")\n\tcase OptTypeStringArray:\n\t\tvalue, ok = acc.GetStringArray(\"Value\")\n\tcase OptTypeInt:\n\t\tvalue, ok = acc.GetInt(\"Value\")\n\tcase OptTypeBool:\n\t\tvalue, ok = acc.GetBool(\"Value\")\n\tcase optTypeAny:\n\t\tok = false\n\t}\n\tif !ok {\n\t\treturn nil, errors.New(\"received invalid value in \\\"Value\\\"\")\n\t}\n\n\tif err := setConfigOption(r.DatabaseKey(), value, false); err != nil {\n\t\treturn nil, err\n\t}\n\treturn option.Export()\n}\n\n// Delete deletes a record from the database.\nfunc (s *StorageInterface) Delete(key string) error {\n\treturn setConfigOption(key, nil, false)\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (s *StorageInterface) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\tit := iterator.New()\n\tvar opts []*Option\n\tfor _, opt := range options {\n\t\tif strings.HasPrefix(opt.Key, q.DatabaseKeyPrefix()) {\n\t\t\topts = append(opts, opt)\n\t\t}\n\t}\n\n\tgo s.processQuery(it, opts)\n\n\treturn it, nil\n}\n\nfunc (s *StorageInterface) processQuery(it *iterator.Iterator, opts []*Option) {\n\tsort.Sort(sortByKey(opts))\n\n\tfor _, opt := range opts {\n\t\tr, err := opt.Export()\n\t\tif err != nil {\n\t\t\tit.Finish(err)\n\t\t\treturn\n\t\t}\n\t\tit.Next <- r\n\t}\n\n\tit.Finish(nil)\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (s *StorageInterface) ReadOnly() bool {\n\treturn false\n}\n\nfunc registerAsDatabase() error {\n\t_, err := database.Register(&database.Database{\n\t\tName:        \"config\",\n\t\tDescription: \"Configuration Manager\",\n\t\tStorageType: \"injected\",\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontroller, err := database.InjectDatabase(\"config\", &StorageInterface{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdbController = controller\n\treturn nil\n}\n\n// handleOptionUpdate updates the expertise and release level options,\n// if required, and eventually pushes a update for the option.\n// The caller must hold the option lock.\nfunc handleOptionUpdate(option *Option, push bool) {\n\tif expertiseLevelOptionFlag.IsSet() && option == expertiseLevelOption {\n\t\tupdateExpertiseLevel()\n\t}\n\n\tif releaseLevelOptionFlag.IsSet() && option == releaseLevelOption {\n\t\tupdateReleaseLevel()\n\t}\n\n\tif push {\n\t\tpushUpdate(option)\n\t}\n}\n\n// pushUpdate pushes an database update notification for option.\n// The caller must hold the option lock.\nfunc pushUpdate(option *Option) {\n\tr, err := option.export()\n\tif err != nil {\n\t\tlog.Errorf(\"failed to export option to push update: %s\", err)\n\t} else {\n\t\tdbController.PushUpdate(r)\n\t}\n}\n"
  },
  {
    "path": "base/config/doc.go",
    "content": "// Package config provides a versatile configuration management system.\npackage config\n"
  },
  {
    "path": "base/config/expertise.go",
    "content": "package config\n\nimport (\n\t\"sync/atomic\"\n\n\t\"github.com/tevino/abool\"\n)\n\n// ExpertiseLevel allows to group settings by user expertise.\n// It's useful if complex or technical settings should be hidden\n// from the average user while still allowing experts and developers\n// to change deep configuration settings.\ntype ExpertiseLevel uint8\n\n// Expertise Level constants.\nconst (\n\tExpertiseLevelUser      ExpertiseLevel = 0\n\tExpertiseLevelExpert    ExpertiseLevel = 1\n\tExpertiseLevelDeveloper ExpertiseLevel = 2\n\n\tExpertiseLevelNameUser      = \"user\"\n\tExpertiseLevelNameExpert    = \"expert\"\n\tExpertiseLevelNameDeveloper = \"developer\"\n\n\texpertiseLevelKey = \"core/expertiseLevel\"\n)\n\nvar (\n\texpertiseLevelOption     *Option\n\texpertiseLevel           = new(int32)\n\texpertiseLevelOptionFlag = abool.New()\n)\n\nfunc init() {\n\tregisterExpertiseLevelOption()\n}\n\nfunc registerExpertiseLevelOption() {\n\texpertiseLevelOption = &Option{\n\t\tName:           \"UI Mode\",\n\t\tKey:            expertiseLevelKey,\n\t\tDescription:    \"Control the default amount of settings and information shown. Hidden settings are still in effect. Can be changed temporarily in the top right corner.\",\n\t\tOptType:        OptTypeString,\n\t\tExpertiseLevel: ExpertiseLevelUser,\n\t\tReleaseLevel:   ReleaseLevelStable,\n\t\tDefaultValue:   ExpertiseLevelNameUser,\n\t\tAnnotations: Annotations{\n\t\t\tDisplayOrderAnnotation: -16,\n\t\t\tDisplayHintAnnotation:  DisplayHintOneOf,\n\t\t\tCategoryAnnotation:     \"User Interface\",\n\t\t},\n\t\tPossibleValues: []PossibleValue{\n\t\t\t{\n\t\t\t\tName:        \"Simple Interface\",\n\t\t\t\tValue:       ExpertiseLevelNameUser,\n\t\t\t\tDescription: \"Hide complex settings and information.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Advanced Interface\",\n\t\t\t\tValue:       ExpertiseLevelNameExpert,\n\t\t\t\tDescription: \"Show technical details.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Developer Interface\",\n\t\t\t\tValue:       ExpertiseLevelNameDeveloper,\n\t\t\t\tDescription: \"Developer mode. Please be careful!\",\n\t\t\t},\n\t\t},\n\t}\n\n\terr := Register(expertiseLevelOption)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\texpertiseLevelOptionFlag.Set()\n}\n\nfunc updateExpertiseLevel() {\n\t// get value\n\tvalue := expertiseLevelOption.activeFallbackValue\n\tif expertiseLevelOption.activeValue != nil {\n\t\tvalue = expertiseLevelOption.activeValue\n\t}\n\tif expertiseLevelOption.activeDefaultValue != nil {\n\t\tvalue = expertiseLevelOption.activeDefaultValue\n\t}\n\t// set atomic value\n\tswitch value.stringVal {\n\tcase ExpertiseLevelNameUser:\n\t\tatomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelUser))\n\tcase ExpertiseLevelNameExpert:\n\t\tatomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelExpert))\n\tcase ExpertiseLevelNameDeveloper:\n\t\tatomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelDeveloper))\n\tdefault:\n\t\tatomic.StoreInt32(expertiseLevel, int32(ExpertiseLevelUser))\n\t}\n}\n\n// GetExpertiseLevel returns the current active expertise level.\nfunc GetExpertiseLevel() uint8 {\n\treturn uint8(atomic.LoadInt32(expertiseLevel))\n}\n"
  },
  {
    "path": "base/config/get-safe.go",
    "content": "package config\n\nimport \"sync\"\n\ntype safe struct{}\n\n// Concurrent makes concurrency safe get methods available.\nvar Concurrent = &safe{}\n\n// GetAsString returns a function that returns the wanted string with high performance.\nfunc (cs *safe) GetAsString(name string, fallback string) StringOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeString)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.stringVal\n\t}\n\tvar lock sync.Mutex\n\n\treturn func() string {\n\t\tlock.Lock()\n\t\tdefer lock.Unlock()\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeString)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.stringVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n\n// GetAsStringArray returns a function that returns the wanted string with high performance.\nfunc (cs *safe) GetAsStringArray(name string, fallback []string) StringArrayOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeStringArray)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.stringArrayVal\n\t}\n\tvar lock sync.Mutex\n\n\treturn func() []string {\n\t\tlock.Lock()\n\t\tdefer lock.Unlock()\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeStringArray)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.stringArrayVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n\n// GetAsInt returns a function that returns the wanted int with high performance.\nfunc (cs *safe) GetAsInt(name string, fallback int64) IntOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeInt)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.intVal\n\t}\n\tvar lock sync.Mutex\n\n\treturn func() int64 {\n\t\tlock.Lock()\n\t\tdefer lock.Unlock()\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeInt)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.intVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n\n// GetAsBool returns a function that returns the wanted int with high performance.\nfunc (cs *safe) GetAsBool(name string, fallback bool) BoolOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeBool)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.boolVal\n\t}\n\tvar lock sync.Mutex\n\n\treturn func() bool {\n\t\tlock.Lock()\n\t\tdefer lock.Unlock()\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeBool)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.boolVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n"
  },
  {
    "path": "base/config/get.go",
    "content": "package config\n\nimport (\n\t\"github.com/safing/portmaster/base/log\"\n)\n\ntype (\n\t// StringOption defines the returned function by GetAsString.\n\tStringOption func() string\n\t// StringArrayOption defines the returned function by GetAsStringArray.\n\tStringArrayOption func() []string\n\t// IntOption defines the returned function by GetAsInt.\n\tIntOption func() int64\n\t// BoolOption defines the returned function by GetAsBool.\n\tBoolOption func() bool\n)\n\nfunc getValueCache(name string, option *Option, requestedType OptionType) (*Option, *valueCache) {\n\t// get option\n\tif option == nil {\n\t\tvar err error\n\t\toption, err = GetOption(name)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"config: request for unregistered option: %s\", name)\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\n\t// Check the option type, no locking required as\n\t// OptType is immutable once it is set\n\tif requestedType != option.OptType {\n\t\tlog.Errorf(\"config: bad type: requested %s as %s, but is %s\", name, getTypeName(requestedType), getTypeName(option.OptType))\n\t\treturn option, nil\n\t}\n\n\toption.Lock()\n\tdefer option.Unlock()\n\n\t// check release level\n\tif option.ReleaseLevel <= getReleaseLevel() && option.activeValue != nil {\n\t\treturn option, option.activeValue\n\t}\n\n\tif option.activeDefaultValue != nil {\n\t\treturn option, option.activeDefaultValue\n\t}\n\n\treturn option, option.activeFallbackValue\n}\n\n// GetAsString returns a function that returns the wanted string with high performance.\nfunc GetAsString(name string, fallback string) StringOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeString)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.stringVal\n\t}\n\n\treturn func() string {\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeString)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.stringVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n\n// GetAsStringArray returns a function that returns the wanted string with high performance.\nfunc GetAsStringArray(name string, fallback []string) StringArrayOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeStringArray)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.stringArrayVal\n\t}\n\n\treturn func() []string {\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeStringArray)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.stringArrayVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n\n// GetAsInt returns a function that returns the wanted int with high performance.\nfunc GetAsInt(name string, fallback int64) IntOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeInt)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.intVal\n\t}\n\n\treturn func() int64 {\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeInt)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.intVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n\n// GetAsBool returns a function that returns the wanted int with high performance.\nfunc GetAsBool(name string, fallback bool) BoolOption {\n\tvalid := getValidityFlag()\n\toption, valueCache := getValueCache(name, nil, OptTypeBool)\n\tvalue := fallback\n\tif valueCache != nil {\n\t\tvalue = valueCache.boolVal\n\t}\n\n\treturn func() bool {\n\t\tif !valid.IsSet() {\n\t\t\tvalid = getValidityFlag()\n\t\t\toption, valueCache = getValueCache(name, option, OptTypeBool)\n\t\t\tif valueCache != nil {\n\t\t\t\tvalue = valueCache.boolVal\n\t\t\t} else {\n\t\t\t\tvalue = fallback\n\t\t\t}\n\t\t}\n\t\treturn value\n\t}\n}\n\n/*\nfunc getAndFindValue(key string) interface{} {\n\toptionsLock.RLock()\n\toption, ok := options[key]\n\toptionsLock.RUnlock()\n\tif !ok {\n\t\tlog.Errorf(\"config: request for unregistered option: %s\", key)\n\t\treturn nil\n\t}\n\n\treturn option.findValue()\n}\n*/\n\n/*\n// findValue finds the preferred value in the user or default config.\nfunc (option *Option) findValue() interface{} {\n\t// lock option\n\toption.Lock()\n\tdefer option.Unlock()\n\n\tif option.ReleaseLevel <= getReleaseLevel() && option.activeValue != nil {\n\t\treturn option.activeValue\n\t}\n\n\tif option.activeDefaultValue != nil {\n\t\treturn option.activeDefaultValue\n\t}\n\n\treturn option.DefaultValue\n}\n*/\n"
  },
  {
    "path": "base/config/get_test.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nfunc parseAndReplaceConfig(jsonData string) error {\n\tm, err := JSONToMap([]byte(jsonData))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvalidationErrors, _ := ReplaceConfig(m)\n\tif len(validationErrors) > 0 {\n\t\treturn fmt.Errorf(\"%d errors, first: %w\", len(validationErrors), validationErrors[0])\n\t}\n\treturn nil\n}\n\nfunc parseAndReplaceDefaultConfig(jsonData string) error {\n\tm, err := JSONToMap([]byte(jsonData))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvalidationErrors, _ := ReplaceDefaultConfig(m)\n\tif len(validationErrors) > 0 {\n\t\treturn fmt.Errorf(\"%d errors, first: %w\", len(validationErrors), validationErrors[0])\n\t}\n\treturn nil\n}\n\nfunc quickRegister(t *testing.T, key string, optType OptionType, defaultValue interface{}) {\n\tt.Helper()\n\n\terr := Register(&Option{\n\t\tName:           key,\n\t\tKey:            key,\n\t\tDescription:    \"test config\",\n\t\tReleaseLevel:   ReleaseLevelStable,\n\t\tExpertiseLevel: ExpertiseLevelUser,\n\t\tOptType:        optType,\n\t\tDefaultValue:   defaultValue,\n\t})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc TestGet(t *testing.T) { //nolint:paralleltest\n\t// reset\n\toptions = make(map[string]*Option)\n\n\terr := log.Start(\"info\", true, \"\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tquickRegister(t, \"monkey\", OptTypeString, \"c\")\n\tquickRegister(t, \"zebras/zebra\", OptTypeStringArray, []string{\"a\", \"b\"})\n\tquickRegister(t, \"elephant\", OptTypeInt, -1)\n\tquickRegister(t, \"hot\", OptTypeBool, false)\n\tquickRegister(t, \"cold\", OptTypeBool, true)\n\n\terr = parseAndReplaceConfig(`\n\t{\n\t\t\"monkey\": \"a\",\n\t\t\"zebras\": {\n\t\t\t\"zebra\": [\"black\", \"white\"]\n\t\t},\n\t\t\"elephant\": 2,\n\t\t\"hot\": true,\n\t\t\"cold\": false\n\t}\n\t`)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = parseAndReplaceDefaultConfig(`\n\t{\n\t\t\"monkey\": \"b\",\n\t\t\"snake\": \"0\",\n\t\t\"elephant\": 0\n\t}\n\t`)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tmonkey := GetAsString(\"monkey\", \"none\")\n\tif monkey() != \"a\" {\n\t\tt.Errorf(\"monkey should be a, is %s\", monkey())\n\t}\n\n\tzebra := GetAsStringArray(\"zebras/zebra\", []string{})\n\tif len(zebra()) != 2 || zebra()[0] != \"black\" || zebra()[1] != \"white\" {\n\t\tt.Errorf(\"zebra should be [\\\"black\\\", \\\"white\\\"], is %v\", zebra())\n\t}\n\n\telephant := GetAsInt(\"elephant\", -1)\n\tif elephant() != 2 {\n\t\tt.Errorf(\"elephant should be 2, is %d\", elephant())\n\t}\n\n\thot := GetAsBool(\"hot\", false)\n\tif !hot() {\n\t\tt.Errorf(\"hot should be true, is %v\", hot())\n\t}\n\n\tcold := GetAsBool(\"cold\", true)\n\tif cold() {\n\t\tt.Errorf(\"cold should be false, is %v\", cold())\n\t}\n\n\terr = parseAndReplaceConfig(`\n\t{\n\t\t\"monkey\": \"3\"\n\t}\n\t`)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif monkey() != \"3\" {\n\t\tt.Errorf(\"monkey should be 0, is %s\", monkey())\n\t}\n\n\tif elephant() != 0 {\n\t\tt.Errorf(\"elephant should be 0, is %d\", elephant())\n\t}\n\n\tzebra()\n\thot()\n\n\t// concurrent\n\tGetAsString(\"monkey\", \"none\")()\n\tGetAsStringArray(\"zebras/zebra\", []string{})()\n\tGetAsInt(\"elephant\", -1)()\n\tGetAsBool(\"hot\", false)()\n\n\t// perspective\n\n\t// load data\n\tpLoaded := make(map[string]interface{})\n\terr = json.Unmarshal([]byte(`{\n\t\t\"monkey\": \"a\",\n\t\t\"zebras\": {\n\t\t\t\"zebra\": [\"black\", \"white\"]\n\t\t},\n\t\t\"elephant\": 2,\n\t\t\"hot\": true,\n\t\t\"cold\": false\n\t}`), &pLoaded)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// create\n\tp, err := NewPerspective(pLoaded)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tmonkeyVal, ok := p.GetAsString(\"monkey\")\n\tif !ok || monkeyVal != \"a\" {\n\t\tt.Errorf(\"[perspective] monkey should be a, is %+v\", monkeyVal)\n\t}\n\n\tzebraVal, ok := p.GetAsStringArray(\"zebras/zebra\")\n\tif !ok || len(zebraVal) != 2 || zebraVal[0] != \"black\" || zebraVal[1] != \"white\" {\n\t\tt.Errorf(\"[perspective] zebra should be [\\\"black\\\", \\\"white\\\"], is %+v\", zebraVal)\n\t}\n\n\telephantVal, ok := p.GetAsInt(\"elephant\")\n\tif !ok || elephantVal != 2 {\n\t\tt.Errorf(\"[perspective] elephant should be 2, is %+v\", elephantVal)\n\t}\n\n\thotVal, ok := p.GetAsBool(\"hot\")\n\tif !ok || !hotVal {\n\t\tt.Errorf(\"[perspective] hot should be true, is %+v\", hotVal)\n\t}\n\n\tcoldVal, ok := p.GetAsBool(\"cold\")\n\tif !ok || coldVal {\n\t\tt.Errorf(\"[perspective] cold should be false, is %+v\", coldVal)\n\t}\n}\n\nfunc TestReleaseLevel(t *testing.T) { //nolint:paralleltest\n\t// reset\n\toptions = make(map[string]*Option)\n\tregisterReleaseLevelOption()\n\n\t// setup\n\tsubsystemOption := &Option{\n\t\tName:           \"test subsystem\",\n\t\tKey:            \"subsystem/test\",\n\t\tDescription:    \"test config\",\n\t\tReleaseLevel:   ReleaseLevelStable,\n\t\tExpertiseLevel: ExpertiseLevelUser,\n\t\tOptType:        OptTypeBool,\n\t\tDefaultValue:   false,\n\t}\n\terr := Register(subsystemOption)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\terr = SetConfigOption(\"subsystem/test\", true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttestSubsystem := GetAsBool(\"subsystem/test\", false)\n\n\t// test option level stable\n\tsubsystemOption.ReleaseLevel = ReleaseLevelStable\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameStable)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !testSubsystem() {\n\t\tt.Error(\"should be active\")\n\t}\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameBeta)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !testSubsystem() {\n\t\tt.Error(\"should be active\")\n\t}\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameExperimental)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !testSubsystem() {\n\t\tt.Error(\"should be active\")\n\t}\n\n\t// test option level beta\n\tsubsystemOption.ReleaseLevel = ReleaseLevelBeta\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameStable)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif testSubsystem() {\n\t\tt.Errorf(\"should be inactive: opt=%d system=%d\", subsystemOption.ReleaseLevel, getReleaseLevel())\n\t}\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameBeta)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !testSubsystem() {\n\t\tt.Error(\"should be active\")\n\t}\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameExperimental)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !testSubsystem() {\n\t\tt.Error(\"should be active\")\n\t}\n\n\t// test option level experimental\n\tsubsystemOption.ReleaseLevel = ReleaseLevelExperimental\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameStable)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif testSubsystem() {\n\t\tt.Error(\"should be inactive\")\n\t}\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameBeta)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif testSubsystem() {\n\t\tt.Error(\"should be inactive\")\n\t}\n\terr = SetConfigOption(releaseLevelKey, ReleaseLevelNameExperimental)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !testSubsystem() {\n\t\tt.Error(\"should be active\")\n\t}\n}\n\nfunc BenchmarkGetAsStringCached(b *testing.B) {\n\t// reset\n\toptions = make(map[string]*Option)\n\n\t// Setup\n\terr := parseAndReplaceConfig(`{\n\t\t\"monkey\": \"banana\"\n\t}`)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tmonkey := GetAsString(\"monkey\", \"no banana\")\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\tmonkey()\n\t}\n}\n\nfunc BenchmarkGetAsStringRefetch(b *testing.B) {\n\t// Setup\n\terr := parseAndReplaceConfig(`{\n\t\t\"monkey\": \"banana\"\n\t}`)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\tgetValueCache(\"monkey\", nil, OptTypeString)\n\t}\n}\n\nfunc BenchmarkGetAsIntCached(b *testing.B) {\n\t// Setup\n\terr := parseAndReplaceConfig(`{\n\t\t\"elephant\": 1\n\t}`)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\telephant := GetAsInt(\"elephant\", -1)\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\telephant()\n\t}\n}\n\nfunc BenchmarkGetAsIntRefetch(b *testing.B) {\n\t// Setup\n\terr := parseAndReplaceConfig(`{\n\t\t\"elephant\": 1\n\t}`)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\tgetValueCache(\"elephant\", nil, OptTypeInt)\n\t}\n}\n"
  },
  {
    "path": "base/config/init_test.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n)\n\ntype testInstance struct {\n\tdataDir string\n}\n\nvar _ instance = testInstance{}\n\nfunc (stub testInstance) DataDir() string {\n\treturn stub.dataDir\n}\n\nfunc (stub testInstance) SetCmdLineOperation(f func() error) {}\n\nfunc newTestInstance(testName string) (*testInstance, error) {\n\ttestDir, err := os.MkdirTemp(\"\", fmt.Sprintf(\"portmaster-%s\", testName))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to make tmp dir: %w\", err)\n\t}\n\n\treturn &testInstance{\n\t\tdataDir: testDir,\n\t}, nil\n}\n\nfunc TestMain(m *testing.M) {\n\tinstance, err := newTestInstance(\"test-config\")\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"failed to create test instance: %w\", err))\n\t}\n\tdefer func() { _ = os.RemoveAll(instance.DataDir()) }()\n\n\tmodule, err = New(instance)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"failed to initialize module: %w\", err))\n\t}\n\n\tm.Run()\n}\n\nfunc TestConfigPersistence(t *testing.T) { //nolint:paralleltest\n\terr := SaveConfig()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = loadConfig(true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "base/config/main.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// ChangeEvent is the name of the config change event.\nconst ChangeEvent = \"config change\"\n\nvar exportConfig bool\n\nfunc init() {\n\tflag.BoolVar(&exportConfig, \"export-config-options\", false, \"export configuration registry and exit\")\n}\n\nfunc prep() error {\n\tif exportConfig {\n\t\tmodule.instance.SetCmdLineOperation(exportConfigCmd)\n\t\treturn mgr.ErrExecuteCmdLineOp\n\t}\n\n\treturn registerBasicOptions()\n}\n\n// true - when config is initialized (from disk). So no new options can be registered anymore.\nvar cfgInitialized atomic.Bool\n\nfunc start() error {\n\tconfigFilePath = filepath.Join(module.instance.DataDir(), \"config.json\")\n\n\t// Load log level from log package after it started.\n\terr := loadLogLevel()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = registerAsDatabase()\n\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\treturn err\n\t}\n\n\t// mark config as loaded, so that options can react on this in their registration and prevent registration of options after loading.\n\tcfgInitialized.Store(true)\n\n\terr = loadConfig(false)\n\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\treturn fmt.Errorf(\"failed to load config file: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc exportConfigCmd() error {\n\t// Reset the metrics instance name option, as the default\n\t// is set to the current hostname.\n\t// Config key copied from metrics.CfgOptionInstanceKey.\n\toption, err := GetOption(\"core/metrics/instance\")\n\tif err == nil {\n\t\toption.DefaultValue = \"\"\n\t}\n\n\tdata, err := json.MarshalIndent(ExportOptions(), \"\", \"  \")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = os.Stdout.Write(data)\n\treturn err\n}\n\n// AddToDebugInfo adds all changed global config options to the given debug.Info.\nfunc AddToDebugInfo(di *debug.Info) {\n\tvar lines []string\n\n\t// Collect all changed settings.\n\t_ = ForEachOption(func(opt *Option) error {\n\t\topt.Lock()\n\t\tdefer opt.Unlock()\n\n\t\tif opt.ReleaseLevel <= getReleaseLevel() && opt.activeValue != nil {\n\t\t\tif opt.Sensitive {\n\t\t\t\tlines = append(lines, fmt.Sprintf(\"%s: [redacted]\", opt.Key))\n\t\t\t} else {\n\t\t\t\tlines = append(lines, fmt.Sprintf(\"%s: %v\", opt.Key, opt.activeValue.getData(opt)))\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n\tsort.Strings(lines)\n\n\t// Add data as section.\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Config: %d\", len(lines)),\n\t\tdebug.UseCodeSection|debug.AddContentLineBreaks,\n\t\tlines...,\n\t)\n}\n\n// GetActiveConfigValues returns a map with the active config values.\nfunc GetActiveConfigValues() map[string]interface{} {\n\tvalues := make(map[string]interface{})\n\n\t// Collect active values from options.\n\t_ = ForEachOption(func(opt *Option) error {\n\t\topt.Lock()\n\t\tdefer opt.Unlock()\n\n\t\tif opt.ReleaseLevel <= getReleaseLevel() && opt.activeValue != nil {\n\t\t\tvalues[opt.Key] = opt.activeValue.getData(opt)\n\t\t}\n\n\t\treturn nil\n\t})\n\n\treturn values\n}\n"
  },
  {
    "path": "base/config/module.go",
    "content": "package config\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// Config provides configuration mgmt.\ntype Config struct {\n\tmgr *mgr.Manager\n\n\tinstance instance\n\n\tEventConfigChange *mgr.EventMgr[struct{}]\n}\n\n// Manager returns the module's manager.\nfunc (u *Config) Manager() *mgr.Manager {\n\treturn u.mgr\n}\n\n// Start starts the module.\nfunc (u *Config) Start() error {\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (u *Config) Stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *Config\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Config module.\nfunc New(instance instance) (*Config, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Config\")\n\tmodule = &Config{\n\t\tmgr:               m,\n\t\tinstance:          instance,\n\t\tEventConfigChange: mgr.NewEventMgr[struct{}](ChangeEvent, m),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tDataDir() string\n\tSetCmdLineOperation(f func() error)\n}\n"
  },
  {
    "path": "base/config/option.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"sync\"\n\n\t\"github.com/mitchellh/copystructure\"\n\t\"github.com/tidwall/sjson\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// OptionType defines the value type of an option.\ntype OptionType uint8\n\n// Various attribute options. Use ExternalOptType for extended types in the frontend.\nconst (\n\toptTypeAny         OptionType = 0\n\tOptTypeString      OptionType = 1\n\tOptTypeStringArray OptionType = 2\n\tOptTypeInt         OptionType = 3\n\tOptTypeBool        OptionType = 4\n)\n\nfunc getTypeName(t OptionType) string {\n\tswitch t {\n\tcase optTypeAny:\n\t\treturn \"any\"\n\tcase OptTypeString:\n\t\treturn \"string\"\n\tcase OptTypeStringArray:\n\t\treturn \"[]string\"\n\tcase OptTypeInt:\n\t\treturn \"int\"\n\tcase OptTypeBool:\n\t\treturn \"bool\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n\n// PossibleValue defines a value that is possible for\n// a configuration setting.\ntype PossibleValue struct {\n\t// Name is a human readable name of the option.\n\tName string\n\t// Description is a human readable description of\n\t// this value.\n\tDescription string\n\t// Value is the actual value of the option. The type\n\t// must match the option's value type.\n\tValue interface{}\n}\n\n// Annotations can be attached to configuration options to\n// provide hints for user interfaces or other systems working\n// or setting configuration options.\n// Annotation keys should follow the below format to ensure\n// future well-known annotation additions do not conflict\n// with vendor/product/package specific annoations.\n//\n// Format: <vendor/package>:<scope>:<identifier> //.\ntype Annotations map[string]interface{}\n\n// MigrationFunc is a function that migrates a config option value.\ntype MigrationFunc func(option *Option, value any) any\n\n// Well known annotations defined by this package.\nconst (\n\t// DisplayHintAnnotation provides a hint for the user\n\t// interface on how to render an option.\n\t// The value of DisplayHintAnnotation is expected to\n\t// be a string. See DisplayHintXXXX constants below\n\t// for a list of well-known display hint annotations.\n\tDisplayHintAnnotation = \"safing/portbase:ui:display-hint\"\n\t// DisplayOrderAnnotation provides a hint for the user\n\t// interface in which order settings should be displayed.\n\t// The value of DisplayOrderAnnotations is expected to be\n\t// an number (int).\n\tDisplayOrderAnnotation = \"safing/portbase:ui:order\"\n\t// UnitAnnotations defines the SI unit of an option (if any).\n\tUnitAnnotation = \"safing/portbase:ui:unit\"\n\t// CategoryAnnotations can provide an additional category\n\t// to each settings. This category can be used by a user\n\t// interface to group certain options together.\n\t// User interfaces should treat a CategoryAnnotation, if\n\t// supported, with higher priority as a DisplayOrderAnnotation.\n\tCategoryAnnotation = \"safing/portbase:ui:category\"\n\t// SubsystemAnnotation can be used to mark an option as part\n\t// of a module subsystem.\n\tSubsystemAnnotation = \"safing/portbase:module:subsystem\"\n\t// StackableAnnotation can be set on configuration options that\n\t// stack on top of the default (or otherwise related) options.\n\t// The value of StackableAnnotaiton is expected to be a boolean but\n\t// may be extended to hold references to other options in the\n\t// future.\n\tStackableAnnotation = \"safing/portbase:options:stackable\"\n\t// RestartPendingAnnotation is automatically set on a configuration option\n\t// that requires a restart and has been changed.\n\t// The value must always be a boolean with value \"true\".\n\tRestartPendingAnnotation = \"safing/portbase:options:restart-pending\"\n\t// QuickSettingAnnotation can be used to add quick settings to\n\t// a configuration option. A quick setting can support the user\n\t// by switching between pre-configured values.\n\t// The type of a quick-setting annotation is []QuickSetting or QuickSetting.\n\tQuickSettingsAnnotation = \"safing/portbase:ui:quick-setting\"\n\t// RequiresAnnotation can be used to mark another option as a\n\t// requirement. The type of RequiresAnnotation is []ValueRequirement\n\t// or ValueRequirement.\n\tRequiresAnnotation = \"safing/portbase:config:requires\"\n\t// RequiresFeatureIDAnnotation can be used to mark a setting as only available\n\t// when the user has a certain feature ID in the subscription plan.\n\t// The type is []string or string.\n\tRequiresFeatureIDAnnotation = \"safing/portmaster:ui:config:requires-feature\"\n\t// SettablePerAppAnnotation can be used to mark a setting as settable per-app and\n\t// is a boolean.\n\tSettablePerAppAnnotation = \"safing/portmaster:settable-per-app\"\n\t// RequiresUIReloadAnnotation can be used to inform the UI that changing the value\n\t// of the annotated setting requires a full reload of the user interface.\n\t// The value of this annotation does not matter as the sole presence of\n\t// the annotation key is enough. Though, users are advised to set the value\n\t// of this annotation to true.\n\tRequiresUIReloadAnnotation = \"safing/portmaster:ui:requires-reload\"\n)\n\n// QuickSettingsAction defines the action of a quick setting.\ntype QuickSettingsAction string\n\nconst (\n\t// QuickReplace replaces the current setting with the one from\n\t// the quick setting.\n\tQuickReplace = QuickSettingsAction(\"replace\")\n\t// QuickMergeTop merges the value of the quick setting with the\n\t// already configured one adding new values on the top. Merging\n\t// is only supported for OptTypeStringArray.\n\tQuickMergeTop = QuickSettingsAction(\"merge-top\")\n\t// QuickMergeBottom merges the value of the quick setting with the\n\t// already configured one adding new values at the bottom. Merging\n\t// is only supported for OptTypeStringArray.\n\tQuickMergeBottom = QuickSettingsAction(\"merge-bottom\")\n)\n\n// QuickSetting defines a quick setting for a configuration option and\n// should be used together with the QuickSettingsAnnotation.\ntype QuickSetting struct {\n\t// Name is the name of the quick setting.\n\tName string\n\n\t// Value is the value that the quick-setting configures. It must match\n\t// the expected value type of the annotated option.\n\tValue interface{}\n\n\t// Action defines the action of the quick setting.\n\tAction QuickSettingsAction\n}\n\n// ValueRequirement defines a requirement on another configuration option.\ntype ValueRequirement struct {\n\t// Key is the key of the configuration option that is required.\n\tKey string\n\n\t// Value that is required.\n\tValue interface{}\n}\n\n// Values for the DisplayHintAnnotation.\nconst (\n\t// DisplayHintOneOf is used to mark an option\n\t// as a \"select\"-style option. That is, only one of\n\t// the supported values may be set. This option makes\n\t// only sense together with the PossibleValues property\n\t// of Option.\n\tDisplayHintOneOf = \"one-of\"\n\t// DisplayHintOrdered is used to mark a list option as ordered.\n\t// That is, the order of items is important and a user interface\n\t// is encouraged to provide the user with re-ordering support\n\t// (like drag'n'drop).\n\tDisplayHintOrdered = \"ordered\"\n\t// DisplayHintFilePicker is used to mark the option as being a file, which\n\t// should give the option to use a file picker to select a local file from disk.\n\tDisplayHintFilePicker = \"file-picker\"\n)\n\n// Option describes a configuration option.\ntype Option struct {\n\tsync.Mutex\n\t// Name holds the name of the configuration options.\n\t// It should be human readable and is mainly used for\n\t// presentation purposes.\n\t// Name is considered immutable after the option has\n\t// been created.\n\tName string\n\t// Key holds the database path for the option. It should\n\t// follow the path format `category/sub/key`.\n\t// Key is considered immutable after the option has\n\t// been created.\n\tKey string\n\t// Description holds a human readable description of the\n\t// option and what is does. The description should be short.\n\t// Use the Help property for a longer support text.\n\t// Description is considered immutable after the option has\n\t// been created.\n\tDescription string\n\t// Help may hold a long version of the description providing\n\t// assistance with the configuration option.\n\t// Help is considered immutable after the option has\n\t// been created.\n\tHelp string\n\t// Sensitive signifies that the configuration values may contain sensitive\n\t// content, such as authentication keys.\n\tSensitive bool\n\t// OptType defines the type of the option.\n\t// OptType is considered immutable after the option has\n\t// been created.\n\tOptType OptionType\n\t// ExpertiseLevel can be used to set the required expertise\n\t// level for the option to be displayed to a user.\n\t// ExpertiseLevel is considered immutable after the option has\n\t// been created.\n\tExpertiseLevel ExpertiseLevel\n\t// ReleaseLevel is used to mark the stability of the option.\n\t// ReleaseLevel is considered immutable after the option has\n\t// been created.\n\tReleaseLevel ReleaseLevel\n\t// RequiresRestart should be set to true if a modification of\n\t// the options value requires a restart of the whole application\n\t// to take effect.\n\t// RequiresRestart is considered immutable after the option has\n\t// been created.\n\tRequiresRestart bool\n\t// DefaultValue holds the default value of the option. Note that\n\t// this value can be overwritten during runtime (see activeDefaultValue\n\t// and activeFallbackValue).\n\t// DefaultValue is considered immutable after the option has\n\t// been created.\n\tDefaultValue interface{}\n\t// ValidationRegex may contain a regular expression used to validate\n\t// the value of option. If the option type is set to OptTypeStringArray\n\t// the validation regex is applied to all entries of the string slice.\n\t// Note that it is recommended to keep the validation regex simple so\n\t// it can also be used in other languages (mainly JavaScript) to provide\n\t// a better user-experience by pre-validating the expression.\n\t// ValidationRegex is considered immutable after the option has\n\t// been created.\n\tValidationRegex string\n\t// ValidationFunc may contain a function to validate more complex values.\n\t// The error is returned beyond the scope of this package and may be\n\t// displayed to a user.\n\tValidationFunc func(value interface{}) error `json:\"-\"`\n\t// PossibleValues may be set to a slice of values that are allowed\n\t// for this configuration setting. Note that PossibleValues makes most\n\t// sense when ExternalOptType is set to HintOneOf\n\t// PossibleValues is considered immutable after the option has\n\t// been created.\n\tPossibleValues []PossibleValue `json:\",omitempty\"`\n\t// Annotations adds additional annotations to the configuration options.\n\t// See documentation of Annotations for more information.\n\t// Annotations is considered mutable and setting/reading annotation keys\n\t// must be performed while the option is locked.\n\tAnnotations Annotations\n\t// Migrations holds migration functions that are given the raw option value\n\t// before any validation is run. The returned value is then used.\n\tMigrations []MigrationFunc `json:\"-\"`\n\n\tactiveValue         *valueCache // runtime value (loaded from config file or set by user)\n\tactiveDefaultValue  *valueCache // runtime default value (may be set internally)\n\tactiveFallbackValue *valueCache // default value from option registration\n\tcompiledRegex       *regexp.Regexp\n}\n\n// AddAnnotation adds the annotation key to option if it's not already set.\nfunc (option *Option) AddAnnotation(key string, value interface{}) {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\tif option.Annotations == nil {\n\t\toption.Annotations = make(Annotations)\n\t}\n\n\tif _, ok := option.Annotations[key]; ok {\n\t\treturn\n\t}\n\toption.Annotations[key] = value\n}\n\n// SetAnnotation sets the value of the annotation key overwritting an\n// existing value if required.\nfunc (option *Option) SetAnnotation(key string, value interface{}) {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\toption.setAnnotation(key, value)\n}\n\n// setAnnotation sets the value of the annotation key overwritting an\n// existing value if required. Does not lock the Option.\nfunc (option *Option) setAnnotation(key string, value interface{}) {\n\tif option.Annotations == nil {\n\t\toption.Annotations = make(Annotations)\n\t}\n\toption.Annotations[key] = value\n}\n\n// GetAnnotation returns the value of the annotation key.\nfunc (option *Option) GetAnnotation(key string) (interface{}, bool) {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\tif option.Annotations == nil {\n\t\treturn nil, false\n\t}\n\tval, ok := option.Annotations[key]\n\treturn val, ok\n}\n\n// AnnotationEquals returns whether the annotation of the given key matches the\n// given value.\nfunc (option *Option) AnnotationEquals(key string, value any) bool {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\tif option.Annotations == nil {\n\t\treturn false\n\t}\n\tsetValue, ok := option.Annotations[key]\n\tif !ok {\n\t\treturn false\n\t}\n\treturn reflect.DeepEqual(value, setValue)\n}\n\n// copyOrNil returns a copy of the option, or nil if copying failed.\nfunc (option *Option) copyOrNil() *Option {\n\tcopied, err := copystructure.Copy(option)\n\tif err != nil {\n\t\treturn nil\n\t}\n\treturn copied.(*Option) //nolint:forcetypeassert\n}\n\n// IsSetByUser returns whether the option has been set by the user.\nfunc (option *Option) IsSetByUser() bool {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\treturn option.activeValue != nil\n}\n\n// UserValue returns the value set by the user or nil if the value has not\n// been changed from the default.\nfunc (option *Option) UserValue() any {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\tif option.activeValue == nil {\n\t\treturn nil\n\t}\n\treturn option.activeValue.getData(option)\n}\n\n// ValidateValue checks if the given value is valid for the option.\nfunc (option *Option) ValidateValue(value any) error {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\tvalue = migrateValue(option, value)\n\tif _, err := validateValue(option, value); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Export expors an option to a Record.\nfunc (option *Option) Export() (record.Record, error) {\n\toption.Lock()\n\tdefer option.Unlock()\n\n\treturn option.export()\n}\n\nfunc (option *Option) export() (record.Record, error) {\n\tdata, err := json.Marshal(option)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif option.activeValue != nil {\n\t\tdata, err = sjson.SetBytes(data, \"Value\", option.activeValue.getData(option))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif option.activeDefaultValue != nil {\n\t\tdata, err = sjson.SetBytes(data, \"DefaultValue\", option.activeDefaultValue.getData(option))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tr, err := record.NewWrapper(fmt.Sprintf(\"config:%s\", option.Key), nil, dsd.JSON, data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tr.SetMeta(&record.Meta{})\n\n\treturn r, nil\n}\n\ntype sortByKey []*Option\n\nfunc (opts sortByKey) Len() int           { return len(opts) }\nfunc (opts sortByKey) Less(i, j int) bool { return opts[i].Key < opts[j].Key }\nfunc (opts sortByKey) Swap(i, j int)      { opts[i], opts[j] = opts[j], opts[i] }\n"
  },
  {
    "path": "base/config/persistence.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\tconfigFilePath string\n\n\tloadedConfigValidationErrors     []*ValidationError\n\tloadedConfigValidationErrorsLock sync.Mutex\n)\n\n// GetLoadedConfigValidationErrors returns the encountered validation errors\n// from the last time loading config from disk.\nfunc GetLoadedConfigValidationErrors() []*ValidationError {\n\tloadedConfigValidationErrorsLock.Lock()\n\tdefer loadedConfigValidationErrorsLock.Unlock()\n\n\treturn loadedConfigValidationErrors\n}\n\nfunc loadConfig(requireValidConfig bool) error {\n\t// check if persistence is configured\n\tif configFilePath == \"\" {\n\t\treturn nil\n\t}\n\n\t// read config file\n\tdata, err := os.ReadFile(configFilePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// convert to map\n\tnewValues, err := JSONToMap(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvalidationErrors, _ := ReplaceConfig(newValues)\n\tif requireValidConfig && len(validationErrors) > 0 {\n\t\treturn fmt.Errorf(\"encountered %d validation errors during config loading\", len(validationErrors))\n\t}\n\n\t// Save validation errors.\n\tloadedConfigValidationErrorsLock.Lock()\n\tdefer loadedConfigValidationErrorsLock.Unlock()\n\tloadedConfigValidationErrors = validationErrors\n\n\treturn nil\n}\n\n// SaveConfig saves the current configuration to file.\n// It will acquire a read-lock on the global options registry\n// lock and must lock each option!\nfunc SaveConfig() error {\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\t// check if persistence is configured\n\tif configFilePath == \"\" {\n\t\treturn nil\n\t}\n\n\t// extract values\n\tactiveValues := make(map[string]interface{})\n\tfor key, option := range options {\n\t\t// we cannot immedately unlock the option afger\n\t\t// getData() because someone could lock and change it\n\t\t// while we are marshaling the value (i.e. for string slices).\n\t\t// We NEED to keep the option locks until we finsihed.\n\t\toption.Lock()\n\t\tdefer option.Unlock()\n\n\t\tif option.activeValue != nil {\n\t\t\tactiveValues[key] = option.activeValue.getData(option)\n\t\t}\n\t}\n\n\t// convert to JSON\n\tdata, err := MapToJSON(activeValues)\n\tif err != nil {\n\t\tlog.Errorf(\"config: failed to save config: %s\", err)\n\t\treturn err\n\t}\n\n\t// write file\n\treturn os.WriteFile(configFilePath, data, 0o0600)\n}\n\n// JSONToMap parses and flattens a hierarchical json object.\nfunc JSONToMap(jsonData []byte) (map[string]interface{}, error) {\n\tloaded := make(map[string]interface{})\n\terr := json.Unmarshal(jsonData, &loaded)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn Flatten(loaded), nil\n}\n\n// Flatten returns a flattened copy of the given hierarchical config.\nfunc Flatten(config map[string]interface{}) (flattenedConfig map[string]interface{}) {\n\tflattenedConfig = make(map[string]interface{})\n\tflattenMap(flattenedConfig, config, \"\")\n\treturn flattenedConfig\n}\n\nfunc flattenMap(rootMap, subMap map[string]interface{}, subKey string) {\n\tfor key, entry := range subMap {\n\n\t\t// get next level key\n\t\tsubbedKey := path.Join(subKey, key)\n\n\t\t// check for next subMap\n\t\tnextSub, ok := entry.(map[string]interface{})\n\t\tif ok {\n\t\t\tflattenMap(rootMap, nextSub, subbedKey)\n\t\t} else {\n\t\t\t// only set if not on root level\n\t\t\trootMap[subbedKey] = entry\n\t\t}\n\t}\n}\n\n// MapToJSON expands a flattened map and returns it as json.\nfunc MapToJSON(config map[string]interface{}) ([]byte, error) {\n\treturn json.MarshalIndent(Expand(config), \"\", \"  \")\n}\n\n// Expand returns a hierarchical copy of the given flattened config.\nfunc Expand(flattenedConfig map[string]interface{}) (config map[string]interface{}) {\n\tconfig = make(map[string]interface{})\n\tfor key, entry := range flattenedConfig {\n\t\tPutValueIntoHierarchicalConfig(config, key, entry)\n\t}\n\treturn config\n}\n\n// PutValueIntoHierarchicalConfig injects a configuration entry into an hierarchical config map. Conflicting entries will be replaced.\nfunc PutValueIntoHierarchicalConfig(config map[string]interface{}, key string, value interface{}) {\n\tparts := strings.Split(key, \"/\")\n\n\t// create/check maps for all parts except the last one\n\tsubMap := config\n\tfor i, part := range parts {\n\t\tif i == len(parts)-1 {\n\t\t\t// do not process the last part,\n\t\t\t// which is not a map, but the value key itself\n\t\t\tbreak\n\t\t}\n\n\t\tvar nextSubMap map[string]interface{}\n\t\t// get value\n\t\tvalue, ok := subMap[part]\n\t\tif !ok {\n\t\t\t// create new map and assign it\n\t\t\tnextSubMap = make(map[string]interface{})\n\t\t\tsubMap[part] = nextSubMap\n\t\t} else {\n\t\t\tnextSubMap, ok = value.(map[string]interface{})\n\t\t\tif !ok {\n\t\t\t\t// create new map and assign it\n\t\t\t\tnextSubMap = make(map[string]interface{})\n\t\t\t\tsubMap[part] = nextSubMap\n\t\t\t}\n\t\t}\n\n\t\t// assign for next parts loop\n\t\tsubMap = nextSubMap\n\t}\n\n\t// assign value to last submap\n\tsubMap[parts[len(parts)-1]] = value\n}\n\n// CleanFlattenedConfig removes all inexistent configuration options from the given flattened config map.\nfunc CleanFlattenedConfig(flattenedConfig map[string]interface{}) {\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\tfor key := range flattenedConfig {\n\t\t_, ok := options[key]\n\t\tif !ok {\n\t\t\tdelete(flattenedConfig, key)\n\t\t}\n\t}\n}\n\n// CleanHierarchicalConfig removes all inexistent configuration options from the given hierarchical config map.\nfunc CleanHierarchicalConfig(config map[string]interface{}) {\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\tcleanSubMap(config, \"\")\n}\n\nfunc cleanSubMap(subMap map[string]interface{}, subKey string) (empty bool) {\n\tvar foundValid int\n\tfor key, value := range subMap {\n\t\tvalue, ok := value.(map[string]interface{})\n\t\tif ok {\n\t\t\t// we found another section\n\t\t\tisEmpty := cleanSubMap(value, path.Join(subKey, key))\n\t\t\tif isEmpty {\n\t\t\t\tdelete(subMap, key)\n\t\t\t} else {\n\t\t\t\tfoundValid++\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// we found an option value\n\t\tif strings.Contains(key, \"/\") {\n\t\t\tdelete(subMap, key)\n\t\t} else {\n\t\t\t_, ok := options[path.Join(subKey, key)]\n\t\t\tif ok {\n\t\t\t\tfoundValid++\n\t\t\t} else {\n\t\t\t\tdelete(subMap, key)\n\t\t\t}\n\t\t}\n\t}\n\treturn foundValid == 0\n}\n"
  },
  {
    "path": "base/config/persistence_test.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"testing\"\n)\n\nvar (\n\tjsonData = `{\n  \"a\": \"b\",\n  \"c\": {\n    \"d\": \"e\",\n    \"f\": \"g\",\n    \"h\": {\n      \"i\": \"j\",\n      \"k\": \"l\",\n      \"m\": {\n        \"n\": \"o\"\n      }\n    }\n  },\n  \"p\": \"q\"\n}`\n\tjsonBytes = []byte(jsonData)\n\n\tmapData = map[string]interface{}{\n\t\t\"a\":       \"b\",\n\t\t\"p\":       \"q\",\n\t\t\"c/d\":     \"e\",\n\t\t\"c/f\":     \"g\",\n\t\t\"c/h/i\":   \"j\",\n\t\t\"c/h/k\":   \"l\",\n\t\t\"c/h/m/n\": \"o\",\n\t}\n)\n\nfunc TestJSONMapConversion(t *testing.T) {\n\tt.Parallel()\n\n\t// convert to json\n\tj, err := MapToJSON(mapData)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// check if to json matches\n\tif !bytes.Equal(jsonBytes, j) {\n\t\tt.Errorf(\"json does not match, got %s\", j)\n\t}\n\n\t// convert to map\n\tm, err := JSONToMap(jsonBytes)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// and back\n\tj2, err := MapToJSON(m)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// check if double convert matches\n\tif !bytes.Equal(jsonBytes, j2) {\n\t\tt.Errorf(\"json does not match, got %s\", j)\n\t}\n}\n\nfunc TestConfigCleaning(t *testing.T) {\n\tt.Parallel()\n\n\t// load\n\tconfigFlat, err := JSONToMap(jsonBytes)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// clean everything\n\tCleanFlattenedConfig(configFlat)\n\tif len(configFlat) != 0 {\n\t\tt.Errorf(\"should be empty: %+v\", configFlat)\n\t}\n\n\t// load manuall for hierarchical config\n\tconfigHier := make(map[string]interface{})\n\terr = json.Unmarshal(jsonBytes, &configHier)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// clean everything\n\tCleanHierarchicalConfig(configHier)\n\tif len(configHier) != 0 {\n\t\tt.Errorf(\"should be empty: %+v\", configHier)\n\t}\n}\n"
  },
  {
    "path": "base/config/perspective.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// Perspective is a view on configuration data without interfering with the configuration system.\ntype Perspective struct {\n\tconfig map[string]*perspectiveOption\n}\n\ntype perspectiveOption struct {\n\toption     *Option\n\tvalueCache *valueCache\n}\n\n// NewPerspective parses the given config and returns it as a new perspective.\nfunc NewPerspective(config map[string]interface{}) (*Perspective, error) {\n\t// flatten config structure\n\tconfig = Flatten(config)\n\n\tperspective := &Perspective{\n\t\tconfig: make(map[string]*perspectiveOption),\n\t}\n\tvar firstErr error\n\tvar errCnt int\n\n\toptionsLock.RLock()\noptionsLoop:\n\tfor key, option := range options {\n\t\t// get option key from config\n\t\tconfigValue, ok := config[key]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\t// migrate value\n\t\tconfigValue = migrateValue(option, configValue)\n\t\t// validate value\n\t\tvalueCache, err := validateValue(option, configValue)\n\t\tif err != nil {\n\t\t\terrCnt++\n\t\t\tif firstErr == nil {\n\t\t\t\tfirstErr = err\n\t\t\t}\n\t\t\tcontinue optionsLoop\n\t\t}\n\n\t\t// add to perspective\n\t\tperspective.config[key] = &perspectiveOption{\n\t\t\toption:     option,\n\t\t\tvalueCache: valueCache,\n\t\t}\n\t}\n\toptionsLock.RUnlock()\n\n\tif firstErr != nil {\n\t\tif errCnt > 0 {\n\t\t\treturn perspective, fmt.Errorf(\"encountered %d errors, first was: %w\", errCnt, firstErr)\n\t\t}\n\t\treturn perspective, firstErr\n\t}\n\n\treturn perspective, nil\n}\n\nfunc (p *Perspective) getPerspectiveValueCache(name string, requestedType OptionType) *valueCache {\n\t// get option\n\tpOption, ok := p.config[name]\n\tif !ok {\n\t\t// check if option exists at all\n\t\tif _, err := GetOption(name); err != nil {\n\t\t\tlog.Errorf(\"config: request for unregistered option: %s\", name)\n\t\t}\n\t\treturn nil\n\t}\n\n\t// check type\n\tif requestedType != pOption.option.OptType && requestedType != optTypeAny {\n\t\tlog.Errorf(\"config: bad type: requested %s as %s, but is %s\", name, getTypeName(requestedType), getTypeName(pOption.option.OptType))\n\t\treturn nil\n\t}\n\n\t// check release level\n\tif pOption.option.ReleaseLevel > getReleaseLevel() {\n\t\treturn nil\n\t}\n\n\treturn pOption.valueCache\n}\n\n// Has returns whether the given option is set in the perspective.\nfunc (p *Perspective) Has(name string) bool {\n\tvalueCache := p.getPerspectiveValueCache(name, optTypeAny)\n\treturn valueCache != nil\n}\n\n// GetAsString returns a function that returns the wanted string with high performance.\nfunc (p *Perspective) GetAsString(name string) (value string, ok bool) {\n\tvalueCache := p.getPerspectiveValueCache(name, OptTypeString)\n\tif valueCache != nil {\n\t\treturn valueCache.stringVal, true\n\t}\n\treturn \"\", false\n}\n\n// GetAsStringArray returns a function that returns the wanted string with high performance.\nfunc (p *Perspective) GetAsStringArray(name string) (value []string, ok bool) {\n\tvalueCache := p.getPerspectiveValueCache(name, OptTypeStringArray)\n\tif valueCache != nil {\n\t\treturn valueCache.stringArrayVal, true\n\t}\n\treturn nil, false\n}\n\n// GetAsInt returns a function that returns the wanted int with high performance.\nfunc (p *Perspective) GetAsInt(name string) (value int64, ok bool) {\n\tvalueCache := p.getPerspectiveValueCache(name, OptTypeInt)\n\tif valueCache != nil {\n\t\treturn valueCache.intVal, true\n\t}\n\treturn 0, false\n}\n\n// GetAsBool returns a function that returns the wanted int with high performance.\nfunc (p *Perspective) GetAsBool(name string) (value bool, ok bool) {\n\tvalueCache := p.getPerspectiveValueCache(name, OptTypeBool)\n\tif valueCache != nil {\n\t\treturn valueCache.boolVal, true\n\t}\n\treturn false, false\n}\n"
  },
  {
    "path": "base/config/registry.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n)\n\nvar (\n\toptionsLock sync.RWMutex\n\toptions     = make(map[string]*Option)\n)\n\n// ForEachOption calls fn for each defined option. If fn returns\n// and error the iteration is stopped and the error is returned.\n// Note that ForEachOption does not guarantee a stable order of\n// iteration between multiple calles. ForEachOption does NOT lock\n// opt when calling fn.\nfunc ForEachOption(fn func(opt *Option) error) error {\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\tfor _, opt := range options {\n\t\tif err := fn(opt); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// ExportOptions exports the registered options. The returned data must be\n// treated as immutable.\n// The data does not include the current active or default settings.\nfunc ExportOptions() []*Option {\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\t// Copy the map into a slice.\n\topts := make([]*Option, 0, len(options))\n\tfor _, opt := range options {\n\t\topts = append(opts, opt)\n\t}\n\n\tsort.Sort(sortByKey(opts))\n\treturn opts\n}\n\n// GetOption returns the option with name or an error\n// if the option does not exist. The caller should lock\n// the returned option itself for further processing.\nfunc GetOption(name string) (*Option, error) {\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\topt, ok := options[name]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"option %q does not exist\", name)\n\t}\n\treturn opt, nil\n}\n\n// Register registers a new configuration option.\n// Note: Option must be registered before initial loading config from disk.\nfunc Register(option *Option) error {\n\tif option.Name == \"\" {\n\t\treturn fmt.Errorf(\"failed to register option: please set option.Name\")\n\t}\n\tif option.Key == \"\" {\n\t\treturn fmt.Errorf(\"failed to register option: please set option.Key\")\n\t}\n\tif option.Description == \"\" {\n\t\treturn fmt.Errorf(\"failed to register option: please set option.Description\")\n\t}\n\tif option.OptType == 0 {\n\t\treturn fmt.Errorf(\"failed to register option: please set option.OptType\")\n\t}\n\tif cfgInitialized.Load() {\n\t\treturn fmt.Errorf(\"cannot register option '%s': config already initialized\", option.Key)\n\t}\n\n\tif option.ValidationRegex == \"\" && option.PossibleValues != nil {\n\t\tvalues := make([]string, len(option.PossibleValues))\n\t\tfor idx, val := range option.PossibleValues {\n\t\t\tvalues[idx] = fmt.Sprintf(\"%v\", val.Value)\n\t\t}\n\t\toption.ValidationRegex = fmt.Sprintf(\"^(%s)$\", strings.Join(values, \"|\"))\n\t}\n\n\tvar err error\n\tif option.ValidationRegex != \"\" {\n\t\toption.compiledRegex, err = regexp.Compile(option.ValidationRegex)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"config: could not compile option.ValidationRegex: %w\", err)\n\t\t}\n\t}\n\n\tvar vErr *ValidationError\n\toption.activeFallbackValue, vErr = validateValue(option, option.DefaultValue)\n\tif vErr != nil {\n\t\treturn fmt.Errorf(\"config: invalid default value: %w\", vErr)\n\t}\n\n\toptionsLock.Lock()\n\tdefer optionsLock.Unlock()\n\toptions[option.Key] = option\n\n\treturn nil\n}\n"
  },
  {
    "path": "base/config/registry_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n)\n\nfunc TestRegistry(t *testing.T) { //nolint:paralleltest\n\t// reset\n\toptions = make(map[string]*Option)\n\n\tif err := Register(&Option{\n\t\tName:            \"name\",\n\t\tKey:             \"key\",\n\t\tDescription:     \"description\",\n\t\tReleaseLevel:    ReleaseLevelStable,\n\t\tExpertiseLevel:  ExpertiseLevelUser,\n\t\tOptType:         OptTypeString,\n\t\tDefaultValue:    \"water\",\n\t\tValidationRegex: \"^(banana|water)$\",\n\t}); err != nil {\n\t\tt.Error(err)\n\t}\n\n\tif err := Register(&Option{\n\t\tName:            \"name\",\n\t\tKey:             \"key\",\n\t\tDescription:     \"description\",\n\t\tReleaseLevel:    ReleaseLevelStable,\n\t\tExpertiseLevel:  ExpertiseLevelUser,\n\t\tOptType:         0,\n\t\tDefaultValue:    \"default\",\n\t\tValidationRegex: \"^[A-Z][a-z]+$\",\n\t}); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\n\tif err := Register(&Option{\n\t\tName:            \"name\",\n\t\tKey:             \"key\",\n\t\tDescription:     \"description\",\n\t\tReleaseLevel:    ReleaseLevelStable,\n\t\tExpertiseLevel:  ExpertiseLevelUser,\n\t\tOptType:         OptTypeString,\n\t\tDefaultValue:    \"default\",\n\t\tValidationRegex: \"[\",\n\t}); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n}\n"
  },
  {
    "path": "base/config/release.go",
    "content": "package config\n\nimport (\n\t\"sync/atomic\"\n\n\t\"github.com/tevino/abool\"\n)\n\n// ReleaseLevel is used to define the maturity of a\n// configuration setting.\ntype ReleaseLevel uint8\n\n// Release Level constants.\nconst (\n\tReleaseLevelStable       ReleaseLevel = 0\n\tReleaseLevelBeta         ReleaseLevel = 1\n\tReleaseLevelExperimental ReleaseLevel = 2\n\n\tReleaseLevelNameStable       = \"stable\"\n\tReleaseLevelNameBeta         = \"beta\"\n\tReleaseLevelNameExperimental = \"experimental\"\n\n\treleaseLevelKey = \"core/releaseLevel\"\n)\n\nvar (\n\treleaseLevel           = new(int32)\n\treleaseLevelOption     *Option\n\treleaseLevelOptionFlag = abool.New()\n)\n\nfunc init() {\n\tregisterReleaseLevelOption()\n}\n\nfunc registerReleaseLevelOption() {\n\treleaseLevelOption = &Option{\n\t\tName:           \"Feature Stability\",\n\t\tKey:            releaseLevelKey,\n\t\tDescription:    `May break things. Decide if you want to experiment with unstable features. \"Beta\" has been tested roughly by the Safing team while \"Experimental\" is really raw. When \"Beta\" or \"Experimental\" are disabled, their settings use the default again.`,\n\t\tOptType:        OptTypeString,\n\t\tExpertiseLevel: ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   ReleaseLevelStable,\n\t\tDefaultValue:   ReleaseLevelNameStable,\n\t\tAnnotations: Annotations{\n\t\t\tDisplayOrderAnnotation: -8,\n\t\t\tDisplayHintAnnotation:  DisplayHintOneOf,\n\t\t\tCategoryAnnotation:     \"Updates\",\n\t\t},\n\t\tPossibleValues: []PossibleValue{\n\t\t\t{\n\t\t\t\tName:        \"Stable\",\n\t\t\t\tValue:       ReleaseLevelNameStable,\n\t\t\t\tDescription: \"Only show stable features.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Beta\",\n\t\t\t\tValue:       ReleaseLevelNameBeta,\n\t\t\t\tDescription: \"Show stable and beta features.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Experimental\",\n\t\t\t\tValue:       ReleaseLevelNameExperimental,\n\t\t\t\tDescription: \"Show all features\",\n\t\t\t},\n\t\t},\n\t}\n\n\terr := Register(releaseLevelOption)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treleaseLevelOptionFlag.Set()\n}\n\nfunc updateReleaseLevel() {\n\t// get value\n\tvalue := releaseLevelOption.activeFallbackValue\n\tif releaseLevelOption.activeValue != nil {\n\t\tvalue = releaseLevelOption.activeValue\n\t}\n\tif releaseLevelOption.activeDefaultValue != nil {\n\t\tvalue = releaseLevelOption.activeDefaultValue\n\t}\n\t// set atomic value\n\tswitch value.stringVal {\n\tcase ReleaseLevelNameStable:\n\t\tatomic.StoreInt32(releaseLevel, int32(ReleaseLevelStable))\n\tcase ReleaseLevelNameBeta:\n\t\tatomic.StoreInt32(releaseLevel, int32(ReleaseLevelBeta))\n\tcase ReleaseLevelNameExperimental:\n\t\tatomic.StoreInt32(releaseLevel, int32(ReleaseLevelExperimental))\n\tdefault:\n\t\tatomic.StoreInt32(releaseLevel, int32(ReleaseLevelStable))\n\t}\n}\n\nfunc getReleaseLevel() ReleaseLevel {\n\treturn ReleaseLevel(atomic.LoadInt32(releaseLevel))\n}\n"
  },
  {
    "path": "base/config/set.go",
    "content": "package config\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\n\t\"github.com/tevino/abool\"\n)\n\nvar (\n\t// ErrInvalidJSON is returned by SetConfig and SetDefaultConfig if they receive invalid json.\n\tErrInvalidJSON = errors.New(\"json string invalid\")\n\n\t// ErrInvalidOptionType is returned by SetConfigOption and SetDefaultConfigOption if given an unsupported option type.\n\tErrInvalidOptionType = errors.New(\"invalid option value type\")\n\n\tvalidityFlag     = abool.NewBool(true)\n\tvalidityFlagLock sync.RWMutex\n)\n\n// getValidityFlag returns a flag that signifies if the configuration has been changed. This flag must not be changed, only read.\nfunc getValidityFlag() *abool.AtomicBool {\n\tvalidityFlagLock.RLock()\n\tdefer validityFlagLock.RUnlock()\n\treturn validityFlag\n}\n\n// signalChanges marks the configs validtityFlag as dirty and eventually\n// triggers a config change event.\nfunc signalChanges() {\n\t// reset validity flag\n\tvalidityFlagLock.Lock()\n\tvalidityFlag.SetTo(false)\n\tvalidityFlag = abool.NewBool(true)\n\tvalidityFlagLock.Unlock()\n\n\tmodule.EventConfigChange.Submit(struct{}{})\n}\n\n// ValidateConfig validates the given configuration and returns all validation\n// errors as well as whether the given configuration contains unknown keys.\nfunc ValidateConfig(newValues map[string]interface{}) (validationErrors []*ValidationError, requiresRestart bool, containsUnknown bool) {\n\t// RLock the options because we are not adding or removing\n\t// options from the registration but rather only checking the\n\t// options value which is guarded by the option's lock itself.\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\tvar checked int\n\tfor key, option := range options {\n\t\tnewValue, ok := newValues[key]\n\t\tif ok {\n\t\t\tchecked++\n\n\t\t\tfunc() {\n\t\t\t\toption.Lock()\n\t\t\t\tdefer option.Unlock()\n\n\t\t\t\tnewValue = migrateValue(option, newValue)\n\t\t\t\t_, err := validateValue(option, newValue)\n\t\t\t\tif err != nil {\n\t\t\t\t\tvalidationErrors = append(validationErrors, err)\n\t\t\t\t}\n\n\t\t\t\tif option.RequiresRestart {\n\t\t\t\t\trequiresRestart = true\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\n\treturn validationErrors, requiresRestart, checked < len(newValues)\n}\n\n// ReplaceConfig sets the (prioritized) user defined config.\nfunc ReplaceConfig(newValues map[string]interface{}) (validationErrors []*ValidationError, requiresRestart bool) {\n\t// RLock the options because we are not adding or removing\n\t// options from the registration but rather only update the\n\t// options value which is guarded by the option's lock itself.\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\tfor key, option := range options {\n\t\tnewValue, ok := newValues[key]\n\n\t\tfunc() {\n\t\t\toption.Lock()\n\t\t\tdefer option.Unlock()\n\n\t\t\toption.activeValue = nil\n\t\t\tif ok {\n\t\t\t\tnewValue = migrateValue(option, newValue)\n\t\t\t\tvalueCache, err := validateValue(option, newValue)\n\t\t\t\tif err == nil {\n\t\t\t\t\toption.activeValue = valueCache\n\t\t\t\t} else {\n\t\t\t\t\tvalidationErrors = append(validationErrors, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\thandleOptionUpdate(option, true)\n\n\t\t\tif option.RequiresRestart {\n\t\t\t\trequiresRestart = true\n\t\t\t}\n\t\t}()\n\t}\n\n\tsignalChanges()\n\n\treturn validationErrors, requiresRestart\n}\n\n// ReplaceDefaultConfig sets the (fallback) default config.\nfunc ReplaceDefaultConfig(newValues map[string]interface{}) (validationErrors []*ValidationError, requiresRestart bool) {\n\t// RLock the options because we are not adding or removing\n\t// options from the registration but rather only update the\n\t// options value which is guarded by the option's lock itself.\n\toptionsLock.RLock()\n\tdefer optionsLock.RUnlock()\n\n\tfor key, option := range options {\n\t\tnewValue, ok := newValues[key]\n\n\t\tfunc() {\n\t\t\toption.Lock()\n\t\t\tdefer option.Unlock()\n\n\t\t\toption.activeDefaultValue = nil\n\t\t\tif ok {\n\t\t\t\tnewValue = migrateValue(option, newValue)\n\t\t\t\tvalueCache, err := validateValue(option, newValue)\n\t\t\t\tif err == nil {\n\t\t\t\t\toption.activeDefaultValue = valueCache\n\t\t\t\t} else {\n\t\t\t\t\tvalidationErrors = append(validationErrors, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\thandleOptionUpdate(option, true)\n\n\t\t\tif option.RequiresRestart {\n\t\t\t\trequiresRestart = true\n\t\t\t}\n\t\t}()\n\t}\n\n\tsignalChanges()\n\n\treturn validationErrors, requiresRestart\n}\n\n// SetConfigOption sets a single value in the (prioritized) user defined config.\nfunc SetConfigOption(key string, value any) error {\n\treturn setConfigOption(key, value, true)\n}\n\nfunc setConfigOption(key string, value any, push bool) (err error) {\n\toption, err := GetOption(key)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toption.Lock()\n\tif value == nil {\n\t\toption.activeValue = nil\n\t} else {\n\t\tvalue = migrateValue(option, value)\n\t\tvalueCache, vErr := validateValue(option, value)\n\t\tif vErr == nil {\n\t\t\toption.activeValue = valueCache\n\t\t} else {\n\t\t\terr = vErr\n\t\t}\n\t}\n\n\t// Add the \"restart pending\" annotation if the settings requires a restart.\n\tif option.RequiresRestart {\n\t\toption.setAnnotation(RestartPendingAnnotation, true)\n\t}\n\n\thandleOptionUpdate(option, push)\n\toption.Unlock()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// finalize change, activate triggers\n\tsignalChanges()\n\n\treturn SaveConfig()\n}\n\n// SetDefaultConfigOption sets a single value in the (fallback) default config.\nfunc SetDefaultConfigOption(key string, value interface{}) error {\n\treturn setDefaultConfigOption(key, value, true)\n}\n\nfunc setDefaultConfigOption(key string, value interface{}, push bool) (err error) {\n\toption, err := GetOption(key)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toption.Lock()\n\tif value == nil {\n\t\toption.activeDefaultValue = nil\n\t} else {\n\t\tvalue = migrateValue(option, value)\n\t\tvalueCache, vErr := validateValue(option, value)\n\t\tif vErr == nil {\n\t\t\toption.activeDefaultValue = valueCache\n\t\t} else {\n\t\t\terr = vErr\n\t\t}\n\t}\n\n\t// Add the \"restart pending\" annotation if the settings requires a restart.\n\tif option.RequiresRestart {\n\t\toption.setAnnotation(RestartPendingAnnotation, true)\n\t}\n\n\thandleOptionUpdate(option, push)\n\toption.Unlock()\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// finalize change, activate triggers\n\tsignalChanges()\n\n\t// Do not save the configuration, as it only saves the active values, not the\n\t// active default value.\n\treturn nil\n}\n"
  },
  {
    "path": "base/config/set_test.go",
    "content": "//nolint:goconst\npackage config\n\nimport \"testing\"\n\nfunc TestLayersGetters(t *testing.T) { //nolint:paralleltest\n\t// reset\n\toptions = make(map[string]*Option)\n\n\tmapData, err := JSONToMap([]byte(`\n\t\t{\n\t\t\t\"monkey\": \"1\",\n\t\t\t\"elephant\": 2,\n\t\t\t\"zebras\": {\n\t\t\t\t\"zebra\": [\"black\", \"white\"],\n\t\t\t\t\"weird_zebra\": [\"black\", -1]\n\t\t\t},\n\t\t\t\"env\": {\n\t\t\t\t\"hot\": true\n\t\t\t}\n\t\t}\n    `))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tvalidationErrors, _ := ReplaceConfig(mapData)\n\tif len(validationErrors) > 0 {\n\t\tt.Fatalf(\"%d errors, first: %s\", len(validationErrors), validationErrors[0].Error())\n\t}\n\n\t// Test missing values\n\n\tmissingString := GetAsString(\"missing\", \"fallback\")\n\tif missingString() != \"fallback\" {\n\t\tt.Error(\"expected fallback value: fallback\")\n\t}\n\n\tmissingStringArray := GetAsStringArray(\"missing\", []string{\"fallback\"})\n\tif len(missingStringArray()) != 1 || missingStringArray()[0] != \"fallback\" {\n\t\tt.Error(\"expected fallback value: [fallback]\")\n\t}\n\n\tmissingInt := GetAsInt(\"missing\", -1)\n\tif missingInt() != -1 {\n\t\tt.Error(\"expected fallback value: -1\")\n\t}\n\n\tmissingBool := GetAsBool(\"missing\", false)\n\tif missingBool() {\n\t\tt.Error(\"expected fallback value: false\")\n\t}\n\n\t// Test value mismatch\n\n\tnotString := GetAsString(\"elephant\", \"fallback\")\n\tif notString() != \"fallback\" {\n\t\tt.Error(\"expected fallback value: fallback\")\n\t}\n\n\tnotStringArray := GetAsStringArray(\"elephant\", []string{\"fallback\"})\n\tif len(notStringArray()) != 1 || notStringArray()[0] != \"fallback\" {\n\t\tt.Error(\"expected fallback value: [fallback]\")\n\t}\n\n\tmixedStringArray := GetAsStringArray(\"zebras/weird_zebra\", []string{\"fallback\"})\n\tif len(mixedStringArray()) != 1 || mixedStringArray()[0] != \"fallback\" {\n\t\tt.Error(\"expected fallback value: [fallback]\")\n\t}\n\n\tnotInt := GetAsInt(\"monkey\", -1)\n\tif notInt() != -1 {\n\t\tt.Error(\"expected fallback value: -1\")\n\t}\n\n\tnotBool := GetAsBool(\"monkey\", false)\n\tif notBool() {\n\t\tt.Error(\"expected fallback value: false\")\n\t}\n}\n\nfunc TestLayersSetters(t *testing.T) { //nolint:paralleltest\n\t// reset\n\toptions = make(map[string]*Option)\n\n\t_ = Register(&Option{\n\t\tName:            \"name\",\n\t\tKey:             \"monkey\",\n\t\tDescription:     \"description\",\n\t\tReleaseLevel:    ReleaseLevelStable,\n\t\tExpertiseLevel:  ExpertiseLevelUser,\n\t\tOptType:         OptTypeString,\n\t\tDefaultValue:    \"banana\",\n\t\tValidationRegex: \"^(banana|water)$\",\n\t})\n\t_ = Register(&Option{\n\t\tName:            \"name\",\n\t\tKey:             \"zebras/zebra\",\n\t\tDescription:     \"description\",\n\t\tReleaseLevel:    ReleaseLevelStable,\n\t\tExpertiseLevel:  ExpertiseLevelUser,\n\t\tOptType:         OptTypeStringArray,\n\t\tDefaultValue:    []string{\"black\", \"white\"},\n\t\tValidationRegex: \"^[a-z]+$\",\n\t})\n\t_ = Register(&Option{\n\t\tName:            \"name\",\n\t\tKey:             \"elephant\",\n\t\tDescription:     \"description\",\n\t\tReleaseLevel:    ReleaseLevelStable,\n\t\tExpertiseLevel:  ExpertiseLevelUser,\n\t\tOptType:         OptTypeInt,\n\t\tDefaultValue:    2,\n\t\tValidationRegex: \"\",\n\t})\n\t_ = Register(&Option{\n\t\tName:            \"name\",\n\t\tKey:             \"hot\",\n\t\tDescription:     \"description\",\n\t\tReleaseLevel:    ReleaseLevelStable,\n\t\tExpertiseLevel:  ExpertiseLevelUser,\n\t\tOptType:         OptTypeBool,\n\t\tDefaultValue:    true,\n\t\tValidationRegex: \"\",\n\t})\n\n\t// correct types\n\tif err := SetConfigOption(\"monkey\", \"banana\"); err != nil {\n\t\tt.Error(err)\n\t}\n\tif err := SetConfigOption(\"zebras/zebra\", []string{\"black\", \"white\"}); err != nil {\n\t\tt.Error(err)\n\t}\n\tif err := SetDefaultConfigOption(\"elephant\", 2); err != nil {\n\t\tt.Error(err)\n\t}\n\tif err := SetDefaultConfigOption(\"hot\", true); err != nil {\n\t\tt.Error(err)\n\t}\n\n\t// incorrect types\n\tif err := SetConfigOption(\"monkey\", []string{\"black\", \"white\"}); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetConfigOption(\"zebras/zebra\", 2); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetDefaultConfigOption(\"elephant\", true); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetDefaultConfigOption(\"hot\", \"banana\"); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetDefaultConfigOption(\"hot\", []byte{0}); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\n\t// validation fail\n\tif err := SetConfigOption(\"monkey\", \"dirt\"); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetConfigOption(\"zebras/zebra\", []string{\"Element649\"}); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\n\t// unregistered checking\n\tif err := SetConfigOption(\"invalid\", \"banana\"); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetConfigOption(\"invalid\", []string{\"black\", \"white\"}); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetConfigOption(\"invalid\", 2); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetConfigOption(\"invalid\", true); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\tif err := SetConfigOption(\"invalid\", []byte{0}); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\n\t// delete\n\tif err := SetConfigOption(\"monkey\", nil); err != nil {\n\t\tt.Error(err)\n\t}\n\tif err := SetDefaultConfigOption(\"elephant\", nil); err != nil {\n\t\tt.Error(err)\n\t}\n\tif err := SetDefaultConfigOption(\"invalid_delete\", nil); err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n}\n"
  },
  {
    "path": "base/config/validate.go",
    "content": "package config\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\ntype valueCache struct {\n\tstringVal      string\n\tstringArrayVal []string\n\tintVal         int64\n\tboolVal        bool\n}\n\nfunc (vc *valueCache) getData(opt *Option) interface{} {\n\tswitch opt.OptType {\n\tcase OptTypeBool:\n\t\treturn vc.boolVal\n\tcase OptTypeInt:\n\t\treturn vc.intVal\n\tcase OptTypeString:\n\t\treturn vc.stringVal\n\tcase OptTypeStringArray:\n\t\treturn vc.stringArrayVal\n\tcase optTypeAny:\n\t\treturn nil\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// isAllowedPossibleValue checks if value is defined as a PossibleValue\n// in opt. If there are not possible values defined value is considered\n// allowed and nil is returned. isAllowedPossibleValue ensure the actual\n// value is an allowed primitiv value by using reflection to convert\n// value and each PossibleValue to a comparable primitiv if possible.\n// In case of complex value types isAllowedPossibleValue uses\n// reflect.DeepEqual as a fallback.\nfunc isAllowedPossibleValue(opt *Option, value interface{}) error {\n\tif opt.PossibleValues == nil {\n\t\treturn nil\n\t}\n\n\tfor _, val := range opt.PossibleValues {\n\t\tcompareAgainst := val.Value\n\t\tvalueType := reflect.TypeOf(value)\n\n\t\t// loading int's from the configuration JSON does not preserve the correct type\n\t\t// as we get float64 instead. Make sure to convert them before.\n\t\tif reflect.TypeOf(val.Value).ConvertibleTo(valueType) {\n\t\t\tcompareAgainst = reflect.ValueOf(val.Value).Convert(valueType).Interface()\n\t\t}\n\t\tif compareAgainst == value {\n\t\t\treturn nil\n\t\t}\n\n\t\tif reflect.DeepEqual(val.Value, value) {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn errors.New(\"value is not allowed\")\n}\n\n// migrateValue runs all value migrations.\nfunc migrateValue(option *Option, value any) any {\n\tfor _, migration := range option.Migrations {\n\t\tnewValue := migration(option, value)\n\t\tif newValue != value {\n\t\t\tlog.Debugf(\"config: migrated %s value from %v to %v\", option.Key, value, newValue)\n\t\t}\n\t\tvalue = newValue\n\t}\n\treturn value\n}\n\n// validateValue ensures that value matches the expected type of option.\n// It does not create a copy of the value!\nfunc validateValue(option *Option, value interface{}) (*valueCache, *ValidationError) { //nolint:gocyclo\n\tif option.OptType != OptTypeStringArray {\n\t\tif err := isAllowedPossibleValue(option, value); err != nil {\n\t\t\treturn nil, &ValidationError{\n\t\t\t\tOption: option.copyOrNil(),\n\t\t\t\tErr:    err,\n\t\t\t}\n\t\t}\n\t}\n\n\tvar validated *valueCache\n\tswitch v := value.(type) {\n\tcase string:\n\t\tif option.OptType != OptTypeString {\n\t\t\treturn nil, invalid(option, \"expected type %s, got type %T\", getTypeName(option.OptType), v)\n\t\t}\n\t\tif option.compiledRegex != nil {\n\t\t\tif !option.compiledRegex.MatchString(v) {\n\t\t\t\treturn nil, invalid(option, \"did not match validation regex\")\n\t\t\t}\n\t\t}\n\t\tvalidated = &valueCache{stringVal: v}\n\tcase []interface{}:\n\t\tvConverted := make([]string, len(v))\n\t\tfor pos, entry := range v {\n\t\t\ts, ok := entry.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, invalid(option, \"entry #%d is not a string\", pos+1)\n\t\t\t}\n\t\t\tvConverted[pos] = s\n\t\t}\n\t\t// Call validation function again with converted value.\n\t\tvar vErr *ValidationError\n\t\tvalidated, vErr = validateValue(option, vConverted)\n\t\tif vErr != nil {\n\t\t\treturn nil, vErr\n\t\t}\n\tcase []string:\n\t\tif option.OptType != OptTypeStringArray {\n\t\t\treturn nil, invalid(option, \"expected type %s, got type %T\", getTypeName(option.OptType), v)\n\t\t}\n\t\tif option.compiledRegex != nil {\n\t\t\tfor pos, entry := range v {\n\t\t\t\tif !option.compiledRegex.MatchString(entry) {\n\t\t\t\t\treturn nil, invalid(option, \"entry #%d did not match validation regex\", pos+1)\n\t\t\t\t}\n\n\t\t\t\tif err := isAllowedPossibleValue(option, entry); err != nil {\n\t\t\t\t\treturn nil, invalid(option, \"entry #%d is not allowed\", pos+1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvalidated = &valueCache{stringArrayVal: v}\n\tcase int, int8, int16, int32, int64, uint, uint8, uint16, uint32, float32, float64:\n\t\t// uint64 is omitted, as it does not fit in a int64\n\t\tif option.OptType != OptTypeInt {\n\t\t\treturn nil, invalid(option, \"expected type %s, got type %T\", getTypeName(option.OptType), v)\n\t\t}\n\t\tif option.compiledRegex != nil {\n\t\t\t// we need to use %v here so we handle float and int correctly.\n\t\t\tif !option.compiledRegex.MatchString(fmt.Sprintf(\"%v\", v)) {\n\t\t\t\treturn nil, invalid(option, \"did not match validation regex\")\n\t\t\t}\n\t\t}\n\t\tswitch v := value.(type) {\n\t\tcase int:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase int8:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase int16:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase int32:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase int64:\n\t\t\tvalidated = &valueCache{intVal: v}\n\t\tcase uint:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase uint8:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase uint16:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase uint32:\n\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\tcase float32:\n\t\t\t// convert if float has no decimals\n\t\t\tif math.Remainder(float64(v), 1) == 0 {\n\t\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\t\t} else {\n\t\t\t\treturn nil, invalid(option, \"failed to convert float32 to int64\")\n\t\t\t}\n\t\tcase float64:\n\t\t\t// convert if float has no decimals\n\t\t\tif math.Remainder(v, 1) == 0 {\n\t\t\t\tvalidated = &valueCache{intVal: int64(v)}\n\t\t\t} else {\n\t\t\t\treturn nil, invalid(option, \"failed to convert float64 to int64\")\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, invalid(option, \"internal error\")\n\t\t}\n\tcase bool:\n\t\tif option.OptType != OptTypeBool {\n\t\t\treturn nil, invalid(option, \"expected type %s, got type %T\", getTypeName(option.OptType), v)\n\t\t}\n\t\tvalidated = &valueCache{boolVal: v}\n\tdefault:\n\t\treturn nil, invalid(option, \"invalid option value type: %T\", value)\n\t}\n\n\t// Check if there is an additional function to validate the value.\n\tif option.ValidationFunc != nil {\n\t\tvar err error\n\t\tswitch option.OptType {\n\t\tcase optTypeAny:\n\t\t\terr = errors.New(\"internal error\")\n\t\tcase OptTypeString:\n\t\t\terr = option.ValidationFunc(validated.stringVal)\n\t\tcase OptTypeStringArray:\n\t\t\terr = option.ValidationFunc(validated.stringArrayVal)\n\t\tcase OptTypeInt:\n\t\t\terr = option.ValidationFunc(validated.intVal)\n\t\tcase OptTypeBool:\n\t\t\terr = option.ValidationFunc(validated.boolVal)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, &ValidationError{\n\t\t\t\tOption: option.copyOrNil(),\n\t\t\t\tErr:    err,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn validated, nil\n}\n\n// ValidationError error holds details about a config option value validation error.\ntype ValidationError struct {\n\tOption *Option\n\tErr    error\n}\n\n// Error returns the formatted error.\nfunc (ve *ValidationError) Error() string {\n\treturn fmt.Sprintf(\"validation of %s failed: %s\", ve.Option.Key, ve.Err)\n}\n\n// Unwrap returns the wrapped error.\nfunc (ve *ValidationError) Unwrap() error {\n\treturn ve.Err\n}\n\nfunc invalid(option *Option, format string, a ...interface{}) *ValidationError {\n\treturn &ValidationError{\n\t\tOption: option.copyOrNil(),\n\t\tErr:    fmt.Errorf(format, a...),\n\t}\n}\n"
  },
  {
    "path": "base/config/validity.go",
    "content": "package config\n\nimport (\n\t\"github.com/tevino/abool\"\n)\n\n// ValidityFlag is a flag that signifies if the configuration has been changed. It is not safe for concurrent use.\ntype ValidityFlag struct {\n\tflag *abool.AtomicBool\n}\n\n// NewValidityFlag returns a flag that signifies if the configuration has been changed.\n// It always starts out as invalid. Refresh to start with the current value.\nfunc NewValidityFlag() *ValidityFlag {\n\tvf := &ValidityFlag{\n\t\tflag: abool.New(),\n\t}\n\treturn vf\n}\n\n// IsValid returns if the configuration is still valid.\nfunc (vf *ValidityFlag) IsValid() bool {\n\treturn vf.flag.IsSet()\n}\n\n// Refresh refreshes the flag and makes it reusable.\nfunc (vf *ValidityFlag) Refresh() {\n\tvalidityFlagLock.RLock()\n\tdefer validityFlagLock.RUnlock()\n\n\tvf.flag = validityFlag\n}\n"
  },
  {
    "path": "base/container/container.go",
    "content": "package container\n\nimport (\n\t\"errors\"\n\t\"io\"\n\n\t\"github.com/safing/structures/varint\"\n)\n\n// Container is []byte sclie on steroids, allowing for quick data appending, prepending and fetching.\ntype Container struct {\n\tcompartments [][]byte\n\toffset       int\n\terr          error\n}\n\n// Data Handling\n\n// NewContainer is DEPRECATED, please use New(), it's the same thing.\nfunc NewContainer(data ...[]byte) *Container {\n\treturn &Container{\n\t\tcompartments: data,\n\t}\n}\n\n// New creates a new container with an optional initial []byte slice. Data will NOT be copied.\nfunc New(data ...[]byte) *Container {\n\treturn &Container{\n\t\tcompartments: data,\n\t}\n}\n\n// Prepend prepends data. Data will NOT be copied.\nfunc (c *Container) Prepend(data []byte) {\n\tif c.offset < 1 {\n\t\tc.renewCompartments()\n\t}\n\tc.offset--\n\tc.compartments[c.offset] = data\n}\n\n// Append appends the given data. Data will NOT be copied.\nfunc (c *Container) Append(data []byte) {\n\tc.compartments = append(c.compartments, data)\n}\n\n// PrependNumber prepends a number (varint encoded).\nfunc (c *Container) PrependNumber(n uint64) {\n\tc.Prepend(varint.Pack64(n))\n}\n\n// AppendNumber appends a number (varint encoded).\nfunc (c *Container) AppendNumber(n uint64) {\n\tc.compartments = append(c.compartments, varint.Pack64(n))\n}\n\n// PrependInt prepends an int (varint encoded).\nfunc (c *Container) PrependInt(n int) {\n\tc.Prepend(varint.Pack64(uint64(n)))\n}\n\n// AppendInt appends an int (varint encoded).\nfunc (c *Container) AppendInt(n int) {\n\tc.compartments = append(c.compartments, varint.Pack64(uint64(n)))\n}\n\n// AppendAsBlock appends the length of the data and the data itself. Data will NOT be copied.\nfunc (c *Container) AppendAsBlock(data []byte) {\n\tc.AppendNumber(uint64(len(data)))\n\tc.Append(data)\n}\n\n// PrependAsBlock prepends the length of the data and the data itself. Data will NOT be copied.\nfunc (c *Container) PrependAsBlock(data []byte) {\n\tc.Prepend(data)\n\tc.PrependNumber(uint64(len(data)))\n}\n\n// AppendContainer appends another Container. Data will NOT be copied.\nfunc (c *Container) AppendContainer(data *Container) {\n\tc.compartments = append(c.compartments, data.compartments...)\n}\n\n// AppendContainerAsBlock appends another Container (length and data). Data will NOT be copied.\nfunc (c *Container) AppendContainerAsBlock(data *Container) {\n\tc.AppendNumber(uint64(data.Length()))\n\tc.compartments = append(c.compartments, data.compartments...)\n}\n\n// HoldsData returns true if the Container holds any data.\nfunc (c *Container) HoldsData() bool {\n\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\tif len(c.compartments[i]) > 0 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Length returns the full length of all bytes held by the container.\nfunc (c *Container) Length() (length int) {\n\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\tlength += len(c.compartments[i])\n\t}\n\treturn\n}\n\n// Replace replaces all held data with a new data slice. Data will NOT be copied.\nfunc (c *Container) Replace(data []byte) {\n\tc.compartments = [][]byte{data}\n}\n\n// CompileData concatenates all bytes held by the container and returns it as one single []byte slice. Data will NOT be copied and is NOT consumed.\nfunc (c *Container) CompileData() []byte {\n\tif len(c.compartments) != 1 {\n\t\tnewBuf := make([]byte, c.Length())\n\t\tcopyBuf := newBuf\n\t\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\t\tcopy(copyBuf, c.compartments[i])\n\t\t\tcopyBuf = copyBuf[len(c.compartments[i]):]\n\t\t}\n\t\tc.compartments = [][]byte{newBuf}\n\t\tc.offset = 0\n\t}\n\treturn c.compartments[0]\n}\n\n// Get returns the given amount of bytes. Data MAY be copied and IS consumed.\nfunc (c *Container) Get(n int) ([]byte, error) {\n\tbuf := c.Peek(n)\n\tif len(buf) < n {\n\t\treturn nil, errors.New(\"container: not enough data to return\")\n\t}\n\tc.skip(len(buf))\n\treturn buf, nil\n}\n\n// GetAll returns all data. Data MAY be copied and IS consumed.\nfunc (c *Container) GetAll() []byte {\n\t// TODO: Improve.\n\tbuf := c.Peek(c.Length())\n\tc.skip(len(buf))\n\treturn buf\n}\n\n// GetAsContainer returns the given amount of bytes in a new container. Data will NOT be copied and IS consumed.\nfunc (c *Container) GetAsContainer(n int) (*Container, error) {\n\tnewC := c.PeekContainer(n)\n\tif newC == nil {\n\t\treturn nil, errors.New(\"container: not enough data to return\")\n\t}\n\tc.skip(n)\n\treturn newC, nil\n}\n\n// GetMax returns as much as possible, but the given amount of bytes at maximum. Data MAY be copied and IS consumed.\nfunc (c *Container) GetMax(n int) []byte {\n\tbuf := c.Peek(n)\n\tc.skip(len(buf))\n\treturn buf\n}\n\n// WriteToSlice copies data to the give slice until it is full, or the container is empty. It returns the bytes written and if the container is now empty. Data IS copied and IS consumed.\nfunc (c *Container) WriteToSlice(slice []byte) (n int, containerEmptied bool) {\n\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\tcopy(slice, c.compartments[i])\n\t\tif len(slice) < len(c.compartments[i]) {\n\t\t\t// only part was copied\n\t\t\tn += len(slice)\n\t\t\tc.compartments[i] = c.compartments[i][len(slice):]\n\t\t\tc.checkOffset()\n\t\t\treturn n, false\n\t\t}\n\t\t// all was copied\n\t\tn += len(c.compartments[i])\n\t\tslice = slice[len(c.compartments[i]):]\n\t\tc.compartments[i] = nil\n\t\tc.offset = i + 1\n\t}\n\tc.checkOffset()\n\treturn n, true\n}\n\n// WriteAllTo writes all the data to the given io.Writer. Data IS NOT copied (but may be by writer) and IS NOT consumed.\nfunc (c *Container) WriteAllTo(writer io.Writer) error {\n\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\twritten := 0\n\t\tfor written < len(c.compartments[i]) {\n\t\t\tn, err := writer.Write(c.compartments[i][written:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\twritten += n\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *Container) clean() {\n\tif c.offset > 100 {\n\t\tc.renewCompartments()\n\t}\n}\n\nfunc (c *Container) renewCompartments() {\n\tbaseLength := len(c.compartments) - c.offset + 5\n\tnewCompartments := make([][]byte, baseLength, baseLength+5)\n\tcopy(newCompartments[5:], c.compartments[c.offset:])\n\tc.compartments = newCompartments\n\tc.offset = 4\n}\n\nfunc (c *Container) carbonCopy() *Container {\n\tnewC := &Container{\n\t\tcompartments: make([][]byte, len(c.compartments)),\n\t\toffset:       c.offset,\n\t\terr:          c.err,\n\t}\n\tcopy(newC.compartments, c.compartments)\n\treturn newC\n}\n\nfunc (c *Container) checkOffset() {\n\tif c.offset >= len(c.compartments) {\n\t\tc.offset = len(c.compartments) / 2\n\t}\n}\n\n// Block Handling\n\n// PrependLength prepends the current full length of all bytes in the container.\nfunc (c *Container) PrependLength() {\n\tc.Prepend(varint.Pack64(uint64(c.Length())))\n}\n\n// Peek returns the given amount of bytes. Data MAY be copied and IS NOT consumed.\nfunc (c *Container) Peek(n int) []byte {\n\t// Check requested length.\n\tif n <= 0 {\n\t\treturn nil\n\t}\n\n\t// Check if the first slice holds enough data.\n\tif len(c.compartments[c.offset]) >= n {\n\t\treturn c.compartments[c.offset][:n]\n\t}\n\n\t// Start gathering data.\n\tslice := make([]byte, n)\n\tcopySlice := slice\n\tn = 0\n\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\tcopy(copySlice, c.compartments[i])\n\t\tif len(copySlice) <= len(c.compartments[i]) {\n\t\t\tn += len(copySlice)\n\t\t\treturn slice[:n]\n\t\t}\n\t\tn += len(c.compartments[i])\n\t\tcopySlice = copySlice[len(c.compartments[i]):]\n\t}\n\treturn slice[:n]\n}\n\n// PeekContainer returns the given amount of bytes in a new container. Data will NOT be copied and IS NOT consumed.\nfunc (c *Container) PeekContainer(n int) (newC *Container) {\n\t// Check requested length.\n\tif n < 0 {\n\t\treturn nil\n\t} else if n == 0 {\n\t\treturn &Container{}\n\t}\n\n\tnewC = &Container{}\n\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\tif n >= len(c.compartments[i]) {\n\t\t\tnewC.compartments = append(newC.compartments, c.compartments[i])\n\t\t\tn -= len(c.compartments[i])\n\t\t} else {\n\t\t\tnewC.compartments = append(newC.compartments, c.compartments[i][:n])\n\t\t\tn = 0\n\t\t}\n\t}\n\tif n > 0 {\n\t\treturn nil\n\t}\n\treturn newC\n}\n\nfunc (c *Container) skip(n int) {\n\tfor i := c.offset; i < len(c.compartments); i++ {\n\t\tif len(c.compartments[i]) <= n {\n\t\t\tn -= len(c.compartments[i])\n\t\t\tc.offset = i + 1\n\t\t\tc.compartments[i] = nil\n\t\t\tif n == 0 {\n\t\t\t\tc.checkOffset()\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tc.compartments[i] = c.compartments[i][n:]\n\t\t\tc.checkOffset()\n\t\t\treturn\n\t\t}\n\t}\n\tc.checkOffset()\n}\n\n// GetNextBlock returns the next block of data defined by a varint. Data MAY be copied and IS consumed.\nfunc (c *Container) GetNextBlock() ([]byte, error) {\n\tblockSize, err := c.GetNextN64()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn c.Get(int(blockSize))\n}\n\n// GetNextBlockAsContainer returns the next block of data as a Container defined by a varint. Data will NOT be copied and IS consumed.\nfunc (c *Container) GetNextBlockAsContainer() (*Container, error) {\n\tblockSize, err := c.GetNextN64()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn c.GetAsContainer(int(blockSize))\n}\n\n// GetNextN8 parses and returns a varint of type uint8.\nfunc (c *Container) GetNextN8() (uint8, error) {\n\tbuf := c.Peek(2)\n\tnum, n, err := varint.Unpack8(buf)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tc.skip(n)\n\treturn num, nil\n}\n\n// GetNextN16 parses and returns a varint of type uint16.\nfunc (c *Container) GetNextN16() (uint16, error) {\n\tbuf := c.Peek(3)\n\tnum, n, err := varint.Unpack16(buf)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tc.skip(n)\n\treturn num, nil\n}\n\n// GetNextN32 parses and returns a varint of type uint32.\nfunc (c *Container) GetNextN32() (uint32, error) {\n\tbuf := c.Peek(5)\n\tnum, n, err := varint.Unpack32(buf)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tc.skip(n)\n\treturn num, nil\n}\n\n// GetNextN64 parses and returns a varint of type uint64.\nfunc (c *Container) GetNextN64() (uint64, error) {\n\tbuf := c.Peek(10)\n\tnum, n, err := varint.Unpack64(buf)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tc.skip(n)\n\treturn num, nil\n}\n"
  },
  {
    "path": "base/container/container_test.go",
    "content": "package container\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\nvar (\n\ttestData         = []byte(\"The quick brown fox jumps over the lazy dog\")\n\ttestDataSplitted = [][]byte{\n\t\t[]byte(\"T\"),\n\t\t[]byte(\"he\"),\n\t\t[]byte(\" qu\"),\n\t\t[]byte(\"ick \"),\n\t\t[]byte(\"brown\"),\n\t\t[]byte(\" fox j\"),\n\t\t[]byte(\"umps ov\"),\n\t\t[]byte(\"er the l\"),\n\t\t[]byte(\"azy dog\"),\n\t}\n)\n\nfunc TestContainerDataHandling(t *testing.T) {\n\tt.Parallel()\n\n\tc1 := New(utils.DuplicateBytes(testData))\n\tc1c := c1.carbonCopy()\n\n\tc2 := New()\n\tfor range len(testData) {\n\t\toneByte := make([]byte, 1)\n\t\tc1c.WriteToSlice(oneByte)\n\t\tc2.Append(oneByte)\n\t}\n\tc2c := c2.carbonCopy()\n\n\tc3 := New()\n\tfor i := len(c2c.compartments) - 1; i >= c2c.offset; i-- {\n\t\tc3.Prepend(c2c.compartments[i])\n\t}\n\tc3c := c3.carbonCopy()\n\n\td4 := make([]byte, len(testData)*2)\n\tn, _ := c3c.WriteToSlice(d4)\n\td4 = d4[:n]\n\tc3c = c3.carbonCopy()\n\n\td5 := make([]byte, len(testData))\n\tfor i := range len(testData) {\n\t\tc3c.WriteToSlice(d5[i : i+1])\n\t}\n\n\tc6 := New()\n\tc6.Replace(testData)\n\n\tc7 := New(testDataSplitted[0])\n\tfor i := 1; i < len(testDataSplitted); i++ {\n\t\tc7.Append(testDataSplitted[i])\n\t}\n\n\tc8 := New(testDataSplitted...)\n\tfor range 110 {\n\t\tc8.Prepend(nil)\n\t}\n\tc8.clean()\n\n\tc9 := c8.PeekContainer(len(testData))\n\n\tc10 := c9.PeekContainer(len(testData) - 1)\n\tc10.Append(testData[len(testData)-1:])\n\n\tcompareMany(t, testData, c1.CompileData(), c2.CompileData(), c3.CompileData(), d4, d5, c6.CompileData(), c7.CompileData(), c8.CompileData(), c9.CompileData(), c10.CompileData())\n}\n\nfunc compareMany(t *testing.T, reference []byte, other ...[]byte) {\n\tt.Helper()\n\n\tfor i, cmp := range other {\n\t\tif !bytes.Equal(reference, cmp) {\n\t\t\tt.Errorf(\"sample %d does not match reference: sample is '%s'\", i+1, string(cmp))\n\t\t}\n\t}\n}\n\nfunc TestDataFetching(t *testing.T) {\n\tt.Parallel()\n\n\tc1 := New(utils.DuplicateBytes(testData))\n\tdata := c1.GetMax(1)\n\tif string(data[0]) != \"T\" {\n\t\tt.Errorf(\"failed to GetMax(1), got %s, expected %s\", string(data), \"T\")\n\t}\n\n\t_, err := c1.Get(1000)\n\tif err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n\n\t_, err = c1.GetAsContainer(1000)\n\tif err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n}\n\nfunc TestBlocks(t *testing.T) {\n\tt.Parallel()\n\n\tc1 := New(utils.DuplicateBytes(testData))\n\tc1.PrependLength()\n\n\tn, err := c1.GetNextN8()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextN8() failed: %s\", err)\n\t}\n\tif n != 43 {\n\t\tt.Errorf(\"n should be 43, was %d\", n)\n\t}\n\tc1.PrependLength()\n\n\tn2, err := c1.GetNextN16()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextN16() failed: %s\", err)\n\t}\n\tif n2 != 43 {\n\t\tt.Errorf(\"n should be 43, was %d\", n2)\n\t}\n\tc1.PrependLength()\n\n\tn3, err := c1.GetNextN32()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextN32() failed: %s\", err)\n\t}\n\tif n3 != 43 {\n\t\tt.Errorf(\"n should be 43, was %d\", n3)\n\t}\n\tc1.PrependLength()\n\n\tn4, err := c1.GetNextN64()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextN64() failed: %s\", err)\n\t}\n\tif n4 != 43 {\n\t\tt.Errorf(\"n should be 43, was %d\", n4)\n\t}\n}\n\nfunc TestContainerBlockHandling(t *testing.T) {\n\tt.Parallel()\n\n\tc1 := New(utils.DuplicateBytes(testData))\n\tc1.PrependLength()\n\tc1.AppendAsBlock(testData)\n\tc1c := c1.carbonCopy()\n\n\tc2 := New(nil)\n\tfor range c1.Length() {\n\t\toneByte := make([]byte, 1)\n\t\tc1c.WriteToSlice(oneByte)\n\t\tc2.Append(oneByte)\n\t}\n\n\tc3 := New(testDataSplitted[0])\n\tfor i := 1; i < len(testDataSplitted); i++ {\n\t\tc3.Append(testDataSplitted[i])\n\t}\n\tc3.PrependLength()\n\n\td1, err := c1.GetNextBlock()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextBlock failed: %s\", err)\n\t}\n\td2, err := c1.GetNextBlock()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextBlock failed: %s\", err)\n\t}\n\td3, err := c2.GetNextBlock()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextBlock failed: %s\", err)\n\t}\n\td4, err := c2.GetNextBlock()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextBlock failed: %s\", err)\n\t}\n\td5, err := c3.GetNextBlock()\n\tif err != nil {\n\t\tt.Errorf(\"GetNextBlock failed: %s\", err)\n\t}\n\n\tcompareMany(t, testData, d1, d2, d3, d4, d5)\n}\n\nfunc TestContainerMisc(t *testing.T) {\n\tt.Parallel()\n\n\tc1 := New()\n\td1 := c1.CompileData()\n\tif len(d1) > 0 {\n\t\tt.Fatalf(\"empty container should not hold any data\")\n\t}\n}\n\nfunc TestDeprecated(t *testing.T) {\n\tt.Parallel()\n\n\tNewContainer(utils.DuplicateBytes(testData))\n}\n"
  },
  {
    "path": "base/container/doc.go",
    "content": "// Package container gives you a []byte slice on steroids, allowing for quick data appending, prepending and fetching as well as transparent error transportation.\n//\n// A Container is basically a [][]byte slice that just appends new []byte slices and only copies things around when necessary.\n//\n// Byte slices added to the Container are not changed or appended, to not corrupt any other data that may be before and after the given slice.\n// If interested, consider the following example to understand why this is important:\n//\n//\tpackage main\n//\n//\timport (\n//\t\t\"fmt\"\n//\t)\n//\n//\tfunc main() {\n//\t\ta := []byte{0, 1,2,3,4,5,6,7,8,9}\n//\t\tfmt.Printf(\"a: %+v\\n\", a)\n//\t\tfmt.Printf(\"\\nmaking changes...\\n(we are not changing a directly)\\n\\n\")\n//\t\tb := a[2:6]\n//\t\tc := append(b, 10, 11)\n//\t\tfmt.Printf(\"b: %+v\\n\", b)\n//\t\tfmt.Printf(\"c: %+v\\n\", c)\n//\t\tfmt.Printf(\"a: %+v\\n\", a)\n//\t}\n//\n// run it here: https://play.golang.org/p/xu1BXT3QYeE\npackage container\n"
  },
  {
    "path": "base/container/serialization.go",
    "content": "package container\n\nimport (\n\t\"encoding/json\"\n)\n\n// MarshalJSON serializes the container as a JSON byte array.\nfunc (c *Container) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(c.CompileData())\n}\n\n// UnmarshalJSON unserializes a container from a JSON byte array.\nfunc (c *Container) UnmarshalJSON(data []byte) error {\n\tvar raw []byte\n\tif err := json.Unmarshal(data, &raw); err != nil {\n\t\treturn err\n\t}\n\n\tc.compartments = [][]byte{raw}\n\treturn nil\n}\n"
  },
  {
    "path": "base/database/accessor/accessor-json-bytes.go",
    "content": "package accessor\n\nimport (\n\t\"github.com/tidwall/gjson\"\n\t\"github.com/tidwall/sjson\"\n)\n\n// JSONBytesAccessor is a json string with get functions.\ntype JSONBytesAccessor struct {\n\tjson *[]byte\n}\n\n// NewJSONBytesAccessor adds the Accessor interface to a JSON bytes string.\nfunc NewJSONBytesAccessor(json *[]byte) *JSONBytesAccessor {\n\treturn &JSONBytesAccessor{\n\t\tjson: json,\n\t}\n}\n\n// Set sets the value identified by key.\nfunc (ja *JSONBytesAccessor) Set(key string, value interface{}) error {\n\tresult := gjson.GetBytes(*ja.json, key)\n\tif result.Exists() {\n\t\terr := checkJSONValueType(result, key, value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tnewJSON, err := sjson.SetBytes(*ja.json, key, value)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*ja.json = newJSON\n\treturn nil\n}\n\n// Get returns the value found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONBytesAccessor) Get(key string) (value interface{}, ok bool) {\n\tresult := gjson.GetBytes(*ja.json, key)\n\tif !result.Exists() {\n\t\treturn nil, false\n\t}\n\treturn result.Value(), true\n}\n\n// GetString returns the string found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONBytesAccessor) GetString(key string) (value string, ok bool) {\n\tresult := gjson.GetBytes(*ja.json, key)\n\tif !result.Exists() || result.Type != gjson.String {\n\t\treturn emptyString, false\n\t}\n\treturn result.String(), true\n}\n\n// GetStringArray returns the []string found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONBytesAccessor) GetStringArray(key string) (value []string, ok bool) {\n\tresult := gjson.GetBytes(*ja.json, key)\n\tif !result.Exists() && !result.IsArray() {\n\t\treturn nil, false\n\t}\n\tslice := result.Array()\n\tsliceCopy := make([]string, len(slice))\n\tfor i, res := range slice {\n\t\tif res.Type == gjson.String {\n\t\t\tsliceCopy[i] = res.String()\n\t\t} else {\n\t\t\treturn nil, false\n\t\t}\n\t}\n\treturn sliceCopy, true\n}\n\n// GetInt returns the int found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONBytesAccessor) GetInt(key string) (value int64, ok bool) {\n\tresult := gjson.GetBytes(*ja.json, key)\n\tif !result.Exists() || result.Type != gjson.Number {\n\t\treturn 0, false\n\t}\n\treturn result.Int(), true\n}\n\n// GetFloat returns the float found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONBytesAccessor) GetFloat(key string) (value float64, ok bool) {\n\tresult := gjson.GetBytes(*ja.json, key)\n\tif !result.Exists() || result.Type != gjson.Number {\n\t\treturn 0, false\n\t}\n\treturn result.Float(), true\n}\n\n// GetBool returns the bool found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONBytesAccessor) GetBool(key string) (value bool, ok bool) {\n\tresult := gjson.GetBytes(*ja.json, key)\n\tswitch {\n\tcase !result.Exists():\n\t\treturn false, false\n\tcase result.Type == gjson.True:\n\t\treturn true, true\n\tcase result.Type == gjson.False:\n\t\treturn false, true\n\tdefault:\n\t\treturn false, false\n\t}\n}\n\n// Exists returns the whether the given key exists.\nfunc (ja *JSONBytesAccessor) Exists(key string) bool {\n\tresult := gjson.GetBytes(*ja.json, key)\n\treturn result.Exists()\n}\n\n// Type returns the accessor type as a string.\nfunc (ja *JSONBytesAccessor) Type() string {\n\treturn \"JSONBytesAccessor\"\n}\n"
  },
  {
    "path": "base/database/accessor/accessor-json-string.go",
    "content": "package accessor\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/tidwall/gjson\"\n\t\"github.com/tidwall/sjson\"\n)\n\n// JSONAccessor is a json string with get functions.\ntype JSONAccessor struct {\n\tjson *string\n}\n\n// NewJSONAccessor adds the Accessor interface to a JSON string.\nfunc NewJSONAccessor(json *string) *JSONAccessor {\n\treturn &JSONAccessor{\n\t\tjson: json,\n\t}\n}\n\n// Set sets the value identified by key.\nfunc (ja *JSONAccessor) Set(key string, value interface{}) error {\n\tresult := gjson.Get(*ja.json, key)\n\tif result.Exists() {\n\t\terr := checkJSONValueType(result, key, value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tnewJSON, err := sjson.Set(*ja.json, key, value)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*ja.json = newJSON\n\treturn nil\n}\n\nfunc checkJSONValueType(jsonValue gjson.Result, key string, value interface{}) error {\n\tswitch value.(type) {\n\tcase string:\n\t\tif jsonValue.Type != gjson.String {\n\t\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %T value\", key, jsonValue.Type.String(), value)\n\t\t}\n\tcase int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:\n\t\tif jsonValue.Type != gjson.Number {\n\t\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %T value\", key, jsonValue.Type.String(), value)\n\t\t}\n\tcase bool:\n\t\tif jsonValue.Type != gjson.True && jsonValue.Type != gjson.False {\n\t\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %T value\", key, jsonValue.Type.String(), value)\n\t\t}\n\tcase []string:\n\t\tif !jsonValue.IsArray() {\n\t\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %T value\", key, jsonValue.Type.String(), value)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Get returns the value found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONAccessor) Get(key string) (value interface{}, ok bool) {\n\tresult := gjson.Get(*ja.json, key)\n\tif !result.Exists() {\n\t\treturn nil, false\n\t}\n\treturn result.Value(), true\n}\n\n// GetString returns the string found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONAccessor) GetString(key string) (value string, ok bool) {\n\tresult := gjson.Get(*ja.json, key)\n\tif !result.Exists() || result.Type != gjson.String {\n\t\treturn emptyString, false\n\t}\n\treturn result.String(), true\n}\n\n// GetStringArray returns the []string found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONAccessor) GetStringArray(key string) (value []string, ok bool) {\n\tresult := gjson.Get(*ja.json, key)\n\tif !result.Exists() && !result.IsArray() {\n\t\treturn nil, false\n\t}\n\tslice := result.Array()\n\tsliceCopy := make([]string, len(slice))\n\tfor i, res := range slice {\n\t\tif res.Type == gjson.String {\n\t\t\tsliceCopy[i] = res.String()\n\t\t} else {\n\t\t\treturn nil, false\n\t\t}\n\t}\n\treturn sliceCopy, true\n}\n\n// GetInt returns the int found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONAccessor) GetInt(key string) (value int64, ok bool) {\n\tresult := gjson.Get(*ja.json, key)\n\tif !result.Exists() || result.Type != gjson.Number {\n\t\treturn 0, false\n\t}\n\treturn result.Int(), true\n}\n\n// GetFloat returns the float found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONAccessor) GetFloat(key string) (value float64, ok bool) {\n\tresult := gjson.Get(*ja.json, key)\n\tif !result.Exists() || result.Type != gjson.Number {\n\t\treturn 0, false\n\t}\n\treturn result.Float(), true\n}\n\n// GetBool returns the bool found by the given json key and whether it could be successfully extracted.\nfunc (ja *JSONAccessor) GetBool(key string) (value bool, ok bool) {\n\tresult := gjson.Get(*ja.json, key)\n\tswitch {\n\tcase !result.Exists():\n\t\treturn false, false\n\tcase result.Type == gjson.True:\n\t\treturn true, true\n\tcase result.Type == gjson.False:\n\t\treturn false, true\n\tdefault:\n\t\treturn false, false\n\t}\n}\n\n// Exists returns the whether the given key exists.\nfunc (ja *JSONAccessor) Exists(key string) bool {\n\tresult := gjson.Get(*ja.json, key)\n\treturn result.Exists()\n}\n\n// Type returns the accessor type as a string.\nfunc (ja *JSONAccessor) Type() string {\n\treturn \"JSONAccessor\"\n}\n"
  },
  {
    "path": "base/database/accessor/accessor-struct.go",
    "content": "package accessor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n)\n\n// StructAccessor is a json string with get functions.\ntype StructAccessor struct {\n\tobject reflect.Value\n}\n\n// NewStructAccessor adds the Accessor interface to a JSON string.\nfunc NewStructAccessor(object interface{}) *StructAccessor {\n\treturn &StructAccessor{\n\t\tobject: reflect.ValueOf(object).Elem(),\n\t}\n}\n\n// Set sets the value identified by key.\nfunc (sa *StructAccessor) Set(key string, value interface{}) error {\n\tfield := sa.object.FieldByName(key)\n\tif !field.IsValid() {\n\t\treturn errors.New(\"struct field does not exist\")\n\t}\n\tif !field.CanSet() {\n\t\treturn fmt.Errorf(\"field %s or struct is immutable\", field.String())\n\t}\n\n\tnewVal := reflect.ValueOf(value)\n\n\t// set directly if type matches\n\tif newVal.Kind() == field.Kind() {\n\t\tfield.Set(newVal)\n\t\treturn nil\n\t}\n\n\t// handle special cases\n\tswitch field.Kind() { // nolint:exhaustive\n\n\t// ints\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\tvar newInt int64\n\t\tswitch newVal.Kind() { // nolint:exhaustive\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\tnewInt = newVal.Int()\n\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\t\tnewInt = int64(newVal.Uint())\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %s value\", key, field.Kind().String(), newVal.Kind().String())\n\t\t}\n\t\tif field.OverflowInt(newInt) {\n\t\t\treturn fmt.Errorf(\"setting field %s (%s) to %d would overflow\", key, field.Kind().String(), newInt)\n\t\t}\n\t\tfield.SetInt(newInt)\n\n\t\t// uints\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\tvar newUint uint64\n\t\tswitch newVal.Kind() { // nolint:exhaustive\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\t\tnewUint = uint64(newVal.Int())\n\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\t\tnewUint = newVal.Uint()\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %s value\", key, field.Kind().String(), newVal.Kind().String())\n\t\t}\n\t\tif field.OverflowUint(newUint) {\n\t\t\treturn fmt.Errorf(\"setting field %s (%s) to %d would overflow\", key, field.Kind().String(), newUint)\n\t\t}\n\t\tfield.SetUint(newUint)\n\n\t\t// floats\n\tcase reflect.Float32, reflect.Float64:\n\t\tswitch newVal.Kind() { // nolint:exhaustive\n\t\tcase reflect.Float32, reflect.Float64:\n\t\t\tfield.SetFloat(newVal.Float())\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %s value\", key, field.Kind().String(), newVal.Kind().String())\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"tried to set field %s (%s) to a %s value\", key, field.Kind().String(), newVal.Kind().String())\n\t}\n\n\treturn nil\n}\n\n// Get returns the value found by the given json key and whether it could be successfully extracted.\nfunc (sa *StructAccessor) Get(key string) (value interface{}, ok bool) {\n\tfield := sa.object.FieldByName(key)\n\tif !field.IsValid() || !field.CanInterface() {\n\t\treturn nil, false\n\t}\n\treturn field.Interface(), true\n}\n\n// GetString returns the string found by the given json key and whether it could be successfully extracted.\nfunc (sa *StructAccessor) GetString(key string) (value string, ok bool) {\n\tfield := sa.object.FieldByName(key)\n\tif !field.IsValid() || field.Kind() != reflect.String {\n\t\treturn \"\", false\n\t}\n\treturn field.String(), true\n}\n\n// GetStringArray returns the []string found by the given json key and whether it could be successfully extracted.\nfunc (sa *StructAccessor) GetStringArray(key string) (value []string, ok bool) {\n\tfield := sa.object.FieldByName(key)\n\tif !field.IsValid() || field.Kind() != reflect.Slice || !field.CanInterface() {\n\t\treturn nil, false\n\t}\n\tv := field.Interface()\n\tslice, ok := v.([]string)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\treturn slice, true\n}\n\n// GetInt returns the int found by the given json key and whether it could be successfully extracted.\nfunc (sa *StructAccessor) GetInt(key string) (value int64, ok bool) {\n\tfield := sa.object.FieldByName(key)\n\tif !field.IsValid() {\n\t\treturn 0, false\n\t}\n\tswitch field.Kind() { // nolint:exhaustive\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn field.Int(), true\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\n\t\treturn int64(field.Uint()), true\n\tdefault:\n\t\treturn 0, false\n\t}\n}\n\n// GetFloat returns the float found by the given json key and whether it could be successfully extracted.\nfunc (sa *StructAccessor) GetFloat(key string) (value float64, ok bool) {\n\tfield := sa.object.FieldByName(key)\n\tif !field.IsValid() {\n\t\treturn 0, false\n\t}\n\tswitch field.Kind() { // nolint:exhaustive\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn field.Float(), true\n\tdefault:\n\t\treturn 0, false\n\t}\n}\n\n// GetBool returns the bool found by the given json key and whether it could be successfully extracted.\nfunc (sa *StructAccessor) GetBool(key string) (value bool, ok bool) {\n\tfield := sa.object.FieldByName(key)\n\tif !field.IsValid() || field.Kind() != reflect.Bool {\n\t\treturn false, false\n\t}\n\treturn field.Bool(), true\n}\n\n// Exists returns the whether the given key exists.\nfunc (sa *StructAccessor) Exists(key string) bool {\n\tfield := sa.object.FieldByName(key)\n\treturn field.IsValid()\n}\n\n// Type returns the accessor type as a string.\nfunc (sa *StructAccessor) Type() string {\n\treturn \"StructAccessor\"\n}\n"
  },
  {
    "path": "base/database/accessor/accessor.go",
    "content": "package accessor\n\nconst (\n\temptyString = \"\"\n)\n\n// Accessor provides an interface to supply the query matcher a method to retrieve values from an object.\ntype Accessor interface {\n\tGet(key string) (value interface{}, ok bool)\n\tGetString(key string) (value string, ok bool)\n\tGetStringArray(key string) (value []string, ok bool)\n\tGetInt(key string) (value int64, ok bool)\n\tGetFloat(key string) (value float64, ok bool)\n\tGetBool(key string) (value bool, ok bool)\n\tExists(key string) bool\n\tSet(key string, value interface{}) error\n\tType() string\n}\n"
  },
  {
    "path": "base/database/accessor/accessor_test.go",
    "content": "//nolint:maligned,unparam\npackage accessor\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\ntype TestStruct struct {\n\tS    string\n\tA    []string\n\tI    int\n\tI8   int8\n\tI16  int16\n\tI32  int32\n\tI64  int64\n\tUI   uint\n\tUI8  uint8\n\tUI16 uint16\n\tUI32 uint32\n\tUI64 uint64\n\tF32  float32\n\tF64  float64\n\tB    bool\n}\n\nvar (\n\ttestStruct = &TestStruct{\n\t\tS:    \"banana\",\n\t\tA:    []string{\"black\", \"white\"},\n\t\tI:    42,\n\t\tI8:   42,\n\t\tI16:  42,\n\t\tI32:  42,\n\t\tI64:  42,\n\t\tUI:   42,\n\t\tUI8:  42,\n\t\tUI16: 42,\n\t\tUI32: 42,\n\t\tUI64: 42,\n\t\tF32:  42.42,\n\t\tF64:  42.42,\n\t\tB:    true,\n\t}\n\ttestJSONBytes, _ = json.Marshal(testStruct) //nolint:errchkjson\n\ttestJSON         = string(testJSONBytes)\n)\n\nfunc testGetString(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue string) {\n\tt.Helper()\n\n\tv, ok := acc.GetString(key)\n\tswitch {\n\tcase !ok && shouldSucceed:\n\t\tt.Errorf(\"%s failed to get string with key %s\", acc.Type(), key)\n\tcase ok && !shouldSucceed:\n\t\tt.Errorf(\"%s should have failed to get string with key %s, it returned %v\", acc.Type(), key, v)\n\t}\n\tif v != expectedValue {\n\t\tt.Errorf(\"%s returned an unexpected value: wanted %v, got %v\", acc.Type(), expectedValue, v)\n\t}\n}\n\nfunc testGetStringArray(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue []string) {\n\tt.Helper()\n\n\tv, ok := acc.GetStringArray(key)\n\tswitch {\n\tcase !ok && shouldSucceed:\n\t\tt.Errorf(\"%s failed to get []string with key %s\", acc.Type(), key)\n\tcase ok && !shouldSucceed:\n\t\tt.Errorf(\"%s should have failed to get []string with key %s, it returned %v\", acc.Type(), key, v)\n\t}\n\tif !utils.StringSliceEqual(v, expectedValue) {\n\t\tt.Errorf(\"%s returned an unexpected value: wanted %v, got %v\", acc.Type(), expectedValue, v)\n\t}\n}\n\nfunc testGetInt(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue int64) {\n\tt.Helper()\n\n\tv, ok := acc.GetInt(key)\n\tswitch {\n\tcase !ok && shouldSucceed:\n\t\tt.Errorf(\"%s failed to get int with key %s\", acc.Type(), key)\n\tcase ok && !shouldSucceed:\n\t\tt.Errorf(\"%s should have failed to get int with key %s, it returned %v\", acc.Type(), key, v)\n\t}\n\tif v != expectedValue {\n\t\tt.Errorf(\"%s returned an unexpected value: wanted %v, got %v\", acc.Type(), expectedValue, v)\n\t}\n}\n\nfunc testGetFloat(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue float64) {\n\tt.Helper()\n\n\tv, ok := acc.GetFloat(key)\n\tswitch {\n\tcase !ok && shouldSucceed:\n\t\tt.Errorf(\"%s failed to get float with key %s\", acc.Type(), key)\n\tcase ok && !shouldSucceed:\n\t\tt.Errorf(\"%s should have failed to get float with key %s, it returned %v\", acc.Type(), key, v)\n\t}\n\tif int64(v) != int64(expectedValue) {\n\t\tt.Errorf(\"%s returned an unexpected value: wanted %v, got %v\", acc.Type(), expectedValue, v)\n\t}\n}\n\nfunc testGetBool(t *testing.T, acc Accessor, key string, shouldSucceed bool, expectedValue bool) {\n\tt.Helper()\n\n\tv, ok := acc.GetBool(key)\n\tswitch {\n\tcase !ok && shouldSucceed:\n\t\tt.Errorf(\"%s failed to get bool with key %s\", acc.Type(), key)\n\tcase ok && !shouldSucceed:\n\t\tt.Errorf(\"%s should have failed to get bool with key %s, it returned %v\", acc.Type(), key, v)\n\t}\n\tif v != expectedValue {\n\t\tt.Errorf(\"%s returned an unexpected value: wanted %v, got %v\", acc.Type(), expectedValue, v)\n\t}\n}\n\nfunc testExists(t *testing.T, acc Accessor, key string, shouldSucceed bool) {\n\tt.Helper()\n\n\tok := acc.Exists(key)\n\tswitch {\n\tcase !ok && shouldSucceed:\n\t\tt.Errorf(\"%s should report key %s as existing\", acc.Type(), key)\n\tcase ok && !shouldSucceed:\n\t\tt.Errorf(\"%s should report key %s as non-existing\", acc.Type(), key)\n\t}\n}\n\nfunc testSet(t *testing.T, acc Accessor, key string, shouldSucceed bool, valueToSet interface{}) {\n\tt.Helper()\n\n\terr := acc.Set(key, valueToSet)\n\tswitch {\n\tcase err != nil && shouldSucceed:\n\t\tt.Errorf(\"%s failed to set %s to %+v: %s\", acc.Type(), key, valueToSet, err)\n\tcase err == nil && !shouldSucceed:\n\t\tt.Errorf(\"%s should have failed to set %s to %+v\", acc.Type(), key, valueToSet)\n\t}\n}\n\nfunc TestAccessor(t *testing.T) {\n\tt.Parallel()\n\n\t// Test interface compliance.\n\taccs := []Accessor{\n\t\tNewJSONAccessor(&testJSON),\n\t\tNewJSONBytesAccessor(&testJSONBytes),\n\t\tNewStructAccessor(testStruct),\n\t}\n\n\t// get\n\tfor _, acc := range accs {\n\t\ttestGetString(t, acc, \"S\", true, \"banana\")\n\t\ttestGetStringArray(t, acc, \"A\", true, []string{\"black\", \"white\"})\n\t\ttestGetInt(t, acc, \"I\", true, 42)\n\t\ttestGetInt(t, acc, \"I8\", true, 42)\n\t\ttestGetInt(t, acc, \"I16\", true, 42)\n\t\ttestGetInt(t, acc, \"I32\", true, 42)\n\t\ttestGetInt(t, acc, \"I64\", true, 42)\n\t\ttestGetInt(t, acc, \"UI\", true, 42)\n\t\ttestGetInt(t, acc, \"UI8\", true, 42)\n\t\ttestGetInt(t, acc, \"UI16\", true, 42)\n\t\ttestGetInt(t, acc, \"UI32\", true, 42)\n\t\ttestGetInt(t, acc, \"UI64\", true, 42)\n\t\ttestGetFloat(t, acc, \"F32\", true, 42.42)\n\t\ttestGetFloat(t, acc, \"F64\", true, 42.42)\n\t\ttestGetBool(t, acc, \"B\", true, true)\n\t}\n\n\t// set\n\tfor _, acc := range accs {\n\t\ttestSet(t, acc, \"S\", true, \"coconut\")\n\t\ttestSet(t, acc, \"A\", true, []string{\"green\", \"blue\"})\n\t\ttestSet(t, acc, \"I\", true, uint32(44))\n\t\ttestSet(t, acc, \"I8\", true, uint64(44))\n\t\ttestSet(t, acc, \"I16\", true, uint8(44))\n\t\ttestSet(t, acc, \"I32\", true, uint16(44))\n\t\ttestSet(t, acc, \"I64\", true, 44)\n\t\ttestSet(t, acc, \"UI\", true, 44)\n\t\ttestSet(t, acc, \"UI8\", true, int64(44))\n\t\ttestSet(t, acc, \"UI16\", true, int32(44))\n\t\ttestSet(t, acc, \"UI32\", true, int8(44))\n\t\ttestSet(t, acc, \"UI64\", true, int16(44))\n\t\ttestSet(t, acc, \"F32\", true, 44.44)\n\t\ttestSet(t, acc, \"F64\", true, 44.44)\n\t\ttestSet(t, acc, \"B\", true, false)\n\t}\n\n\t// get again to check if new values were set\n\tfor _, acc := range accs {\n\t\ttestGetString(t, acc, \"S\", true, \"coconut\")\n\t\ttestGetStringArray(t, acc, \"A\", true, []string{\"green\", \"blue\"})\n\t\ttestGetInt(t, acc, \"I\", true, 44)\n\t\ttestGetInt(t, acc, \"I8\", true, 44)\n\t\ttestGetInt(t, acc, \"I16\", true, 44)\n\t\ttestGetInt(t, acc, \"I32\", true, 44)\n\t\ttestGetInt(t, acc, \"I64\", true, 44)\n\t\ttestGetInt(t, acc, \"UI\", true, 44)\n\t\ttestGetInt(t, acc, \"UI8\", true, 44)\n\t\ttestGetInt(t, acc, \"UI16\", true, 44)\n\t\ttestGetInt(t, acc, \"UI32\", true, 44)\n\t\ttestGetInt(t, acc, \"UI64\", true, 44)\n\t\ttestGetFloat(t, acc, \"F32\", true, 44.44)\n\t\ttestGetFloat(t, acc, \"F64\", true, 44.44)\n\t\ttestGetBool(t, acc, \"B\", true, false)\n\t}\n\n\t// failures\n\tfor _, acc := range accs {\n\t\ttestSet(t, acc, \"S\", false, true)\n\t\ttestSet(t, acc, \"S\", false, false)\n\t\ttestSet(t, acc, \"S\", false, 1)\n\t\ttestSet(t, acc, \"S\", false, 1.1)\n\n\t\ttestSet(t, acc, \"A\", false, \"1\")\n\t\ttestSet(t, acc, \"A\", false, true)\n\t\ttestSet(t, acc, \"A\", false, false)\n\t\ttestSet(t, acc, \"A\", false, 1)\n\t\ttestSet(t, acc, \"A\", false, 1.1)\n\n\t\ttestSet(t, acc, \"I\", false, \"1\")\n\t\ttestSet(t, acc, \"I8\", false, \"1\")\n\t\ttestSet(t, acc, \"I16\", false, \"1\")\n\t\ttestSet(t, acc, \"I32\", false, \"1\")\n\t\ttestSet(t, acc, \"I64\", false, \"1\")\n\t\ttestSet(t, acc, \"UI\", false, \"1\")\n\t\ttestSet(t, acc, \"UI8\", false, \"1\")\n\t\ttestSet(t, acc, \"UI16\", false, \"1\")\n\t\ttestSet(t, acc, \"UI32\", false, \"1\")\n\t\ttestSet(t, acc, \"UI64\", false, \"1\")\n\n\t\ttestSet(t, acc, \"F32\", false, \"1.1\")\n\t\ttestSet(t, acc, \"F64\", false, \"1.1\")\n\n\t\ttestSet(t, acc, \"B\", false, \"false\")\n\t\ttestSet(t, acc, \"B\", false, 1)\n\t\ttestSet(t, acc, \"B\", false, 1.1)\n\t}\n\n\t// get again to check if values werent changed when an error occurred\n\tfor _, acc := range accs {\n\t\ttestGetString(t, acc, \"S\", true, \"coconut\")\n\t\ttestGetStringArray(t, acc, \"A\", true, []string{\"green\", \"blue\"})\n\t\ttestGetInt(t, acc, \"I\", true, 44)\n\t\ttestGetInt(t, acc, \"I8\", true, 44)\n\t\ttestGetInt(t, acc, \"I16\", true, 44)\n\t\ttestGetInt(t, acc, \"I32\", true, 44)\n\t\ttestGetInt(t, acc, \"I64\", true, 44)\n\t\ttestGetInt(t, acc, \"UI\", true, 44)\n\t\ttestGetInt(t, acc, \"UI8\", true, 44)\n\t\ttestGetInt(t, acc, \"UI16\", true, 44)\n\t\ttestGetInt(t, acc, \"UI32\", true, 44)\n\t\ttestGetInt(t, acc, \"UI64\", true, 44)\n\t\ttestGetFloat(t, acc, \"F32\", true, 44.44)\n\t\ttestGetFloat(t, acc, \"F64\", true, 44.44)\n\t\ttestGetBool(t, acc, \"B\", true, false)\n\t}\n\n\t// test existence\n\tfor _, acc := range accs {\n\t\ttestExists(t, acc, \"S\", true)\n\t\ttestExists(t, acc, \"A\", true)\n\t\ttestExists(t, acc, \"I\", true)\n\t\ttestExists(t, acc, \"I8\", true)\n\t\ttestExists(t, acc, \"I16\", true)\n\t\ttestExists(t, acc, \"I32\", true)\n\t\ttestExists(t, acc, \"I64\", true)\n\t\ttestExists(t, acc, \"UI\", true)\n\t\ttestExists(t, acc, \"UI8\", true)\n\t\ttestExists(t, acc, \"UI16\", true)\n\t\ttestExists(t, acc, \"UI32\", true)\n\t\ttestExists(t, acc, \"UI64\", true)\n\t\ttestExists(t, acc, \"F32\", true)\n\t\ttestExists(t, acc, \"F64\", true)\n\t\ttestExists(t, acc, \"B\", true)\n\t}\n\n\t// test non-existence\n\tfor _, acc := range accs {\n\t\ttestExists(t, acc, \"X\", false)\n\t}\n}\n"
  },
  {
    "path": "base/database/boilerplate_test.go",
    "content": "package database\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\ntype Example struct {\n\trecord.Base\n\tsync.Mutex\n\n\tName  string\n\tScore int\n}\n\nvar exampleDB = NewInterface(&Options{\n\tInternal: true,\n\tLocal:    true,\n})\n\n// GetExample gets an Example from the database.\nfunc GetExample(key string) (*Example, error) {\n\tr, err := exampleDB.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewExample := &Example{}\n\t\terr = record.Unwrap(r, newExample)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newExample, nil\n\t}\n\n\t// or adjust type\n\tnewExample, ok := r.(*Example)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *Example, but %T\", r)\n\t}\n\treturn newExample, nil\n}\n\nfunc (e *Example) Save() error {\n\treturn exampleDB.Put(e)\n}\n\nfunc (e *Example) SaveAs(key string) error {\n\te.SetKey(key)\n\treturn exampleDB.PutNew(e)\n}\n\nfunc NewExample(key, name string, score int) *Example {\n\tnewExample := &Example{\n\t\tName:  name,\n\t\tScore: score,\n\t}\n\tnewExample.SetKey(key)\n\treturn newExample\n}\n"
  },
  {
    "path": "base/database/controller.go",
    "content": "package database\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\n// A Controller takes care of all the extra database logic.\ntype Controller struct {\n\tdatabase     *Database\n\tstorage      storage.Interface\n\tshadowDelete bool\n\n\thooksLock sync.RWMutex\n\thooks     []*RegisteredHook\n\n\tsubscriptionLock sync.RWMutex\n\tsubscriptions    []*Subscription\n}\n\n// newController creates a new controller for a storage.\nfunc newController(database *Database, storageInt storage.Interface, shadowDelete bool) *Controller {\n\treturn &Controller{\n\t\tdatabase:     database,\n\t\tstorage:      storageInt,\n\t\tshadowDelete: shadowDelete,\n\t}\n}\n\n// ReadOnly returns whether the storage is read only.\nfunc (c *Controller) ReadOnly() bool {\n\treturn c.storage.ReadOnly()\n}\n\n// Injected returns whether the storage is injected.\nfunc (c *Controller) Injected() bool {\n\treturn c.storage.Injected()\n}\n\n// Get returns the record with the given key.\nfunc (c *Controller) Get(key string) (record.Record, error) {\n\tif shuttingDown.IsSet() {\n\t\treturn nil, ErrShuttingDown\n\t}\n\n\tif err := c.runPreGetHooks(key); err != nil {\n\t\treturn nil, err\n\t}\n\n\tr, err := c.storage.Get(key)\n\tif err != nil {\n\t\t// replace not found error\n\t\tif errors.Is(err, storage.ErrNotFound) {\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tr, err = c.runPostGetHooks(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !r.Meta().CheckValidity() {\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn r, nil\n}\n\n// GetMeta returns the metadata of the record with the given key.\nfunc (c *Controller) GetMeta(key string) (*record.Meta, error) {\n\tif shuttingDown.IsSet() {\n\t\treturn nil, ErrShuttingDown\n\t}\n\n\tvar m *record.Meta\n\tvar err error\n\tif metaDB, ok := c.storage.(storage.MetaHandler); ok {\n\t\tm, err = metaDB.GetMeta(key)\n\t\tif err != nil {\n\t\t\t// replace not found error\n\t\t\tif errors.Is(err, storage.ErrNotFound) {\n\t\t\t\treturn nil, ErrNotFound\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tr, err := c.storage.Get(key)\n\t\tif err != nil {\n\t\t\t// replace not found error\n\t\t\tif errors.Is(err, storage.ErrNotFound) {\n\t\t\t\treturn nil, ErrNotFound\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\tm = r.Meta()\n\t}\n\n\tif !m.CheckValidity() {\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn m, nil\n}\n\n// Put saves a record in the database, executes any registered\n// pre-put hooks and finally send an update to all subscribers.\n// The record must be locked and secured from concurrent access\n// when calling Put().\nfunc (c *Controller) Put(r record.Record) (err error) {\n\tif shuttingDown.IsSet() {\n\t\treturn ErrShuttingDown\n\t}\n\n\tif c.ReadOnly() {\n\t\treturn ErrReadOnly\n\t}\n\n\tr, err = c.runPrePutHooks(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !c.shadowDelete && r.Meta().IsDeleted() {\n\t\t// Immediate delete.\n\t\terr = c.storage.Delete(r.DatabaseKey())\n\t} else {\n\t\t// Put or shadow delete.\n\t\tr, err = c.storage.Put(r)\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif r == nil {\n\t\treturn errors.New(\"storage returned nil record after successful put operation\")\n\t}\n\n\tc.notifySubscribers(r)\n\n\treturn nil\n}\n\n// PutMany stores many records in the database. It does not\n// process any hooks or update subscriptions. Use with care!\nfunc (c *Controller) PutMany() (chan<- record.Record, <-chan error) {\n\tif shuttingDown.IsSet() {\n\t\terrs := make(chan error, 1)\n\t\terrs <- ErrShuttingDown\n\t\treturn make(chan record.Record), errs\n\t}\n\n\tif c.ReadOnly() {\n\t\terrs := make(chan error, 1)\n\t\terrs <- ErrReadOnly\n\t\treturn make(chan record.Record), errs\n\t}\n\n\tif batcher, ok := c.storage.(storage.Batcher); ok {\n\t\treturn batcher.PutMany(c.shadowDelete)\n\t}\n\n\terrs := make(chan error, 1)\n\terrs <- ErrNotImplemented\n\treturn make(chan record.Record), errs\n}\n\n// Query executes the given query on the database.\nfunc (c *Controller) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\tif shuttingDown.IsSet() {\n\t\treturn nil, ErrShuttingDown\n\t}\n\n\tit, err := c.storage.Query(q, local, internal)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn it, nil\n}\n\n// PushUpdate pushes a record update to subscribers.\n// The caller must hold the record's lock when calling\n// PushUpdate.\nfunc (c *Controller) PushUpdate(r record.Record) {\n\tif c != nil {\n\t\tif shuttingDown.IsSet() {\n\t\t\treturn\n\t\t}\n\n\t\tc.notifySubscribers(r)\n\t}\n}\n\nfunc (c *Controller) addSubscription(sub *Subscription) {\n\tif shuttingDown.IsSet() {\n\t\treturn\n\t}\n\n\tc.subscriptionLock.Lock()\n\tdefer c.subscriptionLock.Unlock()\n\n\tc.subscriptions = append(c.subscriptions, sub)\n}\n\n// Maintain runs the Maintain method on the storage.\nfunc (c *Controller) Maintain(ctx context.Context) error {\n\tif shuttingDown.IsSet() {\n\t\treturn ErrShuttingDown\n\t}\n\n\tif maintainer, ok := c.storage.(storage.Maintainer); ok {\n\t\treturn maintainer.Maintain(ctx)\n\t}\n\treturn nil\n}\n\n// MaintainThorough runs the MaintainThorough method on the\n// storage.\nfunc (c *Controller) MaintainThorough(ctx context.Context) error {\n\tif shuttingDown.IsSet() {\n\t\treturn ErrShuttingDown\n\t}\n\n\tif maintainer, ok := c.storage.(storage.Maintainer); ok {\n\t\treturn maintainer.MaintainThorough(ctx)\n\t}\n\treturn nil\n}\n\n// MaintainRecordStates runs the record state lifecycle\n// maintenance on the storage.\nfunc (c *Controller) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time) error {\n\tif shuttingDown.IsSet() {\n\t\treturn ErrShuttingDown\n\t}\n\n\treturn c.storage.MaintainRecordStates(ctx, purgeDeletedBefore, c.shadowDelete)\n}\n\n// Purge deletes all records that match the given query.\n// It returns the number of successful deletes and an error.\nfunc (c *Controller) Purge(ctx context.Context, q *query.Query, local, internal bool) (int, error) {\n\tif shuttingDown.IsSet() {\n\t\treturn 0, ErrShuttingDown\n\t}\n\n\tif purger, ok := c.storage.(storage.Purger); ok {\n\t\treturn purger.Purge(ctx, q, local, internal, c.shadowDelete)\n\t}\n\n\treturn 0, ErrNotImplemented\n}\n\n// PurgeOlderThan deletes all records last updated before the given time.\n// It returns the number of successful deletes and an error.\nfunc (c *Controller) PurgeOlderThan(ctx context.Context, prefix string, purgeBefore time.Time, local, internal bool) (int, error) {\n\tif shuttingDown.IsSet() {\n\t\treturn 0, ErrShuttingDown\n\t}\n\n\tif purger, ok := c.storage.(storage.PurgeOlderThan); ok {\n\t\treturn purger.PurgeOlderThan(ctx, prefix, purgeBefore, local, internal, c.shadowDelete)\n\t}\n\n\treturn 0, ErrNotImplemented\n}\n\n// Shutdown shuts down the storage.\nfunc (c *Controller) Shutdown() error {\n\treturn c.storage.Shutdown()\n}\n\n// notifySubscribers notifies all subscribers that are interested\n// in r. r must be locked when calling notifySubscribers.\n// Any subscriber that is not blocking on it's feed channel will\n// be skipped.\nfunc (c *Controller) notifySubscribers(r record.Record) {\n\tc.subscriptionLock.RLock()\n\tdefer c.subscriptionLock.RUnlock()\n\n\tfor _, sub := range c.subscriptions {\n\t\tif r.Meta().CheckPermission(sub.local, sub.internal) && sub.q.Matches(r) {\n\t\t\tselect {\n\t\t\tcase sub.Feed <- r:\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (c *Controller) runPreGetHooks(key string) error {\n\tc.hooksLock.RLock()\n\tdefer c.hooksLock.RUnlock()\n\n\tfor _, hook := range c.hooks {\n\t\tif !hook.h.UsesPreGet() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !hook.q.MatchesKey(key) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := hook.h.PreGet(key); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *Controller) runPostGetHooks(r record.Record) (record.Record, error) {\n\tc.hooksLock.RLock()\n\tdefer c.hooksLock.RUnlock()\n\n\tvar err error\n\tfor _, hook := range c.hooks {\n\t\tif !hook.h.UsesPostGet() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !hook.q.Matches(r) {\n\t\t\tcontinue\n\t\t}\n\n\t\tr, err = hook.h.PostGet(r)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn r, nil\n}\n\nfunc (c *Controller) runPrePutHooks(r record.Record) (record.Record, error) {\n\tc.hooksLock.RLock()\n\tdefer c.hooksLock.RUnlock()\n\n\tvar err error\n\tfor _, hook := range c.hooks {\n\t\tif !hook.h.UsesPrePut() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !hook.q.Matches(r) {\n\t\t\tcontinue\n\t\t}\n\n\t\tr, err = hook.h.PrePut(r)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn r, nil\n}\n"
  },
  {
    "path": "base/database/controllers.go",
    "content": "package database\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\n// StorageTypeInjected is the type of injected databases.\nconst StorageTypeInjected = \"injected\"\n\nvar (\n\tcontrollers     = make(map[string]*Controller)\n\tcontrollersLock sync.RWMutex\n)\n\nfunc getController(name string) (*Controller, error) {\n\tif !initialized.IsSet() {\n\t\treturn nil, errors.New(\"database not initialized\")\n\t}\n\n\t// return database if already started\n\tcontrollersLock.RLock()\n\tcontroller, ok := controllers[name]\n\tcontrollersLock.RUnlock()\n\tif ok {\n\t\treturn controller, nil\n\t}\n\n\tcontrollersLock.Lock()\n\tdefer controllersLock.Unlock()\n\n\tif shuttingDown.IsSet() {\n\t\treturn nil, ErrShuttingDown\n\t}\n\n\t// get db registration\n\tregisteredDB, err := getDatabase(name)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not start database %s: %w\", name, err)\n\t}\n\n\t// Check if database is injected.\n\tif registeredDB.StorageType == StorageTypeInjected {\n\t\treturn nil, fmt.Errorf(\"database storage is not injected\")\n\t}\n\n\t// get location\n\tdbLocation, err := getLocation(name, registeredDB.StorageType)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not start database %s (type %s): %w\", name, registeredDB.StorageType, err)\n\t}\n\n\t// start database\n\tstorageInt, err := storage.StartDatabase(name, registeredDB.StorageType, dbLocation)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not start database %s (type %s): %w\", name, registeredDB.StorageType, err)\n\t}\n\n\tcontroller = newController(registeredDB, storageInt, registeredDB.ShadowDelete)\n\tcontrollers[name] = controller\n\treturn controller, nil\n}\n\n// InjectDatabase injects an already running database into the system.\nfunc InjectDatabase(name string, storageInt storage.Interface) (*Controller, error) {\n\tcontrollersLock.Lock()\n\tdefer controllersLock.Unlock()\n\n\tif shuttingDown.IsSet() {\n\t\treturn nil, ErrShuttingDown\n\t}\n\n\t_, ok := controllers[name]\n\tif ok {\n\t\treturn nil, fmt.Errorf(`database \"%s\" already loaded`, name)\n\t}\n\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\t// check if database is registered\n\tregisteredDB, ok := registry[name]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"database %q not registered\", name)\n\t}\n\tif registeredDB.StorageType != StorageTypeInjected {\n\t\treturn nil, fmt.Errorf(\"database not of type %q\", StorageTypeInjected)\n\t}\n\n\tcontroller := newController(registeredDB, storageInt, false)\n\tcontrollers[name] = controller\n\treturn controller, nil\n}\n\n// Withdraw withdraws an injected database, but leaves the database registered.\nfunc (c *Controller) Withdraw() {\n\tif c != nil && c.Injected() {\n\t\tcontrollersLock.Lock()\n\t\tdefer controllersLock.Unlock()\n\n\t\tdelete(controllers, c.database.Name)\n\t}\n}\n"
  },
  {
    "path": "base/database/database.go",
    "content": "package database\n\nimport (\n\t\"time\"\n)\n\n// Database holds information about a registered database.\ntype Database struct {\n\tName         string\n\tDescription  string\n\tStorageType  string\n\tShadowDelete bool // Whether deleted records should be kept until purged.\n\tRegistered   time.Time\n\tLastUpdated  time.Time\n\tLastLoaded   time.Time\n}\n\n// Loaded updates the LastLoaded timestamp.\nfunc (db *Database) Loaded() {\n\tdb.LastLoaded = time.Now().Round(time.Second)\n}\n\n// Updated updates the LastUpdated timestamp.\nfunc (db *Database) Updated() {\n\tdb.LastUpdated = time.Now().Round(time.Second)\n}\n"
  },
  {
    "path": "base/database/database_test.go",
    "content": "package database\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"reflect\"\n\t\"runtime/pprof\"\n\t\"testing\"\n\t\"time\"\n\n\tq \"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t_ \"github.com/safing/portmaster/base/database/storage/badger\"\n\t_ \"github.com/safing/portmaster/base/database/storage/bbolt\"\n\t_ \"github.com/safing/portmaster/base/database/storage/fstree\"\n\t_ \"github.com/safing/portmaster/base/database/storage/hashmap\"\n\t_ \"github.com/safing/portmaster/base/database/storage/sqlite\"\n)\n\nfunc TestMain(m *testing.M) {\n\ttestDir, err := os.MkdirTemp(\"\", \"portbase-database-testing-\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = Initialize(testDir)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\texitCode := m.Run()\n\n\t// Clean up the test directory.\n\t// Do not defer, as we end this function with a os.Exit call.\n\t_ = os.RemoveAll(testDir)\n\n\tos.Exit(exitCode)\n}\n\nfunc makeKey(dbName, key string) string {\n\treturn fmt.Sprintf(\"%s:%s\", dbName, key)\n}\n\nfunc testDatabase(t *testing.T, storageType string, shadowDelete bool) { //nolint:maintidx,thelper\n\tt.Run(fmt.Sprintf(\"TestStorage_%s_%v\", storageType, shadowDelete), func(t *testing.T) {\n\t\tdbName := fmt.Sprintf(\"testing-%s-%v\", storageType, shadowDelete)\n\t\tfmt.Println(dbName)\n\t\t_, err := Register(&Database{\n\t\t\tName:         dbName,\n\t\t\tDescription:  fmt.Sprintf(\"Unit Test Database for %s\", storageType),\n\t\t\tStorageType:  storageType,\n\t\t\tShadowDelete: shadowDelete,\n\t\t})\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tdbController, err := getController(dbName)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\t// hook\n\t\thook, err := RegisterHook(q.New(dbName).MustBeValid(), &HookBase{})\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\t// interface\n\t\tdb := NewInterface(&Options{\n\t\t\tLocal:    true,\n\t\t\tInternal: true,\n\t\t})\n\n\t\t// sub\n\t\tsub, err := db.Subscribe(q.New(dbName).MustBeValid())\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tA := NewExample(dbName+\":A\", \"Herbert\", 411)\n\t\terr = A.Save()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tB := NewExample(makeKey(dbName, \"B\"), \"Fritz\", 347)\n\t\terr = B.Save()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tC := NewExample(makeKey(dbName, \"C\"), \"Norbert\", 217)\n\t\terr = C.Save()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\texists, err := db.Exists(makeKey(dbName, \"A\"))\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif !exists {\n\t\t\tt.Fatalf(\"record %s should exist!\", makeKey(dbName, \"A\"))\n\t\t}\n\n\t\tA1, err := GetExample(makeKey(dbName, \"A\"))\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif !reflect.DeepEqual(A, A1) {\n\t\t\tlog.Fatalf(\"A and A1 mismatch, A1: %v\", A1)\n\t\t}\n\n\t\tcnt := countRecords(t, db, q.New(dbName).Where(\n\t\t\tq.And(\n\t\t\t\tq.Where(\"Name\", q.EndsWith, \"bert\"),\n\t\t\t\tq.Where(\"Score\", q.GreaterThan, 100),\n\t\t\t),\n\t\t))\n\t\tif cnt != 2 {\n\t\t\tt.Fatalf(\"expected two records, got %d\", cnt)\n\t\t}\n\n\t\t// test putmany\n\t\tif _, ok := dbController.storage.(storage.Batcher); ok {\n\t\t\tbatchPut := db.PutMany(dbName)\n\t\t\trecords := []record.Record{A, B, C, nil} // nil is to signify finish\n\t\t\tfor _, r := range records {\n\t\t\t\terr = batchPut(r)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatal(err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// test maintenance\n\t\tif _, ok := dbController.storage.(storage.Maintainer); ok {\n\t\t\tnow := time.Now().UTC()\n\t\t\tnowUnix := now.Unix()\n\n\t\t\t// we start with 3 records without expiry\n\t\t\tcnt := countRecords(t, db, q.New(dbName))\n\t\t\tif cnt != 3 {\n\t\t\t\tt.Fatalf(\"expected three records, got %d\", cnt)\n\t\t\t}\n\t\t\t// delete entry\n\t\t\tA.Meta().Deleted = nowUnix - 61\n\t\t\terr = A.Save()\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\t// expire entry\n\t\t\tB.Meta().Expires = nowUnix - 1\n\t\t\terr = B.Save()\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\t// one left\n\t\t\tcnt = countRecords(t, db, q.New(dbName))\n\t\t\tif cnt != 1 {\n\t\t\t\tt.Fatalf(\"expected one record, got %d\", cnt)\n\t\t\t}\n\n\t\t\t// run maintenance\n\t\t\terr = dbController.MaintainRecordStates(t.Context(), now.Add(-60*time.Second))\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\t// one left\n\t\t\tcnt = countRecords(t, db, q.New(dbName))\n\t\t\tif cnt != 1 {\n\t\t\t\tt.Fatalf(\"expected one record, got %d\", cnt)\n\t\t\t}\n\n\t\t\t// check status individually\n\t\t\t_, err = dbController.storage.Get(\"A\")\n\t\t\tif !errors.Is(err, storage.ErrNotFound) {\n\t\t\t\tt.Errorf(\"A should be deleted and purged, err=%s\", err)\n\t\t\t}\n\n\t\t\tif !shadowDelete {\n\t\t\t\t// previous call MaintainRecordStates() must purge all expired and deleted records\n\t\t\t\t_, err := dbController.storage.Get(\"B\")\n\t\t\t\tif !errors.Is(err, storage.ErrNotFound) {\n\t\t\t\t\tt.Errorf(\"B should be deleted and purged, err=%s\", err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tB1, err := dbController.storage.Get(\"B\")\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"should exist: %s, original meta: %+v\", err, B.Meta())\n\t\t\t\t}\n\n\t\t\t\tif B1.Meta().Deleted == 0 {\n\t\t\t\t\tt.Errorf(\"B should be deleted\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// delete last entry\n\t\t\tC.Meta().Deleted = nowUnix - 1\n\t\t\terr = C.Save()\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\t// run maintenance\n\t\t\t// Since previous call MaintainRecordStates() saved actual timestamp for deleted records,\n\t\t\t// use 'now + 1sec' just to guarantee that time is bigger)\n\t\t\terr = dbController.MaintainRecordStates(t.Context(), time.Now().Add(time.Second).UTC())\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\t// check status individually\n\t\t\tB2, err := dbController.storage.Get(\"B\")\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"B should be deleted and purged, meta: %+v\", B2.Meta())\n\t\t\t} else if !errors.Is(err, storage.ErrNotFound) {\n\t\t\t\tt.Errorf(\"B should be deleted and purged, err=%s\", err)\n\t\t\t}\n\t\t\tC2, err := dbController.storage.Get(\"C\")\n\t\t\tif err == nil {\n\t\t\t\tt.Errorf(\"C should be deleted and purged, meta: %+v\", C2.Meta())\n\t\t\t} else if !errors.Is(err, storage.ErrNotFound) {\n\t\t\t\tt.Errorf(\"C should be deleted and purged, err=%s\", err)\n\t\t\t}\n\n\t\t\t// none left\n\t\t\tcnt = countRecords(t, db, q.New(dbName))\n\t\t\tif cnt != 0 {\n\t\t\t\tt.Fatalf(\"expected no records, got %d\", cnt)\n\t\t\t}\n\t\t}\n\n\t\terr = hook.Cancel()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\terr = sub.Cancel()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t})\n}\n\nfunc TestDatabaseSystem(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\t// panic after 10 seconds, to check for locks\n\tfinished := make(chan struct{})\n\tdefer close(finished)\n\tgo func() {\n\t\tselect {\n\t\tcase <-finished:\n\t\tcase <-time.After(10 * time.Second):\n\t\t\tfmt.Println(\"===== TAKING TOO LONG - PRINTING STACK TRACES =====\")\n\t\t\t_ = pprof.Lookup(\"goroutine\").WriteTo(os.Stdout, 1)\n\t\t\tos.Exit(1)\n\t\t}\n\t}()\n\n\tfor _, shadowDelete := range []bool{false, true} {\n\t\ttestDatabase(t, \"sqlite\", shadowDelete)\n\t\ttestDatabase(t, \"bbolt\", shadowDelete)\n\t\ttestDatabase(t, \"hashmap\", shadowDelete)\n\t\ttestDatabase(t, \"fstree\", shadowDelete)\n\t\t// testDatabase(t, \"badger\", shadowDelete)\n\t\t// TODO: Fix badger tests\n\t}\n\n\terr := MaintainRecordStates(context.TODO())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = Maintain(context.TODO())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = MaintainThorough(context.TODO())\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = Shutdown()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc countRecords(t *testing.T, db *Interface, query *q.Query) int {\n\tt.Helper()\n\n\t_, err := query.Check()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tit, err := db.Query(query)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tcnt := 0\n\tfor range it.Next {\n\t\tcnt++\n\t}\n\tif it.Err() != nil {\n\t\tt.Fatal(it.Err())\n\t}\n\treturn cnt\n}\n"
  },
  {
    "path": "base/database/dbmodule/db.go",
    "content": "package dbmodule\n\nimport (\n\t\"errors\"\n\t\"path/filepath\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\ntype DBModule struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc (dbm *DBModule) Manager() *mgr.Manager {\n\treturn dbm.mgr\n}\n\nfunc (dbm *DBModule) Start() error {\n\treturn start()\n}\n\nfunc (dbm *DBModule) Stop() error {\n\treturn stop()\n}\n\nvar databasesRootDir string\n\n// SetDatabaseLocation sets the location of the database for initialization. Supply either a path or dir structure.\nfunc SetDatabaseLocation(dir string) {\n\tif databasesRootDir == \"\" {\n\t\tdatabasesRootDir = dir\n\t}\n}\n\nfunc prep() error {\n\tSetDatabaseLocation(filepath.Join(module.instance.DataDir(), \"databases\"))\n\tif databasesRootDir == \"\" {\n\t\treturn errors.New(\"database location not specified\")\n\t}\n\n\treturn nil\n}\n\nfunc start() error {\n\tstartMaintenanceTasks()\n\treturn nil\n}\n\nfunc stop() error {\n\treturn database.Shutdown()\n}\n\nvar (\n\tmodule     *DBModule\n\tshimLoaded atomic.Bool\n)\n\nfunc New(instance instance) (*DBModule, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"DBModule\")\n\tmodule = &DBModule{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\terr := database.Initialize(databasesRootDir)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tDataDir() string\n}\n"
  },
  {
    "path": "base/database/dbmodule/maintenance.go",
    "content": "package dbmodule\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc startMaintenanceTasks() {\n\t_ = module.mgr.Repeat(\"basic maintenance\", 10*time.Minute, maintainBasic)\n\t_ = module.mgr.Repeat(\"thorough maintenance\", 1*time.Hour, maintainThorough)\n\t_ = module.mgr.Repeat(\"record maintenance\", 1*time.Hour, maintainRecords)\n}\n\nfunc maintainBasic(ctx *mgr.WorkerCtx) error {\n\tlog.Infof(\"database: running Maintain\")\n\treturn database.Maintain(ctx.Ctx())\n}\n\nfunc maintainThorough(ctx *mgr.WorkerCtx) error {\n\tlog.Infof(\"database: running MaintainThorough\")\n\treturn database.MaintainThorough(ctx.Ctx())\n}\n\nfunc maintainRecords(ctx *mgr.WorkerCtx) error {\n\tlog.Infof(\"database: running MaintainRecordStates\")\n\treturn database.MaintainRecordStates(ctx.Ctx())\n}\n"
  },
  {
    "path": "base/database/doc.go",
    "content": "/*\nPackage database provides a universal interface for interacting with the database.\n\n# A Lazy Database\n\nThe database system can handle Go structs as well as serialized data by the dsd package.\nWhile data is in transit within the system, it does not know which form it currently has. Only when it reaches its destination, it must ensure that it is either of a certain type or dump it.\n\n# Record Interface\n\nThe database system uses the Record interface to transparently handle all types of structs that get saved in the database. Structs include the Base struct to fulfill most parts of the Record interface.\n\nBoilerplate Code:\n\n\ttype Example struct {\n\t  record.Base\n\t  sync.Mutex\n\n\t  Name  string\n\t  Score int\n\t}\n\n\tvar (\n\t  db = database.NewInterface(nil)\n\t)\n\n\t// GetExample gets an Example from the database.\n\tfunc GetExample(key string) (*Example, error) {\n\t  r, err := db.Get(key)\n\t  if err != nil {\n\t    return nil, err\n\t  }\n\n\t  // unwrap\n\t  if r.IsWrapped() {\n\t    // only allocate a new struct, if we need it\n\t    new := &Example{}\n\t    err = record.Unwrap(r, new)\n\t    if err != nil {\n\t      return nil, err\n\t    }\n\t    return new, nil\n\t  }\n\n\t  // or adjust type\n\t  new, ok := r.(*Example)\n\t  if !ok {\n\t    return nil, fmt.Errorf(\"record not of type *Example, but %T\", r)\n\t  }\n\t  return new, nil\n\t}\n\n\tfunc (e *Example) Save() error {\n\t  return db.Put(e)\n\t}\n\n\tfunc (e *Example) SaveAs(key string) error {\n\t  e.SetKey(key)\n\t  return db.PutNew(e)\n\t}\n*/\npackage database\n"
  },
  {
    "path": "base/database/errors.go",
    "content": "package database\n\nimport (\n\t\"errors\"\n)\n\n// Errors.\nvar (\n\tErrNotFound         = errors.New(\"database entry not found\")\n\tErrPermissionDenied = errors.New(\"access to database record denied\")\n\tErrReadOnly         = errors.New(\"database is read only\")\n\tErrShuttingDown     = errors.New(\"database system is shutting down\")\n\tErrNotImplemented   = errors.New(\"not implemented by this storage\")\n)\n"
  },
  {
    "path": "base/database/hook.go",
    "content": "package database\n\nimport (\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// Hook can be registered for a database query and\n// will be executed at certain points during the life\n// cycle of a database record.\ntype Hook interface {\n\t// UsesPreGet should return true if the hook's PreGet\n\t// should be called prior to loading a database record\n\t// from the underlying storage.\n\tUsesPreGet() bool\n\t// PreGet is called before a database record is loaded from\n\t// the underlying storage. A PreGet hookd may be used to\n\t// implement more advanced access control on database keys.\n\tPreGet(dbKey string) error\n\t// UsesPostGet should return true if the hook's PostGet\n\t// should be called after loading a database record from\n\t// the underlying storage.\n\tUsesPostGet() bool\n\t// PostGet is called after a record has been loaded form the\n\t// underlying storage and may perform additional mutation\n\t// or access check based on the records data.\n\t// The passed record is already locked by the database system\n\t// so users can safely access all data of r.\n\tPostGet(r record.Record) (record.Record, error)\n\t// UsesPrePut should return true if the hook's PrePut method\n\t// should be called prior to saving a record in the database.\n\tUsesPrePut() bool\n\t// PrePut is called prior to saving (creating or updating) a\n\t// record in the database storage. It may be used to perform\n\t// extended validation or mutations on the record.\n\t// The passed record is already locked by the database system\n\t// so users can safely access all data of r.\n\tPrePut(r record.Record) (record.Record, error)\n}\n\n// RegisteredHook is a registered database hook.\ntype RegisteredHook struct {\n\tq *query.Query\n\th Hook\n}\n\n// RegisterHook registers a hook for records matching the given\n// query in the database.\nfunc RegisterHook(q *query.Query, hook Hook) (*RegisteredHook, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc, err := getController(q.DatabaseName())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trh := &RegisteredHook{\n\t\tq: q,\n\t\th: hook,\n\t}\n\n\tc.hooksLock.Lock()\n\tdefer c.hooksLock.Unlock()\n\tc.hooks = append(c.hooks, rh)\n\n\treturn rh, nil\n}\n\n// Cancel unregisteres the hook from the database. Once\n// Cancel returned the hook's methods will not be called\n// anymore for updates that matched the registered query.\nfunc (h *RegisteredHook) Cancel() error {\n\tc, err := getController(h.q.DatabaseName())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc.hooksLock.Lock()\n\tdefer c.hooksLock.Unlock()\n\n\tfor key, hook := range c.hooks {\n\t\tif hook.q == h.q {\n\t\t\tc.hooks = append(c.hooks[:key], c.hooks[key+1:]...)\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "base/database/hookbase.go",
    "content": "package database\n\nimport (\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// HookBase implements the Hook interface and provides dummy functions to reduce boilerplate.\ntype HookBase struct{}\n\n// UsesPreGet implements the Hook interface and returns false.\nfunc (b *HookBase) UsesPreGet() bool {\n\treturn false\n}\n\n// UsesPostGet implements the Hook interface and returns false.\nfunc (b *HookBase) UsesPostGet() bool {\n\treturn false\n}\n\n// UsesPrePut implements the Hook interface and returns false.\nfunc (b *HookBase) UsesPrePut() bool {\n\treturn false\n}\n\n// PreGet implements the Hook interface.\nfunc (b *HookBase) PreGet(dbKey string) error {\n\treturn nil\n}\n\n// PostGet implements the Hook interface.\nfunc (b *HookBase) PostGet(r record.Record) (record.Record, error) {\n\treturn r, nil\n}\n\n// PrePut implements the Hook interface.\nfunc (b *HookBase) PrePut(r record.Record) (record.Record, error) {\n\treturn r, nil\n}\n"
  },
  {
    "path": "base/database/interface.go",
    "content": "package database\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/bluele/gcache\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nconst (\n\tgetDBFromKey = \"\"\n)\n\n// Interface provides a method to access the database with attached options.\ntype Interface struct {\n\toptions *Options\n\tcache   gcache.Cache\n\n\twriteCache        map[string]record.Record\n\twriteCacheLock    sync.Mutex\n\ttriggerCacheWrite chan struct{}\n}\n\n// Options holds options that may be set for an Interface instance.\ntype Options struct {\n\t// Local specifies if the interface is used by an actor on the local device.\n\t// Setting both the Local and Internal flags will bring performance\n\t// improvements because less checks are needed.\n\tLocal bool\n\n\t// Internal specifies if the interface is used by an actor within the\n\t// software. Setting both the Local and Internal flags will bring performance\n\t// improvements because less checks are needed.\n\tInternal bool\n\n\t// AlwaysMakeSecret will have the interface mark all saved records as secret.\n\t// This means that they will be only accessible by an internal interface.\n\tAlwaysMakeSecret bool\n\n\t// AlwaysMakeCrownjewel will have the interface mark all saved records as\n\t// crown jewels. This means that they will be only accessible by a local\n\t// interface.\n\tAlwaysMakeCrownjewel bool\n\n\t// AlwaysSetRelativateExpiry will have the interface set a relative expiry,\n\t// based on the current time, on all saved records.\n\tAlwaysSetRelativateExpiry int64\n\n\t// AlwaysSetAbsoluteExpiry will have the interface set an absolute expiry on\n\t// all saved records.\n\tAlwaysSetAbsoluteExpiry int64\n\n\t// CacheSize defines that a cache should be used for this interface and\n\t// defines it's size.\n\t// Caching comes with an important caveat: If database records are changed\n\t// from another interface, the cache will not be invalidated for these\n\t// records. It will therefore serve outdated data until that record is\n\t// evicted from the cache.\n\tCacheSize int\n\n\t// DelayCachedWrites defines a database name for which cache writes should\n\t// be cached and batched. The database backend must support the Batcher\n\t// interface. This option is only valid if used with a cache.\n\t// Additionally, this may only be used for internal and local interfaces.\n\t// Please note that this means that other interfaces will not be able to\n\t// guarantee to serve the latest record if records are written this way.\n\tDelayCachedWrites string\n}\n\n// Apply applies options to the record metadata.\nfunc (o *Options) Apply(r record.Record) {\n\tr.UpdateMeta()\n\tif o.AlwaysMakeSecret {\n\t\tr.Meta().MakeSecret()\n\t}\n\tif o.AlwaysMakeCrownjewel {\n\t\tr.Meta().MakeCrownJewel()\n\t}\n\tif o.AlwaysSetAbsoluteExpiry > 0 {\n\t\tr.Meta().SetAbsoluteExpiry(o.AlwaysSetAbsoluteExpiry)\n\t} else if o.AlwaysSetRelativateExpiry > 0 {\n\t\tr.Meta().SetRelativateExpiry(o.AlwaysSetRelativateExpiry)\n\t}\n}\n\n// HasAllPermissions returns whether the options specify the highest possible\n// permissions for operations.\nfunc (o *Options) HasAllPermissions() bool {\n\treturn o.Local && o.Internal\n}\n\n// hasAccessPermission checks if the interface options permit access to the\n// given record, locking the record for accessing it's attributes.\nfunc (o *Options) hasAccessPermission(r record.Record) bool {\n\t// Check if the options specify all permissions, which makes checking the\n\t// record unnecessary.\n\tif o.HasAllPermissions() {\n\t\treturn true\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\t// Check permissions against record.\n\treturn r.Meta().CheckPermission(o.Local, o.Internal)\n}\n\n// NewInterface returns a new Interface to the database.\nfunc NewInterface(opts *Options) *Interface {\n\tif opts == nil {\n\t\topts = &Options{}\n\t}\n\n\tnewIface := &Interface{\n\t\toptions: opts,\n\t}\n\tif opts.CacheSize > 0 {\n\t\tcacheBuilder := gcache.New(opts.CacheSize).ARC()\n\t\tif opts.DelayCachedWrites != \"\" {\n\t\t\tcacheBuilder.EvictedFunc(newIface.cacheEvictHandler)\n\t\t\tnewIface.writeCache = make(map[string]record.Record, opts.CacheSize/2)\n\t\t\tnewIface.triggerCacheWrite = make(chan struct{})\n\t\t}\n\t\tnewIface.cache = cacheBuilder.Build()\n\t}\n\treturn newIface\n}\n\n// Exists return whether a record with the given key exists.\nfunc (i *Interface) Exists(key string) (bool, error) {\n\t_, err := i.Get(key)\n\tif err != nil {\n\t\tswitch {\n\t\tcase errors.Is(err, ErrNotFound):\n\t\t\treturn false, nil\n\t\tcase errors.Is(err, ErrPermissionDenied):\n\t\t\treturn true, nil\n\t\tdefault:\n\t\t\treturn false, err\n\t\t}\n\t}\n\treturn true, nil\n}\n\n// Get return the record with the given key.\nfunc (i *Interface) Get(key string) (record.Record, error) {\n\tr, _, err := i.getRecord(getDBFromKey, key, false)\n\treturn r, err\n}\n\nfunc (i *Interface) getRecord(dbName string, dbKey string, mustBeWriteable bool) (r record.Record, db *Controller, err error) { //nolint:unparam\n\tif dbName == \"\" {\n\t\tdbName, dbKey = record.ParseKey(dbKey)\n\t}\n\n\tdb, err = getController(dbName)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif mustBeWriteable && db.ReadOnly() {\n\t\treturn nil, db, ErrReadOnly\n\t}\n\n\tr = i.checkCache(dbName + \":\" + dbKey)\n\tif r != nil {\n\t\tif !i.options.hasAccessPermission(r) {\n\t\t\treturn nil, db, ErrPermissionDenied\n\t\t}\n\t\treturn r, db, nil\n\t}\n\n\tr, err = db.Get(dbKey)\n\tif err != nil {\n\t\treturn nil, db, err\n\t}\n\n\tif !i.options.hasAccessPermission(r) {\n\t\treturn nil, db, ErrPermissionDenied\n\t}\n\n\tr.Lock()\n\tttl := r.Meta().GetRelativeExpiry()\n\tr.Unlock()\n\ti.updateCache(\n\t\tr,\n\t\tfalse, // writing\n\t\tfalse, // remove\n\t\tttl,   // expiry\n\t)\n\n\treturn r, db, nil\n}\n\nfunc (i *Interface) getMeta(dbName string, dbKey string, mustBeWriteable bool) (m *record.Meta, db *Controller, err error) { //nolint:unparam\n\tif dbName == \"\" {\n\t\tdbName, dbKey = record.ParseKey(dbKey)\n\t}\n\n\tdb, err = getController(dbName)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif mustBeWriteable && db.ReadOnly() {\n\t\treturn nil, db, ErrReadOnly\n\t}\n\n\tr := i.checkCache(dbName + \":\" + dbKey)\n\tif r != nil {\n\t\tif !i.options.hasAccessPermission(r) {\n\t\t\treturn nil, db, ErrPermissionDenied\n\t\t}\n\t\treturn r.Meta(), db, nil\n\t}\n\n\tm, err = db.GetMeta(dbKey)\n\tif err != nil {\n\t\treturn nil, db, err\n\t}\n\n\tif !m.CheckPermission(i.options.Local, i.options.Internal) {\n\t\treturn nil, db, ErrPermissionDenied\n\t}\n\n\treturn m, db, nil\n}\n\n// InsertValue inserts a value into a record.\nfunc (i *Interface) InsertValue(key string, attribute string, value interface{}) error {\n\tr, db, err := i.getRecord(getDBFromKey, key, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tvar acc accessor.Accessor\n\tif r.IsWrapped() {\n\t\twrapper, ok := r.(*record.Wrapper)\n\t\tif !ok {\n\t\t\treturn errors.New(\"record is malformed (reports to be wrapped but is not of type *record.Wrapper)\")\n\t\t}\n\t\tacc = accessor.NewJSONBytesAccessor(&wrapper.Data)\n\t} else {\n\t\tacc = accessor.NewStructAccessor(r)\n\t}\n\n\terr = acc.Set(attribute, value)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to set value with %s: %w\", acc.Type(), err)\n\t}\n\n\ti.options.Apply(r)\n\treturn db.Put(r)\n}\n\n// Put saves a record to the database.\nfunc (i *Interface) Put(r record.Record) (err error) {\n\t// get record or only database\n\tvar db *Controller\n\tif !i.options.HasAllPermissions() {\n\t\t_, db, err = i.getMeta(r.DatabaseName(), r.DatabaseKey(), true)\n\t\tif err != nil && !errors.Is(err, ErrNotFound) {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tdb, err = getController(r.DatabaseName())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Check if database is read only.\n\tif db.ReadOnly() {\n\t\treturn ErrReadOnly\n\t}\n\n\tr.Lock()\n\ti.options.Apply(r)\n\tremove := r.Meta().IsDeleted()\n\tttl := r.Meta().GetRelativeExpiry()\n\tr.Unlock()\n\n\t// The record may not be locked when updating the cache.\n\twritten := i.updateCache(r, true, remove, ttl)\n\tif written {\n\t\treturn nil\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\treturn db.Put(r)\n}\n\n// PutNew saves a record to the database as a new record (ie. with new timestamps).\nfunc (i *Interface) PutNew(r record.Record) (err error) {\n\t// get record or only database\n\tvar db *Controller\n\tif !i.options.HasAllPermissions() {\n\t\t_, db, err = i.getMeta(r.DatabaseName(), r.DatabaseKey(), true)\n\t\tif err != nil && !errors.Is(err, ErrNotFound) {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tdb, err = getController(r.DatabaseName())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Check if database is read only.\n\tif db.ReadOnly() {\n\t\treturn ErrReadOnly\n\t}\n\n\tr.Lock()\n\tif r.Meta() != nil {\n\t\tr.Meta().Reset()\n\t}\n\ti.options.Apply(r)\n\tremove := r.Meta().IsDeleted()\n\tttl := r.Meta().GetRelativeExpiry()\n\tr.Unlock()\n\n\t// The record may not be locked when updating the cache.\n\twritten := i.updateCache(r, true, remove, ttl)\n\tif written {\n\t\treturn nil\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\treturn db.Put(r)\n}\n\n// PutMany stores many records in the database.\n// Warning: This is nearly a direct database access and omits many things:\n// - Record locking\n// - Hooks\n// - Subscriptions\n// - Caching\n// Use with care.\nfunc (i *Interface) PutMany(dbName string) (put func(record.Record) error) {\n\tinterfaceBatch := make(chan record.Record, 100)\n\n\t// permission check\n\tif !i.options.HasAllPermissions() {\n\t\treturn func(r record.Record) error {\n\t\t\treturn ErrPermissionDenied\n\t\t}\n\t}\n\n\t// get database\n\tdb, err := getController(dbName)\n\tif err != nil {\n\t\treturn func(r record.Record) error {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Check if database is read only.\n\tif db.ReadOnly() {\n\t\treturn func(r record.Record) error {\n\t\t\treturn ErrReadOnly\n\t\t}\n\t}\n\n\t// start database access\n\tdbBatch, errs := db.PutMany()\n\tfinished := abool.New()\n\tvar internalErr error\n\n\t// interface options proxy\n\tgo func() {\n\t\tdefer close(dbBatch) // signify that we are finished\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase r := <-interfaceBatch:\n\t\t\t\t// finished?\n\t\t\t\tif r == nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// apply options\n\t\t\t\ti.options.Apply(r)\n\t\t\t\t// pass along\n\t\t\t\tdbBatch <- r\n\t\t\tcase <-time.After(1 * time.Second):\n\t\t\t\t// bail out\n\t\t\t\tinternalErr = errors.New(\"timeout: putmany unused for too long\")\n\t\t\t\tfinished.Set()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn func(r record.Record) error {\n\t\t// finished?\n\t\tif finished.IsSet() {\n\t\t\t// check for internal error\n\t\t\tif internalErr != nil {\n\t\t\t\treturn internalErr\n\t\t\t}\n\t\t\t// check for previous error\n\t\t\tselect {\n\t\t\tcase err := <-errs:\n\t\t\t\treturn err\n\t\t\tdefault:\n\t\t\t\treturn errors.New(\"batch is closed\")\n\t\t\t}\n\t\t}\n\n\t\t// finish?\n\t\tif r == nil {\n\t\t\tfinished.Set()\n\t\t\tinterfaceBatch <- nil // signify that we are finished\n\t\t\t// do not close, as this fn could be called again with nil.\n\t\t\treturn <-errs\n\t\t}\n\n\t\t// check record scope\n\t\tif r.DatabaseName() != dbName {\n\t\t\treturn errors.New(\"record out of database scope\")\n\t\t}\n\n\t\t// submit\n\t\tselect {\n\t\tcase interfaceBatch <- r:\n\t\t\treturn nil\n\t\tcase err := <-errs:\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// SetAbsoluteExpiry sets an absolute record expiry.\nfunc (i *Interface) SetAbsoluteExpiry(key string, time int64) error {\n\tr, db, err := i.getRecord(getDBFromKey, key, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\ti.options.Apply(r)\n\tr.Meta().SetAbsoluteExpiry(time)\n\treturn db.Put(r)\n}\n\n// SetRelativateExpiry sets a relative (self-updating) record expiry.\nfunc (i *Interface) SetRelativateExpiry(key string, duration int64) error {\n\tr, db, err := i.getRecord(getDBFromKey, key, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\ti.options.Apply(r)\n\tr.Meta().SetRelativateExpiry(duration)\n\treturn db.Put(r)\n}\n\n// MakeSecret marks the record as a secret, meaning interfacing processes, such as an UI, are denied access to the record.\nfunc (i *Interface) MakeSecret(key string) error {\n\tr, db, err := i.getRecord(getDBFromKey, key, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\ti.options.Apply(r)\n\tr.Meta().MakeSecret()\n\treturn db.Put(r)\n}\n\n// MakeCrownJewel marks a record as a crown jewel, meaning it will only be accessible locally.\nfunc (i *Interface) MakeCrownJewel(key string) error {\n\tr, db, err := i.getRecord(getDBFromKey, key, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\ti.options.Apply(r)\n\tr.Meta().MakeCrownJewel()\n\treturn db.Put(r)\n}\n\n// Delete deletes a record from the database.\nfunc (i *Interface) Delete(key string) error {\n\tr, db, err := i.getRecord(getDBFromKey, key, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Check if database is read only.\n\tif db.ReadOnly() {\n\t\treturn ErrReadOnly\n\t}\n\n\ti.options.Apply(r)\n\tr.Meta().Delete()\n\treturn db.Put(r)\n}\n\n// Query executes the given query on the database.\n// Will not see data that is in the write cache, waiting to be written.\n// Use with care with caching.\nfunc (i *Interface) Query(q *query.Query) (*iterator.Iterator, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdb, err := getController(q.DatabaseName())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// TODO: Finish caching system integration.\n\t// Flush the cache before we query the database.\n\t// i.FlushCache()\n\n\treturn db.Query(q, i.options.Local, i.options.Internal)\n}\n\n// Purge deletes all records that match the given query. It returns the number\n// of successful deletes and an error.\nfunc (i *Interface) Purge(ctx context.Context, q *query.Query) (int, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tdb, err := getController(q.DatabaseName())\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// Check if database is read only before we add to the cache.\n\tif db.ReadOnly() {\n\t\treturn 0, ErrReadOnly\n\t}\n\n\treturn db.Purge(ctx, q, i.options.Local, i.options.Internal)\n}\n\n// PurgeOlderThan deletes all records last updated before the given time.\n// It returns the number of successful deletes and an error.\nfunc (i *Interface) PurgeOlderThan(ctx context.Context, prefix string, purgeBefore time.Time) (int, error) {\n\tdbName, dbKeyPrefix := record.ParseKey(prefix)\n\tif dbName == \"\" {\n\t\treturn 0, errors.New(\"unknown database\")\n\t}\n\n\tdb, err := getController(dbName)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// Check if database is read only before we add to the cache.\n\tif db.ReadOnly() {\n\t\treturn 0, ErrReadOnly\n\t}\n\n\treturn db.PurgeOlderThan(ctx, dbKeyPrefix, purgeBefore, i.options.Local, i.options.Internal)\n}\n\n// Subscribe subscribes to updates matching the given query.\nfunc (i *Interface) Subscribe(q *query.Query) (*Subscription, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc, err := getController(q.DatabaseName())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsub := &Subscription{\n\t\tq:        q,\n\t\tlocal:    i.options.Local,\n\t\tinternal: i.options.Internal,\n\t\tFeed:     make(chan record.Record, 1000),\n\t}\n\tc.addSubscription(sub)\n\treturn sub, nil\n}\n"
  },
  {
    "path": "base/database/interface_cache.go",
    "content": "package database\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// DelayedCacheWriter must be run by the caller of an interface that uses delayed cache writing.\nfunc (i *Interface) DelayedCacheWriter(wc *mgr.WorkerCtx) error {\n\t// Check if the DelayedCacheWriter should be run at all.\n\tif i.options.CacheSize <= 0 || i.options.DelayCachedWrites == \"\" {\n\t\treturn errors.New(\"delayed cache writer is not applicable to this database interface\")\n\t}\n\n\t// Check if backend support the Batcher interface.\n\tbatchPut := i.PutMany(i.options.DelayCachedWrites)\n\t// End batchPut immediately and check for an error.\n\terr := batchPut(nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// percentThreshold defines the minimum percentage of entries in the write cache in relation to the cache size that need to be present in order for flushing the cache to the database storage.\n\tpercentThreshold := 25\n\tthresholdWriteTicker := time.NewTicker(5 * time.Second)\n\tforceWriteTicker := time.NewTicker(5 * time.Minute)\n\n\tfor {\n\t\t// Wait for trigger for writing the cache.\n\t\tselect {\n\t\tcase <-wc.Done():\n\t\t\t// The caller is shutting down, flush the cache to storage and exit.\n\t\t\ti.flushWriteCache(0)\n\t\t\treturn nil\n\n\t\tcase <-i.triggerCacheWrite:\n\t\t\t// An entry from the cache was evicted that was also in the write cache.\n\t\t\t// This makes it likely that other entries that are also present in the\n\t\t\t// write cache will be evicted soon. Flush the write cache to storage\n\t\t\t// immediately in order to reduce single writes.\n\t\t\ti.flushWriteCache(0)\n\n\t\tcase <-thresholdWriteTicker.C:\n\t\t\t// Often check if the write cache has filled up to a certain degree and\n\t\t\t// flush it to storage before we start evicting to-be-written entries and\n\t\t\t// slow down the hot path again.\n\t\t\ti.flushWriteCache(percentThreshold)\n\n\t\tcase <-forceWriteTicker.C:\n\t\t\t// Once in a while, flush the write cache to storage no matter how much\n\t\t\t// it is filled. We don't want entries lingering around in the write\n\t\t\t// cache forever. This also reduces the amount of data loss in the event\n\t\t\t// of a total crash.\n\t\t\ti.flushWriteCache(0)\n\t\t}\n\t}\n}\n\n// ClearCache clears the read cache.\nfunc (i *Interface) ClearCache() {\n\t// Check if cache is in use.\n\tif i.cache == nil {\n\t\treturn\n\t}\n\n\t// Clear all cache entries.\n\ti.cache.Purge()\n}\n\n// FlushCache writes (and thus clears) the write cache.\nfunc (i *Interface) FlushCache() {\n\t// Check if write cache is in use.\n\tif i.options.DelayCachedWrites != \"\" {\n\t\treturn\n\t}\n\n\ti.flushWriteCache(0)\n}\n\nfunc (i *Interface) flushWriteCache(percentThreshold int) {\n\ti.writeCacheLock.Lock()\n\tdefer i.writeCacheLock.Unlock()\n\n\t// Check if there is anything to do.\n\tif len(i.writeCache) == 0 {\n\t\treturn\n\t}\n\n\t// Check if we reach the given threshold for writing to storage.\n\tif (len(i.writeCache)*100)/i.options.CacheSize < percentThreshold {\n\t\treturn\n\t}\n\n\t// Write the full cache in a batch operation.\n\tbatchPut := i.PutMany(i.options.DelayCachedWrites)\n\tfor _, r := range i.writeCache {\n\t\terr := batchPut(r)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"database: failed to write write-cached entry to %q database: %s\", i.options.DelayCachedWrites, err)\n\t\t}\n\t}\n\t// Finish batch.\n\terr := batchPut(nil)\n\tif err != nil {\n\t\tlog.Warningf(\"database: failed to finish flushing write cache to %q database: %s\", i.options.DelayCachedWrites, err)\n\t}\n\n\t// Optimized map clearing following the Go1.11 recommendation.\n\tfor key := range i.writeCache {\n\t\tdelete(i.writeCache, key)\n\t}\n}\n\n// cacheEvictHandler is run by the cache for every entry that gets evicted\n// from the cache.\nfunc (i *Interface) cacheEvictHandler(keyData, _ interface{}) {\n\t// Transform the key into a string.\n\tkey, ok := keyData.(string)\n\tif !ok {\n\t\treturn\n\t}\n\n\t// Check if the evicted record is one that is to be written.\n\t// Lock the write cache until the end of the function.\n\t// The read cache is locked anyway for the whole duration.\n\ti.writeCacheLock.Lock()\n\tdefer i.writeCacheLock.Unlock()\n\tr, ok := i.writeCache[key]\n\tif ok {\n\t\tdelete(i.writeCache, key)\n\t}\n\tif !ok {\n\t\treturn\n\t}\n\n\t// Write record to database in order to mitigate race conditions where the record would appear\n\t// as non-existent for a short duration.\n\tdb, err := getController(r.DatabaseName())\n\tif err != nil {\n\t\tlog.Warningf(\"database: failed to write evicted cache entry %q: database %q does not exist\", key, r.DatabaseName())\n\t\treturn\n\t}\n\n\tr.Lock()\n\tdefer r.Unlock()\n\n\terr = db.Put(r)\n\tif err != nil {\n\t\tlog.Warningf(\"database: failed to write evicted cache entry %q to database: %s\", key, err)\n\t}\n\n\t// Finally, trigger writing the full write cache because a to-be-written\n\t// entry was just evicted from the cache, and this makes it likely that more\n\t// to-be-written entries will be evicted shortly.\n\tselect {\n\tcase i.triggerCacheWrite <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc (i *Interface) checkCache(key string) record.Record {\n\t// Check if cache is in use.\n\tif i.cache == nil {\n\t\treturn nil\n\t}\n\n\t// Check if record exists in cache.\n\tcacheVal, err := i.cache.Get(key)\n\tif err == nil {\n\t\tr, ok := cacheVal.(record.Record)\n\t\tif ok {\n\t\t\treturn r\n\t\t}\n\t}\n\treturn nil\n}\n\n// updateCache updates an entry in the interface cache. The given record may\n// not be locked, as updating the cache might write an (unrelated) evicted\n// record to the database in the process. If this happens while the\n// DelayedCacheWriter flushes the write cache with the same record present,\n// this will deadlock.\nfunc (i *Interface) updateCache(r record.Record, write bool, remove bool, ttl int64) (written bool) {\n\t// Check if cache is in use.\n\tif i.cache == nil {\n\t\treturn false\n\t}\n\n\t// Check if record should be deleted\n\tif remove {\n\t\t// Remove entry from cache.\n\t\ti.cache.Remove(r.Key())\n\t\t// Let write through to database storage.\n\t\treturn false\n\t}\n\n\t// Update cache with record.\n\tif ttl >= 0 {\n\t\t_ = i.cache.SetWithExpire(\n\t\t\tr.Key(),\n\t\t\tr,\n\t\t\ttime.Duration(ttl)*time.Second,\n\t\t)\n\t} else {\n\t\t_ = i.cache.Set(\n\t\t\tr.Key(),\n\t\t\tr,\n\t\t)\n\t}\n\n\t// Add record to write cache instead if:\n\t// 1. The record is being written.\n\t// 2. Write delaying is active.\n\t// 3. Write delaying is active for the database of this record.\n\tif write && r.DatabaseName() == i.options.DelayCachedWrites {\n\t\ti.writeCacheLock.Lock()\n\t\tdefer i.writeCacheLock.Unlock()\n\t\ti.writeCache[r.Key()] = r\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "base/database/interface_cache_test.go",
    "content": "package database\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc benchmarkCacheWriting(b *testing.B, storageType string, cacheSize int, sampleSize int, delayWrites bool) { //nolint:gocognit,gocyclo,thelper\n\tb.Run(fmt.Sprintf(\"CacheWriting_%s_%d_%d_%v\", storageType, cacheSize, sampleSize, delayWrites), func(b *testing.B) {\n\t\t// Setup Benchmark.\n\n\t\t// Create database.\n\t\tdbName := fmt.Sprintf(\"cache-w-benchmark-%s-%d-%d-%v\", storageType, cacheSize, sampleSize, delayWrites)\n\t\t_, err := Register(&Database{\n\t\t\tName:        dbName,\n\t\t\tDescription: fmt.Sprintf(\"Cache Benchmark Database for %s\", storageType),\n\t\t\tStorageType: storageType,\n\t\t})\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\n\t\t// Create benchmark interface.\n\t\toptions := &Options{\n\t\t\tLocal:     true,\n\t\t\tInternal:  true,\n\t\t\tCacheSize: cacheSize,\n\t\t}\n\t\tif cacheSize > 0 && delayWrites {\n\t\t\toptions.DelayCachedWrites = dbName\n\t\t}\n\t\tdb := NewInterface(options)\n\n\t\t// Start\n\t\tm := mgr.New(\"Cache writing benchmark test\")\n\t\tvar wg sync.WaitGroup\n\t\tif cacheSize > 0 && delayWrites {\n\t\t\twg.Add(1)\n\t\t\tm.Go(\"Cache writing benchmark worker\", func(wc *mgr.WorkerCtx) error {\n\t\t\t\terr := db.DelayedCacheWriter(wc)\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t\twg.Done()\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\n\t\t// Start Benchmark.\n\t\tb.ResetTimer()\n\t\tfor i := range b.N {\n\t\t\ttestRecordID := i % sampleSize\n\t\t\tr := NewExample(\n\t\t\t\tdbName+\":\"+strconv.Itoa(testRecordID),\n\t\t\t\t\"A\",\n\t\t\t\t1,\n\t\t\t)\n\t\t\terr = db.Put(r)\n\t\t\tif err != nil {\n\t\t\t\tb.Fatal(err)\n\t\t\t}\n\t\t}\n\n\t\t// End cache writer and wait\n\t\tm.Cancel()\n\t\twg.Wait()\n\t})\n}\n\nfunc benchmarkCacheReadWrite(b *testing.B, storageType string, cacheSize int, sampleSize int, delayWrites bool) { //nolint:gocognit,gocyclo,thelper\n\tb.Run(fmt.Sprintf(\"CacheReadWrite_%s_%d_%d_%v\", storageType, cacheSize, sampleSize, delayWrites), func(b *testing.B) {\n\t\t// Setup Benchmark.\n\n\t\t// Create database.\n\t\tdbName := fmt.Sprintf(\"cache-rw-benchmark-%s-%d-%d-%v\", storageType, cacheSize, sampleSize, delayWrites)\n\t\t_, err := Register(&Database{\n\t\t\tName:        dbName,\n\t\t\tDescription: fmt.Sprintf(\"Cache Benchmark Database for %s\", storageType),\n\t\t\tStorageType: storageType,\n\t\t})\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\n\t\t// Create benchmark interface.\n\t\toptions := &Options{\n\t\t\tLocal:     true,\n\t\t\tInternal:  true,\n\t\t\tCacheSize: cacheSize,\n\t\t}\n\t\tif cacheSize > 0 && delayWrites {\n\t\t\toptions.DelayCachedWrites = dbName\n\t\t}\n\t\tdb := NewInterface(options)\n\n\t\t// Start\n\t\tm := mgr.New(\"Cache read/write benchmark test\")\n\t\tvar wg sync.WaitGroup\n\t\tif cacheSize > 0 && delayWrites {\n\t\t\twg.Add(1)\n\t\t\tm.Go(\"Cache read/write benchmark worker\", func(wc *mgr.WorkerCtx) error {\n\t\t\t\terr := db.DelayedCacheWriter(wc)\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanic(err)\n\t\t\t\t}\n\t\t\t\twg.Done()\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\n\t\t// Start Benchmark.\n\t\tb.ResetTimer()\n\t\twriting := true\n\t\tfor i := range b.N {\n\t\t\ttestRecordID := i % sampleSize\n\t\t\tkey := dbName + \":\" + strconv.Itoa(testRecordID)\n\n\t\t\tif i > 0 && testRecordID == 0 {\n\t\t\t\twriting = !writing // switch between reading and writing every samplesize\n\t\t\t}\n\n\t\t\tif writing {\n\t\t\t\tr := NewExample(key, \"A\", 1)\n\t\t\t\terr = db.Put(r)\n\t\t\t} else {\n\t\t\t\t_, err = db.Get(key)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tb.Fatal(err)\n\t\t\t}\n\t\t}\n\n\t\t// End cache writer and wait\n\t\tm.Cancel()\n\t\twg.Wait()\n\t})\n}\n\nfunc BenchmarkCache(b *testing.B) {\n\tfor _, storageType := range []string{\"bbolt\", \"hashmap\"} {\n\t\tbenchmarkCacheWriting(b, storageType, 32, 8, false)\n\t\tbenchmarkCacheWriting(b, storageType, 32, 8, true)\n\t\tbenchmarkCacheWriting(b, storageType, 32, 1024, false)\n\t\tbenchmarkCacheWriting(b, storageType, 32, 1024, true)\n\t\tbenchmarkCacheWriting(b, storageType, 512, 1024, false)\n\t\tbenchmarkCacheWriting(b, storageType, 512, 1024, true)\n\n\t\tbenchmarkCacheReadWrite(b, storageType, 32, 8, false)\n\t\tbenchmarkCacheReadWrite(b, storageType, 32, 8, true)\n\t\tbenchmarkCacheReadWrite(b, storageType, 32, 1024, false)\n\t\tbenchmarkCacheReadWrite(b, storageType, 32, 1024, true)\n\t\tbenchmarkCacheReadWrite(b, storageType, 512, 1024, false)\n\t\tbenchmarkCacheReadWrite(b, storageType, 512, 1024, true)\n\t}\n}\n"
  },
  {
    "path": "base/database/iterator/iterator.go",
    "content": "package iterator\n\nimport (\n\t\"sync\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// Iterator defines the iterator structure.\ntype Iterator struct {\n\tNext chan record.Record\n\tDone chan struct{}\n\n\terrLock    sync.Mutex\n\terr        error\n\tdoneClosed *abool.AtomicBool\n}\n\n// New creates a new Iterator.\nfunc New() *Iterator {\n\treturn &Iterator{\n\t\tNext:       make(chan record.Record, 10),\n\t\tDone:       make(chan struct{}),\n\t\tdoneClosed: abool.NewBool(false),\n\t}\n}\n\n// Finish is called be the storage to signal the end of the query results.\nfunc (it *Iterator) Finish(err error) {\n\tclose(it.Next)\n\tif it.doneClosed.SetToIf(false, true) {\n\t\tclose(it.Done)\n\t}\n\n\tit.errLock.Lock()\n\tdefer it.errLock.Unlock()\n\tit.err = err\n}\n\n// Cancel is called by the iteration consumer to cancel the running query.\nfunc (it *Iterator) Cancel() {\n\tif it.doneClosed.SetToIf(false, true) {\n\t\tclose(it.Done)\n\t}\n}\n\n// Err returns the iterator error, if exists.\nfunc (it *Iterator) Err() error {\n\tit.errLock.Lock()\n\tdefer it.errLock.Unlock()\n\treturn it.err\n}\n"
  },
  {
    "path": "base/database/main.go",
    "content": "package database\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/tevino/abool\"\n)\n\nvar (\n\tinitialized = abool.NewBool(false)\n\n\tshuttingDown   = abool.NewBool(false)\n\tshutdownSignal = make(chan struct{})\n\n\trootDir string\n)\n\n// Initialize initializes the database at the specified location.\nfunc Initialize(databasesRootDir string) error {\n\tif initialized.SetToIf(false, true) {\n\t\trootDir = databasesRootDir\n\n\t\t// ensure root and databases dirs\n\t\terr := utils.EnsureDirectory(rootDir, utils.AdminOnlyExecPermission)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create/check database dir %q: %w\", rootDir, err)\n\t\t}\n\n\t\treturn nil\n\t}\n\treturn errors.New(\"database already initialized\")\n}\n\n// Shutdown shuts down the whole database system.\nfunc Shutdown() (err error) {\n\tif shuttingDown.SetToIf(false, true) {\n\t\tclose(shutdownSignal)\n\t} else {\n\t\treturn\n\t}\n\n\tcontrollersLock.RLock()\n\tdefer controllersLock.RUnlock()\n\n\tfor _, c := range controllers {\n\t\terr = c.Shutdown()\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\n// getLocation returns the storage location for the given name and type.\nfunc getLocation(name, storageType string) (string, error) {\n\tlocation := filepath.Join(rootDir, name, storageType)\n\n\t// Make sure location exists.\n\terr := utils.EnsureDirectory(location, utils.AdminOnlyExecPermission)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create/check database dir %q: %w\", location, err)\n\t}\n\treturn location, nil\n}\n"
  },
  {
    "path": "base/database/maintenance.go",
    "content": "package database\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// Maintain runs the Maintain method on all storages.\nfunc Maintain(ctx context.Context) (err error) {\n\t// copy, as we might use the very long\n\tall := duplicateControllers()\n\n\tfor _, c := range all {\n\t\terr = c.Maintain(ctx)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\n// MaintainThorough runs the MaintainThorough method on all storages.\nfunc MaintainThorough(ctx context.Context) (err error) {\n\t// copy, as we might use the very long\n\tall := duplicateControllers()\n\n\tfor _, c := range all {\n\t\terr = c.MaintainThorough(ctx)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\n// MaintainRecordStates runs record state lifecycle maintenance on all storages.\nfunc MaintainRecordStates(ctx context.Context) (err error) {\n\t// delete immediately for now\n\t// TODO: increase purge threshold when starting to sync DBs\n\tpurgeDeletedBefore := time.Now().UTC()\n\n\t// copy, as we might use the very long\n\tall := duplicateControllers()\n\n\tfor _, c := range all {\n\t\terr = c.MaintainRecordStates(ctx, purgeDeletedBefore)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\nfunc duplicateControllers() (all []*Controller) {\n\tcontrollersLock.RLock()\n\tdefer controllersLock.RUnlock()\n\n\tall = make([]*Controller, 0, len(controllers))\n\tfor _, c := range controllers {\n\t\tall = append(all, c)\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "base/database/migration/error.go",
    "content": "package migration\n\nimport \"errors\"\n\n// DiagnosticStep describes one migration step in the Diagnostics.\ntype DiagnosticStep struct {\n\tVersion     string\n\tDescription string\n}\n\n// Diagnostics holds a detailed error report about a failed migration.\ntype Diagnostics struct { //nolint:errname\n\t// Message holds a human readable message of the encountered\n\t// error.\n\tMessage string\n\t// Wrapped must be set to the underlying error that was encountered\n\t// while preparing or executing migrations.\n\tWrapped error\n\t// StartOfMigration is set to the version of the database before\n\t// any migrations are applied.\n\tStartOfMigration string\n\t// LastSuccessfulMigration is set to the version of the database\n\t// which has been applied successfully before the error happened.\n\tLastSuccessfulMigration string\n\t// TargetVersion is set to the version of the database that the\n\t// migration run aimed for. That is, it's the last available version\n\t// added to the registry.\n\tTargetVersion string\n\t// ExecutionPlan is a list of migration steps that were planned to\n\t// be executed.\n\tExecutionPlan []DiagnosticStep\n\t// FailedMigration is the description of the migration that has\n\t// failed.\n\tFailedMigration string\n}\n\n// Error returns a string representation of the migration error.\nfunc (err *Diagnostics) Error() string {\n\tmsg := \"\"\n\tif err.FailedMigration != \"\" {\n\t\tmsg = err.FailedMigration + \": \"\n\t}\n\tif err.Message != \"\" {\n\t\tmsg += err.Message + \": \"\n\t}\n\tmsg += err.Wrapped.Error()\n\treturn msg\n}\n\n// Unwrap returns the actual error that happened when executing\n// a migration. It implements the interface required by the stdlib\n// errors package to support errors.Is() and errors.As().\nfunc (err *Diagnostics) Unwrap() error {\n\tif u := errors.Unwrap(err.Wrapped); u != nil {\n\t\treturn u\n\t}\n\treturn err.Wrapped\n}\n"
  },
  {
    "path": "base/database/migration/migration.go",
    "content": "package migration\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-version\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// MigrateFunc is called when a migration should be applied to the\n// database. It receives the current version (from) and the target\n// version (to) of the database and a dedicated interface for\n// interacting with data stored in the DB.\n// A dedicated log.ContextTracer is added to ctx for each migration\n// run.\ntype MigrateFunc func(ctx context.Context, from, to *version.Version, dbInterface *database.Interface) error\n\n// Migration represents a registered data-migration that should be applied to\n// some database. Migrations are stacked on top and executed in order of increasing\n// version number (see Version field).\ntype Migration struct {\n\t// Description provides a short human-readable description of the\n\t// migration.\n\tDescription string\n\t// Version should hold the version of the database/subsystem after\n\t// the migration has been applied.\n\tVersion string\n\t// MigrateFuc is executed when the migration should be performed.\n\tMigrateFunc MigrateFunc\n}\n\n// Registry holds a migration stack.\ntype Registry struct {\n\tkey string\n\n\tlock       sync.Mutex\n\tmigrations []Migration\n}\n\n// New creates a new migration registry.\n// The key should be the name of the database key that is used to store\n// the version of the last successfully applied migration.\nfunc New(key string) *Registry {\n\treturn &Registry{\n\t\tkey: key,\n\t}\n}\n\n// Add adds one or more migrations to reg.\nfunc (reg *Registry) Add(migrations ...Migration) error {\n\treg.lock.Lock()\n\tdefer reg.lock.Unlock()\n\tfor _, m := range migrations {\n\t\tif _, err := version.NewSemver(m.Version); err != nil {\n\t\t\treturn fmt.Errorf(\"migration %q: invalid version %s: %w\", m.Description, m.Version, err)\n\t\t}\n\t\treg.migrations = append(reg.migrations, m)\n\t}\n\treturn nil\n}\n\n// Migrate migrates the database by executing all registered\n// migration in order of increasing version numbers. The error\n// returned, if not nil, is always of type *Diagnostics.\nfunc (reg *Registry) Migrate(ctx context.Context) (err error) {\n\treg.lock.Lock()\n\tdefer reg.lock.Unlock()\n\n\tstart := time.Now()\n\tlog.Infof(\"migration: migration of %s started\", reg.key)\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"migration: migration of %s failed after %s: %s\", reg.key, time.Since(start), err)\n\t\t} else {\n\t\t\tlog.Infof(\"migration: migration of %s finished after %s\", reg.key, time.Since(start))\n\t\t}\n\t}()\n\n\tdb := database.NewInterface(&database.Options{\n\t\tLocal:    true,\n\t\tInternal: true,\n\t})\n\n\tstartOfMigration, err := reg.getLatestSuccessfulMigration(db)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texecPlan, diag, err := reg.getExecutionPlan(startOfMigration)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(execPlan) == 0 {\n\t\treturn nil\n\t}\n\tdiag.TargetVersion = execPlan[len(execPlan)-1].Version\n\n\t// finally, apply our migrations\n\tlastAppliedMigration := startOfMigration\n\tfor _, m := range execPlan {\n\t\ttarget, _ := version.NewSemver(m.Version) // we can safely ignore the error here\n\n\t\tmigrationCtx, tracer := log.AddTracer(ctx)\n\n\t\tif err := m.MigrateFunc(migrationCtx, lastAppliedMigration, target, db); err != nil {\n\t\t\tdiag.Wrapped = err\n\t\t\tdiag.FailedMigration = m.Description\n\t\t\ttracer.Errorf(\"migration: migration for %s failed: %s - %s\", reg.key, target.String(), m.Description)\n\t\t\ttracer.Submit()\n\t\t\treturn diag\n\t\t}\n\n\t\tlastAppliedMigration = target\n\t\tdiag.LastSuccessfulMigration = lastAppliedMigration.String()\n\n\t\tif err := reg.saveLastSuccessfulMigration(db, target); err != nil {\n\t\t\tdiag.Message = \"failed to persist migration status\"\n\t\t\tdiag.Wrapped = err\n\t\t\tdiag.FailedMigration = m.Description\n\t\t}\n\t\ttracer.Infof(\"migration: applied migration for %s: %s - %s\", reg.key, target.String(), m.Description)\n\t\ttracer.Submit()\n\t}\n\n\t// all migrations have been applied successfully, we're done here\n\treturn nil\n}\n\nfunc (reg *Registry) getLatestSuccessfulMigration(db *database.Interface) (*version.Version, error) {\n\t// find the latest version stored in the database\n\trec, err := db.Get(reg.key)\n\tif errors.Is(err, database.ErrNotFound) {\n\t\treturn nil, nil\n\t}\n\tif err != nil {\n\t\treturn nil, &Diagnostics{\n\t\t\tMessage: \"failed to query database for migration status\",\n\t\t\tWrapped: err,\n\t\t}\n\t}\n\n\t// Unwrap the record to get the actual database\n\tr, ok := rec.(*record.Wrapper)\n\tif !ok {\n\t\treturn nil, &Diagnostics{\n\t\t\tWrapped: errors.New(\"expected wrapped database record\"),\n\t\t}\n\t}\n\n\tsv, err := version.NewSemver(string(r.Data))\n\tif err != nil {\n\t\treturn nil, &Diagnostics{\n\t\t\tMessage: \"failed to parse version stored in migration status record\",\n\t\t\tWrapped: err,\n\t\t}\n\t}\n\treturn sv, nil\n}\n\nfunc (reg *Registry) saveLastSuccessfulMigration(db *database.Interface, ver *version.Version) error {\n\tr := &record.Wrapper{\n\t\tData:   []byte(ver.String()),\n\t\tFormat: dsd.RAW,\n\t}\n\tr.SetKey(reg.key)\n\n\treturn db.Put(r)\n}\n\nfunc (reg *Registry) getExecutionPlan(startOfMigration *version.Version) ([]Migration, *Diagnostics, error) {\n\t// create a look-up map for migrations indexed by their semver created a\n\t// list of version (sorted by increasing number) that we use as our execution\n\t// plan.\n\tlm := make(map[string]Migration)\n\tversions := make(version.Collection, 0, len(reg.migrations))\n\tfor _, m := range reg.migrations {\n\t\tver, err := version.NewSemver(m.Version)\n\t\tif err != nil {\n\t\t\treturn nil, nil, &Diagnostics{\n\t\t\t\tMessage:         \"failed to parse version of migration\",\n\t\t\t\tWrapped:         err,\n\t\t\t\tFailedMigration: m.Description,\n\t\t\t}\n\t\t}\n\t\tlm[ver.String()] = m // use .String() for a normalized string representation\n\t\tversions = append(versions, ver)\n\t}\n\tsort.Sort(versions)\n\n\tdiag := new(Diagnostics)\n\tif startOfMigration != nil {\n\t\tdiag.StartOfMigration = startOfMigration.String()\n\t}\n\n\t// prepare our diagnostics and the execution plan\n\texecPlan := make([]Migration, 0, len(versions))\n\tfor _, ver := range versions {\n\t\t// skip an migration that has already been applied.\n\t\tif startOfMigration != nil && startOfMigration.GreaterThanOrEqual(ver) {\n\t\t\tcontinue\n\t\t}\n\t\tm := lm[ver.String()]\n\t\tdiag.ExecutionPlan = append(diag.ExecutionPlan, DiagnosticStep{\n\t\t\tDescription: m.Description,\n\t\t\tVersion:     ver.String(),\n\t\t})\n\t\texecPlan = append(execPlan, m)\n\t}\n\n\treturn execPlan, diag, nil\n}\n"
  },
  {
    "path": "base/database/query/README.md",
    "content": "# Query\n\n## Control Flow\n\n- Grouping with `(` and `)`\n- Chaining with `and` and `or`\n  - _NO_ mixing! Be explicit and use grouping.\n- Negation with `not`\n  - in front of expression for group: `not (...)`\n  - inside expression for clause: `name not matches \"^King \"`\n\n## Selectors\n\nSupported by all feeders:\n- root level field: `field`\n- sub level field: `field.sub`\n- array/slice/map access: `map.0`\n- array/slice/map length: `map.#`\n\nPlease note that some feeders may have other special characters. It is advised to only use alphanumeric characters for keys.\n\n## Operators\n\n| Name                    | Textual            | Req. Type | Internal Type | Compared with             |\n|-------------------------|--------------------|-----------|---------------|---------------------------|\n| Equals                  | `==`               | int       | int64         | `==`                      |\n| GreaterThan             | `>`                | int       | int64         | `>`                       |\n| GreaterThanOrEqual      | `>=`               | int       | int64         | `>=`                      |\n| LessThan                | `<`                | int       | int64         | `<`                       |\n| LessThanOrEqual         | `<=`               | int       | int64         | `<=`                      |\n| FloatEquals             | `f==`              | float     | float64       | `==`                      |\n| FloatGreaterThan        | `f>`               | float     | float64       | `>`                       |\n| FloatGreaterThanOrEqual | `f>=`              | float     | float64       | `>=`                      |\n| FloatLessThan           | `f<`               | float     | float64       | `<`                       |\n| FloatLessThanOrEqual    | `f<=`              | float     | float64       | `<=`                      |\n| SameAs                  | `sameas`, `s==`    | string    | string        | `==`                      |\n| Contains                | `contains`, `co`   | string    | string        | `strings.Contains()`      |\n| StartsWith              | `startswith`, `sw` | string    | string        | `strings.HasPrefix()`     |\n| EndsWith                | `endswith`, `ew`   | string    | string        | `strings.HasSuffix()`     |\n| In                      | `in`               | string    | string        | for loop with `==`        |\n| Matches                 | `matches`, `re`    | string    | string        | `regexp.Regexp.Matches()` |\n| Is                      | `is`               | bool*     | bool          | `==`                      |\n| Exists                  | `exists`, `ex`     | any       | n/a           | n/a                       |\n\n\\*accepts strings: 1, t, T, true, True, TRUE, 0, f, F, false, False, FALSE\n\n## Escaping\n\nIf you need to use a control character within a value (ie. not for controlling), escape it with `\\`.\nIt is recommended to wrap a word into parenthesis instead of escaping control characters, when possible.\n\n| Location | Characters to be escaped |\n|---|---|\n| Within parenthesis (`\"`) | `\"`, `\\` |\n| Everywhere else | `(`, `)`, `\"`, `\\`, `\\t`, `\\r`, `\\n`, ` ` (space) |\n"
  },
  {
    "path": "base/database/query/condition-and.go",
    "content": "package query\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\n// And combines multiple conditions with a logical _AND_ operator.\nfunc And(conditions ...Condition) Condition {\n\treturn &andCond{\n\t\tconditions: conditions,\n\t}\n}\n\ntype andCond struct {\n\tconditions []Condition\n}\n\nfunc (c *andCond) complies(acc accessor.Accessor) bool {\n\tfor _, cond := range c.conditions {\n\t\tif !cond.complies(acc) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (c *andCond) check() (err error) {\n\tfor _, cond := range c.conditions {\n\t\terr = cond.check()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *andCond) string() string {\n\tall := make([]string, 0, len(c.conditions))\n\tfor _, cond := range c.conditions {\n\t\tall = append(all, cond.string())\n\t}\n\treturn fmt.Sprintf(\"(%s)\", strings.Join(all, \" and \"))\n}\n"
  },
  {
    "path": "base/database/query/condition-bool.go",
    "content": "package query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\ntype boolCondition struct {\n\tkey      string\n\toperator uint8\n\tvalue    bool\n}\n\nfunc newBoolCondition(key string, operator uint8, value interface{}) *boolCondition {\n\tvar parsedValue bool\n\n\tswitch v := value.(type) {\n\tcase bool:\n\t\tparsedValue = v\n\tcase string:\n\t\tvar err error\n\t\tparsedValue, err = strconv.ParseBool(v)\n\t\tif err != nil {\n\t\t\treturn &boolCondition{\n\t\t\t\tkey:      fmt.Sprintf(\"could not parse \\\"%s\\\" to bool: %s\", v, err),\n\t\t\t\toperator: errorPresent,\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn &boolCondition{\n\t\t\tkey:      fmt.Sprintf(\"incompatible value %v for int64\", value),\n\t\t\toperator: errorPresent,\n\t\t}\n\t}\n\n\treturn &boolCondition{\n\t\tkey:      key,\n\t\toperator: operator,\n\t\tvalue:    parsedValue,\n\t}\n}\n\nfunc (c *boolCondition) complies(acc accessor.Accessor) bool {\n\tcomp, ok := acc.GetBool(c.key)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tswitch c.operator {\n\tcase Is:\n\t\treturn comp == c.value\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (c *boolCondition) check() error {\n\tif c.operator == errorPresent {\n\t\treturn errors.New(c.key)\n\t}\n\treturn nil\n}\n\nfunc (c *boolCondition) string() string {\n\treturn fmt.Sprintf(\"%s %s %t\", escapeString(c.key), getOpName(c.operator), c.value)\n}\n"
  },
  {
    "path": "base/database/query/condition-error.go",
    "content": "package query\n\nimport (\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\ntype errorCondition struct {\n\terr error\n}\n\nfunc newErrorCondition(err error) *errorCondition {\n\treturn &errorCondition{\n\t\terr: err,\n\t}\n}\n\nfunc (c *errorCondition) complies(acc accessor.Accessor) bool {\n\treturn false\n}\n\nfunc (c *errorCondition) check() error {\n\treturn c.err\n}\n\nfunc (c *errorCondition) string() string {\n\treturn \"[ERROR]\"\n}\n"
  },
  {
    "path": "base/database/query/condition-exists.go",
    "content": "package query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\ntype existsCondition struct {\n\tkey      string\n\toperator uint8\n}\n\nfunc newExistsCondition(key string, operator uint8) *existsCondition {\n\treturn &existsCondition{\n\t\tkey:      key,\n\t\toperator: operator,\n\t}\n}\n\nfunc (c *existsCondition) complies(acc accessor.Accessor) bool {\n\treturn acc.Exists(c.key)\n}\n\nfunc (c *existsCondition) check() error {\n\tif c.operator == errorPresent {\n\t\treturn errors.New(c.key)\n\t}\n\treturn nil\n}\n\nfunc (c *existsCondition) string() string {\n\treturn fmt.Sprintf(\"%s %s\", escapeString(c.key), getOpName(c.operator))\n}\n"
  },
  {
    "path": "base/database/query/condition-float.go",
    "content": "package query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\ntype floatCondition struct {\n\tkey      string\n\toperator uint8\n\tvalue    float64\n}\n\nfunc newFloatCondition(key string, operator uint8, value interface{}) *floatCondition {\n\tvar parsedValue float64\n\n\tswitch v := value.(type) {\n\tcase int:\n\t\tparsedValue = float64(v)\n\tcase int8:\n\t\tparsedValue = float64(v)\n\tcase int16:\n\t\tparsedValue = float64(v)\n\tcase int32:\n\t\tparsedValue = float64(v)\n\tcase int64:\n\t\tparsedValue = float64(v)\n\tcase uint:\n\t\tparsedValue = float64(v)\n\tcase uint8:\n\t\tparsedValue = float64(v)\n\tcase uint16:\n\t\tparsedValue = float64(v)\n\tcase uint32:\n\t\tparsedValue = float64(v)\n\tcase float32:\n\t\tparsedValue = float64(v)\n\tcase float64:\n\t\tparsedValue = v\n\tcase string:\n\t\tvar err error\n\t\tparsedValue, err = strconv.ParseFloat(v, 64)\n\t\tif err != nil {\n\t\t\treturn &floatCondition{\n\t\t\t\tkey:      fmt.Sprintf(\"could not parse %s to float64: %s\", v, err),\n\t\t\t\toperator: errorPresent,\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn &floatCondition{\n\t\t\tkey:      fmt.Sprintf(\"incompatible value %v for float64\", value),\n\t\t\toperator: errorPresent,\n\t\t}\n\t}\n\n\treturn &floatCondition{\n\t\tkey:      key,\n\t\toperator: operator,\n\t\tvalue:    parsedValue,\n\t}\n}\n\nfunc (c *floatCondition) complies(acc accessor.Accessor) bool {\n\tcomp, ok := acc.GetFloat(c.key)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tswitch c.operator {\n\tcase FloatEquals:\n\t\treturn comp == c.value\n\tcase FloatGreaterThan:\n\t\treturn comp > c.value\n\tcase FloatGreaterThanOrEqual:\n\t\treturn comp >= c.value\n\tcase FloatLessThan:\n\t\treturn comp < c.value\n\tcase FloatLessThanOrEqual:\n\t\treturn comp <= c.value\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (c *floatCondition) check() error {\n\tif c.operator == errorPresent {\n\t\treturn errors.New(c.key)\n\t}\n\treturn nil\n}\n\nfunc (c *floatCondition) string() string {\n\treturn fmt.Sprintf(\"%s %s %g\", escapeString(c.key), getOpName(c.operator), c.value)\n}\n"
  },
  {
    "path": "base/database/query/condition-int.go",
    "content": "package query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\ntype intCondition struct {\n\tkey      string\n\toperator uint8\n\tvalue    int64\n}\n\nfunc newIntCondition(key string, operator uint8, value interface{}) *intCondition {\n\tvar parsedValue int64\n\n\tswitch v := value.(type) {\n\tcase int:\n\t\tparsedValue = int64(v)\n\tcase int8:\n\t\tparsedValue = int64(v)\n\tcase int16:\n\t\tparsedValue = int64(v)\n\tcase int32:\n\t\tparsedValue = int64(v)\n\tcase int64:\n\t\tparsedValue = v\n\tcase uint:\n\t\tparsedValue = int64(v)\n\tcase uint8:\n\t\tparsedValue = int64(v)\n\tcase uint16:\n\t\tparsedValue = int64(v)\n\tcase uint32:\n\t\tparsedValue = int64(v)\n\tcase string:\n\t\tvar err error\n\t\tparsedValue, err = strconv.ParseInt(v, 10, 64)\n\t\tif err != nil {\n\t\t\treturn &intCondition{\n\t\t\t\tkey:      fmt.Sprintf(\"could not parse %s to int64: %s (hint: use \\\"sameas\\\" to compare strings)\", v, err),\n\t\t\t\toperator: errorPresent,\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn &intCondition{\n\t\t\tkey:      fmt.Sprintf(\"incompatible value %v for int64\", value),\n\t\t\toperator: errorPresent,\n\t\t}\n\t}\n\n\treturn &intCondition{\n\t\tkey:      key,\n\t\toperator: operator,\n\t\tvalue:    parsedValue,\n\t}\n}\n\nfunc (c *intCondition) complies(acc accessor.Accessor) bool {\n\tcomp, ok := acc.GetInt(c.key)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tswitch c.operator {\n\tcase Equals:\n\t\treturn comp == c.value\n\tcase GreaterThan:\n\t\treturn comp > c.value\n\tcase GreaterThanOrEqual:\n\t\treturn comp >= c.value\n\tcase LessThan:\n\t\treturn comp < c.value\n\tcase LessThanOrEqual:\n\t\treturn comp <= c.value\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (c *intCondition) check() error {\n\tif c.operator == errorPresent {\n\t\treturn errors.New(c.key)\n\t}\n\treturn nil\n}\n\nfunc (c *intCondition) string() string {\n\treturn fmt.Sprintf(\"%s %s %d\", escapeString(c.key), getOpName(c.operator), c.value)\n}\n"
  },
  {
    "path": "base/database/query/condition-not.go",
    "content": "package query\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\n// Not negates the supplied condition.\nfunc Not(c Condition) Condition {\n\treturn &notCond{\n\t\tnotC: c,\n\t}\n}\n\ntype notCond struct {\n\tnotC Condition\n}\n\nfunc (c *notCond) complies(acc accessor.Accessor) bool {\n\treturn !c.notC.complies(acc)\n}\n\nfunc (c *notCond) check() error {\n\treturn c.notC.check()\n}\n\nfunc (c *notCond) string() string {\n\tnext := c.notC.string()\n\tif strings.HasPrefix(next, \"(\") {\n\t\treturn fmt.Sprintf(\"not %s\", c.notC.string())\n\t}\n\tsplitted := strings.Split(next, \" \")\n\treturn strings.Join(append([]string{splitted[0], \"not\"}, splitted[1:]...), \" \")\n}\n"
  },
  {
    "path": "base/database/query/condition-or.go",
    "content": "package query\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\n// Or combines multiple conditions with a logical _OR_ operator.\nfunc Or(conditions ...Condition) Condition {\n\treturn &orCond{\n\t\tconditions: conditions,\n\t}\n}\n\ntype orCond struct {\n\tconditions []Condition\n}\n\nfunc (c *orCond) complies(acc accessor.Accessor) bool {\n\tfor _, cond := range c.conditions {\n\t\tif cond.complies(acc) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (c *orCond) check() (err error) {\n\tfor _, cond := range c.conditions {\n\t\terr = cond.check()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (c *orCond) string() string {\n\tall := make([]string, 0, len(c.conditions))\n\tfor _, cond := range c.conditions {\n\t\tall = append(all, cond.string())\n\t}\n\treturn fmt.Sprintf(\"(%s)\", strings.Join(all, \" or \"))\n}\n"
  },
  {
    "path": "base/database/query/condition-regex.go",
    "content": "package query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\ntype regexCondition struct {\n\tkey      string\n\toperator uint8\n\tregex    *regexp.Regexp\n}\n\nfunc newRegexCondition(key string, operator uint8, value interface{}) *regexCondition {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tr, err := regexp.Compile(v)\n\t\tif err != nil {\n\t\t\treturn &regexCondition{\n\t\t\t\tkey:      fmt.Sprintf(\"could not compile regex \\\"%s\\\": %s\", v, err),\n\t\t\t\toperator: errorPresent,\n\t\t\t}\n\t\t}\n\t\treturn &regexCondition{\n\t\t\tkey:      key,\n\t\t\toperator: operator,\n\t\t\tregex:    r,\n\t\t}\n\tdefault:\n\t\treturn &regexCondition{\n\t\t\tkey:      fmt.Sprintf(\"incompatible value %v for string\", value),\n\t\t\toperator: errorPresent,\n\t\t}\n\t}\n}\n\nfunc (c *regexCondition) complies(acc accessor.Accessor) bool {\n\tcomp, ok := acc.GetString(c.key)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tswitch c.operator {\n\tcase Matches:\n\t\treturn c.regex.MatchString(comp)\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (c *regexCondition) check() error {\n\tif c.operator == errorPresent {\n\t\treturn errors.New(c.key)\n\t}\n\treturn nil\n}\n\nfunc (c *regexCondition) string() string {\n\treturn fmt.Sprintf(\"%s %s %s\", escapeString(c.key), getOpName(c.operator), escapeString(c.regex.String()))\n}\n"
  },
  {
    "path": "base/database/query/condition-string.go",
    "content": "package query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\ntype stringCondition struct {\n\tkey      string\n\toperator uint8\n\tvalue    string\n}\n\nfunc newStringCondition(key string, operator uint8, value interface{}) *stringCondition {\n\tswitch v := value.(type) {\n\tcase string:\n\t\treturn &stringCondition{\n\t\t\tkey:      key,\n\t\t\toperator: operator,\n\t\t\tvalue:    v,\n\t\t}\n\tdefault:\n\t\treturn &stringCondition{\n\t\t\tkey:      fmt.Sprintf(\"incompatible value %v for string\", value),\n\t\t\toperator: errorPresent,\n\t\t}\n\t}\n}\n\nfunc (c *stringCondition) complies(acc accessor.Accessor) bool {\n\tcomp, ok := acc.GetString(c.key)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tswitch c.operator {\n\tcase SameAs:\n\t\treturn c.value == comp\n\tcase Contains:\n\t\treturn strings.Contains(comp, c.value)\n\tcase StartsWith:\n\t\treturn strings.HasPrefix(comp, c.value)\n\tcase EndsWith:\n\t\treturn strings.HasSuffix(comp, c.value)\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (c *stringCondition) check() error {\n\tif c.operator == errorPresent {\n\t\treturn errors.New(c.key)\n\t}\n\treturn nil\n}\n\nfunc (c *stringCondition) string() string {\n\treturn fmt.Sprintf(\"%s %s %s\", escapeString(c.key), getOpName(c.operator), escapeString(c.value))\n}\n"
  },
  {
    "path": "base/database/query/condition-stringslice.go",
    "content": "package query\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\ntype stringSliceCondition struct {\n\tkey      string\n\toperator uint8\n\tvalue    []string\n}\n\nfunc newStringSliceCondition(key string, operator uint8, value interface{}) *stringSliceCondition {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tparsedValue := strings.Split(v, \",\")\n\t\tif len(parsedValue) < 2 {\n\t\t\treturn &stringSliceCondition{\n\t\t\t\tkey:      v,\n\t\t\t\toperator: errorPresent,\n\t\t\t}\n\t\t}\n\t\treturn &stringSliceCondition{\n\t\t\tkey:      key,\n\t\t\toperator: operator,\n\t\t\tvalue:    parsedValue,\n\t\t}\n\tcase []string:\n\t\treturn &stringSliceCondition{\n\t\t\tkey:      key,\n\t\t\toperator: operator,\n\t\t\tvalue:    v,\n\t\t}\n\tdefault:\n\t\treturn &stringSliceCondition{\n\t\t\tkey:      fmt.Sprintf(\"incompatible value %v for []string\", value),\n\t\t\toperator: errorPresent,\n\t\t}\n\t}\n}\n\nfunc (c *stringSliceCondition) complies(acc accessor.Accessor) bool {\n\tcomp, ok := acc.GetString(c.key)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tswitch c.operator {\n\tcase In:\n\t\treturn utils.StringInSlice(c.value, comp)\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (c *stringSliceCondition) check() error {\n\tif c.operator == errorPresent {\n\t\treturn fmt.Errorf(\"could not parse \\\"%s\\\" to []string\", c.key)\n\t}\n\treturn nil\n}\n\nfunc (c *stringSliceCondition) string() string {\n\treturn fmt.Sprintf(\"%s %s %s\", escapeString(c.key), getOpName(c.operator), escapeString(strings.Join(c.value, \",\")))\n}\n"
  },
  {
    "path": "base/database/query/condition.go",
    "content": "package query\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\n// Condition is an interface to provide a common api to all condition types.\ntype Condition interface {\n\tcomplies(acc accessor.Accessor) bool\n\tcheck() error\n\tstring() string\n}\n\n// Operators.\nconst (\n\tEquals                  uint8 = iota // int\n\tGreaterThan                          // int\n\tGreaterThanOrEqual                   // int\n\tLessThan                             // int\n\tLessThanOrEqual                      // int\n\tFloatEquals                          // float\n\tFloatGreaterThan                     // float\n\tFloatGreaterThanOrEqual              // float\n\tFloatLessThan                        // float\n\tFloatLessThanOrEqual                 // float\n\tSameAs                               // string\n\tContains                             // string\n\tStartsWith                           // string\n\tEndsWith                             // string\n\tIn                                   // stringSlice\n\tMatches                              // regex\n\tIs                                   // bool: accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE\n\tExists                               // any\n\n\terrorPresent uint8 = 255\n)\n\n// Where returns a condition to add to a query.\nfunc Where(key string, operator uint8, value interface{}) Condition {\n\tswitch operator {\n\tcase Equals,\n\t\tGreaterThan,\n\t\tGreaterThanOrEqual,\n\t\tLessThan,\n\t\tLessThanOrEqual:\n\t\treturn newIntCondition(key, operator, value)\n\tcase FloatEquals,\n\t\tFloatGreaterThan,\n\t\tFloatGreaterThanOrEqual,\n\t\tFloatLessThan,\n\t\tFloatLessThanOrEqual:\n\t\treturn newFloatCondition(key, operator, value)\n\tcase SameAs,\n\t\tContains,\n\t\tStartsWith,\n\t\tEndsWith:\n\t\treturn newStringCondition(key, operator, value)\n\tcase In:\n\t\treturn newStringSliceCondition(key, operator, value)\n\tcase Matches:\n\t\treturn newRegexCondition(key, operator, value)\n\tcase Is:\n\t\treturn newBoolCondition(key, operator, value)\n\tcase Exists:\n\t\treturn newExistsCondition(key, operator)\n\tdefault:\n\t\treturn newErrorCondition(fmt.Errorf(\"no operator with ID %d\", operator))\n\t}\n}\n"
  },
  {
    "path": "base/database/query/condition_test.go",
    "content": "package query\n\nimport \"testing\"\n\nfunc testSuccess(t *testing.T, c Condition) {\n\tt.Helper()\n\n\terr := c.check()\n\tif err != nil {\n\t\tt.Errorf(\"failed: %s\", err)\n\t}\n}\n\nfunc TestInterfaces(t *testing.T) {\n\tt.Parallel()\n\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, uint(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, uint8(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, uint16(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, uint32(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, int(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, int8(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, int16(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, int32(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, int64(1)))\n\ttestSuccess(t, newIntCondition(\"banana\", Equals, \"1\"))\n\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, uint(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, uint8(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, uint16(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, uint32(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, int(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, int8(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, int16(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, int32(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, int64(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, float32(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, float64(1)))\n\ttestSuccess(t, newFloatCondition(\"banana\", FloatEquals, \"1.1\"))\n\n\ttestSuccess(t, newStringCondition(\"banana\", SameAs, \"coconut\"))\n\ttestSuccess(t, newRegexCondition(\"banana\", Matches, \"coconut\"))\n\ttestSuccess(t, newStringSliceCondition(\"banana\", FloatEquals, []string{\"banana\", \"coconut\"}))\n\ttestSuccess(t, newStringSliceCondition(\"banana\", FloatEquals, \"banana,coconut\"))\n}\n\nfunc testCondError(t *testing.T, c Condition) {\n\tt.Helper()\n\n\terr := c.check()\n\tif err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n}\n\nfunc TestConditionErrors(t *testing.T) {\n\tt.Parallel()\n\n\t// test invalid value types\n\ttestCondError(t, newBoolCondition(\"banana\", Is, 1))\n\ttestCondError(t, newFloatCondition(\"banana\", FloatEquals, true))\n\ttestCondError(t, newIntCondition(\"banana\", Equals, true))\n\ttestCondError(t, newStringCondition(\"banana\", SameAs, 1))\n\ttestCondError(t, newRegexCondition(\"banana\", Matches, 1))\n\ttestCondError(t, newStringSliceCondition(\"banana\", Matches, 1))\n\n\t// test error presence\n\ttestCondError(t, newBoolCondition(\"banana\", errorPresent, true))\n\ttestCondError(t, And(newBoolCondition(\"banana\", errorPresent, true)))\n\ttestCondError(t, Or(newBoolCondition(\"banana\", errorPresent, true)))\n\ttestCondError(t, newExistsCondition(\"banana\", errorPresent))\n\ttestCondError(t, newFloatCondition(\"banana\", errorPresent, 1.1))\n\ttestCondError(t, newIntCondition(\"banana\", errorPresent, 1))\n\ttestCondError(t, newStringCondition(\"banana\", errorPresent, \"coconut\"))\n\ttestCondError(t, newRegexCondition(\"banana\", errorPresent, \"coconut\"))\n}\n\nfunc TestWhere(t *testing.T) {\n\tt.Parallel()\n\n\tc := Where(\"\", 254, nil)\n\terr := c.check()\n\tif err == nil {\n\t\tt.Error(\"should fail\")\n\t}\n}\n"
  },
  {
    "path": "base/database/query/operators.go",
    "content": "package query\n\nvar (\n\toperatorNames = map[string]uint8{\n\t\t\"==\":         Equals,\n\t\t\">\":          GreaterThan,\n\t\t\">=\":         GreaterThanOrEqual,\n\t\t\"<\":          LessThan,\n\t\t\"<=\":         LessThanOrEqual,\n\t\t\"f==\":        FloatEquals,\n\t\t\"f>\":         FloatGreaterThan,\n\t\t\"f>=\":        FloatGreaterThanOrEqual,\n\t\t\"f<\":         FloatLessThan,\n\t\t\"f<=\":        FloatLessThanOrEqual,\n\t\t\"sameas\":     SameAs,\n\t\t\"s==\":        SameAs,\n\t\t\"contains\":   Contains,\n\t\t\"co\":         Contains,\n\t\t\"startswith\": StartsWith,\n\t\t\"sw\":         StartsWith,\n\t\t\"endswith\":   EndsWith,\n\t\t\"ew\":         EndsWith,\n\t\t\"in\":         In,\n\t\t\"matches\":    Matches,\n\t\t\"re\":         Matches,\n\t\t\"is\":         Is,\n\t\t\"exists\":     Exists,\n\t\t\"ex\":         Exists,\n\t}\n\n\tprimaryNames = make(map[uint8]string)\n)\n\nfunc init() {\n\tfor opName, opID := range operatorNames {\n\t\tname, ok := primaryNames[opID]\n\t\tif ok {\n\t\t\tif len(name) < len(opName) {\n\t\t\t\tprimaryNames[opID] = opName\n\t\t\t}\n\t\t} else {\n\t\t\tprimaryNames[opID] = opName\n\t\t}\n\t}\n}\n\nfunc getOpName(operator uint8) string {\n\tname, ok := primaryNames[operator]\n\tif ok {\n\t\treturn name\n\t}\n\treturn \"[unknown]\"\n}\n"
  },
  {
    "path": "base/database/query/operators_test.go",
    "content": "package query\n\nimport \"testing\"\n\nfunc TestGetOpName(t *testing.T) {\n\tt.Parallel()\n\n\tif getOpName(254) != \"[unknown]\" {\n\t\tt.Error(\"unexpected output\")\n\t}\n}\n"
  },
  {
    "path": "base/database/query/parser.go",
    "content": "package query\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype snippet struct {\n\ttext           string\n\tglobalPosition int\n}\n\n// ParseQuery parses a plaintext query. Special characters (that must be escaped with a '\\') are: `\\()` and any whitespaces.\n//\n//nolint:gocognit\nfunc ParseQuery(query string) (*Query, error) {\n\tsnippets, err := extractSnippets(query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsnippetsPos := 0\n\n\tgetSnippet := func() (*snippet, error) {\n\t\t// order is important, as parseAndOr will always consume one additional snippet.\n\t\tsnippetsPos++\n\t\tif snippetsPos > len(snippets) {\n\t\t\treturn nil, fmt.Errorf(\"unexpected end at position %d\", len(query))\n\t\t}\n\t\treturn snippets[snippetsPos-1], nil\n\t}\n\tremainingSnippets := func() int {\n\t\treturn len(snippets) - snippetsPos\n\t}\n\n\t// check for query word\n\tqueryWord, err := getSnippet()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif queryWord.text != \"query\" {\n\t\treturn nil, errors.New(\"queries must start with \\\"query\\\"\")\n\t}\n\n\t// get prefix\n\tprefix, err := getSnippet()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tq := New(prefix.text)\n\n\tfor remainingSnippets() > 0 {\n\t\tcommand, err := getSnippet()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tswitch command.text {\n\t\tcase \"where\":\n\t\t\tif q.where != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"duplicate \\\"%s\\\" clause found at position %d\", command.text, command.globalPosition)\n\t\t\t}\n\n\t\t\t// parse conditions\n\t\t\tcondition, err := parseAndOr(getSnippet, remainingSnippets, true)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// go one back, as parseAndOr had to check if its done\n\t\t\tsnippetsPos--\n\n\t\t\tq.Where(condition)\n\t\tcase \"orderby\":\n\t\t\tif q.orderBy != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"duplicate \\\"%s\\\" clause found at position %d\", command.text, command.globalPosition)\n\t\t\t}\n\n\t\t\torderBySnippet, err := getSnippet()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tq.OrderBy(orderBySnippet.text)\n\t\tcase \"limit\":\n\t\t\tif q.limit != 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"duplicate \\\"%s\\\" clause found at position %d\", command.text, command.globalPosition)\n\t\t\t}\n\n\t\t\tlimitSnippet, err := getSnippet()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tlimit, err := strconv.ParseUint(limitSnippet.text, 10, 31)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"could not parse integer (%s) at position %d\", limitSnippet.text, limitSnippet.globalPosition)\n\t\t\t}\n\n\t\t\tq.Limit(int(limit))\n\t\tcase \"offset\":\n\t\t\tif q.offset != 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"duplicate \\\"%s\\\" clause found at position %d\", command.text, command.globalPosition)\n\t\t\t}\n\n\t\t\toffsetSnippet, err := getSnippet()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\toffset, err := strconv.ParseUint(offsetSnippet.text, 10, 31)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"could not parse integer (%s) at position %d\", offsetSnippet.text, offsetSnippet.globalPosition)\n\t\t\t}\n\n\t\t\tq.Offset(int(offset))\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown clause \\\"%s\\\" at position %d\", command.text, command.globalPosition)\n\t\t}\n\t}\n\n\treturn q.Check()\n}\n\nfunc extractSnippets(text string) (snippets []*snippet, err error) {\n\tskip := false\n\tstart := -1\n\tinParenthesis := false\n\tvar pos int\n\tvar char rune\n\n\tfor pos, char = range text {\n\n\t\t// skip\n\t\tif skip {\n\t\t\tskip = false\n\t\t\tcontinue\n\t\t}\n\t\tif char == '\\\\' {\n\t\t\tskip = true\n\t\t}\n\n\t\t// wait for parenthesis to be overs\n\t\tif inParenthesis {\n\t\t\tif char == '\"' {\n\t\t\t\tsnippets = append(snippets, &snippet{\n\t\t\t\t\ttext:           prepToken(text[start+1 : pos]),\n\t\t\t\t\tglobalPosition: start + 1,\n\t\t\t\t})\n\t\t\t\tstart = -1\n\t\t\t\tinParenthesis = false\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// handle segments\n\t\tswitch char {\n\t\tcase '\\t', '\\n', '\\r', ' ', '(', ')':\n\t\t\tif start >= 0 {\n\t\t\t\tsnippets = append(snippets, &snippet{\n\t\t\t\t\ttext:           prepToken(text[start:pos]),\n\t\t\t\t\tglobalPosition: start + 1,\n\t\t\t\t})\n\t\t\t\tstart = -1\n\t\t\t}\n\t\tdefault:\n\t\t\tif start == -1 {\n\t\t\t\tstart = pos\n\t\t\t}\n\t\t}\n\n\t\t// handle special segment characters\n\t\tswitch char {\n\t\tcase '(', ')':\n\t\t\tsnippets = append(snippets, &snippet{\n\t\t\t\ttext:           text[pos : pos+1],\n\t\t\t\tglobalPosition: pos + 1,\n\t\t\t})\n\t\tcase '\"':\n\t\t\tif start < pos {\n\t\t\t\treturn nil, fmt.Errorf(\"parenthesis ('\\\"') may not be used within words, please escape with '\\\\' (position: %d)\", pos+1)\n\t\t\t}\n\t\t\tinParenthesis = true\n\t\t}\n\n\t}\n\n\t// add last\n\tif start >= 0 {\n\t\tsnippets = append(snippets, &snippet{\n\t\t\ttext:           prepToken(text[start : pos+1]),\n\t\t\tglobalPosition: start + 1,\n\t\t})\n\t}\n\n\treturn snippets, nil\n}\n\n//nolint:gocognit\nfunc parseAndOr(getSnippet func() (*snippet, error), remainingSnippets func() int, rootCondition bool) (Condition, error) {\n\tvar (\n\t\tisOr          = false\n\t\ttypeSet       = false\n\t\twrapInNot     = false\n\t\texpectingMore = true\n\t\tconditions    []Condition\n\t)\n\n\tfor {\n\t\tif !expectingMore && rootCondition && remainingSnippets() == 0 {\n\t\t\t// advance snippetsPos by one, as it will be set back by 1\n\t\t\t_, _ = getSnippet()\n\t\t\tif len(conditions) == 1 {\n\t\t\t\treturn conditions[0], nil\n\t\t\t}\n\t\t\tif isOr {\n\t\t\t\treturn Or(conditions...), nil\n\t\t\t}\n\t\t\treturn And(conditions...), nil\n\t\t}\n\n\t\tfirstSnippet, err := getSnippet()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif !expectingMore && rootCondition {\n\t\t\tswitch firstSnippet.text {\n\t\t\tcase \"orderby\", \"limit\", \"offset\":\n\t\t\t\tif len(conditions) == 1 {\n\t\t\t\t\treturn conditions[0], nil\n\t\t\t\t}\n\t\t\t\tif isOr {\n\t\t\t\t\treturn Or(conditions...), nil\n\t\t\t\t}\n\t\t\t\treturn And(conditions...), nil\n\t\t\t}\n\t\t}\n\n\t\tswitch firstSnippet.text {\n\t\tcase \"(\":\n\t\t\tcondition, err := parseAndOr(getSnippet, remainingSnippets, false)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif wrapInNot {\n\t\t\t\tconditions = append(conditions, Not(condition))\n\t\t\t\twrapInNot = false\n\t\t\t} else {\n\t\t\t\tconditions = append(conditions, condition)\n\t\t\t}\n\t\t\texpectingMore = true\n\t\tcase \")\":\n\t\t\tif len(conditions) == 1 {\n\t\t\t\treturn conditions[0], nil\n\t\t\t}\n\t\t\tif isOr {\n\t\t\t\treturn Or(conditions...), nil\n\t\t\t}\n\t\t\treturn And(conditions...), nil\n\t\tcase \"and\":\n\t\t\tif typeSet && isOr {\n\t\t\t\treturn nil, fmt.Errorf(\"you may not mix \\\"and\\\" and \\\"or\\\" (position: %d)\", firstSnippet.globalPosition)\n\t\t\t}\n\t\t\tisOr = false\n\t\t\ttypeSet = true\n\t\t\texpectingMore = true\n\t\tcase \"or\":\n\t\t\tif typeSet && !isOr {\n\t\t\t\treturn nil, fmt.Errorf(\"you may not mix \\\"and\\\" and \\\"or\\\" (position: %d)\", firstSnippet.globalPosition)\n\t\t\t}\n\t\t\tisOr = true\n\t\t\ttypeSet = true\n\t\t\texpectingMore = true\n\t\tcase \"not\":\n\t\t\twrapInNot = true\n\t\t\texpectingMore = true\n\t\tdefault:\n\t\t\tcondition, err := parseCondition(firstSnippet, getSnippet)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif wrapInNot {\n\t\t\t\tconditions = append(conditions, Not(condition))\n\t\t\t\twrapInNot = false\n\t\t\t} else {\n\t\t\t\tconditions = append(conditions, condition)\n\t\t\t}\n\t\t\texpectingMore = false\n\t\t}\n\t}\n}\n\nfunc parseCondition(firstSnippet *snippet, getSnippet func() (*snippet, error)) (Condition, error) {\n\twrapInNot := false\n\n\t// get operator name\n\topName, err := getSnippet()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// negate?\n\tif opName.text == \"not\" {\n\t\twrapInNot = true\n\t\topName, err = getSnippet()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// get operator\n\toperator, ok := operatorNames[opName.text]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unknown operator at position %d\", opName.globalPosition)\n\t}\n\n\t// don't need a value for \"exists\"\n\tif operator == Exists {\n\t\tif wrapInNot {\n\t\t\treturn Not(Where(firstSnippet.text, operator, nil)), nil\n\t\t}\n\t\treturn Where(firstSnippet.text, operator, nil), nil\n\t}\n\n\t// get value\n\tvalue, err := getSnippet()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif wrapInNot {\n\t\treturn Not(Where(firstSnippet.text, operator, value.text)), nil\n\t}\n\treturn Where(firstSnippet.text, operator, value.text), nil\n}\n\nvar escapeReplacer = regexp.MustCompile(`\\\\([^\\\\])`)\n\n// prepToken removes surrounding parenthesis and escape characters.\nfunc prepToken(text string) string {\n\treturn escapeReplacer.ReplaceAllString(strings.Trim(text, \"\\\"\"), \"$1\")\n}\n\n// escapeString correctly escapes a snippet for printing.\nfunc escapeString(token string) string {\n\t// check if token contains characters that need to be escaped\n\tif strings.ContainsAny(token, \"()\\\"\\\\\\t\\r\\n \") {\n\t\t// put the token in parenthesis and only escape \\ and \"\n\t\treturn fmt.Sprintf(\"\\\"%s\\\"\", strings.ReplaceAll(token, \"\\\"\", \"\\\\\\\"\"))\n\t}\n\treturn token\n}\n"
  },
  {
    "path": "base/database/query/parser_test.go",
    "content": "package query\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/davecgh/go-spew/spew\"\n)\n\nfunc TestExtractSnippets(t *testing.T) {\n\tt.Parallel()\n\n\ttext1 := `query test: where ( \"bananas\" > 100 and monkeys.# <= \"12\")or(coconuts < 10 \"and\" area > 50) or name sameas Julian or name matches ^King\\ `\n\tresult1 := []*snippet{\n\t\t{text: \"query\", globalPosition: 1},\n\t\t{text: \"test:\", globalPosition: 7},\n\t\t{text: \"where\", globalPosition: 13},\n\t\t{text: \"(\", globalPosition: 19},\n\t\t{text: \"bananas\", globalPosition: 21},\n\t\t{text: \">\", globalPosition: 31},\n\t\t{text: \"100\", globalPosition: 33},\n\t\t{text: \"and\", globalPosition: 37},\n\t\t{text: \"monkeys.#\", globalPosition: 41},\n\t\t{text: \"<=\", globalPosition: 51},\n\t\t{text: \"12\", globalPosition: 54},\n\t\t{text: \")\", globalPosition: 58},\n\t\t{text: \"or\", globalPosition: 59},\n\t\t{text: \"(\", globalPosition: 61},\n\t\t{text: \"coconuts\", globalPosition: 62},\n\t\t{text: \"<\", globalPosition: 71},\n\t\t{text: \"10\", globalPosition: 73},\n\t\t{text: \"and\", globalPosition: 76},\n\t\t{text: \"area\", globalPosition: 82},\n\t\t{text: \">\", globalPosition: 87},\n\t\t{text: \"50\", globalPosition: 89},\n\t\t{text: \")\", globalPosition: 91},\n\t\t{text: \"or\", globalPosition: 93},\n\t\t{text: \"name\", globalPosition: 96},\n\t\t{text: \"sameas\", globalPosition: 101},\n\t\t{text: \"Julian\", globalPosition: 108},\n\t\t{text: \"or\", globalPosition: 115},\n\t\t{text: \"name\", globalPosition: 118},\n\t\t{text: \"matches\", globalPosition: 123},\n\t\t{text: \"^King \", globalPosition: 131},\n\t}\n\n\tsnippets, err := extractSnippets(text1)\n\tif err != nil {\n\t\tt.Errorf(\"failed to extract snippets: %s\", err)\n\t}\n\n\tif !reflect.DeepEqual(result1, snippets) {\n\t\tt.Errorf(\"unexpected results:\")\n\t\tfor _, el := range snippets {\n\t\t\tt.Errorf(\"%+v\", el)\n\t\t}\n\t}\n\n\t// t.Error(spew.Sprintf(\"%v\", treeElement))\n}\n\nfunc testParsing(t *testing.T, queryText string, expectedResult *Query) {\n\tt.Helper()\n\n\t_, err := expectedResult.Check()\n\tif err != nil {\n\t\tt.Errorf(\"failed to create query: %s\", err)\n\t\treturn\n\t}\n\n\tq, err := ParseQuery(queryText)\n\tif err != nil {\n\t\tt.Errorf(\"failed to parse query: %s\", err)\n\t\treturn\n\t}\n\n\tif queryText != q.Print() {\n\t\tt.Errorf(\"string match failed: %s\", q.Print())\n\t\treturn\n\t}\n\tif !reflect.DeepEqual(expectedResult, q) {\n\t\tt.Error(\"deepqual match failed.\")\n\t\tt.Error(\"got:\")\n\t\tt.Error(spew.Sdump(q))\n\t\tt.Error(\"expected:\")\n\t\tt.Error(spew.Sdump(expectedResult))\n\t}\n}\n\nfunc TestParseQuery(t *testing.T) {\n\tt.Parallel()\n\n\ttext1 := `query test: where (bananas > 100 and monkeys.# <= 12) or not (coconuts < 10 and area not > 50) or name sameas Julian or name matches \"^King \" orderby name limit 10 offset 20`\n\tresult1 := New(\"test:\").Where(Or(\n\t\tAnd(\n\t\t\tWhere(\"bananas\", GreaterThan, 100),\n\t\t\tWhere(\"monkeys.#\", LessThanOrEqual, 12),\n\t\t),\n\t\tNot(And(\n\t\t\tWhere(\"coconuts\", LessThan, 10),\n\t\t\tNot(Where(\"area\", GreaterThan, 50)),\n\t\t)),\n\t\tWhere(\"name\", SameAs, \"Julian\"),\n\t\tWhere(\"name\", Matches, \"^King \"),\n\t)).OrderBy(\"name\").Limit(10).Offset(20)\n\ttestParsing(t, text1, result1)\n\n\ttestParsing(t, `query test: orderby name`, New(\"test:\").OrderBy(\"name\"))\n\ttestParsing(t, `query test: limit 10`, New(\"test:\").Limit(10))\n\ttestParsing(t, `query test: offset 10`, New(\"test:\").Offset(10))\n\ttestParsing(t, `query test: where banana matches ^ban`, New(\"test:\").Where(Where(\"banana\", Matches, \"^ban\")))\n\ttestParsing(t, `query test: where banana exists`, New(\"test:\").Where(Where(\"banana\", Exists, nil)))\n\ttestParsing(t, `query test: where banana not exists`, New(\"test:\").Where(Not(Where(\"banana\", Exists, nil))))\n\n\t// test all operators\n\ttestParsing(t, `query test: where banana == 1`, New(\"test:\").Where(Where(\"banana\", Equals, 1)))\n\ttestParsing(t, `query test: where banana > 1`, New(\"test:\").Where(Where(\"banana\", GreaterThan, 1)))\n\ttestParsing(t, `query test: where banana >= 1`, New(\"test:\").Where(Where(\"banana\", GreaterThanOrEqual, 1)))\n\ttestParsing(t, `query test: where banana < 1`, New(\"test:\").Where(Where(\"banana\", LessThan, 1)))\n\ttestParsing(t, `query test: where banana <= 1`, New(\"test:\").Where(Where(\"banana\", LessThanOrEqual, 1)))\n\ttestParsing(t, `query test: where banana f== 1.1`, New(\"test:\").Where(Where(\"banana\", FloatEquals, 1.1)))\n\ttestParsing(t, `query test: where banana f> 1.1`, New(\"test:\").Where(Where(\"banana\", FloatGreaterThan, 1.1)))\n\ttestParsing(t, `query test: where banana f>= 1.1`, New(\"test:\").Where(Where(\"banana\", FloatGreaterThanOrEqual, 1.1)))\n\ttestParsing(t, `query test: where banana f< 1.1`, New(\"test:\").Where(Where(\"banana\", FloatLessThan, 1.1)))\n\ttestParsing(t, `query test: where banana f<= 1.1`, New(\"test:\").Where(Where(\"banana\", FloatLessThanOrEqual, 1.1)))\n\ttestParsing(t, `query test: where banana sameas banana`, New(\"test:\").Where(Where(\"banana\", SameAs, \"banana\")))\n\ttestParsing(t, `query test: where banana contains banana`, New(\"test:\").Where(Where(\"banana\", Contains, \"banana\")))\n\ttestParsing(t, `query test: where banana startswith banana`, New(\"test:\").Where(Where(\"banana\", StartsWith, \"banana\")))\n\ttestParsing(t, `query test: where banana endswith banana`, New(\"test:\").Where(Where(\"banana\", EndsWith, \"banana\")))\n\ttestParsing(t, `query test: where banana in banana,coconut`, New(\"test:\").Where(Where(\"banana\", In, []string{\"banana\", \"coconut\"})))\n\ttestParsing(t, `query test: where banana matches banana`, New(\"test:\").Where(Where(\"banana\", Matches, \"banana\")))\n\ttestParsing(t, `query test: where banana is true`, New(\"test:\").Where(Where(\"banana\", Is, true)))\n\ttestParsing(t, `query test: where banana exists`, New(\"test:\").Where(Where(\"banana\", Exists, nil)))\n\n\t// special\n\ttestParsing(t, `query test: where banana not exists`, New(\"test:\").Where(Not(Where(\"banana\", Exists, nil))))\n}\n\nfunc testParseError(t *testing.T, queryText string, expectedErrorString string) {\n\tt.Helper()\n\n\t_, err := ParseQuery(queryText)\n\tif err == nil {\n\t\tt.Errorf(\"should fail to parse: %s\", queryText)\n\t\treturn\n\t}\n\tif err.Error() != expectedErrorString {\n\t\tt.Errorf(\"unexpected error for query: %s\\nwanted: %s\\n   got: %s\", queryText, expectedErrorString, err)\n\t}\n}\n\nfunc TestParseErrors(t *testing.T) {\n\tt.Parallel()\n\n\t// syntax\n\ttestParseError(t, `query`, `unexpected end at position 5`)\n\ttestParseError(t, `query test: where`, `unexpected end at position 17`)\n\ttestParseError(t, `query test: where (`, `unexpected end at position 19`)\n\ttestParseError(t, `query test: where )`, `unknown clause \")\" at position 19`)\n\ttestParseError(t, `query test: where not`, `unexpected end at position 21`)\n\ttestParseError(t, `query test: where banana`, `unexpected end at position 24`)\n\ttestParseError(t, `query test: where banana >`, `unexpected end at position 26`)\n\ttestParseError(t, `query test: where banana nope`, `unknown operator at position 26`)\n\ttestParseError(t, `query test: where banana exists or`, `unexpected end at position 34`)\n\ttestParseError(t, `query test: where banana exists and`, `unexpected end at position 35`)\n\ttestParseError(t, `query test: where banana exists and (`, `unexpected end at position 37`)\n\ttestParseError(t, `query test: where banana exists and banana is true or`, `you may not mix \"and\" and \"or\" (position: 52)`)\n\ttestParseError(t, `query test: where banana exists or banana is true and`, `you may not mix \"and\" and \"or\" (position: 51)`)\n\t// testParseError(t, `query test: where banana exists and (`, ``)\n\n\t// value parsing error\n\ttestParseError(t, `query test: where banana == banana`, `could not parse banana to int64: strconv.ParseInt: parsing \"banana\": invalid syntax (hint: use \"sameas\" to compare strings)`)\n\ttestParseError(t, `query test: where banana f== banana`, `could not parse banana to float64: strconv.ParseFloat: parsing \"banana\": invalid syntax`)\n\ttestParseError(t, `query test: where banana in banana`, `could not parse \"banana\" to []string`)\n\ttestParseError(t, `query test: where banana matches [banana`, \"could not compile regex \\\"[banana\\\": error parsing regexp: missing closing ]: `[banana`\")\n\ttestParseError(t, `query test: where banana is great`, `could not parse \"great\" to bool: strconv.ParseBool: parsing \"great\": invalid syntax`)\n}\n"
  },
  {
    "path": "base/database/query/query.go",
    "content": "package query\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// Example:\n// q.New(\"core:/\",\n//   q.Where(\"a\", q.GreaterThan, 0),\n//   q.Where(\"b\", q.Equals, 0),\n//   q.Or(\n//       q.Where(\"c\", q.StartsWith, \"x\"),\n//       q.Where(\"d\", q.Contains, \"y\")\n//     )\n//   )\n\n// Query contains a compiled query.\ntype Query struct {\n\tchecked     bool\n\tdbName      string\n\tdbKeyPrefix string\n\twhere       Condition\n\torderBy     string\n\tlimit       int\n\toffset      int\n}\n\n// New creates a new query with the supplied prefix.\nfunc New(prefix string) *Query {\n\tdbName, dbKeyPrefix := record.ParseKey(prefix)\n\treturn &Query{\n\t\tdbName:      dbName,\n\t\tdbKeyPrefix: dbKeyPrefix,\n\t}\n}\n\n// Where adds filtering.\nfunc (q *Query) Where(condition Condition) *Query {\n\tq.where = condition\n\treturn q\n}\n\n// Limit limits the number of returned results.\nfunc (q *Query) Limit(limit int) *Query {\n\tq.limit = limit\n\treturn q\n}\n\n// Offset sets the query offset.\nfunc (q *Query) Offset(offset int) *Query {\n\tq.offset = offset\n\treturn q\n}\n\n// OrderBy orders the results by the given key.\nfunc (q *Query) OrderBy(key string) *Query {\n\tq.orderBy = key\n\treturn q\n}\n\n// Check checks for errors in the query.\nfunc (q *Query) Check() (*Query, error) {\n\tif q.checked {\n\t\treturn q, nil\n\t}\n\n\t// check condition\n\tif q.where != nil {\n\t\terr := q.where.check()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tq.checked = true\n\treturn q, nil\n}\n\n// MustBeValid checks for errors in the query and panics if there is an error.\nfunc (q *Query) MustBeValid() *Query {\n\t_, err := q.Check()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn q\n}\n\n// IsChecked returns whether they query was checked.\nfunc (q *Query) IsChecked() bool {\n\treturn q.checked\n}\n\n// MatchesKey checks whether the query matches the supplied database key (key without database prefix).\nfunc (q *Query) MatchesKey(dbKey string) bool {\n\treturn strings.HasPrefix(dbKey, q.dbKeyPrefix)\n}\n\n// HasWhereCondition returns whether the query has a \"where\" condition set.\nfunc (q *Query) HasWhereCondition() bool {\n\treturn q.where != nil\n}\n\n// MatchesRecord checks whether the query matches the supplied database record (value only).\nfunc (q *Query) MatchesRecord(r record.Record) bool {\n\tif q.where == nil {\n\t\treturn true\n\t}\n\n\tacc := r.GetAccessor(r)\n\tif acc == nil {\n\t\treturn false\n\t}\n\treturn q.where.complies(acc)\n}\n\n// MatchesAccessor checks whether the query matches the supplied accessor (value only).\nfunc (q *Query) MatchesAccessor(acc accessor.Accessor) bool {\n\tif q.where == nil {\n\t\treturn true\n\t}\n\treturn q.where.complies(acc)\n}\n\n// Matches checks whether the query matches the supplied database record.\nfunc (q *Query) Matches(r record.Record) bool {\n\tif !q.MatchesKey(r.DatabaseKey()) {\n\t\treturn false\n\t}\n\treturn q.MatchesRecord(r)\n}\n\n// Print returns the string representation of the query.\nfunc (q *Query) Print() string {\n\tvar where string\n\tif q.where != nil {\n\t\twhere = q.where.string()\n\t\tif where != \"\" {\n\t\t\tif strings.HasPrefix(where, \"(\") {\n\t\t\t\twhere = where[1 : len(where)-1]\n\t\t\t}\n\t\t\twhere = fmt.Sprintf(\" where %s\", where)\n\t\t}\n\t}\n\n\tvar orderBy string\n\tif q.orderBy != \"\" {\n\t\torderBy = fmt.Sprintf(\" orderby %s\", q.orderBy)\n\t}\n\n\tvar limit string\n\tif q.limit > 0 {\n\t\tlimit = fmt.Sprintf(\" limit %d\", q.limit)\n\t}\n\n\tvar offset string\n\tif q.offset > 0 {\n\t\toffset = fmt.Sprintf(\" offset %d\", q.offset)\n\t}\n\n\treturn fmt.Sprintf(\"query %s:%s%s%s%s%s\", q.dbName, q.dbKeyPrefix, where, orderBy, limit, offset)\n}\n\n// DatabaseName returns the name of the database.\nfunc (q *Query) DatabaseName() string {\n\treturn q.dbName\n}\n\n// DatabaseKeyPrefix returns the key prefix for the database.\nfunc (q *Query) DatabaseKeyPrefix() string {\n\treturn q.dbKeyPrefix\n}\n"
  },
  {
    "path": "base/database/query/query_test.go",
    "content": "//nolint:unparam\npackage query\n\nimport (\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// copied from https://github.com/tidwall/gjson/blob/master/gjson_test.go\nvar testJSON = `{\"age\":100, \"name\":{\"here\":\"B\\\\\\\"R\"},\n  \"noop\":{\"what is a wren?\":\"a bird\"},\n  \"happy\":true,\"immortal\":false,\n  \"items\":[1,2,3,{\"tags\":[1,2,3],\"points\":[[1,2],[3,4]]},4,5,6,7],\n  \"arr\":[\"1\",2,\"3\",{\"hello\":\"world\"},\"4\",5],\n  \"vals\":[1,2,3,{\"sadf\":sdf\"asdf\"}],\"name\":{\"first\":\"tom\",\"last\":null},\n  \"created\":\"2014-05-16T08:28:06.989Z\",\n  \"loggy\":{\n  \t\"programmers\": [\n    \t    {\n    \t        \"firstName\": \"Brett\",\n    \t        \"lastName\": \"McLaughlin\",\n    \t        \"email\": \"aaaa\",\n  \t\t\t\"tag\": \"good\"\n    \t    },\n    \t    {\n    \t        \"firstName\": \"Jason\",\n    \t        \"lastName\": \"Hunter\",\n    \t        \"email\": \"bbbb\",\n  \t\t\t\"tag\": \"bad\"\n    \t    },\n    \t    {\n    \t        \"firstName\": \"Elliotte\",\n    \t        \"lastName\": \"Harold\",\n    \t        \"email\": \"cccc\",\n  \t\t\t\"tag\":, \"good\"\n    \t    },\n  \t\t{\n  \t\t\t\"firstName\": 1002.3,\n  \t\t\t\"age\": 101\n  \t\t}\n    \t]\n  },\n  \"lastly\":{\"yay\":\"final\"},\n\t\"temperature\": 120.413\n}`\n\nfunc testQuery(t *testing.T, r record.Record, shouldMatch bool, condition Condition) {\n\tt.Helper()\n\n\tq := New(\"test:\").Where(condition).MustBeValid()\n\t// fmt.Printf(\"%s\\n\", q.Print())\n\n\tmatched := q.Matches(r)\n\tswitch {\n\tcase !matched && shouldMatch:\n\t\tt.Errorf(\"should match: %s\", q.Print())\n\tcase matched && !shouldMatch:\n\t\tt.Errorf(\"should not match: %s\", q.Print())\n\t}\n}\n\nfunc TestQuery(t *testing.T) {\n\tt.Parallel()\n\n\t// if !gjson.Valid(testJSON) {\n\t// \tt.Fatal(\"test json is invalid\")\n\t// }\n\tr, err := record.NewWrapper(\"\", nil, dsd.JSON, []byte(testJSON))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestQuery(t, r, true, Where(\"age\", Equals, 100))\n\ttestQuery(t, r, true, Where(\"age\", GreaterThan, uint8(99)))\n\ttestQuery(t, r, true, Where(\"age\", GreaterThanOrEqual, 99))\n\ttestQuery(t, r, true, Where(\"age\", GreaterThanOrEqual, 100))\n\ttestQuery(t, r, true, Where(\"age\", LessThan, 101))\n\ttestQuery(t, r, true, Where(\"age\", LessThanOrEqual, \"101\"))\n\ttestQuery(t, r, true, Where(\"age\", LessThanOrEqual, 100))\n\n\ttestQuery(t, r, true, Where(\"temperature\", FloatEquals, 120.413))\n\ttestQuery(t, r, true, Where(\"temperature\", FloatGreaterThan, 120))\n\ttestQuery(t, r, true, Where(\"temperature\", FloatGreaterThanOrEqual, 120))\n\ttestQuery(t, r, true, Where(\"temperature\", FloatGreaterThanOrEqual, 120.413))\n\ttestQuery(t, r, true, Where(\"temperature\", FloatLessThan, 121))\n\ttestQuery(t, r, true, Where(\"temperature\", FloatLessThanOrEqual, \"121\"))\n\ttestQuery(t, r, true, Where(\"temperature\", FloatLessThanOrEqual, \"120.413\"))\n\n\ttestQuery(t, r, true, Where(\"lastly.yay\", SameAs, \"final\"))\n\ttestQuery(t, r, true, Where(\"lastly.yay\", Contains, \"ina\"))\n\ttestQuery(t, r, true, Where(\"lastly.yay\", StartsWith, \"fin\"))\n\ttestQuery(t, r, true, Where(\"lastly.yay\", EndsWith, \"nal\"))\n\ttestQuery(t, r, true, Where(\"lastly.yay\", In, \"draft,final\"))\n\ttestQuery(t, r, true, Where(\"lastly.yay\", In, \"final,draft\"))\n\n\ttestQuery(t, r, true, Where(\"happy\", Is, true))\n\ttestQuery(t, r, true, Where(\"happy\", Is, \"true\"))\n\ttestQuery(t, r, true, Where(\"happy\", Is, \"t\"))\n\ttestQuery(t, r, true, Not(Where(\"happy\", Is, \"0\")))\n\ttestQuery(t, r, true, And(\n\t\tWhere(\"happy\", Is, \"1\"),\n\t\tNot(Or(\n\t\t\tWhere(\"happy\", Is, false),\n\t\t\tWhere(\"happy\", Is, \"f\"),\n\t\t)),\n\t))\n\n\ttestQuery(t, r, true, Where(\"happy\", Exists, nil))\n\n\ttestQuery(t, r, true, Where(\"created\", Matches, \"^2014-[0-9]{2}-[0-9]{2}T\"))\n}\n"
  },
  {
    "path": "base/database/record/base.go",
    "content": "package record\n\nimport (\n\t\"errors\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// TODO(ppacher):\n//\t\twe can reduce the record.Record interface a lot by moving\n//\t\tmost of those functions that require the Record as it's first\n//\t\tparameter to static package functions\n//\t\t(i.e. Marshal, MarshalRecord, GetAccessor, ...).\n//\t\tWe should also consider given Base a GetBase() *Base method\n//\t\tthat returns itself. This way we can remove almost all Base\n//\t\tonly methods from the record.Record interface. That is, we can\n//\t\tremove all those CreateMeta, UpdateMeta, ... stuff from the\n//\t\tinterface definition (not the actual functions!). This would make\n// \t\tthe record.Record interface slim and only provide methods that\n//\t\tmost users actually need. All those database/storage related methods\n// \t\tcan still be accessed by using GetBase().XXX() instead. We can also\n//\t\texpose the dbName and dbKey and meta properties directly which would\n// \t\tmake a nice JSON blob when marshalled.\n\n// Base provides a quick way to comply with the Model interface.\ntype Base struct {\n\tdbName string\n\tdbKey  string\n\tmeta   *Meta\n}\n\n// SetKey sets the key on the database record. The key may only be set once and\n// future calls to SetKey will be ignored. If you want to copy/move the record\n// to another database key, you will need to create a copy and assign a new key.\n// A key must be set before the record is used in any database operation.\nfunc (b *Base) SetKey(key string) {\n\tif !b.KeyIsSet() {\n\t\tb.dbName, b.dbKey = ParseKey(key)\n\t} else {\n\t\tlog.Errorf(\"database: key is already set: tried to replace %q with %q\", b.Key(), key)\n\t}\n}\n\n// ResetKey resets the database name and key.\n// Use with caution!\nfunc (b *Base) ResetKey() {\n\tb.dbName = \"\"\n\tb.dbKey = \"\"\n}\n\n// Key returns the key of the database record.\n// As the key must be set before any usage and can only be set once, this\n// function may be used without locking the record.\nfunc (b *Base) Key() string {\n\treturn b.dbName + \":\" + b.dbKey\n}\n\n// KeyIsSet returns true if the database key is set.\n// As the key must be set before any usage and can only be set once, this\n// function may be used without locking the record.\nfunc (b *Base) KeyIsSet() bool {\n\treturn b.dbName != \"\"\n}\n\n// DatabaseName returns the name of the database.\n// As the key must be set before any usage and can only be set once, this\n// function may be used without locking the record.\nfunc (b *Base) DatabaseName() string {\n\treturn b.dbName\n}\n\n// DatabaseKey returns the database key of the database record.\n// As the key must be set before any usage and can only be set once, this\n// function may be used without locking the record.\nfunc (b *Base) DatabaseKey() string {\n\treturn b.dbKey\n}\n\n// Meta returns the metadata object for this record.\nfunc (b *Base) Meta() *Meta {\n\treturn b.meta\n}\n\n// CreateMeta sets a default metadata object for this record.\nfunc (b *Base) CreateMeta() {\n\tb.meta = &Meta{}\n}\n\n// UpdateMeta creates the metadata if it does not exist and updates it.\nfunc (b *Base) UpdateMeta() {\n\tif b.meta == nil {\n\t\tb.CreateMeta()\n\t}\n\tb.meta.Update()\n}\n\n// SetMeta sets the metadata on the database record, it should only be called after loading the record. Use MoveTo to save the record with another key.\nfunc (b *Base) SetMeta(meta *Meta) {\n\tb.meta = meta\n}\n\n// Marshal marshals the format and data.\nfunc (b *Base) Marshal(self Record, format uint8) ([]byte, error) {\n\tif b.Meta() == nil {\n\t\treturn nil, errors.New(\"missing meta\")\n\t}\n\n\tif b.Meta().Deleted > 0 {\n\t\treturn nil, nil\n\t}\n\n\tdumped, err := dsd.Dump(self, format)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dumped, nil\n}\n\n// MarshalDataOnly marshals the data only.\nfunc (b *Base) MarshalDataOnly(self Record, format uint8) ([]byte, error) {\n\tif b.Meta() == nil {\n\t\treturn nil, errors.New(\"missing meta\")\n\t}\n\n\tif b.Meta().Deleted > 0 {\n\t\treturn nil, nil\n\t}\n\n\treturn dsd.DumpWithoutIdentifier(self, format, \"\")\n}\n\n// MarshalRecord marshals the data, format and metadata.\nfunc (b *Base) MarshalRecord(self Record) ([]byte, error) {\n\tif b.Meta() == nil {\n\t\treturn nil, errors.New(\"missing meta\")\n\t}\n\n\t// version\n\tc := container.New([]byte{1})\n\n\t// meta encoding\n\tmetaSection, err := dsd.Dump(b.meta, dsd.GenCode)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.AppendAsBlock(metaSection)\n\n\t// data\n\tdataSection, err := b.Marshal(self, dsd.JSON)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.Append(dataSection)\n\n\treturn c.CompileData(), nil\n}\n\n// IsWrapped returns whether the record is a Wrapper.\nfunc (b *Base) IsWrapped() bool {\n\treturn false\n}\n\n// GetAccessor returns an accessor for this record, if available.\nfunc (b *Base) GetAccessor(self Record) accessor.Accessor {\n\treturn accessor.NewStructAccessor(self)\n}\n"
  },
  {
    "path": "base/database/record/base_test.go",
    "content": "package record\n\nimport \"testing\"\n\nfunc TestBaseRecord(t *testing.T) {\n\tt.Parallel()\n\n\t// check model interface compliance\n\tvar m Record\n\tb := &TestRecord{}\n\tm = b\n\t_ = m\n}\n"
  },
  {
    "path": "base/database/record/key.go",
    "content": "package record\n\nimport (\n\t\"strings\"\n)\n\n// ParseKey splits a key into it's database name and key parts.\nfunc ParseKey(key string) (dbName, dbKey string) {\n\tsplitted := strings.SplitN(key, \":\", 2)\n\tif len(splitted) < 2 {\n\t\treturn splitted[0], \"\"\n\t}\n\treturn splitted[0], strings.Join(splitted[1:], \":\")\n}\n"
  },
  {
    "path": "base/database/record/meta-bench_test.go",
    "content": "package record\n\n// Benchmark:\n// BenchmarkAllocateBytes-8                \t2000000000\t         0.76 ns/op\n// BenchmarkAllocateStruct1-8              \t2000000000\t         0.76 ns/op\n// BenchmarkAllocateStruct2-8              \t2000000000\t         0.79 ns/op\n// BenchmarkMetaSerializeContainer-8       \t 1000000\t      1703 ns/op\n// BenchmarkMetaUnserializeContainer-8     \t 2000000\t       950 ns/op\n// BenchmarkMetaSerializeVarInt-8          \t 3000000\t       457 ns/op\n// BenchmarkMetaUnserializeVarInt-8        \t20000000\t        62.9 ns/op\n// BenchmarkMetaSerializeWithXDR2-8        \t 1000000\t      2360 ns/op\n// BenchmarkMetaUnserializeWithXDR2-8      \t  500000\t      3189 ns/op\n// BenchmarkMetaSerializeWithColfer-8      \t10000000\t       237 ns/op\n// BenchmarkMetaUnserializeWithColfer-8    \t20000000\t        51.7 ns/op\n// BenchmarkMetaSerializeWithCodegen-8     \t50000000\t        23.7 ns/op\n// BenchmarkMetaUnserializeWithCodegen-8   \t100000000\t        18.9 ns/op\n// BenchmarkMetaSerializeWithDSDJSON-8     \t 1000000\t      2398 ns/op\n// BenchmarkMetaUnserializeWithDSDJSON-8   \t  300000\t      6264 ns/op\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n\t\"github.com/safing/structures/varint\"\n)\n\nvar testMeta = &Meta{\n\tCreated:   time.Now().Unix(),\n\tModified:  time.Now().Unix(),\n\tExpires:   time.Now().Unix(),\n\tDeleted:   time.Now().Unix(),\n\tsecret:    true,\n\tcronjewel: true,\n}\n\nfunc BenchmarkAllocateBytes(b *testing.B) {\n\tfor range b.N {\n\t\t_ = make([]byte, 33)\n\t}\n}\n\nfunc BenchmarkAllocateStruct1(b *testing.B) {\n\tfor range b.N {\n\t\tvar newMeta Meta\n\t\t_ = newMeta\n\t}\n}\n\nfunc BenchmarkAllocateStruct2(b *testing.B) {\n\tfor range b.N {\n\t\t_ = Meta{}\n\t}\n}\n\nfunc BenchmarkMetaSerializeContainer(b *testing.B) {\n\t// Start benchmark\n\tfor range b.N {\n\t\tc := container.New()\n\t\tc.AppendNumber(uint64(testMeta.Created))\n\t\tc.AppendNumber(uint64(testMeta.Modified))\n\t\tc.AppendNumber(uint64(testMeta.Expires))\n\t\tc.AppendNumber(uint64(testMeta.Deleted))\n\t\tswitch {\n\t\tcase testMeta.secret && testMeta.cronjewel:\n\t\t\tc.AppendNumber(3)\n\t\tcase testMeta.secret:\n\t\t\tc.AppendNumber(1)\n\t\tcase testMeta.cronjewel:\n\t\t\tc.AppendNumber(2)\n\t\tdefault:\n\t\t\tc.AppendNumber(0)\n\t\t}\n\t}\n}\n\nfunc BenchmarkMetaUnserializeContainer(b *testing.B) {\n\t// Setup\n\tc := container.New()\n\tc.AppendNumber(uint64(testMeta.Created))\n\tc.AppendNumber(uint64(testMeta.Modified))\n\tc.AppendNumber(uint64(testMeta.Expires))\n\tc.AppendNumber(uint64(testMeta.Deleted))\n\tswitch {\n\tcase testMeta.secret && testMeta.cronjewel:\n\t\tc.AppendNumber(3)\n\tcase testMeta.secret:\n\t\tc.AppendNumber(1)\n\tcase testMeta.cronjewel:\n\t\tc.AppendNumber(2)\n\tdefault:\n\t\tc.AppendNumber(0)\n\t}\n\tencodedData := c.CompileData()\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\tvar newMeta Meta\n\t\tvar err error\n\t\tvar num uint64\n\t\tc := container.New(encodedData)\n\t\tnum, err = c.GetNextN64()\n\t\tnewMeta.Created = int64(num)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"could not decode: %s\", err)\n\t\t\treturn\n\t\t}\n\t\tnum, err = c.GetNextN64()\n\t\tnewMeta.Modified = int64(num)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"could not decode: %s\", err)\n\t\t\treturn\n\t\t}\n\t\tnum, err = c.GetNextN64()\n\t\tnewMeta.Expires = int64(num)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"could not decode: %s\", err)\n\t\t\treturn\n\t\t}\n\t\tnum, err = c.GetNextN64()\n\t\tnewMeta.Deleted = int64(num)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"could not decode: %s\", err)\n\t\t\treturn\n\t\t}\n\n\t\tflags, err := c.GetNextN8()\n\t\tif err != nil {\n\t\t\tb.Errorf(\"could not decode: %s\", err)\n\t\t\treturn\n\t\t}\n\n\t\tswitch flags {\n\t\tcase 3:\n\t\t\tnewMeta.secret = true\n\t\t\tnewMeta.cronjewel = true\n\t\tcase 2:\n\t\t\tnewMeta.cronjewel = true\n\t\tcase 1:\n\t\t\tnewMeta.secret = true\n\t\tcase 0:\n\t\tdefault:\n\t\t\tb.Errorf(\"invalid flag value: %d\", flags)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc BenchmarkMetaSerializeVarInt(b *testing.B) {\n\t// Start benchmark\n\tfor range b.N {\n\t\tencoded := make([]byte, 33)\n\t\toffset := 0\n\t\tdata := varint.Pack64(uint64(testMeta.Created))\n\t\tfor _, part := range data {\n\t\t\tencoded[offset] = part\n\t\t\toffset++\n\t\t}\n\t\tdata = varint.Pack64(uint64(testMeta.Modified))\n\t\tfor _, part := range data {\n\t\t\tencoded[offset] = part\n\t\t\toffset++\n\t\t}\n\t\tdata = varint.Pack64(uint64(testMeta.Expires))\n\t\tfor _, part := range data {\n\t\t\tencoded[offset] = part\n\t\t\toffset++\n\t\t}\n\t\tdata = varint.Pack64(uint64(testMeta.Deleted))\n\t\tfor _, part := range data {\n\t\t\tencoded[offset] = part\n\t\t\toffset++\n\t\t}\n\n\t\tswitch {\n\t\tcase testMeta.secret && testMeta.cronjewel:\n\t\t\tencoded[offset] = 3\n\t\tcase testMeta.secret:\n\t\t\tencoded[offset] = 1\n\t\tcase testMeta.cronjewel:\n\t\t\tencoded[offset] = 2\n\t\tdefault:\n\t\t\tencoded[offset] = 0\n\t\t}\n\t}\n}\n\nfunc BenchmarkMetaUnserializeVarInt(b *testing.B) {\n\t// Setup\n\tencoded := make([]byte, 33)\n\toffset := 0\n\tdata := varint.Pack64(uint64(testMeta.Created))\n\tfor _, part := range data {\n\t\tencoded[offset] = part\n\t\toffset++\n\t}\n\tdata = varint.Pack64(uint64(testMeta.Modified))\n\tfor _, part := range data {\n\t\tencoded[offset] = part\n\t\toffset++\n\t}\n\tdata = varint.Pack64(uint64(testMeta.Expires))\n\tfor _, part := range data {\n\t\tencoded[offset] = part\n\t\toffset++\n\t}\n\tdata = varint.Pack64(uint64(testMeta.Deleted))\n\tfor _, part := range data {\n\t\tencoded[offset] = part\n\t\toffset++\n\t}\n\n\tswitch {\n\tcase testMeta.secret && testMeta.cronjewel:\n\t\tencoded[offset] = 3\n\tcase testMeta.secret:\n\t\tencoded[offset] = 1\n\tcase testMeta.cronjewel:\n\t\tencoded[offset] = 2\n\tdefault:\n\t\tencoded[offset] = 0\n\t}\n\toffset++\n\tencodedData := encoded[:offset]\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\tvar newMeta Meta\n\t\toffset = 0\n\n\t\tnum, n, err := varint.Unpack64(encodedData)\n\t\tif err != nil {\n\t\t\tb.Error(err)\n\t\t\treturn\n\t\t}\n\t\ttestMeta.Created = int64(num)\n\t\toffset += n\n\n\t\tnum, n, err = varint.Unpack64(encodedData[offset:])\n\t\tif err != nil {\n\t\t\tb.Error(err)\n\t\t\treturn\n\t\t}\n\t\ttestMeta.Modified = int64(num)\n\t\toffset += n\n\n\t\tnum, n, err = varint.Unpack64(encodedData[offset:])\n\t\tif err != nil {\n\t\t\tb.Error(err)\n\t\t\treturn\n\t\t}\n\t\ttestMeta.Expires = int64(num)\n\t\toffset += n\n\n\t\tnum, n, err = varint.Unpack64(encodedData[offset:])\n\t\tif err != nil {\n\t\t\tb.Error(err)\n\t\t\treturn\n\t\t}\n\t\ttestMeta.Deleted = int64(num)\n\t\toffset += n\n\n\t\tswitch encodedData[offset] {\n\t\tcase 3:\n\t\t\tnewMeta.secret = true\n\t\t\tnewMeta.cronjewel = true\n\t\tcase 2:\n\t\t\tnewMeta.cronjewel = true\n\t\tcase 1:\n\t\t\tnewMeta.secret = true\n\t\tcase 0:\n\t\tdefault:\n\t\t\tb.Errorf(\"invalid flag value: %d\", encodedData[offset])\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc BenchmarkMetaSerializeWithCodegen(b *testing.B) {\n\tfor range b.N {\n\t\t_, err := testMeta.GenCodeMarshal(nil)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"failed to serialize with codegen: %s\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc BenchmarkMetaUnserializeWithCodegen(b *testing.B) {\n\t// Setup\n\tencodedData, err := testMeta.GenCodeMarshal(nil)\n\tif err != nil {\n\t\tb.Errorf(\"failed to serialize with codegen: %s\", err)\n\t\treturn\n\t}\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\tvar newMeta Meta\n\t\t_, err := newMeta.GenCodeUnmarshal(encodedData)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"failed to unserialize with codegen: %s\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc BenchmarkMetaSerializeWithDSDJSON(b *testing.B) {\n\tfor range b.N {\n\t\t_, err := dsd.Dump(testMeta, dsd.JSON)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"failed to serialize with DSD/JSON: %s\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc BenchmarkMetaUnserializeWithDSDJSON(b *testing.B) {\n\t// Setup\n\tencodedData, err := dsd.Dump(testMeta, dsd.JSON)\n\tif err != nil {\n\t\tb.Errorf(\"failed to serialize with DSD/JSON: %s\", err)\n\t\treturn\n\t}\n\n\t// Reset timer for precise results\n\tb.ResetTimer()\n\n\t// Start benchmark\n\tfor range b.N {\n\t\tvar newMeta Meta\n\t\t_, err := dsd.Load(encodedData, &newMeta)\n\t\tif err != nil {\n\t\t\tb.Errorf(\"failed to unserialize with DSD/JSON: %s\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/database/record/meta-gencode.go",
    "content": "package record\n\nimport (\n\t\"fmt\"\n)\n\n// GenCodeSize returns the size of the gencode marshalled byte slice.\nfunc (m *Meta) GenCodeSize() (s int) {\n\ts += 34\n\treturn\n}\n\n// GenCodeMarshal gencode marshalls Meta into the given byte array, or a new one if its too small.\nfunc (m *Meta) GenCodeMarshal(buf []byte) ([]byte, error) {\n\tsize := m.GenCodeSize()\n\t{\n\t\tif cap(buf) >= size {\n\t\t\tbuf = buf[:size]\n\t\t} else {\n\t\t\tbuf = make([]byte, size)\n\t\t}\n\t}\n\ti := uint64(0)\n\n\t{\n\n\t\tbuf[0+0] = byte(m.Created >> 0)\n\n\t\tbuf[1+0] = byte(m.Created >> 8)\n\n\t\tbuf[2+0] = byte(m.Created >> 16)\n\n\t\tbuf[3+0] = byte(m.Created >> 24)\n\n\t\tbuf[4+0] = byte(m.Created >> 32)\n\n\t\tbuf[5+0] = byte(m.Created >> 40)\n\n\t\tbuf[6+0] = byte(m.Created >> 48)\n\n\t\tbuf[7+0] = byte(m.Created >> 56)\n\n\t}\n\t{\n\n\t\tbuf[0+8] = byte(m.Modified >> 0)\n\n\t\tbuf[1+8] = byte(m.Modified >> 8)\n\n\t\tbuf[2+8] = byte(m.Modified >> 16)\n\n\t\tbuf[3+8] = byte(m.Modified >> 24)\n\n\t\tbuf[4+8] = byte(m.Modified >> 32)\n\n\t\tbuf[5+8] = byte(m.Modified >> 40)\n\n\t\tbuf[6+8] = byte(m.Modified >> 48)\n\n\t\tbuf[7+8] = byte(m.Modified >> 56)\n\n\t}\n\t{\n\n\t\tbuf[0+16] = byte(m.Expires >> 0)\n\n\t\tbuf[1+16] = byte(m.Expires >> 8)\n\n\t\tbuf[2+16] = byte(m.Expires >> 16)\n\n\t\tbuf[3+16] = byte(m.Expires >> 24)\n\n\t\tbuf[4+16] = byte(m.Expires >> 32)\n\n\t\tbuf[5+16] = byte(m.Expires >> 40)\n\n\t\tbuf[6+16] = byte(m.Expires >> 48)\n\n\t\tbuf[7+16] = byte(m.Expires >> 56)\n\n\t}\n\t{\n\n\t\tbuf[0+24] = byte(m.Deleted >> 0)\n\n\t\tbuf[1+24] = byte(m.Deleted >> 8)\n\n\t\tbuf[2+24] = byte(m.Deleted >> 16)\n\n\t\tbuf[3+24] = byte(m.Deleted >> 24)\n\n\t\tbuf[4+24] = byte(m.Deleted >> 32)\n\n\t\tbuf[5+24] = byte(m.Deleted >> 40)\n\n\t\tbuf[6+24] = byte(m.Deleted >> 48)\n\n\t\tbuf[7+24] = byte(m.Deleted >> 56)\n\n\t}\n\t{\n\t\tif m.secret {\n\t\t\tbuf[32] = 1\n\t\t} else {\n\t\t\tbuf[32] = 0\n\t\t}\n\t}\n\t{\n\t\tif m.cronjewel {\n\t\t\tbuf[33] = 1\n\t\t} else {\n\t\t\tbuf[33] = 0\n\t\t}\n\t}\n\treturn buf[:i+34], nil\n}\n\n// GenCodeUnmarshal gencode unmarshalls Meta and returns the bytes read.\nfunc (m *Meta) GenCodeUnmarshal(buf []byte) (uint64, error) {\n\tif len(buf) < m.GenCodeSize() {\n\t\treturn 0, fmt.Errorf(\"insufficient data: got %d out of %d bytes\", len(buf), m.GenCodeSize())\n\t}\n\n\ti := uint64(0)\n\n\t{\n\t\tm.Created = 0 | (int64(buf[0+0]) << 0) | (int64(buf[1+0]) << 8) | (int64(buf[2+0]) << 16) | (int64(buf[3+0]) << 24) | (int64(buf[4+0]) << 32) | (int64(buf[5+0]) << 40) | (int64(buf[6+0]) << 48) | (int64(buf[7+0]) << 56)\n\t}\n\t{\n\t\tm.Modified = 0 | (int64(buf[0+8]) << 0) | (int64(buf[1+8]) << 8) | (int64(buf[2+8]) << 16) | (int64(buf[3+8]) << 24) | (int64(buf[4+8]) << 32) | (int64(buf[5+8]) << 40) | (int64(buf[6+8]) << 48) | (int64(buf[7+8]) << 56)\n\t}\n\t{\n\t\tm.Expires = 0 | (int64(buf[0+16]) << 0) | (int64(buf[1+16]) << 8) | (int64(buf[2+16]) << 16) | (int64(buf[3+16]) << 24) | (int64(buf[4+16]) << 32) | (int64(buf[5+16]) << 40) | (int64(buf[6+16]) << 48) | (int64(buf[7+16]) << 56)\n\t}\n\t{\n\t\tm.Deleted = 0 | (int64(buf[0+24]) << 0) | (int64(buf[1+24]) << 8) | (int64(buf[2+24]) << 16) | (int64(buf[3+24]) << 24) | (int64(buf[4+24]) << 32) | (int64(buf[5+24]) << 40) | (int64(buf[6+24]) << 48) | (int64(buf[7+24]) << 56)\n\t}\n\t{\n\t\tm.secret = buf[32] == 1\n\t}\n\t{\n\t\tm.cronjewel = buf[33] == 1\n\t}\n\treturn i + 34, nil\n}\n"
  },
  {
    "path": "base/database/record/meta-gencode_test.go",
    "content": "package record\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar genCodeTestMeta = &Meta{\n\tCreated:   time.Now().Unix(),\n\tModified:  time.Now().Unix(),\n\tExpires:   time.Now().Unix(),\n\tDeleted:   time.Now().Unix(),\n\tsecret:    true,\n\tcronjewel: true,\n}\n\nfunc TestGenCode(t *testing.T) {\n\tt.Parallel()\n\n\tencoded, err := genCodeTestMeta.GenCodeMarshal(nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tnewMeta := &Meta{}\n\t_, err = newMeta.GenCodeUnmarshal(encoded)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif !reflect.DeepEqual(genCodeTestMeta, newMeta) {\n\t\tt.Errorf(\"objects are not equal, got: %v\", newMeta)\n\t}\n}\n"
  },
  {
    "path": "base/database/record/meta.colf",
    "content": "package record\n\ntype course struct {\n  Created   int64\n  Modified  int64\n  Expires   int64\n  Deleted   int64\n  Secret    bool\n  Cronjewel bool\n}\n"
  },
  {
    "path": "base/database/record/meta.gencode",
    "content": "struct Meta {\n\tCreated   int64\n\tModified  int64\n\tExpires   int64\n\tDeleted   int64\n\tSecret    bool\n\tCronjewel bool\n}\n"
  },
  {
    "path": "base/database/record/meta.go",
    "content": "package record\n\nimport \"time\"\n\n// Meta holds metadata about the record.\ntype Meta struct {\n\tCreated   int64\n\tModified  int64\n\tExpires   int64\n\tDeleted   int64\n\tsecret    bool // secrets must not be sent to the UI, only synced between nodes\n\tcronjewel bool // crownjewels must never leave the instance, but may be read by the UI\n}\n\n// SetAbsoluteExpiry sets an absolute expiry time (in seconds), that is not affected when the record is updated.\nfunc (m *Meta) SetAbsoluteExpiry(seconds int64) {\n\tm.Expires = seconds\n\tm.Deleted = 0\n}\n\n// SetRelativateExpiry sets a relative expiry time (ie. TTL in seconds) that is automatically updated whenever the record is updated/saved.\nfunc (m *Meta) SetRelativateExpiry(seconds int64) {\n\tif seconds >= 0 {\n\t\tm.Deleted = -seconds\n\t}\n}\n\n// GetAbsoluteExpiry returns the absolute expiry time.\nfunc (m *Meta) GetAbsoluteExpiry() int64 {\n\treturn m.Expires\n}\n\n// GetRelativeExpiry returns the current relative expiry time - ie. seconds until expiry.\n// A negative value signifies that the record does not expire.\nfunc (m *Meta) GetRelativeExpiry() int64 {\n\tif m.Expires == 0 {\n\t\treturn -1\n\t}\n\n\tabs := m.Expires - time.Now().Unix()\n\tif abs < 0 {\n\t\treturn 0\n\t}\n\treturn abs\n}\n\n// MakeCrownJewel marks the database records as a crownjewel, meaning that it will not be sent/synced to other devices.\nfunc (m *Meta) MakeCrownJewel() {\n\tm.cronjewel = true\n}\n\n// IsCrownJewel returns whether the database record is marked as a crownjewel.\nfunc (m *Meta) IsCrownJewel() bool {\n\treturn m.cronjewel\n}\n\n// MakeSecret sets the database record as secret, meaning that it may only be used internally, and not by interfacing processes, such as the UI.\nfunc (m *Meta) MakeSecret() {\n\tm.secret = true\n}\n\n// IsSecret returns whether the database record is marked as a secret.\nfunc (m *Meta) IsSecret() bool {\n\treturn m.secret\n}\n\n// Update updates the internal meta states and should be called before writing the record to the database.\nfunc (m *Meta) Update() {\n\tnow := time.Now().Unix()\n\tm.Modified = now\n\tif m.Created == 0 {\n\t\tm.Created = now\n\t}\n\tif m.Deleted < 0 {\n\t\tm.Expires = now - m.Deleted\n\t}\n}\n\n// Reset resets all metadata, except for the secret and crownjewel status.\nfunc (m *Meta) Reset() {\n\tm.Created = 0\n\tm.Modified = 0\n\tm.Expires = 0\n\tm.Deleted = 0\n}\n\n// Delete marks the record as deleted.\nfunc (m *Meta) Delete() {\n\tm.Deleted = time.Now().Unix()\n}\n\n// IsDeleted returns whether the record is deleted.\nfunc (m *Meta) IsDeleted() bool {\n\treturn m.Deleted > 0\n}\n\n// CheckValidity checks whether the database record is valid.\nfunc (m *Meta) CheckValidity() (valid bool) {\n\tif m == nil {\n\t\treturn false\n\t}\n\n\tswitch {\n\tcase m.Deleted > 0:\n\t\treturn false\n\tcase m.Expires > 0 && m.Expires < time.Now().Unix():\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\n// CheckPermission checks whether the database record may be accessed with the following scope.\nfunc (m *Meta) CheckPermission(local, internal bool) (permitted bool) {\n\tif m == nil {\n\t\treturn false\n\t}\n\n\tswitch {\n\tcase !local && m.cronjewel:\n\t\treturn false\n\tcase !internal && m.secret:\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\n// Duplicate returns a new copy of Meta.\nfunc (m *Meta) Duplicate() *Meta {\n\treturn &Meta{\n\t\tCreated:   m.Created,\n\t\tModified:  m.Modified,\n\t\tExpires:   m.Expires,\n\t\tDeleted:   m.Deleted,\n\t\tsecret:    m.secret,\n\t\tcronjewel: m.cronjewel,\n\t}\n}\n"
  },
  {
    "path": "base/database/record/record.go",
    "content": "package record\n\nimport (\n\t\"github.com/safing/portmaster/base/database/accessor\"\n)\n\n// Record provides an interface for uniformally handling database records.\ntype Record interface {\n\tSetKey(key string) // test:config\n\tKey() string       // test:config\n\tKeyIsSet() bool\n\tDatabaseName() string // test\n\tDatabaseKey() string  // config\n\n\t// Metadata.\n\tMeta() *Meta\n\tSetMeta(meta *Meta)\n\tCreateMeta()\n\tUpdateMeta()\n\n\t// Serialization.\n\tMarshal(self Record, format uint8) ([]byte, error)\n\tMarshalDataOnly(self Record, format uint8) ([]byte, error)\n\tMarshalRecord(self Record) ([]byte, error)\n\tGetAccessor(self Record) accessor.Accessor\n\n\t// Locking.\n\tLock()\n\tUnlock()\n\n\t// Wrapping.\n\tIsWrapped() bool\n}\n"
  },
  {
    "path": "base/database/record/record_test.go",
    "content": "package record\n\nimport (\n\t\"sync\"\n)\n\ntype TestRecord struct {\n\tBase\n\tsync.Mutex\n}\n"
  },
  {
    "path": "base/database/record/wrapper.go",
    "content": "package record\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n\t\"github.com/safing/structures/varint\"\n)\n\n// Wrapper wraps raw data and implements the Record interface.\ntype Wrapper struct {\n\tBase\n\tsync.Mutex\n\n\tFormat uint8\n\tData   []byte\n}\n\n// NewRawWrapper returns a record wrapper for the given data, including metadata. This is normally only used by storage backends when loading records.\nfunc NewRawWrapper(database, key string, data []byte) (*Wrapper, error) {\n\tversion, offset, err := varint.Unpack8(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif version != 1 {\n\t\treturn nil, fmt.Errorf(\"incompatible record version: %d\", version)\n\t}\n\n\tmetaSection, n, err := varint.GetNextBlock(data[offset:])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not get meta section: %w\", err)\n\t}\n\toffset += n\n\n\tnewMeta := &Meta{}\n\t_, err = dsd.Load(metaSection, newMeta)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not unmarshal meta section: %w\", err)\n\t}\n\n\tvar format uint8 = dsd.RAW\n\tif !newMeta.IsDeleted() {\n\t\tformat, n, err = varint.Unpack8(data[offset:])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not get dsd format: %w\", err)\n\t\t}\n\t\toffset += n\n\t}\n\n\treturn &Wrapper{\n\t\tBase{\n\t\t\tdatabase,\n\t\t\tkey,\n\t\t\tnewMeta,\n\t\t},\n\t\tsync.Mutex{},\n\t\tformat,\n\t\tdata[offset:],\n\t}, nil\n}\n\n// NewWrapper returns a new record wrapper for the given data.\nfunc NewWrapper(key string, meta *Meta, format uint8, data []byte) (*Wrapper, error) {\n\tdbName, dbKey := ParseKey(key)\n\n\treturn &Wrapper{\n\t\tBase{\n\t\t\tdbName: dbName,\n\t\t\tdbKey:  dbKey,\n\t\t\tmeta:   meta,\n\t\t},\n\t\tsync.Mutex{},\n\t\tformat,\n\t\tdata,\n\t}, nil\n}\n\n// NewWrapperFromDatabase returns a new record wrapper for the given data.\nfunc NewWrapperFromDatabase(dbName, dbKey string, meta *Meta, format uint8, data []byte) (*Wrapper, error) {\n\treturn &Wrapper{\n\t\tBase{\n\t\t\tdbName: dbName,\n\t\t\tdbKey:  dbKey,\n\t\t\tmeta:   meta,\n\t\t},\n\t\tsync.Mutex{},\n\t\tformat,\n\t\tdata,\n\t}, nil\n}\n\n// Marshal marshals the format and data.\nfunc (w *Wrapper) Marshal(r Record, format uint8) ([]byte, error) {\n\tif w.Meta() == nil {\n\t\treturn nil, errors.New(\"missing meta\")\n\t}\n\n\tif w.Meta().Deleted > 0 {\n\t\treturn nil, nil\n\t}\n\n\tif format != dsd.AUTO && format != w.Format {\n\t\treturn nil, errors.New(\"could not dump model, wrapped object format mismatch\")\n\t}\n\n\tdata := make([]byte, len(w.Data)+1)\n\tdata[0] = w.Format\n\tcopy(data[1:], w.Data)\n\n\treturn data, nil\n}\n\n// MarshalDataOnly marshals the data only.\nfunc (w *Wrapper) MarshalDataOnly(self Record, format uint8) ([]byte, error) {\n\tif w.Meta() == nil {\n\t\treturn nil, errors.New(\"missing meta\")\n\t}\n\n\tif w.Meta().Deleted > 0 {\n\t\treturn nil, nil\n\t}\n\n\tif format != dsd.AUTO && format != w.Format {\n\t\treturn nil, errors.New(\"could not dump model, wrapped object format mismatch\")\n\t}\n\n\treturn w.Data, nil\n}\n\n// MarshalRecord marshals the data, format and metadata.\nfunc (w *Wrapper) MarshalRecord(r Record) ([]byte, error) {\n\t// Duplication necessary, as the version from Base would call Base.Marshal instead of Wrapper.Marshal\n\n\tif w.Meta() == nil {\n\t\treturn nil, errors.New(\"missing meta\")\n\t}\n\n\t// version\n\tc := container.New([]byte{1})\n\n\t// meta\n\tmetaSection, err := dsd.Dump(w.meta, dsd.GenCode)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.AppendAsBlock(metaSection)\n\n\t// data\n\tdataSection, err := w.Marshal(r, dsd.AUTO)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.Append(dataSection)\n\n\treturn c.CompileData(), nil\n}\n\n// IsWrapped returns whether the record is a Wrapper.\nfunc (w *Wrapper) IsWrapped() bool {\n\treturn true\n}\n\n// Unwrap unwraps data into a record.\nfunc Unwrap(wrapped, r Record) error {\n\twrapper, ok := wrapped.(*Wrapper)\n\tif !ok {\n\t\treturn fmt.Errorf(\"cannot unwrap %T\", wrapped)\n\t}\n\n\terr := dsd.LoadAsFormat(wrapper.Data, wrapper.Format, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to unwrap %T: %w\", r, err)\n\t}\n\n\tr.SetKey(wrapped.Key())\n\tr.SetMeta(wrapped.Meta())\n\n\treturn nil\n}\n\n// GetAccessor returns an accessor for this record, if available.\nfunc (w *Wrapper) GetAccessor(self Record) accessor.Accessor {\n\tif w.Format == dsd.JSON && len(w.Data) > 0 {\n\t\treturn accessor.NewJSONBytesAccessor(&w.Data)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "base/database/record/wrapper_test.go",
    "content": "package record\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/safing/structures/dsd\"\n)\n\nfunc TestWrapper(t *testing.T) {\n\tt.Parallel()\n\n\t// check model interface compliance\n\tvar m Record\n\tw := &Wrapper{}\n\tm = w\n\t_ = m\n\n\t// create test data\n\ttestData := []byte(`{\"a\": \"b\"}`)\n\tencodedTestData := []byte(`J{\"a\": \"b\"}`)\n\n\t// test wrapper\n\twrapper, err := NewWrapper(\"test:a\", &Meta{}, dsd.JSON, testData)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif wrapper.Format != dsd.JSON {\n\t\tt.Error(\"format mismatch\")\n\t}\n\tif !bytes.Equal(testData, wrapper.Data) {\n\t\tt.Error(\"data mismatch\")\n\t}\n\n\tencoded, err := wrapper.Marshal(wrapper, dsd.JSON)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !bytes.Equal(encodedTestData, encoded) {\n\t\tt.Error(\"marshal mismatch\")\n\t}\n\n\twrapper.SetMeta(&Meta{})\n\twrapper.meta.Update()\n\traw, err := wrapper.MarshalRecord(wrapper)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\twrapper2, err := NewRawWrapper(\"test\", \"a\", raw)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !bytes.Equal(testData, wrapper2.Data) {\n\t\tt.Error(\"marshal mismatch\")\n\t}\n}\n"
  },
  {
    "path": "base/database/registry.go",
    "content": "package database\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar (\n\tregistry     = make(map[string]*Database)\n\tregistryLock sync.Mutex\n\n\tnameConstraint = regexp.MustCompile(\"^[A-Za-z0-9_-]{3,}$\")\n)\n\n// Register registers a new database.\n// If the database is already registered, only\n// the description and the primary API will be\n// updated and the effective object will be returned.\nfunc Register(db *Database) (*Database, error) {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\tregisteredDB, ok := registry[db.Name]\n\n\tif ok {\n\t\t// update database\n\t\tif registeredDB.Description != db.Description {\n\t\t\tregisteredDB.Description = db.Description\n\t\t}\n\t\tif registeredDB.ShadowDelete != db.ShadowDelete {\n\t\t\tregisteredDB.ShadowDelete = db.ShadowDelete\n\t\t}\n\t} else {\n\t\t// register new database\n\t\tif !nameConstraint.MatchString(db.Name) {\n\t\t\treturn nil, errors.New(\"database name must only contain alphanumeric and `_-` characters and must be at least 3 characters long\")\n\t\t}\n\n\t\tnow := time.Now().Round(time.Second)\n\t\tdb.Registered = now\n\t\tdb.LastUpdated = now\n\t\tdb.LastLoaded = time.Time{}\n\n\t\tregistry[db.Name] = db\n\t}\n\n\tif ok {\n\t\treturn registeredDB, nil\n\t}\n\treturn nil, nil\n}\n\nfunc getDatabase(name string) (*Database, error) {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\tregisteredDB, ok := registry[name]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(`database \"%s\" not registered`, name)\n\t}\n\tregisteredDB.Loaded()\n\n\treturn registeredDB, nil\n}\n"
  },
  {
    "path": "base/database/storage/badger/badger.go",
    "content": "package badger\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/dgraph-io/badger\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// Badger database made pluggable for portbase.\ntype Badger struct {\n\tname string\n\tdb   *badger.DB\n}\n\nfunc init() {\n\t_ = storage.Register(\"badger\", NewBadger)\n}\n\n// NewBadger opens/creates a badger database.\nfunc NewBadger(name, location string) (storage.Interface, error) {\n\topts := badger.DefaultOptions(location)\n\n\tdb, err := badger.Open(opts)\n\tif errors.Is(err, badger.ErrTruncateNeeded) {\n\t\t// clean up after crash\n\t\tlog.Warningf(\"database/storage: truncating corrupted value log of badger database %s: this may cause data loss\", name)\n\t\topts.Truncate = true\n\t\tdb, err = badger.Open(opts)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Badger{\n\t\tname: name,\n\t\tdb:   db,\n\t}, nil\n}\n\n// Get returns a database record.\nfunc (b *Badger) Get(key string) (record.Record, error) {\n\tvar item *badger.Item\n\n\terr := b.db.View(func(txn *badger.Txn) error {\n\t\tvar err error\n\t\titem, err = txn.Get([]byte(key))\n\t\tif err != nil {\n\t\t\tif errors.Is(err, badger.ErrKeyNotFound) {\n\t\t\t\treturn storage.ErrNotFound\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// return err if deleted or expired\n\tif item.IsDeletedOrExpired() {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\tdata, err := item.ValueCopy(nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm, err := record.NewRawWrapper(b.name, string(item.Key()), data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// GetMeta returns the metadata of a database record.\nfunc (b *Badger) GetMeta(key string) (*record.Meta, error) {\n\t// TODO: Replace with more performant variant.\n\n\tr, err := b.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r.Meta(), nil\n}\n\n// Put stores a record in the database.\nfunc (b *Badger) Put(r record.Record) (record.Record, error) {\n\tdata, err := r.MarshalRecord(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = b.db.Update(func(txn *badger.Txn) error {\n\t\treturn txn.Set([]byte(r.DatabaseKey()), data)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn r, nil\n}\n\n// Delete deletes a record from the database.\nfunc (b *Badger) Delete(key string) error {\n\treturn b.db.Update(func(txn *badger.Txn) error {\n\t\terr := txn.Delete([]byte(key))\n\t\tif err != nil && !errors.Is(err, badger.ErrKeyNotFound) {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (b *Badger) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\tqueryIter := iterator.New()\n\n\tgo b.queryExecutor(queryIter, q, local, internal)\n\treturn queryIter, nil\n}\n\n//nolint:gocognit\nfunc (b *Badger) queryExecutor(queryIter *iterator.Iterator, q *query.Query, local, internal bool) {\n\terr := b.db.View(func(txn *badger.Txn) error {\n\t\tit := txn.NewIterator(badger.DefaultIteratorOptions)\n\t\tdefer it.Close()\n\t\tprefix := []byte(q.DatabaseKeyPrefix())\n\t\tfor it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {\n\t\t\titem := it.Item()\n\n\t\t\tvar data []byte\n\t\t\terr := item.Value(func(val []byte) error {\n\t\t\t\tdata = val\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tr, err := record.NewRawWrapper(b.name, string(item.Key()), data)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif !r.Meta().CheckValidity() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif !r.Meta().CheckPermission(local, internal) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif q.MatchesRecord(r) {\n\t\t\t\tcopiedData, err := item.ValueCopy(nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tnewWrapper, err := record.NewRawWrapper(b.name, r.DatabaseKey(), copiedData)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tselect {\n\t\t\t\tcase <-queryIter.Done:\n\t\t\t\t\treturn nil\n\t\t\t\tcase queryIter.Next <- newWrapper:\n\t\t\t\tdefault:\n\t\t\t\t\tselect {\n\t\t\t\t\tcase queryIter.Next <- newWrapper:\n\t\t\t\t\tcase <-queryIter.Done:\n\t\t\t\t\t\treturn nil\n\t\t\t\t\tcase <-time.After(1 * time.Minute):\n\t\t\t\t\t\treturn errors.New(\"query timeout\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\treturn nil\n\t})\n\n\tqueryIter.Finish(err)\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (b *Badger) ReadOnly() bool {\n\treturn false\n}\n\n// Injected returns whether the database is injected.\nfunc (b *Badger) Injected() bool {\n\treturn false\n}\n\n// Maintain runs a light maintenance operation on the database.\nfunc (b *Badger) Maintain(_ context.Context) error {\n\t_ = b.db.RunValueLogGC(0.7)\n\treturn nil\n}\n\n// MaintainThorough runs a thorough maintenance operation on the database.\nfunc (b *Badger) MaintainThorough(_ context.Context) (err error) {\n\tfor err == nil {\n\t\terr = b.db.RunValueLogGC(0.7)\n\t}\n\treturn nil\n}\n\n// MaintainRecordStates maintains records states in the database.\nfunc (b *Badger) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error {\n\t// TODO: implement MaintainRecordStates\n\treturn nil\n}\n\n// Shutdown shuts down the database.\nfunc (b *Badger) Shutdown() error {\n\treturn b.db.Close()\n}\n"
  },
  {
    "path": "base/database/storage/badger/badger_test.go",
    "content": "package badger\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"reflect\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\nvar (\n\t// Compile time interface checks.\n\t_ storage.Interface  = &Badger{}\n\t_ storage.Maintainer = &Badger{}\n)\n\ntype TestRecord struct { //nolint:maligned\n\trecord.Base\n\tsync.Mutex\n\tS    string\n\tI    int\n\tI8   int8\n\tI16  int16\n\tI32  int32\n\tI64  int64\n\tUI   uint\n\tUI8  uint8\n\tUI16 uint16\n\tUI32 uint32\n\tUI64 uint64\n\tF32  float32\n\tF64  float64\n\tB    bool\n}\n\nfunc TestBadger(t *testing.T) {\n\tt.Parallel()\n\n\ttestDir, err := os.MkdirTemp(\"\", \"testing-\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer func() {\n\t\t_ = os.RemoveAll(testDir) // clean up\n\t}()\n\n\t// start\n\tdb, err := NewBadger(\"test\", testDir)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ta := &TestRecord{\n\t\tS:    \"banana\",\n\t\tI:    42,\n\t\tI8:   42,\n\t\tI16:  42,\n\t\tI32:  42,\n\t\tI64:  42,\n\t\tUI:   42,\n\t\tUI8:  42,\n\t\tUI16: 42,\n\t\tUI32: 42,\n\t\tUI64: 42,\n\t\tF32:  42.42,\n\t\tF64:  42.42,\n\t\tB:    true,\n\t}\n\ta.SetMeta(&record.Meta{})\n\ta.Meta().Update()\n\ta.SetKey(\"test:A\")\n\n\t// put record\n\t_, err = db.Put(a)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// get and compare\n\tr1, err := db.Get(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ta1 := &TestRecord{}\n\terr = record.Unwrap(r1, a1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif !reflect.DeepEqual(a, a1) {\n\t\tt.Fatalf(\"mismatch, got %v\", a1)\n\t}\n\n\t// test query\n\tq := query.New(\"\").MustBeValid()\n\tit, err := db.Query(q, true, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcnt := 0\n\tfor range it.Next {\n\t\tcnt++\n\t}\n\tif it.Err() != nil {\n\t\tt.Fatal(err)\n\t}\n\tif cnt != 1 {\n\t\tt.Fatalf(\"unexpected query result count: %d\", cnt)\n\t}\n\n\t// delete\n\terr = db.Delete(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// check if its gone\n\t_, err = db.Get(\"A\")\n\tif err == nil {\n\t\tt.Fatal(\"should fail\")\n\t}\n\n\t// maintenance\n\tmaintainer, ok := db.(storage.Maintainer)\n\tif ok {\n\t\terr = maintainer.Maintain(context.TODO())\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\terr = maintainer.MaintainThorough(context.TODO())\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t} else {\n\t\tt.Fatal(\"should implement Maintainer\")\n\t}\n\n\t// shutdown\n\terr = db.Shutdown()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/bbolt/bbolt.go",
    "content": "package bbolt\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"go.etcd.io/bbolt\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\nvar bucketName = []byte{0}\n\n// BBolt database made pluggable for portbase.\ntype BBolt struct {\n\tname string\n\tdb   *bbolt.DB\n}\n\nfunc init() {\n\t_ = storage.Register(\"bbolt\", NewBBolt)\n}\n\n// NewBBolt opens/creates a bbolt database.\nfunc NewBBolt(name, location string) (storage.Interface, error) {\n\t// Create options for bbolt database.\n\tdbFile := filepath.Join(location, \"db.bbolt\")\n\tdbOptions := &bbolt.Options{\n\t\tTimeout: 1 * time.Second,\n\t}\n\n\t// Open/Create database, retry if there is a timeout.\n\tdb, err := bbolt.Open(dbFile, 0o0600, dbOptions)\n\tfor i := 0; i < 5 && err != nil; i++ {\n\t\t// Try again if there is an error.\n\t\tdb, err = bbolt.Open(dbFile, 0o0600, dbOptions)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create bucket\n\terr = db.Update(func(tx *bbolt.Tx) error {\n\t\t_, err := tx.CreateBucketIfNotExists(bucketName)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &BBolt{\n\t\tname: name,\n\t\tdb:   db,\n\t}, nil\n}\n\n// Get returns a database record.\nfunc (b *BBolt) Get(key string) (record.Record, error) {\n\tvar r record.Record\n\n\terr := b.db.View(func(tx *bbolt.Tx) error {\n\t\t// get value from db\n\t\tvalue := tx.Bucket(bucketName).Get([]byte(key))\n\t\tif value == nil {\n\t\t\treturn storage.ErrNotFound\n\t\t}\n\n\t\t// copy data\n\t\tduplicate := make([]byte, len(value))\n\t\tcopy(duplicate, value)\n\n\t\t// create record\n\t\tvar txErr error\n\t\tr, txErr = record.NewRawWrapper(b.name, key, duplicate)\n\t\tif txErr != nil {\n\t\t\treturn txErr\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn r, nil\n}\n\n// GetMeta returns the metadata of a database record.\nfunc (b *BBolt) GetMeta(key string) (*record.Meta, error) {\n\t// TODO: Replace with more performant variant.\n\n\tr, err := b.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r.Meta(), nil\n}\n\n// Put stores a record in the database.\nfunc (b *BBolt) Put(r record.Record) (record.Record, error) {\n\tdata, err := r.MarshalRecord(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = b.db.Update(func(tx *bbolt.Tx) error {\n\t\ttxErr := tx.Bucket(bucketName).Put([]byte(r.DatabaseKey()), data)\n\t\tif txErr != nil {\n\t\t\treturn txErr\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn r, nil\n}\n\n// PutMany stores many records in the database.\nfunc (b *BBolt) PutMany(shadowDelete bool) (chan<- record.Record, <-chan error) {\n\tbatch := make(chan record.Record, 100)\n\terrs := make(chan error, 1)\n\n\tgo func() {\n\t\terr := b.db.Batch(func(tx *bbolt.Tx) error {\n\t\t\tbucket := tx.Bucket(bucketName)\n\t\t\tfor r := range batch {\n\t\t\t\ttxErr := b.batchPutOrDelete(bucket, shadowDelete, r)\n\t\t\t\tif txErr != nil {\n\t\t\t\t\treturn txErr\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t\terrs <- err\n\t}()\n\n\treturn batch, errs\n}\n\nfunc (b *BBolt) batchPutOrDelete(bucket *bbolt.Bucket, shadowDelete bool, r record.Record) (err error) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tif !shadowDelete && r.Meta().IsDeleted() {\n\t\t// Immediate delete.\n\t\terr = bucket.Delete([]byte(r.DatabaseKey()))\n\t} else {\n\t\t// Put or shadow delete.\n\t\tvar data []byte\n\t\tdata, err = r.MarshalRecord(r)\n\t\tif err == nil {\n\t\t\terr = bucket.Put([]byte(r.DatabaseKey()), data)\n\t\t}\n\t}\n\n\treturn err\n}\n\n// Delete deletes a record from the database.\nfunc (b *BBolt) Delete(key string) error {\n\terr := b.db.Update(func(tx *bbolt.Tx) error {\n\t\ttxErr := tx.Bucket(bucketName).Delete([]byte(key))\n\t\tif txErr != nil {\n\t\t\treturn txErr\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (b *BBolt) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\tqueryIter := iterator.New()\n\n\tgo b.queryExecutor(queryIter, q, local, internal)\n\treturn queryIter, nil\n}\n\nfunc (b *BBolt) queryExecutor(queryIter *iterator.Iterator, q *query.Query, local, internal bool) {\n\tprefix := []byte(q.DatabaseKeyPrefix())\n\terr := b.db.View(func(tx *bbolt.Tx) error {\n\t\t// Create a cursor for iteration.\n\t\tc := tx.Bucket(bucketName).Cursor()\n\n\t\t// Iterate over items in sorted key order. This starts from the\n\t\t// first key/value pair and updates the k/v variables to the\n\t\t// next key/value on each iteration.\n\t\t//\n\t\t// The loop finishes at the end of the cursor when a nil key is returned.\n\t\tfor key, value := c.Seek(prefix); key != nil; key, value = c.Next() {\n\n\t\t\t// if we don't match the prefix anymore, exit\n\t\t\tif !bytes.HasPrefix(key, prefix) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// wrap value\n\t\t\titerWrapper, err := record.NewRawWrapper(b.name, string(key), value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// check validity / access\n\t\t\tif !iterWrapper.Meta().CheckValidity() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif !iterWrapper.Meta().CheckPermission(local, internal) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// check if matches & send\n\t\t\tif q.MatchesRecord(iterWrapper) {\n\t\t\t\t// copy data\n\t\t\t\tduplicate := make([]byte, len(value))\n\t\t\t\tcopy(duplicate, value)\n\n\t\t\t\tnewWrapper, err := record.NewRawWrapper(b.name, iterWrapper.DatabaseKey(), duplicate)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tselect {\n\t\t\t\tcase <-queryIter.Done:\n\t\t\t\t\treturn nil\n\t\t\t\tcase queryIter.Next <- newWrapper:\n\t\t\t\tdefault:\n\t\t\t\t\tselect {\n\t\t\t\t\tcase <-queryIter.Done:\n\t\t\t\t\t\treturn nil\n\t\t\t\t\tcase queryIter.Next <- newWrapper:\n\t\t\t\t\tcase <-time.After(1 * time.Second):\n\t\t\t\t\t\treturn errors.New(\"query timeout\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n\tqueryIter.Finish(err)\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (b *BBolt) ReadOnly() bool {\n\treturn false\n}\n\n// Injected returns whether the database is injected.\nfunc (b *BBolt) Injected() bool {\n\treturn false\n}\n\n// MaintainRecordStates maintains records states in the database.\nfunc (b *BBolt) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error { //nolint:gocognit\n\tnow := time.Now().Unix()\n\tpurgeThreshold := purgeDeletedBefore.Unix()\n\n\treturn b.db.Update(func(tx *bbolt.Tx) error {\n\t\tbucket := tx.Bucket(bucketName)\n\t\t// Create a cursor for iteration.\n\t\tc := bucket.Cursor()\n\t\tfor key, value := c.First(); key != nil; key, value = c.Next() {\n\t\t\t// check if context is cancelled\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\tdefault:\n\t\t\t}\n\n\t\t\t// wrap value\n\t\t\twrapper, err := record.NewRawWrapper(b.name, string(key), value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// check if we need to do maintenance\n\t\t\tmeta := wrapper.Meta()\n\t\t\tswitch {\n\t\t\tcase meta.Deleted == 0 && meta.Expires > 0 && meta.Expires < now:\n\t\t\t\tif shadowDelete {\n\t\t\t\t\t// mark as deleted\n\t\t\t\t\tmeta.Deleted = meta.Expires\n\t\t\t\t\tdeleted, err := wrapper.MarshalRecord(wrapper)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\terr = bucket.Put(key, deleted)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\t// Cursor repositioning is required after modifying data.\n\t\t\t\t\t// While the documentation states that this is also required after a\n\t\t\t\t\t// delete, this actually makes the cursor skip a record with the\n\t\t\t\t\t// following c.Next() call of the loop.\n\t\t\t\t\t// Docs/Issue: https://github.com/boltdb/bolt/issues/426#issuecomment-141982984\n\t\t\t\t\tc.Seek(key)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Immediately delete expired entries if shadowDelete is disabled.\n\t\t\t\tfallthrough\n\t\t\tcase meta.Deleted > 0 && (!shadowDelete || meta.Deleted < purgeThreshold):\n\t\t\t\t// delete from storage\n\t\t\t\terr = c.Delete()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n}\n\n// Purge deletes all records that match the given query. It returns the number of successful deletes and an error.\nfunc (b *BBolt) Purge(ctx context.Context, q *query.Query, local, internal, shadowDelete bool) (int, error) { //nolint:gocognit\n\tprefix := []byte(q.DatabaseKeyPrefix())\n\n\tvar cnt int\n\tvar done bool\n\tfor !done {\n\t\terr := b.db.Update(func(tx *bbolt.Tx) error {\n\t\t\t// Create a cursor for iteration.\n\t\t\tbucket := tx.Bucket(bucketName)\n\t\t\tc := bucket.Cursor()\n\t\t\tfor key, value := c.Seek(prefix); key != nil; key, value = c.Next() {\n\t\t\t\t// Check if context has been cancelled.\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\tdone = true\n\t\t\t\t\treturn nil\n\t\t\t\tdefault:\n\t\t\t\t}\n\n\t\t\t\t// Check if we still match the key prefix, if not, exit.\n\t\t\t\tif !bytes.HasPrefix(key, prefix) {\n\t\t\t\t\tdone = true\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\t// Wrap the value in a new wrapper to access the metadata.\n\t\t\t\twrapper, err := record.NewRawWrapper(b.name, string(key), value)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\t// Check if we have permission for this record.\n\t\t\t\tif !wrapper.Meta().CheckPermission(local, internal) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Check if record is already deleted.\n\t\t\t\tif wrapper.Meta().IsDeleted() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Check if the query matches this record.\n\t\t\t\tif !q.MatchesRecord(wrapper) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Delete record.\n\t\t\t\tif shadowDelete {\n\t\t\t\t\t// Shadow delete.\n\t\t\t\t\twrapper.Meta().Delete()\n\t\t\t\t\tdeleted, err := wrapper.MarshalRecord(wrapper)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\terr = bucket.Put(key, deleted)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\t// Cursor repositioning is required after modifying data.\n\t\t\t\t\t// While the documentation states that this is also required after a\n\t\t\t\t\t// delete, this actually makes the cursor skip a record with the\n\t\t\t\t\t// following c.Next() call of the loop.\n\t\t\t\t\t// Docs/Issue: https://github.com/boltdb/bolt/issues/426#issuecomment-141982984\n\t\t\t\t\tc.Seek(key)\n\n\t\t\t\t} else {\n\t\t\t\t\t// Immediate delete.\n\t\t\t\t\terr = c.Delete()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Work in batches of 1000 changes in order to enable other operations in between.\n\t\t\t\tcnt++\n\t\t\t\tif cnt%1000 == 0 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tdone = true\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn cnt, err\n\t\t}\n\t}\n\n\treturn cnt, nil\n}\n\n// Shutdown shuts down the database.\nfunc (b *BBolt) Shutdown() error {\n\treturn b.db.Close()\n}\n"
  },
  {
    "path": "base/database/storage/bbolt/bbolt_test.go",
    "content": "package bbolt\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"reflect\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\nvar (\n\t// Compile time interface checks.\n\t_ storage.Interface = &BBolt{}\n\t_ storage.Batcher   = &BBolt{}\n\t_ storage.Purger    = &BBolt{}\n)\n\ntype TestRecord struct { //nolint:maligned\n\trecord.Base\n\tsync.Mutex\n\tS    string\n\tI    int\n\tI8   int8\n\tI16  int16\n\tI32  int32\n\tI64  int64\n\tUI   uint\n\tUI8  uint8\n\tUI16 uint16\n\tUI32 uint32\n\tUI64 uint64\n\tF32  float32\n\tF64  float64\n\tB    bool\n}\n\nfunc TestBBolt(t *testing.T) {\n\tt.Parallel()\n\n\ttestDir, err := os.MkdirTemp(\"\", \"testing-\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer func() {\n\t\t_ = os.RemoveAll(testDir) // clean up\n\t}()\n\n\t// start\n\tdb, err := NewBBolt(\"test\", testDir)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ta := &TestRecord{\n\t\tS:    \"banana\",\n\t\tI:    42,\n\t\tI8:   42,\n\t\tI16:  42,\n\t\tI32:  42,\n\t\tI64:  42,\n\t\tUI:   42,\n\t\tUI8:  42,\n\t\tUI16: 42,\n\t\tUI32: 42,\n\t\tUI64: 42,\n\t\tF32:  42.42,\n\t\tF64:  42.42,\n\t\tB:    true,\n\t}\n\ta.SetMeta(&record.Meta{})\n\ta.Meta().Update()\n\ta.SetKey(\"test:A\")\n\n\t// put record\n\t_, err = db.Put(a)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// get and compare\n\tr1, err := db.Get(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ta1 := &TestRecord{}\n\terr = record.Unwrap(r1, a1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif !reflect.DeepEqual(a, a1) {\n\t\tt.Fatalf(\"mismatch, got %v\", a1)\n\t}\n\n\t// setup query test records\n\tqA := &TestRecord{}\n\tqA.SetKey(\"test:path/to/A\")\n\tqA.CreateMeta()\n\tqB := &TestRecord{}\n\tqB.SetKey(\"test:path/to/B\")\n\tqB.CreateMeta()\n\tqC := &TestRecord{}\n\tqC.SetKey(\"test:path/to/C\")\n\tqC.CreateMeta()\n\tqZ := &TestRecord{}\n\tqZ.SetKey(\"test:z\")\n\tqZ.CreateMeta()\n\t// put\n\t_, err = db.Put(qA)\n\tif err == nil {\n\t\t_, err = db.Put(qB)\n\t}\n\tif err == nil {\n\t\t_, err = db.Put(qC)\n\t}\n\tif err == nil {\n\t\t_, err = db.Put(qZ)\n\t}\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// test query\n\tq := query.New(\"test:path/to/\").MustBeValid()\n\tit, err := db.Query(q, true, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcnt := 0\n\tfor range it.Next {\n\t\tcnt++\n\t}\n\tif it.Err() != nil {\n\t\tt.Fatal(it.Err())\n\t}\n\tif cnt != 3 {\n\t\tt.Fatalf(\"unexpected query result count: %d\", cnt)\n\t}\n\n\t// delete\n\terr = db.Delete(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// check if its gone\n\t_, err = db.Get(\"A\")\n\tif err == nil {\n\t\tt.Fatal(\"should fail\")\n\t}\n\n\t// maintenance\n\terr = db.MaintainRecordStates(context.TODO(), time.Now(), true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// maintenance\n\terr = db.MaintainRecordStates(context.TODO(), time.Now(), false)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// purging\n\tpurger, ok := db.(storage.Purger)\n\tif ok {\n\t\tn, err := purger.Purge(context.TODO(), query.New(\"test:path/to/\").MustBeValid(), true, true, false)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif n != 3 {\n\t\t\tt.Fatalf(\"unexpected purge delete count: %d\", n)\n\t\t}\n\t} else {\n\t\tt.Fatal(\"should implement Purger\")\n\t}\n\n\t// test query\n\tq = query.New(\"test\").MustBeValid()\n\tit, err = db.Query(q, true, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcnt = 0\n\tfor range it.Next {\n\t\tcnt++\n\t}\n\tif it.Err() != nil {\n\t\tt.Fatal(it.Err())\n\t}\n\tif cnt != 1 {\n\t\tt.Fatalf(\"unexpected query result count: %d\", cnt)\n\t}\n\n\t// shutdown\n\terr = db.Shutdown()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/errors.go",
    "content": "package storage\n\nimport \"errors\"\n\n// Errors for storages.\nvar (\n\tErrNotFound        = errors.New(\"storage entry not found\")\n\tErrRecordMalformed = errors.New(\"record is malformed\")\n)\n"
  },
  {
    "path": "base/database/storage/fstree/fstree.go",
    "content": "/*\nPackage fstree provides a dead simple file-based database storage backend.\nIt is primarily meant for easy testing or storing big files that can easily be accesses directly, without datastore.\n*/\npackage fstree\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/utils/renameio\"\n)\n\nconst (\n\tdefaultFileMode = os.FileMode(0o0644)\n\tdefaultDirMode  = os.FileMode(0o0755)\n\tonWindows       = runtime.GOOS == \"windows\"\n)\n\n// FSTree database storage.\ntype FSTree struct {\n\tname     string\n\tbasePath string\n}\n\nfunc init() {\n\t_ = storage.Register(\"fstree\", NewFSTree)\n}\n\n// NewFSTree returns a (new) FSTree database.\nfunc NewFSTree(name, location string) (storage.Interface, error) {\n\tbasePath, err := filepath.Abs(location)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fstree: failed to validate path %s: %w\", location, err)\n\t}\n\n\tfile, err := os.Stat(basePath)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\terr = os.MkdirAll(basePath, defaultDirMode)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"fstree: failed to create directory %s: %w\", basePath, err)\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"fstree: failed to stat path %s: %w\", basePath, err)\n\t\t}\n\t} else {\n\t\tif !file.IsDir() {\n\t\t\treturn nil, fmt.Errorf(\"fstree: provided database path (%s) is a file\", basePath)\n\t\t}\n\t}\n\n\treturn &FSTree{\n\t\tname:     name,\n\t\tbasePath: basePath,\n\t}, nil\n}\n\nfunc (fst *FSTree) buildFilePath(key string, checkKeyLength bool) (string, error) {\n\t// check key length\n\tif checkKeyLength && len(key) < 1 {\n\t\treturn \"\", fmt.Errorf(\"fstree: key too short: %s\", key)\n\t}\n\t// build filepath\n\tdstPath := filepath.Join(fst.basePath, key) // Join also calls Clean()\n\tif !strings.HasPrefix(dstPath, fst.basePath) {\n\t\treturn \"\", fmt.Errorf(\"fstree: key integrity check failed, compiled path is %s\", dstPath)\n\t}\n\t// return\n\treturn dstPath, nil\n}\n\n// Get returns a database record.\nfunc (fst *FSTree) Get(key string) (record.Record, error) {\n\tdstPath, err := fst.buildFilePath(key, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata, err := os.ReadFile(dstPath)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, storage.ErrNotFound\n\t\t}\n\t\treturn nil, fmt.Errorf(\"fstree: failed to read file %s: %w\", dstPath, err)\n\t}\n\n\tr, err := record.NewRawWrapper(fst.name, key, data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn r, nil\n}\n\n// GetMeta returns the metadata of a database record.\nfunc (fst *FSTree) GetMeta(key string) (*record.Meta, error) {\n\t// TODO: Replace with more performant variant.\n\n\tr, err := fst.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r.Meta(), nil\n}\n\n// Put stores a record in the database.\nfunc (fst *FSTree) Put(r record.Record) (record.Record, error) {\n\tdstPath, err := fst.buildFilePath(r.DatabaseKey(), true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata, err := r.MarshalRecord(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = writeFile(dstPath, data, defaultFileMode)\n\tif err != nil {\n\t\t// create dir and try again\n\t\terr = os.MkdirAll(filepath.Dir(dstPath), defaultDirMode)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"fstree: failed to create directory %s: %w\", filepath.Dir(dstPath), err)\n\t\t}\n\t\terr = writeFile(dstPath, data, defaultFileMode)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"fstree: could not write file %s: %w\", dstPath, err)\n\t\t}\n\t}\n\n\treturn r, nil\n}\n\n// Delete deletes a record from the database.\nfunc (fst *FSTree) Delete(key string) error {\n\tdstPath, err := fst.buildFilePath(key, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// remove entry\n\terr = os.Remove(dstPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fstree: could not delete %s: %w\", dstPath, err)\n\t}\n\n\treturn nil\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (fst *FSTree) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\twalkPrefix, err := fst.buildFilePath(q.DatabaseKeyPrefix(), false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfileInfo, err := os.Stat(walkPrefix)\n\tvar walkRoot string\n\tswitch {\n\tcase err == nil && fileInfo.IsDir():\n\t\twalkRoot = walkPrefix\n\tcase err == nil:\n\t\twalkRoot = filepath.Dir(walkPrefix)\n\tcase errors.Is(err, fs.ErrNotExist):\n\t\twalkRoot = filepath.Dir(walkPrefix)\n\tdefault: // err != nil\n\t\treturn nil, fmt.Errorf(\"fstree: could not stat query root %s: %w\", walkPrefix, err)\n\t}\n\n\tqueryIter := iterator.New()\n\n\tgo fst.queryExecutor(walkRoot, queryIter, q, local, internal)\n\treturn queryIter, nil\n}\n\nfunc (fst *FSTree) queryExecutor(walkRoot string, queryIter *iterator.Iterator, q *query.Query, local, internal bool) {\n\terr := filepath.Walk(walkRoot, func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"fstree: error in walking fs: %w\", err)\n\t\t}\n\n\t\tif info.IsDir() {\n\t\t\t// skip dir if not in scope\n\t\t\tif !strings.HasPrefix(path, fst.basePath) {\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\t\t\t// continue\n\t\t\treturn nil\n\t\t}\n\n\t\t// still in scope?\n\t\tif !strings.HasPrefix(path, fst.basePath) {\n\t\t\treturn nil\n\t\t}\n\n\t\t// read file\n\t\tdata, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"fstree: failed to read file %s: %w\", path, err)\n\t\t}\n\n\t\t// parse\n\t\tkey, err := filepath.Rel(fst.basePath, path)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"fstree: failed to extract key from filepath %s: %w\", path, err)\n\t\t}\n\t\tr, err := record.NewRawWrapper(fst.name, key, data)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"fstree: failed to load file %s: %w\", path, err)\n\t\t}\n\n\t\tif !r.Meta().CheckValidity() {\n\t\t\t// record is not valid\n\t\t\treturn nil\n\t\t}\n\n\t\tif !r.Meta().CheckPermission(local, internal) {\n\t\t\t// no permission to access\n\t\t\treturn nil\n\t\t}\n\n\t\t// check if matches, then send\n\t\tif q.MatchesRecord(r) {\n\t\t\tselect {\n\t\t\tcase queryIter.Next <- r:\n\t\t\tcase <-queryIter.Done:\n\t\t\tcase <-time.After(1 * time.Second):\n\t\t\t\treturn errors.New(\"fstree: query buffer full, timeout\")\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tqueryIter.Finish(err)\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (fst *FSTree) ReadOnly() bool {\n\treturn false\n}\n\n// Injected returns whether the database is injected.\nfunc (fst *FSTree) Injected() bool {\n\treturn false\n}\n\n// MaintainRecordStates maintains records states in the database.\nfunc (fst *FSTree) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error {\n\t// TODO: implement MaintainRecordStates\n\treturn nil\n}\n\n// Shutdown shuts down the database.\nfunc (fst *FSTree) Shutdown() error {\n\treturn nil\n}\n\n// writeFile mirrors os.WriteFile, replacing an existing file with the same\n// name atomically. This is not atomic on Windows, but still an improvement.\n// TODO: Replace with github.com/google/renamio.WriteFile as soon as it is fixed on Windows.\n// TODO: This has become a wont-fix. Explore other options.\n// This function is forked from https://github.com/google/renameio/blob/a368f9987532a68a3d676566141654a81aa8100b/writefile.go.\nfunc writeFile(filename string, data []byte, perm os.FileMode) error {\n\tt, err := renameio.TempFile(\"\", filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer t.Cleanup() //nolint:errcheck\n\n\t// Set permissions before writing data, in case the data is sensitive.\n\t// TODO(vladimir): to set permissions on windows we need the full path of the file.\n\terr = t.Chmod(perm)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := t.Write(data); err != nil {\n\t\treturn err\n\t}\n\n\treturn t.CloseAtomicallyReplace()\n}\n"
  },
  {
    "path": "base/database/storage/fstree/fstree_test.go",
    "content": "package fstree\n\nimport \"github.com/safing/portmaster/base/database/storage\"\n\n// Compile time interface checks.\nvar _ storage.Interface = &FSTree{}\n"
  },
  {
    "path": "base/database/storage/hashmap/map.go",
    "content": "package hashmap\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\n// HashMap storage.\ntype HashMap struct {\n\tname   string\n\tdb     map[string]record.Record\n\tdbLock sync.RWMutex\n}\n\nfunc init() {\n\t_ = storage.Register(\"hashmap\", NewHashMap)\n}\n\n// NewHashMap creates a hashmap database.\nfunc NewHashMap(name, location string) (storage.Interface, error) {\n\treturn &HashMap{\n\t\tname: name,\n\t\tdb:   make(map[string]record.Record),\n\t}, nil\n}\n\n// Get returns a database record.\nfunc (hm *HashMap) Get(key string) (record.Record, error) {\n\thm.dbLock.RLock()\n\tdefer hm.dbLock.RUnlock()\n\n\tr, ok := hm.db[key]\n\tif !ok {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\treturn r, nil\n}\n\n// GetMeta returns the metadata of a database record.\nfunc (hm *HashMap) GetMeta(key string) (*record.Meta, error) {\n\t// TODO: Replace with more performant variant.\n\n\tr, err := hm.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r.Meta(), nil\n}\n\n// Put stores a record in the database.\nfunc (hm *HashMap) Put(r record.Record) (record.Record, error) {\n\thm.dbLock.Lock()\n\tdefer hm.dbLock.Unlock()\n\n\thm.db[r.DatabaseKey()] = r\n\treturn r, nil\n}\n\n// PutMany stores many records in the database.\nfunc (hm *HashMap) PutMany(shadowDelete bool) (chan<- record.Record, <-chan error) {\n\thm.dbLock.Lock()\n\tdefer hm.dbLock.Unlock()\n\t// we could lock for every record, but we want to have the same behaviour\n\t// as the other storage backends, especially for testing.\n\n\tbatch := make(chan record.Record, 100)\n\terrs := make(chan error, 1)\n\n\t// start handler\n\tgo func() {\n\t\tfor r := range batch {\n\t\t\thm.batchPutOrDelete(shadowDelete, r)\n\t\t}\n\t\terrs <- nil\n\t}()\n\n\treturn batch, errs\n}\n\nfunc (hm *HashMap) batchPutOrDelete(shadowDelete bool, r record.Record) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\thm.dbLock.Lock()\n\tdefer hm.dbLock.Unlock()\n\n\tif !shadowDelete && r.Meta().IsDeleted() {\n\t\tdelete(hm.db, r.DatabaseKey())\n\t} else {\n\t\thm.db[r.DatabaseKey()] = r\n\t}\n}\n\n// Delete deletes a record from the database.\nfunc (hm *HashMap) Delete(key string) error {\n\thm.dbLock.Lock()\n\tdefer hm.dbLock.Unlock()\n\n\tdelete(hm.db, key)\n\treturn nil\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (hm *HashMap) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\tqueryIter := iterator.New()\n\n\tgo hm.queryExecutor(queryIter, q, local, internal)\n\treturn queryIter, nil\n}\n\nfunc (hm *HashMap) queryExecutor(queryIter *iterator.Iterator, q *query.Query, local, internal bool) {\n\thm.dbLock.RLock()\n\tdefer hm.dbLock.RUnlock()\n\n\tvar err error\n\nmapLoop:\n\tfor key, record := range hm.db {\n\t\trecord.Lock()\n\t\tif !q.MatchesKey(key) ||\n\t\t\t!q.MatchesRecord(record) ||\n\t\t\t!record.Meta().CheckValidity() ||\n\t\t\t!record.Meta().CheckPermission(local, internal) {\n\n\t\t\trecord.Unlock()\n\t\t\tcontinue\n\t\t}\n\t\trecord.Unlock()\n\n\t\tselect {\n\t\tcase <-queryIter.Done:\n\t\t\tbreak mapLoop\n\t\tcase queryIter.Next <- record:\n\t\tdefault:\n\t\t\tselect {\n\t\t\tcase <-queryIter.Done:\n\t\t\t\tbreak mapLoop\n\t\t\tcase queryIter.Next <- record:\n\t\t\tcase <-time.After(1 * time.Second):\n\t\t\t\terr = errors.New(\"query timeout\")\n\t\t\t\tbreak mapLoop\n\t\t\t}\n\t\t}\n\n\t}\n\n\tqueryIter.Finish(err)\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (hm *HashMap) ReadOnly() bool {\n\treturn false\n}\n\n// Injected returns whether the database is injected.\nfunc (hm *HashMap) Injected() bool {\n\treturn false\n}\n\n// MaintainRecordStates maintains records states in the database.\nfunc (hm *HashMap) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error {\n\thm.dbLock.Lock()\n\tdefer hm.dbLock.Unlock()\n\n\tnow := time.Now().Unix()\n\tpurgeThreshold := purgeDeletedBefore.Unix()\n\n\tfor key, record := range hm.db {\n\t\t// check if context is cancelled\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\n\t\tmeta := record.Meta()\n\t\tswitch {\n\t\tcase meta.Deleted == 0 && meta.Expires > 0 && meta.Expires < now:\n\t\t\tif shadowDelete {\n\t\t\t\t// mark as deleted\n\t\t\t\trecord.Lock()\n\t\t\t\tmeta.Deleted = meta.Expires\n\t\t\t\trecord.Unlock()\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Immediately delete expired entries if shadowDelete is disabled.\n\t\t\tfallthrough\n\t\tcase meta.Deleted > 0 && (!shadowDelete || meta.Deleted < purgeThreshold):\n\t\t\t// delete from storage\n\t\t\tdelete(hm.db, key)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Shutdown shuts down the database.\nfunc (hm *HashMap) Shutdown() error {\n\treturn nil\n}\n"
  },
  {
    "path": "base/database/storage/hashmap/map_test.go",
    "content": "package hashmap\n\nimport (\n\t\"reflect\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\nvar (\n\t// Compile time interface checks.\n\t_ storage.Interface = &HashMap{}\n\t_ storage.Batcher   = &HashMap{}\n)\n\ntype TestRecord struct { //nolint:maligned\n\trecord.Base\n\tsync.Mutex\n\tS    string\n\tI    int\n\tI8   int8\n\tI16  int16\n\tI32  int32\n\tI64  int64\n\tUI   uint\n\tUI8  uint8\n\tUI16 uint16\n\tUI32 uint32\n\tUI64 uint64\n\tF32  float32\n\tF64  float64\n\tB    bool\n}\n\nfunc TestHashMap(t *testing.T) {\n\tt.Parallel()\n\n\t// start\n\tdb, err := NewHashMap(\"test\", \"\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ta := &TestRecord{\n\t\tS:    \"banana\",\n\t\tI:    42,\n\t\tI8:   42,\n\t\tI16:  42,\n\t\tI32:  42,\n\t\tI64:  42,\n\t\tUI:   42,\n\t\tUI8:  42,\n\t\tUI16: 42,\n\t\tUI32: 42,\n\t\tUI64: 42,\n\t\tF32:  42.42,\n\t\tF64:  42.42,\n\t\tB:    true,\n\t}\n\ta.SetMeta(&record.Meta{})\n\ta.Meta().Update()\n\ta.SetKey(\"test:A\")\n\n\t// put record\n\t_, err = db.Put(a)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// get and compare\n\ta1, err := db.Get(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif !reflect.DeepEqual(a, a1) {\n\t\tt.Fatalf(\"mismatch, got %v\", a1)\n\t}\n\n\t// setup query test records\n\tqA := &TestRecord{}\n\tqA.SetKey(\"test:path/to/A\")\n\tqA.CreateMeta()\n\tqB := &TestRecord{}\n\tqB.SetKey(\"test:path/to/B\")\n\tqB.CreateMeta()\n\tqC := &TestRecord{}\n\tqC.SetKey(\"test:path/to/C\")\n\tqC.CreateMeta()\n\tqZ := &TestRecord{}\n\tqZ.SetKey(\"test:z\")\n\tqZ.CreateMeta()\n\t// put\n\t_, err = db.Put(qA)\n\tif err == nil {\n\t\t_, err = db.Put(qB)\n\t}\n\tif err == nil {\n\t\t_, err = db.Put(qC)\n\t}\n\tif err == nil {\n\t\t_, err = db.Put(qZ)\n\t}\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// test query\n\tq := query.New(\"test:path/to/\").MustBeValid()\n\tit, err := db.Query(q, true, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcnt := 0\n\tfor range it.Next {\n\t\tcnt++\n\t}\n\tif it.Err() != nil {\n\t\tt.Fatal(it.Err())\n\t}\n\tif cnt != 3 {\n\t\tt.Fatalf(\"unexpected query result count: %d\", cnt)\n\t}\n\n\t// delete\n\terr = db.Delete(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// check if its gone\n\t_, err = db.Get(\"A\")\n\tif err == nil {\n\t\tt.Fatal(\"should fail\")\n\t}\n\n\t// shutdown\n\terr = db.Shutdown()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/injectbase.go",
    "content": "package storage\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// ErrNotImplemented is returned when a function is not implemented by a storage.\nvar ErrNotImplemented = errors.New(\"not implemented\")\n\n// InjectBase is a dummy base structure to reduce boilerplate code for injected storage interfaces.\ntype InjectBase struct{}\n\n// Compile time interface check.\nvar _ Interface = &InjectBase{}\n\n// Get returns a database record.\nfunc (i *InjectBase) Get(key string) (record.Record, error) {\n\treturn nil, ErrNotImplemented\n}\n\n// Put stores a record in the database.\nfunc (i *InjectBase) Put(m record.Record) (record.Record, error) {\n\treturn nil, ErrNotImplemented\n}\n\n// Delete deletes a record from the database.\nfunc (i *InjectBase) Delete(key string) error {\n\treturn ErrNotImplemented\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (i *InjectBase) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\treturn nil, ErrNotImplemented\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (i *InjectBase) ReadOnly() bool {\n\treturn true\n}\n\n// Injected returns whether the database is injected.\nfunc (i *InjectBase) Injected() bool {\n\treturn true\n}\n\n// MaintainRecordStates maintains records states in the database.\nfunc (i *InjectBase) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error {\n\treturn nil\n}\n\n// Shutdown shuts down the database.\nfunc (i *InjectBase) Shutdown() error {\n\treturn nil\n}\n"
  },
  {
    "path": "base/database/storage/interface.go",
    "content": "package storage\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// Interface defines the database storage API.\ntype Interface interface {\n\t// Primary Interface\n\tGet(key string) (record.Record, error)\n\tPut(m record.Record) (record.Record, error)\n\tDelete(key string) error\n\tQuery(q *query.Query, local, internal bool) (*iterator.Iterator, error)\n\n\t// Information and Control\n\tReadOnly() bool\n\tInjected() bool\n\tShutdown() error\n\n\t// Mandatory Record Maintenance\n\tMaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error\n}\n\n// MetaHandler defines the database storage API for backends that support optimized fetching of only the metadata.\ntype MetaHandler interface {\n\tGetMeta(key string) (*record.Meta, error)\n}\n\n// Maintainer defines the database storage API for backends that require regular maintenance.\ntype Maintainer interface {\n\tMaintain(ctx context.Context) error\n\tMaintainThorough(ctx context.Context) error\n}\n\n// Batcher defines the database storage API for backends that support batch operations.\ntype Batcher interface {\n\tPutMany(shadowDelete bool) (batch chan<- record.Record, errs <-chan error)\n}\n\n// Purger defines the database storage API for backends that support the purge operation.\ntype Purger interface {\n\tPurge(ctx context.Context, q *query.Query, local, internal, shadowDelete bool) (int, error)\n}\n\n// PurgeOlderThan defines the database storage API for backends that support the PurgeOlderThan operation.\ntype PurgeOlderThan interface {\n\tPurgeOlderThan(ctx context.Context, prefix string, purgeBefore time.Time, local, internal, shadowDelete bool) (int, error)\n}\n"
  },
  {
    "path": "base/database/storage/sinkhole/sinkhole.go",
    "content": "package sinkhole\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\n// Sinkhole is a dummy storage.\ntype Sinkhole struct {\n\tname string\n}\n\nvar (\n\t// Compile time interface checks.\n\t_ storage.Interface  = &Sinkhole{}\n\t_ storage.Maintainer = &Sinkhole{}\n\t_ storage.Batcher    = &Sinkhole{}\n)\n\nfunc init() {\n\t_ = storage.Register(\"sinkhole\", NewSinkhole)\n}\n\n// NewSinkhole creates a dummy database.\nfunc NewSinkhole(name, location string) (storage.Interface, error) {\n\treturn &Sinkhole{\n\t\tname: name,\n\t}, nil\n}\n\n// Exists returns whether an entry with the given key exists.\nfunc (s *Sinkhole) Exists(key string) (bool, error) {\n\treturn false, nil\n}\n\n// Get returns a database record.\nfunc (s *Sinkhole) Get(key string) (record.Record, error) {\n\treturn nil, storage.ErrNotFound\n}\n\n// GetMeta returns the metadata of a database record.\nfunc (s *Sinkhole) GetMeta(key string) (*record.Meta, error) {\n\treturn nil, storage.ErrNotFound\n}\n\n// Put stores a record in the database.\nfunc (s *Sinkhole) Put(r record.Record) (record.Record, error) {\n\treturn r, nil\n}\n\n// PutMany stores many records in the database.\nfunc (s *Sinkhole) PutMany(shadowDelete bool) (chan<- record.Record, <-chan error) {\n\tbatch := make(chan record.Record, 100)\n\terrs := make(chan error, 1)\n\n\t// start handler\n\tgo func() {\n\t\tfor range batch {\n\t\t\t// discard everything\n\t\t}\n\t\terrs <- nil\n\t}()\n\n\treturn batch, errs\n}\n\n// Delete deletes a record from the database.\nfunc (s *Sinkhole) Delete(key string) error {\n\treturn nil\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (s *Sinkhole) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\treturn nil, errors.New(\"query not implemented by sinkhole\")\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (s *Sinkhole) ReadOnly() bool {\n\treturn false\n}\n\n// Injected returns whether the database is injected.\nfunc (s *Sinkhole) Injected() bool {\n\treturn false\n}\n\n// Maintain runs a light maintenance operation on the database.\nfunc (s *Sinkhole) Maintain(ctx context.Context) error {\n\treturn nil\n}\n\n// MaintainThorough runs a thorough maintenance operation on the database.\nfunc (s *Sinkhole) MaintainThorough(ctx context.Context) error {\n\treturn nil\n}\n\n// MaintainRecordStates maintains records states in the database.\nfunc (s *Sinkhole) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error {\n\treturn nil\n}\n\n// Shutdown shuts down the database.\nfunc (s *Sinkhole) Shutdown() error {\n\treturn nil\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/bobgen.yaml",
    "content": "sqlite:\n  dsn: \"testdata/schema.db\"\n  except:\n    migrations:\n\nno_factory: true\n"
  },
  {
    "path": "base/database/storage/sqlite/dberrors/bob_errors.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage dberrors\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\tsqliteDriver \"modernc.org/sqlite\"\n)\n\n// ErrUniqueConstraint captures all unique constraint errors by explicitly leaving `s` empty.\nvar ErrUniqueConstraint = &UniqueConstraintError{s: \"\"}\n\ntype UniqueConstraintError struct {\n\t// schema is the schema where the unique constraint is defined.\n\tschema string\n\t// table is the name of the table where the unique constraint is defined.\n\ttable string\n\t// columns are the columns constituting the unique constraint.\n\tcolumns []string\n\t// s is a string uniquely identifying the constraint in the raw error message returned from the database.\n\ts string\n}\n\nfunc (e *UniqueConstraintError) Error() string {\n\treturn e.s\n}\n\nfunc (e *UniqueConstraintError) Is(target error) bool {\n\tvar err *sqliteDriver.Error\n\tif !errors.As(target, &err) {\n\t\treturn false\n\t}\n\n\t// 1555 is for Primary Key Constraint\n\t// 2067 is for Unique Constraint\n\tif err.Code() != 1555 && err.Code() != 2067 {\n\t\treturn false\n\t}\n\n\tfor _, col := range e.columns {\n\t\tif !strings.Contains(err.Error(), fmt.Sprintf(\"%s.%s\", e.table, col)) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/dberrors/bob_main.bob_test.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage dberrors\n\nimport \"github.com/stephenafamo/bob\"\n\n// Set the testDB to enable tests that use the database\nvar testDB bob.Transactor[bob.Tx]\n"
  },
  {
    "path": "base/database/storage/sqlite/dberrors/records.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage dberrors\n\nvar RecordErrors = &recordErrors{\n\tErrUniquePkMainRecords: &UniqueConstraintError{\n\t\tschema:  \"\",\n\t\ttable:   \"records\",\n\t\tcolumns: []string{\"key\"},\n\t\ts:       \"pk_main_records\",\n\t},\n}\n\ntype recordErrors struct {\n\tErrUniquePkMainRecords *UniqueConstraintError\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/dbinfo/bob_types.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage dbinfo\n\nimport \"github.com/aarondl/opt/null\"\n\ntype Table[Cols columns, Idxs indexes, FKs foreignKeys, U uniques, C checks] struct {\n\tSchema      string\n\tName        string\n\tColumns     Cols\n\tIndexes     Idxs\n\tPrimaryKey  *constraint\n\tForeignKeys FKs\n\tUniques     U\n\tChecks      C\n\tComment     string\n}\n\ntype columns interface {\n\tAsSlice() []column\n}\n\ntype column struct {\n\tName      string\n\tDBType    string\n\tDefault   string\n\tComment   string\n\tNullable  bool\n\tGenerated bool\n\tAutoIncr  bool\n}\n\ntype indexes interface {\n\tAsSlice() []index\n}\n\ntype index struct {\n\tType    string\n\tName    string\n\tColumns []indexColumn\n\tUnique  bool\n\tComment string\n\tPartial bool\n}\n\ntype indexColumn struct {\n\tName         string\n\tDesc         null.Val[bool]\n\tIsExpression bool\n}\n\ntype constraint struct {\n\tName    string\n\tColumns []string\n\tComment string\n}\n\ntype foreignKeys interface {\n\tAsSlice() []foreignKey\n}\n\ntype foreignKey struct {\n\tconstraint\n\tForeignTable   string\n\tForeignColumns []string\n}\n\ntype uniques interface {\n\tAsSlice() []constraint\n}\n\ntype checks interface {\n\tAsSlice() []check\n}\n\ntype check struct {\n\tconstraint\n\tExpression string\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/dbinfo/records.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage dbinfo\n\nimport \"github.com/aarondl/opt/null\"\n\nvar Records = Table[\n\trecordColumns,\n\trecordIndexes,\n\trecordForeignKeys,\n\trecordUniques,\n\trecordChecks,\n]{\n\tSchema: \"\",\n\tName:   \"records\",\n\tColumns: recordColumns{\n\t\tKey: column{\n\t\t\tName:      \"key\",\n\t\t\tDBType:    \"TEXT\",\n\t\t\tDefault:   \"\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  false,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tFormat: column{\n\t\t\tName:      \"format\",\n\t\t\tDBType:    \"SMALLINT\",\n\t\t\tDefault:   \"NULL\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  true,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tValue: column{\n\t\t\tName:      \"value\",\n\t\t\tDBType:    \"BLOB\",\n\t\t\tDefault:   \"NULL\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  true,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tCreated: column{\n\t\t\tName:      \"created\",\n\t\t\tDBType:    \"BIGINT\",\n\t\t\tDefault:   \"\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  false,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tModified: column{\n\t\t\tName:      \"modified\",\n\t\t\tDBType:    \"BIGINT\",\n\t\t\tDefault:   \"\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  false,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tExpires: column{\n\t\t\tName:      \"expires\",\n\t\t\tDBType:    \"BIGINT\",\n\t\t\tDefault:   \"0\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  false,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tDeleted: column{\n\t\t\tName:      \"deleted\",\n\t\t\tDBType:    \"BIGINT\",\n\t\t\tDefault:   \"0\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  false,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tSecret: column{\n\t\t\tName:      \"secret\",\n\t\t\tDBType:    \"BOOLEAN\",\n\t\t\tDefault:   \"FALSE\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  false,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t\tCrownjewel: column{\n\t\t\tName:      \"crownjewel\",\n\t\t\tDBType:    \"BOOLEAN\",\n\t\t\tDefault:   \"FALSE\",\n\t\t\tComment:   \"\",\n\t\t\tNullable:  false,\n\t\t\tGenerated: false,\n\t\t\tAutoIncr:  false,\n\t\t},\n\t},\n\tIndexes: recordIndexes{\n\t\tSqliteAutoindexRecords1: index{\n\t\t\tType: \"pk\",\n\t\t\tName: \"sqlite_autoindex_records_1\",\n\t\t\tColumns: []indexColumn{\n\t\t\t\t{\n\t\t\t\t\tName:         \"key\",\n\t\t\t\t\tDesc:         null.FromCond(false, true),\n\t\t\t\t\tIsExpression: false,\n\t\t\t\t},\n\t\t\t},\n\t\t\tUnique:  true,\n\t\t\tComment: \"\",\n\t\t\tPartial: false,\n\t\t},\n\t},\n\tPrimaryKey: &constraint{\n\t\tName:    \"pk_main_records\",\n\t\tColumns: []string{\"key\"},\n\t\tComment: \"\",\n\t},\n\n\tComment: \"\",\n}\n\ntype recordColumns struct {\n\tKey        column\n\tFormat     column\n\tValue      column\n\tCreated    column\n\tModified   column\n\tExpires    column\n\tDeleted    column\n\tSecret     column\n\tCrownjewel column\n}\n\nfunc (c recordColumns) AsSlice() []column {\n\treturn []column{\n\t\tc.Key, c.Format, c.Value, c.Created, c.Modified, c.Expires, c.Deleted, c.Secret, c.Crownjewel,\n\t}\n}\n\ntype recordIndexes struct {\n\tSqliteAutoindexRecords1 index\n}\n\nfunc (i recordIndexes) AsSlice() []index {\n\treturn []index{\n\t\ti.SqliteAutoindexRecords1,\n\t}\n}\n\ntype recordForeignKeys struct{}\n\nfunc (f recordForeignKeys) AsSlice() []foreignKey {\n\treturn []foreignKey{}\n}\n\ntype recordUniques struct{}\n\nfunc (u recordUniques) AsSlice() []constraint {\n\treturn []constraint{}\n}\n\ntype recordChecks struct{}\n\nfunc (c recordChecks) AsSlice() []check {\n\treturn []check{}\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/factory/bobfactory_context.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage factory\n\nimport \"context\"\n\ntype contextKey string\n\n// Relationship Contexts for records\nvar recordWithParentsCascadingCtx = newContextual[bool](\"recordWithParentsCascading\")\n\n// Contextual is a convienience wrapper around context.WithValue and context.Value\ntype contextual[V any] struct {\n\tkey contextKey\n}\n\nfunc newContextual[V any](key string) contextual[V] {\n\treturn contextual[V]{key: contextKey(key)}\n}\n\nfunc (k contextual[V]) WithValue(ctx context.Context, val V) context.Context {\n\treturn context.WithValue(ctx, k.key, val)\n}\n\nfunc (k contextual[V]) Value(ctx context.Context) (V, bool) {\n\tv, ok := ctx.Value(k.key).(V)\n\treturn v, ok\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/factory/bobfactory_main.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage factory\n\nimport (\n\t\"context\"\n\n\t\"github.com/aarondl/opt/null\"\n\tmodels \"github.com/safing/portmaster/base/database/storage/sqlite/models\"\n)\n\ntype Factory struct {\n\tbaseRecordMods RecordModSlice\n}\n\nfunc New() *Factory {\n\treturn &Factory{}\n}\n\nfunc (f *Factory) NewRecord(mods ...RecordMod) *RecordTemplate {\n\treturn f.NewRecordWithContext(context.Background(), mods...)\n}\n\nfunc (f *Factory) NewRecordWithContext(ctx context.Context, mods ...RecordMod) *RecordTemplate {\n\to := &RecordTemplate{f: f}\n\n\tif f != nil {\n\t\tf.baseRecordMods.Apply(ctx, o)\n\t}\n\n\tRecordModSlice(mods).Apply(ctx, o)\n\n\treturn o\n}\n\nfunc (f *Factory) FromExistingRecord(m *models.Record) *RecordTemplate {\n\to := &RecordTemplate{f: f, alreadyPersisted: true}\n\n\to.Key = func() string { return m.Key }\n\to.Format = func() null.Val[int64] { return m.Format }\n\to.Value = func() null.Val[[]byte] { return m.Value }\n\to.Created = func() int64 { return m.Created }\n\to.Modified = func() int64 { return m.Modified }\n\to.Expires = func() int64 { return m.Expires }\n\to.Deleted = func() int64 { return m.Deleted }\n\to.Secret = func() bool { return m.Secret }\n\to.Crownjewel = func() bool { return m.Crownjewel }\n\n\treturn o\n}\n\nfunc (f *Factory) ClearBaseRecordMods() {\n\tf.baseRecordMods = nil\n}\n\nfunc (f *Factory) AddBaseRecordMod(mods ...RecordMod) {\n\tf.baseRecordMods = append(f.baseRecordMods, mods...)\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/factory/bobfactory_main.bob_test.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage factory\n\nimport (\n\t\"context\"\n\t\"testing\"\n)\n\nfunc TestCreateRecord(t *testing.T) {\n\tif testDB == nil {\n\t\tt.Skip(\"skipping test, no DSN provided\")\n\t}\n\n\tctx, cancel := context.WithCancel(t.Context())\n\tt.Cleanup(cancel)\n\n\ttx, err := testDB.Begin(ctx)\n\tif err != nil {\n\t\tt.Fatalf(\"Error starting transaction: %v\", err)\n\t}\n\n\tdefer func() {\n\t\tif err := tx.Rollback(ctx); err != nil {\n\t\t\tt.Fatalf(\"Error rolling back transaction: %v\", err)\n\t\t}\n\t}()\n\n\tif _, err := New().NewRecordWithContext(ctx).Create(ctx, tx); err != nil {\n\t\tt.Fatalf(\"Error creating Record: %v\", err)\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/factory/bobfactory_random.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage factory\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jaswdr/faker/v2\"\n)\n\nvar defaultFaker = faker.New()\n\nfunc random___byte(f *faker.Faker, limits ...string) []byte {\n\tif f == nil {\n\t\tf = &defaultFaker\n\t}\n\n\treturn []byte(random_string(f, limits...))\n}\n\nfunc random_bool(f *faker.Faker, limits ...string) bool {\n\tif f == nil {\n\t\tf = &defaultFaker\n\t}\n\n\treturn f.Bool()\n}\n\nfunc random_int64(f *faker.Faker, limits ...string) int64 {\n\tif f == nil {\n\t\tf = &defaultFaker\n\t}\n\n\treturn f.Int64()\n}\n\nfunc random_string(f *faker.Faker, limits ...string) string {\n\tif f == nil {\n\t\tf = &defaultFaker\n\t}\n\n\tval := strings.Join(f.Lorem().Words(f.IntBetween(1, 5)), \" \")\n\tif len(limits) == 0 {\n\t\treturn val\n\t}\n\tlimitInt, _ := strconv.Atoi(limits[0])\n\tif limitInt > 0 && limitInt < len(val) {\n\t\tval = val[:limitInt]\n\t}\n\treturn val\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/factory/bobfactory_random.bob_test.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage factory\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stephenafamo/bob\"\n)\n\n// Set the testDB to enable tests that use the database\nvar testDB bob.Transactor[bob.Tx]\n\nfunc TestRandom___byte(t *testing.T) {\n\tt.Parallel()\n\n\tval1 := random___byte(nil)\n\tval2 := random___byte(nil)\n\n\tif bytes.Equal(val1, val2) {\n\t\tt.Fatalf(\"random___byte() returned the same value twice: %v\", val1)\n\t}\n}\n\nfunc TestRandom_int64(t *testing.T) {\n\tt.Parallel()\n\n\tval1 := random_int64(nil)\n\tval2 := random_int64(nil)\n\n\tif val1 == val2 {\n\t\tt.Fatalf(\"random_int64() returned the same value twice: %v\", val1)\n\t}\n}\n\nfunc TestRandom_string(t *testing.T) {\n\tt.Parallel()\n\n\tval1 := random_string(nil)\n\tval2 := random_string(nil)\n\n\tif val1 == val2 {\n\t\tt.Fatalf(\"random_string() returned the same value twice: %v\", val1)\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/factory/records.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage factory\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/aarondl/opt/null\"\n\t\"github.com/aarondl/opt/omit\"\n\t\"github.com/aarondl/opt/omitnull\"\n\t\"github.com/jaswdr/faker/v2\"\n\tmodels \"github.com/safing/portmaster/base/database/storage/sqlite/models\"\n\t\"github.com/stephenafamo/bob\"\n)\n\ntype RecordMod interface {\n\tApply(context.Context, *RecordTemplate)\n}\n\ntype RecordModFunc func(context.Context, *RecordTemplate)\n\nfunc (f RecordModFunc) Apply(ctx context.Context, n *RecordTemplate) {\n\tf(ctx, n)\n}\n\ntype RecordModSlice []RecordMod\n\nfunc (mods RecordModSlice) Apply(ctx context.Context, n *RecordTemplate) {\n\tfor _, f := range mods {\n\t\tf.Apply(ctx, n)\n\t}\n}\n\n// RecordTemplate is an object representing the database table.\n// all columns are optional and should be set by mods\ntype RecordTemplate struct {\n\tKey        func() string\n\tFormat     func() null.Val[int64]\n\tValue      func() null.Val[[]byte]\n\tCreated    func() int64\n\tModified   func() int64\n\tExpires    func() int64\n\tDeleted    func() int64\n\tSecret     func() bool\n\tCrownjewel func() bool\n\n\tf *Factory\n\n\talreadyPersisted bool\n}\n\n// Apply mods to the RecordTemplate\nfunc (o *RecordTemplate) Apply(ctx context.Context, mods ...RecordMod) {\n\tfor _, mod := range mods {\n\t\tmod.Apply(ctx, o)\n\t}\n}\n\n// setModelRels creates and sets the relationships on *models.Record\n// according to the relationships in the template. Nothing is inserted into the db\nfunc (t RecordTemplate) setModelRels(o *models.Record) {}\n\n// BuildSetter returns an *models.RecordSetter\n// this does nothing with the relationship templates\nfunc (o RecordTemplate) BuildSetter() *models.RecordSetter {\n\tm := &models.RecordSetter{}\n\n\tif o.Key != nil {\n\t\tval := o.Key()\n\t\tm.Key = omit.From(val)\n\t}\n\tif o.Format != nil {\n\t\tval := o.Format()\n\t\tm.Format = omitnull.FromNull(val)\n\t}\n\tif o.Value != nil {\n\t\tval := o.Value()\n\t\tm.Value = omitnull.FromNull(val)\n\t}\n\tif o.Created != nil {\n\t\tval := o.Created()\n\t\tm.Created = omit.From(val)\n\t}\n\tif o.Modified != nil {\n\t\tval := o.Modified()\n\t\tm.Modified = omit.From(val)\n\t}\n\tif o.Expires != nil {\n\t\tval := o.Expires()\n\t\tm.Expires = omit.From(val)\n\t}\n\tif o.Deleted != nil {\n\t\tval := o.Deleted()\n\t\tm.Deleted = omit.From(val)\n\t}\n\tif o.Secret != nil {\n\t\tval := o.Secret()\n\t\tm.Secret = omit.From(val)\n\t}\n\tif o.Crownjewel != nil {\n\t\tval := o.Crownjewel()\n\t\tm.Crownjewel = omit.From(val)\n\t}\n\n\treturn m\n}\n\n// BuildManySetter returns an []*models.RecordSetter\n// this does nothing with the relationship templates\nfunc (o RecordTemplate) BuildManySetter(number int) []*models.RecordSetter {\n\tm := make([]*models.RecordSetter, number)\n\n\tfor i := range m {\n\t\tm[i] = o.BuildSetter()\n\t}\n\n\treturn m\n}\n\n// Build returns an *models.Record\n// Related objects are also created and placed in the .R field\n// NOTE: Objects are not inserted into the database. Use RecordTemplate.Create\nfunc (o RecordTemplate) Build() *models.Record {\n\tm := &models.Record{}\n\n\tif o.Key != nil {\n\t\tm.Key = o.Key()\n\t}\n\tif o.Format != nil {\n\t\tm.Format = o.Format()\n\t}\n\tif o.Value != nil {\n\t\tm.Value = o.Value()\n\t}\n\tif o.Created != nil {\n\t\tm.Created = o.Created()\n\t}\n\tif o.Modified != nil {\n\t\tm.Modified = o.Modified()\n\t}\n\tif o.Expires != nil {\n\t\tm.Expires = o.Expires()\n\t}\n\tif o.Deleted != nil {\n\t\tm.Deleted = o.Deleted()\n\t}\n\tif o.Secret != nil {\n\t\tm.Secret = o.Secret()\n\t}\n\tif o.Crownjewel != nil {\n\t\tm.Crownjewel = o.Crownjewel()\n\t}\n\n\to.setModelRels(m)\n\n\treturn m\n}\n\n// BuildMany returns an models.RecordSlice\n// Related objects are also created and placed in the .R field\n// NOTE: Objects are not inserted into the database. Use RecordTemplate.CreateMany\nfunc (o RecordTemplate) BuildMany(number int) models.RecordSlice {\n\tm := make(models.RecordSlice, number)\n\n\tfor i := range m {\n\t\tm[i] = o.Build()\n\t}\n\n\treturn m\n}\n\nfunc ensureCreatableRecord(m *models.RecordSetter) {\n\tif !(m.Key.IsValue()) {\n\t\tval := random_string(nil)\n\t\tm.Key = omit.From(val)\n\t}\n\tif !(m.Created.IsValue()) {\n\t\tval := random_int64(nil)\n\t\tm.Created = omit.From(val)\n\t}\n\tif !(m.Modified.IsValue()) {\n\t\tval := random_int64(nil)\n\t\tm.Modified = omit.From(val)\n\t}\n}\n\n// insertOptRels creates and inserts any optional the relationships on *models.Record\n// according to the relationships in the template.\n// any required relationship should have already exist on the model\nfunc (o *RecordTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.Record) error {\n\tvar err error\n\n\treturn err\n}\n\n// Create builds a record and inserts it into the database\n// Relations objects are also inserted and placed in the .R field\nfunc (o *RecordTemplate) Create(ctx context.Context, exec bob.Executor) (*models.Record, error) {\n\tvar err error\n\topt := o.BuildSetter()\n\tensureCreatableRecord(opt)\n\n\tm, err := models.Records.Insert(opt).One(ctx, exec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := o.insertOptRels(ctx, exec, m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, err\n}\n\n// MustCreate builds a record and inserts it into the database\n// Relations objects are also inserted and placed in the .R field\n// panics if an error occurs\nfunc (o *RecordTemplate) MustCreate(ctx context.Context, exec bob.Executor) *models.Record {\n\tm, err := o.Create(ctx, exec)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// CreateOrFail builds a record and inserts it into the database\n// Relations objects are also inserted and placed in the .R field\n// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs\nfunc (o *RecordTemplate) CreateOrFail(ctx context.Context, tb testing.TB, exec bob.Executor) *models.Record {\n\ttb.Helper()\n\tm, err := o.Create(ctx, exec)\n\tif err != nil {\n\t\ttb.Fatal(err)\n\t\treturn nil\n\t}\n\treturn m\n}\n\n// CreateMany builds multiple records and inserts them into the database\n// Relations objects are also inserted and placed in the .R field\nfunc (o RecordTemplate) CreateMany(ctx context.Context, exec bob.Executor, number int) (models.RecordSlice, error) {\n\tvar err error\n\tm := make(models.RecordSlice, number)\n\n\tfor i := range m {\n\t\tm[i], err = o.Create(ctx, exec)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn m, nil\n}\n\n// MustCreateMany builds multiple records and inserts them into the database\n// Relations objects are also inserted and placed in the .R field\n// panics if an error occurs\nfunc (o RecordTemplate) MustCreateMany(ctx context.Context, exec bob.Executor, number int) models.RecordSlice {\n\tm, err := o.CreateMany(ctx, exec, number)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// CreateManyOrFail builds multiple records and inserts them into the database\n// Relations objects are also inserted and placed in the .R field\n// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs\nfunc (o RecordTemplate) CreateManyOrFail(ctx context.Context, tb testing.TB, exec bob.Executor, number int) models.RecordSlice {\n\ttb.Helper()\n\tm, err := o.CreateMany(ctx, exec, number)\n\tif err != nil {\n\t\ttb.Fatal(err)\n\t\treturn nil\n\t}\n\treturn m\n}\n\n// Record has methods that act as mods for the RecordTemplate\nvar RecordMods recordMods\n\ntype recordMods struct{}\n\nfunc (m recordMods) RandomizeAllColumns(f *faker.Faker) RecordMod {\n\treturn RecordModSlice{\n\t\tRecordMods.RandomKey(f),\n\t\tRecordMods.RandomFormat(f),\n\t\tRecordMods.RandomValue(f),\n\t\tRecordMods.RandomCreated(f),\n\t\tRecordMods.RandomModified(f),\n\t\tRecordMods.RandomExpires(f),\n\t\tRecordMods.RandomDeleted(f),\n\t\tRecordMods.RandomSecret(f),\n\t\tRecordMods.RandomCrownjewel(f),\n\t}\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Key(val string) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Key = func() string { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) KeyFunc(f func() string) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Key = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetKey() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Key = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\nfunc (m recordMods) RandomKey(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Key = func() string {\n\t\t\treturn random_string(f)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Format(val null.Val[int64]) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Format = func() null.Val[int64] { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) FormatFunc(f func() null.Val[int64]) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Format = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetFormat() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Format = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\n// The generated value is sometimes null\nfunc (m recordMods) RandomFormat(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Format = func() null.Val[int64] {\n\t\t\tif f == nil {\n\t\t\t\tf = &defaultFaker\n\t\t\t}\n\n\t\t\tval := random_int64(f)\n\t\t\treturn null.From(val)\n\t\t}\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\n// The generated value is never null\nfunc (m recordMods) RandomFormatNotNull(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Format = func() null.Val[int64] {\n\t\t\tif f == nil {\n\t\t\t\tf = &defaultFaker\n\t\t\t}\n\n\t\t\tval := random_int64(f)\n\t\t\treturn null.From(val)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Value(val null.Val[[]byte]) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Value = func() null.Val[[]byte] { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) ValueFunc(f func() null.Val[[]byte]) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Value = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetValue() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Value = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\n// The generated value is sometimes null\nfunc (m recordMods) RandomValue(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Value = func() null.Val[[]byte] {\n\t\t\tif f == nil {\n\t\t\t\tf = &defaultFaker\n\t\t\t}\n\n\t\t\tval := random___byte(f)\n\t\t\treturn null.From(val)\n\t\t}\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\n// The generated value is never null\nfunc (m recordMods) RandomValueNotNull(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Value = func() null.Val[[]byte] {\n\t\t\tif f == nil {\n\t\t\t\tf = &defaultFaker\n\t\t\t}\n\n\t\t\tval := random___byte(f)\n\t\t\treturn null.From(val)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Created(val int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Created = func() int64 { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) CreatedFunc(f func() int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Created = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetCreated() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Created = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\nfunc (m recordMods) RandomCreated(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Created = func() int64 {\n\t\t\treturn random_int64(f)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Modified(val int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Modified = func() int64 { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) ModifiedFunc(f func() int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Modified = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetModified() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Modified = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\nfunc (m recordMods) RandomModified(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Modified = func() int64 {\n\t\t\treturn random_int64(f)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Expires(val int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Expires = func() int64 { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) ExpiresFunc(f func() int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Expires = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetExpires() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Expires = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\nfunc (m recordMods) RandomExpires(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Expires = func() int64 {\n\t\t\treturn random_int64(f)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Deleted(val int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Deleted = func() int64 { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) DeletedFunc(f func() int64) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Deleted = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetDeleted() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Deleted = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\nfunc (m recordMods) RandomDeleted(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Deleted = func() int64 {\n\t\t\treturn random_int64(f)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Secret(val bool) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Secret = func() bool { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) SecretFunc(f func() bool) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Secret = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetSecret() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Secret = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\nfunc (m recordMods) RandomSecret(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Secret = func() bool {\n\t\t\treturn random_bool(f)\n\t\t}\n\t})\n}\n\n// Set the model columns to this value\nfunc (m recordMods) Crownjewel(val bool) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Crownjewel = func() bool { return val }\n\t})\n}\n\n// Set the Column from the function\nfunc (m recordMods) CrownjewelFunc(f func() bool) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Crownjewel = f\n\t})\n}\n\n// Clear any values for the column\nfunc (m recordMods) UnsetCrownjewel() RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Crownjewel = nil\n\t})\n}\n\n// Generates a random value for the column using the given faker\n// if faker is nil, a default faker is used\nfunc (m recordMods) RandomCrownjewel(f *faker.Faker) RecordMod {\n\treturn RecordModFunc(func(_ context.Context, o *RecordTemplate) {\n\t\to.Crownjewel = func() bool {\n\t\t\treturn random_bool(f)\n\t\t}\n\t})\n}\n\nfunc (m recordMods) WithParentsCascading() RecordMod {\n\treturn RecordModFunc(func(ctx context.Context, o *RecordTemplate) {\n\t\tif isDone, _ := recordWithParentsCascadingCtx.Value(ctx); isDone {\n\t\t\treturn\n\t\t}\n\t\tctx = recordWithParentsCascadingCtx.WithValue(ctx, true)\n\t})\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/migrations/0_settings.sql",
    "content": "-- +migrate Up\n-- SQL in section 'Up' is executed when this migration is applied\nPRAGMA auto_vacuum = INCREMENTAL; -- https://sqlite.org/pragma.html#pragma_auto_vacuum\n\n-- +migrate Down\n-- SQL section 'Down' is executed when this migration is rolled back\nPRAGMA auto_vacuum = NONE; -- https://sqlite.org/pragma.html#pragma_auto_vacuum\n"
  },
  {
    "path": "base/database/storage/sqlite/migrations/1_initial.sql",
    "content": "-- +migrate Up\n-- SQL in section 'Up' is executed when this migration is applied\nCREATE TABLE records (\n    key TEXT PRIMARY KEY,\n\n    format SMALLINT,\n    value  BLOB,\n\n    created    BIGINT NOT NULL,\n    modified   BIGINT NOT NULL,\n    expires    BIGINT DEFAULT 0 NOT NULL,\n    deleted    BIGINT DEFAULT 0 NOT NULL,\n    secret     BOOLEAN DEFAULT FALSE NOT NULL,\n    crownjewel BOOLEAN DEFAULT FALSE NOT NULL\n);\n\n-- +migrate Down\n-- SQL section 'Down' is executed when this migration is rolled back\nDROP TABLE records;\n"
  },
  {
    "path": "base/database/storage/sqlite/migrations_config.yml",
    "content": "development:\n  dialect: sqlite3\n  datasource: testdata/schema.db\n  dir: migrations\n  table: migrations\n"
  },
  {
    "path": "base/database/storage/sqlite/models/bob_joins.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage models\n\nimport (\n\t\"hash/maphash\"\n\n\t\"github.com/stephenafamo/bob\"\n\t\"github.com/stephenafamo/bob/clause\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/dialect\"\n)\n\nvar (\n\tSelectJoins = getJoins[*dialect.SelectQuery]\n\tUpdateJoins = getJoins[*dialect.UpdateQuery]\n)\n\ntype joinSet[Q interface{ aliasedAs(string) Q }] struct {\n\tInnerJoin Q\n\tLeftJoin  Q\n\tRightJoin Q\n}\n\nfunc (j joinSet[Q]) AliasedAs(alias string) joinSet[Q] {\n\treturn joinSet[Q]{\n\t\tInnerJoin: j.InnerJoin.aliasedAs(alias),\n\t\tLeftJoin:  j.LeftJoin.aliasedAs(alias),\n\t\tRightJoin: j.RightJoin.aliasedAs(alias),\n\t}\n}\n\ntype joins[Q dialect.Joinable] struct{}\n\nfunc buildJoinSet[Q interface{ aliasedAs(string) Q }, C any, F func(C, string) Q](c C, f F) joinSet[Q] {\n\treturn joinSet[Q]{\n\t\tInnerJoin: f(c, clause.InnerJoin),\n\t\tLeftJoin:  f(c, clause.LeftJoin),\n\t\tRightJoin: f(c, clause.RightJoin),\n\t}\n}\n\nfunc getJoins[Q dialect.Joinable]() joins[Q] {\n\treturn joins[Q]{}\n}\n\ntype modAs[Q any, C interface{ AliasedAs(string) C }] struct {\n\tc C\n\tf func(C) bob.Mod[Q]\n}\n\nfunc (m modAs[Q, C]) Apply(q Q) {\n\tm.f(m.c).Apply(q)\n}\n\nfunc (m modAs[Q, C]) AliasedAs(alias string) bob.Mod[Q] {\n\tm.c = m.c.AliasedAs(alias)\n\treturn m\n}\n\nfunc randInt() int64 {\n\tout := int64(new(maphash.Hash).Sum64())\n\n\tif out < 0 {\n\t\treturn -out % 10000\n\t}\n\n\treturn out % 10000\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/models/bob_loaders.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage models\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/stephenafamo/bob\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/dialect\"\n\t\"github.com/stephenafamo/bob/orm\"\n)\n\nvar Preload = getPreloaders()\n\ntype preloaders struct{}\n\nfunc getPreloaders() preloaders {\n\treturn preloaders{}\n}\n\nvar (\n\tSelectThenLoad = getThenLoaders[*dialect.SelectQuery]()\n\tInsertThenLoad = getThenLoaders[*dialect.InsertQuery]()\n\tUpdateThenLoad = getThenLoaders[*dialect.UpdateQuery]()\n)\n\ntype thenLoaders[Q orm.Loadable] struct{}\n\nfunc getThenLoaders[Q orm.Loadable]() thenLoaders[Q] {\n\treturn thenLoaders[Q]{}\n}\n\nfunc thenLoadBuilder[Q orm.Loadable, T any](name string, f func(context.Context, bob.Executor, T, ...bob.Mod[*dialect.SelectQuery]) error) func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] {\n\treturn func(queryMods ...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] {\n\t\treturn func(ctx context.Context, exec bob.Executor, retrieved any) error {\n\t\t\tloader, isLoader := retrieved.(T)\n\t\t\tif !isLoader {\n\t\t\t\treturn fmt.Errorf(\"object %T cannot load %q\", retrieved, name)\n\t\t\t}\n\n\t\t\terr := f(ctx, exec, loader, queryMods...)\n\n\t\t\t// Don't cause an issue due to missing relationships\n\t\t\tif errors.Is(err, sql.ErrNoRows) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/models/bob_types.bob_test.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage models\n\nimport \"github.com/stephenafamo/bob\"\n\n// Set the testDB to enable tests that use the database\nvar testDB bob.Transactor[bob.Tx]\n\n// Make sure the type Record runs hooks after queries\nvar _ bob.HookableType = &Record{}\n"
  },
  {
    "path": "base/database/storage/sqlite/models/bob_where.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage models\n\nimport (\n\t\"github.com/stephenafamo/bob/clause\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/dialect\"\n)\n\nvar (\n\tSelectWhere     = Where[*dialect.SelectQuery]()\n\tUpdateWhere     = Where[*dialect.UpdateQuery]()\n\tDeleteWhere     = Where[*dialect.DeleteQuery]()\n\tOnConflictWhere = Where[*clause.ConflictClause]() // Used in ON CONFLICT DO UPDATE\n)\n\nfunc Where[Q sqlite.Filterable]() struct {\n\tRecords recordWhere[Q]\n} {\n\treturn struct {\n\t\tRecords recordWhere[Q]\n\t}{\n\t\tRecords: buildRecordWhere[Q](Records.Columns),\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/models/records.bob.go",
    "content": "// Code generated by BobGen sqlite v0.41.1. DO NOT EDIT.\n// This file is meant to be re-generated in place and/or deleted at any time.\n\npackage models\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/aarondl/opt/null\"\n\t\"github.com/aarondl/opt/omit\"\n\t\"github.com/aarondl/opt/omitnull\"\n\t\"github.com/stephenafamo/bob\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/dialect\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/dm\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/sm\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/um\"\n\t\"github.com/stephenafamo/bob/expr\"\n)\n\n// Record is an object representing the database table.\ntype Record struct {\n\tKey        string           `db:\"key,pk\" `\n\tFormat     null.Val[int64]  `db:\"format\" `\n\tValue      null.Val[[]byte] `db:\"value\" `\n\tCreated    int64            `db:\"created\" `\n\tModified   int64            `db:\"modified\" `\n\tExpires    int64            `db:\"expires\" `\n\tDeleted    int64            `db:\"deleted\" `\n\tSecret     bool             `db:\"secret\" `\n\tCrownjewel bool             `db:\"crownjewel\" `\n}\n\n// RecordSlice is an alias for a slice of pointers to Record.\n// This should almost always be used instead of []*Record.\ntype RecordSlice []*Record\n\n// Records contains methods to work with the records table\nvar Records = sqlite.NewTablex[*Record, RecordSlice, *RecordSetter](\"\", \"records\", buildRecordColumns(\"records\"))\n\n// RecordsQuery is a query on the records table\ntype RecordsQuery = *sqlite.ViewQuery[*Record, RecordSlice]\n\nfunc buildRecordColumns(alias string) recordColumns {\n\treturn recordColumns{\n\t\tColumnsExpr: expr.NewColumnsExpr(\n\t\t\t\"key\", \"format\", \"value\", \"created\", \"modified\", \"expires\", \"deleted\", \"secret\", \"crownjewel\",\n\t\t).WithParent(\"records\"),\n\t\ttableAlias: alias,\n\t\tKey:        sqlite.Quote(alias, \"key\"),\n\t\tFormat:     sqlite.Quote(alias, \"format\"),\n\t\tValue:      sqlite.Quote(alias, \"value\"),\n\t\tCreated:    sqlite.Quote(alias, \"created\"),\n\t\tModified:   sqlite.Quote(alias, \"modified\"),\n\t\tExpires:    sqlite.Quote(alias, \"expires\"),\n\t\tDeleted:    sqlite.Quote(alias, \"deleted\"),\n\t\tSecret:     sqlite.Quote(alias, \"secret\"),\n\t\tCrownjewel: sqlite.Quote(alias, \"crownjewel\"),\n\t}\n}\n\ntype recordColumns struct {\n\texpr.ColumnsExpr\n\ttableAlias string\n\tKey        sqlite.Expression\n\tFormat     sqlite.Expression\n\tValue      sqlite.Expression\n\tCreated    sqlite.Expression\n\tModified   sqlite.Expression\n\tExpires    sqlite.Expression\n\tDeleted    sqlite.Expression\n\tSecret     sqlite.Expression\n\tCrownjewel sqlite.Expression\n}\n\nfunc (c recordColumns) Alias() string {\n\treturn c.tableAlias\n}\n\nfunc (recordColumns) AliasedAs(alias string) recordColumns {\n\treturn buildRecordColumns(alias)\n}\n\n// RecordSetter is used for insert/upsert/update operations\n// All values are optional, and do not have to be set\n// Generated columns are not included\ntype RecordSetter struct {\n\tKey        omit.Val[string]     `db:\"key,pk\" `\n\tFormat     omitnull.Val[int64]  `db:\"format\" `\n\tValue      omitnull.Val[[]byte] `db:\"value\" `\n\tCreated    omit.Val[int64]      `db:\"created\" `\n\tModified   omit.Val[int64]      `db:\"modified\" `\n\tExpires    omit.Val[int64]      `db:\"expires\" `\n\tDeleted    omit.Val[int64]      `db:\"deleted\" `\n\tSecret     omit.Val[bool]       `db:\"secret\" `\n\tCrownjewel omit.Val[bool]       `db:\"crownjewel\" `\n}\n\nfunc (s RecordSetter) SetColumns() []string {\n\tvals := make([]string, 0, 9)\n\tif s.Key.IsValue() {\n\t\tvals = append(vals, \"key\")\n\t}\n\tif !s.Format.IsUnset() {\n\t\tvals = append(vals, \"format\")\n\t}\n\tif !s.Value.IsUnset() {\n\t\tvals = append(vals, \"value\")\n\t}\n\tif s.Created.IsValue() {\n\t\tvals = append(vals, \"created\")\n\t}\n\tif s.Modified.IsValue() {\n\t\tvals = append(vals, \"modified\")\n\t}\n\tif s.Expires.IsValue() {\n\t\tvals = append(vals, \"expires\")\n\t}\n\tif s.Deleted.IsValue() {\n\t\tvals = append(vals, \"deleted\")\n\t}\n\tif s.Secret.IsValue() {\n\t\tvals = append(vals, \"secret\")\n\t}\n\tif s.Crownjewel.IsValue() {\n\t\tvals = append(vals, \"crownjewel\")\n\t}\n\treturn vals\n}\n\nfunc (s RecordSetter) Overwrite(t *Record) {\n\tif s.Key.IsValue() {\n\t\tt.Key = s.Key.MustGet()\n\t}\n\tif !s.Format.IsUnset() {\n\t\tt.Format = s.Format.MustGetNull()\n\t}\n\tif !s.Value.IsUnset() {\n\t\tt.Value = s.Value.MustGetNull()\n\t}\n\tif s.Created.IsValue() {\n\t\tt.Created = s.Created.MustGet()\n\t}\n\tif s.Modified.IsValue() {\n\t\tt.Modified = s.Modified.MustGet()\n\t}\n\tif s.Expires.IsValue() {\n\t\tt.Expires = s.Expires.MustGet()\n\t}\n\tif s.Deleted.IsValue() {\n\t\tt.Deleted = s.Deleted.MustGet()\n\t}\n\tif s.Secret.IsValue() {\n\t\tt.Secret = s.Secret.MustGet()\n\t}\n\tif s.Crownjewel.IsValue() {\n\t\tt.Crownjewel = s.Crownjewel.MustGet()\n\t}\n}\n\nfunc (s *RecordSetter) Apply(q *dialect.InsertQuery) {\n\tq.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) {\n\t\treturn Records.BeforeInsertHooks.RunHooks(ctx, exec, s)\n\t})\n\n\tif len(q.TableRef.Columns) == 0 {\n\t\tq.TableRef.Columns = s.SetColumns()\n\t\tif len(q.TableRef.Columns) == 0 {\n\t\t\tq.TableRef.Columns = []string{\"key\"}\n\t\t}\n\n\t}\n\n\tq.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {\n\t\tvals := make([]bob.Expression, 0, 9)\n\t\tif s.Key.IsValue() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Key.MustGet()))\n\t\t}\n\n\t\tif !s.Format.IsUnset() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Format.MustGetNull()))\n\t\t}\n\n\t\tif !s.Value.IsUnset() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Value.MustGetNull()))\n\t\t}\n\n\t\tif s.Created.IsValue() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Created.MustGet()))\n\t\t}\n\n\t\tif s.Modified.IsValue() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Modified.MustGet()))\n\t\t}\n\n\t\tif s.Expires.IsValue() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Expires.MustGet()))\n\t\t}\n\n\t\tif s.Deleted.IsValue() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Deleted.MustGet()))\n\t\t}\n\n\t\tif s.Secret.IsValue() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Secret.MustGet()))\n\t\t}\n\n\t\tif s.Crownjewel.IsValue() {\n\t\t\tvals = append(vals, sqlite.Arg(s.Crownjewel.MustGet()))\n\t\t}\n\n\t\tif len(vals) == 0 {\n\t\t\tvals = append(vals, sqlite.Arg(nil))\n\t\t}\n\n\t\treturn bob.ExpressSlice(ctx, w, d, start, vals, \"\", \", \", \"\")\n\t}))\n}\n\nfunc (s RecordSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {\n\treturn um.Set(s.Expressions()...)\n}\n\nfunc (s RecordSetter) Expressions(prefix ...string) []bob.Expression {\n\texprs := make([]bob.Expression, 0, 9)\n\n\tif s.Key.IsValue() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"key\")...),\n\t\t\tsqlite.Arg(s.Key),\n\t\t}})\n\t}\n\n\tif !s.Format.IsUnset() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"format\")...),\n\t\t\tsqlite.Arg(s.Format),\n\t\t}})\n\t}\n\n\tif !s.Value.IsUnset() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"value\")...),\n\t\t\tsqlite.Arg(s.Value),\n\t\t}})\n\t}\n\n\tif s.Created.IsValue() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"created\")...),\n\t\t\tsqlite.Arg(s.Created),\n\t\t}})\n\t}\n\n\tif s.Modified.IsValue() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"modified\")...),\n\t\t\tsqlite.Arg(s.Modified),\n\t\t}})\n\t}\n\n\tif s.Expires.IsValue() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"expires\")...),\n\t\t\tsqlite.Arg(s.Expires),\n\t\t}})\n\t}\n\n\tif s.Deleted.IsValue() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"deleted\")...),\n\t\t\tsqlite.Arg(s.Deleted),\n\t\t}})\n\t}\n\n\tif s.Secret.IsValue() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"secret\")...),\n\t\t\tsqlite.Arg(s.Secret),\n\t\t}})\n\t}\n\n\tif s.Crownjewel.IsValue() {\n\t\texprs = append(exprs, expr.Join{Sep: \" = \", Exprs: []bob.Expression{\n\t\t\tsqlite.Quote(append(prefix, \"crownjewel\")...),\n\t\t\tsqlite.Arg(s.Crownjewel),\n\t\t}})\n\t}\n\n\treturn exprs\n}\n\n// FindRecord retrieves a single record by primary key\n// If cols is empty Find will return all columns.\nfunc FindRecord(ctx context.Context, exec bob.Executor, KeyPK string, cols ...string) (*Record, error) {\n\tif len(cols) == 0 {\n\t\treturn Records.Query(\n\t\t\tsm.Where(Records.Columns.Key.EQ(sqlite.Arg(KeyPK))),\n\t\t).One(ctx, exec)\n\t}\n\n\treturn Records.Query(\n\t\tsm.Where(Records.Columns.Key.EQ(sqlite.Arg(KeyPK))),\n\t\tsm.Columns(Records.Columns.Only(cols...)),\n\t).One(ctx, exec)\n}\n\n// RecordExists checks the presence of a single record by primary key\nfunc RecordExists(ctx context.Context, exec bob.Executor, KeyPK string) (bool, error) {\n\treturn Records.Query(\n\t\tsm.Where(Records.Columns.Key.EQ(sqlite.Arg(KeyPK))),\n\t).Exists(ctx, exec)\n}\n\n// AfterQueryHook is called after Record is retrieved from the database\nfunc (o *Record) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error {\n\tvar err error\n\n\tswitch queryType {\n\tcase bob.QueryTypeSelect:\n\t\tctx, err = Records.AfterSelectHooks.RunHooks(ctx, exec, RecordSlice{o})\n\tcase bob.QueryTypeInsert:\n\t\tctx, err = Records.AfterInsertHooks.RunHooks(ctx, exec, RecordSlice{o})\n\tcase bob.QueryTypeUpdate:\n\t\tctx, err = Records.AfterUpdateHooks.RunHooks(ctx, exec, RecordSlice{o})\n\tcase bob.QueryTypeDelete:\n\t\tctx, err = Records.AfterDeleteHooks.RunHooks(ctx, exec, RecordSlice{o})\n\t}\n\n\treturn err\n}\n\n// primaryKeyVals returns the primary key values of the Record\nfunc (o *Record) primaryKeyVals() bob.Expression {\n\treturn sqlite.Arg(o.Key)\n}\n\nfunc (o *Record) pkEQ() dialect.Expression {\n\treturn sqlite.Quote(\"records\", \"key\").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {\n\t\treturn o.primaryKeyVals().WriteSQL(ctx, w, d, start)\n\t}))\n}\n\n// Update uses an executor to update the Record\nfunc (o *Record) Update(ctx context.Context, exec bob.Executor, s *RecordSetter) error {\n\tv, err := Records.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*o = *v\n\n\treturn nil\n}\n\n// Delete deletes a single Record record with an executor\nfunc (o *Record) Delete(ctx context.Context, exec bob.Executor) error {\n\t_, err := Records.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec)\n\treturn err\n}\n\n// Reload refreshes the Record using the executor\nfunc (o *Record) Reload(ctx context.Context, exec bob.Executor) error {\n\to2, err := Records.Query(\n\t\tsm.Where(Records.Columns.Key.EQ(sqlite.Arg(o.Key))),\n\t).One(ctx, exec)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*o = *o2\n\n\treturn nil\n}\n\n// AfterQueryHook is called after RecordSlice is retrieved from the database\nfunc (o RecordSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error {\n\tvar err error\n\n\tswitch queryType {\n\tcase bob.QueryTypeSelect:\n\t\tctx, err = Records.AfterSelectHooks.RunHooks(ctx, exec, o)\n\tcase bob.QueryTypeInsert:\n\t\tctx, err = Records.AfterInsertHooks.RunHooks(ctx, exec, o)\n\tcase bob.QueryTypeUpdate:\n\t\tctx, err = Records.AfterUpdateHooks.RunHooks(ctx, exec, o)\n\tcase bob.QueryTypeDelete:\n\t\tctx, err = Records.AfterDeleteHooks.RunHooks(ctx, exec, o)\n\t}\n\n\treturn err\n}\n\nfunc (o RecordSlice) pkIN() dialect.Expression {\n\tif len(o) == 0 {\n\t\treturn sqlite.Raw(\"NULL\")\n\t}\n\n\treturn sqlite.Quote(\"records\", \"key\").In(bob.ExpressionFunc(func(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {\n\t\tpkPairs := make([]bob.Expression, len(o))\n\t\tfor i, row := range o {\n\t\t\tpkPairs[i] = row.primaryKeyVals()\n\t\t}\n\t\treturn bob.ExpressSlice(ctx, w, d, start, pkPairs, \"\", \", \", \"\")\n\t}))\n}\n\n// copyMatchingRows finds models in the given slice that have the same primary key\n// then it first copies the existing relationships from the old model to the new model\n// and then replaces the old model in the slice with the new model\nfunc (o RecordSlice) copyMatchingRows(from ...*Record) {\n\tfor i, old := range o {\n\t\tfor _, new := range from {\n\t\t\tif new.Key != old.Key {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\to[i] = new\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// UpdateMod modifies an update query with \"WHERE primary_key IN (o...)\"\nfunc (o RecordSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] {\n\treturn bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) {\n\t\tq.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) {\n\t\t\treturn Records.BeforeUpdateHooks.RunHooks(ctx, exec, o)\n\t\t})\n\n\t\tq.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error {\n\t\t\tvar err error\n\t\t\tswitch retrieved := retrieved.(type) {\n\t\t\tcase *Record:\n\t\t\t\to.copyMatchingRows(retrieved)\n\t\t\tcase []*Record:\n\t\t\t\to.copyMatchingRows(retrieved...)\n\t\t\tcase RecordSlice:\n\t\t\t\to.copyMatchingRows(retrieved...)\n\t\t\tdefault:\n\t\t\t\t// If the retrieved value is not a Record or a slice of Record\n\t\t\t\t// then run the AfterUpdateHooks on the slice\n\t\t\t\t_, err = Records.AfterUpdateHooks.RunHooks(ctx, exec, o)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}))\n\n\t\tq.AppendWhere(o.pkIN())\n\t})\n}\n\n// DeleteMod modifies an delete query with \"WHERE primary_key IN (o...)\"\nfunc (o RecordSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] {\n\treturn bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) {\n\t\tq.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) {\n\t\t\treturn Records.BeforeDeleteHooks.RunHooks(ctx, exec, o)\n\t\t})\n\n\t\tq.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error {\n\t\t\tvar err error\n\t\t\tswitch retrieved := retrieved.(type) {\n\t\t\tcase *Record:\n\t\t\t\to.copyMatchingRows(retrieved)\n\t\t\tcase []*Record:\n\t\t\t\to.copyMatchingRows(retrieved...)\n\t\t\tcase RecordSlice:\n\t\t\t\to.copyMatchingRows(retrieved...)\n\t\t\tdefault:\n\t\t\t\t// If the retrieved value is not a Record or a slice of Record\n\t\t\t\t// then run the AfterDeleteHooks on the slice\n\t\t\t\t_, err = Records.AfterDeleteHooks.RunHooks(ctx, exec, o)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}))\n\n\t\tq.AppendWhere(o.pkIN())\n\t})\n}\n\nfunc (o RecordSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals RecordSetter) error {\n\tif len(o) == 0 {\n\t\treturn nil\n\t}\n\n\t_, err := Records.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec)\n\treturn err\n}\n\nfunc (o RecordSlice) DeleteAll(ctx context.Context, exec bob.Executor) error {\n\tif len(o) == 0 {\n\t\treturn nil\n\t}\n\n\t_, err := Records.Delete(o.DeleteMod()).Exec(ctx, exec)\n\treturn err\n}\n\nfunc (o RecordSlice) ReloadAll(ctx context.Context, exec bob.Executor) error {\n\tif len(o) == 0 {\n\t\treturn nil\n\t}\n\n\to2, err := Records.Query(sm.Where(o.pkIN())).All(ctx, exec)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\to.copyMatchingRows(o2...)\n\n\treturn nil\n}\n\ntype recordWhere[Q sqlite.Filterable] struct {\n\tKey        sqlite.WhereMod[Q, string]\n\tFormat     sqlite.WhereNullMod[Q, int64]\n\tValue      sqlite.WhereNullMod[Q, []byte]\n\tCreated    sqlite.WhereMod[Q, int64]\n\tModified   sqlite.WhereMod[Q, int64]\n\tExpires    sqlite.WhereMod[Q, int64]\n\tDeleted    sqlite.WhereMod[Q, int64]\n\tSecret     sqlite.WhereMod[Q, bool]\n\tCrownjewel sqlite.WhereMod[Q, bool]\n}\n\nfunc (recordWhere[Q]) AliasedAs(alias string) recordWhere[Q] {\n\treturn buildRecordWhere[Q](buildRecordColumns(alias))\n}\n\nfunc buildRecordWhere[Q sqlite.Filterable](cols recordColumns) recordWhere[Q] {\n\treturn recordWhere[Q]{\n\t\tKey:        sqlite.Where[Q, string](cols.Key),\n\t\tFormat:     sqlite.WhereNull[Q, int64](cols.Format),\n\t\tValue:      sqlite.WhereNull[Q, []byte](cols.Value),\n\t\tCreated:    sqlite.Where[Q, int64](cols.Created),\n\t\tModified:   sqlite.Where[Q, int64](cols.Modified),\n\t\tExpires:    sqlite.Where[Q, int64](cols.Expires),\n\t\tDeleted:    sqlite.Where[Q, int64](cols.Deleted),\n\t\tSecret:     sqlite.Where[Q, bool](cols.Secret),\n\t\tCrownjewel: sqlite.Where[Q, bool](cols.Crownjewel),\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/prepared.go",
    "content": "package sqlite\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/stephenafamo/bob\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/im\"\n\t\"github.com/stephenafamo/bob/expr\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/database/storage/sqlite/models\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nvar UsePreparedStatements bool = true\n\n// PutMany stores many records in the database.\nfunc (db *SQLite) putManyWithPreparedStmts(shadowDelete bool) (chan<- record.Record, <-chan error) {\n\tbatch := make(chan record.Record, 100)\n\terrs := make(chan error, 1)\n\n\t// Simulate upsert with custom selection on conflict.\n\trawQuery, _, err := models.Records.Insert(\n\t\tim.Into(\"records\", \"key\", \"format\", \"value\", \"created\", \"modified\", \"expires\", \"deleted\", \"secret\", \"crownjewel\"),\n\t\tim.Values(expr.Arg(\"key\"), expr.Arg(\"format\"), expr.Arg(\"value\"), expr.Arg(\"created\"), expr.Arg(\"modified\"), expr.Arg(\"expires\"), expr.Arg(\"deleted\"), expr.Arg(\"secret\"), expr.Arg(\"crownjewel\")),\n\t\tim.OnConflict(\"key\").DoUpdate(\n\t\t\tim.SetExcluded(\"format\", \"value\", \"created\", \"modified\", \"expires\", \"deleted\", \"secret\", \"crownjewel\"),\n\t\t),\n\t).Build(db.ctx)\n\tif err != nil {\n\t\terrs <- err\n\t\treturn batch, errs\n\t}\n\n\t// Start transaction.\n\ttx, err := db.bob.BeginTx(db.ctx, nil)\n\tif err != nil {\n\t\terrs <- err\n\t\treturn batch, errs\n\t}\n\n\t// Create prepared statement WITHIN TRANSACTION.\n\tpreparedStmt, err := tx.PrepareContext(db.ctx, rawQuery)\n\tif err != nil {\n\t\terrs <- err\n\t\treturn batch, errs\n\t}\n\n\t// start handler\n\tgo func() {\n\t\t// Read all put records.\n\twriteBatch:\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase r := <-batch:\n\t\t\t\tif r != nil {\n\t\t\t\t\t// Write record.\n\t\t\t\t\terr := writeWithPreparedStatement(db.ctx, &preparedStmt, r)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\terrs <- err\n\t\t\t\t\t\tbreak writeBatch\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Finalize transcation.\n\t\t\t\t\terrs <- tx.Commit(db.ctx)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tcase <-db.ctx.Done():\n\t\t\t\tbreak writeBatch\n\t\t\t}\n\t\t}\n\n\t\t// Rollback transaction.\n\t\terrs <- tx.Rollback(db.ctx)\n\t}()\n\n\treturn batch, errs\n}\n\nfunc writeWithPreparedStatement(ctx context.Context, pStmt *bob.StdPrepared, r record.Record) error {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\t// default serialization format - JSON\n\tformat := uint8(dsd.JSON)\n\n\t// For wrapped records, check the required format\n\tif r.IsWrapped() {\n\t\twrapper, ok := r.(*record.Wrapper)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"%w: reports to be wrapped but is not of type *record.Wrapper\", storage.ErrRecordMalformed)\n\t\t}\n\t\tformat, ok = dsd.ValidateSerializationFormat(wrapper.Format)\n\t\tif !ok {\n\t\t\treturn dsd.ErrIncompatibleFormat\n\t\t}\n\t}\n\n\t// Serialize.\n\tdata, err := r.MarshalDataOnly(r, format)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Get Meta.\n\tm := r.Meta()\n\n\t// Insert.\n\tif len(data) > 0 {\n\t\tformat := strconv.Itoa(int(format))\n\t\t_, err = pStmt.ExecContext(\n\t\t\tctx,\n\t\t\tr.DatabaseKey(),\n\t\t\tformat,\n\t\t\tdata,\n\t\t\tm.Created,\n\t\t\tm.Modified,\n\t\t\tm.Expires,\n\t\t\tm.Deleted,\n\t\t\tm.IsSecret(),\n\t\t\tm.IsCrownJewel(),\n\t\t)\n\t} else {\n\t\t_, err = pStmt.ExecContext(\n\t\t\tctx,\n\t\t\tr.DatabaseKey(),\n\t\t\tnil,\n\t\t\tnil,\n\t\t\tm.Created,\n\t\t\tm.Modified,\n\t\t\tm.Expires,\n\t\t\tm.Deleted,\n\t\t\tm.IsSecret(),\n\t\t\tm.IsCrownJewel(),\n\t\t)\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/prepared_test.go",
    "content": "package sqlite\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n)\n\nfunc BenchmarkPutMany(b *testing.B) {\n\t// Configure prepared statement usage.\n\torigSetting := UsePreparedStatements\n\tUsePreparedStatements = false\n\tdefer func() {\n\t\tUsePreparedStatements = origSetting\n\t}()\n\n\t// Run benchmark.\n\tbenchPutMany(b)\n}\n\nfunc BenchmarkPutManyPreparedStmt(b *testing.B) {\n\t// Configure prepared statement usage.\n\torigSetting := UsePreparedStatements\n\tUsePreparedStatements = true\n\tdefer func() {\n\t\tUsePreparedStatements = origSetting\n\t}()\n\n\t// Run benchmark.\n\tbenchPutMany(b)\n}\n\nfunc benchPutMany(b *testing.B) { //nolint:thelper\n\t// Start database.\n\ttestDir := b.TempDir()\n\tdb, err := openSQLite(\"test\", testDir, false)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\tdefer func() {\n\t\t// shutdown\n\t\terr = db.Shutdown()\n\t\tif err != nil {\n\t\t\tb.Fatal(err)\n\t\t}\n\t}()\n\n\t// Start benchmarking.\n\tb.ResetTimer()\n\n\t// Benchmark PutMany.\n\trecords, errs := db.PutMany(false)\n\tfor i := range b.N {\n\t\t// Create test record.\n\t\tnewTestRecord := &TestRecord{\n\t\t\tS:    \"banana\",\n\t\t\tI:    42,\n\t\t\tI8:   42,\n\t\t\tI16:  42,\n\t\t\tI32:  42,\n\t\t\tI64:  42,\n\t\t\tUI:   42,\n\t\t\tUI8:  42,\n\t\t\tUI16: 42,\n\t\t\tUI32: 42,\n\t\t\tUI64: 42,\n\t\t\tF32:  42.42,\n\t\t\tF64:  42.42,\n\t\t\tB:    true,\n\t\t}\n\t\tnewTestRecord.UpdateMeta()\n\t\tnewTestRecord.SetKey(\"test:\" + strconv.Itoa(i))\n\n\t\tselect {\n\t\tcase records <- newTestRecord:\n\t\tcase err := <-errs:\n\t\t\tb.Fatal(err)\n\t\t}\n\t}\n\n\t// Finalize.\n\tclose(records)\n\terr = <-errs\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/schema.go",
    "content": "package sqlite\n\n// Base command for sql-migrate:\n//go:generate -command migrate go tool github.com/rubenv/sql-migrate/sql-migrate\n\n// Run missing migrations:\n//go:generate migrate up --config=migrations_config.yml\n\n// Redo last migration:\n// x go:generate migrate redo --config=migrations_config.yml\n\n// Undo all migrations:\n// x go:generate migrate down --config=migrations_config.yml\n\n// Generate models with bob:\n//go:generate go tool github.com/stephenafamo/bob/gen/bobgen-sqlite\n\nimport (\n\t\"embed\"\n\n\tmigrate \"github.com/rubenv/sql-migrate\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage/sqlite/models\"\n)\n\n//go:embed migrations/*\nvar dbMigrations embed.FS\n\nfunc getMigrations() migrate.EmbedFileSystemMigrationSource {\n\treturn migrate.EmbedFileSystemMigrationSource{\n\t\tFileSystem: dbMigrations,\n\t\tRoot:       \"migrations\",\n\t}\n}\n\nfunc getMeta(r *models.Record) *record.Meta {\n\tmeta := &record.Meta{\n\t\tCreated:  r.Created,\n\t\tModified: r.Modified,\n\t\tExpires:  r.Expires,\n\t\tDeleted:  r.Deleted,\n\t}\n\tif r.Secret {\n\t\tmeta.MakeSecret()\n\t}\n\tif r.Crownjewel {\n\t\tmeta.MakeCrownJewel()\n\t}\n\treturn meta\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/sqlite.go",
    "content": "package sqlite\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/aarondl/opt/omit\"\n\t\"github.com/aarondl/opt/omitnull\"\n\tmigrate \"github.com/rubenv/sql-migrate\"\n\tsqldblogger \"github.com/simukti/sqldb-logger\"\n\t\"github.com/stephenafamo/bob\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/im\"\n\t\"github.com/stephenafamo/bob/dialect/sqlite/um\"\n\t_ \"modernc.org/sqlite\"\n\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/database/storage/sqlite/models\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// Errors.\nvar (\n\tErrQueryTimeout = errors.New(\"query timeout\")\n)\n\n// SQLite storage.\ntype SQLite struct {\n\tname string\n\n\tdb  *sql.DB\n\tbob bob.DB\n\twg  sync.WaitGroup\n\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n}\n\nfunc init() {\n\t_ = storage.Register(\"sqlite\", func(name, location string) (storage.Interface, error) {\n\t\treturn NewSQLite(name, location)\n\t})\n}\n\n// NewSQLite creates a sqlite database.\nfunc NewSQLite(name, location string) (*SQLite, error) {\n\treturn openSQLite(name, location, false)\n}\n\n// openSQLite creates a sqlite database.\nfunc openSQLite(name, location string, printStmts bool) (*SQLite, error) {\n\tdbFile := filepath.Join(location, \"db.sqlite\")\n\n\t// Open database file.\n\t// Default settings:\n\t// _time_format = YYYY-MM-DDTHH:MM:SS.SSS\n\t// _txlock = deferred\n\tdb, err := sql.Open(\"sqlite\", dbFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"open sqlite: %w\", err)\n\t}\n\n\t// Enable statement printing.\n\tif printStmts {\n\t\tdb = sqldblogger.OpenDriver(dbFile, db.Driver(), &statementLogger{})\n\t}\n\n\t// Set other settings.\n\tpragmas := []string{\n\t\t\"PRAGMA journal_mode=WAL;\",   // Corruption safe write ahead log for txs.\n\t\t\"PRAGMA synchronous=NORMAL;\", // Best for WAL.\n\t\t\"PRAGMA cache_size=-10000;\",  // 10MB Cache.\n\t\t\"PRAGMA busy_timeout=3000;\",  // 3s (3000ms) timeout for locked tables.\n\t}\n\tfor _, pragma := range pragmas {\n\t\t_, err := db.Exec(pragma)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to init sqlite with %s: %w\", pragma, err)\n\t\t}\n\t}\n\n\t// Limit concurrent writes to avoid \"SQLITE_BUSY\" errors on large workloads.\n\t// SQLite typically allows only one writer at a time anyway.\n\t// In WAL mode, concurrent readers can still function,\n\t// but we keep a single writer to reduce lock contention.\n\tdb.SetMaxOpenConns(1)    // Only 1 open connection can be active\n\tdb.SetMaxIdleConns(1)    // Maintain at most 1 idle connection in the pool\n\tdb.SetConnMaxLifetime(0) // Keep the single connection alive indefinitely\n\n\t// Run migrations on database.\n\tn, err := migrate.Exec(db, \"sqlite3\", getMigrations(), migrate.Up)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"migrate sqlite: %w\", err)\n\t}\n\tlog.Debugf(\"database/sqlite: ran %d migrations on %s database\", n, name)\n\n\t// Return as bob database.\n\tctx, cancelCtx := context.WithCancel(context.Background())\n\treturn &SQLite{\n\t\tname:      name,\n\t\tdb:        db,\n\t\tbob:       bob.NewDB(db),\n\t\tctx:       ctx,\n\t\tcancelCtx: cancelCtx,\n\t}, nil\n}\n\n// Get returns a database record.\nfunc (db *SQLite) Get(key string) (record.Record, error) {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t// Get record from database.\n\tr, err := models.FindRecord(db.ctx, db.bob, key)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: %w\", storage.ErrNotFound, err)\n\t}\n\n\t// Return data in wrapper.\n\treturn record.NewWrapperFromDatabase(\n\t\tdb.name,\n\t\tkey,\n\t\tgetMeta(r),\n\t\tuint8(r.Format.GetOrZero()), //nolint:gosec // Values are within uint8.\n\t\tr.Value.GetOrZero(),\n\t)\n}\n\n// GetMeta returns the metadata of a database record.\nfunc (db *SQLite) GetMeta(key string) (*record.Meta, error) {\n\tr, err := db.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r.Meta(), nil\n}\n\n// Put stores a record in the database.\nfunc (db *SQLite) Put(r record.Record) (record.Record, error) {\n\treturn db.putRecord(r, nil)\n}\n\nfunc (db *SQLite) putRecord(r record.Record, tx *bob.Tx) (record.Record, error) {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t// Lock record if in a transaction.\n\tif tx != nil {\n\t\tr.Lock()\n\t\tdefer r.Unlock()\n\t}\n\n\t// default serialization format - JSON\n\tformat := uint8(dsd.JSON)\n\n\t// For wrapped records, check the required format\n\tif r.IsWrapped() {\n\t\twrapper, ok := r.(*record.Wrapper)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"%w: reports to be wrapped but is not of type *record.Wrapper\", storage.ErrRecordMalformed)\n\t\t}\n\t\tformat, ok = dsd.ValidateSerializationFormat(wrapper.Format)\n\t\tif !ok {\n\t\t\treturn nil, dsd.ErrIncompatibleFormat\n\t\t}\n\t}\n\n\t// Serialize.\n\tdata, err := r.MarshalDataOnly(r, format)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Prepare for setter.\n\tsetFormat := omitnull.From(int64(format))\n\tsetData := omitnull.From(data)\n\tif len(data) == 0 {\n\t\tsetFormat.Null()\n\t\tsetData.Null()\n\t}\n\n\t// Create structure for insert.\n\tm := r.Meta()\n\tsetter := models.RecordSetter{\n\t\tKey:        omit.From(r.DatabaseKey()),\n\t\tFormat:     setFormat,\n\t\tValue:      setData,\n\t\tCreated:    omit.From(m.Created),\n\t\tModified:   omit.From(m.Modified),\n\t\tExpires:    omit.From(m.Expires),\n\t\tDeleted:    omit.From(m.Deleted),\n\t\tSecret:     omit.From(m.IsSecret()),\n\t\tCrownjewel: omit.From(m.IsCrownJewel()),\n\t}\n\n\t// Simulate upsert with custom selection on conflict.\n\tdbQuery := models.Records.Insert(\n\t\t&setter,\n\t\tim.OnConflict(\"key\").DoUpdate(\n\t\t\tim.SetExcluded(\"format\", \"value\", \"created\", \"modified\", \"expires\", \"deleted\", \"secret\", \"crownjewel\"),\n\t\t),\n\t)\n\n\t// Execute in transaction or directly.\n\tif tx != nil {\n\t\t_, err = dbQuery.Exec(db.ctx, tx)\n\t} else {\n\t\t_, err = dbQuery.Exec(db.ctx, db.bob)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r, nil\n}\n\n// PutMany stores many records in the database.\nfunc (db *SQLite) PutMany(shadowDelete bool) (chan<- record.Record, <-chan error) {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t// Check if we should use prepared statement optimized inserting.\n\tif UsePreparedStatements {\n\t\treturn db.putManyWithPreparedStmts(shadowDelete)\n\t}\n\n\tbatch := make(chan record.Record, 100)\n\terrs := make(chan error, 1)\n\n\ttx, err := db.bob.BeginTx(db.ctx, nil)\n\tif err != nil {\n\t\terrs <- err\n\t\treturn batch, errs\n\t}\n\n\t// start handler\n\tgo func() {\n\t\t// Read all put records.\n\twriteBatch:\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase r := <-batch:\n\t\t\t\tif r != nil {\n\t\t\t\t\t// Write record.\n\t\t\t\t\t_, err := db.putRecord(r, &tx)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\terrs <- err\n\t\t\t\t\t\tbreak writeBatch\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Finalize transcation.\n\t\t\t\t\terrs <- tx.Commit(db.ctx)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tcase <-db.ctx.Done():\n\t\t\t\tbreak writeBatch\n\t\t\t}\n\t\t}\n\n\t\t// Rollback transaction.\n\t\terrs <- tx.Rollback(db.ctx)\n\t}()\n\n\treturn batch, errs\n}\n\n// Delete deletes a record from the database.\nfunc (db *SQLite) Delete(key string) error {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\ttoDelete := &models.Record{Key: key}\n\treturn toDelete.Delete(db.ctx, db.bob)\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (db *SQLite) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t_, err := q.Check()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\tqueryIter := iterator.New()\n\n\tgo db.queryExecutor(queryIter, q, local, internal)\n\treturn queryIter, nil\n}\n\nfunc (db *SQLite) queryExecutor(queryIter *iterator.Iterator, q *query.Query, local, internal bool) {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t// Build query.\n\tvar recordQuery *sqlite.ViewQuery[*models.Record, models.RecordSlice]\n\tif q.DatabaseKeyPrefix() != \"\" {\n\t\trecordQuery = models.Records.View.Query(\n\t\t\tmodels.SelectWhere.Records.Key.Like(q.DatabaseKeyPrefix() + \"%\"),\n\t\t)\n\t} else {\n\t\trecordQuery = models.Records.View.Query()\n\t}\n\n\t// Get cursor to go over all records in the query.\n\tcursor, err := models.RecordsQuery.Cursor(recordQuery, db.ctx, db.bob)\n\tif err != nil {\n\t\tqueryIter.Finish(err)\n\t\treturn\n\t}\n\tdefer func() {\n\t\t_ = cursor.Close()\n\t}()\n\nrecordsLoop:\n\tfor cursor.Next() {\n\t\t// Get next record\n\t\tr, cErr := cursor.Get()\n\t\tif cErr != nil {\n\t\t\terr = fmt.Errorf(\"cursor error: %w\", cErr)\n\t\t\tbreak recordsLoop\n\t\t}\n\n\t\t// Check if key matches.\n\t\tif !q.MatchesKey(r.Key) {\n\t\t\tcontinue recordsLoop\n\t\t}\n\n\t\t// Check Meta.\n\t\tm := getMeta(r)\n\t\tif !m.CheckValidity() ||\n\t\t\t!m.CheckPermission(local, internal) {\n\t\t\tcontinue recordsLoop\n\t\t}\n\n\t\t// Check Data.\n\t\tif q.HasWhereCondition() {\n\t\t\tif r.Format.IsNull() || r.Value.IsNull() {\n\t\t\t\tcontinue recordsLoop\n\t\t\t}\n\n\t\t\tjsonData := string(r.Value.GetOrZero())\n\t\t\tjsonAccess := accessor.NewJSONAccessor(&jsonData)\n\t\t\tif !q.MatchesAccessor(jsonAccess) {\n\t\t\t\tcontinue recordsLoop\n\t\t\t}\n\t\t}\n\n\t\t// Build database record.\n\t\tmatched, _ := record.NewWrapperFromDatabase(\n\t\t\tdb.name,\n\t\t\tr.Key,\n\t\t\tm,\n\t\t\tuint8(r.Format.GetOrZero()), //nolint:gosec // Values are within uint8.\n\t\t\tr.Value.GetOrZero(),\n\t\t)\n\n\t\tselect {\n\t\tcase <-queryIter.Done:\n\t\t\tbreak recordsLoop\n\t\tcase queryIter.Next <- matched:\n\t\tdefault:\n\t\t\tselect {\n\t\t\tcase <-queryIter.Done:\n\t\t\t\tbreak recordsLoop\n\t\t\tcase queryIter.Next <- matched:\n\t\t\tcase <-time.After(1 * time.Second):\n\t\t\t\terr = ErrQueryTimeout\n\t\t\t\tbreak recordsLoop\n\t\t\t}\n\t\t}\n\n\t}\n\n\tqueryIter.Finish(err)\n}\n\n// Purge deletes all records that match the given query. It returns the number of successful deletes and an error.\nfunc (db *SQLite) Purge(ctx context.Context, q *query.Query, local, internal, shadowDelete bool) (int, error) {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t// Optimize for local and internal queries without where clause and without shadow delete.\n\tif local && internal && !shadowDelete && !q.HasWhereCondition() {\n\t\t// First count entries (SQLite does not support affected rows)\n\t\tn, err := models.Records.Query(\n\t\t\tmodels.SelectWhere.Records.Key.Like(q.DatabaseKeyPrefix()+\"%\"),\n\t\t).Count(db.ctx, db.bob)\n\t\tif err != nil || n == 0 {\n\t\t\treturn int(n), err\n\t\t}\n\n\t\t// Delete entries.\n\t\t_, err = models.Records.Delete(\n\t\t\tmodels.DeleteWhere.Records.Key.Like(q.DatabaseKeyPrefix()+\"%\"),\n\t\t).Exec(db.ctx, db.bob)\n\t\treturn int(n), err\n\t}\n\n\t// Optimize for local and internal queries without where clause, but with shadow delete.\n\tif local && internal && shadowDelete && !q.HasWhereCondition() {\n\t\t// First count entries (SQLite does not support affected rows)\n\t\tn, err := models.Records.Query(\n\t\t\tmodels.SelectWhere.Records.Key.Like(q.DatabaseKeyPrefix()+\"%\"),\n\t\t).Count(db.ctx, db.bob)\n\t\tif err != nil || n == 0 {\n\t\t\treturn int(n), err\n\t\t}\n\n\t\t// Mark purged records as deleted.\n\t\tnow := time.Now().Unix()\n\t\t_, err = models.Records.Update(\n\t\t\tum.SetCol(\"format\").ToArg(nil),\n\t\t\tum.SetCol(\"value\").ToArg(nil),\n\t\t\tum.SetCol(\"deleted\").ToArg(now),\n\t\t\tmodels.UpdateWhere.Records.Key.Like(q.DatabaseKeyPrefix()+\"%\"),\n\t\t).Exec(db.ctx, db.bob)\n\t\treturn int(n), err\n\t}\n\n\t// Otherwise, iterate over all entries and delete matching ones.\n\n\t// TODO: Non-local, non-internal or content matching queries are not supported at the moment.\n\treturn 0, storage.ErrNotImplemented\n}\n\n// PurgeOlderThan deletes all records last updated before the given time. It returns the number of successful deletes and an error.\nfunc (db *SQLite) PurgeOlderThan(ctx context.Context, prefix string, purgeBefore time.Time, local, internal, shadowDelete bool) (int, error) {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\tpurgeBeforeInt := purgeBefore.Unix()\n\n\t// Optimize for local and internal queries without where clause and without shadow delete.\n\tif local && internal && !shadowDelete {\n\t\t// First count entries (SQLite does not support affected rows)\n\t\tn, err := models.Records.Query(\n\t\t\tmodels.SelectWhere.Records.Key.Like(prefix+\"%\"),\n\t\t\tmodels.SelectWhere.Records.Modified.LT(purgeBeforeInt),\n\t\t).Count(db.ctx, db.bob)\n\t\tif err != nil || n == 0 {\n\t\t\treturn int(n), err\n\t\t}\n\n\t\t// Delete entries.\n\t\t_, err = models.Records.Delete(\n\t\t\tmodels.DeleteWhere.Records.Key.Like(prefix+\"%\"),\n\t\t\tmodels.DeleteWhere.Records.Modified.LT(purgeBeforeInt),\n\t\t).Exec(db.ctx, db.bob)\n\t\treturn int(n), err\n\t}\n\n\t// Optimize for local and internal queries without where clause, but with shadow delete.\n\tif local && internal && shadowDelete {\n\t\t// First count entries (SQLite does not support affected rows)\n\t\tn, err := models.Records.Query(\n\t\t\tmodels.SelectWhere.Records.Key.Like(prefix+\"%\"),\n\t\t\tmodels.SelectWhere.Records.Modified.LT(purgeBeforeInt),\n\t\t).Count(db.ctx, db.bob)\n\t\tif err != nil || n == 0 {\n\t\t\treturn int(n), err\n\t\t}\n\n\t\t// Mark purged records as deleted.\n\t\tnow := time.Now().Unix()\n\t\t_, err = models.Records.Update(\n\t\t\tum.SetCol(\"format\").ToArg(nil),\n\t\t\tum.SetCol(\"value\").ToArg(nil),\n\t\t\tum.SetCol(\"deleted\").ToArg(now),\n\t\t\tmodels.UpdateWhere.Records.Key.Like(prefix+\"%\"),\n\t\t\tmodels.UpdateWhere.Records.Modified.LT(purgeBeforeInt),\n\t\t).Exec(db.ctx, db.bob)\n\t\treturn int(n), err\n\t}\n\n\t// TODO: Non-local or non-internal queries are not supported at the moment.\n\treturn 0, storage.ErrNotImplemented\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (db *SQLite) ReadOnly() bool {\n\treturn false\n}\n\n// Injected returns whether the database is injected.\nfunc (db *SQLite) Injected() bool {\n\treturn false\n}\n\n// MaintainRecordStates maintains records states in the database.\nfunc (db *SQLite) MaintainRecordStates(ctx context.Context, purgeDeletedBefore time.Time, shadowDelete bool) error {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\tnow := time.Now().Unix()\n\tpurgeThreshold := purgeDeletedBefore.Unix()\n\n\t// Option 1: Using shadow delete.\n\tif shadowDelete {\n\t\t// Mark expired records as deleted.\n\t\t_, err := models.Records.Update(\n\t\t\tum.SetCol(\"format\").ToArg(nil),\n\t\t\tum.SetCol(\"value\").ToArg(nil),\n\t\t\tum.SetCol(\"deleted\").ToArg(now),\n\t\t\tmodels.UpdateWhere.Records.Deleted.EQ(0),\n\t\t\tmodels.UpdateWhere.Records.Expires.GT(0),\n\t\t\tmodels.UpdateWhere.Records.Expires.LT(now),\n\t\t).Exec(db.ctx, db.bob)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to shadow delete expired records: %w\", err)\n\t\t}\n\n\t\t// Purge deleted records before threshold.\n\t\t_, err = models.Records.Delete(\n\t\t\tmodels.DeleteWhere.Records.Deleted.GT(0),\n\t\t\tmodels.DeleteWhere.Records.Deleted.LT(purgeThreshold),\n\t\t).Exec(db.ctx, db.bob)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to purge deleted records (before threshold): %w\", err)\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Option 2: Immediate delete.\n\n\t// Delete expired record.\n\t_, err := models.Records.Delete(\n\t\tmodels.DeleteWhere.Records.Expires.GT(0),\n\t\tmodels.DeleteWhere.Records.Expires.LT(now),\n\t).Exec(db.ctx, db.bob)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete expired records: %w\", err)\n\t}\n\n\t// Delete shadow deleted records.\n\t_, err = models.Records.Delete(\n\t\tmodels.DeleteWhere.Records.Deleted.GT(0),\n\t).Exec(db.ctx, db.bob)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to purge deleted records: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (db *SQLite) Maintain(ctx context.Context) error {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t// Remove up to about 100KB of SQLite pages from the freelist on every run.\n\t// (Assuming 4KB page size.)\n\t_, err := db.db.ExecContext(ctx, \"PRAGMA incremental_vacuum(25);\")\n\treturn err\n}\n\nfunc (db *SQLite) MaintainThorough(ctx context.Context) error {\n\tdb.wg.Add(1)\n\tdefer db.wg.Done()\n\n\t// Remove all pages from the freelist.\n\t_, err := db.db.ExecContext(ctx, \"PRAGMA incremental_vacuum;\")\n\treturn err\n}\n\n// Shutdown shuts down the database.\nfunc (db *SQLite) Shutdown() error {\n\tdb.wg.Wait()\n\tdb.cancelCtx()\n\n\treturn db.bob.Close()\n}\n\ntype statementLogger struct{}\n\nfunc (sl statementLogger) Log(ctx context.Context, level sqldblogger.Level, msg string, data map[string]interface{}) {\n\tfmt.Printf(\"SQL: %s --- %+v\\n\", msg, data)\n}\n"
  },
  {
    "path": "base/database/storage/sqlite/sqlite_test.go",
    "content": "package sqlite\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\nvar (\n\t// Compile time interface checks.\n\t_ storage.Interface = &SQLite{}\n\t_ storage.Batcher   = &SQLite{}\n\t_ storage.Purger    = &SQLite{}\n)\n\ntype TestRecord struct { //nolint:maligned\n\trecord.Base\n\tsync.Mutex\n\tS    string\n\tI    int\n\tI8   int8\n\tI16  int16\n\tI32  int32\n\tI64  int64\n\tUI   uint\n\tUI8  uint8\n\tUI16 uint16\n\tUI32 uint32\n\tUI64 uint64\n\tF32  float32\n\tF64  float64\n\tB    bool\n}\n\nfunc TestSQLite(t *testing.T) {\n\tt.Parallel()\n\n\t// start\n\ttestDir := t.TempDir()\n\tdb, err := openSQLite(\"test\", testDir, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer func() {\n\t\t// shutdown\n\t\terr = db.Shutdown()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}()\n\n\ta := &TestRecord{\n\t\tS:    \"banana\",\n\t\tI:    42,\n\t\tI8:   42,\n\t\tI16:  42,\n\t\tI32:  42,\n\t\tI64:  42,\n\t\tUI:   42,\n\t\tUI8:  42,\n\t\tUI16: 42,\n\t\tUI32: 42,\n\t\tUI64: 42,\n\t\tF32:  42.42,\n\t\tF64:  42.42,\n\t\tB:    true,\n\t}\n\ta.SetMeta(&record.Meta{})\n\ta.Meta().Update()\n\ta.SetKey(\"test:A\")\n\n\t// put record\n\t_, err = db.Put(a)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// get and compare\n\tr1, err := db.Get(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ta1 := &TestRecord{}\n\terr = record.Unwrap(r1, a1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tassert.Equal(t, a, a1, \"struct must match\")\n\n\t// setup query test records\n\tqA := &TestRecord{}\n\tqA.SetKey(\"test:path/to/A\")\n\tqA.UpdateMeta()\n\n\tqB := &TestRecord{}\n\tqB.SetKey(\"test:path/to/B\")\n\tqB.UpdateMeta()\n\t// Set creation/modification in the past.\n\tqB.Meta().Created = time.Now().Add(-time.Hour).Unix()\n\tqB.Meta().Modified = time.Now().Add(-time.Hour).Unix()\n\n\tqC := &TestRecord{}\n\tqC.SetKey(\"test:path/to/C\")\n\tqC.UpdateMeta()\n\t// Set expiry in the past.\n\tqC.Meta().Expires = time.Now().Add(-time.Hour).Unix()\n\n\tqZ := &TestRecord{}\n\tqZ.SetKey(\"test:z\")\n\tqZ.UpdateMeta()\n\n\tput, errs := db.PutMany(false)\n\tput <- qA\n\tput <- qB\n\tput <- qC\n\tput <- qZ\n\tclose(put)\n\terr = <-errs\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// test query\n\tq := query.New(\"test:path/to/\").MustBeValid()\n\tit, err := db.Query(q, true, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcnt := 0\n\tfor range it.Next {\n\t\tcnt++\n\t}\n\tif it.Err() != nil {\n\t\tt.Fatal(it.Err())\n\t}\n\tif cnt != 2 {\n\t\t// Note: One is expired.\n\t\tt.Fatalf(\"unexpected query result count: %d\", cnt)\n\t}\n\n\t// delete\n\terr = db.Delete(\"A\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// check if its gone\n\t_, err = db.Get(\"A\")\n\tif err == nil {\n\t\tt.Fatal(\"should fail\")\n\t}\n\n\t// purge older than\n\tn, err := db.PurgeOlderThan(t.Context(), \"path/to/\", time.Now().Add(-30*time.Minute), true, true, false)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif n != 1 {\n\t\tt.Fatalf(\"unexpected purge older than delete count: %d\", n)\n\t}\n\n\t// maintenance\n\terr = db.MaintainRecordStates(t.Context(), time.Now().Add(-time.Minute), true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// maintenance\n\terr = db.MaintainRecordStates(t.Context(), time.Now(), false)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// purge\n\tn, err = db.Purge(t.Context(), query.New(\"test:path/to/\").MustBeValid(), true, true, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif n != 1 {\n\t\tt.Fatalf(\"unexpected purge delete count: %d\", n)\n\t}\n\n\t// Maintenance\n\terr = db.Maintain(t.Context())\n\tif err != nil {\n\t\tt.Fatalf(\"Maintain: %s\", err)\n\t}\n\terr = db.MaintainThorough(t.Context())\n\tif err != nil {\n\t\tt.Fatalf(\"MaintainThorough: %s\", err)\n\t}\n\n\t// test query\n\tq = query.New(\"test\").MustBeValid()\n\tit, err = db.Query(q, true, true)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tcnt = 0\n\tfor range it.Next {\n\t\tcnt++\n\t}\n\tif it.Err() != nil {\n\t\tt.Fatal(it.Err())\n\t}\n\tif cnt != 1 {\n\t\tt.Fatalf(\"unexpected query result count: %d\", cnt)\n\t}\n}\n"
  },
  {
    "path": "base/database/storage/storages.go",
    "content": "package storage\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n)\n\n// A Factory creates a new database of it's type.\ntype Factory func(name, location string) (Interface, error)\n\nvar (\n\tstorages     = make(map[string]Factory)\n\tstoragesLock sync.Mutex\n)\n\n// Register registers a new storage type.\nfunc Register(name string, factory Factory) error {\n\tstoragesLock.Lock()\n\tdefer storagesLock.Unlock()\n\n\t_, ok := storages[name]\n\tif ok {\n\t\treturn errors.New(\"factory for this type already exists\")\n\t}\n\n\tstorages[name] = factory\n\treturn nil\n}\n\n// CreateDatabase starts a new database with the given name and storageType at location.\nfunc CreateDatabase(name, storageType, location string) (Interface, error) {\n\treturn nil, nil\n}\n\n// StartDatabase starts a new database with the given name and storageType at location.\nfunc StartDatabase(name, storageType, location string) (Interface, error) {\n\tstoragesLock.Lock()\n\tdefer storagesLock.Unlock()\n\n\tfactory, ok := storages[storageType]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"storage type %s not registered\", storageType)\n\t}\n\n\treturn factory(name, location)\n}\n"
  },
  {
    "path": "base/database/subscription.go",
    "content": "package database\n\nimport (\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// Subscription is a database subscription for updates.\ntype Subscription struct {\n\tq        *query.Query\n\tlocal    bool\n\tinternal bool\n\n\tFeed chan record.Record\n}\n\n// Cancel cancels the subscription.\nfunc (s *Subscription) Cancel() error {\n\tc, err := getController(s.q.DatabaseName())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc.subscriptionLock.Lock()\n\tdefer c.subscriptionLock.Unlock()\n\n\tfor key, sub := range c.subscriptions {\n\t\tif sub.q == s.q {\n\t\t\tc.subscriptions = append(c.subscriptions[:key], c.subscriptions[key+1:]...)\n\t\t\tclose(s.Feed) // this close is guarded by the controllers subscriptionLock.\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "base/info/version.go",
    "content": "package info\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"sync\"\n)\n\nvar (\n\tname    string\n\tlicense string\n\n\tversion       = \"dev build\"\n\tversionNumber = \"0.0.0\"\n\tbuildSource   = \"unknown\"\n\tbuildTime     = \"unknown\"\n\n\tinfo     *Info\n\tloadInfo sync.Once\n)\n\nfunc init() {\n\t// Replace space placeholders.\n\tbuildSource = strings.ReplaceAll(buildSource, \"_\", \" \")\n\tbuildTime = strings.ReplaceAll(buildTime, \"_\", \" \")\n\n\t// Convert version string from git tag to expected format.\n\tversion = strings.TrimSpace(strings.ReplaceAll(strings.TrimPrefix(version, \"v\"), \"_\", \" \"))\n\tversionNumber = strings.TrimSpace(strings.TrimSuffix(version, \"dev build\"))\n\tif versionNumber == \"\" {\n\t\tversionNumber = \"0.0.0\"\n\t}\n\n\t// Get build info.\n\tbuildInfo, _ := debug.ReadBuildInfo()\n\tbuildSettings := make(map[string]string)\n\tfor _, setting := range buildInfo.Settings {\n\t\tbuildSettings[setting.Key] = setting.Value\n\t}\n\n\t// Add \"dev build\" to version if repo is dirty.\n\tif buildSettings[\"vcs.modified\"] == \"true\" &&\n\t\t!strings.HasSuffix(version, \"dev build\") {\n\t\tversion += \" dev build\"\n\t}\n}\n\n// Info holds the programs meta information.\ntype Info struct { //nolint:maligned\n\tName          string\n\tVersion       string\n\tVersionNumber string\n\tLicense       string\n\n\tSource    string\n\tBuildTime string\n\tCGO       bool\n\n\tCommit     string\n\tCommitTime string\n\tDirty      bool\n\n\tdebug.BuildInfo\n}\n\n// Set sets meta information via the main routine. This should be the first thing your program calls.\nfunc Set(setName string, setVersion string, setLicenseName string) {\n\tname = setName\n\tlicense = setLicenseName\n\n\tif setVersion != \"\" {\n\t\tversion = setVersion\n\t\tversionNumber = setVersion\n\t}\n}\n\n// GetInfo returns all the meta information about the program.\nfunc GetInfo() *Info {\n\tloadInfo.Do(func() {\n\t\tbuildInfo, _ := debug.ReadBuildInfo()\n\t\tbuildSettings := make(map[string]string)\n\t\tfor _, setting := range buildInfo.Settings {\n\t\t\tbuildSettings[setting.Key] = setting.Value\n\t\t}\n\n\t\tinfo = &Info{\n\t\t\tName:          name,\n\t\t\tVersion:       version,\n\t\t\tVersionNumber: versionNumber,\n\t\t\tLicense:       license,\n\t\t\tSource:        buildSource,\n\t\t\tBuildTime:     buildTime,\n\t\t\tCGO:           buildSettings[\"CGO_ENABLED\"] == \"1\",\n\t\t\tCommit:        buildSettings[\"vcs.revision\"],\n\t\t\tCommitTime:    buildSettings[\"vcs.time\"],\n\t\t\tDirty:         buildSettings[\"vcs.modified\"] == \"true\",\n\t\t\tBuildInfo:     *buildInfo,\n\t\t}\n\n\t\tif info.Commit == \"\" {\n\t\t\tinfo.Commit = \"unknown\"\n\t\t}\n\t\tif info.CommitTime == \"\" {\n\t\t\tinfo.CommitTime = \"unknown\"\n\t\t}\n\t})\n\n\treturn info\n}\n\n// Version returns the annotated version.\nfunc Version() string {\n\treturn version\n}\n\n// VersionNumber returns the version number only.\nfunc VersionNumber() string {\n\treturn versionNumber\n}\n\n// FullVersion returns the full and detailed version string.\nfunc FullVersion() string {\n\tinfo := GetInfo()\n\tbuilder := new(strings.Builder)\n\n\t// Name and version.\n\tbuilder.WriteString(fmt.Sprintf(\"%s %s\\n\", info.Name, version))\n\n\t// Build info.\n\tcgoInfo := \"-cgo\"\n\tif info.CGO {\n\t\tcgoInfo = \"+cgo\"\n\t}\n\tbuilder.WriteString(fmt.Sprintf(\"\\nbuilt with %s (%s %s) for %s/%s\\n\", runtime.Version(), runtime.Compiler, cgoInfo, runtime.GOOS, runtime.GOARCH))\n\tbuilder.WriteString(fmt.Sprintf(\"  at %s\\n\", info.BuildTime))\n\n\t// Commit info.\n\tdirtyInfo := \"clean\"\n\tif info.Dirty {\n\t\tdirtyInfo = \"dirty\"\n\t}\n\tbuilder.WriteString(fmt.Sprintf(\"\\ncommit %s (%s)\\n\", info.Commit, dirtyInfo))\n\tbuilder.WriteString(fmt.Sprintf(\"  at %s\\n\", info.CommitTime))\n\tbuilder.WriteString(fmt.Sprintf(\"  from %s\\n\", info.Source))\n\n\tbuilder.WriteString(fmt.Sprintf(\"\\nLicensed under the %s license.\", license))\n\n\treturn builder.String()\n}\n\n// CondensedVersion returns the rather complete, but condensed version string.\nfunc CondensedVersion() string {\n\tinfo := GetInfo()\n\n\tcgoInfo := \"-cgo\"\n\tif info.CGO {\n\t\tcgoInfo = \"+cgo\"\n\t}\n\tdirtyInfo := \"clean\"\n\tif info.Dirty {\n\t\tdirtyInfo = \"dirty\"\n\t}\n\n\treturn fmt.Sprintf(\n\t\t\"%s %s (%s/%s; built with %s [%s %s] from %s [%s] at %s)\",\n\t\tinfo.Name, version,\n\t\truntime.GOOS, runtime.GOARCH,\n\t\truntime.Version(), runtime.Compiler, cgoInfo,\n\t\tinfo.Commit, dirtyInfo, info.CommitTime,\n\t)\n}\n\n// CheckVersion checks if the metadata is ok.\nfunc CheckVersion() error {\n\tswitch {\n\tcase strings.HasSuffix(os.Args[0], \".test\"):\n\t\treturn nil // testing on linux/darwin\n\tcase strings.HasSuffix(os.Args[0], \".test.exe\"):\n\t\treturn nil // testing on windows\n\tdefault:\n\t\t// check version information\n\t\tif name == \"\" || license == \"\" {\n\t\t\treturn errors.New(\"must call SetInfo() before calling CheckVersion()\")\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "base/log/formatting.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nvar counter uint16\n\nconst (\n\tmaxCount   uint16 = 999\n\ttimeFormat string = \"2006-01-02 15:04:05.000\"\n)\n\nfunc (s Severity) String() string {\n\tswitch s {\n\tcase TraceLevel:\n\t\treturn \"TRC\"\n\tcase DebugLevel:\n\t\treturn \"DBG\"\n\tcase InfoLevel:\n\t\treturn \"INF\"\n\tcase WarningLevel:\n\t\treturn \"WRN\"\n\tcase ErrorLevel:\n\t\treturn \"ERR\"\n\tcase CriticalLevel:\n\t\treturn \"CRT\"\n\tdefault:\n\t\treturn \"NON\"\n\t}\n}\n\nfunc formatLine(line *logLine, duplicates uint64, useColor bool) string {\n\tvar colorStart, colorEnd, colorDim, colorEndDim string\n\tif useColor {\n\t\tcolorStart = line.level.color()\n\t\tcolorEnd = endColor()\n\t\tcolorDim = dimColor()\n\t\tcolorEndDim = endDimColor()\n\t}\n\n\tcounter++\n\n\tvar fLine string\n\tif line.line == 0 {\n\t\tfLine = fmt.Sprintf(\n\t\t\t\"%s%s%s %s%s%s %s? %s %03d%s%s %s\",\n\n\t\t\tcolorDim,\n\t\t\tline.timestamp.Format(timeFormat),\n\t\t\tcolorEndDim,\n\n\t\t\tcolorStart,\n\t\t\tline.level.String(),\n\t\t\tcolorEnd,\n\n\t\t\tcolorDim,\n\n\t\t\trightArrow,\n\n\t\t\tcounter,\n\t\t\tformatDuplicates(duplicates),\n\t\t\tcolorEndDim,\n\n\t\t\tline.msg,\n\t\t)\n\t} else {\n\t\tfLen := len(line.file)\n\t\tfPartStart := fLen - 10\n\t\tif fPartStart < 0 {\n\t\t\tfPartStart = 0\n\t\t}\n\t\tfLine = fmt.Sprintf(\n\t\t\t\"%s%s%s %s%s%s %s%s:%03d %s %03d%s%s %s\",\n\n\t\t\tcolorDim,\n\t\t\tline.timestamp.Format(timeFormat),\n\t\t\tcolorEndDim,\n\n\t\t\tcolorStart,\n\t\t\tline.level.String(),\n\t\t\tcolorEnd,\n\n\t\t\tcolorDim,\n\t\t\tline.file[fPartStart:],\n\t\t\tline.line,\n\n\t\t\trightArrow,\n\n\t\t\tcounter,\n\t\t\tformatDuplicates(duplicates),\n\t\t\tcolorEndDim,\n\n\t\t\tline.msg,\n\t\t)\n\t}\n\n\tif line.tracer != nil {\n\t\t// append full trace time\n\t\tif len(line.tracer.logs) > 0 {\n\t\t\tfLine += fmt.Sprintf(\" Σ=%s\", line.timestamp.Sub(line.tracer.logs[0].timestamp))\n\t\t}\n\n\t\t// append all trace actions\n\t\tvar d time.Duration\n\t\tfor i, action := range line.tracer.logs {\n\t\t\t// set color\n\t\t\tif useColor {\n\t\t\t\tcolorStart = action.level.color()\n\t\t\t}\n\t\t\t// set filename length\n\t\t\tfLen := len(action.file)\n\t\t\tfPartStart := fLen - 10\n\t\t\tif fPartStart < 0 {\n\t\t\t\tfPartStart = 0\n\t\t\t}\n\t\t\t// format\n\t\t\tif i == len(line.tracer.logs)-1 { // last\n\t\t\t\td = line.timestamp.Sub(action.timestamp)\n\t\t\t} else {\n\t\t\t\td = line.tracer.logs[i+1].timestamp.Sub(action.timestamp)\n\t\t\t}\n\t\t\tfLine += fmt.Sprintf(\n\t\t\t\t\"\\n%s%23s%s %s%s%s %s%s:%03d %s%s     %s\",\n\t\t\t\tcolorDim,\n\t\t\t\td,\n\t\t\t\tcolorEndDim,\n\n\t\t\t\tcolorStart,\n\t\t\t\taction.level.String(),\n\t\t\t\tcolorEnd,\n\n\t\t\t\tcolorDim,\n\t\t\t\taction.file[fPartStart:],\n\t\t\t\taction.line,\n\n\t\t\t\trightArrow,\n\t\t\t\tcolorEndDim,\n\n\t\t\t\taction.msg,\n\t\t\t)\n\t\t}\n\t}\n\n\tif counter >= maxCount {\n\t\tcounter = 0\n\t}\n\n\treturn fLine\n}\n\nfunc formatDuplicates(duplicates uint64) string {\n\tif duplicates == 0 {\n\t\treturn \"\"\n\t}\n\treturn fmt.Sprintf(\" [%dx]\", duplicates+1)\n}\n"
  },
  {
    "path": "base/log/formatting_unix.go",
    "content": "//go:build !windows\n\npackage log\n\nconst (\n\trightArrow = \"▶\"\n\tleftArrow  = \"◀\"\n)\n\nconst (\n\tcolorDim     = \"\\033[2m\"\n\tcolorEndDim  = \"\\033[22m\"\n\tcolorRed     = \"\\033[91m\"\n\tcolorYellow  = \"\\033[93m\"\n\tcolorBlue    = \"\\033[34m\"\n\tcolorMagenta = \"\\033[35m\"\n\tcolorCyan    = \"\\033[36m\"\n\tcolorGreen   = \"\\033[92m\"\n\n\t// Saved for later:\n\t// colorBlack   = \"\\033[30m\" //.\n\t// colorGreen   = \"\\033[32m\" //.\n\t// colorWhite   = \"\\033[37m\" //.\n)\n\nfunc (s Severity) color() string {\n\tswitch s {\n\tcase DebugLevel:\n\t\treturn colorCyan\n\tcase InfoLevel:\n\t\treturn colorGreen\n\tcase WarningLevel:\n\t\treturn colorYellow\n\tcase ErrorLevel:\n\t\treturn colorRed\n\tcase CriticalLevel:\n\t\treturn colorMagenta\n\tcase TraceLevel:\n\t\treturn \"\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc endColor() string {\n\treturn \"\\033[0m\"\n}\n\nfunc blueColor() string {\n\treturn colorBlue\n}\n\nfunc dimColor() string {\n\treturn colorDim\n}\n\nfunc endDimColor() string {\n\treturn colorEndDim\n}\n"
  },
  {
    "path": "base/log/formatting_windows.go",
    "content": "package log\n\nimport (\n\t\"github.com/safing/portmaster/base/utils/osdetail\"\n)\n\nconst (\n\trightArrow = \">\"\n\tleftArrow  = \"<\"\n)\n\nconst (\n\tcolorDim     = \"\\033[2m\"\n\tcolorEndDim  = \"\\033[22m\"\n\tcolorRed     = \"\\033[91m\"\n\tcolorYellow  = \"\\033[93m\"\n\tcolorBlue    = \"\\033[34m\"\n\tcolorMagenta = \"\\033[35m\"\n\tcolorCyan    = \"\\033[36m\"\n\tcolorGreen   = \"\\033[92m\"\n\n\t// colorBlack   = \"\\033[30m\"\n\t// colorGreen   = \"\\033[32m\"\n\t// colorWhite   = \"\\033[37m\"\n)\n\nvar (\n\tcolorsSupported bool\n)\n\nfunc init() {\n\tcolorsSupported = osdetail.EnableColorSupport()\n}\n\nfunc (s Severity) color() string {\n\tif colorsSupported {\n\t\tswitch s {\n\t\tcase DebugLevel:\n\t\t\treturn colorCyan\n\t\tcase InfoLevel:\n\t\t\treturn colorGreen\n\t\tcase WarningLevel:\n\t\t\treturn colorYellow\n\t\tcase ErrorLevel:\n\t\t\treturn colorRed\n\t\tcase CriticalLevel:\n\t\t\treturn colorMagenta\n\t\tdefault:\n\t\t\treturn \"\"\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc endColor() string {\n\tif colorsSupported {\n\t\treturn \"\\033[0m\"\n\t}\n\treturn \"\"\n}\n\nfunc blueColor() string {\n\tif colorsSupported {\n\t\treturn colorBlue\n\t}\n\treturn \"\"\n}\n\nfunc dimColor() string {\n\tif colorsSupported {\n\t\treturn colorDim\n\t}\n\treturn \"\"\n}\n\nfunc endDimColor() string {\n\tif colorsSupported {\n\t\treturn colorEndDim\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "base/log/input.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar (\n\twarnLogLines = new(uint64)\n\terrLogLines  = new(uint64)\n\tcritLogLines = new(uint64)\n)\n\nfunc log(level Severity, msg string, tracer *ContextTracer) {\n\tif !started.IsSet() {\n\t\t// a bit resource intense, but keeps logs before logging started.\n\t\t// TODO: create option to disable logging\n\t\tgo func() {\n\t\t\t<-startedSignal\n\t\t\tlog(level, msg, tracer)\n\t\t}()\n\t\treturn\n\t}\n\n\t// Check log level.\n\tif uint32(level) < atomic.LoadUint32(logLevel) {\n\t\treturn\n\t}\n\n\t// get time\n\tnow := time.Now()\n\n\t// get file and line\n\t_, file, line, ok := runtime.Caller(2)\n\tif !ok {\n\t\tfile = \"\"\n\t\tline = 0\n\t} else {\n\t\tif len(file) > 3 {\n\t\t\tfile = file[:len(file)-3]\n\t\t} else {\n\t\t\tfile = \"\"\n\t\t}\n\t}\n\n\t// create log object\n\tlog := &logLine{\n\t\tmsg:       msg,\n\t\ttracer:    tracer,\n\t\tlevel:     level,\n\t\ttimestamp: now,\n\t\tfile:      file,\n\t\tline:      line,\n\t}\n\n\t// send log to processing\n\tselect {\n\tcase logBuffer <- log:\n\tdefault:\n\tforceEmptyingLoop:\n\t\t// force empty buffer until we can send to it\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase forceEmptyingOfBuffer <- struct{}{}:\n\t\t\tcase logBuffer <- log:\n\t\t\t\tbreak forceEmptyingLoop\n\t\t\t}\n\t\t}\n\t}\n\n\t// wake up writer if necessary\n\tif logsWaitingFlag.SetToIf(false, true) {\n\t\tselect {\n\t\tcase logsWaiting <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}\n}\n\nfunc fastcheck(level Severity) bool {\n\treturn uint32(level) >= atomic.LoadUint32(logLevel)\n}\n\n// Trace is used to log tiny steps. Log traces to context if you can!\nfunc Trace(msg string) {\n\tif fastcheck(TraceLevel) {\n\t\tlog(TraceLevel, msg, nil)\n\t}\n}\n\n// Tracef is used to log tiny steps. Log traces to context if you can!\nfunc Tracef(format string, things ...interface{}) {\n\tif fastcheck(TraceLevel) {\n\t\tlog(TraceLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Debug is used to log minor errors or unexpected events. These occurrences are usually not worth mentioning in itself, but they might hint at a bigger problem.\nfunc Debug(msg string) {\n\tif fastcheck(DebugLevel) {\n\t\tlog(DebugLevel, msg, nil)\n\t}\n}\n\n// Debugf is used to log minor errors or unexpected events. These occurrences are usually not worth mentioning in itself, but they might hint at a bigger problem.\nfunc Debugf(format string, things ...interface{}) {\n\tif fastcheck(DebugLevel) {\n\t\tlog(DebugLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Info is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen.\nfunc Info(msg string) {\n\tif fastcheck(InfoLevel) {\n\t\tlog(InfoLevel, msg, nil)\n\t}\n}\n\n// Infof is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen.\nfunc Infof(format string, things ...interface{}) {\n\tif fastcheck(InfoLevel) {\n\t\tlog(InfoLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Warning is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet.\nfunc Warning(msg string) {\n\tatomic.AddUint64(warnLogLines, 1)\n\tif fastcheck(WarningLevel) {\n\t\tlog(WarningLevel, msg, nil)\n\t}\n}\n\n// Warningf is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet.\nfunc Warningf(format string, things ...interface{}) {\n\tatomic.AddUint64(warnLogLines, 1)\n\tif fastcheck(WarningLevel) {\n\t\tlog(WarningLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Error is used to log errors that break or impair functionality. The task/process may have to be aborted and tried again later. The system is still operational. Maybe User/Admin should be informed.\nfunc Error(msg string) {\n\tatomic.AddUint64(errLogLines, 1)\n\tif fastcheck(ErrorLevel) {\n\t\tlog(ErrorLevel, msg, nil)\n\t}\n}\n\n// Errorf is used to log errors that break or impair functionality. The task/process may have to be aborted and tried again later. The system is still operational.\nfunc Errorf(format string, things ...interface{}) {\n\tatomic.AddUint64(errLogLines, 1)\n\tif fastcheck(ErrorLevel) {\n\t\tlog(ErrorLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Critical is used to log events that completely break the system. Operation cannot continue. User/Admin must be informed.\nfunc Critical(msg string) {\n\tatomic.AddUint64(critLogLines, 1)\n\tif fastcheck(CriticalLevel) {\n\t\tlog(CriticalLevel, msg, nil)\n\t}\n}\n\n// Criticalf is used to log events that completely break the system. Operation cannot continue. User/Admin must be informed.\nfunc Criticalf(format string, things ...interface{}) {\n\tatomic.AddUint64(critLogLines, 1)\n\tif fastcheck(CriticalLevel) {\n\t\tlog(CriticalLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// TotalWarningLogLines returns the total amount of warning log lines since\n// start of the program.\nfunc TotalWarningLogLines() uint64 {\n\treturn atomic.LoadUint64(warnLogLines)\n}\n\n// TotalErrorLogLines returns the total amount of error log lines since start\n// of the program.\nfunc TotalErrorLogLines() uint64 {\n\treturn atomic.LoadUint64(errLogLines)\n}\n\n// TotalCriticalLogLines returns the total amount of critical log lines since\n// start of the program.\nfunc TotalCriticalLogLines() uint64 {\n\treturn atomic.LoadUint64(critLogLines)\n}\n"
  },
  {
    "path": "base/log/logging.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"log/slog\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n)\n\n// concept\n/*\n- Logging function:\n  - check if file-based levelling enabled\n    - if yes, check if level is active on this file\n  - check if level is active\n  - send data to backend via big buffered channel\n- Backend:\n  - wait until there is time for writing logs\n  - write logs\n  - configurable if logged to folder (buffer + rollingFileAppender) and/or console\n  - console: log everything above INFO to stderr\n- Channel overbuffering protection:\n  - if buffer is full, trigger write\n- Anti-Importing-Loop:\n  - everything imports logging\n  - logging is configured by main module and is supplied access to configuration and taskmanager\n*/\n\n// Severity describes a log level.\ntype Severity uint32\n\nfunc (s Severity) toSLogLevel() slog.Level {\n\t// Convert to slog level.\n\tswitch s {\n\tcase TraceLevel:\n\t\treturn slog.LevelDebug\n\tcase DebugLevel:\n\t\treturn slog.LevelDebug\n\tcase InfoLevel:\n\t\treturn slog.LevelInfo\n\tcase WarningLevel:\n\t\treturn slog.LevelWarn\n\tcase ErrorLevel:\n\t\treturn slog.LevelError\n\tcase CriticalLevel:\n\t\treturn slog.LevelError\n\t}\n\t// Failed to convert, return default log level\n\treturn slog.LevelWarn\n}\n\n// Message describes a log level message and is implemented\n// by logLine.\ntype Message interface {\n\tText() string\n\tSeverity() Severity\n\tTime() time.Time\n\tFile() string\n\tLineNumber() int\n}\n\ntype logLine struct {\n\tmsg       string\n\ttracer    *ContextTracer\n\tlevel     Severity\n\ttimestamp time.Time\n\tfile      string\n\tline      int\n}\n\nfunc (ll *logLine) Text() string {\n\treturn ll.msg\n}\n\nfunc (ll *logLine) Severity() Severity {\n\treturn ll.level\n}\n\nfunc (ll *logLine) Time() time.Time {\n\treturn ll.timestamp\n}\n\nfunc (ll *logLine) File() string {\n\treturn ll.file\n}\n\nfunc (ll *logLine) LineNumber() int {\n\treturn ll.line\n}\n\nfunc (ll *logLine) Equal(ol *logLine) bool {\n\tswitch {\n\tcase ll.msg != ol.msg:\n\t\treturn false\n\tcase ll.tracer != nil || ol.tracer != nil:\n\t\treturn false\n\tcase ll.file != ol.file:\n\t\treturn false\n\tcase ll.line != ol.line:\n\t\treturn false\n\tcase ll.level != ol.level:\n\t\treturn false\n\t}\n\treturn true\n}\n\n// Log Levels.\nconst (\n\tTraceLevel    Severity = 1\n\tDebugLevel    Severity = 2\n\tInfoLevel     Severity = 3\n\tWarningLevel  Severity = 4\n\tErrorLevel    Severity = 5\n\tCriticalLevel Severity = 6\n)\n\nvar (\n\tlogBuffer             chan *logLine\n\tforceEmptyingOfBuffer = make(chan struct{})\n\n\tlogLevelInt = uint32(InfoLevel)\n\tlogLevel    = &logLevelInt\n\n\tlogsWaiting     = make(chan struct{}, 1)\n\tlogsWaitingFlag = abool.NewBool(false)\n\n\tshutdownFlag      = abool.NewBool(false)\n\tshutdownSignal    = make(chan struct{})\n\tshutdownWaitGroup sync.WaitGroup\n\n\tinitializing  = abool.NewBool(false)\n\tstarted       = abool.NewBool(false)\n\tstartedSignal = make(chan struct{})\n)\n\n// GetLogLevel returns the current log level.\nfunc GetLogLevel() Severity {\n\treturn Severity(atomic.LoadUint32(logLevel))\n}\n\n// SetLogLevel sets a new log level. Only effective after Start().\nfunc SetLogLevel(level Severity) {\n\tatomic.StoreUint32(logLevel, uint32(level))\n\n\t// Setup slog here for the transition period.\n\tsetupSLog(level)\n}\n\n// Name returns the name of the log level.\nfunc (s Severity) Name() string {\n\tswitch s {\n\tcase TraceLevel:\n\t\treturn \"trace\"\n\tcase DebugLevel:\n\t\treturn \"debug\"\n\tcase InfoLevel:\n\t\treturn \"info\"\n\tcase WarningLevel:\n\t\treturn \"warning\"\n\tcase ErrorLevel:\n\t\treturn \"error\"\n\tcase CriticalLevel:\n\t\treturn \"critical\"\n\tdefault:\n\t\treturn \"none\"\n\t}\n}\n\n// ParseLevel returns the level severity of a log level name.\nfunc ParseLevel(level string) Severity {\n\tswitch strings.ToLower(level) {\n\tcase \"trace\":\n\t\treturn 1\n\tcase \"debug\":\n\t\treturn 2\n\tcase \"info\":\n\t\treturn 3\n\tcase \"warning\":\n\t\treturn 4\n\tcase \"error\":\n\t\treturn 5\n\tcase \"critical\":\n\t\treturn 6\n\t}\n\treturn 0\n}\n\n// Start starts the logging system. Must be called in order to see logs.\nfunc Start(level string, logToStdout bool, logDir string) error {\n\tif !initializing.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Parse log level argument.\n\tinitialLogLevel := InfoLevel\n\tif level != \"\" {\n\t\tinitialLogLevel = ParseLevel(level)\n\t\tif initialLogLevel == 0 {\n\t\t\tfmt.Fprintf(os.Stderr, \"log warning: invalid log level %q, falling back to level info\\n\", level)\n\t\t\tinitialLogLevel = InfoLevel\n\t\t}\n\t}\n\n\t// Setup writer.\n\tif logToStdout {\n\t\tGlobalWriter = NewStdoutWriter()\n\t} else {\n\t\t// Create file log writer.\n\t\tvar err error\n\t\tGlobalWriter, err = NewFileWriter(logDir)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to initialize log file: %w\", err)\n\t\t}\n\t}\n\n\t// Init logging systems.\n\tSetLogLevel(initialLogLevel)\n\tlogBuffer = make(chan *logLine, 1024)\n\n\tif !schedulingEnabled {\n\t\tclose(writeTrigger)\n\t}\n\tstartWriter()\n\n\tstarted.Set()\n\tclose(startedSignal)\n\n\t// Delete all logs older than one month.\n\tif !logToStdout {\n\t\terr := CleanOldLogs(logDir, 30*24*time.Hour)\n\t\tif err != nil {\n\t\t\tErrorf(\"log: failed to clean old log files: %s\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Shutdown writes remaining log lines and then stops the log system.\nfunc Shutdown() {\n\tif shutdownFlag.SetToIf(false, true) {\n\t\tclose(shutdownSignal)\n\t}\n\tshutdownWaitGroup.Wait()\n\tGlobalWriter.Close()\n}\n"
  },
  {
    "path": "base/log/logging_test.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc init() {\n\terr := Start(\"info\", true, \"\")\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"start failed: %s\", err))\n\t}\n}\n\nfunc TestLogging(t *testing.T) {\n\tt.Parallel()\n\n\t// skip\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\t// set levels (static random)\n\tSetLogLevel(WarningLevel)\n\tSetLogLevel(InfoLevel)\n\tSetLogLevel(ErrorLevel)\n\tSetLogLevel(DebugLevel)\n\tSetLogLevel(CriticalLevel)\n\tSetLogLevel(TraceLevel)\n\n\t// log\n\tTrace(\"Trace\")\n\tDebug(\"Debug\")\n\tInfo(\"Info\")\n\tWarning(\"Warning\")\n\tError(\"Error\")\n\tCritical(\"Critical\")\n\n\t// logf\n\tTracef(\"Trace %s\", \"f\")\n\tDebugf(\"Debug %s\", \"f\")\n\tInfof(\"Info %s\", \"f\")\n\tWarningf(\"Warning %s\", \"f\")\n\tErrorf(\"Error %s\", \"f\")\n\tCriticalf(\"Critical %s\", \"f\")\n\n\t// play with levels\n\tSetLogLevel(CriticalLevel)\n\tWarning(\"Warning\")\n\tSetLogLevel(TraceLevel)\n\n\t// log invalid level\n\tlog(0xFF, \"msg\", nil)\n\n\t// wait logs to be written\n\ttime.Sleep(1 * time.Millisecond)\n\n\t// do not really shut down, we may need logging for other tests\n\t// ShutdownLogging()\n}\n"
  },
  {
    "path": "base/log/output.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"runtime/debug\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/info\"\n)\n\n// Adapter is used to write logs.\ntype Adapter interface {\n\t// Write is called for each log message.\n\tWriteMessage(msg Message, duplicates uint64)\n}\n\nvar (\n\tschedulingEnabled = false\n\twriteTrigger      = make(chan struct{})\n)\n\n// EnableScheduling enables external scheduling of the logger. This will require to manually trigger writes via TriggerWrite whenever logs should be written. Please note that full buffers will also trigger writing. Must be called before Start() to have an effect.\nfunc EnableScheduling() {\n\tif !initializing.IsSet() {\n\t\tschedulingEnabled = true\n\t}\n}\n\n// TriggerWriter triggers log output writing.\nfunc TriggerWriter() {\n\tif started.IsSet() && schedulingEnabled {\n\t\tselect {\n\t\tcase writeTrigger <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}\n}\n\n// TriggerWriterChannel returns the channel to trigger log writing. Returned channel will close if EnableScheduling() is not called correctly.\nfunc TriggerWriterChannel() chan struct{} {\n\treturn writeTrigger\n}\n\nfunc startWriter() {\n\tif GlobalWriter.isStdout {\n\t\tfmt.Fprintf(GlobalWriter,\n\t\t\t\"%s%s%s %sBOF %s%s\\n\",\n\n\t\t\tdimColor(),\n\t\t\ttime.Now().Format(timeFormat),\n\t\t\tendDimColor(),\n\n\t\t\tblueColor(),\n\t\t\trightArrow,\n\t\t\tendColor(),\n\t\t)\n\t} else {\n\t\tfmt.Fprintf(GlobalWriter,\n\t\t\t\"%s BOF %s\\n\",\n\t\t\ttime.Now().Format(timeFormat),\n\t\t\trightArrow,\n\t\t)\n\t}\n\twriteVersion()\n\n\tshutdownWaitGroup.Add(1)\n\tgo writerManager()\n}\n\nfunc writeVersion() {\n\tif GlobalWriter.isStdout {\n\t\tfmt.Fprintf(GlobalWriter, \"%s%s%s running %s%s%s\\n\",\n\t\t\tdimColor(),\n\t\t\ttime.Now().Format(timeFormat),\n\t\t\tendDimColor(),\n\n\t\t\tblueColor(),\n\t\t\tinfo.CondensedVersion(),\n\t\t\tendColor())\n\t} else {\n\t\tfmt.Fprintf(GlobalWriter, \"%s running %s\\n\", time.Now().Format(timeFormat), info.CondensedVersion())\n\t}\n}\n\nfunc writerManager() {\n\tdefer shutdownWaitGroup.Done()\n\n\tfor {\n\t\terr := writer()\n\t\tif err != nil {\n\t\t\tErrorf(\"log: writer failed: %s\", err)\n\t\t} else {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc writer() error {\n\tvar err error\n\tdefer func() {\n\t\t// recover from panic\n\t\tpanicVal := recover()\n\t\tif panicVal != nil {\n\t\t\t_, err = fmt.Fprintf(GlobalWriter, \"%s\", panicVal)\n\n\t\t\t// write stack to stderr\n\t\t\tfmt.Fprintf(\n\t\t\t\tGlobalWriter,\n\t\t\t\t`===== Error Report =====\nMessage: %s\nStackTrace:\n\n%s\n===== End of Report =====\n`,\n\t\t\t\terr,\n\t\t\t\tstring(debug.Stack()),\n\t\t\t)\n\t\t}\n\t}()\n\n\tvar currentLine *logLine\n\tvar duplicates uint64\n\n\tfor {\n\t\t// reset\n\t\tcurrentLine = nil\n\t\tduplicates = 0\n\n\t\t// wait until logs need to be processed\n\t\tselect {\n\t\tcase <-logsWaiting: // normal process\n\t\t\tlogsWaitingFlag.UnSet()\n\t\tcase <-forceEmptyingOfBuffer: // log buffer is full!\n\t\tcase <-shutdownSignal: // shutting down\n\t\t\tfinalizeWriting()\n\t\t\treturn err\n\t\t}\n\n\t\t// wait for timeslot to log\n\t\tselect {\n\t\tcase <-writeTrigger: // normal process\n\t\tcase <-forceEmptyingOfBuffer: // log buffer is full!\n\t\tcase <-shutdownSignal: // shutting down\n\t\t\tfinalizeWriting()\n\t\t\treturn err\n\t\t}\n\n\t\t// write all the logs!\n\twriteLoop:\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase nextLine := <-logBuffer:\n\t\t\t\t// first line we process, just assign to currentLine\n\t\t\t\tif currentLine == nil {\n\t\t\t\t\tcurrentLine = nextLine\n\t\t\t\t\tcontinue writeLoop\n\t\t\t\t}\n\n\t\t\t\t// we now have currentLine and nextLine\n\n\t\t\t\t// if currentLine and nextLine are equal, do not print, just increase counter and continue\n\t\t\t\tif nextLine.Equal(currentLine) {\n\t\t\t\t\tduplicates++\n\t\t\t\t\tcontinue writeLoop\n\t\t\t\t}\n\n\t\t\t\t// if currentLine and line are _not_ equal, output currentLine\n\t\t\t\tGlobalWriter.WriteMessage(currentLine, duplicates)\n\t\t\t\t// add to unexpected logs\n\t\t\t\taddUnexpectedLogs(currentLine)\n\t\t\t\t// reset duplicate counter\n\t\t\t\tduplicates = 0\n\t\t\t\t// set new currentLine\n\t\t\t\tcurrentLine = nextLine\n\t\t\tdefault:\n\t\t\t\tbreak writeLoop\n\t\t\t}\n\t\t}\n\n\t\t// write final line\n\t\tif currentLine != nil {\n\t\t\tGlobalWriter.WriteMessage(currentLine, duplicates)\n\t\t\t// add to unexpected logs\n\t\t\taddUnexpectedLogs(currentLine)\n\t\t}\n\n\t\t// back down a little\n\t\tselect {\n\t\tcase <-time.After(10 * time.Millisecond):\n\t\tcase <-shutdownSignal:\n\t\t\tfinalizeWriting()\n\t\t\treturn err\n\t\t}\n\n\t}\n}\n\nfunc finalizeWriting() {\n\tfor {\n\t\tselect {\n\t\tcase line := <-logBuffer:\n\t\t\tGlobalWriter.WriteMessage(line, 0)\n\t\tcase <-time.After(10 * time.Millisecond):\n\t\t\tif GlobalWriter.isStdout {\n\t\t\t\tfmt.Fprintf(GlobalWriter,\n\t\t\t\t\t\"%s%s%s %sEOF %s%s\\n\",\n\n\t\t\t\t\tdimColor(),\n\t\t\t\t\ttime.Now().Format(timeFormat),\n\t\t\t\t\tendDimColor(),\n\n\t\t\t\t\tblueColor(),\n\t\t\t\t\tleftArrow,\n\t\t\t\t\tendColor(),\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(GlobalWriter,\n\t\t\t\t\t\"%s EOF %s\\n\",\n\t\t\t\t\ttime.Now().Format(timeFormat),\n\t\t\t\t\tleftArrow,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Last Unexpected Logs\n\nvar (\n\tlastUnexpectedLogs      [10]string\n\tlastUnexpectedLogsIndex int\n\tlastUnexpectedLogsLock  sync.Mutex\n)\n\nfunc addUnexpectedLogs(line *logLine) {\n\t// Add main line.\n\tif line.level >= WarningLevel {\n\t\taddUnexpectedLogLine(line)\n\t\treturn\n\t}\n\n\t// Check for unexpected lines in the tracer.\n\tif line.tracer != nil {\n\t\tfor _, traceLine := range line.tracer.logs {\n\t\t\tif traceLine.level >= WarningLevel {\n\t\t\t\t// Add full trace.\n\t\t\t\taddUnexpectedLogLine(line)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc addUnexpectedLogLine(line *logLine) {\n\tlastUnexpectedLogsLock.Lock()\n\tdefer lastUnexpectedLogsLock.Unlock()\n\n\t// Format line and add to logs.\n\tlastUnexpectedLogs[lastUnexpectedLogsIndex] = formatLine(line, 0, false)\n\n\t// Increase index and wrap back to start.\n\tlastUnexpectedLogsIndex = (lastUnexpectedLogsIndex + 1) % len(lastUnexpectedLogs)\n}\n\n// GetLastUnexpectedLogs returns the last 10 log lines of level Warning an up.\nfunc GetLastUnexpectedLogs() []string {\n\tlastUnexpectedLogsLock.Lock()\n\tdefer lastUnexpectedLogsLock.Unlock()\n\n\t// Make a copy and return.\n\tlogsLen := len(lastUnexpectedLogs)\n\tstart := lastUnexpectedLogsIndex\n\tlogsCopy := make([]string, 0, logsLen)\n\t// Loop from mid-to-mid.\n\tfor i := start; i < start+logsLen; i++ {\n\t\tif lastUnexpectedLogs[i%logsLen] != \"\" {\n\t\t\tlogsCopy = append(logsCopy, lastUnexpectedLogs[i%logsLen])\n\t\t}\n\t}\n\n\treturn logsCopy\n}\n"
  },
  {
    "path": "base/log/slog.go",
    "content": "package log\n\nimport (\n\t\"io\"\n\t\"log/slog\"\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/lmittmann/tint\"\n\t\"github.com/mattn/go-colorable\"\n\t\"github.com/mattn/go-isatty\"\n)\n\nfunc setupSLog(level Severity) {\n\t// TODO: Changes in the log level are not yet reflected onto the slog handlers in the modules.\n\n\t// Set highest possible level, so it can be changed in runtime.\n\thandlerLogLevel := level.toSLogLevel()\n\n\t// Create handler depending on OS.\n\tvar logHandler slog.Handler\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\tlogHandler = tint.NewHandler(\n\t\t\twindowsColoring(GlobalWriter), // Enable coloring on Windows.\n\t\t\t&tint.Options{\n\t\t\t\tAddSource:  true,\n\t\t\t\tLevel:      handlerLogLevel,\n\t\t\t\tTimeFormat: timeFormat,\n\t\t\t\tNoColor:    !( /* Color: */ GlobalWriter.IsStdout() && isatty.IsTerminal(GlobalWriter.file.Fd())),\n\t\t\t},\n\t\t)\n\n\tcase \"linux\":\n\t\tlogHandler = tint.NewHandler(GlobalWriter, &tint.Options{\n\t\t\tAddSource:  true,\n\t\t\tLevel:      handlerLogLevel,\n\t\t\tTimeFormat: timeFormat,\n\t\t\tNoColor:    !( /* Color: */ GlobalWriter.IsStdout() && isatty.IsTerminal(GlobalWriter.file.Fd())),\n\t\t})\n\n\tdefault:\n\t\tlogHandler = tint.NewHandler(os.Stdout, &tint.Options{\n\t\t\tAddSource:  true,\n\t\t\tLevel:      handlerLogLevel,\n\t\t\tTimeFormat: timeFormat,\n\t\t\tNoColor:    true,\n\t\t})\n\t}\n\n\t// Set as default logger.\n\tslog.SetDefault(slog.New(logHandler))\n}\n\nfunc windowsColoring(lw *LogWriter) io.Writer {\n\tif lw.IsStdout() {\n\t\treturn colorable.NewColorable(lw.file)\n\t}\n\treturn lw\n}\n"
  },
  {
    "path": "base/log/trace.go",
    "content": "package log\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// ContextTracerKey is the key used for the context key/value storage.\ntype ContextTracerKey struct{}\n\n// ContextTracer is attached to a context in order bind logs to a context.\ntype ContextTracer struct {\n\tsync.Mutex\n\tlogs []*logLine\n}\n\nvar key = ContextTracerKey{}\n\n// AddTracer adds a ContextTracer to the returned Context. Will return a nil ContextTracer if logging level is not set to trace. Will return a nil ContextTracer if one already exists. Will return a nil ContextTracer in case of an error. Will return a nil context if nil.\nfunc AddTracer(ctx context.Context) (context.Context, *ContextTracer) {\n\tif ctx != nil && fastcheck(TraceLevel) {\n\t\t// Check log level.\n\t\tif atomic.LoadUint32(logLevel) > uint32(TraceLevel) {\n\t\t\treturn ctx, nil\n\t\t}\n\n\t\t// check for existing tracer\n\t\t_, ok := ctx.Value(key).(*ContextTracer)\n\t\tif !ok {\n\t\t\t// add and return new tracer\n\t\t\ttracer := &ContextTracer{}\n\t\t\treturn context.WithValue(ctx, key, tracer), tracer\n\t\t}\n\t}\n\treturn ctx, nil\n}\n\n// Tracer returns the ContextTracer previously added to the given Context.\nfunc Tracer(ctx context.Context) *ContextTracer {\n\tif ctx != nil {\n\t\ttracer, ok := ctx.Value(key).(*ContextTracer)\n\t\tif ok {\n\t\t\treturn tracer\n\t\t}\n\t}\n\treturn nil\n}\n\n// Submit collected logs on the context for further processing/outputting. Does nothing if called on a nil ContextTracer.\nfunc (tracer *ContextTracer) Submit() {\n\tif tracer == nil {\n\t\treturn\n\t}\n\n\tif !started.IsSet() {\n\t\t// a bit resource intense, but keeps logs before logging started.\n\t\t// TODO: create option to disable logging\n\t\tgo func() {\n\t\t\t<-startedSignal\n\t\t\ttracer.Submit()\n\t\t}()\n\t\treturn\n\t}\n\n\tif len(tracer.logs) == 0 {\n\t\treturn\n\t}\n\n\t// extract last line as main line\n\tmainLine := tracer.logs[len(tracer.logs)-1]\n\ttracer.logs = tracer.logs[:len(tracer.logs)-1]\n\n\t// create log object\n\tlog := &logLine{\n\t\tmsg:       mainLine.msg,\n\t\ttracer:    tracer,\n\t\tlevel:     mainLine.level,\n\t\ttimestamp: mainLine.timestamp,\n\t\tfile:      mainLine.file,\n\t\tline:      mainLine.line,\n\t}\n\n\t// send log to processing\n\tselect {\n\tcase logBuffer <- log:\n\tdefault:\n\tforceEmptyingLoop:\n\t\t// force empty buffer until we can send to it\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase forceEmptyingOfBuffer <- struct{}{}:\n\t\t\tcase logBuffer <- log:\n\t\t\t\tbreak forceEmptyingLoop\n\t\t\t}\n\t\t}\n\t}\n\n\t// wake up writer if necessary\n\tif logsWaitingFlag.SetToIf(false, true) {\n\t\tlogsWaiting <- struct{}{}\n\t}\n}\n\nfunc (tracer *ContextTracer) log(level Severity, msg string) {\n\t// get file and line\n\t_, file, line, ok := runtime.Caller(2)\n\tif !ok {\n\t\tfile = \"\"\n\t\tline = 0\n\t} else {\n\t\tif len(file) > 3 {\n\t\t\tfile = file[:len(file)-3]\n\t\t} else {\n\t\t\tfile = \"\"\n\t\t}\n\t}\n\n\ttracer.Lock()\n\tdefer tracer.Unlock()\n\ttracer.logs = append(tracer.logs, &logLine{\n\t\ttimestamp: time.Now(),\n\t\tlevel:     level,\n\t\tmsg:       msg,\n\t\tfile:      file,\n\t\tline:      line,\n\t})\n}\n\n// Trace is used to log tiny steps. Log traces to context if you can!\nfunc (tracer *ContextTracer) Trace(msg string) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(TraceLevel, msg)\n\tcase fastcheck(TraceLevel):\n\t\tlog(TraceLevel, msg, nil)\n\t}\n}\n\n// Tracef is used to log tiny steps. Log traces to context if you can!\nfunc (tracer *ContextTracer) Tracef(format string, things ...interface{}) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(TraceLevel, fmt.Sprintf(format, things...))\n\tcase fastcheck(TraceLevel):\n\t\tlog(TraceLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Debug is used to log minor errors or unexpected events. These occurrences are usually not worth mentioning in itself, but they might hint at a bigger problem.\nfunc (tracer *ContextTracer) Debug(msg string) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(DebugLevel, msg)\n\tcase fastcheck(DebugLevel):\n\t\tlog(DebugLevel, msg, nil)\n\t}\n}\n\n// Debugf is used to log minor errors or unexpected events. These occurrences are usually not worth mentioning in itself, but they might hint at a bigger problem.\nfunc (tracer *ContextTracer) Debugf(format string, things ...interface{}) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(DebugLevel, fmt.Sprintf(format, things...))\n\tcase fastcheck(DebugLevel):\n\t\tlog(DebugLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Info is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen.\nfunc (tracer *ContextTracer) Info(msg string) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(InfoLevel, msg)\n\tcase fastcheck(InfoLevel):\n\t\tlog(InfoLevel, msg, nil)\n\t}\n}\n\n// Infof is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen.\nfunc (tracer *ContextTracer) Infof(format string, things ...interface{}) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(InfoLevel, fmt.Sprintf(format, things...))\n\tcase fastcheck(InfoLevel):\n\t\tlog(InfoLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Warning is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet.\nfunc (tracer *ContextTracer) Warning(msg string) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(WarningLevel, msg)\n\tcase fastcheck(WarningLevel):\n\t\tlog(WarningLevel, msg, nil)\n\t}\n}\n\n// Warningf is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet.\nfunc (tracer *ContextTracer) Warningf(format string, things ...interface{}) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(WarningLevel, fmt.Sprintf(format, things...))\n\tcase fastcheck(WarningLevel):\n\t\tlog(WarningLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Error is used to log errors that break or impair functionality. The task/process may have to be aborted and tried again later. The system is still operational. Maybe User/Admin should be informed.\nfunc (tracer *ContextTracer) Error(msg string) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(ErrorLevel, msg)\n\tcase fastcheck(ErrorLevel):\n\t\tlog(ErrorLevel, msg, nil)\n\t}\n}\n\n// Errorf is used to log errors that break or impair functionality. The task/process may have to be aborted and tried again later. The system is still operational.\nfunc (tracer *ContextTracer) Errorf(format string, things ...interface{}) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(ErrorLevel, fmt.Sprintf(format, things...))\n\tcase fastcheck(ErrorLevel):\n\t\tlog(ErrorLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n\n// Critical is used to log events that completely break the system. Operation connot continue. User/Admin must be informed.\nfunc (tracer *ContextTracer) Critical(msg string) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(CriticalLevel, msg)\n\tcase fastcheck(CriticalLevel):\n\t\tlog(CriticalLevel, msg, nil)\n\t}\n}\n\n// Criticalf is used to log events that completely break the system. Operation connot continue. User/Admin must be informed.\nfunc (tracer *ContextTracer) Criticalf(format string, things ...interface{}) {\n\tswitch {\n\tcase tracer != nil:\n\t\ttracer.log(CriticalLevel, fmt.Sprintf(format, things...))\n\tcase fastcheck(CriticalLevel):\n\t\tlog(CriticalLevel, fmt.Sprintf(format, things...), nil)\n\t}\n}\n"
  },
  {
    "path": "base/log/trace_test.go",
    "content": "package log\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestContextTracer(t *testing.T) {\n\tt.Parallel()\n\n\t// skip\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\tctx, tracer := AddTracer(context.Background())\n\t_ = Tracer(ctx)\n\n\ttracer.Trace(\"api: request received, checking security\")\n\ttime.Sleep(1 * time.Millisecond)\n\ttracer.Trace(\"login: logging in user\")\n\ttime.Sleep(1 * time.Millisecond)\n\ttracer.Trace(\"database: fetching requested resources\")\n\ttime.Sleep(10 * time.Millisecond)\n\ttracer.Warning(\"database: partial failure\")\n\ttime.Sleep(10 * time.Microsecond)\n\ttracer.Trace(\"renderer: rendering output\")\n\ttime.Sleep(1 * time.Millisecond)\n\ttracer.Trace(\"api: returning request\")\n\n\ttracer.Trace(\"api: completed request\")\n\ttracer.Submit()\n\ttime.Sleep(100 * time.Millisecond)\n}\n"
  },
  {
    "path": "base/log/writer.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"time\"\n)\n\n// GlobalWriter is the global log writer.\nvar GlobalWriter *LogWriter = nil\n\ntype LogWriter struct {\n\twriteLock sync.Mutex\n\tisStdout  bool\n\tfile      *os.File\n}\n\n// NewStdoutWriter creates a new log writer thet will write to the stdout.\nfunc NewStdoutWriter() *LogWriter {\n\treturn &LogWriter{\n\t\tfile:     os.Stdout,\n\t\tisStdout: true,\n\t}\n}\n\n// NewFileWriter creates a new log writer that will write to a file. The file path will be <dir>/2006-01-02_15-04-05.log (with current date and time)\nfunc NewFileWriter(dir string) (*LogWriter, error) {\n\t// Make sure log dir exists, if not, create with strict permission, as logs can contain sensitive data.\n\t_ = os.MkdirAll(dir, 0o700)\n\n\t// Open new log file.\n\tlogFile := time.Now().UTC().Format(\"2006-01-02_15-04-05\") + \".log\"\n\tfile, err := os.Create(filepath.Join(dir, logFile))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &LogWriter{\n\t\tfile:     file,\n\t\tisStdout: false,\n\t}, nil\n}\n\n// Write writes the buffer to the writer.\nfunc (l *LogWriter) Write(buf []byte) (int, error) {\n\tif l == nil {\n\t\treturn 0, fmt.Errorf(\"log writer not initialized\")\n\t}\n\n\t// No need to lock in stdout context.\n\tif !l.isStdout {\n\t\tl.writeLock.Lock()\n\t\tdefer l.writeLock.Unlock()\n\t}\n\n\treturn l.file.Write(buf)\n}\n\n// WriteMessage writes the message to the writer.\nfunc (l *LogWriter) WriteMessage(msg Message, duplicates uint64) {\n\tif l == nil {\n\t\treturn\n\t}\n\n\t// No need to lock in stdout context.\n\tif !l.isStdout {\n\t\tl.writeLock.Lock()\n\t\tdefer l.writeLock.Unlock()\n\t}\n\n\tfmt.Fprintln(l.file, formatLine(msg.(*logLine), duplicates, l.isStdout))\n}\n\n// IsStdout returns true if writer was initialized with stdout.\nfunc (l *LogWriter) IsStdout() bool {\n\treturn l != nil && l.isStdout\n}\n\n// Close closes the writer.\nfunc (l *LogWriter) Close() {\n\tif l != nil && !l.isStdout {\n\t\t_ = l.file.Close()\n\t}\n}\n\n// CleanOldLogs deletes all log files in given directory that are older than the given threshold.\nfunc CleanOldLogs(dir string, threshold time.Duration) error {\n\t// Get current log file name.\n\tvar currentLogFile string\n\tif GlobalWriter != nil && GlobalWriter.file != nil {\n\t\tcurrentLogFile = GlobalWriter.file.Name()\n\t}\n\n\t// Read dir entries.\n\tfiles, err := os.ReadDir(dir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read dir: %w\", err)\n\t}\n\n\t// Remove files older than threshold\n\tdeleteOlderThan := time.Now().Add(-threshold)\n\tfor _, f := range files {\n\t\t// Skip directories and the current log file.\n\t\tif f.IsDir() || f.Name() == currentLogFile {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Delete log files.\n\t\tif fileInfo, err := f.Info(); err == nil {\n\t\t\tif fileInfo.ModTime().Before(deleteOlderThan) {\n\t\t\t\t_ = os.Remove(filepath.Join(dir, f.Name()))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "base/metrics/api.go",
    "content": "package metrics\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc registerAPI() error {\n\tapi.RegisterHandler(\"/metrics\", &metricsAPI{})\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Export Registered Metrics\",\n\t\tDescription: \"List all registered metrics with their metadata.\",\n\t\tPath:        \"metrics/list\",\n\t\tRead:        api.Dynamic,\n\t\tStructFunc: func(ar *api.Request) (any, error) {\n\t\t\treturn ExportMetrics(ar.AuthToken.Read), nil\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Export Metric Values\",\n\t\tDescription: \"List all exportable metric values.\",\n\t\tPath:        \"metrics/values\",\n\t\tRead:        api.Dynamic,\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"internal-only\",\n\t\t\tDescription: \"Specify to only return metrics with an alternative internal ID.\",\n\t\t}},\n\t\tStructFunc: func(ar *api.Request) (any, error) {\n\t\t\treturn ExportValues(\n\t\t\t\tar.AuthToken.Read,\n\t\t\t\tar.Request.URL.Query().Has(\"internal-only\"),\n\t\t\t), nil\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\ntype metricsAPI struct{}\n\nfunc (m *metricsAPI) ReadPermission(*http.Request) api.Permission { return api.Dynamic }\n\nfunc (m *metricsAPI) WritePermission(*http.Request) api.Permission { return api.NotSupported }\n\nfunc (m *metricsAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\t// Get API Request for permission and query.\n\tar := api.GetAPIRequest(r)\n\tif ar == nil {\n\t\thttp.Error(w, \"Missing API Request.\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Get expertise level from query.\n\texpertiseLevel := config.ExpertiseLevelDeveloper\n\tswitch ar.Request.URL.Query().Get(\"level\") {\n\tcase config.ExpertiseLevelNameUser:\n\t\texpertiseLevel = config.ExpertiseLevelUser\n\tcase config.ExpertiseLevelNameExpert:\n\t\texpertiseLevel = config.ExpertiseLevelExpert\n\tcase config.ExpertiseLevelNameDeveloper:\n\t\texpertiseLevel = config.ExpertiseLevelDeveloper\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"text/plain; version=0.0.4; charset=utf-8\")\n\tw.WriteHeader(http.StatusOK)\n\tWriteMetrics(w, ar.AuthToken.Read, expertiseLevel)\n}\n\n// WriteMetrics writes all metrics that match the given permission and\n// expertiseLevel to the given writer.\nfunc WriteMetrics(w io.Writer, permission api.Permission, expertiseLevel config.ExpertiseLevel) {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\t// Write all matching metrics.\n\tfor _, metric := range registry {\n\t\tif permission >= metric.Opts().Permission &&\n\t\t\texpertiseLevel >= metric.Opts().ExpertiseLevel {\n\t\t\tmetric.WritePrometheus(w)\n\t\t}\n\t}\n}\n\nfunc writeMetricsTo(ctx context.Context, url string) error {\n\t// First, collect metrics into buffer.\n\tbuf := &bytes.Buffer{}\n\tWriteMetrics(buf, api.PermitSelf, config.ExpertiseLevelDeveloper)\n\n\t// Check if there is something to send.\n\tif buf.Len() == 0 {\n\t\tlog.Debugf(\"metrics: not pushing metrics, nothing to send\")\n\t\treturn nil\n\t}\n\n\t// Create request\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, buf)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create request: %w\", err)\n\t}\n\n\t// Send.\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = resp.Body.Close()\n\t}()\n\n\t// Check return status.\n\tif resp.StatusCode >= 200 && resp.StatusCode <= 299 {\n\t\treturn nil\n\t}\n\n\t// Get and return error.\n\tbody, _ := io.ReadAll(resp.Body)\n\treturn fmt.Errorf(\n\t\t\"got %s while writing metrics to %s: %s\",\n\t\tresp.Status,\n\t\turl,\n\t\tbody,\n\t)\n}\n\nfunc metricsWriter(ctx *mgr.WorkerCtx) error {\n\tpushURL := pushOption()\n\tmodule.metricTicker = mgr.NewSleepyTicker(1*time.Minute, 0)\n\tdefer module.metricTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-module.metricTicker.Wait():\n\t\t\terr := writeMetricsTo(ctx.Ctx(), pushURL)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/metrics/config.go",
    "content": "package metrics\n\nimport (\n\t\"flag\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/config\"\n)\n\n// Configuration Keys.\nvar (\n\tCfgOptionInstanceKey   = \"core/metrics/instance\"\n\tinstanceOption         config.StringOption\n\tcfgOptionInstanceOrder = 0\n\n\tCfgOptionCommentKey   = \"core/metrics/comment\"\n\tcommentOption         config.StringOption\n\tcfgOptionCommentOrder = 0\n\n\tCfgOptionPushKey   = \"core/metrics/push\"\n\tpushOption         config.StringOption\n\tcfgOptionPushOrder = 0\n\n\tinstanceFlag    string\n\tdefaultInstance string\n\tcommentFlag     string\n\tpushFlag        string\n)\n\nfunc init() {\n\thostname, err := os.Hostname()\n\tif err == nil {\n\t\thostname = strings.ReplaceAll(hostname, \"-\", \"\")\n\t\tif prometheusFormat.MatchString(hostname) {\n\t\t\tdefaultInstance = hostname\n\t\t}\n\t}\n\n\tflag.StringVar(&instanceFlag, \"metrics-instance\", defaultInstance, \"set the default metrics instance label for all metrics\")\n\tflag.StringVar(&commentFlag, \"metrics-comment\", \"\", \"set the default metrics comment label\")\n\tflag.StringVar(&pushFlag, \"push-metrics\", \"\", \"set default URL to push prometheus metrics to\")\n}\n\nfunc prepConfig() error {\n\terr := config.Register(&config.Option{\n\t\tName:            \"Metrics Instance Name\",\n\t\tKey:             CfgOptionInstanceKey,\n\t\tDescription:     \"Define the prometheus instance label for all exported metrics. Please note that changing the metrics instance name will reset persisted metrics.\",\n\t\tSensitive:       true,\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tDefaultValue:    instanceFlag,\n\t\tRequiresRestart: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionInstanceOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Metrics\",\n\t\t},\n\t\tValidationRegex: \"^(\" + prometheusBaseFormt + \")?$\",\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tinstanceOption = config.Concurrent.GetAsString(CfgOptionInstanceKey, instanceFlag)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Metrics Comment Label\",\n\t\tKey:             CfgOptionCommentKey,\n\t\tDescription:     \"Define a metrics comment label, which is added to the info metric.\",\n\t\tSensitive:       true,\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tDefaultValue:    commentFlag,\n\t\tRequiresRestart: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionCommentOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Metrics\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcommentOption = config.Concurrent.GetAsString(CfgOptionCommentKey, commentFlag)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Push Prometheus Metrics\",\n\t\tKey:             CfgOptionPushKey,\n\t\tDescription:     \"Push metrics to this URL in the prometheus format.\",\n\t\tSensitive:       true,\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tDefaultValue:    pushFlag,\n\t\tRequiresRestart: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionPushOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Metrics\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpushOption = config.Concurrent.GetAsString(CfgOptionPushKey, pushFlag)\n\n\treturn nil\n}\n"
  },
  {
    "path": "base/metrics/metric.go",
    "content": "package metrics\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\n\tvm \"github.com/VictoriaMetrics/metrics\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n)\n\n// PrometheusFormatRequirement is required format defined by prometheus for\n// metric and label names.\nconst (\n\tprometheusBaseFormt         = \"[a-zA-Z_][a-zA-Z0-9_]*\"\n\tPrometheusFormatRequirement = \"^\" + prometheusBaseFormt + \"$\"\n)\n\nvar prometheusFormat = regexp.MustCompile(PrometheusFormatRequirement)\n\n// Metric represents one or more metrics.\ntype Metric interface {\n\tID() string\n\tLabeledID() string\n\tOpts() *Options\n\tWritePrometheus(w io.Writer)\n}\n\ntype metricBase struct {\n\tIdentifier        string\n\tLabels            map[string]string\n\tLabeledIdentifier string\n\tOptions           *Options\n\tset               *vm.Set\n}\n\n// Options can be used to set advanced metric settings.\ntype Options struct {\n\t// Name defines an optional human readable name for the metric.\n\tName string\n\n\t// InternalID specifies an alternative internal ID that will be used when\n\t// exposing the metric via the API in a structured format.\n\tInternalID string\n\n\t// AlertLimit defines an upper limit that triggers an alert.\n\tAlertLimit float64\n\n\t// AlertTimeframe defines an optional timeframe in seconds for which the\n\t// AlertLimit should be interpreted in.\n\tAlertTimeframe float64\n\n\t// Permission defines the permission that is required to read the metric.\n\tPermission api.Permission\n\n\t// ExpertiseLevel defines the expertise level that the metric is meant for.\n\tExpertiseLevel config.ExpertiseLevel\n\n\t// Persist enabled persisting the metric on shutdown and loading the previous\n\t// value at start. This is only supported for counters.\n\tPersist bool\n}\n\nfunc newMetricBase(id string, labels map[string]string, opts Options) (*metricBase, error) {\n\t// Check formats.\n\tif !prometheusFormat.MatchString(strings.ReplaceAll(id, \"/\", \"_\")) {\n\t\treturn nil, fmt.Errorf(\"metric name %q must match %s\", id, PrometheusFormatRequirement)\n\t}\n\tfor labelName := range labels {\n\t\tif !prometheusFormat.MatchString(labelName) {\n\t\t\treturn nil, fmt.Errorf(\"metric label name %q must match %s\", labelName, PrometheusFormatRequirement)\n\t\t}\n\t}\n\n\t// Check permission.\n\tif opts.Permission < api.PermitAnyone {\n\t\t// Default to PermitUser.\n\t\topts.Permission = api.PermitUser\n\t}\n\n\t// Ensure that labels is a map.\n\tif labels == nil {\n\t\tlabels = make(map[string]string)\n\t}\n\n\t// Create metric base.\n\tbase := &metricBase{\n\t\tIdentifier: id,\n\t\tLabels:     labels,\n\t\tOptions:    &opts,\n\t\tset:        vm.NewSet(),\n\t}\n\tbase.LabeledIdentifier = base.buildLabeledID()\n\treturn base, nil\n}\n\n// ID returns the given ID of the metric.\nfunc (m *metricBase) ID() string {\n\treturn m.Identifier\n}\n\n// LabeledID returns the Prometheus-compatible labeled ID of the metric.\nfunc (m *metricBase) LabeledID() string {\n\treturn m.LabeledIdentifier\n}\n\n// Opts returns the metric options. They  may not be modified.\nfunc (m *metricBase) Opts() *Options {\n\treturn m.Options\n}\n\n// WritePrometheus writes the metric in the prometheus format to the given writer.\nfunc (m *metricBase) WritePrometheus(w io.Writer) {\n\tm.set.WritePrometheus(w)\n}\n\nfunc (m *metricBase) buildLabeledID() string {\n\t// Because we use the namespace and the global flags here, we need to flag\n\t// them as immutable.\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\tfirstMetricRegistered = true\n\n\t// Build ID from Identifier.\n\tmetricID := strings.TrimSpace(strings.ReplaceAll(m.Identifier, \"/\", \"_\"))\n\n\t// Add namespace to ID.\n\tif metricNamespace != \"\" {\n\t\tmetricID = metricNamespace + \"_\" + metricID\n\t}\n\n\t// Return now if no labels are defined.\n\tif len(globalLabels) == 0 && len(m.Labels) == 0 {\n\t\treturn metricID\n\t}\n\n\t// Add global labels to the custom ones, if they don't exist yet.\n\tfor labelName, labelValue := range globalLabels {\n\t\tif _, ok := m.Labels[labelName]; !ok {\n\t\t\tm.Labels[labelName] = labelValue\n\t\t}\n\t}\n\n\t// Render labels into a slice and sort them in order to make the labeled ID\n\t// reproducible.\n\tlabels := make([]string, 0, len(m.Labels))\n\tfor labelName, labelValue := range m.Labels {\n\t\tlabels = append(labels, fmt.Sprintf(\"%s=%q\", labelName, labelValue))\n\t}\n\tsort.Strings(labels)\n\n\t// Return fully labaled ID.\n\treturn fmt.Sprintf(\"%s{%s}\", metricID, strings.Join(labels, \",\"))\n}\n\n// Split metrics into sets, according to the API Auth Levels, which will also correspond to the UI Mode levels. SPN // nodes will also allow public access to metrics with the permission \"PermitAnyone\".\n// Save \"life-long\" metrics on shutdown and load them at start.\n// Generate the correct metric name and labels.\n// Expose metrics via http, but also via the runtime DB in order to push metrics to the UI.\n// The UI will have to parse the prometheus metrics format and will not be able to immediately present historical data, // but data will have to be built.\n// Provide the option to push metrics to a prometheus push gateway, this is especially helpful when gathering data from // loads of SPN nodes.\n"
  },
  {
    "path": "base/metrics/metric_counter.go",
    "content": "package metrics\n\nimport (\n\tvm \"github.com/VictoriaMetrics/metrics\"\n)\n\n// Counter is a counter metric.\ntype Counter struct {\n\t*metricBase\n\t*vm.Counter\n}\n\n// NewCounter registers a new counter metric.\nfunc NewCounter(id string, labels map[string]string, opts *Options) (*Counter, error) {\n\t// Ensure that there are options.\n\tif opts == nil {\n\t\topts = &Options{}\n\t}\n\n\t// Make base.\n\tbase, err := newMetricBase(id, labels, *opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create metric struct.\n\tm := &Counter{\n\t\tmetricBase: base,\n\t}\n\n\t// Create metric in set\n\tm.Counter = m.set.NewCounter(m.LabeledID())\n\n\t// Register metric.\n\terr = register(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Load state.\n\tm.loadState()\n\n\treturn m, nil\n}\n\n// CurrentValue returns the current counter value.\nfunc (c *Counter) CurrentValue() uint64 {\n\treturn c.Get()\n}\n"
  },
  {
    "path": "base/metrics/metric_counter_fetching.go",
    "content": "package metrics\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\tvm \"github.com/VictoriaMetrics/metrics\"\n)\n\n// FetchingCounter is a counter metric that fetches the values via a function call.\ntype FetchingCounter struct {\n\t*metricBase\n\tcounter  *vm.Counter\n\tfetchCnt func() uint64\n}\n\n// NewFetchingCounter registers a new fetching counter metric.\nfunc NewFetchingCounter(id string, labels map[string]string, fn func() uint64, opts *Options) (*FetchingCounter, error) {\n\t// Check if a fetch function is provided.\n\tif fn == nil {\n\t\treturn nil, fmt.Errorf(\"%w: no fetch function provided\", ErrInvalidOptions)\n\t}\n\n\t// Ensure that there are options.\n\tif opts == nil {\n\t\topts = &Options{}\n\t}\n\n\t// Make base.\n\tbase, err := newMetricBase(id, labels, *opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create metric struct.\n\tm := &FetchingCounter{\n\t\tmetricBase: base,\n\t\tfetchCnt:   fn,\n\t}\n\n\t// Create metric in set\n\tm.counter = m.set.NewCounter(m.LabeledID())\n\n\t// Register metric.\n\terr = register(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn m, nil\n}\n\n// CurrentValue returns the current counter value.\nfunc (fc *FetchingCounter) CurrentValue() uint64 {\n\treturn fc.fetchCnt()\n}\n\n// WritePrometheus writes the metric in the prometheus format to the given writer.\nfunc (fc *FetchingCounter) WritePrometheus(w io.Writer) {\n\tfc.counter.Set(fc.fetchCnt())\n\tfc.metricBase.set.WritePrometheus(w)\n}\n"
  },
  {
    "path": "base/metrics/metric_export.go",
    "content": "package metrics\n\nimport (\n\t\"github.com/safing/portmaster/base/api\"\n)\n\n// UIntMetric is an interface for special functions of uint metrics.\ntype UIntMetric interface {\n\tCurrentValue() uint64\n}\n\n// FloatMetric is an interface for special functions of float metrics.\ntype FloatMetric interface {\n\tCurrentValue() float64\n}\n\n// MetricExport is used to export a metric and its current value.\ntype MetricExport struct {\n\tMetric\n\tCurrentValue any\n}\n\n// ExportMetrics exports all registered metrics.\nfunc ExportMetrics(requestPermission api.Permission) []*MetricExport {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\texport := make([]*MetricExport, 0, len(registry))\n\tfor _, metric := range registry {\n\t\t// Check permission.\n\t\tif requestPermission < metric.Opts().Permission {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Add metric with current value.\n\t\texport = append(export, &MetricExport{\n\t\t\tMetric:       metric,\n\t\t\tCurrentValue: getCurrentValue(metric),\n\t\t})\n\t}\n\n\treturn export\n}\n\n// ExportValues exports the values of all supported metrics.\nfunc ExportValues(requestPermission api.Permission, internalOnly bool) map[string]any {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\texport := make(map[string]any, len(registry))\n\tfor _, metric := range registry {\n\t\t// Check permission.\n\t\tif requestPermission < metric.Opts().Permission {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get Value.\n\t\tv := getCurrentValue(metric)\n\t\tif v == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get ID.\n\t\tvar id string\n\t\tswitch {\n\t\tcase metric.Opts().InternalID != \"\":\n\t\t\tid = metric.Opts().InternalID\n\t\tcase internalOnly:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\tid = metric.LabeledID()\n\t\t}\n\n\t\t// Add to export\n\t\texport[id] = v\n\t}\n\n\treturn export\n}\n\nfunc getCurrentValue(metric Metric) any {\n\tif m, ok := metric.(UIntMetric); ok {\n\t\treturn m.CurrentValue()\n\t}\n\tif m, ok := metric.(FloatMetric); ok {\n\t\treturn m.CurrentValue()\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "base/metrics/metric_gauge.go",
    "content": "package metrics\n\nimport (\n\tvm \"github.com/VictoriaMetrics/metrics\"\n)\n\n// Gauge is a gauge metric.\ntype Gauge struct {\n\t*metricBase\n\t*vm.Gauge\n}\n\n// NewGauge registers a new gauge metric.\nfunc NewGauge(id string, labels map[string]string, fn func() float64, opts *Options) (*Gauge, error) {\n\t// Ensure that there are options.\n\tif opts == nil {\n\t\topts = &Options{}\n\t}\n\n\t// Make base.\n\tbase, err := newMetricBase(id, labels, *opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create metric struct.\n\tm := &Gauge{\n\t\tmetricBase: base,\n\t}\n\n\t// Create metric in set\n\tm.Gauge = m.set.NewGauge(m.LabeledID(), fn)\n\n\t// Register metric.\n\terr = register(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn m, nil\n}\n\n// CurrentValue returns the current gauge value.\nfunc (g *Gauge) CurrentValue() float64 {\n\treturn g.Get()\n}\n"
  },
  {
    "path": "base/metrics/metric_histogram.go",
    "content": "package metrics\n\nimport (\n\tvm \"github.com/VictoriaMetrics/metrics\"\n)\n\n// Histogram is a histogram metric.\ntype Histogram struct {\n\t*metricBase\n\t*vm.Histogram\n}\n\n// NewHistogram registers a new histogram metric.\nfunc NewHistogram(id string, labels map[string]string, opts *Options) (*Histogram, error) {\n\t// Ensure that there are options.\n\tif opts == nil {\n\t\topts = &Options{}\n\t}\n\n\t// Make base.\n\tbase, err := newMetricBase(id, labels, *opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create metric struct.\n\tm := &Histogram{\n\t\tmetricBase: base,\n\t}\n\n\t// Create metric in set\n\tm.Histogram = m.set.NewHistogram(m.LabeledID())\n\n\t// Register metric.\n\terr = register(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn m, nil\n}\n"
  },
  {
    "path": "base/metrics/metrics_host.go",
    "content": "package metrics\n\nimport (\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/shirou/gopsutil/disk\"\n\t\"github.com/shirou/gopsutil/load\"\n\t\"github.com/shirou/gopsutil/mem\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst hostStatTTL = 1 * time.Second\n\nfunc registerHostMetrics() (err error) {\n\t// Register load average metrics.\n\t_, err = NewGauge(\"host/load/avg/1\", nil, getFloat64HostStat(LoadAvg1), &Options{Name: \"Host Load Avg 1min\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/load/avg/5\", nil, getFloat64HostStat(LoadAvg5), &Options{Name: \"Host Load Avg 5min\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/load/avg/15\", nil, getFloat64HostStat(LoadAvg15), &Options{Name: \"Host Load Avg 15min\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Register memory usage metrics.\n\t_, err = NewGauge(\"host/mem/total\", nil, getUint64HostStat(MemTotal), &Options{Name: \"Host Memory Total\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/mem/used\", nil, getUint64HostStat(MemUsed), &Options{Name: \"Host Memory Used\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/mem/available\", nil, getUint64HostStat(MemAvailable), &Options{Name: \"Host Memory Available\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/mem/used/percent\", nil, getFloat64HostStat(MemUsedPercent), &Options{Name: \"Host Memory Used in Percent\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Register disk usage metrics.\n\t_, err = NewGauge(\"host/disk/total\", nil, getUint64HostStat(DiskTotal), &Options{Name: \"Host Disk Total\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/disk/used\", nil, getUint64HostStat(DiskUsed), &Options{Name: \"Host Disk Used\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/disk/free\", nil, getUint64HostStat(DiskFree), &Options{Name: \"Host Disk Free\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = NewGauge(\"host/disk/used/percent\", nil, getFloat64HostStat(DiskUsedPercent), &Options{Name: \"Host Disk Used in Percent\", Permission: api.PermitUser})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc getUint64HostStat(getStat func() (uint64, bool)) func() float64 {\n\treturn func() float64 {\n\t\tval, _ := getStat()\n\t\treturn float64(val)\n\t}\n}\n\nfunc getFloat64HostStat(getStat func() (float64, bool)) func() float64 {\n\treturn func() float64 {\n\t\tval, _ := getStat()\n\t\treturn val\n\t}\n}\n\nvar (\n\tloadAvg        *load.AvgStat\n\tloadAvgExpires time.Time\n\tloadAvgLock    sync.Mutex\n)\n\nfunc getLoadAvg() *load.AvgStat {\n\tloadAvgLock.Lock()\n\tdefer loadAvgLock.Unlock()\n\n\t// Return cache if still valid.\n\tif time.Now().Before(loadAvgExpires) {\n\t\treturn loadAvg\n\t}\n\n\t// Refresh.\n\tvar err error\n\tloadAvg, err = load.Avg()\n\tif err != nil {\n\t\tlog.Warningf(\"metrics: failed to get load avg: %s\", err)\n\t\tloadAvg = nil\n\t}\n\tloadAvgExpires = time.Now().Add(hostStatTTL)\n\n\treturn loadAvg\n}\n\n// LoadAvg1 returns the 1-minute average system load.\nfunc LoadAvg1() (loadAvg float64, ok bool) {\n\tif stat := getLoadAvg(); stat != nil {\n\t\treturn stat.Load1 / float64(runtime.NumCPU()), true\n\t}\n\treturn 0, false\n}\n\n// LoadAvg5 returns the 5-minute average system load.\nfunc LoadAvg5() (loadAvg float64, ok bool) {\n\tif stat := getLoadAvg(); stat != nil {\n\t\treturn stat.Load5 / float64(runtime.NumCPU()), true\n\t}\n\treturn 0, false\n}\n\n// LoadAvg15 returns the 15-minute average system load.\nfunc LoadAvg15() (loadAvg float64, ok bool) {\n\tif stat := getLoadAvg(); stat != nil {\n\t\treturn stat.Load15 / float64(runtime.NumCPU()), true\n\t}\n\treturn 0, false\n}\n\nvar (\n\tmemStat        *mem.VirtualMemoryStat\n\tmemStatExpires time.Time\n\tmemStatLock    sync.Mutex\n)\n\nfunc getMemStat() *mem.VirtualMemoryStat {\n\tmemStatLock.Lock()\n\tdefer memStatLock.Unlock()\n\n\t// Return cache if still valid.\n\tif time.Now().Before(memStatExpires) {\n\t\treturn memStat\n\t}\n\n\t// Refresh.\n\tvar err error\n\tmemStat, err = mem.VirtualMemory()\n\tif err != nil {\n\t\tlog.Warningf(\"metrics: failed to get load avg: %s\", err)\n\t\tmemStat = nil\n\t}\n\tmemStatExpires = time.Now().Add(hostStatTTL)\n\n\treturn memStat\n}\n\n// MemTotal returns the total system memory.\nfunc MemTotal() (total uint64, ok bool) {\n\tif stat := getMemStat(); stat != nil {\n\t\treturn stat.Total, true\n\t}\n\treturn 0, false\n}\n\n// MemUsed returns the used system memory.\nfunc MemUsed() (used uint64, ok bool) {\n\tif stat := getMemStat(); stat != nil {\n\t\treturn stat.Used, true\n\t}\n\treturn 0, false\n}\n\n// MemAvailable returns the available system memory.\nfunc MemAvailable() (available uint64, ok bool) {\n\tif stat := getMemStat(); stat != nil {\n\t\treturn stat.Available, true\n\t}\n\treturn 0, false\n}\n\n// MemUsedPercent returns the percent of used system memory.\nfunc MemUsedPercent() (usedPercent float64, ok bool) {\n\tif stat := getMemStat(); stat != nil {\n\t\treturn stat.UsedPercent, true\n\t}\n\treturn 0, false\n}\n\nvar (\n\tdiskStat        *disk.UsageStat\n\tdiskStatExpires time.Time\n\tdiskStatLock    sync.Mutex\n)\n\nfunc getDiskStat() *disk.UsageStat {\n\tdiskStatLock.Lock()\n\tdefer diskStatLock.Unlock()\n\n\t// Return cache if still valid.\n\tif time.Now().Before(diskStatExpires) {\n\t\treturn diskStat\n\t}\n\n\t// Refresh.\n\tvar err error\n\tdiskStat, err = disk.Usage(module.instance.DataDir())\n\tif err != nil {\n\t\tlog.Warningf(\"metrics: failed to get load avg: %s\", err)\n\t\tdiskStat = nil\n\t}\n\tdiskStatExpires = time.Now().Add(hostStatTTL)\n\n\treturn diskStat\n}\n\n// DiskTotal returns the total disk space (from the program's data root).\nfunc DiskTotal() (total uint64, ok bool) {\n\tif stat := getDiskStat(); stat != nil {\n\t\treturn stat.Total, true\n\t}\n\treturn 0, false\n}\n\n// DiskUsed returns the used disk space (from the program's data root).\nfunc DiskUsed() (used uint64, ok bool) {\n\tif stat := getDiskStat(); stat != nil {\n\t\treturn stat.Used, true\n\t}\n\treturn 0, false\n}\n\n// DiskFree returns the available disk space (from the program's data root).\nfunc DiskFree() (free uint64, ok bool) {\n\tif stat := getDiskStat(); stat != nil {\n\t\treturn stat.Free, true\n\t}\n\treturn 0, false\n}\n\n// DiskUsedPercent returns the percent of used disk space (from the program's data root).\nfunc DiskUsedPercent() (usedPercent float64, ok bool) {\n\tif stat := getDiskStat(); stat != nil {\n\t\treturn stat.UsedPercent, true\n\t}\n\treturn 0, false\n}\n"
  },
  {
    "path": "base/metrics/metrics_info.go",
    "content": "package metrics\n\nimport (\n\t\"runtime\"\n\t\"strings\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/info\"\n)\n\nvar reportedStart atomic.Bool\n\nfunc registerInfoMetric() error {\n\tmeta := info.GetInfo()\n\t_, err := NewGauge(\n\t\t\"info\",\n\t\tmap[string]string{\n\t\t\t\"version\":      checkUnknown(meta.Version),\n\t\t\t\"commit\":       checkUnknown(meta.Commit),\n\t\t\t\"build_date\":   checkUnknown(meta.BuildTime),\n\t\t\t\"build_source\": checkUnknown(meta.Source),\n\t\t\t\"go_os\":        runtime.GOOS,\n\t\t\t\"go_arch\":      runtime.GOARCH,\n\t\t\t\"go_version\":   runtime.Version(),\n\t\t\t\"go_compiler\":  runtime.Compiler,\n\t\t\t\"comment\":      commentOption(),\n\t\t},\n\t\tfunc() float64 {\n\t\t\t// Report as 0 the first time in order to detect (re)starts.\n\t\t\tif reportedStart.CompareAndSwap(false, true) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn 1\n\t\t},\n\t\tnil,\n\t)\n\treturn err\n}\n\nfunc checkUnknown(s string) string {\n\tif strings.Contains(s, \"unknown\") {\n\t\treturn \"unknown\"\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "base/metrics/metrics_logs.go",
    "content": "package metrics\n\nimport (\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nfunc registerLogMetrics() (err error) {\n\t_, err = NewFetchingCounter(\n\t\t\"logs/warning/total\",\n\t\tnil,\n\t\tlog.TotalWarningLogLines,\n\t\t&Options{\n\t\t\tName:       \"Total Warning Log Lines\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = NewFetchingCounter(\n\t\t\"logs/error/total\",\n\t\tnil,\n\t\tlog.TotalErrorLogLines,\n\t\t&Options{\n\t\t\tName:       \"Total Error Log Lines\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = NewFetchingCounter(\n\t\t\"logs/critical/total\",\n\t\tnil,\n\t\tlog.TotalCriticalLogLines,\n\t\t&Options{\n\t\t\tName:       \"Total Critical Log Lines\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "base/metrics/metrics_runtime.go",
    "content": "package metrics\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\tvm \"github.com/VictoriaMetrics/metrics\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nfunc registerRuntimeMetric() error {\n\truntimeBase, err := newMetricBase(\"_runtime\", nil, Options{\n\t\tName:           \"Golang Runtime\",\n\t\tPermission:     api.PermitAdmin,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn register(&runtimeMetrics{\n\t\tmetricBase: runtimeBase,\n\t})\n}\n\ntype runtimeMetrics struct {\n\t*metricBase\n}\n\nfunc (r *runtimeMetrics) WritePrometheus(w io.Writer) {\n\t// If there nothing to change, just write directly to w.\n\tif metricNamespace == \"\" && len(globalLabels) == 0 {\n\t\tvm.WriteProcessMetrics(w)\n\t\treturn\n\t}\n\n\t// Write metrics to buffer.\n\tbuf := new(bytes.Buffer)\n\tvm.WriteProcessMetrics(buf)\n\n\t// Add namespace and label per line.\n\tscanner := bufio.NewScanner(buf)\n\tscanner.Split(bufio.ScanLines)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\t// Add namespace, if set.\n\t\tif metricNamespace != \"\" {\n\t\t\tline = metricNamespace + \"_\" + line\n\t\t}\n\n\t\t// Add global labels, if set.\n\t\tif len(globalLabels) > 0 {\n\t\t\t// Find where to insert.\n\t\t\tmergeWithExisting := true\n\t\t\tinsertAt := strings.Index(line, \"{\") + 1\n\t\t\tif insertAt <= 0 {\n\t\t\t\tmergeWithExisting = false\n\t\t\t\tinsertAt = strings.Index(line, \" \")\n\t\t\t\tif insertAt < 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Write new line directly to w.\n\t\t\tfmt.Fprint(w, line[:insertAt])\n\t\t\tif !mergeWithExisting {\n\t\t\t\tfmt.Fprint(w, \"{\")\n\t\t\t}\n\t\t\tlabelsAdded := 0\n\t\t\tfor labelKey, labelValue := range globalLabels {\n\t\t\t\tfmt.Fprintf(w, \"%s=%q\", labelKey, labelValue)\n\t\t\t\t// Add separator if not last label.\n\t\t\t\tlabelsAdded++\n\t\t\t\tif labelsAdded < len(globalLabels) {\n\t\t\t\t\tfmt.Fprint(w, \", \")\n\t\t\t\t}\n\t\t\t}\n\t\t\tif mergeWithExisting {\n\t\t\t\tfmt.Fprint(w, \", \")\n\t\t\t} else {\n\t\t\t\tfmt.Fprint(w, \"}\")\n\t\t\t}\n\t\t\tfmt.Fprintln(w, line[insertAt:])\n\t\t}\n\t}\n\n\t// Check if there was an error in the scanner.\n\tif scanner.Err() != nil {\n\t\tlog.Warningf(\"metrics: failed to scan go process metrics: %s\", scanner.Err())\n\t}\n}\n"
  },
  {
    "path": "base/metrics/module.go",
    "content": "package metrics\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\ntype Metrics struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tmetricTicker *mgr.SleepyTicker\n}\n\nfunc (met *Metrics) Manager() *mgr.Manager {\n\treturn met.mgr\n}\n\nfunc (met *Metrics) Start() error {\n\treturn start()\n}\n\nfunc (met *Metrics) Stop() error {\n\treturn stop()\n}\n\nfunc (met *Metrics) SetSleep(enabled bool) {\n\tif met.metricTicker != nil {\n\t\tmet.metricTicker.SetSleep(enabled)\n\t}\n}\n\nvar (\n\tmodule     *Metrics\n\tshimLoaded atomic.Bool\n\n\tregistry     []Metric\n\tregistryLock sync.RWMutex\n\n\treadyToRegister       bool\n\tfirstMetricRegistered bool\n\tmetricNamespace       string\n\tglobalLabels          = make(map[string]string)\n\n\t// ErrAlreadyStarted is returned when an operation is only valid before the\n\t// first metric is registered, and is called after.\n\tErrAlreadyStarted = errors.New(\"can only be changed before first metric is registered\")\n\n\t// ErrAlreadyRegistered is returned when a metric with the same ID is\n\t// registered again.\n\tErrAlreadyRegistered = errors.New(\"metric already registered\")\n\n\t// ErrAlreadySet is returned when a value is already set and cannot be changed.\n\tErrAlreadySet = errors.New(\"already set\")\n\n\t// ErrInvalidOptions is returned when invalid options where provided.\n\tErrInvalidOptions = errors.New(\"invalid options\")\n)\n\nfunc start() error {\n\t// Add metric instance name as global variable if set.\n\tif instanceOption() != \"\" {\n\t\tif err := AddGlobalLabel(\"instance\", instanceOption()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Mark registry as ready to register metrics.\n\tfunc() {\n\t\tregistryLock.Lock()\n\t\tdefer registryLock.Unlock()\n\t\treadyToRegister = true\n\t}()\n\n\tif err := registerInfoMetric(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerRuntimeMetric(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerHostMetrics(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerLogMetrics(); err != nil {\n\t\treturn err\n\t}\n\n\tif pushOption() != \"\" {\n\t\tmodule.mgr.Go(\"metric pusher\", metricsWriter)\n\t}\n\n\treturn nil\n}\n\nfunc stop() error {\n\t// Wait until the metrics pusher is done, as it may have started reporting\n\t// and may report a higher number than we store to disk. For persistent\n\t// metrics it can then happen that the first report is lower than the\n\t// previous report, making prometheus think that all that happened since the\n\t// last report, due to the automatic restart detection.\n\n\t// The registry is read locked when writing metrics.\n\t// Write lock the registry to make sure all writes are finished.\n\tregistryLock.Lock()\n\tregistryLock.Unlock() //nolint:staticcheck\n\n\tstorePersistentMetrics()\n\n\treturn nil\n}\n\nfunc register(m Metric) error {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\t// Check if metric ID is already registered.\n\tfor _, registeredMetric := range registry {\n\t\tif m.LabeledID() == registeredMetric.LabeledID() {\n\t\t\treturn ErrAlreadyRegistered\n\t\t}\n\t\tif m.Opts().InternalID != \"\" &&\n\t\t\tm.Opts().InternalID == registeredMetric.Opts().InternalID {\n\t\t\treturn fmt.Errorf(\"%w with this internal ID\", ErrAlreadyRegistered)\n\t\t}\n\t}\n\n\t// Add new metric to registry and sort it.\n\tregistry = append(registry, m)\n\tsort.Sort(byLabeledID(registry))\n\n\t// Check if we can already register.\n\tif !readyToRegister {\n\t\treturn fmt.Errorf(\"registering metric %q too early\", m.ID())\n\t}\n\n\t// Set flag that first metric is now registered.\n\tfirstMetricRegistered = true\n\n\treturn nil\n}\n\n// SetNamespace sets the namespace for all metrics. It is prefixed to all\n// metric IDs.\n// It must be set before any metric is registered.\n// Does not affect golang runtime metrics.\nfunc SetNamespace(namespace string) error {\n\t// Lock registry and check if a first metric is already registered.\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\tif firstMetricRegistered {\n\t\treturn ErrAlreadyStarted\n\t}\n\n\t// Check if the namespace is already set.\n\tif metricNamespace != \"\" {\n\t\treturn ErrAlreadySet\n\t}\n\n\tmetricNamespace = namespace\n\treturn nil\n}\n\n// AddGlobalLabel adds a global label to all metrics.\n// Global labels must be added before any metric is registered.\n// Does not affect golang runtime metrics.\nfunc AddGlobalLabel(name, value string) error {\n\t// Lock registry and check if a first metric is already registered.\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\tif firstMetricRegistered {\n\t\treturn ErrAlreadyStarted\n\t}\n\n\t// Check format.\n\tif !prometheusFormat.MatchString(name) {\n\t\treturn fmt.Errorf(\"metric label name %q must match %s\", name, PrometheusFormatRequirement)\n\t}\n\n\tglobalLabels[name] = value\n\treturn nil\n}\n\ntype byLabeledID []Metric\n\nfunc (r byLabeledID) Len() int           { return len(r) }\nfunc (r byLabeledID) Less(i, j int) bool { return r[i].LabeledID() < r[j].LabeledID() }\nfunc (r byLabeledID) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }\n\nfunc New(instance instance) (*Metrics, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Metrics\")\n\tmodule = &Metrics{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\tif err := prepConfig(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := registerAPI(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tDataDir() string\n}\n"
  },
  {
    "path": "base/metrics/persistence.go",
    "content": "package metrics\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\tstorage       *metricsStorage\n\tstorageKey    string\n\tstorageInit   = abool.New()\n\tstorageLoaded = abool.New()\n\n\tdb = database.NewInterface(&database.Options{\n\t\tLocal:    true,\n\t\tInternal: true,\n\t})\n\n\t// ErrAlreadyInitialized is returned when trying to initialize an option\n\t// more than once or if the time window for initializing is over.\n\tErrAlreadyInitialized = errors.New(\"already initialized\")\n)\n\ntype metricsStorage struct {\n\tsync.Mutex\n\trecord.Base\n\n\tStart    time.Time\n\tCounters map[string]uint64\n}\n\n// EnableMetricPersistence enables metric persistence for metrics that opted\n// for it. They given key is the database key where the metric data will be\n// persisted.\n// This call also directly loads the stored data from the database.\n// The returned error is only about loading the metrics, not about enabling\n// persistence.\n// May only be called once.\nfunc EnableMetricPersistence(key string) error {\n\t// Check if already initialized.\n\tif !storageInit.SetToIf(false, true) {\n\t\treturn ErrAlreadyInitialized\n\t}\n\n\t// Set storage key.\n\tstorageKey = key\n\n\t// Load metrics from storage.\n\tvar err error\n\tstorage, err = getMetricsStorage(storageKey)\n\tswitch {\n\tcase err == nil:\n\t\t// Continue.\n\tcase errors.Is(err, database.ErrNotFound):\n\t\treturn nil\n\tdefault:\n\t\treturn err\n\t}\n\tstorageLoaded.Set()\n\n\t// Load saved state for all counter metrics.\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\tfor _, m := range registry {\n\t\tcounter, ok := m.(*Counter)\n\t\tif ok {\n\t\t\tcounter.loadState()\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *Counter) loadState() {\n\t// Check if we can and should load the state.\n\tif !storageLoaded.IsSet() || !c.Opts().Persist {\n\t\treturn\n\t}\n\n\tc.Set(storage.Counters[c.LabeledID()])\n}\n\nfunc storePersistentMetrics() {\n\t// Check if persistence is enabled.\n\tif !storageInit.IsSet() || storageKey == \"\" {\n\t\treturn\n\t}\n\n\t// Create new storage.\n\tnewStorage := &metricsStorage{\n\t\t// TODO: This timestamp should be taken from previous save, if possible.\n\t\tStart:    time.Now(),\n\t\tCounters: make(map[string]uint64),\n\t}\n\tnewStorage.SetKey(storageKey)\n\t// Copy values from previous version.\n\tif storageLoaded.IsSet() {\n\t\tnewStorage.Start = storage.Start\n\t}\n\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\t// Export all counter metrics.\n\tfor _, m := range registry {\n\t\tif m.Opts().Persist {\n\t\t\tcounter, ok := m.(*Counter)\n\t\t\tif ok {\n\t\t\t\tnewStorage.Counters[m.LabeledID()] = counter.Get()\n\t\t\t}\n\t\t}\n\t}\n\n\t// Save to database.\n\terr := db.Put(newStorage)\n\tif err != nil {\n\t\tlog.Warningf(\"metrics: failed to save metrics storage to db: %s\", err)\n\t}\n}\n\nfunc getMetricsStorage(key string) (*metricsStorage, error) {\n\tr, err := db.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewStorage := &metricsStorage{}\n\t\terr = record.Unwrap(r, newStorage)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newStorage, nil\n\t}\n\n\t// or adjust type\n\tnewStorage, ok := r.(*metricsStorage)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *metricsStorage, but %T\", r)\n\t}\n\treturn newStorage, nil\n}\n"
  },
  {
    "path": "base/notifications/cleaner.go",
    "content": "package notifications\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc cleaner(ctx *mgr.WorkerCtx) error { //nolint:unparam // Conforms to worker interface\n\tticker := time.NewTicker(1 * time.Second)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ticker.C:\n\t\t\tdeleteExpiredNotifs()\n\t\t}\n\t}\n}\n\nfunc deleteExpiredNotifs() {\n\t// Get a copy of the notification map.\n\tnotsCopy := getNotsCopy()\n\n\t// Delete all expired notifications.\n\tfor _, n := range notsCopy {\n\t\tif n.isExpired() {\n\t\t\tn.delete(true)\n\t\t}\n\t}\n}\n\nfunc (n *Notification) isExpired() bool {\n\tn.Lock()\n\tdefer n.Unlock()\n\n\treturn n.Expires > 0 && n.Expires < time.Now().Unix()\n}\n\nfunc getNotsCopy() []*Notification {\n\tnotsLock.RLock()\n\tdefer notsLock.RUnlock()\n\n\tnotsCopy := make([]*Notification, 0, len(nots))\n\tfor _, n := range nots {\n\t\tnotsCopy = append(notsCopy, n)\n\t}\n\n\treturn notsCopy\n}\n"
  },
  {
    "path": "base/notifications/config.go",
    "content": "package notifications\n\nimport (\n\t\"github.com/safing/portmaster/base/config\"\n)\n\n// Configuration Keys.\nvar (\n\tCfgUseSystemNotificationsKey = \"core/useSystemNotifications\"\n\tuseSystemNotifications       config.BoolOption\n)\n\nfunc registerConfig() error {\n\tif err := config.Register(&config.Option{\n\t\tName:           \"Desktop Notifications\",\n\t\tKey:            CfgUseSystemNotificationsKey,\n\t\tDescription:    \"In addition to showing notifications in the Portmaster App, also send them to the Desktop. This requires the Portmaster Notifier to be running.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   true, // TODO: turn off by default on unsupported systems\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: -15,\n\t\t\tconfig.CategoryAnnotation:     \"User Interface\",\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\tuseSystemNotifications = config.Concurrent.GetAsBool(CfgUseSystemNotificationsKey, true)\n\n\treturn nil\n}\n"
  },
  {
    "path": "base/notifications/database.go",
    "content": "package notifications\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\tnots     = make(map[string]*Notification)\n\tnotsLock sync.RWMutex\n\n\tdbController *database.Controller\n)\n\n// Storage interface errors.\nvar (\n\tErrInvalidData = errors.New(\"invalid data, must be a notification object\")\n\tErrInvalidPath = errors.New(\"invalid path\")\n\tErrNoDelete    = errors.New(\"notifications may not be deleted, they must be handled\")\n)\n\n// StorageInterface provices a storage.Interface to the configuration manager.\ntype StorageInterface struct {\n\tstorage.InjectBase\n}\n\nfunc registerAsDatabase() error {\n\t_, err := database.Register(&database.Database{\n\t\tName:        \"notifications\",\n\t\tDescription: \"Notifications\",\n\t\tStorageType: \"injected\",\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontroller, err := database.InjectDatabase(\"notifications\", &StorageInterface{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdbController = controller\n\treturn nil\n}\n\n// Get returns a database record.\nfunc (s *StorageInterface) Get(key string) (record.Record, error) {\n\t// Get EventID from key.\n\tif !strings.HasPrefix(key, \"all/\") {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\tkey = strings.TrimPrefix(key, \"all/\")\n\n\t// Get notification from storage.\n\tn, ok := getNotification(key)\n\tif !ok {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\treturn n, nil\n}\n\nfunc getNotification(eventID string) (n *Notification, ok bool) {\n\tnotsLock.RLock()\n\tdefer notsLock.RUnlock()\n\n\tn, ok = nots[eventID]\n\treturn\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (s *StorageInterface) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\tit := iterator.New()\n\tgo s.processQuery(q, it)\n\t// TODO: check local and internal\n\n\treturn it, nil\n}\n\nfunc (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {\n\t// Get a copy of the notification map.\n\tnotsCopy := getNotsCopy()\n\n\t// send all notifications\n\tfor _, n := range notsCopy {\n\t\tif inQuery(n, q) {\n\t\t\tselect {\n\t\t\tcase it.Next <- n:\n\t\t\tcase <-it.Done:\n\t\t\t\t// make sure we don't leak this goroutine if the iterator get's cancelled\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tit.Finish(nil)\n}\n\nfunc inQuery(n *Notification, q *query.Query) bool {\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\n\tswitch {\n\tcase n.Meta().IsDeleted():\n\t\treturn false\n\tcase !q.MatchesKey(n.DatabaseKey()):\n\t\treturn false\n\tcase !q.MatchesRecord(n):\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Put stores a record in the database.\nfunc (s *StorageInterface) Put(r record.Record) (record.Record, error) {\n\t// record is already locked!\n\tkey := r.DatabaseKey()\n\tn, err := EnsureNotification(r)\n\tif err != nil {\n\t\treturn nil, ErrInvalidData\n\t}\n\n\t// transform key\n\tif strings.HasPrefix(key, \"all/\") {\n\t\tkey = strings.TrimPrefix(key, \"all/\")\n\t} else {\n\t\treturn nil, ErrInvalidPath\n\t}\n\n\treturn applyUpdate(n, key)\n}\n\nfunc applyUpdate(n *Notification, key string) (*Notification, error) {\n\t// separate goroutine in order to correctly lock notsLock\n\texisting, ok := getNotification(key)\n\n\t// ignore if already deleted\n\tif !ok || existing.Meta().IsDeleted() {\n\t\t// this is a completely new notification\n\t\t// we pass pushUpdate==false because the storage\n\t\t// controller will push an update on put anyway.\n\t\tn.save(false)\n\t\treturn n, nil\n\t}\n\n\t// Save when we're finished, if needed.\n\tsave := false\n\tdefer func() {\n\t\tif save {\n\t\t\texisting.save(false)\n\t\t}\n\t}()\n\n\texisting.Lock()\n\tdefer existing.Unlock()\n\n\tif existing.State == Executed {\n\t\treturn existing, fmt.Errorf(\"action already executed\")\n\t}\n\n\t// check if the notification has been marked as\n\t// \"executed externally\".\n\tif n.State == Executed {\n\t\tlog.Tracef(\"notifications: action for %s executed externally\", n.EventID)\n\t\texisting.State = Executed\n\t\tsave = true\n\n\t\t// in case the action has been executed immediately by the\n\t\t// sender we may need to update the SelectedActionID.\n\t\t// Though, we guard the assignments with value check\n\t\t// so partial updates that only change the\n\t\t// State property do not overwrite existing values.\n\t\tif n.SelectedActionID != \"\" {\n\t\t\texisting.SelectedActionID = n.SelectedActionID\n\t\t}\n\t}\n\n\tif n.SelectedActionID != \"\" && existing.State == Active {\n\t\tlog.Tracef(\"notifications: selected action for %s: %s\", n.EventID, n.SelectedActionID)\n\t\texisting.selectAndExecuteAction(n.SelectedActionID)\n\t\tsave = true\n\t}\n\n\treturn existing, nil\n}\n\n// Delete deletes a record from the database.\nfunc (s *StorageInterface) Delete(key string) error {\n\t// Get EventID from key.\n\tif !strings.HasPrefix(key, \"all/\") {\n\t\treturn storage.ErrNotFound\n\t}\n\tkey = strings.TrimPrefix(key, \"all/\")\n\n\t// Get notification from storage.\n\tn, ok := getNotification(key)\n\tif !ok {\n\t\treturn storage.ErrNotFound\n\t}\n\n\tn.delete(true)\n\treturn nil\n}\n\n// ReadOnly returns whether the database is read only.\nfunc (s *StorageInterface) ReadOnly() bool {\n\treturn false\n}\n\n// EnsureNotification ensures that the given record is a Notification and returns it.\nfunc EnsureNotification(r record.Record) (*Notification, error) {\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tn := &Notification{}\n\t\terr := record.Unwrap(r, n)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn n, nil\n\t}\n\n\t// or adjust type\n\tn, ok := r.(*Notification)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *Notification, but %T\", r)\n\t}\n\treturn n, nil\n}\n"
  },
  {
    "path": "base/notifications/doc.go",
    "content": "/*\nPackage notifications provides a notification system.\n\n# Notification Lifecycle\n\n1. Create Notification with an ID and Message.\n2. Set possible actions and save it.\n3. When the user responds, the action is executed.\n\nExample\n\n\t// create notification\n\tn := notifications.New(\"update-available\", \"A new update is available. Restart to upgrade.\")\n\t// set actions and save\n\tn.AddAction(\"later\", \"Later\").AddAction(\"restart\", \"Restart now!\").Save()\n\n\t// wait for user action\n\tselectedAction := <-n.Response()\n\tswitch selectedAction {\n\tcase \"later\":\n\t  log.Infof(\"user wants to upgrade later.\")\n\tcase \"restart\":\n\t  log.Infof(\"user wants to restart now.\")\n\t}\n*/\npackage notifications\n"
  },
  {
    "path": "base/notifications/module-mirror.go",
    "content": "package notifications\n\nimport (\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// SyncWithState syncs the notification to a state in the given state mgr.\n// The state will be removed when the notification is removed.\nfunc (n *Notification) SyncWithState(state *mgr.StateMgr) {\n\tif state == nil {\n\t\tlog.Warningf(\"notifications: invalid usage: cannot attach %s to nil module\", n.EventID)\n\t\treturn\n\t}\n\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\n\tif n.Meta().IsDeleted() {\n\t\tlog.Warningf(\"notifications: cannot attach module to deleted notification %s\", n.EventID)\n\t\treturn\n\t}\n\tif n.State != Active {\n\t\tlog.Warningf(\"notifications: cannot attach module to inactive notification %s\", n.EventID)\n\t\treturn\n\t}\n\tif n.belongsTo != nil {\n\t\tlog.Warningf(\"notifications: cannot override attached module for notification %s\", n.EventID)\n\t\treturn\n\t}\n\n\t// Attach module.\n\tn.belongsTo = state\n\n\t// Create state with same ID.\n\tstate.Add(mgr.State{\n\t\tID:      n.EventID,\n\t\tName:    n.Title,\n\t\tMessage: n.Message,\n\t\tType:    notifTypeToStateType(n.Type),\n\t\tData:    n.EventData,\n\t})\n}\n\nfunc notifTypeToStateType(notifType Type) mgr.StateType {\n\tswitch notifType {\n\tcase Info:\n\t\treturn mgr.StateTypeHint\n\tcase Warning:\n\t\treturn mgr.StateTypeWarning\n\tcase Prompt:\n\t\treturn mgr.StateTypeUndefined\n\tcase Error:\n\t\treturn mgr.StateTypeError\n\tdefault:\n\t\treturn mgr.StateTypeUndefined\n\t}\n}\n"
  },
  {
    "path": "base/notifications/module.go",
    "content": "package notifications\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\ntype Notifications struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tstates *mgr.StateMgr\n}\n\nfunc (n *Notifications) Manager() *mgr.Manager {\n\treturn n.mgr\n}\n\nfunc (n *Notifications) States() *mgr.StateMgr {\n\treturn n.states\n}\n\nfunc (n *Notifications) Start() error {\n\treturn start()\n}\n\nfunc (n *Notifications) Stop() error {\n\treturn nil\n}\n\n// NotifyInfo is a helper method for quickly showing an info notification.\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is disabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc (n *Notifications) NotifyInfo(id, title, msg string, actions ...Action) *Notification {\n\treturn NotifyInfo(id, title, msg, actions...)\n}\n\n// NotifyWarn is a helper method for quickly showing a warning notification\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is enabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc (n *Notifications) NotifyWarn(id, title, msg string, actions ...Action) *Notification {\n\treturn NotifyWarn(id, title, msg, actions...)\n}\n\n// NotifyError is a helper method for quickly showing an error notification.\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is enabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc (n *Notifications) NotifyError(id, title, msg string, actions ...Action) *Notification {\n\treturn NotifyError(id, title, msg, actions...)\n}\n\n// NotifyPrompt is a helper method for quickly showing a prompt notification.\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is disabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc (n *Notifications) NotifyPrompt(id, title, msg string, actions ...Action) *Notification {\n\treturn NotifyPrompt(id, title, msg, actions...)\n}\n\n// Notify sends the given notification.\nfunc (n *Notifications) Notify(notification *Notification) *Notification {\n\treturn Notify(notification)\n}\n\nfunc prep() error {\n\treturn registerConfig()\n}\n\nfunc start() error {\n\terr := registerAsDatabase()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tshowConfigLoadingErrors()\n\n\tmodule.mgr.Go(\"cleaner\", cleaner)\n\treturn nil\n}\n\nfunc showConfigLoadingErrors() {\n\tvalidationErrors := config.GetLoadedConfigValidationErrors()\n\tif len(validationErrors) == 0 {\n\t\treturn\n\t}\n\n\t// Trigger a module error for more awareness.\n\tmodule.states.Add(mgr.State{\n\t\tID:      \"config:validation-errors-on-load\",\n\t\tName:    \"Invalid Settings\",\n\t\tMessage: \"Some current settings are invalid. Please update them and restart the Portmaster.\",\n\t\tType:    mgr.StateTypeError,\n\t})\n\n\t// Send one notification per invalid setting.\n\tfor _, validationError := range config.GetLoadedConfigValidationErrors() {\n\t\tNotifyError(\n\t\t\tfmt.Sprintf(\"config:validation-error:%s\", validationError.Option.Key),\n\t\t\tfmt.Sprintf(\"Invalid Setting for %s\", validationError.Option.Name),\n\t\t\tfmt.Sprintf(`Your current setting for %s is invalid: %s\n\nPlease update the setting and restart the Portmaster, until then the default value is used.`,\n\t\t\t\tvalidationError.Option.Name,\n\t\t\t\tvalidationError.Err.Error(),\n\t\t\t),\n\t\t\tAction{\n\t\t\t\tText: \"Change\",\n\t\t\t\tType: ActionTypeOpenSetting,\n\t\t\t\tPayload: &ActionTypeOpenSettingPayload{\n\t\t\t\t\tKey: validationError.Option.Key,\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n}\n\nvar (\n\tmodule     *Notifications\n\tshimLoaded atomic.Bool\n)\n\nfunc New(instance instance) (*Notifications, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Notifications\")\n\tmodule = &Notifications{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tstates: mgr.NewStateMgr(m),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "base/notifications/notification.go",
    "content": "package notifications\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// Type describes the type of a notification.\ntype Type uint8\n\n// Notification types.\nconst (\n\tInfo    Type = 0\n\tWarning Type = 1\n\tPrompt  Type = 2\n\tError   Type = 3\n)\n\n// State describes the state of a notification.\ntype State string\n\n// NotificationActionFn defines the function signature for notification action\n// functions.\ntype NotificationActionFn func(context.Context, *Notification) error\n\n// Possible notification states.\n// State transitions can only happen from top to bottom.\nconst (\n\t// Active describes a notification that is active, no expired and,\n\t// if actions are available, still waits for the user to select an\n\t// action.\n\tActive State = \"active\"\n\t// Responded describes a notification where the user has already\n\t// selected which action to take but that action is still to be\n\t// performed.\n\tResponded State = \"responded\"\n\t// Executes describes a notification where the user has selected\n\t// and action and that action has been performed.\n\tExecuted State = \"executed\"\n)\n\n// Notification represents a notification that is to be delivered to the user.\ntype Notification struct { //nolint:maligned\n\trecord.Base\n\t// EventID is used to identify a specific notification. It consists of\n\t// the module name and a per-module unique event id.\n\t// The following format is recommended:\n\t// \t<module-id>:<event-id>\n\tEventID string\n\t// GUID is a unique identifier for each notification instance. That is\n\t// two notifications with the same EventID must still have unique GUIDs.\n\t// The GUID is mainly used for system (Windows) integration and is\n\t// automatically populated by the notification package. Average users\n\t// don't need to care about this field.\n\tGUID string\n\t// Type is the notification type. It can be one of Info, Warning or Prompt.\n\tType Type\n\t// Title is an optional and very short title for the message that gives a\n\t// hint about what the notification is about.\n\tTitle string\n\t// Category is an optional category for the notification that allows for\n\t// tagging and grouping notifications by category.\n\tCategory string\n\t// Message is the default message shown to the user if no localized version\n\t// of the notification is available. Note that the message should already\n\t// have any paramerized values replaced.\n\tMessage string\n\t// ShowOnSystem specifies if the notification should be also shown on the\n\t// operating system. Notifications shown on the operating system level are\n\t// more focus-intrusive and should only be used for important notifications.\n\t// If the configuration option \"Desktop Notifications\" is switched off, this\n\t// will be forced to false on the first save.\n\tShowOnSystem bool\n\t// EventData contains an additional payload for the notification. This payload\n\t// may contain contextual data and may be used by a localization framework\n\t// to populate the notification message template.\n\t// If EventData implements sync.Locker it will be locked and unlocked together with the\n\t// notification. Otherwise, EventData is expected to be immutable once the\n\t// notification has been saved and handed over to the notification or database package.\n\tEventData interface{}\n\t// Expires holds the unix epoch timestamp at which the notification expires\n\t// and can be cleaned up.\n\t// Users can safely ignore expired notifications and should handle expiry the\n\t// same as deletion.\n\tExpires int64\n\t// State describes the current state of a notification. See State for\n\t// a list of available values and their meaning.\n\tState State\n\t// AvailableActions defines a list of actions that a user can choose from.\n\tAvailableActions []*Action\n\t// SelectedActionID is updated to match the ID of one of the AvailableActions\n\t// based on the user selection.\n\tSelectedActionID string\n\n\t// belongsTo holds the state this notification belongs to. The notification\n\t// lifecycle will be mirrored to the specified failure status.\n\tbelongsTo *mgr.StateMgr\n\n\tlock           sync.Mutex\n\tactionFunction NotificationActionFn // call function to process action\n\tactionTrigger  chan string          // and/or send to a channel\n\texpiredTrigger chan struct{}        // closed on expire\n}\n\n// Action describes an action that can be taken for a notification.\ntype Action struct {\n\t// ID specifies a unique ID for the action. If an action is selected, the ID\n\t// is written to SelectedActionID and the notification is saved.\n\t// If the action type is not ActionTypeNone, the ID may be empty, signifying\n\t// that this action is merely additional and selecting it does not dismiss the\n\t// notification.\n\tID string\n\t// Text on the button.\n\tText string\n\t// Type specifies the action type. Implementing interfaces should only\n\t// display action types they can handle.\n\tType ActionType\n\t// Payload holds additional data for special action types.\n\tPayload interface{}\n\t// Visibility specifies where the action should be visible. Default is always visible.\n\tVisibility ActionVisibility\n}\n\ntype ActionVisibility string\n\nconst (\n\t// Default visibility, action is always visible.\n\tActionVisibilityDefault ActionVisibility = \"\" // default visibility\n\t// Visible only in extended view\n\t// (when user clicks on notification to read full message)\n\tActionVisibilityDetailed ActionVisibility = \"detailed\"\n\t// Visible only in the UI app, never on the system level (if ShowOnSystem is true).\n\tActionVisibilityInAppOnly ActionVisibility = \"in-app-only\"\n)\n\n// ActionType defines a specific type of action.\ntype ActionType string\n\n// Action Types.\nconst (\n\tActionTypeNone        = \"\"             // Report selected ID back to backend.\n\tActionTypeOpenURL     = \"open-url\"     // Open external URL\n\tActionTypeOpenPage    = \"open-page\"    // Payload: Page ID\n\tActionTypeOpenSetting = \"open-setting\" // Payload: See struct definition below.\n\tActionTypeOpenProfile = \"open-profile\" // Payload: Scoped Profile ID\n\tActionTypeInjectEvent = \"inject-event\" // Payload: Event ID\n\tActionTypeWebhook     = \"call-webhook\" // Payload: See struct definition below.\n)\n\n// ActionTypeOpenSettingPayload defines the payload for the OpenSetting Action Type.\ntype ActionTypeOpenSettingPayload struct {\n\t// Key is the key of the setting.\n\tKey string\n\t// Profile is the scoped ID of the profile.\n\t// Leaving this empty opens the global settings.\n\tProfile string\n}\n\n// ActionTypeWebhookPayload defines the payload for the WebhookPayload Action Type.\ntype ActionTypeWebhookPayload struct {\n\t// HTTP Method to use. Defaults to \"GET\", or \"POST\" if a Payload is supplied.\n\tMethod string\n\t// URL to call.\n\t// If the URL is relative, prepend the current API endpoint base path.\n\t// If the URL is absolute, send request to the Portmaster.\n\tURL string\n\t// Payload holds arbitrary payload data.\n\tPayload interface{}\n\t// ResultAction defines what should be done with successfully returned data.\n\t// Must one of:\n\t// - `ignore`: do nothing (default)\n\t// - `display`: the result is a human readable message, display it in a success message.\n\tResultAction string\n}\n\n// Get returns the notification identifed by the given id or nil if it doesn't exist.\nfunc Get(id string) *Notification {\n\tnotsLock.RLock()\n\tdefer notsLock.RUnlock()\n\tn, ok := nots[id]\n\tif ok {\n\t\treturn n\n\t}\n\treturn nil\n}\n\n// Delete deletes the notification with the given id.\nfunc Delete(id string) {\n\t// Delete notification in defer to enable deferred unlocking.\n\tvar n *Notification\n\tvar ok bool\n\tdefer func() {\n\t\tif ok {\n\t\t\tn.Delete()\n\t\t}\n\t}()\n\n\tnotsLock.Lock()\n\tdefer notsLock.Unlock()\n\tn, ok = nots[id]\n}\n\n// NotifyInfo is a helper method for quickly showing an info notification.\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is disabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc NotifyInfo(id, title, msg string, actions ...Action) *Notification {\n\treturn notify(Info, id, title, msg, false, actions...)\n}\n\n// NotifyWarn is a helper method for quickly showing a warning notification\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is enabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc NotifyWarn(id, title, msg string, actions ...Action) *Notification {\n\treturn notify(Warning, id, title, msg, true, actions...)\n}\n\n// NotifyError is a helper method for quickly showing an error notification.\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is enabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc NotifyError(id, title, msg string, actions ...Action) *Notification {\n\treturn notify(Error, id, title, msg, true, actions...)\n}\n\n// NotifyPrompt is a helper method for quickly showing a prompt notification.\n// The notification will be activated immediately.\n// If the provided id is empty, an id will derived from msg.\n// ShowOnSystem is disabled.\n// If no actions are defined, a default \"OK\" (ID:\"ack\") action will be added.\nfunc NotifyPrompt(id, title, msg string, actions ...Action) *Notification {\n\treturn notify(Prompt, id, title, msg, false, actions...)\n}\n\nfunc notify(nType Type, id, title, msg string, showOnSystem bool, actions ...Action) *Notification {\n\t// Process actions.\n\tvar acts []*Action\n\tif len(actions) == 0 {\n\t\t// Create ack action if there are no defined actions.\n\t\tacts = []*Action{\n\t\t\t{\n\t\t\t\tID:   \"ack\",\n\t\t\t\tText: \"OK\",\n\t\t\t},\n\t\t}\n\t} else {\n\t\t// Reference given actions for notification.\n\t\tacts = make([]*Action, len(actions))\n\t\tfor index := range actions {\n\t\t\ta := actions[index]\n\t\t\tacts[index] = &a\n\t\t}\n\t}\n\n\treturn Notify(&Notification{\n\t\tEventID:          id,\n\t\tType:             nType,\n\t\tTitle:            title,\n\t\tMessage:          msg,\n\t\tShowOnSystem:     showOnSystem,\n\t\tAvailableActions: acts,\n\t})\n}\n\n// Notify sends the given notification.\nfunc Notify(n *Notification) *Notification {\n\t// While this function is very similar to Save(), it is much nicer to use in\n\t// order to just fire off one notification, as it does not require some more\n\t// uncommon Go syntax.\n\n\tn.save(true)\n\treturn n\n}\n\n// Save saves the notification.\nfunc (n *Notification) Save() {\n\tn.save(true)\n}\n\n// save saves the notification to the internal storage. It locks the\n// notification, so it must not be locked when save is called.\nfunc (n *Notification) save(pushUpdate bool) {\n\tvar id string\n\n\t// Save notification after pre-save processing.\n\tdefer func() {\n\t\tif id != \"\" {\n\t\t\t// Lock and save to notification storage.\n\t\t\tnotsLock.Lock()\n\t\t\tdefer notsLock.Unlock()\n\t\t\tnots[id] = n\n\t\t}\n\t}()\n\n\t// We do not access EventData here, so it is enough to just lock the\n\t// notification itself.\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\n\t// Check if required data is present.\n\tif n.Title == \"\" && n.Message == \"\" {\n\t\tlog.Warning(\"notifications: ignoring notification without Title or Message\")\n\t\treturn\n\t}\n\n\t// Derive EventID from Message if not given.\n\tif n.EventID == \"\" {\n\t\tn.EventID = fmt.Sprintf(\n\t\t\t\"unknown:%s\",\n\t\t\tutils.DerivedInstanceUUID(n.Message).String(),\n\t\t)\n\t}\n\n\t// Save ID for deletion\n\tid = n.EventID\n\n\t// Generate random GUID if not set.\n\tif n.GUID == \"\" {\n\t\tn.GUID = utils.RandomUUID(n.EventID).String()\n\t}\n\n\t// Make sure we always have a notification state assigned.\n\tif n.State == \"\" {\n\t\tn.State = Active\n\t}\n\n\t// Initialize on first save.\n\tif !n.KeyIsSet() {\n\t\t// Set database key.\n\t\tn.SetKey(fmt.Sprintf(\"notifications:all/%s\", n.EventID))\n\n\t\t// Check if notifications should be shown on the system at all.\n\t\tif !useSystemNotifications() {\n\t\t\tn.ShowOnSystem = false\n\t\t}\n\t}\n\n\t// Update meta data.\n\tn.UpdateMeta()\n\n\t// Push update via the database system if needed.\n\tif pushUpdate {\n\t\tlog.Tracef(\"notifications: pushing update for %s to subscribers\", n.Key())\n\t\tdbController.PushUpdate(n)\n\t}\n}\n\n// SetActionFunction sets a trigger function to be executed when the user reacted on the notification.\n// The provided function will be started as its own goroutine and will have to lock everything it accesses, even the provided notification.\nfunc (n *Notification) SetActionFunction(fn NotificationActionFn) *Notification {\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\tn.actionFunction = fn\n\treturn n\n}\n\n// Response waits for the user to respond to the notification and returns the selected action.\nfunc (n *Notification) Response() <-chan string {\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\n\tif n.actionTrigger == nil {\n\t\tn.actionTrigger = make(chan string)\n\t}\n\n\treturn n.actionTrigger\n}\n\n// Update updates/resends a notification if it was not already responded to.\nfunc (n *Notification) Update(expires int64) {\n\t// Save when we're finished, if needed.\n\tsave := false\n\tdefer func() {\n\t\tif save {\n\t\t\tn.save(true)\n\t\t}\n\t}()\n\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\n\t// Don't update if notification isn't active.\n\tif n.State != Active {\n\t\treturn\n\t}\n\n\t// Don't update too quickly.\n\tif n.Meta().Modified > time.Now().Add(-10*time.Second).Unix() {\n\t\treturn\n\t}\n\n\t// Update expiry and save.\n\tn.Expires = expires\n\tsave = true\n}\n\n// Delete (prematurely) cancels and deletes a notification.\nfunc (n *Notification) Delete() {\n\t// Dismiss notification.\n\tfunc() {\n\t\tn.lock.Lock()\n\t\tdefer n.lock.Unlock()\n\n\t\tif n.actionTrigger != nil {\n\t\t\tclose(n.actionTrigger)\n\t\t\tn.actionTrigger = nil\n\t\t}\n\t}()\n\n\tn.delete(true)\n}\n\n// delete deletes the notification from the internal storage. It locks the\n// notification, so it must not be locked when delete is called.\nfunc (n *Notification) delete(pushUpdate bool) {\n\tvar id string\n\n\t// Delete notification after processing deletion.\n\tdefer func() {\n\t\t// Lock and delete from notification storage.\n\t\tnotsLock.Lock()\n\t\tdefer notsLock.Unlock()\n\t\tdelete(nots, id)\n\t}()\n\n\t// We do not access EventData here, so it is enough to just lock the\n\t// notification itself.\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\n\t// Check if notification is already deleted.\n\tif n.Meta().IsDeleted() {\n\t\treturn\n\t}\n\n\t// Save ID for deletion\n\tid = n.EventID\n\n\t// Mark notification as deleted.\n\tn.Meta().Delete()\n\n\t// Close expiry channel if available.\n\tif n.expiredTrigger != nil {\n\t\tclose(n.expiredTrigger)\n\t\tn.expiredTrigger = nil\n\t}\n\n\t// Push update via the database system if needed.\n\tif pushUpdate {\n\t\tdbController.PushUpdate(n)\n\t}\n\n\t// Remove the connected state.\n\tif n.belongsTo != nil {\n\t\tn.belongsTo.Remove(n.EventID)\n\t}\n}\n\n// Expired notifies the caller when the notification has expired.\nfunc (n *Notification) Expired() <-chan struct{} {\n\tn.lock.Lock()\n\tdefer n.lock.Unlock()\n\n\tif n.expiredTrigger == nil {\n\t\tn.expiredTrigger = make(chan struct{})\n\t}\n\n\treturn n.expiredTrigger\n}\n\n// selectAndExecuteAction sets the user response and executes/triggers the action, if possible.\nfunc (n *Notification) selectAndExecuteAction(id string) {\n\tif n.State != Active {\n\t\treturn\n\t}\n\n\tn.State = Responded\n\tn.SelectedActionID = id\n\n\texecuted := false\n\tif n.actionFunction != nil {\n\t\tmodule.mgr.Go(\"notification action execution\", func(ctx *mgr.WorkerCtx) error {\n\t\t\treturn n.actionFunction(ctx.Ctx(), n)\n\t\t})\n\t\texecuted = true\n\t}\n\n\tif n.actionTrigger != nil {\n\t\t// satisfy all listeners (if they are listening)\n\t\t// TODO(ppacher): if we miss to notify the waiter here (because\n\t\t//                nobody is listeing on actionTrigger) we wil likely\n\t\t//                never be able to execute the action again (simply because\n\t\t//                we won't try). May consider replacing the single actionTrigger\n\t\t//                channel with a per-listener (buffered) one so we just send\n\t\t//                the value and close the channel.\n\ttriggerAll:\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase n.actionTrigger <- n.SelectedActionID:\n\t\t\t\texecuted = true\n\t\t\tcase <-time.After(100 * time.Millisecond): // mitigate race conditions\n\t\t\t\tbreak triggerAll\n\t\t\t}\n\t\t}\n\t}\n\n\tif executed {\n\t\tn.State = Executed\n\t\t// n.resolveModuleFailure()\n\t}\n}\n\n// Lock locks the Notification. If EventData is set and\n// implements sync.Locker it is locked as well. Users that\n// want to replace the EventData on a notification must\n// ensure to unlock the current value on their own. If the\n// new EventData implements sync.Locker as well, it must\n// be locked prior to unlocking the notification.\nfunc (n *Notification) Lock() {\n\tn.lock.Lock()\n\tif locker, ok := n.EventData.(sync.Locker); ok {\n\t\tlocker.Lock()\n\t}\n}\n\n// Unlock unlocks the Notification and the EventData, if\n// it implements sync.Locker. See Lock() for more information\n// on how to replace and work with EventData.\nfunc (n *Notification) Unlock() {\n\tn.lock.Unlock()\n\tif locker, ok := n.EventData.(sync.Locker); ok {\n\t\tlocker.Unlock()\n\t}\n}\n"
  },
  {
    "path": "base/rng/doc.go",
    "content": "// Package rng provides a feedable CSPRNG.\n//\n// CSPRNG used is fortuna: github.com/seehuhn/fortuna\n// By default the CSPRNG is fed by two sources:\n// - It starts with a seed from `crypto/rand` and periodically reseeds from there\n// - A really simple tickfeeder which extracts entropy from the internal go scheduler using goroutines and is meant to be used under load.\n//\n// The RNG can also be easily fed with additional sources.\npackage rng\n"
  },
  {
    "path": "base/rng/entropy.go",
    "content": "package rng\n\nimport (\n\t\"encoding/binary\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/structures/container\"\n)\n\nconst (\n\tminFeedEntropy = 256\n)\n\nvar rngFeeder = make(chan []byte)\n\n// The Feeder is used to feed entropy to the RNG.\ntype Feeder struct {\n\tinput        chan *entropyData\n\tentropy      int64\n\tneedsEntropy *abool.AtomicBool\n\tbuffer       *container.Container\n}\n\ntype entropyData struct {\n\tdata    []byte\n\tentropy int\n}\n\n// NewFeeder returns a new entropy Feeder.\nfunc NewFeeder() *Feeder {\n\tnewFeeder := &Feeder{\n\t\tinput:        make(chan *entropyData),\n\t\tneedsEntropy: abool.NewBool(true),\n\t\tbuffer:       container.New(),\n\t}\n\tmodule.mgr.Go(\"feeder\", newFeeder.run)\n\treturn newFeeder\n}\n\n// NeedsEntropy returns whether the feeder is currently gathering entropy.\nfunc (f *Feeder) NeedsEntropy() bool {\n\treturn f.needsEntropy.IsSet()\n}\n\n// SupplyEntropy supplies entropy to the Feeder, it will block until the Feeder has read from it.\nfunc (f *Feeder) SupplyEntropy(data []byte, entropy int) {\n\tf.input <- &entropyData{\n\t\tdata:    data,\n\t\tentropy: entropy,\n\t}\n}\n\n// SupplyEntropyIfNeeded supplies entropy to the Feeder, but will not block if no entropy is currently needed.\nfunc (f *Feeder) SupplyEntropyIfNeeded(data []byte, entropy int) {\n\tif f.needsEntropy.IsSet() {\n\t\treturn\n\t}\n\n\tselect {\n\tcase f.input <- &entropyData{\n\t\tdata:    data,\n\t\tentropy: entropy,\n\t}:\n\tdefault:\n\t}\n}\n\n// SupplyEntropyAsInt supplies entropy to the Feeder, it will block until the Feeder has read from it.\nfunc (f *Feeder) SupplyEntropyAsInt(n int64, entropy int) {\n\tb := make([]byte, 8)\n\tbinary.LittleEndian.PutUint64(b, uint64(n))\n\tf.SupplyEntropy(b, entropy)\n}\n\n// SupplyEntropyAsIntIfNeeded supplies entropy to the Feeder, but will not block if no entropy is currently needed.\nfunc (f *Feeder) SupplyEntropyAsIntIfNeeded(n int64, entropy int) {\n\tif f.needsEntropy.IsSet() { // avoid allocating a slice if possible\n\t\tb := make([]byte, 8)\n\t\tbinary.LittleEndian.PutUint64(b, uint64(n))\n\t\tf.SupplyEntropyIfNeeded(b, entropy)\n\t}\n}\n\n// CloseFeeder stops the feed processing - the responsible goroutine exits. The input channel is closed and the feeder may not be used anymore in any way.\nfunc (f *Feeder) CloseFeeder() {\n\tclose(f.input)\n}\n\nfunc (f *Feeder) run(ctx *mgr.WorkerCtx) error {\n\tdefer f.needsEntropy.UnSet()\n\n\tfor {\n\t\t// gather\n\t\tf.needsEntropy.Set()\n\tgather:\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase newEntropy := <-f.input:\n\t\t\t\t// check if feed has been closed\n\t\t\t\tif newEntropy == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t// append to buffer\n\t\t\t\tf.buffer.Append(newEntropy.data)\n\t\t\t\tf.entropy += int64(newEntropy.entropy)\n\t\t\t\tif f.entropy >= minFeedEntropy {\n\t\t\t\t\tbreak gather\n\t\t\t\t}\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\t// feed\n\t\tf.needsEntropy.UnSet()\n\t\tselect {\n\t\tcase rngFeeder <- f.buffer.CompileData():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t\tf.buffer = container.New()\n\t}\n}\n"
  },
  {
    "path": "base/rng/entropy_test.go",
    "content": "package rng\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestFeeder(t *testing.T) {\n\tt.Parallel()\n\n\t// wait for start / first round to complete\n\ttime.Sleep(1 * time.Millisecond)\n\n\tf := NewFeeder()\n\n\t// go through all functions\n\tf.NeedsEntropy()\n\tf.SupplyEntropy([]byte{0}, 0)\n\tf.SupplyEntropyAsInt(0, 0)\n\tf.SupplyEntropyIfNeeded([]byte{0}, 0)\n\tf.SupplyEntropyAsIntIfNeeded(0, 0)\n\n\t// fill entropy\n\tf.SupplyEntropyAsInt(0, 65535)\n\n\t// check blocking calls\n\n\twaitOne := make(chan struct{})\n\tgo func() {\n\t\tf.SupplyEntropy([]byte{0}, 0)\n\t\tclose(waitOne)\n\t}()\n\tselect {\n\tcase <-waitOne:\n\t\tt.Error(\"call does not block!\")\n\tcase <-time.After(10 * time.Millisecond):\n\t}\n\n\twaitTwo := make(chan struct{})\n\tgo func() {\n\t\tf.SupplyEntropyAsInt(0, 0)\n\t\tclose(waitTwo)\n\t}()\n\tselect {\n\tcase <-waitTwo:\n\t\tt.Error(\"call does not block!\")\n\tcase <-time.After(10 * time.Millisecond):\n\t}\n\n\t// check non-blocking calls\n\n\twaitThree := make(chan struct{})\n\tgo func() {\n\t\tf.SupplyEntropyIfNeeded([]byte{0}, 0)\n\t\tclose(waitThree)\n\t}()\n\tselect {\n\tcase <-waitThree:\n\tcase <-time.After(10 * time.Millisecond):\n\t\tt.Error(\"call blocks!\")\n\t}\n\n\twaitFour := make(chan struct{})\n\tgo func() {\n\t\tf.SupplyEntropyAsIntIfNeeded(0, 0)\n\t\tclose(waitFour)\n\t}()\n\tselect {\n\tcase <-waitFour:\n\tcase <-time.After(10 * time.Millisecond):\n\t\tt.Error(\"call blocks!\")\n\t}\n}\n"
  },
  {
    "path": "base/rng/fullfeed.go",
    "content": "package rng\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc getFullFeedDuration() time.Duration {\n\t// full feed every 5x time of reseedAfterSeconds\n\tsecsUntilFullFeed := reseedAfterSeconds * 5\n\n\t// full feed at most once every ten minutes\n\tif secsUntilFullFeed < 600 {\n\t\tsecsUntilFullFeed = 600\n\t}\n\n\treturn time.Duration(secsUntilFullFeed) * time.Second\n}\n\nfunc fullFeeder(ctx *mgr.WorkerCtx) error {\n\tfullFeedDuration := getFullFeedDuration()\n\n\tfor {\n\t\tselect {\n\t\tcase <-time.After(fullFeedDuration):\n\n\t\t\trngLock.Lock()\n\t\tfeedAll:\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase data := <-rngFeeder:\n\t\t\t\t\trng.Reseed(data)\n\t\t\t\tdefault:\n\t\t\t\t\tbreak feedAll\n\t\t\t\t}\n\t\t\t}\n\t\t\trngLock.Unlock()\n\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/rng/fullfeed_test.go",
    "content": "package rng\n\nimport (\n\t\"testing\"\n)\n\nfunc TestFullFeeder(t *testing.T) {\n\tt.Parallel()\n\n\tfor range 10 {\n\t\tgo func() {\n\t\t\trngFeeder <- []byte{0}\n\t\t}()\n\t}\n}\n"
  },
  {
    "path": "base/rng/get.go",
    "content": "package rng\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n\t\"math\"\n\t\"time\"\n)\n\nconst (\n\treseedAfterSeconds = 600     // ten minutes\n\treseedAfterBytes   = 1048576 // one megabyte\n)\n\nvar (\n\t// Reader provides a global instance to read from the RNG.\n\tReader io.Reader\n\n\trngBytesRead uint64\n\trngLastFeed  = time.Now()\n)\n\n// reader provides an io.Reader interface.\ntype reader struct{}\n\nfunc init() {\n\tReader = reader{}\n}\n\nfunc checkEntropy() (err error) {\n\tif !rngReady {\n\t\treturn errors.New(\"RNG is not ready yet\")\n\t}\n\tif rngBytesRead > reseedAfterBytes ||\n\t\tint(time.Since(rngLastFeed).Seconds()) > reseedAfterSeconds {\n\t\tselect {\n\t\tcase r := <-rngFeeder:\n\t\t\trng.Reseed(r)\n\t\t\trngBytesRead = 0\n\t\t\trngLastFeed = time.Now()\n\t\tcase <-time.After(1 * time.Second):\n\t\t\treturn errors.New(\"failed to get new entropy\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Read reads random bytes into the supplied byte slice.\nfunc Read(b []byte) (n int, err error) {\n\trngLock.Lock()\n\tdefer rngLock.Unlock()\n\n\tif err := checkEntropy(); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn copy(b, rng.PseudoRandomData(uint(len(b)))), nil\n}\n\n// Read implements the io.Reader interface.\nfunc (r reader) Read(b []byte) (n int, err error) {\n\treturn Read(b)\n}\n\n// Bytes allocates a new byte slice of given length and fills it with random data.\nfunc Bytes(n int) ([]byte, error) {\n\trngLock.Lock()\n\tdefer rngLock.Unlock()\n\n\tif err := checkEntropy(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn rng.PseudoRandomData(uint(n)), nil\n}\n\n// Number returns a random number from 0 to (incl.) max.\nfunc Number(max uint64) (uint64, error) {\n\tsecureLimit := math.MaxUint64 - (math.MaxUint64 % max)\n\tmax++\n\n\tfor {\n\t\trandomBytes, err := Bytes(8)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tcandidate := binary.LittleEndian.Uint64(randomBytes)\n\t\tif candidate < secureLimit {\n\t\t\treturn candidate % max, nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/rng/get_test.go",
    "content": "package rng\n\nimport (\n\t\"testing\"\n)\n\nfunc TestNumberRandomness(t *testing.T) {\n\tt.Parallel()\n\n\t// skip in automated tests\n\tt.Logf(\"Integer number bias test deactivated, as it sometimes triggers.\")\n\tt.SkipNow()\n\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\tvar subjects uint64 = 10\n\tvar testSize uint64 = 10000\n\n\tresults := make([]uint64, int(subjects))\n\tfor range int(subjects * testSize) {\n\t\tn, err := Number(subjects - 1)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t\treturn\n\t\t}\n\t\tresults[int(n)]++\n\t}\n\n\t// catch big mistakes in the number function, eg. massive % bias\n\tlowerMargin := testSize - testSize/50\n\tupperMargin := testSize + testSize/50\n\tfor subject, result := range results {\n\t\tif result < lowerMargin || result > upperMargin {\n\t\t\tt.Errorf(\"subject %d is outside of margins: %d\", subject, result)\n\t\t}\n\t}\n\n\tt.Fatal(results)\n}\n"
  },
  {
    "path": "base/rng/osfeeder.go",
    "content": "package rng\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc osFeeder(ctx *mgr.WorkerCtx) error {\n\tentropyBytes := minFeedEntropy / 8\n\tfeeder := NewFeeder()\n\tdefer feeder.CloseFeeder()\n\n\tfor {\n\t\t// gather\n\t\tosEntropy := make([]byte, entropyBytes)\n\t\tn, err := rand.Read(osEntropy)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not read entropy from os: %w\", err)\n\t\t}\n\t\tif n != entropyBytes {\n\t\t\treturn fmt.Errorf(\"could not read enough entropy from os: got only %d bytes instead of %d\", n, entropyBytes)\n\t\t}\n\n\t\t// feed\n\t\tselect {\n\t\tcase feeder.input <- &entropyData{\n\t\t\tdata:    osEntropy,\n\t\t\tentropy: entropyBytes * 8,\n\t\t}:\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/rng/rng.go",
    "content": "package rng\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/aead/serpent\"\n\t\"github.com/seehuhn/fortuna\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// Rng is a random number generator.\ntype Rng struct {\n\tmgr *mgr.Manager\n\n\tinstance instance\n}\n\nvar (\n\trng      *fortuna.Generator\n\trngLock  sync.Mutex\n\trngReady = false\n\n\trngCipher = \"aes\"\n\t// Possible values: \"aes\", \"serpent\".\n)\n\nfunc newCipher(key []byte) (cipher.Block, error) {\n\tswitch rngCipher {\n\tcase \"aes\":\n\t\treturn aes.NewCipher(key)\n\tcase \"serpent\":\n\t\treturn serpent.NewCipher(key)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown or unsupported cipher: %s\", rngCipher)\n\t}\n}\n\n// Manager returns the module manager.\nfunc (r *Rng) Manager() *mgr.Manager {\n\treturn r.mgr\n}\n\n// Start starts the module.\nfunc (r *Rng) Start() error {\n\trngLock.Lock()\n\tdefer rngLock.Unlock()\n\n\trng = fortuna.NewGenerator(newCipher)\n\tif rng == nil {\n\t\treturn errors.New(\"failed to initialize rng\")\n\t}\n\n\t// add another (async) OS rng seed\n\tr.mgr.Go(\"initial rng feed\", func(_ *mgr.WorkerCtx) error {\n\t\t// get entropy from OS\n\t\tosEntropy := make([]byte, minFeedEntropy/8)\n\t\t_, err := rand.Read(osEntropy)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not read entropy from os: %w\", err)\n\t\t}\n\t\t// feed\n\t\trngLock.Lock()\n\t\trng.Reseed(osEntropy)\n\t\trngLock.Unlock()\n\t\treturn nil\n\t})\n\n\t// mark as ready\n\trngReady = true\n\n\t// random source: OS\n\tr.mgr.Go(\"os rng feeder\", osFeeder)\n\n\t// random source: goroutine ticks\n\tr.mgr.Go(\"tick rng feeder\", tickFeeder)\n\n\t// full feeder\n\tr.mgr.Go(\"full feeder\", fullFeeder)\n\n\treturn nil\n}\n\n// Stop stops the module.\nfunc (r *Rng) Stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *Rng\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new rng.\nfunc New(instance instance) (*Rng, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Rng\")\n\tmodule = &Rng{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "base/rng/rng_test.go",
    "content": "package rng\n\nimport (\n\t\"testing\"\n)\n\nfunc init() {\n\tvar err error\n\tmodule, err = New(struct{}{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = module.Start()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc TestRNG(t *testing.T) {\n\tt.Parallel()\n\n\tkey := make([]byte, 16)\n\n\trngCipher = \"aes\"\n\t_, err := newCipher(key)\n\tif err != nil {\n\t\tt.Errorf(\"failed to create aes cipher: %s\", err)\n\t}\n\n\trngCipher = \"serpent\"\n\t_, err = newCipher(key)\n\tif err != nil {\n\t\tt.Errorf(\"failed to create serpent cipher: %s\", err)\n\t}\n\n\tb := make([]byte, 32)\n\t_, err = Read(b)\n\tif err != nil {\n\t\tt.Errorf(\"Read failed: %s\", err)\n\t}\n\t_, err = Reader.Read(b)\n\tif err != nil {\n\t\tt.Errorf(\"Read failed: %s\", err)\n\t}\n\n\t_, err = Bytes(32)\n\tif err != nil {\n\t\tt.Errorf(\"Bytes failed: %s\", err)\n\t}\n\n\t_, err = Number(100)\n\tif err != nil {\n\t\tt.Errorf(\"Number failed: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "base/rng/tickfeeder.go",
    "content": "package rng\n\nimport (\n\t\"encoding/binary\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc getTickFeederTickDuration() time.Duration {\n\t// be ready in 1/10 time of reseedAfterSeconds\n\tmsecsAvailable := reseedAfterSeconds * 100\n\t// ex.: reseed after 10 minutes: msecsAvailable = 60000\n\t// have full entropy after 5 minutes\n\n\t// one tick generates 0,125 bits of entropy\n\tticksNeeded := minFeedEntropy * 8\n\t// ex.: minimum entropy is 256: ticksNeeded = 2048\n\n\t// msces between ticks\n\ttickMsecs := msecsAvailable / ticksNeeded\n\t// ex.: tickMsecs = 29(,296875)\n\n\t// use a minimum of 10 msecs per tick for good entropy\n\t// it would take 21 seconds to get full 256 bits of entropy with 10msec ticks\n\tif tickMsecs < 10 {\n\t\ttickMsecs = 10\n\t}\n\n\treturn time.Duration(tickMsecs) * time.Millisecond\n}\n\n// tickFeeder is a really simple entropy feeder that adds the least significant bit of the current nanosecond unixtime to its pool every time it 'ticks'.\n// The more work the program does, the better the quality, as the internal schedular cannot immediately run the goroutine when it's ready.\nfunc tickFeeder(ctx *mgr.WorkerCtx) error {\n\tvar value int64\n\tvar pushes int\n\tfeeder := NewFeeder()\n\tdefer feeder.CloseFeeder()\n\n\tticker := time.NewTicker(getTickFeederTickDuration())\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\t// add tick value\n\t\tvalue = (value << 1) | (time.Now().UnixNano() % 2)\n\t\tpushes++\n\n\t\tif pushes >= 64 {\n\t\t\t// convert to []byte\n\t\t\tb := make([]byte, 8)\n\t\t\tbinary.LittleEndian.PutUint64(b, uint64(value))\n\t\t\t// reset\n\t\t\tpushes = 0\n\n\t\t\t// feed\n\t\t\tselect {\n\t\t\tcase feeder.input <- &entropyData{\n\t\t\t\tdata:    b,\n\t\t\t\tentropy: 8,\n\t\t\t}:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/runtime/module.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// DefaultRegistry is the default registry\n// that is used by the module-level API.\nvar DefaultRegistry = NewRegistry()\n\ntype Runtime struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc (r *Runtime) Manager() *mgr.Manager {\n\treturn r.mgr\n}\n\nfunc (r *Runtime) Start() error {\n\t_, err := database.Register(&database.Database{\n\t\tName:         \"runtime\",\n\t\tDescription:  \"Runtime database\",\n\t\tStorageType:  \"injected\",\n\t\tShadowDelete: false,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := DefaultRegistry.InjectAsDatabase(\"runtime\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (r *Runtime) Stop() error {\n\treturn nil\n}\n\n// Register is like Registry.Register but uses\n// the package DefaultRegistry.\nfunc Register(key string, provider ValueProvider) (PushFunc, error) {\n\treturn DefaultRegistry.Register(key, provider)\n}\n\nvar (\n\tmodule     *Runtime\n\tshimLoaded atomic.Bool\n)\n\nfunc New(instance instance) (*Runtime, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"Runtime\")\n\tmodule = &Runtime{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "base/runtime/provider.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nvar (\n\t// ErrReadOnly should be returned from ValueProvider.Set if a\n\t// runtime record is considered read-only.\n\tErrReadOnly = errors.New(\"runtime record is read-only\")\n\t// ErrWriteOnly should be returned from ValueProvider.Get if\n\t// a runtime record is considered write-only.\n\tErrWriteOnly = errors.New(\"runtime record is write-only\")\n)\n\ntype (\n\t// PushFunc is returned when registering a new value provider\n\t// and can be used to inform the database system about the\n\t// availability of a new runtime record value. Similar to\n\t// database.Controller.PushUpdate, the caller must hold\n\t// the lock for each record passed to PushFunc.\n\tPushFunc func(...record.Record)\n\n\t// ValueProvider provides access to a runtime-computed\n\t// database record.\n\tValueProvider interface {\n\t\t// Set is called when the value is set from outside.\n\t\t// If the runtime value is considered read-only ErrReadOnly\n\t\t// should be returned. It is guaranteed that the key of\n\t\t// the record passed to Set is prefixed with the key used\n\t\t// to register the value provider.\n\t\tSet(r record.Record) (record.Record, error)\n\t\t// Get should return one or more records that match keyOrPrefix.\n\t\t// keyOrPrefix is guaranteed to be at least the prefix used to\n\t\t// register the ValueProvider.\n\t\tGet(keyOrPrefix string) ([]record.Record, error)\n\t}\n\n\t// SimpleValueSetterFunc is a convenience type for implementing a\n\t// write-only value provider.\n\tSimpleValueSetterFunc func(record.Record) (record.Record, error)\n\n\t// SimpleValueGetterFunc is a convenience type for implementing a\n\t// read-only value provider.\n\tSimpleValueGetterFunc func(keyOrPrefix string) ([]record.Record, error)\n)\n\n// Set implements ValueProvider.Set and calls fn.\nfunc (fn SimpleValueSetterFunc) Set(r record.Record) (record.Record, error) {\n\treturn fn(r)\n}\n\n// Get implements ValueProvider.Get and returns ErrWriteOnly.\nfunc (SimpleValueSetterFunc) Get(_ string) ([]record.Record, error) {\n\treturn nil, ErrWriteOnly\n}\n\n// Set implements ValueProvider.Set and returns ErrReadOnly.\nfunc (SimpleValueGetterFunc) Set(r record.Record) (record.Record, error) {\n\treturn nil, ErrReadOnly\n}\n\n// Get implements ValueProvider.Get and calls fn.\nfunc (fn SimpleValueGetterFunc) Get(keyOrPrefix string) ([]record.Record, error) {\n\treturn fn(keyOrPrefix)\n}\n\n// Compile time checks.\nvar (\n\t_ ValueProvider = SimpleValueGetterFunc(nil)\n\t_ ValueProvider = SimpleValueSetterFunc(nil)\n)\n"
  },
  {
    "path": "base/runtime/registry.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/armon/go-radix\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\t// ErrKeyTaken is returned when trying to register\n\t// a value provider at database key or prefix that\n\t// is already occupied by another provider.\n\tErrKeyTaken = errors.New(\"runtime key or prefix already used\")\n\t// ErrKeyUnmanaged is returned when a Put operation\n\t// on an unmanaged key is performed.\n\tErrKeyUnmanaged = errors.New(\"runtime key not managed by any provider\")\n\t// ErrInjected is returned by Registry.InjectAsDatabase\n\t// if the registry has already been injected.\n\tErrInjected = errors.New(\"registry already injected\")\n)\n\n// Registry keeps track of registered runtime\n// value providers and exposes them via an\n// injected database. Users normally just need\n// to use the defaul registry provided by this\n// package but may consider creating a dedicated\n// runtime registry on their own. Registry uses\n// a radix tree for value providers and their\n// chosen database key/prefix.\ntype Registry struct {\n\tl            sync.RWMutex\n\tproviders    *radix.Tree\n\tdbController *database.Controller\n\tdbName       string\n}\n\n// keyedValueProvider simply wraps a value provider with it's\n// registration prefix.\ntype keyedValueProvider struct {\n\tValueProvider\n\tkey string\n}\n\n// NewRegistry returns a new registry.\nfunc NewRegistry() *Registry {\n\treturn &Registry{\n\t\tproviders: radix.New(),\n\t}\n}\n\nfunc isPrefixKey(key string) bool {\n\treturn strings.HasSuffix(key, \"/\")\n}\n\n// DatabaseName returns the name of the database where the\n// registry has been injected. It returns an empty string\n// if InjectAsDatabase has not been called.\nfunc (r *Registry) DatabaseName() string {\n\tr.l.RLock()\n\tdefer r.l.RUnlock()\n\n\treturn r.dbName\n}\n\n// InjectAsDatabase injects the registry as the storage\n// database for name.\nfunc (r *Registry) InjectAsDatabase(name string) error {\n\tr.l.Lock()\n\tdefer r.l.Unlock()\n\n\tif r.dbController != nil {\n\t\treturn ErrInjected\n\t}\n\n\tctrl, err := database.InjectDatabase(name, r.asStorage())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.dbName = name\n\tr.dbController = ctrl\n\n\treturn nil\n}\n\n// Register registers a new value provider p under keyOrPrefix. The\n// returned PushFunc can be used to send update notitifcations to\n// database subscribers. Note that keyOrPrefix must end in '/' to be\n// accepted as a prefix.\nfunc (r *Registry) Register(keyOrPrefix string, p ValueProvider) (PushFunc, error) {\n\tr.l.Lock()\n\tdefer r.l.Unlock()\n\n\t// search if there's a provider registered for a prefix\n\t// that matches or is equal to keyOrPrefix.\n\tkey, _, ok := r.providers.LongestPrefix(keyOrPrefix)\n\tif ok && (isPrefixKey(key) || key == keyOrPrefix) {\n\t\treturn nil, fmt.Errorf(\"%w: found provider on %s\", ErrKeyTaken, key)\n\t}\n\n\t// if keyOrPrefix is a prefix there must not be any provider\n\t// registered for a key that matches keyOrPrefix.\n\tif isPrefixKey(keyOrPrefix) {\n\t\tfoundProvider := \"\"\n\t\tr.providers.WalkPrefix(keyOrPrefix, func(s string, _ interface{}) bool {\n\t\t\tfoundProvider = s\n\t\t\treturn true\n\t\t})\n\t\tif foundProvider != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"%w: found provider on %s\", ErrKeyTaken, foundProvider)\n\t\t}\n\t}\n\n\tr.providers.Insert(keyOrPrefix, &keyedValueProvider{\n\t\tValueProvider: TraceProvider(p),\n\t\tkey:           keyOrPrefix,\n\t})\n\n\tlog.Tracef(\"runtime: registered new provider at %s\", keyOrPrefix)\n\n\treturn func(records ...record.Record) {\n\t\tr.l.RLock()\n\t\tdefer r.l.RUnlock()\n\n\t\tif r.dbController == nil {\n\t\t\treturn\n\t\t}\n\n\t\tfor _, rec := range records {\n\t\t\tr.dbController.PushUpdate(rec)\n\t\t}\n\t}, nil\n}\n\n// Get returns the runtime value that is identified by key.\n// It implements the storage.Interface.\nfunc (r *Registry) Get(key string) (record.Record, error) {\n\tprovider := r.getMatchingProvider(key)\n\tif provider == nil {\n\t\treturn nil, database.ErrNotFound\n\t}\n\n\trecords, err := provider.Get(key)\n\tif err != nil {\n\t\t// instead of returning ErrWriteOnly to the database interface\n\t\t// we wrap it in ErrNotFound so the records effectively gets\n\t\t// hidden.\n\t\tif errors.Is(err, ErrWriteOnly) {\n\t\t\treturn nil, database.ErrNotFound\n\t\t}\n\t\treturn nil, err\n\t}\n\n\t// Get performs an exact match so filter out\n\t// and values that do not match key.\n\tfor _, r := range records {\n\t\tif r.DatabaseKey() == key {\n\t\t\treturn r, nil\n\t\t}\n\t}\n\n\treturn nil, database.ErrNotFound\n}\n\n// Put stores the record m in the runtime database. Note that\n// ErrReadOnly is returned if there's no value provider responsible\n// for m.Key().\nfunc (r *Registry) Put(m record.Record) (record.Record, error) {\n\tprovider := r.getMatchingProvider(m.DatabaseKey())\n\tif provider == nil {\n\t\t// if there's no provider for the given value\n\t\t// return ErrKeyUnmanaged.\n\t\treturn nil, ErrKeyUnmanaged\n\t}\n\n\tres, err := provider.Set(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn res, nil\n}\n\n// Query performs a query on the runtime registry returning all\n// records across all value providers that match q.\n// Query implements the storage.Storage interface.\nfunc (r *Registry) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\tif _, err := q.Check(); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\tsearchPrefix := q.DatabaseKeyPrefix()\n\tproviders := r.collectProviderByPrefix(searchPrefix)\n\tif len(providers) == 0 {\n\t\treturn nil, fmt.Errorf(\"%w: for key %s\", ErrKeyUnmanaged, searchPrefix)\n\t}\n\n\titer := iterator.New()\n\n\tgrp := new(errgroup.Group)\n\tfor idx := range providers {\n\t\tp := providers[idx]\n\n\t\tgrp.Go(func() (err error) {\n\t\t\tdefer recovery(&err)\n\n\t\t\tkey := p.key\n\t\t\tif len(searchPrefix) > len(key) {\n\t\t\t\tkey = searchPrefix\n\t\t\t}\n\n\t\t\trecords, err := p.Get(key)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, ErrWriteOnly) {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, r := range records {\n\t\t\t\tr.Lock()\n\t\t\t\tvar (\n\t\t\t\t\tmatchesKey = q.MatchesKey(r.DatabaseKey())\n\t\t\t\t\tisValid    = r.Meta().CheckValidity()\n\t\t\t\t\tisAllowed  = r.Meta().CheckPermission(local, internal)\n\n\t\t\t\t\tallowed = matchesKey && isValid && isAllowed\n\t\t\t\t)\n\t\t\t\tif allowed {\n\t\t\t\t\tallowed = q.MatchesRecord(r)\n\t\t\t\t}\n\t\t\t\tr.Unlock()\n\n\t\t\t\tif !allowed {\n\t\t\t\t\tlog.Tracef(\"runtime: not sending %s for query %s. matchesKey=%v isValid=%v isAllowed=%v\", r.DatabaseKey(), searchPrefix, matchesKey, isValid, isAllowed)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tselect {\n\t\t\t\tcase iter.Next <- r:\n\t\t\t\tcase <-iter.Done:\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tgo func() {\n\t\terr := grp.Wait()\n\t\titer.Finish(err)\n\t}()\n\n\treturn iter, nil\n}\n\nfunc (r *Registry) getMatchingProvider(key string) *keyedValueProvider {\n\tr.l.RLock()\n\tdefer r.l.RUnlock()\n\n\tproviderKey, provider, ok := r.providers.LongestPrefix(key)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tif !isPrefixKey(providerKey) && providerKey != key {\n\t\treturn nil\n\t}\n\n\treturn provider.(*keyedValueProvider) //nolint:forcetypeassert\n}\n\nfunc (r *Registry) collectProviderByPrefix(prefix string) []*keyedValueProvider {\n\tr.l.RLock()\n\tdefer r.l.RUnlock()\n\n\t// if there's a LongestPrefix provider that's the only one\n\t// we need to ask\n\tif _, p, ok := r.providers.LongestPrefix(prefix); ok {\n\t\treturn []*keyedValueProvider{p.(*keyedValueProvider)} //nolint:forcetypeassert\n\t}\n\n\tvar providers []*keyedValueProvider\n\tr.providers.WalkPrefix(prefix, func(key string, p interface{}) bool {\n\t\tproviders = append(providers, p.(*keyedValueProvider)) //nolint:forcetypeassert\n\t\treturn false\n\t})\n\n\treturn providers\n}\n\n// GetRegistrationKeys returns a list of all provider registration\n// keys or prefixes.\nfunc (r *Registry) GetRegistrationKeys() []string {\n\tr.l.RLock()\n\tdefer r.l.RUnlock()\n\n\tvar keys []string\n\n\tr.providers.Walk(func(key string, p interface{}) bool {\n\t\tkeys = append(keys, key)\n\t\treturn false\n\t})\n\treturn keys\n}\n\n// asStorage returns a storage.Interface compatible struct\n// that is backed by r.\nfunc (r *Registry) asStorage() storage.Interface {\n\treturn &storageWrapper{\n\t\tRegistry: r,\n\t}\n}\n\nfunc recovery(err *error) {\n\tif x := recover(); x != nil {\n\t\tif e, ok := x.(error); ok {\n\t\t\t*err = e\n\t\t\treturn\n\t\t}\n\n\t\t*err = fmt.Errorf(\"%v\", x)\n\t}\n}\n"
  },
  {
    "path": "base/runtime/registry_test.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\ntype testRecord struct {\n\trecord.Base\n\tsync.Mutex\n\tValue string\n}\n\nfunc makeTestRecord(key, value string) record.Record {\n\tr := &testRecord{Value: value}\n\tr.CreateMeta()\n\tr.SetKey(\"runtime:\" + key)\n\treturn r\n}\n\ntype testProvider struct {\n\tk string\n\tr []record.Record\n}\n\nfunc (tp *testProvider) Get(key string) ([]record.Record, error) {\n\treturn tp.r, nil\n}\n\nfunc (tp *testProvider) Set(r record.Record) (record.Record, error) {\n\treturn nil, errors.New(\"not implemented\")\n}\n\nfunc getTestRegistry(t *testing.T) *Registry {\n\tt.Helper()\n\n\tr := NewRegistry()\n\n\tproviders := []testProvider{\n\t\t{\n\t\t\tk: \"p1/\",\n\t\t\tr: []record.Record{\n\t\t\t\tmakeTestRecord(\"p1/f1/v1\", \"p1.1\"),\n\t\t\t\tmakeTestRecord(\"p1/f2/v2\", \"p1.2\"),\n\t\t\t\tmakeTestRecord(\"p1/v3\", \"p1.3\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tk: \"p2/f1\",\n\t\t\tr: []record.Record{\n\t\t\t\tmakeTestRecord(\"p2/f1/v1\", \"p2.1\"),\n\t\t\t\tmakeTestRecord(\"p2/f1/f2/v2\", \"p2.2\"),\n\t\t\t\tmakeTestRecord(\"p2/f1/v3\", \"p2.3\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor idx := range providers {\n\t\tp := providers[idx]\n\t\t_, err := r.Register(p.k, &p)\n\t\trequire.NoError(t, err)\n\t}\n\n\treturn r\n}\n\nfunc TestRegistryGet(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\tr   record.Record\n\t\terr error\n\t)\n\n\treg := getTestRegistry(t)\n\n\tr, err = reg.Get(\"p1/f1/v1\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, r)\n\tassert.Equal(t, \"p1.1\", r.(*testRecord).Value) //nolint:forcetypeassert\n\n\tr, err = reg.Get(\"p1/v3\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, r)\n\tassert.Equal(t, \"p1.3\", r.(*testRecord).Value) //nolint:forcetypeassert\n\n\tr, err = reg.Get(\"p1/v4\")\n\trequire.Error(t, err)\n\tassert.Nil(t, r)\n\n\tr, err = reg.Get(\"no-provider/foo\")\n\trequire.Error(t, err)\n\tassert.Nil(t, r)\n}\n\nfunc TestRegistryQuery(t *testing.T) {\n\tt.Parallel()\n\n\treg := getTestRegistry(t)\n\n\tq := query.New(\"runtime:p\")\n\titer, err := reg.Query(q, true, true)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, iter)\n\tvar records []record.Record //nolint:prealloc\n\tfor r := range iter.Next {\n\t\trecords = append(records, r)\n\t}\n\tassert.Len(t, records, 6)\n\n\tq = query.New(\"runtime:p1/f\")\n\titer, err = reg.Query(q, true, true)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, iter)\n\trecords = nil\n\tfor r := range iter.Next {\n\t\trecords = append(records, r)\n\t}\n\tassert.Len(t, records, 2)\n}\n\nfunc TestRegistryRegister(t *testing.T) {\n\tt.Parallel()\n\n\tr := NewRegistry()\n\n\tcases := []struct {\n\t\tinp string\n\t\terr bool\n\t}{\n\t\t{\"runtime:foo/bar/bar\", false},\n\t\t{\"runtime:foo/bar/bar2\", false},\n\t\t{\"runtime:foo/bar\", false},\n\t\t{\"runtime:foo/bar\", true},  // already used\n\t\t{\"runtime:foo/bar/\", true}, // cannot register a prefix if there are providers below\n\t\t{\"runtime:foo/baz/\", false},\n\t\t{\"runtime:foo/baz2/\", false},\n\t\t{\"runtime:foo/baz3\", false},\n\t\t{\"runtime:foo/baz/bar\", true},\n\t}\n\n\tfor _, c := range cases {\n\t\t_, err := r.Register(c.inp, nil)\n\t\tif c.err {\n\t\t\tassert.Error(t, err, c.inp)\n\t\t} else {\n\t\t\tassert.NoError(t, err, c.inp)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/runtime/singe_record_provider.go",
    "content": "package runtime\n\nimport \"github.com/safing/portmaster/base/database/record\"\n\n// singleRecordReader is a convenience type for read-only exposing\n// a single record.Record. Note that users must lock the whole record\n// themself before performing any manipulation on the record.\ntype singleRecordReader struct {\n\trecord.Record\n}\n\n// ProvideRecord returns a ValueProvider the exposes read-only\n// access to r. Users of ProvideRecord need to ensure the lock\n// the whole record before performing modifications on it.\n//\n// Example:\n//\n//\ttype MyValue struct {\n//\t\trecord.Base\n//\t\tValue string\n//\t}\n//\tr := new(MyValue)\n//\tpushUpdate, _ := runtime.Register(\"my/key\", ProvideRecord(r))\n//\tr.Lock()\n//\tr.Value = \"foobar\"\n//\tpushUpdate(r)\n//\tr.Unlock()\nfunc ProvideRecord(r record.Record) ValueProvider {\n\treturn &singleRecordReader{r}\n}\n\n// Set implements ValueProvider.Set and returns ErrReadOnly.\nfunc (sr *singleRecordReader) Set(_ record.Record) (record.Record, error) {\n\treturn nil, ErrReadOnly\n}\n\n// Get implements ValueProvider.Get and returns the wrapped record.Record\n// but only if keyOrPrefix exactly matches the records database key.\nfunc (sr *singleRecordReader) Get(keyOrPrefix string) ([]record.Record, error) {\n\tif keyOrPrefix != sr.Record.DatabaseKey() {\n\t\treturn nil, nil\n\t}\n\treturn []record.Record{sr.Record}, nil\n}\n"
  },
  {
    "path": "base/runtime/storage.go",
    "content": "package runtime\n\nimport (\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n)\n\n// storageWrapper is a simple wrapper around storage.InjectBase and\n// Registry and make sure the supported methods are handled by\n// the registry rather than the InjectBase defaults.\n// storageWrapper is mainly there to keep the method landscape of\n// Registry as small as possible.\ntype storageWrapper struct {\n\tstorage.InjectBase\n\tRegistry *Registry\n}\n\nfunc (sw *storageWrapper) Get(key string) (record.Record, error) {\n\treturn sw.Registry.Get(key)\n}\n\nfunc (sw *storageWrapper) Put(r record.Record) (record.Record, error) {\n\treturn sw.Registry.Put(r)\n}\n\nfunc (sw *storageWrapper) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\treturn sw.Registry.Query(q, local, internal)\n}\n\nfunc (sw *storageWrapper) ReadOnly() bool { return false }\n"
  },
  {
    "path": "base/runtime/trace_provider.go",
    "content": "package runtime\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// traceValueProvider can be used to wrap an\n// existing value provider to trace an calls to\n// their Set and Get methods.\ntype traceValueProvider struct {\n\tValueProvider\n}\n\n// TraceProvider returns a new ValueProvider that wraps\n// vp but traces all Set and Get methods calls.\nfunc TraceProvider(vp ValueProvider) ValueProvider {\n\treturn &traceValueProvider{vp}\n}\n\nfunc (tvp *traceValueProvider) Set(r record.Record) (res record.Record, err error) {\n\tdefer func(start time.Time) {\n\t\tlog.Tracef(\"runtime: setting record %q: duration=%s err=%v\", r.Key(), time.Since(start), err)\n\t}(time.Now())\n\n\treturn tvp.ValueProvider.Set(r)\n}\n\nfunc (tvp *traceValueProvider) Get(keyOrPrefix string) (records []record.Record, err error) {\n\tdefer func(start time.Time) {\n\t\tlog.Tracef(\"runtime: loading records %q: duration=%s err=%v #records=%d\", keyOrPrefix, time.Since(start), err, len(records))\n\t}(time.Now())\n\n\treturn tvp.ValueProvider.Get(keyOrPrefix)\n}\n"
  },
  {
    "path": "base/template/module.go",
    "content": "package template\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// Template showcases the usage of the module system.\ntype Template struct {\n\ti      instance\n\tm      *mgr.Manager\n\tstates *mgr.StateMgr\n\n\tEventRecordAdded   *mgr.EventMgr[string]\n\tEventRecordDeleted *mgr.EventMgr[string]\n\n\tspecialWorkerMgr *mgr.WorkerMgr\n}\n\ntype instance interface{}\n\n// New returns a new template.\nfunc New(instance instance) (*Template, error) {\n\tm := mgr.New(\"template\")\n\tt := &Template{\n\t\ti:      instance,\n\t\tm:      m,\n\t\tstates: m.NewStateMgr(),\n\n\t\tEventRecordAdded:   mgr.NewEventMgr[string](\"record added\", m),\n\t\tEventRecordDeleted: mgr.NewEventMgr[string](\"record deleted\", m),\n\n\t\tspecialWorkerMgr: m.NewWorkerMgr(\"special worker\", serviceWorker, nil),\n\t}\n\n\t// register options\n\terr := config.Register(&config.Option{\n\t\tName:            \"language\",\n\t\tKey:             \"template/language\",\n\t\tDescription:     \"Sets the language for the template [TEMPLATE]\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelUser, // default\n\t\tReleaseLevel:    config.ReleaseLevelStable, // default\n\t\tRequiresRestart: false,                     // default\n\t\tDefaultValue:    \"en\",\n\t\tValidationRegex: \"^[a-z]{2}$\",\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn t, nil\n}\n\n// Manager returns the module manager.\nfunc (t *Template) Manager() *mgr.Manager {\n\treturn t.m\n}\n\n// States returns the module states.\nfunc (t *Template) States() *mgr.StateMgr {\n\treturn t.states\n}\n\n// Start starts the module.\nfunc (t *Template) Start() error {\n\tt.m.Go(\"worker\", serviceWorker)\n\tt.specialWorkerMgr.Delay(10 * time.Minute)\n\n\treturn nil\n}\n\n// Stop stops the module.\nfunc Stop() error {\n\treturn nil\n}\n\nfunc serviceWorker(w *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-time.After(1 * time.Second):\n\t\t\terr := do()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase <-w.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc do() error {\n\treturn nil\n}\n"
  },
  {
    "path": "base/utils/atomic.go",
    "content": "package utils\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\n\t\"github.com/safing/portmaster/base/utils/renameio\"\n)\n\n// AtomicFileOptions holds additional options for manipulating\n// the behavior of CreateAtomic and friends.\ntype AtomicFileOptions struct {\n\t// Mode is the file mode for the new file. If\n\t// 0, the file mode will be set to 0600.\n\tMode os.FileMode\n\n\t// TempDir is the path to the temp-directory\n\t// that should be used. If empty, it defaults\n\t// to the system temp.\n\tTempDir string\n}\n\n// CreateAtomic creates or overwrites a file at dest atomically using\n// data from r. Atomic means that even in case of a power outage,\n// dest will never be a zero-length file. It will always either contain\n// the previous data (or not exist) or the new data but never anything\n// in between.\nfunc CreateAtomic(dest string, r io.Reader, opts *AtomicFileOptions) error {\n\tif opts == nil {\n\t\topts = &AtomicFileOptions{}\n\t}\n\n\ttmpFile, err := renameio.TempFile(opts.TempDir, dest)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temp file: %w\", err)\n\t}\n\tdefer tmpFile.Cleanup() //nolint:errcheck\n\n\tif opts.Mode != 0 {\n\t\tif err := tmpFile.Chmod(opts.Mode); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update mode bits of temp file: %w\", err)\n\t\t}\n\t}\n\n\tif _, err := io.Copy(tmpFile, r); err != nil {\n\t\treturn fmt.Errorf(\"failed to copy source file: %w\", err)\n\t}\n\n\tif err := tmpFile.CloseAtomicallyReplace(); err != nil {\n\t\treturn fmt.Errorf(\"failed to rename temp file to %q\", dest)\n\t}\n\n\treturn nil\n}\n\n// CopyFileAtomic is like CreateAtomic but copies content from\n// src to dest. If opts.Mode is 0 CopyFileAtomic tries to set\n// the file mode of src to dest.\nfunc CopyFileAtomic(dest string, src string, opts *AtomicFileOptions) error {\n\tif opts == nil {\n\t\topts = &AtomicFileOptions{}\n\t}\n\n\tif opts.Mode == 0 {\n\t\tstat, err := os.Stat(src)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\topts.Mode = stat.Mode()\n\t}\n\n\tf, err := os.Open(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = f.Close()\n\t}()\n\n\treturn CreateAtomic(dest, f, opts)\n}\n\n// ReplaceFileAtomic replaces the file at dest with the content from src.\n// If dest exists it's file mode copied and used for the replacement. If\n// not, dest will get the same file mode as src. See CopyFileAtomic and\n// CreateAtomic for more information.\nfunc ReplaceFileAtomic(dest string, src string, opts *AtomicFileOptions) error {\n\tif opts == nil {\n\t\topts = &AtomicFileOptions{}\n\t}\n\n\tif opts.Mode == 0 {\n\t\tstat, err := os.Stat(dest)\n\t\tif err == nil {\n\t\t\topts.Mode = stat.Mode()\n\t\t} else if !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn CopyFileAtomic(dest, src, opts)\n}\n"
  },
  {
    "path": "base/utils/broadcastflag.go",
    "content": "package utils\n\nimport (\n\t\"sync\"\n\n\t\"github.com/tevino/abool\"\n)\n\n// BroadcastFlag is a simple system to broadcast a flag value.\ntype BroadcastFlag struct {\n\tflag   *abool.AtomicBool\n\tsignal chan struct{}\n\tlock   sync.Mutex\n}\n\n// Flag receives changes from its broadcasting flag.\n// A Flag must only be used in one goroutine and is not concurrency safe,\n// but fast.\ntype Flag struct {\n\tflag        *abool.AtomicBool\n\tsignal      chan struct{}\n\tbroadcaster *BroadcastFlag\n}\n\n// NewBroadcastFlag returns a new BroadcastFlag.\n// In the initial state, the flag is not set and the signal does not trigger.\nfunc NewBroadcastFlag() *BroadcastFlag {\n\treturn &BroadcastFlag{\n\t\tflag:   abool.New(),\n\t\tsignal: make(chan struct{}),\n\t\tlock:   sync.Mutex{},\n\t}\n}\n\n// NewFlag returns a new Flag that listens to this broadcasting flag.\n// In the initial state, the flag is set and the signal triggers.\n// You can call Refresh immediately to get the current state from the\n// broadcasting flag.\nfunc (bf *BroadcastFlag) NewFlag() *Flag {\n\tnewFlag := &Flag{\n\t\tflag:        abool.NewBool(true),\n\t\tsignal:      make(chan struct{}),\n\t\tbroadcaster: bf,\n\t}\n\tclose(newFlag.signal)\n\treturn newFlag\n}\n\n// NotifyAndReset notifies all flags of this broadcasting flag and resets the\n// internal broadcast flag state.\nfunc (bf *BroadcastFlag) NotifyAndReset() {\n\tbf.lock.Lock()\n\tdefer bf.lock.Unlock()\n\n\t// Notify all flags of the change.\n\tbf.flag.Set()\n\tclose(bf.signal)\n\n\t// Reset\n\tbf.flag = abool.New()\n\tbf.signal = make(chan struct{})\n}\n\n// Signal returns a channel that waits for the flag to be set. This does not\n// reset the Flag itself, you'll need to call Refresh for that.\nfunc (f *Flag) Signal() <-chan struct{} {\n\treturn f.signal\n}\n\n// IsSet returns whether the flag was set since the last Refresh.\n// This does not reset the Flag itself, you'll need to call Refresh for that.\nfunc (f *Flag) IsSet() bool {\n\treturn f.flag.IsSet()\n}\n\n// Refresh fetches the current state from the broadcasting flag.\nfunc (f *Flag) Refresh() {\n\tf.broadcaster.lock.Lock()\n\tdefer f.broadcaster.lock.Unlock()\n\n\t// Copy current flag and signal from the broadcasting flag.\n\tf.flag = f.broadcaster.flag\n\tf.signal = f.broadcaster.signal\n}\n"
  },
  {
    "path": "base/utils/call_limiter.go",
    "content": "package utils\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// CallLimiter bundles concurrent calls and optionally limits how fast a function is called.\ntype CallLimiter struct {\n\tpause time.Duration\n\n\tinLock   sync.Mutex\n\tlastExec time.Time\n\n\twaiters atomic.Int32\n\toutLock sync.Mutex\n}\n\n// NewCallLimiter returns a new call limiter.\n// Set minPause to zero to disable the minimum pause between calls.\nfunc NewCallLimiter(minPause time.Duration) *CallLimiter {\n\treturn &CallLimiter{\n\t\tpause: minPause,\n\t}\n}\n\n// Do executes the given function.\n// All concurrent calls to Do are bundled and return when f() finishes.\n// Waits until the minimum pause is over before executing f() again.\nfunc (l *CallLimiter) Do(f func()) {\n\t// Wait for the previous waiters to exit.\n\tl.inLock.Lock()\n\n\t// Defer final unlock to safeguard from panics.\n\tdefer func() {\n\t\t// Execution is finished - leave.\n\t\t// If we are the last waiter, let the next batch in.\n\t\tif l.waiters.Add(-1) == 0 {\n\t\t\tl.inLock.Unlock()\n\t\t}\n\t}()\n\n\t// Check if we are the first waiter.\n\tif l.waiters.Add(1) == 1 {\n\t\t// Take the lead on this execution run.\n\t\tl.lead(f)\n\t} else {\n\t\t// We are not the first waiter, let others in.\n\t\tl.inLock.Unlock()\n\t}\n\n\t// Wait for execution to complete.\n\tl.outLock.Lock()\n\tl.outLock.Unlock() //nolint:staticcheck\n\n\t// Last statement is in defer above.\n}\n\nfunc (l *CallLimiter) lead(f func()) {\n\t// Make all others wait while we execute the function.\n\tl.outLock.Lock()\n\n\t// Unlock in lock until execution is finished.\n\tl.inLock.Unlock()\n\n\t// Transition from out lock to in lock when done.\n\tdefer func() {\n\t\t// Update last execution time.\n\t\tl.lastExec = time.Now().UTC()\n\t\t// Stop newcomers from waiting on previous execution.\n\t\tl.inLock.Lock()\n\t\t// Allow waiters to leave.\n\t\tl.outLock.Unlock()\n\t}()\n\n\t// Wait for the minimum duration between executions.\n\tif l.pause > 0 {\n\t\tsinceLastExec := time.Since(l.lastExec)\n\t\tif sinceLastExec < l.pause {\n\t\t\ttime.Sleep(l.pause - sinceLastExec)\n\t\t}\n\t}\n\n\t// Execute.\n\tf()\n}\n"
  },
  {
    "path": "base/utils/call_limiter2.go",
    "content": "package utils\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// CallLimiter2 bundles concurrent calls and optionally limits how fast a function is called.\ntype CallLimiter2 struct {\n\tpause time.Duration\n\n\tslot     atomic.Int64\n\tslotWait sync.RWMutex\n\n\texecuting atomic.Bool\n\tlastExec  time.Time\n}\n\n// NewCallLimiter2 returns a new call limiter.\n// Set minPause to zero to disable the minimum pause between calls.\nfunc NewCallLimiter2(minPause time.Duration) *CallLimiter2 {\n\treturn &CallLimiter2{\n\t\tpause: minPause,\n\t}\n}\n\n// Do executes the given function.\n// All concurrent calls to Do are bundled and return when f() finishes.\n// Waits until the minimum pause is over before executing f() again.\nfunc (l *CallLimiter2) Do(f func()) {\n\t// Get ticket number.\n\tslot := l.slot.Load()\n\n\t// Check if we can execute.\n\tif l.executing.CompareAndSwap(false, true) {\n\t\t// Make others wait.\n\t\tl.slotWait.Lock()\n\t\tdefer l.slotWait.Unlock()\n\n\t\t// Execute and return.\n\t\tl.waitAndExec(f)\n\t\treturn\n\t}\n\n\t// Wait for slot to end and check if slot is done.\n\tfor l.slot.Load() == slot {\n\t\ttime.Sleep(100 * time.Microsecond)\n\t\tl.slotWait.RLock()\n\t\tl.slotWait.RUnlock() //nolint:staticcheck\n\t}\n}\n\nfunc (l *CallLimiter2) waitAndExec(f func()) {\n\tdefer func() {\n\t\t// Update last exec time.\n\t\tl.lastExec = time.Now().UTC()\n\t\t// Enable next execution first.\n\t\tl.executing.Store(false)\n\t\t// Move to next slot aftewards to prevent wait loops.\n\t\tl.slot.Add(1)\n\t}()\n\n\t// Wait for the minimum duration between executions.\n\tif l.pause > 0 {\n\t\tsinceLastExec := time.Since(l.lastExec)\n\t\tif sinceLastExec < l.pause {\n\t\t\ttime.Sleep(l.pause - sinceLastExec)\n\t\t}\n\t}\n\n\t// Execute.\n\tf()\n}\n"
  },
  {
    "path": "base/utils/call_limiter_test.go",
    "content": "package utils\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n)\n\nfunc TestCallLimiter(t *testing.T) {\n\tt.Parallel()\n\n\tpause := 10 * time.Millisecond\n\toa := NewCallLimiter2(pause)\n\texecuted := abool.New()\n\tvar testWg sync.WaitGroup\n\n\t// One execution should gobble up the whole batch.\n\t// We are doing this without sleep in function, so dummy exec first to trigger first pause.\n\toa.Do(func() {})\n\t// Start\n\tfor range 10 {\n\t\ttestWg.Add(100)\n\t\tfor range 100 {\n\t\t\tgo func() {\n\t\t\t\toa.Do(func() {\n\t\t\t\t\tif !executed.SetToIf(false, true) {\n\t\t\t\t\t\tt.Errorf(\"concurrent execution!\")\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\ttestWg.Done()\n\t\t\t}()\n\t\t}\n\t\ttestWg.Wait()\n\t\t// Check if function was executed at least once.\n\t\tif executed.IsNotSet() {\n\t\t\tt.Errorf(\"no execution!\")\n\t\t}\n\t\texecuted.UnSet() // reset check\n\t}\n\n\t// Wait for 2x pause to reset.\n\ttime.Sleep(2 * pause)\n\n\t// Continuous use with re-execution.\n\t// Choose values so that about 10 executions are expected\n\tvar execs uint32\n\ttestWg.Add(100)\n\tfor range 100 {\n\t\tgo func() {\n\t\t\toa.Do(func() {\n\t\t\t\tatomic.AddUint32(&execs, 1)\n\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t})\n\t\t\ttestWg.Done()\n\t\t}()\n\n\t\t// Start one goroutine every 1ms.\n\t\ttime.Sleep(1 * time.Millisecond)\n\t}\n\n\ttestWg.Wait()\n\tif execs <= 5 {\n\t\tt.Errorf(\"unexpected low exec count: %d\", execs)\n\t}\n\tif execs >= 15 {\n\t\tt.Errorf(\"unexpected high exec count: %d\", execs)\n\t}\n\n\t// Wait for 2x pause to reset.\n\ttime.Sleep(2 * pause)\n\n\t// Check if the limiter correctly handles panics.\n\ttestWg.Add(100)\n\tfor range 100 {\n\t\tgo func() {\n\t\t\tdefer func() {\n\t\t\t\t_ = recover()\n\t\t\t\ttestWg.Done()\n\t\t\t}()\n\t\t\toa.Do(func() {\n\t\t\t\ttime.Sleep(1 * time.Millisecond)\n\t\t\t\tpanic(\"test\")\n\t\t\t})\n\t\t}()\n\t\ttime.Sleep(100 * time.Microsecond)\n\t}\n\ttestWg.Wait()\n}\n"
  },
  {
    "path": "base/utils/debug/debug.go",
    "content": "package debug\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"runtime/pprof\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// Info gathers debugging information and stores everything in a buffer in\n// order to write it to somewhere later. It directly inherits a bytes.Buffer,\n// so you can also use all these functions too.\ntype Info struct {\n\tbytes.Buffer\n\tStyle string\n}\n\n// InfoFlag defines possible options for adding sections to a Info.\ntype InfoFlag int\n\nconst (\n\t// NoFlags does nothing.\n\tNoFlags InfoFlag = 0\n\n\t// UseCodeSection wraps the section content in a markdown code section.\n\tUseCodeSection InfoFlag = 1\n\n\t// AddContentLineBreaks adds a line breaks after each line of content,\n\t// except for the last.\n\tAddContentLineBreaks InfoFlag = 2\n)\n\nfunc useCodeSection(flags InfoFlag) bool {\n\treturn flags&UseCodeSection > 0\n}\n\nfunc addContentLineBreaks(flags InfoFlag) bool {\n\treturn flags&AddContentLineBreaks > 0\n}\n\n// AddSection adds a debug section to the Info. The result is directly\n// written into the buffer.\nfunc (di *Info) AddSection(name string, flags InfoFlag, content ...string) {\n\t// Check if we need a spacer.\n\tif di.Len() > 0 {\n\t\t_, _ = di.WriteString(\"\\n\\n\")\n\t}\n\n\t// Write section to buffer.\n\n\t// Write section header.\n\tif di.Style == \"github\" {\n\t\t_, _ = di.WriteString(fmt.Sprintf(\"<details>\\n<summary>%s</summary>\\n\\n\", name))\n\t} else {\n\t\t_, _ = di.WriteString(fmt.Sprintf(\"**%s**:\\n\\n\", name))\n\t}\n\n\t// Write section content.\n\tif useCodeSection(flags) {\n\t\t// Write code header: Needs one empty line between previous data.\n\t\t_, _ = di.WriteString(\"```\\n\")\n\t}\n\tfor i, part := range content {\n\t\t_, _ = di.WriteString(part)\n\t\tif addContentLineBreaks(flags) && i < len(content)-1 {\n\t\t\t_, _ = di.WriteString(\"\\n\")\n\t\t}\n\t}\n\tif useCodeSection(flags) {\n\t\t// Write code footer: Needs one empty line between next data.\n\t\t_, _ = di.WriteString(\"\\n```\\n\")\n\t}\n\n\t// Write section header.\n\tif di.Style == \"github\" {\n\t\t_, _ = di.WriteString(\"\\n</details>\")\n\t}\n}\n\n// AddVersionInfo adds version information from the info pkg.\nfunc (di *Info) AddVersionInfo() {\n\tdi.AddSection(\n\t\t\"Version \"+info.Version(),\n\t\tUseCodeSection,\n\t\tinfo.FullVersion(),\n\t)\n}\n\n// AddGoroutineStack adds the current goroutine stack.\nfunc (di *Info) AddGoroutineStack() {\n\tbuf := new(bytes.Buffer)\n\terr := pprof.Lookup(\"goroutine\").WriteTo(buf, 1)\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Goroutine Stack\",\n\t\t\tNoFlags,\n\t\t\tfmt.Sprintf(\"Failed to get: %s\", err),\n\t\t)\n\t\treturn\n\t}\n\n\t// Add section.\n\tdi.AddSection(\n\t\t\"Goroutine Stack\",\n\t\tUseCodeSection,\n\t\tbuf.String(),\n\t)\n}\n\n// AddLastUnexpectedLogs adds the last 10 unexpected log lines, if any.\nfunc (di *Info) AddLastUnexpectedLogs() {\n\tlines := log.GetLastUnexpectedLogs()\n\n\t// Check if there is anything at all.\n\tif len(lines) == 0 {\n\t\tdi.AddSection(\"No Unexpected Logs\", NoFlags)\n\t\treturn\n\t}\n\n\tdi.AddSection(\n\t\t\"Unexpected Logs\",\n\t\tUseCodeSection|AddContentLineBreaks,\n\t\tappend(\n\t\t\tlines,\n\t\t\tfmt.Sprintf(\"%s CURRENT TIME\", time.Now().Format(\"060102 15:04:05.000\")),\n\t\t)...,\n\t)\n}\n"
  },
  {
    "path": "base/utils/debug/debug_android.go",
    "content": "package debug\n\n// TODO: Re-enable Android interfaces.\n// Deactived for transition to new module system.\n\n// import (\n// \t\"context\"\n// \t\"fmt\"\n\n// \t\"github.com/safing/portmaster-android/go/app_interface\"\n// )\n\n// // AddPlatformInfo adds OS and platform information.\n// func (di *Info) AddPlatformInfo(_ context.Context) {\n// \t// Get information from the system.\n// \tinfo, err := app_interface.GetPlatformInfo()\n// \tif err != nil {\n// \t\tdi.AddSection(\n// \t\t\t\"Platform Information\",\n// \t\t\tNoFlags,\n// \t\t\tfmt.Sprintf(\"Failed to get: %s\", err),\n// \t\t)\n// \t\treturn\n// \t}\n\n// \t// Add section.\n// \tdi.AddSection(\n// \t\tfmt.Sprintf(\"Platform: Android\"),\n// \t\tUseCodeSection|AddContentLineBreaks,\n// \t\tfmt.Sprintf(\"SDK: %d\", info.SDK),\n// \t\tfmt.Sprintf(\"Device: %s %s (%s)\", info.Manufacturer, info.Brand, info.Board),\n// \t\tfmt.Sprintf(\"App: %s: %s %s\", info.ApplicationID, info.VersionName, info.BuildType))\n\n// }\n"
  },
  {
    "path": "base/utils/debug/debug_default.go",
    "content": "//go:build !android\n\npackage debug\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/shirou/gopsutil/host\"\n)\n\n// AddPlatformInfo adds OS and platform information.\nfunc (di *Info) AddPlatformInfo(ctx context.Context) {\n\t// Get information from the system.\n\tinfo, err := host.InfoWithContext(ctx)\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Platform Information\",\n\t\t\tNoFlags,\n\t\t\tfmt.Sprintf(\"Failed to get: %s\", err),\n\t\t)\n\t\treturn\n\t}\n\n\t// Check if we want to add virtulization information.\n\tvar virtInfo string\n\tif info.VirtualizationRole == \"guest\" {\n\t\tif info.VirtualizationSystem != \"\" {\n\t\t\tvirtInfo = fmt.Sprintf(\"VM: %s\", info.VirtualizationSystem)\n\t\t} else {\n\t\t\tvirtInfo = \"VM: unidentified\"\n\t\t}\n\t}\n\n\t// Add section.\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Platform: %s %s\", info.Platform, info.PlatformVersion),\n\t\tUseCodeSection|AddContentLineBreaks,\n\t\tfmt.Sprintf(\"System: %s %s (%s) %s\", info.Platform, info.OS, info.PlatformFamily, info.PlatformVersion),\n\t\tfmt.Sprintf(\"Kernel: %s %s\", info.KernelVersion, info.KernelArch),\n\t\tvirtInfo,\n\t)\n}\n"
  },
  {
    "path": "base/utils/fs.go",
    "content": "package utils\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log/slog\"\n\t\"os\"\n\t\"runtime\"\n)\n\nconst isWindows = runtime.GOOS == \"windows\"\n\n// EnsureDirectory ensures that the given directory exists and that is has the given permissions set.\n// If path is a file, it is deleted and a directory created.\nfunc EnsureDirectory(path string, perm FSPermission) error {\n\tif !perm.IsExecPermission() {\n\t\tslog.Warn(\"utils: setting not executable permission for directory\", \"dir\", path)\n\t}\n\n\t// open path\n\tf, err := os.Stat(path)\n\tif err == nil {\n\t\t// file exists\n\t\tif f.IsDir() {\n\t\t\t// directory exists, check permissions\n\t\t\tif isWindows {\n\t\t\t\t// Ignore windows permission error. For none admin users it will always fail.\n\t\t\t\t_ = SetFilePermission(path, perm)\n\t\t\t\treturn nil\n\t\t\t} else if f.Mode().Perm() != perm.AsUnixPermission() {\n\t\t\t\treturn SetFilePermission(path, perm)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\terr = os.Remove(path)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not remove file %s to place dir: %w\", path, err)\n\t\t}\n\t}\n\t// file does not exist (or has been deleted)\n\tif err == nil || errors.Is(err, fs.ErrNotExist) {\n\t\terr = os.MkdirAll(path, perm.AsUnixPermission())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not create dir %s: %w\", path, err)\n\t\t}\n\t\t// Set permissions.\n\t\terr = SetFilePermission(path, perm)\n\t\t// Ignore windows permission error. For none admin users it will always fail.\n\t\tif !isWindows {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n\t// other error opening path\n\treturn fmt.Errorf(\"failed to access %s: %w\", path, err)\n}\n\n// PathExists returns whether the given path (file or dir) exists.\nfunc PathExists(path string) bool {\n\t_, err := os.Stat(path)\n\treturn err == nil || errors.Is(err, fs.ErrExist)\n}\n"
  },
  {
    "path": "base/utils/mimetypes.go",
    "content": "package utils\n\nimport \"strings\"\n\n// Do not depend on the OS for mimetypes.\n// A Windows update screwed us over here and broke all the automatic mime\n// typing via Go in April 2021.\n\n// MimeTypeByExtension returns a mimetype for the given file name extension,\n// which must including the leading dot.\n// If the extension is not known, the call returns with ok=false and,\n// additionally, a default \"application/octet-stream\" mime type is returned.\nfunc MimeTypeByExtension(ext string) (mimeType string, ok bool) {\n\tmimeType, ok = mimeTypes[strings.ToLower(ext)]\n\tif ok {\n\t\treturn\n\t}\n\n\treturn defaultMimeType, false\n}\n\nvar (\n\tdefaultMimeType = \"application/octet-stream\"\n\n\tmimeTypes = map[string]string{\n\t\t\".7z\":    \"application/x-7z-compressed\",\n\t\t\".atom\":  \"application/atom+xml\",\n\t\t\".css\":   \"text/css; charset=utf-8\",\n\t\t\".csv\":   \"text/csv; charset=utf-8\",\n\t\t\".deb\":   \"application/x-debian-package\",\n\t\t\".epub\":  \"application/epub+zip\",\n\t\t\".es\":    \"application/ecmascript\",\n\t\t\".flv\":   \"video/x-flv\",\n\t\t\".gif\":   \"image/gif\",\n\t\t\".gz\":    \"application/gzip\",\n\t\t\".htm\":   \"text/html; charset=utf-8\",\n\t\t\".html\":  \"text/html; charset=utf-8\",\n\t\t\".jpeg\":  \"image/jpeg\",\n\t\t\".jpg\":   \"image/jpeg\",\n\t\t\".js\":    \"text/javascript; charset=utf-8\",\n\t\t\".json\":  \"application/json; charset=utf-8\",\n\t\t\".m3u\":   \"audio/mpegurl\",\n\t\t\".m4a\":   \"audio/mpeg\",\n\t\t\".md\":    \"text/markdown; charset=utf-8\",\n\t\t\".mjs\":   \"text/javascript; charset=utf-8\",\n\t\t\".mov\":   \"video/quicktime\",\n\t\t\".mp3\":   \"audio/mpeg\",\n\t\t\".mp4\":   \"video/mp4\",\n\t\t\".mpeg\":  \"video/mpeg\",\n\t\t\".mpg\":   \"video/mpeg\",\n\t\t\".ogg\":   \"audio/ogg\",\n\t\t\".ogv\":   \"video/ogg\",\n\t\t\".otf\":   \"font/otf\",\n\t\t\".pdf\":   \"application/pdf\",\n\t\t\".png\":   \"image/png\",\n\t\t\".qt\":    \"video/quicktime\",\n\t\t\".rar\":   \"application/rar\",\n\t\t\".rtf\":   \"application/rtf\",\n\t\t\".svg\":   \"image/svg+xml\",\n\t\t\".tar\":   \"application/x-tar\",\n\t\t\".tiff\":  \"image/tiff\",\n\t\t\".ts\":    \"video/MP2T\",\n\t\t\".ttc\":   \"font/collection\",\n\t\t\".ttf\":   \"font/ttf\",\n\t\t\".txt\":   \"text/plain; charset=utf-8\",\n\t\t\".wasm\":  \"application/wasm\",\n\t\t\".wav\":   \"audio/x-wav\",\n\t\t\".webm\":  \"video/webm\",\n\t\t\".webp\":  \"image/webp\",\n\t\t\".woff\":  \"font/woff\",\n\t\t\".woff2\": \"font/woff2\",\n\t\t\".xml\":   \"text/xml; charset=utf-8\",\n\t\t\".xz\":    \"application/x-xz\",\n\t\t\".yaml\":  \"application/yaml; charset=utf-8\",\n\t\t\".yml\":   \"application/yaml; charset=utf-8\",\n\t\t\".zip\":   \"application/zip\",\n\t}\n)\n"
  },
  {
    "path": "base/utils/onceagain.go",
    "content": "package utils\n\n// This file is forked from https://github.com/golang/go/blob/bc593eac2dc63d979a575eccb16c7369a5ff81e0/src/sync/once.go.\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\n// OnceAgain is an object that will perform only one action \"in flight\". It's\n// basically the same as sync.Once, but is automatically reused when the\n// function was executed and everyone who waited has left.\n// Important: This is somewhat racy when used heavily as it only resets _after_\n// everyone who waited has left. So, while some goroutines are waiting to be\n// activated again to leave the waiting state, other goroutines will call Do()\n// without executing the function again.\ntype OnceAgain struct {\n\t// done indicates whether the action has been performed.\n\t// It is first in the struct because it is used in the hot path.\n\t// The hot path is inlined at every call site.\n\t// Placing done first allows more compact instructions on some architectures (amd64/x86),\n\t// and fewer instructions (to calculate offset) on other architectures.\n\tdone uint32\n\n\t// Number of waiters waiting for the function to finish. The last waiter resets done.\n\twaiters int32\n\n\tm sync.Mutex\n}\n\n// Do calls the function f if and only if Do is being called for the\n// first time for this instance of Once. In other words, given\n//\n//\tvar once Once\n//\n// if once.Do(f) is called multiple times, only the first call will invoke f,\n// even if f has a different value in each invocation. A new instance of\n// Once is required for each function to execute.\n//\n// Do is intended for initialization that must be run exactly once. Since f\n// is niladic, it may be necessary to use a function literal to capture the\n// arguments to a function to be invoked by Do:\n//\n//\tconfig.once.Do(func() { config.init(filename) })\n//\n// Because no call to Do returns until the one call to f returns, if f causes\n// Do to be called, it will deadlock.\n//\n// If f panics, Do considers it to have returned; future calls of Do return\n// without calling f.\nfunc (o *OnceAgain) Do(f func()) {\n\t// Note: Here is an incorrect implementation of Do:\n\t//\n\t//\tif atomic.CompareAndSwapUint32(&o.done, 0, 1) {\n\t//\t\tf()\n\t//\t}\n\t//\n\t// Do guarantees that when it returns, f has finished.\n\t// This implementation would not implement that guarantee:\n\t// given two simultaneous calls, the winner of the cas would\n\t// call f, and the second would return immediately, without\n\t// waiting for the first's call to f to complete.\n\t// This is why the slow path falls back to a mutex, and why\n\t// the atomic.StoreUint32 must be delayed until after f returns.\n\n\tif atomic.LoadUint32(&o.done) == 0 {\n\t\t// Outlined slow-path to allow inlining of the fast-path.\n\t\to.doSlow(f)\n\t}\n}\n\nfunc (o *OnceAgain) doSlow(f func()) {\n\tatomic.AddInt32(&o.waiters, 1)\n\tdefer func() {\n\t\tif atomic.AddInt32(&o.waiters, -1) == 0 {\n\t\t\tatomic.StoreUint32(&o.done, 0) // reset\n\t\t}\n\t}()\n\n\to.m.Lock()\n\tdefer o.m.Unlock()\n\tif o.done == 0 {\n\t\tdefer atomic.StoreUint32(&o.done, 1)\n\t\tf()\n\t}\n}\n"
  },
  {
    "path": "base/utils/onceagain_test.go",
    "content": "package utils\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n)\n\nfunc TestOnceAgain(t *testing.T) {\n\tt.Parallel()\n\n\toa := OnceAgain{}\n\texecuted := abool.New()\n\tvar testWg sync.WaitGroup\n\n\t// One execution should gobble up the whole batch.\n\tfor range 10 {\n\t\ttestWg.Add(100)\n\t\tfor range 100 {\n\t\t\tgo func() {\n\t\t\t\toa.Do(func() {\n\t\t\t\t\tif !executed.SetToIf(false, true) {\n\t\t\t\t\t\tt.Errorf(\"concurrent execution!\")\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t\t})\n\t\t\t\ttestWg.Done()\n\t\t\t}()\n\t\t}\n\t\ttestWg.Wait()\n\t\texecuted.UnSet() // reset check\n\t}\n\n\t// Continuous use with re-execution.\n\t// Choose values so that about 10 executions are expected\n\tvar execs uint32\n\ttestWg.Add(100)\n\tfor range 100 {\n\t\tgo func() {\n\t\t\toa.Do(func() {\n\t\t\t\tatomic.AddUint32(&execs, 1)\n\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t})\n\t\t\ttestWg.Done()\n\t\t}()\n\n\t\ttime.Sleep(1 * time.Millisecond)\n\t}\n\n\ttestWg.Wait()\n\tif execs <= 8 {\n\t\tt.Errorf(\"unexpected low exec count: %d\", execs)\n\t}\n\tif execs >= 12 {\n\t\tt.Errorf(\"unexpected high exec count: %d\", execs)\n\t}\n}\n"
  },
  {
    "path": "base/utils/osdetail/colors_windows.go",
    "content": "package osdetail\n\nimport (\n\t\"sync\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\nvar (\n\tcolorSupport bool\n\n\tcolorSupportChecked  bool\n\tcheckingColorSupport sync.Mutex\n)\n\n// EnableColorSupport tries to enable color support for cmd on windows and returns whether it is enabled.\nfunc EnableColorSupport() bool {\n\tcheckingColorSupport.Lock()\n\tdefer checkingColorSupport.Unlock()\n\n\tif !colorSupportChecked {\n\t\tcolorSupport = enableColorSupport()\n\t\tcolorSupportChecked = true\n\t}\n\treturn colorSupport\n}\n\nfunc enableColorSupport() bool {\n\tif IsAtLeastWindowsNTVersionWithDefault(\"10\", false) {\n\n\t\t// check if windows.Stdout is file\n\t\tif windows.GetFileInformationByHandle(windows.Stdout, &windows.ByHandleFileInformation{}) == nil {\n\t\t\treturn false\n\t\t}\n\n\t\tvar mode uint32\n\t\terr := windows.GetConsoleMode(windows.Stdout, &mode)\n\t\tif err == nil {\n\t\t\tif mode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {\n\t\t\t\tmode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING\n\t\t\t\terr = windows.SetConsoleMode(windows.Stdout, mode)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "base/utils/osdetail/command.go",
    "content": "package osdetail\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"os/exec\"\n\t\"strings\"\n)\n\n// RunCmd runs the given command and run error checks on the output.\nfunc RunCmd(command ...string) (output []byte, err error) {\n\t// Create command to execute.\n\tvar cmd *exec.Cmd\n\tswitch len(command) {\n\tcase 0:\n\t\treturn nil, errors.New(\"no command supplied\")\n\tcase 1:\n\t\tcmd = exec.Command(command[0])\n\tdefault:\n\t\tcmd = exec.Command(command[0], command[1:]...)\n\t}\n\n\t// Create and assign output buffers.\n\tvar stdoutBuf bytes.Buffer\n\tvar stderrBuf bytes.Buffer\n\tcmd.Stdout = &stdoutBuf\n\tcmd.Stderr = &stderrBuf\n\n\t// Run command and collect output.\n\terr = cmd.Run()\n\tstdout, stderr := stdoutBuf.Bytes(), stderrBuf.Bytes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Command might not return an error, but just write to stdout instead.\n\tif len(stderr) > 0 {\n\t\treturn nil, errors.New(strings.SplitN(string(stderr), \"\\n\", 2)[0])\n\t}\n\n\t// Debugging output:\n\t// fmt.Printf(\"command stdout: %s\\n\", stdout)\n\t// fmt.Printf(\"command stderr: %s\\n\", stderr)\n\n\t// Finalize stdout.\n\tcleanedOutput := bytes.TrimSpace(stdout)\n\tif len(cleanedOutput) == 0 {\n\t\treturn nil, ErrEmptyOutput\n\t}\n\n\treturn cleanedOutput, nil\n}\n"
  },
  {
    "path": "base/utils/osdetail/dnscache_windows.go",
    "content": "package osdetail\n\nimport (\n\t\"os/exec\"\n)\n\n// EnableDNSCache enables the Windows Service \"DNS Client\" by setting the registry value \"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\Dnscache\" to 2 (Automatic).\n// A reboot is required for this setting to take effect.\nfunc EnableDNSCache() error {\n\treturn exec.Command(\"reg\", \"add\", \"HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlSet\\\\services\\\\Dnscache\", \"/v\", \"Start\", \"/t\", \"REG_DWORD\", \"/d\", \"2\", \"/f\").Run()\n}\n\n// DisableDNSCache disables the Windows Service \"DNS Client\" by setting the registry value \"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\Dnscache\" to 4 (Disabled).\n// A reboot is required for this setting to take effect.\nfunc DisableDNSCache() error {\n\treturn exec.Command(\"reg\", \"add\", \"HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlSet\\\\services\\\\Dnscache\", \"/v\", \"Start\", \"/t\", \"REG_DWORD\", \"/d\", \"4\", \"/f\").Run()\n}\n"
  },
  {
    "path": "base/utils/osdetail/errors.go",
    "content": "package osdetail\n\nimport \"errors\"\n\nvar (\n\t// ErrNotSupported is returned when an operation is not supported on the current platform.\n\tErrNotSupported = errors.New(\"not supported\")\n\t// ErrNotFound is returned when the desired data is not found.\n\tErrNotFound = errors.New(\"not found\")\n\t// ErrEmptyOutput is a special error that is returned when an operation has no error, but also returns to data.\n\tErrEmptyOutput = errors.New(\"command succeeded with empty output\")\n)\n"
  },
  {
    "path": "base/utils/osdetail/service_windows.go",
    "content": "package osdetail\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Service Status\nconst (\n\tStatusUnknown uint8 = iota\n\tStatusRunningStoppable\n\tStatusRunningNotStoppable\n\tStatusStartPending\n\tStatusStopPending\n\tStatusStopped\n)\n\n// Exported errors\nvar (\n\tErrServiceNotStoppable = errors.New(\"the service is not stoppable\")\n)\n\n// GetServiceStatus returns the current status of a Windows Service (limited implementation).\nfunc GetServiceStatus(name string) (status uint8, err error) {\n\n\toutput, err := exec.Command(\"sc\", \"query\", name).Output()\n\tif err != nil {\n\t\treturn StatusUnknown, fmt.Errorf(\"failed to query service: %s\", err)\n\t}\n\toutputString := string(output)\n\n\tswitch {\n\tcase strings.Contains(outputString, \"RUNNING\"):\n\t\tif strings.Contains(outputString, \"NOT_STOPPABLE\") {\n\t\t\treturn StatusRunningNotStoppable, nil\n\t\t}\n\t\treturn StatusRunningStoppable, nil\n\tcase strings.Contains(outputString, \"STOP_PENDING\"):\n\t\treturn StatusStopPending, nil\n\tcase strings.Contains(outputString, \"STOPPED\"):\n\t\treturn StatusStopped, nil\n\tcase strings.Contains(outputString, \"START_PENDING\"):\n\t\treturn StatusStopPending, nil\n\t}\n\n\treturn StatusUnknown, errors.New(\"unknown service status\")\n}\n\n// StopService stops a Windows Service.\nfunc StopService(name string) (err error) {\n\tpendingCnt := 0\n\tfor {\n\n\t\t// get status\n\t\tstatus, err := GetServiceStatus(name)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch status {\n\t\tcase StatusRunningStoppable:\n\t\t\terr := exec.Command(\"sc\", \"stop\", name).Run()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to stop service: %s\", err)\n\t\t\t}\n\t\tcase StatusRunningNotStoppable:\n\t\t\treturn ErrServiceNotStoppable\n\t\tcase StatusStartPending, StatusStopPending:\n\t\t\tpendingCnt++\n\t\t\tif pendingCnt > 50 {\n\t\t\t\treturn errors.New(\"service stuck in pending status (5s)\")\n\t\t\t}\n\t\tcase StatusStopped:\n\t\t\treturn nil\n\t\t}\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}\n}\n\n// SartService starts a Windows Service.\nfunc SartService(name string) (err error) {\n\tpendingCnt := 0\n\tfor {\n\n\t\t// get status\n\t\tstatus, err := GetServiceStatus(name)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch status {\n\t\tcase StatusRunningStoppable, StatusRunningNotStoppable:\n\t\t\treturn nil\n\t\tcase StatusStartPending, StatusStopPending:\n\t\t\tpendingCnt++\n\t\t\tif pendingCnt > 50 {\n\t\t\t\treturn errors.New(\"service stuck in pending status (5s)\")\n\t\t\t}\n\t\tcase StatusStopped:\n\t\t\terr := exec.Command(\"sc\", \"start\", name).Run()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to stop service: %s\", err)\n\t\t\t}\n\t\t}\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}\n}\n"
  },
  {
    "path": "base/utils/osdetail/shell_windows.go",
    "content": "package osdetail\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n)\n\n// RunPowershellCmd runs a powershell command and returns its output.\nfunc RunPowershellCmd(script string) (output []byte, err error) {\n\t// Create command to execute.\n\treturn RunCmd(\n\t\t\"powershell.exe\",\n\t\t\"-ExecutionPolicy\", \"Bypass\",\n\t\t\"-NoProfile\",\n\t\t\"-NonInteractive\",\n\t\t\"[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8\\n\"+script,\n\t)\n}\n\nconst outputSeparator = \"pwzzhtuvpwdgozhzbnjj\"\n\n// RunTerminalCmd runs a Windows cmd command and returns its output.\n// It sets the output of the cmd to UTF-8 in order to avoid encoding errors.\nfunc RunTerminalCmd(command ...string) (output []byte, err error) {\n\toutput, err = RunCmd(append([]string{\n\t\t\"cmd.exe\",\n\t\t\"/c\",\n\t\t\"chcp\",  // Set output encoding...\n\t\t\"65001\", // ...to UTF-8.\n\t\t\"&\",\n\t\t\"echo\",\n\t\toutputSeparator,\n\t\t\"&\",\n\t},\n\t\tcommand...,\n\t)...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Find correct start of output and shift start.\n\tindex := bytes.IndexAny(output, outputSeparator+\"\\r\\n\")\n\tif index < 0 {\n\t\treturn nil, errors.New(\"failed to post-process output: could not find output separator\")\n\t}\n\toutput = output[index+len(outputSeparator)+2:]\n\n\treturn output, nil\n}\n"
  },
  {
    "path": "base/utils/osdetail/svchost_windows.go",
    "content": "package osdetail\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n)\n\nvar (\n\tserviceNames     map[int32][]string\n\tserviceNamesLock sync.Mutex\n)\n\n// Errors\nvar (\n\tErrServiceNotFound = errors.New(\"no service with the given PID was found\")\n)\n\n// GetServiceNames returns all service names assosicated with a svchost.exe process on Windows.\nfunc GetServiceNames(pid int32) ([]string, error) {\n\tserviceNamesLock.Lock()\n\tdefer serviceNamesLock.Unlock()\n\n\tif serviceNames != nil {\n\t\tnames, ok := serviceNames[pid]\n\t\tif ok {\n\t\t\treturn names, nil\n\t\t}\n\t}\n\n\tserviceNames, err := GetAllServiceNames()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnames, ok := serviceNames[pid]\n\tif ok {\n\t\treturn names, nil\n\t}\n\n\treturn nil, ErrServiceNotFound\n}\n\n// GetAllServiceNames returns a list of service names assosicated with svchost.exe processes on Windows.\nfunc GetAllServiceNames() (map[int32][]string, error) {\n\toutput, err := exec.Command(\"tasklist\", \"/svc\", \"/fi\", \"imagename eq svchost.exe\").Output()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get svchost tasklist: %s\", err)\n\t}\n\n\t// file scanner\n\tscanner := bufio.NewScanner(bytes.NewReader(output))\n\tscanner.Split(bufio.ScanLines)\n\n\t// skip output header\n\tfor scanner.Scan() {\n\t\tif strings.HasPrefix(scanner.Text(), \"=\") {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tvar (\n\t\tpid        int32\n\t\tservices   []string\n\t\tcollection = make(map[int32][]string)\n\t)\n\n\tfor scanner.Scan() {\n\t\t// get fields of line\n\t\tfields := strings.Fields(scanner.Text())\n\n\t\t// check fields length\n\t\tif len(fields) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// new entry\n\t\tif fields[0] == \"svchost.exe\" {\n\t\t\t// save old entry\n\t\t\tif pid != 0 {\n\t\t\t\tcollection[pid] = services\n\t\t\t}\n\t\t\t// reset PID\n\t\t\tpid = 0\n\t\t\tservices = make([]string, 0, len(fields))\n\n\t\t\t// check fields length\n\t\t\tif len(fields) < 3 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// get pid\n\t\t\ti, err := strconv.ParseInt(fields[1], 10, 32)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tpid = int32(i)\n\n\t\t\t// skip used fields\n\t\t\tfields = fields[2:]\n\t\t}\n\n\t\t// add service names\n\t\tfor _, field := range fields {\n\t\t\tservices = append(services, strings.Trim(strings.TrimSpace(field), \",\"))\n\t\t}\n\t}\n\n\tif pid != 0 {\n\t\t// save last entry\n\t\tcollection[pid] = services\n\t}\n\n\treturn collection, nil\n}\n"
  },
  {
    "path": "base/utils/osdetail/version_windows.go",
    "content": "package osdetail\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/go-version\"\n\t\"github.com/shirou/gopsutil/host\"\n)\n\nvar (\n\t// versionRe = regexp.MustCompile(`[0-9\\.]+`)\n\n\twindowsNTVersion       string\n\twindowsNTVersionForCmp *version.Version\n\n\tfetching sync.Mutex\n\tfetched  bool\n)\n\n// WindowsNTVersion returns the current Windows version.\nfunc WindowsNTVersion() (string, error) {\n\tvar err error\n\tfetching.Lock()\n\tdefer fetching.Unlock()\n\n\tif !fetched {\n\t\t_, _, windowsNTVersion, err = host.PlatformInformation()\n\n\t\twindowsNTVersion = strings.SplitN(windowsNTVersion, \" \", 2)[0]\n\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to obtain Windows-Version: %s\", err)\n\t\t}\n\n\t\twindowsNTVersionForCmp, err = version.NewVersion(windowsNTVersion)\n\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to parse Windows-Version %s: %s\", windowsNTVersion, err)\n\t\t}\n\n\t\tfetched = true\n\t}\n\n\treturn windowsNTVersion, err\n}\n\n// IsAtLeastWindowsNTVersion returns whether the current WindowsNT version is at least the given version or newer.\nfunc IsAtLeastWindowsNTVersion(v string) (bool, error) {\n\t_, err := WindowsNTVersion()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tversionForCmp, err := version.NewVersion(v)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn windowsNTVersionForCmp.GreaterThanOrEqual(versionForCmp), nil\n}\n\n// IsAtLeastWindowsNTVersionWithDefault is like IsAtLeastWindowsNTVersion(), but keeps the Error and returns the default Value in Errorcase\nfunc IsAtLeastWindowsNTVersionWithDefault(v string, defaultValue bool) bool {\n\tval, err := IsAtLeastWindowsNTVersion(v)\n\tif err != nil {\n\t\treturn defaultValue\n\t}\n\treturn val\n}\n\n// IsAtLeastWindowsVersion returns whether the current Windows version is at least the given version or newer.\nfunc IsAtLeastWindowsVersion(v string) (bool, error) {\n\tvar NTVersion string\n\tswitch v {\n\tcase \"7\":\n\t\tNTVersion = \"6.1\"\n\tcase \"8\":\n\t\tNTVersion = \"6.2\"\n\tcase \"8.1\":\n\t\tNTVersion = \"6.3\"\n\tcase \"10\":\n\t\tNTVersion = \"10\"\n\tdefault:\n\t\treturn false, fmt.Errorf(\"failed to compare Windows-Version: Windows %s is unknown\", v)\n\t}\n\n\treturn IsAtLeastWindowsNTVersion(NTVersion)\n}\n\n// IsAtLeastWindowsVersionWithDefault is like IsAtLeastWindowsVersion(), but keeps the Error and returns the default Value in Errorcase\nfunc IsAtLeastWindowsVersionWithDefault(v string, defaultValue bool) bool {\n\tval, err := IsAtLeastWindowsVersion(v)\n\tif err != nil {\n\t\treturn defaultValue\n\t}\n\treturn val\n}\n"
  },
  {
    "path": "base/utils/osdetail/version_windows_test.go",
    "content": "package osdetail\n\nimport \"testing\"\n\nfunc TestWindowsNTVersion(t *testing.T) {\n\tif str, err := WindowsNTVersion(); str == \"\" || err != nil {\n\t\tt.Fatalf(\"failed to obtain windows version: %s\", err)\n\t}\n}\n\nfunc TestIsAtLeastWindowsNTVersion(t *testing.T) {\n\tret, err := IsAtLeastWindowsNTVersion(\"6\")\n\tif err != nil {\n\t\tt.Fatalf(\"failed to compare windows versions: %s\", err)\n\t}\n\tif !ret {\n\t\tt.Fatalf(\"WindowsNTVersion is less than 6 (Vista)\")\n\t}\n}\n\nfunc TestIsAtLeastWindowsVersion(t *testing.T) {\n\tret, err := IsAtLeastWindowsVersion(\"7\")\n\tif err != nil {\n\t\tt.Fatalf(\"failed to compare windows versions: %s\", err)\n\t}\n\tif !ret {\n\t\tt.Fatalf(\"WindowsVersion is less than 7\")\n\t}\n}\n"
  },
  {
    "path": "base/utils/permissions.go",
    "content": "//go:build !windows\n\npackage utils\n\nimport \"os\"\n\n// SetFilePermission sets the permission of a file or directory.\nfunc SetFilePermission(path string, perm FSPermission) error {\n\treturn os.Chmod(path, perm.AsUnixPermission())\n}\n"
  },
  {
    "path": "base/utils/permissions_windows.go",
    "content": "//go:build windows\n\npackage utils\n\nimport (\n\t\"github.com/hectane/go-acl\"\n\t\"golang.org/x/sys/windows\"\n)\n\nvar (\n\tsystemSID *windows.SID\n\tadminsSID *windows.SID\n\tusersSID  *windows.SID\n)\n\nfunc init() {\n\t// Initialize Security ID for all need groups.\n\t// Reference: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers\n\tvar err error\n\tsystemSID, err = windows.StringToSid(\"S-1-5-18\") // SYSTEM (Local System)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tadminsSID, err = windows.StringToSid(\"S-1-5-32-544\") // Administrators\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tusersSID, err = windows.StringToSid(\"S-1-5-32-545\") // Users\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// SetFilePermission sets the permission of a file or directory.\nfunc SetFilePermission(path string, perm FSPermission) error {\n\tswitch perm {\n\tcase AdminOnlyPermission, AdminOnlyExecPermission:\n\t\t// Set only admin rights, remove all others.\n\t\tacl.Apply(\n\t\t\tpath,\n\t\t\ttrue,\n\t\t\tfalse,\n\t\t\tacl.GrantSid(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, systemSID),\n\t\t\tacl.GrantSid(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, adminsSID),\n\t\t)\n\tcase PublicReadPermission, PublicReadExecPermission:\n\t\t// Set admin rights and read/execute rights for users, remove all others.\n\t\tacl.Apply(\n\t\t\tpath,\n\t\t\ttrue,\n\t\t\tfalse,\n\t\t\tacl.GrantSid(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, systemSID),\n\t\t\tacl.GrantSid(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, adminsSID),\n\t\t\tacl.GrantSid(windows.GENERIC_READ|windows.GENERIC_EXECUTE, usersSID),\n\t\t)\n\tcase PublicWritePermission, PublicWriteExecPermission:\n\t\t// Set full control to admin and regular users. Guest users will not have access.\n\t\tacl.Apply(\n\t\t\tpath,\n\t\t\ttrue,\n\t\t\tfalse,\n\t\t\tacl.GrantSid(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, systemSID),\n\t\t\tacl.GrantSid(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, adminsSID),\n\t\t\tacl.GrantSid(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, usersSID),\n\t\t)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "base/utils/renameio/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "base/utils/renameio/README.md",
    "content": "This is a fork of the github.com/google/renameio Go package at commit 353f8196982447d8b12c64f69530e657331e3dbc.\n\nThe inital commit of this package will carry the original package contents.  \nThe Original License is the Apache License in Version 2.0 and the copyright of the forked package is held by Google Inc.  \nAny changes are recorded in the git history, which is part of this project.\n\n---\n\nThe `renameio` Go package provides a way to atomically create or replace a file or\nsymbolic link.\n\n## Atomicity vs durability\n\n`renameio` concerns itself *only* with atomicity, i.e. making sure applications\nnever see unexpected file content (a half-written file, or a 0-byte file).\n\nAs a practical example, consider https://manpages.debian.org/: if there is a\npower outage while the site is updating, we are okay with losing the manpages\nwhich were being rendered at the time of the power outage. They will be added in\na later run of the software. We are not okay with having a manpage replaced by a\n0-byte file under any circumstances, though.\n\n## Advantages of this package\n\nThere are other packages for atomically replacing files, and sometimes ad-hoc\nimplementations can be found in programs.\n\nA naive approach to the problem is to create a temporary file followed by a call\nto `os.Rename()`. However, there are a number of subtleties which make the\ncorrect sequence of operations hard to identify:\n\n* The temporary file should be removed when an error occurs, but a remove must\n  not be attempted if the rename succeeded, as a new file might have been\n  created with the same name. This renders a throwaway `defer\n  os.Remove(t.Name())` insufficient; state must be kept.\n\n* The temporary file must be created on the same file system (same mount point)\n  for the rename to work, but the TMPDIR environment variable should still be\n  respected, e.g. to direct temporary files into a separate directory outside of\n  the webserver’s document root but on the same file system.\n\n* On POSIX operating systems, the\n  [`fsync`](https://manpages.debian.org/stretch/manpages-dev/fsync.2) system\n  call must be used to ensure that the `os.Rename()` call will not result in a\n  0-length file.\n\nThis package attempts to get all of these details right, provides an intuitive,\nyet flexible API and caters to use-cases where high performance is required.\n\n## Disclaimer\n\nThis is not an official Google product (experimental or otherwise), it\nis just code that happens to be owned by Google.\n\nThis project is not affiliated with the Go project.\n"
  },
  {
    "path": "base/utils/renameio/doc.go",
    "content": "// Package renameio provides a way to atomically create or replace a file or\n// symbolic link.\n//\n// Caveat: this package requires the file system rename(2) implementation to be\n// atomic. Notably, this is not the case when using NFS with multiple clients:\n// https://stackoverflow.com/a/41396801\npackage renameio\n"
  },
  {
    "path": "base/utils/renameio/example_test.go",
    "content": "package renameio_test\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/safing/portmaster/base/utils/renameio\"\n)\n\nfunc ExampleTempFile_justone() { //nolint:testableexamples\n\tpersist := func(temperature float64) error {\n\t\tt, err := renameio.TempFile(\"\", \"/srv/www/metrics.txt\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer func() {\n\t\t\t_ = t.Cleanup()\n\t\t}()\n\t\tif _, err := fmt.Fprintf(t, \"temperature_degc %f\\n\", temperature); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn t.CloseAtomicallyReplace()\n\t}\n\t// Thanks to the write package, a webserver exposing /srv/www never\n\t// serves an incomplete or missing file.\n\tif err := persist(31.2); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc ExampleTempFile_many() { //nolint:testableexamples\n\t// Prepare for writing files to /srv/www, effectively caching calls to\n\t// TempDir which TempFile would otherwise need to make.\n\tdir := renameio.TempDir(\"/srv/www\")\n\tpersist := func(temperature float64) error {\n\t\tt, err := renameio.TempFile(dir, \"/srv/www/metrics.txt\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer func() {\n\t\t\t_ = t.Cleanup()\n\t\t}()\n\t\tif _, err := fmt.Fprintf(t, \"temperature_degc %f\\n\", temperature); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn t.CloseAtomicallyReplace()\n\t}\n\n\t// Imagine this was an endless loop, reading temperature sensor values.\n\t// Thanks to the write package, a webserver exposing /srv/www never\n\t// serves an incomplete or missing file.\n\tfor {\n\t\tif err := persist(31.2); err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/utils/renameio/symlink_test.go",
    "content": "//go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris || windows\n\npackage renameio\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc TestSymlink(t *testing.T) {\n\tt.Parallel()\n\n\td, err := os.MkdirTemp(\"\", \"test-renameio-testsymlink\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Cleanup(func() {\n\t\t_ = os.RemoveAll(d)\n\t})\n\n\twant := []byte(\"Hello World\")\n\tif err := os.WriteFile(filepath.Join(d, \"hello.txt\"), want, 0o0600); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tfor range 2 {\n\t\tif err := Symlink(\"hello.txt\", filepath.Join(d, \"hi.txt\")); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tgot, err := os.ReadFile(filepath.Join(d, \"hi.txt\"))\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif !bytes.Equal(got, want) {\n\t\t\tt.Fatalf(\"unexpected content: got %q, want %q\", string(got), string(want))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/utils/renameio/tempfile.go",
    "content": "package renameio\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// TempDir checks whether os.TempDir() can be used as a temporary directory for\n// later atomically replacing files within dest. If no (os.TempDir() resides on\n// a different mount point), dest is returned.\n//\n// Note that the returned value ceases to be valid once either os.TempDir()\n// changes (e.g. on Linux, once the TMPDIR environment variable changes) or the\n// file system is unmounted.\nfunc TempDir(dest string) string {\n\treturn tempDir(\"\", filepath.Join(dest, \"renameio-TempDir\"))\n}\n\nfunc tempDir(dir, dest string) string {\n\tif dir != \"\" {\n\t\treturn dir // caller-specified directory always wins\n\t}\n\n\t// Chose the destination directory as temporary directory so that we\n\t// definitely can rename the file, for which both temporary and destination\n\t// file need to point to the same mount point.\n\tfallback := filepath.Dir(dest)\n\n\t// The user might have overridden the os.TempDir() return value by setting\n\t// the TMPDIR environment variable.\n\ttmpdir := os.TempDir()\n\n\ttestsrc, err := os.CreateTemp(tmpdir, \".\"+filepath.Base(dest))\n\tif err != nil {\n\t\treturn fallback\n\t}\n\tcleanup := true\n\tdefer func() {\n\t\tif cleanup {\n\t\t\t_ = os.Remove(testsrc.Name())\n\t\t}\n\t}()\n\t_ = testsrc.Close()\n\n\ttestdest, err := os.CreateTemp(filepath.Dir(dest), \".\"+filepath.Base(dest))\n\tif err != nil {\n\t\treturn fallback\n\t}\n\tdefer func() {\n\t\t_ = os.Remove(testdest.Name())\n\t}()\n\t_ = testdest.Close()\n\n\tif err := os.Rename(testsrc.Name(), testdest.Name()); err != nil {\n\t\treturn fallback\n\t}\n\tcleanup = false // testsrc no longer exists\n\treturn tmpdir\n}\n\n// PendingFile is a pending temporary file, waiting to replace the destination\n// path in a call to CloseAtomicallyReplace.\ntype PendingFile struct {\n\t*os.File\n\n\tpath   string\n\tdone   bool\n\tclosed bool\n}\n\n// Cleanup is a no-op if CloseAtomicallyReplace succeeded, and otherwise closes\n// and removes the temporary file.\nfunc (t *PendingFile) Cleanup() error {\n\tif t.done {\n\t\treturn nil\n\t}\n\t// An error occurred. Close and remove the tempfile. Errors are returned for\n\t// reporting, there is nothing the caller can recover here.\n\tvar closeErr error\n\tif !t.closed {\n\t\tcloseErr = t.Close()\n\t}\n\tif err := os.Remove(t.Name()); err != nil {\n\t\treturn err\n\t}\n\treturn closeErr\n}\n\n// CloseAtomicallyReplace closes the temporary file and atomically replaces\n// the destination file with it, i.e., a concurrent open(2) call will either\n// open the file previously located at the destination path (if any), or the\n// just written file, but the file will always be present.\nfunc (t *PendingFile) CloseAtomicallyReplace() error {\n\t// Even on an ordered file system (e.g. ext4 with data=ordered) or file\n\t// systems with write barriers, we cannot skip the fsync(2) call as per\n\t// Theodore Ts'o (ext2/3/4 lead developer):\n\t//\n\t// > data=ordered only guarantees the avoidance of stale data (e.g., the previous\n\t// > contents of a data block showing up after a crash, where the previous data\n\t// > could be someone's love letters, medical records, etc.). Without the fsync(2)\n\t// > a zero-length file is a valid and possible outcome after the rename.\n\tif err := t.Sync(); err != nil {\n\t\treturn err\n\t}\n\tt.closed = true\n\tif err := t.Close(); err != nil {\n\t\treturn err\n\t}\n\tif err := os.Rename(t.Name(), t.path); err != nil {\n\t\treturn err\n\t}\n\tt.done = true\n\treturn nil\n}\n\n// TempFile wraps os.CreateTemp for the use case of atomically creating or\n// replacing the destination file at path.\n//\n// If dir is the empty string, TempDir(filepath.Base(path)) is used. If you are\n// going to write a large number of files to the same file system, store the\n// result of TempDir(filepath.Base(path)) and pass it instead of the empty\n// string.\n//\n// The file's permissions will be 0600 by default. You can change these by\n// explicitly calling Chmod on the returned PendingFile.\nfunc TempFile(dir, path string) (*PendingFile, error) {\n\tf, err := os.CreateTemp(tempDir(dir, path), \".\"+filepath.Base(path))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &PendingFile{File: f, path: path}, nil\n}\n\n// Symlink wraps os.Symlink, replacing an existing symlink with the same name\n// atomically (os.Symlink fails when newname already exists, at least on Linux).\nfunc Symlink(oldname, newname string) error {\n\t// Fast path: if newname does not exist yet, we can skip the whole dance\n\t// below.\n\tif err := os.Symlink(oldname, newname); err == nil || !errors.Is(err, fs.ErrExist) {\n\t\treturn err\n\t}\n\n\t// We need to use os.MkdirTemp, as we cannot overwrite a os.CreateTemp,\n\t// and removing+symlinking creates a TOCTOU race.\n\td, err := os.MkdirTemp(filepath.Dir(newname), \".\"+filepath.Base(newname))\n\tif err != nil {\n\t\treturn err\n\t}\n\tcleanup := true\n\tdefer func() {\n\t\tif cleanup {\n\t\t\t_ = os.RemoveAll(d)\n\t\t}\n\t}()\n\n\tsymlink := filepath.Join(d, \"tmp.symlink\")\n\tif err := os.Symlink(oldname, symlink); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.Rename(symlink, newname); err != nil {\n\t\treturn err\n\t}\n\n\tcleanup = false\n\treturn os.RemoveAll(d)\n}\n"
  },
  {
    "path": "base/utils/renameio/tempfile_linux_test.go",
    "content": "//go:build linux\n\npackage renameio\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"testing\"\n)\n\nfunc TestTempDir(t *testing.T) {\n\tt.Parallel()\n\n\tif tmpdir, ok := os.LookupEnv(\"TMPDIR\"); ok {\n\t\tt.Cleanup(func() {\n\t\t\t_ = os.Setenv(\"TMPDIR\", tmpdir) // restore\n\t\t})\n\t} else {\n\t\tt.Cleanup(func() {\n\t\t\t_ = os.Unsetenv(\"TMPDIR\") // restore\n\t\t})\n\t}\n\n\tmount1, err := os.MkdirTemp(\"\", \"test-renameio-testtempdir1\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Cleanup(func() {\n\t\t_ = os.RemoveAll(mount1)\n\t})\n\n\tmount2, err := os.MkdirTemp(\"\", \"test-renameio-testtempdir2\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Cleanup(func() {\n\t\t_ = os.RemoveAll(mount2)\n\t})\n\n\tif err := syscall.Mount(\"tmpfs\", mount1, \"tmpfs\", 0, \"\"); err != nil {\n\t\tt.Skipf(\"cannot mount tmpfs on %s: %v\", mount1, err)\n\t}\n\tt.Cleanup(func() {\n\t\t_ = syscall.Unmount(mount1, 0)\n\t})\n\n\tif err := syscall.Mount(\"tmpfs\", mount2, \"tmpfs\", 0, \"\"); err != nil {\n\t\tt.Skipf(\"cannot mount tmpfs on %s: %v\", mount2, err)\n\t}\n\tt.Cleanup(func() {\n\t\t_ = syscall.Unmount(mount2, 0)\n\t})\n\n\ttests := []struct {\n\t\tname   string\n\t\tdir    string\n\t\tpath   string\n\t\tTMPDIR string\n\t\twant   string\n\t}{\n\t\t{\n\t\t\tname: \"implicit TMPDIR\",\n\t\t\tpath: filepath.Join(os.TempDir(), \"foo.txt\"),\n\t\t\twant: os.TempDir(),\n\t\t},\n\n\t\t{\n\t\t\tname:   \"explicit TMPDIR\",\n\t\t\tpath:   filepath.Join(mount1, \"foo.txt\"),\n\t\t\tTMPDIR: mount1,\n\t\t\twant:   mount1,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"explicit unsuitable TMPDIR\",\n\t\t\tpath:   filepath.Join(mount1, \"foo.txt\"),\n\t\t\tTMPDIR: mount2,\n\t\t\twant:   mount1,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"nonexistant TMPDIR\",\n\t\t\tpath:   filepath.Join(mount1, \"foo.txt\"),\n\t\t\tTMPDIR: \"/nonexistant\",\n\t\t\twant:   mount1,\n\t\t},\n\n\t\t{\n\t\t\tname:   \"caller-specified\",\n\t\t\tdir:    \"/overridden\",\n\t\t\tpath:   filepath.Join(mount1, \"foo.txt\"),\n\t\t\tTMPDIR: \"/nonexistant\",\n\t\t\twant:   \"/overridden\",\n\t\t},\n\t}\n\n\tfor _, testCase := range tests {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tif testCase.TMPDIR == \"\" {\n\t\t\t\t_ = os.Unsetenv(\"TMPDIR\")\n\t\t\t} else {\n\t\t\t\t_ = os.Setenv(\"TMPDIR\", testCase.TMPDIR)\n\t\t\t}\n\n\t\t\tif got := tempDir(testCase.dir, testCase.path); got != testCase.want {\n\t\t\t\tt.Fatalf(\"tempDir(%q, %q): got %q, want %q\", testCase.dir, testCase.path, got, testCase.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "base/utils/renameio/writefile.go",
    "content": "package renameio\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/hectane/go-acl\"\n)\n\n// WriteFile mirrors os.WriteFile, replacing an existing file with the same\n// name atomically.\nfunc WriteFile(filename string, data []byte, perm os.FileMode) error {\n\tt, err := TempFile(\"\", filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = t.Cleanup()\n\t}()\n\n\t// Set permissions before writing data, in case the data is sensitive.\n\tif runtime.GOOS == \"windows\" {\n\t\terr = acl.Chmod(t.path, perm)\n\t} else {\n\t\terr = t.Chmod(perm)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := t.Write(data); err != nil {\n\t\treturn err\n\t}\n\n\treturn t.CloseAtomicallyReplace()\n}\n"
  },
  {
    "path": "base/utils/renameio/writefile_test.go",
    "content": "//go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris || windows\n\npackage renameio\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc TestWriteFile(t *testing.T) {\n\tt.Parallel()\n\n\td, err := os.MkdirTemp(\"\", \"test-renameio-testwritefile\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer func() {\n\t\t_ = os.RemoveAll(d)\n\t}()\n\n\tfilename := filepath.Join(d, \"hello.sh\")\n\n\twantData := []byte(\"#!/bin/sh\\necho \\\"Hello World\\\"\\n\")\n\twantPerm := os.FileMode(0o0600)\n\tif err := WriteFile(filename, wantData, wantPerm); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tgotData, err := os.ReadFile(filename)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !bytes.Equal(gotData, wantData) {\n\t\tt.Errorf(\"got data %v, want data %v\", gotData, wantData)\n\t}\n\n\tfi, err := os.Stat(filename)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif gotPerm := fi.Mode() & os.ModePerm; gotPerm != wantPerm {\n\t\tt.Errorf(\"got permissions 0%o, want permissions 0%o\", gotPerm, wantPerm)\n\t}\n}\n"
  },
  {
    "path": "base/utils/safe.go",
    "content": "package utils\n\nimport (\n\t\"encoding/hex\"\n\t\"strings\"\n)\n\n// SafeFirst16Bytes return the first 16 bytes of the given data in safe form.\nfunc SafeFirst16Bytes(data []byte) string {\n\tif len(data) == 0 {\n\t\treturn \"<empty>\"\n\t}\n\n\treturn strings.TrimPrefix(\n\t\tstrings.SplitN(hex.Dump(data), \"\\n\", 2)[0],\n\t\t\"00000000  \",\n\t)\n}\n\n// SafeFirst16Chars return the first 16 characters of the given data in safe form.\nfunc SafeFirst16Chars(s string) string {\n\treturn SafeFirst16Bytes([]byte(s))\n}\n"
  },
  {
    "path": "base/utils/safe_test.go",
    "content": "package utils\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSafeFirst16(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t,\n\t\t\"47 6f 20 69 73 20 61 6e  20 6f 70 65 6e 20 73 6f  |Go is an open so|\",\n\t\tSafeFirst16Bytes([]byte(\"Go is an open source programming language.\")),\n\t)\n\tassert.Equal(t,\n\t\t\"47 6f 20 69 73 20 61 6e  20 6f 70 65 6e 20 73 6f  |Go is an open so|\",\n\t\tSafeFirst16Chars(\"Go is an open source programming language.\"),\n\t)\n\n\tassert.Equal(t,\n\t\t\"<empty>\",\n\t\tSafeFirst16Bytes(nil),\n\t)\n\tassert.Equal(t,\n\t\t\"<empty>\",\n\t\tSafeFirst16Chars(\"\"),\n\t)\n}\n"
  },
  {
    "path": "base/utils/slices.go",
    "content": "package utils\n\n// IndexOfString returns the index of given string and -1 if its not part of the slice.\nfunc IndexOfString(a []string, s string) int {\n\tfor i, entry := range a {\n\t\tif entry == s {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// StringInSlice returns whether the given string is in the string slice.\nfunc StringInSlice(a []string, s string) bool {\n\treturn IndexOfString(a, s) >= 0\n}\n\n// RemoveFromStringSlice removes the given string from the slice and returns a new slice.\nfunc RemoveFromStringSlice(a []string, s string) []string {\n\ti := IndexOfString(a, s)\n\tif i > 0 {\n\t\ta = append(a[:i], a[i+1:]...)\n\t}\n\treturn a\n}\n\n// DuplicateStrings returns a new copy of the given string slice.\nfunc DuplicateStrings(a []string) []string {\n\tb := make([]string, len(a))\n\tcopy(b, a)\n\treturn b\n}\n\n// StringSliceEqual returns whether the given string slices are equal.\nfunc StringSliceEqual(a []string, b []string) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, v := range a {\n\t\tif v != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// DuplicateBytes returns a new copy of the given byte slice.\nfunc DuplicateBytes(a []byte) []byte {\n\tb := make([]byte, len(a))\n\tcopy(b, a)\n\treturn b\n}\n"
  },
  {
    "path": "base/utils/slices_test.go",
    "content": "package utils\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nvar (\n\tstringTestSlice  = []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\"}\n\tstringTestSlice2 = []string{\"a\", \"x\", \"x\", \"x\", \"x\", \"x\", \"x\", \"x\", \"x\", \"j\"}\n\tstringTestSlice3 = []string{\"a\", \"x\"}\n\tbyteTestSlice    = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}\n)\n\nfunc TestStringInSlice(t *testing.T) {\n\tt.Parallel()\n\n\tif !StringInSlice(stringTestSlice, \"a\") {\n\t\tt.Fatal(\"string reported not in slice (1), but it is\")\n\t}\n\tif !StringInSlice(stringTestSlice, \"d\") {\n\t\tt.Fatal(\"string reported not in slice (2), but it is\")\n\t}\n\tif !StringInSlice(stringTestSlice, \"j\") {\n\t\tt.Fatal(\"string reported not in slice (3), but it is\")\n\t}\n\n\tif StringInSlice(stringTestSlice, \"0\") {\n\t\tt.Fatal(\"string reported in slice (1), but is not\")\n\t}\n\tif StringInSlice(stringTestSlice, \"x\") {\n\t\tt.Fatal(\"string reported in slice (2), but is not\")\n\t}\n\tif StringInSlice(stringTestSlice, \"k\") {\n\t\tt.Fatal(\"string reported in slice (3), but is not\")\n\t}\n}\n\nfunc TestRemoveFromStringSlice(t *testing.T) {\n\tt.Parallel()\n\n\ttest1 := DuplicateStrings(stringTestSlice)\n\ttest1 = RemoveFromStringSlice(test1, \"b\")\n\tif StringInSlice(test1, \"b\") {\n\t\tt.Fatal(\"string reported in slice, but was removed\")\n\t}\n\tif len(test1) != len(stringTestSlice)-1 {\n\t\tt.Fatalf(\"new string slice length not as expected: is %d, should be %d\\nnew slice is %v\", len(test1), len(stringTestSlice)-1, test1)\n\t}\n\tRemoveFromStringSlice(test1, \"b\")\n}\n\nfunc TestDuplicateStrings(t *testing.T) {\n\tt.Parallel()\n\n\ta := DuplicateStrings(stringTestSlice)\n\tif !StringSliceEqual(a, stringTestSlice) {\n\t\tt.Fatal(\"copied string slice is not equal\")\n\t}\n\ta[0] = \"x\"\n\tif StringSliceEqual(a, stringTestSlice) {\n\t\tt.Fatal(\"copied string slice is not a real copy\")\n\t}\n}\n\nfunc TestStringSliceEqual(t *testing.T) {\n\tt.Parallel()\n\n\tif !StringSliceEqual(stringTestSlice, stringTestSlice) {\n\t\tt.Fatal(\"strings are equal, but are reported as not\")\n\t}\n\tif StringSliceEqual(stringTestSlice, stringTestSlice2) {\n\t\tt.Fatal(\"strings are not equal (1), but are reported as equal\")\n\t}\n\tif StringSliceEqual(stringTestSlice, stringTestSlice3) {\n\t\tt.Fatal(\"strings are not equal (1), but are reported as equal\")\n\t}\n}\n\nfunc TestDuplicateBytes(t *testing.T) {\n\tt.Parallel()\n\n\ta := DuplicateBytes(byteTestSlice)\n\tif !bytes.Equal(a, byteTestSlice) {\n\t\tt.Fatal(\"copied bytes slice is not equal\")\n\t}\n\ta[0] = 0xff\n\tif bytes.Equal(a, byteTestSlice) {\n\t\tt.Fatal(\"copied bytes slice is not a real copy\")\n\t}\n}\n"
  },
  {
    "path": "base/utils/stablepool.go",
    "content": "package utils\n\nimport \"sync\"\n\n// A StablePool is a drop-in replacement for sync.Pool that is slower, but\n// predictable.\n// A StablePool is a set of temporary objects that may be individually saved and\n// retrieved.\n//\n// In contrast to sync.Pool, items are not removed automatically. Every item\n// will be returned at some point. Items are returned in a FIFO manner in order\n// to evenly distribute usage of a set of items.\n//\n// A StablePool is safe for use by multiple goroutines simultaneously and must\n// not be copied after first use.\ntype StablePool struct {\n\tlock sync.Mutex\n\n\tpool     []interface{}\n\tcnt      int\n\tgetIndex int\n\tputIndex int\n\n\t// New optionally specifies a function to generate\n\t// a value when Get would otherwise return nil.\n\t// It may not be changed concurrently with calls to Get.\n\tNew func() interface{}\n}\n\n// Put adds x to the pool.\nfunc (p *StablePool) Put(x interface{}) {\n\tif x == nil {\n\t\treturn\n\t}\n\n\tp.lock.Lock()\n\tdefer p.lock.Unlock()\n\n\t// check if pool is full (or unitialized)\n\tif p.cnt == len(p.pool) {\n\t\tp.pool = append(p.pool, x)\n\t\tp.cnt++\n\t\tp.putIndex = p.cnt\n\t\treturn\n\t}\n\n\t// correct putIndex\n\tp.putIndex %= len(p.pool)\n\n\t// iterate the whole pool once to find a free spot\n\tstopAt := p.putIndex - 1\n\tfor i := p.putIndex; i != stopAt; i = (i + 1) % len(p.pool) {\n\t\tif p.pool[i] == nil {\n\t\t\tp.pool[i] = x\n\t\t\tp.cnt++\n\t\t\tp.putIndex = i + 1\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Get returns the next item from the Pool, removes it from the Pool, and\n// returns it to the caller.\n// In contrast to sync.Pool, Get never ignores the pool.\n// Callers should not assume any relation between values passed to Put and\n// the values returned by Get.\n//\n// If Get would otherwise return nil and p.New is non-nil, Get returns\n// the result of calling p.New.\nfunc (p *StablePool) Get() interface{} {\n\tp.lock.Lock()\n\tdefer p.lock.Unlock()\n\n\t// check if pool is empty\n\tif p.cnt == 0 {\n\t\tif p.New != nil {\n\t\t\treturn p.New()\n\t\t}\n\t\treturn nil\n\t}\n\n\t// correct getIndex\n\tp.getIndex %= len(p.pool)\n\n\t// iterate the whole pool to find an item\n\tstopAt := p.getIndex - 1\n\tfor i := p.getIndex; i != stopAt; i = (i + 1) % len(p.pool) {\n\t\tif p.pool[i] != nil {\n\t\t\tx := p.pool[i]\n\t\t\tp.pool[i] = nil\n\t\t\tp.cnt--\n\t\t\tp.getIndex = i + 1\n\t\t\treturn x\n\t\t}\n\t}\n\n\t// if we ever get here, return a new item\n\tif p.New != nil {\n\t\treturn p.New()\n\t}\n\treturn nil\n}\n\n// Size returns the amount of items the pool currently holds.\nfunc (p *StablePool) Size() int {\n\tp.lock.Lock()\n\tdefer p.lock.Unlock()\n\n\treturn p.cnt\n}\n\n// Max returns the amount of items the pool held at maximum.\nfunc (p *StablePool) Max() int {\n\tp.lock.Lock()\n\tdefer p.lock.Unlock()\n\n\treturn len(p.pool)\n}\n"
  },
  {
    "path": "base/utils/stablepool_test.go",
    "content": "package utils\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStablePoolRealWorld(t *testing.T) {\n\tt.Parallel()\n\t// \"real world\" simulation\n\n\tcnt := 0\n\ttestPool := &StablePool{\n\t\tNew: func() interface{} {\n\t\t\tcnt++\n\t\t\treturn cnt\n\t\t},\n\t}\n\tvar testWg sync.WaitGroup\n\tvar testWorkerWg sync.WaitGroup\n\n\t// for i := 0; i < 100; i++ {\n\t// \tcnt++\n\t// \ttestPool.Put(cnt)\n\t// }\n\tfor range 100 {\n\t\t// block round\n\t\ttestWg.Add(1)\n\t\t// add workers\n\t\ttestWorkerWg.Add(100)\n\t\tfor j := range 100 {\n\t\t\tgo func() {\n\t\t\t\t// wait for round to start\n\t\t\t\ttestWg.Wait()\n\t\t\t\t// get value\n\t\t\t\tx := testPool.Get()\n\t\t\t\t// fmt.Println(x)\n\t\t\t\t// \"work\"\n\t\t\t\ttime.Sleep(5 * time.Microsecond)\n\t\t\t\t// re-insert 99%\n\t\t\t\tif j%100 > 0 {\n\t\t\t\t\ttestPool.Put(x)\n\t\t\t\t}\n\t\t\t\t// mark as finished\n\t\t\t\ttestWorkerWg.Done()\n\t\t\t}()\n\t\t}\n\t\t// start round\n\t\ttestWg.Done()\n\t\t// wait for round to finish\n\t\ttestWorkerWg.Wait()\n\t}\n\tt.Logf(\"real world simulation: cnt=%d p.cnt=%d p.max=%d\\n\", cnt, testPool.Size(), testPool.Max())\n\tassert.GreaterOrEqual(t, 200, cnt, \"should not use more than 200 values\")\n\tassert.GreaterOrEqual(t, 100, testPool.Max(), \"pool should have at most this max size\")\n\n\t// optimal usage test\n\n\toptPool := &StablePool{}\n\tfor range 1000 {\n\t\tfor j := range 100 {\n\t\t\toptPool.Put(j)\n\t\t}\n\t\tfor k := range 100 {\n\t\t\tassert.Equal(t, k, optPool.Get(), \"should match\")\n\t\t}\n\t}\n\tassert.Equal(t, 100, optPool.Max(), \"pool should have exactly this max size\")\n}\n\nfunc TestStablePoolFuzzing(t *testing.T) {\n\tt.Parallel()\n\t// fuzzing test\n\n\tfuzzPool := &StablePool{}\n\tvar fuzzWg sync.WaitGroup\n\tvar fuzzWorkerWg sync.WaitGroup\n\t// start goroutines and wait\n\tfuzzWg.Add(1)\n\tfor i := range 1000 {\n\t\tfuzzWorkerWg.Add(2)\n\t\tgo func() {\n\t\t\tfuzzWg.Wait()\n\t\t\tfuzzPool.Put(i)\n\t\t\tfuzzWorkerWg.Done()\n\t\t}()\n\t\tgo func() {\n\t\t\tfuzzWg.Wait()\n\t\t\tfmt.Print(fuzzPool.Get())\n\t\t\tfuzzWorkerWg.Done()\n\t\t}()\n\t}\n\t// kick off\n\tfuzzWg.Done()\n\t// wait for all to finish\n\tfuzzWorkerWg.Wait()\n}\n\nfunc TestStablePoolBreaking(t *testing.T) {\n\tt.Parallel()\n\t// try to break it\n\n\tbreakPool := &StablePool{}\n\tfor range 10 {\n\t\tfor j := range 100 {\n\t\t\tbreakPool.Put(nil)\n\t\t\tbreakPool.Put(j)\n\t\t\tbreakPool.Put(nil)\n\t\t}\n\t\tfor k := range 100 {\n\t\t\tassert.Equal(t, k, breakPool.Get(), \"should match\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "base/utils/structure.go",
    "content": "package utils\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n)\n\ntype FSPermission uint8\n\nconst (\n\tAdminOnlyPermission FSPermission = iota\n\tAdminOnlyExecPermission\n\tPublicReadPermission\n\tPublicReadExecPermission\n\tPublicWritePermission\n\tPublicWriteExecPermission\n)\n\n// AsUnixDirExecPermission return the corresponding unix permission for a directory or executable.\nfunc (perm FSPermission) AsUnixPermission() fs.FileMode {\n\tswitch perm {\n\tcase AdminOnlyPermission:\n\t\treturn 0o600\n\tcase AdminOnlyExecPermission:\n\t\treturn 0o700\n\tcase PublicReadPermission:\n\t\treturn 0o644\n\tcase PublicReadExecPermission:\n\t\treturn 0o755\n\tcase PublicWritePermission:\n\t\treturn 0o666\n\tcase PublicWriteExecPermission:\n\t\treturn 0o777\n\t}\n\n\treturn 0\n}\n\nfunc (perm FSPermission) IsExecPermission() bool {\n\tswitch perm {\n\tcase AdminOnlyExecPermission, PublicReadExecPermission, PublicWriteExecPermission:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// DirStructure represents a directory structure with permissions that should be enforced.\ntype DirStructure struct {\n\tsync.Mutex\n\n\tPath     string\n\tDir      string\n\tPerm     FSPermission\n\tParent   *DirStructure\n\tChildren map[string]*DirStructure\n}\n\n// NewDirStructure returns a new DirStructure.\nfunc NewDirStructure(path string, perm FSPermission) *DirStructure {\n\treturn &DirStructure{\n\t\tPath:     path,\n\t\tPerm:     perm,\n\t\tChildren: make(map[string]*DirStructure),\n\t}\n}\n\n// ChildDir adds a new child DirStructure and returns it. Should the child already exist, the existing child is returned and the permissions are updated.\nfunc (ds *DirStructure) ChildDir(dirName string, perm FSPermission) (child *DirStructure) {\n\tds.Lock()\n\tdefer ds.Unlock()\n\n\t// if exists, update\n\tchild, ok := ds.Children[dirName]\n\tif ok {\n\t\tchild.Perm = perm\n\t\treturn child\n\t}\n\n\t// create new\n\tnewDir := &DirStructure{\n\t\tPath:     filepath.Join(ds.Path, dirName),\n\t\tDir:      dirName,\n\t\tPerm:     perm,\n\t\tParent:   ds,\n\t\tChildren: make(map[string]*DirStructure),\n\t}\n\tds.Children[dirName] = newDir\n\treturn newDir\n}\n\n// Ensure ensures that the specified directory structure (from the first parent on) exists.\nfunc (ds *DirStructure) Ensure() error {\n\treturn ds.EnsureAbsPath(ds.Path)\n}\n\n// EnsureRelPath ensures that the specified directory structure (from the first parent on) and the given relative path (to the DirStructure) exists.\nfunc (ds *DirStructure) EnsureRelPath(dirPath string) error {\n\treturn ds.EnsureAbsPath(filepath.Join(ds.Path, dirPath))\n}\n\n// EnsureRelDir ensures that the specified directory structure (from the first parent on) and the given relative path (to the DirStructure) exists.\nfunc (ds *DirStructure) EnsureRelDir(dirNames ...string) error {\n\treturn ds.EnsureAbsPath(filepath.Join(append([]string{ds.Path}, dirNames...)...))\n}\n\n// EnsureAbsPath ensures that the specified directory structure (from the first parent on) and the given absolute path exists.\n// If the given path is outside the DirStructure, an error will be returned.\nfunc (ds *DirStructure) EnsureAbsPath(dirPath string) error {\n\t// always start at the top\n\tif ds.Parent != nil {\n\t\treturn ds.Parent.EnsureAbsPath(dirPath)\n\t}\n\n\t// check if root\n\tif dirPath == ds.Path {\n\t\treturn ds.ensure(nil)\n\t}\n\n\t// check scope\n\tslashedPath := ds.Path\n\t// add slash to end\n\tif !strings.HasSuffix(slashedPath, string(filepath.Separator)) {\n\t\tslashedPath += string(filepath.Separator)\n\t}\n\t// check if given path is in scope\n\tif !strings.HasPrefix(dirPath, slashedPath) {\n\t\treturn fmt.Errorf(`path \"%s\" is outside of DirStructure scope`, dirPath)\n\t}\n\n\t// get relative path\n\trelPath, err := filepath.Rel(ds.Path, dirPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get relative path: %w\", err)\n\t}\n\n\t// split to path elements\n\tpathDirs := strings.Split(filepath.ToSlash(relPath), \"/\")\n\n\t// start checking\n\treturn ds.ensure(pathDirs)\n}\n\nfunc (ds *DirStructure) ensure(pathDirs []string) error {\n\tds.Lock()\n\tdefer ds.Unlock()\n\n\t// check current dir\n\terr := EnsureDirectory(ds.Path, ds.Perm)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(pathDirs) == 0 {\n\t\t// we reached the end!\n\t\treturn nil\n\t}\n\n\tchild, ok := ds.Children[pathDirs[0]]\n\tif !ok {\n\t\t// we have reached the end of the defined dir structure\n\t\t// ensure all remaining dirs\n\t\tdirPath := ds.Path\n\t\tfor _, dir := range pathDirs {\n\t\t\tdirPath = filepath.Join(dirPath, dir)\n\t\t\terr := EnsureDirectory(dirPath, ds.Perm)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\t// we got a child, continue\n\treturn child.ensure(pathDirs[1:])\n}\n"
  },
  {
    "path": "base/utils/structure_test.go",
    "content": "//go:build !windows\n\npackage utils\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc ExampleDirStructure() {\n\t// output:\n\t// / [755]\n\t// /repo [777]\n\t// /repo/b [755]\n\t// /repo/b/c [777]\n\t// /repo/b/d [755]\n\t// /repo/b/d/e [755]\n\t// /repo/b/d/f [755]\n\t// /repo/b/d/f/g [755]\n\t// /repo/b/d/f/g/h [755]\n\t// /secret [700]\n\n\tbasePath, err := os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tds := NewDirStructure(basePath, PublicReadExecPermission)\n\tsecret := ds.ChildDir(\"secret\", AdminOnlyExecPermission)\n\trepo := ds.ChildDir(\"repo\", PublicWriteExecPermission)\n\t_ = repo.ChildDir(\"a\", AdminOnlyExecPermission)\n\tb := repo.ChildDir(\"b\", PublicReadExecPermission)\n\tc := b.ChildDir(\"c\", PublicWriteExecPermission)\n\n\terr = ds.Ensure()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\terr = c.Ensure()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\terr = secret.Ensure()\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\terr = b.EnsureRelDir(\"d\", \"e\")\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\terr = b.EnsureRelPath(\"d/f/g/h\")\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n\n\t_ = filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {\n\t\tif err == nil {\n\t\t\tdir := strings.TrimPrefix(path, basePath)\n\t\t\tif dir == \"\" {\n\t\t\t\tdir = \"/\"\n\t\t\t}\n\t\t\tfmt.Printf(\"%s [%o]\\n\", dir, info.Mode().Perm())\n\t\t}\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "base/utils/uuid.go",
    "content": "package utils\n\nimport (\n\t\"encoding/binary\"\n\t\"time\"\n\n\t\"github.com/gofrs/uuid\"\n)\n\nvar (\n\tconstantUUID = uuid.Must(uuid.FromString(\"e8dba9f7-21e2-4c82-96cb-6586922c6422\"))\n\tinstanceUUID = RandomUUID(\"instance\")\n)\n\n// RandomUUID returns a new random UUID with optionally provided ns.\nfunc RandomUUID(ns string) uuid.UUID {\n\trandUUID, err := uuid.NewV4()\n\tswitch {\n\tcase err != nil:\n\t\t// fallback\n\t\t// should practically never happen\n\t\treturn uuid.NewV5(uuidFromTime(), ns)\n\tcase ns != \"\":\n\t\t// mix ns into the UUID\n\t\treturn uuid.NewV5(randUUID, ns)\n\tdefault:\n\t\treturn randUUID\n\t}\n}\n\n// DerivedUUID returns a new UUID that is derived from the input only, and therefore is always reproducible.\nfunc DerivedUUID(input string) uuid.UUID {\n\treturn uuid.NewV5(constantUUID, input)\n}\n\n// DerivedInstanceUUID returns a new UUID that is derived from the input, but is unique per instance (execution) and therefore is only reproducible with the same process.\nfunc DerivedInstanceUUID(input string) uuid.UUID {\n\treturn uuid.NewV5(instanceUUID, input)\n}\n\nfunc uuidFromTime() uuid.UUID {\n\tvar timeUUID uuid.UUID\n\tbinary.LittleEndian.PutUint64(timeUUID[:], uint64(time.Now().UnixNano()))\n\treturn timeUUID\n}\n"
  },
  {
    "path": "base/utils/uuid_test.go",
    "content": "package utils\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gofrs/uuid\"\n)\n\nfunc TestUUID(t *testing.T) {\n\tt.Parallel()\n\n\t// check randomness\n\ta := RandomUUID(\"\")\n\ta2 := RandomUUID(\"\")\n\tif a.String() == a2.String() {\n\t\tt.Error(\"should not match\")\n\t}\n\n\t// check with input\n\tb := RandomUUID(\"b\")\n\tb2 := RandomUUID(\"b\")\n\tif b.String() == b2.String() {\n\t\tt.Error(\"should not match\")\n\t}\n\n\t// check with long input\n\tc := RandomUUID(\"TG8UkxS+4rVrDxHtDAaNab1CBpygzmX1g5mJA37jbQ5q2uE4rVrDxHtDAaNab1CBpygzmX1g5mJA37jbQ5q2uE\")\n\tc2 := RandomUUID(\"TG8UkxS+4rVrDxHtDAaNab1CBpygzmX1g5mJA37jbQ5q2uE4rVrDxHtDAaNab1CBpygzmX1g5mJA37jbQ5q2uE\")\n\tif c.String() == c2.String() {\n\t\tt.Error(\"should not match\")\n\t}\n\n\t// check for nanosecond precision\n\td := uuidFromTime()\n\ttime.Sleep(2 * time.Nanosecond)\n\td2 := uuidFromTime()\n\tif d.String() == d2.String() {\n\t\tt.Error(\"should not match\")\n\t}\n\n\t// check mixing\n\ttimeUUID := uuidFromTime()\n\te := uuid.NewV5(timeUUID, \"e\")\n\te2 := uuid.NewV5(timeUUID, \"e2\")\n\tif e.String() == e2.String() {\n\t\tt.Error(\"should not match\")\n\t}\n\n\t// check deriving\n\tf := DerivedUUID(\"f\")\n\tf2 := DerivedUUID(\"f\")\n\tf3 := DerivedUUID(\"f3\")\n\tif f.String() != f2.String() {\n\t\tt.Error(\"should match\")\n\t}\n\tif f.String() == f3.String() {\n\t\tt.Error(\"should not match\")\n\t}\n\n\t// check instance deriving\n\tg := DerivedInstanceUUID(\"g\")\n\tg2 := DerivedInstanceUUID(\"g\")\n\tg3 := DerivedInstanceUUID(\"g3\")\n\tif g.String() != g2.String() {\n\t\tt.Error(\"should match\")\n\t}\n\tif g.String() == g3.String() {\n\t\tt.Error(\"should not match\")\n\t}\n}\n"
  },
  {
    "path": "cmds/cmdbase/service.go",
    "content": "package cmdbase\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log/slog\"\n\t\"os\"\n\t\"os/exec\"\n\t\"runtime\"\n\t\"runtime/pprof\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar (\n\tRebootOnRestart  bool\n\tPrintStackOnExit bool\n)\n\ntype SystemService interface {\n\tRun()\n\tIsService() bool\n\tRestartService() error\n}\n\ntype ServiceInstance interface {\n\tReady() bool\n\tStart() error\n\tStop() error\n\tRestart()\n\tShutdown()\n\tCtx() context.Context\n\tIsShuttingDown() bool\n\tShuttingDown() <-chan struct{}\n\tShutdownCtx() context.Context\n\tIsShutDown() bool\n\tShutdownComplete() <-chan struct{}\n\tExitCode() int\n\tShouldRestartIsSet() bool\n\tCommandLineOperationIsSet() bool\n\tCommandLineOperationExecute() error\n}\n\nvar (\n\tSvcFactory func(*service.ServiceConfig) (ServiceInstance, error)\n\tSvcConfig  *service.ServiceConfig\n)\n\nfunc RunService(cmd *cobra.Command, args []string) {\n\tif SvcFactory == nil || SvcConfig == nil {\n\t\tfmt.Fprintln(os.Stderr, \"internal error: service not set up in cmdbase\")\n\t\tos.Exit(1)\n\t}\n\n\t// Start logging.\n\t// Note: Must be created before the service instance, so that they use the right logger.\n\terr := log.Start(SvcConfig.LogLevel, SvcConfig.LogToStdout, SvcConfig.LogDir)\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err.Error())\n\t\tos.Exit(4)\n\t}\n\n\t// Create instance.\n\t// Instance modules might request a cmdline execution of a function.\n\tvar execCmdLine bool\n\tinstance, err := SvcFactory(SvcConfig)\n\tswitch {\n\tcase err == nil:\n\t\t// Continue\n\tcase errors.Is(err, mgr.ErrExecuteCmdLineOp):\n\t\texecCmdLine = true\n\tdefault:\n\t\tfmt.Printf(\"error creating an instance: %s\\n\", err)\n\t\tos.Exit(2)\n\t}\n\n\t// Execute module command line operation, if requested or available.\n\tswitch {\n\tcase !execCmdLine:\n\t\t// Run service.\n\tcase !instance.CommandLineOperationIsSet():\n\t\tfmt.Println(\"command line operation execution requested, but not set\")\n\t\tos.Exit(3)\n\tdefault:\n\t\t// Run the function and exit.\n\t\tfmt.Println(\"executing cmdline op\")\n\t\terr = instance.CommandLineOperationExecute()\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"command line operation failed: %s\\n\", err)\n\t\t\tos.Exit(3)\n\t\t}\n\t\tos.Exit(0)\n\t}\n\n\t// START\n\n\t// Create system service.\n\tservice := NewSystemService(instance)\n\n\t// Start instance via system service manager.\n\tgo func() {\n\t\tservice.Run()\n\t}()\n\n\t// SHUTDOWN\n\n\t// Wait for shutdown to be started.\n\t<-instance.ShuttingDown()\n\n\t// Wait for shutdown to be finished.\n\tselect {\n\tcase <-instance.ShutdownComplete():\n\t\t// Print stack on shutdown, if enabled.\n\t\tif PrintStackOnExit {\n\t\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK ON EXIT\")\n\t\t}\n\tcase <-time.After(3 * time.Minute):\n\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK - TAKING TOO LONG FOR SHUTDOWN\")\n\t}\n\n\t// Check if restart was triggered and send start service command if true.\n\tif instance.ShouldRestartIsSet() && service.IsService() {\n\t\t// Check if we should reboot instead.\n\t\tvar rebooting bool\n\t\tif RebootOnRestart {\n\t\t\t// Trigger system reboot and record success.\n\t\t\trebooting = triggerSystemReboot()\n\t\t\tif !rebooting {\n\t\t\t\tlog.Warningf(\"updates: rebooting failed, only restarting service instead\")\n\t\t\t}\n\t\t}\n\n\t\t// Restart service if not rebooting.\n\t\tif !rebooting {\n\t\t\tif err := service.RestartService(); err != nil {\n\t\t\t\tslog.Error(\"failed to restart service\", \"err\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Stop logging.\n\tlog.Shutdown()\n\n\t// Give a small amount of time for everything to settle:\n\t// - All logs written.\n\t// - Restart command started, if needed.\n\t// - Windows service manager notified.\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// Exit\n\tos.Exit(instance.ExitCode())\n}\n\nfunc printStackTo(writer io.Writer, msg string) {\n\t_, err := fmt.Fprintf(writer, \"===== %s =====\\n\", msg)\n\tif err == nil {\n\t\terr = pprof.Lookup(\"goroutine\").WriteTo(writer, 1)\n\t}\n\tif err != nil {\n\t\tslog.Error(\"failed to write stack trace\", \"err\", err)\n\t}\n}\n\nfunc triggerSystemReboot() (success bool) {\n\tswitch runtime.GOOS {\n\tcase \"linux\":\n\t\terr := exec.Command(\"systemctl\", \"reboot\").Run()\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"updates: triggering reboot with systemctl failed: %s\", err)\n\t\t\treturn false\n\t\t}\n\tdefault:\n\t\tlog.Warningf(\"updates: rebooting is not support on %s\", runtime.GOOS)\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "cmds/cmdbase/service_linux.go",
    "content": "package cmdbase\n\nimport (\n\t\"fmt\"\n\t\"log/slog\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\tprocessInfo \"github.com/shirou/gopsutil/process\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\ntype LinuxSystemService struct {\n\tinstance ServiceInstance\n}\n\nfunc NewSystemService(instance ServiceInstance) *LinuxSystemService {\n\treturn &LinuxSystemService{instance: instance}\n}\n\nfunc (s *LinuxSystemService) Run() {\n\t// Start instance.\n\terr := s.instance.Start()\n\tif err != nil {\n\t\tslog.Error(\"failed to start\", \"err\", err)\n\n\t\t// Print stack on start failure, if enabled.\n\t\tif PrintStackOnExit {\n\t\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK ON START FAILURE\")\n\t\t}\n\n\t\tos.Exit(1)\n\t}\n\n\t// Subscribe to signals.\n\tsignalCh := make(chan os.Signal, 1)\n\tsignal.Notify(\n\t\tsignalCh,\n\t\tos.Interrupt,\n\t\tsyscall.SIGHUP,\n\t\tsyscall.SIGINT,\n\t\tsyscall.SIGTERM,\n\t\tsyscall.SIGQUIT,\n\t\tsyscall.SIGUSR1,\n\t)\n\n\t// Wait for shutdown signal.\nwait:\n\tfor {\n\t\tselect {\n\t\tcase <-s.instance.ShuttingDown():\n\t\t\tbreak wait\n\t\tcase sig := <-signalCh:\n\t\t\t// Only print and continue to wait if SIGUSR1\n\t\t\tif sig == syscall.SIGUSR1 {\n\t\t\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK ON REQUEST\")\n\t\t\t\tcontinue wait\n\t\t\t} else {\n\t\t\t\t// Trigger shutdown.\n\t\t\t\tfmt.Printf(\" <SIGNAL: %v>\\n\", sig) // CLI output.\n\t\t\t\tslog.Warn(\"received stop signal\", \"signal\", sig)\n\t\t\t\ts.instance.Shutdown()\n\t\t\t\tbreak wait\n\t\t\t}\n\t\t}\n\t}\n\n\t// Wait for shutdown to finish.\n\n\t// Catch signals during shutdown.\n\t// Force exit after 5 interrupts.\n\tforceCnt := 5\n\tfor {\n\t\tselect {\n\t\tcase <-s.instance.ShutdownComplete():\n\t\t\treturn\n\t\tcase sig := <-signalCh:\n\t\t\tif sig != syscall.SIGUSR1 {\n\t\t\t\tforceCnt--\n\t\t\t\tif forceCnt > 0 {\n\t\t\t\t\tfmt.Printf(\" <SIGNAL: %s> again, but already shutting down - %d more to force\\n\", sig, forceCnt)\n\t\t\t\t} else {\n\t\t\t\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK ON FORCED EXIT\")\n\t\t\t\t\tos.Exit(1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (s *LinuxSystemService) RestartService() error {\n\t// Check if user defined custom command for restarting the service.\n\trestartCommand, exists := os.LookupEnv(\"PORTMASTER_RESTART_COMMAND\")\n\n\t// Run the service restart\n\tvar cmd *exec.Cmd\n\tif exists && restartCommand != \"\" {\n\t\tslog.Debug(\"running custom restart command\", \"command\", restartCommand)\n\t\tcmd = exec.Command(\"sh\", \"-c\", restartCommand)\n\t} else {\n\t\tcmd = exec.Command(\"systemctl\", \"restart\", \"portmaster\")\n\t}\n\tif err := cmd.Start(); err != nil {\n\t\treturn fmt.Errorf(\"failed run restart command: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (s *LinuxSystemService) IsService() bool {\n\t// Get own process ID\n\tpid := os.Getpid()\n\n\t// Get parent process ID.\n\tcurrentProcess, err := processInfo.NewProcess(int32(pid)) //nolint:gosec\n\tif err != nil {\n\t\treturn false\n\t}\n\tppid, err := currentProcess.Ppid()\n\tif err != nil {\n\t\treturn false\n\t}\n\n\t// Check if the parent process ID is 1 == init system\n\treturn ppid == 1\n}\n"
  },
  {
    "path": "cmds/cmdbase/service_windows.go",
    "content": "package cmdbase\n\n// Based on the official Go examples from\n// https://github.com/golang/sys/blob/master/windows/svc/example\n// by The Go Authors.\n// Original LICENSE (sha256sum: 2d36597f7117c38b006835ae7f537487207d8ec407aa9d9980794b2030cbc067) can be found in vendor/pkg cache directory.\n\nimport (\n\t\"fmt\"\n\t\"log/slog\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"golang.org/x/sys/windows/svc\"\n\t\"golang.org/x/sys/windows/svc/debug\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst serviceName = \"PortmasterCore\"\n\ntype WindowsSystemService struct {\n\tinstance ServiceInstance\n}\n\nfunc NewSystemService(instance ServiceInstance) *WindowsSystemService {\n\treturn &WindowsSystemService{instance: instance}\n}\n\nfunc (s *WindowsSystemService) Run() {\n\tsvcRun := svc.Run\n\n\t// Check if we are running interactively.\n\tisService, err := svc.IsWindowsService()\n\tswitch {\n\tcase err != nil:\n\t\tslog.Warn(\"failed to determine if running interactively\", \"err\", err)\n\t\tslog.Warn(\"continuing without service integration (no real service)\")\n\t\tsvcRun = debug.Run\n\n\tcase !isService:\n\t\tslog.Warn(\"running interactively, switching to debug execution (no real service)\")\n\t\tsvcRun = debug.Run\n\t}\n\n\t// Run service client.\n\terr = svcRun(serviceName, s)\n\tif err != nil {\n\t\tslog.Error(\"service execution failed\", \"err\", err)\n\t\tos.Exit(1)\n\t}\n\n\t// Execution continues in s.Execute().\n}\n\nfunc (s *WindowsSystemService) Execute(args []string, changeRequests <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {\n\t// Tell service manager we are starting.\n\tchanges <- svc.Status{State: svc.StartPending}\n\n\t// Start instance.\n\terr := s.instance.Start()\n\tif err != nil {\n\t\tfmt.Printf(\"failed to start: %s\\n\", err)\n\n\t\t// Print stack on start failure, if enabled.\n\t\tif PrintStackOnExit {\n\t\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK ON START FAILURE\")\n\t\t}\n\n\t\t// Notify service manager we stopped again.\n\t\tchanges <- svc.Status{State: svc.Stopped}\n\n\t\t// Relay exit code to service manager.\n\t\treturn false, 1\n\t}\n\n\t// Tell service manager we are up and running!\n\tchanges <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}\n\n\t// Subscribe to signals.\n\t// Docs: https://pkg.go.dev/os/signal?GOOS=windows\n\tsignalCh := make(chan os.Signal, 4)\n\tsignal.Notify(\n\t\tsignalCh,\n\n\t\t// Windows ^C (Control-C) or ^BREAK (Control-Break).\n\t\t// Completely prevents kill.\n\t\tos.Interrupt,\n\n\t\t// Windows CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT.\n\t\t// Does not prevent kill, but gives a little time to stop service.\n\t\tsyscall.SIGTERM,\n\t)\n\n\tisShuttingDown := false\n\t// Wait for shutdown signal.\nwaitSignal:\n\tfor {\n\t\tselect {\n\t\tcase sig := <-signalCh:\n\t\t\t// Trigger shutdown.\n\t\t\tfmt.Printf(\" <SIGNAL: %v>\\n\", sig) // CLI output.\n\t\t\tslog.Warn(\"received stop signal\", \"signal\", sig)\n\t\t\tbreak waitSignal\n\n\t\tcase c := <-changeRequests:\n\t\t\tswitch c.Cmd {\n\t\t\tcase svc.Interrogate:\n\t\t\t\tchanges <- c.CurrentStatus\n\n\t\t\tcase svc.Stop, svc.Shutdown:\n\t\t\t\tfmt.Printf(\" <SERVICE CMD: %v>\\n\", serviceCmdName(c.Cmd)) // CLI output.\n\t\t\t\tslog.Warn(\"received service shutdown command\", \"cmd\", c.Cmd)\n\t\t\t\tbreak waitSignal\n\n\t\t\tdefault:\n\t\t\t\tslog.Error(\"unexpected service control request\", \"cmd\", serviceCmdName(c.Cmd))\n\t\t\t}\n\n\t\tcase <-s.instance.ShuttingDown():\n\t\t\tisShuttingDown = true\n\t\t\tbreak waitSignal\n\t\t}\n\t}\n\n\t// Trigger shutdown,\n\t// but only if we are not already shutting down.\n\tif !isShuttingDown {\n\t\ts.instance.Shutdown()\n\t}\n\n\t// Notify the service host that service is in shutting down state.\n\tchanges <- svc.Status{State: svc.StopPending}\n\n\t// Wait for shutdown to finish.\n\t// Catch signals during shutdown.\n\t// Force exit after 5 interrupts.\n\tforceCnt := 5\nwaitShutdown:\n\tfor {\n\t\tselect {\n\t\tcase <-s.instance.ShutdownComplete():\n\t\t\tbreak waitShutdown\n\n\t\tcase sig := <-signalCh:\n\t\t\tforceCnt--\n\t\t\tif forceCnt > 0 {\n\t\t\t\tfmt.Printf(\" <SIGNAL: %s> but already shutting down - %d more to force\\n\", sig, forceCnt)\n\t\t\t} else {\n\t\t\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK ON FORCED EXIT\")\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\tcase c := <-changeRequests:\n\t\t\tswitch c.Cmd {\n\t\t\tcase svc.Interrogate:\n\t\t\t\tchanges <- c.CurrentStatus\n\n\t\t\tcase svc.Stop, svc.Shutdown:\n\t\t\t\tforceCnt--\n\t\t\t\tif forceCnt > 0 {\n\t\t\t\t\tfmt.Printf(\" <SERVICE CMD: %v> but already shutting down - %d more to force\\n\", serviceCmdName(c.Cmd), forceCnt)\n\t\t\t\t} else {\n\t\t\t\t\tprintStackTo(log.GlobalWriter, \"PRINTING STACK ON FORCED EXIT\")\n\t\t\t\t\tos.Exit(1)\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tslog.Error(\"unexpected service control request\", \"cmd\", serviceCmdName(c.Cmd))\n\t\t\t}\n\t\t}\n\t}\n\n\t// Notify service manager.\n\tchanges <- svc.Status{State: svc.Stopped}\n\n\treturn false, 0\n}\n\nfunc (s *WindowsSystemService) IsService() bool {\n\tisService, err := svc.IsWindowsService()\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn isService\n}\n\nfunc (s *WindowsSystemService) RestartService() error {\n\t// Script that wait for portmaster service status to change to stop\n\t// and then sends a start command for the same service.\n\tcommand := `\n$serviceName = \"PortmasterCore\"\nwhile ((Get-Service -Name $serviceName).Status -ne 'Stopped') {\n    Start-Sleep -Seconds 1\n}\nsc.exe start $serviceName`\n\n\t// Create the command to execute the PowerShell script\n\tcmd := exec.Command(\"powershell.exe\", \"-Command\", command)\n\t// Start the command. The script will continue even after the parent process exits.\n\terr := cmd.Start()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc serviceCmdName(cmd svc.Cmd) string {\n\tswitch cmd {\n\tcase svc.Stop:\n\t\treturn \"Stop\"\n\tcase svc.Pause:\n\t\treturn \"Pause\"\n\tcase svc.Continue:\n\t\treturn \"Continue\"\n\tcase svc.Interrogate:\n\t\treturn \"Interrogate\"\n\tcase svc.Shutdown:\n\t\treturn \"Shutdown\"\n\tcase svc.ParamChange:\n\t\treturn \"ParamChange\"\n\tcase svc.NetBindAdd:\n\t\treturn \"NetBindAdd\"\n\tcase svc.NetBindRemove:\n\t\treturn \"NetBindRemove\"\n\tcase svc.NetBindEnable:\n\t\treturn \"NetBindEnable\"\n\tcase svc.NetBindDisable:\n\t\treturn \"NetBindDisable\"\n\tcase svc.DeviceEvent:\n\t\treturn \"DeviceEvent\"\n\tcase svc.HardwareProfileChange:\n\t\treturn \"HardwareProfileChange\"\n\tcase svc.PowerEvent:\n\t\treturn \"PowerEvent\"\n\tcase svc.SessionChange:\n\t\treturn \"SessionChange\"\n\tcase svc.PreShutdown:\n\t\treturn \"PreShutdown\"\n\tdefault:\n\t\treturn \"Unknown Command\"\n\t}\n}\n"
  },
  {
    "path": "cmds/cmdbase/update.go",
    "content": "package cmdbase\n\nimport (\n\t\"fmt\"\n\t\"log/slog\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nvar UpdateCmd = &cobra.Command{\n\tUse:   \"update\",\n\tShort: \"Force an update of all components.\",\n\tRunE:  update,\n}\n\nfunc update(cmd *cobra.Command, args []string) error {\n\t// Finalize config.\n\terr := SvcConfig.Init()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"internal configuration error: %w\", err)\n\t}\n\t// Force logging to stdout.\n\tSvcConfig.LogToStdout = true\n\n\t// Start logging.\n\t_ = log.Start(SvcConfig.LogLevel, SvcConfig.LogToStdout, SvcConfig.LogDir)\n\tdefer log.Shutdown()\n\n\t// Create updaters.\n\tinstance := &updateDummyInstance{}\n\tbinaryUpdateConfig, intelUpdateConfig, err := service.MakeUpdateConfigs(SvcConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"init updater config: %w\", err)\n\t}\n\tbinaryUpdates, err := updates.New(instance, \"Binary Updater\", *binaryUpdateConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"configure binary updates: %w\", err)\n\t}\n\tintelUpdates, err := updates.New(instance, \"Intel Updater\", *intelUpdateConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"configure intel updates: %w\", err)\n\t}\n\n\t// Force update all.\n\tbinErr := binaryUpdates.ForceUpdate()\n\tif binErr != nil {\n\t\tslog.Error(\"binary update failed\", \"err\", binErr)\n\t}\n\tintelErr := intelUpdates.ForceUpdate()\n\tif intelErr != nil {\n\t\tslog.Error(\"intel update failed\", \"err\", intelErr)\n\t}\n\n\t// Return error.\n\tif binErr != nil {\n\t\treturn fmt.Errorf(\"binary update failed: %w\", binErr)\n\t}\n\tif intelErr != nil {\n\t\treturn fmt.Errorf(\"intel update failed: %w\", intelErr)\n\t}\n\treturn nil\n}\n\ntype updateDummyInstance struct{}\n\nfunc (udi *updateDummyInstance) Restart()                                    {}\nfunc (udi *updateDummyInstance) Shutdown()                                   {}\nfunc (udi *updateDummyInstance) Notifications() *notifications.Notifications { return nil }\nfunc (udi *updateDummyInstance) UI() *ui.UI                                  { return nil }\n"
  },
  {
    "path": "cmds/cmdbase/version.go",
    "content": "package cmdbase\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/safing/portmaster/base/info\"\n)\n\nvar VersionCmd = &cobra.Command{\n\tUse:   \"version\",\n\tShort: \"Show version and related metadata.\",\n\tRunE:  Version,\n}\n\nfunc Version(cmd *cobra.Command, args []string) error {\n\tfmt.Println(info.FullVersion())\n\treturn nil\n}\n"
  },
  {
    "path": "cmds/integrationtest/main.go",
    "content": "package main\n\nimport (\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar rootCmd = &cobra.Command{\n\tUse:   \"integrationtest\",\n\tShort: \"A simple tool to test system integrations\",\n}\n\nfunc main() {\n\tif err := rootCmd.Execute(); err != nil {\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "cmds/integrationtest/netstate.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\tprocessInfo \"github.com/shirou/gopsutil/process\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n\t\"github.com/safing/portmaster/service/network/state\"\n)\n\nfunc init() {\n\trootCmd.AddCommand(netStateCmd)\n\tnetStateCmd.AddCommand(netStateMonitorCmd)\n}\n\nvar (\n\tnetStateCmd = &cobra.Command{\n\t\tUse:   \"netstate\",\n\t\tShort: \"Print current network state as received from the system\",\n\t\tRunE:  netState,\n\t}\n\tnetStateMonitorCmd = &cobra.Command{\n\t\tUse:   \"monitor\",\n\t\tShort: \"Monitor the network state and print any new connections\",\n\t\tRunE:  netStateMonitor,\n\t}\n\n\tseen = make(map[string]bool)\n)\n\nfunc netState(cmd *cobra.Command, args []string) error {\n\ttables := state.GetInfo()\n\n\tfor _, s := range tables.TCP4Connections {\n\t\tcheckAndPrintConnectionInfoIfNew(packet.IPv4, packet.TCP, s)\n\t}\n\tfor _, s := range tables.TCP4Listeners {\n\t\tcheckAndPrintBindInfoIfNew(packet.IPv4, packet.TCP, s)\n\t}\n\tfor _, s := range tables.TCP6Connections {\n\t\tcheckAndPrintConnectionInfoIfNew(packet.IPv6, packet.TCP, s)\n\t}\n\tfor _, s := range tables.TCP6Listeners {\n\t\tcheckAndPrintBindInfoIfNew(packet.IPv6, packet.TCP, s)\n\t}\n\tfor _, s := range tables.UDP4Binds {\n\t\tcheckAndPrintBindInfoIfNew(packet.IPv6, packet.UDP, s)\n\t}\n\tfor _, s := range tables.UDP6Binds {\n\t\tcheckAndPrintBindInfoIfNew(packet.IPv6, packet.UDP, s)\n\t}\n\treturn nil\n}\n\nfunc netStateMonitor(cmd *cobra.Command, args []string) error {\n\tfor {\n\t\terr := netState(cmd, args)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n}\n\nfunc checkAndPrintConnectionInfoIfNew(ipv packet.IPVersion, p packet.IPProtocol, s *socket.ConnectionInfo) {\n\t// Build connection string.\n\tc := fmt.Sprintf(\n\t\t\"%s %s %s:%d <-> %s:%d\",\n\t\tipv, p,\n\t\ts.Local.IP,\n\t\ts.Local.Port,\n\t\ts.Remote.IP,\n\t\ts.Remote.Port,\n\t)\n\n\tcheckAndPrintSocketInfoIfNew(c, s)\n}\n\nfunc checkAndPrintBindInfoIfNew(ipv packet.IPVersion, p packet.IPProtocol, s *socket.BindInfo) {\n\t// Build connection string.\n\tc := fmt.Sprintf(\n\t\t\"%s %s bind %s:%d\",\n\t\tipv, p,\n\t\ts.Local.IP,\n\t\ts.Local.Port,\n\t)\n\n\tcheckAndPrintSocketInfoIfNew(c, s)\n}\n\nfunc checkAndPrintSocketInfoIfNew(c string, s socket.Info) {\n\t// Return if connection was already seen.\n\tif _, ok := seen[c]; ok {\n\t\treturn\n\t}\n\t// Otherwise, add as seen.\n\tseen[c] = true\n\n\t// Check if we have the PID.\n\t_, _, err := state.CheckPID(s, false)\n\n\t// Print result.\n\tif err == nil {\n\n\t\tpInfo, err := processInfo.NewProcess(int32(s.GetPID()))\n\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"%s %d no binary: %s\\n\", c, s.GetPID(), err)\n\t\t} else {\n\t\t\texe, _ := pInfo.Exe()\n\t\t\tfmt.Printf(\"%s %d %s\\n\", c, s.GetPID(), exe)\n\t\t}\n\n\t} else {\n\t\tfmt.Printf(\"%s %d (err: %s)\\n\", c, s.GetPID(), err)\n\t}\n}\n"
  },
  {
    "path": "cmds/trafficgen/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst dnsResolver = \"1.1.1.1:53\"\n\nvar (\n\turl      string\n\tlookup   string\n\tn        int\n\twaitMsec int\n)\n\nfunc init() {\n\tflag.StringVar(&url, \"url\", \"\", \"send HTTP HEAD requests to this url\")\n\tflag.StringVar(&lookup, \"lookup\", \"\", fmt.Sprintf(\"query %s for this domains\", dnsResolver))\n\tflag.IntVar(&n, \"n\", 10, \"how many requests to make\")\n\tflag.IntVar(&waitMsec, \"w\", 100, \"how many ms to wait between requests\")\n}\n\nfunc main() {\n\t// Parse flags\n\tflag.Parse()\n\tif url == \"\" && lookup == \"\" {\n\t\tflag.Usage()\n\t\tos.Exit(1)\n\t}\n\n\t// Start logging.\n\terr := log.Start(\"trace\", true, \"\")\n\tif err != nil {\n\t\tfmt.Printf(\"failed to start logging: %s\\n\", err)\n\t\tos.Exit(1)\n\t}\n\tdefer log.Shutdown()\n\tlog.Info(\"starting traffic generator\")\n\n\t// Execute requests\n\twaitDuration := time.Duration(waitMsec) * time.Millisecond\n\tfor i := 1; i <= n; i++ {\n\t\tmakeHTTPRequest(i)\n\t\tlookupDomain(i)\n\t\ttime.Sleep(waitDuration)\n\t}\n}\n\nfunc makeHTTPRequest(i int) {\n\tif url == \"\" {\n\t\treturn\n\t}\n\n\t// Create a new client so that the connection won't be shared with other requests.\n\tclient := http.Client{\n\t\tCheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse },\n\t}\n\tstart := time.Now()\n\tresp, err := client.Head(url)\n\tif err != nil {\n\t\tlog.Errorf(\"http request #%d failed after %s: %s\", i, time.Since(start).Round(time.Millisecond), err)\n\t\treturn\n\t}\n\tdefer func() {\n\t\t_ = resp.Body.Close()\n\t}()\n\n\tlog.Infof(\"http response #%d after %s: %d\", i, time.Since(start).Round(time.Millisecond), resp.StatusCode)\n}\n\nfunc lookupDomain(i int) {\n\tif lookup == \"\" {\n\t\treturn\n\t}\n\n\t// Create DNS query.\n\tdnsQuery := new(dns.Msg)\n\tdnsQuery.SetQuestion(dns.Fqdn(lookup), dns.TypeA)\n\n\t// Send request.\n\tstart := time.Now()\n\treply, err := dns.Exchange(dnsQuery, dnsResolver)\n\tif err != nil {\n\t\tlog.Errorf(\"dns request #%d failed after %s: %s\", i, time.Since(start).Round(time.Millisecond), err)\n\t\treturn\n\t}\n\n\tlog.Infof(\"dns response #%d after %s: %s\", i, time.Since(start).Round(time.Millisecond), dns.RcodeToString[reply.Rcode])\n}\n"
  },
  {
    "path": "cmds/trafficgen/pack",
    "content": "#!/bin/bash\n\nbaseDir=\"$( cd \"$(dirname \"$0\")\" && pwd )\"\ncd \"$baseDir\"\n\necho \"building...\"\nGOOS=windows go build\n\ndstFile=\"../../../portmaster-windows-kext/install/MINGW/amd64/trafficgen.exe\"\nif [[ -d $(dirname \"$dstFile\") ]]; then\n  # make path absolute\n  dstFile=\"$(cd \"$(dirname \"$dstFile\")\" && pwd)/$(basename \"$dstFile\")\"\n  # copy\n  echo \"copying to $dstFile\"\n  cp trafficgen.exe \"$dstFile\"\nelse\n  echo \"not copying to $dstFile (dir does not exist)\"\nfi\n"
  },
  {
    "path": "cmds/winkext-test/main.go",
    "content": "//go:build windows\n// +build windows\n\npackage main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"syscall\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/firewall/interception/windowskext\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\nvar (\n\tpackets    chan packet.Packet\n\tshutdownCh = make(chan struct{})\n\n\tgetPayload      bool\n\trerouteDNS      bool\n\tpermanentAccept bool\n\tmaxPackets      int\n)\n\nfunc init() {\n\tflag.BoolVar(&getPayload, \"get-payload\", false, \"get payload of handled packets\")\n\tflag.BoolVar(&rerouteDNS, \"reroute-dns\", false, \"reroute dns to own IP\")\n\tflag.BoolVar(&permanentAccept, \"permanent-accept\", false, \"permanent-accept packets\")\n\tflag.IntVar(&maxPackets, \"max-packets\", 0, \"handle specified amount of packets, then exit\")\n}\n\nfunc main() {\n\tflag.Parse()\n\n\t// check parameter count\n\tif flag.NArg() != 2 {\n\t\tfmt.Printf(\"usage: %s [options] <dll> <sys>\\n\", os.Args[0])\n\t\tflag.Usage()\n\t\tos.Exit(1)\n\t}\n\n\t// logging\n\terr := log.Start(\"info\", true, \"\")\n\tif err != nil {\n\t\tfmt.Printf(\"failed to start logging: %s\\n\", err)\n\t\tos.Exit(1)\n\t}\n\tdefer log.Shutdown()\n\tlog.SetLogLevel(log.TraceLevel)\n\tlog.Info(\"starting windows kext test program\")\n\n\t// Check paths.\n\tdllPath, err := filepath.Abs(flag.Arg(0))\n\tif err == nil {\n\t\t_, err = os.Stat(dllPath)\n\t}\n\tif err != nil {\n\t\tlog.Criticalf(\"cannot find .dll: %s\\n\", err)\n\t\treturn\n\t}\n\tlog.Infof(\"using .dll at %s\", dllPath)\n\n\tsysPath, err := filepath.Abs(flag.Arg(1))\n\tif err == nil {\n\t\t_, err = os.Stat(sysPath)\n\t}\n\tif err != nil {\n\t\tlog.Criticalf(\"cannot find .sys: %s\", err)\n\t\treturn\n\t}\n\tlog.Infof(\"using .sys at %s\", sysPath)\n\n\t// init\n\terr = windowskext.Init(sysPath)\n\tif err != nil {\n\t\tlog.Criticalf(\"failed to init kext: %s\", err)\n\t\treturn\n\t}\n\n\t// start\n\terr = windowskext.Start()\n\tif err != nil {\n\t\tlog.Criticalf(\"failed to start kext: %s\", err)\n\t\treturn\n\t}\n\n\tpackets = make(chan packet.Packet, 1000)\n\tgo windowskext.Handler(context.TODO(), packets)\n\tgo handlePackets()\n\n\t// catch interrupt for clean shutdown\n\tsignalCh := make(chan os.Signal, 1)\n\tsignal.Notify(\n\t\tsignalCh,\n\t\tos.Interrupt,\n\t\tsyscall.SIGHUP,\n\t\tsyscall.SIGINT,\n\t\tsyscall.SIGTERM,\n\t\tsyscall.SIGQUIT,\n\t)\n\tselect {\n\tcase <-signalCh:\n\t\tfmt.Println(\" <INTERRUPT>\")\n\t\tlog.Warning(\"program was interrupted, shutting down\")\n\tcase <-shutdownCh:\n\t\tlog.Warningf(\"shutting down\")\n\t}\n\n\t// stop\n\terr = windowskext.Stop()\n\tif err != nil {\n\t\tlog.Criticalf(\"failed to stop kext: %s\", err)\n\t}\n\n\tlog.Info(\"shutdown complete\")\n}\n\nfunc handlePackets() {\n\tvar err error\n\tvar handledPackets int\n\n\tfor {\n\t\tpkt := <-packets\n\n\t\tif pkt == nil {\n\t\t\tlog.Infof(\"stopped handling packets\")\n\t\t\treturn\n\t\t}\n\n\t\tlog.Infof(\"received packet: %s\", pkt)\n\t\thandledPackets++\n\n\t\tif getPayload {\n\t\t\tdata := pkt.Payload()\n\t\t\tlog.Infof(\"payload is: %x\", data)\n\t\t}\n\n\t\t// reroute dns requests to nameserver\n\t\tif rerouteDNS {\n\t\t\tif pkt.IsOutbound() && !pkt.Info().Src.Equal(pkt.Info().Dst) && pkt.Info().DstPort == 53 {\n\t\t\t\tlog.Infof(\"rerouting %s\", pkt)\n\t\t\t\terr = pkt.RerouteToNameserver()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(\"failed to reroute: %s\", err)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// accept all\n\t\tlog.Infof(\"accepting %s\", pkt)\n\t\tif permanentAccept {\n\t\t\terr = pkt.PermanentAccept()\n\t\t} else {\n\t\t\terr = pkt.Accept()\n\t\t}\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"failed to accept: %s\", err)\n\t\t}\n\n\t\tif maxPackets > 0 && handledPackets > maxPackets {\n\t\t\tlog.Infof(\"max-packets (%d) reached\", maxPackets)\n\t\t\tclose(shutdownCh)\n\t\t\treturn\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "cmds/winkext-test/main_linux.go",
    "content": "//go:build linux\n// +build linux\n\npackage main\n\nimport \"log\"\n\nfunc main() {\n\tlog.Fatalf(\"winkext-test not supported on linux\")\n}\n"
  },
  {
    "path": "cmds/winkext-test/pack",
    "content": "#!/bin/bash\n\nbaseDir=\"$( cd \"$(dirname \"$0\")\" && pwd )\"\ncd \"$baseDir\"\n\necho \"building...\"\nGOOS=windows go build\n\ndstFile=\"../../../portmaster-windows-kext/install/MINGW/amd64/winkext-test.exe\"\nif [[ -d $(dirname \"$dstFile\") ]]; then\n  # make path absolute\n  dstFile=\"$(cd \"$(dirname \"$dstFile\")\" && pwd)/$(basename \"$dstFile\")\"\n  # copy\n  echo \"copying to $dstFile\"\n  cp winkext-test.exe \"$dstFile\"\nelse\n  echo \"not copying to $dstFile (dir does not exist)\"\nfi\n"
  },
  {
    "path": "desktop/angular/.eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"ignorePatterns\": [\n    \"projects/**/*\"\n  ],\n  \"parserOptions\": {\n    \"tsconfigRootDir\": \"desktop/angular\"\n  },\n  \"overrides\": [\n    {\n      \"files\": [\n        \"*.ts\"\n      ],\n      \"extends\": [\n        \"eslint:recommended\",\n        \"plugin:@typescript-eslint/recommended\",\n        \"plugin:@angular-eslint/recommended\",\n        \"plugin:@angular-eslint/template/process-inline-templates\"\n      ],\n      \"rules\": {\n        \"@angular-eslint/directive-selector\": [\n          \"error\",\n          {\n            \"type\": \"attribute\",\n            \"prefix\": \"app\",\n            \"style\": \"camelCase\"\n          }\n        ],\n        \"@angular-eslint/component-selector\": [\n          \"error\",\n          {\n            \"type\": \"element\",\n            \"prefix\": \"app\",\n            \"style\": \"kebab-case\"\n          }\n        ],\n        \"@typescript-eslint/no-explicit-any\": \"off\"\n      }\n    },\n    {\n      \"files\": [\n        \"*.html\"\n      ],\n      \"extends\": [\n        \"plugin:@angular-eslint/template/recommended\",\n        \"plugin:@angular-eslint/template/accessibility\"\n      ],\n      \"rules\": {\n        \"@angular-eslint/template/click-events-have-key-events\": \"off\",\n        \"@angular-eslint/template/interactive-supports-focus\": \"off\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/.gitignore",
    "content": "node_modules\ndist\ndist-extension\ndist-lib\n.angular"
  },
  {
    "path": "desktop/angular/.vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Run UI in Chrome (npm run start)\",\n            \"type\": \"chrome\",\n            \"request\": \"launch\",\n            \"preLaunchTask\": \"debugproj\",\n            \"postDebugTask\": \"killnode\",\n            \"url\": \"http://localhost:4200/\",\n            \"webRoot\": \"${workspaceFolder}\",\n            \"sourceMapPathOverrides\": {\n              \"webpack:/*\": \"${webRoot}/*\",\n              \"/./*\": \"${webRoot}/*\",\n              \"/src/*\": \"${webRoot}/*\",\n              \"/*\": \"*\",\n              \"/./~/*\": \"${webRoot}/node_modules/*\"\n            }\n        },\n\n    ]\n}"
  },
  {
    "path": "desktop/angular/.vscode/tasks.json",
    "content": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"ui-library-watch\",\n            \"type\": \"npm\",\n            \"script\": \"build-ui:dev:watch\",\n            \"isBackground\": true,\n            \"presentation\": {\n                \"echo\": true,\n                \"reveal\": \"always\",\n                \"focus\": false,\n                \"panel\": \"dedicated\",\n                \"group\": \"dev-libraries\"\n            },\n            \"group\": {\n                \"kind\": \"build\"\n            },\n            \"problemMatcher\": {\n                \"owner\": \"typescript\",\n                \"source\": \"ts\",\n                \"fileLocation\": [\"relative\", \"${workspaceFolder}\"],\n                \"pattern\": \"$tsc\",\n                \"background\": {\n                    \"activeOnStart\": true,\n                    \"beginsPattern\": \"Building Angular Package\",\n                    \"endsPattern\": \"Compilation complete\\\\. Watching for file changes\\\\.\\\\.\\\\.\"\n                }\n            }\n        },\n        {\n            \"label\": \"api-library-watch\",\n            \"type\": \"npm\",\n            \"script\": \"build-api:dev:watch\",\n            \"isBackground\": true,\n            \"presentation\": {\n                \"echo\": true,\n                \"reveal\": \"always\",\n                \"focus\": false,\n                \"panel\": \"dedicated\",\n                \"group\": \"dev-libraries\"\n            },\n            \"group\": {\n                \"kind\": \"build\"\n            },\n            \"problemMatcher\": {\n                \"owner\": \"typescript\",\n                \"source\": \"ts\",\n                \"fileLocation\": [\"relative\", \"${workspaceFolder}\"],\n                \"pattern\": \"$tsc\",\n                \"background\": {\n                    \"activeOnStart\": true,\n                    \"beginsPattern\": \"Building Angular Package\",\n                    \"endsPattern\": \"Compilation complete\\\\. Watching for file changes\\\\.\\\\.\\\\.\"\n                }\n            }\n        },\n        {\n            \"label\": \"build-libs-first\",\n            \"type\": \"npm\",\n            \"script\": \"build-libs:dev\",\n            \"isBackground\": false,\n            \"presentation\": {\n                \"echo\": true,\n                \"reveal\": \"always\",\n                \"focus\": false,\n                \"panel\": \"shared\"\n            },\n            \"group\": {\n                \"kind\": \"build\"\n            },\n            \"problemMatcher\": []\n        },\n        {\n            \"label\": \"debugproj\",\n            \"dependsOrder\": \"sequence\",\n            \"dependsOn\": [\n                \"build-libs-first\",\n                \"ui-library-watch\",\n                \"api-library-watch\",\n                \"main-app-with-polling\"\n            ],\n            \"isBackground\": true,\n            \"presentation\": {\n                \"echo\": false,\n                \"reveal\": \"never\",\n                \"focus\": false,\n                \"panel\": \"shared\"\n            },\n            \"group\": {\n                \"kind\": \"build\",\n                \"isDefault\": true\n            },\n            \"problemMatcher\": []\n        },\n        {\n            \"label\": \"main-app-with-polling\",\n            \"type\": \"npm\",\n            \"script\": \"serve-with-lib-watch\",\n            \"isBackground\": true,\n            \"presentation\": {\n                \"echo\": true,\n                \"reveal\": \"always\",\n                \"focus\": true,\n                \"panel\": \"dedicated\",\n                \"group\": \"dev-main\"\n            },\n            \"group\": {\n                \"kind\": \"build\"\n            },\n            \"problemMatcher\": {\n                \"owner\": \"typescript\",\n                \"source\": \"ts\",\n                \"applyTo\": \"closedDocuments\",\n                \"fileLocation\": [\"relative\", \"${workspaceFolder}\"],\n                \"pattern\": \"$tsc\",\n                \"background\": {\n                    \"activeOnStart\": true,\n                    \"beginsPattern\": \"Generating browser application bundles\",\n                    \"endsPattern\": \"Compiled successfully\\\\.|Failed to compile\\\\.\"\n                }\n            }\n        },\n        {\n            \"label\": \"killnode\",\n            \"type\": \"process\",\n            \"windows\": {\n                \"command\": \"taskkill\",\n                \"args\": [\"/F\", \"/IM\", \"node.exe\"]\n            },\n            \"osx\":{\n                \"command\": \"killall\",\n                \"args\": [\"node\"]\n            },\n            \"linux\":{\n                \"command\": \"killall\",\n                \"args\": [\"node\"]\n            },\n            \"presentation\": {\n                \"echo\": true,\n                \"reveal\": \"always\",\n                \"focus\": false,\n                \"panel\": \"shared\"\n            },\n            \"group\": {\n                \"kind\": \"build\"\n            },\n            \"isBackground\": false,\n            \"problemMatcher\": []\n        }\n    ]\n}"
  },
  {
    "path": "desktop/angular/README.md",
    "content": "# Portmaster\n\nWelcome to the new Portmaster User-Interface. It's based on Angular and is built, unit and e2e tested using `@angular/cli`.\n\n## Running locally\n\nThis section explains how to prepare your Ubuntu machine to build and test the new Portmaster User-Interface. It's recommended to use\na virtual machine but running it on bare metal will work as well. You can use the new Portmaster UI as well as the old one in parallel so\nyou can simply switch back when something is still missing or buggy.\n\n1. **Prepare your tooling**\n\nThere's a simple dockerized way to build and test the new UI. Just make sure to have docker installed:\n\n```bash\nsudo apt update\nsudo apt install -y docker.io git\nsudo systemctl enable --now docker\nsudo gpasswd -a $USER docker\n```\n\n2. **Portmaster installation**\n\nNext, make sure to install the Portmaster using the official .deb installer from [here](https://updates.safing.io/latest/linux_amd64/packages/portmaster-installer.deb). See the [Wiki](https://github.com/safing/portmaster/wiki/Linux) for more information.\n\nOnce the Portmaster is installed we need to add two new configuration flags. Execute the following:\n\n```bash\necho 'PORTMASTER_ARGS=\"--experimental-nfqueue --devmode\"' | sudo tee /etc/default/portmaster\nsudo systemctl daemon-reload\nsudo systemctl restart portmaster\n```\n\n3. **Build and run the new UI**\n\nNow, clone this repository and execute the `docker.sh` script:\n\n```bash\n# Clone the repository\ngit clone https://github.com/safing/portmaster-ui\n\n# Enter the repo and checkout the correct branch\ncd portmaster-ui\ngit checkout feature/new-ui\n\n# Enter the directory and run docker.sh\ncd modules/portmaster\nsudo bash ./docker.sh\n```\n\nFinally open your browser and point it to http://localhost:8080.\n\n## Hacking Quick Start\n\nAlthough everything should work in the docker container as well, for the best development experience it's recommended to install `@angular/cli` locally.\n\nIt's highly recommended to:\n- Use [VSCode](https://code.visualstudio.com/) (or it's oss or server-side variant) with\n  - the official [Angular Language Service](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template) extension\n  - the [Tailwind CSS Extension Pack](https://marketplace.visualstudio.com/items?itemName=andrewmcodes.tailwindcss-extension-pack) extension\n  - the [formate: CSS/LESS/SCSS formatter](https://github.com/mblander/formate) extension\n\n### Folder Structure\n\nFrom the project root (the folder containing this [README.md](./)) there are only two folders with the following content and structure:\n\n- **`src/`** contains the actual application sources:\n  - **`app/`** contains the actual application sources (components, services, uni tests ...)\n    - **`layout/`** contains components that form the overall application layout. For example the navigation bar and the side dash are located there.\n    - **`pages/`** contains the different pages of the application. A page is something that is associated with a dedicated application route and is rendered at the applications main content.\n    - **`services/`** contains shared services (like PortAPI and friends)\n    - **`shared/`** contains shared components that are likely used accross other components or pages.\n    - **`widgets/`** contains widgets and their settings components for the application side dash.\n    - **`debug/`** contains a debug sidebar component\n  - **`assets/`** contains static assets that must be shipped seperately.\n  - **`environments/`** contains build and production related environment settings (those are handled by `@angular/cli` automatically, see [angular.json](angular.json))\n- **`e2e/`** contains end-to-end testing sources.\n\n\n### Development server\n\nRun `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.\n\nIn development mode (that is, you don't pass `--prod`) the UI expects portmaster running at `ws://127.0.0.1:817/api/database/v1`. See [environment](./src/app/environments/environment.ts).\n\n### Code scaffolding\n\nRun `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.\n\n### Build\n\nRun `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.\n\n### Running unit tests\n\nRun `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).\n\n### Running end-to-end tests\n\nRun `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).\n\n### Further help\n\nTo get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).\n"
  },
  {
    "path": "desktop/angular/angular.json",
    "content": "{\n  \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n  \"version\": 1,\n  \"newProjectRoot\": \"projects\",\n  \"projects\": {\n    \"portmaster\": {\n      \"projectType\": \"application\",\n      \"schematics\": {\n        \"@schematics/angular:component\": {\n          \"style\": \"scss\"\n        },\n        \"@schematics/angular:application\": {\n          \"strict\": true\n        }\n      },\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"prefix\": \"app\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:browser\",\n          \"options\": {\n            \"outputPath\": \"dist\",\n            \"index\": \"src/index.html\",\n            \"main\": \"src/main.ts\",\n            \"polyfills\": \"src/polyfills.ts\",\n            \"tsConfig\": \"tsconfig.app.json\",\n            \"aot\": true,\n            \"assets\": [\n              \"src/favicon.ico\",\n              \"src/assets\"\n            ],\n            \"styles\": [\n              \"src/theme.less\",\n              \"src/styles.scss\",\n              \"node_modules/prismjs/themes/prism-okaidia.css\",\n              \"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css\"\n            ],\n            \"stylePreprocessorOptions\": {\n              \"includePaths\": [\n                \"dist-lib/\"\n              ]\n            },\n            \"scripts\": [\n              \"node_modules/marked/marked.min.js\",\n              \"node_modules/emoji-toolkit/lib/js/joypixels.min.js\",\n              \"node_modules/prismjs/prism.js\",\n              \"node_modules/prismjs/components/prism-yaml.min.js\",\n              \"node_modules/prismjs/components/prism-json.min.js\",\n              \"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js\"\n            ],\n            \"vendorChunk\": true,\n            \"extractLicenses\": false,\n            \"buildOptimizer\": false,\n            \"sourceMap\": true,\n            \"optimization\": false,\n            \"namedChunks\": true\n          },\n          \"configurations\": {\n            \"development\": {},\n            \"production\": {\n              \"fileReplacements\": [\n                {\n                  \"replace\": \"src/environments/environment.ts\",\n                  \"with\": \"src/environments/environment.prod.ts\"\n                }\n              ],\n              \"optimization\": {\n                \"scripts\": true,\n                \"styles\": {\n                  \"minify\": true,\n                  \"inlineCritical\": false\n                }\n              },\n              \"outputHashing\": \"all\",\n              \"sourceMap\": false,\n              \"namedChunks\": false,\n              \"extractLicenses\": true,\n              \"vendorChunk\": true,\n              \"buildOptimizer\": true,\n              \"budgets\": [\n                {\n                  \"type\": \"initial\",\n                  \"maximumWarning\": \"4mb\",\n                  \"maximumError\": \"16mb\"\n                },\n                {\n                  \"type\": \"anyComponentStyle\",\n                  \"maximumWarning\": \"4mb\",\n                  \"maximumError\": \"16mb\"\n                }\n              ]\n            }\n          }\n        },\n        \"serve\": {\n          \"builder\": \"@angular-devkit/build-angular:dev-server\",\n          \"options\": {\n            \"browserTarget\": \"portmaster:build\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"browserTarget\": \"portmaster:build:production\"\n            }\n          }\n        },\n        \"extract-i18n\": {\n          \"builder\": \"@angular-devkit/build-angular:extract-i18n\",\n          \"options\": {\n            \"browserTarget\": \"portmaster:build\"\n          }\n        },\n        \"test\": {\n          \"builder\": \"@angular-devkit/build-angular:karma\",\n          \"options\": {\n            \"main\": \"src/test.ts\",\n            \"polyfills\": \"src/polyfills.ts\",\n            \"tsConfig\": \"tsconfig.spec.json\",\n            \"karmaConfig\": \"karma.conf.js\",\n            \"assets\": [\n              \"src/favicon.ico\",\n              \"src/assets\"\n            ],\n            \"styles\": [\n              \"src/styles.scss\"\n            ],\n            \"scripts\": []\n          }\n        },\n        \"e2e\": {\n          \"builder\": \"@angular-devkit/build-angular:protractor\",\n          \"options\": {\n            \"protractorConfig\": \"e2e/protractor.conf.js\",\n            \"devServerTarget\": \"portmaster:serve\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"devServerTarget\": \"portmaster:serve:production\"\n            }\n          }\n        },\n        \"lint\": {\n          \"builder\": \"@angular-eslint/builder:lint\",\n          \"options\": {\n            \"lintFilePatterns\": [\n              \"src/**/*.ts\",\n              \"src/**/*.html\"\n            ]\n          }\n        }\n      }\n    },\n    \"@safing/ui\": {\n      \"projectType\": \"library\",\n      \"root\": \"projects/safing/ui\",\n      \"sourceRoot\": \"projects/safing/ui/src\",\n      \"prefix\": \"lib\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:ng-packagr\",\n          \"options\": {\n            \"project\": \"projects/safing/ui/ng-package.json\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"tsConfig\": \"projects/safing/ui/tsconfig.lib.prod.json\"\n            },\n            \"development\": {\n              \"tsConfig\": \"projects/safing/ui/tsconfig.lib.json\"\n            }\n          },\n          \"defaultConfiguration\": \"production\"\n        },\n        \"test\": {\n          \"builder\": \"@angular-devkit/build-angular:karma\",\n          \"options\": {\n            \"main\": \"projects/safing/ui/src/test.ts\",\n            \"tsConfig\": \"projects/safing/ui/tsconfig.spec.json\",\n            \"karmaConfig\": \"projects/safing/ui/karma.conf.js\"\n          }\n        },\n        \"lint\": {\n          \"builder\": \"@angular-eslint/builder:lint\",\n          \"options\": {\n            \"lintFilePatterns\": [\n              \"projects/safing/ui/**/*.ts\",\n              \"projects/safing/ui/**/*.html\"\n            ]\n          }\n        }\n      }\n    },\n    \"portmaster-chrome-extension\": {\n      \"projectType\": \"application\",\n      \"schematics\": {\n        \"@schematics/angular:component\": {\n          \"style\": \"scss\"\n        }\n      },\n      \"root\": \"projects/portmaster-chrome-extension\",\n      \"sourceRoot\": \"projects/portmaster-chrome-extension/src\",\n      \"prefix\": \"app\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-builders/custom-webpack:browser\",\n          \"options\": {\n            \"customWebpackConfig\": {\n              \"path\": \"./browser-extension.config.ts\"\n            },\n            \"outputPath\": \"dist-extension\",\n            \"index\": \"projects/portmaster-chrome-extension/src/index.html\",\n            \"main\": \"projects/portmaster-chrome-extension/src/main.ts\",\n            \"polyfills\": \"projects/portmaster-chrome-extension/src/polyfills.ts\",\n            \"tsConfig\": \"projects/portmaster-chrome-extension/tsconfig.app.json\",\n            \"inlineStyleLanguage\": \"scss\",\n            \"assets\": [\n              \"projects/portmaster-chrome-extension/src/favicon.ico\",\n              \"projects/portmaster-chrome-extension/src/assets\",\n              \"projects/portmaster-chrome-extension/src/manifest.json\"\n            ],\n            \"styles\": [\n              \"projects/portmaster-chrome-extension/src/styles.scss\"\n            ],\n            \"scripts\": [],\n            \"optimization\": {\n              \"styles\": {\n                \"inlineCritical\": false\n              }\n            },\n            \"outputHashing\": \"none\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"budgets\": [\n                {\n                  \"type\": \"initial\",\n                  \"maximumWarning\": \"500kb\",\n                  \"maximumError\": \"1mb\"\n                },\n                {\n                  \"type\": \"anyComponentStyle\",\n                  \"maximumWarning\": \"2kb\",\n                  \"maximumError\": \"4kb\"\n                }\n              ],\n              \"fileReplacements\": [\n                {\n                  \"replace\": \"projects/portmaster-chrome-extension/src/environments/environment.ts\",\n                  \"with\": \"projects/portmaster-chrome-extension/src/environments/environment.prod.ts\"\n                }\n              ],\n              \"outputHashing\": \"none\"\n            },\n            \"development\": {\n              \"customWebpackConfig\": {\n                \"path\": \"./browser-extension-dev.config.ts\"\n              },\n              \"buildOptimizer\": false,\n              \"optimization\": false,\n              \"vendorChunk\": true,\n              \"extractLicenses\": false,\n              \"sourceMap\": true,\n              \"namedChunks\": true\n            }\n          },\n          \"defaultConfiguration\": \"production\"\n        },\n        \"serve\": {\n          \"builder\": \"@angular-devkit/build-angular:dev-server\",\n          \"configurations\": {\n            \"production\": {\n              \"browserTarget\": \"portmaster-chrome-extension:build:production\"\n            },\n            \"development\": {\n              \"browserTarget\": \"portmaster-chrome-extension:build:development\"\n            }\n          },\n          \"defaultConfiguration\": \"development\"\n        },\n        \"extract-i18n\": {\n          \"builder\": \"@angular-devkit/build-angular:extract-i18n\",\n          \"options\": {\n            \"browserTarget\": \"portmaster-chrome-extension:build\"\n          }\n        },\n        \"test\": {\n          \"builder\": \"@angular-devkit/build-angular:karma\",\n          \"options\": {\n            \"main\": \"projects/portmaster-chrome-extension/src/test.ts\",\n            \"polyfills\": \"projects/portmaster-chrome-extension/src/polyfills.ts\",\n            \"tsConfig\": \"projects/portmaster-chrome-extension/tsconfig.spec.json\",\n            \"karmaConfig\": \"projects/portmaster-chrome-extension/karma.conf.js\",\n            \"inlineStyleLanguage\": \"scss\",\n            \"assets\": [\n              \"projects/portmaster-chrome-extension/src/favicon.ico\",\n              \"projects/portmaster-chrome-extension/src/assets\"\n            ],\n            \"styles\": [\n              \"projects/portmaster-chrome-extension/src/styles.scss\"\n            ],\n            \"scripts\": []\n          }\n        }\n      }\n    },\n    \"@safing/portmaster-api\": {\n      \"projectType\": \"library\",\n      \"root\": \"projects/safing/portmaster-api\",\n      \"sourceRoot\": \"projects/safing/portmaster-api/src\",\n      \"prefix\": \"lib\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:ng-packagr\",\n          \"options\": {\n            \"project\": \"projects/safing/portmaster-api/ng-package.json\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"tsConfig\": \"projects/safing/portmaster-api/tsconfig.lib.prod.json\"\n            },\n            \"development\": {\n              \"tsConfig\": \"projects/safing/portmaster-api/tsconfig.lib.json\"\n            }\n          },\n          \"defaultConfiguration\": \"production\"\n        },\n        \"test\": {\n          \"builder\": \"@angular-devkit/build-angular:karma\",\n          \"options\": {\n            \"main\": \"projects/safing/portmaster-api/src/test.ts\",\n            \"tsConfig\": \"projects/safing/portmaster-api/tsconfig.spec.json\",\n            \"karmaConfig\": \"projects/safing/portmaster-api/karma.conf.js\"\n          }\n        }\n      }\n    },\n    \"tauri-builtin\": {\n      \"projectType\": \"application\",\n      \"schematics\": {\n        \"@schematics/angular:component\": {\n          \"skipTests\": true,\n          \"style\": \"scss\",\n          \"standalone\": true\n        },\n        \"@schematics/angular:class\": {\n          \"skipTests\": true\n        },\n        \"@schematics/angular:directive\": {\n          \"skipTests\": true,\n          \"standalone\": true\n        },\n        \"@schematics/angular:guard\": {\n          \"skipTests\": true\n        },\n        \"@schematics/angular:interceptor\": {\n          \"skipTests\": true\n        },\n        \"@schematics/angular:pipe\": {\n          \"skipTests\": true,\n          \"standalone\": true\n        },\n        \"@schematics/angular:resolver\": {\n          \"skipTests\": true\n        },\n        \"@schematics/angular:service\": {\n          \"skipTests\": true\n        }\n      },\n      \"root\": \"projects/tauri-builtin\",\n      \"sourceRoot\": \"projects/tauri-builtin/src\",\n      \"prefix\": \"app\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:browser\",\n          \"options\": {\n            \"outputPath\": \"dist/tauri-builtin\",\n            \"index\": \"projects/tauri-builtin/src/index.html\",\n            \"main\": \"projects/tauri-builtin/src/main.ts\",\n            \"polyfills\": [\n              \"zone.js\"\n            ],\n            \"tsConfig\": \"projects/tauri-builtin/tsconfig.app.json\",\n            \"assets\": [\n              \"projects/tauri-builtin/src/favicon.ico\",\n              \"projects/tauri-builtin/src/assets\"\n            ],\n            \"styles\": [\n              \"projects/tauri-builtin/src/styles.scss\"\n            ],\n            \"inlineStyleLanguage\": \"scss\",\n            \"stylePreprocessorOptions\": {\n              \"includePaths\": [\n                \"dist-lib/\"\n              ]\n            },\n            \"scripts\": []\n          },\n          \"configurations\": {\n            \"production\": {\n              \"budgets\": [\n                {\n                  \"type\": \"initial\",\n                  \"maximumWarning\": \"500kb\",\n                  \"maximumError\": \"1mb\"\n                },\n                {\n                  \"type\": \"anyComponentStyle\",\n                  \"maximumWarning\": \"2kb\",\n                  \"maximumError\": \"4kb\"\n                }\n              ],\n              \"outputHashing\": \"all\"\n            },\n            \"development\": {\n              \"buildOptimizer\": false,\n              \"optimization\": false,\n              \"vendorChunk\": true,\n              \"extractLicenses\": false,\n              \"sourceMap\": true,\n              \"namedChunks\": true\n            }\n          },\n          \"defaultConfiguration\": \"production\"\n        },\n        \"serve\": {\n          \"builder\": \"@angular-devkit/build-angular:dev-server\",\n          \"configurations\": {\n            \"production\": {\n              \"browserTarget\": \"tauri-builtin:build:production\"\n            },\n            \"development\": {\n              \"browserTarget\": \"tauri-builtin:build:development\"\n            }\n          },\n          \"defaultConfiguration\": \"development\"\n        },\n        \"extract-i18n\": {\n          \"builder\": \"@angular-devkit/build-angular:extract-i18n\",\n          \"options\": {\n            \"browserTarget\": \"tauri-builtin:build\"\n          }\n        }\n      }\n    }\n  },\n  \"cli\": {\n    \"analytics\": false\n  },\n  \"schematics\": {\n    \"@angular-eslint/schematics:application\": {\n      \"setParserOptionsProject\": true\n    },\n    \"@angular-eslint/schematics:library\": {\n      \"setParserOptionsProject\": true\n    }\n  }\n}"
  },
  {
    "path": "desktop/angular/browser-extension-dev.config.ts",
    "content": "import type { Configuration } from 'webpack';\nconst ExtensionReloader = require('webpack-ext-reloader');\nconst config = require('./browser-extension.config');\n\nmodule.exports = {\n  ...config,\n  mode: 'development',\n  plugins: [\n    new ExtensionReloader({\n      reloadPage: true, // Force the reload of the page also\n      entries: { // The entries used for the content/background scripts or extension pages\n        background: 'background',\n      }\n    })\n  ]\n} as Configuration;\n"
  },
  {
    "path": "desktop/angular/browser-extension.config.ts",
    "content": "import type { Configuration } from 'webpack';\n\nmodule.exports = {\n  entry: { background: { import: 'projects/portmaster-chrome-extension/src/background.ts', runtime: false } },\n} as Configuration;\n"
  },
  {
    "path": "desktop/angular/docker.sh",
    "content": "#!/bin/bash\n\n# cd to script dir\nbaseDir=\"$( cd \"$(dirname \"$0\")\" && pwd )\"\ncd \"$baseDir\"\n\n# get base dir for mounting\nmnt=\"$( cd ../.. && pwd )\"\n\n# run container and start dev server\ndocker run                                \\\n    -ti                                   \\\n    --rm                                  \\\n    -v $mnt:/portmaster                   \\\n    -w /portmaster/desktop/angular        \\\n    -p 8081:8080                          \\\n    node:latest                           \\\n    npm start -- --host 0.0.0.0 --port 8080\n"
  },
  {
    "path": "desktop/angular/e2e/protractor.conf.js",
    "content": "// @ts-check\n// Protractor configuration file, see link for more information\n// https://github.com/angular/protractor/blob/master/lib/config.ts\n\nconst { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');\n\n/**\n * @type { import(\"protractor\").Config }\n */\nexports.config = {\n  allScriptsTimeout: 11000,\n  specs: [\n    './src/**/*.e2e-spec.ts'\n  ],\n  capabilities: {\n    browserName: 'chrome'\n  },\n  directConnect: true,\n  baseUrl: 'http://localhost:4200/',\n  framework: 'jasmine',\n  jasmineNodeOpts: {\n    showColors: true,\n    defaultTimeoutInterval: 30000,\n    print: function() {}\n  },\n  onPrepare() {\n    require('ts-node').register({\n      project: require('path').join(__dirname, './tsconfig.json')\n    });\n    jasmine.getEnv().addReporter(new SpecReporter({\n      spec: {\n        displayStacktrace: StacktraceOption.PRETTY\n      }\n    }));\n  }\n};"
  },
  {
    "path": "desktop/angular/e2e/src/app.e2e-spec.ts",
    "content": "import { AppPage } from './app.po';\nimport { browser, logging } from 'protractor';\n\ndescribe('workspace-project App', () => {\n  let page: AppPage;\n\n  beforeEach(() => {\n    page = new AppPage();\n  });\n\n  it('should display welcome message', () => {\n    page.navigateTo();\n    expect(page.getTitleText()).toEqual('portmaster app is running!');\n  });\n\n  afterEach(async () => {\n    // Assert that there are no errors emitted from the browser\n    const logs = await browser.manage().logs().get(logging.Type.BROWSER);\n    expect(logs).not.toContain(jasmine.objectContaining({\n      level: logging.Level.SEVERE,\n    } as logging.Entry));\n  });\n});\n"
  },
  {
    "path": "desktop/angular/e2e/src/app.po.ts",
    "content": "import { browser, by, element } from 'protractor';\n\nexport class AppPage {\n  navigateTo(): Promise<unknown> {\n    return browser.get(browser.baseUrl) as Promise<unknown>;\n  }\n\n  getTitleText(): Promise<string> {\n    return element(by.css('app-root .content span')).getText() as Promise<string>;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/e2e/tsconfig.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../out-tsc/e2e\",\n    \"module\": \"commonjs\",\n    \"target\": \"es2018\",\n    \"types\": [\n      \"jasmine\",\n      \"jasminewd2\",\n      \"node\"\n    ]\n  }\n}\n"
  },
  {
    "path": "desktop/angular/karma.conf.js",
    "content": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/1.0/config/configuration-file.html\n\nmodule.exports = function (config) {\n  config.set({\n    basePath: '',\n    frameworks: ['jasmine', '@angular-devkit/build-angular'],\n    plugins: [\n      require('karma-jasmine'),\n      require('karma-chrome-launcher'),\n      require('karma-jasmine-html-reporter'),\n      require('karma-coverage-istanbul-reporter'),\n      require('@angular-devkit/build-angular/plugins/karma')\n    ],\n    client: {\n      clearContext: false // leave Jasmine Spec Runner output visible in browser\n    },\n    coverageIstanbulReporter: {\n      dir: require('path').join(__dirname, './coverage/portmaster'),\n      reports: ['html', 'lcovonly', 'text-summary'],\n      fixWebpackSourcePaths: true\n    },\n    reporters: ['progress', 'kjhtml'],\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    browsers: ['Chrome'],\n    singleRun: false,\n    restartOnFileChange: true\n  });\n};\n"
  },
  {
    "path": "desktop/angular/package.json",
    "content": "{\n  \"name\": \"portmaster\",\n  \"version\": \"2.1.8\",\n  \"scripts\": {\n    \"ng\": \"ng\",\n    \"start\": \"npm install && npm run build-libs:dev && ng serve --proxy-config ./proxy.json\",\n    \"build-libs\": \"cross-env NODE_ENV=production ng build --configuration production @safing/ui && cross-env NODE_ENV=production ng build --configuration production @safing/portmaster-api\",\n    \"build-libs:dev\": \"ng build --configuration development @safing/ui && ng build --configuration development @safing/portmaster-api\",\n\n    \"build-ui:dev:watch\": \"ng build --configuration development @safing/ui --watch\",\n    \"build-api:dev:watch\": \"ng build --configuration development @safing/portmaster-api --watch\",\n    \"serve-with-lib-watch\": \"ng serve --proxy-config ./proxy.json --poll=2000\",\n\n    \"serve\": \"npm run build-libs:dev && ng serve --proxy-config ./proxy.json\",\n    \"build:dev\": \"npm run build-libs:dev && ng build\",\n    \"test\": \"ng test\",\n    \"lint\": \"ng lint\",\n    \"e2e\": \"ng e2e\",\n    \"zip-dist\": \"node pack.js\",\n    \"chrome-extension\": \"cross-env NODE_ENV=production ng build --configuration production portmaster-chrome-extension\",\n    \"chrome-extension:dev\": \"ng build --configuration development portmaster-chrome-extension --watch\",\n    \"build\": \"npm run build-libs && NODE_ENV=production ng build --configuration production --base-href /ui/modules/portmaster/\",\n    \"build-tauri\": \"npm run build-libs && cross-env NODE_ENV=production ng build --configuration production tauri-builtin\",\n    \"serve-tauri-builtin\": \"ng serve tauri-builtin --port 4100\",\n    \"serve-app\": \"ng serve --port 4200 --proxy-config ./proxy.json\",\n    \"tauri-dev\": \"npm install && run-s build-libs:dev && run-p serve-app serve-tauri-builtin\"\n  },\n  \"private\": true,\n  \"dependencies\": {\n    \"@angular/animations\": \"^16.0.1\",\n    \"@angular/cdk\": \"^16.0.1\",\n    \"@angular/common\": \"^16.0.1\",\n    \"@angular/compiler\": \"^16.0.1\",\n    \"@angular/core\": \"^16.0.1\",\n    \"@angular/forms\": \"^16.0.1\",\n    \"@angular/localize\": \"^16.0.1\",\n    \"@angular/platform-browser\": \"^16.0.1\",\n    \"@angular/platform-browser-dynamic\": \"^16.0.1\",\n    \"@angular/router\": \"^16.0.1\",\n    \"@ctrl/tinycolor\": \"^4.1.0\",\n    \"@fortawesome/angular-fontawesome\": \"^0.13.0\",\n    \"@fortawesome/fontawesome-svg-core\": \"^6.4.0\",\n    \"@fortawesome/free-brands-svg-icons\": \"^6.4.0\",\n    \"@fortawesome/free-regular-svg-icons\": \"^6.4.0\",\n    \"@fortawesome/free-solid-svg-icons\": \"^6.4.0\",\n    \"@tauri-apps/api\": \">=2.1.1\",\n    \"@tauri-apps/plugin-cli\": \">=2.0.0\",\n    \"@tauri-apps/plugin-clipboard-manager\": \">=2.0.0\",\n    \"@tauri-apps/plugin-dialog\": \">=2.0.0\",\n    \"@tauri-apps/plugin-notification\": \">=2.0.0\",\n    \"@tauri-apps/plugin-os\": \">=2.0.0\",\n    \"@tauri-apps/plugin-shell\": \"^2.0.1\",\n    \"@tauri-apps/plugin-websocket\": \"^2.3.0\",\n    \"autoprefixer\": \"^10.4.14\",\n    \"d3\": \"^7.8.4\",\n    \"data-urls\": \"^5.0.0\",\n    \"emoji-toolkit\": \"^7.0.1\",\n    \"fuse.js\": \"^6.6.2\",\n    \"ng-zorro-antd\": \"^16.1.0\",\n    \"ngx-markdown\": \"^16.0.0\",\n    \"postcss\": \"^8.4.23\",\n    \"prismjs\": \"^1.29.0\",\n    \"psl\": \"^1.9.0\",\n    \"rxjs\": \"~7.8.1\",\n    \"topojson-client\": \"^3.1.0\",\n    \"topojson-simplify\": \"^3.0.3\",\n    \"tslib\": \"^2.5.0\",\n    \"whatwg-encoding\": \"^3.1.1\",\n    \"zone.js\": \"^0.13.0\"\n  },\n  \"devDependencies\": {\n    \"@angular-builders/custom-webpack\": \"^16.0.0-beta.1\",\n    \"@angular-devkit/build-angular\": \"^16.0.1\",\n    \"@angular-eslint/builder\": \"16.0.1\",\n    \"@angular-eslint/eslint-plugin\": \"16.0.1\",\n    \"@angular-eslint/eslint-plugin-template\": \"16.0.1\",\n    \"@angular-eslint/schematics\": \"16.0.1\",\n    \"@angular-eslint/template-parser\": \"16.0.1\",\n    \"@angular/cli\": \"^16.0.1\",\n    \"@angular/compiler-cli\": \"^16.0.1\",\n    \"@fullhuman/postcss-purgecss\": \"^5.0.0\",\n    \"@types/chrome\": \"^0.0.236\",\n    \"@types/d3\": \"^7.4.0\",\n    \"@types/data-urls\": \"^3.0.4\",\n    \"@types/jasmine\": \"^4.3.1\",\n    \"@types/jasminewd2\": \"~2.0.10\",\n    \"@types/node\": \"^20.1.5\",\n    \"@types/psl\": \"^1.1.0\",\n    \"@types/topojson-client\": \"^3.1.1\",\n    \"@types/topojson-simplify\": \"^3.0.1\",\n    \"@types/whatwg-encoding\": \"^2.0.3\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.59.6\",\n    \"@typescript-eslint/parser\": \"^5.59.6\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"^8.40.0\",\n    \"jasmine-core\": \"^5.0.0\",\n    \"jasmine-spec-reporter\": \"^7.0.0\",\n    \"js-yaml-loader\": \"^1.2.2\",\n    \"ng-packagr\": \"^16.0.1\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"postcss-import\": \"^15.1.0\",\n    \"postcss-loader\": \"^7.3.0\",\n    \"postcss-scss\": \"^4.0.6\",\n    \"protractor\": \"~7.0.0\",\n    \"tailwindcss\": \"^3.3.2\",\n    \"ts-node\": \"^10.9.1\",\n    \"typescript\": \"4.9\",\n    \"webpack-bundle-analyzer\": \"^4.8.0\",\n    \"webpack-ext-reloader\": \"^1.1.9\",\n    \"zip-a-folder\": \"^1.1.5\"\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/karma.conf.js",
    "content": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/1.0/config/configuration-file.html\n\nmodule.exports = function (config) {\n  config.set({\n    basePath: '',\n    frameworks: ['jasmine', '@angular-devkit/build-angular'],\n    plugins: [\n      require('karma-jasmine'),\n      require('karma-chrome-launcher'),\n      require('karma-jasmine-html-reporter'),\n      require('karma-coverage'),\n      require('@angular-devkit/build-angular/plugins/karma')\n    ],\n    client: {\n      jasmine: {\n        // you can add configuration options for Jasmine here\n        // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html\n        // for example, you can disable the random execution with `random: false`\n        // or set a specific seed with `seed: 4321`\n      },\n      clearContext: false // leave Jasmine Spec Runner output visible in browser\n    },\n    jasmineHtmlReporter: {\n      suppressAll: true // removes the duplicated traces\n    },\n    coverageReporter: {\n      dir: require('path').join(__dirname, '../../coverage/portmaster-chrome-extension'),\n      subdir: '.',\n      reporters: [\n        { type: 'html' },\n        { type: 'text-summary' }\n      ]\n    },\n    reporters: ['progress', 'kjhtml'],\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    browsers: ['Chrome'],\n    singleRun: false,\n    restartOnFileChange: true\n  });\n};\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/app-routing.module.ts",
    "content": "import { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\nimport { ExtDomainListComponent } from './domain-list';\nimport { IntroComponent } from './welcome/intro.component';\n\nconst routes: Routes = [\n  { path: '', pathMatch: 'full', component: ExtDomainListComponent },\n  { path: 'authorize', pathMatch: 'prefix', component: IntroComponent }\n];\n\n@NgModule({\n  imports: [RouterModule.forRoot(routes)],\n  exports: [RouterModule]\n})\nexport class AppRoutingModule { }\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/app.component.html",
    "content": "<ext-header *ngIf=\"!isAuthorizeView\"></ext-header>\n\n<router-outlet></router-outlet>\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/app.component.scss",
    "content": ":host {\n  @apply bg-background text-white flex flex-col w-96 h-96;\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/app.component.ts",
    "content": "import { HttpErrorResponse } from '@angular/common/http';\nimport { Component, OnInit } from '@angular/core';\nimport { NavigationEnd, Router } from '@angular/router';\nimport { MetaAPI, MyProfileResponse, retryPipeline } from '@safing/portmaster-api';\nimport { catchError, filter, throwError } from 'rxjs';\n\n\n@Component({\n  selector: 'app-root',\n  templateUrl: './app.component.html',\n  styleUrls: ['./app.component.scss'],\n})\nexport class AppComponent implements OnInit {\n  isAuthorizeView = false;\n\n  constructor(\n    private metaapi: MetaAPI,\n    private router: Router,\n  ) { }\n\n  profile: MyProfileResponse | null = null;\n\n  ngOnInit(): void {\n    this.router.events\n      .pipe(\n        filter(event => event instanceof NavigationEnd)\n      )\n      .subscribe(event => {\n        if (event instanceof NavigationEnd) {\n          this.isAuthorizeView = event.url.includes(\"/authorize\")\n        }\n      })\n\n    this.metaapi.myProfile()\n      .pipe(\n        catchError(err => {\n          if (err instanceof HttpErrorResponse && err.status === 403) {\n            this.router.navigate(['/authorize'])\n          }\n\n          return throwError(() => err)\n        }),\n        retryPipeline()\n      )\n      .subscribe({\n        next: profile => {\n          this.profile = profile;\n\n          console.log(this.profile);\n        }\n      })\n  }\n\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/app.module.ts",
    "content": "import { OverlayModule } from '@angular/cdk/overlay';\nimport { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { NgModule } from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { PortmasterAPIModule } from '@safing/portmaster-api';\nimport { TabModule } from '@safing/ui';\nimport { AppRoutingModule } from './app-routing.module';\nimport { AppComponent } from './app.component';\nimport { ExtDomainListComponent } from './domain-list';\nimport { ExtHeaderComponent } from './header';\nimport { AuthIntercepter as AuthInterceptor } from './interceptor';\nimport { WelcomeModule } from './welcome';\n\n\n@NgModule({\n  declarations: [\n    AppComponent,\n    ExtDomainListComponent,\n    ExtHeaderComponent,\n  ],\n  imports: [\n    BrowserModule,\n    AppRoutingModule,\n    HttpClientModule,\n    PortmasterAPIModule.forRoot(),\n    TabModule,\n    WelcomeModule,\n    OverlayModule,\n  ],\n  providers: [\n    {\n      provide: HTTP_INTERCEPTORS,\n      multi: true,\n      useClass: AuthInterceptor,\n    }\n  ],\n  bootstrap: [AppComponent]\n})\nexport class AppModule { }\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/domain-list/domain-list.component.html",
    "content": "<ul>\n  <li class=\"flex flex-col gap-1 px-2 py-1 hover:bg-gray-300\" *ngFor=\"let req of requests\">\n    <div class=\"flex flex-row items-center justify-start gap-2\">\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 text-green-300\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n        *ngIf=\"!req.latestIsBlocked\">\n        <path fill-rule=\"evenodd\"\n          d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 text-red-300\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n        *ngIf=\"req.latestIsBlocked\">\n        <path fill-rule=\"evenodd\"\n          d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n\n      <span>\n        {{ req.domain }}\n      </span>\n    </div>\n    <span *ngIf=\"req.latestIsBlocked && !!req.lastConn\" class=\"flex flex-row gap-2 text-xs text-secondary\">\n      <span class=\"w-4\"></span>\n      {{ req.lastConn.extra_data?.reason?.Msg }}\n    </span>\n  </li>\n</ul>\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/domain-list/domain-list.component.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from \"@angular/core\";\nimport { Netquery, NetqueryConnection } from \"@safing/portmaster-api\";\nimport { ListRequests, NotifyRequests } from \"../../background/commands\";\nimport { Request } from '../../background/tab-tracker';\n\ninterface DomainRequests {\n  domain: string;\n  requests: Request[];\n  latestIsBlocked: boolean;\n  lastConn?: NetqueryConnection;\n}\n\n@Component({\n  selector: 'ext-domain-list',\n  templateUrl: './domain-list.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styles: [\n    `\n    :host {\n      @apply flex flex-grow flex-col overflow-auto;\n    }\n    `\n  ]\n})\nexport class ExtDomainListComponent implements OnInit {\n  requests: DomainRequests[] = [];\n\n  constructor(\n    private netquery: Netquery,\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  ngOnInit() {\n    // setup listening for requests sent from our background script\n    const self = this;\n    chrome.runtime.onMessage.addListener((msg: NotifyRequests) => {\n      if (typeof msg !== 'object') {\n        console.error('Received invalid message from background script')\n\n        return;\n      }\n\n      console.log(`DEBUG: received command ${msg.type} from background script`)\n\n      switch (msg.type) {\n        case 'notifyRequests':\n          self.updateRequests(msg.requests);\n          break;\n\n        default:\n          console.error('Received unknown command from background script')\n      }\n    })\n\n    this.loadRequests();\n  }\n\n  updateRequests(req: Request[]) {\n    let m = new Map<string, DomainRequests>();\n\n    this.requests.forEach(obj => {\n      obj.requests = [];\n      m.set(obj.domain, obj);\n    });\n\n    req.forEach(r => {\n      let obj = m.get(r.domain);\n      if (!obj) {\n        obj = {\n          domain: r.domain,\n          requests: [],\n          latestIsBlocked: false\n        }\n        m.set(r.domain, obj)\n      }\n\n      obj.requests.push(r);\n    })\n\n    this.requests = [];\n    Array.from(m.keys()).sort()\n      .map(key => m.get(key)!)\n      .forEach(obj => {\n        this.requests.push(obj)\n\n        this.netquery.query({\n          query: {\n            domain: obj.domain,\n          },\n          orderBy: [\n            {\n              field: 'started',\n              desc: true,\n            }\n          ],\n          page: 0,\n          pageSize: 1,\n        })\n          .subscribe(result => {\n            if (!result[0]) {\n              return;\n            }\n\n            obj.latestIsBlocked = !result[0].allowed;\n            obj.lastConn = result[0] as NetqueryConnection;\n          })\n      })\n\n    this.cdr.detectChanges();\n  }\n\n  private loadRequests() {\n    const cmd: ListRequests = {\n      type: 'listRequests',\n      tabId: 'current'\n    }\n\n    const self = this;\n    chrome.runtime.sendMessage(cmd, (response: any) => {\n      if (Array.isArray(response)) {\n        self.updateRequests(response)\n\n        return;\n      }\n\n      console.error(response);\n    })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/domain-list/index.ts",
    "content": "export * from './domain-list.component';\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/header/header.component.html",
    "content": "<div class=\"flex flex-row items-center w-full p-4 text-xl bg-gray-200 h-28\">\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" class=\"h-full \">\n    <path fill=\"currentColor\" class=\"text-green-100 shield-three\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n      stroke-width=\"1\"\n      d=\"M20 11.242c0 4.368-3.157 8.462-7.48 9.686-.338.096-.702.096-1.04 0C7.157 19.705 4 15.61 4 11.242V7.214c0-.812.491-1.544 1.243-1.851l4.864-1.99c1.214-.497 2.574-.497 3.787 0l4.864 1.99C19.509 5.67 20 6.402 20 7.214v4.028z\" />\n    <path fill=\"currentColor\" class=\"text-green-200 shield-two\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n      stroke-width=\"1\"\n      d=\"M20 11.242c0 4.368-3.157 8.462-7.48 9.686-.338.096-.702.096-1.04 0C7.157 19.705 4 15.61 4 11.242V7.214c0-.812.491-1.544 1.243-1.851l4.864-1.99c1.214-.497 2.574-.497 3.787 0l4.864 1.99C19.509 5.67 20 6.402 20 7.214v4.028z\" />\n    <path fill=\"currentColor\" class=\"text-green-300 shield-one\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n      stroke-width=\"1.4\"\n      d=\"M20 11.242c0 4.368-3.157 8.462-7.48 9.686-.338.096-.702.096-1.04 0C7.157 19.705 4 15.61 4 11.242V7.214c0-.812.491-1.544 1.243-1.851l4.864-1.99c1.214-.497 2.574-.497 3.787 0l4.864 1.99C19.509 5.67 20 6.402 20 7.214v4.028z\" />\n\n    <path stroke=\"currentColor\" fill=\"transparent\" class=\"text-background shield-ok\" stroke-linecap=\"round\"\n      stroke-linejoin=\"round\" stroke-width=\"1\" d=\"M8.712 12.566l2.193 2.193 4.787-4.788\" />\n\n\n  </svg>\n\n  <span class=\"text-2xl font-thin text-white\">\n    Secure\n  </span>\n</div>\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/header/header.component.scss",
    "content": "svg {\n  transform: scale(0.95);\n\n  path {\n    top: 0px;\n    left: 0px;\n    transform-origin: center center;\n  }\n\n  .shield-one {\n    transform: scale(.62);\n  }\n\n  .shield-two {\n    animation-delay: -1.2s;\n    opacity: .6;\n    transform: scale(.8);\n  }\n\n  .shield-three {\n    animation-delay: -2.5s;\n    opacity: .4;\n    transform: scale(1);\n  }\n\n  .shield-ok {\n    transform: scale(.62);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/header/header.component.ts",
    "content": "import { ChangeDetectionStrategy, Component } from \"@angular/core\";\n\n@Component({\n  selector: 'ext-header',\n  templateUrl: './header.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styleUrls: ['./header.component.scss']\n})\nexport class ExtHeaderComponent { }\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/header/index.ts",
    "content": "export * from './header.component';\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/interceptor.ts",
    "content": "import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from \"@angular/common/http\";\nimport { Injectable } from \"@angular/core\";\nimport { BehaviorSubject, filter, Observable, switchMap } from \"rxjs\";\n\n\n@Injectable()\nexport class AuthIntercepter implements HttpInterceptor {\n  /** Used to delay requests until we loaded the access token from the extension storage. */\n  private loaded$ = new BehaviorSubject<boolean>(false);\n\n  /** Holds the access token required to talk to the Portmaster API. */\n  private token: string | null = null;\n\n  constructor() {\n    // make sure we use the new access token once we get one.\n    chrome.storage.onChanged.addListener(changes => {\n      this.token = changes['key'].newValue || null;\n    })\n\n    // try to read the current access token from the extension storage.\n    chrome.storage.local.get('key', obj => {\n      this.token = obj.key || null;\n      console.log(\"got token\", this.token)\n      this.loaded$.next(true);\n    })\n\n    chrome.runtime.sendMessage({ type: 'listRequests', tabId: 'current' }, (response: any) => {\n      console.log(response);\n    })\n  }\n\n  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\n    return this.loaded$.pipe(\n      filter(loaded => loaded),\n      switchMap(() => {\n        if (!!this.token) {\n          req = req.clone({\n            headers: req.headers.set(\"Authorization\", \"Bearer \" + this.token)\n          })\n        }\n        return next.handle(req)\n      })\n    )\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/request-interceptor.service.ts",
    "content": "import { Injectable } from \"@angular/core\";\nimport { Subject } from \"rxjs\";\n\n\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class RequestInterceptorService {\n  /** Used to emit when a new URL was requested */\n  private onUrlRequested$ = new Subject<chrome.webRequest.WebRequestBodyDetails>();\n\n  /** Used to emit when a URL has likely been blocked by the portmaster */\n  private onUrlBlocked$ = new Subject<chrome.webRequest.WebResponseErrorDetails>();\n\n  /** Emits when a new URL was requested */\n  get onUrlRequested() {\n    return this.onUrlRequested$.asObservable();\n  }\n\n  /** Emits when a new URL was likely blocked by the portmaster */\n  get onUrlBlocked() {\n    return this.onUrlBlocked$.asObservable();\n  }\n\n  constructor() {\n    this.registerCallbacks()\n  }\n\n  private registerCallbacks() {\n    const filter = {\n      urls: [\n        \"http://*/*\",\n        \"https://*/*\",\n      ]\n    };\n\n    chrome.webRequest.onBeforeRequest.addListener(details => this.onUrlRequested$.next(details), filter)\n    chrome.webRequest.onErrorOccurred.addListener(details => {\n      if (details.error !== \"net::ERR_ADDRESS_UNREACHABLE\") {\n        // we don't care about errors other than UNREACHABLE because that's error caused\n        // by the portmaster.\n        return;\n      }\n\n      this.onUrlBlocked$.next(details);\n    }, filter)\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/welcome/index.ts",
    "content": "export * from './welcome.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/welcome/intro.component.html",
    "content": "<div class=\"flex flex-col items-center\">\n\n  <h1 class=\"flex flex-row items-center gap-4 p-4 bg-gray-200 text-md\">\n    <svg class=\"w-auto h-16 mr-4\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\"\n      xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 128 128\">\n      <g data-name=\"Main\" fill-rule=\"evenodd\">\n        <path fill=\"#fff\" d=\"M176.11 36.73l-5-8.61a41.53 41.53 0 00-14.73 57.22l8.55-5.12a31.58 31.58 0 0111.19-43.49z\"\n          transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n        <path fill=\"#fff\" d=\"M222.36 72.63a31.55 31.55 0 01-45 19.35l-4.62 8.84a41.54 41.54 0 0059.17-25.46z\"\n          transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n        <path fill=\"#fff\" d=\"M197 83a19.66 19.66 0 01-19.25-32.57l-4.5-4.27A25.87 25.87 0 00198.59 89z\"\n          transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".6\"></path>\n        <path fill=\"#fff\"\n          d=\"M192 112.64A48.64 48.64 0 11240.64 64 48.64 48.64 0 01192 112.64zM256 64a64 64 0 10-64 64 64 64 0 0064-64z\"\n          transform=\"translate(-127.99 .1)\"></path>\n      </g>\n    </svg>\n\n    <span class=\"inline-flex flex-col items-start\">\n      <span class=\"text-secondary\">Welcome to the</span>\n      <span class=\"text-lg font-semibold\">\n        Portmaster Browser Extension\n      </span>\n    </span>\n  </h1>\n</div>\n<div class=\"flex flex-col items-center flex-grow p-4 justify-evenly\">\n  <ng-container *ngIf=\"state === ''; else: authorizingTemplate\">\n    <span class=\"text-sm text-center text-secondary\">\n      This extension adds direct support for Portmaster to your Browser. For that, it needs to get access to the\n      Portmaster on your system. For security reasons, you first need to authorize the Browser Extension to talk to the\n      Portmaster.\n    </span>\n\n  </ng-container>\n\n  <ng-template #authorizingTemplate>\n    <h2 class=\"text-base text-primary\">Waiting for Authorization</h2>\n    <span class=\"text-sm text-center text-secondary\">\n      Please open the Portmaster and approve the authorization request.\n    </span>\n  </ng-template>\n\n  <button (click)=\"authorizeExtension()\"\n    class=\"px-3 py-1.5 text-center text-white rounded-md cursor-pointer hover:bg-blue hover:bg-opacity-70 bg-blue outline-none text-sm\"\n    type=\"button\">{{ state === 'authorizing' ? 'Retry' : 'Authorize' }}\n  </button>\n</div>\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/welcome/intro.component.ts",
    "content": "import { Component } from \"@angular/core\";\nimport { Router } from \"@angular/router\";\nimport { MetaAPI } from \"@safing/portmaster-api\";\nimport { Subject, takeUntil } from \"rxjs\";\n\n@Component({\n  templateUrl: './intro.component.html',\n  styles: [\n    `\n    :host {\n      @apply flex flex-col h-full;\n    }\n    `\n  ]\n})\nexport class IntroComponent {\n  private cancelRequest$ = new Subject<void>();\n\n  state: 'authorizing' | 'failed' | '' = '';\n\n  constructor(\n    private meta: MetaAPI,\n    private router: Router,\n  ) { }\n\n  authorizeExtension() {\n    // cancel any pending request\n    this.cancelRequest$.next();\n\n    this.state = 'authorizing';\n    this.meta.requestApplicationAccess(\"Portmaster Browser Extension\")\n      .pipe(takeUntil(this.cancelRequest$))\n      .subscribe({\n        next: token => {\n          chrome.storage.local.set(token);\n          console.log(token);\n          this.router.navigate(['/'])\n        },\n        error: err => {\n          this.state = 'failed';\n        }\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/app/welcome/welcome.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { OverlayStepperModule } from \"@safing/ui\";\nimport { IntroComponent } from \"./intro.component\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    OverlayStepperModule,\n  ],\n  declarations: [\n    IntroComponent,\n  ],\n  exports: [\n    IntroComponent,\n  ]\n})\nexport class WelcomeModule { }\n\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/assets/.gitkeep",
    "content": ""
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/background/commands.ts",
    "content": "import { Request } from \"./tab-tracker\";\n\nexport interface ListRequests {\n  type: 'listRequests';\n  domain?: string;\n  tabId: number | 'current';\n}\n\nexport interface NotifyRequests {\n  type: 'notifyRequests',\n  requests: Request[];\n}\n\nexport type CallRequest = ListRequests;\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/background/tab-tracker.ts",
    "content": "import { deepClone } from \"@safing/portmaster-api\";\n\nexport interface Request {\n  /** The ID assigned by the browser */\n  id: string;\n\n  /** The domain this request was for */\n  domain: string;\n\n  /** The timestamp in milliseconds since epoch at which the request was initiated */\n  time: number;\n\n  /** Whether or not this request errored with net::ERR_ADDRESS_UNREACHABLE */\n  isUnreachable: boolean;\n}\n\n/**\n * TabTracker tracks requests to domains made by a single browser tab.\n */\nexport class TabTracker {\n  /** A list of requests observed for this tab order by time they have been initiated */\n  private requests: Request[] = [];\n\n  /** A lookup map for requests to specific domains */\n  private byDomain = new Map<string, Request[]>();\n\n  /** A lookup map for requests by the chrome request ID */\n  private byRequestId = new Map<string, Request>;\n\n  constructor(public readonly tabId: number) { }\n\n  /** Returns an array of all requests observed in this tab. */\n  allRequests(): Request[] {\n    return deepClone(this.requests)\n  }\n\n  /** Returns a list of requests that have been observed for domain */\n  forDomain(domain: string): Request[] {\n    if (!domain.endsWith(\".\")) {\n      domain += \".\"\n    }\n\n    return this.byDomain.get(domain) || [];\n  }\n\n  /** Call to add the details of a web-request to this tab-tracker */\n  trackRequest(details: chrome.webRequest.WebRequestDetails) {\n    // If this is the wrong tab ID ignore the request details\n    if (details.tabId !== this.tabId) {\n      console.error(`TabTracker.trackRequest: called with wrong tab ID. Expected ${this.tabId} but got ${details.tabId}`)\n\n      return;\n    }\n\n    // if the type of the request is for the main_frame the user switched to a new website.\n    // In that case, we can wipe out all currently stored requests as the user will likely not\n    // care anymore.\n    if (details.type === \"main_frame\") {\n      this.clearState();\n    }\n\n    // get the domain of the request normalized to contain the trailing dot.\n    let domain = new URL(details.url).host;\n    if (!domain.endsWith(\".\")) {\n      domain += \".\"\n    }\n\n    const req: Request = {\n      id: details.requestId,\n      domain: domain,\n      time: details.timeStamp,\n      isUnreachable: false, // we don't actually know that yet\n    }\n\n    this.requests.push(req);\n    this.byRequestId.set(req.id, req)\n\n    // Add the request to the by-domain lookup map\n    let byDomainRequests = this.byDomain.get(req.domain);\n    if (!byDomainRequests) {\n      byDomainRequests = [];\n      this.byDomain.set(req.domain, byDomainRequests)\n    }\n    byDomainRequests.push(req)\n\n    console.log(`DEBUG: observed request ${req.id} to ${req.domain}`)\n  }\n\n  /** Call to notify the tab-tracker of a request error */\n  trackError(errorDetails: chrome.webRequest.WebResponseErrorDetails) {\n    // we only care about net::ERR_ADDRESS_UNREACHABLE here because that's how the\n    // Portmaster blocks the request.\n\n    // TODO(ppacher): docs say we must not rely on that value so we should figure out a better\n    // way to detect if the error is caused by the Portmaster.\n    if (errorDetails.error !== \"net::ERR_ADDRESS_UNREACHABLE\") {\n      return;\n    }\n\n    // the the previsouly observed request by the request ID.\n    const req = this.byRequestId.get(errorDetails.requestId)\n    if (!req) {\n      console.error(\"TabTracker.trackError: request has not been observed before\")\n\n      return\n    }\n\n    // make sure the error details actually happend for the observed tab.\n    if (errorDetails.tabId !== this.tabId) {\n      console.error(`TabTracker.trackRequest: called with wrong tab ID. Expected ${this.tabId} but got ${errorDetails.tabId}`)\n\n      return;\n    }\n\n    // mark the request as unreachable.\n    req.isUnreachable = true;\n    console.log(`DEBUG: marked request ${req.id} to ${req.domain} as unreachable`)\n  }\n\n  /** Clears the current state of the tab tracker */\n  private clearState() {\n    this.requests = [];\n    this.byDomain = new Map();\n    this.byRequestId = new Map();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/background/tab-utils.ts",
    "content": "\n/** Queries and returns the currently active tab */\nexport function getCurrentTab(): Promise<chrome.tabs.Tab> {\n  return new Promise((resolve) => {\n    chrome.tabs.query({ active: true, lastFocusedWindow: true }, ([tab]) => {\n      resolve(tab);\n    })\n  })\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/background.ts",
    "content": "import { debounceTime, Subject } from \"rxjs\";\nimport { CallRequest, ListRequests, NotifyRequests } from \"./background/commands\";\nimport { Request, TabTracker } from \"./background/tab-tracker\";\nimport { getCurrentTab } from \"./background/tab-utils\";\n\nexport class BackgroundService {\n  /** a lookup map for tab trackers by tab-id */\n  private trackers = new Map<number, TabTracker>();\n\n  /** used to signal the pop-up that new requests arrived */\n  private notifyRequests = new Subject<void>();\n\n  constructor() {\n    // register a navigation-completed listener. This is fired when the user switches to a new website\n    // by entering it in the browser address bar.\n    chrome.webNavigation.onCompleted.addListener((details) => {\n      console.log(\"event: webNavigation.onCompleted\", details);\n    })\n\n    // request event listeners for new requests and errors that occured for them.\n    // We only care about http and https here.\n    const filter = {\n      urls: [\n        'http://*/*',\n        'https://*/*'\n      ]\n    }\n    chrome.webRequest.onBeforeRequest.addListener(details => this.handleOnBeforeRequest(details), filter)\n    chrome.webRequest.onErrorOccurred.addListener(details => this.handleOnErrorOccured(details), filter)\n\n    // make sure we can communicate with the extension popup\n    chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => this.handleMessage(msg, sender, sendResponse))\n\n    // set-up signalling of new requests to the pop-up\n    this.notifyRequests\n      .pipe(debounceTime(500))\n      .subscribe(async () => {\n        const currentTab = await getCurrentTab();\n        if (!!currentTab && !!currentTab.id) {\n          const msg: NotifyRequests = {\n            type: 'notifyRequests',\n            requests: this.mustGetTab({ tabId: currentTab.id }).allRequests()\n          }\n\n          chrome.runtime.sendMessage(msg)\n        }\n      })\n  }\n\n  /** Callback for messages sent by the popup */\n  private handleMessage(msg: CallRequest, sender: chrome.runtime.MessageSender, sendResponse: (msg: any) => void) {\n    console.log(`DEBUG: got message from ${sender.origin} (tab=${sender.tab?.id})`)\n\n    if (typeof msg !== 'object') {\n      console.error(`Received invalid message from popup`, msg)\n\n      return;\n    }\n\n    let response: Promise<any>;\n    switch (msg.type) {\n      case 'listRequests':\n        response = this.handleListRequests(msg)\n        break;\n\n      default:\n        response = Promise.reject(\"unknown command\")\n    }\n\n    response\n      .then(res => {\n        console.log(`DEBUG: sending response for command ${msg.type}`, res)\n        sendResponse(res);\n      })\n      .catch(err => {\n        console.error(`Failed to handle command ${msg.type}`, err)\n        sendResponse({\n          type: 'error',\n          details: err\n        });\n      })\n  }\n\n  /** Returns a list of all observed requests based on the filter in msg. */\n  private async handleListRequests(msg: ListRequests): Promise<Request[]> {\n    if (msg.tabId === 'current') {\n      const currentID = (await getCurrentTab()).id\n      if (!currentID) {\n        return [];\n      }\n\n      msg.tabId = currentID;\n    }\n\n    const tracker = this.mustGetTab({ tabId: msg.tabId as number })\n\n    if (!!msg.domain) {\n      return tracker.forDomain(msg.domain)\n    }\n\n    return tracker.allRequests()\n  }\n\n  /** Callback for chrome.webRequest.onBeforeRequest */\n  private handleOnBeforeRequest(details: chrome.webRequest.WebRequestDetails) {\n    this.mustGetTab(details).trackRequest(details)\n\n    this.notifyRequests.next();\n  }\n\n  /** Callback for chrome.webRequest.onErrorOccured */\n  private handleOnErrorOccured(details: chrome.webRequest.WebResponseErrorDetails) {\n    this.mustGetTab(details).trackError(details);\n\n    this.notifyRequests.next();\n  }\n\n  /** Returns the tab-tracker for tabId. Creates a new tracker if none exists. */\n  private mustGetTab({ tabId }: { tabId: number }): TabTracker {\n    let tracker = this.trackers.get(tabId);\n    if (!tracker) {\n      tracker = new TabTracker(tabId)\n      this.trackers.set(tabId, tracker)\n    }\n\n    return tracker;\n  }\n}\n\n/** start the background service once we got successfully installed. */\nchrome.runtime.onInstalled.addListener(() => {\n  new BackgroundService()\n});\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/environments/environment.prod.ts",
    "content": "export const environment = {\n  production: false\n};\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/environments/environment.ts",
    "content": "// This file can be replaced during build by using the `fileReplacements` array.\n// `ng build` replaces `environment.ts` with `environment.prod.ts`.\n// The list of file replacements can be found in `angular.json`.\n\nexport const environment = {\n  production: false\n};\n\n/*\n * For easier debugging in development mode, you can import the following file\n * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.\n *\n * This import should be commented out in production mode because it will have a negative impact\n * on performance if an error is thrown.\n */\n// import 'zone.js/plugins/zone-error';  // Included with Angular CLI.\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>PortmasterChromeExtension</title>\n  <base href=\"/\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link rel=\"icon\" type=\"image/x-icon\" href=\"favicon.ico\">\n</head>\n<body>\n  <app-root></app-root>\n</body>\n</html>\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/main.ts",
    "content": "import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n\nimport { AppModule } from './app/app.module';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n  enableProdMode();\n}\n\nplatformBrowserDynamic().bootstrapModule(AppModule)\n  .catch(err => console.error(err));\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/manifest.json",
    "content": "{\n  \"name\": \"Portmaster Browser Extension\",\n  \"version\": \"0.1\",\n  \"description\": \"Browser Extension for even better Portmaster integration\",\n  \"manifest_version\": 2,\n  \"permissions\": [\n      \"activeTab\",\n      \"storage\",\n      \"webRequest\",\n      \"webNavigation\",\n      \"*://*/*\"\n  ],\n  \"browser_action\": {\n    \"default_popup\": \"index.html\",\n    \"default_icon\": {\n      \"128\": \"assets/icon_128.png\"\n    }\n  },\n  \"background\": {\n    \"scripts\": [\"background.js\"],\n    \"persistent\": true\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/polyfills.ts",
    "content": "/**\n * This file includes polyfills needed by Angular and is loaded before the app.\n * You can add your own extra polyfills to this file.\n *\n * This file is divided into 2 sections:\n *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.\n *   2. Application imports. Files imported after ZoneJS that should be loaded before your main\n *      file.\n *\n * The current setup is for so-called \"evergreen\" browsers; the last versions of browsers that\n * automatically update themselves. This includes recent versions of Safari, Chrome (including\n * Opera), Edge on the desktop, and iOS and Chrome on mobile.\n *\n * Learn more in https://angular.io/guide/browser-support\n */\n\n/***************************************************************************************************\n * BROWSER POLYFILLS\n */\n\n/**\n * By default, zone.js will patch all possible macroTask and DomEvents\n * user can disable parts of macroTask/DomEvents patch by setting following flags\n * because those flags need to be set before `zone.js` being loaded, and webpack\n * will put import in the top of bundle, so user need to create a separate file\n * in this directory (for example: zone-flags.ts), and put the following flags\n * into that file, and then add the following code before importing zone.js.\n * import './zone-flags';\n *\n * The flags allowed in zone-flags.ts are listed here.\n *\n * The following flags will work for all browsers.\n *\n * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame\n * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick\n * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames\n *\n *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js\n *  with the following flag, it will bypass `zone.js` patch for IE/Edge\n *\n *  (window as any).__Zone_enable_cross_context_check = true;\n *\n */\n\n/***************************************************************************************************\n * Zone JS is required by default for Angular itself.\n */\nimport 'zone.js';  // Included with Angular CLI.\n\n\n/***************************************************************************************************\n * APPLICATION IMPORTS\n */\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/styles.scss",
    "content": "/* You can add global styles to this file, and also import other style files */\n\n@import 'tailwindcss/base';\n@import 'tailwindcss/components';\n@import 'tailwindcss/utilities';\n\n\n@import '@angular/cdk/overlay-prebuilt';\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/src/test.ts",
    "content": "// This file is required by karma.conf.js and loads recursively all the .spec and framework files\n\nimport 'zone.js/testing';\nimport { getTestBed } from '@angular/core/testing';\nimport {\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting\n} from '@angular/platform-browser-dynamic/testing';\n\n// First, initialize the Angular testing environment.\ngetTestBed().initTestEnvironment(\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting(),\n);\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/tsconfig.app.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../out-tsc/app\",\n    \"types\": [\n      \"chrome\"\n    ]\n  },\n  \"files\": [\n    \"src/main.ts\",\n    \"src/polyfills.ts\",\n    \"src/background.ts\"\n  ],\n  \"include\": [\n    \"src/**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/portmaster-chrome-extension/tsconfig.spec.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../out-tsc/spec\",\n    \"types\": [\n      \"jasmine\"\n    ]\n  },\n  \"files\": [\n    \"src/test.ts\",\n    \"src/polyfills.ts\"\n  ],\n  \"include\": [\n    \"src/**/*.spec.ts\",\n    \"src/**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/README.md",
    "content": "# PortmasterApi\n\nThis library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.0.0.\n\n## Code scaffolding\n\nRun `ng generate component component-name --project portmaster-api` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project portmaster-api`.\n> Note: Don't forget to add `--project portmaster-api` or else it will be added to the default project in your `angular.json` file. \n\n## Build\n\nRun `ng build portmaster-api` to build the project. The build artifacts will be stored in the `dist/` directory.\n\n## Publishing\n\nAfter building your library with `ng build portmaster-api`, go to the dist folder `cd dist/portmaster-api` and run `npm publish`.\n\n## Running unit tests\n\nRun `ng test portmaster-api` to execute the unit tests via [Karma](https://karma-runner.github.io).\n\n## Further help\n\nTo get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/karma.conf.js",
    "content": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/1.0/config/configuration-file.html\n\nmodule.exports = function (config) {\n  config.set({\n    basePath: '',\n    frameworks: ['jasmine', '@angular-devkit/build-angular'],\n    plugins: [\n      require('karma-jasmine'),\n      require('karma-chrome-launcher'),\n      require('karma-jasmine-html-reporter'),\n      require('karma-coverage'),\n      require('@angular-devkit/build-angular/plugins/karma')\n    ],\n    client: {\n      jasmine: {\n        // you can add configuration options for Jasmine here\n        // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html\n        // for example, you can disable the random execution with `random: false`\n        // or set a specific seed with `seed: 4321`\n      },\n      clearContext: false // leave Jasmine Spec Runner output visible in browser\n    },\n    jasmineHtmlReporter: {\n      suppressAll: true // removes the duplicated traces\n    },\n    coverageReporter: {\n      dir: require('path').join(__dirname, '../../../coverage/safing/portmaster-api'),\n      subdir: '.',\n      reporters: [\n        { type: 'html' },\n        { type: 'text-summary' }\n      ]\n    },\n    reporters: ['progress', 'kjhtml'],\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    browsers: ['Chrome'],\n    singleRun: false,\n    restartOnFileChange: true\n  });\n};\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/ng-package.json",
    "content": "{\n  \"$schema\": \"../../../node_modules/ng-packagr/ng-package.schema.json\",\n  \"dest\": \"../../../dist-lib/safing/portmaster-api\",\n  \"lib\": {\n    \"entryFile\": \"src/public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/package.json",
    "content": "{\n  \"name\": \"@safing/portmaster-api\",\n  \"version\": \"0.0.1\",\n  \"peerDependencies\": {\n    \"@angular/common\": \"^14.0.0\",\n    \"@angular/core\": \"^14.0.0\"\n  },\n  \"dependencies\": {\n    \"tslib\": \"^2.3.0\"\n  },\n  \"devDependencies\": {\n    \"@types/jasmine\": \"^4.0.3\"\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/app-profile.service.ts",
    "content": "import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';\nimport { Inject, Injectable } from '@angular/core';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { filter, finalize, map, mergeMap, share, take } from 'rxjs/operators';\nimport {\n  AppProfile,\n  FlatConfigObject,\n  LayeredProfile,\n  TagDescription,\n  flattenProfileConfig,\n} from './app-profile.types';\nimport {\n  PORTMASTER_HTTP_API_ENDPOINT,\n  PortapiService,\n} from './portapi.service';\nimport { Process } from './portapi.types';\n\n@Injectable()\nexport class AppProfileService {\n  private watchedProfiles = new Map<string, Observable<AppProfile>>();\n\n  constructor(\n    private portapi: PortapiService,\n    private http: HttpClient,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpAPI: string\n  ) { }\n\n  /**\n   * Returns the database key of a profile.\n   *\n   * @param source The source of the profile.\n   * @param id The profile ID.\n   */\n  getKey(source: string, id: string): string;\n\n  /**\n   * Returns the database key of a profile\n   *\n   * @param p The app-profile itself..\n   */\n  getKey(p: AppProfile): string;\n\n  getKey(idOrSourceOrProfile: string | AppProfile, id?: string): string {\n    if (typeof idOrSourceOrProfile === 'object') {\n      return this.getKey(idOrSourceOrProfile.Source, idOrSourceOrProfile.ID);\n    }\n\n    let key = idOrSourceOrProfile;\n\n    if (!!id) {\n      key = `core:profiles/${idOrSourceOrProfile}/${id}`;\n    }\n\n    return key;\n  }\n\n  /**\n   * Load an application profile.\n   *\n   * @param sourceAndId The full profile ID including source\n   */\n  getAppProfile(sourceAndId: string): Observable<AppProfile>;\n\n  /**\n   * Load an application profile.\n   *\n   * @param source The source of the profile\n   * @param id The ID of the profile\n   */\n  getAppProfile(source: string, id: string): Observable<AppProfile>;\n\n  getAppProfile(\n    sourceOrSourceAndID: string,\n    id?: string\n  ): Observable<AppProfile> {\n    let source = sourceOrSourceAndID;\n    if (id !== undefined) {\n      source += '/' + id;\n    }\n    const key = `core:profiles/${source}`;\n\n    if (this.watchedProfiles.has(key)) {\n      return this.watchedProfiles.get(key)!.pipe(take(1));\n    }\n\n    return this.getAppProfileFromKey(key);\n  }\n\n  setProfileIcon(\n    content: string | ArrayBuffer,\n    mimeType: string\n  ): Observable<{ filename: string }> {\n    return this.http.post<{ filename: string }>(\n      `${this.httpAPI}/v1/profile/icon`,\n      content,\n      {\n        headers: new HttpHeaders({\n          'Content-Type': mimeType,\n        }),\n      }\n    );\n  }\n\n  /**\n   * Loads an application profile by it's database key.\n   *\n   * @param key The key of the application profile.\n   */\n  getAppProfileFromKey(key: string): Observable<AppProfile> {\n    return this.portapi.get(key);\n  }\n\n  /**\n   * Loads the global-configuration profile.\n   */\n  globalConfig(): Observable<FlatConfigObject> {\n    return this.getAppProfile('special', 'global-config').pipe(\n      map((profile) => flattenProfileConfig(profile.Config))\n    );\n  }\n\n  /** Returns all possible process tags. */\n  tagDescriptions(): Observable<TagDescription[]> {\n    return this.http\n      .get<{ Tags: TagDescription[] }>(`${this.httpAPI}/v1/process/tags`)\n      .pipe(map((result) => result.Tags));\n  }\n\n  /**\n   * Watches an application profile for changes.\n   *\n   * @param source The source of the profile\n   * @param id The ID of the profile\n   */\n  watchAppProfile(sourceAndId: string): Observable<AppProfile>;\n  /**\n   * Watches an application profile for changes.\n   *\n   * @param source The source of the profile\n   * @param id The ID of the profile\n   */\n  watchAppProfile(source: string, id: string): Observable<AppProfile>;\n\n  watchAppProfile(sourceAndId: string, id?: string): Observable<AppProfile> {\n    let key = '';\n\n    if (id === undefined) {\n      key = sourceAndId;\n      if (!key.startsWith('core:profiles/')) {\n        key = `core:profiles/${key}`;\n      }\n    } else {\n      key = `core:profiles/${sourceAndId}/${id}`;\n    }\n\n    if (this.watchedProfiles.has(key)) {\n      return this.watchedProfiles.get(key)!;\n    }\n\n    const stream = this.portapi.get<AppProfile>(key).pipe(\n      mergeMap(() => this.portapi.watch<AppProfile>(key)),\n      finalize(() => {\n        console.log(\n          'watchAppProfile: removing cached profile stream for ' + key\n        );\n        this.watchedProfiles.delete(key);\n      }),\n      share({\n        connector: () => new BehaviorSubject<AppProfile | null>(null),\n        resetOnRefCountZero: true,\n      }),\n      filter((profile) => profile !== null)\n    ) as Observable<AppProfile>;\n\n    this.watchedProfiles.set(key, stream);\n\n    return stream;\n  }\n\n  /** @deprecated use saveProfile instead */\n  saveLocalProfile(profile: AppProfile): Observable<void> {\n    return this.saveProfile(profile);\n  }\n\n  /**\n   * Save an application profile.\n   *\n   * @param profile The profile to save\n   */\n  saveProfile(profile: AppProfile): Observable<void> {\n    profile.LastEdited = Math.floor(new Date().getTime() / 1000);\n    return this.portapi.update(\n      `core:profiles/${profile.Source}/${profile.ID}`,\n      profile\n    );\n  }\n\n  /**\n   * Watch all application profiles\n   */\n  watchProfiles(): Observable<AppProfile[]> {\n    return this.portapi.watchAll<AppProfile>('core:profiles/');\n  }\n\n  watchLayeredProfile(source: string, id: string): Observable<LayeredProfile>;\n\n  /**\n   * Watches the layered runtime profile for a given application\n   * profile.\n   *\n   * @param profile The app profile\n   */\n  watchLayeredProfile(profile: AppProfile): Observable<LayeredProfile>;\n\n  watchLayeredProfile(\n    profileOrSource: string | AppProfile,\n    id?: string\n  ): Observable<LayeredProfile> {\n    if (typeof profileOrSource == 'object') {\n      id = profileOrSource.ID;\n      profileOrSource = profileOrSource.Source;\n    }\n\n    const key = `runtime:layeredProfile/${profileOrSource}/${id}`;\n    return this.portapi.watch<LayeredProfile>(key);\n  }\n\n  /**\n   * Loads the layered runtime profile for a given application\n   * profile.\n   *\n   * @param profile The app profile\n   */\n  getLayeredProfile(profile: AppProfile): Observable<LayeredProfile> {\n    const key = `runtime:layeredProfile/${profile.Source}/${profile.ID}`;\n    return this.portapi.get<LayeredProfile>(key);\n  }\n\n  /**\n   * Delete an application profile.\n   *\n   * @param profile The profile to delete\n   */\n  deleteProfile(profile: AppProfile): Observable<void> {\n    return this.portapi.delete(`core:profiles/${profile.Source}/${profile.ID}`);\n  }\n\n  getProcessesByProfile(profileOrId: AppProfile | string): Observable<Process[]> {\n    if (typeof profileOrId === 'object') {\n      profileOrId = profileOrId.Source + \"/\" + profileOrId.ID\n    }\n\n    return this.http.get<Process[]>(`${this.httpAPI}/v1/process/list/by-profile/${profileOrId}`)\n  }\n\n  getProcessByPid(pid: number): Observable<Process> {\n    return this.http.get<Process>(`${this.httpAPI}/v1/process/group-leader/${pid}`)\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/app-profile.types.ts",
    "content": "import { BaseSetting, OptionValueType, SettingValueType } from './config.types';\nimport { SecurityLevel } from './core.types';\nimport { Record } from './portapi.types';\n\nexport interface ConfigMap {\n  [key: string]: ConfigObject;\n}\n\nexport type ConfigObject = OptionValueType | ConfigMap;\n\nexport interface FlatConfigObject {\n  [key: string]: OptionValueType;\n}\n\n\nexport interface LayeredProfile extends Record {\n  // LayerIDs is a list of all profiles that are used\n  // by this layered profile. Profiles are evaluated in\n  // order.\n  LayerIDs: string[];\n\n  // The current revision counter of the layered profile.\n  RevisionCounter: number;\n}\n\nexport enum FingerprintType {\n  Tag = 'tag',\n  Cmdline = 'cmdline',\n  Env = 'env',\n  Path = 'path',\n}\n\nexport enum FingerpringOperation {\n  Equal = 'equals',\n  Prefix = 'prefix',\n  Regex = 'regex',\n}\n\nexport interface Fingerprint {\n  Type: FingerprintType;\n  Key: string;\n  Operation: FingerpringOperation;\n  Value: string;\n}\n\nexport interface TagDescription {\n  ID: string;\n  Name: string;\n  Description: string;\n}\n\nexport interface Icon {\n  Type: '' | 'database' | 'path' | 'api';\n  Source: '' | 'user' | 'import' | 'core' | 'ui';\n  Value: string;\n}\n\nexport interface AppProfile extends Record {\n  ID: string;\n  LinkedPath: string; // deprecated\n  PresentationPath: string;\n  Fingerprints: Fingerprint[];\n  Created: number;\n  LastEdited: number;\n  Config?: ConfigMap;\n  Description: string;\n  Warning: string;\n  WarningLastUpdated: string;\n  Homepage: string;\n  Icons: Icon[];\n  Name: string;\n  Internal: boolean;\n  SecurityLevel: SecurityLevel;\n  Source: 'local';\n}\n\n// flattenProfileConfig returns a flat version of a nested ConfigMap where each property\n// can be used as the database key for the associated setting.\nexport function flattenProfileConfig(\n  p?: ConfigMap,\n  prefix = ''\n): FlatConfigObject {\n  if (p === null || p === undefined) {\n    return {}\n  }\n\n  let result: FlatConfigObject = {};\n\n  Object.keys(p).forEach((key) => {\n    const childPrefix = prefix === '' ? key : `${prefix}/${key}`;\n\n    const prop = p[key];\n\n    if (isConfigMap(prop)) {\n      const flattened = flattenProfileConfig(prop, childPrefix);\n      result = mergeObjects(result, flattened);\n      return;\n    }\n\n    result[childPrefix] = prop;\n  });\n\n  return result;\n}\n\n/**\n * Returns the current value (or null) of a setting stored in a config\n * map by path.\n *\n * @param obj The ConfigMap object\n * @param path  The path of the setting separated by foward slashes.\n */\nexport function getAppSetting<T extends OptionValueType>(\n  obj: ConfigMap | null | undefined,\n  path: string\n): T | null {\n  if (obj === null || obj === undefined) {\n    return null\n  }\n\n  const parts = path.split('/');\n\n  let iter = obj;\n  for (let idx = 0; idx < parts.length; idx++) {\n    const propName = parts[idx];\n\n    if (iter[propName] === undefined) {\n      return null;\n    }\n\n    const value = iter[propName];\n    if (idx === parts.length - 1) {\n      return value as T;\n    }\n\n    if (!isConfigMap(value)) {\n      return null;\n    }\n\n    iter = value;\n  }\n  return null;\n}\n\nexport function getActualValue<S extends BaseSetting<any, any>>(\n  s: S\n): SettingValueType<S> {\n  if (s.Value !== undefined) {\n    return s.Value;\n  }\n  if (s.GlobalDefault !== undefined) {\n    return s.GlobalDefault;\n  }\n  return s.DefaultValue;\n}\n\n/**\n * Sets the value of a settings inside the nested config object.\n *\n * @param obj THe config object\n * @param path  The path of the setting\n * @param value The new value to set.\n */\nexport function setAppSetting(obj: ConfigObject, path: string, value: any) {\n  const parts = path.split('/');\n  if (typeof obj !== 'object' || Array.isArray(obj)) {\n    return;\n  }\n\n  let iter = obj;\n  for (let idx = 0; idx < parts.length; idx++) {\n    const propName = parts[idx];\n\n    if (idx === parts.length - 1) {\n      if (value === undefined) {\n        delete iter[propName];\n      } else {\n        iter[propName] = value;\n      }\n      return;\n    }\n\n    if (iter[propName] === undefined) {\n      iter[propName] = {};\n    }\n\n    iter = iter[propName] as ConfigMap;\n  }\n}\n\n/** Typeguard to ensure v is a ConfigMap */\nfunction isConfigMap(v: any): v is ConfigMap {\n  return typeof v === 'object' && !Array.isArray(v);\n}\n\n/**\n * Returns a new flat-config object that contains values from both\n * parameters.\n *\n * @param a The first config object\n * @param b The second config object\n */\nfunction mergeObjects(\n  a: FlatConfigObject,\n  b: FlatConfigObject\n): FlatConfigObject {\n  var res: FlatConfigObject = {};\n  Object.keys(a).forEach((key) => {\n    res[key] = a[key];\n  });\n  Object.keys(b).forEach((key) => {\n    res[key] = b[key];\n  });\n  return res;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/config.service.ts",
    "content": "import { Injectable, TrackByFunction } from '@angular/core';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { distinctUntilChanged, filter, map, share, toArray } from 'rxjs/operators';\nimport { BaseSetting, BoolSetting, OptionType, Setting, SettingValueType } from './config.types';\nimport { PortapiService } from './portapi.service';\n\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class ConfigService {\n  networkRatingEnabled$: Observable<boolean>;\n\n  /**\n   * A {@link TrackByFunction} for tracking settings.\n   */\n  static trackBy: TrackByFunction<Setting> = (_: number, obj: Setting) => obj.Name;\n  readonly trackBy = ConfigService.trackBy;\n\n  /** configPrefix is the database key prefix for the config db */\n  readonly configPrefix = \"config:\";\n\n  constructor(private portapi: PortapiService) {\n    this.networkRatingEnabled$ = this.watch<BoolSetting>(\"core/enableNetworkRating\")\n      .pipe(\n        share({ connector: () => new BehaviorSubject(false) }),\n      )\n  }\n\n  /**\n   * Loads a configuration setting from the database.\n   *\n   * @param key The key of the configuration setting.\n   */\n  get(key: string): Observable<Setting> {\n    return this.portapi.get<Setting>(this.configPrefix + key);\n  }\n\n  /**\n   * Returns all configuration settings that match query. Note that in\n   * contrast to {@link PortAPI} settings values are collected into\n   * an array before being emitted. This allows simple usage in *ngFor\n   * and friends.\n   *\n   * @param query The query used to search for configuration settings.\n   */\n  query(query: string): Observable<Setting[]> {\n    return this.portapi.query<Setting>(this.configPrefix + query)\n      .pipe(\n        map(setting => setting.data),\n        toArray()\n      );\n  }\n\n  /**\n   * Save a setting.\n   *\n   * @param s The setting to save. Note that the new value should already be set to {@property Value}.\n   */\n  save(s: Setting): Observable<void>;\n\n  /**\n   * Save a setting.\n   *\n   * @param key The key of the configuration setting\n   * @param value The new value of the setting.\n   */\n  save(key: string, value: any): Observable<void>;\n\n  // save is overloaded, see above.\n  save(s: Setting | string, v?: any): Observable<void> {\n    if (typeof s === 'string') {\n      return this.portapi.update(this.configPrefix + s, {\n        Key: s,\n        Value: v,\n      });\n    }\n    return this.portapi.update(this.configPrefix + s.Key, s);\n  }\n\n  /**\n   * Watch a configuration setting.\n   *\n   * @param key The key of the setting to watch.\n   */\n  watch<T extends Setting>(key: string): Observable<SettingValueType<T>> {\n    return this.portapi.qsub<BaseSetting<SettingValueType<T>, any>>(this.configPrefix + key)\n      .pipe(\n        filter(value => value.key === this.configPrefix + key), // qsub does a query so filter for our key.\n        map(value => value.data),\n        map(value => value.Value !== undefined ? value.Value : value.DefaultValue),\n        distinctUntilChanged(),\n      )\n  }\n\n  /**\n   * Tests if a value is valid for a given option.\n   *\n   * @param spec The option specification (as returned by get()).\n   * @param value The value that should be tested.\n   */\n  validate<S extends Setting>(spec: S, value: SettingValueType<S>) {\n    if (!spec.ValidationRegex) {\n      return;\n    }\n\n    const re = new RegExp(spec.ValidationRegex);\n\n    switch (spec.OptType) {\n      case OptionType.Int:\n      case OptionType.Bool:\n        // todo(ppacher): do we validate that?\n        return\n      case OptionType.String:\n        if (!re.test(value as string)) {\n          throw new Error(`${value} does not match ${spec.ValidationRegex}`)\n        }\n        return;\n      case OptionType.StringArray:\n        (value as string[]).forEach(v => {\n          if (!re.test(v as string)) {\n            throw new Error(`${value} does not match ${spec.ValidationRegex}`)\n          }\n        });\n        return\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/config.types.ts",
    "content": "import { FeatureID } from './features';\nimport { Record } from './portapi.types';\nimport { deepClone } from './utils';\n\n/**\n * ExpertiseLevel defines all available expertise levels.\n */\nexport enum ExpertiseLevel {\n  User = 'user',\n  Expert = 'expert',\n  Developer = 'developer',\n}\n\nexport enum ExpertiseLevelNumber {\n  user = 0,\n  expert = 1,\n  developer = 2\n}\n\nexport function getExpertiseLevelNumber(lvl: ExpertiseLevel): ExpertiseLevelNumber {\n  switch (lvl) {\n    case ExpertiseLevel.User:\n      return ExpertiseLevelNumber.user;\n    case ExpertiseLevel.Expert:\n      return ExpertiseLevelNumber.expert;\n    case ExpertiseLevel.Developer:\n      return ExpertiseLevelNumber.developer\n  }\n}\n\n/**\n * OptionType defines the type of an option as stored in\n * the backend. Note that ExternalOptionHint may be used\n * to request a different visual representation and edit\n * menu on a per-option basis.\n */\nexport enum OptionType {\n  String = 1,\n  StringArray = 2,\n  Int = 3,\n  Bool = 4,\n}\n\n/**\n * Converts an option type to it's string representation.\n *\n * @param opt The option type to convert\n */\nexport function optionTypeName(opt: OptionType): string {\n  switch (opt) {\n    case OptionType.String:\n      return 'string';\n    case OptionType.StringArray:\n      return '[]string';\n    case OptionType.Int:\n      return 'int'\n    case OptionType.Bool:\n      return 'bool'\n  }\n}\n\n/** The actual type an option value can be */\nexport type OptionValueType = string | string[] | number | boolean;\n\n/** Type-guard for string option types */\nexport function isStringType(opt: OptionType, vt: OptionValueType): vt is string {\n  return opt === OptionType.String;\n}\n\n/** Type-guard for string-array option types */\nexport function isStringArrayType(opt: OptionType, vt: OptionValueType): vt is string[] {\n  return opt === OptionType.StringArray;\n}\n\n/** Type-guard for number option types */\nexport function isNumberType(opt: OptionType, vt: OptionValueType): vt is number {\n  return opt === OptionType.Int;\n}\n\n/** Type-guard for boolean option types */\nexport function isBooleanType(opt: OptionType, vt: OptionValueType): vt is boolean {\n  return opt === OptionType.Bool;\n}\n\n/**\n * ReleaseLevel defines the available release and maturity\n * levels.\n */\nexport enum ReleaseLevel {\n  Stable = 0,\n  Beta = 1,\n  Experimental = 2,\n}\n\nexport function releaseLevelFromName(name: 'stable' | 'beta' | 'experimental'): ReleaseLevel {\n  switch (name) {\n    case 'stable':\n      return ReleaseLevel.Stable;\n    case 'beta':\n      return ReleaseLevel.Beta;\n    case 'experimental':\n      return ReleaseLevel.Experimental;\n  }\n}\n\n/**\n * releaseLevelName returns a string representation of the\n * release level.\n *\n * @args level The release level to convert.\n */\nexport function releaseLevelName(level: ReleaseLevel): string {\n  switch (level) {\n    case ReleaseLevel.Stable:\n      return 'stable'\n    case ReleaseLevel.Beta:\n      return 'beta'\n    case ReleaseLevel.Experimental:\n      return 'experimental'\n  }\n}\n\n/**\n * ExternalOptionHint tells the UI to use a different visual\n * representation and edit menu that the options value would\n * imply.\n */\nexport enum ExternalOptionHint {\n  SecurityLevel = 'security level',\n  EndpointList = 'endpoint list',\n  FilterList = 'filter list',\n  OneOf = 'one-of',\n  OrderedList = 'ordered'\n}\n\n/** A list of well-known option annotation keys. */\nexport enum WellKnown {\n  DisplayHint = \"safing/portbase:ui:display-hint\",\n  Order = \"safing/portbase:ui:order\",\n  Unit = \"safing/portbase:ui:unit\",\n  Category = \"safing/portbase:ui:category\",\n  Subsystem = \"safing/portbase:module:subsystem\",\n  Stackable = \"safing/portbase:options:stackable\",\n  QuickSetting = \"safing/portbase:ui:quick-setting\",\n  Requires = \"safing/portbase:config:requires\",\n  RestartPending = \"safing/portbase:options:restart-pending\",\n  EndpointListVerdictNames = \"safing/portmaster:ui:endpoint-list:verdict-names\",\n  RequiresFeatureID = \"safing/portmaster:ui:config:requires-feature\",\n  RequiresUIReload = \"safing/portmaster:ui:requires-reload\",\n}\n\n/**\n * Annotations describes the annoations object of a configuration\n * setting. Well-known annotations are stricktly typed.\n */\nexport interface Annotations<T extends OptionValueType> {\n  // Well known option annoations and their\n  // types.\n  [WellKnown.DisplayHint]?: ExternalOptionHint;\n  [WellKnown.Order]?: number;\n  [WellKnown.Unit]?: string;\n  [WellKnown.Category]?: string;\n  [WellKnown.Subsystem]?: string;\n  [WellKnown.Stackable]?: true;\n  [WellKnown.QuickSetting]?: QuickSetting<T> | QuickSetting<T>[] | CountrySelectionQuickSetting<T> | CountrySelectionQuickSetting<T>[];\n  [WellKnown.Requires]?: ValueRequirement | ValueRequirement[];\n  [WellKnown.RequiresFeatureID]?: FeatureID | FeatureID[];\n  [WellKnown.RequiresUIReload]?: unknown,\n  // Any thing else...\n  [key: string]: any;\n}\n\nexport interface PossilbeValue<T = any> {\n  /** Name is the name of the value and should be displayed */\n  Name: string;\n  /** Description may hold an additional description of the value */\n  Description: string;\n  /** Value is the actual value expected by the portmaster */\n  Value: T;\n}\n\nexport interface QuickSetting<T extends OptionValueType> {\n  // Name is the name of the quick setting.\n  Name: string;\n  // Value is the value that the quick-setting configures. It must match\n  // the expected value type of the annotated option.\n  Value: T;\n  // Action defines the action of the quick setting.\n  Action: 'replace' | 'merge-top' | 'merge-bottom';\n}\n\nexport interface CountrySelectionQuickSetting<T extends OptionValueType> extends QuickSetting<T> {\n  // Filename of the flag to be used.\n  // In most cases this will be the 2-letter country code, but there are also special flags.\n  FlagID: string;\n}\n\nexport interface ValueRequirement {\n  // Key is the configuration key of the required setting.\n  Key: string;\n  // Value is the required value of the linked setting.\n  Value: any;\n}\n\n/**\n * BaseSetting describes the general shape of a portbase config setting.\n */\nexport interface BaseSetting<T extends OptionValueType, O extends OptionType> extends Record {\n  // Value is the value of a setting.\n  Value?: T;\n  // DefaultValue is the default value of a setting.\n  DefaultValue: T;\n  // Description is a short description.\n  Description?: string;\n  // ExpertiseLevel defines the required expertise level for\n  // this setting to show up.\n  ExpertiseLevel: ExpertiseLevelNumber;\n  // Help may contain a longer help text for this option.\n  Help?: string;\n  // Key is the database key.\n  Key: string;\n  // Name is the name of the option.\n  Name: string;\n  // OptType is the option's basic type.\n  OptType: O;\n  // Annotations holds option specific annotations.\n  Annotations: Annotations<T>;\n  // ReleaseLevel defines the release level of the feature\n  // or settings changed by this option.\n  ReleaseLevel: ReleaseLevel;\n  // RequiresRestart may be set to true if the service requires\n  // a restart after this option has been changed.\n  RequiresRestart?: boolean;\n  // ValidateRegex defines the regex used to validate this option.\n  // The regex is used in Golang but is expected to be valid in\n  // JavaScript as well.\n  ValidationRegex?: string;\n  PossibleValues?: PossilbeValue[];\n\n  // GlobalDefault holds the global default value and is used in the app settings\n  // This property is NOT defined inside the portmaster!\n  GlobalDefault?: T;\n}\n\nexport type IntSetting = BaseSetting<number, OptionType.Int>;\nexport type StringSetting = BaseSetting<string, OptionType.String>;\nexport type StringArraySetting = BaseSetting<string[], OptionType.StringArray>;\nexport type BoolSetting = BaseSetting<boolean, OptionType.Bool>;\n\n/**\n * Apply a quick setting to a value.\n *\n * @param current The current value of the setting.\n * @param qs The quick setting to apply.\n */\nexport function applyQuickSetting<V extends OptionValueType>(current: V | null, qs: QuickSetting<V>): V | null {\n  if (qs.Action === 'replace' || !qs.Action) {\n    return deepClone(qs.Value);\n  }\n\n  if ((!Array.isArray(current) && current !== null) || !Array.isArray(qs.Value)) {\n    console.warn(`Tried to ${qs.Action} quick-setting on non-array type`);\n    return current;\n  }\n\n  const clone = deepClone(current);\n  let missing: any[] = [];\n\n  qs.Value.forEach(val => {\n    if (clone.includes(val)) {\n      return\n    }\n    missing.push(val);\n  });\n\n  if (qs.Action === 'merge-bottom') {\n    return clone.concat(missing) as V;\n  }\n\n  return missing.concat(clone) as V;\n}\n\n/**\n * Parses the ValidationRegex of a setting and returns a list\n * of supported values.\n *\n * @param s The setting to extract support values from.\n */\nexport function parseSupportedValues<S extends Setting>(s: S): SettingValueType<S>[] {\n  if (!s.ValidationRegex) {\n    return [];\n  }\n\n  const values = s.ValidationRegex.match(/\\w+/gmi);\n  const result: SettingValueType<S>[] = [];\n\n  let converter: (s: string) => any;\n\n  switch (s.OptType) {\n    case OptionType.Bool:\n      converter = s => s === 'true';\n      break;\n    case OptionType.Int:\n      converter = s => +s;\n      break;\n    case OptionType.String:\n    case OptionType.StringArray:\n      converter = s => s\n      break\n  }\n\n  values?.forEach(val => {\n    result.push(converter(val))\n  });\n\n  return result;\n}\n\n/**\n * isDefaultValue checks if value is the settings default value.\n * It supports all available settings type and fallsback to use\n * JSON encoded string comparision (JS JSON.stringify is stable).\n */\nexport function isDefaultValue<T extends OptionValueType>(value: T | undefined | null, defaultValue: T): boolean {\n  if (value === undefined) {\n    return true;\n  }\n\n  const isObject = typeof value === 'object';\n  const isDefault = isObject\n    ? JSON.stringify(value) === JSON.stringify(defaultValue)\n    : value === defaultValue;\n\n  return isDefault;\n}\n\n/**\n * SettingValueType is used to infer the type of a settings from it's default value.\n * Use like this:\n *\n *      validate<S extends Setting>(spec: S, value SettingValueType<S>) { ... }\n */\nexport type SettingValueType<S extends Setting> = S extends { DefaultValue: infer T } ? T : any;\n\nexport type Setting = IntSetting\n  | StringSetting\n  | StringArraySetting\n  | BoolSetting;\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/core.types.ts",
    "content": "import { TrackByFunction } from '@angular/core';\n\nexport enum SecurityLevel {\n  Off = 0,\n  Normal = 1,\n  High = 2,\n  Extreme = 4,\n}\n\nexport enum RiskLevel {\n  Off = 'off',\n  Auto = 'auto',\n  Low = 'low',\n  Medium = 'medium',\n  High = 'high'\n}\n\n/** Interface capturing any object that has an ID member. */\nexport interface Identifyable {\n  ID: string | number;\n}\n\n/** A TrackByFunction for all Identifyable objects. */\nexport const trackById: TrackByFunction<Identifyable> = (_: number, obj: Identifyable) => {\n  return obj.ID;\n}\n\nexport function getEnumKey(enumLike: any, value: string | number): string {\n  if (typeof value === 'string') {\n    return value.toLowerCase()\n  }\n\n  return (enumLike[value] as string).toLowerCase()\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/debug-api.service.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { Inject, Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { PORTMASTER_HTTP_API_ENDPOINT } from './portapi.service';\n\n@Injectable({\n  providedIn: 'root',\n})\nexport class DebugAPI {\n  constructor(\n    private http: HttpClient,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpAPI: string,\n  ) { }\n\n  ping(): Observable<string> {\n    return this.http.get(`${this.httpAPI}/v1/ping`, {\n      responseType: 'text'\n    })\n  }\n\n  ready(): Observable<string> {\n    return this.http.get(`${this.httpAPI}/v1/ready`, {\n      responseType: 'text'\n    })\n  }\n\n  getStack(): Observable<string> {\n    return this.http.get(`${this.httpAPI}/v1/debug/stack`, {\n      responseType: 'text'\n    })\n  }\n\n  getDebugInfo(style = 'github'): Observable<string> {\n    return this.http.get(`${this.httpAPI}/v1/debug/info`, {\n      params: {\n        style,\n      },\n      responseType: 'text',\n    })\n  }\n\n  getCoreDebugInfo(style = 'github'): Observable<string> {\n    return this.http.get(`${this.httpAPI}/v1/debug/core`, {\n      params: {\n        style,\n      },\n      responseType: 'text',\n    })\n  }\n\n  getProfileDebugInfo(source: string, id: string, style = 'github'): Observable<string> {\n    return this.http.get(`${this.httpAPI}/v1/debug/network`, {\n      params: {\n        profile: `${source}/${id}`,\n        style,\n      },\n      responseType: 'text',\n    })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/features.ts",
    "content": "export enum FeatureID {\n  None = \"\",\n  SPN = \"spn\",\n  PrioritySupport = \"support\",\n  History = \"history\",\n  Bandwidth = \"bw-vis\",\n  VPNCompat = \"vpn-compat\",\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/meta-api.service.ts",
    "content": "import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';\nimport { Inject, Injectable, Optional } from '@angular/core';\nimport { Observable, of, throwError } from 'rxjs';\nimport { catchError, map } from 'rxjs/operators';\nimport { PORTMASTER_HTTP_API_ENDPOINT } from './portapi.service';\n\nexport interface MetaEndpointParameter {\n  Method: string;\n  Field: string;\n  Value: string;\n  Description: string;\n}\n\nexport interface MetaEndpoint {\n  Path: string;\n  MimeType: string;\n  Read: number;\n  Write: number;\n  Name: string;\n  Description: string;\n  Parameters: MetaEndpointParameter[];\n}\n\nexport interface AuthPermission {\n  Read: number;\n  Write: number;\n  ReadRole: string;\n  WriteRole: string;\n}\n\nexport interface MyProfileResponse {\n  profile: string;\n  source: string;\n  name: string;\n}\n\nexport interface AuthKeyResponse {\n  key: string;\n  validUntil: string;\n}\n\n@Injectable()\nexport class MetaAPI {\n  constructor(\n    private http: HttpClient,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) @Optional() private httpEndpoint: string,\n  ) { \n      if (!this.httpEndpoint) {\n        this.httpEndpoint = `http://localhost:817/api`;\n        console.warn(\"[portmaster-api: MetaAPI] No HTTP API endpoint provided, using default: \" + this.httpEndpoint);\n      }\n  }\n\n  listEndpoints(): Observable<MetaEndpoint[]> {\n    return this.http.get<MetaEndpoint[]>(`${this.httpEndpoint}/v1/endpoints`)\n  }\n\n  permissions(): Observable<AuthPermission> {\n    return this.http.get<AuthPermission>(`${this.httpEndpoint}/v1/auth/permissions`)\n  }\n\n  myProfile(): Observable<MyProfileResponse> {\n    return this.http.get<MyProfileResponse>(`${this.httpEndpoint}/v1/app/profile`)\n  }\n\n  requestApplicationAccess(appName: string, read: 'user' | 'admin' = 'user', write: 'user' | 'admin' = 'user'): Observable<AuthKeyResponse> {\n    let params = new HttpParams()\n      .set(\"app-name\", appName)\n      .set(\"read\", read)\n      .set(\"write\", write)\n\n    return this.http.get<AuthKeyResponse>(`${this.httpEndpoint}/v1/app/auth`, { params })\n  }\n\n  login(bearer: string): Observable<boolean>;\n  login(username: string, password: string): Observable<boolean>;\n  login(usernameOrBearer: string, password?: string): Observable<boolean> {\n    let login: Observable<void>;\n\n    if (!!password) {\n      login = this.http.get<void>(`${this.httpEndpoint}/v1/auth/basic`, {\n        headers: {\n          'Authorization': `Basic ${btoa(usernameOrBearer + \":\" + password)}`\n        }\n      })\n    } else {\n      login = this.http.get<void>(`${this.httpEndpoint}/v1/auth/bearer`, {\n        headers: {\n          'Authorization': `Bearer ${usernameOrBearer}`\n        }\n      })\n    }\n\n    return login.pipe(\n      map(() => true),\n      catchError(err => {\n        if (err instanceof HttpErrorResponse) {\n          if (err.status === 401) {\n            return of(false);\n          }\n        }\n\n        return throwError(() => err)\n      })\n    )\n  }\n\n  logout(): Observable<void> {\n    return this.http.get<void>(`${this.httpEndpoint}/v1/auth/reset`);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/module.ts",
    "content": "import { ModuleWithProviders, NgModule } from \"@angular/core\";\nimport { AppProfileService } from \"./app-profile.service\";\nimport { ConfigService } from \"./config.service\";\nimport { DebugAPI } from \"./debug-api.service\";\nimport { MetaAPI } from \"./meta-api.service\";\nimport { Netquery } from \"./netquery.service\";\nimport { PortapiService, PORTMASTER_HTTP_API_ENDPOINT, PORTMASTER_WS_API_ENDPOINT } from \"./portapi.service\";\nimport { SPNService } from \"./spn.service\";\nimport { WebsocketService } from \"./websocket.service\";\nimport { provideHttpClient, withInterceptors } from '@angular/common/http';\nimport { TauriHttpInterceptor } from \"./platform-specific/tauri/tauri-http-interceptor\";\nimport { IsTauriEnvironment } from \"./platform-specific/utils\";\n\nexport interface ModuleConfig {\n  httpAPI?: string;\n  websocketAPI?: string;\n}\n\n// Factory function to provide the appropriate HTTP client configuration\n//\n// This function determines the appropriate HTTP client configuration based on the runtime environment.\n// If the application is running in a Tauri environment, it uses the TauriHttpInterceptor to ensure\n// that all HTTP requests are made from the application binary instead of the WebView instance.\n// This allows for more direct and controlled communication with the Portmaster API.\n// In other environments (e.g., browser, Electron), the standard HttpClient is used without any interceptors.\nexport function HttpClientProviderFactory() {\n  if (IsTauriEnvironment()) \n  {\n    console.log(\"[portmaster-api] Running under Tauri - using TauriHttpClient\");\n    return provideHttpClient(\n      withInterceptors([TauriHttpInterceptor])\n    );\n  } \n  else \n  {\n    console.log(\"[portmaster-api] Running in browser - using default HttpClient\");\n    return provideHttpClient();\n  }\n}\n\n@NgModule({})\nexport class PortmasterAPIModule {\n\n  /**\n   * Configures a module with additional providers.\n   *\n   * @param cfg The module configuration defining the Portmaster HTTP and Websocket API endpoints.\n   */\n  static forRoot(cfg: ModuleConfig = {}): ModuleWithProviders<PortmasterAPIModule> {\n    if (!cfg.httpAPI) {\n      cfg.httpAPI = `http://${window.location.host}/api`;\n      console.warn(\"[portmaster-api] No HTTP API endpoint provided, using default: \" + cfg.httpAPI);\n    }\n    if (!cfg.websocketAPI) {\n      cfg.websocketAPI = `ws://${window.location.host}/api/database/v1`;\n      console.warn(\"[portmaster-api] No WebSocket API endpoint provided, using default: \" + cfg.websocketAPI);\n    }\n\n    return {\n      ngModule: PortmasterAPIModule,\n      providers: [\n        HttpClientProviderFactory(), \n        PortapiService,\n        WebsocketService,\n        MetaAPI,\n        ConfigService,\n        AppProfileService,\n        DebugAPI,\n        Netquery,\n        SPNService,\n        {\n          provide: PORTMASTER_HTTP_API_ENDPOINT,\n          useValue: cfg.httpAPI,\n        },\n        {\n          provide: PORTMASTER_WS_API_ENDPOINT,\n          useValue: cfg.websocketAPI\n        }\n      ]\n    }\n  }\n\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/netquery.service.ts",
    "content": "import { HttpClient, HttpParams, HttpResponse } from \"@angular/common/http\";\nimport { Inject, Injectable } from \"@angular/core\";\nimport { Observable, forkJoin, of } from \"rxjs\";\nimport { catchError, map, mergeMap } from \"rxjs/operators\";\nimport { AppProfileService } from \"./app-profile.service\";\nimport { AppProfile } from \"./app-profile.types\";\nimport { DNSContext, IPScope, Reason, TLSContext, TunnelContext, Verdict } from \"./network.types\";\nimport { PORTMASTER_HTTP_API_ENDPOINT, PortapiService } from \"./portapi.service\";\nimport { Container } from \"postcss\";\n\nexport interface FieldSelect {\n  field: string;\n}\n\nexport interface FieldAsSelect {\n  $field: {\n    field: string;\n    as: string;\n  }\n}\n\nexport interface Count {\n  $count: {\n    field: string;\n    distinct?: boolean;\n    as?: string;\n  }\n}\n\nexport interface Sum {\n  $sum: {\n    condition: Condition;\n    as: string;\n    distinct?: boolean;\n  } | {\n    field: string;\n    as: string;\n    distinct?: boolean;\n  }\n}\n\nexport interface Min {\n  $min: {\n    condition: Condition;\n    as: string;\n    distinct?: boolean;\n  } | {\n    field: string;\n    as: string;\n    distinct?: boolean;\n  }\n}\n\nexport interface Distinct {\n  $distinct: string;\n}\n\nexport type Select = FieldSelect | FieldAsSelect | Count | Distinct | Sum | Min;\n\nexport interface Equal {\n  $eq: any;\n}\n\nexport interface NotEqual {\n  $ne: any;\n}\n\nexport interface Like {\n  $like: string;\n}\n\nexport interface In {\n  $in: any[];\n}\n\nexport interface NotIn {\n  $notin: string[];\n}\n\nexport interface Greater {\n  $gt: number;\n}\n\nexport interface GreaterOrEqual {\n  $ge: number;\n}\n\nexport interface Less {\n  $lt: number;\n}\n\nexport interface LessOrEqual {\n  $le: number;\n}\n\nexport type Matcher = Equal | NotEqual | Like | In | NotIn | Greater | GreaterOrEqual | Less | LessOrEqual;\n\nexport interface OrderBy {\n  field: string;\n  desc?: boolean;\n}\n\nexport interface Condition {\n  [key: string]: string | Matcher | (string | Matcher)[];\n}\n\nexport interface TextSearch {\n  fields: string[];\n  value: string;\n}\n\nexport enum Database {\n  Live = \"main\",\n  History = \"history\"\n}\n\nexport interface Query {\n  select?: string | Select | (Select | string)[];\n  query?: Condition;\n  orderBy?: string | OrderBy | (OrderBy | string)[];\n  textSearch?: TextSearch;\n  groupBy?: string[];\n  pageSize?: number;\n  page?: number;\n  databases?: Database[];\n}\n\nexport interface NetqueryConnection {\n  id: string;\n  allowed: boolean | null;\n  profile: string;\n  path: string;\n  type: 'dns' | 'ip';\n  external: boolean;\n  ip_version: number;\n  ip_protocol: number;\n  local_ip: string;\n  local_port: number;\n  remote_ip: string;\n  remote_port: number;\n  domain: string;\n  country: string;\n  asn: number;\n  as_owner: string;\n  latitude: number;\n  longitude: number;\n  scope: IPScope;\n  verdict: Verdict;\n  started: string;\n  ended: string;\n  tunneled: boolean;\n  encrypted: boolean;\n  internal: boolean;\n  direction: 'inbound' | 'outbound';\n  profile_revision: number;\n  exit_node?: string;\n  extra_data?: {\n    pid?: number;\n    processCreatedAt?: number;\n    cname?: string[];\n    blockedByLists?: string[];\n    blockedEntities?: string[];\n    reason?: Reason;\n    tunnel?: TunnelContext;\n    dns?: DNSContext;\n    tls?: TLSContext;\n  };\n\n  profile_name: string;\n  active: boolean;\n  bytes_received: number;\n  bytes_sent: number;\n}\n\nexport interface ChartResult {\n  timestamp: number;\n  value: number;\n  countBlocked: number;\n}\n\nexport interface QueryResult extends Partial<NetqueryConnection> {\n  [key: string]: any;\n}\n\nexport interface Identities {\n  exit_node: string;\n  count: number;\n}\n\nexport interface IProfileStats {\n  ID: string;\n  Name: string;\n\n  size: number;\n  empty: boolean;\n  identities: Identities[];\n  countAllowed: number;\n  countUnpermitted: number;\n  countAliveConnections: number;\n  bytes_sent: number;\n  bytes_received: number;\n}\n\ntype BatchResponse<T> = {\n  [key in keyof T]: QueryResult[]\n}\n\ninterface BatchRequest {\n  [key: string]: Query\n}\n\ninterface BandwidthBaseResult {\n  timestamp: number;\n  incoming: number;\n  outgoing: number;\n}\n\nexport type ConnKeys = keyof NetqueryConnection\n\nexport type BandwidthChartResult<K extends ConnKeys> = {\n  [key in K]: NetqueryConnection[K];\n} & BandwidthBaseResult\n\nexport type ProfileBandwidthChartResult = BandwidthChartResult<'profile'>;\n\nexport type ConnectionBandwidthChartResult = BandwidthChartResult<'id'>;\n\n@Injectable({ providedIn: 'root' })\nexport class Netquery {\n  constructor(\n    private http: HttpClient,\n    private profileService: AppProfileService,\n    private portapi: PortapiService,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpAPI: string,\n  ) { }\n\n  query(query: Query, origin: string): Observable<QueryResult[]> {\n    return this.http.post<{ results: QueryResult[] }>(`${this.httpAPI}/v1/netquery/query`, query, {\n      params: new HttpParams().set(\"origin\", origin)\n    })\n      .pipe(map(res => res.results || []));\n  }\n\n  batch<T extends BatchRequest>(queries: T): Observable<BatchResponse<T>> {\n    return this.http.post<BatchResponse<T>>(`${this.httpAPI}/v1/netquery/query/batch`, queries)\n  }\n\n  cleanProfileHistory(profileIDs: string | string[]): Observable<HttpResponse<any>> {\n    return this.http.post(`${this.httpAPI}/v1/netquery/history/clear`,\n      {\n        profileIDs: Array.isArray(profileIDs) ? profileIDs : [profileIDs]\n      },\n      {\n        observe: 'response',\n        responseType: 'text',\n        reportProgress: false,\n      }\n    )\n  }\n\n  profileBandwidthChart(profile?: string[], interval?: number): Observable<{ [profile: string]: ProfileBandwidthChartResult[] }> {\n    const cond: Condition = {}\n    if (!!profile) {\n      cond['profile'] = profile\n    }\n\n    return this.bandwidthChart(cond, ['profile'], interval)\n      .pipe(\n        map(results => {\n          const obj: {\n            [connId: string]: ProfileBandwidthChartResult[]\n          } = {};\n\n          results?.forEach(row => {\n            const arr = obj[row.profile] || []\n            arr.push(row)\n            obj[row.profile] = arr\n          })\n\n          return obj\n        })\n      )\n  }\n\n  bandwidthChart<K extends ConnKeys>(query: Condition, groupBy?: K[], interval?: number): Observable<BandwidthChartResult<K>[]> {\n    return this.http.post<{ results: BandwidthChartResult<K>[] }>(`${this.httpAPI}/v1/netquery/charts/bandwidth`, {\n      interval,\n      groupBy,\n      query,\n    })\n      .pipe(\n        map(response => response.results),\n      )\n  }\n\n  connectionBandwidthChart(connIds: string[], interval?: number): Observable<{ [connId: string]: ConnectionBandwidthChartResult[] }> {\n    const cond: Condition = {}\n    if (!!connIds) {\n      cond['id'] = connIds\n    }\n\n    return this.bandwidthChart(cond, ['id'], interval)\n      .pipe(\n        map(results => {\n          const obj: {\n            [connId: string]: ConnectionBandwidthChartResult[]\n          } = {};\n\n          results?.forEach(row => {\n            const arr = obj[row.id] || []\n            arr.push(row)\n            obj[row.id] = arr\n          })\n\n          return obj\n        })\n      )\n  }\n\n  activeConnectionChart(cond: Condition, textSearch?: TextSearch): Observable<ChartResult[]> {\n    return this.http.post<{ results: ChartResult[] }>(`${this.httpAPI}/v1/netquery/charts/connection-active`, {\n      query: cond,\n      textSearch,\n    })\n      .pipe(map(res => {\n        const now = new Date();\n\n        let data: ChartResult[] = [];\n\n        let lastPoint: ChartResult | null = {\n          timestamp: Math.floor(now.getTime() / 1000 - 600),\n          value: 0,\n          countBlocked: 0,\n        };\n        res.results?.forEach(point => {\n          if (!!lastPoint && lastPoint.timestamp < (point.timestamp - 10)) {\n            for (let i = lastPoint.timestamp; i < point.timestamp; i += 10) {\n              data.push({\n                timestamp: i,\n                value: 0,\n                countBlocked: 0,\n              })\n            }\n          }\n          data.push(point);\n          lastPoint = point;\n        })\n\n        const lastPointTs = Math.round(now.getTime() / 1000);\n        if (!!lastPoint && lastPoint.timestamp < (lastPointTs - 20)) {\n          for (let i = lastPoint.timestamp; i < lastPointTs; i += 20) {\n            data.push({\n              timestamp: i,\n              value: 0,\n              countBlocked: 0\n            })\n          }\n        }\n\n        return data;\n      }));\n  }\n\n  getActiveProfileIDs(): Observable<string[]> {\n    return this.query({\n      select: [\n        'profile',\n      ],\n      groupBy: [\n        'profile',\n      ],\n    }, 'get-active-profile-ids').pipe(\n      map(result => {\n        return result.map(res => res.profile!);\n      })\n    )\n  }\n\n  getActiveProfiles(): Observable<AppProfile[]> {\n    return this.getActiveProfileIDs()\n      .pipe(\n        mergeMap(profiles => forkJoin(profiles.map(pid => this.profileService.getAppProfile(pid))))\n      )\n  }\n\n  getProfileStats(query?: Condition): Observable<IProfileStats[]> {\n    let profileCache = new Map<string, AppProfile>();\n\n    return this.batch({\n      verdicts: {\n        select: [\n          'profile',\n          'verdict',\n          { $count: { field: '*', as: 'totalCount' } },\n        ],\n        groupBy: [\n          'profile',\n          'verdict',\n        ],\n        query: query,\n      },\n\n      conns: {\n        select: [\n          'profile',\n          { $count: { field: '*', as: 'totalCount' } },\n          { $count: { field: 'ended', as: 'countEnded' } },\n          { $sum: { field: 'bytes_sent', as: 'bytes_sent' } },\n          { $sum: { field: 'bytes_received', as: 'bytes_received' } },\n        ],\n        groupBy: [\n          'profile',\n        ],\n        query: query,\n      },\n\n      identities: {\n        select: [\n          'profile',\n          'exit_node',\n          { $count: { field: '*', as: 'totalCount' } }\n        ],\n        groupBy: [\n          'profile',\n          'exit_node',\n        ],\n        query: {\n          ...query,\n          exit_node: {\n            $ne: \"\",\n          },\n        },\n      }\n    }).pipe(\n      map(result => {\n        let statsMap = new Map<string, IProfileStats>();\n\n        const getOrCreate = (id: string) => {\n          let stats = statsMap.get(id) || {\n            ID: id,\n            Name: 'Deleted',\n            countAliveConnections: 0,\n            countAllowed: 0,\n            countUnpermitted: 0,\n            empty: true,\n            identities: [],\n            size: 0,\n            bytes_received: 0,\n            bytes_sent: 0\n          };\n\n          statsMap.set(id, stats);\n          return stats;\n        }\n        result.verdicts?.forEach(res => {\n          const stats = getOrCreate(res.profile!);\n\n          switch (res.verdict) {\n            case Verdict.Accept:\n            case Verdict.RerouteToNs:\n            case Verdict.RerouteToTunnel:\n            case Verdict.Undeterminable:\n              stats.size += res.totalCount\n              stats.countAllowed += res.totalCount;\n              break;\n\n            case Verdict.Block:\n            case Verdict.Drop:\n            case Verdict.Failed:\n            case Verdict.Undecided:\n              stats.size += res.totalCount\n              stats.countUnpermitted += res.totalCount;\n              break;\n          }\n\n          stats.empty = stats.size == 0;\n        })\n\n        result.conns?.forEach(res => {\n          const stats = getOrCreate(res.profile!);\n\n          stats.countAliveConnections = res.totalCount - res.countEnded;\n          stats.bytes_received += res.bytes_received!;\n          stats.bytes_sent += res.bytes_sent!;\n        })\n\n        result.identities?.forEach(res => {\n          const stats = getOrCreate(res.profile!);\n\n          let ident = stats.identities.find(value => value.exit_node === res.exit_node)\n          if (!ident) {\n            ident = {\n              count: 0,\n              exit_node: res.exit_node!,\n            }\n            stats.identities.push(ident);\n          }\n\n          ident.count += res.totalCount;\n        })\n\n        return Array.from(statsMap.values())\n      }),\n      mergeMap(stats => {\n        return forkJoin(stats.map(p => {\n          if (profileCache.has(p.ID)) {\n            return of(profileCache.get(p.ID)!);\n          }\n          return this.profileService.getAppProfile(p.ID)\n            .pipe(catchError(err => {\n              return of(null)\n            }))\n        }))\n          .pipe(\n            map((profiles: (AppProfile | null)[]) => {\n              profileCache = new Map();\n\n              let lm = new Map<string, IProfileStats>();\n              stats.forEach(stat => lm.set(stat.ID, stat));\n\n              profiles\n                .forEach(p => {\n                  if (!p) {\n                    return\n                  }\n\n                  profileCache.set(`${p.Source}/${p.ID}`, p)\n\n                  let stat = lm.get(`${p.Source}/${p.ID}`)\n                  if (!stat) {\n                    return;\n                  }\n\n                  stat.Name = p.Name\n                })\n\n              return Array.from(lm.values())\n            })\n          )\n      })\n    )\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/network.types.ts",
    "content": "import { Record } from './portapi.types';\n\nexport enum Verdict {\n  Undecided = 0,\n  Undeterminable = 1,\n  Accept = 2,\n  Block = 3,\n  Drop = 4,\n  RerouteToNs = 5,\n  RerouteToTunnel = 6,\n  Failed = 7\n}\n\nexport enum IPProtocol {\n  ICMP = 1,\n  IGMP = 2,\n  TCP = 6,\n  UDP = 17,\n  ICMPv6 = 58,\n  UDPLite = 136,\n  RAW = 255, // TODO(ppacher): what is RAW used for?\n}\n\nexport enum IPVersion {\n  V4 = 4,\n  V6 = 6,\n}\n\nexport enum IPScope {\n  Invalid = -1,\n  Undefined = 0,\n  HostLocal = 1,\n  LinkLocal = 2,\n  SiteLocal = 3,\n  Global = 4,\n  LocalMulticast = 5,\n  GlobalMulitcast = 6\n}\n\nlet globalScopes = new Set([IPScope.GlobalMulitcast, IPScope.Global])\nlet localScopes = new Set([IPScope.SiteLocal, IPScope.LinkLocal, IPScope.LocalMulticast])\n\n// IsGlobalScope returns true if scope represents a globally\n// routed destination.\nexport function IsGlobalScope(scope: IPScope): scope is IPScope.GlobalMulitcast | IPScope.Global {\n  return globalScopes.has(scope);\n}\n\n// IsLocalScope returns true if scope represents a locally\n// routed destination.\nexport function IsLANScope(scope: IPScope): scope is IPScope.SiteLocal | IPScope.LinkLocal | IPScope.LocalMulticast {\n  return localScopes.has(scope);\n}\n\n// IsLocalhost returns true if scope represents localhost.\nexport function IsLocalhost(scope: IPScope): scope is IPScope.HostLocal {\n  return scope === IPScope.HostLocal;\n}\n\nconst deniedVerdicts = new Set([\n  Verdict.Drop,\n  Verdict.Block,\n])\n// IsDenied returns true if the verdict v represents a\n// deny or block decision.\nexport function IsDenied(v: Verdict): boolean {\n  return deniedVerdicts.has(v);\n}\n\nexport interface CountryInfo {\n  Code: string;\n\tName: string;\n\tCenter: GeoCoordinates;\n  Continent: ContinentInfo;\n}\n\nexport interface ContinentInfo {\n  Code: string;\n  Region: string;\n  Name: string;\n}\n\nexport interface GeoCoordinates {\n  AccuracyRadius: number;\n  Latitude: number;\n  Longitude: number;\n}\n\nexport const UnknownLocation: GeoCoordinates = {\n  AccuracyRadius: 0,\n  Latitude: 0,\n  Longitude: 0\n}\n\nexport interface IntelEntity {\n  // Protocol is the IP protocol used to connect/communicate\n  // the the described entity.\n  Protocol: IPProtocol;\n  // Port is the remote port number used.\n  Port: number;\n  // Domain is the domain name of the entity. This may either\n  // be the domain name used in the DNS request or the\n  // named returned from reverse PTR lookup.\n  Domain: string;\n  // CNAME is a list of CNAMEs that have been used\n  // to resolve this entity.\n  CNAME: string[] | null;\n  // IP is the IP address of the entity.\n  IP: string;\n  // IPScope holds the classification of the IP address.\n  IPScope: IPScope;\n  // Country holds the country of residence of the IP address.\n  Country: string;\n  // ASN holds the number of the autonoumous system that operates\n  // the IP.\n  ASN: number;\n  // ASOrg holds the AS owner name.\n  ASOrg: string;\n  // Coordinates contains the geographic coordinates of the entity.\n  Coordinates: GeoCoordinates | null;\n  // BlockedByLists holds a list of filter list IDs that\n  // would have blocked the entity.\n  BlockedByLists: string[] | null;\n  // BlockedEntities holds a list of entities that have been\n  // blocked by filter lists. Those entities can be ASNs, domains,\n  // CNAMEs, IPs or Countries.\n  BlockedEntities: string[] | null;\n  // ListOccurences maps the blocked entity (see BlockedEntities)\n  // to a list of filter-list IDs that contains it.\n  ListOccurences: { [key: string]: string[] } | null;\n}\n\nexport enum ScopeIdentifier {\n  IncomingHost = \"IH\",\n  IncomingLAN = \"IL\",\n  IncomingInternet = \"II\",\n  IncomingInvalid = \"IX\",\n  PeerHost = \"PH\",\n  PeerLAN = \"PL\",\n  PeerInternet = \"PI\",\n  PeerInvalid = \"PX\"\n}\n\nexport const ScopeTranslation: { [key: string]: string } = {\n  [ScopeIdentifier.IncomingHost]: \"Device-Local Incoming\",\n  [ScopeIdentifier.IncomingLAN]: \"LAN Incoming\",\n  [ScopeIdentifier.IncomingInternet]: \"Internet Incoming\",\n  [ScopeIdentifier.PeerHost]: \"Device-Local Outgoing\",\n  [ScopeIdentifier.PeerLAN]: \"LAN Peer-to-Peer\",\n  [ScopeIdentifier.PeerInternet]: \"Internet Peer-to-Peer\",\n  [ScopeIdentifier.IncomingInvalid]: \"N/A\",\n  [ScopeIdentifier.PeerInvalid]: \"N/A\",\n}\n\nexport interface ProcessContext {\n  BinaryPath: string;\n  ProcessName: string;\n  ProfileName: string;\n  PID: number;\n  Profile: string;\n  Source: string\n}\n\n// Reason justifies the decision on a connection\n// verdict.\nexport interface Reason {\n  // Msg holds a human readable message of the reason.\n  Msg: string;\n  // OptionKey, if available, holds the key of the\n  // configuration option that caused the verdict.\n  OptionKey: string;\n  // Profile holds the profile the option setting has\n  // been configured in.\n  Profile: string;\n  // Context may holds additional data about the reason.\n  Context: any;\n}\n\nexport enum ConnectionType {\n  Undefined = 0,\n  IPConnection = 1,\n  DNSRequest = 2\n}\n\nexport function IsDNSRequest(t: ConnectionType): t is ConnectionType.DNSRequest {\n  return t === ConnectionType.DNSRequest;\n}\n\nexport function IsIPConnection(t: ConnectionType): t is ConnectionType.IPConnection {\n  return t === ConnectionType.IPConnection;\n}\n\nexport interface DNSContext {\n  Domain: string;\n  ServedFromCache: boolean;\n  RequestingNew: boolean;\n  IsBackup: boolean;\n  Filtered: boolean;\n  FilteredEntries: string[], // RR\n  Question: 'A' | 'AAAA' | 'MX' | 'TXT' | 'SOA' | 'SRV' | 'PTR' | 'NS' | string;\n  RCode: 'NOERROR' | 'SERVFAIL' | 'NXDOMAIN' | 'REFUSED' | string;\n  Modified: string;\n  Expires: string;\n}\n\nexport interface TunnelContext {\n  Path: TunnelNode[];\n  PathCost: number;\n  RoutingAlg: 'default';\n}\n\nexport interface GeoIPInfo {\n  IP: string;\n  Country: string;\n  ASN: number;\n  ASOwner: string;\n}\n\nexport interface TunnelNode {\n  ID: string;\n  Name: string;\n  IPv4?: GeoIPInfo;\n  IPv6?: GeoIPInfo;\n\n}\n\nexport interface CertInfo<dateType extends string | Date = string> {\n  Subject: string;\n  Issuer: string;\n  AlternateNames: string[];\n  NotBefore: dateType;\n  NotAfter: dateType;\n}\n\nexport interface TLSContext {\n  Version: string;\n  VersionRaw: number;\n  SNI: string;\n  Chain: CertInfo[][];\n}\n\nexport interface Connection extends Record {\n  // ID is a unique ID for the connection.\n  ID: string;\n  // Type defines the connection type.\n  Type: ConnectionType;\n  // TLS may holds additional data for the TLS\n  // session.\n  TLS: TLSContext | null;\n  // DNSContext holds additional data about the DNS request for\n  // this connection.\n  DNSContext: DNSContext | null;\n  // TunnelContext holds additional data about the SPN tunnel used for\n  // the connection.\n  TunnelContext: TunnelContext | null;\n  // Scope defines the scope of the connection. It's an somewhat\n  // weired field that may contain a ScopeIdentifier or a string.\n  // In case of a string it may eventually be interpreted as a\n  // domain name.\n  Scope: ScopeIdentifier | string;\n  // IPVersion is the version of the IP protocol used.\n  IPVersion: IPVersion;\n  // Inbound is true if the connection is incoming to\n  // hte local system.\n  Inbound: boolean;\n  // IPProtocol is the protocol used by the connection.\n  IPProtocol: IPProtocol;\n  // LocalIP is the local IP address that is involved into\n  // the connection.\n  LocalIP: string;\n  // LocalIPScope holds the classification of the local IP\n  // address;\n  LocalIPScope: IPScope;\n  // LocalPort is the local port that is involved into the\n  // connection.\n  LocalPort: number;\n  // Entity describes the remote entity that is part of the\n  // connection.\n  Entity: IntelEntity;\n  // Verdict defines the final verdict.\n  Verdict: Verdict;\n  // Reason is the reason justifying the verdict of the connection.\n  Reason: Reason;\n  // Started holds the number of seconds in UNIX epoch time at which\n  // the connection was initiated.\n  Started: number;\n  // End dholds the number of seconds in UNIX epoch time at which\n  // the connection was considered terminated.\n  Ended: number;\n  // Tunneled is set to true if the connection was tunneled through the\n  // SPN.\n  Tunneled: boolean;\n  // VerdictPermanent is set to true if the connection was marked and\n  // handed back to the operating system.\n  VerdictPermanent: boolean;\n  // Inspecting is set to true if the connection is being inspected.\n  Inspecting: boolean;\n  // Encrypted is set to true if the connection is estimated as being\n  // encrypted. Interpreting this field must be done with care!\n  Encrypted: boolean;\n  // Internal is set to true if this connection is done by the Portmaster\n  // or any associated helper processes/binaries itself.\n  Internal: boolean;\n  // ProcessContext holds additional information about the process\n  // that initated the connection.\n  ProcessContext: ProcessContext;\n  // ProfileRevisionCounter is used to track changes to the process\n  // profile.\n  ProfileRevisionCounter: number;\n}\n\nexport interface ReasonContext {\n  [key: string]: any;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/platform-specific/tauri/tauri-http-interceptor.ts",
    "content": "import { HttpEvent, HttpHandlerFn, HttpRequest, HttpResponse, HttpHeaders, HttpErrorResponse } from '@angular/common/http';\nimport { from, Observable, switchMap, map, catchError, throwError } from 'rxjs';\nimport { invoke } from '@tauri-apps/api/core'\nimport { inject } from '@angular/core';\nimport { PORTMASTER_HTTP_API_ENDPOINT } from '../../portapi.service';\n\n/**\n * TauriHttpInterceptor intercepts HTTP requests and routes them through Tauri's `@tauri-apps/plugin-http` API.\n * \n * This allows HTTP requests to be executed from the Tauri application binary instead of the WebView, \n * enabling more secure and direct communication with external APIs.\n * \n * The interceptor handles various response types (e.g., JSON, text, blob, arraybuffer) and ensures\n * that headers and response data are properly mapped to Angular's HttpResponse format.\n * \n * References:\n * - https://angular.dev/guide/http/interceptors \n */\nexport function TauriHttpInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {\n    const httpApiEndpoint = inject(PORTMASTER_HTTP_API_ENDPOINT);\n    if (httpApiEndpoint && !req.url.startsWith(httpApiEndpoint)) {\n        // If the request URL does not start with the configured HTTP API endpoint, skip interception\n        console.log('[TauriHttpInterceptor] Non-API request, skipping interception:', req.url);\n        return next(req);\n    }\n\n    const fetchOptions: RequestInit = {\n        method: req.method,\n        headers: req.headers.keys().reduce((acc: Record<string, string>, key) => {\n            acc[key] = req.headers.get(key) || '';\n            return acc;\n        }, {}),\n        body: getRequestBody(req),\n    };\n    //console.log('[TauriHttpInterceptor] Fetching:', req.url, \"Headers:\", fetchOptions.headers);\n    return from(send_tauri_http_request(req.url, fetchOptions)).pipe(\n        switchMap(response => {\n            // Copy all response headers\n            const headerMap: Record<string, string> = {};                \n            response.headers.forEach((value: string, key: string) => {\n                headerMap[key] = value;\n            });                \n            const headers = new HttpHeaders(headerMap);\n\n            // Check if response status is ok (2xx)\n            if (!response.ok) {\n                // Get the error content\n                return from(response.text()).pipe(\n                    map(errorText => {\n                        throw new HttpErrorResponse({\n                            error: errorText,\n                            headers: headers,\n                            status: response.status,\n                            statusText: response.statusText,\n                            url: req.url\n                        });\n                    })\n                );\n            }\n            \n            // Get the response type from the request\n            const responseType = req.responseType || 'json';\n                \n            // Helper function to create HttpResponse from body\n            const createResponse = (body: any): HttpEvent<unknown> => {\n                return new HttpResponse({\n                    body,\n                    status: response.status,\n                    headers: headers,\n                    url: req.url\n                }) as HttpEvent<unknown>;\n            };\n                \n            switch (responseType) {\n                case 'text':\n                    return from(response.text()).pipe(map(createResponse));\n                case 'arraybuffer':\n                    return from(response.arrayBuffer()).pipe(map(createResponse));\n                case 'blob':\n                    return from(response.blob()).pipe(\n                        map(blob => {\n                            const contentType = response.headers.get('content-type') || '';\n                            // Create a new blob with the proper MIME type\n                            if (contentType && (!blob.type || blob.type === 'application/octet-stream')) {\n                                const typedBlob = new Blob([blob], { type: contentType });\n                                return createResponse(typedBlob);\n                            }\n                            \n                            return createResponse(blob);\n                        })\n                    );\n                case 'json':\n                default:\n                    return from(response.text()).pipe(\n                        map(body => {\n                            let parsedBody: any;\n                            try {\n                                // Only attempt to parse as JSON if we have content\n                                // and either explicitly requested JSON or content-type is JSON\n                                if (body && (responseType === 'json' || \n                                    (response.headers.get('content-type') || '').includes('application/json'))) {\n                                    parsedBody = JSON.parse(body);\n                                } else {\n                                    parsedBody = body;\n                                }\n                            } catch (e) {\n                                console.warn('[TauriHttpInterceptor] Failed to parse JSON response:', e);\n                                parsedBody = body;\n                            }\n                            return createResponse(parsedBody);\n                        })\n                    );\n            }\n        }),\n        catchError(error => {\n            console.error('[TauriHttpInterceptor] Request failed:', error);\n            \n            // If it's already an HttpErrorResponse, just return it\n            if (error instanceof HttpErrorResponse) {\n                return throwError(() => error);\n            }\n            \n            // Otherwise create a new HttpErrorResponse with available information\n            return throwError(() => new HttpErrorResponse({\n                error: error.message || 'Unknown error occurred',\n                status: error.status || 0,\n                statusText: error.statusText || 'Unknown Error',\n                url: req.url,\n                headers: error.headers ? new HttpHeaders(error.headers) : new HttpHeaders()\n            }));\n        })\n    );\n}\n\nfunction getRequestBody(req: HttpRequest<unknown>): any {\n    if (!req.body) {\n        return undefined;\n    }\n    \n    // Handle different body types properly\n    if (req.body instanceof FormData || \n        req.body instanceof Blob || \n        req.body instanceof ArrayBuffer ||\n        req.body instanceof URLSearchParams) {\n        return req.body;\n    }\n    \n    // Default to JSON stringify for object data\n    return JSON.stringify(req.body);\n}\n\nexport async function send_tauri_http_request(\n    url: string,\n    init: RequestInit = {}\n  ): Promise<Response> {\n    // Extract method, headers, and body buffer\n    const method = init.method || 'GET';\n    const headers = [...(init.headers instanceof Headers\n      ? (() => {\n          const headerArray: [string, string][] = [];\n          init.headers.forEach((value, key) => headerArray.push([key, value]));\n          return headerArray;\n        })()\n      : Object.entries(init.headers || {}))];\n\n    let body: Uint8Array | undefined;\n    if (init.body) {\n        if (typeof init.body === 'string') {\n            // Most efficient way to convert a string to Uint8Array\n            body = new TextEncoder().encode(init.body);\n        } else if (init.body instanceof ArrayBuffer) {\n            body = new Uint8Array(init.body);\n        } else if (init.body instanceof Uint8Array) {\n            body = init.body;\n        } else if (init.body instanceof Blob) {\n            // Efficiently read Blob data\n            body = new Uint8Array(await init.body.arrayBuffer());\n        } else if (init.body instanceof URLSearchParams) {\n            body = new TextEncoder().encode(init.body.toString());\n        } else {\n            // Fallback for other types, though the inefficient path is kept for unsupported types\n            // This path should ideally be avoided by handling types in getRequestBody.\n            console.warn('[TauriHttpInterceptor] Using inefficient body conversion for unknown type.');\n            body = new Uint8Array(await new Response(init.body as any).arrayBuffer());\n        }\n    }\n  \n    const res = await invoke<{\n      status: number;\n      status_text: string;\n      headers: [string, string][];\n      body: number[];\n    }>('send_tauri_http_request', { url, opts: { method, headers, body: body ? Array.from(body) : undefined } });\n                                  \n    return new Response(new Uint8Array(res.body), {\n      status: res.status,\n      statusText: res.status_text,\n      headers: res.headers,\n    });\n  }"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/platform-specific/tauri/tauri-websocket-subject.ts",
    "content": "import WebSocket, { Message } from '@tauri-apps/plugin-websocket';\nimport { Subject, Observable, merge, mergeMap, throwError } from 'rxjs';\nimport { WebSocketSubject, WebSocketSubjectConfig } from 'rxjs/webSocket';\n\nconst LOG_PREFIX        = '[tauri_ws]';\nconst PING_INTERVAL_MS  = 10000;  // Send a ping every PING_INTERVAL_MS milliseconds\nconst PONG_TIMEOUT_MS   = 5000;   // Wait PONG_TIMEOUT_MS milliseconds for a pong response\n/**\n * Creates a WebSocket connection using the Tauri WebSocket API and wraps it in an RxJS WebSocketSubject-compatible interface.\n *\n * @template T - The type of messages sent and received through the WebSocket.\n * @param {WebSocketSubjectConfig<T>} opts - Configuration options for the WebSocket connection.\n * @returns {WebSocketSubject<T>} - An RxJS WebSocketSubject-compatible object for interacting with the WebSocket.\n * @throws {Error} If the `serializer` or `deserializer` functions are not provided.\n *\n * @example\n * const wsSubject = createTauriWsConnection({\n *   url: 'ws://example.com',\n *   serializer: JSON.stringify,\n *   deserializer: JSON.parse,\n *   openObserver: { next: () => console.log('Connection opened') },\n *   closeObserver: { next: () => console.log('Connection closed') },\n *   closingObserver: { next: () => console.log('Connection closing') },\n * }, ngZone);\n */\nexport function createTauriWsConnection<T>(opts: WebSocketSubjectConfig<T>): WebSocketSubject<T> {\n    if (!opts.serializer)   throw new Error(`${LOG_PREFIX} Messages Serializer not provided!`);\n    if (!opts.deserializer) throw new Error(`${LOG_PREFIX} Messages Deserializer not provided!`);\n    \n    const serializer = opts.serializer;\n    const deserializer = opts.deserializer;\n    \n    let wsConnection: WebSocket | null = null;\n    const messageSubject = new Subject<T>();\n    const errorSubject   = new Subject<any>(); // Added for error propagation\n\n    // Combined stream with both messages and errors\n    const observable$ = merge(\n      messageSubject.asObservable(),\n      errorSubject.pipe(\n        mergeMap(err => throwError(() => err))\n      )\n    );\n\n    //////////////////////////////////////////////////////////////\n    // Track subscriptions\n    //////////////////////////////////////////////////////////////\n    let subscriptionCount = 0;\n\n    // Wrapper with subscription tracking\n    const trackedObservable$ = new Observable<T>(subscriber => {\n      subscriptionCount++;\n\n      // If this is the first subscription, connect to WebSocket\n      if (subscriptionCount === 1) {\n          connect();\n      }\n\n      const subscription = observable$.subscribe({\n        next: value => subscriber.next(value),\n        error: err => subscriber.error(err),\n        complete: () => subscriber.complete()\n      });\n      \n      // Cleanup function - called when unsubscribed\n      return () => {\n        subscriptionCount--;        \n        subscription.unsubscribe();\n\n        // If this was the last subscription, close the WebSocket connection\n        if (subscriptionCount === 0) {\n          disconnect();\n        } \n      };\n    });\n    \n    //////////////////////////////////////////////////////////////\n    // Function to establish a WebSocket connection\n    //////////////////////////////////////////////////////////////\n    let listenerRemovalFn: (() => void) | null = null; // Store the removal function for the ws listener\n\n    const connect = (): void => {\n      console.log(`${LOG_PREFIX} Connecting to WebSocket: ${opts.url}`);\n      WebSocket.connect(opts.url)\n          .then((ws) => {\n              wsConnection = ws;\n              lastMessageReceivedTime = 0;\n              console.log(`${LOG_PREFIX} Connection established`);\n              opts.openObserver?.next(undefined as unknown as Event);\n              listenerRemovalFn = ws.addListener(messagesListener);\n              startHealthChecks();\n          })\n          .catch((error: Error) => {                \n              console.error(`${LOG_PREFIX} Connection failed:`, error);\n              errorSubject.next(error);\n          });\n    };\n\n    const disconnect = (): void => {\n      stopHealthChecks();\n\n      if (listenerRemovalFn) {\n        try {\n            listenerRemovalFn();            \n        } catch (err) {\n            console.error(`${LOG_PREFIX} Error removing listener:`, err);\n        }\n        listenerRemovalFn = null; // Clear the reference\n      }\n\n      const currentWs = wsConnection;\n      wsConnection = null;\n\n      if (!currentWs) return;\n\n      console.log(`${LOG_PREFIX} Closing WebSocket connection.`);\n      opts.closeObserver?.next(undefined as unknown as CloseEvent);\n      currentWs.disconnect().catch(err => console.warn(`${LOG_PREFIX} Error closing connection:`, err));\n    }\n\n    //////////////////////////////////////////////////////////////\n    // Function to check if connection alive\n    //////////////////////////////////////////////////////////////    \n    let healthCheckIntervalId: ReturnType<typeof setInterval> | null = null;\n    let pongTimeoutId: ReturnType<typeof setTimeout> | null = null;\n\n    const startHealthChecks = () => {\n        stopHealthChecks(); // Ensure no multiple intervals are running\n        healthCheckIntervalId = setInterval(() => {\n            if (!wsConnection) {\n                stopHealthChecks();\n                return;\n            }\n            if (pongTimeoutId) {\n                // Ping already in flight, waiting for pong.\n                return;\n            }\n\n            wsConnection.send({ type: 'Ping', data: [] })\n                .then(() => {\n                    pongTimeoutId = setTimeout(() => {\n                        console.error(`${LOG_PREFIX} No Pong received. Connection is likely dead.`);\n                        errorSubject.next(new Error('Connection timed out'));\n                        stopHealthChecks();\n                    }, PONG_TIMEOUT_MS);\n                })\n                .catch(err => {\n                    console.error(`${LOG_PREFIX} Ping send failed:`, err);\n                    errorSubject.next(new Error(`Ping send failed: ${err}`));\n                    stopHealthChecks();\n                });\n        }, PING_INTERVAL_MS);\n    };\n\n    const stopHealthChecks = () => {\n        if (healthCheckIntervalId) {\n            clearInterval(healthCheckIntervalId);\n            healthCheckIntervalId = null;\n        }\n        if (pongTimeoutId) {\n            clearTimeout(pongTimeoutId);\n            pongTimeoutId = null;\n        }\n    };\n\n    //////////////////////////////////////////////////////////////\n    // Track last message received time to detect inactivity timeout\n    // If no message received for INACTIVITY_TIMEOUT_MS, \n    // assume connection was paused due to OS hibernation or similar.\n    //////////////////////////////////////////////////////////////\n    const INACTIVITY_TIMEOUT_MS = 1000 * 60 * 15; // 15 minutes inactivity timeout\n    let lastMessageReceivedTime: number = 0;\n    const checkReceivedMessageTime = () => {\n      if ((Date.now() - lastMessageReceivedTime) > INACTIVITY_TIMEOUT_MS && lastMessageReceivedTime>0) {\n        console.error(`${LOG_PREFIX} Inactivity timeout reached. Assuming connection was paused.`);\n        errorSubject.next(new Error('Inactivity timeout'));\n      }\n      lastMessageReceivedTime = Date.now();\n    }\n    \n    //////////////////////////////////////////////////////////////\n    // Messages listener\n    //////////////////////////////////////////////////////////////\n    const messagesListener = (message: Message) => {\n      checkReceivedMessageTime(); // Update last message received time\n      try {\n        switch (message.type) {\n          case 'Text':\n            try {\n              const deserializedMessage = deserializer({ data: message.data as string } as any);\n              messageSubject.next(deserializedMessage);\n            } catch (err) {\n              console.error(`${LOG_PREFIX} Error deserializing text message:`, err);\n            }\n            break;\n              \n          case 'Binary':\n            try {\n              const uint8Array = new Uint8Array(message.data as number[]);\n              const deserializedMessage = deserializer({ data: uint8Array.buffer } as any);\n              messageSubject.next(deserializedMessage);\n            } catch (err) {\n                console.error(`${LOG_PREFIX} Error deserializing binary message:`, err);\n            }\n            break;\n              \n          case 'Close':\n            console.warn(`${LOG_PREFIX} Connection closed by server: ${message}`); \n            errorSubject.next(new Error(`Connection closed by server: ${message}`)); \n            break;\n              \n          case 'Ping':\n            break;\n\n          case 'Pong':\n            // Pong received, clear the timeout.                     \n            if (pongTimeoutId) {\n                clearTimeout(pongTimeoutId);\n                pongTimeoutId = null;\n            }\n            break;\n\n          // All other message types are unexpected. Proceed with reconnect.\n          default:\n            console.warn(`${LOG_PREFIX} Received unexpected message: '${message}'`);                      \n            break;\n        }\n      } catch (error) {\n          console.error(`${LOG_PREFIX} Error processing message: `, error);\n      }\n    }\n    \n    //////////////////////////////////////////////////////////////\n    // RxJS WebSocketSubject-compatible interface\n    //////////////////////////////////////////////////////////////\n    const webSocketSubject = {\n      asObservable: () => trackedObservable$,\n      next: (message: T) => {\n        if (!wsConnection) {\n          errorSubject.next(new Error('Connection not established'));\n          return;\n        }\n        try {\n          const serializedMessage = serializer(message);          \n          // 'string' type is enough here, since default serializer for portmaster message returns string\n          if (typeof serializedMessage !== 'string') \n            throw new Error('Serialized message is not a string');\n\n          wsConnection?.send(serializedMessage).catch((err: Error) => {\n            console.error(`${LOG_PREFIX} Error sending message:`, err);\n            errorSubject.next(err);\n          });\n        } catch (error) {\n          console.error(`${LOG_PREFIX} Error serializing message:`, error);\n          return;\n        }\n      },\n      complete: () => {\n        if (wsConnection) {\n          opts.closingObserver?.next();       \n          disconnect();\n        }        \n        messageSubject.complete();        \n      },\n      subscribe: trackedObservable$.subscribe.bind(trackedObservable$),\n      pipe: trackedObservable$.pipe.bind(trackedObservable$),      \n    };\n\n    return webSocketSubject as unknown as WebSocketSubject<T>;\n}"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/platform-specific/utils.ts",
    "content": "// Simple function to detect if the app is running in a Tauri environment\nexport function IsTauriEnvironment(): boolean {\n  return '__TAURI__' in window;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/portapi.service.ts",
    "content": "import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';\nimport {\n  Inject,\n  Injectable,\n  InjectionToken,\n  isDevMode,\n  NgZone,\n} from '@angular/core';\nimport { BehaviorSubject, Observable, Observer, of } from 'rxjs';\nimport {\n  concatMap,\n  delay,\n  filter,\n  map,\n  retryWhen,\n  takeWhile,\n  tap,\n  bufferTime,\n} from 'rxjs/operators';\nimport { WebSocketSubject } from 'rxjs/webSocket';\nimport {\n  DataReply,\n  deserializeMessage,\n  DoneReply,\n  ImportResult,\n  InspectedActiveRequest,\n  isCancellable,\n  isDataReply,\n  ProfileImportResult,\n  Record,\n  ReplyMessage,\n  Requestable,\n  RequestMessage,\n  RequestType,\n  RetryableOpts,\n  retryPipeline,\n  serializeMessage,\n  WatchOpts,\n} from './portapi.types';\nimport { WebsocketService } from './websocket.service';\n\nexport const PORTMASTER_WS_API_ENDPOINT = new InjectionToken<string>(\n  'PortmasterWebsocketEndpoint'\n);\nexport const PORTMASTER_HTTP_API_ENDPOINT = new InjectionToken<string>(\n  'PortmasterHttpApiEndpoint'\n);\n\nexport const RECONNECT_INTERVAL = 2000;\n\nlet uniqueRequestId = 0;\n\ninterface PendingMethod {\n  observer: Observer<ReplyMessage>;\n  request: RequestMessage;\n}\n\n@Injectable()\nexport class PortapiService {\n  /** The actual websocket connection, auto-(re)connects on subscription */\n  private ws$: WebSocketSubject<ReplyMessage | RequestMessage> | null;\n\n  /** used to emit changes to our \"connection state\" */\n  private connectedSubject = new BehaviorSubject(false);\n\n  /** A map to multiplex websocket messages to the actual observer/initator */\n  private _streams$ = new Map<string, Observer<ReplyMessage<any>>>();\n\n  /** Map to keep track of \"still-to-send\" requests when we are currently disconnected */\n  private _pendingCalls$ = new Map<string, PendingMethod>();\n\n  /** Whether or not we are currently connected. */\n  get connected$() {\n    return this.connectedSubject.asObservable();\n  }\n\n  /** @private DEBUGGING ONLY - keeps track of current requests and supports injecting messages  */\n  readonly activeRequests = new BehaviorSubject<{\n    [key: string]: InspectedActiveRequest;\n  }>({});\n\n  constructor(\n    private websocketFactory: WebsocketService,\n    private ngZone: NgZone,\n    private http: HttpClient,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpEndpoint: string,\n    @Inject(PORTMASTER_WS_API_ENDPOINT) private wsEndpoint: string\n  ) {\n    // create a new websocket connection that will auto-connect\n    // on the first subscription and will automatically reconnect\n    // with consecutive subscribers.\n    this.ws$ = this.createWebsocket();\n\n    // no need to keep a reference to the subscription as we're not going\n    // to unsubscribe ...\n    this.ws$\n      .pipe(\n        retryWhen((errors) =>\n          errors.pipe(\n            // use concatMap to keep the errors in order and make sure\n            // they don't execute in parallel.\n            concatMap((e, i) =>\n              of(e).pipe(\n                // We need to forward the error to all streams here because\n                // due to the retry feature the subscriber below won't see\n                // any error at all.\n                tap(() => {\n                  this._streams$.forEach((observer) => observer.error(e));\n                  this._streams$.clear();\n                }),\n                delay(1000)\n              )\n            )\n          )\n        ),\n        // Buffer all incoming messages for X ms. This creates batches (arrays of messages).\n        bufferTime(25),\n        // Don't process empty batches that can occur during idle periods.\n        filter(batch => batch.length > 0),\n      )\n      .subscribe(\n        // The subscriber now receives an array of messages (a batch).\n        (batch) => {\n          // Re-enter the Angular Zone ONCE for the entire batch.\n          this.ngZone.run(() => {\n            for (const msg of batch) {\n              const observer = this._streams$.get(msg.id);\n              if (!observer) {\n                // it's expected that we receive done messages from time to time here\n                // as portmaster sends a \"done\" message after we \"cancel\" a subscription\n                // and we already remove the observer from _streams$ if the subscription\n                // is unsubscribed. So just hide that warning message for \"done\"\n                if (msg.type !== 'done') {\n                  console.warn(`Received message for unknown request id ${msg.id} (type=${msg.type})`, msg);\n                }\n                continue;\n              }\n              \n              // forward the message to the actual stream.\n              observer.next(msg as ReplyMessage);\n            }\n          });\n        },\n        console.error,\n        () => {\n          // This should actually never happen but if, make sure\n          // we handle it ...\n          this._streams$.forEach((observer) => observer.complete());\n          this._streams$.clear();\n        }\n      );\n  }\n\n  /** Triggers a restart of the portmaster service */\n  restartPortmaster(): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/core/restart`, undefined, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n    });\n  }\n\n  /** Triggers a shutdown of the portmaster service */\n  shutdownPortmaster(): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/core/shutdown`, undefined, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n    });\n  }\n\n  /** Triggers a pause of the portmaster or SPN service\n   * @param duration The duration of the pause in seconds\n   * @param onlySPN Whether or not only the SPN should be paused\n   */\n  pause(duration: number, onlySPN: boolean): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/control/pause`, { duration, onlySPN }, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n    });\n  }\n  /** Triggers a resume of the portmaster (and SPN) service */\n  resume(): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/control/resume`, undefined, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n    });\n  }  \n  /** Force the portmaster to check for updates */\n  checkForUpdates(): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/updates/check`, undefined, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n      reportProgress: false,\n    });\n  }\n\n  /** Force a reload of the UI assets */\n  reloadUI(): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/ui/reload`, undefined, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n    });\n  }\n\n  /** Clear DNS cache */\n  clearDNSCache(): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/dns/clear`, undefined, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n    });\n  }\n\n  /** Reset the broadcast notifications state */\n  resetBroadcastState(): Observable<any> {\n    return this.http.post(\n      `${this.httpEndpoint}/v1/broadcasts/reset-state`,\n      undefined,\n      { observe: 'response', responseType: 'arraybuffer' }\n    );\n  }\n\n  /** Re-initialize the SPN */\n  reinitSPN(): Observable<any> {\n    return this.http.post(`${this.httpEndpoint}/v1/spn/reinit`, undefined, {\n      observe: 'response',\n      responseType: 'arraybuffer',\n    });\n  }\n\n  /** Cleans up the history database by applying history retention settings */\n  cleanupHistory(): Observable<any> {\n    return this.http.post(\n      `${this.httpEndpoint}/v1/netquery/history/cleanup`,\n      undefined,\n      { observe: 'response', responseType: 'arraybuffer' }\n    );\n  }\n\n  /** Requests a resource from the portmaster as application/json and automatically parses the response body*/\n  getResource<T>(resource: string): Observable<T>;\n\n  /** Requests a resource from the portmaster as text */\n  getResource(resource: string, type: string): Observable<HttpResponse<string>>;\n\n  getResource(\n    resource: string,\n    type?: string\n  ): Observable<HttpResponse<string> | any> {\n    if (type !== undefined) {\n      return this.http.get(`${this.httpEndpoint}/v1/updates/get/${resource}`, {\n        headers: new HttpHeaders({ Accept: type }),\n        observe: 'response',\n        responseType: 'text',\n      });\n    }\n\n    return this.http.get<any>(\n      `${this.httpEndpoint}/v1/updates/get/${resource}`,\n      {\n        headers: new HttpHeaders({ Accept: 'application/json' }),\n        responseType: 'json',\n      }\n    );\n  }\n\n  /** Export one or more settings, either from global settings or a specific profile */\n  exportSettings(\n    keys: string[],\n    from: 'global' | string = 'global'\n  ): Observable<string> {\n    return this.http.post(\n      `${this.httpEndpoint}/v1/sync/settings/export`,\n      {\n        from,\n        keys,\n      },\n      {\n        headers: new HttpHeaders({ Accept: 'text/yaml' }),\n        responseType: 'text',\n        observe: 'body',\n      }\n    );\n  }\n\n  /** Validate a settings import for a given target */\n  validateSettingsImport(\n    blob: string | Blob,\n    target: string | 'global' = 'global',\n    mimeType: string = 'text/yaml'\n  ): Observable<ImportResult> {\n    return this.http.post<ImportResult>(\n      `${this.httpEndpoint}/v1/sync/settings/import`,\n      {\n        target,\n        rawExport: blob.toString(),\n        rawMime: mimeType,\n        validateOnly: true,\n      }\n    );\n  }\n\n  /** Import settings into a given target */\n  importSettings(\n    blob: string | Blob,\n    target: string | 'global' = 'global',\n    mimeType: string = 'text/yaml',\n    reset = false,\n    allowUnknown = false\n  ): Observable<ImportResult> {\n    return this.http.post<ImportResult>(\n      `${this.httpEndpoint}/v1/sync/settings/import`,\n      {\n        target,\n        rawExport: blob.toString(),\n        rawMime: mimeType,\n        validateOnly: false,\n        reset,\n        allowUnknown,\n      }\n    );\n  }\n\n  /** Import a profile */\n  importProfile(\n    blob: string | Blob,\n    mimeType: string = 'text/yaml',\n    reset = false,\n    allowUnknown = false,\n    allowReplaceProfiles = false\n  ): Observable<ImportResult> {\n    return this.http.post<ProfileImportResult>(\n      `${this.httpEndpoint}/v1/sync/profile/import`,\n      {\n        rawExport: blob.toString(),\n        rawMime: mimeType,\n        validateOnly: false,\n        reset,\n        allowUnknown,\n        allowReplaceProfiles,\n      }\n    );\n  }\n\n  /** Import a profile */\n  validateProfileImport(\n    blob: string | Blob,\n    mimeType: string = 'text/yaml'\n  ): Observable<ImportResult> {\n    return this.http.post<ProfileImportResult>(\n      `${this.httpEndpoint}/v1/sync/profile/import`,\n      {\n        rawExport: blob.toString(),\n        rawMime: mimeType,\n        validateOnly: true,\n      }\n    );\n  }\n\n  /** Export one or more settings, either from global settings or a specific profile */\n  exportProfile(id: string): Observable<string> {\n    return this.http.post(\n      `${this.httpEndpoint}/v1/sync/profile/export`,\n      {\n        id,\n      },\n      {\n        headers: new HttpHeaders({ Accept: 'text/yaml' }),\n        responseType: 'text',\n        observe: 'body',\n      }\n    );\n  }\n\n  /** Merge multiple profiles into one primary profile. */\n  mergeProfiles(\n    name: string,\n    primary: string,\n    secondaries: string[]\n  ): Observable<string> {\n    return this.http\n      .post<{ new: string }>(`${this.httpEndpoint}/v1/profile/merge`, {\n        name: name,\n        to: primary,\n        from: secondaries,\n      })\n      .pipe(map((response) => response.new));\n  }\n\n  /**\n   * Injects an event into a module to trigger certain backend\n   * behavior.\n   *\n   * @deprecated - Use the HTTP API instead.\n   *\n   * @param module The name of the module to inject\n   * @param kind The event kind to inject\n   */\n  bridgeAPI(call: string, method: string): Observable<void> {\n    return this.create(`api:${call}`, {\n      Method: method,\n    }).pipe(map(() => { }));\n  }\n\n  /**\n   * Flushes all pending method calls that have been collected\n   * while we were not connected to the portmaster API.\n   */\n  private _flushPendingMethods() {\n    const count = this._pendingCalls$.size;\n    try {\n      this._pendingCalls$.forEach((req, key) => {\n        // It's fine if we throw an error here!\n        this.ws$!.next(req.request);\n        this._streams$.set(req.request.id, req.observer);\n        this._pendingCalls$.delete(key);\n      });\n    } catch (err) {\n      // we failed to send the pending calls because the\n      // websocket connection just broke.\n      console.error(\n        `Failed to flush pending calls, ${this._pendingCalls$.size} left: `,\n        err\n      );\n    }\n\n    console.log(`Successfully flushed all (${count}) pending calles`);\n  }\n\n  /**\n   * Allows to inspect currently active requests.\n   */\n  inspectActiveRequests(): { [key: string]: InspectedActiveRequest } {\n    return this.activeRequests.getValue();\n  }\n\n  /**\n   * Loads a database entry. The returned observable completes\n   * after the entry has been loaded.\n   *\n   * @param key The database key of the entry to load.\n   */\n  get<T extends Record>(key: string): Observable<T> {\n    return this.request('get', { key }).pipe(map((res) => res.data));\n  }\n\n  /**\n   * Searches for multiple database entries at once. Each entry\n   * is streams via the returned observable. The observable is\n   * closed after the last entry has been published.\n   *\n   * @param query The query used to search the database.\n   */\n  query<T extends Record>(query: string): Observable<DataReply<T>> {\n    return this.request('query', { query });\n  }\n\n  /**\n   * Subscribes for updates on entries of the selected query.\n   *\n   * @param query The query use to subscribe.\n   */\n  sub<T extends Record>(\n    query: string,\n    opts: RetryableOpts = {}\n  ): Observable<DataReply<T>> {\n    return this.request('sub', { query }).pipe(retryPipeline(opts));\n  }\n\n  /**\n   * Subscribes for updates on entries of the selected query and\n   * ensures entries are stream once upon subscription.\n   *\n   * @param query The query use to subscribe.\n   * @todo(ppacher): check what a ok/done message mean here.\n   */\n  qsub<T extends Record>(\n    query: string,\n    opts?: RetryableOpts\n  ): Observable<DataReply<T>>;\n  qsub<T extends Record>(\n    query: string,\n    opts: RetryableOpts,\n    _: { forwardDone: true }\n  ): Observable<DataReply<T> | DoneReply>;\n  qsub<T extends Record>(\n    query: string,\n    opts: RetryableOpts = {},\n    { forwardDone }: { forwardDone?: true } = {}\n  ): Observable<DataReply<T>> {\n    return this.request('qsub', { query }, { forwardDone }).pipe(\n      retryPipeline(opts)\n    );\n  }\n\n  /**\n   * Creates a new database entry.\n   *\n   * @warn create operations do not validate the type of data\n   * to be overwritten (for keys that does already exist).\n   * Use {@function insert} for more validation.\n   *\n   * @param key The database key for the entry.\n   * @param data The actual data for the entry.\n   */\n  create(key: string, data: any): Observable<void> {\n    data = this.stripMeta(data);\n    return this.request('create', { key, data }).pipe(map(() => { }));\n  }\n\n  /**\n   * Updates an existing entry.\n   *\n   * @param key The database key for the entry\n   * @param data The actual, updated entry data.\n   */\n  update(key: string, data: any): Observable<void> {\n    data = this.stripMeta(data);\n    return this.request('update', { key, data }).pipe(map(() => { }));\n  }\n\n  /**\n   * Creates a new database entry.\n   *\n   * @param key The database key for the entry.\n   * @param data The actual data for the entry.\n   * @todo(ppacher): check what's different to create().\n   */\n  insert(key: string, data: any): Observable<void> {\n    data = this.stripMeta(data);\n    return this.request('insert', { key, data }).pipe(map(() => { }));\n  }\n\n  /**\n   * Deletes an existing database entry.\n   *\n   * @param key The key of the database entry to delete.\n   */\n  delete(key: string): Observable<void> {\n    return this.request('delete', { key }).pipe(map(() => { }));\n  }\n\n  /**\n   * Watch a database key for modifications. If the\n   * websocket connection is lost or an error is returned\n   * watch will automatically retry after retryDelay\n   * milliseconds. It stops retrying to watch key once\n   * maxRetries is exceeded. The returned observable completes\n   * when the watched key is deleted.\n   *\n   * @param key The database key to watch\n   * @param opts.retryDelay Number of milliseconds to wait\n   *        between retrying the request. Defaults to 1000\n   * @param opts.maxRetries Maximum number of tries before\n   *        giving up. Defaults to Infinity\n   * @param opts.ingoreNew Whether or not `new` notifications\n   *        will be ignored. Defaults to false\n   * @param opts.ignoreDelete Whether or not \"delete\" notification\n   *        will be ignored (and replaced by null)\n   * @param forwardDone: Whether or not the \"done\" message should be forwarded\n   */\n  watch<T extends Record>(key: string, opts?: WatchOpts): Observable<T>;\n  watch<T extends Record>(\n    key: string,\n    opts?: WatchOpts & { ignoreDelete: true }\n  ): Observable<T | null>;\n  watch<T extends Record>(\n    key: string,\n    opts: WatchOpts,\n    _: { forwardDone: true }\n  ): Observable<T | DoneReply>;\n  watch<T extends Record>(\n    key: string,\n    opts: WatchOpts & { ignoreDelete: true },\n    _: { forwardDone: true }\n  ): Observable<T | DoneReply | null>;\n  watch<T extends Record>(\n    key: string,\n    opts: WatchOpts = {},\n    { forwardDone }: { forwardDone?: boolean } = {}\n  ): Observable<T | DoneReply | null> {\n    return this.qsub<T>(key, opts, { forwardDone } as any).pipe(\n      filter((reply) => reply.type !== 'done' || forwardDone === true),\n      filter((reply) => reply.type === 'done' || reply.key === key),\n      takeWhile((reply) => opts.ignoreDelete || reply.type !== 'del'),\n      filter((reply) => {\n        return !opts.ingoreNew || reply.type !== 'new';\n      }),\n      map((reply) => {\n        if (reply.type === 'del') {\n          return null;\n        }\n\n        if (reply.type === 'done') {\n          return reply;\n        }\n        return reply.data;\n      })\n    );\n  }\n\n  watchAll<T extends Record>(\n    query: string,\n    opts?: RetryableOpts\n  ): Observable<T[]> {\n    return new Observable<T[]>((observer) => {\n      let values: T[] = [];\n      let keys: string[] = [];\n      let doneReceived = false;\n\n      const sub = this.request(\n        'qsub',\n        { query },\n        { forwardDone: true }\n      ).subscribe({\n        next: (value) => {\n          if ((value as any).type === 'done') {\n            doneReceived = true;\n            observer.next(values);\n            return;\n          }\n\n          if (!doneReceived) {\n            values.push(value.data);\n            keys.push(value.key);\n            return;\n          }\n\n          const idx = keys.findIndex((k) => k === value.key);\n          switch (value.type) {\n            case 'new':\n              if (idx < 0) {\n                values.push(value.data);\n                keys.push(value.key);\n              } else {\n                /*\n                                    const existing = values[idx]._meta!;\n                                    const existingTs = existing.Modified || existing.Created;\n                                    const newTs = (value.data as Record)?._meta?.Modified || (value.data as Record)?._meta?.Created || 0;\n\n                                    console.log(`Comparing ${newTs} against ${existingTs}`);\n\n                                    if (newTs > existingTs) {\n                                      console.log(`New record is ${newTs - existingTs} seconds newer`);\n                                      values[idx] = value.data;\n                                    } else {\n                                      return;\n                                    }\n                  */\n                values[idx] = value.data;\n              }\n              break;\n            case 'del':\n              if (idx >= 0) {\n                keys.splice(idx, 1);\n                values.splice(idx, 1);\n              }\n              break;\n            case 'upd':\n              if (idx >= 0) {\n                values[idx] = value.data;\n              }\n              break;\n          }\n\n          observer.next(values);\n        },\n        error: (err) => {\n          observer.error(err);\n        },\n        complete: () => {\n          observer.complete();\n        },\n      });\n\n      return () => {\n        sub.unsubscribe();\n      };\n    }).pipe(retryPipeline(opts));\n  }\n\n  /**\n   * Close the current websocket connection. A new subscription\n   * will _NOT_ trigger a reconnect.\n   */\n  close() {\n    if (!this.ws$) {\n      return;\n    }\n\n    this.ws$.complete();\n    this.ws$ = null;\n  }\n\n  request<M extends RequestType, R extends Record = any>(\n    method: M,\n    attrs: Partial<Requestable<M>>,\n    { forwardDone }: { forwardDone?: boolean } = {}\n  ): Observable<DataReply<R>> {\n    return new Observable((observer) => {\n      const id = `${++uniqueRequestId}`;\n      if (!this.ws$) {\n        observer.error('No websocket connection');\n        return;\n      }\n\n      let shouldCancel = isCancellable(method);\n      let unsub: () => RequestMessage | null = () => {\n        if (shouldCancel) {\n          return {\n            id: id,\n            type: 'cancel',\n          };\n        }\n\n        return null;\n      };\n\n      const request: any = {\n        ...attrs,\n        id: id,\n        type: method,\n      };\n\n      let inspected: InspectedActiveRequest = {\n        type: method,\n        messagesReceived: 0,\n        observer: observer,\n        payload: request,\n        lastData: null,\n        lastKey: '',\n      };\n\n      if (isDevMode()) {\n        this.activeRequests.next({\n          ...this.inspectActiveRequests(),\n          [id]: inspected,\n        });\n      }\n\n      let stream$: Observable<ReplyMessage<any>> = this.multiplex(\n        request,\n        unsub\n      );\n      if (isDevMode()) {\n        // in development mode we log all replys for the different\n        // methods. This also includes updates to subscriptions.\n        stream$ = stream$.pipe(\n          tap(\n            (msg) => { },\n            //msg => console.log(`[portapi] reply for ${method} ${id}: `, msg),\n            (err) => console.error(`[portapi] error in ${method} ${id}: `, err)\n          )\n        );\n      }\n\n      const subscription = stream$?.subscribe({\n        next: (data) => {\n          inspected.messagesReceived++;\n\n          // in all cases, an `error` message type\n          // terminates the data flow.\n          if (data.type === 'error') {\n            console.error(data.message, inspected);\n            shouldCancel = false;\n\n            observer.error(data.message);\n            return;\n          }\n\n          if (\n            method === 'create' ||\n            method === 'update' ||\n            method === 'insert' ||\n            method === 'delete'\n          ) {\n            // for data-manipulating methods success\n            // ends the stream.\n            if (data.type === 'success') {\n              observer.next(null as any);\n              observer.complete();\n              return;\n            }\n          }\n\n          if (method === 'query' || method === 'sub' || method === 'qsub') {\n            if (data.type === 'warning') {\n              console.warn(data.message);\n              return;\n            }\n\n            // query based methods send `done` once all\n            // results are sent at least once.\n            if (data.type === 'done') {\n              if (method === 'query') {\n                // done ends the query but does not end sub or qsub\n                shouldCancel = false;\n                observer.complete();\n                return;\n              }\n\n              if (!!forwardDone) {\n                // A done message in qsub does not actually represent\n                // a DataReply but we still want to forward that.\n                observer.next(data as any);\n              }\n              return;\n            }\n          }\n\n          if (!isDataReply(data)) {\n            console.error(\n              `Received unexpected message type ${data.type} in a ${method} operation`\n            );\n            return;\n          }\n\n          inspected.lastData = data.data;\n          inspected.lastKey = data.key;\n\n          observer.next(data);\n\n          // for a `get` method the first `ok` message\n          // also marks the end of the stream.\n          if (method === 'get' && data.type === 'ok') {\n            shouldCancel = false;\n            observer.complete();\n          }\n        },\n        error: (err) => {\n          console.error(\"[portapi] request error:\", err.message || err, attrs);\n          observer.error(err);\n        },\n        complete: () => {\n          observer.complete();\n        },\n      });\n\n      if (isDevMode()) {\n        // make sure we remove the \"active\" request when the subscription\n        // goes down\n        subscription.add(() => {\n          const active = this.inspectActiveRequests();\n          delete active[request.id];\n          this.activeRequests.next(active);\n        });\n      }\n\n      return () => {\n        subscription.unsubscribe();\n      };\n    });\n  }\n\n  private multiplex(\n    req: RequestMessage,\n    cancel: (() => RequestMessage | null) | null\n  ): Observable<ReplyMessage> {\n    return new Observable((observer) => {\n      if (this.connectedSubject.getValue()) {\n        // Try to directly send the request to the backend\n        this._streams$.set(req.id, observer);\n        this.ws$!.next(req);\n      } else {\n        // in case of an error we just add the request as\n        // \"pending\" and wait for the connection to be\n        // established.\n        console.warn(\n          `Failed to send request ${req.id}:${req.type}, marking as pending ...`\n        );\n        this._pendingCalls$.set(req.id, {\n          request: req,\n          observer: observer,\n        });\n      }\n\n      return () => {\n        // Try to cancel the request but ingore\n        // any errors here.\n        try {\n          if (cancel !== null) {\n            const cancelMsg = cancel();\n            if (!!cancelMsg) {\n              this.ws$!.next(cancelMsg);\n            }\n          }\n        } catch (err) { }\n\n        this._pendingCalls$.delete(req.id);\n        this._streams$.delete(req.id);\n      };\n    });\n  }\n\n  /**\n   * Inject a message into a PortAPI stream.\n   *\n   * @param id The request ID to inject msg into.\n   * @param msg The message to inject.\n   */\n  _injectMessage(id: string, msg: DataReply<any>) {\n    // we are using runTask here so change-detection is\n    // triggered as needed\n    this.ngZone.runTask(() => {\n      const req = this.activeRequests.getValue()[id];\n      if (!req) {\n        return;\n      }\n\n      req.observer.next(msg as DataReply<any>);\n    });\n  }\n\n  /**\n   * Injects a 'ok' type message\n   *\n   * @param id The ID of the request to inject into\n   * @param data The data blob to inject\n   * @param key [optional] The key of the entry to inject\n   */\n  _injectData(id: string, data: any, key: string = '') {\n    this._injectMessage(id, { type: 'ok', data: data, key, id: id });\n  }\n\n  /**\n   * Patches the last message received on id by deeply merging\n   * data and re-injects that message.\n   *\n   * @param id The ID of the request\n   * @param data The patch to apply and reinject\n   */\n  _patchLast(id: string, data: any) {\n    const req = this.activeRequests.getValue()[id];\n    if (!req || !req.lastData) {\n      return;\n    }\n\n    const newPayload = mergeDeep({}, req.lastData, data);\n    this._injectData(id, newPayload, req.lastKey);\n  }\n\n  private stripMeta<T extends Record>(obj: T): T {\n    let copy = {\n      ...obj,\n      _meta: undefined,\n    };\n    return copy;\n  }\n\n  /**\n   * Creates a new websocket subject and configures appropriate serializer\n   * and deserializer functions for PortAPI.\n   *\n   * @private\n   */\n  private createWebsocket(): WebSocketSubject<ReplyMessage | RequestMessage> {\n    return this.websocketFactory.createConnection<\n      ReplyMessage | RequestMessage\n    >({\n      url: this.wsEndpoint,\n      serializer: (msg) => {\n        try {\n          return serializeMessage(msg);\n        } catch (err) {\n          console.error('serialize message', err);\n          return {\n            type: 'error',\n          };\n        }\n      },\n      // deserializeMessage also supports RequestMessage so cast as any\n      deserializer: <any>((msg: any) => {\n        try {\n          const res = deserializeMessage(msg);\n          return res;\n        } catch (err) {\n          console.error('deserialize message', err);\n          return {\n            type: 'error',\n          };\n        }\n      }),\n      binaryType: 'arraybuffer',\n      openObserver: {\n        next: () => {\n          console.log('[portapi] connection to portmaster established');\n          this.connectedSubject.next(true);\n          this._flushPendingMethods();\n        },\n      },\n      closeObserver: {\n        next: () => {\n          console.log('[portapi] connection to portmaster closed');\n          this.connectedSubject.next(false);\n        },\n      },\n      closingObserver: {\n        next: () => {\n          console.log('[portapi] connection to portmaster closing');\n        },\n      },\n    });\n  }\n}\n\n// Counts the number of \"truthy\" datafields in obj.\nfunction countTruthyDataFields(obj: { [key: string]: any }): number {\n  let count = 0;\n  Object.keys(obj).forEach((key) => {\n    let value = obj[key];\n    if (!!value) {\n      count++;\n    }\n  });\n  return count;\n}\n\nfunction isObject(item: any): item is Object {\n  return item && typeof item === 'object' && !Array.isArray(item);\n}\n\nexport function mergeDeep(target: any, ...sources: any): any {\n  if (!sources.length) return target;\n  const source = sources.shift();\n\n  if (isObject(target) && isObject(source)) {\n    for (const key in source) {\n      if (isObject(source[key])) {\n        if (!target[key]) Object.assign(target, { [key]: {} });\n        mergeDeep(target[key], source[key]);\n      } else {\n        Object.assign(target, { [key]: source[key] });\n      }\n    }\n  }\n\n  return mergeDeep(target, ...sources);\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/portapi.types.ts",
    "content": "import { iif, MonoTypeOperatorFunction, of, Subscriber, throwError } from 'rxjs';\nimport { concatMap, delay, retryWhen } from 'rxjs/operators';\n\n/**\n* ReplyType contains all possible message types of a reply.\n*/\nexport type ReplyType = 'ok'\n  | 'upd'\n  | 'new'\n  | 'del'\n  | 'success'\n  | 'error'\n  | 'warning'\n  | 'done';\n\n/**\n* RequestType contains all possible message types of a request.\n*/\nexport type RequestType = 'get'\n  | 'query'\n  | 'sub'\n  | 'qsub'\n  | 'create'\n  | 'update'\n  | 'insert'\n  | 'delete'\n  | 'cancel';\n\n// RecordMeta describes the meta-data object that is part of\n// every API resource.\nexport interface RecordMeta {\n  // Created hold a unix-epoch timestamp when the record has been\n  // created.\n  Created: number;\n  // Deleted hold a unix-epoch timestamp when the record has been\n  // deleted.\n  Deleted: number;\n  // Expires hold a unix-epoch timestamp when the record has been\n  // expires.\n  Expires: number;\n  // Modified hold a unix-epoch timestamp when the record has been\n  // modified last.\n  Modified: number;\n  // Key holds the database record key.\n  Key: string;\n}\n\nexport interface Process extends Record {\n  Name: string;\n  UserID: number;\n  UserName: string;\n  UserHome: string;\n  Pid: number;\n  Pgid: number;\n  CreatedAt: number;\n  ParentPid: number;\n  ParentCreatedAt: number;\n  Path: string;\n  ExecName: string;\n  Cwd: string;\n  CmdLine: string;\n  FirstArg: string;\n  Env: {\n    [key: string]: string\n  } | null;\n  Tags: {\n    Key: string;\n    Value: string;\n  }[] | null;\n  MatchingPath: string;\n  PrimaryProfileID: string;\n  FirstSeen: number;\n  LastSeen: number;\n  Error: string;\n  ExecHashes: {\n    [key: string]: string\n  } | null;\n}\n\n// Record describes the base record structure of all API resources.\nexport interface Record {\n  _meta?: RecordMeta;\n}\n\n/**\n* All possible MessageType that are available in PortAPI.\n*/\nexport type MessageType = RequestType | ReplyType;\n\n/**\n* BaseMessage describes the base message type that is exchanged\n* via PortAPI.\n*/\nexport interface BaseMessage<M extends MessageType = MessageType> {\n  // ID of the request. Used to correlated (multiplex) requests and\n  // responses across a single websocket connection.\n  id: string;\n  // Type is the request/response message type.\n  type: M;\n}\n\n/**\n* DoneReply marks the end of a PortAPI stream.\n*/\nexport interface DoneReply extends BaseMessage<'done'> { }\n\n/**\n* DataReply is either sent once as a result on a `get` request or\n* is sent multiple times in the course of a PortAPI stream.\n*/\nexport interface DataReply<T extends Record> extends BaseMessage<'ok' | 'upd' | 'new' | 'del'> {\n  // Key is the database key including the database prefix.\n  key: string;\n  // Data is the actual data of the entry.\n  data: T;\n}\n\n/**\n * Returns true if d is a DataReply message type.\n *\n * @param d The reply message to check\n */\nexport function isDataReply(d: ReplyMessage): d is DataReply<any> {\n  return d.type === 'ok'\n    || d.type === 'upd'\n    || d.type === 'new'\n    || d.type === 'del';\n  //|| d.type === 'done'; // done is actually not correct\n}\n\n/**\n* SuccessReply is used to mark an operation as successfully. It does not carry any\n* data. Think of it as a \"201 No Content\" in HTTP.\n*/\nexport interface SuccessReply extends BaseMessage<'success'> { }\n\n/**\n* ErrorReply describes an error that happened while processing a\n* request. Note that an `error` type message may be sent for single\n* and response-stream requests. In case of a stream the `error` type\n* message marks the end of the stream. See WarningReply for a simple\n* warning message that can be transmitted via PortAPI.\n*/\nexport interface ErrorReply extends BaseMessage<'error'> {\n  // Message is the error message from the backend.\n  message: string;\n}\n\n/**\n* WarningReply contains a warning message that describes an error\n* condition encountered when processing a single entitiy of a\n* response stream. In contrast to `error` type messages, a `warning`\n* can only occure during data streams and does not end the stream.\n*/\nexport interface WarningReply extends BaseMessage<'warning'> {\n  // Message describes the warning/error condition the backend\n  // encountered.\n  message: string;\n}\n\n/**\n* QueryRequest defines the payload for `query`, `sub` and `qsub` message\n* types. The result of a query request is always a stream of responses.\n* See ErrorReply, WarningReply and DoneReply for more information.\n*/\nexport interface QueryRequest extends BaseMessage<'query' | 'sub' | 'qsub'> {\n  // Query is the query for the database.\n  query: string;\n}\n\n/**\n* KeyRequests defines the payload for a `get` or `delete` request. Those\n* message type only carry the key of the database entry to delete. Note that\n* `delete` can only return a `success` or `error` type message while `get` will\n* receive a `ok` or `error` type message.\n*/\nexport interface KeyRequest extends BaseMessage<'delete' | 'get'> {\n  // Key is the database entry key.\n  key: string;\n}\n\n\n/**\n* DataRequest is used during create, insert or update operations.\n* TODO(ppacher): check what's the difference between create and insert,\n*                both seem to error when trying to create a new entry.\n*/\nexport interface DataRequest<T> extends BaseMessage<'update' | 'create' | 'insert'> {\n  // Key is the database entry key.\n  key: string;\n  // Data is the data to store.\n  data: T;\n}\n\n/**\n * CancelRequest can be sent on stream operations to early-abort the request.\n */\nexport interface CancelRequest extends BaseMessage<'cancel'> { }\n\n/**\n* ReplyMessage is a union of all reply message types.\n*/\nexport type ReplyMessage<T extends Record = any> = DataReply<T>\n  | DoneReply\n  | SuccessReply\n  | WarningReply\n  | ErrorReply;\n\n/**\n* RequestMessage is a union of all request message types.\n*/\nexport type RequestMessage<T = any> = QueryRequest\n  | KeyRequest\n  | DataRequest<T>\n  | CancelRequest;\n\n/**\n* Requestable can be used to accept only properties that match\n* the request message type M.\n*/\nexport type Requestable<M extends RequestType> = RequestMessage & { type: M };\n\n/**\n * Returns true if m is a cancellable message type.\n *\n * @param m The message type to check.\n */\nexport function isCancellable(m: MessageType): boolean {\n  switch (m) {\n    case 'qsub':\n    case 'sub':\n      return true;\n    default:\n      return false;\n  }\n}\n\n/**\n * Reflects a currently in-flight PortAPI request. Used to\n * intercept and mangle with responses.\n */\nexport interface InspectedActiveRequest {\n  // The type of request.\n  type: RequestType;\n  // The actual request payload.\n  // @todo(ppacher): typings\n  payload: any;\n  // The request observer. Use to inject data\n  // or complete/error the subscriber. Use with\n  // care!\n  observer: Subscriber<DataReply<any>>;\n  // Counter for the number of messages received\n  // for this request.\n  messagesReceived: number;\n  // The last data received on the request\n  lastData: any;\n  // The last key received on the request\n  lastKey: string;\n}\n\nexport interface RetryableOpts {\n  // A delay in milliseconds before retrying an operation.\n  retryDelay?: number;\n  // The maximum number of retries.\n  maxRetries?: number;\n}\n\nexport interface ProfileImportResult extends ImportResult {\n  replacesProfiles: string[];\n}\n\nexport interface ImportResult {\n  restartRequired: boolean;\n  replacesExisting: boolean;\n  containsUnknown: boolean;\n}\n\n/**\n * Returns a RxJS operator function that implements a retry pipeline\n * with a configurable retry delay and an optional maximum retry count.\n * If maxRetries is reached the last error captured is thrown.\n *\n * @param opts  Configuration options for the retryPipeline.\n *        see {@type RetryableOpts} for more information.\n */\nexport function retryPipeline<T>({ retryDelay, maxRetries }: RetryableOpts = {}): MonoTypeOperatorFunction<T> {\n  return retryWhen(errors => errors.pipe(\n    // use concatMap to keep the errors in order and make sure\n    // they don't execute in parallel.\n    concatMap((e, i) =>\n      iif(\n        // conditional observable seletion, throwError if i > maxRetries\n        // or a retryDelay otherwise\n        () => i > (maxRetries || Infinity),\n        throwError(() => e),\n        of(e).pipe(delay(retryDelay || 1000))\n      )\n    )\n  ))\n}\n\nexport interface WatchOpts extends RetryableOpts {\n  // Whether or not `new` updates should be filtered\n  // or let through. See {@method PortAPI.watch} for\n  // more information.\n  ingoreNew?: boolean;\n\n  ignoreDelete?: boolean;\n}\n\n\n/**\n* Serializes a request or reply message into it's wire format.\n*\n* @param msg The request or reply messsage to serialize\n*/\nexport function serializeMessage(msg: RequestMessage | ReplyMessage): any {\n  if (msg === undefined) {\n    return undefined;\n  }\n\n  let blob = `${msg.id}|${msg.type}`;\n\n  switch (msg.type) {\n    case 'done':        // reply\n    case 'success':     // reply\n    case 'cancel':      // request\n      break;\n\n    case 'error':       // reply\n    case 'warning':     // reply\n      blob += `|${msg.message}`\n      break;\n\n    case 'ok':          // reply\n    case 'upd':         // reply\n    case 'new':         // reply\n    case 'insert':      // request\n    case 'update':      // request\n    case 'create':      // request\n      blob += `|${msg.key}|J${JSON.stringify(msg.data)}`\n      break;\n\n\n    case 'del':         // reply\n    case 'get':         // request\n    case 'delete':      // request\n      blob += `|${msg.key}`\n      break;\n\n    case 'query':       // request\n    case 'sub':         // request\n    case 'qsub':        // request\n      blob += `|query ${msg.query}`\n      break;\n\n    default:\n      // We need (msg as any) here because typescript knows that we covered\n      // all possible values above and that .type can never be something else.\n      // Still, we want to guard against unexpected portmaster message\n      // types.\n      console.error(`Unknown message type ${(msg as any).type}`);\n  }\n\n  return blob;\n}\n\n/**\n* Deserializes (loads) a PortAPI message from a WebSocket message event.\n*\n* @param event The WebSocket MessageEvent to parse.\n*/\nexport function deserializeMessage(event: MessageEvent): RequestMessage | ReplyMessage {\n  let data: string;\n\n  if (typeof event.data !== 'string') {\n    data = new TextDecoder(\"utf-8\").decode(event.data)\n  } else {\n    data = event.data;\n  }\n\n  const parts = data.split(\"|\");\n\n  if (parts.length < 2) {\n    throw new Error(`invalid number of message parts, expected 3-4 but got ${parts.length}`);\n  }\n\n  const id = parts[0];\n  const type = parts[1] as MessageType;\n\n  var msg: Partial<RequestMessage | ReplyMessage> = {\n    id,\n    type,\n  }\n\n  if (parts.length > 4) {\n    parts[3] = parts.slice(3).join('|')\n  }\n\n  switch (msg.type) {\n    case 'done':        // reply\n    case 'success':     // reply\n    case 'cancel':      // request\n      break;\n\n    case 'error':       // reply\n    case 'warning':     // reply\n      msg.message = parts[2];\n      break;\n\n    case 'ok':          // reply\n    case 'upd':         // reply\n    case 'new':         // reply\n    case 'insert':      // request\n    case 'update':      // request\n    case 'create':      // request\n      msg.key = parts[2];\n      try {\n        if (parts[3][0] === 'J') {\n          msg.data = JSON.parse(parts[3].slice(1));\n        } else {\n          msg.data = parts[3];\n        }\n      } catch (e) {\n        console.log(e, data)\n      }\n      break;\n\n    case 'del':         // reply\n    case 'get':         // request\n    case 'delete':      // request\n      msg.key = parts[2];\n      break;\n\n    case 'query':       // request\n    case 'sub':         // request\n    case 'qsub':        // request\n      msg.query = parts[2];\n      if (msg.query.startsWith(\"query \")) {\n        msg.query = msg.query.slice(6);\n      }\n      break;\n\n    default:\n      // We need (msg as any) here because typescript knows that we covered\n      // all possible values above and that .type can never be something else.\n      // Still, we want to guard against unexpected portmaster message\n      // types.\n      console.error(`Unknown message type ${(msg as any).type}`);\n  }\n\n  return msg as (ReplyMessage | RequestMessage); // it's not partitial anymore\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/spn.service.ts",
    "content": "import { HttpClient, HttpParams, HttpResponse } from \"@angular/common/http\";\nimport { Inject, Injectable } from \"@angular/core\";\nimport { BehaviorSubject, Observable, of } from \"rxjs\";\nimport { filter, map, share, switchMap } from \"rxjs/operators\";\nimport { FeatureID } from \"./features\";\nimport { PORTMASTER_HTTP_API_ENDPOINT, PortapiService } from './portapi.service';\nimport { Feature, Pin, SPNStatus, UserProfile } from \"./spn.types\";\n\n@Injectable()\nexport class SPNService {\n\n  /** Emits the SPN status whenever it changes */\n  status$: Observable<SPNStatus>;\n\n  profile$ = this.watchProfile()\n    .pipe(\n      share({ connector: () => new BehaviorSubject<UserProfile | null | undefined>(undefined) }),\n      filter(val => val !== undefined)\n    ) as Observable<UserProfile | null>;\n\n  private pins$: Observable<Pin[]>;\n\n  constructor(\n    private portapi: PortapiService,\n    private http: HttpClient,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpAPI: string,\n  ) {\n    this.status$ = this.portapi.watch<SPNStatus>('runtime:spn/status', { ignoreDelete: true })\n      .pipe(\n        share({ connector: () => new BehaviorSubject<any | null>(null) }),\n        filter(val => val !== null),\n      )\n\n    this.pins$ = this.status$\n      .pipe(\n        switchMap(status => {\n          if (status.Status !== \"disabled\") {\n            return this.portapi.watchAll<Pin>(\"map:main/\", { retryDelay: 50000 })\n          }\n\n          return of([] as Pin[]);\n        }),\n        share({ connector: () => new BehaviorSubject<Pin[] | undefined>(undefined) }),\n        filter(val => val !== undefined)\n      ) as Observable<Pin[]>;\n  }\n\n  /**\n   * Watches all pins of the \"main\" SPN map.\n   */\n  watchPins(): Observable<Pin[]> {\n    return this.pins$;\n  }\n\n  /**\n   * Encodes a unicode string to base64.\n   * See https://developer.mozilla.org/en-US/docs/Web/API/btoa\n   * and https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings\n   */\n  b64EncodeUnicode(str: string): string {\n    return window.btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {\n      return String.fromCharCode(parseInt(p1, 16))\n    }))\n  }\n\n  /**\n   *  Logs into the SPN user account\n   */\n  login({ username, password }: { username: string, password: string }): Observable<HttpResponse<string>> {\n    return this.http.post(`${this.httpAPI}/v1/spn/account/login`, undefined, {\n      headers: {\n        Authorization: `Basic ${this.b64EncodeUnicode(username + ':' + password)}`\n      },\n      responseType: 'text',\n      observe: 'response'\n    });\n  }\n\n  /**\n   * Log out of the SPN user account\n   *\n   * @param purge Whether or not the portmaster should keep user/device information for the next login\n   */\n  logout(purge = false): Observable<HttpResponse<string>> {\n    let params = new HttpParams();\n    if (!!purge) {\n      params = params.set(\"purge\", \"true\")\n    }\n    return this.http.delete(`${this.httpAPI}/v1/spn/account/logout`, {\n      params,\n      responseType: 'text',\n      observe: 'response'\n    })\n  }\n\n  watchEnabledFeatures(): Observable<(Feature & { enabled: boolean })[]> {\n    return this.profile$\n      .pipe(\n        switchMap(profile => {\n          return this.loadFeaturePackages()\n            .pipe(\n              map(features => {\n                return features.map(feature => {\n                  // console.log(feature, profile?.current_plan?.feature_ids)\n                  return {\n                    ...feature,\n                    enabled: feature.RequiredFeatureID === FeatureID.None || profile?.current_plan?.feature_ids?.includes(feature.RequiredFeatureID) || false,\n                  }\n                })\n              })\n            )\n        })\n      );\n  }\n\n  /** Returns a list of all feature packages */\n  loadFeaturePackages(): Observable<Feature[]> {\n    return this.http.get<{ Features: Feature[] }>(`${this.httpAPI}/v1/account/features`)\n      .pipe(\n        map(response => response.Features.map(feature => {\n          return {\n            ...feature,\n            IconURL: `${this.httpAPI}/v1/account/features/${feature.ID}/icon`,\n          }\n        }))\n      );\n  }\n\n  /**\n   * Returns the current SPN user profile.\n   *\n   * @param refresh Whether or not the user profile should be refreshed from the ticket agent\n   * @returns\n   */\n  userProfile(refresh = false): Observable<UserProfile> {\n    let params = new HttpParams();\n    if (!!refresh) {\n      params = params.set(\"refresh\", true)\n    }\n    return this.http.get<UserProfile>(`${this.httpAPI}/v1/spn/account/user/profile`, {\n      params\n    });\n  }\n\n  /**\n   * Watches the user profile. It will emit null if there is no profile available yet.\n   */\n  watchProfile(): Observable<UserProfile | null> {\n    let hasSent = false;\n    return this.portapi.watch<UserProfile>('core:spn/account/user', { ignoreDelete: true }, { forwardDone: true })\n      .pipe(\n        filter(result => {\n          if ('type' in result && result.type === 'done') {\n            if (hasSent) {\n              return false;\n            }\n          }\n\n          return true\n        }),\n        map(result => {\n          hasSent = true;\n          if ('type' in result) {\n            return null;\n          }\n\n          return result;\n        })\n      );\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/spn.types.ts",
    "content": "import { FeatureID } from './features';\nimport { CountryInfo, GeoCoordinates, IntelEntity } from './network.types';\nimport { Record } from './portapi.types';\n\nexport interface SPNStatus extends Record {\n  Status: 'failed' | 'disabled' | 'connecting' | 'connected';\n  HomeHubID: string;\n  HomeHubName: string;\n  ConnectedIP: string;\n  ConnectedTransport: string;\n  ConnectedCountry: CountryInfo | null;\n  ConnectedSince: string | null;\n}\n\nexport interface Pin extends Record {\n  ID: string;\n  Name: string;\n  FirstSeen: string;\n  EntityV4?: IntelEntity | null;\n  EntityV6?: IntelEntity | null;\n  States: string[];\n  SessionActive: boolean;\n  HopDistance: number;\n  ConnectedTo: {\n    [key: string]: Lane,\n  };\n  Route: string[] | null;\n  VerifiedOwner: string;\n}\n\nexport interface Lane {\n  HubID: string;\n  Capacity: number;\n  Latency: number;\n}\n\nexport function getPinCoords(p: Pin): GeoCoordinates | null {\n  if (p.EntityV4 && p.EntityV4.Coordinates) {\n    return p.EntityV4.Coordinates;\n  }\n  return p.EntityV6?.Coordinates || null;\n}\n\nexport interface Device {\n  name: string;\n  id: string;\n}\n\nexport interface Subscription {\n  ends_at: string;\n  state: 'manual' | 'active' | 'cancelled';\n  next_billing_date: string;\n  payment_provider: string;\n}\n\nexport interface Plan {\n  name: string;\n  amount: number;\n  months: number;\n  renewable: boolean;\n  feature_ids: FeatureID[];\n}\n\nexport interface View {\n  Message: string;\n  ShowAccountData: boolean;\n  ShowAccountButton: boolean;\n  ShowLoginButton: boolean;\n  ShowRefreshButton: boolean;\n  ShowLogoutButton: boolean;\n}\n\nexport interface UserProfile extends Record {\n  username: string;\n  state: string;\n  balance: number;\n  device: Device | null;\n  subscription: Subscription | null;\n  current_plan: Plan | null;\n  next_plan: Plan | null;\n  view: View | null;\n  LastNotifiedOfEnd?: string;\n  LoggedInAt?: string;\n}\n\nexport interface Package {\n  Name: string;\n  HexColor: string;\n}\n\nexport interface Feature {\n  ID: string;\n  Name: string;\n  ConfigKey: string;\n  ConfigScope: string;\n  RequiredFeatureID: FeatureID;\n  InPackage: Package | null;\n  Comment: string;\n  Beta?: boolean;\n  ComingSoon?: boolean;\n\n  // does not come from the PM API but is set by SPNService\n  IconURL: string;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/utils.ts",
    "content": "\nexport function deepClone<T = any>(o?: T | null): T {\n  if (o === null || o === undefined) {\n    return null as any as T;\n  }\n\n  let _out: T = (Array.isArray(o) ? [] : {}) as T;\n  for (let _key in (o as T)) {\n    let v = o[_key];\n    _out[_key] = (typeof v === \"object\") ? deepClone(v) : v;\n  }\n  return _out as T;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/lib/websocket.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { webSocket, WebSocketSubject, WebSocketSubjectConfig } from 'rxjs/webSocket';\nimport { createTauriWsConnection } from './platform-specific/tauri/tauri-websocket-subject';\nimport { IsTauriEnvironment } from './platform-specific/utils';\n\n@Injectable()\nexport class WebsocketService {\n  constructor() { }\n\n  /**\n   * createConnection creates a new websocket connection using opts.\n   *\n   * @param opts Options for the websocket connection.\n   */\n  createConnection<T>(opts: WebSocketSubjectConfig<T>): WebSocketSubject<T> {\n    if (IsTauriEnvironment()) {\n      console.log('[portmaster-api] Running under Tauri - Using Tauri WebSocket');\n      return createTauriWsConnection<T>(opts);\n    }\n\n    console.log('[portmaster-api] Running in browser - Using RxJS WebSocket');\n    return webSocket<T>(opts);\n  }\n}"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/public-api.ts",
    "content": "/*\n * Public API Surface of portmaster-api\n */\n\nexport * from './lib/app-profile.service';\nexport * from './lib/app-profile.types';\nexport * from './lib/config.service';\nexport * from './lib/config.types';\nexport * from './lib/core.types';\nexport * from './lib/debug-api.service';\nexport * from './lib/features';\nexport * from './lib/meta-api.service';\nexport * from './lib/module';\nexport * from './lib/netquery.service';\nexport * from './lib/network.types';\nexport * from './lib/portapi.service';\nexport * from './lib/portapi.types';\nexport * from './lib/spn.service';\nexport * from './lib/spn.types';\nexport * from './lib/utils';\nexport * from './lib/websocket.service';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/src/test.ts",
    "content": "// This file is required by karma.conf.js and loads recursively all the .spec and framework files\n\nimport 'zone.js';\nimport 'zone.js/testing';\nimport { getTestBed } from '@angular/core/testing';\nimport {\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting\n} from '@angular/platform-browser-dynamic/testing';\n\n// First, initialize the Angular testing environment.\ngetTestBed().initTestEnvironment(\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting(),\n);\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/tsconfig.lib.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../../out-tsc/lib\",\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"inlineSources\": true,\n    \"types\": []\n  },\n  \"exclude\": [\n    \"src/test.ts\",\n    \"testing/**/*\",\n    \"**/*.spec.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/tsconfig.lib.prod.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"./tsconfig.lib.json\",\n  \"compilerOptions\": {\n    \"declarationMap\": false\n  },\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/portmaster-api/tsconfig.spec.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../../out-tsc/spec\",\n    \"types\": [\n      \"jasmine\"\n    ]\n  },\n  \"files\": [\n    \"testing/**/*.ts\"\n  ],\n  \"include\": [\n    \"testing/**/*.ts\",\n    \"**/*.spec.ts\",\n    \"**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/.eslintrc.json",
    "content": "{\n  \"extends\": \"../../../.eslintrc.json\",\n  \"ignorePatterns\": [\n    \"!**/*\"\n  ],\n  \"overrides\": [\n    {\n      \"files\": [\n        \"*.ts\"\n      ],\n      \"parserOptions\": {\n        \"project\": [\n          \"projects/safing/ui/tsconfig.lib.json\",\n          \"projects/safing/ui/tsconfig.spec.json\"\n        ],\n        \"createDefaultProgram\": true\n      },\n      \"rules\": {\n        \"@angular-eslint/directive-selector\": [\n          \"error\",\n          {\n            \"type\": \"attribute\",\n            \"prefix\": \"sfng\",\n            \"style\": \"camelCase\"\n          }\n        ],\n        \"@angular-eslint/component-selector\": [\n          \"error\",\n          {\n            \"type\": \"element\",\n            \"prefix\": \"sfng\",\n            \"style\": \"kebab-case\"\n          }\n        ]\n      }\n    },\n    {\n      \"files\": [\n        \"*.html\"\n      ],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/README.md",
    "content": "# Ui\n\nThis library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.\n\n## Code scaffolding\n\nRun `ng generate component component-name --project ui` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ui`.\n> Note: Don't forget to add `--project ui` or else it will be added to the default project in your `angular.json` file. \n\n## Build\n\nRun `ng build ui` to build the project. The build artifacts will be stored in the `dist/` directory.\n\n## Publishing\n\nAfter building your library with `ng build ui`, go to the dist folder `cd dist/ui` and run `npm publish`.\n\n## Running unit tests\n\nRun `ng test ui` to execute the unit tests via [Karma](https://karma-runner.github.io).\n\n## Further help\n\nTo get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/karma.conf.js",
    "content": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/1.0/config/configuration-file.html\n\nmodule.exports = function (config) {\n  config.set({\n    basePath: '',\n    frameworks: ['jasmine', '@angular-devkit/build-angular'],\n    plugins: [\n      require('karma-jasmine'),\n      require('karma-chrome-launcher'),\n      require('karma-jasmine-html-reporter'),\n      require('karma-coverage'),\n      require('@angular-devkit/build-angular/plugins/karma')\n    ],\n    client: {\n      jasmine: {\n        // you can add configuration options for Jasmine here\n        // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html\n        // for example, you can disable the random execution with `random: false`\n        // or set a specific seed with `seed: 4321`\n      },\n      clearContext: false // leave Jasmine Spec Runner output visible in browser\n    },\n    jasmineHtmlReporter: {\n      suppressAll: true // removes the duplicated traces\n    },\n    coverageReporter: {\n      dir: require('path').join(__dirname, '../../../coverage/safing/ui'),\n      subdir: '.',\n      reporters: [\n        { type: 'html' },\n        { type: 'text-summary' }\n      ]\n    },\n    reporters: ['progress', 'kjhtml'],\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    browsers: ['Chrome'],\n    singleRun: false,\n    restartOnFileChange: true\n  });\n};\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/ng-package.json",
    "content": "{\n  \"$schema\": \"../../../node_modules/ng-packagr/ng-package.schema.json\",\n  \"dest\": \"../../../dist-lib/safing/ui\",\n  \"lib\": {\n    \"entryFile\": \"src/public-api.ts\"\n  },\n  \"assets\": [\n    \"theming.scss\",\n    \"**/_*.scss\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/package.json",
    "content": "{\n  \"name\": \"@safing/ui\",\n  \"version\": \"0.0.1\",\n  \"peerDependencies\": {\n    \"@angular/common\": \"~12.2.0\",\n    \"@angular/core\": \"~12.2.0\",\n    \"@angular/cdk\": \"~12.2.0\"\n  },\n  \"dependencies\": {\n    \"tslib\": \"^2.3.0\"\n  },\n  \"exports\": {\n    \"./theming\": {\n      \"sass\": \"./theming.scss\"\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/accordion/accordion-group.html",
    "content": "<ng-content></ng-content>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/accordion/accordion-group.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, Component, Input, OnDestroy, TemplateRef } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { SfngAccordionComponent } from './accordion';\n\n@Component({\n  selector: 'sfng-accordion-group',\n  templateUrl: './accordion-group.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngAccordionGroupComponent implements OnDestroy {\n  /** @private Currently registered accordion components */\n  accordions: SfngAccordionComponent[] = [];\n\n  /**\n   * A template-ref to render as the header for each accordion-component.\n   * Receives the accordion data as an $implicit context.\n   */\n  @Input()\n  set headerTemplate(v: TemplateRef<any> | null) {\n    this._headerTemplate = v;\n\n    if (!!this.accordions.length) {\n      this.accordions.forEach(a => {\n        a.headerTemplate = v;\n        a.cdr.markForCheck();\n      })\n    }\n  }\n  get headerTemplate() { return this._headerTemplate }\n  private _headerTemplate: TemplateRef<any> | null = null;\n\n  /** Whether or not one or more components can be expanded. */\n  @Input()\n  set singleMode(v: any) {\n    this._singleMode = coerceBooleanProperty(v);\n  }\n  get singleMode() { return this._singleMode }\n  private _singleMode = false;\n\n  /** Whether or not the accordion is disabled and does not allow expanding */\n  @Input()\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v);\n    if (this._disabled) {\n      this.accordions.forEach(a => a.active = false);\n    }\n  }\n  get disabled(): boolean { return this._disabled; }\n  private _disabled = false;\n\n  /** A list of subscriptions to the activeChange output of the registered accordion-components */\n  private subscriptions: Subscription[] = [];\n\n  /**\n   * Registeres an accordion component to be handled together with this\n   * accordion group.\n   *\n   * @param a The accordion component to register\n   */\n  register(a: SfngAccordionComponent) {\n    this.accordions.push(a);\n\n    // Tell the accordion-component about the default header-template.\n    if (!a.headerTemplate) {\n      a.headerTemplate = this.headerTemplate;\n    }\n\n    // Subscribe to the activeChange output of the registered\n    // accordion and call toggle() for each event emitted.\n    this.subscriptions.push(a.activeChange.subscribe(() => {\n      if (this.disabled) {\n        return;\n      }\n\n      this.toggle(a);\n    }))\n  }\n\n  /**\n   * Unregisters a accordion component\n   *\n   * @param a The accordion component to unregister\n   */\n  unregister(a: SfngAccordionComponent) {\n    const index = this.accordions.indexOf(a);\n    if (index === -1) return;\n  \n    const subscription = this.subscriptions[index];\n  \n    subscription.unsubscribe();\n    this.accordions = this.accordions.splice(index, 1);\n    this.subscriptions = this.subscriptions.splice(index, 1);\n  }\n\n  ngOnDestroy() {\n    this.subscriptions.forEach(s => s.unsubscribe());\n    this.subscriptions = [];\n    this.accordions = [];\n  }\n\n  /**\n   * Expand an accordion component and collaps all others if\n   * single-mode is selected.\n   *\n   * @param a The accordion component to toggle.\n   */\n  private toggle(a: SfngAccordionComponent) {\n    if (!a.active && this._singleMode) {\n      this.accordions?.forEach(a => a.active = false);\n    }\n\n    a.active = !a.active;\n  }\n\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/accordion/accordion.html",
    "content": "<div [class.active]=\"active\" [class.cursor-pointer]=\"!group || !group.disabled\" (click)=\"toggle($event)\">\n  <ng-container *ngTemplateOutlet=\"headerTemplate; context: {$implicit: data, active: active, accordion: component}\">\n  </ng-container>\n</div>\n\n<div class=\"h-auto overflow-visible opacity-100\" *ngIf=\"active\" [@fadeIn] [@fadeOut]>\n  <ng-container>\n    <ng-content></ng-content>\n  </ng-container>\n</div>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/accordion/accordion.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { SfngAccordionComponent } from \"./accordion\";\nimport { SfngAccordionGroupComponent } from \"./accordion-group\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n  ],\n  declarations: [\n    SfngAccordionGroupComponent,\n    SfngAccordionComponent,\n  ],\n  exports: [\n    SfngAccordionGroupComponent,\n    SfngAccordionComponent,\n  ]\n})\nexport class SfngAccordionModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/accordion/accordion.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnDestroy, OnInit, Optional, Output, TemplateRef, TrackByFunction } from '@angular/core';\nimport { fadeInAnimation, fadeOutAnimation } from '../animations';\nimport { SfngAccordionGroupComponent } from './accordion-group';\n\n@Component({\n  selector: 'sfng-accordion',\n  templateUrl: './accordion.html',\n  exportAs: 'sfngAccordion',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation\n  ]\n})\nexport class SfngAccordionComponent<T = any> implements OnInit, OnDestroy {\n  /** @deprecated in favor of [data] */\n  @Input()\n  title: string = '';\n\n  /** A reference to the component provided via the template context */\n  component = this;\n\n  /**\n   * The data the accordion component is used for. This is passed as an $implicit context\n   * to the header template.\n   */\n  @Input()\n  data: T | undefined = undefined;\n\n  @Input()\n  trackBy: TrackByFunction<T | null> = (_, c) => c\n\n  /** Whether or not the accordion component starts active. */\n  @Input()\n  set active(v: any) {\n    this._active = coerceBooleanProperty(v);\n  }\n  get active() {\n    return this._active;\n  }\n  private _active: boolean = false;\n\n  /** Emits whenever the active value changes. Supports two-way bindings. */\n  @Output()\n  activeChange = new EventEmitter<boolean>();\n\n  /**\n   * The header-template to render for this component. If null, the default template from\n   * the parent accordion-group will be used.\n   */\n  @Input()\n  headerTemplate: TemplateRef<any> | null = null;\n\n  @HostBinding('class.active')\n  /** @private Whether or not the accordion should have the 'active' class */\n  get activeClass(): string {\n    return this.active;\n  }\n\n  ngOnInit(): void {\n    // register at our parent group-component (if any).\n    this.group?.register(this);\n  }\n\n  ngOnDestroy(): void {\n    this.group?.unregister(this);\n  }\n\n  /**\n   * Toggle the active-state of the accordion-component.\n   *\n   * @param event The mouse event.\n   */\n  toggle(event?: Event) {\n    if (!!this.group && this.group.disabled) {\n      return;\n    }\n\n    event?.preventDefault();\n    this.activeChange.emit(!this.active);\n  }\n\n  constructor(\n    public cdr: ChangeDetectorRef,\n    @Optional() public group: SfngAccordionGroupComponent,\n  ) { }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/accordion/index.ts",
    "content": "export { SfngAccordionComponent } from './accordion';\nexport { SfngAccordionGroupComponent } from './accordion-group';\nexport { SfngAccordionModule } from './accordion.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/animations/index.ts",
    "content": "import { animate, query, stagger, style, transition, trigger } from '@angular/animations';\n\nexport const fadeInAnimation = trigger(\n  'fadeIn',\n  [\n    transition(\n      ':enter',\n      [\n        style({ opacity: 0, transform: 'translateY(-5px)' }),\n        animate('120ms cubic-bezier(0, 0, 0.2, 1)',\n          style({ opacity: 1, transform: 'translateY(0px)' }))\n      ]\n    ),\n  ]\n);\n\nexport const fadeOutAnimation = trigger(\n  'fadeOut',\n  [\n    transition(\n      ':leave',\n      [\n        style({ opacity: 1, transform: 'translateY(0px)' }),\n        animate('120ms cubic-bezier(0, 0, 0.2, 1)',\n          style({ opacity: 0, transform: 'translateY(-5px)' }))\n      ]\n    ),\n  ]\n);\n\nexport const fadeInListAnimation = trigger(\n  'fadeInList',\n  [\n    transition(':enter, * => 0, * => -1', []),\n    transition(':increment', [\n      query(':enter', [\n        style({ opacity: 0 }),\n        stagger(5, [\n          animate('300ms ease-out', style({ opacity: 1 })),\n        ]),\n      ], { optional: true })\n    ]),\n  ]\n)\n\nexport const moveInOutAnimation = trigger(\n  'moveInOut',\n  [\n    transition(\n      ':enter',\n      [\n        style({ opacity: 0, transform: 'translateX(100%)' }),\n        animate('.2s ease-in',\n          style({ opacity: 1, transform: 'translateX(0%)' }))\n      ]\n    ),\n    transition(\n      ':leave',\n      [\n        style({ opacity: 1 }),\n        animate('.2s ease-out',\n          style({ opacity: 0, transform: 'translateX(100%)' }))\n      ]\n    )\n  ]\n)\n\nexport const moveInOutListAnimation = trigger(\n  'moveInOutList',\n  [\n    transition(':enter, * => 0, * => -1', []),\n    transition(':increment', [\n      query(':enter', [\n        style({ opacity: 0, transform: 'translateX(100%)' }),\n        stagger(50, [\n          animate('200ms ease-out', style({ opacity: 1, transform: 'translateX(0%)' })),\n        ]),\n      ], { optional: true })\n    ]),\n    transition(':decrement', [\n      query(':leave', [\n        stagger(-50, [\n          animate('200ms ease-out', style({ opacity: 0, transform: 'translateX(100%)' })),\n        ]),\n      ], { optional: true })\n    ]),\n  ]\n)\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/_confirm.dialog.scss",
    "content": ".sfng-confirm-dialog {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n\n  caption {\n    @apply text-sm;\n    opacity: .6;\n    font-size: .6rem;\n  }\n\n  h1 {\n    font-size: 0.85rem;\n    font-weight: 500;\n    margin-bottom: 1rem;\n  }\n\n  .message,\n  h1 {\n    flex-shrink: 0;\n    text-overflow: ellipsis;\n    word-break: normal;\n  }\n\n  .message {\n    font-size: 0.75rem;\n    flex-grow: 1;\n    opacity: .6;\n    max-width: 300px;\n  }\n\n  .message~input {\n    margin-top: 0.5rem;\n    font-size: 95%;\n  }\n\n  .close-icon {\n    position: absolute;\n    top: 1rem;\n    right: 1rem;\n    opacity: .7;\n    cursor: pointer;\n\n    &:hover {\n      opacity: 1;\n    }\n  }\n\n  input[type=\"text\"] {\n    @apply text-primary;\n    @apply bg-gray-500 border-gray-400 bg-opacity-75 border-opacity-75;\n\n    &::placeholder {\n      @apply text-tertiary;\n    }\n  }\n\n  .actions {\n    margin-top: 1rem;\n    width: 100%;\n    display: flex;\n    justify-content: flex-end;\n    align-items: center;\n\n    button.action-button {\n      &:not(:last-child) {\n        margin-right: 0.5rem;\n      }\n\n      &:not(.outline) {\n        @apply bg-blue;\n      }\n\n      &.danger {\n        @apply bg-red-300;\n      }\n\n      &.outline {\n        @apply outline-none;\n        @apply border;\n        @apply border-gray-400;\n      }\n    }\n\n    &>span {\n      display: flex;\n      align-items: center;\n\n      label {\n        margin-left: .5rem;\n        user-select: none;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/_dialog.scss",
    "content": "sfng-dialog-container {\n  .container {\n    display: block;\n    box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.75);\n    @apply p-6;\n    @apply bg-gray-300;\n    @apply rounded;\n    min-width: 20rem;\n    width: fit-content;\n    position: relative;\n  }\n\n  #drag-handle {\n    display: block;\n    height: 6px;\n    background-color: white;\n    opacity: .4;\n    border-radius: 3px;\n    position: absolute;\n    bottom: calc(0.5rem - 2px);\n    width: 30%;\n    left: calc(50% - 15%);\n\n    &:hover {\n      opacity: .8;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/confirm.dialog.html",
    "content": "<div class=\"sfng-confirm-dialog\">\n  <caption *ngIf=\"config.caption\">{{config.caption}}</caption>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" *ngIf=\"config.canCancel\" class=\"w-5 h-5 close-icon\" viewBox=\"0 0 20 20\"\n    fill=\"currentColor\" (click)=\"select()\">\n    <path fill-rule=\"evenodd\"\n      d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n      clip-rule=\"evenodd\" />\n  </svg>\n\n\n  <h1 *ngIf=\"config.header\">{{config.header}}</h1>\n\n  <span class=\"message\" *ngIf=\"config.message\">{{ config.message }}</span>\n\n  <input *ngIf=\"!!config.inputType\" [attr.type]=\"config.inputType\" [(ngModel)]=\"config.inputModel\"\n    [attr.placeholder]=\"config.inputPlaceholder || null\">\n\n  <div class=\"actions\" *ngIf=\"!!config.buttons\">\n    <button *ngFor=\"let button of config.buttons\" (click)=\"select(button.id)\" type=\"button\"\n      class=\"action-button {{button.class}}\">{{button.text}}</button>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/confirm.dialog.ts",
    "content": "import { ChangeDetectionStrategy, Component, Inject, InjectionToken } from '@angular/core';\nimport { SfngDialogRef, SFNG_DIALOG_REF } from './dialog.ref';\n\nexport interface ConfirmDialogButton {\n  text: string;\n  id: string;\n  class?: 'danger' | 'outline';\n}\n\nexport interface ConfirmDialogConfig {\n  buttons?: ConfirmDialogButton[];\n  canCancel?: boolean;\n  header?: string;\n  message?: string;\n  caption?: string;\n  inputType?: 'text' | 'password';\n  inputModel?: string;\n  inputPlaceholder?: string;\n}\n\nexport const CONFIRM_DIALOG_CONFIG = new InjectionToken<ConfirmDialogConfig>('ConfirmDialogConfig');\n\n@Component({\n  templateUrl: './confirm.dialog.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngConfirmDialogComponent {\n  constructor(\n    @Inject(SFNG_DIALOG_REF) private dialogRef: SfngDialogRef<any>,\n    @Inject(CONFIRM_DIALOG_CONFIG) public config: ConfirmDialogConfig,\n  ) {\n    if (config.inputType !== undefined && config.inputModel === undefined) {\n      config.inputModel = '';\n    }\n  }\n\n  select(action?: string) {\n    this.dialogRef.close(action || null);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/dialog.animations.ts",
    "content": "import { animate, state, style, transition, trigger } from \"@angular/animations\";\n\nexport const dialogAnimation = trigger(\n  'dialogContainer',\n  [\n    state('void, exit', style({ opacity: 0, transform: 'scale(0.7)' })),\n    state('enter', style({ transform: 'none', opacity: 1 })),\n    transition(\n      '* => enter',\n      animate('120ms cubic-bezier(0, 0, 0.2, 1)',\n        style({ opacity: 1, transform: 'translateY(0px)' }))\n    ),\n    transition(\n      '* => void, * => exit',\n      animate('120ms cubic-bezier(0, 0, 0.2, 1)',\n        style({ opacity: 0, transform: 'scale(0.7)' }))\n    ),\n  ]\n);\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/dialog.container.ts",
    "content": "import { AnimationEvent } from '@angular/animations';\nimport { CdkDrag } from '@angular/cdk/drag-drop';\nimport { CdkPortalOutlet, ComponentPortal, Portal, TemplatePortal } from '@angular/cdk/portal';\nimport { ChangeDetectorRef, Component, ComponentRef, EmbeddedViewRef, HostBinding, HostListener, InjectionToken, Input, ViewChild } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { dialogAnimation } from './dialog.animations';\n\nexport const SFNG_DIALOG_PORTAL = new InjectionToken<Portal<any>>('SfngDialogPortal');\n\nexport type SfngDialogState = 'opening' | 'open' | 'closing' | 'closed';\n\n@Component({\n  selector: 'sfng-dialog-container',\n  template: `\n  <div class=\"container\" cdkDrag cdkDragRootElement=\".cdk-overlay-pane\" [cdkDragDisabled]=\"!dragable\">\n    <div *ngIf=\"dragable\" cdkDragHandle id=\"drag-handle\"></div>\n    <ng-container cdkPortalOutlet></ng-container>\n  </div>\n  `,\n  animations: [dialogAnimation]\n})\nexport class SfngDialogContainerComponent<T> {\n  onStateChange = new Subject<SfngDialogState>();\n\n  ref: ComponentRef<T> | EmbeddedViewRef<T> | null = null;\n\n  constructor(\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  @HostBinding('@dialogContainer')\n  state = 'enter';\n\n  @ViewChild(CdkPortalOutlet, { static: true })\n  _portalOutlet: CdkPortalOutlet | null = null;\n\n  @ViewChild(CdkDrag, { static: true })\n  drag!: CdkDrag;\n\n  attachComponentPortal(portal: ComponentPortal<T>): ComponentRef<T> {\n    this.ref = this._portalOutlet!.attachComponentPortal(portal)\n    return this.ref;\n  }\n\n  attachTemplatePortal(portal: TemplatePortal<T>): EmbeddedViewRef<T> {\n    this.ref = this._portalOutlet!.attachTemplatePortal(portal);\n    return this.ref;\n  }\n\n  @Input()\n  dragable: boolean = false;\n\n  @HostListener('@dialogContainer.start', ['$event'])\n  onAnimationStart({ toState }: AnimationEvent) {\n    if (toState === 'enter') {\n      this.onStateChange.next('opening');\n    } else if (toState === 'exit') {\n      this.onStateChange.next('closing');\n    }\n  }\n\n  @HostListener('@dialogContainer.done', ['$event'])\n  onAnimationEnd({ toState }: AnimationEvent) {\n    if (toState === 'enter') {\n      this.onStateChange.next('open');\n    } else if (toState === 'exit') {\n      this.onStateChange.next('closed');\n    }\n  }\n\n  /** Starts the exit animation */\n  _startExit() {\n    this.state = 'exit';\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/dialog.module.ts",
    "content": "import { DragDropModule } from \"@angular/cdk/drag-drop\";\nimport { OverlayModule } from \"@angular/cdk/overlay\";\nimport { PortalModule } from \"@angular/cdk/portal\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { FormsModule } from \"@angular/forms\";\nimport { SfngConfirmDialogComponent } from \"./confirm.dialog\";\nimport { SfngDialogContainerComponent } from \"./dialog.container\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    OverlayModule,\n    PortalModule,\n    DragDropModule,\n    FormsModule,\n  ],\n  declarations: [\n    SfngDialogContainerComponent,\n    SfngConfirmDialogComponent,\n  ]\n})\nexport class SfngDialogModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/dialog.ref.ts",
    "content": "import { OverlayRef } from \"@angular/cdk/overlay\";\nimport { InjectionToken } from \"@angular/core\";\nimport { Observable, PartialObserver, Subject } from \"rxjs\";\nimport { filter, take } from \"rxjs/operators\";\nimport { SfngDialogContainerComponent, SfngDialogState } from \"./dialog.container\";\n\nexport const SFNG_DIALOG_REF = new InjectionToken<SfngDialogRef<any>>('SfngDialogRef');\n\nexport class SfngDialogRef<T, R = any, D = any> {\n  constructor(\n    private _overlayRef: OverlayRef,\n    private container: SfngDialogContainerComponent<T>,\n    public readonly data: D,\n  ) {\n    this.container.onStateChange\n      .pipe(\n        filter(state => state === 'closed'),\n        take(1)\n      )\n      .subscribe(() => {\n        this._overlayRef.detach();\n        this._overlayRef.dispose();\n        this.onClose.next(this.value);\n        this.onClose.complete();\n      });\n  }\n\n  get onStateChange(): Observable<SfngDialogState> {\n    return this.container.onStateChange;\n  }\n\n\n  /**\n   * @returns The overlayref that holds the dialog container.\n   */\n  overlay() { return this._overlayRef }\n\n  /**\n   * @returns the instance attached to the dialog container\n   */\n  contentRef() { return this.container.ref! }\n\n  /** Value holds the value passed on close() */\n  private value: R | null = null;\n\n  /**\n   * Emits the result of the dialog and closes the overlay.\n   */\n  onClose = new Subject<R | null>()\n\n  /** onAction only emits if close() is called with action. */\n  onAction<T extends R>(action: T, observer: PartialObserver<T> | ((value: T) => void)): this {\n    (this.onClose.pipe(filter(val => val === action)) as Observable<T>)\n      .subscribe(observer as any); // typescript does not select the correct type overload here.\n    return this;\n  }\n\n  close(result?: R) {\n    this.value = result || null;\n    this.container._startExit();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/dialog.service.ts",
    "content": "import { Overlay, OverlayConfig, OverlayPositionBuilder, PositionStrategy } from '@angular/cdk/overlay';\nimport { ComponentPortal, ComponentType, TemplatePortal } from '@angular/cdk/portal';\nimport { EmbeddedViewRef, Injectable, Injector } from '@angular/core';\nimport { filter, take, takeUntil } from 'rxjs/operators';\nimport { ConfirmDialogConfig, CONFIRM_DIALOG_CONFIG, SfngConfirmDialogComponent } from './confirm.dialog';\nimport { SfngDialogContainerComponent } from './dialog.container';\nimport { SfngDialogModule } from './dialog.module';\nimport { SfngDialogRef, SFNG_DIALOG_REF } from './dialog.ref';\n\nexport interface BaseDialogConfig {\n  /** whether or not the dialog should close on outside-clicks and ESC */\n  autoclose?: boolean;\n\n  /** whether or not a backdrop should be visible */\n  backdrop?: boolean | 'light';\n\n  /** whether or not the dialog should be dragable */\n  dragable?: boolean;\n\n  /**\n   * optional position strategy for the overlay. if omitted, the\n   * overlay will be centered on the screen\n   */\n  positionStrategy?: PositionStrategy;\n\n  /**\n   * Optional data for the dialog that is available either via the\n   * SfngDialogRef for ComponentPortals as an $implicit context value\n   * for TemplatePortals.\n   *\n   * Note, for template portals, data is only set as an $implicit context\n   * value if it is not yet set in the portal!\n   */\n  data?: any;\n}\n\nexport interface ComponentPortalConfig {\n  injector?: Injector;\n}\n\n@Injectable({ providedIn: SfngDialogModule })\nexport class SfngDialogService {\n\n  constructor(\n    private injector: Injector,\n    private overlay: Overlay,\n  ) { }\n\n  position(): OverlayPositionBuilder {\n    return this.overlay.position();\n  }\n\n  create<T>(template: TemplatePortal<T>, opts?: BaseDialogConfig): SfngDialogRef<EmbeddedViewRef<T>>;\n  create<T>(target: ComponentType<T>, opts?: BaseDialogConfig & ComponentPortalConfig): SfngDialogRef<T>;\n  create<T>(target: ComponentType<T> | TemplatePortal<T>, opts: BaseDialogConfig & ComponentPortalConfig = {}): SfngDialogRef<any> {\n    let position: PositionStrategy = opts?.positionStrategy || this.overlay\n      .position()\n      .global()\n      .centerVertically()\n      .centerHorizontally();\n\n    let hasBackdrop = true;\n    let backdropClass = 'dialog-screen-backdrop';\n    if (opts.backdrop !== undefined) {\n      if (opts.backdrop === false) {\n        hasBackdrop = false;\n      } else if (opts.backdrop === 'light') {\n        backdropClass = 'dialog-screen-backdrop-light';\n      }\n    }\n\n    const cfg = new OverlayConfig({\n      scrollStrategy: this.overlay.scrollStrategies.noop(),\n      positionStrategy: position,\n      hasBackdrop: hasBackdrop,\n      backdropClass: backdropClass,\n    });\n    const overlayref = this.overlay.create(cfg);\n\n    // create our dialog container and attach it to the\n    // overlay.\n    const containerPortal = new ComponentPortal<SfngDialogContainerComponent<T>>(\n      SfngDialogContainerComponent,\n      undefined,\n      this.injector,\n    )\n    const containerRef = containerPortal.attach(overlayref);\n\n    if (!!opts.dragable) {\n      containerRef.instance.dragable = true;\n    }\n\n    // create the dialog ref\n    const dialogRef = new SfngDialogRef<T>(overlayref, containerRef.instance, opts.data);\n\n    // prepare the content portal and attach it to the container\n    let result: any;\n    if (target instanceof TemplatePortal) {\n      let r = containerRef.instance.attachTemplatePortal(target)\n\n      if (!!r.context && typeof r.context === 'object' && !('$implicit' in r.context)) {\n        r.context = {\n          $implicit: opts.data,\n          ...r.context,\n        }\n      }\n\n      result = r\n    } else {\n      const contentPortal = new ComponentPortal(target, null, Injector.create({\n        providers: [\n          {\n            provide: SFNG_DIALOG_REF,\n            useValue: dialogRef,\n          }\n        ],\n        parent: opts?.injector || this.injector,\n      }));\n      result = containerRef.instance.attachComponentPortal(contentPortal);\n    }\n    // update the container position now that we have some content.\n    overlayref.updatePosition();\n\n    if (!!opts?.autoclose) {\n      overlayref.outsidePointerEvents()\n        .pipe(take(1))\n        .subscribe(() => dialogRef.close());\n      overlayref.keydownEvents()\n        .pipe(\n          takeUntil(overlayref.detachments()),\n          filter(event => event.key === 'Escape')\n        )\n        .subscribe(() => {\n          dialogRef.close();\n        })\n    }\n    return dialogRef;\n  }\n\n  confirm(opts: ConfirmDialogConfig): SfngDialogRef<SfngConfirmDialogComponent, string> {\n    return this.create(SfngConfirmDialogComponent, {\n      autoclose: opts.canCancel,\n      injector: Injector.create({\n        providers: [\n          {\n            provide: CONFIRM_DIALOG_CONFIG,\n            useValue: opts,\n          },\n        ],\n        parent: this.injector,\n      })\n    })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dialog/index.ts",
    "content": "export { ConfirmDialogConfig } from './confirm.dialog';\nexport * from './dialog.module';\nexport * from './dialog.ref';\nexport * from './dialog.service';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dropdown/dropdown.html",
    "content": "<div *ngIf=\"!externalTrigger\" class=\"w-full\" cdkOverlayOrigin #trigger=\"cdkOverlayOrigin\" (click)=\"toggle(trigger)\">\n  <ng-template [ngTemplateOutlet]=\"triggerTemplate || defaultTriggerTemplate\"></ng-template>\n</div>\n\n<ng-template #defaultTriggerTemplate>\n  <!-- TODO(ppacher): use a button rather than a div but first fix the button styling -->\n  <div [class.rounded-b]=\"!isOpen\"\n    class=\"flex flex-row items-center justify-between w-full px-4 py-2 mt-6 bg-gray-100 rounded-t cursor-pointer hover:bg-gray-100 hover:bg-opacity-75 text-secondary\">\n    {{ label }}\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-6 h-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"\n      stroke-width=\"2\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n    </svg>\n  </div>\n</ng-template>\n\n<ng-template cdkConnectedOverlay [cdkConnectedOverlayOffsetY]=\"offsetY\" [cdkConnectedOverlayOffsetX]=\"offsetX\"\n  [cdkConnectedOverlayMinWidth]=\"minWidth\" [cdkConnectedOverlayMinHeight]=\"minHeight\"\n  [cdkConnectedOverlayOrigin]=\"trigger!\" [cdkConnectedOverlayOpen]=\"isOpen\" (detach)=\"onOverlayClosed()\"\n  [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\" (overlayOutsideClick)=\"onOutsideClick($event)\"\n  [cdkConnectedOverlayPositions]=\"positions\">\n  <div class=\"w-full overflow-hidden bg-gray-200 rounded-b shadow {{ overlayClass }}\" [style.maxHeight]=\"maxHeight\"\n    [style.maxWidth]=\"maxWidth\" [@fadeIn] [@fadeOut]>\n    <ng-content></ng-content>\n  </div>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dropdown/dropdown.module.ts",
    "content": "import { OverlayModule } from \"@angular/cdk/overlay\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { SfngDropdownComponent } from \"./dropdown\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    OverlayModule,\n  ],\n  declarations: [\n    SfngDropdownComponent,\n  ],\n  exports: [\n    SfngDropdownComponent,\n  ]\n})\nexport class SfngDropDownModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dropdown/dropdown.ts",
    "content": "import { coerceBooleanProperty, coerceCssPixelValue, coerceNumberProperty } from \"@angular/cdk/coercion\";\nimport { CdkOverlayOrigin, ConnectedPosition, ScrollStrategy, ScrollStrategyOptions } from \"@angular/cdk/overlay\";\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnInit, Output, Renderer2, TemplateRef, ViewChild } from \"@angular/core\";\nimport { fadeInAnimation, fadeOutAnimation } from '../animations';\n\n@Component({\n  selector: 'sfng-dropdown',\n  exportAs: 'sfngDropdown',\n  templateUrl: './dropdown.html',\n  styles: [\n    `\n    :host {\n      display: block;\n    }\n    `\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [fadeInAnimation, fadeOutAnimation],\n})\nexport class SfngDropdownComponent implements OnInit {\n  /** The trigger origin used to open the drop-down */\n  @ViewChild('trigger', { read: CdkOverlayOrigin })\n  trigger: CdkOverlayOrigin | null = null;\n\n  /**\n   * The button/drop-down label. Only when not using\n   * {@Link SfngDropdown.externalTrigger}\n   */\n  @Input()\n  label: string = '';\n\n  /** The trigger template to use when {@Link SfngDropdown.externalTrigger} */\n  @Input()\n  triggerTemplate: TemplateRef<any> | null = null;\n\n  /** Set to true to provide an external dropdown trigger template using {@Link SfngDropdown.triggerTemplate} */\n  @Input()\n  set externalTrigger(v: any) {\n    this._externalTrigger = coerceBooleanProperty(v)\n  }\n  get externalTrigger() {\n    return this._externalTrigger;\n  }\n  private _externalTrigger = false;\n\n  /** A list of classes to apply to the overlay element */\n  @Input()\n  overlayClass: string = '';\n\n  /** Whether or not the drop-down is disabled. */\n  @Input()\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v)\n  }\n  get disabled() {\n    return this._disabled;\n  }\n  private _disabled = false;\n\n  /** The Y-offset of the drop-down overlay */\n  @Input()\n  set offsetY(v: any) {\n    this._offsetY = coerceNumberProperty(v);\n  }\n  get offsetY() { return this._offsetY }\n  private _offsetY = 4;\n\n  /** The X-offset of the drop-down overlay */\n  @Input()\n  set offsetX(v: any) {\n    this._offsetX = coerceNumberProperty(v);\n  }\n  get offsetX() { return this._offsetX }\n  private _offsetX = 0;\n\n  /** The scrollStrategy of the drop-down */\n  @Input()\n  scrollStrategy!: ScrollStrategy;\n\n  /** Whether or not the pop-over is currently shown. Do not modify this directly */\n  isOpen = false;\n\n  /** The minimum width of the drop-down */\n  @Input()\n  set minWidth(val: any) {\n    this._minWidth = coerceCssPixelValue(val)\n  }\n  get minWidth() { return this._minWidth }\n  private _minWidth: string | number = 0;\n\n  /** The maximum width of the drop-down */\n  @Input()\n  set maxWidth(val: any) {\n    this._maxWidth = coerceCssPixelValue(val)\n  }\n  get maxWidth() { return this._maxWidth }\n  private _maxWidth: string | number | null = null;\n\n  /** The minimum height of the drop-down */\n  @Input()\n  set minHeight(val: any) {\n    this._minHeight = coerceCssPixelValue(val)\n  }\n  get minHeight() { return this._minHeight }\n  private _minHeight: string | number | null = null;\n\n  /** The maximum width of the drop-down */\n  @Input()\n  set maxHeight(val: any) {\n    this._maxHeight = coerceCssPixelValue(val)\n  }\n  get maxHeight() { return this._maxHeight }\n  private _maxHeight: string | number | null = null;\n\n  /** Emits whenever the drop-down is opened */\n  @Output()\n  opened = new EventEmitter<void>();\n\n  /** Emits whenever the drop-down is closed. */\n  @Output()\n  closed = new EventEmitter<void>();\n\n  @Input()\n  positions: ConnectedPosition[] = [\n    {\n      originX: 'end',\n      originY: 'bottom',\n      overlayX: 'end',\n      overlayY: 'top',\n    },\n    {\n      originX: 'end',\n      originY: 'top',\n      overlayX: 'end',\n      overlayY: 'bottom',\n    },\n    {\n      originX: 'end',\n      originY: 'bottom',\n      overlayX: 'start',\n      overlayY: 'bottom',\n    },\n  ]\n\n  constructor(\n    public readonly elementRef: ElementRef,\n    private changeDetectorRef: ChangeDetectorRef,\n    private renderer: Renderer2,\n    private scrollOptions: ScrollStrategyOptions,\n  ) {\n  }\n\n  ngOnInit() {\n    this.scrollStrategy = this.scrollStrategy || this.scrollOptions.close();\n  }\n\n  onOutsideClick(event: MouseEvent) {\n    if (!!this.trigger) {\n      const triggerEl = this.trigger.elementRef.nativeElement;\n\n      let node = event.target;\n      while (!!node) {\n        if (node === triggerEl) {\n          return;\n        }\n        node = this.renderer.parentNode(node);\n      }\n    }\n\n    this.close();\n  }\n\n  onOverlayClosed() {\n    this.closed.next();\n  }\n\n  close() {\n    if (!this.isOpen) {\n      return;\n    }\n\n    this.isOpen = false;\n    this.changeDetectorRef.markForCheck();\n  }\n\n  toggle(t: CdkOverlayOrigin | null = this.trigger) {\n    if (this.isOpen) {\n      this.close();\n\n      return;\n    }\n\n    this.show(t);\n  }\n\n  show(t: CdkOverlayOrigin | null = this.trigger) {\n    if (t === null) {\n      return;\n    }\n\n    if (this.isOpen || this._disabled) {\n      return;\n    }\n\n    if (!!t) {\n      this.trigger = t;\n      const rect = (this.trigger.elementRef.nativeElement as HTMLElement).getBoundingClientRect()\n\n      this.minWidth = rect ? rect.width : this.trigger.elementRef.nativeElement.offsetWidth;\n\n    }\n    this.isOpen = true;\n    this.opened.next();\n    this.changeDetectorRef.markForCheck();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/dropdown/index.ts",
    "content": "export * from './dropdown';\nexport * from './dropdown.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/index.ts",
    "content": "export * from './overlay-stepper';\nexport * from './overlay-stepper.module';\nexport * from './refs';\nexport * from './step';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/overlay-stepper-container.html",
    "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" *ngIf=\"canAbort\" (click)=\"close()\"\n  class=\"absolute top-0 right-0 w-5 h-5 -mt-2 -mr-2 opacity-75 cursor-pointer hover:opacity-100\" fill=\"none\"\n  viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n</svg>\n\n<div class=\"flex-grow py-4 mb-4\" [@moveInOut]=\"portal.hasAttached()\">\n  <ng-container cdkPortalOutlet #portal=\"cdkPortalOutlet\"></ng-container>\n</div>\n\n<ng-template [ngIf]=\"!!currentStep\">\n  <ng-container *ngTemplateOutlet=\"currentStep?.buttonTemplate || defaultButtonTemplate\"></ng-container>\n</ng-template>\n\n<ng-template #defaultButtonTemplate>\n  <div class=\"flex flex-row justify-between\">\n    <button class=\"w-32 py-2\" (click)=\"goBack()\">Go Back</button>\n    <button class=\"w-32 py-2 custom bg-blue hover:bg-blue hover:bg-opacity-75 active:shadow-inner\"\n      [disabled]=\"(currentStep?.validChange | async) === false\" (click)=\"next()\">\n      {{ currentStep?.nextButtonLabel ||  (!isLast ? 'Next' : 'Finish') }}</button>\n  </div>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/overlay-stepper-container.ts",
    "content": "import { animate, style, transition, trigger } from \"@angular/animations\";\nimport { CdkPortalOutlet, ComponentPortal, ComponentType } from \"@angular/cdk/portal\";\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentRef, Inject, InjectionToken, Injector, isDevMode, OnDestroy, OnInit, ViewChild } from \"@angular/core\";\nimport { Subject } from \"rxjs\";\nimport { SfngDialogRef, SFNG_DIALOG_REF } from \"../dialog\";\nimport { StepperControl, StepRef, STEP_REF } from \"./refs\";\nimport { Step, StepperConfig } from \"./step\";\nimport { StepOutletComponent, STEP_ANIMATION_DIRECTION, STEP_PORTAL } from \"./step-outlet\";\n\n/**\n * STEP_CONFIG is used to inject the StepperConfig into the OverlayStepperContainer.\n */\nexport const STEP_CONFIG = new InjectionToken<StepperConfig>('StepperConfig');\n\n@Component({\n  templateUrl: './overlay-stepper-container.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styles: [\n    `\n    :host {\n      position: relative;\n      display: flex;\n      flex-direction: column;\n      width: 600px;\n    }\n    `\n  ],\n  animations: [\n    trigger(\n      'moveInOut',\n      [\n        transition(\n          ':enter',\n          [\n            style({ opacity: 0, transform: 'translateX({{ in }})' }),\n            animate('.2s cubic-bezier(0.4, 0, 0.2, 1)',\n              style({ opacity: 1, transform: 'translateX(0%)' }))\n          ],\n          { params: { in: '100%' } } // default parameters\n        ),\n        transition(\n          ':leave',\n          [\n            style({ opacity: 1 }),\n            animate('.2s cubic-bezier(0.4, 0, 0.2, 1)',\n              style({ opacity: 0, transform: 'translateX({{ out }})' }))\n          ],\n          { params: { out: '-100%' } } // default parameters\n        )\n      ]\n    )]\n})\nexport class OverlayStepperContainerComponent implements OnInit, OnDestroy, StepperControl {\n  /** Used to keep cache the stepRef instances. See documentation for {@class StepRef} */\n  private stepRefCache = new Map<number, StepRef>();\n\n  /** Used to emit when the stepper finished. This is always folled by emitting on onClose$ */\n  private onFinish$ = new Subject<void>();\n\n  /** Emits when the stepper finished - also see {@link OverlayStepperContainerComponent.onClose}*/\n  get onFinish() {\n    return this.onFinish$.asObservable();\n  }\n\n  /**\n   * Emits when the stepper is closed.\n   * If the stepper if finished then onFinish will emit first\n   */\n  get onClose() {\n    return this.dialogRef.onClose;\n  }\n\n  /** The index of the currently displayed step */\n  currentStepIndex = -1;\n\n  /** The component instance of the current step */\n  currentStep: Step | null = null;\n\n  /** A reference to the portalOutlet used to render our steps */\n  @ViewChild(CdkPortalOutlet, { static: true })\n  portalOutlet!: CdkPortalOutlet;\n\n  /** Whether or not the user can go back */\n  canGoBack = false;\n\n  /** Whether or not the user can abort and close the stepper */\n  canAbort = false;\n\n  /** Whether the current step is the last step */\n  get isLast() {\n    return this.currentStepIndex + 1 >= this.config.steps.length;\n  }\n\n  constructor(\n    @Inject(STEP_CONFIG) public readonly config: StepperConfig,\n    @Inject(SFNG_DIALOG_REF) public readonly dialogRef: SfngDialogRef<void>,\n    private injector: Injector,\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  /**\n   * Moves forward to the next step or closes the stepper\n   * when moving beyond the last one.\n   */\n  next(): Promise<void> {\n    if (this.isLast) {\n      this.onFinish$.next();\n      this.close();\n\n      return Promise.resolve();\n    }\n\n    return this.attachStep(this.currentStepIndex + 1, true)\n  }\n\n  /**\n   * Moves back to the previous step. This does not take canGoBack\n   * into account.\n   */\n  goBack(): Promise<void> {\n    return this.attachStep(this.currentStepIndex - 1, false)\n  }\n\n\n  /** Closes the stepper - this does not run the onFinish hooks of the steps */\n  async close(): Promise<void> {\n    this.dialogRef.close();\n  }\n\n  ngOnInit(): void {\n    this.next();\n  }\n\n  ngOnDestroy(): void {\n    this.onFinish$.complete();\n  }\n\n  /**\n   * Attaches a new step component in the current outlet. It detaches any previous\n   * step and calls onBeforeBack and onBeforeNext respectively.\n   *\n   * @param index The index of the new step to attach.\n   * @param forward Whether or not the new step is attached by going \"forward\" or \"backward\"\n   * @returns\n   */\n  private async attachStep(index: number, forward = true) {\n    if (index >= this.config.steps.length) {\n      if (isDevMode()) {\n        throw new Error(`Cannot attach step at ${index}: index out of range`)\n      }\n      return;\n    }\n\n    // call onBeforeNext or onBeforeBack of the current step\n    if (this.currentStep) {\n      if (forward) {\n        if (!!this.currentStep.onBeforeNext) {\n          try {\n            await this.currentStep.onBeforeNext();\n          } catch (err) {\n            console.error(`Failed to move to next step`, err)\n            // TODO(ppacher): display error\n\n            return;\n          }\n        }\n      } else {\n        if (!!this.currentStep.onBeforeBack) {\n          try {\n            await this.currentStep.onBeforeBack()\n          } catch (err) {\n            console.error(`Step onBeforeBack callback failed`, err)\n          }\n        }\n      }\n\n      // detach the current step component.\n      this.portalOutlet.detach();\n    }\n\n    const stepType = this.config.steps[index];\n    const contentPortal = this.createStepContentPortal(stepType, index)\n    const outletPortal = this.createStepOutletPortal(contentPortal, forward ? 'right' : 'left')\n\n    // attach the new step (which is wrapped in a StepOutletComponent).\n    const ref = this.portalOutlet.attachComponentPortal(outletPortal);\n\n    // We need to wait for the step to be actually attached in the outlet\n    // to get access to the actual step component instance.\n    ref.instance.portalOutlet!.attached\n      .subscribe((stepRef: ComponentRef<Step>) => {\n        this.currentStep = stepRef.instance;\n        this.currentStepIndex = index;\n\n        if (typeof this.config.canAbort === 'function') {\n          this.canAbort = this.config.canAbort(this.currentStepIndex, this.currentStep);\n        }\n\n        // make sure we trigger a change-detection cycle now\n        // markForCheck() is not enough here as we need a CD to run\n        // immediately for the Step.buttonTemplate to be accounted for correctly.\n        this.cdr.detectChanges();\n      })\n  }\n\n  /**\n   * Creates a new component portal for a step and provides access to the {@class StepRef}\n   * using dependency injection.\n   *\n   * @param stepType The component type of the step for which a new portal should be created.\n   * @param index The index of the current step. Used to create/cache the {@class StepRef}\n   */\n  private createStepContentPortal(stepType: ComponentType<Step>, index: number): ComponentPortal<Step> {\n    let stepRef = this.stepRefCache.get(index);\n    if (stepRef === undefined) {\n      stepRef = new StepRef(index, this)\n      this.stepRefCache.set(index, stepRef);\n    }\n\n    const injector = Injector.create({\n      providers: [\n        {\n          provide: STEP_REF,\n          useValue: stepRef,\n        }\n      ],\n      parent: this.config.injector || this.injector,\n    })\n\n    return new ComponentPortal(stepType, undefined, injector);\n  }\n\n  /**\n   * Creates a new component portal for a step outlet component that will attach another content\n   * portal and wrap the attachment in a \"move in\" animation for a given direction.\n   *\n   * @param contentPortal The portal of the actual content that should be attached in the outlet\n   * @param dir The direction for the animation of the step outlet.\n   */\n  private createStepOutletPortal(contentPortal: ComponentPortal<Step>, dir: 'left' | 'right'): ComponentPortal<StepOutletComponent> {\n    const injector = Injector.create({\n      providers: [\n        {\n          provide: STEP_PORTAL,\n          useValue: contentPortal,\n        },\n        {\n          provide: STEP_ANIMATION_DIRECTION,\n          useValue: dir,\n        },\n      ],\n      parent: this.injector,\n    })\n\n    return new ComponentPortal(\n      StepOutletComponent,\n      undefined,\n      injector,\n    )\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/overlay-stepper.module.ts",
    "content": "import { OverlayModule } from \"@angular/cdk/overlay\";\nimport { PortalModule } from \"@angular/cdk/portal\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { SfngDialogModule } from \"../dialog\";\nimport { OverlayStepperContainerComponent } from \"./overlay-stepper-container\";\nimport { StepOutletComponent } from \"./step-outlet\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    PortalModule,\n    OverlayModule,\n    SfngDialogModule,\n  ],\n  declarations: [\n    OverlayStepperContainerComponent,\n    StepOutletComponent,\n  ]\n})\nexport class OverlayStepperModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/overlay-stepper.ts",
    "content": "import { ComponentRef, Injectable, Injector } from \"@angular/core\";\nimport { SfngDialogService } from \"../dialog\";\nimport { OverlayStepperContainerComponent, STEP_CONFIG } from \"./overlay-stepper-container\";\nimport { OverlayStepperModule } from \"./overlay-stepper.module\";\nimport { StepperRef } from \"./refs\";\nimport { StepperConfig } from \"./step\";\n\n@Injectable({ providedIn: OverlayStepperModule })\nexport class OverlayStepper {\n  constructor(\n    private injector: Injector,\n    private dialog: SfngDialogService,\n  ) { }\n\n  /**\n   * Creates a new overlay stepper given it's configuration and returns\n   * a reference to the stepper that can be used to wait for or control\n   * the stepper from outside.\n   *\n   * @param config The configuration for the overlay stepper.\n   */\n  create(config: StepperConfig): StepperRef {\n    // create a new injector for our OverlayStepperContainer\n    // that holds a reference to the StepperConfig.\n    const injector = this.createInjector(config);\n\n    const dialogRef = this.dialog.create(OverlayStepperContainerComponent, {\n      injector: injector,\n      autoclose: false,\n      backdrop: 'light',\n      dragable: false,\n    })\n\n    const containerComponentRef = dialogRef.contentRef() as ComponentRef<OverlayStepperContainerComponent>;\n\n    return new StepperRef(containerComponentRef.instance);\n  }\n\n  /**\n   * Creates a new dependency injector that provides access to the\n   * stepper configuration using the STEP_CONFIG injection token.\n   *\n   * @param config The stepper configuration to provide using DI\n   * @returns\n   */\n  private createInjector(config: StepperConfig): Injector {\n    return Injector.create({\n      providers: [\n        {\n          provide: STEP_CONFIG,\n          useValue: config,\n        },\n      ],\n      parent: this.injector,\n    })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/refs.ts",
    "content": "import { InjectionToken } from \"@angular/core\";\nimport { Observable } from \"rxjs\";\nimport { take } from \"rxjs/operators\";\nimport { OverlayStepperContainerComponent } from \"./overlay-stepper-container\";\n\n/**\n * STEP_REF is the injection token that is used to provide a reference to the\n * Stepper to each step.\n */\nexport const STEP_REF = new InjectionToken<StepRef<any>>('StepRef')\n\nexport interface StepperControl {\n  /**\n   * Next should move the stepper forward to the next\n   * step or close the stepper if no more steps are\n   * available.\n   * If the stepper is closed this way all onFinish hooks\n   * registered at {@link StepRef} are executed.\n   */\n  next(): Promise<void>;\n\n  /**\n   * goBack should move the stepper back to the previous\n   * step. This is a no-op if there's no previous step to\n   * display.\n   */\n  goBack(): Promise<void>;\n\n  /**\n   * close closes the stepper but does not run any onFinish hooks\n   * of {@link StepRef}.\n   */\n  close(): Promise<void>;\n}\n\n/**\n * StepRef is a reference to the overlay stepper and can be used to control, abort\n * or otherwise interact with the stepper.\n *\n * It is made available to individual steps using the STEP_REF injection token.\n * Each step in the OverlayStepper receives it's own StepRef instance and will receive\n * a reference to the same instance in case the user goes back and re-opens a step\n * again.\n *\n * Steps should therefore store any configuration data that is needed to restore\n * the previous view in the StepRef using it's save() and load() methods.\n */\nexport class StepRef<T = any> implements StepperControl {\n  private onFinishHooks: (() => PromiseLike<void> | void)[] = [];\n  private data: T | null = null;\n\n  constructor(\n    private currentStepIndex: number,\n    private stepContainerRef: OverlayStepperContainerComponent,\n  ) {\n    this.stepContainerRef.onFinish\n      .pipe(take(1))\n      .subscribe(() => this.runOnFinishHooks)\n  }\n\n  next(): Promise<void> {\n    return this.stepContainerRef.next();\n  }\n\n  goBack(): Promise<void> {\n    return this.stepContainerRef.goBack();\n  }\n\n  close(): Promise<void> {\n    return this.stepContainerRef.close();\n  }\n\n  /**\n   * Save saves data of the current step in the stepper session.\n   * This data is saved in case the user decides to \"go back\" to\n   * to a previous step so the old view can be restored.\n   *\n   * @param data The data to save in the stepper session.\n   */\n  save(data: T): void {\n    this.data = data;\n  }\n\n  /**\n   * Load returns the data previously stored using save(). The\n   * StepperRef automatically makes sure the correct data is returned\n   * for the current step.\n   */\n  load(): T | null {\n    return this.data;\n  }\n\n  /**\n   * registerOnFinish registers fn to be called when the last step\n   * completes and the stepper is going to finish.\n   */\n  registerOnFinish(fn: () => PromiseLike<void> | void) {\n    this.onFinishHooks.push(fn);\n  }\n\n  /**\n   * Executes all onFinishHooks in the order they have been defined\n   * and waits for each hook to complete.\n   */\n  private async runOnFinishHooks() {\n    for (let i = 0; i < this.onFinishHooks.length; i++) {\n      let res = this.onFinishHooks[i]();\n      if (typeof res === 'object' && 'then' in res) {\n        // res is a PromiseLike so wait for it\n        try {\n          await res;\n        } catch (err) {\n          console.error(`Failed to execute on-finish hook of step ${this.currentStepIndex}: `, err)\n        }\n      }\n    }\n  }\n}\n\n\nexport class StepperRef implements StepperControl {\n  constructor(private stepContainerRef: OverlayStepperContainerComponent) { }\n\n  next(): Promise<void> {\n    return this.stepContainerRef.next();\n  }\n\n  goBack(): Promise<void> {\n    return this.stepContainerRef.goBack();\n  }\n\n  close(): Promise<void> {\n    return this.stepContainerRef.close();\n  }\n\n  get onFinish(): Observable<void> {\n    return this.stepContainerRef.onFinish;\n  }\n\n  get onClose(): Observable<void> {\n    return this.stepContainerRef.onClose;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/step-outlet.ts",
    "content": "import { animate, style, transition, trigger } from \"@angular/animations\";\nimport { CdkPortalOutlet, ComponentPortal } from \"@angular/cdk/portal\";\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentRef, Inject, InjectionToken, ViewChild } from \"@angular/core\";\nimport { Step } from \"./step\";\n\nexport const STEP_PORTAL = new InjectionToken<ComponentPortal<Step>>('STEP_PORTAL')\nexport const STEP_ANIMATION_DIRECTION = new InjectionToken<'left' | 'right'>('STEP_ANIMATION_DIRECTION');\n\n/**\n * A simple wrapper component around CdkPortalOutlet to add nice\n * move animations.\n */\n@Component({\n  template: `\n    <div [@moveInOut]=\"{value: _appAnimate, params: {in: in, out: out}}\" class=\"flex flex-col overflow-auto\">\n      <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n    </div>\n  `,\n  styles: [\n    `\n    :host{\n      display: flex;\n      flex-direction: column;\n      overflow: hidden;\n    }\n    `\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    trigger(\n      'moveInOut',\n      [\n        transition(\n          ':enter',\n          [\n            style({ opacity: 0, transform: 'translateX({{ in }})' }),\n            animate('.2s ease-in',\n              style({ opacity: 1, transform: 'translateX(0%)' }))\n          ],\n          { params: { in: '100%' } } // default parameters\n        ),\n        transition(\n          ':leave',\n          [\n            style({ opacity: 1 }),\n            animate('.2s ease-out',\n              style({ opacity: 0, transform: 'translateX({{ out }})' }))\n          ],\n          { params: { out: '-100%' } } // default parameters\n        )\n      ]\n    )]\n})\nexport class StepOutletComponent implements AfterViewInit {\n  /** @private - Whether or not the animation should run. */\n  _appAnimate = false;\n\n  /** The actual step instance that has been attached. */\n  stepInstance: ComponentRef<Step> | null = null;\n\n  /** @private - used in animation interpolation for translateX  */\n  get in() {\n    return this._animateDirection == 'left' ? '-100%' : '100%'\n  }\n\n  /** @private - used in animation interpolation for traslateX  */\n  get out() {\n    return this._animateDirection == 'left' ? '100%' : '-100%'\n  }\n\n  /** The portal outlet in our view used to attach the step */\n  @ViewChild(CdkPortalOutlet, { static: true })\n  portalOutlet!: CdkPortalOutlet;\n\n  constructor(\n    @Inject(STEP_PORTAL) public portal: ComponentPortal<Step>,\n    @Inject(STEP_ANIMATION_DIRECTION) public _animateDirection: 'left' | 'right',\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  ngAfterViewInit(): void {\n    this.portalOutlet?.attached\n      .subscribe(ref => {\n        this.stepInstance = ref as ComponentRef<Step>;\n\n        this._appAnimate = true;\n        this.cdr.detectChanges();\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/overlay-stepper/step.ts",
    "content": "import { Injector, TemplateRef, Type } from \"@angular/core\";\nimport { Observable } from \"rxjs\";\n\nexport interface Step {\n  /**\n   * validChange should emit true or false when the current step\n   * is valid and the \"next\" button should be visible.\n   */\n  validChange: Observable<boolean>;\n\n  /**\n   * onBeforeBack, if it exists, is called when the user\n   * clicks the \"Go Back\" button but before the current step\n   * is unloaded.\n   *\n   * The OverlayStepper will wait for the callback to resolve or\n   * reject but will not abort going back!\n   */\n  onBeforeBack?: () => Promise<void>;\n\n  /**\n   * onBeforeNext, if it exists, is called when the user\n   * clicks the \"Next\" button but before the current step\n   * is unloaded.\n   *\n   * The OverlayStepper willw ait for the callback to resolve\n   * or reject. If it rejects the current step will not be unloaded\n   * and the rejected error will be displayed to the user.\n   */\n  onBeforeNext?: () => Promise<void>;\n\n  /**\n   * nextButtonLabel can overwrite the label for the \"Next\" button.\n   */\n  nextButtonLabel?: string;\n\n  /**\n   * buttonTemplate may hold a tempalte ref that is rendered instead\n   * of the default button row with a \"Go Back\" and a \"Next\" button.\n   * Note that if set, the step component must make sure to handle\n   * navigation itself. See {@class StepRef} for more information on how\n   * to control the stepper.\n   */\n  buttonTemplate?: TemplateRef<any>;\n}\n\nexport interface StepperConfig {\n  /**\n   * canAbort can be set to a function that is called\n   * for each step to determine if the stepper is abortable.\n   */\n  canAbort?: (idx: number, step: Step) => boolean;\n\n  /** steps holds the list of steps to execute */\n  steps: Array<Type<Step>>\n\n  /**\n   * injector, if set, defines the parent injector used to\n   * create dedicated instances of the step types.\n   */\n  injector?: Injector;\n}\n\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/pagination/_pagination.scss",
    "content": "sfng-pagination {\n  .pagination {\n    @apply my-2 w-full flex justify-between;\n\n    button {\n      @apply text-xxs px-2 flex items-center justify-start;\n\n      &.page {\n        @apply bg-cards-secondary;\n        @apply opacity-50;\n\n        &:hover {\n          @apply opacity-100;\n        }\n      }\n\n      &.active-page {\n        @apply text-blue font-medium opacity-100;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/pagination/dynamic-items-paginator.ts",
    "content": "\nimport { BehaviorSubject, Observable, Subscription } from \"rxjs\";\nimport { Pagination, clipPage } from \"./pagination\";\n\nexport interface Datasource<T> {\n  // view should emit all items in the given page using the specified page number.\n  view(page: number, pageSize: number): Observable<T[]>;\n}\n\nexport class DynamicItemsPaginator<T> implements Pagination<T> {\n  private _total = 0;\n  private _pageNumber$ = new BehaviorSubject<number>(1);\n  private _pageItems$ = new BehaviorSubject<T[]>([]);\n  private _pageLoading$ = new BehaviorSubject<boolean>(false);\n  private _pageSubscription = Subscription.EMPTY;\n\n  /** Returns the number of total pages. */\n  get total() { return this._total; }\n\n  /** Emits the current page number */\n  get pageNumber$() { return this._pageNumber$.asObservable() }\n\n  /** Emits all items of the current page */\n  get pageItems$() { return this._pageItems$.asObservable() }\n\n  /** Emits whether or not we're loading the next page */\n  get pageLoading$() { return this._pageLoading$.asObservable() }\n\n  constructor(\n    private source: Datasource<T>,\n    public readonly pageSize = 25,\n  ) { }\n\n  reset(newTotal: number) {\n    this._total = Math.ceil(newTotal / this.pageSize);\n    this.openPage(1);\n  }\n\n  /** Clear resets the current total and emits an empty item set. */\n  clear() {\n    this._total = 0;\n    this._pageItems$.next([]);\n    this._pageNumber$.next(1);\n    this._pageSubscription.unsubscribe();\n  }\n\n  openPage(pageNumber: number): void {\n    pageNumber = clipPage(pageNumber, this.total);\n    this._pageLoading$.next(true);\n\n    this._pageSubscription.unsubscribe()\n    this._pageSubscription = this.source.view(pageNumber, this.pageSize)\n      .subscribe({\n        next: results => {\n          this._pageLoading$.next(false);\n          this._pageItems$.next(results);\n          this._pageNumber$.next(pageNumber);\n        }\n      });\n  }\n\n  nextPage(): void { this.openPage(this._pageNumber$.getValue() + 1) }\n  prevPage(): void { this.openPage(this._pageNumber$.getValue() - 1) }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/pagination/index.ts",
    "content": "export * from './dynamic-items-paginator';\nexport * from './pagination';\nexport * from './pagination.module';\nexport * from './snapshot-paginator';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/pagination/pagination.html",
    "content": "<!-- Pagination template -->\n<ng-template #paginationTpl>\n  <div class=\"pagination\" *ngIf=\"source!.total > 1\">\n    <button class=\"btn-outline\" [disabled]=\"currentPageIdx === 1\" (click)=\"source!.prevPage()\">\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"inline-block w-5 h-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n        <path fill-rule=\"evenodd\"\n          d=\"M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n      Previous\n    </button>\n    <span class=\"flex flex-row items-center gap-1\">\n      <button class=\"page\" *ngFor=\"let page of pageNumbers\" [class.active-page]=\"page === currentPageIdx\"\n        (click)=\"source!.openPage(page)\">{{ page }}</button>\n    </span>\n    <button class=\"btn-outline\" [disabled]=\"currentPageIdx+1 > source!.total\" (click)=\"source!.nextPage()\">\n      Next\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n        <path fill-rule=\"evenodd\"\n          d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n    </button>\n  </div>\n</ng-template>\n<!-- End Pagination Template -->\n\n<ng-container *ngIf=\"!!content && !!source\">\n  <ng-container *ngTemplateOutlet=\"paginationTpl\"></ng-container>\n  <ng-container *ngTemplateOutlet=\"content!.templateRef\">\n  </ng-container>\n  <ng-container *ngTemplateOutlet=\"paginationTpl\"></ng-container>\n</ng-container>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/pagination/pagination.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { SfngPaginationContentDirective } from \".\";\nimport { SfngPaginationWrapperComponent } from \"./pagination\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n  ],\n  declarations: [\n    SfngPaginationContentDirective,\n    SfngPaginationWrapperComponent,\n  ],\n  exports: [\n    SfngPaginationContentDirective,\n    SfngPaginationWrapperComponent,\n  ],\n})\nexport class SfngPaginationModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/pagination/pagination.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, Directive, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges, TemplateRef } from \"@angular/core\";\nimport { Observable, Subscription } from \"rxjs\";\n\nexport interface Pagination<T> {\n  /**\n   * Total should return the total number of pages\n   */\n  total: number;\n\n  /**\n   * pageNumber$ should emit the currently displayed page\n   */\n  pageNumber$: Observable<number>;\n\n  /**\n   * pageItems$ should emit all items of the current page\n   */\n  pageItems$: Observable<T[]>;\n\n  /**\n   * nextPage should progress to the next page. If there are no more\n   * pages than nextPage() should be a no-op.\n   */\n  nextPage(): void;\n\n  /**\n   * prevPage should move back the the previous page. If there is no\n   * previous page, prevPage should be a no-op.\n   */\n  prevPage(): void;\n\n  /**\n   * openPage opens the page @pageNumber. If pageNumber is greater than\n   * the total amount of pages it is clipped to the lastPage. If it is\n   * less than 1, it is clipped to 1.\n   */\n  openPage(pageNumber: number): void\n}\n\n\n\n@Directive({\n  selector: '[sfngPageContent]'\n})\nexport class SfngPaginationContentDirective<T = any> {\n  constructor(public readonly templateRef: TemplateRef<T>) { }\n}\n\nexport interface PageChangeEvent {\n  totalPages: number;\n  currentPage: number;\n}\n\n@Component({\n  selector: 'sfng-pagination',\n  templateUrl: './pagination.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngPaginationWrapperComponent<T = any> implements OnChanges, OnDestroy {\n  private _sub: Subscription = Subscription.EMPTY;\n\n  @Input()\n  source: Pagination<T> | null = null;\n\n  @Output()\n  pageChange = new EventEmitter<PageChangeEvent>();\n\n  @ContentChild(SfngPaginationContentDirective)\n  content: SfngPaginationContentDirective | null = null;\n\n  currentPageIdx: number = 0;\n  pageNumbers: number[] = [];\n\n  ngOnChanges(changes: SimpleChanges) {\n    if ('source' in changes) {\n      this.subscribeToSource(changes.source.currentValue);\n    }\n  }\n\n  ngOnDestroy() {\n    this._sub.unsubscribe();\n  }\n\n  private subscribeToSource(source: Pagination<T>) {\n    // Unsubscribe from the previous pagination, if any\n    this._sub.unsubscribe();\n\n    this._sub = new Subscription();\n\n    this._sub.add(\n      source.pageNumber$\n        .subscribe(current => {\n          this.currentPageIdx = current;\n          this.pageNumbers = generatePageNumbers(current - 1, source.total);\n          this.cdr.markForCheck();\n\n          this.pageChange.next({\n            totalPages: source.total,\n            currentPage: current,\n          })\n        })\n    )\n  }\n\n  constructor(private cdr: ChangeDetectorRef) { }\n}\n\n/**\n * Generates an array of page numbers that should be displayed in paginations.\n *\n * @param current The current page number\n * @param countPages The total number of pages\n * @returns An array of page numbers to display\n */\nexport function generatePageNumbers(current: number, countPages: number): number[] {\n  let delta = 2;\n  let leftRange = current - delta;\n  let rightRange = current + delta + 1;\n\n  return Array.from({ length: countPages }, (v, k) => k + 1)\n    .filter(i => i === 1 || i === countPages || (i >= leftRange && i < rightRange));\n}\n\nexport function clipPage(pageNumber: number, total: number): number {\n  if (pageNumber < 1) {\n    return 1;\n  }\n  if (pageNumber > total) {\n    return total;\n  }\n  return pageNumber;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/pagination/snapshot-paginator.ts",
    "content": "import { BehaviorSubject, Observable } from \"rxjs\";\nimport { debounceTime, map } from \"rxjs/operators\";\nimport { clipPage, Pagination } from \"./pagination\";\n\nexport class SnapshotPaginator<T> implements Pagination<T> {\n  private _itemSnapshot: T[] = [];\n  private _activePageItems = new BehaviorSubject<T[]>([]);\n  private _totalPages = 1;\n  private _updatePending = false;\n\n  constructor(\n    public items$: Observable<T[]>,\n    public readonly pageSize: number,\n  ) {\n    items$\n      .pipe(debounceTime(100))\n      .subscribe(data => {\n        this._itemSnapshot = data;\n        this.openPage(this._currentPage.getValue());\n      });\n\n    this._currentPage\n      .subscribe(page => {\n        this._updatePending = false;\n        const start = this.pageSize * (page - 1);\n        const end = this.pageSize * page;\n        this._totalPages = Math.ceil(this._itemSnapshot.length / this.pageSize) || 1;\n        this._activePageItems.next(this._itemSnapshot.slice(start, end));\n      })\n  }\n\n  private _currentPage = new BehaviorSubject<number>(0);\n\n  get updatePending() {\n    return this._updatePending;\n  }\n  get pageNumber$(): Observable<number> {\n    return this._activePageItems.pipe(map(() => this._currentPage.getValue()));\n  }\n  get pageNumber(): number {\n    return this._currentPage.getValue();\n  }\n  get total(): number {\n    return this._totalPages\n  }\n  get pageItems$(): Observable<T[]> {\n    return this._activePageItems.asObservable();\n  }\n  get pageItems(): T[] {\n    return this._activePageItems.getValue();\n  }\n  get snapshot(): T[] { return this._itemSnapshot };\n\n  reload(): void { this.openPage(this._currentPage.getValue()) }\n\n  nextPage(): void { this.openPage(this._currentPage.getValue() + 1) }\n\n  prevPage(): void { this.openPage(this._currentPage.getValue() - 1) }\n\n  openPage(pageNumber: number): void {\n    pageNumber = clipPage(pageNumber, this.total);\n    this._currentPage.next(pageNumber);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/select/_select.scss",
    "content": ".sfng-select {\n  @apply cursor-pointer relative p-0 flex whitespace-nowrap w-full items-center outline-none self-center overflow-hidden;\n  @apply hover:bg-gray-400;\n  @apply bg-gray-300 border border-gray-300 transition ease-in-out duration-200;\n\n  &.disabled {\n    @apply cursor-not-allowed opacity-75 hover:bg-gray-400;\n  }\n\n  min-width: 6rem;\n  max-width: 12rem;\n\n  &.active {\n    @apply bg-gray-400;\n\n    div.arrow svg {\n      @apply transform -rotate-90;\n    }\n  }\n\n  & > span {\n    @apply flex-grow text-ellipsis inline-block overflow-hidden;\n    @apply px-2;\n  }\n\n  div.arrow {\n    @apply flex flex-row items-center justify-center bg-gray-200 rounded-r-sm;\n    @apply w-5 h-7;\n\n    svg {\n      @apply w-4 m-0 p-0 rotate-90 transform transition ease-in-out duration-100;\n\n      g {\n        @apply text-white;\n        stroke: currentColor;\n      }\n    }\n  }\n}\n\n.sfng-select-dropdown {\n  ul {\n    max-height: 12rem;\n    @apply relative py-1 overflow-auto;\n\n    li {\n      @apply py-2;\n      @apply flex flex-row items-center justify-start gap-1 transition duration-200 ease-in-out cursor-pointer hover:bg-gray-300;\n    }\n\n    li:not(.disabled) {\n      @apply hover:bg-gray-300;\n    }\n\n    li.disabled {\n      @apply cursor-not-allowed;\n    }\n  }\n}\n\n.sfng-select-dropdown.sfng-select-inline {\n  ul {\n    max-height: unset;\n  }\n}\n\nsfng-select-item {\n  @apply text-xxs w-full font-medium gap-3 text-primary flex flex-row items-center justify-start;\n\n  &.disabled {\n    @apply opacity-75 cursor-not-allowed;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/select/index.ts",
    "content": "export * from './item';\nexport * from './select';\nexport * from './select.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/select/item.ts",
    "content": "import { ListKeyManagerOption } from '@angular/cdk/a11y';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, Directive, HostBinding, Input, Optional, TemplateRef } from '@angular/core';\n\nexport interface SelectOption<T = any> extends ListKeyManagerOption {\n  value: any;\n  selected: boolean;\n\n  data?: T;\n  label?: string;\n  description?: string;\n  templateRef?: TemplateRef<any>;\n  disabled?: boolean;\n}\n\n@Component({\n  selector: 'sfng-select-item',\n  template: `<ng-content></ng-content>`,\n})\nexport class SfngSelectItemComponent implements ListKeyManagerOption {\n  @HostBinding('class.disabled')\n  get disabled() {\n    return this.sfngSelectValue?.disabled || false;\n  }\n\n  getLabel() {\n    return this.sfngSelectValue?.label || '';\n  }\n\n  constructor(@Optional() private sfngSelectValue: SfngSelectValueDirective) { }\n}\n\n@Directive({\n  selector: '[sfngSelectValue]',\n})\nexport class SfngSelectValueDirective<T = any> implements SelectOption<T> {\n  @Input('sfngSelectValue')\n  value: any;\n\n  @Input('sfngSelectValueLabel')\n  label?: string;\n\n  @Input('sfngSelectValueData')\n  data?: T;\n\n  @Input('sfngSelectValueDescription')\n  description = '';\n\n  @Input('sfngSelectValueDisabled')\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v)\n  }\n  get disabled() { return this._disabled }\n  private _disabled = false;\n\n  getLabel() {\n    return this.label || ('' + this.value);\n  }\n\n  /** Whether or not the item is currently selected */\n  selected = false;\n\n  constructor(public templateRef: TemplateRef<any>) { }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/select/select.html",
    "content": "<ng-template #customTriggerTemplate>\n  <button [class.active]=\"dropdown?.isOpen\" type=\"button\" class=\"sfng-select\" [class.disabled]=\"disabled\" tabindex=\"-1\">\n\n    <ng-template [ngIf]=\"mode !== 'multi' || (currentItems.length || 0) <= 1\" [ngIfElse]=\"multiTemplate\">\n      <span *ngIf=\"!currentItems.length; else: itemTemplate\">\n        {{ placeholder }}\n      </span>\n      <ng-template #itemTemplate>\n        <span class=\"flex flex-row items-center justify-start\">\n          <ng-template [ngIf]=\"!!currentItems[0].label\" [ngIfElse]=\"renderTemplate\">\n            {{ currentItems[0].label }}\n          </ng-template>\n          <ng-template #renderTemplate>\n            <ng-container\n              *ngTemplateOutlet=\"currentItems[0].templateRef || dynamicValueTemplate || defaultDynamicValueTemplate; context: {$implicit: currentItems[0]}\">\n            </ng-container>\n          </ng-template>\n        </span>\n      </ng-template>\n    </ng-template>\n\n    <ng-template #multiTemplate>\n      <span>\n        {{ itemName ? itemName + ': ' : '' }}{{currentItems.length}} selected\n      </span>\n    </ng-template>\n\n    <div class=\"arrow\">\n      <svg viewBox=\"0 0 24 24\" class=\"arrow-icon\">\n        <g fill=\"none\" class=\"inner\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.2\" d=\"M10 16l4-4-4-4\" />\n        </g>\n      </svg>\n    </div>\n  </button>\n</ng-template>\n\n<ng-template #content>\n  <input *ngIf=\"allowSearch && (userProvidedItems?.length || 0) >= searchItemThreshold\" type=\"text\"\n    class=\"w-full mb-2 rounded-t\" [placeholder]=\"searchPlaceholder\" [ngModel]=\"searchText\"\n    (ngModelChange)=\"onSearch($event)\" (keydown)=\"onKeyDown($event)\" (keydown.enter)=\"onEnter($event)\">\n\n  <ul #scrollable>\n    <li *ngFor=\"let item of items\" (click)=\"selectItem(item)\" [sfng-tooltip]=\"item.description || null\"\n      snfgTooltipPosition=\"left\" [class.disabled]=\"item.disabled\" #renderedItem [sfngSelectRenderedListItem]=\"item\"\n      class=\"pl-1 pr-5\">\n\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"flex-grow-0 flex-shrink-0 w-4 h-4 transition-all duration-200\"\n        viewBox=\"0 0 20 20\" fill=\"currentColor\" [class.opacity-0]=\"!item.selected\">\n        <path fill-rule=\"evenodd\"\n          d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n\n      <ng-container\n        *ngTemplateOutlet=\"item.templateRef || dynamicValueTemplate || defaultDynamicValueTemplate; context: {$implicit: item}\">\n      </ng-container>\n    </li>\n\n    <!-- fake item for \"dynamic\" values -->\n    <li *ngIf=\"!!searchText && items.length === 0 && dynamicValues\" \n      (click)=\"selectItem({selected: false, value: searchText})\" class=\"pl-1 pr-5\">\n      <sfng-select-item>\n        <span>\n          <span class=\"mx-2 text-tertiary\">Add </span> {{ searchText }}\n        </span>\n      </sfng-select-item>\n    </li>\n  </ul>\n</ng-template>\n\n<!-- This template displays the overlay content and is connected to the button -->\n<ng-container [ngSwitch]=\"displayMode\">\n  <sfng-dropdown *ngSwitchCase=\"'dropdown'\" #dropdown=\"sfngDropdown\" [triggerTemplate]=\"customTriggerTemplate\"\n    overlayClass=\"sfng-select-dropdown\" [disabled]=\"allItems.length === 0 && searchText === '' && disableWhenEmpty\"\n    [minWidth]=\"minWidth\" [minHeight]=\"minHeight\" (opened)=\"onDropdownOpen()\" (closed)=\"onDropdownClose()\">\n    <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n  </sfng-dropdown>\n\n  <div *ngSwitchCase=\"'inline'\" class=\"sfng-select-dropdown sfng-select-inline\">\n    <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n  </div>\n</ng-container>\n\n\n<ng-template #defaultDynamicValueTemplate let-data>\n  <sfng-select-item>{{ data.label || data.value }}</sfng-select-item>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/select/select.module.ts",
    "content": "import { CdkScrollableModule } from \"@angular/cdk/scrolling\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { FormsModule, ReactiveFormsModule } from \"@angular/forms\";\nimport { SfngDropDownModule } from \"../dropdown\";\nimport { SfngTooltipModule } from \"../tooltip\";\nimport { SfngSelectItemComponent, SfngSelectValueDirective } from \"./item\";\nimport { SfngSelectComponent, SfngSelectRenderedItemDirective } from \"./select\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    ReactiveFormsModule,\n    SfngDropDownModule,\n    SfngTooltipModule,\n    CdkScrollableModule\n  ],\n  declarations: [\n    SfngSelectComponent,\n    SfngSelectValueDirective,\n    SfngSelectItemComponent,\n    SfngSelectRenderedItemDirective\n  ],\n  exports: [\n    SfngSelectComponent,\n    SfngSelectValueDirective,\n    SfngSelectItemComponent,\n  ]\n})\nexport class SfngSelectModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/select/select.ts",
    "content": "import { ListKeyManager, ListKeyManagerOption } from '@angular/cdk/a11y';\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, DestroyRef, Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, Output, QueryList, TemplateRef, ViewChild, ViewChildren, forwardRef, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { BehaviorSubject, combineLatest } from 'rxjs';\nimport { startWith } from 'rxjs/operators';\nimport { SfngDropdownComponent } from '../dropdown';\nimport { SelectOption, SfngSelectValueDirective } from './item';\n\n\nexport type SelectModes = 'single' | 'multi';\n\ntype ModeInput = {\n  mode: SelectModes;\n}\n\ntype SelectValue<T, S extends ModeInput> = S['mode'] extends 'single' ? T : T[];\n\nexport type SortByFunc = (a: SelectOption, b: SelectOption) => number;\n\nexport type SelectDisplayMode = 'dropdown' | 'inline';\n\n@Directive({\n  selector: '[sfngSelectRenderedListItem]'\n})\nexport class SfngSelectRenderedItemDirective implements ListKeyManagerOption {\n  @Input('sfngSelectRenderedListItem')\n  option: SelectOption | null = null;\n\n  getLabel() {\n    return this.option?.label || '';\n  }\n\n  get disabled() {\n    return this.option?.disabled || false;\n  }\n\n  @HostBinding('class.bg-gray-300')\n  set focused(v: boolean) {\n    this._focused = v;\n  }\n  get focused() { return this._focused }\n  private _focused = false;\n\n  constructor(public readonly elementRef: ElementRef) { }\n}\n\n@Component({\n  selector: 'sfng-select',\n  templateUrl: './select.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => SfngSelectComponent),\n      multi: true,\n    },\n  ]\n})\nexport class SfngSelectComponent<T> implements AfterViewInit, ControlValueAccessor, OnDestroy {\n  /** emits the search text entered by the user */\n  private search$ = new BehaviorSubject('');\n\n  /** emits and completes when the component is destroyed. */\n  private destroyRef = inject(DestroyRef);\n\n  /** the key manager used for keyboard support */\n  private keyManager!: ListKeyManager<SfngSelectRenderedItemDirective>;\n\n  @ViewChild(SfngDropdownComponent, { static: false })\n  dropdown: SfngDropdownComponent | null = null;\n\n  /** A reference to the cdk-scrollable directive that's placed on the item list */\n  @ViewChild('scrollable', { read: ElementRef })\n  scrollableList?: ElementRef;\n\n  @ContentChildren(SfngSelectValueDirective)\n  userProvidedItems!: QueryList<SfngSelectValueDirective>;\n\n  @ViewChildren('renderedItem', { read: SfngSelectRenderedItemDirective })\n  renderedItems!: QueryList<SfngSelectRenderedItemDirective>;\n\n  /** A list of all items available in the select box including dynamic ones. */\n  allItems: SelectOption[] = []\n\n  /** The acutally rendered list of items after applying search and item threshold */\n  items: SelectOption[] = [];\n\n  @Input()\n  @HostBinding('attr.tabindex')\n  readonly tabindex = 0;\n\n  @HostBinding('attr.role')\n  readonly role = 'listbox';\n\n  value?: SelectValue<T, this>;\n\n  /** A list of currently selected items */\n  currentItems: SelectOption[] = [];\n\n  /** The current search text. Used by ngModel */\n  searchText = '';\n\n  /** Whether or not the select operates in \"single\" or \"multi\" mode */\n  @Input()\n  mode: SelectModes = 'single';\n\n  @Input()\n  displayMode: SelectDisplayMode = 'dropdown';\n\n  /** The placehodler to show when nothing is selected */\n  @Input()\n  placeholder = 'Select'\n\n  /** The type of item to show in multi mode when more than one value is selected */\n  @Input()\n  itemName = '';\n\n  /** The maximum number of items to render. */\n  @Input()\n  set itemLimit(v: any) {\n    this._maxItemLimit = coerceNumberProperty(v)\n  }\n  get itemLimit(): number { return this._maxItemLimit }\n  private _maxItemLimit = Infinity;\n\n  /** The placeholder text for the search bar */\n  @Input()\n  searchPlaceholder = '';\n\n  /** Whether or not the search bar is visible */\n  @Input()\n  set allowSearch(v: any) {\n    this._allowSearch = coerceBooleanProperty(v);\n  }\n  get allowSearch(): boolean {\n    return this._allowSearch;\n  }\n  private _allowSearch = false;\n\n  /** The minimum number of items required for the search bar to be visible */\n  @Input()\n  set searchItemThreshold(v: any) {\n    this._searchItemThreshold = coerceNumberProperty(v);\n  }\n  get searchItemThreshold(): number {\n    return this._searchItemThreshold;\n  }\n  private _searchItemThreshold = 0;\n\n  /**\n   * Whether or not the select should be disabled when not options\n   * are available.\n   */\n  @Input()\n  set disableWhenEmpty(v: any) {\n    this._disableWhenEmpty = coerceBooleanProperty(v);\n  }\n  get disableWhenEmpty() {\n    return this._disableWhenEmpty;\n  }\n  private _disableWhenEmpty = false;\n\n  /** Whether or not the select component will add options for dynamic values as well. */\n  @Input()\n  set dynamicValues(v: any) {\n    this._dynamicValues = coerceBooleanProperty(v);\n  }\n  get dynamicValues() {\n    return this._dynamicValues\n  }\n  private _dynamicValues = false;\n\n  /** An optional template to use for dynamic values. */\n  @Input()\n  dynamicValueTemplate?: TemplateRef<any>;\n\n  /** The minimum-width of the drop-down. See {@link SfngDropdownComponent.minWidth} */\n  @Input()\n  minWidth: any;\n\n  /** The minimum-width of the drop-down. See {@link SfngDropdownComponent.minHeight} */\n  @Input()\n  minHeight: any;\n\n  /** Whether or not selected items should be sorted to the top */\n  @Input()\n  set sortValues(v: any) {\n    this._sortValues = coerceBooleanProperty(v);\n  }\n  get sortValues() {\n    if (this._sortValues === null) {\n      return this.mode === 'multi';\n    }\n    return this._sortValues;\n  }\n  private _sortValues: boolean | null = null;\n\n  /** The sort function to use. Defaults to sort by label/value */\n  @Input()\n  sortBy: SortByFunc = (a: SelectOption, b: SelectOption) => {\n    if ((a.label || a.value) < (b.label || b.value)) {\n      return 1;\n    }\n    if ((a.label || a.value) > (b.label || b.value)) {\n      return -1;\n    }\n\n    return 0;\n  }\n\n  @Input()\n  set disabled(v: any) {\n    const disabled = coerceBooleanProperty(v);\n    this.setDisabledState(disabled);\n  }\n  get disabled() {\n    return this._disabled;\n  }\n  private _disabled: boolean = false;\n\n  @HostListener('keydown.enter', ['$event'])\n  @HostListener('keydown.space', ['$event'])\n  onEnter(event: Event) {\n    if (!this.dropdown?.isOpen) {\n      this.dropdown?.toggle()\n\n      event.preventDefault();\n      event.stopPropagation();\n\n      return;\n    }\n\n    if (this.keyManager.activeItem !== null && !!this.keyManager.activeItem?.option) {\n      this.selectItem(this.keyManager.activeItem.option)\n\n      event.preventDefault();\n      event.stopPropagation();\n\n      return;\n    }\n  }\n\n  @HostListener('keydown', ['$event'])\n  onKeyDown(event: KeyboardEvent) {\n    this.keyManager.onKeydown(event);\n  }\n\n  @Output()\n  closed = new EventEmitter<void>();\n\n  @Output()\n  opened = new EventEmitter<void>();\n\n  trackItem(_: number, item: SelectOption) {\n    return item.value;\n  }\n\n  setDisabledState(disabled: boolean) {\n    this._disabled = disabled;\n    this.cdr.markForCheck();\n  }\n\n  constructor(private cdr: ChangeDetectorRef) { }\n\n  ngAfterViewInit(): void {\n    this.keyManager = new ListKeyManager(this.renderedItems)\n      .withVerticalOrientation()\n      .withHomeAndEnd()\n      .withWrap()\n      .withTypeAhead();\n\n    this.keyManager.change\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(itemIdx => {\n        this.renderedItems.forEach(item => {\n          item.focused = false;\n        })\n\n        this.keyManager.activeItem!.focused = true;\n\n        // the item might be out-of-view so make sure\n        // we scroll enough to have it inside the view\n        const scrollable = this.scrollableList?.nativeElement;\n        if (!!scrollable) {\n          const active = this.keyManager.activeItem!.elementRef.nativeElement;\n          const activeHeight = active.getBoundingClientRect().height;\n          const bottom = scrollable.scrollTop + scrollable.getBoundingClientRect().height;\n          const top = scrollable.scrollTop;\n\n          let scrollTo = -1;\n          if (active.offsetTop >= bottom) {\n            scrollTo = top + active.offsetTop - bottom + activeHeight;\n          } else if (active.offsetTop < top) {\n            scrollTo = active.offsetTop;\n          }\n\n          if (scrollTo > -1) {\n            scrollable.scrollTo({\n              behavior: 'smooth',\n              top: scrollTo,\n            })\n          }\n        }\n\n        this.cdr.markForCheck();\n      })\n\n\n    combineLatest([\n      this.userProvidedItems!.changes\n        .pipe(startWith(undefined)),\n      this.search$\n    ])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(\n        ([_, search]) => {\n          this.updateItems();\n\n          search = (search || '').toLocaleLowerCase()\n          let items: SelectOption[] = [];\n          if (search === '') {\n            items = this.allItems!;\n          } else {\n            items = this.allItems!.filter(item => {\n              // we always count selected items as a \"match\" in search mode.\n              // this is to ensure the user always see all selected items.\n              if (item.selected) {\n                return true;\n              }\n\n              if (!!item.value && typeof item.value === 'string') {\n                if (item.value.toLocaleLowerCase().includes(search)) {\n                  return true;\n                }\n              }\n\n              if (!!item.label) {\n                if (item.label.toLocaleLowerCase().includes(search)) {\n                  return true\n                }\n              }\n              return false;\n            })\n          }\n\n          this.items = items.slice(0, this._maxItemLimit);\n          this.keyManager.setActiveItem(0);\n\n          this.cdr.detectChanges();\n        }\n      );\n  }\n\n  ngOnDestroy(): void {\n    this.search$.complete();\n  }\n\n  @HostListener('blur')\n  onBlur(): void {\n    this.onTouch();\n  }\n\n  /** @private - called when the internal dropdown opens */\n  onDropdownOpen() {\n    // emit the open event on this component as well\n    this.opened.next();\n\n    // reset the search. We do that when opened instead of closed\n    // to avoid flickering when the component height increases\n    // during the \"close\" animation\n    this.onSearch('');\n  }\n\n  /** @private - called when the internal dropdown closes */\n  onDropdownClose() {\n    this.closed.next();\n  }\n\n  onSearch(text: string) {\n    this.searchText = text;\n    this.search$.next(text);\n  }\n\n  selectItem(item: SelectOption) {\n    if (item.disabled) {\n      return;\n    }\n\n    const isSelected = this.currentItems.findIndex(selected => item.value === selected.value);\n    if (isSelected === -1) {\n      item.selected = true;\n\n      if (this.mode === 'single') {\n        this.currentItems.forEach(i => i.selected = false);\n        this.currentItems = [item];\n        this.value = item.value;\n      } else {\n        this.currentItems.push(item);\n        // TODO(ppacher): somehow typescript does not correctly pick up\n        // the type of this.value here although it can be infered from the\n        // mode === 'single' check above.\n        this.value = [\n          ...(this.value || []) as any,\n          item.value,\n        ] as any\n      }\n    } else if (this.mode !== 'single') { // \"unselecting\" a value is not allowed in single mode\n      this.currentItems.splice(isSelected, 1)\n      item.selected = false;\n      // same note about typescript as above.\n      this.value = (this.value as T[]).filter(val => val !== item.value) as any;\n    }\n\n    // only close the drop down in single mode. In multi-mode\n    // we keep it open as the user might want to select an additional\n    // item as well.\n    if (this.mode === 'single') {\n      this.dropdown?.close();\n    }\n    this.onChange(this.value!);\n  }\n\n  private updateItems() {\n    let values: T[] = [];\n    if (this.mode === 'single') {\n      values = [this.value as T];\n    } else {\n      values = (this.value as T[]) || [];\n    }\n\n    this.currentItems = [];\n    this.allItems = [];\n\n    // mark all user-selected items as \"deselected\" first\n    this.userProvidedItems?.forEach(item => {\n      item.selected = false;\n      this.allItems.push(item);\n    });\n\n    for (let i = 0; i < values.length; i++) {\n      const val = values[i];\n      let option: SelectOption | undefined = this.userProvidedItems?.find(item => item.value === val);\n      if (!option) {\n        if (!this._dynamicValues) {\n          continue\n        }\n\n        option = {\n          selected: true,\n          value: val,\n          label: `${val}`,\n        }\n        this.allItems.push(option);\n      } else {\n        option.selected = true\n      }\n\n      this.currentItems.push(option);\n    }\n\n    if (this.sortValues) {\n      this.allItems.sort((a, b) => {\n        if (b.selected && !a.selected) {\n          return 1;\n        }\n\n        if (a.selected && !b.selected) {\n          return -1;\n        }\n\n        return this.sortBy(a, b)\n      })\n    }\n  }\n\n  writeValue(value: SelectValue<T, this>): void {\n    this.value = value;\n\n    this.updateItems();\n\n    this.cdr.markForCheck();\n  }\n\n  onChange = (value: SelectValue<T, this>): void => { }\n  registerOnChange(fn: (value: SelectValue<T, this>) => void): void {\n    this.onChange = fn;\n  }\n\n  onTouch = (): void => { }\n  registerOnTouched(fn: () => void): void {\n    this.onTouch = fn;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tabs/_tab-group.scss",
    "content": "sfng-tab-group {\n  @apply flex flex-col overflow-hidden;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tabs/index.ts",
    "content": "export { SfngTabComponent, SfngTabContentDirective } from './tab';\nexport { SfngTabContentScrollEvent, SfngTabGroupComponent } from './tab-group';\nexport { SfngTabModule as TabModule } from './tabs.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tabs/tab-group.html",
    "content": "<div *ngIf=\"!customHeader\" class=\"relative flex flex-row mb-2 border-b outline-none border-secondary\" tabindex=\"0\"\n  (keydown)=\"onKeydown($event)\">\n\n  <!-- Tab Group Header -->\n  <div *ngFor=\"let tab of (tabs$ | async); let index=index\"\n    class=\"flex flex-row items-center justify-center px-4 py-2 space-x-1 cursor-pointer hover:text-primary\" #tabHeader\n    [ngClass]=\"{'text-primary': index === activeTabIndex, 'text-secondary': index !== activeTabIndex}\"\n    (click)=\"activateTab(index)\">\n\n    <span>{{ tab.title }}</span>\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 text-yellow-300\" fill=\"none\" viewBox=\"0 0 24 24\"\n      *ngIf=\"tab.warning\" stroke=\"currentColor\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n        d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n    </svg>\n    <sfng-tipup [key]=\"tab.tipUpKey\" *ngIf=\"tab.tipUpKey\"></sfng-tipup>\n\n  </div>\n\n  <!-- There are no \"transition\" classes yet because we add it AFTER the first animation -->\n  <div class=\"absolute top-0 left-0 border-t border-white opacity-0\" #activeTabBar></div>\n</div>\n\n<ng-container cdkPortalOutlet></ng-container>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tabs/tab-group.ts",
    "content": "import { ListKeyManager } from \"@angular/cdk/a11y\";\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { CdkPortalOutlet, ComponentPortal } from \"@angular/cdk/portal\";\nimport { AfterContentInit, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentRef, ContentChildren, DestroyRef, ElementRef, EventEmitter, Injector, Input, OnInit, Output, QueryList, ViewChild, ViewChildren, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { ActivatedRoute, Router } from \"@angular/router\";\nimport { Observable, Subject } from \"rxjs\";\nimport { distinctUntilChanged, map, startWith } from \"rxjs/operators\";\nimport { SfngTabComponent, TAB_ANIMATION_DIRECTION, TAB_PORTAL, TAB_SCROLL_HANDLER, TabOutletComponent } from \"./tab\";\n\nexport interface SfngTabContentScrollEvent {\n  event?: Event;\n  scrollTop: number;\n  previousScrollTop: number;\n}\n\n/**\n * Tab group component for rendering a tab-style navigation with support for\n * keyboard navigation and type-ahead. Tab content are lazy loaded using a\n * structural directive.\n * The tab group component also supports adding the current active tab index\n * to the active route so it is possible to navigate through tabs using back/forward\n * keys (browser history) as well.\n *\n * Example:\n *  <sfng-tab-group>\n *\n *    <sfng-tab id=\"tab1\" title=\"Overview\">\n *      <div *sfngTabContent>\n *        Some content\n *      </div>\n *    </sfng-tab>\n *\n *    <sfng-tab id=\"tab2\" title=\"Settings\">\n *      <div *sfngTabContent>\n *        Some different content\n *      </div>\n *    </sfng-tab>\n *\n *  </sfng-tab-group>\n */\n@Component({\n  selector: 'sfng-tab-group',\n  templateUrl: './tab-group.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngTabGroupComponent implements AfterContentInit, AfterViewInit, OnInit {\n  @ContentChildren(SfngTabComponent)\n  tabs: QueryList<SfngTabComponent> | null = null;\n\n  /** References to all tab header elements */\n  @ViewChildren('tabHeader', { read: ElementRef })\n  tabHeaders: QueryList<ElementRef<HTMLDivElement>> | null = null;\n\n  /** Reference to the active tab bar element */\n  @ViewChild('activeTabBar', { read: ElementRef, static: false })\n  activeTabBar: ElementRef<HTMLDivElement> | null = null;\n\n  /** Reference to the portal outlet that we will use to render a TabOutletComponent. */\n  @ViewChild(CdkPortalOutlet, { static: true })\n  portalOutlet: CdkPortalOutlet | null = null;\n\n  @Output()\n  tabContentScroll = new EventEmitter<SfngTabContentScrollEvent>();\n\n  /** The name of the tab group. Used to update the currently active tab in the route */\n  @Input()\n  name = 'tab'\n\n  @Input()\n  outletClass = '';\n\n  private scrollTop: number = 0;\n\n  /** Whether or not the current tab should be syncronized with the angular router using a query parameter */\n  @Input()\n  set linkRouter(v: any) {\n    this._linkRouter = coerceBooleanProperty(v)\n  }\n  get linkRouter() { return this._linkRouter }\n  private _linkRouter = true;\n\n  /** Whether or not the default tab header should be rendered */\n  @Input()\n  set customHeader(v: any) {\n    this._customHeader = coerceBooleanProperty(v)\n  }\n  get customHeader() { return this._customHeader }\n  private _customHeader = false;\n\n  private tabActivate$ = new Subject<string>();\n  private destroyRef = inject(DestroyRef);\n\n  /** Emits the tab QueryList every time there are changes to the content-children */\n  get tabs$() {\n    return this.tabs?.changes\n      .pipe(\n        map(() => this.tabs),\n        startWith(this.tabs)\n      )\n  }\n\n  /** onActivate fires when a tab has been activated. */\n  get onActivate(): Observable<string> { return this.tabActivate$.asObservable() }\n\n  /** the index of the currently active tab. */\n  activeTabIndex = -1;\n\n  /** The key manager used to support keyboard navigation and type-ahead in the tab group */\n  private keymanager: ListKeyManager<SfngTabComponent> | null = null;\n\n  /** Used to force the animation direction when calling activateTab. */\n  private forceAnimationDirection: 'left' | 'right' | null = null;\n\n  /**\n   * pendingTabIdx holds the id or the index of a tab that should be activated after the component\n   * has been bootstrapped. We need to cache this value here because the ActivatedRoute might emit\n   * before we are AfterViewInit.\n   */\n  private pendingTabIdx: string | null = null;\n\n  constructor(\n    private injector: Injector,\n    private route: ActivatedRoute,\n    private router: Router,\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  /**\n   * @private\n   * Used to forward keyboard events to the keymanager.\n   */\n  onKeydown(v: KeyboardEvent) {\n    this.keymanager?.onKeydown(v);\n  }\n\n  ngOnInit(): void {\n    this.route.queryParamMap\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        map(params => params.get(this.name)),\n        distinctUntilChanged(),\n      )\n      .subscribe(newIdx => {\n        if (!this._linkRouter) {\n          return;\n        }\n\n        if (!!this.keymanager && !!this.tabs) {\n          const actualIndex = this.getIndex(newIdx);\n          if (actualIndex !== null) {\n            this.keymanager.setActiveItem(actualIndex);\n            this.cdr.markForCheck();\n          }\n        } else {\n          this.pendingTabIdx = newIdx;\n        }\n      })\n  }\n\n  ngAfterContentInit(): void {\n    this.keymanager = new ListKeyManager(this.tabs!)\n      .withHomeAndEnd()\n      .withHorizontalOrientation(\"ltr\")\n      .withTypeAhead()\n      .withWrap()\n\n    this.tabs!.changes\n      .subscribe(() => {\n        if (this.portalOutlet?.hasAttached()) {\n          if (this.tabs!.length === 0) {\n            this.portalOutlet.detach();\n          }\n        } else {\n          if (this.tabs!.length > 0) {\n            this.activateTab(0)\n          }\n        }\n\n      })\n\n    this.keymanager.change\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(change => {\n        const activeTab = this.tabs!.get(change);\n        if (!!activeTab && !!activeTab.tabContent) {\n          const prevIdx = this.activeTabIndex;\n\n          let animationDirection: 'left' | 'right' = prevIdx < change ? 'left' : 'right';\n          if (this.forceAnimationDirection !== null) {\n            animationDirection = this.forceAnimationDirection;\n            this.forceAnimationDirection = null;\n          }\n\n          if (this.portalOutlet?.attachedRef) {\n            // we know for sure that attachedRef is a ComponentRef of TabOutletComponent\n            const ref = (this.portalOutlet.attachedRef as ComponentRef<TabOutletComponent>)\n            ref.instance._animateDirection = animationDirection;\n            ref.instance.outletClass = this.outletClass;\n            ref.changeDetectorRef.detectChanges();\n          }\n\n          this.portalOutlet?.detach();\n\n          const newOutletPortal = this.createTabOutlet(activeTab, animationDirection);\n          this.activeTabIndex = change;\n          this.tabContentScroll.next({\n            scrollTop: 0,\n            previousScrollTop: this.scrollTop,\n          })\n\n          this.scrollTop = 0;\n\n          this.tabActivate$.next(activeTab.id);\n          this.portalOutlet?.attach(newOutletPortal);\n\n          this.repositionTabBar();\n\n          if (this._linkRouter) {\n            this.router.navigate([], {\n              queryParams: {\n                ...this.route.snapshot.queryParams,\n                [this.name]: this.activeTabIndex,\n              }\n            })\n          }\n          this.cdr.markForCheck();\n        }\n      });\n\n    if (this.pendingTabIdx === null) {\n      // active the first tab that is NOT disabled\n      const firstActivatable = this.tabs?.toArray().findIndex(tap => !tap.disabled);\n      if (firstActivatable !== undefined) {\n        this.keymanager.setActiveItem(firstActivatable);\n      }\n    } else {\n      const idx = this.getIndex(this.pendingTabIdx);\n      if (idx !== null) {\n        this.keymanager.setActiveItem(idx);\n        this.pendingTabIdx = null;\n      }\n    }\n  }\n\n  ngAfterViewInit(): void {\n    this.repositionTabBar();\n    this.tabHeaders?.changes.subscribe(() => this.repositionTabBar())\n    setTimeout(() => this.repositionTabBar(), 250)\n  }\n\n  /**\n   * @private\n   * Activates a new tab\n   *\n   * @param idx The index of the new tab.\n   */\n  activateTab(idx: number, forceDirection?: 'left' | 'right') {\n    if (forceDirection !== undefined) {\n      this.forceAnimationDirection = forceDirection;\n    }\n\n    this.keymanager?.setActiveItem(idx);\n  }\n\n  private getIndex(newIdx: string | null): number | null {\n    let actualIndex: number = -1;\n    if (!this.tabs) {\n      return null;\n    }\n\n    if (newIdx === undefined || newIdx === null) { // not present in the URL\n      return null;\n    }\n    if (isNaN(+newIdx)) { // likley the ID of a tab\n      actualIndex = this.tabs?.toArray().findIndex(tab => tab.id === newIdx) || -1;\n    } else { // it's a number as a string\n      actualIndex = +newIdx;\n    }\n\n    if (actualIndex < 0) {\n      return null;\n    }\n    return actualIndex;\n  }\n\n  private repositionTabBar() {\n    if (!this.tabHeaders) {\n      return;\n    }\n\n    requestAnimationFrame(() => {\n      const tabHeader = this.tabHeaders!.get(this.activeTabIndex);\n      if (!tabHeader || !this.activeTabBar) {\n        return;\n      }\n      const rect = tabHeader.nativeElement.getBoundingClientRect();\n      const transform = `translate(${tabHeader.nativeElement.offsetLeft}px, ${tabHeader.nativeElement.offsetTop + rect.height}px)`\n      this.activeTabBar.nativeElement.style.width = `${rect.width}px`\n      this.activeTabBar.nativeElement.style.transform = transform;\n      this.activeTabBar.nativeElement.style.opacity = '1';\n\n      // initialize animations on the active-tab-bar required\n      if (!this.activeTabBar.nativeElement.classList.contains(\"transition-all\")) {\n        // only initialize the transitions if this is the very first \"reposition\"\n        // this is to prevent the bar from animating to the \"bottom\" line of the tab\n        // header the first time.\n        requestAnimationFrame(() => {\n          this.activeTabBar?.nativeElement.classList.add(\"transition-all\", \"duration-200\");\n        })\n      }\n    })\n  }\n\n  private createTabOutlet(tab: SfngTabComponent, animationDir: 'left' | 'right'): ComponentPortal<TabOutletComponent> {\n    const injector = Injector.create({\n      providers: [\n        {\n          provide: TAB_PORTAL,\n          useValue: tab.tabContent!.portal,\n        },\n        {\n          provide: TAB_ANIMATION_DIRECTION,\n          useValue: animationDir,\n        },\n        {\n          provide: TAB_SCROLL_HANDLER,\n          useValue: (e: Event) => {\n            const newScrollTop = (e.target as HTMLElement).scrollTop;\n\n            tab.tabContentScroll.next(e);\n            this.tabContentScroll.next({\n              event: e,\n              scrollTop: newScrollTop,\n              previousScrollTop: this.scrollTop,\n            });\n\n            this.scrollTop = newScrollTop;\n          }\n        },\n      ],\n      parent: this.injector,\n      name: 'TabOutletInjectot',\n    })\n\n    return new ComponentPortal(\n      TabOutletComponent,\n      undefined,\n      injector\n    )\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tabs/tab.ts",
    "content": "import { animate, style, transition, trigger } from \"@angular/animations\";\nimport { ListKeyManagerOption } from \"@angular/cdk/a11y\";\nimport { coerceBooleanProperty } from \"@angular/cdk/coercion\";\nimport { CdkPortalOutlet, TemplatePortal } from \"@angular/cdk/portal\";\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, Directive, EventEmitter, Inject, InjectionToken, Input, Output, TemplateRef, ViewChild, ViewContainerRef } from \"@angular/core\";\n\n/** TAB_PORTAL is the injection token used to inject the TabContentDirective portal into TabOutletComponent */\nexport const TAB_PORTAL = new InjectionToken<TemplatePortal>('TAB_PORTAL');\n\n/** TAB_ANIMATION_DIRECTION is the injection token used to control the :enter animation origin of TabOutletComponent */\nexport const TAB_ANIMATION_DIRECTION = new InjectionToken<'left' | 'right'>('TAB_ANIMATION_DIRECTION');\n\n/** TAB_SCROLL_HANDLER is called by the SfngTabOutletComponent when a scroll event occurs. */\nexport const TAB_SCROLL_HANDLER = new InjectionToken<(_: Event) => void>('TAB_SCROLL_HANDLER')\n\n/**\n * Structural directive (*sfngTabContent) to defined lazy-loaded tab content.\n */\n@Directive({\n  selector: '[sfngTabContent]',\n})\nexport class SfngTabContentDirective<T> {\n  portal: TemplatePortal;\n\n  constructor(\n    public readonly templateRef: TemplateRef<T>,\n    public readonly viewRef: ViewContainerRef,\n  ) {\n    this.portal = new TemplatePortal(this.templateRef, this.viewRef);\n  }\n}\n\n\n/**\n * The tab component that is used to define a new tab as a part of a tab group.\n * The content of the tab is lazy-loaded by using the TabContentDirective.\n */\n@Component({\n  selector: 'sfng-tab',\n  template: '<ng-content></ng-content>',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngTabComponent implements ListKeyManagerOption {\n  @ContentChild(SfngTabContentDirective, { static: false })\n  tabContent: SfngTabContentDirective<any> | null = null;\n\n  /** The ID of the tab used to programatically activate the tab. */\n  @Input()\n  id = '';\n\n  /** The title for the tab as displayed in the tab group header. */\n  @Input()\n  title = '';\n\n  /** The key for the tip up in the tab group header. */\n  @Input()\n  tipUpKey = '';\n\n  @Input()\n  set warning(v) {\n    this._warning = coerceBooleanProperty(v)\n  }\n  get warning() { return this._warning }\n  private _warning = false;\n\n  /** Emits when the tab content is scrolled */\n  @Output()\n  tabContentScroll = new EventEmitter<Event>();\n\n  /** Whether or not the tab is currently disabled. */\n  @Input()\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v);\n  }\n  get disabled() {\n    return this._disabled;\n  }\n  private _disabled: boolean = false;\n\n  /** getLabel is used by the list key manager to support type-ahead */\n  getLabel() { return this.title }\n}\n\n\n/**\n * A simple wrapper component around CdkPortalOutlet to add nice\n * move animations.\n */\n@Component({\n  selector: 'sfng-tab-outlet',\n  template: `\n    <div [@moveInOut]=\"{value: _appAnimate, params: {in: in, out: out}}\" class=\"flex flex-col overflow-auto {{ outletClass }}\" (scroll)=\"onTabContentScroll($event)\">\n      <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n    </div>\n  `,\n  styles: [\n    `\n    :host{\n      display: flex;\n      flex-direction: column;\n      overflow: hidden;\n    }\n    `\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    trigger(\n      'moveInOut',\n      [\n        transition(\n          ':enter',\n          [\n            style({ opacity: 0, transform: 'translateX({{ in }})' }),\n            animate('.2s ease-in',\n              style({ opacity: 1, transform: 'translateX(0%)' }))\n          ],\n          { params: { in: '100%' } } // default parameters\n        ),\n        transition(\n          ':leave',\n          [\n            style({ opacity: 1 }),\n            animate('.2s ease-out',\n              style({ opacity: 0, transform: 'translateX({{ out }})' }))\n          ],\n          { params: { out: '-100%' } } // default parameters\n        )\n      ]\n    )]\n})\nexport class TabOutletComponent implements AfterViewInit {\n  _appAnimate = false;\n\n  @Input()\n  outletClass = ''\n\n  get in() {\n    return this._animateDirection == 'left' ? '100%' : '-100%'\n  }\n  get out() {\n    return this._animateDirection == 'left' ? '-100%' : '100%'\n  }\n\n  onTabContentScroll(event: Event) {\n    if (!!this.scrollHandler) {\n      this.scrollHandler(event)\n    }\n  }\n\n  @ViewChild(CdkPortalOutlet, { static: true })\n  portalOutlet!: CdkPortalOutlet;\n\n  constructor(\n    @Inject(TAB_PORTAL) public portal: TemplatePortal<any>,\n    @Inject(TAB_ANIMATION_DIRECTION) public _animateDirection: 'left' | 'right',\n    @Inject(TAB_SCROLL_HANDLER) public scrollHandler: (_: Event) => void,\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  ngAfterViewInit(): void {\n    this.portalOutlet?.attached\n      .subscribe(() => {\n        this._appAnimate = true;\n        this.cdr.detectChanges();\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tabs/tabs.module.ts",
    "content": "import { PortalModule } from \"@angular/cdk/portal\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { BrowserAnimationsModule } from \"@angular/platform-browser/animations\";\nimport { SfngTipUpModule } from \"../tipup\";\nimport { SfngTabComponent, SfngTabContentDirective, TabOutletComponent } from \"./tab\";\nimport { SfngTabGroupComponent } from \"./tab-group\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    PortalModule,\n    SfngTipUpModule,\n    BrowserAnimationsModule\n  ],\n  declarations: [\n    SfngTabContentDirective,\n    SfngTabComponent,\n    SfngTabGroupComponent,\n    TabOutletComponent,\n  ],\n  exports: [\n    SfngTabContentDirective,\n    SfngTabComponent,\n    SfngTabGroupComponent\n  ]\n})\nexport class SfngTabModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/_tipup.scss",
    "content": "sfng-tipup-container {\n  display: block;\n\n  caption {\n    @apply text-sm;\n    opacity: .6;\n    font-size: .6rem;\n  }\n\n  h1 {\n    font-size: 0.85rem;\n    font-weight: 500;\n    margin-bottom: 1rem;\n  }\n\n  .message,\n  h1 {\n    flex-shrink: 0;\n    text-overflow: ellipsis;\n    word-break: normal;\n  }\n\n  .message {\n    font-size: 0.75rem;\n    flex-grow: 1;\n    opacity: .8;\n    max-width: 300px;\n    padding: 0;\n  }\n\n  .close-icon {\n    position: absolute;\n    top: 1rem;\n    right: 1rem;\n    opacity: .7;\n    cursor: pointer;\n\n    &:hover {\n      opacity: 1;\n    }\n  }\n\n  .buttons {\n    width: 100%;\n    display: flex;\n    justify-content: space-between;\n  }\n\n  a {\n    text-decoration: underline;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/anchor.ts",
    "content": "import { Directive, ElementRef, HostBinding, Input, isDevMode } from \"@angular/core\";\nimport { SfngTipUpPlacement } from \"./utils\";\n\n@Directive({\n  selector: '[sfngTipUpAnchor]',\n})\nexport class SfngTipUpAnchorDirective implements SfngTipUpPlacement {\n  constructor(\n    public readonly elementRef: ElementRef,\n  ) { }\n\n  origin: 'left' | 'right' = 'right';\n  offset: number = 10;\n\n  @HostBinding('class.active-tipup-anchor')\n  isActiveAnchor = false;\n\n  @Input()\n  set sfngTipUpAnchor(posSpec: string | undefined) {\n    const parts = (posSpec || '').split(';')\n    if (parts.length > 2) {\n      if (isDevMode()) {\n        throw new Error(`Invalid value \"${posSpec}\" for [sfngTipUpAnchor]`);\n      }\n      return;\n    }\n\n    if (parts[0] === 'left') {\n      this.origin = 'left';\n    } else {\n      this.origin = 'right';\n    }\n\n    if (parts.length === 2) {\n      this.offset = +parts[1];\n      if (isNaN(this.offset)) {\n        this.offset = 10;\n      }\n    } else {\n      this.offset = 10;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/clone-node.ts",
    "content": "/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\n/** Creates a deep clone of an element. */\nexport function deepCloneNode(node: HTMLElement): HTMLElement {\n  const clone = node.cloneNode(true) as HTMLElement;\n  const descendantsWithId = clone.querySelectorAll('[id]');\n  const nodeName = node.nodeName.toLowerCase();\n\n  // Remove the `id` to avoid having multiple elements with the same id on the page.\n  clone.removeAttribute('id');\n\n  for (let i = 0; i < descendantsWithId.length; i++) {\n    descendantsWithId[i].removeAttribute('id');\n  }\n\n  if (nodeName === 'canvas') {\n    transferCanvasData(node as HTMLCanvasElement, clone as HTMLCanvasElement);\n  } else if (nodeName === 'input' || nodeName === 'select' || nodeName === 'textarea') {\n    transferInputData(node as HTMLInputElement, clone as HTMLInputElement);\n  }\n\n  transferData('canvas', node, clone, transferCanvasData);\n  transferData('input, textarea, select', node, clone, transferInputData);\n  return clone;\n}\n\n/** Matches elements between an element and its clone and allows for their data to be cloned. */\nfunction transferData<T extends Element>(selector: string, node: HTMLElement, clone: HTMLElement,\n  callback: (source: T, clone: T) => void) {\n  const descendantElements = node.querySelectorAll<T>(selector);\n\n  if (descendantElements.length) {\n    const cloneElements = clone.querySelectorAll<T>(selector);\n\n    for (let i = 0; i < descendantElements.length; i++) {\n      callback(descendantElements[i], cloneElements[i]);\n    }\n  }\n}\n\n// Counter for unique cloned radio button names.\nlet cloneUniqueId = 0;\n\n/** Transfers the data of one input element to another. */\nfunction transferInputData(source: Element & { value: string },\n  clone: Element & { value: string; name: string; type: string }) {\n  // Browsers throw an error when assigning the value of a file input programmatically.\n  if (clone.type !== 'file') {\n    clone.value = source.value;\n  }\n\n  // Radio button `name` attributes must be unique for radio button groups\n  // otherwise original radio buttons can lose their checked state\n  // once the clone is inserted in the DOM.\n  if (clone.type === 'radio' && clone.name) {\n    clone.name = `sfng-clone-${clone.name}-${cloneUniqueId++}`;\n  }\n}\n\n/** Transfers the data of one canvas element to another. */\nfunction transferCanvasData(source: HTMLCanvasElement, clone: HTMLCanvasElement) {\n  const context = clone.getContext('2d');\n\n  if (context) {\n    // In some cases `drawImage` can throw (e.g. if the canvas size is 0x0).\n    // We can't do much about it so just ignore the error.\n    try {\n      context.drawImage(source, 0, 0);\n    } catch { }\n  }\n}\n\n/**\n * Gets a 3d `transform` that can be applied to an element.\n * @param x Desired position of the element along the X axis.\n * @param y Desired position of the element along the Y axis.\n */\nexport function getTransform(x: number, y: number): string {\n  // Round the transforms since some browsers will\n  // blur the elements for sub-pixel transforms.\n  return `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`;\n}\n\n/**\n * Matches the target element's size to the source's size.\n * @param target Element that needs to be resized.\n * @param sourceRect Dimensions of the source element.\n */\nexport function matchElementSize(target: HTMLElement, sourceRect: ClientRect): void {\n  target.style.width = `${sourceRect.width}px`;\n  target.style.height = `${sourceRect.height}px`;\n  target.style.transform = getTransform(sourceRect.left, sourceRect.top);\n}\n\n/**\n * Shallow-extends a stylesheet object with another stylesheet-like object.\n * Note that the keys in `source` have to be dash-cased.\n */\nexport function extendStyles(dest: CSSStyleDeclaration,\n  source: Record<string, string>,\n  importantProperties?: Set<string>) {\n  for (let key in source) {\n    if (source.hasOwnProperty(key)) {\n      const value = source[key];\n\n      if (value) {\n        dest.setProperty(key, value, importantProperties?.has(key) ? 'important' : '');\n      } else {\n        dest.removeProperty(key);\n      }\n    }\n  }\n\n  return dest;\n}\n\nexport function removeNode(node: Node | null) {\n  if (node && node.parentNode) {\n    node.parentNode.removeChild(node);\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/css-utils.ts",
    "content": "\nexport function synchronizeCssStyles(src: HTMLElement, destination: HTMLElement, skipStyles: Set<string>) {\n  // Get a list of all the source and destination elements\n  const srcElements = <HTMLCollectionOf<HTMLElement>>src.getElementsByTagName('*');\n  const dstElements = <HTMLCollectionOf<HTMLElement>>destination.getElementsByTagName('*');\n\n  cloneStyle(src, destination, skipStyles);\n\n  // For each element\n  for (let i = srcElements.length; i--;) {\n    const srcElement = srcElements[i];\n    const dstElement = dstElements[i];\n    cloneStyle(srcElement, dstElement, skipStyles);\n  }\n}\n\nfunction cloneStyle(srcElement: HTMLElement, dstElement: HTMLElement, skipStyles: Set<string>) {\n  const sourceElementStyles = document.defaultView!.getComputedStyle(srcElement, '');\n  const styleAttributeKeyNumbers = Object.keys(sourceElementStyles);\n\n  // Copy the attribute\n  for (let j = 0; j < styleAttributeKeyNumbers.length; j++) {\n    const attributeKeyNumber = styleAttributeKeyNumbers[j];\n    const attributeKey: string = sourceElementStyles[attributeKeyNumber as any];\n    if (!isNaN(+attributeKey)) {\n      continue\n    }\n    if (attributeKey === 'cssText') {\n      continue\n    }\n\n    if (skipStyles.has(attributeKey)) {\n      continue\n    }\n\n    try {\n      dstElement.style[attributeKey as any] = sourceElementStyles[attributeKey as any];\n    } catch (e) {\n      console.error(attributeKey, e);\n    }\n  }\n}\n\n/**\n * Returns a CSS selector for el from rootNode.\n *\n * @param el The source element to get the CSS path to\n * @param rootNode The root node at which the CSS path should be applyable\n * @returns A CSS selector to access el from rootNode.\n */\nexport function getCssSelector(el: HTMLElement, rootNode: HTMLElement | null): string {\n  if (!el) {\n    return '';\n  }\n  let stack = [];\n  let isShadow = false;\n  while (el !== rootNode && el.parentNode !== null) {\n    // console.log(el.nodeName);\n    let sibCount = 0;\n    let sibIndex = 0;\n    // get sibling indexes\n    for (let i = 0; i < (el.parentNode as HTMLElement).childNodes.length; i++) {\n      let sib = (el.parentNode as HTMLElement).childNodes[i];\n      if (sib.nodeName == el.nodeName) {\n        if (sib === el) {\n          sibIndex = sibCount;\n        }\n        sibCount++;\n      }\n    }\n    let nodeName = el.nodeName.toLowerCase();\n    if (isShadow) {\n      throw new Error(`cannot traverse into shadow dom.`)\n    }\n    if (sibCount > 1) {\n      stack.unshift(nodeName + ':nth-of-type(' + (sibIndex + 1) + ')');\n    } else {\n      stack.unshift(nodeName);\n    }\n    el = el.parentNode as HTMLElement;\n    if (el.nodeType === 11) { // for shadow dom, we\n      isShadow = true;\n      el = (el as any).host;\n    }\n  }\n  return stack.join(' > ');\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/index.ts",
    "content": "export * from './anchor';\nexport * from './tipup';\nexport * from './tipup-component';\nexport * from './tipup.module';\nexport * from './translations';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/safe.pipe.ts",
    "content": "import { Pipe, PipeTransform } from '@angular/core';\nimport { DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';\n\n@Pipe({\n  name: 'safe'\n})\nexport class SafePipe implements PipeTransform {\n\n  constructor(protected sanitizer: DomSanitizer) { }\n\n  public transform(value: any, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {\n    switch (type) {\n      case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);\n      case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);\n      case 'script': return this.sanitizer.bypassSecurityTrustScript(value);\n      case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);\n      case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);\n      default: throw new Error(`Invalid safe type specified: ${type}`);\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/tipup-component.ts",
    "content": "import { ChangeDetectionStrategy, Component, Inject, OnInit } from \"@angular/core\";\nimport { SfngDialogRef, SFNG_DIALOG_REF } from \"../dialog\";\nimport { SfngTipUpService } from \"./tipup\";\nimport { ActionRunner, Button, SFNG_TIP_UP_ACTION_RUNNER, TipUp } from './translations';\nimport { TIPUP_TOKEN } from \"./utils\";\n\n@Component({\n  selector: 'sfng-tipup-container',\n  templateUrl: './tipup.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngTipUpComponent implements OnInit, TipUp<any> {\n  title: string = 'N/A';\n  content: string = 'N/A';\n  nextKey?: string;\n  buttons?: Button<any>[];\n  url?: string;\n  urlText: string = 'Read More';\n\n  constructor(\n    @Inject(TIPUP_TOKEN) public readonly token: string,\n    @Inject(SFNG_DIALOG_REF) private readonly dialogRef: SfngDialogRef<SfngTipUpComponent>,\n    @Inject(SFNG_TIP_UP_ACTION_RUNNER) private runner: ActionRunner<any>,\n    private tipupService: SfngTipUpService,\n  ) { }\n\n  ngOnInit() {\n    const doc = this.tipupService.getTipUp(this.token);\n    if (!!doc) {\n      Object.assign(this, doc);\n      this.urlText = doc.urlText || 'Read More';\n    }\n  }\n\n  async next() {\n    if (!this.nextKey) {\n      return;\n    }\n\n    this.tipupService.open(this.nextKey);\n    this.dialogRef.close();\n  }\n\n  async runAction(btn: Button<any>) {\n    await this.runner.performAction(btn.action);\n\n    // if we have a nextKey for the button but do not do in-app\n    // routing we should be able to open the next tipup as soon\n    // as the action finished\n    if (!!btn.nextKey) {\n      this.tipupService.waitFor(btn.nextKey!)\n        .subscribe({\n          next: () => {\n            this.dialogRef.close();\n            this.tipupService.open(btn.nextKey!);\n          },\n          error: console.error\n        })\n    } else {\n      this.close();\n    }\n  }\n\n  close() {\n    this.dialogRef.close();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/tipup.html",
    "content": "<div class=\"flex flex-col items-start\">\n  <caption>Tip</caption>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 close-icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n    (click)=\"close()\">\n    <path fill-rule=\"evenodd\"\n      d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n      clip-rule=\"evenodd\" />\n  </svg>\n\n  <h1 [innerHTML]=\"title | safe: 'html'\"></h1>\n\n  <markdown emoji [data]=\"content\" class=\"message\"></markdown>\n\n  <a *ngIf=\"!!url\" [href]=\"url\" target=\"_blank\">{{ urlText }}</a>\n\n  <div class=\"buttons\">\n    <div class=\"actions\">\n      <button *ngFor=\"let btn of buttons\" (click)=\"runAction(btn)\">{{ btn.name }}</button>\n    </div>\n    <button *ngIf=\"!!nextKey\" class=\"btn\" (click)=\"next()\">Next</button>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/tipup.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { ModuleWithProviders, NgModule, Type } from \"@angular/core\";\nimport { MarkdownModule } from \"ngx-markdown\";\nimport { SfngDialogModule } from \"../dialog\";\nimport { SfngTipUpAnchorDirective } from './anchor';\nimport { SfngsfngTipUpTriggerDirective, SfngTipUpIconComponent } from './tipup';\nimport { SfngTipUpComponent } from './tipup-component';\nimport { ActionRunner, HelpTexts, SFNG_TIP_UP_ACTION_RUNNER, SFNG_TIP_UP_CONTENTS } from \"./translations\";\nimport { SafePipe } from \"./safe.pipe\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    MarkdownModule.forChild(),\n    SfngDialogModule,\n  ],\n  declarations: [\n    SfngTipUpIconComponent,\n    SfngsfngTipUpTriggerDirective,\n    SfngTipUpComponent,\n    SfngTipUpAnchorDirective,\n    SafePipe\n  ],\n  exports: [\n    SfngTipUpIconComponent,\n    SfngsfngTipUpTriggerDirective,\n    SfngTipUpComponent,\n    SfngTipUpAnchorDirective\n  ],\n})\nexport class SfngTipUpModule {\n  static forRoot(text: HelpTexts<any>, runner: Type<ActionRunner<any>>): ModuleWithProviders<SfngTipUpModule> {\n    return {\n      ngModule: SfngTipUpModule,\n      providers: [\n        {\n          provide: SFNG_TIP_UP_CONTENTS,\n          useValue: text,\n        },\n        {\n          provide: SFNG_TIP_UP_ACTION_RUNNER,\n          useExisting: runner,\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/tipup.ts",
    "content": "/* eslint-disable @angular-eslint/no-input-rename */\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { ConnectedPosition } from '@angular/cdk/overlay';\nimport { _getShadowRoot } from '@angular/cdk/platform';\nimport { DOCUMENT } from '@angular/common';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, Directive, ElementRef, HostBinding, HostListener, Inject, Injectable, Injector, Input, NgZone, OnDestroy, Optional, Renderer2, RendererFactory2 } from '@angular/core';\nimport { Observable, of, Subject } from 'rxjs';\nimport { debounce, debounceTime, filter, map, skip, take, timeout } from 'rxjs/operators';\nimport { SfngDialogRef, SfngDialogService } from '../dialog';\nimport { SfngTipUpAnchorDirective } from './anchor';\nimport { deepCloneNode, extendStyles, matchElementSize, removeNode } from './clone-node';\nimport { getCssSelector, synchronizeCssStyles } from './css-utils';\nimport { SfngTipUpComponent } from './tipup-component';\nimport { Button, HelpTexts, SFNG_TIP_UP_CONTENTS, TipUp } from './translations';\nimport { SfngTipUpPlacement, TIPUP_TOKEN } from './utils';\n\n@Directive({\n  selector: '[sfngTipUpTrigger]',\n})\nexport class SfngsfngTipUpTriggerDirective implements OnDestroy {\n  constructor(\n    public readonly elementRef: ElementRef,\n    public dialog: SfngDialogService,\n    @Optional() @Inject(SfngTipUpAnchorDirective) public anchor: SfngTipUpAnchorDirective | ElementRef<any> | HTMLElement,\n    @Inject(SFNG_TIP_UP_CONTENTS) private tipUpContents: HelpTexts<any>,\n    private tipupService: SfngTipUpService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  private dialogRef: SfngDialogRef<SfngTipUpComponent> | null = null;\n\n  /**\n   * The helptext token used to search for the tip up defintion.\n   */\n  @Input('sfngTipUpTrigger')\n  set textKey(s: string) {\n    if (!!this._textKey) {\n      this.tipupService.deregister(this._textKey, this);\n    }\n    this._textKey = s;\n    this.tipupService.register(this._textKey, this);\n  }\n  get textKey() { return this._textKey; }\n  private _textKey: string = '';\n\n  /**\n   * The text to display inside the tip up. If unset, the tipup definition\n   * will be loaded form helptexts.yaml.\n   * This input property is mainly designed for programatic/dynamic tip-up generation\n   */\n  @Input('sfngTipUpText')\n  text: string | undefined;\n\n  @Input('sfngTipUpTitle')\n  title: string | undefined;\n\n  @Input('sfngTipUpButtons')\n  buttons: Button<any>[] | undefined;\n\n  /**\n   * asTipUp returns a tip-up definition built from the input\n   * properties sfngTipUpText and sfngTipUpTitle. If none are set\n   * then null is returned.\n   */\n  asTipUp(): TipUp<any> | null {\n    // TODO(ppacher): we could also merge the defintions from MyYamlFile\n    // and the properties set on this directive....\n    if (!this.text) {\n      return this.tipUpContents[this.textKey];\n    }\n    return {\n      title: this.title || '',\n      content: this.text,\n      buttons: this.buttons,\n    }\n  }\n\n  /**\n   * The default anchor for the tipup if non is provided via Dependency-Injection\n   * or using sfngTipUpAnchorRef\n   */\n  @Input('sfngTipUpDefaultAnchor')\n  defaultAnchor: ElementRef<any> | HTMLElement | null = null;\n\n  /** Optionally overwrite the anchor element received via Dependency Injection */\n  @Input('sfngTipUpAnchorRef')\n  set anchorRef(ref: ElementRef<any> | HTMLElement | null) {\n    this.anchor = ref ?? this.anchor;\n  }\n\n  /** Used to ensure all tip-up triggers have a pointer cursor */\n  @HostBinding('style.cursor')\n  cursor = 'pointer';\n\n  /** De-register ourself upon destroy */\n  ngOnDestroy() {\n    this.tipupService.deregister(this.textKey, this);\n  }\n\n  /** Whether or not we're passive-only and thus do not handle click-events form the user */\n  @Input('sfngTipUpPassive')\n  set passive(v: any) {\n    this._passive = coerceBooleanProperty(v ?? true);\n  }\n  get passive() { return this._passive; }\n  private _passive = false;\n\n  @Input('sfngTipUpOffset')\n  set offset(v: any) {\n    this._defaultOffset = coerceNumberProperty(v)\n  }\n  get offset() { return this._defaultOffset }\n  private _defaultOffset = 20;\n\n  @Input('sfngTipUpPlacement')\n  placement: SfngTipUpPlacement | null = null;\n\n  @HostListener('click', ['$event'])\n  onClick(event?: MouseEvent): Promise<any> {\n    if (!!event) {\n      // if there's a click event the user actually clicked the element.\n      // we only handle this if we're not marked as passive.\n      if (this._passive) {\n        return Promise.resolve();\n      }\n\n      event.preventDefault();\n      event.stopPropagation();\n    }\n\n    if (!!this.dialogRef) {\n      this.dialogRef.close();\n      return Promise.resolve();\n    }\n\n    let anchorElement: ElementRef<any> | HTMLElement | null = this.defaultAnchor || this.elementRef;\n    let placement: SfngTipUpPlacement | null = this.placement;\n\n    if (!!this.anchor) {\n      if (this.anchor instanceof SfngTipUpAnchorDirective) {\n        anchorElement = this.anchor.elementRef;\n        placement = this.anchor;\n      } else {\n        anchorElement = this.anchor;\n      }\n    }\n\n    this.dialogRef = this.tipupService.createTipup(\n      anchorElement,\n      this.textKey,\n      this,\n      placement,\n    )\n\n    this.dialogRef.onClose\n      .pipe(take(1))\n      .subscribe(() => {\n        this.dialogRef = null;\n        this.cdr.markForCheck();\n      });\n\n    this.cdr.detectChanges();\n\n    return this.dialogRef.onStateChange\n      .pipe(\n        filter(state => state === 'opening'),\n        take(1),\n      )\n      .toPromise()\n  }\n}\n\n@Component({\n  selector: 'sfng-tipup',\n  template:\n    `<svg viewBox=\"0 0 24 24\"\n    class=\"tipup\"\n    [sfngTipUpTrigger]=\"key\"\n    [sfngTipUpDefaultAnchor]=\"parent\"\n    [sfngTipUpPlacement]=\"placement\"\n    [sfngTipUpText]=\"text\"\n    [sfngTipUpTitle]=\"title\"\n    [sfngTipUpButtons]=\"buttons\"\n    [sfngTipUpAnchorRef]=\"anchor\">\n    <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" >\n      <path stroke=\"#ffff\" shape-rendering=\"geometricPrecision\" d=\"M12 21v0c-4.971 0-9-4.029-9-9v0c0-4.971 4.029-9 9-9v0c4.971 0 9 4.029 9 9v0c0 4.971-4.029 9-9 9z\"/>\n      <path stroke=\"#ffff\" shape-rendering=\"geometricPrecision\" d=\"M12 17v-5h-1M11.749 8c-.138 0-.25.112-.249.25 0 .138.112.25.25.25s.25-.112.25-.25-.112-.25-.251-.25\"/>\n    </g>\n  </svg>`,\n  styles: [\n    `\n      :host {\n        display: inline-block;\n        width   : 1rem;\n        position: relative;\n        opacity: 0.55;\n        cursor  : pointer;\n        align-self: center;\n      }\n\n      :host:hover {\n        opacity: 1;\n      }\n      `\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngTipUpIconComponent implements SfngTipUpPlacement {\n  @Input()\n  key: string = '';\n\n  // see sfngTipUpTrigger sfngTipUpText and sfngTipUpTitle\n  @Input() text: string | undefined = undefined;\n  @Input() title: string | undefined = undefined;\n  @Input() buttons: Button<any>[] | undefined = undefined;\n\n  @Input()\n  anchor: ElementRef<any> | HTMLElement | null = null;\n\n  @Input('placement')\n  origin: 'left' | 'right' = 'right';\n\n  @Input()\n  set offset(v: any) {\n    this._offset = coerceNumberProperty(v);\n  }\n  get offset() { return this._offset; }\n  private _offset: number = 10;\n\n  constructor(private elementRef: ElementRef<any>) { }\n\n  get placement(): SfngTipUpPlacement {\n    return this\n  }\n\n  get parent(): HTMLElement | null {\n    return (this.elementRef?.nativeElement as HTMLElement)?.parentElement;\n  }\n}\n\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class SfngTipUpService {\n  tipups = new Map<string, SfngsfngTipUpTriggerDirective>();\n\n  private _onRegister = new Subject<string>();\n  private _onUnregister = new Subject<string>();\n\n  get onRegister(): Observable<string> {\n    return this._onRegister.asObservable();\n  }\n\n  get onUnregister(): Observable<string> {\n    return this._onUnregister.asObservable();\n  }\n\n  waitFor(key: string): Observable<void> {\n    if (this.tipups.has(key)) {\n      return of(undefined);\n    }\n\n    return this.onRegister\n      .pipe(\n        filter(val => val === key),\n        debounce(() => this.ngZone.onStable.pipe(skip(2))),\n        debounceTime(1000),\n        take(1),\n        map(() => { }),\n        timeout(5000),\n      );\n  }\n\n  private renderer: Renderer2;\n\n  constructor(\n    @Inject(DOCUMENT) private _document: Document,\n    private dialog: SfngDialogService,\n    private ngZone: NgZone,\n    private injector: Injector,\n    rendererFactory: RendererFactory2\n  ) {\n    this.renderer = rendererFactory.createRenderer(null, null)\n  }\n\n  register(key: string, trigger: SfngsfngTipUpTriggerDirective) {\n    if (this.tipups.has(key)) {\n      return;\n    }\n\n    this.tipups.set(key, trigger);\n    this._onRegister.next(key);\n  }\n\n  deregister(key: string, trigger: SfngsfngTipUpTriggerDirective) {\n    if (this.tipups.get(key) === trigger) {\n      this.tipups.delete(key);\n      this._onUnregister.next(key);\n    }\n  }\n\n  getTipUp(key: string): TipUp<any> | null {\n    return this.tipups.get(key)?.asTipUp() || null;\n  }\n\n  private _latestTipUp: SfngDialogRef<SfngTipUpComponent> | null = null;\n\n  createTipup(\n    anchor: HTMLElement | ElementRef<any>,\n    key: string,\n    origin?: SfngsfngTipUpTriggerDirective,\n    opts: SfngTipUpPlacement | null = {},\n    injector?: Injector): SfngDialogRef<SfngTipUpComponent> {\n\n    const lastTipUp = this._latestTipUp\n    let closePrevious = () => {\n      if (!!lastTipUp) {\n        lastTipUp.close();\n      }\n    }\n\n    // make sure we have an ElementRef to work with\n    if (!(anchor instanceof ElementRef)) {\n      anchor = new ElementRef(anchor)\n    }\n\n    // the the origin placement of the tipup\n    const positions: ConnectedPosition[] = [];\n    if (opts?.origin === 'left') {\n      positions.push({\n        originX: 'start',\n        originY: 'center',\n        overlayX: 'end',\n        overlayY: 'center',\n      })\n    } else {\n      positions.push({\n        originX: 'end',\n        originY: 'center',\n        overlayX: 'start',\n        overlayY: 'center',\n      })\n    }\n\n    // determine the offset to the tipup origin\n    let offset = opts?.offset ?? 10;\n    if (opts?.origin === 'left') {\n      offset *= -1;\n    }\n\n    let postitionStrategy = this.dialog.position()\n      .flexibleConnectedTo(anchor)\n      .withPositions(positions)\n      .withDefaultOffsetX(offset);\n\n    const inj = Injector.create({\n      providers: [\n        {\n          useValue: key,\n          provide: TIPUP_TOKEN,\n        }\n      ],\n      parent: injector || this.injector,\n    });\n\n\n    const newTipUp = this.dialog.create(SfngTipUpComponent, {\n      dragable: false,\n      autoclose: true,\n      backdrop: 'light',\n      injector: inj,\n      positionStrategy: postitionStrategy\n    });\n    this._latestTipUp = newTipUp;\n\n    const _preview = this._createPreview(anchor.nativeElement, _getShadowRoot(anchor.nativeElement));\n\n    // construct a CSS selector that targets the clicked origin (sfngTipUpTriggerDirective) from within\n    // the anchor. We use that path to highlight the copy of the trigger-directive in the preview.\n    if (!!origin) {\n      const originSelector = getCssSelector(origin.elementRef.nativeElement, anchor.nativeElement);\n      let target: HTMLElement | null = null;\n      if (!!originSelector) {\n        target = _preview.querySelector(originSelector);\n      } else {\n        target = _preview;\n      }\n\n      this.renderer.addClass(target, 'active-tipup-trigger')\n    }\n\n    newTipUp.onStateChange\n      .pipe(\n        filter(state => state === 'open'),\n        take(1)\n      )\n      .subscribe(() => {\n        closePrevious();\n        _preview.attach()\n      })\n\n    newTipUp.onStateChange\n      .pipe(\n        filter(state => state === 'closing'),\n        take(1)\n      )\n      .subscribe(() => {\n        if (this._latestTipUp === newTipUp) {\n          this._latestTipUp = null;\n        }\n        _preview.classList.remove('visible');\n        setTimeout(() => {\n          removeNode(_preview);\n        }, 300)\n      });\n\n    return newTipUp;\n  }\n\n  private _createPreview(element: HTMLElement, shadowRoot: ShadowRoot | null): HTMLElement & { attach: () => void } {\n    const preview = deepCloneNode(element);\n    // clone all CSS styles by applying them directly to the copied\n    // nodes. Though, we skip the opacity property because we use that\n    // a lot and it makes the preview strange ....\n    synchronizeCssStyles(element, preview, new Set([\n      'opacity'\n    ]));\n\n    // make sure the preview element is at the exact same position\n    // as the original one.\n    matchElementSize(preview, element.getBoundingClientRect());\n\n    extendStyles(preview.style, {\n      // We have to reset the margin, because it can throw off positioning relative to the viewport.\n      'margin': '0',\n      'position': 'fixed',\n      'top': '0',\n      'left': '0',\n      'z-index': '1000',\n      'opacity': 'unset',\n    }, new Set(['position']));\n\n    // We add a dedicated class to the preview element so\n    // it can handle special higlighting itself.\n    preview.classList.add('tipup-preview')\n\n    // since the user might want to click on the preview element we must\n    // intercept the click-event, determine the path to the target element inside\n    // the preview and eventually dispatch a click-event on the actual\n    // - real - target inside the cloned element.\n    preview.onclick = function (event: MouseEvent) {\n      let path = getCssSelector(event.target as HTMLElement, preview);\n      if (!!path) {\n        // find the target by it's CSS path\n        let actualTarget: HTMLElement | null = element.querySelector<HTMLElement>(path);\n\n        // some (SVG) elements don't have a direct click() listener so we need to search\n        // the parents upwards to find one that implements click().\n        // we're basically searching up until we reach the <html> tag.\n        //\n        // TODO(ppacher): stop searching at the respective root node.\n        if (!!actualTarget) {\n          let iter: HTMLElement = actualTarget;\n          while (iter != null) {\n            if ('click' in iter && typeof iter['click'] === 'function') {\n              iter.click();\n              break;\n            }\n            iter = iter.parentNode as HTMLElement;\n          }\n        }\n      } else {\n        // the user clicked the preview element directly\n        try {\n          element.click()\n        } catch (e) {\n          console.error(e);\n        }\n      }\n    }\n\n    let attach = () => {\n      const parent = this._getPreviewInserationPoint(shadowRoot)\n      const cdkOverlayContainer = parent.getElementsByClassName('cdk-overlay-container')[0]\n      // if we find a cdkOverlayContainer in our inseration point (which we expect to be there)\n      // we insert the preview element right after the overlay-backdrop. This way the tip-up\n      // dialog will still be on top of the preview.\n      if (!!cdkOverlayContainer) {\n        const reference = cdkOverlayContainer.getElementsByClassName(\"cdk-overlay-backdrop\")[0].nextSibling;\n        cdkOverlayContainer.insertBefore(preview, reference)\n      } else {\n        parent.appendChild(preview);\n      }\n\n      setTimeout(() => {\n        preview.classList.add('visible');\n      })\n    }\n\n    Object.defineProperty(preview, 'attach', {\n      value: attach,\n    })\n\n    return preview as any;\n  }\n\n  private _getPreviewInserationPoint(shadowRoot: ShadowRoot | null): HTMLElement {\n    const documentRef = this._document;\n    return shadowRoot ||\n      documentRef.fullscreenElement ||\n      (documentRef as any).webkitFullscreenElement ||\n      (documentRef as any).mozFullScreenElement ||\n      (documentRef as any).msFullscreenElement ||\n      documentRef.body;\n  }\n\n  async open(key: string) {\n    const comp = this.tipups.get(key);\n    if (!comp) {\n      console.error('Tried to open unknown tip-up with key ' + key);\n      return;\n    }\n    comp.onClick()\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/translations.ts",
    "content": "import { InjectionToken } from '@angular/core';\n\nexport const SFNG_TIP_UP_CONTENTS = new InjectionToken<HelpTexts<any>>('SfngTipUpContents');\nexport const SFNG_TIP_UP_ACTION_RUNNER = new InjectionToken<ActionRunner<any>>('SfngTipUpActionRunner')\n\nexport interface Button<T> {\n  name: string;\n  action: T;\n  nextKey?: string;\n}\n\nexport interface TipUp<T> {\n  title: string;\n  content: string;\n  url?: string;\n  urlText?: string;\n  buttons?: Button<T>[];\n  nextKey?: string;\n}\n\nexport interface HelpTexts<T> {\n  [key: string]: TipUp<T>;\n}\n\nexport interface ActionRunner<T> {\n  performAction(action: T): Promise<void>;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tipup/utils.ts",
    "content": "import { InjectionToken } from \"@angular/core\";\n\nexport const TIPUP_TOKEN = new InjectionToken<string>('TipUPJSONToken');\n\nexport interface SfngTipUpPlacement {\n  origin?: 'left' | 'right';\n  offset?: number;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/toggle-switch/_toggle-switch.scss",
    "content": "sfng-toggle {\n  @apply flex items-center;\n\n  label {\n    @apply inline-block w-10 h-5 relative bg-gray-500 rounded-full;\n  }\n\n  .slider {\n    @apply absolute cursor-pointer top-0 left-0 right-0 bottom-0 bg-gray-600 transition-all duration-100 rounded-full shadow-inner-xs;\n  }\n\n  .dot {\n    @apply absolute transition-all duration-200 rounded-full bg-white;\n    height: 18px;\n    width: 18px;\n    bottom: 1px;\n    left: 1px;\n  }\n\n  input:checked:not(:disabled)+.slider {\n    @apply bg-green-300 bg-opacity-50 text-green;\n  }\n\n  input:disabled+.slider {\n    @apply opacity-75 cursor-not-allowed;\n  }\n\n  .dot.checked {\n    transform: translateX(calc(2.5rem - 18px - 2px));\n  }\n\n  .dot.disabled {\n    transform: translateX(calc((2.5rem - 18px - 2px)/2));\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/toggle-switch/index.ts",
    "content": "export * from './toggle-switch';\nexport * from './toggle.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/toggle-switch/toggle-switch.html",
    "content": "<label>\n  <input type=\"checkbox\" class=\"block w-0 h-0 opacity-0\" [ngModel]=\"value\" (ngModelChange)=\"onValueChange($event)\" [disabled]=\"disabled\">\n  <span class=\"slider\">\n    <span class=\"flex items-center justify-center dot\" [class.checked]=\"value && !disabled\" [class.disabled]=\"disabled\">\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-3 h-3\" viewBox=\"0 0 20 20\" fill=\"currentColor\" *ngIf=\"value && !disabled\">\n        <path fill-rule=\"evenodd\"\n          d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-3 h-3\" viewBox=\"0 0 20 20\" fill=\"currentColor\" *ngIf=\"!value && !disabled\">\n        <path fill-rule=\"evenodd\"\n          d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-3 h-3\" viewBox=\"0 0 20 20\" fill=\"currentColor\" *ngIf=\"disabled\">\n        <path fill-rule=\"evenodd\" d=\"M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z\" clip-rule=\"evenodd\" />\n      </svg>\n    </span>\n  </span>\n</label>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/toggle-switch/toggle-switch.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostListener } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\n@Component({\n  selector: 'sfng-toggle',\n  templateUrl: './toggle-switch.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => SfngToggleSwitchComponent),\n      multi: true,\n    }\n  ]\n})\nexport class SfngToggleSwitchComponent implements ControlValueAccessor {\n  @HostListener('blur')\n  onBlur() {\n    this.onTouch();\n  }\n\n  set disabled(v: any) {\n    this.setDisabledState(coerceBooleanProperty(v))\n  }\n  get disabled() {\n    return this._disabled;\n  }\n  private _disabled = false;\n\n  value: boolean = false;\n\n  constructor(private _changeDetector: ChangeDetectorRef) { }\n\n  setDisabledState(isDisabled: boolean) {\n    this._disabled = isDisabled;\n    this._changeDetector.markForCheck();\n  }\n\n  onValueChange(value: boolean) {\n    this.value = value;\n    this.onChange(this.value);\n  }\n\n  writeValue(value: boolean) {\n    this.value = value;\n    this._changeDetector.markForCheck();\n  }\n\n  onChange = (_: any): void => { };\n  registerOnChange(fn: (value: any) => void) {\n    this.onChange = fn;\n  }\n\n  onTouch = (): void => { };\n  registerOnTouched(fn: () => void) {\n    this.onTouch = fn;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/toggle-switch/toggle.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { FormsModule } from \"@angular/forms\";\nimport { SfngToggleSwitchComponent } from \"./toggle-switch\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n  ],\n  declarations: [\n    SfngToggleSwitchComponent,\n  ],\n  exports: [\n    SfngToggleSwitchComponent,\n  ]\n})\nexport class SfngToggleSwitchModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tooltip/_tooltip-component.scss",
    "content": "sfng-tooltip-container {\n  @apply relative block;\n\n  max-width: 16rem;\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tooltip/index.ts",
    "content": "export * from './tooltip';\nexport * from './tooltip.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tooltip/tooltip-component.html",
    "content": "<div [@moveInOut]=\"{value: _appAnimate, params: {value: value, what: what}}\" *ngIf=\"_appAnimate\"\n  [style.transformOrigin]=\"transformOrigin\" (@moveInOut.done)=\"animationDone($event)\"\n  class=\"relative px-2 py-0.5 text-white bg-gray-100 text-xxs border rounded shadow-lg w-fit\">\n  {{ message }}\n  <ng-container [cdkPortalOutlet]=\"portal\"></ng-container>\n</div>\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tooltip/tooltip-component.ts",
    "content": "import { animate, AnimationEvent, style, transition, trigger } from \"@angular/animations\";\nimport { OverlayRef } from \"@angular/cdk/overlay\";\nimport { TemplatePortal } from \"@angular/cdk/portal\";\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, Inject, InjectionToken, OnDestroy, TemplateRef, ViewContainerRef } from \"@angular/core\";\nimport { SfngTooltipDirective } from \"./tooltip\";\n\nexport const SFNG_TOOLTIP_CONTENT = new InjectionToken<string | TemplateRef<any>>('SFNG_TOOLTIP_CONTENT');\nexport const SFNG_TOOLTIP_OVERLAY = new InjectionToken<OverlayRef>('SFNG_TOOLTIP_OVERLAY');\n\n@Component({\n  selector: 'sfng-tooltip-container',\n  templateUrl: './tooltip-component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    trigger(\n      'moveInOut',\n      [\n        transition(\n          ':enter',\n          [\n            style({ opacity: 0, transform: 'translate{{ what }}({{ value }}) scale(0.75)' }),\n            animate('.1s ease-in',\n              style({ opacity: 1, transform: 'translate{{ what }}(0%) scale(1)' }))\n          ],\n          { params: { what: 'Y', value: '-8px' } } // default parameters\n        ),\n        transition(\n          ':leave',\n          [\n            style({ opacity: 1 }),\n            animate('.1s ease-out',\n              style({ opacity: 0, transform: 'translate{{ what }}({{ value }}) scale(0.75)' }))\n          ],\n          { params: { what: 'Y', value: '8px' } } // default parameters\n        )\n      ]\n    )]\n\n})\nexport class SfngTooltipComponent implements AfterViewInit, OnDestroy {\n  /**\n   * Adds snfg-tooltip-instance class to the host element.\n   * This is used as a selector in the FlexibleConnectedPosition stragegy\n   * to set a transform-origin. That origin is then used for the \"arrow\" anchor\n   * placement.\n   */\n  @HostBinding('class.sfng-tooltip-instance')\n  _hostClass = true;\n\n  /**\n   * Used to clear the \"hide\" timeout when the cursor moves from the the origin\n   * into the tooltip content.\n   * This is required if the tooltip contains rich and likely clickable content.\n   */\n  @HostListener('mouseenter')\n  onMouseEnter() { this.directive.show() }\n\n  /**\n   * If the tooltip is visible because the user moved inside the tooltip-component\n   * (see comment above) then we need to handle a mouse-leave event as well.\n   */\n  @HostListener('mouseleave')\n  onMouseLeave() { this.directive.hide() }\n\n  what = 'Y';\n  value = '8px'\n  transformOrigin = '';\n\n  _appAnimate = false;\n\n  private observer: MutationObserver | null = null;\n\n  /** Message is the tooltip message to display in case tooltipContent is a string */\n  message = '';\n\n  /** Portal is the tooltip content to display in case tooltipContent is a template reference */\n  portal: TemplatePortal<any> | null = null;\n\n  constructor(\n    @Inject(SFNG_TOOLTIP_CONTENT) tooltipContent: string | TemplateRef<any>,\n    @Inject(SFNG_TOOLTIP_OVERLAY) public overlayRef: OverlayRef,\n    private directive: SfngTooltipDirective,\n    private elementRef: ElementRef<HTMLElement>,\n    private cdr: ChangeDetectorRef,\n    private viewContainer: ViewContainerRef\n  ) {\n    if (tooltipContent instanceof TemplateRef) {\n      this.portal = new TemplatePortal(tooltipContent, this.viewContainer)\n    } else {\n      this.message = tooltipContent;\n    }\n  }\n\n  dispose() {\n    this._appAnimate = false;\n    this.cdr.markForCheck();\n  }\n\n  animationDone(event: AnimationEvent) {\n    if (event.toState === 'void') {\n      this.overlayRef.dispose();\n    }\n  }\n\n  ngOnDestroy(): void {\n    this.observer?.disconnect();\n  }\n\n  ngAfterViewInit(): void {\n    this.observer = new MutationObserver(mutations => {\n      this.transformOrigin = this.elementRef.nativeElement.style.transformOrigin;\n      if (!this.transformOrigin) {\n        return;\n      }\n\n      const [x, y] = this.transformOrigin.split(\" \");\n      if (x === 'center') {\n        this.what = 'Y'\n        if (y === 'top') {\n          this.value = '-8px'\n        } else {\n          this.value = '8px'\n        }\n      } else {\n        this.what = 'X'\n        if (x === 'left') {\n          this.value = '-8px'\n        } else {\n          this.value = '8px'\n        }\n      }\n\n      this._appAnimate = true;\n      this.cdr.detectChanges();\n    });\n    this.observer.observe(this.elementRef.nativeElement, { attributes: true, attributeFilter: ['style'] })\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tooltip/tooltip.module.ts",
    "content": "import { OverlayModule } from \"@angular/cdk/overlay\";\nimport { PortalModule } from \"@angular/cdk/portal\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { SfngTooltipDirective } from \"./tooltip\";\nimport { SfngTooltipComponent } from \"./tooltip-component\";\n\n@NgModule({\n  imports: [\n    PortalModule,\n    OverlayModule,\n    CommonModule,\n  ],\n  declarations: [\n    SfngTooltipDirective,\n    SfngTooltipComponent\n  ],\n  exports: [\n    SfngTooltipDirective\n  ]\n})\nexport class SfngTooltipModule { }\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/tooltip/tooltip.ts",
    "content": "/* eslint-disable @angular-eslint/no-input-rename */\nimport { coerceNumberProperty } from \"@angular/cdk/coercion\";\nimport { ConnectedPosition, Overlay, OverlayRef, PositionStrategy } from \"@angular/cdk/overlay\";\nimport { ComponentPortal } from \"@angular/cdk/portal\";\nimport { ComponentRef, Directive, ElementRef, HostListener, Injector, Input, isDevMode, OnChanges, OnDestroy, OnInit, TemplateRef } from \"@angular/core\";\nimport { Subject } from \"rxjs\";\nimport { SfngTooltipComponent, SFNG_TOOLTIP_CONTENT, SFNG_TOOLTIP_OVERLAY } from \"./tooltip-component\";\n\n/** The allowed tooltip positions. */\nexport type SfngTooltipPosition = 'left' | 'right' | 'bottom' | 'top';\n\n@Directive({\n  selector: '[sfng-tooltip],[snfgTooltip]',\n})\nexport class SfngTooltipDirective implements OnInit, OnDestroy, OnChanges {\n  /** Used to control the visibility of the tooltip */\n  private attach$ = new Subject<boolean>();\n\n  /** Holds a reference to the tooltip overlay */\n  private tooltipRef: ComponentRef<SfngTooltipComponent> | null = null;\n\n  /**\n   * A reference to a timeout created by setTimeout used to debounce\n   * displaying the tooltip\n   */\n  private debouncer: any | null = null;\n\n  constructor(\n    private overlay: Overlay,\n    private injector: Injector,\n    private originRef: ElementRef<any>,\n  ) { }\n\n  @HostListener('mouseenter')\n  show(delay = this.delay) {\n    if (this.debouncer !== null) {\n      clearTimeout(this.debouncer);\n    }\n\n    this.debouncer = setTimeout(() => {\n      this.debouncer = null;\n      this.attach$.next(true);\n    }, delay);\n  }\n\n  @HostListener('mouseleave')\n  hide(delay = this.delay / 2) {\n    // if we're currently debouncing a \"show\" than\n    // we should clear that out to avoid re-attaching\n    // the tooltip right after we disposed it.\n    if (this.debouncer !== null) {\n      clearTimeout(this.debouncer);\n      this.debouncer = null;\n    }\n\n    this.debouncer = setTimeout(() => {\n      this.attach$.next(false);\n      this.debouncer = null;\n    }, delay);\n  }\n\n  /** Debounce delay before showing the tooltip */\n  @Input('sfngTooltipDelay')\n  set delay(v: any) {\n    this._delay = coerceNumberProperty(v);\n  }\n  get delay() { return this._delay }\n  private _delay = 500;\n\n  /** An additional offset between the tooltip overlay and the origin centers */\n  @Input('sfngTooltipOffset')\n  set offset(v: any) {\n    this._offset = coerceNumberProperty(v);\n  }\n  private _offset: number | null = 8;\n\n  /** The actual content that should be displayed in the tooltip overlay. */\n  @Input('sfngTooltip')\n  @Input('sfng-tooltip')\n  tooltipContent: string | TemplateRef<any> | null = null;\n\n  @Input('snfgTooltipPosition')\n  position: ConnectedPosition | SfngTooltipPosition | (SfngTooltipPosition | ConnectedPosition)[] | 'any' = 'any';\n\n  ngOnInit() {\n    this.attach$\n      .subscribe(attach => {\n        if (attach) {\n          this.createTooltip();\n          return;\n        }\n        if (!!this.tooltipRef) {\n          this.tooltipRef.instance.dispose();\n          this.tooltipRef = null;\n        }\n      })\n  }\n\n  ngOnDestroy(): void {\n    this.attach$.next(false);\n    this.attach$.complete();\n  }\n\n  ngOnChanges(): void {\n    // if the tooltip content has be set to null and we're still\n    // showing the tooltip we treat that as an attempt to hide.\n    if (this.tooltipContent === null && !!this.tooltipRef) {\n      this.hide();\n    }\n  }\n\n  /** Creates the actual tooltip overlay */\n  private createTooltip() {\n    // there's nothing to do if the tooltip is still active.\n    if (!!this.tooltipRef) {\n      return;\n    }\n\n    // support disabling the tooltip by passing \"null\" for\n    // the content.\n    if (this.tooltipContent === null) {\n      return;\n    }\n\n    const position = this.buildPositionStrategy();\n\n    const overlayRef = this.overlay.create({\n      positionStrategy: position,\n      scrollStrategy: this.overlay.scrollStrategies.close(),\n      disposeOnNavigation: true,\n    });\n\n    // make sure we close the tooltip if the user clicks on our\n    // originRef.\n    overlayRef.outsidePointerEvents()\n      .subscribe(() => this.hide());\n\n    overlayRef.attachments()\n      .subscribe(() => {\n        if (!overlayRef) {\n          return\n        }\n        overlayRef.updateSize({});\n        overlayRef.updatePosition();\n      })\n\n    // create a component portal for the tooltip component\n    // and attach it to our newly created overlay.\n    const portal = this.getOverlayPortal(overlayRef);\n    this.tooltipRef = overlayRef.attach(portal);\n  }\n\n  private getOverlayPortal(ref: OverlayRef): ComponentPortal<SfngTooltipComponent> {\n    const inj = Injector.create({\n      providers: [\n        { provide: SFNG_TOOLTIP_CONTENT, useValue: this.tooltipContent },\n        { provide: SFNG_TOOLTIP_OVERLAY, useValue: ref },\n      ],\n      parent: this.injector,\n      name: 'SfngTooltipDirective'\n    })\n\n    const portal = new ComponentPortal(\n      SfngTooltipComponent,\n      undefined,\n      inj\n    )\n\n    return portal;\n  }\n\n  /** Builds a FlexibleConnectedPositionStrategy for the tooltip overlay */\n  private buildPositionStrategy(): PositionStrategy {\n    let pos = this.position;\n    if (pos === 'any') {\n      pos = ['top', 'bottom', 'right', 'left']\n    } else if (!Array.isArray(pos)) {\n      pos = [pos];\n    }\n\n    let allowedPositions: ConnectedPosition[] =\n      pos.map(p => {\n        if (typeof p === 'string') {\n          return this.getAllowedConnectedPosition(p);\n        }\n        // this is already a ConnectedPosition\n        return p\n      });\n\n    let position = this.overlay.position()\n      .flexibleConnectedTo(this.originRef)\n      .withFlexibleDimensions(true)\n      .withPush(true)\n      .withPositions(allowedPositions)\n      .withGrowAfterOpen(true)\n      .withTransformOriginOn('.sfng-tooltip-instance')\n\n    return position;\n  }\n\n  private getAllowedConnectedPosition(type: SfngTooltipPosition): ConnectedPosition {\n    switch (type) {\n      case 'left':\n        return {\n          originX: 'start',\n          originY: 'center',\n          overlayX: 'end',\n          overlayY: 'center',\n          offsetX: - (this._offset || 0),\n        }\n      case 'right':\n        return {\n          originX: 'end',\n          originY: 'center',\n          overlayX: 'start',\n          overlayY: 'center',\n          offsetX: (this._offset || 0),\n        }\n      case 'top':\n        return {\n          originX: 'center',\n          originY: 'top',\n          overlayX: 'center',\n          overlayY: 'bottom',\n          offsetY: - (this._offset || 0),\n        }\n      case 'bottom':\n        return {\n          originX: 'center',\n          originY: 'bottom',\n          overlayX: 'center',\n          overlayY: 'top',\n          offsetY: (this._offset || 0),\n        }\n      default:\n        if (isDevMode()) {\n          throw new Error(`invalid value for SfngTooltipPosition: ${type}`)\n        }\n        // fallback to \"right\"\n        return this.getAllowedConnectedPosition('right')\n    }\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/lib/ui.module.ts",
    "content": "import { NgModule } from '@angular/core';\nimport { SfngAccordionModule } from './accordion';\n\n\n@NgModule({\n  exports: [\n    SfngAccordionModule\n  ]\n})\nexport class UiModule { }\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/public-api.ts",
    "content": "/*\n * Public API Surface of ui\n */\n\nexport * from './lib/accordion';\nexport * from './lib/dialog';\nexport * from './lib/dropdown';\nexport * from './lib/overlay-stepper';\nexport * from './lib/pagination';\nexport * from './lib/select';\nexport * from './lib/tabs';\nexport * from './lib/tipup';\nexport * from './lib/toggle-switch';\nexport * from './lib/tooltip';\nexport * from './lib/ui.module';\n\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/src/test.ts",
    "content": "// This file is required by karma.conf.js and loads recursively all the .spec and framework files\n\nimport { getTestBed } from '@angular/core/testing';\nimport {\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting\n} from '@angular/platform-browser-dynamic/testing';\nimport 'zone.js';\nimport 'zone.js/testing';\n\n// First, initialize the Angular testing environment.\ngetTestBed().initTestEnvironment(\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting(),\n  { teardown: { destroyAfterEach: true } },\n);\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/theming.scss",
    "content": "@import \"./src/lib/select/select\";\n@import \"./src/lib/dialog/dialog\";\n@import \"./src/lib/pagination/pagination\";\n@import \"./src/lib/tabs/tab-group\";\n@import \"./src/lib/tipup/tipup\";\n@import \"./src/lib/tooltip/tooltip-component\";\n@import \"./src/lib/toggle-switch/toggle-switch\";\n@import \"./src/lib/dialog/confirm.dialog\";\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/tsconfig.lib.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../../out-tsc/lib\",\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"inlineSources\": true,\n    \"types\": [],\n    \"lib\": [\n      \"dom\",\n      \"es2018\"\n    ]\n  },\n  \"exclude\": [\n    \"src/test.ts\",\n    \"**/*.spec.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/tsconfig.lib.prod.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"./tsconfig.lib.json\",\n  \"compilerOptions\": {\n    \"declarationMap\": false\n  },\n}\n"
  },
  {
    "path": "desktop/angular/projects/safing/ui/tsconfig.spec.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../../out-tsc/spec\",\n    \"types\": [\n      \"jasmine\"\n    ]\n  },\n  \"files\": [\n    \"src/test.ts\"\n  ],\n  \"include\": [\n    \"**/*.spec.ts\",\n    \"**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/projects/tauri-builtin/src/app/app.component.html",
    "content": "<div class=\"flex flex-row items-center justify-start text-white w-full gap-2 p-2\">\n  <!-- Logo -->\n  <div class=\"relative w-24 h-20 flex-grow-0 flex-shrink-0 block\" id=\"logo\">\n    <svg stroke=\"currentColor\" data-name=\"Layer-1\" viewBox=\"0 0 128 128\">\n      <g data-name=\"Main\" fill-rule=\"evenodd\">\n        <path shape-rendering=\"geometricPrecision\" fill=\"#fff\"\n          d=\"M176.11 36.73l-5-8.61a41.53 41.53 0 00-14.73 57.22l8.55-5.12a31.58 31.58 0 0111.19-43.49z\"\n          transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n        <path shape-rendering=\"geometricPrecision\" fill=\"#fff\" class=\"inner\"\n          d=\"M222.36 72.63a31.55 31.55 0 01-45 19.35l-4.62 8.84a41.54 41.54 0 0059.17-25.46z\"\n          transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n      </g>\n    </svg>\n    <svg data-name=\"layer-2\" viewBox=\"0 0 128 128\">\n      <g data-name=\"Main\" fill-rule=\"evenodd\">\n        <path shape-rendering=\"geometricPrecision\" fill=\"#fff\"\n          d=\"M197 83a19.66 19.66 0 01-19.25-32.57l-4.5-4.27A25.87 25.87 0 00198.59 89z\"\n          transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".6\"></path>\n      </g>\n    </svg>\n    <svg data-name=\"layer-3\" viewBox=\"0 0 128 128\">\n      <g data-name=\"Main\" fill-rule=\"evenodd\">\n        <path shape-rendering=\"geometricPrecision\" fill=\"#fff\"\n          d=\"M192 112.64A48.64 48.64 0 11240.64 64 48.64 48.64 0 01192 112.64zM256 64a64 64 0 10-64 64 64 64 0 0064-64z\"\n          transform=\"translate(-127.99 .1)\"></path>\n      </g>\n    </svg>\n  </div>\n\n  <div class=\"flex flex-col leading-3\">\n    <h2>Safing</h2>\n    <h1 class=\"text-2xl\">\n      Portmaster\n    </h1>\n  </div>\n</div>\n\n<div [ngSwitch]=\"status\" class=\"text-base flex flex-row gap-4 mx-2 text-white mt-2 items-center justify-evenly\"\n  [ngClass]=\"{\n      'bg-red-300 p-2 rounded shadow-inner': status !== 'Running' && status !== null\n    }\">\n\n  <ng-template [ngSwitchCase]=\"null\">\n    Connecting to System Service ...\n  </ng-template>\n\n  <ng-template [ngSwitchCase]=\"'Running'\">\n    Connecting to System Service ...\n  </ng-template>\n\n  <ng-template [ngSwitchCase]=\"'Stopped'\">\n\n    Portmaster System Service is not running:\n\n    <button (click)=\"startService()\"\n      class=\"px-2 py-1 rounded uppercase text-xs block self-end btn bg-white bg-opacity-25 text-white hover:bg-red-100 cursor-pointer\">\n      Start Now\n    </button>\n\n  </ng-template>\n\n  <ng-template [ngSwitchCase]=\"'NotFound'\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-12 h-12\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z\" />\n    </svg>\n\n    <span>\n      Failed to find Portmaster System Service.\n      <br />\n      Please reinstall the application.\n    </span>\n\n    <button (click)=\"getHelp()\"\n      class=\"px-2 py-1 rounded uppercase text-xs block self-end btn bg-white bg-opacity-25 text-white hover:bg-red-100 cursor-pointer\">Get\n      Help</button>\n  </ng-template>\n\n  <ng-template [ngSwitchCase]=\"'unsupported service manager'\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-12 h-12\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z\" />\n    </svg>\n\n    <span>\n      Your System Service Manager is not supported. Please make sure Portmaster is running.\n    </span>\n  </ng-template>\n\n  <ng-template [ngSwitchCase]=\"'unsupported operating system'\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-12 h-12\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z\" />\n    </svg>\n\n    <span>\n      Your System Service Manager is not supported. Please make sure Portmaster is running.\n    </span>\n  </ng-template>\n\n  <span *ngSwitchDefault>Unknown error: {{ status }}</span>\n</div>"
  },
  {
    "path": "desktop/angular/projects/tauri-builtin/src/app/app.component.ts",
    "content": "import { OnInit, Component, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { ServiceManagerStatus, TauriIntegrationService } from 'src/app/integration/taur-app';\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  imports: [CommonModule],\n  templateUrl: './app.component.html',\n  styles: [\n    `\n      :host {\n        @apply block w-screen h-screen bg-background;\n      }\n\n      #logo svg {\n        @apply absolute w-20;\n      }\n    `,\n  ],\n})\nexport class AppComponent implements OnInit {\n  private tauri = inject(TauriIntegrationService);\n\n  status: ServiceManagerStatus | string | null = null;\n\n  getHelp() {\n    this.tauri.openExternal(\"https://wiki.safing.io/en/Portmaster/App\")\n  }\n\n  startService() {\n    this.tauri.startService()\n      .then(() => this.getStatus())\n      .catch(err => {\n        this.status = err.error;\n      });\n  }\n\n  getStatus() {\n    this.tauri.getServiceManagerStatus()\n      .then(result => {\n        this.status = result;\n      })\n      .catch(err => {\n        this.status = err.error;\n      })\n  }\n\n  ngOnInit() {\n    this.getStatus();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/projects/tauri-builtin/src/app/app.config.ts",
    "content": "import { ApplicationConfig } from '@angular/core';\nimport { TauriIntegrationService } from 'src/app/integration/taur-app';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    {\n      provide: TauriIntegrationService,\n      useClass: TauriIntegrationService,\n      deps: []\n    },\n  ],\n};\n"
  },
  {
    "path": "desktop/angular/projects/tauri-builtin/src/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>TauriBuiltin</title>\n  <base href=\"/\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link rel=\"icon\" type=\"image/x-icon\" href=\"favicon.ico\">\n</head>\n<body>\n  <app-root></app-root>\n</body>\n</html>\n"
  },
  {
    "path": "desktop/angular/projects/tauri-builtin/src/main.ts",
    "content": "import { bootstrapApplication } from '@angular/platform-browser';\nimport { appConfig } from './app/app.config';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent, appConfig)\n  .catch((err) => console.error(err));\n"
  },
  {
    "path": "desktop/angular/projects/tauri-builtin/src/styles.scss",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@import \"safing/ui/theming\";\n\n/** foboar **/\n"
  },
  {
    "path": "desktop/angular/projects/tauri-builtin/tsconfig.app.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../out-tsc/app\",\n    \"types\": []\n  },\n  \"files\": [\"src/main.ts\"],\n  \"include\": [\"src/**/*.d.ts\", \"../../src/electron-app.d.ts\"]\n}\n"
  },
  {
    "path": "desktop/angular/proxy.json",
    "content": "{\n  \"/api\": {\n    \"target\": \"http://localhost:817/\",\n    \"secure\": false\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/app-routing.module.ts",
    "content": "import { NgModule } from '@angular/core';\nimport { RouterModule, Routes } from '@angular/router';\nimport { AppViewComponent } from './pages/app-view';\nimport { DashboardPageComponent } from './pages/dashboard/dashboard.component';\nimport { MonitorPageComponent } from './pages/monitor';\nimport { SettingsComponent } from './pages/settings/settings';\nimport { SpnPageComponent } from './pages/spn';\nimport { SupportPageComponent } from './pages/support';\nimport { SupportFormComponent } from './pages/support/form';\n\nconst routes: Routes = [\n  {\n    path: '',\n    pathMatch: 'full',\n    redirectTo: 'dashboard',\n  },\n  {\n    path: 'settings',\n    component: SettingsComponent,\n  },\n  {\n    path: 'app',\n    pathMatch: 'full',\n    redirectTo: 'app/overview',\n  },\n  {\n    path: 'app/overview',\n    component: AppViewComponent,\n  },\n  {\n    path: 'app/:source/:id',\n    component: AppViewComponent,\n  },\n  {\n    path: 'monitor',\n    component: MonitorPageComponent,\n  },\n  {\n    path: 'monitor/profile/:source/:profile',\n    redirectTo: 'monitor',\n  },\n  {\n    path: 'support',\n    component: SupportPageComponent,\n  },\n  {\n    path: 'support/:id',\n    component: SupportFormComponent,\n  },\n  {\n    path: 'spn',\n    component: SpnPageComponent,\n  },\n  {\n    path: '**',\n    redirectTo: 'dashboard'\n  },\n  {\n    path: 'dashboard',\n    component: DashboardPageComponent\n  }\n];\n\n@NgModule({\n  imports: [RouterModule.forRoot(routes, { anchorScrolling: 'enabled' })],\n  exports: [RouterModule]\n})\nexport class AppRoutingModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/app.component.html",
    "content": "<app-navigation #navigation (sideDashChange)=\"onSideDashChange($event)\" class=\"relative block bg-background\">\n</app-navigation>\n\n<div *ngIf=\"sideDashStatus === 'expanded' && sideDashOverlay\" (click)=\"navigation.toggleSideDash($event)\" [@fadeIn]\n  [@fadeOut] class=\"absolute top-0 bottom-0 right-0 left-16 dialog-screen-backdrop-light\" style=\"z-index: 100\"></div>\n\n<app-side-dash class=\"flex-shrink-0\" style=\"z-index: 100\"\n  [ngClass]=\"{'absolute top-0 left-16 bg-gray-1002 h-full shadow-2xl': sideDashOverlay, 'relative': !sideDashOverlay}\"\n  *ngIf=\"sideDashStatus === 'expanded'\" [@fadeIn] (@fadeIn.done)=\"windowResizeChange.next()\" [@fadeOut]\n  (@fadeOut.done)=\"windowResizeChange.next()\">\n</app-side-dash>\n\n<div class=\"main\" #mainContent>\n  <router-outlet></router-outlet>\n</div>\n\n<div class=\"loading\" *ngIf=\"(showOverlay$ | async) as overlayText\" [@fadeIn] [@fadeOut]>\n  <div class=\"message\">\n    <div class=\"logo\" routerLink=\"monitor\">\n      <svg data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n        viewBox=\"0 0 128 128\" class=\"spin reverse\">\n        <g data-name=\"Main\" fill-rule=\"evenodd\">\n          <path fill=\"#fff\" class=\"inner\"\n            d=\"M176.11 36.73l-5-8.61a41.53 41.53 0 00-14.73 57.22l8.55-5.12a31.58 31.58 0 0111.19-43.49z\"\n            transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n          <path fill=\"#fff\" class=\"inner\"\n            d=\"M222.36 72.63a31.55 31.55 0 01-45 19.35l-4.62 8.84a41.54 41.54 0 0059.17-25.46z\"\n            transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n        </g>\n      </svg>\n\n      <svg data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n        viewBox=\"0 0 128 128\" class=\"spin\">\n        <g data-name=\"Main\" fill-rule=\"evenodd\">\n          <path fill=\"#fff\" class=\"inner reverse\"\n            d=\"M197 83a19.66 19.66 0 01-19.25-32.57l-4.5-4.27A25.87 25.87 0 00198.59 89z\"\n            transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".6\"></path>\n        </g>\n      </svg>\n\n      <svg data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n        viewBox=\"0 0 128 128\">\n        <g data-name=\"Main\" fill-rule=\"evenodd\">\n          <path fill=\"#fff\"\n            d=\"M192 112.64A48.64 48.64 0 11240.64 64 48.64 48.64 0 01192 112.64zM256 64a64 64 0 10-64 64 64 64 0 0064-64z\"\n            transform=\"translate(-127.99 .1)\"></path>\n        </g>\n      </svg>\n    </div>\n    <h1>{{overlayText}}</h1>\n    <h1>...</h1>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/app.component.scss",
    "content": ":host {\n  display: flex;\n  @apply bg-background;\n  @apply h-screen overflow-hidden;\n\n  &>* {\n    flex-shrink: 0;\n  }\n}\n\napp-navigation,\napp-side-dash {\n  @apply border-r;\n  @apply border-cards-tertiary;\n  @apply bg-background;\n}\n\napp-navigation {\n  @apply w-16;\n}\n\ndiv.main {\n  flex-grow: 1;\n  flex-shrink: 1;\n\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  @apply bg-background;\n  height: 100vh;\n  overflow: hidden;\n}\n\napp-debug {\n  @apply border-l;\n  @apply border-cards-tertiary;\n  @apply bg-background;\n\n  width: 30vw;\n  height: 100vh;\n  min-width: 350px;\n  top: 0px;\n  position: sticky;\n}\n\n.loading {\n  z-index: 100;\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n  backdrop-filter: blur(10px);\n  background-color: rgba(#222222, 0.35);\n\n  .message {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    width: 100%;\n    flex-direction: column;\n  }\n\n  svg {\n    width: 100%;\n    position: absolute;\n    top: 0;\n    left: 0;\n  }\n\n  div.logo {\n    opacity: 0.8;\n    position: relative;\n    width: 10vh;\n    height: 10vh;\n    @apply mt-4;\n  }\n\n  .spin {\n    animation-name: spin;\n    animation-duration: 3500ms;\n    animation-iteration-count: infinite;\n    animation-timing-function: linear;\n  }\n\n  .reverse {\n    animation-name: spin-reverse;\n  }\n}\n\n\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes spin-reverse {\n  0% {\n    transform: rotate(360deg);\n  }\n\n  100% {\n    transform: rotate(0deg);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/app.component.spec.ts",
    "content": "import { TestBed, waitForAsync } from '@angular/core/testing';\nimport { RouterTestingModule } from '@angular/router/testing';\nimport { AppComponent } from './app.component';\n\ndescribe('AppComponent', () => {\n  beforeEach(waitForAsync(() => {\n    TestBed.configureTestingModule({\n      imports: [\n        RouterTestingModule\n      ],\n      declarations: [\n        AppComponent\n      ],\n    }).compileComponents();\n  }));\n\n  it('should create the app', () => {\n    const fixture = TestBed.createComponent(AppComponent);\n    const app = fixture.componentInstance;\n    expect(app).toBeTruthy();\n  });\n\n  it(`should have as title 'portmaster'`, () => {\n    const fixture = TestBed.createComponent(AppComponent);\n    const app = fixture.componentInstance;\n    expect(app.title).toEqual('portmaster');\n  });\n});\n"
  },
  {
    "path": "desktop/angular/src/app/app.component.ts",
    "content": "import { Overlay } from '@angular/cdk/overlay';\nimport { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostListener, Inject, NgZone, OnInit, Renderer2, ViewChild } from '@angular/core';\nimport { Params, Router } from '@angular/router';\nimport { PortapiService } from '@safing/portmaster-api';\nimport { OverlayStepper, SfngDialogService, StepperRef } from '@safing/ui';\nimport { BehaviorSubject, merge, Subject } from 'rxjs';\nimport { debounceTime, filter, mergeMap, skip, startWith, take } from 'rxjs/operators';\nimport { IntroModule } from './intro';\nimport { NotificationsService, UIStateService } from './services';\nimport { ActionIndicatorService } from './shared/action-indicator';\nimport { fadeInAnimation, fadeOutAnimation } from './shared/animations';\nimport { ExitService } from './shared/exit-screen';\nimport { SfngNetquerySearchOverlayComponent } from './shared/netquery/search-overlay';\nimport { INTEGRATION_SERVICE, IntegrationService } from './integration';\nimport { TauriIntegrationService } from './integration/taur-app';\n\n@Component({\n  selector: 'app-root',\n  templateUrl: './app.component.html',\n  styleUrls: ['./app.component.scss'],\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation,\n  ]\n})\nexport class AppComponent implements OnInit, AfterViewInit {\n  readonly connected = this.portapi.connected$.pipe(\n    debounceTime(250),\n    startWith(false)\n  );\n  title = 'portmaster';\n\n  /** The current status of the side dash as emitted by the navigation component */\n  sideDashStatus: 'collapsed' | 'expanded' = 'expanded';\n\n  /** Whether or not the side-dash is in overlay mode */\n  sideDashOverlay = false;\n\n  /** The MQL to watch for screen size changes. */\n  private mql!: MediaQueryList;\n\n  /** Emits when the side-dash is opened or closed in non-overlay mode */\n  private sideDashOpen = new BehaviorSubject<boolean>(false);\n\n  /** Used to emit when the window size changed */\n  windowResizeChange = new Subject<void>();\n\n  get sideDashOpen$() { return this.sideDashOpen.asObservable() }\n\n  get showOverlay$() { return this.exitService.showOverlay$ }\n\n  get onContentSizeChange$() {\n    return merge(\n      this.windowResizeChange,\n      this.sideDashOpen$\n    )\n      .pipe(\n        startWith(undefined),\n        debounceTime(100),\n      )\n  }\n\n  @ViewChild('mainContent', { read: ElementRef, static: true })\n  mainContent!: ElementRef<HTMLDivElement>;\n\n  @HostListener('window:resize')\n  onWindowResize() {\n    this.windowResizeChange.next();\n  }\n\n  @HostListener('document:keydown', ['$event'])\n  onKeyDown(event: KeyboardEvent) {\n    if (event.key === ' ' && event.ctrlKey) {\n      this.dialog.create(\n        SfngNetquerySearchOverlayComponent,\n        {\n          positionStrategy: this.overlay\n            .position()\n            .global()\n            .centerHorizontally()\n            .top('1rem'),\n          backdrop: 'light',\n          autoclose: true,\n        }\n      )\n      return;\n    }\n  }\n\n  constructor(\n    public ngZone: NgZone,\n    public portapi: PortapiService,\n    public changeDetectorRef: ChangeDetectorRef,\n    private router: Router,\n    private exitService: ExitService,\n    private overlayStepper: OverlayStepper,\n    private dialog: SfngDialogService,\n    private overlay: Overlay,\n    private stateService: UIStateService,\n    private renderer2: Renderer2,\n    @Inject(INTEGRATION_SERVICE) private integration: IntegrationService,\n  ) {\n    (window as any).portapi = portapi;\n  }\n\n  onSideDashChange(state: 'expanded' | 'collapsed' | 'force-overlay') {\n    if (state === 'force-overlay') {\n      state = 'expanded';\n      if (!this.sideDashOverlay) {\n        this.sideDashOverlay = true;\n      }\n    } else {\n      this.sideDashOverlay = this.mql.matches;\n    }\n\n    this.sideDashStatus = state;\n\n    if (!this.sideDashOverlay) {\n      this.sideDashOpen.next(this.sideDashStatus === 'expanded')\n    }\n  }\n\n  ngOnInit() {\n    // default breakpoints used by tailwindcss\n    const minContentWithBp = [\n      640,  // sfng-sm:\n      768,  // sfng-md:\n      1024, // sfng-lg:\n      1280, // sfng-xl:\n      1536  // sfng-2xl:\n    ]\n\n    // prepare our breakpoint listeners and add the classes to our main element\n    merge(\n      this.windowResizeChange,\n      this.sideDashOpen$\n    )\n      .pipe(\n        startWith(undefined),\n        debounceTime(100),\n      )\n      .subscribe(() => {\n        const rect = (this.mainContent.nativeElement as HTMLElement).getBoundingClientRect();\n\n        minContentWithBp.forEach((bp, idx) => {\n          if (rect.width >= bp) {\n            this.renderer2.addClass(this.mainContent.nativeElement, `min-width-${bp}px`)\n          } else {\n            this.renderer2.removeClass(this.mainContent.nativeElement, `min-width-${bp}px`)\n          }\n        })\n\n        this.changeDetectorRef.markForCheck();\n      })\n\n    // force a reload of the current route if we reconnected to\n    // portmaster. This ensures we'll refresh any data that's currently\n    // displayed.\n    this.connected\n      .pipe(\n        filter(connected => !!connected),\n        skip(1),\n      )\n      .subscribe(async () => {\n        const location = new URL(window.location.toString());\n\n        const params: Params = {}\n        location.searchParams.forEach((value, key) => {\n          params[key] = [\n            ...(params[key] || []),\n            value,\n          ]\n        })\n\n        await this.router.navigateByUrl('/', { skipLocationChange: true })\n        this.router.navigate([location.pathname], {\n          queryParams: params,\n        });\n      })\n\n    this.stateService.uiState()\n      .pipe(take(1))\n      .subscribe(state => {\n        if (!state.introScreenFinished) {\n          this.showIntro();\n        }\n      })\n\n    this.mql = window.matchMedia('(max-width: 1200px)');\n    this.sideDashOverlay = this.mql.matches;\n\n    this.mql.addEventListener('change', () => {\n      this.sideDashOverlay = this.mql.matches;\n\n      if (!this.sideDashOverlay) {\n        this.sideDashOpen.next(this.sideDashStatus === 'expanded')\n      }\n    })\n  }\n\n  ngAfterViewInit(): void {\n    this.sideDashOpen.next(this.sideDashStatus !== 'collapsed')\n\n    if (this.integration instanceof TauriIntegrationService) {\n      let tauri = this.integration;\n\n      tauri.shouldShow()\n        .then(show => {\n          console.log(\"should open window: \", show)\n          if (show) {\n            tauri.openApp();\n          }\n        });\n    }\n  }\n\n  showIntro(): StepperRef {\n    const stepperRef = this.overlayStepper.create(IntroModule.Stepper)\n\n    stepperRef.onFinish.subscribe(() => {\n      this.stateService.uiState()\n        .pipe(\n          take(1),\n          mergeMap(state => this.stateService.saveState({\n            ...state,\n            introScreenFinished: true\n          }))\n        )\n        .subscribe();\n    })\n\n    return stepperRef;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/app.module.ts",
    "content": "import { DragDropModule } from '@angular/cdk/drag-drop';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport { PortalModule } from '@angular/cdk/portal';\nimport { ScrollingModule } from '@angular/cdk/scrolling';\nimport { CdkTableModule } from '@angular/cdk/table';\nimport { CommonModule, registerLocaleData } from '@angular/common';\n\nimport { APP_INITIALIZER, LOCALE_ID, NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { BrowserAnimationsModule } from '@angular/platform-browser/animations';\nimport { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome';\nimport { faGithub } from '@fortawesome/free-brands-svg-icons';\nimport { far } from '@fortawesome/free-regular-svg-icons';\nimport { fas } from '@fortawesome/free-solid-svg-icons';\nimport { ConfigService, PortmasterAPIModule, StringSetting, getActualValue } from '@safing/portmaster-api';\nimport { OverlayStepperModule, SfngAccordionModule, SfngDialogModule, SfngDropDownModule, SfngPaginationModule, SfngSelectModule, SfngTipUpModule, SfngToggleSwitchModule, SfngTooltipModule, TabModule, UiModule } from '@safing/ui';\nimport MyYamlFile from 'js-yaml-loader!../i18n/helptexts.yaml';\nimport * as i18n from 'ng-zorro-antd/i18n';\nimport { MarkdownModule } from 'ngx-markdown';\nimport { firstValueFrom } from 'rxjs';\nimport { environment } from 'src/environments/environment';\nimport { AppRoutingModule } from './app-routing.module';\nimport { AppComponent } from './app.component';\nimport { IntroModule } from './intro';\nimport { NavigationComponent } from './layout/navigation/navigation';\nimport { SideDashComponent } from './layout/side-dash/side-dash';\nimport { AppOverviewComponent, AppViewComponent, QuickSettingInternetButtonComponent } from './pages/app-view';\nimport { QsHistoryComponent } from './pages/app-view/qs-history/qs-history.component';\nimport { QuickSettingSelectExitButtonComponent } from './pages/app-view/qs-select-exit/qs-select-exit';\nimport { QuickSettingUseSPNButtonComponent } from './pages/app-view/qs-use-spn/qs-use-spn';\nimport { DashboardPageComponent } from './pages/dashboard/dashboard.component';\nimport { FeatureCardComponent } from './pages/dashboard/feature-card/feature-card.component';\nimport { MonitorPageComponent } from './pages/monitor';\nimport { SettingsComponent } from './pages/settings/settings';\nimport { SPNModule } from './pages/spn/spn.module';\nimport { SupportPageComponent } from './pages/support';\nimport { SupportFormComponent } from './pages/support/form';\nimport { NotificationsService } from './services';\nimport { ActionIndicatorModule } from './shared/action-indicator';\nimport { SfngAppIconModule } from './shared/app-icon';\nimport { ConfigModule } from './shared/config';\nimport { CountIndicatorModule } from './shared/count-indicator';\nimport { CountryFlagModule } from './shared/country-flag';\nimport { EditProfileDialog } from './shared/edit-profile-dialog';\nimport { ExitScreenComponent } from './shared/exit-screen/exit-screen';\nimport { ExpertiseModule } from './shared/expertise/expertise.module';\nimport { ExternalLinkDirective } from './shared/external-link.directive';\nimport { FeatureScoutComponent } from './shared/feature-scout';\nimport { SfngFocusModule } from './shared/focus';\nimport { FuzzySearchPipe } from './shared/fuzzySearch';\nimport { LoadingComponent } from './shared/loading';\nimport { SfngMenuModule } from './shared/menu';\nimport { SfngMultiSwitchModule } from './shared/multi-switch';\nimport { NetqueryModule } from './shared/netquery';\nimport { NetworkScoutComponent } from './shared/network-scout';\nimport { NotificationListComponent } from './shared/notification-list/notification-list.component';\nimport { NotificationComponent } from './shared/notification/notification';\nimport { CommonPipesModule } from './shared/pipes';\nimport { ProcessDetailsDialogComponent } from './shared/process-details-dialog';\nimport { PromptListComponent } from './shared/prompt-list/prompt-list.component';\nimport { SecurityLockComponent } from './shared/security-lock';\nimport { SPNAccountDetailsComponent } from './shared/spn-account-details';\nimport { SPNLoginComponent } from './shared/spn-login';\nimport { SPNStatusComponent } from './shared/spn-status';\nimport { PlaceholderComponent } from './shared/text-placeholder';\nimport { DashboardWidgetComponent } from './pages/dashboard/dashboard-widget/dashboard-widget.component';\nimport { MergeProfileDialogComponent } from './pages/app-view/merge-profile-dialog/merge-profile-dialog.component';\nimport { AppInsightsComponent } from './pages/app-view/app-insights/app-insights.component';\nimport { INTEGRATION_SERVICE, integrationServiceFactory } from './integration';\nimport { SupportProgressDialogComponent } from './pages/support/progress-dialog';\n\nfunction loadAndSetLocaleInitializer(configService: ConfigService) {\n  return async function () {\n    let angularLocaleID = 'en-GB';\n    let nzLocaleID: string = 'en_GB';\n\n    try {\n      const setting = await firstValueFrom(configService.get(\"core/locale\"))\n\n      const currentValue = getActualValue(setting as StringSetting);\n      switch (currentValue) {\n        case 'en-US':\n          angularLocaleID = 'en-US'\n          nzLocaleID = 'en_US'\n          break;\n        case 'en-GB':\n          angularLocaleID = 'en-GB'\n          nzLocaleID = 'en_GB'\n          break;\n\n        default:\n          console.error(`Unsupported locale value: ${currentValue}, defaulting to en-GB`)\n      }\n    } catch (err) {\n      console.error(`failed to get locale setting, using default en-GB:`, err)\n    }\n\n    try {\n      // Get name of module.\n      let localeModuleID = angularLocaleID;\n      if (localeModuleID == \"en-US\") {\n        localeModuleID = \"en\";\n      }\n\n      /* webpackInclude: /(en|en-GB)\\.mjs$/ */\n      /* webpackChunkName: \"./l10n-base/[request]\"*/\n      await import(`../../node_modules/@angular/common/locales/${localeModuleID}.mjs`)\n        .then(locale => {\n          registerLocaleData(locale.default)\n\n          localeConfig.localeId = angularLocaleID;\n          localeConfig.nzLocale = (i18n as any)[nzLocaleID];\n        })\n    } catch (err) {\n      console.error(`failed to load locale module for ${angularLocaleID}:`, err)\n    }\n  }\n}\n\nconst localeConfig = {\n  nzLocale: i18n.en_GB,\n  localeId: 'en-GB'\n}\n\n@NgModule({\n  declarations: [\n    AppComponent,\n    NotificationComponent,\n    SettingsComponent,\n    MonitorPageComponent,\n    SideDashComponent,\n    NavigationComponent,\n    NotificationListComponent,\n    PromptListComponent,\n    FuzzySearchPipe,\n    AppViewComponent,\n    QuickSettingInternetButtonComponent,\n    QuickSettingUseSPNButtonComponent,\n    QuickSettingSelectExitButtonComponent,\n    AppOverviewComponent,\n    PlaceholderComponent,\n    LoadingComponent,\n    ExternalLinkDirective,\n    ExitScreenComponent,\n    SupportPageComponent,\n    SupportFormComponent,\n    SecurityLockComponent,\n    SPNStatusComponent,\n    FeatureScoutComponent,\n    SPNLoginComponent,\n    SPNAccountDetailsComponent,\n    NetworkScoutComponent,\n    EditProfileDialog,\n    ProcessDetailsDialogComponent,\n    QsHistoryComponent,\n    DashboardPageComponent,\n    DashboardWidgetComponent,\n    FeatureCardComponent,\n    MergeProfileDialogComponent,\n    AppInsightsComponent,\n    SupportProgressDialogComponent\n  ],\n  imports: [\n    BrowserModule,\n    CommonModule,\n    BrowserAnimationsModule,\n    FormsModule,\n    ReactiveFormsModule,\n    AppRoutingModule,\n    FontAwesomeModule,\n    OverlayModule,\n    PortalModule,\n    CdkTableModule,\n    DragDropModule,\n    MarkdownModule.forRoot(),\n    ScrollingModule,\n    SfngAccordionModule,\n    TabModule,\n    SfngTipUpModule.forRoot(MyYamlFile, NotificationsService),\n    SfngTooltipModule,\n    ActionIndicatorModule,\n    SfngDialogModule,\n    OverlayStepperModule,\n    IntroModule,\n    SfngDropDownModule,\n    SfngSelectModule,\n    SfngMultiSwitchModule,\n    SfngMenuModule,\n    SfngFocusModule,\n    SfngToggleSwitchModule,\n    SfngPaginationModule,\n    SfngAppIconModule,\n    ExpertiseModule,\n    ConfigModule,\n    CountryFlagModule,\n    CountIndicatorModule,\n    NetqueryModule,\n    CommonPipesModule,\n    UiModule,\n    SPNModule,\n    PortmasterAPIModule.forRoot({\n      httpAPI: environment.httpAPI,\n      websocketAPI: environment.portAPI,\n    }),\n  ],\n  bootstrap: [AppComponent],\n  providers: [\n    {\n      provide: APP_INITIALIZER, useFactory: loadAndSetLocaleInitializer, deps: [ConfigService], multi: true\n    },\n    {\n      provide: i18n.NZ_I18N, useFactory: () => {\n        console.log(\"nz-locale is set to\", localeConfig.nzLocale)\n        return localeConfig.nzLocale\n      }\n    },\n    {\n      provide: LOCALE_ID, useFactory: () => {\n        console.log(\"locale-id is set to\", localeConfig.localeId)\n        return localeConfig.localeId\n      }\n    },\n    {\n      provide: INTEGRATION_SERVICE,\n      useFactory: integrationServiceFactory\n    }\n  ]\n})\nexport class AppModule {\n  constructor(library: FaIconLibrary) {\n    library.addIconPacks(fas, far);\n    library.addIcons(faGithub)\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/integration/browser.ts",
    "content": "import { AppInfo, IntegrationService, ProcessInfo } from \"./integration\";\n\nexport class BrowserIntegrationService implements IntegrationService {\n  writeToClipboard(text: string): Promise<void> {\n    if (!!navigator.clipboard) {\n      return navigator.clipboard.writeText(text);\n    }\n\n    return Promise.reject(new Error(`Clipboard API not supported`))\n  }\n\n  openExternal(pathOrUrl: string): Promise<void> {\n    window.open(pathOrUrl, '_blank')\n\n    return Promise.resolve();\n  }\n\n  getInstallDir(): Promise<string> {\n    return Promise.reject('Not supported in browser')\n  }\n\n  getAppIcon(_: ProcessInfo): Promise<string> {\n    return Promise.reject('Not supported in browser')\n  }\n\n  getAppInfo(_: ProcessInfo): Promise<AppInfo> {\n    return Promise.reject('Not supported in browser')\n  }\n\n  exitApp(): Promise<void> {\n    window.close();\n\n    return Promise.resolve();\n  }\n\n  onExitRequest(cb: () => void): () => void {\n    // nothing to do, there\n    return () => { }\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/integration/electron.ts",
    "content": "import { BrowserIntegrationService } from \"./browser\";\nimport { AppInfo, ProcessInfo } from \"./integration\";\n\nexport class ElectronIntegrationService extends BrowserIntegrationService {\n\n  openExternal(pathOrUrl: string): Promise<void> {\n    if (!!window.app) {\n      return window.app.openExternal(pathOrUrl);\n    }\n\n    return Promise.reject('No electron API available')\n  }\n\n  getInstallDir(): Promise<string> {\n    if (!!window.app) {\n      return window.app.getInstallDir()\n    }\n\n    return Promise.reject('No electron API available')\n  }\n\n  getAppIcon(info: ProcessInfo): Promise<string> {\n    if (!!window.app) {\n      return window.app.getFileIcon(info.execPath)\n    }\n\n    return Promise.reject('No electron API available')\n  }\n\n  getAppInfo(_: ProcessInfo): Promise<AppInfo> {\n    return Promise.reject('Not supported in electron')\n  }\n\n  exitApp(): Promise<void> {\n    if (!!window.app) {\n      window.app.exitApp();\n    }\n\n    return Promise.resolve();\n  }\n\n  onExitRequest(cb: () => void): () => void {\n    let listener = (event: MessageEvent<any>) => {\n      if (event.data === 'on-app-close') {\n        cb();\n      }\n    }\n\n    window.addEventListener('message', listener);\n\n    return () => {\n      window.removeEventListener('message', listener)\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/integration/factory.ts",
    "content": "import { InjectionToken } from \"@angular/core\";\nimport { BrowserIntegrationService } from \"./browser\";\nimport { ElectronIntegrationService } from \"./electron\";\nimport { IntegrationService } from \"./integration\";\nimport { TauriIntegrationService } from \"./taur-app\";\n\nexport function integrationServiceFactory(): IntegrationService {\n  if ('__TAURI__' in window) {\n    console.log(\"[app] running under tauri\")\n    return new TauriIntegrationService();\n  }\n\n  if ('app' in window) {\n    console.log(\"[app] running under electron\")\n    return new ElectronIntegrationService();\n  }\n\n  console.log(\"[app] running in browser\")\n  return new BrowserIntegrationService();\n}\n\nexport const INTEGRATION_SERVICE = new InjectionToken<IntegrationService>('INTEGRATION_SERVICE');\n"
  },
  {
    "path": "desktop/angular/src/app/integration/index.ts",
    "content": "export * from './integration';\nexport * from './factory';\n"
  },
  {
    "path": "desktop/angular/src/app/integration/integration.ts",
    "content": "\nexport interface AppInfo {\n  app_name: string;\n  comment: string;\n  icon_dataurl: string;\n  icon_path: string;\n}\n\nexport interface ProcessInfo {\n  execPath: string;\n  cmdline: string;\n  pid: number;\n  matchingPath: string;\n}\n\nexport interface IntegrationService {\n  /** writeToClipboard copies text to the system clipboard */\n  writeToClipboard(text: string): Promise<void>;\n\n  /** openExternal opens a file or URL in an external window */\n  openExternal(pathOrUrl: string): Promise<void>;\n\n  /** Gets the path to the portmaster installation directory */\n  getInstallDir(): Promise<string>;\n\n  /** Load application information (currently linux only) */\n  getAppInfo(info: ProcessInfo): Promise<AppInfo>;\n\n  /** Loads the application icon as a dataurl */\n  getAppIcon(info: ProcessInfo): Promise<string>;\n\n  /** Closes the application, does not return */\n  exitApp(): Promise<void>;\n\n  /** Registers a listener for on-close requests. */\n  onExitRequest(cb: () => void): () => void;\n}\n\n\n\n\n"
  },
  {
    "path": "desktop/angular/src/app/integration/taur-app.ts",
    "content": "import { AppInfo, IntegrationService, ProcessInfo } from \"./integration\";\nimport { writeText } from '@tauri-apps/plugin-clipboard-manager';\nimport { open } from '@tauri-apps/plugin-shell';\nimport { listen, once } from '@tauri-apps/api/event';\nimport { invoke } from '@tauri-apps/api/core'\nimport { getCurrentWindow, Window } from '@tauri-apps/api/window';\n\n// Returns a new uuidv4. If crypto.randomUUID is not available it fals back to\n// using Math.random(). While this is not as random as it should be it's still\n// enough for our use-case here (which is just to generate a random response-id).\nfunction uuid(): string {\n  if (typeof crypto.randomUUID === 'function') {\n    return crypto.randomUUID();\n  }\n\n  // This one is not really random and not RFC compliant but serves enough for fallback\n  // purposes if the UI is opened in a browser that does not yet support randomUUID\n  console.warn('Using browser with lacking support for crypto.randomUUID()');\n\n  return Date.now().toString(36) + Math.random().toString(36).substring(2);\n}\n\nfunction asyncInvoke<T>(method: string, args: object): Promise<T> {\n  return new Promise<T>((resolve, reject) => {\n    const eventId = uuid();\n\n    const listenerPromise = once<T & { error: string }>(eventId, (event) => {\n      if (typeof event.payload === 'object' && 'error' in event.payload) {\n        reject(event.payload);\n        return\n      }\n\n      resolve(event.payload);\n    })\n\n    // Only make the invoke call after the listener is registered\n    listenerPromise.then(() => {\n      invoke<string>(method, {\n        ...args,\n        responseId: eventId,\n      }).catch((err: any) => {\n        console.error(\"tauri:invoke rejected: \", method, args, err);\n        reject(err)\n      });\n    })\n  });\n}\n\nexport type ServiceManagerStatus = 'Running' | 'Stopped' | 'NotFound' | 'unsupported service manager' | 'unsupported operating system';\n\nexport class TauriIntegrationService implements IntegrationService {\n  private withPrompts = false;\n\n  constructor() {\n    this.shouldHandlePrompts()\n      .then(result => {\n        this.withPrompts = result;\n      });\n\n    // listen for the portmaster:show event that is emitted\n    // when tauri want's to tell us that we should make our\n    // window visible.\n    listen(\"portmaster:show\", () => {\n      this.openApp();\n    })\n  }\n\n  writeToClipboard(text: string): Promise<void> {\n    return writeText(text);\n  }\n\n  openExternal(pathOrUrl: string): Promise<void> {\n    return open(pathOrUrl);\n  }\n\n  getInstallDir(): Promise<string> {\n    return Promise.reject(\"not yet supported in tauri\")\n  }\n\n  getAppInfo(info: ProcessInfo): Promise<AppInfo> {\n    return asyncInvoke(\"get_app_info\", {\n      ...info,\n    })\n  }\n\n  getAppIcon(info: ProcessInfo): Promise<string> {\n    return this.getAppInfo(info)\n      .then(info => info.icon_dataurl)\n  }\n\n  exitApp(): Promise<void> {\n    // we have two options here:\n    //  - close(): close the native tauri window and release all resources of it.\n    //             this has the disadvantage that if the user re-opens the window,\n    //             it will take slightly longer because angular need to re-bootstrap\n    //             the application.\n    //\n    //             IMPORTANT: the angular application will automatically launch prompt\n    //             windows via the tauri window interface. If we would call close(),\n    //             those prompts wouldn't work anymore because the angular app would not\n    //             be running in the background.\n    //\n    //  - hide(): just set the window visibility to false. The advantage is that angular\n    //            is still running and interacting with portmaster but it also means that\n    //            we waste some system resources due to tauri window objects and the angular\n    //            application.\n\n    getCurrentWindow().hide()\n\n    return Promise.resolve();\n  }\n\n  // Tauri specific functions that are not defined in the IntegrationService interface.\n  // to use those methods you must check if integration instanceof TauriIntegrationService.\n\n  async shouldShow(): Promise<boolean> {\n    try {\n      const response = await invoke<string>(\"should_show\");\n      return response === \"show\";\n    } catch (err) {\n      console.error(err);\n      return true;\n    }\n  }\n\n  async shouldHandlePrompts(): Promise<boolean> {\n    try {\n      const response = await invoke<string>(\"should_handle_prompts\")\n      return response === \"true\"\n    } catch (err) {\n      console.error(err);\n      return false;\n    }\n  }\n\n  get_state(_: string): Promise<string> {\n    return invoke<string>(\"get_state\");\n  }\n\n  set_state(key: string, value: string): Promise<void> {\n    return invoke<void>(\"set_state\", {\n      key,\n      value\n    })\n  }\n\n  getServiceManagerStatus(): Promise<ServiceManagerStatus> {\n    return asyncInvoke(\"get_service_manager_status\", {})\n  }\n\n  startService(): Promise<any> {\n    return asyncInvoke(\"start_service\", {});\n  }\n\n  onExitRequest(cb: () => void): () => void {\n    let unlisten: () => void = () => undefined;\n\n    listen('exit-requested', () => {\n      cb();\n    }).then(cleanup => {\n      unlisten = cleanup;\n    })\n\n    return () => {\n      unlisten();\n    }\n  }\n\n  openApp() {\n    Window.getByLabel(\"splash\").then(splash => { splash?.close();});\n    const current = Window.getCurrent()\n\n    current.isVisible()\n      .then(visible => {\n        if (!visible) {\n          current.show();\n          current.setFocus();\n        }\n      });\n  }\n\n  closePrompt() {\n    Window.getByLabel(\"prompt\").then(window => { window?.close();});\n  }\n\n  openPrompt() {\n    if (!this.withPrompts) {\n      return;\n    }\n\n    Window.getByLabel(\"prompt\").then(prompt => { \n      if (prompt) {\n        return;\n      }\n\n      const promptWindow = new Window(\"prompt\", {\n        alwaysOnTop: true,\n        decorations: false,\n        minimizable: false,\n        maximizable: false,\n        resizable: false,\n        title: 'Portmaster Prompt',\n        visible: false, // the prompt marks it self as visible.\n        skipTaskbar: true,\n        closable: false,\n        center: true,\n        width: 600,\n        height: 300,\n\n        // in src/main.ts we check the current location path\n        // and if it matches /prompt, we bootstrap the PromptEntryPointComponent\n        // instead of the AppComponent.\n        url: `http://${window.location.host}/prompt`,\n      } as any)\n\n      promptWindow.once(\"tauri://error\", (err) => {\n        console.error(err);\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/intro/index.ts",
    "content": "export * from './intro.module';\n"
  },
  {
    "path": "desktop/angular/src/app/intro/intro.module.ts",
    "content": "import { OverlayModule } from \"@angular/cdk/overlay\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { FormsModule } from \"@angular/forms\";\nimport { SfngDropDownModule, SfngTipUpModule, StepperConfig } from \"@safing/ui\";\nimport { ConfigModule } from \"../shared/config\";\nimport { Step1WelcomeComponent } from \"./step-1-welcome\";\nimport { Step2TrackersComponent } from \"./step-2-trackers\";\nimport { Step3DNSComponent } from \"./step-3-dns\";\nimport { Step4TipupsComponent } from \"./step-4-tipups\";\n\nconst steps = [\n  Step1WelcomeComponent,\n  Step2TrackersComponent,\n  Step3DNSComponent,\n  Step4TipupsComponent,\n]\n\n@NgModule({\n  imports: [\n    CommonModule,\n    OverlayModule,\n    FormsModule,\n    SfngDropDownModule,\n    ConfigModule,\n    SfngTipUpModule,\n  ],\n  declarations: steps\n})\nexport class IntroModule {\n  static Stepper: StepperConfig = {\n    steps: steps,\n    canAbort: (idx) => idx === 0,\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-1-welcome/index.ts",
    "content": "export * from './step-1-welcome';\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-1-welcome/step-1-welcome.html",
    "content": "<h1>Portmaster Protects Your Privacy</h1>\n\n<p>\n  Portmaster enhances your privacy with powerful defaults - no configuration needed! Of course you can customize\n  everything to your specific needs.\n</p>\n\n<!-- This card does not use the default button template -->\n<ng-template #buttonTemplate>\n  <button class=\"self-center w-56 py-2 mb-6 rounded-full bg-blue hover:bg-blue hover:bg-opacity-75\"\n    (click)=\"stepRef.next()\">\n    Quick Setup\n  </button>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-1-welcome/step-1-welcome.ts",
    "content": "import { ChangeDetectionStrategy, Component, Inject, TemplateRef, ViewChild } from \"@angular/core\";\nimport { Step, StepRef, STEP_REF } from \"@safing/ui\";\nimport { of } from \"rxjs\";\n\n@Component({\n  templateUrl: './step-1-welcome.html',\n  styleUrls: ['../step.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Step1WelcomeComponent implements Step {\n  validChange = of(true)\n\n  readonly nextButtonLabel = 'Quick Setup';\n\n  @ViewChild('buttonTemplate', { static: true })\n  buttonTemplate!: TemplateRef<any>;\n\n  constructor(\n    @Inject(STEP_REF) public stepRef: StepRef<void>,\n  ) { }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-2-trackers/index.ts",
    "content": "export * from './step-2-trackers'\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-2-trackers/step-2-trackers.html",
    "content": "<h1>Trackers Are Blocked System-Wide</h1>\n\n<p>Portmaster automatically blocks ads, trackers and malware hosts on your whole device. Portmaster knows what to block\n  through trusted domain lists, which are also used by Ad-Blockers in browsers, etc. You can always customize this in\n  the settings.</p>\n\n<sfng-dropdown label=\"Customize\" class=\"w-full\" maxHeight=\"300px\" maxWidth=\"600px\" offsetY=\"0\">\n  <app-generic-setting class=\"h-full\" [setting]=\"setting\" [attr.id]=\"setting?.Key\" (save)=\"saveSetting($event)\"\n    enableActiveBorder=\"false\" showHeader=\"false\">\n  </app-generic-setting>\n</sfng-dropdown>\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-2-trackers/step-2-trackers.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, ElementRef, OnInit, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { ConfigService, Setting } from \"@safing/portmaster-api\";\nimport { Step } from \"@safing/ui\";\nimport { of } from \"rxjs\";\nimport { mergeMap } from \"rxjs/operators\";\nimport { SaveSettingEvent } from \"src/app/shared/config/generic-setting\";\n\n@Component({\n  templateUrl: './step-2-trackers.html',\n  styleUrls: ['../step.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Step2TrackersComponent implements Step, OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  validChange = of(true)\n\n  setting: Setting | null = null;\n\n  constructor(\n    public configService: ConfigService,\n    public readonly elementRef: ElementRef,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  ngOnInit(): void {\n    this.configService.get('filter/lists')\n      .pipe(\n        mergeMap(setting => {\n          this.setting = setting;\n\n          return this.configService.watch(setting.Key)\n        }),\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(value => {\n        this.setting!.Value = value;\n\n        this.cdr.markForCheck();\n      });\n  }\n\n  saveSetting(event: SaveSettingEvent) {\n    this.configService.save(event.key, event.value)\n      .subscribe()\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-3-dns/index.ts",
    "content": "export * from './step-3-dns'\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-3-dns/step-3-dns.html",
    "content": "<h1>Secure DNS for All Connections</h1>\n\n<p>Portmaster automatically encrypts all your DNS queries to safeguard them from prying eyes. Portmaster sets a default\n  provider, but you can always switch to a custom DNS-over-TLS provider in the global settings.</p>\n\n<sfng-dropdown label=\"Customize\" class=\"w-full\" maxHeight=\"300px\" maxWidth=\"600px\" offsetY=\"0\">\n  <div class=\"flex flex-wrap items-center justify-center w-full gap-6 px-8 py-8\">\n    <button *ngFor=\"let button of quickSettings\" [style.minWidth]=\"'6rem'\" (click)=\"applyQuickSetting(button)\"\n      [disabled]=\"isCustomValue\" [class.bg-blue]=\"button.active\" class=\"px-4 py-3\">\n      {{ button.Name }}\n    </button>\n\n    <button class=\"w-24 px-4 py-3 bg-blue\" *ngIf=\"isCustomValue\">\n      Custom\n    </button>\n  </div>\n</sfng-dropdown>\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-3-dns/step-3-dns.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, ElementRef, OnInit, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { ConfigService, QuickSetting, Setting, applyQuickSetting } from \"@safing/portmaster-api\";\nimport { Step } from \"@safing/ui\";\nimport { of } from \"rxjs\";\nimport { mergeMap } from \"rxjs/operators\";\nimport { SaveSettingEvent } from \"src/app/shared/config/generic-setting\";\n\ninterface QuickSettingModel extends QuickSetting<any> {\n  active: boolean;\n}\n\n@Component({\n  templateUrl: './step-3-dns.html',\n  styleUrls: ['../step.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Step3DNSComponent implements Step, OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  validChange = of(true)\n\n  setting: Setting | null = null;\n  quickSettings: QuickSettingModel[] = [];\n  isCustomValue = false;\n\n  constructor(\n    public configService: ConfigService,\n    public readonly elementRef: ElementRef,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  private getQuickSettings(): QuickSettingModel[] {\n    if (!this.setting) {\n      return [];\n    }\n\n    let val = this.setting.Annotations[\"safing/portbase:ui:quick-setting\"];\n    if (val === undefined) {\n      return [];\n    }\n\n    if (!Array.isArray(val)) {\n      return [{\n        ...val,\n        active: false,\n      }]\n    }\n\n    return val.map(v => ({\n      ...v,\n      active: false,\n    }))\n  }\n\n  ngOnInit(): void {\n    this.configService.get('dns/nameservers')\n      .pipe(\n        mergeMap(setting => {\n          this.setting = setting;\n          this.quickSettings = this.getQuickSettings();\n          return this.configService.watch(setting.Key)\n        }),\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(value => {\n        this.setting!.Value = value;\n\n        let hasActive = false;\n        this.isCustomValue = false;\n\n        this.quickSettings.forEach(setting => {\n          if (this.setting?.Value !== undefined && JSON.stringify(this.setting.Value) === JSON.stringify(setting.Value)) {\n            setting.active = true;\n            hasActive = true;\n          } else {\n            setting.active = false;\n          }\n        });\n\n        if (!hasActive) {\n          if (this.setting?.Value !== undefined && JSON.stringify(this.setting!.Value) !== JSON.stringify(this.setting!.DefaultValue)) {\n            this.isCustomValue = true;\n          } else if (this.quickSettings.length > 0) {\n            this.quickSettings[0].active = true;\n          }\n        }\n\n        this.cdr.markForCheck();\n      });\n  }\n\n  saveSetting(event: SaveSettingEvent) {\n    this.configService.save(event.key, event.value)\n      .subscribe()\n  }\n\n  applyQuickSetting(action: QuickSetting<any>) {\n    const newValue = applyQuickSetting(\n      this.setting!.Value || this.setting!.DefaultValue,\n      action,\n    )\n    this.configService.save(this.setting!.Key, newValue)\n      .subscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-4-tipups/index.ts",
    "content": "export * from './step-4-tipups'\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-4-tipups/step-4-tipups.html",
    "content": "<h1>Learn More as You Explore</h1>\n\n<p>Portmaster has a lot more to offer. When you decide to dive deeper you can always click on an information icon to\n  learn more about a certain feature. Look out for those!</p>\n\n<div class=\"flex flex-col items-center justify-center gap-1 p-8 text-xxs\">\n  <span class=\"text-tertiary\">Click Me!</span>\n  <div class=\"flex items-center justify-center px-4 py-4 bg-gray-400 rounded\">\n    <sfng-tipup class=\"transform scale-125\" key=\"introTipup\"></sfng-tipup>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step-4-tipups/step-4-tipups.ts",
    "content": "import { ChangeDetectionStrategy, Component } from \"@angular/core\";\nimport { Step } from \"@safing/ui\";\nimport { of } from \"rxjs\";\n\n@Component({\n  templateUrl: './step-4-tipups.html',\n  styleUrls: ['../step.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Step4TipupsComponent implements Step {\n  validChange = of(true)\n}\n"
  },
  {
    "path": "desktop/angular/src/app/intro/step.scss",
    "content": ":host {\n  @apply flex flex-col items-center justify-center;\n}\n\nh1 {\n  @apply text-primary text-2xl font-medium capitalize text-center py-5;\n}\n\np {\n  @apply text-tertiary text-sm font-medium text-center;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/layout/navigation/navigation.html",
    "content": "<div class=\"flex flex-col items-center gap-1\">\n  <div class=\"relative w-16 h-16\">\n\n    <app-security-lock [@fadeIn] [@fadeOut] mode=\"small\" class=\"absolute w-16 h-16\" routerLink=\"dashboard\"\n      *ngIf=\"sideDashStatus === 'collapsed'\">\n    </app-security-lock>\n\n    <div class=\"absolute flex flex-col items-center justify-center w-16 h-16 outline-none\" routerLink=\"dashboard\"\n      [@fadeIn] [@fadeOut] *ngIf=\"sideDashStatus === 'expanded'\">\n      <div class=\"relative\">\n\n        <svg [class.connected]=\"(connected$ | async)\" data-name=\"Layer 1\" viewBox=\"0 0 128 128\"\n          class=\"spin reverse logo-image\">\n          <g data-name=\"Main\" fill-rule=\"evenodd\">\n            <path shape-rendering=\"geometricPrecision\" fill=\"#fff\" class=\"inner\"\n              d=\"M176.11 36.73l-5-8.61a41.53 41.53 0 00-14.73 57.22l8.55-5.12a31.58 31.58 0 0111.19-43.49z\"\n              transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n            <path shape-rendering=\"geometricPrecision\" fill=\"#fff\" class=\"inner\"\n              d=\"M222.36 72.63a31.55 31.55 0 01-45 19.35l-4.62 8.84a41.54 41.54 0 0059.17-25.46z\"\n              transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n          </g>\n        </svg>\n        <svg [class.connected]=\"(connected$ | async)\" data-name=\"Layer 1\" viewBox=\"0 0 128 128\" class=\"spin logo-image\">\n          <g data-name=\"Main\" fill-rule=\"evenodd\">\n            <path shape-rendering=\"geometricPrecision\" fill=\"#fff\" class=\"inner reverse\"\n              d=\"M197 83a19.66 19.66 0 01-19.25-32.57l-4.5-4.27A25.87 25.87 0 00198.59 89z\"\n              transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".6\"></path>\n          </g>\n        </svg>\n        <svg [class.connected]=\"(connected$ | async)\" data-name=\"Layer 1\" viewBox=\"0 0 128 128\" class=\"logo-image\">\n          <g data-name=\"Main\" fill-rule=\"evenodd\">\n            <path shape-rendering=\"geometricPrecision\" fill=\"#fff\"\n              d=\"M192 112.64A48.64 48.64 0 11240.64 64 48.64 48.64 0 01192 112.64zM256 64a64 64 0 10-64 64 64 64 0 0064-64z\"\n              transform=\"translate(-127.99 .1)\"></path>\n          </g>\n        </svg>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"flex justify-center\">\n    <sfng-tipup key=\"intro\"></sfng-tipup>\n  </div>\n\n  <div class=\"nav-list\">\n    <div class=\"relative link\" (click)=\"toggleSideDash($event)\">\n      <svg [class.-rotate-180]=\"sideDashStatus === 'expanded'\" [class.bg-gray-400]=\"sideDashStatus === 'collapsed'\"\n        xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n        class=\"w-5 h-5 transition-all duration-200 rounded\">\n        <path fill-rule=\"evenodd\"\n          d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n    </div>\n  </div>\n\n  <div class=\"pt-1 border-t border-gray-400 nav-list\">\n    <!-- The notification drop-down -->\n    <div sfngTipUpTrigger=\"navNotifications\" sfngTipUpPassive class=\"relative mt-3\" (click)=\"toggleSideDash($event)\"\n      *ngIf=\"sideDashStatus !== 'expanded'\">\n\n      <svg class=\"w-4 h-4 {{ hasNewNotifications ? notificationColor : 'text-tertiary' }}\" xmlns=\"http://www.w3.org/2000/svg\"\n        fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n        <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n          d=\"M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9\" />\n      </svg>\n    </div>\n\n    <!-- The prompt list drop-down -->\n    <div class=\"relative link\" cdkOverlayOrigin #promptOrigin=\"cdkOverlayOrigin\"\n      *ngIf=\"hasNewPrompts || globalPromptingEnabled\" (click)=\"promptDropDown.toggle(promptOrigin)\"\n      [class.active]=\"promptDropDown.isOpen\">\n\n      <span *ngIf=\"hasNewPrompts\" class=\"absolute w-1.5 h-1.5 bg-yellow-300 rounded-full top-1.5 right-1.5\"></span>\n\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"\n        stroke-width=\"2\">\n        <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n          d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n      </svg>\n    </div>\n    <sfng-dropdown [positions]=\"dropDownPositions\" externalTrigger=\"true\" #promptDropDown offsetY=\"0\" offsetX=\"10\"\n      overlayClass=\"rounded-t\">\n      <app-prompt-list></app-prompt-list>\n    </sfng-dropdown>\n  </div>\n</div>\n\n\n<div class=\"nav-list\">\n  <!-- Network Activity -->\n  <div sfng-tooltip=\"Network Activity\" sfngTooltipDelay=\"1000\" snfgTooltipPosition=\"right\" routerLinkActive=\"active\"\n    routerLink=\"monitor\" class=\"link\" sfngTipUpTrigger=\"navMonitor\" sfngTipUpPassive>\n    <svg viewBox=\"0 0 24 24\" class=\"monitor\">\n      <g fill=\"none\">\n        <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n          d=\"M8.464 8.464c-1.953 1.953-1.953 5.118 0 7.071 1.953 1.953 5.118 1.953 7.071 0 1.953-1.953 1.953-5.119 0-7.071C14.559 7.488 13.28 7 12 7\" />\n        <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n          d=\"M5.636 5.636c-3.515 3.515-3.515 9.213 0 12.728 3.515 3.515 9.213 3.515 12.728 0 3.515-3.515 3.515-9.213 0-12.728-2.627-2.627-6.474-3.289-9.717-1.989M5.64 5.64L12 12\" />\n      </g>\n    </svg>\n  </div>\n\n  <!-- App View -->\n  <div sfng-tooltip=\"Apps and Profiles\" sfngTooltipDelay=\"1000\" snfgTooltipPosition=\"right\" routerLinkActive=\"active\"\n    routerLink=\"app\" class=\"link\" sfngTipUpTrigger=\"navApps\" sfngTipUpPassive>\n    <svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"Layer 1\" viewBox=\"0 0 24 24\" class=\"app\" fill=\"none\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" fill=\"currentColor\"\n        d=\"M19 21h-3a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2Z\" />\n      <path fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n        d=\"M19 9h-3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2ZM5 3h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2ZM5 15h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2Z\" />\n    </svg>\n  </div>\n\n  <!-- SPN -->\n  <div sfng-tooltip=\"Safing Privacy Network\" sfngTooltipDelay=\"1000\" snfgTooltipPosition=\"right\"\n    routerLinkActive=\"active\" routerLink=\"spn\" class=\"link\" sfngTipUpTrigger=\"navMap\" sfngTipUpPassive>\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" class=\"spn\" stroke=\"currentColor\">\n      <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\n        <path\n          d=\"M6.488 15.581c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0M13.415 3.586c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.049-.781 2.83 0M20.343 15.58c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0\" />\n        <path\n          d=\"M17.721 18.581C16.269 20.071 14.246 21 12 21c-1.146 0-2.231-.246-3.215-.68M4.293 15.152c-.56-1.999-.352-4.21.769-6.151.574-.995 1.334-1.814 2.205-2.449M13.975 5.254c2.017.512 3.834 1.799 4.957 3.743.569.985.899 2.041 1.018 3.103\" />\n      </g>\n    </svg>\n  </div>\n\n  <!-- Global Settings -->\n  <div sfng-tooltip=\"Global Settings\" sfngTooltipDelay=\"1000\" snfgTooltipPosition=\"right\" routerLinkActive=\"active\"\n    routerLink=\"settings\" class=\"link\" sfngTipUpTrigger=\"navSettings\" sfngTipUpPassive>\n    <svg viewBox=\"0 0 24 24\" class=\"settings\">\n      <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\n        <path shape-rendering=\"geometricPrecision\"\n          d=\"M13.7678 10.2322c.976311.976311.976311 2.55922 0 3.53553-.976311.976311-2.55922.976311-3.53553 0-.976311-.976311-.976311-2.55922 0-3.53553.976311-.976311 2.55922-.976311 3.53553 0\" />\n        <path shape-rendering=\"geometricPrecision\"\n          d=\"M14.849 4.12l.583.194c.534.178.895.678.895 1.241v.837c0 .712.568 1.293 1.28 1.308l.838.018c.485.01.925.289 1.142.723l.275.55c.252.504.153 1.112-.245 1.51l-.592.592c-.503.503-.512 1.316-.02 1.83l.58.606c.336.351.45.858.296 1.319l-.194.583c-.178.534-.678.895-1.241.895h-.837c-.712 0-1.293.568-1.308 1.28l-.018.838c-.01.485-.289.925-.723 1.142l-.55.275c-.504.252-1.112.153-1.51-.245l-.592-.592c-.503-.503-1.316-.512-1.83-.02l-.606.58c-.351.336-.858.45-1.319.296l-.583-.194c-.534-.178-.895-.678-.895-1.241v-.837c0-.712-.568-1.293-1.28-1.308l-.838-.018c-.485-.01-.925-.289-1.142-.723l-.275-.55c-.252-.504-.153-1.112.245-1.51l.592-.592c.503-.503.512-1.316.02-1.83l-.58-.606c-.337-.352-.451-.86-.297-1.32l.194-.583c.178-.534.678-.895 1.241-.895h.837c.712 0 1.293-.568 1.308-1.28l.018-.838c.012-.485.29-.925.724-1.142l.55-.275c.504-.252 1.112-.153 1.51.245l.592.592c.503.503 1.316.512 1.83.02l.606-.58c.351-.335.859-.449 1.319-.295z\" />\n      </g>\n    </svg>\n  </div>\n\n  <div class=\"w-full border-t border-gray-400\"></div>\n\n  <div sfng-tooltip=\"Get Help\" sfngTooltipDelay=\"1000\" snfgTooltipPosition=\"right\" routerLink=\"support\"\n    routerLinkActive=\"active\" class=\"link\" sfngTipUpTrigger=\"navSupport\" sfngTipUpPassive>\n    <svg viewBox=\"0 0 24 24\" class=\"help\">\n      <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\n        <path shape-rendering=\"geometricPrecision\"\n          d=\"M12 21v0c-4.971 0-9-4.029-9-9v0c0-4.971 4.029-9 9-9v0c4.971 0 9 4.029 9 9v0c0 4.971-4.029 9-9 9z\" />\n        <path shape-rendering=\"geometricPrecision\"\n          d=\"M12 13.25V13c0-.817.505-1.26 1.011-1.6.494-.333.989-.767.989-1.567 0-1.105-.895-2-2-2s-2 .895-2 2M11.999 16c-.138 0-.25.112-.249.25 0 .138.112.25.25.25s.25-.112.25-.25-.112-.25-.251-.25\" />\n      </g>\n    </svg>\n  </div>\n</div>\n<div class=\"nav-lower-list\">\n  <div class=\"relative link\" sfngTipUpTrigger=\"navTools\" sfngTipUpPassive sfng-tooltip=\"Version and Tools\"\n    sfngTooltipDelay=\"1000\" snfgTooltipPosition=\"right\" (click)=\"settingsMenu.dropdown.toggle(settingsMenuTrigger)\"\n    cdkOverlayOrigin #settingsMenuTrigger=\"cdkOverlayOrigin\" [class.active]=\"settingsMenu.dropdown.isOpen\">\n\n    <span *ngIf=\"versions?.Channel !== 'stable'\"\n      class=\"absolute w-1.5 h-1.5 bg-yellow-300 rounded-full top-1.5 right-1.5\"></span>\n\n    <svg version=\"1.1\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" class=\"help\"\n      xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <g stroke-linecap=\"round\" stroke-width=\"1.5\" stroke=\"currentColor\" fill=\"none\" stroke-linejoin=\"round\">\n        <path d=\"M11.835,15l5,5c0.828,0.828 2.172,0.828 3,0v0c0.828,-0.828 0.828,-2.172 0,-3l-5,-5\"></path>\n        <path\n          d=\"M20.916,5.847c0.024,0.023 0.042,0.053 0.051,0.085c0.47,1.567 0.106,3.33 -1.132,4.568c-1.251,1.251 -3.038,1.609 -4.617,1.117l-8.347,8.347c-0.813,0.813 -2.139,0.874 -2.98,0.09c-0.884,-0.823 -0.902,-2.207 -0.056,-3.054l8.383,-8.383c-0.492,-1.579 -0.134,-3.366 1.117,-4.617c1.238,-1.238 3.001,-1.602 4.568,-1.132c0.032,0.01 0.062,0.027 0.085,0.051l0.162,0.162c0.078,0.078 0.078,0.205 0,0.283l-2.635,2.636l2.32,2.32l2.636,-2.636c0.078,-0.078 0.205,-0.078 0.283,0l0.162,0.163Z\">\n        </path>\n        <path\n          d=\"M2.933,4.293l0.674,2.023c0.136,0.409 0.518,0.684 0.949,0.684h2.279v-2.279c0,-0.43 -0.275,-0.813 -0.684,-0.949l-2.023,-0.674c-0.18,-0.06 -0.378,-0.013 -0.512,0.121l-0.562,0.562c-0.134,0.134 -0.181,0.332 -0.121,0.512Z\">\n        </path>\n        <path d=\"M6.84,7l3.5,3.5\"></path>\n      </g>\n    </svg>\n\n  </div>\n  <app-menu #settingsMenu offsetY=\"0\" offsetX=\"10\" overlayClass=\"rounded-t\">\n    <div class=\"flex flex-col p-4 text-xxs\">\n      <span class=\"text-secondary\">\n        Version: <span class=\"text-primary\">{{ versions?.Core?.Version }} </span>\n      </span>\n      <span class=\"text-secondary\">\n        Release Channel:\n        <span class=\"uppercase text-primary\"\n          [class.text-yellow-300]=\"versions?.Channel !== 'stable'\">{{ versions?.Channel }}</span>\n      </span>\n    </div>\n\n    <app-menu-item (click)=\"downloadUpdates($event)\">Check for Updates</app-menu-item>\n    <app-menu-item (click)=\"openChangeLog()\">View Changelog</app-menu-item>\n    <app-menu-item (click)=\"reloadUI($event)\">Reload UI</app-menu-item>\n    <app-menu-item *appExpertiseLevel=\"'developer'\" (click)=\"showIntro()\">\n      Show Intro Screen\n    </app-menu-item>\n    <app-menu-item (click)=\"reinitSPN($event)\">Re-Initialize SPN</app-menu-item>\n    <app-menu-item (click)=\"logoutCompletely($event)\">Logout Completely</app-menu-item>\n    <app-menu-item (click)=\"resetBroadcastState()\">Reset Notifications State</app-menu-item>\n    <app-menu-item (click)=\"clearDNSCache($event)\">Clear DNS Cache</app-menu-item>\n    <app-menu-item (click)=\"openDataDir($event)\">Open Data Directory</app-menu-item>\n    <app-menu-item (click)=\"copyDebugInfo($event)\">Copy Debug Info</app-menu-item>\n    <app-menu-item (click)=\"cleanupHistory($event)\">Cleanup Network History</app-menu-item>\n  </app-menu>\n\n  <!-- Pause Menu -->\n  <div sfngTipUpTrigger=\"navPause\" sfngTipUpPassive sfng-tooltip=\"Pause and Resume\" sfngTooltipDelay=\"1000\"\n    snfgTooltipPosition=\"right\" class=\"link\" (click)=\"pauseMenu.dropdown.toggle(pauseMenuTrigger)\" cdkOverlayOrigin\n    #pauseMenuTrigger=\"cdkOverlayOrigin\" [class.active]=\"pauseMenu.dropdown.isOpen\">\n\n    <svg viewBox=\"0 0 24 24\" class=\"help\" xmlns=\"http://www.w3.org/2000/svg\">\n      <g fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> \n        <path d=\"M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z\"></path> \n        <path d=\"M14 9L14 15\"></path> \n        <path d=\"M10 9L10 15\"></path> \n      </g>\n    </svg>\n\n  </div>\n  <app-menu #pauseMenu offsetY=\"0\" offsetX=\"10\" overlayClass=\"rounded-t\">\n      <div *ngIf=\"isPaused\">\n        <div class=\"flex flex-col p-4 text-xxs\">            \n          <span class=\"text-secondary\">\n            <span class=\"text-secondary\">{{ pauseInfo }} </span>\n          </span>\n          <span class=\"text-secondary\" *ngIf=\"pauseInfoTillTime\">\n            {{ pauseInfoTillTime }}\n          </span>            \n        </div>\n        <hr/>\n      </div>\n\n      <!-- we show 'Pause SPN...' items even when isPausedSPN to allow pause time modification-->\n      <app-menu-item (click)=\"pauseSPN($event, 60*5)\" *ngIf=\"spnEnabled || isPausedSPN\" [disabled]=\"isPausedInterception\">Pause SPN for 5 minutes</app-menu-item>\n      <app-menu-item (click)=\"pauseSPN($event, 60*15)\" *ngIf=\"spnEnabled || isPausedSPN\" [disabled]=\"isPausedInterception\">Pause SPN for 15 minutes</app-menu-item>\n      <app-menu-item (click)=\"pauseSPN($event, 60*60)\" *ngIf=\"spnEnabled || isPausedSPN\" [disabled]=\"isPausedInterception\">Pause SPN for 1 hour</app-menu-item>\n      <hr/>\n      <app-menu-item (click)=\"pause($event, 60*5)\">Pause for 5 minutes</app-menu-item>\n      <app-menu-item (click)=\"pause($event, 60*15)\">Pause for 15 minutes</app-menu-item>\n      <app-menu-item (click)=\"pause($event, 60*60)\">Pause for 1 hour</app-menu-item>\n      <hr/>\n      <app-menu-item (click)=\"resume($event)\" [disabled]=\"!isPaused\">Resume now</app-menu-item>\n  </app-menu>\n\n  <!-- Power Menu -->\n  <div sfngTipUpTrigger=\"navPower\" sfngTipUpPassive sfng-tooltip=\"Shutdown and Restart\" sfngTooltipDelay=\"1000\"\n    snfgTooltipPosition=\"right\" class=\"link\" (click)=\"powerMenu.dropdown.toggle(powerMenuTrigger)\" cdkOverlayOrigin\n    #powerMenuTrigger=\"cdkOverlayOrigin\" [class.active]=\"powerMenu.dropdown.isOpen\">\n\n    <svg version=\"1.1\" viewBox=\"0 0 24 24\" class=\"help\" xmlns=\"http://www.w3.org/2000/svg\"\n      xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n      <g fill=\"none\">\n        <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\"\n          d=\"M18.364,5.63604c3.51472,3.51472 3.51472,9.2132 0,12.7279c-3.51472,3.51472 -9.2132,3.51472 -12.7279,0c-3.51472,-3.51472 -3.51472,-9.2132 -1.77636e-15,-12.7279c3.51472,-3.51472 9.2132,-3.51472 12.7279,-1.77636e-15\">\n        </path>\n        <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M12,7v5\">\n        </path>\n        <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\"\n          d=\"M15.534,8.466c1.952,1.952 1.952,5.117 0,7.069c-1.952,1.952 -5.117,1.952 -7.069,0c-1.952,-1.952 -1.952,-5.117 0,-7.069\">\n        </path>\n      </g>\n    </svg>\n\n  </div>\n  <app-menu #powerMenu offsetY=\"0\" offsetX=\"10\" overlayClass=\"rounded-t\">\n    <app-menu-item (click)=\"shutdown($event)\">Shutdown</app-menu-item>\n    <app-menu-item (click)=\"restart($event)\">Restart</app-menu-item>\n  </app-menu>\n\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/layout/navigation/navigation.scss",
    "content": ":host {\n  height: 100vh;\n  top: 0px;\n  position: sticky;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: center;\n  user-select: none;\n\n  .logo-image {\n    @apply w-6 -top-3 -left-3 absolute;\n    position: absolute;\n  }\n\n  svg {\n    &:not(.connected) {\n      animation-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);\n\n      path.inner {\n        fill: theme('colors.info.red');\n      }\n    }\n  }\n\n  div.nav-list {\n    display: flex;\n    flex-direction: column;\n    justify-content: flex-start;\n    align-items: center;\n  }\n\n  div.nav-lower-list {\n    display: flex;\n    flex-direction: column;\n    justify-content: flex-start;\n    align-items: center;\n    padding-bottom: 1.5rem;\n  }\n\n  div.link {\n    @apply my-2;\n\n    width: 2rem;\n    height: 2rem;\n    border-radius: 10px;\n\n    display: flex;\n    justify-content: space-around;\n    align-items: center;\n\n    cursor: pointer;\n\n    & {\n      outline: none;\n\n      svg,\n      fa-icon {\n        opacity: .5;\n      }\n    }\n\n    &:target,\n    &.active {\n      background-color: #2c2c2c;\n\n      svg,\n      fa-icon {\n        opacity: 1;\n        transform: scale(1.08);\n      }\n    }\n\n    &:hover {\n\n      svg,\n      fa-icon {\n        opacity: 1;\n      }\n    }\n\n    svg,\n    fa-icon {\n\n      &.dash,\n      &.spn,\n      &.monitor,\n      &.app,\n      &.help,\n      &.settings {\n        @apply text-white;\n        width: 1.1rem;\n        position: relative;\n        stroke: currentColor;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/layout/navigation/navigation.ts",
    "content": "import { INTEGRATION_SERVICE, IntegrationService } from 'src/app/integration';\nimport { ConnectedPosition } from '@angular/cdk/overlay';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, OnInit, Output, inject } from '@angular/core';\nimport { ConfigService, DebugAPI, PortapiService, SPNService, StringSetting, BoolSetting } from '@safing/portmaster-api';\nimport { tap } from 'rxjs/operators';\nimport { AppComponent } from 'src/app/app.component';\nimport { NotificationType, NotificationsService, StatusService, VersionStatus, GetModuleState, ControlPauseStateData } from 'src/app/services';\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\nimport { fadeInAnimation, fadeOutAnimation } from 'src/app/shared/animations';\nimport { ExitService } from 'src/app/shared/exit-screen';\nimport { TauriIntegrationService } from 'src/app/integration/taur-app';\n\n@Component({\n  selector: 'app-navigation',\n  templateUrl: './navigation.html',\n  styleUrls: ['./navigation.scss'],\n  exportAs: 'navigation',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation,\n  ]\n})\nexport class NavigationComponent implements OnInit {\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  /** Emits the current portapi connection state on changes. */\n  readonly connected$ = this.portapi.connected$;\n\n  /** @private The available and selected resource versions. */\n  versions: VersionStatus | null = null;\n\n  /** Whether or not we have new, unseen notifications */\n  hasNewNotifications = false;\n\n  /** The color to use for the notifcation-available hint (dot) */\n  notificationColor: string = 'text-green-300';\n\n  pauseState: ControlPauseStateData | null = null;\n  get isPaused(): boolean { return this.pauseState?.Interception===true || this.pauseState?.SPN===true; }\n  get isPausedInterception(): boolean { return this.pauseState?.Interception===true; }\n  get isPausedSPN(): boolean { return this.pauseState?.SPN===true; }\n  get pauseInfo(): string {\n    if (this.pauseState?.Interception===true && this.pauseState?.SPN===true) \n      return 'Portmaster and SPN are paused';\n    else if (this.pauseState?.Interception===true)\n      return 'Portmaster is paused';\n    else if (this.pauseState?.SPN===true)\n      return 'SPN is paused';\n    return '';\n  }\n  get pauseInfoTillTime(): string {\n    if (this.isPaused && this.pauseState?.TillTime) {\n      const date = new Date(this.pauseState.TillTime);\n      if (isNaN(date.getTime()) || date.getTime() < Date.now())\n        return '';    \n      return `Auto-resume at ${date.toLocaleTimeString(undefined, { hour12: false })}`;\n    }\n    return '';\n  }\n\n  /** Whether or not we have new, unseen prompts */\n  hasNewPrompts = false;\n\n  /** Whether or not prompting is globally enabled. */\n  globalPromptingEnabled = false;\n\n  /** Whether or not the SPN is currently enabled */\n  spnEnabled = false;\n\n  @Output()\n  sideDashChange = new EventEmitter<'collapsed' | 'expanded' | 'force-overlay'>();\n\n  /** Whether or not the side dash should be expanded or collapsed */\n  sideDashStatus: 'collapsed' | 'expanded' = 'expanded';\n\n  constructor(\n    private portapi: PortapiService,\n    private exitService: ExitService,\n    private statusService: StatusService,\n    private configService: ConfigService,\n    private appComponent: AppComponent,\n    private debugAPI: DebugAPI,\n    private actionIndicator: ActionIndicatorService,\n    private notificationService: NotificationsService,\n    private spnService: SPNService,\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  dropDownPositions: ConnectedPosition[] = [\n    {\n      originX: 'end',\n      originY: 'top',\n      overlayX: 'start',\n      overlayY: 'top'\n    }\n  ]\n\n  ngOnInit() {\n    const mql = window.matchMedia('(max-width: 1200px)');\n\n    if (mql.matches) {\n      this.sideDashStatus = 'collapsed';\n      this.sideDashChange.next(this.sideDashStatus);\n    }\n\n    mql.addEventListener('change', () => {\n      if (mql.matches) {\n        this.sideDashStatus = 'collapsed';\n      } else {\n        this.sideDashStatus = 'expanded';\n      }\n      this.sideDashChange.next(this.sideDashStatus);\n    })\n\n    this.statusService.getVersions()\n      .subscribe(versions => {\n        this.versions = versions;\n        this.cdr.markForCheck();\n      });\n\n    this.statusService.status$.subscribe(status => {\n      this.pauseState = GetModuleState(status, 'Control', 'control:paused')?.Data || null;\n    });\n\n    this.configService.watch<StringSetting>('filter/defaultAction')\n      .subscribe(defaultAction => {\n        this.globalPromptingEnabled = defaultAction === 'ask';\n        this.cdr.markForCheck();\n      })\n    \n    this.configService.watch<BoolSetting>(\"spn/enable\")\n      .subscribe(value => {\n        this.spnEnabled = value;\n        this.cdr.markForCheck();\n      });\n\n    this.notificationService.new$\n      .subscribe(notif => {\n\n\n        if (notif.some(n => n.Type === NotificationType.Prompt && n.EventID.startsWith(\"filter:prompt\"))) {\n          this.hasNewPrompts = true;\n\n          if (this.integration instanceof TauriIntegrationService) {\n            this.integration.openPrompt();\n          }\n        } else {\n          this.hasNewPrompts = false;\n\n          if (this.integration instanceof TauriIntegrationService) {\n            this.integration.closePrompt();\n          }\n        }\n\n        if (notif.some(n => !n.EventID.startsWith(\"filter:prompt\"))) {\n          this.hasNewNotifications = true;\n        } else {\n          this.hasNewNotifications = false;\n        }\n\n        if (notif.some(n => n.Type === NotificationType.Error)) {\n          this.notificationColor = 'text-red-300';\n        } else if (notif.some(n => n.Type === NotificationType.Warning)) {\n          this.notificationColor = 'text-yellow-300';\n        } else {\n          this.notificationColor = 'text-green-300';\n        }\n\n        this.cdr.markForCheck();\n      })\n  }\n\n  toggleSideDash(event: MouseEvent) {\n    let notify: 'expanded' | 'collapsed' | 'force-overlay' = this.sideDashStatus;\n\n    if (this.sideDashStatus === 'collapsed') {\n      this.sideDashStatus = 'expanded';\n      notify = 'expanded';\n      if (event.shiftKey) {\n        notify = 'force-overlay'\n      }\n    } else {\n      this.sideDashStatus = 'collapsed';\n      notify = 'collapsed'\n    }\n\n    this.sideDashChange.next(notify);\n  }\n\n  /**\n   * @private\n   * Injects a ui/reload event and performs a complete\n   * reload of the window once the portmaster re-opened the\n   * UI bundle.\n   */\n  reloadUI(_: Event) {\n    this.portapi.reloadUI()\n      .pipe(\n        tap(() => {\n          setTimeout(() => window.location.reload(), 1000)\n        })\n      )\n      .subscribe(this.actionIndicator.httpObserver(\n        'Reloading UI ...',\n        'Failed to Reload UI',\n      ))\n  }\n\n  /** Re-initialize the SPN */\n  reinitSPN(_: Event) {\n    this.portapi.reinitSPN()\n      .subscribe(this.actionIndicator.httpObserver(\n        'Re-initialized SPN',\n        'Failed to re-initialize the SPN'\n      ))\n  }\n\n  /** Logs the user out of the SPN completely by purgin the user profile from the local storage */\n  logoutCompletely(_: Event) {\n    this.spnService.logout(true)\n      .subscribe(this.actionIndicator.httpObserver(\n        'Logout',\n        'You have been logged out of the SPN completely.'\n      ))\n  }\n\n  /**\n   * @private\n   * Clear the DNS name cache.\n   */\n  clearDNSCache(_: Event) {\n    this.portapi.clearDNSCache()\n      .subscribe(this.actionIndicator.httpObserver(\n        'DNS Cache Cleared',\n        'Failed to Clear DNS Cache.',\n      ))\n  }\n\n  cleanupHistory(_: Event) {\n    this.portapi.cleanupHistory()\n      .subscribe(this.actionIndicator.httpObserver(\n        'Network History Cleaned Up',\n        'Failed to Cleanup Network History.'\n      ))\n  }\n\n  /**\n   * @private\n   * Trigger downloading of updates\n   *\n   * @param event - The mouse event\n   */\n  downloadUpdates(event: Event) {\n    this.portapi.checkForUpdates()\n      .subscribe(this.actionIndicator.httpObserver(\n        'Downloading Updates ...',\n        'Failed to Check for Updates',\n      ))\n  }\n\n  /**\n   * @private\n   * Trigger a shutdown of the portmaster-core service\n   */\n  shutdown(_: Event) {\n    this.exitService.shutdownPortmaster();\n  }\n\n  /**\n   * @private\n   * Trigger a restart of the portmaster-core service. Requires\n   * that portmaster has been started with a service-wrapper.\n   *\n   * @param event The mouse event\n   */\n  restart(event: Event) {\n    // prevent default and stop-propagation to avoid\n    // expanding the accordion body.\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.portapi.restartPortmaster()\n      .subscribe(this.actionIndicator.httpObserver(\n        'Restarting ...',\n        'Failed to Restart',\n      ))\n  }\n\n   pause(event: Event, duration: number) {\n    // prevent default and stop-propagation to avoid\n    // expanding the accordion body.\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.portapi.pause(duration, false)\n      .subscribe(this.actionIndicator.httpObserver(\n        'Pausing ...',\n        'Failed to Pause',\n      ))\n  }\n  pauseSPN(event: Event, duration: number) {\n    // prevent default and stop-propagation to avoid\n    // expanding the accordion body.\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.portapi.pause(duration, true)\n      .subscribe(this.actionIndicator.httpObserver(\n        'Pausing SPN...',\n        'Failed to Pause SPN',\n      ))\n  }\n  resume(event: Event) {\n    // prevent default and stop-propagation to avoid\n    // expanding the accordion body.\n    event.preventDefault();\n    event.stopPropagation();\n\n    let msg = 'Resuming ...';\n    if (this.pauseState?.Interception===true && this.pauseState?.SPN===true) \n      msg = 'Resuming Portmaster and SPN ...';\n    else if (this.pauseState?.Interception===true)\n      msg = 'Resuming Portmaster ...';\n    else if (this.pauseState?.SPN===true)\n      msg = 'Resuming SPN ...';\n\n    this.portapi.resume()\n      .subscribe(this.actionIndicator.httpObserver(\n        msg,\n        'Failed to Resume',\n      ))\n  }\n    \n  /**\n   * @private\n   * Opens the data-directory of the portmaster installation.\n   * Requires the application to run inside electron.\n   */\n  async openDataDir(event: Event) {\n    const dir = await this.integration.getInstallDir()\n    await this.integration.openExternal(dir);\n  }\n\n  openChangeLog() {\n    const url = \"https://github.com/safing/portmaster/releases\";\n    this.integration.openExternal(url);\n  }\n\n  showIntro() {\n    this.appComponent.showIntro()\n  }\n\n  resetBroadcastState() {\n    this.portapi.resetBroadcastState()\n      .subscribe(this.actionIndicator.httpObserver(\n        'Notifications State Cleared',\n        'Failed to Reset Notifications State.',\n      ))\n  }\n\n  copyDebugInfo(event: Event) {\n    // prevent default and stop-propagation to avoid\n    // expanding the accordion body.\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.debugAPI.getCoreDebugInfo()\n      .subscribe(\n        async info => {\n          await this.integration.writeToClipboard(info);\n        },\n        err => {\n          console.error(err);\n          this.actionIndicator.error('Failed loading debug data', err);\n        }\n      )\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/layout/side-dash/side-dash.html",
    "content": "<div sfngTipUpTrigger=\"navShield\" sfngTipUpPassive class=\"relative flex flex-row w-full gap-2 px-2 pb-4 justify-evenly\">\n  <app-security-lock routerLink=\"/dashboard\"></app-security-lock>\n</div>\n\n<app-feature-scout></app-feature-scout>\n\n<app-notification-list></app-notification-list>\n\n<app-spn-login *ngIf=\"spnLoginRequired\"></app-spn-login>\n<app-network-scout *ngIf=\"!spnLoginRequired\" class=\"flex-grow overflow-auto\"></app-network-scout>\n"
  },
  {
    "path": "desktop/angular/src/app/layout/side-dash/side-dash.scss",
    "content": ":host {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: flex-start;\n  overflow: hidden;\n  overflow-y: hidden;\n  width: 419px;\n\n  @apply pt-4;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/layout/side-dash/side-dash.ts",
    "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n@Component({\n  selector: 'app-side-dash',\n  templateUrl: './side-dash.html',\n  styleUrls: ['./side-dash.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SideDashComponent {\n  /** Whether or not a SPN account login is required */\n  spnLoginRequired = false;\n\n}\n"
  },
  {
    "path": "desktop/angular/src/app/package.json",
    "content": "{\n  \"name\": \"portmaster\",\n  \"private\": true,\n  \"description_1\": \"This is a special package.json file that is not used by package managers.\",\n  \"description_2\": \"It is used to tell the tools and bundlers whether the code under this directory is free of code with non-local side-effect. Any code that does have non-local side-effects can't be well optimized (tree-shaken) and will result in unnecessary increased payload size.\",\n  \"description_3\": \"It should be safe to set this option to 'false' for new applications, but existing code bases could be broken when built with the production config if the application code does contain non-local side-effects that the application depends on.\",\n  \"description_4\": \"To learn more about this file see: https://angular.io/config/app-package-json.\",\n  \"sideEffects\": false,\n  \"devDependencies\": {\n    \"@types/node\": \"^17.0.31\"\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/app-insights/app-insights.component.html",
    "content": "<div class=\"grid grid-cols-2 gap-2\">\n  <app-dashboard-widget label=\"Connections\" style=\"min-height: 400px;\">\n    <sfng-netquery-line-chart [data]=\"connectionChart\"></sfng-netquery-line-chart>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget label=\"Data Usage\" beta=\"true\" style=\"min-height: 400px;\">\n    <sfng-netquery-line-chart [config]=\"bwChartConfig\" [data]=\"bandwidthChart\"></sfng-netquery-line-chart>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget label=\"Countries\" beta=\"true\" style=\"min-height: 400px\">\n    <sfng-netquery-circular-bar-chart class=\"block w-full h-full\" [data]=\"countryData\" [config]=\"countryBarConfig\"></sfng-netquery-circular-bar-chart>\n  </app-dashboard-widget>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/app-insights/app-insights.component.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Input, OnInit, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AppProfile, BandwidthChartResult, ChartResult, Netquery } from '@safing/portmaster-api';\nimport { repeat } from 'rxjs';\nimport { CircularBarChartConfig, splitQueryResult } from 'src/app/shared/netquery/circular-bar-chart/circular-bar-chart.component';\nimport { DefaultBandwidthChartConfig } from 'src/app/shared/netquery/line-chart/line-chart';\n\ninterface CountryBarData {\n  series: 'country';\n  value: number;\n  country: string;\n}\n\n@Component({\n  selector: 'app-app-insights',\n  templateUrl: './app-insights.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class AppInsightsComponent implements OnInit {\n  private readonly netquery = inject(Netquery);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly cdr = inject(ChangeDetectorRef);\n\n  @Input()\n  profile!: AppProfile;\n\n  connectionChart: ChartResult[] = [];\n\n  bandwidthChart: BandwidthChartResult<any>[] = [];\n\n  bwChartConfig = DefaultBandwidthChartConfig;\n\n  countryData: CountryBarData[] = [];\n\n  readonly countryBarConfig: CircularBarChartConfig<CountryBarData> = {\n    stack: 'country',\n    seriesKey: 'series',\n    value: 'value',\n    ticks: 3,\n    colorAsClass: true,\n    series: {\n      'count': {\n        color: 'text-green-300 text-opacity-50',\n      },\n    },\n  }\n\n  ngOnInit() {\n    const key = `${this.profile.Source}/${this.profile.ID}`\n\n    this.netquery.batch({\n      countryData: {\n        select: [\n          'country',\n          { $count: { field: '*', as: 'count' } },\n        ],\n        query: {\n          internal: { $eq: false },\n          country: { $ne: '' }\n        },\n        groupBy: ['country']\n      }\n    })\n      .pipe(\n        repeat({ delay: 10000 }),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(result => {\n        this.countryData = splitQueryResult(result.countryData, ['count']) as CountryBarData[];\n        console.log(this.countryData)\n        this.cdr.markForCheck();\n      })\n\n    this.netquery.activeConnectionChart({ profile: key })\n      .pipe(\n        repeat({ delay: 10000 }),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(data => {\n        this.connectionChart = data;\n        this.cdr.markForCheck();\n      })\n\n    this.netquery.bandwidthChart({ profile: key }, undefined, 60)\n      .pipe(\n        repeat({ delay: 10000 }),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(data => {\n        this.bandwidthChart = data;\n        this.cdr.markForCheck();\n      })\n\n  }\n\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/app-view.html",
    "content": "<ng-container *ngIf=\"!showOverview && !!appProfile\">\n  <!-- Header -->\n  <div class=\"flex justify-between items-center p-4 px-12 text-xxs\">\n    <!-- Breadcrumbs -->\n    <div class=\"flex items-center\">\n      <div class=\"cursor-pointer text-secondary hover:text-primary\" [routerLink]=\"['/app/overview']\">Apps</div>\n      <svg viewBox=\"0 0 24 24\" class=\"inline-block w-4 h-4 text-secondary\">\n        <g fill=\"none\" class=\"inner\" stroke=\"currentColor\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.2\" d=\"M10 16l4-4-4-4\" />\n        </g>\n      </svg>\n      <span class=\"text-primary\">{{ appProfile.Name }}</span>\n    </div>\n\n    <!-- Expertise level switch -->\n    <app-expertise></app-expertise>\n  </div>\n\n\n  <!-- Application Header -->\n  <div class=\"relative px-12 transition-all duration-200\" [class.p-4]=\"!collapseHeader\">\n    <div class=\"flex relative z-10 flex-row items-center w-full\" [class.py-8]=\"!collapseHeader\">\n      <!-- Application metadata -->\n      <div class=\"flex flex-col flex-grow items-start space-y-5\">\n        <!-- App Name & Icon -->\n        <h1 class=\"flex flex-row gap-2 items-center mb-0 text-2xl whitespace-nowrap text-primary\">\n          <app-icon [profile]=\"appProfile\" style=\"--app-icon-size: 3rem\"></app-icon>\n\n          <span>{{appProfile!.Name}}</span>\n        </h1>\n\n        <!-- App Metadata -->\n        <div class=\"text-tertiary text-xxs\" *ngIf=\"!collapseHeader\" [@fadeIn] [@fadeOut]>\n          <div class=\"space-x-2\" *ngIf=\"!!applicationDirectory\">\n            <span>Path:</span>\n            <span class=\"text-opacity-75 text-primary\">\n              {{ applicationDirectory }}\n            </span>\n          </div>\n          <div class=\"space-x-2\" *ngIf=\"!!binaryName\">\n            <span>Binary:</span>\n            <span class=\"text-opacity-75 text-primary\">\n              {{ binaryName }}\n            </span>\n          </div>\n          <div class=\"space-x-2\">\n            <span>Active Connections:</span>\n            <span class=\"text-opacity-75 text-primary\">{{stats?.countAliveConnections || 0}}</span>\n          </div>\n          <div class=\"space-x-2\">\n            <span>Network History:</span>\n            <ng-container *ngIf=\"historyAvailableSince\">\n              <span class=\"text-opacity-75 text-primary\">As of {{ historyAvailableSince | date }}</span>\n              <span class=\"-mt-3 underline cursor-pointer text-primary hover:text-secondary text-xxs\"\n                (click)=\"cleanProfileHistory()\">Remove all {{ connectionsInHistory }} Connections</span>\n            </ng-container>\n            <ng-container *ngIf=\"!historyAvailableSince\">\n              <span class=\"text-opacity-75 text-primary\"\n                sfng-tooltip=\"Network History feature is available in Portmaster Plus\">None</span>\n            </ng-container>\n          </div>\n        </div>\n\n        <!-- Quick Settings -->\n        <div class=\"flex flex-row flex-wrap gap-2 items-stretch whitespace-nowrap text-xxs\" *ngIf=\"!collapseHeader\" [@fadeIn]\n          [@fadeOut]>\n          <app-qs-internet [settings]=\"profileSettings\" (save)=\"saveSetting($event)\">\n          </app-qs-internet>\n\n          <app-qs-history [canUse]=\"canUseHistory\" [settings]=\"profileSettings\" (save)=\"saveSetting($event)\">\n          </app-qs-history>\n\n          <app-qs-use-spn [canUse]=\"canUseSPN\" [settings]=\"profileSettings\" (save)=\"saveSetting($event)\">\n          </app-qs-use-spn>\n\n          <app-qs-select-exit [canUse]=\"canUseSPN\" [settings]=\"profileSettings\" (save)=\"saveSetting($event)\">\n          </app-qs-select-exit>\n\n          <button class=\"flex flex-row gap-2 items-center px-4 bg-gray-300 btn\" cdkOverlayOrigin #overlayOrigin=\"cdkOverlayOrigin\" (click)=\"profileMenu.dropdown.toggle(overlayOrigin)\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4\">\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z\" />\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\" />\n            </svg>\n\n            More\n          </button>\n\n          <app-menu #profileMenu>\n            <app-menu-item (click)=\"editProfile()\">Edit App Profile</app-menu-item>\n            <app-menu-item (click)=\"exportProfile()\">Export App Profile</app-menu-item>\n            <app-menu-item (click)=\"deleteProfile()\">Delete App Profile</app-menu-item>\n          </app-menu>\n\n          <sfng-tipup key=\"appSettings-QuickSettings\"></sfng-tipup>\n        </div>\n      </div>\n\n      <!-- Statistics -->\n      <div class=\"flex flex-row flex-wrap flex-grow gap-4 justify-end items-center pr-8\"\n        *ngIf=\"!!stats && stats.size > 0\">\n        <div [ngClass]=\"{\n            'h-20 sfng-lg:w-32 sfng-lg:h-24': !collapseHeader\n          }\"\n          class=\"flex flex-col justify-center items-center px-4 py-1 w-24 bg-gray-300 bg-opacity-75 rounded border border-gray-300 shadow transition-all duration-200\">\n          <h2 class=\"p-0 m-0 text-lg sfng-lg:text-xl text-primary\">{{ stats!.size | prettyCount }}</h2>\n          <span class=\"text-secondary\">Connections</span>\n        </div>\n\n        <div [ngClass]=\"{\n            'h-20 sfng-lg:w-32 sfng-lg:h-24': !collapseHeader\n          }\"\n          class=\"flex flex-col justify-center items-center px-4 py-1 w-24 bg-gray-300 bg-opacity-75 rounded border border-gray-300 shadow transition-all duration-200\">\n          <h2 class=\"p-0 m-0 text-lg sfng-lg:text-xl text-primary\">{{ (100 / stats!.size) * (stats!.size\n            - stats!.countAllowed) | number:'1.0-1' }}%</h2>\n          <span class=\"text-secondary\">Blocked</span>\n        </div>\n\n        <div [ngClass]=\"{\n            'h-20 sfng-lg:w-32 sfng-lg:h-24': !collapseHeader\n          }\"\n          class=\"flex flex-col justify-center items-center px-4 py-1 w-24 bg-gray-300 bg-opacity-75 rounded border border-gray-300 shadow transition-all duration-200\">\n          <h2 *ngIf=\"canViewBW; else: cannotViewBW\"\n            class=\"p-0 m-0 text-lg whitespace-nowrap sfng-lg:text-xl text-primary\">\n            {{ stats.bytes_received | bytes }}\n          </h2>\n          <ng-template #cannotViewBW>\n            <span routerLink=\"/dashboard\"\n              class=\"p-0 pb-2.5 m-0 text-opacity-50 whitespace-nowrap text-xxs sfng-lg:text-xs text-tertiary hover:underline\">\n              Available in Plus\n            </span>\n          </ng-template>\n          <span class=\"text-secondary\">Received</span>\n        </div>\n\n        <div [ngClass]=\"{\n            'h-20 sfng-lg:w-32 sfng-lg:h-24': !collapseHeader\n          }\"\n          class=\"flex flex-col justify-center items-center px-4 py-1 w-24 bg-gray-300 bg-opacity-75 rounded border border-gray-300 shadow transition-all duration-200\">\n          <h2 *ngIf=\"canViewBW; else: cannotViewBW\"\n            class=\"p-0 m-0 text-lg whitespace-nowrap sfng-lg:text-xl text-primary\">\n            {{ stats.bytes_sent | bytes }}\n          </h2>\n          <span class=\"text-secondary\">Sent</span>\n        </div>\n\n      </div>\n    </div>\n\n    <div class=\"absolute bottom-0 right-10 z-10 cursor-pointer hover:text-primary text-secondary\"\n      (click)=\"collapseHeader = !collapseHeader\">\n      <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n        class=\"w-6 h-6 transition-all duration-200\" [class.rotate-180]=\"collapseHeader\">\n        <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 15.75l7.5-7.5 7.5 7.5\" />\n      </svg>\n    </div>\n  </div>\n\n  <sfng-tab-group class=\"flex overflow-hidden flex-col flex-grow p-4 px-12 w-full\">\n    <!-- Connections -->\n    <sfng-tab id=\"connections\" title=\"Connections\">\n      <div *sfngTabContent>\n        <sfng-netquery-viewer [filters]=\"['allowed', 'as_owner', 'country', 'domain']\"\n          [mergeFilter]=\"{profile: appProfile.Source + '/' + appProfile.ID}\">\n        </sfng-netquery-viewer>\n      </div>\n    </sfng-tab>\n    <!-- App Settings -->\n    <sfng-tab id=\"settings\" title=\"Settings\">\n      <div *sfngTabContent class=\"overflow-auto py-4\" cdkScrollable>\n\n        <div class=\"flex flex-row items-center pr-2 mb-4 space-x-4\">\n          <input type=\"text\" [(ngModel)]=\"searchTerm\" placeholder=\"Search Settings\">\n\n          <a href=\"https://docs.safing.io/portmaster/settings?source=Portmaster\"\n            class=\"flex flex-row gap-1 justify-center items-center self-stretch px-2 whitespace-nowrap bg-gray-300 rounded hover:bg-gray-200 text-blue\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n              stroke=\"currentColor\" class=\"w-4 h-4\">\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                d=\"M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25\" />\n            </svg>\n            Get Help\n          </a>\n\n          <!--\n          TODO: \"View Active\" button is broken or should have been removed.\n          <div sfngTipUpAnchor=\"left\" class=\"flex space-x-2 flex-rows\">\n            <sfng-tipup key=\"appSettings-Filter\"></sfng-tipup>\n            <sfng-select [ngModel]=\"viewSetting\" (ngModelChange)=\"viewSettingChange.next($event)\"\n              sfngTipUpTrigger=\"appSettings-Filter\" sfngTipUpAnchor=\"left\" sfngTipUpPassive>\n              <sfng-select-item *sfngSelectValue=\"'all'\">\n                View All\n              </sfng-select-item>\n              <sfng-select-item *sfngSelectValue=\"'active'\">\n                View Active\n              </sfng-select-item>\n            </sfng-select>\n          </div>\n          -->\n        </div>\n\n        <div class=\"flex items-center text-tertiary\">\n          <div class=\"inline-flex items-center\" sfngTipUpAnchor=>\n            <span class=\"mr-3 text-xxs\">App Specific Settings</span>\n            <sfng-tipup key=\"appSettings\"></sfng-tipup>\n          </div>\n        </div>\n\n        <ng-container *ngIf=\"settings.length > 0; else: noSettingsTemplate\">\n          <app-settings-view [searchTerm]=\"searchTerm\" [availableSettings]=\"settings\" compactView=\"true\"\n            [highlightKey]=\"highlightSettingKey\" userSettingsMarker=\"true\" (save)=\"saveSetting($event)\"\n            resetLabelText=\"Use global setting\" lockDefaults=\"true\" displayStackable=\"true\" [scope]=\"appProfile.Source + '/' + appProfile.ID\">\n          </app-settings-view>\n        </ng-container>\n\n        <ng-template #noSettingsTemplate>\n          <div class=\"flex flex-col items-center mt-32\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-32 h-32 text-opacity-50 text-tertiary\" viewBox=\"0 0 20 20\"\n              fill=\"currentColor\">\n              <path fill-rule=\"evenodd\"\n                d=\"M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z\"\n                clip-rule=\"evenodd\" />\n            </svg>\n\n            <p class=\"text-sm\">\n              <span class=\"text-primary\">\n                {{ appProfile!.Name }}\n              </span>\n              is fully using the global settings.\n            </p>\n            <p class=\"mb-4 text-sm\">\n              Start creating exceptions for it now.\n            </p>\n            <button (click)=\"viewSettingChange.next('all')\">Edit Settings</button>\n          </div>\n        </ng-template>\n      </div>\n    </sfng-tab>\n\n    <!-- Details -->\n    <sfng-tab id=\"details\" title=\"Details\" [warning]=\"displayWarning\">\n      <div *sfngTabContent class=\"overflow-auto py-4 space-y-8\" cdkScrollable>\n\n        <div class=\"grid grid-cols-2 gap-4 text-primary text-xxs\">\n          <div class=\"flex flex-col justify-center p-4 bg-gray-200 rounded\">\n            <p class=\"space-x-2\">\n              <label class=\"text-secondary\">Name:</label>\n              <span>{{appProfile!.Name}}</span>\n            </p>\n            <p class=\"space-x-2\">\n              <label class=\"text-secondary\">Path:</label>\n              <span>{{appProfile!.PresentationPath}}</span>\n            </p>\n          </div>\n\n          <div class=\"flex flex-col justify-center p-4 bg-gray-200 rounded\">\n            <p class=\"space-x-2\">\n              <label class=\"text-secondary\">Created:</label>\n              <span>{{appProfile!.Created * 1000 | date:'medium'}}</span>\n            </p>\n            <p class=\"space-x-2\">\n              <label class=\"text-secondary\">Last Edited:</label>\n              <span *ngIf=\"!!appProfile.LastEdited\">{{appProfile!.LastEdited * 1000 | date:'medium'}}</span>\n              <span *ngIf=\"!appProfile.LastEdited\">N/A</span>\n            </p>\n          </div>\n\n          <ng-container *appExpertiseLevel=\"'developer'\">\n            <div class=\"flex flex-col justify-center p-4 bg-gray-200 rounded\">\n              <p class=\"space-x-2\">\n                <label class=\"text-secondary\">Internal:</label>\n                <span>{{!!appProfile!.Internal ? 'yes' : 'no'}}</span>\n              </p>\n              <p class=\"space-x-2\">\n                <label class=\"text-secondary\">Source:</label>\n                <span>{{appProfile!.Source}}</span>\n              </p>\n              <p class=\"space-x-2\">\n                <label class=\"text-secondary\">ID:</label>\n                <span>{{appProfile!.ID}}</span>\n              </p>\n            </div>\n\n            <div class=\"flex flex-col justify-center p-4 bg-gray-200 rounded\">\n              <p class=\"space-x-2\">\n                <label class=\"text-secondary\">Revision:</label>\n                <span>{{layeredProfile?.RevisionCounter}}</span>\n              </p>\n              <p class=\"space-x-2\">\n                <label class=\"text-secondary\">Layers:</label>\n                <span>\n                  <ol class=\"inline-block\">\n                    <li *ngFor=\"let layer of layeredProfile?.LayerIDs\"\n                      [routerLink]=\"['/', 'app'].concat(layer.split('/'))\">\n                      {{layer}}\n                    </li>\n                  </ol>\n                </span>\n              </p>\n            </div>\n          </ng-container>\n        </div>\n\n        <!-- Description Section -->\n        <div class=\"flex flex-col space-y-4\" *ngIf=\"!!appProfile?.Description\">\n          <h2 class=\"flex flex-row items-center p-0 m-0 mr-2 mb-4 text-opacity-75 text-primary\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-1 w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\"\n              stroke=\"currentColor\">\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n                d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n            </svg>\n            <span class=\"mr-2 text-xxs\">Description</span>\n            <span class=\"inline-block flex-grow border-b border-gray-400\"></span>\n          </h2>\n\n          <markdown emoji [data]=\"appProfile.Description\"\n            class=\"block self-stretch p-4 -mb-4 ml-2 w-auto h-auto text-secondary\">\n          </markdown>\n        </div>\n\n        <!-- Warning Section -->\n        <div class=\"flex flex-col space-y-4\" *ngIf=\"displayWarning\">\n          <h2 class=\"flex flex-row items-center p-0 m-0 mr-2 mb-4 text-opacity-75 text-primary\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-1 w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\"\n              stroke=\"currentColor\">\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n                d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n            </svg>\n            <span class=\"mr-2 text-xxs\">Warning</span>\n            <span class=\"inline-block flex-grow border-b border-gray-400\"></span>\n          </h2>\n\n          <markdown emoji [data]=\"appProfile.Warning\"\n            class=\"block self-stretch p-4 ml-2 w-auto h-auto border-l text-secondary border-yellow\">\n          </markdown>\n          <span class=\"text-tertiary text-xxs\" *ngIf=\"appProfile?.WarningLastUpdated\">updated\n            {{ appProfile.WarningLastUpdated | timeAgo }}</span>\n        </div>\n\n        <!-- Fingerprints -->\n        <div class=\"space-y-4 text-xxs\">\n          <h2 class=\"flex flex-row items-center p-0 m-0 mr-2 mb-4 text-opacity-75 text-primary\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n              stroke=\"currentColor\" class=\"mr-1 w-5 h-5\">\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                d=\"M7.864 4.243A7.5 7.5 0 0119.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 004.5 10.5a7.464 7.464 0 01-1.15 3.993m1.989 3.559A11.209 11.209 0 008.25 10.5a3.75 3.75 0 117.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 01-3.6 9.75m6.633-4.596a18.666 18.666 0 01-2.485 5.33\" />\n            </svg>\n\n            <span class=\"mr-2 text-xxs\">Fingerprints</span>\n            <span class=\"inline-block flex-grow border-b border-gray-400\"></span>\n          </h2>\n\n          <span class=\"text-xs text-secondary\">This profile will be applied to processes that match one of the following\n            fingerprints:</span>\n\n          <div\n            class=\"flex relative flex-row gap-2 items-center p-2 mx-3 bg-gray-200 border-r border-l border-gray-500 w-fit\"\n            *ngFor=\"let fp of appProfile.Fingerprints\">\n\n            <span class=\"block absolute top-0 left-0 w-2 border-b border-gray-500\"></span>\n            <span class=\"block absolute bottom-0 left-0 w-2 border-b border-gray-500\"></span>\n\n            <span class=\"block absolute top-0 right-0 w-2 border-b border-gray-500\"></span>\n            <span class=\"block absolute right-0 bottom-0 w-2 border-b border-gray-500\"></span>\n\n            <span class=\"inline-block px-2 py-1 bg-gray-400 rounded\">{{ fp.Type }}</span>\n\n            <ng-container *ngIf=\"!!fp.Key\">\n              <span class=\"text-secondary\">where</span>\n              <span\n                class=\"inline-block px-2 py-1 bg-gray-400 rounded\">{{ fp.Type === 'tag' ? (tagNames[fp.Key] || fp.Key) : fp.Key }}</span>\n            </ng-container>\n\n            <span class=\"inline-block px-2 py-1 bg-gray-400 rounded\">{{ fp.Operation }}</span>\n            <span class=\"inline-block px-2 py-1 bg-gray-400 rounded\">{{ fp.Value }}</span>\n          </div>\n        </div>\n\n        <!-- Delete Profile Section -->\n        <div class=\"space-y-4\">\n          <h2 class=\"flex flex-row items-center p-0 m-0 mr-2 mb-4 text-opacity-75 text-primary\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-1 w-5 h-5\" fill=\"none\" viewBox=\"0 0 24 24\"\n              stroke=\"currentColor\">\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\"\n                d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" />\n            </svg>\n            <span class=\"mr-2 text-xxs\">Delete Profile</span>\n            <span class=\"inline-block flex-grow border-b border-gray-400\"></span>\n          </h2>\n\n          <span class=\"text-secondary\">You can completely delete this profile to get rid of any settings. The profile\n            will\n            be automatically re-created with default settings as soon as the application starts to use the\n            network.</span>\n\n          <button class=\"block mt-2\" (click)=\"deleteProfile()\">Delete Profile</button>\n        </div>\n\n        <!-- Debug Section -->\n        <div class=\"space-y-4\">\n          <h2 class=\"flex flex-row items-center p-0 m-0 mr-2 mb-4 text-opacity-75 text-primary\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" class=\"mr-1 w-5 h-5\">\n              <g fill=\"none\">\n                <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\"\n                  d=\"m18 7-1 2-1.333.917M5 12h3.11M15.89 12H19M6 3H5c-1.105 0-2 .895-2 2v1M18 21h1c1.105 0 2-.895 2-2v-1M3 18v1c0 1.105.895 2 2 2h1M21 6V5c0-1.105-.895-2-2-2h-1M6 7l1 2 1.333.917M12.444 17h-.889c-1.657 0-3-1.343-3-3v-3c0-1.105.895-2 2-2h2.889c1.105 0 2 .895 2 2v3c0 1.657-1.343 3-3 3ZM6 17l1-2 1.333-.917M18 17l-1-2-1.333-.917M14 9h-4V7c0-.552.448-1 1-1h2c.552 0 1 .448 1 1v2Z\" />\n              </g>\n            </svg>\n\n            <span class=\"mr-2 text-xxs\">Debugging</span>\n            <span class=\"inline-block flex-grow border-b border-gray-400\"></span>\n          </h2>\n\n          <span class=\"text-secondary\">When reporting issues with this app please make sure to include the\n            following\n            debug information:</span>\n\n          <button class=\"block mt-2\" (click)=\"copyDebugInfo()\">Copy Debug Information</button>\n        </div>\n      </div>\n    </sfng-tab>\n    <sfng-tab id=\"insights\" title=\"Insights\">\n      <div *sfngTabContent class=\"py-4 space-y-8 overflow-auto\" cdkScrollable>\n        <app-app-insights [profile]=\"appProfile\"></app-app-insights>\n      </div>\n    </sfng-tab>\n  </sfng-tab-group>\n</ng-container>\n\n<app-settings-overview *ngIf=\"showOverview\" class=\"p-4 px-12\"></app-settings-overview>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/app-view.scss",
    "content": ":host {\n  @apply flex flex-col h-screen max-h-screen;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/app-view.ts",
    "content": "import {\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  OnDestroy,\n  OnInit,\n  ViewChild,\n  inject,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport {\n  AppProfile,\n  AppProfileService,\n  Condition,\n  ConfigService,\n  Database,\n  DebugAPI,\n  ExpertiseLevel,\n  FeatureID,\n  FlatConfigObject,\n  IProfileStats,\n  LayeredProfile,\n  Netquery,\n  PortapiService,\n  SPNService,\n  Setting,\n  flattenProfileConfig,\n  setAppSetting\n} from '@safing/portmaster-api';\nimport { SfngDialogService } from '@safing/ui';\nimport {\n  BehaviorSubject,\n  Observable,\n  Subscription,\n  combineLatest,\n  interval,\n  of,\n  throwError,\n} from 'rxjs';\nimport {\n  catchError,\n  distinctUntilChanged,\n  map,\n  mergeMap,\n  startWith,\n  switchMap,\n} from 'rxjs/operators';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\nimport { SessionDataService } from 'src/app/services';\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\nimport { fadeInAnimation, fadeOutAnimation } from 'src/app/shared/animations';\nimport {\n  ExportConfig,\n  ExportDialogComponent,\n} from 'src/app/shared/config/export-dialog/export-dialog.component';\nimport { SaveSettingEvent } from 'src/app/shared/config/generic-setting/generic-setting';\nimport { ExpertiseService } from 'src/app/shared/expertise';\nimport { SfngNetqueryViewer } from 'src/app/shared/netquery';\nimport { EditProfileDialog } from './../../shared/edit-profile-dialog/edit-profile-dialog';\n\n@Component({\n  templateUrl: './app-view.html',\n  styleUrls: ['../page.scss', './app-view.scss'],\n  animations: [fadeOutAnimation, fadeInAnimation],\n})\nexport class AppViewComponent implements OnInit, OnDestroy {\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  @ViewChild(SfngNetqueryViewer)\n  netqueryViewer?: SfngNetqueryViewer;\n\n  destroyRef = inject(DestroyRef);\n  spn = inject(SPNService);\n\n  canUseHistory = false;\n  canViewBW = false;\n  canUseSPN = false;\n\n  /** subscription to our update-process observable */\n  private subscription = Subscription.EMPTY;\n\n  /**\n   * @private\n   * historyAvailableSince holds the date of the oldes connection\n   * in the history database for this app.\n   */\n  historyAvailableSince: Date | null = null;\n\n  /**\n   * @private\n   * connectionsInHistory holds the total amount of connections\n   * in the history database for this app\n   */\n  connectionsInHistory = 0;\n\n  /**\n   * @private\n   * The current AppProfile we are showing.\n   */\n  appProfile: AppProfile | null = null;\n\n  /**\n   * @private\n   * Whether or not the overview componet should be rendered.\n   */\n  get showOverview() {\n    return this.appProfile == null && !this._loading;\n  }\n\n  /**\n   * @private\n   * The currently displayed list of settings\n   */\n  settings: Setting[] = [];\n\n  profileSettings: Setting[] = [];\n\n  /**\n   * @private\n   * All available settings.\n   */\n  allSettings: Setting[] = [];\n\n  /**\n   * @private\n   * The current search term displayed in the search-input.\n   */\n  searchTerm = '';\n\n  /**\n   * @private\n   * The key of the setting to highligh, if any ...\n   */\n  highlightSettingKey: string | null = null;\n\n  /**\n   * @private\n   * Emits whenever the currently used settings \"view\" changes.\n   */\n  viewSettingChange = new BehaviorSubject<'all' | 'active'>('all');\n\n  /**\n   * @private\n   * The path of the application binary\n   */\n  applicationDirectory = '';\n\n  /**\n   * @private\n   * The name of the binary\n   */\n  binaryName = '';\n\n  /**\n   * @private\n   * Whether or not the profile warning message should be displayed\n   */\n  displayWarning = false;\n\n  /**\n   * @private\n   * The current profile statistics\n   */\n  stats: IProfileStats | null = null;\n\n  /**\n   * @private\n   * The internal, layered profile if the app is active\n   */\n  layeredProfile: LayeredProfile | null = null;\n\n  /** Used to track whether we are already initialized */\n  private _loading = true;\n\n  /**\n   * @private\n   *\n   * Defines what \"view\" we are currently in\n   */\n  get viewSetting(): 'all' | 'active' {\n    return this.viewSettingChange.getValue();\n  }\n\n  /** A lookup map from tag ID to tag Name */\n  tagNames: {\n    [tagID: string]: string;\n  } = {};\n\n  collapseHeader = false;\n\n  constructor(\n    public sessionDataService: SessionDataService,\n    private profileService: AppProfileService,\n    private route: ActivatedRoute,\n    private netquery: Netquery,\n    private cdr: ChangeDetectorRef,\n    private configService: ConfigService,\n    private router: Router,\n    private actionIndicator: ActionIndicatorService,\n    private dialog: SfngDialogService,\n    private debugAPI: DebugAPI,\n    private expertiseService: ExpertiseService,\n    private portapi: PortapiService\n  ) { }\n\n  /**\n   * @private\n   * Used to save a change in the app settings. Emitted by the config-view\n   * component\n   *\n   * @param event The emitted save-settings-event.\n   */\n  saveSetting(event: SaveSettingEvent) {\n    // Guard against invalid usage and abort if there's not appProfile\n    // to save.\n    if (!this.appProfile) {\n      return;\n    }\n\n    if (!this.appProfile!.Config) {\n      this.appProfile.Config = {}\n    }\n\n    // If the value has been \"reset to global value\" we need to\n    // set the value to \"undefined\".\n    if (event.isDefault) {\n      setAppSetting(this.appProfile!.Config, event.key, undefined);\n    } else {\n      setAppSetting(this.appProfile!.Config, event.key, event.value);\n    }\n\n    // Actually safe the profile\n    this.profileService.saveProfile(this.appProfile!).subscribe({\n      next: () => {\n        if (!!event.accepted) {\n          event.accepted();\n        }\n      },\n      error: (err) => {\n        // if there's a callback function for errors call it.\n        if (!!event.rejected) {\n          event.rejected(err);\n        }\n\n        console.error(err);\n        this.actionIndicator.error('Failed to save setting', err);\n      },\n    });\n  }\n\n  exportProfile() {\n    if (!this.appProfile) {\n      return;\n    }\n\n    this.portapi\n      .exportProfile(`${this.appProfile.Source}/${this.appProfile.ID}`)\n      .subscribe((exportBlob) => {\n        const exportConfig: ExportConfig = {\n          type: 'profile',\n          content: exportBlob,\n        };\n\n        this.dialog.create(ExportDialogComponent, {\n          data: exportConfig,\n          autoclose: false,\n          backdrop: true,\n        });\n      });\n  }\n\n  editProfile() {\n    if (!this.appProfile) {\n      return;\n    }\n\n    this.dialog\n      .create(EditProfileDialog, {\n        backdrop: true,\n        autoclose: false,\n        data: `${this.appProfile.Source}/${this.appProfile.ID}`,\n      })\n      .onAction('deleted', () => {\n        // navigate to the app overview if it has been deleted.\n        this.router.navigate(['/app/']);\n      });\n  }\n\n  cleanProfileHistory() {\n    if (!this.appProfile) {\n      return;\n    }\n\n    const observer = this.actionIndicator.httpObserver(\n      'History successfully removed',\n      'Failed to remove history'\n    );\n\n    this.netquery\n      .cleanProfileHistory(this.appProfile.Source + '/' + this.appProfile.ID)\n      .subscribe({\n        next: (res) => {\n          observer.next!(res);\n          this.historyAvailableSince = null;\n          this.connectionsInHistory = 0;\n          this.cdr.markForCheck();\n        },\n        error: (err) => {\n          observer.error!(err);\n        },\n      });\n  }\n\n  ngOnInit() {\n    this.profileService.tagDescriptions().subscribe((tags) => {\n      tags.forEach((t) => {\n        this.tagNames[t.ID] = t.Name;\n        this.cdr.markForCheck();\n      });\n    });\n\n    // watch the route parameters and start watching the referenced\n    // application profile, it's layer profile and polling the stats.\n    const profileStream: Observable<\n      [AppProfile, LayeredProfile | null, IProfileStats | null] | null\n    > = this.route.paramMap.pipe(\n      switchMap((params) => {\n        // Get the profile source and id. If one is unset (null)\n        // than return a\"null\" emit-once stream.\n        const source = params.get('source');\n        const id = params.get('id');\n        if (source === null || id === null) {\n          this._loading = false;\n          return of(null);\n        }\n        this._loading = true;\n\n        this.historyAvailableSince = null;\n        this.connectionsInHistory = 0;\n        this.appProfile = null;\n        this.stats = null;\n\n        // Start watching the application profile.\n        // switchMap will unsubscribe automatically if\n        // we start watching a different profile.\n        return this.profileService.getAppProfile(source, id).pipe(\n          catchError((err) => {\n            if (typeof err === 'string') {\n              err = new Error(err);\n            }\n\n            this.router.navigate(['/app/overview'], {\n              onSameUrlNavigation: 'reload',\n            });\n\n            this.actionIndicator.error(\n              'Failed To Get Profile',\n              this.actionIndicator.getErrorMessgae(err)\n            );\n\n            return throwError(() => err);\n          }),\n          mergeMap(() => {\n            return combineLatest([\n              this.profileService.watchAppProfile(source, id),\n              this.profileService\n                .watchLayeredProfile(source, id)\n                .pipe(startWith(null)),\n              interval(10000).pipe(\n                startWith(-1),\n                mergeMap(() =>\n                  this.netquery\n                    .getProfileStats({\n                      profile: `${source}/${id}`,\n                    })\n                    .pipe(map((result) => result?.[0]))\n                ),\n                startWith(null)\n              ),\n            ]);\n          })\n        );\n      })\n    );\n\n    // used to track changes to the object identity of the global configuration\n    let prevousGlobal: FlatConfigObject = {};\n\n    this.subscription = combineLatest([\n      profileStream, // emits the current app profile everytime it changes\n      this.route.queryParamMap, // for changes to the settings= query parameter\n      this.profileService.globalConfig(), // for changes to ghe global profile\n      this.configService.query(''), // get ALL settings (once, only the defintion is of intereset)\n      this.viewSettingChange.pipe(\n        // watch the current \"settings-view\" setting, but only if it changes\n        distinctUntilChanged()\n      ),\n    ]).subscribe(\n      async ([profile, queryMap, global, allSettings, viewSetting]) => {\n        const previousProfile = this.appProfile;\n\n        if (!!profile) {\n          const key = profile![0].Source + '/' + profile![0].ID;\n\n          const query: Condition = {\n            profile: key,\n          };\n\n          // ignore internal connections if the user is not in developer mode.\n          if (this.expertiseService.currentLevel !== ExpertiseLevel.Developer) {\n            query.internal = {\n              $eq: false,\n            };\n          }\n\n          this.netquery\n            .query(\n              {\n                select: [\n                  {\n                    $min: {\n                      field: 'started',\n                      as: 'first_connection',\n                    },\n                  },\n                  {\n                    $count: {\n                      field: '*',\n                      as: 'totalCount',\n                    },\n                  },\n                ],\n                groupBy: ['profile'],\n                query: {\n                  profile: `${profile[0].Source}/${profile[0].ID}`,\n                },\n                databases: [Database.History],\n              },\n              'app-view-get-first-connection'\n            )\n            .subscribe((result) => {\n              if (result.length > 0) {\n                this.historyAvailableSince = new Date(\n                  result[0].first_connection!\n                );\n                this.connectionsInHistory = result[0].totalCount;\n              } else {\n                this.historyAvailableSince = null;\n                this.connectionsInHistory = 0;\n              }\n\n              this.cdr.markForCheck();\n            });\n\n          this.appProfile = profile[0] || null;\n          this.layeredProfile = profile[1] || null;\n          this.stats = profile[2] || null;\n        } else {\n          this.appProfile = null;\n          this.layeredProfile = null;\n          this.stats = null;\n        }\n\n        this.displayWarning = false;\n\n        if (this.appProfile?.WarningLastUpdated) {\n          const now = new Date().getTime();\n          const diff =\n            now - new Date(this.appProfile.WarningLastUpdated).getTime();\n          this.displayWarning = diff < 1000 * 60 * 60 * 24 * 7;\n        }\n\n        if (!!this.netqueryViewer && this._loading) {\n          this.netqueryViewer.performSearch();\n        }\n\n        this._loading = false;\n\n        if (!!this.appProfile?.PresentationPath) {\n          let parts: string[] = [];\n          let sep = '/';\n          if (this.appProfile.PresentationPath[0] === '/') {\n            // linux, darwin, bsd ...\n            sep = '/';\n          } else {\n            // windows ...\n            sep = '\\\\';\n          }\n          parts = this.appProfile.PresentationPath.split(sep);\n\n          this.binaryName = parts.pop()!;\n          this.applicationDirectory = parts.join(sep);\n        } else {\n          this.applicationDirectory = '';\n          this.binaryName = '';\n        }\n\n        this.highlightSettingKey = queryMap.get('setting');\n        let profileConfig: FlatConfigObject = {};\n\n        // if we have a profile flatten it's configuration map to something\n        // more useful.\n        if (!!this.appProfile) {\n          profileConfig = flattenProfileConfig(this.appProfile.Config);\n        }\n\n        // if we should highlight a setting make sure to switch the\n        // viewSetting to all if it's the \"global\" default (that is, no\n        // value is set). Otherwise the setting won't render and we cannot\n        // highlight it.\n        // We need to keep this even though we default to \"all\" now since\n        // the following might happen:\n        //  - user already navigated to an app-page and selected \"View Active\".\n        //  - a notification comes in that has a \"show setting\" action\n        //  - the user clicks the action button and the setting should be displayed\n        //  - since the requested setting has not been changed it is not available\n        //    in \"View Active\" so we need to switch back to \"View All\". Otherwise\n        //    the action button would fail and the user would not notice something\n        //    changing.\n        //\n        if (!!this.highlightSettingKey) {\n          if (profileConfig[this.highlightSettingKey] === undefined) {\n            this.viewSettingChange.next('all');\n          }\n        }\n\n        // check if we got new values for the profile or the settings. In both cases, we need to update the\n        // profile settings displayed as there might be new values to show.\n        const profileChanged = previousProfile !== this.appProfile;\n        const settingsChanged = allSettings !== this.allSettings;\n        const globalChanged = global !== prevousGlobal;\n\n        const settingsNeedUpdate =\n          profileChanged || settingsChanged || globalChanged;\n\n        // save the current global config object so we can compare for identity changes\n        // the next time we're executed\n        prevousGlobal = global;\n\n        if (!!this.appProfile && settingsNeedUpdate) {\n          // filter the settings and remove all settings that are not\n          // profile specific (i.e. not part of the global config). Also\n          // update the current settings value (from the app profile) and\n          // the default value (from the global profile).\n          this.profileSettings = allSettings.map((setting) => {\n            setting.Value = profileConfig[setting.Key];\n            setting.GlobalDefault = global[setting.Key];\n\n            return setting;\n          });\n\n          this.settings = this.profileSettings.filter((setting) => {\n            if (!(setting.Key in global)) {\n              return false;\n            }\n\n            const isModified = setting.Value !== undefined;\n            if (this.viewSetting === 'all') {\n              return true;\n            }\n            return isModified;\n          });\n\n          this.allSettings = allSettings;\n        }\n\n        this.cdr.markForCheck();\n      }\n    );\n\n    this.spn.profile$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({\n      next: (profile) => {\n        this.canUseHistory =\n          profile?.current_plan?.feature_ids?.includes(FeatureID.History) ||\n          false;\n        this.canViewBW =\n          profile?.current_plan?.feature_ids?.includes(FeatureID.Bandwidth) ||\n          false;\n        this.canUseSPN =\n          profile?.current_plan?.feature_ids?.includes(FeatureID.SPN) || false;\n      },\n    });\n  }\n\n  /**\n   * @private\n   * Retrieves debug information from the current\n   * profile and copies it to the clipboard\n   */\n  copyDebugInfo() {\n    if (!this.appProfile) {\n      return;\n    }\n\n    this.debugAPI\n      .getProfileDebugInfo(this.appProfile.Source, this.appProfile.ID)\n      .subscribe(async (data) => {\n        console.log(data);\n        // Copy to clip-board if supported\n        await this.integration.writeToClipboard(data);\n        this.actionIndicator.success('Copied to Clipboard');\n      });\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe();\n  }\n\n  /**\n   * @private\n   * Delete the current profile. Requires a two-step confirmation.\n   */\n  deleteProfile() {\n    if (!this.appProfile) {\n      return;\n    }\n\n    this.dialog\n      .confirm({\n        canCancel: true,\n        caption: 'Caution',\n        header: 'Deleting Profile ' + this.appProfile.Name,\n        message:\n          'Do you really want to delete this profile? All settings will be lost.',\n        buttons: [\n          { id: '', text: 'Cancel', class: 'outline' },\n          { id: 'delete', class: 'danger', text: 'Yes, delete it' },\n        ],\n      })\n      .onAction('delete', () => {\n        this.profileService.deleteProfile(this.appProfile!).subscribe(() => {\n          this.router.navigate(['/app/overview']);\n          this.actionIndicator.success(\n            'Profile Deleted',\n            'Successfully deleted profile ' + this.appProfile?.Name\n          );\n        });\n      });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/index.ts",
    "content": "export { AppViewComponent } from './app-view';\nexport { AppOverviewComponent } from './overview';\nexport { QuickSettingInternetButtonComponent } from './qs-internet';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/merge-profile-dialog/merge-profile-dialog.component.html",
    "content": "<header class=\"flex flex-row items-center justify-between mb-2\">\n  <h1 class=\"text-sm font-light m-0\">\n    Merge Profiles\n  </h1>\n\n  <svg role=\"img\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\" class=\"w-3 h-3 text-secondary hover:text-primary cursor-pointer\" (click)=\"dialogRef.close()\">\n    <path fill=\"currentColor\" d=\"M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z\"></path>\n  </svg>\n</header>\n\n<span class=\"py-2 text-secondary text-xxs\">\n  Please select the primary profile. All other selected profiles will be merged into the primary profile by copying metadata, fingerprints and icons into a new profile.\n  Only the settings of the primary profile will be kept.\n</span>\n\n<div class=\"flex flex-row gap-2 justify-between border-b border-gray-500 p-2 items-center\">\n  <label class=\"text-primary text-xxs relative\">Primary Profile:</label>\n  <sfng-select [(ngModel)]=\"primary\" (ngModelChange)=\"newName = newName || primary?.Name || ''\" class=\"border border-gray-500\">\n    <ng-container *ngFor=\"let p of profiles; trackBy: trackProfile\">\n      <sfng-select-item *sfngSelectValue=\"p; label:p.Name\" class=\"flex flex-row items-center gap-2\">\n        <app-icon [profile]=\"p\"></app-icon>\n        {{ p.Name }}\n      </sfng-select-item>\n    </ng-container>\n  </sfng-select>\n</div>\n\n<div class=\"flex flex-row gap-2 justify-between items-center p-2\">\n  <label class=\"text-primary text-xxs relative\">Name for the new Profile</label>\n  <input type=\"text\" [(ngModel)]=\"newName\" placeholder=\"New Profile Name\" class=\"!border !border-gray-500 flex-grow\">\n</div>\n\n<div class=\"flex flex-row justify-end gap-2\">\n  <button (click)=\"dialogRef.close()\">Cancel</button>\n  <button class=\"bg-blue text-white\" (click)=\"mergeProfiles()\" [disabled]=\"!primary || !newName\">Merge</button>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/merge-profile-dialog/merge-profile-dialog.component.ts",
    "content": "import { AppProfile } from './../../../../../dist-lib/safing/portmaster-api/lib/app-profile.types.d';\nimport { ChangeDetectionStrategy, Component, OnInit, TrackByFunction, inject } from \"@angular/core\";\nimport { Router } from '@angular/router';\nimport { PortapiService } from '@safing/portmaster-api';\nimport { SFNG_DIALOG_REF, SfngDialogRef } from \"@safing/ui\";\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\n\n@Component({\n  templateUrl: './merge-profile-dialog.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styles: [\n    `\n    :host {\n      @apply flex flex-col gap-2 justify-start h-96 w-96;\n    }\n    `\n  ]\n})\nexport class MergeProfileDialogComponent implements OnInit {\n  readonly dialogRef: SfngDialogRef<MergeProfileDialogComponent, unknown, AppProfile[]> = inject(SFNG_DIALOG_REF);\n  private readonly portapi = inject(PortapiService);\n  private readonly router = inject(Router);\n  private readonly uai = inject(ActionIndicatorService);\n\n  get profiles(): AppProfile[] {\n    return this.dialogRef.data;\n  }\n\n  primary: AppProfile | null = null;\n  newName = '';\n\n  trackProfile: TrackByFunction<AppProfile> = (_, p) => `${p.Source}/${p.ID}`\n\n  ngOnInit(): void {\n    (() => { });\n  }\n\n  mergeProfiles() {\n    if (!this.primary) {\n      return\n    }\n\n    this.portapi.mergeProfiles(\n      this.newName,\n      `${this.primary.Source}/${this.primary.ID}`,\n      this.profiles\n        .filter(p => p !== this.primary)\n        .map(p => `${p.Source}/${p.ID}`)\n    )\n      .subscribe({\n        next: newID => {\n          this.router.navigate(['/app/' + newID])\n          this.uai.success('Profiles Merged Successfully', 'All selected profiles have been merged')\n\n          this.dialogRef.close()\n        },\n        error: err => {\n          this.uai.error('Failed To Merge Profiles', this.uai.getErrorMessgae(err))\n        }\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/overview.html",
    "content": "<div class=\"flex flex-row justify-between items-center mb-4\">\n  <input\n    type=\"text\"\n    placeholder=\"Search\"\n    [ngModel]=\"searchTerm\"\n    (ngModelChange)=\"searchApps($event)\"\n    [autoFocus]=\"true\"\n  />\n  <app-expertise></app-expertise>\n</div>\n\n<div class=\"header-title\">\n  <h1>\n    All Apps\n    <sfng-tipup key=\"appsTitle\"></sfng-tipup>\n  </h1>\n  <div class=\"flex-grow\"></div>\n\n  <app-menu #profileMenu>\n    <app-menu-item (click)=\"createProfile()\">Create profile</app-menu-item>\n    <app-menu-item (click)=\"importProfile()\">Import Profile</app-menu-item>\n    <app-menu-item (click)=\"selectMode = true\"\n      >Merge or Delete profiles</app-menu-item\n    >\n  </app-menu>\n\n  <div class=\"flex flex-row gap-2 items-center\">\n    <app-menu-trigger\n      *ngIf=\"!selectMode\"\n      [menu]=\"profileMenu\"\n      useContent=\"true\"\n    >\n      <div class=\"flex flex-row gap-2 items-center text-xs font-light\">\n        Manage\n\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          fill=\"none\"\n          viewBox=\"0 0 24 24\"\n          stroke-width=\"1.5\"\n          stroke=\"currentColor\"\n          class=\"w-3 h-3\"\n        >\n          <path\n            stroke-linecap=\"round\"\n            stroke-linejoin=\"round\"\n            d=\"M11.42 15.17L17.25 21A2.652 2.652 0 0021 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 11-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 004.486-6.336l-3.276 3.277a3.004 3.004 0 01-2.25-2.25l3.276-3.276a4.5 4.5 0 00-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437l1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008z\"\n          />\n        </svg>\n      </div>\n    </app-menu-trigger>\n\n    <ng-container *ngIf=\"selectMode\">\n      <app-menu #selectionMenu>\n        <app-menu-item (click)=\"openMergeDialog()\"\n          >Merge Profiles</app-menu-item\n        >\n        <app-menu-item (click)=\"deleteSelectedProfiles()\"\n          >Delete Profiles</app-menu-item\n        >\n        <app-menu-item (click)=\"selectMode = false\">Cancel</app-menu-item>\n      </app-menu>\n\n      <app-menu-trigger [menu]=\"selectionMenu\" useContent=\"true\">\n        <div class=\"flex flex-row gap-2 items-center text-xs font-light\">\n          {{ selectedProfileCount}} selected\n\n          <svg\n            xmlns=\"http://www.w3.org/2000/svg\"\n            fill=\"none\"\n            viewBox=\"0 0 24 24\"\n            stroke-width=\"1.5\"\n            stroke=\"currentColor\"\n            class=\"w-3 h-3\"\n          >\n            <path\n              stroke-linecap=\"round\"\n              stroke-linejoin=\"round\"\n              d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"\n            />\n          </svg>\n        </div>\n      </app-menu-trigger>\n    </ng-container>\n  </div>\n</div>\n\n<div class=\"scrollable\" [@fadeInList]=\"total\">\n  <ng-container *ngIf=\"runningProfiles.length > 0\">\n    <div class=\"scrollable-header\">\n      <h4>Active</h4>\n    </div>\n    <ng-container\n      *ngTemplateOutlet=\"profileList; context: {$implicit: runningProfiles}\"\n    ></ng-container>\n  </ng-container>\n\n  <ng-container *ngIf=\"recentlyEdited.length > 0\">\n    <div class=\"scrollable-header\">\n      <h4>Recently Edited</h4>\n    </div>\n    <ng-container\n      *ngTemplateOutlet=\"profileList; context: {$implicit: recentlyEdited}\"\n    ></ng-container>\n  </ng-container>\n\n  <ng-container *ngIf=\"profiles.length > 0\">\n    <div class=\"scrollable-header\">\n      <h4>All</h4>\n    </div>\n    <ng-container\n      *ngTemplateOutlet=\"profileList; context: {$implicit: profiles}\"\n    ></ng-container>\n  </ng-container>\n\n  <ng-template #profileList let-list>\n    <ng-container *ngFor=\"let profile of list; trackBy: trackProfile\">\n      <div\n        *appExpertiseLevel=\"profile.Internal ? 'developer' : 'user'\"\n        class=\"relative card-header\"\n        [ngClass]=\"{'ring-1 ring-inset ring-yellow-300': profile.selected}\"\n        (click)=\"handleProfileClick(profile, $event)\"\n        [routerLink]=\"selectMode ? null : ['/app', profile.Source,  profile.ID]\"\n      >\n        <app-icon [profile]=\"profile\"></app-icon>\n\n        <span class=\"card-title\">\n          <span [innerHTML]=\"profile?.Name | safe:'html'\"></span>\n          <span\n            class=\"card-sub-title\"\n            *appExpertiseLevel=\"'expert'\"\n            [innerHTML]=\"profile?.PresentationPath | safe:'html'\"\n          ></span>\n        </span>\n\n        <input\n          type=\"checkbox\"\n          *ngIf=\"selectMode\"\n          [(ngModel)]=\"profile.selected\"\n          (click)=\"$event.stopPropagation()\"\n        />\n\n        <span\n          *ngIf=\"profile.hasConfigChanges\"\n          sfng-tooltip=\"Settings Edited\"\n          class=\"absolute top-1 right-1 w-2 h-2 rounded-full bg-blue\"\n        ></span>\n      </div>\n    </ng-container>\n\n    <ng-container *ngIf=\"loading\">\n      <div class=\"card-header\">\n        <fa-icon class=\"card-icon loading\" icon=\"square\"></fa-icon>\n        <app-text-placeholder\n          mode=\"input\"\n          width=\"small\"\n          class=\"card-title\"\n        ></app-text-placeholder>\n      </div>\n      <div class=\"card-header\">\n        <fa-icon class=\"card-icon loading\" icon=\"square\"></fa-icon>\n        <app-text-placeholder\n          mode=\"input\"\n          width=\"small\"\n          class=\"card-title\"\n        ></app-text-placeholder>\n      </div>\n      <div class=\"card-header\">\n        <fa-icon class=\"card-icon loading\" icon=\"square\"></fa-icon>\n        <app-text-placeholder\n          mode=\"input\"\n          width=\"7rem\"\n          class=\"card-title\"\n        ></app-text-placeholder>\n      </div>\n      <div class=\"card-header\">\n        <fa-icon class=\"card-icon loading\" icon=\"square\"></fa-icon>\n        <app-text-placeholder\n          mode=\"input\"\n          width=\"3rem\"\n          class=\"card-title\"\n        ></app-text-placeholder>\n      </div>\n    </ng-container>\n  </ng-template>\n</div>\n\n<div\n  *ngIf=\"total === 0 && searchTerm !== ''\"\n  class=\"flex justify-center items-center p-2 bg-gray-200 text-secondary\"\n>\n  No applications match your search term.\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/overview.scss",
    "content": ":host {\n  justify-content: flex-start;\n}\n\n.header-title {\n  display: flex;\n  width: 100%;\n  margin-bottom: 0.5rem;\n  align-items: center;\n  height: 3rem;\n  flex-shrink: 0;\n\n  h1 {\n    flex-grow: unset;\n  }\n\n  fa-icon[icon*=\"question-circle\"] {\n    margin-left: 0.35rem;\n  }\n}\n\n.scrollable {\n  width: auto;\n  flex-grow: 0;\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n  gap: 1rem;\n}\n\n\n.scrollable-header {\n\n  @apply bg-background;\n  @apply pt-4;\n  @apply pb-1;\n  width: 100%;\n  position: sticky;\n  top: 0px;\n  display: flex;\n\n  grid-column: 1 / -1;\n\n  fa-icon[icon*=\"question-circle\"] {\n    margin-left: 0.35rem;\n  }\n}\n\n\n.card-header {\n  // Card headers have top-margin by default.\n  // Since we're using a grid-gap anyway we need\n  // to clear the margin.\n  @apply mt-0;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/overview.ts",
    "content": "import {\n  ChangeDetectorRef,\n  Component,\n  OnDestroy,\n  OnInit,\n  TrackByFunction,\n} from '@angular/core';\nimport {\n  AppProfile,\n  AppProfileService,\n  Netquery,\n  trackById,\n} from '@safing/portmaster-api';\nimport { SfngDialogService } from '@safing/ui';\nimport { BehaviorSubject, Subscription, combineLatest, forkJoin } from 'rxjs';\nimport { debounceTime, filter, startWith } from 'rxjs/operators';\nimport {\n  fadeInAnimation,\n  fadeInListAnimation,\n  moveInOutListAnimation,\n} from 'src/app/shared/animations';\nimport { FuzzySearchService } from 'src/app/shared/fuzzySearch';\nimport { EditProfileDialog } from './../../shared/edit-profile-dialog/edit-profile-dialog';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { MergeProfileDialogComponent } from './merge-profile-dialog/merge-profile-dialog.component';\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\nimport { Router } from '@angular/router';\nimport {\n  ImportConfig,\n  ImportDialogComponent,\n} from 'src/app/shared/config/import-dialog/import-dialog.component';\n\ninterface LocalAppProfile extends AppProfile {\n  hasConfigChanges: boolean;\n  selected: boolean;\n}\n\n@Component({\n  selector: 'app-settings-overview',\n  templateUrl: './overview.html',\n  styleUrls: ['../page.scss', './overview.scss'],\n  animations: [fadeInAnimation, fadeInListAnimation, moveInOutListAnimation],\n})\nexport class AppOverviewComponent implements OnInit, OnDestroy {\n  private subscription = Subscription.EMPTY;\n\n  /** Whether or not we are currently loading */\n  loading = true;\n\n  /** All application profiles that are actually running */\n  runningProfiles: LocalAppProfile[] = [];\n\n  /** All application profiles that have been edited recently */\n  recentlyEdited: LocalAppProfile[] = [];\n\n  /** All application profiles */\n  profiles: LocalAppProfile[] = [];\n\n  /** The current search term */\n  searchTerm: string = '';\n\n  /** total number of profiles */\n  total: number = 0;\n\n  /** Whether or not we are in profile-selection mode */\n  set selectMode(v: any) {\n    this._selectMode = coerceBooleanProperty(v);\n\n    // reset all previous profile selections\n    if (!this._selectMode) {\n      this.profiles.forEach((profile) => (profile.selected = false));\n    }\n  }\n  get selectMode() {\n    return this._selectMode;\n  }\n  private _selectMode = false;\n\n  get selectedProfileCount() {\n    return this.profiles.reduce(\n      (sum, profile) => (profile.selected ? sum + 1 : sum),\n      0\n    );\n  }\n\n  /** Observable emitting the search term */\n  private onSearch = new BehaviorSubject('');\n\n  /** TrackBy function for the profiles. */\n  trackProfile: TrackByFunction<LocalAppProfile> = trackById;\n\n  constructor(\n    private profileService: AppProfileService,\n    private changeDetector: ChangeDetectorRef,\n    private searchService: FuzzySearchService,\n    private netquery: Netquery,\n    private dialog: SfngDialogService,\n    private actionIndicator: ActionIndicatorService,\n    private router: Router\n  ) { }\n\n  handleProfileClick(profile: LocalAppProfile, event: MouseEvent) {\n    if (event.shiftKey) {\n      // stay on the same page as clicking the app actually triggers\n      // a navigation before this handler is executed.\n      this.router.navigate(['/app/overview']);\n\n      this.selectMode = true;\n\n      event.preventDefault();\n      event.stopImmediatePropagation();\n      event.stopPropagation();\n    }\n\n    if (this.selectMode) {\n      profile.selected = !profile.selected;\n    }\n\n    if (event.shiftKey && this.selectedProfileCount === 0) {\n      this.selectMode = false;\n    }\n  }\n\n  importProfile() {\n    const importConfig: ImportConfig = {\n      type: 'profile',\n      key: '',\n    };\n\n    this.dialog.create(ImportDialogComponent, {\n      data: importConfig,\n      autoclose: false,\n      backdrop: 'light',\n    });\n  }\n\n  stripHtmlTags(text: string): string {\n    if (!text) return '';  \n    // Only strip if we have proper HTML tags (opening and closing with same tag name)\n    return text.replace(/<([a-zA-Z][a-zA-Z0-9]*)[^>]*>([^<]*)<\\/\\1>/g, '$2');\n  }\n\n  openMergeDialog() {\n    this.dialog.create(MergeProfileDialogComponent, {\n      autoclose: true,\n      backdrop: 'light',\n      data: this.profiles.filter((p) => p.selected)\n      .map((p) => ({\n        ...p,\n        // Strip HTML tags from Name if it exists (e.g., highlighted search results)\n        ...(p.Name ? { Name: this.stripHtmlTags(p.Name) } : {})\n      })), \n    });\n\n    this.selectMode = false;\n  }\n\n  deleteSelectedProfiles() {\n    this.dialog\n      .confirm({\n        header: 'Confirm Profile Deletion',\n        message: `Are you sure you want to delete all ${this.selectedProfileCount} selected profiles?`,\n        caption: 'Attention',\n        buttons: [\n          {\n            id: 'no',\n            text: 'Cancel',\n            class: 'outline',\n          },\n          {\n            id: 'yes',\n            text: 'Delete',\n            class: 'danger',\n          },\n        ],\n      })\n      .onAction('yes', () => {\n        forkJoin(\n          this.profiles\n            .filter((profile) => profile.selected)\n            .map((p) => this.profileService.deleteProfile(p))\n        ).subscribe({\n          next: () => {\n            this.actionIndicator.success(\n              'Selected Profiles Delete',\n              'All selected profiles have been deleted'\n            );\n          },\n          error: (err) => {\n            this.actionIndicator.error(\n              'Failed To Delete Profiles',\n              `An error occured while deleting some profiles: ${this.actionIndicator.getErrorMessgae(\n                err\n              )}`\n            );\n          },\n        });\n      })\n      .onClose.subscribe(() => (this.selectMode = false));\n  }\n\n  ngOnInit() {\n    // watch all profiles and re-emit (debounced) when the user\n    // enters or chanages the search-text.\n    this.subscription = combineLatest([\n      this.profileService.watchProfiles(),\n      this.onSearch.pipe(debounceTime(100), startWith('')),\n      this.netquery.getActiveProfileIDs().pipe(startWith([] as string[])),\n    ]).subscribe(([profiles, searchTerm, activeProfiles]) => {\n      this.loading = false;\n\n      // find all profiles that match the search term. For searchTerm=\"\" thsi\n      // will return all profiles.\n      const filtered = this.searchService.searchList(profiles, searchTerm, {\n        ignoreLocation: true,\n        ignoreFieldNorm: true,\n        threshold: 0.1,\n        minMatchCharLength: 3,\n        keys: ['Name', 'PresentationPath'],\n      });\n\n      // create a lookup map of all profiles we already loaded so we don't loose\n      // selection state when a profile has been updated.\n      const oldProfiles = new Map<string, LocalAppProfile>(\n        this.profiles.map((profile) => [\n          `${profile.Source}/${profile.ID}`,\n          profile,\n        ])\n      );\n\n      // Prepare new, empty lists for our groups\n      this.profiles = [];\n      this.runningProfiles = [];\n      this.recentlyEdited = [];\n\n      // calcualte the threshold for \"recently-used\" (1 week).\n      const recentlyUsedThreshold =\n        new Date().valueOf() / 1000 - 60 * 60 * 24 * 7;\n\n      // flatten the filtered profiles, sort them by name and group them into\n      // our \"app-groups\" (active, recentlyUsed, others)\n      this.total = filtered.length;\n      filtered\n        .map((item) => item.item)\n        .sort((a, b) => {\n          const aName = a.Name.toLocaleLowerCase();\n          const bName = b.Name.toLocaleLowerCase();\n\n          if (aName > bName) {\n            return 1;\n          }\n\n          if (aName < bName) {\n            return -1;\n          }\n\n          return 0;\n        })\n        .forEach((profile) => {\n          const local: LocalAppProfile = {\n            ...profile,\n            hasConfigChanges:\n              profile.LastEdited > 0 && Object.keys(profile.Config || {}).length > 0,\n            selected:\n              oldProfiles.get(`${profile.Source}/${profile.ID}`)?.selected ||\n              false,\n          };\n\n          if (activeProfiles.includes(profile.Source + '/' + profile.ID)) {\n            this.runningProfiles.push(local);\n          } else if (profile.LastEdited >= recentlyUsedThreshold) {\n            this.recentlyEdited.push(local);\n          }\n\n          // we always add the profile to \"All Apps\"\n          this.profiles.push(local);\n        });\n\n      this.changeDetector.markForCheck();\n    });\n  }\n\n  /**\n   * @private\n   *\n   * Used as an ngModelChange callback on the search-input.\n   *\n   * @param term The search term entered by the user\n   */\n  searchApps(term: string) {\n    this.searchTerm = term;\n    this.onSearch.next(term);\n  }\n\n  /**\n   * @private\n   *\n   * Opens the create profile dialog\n   */\n  createProfile() {\n    const ref = this.dialog.create(EditProfileDialog, {\n      backdrop: true,\n      autoclose: false,\n    });\n\n    ref.onClose.pipe(filter((action) => action === 'saved')).subscribe(() => {\n      // reset the search and reload to make sure the new\n      // profile shows up\n      this.searchApps('');\n    });\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-history/qs-history.component.html",
    "content": "<div class=\"relative flex flex-wrap items-center justify-center w-full h-full gap-2 px-3 py-2 bg-gray-300 border border-gray-300 rounded shadow\">\n  <span class=\"text-primary\">\n    Keep History\n  </span>\n\n  <span *ngIf=\"!canUse\" routerLink=\"/dashboard\" class=\"cursor-pointer text-tertiary hover:underline\">\n    Get Plus\n  </span>\n\n  <sfng-toggle *ngIf=\"canUse\" [ngModel]=\"currentValue\" (ngModelChange)=\"updateHistoryEnabled($event)\"\n    [disabled]=\"(historyFeatureAllowed | async) === false\"></sfng-toggle>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-history/qs-history.component.scss",
    "content": ""
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-history/qs-history.component.ts",
    "content": "import {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  inject,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n  BoolSetting,\n  FeatureID,\n  SPNService,\n  Setting,\n  getActualValue,\n} from '@safing/portmaster-api';\nimport { BehaviorSubject, Observable, map } from 'rxjs';\nimport { share } from 'rxjs/operators';\nimport { SaveSettingEvent } from 'src/app/shared/config';\n\n@Component({\n  selector: 'app-qs-history',\n  templateUrl: './qs-history.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class QsHistoryComponent implements OnChanges {\n  currentValue = false;\n  historyFeatureAllowed: Observable<boolean> = inject(SPNService).profile$.pipe(\n    takeUntilDestroyed(),\n    map((profile) => {\n      return (\n        profile?.current_plan?.feature_ids?.includes(FeatureID.History) || false\n      );\n    }),\n    share({ connector: () => new BehaviorSubject<boolean>(false) })\n  );\n\n  @Input()\n  canUse: boolean = true;\n\n  @Input()\n  settings: Setting[] = [];\n\n  @Output()\n  save = new EventEmitter<SaveSettingEvent<any>>();\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if ('settings' in changes) {\n      const historySetting = this.settings.find(\n        (s) => s.Key === 'history/enable'\n      ) as BoolSetting | undefined;\n      if (historySetting) {\n        this.currentValue = getActualValue(historySetting);\n      }\n    }\n  }\n\n  updateHistoryEnabled(enabled: boolean) {\n    this.save.next({\n      isDefault: false,\n      key: 'history/enable',\n      value: enabled,\n    });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-internet/index.ts",
    "content": "export * from './qs-internet';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-internet/qs-internet.html",
    "content": "<div\n  class=\"relative flex flex-wrap items-center justify-center w-full h-full gap-2 px-3 py-2 bg-gray-300 border border-gray-300 rounded shadow\"\n  snfgTooltipPosition=\"right\" [sfng-tooltip]=\"interferingSettings.length > 0 ? tooltipTemplate : null\">\n  <span class=\"text-primary\" [class.cursor-pointer]=\"interferingSettings.length > 0\">\n    Block Connections\n  </span>\n\n  <sfng-toggle *ngIf=\"currentValue !== 'ask'; else: promptingTemplate\" [ngModel]=\"currentValue === 'block'\"\n    (ngModelChange)=\"updateUseInternet($event)\"></sfng-toggle>\n\n  <span class=\"absolute right-0 block w-2 h-2 bg-yellow-300 border border-gray-100 rounded opacity-75\"\n    style=\"top: 2px; transform: translateX(-2px)\" *ngIf=\"interferingSettings.length > 0\"></span>\n\n  <ng-template #promptingTemplate>\n    <span class=\"mr-2 outline-none cursor-pointer text-secondary hover:underline\" [routerLink]=\"[]\"\n      [queryParams]=\"{setting: 'filter/defaultAction', tab: 'settings'}\">Prompting</span>\n  </ng-template>\n</div>\n\n<ng-template #tooltipTemplate>\n  The following enabled settings may interfere:\n  <ul class=\"pl-4 list-disc\">\n    <ng-container *ngFor=\"let setting of interferingSettings\">\n      <li class=\"cursor-pointer hover:underline\" [routerLink]=\"[]\"\n        [queryParams]=\"{setting: setting.Key, tab: 'settings'}\">\n        {{ setting.Name }}\n      </li>\n    </ng-container>\n  </ul>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-internet/qs-internet.ts",
    "content": "import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from \"@angular/core\";\nimport { Setting, StringSetting, getActualValue } from \"@safing/portmaster-api\";\nimport { SaveSettingEvent } from \"src/app/shared/config/generic-setting/generic-setting\";\n\nconst interferingSettings = {\n  'permit': [\n    'filter/blockInternet',\n    'filter/blockLAN',\n    'filter/blockLocal',\n    'filter/blockP2P',\n    'filter/blockInbound',\n    'filter/endpoints',\n  ],\n  'block': [\n    'filter/endpoints',\n  ],\n}\n\n@Component({\n  selector: 'app-qs-internet',\n  templateUrl: './qs-internet.html',\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class QuickSettingInternetButtonComponent implements OnChanges {\n  @Input()\n  settings: Setting[] = [];\n\n  @Output()\n  save = new EventEmitter<SaveSettingEvent>();\n\n  currentValue = ''\n\n  interferingSettings: Setting[] = [];\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if ('settings' in changes) {\n      this.currentValue = '';\n      const defaultActionSetting = this.settings.find(s => s.Key == 'filter/defaultAction') as (StringSetting | undefined);\n      if (!!defaultActionSetting) {\n        this.currentValue = getActualValue(defaultActionSetting);\n        this.updateInterfering();\n      }\n    }\n  }\n\n  updateUseInternet(blocked: boolean) {\n    const newValue = blocked ? 'block' : 'permit';\n    this.save.next({\n      isDefault: false,\n      key: 'filter/defaultAction',\n      value: newValue,\n    })\n  }\n\n  private updateInterfering() {\n    this.interferingSettings = [];\n    if (this.currentValue !== 'permit' && this.currentValue !== 'block') {\n      return;\n    }\n\n    // create a lookup map for setting key to setting\n    const lm = new Map<string, Setting>();\n    this.settings.forEach(s => lm.set(s.Key, s))\n\n    this.interferingSettings = interferingSettings[this.currentValue]\n      .map(key => lm.get(key))\n      .filter(setting => {\n        if (!setting) {\n          return false;\n        }\n        const value = getActualValue(setting);\n        if (Array.isArray(value)) {\n          return value.length > 0;\n        }\n\n        return !!value;\n      }) as Setting[];\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-select-exit/index.ts",
    "content": "export * from './qs-select-exit';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-select-exit/qs-select-exit.html",
    "content": "<div class=\"qs-select-exit relative flex flex-wrap items-center justify-center w-full h-full gap-2 px-3 py-1 bg-gray-300 border border-gray-300 rounded shadow\">\n  <span class=\"text-primary\">\n    SPN Exit\n  </span>\n\n  <span *ngIf=\"!canUse\" routerLink=\"/dashboard\" class=\"cursor-pointer text-tertiary hover:underline\">\n    Get Pro\n  </span>\n\n  <sfng-select *ngIf=\"canUse && spnEnabled === true && exitRuleSetting\"\n    [ngModel]=\"selectedExitRules\" (ngModelChange)=\"updateExitRules($event)\" placeholder=\"Custom\"\n    class=\"\">\n    <sfng-select-item *sfngSelectValue=\"\">\n      Automatic\n    </sfng-select-item>\n    <ng-container *ngFor=\"let option of availableExitRules\">\n      <sfng-select-item *sfngSelectValue=\"option.Value.join(',')\">\n        <span *ngIf=\"option.FlagID\" [appCountryFlags]=\"option.FlagID\"></span>\n        <span *ngIf=\"!option.FlagID\" class=\"text-tertiary\">\n          <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-globe\" viewBox=\"0 0 16 16\">\n            <path d=\"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855.173-.324.33-.682.468-1.068H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z\"/>\n          </svg>\n        </span>\n        {{ option.Name }}\n      </sfng-select-item>\n    </ng-container>\n  </sfng-select>\n\n  <ng-template *ngIf=\"canUse && spnEnabled === true && exitRuleSetting === null\">\n    <fa-icon icon=\"spinner\" [spin]=\"true\"></fa-icon>\n  </ng-template>\n\n  <span *ngIf=\"canUse && spnEnabled === false\"\n    routerLink=\"/spn\" class=\"cursor-pointer text-tertiary hover:underline\"\n    sfng-tooltip=\"Enable SPN to start using.\">\n      Disabled\n  </span>\n\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-select-exit/qs-select-exit.scss",
    "content": ""
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-select-exit/qs-select-exit.ts",
    "content": "import {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  inject,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n  BoolSetting,\n  StringArraySetting,\n  CountrySelectionQuickSetting,\n  ConfigService,\n  Setting,\n  getActualValue,\n} from '@safing/portmaster-api';\nimport { SaveSettingEvent } from 'src/app/shared/config/generic-setting/generic-setting';\n\n@Component({\n  selector: 'app-qs-select-exit',\n  templateUrl: './qs-select-exit.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class QuickSettingSelectExitButtonComponent\n  implements OnInit, OnChanges\n{\n  private destroyRef = inject(DestroyRef);\n\n  @Input()\n  canUse: boolean = true;\n\n  @Input()\n  settings: Setting[] = [];\n\n  @Output()\n  save = new EventEmitter<SaveSettingEvent>();\n\n  spnEnabled: boolean | null = null;\n  exitRuleSetting: StringArraySetting | null = null;\n\n  selectedExitRules: string | undefined = undefined;\n  availableExitRules: CountrySelectionQuickSetting<string[]>[] | null = null;\n\n  constructor(\n    private configService: ConfigService,\n    private cdr: ChangeDetectorRef\n  ) {}\n\n  updateExitRules(newExitRules: string) {\n    this.selectedExitRules = newExitRules;\n\n    let newConfigValue: string[] = [];\n    if (!!newExitRules) {\n      newConfigValue = newExitRules.split(',');\n    }\n\n    this.save.next({\n      isDefault: false,\n      key: 'spn/exitHubPolicy',\n      value: newConfigValue,\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if ('settings' in changes) {\n      this.exitRuleSetting = null;\n      this.selectedExitRules = undefined;\n\n      const exitRuleSetting = this.settings.find(\n        (s) => s.Key == 'spn/exitHubPolicy'\n      ) as StringArraySetting | undefined;\n      if (exitRuleSetting) {\n        this.exitRuleSetting = exitRuleSetting;\n        this.updateOptions();\n      }\n    }\n  }\n\n  ngOnInit() {\n    this.configService\n      .watch<BoolSetting>('spn/enable')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe((value) => {\n        this.spnEnabled = value;\n        this.updateOptions();\n      });\n  }\n\n  private updateOptions() {\n    if (!this.exitRuleSetting) {\n      this.selectedExitRules = undefined;\n      this.availableExitRules = null;\n      return;\n    }\n\n    if (!!this.exitRuleSetting.Value && this.exitRuleSetting.Value.length > 0) {\n      this.selectedExitRules = this.exitRuleSetting.Value.join(',');\n    }\n    this.availableExitRules = this.getQuickSettings();\n\n    this.cdr.markForCheck();\n  }\n\n  private getQuickSettings(): CountrySelectionQuickSetting<string[]>[] {\n    if (!this.exitRuleSetting) {\n      return [];\n    }\n\n    let val = this.exitRuleSetting.Annotations[\n      'safing/portbase:ui:quick-setting'\n    ] as CountrySelectionQuickSetting<string[]>[];\n    if (val === undefined) {\n      return [];\n    }\n\n    if (!Array.isArray(val)) {\n      return [];\n    }\n\n    return val;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-use-spn/index.ts",
    "content": "export * from './qs-use-spn';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-use-spn/qs-use-spn.html",
    "content": "<div\n  class=\"relative flex flex-wrap items-center justify-center w-full h-full gap-2 px-3 py-2 bg-gray-300 border border-gray-300 rounded shadow\"\n  snfgTooltipPosition=\"right\"\n  [sfng-tooltip]=\"interferingSettings.length > 0 ? tooltipTemplate : null\">\n  <span class=\"text-primary\" [class.cursor-pointer]=\"interferingSettings.length > 0\">\n    Use SPN\n  </span>\n\n  <span *ngIf=\"!canUse\" routerLink=\"/dashboard\" class=\"cursor-pointer text-tertiary hover:underline\">\n    Get Pro\n  </span>\n\n  <sfng-toggle *ngIf=\"canUse && spnDisabled === false\"\n    [ngModel]=\"currentValue\" (ngModelChange)=\"updateUseSpn($event)\">\n  </sfng-toggle>\n\n  <span *ngIf=\"canUse && spnDisabled === true\"\n    routerLink=\"/spn\" class=\"cursor-pointer text-tertiary hover:underline\"\n    sfng-tooltip=\"Enable SPN to start using.\">\n      Disabled\n  </span>\n\n  <ng-template *ngIf=\"canUse && spnDisabled === null\">\n    <fa-icon icon=\"spinner\" [spin]=\"true\"></fa-icon>\n  </ng-template>\n\n  <span class=\"absolute right-0 block w-2 h-2 bg-yellow-300 border border-gray-100 rounded opacity-75\"\n    style=\"top: 2px; transform: translateX(-2px)\" *ngIf=\"interferingSettings.length > 0\"></span>\n\n</div>\n\n<ng-template #tooltipTemplate>\n  The following enabled settings may interfere:\n  <ul class=\"pl-4 list-disc\">\n    <ng-container *ngFor=\"let setting of interferingSettings\">\n      <li class=\"cursor-pointer hover:underline\" [routerLink]=\"[]\"\n        [queryParams]=\"{setting: setting.Key, tab: 'settings'}\">\n        {{ setting.Name }}\n      </li>\n    </ng-container>\n  </ul>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/app-view/qs-use-spn/qs-use-spn.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { BoolSetting, ConfigService, Setting, getActualValue } from \"@safing/portmaster-api\";\nimport { SaveSettingEvent } from \"src/app/shared/config/generic-setting/generic-setting\";\n\nconst interferingSettingsWhenOn = [\n  'spn/usagePolicy'\n]\n\n@Component({\n  selector: 'app-qs-use-spn',\n  templateUrl: './qs-use-spn.html',\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class QuickSettingUseSPNButtonComponent implements OnInit, OnChanges {\n  private destroyRef = inject(DestroyRef);\n\n  @Input()\n  canUse: boolean = true;\n\n  @Input()\n  settings: Setting[] = [];\n\n  @Output()\n  save = new EventEmitter<SaveSettingEvent>();\n\n  currentValue = false\n\n  interferingSettings: Setting[] = [];\n\n  /* Whether or not the SPN is currently disabled. null means we don't know yet ... */\n  spnDisabled: boolean | null = null;\n\n  constructor(\n    private configService: ConfigService,\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if ('settings' in changes) {\n      this.currentValue = false;\n\n      const useSpnSetting = this.settings.find(s => s.Key === 'spn/use') as (BoolSetting | undefined);\n      if (!!useSpnSetting) {\n        this.currentValue = getActualValue(useSpnSetting);\n        this.updateInterfering();\n      }\n    }\n  }\n\n  updateUseSpn(allowed: boolean) {\n    this.save.next({\n      isDefault: false,\n      key: 'spn/use',\n      value: allowed,\n    })\n  }\n\n  ngOnInit() {\n    this.configService.watch<BoolSetting>('spn/enable')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(value => {\n        this.spnDisabled = !value;\n        this.cdr.markForCheck();\n        this.updateInterfering();\n      })\n  }\n\n  private updateInterfering() {\n    this.interferingSettings = [];\n\n    // only \"enabled\" state has interfering settings\n    // only show if we already know if the SPN module is enabled\n    if (!this.currentValue || this.spnDisabled !== false) {\n      return\n    }\n\n    // create a lookup map for setting key to setting\n    const lm = new Map<string, Setting>();\n    this.settings.forEach(s => lm.set(s.Key, s))\n\n\n    this.interferingSettings = interferingSettingsWhenOn\n      .map(key => lm.get(key))\n      .filter(setting => {\n        if (!setting) {\n          return false;\n        }\n        const value = getActualValue(setting);\n        if (Array.isArray(value)) {\n          return value.length > 0;\n        }\n\n        return !!value;\n      }) as Setting[];\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/dashboard-widget/dashboard-widget.component.html",
    "content": "<label class=\"relative\" *ngIf=\"label\">\n  {{ label }}\n  <div *ngIf=\"beta\" class=\"absolute top-0 right-0 flex flex-col items-center justify-center gap-0 text-yellow-200\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"relative z-10 w-4 h-4\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M9.75 3.104v5.714a2.25 2.25 0 01-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 014.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0112 15a9.065 9.065 0 00-6.23-.693L5 14.5m14.8.8l1.402 1.402c1.232 1.232.65 3.318-1.067 3.611A48.309 48.309 0 0112 21c-2.773 0-5.491-.235-8.135-.687-1.718-.293-2.3-2.379-1.067-3.61L5 14.5\" />\n    </svg>\n    <span class=\"-mt-1 uppercase\" style=\"font-size: 0.6rem\">BETA</span>\n  </div>\n\n</label>\n\n<ng-content></ng-content>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/dashboard-widget/dashboard-widget.component.ts",
    "content": "import { coerceBooleanProperty } from \"@angular/cdk/coercion\";\nimport { ChangeDetectionStrategy, Component, Input } from \"@angular/core\";\n\n@Component({\n  selector: 'app-dashboard-widget',\n  templateUrl: './dashboard-widget.component.html',\n  styles: [\n    `\n      :host {\n        @apply bg-gray-200 p-4 self-stretch rounded-md flex flex-col gap-2;\n      }\n\n      label {\n        @apply text-xs uppercase text-secondary font-light flex flex-row items-center gap-2 pb-2;\n      }\n    `\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class DashboardWidgetComponent {\n  @Input()\n  set beta(v: any) {\n    this._beta = coerceBooleanProperty(v)\n  }\n  get beta() { return this._beta }\n  private _beta = false;\n\n  @Input()\n  label: string = '';\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/dashboard.component.html",
    "content": "<div class=\"w-full gap-4 p-4 dashboard-grid\">\n  <header class=\"flex flex-row items-center justify-between w-full\" id=\"header\">\n    <div class=\"flex flex-col flex-grow text-lg font-light text-white\">\n      <h1>\n        Dashboard\n        <sfng-tipup key=\"dashboardIntro\" placement=\"left\"></sfng-tipup>\n      </h1>\n\n      <span class=\"text-sm font-normal text-secondary\">\n        <ng-container *ngIf=\"!!profile; else: noUsername\">\n          Welcome back, <span class=\"text-primary\">{{ profile.username }}</span>!\n          <a *ngIf=\"profile?.state === '' && !!profile?.username\" class=\"text-xs underline cursor-pointer text-tertiary\"\n            (click)=\"logoutCompletely($event)\">Clear</a>\n        </ng-container>\n        <ng-template #noUsername>\n          Welcome back!\n        </ng-template>\n      </span>\n    </div>\n\n    <div class=\"flex flex-row gap-8\">\n      <div class=\"flex flex-col text-xs leading-4\">\n        <span class=\"font-light text-secondary\">\n          Your current plan is\n          <span class=\"font-normal text-primary\">\n            {{ profile?.current_plan?.name || 'Portmaster Free' }}\n          </span>\n        </span>\n\n        <span class=\"font-light text-secondary\" *ngIf=\"!profile?.subscription?.next_billing_date\">\n          and ends\n          <ng-container *ngIf=\"profile?.subscription?.ends_at; else: endsNever\">\n            in\n            <span class=\"font-normal text-primary\">\n              {{ profile?.subscription?.ends_at! | timeAgo }}\n            </span>\n          </ng-container>\n          <ng-template #endsNever>\n            never\n          </ng-template>\n        </span>\n        <span class=\"font-light text-secondary\" *ngIf=\"!!profile?.subscription?.next_billing_date\">\n          and auto-renews in <span class=\"font-normal text-primary\">\n            {{ profile?.subscription?.next_billing_date! | timeAgo }}\n          </span>\n        </span>\n      </div>\n\n      <ng-container *ngIf=\"!!profile && profile.state !== ''; else: loginButton\">\n        <button (click)=\"openAccountDetails()\"\n          class=\"text-sm font-normal text-white cursor-pointer btn bg-blue bg-opacity-80 hover:bg-opacity-100 hover:bg-blue\">\n          Account Details\n        </button>\n      </ng-container>\n      <ng-template #loginButton>\n        <button (click)=\"openAccountDetails()\"\n          class=\"text-sm font-normal text-white cursor-pointer btn bg-blue bg-opacity-80 hover:bg-opacity-100 hover:bg-blue\">\n          Login / Subscribe\n        </button>\n      </ng-template>\n    </div>\n  </header>\n\n\n  <app-dashboard-widget id=\"features\" label=\"Features\">\n    <div class=\"feature-card-list\">\n      <app-feature-card *ngFor=\"let feature of (features$ | async)\" [feature]=\"feature\" [disabled]=\"!feature.enabled\">\n      </app-feature-card>\n    </div>\n  </app-dashboard-widget>\n\n\n  <app-dashboard-widget id=\"stats\" label=\"Recent Activity\">\n    <!-- Mini Stats -->\n    <div class=\"mini-stats-list\">\n      <div class=\"mini-stat\" routerLink=\"/monitor\" [queryParams]=\"{q: 'verdict:3 verdict:4'}\">\n        <label routerLink=\"/monitor\" [queryParams]=\"{q: 'verdict:3 verdict:4'}\">Connections Blocked</label>\n        <span>{{ blockedConnections }}</span>\n      </div>\n\n      <div class=\"mini-stat\" routerLink=\"/monitor\" [queryParams]=\"{q: 'active:true'}\">\n        <label routerLink=\"/monitor\" [queryParams]=\"{q: 'active:true'}\">Active Connections</label>\n        <span>{{ activeConnections }}</span>\n      </div>\n\n      <div class=\"mini-stat\" routerLink=\"/monitor\" [queryParams]=\"{q: 'active:true groupby:profile'}\">\n        <label routerLink=\"/monitor\" [queryParams]=\"{q: 'active:true groupby:profile'}\">Active Apps</label>\n        <span>{{ activeProfiles }}</span>\n      </div>\n\n      <div class=\"mini-stat\">\n        <label>Data Received</label>\n        <span *ngIf=\"featureBw\">\n          {{ dataIncoming | bytes }}\n        </span>\n        <span *ngIf=\"!featureBw\"\n          class=\"!text-xxs !font-light !text-tertiary !text-opacity-50 w-full text-center !leading-3\">\n          Available in<br />Portmaster Plus\n        </span>\n      </div>\n\n      <div class=\"mini-stat\">\n        <label>Data Sent</label>\n        <span *ngIf=\"featureBw\">\n          {{ dataOutgoing | bytes }}\n        </span>\n        <span *ngIf=\"!featureBw\"\n          class=\"!text-xxs !font-light !text-tertiary !text-opacity-50 w-full text-center !leading-3\">\n          Available in<br />Portmaster Plus\n        </span>\n      </div>\n\n      <div class=\"mini-stat\" routerLink=\"/monitor\" [queryParams]=\"{q: 'tunneled:true groupby:exit_node'}\">\n        <label routerLink=\"/monitor\" [queryParams]=\"{q: 'tunneled:true groupby:exit_node'}\">SPN Identities</label>\n        <span *ngIf=\"featureSPN\">{{ activeIdentities }}</span>\n        <span *ngIf=\"!featureSPN\"\n          class=\"!text-xxs !font-light !text-tertiary !text-opacity-50 w-full text-center !leading-3\">\n          Available in<br />Portmaster Pro\n        </span>\n      </div>\n    </div>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget id=\"charts\">\n    <div class=\"mini-stats-list\">\n      <div class=\"mini-stat\">\n        <label routerLink=\"/monitor\">\n          Active/Blocked Connections\n        </label>\n        <sfng-netquery-line-chart activeConnectionColor=\"text-green-300 text-opacity-70\" class=\"w-full !h-36\"\n          [data]=\"connectionChart\"></sfng-netquery-line-chart>\n      </div>\n      <div class=\"mini-stat\" *ngIf=\"featureSPN\">\n        <label routerLink=\"/monitor\" [queryParams]=\"{q: 'tunneled:true'}\">\n          Connections Tunneled through SPN\n        </label>\n        <sfng-netquery-line-chart\n          [config]=\"{\n            series: {\n              value: {\n                lineColor: 'text-blue text-opacity-80',\n                areaColor: 'text-blue text-opacity-20',\n              }\n            }\n          }\"\n          class=\"w-full !h-36\"\n          [data]=\"tunneldConnectionChart\">\n        </sfng-netquery-line-chart>\n      </div>\n    </div>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget class=\"flex-grow\" id=\"countries\" label=\"Recent Connections per Country\">\n    <div class=\"block w-full\">\n      <ul class=\"list-none auto-grid-4\">\n        <li *ngFor=\"let country of (connectionsPerCountry | keyvalue); trackBy: trackCountry\"\n          [routerLink]=\"['/monitor']\" [queryParams]=\"{q: 'country:' + country.key}\"\n          (mouseenter)=\"onCountryHover(country.key)\" (mouseleave)=\"onCountryHover(null)\"\n          class=\"flex flex-row items-center p-2 bg-gray-300 rounded-md cursor-pointer hover:bg-gray-400\">\n          <div class=\"flex flex-row items-center flex-grow gap-2\">\n            <span class=\"flex-shrink-0\" *ngIf=\"!!country.key\" [appCountryFlags]=\"country.key\"></span>\n            <span\n              class=\"overflow-hidden text-xs text-secondary whitespace-nowrap\">{{ countryNames[country.key] || country.key || 'N/A' }}</span>\n          </div>\n          <span class=\"ml-2\">{{ country.value }}</span>\n        </li>\n      </ul>\n    </div>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget class=\"flex-grow\" id=\"blocked\" label=\"Recently Blocked Applications\">\n    <div class=\"block w-full h-full\">\n      <span *ngIf=\"!blockedProfiles?.length\"\n        class=\"flex flex-row items-center justify-center h-full gap-2 text-tertiary\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n          class=\"w-5 h-5\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n            d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\" />\n        </svg>\n\n        <span>\n          No applications have been blocked in the last 10 minutes.\n        </span>\n      </span>\n\n      <ul class=\"list-none auto-grid-3\">\n        <ng-container *ngFor=\"let entry of blockedProfiles; trackBy: trackApp\">\n          <li *ngIf=\"(entry.profileID | toAppProfile) as profile\" (mouseenter)=\"onProfileHover(entry.profileID)\"\n            (mouseleave)=\"onProfileHover(null)\" [routerLink]=\"['/app', profile.Source, profile.ID]\"\n            class=\"flex flex-row items-center p-2 bg-gray-300 rounded-md cursor-pointer hover:bg-gray-400\">\n            <div class=\"flex flex-row items-center flex-grow gap-2\">\n              <app-icon [profile]=\"profile\"></app-icon>\n              <span class=\"text-xs text-secondary\">{{ profile.Name }}</span>\n            </div>\n            {{ entry.count }}\n          </li>\n        </ng-container>\n      </ul>\n    </div>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget class=\"flex-grow\" id=\"connmap\" style=\"min-height: 400px\" label=\"Recent Connection Countries\" beta=\"true\">\n    <spn-map-renderer class=\"w-full h-full\" mapId=\"dashboard-map\"></spn-map-renderer>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget class=\"flex-grow\" id=\"bwvis-bar\" [ngStyle]=\"{minHeight: featureBw ? '400px' : 'unset'}\" label=\"Recent Top Consumers\" beta=\"true\">\n    <sfng-netquery-circular-bar-chart *ngIf=\"featureBw\" class=\"block w-full h-full\" [data]=\"bandwidthBarData\" [config]=\"bandwidthBarConfig\"></sfng-netquery-circular-bar-chart>\n\n    <span *ngIf=\"!featureBw\"\n      class=\"!text-xxs !font-light !text-tertiary !text-opacity-50 w-full text-center !leading-3\">\n      Available in Portmaster Plus\n    </span>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget class=\"flex-grow\" id=\"bwvis-line\" [ngStyle]=\"{minHeight: featureBw ? '400px' : 'unset'}\" label=\"Recent Bandwidth Usage\" beta=\"true\">\n    <sfng-netquery-line-chart class=\"block w-full h-full\" *ngIf=\"featureBw\" [data]=\"bandwidthLineChart\" [config]=\"bwChartConfig\"></sfng-netquery-line-chart>\n\n    <span *ngIf=\"!featureBw\"\n      class=\"!text-xxs !font-light !text-tertiary !text-opacity-50 w-full text-center !leading-3\">\n      Available in Portmaster Plus\n    </span>\n  </app-dashboard-widget>\n\n  <app-dashboard-widget class=\"flex-grow relative\" id=\"news\" label=\"News\">\n\n    <div class=\"flex flex-col items-center justify-center w-full h-full gap-2 font-light\" *ngIf=\"!news\">\n      <span>News is only available if intel data updates are enabled</span>\n      <button [routerLink]=\"['/settings']\" [queryParams]=\"{setting: 'core/automaticIntelUpdates'}\">Open Settings</button>\n    </div>\n\n    <div class=\"flex flex-col items-center justify-center w-full h-full gap-2 font-light\" *ngIf=\"news === 'pending'\">\n      <span>Just a second, we're loading the latest news...</span>\n    </div>\n\n    <ng-container *ngIf=\"!!news && news !== 'pending'\">\n      <sfng-tab-group linkRouter=\"false\" [customHeader]=\"true\" #carousel>\n        <sfng-tab *ngFor=\"let card of news?.cards\" [id]=\"card.title\" [title]=\"card.title\">\n          <section *sfngTabContent class=\"flex flex-col gap-2 p-2 h-full\" (mouseenter)=\"onCarouselTabHover(card)\" (mouseleave)=\"onCarouselTabHover(null)\">\n            <a [attr.href]=\"card.url\">\n              <h1 class=\"flex flex-row gap-2 items-center w-full ml-2 mr-2\">\n                {{ card.title }}\n                <svg *ngIf=\"card.url\" role=\"img\" aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" class=\"text-white text-opacity-50 w-3 h-3\">\n                  <path fill=\"currentColor\" d=\"M352 0c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9L370.7 96 201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L416 141.3l41.4 41.4c9.2 9.2 22.9 11.9 34.9 6.9s19.8-16.6 19.8-29.6V32c0-17.7-14.3-32-32-32H352zM80 32C35.8 32 0 67.8 0 112V432c0 44.2 35.8 80 80 80H400c44.2 0 80-35.8 80-80V320c0-17.7-14.3-32-32-32s-32 14.3-32 32V432c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H192c17.7 0 32-14.3 32-32s-14.3-32-32-32H80z\"></path>\n                </svg>\n              </h1>\n            </a>\n\n            <markdown class=\"flex-grow\" *ngIf=\"card.body\" emoji [data]=\"card.body\"></markdown>\n\n            <div *ngIf=\"card.progress as progress\" class=\"ml-2 mr-2\">\n              <div class=\"overflow-hidden rounded border bg-gray-400 border-gray-100 h-5 w-full relative\">\n                <div class=\"h-full\" [style]=\"progress.style\" [style.width.%]=\"progress.percent\"></div>\n                <div class=\"absolute top-0.5 bottom-0 left-0 right-0 flex flex-row justify-center items-center text-xxs text-background\">\n                  <span>{{ progress.percent }}%</span>\n                </div>\n              </div>\n            </div>\n\n            <markdown *ngIf=\"card.footer\" emoji [data]=\"card.footer\" class=\"!text-secondary\"></markdown>\n\n          </section>\n        </sfng-tab>\n      </sfng-tab-group>\n\n      <div class=\"absolute bottom-2 left-0 right-0 flex flex-row items-center justify-center gap-2\">\n        <span *ngFor=\"let dot of carousel.tabs; let index=index\"\n          class=\"block w-2 h-2 transition-all duration-150 ease-in-out bg-opacity-50 rounded-full cursor-pointer bg-background\"\n          [class.bg-blue]=\"carousel.activeTabIndex === index\" (click)=\"carousel.activateTab(index)\"></span>\n      </div>\n    </ng-container>\n\n  </app-dashboard-widget>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/dashboard.component.scss",
    "content": ":host {\n  @apply flex flex-row w-full gap-3 p-4 overflow-auto;\n}\n\n.dashboard-grid {\n  @apply grid gap-4;\n\n  align-items: stretch;\n  justify-items: stretch;\n  grid-template-columns: 1fr 1fr 1fr 1fr;\n  grid-template-areas:\n    \"header header header header\"\n    \"feature feature feature feature\"\n    \"feature feature feature feature\"\n    \"stats stats news news\"\n    \"stats stats news news\"\n    \"charts charts charts charts\"\n    \"charts charts charts charts\"\n    \"blocked blocked countries countries\"\n    \"map map map map\"\n    \"bwvis-bar bwvis-bar bwvis-line bwvis-line\";\n}\n\n:host-context(.min-width-1024px) {\n  .dashboard-grid {\n    grid-template-areas:\n      \"header header header header\"\n      \"feature feature feature news\"\n      \"feature feature feature news\"\n      \"stats stats stats news\"\n      \"stats stats stats news\"\n      \"charts charts charts charts\"\n      \"countries countries map map\"\n      \"blocked blocked map map\"\n      \"bwvis-bar bwvis-bar bwvis-line bwvis-line\";\n  }\n}\n\n#header {\n  grid-area: header;\n}\n\n#features {\n  grid-area: feature;\n}\n\n#stats {\n  grid-area: stats;\n}\n\n#charts {\n  grid-area: charts;\n}\n\n#countries {\n  grid-area: countries;\n}\n\n#blocked {\n  grid-area: blocked;\n}\n\n#connmap {\n  grid-area: map;\n}\n\n#bwvis-bar {\n  grid-area: bwvis-bar;\n}\n\n#bwvis-line {\n  grid-area: bwvis-line;\n}\n\n#news {\n  grid-area: news;\n}\n\n.auto-grid-3 {\n  @apply grid gap-4;\n  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n}\n\n.auto-grid-4 {\n  @apply grid gap-4;\n  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n}\n\napp-dashboard-widget {\n  label {\n    @apply text-xs uppercase text-secondary font-light flex flex-row items-center gap-2 pb-2;\n  }\n\n  .feature-card-list {\n    @apply grid gap-3 w-full;\n    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n  }\n\n  .mini-stats-list {\n    @apply grid gap-3 w-full;\n    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n  }\n\n  &#news {\n\n    h1 {\n      @apply text-base;\n      @apply font-light;\n    }\n\n    ::ng-deep markdown {\n      @apply font-light;\n\n      a {\n        @apply underline text-blue;\n      }\n\n      strong {\n        @apply font-medium;\n      }\n    }\n  }\n\n}\n\n::ng-deep #dashboard-map {\n  #world-group {\n    --map-bg: #111112;\n    --map-country-active: #424141;\n    --map-country-inactive: #2a2a2a;\n    --map-country-border-width: 1px;\n    --map-country-border-color: #1e1e1e;\n    --map-country-border-color-selected: #858585;\n    --map-country-blocked-primary: #858585;\n    --map-country-blocked-secondary: #402323;\n\n    path {\n      fill: var(--map-country-active);\n      stroke: var(--map-bg);\n      stroke-width: var(--map-country-border-width);\n      stroke-linejoin: round;\n    }\n\n    path.active {\n      color: #1d3c24;\n      fill: currentColor;\n    }\n\n    path.hover {\n      color: #4fae4f;\n      fill: currentColor;\n    }\n  }\n}\n\n.mini-stat {\n  @apply flex flex-col items-center justify-center py-3 px-2 bg-gray-300 rounded shadow;\n\n  label {\n    @apply font-light uppercase text-xxs text-secondary -mb-2;\n  }\n\n  span {\n    @apply text-xl text-blue;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/dashboard.component.ts",
    "content": "import { KeyValue } from \"@angular/common\";\nimport { AfterContentInit, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, ElementRef, OnInit, QueryList, TrackByFunction, ViewChild, ViewChildren, forwardRef, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { AppProfileService, BandwidthChartResult, ChartResult, Database, FeatureID, Netquery, PortapiService, SPNService, UserProfile, Verdict } from \"@safing/portmaster-api\";\nimport { SfngDialogService, SfngTabGroupComponent } from \"@safing/ui\";\nimport { Observable, catchError, filter, interval, map, repeat, retry, startWith, throwError } from \"rxjs\";\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\nimport { DefaultBandwidthChartConfig, SfngNetqueryLineChartComponent } from \"src/app/shared/netquery/line-chart/line-chart\";\nimport { SPNAccountDetailsComponent } from \"src/app/shared/spn-account-details\";\nimport { MAP_HANDLER, MapRef } from \"../spn/map-renderer\";\nimport { CircularBarChartConfig, splitQueryResult } from \"src/app/shared/netquery/circular-bar-chart/circular-bar-chart.component\";\nimport { BytesPipe } from \"src/app/shared/pipes/bytes.pipe\";\nimport { HttpErrorResponse } from \"@angular/common/http\";\n\ninterface BlockedProfile {\n  profileID: string;\n  count: number;\n}\n\ninterface BandwidthBarData {\n  profile: string;\n  profile_name: string;\n  series: 'sent' | 'received';\n  value: number;\n  sent: number;\n  received: number;\n}\n\ninterface NewsCard {\n  title: string;\n  body: string;\n  url?: string;\n  footer?: string;\n  progress?: {\n    percent: number;\n    style: string;\n  }\n}\n\ninterface News {\n  cards: NewsCard[];\n}\n\nconst newsResourceIdentifier = \"intel/news.yaml\"\n\n@Component({\n  selector: 'app-dashboard',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styleUrls: ['./dashboard.component.scss'],\n  templateUrl: './dashboard.component.html',\n  providers: [\n    { provide: MAP_HANDLER, useExisting: forwardRef(() => DashboardPageComponent), multi: true },\n  ]\n})\nexport class DashboardPageComponent implements OnInit, AfterViewInit {\n  @ViewChildren(SfngNetqueryLineChartComponent)\n  lineCharts!: QueryList<SfngNetqueryLineChartComponent>;\n\n  @ViewChild(SfngTabGroupComponent)\n  carouselTabGroup?: SfngTabGroupComponent;\n\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly netquery = inject(Netquery);\n  private readonly spn = inject(SPNService);\n  private readonly actionIndicator = inject(ActionIndicatorService);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly dialog = inject(SfngDialogService);\n  private readonly portapi = inject(PortapiService)\n\n  resizeObserver!: ResizeObserver;\n\n  blockedProfiles: BlockedProfile[] = []\n\n  connectionsPerCountry: {\n    [country: string]: number\n  } = {};\n\n  get countryNames(): { [country: string]: string } {\n    return this.mapRef?.countryNames || {};\n  }\n\n  bandwidthLineChart: BandwidthChartResult<any>[] = [];\n\n  bandwidthBarData: BandwidthBarData[] = [];\n\n  readonly bandwidthBarConfig: CircularBarChartConfig<BandwidthBarData> = {\n    stack: 'profile_name',\n    seriesKey: 'series',\n    seriesLabel: d => {\n      if (d === 'sent') {\n        return 'Bytes Sent'\n      }\n      return 'Bytes Received'\n    },\n    value: 'value',\n    ticks: 3,\n    colorAsClass: true,\n    series: {\n      'sent': {\n        color: 'text-deepPurple-500 text-opacity-50',\n      },\n      'received': {\n        color: 'text-cyan-800 text-opacity-50',\n      }\n    },\n    formatTick: (tick: number) => {\n      return new BytesPipe().transform(tick, '1.0-0')\n    },\n    formatValue: (stack, series, value, data) => {\n      const bytes = new BytesPipe().transform\n      return `${stack}\\nSent: ${bytes(data?.sent)}\\nReceived: ${bytes(data?.received)}`\n    },\n    formatStack: (sel, data) => {\n      const bytes = new BytesPipe().transform\n\n      return sel\n        .call(sel => {\n          sel.append(\"text\")\n            .attr(\"dy\", \"0\")\n            .attr(\"y\", \"0\")\n            .text(d => d)\n        })\n        .call(sel => {\n          sel.append(\"text\")\n            .attr(\"y\", 0)\n            .attr(\"dy\", \"0.8rem\")\n            .style(\"font-size\", \"0.6rem\")\n            .text(d => {\n              const first = data.find(result => result.profile_name === d);\n              return `${bytes(first?.sent)} / ${bytes(first?.received)}`\n            })\n        })\n    }\n  }\n\n  bwChartConfig = DefaultBandwidthChartConfig;\n\n  activeConnections: number = 0;\n  blockedConnections: number = 0;\n  activeProfiles: number = 0;\n  activeIdentities = 0;\n  dataIncoming = 0;\n  dataOutgoing = 0;\n  connectionChart: ChartResult[] = [];\n  tunneldConnectionChart: ChartResult[] = [];\n\n  countriesPerProfile: { [profile: string]: string[] } = {}\n\n  profile: UserProfile | null = null;\n\n  featureBw = false;\n  featureSPN = false;\n\n  hoveredCard: NewsCard | null = null;\n\n  features$ = this.spn.watchEnabledFeatures()\n    .pipe(takeUntilDestroyed());\n\n  trackCountry: TrackByFunction<KeyValue<string, any>> = (_, ctr) => ctr.key;\n  trackApp: TrackByFunction<BlockedProfile> = (_, bp) => bp.profileID;\n\n  data: any;\n\n  news?: News | 'pending' = 'pending';\n\n  private mapRef: MapRef | null = null;\n\n  registerMap(ref: MapRef): void {\n    this.mapRef = ref;\n\n    this.mapRef.onMapReady(() => {\n      this.updateMapCountries();\n    })\n  }\n\n  private updateMapCountries() {\n    // this check is basically to make typescript happy ...\n    if (!this.mapRef) {\n      return;\n    }\n\n    this.mapRef.worldGroup\n      .selectAll('path')\n      .classed('active', (d: any) => {\n        return !!this.connectionsPerCountry[d.properties.iso_a2];\n      });\n  }\n\n  unregisterMap(ref: MapRef): void {\n    this.mapRef = null;\n  }\n\n  onCarouselTabHover(card: NewsCard | null) {\n    this.hoveredCard = card;\n  }\n\n  openAccountDetails() {\n    this.dialog.create(SPNAccountDetailsComponent, {\n      autoclose: true,\n      backdrop: 'light'\n    })\n  }\n\n  onCountryHover(code: string | null) {\n    if (!this.mapRef) {\n      return\n    }\n\n    this.mapRef.worldGroup\n      .selectAll('path')\n      .classed('hover', (d: any) => {\n        return (d.properties.iso_a2 === code);\n      });\n  }\n\n  onProfileHover(profile: string | null) {\n    if (!this.mapRef) {\n      return\n    }\n\n    this.mapRef.worldGroup\n      .selectAll('path')\n      .classed('hover', (d: any) => {\n        if (!profile) {\n          return false;\n        }\n\n        return this.countriesPerProfile[profile]?.includes(d.properties.iso_a2);\n      });\n  }\n\n  ngAfterViewInit(): void {\n    interval(15000)\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        startWith(-1),\n        filter(() => this.hoveredCard === null)\n      )\n      .subscribe(() => {\n        if (!this.carouselTabGroup) {\n          return\n        }\n\n        let next = this.carouselTabGroup.activeTabIndex + 1\n        if (next >= this.carouselTabGroup.tabs!.length) {\n          next = 0\n        }\n\n        this.carouselTabGroup.activateTab(next, \"left\")\n      })\n  }\n\n  async ngOnInit() {\n    this.portapi.getResource<News>(newsResourceIdentifier)\n      .pipe(\n        repeat({ delay: 60000 }),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe({\n        next: response => {\n          this.news = response;\n          this.cdr.markForCheck();\n        },\n        error: () => {\n          this.news = undefined;\n          this.cdr.markForCheck();\n        }\n      });\n\n    this.netquery\n      .batch({\n        bwBarChart: {\n          query: {\n            internal: { $eq: false },\n          },\n          select: [\n            'profile',\n            'profile_name',\n            {\n              $sum: {\n                field: 'bytes_sent',\n                as: 'sent'\n              }\n            },\n            {\n              $sum: {\n                field: 'bytes_received',\n                as: 'received'\n              }\n            },\n          ],\n          groupBy: ['profile', 'profile_name'],\n        },\n\n        profileCount: {\n          select: [\n            'profile',\n            {\n              $count: {\n                field: '*',\n                as: 'totalCount'\n              }\n            }\n          ],\n          query: {\n            verdict: { $in: [Verdict.Block, Verdict.Drop] }\n          },\n          groupBy: ['profile'],\n          databases: [Database.Live]\n        },\n\n        countryStats: {\n          select: [\n            'country',\n            { $count: { field: '*', as: 'totalCount' } },\n            { $sum: { field: 'bytes_sent', as: 'bwout' } },\n            { $sum: { field: 'bytes_received', as: 'bwin' } },\n          ],\n          query: {\n            allowed: { $eq: true },\n          },\n          groupBy: ['country'],\n          databases: [Database.Live]\n        },\n\n        perCountryConns: {\n          select: ['profile', 'country', 'active', { $count: { field: '*', as: 'totalCount' } }],\n          query: {\n            allowed: { $eq: true },\n          },\n          groupBy: ['profile', 'country', 'active'],\n          databases: [Database.Live],\n        },\n\n        exitNodes: {\n          query: { tunneled: { $eq: true }, exit_node: { $ne: \"\" } },\n          groupBy: ['exit_node'],\n          select: [\n            'exit_node',\n            { $count: { field: '*', as: 'totalCount' } }\n          ],\n          databases: [Database.Live],\n        }\n      })\n      .pipe(\n        repeat({ delay: 10000 }),\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(response => {\n        // bandwidth bar chart\n        if (response?.bwBarChart){\n          const barChartData = response.bwBarChart\n            .filter(value => (value.sent + value.received) > 0)\n            .sort((a, b) => (b.sent + b.received) - (a.sent + a.received))\n            .slice(0, 10);\n          this.bandwidthBarData = splitQueryResult(barChartData, ['sent', 'received']) as BandwidthBarData[]\n        }\n\n        // profileCount\n        this.blockedConnections = 0;\n        this.blockedProfiles = [];\n\n        response.profileCount?.forEach(row => {\n          this.blockedConnections += row.totalCount;\n          this.blockedProfiles.push({\n            profileID: row.profile!,\n            count: row.totalCount\n          })\n        });\n\n        // countryStats\n        this.connectionsPerCountry = {};\n        this.dataIncoming = 0;\n        this.dataOutgoing = 0;\n\n        response.countryStats?.forEach(row => {\n          this.dataIncoming += row.bwin;\n          this.dataOutgoing += row.bwout;\n\n          if (row.country === '') {\n            return\n          }\n\n          this.connectionsPerCountry[row.country!] = row.totalCount || 0;\n        })\n\n        this.updateMapCountries()\n\n        // perCountryConns\n        let profiles = new Set<string>();\n\n        this.activeConnections = 0;\n        this.countriesPerProfile = {};\n\n        response.perCountryConns?.forEach(row => {\n          profiles.add(row.profile!);\n\n          if (row.active) {\n            this.activeConnections += row.totalCount;\n          }\n\n          const arr = (this.countriesPerProfile[row.profile!] || []);\n          arr.push(row.country!)\n          this.countriesPerProfile[row.profile!] = arr;\n        });\n\n        this.activeProfiles = profiles.size;\n\n        // exitNodes\n        this.activeIdentities = response.exitNodes?.length || 0;\n        this.cdr.markForCheck();\n      })\n\n\n    // Charts\n\n    this.netquery\n      .activeConnectionChart({})\n      .pipe(\n        repeat({ delay: 10000 }),\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(result => {\n        this.connectionChart = result;\n        this.cdr.markForCheck();\n      })\n\n    this.netquery\n      .bandwidthChart({}, undefined, 60)\n      .pipe(\n        repeat({ delay: 10000 }),\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(bw => {\n        this.bandwidthLineChart = bw;\n        this.cdr.markForCheck();\n      })\n\n    this.netquery\n      .activeConnectionChart({ tunneled: { $eq: true } })\n      .pipe(\n        repeat({ delay: 10000 }),\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(result => {\n        this.tunneldConnectionChart = result;\n        this.cdr.markForCheck();\n      })\n\n    // SPN profile and enabled/allowed features\n\n    this.spn\n      .profile$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe({\n        next: (profile) => {\n          this.profile = profile || null;\n          this.featureBw = profile?.current_plan?.feature_ids?.includes(FeatureID.Bandwidth) || false;\n          this.featureSPN = profile?.current_plan?.feature_ids?.includes(FeatureID.SPN) || false;\n\n          // force a full change-detection cylce now!\n          this.cdr.detectChanges()\n\n          // force re-draw of the charts after change-detection because the\n          // width may change now.\n          this.lineCharts?.forEach(chart => chart.redraw())\n\n          this.cdr.markForCheck();\n        },\n      })\n  }\n\n  /** Logs the user out of the SPN completely by purgin the user profile from the local storage */\n  logoutCompletely(_: Event) {\n    this.spn.logout(true)\n      .subscribe(this.actionIndicator.httpObserver(\n        'Logout',\n        'You have been logged out of the SPN completely.'\n      ))\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/feature-card/feature-card.component.html",
    "content": "    <div class=\"feature-card\"\n      [class.disabled]=\"disabled || comingSoon\"\n      [class.clickable]=\"disabled || comingSoon || !!configValue || !!feature?.ConfigScope\"\n      (click)=\"navigateToConfigScope()\">\n      <ng-container *ngIf=\"disabled || comingSoon\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\" class=\"disabled-bg\">\n          <defs>\n            <pattern id=\"pattern_63Hoo\" patternUnits=\"userSpaceOnUse\" width=\"9.5\" height=\"9.5\"\n              patternTransform=\"rotate(45)\">\n              <line x1=\"0\" y=\"0\" x2=\"0\" y2=\"9.5\" stroke=\"currentColor\" stroke-width=\"1\" />\n            </pattern>\n          </defs>\n          <rect width=\"100%\" height=\"100%\" fill=\"url(#pattern_63Hoo)\" :opacity=\"1\" />\n        </svg>\n      </ng-container>\n\n      <header>\n        <img [attr.src]=\"feature?.IconURL\">\n\n        <span>\n          {{ feature?.Name }}\n        </span>\n\n        <div class=\"relative flex flex-row self-start flex-grow\" *ngIf=\"disabled || comingSoon || !!feature?.Beta\">\n          <div class=\"flex-grow\"></div>\n\n          <div *ngIf=\"!!feature?.Beta && !disabled\"\n            class=\"absolute top-0 right-0 flex flex-col items-center justify-center gap-0 text-yellow-200\">\n            <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n              stroke=\"currentColor\" class=\"relative z-10 w-4 h-4\">\n              <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                d=\"M9.75 3.104v5.714a2.25 2.25 0 01-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 014.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0112 15a9.065 9.065 0 00-6.23-.693L5 14.5m14.8.8l1.402 1.402c1.232 1.232.65 3.318-1.067 3.611A48.309 48.309 0 0112 21c-2.773 0-5.491-.235-8.135-.687-1.718-.293-2.3-2.379-1.067-3.61L5 14.5\" />\n            </svg>\n            <span class=\"-mt-1 uppercase\" style=\"font-size: 0.6rem\">BETA</span>\n          </div>\n        </div>\n      </header>\n      <div>\n        <span class=\"font-normal ml-7 text-xxs text-secondary\">\n          {{ (disabled ? 'Available in ' : '') + 'Portmaster ' + feature?.InPackage?.Name}}\n          {{ comingSoon ? ' - coming soon' : '' }}\n          {{ feature?.Comment }}\n        </span>\n      </div>\n\n      <div *ngIf=\"!comingSoon && !disabled && configValue !== undefined\" class=\"absolute right-4 bottom-4\">\n        <sfng-toggle [ngModel]=\"configValue\" (ngModelChange)=\"updateSettingsValue($event)\"\n          (click)=\"$event.cancelBubble = true\"></sfng-toggle>\n      </div>\n      <div *ngIf=\"!comingSoon && !disabled && configValue === undefined\" class=\"absolute right-4 bottom-4\">\n        <span class=\"text-light text-green text-opacity-80\">\n          Active\n        </span>\n      </div>\n\n      <div class=\"ribbon\" *ngIf=\"!!disabled && !!feature?.InPackage\"><span class=\"ribbon__content\"\n          [style.backgroundColor]=\"feature?.InPackage?.HexColor\" [style.color]=\"planColor\">\n          {{ feature?.InPackage?.Name }}\n        </span>\n      </div>\n    </div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/feature-card/feature-card.component.scss",
    "content": ".feature-card {\n  @apply flex flex-col p-4 bg-gray-300 rounded shadow w-full relative gap-2 overflow-hidden;\n\n  .disabled-bg {\n    @apply absolute top-0 left-0 text-gray-500 opacity-50;\n  }\n\n  &.disabled {\n    @apply opacity-80 shadow-inner;\n  }\n\n  &.clickable {\n    @apply cursor-pointer;\n    &:hover {\n      @apply bg-gray-400;\n    }\n  }\n\n  header {\n    @apply flex flex-row items-center justify-start gap-2 w-full;\n\n    img {\n      @apply w-5 h-5;\n      filter: invert(1);\n    }\n\n    &>span {\n      @apply text-base font-light;\n    }\n  }\n}\n\n.ribbon {\n  width: 90px;\n  height: 100%;\n  overflow: hidden;\n  position: absolute;\n  top: 0px;\n  right: 0px;\n  z-index: 100;\n}\n\n.ribbon__content {\n  left: -7px;\n  top: 25px;\n  -webkit-transform: rotate(45deg);\n  -ms-transform: rotate(45deg);\n  transform: rotate(45deg);\n  position: absolute;\n  display: block;\n  width: 125px;\n  padding: 2px 0;\n  text-shadow: 0 1px 0px rgba(0, 0, 0, .2);\n  text-transform: uppercase;\n  text-align: center;\n  border: 2px dotted #fff;\n  outline-color: #fff;\n  outline-width: 1px;\n  outline-style: solid;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/dashboard/feature-card/feature-card.component.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, SimpleChanges, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { BoolSetting, ConfigService, Feature } from '@safing/portmaster-api';\nimport { Subscription } from 'rxjs';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\n\n@Component({\n  selector: 'app-feature-card',\n  templateUrl: './feature-card.component.html',\n  styleUrls: ['./feature-card.component.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class FeatureCardComponent implements OnChanges, OnDestroy {\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly configService = inject(ConfigService);\n  private readonly router = inject(Router);\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  private configValueSubscription = Subscription.EMPTY;\n\n  @Input()\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v)\n  }\n  get disabled() { return this._disabled }\n  _disabled = false;\n\n  get comingSoon() { return this.feature?.ComingSoon || false }\n\n  @Input()\n  feature?: Feature;\n\n  planColor: string | null = null;\n\n  configValue: boolean | undefined = undefined;\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if ('feature' in changes) {\n      this.configValueSubscription.unsubscribe();\n      this.configValueSubscription = Subscription.EMPTY;\n\n      if (!!this.feature?.ConfigKey) {\n        this.configValueSubscription =\n          this.configService.watch<BoolSetting>(this.feature!.ConfigKey)\n            .subscribe(value => {\n              this.configValue = value;\n              this.cdr.markForCheck();\n            });\n      }\n\n      if (this.feature?.InPackage?.HexColor) {\n        this.planColor = getContrastFontColor(this.feature.InPackage.HexColor);\n        // console.log(this.feature.InPackage.HexColor, this.planColor)\n        this.cdr.markForCheck();\n      }\n    }\n  }\n\n  ngOnDestroy() {\n    this.configValueSubscription.unsubscribe();\n  }\n\n  updateSettingsValue(newValue: boolean) {\n    this.configService.save(this.feature!.ConfigKey, newValue)\n      .subscribe()\n  }\n\n  navigateToConfigScope() {\n    if (this.disabled) {\n      this.integration.openExternal(\"https://safing.io/pricing?source=Portmaster\")\n      return;\n    }\n\n    let key: string | undefined;\n    if (this.feature?.ConfigScope) {\n      key = 'config:' + this.feature?.ConfigScope;\n    } else {\n      key = this.feature?.ConfigKey;\n    }\n\n    if (!key) {\n      return\n    }\n\n\n    this.router.navigate(['/settings'], {\n      queryParams: {\n        setting: key,\n      }\n    })\n  }\n}\n\nfunction parseColor(input: string): number[] {\n  if (input.substr(0, 1) === '#') {\n    const collen = (input.length - 1) / 3;\n    const fact = [17, 1, 0.062272][collen - 1];\n    return [\n      Math.round(parseInt(input.substr(1, collen), 16) * fact),\n      Math.round(parseInt(input.substr(1 + collen, collen), 16) * fact),\n      Math.round(parseInt(input.substr(1 + 2 * collen, collen), 16) * fact),\n    ];\n  }\n\n  return input\n    .split('(')[1]\n    .split(')')[0]\n    .split(',')\n    .map((x) => +x);\n}\n\nfunction getContrastFontColor(bgColor: string): string {\n  // if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff\n  // based on https://stackoverflow.com/a/3943023\n\n  let col = bgColor;\n  if (bgColor.startsWith('#') && bgColor.length > 7) {\n    col = bgColor.slice(0, 7);\n  }\n  const [r, g, b] = parseColor(col);\n\n  if (r * 0.299 + g * 0.587 + b * 0.114 > 186) {\n    return '#000000';\n  }\n\n  return '#ffffff';\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/monitor/index.ts",
    "content": "export { MonitorPageComponent } from './monitor';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/monitor/monitor.html",
    "content": "<div class=\"header\">\n  <div class=\"breadcrumbs\">\n    <span routerLink=\"/monitor\">Network Activity</span>\n  </div>\n  <app-expertise></app-expertise>\n</div>\n<div class=\"relative flex flex-col flex-grow overflow-auto\" cdkScrollable>\n\n  <div class=\"flex flex-col items-start justify-center py-6\">\n    <h1 class=\"flex flex-row items-center gap-2 text-xl font-semibold text-primary\">\n      Network Activity\n      <sfng-tipup key=\"networkMonitor-App-Focus-connection-history\"></sfng-tipup>\n    </h1>\n\n    <span class=\"flex flex-row items-center gap-2 p-0 mb-2 ml-0 text-secondary\">\n      <ng-container *ngIf=\"(history | async) as data; else: noHistory\">\n        <ng-container *ngIf=\"!!data\">\n          <span>\n            Network history data available as of {{ data.first | date }}. ({{ data.count }} connections)\n          </span>\n          <a class=\"text-xs underline cursor-pointer text-primary\" (click)=\"clearHistoryData()\">Clear</a>\n        </ng-container>\n      </ng-container>\n      <ng-template #noHistory>\n        <span>\n          No network history data available.\n          <ng-container *ngIf=\"(canUseHistory | async) && (historyEnabled | async) === false\">\n            <a class=\"text-xs underline cursor-pointer text-primary\" (click)=\"enableHistory()\">Enable</a>\n          </ng-container>\n          <ng-container *ngIf=\"(canUseHistory | async) === false\">\n            <a class=\"text-xs underline cursor-pointer text-opacity-75\" href=\"https://safing.io/pricing/?source=Portmaster\">Available in Portmaster Plus</a>\n          </ng-container>\n        </span>\n      </ng-template>\n    </span>\n\n    <span class=\"text-secondary\">\n      Use the search bar and drop downs to search and filter the last 10 minutes of network traffic.\n      Optionally, search all network history data if enabled.\n    </span>\n  </div>\n\n  <sfng-netquery-viewer [filterPreset]=\"session.get('monitor/global-filter') || 'scope:4'\"\n    (filterChange)=\"session.set('monitor/global-filter', $event)\"></sfng-netquery-viewer>\n\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/monitor/monitor.scss",
    "content": ":host {\n  overflow: hidden;\n  flex-direction: row;\n  flex-grow: 1;\n  width: 100%;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  padding-left: 1.7rem;\n  padding-right: 0.8rem;\n\n  .header,\n  .content {\n    padding: 0;\n    margin: 0;\n  }\n\n  .header {\n    padding-top: 0.9rem;\n\n    .breadcrumbs {\n      font-size: 0.715rem;\n      font-weight: 500;\n      color: #cacaca;\n      user-select: none;\n      display: flex;\n\n      span:first-child {\n        opacity: .55;\n        font-weight: 400;\n        margin-right: 4px;\n\n        &:hover {\n          opacity: 1;\n        }\n      }\n\n      svg.arrow {\n        width: 1rem;\n        padding: 0;\n        margin: 0;\n\n        .inner {\n          stroke: white;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/monitor/monitor.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BoolSetting, ConfigService, Database, FeatureID, Netquery, SPNService } from '@safing/portmaster-api';\nimport { Subject, interval, map, merge, repeat } from 'rxjs';\nimport { SessionDataService } from 'src/app/services';\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\nimport { fadeInAnimation, moveInOutListAnimation } from 'src/app/shared/animations';\n\n@Component({\n  templateUrl: './monitor.html',\n  styleUrls: ['../page.scss', './monitor.scss'],\n  providers: [],\n  animations: [fadeInAnimation, moveInOutListAnimation],\n})\nexport class MonitorPageComponent {\n  session = inject(SessionDataService);\n  netquery = inject(Netquery);\n  reload = new Subject<void>();\n\n  configService = inject(ConfigService);\n  uai = inject(ActionIndicatorService);\n\n  historyEnabled = inject(ConfigService)\n    .watch<BoolSetting>('history/enable');\n\n  canUseHistory = inject(SPNService).profile$\n    .pipe(\n      map(profile => {\n        return profile?.current_plan?.feature_ids?.includes(FeatureID.History) || false;\n      })\n    );\n\n  history = inject(Netquery)\n    .query({\n      select: [\n        {\n          $min: {\n            field: \"started\",\n            as: \"first_connection\",\n          },\n        },\n        {\n          $count: {\n            field: \"*\",\n            as: \"totalCount\"\n          }\n        }\n      ],\n      databases: [Database.History]\n    }, 'monitor-get-first-history-connection')\n    .pipe(\n      repeat({ delay: () => merge(interval(10000), this.reload) }),\n      map(result => {\n        if (!result.length || result[0].totalCount === 0) {\n          return null\n        }\n\n        return {\n          first: new Date(result[0].first_connection),\n          count: result[0].totalCount,\n        }\n      }),\n      takeUntilDestroyed()\n    );\n\n  enableHistory() {\n    this.configService.save('history/enable', true)\n      .subscribe();\n  }\n\n  clearHistoryData() {\n    this.netquery.cleanProfileHistory([])\n      .subscribe(() => {\n        this.reload.next();\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/page.scss",
    "content": ":host {\n  display       : flex;\n  flex-direction: column;\n  width         : 100%;\n  height        : 100%;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/settings/settings.html",
    "content": "<div class=\"gap-2 header\">\n  <input type=\"text\" placeholder=\"Search\" [(ngModel)]=\"searchTerm\">\n\n  <a href=\"https://docs.safing.io/portmaster/settings?source=Portmaster\"\n    class=\"flex flex-row items-center justify-center gap-1 px-2 py-1.5 bg-gray-300 rounded hover:bg-gray-200 text-blue whitespace-nowrap\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-4 h-4\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25\" />\n    </svg>\n    Get Help\n  </a>\n\n  <app-expertise></app-expertise>\n</div>\n\n<div class=\"header-title\">\n  <h1>\n    Global Settings\n    <sfng-tipup key=\"globalSettings\"></sfng-tipup>\n  </h1>\n</div>\n\n<app-settings-view [searchTerm]=\"searchTerm\" [highlightKey]=\"highlightSettingKey\" [availableSettings]=\"settings\"\n  (save)=\"saveSetting($event)\">\n</app-settings-view>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/settings/settings.scss",
    "content": ".header-title {\n  display: flex;\n  width: 100%;\n  padding-left: 3rem;\n  padding-right: 1.25rem;\n  margin-bottom: 0.5rem;\n  align-items: center;\n  height: 3rem;\n  flex-shrink: 0;\n\n  h1{\n    flex-grow: unset;\n  }\n\n  fa-icon[icon*=\"question-circle\"]{\n    margin-left: 0.35rem;\n  }\n}\n\n.card-title.meta {\n  div {\n    display: inline-block;\n    @apply mr-2;\n  }\n}\n\n.columns {\n  width         : 100%;\n  display       : flex;\n  flex-direction: row;\n}\n\n.meta {\n\n  span:first-of-type {\n    @apply text-secondary;\n    @apply mr-1;\n  }\n}\n\n.col {\n  flex-grow: 1;\n}\n\n.unstable {\n  @apply text-xs;\n  @apply uppercase;\n  color: theme('colors.info.yellow');\n}\n\nsfng-accordion-group {\n  @apply pl-12;\n  @apply pr-4; // align with the scroll bar on the right side\n  @apply my-4;\n}\n\ndiv.tableFixHead {\n  @apply mt-4;\n  @apply rounded-t;\n\n  &:not(.empty) {\n    @apply rounded;\n  }\n\n  max-height: 16rem;\n}\n\n.cdk-row.unused {\n  opacity: 0.4;\n}\n\n.card-actions {\n  display    : flex;\n  align-items: center;\n\n  * {\n    @apply ml-2;\n  }\n\n  app-menu-trigger {\n    display: inline-block;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/settings/settings.ts",
    "content": "import { Component, OnDestroy, OnInit } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { ConfigService, Setting } from '@safing/portmaster-api';\nimport { Subscription } from 'rxjs';\nimport { StatusService, VersionStatus } from 'src/app/services';\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\nimport { fadeInAnimation } from 'src/app/shared/animations';\nimport { SaveSettingEvent } from 'src/app/shared/config/generic-setting/generic-setting';\n\n@Component({\n  templateUrl: './settings.html',\n  styleUrls: [\n    '../page.scss',\n    './settings.scss'\n  ],\n  animations: [fadeInAnimation]\n})\nexport class SettingsComponent implements OnInit, OnDestroy {\n  /** @private The current search term for the settings. */\n  searchTerm: string = '';\n\n  /** @private All settings currently displayed. */\n  settings: Setting[] = [];\n\n  /** @private The available and selected resource versions. */\n  versions: VersionStatus | null = null;\n\n  /**\n   * @private\n   * The key of the setting to highligh, if any ...\n   */\n  highlightSettingKey: string | null = null;\n\n  /** Subscription to watch all available settings. */\n  private subscription = Subscription.EMPTY;\n\n  constructor(\n    public configService: ConfigService,\n    public statusService: StatusService,\n    private actionIndicator: ActionIndicatorService,\n    private route: ActivatedRoute,\n  ) { }\n\n  ngOnInit(): void {\n    this.subscription = new Subscription();\n\n    this.loadSettings();\n\n    // Request the current resource versions once. We add\n    // it to the subscription to prevent a memory leak in\n    // case the user leaves the page before the versions\n    // have been loaded.\n    const versionSub = this.statusService.getVersions()\n      .subscribe(version => this.versions = version);\n\n    this.subscription.add(versionSub);\n\n    const querySub = this.route.queryParamMap\n      .subscribe(\n        params => {\n          this.highlightSettingKey = params.get('setting');\n        }\n      )\n    this.subscription.add(querySub);\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe();\n  }\n\n  /**\n   * Loads all settings from the portmaster.\n   */\n  private loadSettings() {\n    const configSub = this.configService.query('')\n      .subscribe(settings => this.settings = settings);\n    this.subscription.add(configSub);\n  }\n\n  /**\n   * @private\n   * SaveSettingEvent is emitted by the settings-view\n   * component when a value has been changed and should be saved.\n   *\n   * @param event The save-settings event\n   */\n  saveSetting(event: SaveSettingEvent) {\n    let idx = this.settings.findIndex(setting => setting.Key === event.key);\n    if (idx < 0) {\n      return;\n    }\n\n    const setting = {\n      ...this.settings[idx],\n    }\n\n    if (event.isDefault) {\n      delete (setting['Value']);\n    } else {\n      setting.Value = event.value;\n    }\n\n    this.configService.save(setting)\n      .subscribe({\n        next: () => {\n          if (!!event.accepted) {\n            event.accepted();\n          }\n\n          this.settings[idx] = setting;\n\n          // copy the settings into a new array so we trigger\n          // an input update due to changed array identity.\n          this.settings = [...this.settings];\n\n          // for the release level setting we need to\n          // to a page-reload since portmaster will now\n          // return more settings.\n          if (setting.Key === 'core/releaseLevel') {\n            this.loadSettings();\n          }\n        },\n        error: err => {\n          if (!!event.rejected) {\n            event.rejected(err);\n          }\n\n          this.actionIndicator.error('Failed to save setting', err);\n          console.error(err);\n        }\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/country-details/country-details.html",
    "content": "<h1 class=\"flex flex-row items-center gap-2\" cdkDragHandle cdkDrag cdkDragRootElement=\".cdk-overlay-pane\">\n  <span [appCountryFlags]=\"countryCode\"></span>\n  <span>{{ countryName }}</span>\n  <span class=\"flex-grow\"></span>\n\n  <svg *ngIf=\"!!dialogRef\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"\n    stroke-width=\"2\" class=\"w-4 h-4 ml-2 opacity-75 cursor-pointer hover:opacity-100\" (click)=\"dialogRef.close()\">\n    <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\"></path>\n  </svg>\n</h1>\n\n<sfng-tab-group linkRouter=\"false\" class=\"h-full\">\n  <!-- Tab that displays all nodes in that country -->\n  <sfng-tab id=\"pins\" title=\"Nodes\">\n    <spn-pin-list *sfngTabContent [pins]=\"pins\" (pinHover)=\"pinHover.next($event)\" (pinClick)=\"openPinDetails($event)\"\n      allowClick=\"true\">\n    </spn-pin-list>\n  </sfng-tab>\n\n  <!-- Tab that displays generale statistics about the country -->\n  <sfng-tab id=\"Statistics\" title=\"Statistics\">\n    <div *sfngTabContent class=\"flex flex-col gap-3\">\n      <table>\n        <tr>\n          <th>\n            <span class=\"text-primary\">Total Nodes</span>\n          </th>\n          <td>{{ totalAliveCount }}</td>\n        </tr>\n        <tr *ngIf=\"totalAliveCount\">\n          <th>\n            <span class=\"inline-block pl-4\">\n              <spn-node-icon bySafing=\"true\" isActive=\"true\"></spn-node-icon>\n              by Safing\n            </span>\n          </th>\n          <td>{{ safingNodeCount }}</td>\n        </tr>\n        <tr *ngIf=\"totalAliveCount\">\n          <th>\n            <span class=\"inline-block pl-4\">\n              <spn-node-icon bySafing=\"false\" isActive=\"true\"></spn-node-icon>\n              by Community\n            </span>\n          </th>\n          <td>{{ communityNodeCount }}</td>\n        </tr>\n        <tr>\n          <th>\n            <span class=\"text-primary\">Exit Nodes</span>\n          </th>\n          <td>{{ exitNodeCount }}</td>\n        </tr>\n        <tr *ngIf=\"!!exitNodeCount\">\n          <th>\n            <span class=\"inline-block pl-4\">\n              <spn-node-icon bySafing=\"true\" isExit=\"true\"></spn-node-icon>\n              by Safing\n            </span>\n          </th>\n          <td>{{ safingExitNodeCount }}</td>\n        </tr>\n        <tr *ngIf=\"!!exitNodeCount\">\n          <th>\n            <span class=\"inline-block pl-4\">\n              <spn-node-icon bySafing=\"false\" isExit=\"true\"></spn-node-icon>\n              by Community\n            </span>\n          </th>\n          <td>{{ communityExitNodeCount }}</td>\n        </tr>\n        <tr>\n          <th>\n            <span class=\"text-primary\">Nodes In Use</span>\n          </th>\n          <td>{{ activeNodeCount }}</td>\n        </tr>\n        <tr *ngIf=\"activeNodeCount\">\n          <th>\n            <span class=\"inline-block pl-4\">\n              <spn-node-icon bySafing=\"true\" isActive=\"true\"></spn-node-icon>\n              by Safing\n            </span>\n          </th>\n          <td>{{ activeSafingNodeCount }}</td>\n        </tr>\n        <tr *ngIf=\"activeNodeCount\">\n          <th>\n            <span class=\"inline-block pl-4\">\n              <spn-node-icon bySafing=\"false\" isActive=\"true\"></spn-node-icon>\n              by Community\n            </span>\n          </th>\n          <td>{{ activeCommunityNodeCount }}</td>\n        </tr>\n      </table>\n    </div>\n  </sfng-tab>\n\n\n  <!-- Tab that displays all apps that exit in this country -->\n  <sfng-tab id=\"profiles\" title=\"Apps\">\n    <div *sfngTabContent>\n      <span class=\"inline-block p-2 mb-2 text-tertiary\">The following Apps have connections that are routed through the\n        SPN and use an\n        exit node in {{ countryName }} ({{ countryCode }}):</span>\n      <table class=\"w-full custom \">\n        <tbody>\n          <tr *ngFor=\"let app of profiles; trackBy: trackProfile\"\n            class=\"bg-transparent hover:bg-gray-500 hover:bg-opacity-50\">\n            <td class=\"p-2\">\n              <app-icon [profile]=\"app.profile\"></app-icon>\n              {{ app.profile.Name }}\n            </td>\n            <td class=\"p-2\">\n              {{ app.count }} <span class=\"text-tertiary\">connections</span>\n            </td>\n            <td class=\"w-10 p-2\">\n              <div class=\"flex flex-row items-center gap-2 \">\n                <div class=\"w-6 outline-none cursor-pointer hover:text-primary text-secondary\"\n                  [routerLink]=\"['/app/', app.profile.Source, app.profile.ID]\"\n                  [queryParams]=\"{tab: 0, q: filterConnectionsByCountryNodes}\" (click)=\"$event.stopPropagation()\">\n                  <svg viewBox=\"0 0 24 24\" class=\"w-4 h-4\">\n                    <g fill=\"none\" stroke=\"currentColor\">\n                      <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                        stroke-width=\"2\"\n                        d=\"M8.464 8.464c-1.953 1.953-1.953 5.118 0 7.071 1.953 1.953 5.118 1.953 7.071 0 1.953-1.953 1.953-5.119 0-7.071C14.559 7.488 13.28 7 12 7\" />\n                      <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                        stroke-width=\"2\"\n                        d=\"M5.636 5.636c-3.515 3.515-3.515 9.213 0 12.728 3.515 3.515 9.213 3.515 12.728 0 3.515-3.515 3.515-9.213 0-12.728-2.627-2.627-6.474-3.289-9.717-1.989M5.64 5.64L12 12\" />\n                    </g>\n                  </svg>\n                </div>\n\n                <div class=\"cursor-pointer w-6outline-none hover:text-primary text-secondary\"\n                  [routerLink]=\"['/app/',  app.profile.Source, app.profile.ID]\" [queryParams]=\"{tab: 'settings'}\"\n                  (click)=\"$event.stopPropagation()\">\n                  <svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"Layer 1\" viewBox=\"0 0 24 24\" class=\"w-4 h-4\"\n                    fill=\"none\" stroke=\"currentColor\">\n                    <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" fill=\"currentColor\"\n                      d=\"M19 21h-3a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2Z\" />\n                    <path fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n                      d=\"M19 9h-3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2ZM5 3h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2ZM5 15h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2Z\" />\n                  </svg>\n                </div>\n              </div>\n            </td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  </sfng-tab>\n\n</sfng-tab-group>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/country-details/country-details.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, Optional, Output, SimpleChanges, TrackByFunction } from \"@angular/core\";\nimport { AppProfile, AppProfileService, Netquery } from '@safing/portmaster-api';\nimport { SFNG_DIALOG_REF, SfngDialogRef, SfngDialogService } from \"@safing/ui\";\nimport { Subscription, forkJoin, of, switchMap } from 'rxjs';\nimport { repeat } from 'rxjs/operators';\nimport { MapPin, MapService } from './../map.service';\nimport { PinDetailsComponent } from './../pin-details/pin-details';\n\n@Component({\n  templateUrl: './country-details.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styles: [\n    `:host{\n      display: block;\n      min-width: 630px;\n      height: 400px;\n      overflow: hidden;\n    }`\n  ]\n})\nexport class CountryDetailsComponent implements OnInit, OnChanges, OnDestroy {\n  /** Subscription to poll map pins and profiles. */\n  private subscription = Subscription.EMPTY;\n\n  /** The two letter ISO country code */\n  @Input()\n  countryCode: string = '';\n\n  /** The name of the country */\n  @Input()\n  countryName: string = '';\n\n  /** Emits the ID of the pin that is hovered in the list. null if no pin is hovered */\n  @Output()\n  pinHover = new EventEmitter<string | null>();\n\n  /** @private - The list of pins available in this country */\n  pins: MapPin[] = [];\n\n  /** @private - A list of app profiles that use this country as an exit node */\n  profiles: { profile: AppProfile, count: number }[] = [];\n\n  /** @private - A {@link TrackByFunction} for all profiles that use this country for exit */\n  trackProfile: TrackByFunction<this['profiles'][0]> = (_: number, profile: this['profiles'][0]) => `${profile.profile.Source}/${profile.profile.ID}`;\n\n  /** The number of alive nodes in this country */\n  totalAliveCount = 0;\n\n  /** The number of exit nodes in this country */\n  exitNodeCount = 0;\n\n  /** The number of active (used) nodes in this country */\n  activeNodeCount = 0;\n\n  /** The number of active (used) nodes operated by safing */\n  activeSafingNodeCount = 0;\n\n  /** The number of active (used) nodes operated by the community */\n  activeCommunityNodeCount = 0;\n\n  /** The number of nodes operated by safing */\n  safingNodeCount = 0;\n\n  /** The number of exit nodes operated by safing */\n  safingExitNodeCount = 0;\n\n  /** The number of nodes operated by a community member */\n  communityNodeCount = 0;\n\n  /** The number of exit ndoes operated by the community */\n  communityExitNodeCount = 0;\n\n  /** holds the text format of a netquery search to show all connections that exit in this country */\n  filterConnectionsByCountryNodes = '';\n\n  constructor(\n    private mapService: MapService,\n    private netquery: Netquery,\n    private appService: AppProfileService,\n    private cdr: ChangeDetectorRef,\n    private dialog: SfngDialogService,\n    @Inject(SFNG_DIALOG_REF) @Optional() public dialogRef?: SfngDialogRef<CountryDetailsComponent, never, { code: string, name: string }>,\n  ) { }\n\n  openPinDetails(id: string) {\n    this.dialog.create(PinDetailsComponent, {\n      data: id,\n      backdrop: false,\n      autoclose: true,\n      dragable: true,\n    })\n  }\n\n  ngOnInit() {\n    // if we got opened as a dialog we get the code and name of the country\n    // from the dialogRef.data field.\n    if (!!this.dialogRef) {\n      this.countryCode = this.dialogRef.data.code;\n      this.countryName = this.dialogRef.data.name;\n    }\n\n    this.subscription.unsubscribe();\n\n    this.subscription =\n      this.mapService\n        .pins$\n        .pipe(\n          switchMap(pins => {\n            // get a list of pins in that country\n            const countryPins = pins.filter(pin => pin.entity.Country === this.countryCode);\n\n            // prepare a netquery query that loads the IDs of all profiles that use one of the countries\n            // pins as an exit node. Then, map those IDs to the actual app profile object\n            const profiles = this.netquery\n              .query({\n                select: [\n                  'profile',\n                  { $count: { field: '*', as: 'totalCount' } }\n                ],\n                groupBy: ['profile'],\n                query: {\n                  'exit_node': {\n                    $in: countryPins.map(pin => pin.pin.ID),\n                  }\n                }\n              }, 'get-connections-per-profile-in-country')\n              .pipe(\n                switchMap(queryResult => {\n                  if (queryResult.length === 0) {\n                    return of([]);\n                  }\n\n                  return forkJoin(\n                    queryResult.map(row => forkJoin({\n                      profile: this.appService.getAppProfile(row.profile!),\n                      count: of(row.totalCount),\n                    })\n                    )\n                  )\n                }),\n              );\n\n            return forkJoin({\n              pins: of(countryPins),\n              profiles: profiles,\n            })\n          }\n          ),\n          repeat({\n            delay: 5000\n          }),\n        )\n        .subscribe(result => {\n          this.pins = result.pins;\n          this.profiles = result.profiles\n\n          this.activeNodeCount = 0;\n          this.activeCommunityNodeCount = 0;\n          this.activeSafingNodeCount = 0;\n          this.exitNodeCount = 0;\n          this.safingNodeCount = 0;\n          this.communityNodeCount = 0;\n          this.safingExitNodeCount = 0;\n          this.communityExitNodeCount = 0;\n\n          this.pins.forEach(pin => {\n            if (pin.isOffline) {\n              return\n            }\n            this.totalAliveCount++;\n\n            if (pin.pin.VerifiedOwner === 'Safing') {\n              this.safingNodeCount++;\n\n              if (pin.isExit) {\n                this.exitNodeCount++;\n                this.safingExitNodeCount++;\n              }\n              if (pin.isActive) {\n                this.activeSafingNodeCount++;\n                this.activeNodeCount++;\n              }\n\n            } else {\n              this.communityNodeCount++;\n\n              if (pin.isExit) {\n                this.exitNodeCount++;\n                this.communityExitNodeCount++;\n              }\n              if (pin.isActive) {\n                this.activeCommunityNodeCount++;\n                this.activeNodeCount++;\n              }\n            }\n          })\n\n          // create a netquery text-query in the format of \"exit_node:<id1> exit_node:<id2> ...\"\n          this.filterConnectionsByCountryNodes = this.pins.map(pin => `exit_node:${pin.pin.ID}`).join(\" \")\n\n          this.cdr.markForCheck();\n        })\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    // if we are rendered as a regular component (not as a dialog) we need to\n    // handle updates to our @Inputs().\n    // just let ngOnInit() do it's thing if the countryCode changed.\n    if (!!changes['countryCode']) {\n      this.ngOnInit();\n    }\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/country-details/index.ts",
    "content": "export * from './country-details';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/country-overlay/country-overlay.html",
    "content": "<span class=\"country-content-wrapper\">\n\n  <span class=\"country-name\">\n    <span class=\"country-name-flag\" [appCountryFlags]=\"countryCode\"></span>\n    <span class=\"country-name-name\">{{ countryName }}</span>\n  </span>\n\n  <span class=\"country-stats\">\n    <span class=\"country-stats--safing\">\n      <spn-node-icon bySafing=\"true\" isActive=\"true\"></spn-node-icon>\n      <span>Safing Nodes:</span>\n      <span class=\"count\">{{ safingNodes.length }}</span>\n    </span>\n\n    <span class=\"country-stats--community\">\n      <spn-node-icon bySafing=\"false\" isActive=\"true\"></spn-node-icon>\n      <span>Community Nodes:</span>\n      <span class=\"count\">{{ communityNodes.length }}</span>\n    </span>\n  </span>\n\n  <span class=\"pb-2 text-xxs text-tertiary\">\n    Click country for details\n  </span>\n</span>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/country-overlay/country-overlay.scss",
    "content": ":host {\n  @apply flex flex-row items-center justify-center;\n}\n\n.country-content-wrapper {\n  @apply flex flex-col gap-2 items-center justify-center bg-gray-200 border bg-opacity-50 border-gray-600 border-opacity-25;\n}\n\n.country-name {\n  @apply text-sm flex flex-row gap-1 items-center justify-center bg-gray-100 bg-opacity-50 py-2 w-full;\n}\n\n.country-stats {\n  @apply flex flex-col gap-2 items-start py-2 px-4;\n\n  &>span {\n    @apply flex flex-row gap-1 items-center;\n    @apply text-xs font-light;\n  }\n\n  .count {\n    @apply text-sm font-normal;\n  }\n}\n\n.country-stats--safing {\n  svg polygon {\n    fill: #0376bb;\n    stroke: #0376bb;\n    transform: scale(1.15)\n  }\n}\n\n.country-stats--community {\n  svg circle {\n    fill: #239215;\n    stroke: #239215;\n    transform: scale(1.15)\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/country-overlay/country-overlay.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';\nimport { BehaviorSubject, combineLatest, map } from 'rxjs';\nimport { takeWhile } from 'rxjs/operators';\nimport { MapPin, MapService } from './../map.service';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'spn-map-country-overlay',\n  templateUrl: './country-overlay.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styleUrls: [\n    './country-overlay.scss'\n  ]\n})\nexport class CountryOverlayComponent implements OnInit, OnChanges, OnDestroy {\n  /** The two-letter ISO code of the country */\n  @Input()\n  countryCode!: string;\n\n  /** The (english) name of the country */\n  @Input()\n  countryName!: string;\n\n  /** all nodes in this country operated by Safing */\n  safingNodes: MapPin[] = [];\n\n  /** all nodes in this country operated by a community member */\n  communityNodes: MapPin[] = [];\n\n  /** used to trigger a reload onChanges */\n  private reload$ = new BehaviorSubject<void>(undefined);\n\n  constructor(\n    private mapService: MapService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    this.reload$.next();\n  }\n\n  ngOnInit(): void {\n    combineLatest([\n      this.mapService.pins$,\n      this.reload$\n    ])\n      .pipe(\n        takeWhile(() => !this.reload$.closed),\n        map(([pins]) => pins.filter(pin => pin.entity.Country === this.countryCode)),\n      )\n      .subscribe(pinsInCountry => {\n        this.safingNodes = [];\n        this.communityNodes = [];\n\n        pinsInCountry.forEach(pin => {\n          if (pin.isOffline && !pin.isActive) {\n            return\n          }\n\n          if (pin.pin.VerifiedOwner === 'Safing') {\n            this.safingNodes.push(pin)\n          } else {\n            this.communityNodes.push(pin)\n          }\n        })\n\n        this.cdr.markForCheck();\n      })\n  }\n\n  ngOnDestroy(): void {\n    this.reload$.complete();\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/country-overlay/index.ts",
    "content": "export * from './country-overlay';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/index.ts",
    "content": "export * from './spn-page';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/map-legend/index.ts",
    "content": "export * from './map-legend';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/map-legend/map-legend.html",
    "content": "  <div class=\"flex flex-col gap-2 bg-gray-200 bg-opacity-50 border border-gray-600 border-opacity-25\">\n    <table class=\"p-2 font-thin custom\">\n      <tr>\n        <td class=\"p-2 font-normal\">\n          <spn-node-icon bySafing=\"true\"></spn-node-icon>\n          Safing Nodes\n        </td>\n        <td class=\"p-2\">{{ safingNodeCount }}</td>\n      </tr>\n      <tr>\n        <td class=\"p-2\">\n          <span class=\"pl-5\">\n            <spn-node-icon bySafing=\"true\" isActive=\"true\"></spn-node-icon>\n            used as Transit\n          </span>\n        </td>\n        <td class=\"p-2\">{{ safingActiveCount }}</td>\n      </tr>\n      <tr>\n        <td class=\"p-2\">\n          <span class=\"pl-5\">\n            <spn-node-icon bySafing=\"true\" isExit=\"true\"></spn-node-icon>\n            used as Exit\n          </span>\n        </td>\n        <td class=\"p-2\">{{ safingExitCount }}</td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-normal\">\n          <spn-node-icon bySafing=\"false\"></spn-node-icon>\n          Community Nodes\n        </td>\n        <td class=\"p-2\">{{ communityNodeCount }}</td>\n      </tr>\n      <tr>\n        <td class=\"p-2\">\n          <span class=\"pl-5\">\n            <spn-node-icon bySafing=\"false\" isActive=\"true\"></spn-node-icon>\n            used as Transit\n          </span>\n        </td>\n        <td class=\"p-2\">{{ communityActiveCount }}</td>\n      </tr>\n      <tr>\n        <td class=\"p-2\">\n          <span class=\"pl-5\">\n            <spn-node-icon bySafing=\"false\" isExit=\"true\"></spn-node-icon>\n            used as Exit\n          </span>\n        </td>\n        <td class=\"p-2\">{{ communityExitCount }}</td>\n      </tr>\n    </table>\n  </div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/map-legend/map-legend.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from \"@angular/core\";\nimport { Subscription } from 'rxjs';\nimport { MapService } from './../map.service';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'spn-map-legend',\n  templateUrl: './map-legend.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SpnMapLegendComponent implements OnInit, OnDestroy {\n  private subscription = Subscription.EMPTY;\n\n  safingNodeCount = 0;\n  safingExitCount = 0;\n  safingActiveCount = 0;\n\n  communityNodeCount = 0;\n  communityExitCount = 0;\n  communityActiveCount = 0;\n\n  constructor(\n    private mapService: MapService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  ngOnInit() {\n    this.subscription = this.mapService\n      .pins$\n      .subscribe(pins => {\n        this.safingActiveCount = 0;\n        this.safingExitCount = 0;\n        this.safingNodeCount = 0;\n        this.communityActiveCount = 0;\n        this.communityExitCount = 0;\n        this.communityNodeCount = 0;\n\n        pins.forEach(pin => {\n          if (pin.pin.VerifiedOwner === 'Safing') {\n            if (pin.isActive) {\n              this.safingActiveCount++;\n            }\n\n            if (pin.isExit) {\n              this.safingExitCount++\n            }\n\n            this.safingNodeCount++\n          } else {\n            if (pin.isActive) {\n              this.communityActiveCount++;\n            }\n\n            if (pin.isExit) {\n              this.communityExitCount++;\n            }\n\n            this.communityNodeCount++;\n          }\n        })\n\n        this.cdr.markForCheck();\n      })\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/map-renderer/index.ts",
    "content": "export * from './map-renderer';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/map-renderer/map-renderer.ts",
    "content": "import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, ElementRef, Inject, InjectionToken, Input, OnDestroy, OnInit, Optional, inject } from '@angular/core';\nimport { GeoPath, GeoPermissibleObjects, GeoProjection, Selection, ZoomTransform, geoMercator, geoPath, json, pointer, select, zoom, zoomIdentity } from 'd3';\nimport { feature } from 'topojson-client';\n\n\nexport type MapRoot = Selection<SVGSVGElement, unknown, null, never>;\nexport type WorldGroup = Selection<SVGGElement, unknown, null, unknown>\n\nexport interface CountryEvent {\n  event?: MouseEvent;\n  countryCode: string;\n  countryName: string;\n}\n\nexport interface MapRef {\n  onMapReady(cb: () => any): void;\n  onZoomPan(cb: () => any): void;\n  onCountryHover(cb: (_: CountryEvent | null) => void): void;\n  onCountryClick(cb: (_: CountryEvent) => void): void;\n  select(selection: string): Selection<any, any, any, any> | null;\n\n  countryNames: { [key: string]: string };\n  root: MapRoot;\n  projection: GeoProjection;\n  zoomScale: number;\n  worldGroup: WorldGroup;\n}\n\nexport interface MapHandler {\n  registerMap(ref: MapRef): void;\n  unregisterMap(ref: MapRef): void;\n}\n\nexport const MAP_HANDLER = new InjectionToken<MapHandler>('MAP_HANDLER');\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'spn-map-renderer',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: '',\n  styleUrls: [\n    './map-style.scss'\n  ],\n})\nexport class MapRendererComponent implements OnInit, AfterViewInit, OnDestroy {\n  static readonly Rotate = 0; // so [-0, 0] is the initial center of the projection\n  static readonly Maxlat = 83; // clip northern and southern pols (infinite in mercator)\n  static readonly MarkerSize = 4;\n  static readonly LineAnimationDuration = 200;\n\n  private readonly destroyRef = inject(DestroyRef);\n  private destroyed = false;\n\n  countryNames: {\n    [countryCode: string]: string\n  } = {}\n\n  // SVG group elements\n  private svg: MapRoot | null = null;\n  worldGroup!: WorldGroup;\n\n  // Projection and line rendering functions\n  projection!: GeoProjection;\n  zoomScale: number = 1\n\n  private pathFunc!: GeoPath<any, GeoPermissibleObjects>;\n\n  get root() {\n    return this.svg!\n  }\n\n  @Input()\n  mapId: string = 'map'\n\n  constructor(\n    private mapRoot: ElementRef<HTMLElement>,\n    private cdr: ChangeDetectorRef,\n    @Inject(MAP_HANDLER) @Optional() private overlays: MapHandler[],\n  ) { }\n\n  ngOnInit(): void {\n    this.overlays?.forEach(ov => {\n      ov.registerMap(this)\n    })\n\n    this.cdr.detach()\n  }\n\n  select(selector: string) {\n    if (!this.svg) {\n      return null\n    }\n\n    return this.svg.select(selector);\n  }\n\n  private _readyCb: (() => void)[] = [];\n  onMapReady(cb: () => void) {\n    this._readyCb.push(cb);\n  }\n\n  private _zoomCb: (() => void)[] = [];\n  onZoomPan(cb: () => void) {\n    this._zoomCb.push(cb)\n  }\n\n  private _countryHoverCb: ((e: CountryEvent | null) => void)[] = [];\n  onCountryHover(cb: (e: CountryEvent | null) => void) {\n    this._countryHoverCb.push(cb);\n  }\n\n  private _countryClickCb: ((e: CountryEvent) => void)[] = [];\n  onCountryClick(cb: (e: CountryEvent) => void) {\n    this._countryClickCb.push(cb)\n  }\n\n  async ngAfterViewInit() {\n    await this.renderMap()\n\n    const observer = new ResizeObserver(() => {\n      this.renderMap()\n    })\n\n    this.destroyRef.onDestroy(() => {\n      observer.unobserve(this.mapRoot.nativeElement)\n      observer.disconnect()\n    })\n\n    observer.observe(this.mapRoot.nativeElement);\n  }\n\n  async renderMap() {\n    if (this.destroyed) {\n      return;\n    }\n\n    if (!!this.svg) {\n      this.svg.remove()\n    }\n\n    const map = select(this.mapRoot.nativeElement);\n\n    // setup the basic SVG elements\n    this.svg = map\n      .append('svg')\n      .attr('id', this.mapId)\n      .attr(\"xmlns\", \"http://www.w3.org/2000/svg\")\n      .attr('width', '100%')\n      .attr('preserveAspectRation', 'none')\n      .attr('height', '100%')\n\n    this.worldGroup = this.svg.append('g').attr('id', 'world-group')\n\n    // load the world-map data and start rendering\n    const world = await json<any>('/assets/world-50m.json');\n\n    // actually render the countries\n    const countries = (feature(world, world.objects.countries) as any);\n\n    this.setupProjection();\n    await this.setupZoom(countries);\n\n    // we need to await the initial world render here because otherwise\n    // the initial renderPins() will not be able to update the country attributes\n    // and cause a delay before the state of the country (has-nodes, is-blocked, ...)\n    // is visible.\n    this.renderWorld(countries);\n\n    this._readyCb.forEach(cb => cb());\n  }\n\n  ngOnDestroy() {\n    this.destroyed = true;\n\n    this.overlays?.forEach(ov => ov.unregisterMap(this));\n\n    this._countryClickCb = [];\n    this._countryHoverCb = [];\n    this._readyCb = [];\n    this._zoomCb = [];\n\n    if (!this.svg) {\n      return;\n    }\n\n    this.svg.remove();\n    this.svg = null;\n  }\n\n  private renderWorld(countries: any) {\n    // actually render the countries\n    const data = countries.features;\n    const self = this;\n\n    data.forEach((country: any) => {\n      this.countryNames[country.properties.iso_a2] = country.properties.name\n    })\n    // Add special country values.\n    this.countryNames[\"__\"] = \"Anycast\"\n\n    this.worldGroup.selectAll()\n      .data<GeoPermissibleObjects>(data)\n      .enter()\n      .append('path')\n      .attr('countryCode', (d: any) => d.properties.iso_a2)\n      .attr('name', (d: any) => d.properties.name)\n      .attr('d', this.pathFunc)\n      .on('mouseenter', function (event: MouseEvent) {\n        const country = select(this).datum() as any;\n        const countryEvent: CountryEvent = {\n          event: event,\n          countryCode: country.properties.iso_a2,\n          countryName: country.properties.name,\n        }\n\n        self._countryHoverCb.forEach(cb => cb(countryEvent))\n      })\n      .on('mouseout', function (event: MouseEvent) {\n        self._countryHoverCb.forEach(cb => cb(null))\n      })\n      .on('click', function (event: MouseEvent) {\n        const country = select(this).datum() as any;\n        const countryEvent: CountryEvent = {\n          event: event,\n          countryCode: country.properties.iso_a2,\n          countryName: country.properties.name,\n        }\n\n        const loc = self.projection.invert!([event.clientX, event.clientY])\n\n        console.log(loc)\n\n        self._countryClickCb.forEach(cb => cb(countryEvent))\n      })\n  }\n\n  private setupProjection() {\n    const size = this.mapRoot.nativeElement.getBoundingClientRect();\n\n    this.projection = geoMercator()\n      .rotate([MapRendererComponent.Rotate, 0])\n      .scale(1)\n      .translate([size.width / 2, size.height / 2]);\n\n\n    // path is used to update the SVG path to match our mercator projection\n    this.pathFunc = geoPath().projection(this.projection);\n  }\n\n  private async setupZoom(countries: any) {\n    if (!this.svg) {\n      return\n    }\n\n    // create a copy of countries\n    countries = {\n      ...countries,\n      features: [...countries.features]\n    }\n\n    // remove Antarctica from the feature set so projection.fitSize ignores it\n    // and better aligns the rest of the world :)\n    const aqIdx = countries.features.findIndex((p: GeoJSON.Feature) => p.properties?.iso_a2 === \"AQ\");\n    if (aqIdx >= 0) {\n      countries.features.splice(aqIdx, 1)\n    }\n\n    const size = this.mapRoot.nativeElement.getBoundingClientRect();\n\n    this.projection.fitSize([size.width, size.height], countries)\n\n    //this.projection.fitWidth(size.width, countries)\n    //this.projection.fitHeight(size.height, countries)\n\n    // returns the top-left and the bottom-right of the current projection\n    const mercatorBounds = () => {\n      const yaw = this.projection.rotate()[0];\n      const xymax = this.projection([-yaw + 180 - 1e-6, -MapRendererComponent.Maxlat])!;\n      const xymin = this.projection([-yaw - 180 + 1e-6, MapRendererComponent.Maxlat])!;\n      return [xymin, xymax];\n    }\n\n    const s = this.projection.scale()\n    const scaleExtent = [s, s * 10]\n\n    const transform = zoomIdentity\n      .scale(this.projection.scale())\n      .translate(this.projection.translate()[0], this.projection.translate()[1]);\n\n    // whenever the users zooms we need to update our groups\n    // individually to apply the zoom effect.\n    let tlast = {\n      x: 0,\n      y: 0,\n      k: 0,\n    }\n\n    const self = this;\n\n    let z = zoom<SVGSVGElement, unknown>()\n      .scaleExtent(scaleExtent as [number, number])\n      .on('zoom', (e) => {\n        const t: ZoomTransform = e.transform;\n\n        if (t.k != tlast.k) {\n          let p = pointer(e)\n          let scrollToMouse = () => { };\n\n          if (!!p && !!p[0]) {\n            const tp = this.projection.translate();\n            const coords = this.projection!.invert!(p)\n            scrollToMouse = () => {\n              const newPos = this.projection(coords!)!;\n              const yaw = this.projection.rotate()[0];\n              this.projection.translate([tp[0], tp[1] + (p[1] - newPos[1])])\n              this.projection.rotate([yaw + 360.0 * (p[0] - newPos[0]) / size.width * scaleExtent[0] / t.k, 0, 0])\n            }\n          }\n\n          this.projection.scale(t.k);\n          scrollToMouse();\n\n        } else {\n          let dy = t.y - tlast.y;\n          const dx = t.x - tlast.x;\n          const yaw = this.projection.rotate()[0]\n          const tp = this.projection.translate();\n\n          // use x translation to rotate based on current scale\n          this.projection.rotate([yaw + 360.0 * dx / size.width * scaleExtent[0] / t.k, 0, 0])\n          // use y translation to translate projection clamped to bounds\n          let bounds = mercatorBounds();\n          if (bounds[0][1] + dy > 0) {\n            dy = -bounds[0][1];\n          } else if (bounds[1][1] + dy < size.height) {\n            dy = size.height - bounds[1][1];\n          }\n          this.projection.translate([tp[0], tp[1] + dy]);\n        }\n\n        tlast = {\n          x: t.x,\n          y: t.y,\n          k: t.k,\n        }\n\n        // finally, re-render the SVG shapes according to the new projection\n        this.worldGroup.selectAll<SVGPathElement, GeoPermissibleObjects>('path')\n          .attr('d', this.pathFunc)\n\n\n        this._zoomCb.forEach(cb => cb());\n      });\n\n    this.svg.call(z)\n    this.svg.call(z.transform, transform);\n  }\n\n  public getCoords(lat: number, lng: number) {\n    const loc = this.projection([lng, lat]);\n    if (!loc) {\n      return null;\n    }\n\n    const rootElem = this.mapRoot.nativeElement.getBoundingClientRect();\n    const x = rootElem.x + loc[0];\n    const y = rootElem.y + loc[1];\n\n    return [x, y];\n  }\n\n  public coordsInView(lat: number, lng: number) {\n    const loc = this.projection([lng, lat]);\n    if (!loc) {\n      return false\n    }\n\n    const rootElem = this.mapRoot.nativeElement.getBoundingClientRect();\n    const x = rootElem.x + loc[0];\n    const y = rootElem.y + loc[1];\n\n    return x >= rootElem.left && x <= rootElem.right && y >= rootElem.top && y <= rootElem.bottom;\n  }\n\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/map-renderer/map-style.scss",
    "content": "::ng-deep {\n  .pin {\n    opacity: 0;\n\n    &.in-view {\n      opacity: 1;\n    }\n  }\n}\n\n::ng-deep #spn-map {\n  --map-bg: #111112;\n  --map-country-active: #424141;\n  --map-country-inactive: #2a2a2a;\n  --map-country-border-width: 2px;\n  --map-country-border-color: #1e1e1e;\n  --map-country-border-color-selected: #858585;\n  --map-country-blocked-primary: #858585;\n  --map-country-blocked-secondary: #402323;\n\n  .overlay {\n    fill: none;\n    pointer-events: all;\n  }\n\n  g {\n\n    circle,\n    polygon {\n      fill: #626262;\n      stroke: #626262;\n      stroke-width: 1;\n      stroke-linejoin: round;\n      transition: all 200ms linear 0s;\n    }\n\n    circle:hover,\n    polygon:hover {\n      fill: theme('colors.yellow.200');\n      stroke: theme('colors.yellow.300');\n      stroke-width: 2;\n    }\n  }\n\n  g[in-use=true] {\n    circle {\n      fill: #239215;\n      stroke: #239215;\n      transform: scale(1.15)\n    }\n\n    polygon {\n      fill: #0376bb;\n      stroke: #0376bb;\n      transform: scale(1.15)\n    }\n  }\n\n  g[is-exit=true] {\n\n    circle,\n    polygon {\n      transform: scale(1.3);\n      stroke-width: 2;\n    }\n\n    polygon {\n      stroke: #039af4;\n      fill: #0376bb;\n    }\n\n    circle {\n      stroke: #30ae20;\n      fill: #239215;\n    }\n  }\n\n  g[is-home=true] circle {\n    stroke: white;\n    stroke-width: 4.5;\n    fill: black;\n    transform: scale(1);\n  }\n\n  g[raise=true] {\n\n    circle,\n    polygon {\n      fill: theme('colors.yellow.200');\n      stroke: theme('colors.yellow.300');\n      stroke-width: 2;\n      transform: scale(1.8);\n    }\n  }\n\n  .marker {\n    cursor: pointer;\n    fill: #252525;\n    stroke: rgba(151, 151, 151, 0.8);\n    transition: all 250ms 0s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n  }\n\n  .marker-label {\n    fill: white;\n  }\n\n  path.lane {\n    stroke: rgba(151, 151, 151, 0.2);\n    fill: transparent;\n\n    &[in-use=true] {\n      stroke-width: 2;\n      stroke: #0376bb;\n    }\n\n    &[is-live=true] {\n      stroke-width: 1;\n      stroke: theme('colors.red.300');\n\n      &[is-encrypted=true] {\n        stroke: theme('colors.green.200');\n      }\n\n      &:hover {\n        stroke-width: 3;\n      }\n    }\n  }\n\n  #world-group {\n    path {\n      fill: var(--map-country-border-color);\n      stroke: var(--map-country-border-color);\n      stroke-width: var(--map-country-border-width);\n      stroke-linejoin: round;\n    }\n\n    path[has-nodes=true] {\n      fill: var(--map-country-inactive);\n    }\n\n    path[in-use=true] {\n      fill: var(--map-country-active);\n    }\n\n    path:hover {\n      cursor: pointer;\n      fill: var(--map-country-active);\n    }\n\n    path.selected {\n      stroke: var(--map-country-border-color-selected);\n    }\n  }\n}\n\n:host-context(.disabled) {\n  @apply bg-white;\n\n  #world-group {\n    path {\n      fill: #000000;\n      stroke: #111111;\n      stroke-width: .5px;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/map.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { AppProfile, GeoCoordinates, IntelEntity, Netquery, Pin, SPNService, UnknownLocation, getPinCoords } from '@safing/portmaster-api';\nimport { BehaviorSubject, Observable, combineLatest, debounceTime, interval, of, startWith, switchMap } from 'rxjs';\nimport { distinctUntilChanged, filter, map, share } from 'rxjs/operators';\nimport { SPNStatus } from './../../../../projects/safing/portmaster-api/src/lib/spn.types';\n\nexport interface MapPin {\n  pin: Pin;\n  // location is set to the geo-coordinates that should be used\n  // for that pin.\n  location: GeoCoordinates;\n  // entity is set to the intel entity that should be used for\n  // this pin.\n  entity: IntelEntity;\n\n  // whether the pin is regarded as offline / not available.\n  isOffline: boolean;\n\n  // whether or not the pin is currently used as an exit node\n  isExit: boolean;\n\n  // whether or not the pin is used as a transit node\n  isTransit: boolean;\n\n  // whether or not the pin is currently active.\n  isActive: boolean;\n\n  // whether or not the pin is used as the entry-node.\n  isHome: boolean;\n\n  // whether the pin has any known issues\n  hasIssues: boolean;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class MapService {\n  /**\n   * activeSince$ emits the pre-formatted duration since the SPN is active\n   * it formats the duration as \"HH:MM:SS\" or null if the SPN is not enabled.\n   */\n  activeSince$: Observable<string | null>;\n\n  /** Emits the current status of the SPN */\n  status$: Observable<SPNStatus['Status']>;\n\n  /** Emits all map pins */\n  _pins$ = new BehaviorSubject<MapPin[]>([]);\n\n  get pins$(): Observable<MapPin[]> {\n    return this._pins$.asObservable();\n  }\n\n  pinsMap$ = this.pins$\n    .pipe(\n      filter(allPins => !!allPins.length),\n      map(allPins => {\n        const lm = new Map<string, MapPin>();\n        allPins.forEach(pin => lm.set(pin.pin.ID, pin));\n\n        return lm\n      }),\n      share(),\n    )\n\n  constructor(\n    private spnService: SPNService,\n    private netquery: Netquery,\n  ) {\n    this.status$ = this.spnService\n      .status$\n      .pipe(\n        map(status => !!status ? status.Status : 'disabled'),\n        distinctUntilChanged()\n      );\n\n    // setup the activeSince$ observable that emits every second how long the\n    // SPN has been active.\n    this.activeSince$ = combineLatest([\n      this.spnService.status$,\n      interval(1000).pipe(startWith(-1))\n    ]).pipe(\n      map(([status]) => !!status.ConnectedSince ? this.formatActiveSinceDate(status.ConnectedSince) : null),\n      share(),\n    );\n\n    let pinMap = new Map<string, MapPin>();\n    let pinResult: MapPin[] = [];\n\n    // create a stream of pin updates from the SPN service if it is enabled.\n    this.status$\n      .pipe(\n        switchMap(status => {\n          if (status !== 'disabled') {\n            return combineLatest([\n              this.spnService.watchPins(),\n              interval(5000)\n                .pipe(\n                  startWith(-1),\n                  switchMap(() => this.getPinIDsUsedAsExit())\n                )\n            ])\n          }\n          return of([[], []]);\n        }),\n        map(([pins, exitPinIDs]) => {\n          const exitPins = new Set(exitPinIDs);\n          const activePins = new Set<string>();\n          const transitPins = new Set<string>();\n          const seenPinIDs = new Set<string>();\n\n          let hasChanges = false;\n\n          pins.forEach(pin => pin.Route?.forEach((hop, index) => {\n            if (index < pin.Route!.length - 1) {\n              transitPins.add(hop)\n            }\n\n            activePins.add(hop);\n          }));\n\n          pins.forEach(pin => {\n            // Save Pin ID as seen.\n            seenPinIDs.add(pin.ID);\n\n            const oldPinModel = pinMap.get(pin.ID);\n\n            // Get states of new model.\n            const isOffline = pin.States.includes('Offline') || !pin.States.includes('Reachable');\n            const isHome = pin.HopDistance === 1;\n            const isTransit = transitPins.has(pin.ID);\n\n            const isExit = exitPins.has(pin.ID);\n            const isActive = activePins.has(pin.ID);\n            const hasIssues = pin.States.includes('ConnectivityIssues');\n\n            const pinHasChanged = !oldPinModel || oldPinModel.pin !== pin ||\n              oldPinModel.isOffline !== isOffline || oldPinModel.isHome !== isHome || oldPinModel.isTransit !== isTransit ||\n              oldPinModel.isExit !== isExit || oldPinModel.isActive !== isActive || oldPinModel.hasIssues !== hasIssues;\n\n            if (pinHasChanged) {\n              const newPinModel: MapPin = {\n                pin: pin,\n                location: getPinCoords(pin) || UnknownLocation,\n                entity: (pin.EntityV4 || pin.EntityV6)!,\n                isExit,\n                isTransit,\n                isActive,\n                isOffline,\n                isHome,\n                hasIssues,\n              }\n\n              pinMap.set(pin.ID, newPinModel);\n\n              hasChanges = true;\n            }\n          })\n\n          for (let key of pinMap.keys()) {\n            if (!seenPinIDs.has(key)) {\n              // this pin has been removed\n              pinMap.delete(key)\n              hasChanges = true;\n            }\n          }\n\n          if (hasChanges) {\n            pinResult = Array.from(pinMap.values());\n          }\n\n          return pinResult;\n        }),\n        debounceTime(10),\n        distinctUntilChanged(),\n      )\n      .subscribe(pins => this._pins$.next(pins))\n  }\n\n  getExitPinIDsForProfile(profile: AppProfile) {\n    return this.netquery\n      .query({\n        select: ['exit_node'],\n        groupBy: ['exit_node'],\n        query: {\n          profile: { $eq: `${profile.Source}/${profile.ID}` },\n        }\n      }, 'map-service-get-exit-pin-ids-for-profile')\n      .pipe(map(result => result.map(row => row.exit_node!)))\n  }\n\n  getPinIDsWithActiveSession() {\n    return this.pins$\n      .pipe(\n        map(result => result.filter(pin => pin.pin.SessionActive).map(pin => pin.pin.ID))\n      )\n  }\n\n  getPinIDsUsedAsExit() {\n    return this.netquery\n      .query({\n        select: ['exit_node'],\n        groupBy: ['exit_node']\n      }, 'map-service-get-pins-used-as-exit')\n      .pipe(\n        map(result => result.map(row => row.exit_node!))\n      )\n  }\n\n  getPinIDsWithActiveConnections() {\n    return this.netquery.query({\n      select: ['exit_node'],\n      groupBy: ['exit_node'],\n      query: {\n        active: { $eq: true }\n      }\n    }, 'map-service-get-pins-with-connections')\n      .pipe(\n        map(activeExitNodes => {\n          const pins = this._pins$.getValue();\n\n          const pinIDs = new Set<string>();\n          const pinLookupMap = new Map<string, MapPin>();\n\n          pins.forEach(p => pinLookupMap.set(p.pin.ID, p))\n\n          activeExitNodes.map(row => {\n            const pin = pinLookupMap.get(row.exit_node!);\n            if (!!pin) {\n              pin.pin.Route?.forEach(hop => {\n                pinIDs.add(hop)\n              })\n            }\n          })\n\n          return Array.from(pinIDs);\n        })\n      )\n  }\n\n  private formatActiveSinceDate(date: string): string {\n    const d = new Date(date);\n    const diff = Math.floor((new Date().getTime() - d.getTime()) / 1000);\n    const hours = Math.floor(diff / 3600);\n    const minutes = Math.floor((diff - (hours * 3600)) / 60);\n    const secs = diff - (hours * 3600) - (minutes * 60);\n    const pad = (d: number) => d < 10 ? `0${d}` : '' + d;\n\n    return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/node-icon/index.ts",
    "content": "export * from './node-icon';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/node-icon/node-icon.html",
    "content": "<svg *ngIf=\"bySafing\" class=\"inline-block\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" preserveAspectRation=\"none\"\n  height=\"16\">\n  <g transform=\"translate(9, 7)\">\n    <polygon class=\"{{ nodeClass }}\" points=\"0,-4 -4,4 4,4\"></polygon>\n  </g>\n</svg>\n<svg *ngIf=\"!bySafing\" class=\"inline-block\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" preserveAspectRation=\"none\"\n  height=\"16\">\n  <g transform=\"translate(9, 7)\">\n    <circle class=\"{{ nodeClass }}\" r=\"4\"></circle>\n  </g>\n</svg>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/node-icon/node-icon.scss",
    "content": "svg {\n\n  circle,\n  polygon {\n    fill: #626262;\n    stroke: #626262;\n    stroke-width: 1;\n    stroke-linejoin: round;\n    transition: all 200ms linear 0s;\n  }\n\n  polygon.active,\n  polygon.exit {\n    fill: #0376bb;\n    stroke: #0376bb;\n    transform: scale(1.15)\n  }\n\n  circle.active,\n  circle.exit {\n    fill: #239215;\n    stroke: #239215;\n    transform: scale(1.15)\n  }\n\n  circle.exit,\n  polygon.exit {\n    stroke-width: 2;\n  }\n\n  circle.exit {\n    stroke: #30ae20;\n  }\n\n  polygon.exit {\n    stroke: #039af4;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/node-icon/node-icon.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, Component, Input } from \"@angular/core\";\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'spn-node-icon',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  templateUrl: './node-icon.html',\n  styleUrls: ['./node-icon.scss'],\n})\nexport class SpnNodeIconComponent {\n  @Input()\n  set bySafing(v: any) {\n    this._bySafing = coerceBooleanProperty(v);\n  }\n  get bySafing() { return this._bySafing }\n  private _bySafing = false;\n\n  @Input()\n  set isActive(v: any) {\n    this._isActive = coerceBooleanProperty(v);\n  }\n  get isActive() { return this._isActive }\n  private _isActive = false;\n\n  @Input()\n  set isExit(v: any) {\n    this._isExit = coerceBooleanProperty(v);\n  }\n  get isExit() { return this._isExit; }\n  private _isExit = false;\n\n  get nodeClass() {\n    if (this._isExit) {\n      return 'exit';\n    }\n\n    if (this.isActive) {\n      return 'active'\n    }\n\n    return '';\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-details/index.ts",
    "content": "export * from './pin-details';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-details/pin-details.html",
    "content": "<h1 class=\"flex flex-row items-center gap-2 text-base\">\n  <span [appCountryFlags]=\"pin?.entity?.Country || ''\"></span>\n  {{ pin?.pin?.Name || 'N/A' }}\n  <span class=\"flex-grow\"></span>\n  <svg *ngIf=\"!!dialogRef\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"\n    stroke-width=\"2\" class=\"w-4 h-4 ml-2 opacity-75 cursor-pointer hover:opacity-100\" (click)=\"dialogRef.close()\">\n    <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\"></path>\n  </svg>\n</h1>\n\n<span class=\"text-sm inline-block mt-.5 mb-2 font-thin\" *ngIf=\"pin as pin\">\n  This SPN Node is run by\n  <svg sfng-tooltip=\"Verified operator: {{pin.pin.VerifiedOwner}}\" *ngIf=\"!!pin.pin.VerifiedOwner\"\n    xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n    class=\"inline-block w-4 h-4 mx-1 -mt-1 text-green-300\">\n    <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n      d=\"M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.745 3.745 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z\" />\n  </svg>\n  <span class=\"font-normal\">{{ pin.pin.VerifiedOwner || 'Community' }}</span>\n</span>\n\n<div *ngIf=\"pin?.isOffline\" class=\"text-sm mt-.5 mb-2 font-thin text-red-300\">\n  Node is Offline\n</div>\n<div *ngIf=\"pin?.hasIssues && !pin?.isOffline\" class=\"text-sm mt-.5 mb-2 font-thin text-yellow-300\">\n  Node has Issues\n</div>\n\n<sfng-tab-group *ngIf=\"pin as pin\" linkRouter=\"false\">\n  <sfng-tab id=\"details\" title=\"Details\">\n    <table *sfngTabContent class=\"custom\">\n      <tr>\n        <td class=\"p-2 font-thin\">ID</td>\n        <td>{{ pin.pin.ID }}</td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">Verified Owner</td>\n        <td>\n          <pre>{{ pin.pin.VerifiedOwner }}</pre>\n        </td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">First Seen</td>\n        <td>{{ pin.pin.FirstSeen | date:'medium' }}</td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">IPv4</td>\n        <td *ngIf=\"pin.pin.EntityV4 as entity\">\n          <div class=\"flex flex-col gap-1\">\n            <span class=\"text-primary\">\n              <span [appCountryFlags]=\"entity.Country\"></span>\n              {{ entity.ASOrg }}\n              <span class=\"font-thin text-tertiary\">({{ entity.ASN }})</span>\n            </span>\n            <span class=\"text-primary\">\n              {{ entity.IP || 'N/A' }}\n            </span>\n          </div>\n        </td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">IPv6</td>\n        <td *ngIf=\"pin.pin.EntityV6 as entity\">\n          <div class=\"flex flex-col gap-1\">\n            <span class=\"text-primary\">\n              <span [appCountryFlags]=\"entity.Country\"></span>\n              {{ entity.ASOrg }}\n              <span class=\"font-thin text-tertiary\">({{ entity.ASN }})</span>\n            </span>\n            <span class=\"text-primary\">\n              {{ entity.IP || 'N/A' }}\n            </span>\n          </div>\n        </td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">States</td>\n        <td>\n          <pre>{{ pin.pin.States.join(\", \") }}</pre>\n        </td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">SessionActive</td>\n        <td>\n          <pre>{{ pin.pin.SessionActive }}</pre>\n        </td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">HopDistance</td>\n        <td>\n          <pre>{{ pin.pin.HopDistance }}</pre>\n        </td>\n      </tr>\n      <tr>\n        <td class=\"p-2 font-thin\">Exit Connections</td>\n        <td>\n          <div class=\"flex flex-row items-center gap-2 cursor-pointer\" [routerLink]=\"['/monitor']\"\n            [queryParams]=\"{q: 'exit_node:' + pin.pin.ID}\" (click)=\"dialogRef?.close()\">\n            <pre>{{ exitConnectionCount }}</pre>\n            <svg viewBox=\"0 0 24 24\" class=\"w-4 h-4\" sfng-tooltip=\"Show exit connections in monitor.\"\n              *ngIf=\"exitConnectionCount > 0\">\n              <g fill=\"none\" stroke=\"currentColor\">\n                <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                  stroke-width=\"2\"\n                  d=\"M8.464 8.464c-1.953 1.953-1.953 5.118 0 7.071 1.953 1.953 5.118 1.953 7.071 0 1.953-1.953 1.953-5.119 0-7.071C14.559 7.488 13.28 7 12 7\" />\n                <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                  stroke-width=\"2\"\n                  d=\"M5.636 5.636c-3.515 3.515-3.515 9.213 0 12.728 3.515 3.515 9.213 3.515 12.728 0 3.515-3.515 3.515-9.213 0-12.728-2.627-2.627-6.474-3.289-9.717-1.989M5.64 5.64L12 12\" />\n              </g>\n            </svg>\n          </div>\n        </td>\n      </tr>\n    </table>\n  </sfng-tab>\n\n  <sfng-tab id=\"routeHome\" title=\"Route\" *ngIf=\"!!pin.pin.Route\">\n    <div *sfngTabContent>\n      <sfng-spn-pin-route [route]=\"pin.pin.Route\"></sfng-spn-pin-route>\n    </div>\n  </sfng-tab>\n\n  <sfng-tab id=\"connectedHubs\" title=\"Connected Nodes\">\n    <spn-pin-list *sfngTabContent [pins]=\"connectedPins\" allowHover=\"false\" allowClick=\"false\"></spn-pin-list>\n  </sfng-tab>\n\n</sfng-tab-group>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-details/pin-details.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, OnChanges, OnDestroy, OnInit, Optional, SimpleChanges } from '@angular/core';\nimport { Netquery } from '@safing/portmaster-api';\nimport { SFNG_DIALOG_REF, SfngDialogRef } from '@safing/ui';\nimport { Subscription, forkJoin, map, of, switchMap } from 'rxjs';\nimport { LaneModel } from '../pin-list/pin-list';\nimport { MapPin, MapService } from './../map.service';\n\n@Component({\n  templateUrl: './pin-details.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PinDetailsComponent implements OnInit, OnChanges, OnDestroy {\n  private subscription = Subscription.EMPTY;\n\n  @Input()\n  mapPinID!: string;\n\n  pin: MapPin | null = null;\n\n  /** Holds all pins this pin has a active connection to */\n  connectedPins: LaneModel[] = [];\n\n  /** The number of connections that exit at this pin */\n  exitConnectionCount: number = 0;\n\n  constructor(\n    private mapService: MapService,\n    private netquery: Netquery,\n    private cdr: ChangeDetectorRef,\n    @Optional() @Inject(SFNG_DIALOG_REF) public dialogRef?: SfngDialogRef<PinDetailsComponent, never, string>,\n  ) { }\n\n  ngOnInit(): void {\n    // if we got opened via a dialog we get the map pin ID from the dialog data.\n    if (!!this.dialogRef) {\n      this.mapPinID = this.dialogRef.data;\n    }\n\n    this.subscription.unsubscribe();\n\n    this.subscription = this.mapService\n      .pins$\n      .pipe(\n        map(pins => {\n          return [pins.find(p => p.pin.ID === this.mapPinID), pins] as [MapPin, MapPin[]];\n        }),\n        switchMap(([pin, allPins]) => forkJoin({\n          pin: of(pin),\n          allPins: of(allPins),\n          exitConnections: this.netquery.query({\n            select: [\n              { $count: { field: '*', as: 'totalCount', } },\n            ],\n            query: {\n              exit_node: pin.pin.ID,\n            },\n            groupBy: ['exit_node']\n          }, 'pin-details-get-connections-per-exit-node')\n        }))\n      )\n      .subscribe((result) => {\n        this.pin = result.pin || null;\n\n        const lm = new Map<string, MapPin>();\n        result.allPins.forEach(pin => lm.set(pin.pin.ID, pin))\n\n        const connectedTo = this.pin?.pin.ConnectedTo || {};\n        this.connectedPins = Object.keys(connectedTo)\n          .map(pinID => {\n            const pin = lm.get(pinID)!;\n            return {\n              ...connectedTo[pinID],\n              mapPin: pin,\n            }\n          });\n\n        if (result.exitConnections.length) {\n          // we expect only one row to be returned for the above query.\n          this.exitConnectionCount = result.exitConnections[0].totalCount;\n        } else {\n          this.exitConnectionCount = 0;\n        }\n\n        this.cdr.markForCheck();\n      })\n  }\n\n  ngOnChanges(changes: SimpleChanges) {\n    // if we got rendered directly (without a dialog) we need to\n    // handle updates to the mapPinID input field by re-loading the\n    // pin details. We do that by simply re-running ngOnInit\n    if (!!changes['mapPinID']) {\n      this.ngOnInit()\n    }\n  }\n\n  ngOnDestroy(): void {\n    this.subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-list/index.ts",
    "content": ""
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-list/pin-list.html",
    "content": "<table>\n  <thead>\n    <th>Name</th>\n    <th><span class=\"pl-5\">Operator</span></th>\n    <th>Used As</th>\n    <th *ngIf=\"!!lanes\">Latency</th>\n    <th *ngIf=\"!!lanes\">Capacity</th>\n    <th>IPv4</th>\n    <th>IPv6</th>\n    <th *ngIf=\"allowClick\"></th>\n  </thead>\n  <tbody>\n    <tr class=\"border-l-2 border-transparent\" [ngClass]=\"{'hover:border-l-yellow-300': allowHover}\"\n      *ngFor=\"let pin of pins; trackBy: trackPin\" (mouseenter)=\"pinHover.next(pin.pin.ID)\"\n      (mouseleave)=\"pinHover.next(null)\">\n      <td>\n        <spn-node-icon [bySafing]=\"pin.pin.VerifiedOwner === 'Safing'\" [isExit]=\"pin.isExit\" [isActive]=\"pin.isActive\">\n        </spn-node-icon>\n        {{ pin.pin.Name }}\n      </td>\n\n      <td>\n        <div class=\"flex flex-row items-center gap-1 text-secondary\">\n          <svg sfng-tooltip=\"Verified operator: {{pin.pin.VerifiedOwner}}\" *ngIf=\"!!pin.pin.VerifiedOwner\"\n            xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n            class=\"inline-block w-4 h-4 -mt-1 text-green-300\">\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n              d=\"M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.745 3.745 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z\" />\n          </svg>\n          <span [ngClass]=\"{'pl-5': !pin.pin.VerifiedOwner}\">\n            {{ pin.pin.VerifiedOwner || 'Community' }}\n          </span>\n        </div>\n      </td>\n\n      <td>\n        <div class=\"flex flex-row items-center gap-2\">\n\n          <!-- Home Node Icon -->\n          <svg sfng-tooltip=\"Home Node\" *ngIf=\"pin.isHome\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\"\n            viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4 text-blue\">\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 10.5a3 3 0 11-6 0 3 3 0 016 0z\" />\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n              d=\"M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z\" />\n          </svg>\n\n\n          <!-- Exit Node Icon -->\n          <svg sfng-tooltip=\"Exit Node\" *ngIf=\"pin.isExit\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\"\n            viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4 text-blue\">\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n              d=\"M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z\" />\n          </svg>\n\n          <!-- Transit Node Icon -->\n          <svg sfng-tooltip=\"Transit Node\" *ngIf=\"pin.isTransit && !pin.isHome\" xmlns=\"http://www.w3.org/2000/svg\"\n            fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-4 h-4 text-blue\">\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n              d=\"M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88\" />\n          </svg>\n        </div>\n      </td>\n\n      <ng-container *ngIf=\"!!lanes && lanes.get(pin.pin.ID) as val\">\n        <td>\n          {{ val.Latency / 1000 / 1000 | number:'1.0-2' }} ms\n        </td>\n        <td>\n          {{ val.Capacity / 1000 / 1000 | number:'1.0-2' }} Mbit/s\n        </td>\n      </ng-container>\n\n      <td>{{ pin.pin.EntityV4?.IP || 'N/A' }}</td>\n      <td>{{ pin.pin.EntityV6?.IP || 'N/A' }}</td>\n      <td *ngIf=\"allowClick\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n          class=\"w-4 h-4 cursor-pointer text-secondary hover:text-primary\" (click)=\"pinClick.next(pin.pin.ID)\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n            d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\" />\n        </svg>\n      </td>\n    </tr>\n  </tbody>\n</table>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-list/pin-list.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, TrackByFunction } from '@angular/core';\nimport { Lane } from '@safing/portmaster-api';\nimport { take } from 'rxjs/operators';\nimport { MapPin } from '../map.service';\nimport { MapService } from './../map.service';\n\nexport interface LaneModel extends Lane {\n  mapPin: MapPin;\n}\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'spn-pin-list',\n  templateUrl: './pin-list.html',\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SpnPinListComponent {\n  @Input()\n  set allowHover(v: any) {\n    this._allowHover = coerceBooleanProperty(v);\n  }\n  get allowHover() { return this._allowHover }\n  private _allowHover = true;\n\n  @Input()\n  set allowClick(v: any) {\n    this._allowClick = coerceBooleanProperty(v);\n  }\n  get allowClick() { return this._allowClick }\n  private _allowClick = true;\n\n  @Input()\n  set pins(pins: (string | MapPin | LaneModel)[]) {\n    this.mapService\n      .pinsMap$\n      .pipe(take(1))\n      .subscribe(allPins => {\n        this.lanes = null;\n\n        this._pins = (pins || []).map(idOrPin => {\n          if (typeof idOrPin === 'string') {\n            return allPins.get(idOrPin)!;\n          }\n\n          if ('mapPin' in idOrPin) { // LaneModel\n            if (this.lanes === null) {\n              this.lanes = new Map();\n            }\n\n            this.lanes.set(idOrPin.HubID, {\n              Capacity: idOrPin.Capacity,\n              Latency: idOrPin.Latency,\n            })\n\n            return idOrPin.mapPin;\n          }\n\n          return idOrPin; // MapPin\n        })\n\n        this.cdr.markForCheck();\n      })\n  }\n  get pins(): MapPin[] {\n    return this._pins;\n  }\n  private _pins: MapPin[] = [];\n\n  /** If we got LaneModel in @Input() pins than this will contain a map with the capacity/latency */\n  lanes: Map<string, Pick<LaneModel, 'Capacity' | 'Latency'>> | null = null;\n\n  /** Emits the ID of the pin that got hovered, null if the mouse left a pin */\n  @Output()\n  pinHover = new EventEmitter<string | null>();\n\n  @Output()\n  pinClick = new EventEmitter<string>();\n\n  /** @private - A {@link TrackByFunction} for all pins available in this country */\n  trackPin: TrackByFunction<MapPin> = (_: number, pin: MapPin) => pin.pin.ID;\n\n  constructor(\n    private mapService: MapService,\n    private cdr: ChangeDetectorRef\n  ) { }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-overlay/index.ts",
    "content": "export * from './pin-overlay';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-overlay/pin-overlay.html",
    "content": "<div *ngIf=\"showContent\" [@moveIn]=\"{value: ':enter', params: {delay: delay}}\"\n  (@moveIn.done)=\"onAnimationComplete($event)\"\n  class=\"flex flex-col items-start justify-start gap-2 p-2 bg-gray-200 border border-gray-500 border-opacity-50 rounded-sm {{ containerClass }}\"\n  cdkDrag (cdkDragReleased)=\"onDragRelease($event)\" (cdkDragStart)=\"onDragStart()\">\n  <div class=\"flex flex-row items-center justify-start w-full gap-1\">\n    <app-menu #pinUseMenu>\n      <app-menu-item (click)=\"openPinDetails()\">Show Details</app-menu-item>\n      <app-menu-item (click)=\"showExitConnections()\">Show exit connections</app-menu-item>\n      <app-menu-item (click)=\"copyNodeID()\">Copy Node ID</app-menu-item>\n    </app-menu>\n    <app-menu-trigger class=\"mr-0 -ml-2\" useContent=\"true\" [menu]=\"pinUseMenu\">\n      <span class=\"flex flex-row items-center gap-1 -ml-2 -mr-2\">\n        <span [appCountryFlags]=\"mapPin.entity.Country\"></span>\n        <span>{{ mapPin.pin.Name }}</span>\n\n        <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"w-4 h-4\">\n          <path fill-rule=\"evenodd\"\n            d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n            clip-rule=\"evenodd\" />\n        </svg>\n      </span>\n    </app-menu-trigger>\n\n    <span class=\"flex-grow\">\n      <!-- flexible padding -->\n    </span>\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-4 h-4 opacity-75 hover:opacity-100\" cdkDragHandle (dblclick)=\"onDragDblClick()\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15\" />\n    </svg>\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"\n      class=\"w-4 h-4 ml-2 opacity-75 cursor-pointer hover:opacity-100\" (click)=\"disposeOverlay()\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\"></path>\n    </svg>\n  </div>\n  <div class=\"space-x-2\">\n    <span class=\"inline-block w-12 font-thin text-secondary\">IPv4</span>\n    <span>{{ mapPin.pin.EntityV4?.IP  || 'N/A' }}</span>\n  </div>\n  <div class=\"space-x-2\">\n    <span class=\"inline-block w-12 font-thin text-secondary\">IPv6</span>\n    <span>{{ mapPin.pin.EntityV6?.IP  || 'N/A' }}</span>\n  </div>\n  <div class=\"flex flex-row items-center gap-2\">\n    <span class=\"inline-block w-12 font-thin text-secondary\">Run By</span>\n\n    <span class=\"inline-flex flex-row items-center gap-1\">\n      <svg *ngIf=\"!!mapPin.pin.VerifiedOwner\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\"\n        stroke-width=\"1.5\" stroke=\"currentColor\" class=\"inline-block w-4 h-4 -mt-1 text-green-300\">\n        <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n          d=\"M9 12.75L11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 01-1.043 3.296 3.745 3.745 0 01-3.296 1.043A3.745 3.745 0 0112 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 01-3.296-1.043 3.745 3.745 0 01-1.043-3.296A3.745 3.745 0 013 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 011.043-3.296 3.746 3.746 0 013.296-1.043A3.746 3.746 0 0112 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 013.296 1.043 3.746 3.746 0 011.043 3.296A3.745 3.745 0 0121 12z\" />\n      </svg>\n\n      <span>{{ mapPin.pin.VerifiedOwner || 'Community' }}</span>\n    </span>\n  </div>\n  <div class=\"flex flex-row items-start w-full gap-2 \" *ngIf=\"mapPin.isExit || mapPin.isHome || mapPin.isTransit\">\n    <span class=\"inline-block w-12 font-thin text-secondary\">Used As</span>\n\n    <div class=\"inline-flex flex-col flex-grow gap-1\">\n      <span class=\"flex flex-row items-center w-full gap-1\" *ngIf=\"mapPin.isHome\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n          class=\"w-4 h-4 text-blue\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15 10.5a3 3 0 11-6 0 3 3 0 016 0z\" />\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n            d=\"M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z\" />\n        </svg>\n\n        <span class=\"flex-grow\">Home Node</span>\n        <ng-container\n          *ngTemplateOutlet=\"helpText; context: {$implicit: 'This node does not know the destinations of you connections but may know where you are'}\">\n        </ng-container>\n      </span>\n\n      <span class=\"flex flex-row items-center w-full gap-1\" *ngIf=\"mapPin.isExit\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n          class=\"w-4 h-4 text-blue\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n            d=\"M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z\" />\n        </svg>\n\n        <span class=\"flex-grow\">Exit Node</span>\n        <ng-container\n          *ngTemplateOutlet=\"helpText; context: {$implicit: 'This node does not know who you are but knows the destination of connections for which it is used as an exit node'}\">\n        </ng-container>\n      </span>\n\n      <span class=\"flex flex-row items-center w-full gap-1\" *ngIf=\"mapPin.isTransit && !mapPin.isHome\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n          class=\"w-4 h-4 text-blue\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n            d=\"M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88\" />\n        </svg>\n\n        <span class=\"flex-grow\">Transit Node</span>\n        <ng-container\n          *ngTemplateOutlet=\"helpText; context: {$implicit: 'This node does not know who you are and where you are connecting to'}\">\n        </ng-container>\n      </span>\n\n    </div>\n  </div>\n</div>\n\n<ng-template #helpText let-data>\n  <svg viewBox=\"0 0 24 24\" [sfng-tooltip]=\"data\" class=\"w-4 h-4 text-tertiary\">\n    <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\">\n      <path stroke=\"#ffff\" shape-rendering=\"geometricPrecision\"\n        d=\"M12 21v0c-4.971 0-9-4.029-9-9v0c0-4.971 4.029-9 9-9v0c4.971 0 9 4.029 9 9v0c0 4.971-4.029 9-9 9z\" />\n      <path stroke=\"#ffff\" shape-rendering=\"geometricPrecision\"\n        d=\"M12 17v-5h-1M11.749 8c-.138 0-.25.112-.249.25 0 .138.112.25.25.25s.25-.112.25-.25-.112-.25-.251-.25\" />\n    </g>\n  </svg>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-overlay/pin-overlay.scss",
    "content": ":host {\n  min-width: 220px;\n  display: block;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-overlay/pin-overlay.ts",
    "content": "import { AnimationEvent, animate, keyframes, style, transition, trigger } from '@angular/animations';\nimport { CdkDrag, CdkDragHandle, CdkDragRelease } from '@angular/cdk/drag-drop';\nimport { Overlay, OverlayRef, PositionStrategy } from '@angular/cdk/overlay';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostListener, Inject, Input, OnInit, Output, ViewChild, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { SfngDialogService } from '@safing/ui';\nimport { PinDetailsComponent } from '../pin-details';\nimport { MapOverlay, Path } from '../spn-page';\nimport { ActionIndicatorService } from './../../../shared/action-indicator/action-indicator.service';\nimport { MapPin } from './../map.service';\nimport { OVERLAY_REF } from './../utils';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\n\nexport interface PinOverlayHoverEvent {\n  type: 'enter' | 'leave';\n  pinID: string;\n}\n\n@Component({\n  templateUrl: './pin-overlay.html',\n  styleUrls: [\n    './pin-overlay.scss'\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    trigger('moveIn', [\n      transition(':enter', [\n        style({ transform: 'scale(0)', transformOrigin: 'top left' }),\n        animate('200ms {{ delay }}ms cubic-bezier(0, 0, 0.2, 1)',\n          keyframes([\n            style({ transform: 'scaleX(1) scaleY(0.1)', transformOrigin: 'top left', offset: 0.3 }),\n            style({ transform: 'scaleX(1) scaleY(1)', transformOrigin: 'top left', offset: 0.8 }),\n          ])\n        )\n      ], { params: { delay: \"0\" } }),\n      transition(':leave', [\n        style({ transform: 'scale(1)', opacity: 1, transformOrigin: 'top left' }),\n        animate('500ms cubic-bezier(0, 0, 0.2, 1)',\n          keyframes([\n            style({ transform: 'scaleX(1) scaleY(0.1)', opacity: 0.5, transformOrigin: 'top left', offset: 0.3 }),\n            style({ transform: 'scaleX(0) scaleY(0)', opacity: 0, transformOrigin: 'top left', offset: 0.8 }),\n          ])\n        )\n      ])\n    ])\n  ]\n})\nexport class PinOverlayComponent implements OnInit {\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  @Input()\n  mapPin!: MapPin;\n\n  @Input()\n  routeHome?: Path;\n\n  @Input()\n  additionalPaths?: Path[] = [];\n\n  @Input()\n  delay: number = 0;\n\n  @Output()\n  afterDispose = new EventEmitter<string>();\n\n  @Output()\n  overlayHover = new EventEmitter<PinOverlayHoverEvent>();\n\n  @ViewChild(CdkDrag)\n  dragContainer!: CdkDrag;\n\n  @ViewChild(CdkDragHandle)\n  dragHandle!: CdkDragHandle;\n\n  showContent = false;\n\n  /** Indicates whether or not the pin overlay has been moved by the user */\n  hasBeenMoved = false;\n\n  private oldPositionStrategy?: PositionStrategy;\n\n  @HostListener('mouseenter')\n  onHostElementMouseEnter(event: MouseEvent) {\n    this.overlayHover.next({\n      type: 'enter',\n      pinID: this.mapPin.pin.ID\n    })\n\n    this.containerClass = '';\n  }\n\n  @HostListener('mouseleave')\n  onHostElementMouseLeave(event: MouseEvent) {\n    this.overlayHover.next({\n      type: 'leave',\n      pinID: this.mapPin.pin.ID\n    })\n\n    this.containerClass = 'bg-opacity-90'\n  }\n\n  /** on double-click, restore the old pin overlay position (before being initialy dragged by the user) */\n  onDragDblClick() {\n    if (!!this.oldPositionStrategy) {\n      this.overlayRef.updatePositionStrategy(this.oldPositionStrategy);\n      this.overlayRef.updatePosition();\n      this.hasBeenMoved = false;\n    }\n  }\n\n  onDragStart() {\n    this.containerClass = 'outline'\n  }\n\n  openPinDetails() {\n    this.dialog.create(PinDetailsComponent, {\n      data: this.mapPin.pin.ID,\n      autoclose: true,\n      backdrop: false,\n      dragable: true,\n    })\n  }\n\n  onDragRelease(event: CdkDragRelease) {\n    if (!this.dragContainer || !this.overlayRef.hostElement || !this.overlayRef.hostElement.parentElement) {\n      return;\n    }\n\n    const bbox = this.dragContainer.element.nativeElement.getBoundingClientRect();\n    const parent = this.overlayRef.hostElement.parentElement!.getBoundingClientRect();\n\n    if (!this.oldPositionStrategy) {\n      this.oldPositionStrategy = this.overlayRef.getConfig().positionStrategy;\n    }\n\n    this.containerClass = '';\n\n    this.dragContainer.reset()\n\n    this.overlayRef.updatePositionStrategy(\n      this.overlay.position()\n        .global()\n        .top((bbox.top - parent.top) + 'px')\n        .left((bbox.left - parent.left) + 'px')\n    );\n\n    this.hasBeenMoved = true;\n  }\n\n  onAnimationComplete(event: AnimationEvent) {\n    if (event.toState === 'void') {\n      this.afterDispose.next(this.mapPin.pin.ID)\n      this.overlayRef.dispose();\n    }\n  }\n\n  containerClass = '';\n\n  constructor(\n    @Inject(OVERLAY_REF) public readonly overlayRef: OverlayRef,\n    @Inject(MapOverlay) public overlay: Overlay,\n    private dialog: SfngDialogService,\n    private actionIndicator: ActionIndicatorService,\n    private router: Router,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  ngOnInit(): void {\n    this.showContent = true;\n    this.cdr.markForCheck();\n  }\n\n  disposeOverlay() {\n    this.showContent = false;\n    this.cdr.markForCheck();\n  }\n\n  showExitConnections() {\n    this.router.navigate(['/monitor'], {\n      queryParams: {\n        q: 'exit_node:' + this.mapPin.pin.ID\n      }\n    })\n  }\n\n  async copyNodeID() {\n    await this.integration.writeToClipboard(this.mapPin?.pin.ID)\n    this.actionIndicator.success(\"Copied to Clipboard\")\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-route/index.ts",
    "content": "export * from './pin-route';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-route/pin-route.html",
    "content": "<span class=\"tunnel-path\">\n  <div class=\"line\">\n    <!--<span class=\"arrow\"></span>-->\n  </div>\n  <ul>\n    <li>\n      <span class=\"hop-icon\">\n        <fa-icon far icon=\"dot-circle\"></fa-icon>\n      </span>\n      <span class=\"hop-title text-tertiary\">\n        Your Device\n      </span>\n    </li>\n\n    <li *ngFor=\"let node of route; let first=first; let last=last\">\n      <span *ngIf=\"node.entity.Country as country; else: noCountry\" class=\"country\" [appCountryFlags]=\"country\"></span>\n      <ng-template #noCountry>\n        <!-- TODO: use hop icon instead if unknown -->\n        <span class=\"country unknown\"></span>\n      </ng-template>\n      <span>{{ node.entity.Country || 'No Location' }}</span>\n      <span class=\"ip text-tertiary\">{{ node.entity.IP || ''\n        }}</span>\n      <span class=\"node-tag\" *ngIf=\"first\">Home</span>\n      <span class=\"node-tag\" *ngIf=\"last\">Exit</span>\n      <span *appExpertiseLevel=\"'expert'\" class=\"text-tertiary\"><br />{{ node.pin.Name }}\n\n        <span class=\"ml-2\">\n          by\n          <spn-node-icon [bySafing]=\"node.pin.VerifiedOwner === 'Safing'\" isActive=\"true\" isExit=\"last\"></spn-node-icon>\n          {{ node.pin.VerifiedOwner || 'Community' }}\n        </span>\n      </span>\n\n      <span *appExpertiseLevel=\"'expert'\" class=\"text-tertiary\"><br />AS{{ node.entity.ASN }} - {{ node.entity.ASOrg ||\n          'AS Organization not in DB'\n          }}</span>\n\n      <span *appExpertiseLevel=\"'developer'\" class=\"text-tertiary\"><br />{{ node.pin.ID }}</span>\n    </li>\n\n    <li>\n      <span class=\"hop-icon\">\n        <fa-icon far icon=\"dot-circle\"></fa-icon>\n        <!-- TODO: use destination country flag instead if known -->\n      </span>\n      <span class=\"hop-title text-tertiary\">\n        Destination\n      </span>\n      <!-- TODO: add destination details? (Would be duplicate information from above.) -->\n    </li>\n  </ul>\n</span>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-route/pin-route.scss",
    "content": ".tunnel-path {\n  position: relative;\n\n  .line {\n    position: absolute;\n    top: 10px;\n    bottom: 10px;\n    left: 8px;\n    width: 1px;\n    background-color: rgba(255, 255, 255, 0.1);\n  }\n\n  .node-tag {\n    border-radius: 1px solid rgba(255, 255, 255, 0.2);\n    background-color: rgba(255, 255, 255, 0.1);\n    padding: 2px;\n    font-size: 85%;\n    border-radius: 2px;\n    transform: scale(0.85);\n    display: inline-block;\n  }\n\n  ul {\n    position: relative;\n    padding-left: 20px;\n\n    li:not(:last-of-type) {\n      padding-bottom: 0.35rem;\n    }\n\n    .ip {\n      margin-left: 0.35rem;\n    }\n\n    .hop-icon {\n      display: inline-block;\n      margin-left: -17px;\n      margin-right: 4px;\n      font-weight: 400;\n\n      &.country {\n        margin-left: -20px;\n      }\n    }\n\n    .hop-title {\n      margin-right: 2px;\n    }\n\n    .country {\n      display: inline-block;\n      margin-left: -20px;\n      margin-right: 4px;\n\n      &.unknown {\n        height: 14px;\n        width: 16px;\n        position: relative;\n        top: 3px;\n        border: 1px solid rgba(0, 0, 0, 0.25);\n        opacity: 0.5;\n        border-radius: 3px;\n        @apply bg-buttons-icon;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/pin-route/pin-route.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from \"@angular/core\";\nimport { TunnelNode } from \"@safing/portmaster-api\";\nimport { take } from 'rxjs';\nimport { MapPin, MapService } from './../map.service';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'sfng-spn-pin-route',\n  templateUrl: './pin-route.html',\n  styleUrls: ['./pin-route.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SpnPinRouteComponent {\n  @Input()\n  set route(path: (string | MapPin | TunnelNode)[] | null) {\n    this.mapService\n      .pinsMap$\n      .pipe(\n        take(1),\n      )\n      .subscribe(lm => {\n        this._route = (path || []).map(idOrPin => {\n          if (typeof idOrPin === 'string') {\n            return lm.get(idOrPin)!;\n          }\n\n          if ('ID' in idOrPin) { // TunnelNode\n            return lm.get(idOrPin.ID)!\n          }\n\n          return idOrPin;\n        });\n\n        this.cdr.markForCheck();\n      })\n  }\n  get route(): MapPin[] {\n    return this._route\n  }\n  private _route: MapPin[] = [];\n\n  constructor(\n    private mapService: MapService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn-feature-carousel/index.ts",
    "content": "export * from './spn-feature-carousel';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn-feature-carousel/spn-feature-carousel.html",
    "content": "<div class=\"flex flex-row items-center self-stretch gap-2\">\n  <svg (click)=\"showPrev()\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n    stroke=\"currentColor\"\n    class=\"flex-shrink-0 w-8 h-8 text-opacity-50 cursor-pointer text-background hover:text-background\">\n    <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5L8.25 12l7.5-7.5\" />\n  </svg>\n\n  <sfng-tab-group #tabs customHeader=\"true\" outletClass=\"overflow-visible\" class=\"flex-grow\">\n    <sfng-tab>\n      <section *sfngTabContent>\n        <div>\n          <h1>Get\n            Multiple Identities for Each App</h1>\n          <span>\n            Automatically get a vast amount of identities (IP addresses). The SPN calculates an individual path for\n            every\n            connection through the privacy network. Spread your connections across the globe, without any effort.\n          </span>\n        </div>\n        <img src=\"/assets/img/spn-feature-carousel/multiple-identities-for-each-app.png\">\n      </section>\n    </sfng-tab>\n\n    <!-- <sfng-tab>\n      <section *sfngTabContent class=\"reverse\">\n        <div>\n          <h1>Simply Access Regional Content</h1>\n          <span>\n            Is a website blocked or restricted in your country? Because SPN makes that connection exit near the\n            destination server, it will automatically unblock the content. SPN has best coverage in Europe and North\n            America.\n          </span>\n        </div>\n        <img src=\"/assets/img/spn-feature-carousel/access-regional-content-easily.png\">\n      </section>\n    </sfng-tab> -->\n\n    <sfng-tab>\n      <section *sfngTabContent>\n        <div>\n          <h1>Easily Adjust <span class=\"text-blue\">Your Privacy</span></h1>\n          <span>\n            SPN just works and does the heavy lifting for you. But of course you can easily configure the settings, so\n            it fits your needs: Exclude certain apps and domains from the SPN. Or never exit in specific countries. And\n            so much more...\n          </span>\n        </div>\n        <img src=\"/assets/img/spn-feature-carousel/easily-control-your-privacy.png\">\n      </section>\n    </sfng-tab>\n\n    <sfng-tab>\n      <section *sfngTabContent class=\"reverse\">\n        <div>\n          <h1>Built from Scratch, for <span class=\"text-blue\">Your Privacy</span></h1>\n          <span>\n            SPN is built from the ground up. Privacy is cooked right into it. Inspired by Tor, it comes with onion\n            routing and state of the art encryption. Fully open source so all our claims can be validated.\n          </span>\n        </div>\n        <img class=\"-top-16\" src=\"/assets/img/spn-feature-carousel/built-from-the-ground-up.png\">\n      </section>\n    </sfng-tab>\n\n    <sfng-tab>\n      <section *sfngTabContent>\n        <div>\n          <h1>Bye Bye, VPNs</h1>\n          <span>\n            VPN technology was NOT built for user privacy, but for company security. Because of that, you can only trust\n            a VPN provider's policy - and many have been caught abusing user data. Honestly, the best way forward: just\n            stop paying for outdated technology.\n          </span>\n        </div>\n        <img src=\"/assets/img/spn-feature-carousel/bye-bye-vpns.png\">\n      </section>\n    </sfng-tab>\n\n    <sfng-tab>\n\n      <ng-template #tmplYes>\n        <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n          class=\"inline-block w-6 h-6 text-green-200\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n            d=\"M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n        </svg>\n      </ng-template>\n\n      <ng-template #tmplNo>\n        <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n          class=\"inline-block w-6 h-6 text-red-200\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n            d=\"M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n        </svg>\n      </ng-template>\n\n      <ng-template #windows>\n        <svg data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 89.33 88.6\" fill=\"currentColor\"\n          class=\"w-5 h-5 text-blue\">\n          <path\n            d=\"m0 11.4 35.69-4.86V41L0 41.17Zm35.67 35.53v34.45L0 76.48V46.7ZM42 5.91 89.31 0v40.53L42 40.9Zm47.33 41.34v41.34L42 81.92l-.07-34.74Z\" />\n        </svg>\n      </ng-template>\n\n      <ng-template #linux>\n        <svg xmlns=\"http://www.w4.org/2000/svg\" xml:space=\"preserve\" viewBox=\"0 0 24 24\"\n          class=\"w-5 h-5 text-background\">\n          <path\n            d=\"M20.6 19c-.5-.4-.3-1.4-.9-1.9.6-3.4-1-6.3-2.8-8.2-1.6-1.6-1.1-3.1-1.1-4.5 0-2.1-.9-4.4-3.6-4.4-2.8 0-3.6 2.4-3.6 3.7-.1 3.3.6 4.1-1.3 6.5-2.2 2.8-2.6 5.6-2.1 7.1-.3.4-.7.7-1.2.8-1.7.7-.4 1.9-.9 2.8 0 .2-.1.5-.1.7 0 .8.6 1.4 1.7 1.3 1.5-.1 2.8.9 3.7.9.8 0 1.4-.4 1.7-1 1.4-.3 3.1-.3 4.5.1.2.7.9 1.1 1.7 1.1 1.6 0 1.9-1.8 3.8-2.5.7-.2 1-.9 1-1.5-.1-.4-.2-.7-.5-1zM11.4 8.6c-.3 0-.6-.3-1-.6-.5-.4-1-.6-1-1 0-.3.4-.4.9-.7.5-.3.7-.7 1.2-.7s.7.3 1.4.6 1.2.4 1.2.8-.7.6-1.2.9c-.6.3-.9.7-1.5.7zm1.7-5.2c.9.1 1 1.7.6 2.5l-.4-.1c.2-.5.2-1.4-.4-1.5-.4 0-.6.5-.7.9-.2-.2-.4-.2-.6-.2.1-.9.7-1.8 1.5-1.6zm-3.4.3c.7-.2 1.1.6 1.1 1.4l-.3.2c0-.3-.2-.9-.6-.8-.4.2-.4 1.1-.1 1.3l-.3.2c-.5-.7-.5-2.1.2-2.3zM7.6 22.9c-2-.9-2.6-.7-3-.7-.8 0-1-.6-.7-1.1.2-.5.2-1 .1-1.3-.1-.6-.1-.8.5-1.1.8-.3 1.2-.8 1.4-1.1.8-.9 1.5.5 2.1 1.9.4.9 1.2 1.3 1.5 2.2.2.9-.7 1.8-1.9 1.2zm7-1.8c-1.4.7-3.1 1-4.5.3-.2-.6-.5-.9-.8-1.3.5-.1.9-.8.5-1.5-.5-.7-1.6-1.2-2.6-2s-1.3-2.6 0-4.7c-.7 1.9-.3 3.6.1 4.1.1-1 .1-2.6 1.5-4.6.7-1 .7-2.3.7-3.1l.5.2c.5.3.8.7 1.4.7.8 0 1.3-.5 1.9-.9.2-.1.6-.3.9-.5.5 2.5 2.7 5.5 2.8 7.2.5-1-.1-3.5-.1-3.5.8 1.3.9 2.4.9 3.7.6.2 1.2.9 1.3 1.7h-.2c-.1-.9-2.6-2.3-2.8-.5-1.2.2-.8 2.1-1 3.3-.2.5-.4.9-.5 1.4zm4.8-.1c-1 .4-1.6 1.2-2.1 1.7-.9 1-2 .5-2.2-.4-.1-1 .4-1.5.6-2.6.2-1 0-2.5.4-2.7.3 1.8 2.1 1 2.5.5.7 0 .7.2.9.8.1.4.2.7.6 1.1.4.6.2 1.3-.7 1.6zm-8-13c-.7 0-1.1-.4-1.5-.8-.2-.2.1-.5.3-.3.4.3.8.7 1.3.7.6 0 1.1-.5 1.9-.8.2-.1.4.3.1.4-.8.3-1.3.8-2.1.8z\" />\n        </svg>\n      </ng-template>\n\n      <ng-template #mac>\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5 text-gray-500\" viewBox=\"0 0 1000 1187.198\">\n          <path fill=\"currentColor\"\n            d=\"M979.04184 925.18785c-17.95397 41.47737-39.20563 79.65705-63.82824 114.75895-33.56298 47.8528-61.04356 80.9761-82.22194 99.3698-32.83013 30.192-68.00529 45.6544-105.67203 46.5338-27.04089 0-59.6512-7.6946-97.61105-23.3035-38.08442-15.5358-73.08371-23.2303-105.08578-23.2303-33.56296 0-69.55888 7.6945-108.06101 23.2303-38.5608 15.6089-69.62484 23.7432-93.37541 24.5493-36.12049 1.5389-72.1237-14.3632-108.06101-47.7796-22.93711-20.0059-51.62684-54.3017-85.99592-102.8874-36.875274-51.88328-67.191862-112.04745-90.942422-180.639C12.750995 781.70252 0 709.95986 0 640.50361c0-79.5618 17.191859-148.18267 51.626869-205.68673 27.062885-46.18935 63.066121-82.62496 108.126941-109.37275 45.06086-26.74775 93.74914-40.37812 146.18212-41.25019 28.68971 0 66.3125 8.8744 113.06613 26.31542 46.62174 17.49964 76.55727 26.37404 89.68198 26.37404 9.8124 0 43.06758-10.37669 99.4431-31.06405 53.31237-19.18512 98.30724-27.12887 135.16787-23.99975 99.8828 8.06098 174.92313 47.43518 224.82789 118.37174-89.33023 54.12578-133.51903 129.93556-132.63966 227.18753.8061 75.75115 28.28668 138.78795 82.2952 188.8393 24.47603 23.23022 51.81008 41.18421 82.22186 53.93522-6.59525 19.12648-13.557 37.44688-20.95846 55.03446zM749.96366 23.751237c0 59.37343-21.69138 114.810233-64.92748 166.121963-52.17652 60.99961-115.28658 96.24803-183.72426 90.68597-.87204-7.12298-1.37769-14.61967-1.37769-22.49743 0-56.99843 24.81315-117.99801 68.87738-167.873453 21.99909-25.25281 49.978-46.25018 83.90738-63.00018 33.85608-16.50008 65.88014-25.6249796 95.99884-27.18757966.87944 7.93730006 1.24583 15.87509966 1.24583 23.74993966z\" />\n        </svg>\n      </ng-template>\n\n      <ng-template #mobile>\n        <svg class=\"w-5 h-5\" version=\"1.1\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"\n          xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n          <g fill=\"none\">\n            <path d=\"M0,0h24v24h-24Z\"></path>\n            <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M3,12v6\">\n            </path>\n            <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M21,6v6\">\n            </path>\n            <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\"\n              d=\"M10.88,17.5h2.24\"></path>\n            <path stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\"\n              d=\"M9,4h6c1.105,0 2,0.895 2,2v12c0,1.105 -0.895,2 -2,2h-6c-1.105,0 -2,-0.895 -2,-2v-12c0,-1.105 0.895,-2 2,-2Z\">\n            </path>\n          </g>\n        </svg>\n      </ng-template>\n\n      <section *sfngTabContent>\n        <table class=\"custom\">\n          <colgroup>\n            <col class=\"w-fit\">\n            <col class=\"w-40\">\n            <col class=\"w-40 bg-gray bg-opacity-20\">\n            <col class=\"w-40\">\n          </colgroup>\n          <thead>\n            <tr>\n              <th></th>\n              <th>\n                <a href=\"https://safing.io/blog/2022/09/06/spn-vs-vpns/?source=Portmaster\">\n                  Most VPNs\n                  <br>\n                  <span class=\"text-xs underline text-blue\">Read Comparison Blog</span>\n                </a>\n              </th>\n              <th>SPN</th>\n              <th>Tor</th>\n            </tr>\n          </thead>\n          <tbody>\n            <tr>\n              <td>Multiple Identities (simultaneous)</td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplNo\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n            </tr>\n            <!-- <tr>\n              <td>Automatic Geo-Unblocking</td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplNo\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplNo\"></ng-container>\n              </td>\n            </tr> -->\n            <tr>\n              <td>Individual Apps Settings</td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplNo\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplNo\"></ng-container>\n              </td>\n            </tr>\n            <tr>\n              <td>Easy Setup</td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n              <td><strong>Browser Only</strong></td>\n            </tr>\n            <tr>\n              <td>Availabilty</td>\n              <td>\n                <div class=\"flex flex-row items-center justify-center gap-2\">\n                  <ng-container *ngTemplateOutlet=\"windows\"></ng-container>\n                  <ng-container *ngTemplateOutlet=\"linux\"></ng-container>\n                  <ng-container *ngTemplateOutlet=\"mac\"></ng-container>\n                  <ng-container *ngTemplateOutlet=\"mobile\"></ng-container>\n                </div>\n              </td>\n              <td>\n                <div class=\"flex flex-row items-center justify-center gap-2\">\n                  <ng-container *ngTemplateOutlet=\"windows\"></ng-container>\n                  <ng-container *ngTemplateOutlet=\"linux\"></ng-container>\n                </div>\n              </td>\n              <td>\n                <div class=\"flex flex-row items-center justify-center gap-2\">\n                  <ng-container *ngTemplateOutlet=\"windows\"></ng-container>\n                  <ng-container *ngTemplateOutlet=\"linux\"></ng-container>\n                  <ng-container *ngTemplateOutlet=\"mac\"></ng-container>\n                  <ng-container *ngTemplateOutlet=\"mobile\"></ng-container>\n                </div>\n              </td>\n            </tr>\n            <tr>\n              <td>Open Source</td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplNo\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n            </tr>\n            <tr>\n              <td>Built for Privacy</td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplNo\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n              <td>\n                <ng-container *ngTemplateOutlet=\"tmplYes\"></ng-container>\n              </td>\n            </tr>\n          </tbody>\n        </table>\n      </section>\n    </sfng-tab>\n  </sfng-tab-group>\n\n  <svg (click)=\"showNext()\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n    stroke=\"currentColor\"\n    class=\"flex-shrink-0 w-8 h-8 text-opacity-50 cursor-pointer text-background hover:text-background\">\n    <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" />\n  </svg>\n\n</div>\n\n<div class=\"absolute bottom-0 left-0 right-0 flex flex-row items-center justify-center gap-2\">\n  <span *ngFor=\"let dot of carousel; let index=index\"\n    class=\"block w-3 h-3 transition-all duration-150 ease-in-out bg-opacity-50 rounded-full cursor-pointer bg-background\"\n    [class.bg-blue]=\"currentIndex === index\" (click)=\"openTab(index)\"></span>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn-feature-carousel/spn-feature-carousel.scss",
    "content": ":host {\n  @apply flex flex-col gap-2 justify-center items-center relative;\n}\n\nsection {\n  @apply flex flex-row items-start gap-4 justify-evenly text-background;\n\n  &.reverse {\n    @apply flex-row-reverse\n  }\n\n  &>div {\n    @apply flex flex-col w-1/3 gap-6;\n\n    span {\n      @apply text-base break-normal text-background text-opacity-80;\n    }\n\n    h1,\n    h1>span {\n      @apply text-2xl font-semibold break-normal md:text-3xl lg:text-4xl xl:text-5xl text-background;\n\n    }\n\n    h1>span {\n      &.text-blue {\n        color: theme('colors.blue.DEFAULT') !important;\n      }\n    }\n  }\n\n  img {\n    position: relative;\n    max-width: 50%;\n  }\n\n  table {\n    @apply mb-12;\n\n    th {\n      @apply text-base;\n    }\n\n    td {\n      @apply text-center p-2 leading-6;\n    }\n\n    tr>td:first-of-type {\n      @apply text-left p-2 font-semibold text-base whitespace-nowrap;\n    }\n  }\n}\n\n::ng-deep {\n  spn-feature-carousel {\n    sfng-tab-outlet {\n      &>div {\n        overflow: visible !important;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn-feature-carousel/spn-feature-carousel.ts",
    "content": "import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnDestroy, QueryList, ViewChild, ViewChildren } from \"@angular/core\";\nimport { SfngTabComponent, SfngTabGroupComponent } from '@safing/ui';\nimport { filter, interval, startWith, Subscription } from 'rxjs';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'spn-feature-carousel',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  templateUrl: './spn-feature-carousel.html',\n  styleUrls: [\n    './spn-feature-carousel.scss'\n  ]\n})\nexport class SPNFeatureCarouselComponent implements AfterViewInit, OnDestroy {\n  private sub: Subscription = Subscription.EMPTY;\n\n  pause = false;\n  currentIndex = -1;\n\n  @HostListener('mouseenter')\n  onMouseEnter() {\n    this.pause = true\n  }\n\n  @HostListener('mouseleave')\n  onMouseLeave() {\n    this.pause = false;\n  }\n\n  /** A list of all carousel templates */\n  @ViewChildren(SfngTabComponent)\n  carousel!: QueryList<SfngTabComponent>;\n\n  @ViewChild(SfngTabGroupComponent)\n  tabGroup!: SfngTabGroupComponent;\n\n  constructor(\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  ngAfterViewInit(): void {\n    this.sub = interval(5000)\n      .pipe(\n        startWith(-1),\n        filter(() => !this.pause),\n      )\n      .subscribe(() => {\n        this.openTab(this.currentIndex + 1, 'left')\n      })\n  }\n\n  ngOnDestroy(): void {\n    this.sub.unsubscribe()\n  }\n\n  openTab(idx: number, direction?: 'left' | 'right') {\n    // force animation to circle if we go before the first\n    // or after the last one.\n    if (idx < 0) {\n      idx = this.carousel.length - 1;\n      direction = 'right'\n    }\n    if (idx >= this.carousel.length) {\n      direction = 'left'\n    }\n\n    this.currentIndex = idx % this.carousel.length;\n    this.tabGroup.activateTab(this.currentIndex, direction)!;\n    this.cdr.markForCheck();\n  }\n\n  showNext() {\n    this.sub.unsubscribe()\n\n    this.openTab(this.currentIndex + 1)\n  }\n\n  showPrev() {\n    this.sub.unsubscribe()\n\n    this.openTab(this.currentIndex - 1)\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn-page.html",
    "content": "<ng-container *ngIf=\"(mapService.status$ | async) as status\">\n  <div *ngIf=\"status === 'connected'\"\n    class=\"absolute z-10 flex flex-col items-center justify-center gap-2 text-xs font-medium top-4 left-4 right-4\">\n    <div class=\"flex flex-col items-center justify-center gap-2\">\n\n      <div\n        class=\"flex flex-row items-center justify-center w-full gap-2 px-4 bg-gray-300 rounded-sm bg-opacity-90 text-xxs\"\n        [@fadeIn] *ngIf=\"loading\">\n        <fa-icon icon=\"circle-notch\" [spin]=\"true\" class=\"py-3\"></fa-icon>\n        Loading data, please wait ...\n      </div>\n    </div>\n  </div>\n\n  <div class=\"absolute top-0 bottom-0 left-0 flex flex-row items-start justify-start w-full h-full\"\n    [class.w-full]=\"currentUser === null || status === 'disabled'\">\n    <div\n      class=\"z-10 flex flex-col items-center justify-center flex-grow h-full bg-white bg-opacity-90 backdrop-filter backdrop-blur-sm\"\n      *ngIf=\"!currentUser || status === 'disabled'\">\n\n      <spn-feature-carousel class=\"w-full p-10 mb-6 overflow-visible h-1/2\">\n      </spn-feature-carousel>\n\n      <div class=\"flex flex-col items-center justify-center gap-4\">\n        <button (click)=\"openAccountDetails()\" *ngIf=\"!currentUser?.current_plan?.feature_ids?.includes(featureID)\"\n          class=\"w-56 px-5 py-2 font-medium uppercase rounded-full bg-blue bg-opacity-90 hover:bg-blue text-primary\">\n          Login\n        </button>\n\n        <button (click)=\"toggleSPN()\" *ngIf=\"currentUser?.current_plan?.feature_ids?.includes(featureID)\"\n          class=\"w-56 px-5 py-2 font-medium text-white uppercase rounded-full bg-blue bg-opacity-90 hover:bg-blue\">\n          Enable the SPN\n        </button>\n\n        <a href=\"https://safing.io/pricing/?source=Portmaster\"\n          class=\"w-56 px-5 py-2 font-medium text-center text-white uppercase rounded-full bg-background bg-opacity-90 hover:bg-background\">\n          Pricing\n        </a>\n      </div>\n    </div>\n  </div>\n</ng-container>\n\n\n<div class=\"absolute top-0 right-0 z-10 flex gap-2 mt-4 mr-4\">\n  <!-- DISABLED for now as it causes a lot of confusion ...\n\n  <sfng-toggle class=\"inline-block\" [ngModel]=\"liveMode\" (ngModelChange)=\"toggleLiveMode($event)\"></sfng-toggle>\n\n  -->\n  <app-expertise></app-expertise>\n</div>\n\n<div class=\"relative flex-grow h-full\">\n  <spn-map-renderer class=\"block w-full h-full\" mapId=\"spn-map\"\n    [class.disabled]=\"!currentUser || (mapService.status$ | async) === 'disabled'\">\n  </spn-map-renderer>\n\n  <spn-map-country-overlay *ngIf=\"hoveredCountry as ctry\" class=\"absolute right-10 bottom-10\"\n    [countryCode]=\"ctry.countryCode\" [countryName]=\"ctry.countryName\"></spn-map-country-overlay>\n\n  <spn-map-legend *ngIf=\"!hoveredCountry\" class=\"absolute right-10 bottom-10\"></spn-map-legend>\n\n  <div class=\"absolute bottom-1.5 left-0 right-0 flex items-center justify-center gap-1 text-secondary\"\n    *ngIf=\"!!proTipTemplate\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-3 h-3 -mt-0.5 \" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n      <path\n        d=\"M11 3a1 1 0 10-2 0v1a1 1 0 102 0V3zM15.657 5.757a1 1 0 00-1.414-1.414l-.707.707a1 1 0 001.414 1.414l.707-.707zM18 10a1 1 0 01-1 1h-1a1 1 0 110-2h1a1 1 0 011 1zM5.05 6.464A1 1 0 106.464 5.05l-.707-.707a1 1 0 00-1.414 1.414l.707.707zM5 10a1 1 0 01-1 1H3a1 1 0 110-2h1a1 1 0 011 1zM8 16v-1h4v1a2 2 0 11-4 0zM12 14c.015-.34.208-.646.477-.859a4 4 0 10-4.954 0c.27.213.462.519.476.859h4.002z\" />\n    </svg>\n    <span class=\"font-semibold \">Pro Tip:</span>\n    <ng-container *ngTemplateOutlet=\"proTipTemplate\"></ng-container>\n  </div>\n\n  <!-- we use a customer overlay container for all overlays created using the CdkOverlayService here -->\n  <div class=\"absolute top-0 bottom-0 left-0 right-0 pointer-events-none\" #overlayContainer></div>\n</div>\n\n<ng-container>\n  <ng-template #proTip>\n    Hold <b>\n      <pre>CTRL</pre></b> key and click a node on the map to immediately open the node details dialog.\n  </ng-template>\n\n  <ng-template #proTip>\n    Hold <b>\n      <pre>SHIFT</pre></b> key to open more than one node overlay when clicking the node icon.\n  </ng-template>\n\n  <ng-template #proTip>\n    To keep node overlays open move them using\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"inline-block w-4 h-4 opacity-75 hover:opacity-100\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15\" />\n    </svg>. Double click to revert the overlay position on the map.\n  </ng-template>\n\n  <ng-template #proTip>\n    Click on a country to get more information about all nodes in that country and a list of Apps that use nodes in the\n    country as an identity.\n  </ng-template>\n</ng-container>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn-page.scss",
    "content": ":host {\n  @apply flex flex-row w-full h-full justify-items-stretch items-stretch relative;\n}\n\n.text-info-red {\n  color: theme(\"colors.info.red\");\n}\n\n.network-status-dialog {\n  width: 50vw;\n  height: 50vh;\n  min-height: 300px;\n  min-width: 400px;\n  padding: 12px;\n  overflow: auto;\n  display: flex;\n  flex-direction: column;\n\n  .issue {\n    flex-grow: 1;\n  }\n\n  .issue-list {\n    width: 100% !important;\n    flex-grow: 1;\n\n    ul {\n      overflow: auto;\n    }\n  }\n\n  .issue.expanded {\n    background-color: var(--button-light) !important;\n  }\n\n  .body {\n    background-color: var(--cards-primary) !important;\n  }\n}\n\n.connect-button {\n\n  &.spn-connected {\n    @apply bg-info-blue;\n  }\n\n  &.spn-connecting {\n    @apply bg-info-blue;\n  }\n\n  &.spn-failed {\n    @apply bg-info-red;\n  }\n\n  &:hover {\n    @apply bg-info-blue opacity-75;\n  }\n}\n\n.table {\n  @apply w-full font-normal;\n\n  &>div {\n    @apply text-xs border-buttons-dark flex flex-row justify-between py-1;\n\n    &:not(:last-child) {\n      @apply border-b;\n    }\n\n    span:first-child {\n      @apply text-tertiary;\n    }\n\n    span:last-child {\n      @apply text-primary;\n    }\n  }\n}\n\n\ntable tr:nth-child(odd) {\n  background: none;\n}\n\n\n.tunnel-path {\n  position: relative;\n\n  .line {\n    position: absolute;\n    top: 10px;\n    bottom: 10px;\n    left: 8px;\n    width: 1px;\n    background-color: rgba(255, 255, 255, 0.1);\n  }\n\n\n  ul {\n    position: relative;\n    padding-left: 20px;\n\n    li:not(:last-of-type) {\n      padding-bottom: 0.35rem;\n    }\n\n    .ip {\n      margin-left: 0.35rem;\n    }\n\n    .hop-icon {\n      display: inline-block;\n      margin-left: -17px;\n      margin-right: 4px;\n      font-weight: 400;\n\n      &.country {\n        margin-left: -20px;\n      }\n    }\n\n    .hop-title {\n      margin-right: 2px;\n    }\n\n    .country {\n      display: inline-block;\n      margin-left: -20px;\n      margin-right: 4px;\n\n      &.unknown {\n        height: 14px;\n        width: 16px;\n        position: relative;\n        top: 3px;\n        border: 1px solid rgba(0, 0, 0, 0.25);\n        opacity: 0.5;\n        border-radius: 3px;\n        @apply bg-buttons-icon;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn-page.ts",
    "content": "import { coerceElement } from \"@angular/cdk/coercion\";\nimport { Overlay, OverlayContainer } from \"@angular/cdk/overlay\";\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { HttpClient } from '@angular/common/http';\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentRef, DestroyRef, ElementRef, Inject, Injectable, InjectionToken, Injector, OnDestroy, OnInit, QueryList, TemplateRef, ViewChild, ViewChildren, forwardRef, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { ActivatedRoute, ParamMap, Router } from \"@angular/router\";\nimport { AppProfile, ConfigService, Connection, ExpertiseLevel, FeatureID, Netquery, PORTMASTER_HTTP_API_ENDPOINT, PortapiService, SPNService, SPNStatus, UserProfile } from \"@safing/portmaster-api\";\nimport { SfngDialogService } from \"@safing/ui\";\nimport { Line as D3Line, Selection, interpolateString, line, select } from 'd3';\nimport { BehaviorSubject, Observable, Subscription, combineLatest, interval, of } from \"rxjs\";\nimport { catchError, debounceTime, map, mergeMap, share, startWith, switchMap, take, takeUntil, withLatestFrom } from \"rxjs/operators\";\nimport { fadeInAnimation, fadeInListAnimation, fadeOutAnimation } from \"src/app/shared/animations\";\nimport { ExpertiseService } from \"src/app/shared/expertise/expertise.service\";\nimport { SPNAccountDetailsComponent } from \"src/app/shared/spn-account-details\";\nimport { CountryDetailsComponent } from \"./country-details\";\nimport { CountryEvent, MAP_HANDLER, MapRef, MapRendererComponent } from \"./map-renderer/map-renderer\";\nimport { MapPin, MapService } from \"./map.service\";\nimport { PinDetailsComponent } from \"./pin-details\";\nimport { PinOverlayComponent } from \"./pin-overlay\";\nimport { OVERLAY_REF } from './utils';\n\nexport const MapOverlay = new InjectionToken<Overlay>('MAP_OVERLAY')\n\nexport type PinGroup = Selection<SVGGElement, unknown, null, unknown>;\nexport type LaneGroup = Selection<SVGGElement, unknown, null, unknown>;\n\nexport interface Path {\n  id: string;\n  points: (MapPin | [number, number])[];\n  attributes?: {\n    [key: string]: string;\n  }\n}\n\nexport interface PinEvent {\n  event?: MouseEvent;\n  mapPin: MapPin;\n}\n\n\n/**\n * A custom class that implements the OverlayContainer interface of CDK. This\n * is used so we can configure a custom container element that will hold all overlays created\n * by the map component. This way the overlays will be bound to the map container and not overflow\n * the sidebar or other overlays that are created by the \"root\" app.\n */\n@Injectable()\nclass MapOverlayContainer {\n  private _overlayContainer?: HTMLElement;\n\n  setOverlayContainer(element: ElementRef<HTMLElement> | HTMLElement) {\n    this._overlayContainer = coerceElement(element);\n  }\n\n  getContainerElement(): HTMLElement {\n    if (!this._overlayContainer) {\n      throw new Error(\"Overlay container element not initialized. Call setOverlayContainer first.\")\n    }\n\n    return this._overlayContainer;\n  }\n}\n\n@Component({\n  templateUrl: './spn-page.html',\n  styleUrls: ['./spn-page.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    MapOverlayContainer,\n    { provide: MapOverlay, useClass: Overlay },\n    { provide: OverlayContainer, useExisting: MapOverlayContainer },\n    { provide: MAP_HANDLER, useExisting: forwardRef(() => SpnPageComponent), multi: true }\n  ],\n  animations: [\n    fadeInListAnimation,\n    fadeInAnimation,\n    fadeOutAnimation\n  ]\n})\nexport class SpnPageComponent implements OnInit, OnDestroy, AfterViewInit {\n  private destroyRef = inject(DestroyRef);\n\n  private countryDebounceTimer: any | null = null;\n\n  /** a list of opened country details. required to close them on destry */\n  private openedCountryDetails: CountryDetailsComponent[] = [];\n\n  readonly featureID = FeatureID.SPN;\n\n  paths: Path[] = [];\n\n  @ViewChild('overlayContainer', { static: true, read: ElementRef })\n  overlayContainer!: ElementRef<HTMLElement>;\n\n  @ViewChild(MapRendererComponent, { static: true })\n  mapRenderer!: MapRendererComponent;\n\n  @ViewChild('accountDetails', { read: TemplateRef, static: true })\n  accountDetails: TemplateRef<any> | null = null;\n\n  /** A list of pro-tip templates in our view */\n  @ViewChildren('proTip', { read: TemplateRef })\n  proTipTemplates!: QueryList<TemplateRef<any>>;\n\n  /** The selected pro-tip template */\n  proTipTemplate: TemplateRef<any> | null = null;\n\n  /** currentUser holds the current SPN user profile if any */\n  currentUser: UserProfile | null = null;\n\n  /** An observable that emits all active processes. */\n  activeProfiles$: Observable<AppProfile[]>;\n\n  /** Whether or not we are still waiting for all data in order to satisfy a \"show process/pin\" request by query-params */\n  loading = true;\n\n  /** a list of currently selected pins */\n  selectedPins: PinOverlayComponent[] = [];\n\n  /** the currently hovered country, if any */\n  hoveredCountry: {\n    countryName: string;\n    countryCode: string;\n  } | null = null;\n\n  liveMode = false;\n  liveModePaths: Path[] = [];\n\n  private liveModeSubscription = Subscription.EMPTY;\n\n  /**\n   * spnStatusTranslation translates the spn status to the text that is displayed\n   * at the view\n   */\n  readonly spnStatusTranslation: Readonly<Record<SPNStatus['Status'], string>> = {\n    connected: 'Connected',\n    connecting: 'Connecting',\n    disabled: 'Disabled',\n    failed: 'Failure'\n  }\n\n\n  private mapRef: MapRef | null = null;\n  private lineFunc: D3Line<(MapPin | [number, number])> | null = null;\n  private highlightedPins = new Set<string>();\n\n  registerMap(ref: MapRef) {\n    this.mapRef = ref;\n\n    ref.onMapReady(() => {\n      // we want to have straight lines between our hubs so we use a custom\n      // path function that updates x and y coordinates based on the mercator projection\n      // without, points will no be at the correct geo-coordinates.\n      this.lineFunc = line<MapPin | [number, number]>()\n        .x(d => {\n          if (Array.isArray(d)) {\n            return this.mapRef!.projection([d[0], d[1]])![0];\n          }\n          return this.mapRef!.projection([d.location.Longitude, d.location.Latitude])![0];\n        })\n        .y(d => {\n          if (Array.isArray(d)) {\n            return this.mapRef!.projection([d[0], d[1]])![1];\n          }\n          return this.mapRef!.projection([d.location.Longitude, d.location.Latitude])![1];\n        })\n\n      this.mapRef!.root.append('g').attr('id', 'line-group')\n      this.mapRef!.root.append('g').attr('id', 'pin-group')\n\n      if (this.mapService._pins$.getValue().length > 0) {\n        this.renderPins(this.mapService._pins$.getValue())\n      }\n    })\n\n    ref.onCountryClick(event => this.onCountryClick(event))\n    ref.onCountryHover(event => this.onCountryHover(event))\n    ref.onZoomPan(() => this.onZoomAndPan())\n  }\n\n  unregisterMap(ref: MapRef) {\n    this.mapRef = null;\n    this.lineFunc = null;\n  }\n\n  constructor(\n    private configService: ConfigService,\n    private spnService: SPNService,\n    private netquery: Netquery,\n    private expertiseService: ExpertiseService,\n    private router: Router,\n    private route: ActivatedRoute,\n    private portapi: PortapiService,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpAPI: string,\n    private http: HttpClient,\n    public mapService: MapService,\n    @Inject(MapOverlay) private mapOverlay: Overlay,\n    private dialog: SfngDialogService,\n    private overlayContainerService: MapOverlayContainer,\n    private cdr: ChangeDetectorRef,\n    private injector: Injector,\n  ) {\n    this.activeProfiles$ = interval(5000)\n      .pipe(\n        startWith(-1),\n        switchMap(() => this.netquery.getActiveProfiles()),\n        share({ connector: () => new BehaviorSubject<AppProfile[]>([]) })\n      )\n  }\n\n  ngAfterViewInit() {\n    // configure our custom overlay container\n    this.overlayContainerService.setOverlayContainer(this.overlayContainer);\n\n    // Select a random \"Pro-Tip\" template and run change detection\n    this.proTipTemplate = this.proTipTemplates.get(Math.floor(Math.random() * this.proTipTemplates.length)) || null;\n    this.cdr.detectChanges();\n  }\n\n  openAccountDetails() {\n    this.dialog.create(SPNAccountDetailsComponent, {\n      autoclose: true,\n      backdrop: 'light'\n    })\n  }\n\n  ngOnInit() {\n    this.spnService\n      .profile$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        catchError(() => of(null))\n      )\n      .subscribe((user: UserProfile | null) => {\n        if (user?.state !== '') {\n          this.currentUser = user || null;\n        } else {\n          this.currentUser = null;\n        }\n\n        this.cdr.markForCheck();\n      })\n\n    let previousQueryMap: ParamMap | null = null;\n\n    combineLatest([\n      this.route.queryParamMap,\n      this.mapService.pins$,\n      this.activeProfiles$,\n    ])\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n      ).subscribe(([params, pins, profiles]) => {\n        if (params !== previousQueryMap) {\n          const app = params.get(\"app\")\n          if (!!app) {\n            const profile = profiles.find(p => `${p.Source}/${p.ID}` === app);\n            if (!!profile) {\n              const pinID = params.get(\"pin\")\n              const pin = pins.find(p => p.pin.ID === pinID);\n\n              this.selectGroup(profile, pin)\n            }\n          }\n\n          previousQueryMap = params;\n        }\n\n        this.renderPins(pins);\n\n        // we're done with everything now.\n        this.loading = false;\n      })\n\n  }\n\n  toggleLiveMode(enabled: boolean) {\n    this.liveMode = enabled;\n\n    if (!enabled) {\n      this.liveModeSubscription.unsubscribe();\n      this.liveModePaths = [];\n      this.updatePaths([]);\n      this.cdr.markForCheck();\n\n      return;\n    }\n\n    this.liveModeSubscription = this.portapi.watchAll<Connection>(\"network:tree\")\n      .pipe(\n        withLatestFrom(this.mapService.pinsMap$),\n        takeUntilDestroyed(this.destroyRef),\n        debounceTime(100),\n      )\n      .subscribe(([connections, mapPins]) => {\n        connections = connections.filter(conn => conn.Ended === 0 && !!conn.TunnelContext);\n\n        this.liveModePaths = connections.map(conn => {\n          const points: (MapPin | [number, number])[] = conn.TunnelContext!.Path.map(hop => mapPins.get(hop.ID)!)\n\n          if (!!conn.Entity.Coordinates) {\n            points.push([conn.Entity.Coordinates.Longitude, conn.Entity.Coordinates.Latitude])\n          }\n\n          return {\n            id: conn.Entity.Domain || conn.ID,\n            points: points,\n            attributes: {\n              'is-live': 'true',\n              'is-encrypted': `${conn.Encrypted}`\n            }\n          }\n        })\n\n        this.updatePaths([])\n        this.cdr.markForCheck();\n      })\n  }\n\n  /**\n   * Toggle the spn/enable setting. This does NOT update the view as that\n   * will happen as soon as we get an update from the db qsub.\n   *\n   * @private - template only\n   */\n  toggleSPN() {\n    this.configService.get('spn/enable')\n      .pipe(\n        map(setting => setting.Value ?? setting.DefaultValue),\n        mergeMap(active => this.configService.save('spn/enable', !active))\n      )\n      .subscribe()\n  }\n\n  /**\n   * Select one or more pins by ID. If shift key is hold then all currently\n   * selected pin overlays will be cleared before selecting the new ones.\n   */\n  private selectPins(event: MouseEvent | undefined, pinIDs: Observable<string[]>) {\n    combineLatest([\n      this.mapService.pins$,\n      pinIDs,\n    ])\n      .pipe(take(1))\n      .subscribe(([allPins, pinIDs]) => {\n        if (event?.shiftKey !== true) {\n          this.selectedPins\n            .filter(overlay => !overlay.hasBeenMoved)\n            .forEach(selected => selected.disposeOverlay())\n        }\n\n        pinIDs\n          .filter(id => !this.selectedPins.find(selectedPin => selectedPin.mapPin.pin.ID === id))\n          .map(id => allPins.find(pin => pin.pin.ID === id))\n          .filter(mapPin => !!mapPin)\n          .forEach(mapPin => this.onPinClick({\n            mapPin: mapPin!,\n          }));\n      })\n  }\n\n  /**\n   * Select all pins that are used for transit.\n   *\n   * @private - template only\n   */\n  selectTransitNodes(event: MouseEvent) {\n    this.selectPins(event, this.mapService.getPinIDsWithActiveSession())\n  }\n\n  /**\n   * Select all pins that are used as an exit hub.\n   *\n   * @private - template only\n   */\n  selectExitNodes(event: MouseEvent) {\n    this.selectPins(event, this.mapService.getPinIDsUsedAsExit())\n  }\n\n  /**\n   * Select all pins that currently host alive connections.\n   *\n   * @private - template only\n   */\n  selectNodesWithAliveConnections(event: MouseEvent) {\n    this.selectPins(event, this.mapService.getPinIDsWithActiveConnections())\n  }\n\n  navigateToMonitor(process: AppProfile) {\n    this.router.navigate(['/app', process.Source, process.ID])\n  }\n\n  ngOnDestroy() {\n    this.openedCountryDetails.forEach(cmp => cmp.dialogRef!.close());\n  }\n\n  onZoomAndPan() {\n    this.updateOverlayPositions();\n\n    if (this.mapRef) {\n      this.mapRef.root\n        .select('#lines-group')\n        .selectAll<SVGPathElement, Path>('path')\n        .attr('d', d => this.lineFunc!(d.points))\n\n      this.mapRef.root\n        .select(\"#pin-group\")\n        .selectAll<SVGGElement, MapPin>('g')\n        .attr('transform', d => `translate(${this.mapRef!.projection([d.location.Longitude, d.location.Latitude])})`)\n    }\n\n    this.cdr.markForCheck();\n  }\n\n  private createPinOverlay(pinEvent: PinEvent, lm: Map<string, MapPin>): PinOverlayComponent {\n    const paths = this.getRouteHome(pinEvent.mapPin, lm, false)\n    const overlayBoundingRect = this.overlayContainer.nativeElement.getBoundingClientRect();\n    const target = pinEvent.event?.target || this.getPinElem(pinEvent.mapPin.pin.ID)?.children[0];\n    let delay = 0;\n    if (paths.length > 0) {\n      delay = paths[0].points.length * MapRendererComponent.LineAnimationDuration;\n    }\n\n    const overlayRef = this.mapOverlay.create({\n      positionStrategy: this.mapOverlay.position()\n        .flexibleConnectedTo(new ElementRef(target))\n        .withDefaultOffsetY(-overlayBoundingRect.y - 10)\n        .withDefaultOffsetX(-overlayBoundingRect.x + 20)\n        .withPositions([\n          {\n            overlayX: 'start',\n            overlayY: 'top',\n            originX: 'start',\n            originY: 'top'\n          }\n        ]),\n      scrollStrategy: this.mapOverlay.scrollStrategies.reposition(),\n    })\n\n    const injector = Injector.create({\n      providers: [\n        {\n          provide: OVERLAY_REF,\n          useValue: overlayRef,\n        }\n      ],\n      parent: this.injector\n    })\n\n\n    const pinOverlay = overlayRef.attach(\n      new ComponentPortal(PinOverlayComponent, undefined, injector)\n    ).instance;\n\n    pinOverlay.delay = delay;\n    pinOverlay.mapPin = pinEvent.mapPin;\n    if (paths.length > 0) {\n      pinOverlay.routeHome = {\n        ...(paths[0]),\n      }\n      pinOverlay.additionalPaths = paths.slice(1);\n    }\n\n    return pinOverlay;\n  }\n\n\n  private openPinDetails(id: string) {\n    this.dialog.create(PinDetailsComponent, {\n      data: id,\n      backdrop: false,\n      autoclose: true,\n      dragable: true,\n    })\n  }\n\n  private openCountryDetails(event: CountryEvent) {\n    // abort if we already have the country details open.\n    if (this.openedCountryDetails.find(cmp => cmp.countryCode === event.countryCode)) {\n      return;\n    }\n\n    const ref = this.dialog.create(CountryDetailsComponent, {\n      data: {\n        name: event.countryName,\n        code: event.countryCode,\n      },\n      autoclose: false,\n      dragable: true,\n      backdrop: false,\n    })\n    const component = (ref.contentRef() as ComponentRef<CountryDetailsComponent>).instance;\n\n    // used to track whether we highlighted a map pin\n    let hasPinHighlightActive = false;\n\n    combineLatest([\n      component.pinHover,\n      this.mapService.pins$,\n    ])\n      .pipe(\n        takeUntil(ref.onClose),\n      )\n      .subscribe(([hovered, pins]) => {\n        hasPinHighlightActive = hovered !== null;\n\n        if (hovered !== null) {\n          this.onPinHover({\n            mapPin: pins.find(p => p.pin.ID === hovered)!,\n          })\n          this.highlightPin(hovered, true)\n        } else {\n          this.onPinHover(null);\n          this.clearPinHighlights();\n        }\n\n\n        this.cdr.markForCheck();\n      })\n\n    ref.onClose\n      .subscribe(() => {\n        if (hasPinHighlightActive) {\n          this.clearPinHighlights();\n        }\n\n        const index = this.openedCountryDetails.findIndex(cmp => cmp === component);\n        if (index >= 0) {\n          this.openedCountryDetails.splice(index, 1);\n        }\n      })\n\n    this.openedCountryDetails.push(component);\n  }\n\n  private updateOverlayPositions() {\n    this.mapService.pinsMap$\n      .pipe(take(1))\n      .subscribe(allPins => {\n        this.selectedPins.forEach(pin => {\n          const pinObj = allPins.get(pin.mapPin.pin.ID);\n          if (!pinObj) {\n            return;\n          }\n\n          pin.overlayRef.updatePosition();\n        })\n      })\n  }\n\n  onCountryClick(countryEvent: CountryEvent) {\n    this.openCountryDetails(countryEvent);\n  }\n\n  onCountryHover(countryEvent: CountryEvent | null) {\n    if (this.countryDebounceTimer !== null) {\n      clearTimeout(this.countryDebounceTimer);\n    }\n\n    if (!!countryEvent) {\n      this.hoveredCountry = {\n        countryCode: countryEvent.countryCode,\n        countryName: countryEvent.countryName,\n      }\n      this.cdr.markForCheck();\n\n      return;\n    }\n\n    this.countryDebounceTimer = setTimeout(() => {\n      this.hoveredCountry = null;\n      this.countryDebounceTimer = null;\n      this.cdr.markForCheck();\n    }, 200)\n  }\n\n  onPinClick(pinEvent: PinEvent) {\n    // if the control key hold when clicking a map pin, we immediately open the\n    // pin details instead of the overlay.\n    if (pinEvent.event?.ctrlKey) {\n      this.openPinDetails(pinEvent.mapPin.pin.ID);\n    }\n\n    const overlay = this.selectedPins.find(por => por.mapPin.pin.ID === pinEvent.mapPin.pin.ID);\n    if (!!overlay) {\n      overlay.disposeOverlay()\n      return;\n    }\n\n    // if shiftKey was not pressed during the pinClick we dispose all active overlays that have not been\n    // moved by the user\n    if (!pinEvent.event?.shiftKey) {\n      this.selectedPins\n        .filter(overlay => !overlay.hasBeenMoved)\n        .forEach(selected => selected.disposeOverlay())\n    }\n\n    this.mapService.pinsMap$\n      .pipe(take(1))\n      .subscribe(async lm => {\n        const overlayComp = this.createPinOverlay(pinEvent, lm);\n\n        // when the user wants to dispose a pin overlay (by clicking the X) we\n        //  - make sure the pin is not highlighted anymore\n        //  - remove the pin from the selectedPins list\n        //  - remove lines showing the route to the home hub\n        overlayComp.afterDispose\n          .subscribe(pinID => {\n            this.highlightPin(pinID, false);\n\n            const overlayIdx = this.selectedPins.findIndex(por => por.mapPin.pin.ID === pinEvent.mapPin.pin.ID);\n            this.selectedPins.splice(overlayIdx, 1)\n\n            this.updatePaths()\n            this.cdr.markForCheck();\n          })\n\n        // when the user hovers/leaves a pin overlay, we:\n        //   - move the pin-overlay to the top when the user hovers it so stacking order is correct\n        //   - (un)hightlight the pin element on the map\n        overlayComp.overlayHover\n          .subscribe(evt => {\n            this.highlightPin(evt.pinID, evt.type === 'enter')\n\n            // over the overlay component to the top\n            if (evt.type === 'enter') {\n              this.selectedPins.forEach(ref => {\n                if (ref !== overlayComp && ref.overlayRef.hostElement) {\n                  ref.overlayRef.hostElement.style.zIndex = '0';\n                }\n              })\n\n              overlayComp.overlayRef.hostElement.style.zIndex = '';\n            }\n          })\n\n        this.selectedPins.push(overlayComp)\n\n        this.updatePaths([]);\n        this.cdr.markForCheck();\n      })\n  }\n\n  private updatePaths(additional: Path[] = []) {\n    const paths = [\n      ...(this.selectedPins\n        .reduce((list, pin) => {\n          if (pin.routeHome) {\n            list.push(pin.routeHome)\n          }\n\n          return [\n            ...list,\n            ...(pin.additionalPaths || [])\n          ]\n        }, [] as Path[])),\n      ...this.liveModePaths,\n      ...additional\n    ]\n\n    this.paths = paths.map(p => {\n      return {\n        ...p,\n        attributes: {\n          class: 'lane',\n          ...(p.attributes || {})\n        }\n      }\n    });\n\n    this.renderPaths(this.paths)\n  }\n\n  onPinHover(pinEvent: PinEvent | null) {\n    if (!pinEvent) {\n      this.updatePaths([]);\n      this.onCountryHover(null);\n\n      return;\n    }\n\n    // we also emit a country hover event here to keep the country\n    // overlay open.\n    const countryName = this.mapRenderer.countryNames[pinEvent.mapPin.entity.Country]\n    this.onCountryHover({\n      event: pinEvent.event,\n      countryCode: pinEvent.mapPin.entity.Country,\n      countryName: countryName!,\n    })\n\n    // in developer mode, we show all connected lanes of the hovered pin.\n    if (this.expertiseService.currentLevel === ExpertiseLevel.Developer) {\n      this.mapService.pinsMap$\n        .pipe(take(1))\n        .subscribe(lm => {\n          const lanes = this.getConnectedLanes(pinEvent?.mapPin, lm)\n          this.updatePaths(lanes);\n          this.cdr.markForCheck();\n        })\n    }\n  }\n\n  /**\n   * Marks a process group as selected and either selects one or all exit pins\n   * of that group. If shiftKey is pressed during click, the ID(s) will be added\n   * to the list of selected pins instead of replacing it. If shiftKey is pressed\n   * the process group itself will NOT be displayed as selected.\n   *\n   * @private - template only\n   */\n  selectGroup(grp: AppProfile, pin?: MapPin | null, event?: MouseEvent) {\n    if (!!pin) {\n      this.selectPins(event, of([pin.pin.ID]))\n      return;\n    }\n\n    this.selectPins(event, this.mapService.getExitPinIDsForProfile(grp))\n  }\n\n  /** Returns a list of lines that represent the route from pin to home. */\n  private getRouteHome(pin: MapPin, lm: Map<string, MapPin>, includeAllRoutes = false): Path[] {\n    let pinsToEval: MapPin[] = [pin];\n\n    // decide whether to draw all connection routes that travel through pin.\n    if (includeAllRoutes) {\n      pinsToEval = [\n        ...pinsToEval,\n        ...Array.from(lm.values())\n          .filter(p => p.pin.Route?.includes(pin.pin.ID))\n      ]\n    }\n\n    return pinsToEval.map(pin => ({\n      id: `route-home-from-${pin.pin.ID}`,\n      points: (pin.pin.Route || []).map(hop => lm.get(hop)!),\n      attributes: {\n        'in-use': 'true'\n      }\n    }));\n  }\n\n  /** Returns a list of lines the represent all lanes to connected pins of pin */\n  private getConnectedLanes(pin: MapPin, lm: Map<string, MapPin>): Path[] {\n    let result: Path[] = [];\n\n    // add all lanes for connected hubs\n    Object.keys(pin.pin.ConnectedTo).forEach(target => {\n      const p = lm.get(target);\n      if (!!p) {\n        result.push({\n          id: lineID([pin, p]),\n          points: [\n            pin,\n            p\n          ]\n        })\n      }\n    });\n\n    return result;\n\n  }\n\n  private async renderPaths(paths: Path[]) {\n    if (!this.mapRef) {\n      return;\n    }\n\n    const ref = this.mapRef!\n\n    const linesGroup: LaneGroup = this.mapRef.select(\"#line-group\")!\n\n    const self = this;\n    const renderedPaths = linesGroup.selectAll<SVGPathElement, Path>('path')\n      .data(paths, p => p.id);\n\n    renderedPaths\n      .enter()\n      .append('path')\n      .attr('d', path => {\n        return self.lineFunc!(path.points)\n      })\n      .attr(\"stroke-width\", d => {\n        if (d.attributes) {\n          if (d.attributes['in-use']) {\n            return 2 / ref.zoomScale\n          }\n        }\n\n        return 1 / ref.zoomScale;\n      })\n      .call(sel => {\n        if (sel.empty()) {\n          return;\n        }\n        const data = sel.datum()?.attributes || {};\n        Object.keys(data)\n          .forEach(key => {\n            sel.attr(key, data[key])\n          })\n      })\n      .transition(\"enter-lane\")\n      .duration(d => d.points.length * MapRendererComponent.LineAnimationDuration)\n      .attrTween('stroke-dasharray', tweenDashEnter)\n\n    renderedPaths.exit()\n      .interrupt(\"enter-lane\")\n      .transition(\"leave-lane\")\n      .duration(200)\n      .attrTween('stroke-dasharray', tweenDashExit)\n      .remove();\n  }\n\n  private async renderPins(pins: MapPin[]) {\n    pins = pins.filter(pin => !pin.isOffline || pin.isActive);\n\n    if (!this.mapRef) {\n      return\n    }\n\n    const ref = this.mapRef!;\n\n    const countriesWithNodes = new Set<string>();\n\n    pins.forEach(pin => {\n      countriesWithNodes.add(pin.entity.Country)\n    })\n\n    const pinsGroup = ref.select('#pin-group')!\n\n    const pinElements = pinsGroup\n      .selectAll<SVGGElement, MapPin>('g')\n      .data(pins, pin => pin.pin.ID)\n\n    const self = this;\n\n    // add new pins\n    pinElements\n      .enter()\n      .append('g')\n      .append(d => {\n        const val = MapRendererComponent.MarkerSize / ref.zoomScale;\n\n        if (d.isHome) {\n          const homeIcon = document.createElementNS('http://www.w3.org/2000/svg', 'circle')\n          homeIcon.setAttribute('r', `${val * 1.25}`)\n\n          return homeIcon;\n        }\n\n        if (d.pin.VerifiedOwner === 'Safing') {\n          const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon')\n          polygon.setAttribute('points', `0,-${val} -${val},${val} ${val},${val}`)\n\n          return polygon;\n        }\n\n        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle')\n        circle.setAttribute('r', `${val}`)\n\n        return circle;\n      })\n      .attr(\"stroke-width\", d => {\n        if (d.isExit || self.highlightedPins.has(d.pin.ID)) {\n          return 2 / ref.zoomScale\n        }\n\n        if (d.isHome) {\n          return 4.5 / ref.zoomScale\n        }\n\n        return 1 / ref.zoomScale\n      })\n      .call(selection => {\n        selection\n          .style('opacity', 0)\n          .attr('transform', d => 'scale(0)')\n          .transition('enter-marker')\n          /**/.duration(1000)\n          /**/.attr('transform', d => `scale(1)`)\n          /**/.style('opacity', 1)\n      })\n      .on('click', function (e: MouseEvent) {\n        const pin = select(this).datum() as MapPin;\n        self.onPinClick({\n          event: e,\n          mapPin: pin\n        });\n      })\n      .on('mouseenter', function (e: MouseEvent) {\n        const pin = select(this).datum() as MapPin;\n        self.onPinHover({\n          event: e,\n          mapPin: pin,\n        })\n      })\n      .on('mouseout', function (e: MouseEvent) {\n        self.onPinHover(null);\n      })\n\n    // remove pins from the map that disappeared\n    pinElements\n      .exit()\n      .remove()\n\n    // update all pins to their correct position and update their attributes\n    pinsGroup.selectAll<SVGGElement, MapPin>('g')\n      .attr('hub-id', d => d.pin.ID)\n      .attr('is-home', d => d.isHome)\n      .attr('transform', d => `translate(${ref.projection([d.location.Longitude, d.location.Latitude])})`)\n      .attr('in-use', d => d.isTransit)\n      .attr('is-exit', d => d.isExit)\n      .attr('raise', d => this.highlightedPins.has(d.pin.ID))\n\n    // update the attributes of the country shapes\n    ref.worldGroup.selectAll<SVGGElement, any>('path')\n      .attr('has-nodes', d => countriesWithNodes.has(d.properties.iso_a2))\n\n    // get all in-use pins and raise them to the top\n    pinsGroup.selectAll<SVGGElement, MapPin>('g[in-use=true]')\n      .raise()\n\n    // finally, re-raise all pins that are highlighted\n    pinsGroup.selectAll<SVGGElement, MapPin>('g[raise=true]')\n      .raise()\n\n    const activeCountrySet = new Set<string>();\n    pins.forEach(pin => {\n      if (pin.isTransit) {\n        activeCountrySet.add(pin.pin.ID)\n      }\n    })\n\n    // update the in-use attributes of the country shapes\n    ref.worldGroup.selectAll<SVGPathElement, any>('path')\n      .attr('in-use', d => activeCountrySet.has(d.properties.iso_a2))\n\n    this.cdr.detectChanges();\n  }\n\n  public getPinElem(pinID: string) {\n    if (!this.mapRef) {\n      return\n    }\n\n    return this.mapRef.root\n      .select(\"#pin-group\")\n      .select<SVGGElement>(`g[hub-id=${pinID}]`)\n      .node()\n  }\n\n  public clearPinHighlights() {\n    if (!this.mapRef) {\n      return\n    }\n\n    this.mapRef.root\n      .select('#pin-group')\n      .select<SVGGElement>(`g[raise=true]`)\n      .attr('raise', false)\n\n    this.highlightedPins.clear();\n  }\n\n  public highlightPin(pinID: string, highlight: boolean) {\n    if (highlight) {\n      this.highlightedPins.add(pinID)\n    } else {\n      this.highlightedPins.delete(pinID);\n    }\n\n    if (!this.mapRef) {\n      return\n    }\n    const pinElemn = this.mapRef!.root\n      .select(\"#pin-group\")\n      .select<SVGGElement>(`g[hub-id=${pinID}]`)\n      .attr('raise', highlight)\n\n    if (highlight) {\n      pinElemn\n        .raise()\n    }\n  }\n}\n\nfunction lineID(l: [MapPin, MapPin]): string {\n  return [l[0].pin.ID, l[1].pin.ID].sort().join(\"-\")\n}\n\nconst tweenDashEnter = function (this: SVGPathElement) {\n  const len = this.getTotalLength();\n  const interpolate = interpolateString(`0, ${len}`, `${len}, ${len}`);\n  return (t: number) => {\n    if (t === 1) {\n      return '0';\n    }\n    return interpolate(t);\n  }\n}\n\nconst tweenDashExit = function (this: SVGPathElement) {\n  const len = this.getTotalLength();\n  const interpolate = interpolateString(`${len}, ${len}`, `0, ${len}`);\n  return (t: number) => {\n    if (t === 1) {\n      return `${len}`;\n    }\n    return interpolate(t);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/spn.module.ts",
    "content": "import { A11yModule } from '@angular/cdk/a11y';\nimport { DragDropModule } from '@angular/cdk/drag-drop';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\nimport { FontAwesomeModule } from '@fortawesome/angular-fontawesome';\nimport { SfngToggleSwitchModule, SfngTooltipModule, TabModule } from '@safing/ui';\nimport { SfngAppIconModule } from 'src/app/shared/app-icon';\nimport { CountIndicatorModule } from 'src/app/shared/count-indicator';\nimport { CountryFlagModule } from 'src/app/shared/country-flag';\nimport { ExpertiseModule } from 'src/app/shared/expertise/expertise.module';\nimport { SfngFocusModule } from 'src/app/shared/focus';\nimport { SfngMenuModule } from 'src/app/shared/menu';\nimport { CommonPipesModule } from 'src/app/shared/pipes';\nimport { SpnPageComponent } from './';\nimport { CountryDetailsComponent } from './country-details';\nimport { CountryOverlayComponent } from './country-overlay';\nimport { SpnMapLegendComponent } from './map-legend';\nimport { MapRendererComponent } from './map-renderer';\nimport { SpnNodeIconComponent } from './node-icon';\nimport { PinDetailsComponent } from './pin-details';\nimport { SpnPinListComponent } from './pin-list/pin-list';\nimport { PinOverlayComponent } from './pin-overlay';\nimport { SpnPinRouteComponent } from './pin-route';\nimport { SPNFeatureCarouselComponent } from './spn-feature-carousel';\n\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    CountryFlagModule,\n    SfngTooltipModule,\n    SfngMenuModule,\n    SfngFocusModule,\n    SfngAppIconModule,\n    SfngToggleSwitchModule,\n    TabModule,\n    A11yModule,\n    ExpertiseModule,\n    OverlayModule,\n    CountIndicatorModule,\n    FontAwesomeModule,\n    CommonPipesModule,\n    DragDropModule,\n    RouterModule,\n  ],\n  declarations: [\n    MapRendererComponent,\n    PinOverlayComponent,\n    CountryOverlayComponent,\n    CountryDetailsComponent,\n    SpnNodeIconComponent,\n    SpnMapLegendComponent,\n    PinDetailsComponent,\n    SpnPinRouteComponent,\n    SPNFeatureCarouselComponent,\n    SpnPageComponent,\n    SpnPinListComponent,\n  ],\n  exports: [\n    SpnPageComponent,\n    SpnPinRouteComponent,\n    SpnNodeIconComponent,\n    MapRendererComponent,\n  ]\n})\nexport class SPNModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/pages/spn/utils.ts",
    "content": "import { OverlayRef } from '@angular/cdk/overlay';\nimport { InjectionToken } from '@angular/core';\n\nexport const OVERLAY_REF = new InjectionToken<OverlayRef>('OVERLAY_REF');\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/form/index.ts",
    "content": "export * from './support-form';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/form/support-form.html",
    "content": "<div class=\"header\">\n  <h4 class=\"breadcrumbs\">\n    <span routerLink=\"../\">Get Help</span>\n    <fa-icon icon=\"chevron-right\" [@moveInOut]></fa-icon>\n    <span [@moveInOut]>{{ page?.title }}</span>\n  </h4>\n  <app-expertise></app-expertise>\n</div>\n\n<div class=\" scroll-container\" cdkScrollable [@fadeIn]=\"true\">\n  <div class=\"form-wrapper\">\n    <div class=\"page-title\">\n      <h1>{{ page?.title }}</h1>\n    </div>\n\n    <p class=\"prologue secondary-text\" *ngIf=\"page?.prologue || page?.shortHelp\">\n      {{ page?.prologue || page?.shortHelp }}\n    </p>\n\n    <div class=\"repo-list\" *ngIf=\"page?.repositories?.length\">\n      <h4>{{ page?.repoHelp }}</h4>\n      <button *ngFor=\"let repo of page?.repositories\" [attr.id]=\"repo.repo\"\n        [class.selected]=\"selectedRepo === repo.repo\" (click)=\"selectRepo(repo.repo)\">\n        {{ repo.name }}\n      </button>\n    </div>\n\n    <h3>Title</h3>\n    <div class=\"input-wrapper\">\n      <input class=\"title\" [class.missing]=\"titleMissing && title === ''\" required type=\"text\" [(ngModel)]=\"title\"\n        (ngModelChange)=\"searchIssues($event)\" placeholder=\"Summarize your report\">\n      <span class=\"copy-button\" (click)=\"copyToClipboard(title)\">Copy</span>\n    </div>\n\n    <section *ngFor=\"let section of page?.sections\">\n      <h3>{{section.title}}</h3>\n      <div class=\"input-wrapper\">\n        <textarea [(ngModel)]=\"form[section.title]\" (ngModelChange)=\"onModelChange()\" rows=\"4\"\n          [placeholder]=\"section.help || ''\"></textarea>\n        <span class=\"copy-button\" (click)=\"copyToClipboard(form[section.title])\">Copy</span>\n      </div>\n      <!--\n      <span class=\"section-help\" *ngIf=\"section.help\">\n        {{section.help}}\n      </span>\n    -->\n    </section>\n\n    <ng-template [ngIf]=\"page?.includeDebugData\">\n      <div class=\"page-title\">\n        <h1>Included Debug Info</h1>\n      </div>\n\n      <p class=\"prologue secondary-text\">\n        The following debug information will be sent together with your report. Please check it and remove potentially sensitive\n        information. The debug information sent with your reports will be saved on Safing's self-hosted pastebin server\n        and is viewable via its created url. The data is automatically destroyed after one month.\n      </p>\n      <div class=\"debug-header\">\n        <div class=\"pl-4 secondary-text\">\n          Portmaster Version: <u>{{version}}</u>\n          built on <u>{{buildDate}}</u>\n        </div>\n        <span class=\"copy-button\" (click)=\"copyToClipboard(debugData)\">Copy</span>\n      </div>\n      <textarea [(ngModel)]=\"debugData\" rows=\"8\"></textarea>\n    </ng-template>\n\n    <div class=\"actions\">\n      <button *ngIf=\"!!page?.ghIssuePreset\" class=\"primary\" (click)=\"createOnGithub()\">\n        <fa-icon [icon]=\"['fab', 'github']\" class=\"mr-1\"></fa-icon>\n        {{ haveGhAccount ? 'Open' : 'Create'}} on GitHub\n      </button>\n      <button *ngIf=\"page?.privateTicket\" [class.primary]=\"!page?.ghIssuePreset\" (click)=\"createPrivateTicket()\">\n        Send private Ticket\n      </button>\n    </div>\n  </div>\n\n  <div *ngIf=\"page?.ghIssuePreset\" class=\"issue-list\" sfngTipUpAnchor=\"left\">\n    <div class=\"page-title\">\n      <h1>\n        Related Issues\n        <sfng-tipup key=\"support-page-related-issues\"></sfng-tipup>\n      </h1>\n    </div>\n    <p class=\"prologue secondary-text\">\n      Public issues related to your title:\n    </p>\n\n    <p class=\"prologue secondary-text\" *ngIf=\"!relatedIssues.length\">\n      No related issues were found.\n    </p>\n\n    <ul [@fadeInList]=\"relatedIssues.slice(0, 8).length\">\n      <li *ngFor=\"let issue of relatedIssues.slice(0, 8); trackBy: trackIssue\" (click)=\"openIssue(issue)\" class=\"issue\">\n        <span class=\"title\">{{ issue.title }}</span>\n        <span class=\"meta\">{{ issue.closed ? 'closed' : 'opened'}} in <u>{{ repos[issue.repository] || issue.repository\n            }}</u> by <u>{{ issue.user }}</u>\n          {{\n          issue.createdAt | timeAgo\n          }}</span>\n        <fa-icon icon=\"external-link-alt\"></fa-icon>\n      </li>\n    </ul>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/form/support-form.scss",
    "content": ":host {\n  width: 100%;\n  display: flex;\n  flex-grow: 1;\n  flex-direction: column;\n  height: 100%;\n}\n\n.scroll-container {\n  overflow: auto;\n  margin-right: 1rem;\n  display: flex;\n  flex-direction: row;\n  justify-content: center;\n  flex-grow: 1;\n\n  @apply p-8;\n\n  h3 {\n    opacity: .9;\n    font-size: 0.95rem;\n  }\n}\n\n.form-wrapper {\n  flex-grow: 2;\n\n  @media (min-width: 1250px) {\n    max-width: 800px;\n  }\n\n}\n\n.issue-list {\n  width: 400px;\n\n  margin-left: 2rem;\n\n  &,\n  ul {\n    overflow-y: hidden;\n  }\n\n  .issue {\n    @apply px-4;\n    @apply pr-8;\n    @apply py-4;\n    @apply rounded;\n    @apply bg-cards-secondary;\n\n    span {\n      word-break: keep-all;\n    }\n\n    display : flex;\n    flex-direction: column;\n    position : relative;\n    cursor : pointer;\n\n    &:not(:last-child) {\n      margin-bottom: 0.5rem;\n    }\n\n    .meta {\n      @apply text-tertiary;\n      @apply font-normal;\n      opacity: .7;\n      font-size: 95%;\n    }\n\n    &:hover {\n      @apply bg-cards-tertiary;\n    }\n\n    fa-icon {\n      position: absolute;\n      right: calc((2rem - 12px) / 2);\n      top: calc(50% - 8px); // actually the half height is 6px but that looks off for the icon we're using\n      opacity: .3;\n    }\n  }\n}\n\np.prologue {\n  @apply mb-8;\n}\n\n.page-title {\n  margin-top: 20px;\n  margin-bottom: 40px;\n  position: relative;\n  border-bottom: 1px solid rgba(255, 255, 255, .2);\n\n  h1 {\n    position: absolute;\n    top: -1rem;\n    background-color: var(--background);\n    @apply pr-8;\n  }\n}\n\n.repo-list {\n  @apply mb-8;\n\n}\n\nbutton {\n  @apply p-2;\n  @apply bg-buttons-dark;\n  @apply border;\n  @apply border-buttons-dark;\n  opacity: .4;\n\n  &:not(:last-child) {\n    @apply mr-1;\n  }\n\n  &:hover {\n    @apply bg-buttons-light;\n    @apply border-buttons-light;\n  }\n\n  &.selected {\n    @apply bg-buttons-dark;\n    @apply border-buttons-light;\n    opacity: 1;\n  }\n}\n\n.actions {\n  @apply mt-8;\n  @apply pb-16;\n\n  button {\n    opacity: 1;\n    @apply bg-transparent;\n\n    &.primary {\n      @apply bg-buttons-dark;\n      opacity: 1;\n    }\n\n    &:hover {\n      @apply bg-buttons-light;\n    }\n  }\n\n}\n\n.debug-header {\n  height: 32px;\n  display: flex;\n  flex-direction: row;\n  justify-content: space-between;\n  align-items: center;\n  position: relative;\n  @apply bg-cards-primary;\n  @apply rounded-t;\n  top: 2px;\n}\n\ntextarea {\n  @apply px-4;\n  @apply py-2;\n  min-height: 40px;\n}\n\ntextarea,\ninput[type=\"text\"].title {\n  @apply font-medium;\n  @apply border;\n  @apply border-cards-secondary;\n  @apply bg-cards-secondary;\n  padding-right: 4.5rem; // copy button width\n\n  &:hover,\n  &:active,\n  &:focus {\n    @apply border-cards-primary;\n  }\n}\n\ninput[type=\"text\"].title {\n  padding-left: 1rem;\n}\n\nsection {\n  @apply py-8;\n\n  &:not(:first-of-type) {\n    @apply pt-0;\n  }\n}\n\n.input-wrapper {\n  position: relative;\n  display: flex;\n}\n\n.copy-button {\n  user-select: none;\n  position: absolute;\n  top: 1px;\n  right: 0px;\n  width: 4rem;\n  height: 31px;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  cursor: pointer;\n  @apply bg-buttons-dark;\n  @apply rounded-sm;\n  opacity: .5;\n\n  &:hover {\n    opacity: .9;\n  }\n}\n\n.section-help {\n  @apply bg-cards-primary;\n  @apply border-t;\n  @apply border-dashed;\n  @apply border-buttons-light;\n  @apply p-2;\n  @apply px-4;\n  @apply rounded-sm;\n  color: rgba(255, 255, 255, .6);\n  font-size: 0.7rem;\n  position: relative;\n  width: 100%;\n  display: flex;\n  flex-direction: column;\n}\n\n.gh-author {\n  @apply mt-8;\n  display: flex;\n  flex-direction: row;\n  justify-content: flex-start;\n  align-items: flex-start;\n\n  .input-wrapper {\n    padding-top: 2px;\n    @apply pr-2;\n  }\n}\n\ninput[type=\"text\"].missing,\ntextarea.missing {\n  @apply border-info-red;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/form/support-form.ts",
    "content": "import { CdkScrollable } from '@angular/cdk/scrolling';\nimport { Component, DestroyRef, OnInit, TrackByFunction, ViewChild, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { DebugAPI } from '@safing/portmaster-api';\nimport { ConfirmDialogConfig, SfngDialogService } from '@safing/ui';\nimport { BehaviorSubject, Observable, of } from 'rxjs';\nimport { debounceTime, mergeMap } from 'rxjs/operators';\nimport { SessionDataService, StatusService } from 'src/app/services';\nimport { Issue, SupportHubService } from 'src/app/services/supporthub.service';\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\nimport { fadeInAnimation, fadeInListAnimation, moveInOutAnimation } from 'src/app/shared/animations';\nimport { FuzzySearchService } from 'src/app/shared/fuzzySearch';\nimport { SupportPage, supportTypes } from '../pages';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\nimport { SupportProgressDialogComponent, TicketData, TicketInfo } from '../progress-dialog';\n\n@Component({\n  templateUrl: './support-form.html',\n  styleUrls: ['./support-form.scss'],\n  animations: [fadeInAnimation, moveInOutAnimation, fadeInListAnimation]\n})\nexport class SupportFormComponent implements OnInit {\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly search$ = new BehaviorSubject<string>('');\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  page: SupportPage | null = null;\n\n  debugData: string = '';\n  title: string = '';\n  form: { [key: string]: string } = {}\n  selectedRepo: string = '';\n  haveGhAccount = false;\n  version: string = '';\n  buildDate: string = '';\n  titleMissing = false;\n\n  relatedIssues: Issue[] = [];\n  allIssues: Issue[] = [];\n  repos: { [repo: string]: string } = {};\n\n  @ViewChild(CdkScrollable)\n  scrollContainer: CdkScrollable | null = null;\n\n  trackIssue: TrackByFunction<Issue> = (_: number, issue: Issue) => issue.url;\n\n  constructor(\n    private route: ActivatedRoute,\n    private router: Router,\n    private uai: ActionIndicatorService,\n    private debugapi: DebugAPI,\n    private statusService: StatusService,\n    private dialog: SfngDialogService,\n    private supporthub: SupportHubService,\n    private searchService: FuzzySearchService,\n    private sessionService: SessionDataService,\n  ) { }\n\n  ngOnInit() {\n    this.supporthub.loadIssues().subscribe(issues => {\n      issues = issues.reverse();\n      this.allIssues = issues;\n      this.relatedIssues = issues;\n    })\n\n    this.search$.pipe(\n      takeUntilDestroyed(this.destroyRef),\n      debounceTime(200),\n    )\n      .subscribe((text) => {\n        this.relatedIssues = this.searchService.searchList(this.allIssues, text, {\n          disableHighlight: true,\n          shouldSort: true,\n          isCaseSensitive: false,\n          minMatchCharLength: 4,\n          keys: [\n            'title',\n            'body',\n          ],\n        }).map(res => res.item)\n      })\n\n    this.statusService.getVersions()\n      .subscribe(status => {\n        this.version = status.Core.Version;\n        this.buildDate = status.Core.BuildTime;\n      })\n\n    this.route.paramMap\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(params => {\n        const id = params.get(\"id\")\n        for (let pIdx = 0; pIdx < supportTypes.length; pIdx++) {\n          const pageSection = supportTypes[pIdx];\n          const page = pageSection.choices.find(choice => choice.type !== 'link' && choice.id === id);\n          if (!!page) {\n            this.page = page as SupportPage;\n            break;\n          }\n        }\n\n        if (!this.page) {\n          this.router.navigate(['..']);\n          return;\n        }\n        this.title = '';\n        this.form = {};\n        this.selectedRepo = 'portmaster';\n        this.debugData = '';\n        this.repos = {};\n        this.page.sections.forEach(section => this.form[section.title] = '');\n        this.page.repositories?.forEach(repo => this.repos[repo.repo] = repo.name)\n\n        // try to restore from session service\n        this.sessionService.restore(this.page.id, this);\n\n        if (this.page.includeDebugData) {\n          this.debugapi.getCoreDebugInfo('github')\n            .subscribe({\n              next: data => this.debugData = data,\n              error: err => this.uai.error('Failed to get Debug Data', this.uai.getErrorMessgae(err))\n            })\n        }\n      })\n  }\n\n  onModelChange() {\n    if (!this.page) {\n      return;\n    }\n    this.sessionService.save(this.page.id, this, ['title', 'form', 'selectedRepo', 'haveGhAccount']);\n  }\n\n  selectRepo(repo: string) {\n    this.selectedRepo = repo;\n    this.onModelChange();\n  }\n\n  searchIssues(text: string) {\n    this.onModelChange();\n    this.search$.next(text);\n  }\n\n  copyToClipboard(what: string) {\n    this.integration.writeToClipboard(what)\n      .then(() => this.uai.success(\"Copied to Clipboard\"))\n      .catch(() => this.uai.error('Failed to Copy to Clipboard'));\n  }\n\n  validate(): boolean {\n    this.titleMissing = this.title === '';\n    const valid = !this.titleMissing;\n    if (!valid) {\n      this.scrollContainer?.scrollTo({ top: 0, behavior: 'smooth' })\n    }\n    return valid;\n  }\n\n  createIssue(type: 'github' | 'private', genUrl?: boolean, email?: string) {\n    const ticketData: TicketData = {\n      repo: this.selectedRepo || '',\n      title: this.title,\n      debugInfo: this.debugData,\n      sections: this.page?.sections.map(section => ({\n        title: section.title,\n        body: this.form[section.title],\n      })) || [],\n    }\n\n    let issue: TicketInfo;\n\n    switch (type) {\n      case 'github':\n        issue = {\n          type: 'github',\n          generateUrl: genUrl || false,\n          preset: this.page!.ghIssuePreset || '',\n          ...ticketData\n        };\n\n        break;\n\n      case 'private':\n        issue = {\n          type: 'private',\n          email: email,\n          ...ticketData\n        }\n\n        break;\n    }\n\n    SupportProgressDialogComponent.open(this.dialog, issue)\n      .subscribe(() => {\n        this.sessionService.delete(this.page?.id || '');\n      });\n  }\n\n  createOnGithub(genUrl?: boolean) {\n    if (!this.validate()) {\n      return;\n    }\n\n    if (genUrl === undefined && this.haveGhAccount) {\n      genUrl = true;\n    }\n\n    if (genUrl === undefined) {\n      this.dialog.confirm({\n        canCancel: true,\n        caption: 'Caution',\n        header: 'Create Issue on GitHub',\n        message: 'You can easily create the issue with your own GitHub account. Or create the GitHub issue privately, but then we will have no way to communicate with you for further information.',\n        buttons: [\n          { id: 'createWithout', text: 'Create Without Account', class: 'outline' },\n          { id: 'openGithub', text: 'Use My Account' },\n        ]\n      })\n        .onAction('openGithub', () => {\n          this.createIssue('github', true)\n        })\n        .onAction('createWithout', () => {\n          this.createIssue('github', false)\n        })\n      return;\n    }\n  }\n\n  openIssue(issue: Issue) {\n    this.integration.openExternal(issue.url);\n  }\n\n  createPrivateTicket() {\n    if (!this.validate()) {\n      return;\n    }\n\n    const opts: ConfirmDialogConfig = {\n      caption: 'Info',\n      canCancel: true,\n      header: 'How should we stay in touch?',\n      message: 'Please enter your email address so we can write back and forth until the issue is concluded.',\n      inputModel: '',\n      inputPlaceholder: 'Optional Email',\n      inputType: 'text',\n      buttons: [\n        { id: '', class: 'outline', text: 'Cancel' },\n        { id: 'create', text: 'Create Ticket' },\n      ],\n    }\n    this.dialog.confirm(opts)\n      .onAction('create', () => {\n        this.createIssue('private', undefined, opts.inputModel);\n      });\n  }\n\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/index.ts",
    "content": "export * from './support';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/pages.ts",
    "content": "export interface PageSections {\n  title?: string;\n  choices: SupportType[];\n  style?: 'small';\n}\n\nexport interface QuestionSection {\n  title: string;\n  help?: string;\n}\n\nexport interface SupportPage {\n  type?: undefined;\n  id: string;\n  title: string;\n  shortHelp: string;\n  repoHelp?: string;\n  prologue?: string;\n  epilogue?: string;\n  sections: QuestionSection[];\n  privateTicket?: boolean;\n  ghIssuePreset?: string;\n  includeDebugData?: boolean;\n  repositories?: { repo: string, name: string }[];\n}\n\nexport interface ExternalLink {\n  type: 'link',\n  url: string;\n  title: string;\n  shortHelp: string;\n}\n\nexport type SupportType = SupportPage | ExternalLink;\n\nexport const supportTypes: PageSections[] = [\n  {\n    title: \"Resources\",\n    choices: [\n      {\n        type: 'link',\n        title: '📘 Portmaster Wiki & FAQ',\n        url: 'https://wiki.safing.io/?source=Portmaster',\n        shortHelp: 'Search the Portmaster knowledge base and FAQ.',\n      },\n      {\n        type: 'link',\n        title: '🔖 Settings Handbook',\n        url: 'https://docs.safing.io/portmaster/settings?source=Portmaster',\n        shortHelp: 'A reference document of all Portmaster settings.'\n      },\n      {\n        type: 'link',\n        title: '📑 Safing Blog',\n        url: 'https://safing.io/blog?source=Portmaster',\n        shortHelp: 'Read our blog posts and announcements.',\n      }\n    ]\n  },\n  {\n    title: \"Communities & Support\",\n    style: 'small',\n    choices: [\n      {\n        type: 'link',\n        title: 'Join us on Discord',\n        url: 'https://discord.gg/safing',\n        shortHelp: 'Get help from the community and our AI bot on Discord.'\n      },\n      {\n        type: 'link',\n        title: 'Follow us on Mastodon',\n        url: 'https://fosstodon.org/@safing',\n        shortHelp: 'Get updates and privacy jokes on Mastodon.'\n      },\n      {\n        type: 'link',\n        title: 'Follow us on Twitter',\n        url: 'https://twitter.com/SafingIO',\n        shortHelp: 'Get updates and privacy jokes on Twitter.'\n      },\n      {\n        type: 'link',\n        title: 'Safing Support via Email',\n        url: 'mailto:support@safing.io',\n        shortHelp: 'As a subscriber, reach out to the Safing team directly.'\n      }\n    ]\n  },\n  {\n    title: \"Make a Report\",\n    style: 'small',\n    choices: [\n      {\n        id: \"report-bug\",\n        title: \"🐞 Report a Bug\",\n        shortHelp: \"Found a bug? Report your discovery and make the Portmaster better for everyone.\",\n        repoHelp: \"Where did the bug take place?\",\n        sections: [\n          {\n            title: \"What happened?\",\n            help: \"Describe what happened in detail\"\n          },\n          {\n            title: \"What did you expect to happen?\",\n            help: \"Describe what you expected to happen instead\"\n          },\n          {\n            title: \"How did you reproduce it?\",\n            help: \"Describe how to reproduce the issue\"\n          },\n          {\n            title: \"Additional information\",\n            help: \"Provide extra details if needed\"\n          },\n        ],\n        includeDebugData: true,\n        privateTicket: true,\n        ghIssuePreset: \"report-bug.md\",\n        repositories: []\n      },\n      {\n        id: \"give-feedback\",\n        title: \"💡 Suggest an Improvement\",\n        shortHelp: \"Suggest an enhancement or a new feature for Portmaster.\",\n        repoHelp: \"What would you would like to improve?\",\n        sections: [\n          {\n            title: \"What would you like to add or change?\",\n          },\n          {\n            title: \"Why do you and others need this?\"\n          }\n        ],\n        includeDebugData: false,\n        privateTicket: true,\n        ghIssuePreset: \"suggest-feature.md\",\n        repositories: []\n      },\n      {\n        id: \"compatibility-report\",\n        title: \"📝 Make a Compatibility Report\",\n        shortHelp: \"Report Portmaster in/compatibility with Linux Distros, VPN Clients or general Software.\",\n        sections: [\n          {\n            title: \"What worked?\",\n            help: \"Describe what worked\"\n          },\n          {\n            title: \"What did not work?\",\n            help: \"Describe what did not work in detail\"\n          },\n          {\n            title: \"Additional information\",\n            help: \"Provide extra details if needed\"\n          },\n        ],\n        includeDebugData: true,\n        privateTicket: true,\n        ghIssuePreset: \"report-compatibility.md\",\n        repositories: [] // not needed with the default being \"portmaster\"\n      },\n    ],\n  }\n]\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/progress-dialog/index.ts",
    "content": "export * from './progress-dialog';\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/progress-dialog/progress-dialog.html",
    "content": "<!-- Progress Indicator -->\n<div *ngIf=\"state !== 'error' && state !== 'done'\">\n\n  <caption class=\"text-xxs text-secondary\">Status</caption>\n\n  <div class=\"flex flex-row gap-2\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-5 h-5 animate animate-spin\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99\" />\n    </svg>\n\n    <div [ngSwitch]=\"state\">\n      <!-- Uploading debug data -->\n      <ng-template ngSwitchCase=\"debug-info\">\n        <span>Uploading debug data ....</span>\n      </ng-template>\n\n      <!-- Github Issue -->\n      <ng-template ngSwitchCase=\"create-issue\">\n        <span>Creating GitHub issue ...</span>\n      </ng-template>\n\n      <!-- Private ticket -->\n      <ng-template ngSwitchCase=\"create-ticket\">\n        <span>Creating private support ticket ...</span>\n      </ng-template>\n    </div>\n  </div>\n</div>\n\n\n<!-- Issue/ticket creation successfull -->\n<ng-template [ngIf]=\"state === 'done'\">\n  <span class=\"flex flex-row gap-2 items-center justify-start\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"0.75\" stroke=\"currentColor\"\n      class=\"text-green-300 w-10 h-10\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z\" />\n    </svg>\n\n    <span class=\"text-base text-primary\">\n      <ng-template [ngIf]=\"dialogRef.data.type === 'github' && dialogRef.data.generateUrl\">\n        Ticket prepared successfully\n      </ng-template>\n\n      <ng-template [ngIf]=\"dialogRef.data.type !== 'github' || !dialogRef.data.generateUrl\">\n        Ticket created successfully!\n      </ng-template>\n    </span>\n  </span>\n\n  <div *ngIf=\"dialogRef.data.type === 'github' && dialogRef.data.generateUrl\">\n    <span>Use the following button to open the pre-filled GitHub issue form:</span>\n\n    <br />\n\n    <div class=\"flex flex-row items-center justify-center p-4\">\n      <button class=\"bg-blue\" (click)=\"integration.openExternal(url)\">Create Issue</button>\n    </div>\n  </div>\n\n  <div *ngIf=\"dialogRef.data.type === 'github' && !dialogRef.data.generateUrl\" class=\"flex flex-col\">\n    <span>\n      We successfully create the issue on GitHub for you.\n      <br />\n      Use the following link to check for updates:\n    </span>\n\n    <span class=\"inline-block w-full text-center mt-4 underline text-secondary\"\n      (click)=\"integration.openExternal(url)\">{{ url }}</span>\n  </div>\n\n  <span *ngIf=\"dialogRef.data.type === 'private' && dialogRef.data.email\">\n    We will contact you as soon as possbile.\n  </span>\n</ng-template>\n\n<!-- An error occured -->\n<div *ngIf=\"state === 'error'\" class=\"flex flex-col gap-2\">\n\n  <span class=\"flex flex-row gap-2 items-center justify-start\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"0.75\" stroke=\"currentColor\"\n      class=\"text-red-300 w-10 h-10\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z\" />\n    </svg>\n\n    <span class=\"text-base text-primary\">\n      Failed to create Support Ticket\n    </span>\n  </span>\n\n\n  <span>\n    An error occured while creating your support ticket:\n  </span>\n\n  <span class=\"text-red block w-full text-center\">\n    {{ error || 'Unknown Error' }}\n  </span>\n</div>\n\n\n<div class=\"flex flex-row justify-center items-center gap-2\">\n\n  <button *ngIf=\"state === 'done' && !!url && dialogRef.data.type === 'github' && !dialogRef.data.generateUrl \"\n    class=\"bg-blue\" (click)=\"integration.openExternal(url)\">Open Issue</button>\n\n  <button *ngIf=\"state === 'done' && !!url && dialogRef.data.type === 'github' && !dialogRef.data.generateUrl \"\n    (click)=\"copyUrl()\">Copy URL</button>\n\n  <button (click)=\"dialogRef.close()\" class=\"btn\">Close</button>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/progress-dialog/progress-dialog.ts",
    "content": "import { ComponentPortal } from \"@angular/cdk/portal\";\nimport { HttpErrorResponse } from \"@angular/common/http\";\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentRef, EventEmitter, OnInit, inject } from \"@angular/core\";\nimport { SFNG_DIALOG_REF, SfngDialogRef, SfngDialogService } from \"@safing/ui\";\nimport { Observable, map, mergeMap, of } from \"rxjs\";\nimport { INTEGRATION_SERVICE } from \"src/app/integration\";\nimport { SupportHubService, SupportSection } from \"src/app/services\";\nimport { ActionIndicatorService } from \"src/app/shared/action-indicator\";\n\nexport interface TicketData {\n  debugInfo: string;\n  repo: string;\n  title: string;\n  sections: SupportSection[];\n}\n\nexport interface GithubIssue extends TicketData {\n  type: 'github',\n  generateUrl?: boolean;\n  preset?: string;\n}\n\nexport interface PrivateTicket extends TicketData {\n  type: 'private',\n  email?: string,\n}\n\nexport type TicketInfo = GithubIssue | PrivateTicket;\n\n\n@Component({\n  templateUrl: './progress-dialog.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styles: [\n    `\n    :host {\n      @apply block flex flex-col gap-8 relative;\n    }\n    `,\n  ]\n})\nexport class SupportProgressDialogComponent implements OnInit {\n\n  /** Static method to open the support-progress dialog. */\n  static open(dialog: SfngDialogService, data: TicketInfo): Observable<void> {\n    const ref = dialog.create(SupportProgressDialogComponent, {\n      data,\n      dragable: true,\n      backdrop: false,\n      autoclose: false,\n    });\n\n    return (ref.contentRef() as ComponentRef<SupportProgressDialogComponent>)\n      .instance\n      .done;\n  }\n\n\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly supporthub = inject(SupportHubService);\n  private readonly uai = inject(ActionIndicatorService);\n\n  readonly integration = inject(INTEGRATION_SERVICE);\n\n  readonly dialogRef: SfngDialogRef<this, any, TicketInfo> = inject(SFNG_DIALOG_REF);\n\n  /** Holds the current state of the issue-creation */\n  state: '' | 'debug-info' | 'create-issue' | 'create-ticket' | 'done' | 'error' = '';\n\n  /** The URL to the github issue once it was created. */\n  url: string = '';\n\n  /** The error message if one occured */\n  error: string = '';\n\n  /** Emits once the issue has been created successfully */\n  done = new EventEmitter<void>;\n\n  ngOnInit(): void {\n    this.createSupportRequest();\n  }\n\n  setState(state: typeof this['state']) {\n    this.state = state;\n    this.cdr.detectChanges();\n  }\n\n  createSupportRequest(): void {\n    const data = this.dialogRef.data;\n    let stream = of('')\n\n    // Upload debug info\n    if (data.debugInfo) {\n      stream = new Observable((observer) => {\n        this.state = 'debug-info';\n        this.cdr.detectChanges();\n\n        this.supporthub.uploadText('debug-info', data.debugInfo)\n          .subscribe(observer);\n      })\n    }\n\n    // either create on github or create a private ticket through support-hub\n    if (data.type === 'github') {\n      stream = stream.pipe(\n        mergeMap((url) => {\n          this.state = 'create-issue';\n          this.cdr.detectChanges();\n\n          return this.supporthub.createIssue(\n            data.repo,\n            data.preset || '',\n            data.title,\n            data.sections,\n            url,\n            {\n              generateUrl: data.generateUrl || false\n            },\n          );\n        })\n      )\n    } else {\n      stream = stream.pipe(\n        mergeMap((url) => {\n          this.state = 'create-ticket';\n          this.cdr.markForCheck();\n\n          return this.supporthub.createTicket(\n            data.repo,\n            data.title,\n            data.email || '',\n            data.sections,\n            url\n          )\n        }),\n        map(() => '')\n      )\n    }\n\n    stream.subscribe({\n      next: (url) => {\n        this.state = 'done';\n        this.url = url;\n        this.cdr.markForCheck();\n\n        this.done.next();\n      },\n\n      error: (err) => {\n        console.error(\"error\", err);\n\n        this.state = 'error';\n        if (err instanceof HttpErrorResponse && err.error instanceof ProgressEvent) {\n          this.error = err.statusText;\n        } else {\n          this.error = this.uai.getErrorMessage(err);\n        }\n\n        this.cdr.markForCheck();\n      }\n    });\n  }\n\n  copyUrl() {\n    if (!this.url) {\n      return\n    }\n\n    this.integration.writeToClipboard(this.url)\n      .then(() => this.uai.success('URL Copied To Clipboard'))\n      .catch(err => this.uai.error('Failed to Copy To Clipboard', this.uai.getErrorMessage(err)))\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/support.html",
    "content": "<div class=\"header\">\n  <h4 class=\"breadcrumbs\">\n    <span>Get Help</span>\n  </h4>\n  <app-expertise></app-expertise>\n</div>\n\n<div class=\"list-container\" [@fadeIn]=\"true\">\n  <div *ngFor=\"let section of supportTypes\" class=\"page-section\" [class.small]=\"section.style === 'small'\">\n    <div *ngIf=\"!!section.title\" class=\"section-title\">\n      <h4 class=\"text-lg text-primary -mt-1.5\">{{section.title}}</h4>\n    </div>\n\n    <div class=\"option-list\">\n      <section *ngFor=\"let item of section.choices\" (click)=\"openPage(item)\" [@fadeInList]=\"section.choices.length\">\n        <fa-icon *ngIf=\"!!item.type\" icon=\"external-link-alt\"></fa-icon>\n\n        <h3>{{item.title}}</h3>\n        <label *ngIf=\"!item.type\" class=\"secondary-text\">{{ item.shortHelp || item.prologue}}</label>\n        <label *ngIf=\"item.type\" class=\"secondary-text\">{{ item.shortHelp}}</label>\n      </section>\n    </div>\n  </div>\n</div>\n\n<!--\nTODO: Remove when not needed anymore.\n<div class=\"list-container\">\n  <div class=\"page-section\">\n    <div class=\"section-title\">\n      <h4 class=\"text-lg text-primary -mt-1.5\">FAQ</h4>\n    </div>\n\n    <input type=\"text\" [(ngModel)]=\"searchTerm\" (ngModelChange)=\"searchFaqs.next($event)\" placeholder=\"Search FAQs\"\n      class=\"mb-2\">\n\n    <div class=\"flex flex-col gap-2\">\n      <section *ngFor=\"let faq of faqEntries\" [@fadeInList]=\"faqEntries.length\" (click)=\"openIssue(faq)\"\n        class=\"flex flex-row items-center w-full p-3 bg-gray-200 rounded cursor-pointer hover:bg-gray-300\">\n        <span class=\"flex-grow\">\n          {{ faq.title }}\n        </span>\n        <fa-icon icon=\"external-link-alt\" class=\"text-secondary\"></fa-icon>\n      </section>\n    </div>\n  </div>\n</div>\n-->\n\n<div class=\"flex-grow\"></div>\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/support.scss",
    "content": ":host {\n  width: 100%;\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n  overflow: auto;\n}\n\n.list-container {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: flex-start;\n\n  .section-title {\n    margin-top: 20px;\n    margin-bottom: 40px;\n    position: relative;\n    border-bottom: 1px solid rgba(255, 255, 255, .2);\n\n    h4 {\n      position: absolute;\n      top: -0.5rem;\n      background-color: var(--background);\n      @apply pr-8;\n    }\n  }\n\n  .page-section {\n    width: 100%;\n    display: flex;\n    justify-content: stretch;\n    align-items: stretch;\n    flex-direction: column;\n    @apply px-4;\n\n    @media (min-width: 1250px) {\n      max-width: 800px;\n    }\n  }\n\n  .option-list {\n    display: grid;\n    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n    grid-gap: 20px;\n    grid-auto-rows: 1fr;\n\n    width: 100%;\n    margin-bottom: 20px;\n\n    section {\n      @apply bg-cards-secondary;\n      @apply p-8;\n      @apply rounded;\n      transition: all 250ms ease-in-out;\n      position: relative;\n      cursor: pointer;\n\n      &:hover {\n        @apply bg-cards-tertiary;\n      }\n\n      fa-icon {\n        position: absolute;\n        top: 1rem;\n        right: 1rem;\n        opacity: .4;\n      }\n    }\n\n\n  }\n\n  .small .option-list section {\n    @apply p-4;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/pages/support/support.ts",
    "content": "import { Component, DestroyRef, OnInit, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Router } from '@angular/router';\nimport { BehaviorSubject, combineLatest, debounceTime } from 'rxjs';\nimport { Issue, SupportHubService } from 'src/app/services';\nimport { fadeInAnimation, fadeInListAnimation } from 'src/app/shared/animations';\nimport { FuzzySearchService } from 'src/app/shared/fuzzySearch';\nimport { SupportType, supportTypes } from './pages';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\n\n@Component({\n  templateUrl: './support.html',\n  styleUrls: ['./support.scss'],\n  animations: [\n    fadeInListAnimation,\n    fadeInAnimation,\n  ]\n})\nexport class SupportPageComponent implements OnInit {\n  // make supportTypes available in the page template.\n  readonly supportTypes = supportTypes;\n\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  /** @private The current search term for the FAQ entries. */\n  searchFaqs = new BehaviorSubject<string>('');\n\n  searchTerm: string = '';\n\n  /** A list of all faq entries loaded from the Support Hub */\n  allFaqEntries: Issue<Date>[] = [];\n\n  /** A list of faq entries to show */\n  faqEntries: Issue<Date>[] = [];\n\n  constructor(\n    private router: Router,\n    private searchService: FuzzySearchService,\n    private supportHub: SupportHubService,\n  ) { }\n\n  ngOnInit(): void {\n    combineLatest([\n      this.searchFaqs,\n      this.supportHub.loadIssues()\n    ])\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        debounceTime(200),\n      )\n      .subscribe(([searchTerm, allFaqEntries]) => {\n        this.allFaqEntries = allFaqEntries\n          .filter(issue => issue.labels?.includes(\"faq\"))\n          .map(issue => {\n            return {\n              ...issue,\n\n              title: issue.title.replace(\"FAQ: \", \"\")\n            }\n          })\n\n        if (searchTerm === '') {\n          this.faqEntries = [\n            ...this.allFaqEntries\n          ]\n\n          return;\n        }\n\n        this.faqEntries = this.searchService.searchList(this.allFaqEntries, searchTerm, {\n          disableHighlight: true,\n          shouldSort: true,\n          isCaseSensitive: false,\n          minMatchCharLength: 3,\n          keys: [\n            'title',\n            'body',\n          ],\n        }).map(res => res.item)\n      })\n  }\n\n  openIssue(issue: Issue<any>) {\n    this.integration.openExternal(issue.url);\n  }\n\n  openPage(item: SupportType) {\n    if (item.type === 'link') {\n      this.integration.openExternal(item.url);\n      return;\n    }\n\n    this.router.navigate(['/support', item.id]);\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/prompt-entrypoint/prompt-entrypoint.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { Component, OnInit, TrackByFunction, inject } from \"@angular/core\";\nimport { AppProfile, AppProfileService, PortapiService } from \"@safing/portmaster-api\";\nimport { combineLatest, forkJoin, map, of, switchMap } from \"rxjs\";\nimport { ConnectionPrompt, NotificationType, NotificationsService } from \"../services\";\nimport { SfngAppIconModule } from \"../shared/app-icon\";\nimport { getCurrentWindow } from '@tauri-apps/api/window';\nimport { CountryFlagModule } from \"../shared/country-flag\";\n\ninterface Prompt {\n  prompts: ConnectionPrompt[];\n  profile: AppProfile;\n}\n\n@Component({\n  standalone: true,\n  selector: 'app-root',\n  templateUrl: './prompt.html',\n  imports: [\n    CommonModule,\n    SfngAppIconModule,\n    CountryFlagModule\n  ]\n})\nexport class PromptEntryPointComponent implements OnInit {\n  private readonly notificationService = inject(NotificationsService);\n  private readonly portapi = inject(PortapiService);\n  private readonly profileService = inject(AppProfileService);\n\n  prompts: Prompt[] = [];\n\n  trackPrompt: TrackByFunction<ConnectionPrompt> = (_, p) => p.EventID;\n  trackProfile: TrackByFunction<Prompt> = (_, p) => p.profile._meta!.Key;\n\n  ngOnInit(): void {\n\n    this.notificationService\n      .new$\n      .pipe(\n        map(notifs => {\n          return notifs.filter(n => n.Type === NotificationType.Prompt && n.EventID.startsWith(\"filter:prompt\"))\n        }),\n        switchMap(notifications => {\n          const distictProfiles = new Map<string, ConnectionPrompt[]>();\n          notifications.forEach(n => {\n            const key = `${n.EventData!.Profile.Source}/${n.EventData!.Profile.ID}`\n            const arr = distictProfiles.get(key) || [];\n            arr.push(n);\n            distictProfiles.set(key, arr);\n          });\n\n          if (distictProfiles.size === 0) {\n            return of([]);\n          }\n\n          return combineLatest(Array.from(distictProfiles.entries()).map(([key, prompts]) => forkJoin({\n            profile: this.profileService.getAppProfile(key),\n            prompts: of(Array.from(prompts))\n          })));\n        })\n      )\n      .subscribe(result => {\n        this.prompts = result;\n\n        // show the prompt now since we're ready\n        if (this.prompts.length) {\n          getCurrentWindow()!.show();\n        }\n      })\n  }\n\n  selectAction(prompt: ConnectionPrompt, action: string) {\n    prompt.SelectedActionID = action;\n\n    this.portapi.update(prompt._meta!.Key, prompt)\n      .subscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/prompt-entrypoint/prompt.html",
    "content": "<div class=\"w-full h-full flex flex-col p-4 gap-4\">\n\n  <header class=\"flex flex-row justify-start items-center gap-4\">\n    <img src=\"/assets/icons/pm_light_256.png\" class=\"w-10 h-10\">\n    <h1 class=\"m-0\">Portmaster</h1>\n  </header>\n\n  <div class=\"flex flex-col gap-2\">\n    <label class=\"text-xxs font-light text-white\">Some applications want to establish connections:</label>\n\n    <ng-container *ngFor=\"let prompt of prompts; trackBy: trackProfile\">\n\n      <div class=\"flex flex-row items-start justify-start gap-4 rounded bg-gray-100 shadow-inner p-2\">\n        <div style=\"min-width: 200px\"\n          class=\"flex flex-row items-center justify-start gap-3 flex-initial flex-shrink-0 flex-grow-0 pt-2\">\n          <app-icon class=\"[--app-icon-size:48px]\" [profile]=\"prompt.profile\"></app-icon>\n          <span class=\"flex flex-col items-start justify-start\">\n            <span>{{ prompt.profile.Name }}</span>\n            <span class=\"text-white text-xxs font-light\">{{ prompt.profile.LinkedPath }}</span>\n          </span>\n        </div>\n\n        <div class=\"flex flex-col gap-2 flex-grow\">\n          <table class=\"custom flex-grow\">\n            <tbody>\n              <ng-container *ngFor=\"let prompt of prompt.prompts; trackBy: trackPrompt; let last=last\">\n\n                <tr>\n                  <td class=\"text-secondary p-1 w-16\">Domain:</td>\n                  <td class=\"p-1 text-left\">\n                    <span [appCountryFlags]=\"prompt.EventData?.Entity?.Country || ''\"></span>\n                    <span>\n                      {{ prompt.EventData?.Entity?.Domain || 'N/A' }}\n                    </span>\n                  </td>\n                  <td rowspan=\"2\">\n                    <div class=\"flex flex-row gap-2 items-center justify-end\">\n                      <button *ngFor=\"let action of prompt.AvailableActions\"\n                        (click)=\"selectAction(prompt, action.ID)\">{{action.Text}}</button>\n                    </div>\n                  </td>\n                </tr>\n\n                <tr>\n                  <td class=\"text-secondary p-1 w-16\">IP:</td>\n                  <td class=\"p-1 text-left\">{{ prompt.EventData?.Entity?.IP || 'N/A' }}</td>\n                </tr>\n\n\n                <tr *ngIf=\"!last\">\n                  <td colspan=\"3\">\n                    <div class=\"block h-2 mb-2 border-b border-dashed border-gray-300\"></div>\n                  </td>\n                </tr>\n\n              </ng-container>\n\n            </tbody>\n          </table>\n        </div>\n      </div>\n    </ng-container>\n  </div>\n\n</div>"
  },
  {
    "path": "desktop/angular/src/app/services/index.ts",
    "content": "export { NotificationsService } from './notifications.service';\nexport * from './notifications.types';\nexport * from './session-data.service';\nexport { StatusService } from './status.service';\nexport * from './status.types';\nexport * from './supporthub.service';\nexport * from './ui-state.service';\n\n"
  },
  {
    "path": "desktop/angular/src/app/services/notifications.service.spec.ts",
    "content": "import { TestBed } from '@angular/core/testing';\nimport { WebsocketService } from '@safing/portmaster-api';\nimport { MockWebSocketSubject } from '@safing/portmaster-api/testing';\nimport { PartialObserver } from 'rxjs';\nimport { NotificationsService } from './notifications.service';\nimport { Notification, NotificationType } from './notifications.types';\n\ndescribe('NotificationsService', () => {\n  let service: NotificationsService;\n  let mock: MockWebSocketSubject;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        {\n          provide: WebsocketService,\n          useValue: MockWebSocketSubject,\n        }\n      ]\n    });\n    service = TestBed.inject(NotificationsService);\n    mock = MockWebSocketSubject.lastMock!;\n  });\n\n  afterEach(() => {\n    mock.close();\n  })\n\n  it('should be created', () => {\n    expect(service).toBeTruthy();\n  });\n\n  it('should allow to query for notifications', () => {\n    const observer = createSpyObserver();\n    service.query(\"updates:\").subscribe(observer);\n\n    mock.expectLastMessage()\n    mock.expectLastMessage('type').toBe('query')\n    mock.expectLastMessage('query').toBe('notifications:all/updates:')\n\n    mock.lastMultiplex!.next({\n      id: mock.lastRequestId!,\n      type: 'ok',\n      data: {\n        ID: 'updates:core-update-available',\n        Message: 'Update available',\n      },\n      key: 'notifications:all/updates:core-update-available'\n    })\n\n    mock.lastMultiplex!.next({\n      id: mock.lastRequestId!,\n      type: 'ok',\n      data: {\n        ID: 'updates:ui-reload-required',\n        Message: 'UI reload required',\n      },\n      key: 'notifications:all/updates:ui-reload-required'\n    })\n\n    // query collects all notifications using toArray\n    // so nothing should be nexted yet.\n    expect(observer.next).not.toHaveBeenCalled()\n    expect(observer.error).not.toHaveBeenCalled()\n    expect(observer.complete).not.toHaveBeenCalled()\n\n    // finish the strea\n    mock.lastMultiplex!.next({\n      id: mock.lastRequestId!,\n      type: 'done'\n    })\n\n    expect(observer.next).toHaveBeenCalledWith([\n      {\n        ID: 'updates:core-update-available',\n        Message: 'Update available',\n      },\n      {\n        ID: 'updates:ui-reload-required',\n        Message: 'UI reload required',\n      }\n    ])\n    expect(observer.error).not.toHaveBeenCalled()\n    expect(observer.complete).toHaveBeenCalled()\n  });\n\n  describe('execute notification actions', () => {\n    it('should work using a notif object', () => {\n      let observer = createSpyObserver();\n      let notif: any = {\n        ID: 'updates:core-update-available',\n        Message: 'An update is available',\n        Type: NotificationType.Info,\n        AvailableActions: [{ ID: \"restart\", Text: \"Restart\" }],\n      }\n\n      service.execute(notif, \"restart\").subscribe(observer);\n\n      expect(observer.error).not.toHaveBeenCalled()\n\n      mock.expectLastMessage('type').toBe('update');\n      mock.expectLastMessage('key').toBe('notifications:all/updates:core-update-available');\n      mock.expectLastMessage('data').toEqual({\n        ID: 'updates:core-update-available',\n        SelectedActionID: 'restart',\n      });\n\n      mock.lastMultiplex!.next({\n        id: mock.lastRequestId!,\n        type: 'success'\n      })\n\n      expect(observer.next).toHaveBeenCalledWith(undefined);\n      expect(observer.error).not.toHaveBeenCalled();\n      expect(observer.complete).toHaveBeenCalled();\n    });\n\n    it('should throw when executing an unknown action using a notif object', () => {\n      let observer = createSpyObserver();\n      let notif: any = {\n        ID: 'updates:core-update-available',\n        Message: 'An update is available',\n        Type: NotificationType.Info,\n        AvailableActions: [{ ID: \"restart\", Text: \"Restart\" }],\n      }\n\n      service.execute(notif, \"restart-with-typo\").subscribe(observer);\n\n      expect(observer.error).toHaveBeenCalled()\n      expect(mock.lastMessageSent).toBeUndefined();\n    });\n\n    it('should work using a key', () => {\n      let observer = createSpyObserver();\n      service.execute(\"updates:core-update-available\", \"restart\").subscribe(observer);\n\n      expect(observer.error).not.toHaveBeenCalled()\n\n      mock.expectLastMessage('type').toBe('update');\n      mock.expectLastMessage('key').toBe('notifications:all/updates:core-update-available');\n      mock.expectLastMessage('data').toEqual({\n        ID: 'updates:core-update-available',\n        SelectedActionID: 'restart',\n      });\n\n      mock.lastMultiplex!.next({\n        id: mock.lastRequestId!,\n        type: 'success'\n      })\n\n      expect(observer.next).toHaveBeenCalledWith(undefined);\n      expect(observer.error).not.toHaveBeenCalled();\n      expect(observer.complete).toHaveBeenCalled();\n    });\n  })\n\n  describe('resolving pending actions', () => {\n    it('should work using a notif object', () => {\n      let observer = createSpyObserver();\n      let notif: any = {\n        ID: 'updates:core-update-available',\n        Message: 'An update is available',\n        Type: NotificationType.Info,\n        Responded: Math.round(Date.now() / 1000),\n        SelectedActionID: \"restart\",\n      }\n\n      service.resolvePending(notif, 100).subscribe(observer)\n\n      expect(observer.error).not.toHaveBeenCalled()\n\n      mock.expectLastMessage('type').toBe('update');\n      mock.expectLastMessage('key').toBe('notifications:all/updates:core-update-available');\n      mock.expectLastMessage('data').toEqual({\n        ID: 'updates:core-update-available',\n        Executed: 100,\n      });\n\n      mock.lastMultiplex!.next({\n        id: mock.lastRequestId!,\n        type: 'success'\n      })\n\n      expect(observer.next).toHaveBeenCalledWith(undefined);\n      expect(observer.error).not.toHaveBeenCalled();\n      expect(observer.complete).toHaveBeenCalled();\n    });\n\n    it('should throw on an executed notification using a notif object', () => {\n      let observer = createSpyObserver();\n      let notif: any = {\n        ID: 'updates:core-update-available',\n        Message: 'An update is available',\n        Type: NotificationType.Info,\n        SelectedActionID: 'restart',\n        Responded: Math.round(Date.now() / 1000),\n        Executed: Math.round(Date.now() / 1000),\n      }\n\n      service.resolvePending(notif).subscribe(observer);\n\n      expect(observer.error).toHaveBeenCalled()\n      expect(mock.lastMessageSent).toBeUndefined();\n    });\n\n    it('should work using a key', () => {\n      let observer = createSpyObserver();\n      service.resolvePending(\"updates:core-update-available\", 100).subscribe(observer);\n\n      expect(observer.error).not.toHaveBeenCalled()\n\n      mock.expectLastMessage('type').toBe('update');\n      mock.expectLastMessage('key').toBe('notifications:all/updates:core-update-available');\n      mock.expectLastMessage('data').toEqual({\n        ID: 'updates:core-update-available',\n        Executed: 100,\n      });\n\n      mock.lastMultiplex!.next({\n        id: mock.lastRequestId!,\n        type: 'success'\n      })\n\n      expect(observer.next).toHaveBeenCalledWith(undefined);\n      expect(observer.error).not.toHaveBeenCalled();\n      expect(observer.complete).toHaveBeenCalled();\n    });\n  });\n\n  describe('watching notifications', () => {\n    it('should be possible to watch for new and action-required notifs only', () => {\n      const observer = createSpyObserver();\n      service.new$.subscribe(observer);\n\n      let send = (msg: any) => {\n        mock.lastMultiplex!.next({\n          id: mock.lastRequestId!,\n          data: msg,\n          type: 'ok',\n          key: \"notifications:all/\" + msg.ID,\n        })\n      }\n\n      let n1 = {\n        ID: \"new-notif-1\",\n        Message: \"a new notification\",\n        Responded: 0,\n        Executed: 0,\n        Expires: Math.round(Date.now() / 1000) + 60 * 60,\n      }\n      let n2 = {\n        ID: \"new-notif-2\",\n        Message: \"a new notification\",\n        Responded: 0,\n        Executed: 0,\n        Expires: 0,\n        AvailableActions: [{ ID: \"action-id\", Text: \"some action\" }],\n      }\n      let expired = {\n        ID: \"new-notif-3\",\n        Message: \"a new notification\",\n        Responded: 0,\n        Executed: 0,\n        Expires: 100,\n      }\n      let pending = {\n        ID: \"new-notif-4\",\n        Message: \"a new notification\",\n        Responded: Math.round(Date.now() / 1000),\n        Executed: 0,\n        SelectedActionID: \"test\",\n      }\n\n      send(n1)\n      send(expired)\n      send(n2)\n      send(pending)\n\n      expect(observer.complete).not.toHaveBeenCalled()\n      expect(observer.error).not.toHaveBeenCalled()\n      expect(observer.next).toHaveBeenCalledTimes(2)\n      expect(observer.next).toHaveBeenCalledWith(n1)\n      expect(observer.next).toHaveBeenCalledWith(n2)\n    })\n  })\n\n  describe('creating notifications', () => {\n    it('should be possible using an object', () => {\n      let notification: Partial<Notification<any>> = {\n        ID: 'my-awesome-notification',\n        AvailableActions: [\n          { ID: 'action-no', Text: 'No' },\n          { ID: 'force-no', Text: 'Hell No' }\n        ],\n        Message: 'Update complete, do you want to reboot?',\n        Persistent: true,\n        Type: NotificationType.Warning,\n      }\n\n      let observer = createSpyObserver();\n      service.create(notification).subscribe(observer);\n\n      expect(observer.error).not.toHaveBeenCalled();\n\n      mock.expectLastMessage('type').toBe('create')\n      mock.expectLastMessage('key').toBe('notifications:all/my-awesome-notification')\n      mock.expectLastMessage('data').toEqual(notification);\n      expect(notification.Created).toBeTruthy();\n\n      mock.lastMultiplex!.next({\n        type: 'success',\n        id: mock.lastRequestId!,\n      })\n\n      expect(observer.complete).toHaveBeenCalled()\n      expect(observer.error).not.toHaveBeenCalled()\n      expect(observer.next).toHaveBeenCalledWith(undefined)\n    })\n\n    it('should be possible using parameters', () => {\n      let observer = createSpyObserver();\n      service.create('my-param-notification', 'message', NotificationType.Prompt, {\n        Persistent: true,\n        Created: 100,\n      }).subscribe(observer);\n\n      expect(observer.error).not.toHaveBeenCalled();\n\n      mock.expectLastMessage('type').toBe('create')\n      mock.expectLastMessage('key').toBe('notifications:all/my-param-notification')\n      mock.expectLastMessage('data').toEqual({\n        Type: NotificationType.Prompt,\n        ID: 'my-param-notification',\n        Message: 'message',\n        Created: 100,\n        Persistent: true,\n      });\n\n      mock.lastMultiplex!.next({\n        type: 'success',\n        id: mock.lastRequestId!,\n      })\n\n      expect(observer.complete).toHaveBeenCalled()\n      expect(observer.error).not.toHaveBeenCalled()\n      expect(observer.next).toHaveBeenCalledWith(undefined)\n\n    })\n  })\n});\n\nfunction createSpyObserver(): PartialObserver<any> {\n  return jasmine.createSpyObj(\"observer\", [\"next\", \"error\", \"complete\"])\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/notifications.service.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { Injectable, TrackByFunction, inject } from '@angular/core';\nimport { Params, Router } from '@angular/router';\nimport { PortapiService, RetryableOpts } from '@safing/portmaster-api';\nimport { BehaviorSubject, Observable, combineLatest, defer, throwError } from 'rxjs';\nimport { map, share, toArray } from 'rxjs/operators';\nimport { environment } from 'src/environments/environment';\nimport { ActionIndicatorService } from '../shared/action-indicator';\nimport { Action, ActionHandler, NetqueryAction, Notification, NotificationState, NotificationType, OpenPageAction, OpenProfileAction, OpenSettingAction, OpenURLAction, PageIDs, WebhookAction } from './notifications.types';\nimport { VirtualNotification } from './virtual-notification';\nimport { INTEGRATION_SERVICE } from '../integration';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NotificationsService {\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  /**\n   * A {@link TrackByFunction} from tracking notifications.\n   */\n  static trackBy: TrackByFunction<Notification<any>> = function (_: number, n: Notification<any>) {\n    return n.EventID;\n  };\n\n  /**\n   * This object contains handler methods for all\n   * notification action types we currently support.\n   */\n  private actionHandler: {\n    [key in Action['Type']]: (a: any) => Promise<any>;\n  } = {\n      '': async () => { },\n      'open-url': async (a: OpenURLAction) => {\n        await this.integration.openExternal(a.Payload);\n      },\n      'open-profile': (a: OpenProfileAction) => this.router.navigate([\n        '/app', ...a.Payload.split('/')\n      ]),\n      'open-setting': (a: OpenSettingAction) => {\n        if (a.Payload.Profile) {\n          return this.router.navigate(['/app', ...a.Payload.Profile.split('/')], {\n            queryParams: {\n              setting: a.Payload.Key,\n              tab: 'settings'\n            }\n          })\n        }\n        return this.router.navigate(['/settings'], {\n          queryParams: {\n            setting: a.Payload.Key\n          }\n        })\n      },\n      \"open-page\": (a: OpenPageAction) => {\n        let pageID: keyof typeof PageIDs | null = null;\n        let queryParams: Params | null = null;\n\n        if (typeof a.Payload === 'string') {\n          pageID = a.Payload;\n          queryParams = {};\n        } else {\n          pageID = a.Payload.id;\n          queryParams = a.Payload.query;\n        }\n\n        const url = PageIDs[pageID];\n        if (!!url) {\n          return this.router.navigate([url], {\n            queryParams,\n          })\n        }\n        return Promise.reject('not yet supported');\n      },\n      \"ui\": (a: ActionHandler<any>) => {\n        return a.Run(a);\n      },\n      \"netquery\": (a: NetqueryAction) => {\n        return this.router.navigate(['/monitor'], {\n          queryParams: {\n            q: a.Payload,\n          }\n        })\n      },\n      \"call-webhook\": (a: WebhookAction) => {\n        let method = a.Payload.Method;\n        if (method === '') {\n          if (a.Payload.Payload !== undefined && a.Payload.Payload !== null) {\n            method = 'PUT'\n          } else {\n            method = 'POST'\n          }\n        }\n        let req = this.http.request(\n          method,\n          `${environment.httpAPI}/v1/${a.Payload.URL}`,\n          {\n            body: a.Payload.Payload,\n            observe: 'response',\n            responseType: 'arraybuffer',\n          }\n        )\n        return new Promise((resolve, reject) => {\n          const observer = this.actionIndicator.httpObserver();\n          req.subscribe({\n            next: res => {\n              if (a.Payload.ResultAction === 'display') {\n                if (!!observer?.next) {\n                  observer.next(res)\n                }\n              }\n              resolve(res);\n            },\n            error: err => {\n              if (!!observer?.error) {\n                observer.error(err);\n              }\n              reject(err);\n            },\n          })\n        })\n      }\n    };\n\n  // For testing purposes only\n  VirtualNotification = VirtualNotification;\n\n  /** A map of virtual notifications */\n  private _virtualNotifications = new Map<string, VirtualNotification<any>>();\n\n  /* Emits all virtual notifications whenever they change */\n  private _virtualNotificationChange = new BehaviorSubject<VirtualNotification<any>[]>([]);\n\n  /* A copy of the static trackBy function. */\n  trackBy = NotificationsService.trackBy;\n\n  /** The prefix that all notifications have */\n  readonly notificationPrefix = \"notifications:all/\";\n\n  /** new$ emits new (active) notifications as they arrive */\n  readonly new$: Observable<Notification<any>[]>;\n\n  constructor(\n    private portapi: PortapiService,\n    private router: Router,\n    private http: HttpClient,\n    private actionIndicator: ActionIndicatorService,\n  ) {\n    this.new$ = this.watchAll().pipe(\n      src => this.injectVirtual(src),\n      map(msgs => {\n        return msgs.filter(msg => msg.State === NotificationState.Active || !msg.State)\n      }),\n      share({ connector: () => new BehaviorSubject<Notification<any>[]>([]) })\n    );\n  }\n\n  /**\n   * Inject a new virtual notification. If not configured otherwise,\n   * the notification is automatically removed when executed.\n   */\n  inject(notif: VirtualNotification<any>, { autoRemove } = { autoRemove: true }) {\n    this._virtualNotifications.set(notif.EventID, notif);\n    this._virtualNotificationChange.next(\n      Array.from(this._virtualNotifications.values())\n    )\n\n    if (autoRemove) {\n      notif.executed.subscribe({ complete: () => this.deject(notif) });\n    }\n  }\n\n  /** Deject (remove) a virtual notification. */\n  deject(notif: VirtualNotification<any>) {\n    this._virtualNotifications.delete(notif.EventID);\n\n    this._virtualNotificationChange.next(\n      Array.from(this._virtualNotifications.values())\n    )\n  }\n\n  /** A {@link MonoOperatorFunction} that injects all virtual observables into the source. */\n  private injectVirtual(obs: Observable<Notification<any>[]>): Observable<Notification[]> {\n    return combineLatest([\n      obs,\n      this._virtualNotificationChange,\n    ]).pipe(\n      map(([real, virtual]) => {\n        return [\n          ...real,\n          ...virtual,\n        ]\n      })\n    )\n  }\n\n  /**\n   * Watch all notifications that match a query.\n   *\n   *\n   * @param query The query to watch. Defaulta to all notifcations\n   * @param opts Optional retry configuration options.\n   */\n  watchAll<T = any>(query: string = '', opts?: RetryableOpts): Observable<Notification<T>[]> {\n    return this.portapi.watchAll<Notification<T>>(this.notificationPrefix + query, opts);\n  }\n\n  /**\n   * Query the backend for a list of notifications. In contrast\n   * to {@class PortAPI} query collects all results into an array\n   * first which makes it convenient to be used in *ngFor and\n   * friends. See {@function trackNotification} for a suitable track-by\n   * function.\n   *\n   * @param query The search query.\n   */\n  query(query: string): Observable<Notification<any>[]> {\n    return this.portapi.query<Notification<any>>(this.notificationPrefix + query)\n      .pipe(\n        map(value => value.data),\n        toArray()\n      )\n  }\n\n  /**\n   * Returns the notification by ID.\n   *\n   * @param id The ID of the notification\n   */\n  get<T>(id: string): Observable<Notification<T>> {\n    return this.portapi.get(this.notificationPrefix + id)\n  }\n\n  /**\n   * Execute an action attached to a notification.\n   *\n   * @param n The notification object.\n   * @param actionId The ID of the action to execute.\n   */\n  execute(n: Notification<any>, action: Action): Observable<void>;\n\n  /**\n   * Execute an action attached to a notification.\n   *\n   * @param notificationId The ID of the notification.\n   * @param actionId The ID of the action to execute.\n   */\n  execute(notificationId: string, action: Action): Observable<void>;\n\n  // overloaded implementation of execute\n  execute(notifOrId: Notification<any> | string, action: Action): Observable<void> {\n    const payload: Partial<Notification<any>> = {};\n    if (typeof notifOrId === 'string') {\n      payload.EventID = notifOrId;\n    } else {\n      payload.EventID = notifOrId.EventID;\n    }\n\n    // if it's a virtual notification we should let it handle the action\n    // on it's own.\n    if (!!this._virtualNotifications.get(payload.EventID)) {\n      return defer(async () => {\n        const notif = this._virtualNotifications.get(payload.EventID!);\n        if (!!notif) {\n          notif.selectAction(action.ID);\n        }\n      })\n    }\n\n    return defer(async () => {\n      try {\n        await this.performAction(action);\n\n        // finally, if there's an action ID, mark the notification as resolved.\n        if (!!action.ID) {\n          payload.SelectedActionID = action.ID;\n          const key = this.notificationPrefix + payload.EventID;\n          await this.portapi.update(key, payload).toPromise();\n        }\n      } catch (err: any) {\n        const msg = this.actionIndicator.getErrorMessgae(err);\n        this.actionIndicator.error('Internal Error', 'Failed to perform action: ' + msg)\n      }\n    })\n  }\n\n  async performAction(action: Action) {\n    // if there's an action type defined execute the handler.\n    if (!!action.Type) {\n      const handler = this.actionHandler[action.Type] as (a: Action) => Promise<any>;\n      if (!!handler) {\n        console.log(action);\n        await handler(action);\n      } else {\n        this.actionIndicator.error('Internal Error', 'Cannot handle action type ' + action.Type)\n      }\n    }\n  }\n\n  /**\n   * Resolve a pending notification execution.\n   *\n   * @param n The notification object to resolve the pending execution.\n   * @param time optional The time at which the pending execution took place\n   */\n  resolvePending(n: Notification<any>, time?: number): Observable<void>;\n\n  /**\n   * Resolve a pending notification execution.\n   *\n   * @param n The notification ID to resolve the pending execution.\n   * @param time optional The time at which the pending execution took place\n   */\n  resolvePending(n: string, time?: number): Observable<void>;\n\n  // overloaded implementation of resolvePending.\n  resolvePending(notifOrID: Notification<any> | string, time: number = (Math.round(Date.now() / 1000))): Observable<void> {\n    const payload: Partial<Notification<any>> = {};\n    if (typeof notifOrID === 'string') {\n      payload.EventID = notifOrID;\n    } else {\n      payload.EventID = notifOrID.EventID;\n      if (notifOrID.State === NotificationState.Executed) {\n        return throwError(`Notification ${notifOrID.EventID} already executed`);\n      }\n    }\n\n    payload.State = NotificationState.Responded;\n    const key = this.notificationPrefix + payload.EventID\n    return this.portapi.update(key, payload);\n  }\n\n  /**\n   * Delete a notification.\n   *\n   * @param n The notification to delete.\n   */\n  delete(n: Notification<any>): Observable<void>;\n\n  /**\n   * Delete a notification.\n   *\n   * @param n The notification to delete.\n   */\n  delete(id: string): Observable<void>;\n\n  // overloaded implementation of delete.\n  delete(notifOrId: Notification<any> | string): Observable<void> {\n    return this.portapi.delete(typeof notifOrId === 'string' ? notifOrId : notifOrId.EventID);\n  }\n\n  /**\n   * Create a new notification.\n   *\n   * @param n The notification to create.\n   */\n  create(n: Partial<Notification<any>>): Observable<void>;\n\n  /**\n   * Create a new notification.\n   *\n   * @param id The ID of the notificaiton.\n   * @param message The default message of the notificaiton.\n   * @param type The notification type\n   * @param args Additional arguments for the notification.\n   */\n  create(id: string, message: string, type: NotificationType, args?: Partial<Notification<any>>): Observable<void>;\n\n  // overloaded implementation of create.\n  create(notifOrId: Partial<Notification<any>> | string, message?: string, type?: NotificationType, args?: Partial<Notification<any>>): Observable<void> {\n    if (typeof notifOrId === 'string') {\n      notifOrId = {\n        ...args,\n        EventID: notifOrId,\n        State: NotificationState.Active,\n        Message: message,\n        Type: type,\n      } as Notification<any>; // it's actual Partial but that's fine.\n    }\n\n    if (!notifOrId.EventID) {\n      return throwError(`Notification ID is required`);\n    }\n\n    if (!notifOrId.Message) {\n      return throwError(`Notification message is required`);\n    }\n\n    if (typeof notifOrId.Type !== 'number') {\n      return throwError(`Notification type is required`);\n    }\n\n    return this.portapi.create(this.notificationPrefix + notifOrId.EventID, notifOrId);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/notifications.types.ts",
    "content": "import { getEnumKey, IntelEntity, Record } from '@safing/portmaster-api';\n\n/**\n * BaseAction defines a user selectable action and can\n * be attached to a notification. Once selected,\n * the action's ID is set as the SelectedActionID\n * of the notification.\n */\nexport interface BaseAction {\n  // ID uniquely identifies the action. It's safe to\n  // use ID to select a localizable template to use\n  // instead of the Text property. If Type is set\n  // to None the ID may be empty, signifying that this\n  // action is merely to dismiss the notification.\n  ID: string;\n  // Text is the (default) text for the action label.\n  Text: string;\n  // Visibility specifies where the action should be visible. Default is always visible.\n  // Possible values are:\n  // - \"\": Action is always visible.\n  // - \"detailed\": Action is only visible in the detailed view of a notification.\n  // - \"in-app-only\": Visible only in the UI app, never on the system level (if ShowOnSystem is true).\n  Visibility: string; \n}\n\nexport interface GenericAction extends BaseAction {\n  Type: '';\n}\n\nexport interface OpenURLAction extends BaseAction {\n  Type: 'open-url';\n  Payload: string;\n}\n\nexport interface OpenPageAction extends BaseAction {\n  Type: 'open-page';\n  Payload: keyof typeof PageIDs | {\n    id: keyof typeof PageIDs,\n    query: {\n      [key: string]: string,\n    }\n  };\n}\n\nexport interface NetqueryAction extends BaseAction {\n  Type: 'netquery';\n  Payload: string;\n}\n\n/**\n * PageIDs holds a list of pages that can be opened using\n * the OpenPageAction.\n */\nexport const PageIDs = {\n  'monitor': '/monitor',\n  'support': '/support',\n  'settings': '/settings',\n  'apps': '/app/overview',\n  'spn': '/spn',\n}\n\nexport interface OpenSettingAction extends BaseAction {\n  Type: 'open-setting';\n  Payload: {\n    Key: string;\n    Profile?: string;\n  }\n}\n\nexport interface OpenProfileAction extends BaseAction {\n  Type: 'open-profile';\n  Payload: string;\n}\n\nexport interface WebhookAction extends BaseAction {\n  Type: 'call-webhook';\n  Payload: {\n    Method: string;\n    URL: string;\n    Payload: any;\n    ResultAction: 'ignore' | 'display';\n  }\n}\n\nexport interface ActionHandler<T> extends BaseAction {\n  Type: 'ui'\n  Run: (vn: T) => Promise<void>;\n  Payload: T;\n}\n\nexport type Action = GenericAction\n  | OpenURLAction\n  | OpenPageAction\n  | OpenSettingAction\n  | OpenProfileAction\n  | WebhookAction\n  | NetqueryAction\n  | ActionHandler<any>;\n\n/** All action types that perform in-application routing. */\nexport const routingActions = new Set<Action['Type']>([\n  'open-page',\n  'open-profile',\n  'open-setting'\n])\n\n/**\n * Available types of notifications. Notification\n * types are mainly for filtering and style related\n * decisions.\n */\nexport enum NotificationType {\n  // Info is an informational message only.\n  Info = 0,\n  // Warning is a warning message.\n  Warning = 1,\n  // Prompt asks the user for a decision.\n  Prompt = 2,\n  // Error is for error notifications and module\n  // failure status.\n  Error = 3,\n}\n\nexport interface ConnectionPromptData {\n  Profile: {\n    ID: string;\n    LinkedPath: string;\n    Source: 'local';\n  };\n  Entity: IntelEntity;\n}\n\n/**\n * Returns a string representation of the notifcation type.\n *\n * @param val The notifcation type\n */\nexport function getNotificationTypeString(val: NotificationType): string {\n  return getEnumKey(NotificationType, val)\n}\n\n/**\n * Each notification can be in one of six different states\n * that inform the client on how to handle the notification.\n */\nexport enum NotificationState {\n  // Active describes a notification that is active, no expired and,\n  // if actions are available, still waits for the user to select an\n  // action.\n  Active = \"active\",\n  // Responded describes a notification where the user has already\n  // selected which action to take but that action is still to be\n  // performed.\n  Responded = \"responded\",\n  // Responded describes a notification where the user has already\n  // selected which action to take but that action is still to be\n  // performed.\n  Executed = \"executed\",\n  // Invalid is a UI-only state that is used when the state of a\n  // notification is unknown.\n  Invalid = \"invalid\",\n}\n\nexport interface Notification<T = any> extends Record {\n  // EventID is used to identify a specific notification. It consists of\n  // the module name and a per-module unique event id.\n  // The following format is recommended:\n  // \t<module-id>:<event-id>\n  EventID: string;\n  // GUID is a unique identifier for each notification instance. That is\n  // two notifications with the same EventID must still have unique GUIDs.\n  // The GUID is mainly used for system (Windows) integration and is\n  // automatically populated by the notification package. Average users\n  // don't need to care about this field.\n  GUID: string;\n  // Type is the notification type. It can be one of Info, Warning or Prompt.\n  Type: NotificationType;\n  // Message is the default message shown to the user if no localized version\n  // of the notification is available. Note that the message should already\n  // have any paramerized values replaced. Message may be formatted using\n  // markdown.\n  Message: string;\n  // Title holds a short notification title that quickly informs the user\n  // about the type of notification.\n  Title: string;\n  // Category holds an informative category for the notification and is mainly\n  // used for presentation purposes.\n  Category: string;\n  // EventData contains an additional payload for the notification. This payload\n  // may contain contextual data and may be used by a localization framework\n  // to populate the notification message template.\n  // If EventData implements sync.Locker it will be locked and unlocked together with the\n  // notification. Otherwise, EventData is expected to be immutable once the\n  // notification has been saved and handed over to the notification or database package.\n  EventData: T | null;\n  // Expires holds the unix epoch timestamp at which the notification expires\n  // and can be cleaned up.\n  // Users can safely ignore expired notifications and should handle expiry the\n  // same as deletion.\n  Expires: number;\n  // State describes the current state of a notification. See State for\n  // a list of available values and their meaning.\n  State: NotificationState;\n  // AvailableActions defines a list of actions that a user can choose from.\n  AvailableActions: Action[];\n  // SelectedActionID is updated to match the ID of one of the AvailableActions\n  // based on the user selection.\n  SelectedActionID: string;\n}\n\nexport type ConnectionPrompt = Notification<ConnectionPromptData>;\n"
  },
  {
    "path": "desktop/angular/src/app/services/package.json",
    "content": "{\n  \"sideEffects\": false\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/session-data.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { distinctUntilChanged, map } from 'rxjs/operators';\n\n/**\n * SessionDataService is used to store transient data\n * that are only important as long as the application is\n * being used. Those data are not presisted and are\n * removed once the application is restarted.\n */\n@Injectable({\n  providedIn: 'root'\n})\nexport class SessionDataService {\n  private data = new Map<string, any>();\n  private stream = new BehaviorSubject<void>(undefined);\n\n  /** Set sets a value in the session data service */\n  set<T>(key: string, value: T): void {\n    this.data.set(key, value);\n  }\n\n  get<T>(key: string): T | null;\n  get<T>(key: string, def: T): T;\n\n  /** Get retrieves a value from the session data service */\n  get(key: string, def?: any): any {\n    const value = this.data.get(key);\n    if (value !== undefined) {\n      return value;\n    }\n\n    if (def !== undefined) {\n      return def;\n    }\n    return null;\n  }\n\n  watch<T>(key: string): Observable<T | null>;\n  watch<T>(key: string, def: T): Observable<T>;\n\n  /** Watch a key for changes to it's identity. */\n  watch<T>(key: string, def?: any): Observable<T | null> {\n    return this.stream\n      .pipe(\n        map(() => this.get<T>(key, def)),\n        distinctUntilChanged()\n      );\n  }\n\n  delete<T>(key: string): T | null {\n    let value = this.get<T>(key);\n    if (value !== null) {\n      this.data.delete(key);\n    }\n    return value;\n  }\n\n  save<M, K extends keyof M>(id: string, model: M, keys: K[]) {\n    let copy: Partial<M> = {};\n    keys.forEach(key => copy[key] = model[key]);\n    this.set(id, copy);\n  }\n\n  restore<M extends object, K extends keyof M>(id: string, model: M) {\n    let copy: Partial<M> | null = this.get(id);\n    if (copy === null) {\n      return;\n    }\n    Object.assign(model, copy);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/status.service.spec.ts",
    "content": "import { TestBed } from '@angular/core/testing';\n\nimport { StatusService } from './status.service';\n\ndescribe('StatusService', () => {\n  let service: StatusService;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({});\n    service = TestBed.inject(StatusService);\n  });\n\n  it('should be created', () => {\n    expect(service).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "desktop/angular/src/app/services/status.service.ts",
    "content": "import { Injectable, TrackByFunction } from '@angular/core';\nimport { PortapiService, RetryableOpts, SecurityLevel, WatchOpts, trackById } from '@safing/portmaster-api';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { filter, map, repeat, share, toArray } from 'rxjs/operators';\nimport { CoreStatus, Subsystem, VersionStatus } from './status.types';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class StatusService {\n  /**\n   * A {@link TrackByFunction} from tracking subsystems.\n   */\n  static trackSubsystem: TrackByFunction<Subsystem> = trackById;\n  readonly trackSubsystem = StatusService.trackSubsystem;\n  \n  /**\n   * status$ watches the global core status. It's mutlicasted using a BehaviorSubject so new\n   * subscribers will automatically get the latest version while only one subscription\n   * to the backend is held.\n   */\n  readonly status$: Observable<CoreStatus> = this.portapi.qsub<CoreStatus>(`runtime:system/status`)\n    .pipe(\n      repeat({ delay: 2000 }),\n      map(reply => reply.data),\n      share({ connector: () => new BehaviorSubject<CoreStatus | null>(null) }),\n      filter(value => value !== null),\n    ) as Observable<CoreStatus>; // we filtered out the null values but we cannot make that typed with RxJS.\n\n  constructor(private portapi: PortapiService) { }\n\n  /** Returns the currently available versions for all resources. */\n  getVersions(): Observable<VersionStatus> {\n    return this.portapi.get<VersionStatus>('core:status/versions')\n  }\n\n  /**\n   * Selectes a new security level. SecurityLevel.Off means that\n   * the auto-pilot should take over.\n   *\n   * @param securityLevel The security level to select\n   */\n  selectLevel(securityLevel: SecurityLevel): Observable<void> {\n    return this.portapi.update(`runtime:system/security-level`, {\n      SelectedSecurityLevel: securityLevel,\n    });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/status.types.ts",
    "content": "import { getEnumKey, Record, ReleaseLevel, SecurityLevel } from '@safing/portmaster-api';\n\nexport interface CaptivePortal {\n  URL: string;\n  IP: string;\n  Domain: string;\n}\n\nexport enum OnlineStatus {\n  Unknown = 0,\n  Offline = 1,\n  Limited = 2, // local network only,\n  Portal = 3,\n  SemiOnline = 4,\n  Online = 5,\n}\n\n/**\n * Converts a online status value to a string.\n *\n * @param stat The online status value to convert\n */\nexport function getOnlineStatusString(stat: OnlineStatus): string {\n  return getEnumKey(OnlineStatus, stat)\n}\n\nexport interface CoreStatus extends Record {\n  OnlineStatus: OnlineStatus;\n  CaptivePortal: CaptivePortal;\n  Modules: StateUpdate[]; // TODO: Do we need all modules?\n  WorstState: {\n    Module: string,\n    ID: string,\n    Name: string,\n    Message: string,\n    Type: ModuleStateType,\n    // Time: time.Time, // TODO: How do we best use Go's time.Time?\n    Data: any\n  }\n}\n\nexport interface StateUpdate {\n  Module: string;\n  States: State[];\n}\n\nexport interface State {  \n  ID: string;             // Program-unique identifier  \n  Name: string;           // State name (may serve as notification title)  \n  Message?: string;       // Detailed message about the state  \n  Type?: ModuleStateType; // State type  \n  Time?: Date;            // Creation time  \n  Data?: any;             // Additional data for processing\n}\n\nexport enum ModuleStateType {\n  Undefined = \"\",\n  Hint = \"hint\",\n  Warning = \"warning\",\n  Error = \"error\"\n}\n\n/**\n * Returns a string representation of a failure status value.\n *\n * @param stateType The module state type value.\n */\nexport function getModuleStateString(stateType: ModuleStateType): string {\n  return getEnumKey(ModuleStateType, stateType)\n}\n\nexport interface Module {\n  Enabled: boolean;\n  Name: string;\n}\n\nexport interface Subsystem extends Record {\n  ConfigKeySpace: string;\n  Description: string;\n  ExpertiseLevel: string;\n  ID: string;\n  Modules: Module[];\n  Name: string;\n  ReleaseLevel: ReleaseLevel;\n  ToggleOptionKey: string;\n}\n\nexport interface CoreVersion {\n  // Copied from base/info/version.go\n\n  Name:          string;\n  Version:       string;\n  VersionNumber: string;\n  License:       string;\n\n  Source:    string;\n  BuildTime: string;\n  CGO:       boolean;\n\n  Commit:     string;\n  CommitTime: string;\n  Dirty:      boolean;\n}\n\nexport interface ResourceVersion {\n  Available: boolean;\n  BetaRelease: boolean;\n  Blacklisted: boolean;\n  StableRelease: boolean;\n  VersionNumber: string;\n}\n\nexport interface Resource {\n  ActiveVersion: ResourceVersion | null;\n  Identifier: string;\n  SelectedVersion: ResourceVersion;\n  Versions: ResourceVersion[];\n}\n\nexport interface VersionStatus extends Record {\n  Channel: string;\n  Core: CoreVersion;\n  Resources: {\n    [key: string]: Resource\n  }\n}\n\nfunction getModuleStates(status: CoreStatus, moduleID: string): State[] {\n  const module = status.Modules?.find(m => m.Module === moduleID);\n  return module?.States || [];  \n}\n\n/**\n * Retrieves a specific state from a module within the CoreStatus.\n * @param status The CoreStatus object containing module states.\n * @param moduleID The identifier of the module to search within.\n * @param stateID The identifier of the state to retrieve.\n * @returns The State object if found; otherwise, null.\n * @example\n * ```typescript\n * const state = GetModuleState(status, 'Control', 'control:paused');\n * if (state) {\n *   console.log(`State found: ${state.Name}`);\n * } else {\n *   console.log('State not found');\n * }\n * ```\n */\nexport function GetModuleState(status: CoreStatus, moduleID: string, stateID: string): State | null {\n  const states = getModuleStates(status, moduleID);\n  for (const state of states) {\n    if (state.ID === stateID) {\n      return state;\n    }\n  }\n  return null;\n}\n\n/**\n * Data structure for the 'control:paused' state from the 'Control' module.\n * \n * This interface defines the expected structure of the Data field when Portmaster\n * or its components are temporarily paused by the user.\n * \n * @example\n * ```typescript\n * const pausedState = GetModuleState(status, 'Control', 'control:paused');\n * if (pausedState?.Data) {\n *   const pauseData = pausedState.Data as ControlPauseStateData;\n *   console.log(`SPN paused: ${pauseData.SPN}`);\n * }\n * ```\n */\nexport interface ControlPauseStateData { \n    Interception: boolean;  // Whether Portmaster interception is paused\n    SPN:          boolean;  // Whether SPN is paused    \n    TillTime:     string;   // When the pause will end (JSON date as string, has to be converted to Date)\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/supporthub.service.ts",
    "content": "import { HttpClient, HttpParams } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { environment } from 'src/environments/environment';\n\nexport interface SupportSection {\n  title: string;\n  body: string;\n}\n\nexport interface Issue<CreatedAt = Date> {\n  title: string;\n  body: string;\n  createdAt: CreatedAt;\n  repository: string;\n  url: string;\n  user: string;\n  closed?: boolean;\n  labels: string[];\n}\n\n@Injectable({ providedIn: 'root' })\nexport class SupportHubService {\n  constructor(private http: HttpClient) { }\n\n  loadIssues(): Observable<Issue[]> {\n    interface LoadIssuesResponse {\n      issues: Issue<string>[];\n    }\n    return this.http.get<LoadIssuesResponse>(`${environment.supportHub}/api/v1/issues`)\n      .pipe(map(res => res.issues.map(issue => ({\n        ...issue,\n        createdAt: new Date(issue.createdAt),\n      })).reverse()));\n  }\n\n  /** Uploads content under name */\n  uploadText(name: string, content: string): Observable<string> {\n    interface UploadResponse {\n      urls: {\n        [key: string]: string[];\n      }\n    }\n    const blob = new Blob([content], { type: 'text/plain' });\n    const data = new FormData();\n    data.set(\"file\", blob, name);\n\n    return this.http.post<UploadResponse>(`${environment.supportHub}/api/v1/upload`, data)\n      .pipe(map(res => res.urls['file'][0]));\n  }\n\n  /** Create github issue */\n  createIssue(repo: string, preset: string, title: string, sections: SupportSection[], debugInfoUrl?: string, opts?: {\n    generateUrl: boolean,\n  }): Observable<string> {\n    interface CreateIssueResponse {\n      url: string;\n    }\n    const req = {\n      title,\n      sections,\n      debugInfoUrl\n    }\n    let params = new HttpParams();\n    if (!!opts?.generateUrl) {\n      params = params.set('generate-url', '')\n    }\n    return this.http.post<CreateIssueResponse>(`${environment.supportHub}/api/v1/issues/${repo}/${preset}`, req, { params }).pipe(map(r => r.url))\n  }\n\n  createTicket(repoName: string, title: string, email: string, sections: SupportSection[], debugInfoUrl?: string): Observable<void> {\n    const req = {\n      title,\n      sections,\n      debugInfoUrl,\n      email,\n      repoName,\n    }\n    return this.http.post<void>(`${environment.supportHub}/api/v1/ticket`, req)\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/ui-state.service.ts",
    "content": "import { Injectable } from \"@angular/core\";\nimport { PortapiService, Record } from '@safing/portmaster-api';\nimport { Observable, of } from \"rxjs\";\nimport { catchError, map, switchMap } from \"rxjs/operators\";\nimport { SortTypes } from './../shared/network-scout/network-scout';\n\nexport interface UIState extends Record {\n  hideExitScreen?: boolean;\n  introScreenFinished?: boolean;\n  netscoutSortOrder: SortTypes;\n}\n\nconst defaultState: UIState = {\n  hideExitScreen: false,\n  introScreenFinished: false,\n  netscoutSortOrder: SortTypes.static\n}\n\n@Injectable({ providedIn: 'root' })\nexport class UIStateService {\n  constructor(private portapi: PortapiService) { }\n\n  uiState(): Observable<UIState> {\n    const key = 'core:ui/v1';\n    return this.portapi.get<UIState>(key)\n      .pipe(\n        catchError(err => of(defaultState)),\n        map(state => {\n          (Object.keys(defaultState) as (keyof UIState)[])\n            .forEach(key => {\n              if (state[key] === undefined) {\n                (state as any)[key] = defaultState[key]!\n              }\n            })\n\n          return state\n        })\n      )\n  }\n\n  saveState(state: UIState): Observable<void> {\n    const key = 'core:ui/v1';\n    return this.portapi.create(key, state);\n  }\n\n  set<K extends keyof UIState, V extends UIState[K]>(key: K, value: V): Observable<void> {\n    return this.uiState()\n      .pipe(\n        map(state => {\n          state[key] = value\n\n          return state;\n        }),\n        switchMap(newState => this.saveState(newState))\n      );\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/services/virtual-notification.ts",
    "content": "import { RecordMeta } from '@safing/portmaster-api';\nimport { BehaviorSubject } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { ActionHandler, Notification, NotificationState, NotificationType } from './notifications.types';\n\nexport class VirtualNotification<T> implements Notification<T> {\n  readonly AvailableActions: ActionHandler<T>[];\n  readonly Category: string;\n  readonly EventData: T | null;\n  readonly GUID: string = ''; // TODO(ppacher): should we fake it?\n  readonly Expires: number;\n  readonly _meta: RecordMeta;\n\n  get State() {\n    if (this.SelectedActionID === '') {\n      return NotificationState.Active\n    }\n\n    return NotificationState.Executed\n  }\n\n  get SelectedActionID() {\n    return this._selectedAction.getValue();\n  }\n\n  /** Emits as soon as the user selects one of the notification actions. */\n  get executed() {\n    return this._selectedAction.pipe(\n      filter(action => action !== '')\n    );\n  }\n\n  /* Used to emit the selected action */\n  private _selectedAction = new BehaviorSubject<string>('');\n\n  /**\n   * Select and execute the action by ID.\n   *\n   * @param aid The ID of the action to execute.\n   */\n  selectAction(aid: string) {\n    this._selectedAction.next(aid);\n    this._meta.Modified = new Date().valueOf() / 1000;\n\n    const action = this.AvailableActions.find(a => a.ID === aid);\n    if (!!action) {\n      action.Run(action.Payload);\n    }\n  }\n\n  constructor(\n    public readonly EventID: string,\n    public readonly Type: NotificationType,\n    public readonly Title: string,\n    public readonly Message: string,\n    {\n      AvailableActions,\n      EventData,\n      Category,\n      Expires,\n    }: {\n      AvailableActions?: ActionHandler<T>[];\n      EventData?: T | null;\n      Category?: string,\n      Expires?: number,\n    } = {}\n  ) {\n    this.AvailableActions = AvailableActions || [];\n    this.EventData = EventData || null;\n    this.Category = Category || '';\n    this.Expires = Expires || 0;\n\n    this._meta = {\n      Created: new Date().valueOf() / 1000,\n      Deleted: 0,\n      Expires: this.Expires,\n      Modified: new Date().valueOf() / 1000,\n      Key: `notifications:all/${EventID}`,\n    }\n  }\n\n  dispose() {\n    this._selectedAction.complete();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/action-indicator/action-indicator.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { IndicatorComponent } from \"./indicator\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n  ],\n  declarations: [\n    IndicatorComponent,\n  ]\n})\nexport class ActionIndicatorModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/action-indicator/action-indicator.service.ts",
    "content": "import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { HttpErrorResponse, HttpResponse } from '@angular/common/http';\nimport { Injectable, InjectionToken, Injector, isDevMode } from '@angular/core';\nimport { interval, PartialObserver, Subject } from 'rxjs';\nimport { take, takeUntil } from 'rxjs/operators';\nimport { IndicatorComponent } from './indicator';\n\nexport interface ActionIndicator {\n  title: string;\n  message?: string;\n  status: 'info' | 'success' | 'error';\n  timeout?: number;\n}\n\nexport const ACTION_REF = new InjectionToken<ActionIndicatorRef>('ActionIndicatorRef')\nexport class ActionIndicatorRef implements ActionIndicator {\n  title: string;\n  message?: string;\n  status: 'info' | 'success' | 'error';\n  timeout?: number;\n\n  onClose = new Subject<void>();\n  onCloseReplace = new Subject<void>();\n\n  constructor(opts: ActionIndicator, private _overlayRef: OverlayRef) {\n    this.title = opts.title;\n    this.message = opts.message;\n    this.status = opts.status;\n    this.timeout = opts.timeout;\n  }\n\n  close() {\n    this._overlayRef.detach();\n    this.onClose.next();\n    this.onClose.complete();\n  }\n}\n\n@Injectable({ providedIn: 'root' })\nexport class ActionIndicatorService {\n  private _activeIndicatorRef: ActionIndicatorRef | null = null;\n\n  constructor(\n    private _injector: Injector,\n    private overlay: Overlay,\n  ) { }\n\n  /**\n   * Returns an observer that parses the HTTP API response\n   * and shows a success/error action indicator.\n   */\n  httpObserver(successTitle?: string, errorTitle?: string): PartialObserver<HttpResponse<ArrayBuffer | string>> {\n    return {\n      next: resp => {\n        let msg = this.getErrorMessgae(resp)\n        if (!successTitle) {\n          successTitle = msg;\n          msg = '';\n        }\n        this.success(successTitle || '', msg)\n      },\n      error: err => {\n        let msg = this.getErrorMessgae(err);\n        if (!errorTitle) {\n          errorTitle = msg;\n          msg = '';\n        }\n        this.error(errorTitle || '', msg);\n      }\n    }\n  }\n\n  info(title: string, message?: string, timeout?: number) {\n    this.create({\n      title,\n      message: this.ensureMessage(message),\n      timeout,\n      status: 'info'\n    })\n  }\n\n  error(title: string, message?: string | any, timeout?: number) {\n    this.create({\n      title,\n      message: this.ensureMessage(message),\n      timeout,\n      status: 'error'\n    })\n  }\n\n  success(title: string, message?: string, timeout?: number) {\n    this.create({\n      title,\n      message: this.ensureMessage(message),\n      timeout,\n      status: 'success'\n    })\n  }\n\n  /**\n   * Creates a new user action indicator.\n   *\n   * @param msg The action indicator message to show\n   */\n  async create(msg: ActionIndicator) {\n    if (!!this._activeIndicatorRef) {\n      this._activeIndicatorRef.onCloseReplace.next();\n      await this._activeIndicatorRef.onClose.toPromise();\n    }\n\n    const cfg = new OverlayConfig({\n      scrollStrategy: this.overlay\n        .scrollStrategies.noop(),\n      positionStrategy: this.overlay\n        .position()\n        .global()\n        .bottom('2rem')\n        .left('5rem'),\n    });\n    const overlayRef = this.overlay.create(cfg);\n\n    const ref = new ActionIndicatorRef(msg, overlayRef);\n    ref.onClose.pipe(take(1)).subscribe(() => {\n      if (ref === this._activeIndicatorRef) {\n        this._activeIndicatorRef = null;\n      }\n    })\n\n    // close after the specified time our (or 5000 seconds).\n    const timeout = msg.timeout || 5000;\n    interval(timeout).pipe(\n      takeUntil(ref.onClose),\n      take(1),\n    ).subscribe(() => {\n      ref.close();\n    })\n\n    const injector = this.createInjector(ref);\n    const portal = new ComponentPortal(\n      IndicatorComponent,\n      undefined,\n      injector\n    );\n    this._activeIndicatorRef = ref;\n    overlayRef.attach(portal);\n  }\n\n  /**\n   * Creates a new dependency injector that provides msg as\n   * ACTION_MESSAGE.\n   */\n  private createInjector(ref: ActionIndicatorRef): Injector {\n    return Injector.create({\n      providers: [\n        {\n          provide: ACTION_REF,\n          useValue: ref,\n        }\n      ],\n      parent: this._injector,\n    })\n  }\n\n  /**\n   * Tries to extract a meaningful error message from msg.\n   */\n  private ensureMessage(msg: string | any): string | undefined {\n    if (msg === undefined || msg === null) {\n      return undefined;\n    }\n\n    if (msg instanceof HttpErrorResponse) {\n      return msg.message;\n    }\n\n    if (typeof msg === 'string') {\n      return msg;\n    }\n\n    if (typeof msg === 'object') {\n      if ('message' in msg) {\n        return msg.message;\n      }\n      if ('error' in msg) {\n        return this.ensureMessage(msg.error);\n      }\n      if ('toString' in msg) {\n        return msg.toString();\n      }\n    }\n\n    return JSON.stringify(msg);\n  }\n\n  /**\n   * Coverts an untyped body received by the HTTP API to a string.\n   */\n  private stringifyBody(body: any): string {\n    if (typeof body === 'string') {\n      return body;\n    }\n\n    if (body instanceof ArrayBuffer) {\n      return new TextDecoder('utf-8').decode(body);\n    }\n\n    if (typeof body === 'object') {\n      return this.ensureMessage(body) || '';\n    }\n    console.error('unsupported body', body);\n\n    return '';\n  }\n\n  /**\n   *  @deprecated use the version without a typo ...\n   */\n  getErrorMessgae(resp: HttpResponse<ArrayBuffer | string> | HttpErrorResponse | Error): string {\n    return this.getErrorMessage(resp)\n  }\n\n  /**\n   * Parses a HTTP or HTTP Error response and returns a\n   * message that can be displayed to the user.\n   */\n  getErrorMessage(resp: HttpResponse<ArrayBuffer | string> | HttpErrorResponse | Error): string {\n    try {\n      let body: string | null = null;\n\n      if (typeof resp === 'string') {\n        return resp\n      }\n\n      if (resp instanceof Error) {\n        return resp.message;\n      }\n\n      if (resp instanceof HttpErrorResponse) {\n        // A client-side or network error occured.\n        if (resp.error instanceof Error) {\n          body = resp.error.message;\n        } else {\n          body = this.stringifyBody(resp.error);\n        }\n\n        if (!!body) {\n          body = body[0].toLocaleUpperCase() + body.slice(1)\n          return body\n        }\n      }\n\n\n      if (resp instanceof HttpResponse) {\n        let msg = '';\n        const ct = resp.headers.get('content-type') || '';\n\n        body = this.stringifyBody(resp.body);\n\n        if (/application\\/json/.test(ct)) {\n          if (!!body) {\n            msg = body;\n          }\n        } else if (/text\\/plain/.test(ct)) {\n          msg = body;\n        }\n\n        // Make the first letter uppercase\n        if (!!msg) {\n          msg = msg[0].toLocaleUpperCase() + msg.slice(1)\n          return msg;\n        }\n      }\n\n      console.error(`Unexpected error type`, resp)\n\n      return `Unknown error: ${resp}`\n\n    } catch (err: any) {\n      console.error(err)\n      return `Unknown error: ${resp}`\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/action-indicator/index.ts",
    "content": "export * from './action-indicator.service';\nexport * from './action-indicator.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/action-indicator/indicator.html",
    "content": "<ng-container [ngSwitch]=\"ref.status\">\n  <div class=\"icon\" *ngSwitchCase=\"'success'\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-6 w-6\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n      <path fill-rule=\"evenodd\"\n        d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n        clip-rule=\"evenodd\" />\n    </svg>\n  </div>\n  <div class=\"icon error\" *ngSwitchCase=\"'error'\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n        d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n    </svg>\n  </div>\n</ng-container>\n<div class=\"indicator-content\">\n  <h1 *ngIf=\"!!ref.title\">{{ ref.title }}</h1>\n\n  <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 close-icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n    <path fill-rule=\"evenodd\"\n      d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n      clip-rule=\"evenodd\" />\n  </svg>\n\n  <div class=\"message\" *ngIf=\"ref.message\">\n    <span>\n      {{ ref.message }}\n    </span>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/action-indicator/indicator.scss",
    "content": ":host {\n  box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.75);\n  @apply bg-gray-200;\n  @apply p-4;\n  @apply rounded;\n  position: relative;\n  width: 20rem;\n  display: flex;\n  cursor: pointer;\n  border-left: 2px solid transparent;\n\n\n  .icon {\n    display: flex;\n    align-items: flex-start;\n    flex-shrink: 1;\n    margin-right: 1rem;\n    padding-top: 2px;\n  }\n\n  &.error {\n    @apply border-yellow;\n\n    .icon {\n      @apply text-yellow\n    }\n  }\n\n  .indicator-content {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n\n    h1 {\n      font-size: 0.85rem;\n      font-weight: 500;\n      margin-bottom: 0;\n    }\n\n    .message,\n    h1 {\n      flex-shrink: 0;\n      text-overflow: ellipsis;\n    }\n\n    .message {\n      font-size: 0.7rem;\n      flex-grow: 1;\n      opacity: .5;\n\n      span {\n        display: block;\n        height: 100%;\n        word-break: keep-all;\n      }\n    }\n\n    .close-icon {\n      position: absolute;\n      top: 1rem;\n      right: 1rem;\n      opacity: .7;\n      cursor: pointer;\n\n      &:hover {\n        opacity: 1;\n      }\n    }\n\n    h1~.message {\n      margin-top: .5rem;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/action-indicator/indicator.ts",
    "content": "import { animate, state, style, transition, trigger } from '@angular/animations';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, HostListener, Inject, OnInit } from '@angular/core';\nimport { takeUntil } from 'rxjs/operators';\nimport { ActionIndicatorRef, ACTION_REF } from './action-indicator.service';\n\n@Component({\n  templateUrl: './indicator.html',\n  styleUrls: ['./indicator.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    trigger('slideIn', [\n      state('void', style({\n        opacity: 0,\n        transform: 'translateY(32px)'\n      })),\n\n      state('showing', style({\n        opacity: 1,\n        transform: 'translateY(0px)'\n      })),\n\n      state('replace', style({\n        transform: 'translateY(0px) rotate(-3deg)',\n        zIndex: -100,\n      })),\n\n      transition('showing => replace', animate('10ms cubic-bezier(0, 0, 0.2, 1)')),\n      transition('void => *', animate('220ms cubic-bezier(0, 0, 0.2, 1)')),\n\n      transition('showing => void', animate('220ms cubic-bezier(0, 0, 0.2, 1)', style({\n        opacity: 0,\n        transform: 'translateX(-100%)'\n      }))),\n\n      transition('replace => void', animate('220ms cubic-bezier(0, 0, 0.2, 1)', style({\n        opacity: 0,\n        transform: 'translateY(-64px) rotate(-3deg)'\n      })))\n    ])\n  ]\n})\nexport class IndicatorComponent implements OnInit {\n  constructor(\n    @Inject(ACTION_REF)\n    public ref: ActionIndicatorRef,\n    public cdr: ChangeDetectorRef,\n  ) { }\n\n  @HostBinding('@slideIn')\n  state = 'showing';\n\n  @HostBinding('class.error')\n  isError = this.ref.status === 'error';\n\n  @HostListener('click')\n  closeIndicator() {\n    this.ref.close();\n  }\n\n  @HostListener('@slideIn.done', ['$event'])\n  onAnimationDone() {\n    if (this.state === 'replace') {\n      this.ref.close();\n    }\n  }\n\n  ngOnInit() {\n    this.ref.onCloseReplace\n      .pipe(\n        takeUntil(this.ref.onClose),\n      )\n      .subscribe(state => {\n        this.state = 'replace';\n        this.cdr.detectChanges();\n      })\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/shared/animations.ts",
    "content": "import { animate, query, stagger, style, transition, trigger } from '@angular/animations';\n\nexport const fadeInAnimation = trigger(\n  'fadeIn',\n  [\n    transition(\n      ':enter',\n      [\n        style({ opacity: 0, transform: 'translateY(-5px)' }),\n        animate('120ms cubic-bezier(0, 0, 0.2, 1)',\n          style({ opacity: 1, transform: 'translateY(0px)' }))\n      ]\n    ),\n  ]\n);\n\nexport const fadeOutAnimation = trigger(\n  'fadeOut',\n  [\n    transition(\n      ':leave',\n      [\n        style({ opacity: 1, transform: 'translateY(0px)' }),\n        animate('120ms cubic-bezier(0, 0, 0.2, 1)',\n          style({ opacity: 0, transform: 'translateY(-5px)' }))\n      ]\n    ),\n  ]\n);\n\nexport const fadeInListAnimation = trigger(\n  'fadeInList',\n  [\n    transition(':enter, * => 0, * => -1', []),\n    transition(':increment', [\n      query(':enter', [\n        style({ opacity: 0 }),\n        stagger(5, [\n          animate('300ms ease-out', style({ opacity: 1 })),\n        ]),\n      ], { optional: true })\n    ]),\n  ]\n)\n\nexport const moveInOutLeftAnimation = trigger(\n  'moveInOutLeft',\n  [\n    transition(\n      ':enter',\n      [\n        style({ opacity: 0, transform: 'translateX(-100%)' }),\n        animate('.1s ease-in',\n          style({ opacity: 1, transform: 'translateX(0%)' }))\n      ]\n    ),\n    transition(\n      ':leave',\n      [\n        style({ opacity: 1, 'z-index': -100 }),\n        animate('.1s ease-out',\n          style({ opacity: 0, transform: 'translateX(-100%)' }))\n      ]\n    )\n  ]\n)\n\n\nexport const moveInOutAnimation = trigger(\n  'moveInOut',\n  [\n    transition(\n      ':enter',\n      [\n        style({ opacity: 0, transform: 'translateX(100%)' }),\n        animate('.2s ease-in',\n          style({ opacity: 1, transform: 'translateX(0%)' }))\n      ]\n    ),\n    transition(\n      ':leave',\n      [\n        style({ opacity: 1 }),\n        animate('.2s ease-out',\n          style({ opacity: 0, transform: 'translateX(100%)' }))\n      ]\n    )\n  ]\n)\n\nexport const moveInOutListAnimation = trigger(\n  'moveInOutList',\n  [\n    transition(':enter, * => 0, * => -1', []),\n    transition(':increment', [\n      query(':enter', [\n        style({ opacity: 0, transform: 'translateX(100%)' }),\n        stagger(50, [\n          animate('200ms ease-out', style({ opacity: 1, transform: 'translateX(0%)' })),\n        ]),\n      ], { optional: true })\n    ]),\n    transition(':decrement', [\n      query(':leave', [\n        stagger(-50, [\n          animate('200ms ease-out', style({ opacity: 0, transform: 'translateX(100%)' })),\n        ]),\n      ], { optional: true })\n    ]),\n  ]\n)\n"
  },
  {
    "path": "desktop/angular/src/app/shared/app-icon/app-icon-resolver.ts",
    "content": "import { Injectable, inject, isDevMode } from \"@angular/core\";\nimport { AppProfile, AppProfileService, deepClone } from \"@safing/portmaster-api\";\nimport { firstValueFrom, map, switchMap } from \"rxjs\";\nimport { INTEGRATION_SERVICE, ProcessInfo } from \"src/app/integration\";\nimport * as parseDataURL from 'data-urls';\n\nexport abstract class AppIconResolver {\n  abstract resolveIcon(profile: AppProfile): void;\n}\n\n@Injectable()\nexport class DefaultIconResolver extends AppIconResolver {\n  private integration = inject(INTEGRATION_SERVICE);\n  private profileService = inject(AppProfileService);\n\n  private pendingResolvers = new Map<string, Promise<void>>();\n\n  resolveIcon(profile: AppProfile): void {\n    const key = `${profile.Source}/${profile.ID}`;\n\n    // if there's already a promise in flight, abort.\n    if (this.pendingResolvers.has(key)) {\n      if (isDevMode()) {\n        console.log(`[icon:${profile.Name}] loading icon already in progress ...`)\n      }\n\n      return;\n    }\n\n    let promise = new Promise<void>((resolve) => {\n      this.profileService\n        .getProcessesByProfile(profile)\n        .pipe(\n          map(processes => {\n            // if we there are no running processes for this profile,\n            // we try to find the icon based on the information stored in\n            // the profile.\n            let info: ProcessInfo[] = [{\n              execPath: profile.LinkedPath,\n              cmdline: profile.PresentationPath,\n              pid: -1,\n              matchingPath: profile.PresentationPath,\n            }]\n\n            processes?.forEach(process => {\n              // BUG: Portmaster sometimes runs a null entry, skip it here.\n              if (!process) {\n                return;\n              }\n\n              // insert at the beginning since the process data might reveal\n              // better results than the profile one.\n              info.splice(0, 0, {\n                execPath: process.Path,\n                cmdline: process.CmdLine,\n                pid: process.Pid,\n                matchingPath: process.MatchingPath,\n              })\n            })\n\n            return info;\n          })\n        ).subscribe(async (processInfos) => {\n          for (const info of processInfos) {\n            try {\n              await this.loadAndSaveIcon(info, profile);\n\n              // success, abort now\n              resolve();\n              return;\n            } catch (err) {\n              // continue using the next one\n            }\n          }\n\n          // we failed to find an icon, still resolve the promise here\n          // because nobody actually cares ....\n          resolve();\n        })\n    });\n    this.pendingResolvers.set(key, promise);\n\n    promise.finally(() => this.pendingResolvers.delete(key));\n  }\n\n  private async loadAndSaveIcon(info: ProcessInfo, profile: AppProfile): Promise<void> {\n    const icon = await this.integration.getAppIcon(info);\n\n    const dataURL = parseDataURL(icon);\n    if (!dataURL) {\n      throw new Error(\"invalid data url\");\n    }\n    const blob = new Blob([dataURL.body], {\n      type: dataURL.mimeType.essence,\n    })\n\n    const body = await blob.arrayBuffer();\n\n    const save$ = this.profileService\n      .setProfileIcon(body, blob.type)\n      .pipe(switchMap(result => {\n        // save the profile icon\n        profile = deepClone(profile);\n        profile.Icons = [\n          ...(profile.Icons || []),\n          {\n            Value: result.filename,\n            Type: 'api',\n            Source: 'ui'\n          }\n        ];\n\n        return this.profileService.saveProfile(profile)\n      }));\n\n    await firstValueFrom(save$);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/app-icon/app-icon.html",
    "content": "<span *ngIf=\"!src && !isIgnoredProfile\">\n  {{letter}}\n</span>\n<img [attr.src]=\"src\" *ngIf=\"!!src\" loading=\"lazy\">\n<svg *ngIf=\"!src && isIgnoredProfile\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\"\n  stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-full h-full text-gray-700\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n    d=\"M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z\" />\n</svg>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/app-icon/app-icon.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { AppIconComponent } from \"./app-icon\";\nimport { AppIconResolver, DefaultIconResolver } from \"./app-icon-resolver\";\n\n@NgModule({\n  imports: [\n    CommonModule\n  ],\n  declarations: [\n    AppIconComponent,\n  ],\n  exports: [\n    AppIconComponent,\n  ],\n  providers: [\n    {\n      provide: AppIconResolver,\n      useClass: DefaultIconResolver,\n    }\n  ]\n})\nexport class SfngAppIconModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/app-icon/app-icon.scss",
    "content": ":host {\n  border-radius: 50%;\n  user-select: none;\n\n  height: var(--app-icon-size, 25px);\n  width: var(--app-icon-size, 25px);\n  flex-shrink: 0;\n  @apply mr-2;\n\n  display: inline-flex;\n  justify-content: center;\n  align-items: center;\n}\n\nspan,\nimg {\n  @apply text-primary;\n  @apply font-medium;\n  @apply rounded-full;\n  text-shadow: rgba(0, 0, 0, .8) 0px 0px 1px;\n\n  font-size: calc(var(--app-icon-size, 25px) / 6 * 4);\n}\n\nimg {\n  width: 100%;\n  height: 100%;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/app-icon/app-icon.ts",
    "content": "import {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  HostBinding,\n  Inject,\n  Input,\n  OnDestroy,\n  OnInit,\n  SkipSelf,\n  inject,\n} from '@angular/core';\nimport { DomSanitizer, SafeUrl } from '@angular/platform-browser';\nimport {\n  AppProfileService,\n  PORTMASTER_HTTP_API_ENDPOINT,\n  PortapiService,\n  Record,\n  deepClone,\n} from '@safing/portmaster-api';\nimport { Subscription, map, of } from 'rxjs';\nimport { switchMap } from 'rxjs/operators';\nimport { AppIconResolver } from './app-icon-resolver';\nimport { AppProfile } from 'projects/safing/portmaster-api/src/public-api';\n\n// Interface that must be satisfied for the profile-input\n// of app-icon.\nexport interface IDandName {\n  // ID of the profile.\n  ID?: string;\n\n  // Source is the source of the profile.\n  Source?: string;\n\n  // Name of the profile.\n  Name: string;\n}\n\n// Some icons we don't want to show on the UI.\n// Note that this works on a best effort basis and might\n// start breaking with updates to the built-in icons...\nconst iconBlobsToIgnore = [\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABU0lEQVRYhe2WTUrEQBCF36i4ctm4FsdTKF5AEFxL0knuILgQXAy4ELxDfgTXguAFRG/hDXKCAbtcOB3aSVenMjPRTb5NvdCE97oq3QQYGflnJlbc3T/QXxrfXF9NAGBraKPTk2Nvtey4D1l8OUiIo8ODX/Xt/cMfQCk1SAAi8upWgLquWy8rpbB7+yk2m8+mYvNWAAB4fnlt9MX5WaP397ZhCPgygCFa1IUmwJifCgB5nrMBtdbhAK6pi9QcALIs8+5c1AEOqTmwZge4EUjNiQhpmjbarcvaG4AbgcTcUhSFfwFAHMfhABxScwBIkgRA9wnwBgiOQGBORCjLkl2PoigcgB2BwNzifmi97wEOqTkRoaoqdr2zA9wIJOYWrTW785VPQR+WO2B3vdYIpBBRc9Qkp2Cw/4GVR+BjPpt23u19tUXUgU2aBzuQPz5J8oyMjGyUb9+FOUOmulVPAAAAAElFTkSuQmCC',\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAACLElEQVR4nO2av07DMBDGP1DFxtaFmbeg6gtUqtQZtU3yDkgMSAxIDEi8Q/8gMVdC4m1YYO0TMNQspErdOG3Md25c7rc0st3E353v7EsLKIqiKIqiKMq/5MRueHx6NoeYSCjubm82NJ8eaiISdDtX6HauKq9tWsFmF4DPr6+d1zalBshG18RpNYfJy+tW21GFgA+lK6DdboeeBwVjyvO3qx1wGGC5XO71wCYZykc8QEqCZ/cfjNs4+X64rOz3FQ/sMMDi7R2Dfg+Lt/eN9kG/tzX24rwFA8AYYGXM+nr9aQADs9mG37FWW3HsqqBhMpnsFFRGkiTOvkoD5ELLBNtIiLcdmGXZ5jP/4Pkc2i4gIb5KRl3xrnbaQSiEeN8QGI/Hzj5aDgjh+SzLaJ7P4eWAiJZ9EVoIhBA/nU695uYdAnUI4fk0TUvbXeP3gZcDhMS7CLIL1DsHyIv3DYHRaOTs44YAZD2fpik9EfIOQohn2Rch5wBZ8bPZzOObfwiBurWAtOftoqaO511jaSEgJd4FQzwgmAQlxPuGwHA4dPbJ1QICnk+ShOb5HJlaoOHLvgi/FhAUP5/P9xpbteRtyDlA1vN2UVPH8+K7gJR45/MI4gHyK7HYxANsA7BuVvkcnniAXAtIwxYPRPTboIR4IBIDMMSL7wIhYZbF0RmgsS9EQtDY1+L5r7esCUrGvA3xHBCfeIBkgBjEi+0CMYsHHDmg7N9UiqIoiqIoiqIcFT++NKIXgDvowAAAAABJRU5ErkJggg==',\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAABqUlEQVRYhe2XP2rDMBSHfymhU0dDD5BbJOQCgUDmEv+7Q6FDoUOgQ6F3cJxC50Agt+nSrD5BBr8OqVyrtfWkl8ShoG+SjJE+/95DwoDH4/nf9NTg+eWVLinym8eH+x4AXF1i8/FoiPFoaBwr+p3bAfjc7dixQhNMw7szatmTvb1XY00wCILOZYjIONcEi6JoXSgIAlw/fYhF9ouBsxzQ0IPrzRaz6QTrzbZ6NptOqvHtTR8EQklAWQIl4WdOQEkEqsaHefm9b5Zl7IfEcWwWVDJ1Ke0rHeXqmaRpeljDIrlWQQ5XufreNglGUWQW5EoslQOAJEm0uagHuRJL5YgIy+Wycc06bIIcEjmFStCUnPGYASxKLJQDYJVgGIZmQZsSS+SAv0eIKblWQQ6pHBEhz3N2fTZBrsQSOYVK0JQc24N2JXaXA2CV4Hw+NwtySOUA/QixvU1kPSiQIyKsViv2vaMTlMgpoihik2N7kEMqB6AxwXpiVlfduSAi7Qix7cGL/DS5XHWdC7rIAY4l3i8GTk1+zLsKpwS7lnMS7ErOeMzU/0c9Ho/nNHwBdUH2gB9vJRsAAAAASUVORK5CYII=',\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAByElEQVRYhe1WQUoDQRCsmSh4CAreo3/w4CdE8JirLzCKGhRERPBqfISQx3j0BcaDJxHNRWS7PWRmtmdmJ9mNiSuYOmyYbOiqruoeAizw36G6p0e3WulOHeTE1NO/Qb6zu1f4qZXuqLPuMV9d38xbQyEuL86ha2EWWJKHfr+P4XAIAGg2m2i32wCA7fsXPH9kABjMgHkADP87cW6tNvCwvzG2biRAvpAYvH+54mCAmUcvmI0Yq4nM74DBG02sGwlIgqigS/ZEgdkcrSAuVbpUBEyjTiP7JSkDzKZrdo+xdSMBKas4y4K8befSiVxcLnR83UhACtYBV9TOgbBbOX4TF2YZQZY5Yi9/MYwkXQjy/3EEtjp7LgQzAeOUVSo0zCACcgOnwjUEC2LE7kxApS0AGFRgP4vZ8M5VBaQjoNGKuQ20Q2ney8Gr0H0kIAU7hK4zYiPCJxtFZYRMIyAdAQWrFgyicMSfj4oCkheRmQFyIoq2IRcy9T2QhNmCfN/FVcwMBSWu4XlsQUZe5tZmZW0HBXGU4o4FpCJorS3j6fXTEOVdUrgNApvrK9UFpPB4vlWq2DSo/S+Z6p4c9rRuHNRBTsR3dfAu8LfwDdGgu25Uax8RAAAAAElFTkSuQmCC',\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAByUlEQVRYhe1WQUoDQRCs2UTwEBS8R//gwU+I4DFXX2AENRgQEcGr8RFCHuPRFxgPnkQ0F9Ht9rAzsz0zO8luTFzB1GHDZENXdVX3EGCJ/w7VO+3eJKrZrYOc+GuQ/Ab57t5+4Weiml111jvmy6vrRWsoxMV5H0ktzAJNeRgOhxiPxwCAVquFTqcDANi5e8bTewqAwQzoB8BwvxPn9loD9webE+sGAuQLidHbpy0OBpg5e8GsxRhNpH8HjF5pat1AQBREBV2yIwrM+mgEcanSpSJgyjoN7JekDDDrrtk+JtYNBMSs4jT18jadSydycbnQyXUDATEYB2xRMwfCbmX5dVyYZwRpaomd/MUwknTBy//HEZjq7LjgzQS0U0ap0DCHCMgOnPLXECyIEbozBZW2AGBQgf0sZsM5VxUQj4CyFbMbaIZSv5eDV6H7QEAMZghtZ8RahEuWRaWFzCIgHgF5q+YNonDEnY+KAqIXkZ4BsiKKtiEXMvM9EIXegnzfxVXMDAUlruFFbEFKTubGZmVsB3lxlOIOBcQiaK+v4PHlQxPlXZK/DQJbG6vVBcTw0N8uVWwW1P6XTPVOjgZJ0jisg5yIb+vgXeJv4RvrxrtwzfCUqAAAAABJRU5ErkJggg==',\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADo0lEQVRYhe2Wu28cVRTGf+fcuzZeY0NCUqTgD3C8mzRU0KDQEgmqoBSGhoKWAlFEKYyQAAkrTRRqOpCQkOhAkUCio4D4IYSAzkkKB+wQbLy7c8+hmNmd2WecDQoFfNJodGfn7vc4Z84M/I9/GfLeB1cutdqH7zxSUli9fOntd4EsmrVXL1xcodVqAf6PEl37+AveWDk/dP78s08vA1eBvSgSDnd3bs49DJGKICIg+dod3J3XXn6Ogz9+49WXnu07F1gA9mOWJRqNBrNRcJ8mAQF8ZHYyuBYhI/DlV9cBAqARnBAj2agdjwARoBaETnK+/eY7NMwfaaPZPueefwaA73+4MfKeM80GAC+8+QkA19cukCQOC+ga1zDPR1//jIgjWhzBEQWNBupoNESdldNn2dm5w/FjT/SIpkEcvLAwX0PUQRwNXQGOBCvXoVpxZ31jc2ICEwWY+1y19AvzEQr3GgAtiLUUo8F690tB5DhC3sgiw800f2p/fAJ/tTtoyMOo1yOqnscdnINOIqNDO+vQbrdwMTRWEnBhfXNyAvOn9qmfOBgvwKxwC9TnAskTN3f32PnzHi1robEbv6HFUVGQJ+AOIvkQgL4U6icOqC9OSKCKu4cH/HT7Nh3P0GiEWkEcc+LBEhylB+qL+ywe+328gGrFNre3kWiE6EjsOi5EqPVS6EGEZrOJW0JVR5KMIy8TqCjQmlUcl7GLlvGrlgLcYWNzY2ICk1CUoFSgtdRPHAwtYteQeimUCuDsmebEMX7l3Pv3E1BCY+lUgqNaFZJ663ID3Fh/6ARKhFrqNVq15lVy1dRP1FjGRaZ6lQwnEKqkw+Si/QLMATwnHxhA7o65k2UJM0NwanOP30dATAPkhmjlmuYiuhCcja0fR7prNhqA4W5Fjwz3ydBTEGLZaKoV99p13y8AnGZjeeT4dfd8LrnnCYyoUQTQQsGtW7/y+tPnR7oZxPb2LywvncRd2dzaGnnP6aUlzBLJvKt1tIAsObUAF195kZ2dO0cSsLx0EgAz6yWQO3aSGeZOJ8swS5gNj+c+AeYwE4QgxlPHF6nNzkBKpGQ4EGMAnSksOGCA41nisJP/eTfuVIjAHQRCCITiPaPjBAC0kwMKMkvW7vuJTgZQffSkOBRCLqeL0cN4PKLA6trah2/FGB97wL05oSohKCEEzMBSRkpp4gf+3d3dq+SOTIAZ4Enyz+QwjYgpkIB7wF6RIxGo8eAJTgsDOpB/jP+38TcKdstukjAxWQAAAABJRU5ErkJggg==',\n];\nconst iconIDsToIgnore = [\n  \"a27898ddfa4e0481b62c69faa196919a738fcade\",\n\t\"5a3eea8bcd08b9336ce9c5083f26185164268ee9\",\n\t\"573393d6ad238d255b20dc1c1b303c95debe6965\",\n\t\"d459b2cb23c27cc31ccab5025533048d5d8301bf\",\n\t\"d35a0d91ebfda81df5286f68ec5ddb1d6ad6b850\",\n\t\"cc33187385498384f1b648e23be5ef1a2e9f5f71\",\n];\n\n\nconst profilesToIgnore = ['local/_unidentified', 'local/_unsolicited'];\n\n@Component({\n  selector: 'app-icon',\n  templateUrl: './app-icon.html',\n  styleUrls: ['./app-icon.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppIconComponent implements OnInit, OnDestroy {\n  private sub = Subscription.EMPTY;\n  private initDone = false;\n\n  private resovler = inject(AppIconResolver);\n\n  /** @private The data-URL for the app-icon if available */\n  src: SafeUrl | string = '';\n\n  /** The profile for which to show the app-icon */\n  @Input()\n  set profile(p: IDandName | null | undefined | string) {\n    if (typeof p === 'string') {\n      const parts = p.split(\"/\")\n      p = {\n        Source: parts[0],\n        ID: parts[1],\n        Name: '',\n      }\n    }\n\n    if (!!this._profile && !!p && this._profile.ID === p.ID) {\n      // skip if this is the same profile\n      return;\n    }\n\n    this._profile = p || null;\n\n    if (this.initDone) {\n      this.updateView();\n    }\n  }\n  get profile(): IDandName | null | undefined {\n    return this._profile;\n  }\n  private _profile: IDandName | null = null;\n\n  /** isIgnoredProfile is set to true if the profile is part of profilesToIgnore */\n  isIgnoredProfile = false;\n\n  /** If not icon is available, this holds the first - uppercased - letter of the app - name */\n  letter = '';\n\n  /** @private The background color of the component, based on icon availability and generated by ID */\n  @HostBinding('style.background-color')\n  color = 'var(--text-tertiary)';\n\n  constructor(\n    private profileService: AppProfileService,\n    private changeDetectorRef: ChangeDetectorRef,\n    private portapi: PortapiService,\n    // @HostBinding() is not evaluated in our change-detection run but rather\n    // checked by the parent component during updateRenderer.\n    // Since we want the background color to change immediately after we set the\n    // src path we need to tell the parent (which ever it is) to update as wel.\n    @SkipSelf() private parentCdr: ChangeDetectorRef,\n    private sanitzier: DomSanitizer,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpAPI: string\n  ) { }\n\n  /** Updates the view of the app-icon and tries to find the actual application icon */\n  private requestedAnimationFrame: number | null = null;\n  private updateView(skipIcon = false) {\n    if (this.requestedAnimationFrame !== null) {\n      cancelAnimationFrame(this.requestedAnimationFrame);\n    }\n\n    this.requestedAnimationFrame = requestAnimationFrame(() => {\n      this.__updateView(skipIcon);\n    })\n  }\n\n  ngOnInit(): void {\n    this.updateView();\n    this.initDone = true;\n  }\n\n  private __updateView(skipIcon = false) {\n    this.requestedAnimationFrame = null;\n\n    const p = this.profile;\n    const sourceAndId = this.getIDAndSource();\n\n    if (!!p && sourceAndId !== null) {\n      let idx = 0;\n      for (let i = 0; i < (p.ID || p.Name).length; i++) {\n        idx += (p.ID || p.Name).charCodeAt(i);\n      }\n\n      const combinedID = `${sourceAndId[0]}/${sourceAndId[1]}`;\n      this.isIgnoredProfile = profilesToIgnore.includes(combinedID);\n\n      this.updateLetter(p);\n\n      if (!this.isIgnoredProfile) {\n        this.color = AppColors[idx % AppColors.length];\n      } else {\n        this.color = 'transparent';\n      }\n\n      if (!skipIcon) {\n        this.tryGetSystemIcon();\n      }\n\n    } else {\n      this.isIgnoredProfile = false;\n      this.color = 'var(--text-tertiary)';\n    }\n\n    this.changeDetectorRef.markForCheck();\n    this.parentCdr.markForCheck();\n  }\n\n  private updateLetter(p: IDandName) {\n    if (p.Name !== '') {\n      if (p.Name[0] === '<') {\n        // we might get the name with search-highlighting which\n        // will then include <em> tags. If the first character is a <\n        // make sure to strip all HTML tags before getting [0].\n        this.letter = p.Name.replace(\n          /(&nbsp;|<([^>]+)>)/gi,\n          ''\n        )[0].toLocaleUpperCase();\n      } else {\n        this.letter = p.Name[0];\n      }\n\n      this.letter = this.letter.toLocaleUpperCase();\n    } else {\n      this.letter = '?';\n    }\n  }\n\n  getIDAndSource(): [string, string] | null {\n    if (!this.profile) {\n      return null;\n    }\n\n    const id = this.profile.ID;\n    if (!id) {\n      return null;\n    }\n\n    // if there's a source ID only holds the profile ID\n    if (!!this.profile.Source) {\n      return [this.profile.Source, id];\n    }\n\n    // otherwise, ID likely contains the source\n    const [source, ...rest] = id.split('/');\n    if (rest.length > 0) {\n      return [source, rest.join('/')];\n    }\n\n    // id does not contain a forward-slash so we\n    // assume the source is local\n    return ['local', id];\n  }\n\n  /**\n   * Tries to get the application icon form the system.\n   * Requires the app to be running in the electron wrapper.\n   */\n  private tryGetSystemIcon() {\n    const sourceAndId = this.getIDAndSource();\n    if (sourceAndId === null) {\n      return;\n    }\n\n    this.sub.unsubscribe();\n\n    this.sub = this.profileService\n      .watchAppProfile(sourceAndId[0], sourceAndId[1])\n      .pipe(\n        switchMap((profile: AppProfile) => {\n          this.updateLetter(profile);\n\n          if (!!profile.Icons?.length) {\n            const firstIcon = profile.Icons[0];\n\n            console.log(`profile ${profile.Name} has icon of from source ${firstIcon.Source} stored in ${firstIcon.Type}`)\n\n            switch (firstIcon.Type) {\n              case 'database':\n                return this.portapi\n                  .get<Record & { iconData: string }>(firstIcon.Value)\n                  .pipe(\n                    map((result) => {\n                      return result.iconData;\n                    })\n                  );\n\n              case 'api':\n                return of(`${this.httpAPI}/v1/profile/icon/${firstIcon.Value}`);\n\n              case 'path':\n                // TODO: Silently ignore for now.\n                return of('');\n\n              case '':\n                // Icon is not set.\n                return of('');\n\n              default:\n                console.error(`Icon type ${firstIcon.Type} not yet supported`);\n            }\n          }\n\n          this.resovler.resolveIcon(profile);\n\n          // return an empty icon here. If the resolver manages to find an icon\n          // the profle will get updated and we'll run again here.\n          return of('');\n        })\n      )\n      .subscribe({\n        next: (icon) => {\n          if (iconBlobsToIgnore.some((i) => i === icon)) {\n            icon = '';\n          } else if (iconIDsToIgnore.some((i) => icon.includes(i))) {\n            // TODO: This just checks if the value (blob, URL, etc.) contains\n            // the SHA1 sum of the icon, which is used in the URL of api icon types.\n            // This is very unlikely to have false positivies, but this could still\n            // be done a lot cleaner.\n            icon = '';\n          }\n          if (icon !== '') {\n            this.src = this.sanitzier.bypassSecurityTrustUrl(icon);\n            this.color = 'unset';\n          } else {\n            this.src = '';\n            this.color =\n              this.color === 'unset' ? 'var(--text-tertiary)' : this.color;\n          }\n          this.changeDetectorRef.detectChanges();\n          this.parentCdr.markForCheck();\n        },\n        error: (err) => console.error(err),\n      });\n  }\n\n  ngOnDestroy(): void {\n    this.sub.unsubscribe();\n  }\n}\n\nexport const AppColors: string[] = [\n  'rgba(244, 67, 54, .7)',\n  'rgba(233, 30, 99, .7)',\n  'rgba(156, 39, 176, .7)',\n  'rgba(103, 58, 183, .7)',\n  'rgba(63, 81, 181, .7)',\n  'rgba(33, 150, 243, .7)',\n  'rgba(3, 169, 244, .7)',\n  'rgba(0, 188, 212, .7)',\n  'rgba(0, 150, 136, .7)',\n  'rgba(76, 175, 80, .7)',\n  'rgba(139, 195, 74, .7)',\n  'rgba(205, 220, 57, .7)',\n  'rgba(255, 235, 59, .7)',\n  'rgba(255, 193, 7, .7)',\n  'rgba(255, 152, 0, .7)',\n  'rgba(255, 87, 34, .7)',\n  'rgba(121, 85, 72, .7)',\n  'rgba(158, 158, 158, .7)',\n  'rgba(96, 125, 139, .7)',\n];\n"
  },
  {
    "path": "desktop/angular/src/app/shared/app-icon/index.ts",
    "content": "export { AppIconComponent } from './app-icon';\nexport { SfngAppIconModule } from './app-icon.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/basic-setting/basic-setting.html",
    "content": "<ng-container *ngIf=\"!!setting\">\n  <ng-container [ngSwitch]=\"_type\">\n    <ng-container *ngSwitchCase=\"'string'\">\n      <!--\n        Dropdowns for a limited set of allowed values. Either using PossibleValues (the new way)\n        or by parsing the settings validation regex (deprecated)\n      -->\n      <sfng-select *ngIf=\"externalOptType(setting) === optionHints.OneOf; else: simpleTextInput\" [ngModel]=\"_value\"\n        (ngModelChange)=\"setInternalValue($event); touched()\" [disabled]=\"_disabled\">\n\n        <ng-container *ngIf=\"!!setting.PossibleValues; else: noPossibleValues\">\n          <ng-container *ngFor=\"let opt of setting.PossibleValues\">\n            <sfng-select-item *sfngSelectValue=\"opt.Value; description: opt.Description\">{{opt.Name}}</sfng-select-item>\n          </ng-container>\n        </ng-container>\n\n        <ng-template #noPossibleValues>\n          <ng-container *ngFor=\"let opt of parseSupportedValues(setting)\">\n            <sfng-select-item *sfngSelectValue=\"opt\">{{opt}}</sfng-select-item>\n          </ng-container>\n        </ng-template>\n      </sfng-select>\n\n      <!--\n        A simple text input\n      -->\n      <ng-template #simpleTextInput>\n        <div class=\"input-container\">\n          <input type=\"text\" [ngModel]=\"_value\" (ngModelChange)=\"setInternalValue($event)\" [disabled]=\"_disabled\" #input\n            (blur)=\"touched()\" (click)=\"input.focus()\">\n          <span *ngIf=\"!!unit\" class=\"suffix\" #suffixElement>\n            {{ unit }}\n          </span>\n        </div>\n      </ng-template>\n    </ng-container>\n\n    <!--\n      A number input\n    -->\n    <div class=\"input-container\" *ngSwitchCase=\"'number'\">\n      <input type=\"number\" [ngModel]=\"_value\" (ngModelChange)=\"setInternalValue($event)\" [disabled]=\"_disabled\" #input\n        (blur)=\"touched()\">\n      <span *ngIf=\"!!unit\" class=\"suffix\" #suffixElement (click)=\"input.focus()\">\n        {{ unit }}\n      </span>\n    </div>\n\n    <!--\n      Toggle switch (On/Off)\n    -->\n    <ng-container *ngSwitchCase=\"'boolean'\">\n      <sfng-toggle id=\"check-{{setting.Key}}\" name=\"check\" [ngModel]=\"_value\"\n        (ngModelChange)=\"setInternalValue($event); touched()\" [disabled]=\"_disabled\">\n      </sfng-toggle>\n    </ng-container>\n\n    <!--\n      Multi-line text input\n      Mainly used as a fallback if we don't support the given input type\n      yet.\n      This allows direct manipulatoin of the JSON encoded value\n    -->\n    <textarea *ngSwitchDefault [attr.rows]=\"lineCount(_value)\" [ngModel]=\"_value\"\n      (ngModelChange)=\"setInternalValue($event)\" [disabled]=\"_disabled\" (blur)=\"touched()\">\n    </textarea>\n\n  </ng-container>\n</ng-container>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/basic-setting/basic-setting.scss",
    "content": "label {\n  @apply text-sm;\n}\n\ninput[type=\"checkbox\"] {\n  float: right;\n  user-select: none;\n}\n\n.input-container {\n  display: block;\n  position: relative;\n  font-size: 0.75rem;\n\n  input {\n    font-size: inherit;\n  }\n\n  .suffix {\n    user-select: none;\n    position: absolute;\n    left: 0;\n    top: calc(50% - 0.55rem);\n    padding-left: 0.3rem;\n    color: #aaa;\n    font: inherit;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/basic-setting/basic-setting.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport { AfterViewChecked, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, Inject, Input, Output, ViewChild } from '@angular/core';\nimport { AbstractControl, ControlValueAccessor, NgModel, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors, Validator } from '@angular/forms';\nimport { BaseSetting, ExternalOptionHint, OptionType, parseSupportedValues, SettingValueType, WellKnown } from '@safing/portmaster-api';\n\n@Component({\n  selector: 'app-basic-setting',\n  templateUrl: './basic-setting.html',\n  styleUrls: ['./basic-setting.scss'],\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      multi: true,\n      useExisting: forwardRef(() => BasicSettingComponent),\n    },\n    {\n      provide: NG_VALIDATORS,\n      multi: true,\n      useExisting: forwardRef(() => BasicSettingComponent),\n    }\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class BasicSettingComponent<S extends BaseSetting<any, any>> implements ControlValueAccessor, Validator, AfterViewChecked {\n  /** @private template-access to all external option hits */\n  readonly optionHints = ExternalOptionHint;\n\n  /** @private template-access to parseSupportedValues */\n  readonly parseSupportedValues = parseSupportedValues;\n\n  @ViewChild('suffixElement', { static: false, read: ElementRef })\n  suffixElement?: ElementRef<HTMLSpanElement>;\n\n  /** Cached canvas element used by getTextWidth */\n  private cachedCanvas?: HTMLCanvasElement;\n\n  /** Returns the value of external-option hint annotation */\n  externalOptType(opt: S): ExternalOptionHint | null {\n    return opt.Annotations?.[\"safing/portbase:ui:display-hint\"] || null;\n  }\n\n  /** Whether or not the input should be currently disabled. */\n  @Input()\n  set disabled(v: any) {\n    const disabled = coerceBooleanProperty(v);\n    this.setDisabledState(disabled);\n  }\n  get disabled() {\n    return this._disabled;\n  }\n\n  /** The setting to display */\n  @Input()\n  setting: S | null = null;\n\n  /** Emits when the user activates focus on this component */\n  @Output()\n  blured = new EventEmitter<void>();\n\n  /** @private The ngModel in our view used to display the value */\n  @ViewChild(NgModel)\n  model: NgModel | null = null;\n\n  /** The unit of the setting */\n  get unit() {\n    if (!this.setting) {\n      return '';\n    }\n    return this.setting.Annotations[WellKnown.Unit] || '';\n  }\n\n  /**\n   * Holds the value as it is presented to the user.\n   * That is, a JSON encoded object or array is dumped as a\n   * JSON string. Strings, numbers and booleans are presented\n   * as they are.\n   */\n  _value: string | number | boolean = \"\";\n\n  /**\n   * Describes the type of the original settings value\n   * as passed to writeValue().\n   * This may be anything that can be returned from `typeof v`.\n   * If set to \"string\", \"number\" or \"boolean\" then _value is emitted\n   * as it is.\n   * If it's set anything else (like \"object\") than _value is JSON.parse`d\n   * before being emitted.\n   */\n  _type: string = '';\n\n  /* Returns true if the current _type and _value is managed as JSON */\n  get isJSON(): boolean {\n    return this._type !== 'string'\n      && this._type !== 'number'\n      && this._type !== 'boolean'\n  }\n\n  /*\n   * _onChange is set using registerOnChange by @angular/forms\n   * and satisfies the ControlValueAccessor.\n   */\n  private _onChange: (_: SettingValueType<S>) => void = () => { };\n\n  /* _onTouch is set using registerOnTouched by @angular/forms\n   * and satisfies the ControlValueAccessor.\n   */\n  private _onTouch: () => void = () => { };\n\n  private _onValidatorChange: () => void = () => { };\n\n  /* Whether or not the input field is disabled. Set by setDisabledState\n   * from @angular/forms\n   */\n  _disabled: boolean = false;\n  private _valid: boolean = true;\n\n  // We are using ChangeDetectionStrategy.OnPush so angular does not\n  // update ourself when writeValue or setDisabledState is called.\n  // Using the changeDetectorRef we can take care of that ourself.\n  constructor(\n    @Inject(DOCUMENT) private document: Document,\n    private _changeDetectorRef: ChangeDetectorRef\n  ) { }\n\n  ngAfterViewChecked() {\n    // update the suffix position everytime angular has\n    // checked our view for changes.\n    this.updateUnitSuffixPosition();\n  }\n\n  /**\n   * Sets the user-presented value and emits a change.\n   * Used by our view. Not meant to be used from outside!\n   * Use writeValue instead.\n   * @private\n   *\n   * @param value The value to set\n   */\n  setInternalValue(value: string | number | boolean) {\n    let toEmit: any = value;\n    try {\n      if (!this.isJSON) {\n        toEmit = value;\n      } else {\n        toEmit = JSON.parse(value as string);\n      }\n    } catch (err) {\n      this._valid = false;\n      this._onValidatorChange();\n      return;\n    }\n\n    this._valid = true;\n    this._value = value;\n    this._onChange(toEmit);\n    this.updateUnitSuffixPosition();\n  }\n\n  /**\n   * Updates the position of the value's unit suffix element\n   */\n  private updateUnitSuffixPosition() {\n    if (!!this.unit && !!this.suffixElement) {\n      const input = this.suffixElement.nativeElement.previousSibling! as HTMLInputElement;\n      const style = window.getComputedStyle(input);\n      let paddingleft = parseInt(style.paddingLeft.slice(0, -2))\n      // we need to use `input.value` instead of `value` as we need to\n      // get preceding zeros of the number input as well, while still\n      // using the value as a fallback.\n      let value = input.value || (this._value as string);\n      const width = this.getTextWidth(value, style.font) + paddingleft;\n      this.suffixElement.nativeElement.style.left = `${width}px`;\n    }\n  }\n\n  /**\n   * Validates if \"value\" matches the settings requirements.\n   * It satisfies the NG_VALIDATORS interface and validates the\n   * value for THIS component.\n   *\n   * @param param0 The AbstractControl to validate\n   */\n  validate({ value }: AbstractControl): ValidationErrors | null {\n    if (!this._valid) {\n      return {\n        jsonParseError: true\n      }\n    }\n\n    if (this._type === 'string' || value === null) {\n      if (!!this.setting?.DefaultValue && !value) {\n        return {\n          required: true,\n        }\n      }\n    }\n\n    if (!!this.setting?.ValidationRegex) {\n      const re = new RegExp(this.setting.ValidationRegex);\n\n      if (!this.isJSON) {\n        if (!re.test(`${value}`)) {\n          return {\n            pattern: `\"${value}\"`\n          }\n        }\n      } else {\n        if (!Array.isArray(value)) {\n          return {\n            invalidType: true\n          }\n        }\n        const invalidLines = value.filter(v => !re.test(v));\n        if (invalidLines.length) {\n          return {\n            pattern: invalidLines\n          }\n        }\n      }\n    }\n\n    return null;\n  }\n\n  /**\n   * Writes a new value and satisfies the ControlValueAccessor\n   *\n   * @param v The new value to write\n   */\n  writeValue(v: SettingValueType<S>) {\n    // the following is a super ugly work-around for the migration\n    // from security-settings to booleans.\n    //\n    // In order to not mess and hide an actual portmaster issue\n    // we only convert v to a boolean if it's a number value and marked as a security setting.\n    // In all other cases we don't mangle it.\n    //\n    // TODO(ppacher): Remove in v1.8?\n    // BOM\n    if (this.setting?.OptType === OptionType.Bool && this.setting?.Annotations[WellKnown.DisplayHint] === ExternalOptionHint.SecurityLevel) {\n      if (typeof v === 'number') {\n        (v as any) = v === 7;\n      }\n    }\n    // EOM\n\n    let t = typeof v;\n    this._type = t;\n\n    if (this.isJSON) {\n      this._value = JSON.stringify(v, undefined, 2);\n    } else {\n      this._value = v;\n    }\n\n    this.updateUnitSuffixPosition();\n    this._changeDetectorRef.markForCheck();\n  }\n\n  registerOnValidatorChange(fn: () => void) {\n    this._onValidatorChange = fn;\n  }\n\n  /**\n   * Registers the onChange function requred by the\n   * ControlValueAccessor\n   *\n   * @param fn The fn to register\n   */\n  registerOnChange(fn: (_: SettingValueType<S>) => void) {\n    this._onChange = fn;\n  }\n\n  /**\n   * @private\n   * Called when the input-component used for the setting is touched/focused.\n   */\n  touched() {\n    this._onTouch();\n    this.blured.next();\n  }\n\n  /**\n   * Registers the onTouch function requred by the\n   * ControlValueAccessor\n   *\n   * @param fn The fn to register\n   */\n  registerOnTouched(fn: () => void) {\n    this._onTouch = fn;\n  }\n\n  /**\n   * Enable or disable the component. Required for the\n   * ControlValueAccessor.\n   *\n   * @param disable Whether or not the component is disabled\n   */\n  setDisabledState(disable: boolean) {\n    this._disabled = disable;\n    this._changeDetectorRef.markForCheck();\n  }\n\n  /**\n   * @private\n   * Returns the number of lines in value. If value is not\n   * a string 1 is returned.\n   */\n  lineCount(value: string | number | boolean) {\n    if (typeof value === 'string') {\n      return value.split('\\n').length\n    }\n    return 1\n  }\n\n  /**\n   * Calculates the amount of pixel a text requires when being rendered.\n   * It uses canvas.measureText on a dummy (no attached) element\n   *\n   * @param text The text that would be rendered\n   * @param font The CSS font descriptor that would be used for the text\n   */\n  private getTextWidth(text: string, font: string): number {\n    let canvas = this.cachedCanvas || this.document.createElement('canvas');\n    this.cachedCanvas = canvas;\n\n    let context = canvas.getContext(\"2d\")!;\n    context.font = font;\n    let metrics = context.measureText(text);\n    return metrics.width;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/basic-setting/index.ts",
    "content": "export * from './basic-setting';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/config-settings.html",
    "content": "<!-- navigation for the settings -->\n<div class=\"settings-nav hidden sfng-md:block\" *ngIf=\"!loading\" [@fadeIn]\n  [ngClass]=\"{'w-48 pl-12': !compactView, 'w-36 pl-3': compactView}\">\n  <ul>\n    <ng-container *ngFor=\"let subsys of subsystems; trackBy: trackSubsystem\">\n      <ng-template [appExpertiseLevel]=\"subsys.minimumExpertise\" [appExpertiseLevelData]=\"subsys\"\n        [appExpertiseLevelOverwrite]=\"mustShowSubsystem\">\n        <li [class.active]=\"activeSection === subsys.ConfigKeySpace\" [class.separated]=\"subsys.ID === 'core'\">\n          <span (click)=\"scrollTo(subsys.ConfigKeySpace)\" class=\"relative\">\n            {{subsys.Name}}\n            <span *ngIf=\"subsys.hasUserDefinedValues && userSettingsMarker\" class=\"user-defined-value\"></span>\n          </span>\n          <ul class=\"settings\">\n            <ng-container *ngFor=\"let cat of settings.get(subsys.ConfigKeySpace); trackBy: trackCategory\">\n              <li [class.active]=\"activeCategory === cat.name\" class=\"category\"\n                *appExpertiseLevel=\"cat.minimumExpertise; data: cat; overwrite: mustShowCategory\"\n                (click)=\"scrollTo(subsys.ConfigKeySpace + ':' + cat.name, cat)\">\n                <span class=\"relative\">\n                  {{cat.name}}\n                  <span *ngIf=\"cat.hasUserDefinedValues && userSettingsMarker\"\n                    class=\"user-defined-value category\"></span>\n                </span>\n              </li>\n            </ng-container>\n          </ul>\n        </li>\n      </ng-template>\n    </ng-container>\n    <li *ngIf=\"!!others\" (click)=\"scrollTo('config:other')\" [class.active]=\"activeSection === 'config:other'\">\n      Other\n    </li>\n  </ul>\n\n  <ul class=\"bottom-0 mb-7\">\n    <li class=\"mt-3\" *ngIf=\"!exportMode\">\n      <button class=\"bg-grey text-white w-full\" (click)=\"openImportDialog()\">Import Settings</button>\n    </li>\n    <li *ngIf=\"exportMode\" class=\"mt-3\">\n      <button class=\"bg-grey text-white w-full\" (click)=\"generateExport()\">Save</button>\n    </li>\n    <li>\n      <button [ngClass]=\"{'bg-grey': !exportMode, 'bg-gray-400': exportMode}\" class=\"text-white w-full\" (click)=\"toggleExportMode()\">{{ !exportMode ? 'Export Settings' : 'Cancel Export' }}</button>\n    </li>\n  </ul>\n\n</div>\n\n<div class=\"flex justify-center flex-grow px-0 pb-24 pr-4 overflow-auto whitespace-normal\" cdkScrollable>\n  <fa-icon icon=\"spinner\" [spin]=\"true\" *ngIf=\"loading\"></fa-icon>\n\n  <div class=\"w-full space-y-4\" *ngIf=\"!loading\">\n    <!-- actual settings -->\n    <ng-container *ngFor=\"let subsys of subsystems; trackBy: trackSubsystem\">\n\n      <ng-template [appExpertiseLevel]=\"subsys.minimumExpertise\" [appExpertiseLevelData]=\"subsys\"\n        [appExpertiseLevelOverwrite]=\"mustShowSubsystem\">\n\n        <h2 class=\"w-full px-0 ml-0 text-xl text-primary\" [attr.id]=\"subsys.ConfigKeySpace\">\n          {{subsys.Name}}\n        </h2>\n\n        <ng-container *ngFor=\"let cat of settings.get(subsys.ConfigKeySpace); trackBy: trackCategory; let index=index\">\n          <div class=\"max-w-screen-lg space-y-4\" #navLink anchor=\"top\" [attr.subsystem]=\"subsys.ConfigKeySpace\"\n            [attr.category]=\"cat.name\"\n            *appExpertiseLevel=\"cat.minimumExpertise; data: cat; overwrite: mustShowCategory\">\n\n            <div (click)=\"cat.collapsed = !cat.collapsed\" [attr.id]=\"subsys.ConfigKeySpace +':' + cat.name\"\n              class=\"flex items-center justify-between p-3 px-5 bg-gray-300 rounded cursor-pointer select-none\">\n              <h4 class=\"text-md text-primary\">{{cat.name}}</h4>\n\n              <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-6 h-6 transition-transform duration-150 transform\"\n                [class.rotate-90]=\"!cat.collapsed\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n              </svg>\n\n            </div>\n\n            <div *ngIf=\"!cat.collapsed\" [@fadeIn] [@fadeOut] class=\"space-y-4\">\n              <ng-container *ngFor=\"let setting of cat.settings; trackBy: configService.trackBy\">\n                <div class=\"ml-6\"\n                  *appExpertiseLevel=\"setting.ExpertiseLevel; data: setting; overwrite: mustShowSetting\">\n\n                  <app-generic-setting [class.highlighted]=\"highlightKey === setting.Key\" [setting]=\"setting\"\n                    [attr.id]=\"setting.Key\" [resetLabelText]=\"resetLabelText\" (save)=\"saveSetting($event, setting)\"\n                    [lockDefaults]=\"lockDefaults\" [displayStackable]=\"displayStackable\" [selectMode]=\"exportMode\" [(selected)]=\"selectedSettings[setting.Key]\">\n                  </app-generic-setting>\n\n                </div>\n              </ng-container>\n            </div>\n          </div>\n        </ng-container>\n      </ng-template>\n    </ng-container>\n\n    <ng-container *ngIf=\"!!others\">\n      <h2 id=\"config:other\" #navLink>\n        Other\n      </h2>\n      <div class=\"category\">\n        <ng-container *ngFor=\"let setting of others; trackBy: configService.trackBy\">\n          <app-generic-setting *appExpertiseLevel=\"setting.ExpertiseLevel; data: setting; overwrite: mustShowSetting\"\n            [setting]=\"setting\" [resetLabelText]=\"resetLabelText\" (save)=\"saveSetting($event, setting)\"\n            [lockDefaults]=\"lockDefaults\" [displayStackable]=\"displayStackable\" [selectMode]=\"exportMode\" [(selected)]=\"selectedSettings[setting.Key]\">\n          </app-generic-setting>\n        </ng-container>\n      </div>\n    </ng-container>\n    <div class=\"pb-24\"></div>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/config-settings.scss",
    "content": ":host {\n  display: flex;\n  overflow: hidden;\n}\n\n\nfa-icon[icon=\"spinner\"] {\n  @apply text-3xl;\n  display: block;\n  width: 100%;\n  text-align: center;\n  height: 6rem;\n}\n\ndiv.settings-nav {\n  @apply mt-4;\n  flex-shrink: 0;\n  overflow: visible;\n  white-space: nowrap;\n\n  transition: height cubic-bezier(0.25, 0.46, 0.45, 0.94) .5s;\n  @apply text-xs;\n\n\n  ul {\n    position: fixed;\n\n    li {\n      @apply font-medium;\n\n      &.separated {\n        margin-top: 1.25rem;\n      }\n\n    }\n\n    &>li {\n      @apply mb-1;\n      @apply text-tertiary;\n\n      span {\n        cursor: pointer;\n        display: block;\n      }\n\n      &:hover,\n      &.active {\n        @apply text-primary;\n      }\n\n      &.active {\n        &.category:before {\n          content: \"\";\n          width: 1px;\n          height: 1rem;\n          @apply bg-white block absolute;\n          left: 0.5rem;\n        }\n\n        ul.settings {\n          display: inline-block;\n        }\n      }\n\n      ul.settings {\n        position: unset;\n        @apply mt-2;\n        @apply ml-2;\n        @apply pl-3;\n        @apply text-xs;\n        @apply border-l;\n        @apply border-cards-tertiary;\n        display: none;\n\n        li {\n          cursor: pointer;\n          margin-top: 0;\n        }\n      }\n    }\n  }\n}\n\n.user-defined-value:before {\n  content: \"\";\n  height: 1rem;\n  @apply bg-blue block absolute rounded-full w-1 h-1;\n  top: 0.45rem;\n  left: -1rem;\n}\n\n.user-defined-value.category:before {\n  left: -2rem;\n  top: 0.35rem;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/config-settings.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ScrollDispatcher } from '@angular/cdk/overlay';\nimport {\n  AfterViewInit,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnDestroy,\n  OnInit,\n  Output,\n  QueryList,\n  TrackByFunction,\n  ViewChildren,\n} from '@angular/core';\nimport {\n  ConfigService,\n  ExpertiseLevelNumber,\n  PortapiService,\n  Setting,\n  StringSetting,\n  releaseLevelFromName,\n} from '@safing/portmaster-api';\nimport { BehaviorSubject, Subscription, combineLatest } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\nimport { StatusService } from 'src/app/services';\nimport {\n  fadeInAnimation,\n  fadeInListAnimation,\n  fadeOutAnimation,\n} from 'src/app/shared/animations';\nimport { FuzzySearchService } from 'src/app/shared/fuzzySearch';\nimport { ExpertiseLevelOverwrite } from '../expertise/expertise-directive';\nimport { SaveSettingEvent } from './generic-setting/generic-setting';\nimport { ActionIndicatorService } from '../action-indicator';\nimport { SfngDialogService } from '@safing/ui';\nimport {\n  ExportConfig,\n  ExportDialogComponent,\n} from './export-dialog/export-dialog.component';\nimport {\n  ImportConfig,\n  ImportDialogComponent,\n} from './import-dialog/import-dialog.component';\n\nimport { subsystems, SubsystemWithExpertise } from './subsystems'\n\ninterface Category {\n  name: string;\n  settings: Setting[];\n  minimumExpertise: ExpertiseLevelNumber;\n  collapsed: boolean;\n  hasUserDefinedValues: boolean;\n}\n\n@Component({\n  selector: 'app-settings-view',\n  templateUrl: './config-settings.html',\n  styleUrls: ['./config-settings.scss'],\n  animations: [fadeInAnimation, fadeOutAnimation, fadeInListAnimation],\n})\nexport class ConfigSettingsViewComponent\n  implements OnInit, OnDestroy, AfterViewInit {\n  subsystems: SubsystemWithExpertise[] = subsystems;\n  others: Setting[] | null = null;\n  settings: Map<string, Category[]> = new Map();\n\n  /** A list of all selected settings for export */\n  selectedSettings: { [key: string]: boolean } = {};\n\n  /** Whether or not we are currently in \"export\" mode */\n  exportMode = false;\n\n  activeSection = '';\n  activeCategory = '';\n  loading = true;\n\n  @Input()\n  resetLabelText = 'Reset to system default';\n\n  @Input()\n  set compactView(v: any) {\n    this._compactView = coerceBooleanProperty(v);\n  }\n  get compactView() {\n    return this._compactView;\n  }\n  private _compactView = false;\n\n  @Input()\n  set lockDefaults(v: any) {\n    this._lockDefaults = coerceBooleanProperty(v);\n  }\n  get lockDefaults() {\n    return this._lockDefaults;\n  }\n  private _lockDefaults = false;\n\n  @Input()\n  set userSettingsMarker(v: any) {\n    this._userSettingsMarker = coerceBooleanProperty(v);\n  }\n  get userSettingsMarker() {\n    return this._userSettingsMarker;\n  }\n  private _userSettingsMarker = true;\n\n  @Input()\n  set searchTerm(v: string) {\n    this.onSearch.next(v);\n  }\n\n  @Input()\n  set availableSettings(v: Setting[]) {\n    this.onSettingsChange.next(v);\n  }\n\n  @Input()\n  set scope(scope: 'global' | string) {\n    this._scope = scope;\n  }\n  get scope() {\n    return this._scope;\n  }\n  private _scope: 'global' | string = 'global';\n\n  @Input()\n  displayStackable: string | boolean = false;\n\n  @Input()\n  set highlightKey(key: string | null) {\n    this._highlightKey = key || null;\n    this._scrolledToHighlighted = false;\n    // If we already loaded the settings then instruct the window\n    // to scroll the setting into the view.\n    if (!!key && !!this.settings && this.settings.size > 0) {\n      this.scrollTo(key);\n      this._scrolledToHighlighted = true;\n    }\n  }\n  get highlightKey() {\n    return this._highlightKey;\n  }\n  private _highlightKey: string | null = null;\n  private _scrolledToHighlighted = false;\n\n  mustShowSetting: ExpertiseLevelOverwrite<Setting> = (\n    lvl: ExpertiseLevelNumber,\n    s: Setting\n  ) => {\n    if (lvl >= s.ExpertiseLevel) {\n      // this setting is shown anyway.\n      return false;\n    }\n    if (s.Key === this.highlightKey) {\n      return true;\n    }\n    // the user is searching for settings so make sure we even show advanced or developer settings\n    if (this.onSearch.getValue() !== '') {\n      return true;\n    }\n    if (s.Value === undefined) {\n      // no value set\n      return false;\n    }\n    return true;\n  };\n\n  mustShowCategory: ExpertiseLevelOverwrite<Category> = (\n    lvl: ExpertiseLevelNumber,\n    cat: Category\n  ) => {\n    return cat.settings.some((setting) => this.mustShowSetting(lvl, setting));\n  };\n\n  mustShowSubsystem: ExpertiseLevelOverwrite<SubsystemWithExpertise> = (\n    lvl: ExpertiseLevelNumber,\n    subsys: SubsystemWithExpertise\n  ) => {\n    return !!this.settings\n      .get(subsys.ConfigKeySpace)\n      ?.some((cat) => this.mustShowCategory(lvl, cat));\n  };\n\n  @Output()\n  save = new EventEmitter<SaveSettingEvent>();\n\n  private onSearch = new BehaviorSubject<string>('');\n  private onSettingsChange = new BehaviorSubject<Setting[]>([]);\n\n  @ViewChildren('navLink', { read: ElementRef })\n  navLinks: QueryList<ElementRef> | null = null;\n\n  private subscription = Subscription.EMPTY;\n\n  constructor(\n    public statusService: StatusService,\n    public configService: ConfigService,\n    private elementRef: ElementRef,\n    private changeDetectorRef: ChangeDetectorRef,\n    private scrollDispatcher: ScrollDispatcher,\n    private searchService: FuzzySearchService,\n    private actionIndicator: ActionIndicatorService,\n    private portapi: PortapiService,\n    private dialog: SfngDialogService,\n  ) { }\n\n  openImportDialog() {\n    const importConfig: ImportConfig = {\n      type: 'setting',\n      key: this.scope,\n    };\n    this.dialog.create(ImportDialogComponent, {\n      data: importConfig,\n      autoclose: false,\n      backdrop: 'light',\n    });\n  }\n\n  toggleExportMode() {\n    this.exportMode = !this.exportMode;\n\n    if (this.exportMode) {\n      this.actionIndicator.info(\n        'Settings Export',\n        'Please select all settings you want to export and press \"Save\" to generate the export. Note that settings with system defaults cannot be exported and are hidden.'\n      );\n    }\n  }\n\n  generateExport() {\n    let selectedKeys = Object.keys(this.selectedSettings).reduce((sum, key) => {\n      if (this.selectedSettings[key]) {\n        sum.push(key);\n      }\n\n      return sum;\n    }, [] as string[]);\n\n    if (selectedKeys.length === 0) {\n      selectedKeys = Array.from(this.settings.values()).reduce(\n        (sum, current) => {\n          current.forEach((cat) => {\n            cat.settings.forEach((s) => {\n              if (s.Value !== undefined) {\n                sum.push(s.Key);\n              }\n            });\n          });\n\n          return sum;\n        },\n        [] as string[]\n      );\n    }\n\n    this.portapi.exportSettings(selectedKeys, this.scope).subscribe({\n      next: (exportBlob) => {\n        const exportConfig: ExportConfig = {\n          type: 'setting',\n          content: exportBlob,\n        };\n\n        this.dialog.create(ExportDialogComponent, {\n          data: exportConfig,\n          backdrop: 'light',\n          autoclose: true,\n        });\n\n        this.exportMode = false;\n      },\n      error: (err) => {\n        const msg = this.actionIndicator.getErrorMessgae(err);\n        this.actionIndicator.error('Failed To Generate Export', msg);\n      },\n    });\n  }\n\n  saveSetting(event: SaveSettingEvent, s: Setting) {\n    this.save.next(event);\n    const subsys = this.subsystems.find(\n      (subsys) => s.Key === subsys.ToggleOptionKey\n    );\n    if (!!subsys) {\n      // trigger a reload of the page as we now might need to show more\n      // settings.\n      this.onSettingsChange.next(this.onSettingsChange.getValue());\n    }\n  }\n\n  trackSubsystem: TrackByFunction<SubsystemWithExpertise> =\n    this.statusService.trackSubsystem;\n\n  trackCategory(_: number, cat: Category) {\n    return cat.name;\n  }\n\n  ngOnInit(): void {\n    this.subscription = combineLatest([\n      this.onSettingsChange,\n      this.onSearch.pipe(debounceTime(250)),\n      this.configService.watch<StringSetting>('core/releaseLevel'),\n    ])\n      .pipe(debounceTime(10))\n      .subscribe(\n        ([settings, searchTerm, currentReleaseLevelSetting]) => {\n          this.others = [];\n          this.settings = new Map();\n\n          // Get the current release level as a number (fallback to 'stable' is something goes wrong)\n          const currentReleaseLevel = releaseLevelFromName(\n            currentReleaseLevelSetting || ('stable' as any)\n          );\n\n          // Make sure we only display settings that are allowed by the releaselevel setting.\n          settings = settings.filter(\n            (setting) => setting.ReleaseLevel <= currentReleaseLevel\n          );\n\n          // Use fuzzy-search to limit the number of settings shown.\n          const filtered = this.searchService.searchList(settings, searchTerm, {\n            ignoreLocation: true,\n            ignoreFieldNorm: true,\n            threshold: 0.1,\n            minMatchCharLength: 3,\n            keys: [\n              { name: 'Name', weight: 3 },\n              { name: 'Description', weight: 2 },\n            ],\n          });\n\n          // The search service wraps the items in a search-result object.\n          // Unwrap them now.\n          settings = filtered.map((res) => res.item);\n\n          // use order-annotations to sort the settings. This affects the order of\n          // the categories as well as the settings inside the categories.\n          settings.sort((a, b) => {\n            const orderA = a.Annotations?.['safing/portbase:ui:order'] || 0;\n            const orderB = b.Annotations?.['safing/portbase:ui:order'] || 0;\n            return orderA - orderB;\n          });\n\n          settings.forEach((setting) => {\n            let pushed = false;\n            this.subsystems.forEach((subsys) => {\n              if (\n                setting.Key.startsWith(\n                  subsys.ConfigKeySpace.slice('config:'.length)\n                )\n              ) {\n                // get the category name annotation and fallback to 'others'\n                let catName = 'other';\n                if (\n                  !!setting.Annotations &&\n                  !!setting.Annotations['safing/portbase:ui:category']\n                ) {\n                  catName = setting.Annotations['safing/portbase:ui:category'];\n                }\n\n                // ensure we have a category array for the subsystem.\n                let categories = this.settings.get(subsys.ConfigKeySpace);\n                if (!categories) {\n                  categories = [];\n                  this.settings.set(subsys.ConfigKeySpace, categories);\n                }\n\n                // find or create the appropriate category object.\n                let cat = categories.find((c) => c.name === catName);\n                if (!cat) {\n                  cat = {\n                    name: catName,\n                    minimumExpertise: ExpertiseLevelNumber.developer,\n                    settings: [],\n                    collapsed: false,\n                    hasUserDefinedValues: false,\n                  };\n                  categories.push(cat);\n                }\n\n                // add the setting to the category object and update\n                // the minimum expertise required for the category.\n                cat.settings.push(setting);\n                if (setting.ExpertiseLevel < cat.minimumExpertise) {\n                  cat.minimumExpertise = setting.ExpertiseLevel;\n                }\n\n                pushed = true;\n              }\n            });\n\n            // if we did not push the setting to some subsystem\n            // we need to push it to \"others\"\n            if (!pushed) {\n              this.others!.push(setting);\n            }\n          });\n\n          if (this.others.length === 0) {\n            this.others = null;\n          }\n\n          // Reduce the subsystem array to only contain subsystems that\n          // actually have settings to show.\n          // Also update the minimumExpertiseLevel for those subsystems\n          this.subsystems = this.subsystems\n            .filter((subsys) => {\n              return !!this.settings.get(subsys.ConfigKeySpace);\n            })\n            .map((subsys) => {\n              let categories = this.settings.get(subsys.ConfigKeySpace)!;\n              let hasUserDefinedValues = false;\n              categories.forEach((c) => {\n                c.hasUserDefinedValues = c.settings.some(\n                  (s) => s.Value !== undefined\n                );\n                hasUserDefinedValues =\n                  c.hasUserDefinedValues || hasUserDefinedValues;\n              });\n\n              subsys.hasUserDefinedValues = hasUserDefinedValues;\n\n              let toggleOption: Setting | undefined = undefined;\n              for (let c of categories) {\n                toggleOption = c.settings.find(\n                  (s) => s.Key === subsys.ToggleOptionKey\n                );\n                if (!!toggleOption) {\n                  if (\n                    (toggleOption.Value !== undefined && !toggleOption.Value) ||\n                    (toggleOption.Value === undefined &&\n                      !toggleOption.DefaultValue)\n                  ) {\n                    subsys.isDisabled = true;\n\n                    // remove all settings for all subsystem categories\n                    // except for the ToggleOption.\n                    categories = categories\n                      .map((c) => ({\n                        ...c,\n                        settings: c.settings.filter(\n                          (s) => s.Key === toggleOption!.Key\n                        ),\n                      }))\n                      .filter((cat) => cat.settings.length > 0);\n                    this.settings.set(subsys.ConfigKeySpace, categories);\n                  }\n                  break;\n                }\n              }\n\n              // reduce the categories to find the smallest expertise level requirement.\n              subsys.minimumExpertise = categories.reduce((min, current) => {\n                if (current.minimumExpertise < min) {\n                  return current.minimumExpertise;\n                }\n                return min;\n              }, ExpertiseLevelNumber.developer as ExpertiseLevelNumber);\n\n              return subsys;\n            });\n\n          // Force the core subsystem to the end.\n          if (this.subsystems.length >= 2 && this.subsystems[0].ID === 'core') {\n            this.subsystems.push(\n              this.subsystems.shift() as SubsystemWithExpertise\n            );\n          }\n\n          // Notify the user interface that we're done loading\n          // the settings.\n          this.loading = false;\n\n          // If there's a highlightKey set and we have not yet scrolled\n          // to it (because it was set during component bootstrap) we\n          // need to scroll there now.\n          if (this._highlightKey !== null && !this._scrolledToHighlighted) {\n            this._scrolledToHighlighted = true;\n\n            // Use the next animation frame for scrolling\n            window.requestAnimationFrame(() => {\n              this.scrollTo(this._highlightKey || '');\n            });\n          }\n        }\n      );\n  }\n\n  ngAfterViewInit() {\n    this.subscription = new Subscription();\n\n    // Whenever our scroll-container is scrolled we might\n    // need to update which setting is currently highlighted\n    // in the settings-navigation.\n    this.subscription.add(\n      this.scrollDispatcher\n        .scrolled(10)\n        .subscribe(() => this.intersectionCallback())\n    );\n\n    // Also, entries in the settings-navigation might become\n    // visible with expertise/release level changes so make\n    // sure to recalculate the current one whenever a change\n    // happens.\n    this.subscription.add(\n      this.navLinks?.changes.subscribe(() => {\n        this.intersectionCallback();\n        this.changeDetectorRef.detectChanges();\n      })\n    );\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe();\n    this.onSearch.complete();\n  }\n\n  /**\n   * Calculates which navigation entry should be highlighted\n   * depending on the scroll position.\n   */\n  private intersectionCallback() {\n    // search our parents for the element that's scrollable\n    let elem: HTMLElement = this.elementRef.nativeElement;\n    while (!!elem) {\n      if (elem.scrollTop > 0) {\n        break;\n      }\n      elem = elem.parentElement!;\n    }\n\n    // if there's no scrolled/scrollable parent element\n    // our content itself is scrollable so use our own\n    // host element as the anchor for the calculation.\n    if (!elem) {\n      elem = this.elementRef.nativeElement;\n    }\n\n    // get the elements offset to page-top\n    var offsetTop = 0;\n    if (!!elem) {\n      const viewRect = elem.getBoundingClientRect();\n      offsetTop = viewRect.top;\n    }\n\n    this.navLinks?.some((link) => {\n      const subsystem = link.nativeElement.getAttribute('subsystem');\n      const category = link.nativeElement.getAttribute('category');\n\n      const lastChild = (link.nativeElement as HTMLElement)\n        .lastElementChild as HTMLElement;\n      if (!lastChild) {\n        return false;\n      }\n\n      const rect = lastChild.getBoundingClientRect();\n      const styleBox = getComputedStyle(lastChild);\n\n      const offset =\n        rect.top +\n        rect.height -\n        parseInt(styleBox.marginBottom) -\n        parseInt(styleBox.paddingBottom);\n\n      if (offset >= offsetTop) {\n        this.activeSection = subsystem;\n        this.activeCategory = category;\n        return true;\n      }\n\n      return false;\n    });\n    this.changeDetectorRef.detectChanges();\n  }\n\n  /**\n   * @private\n   * Performs a smooth-scroll to the given anchor element ID.\n   *\n   * @param id The ID of the anchor element to scroll to.\n   */\n  scrollTo(id: string, cat?: Category) {\n    if (!!cat) {\n      cat.collapsed = false;\n    }\n    document.getElementById(id)?.scrollIntoView({\n      behavior: 'smooth',\n      block: 'start',\n      inline: 'nearest',\n    });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/config.module.ts",
    "content": "import { DragDropModule } from '@angular/cdk/drag-drop';\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\nimport { FontAwesomeModule } from '@fortawesome/angular-fontawesome';\nimport {\n  SfngSelectModule,\n  SfngTipUpModule,\n  SfngToggleSwitchModule,\n  SfngTooltipModule,\n} from '@safing/ui';\nimport { MarkdownModule } from 'ngx-markdown';\nimport { ExpertiseModule } from '../expertise/expertise.module';\nimport { SfngFocusModule } from '../focus';\nimport { SfngMenuModule } from '../menu';\nimport { SfngMultiSwitchModule } from '../multi-switch';\nimport { BasicSettingComponent } from './basic-setting/basic-setting';\nimport { ConfigSettingsViewComponent } from './config-settings';\nimport { FilterListComponent } from './filter-lists';\nimport { GenericSettingComponent } from './generic-setting';\nimport {\n  OrderedListComponent,\n  OrderedListItemComponent,\n} from './ordererd-list';\nimport { RuleListItemComponent } from './rule-list/list-item';\nimport { RuleListComponent } from './rule-list/rule-list';\nimport { SafePipe } from './safe.pipe';\nimport { ExportDialogComponent } from './export-dialog/export-dialog.component';\nimport { ImportDialogComponent } from './import-dialog/import-dialog.component';\nimport { SfngAppIconModule } from '../app-icon';\n\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    DragDropModule,\n    SfngTooltipModule,\n    SfngSelectModule,\n    SfngMultiSwitchModule,\n    SfngFocusModule,\n    SfngMenuModule,\n    SfngTipUpModule,\n    FontAwesomeModule,\n    MarkdownModule,\n    RouterModule,\n    ExpertiseModule,\n    SfngToggleSwitchModule,\n    MarkdownModule,\n    SfngAppIconModule\n  ],\n  declarations: [\n    BasicSettingComponent,\n    FilterListComponent,\n    OrderedListComponent,\n    OrderedListItemComponent,\n    RuleListComponent,\n    RuleListItemComponent,\n    ConfigSettingsViewComponent,\n    GenericSettingComponent,\n    SafePipe,\n    ExportDialogComponent,\n    ImportDialogComponent,\n  ],\n  exports: [\n    BasicSettingComponent,\n    FilterListComponent,\n    OrderedListComponent,\n    OrderedListItemComponent,\n    RuleListComponent,\n    RuleListItemComponent,\n    ConfigSettingsViewComponent,\n    GenericSettingComponent,\n    SafePipe,\n  ],\n})\nexport class ConfigModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/export-dialog/export-dialog.component.html",
    "content": "<header class=\"flex flex-row items-center justify-between mb-4\">\n  <h1 class=\"text-sm font-light m-0\">\n    {{ dialogRef.data.type === \"setting\" ? \"Settings\" : \"Profile\" }} Export\n  </h1>\n\n  <svg role=\"img\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"\n    class=\"w-3 h-3 text-secondary hover:text-primary cursor-pointer\" (click)=\"dialogRef.close()\">\n    <path fill=\"currentColor\"\n      d=\"M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z\">\n    </path>\n  </svg>\n</header>\n\n<markdown lineNumbers [data]=\"content\" emoji class=\"overflow-auto\"></markdown>\n\n<div class=\"flex flex-row justify-end gap-2 items-center\">\n  <button (click)=\"copyToClipboard()\">Copy To Clipboard</button>\n  <button (click)=\"download()\">Save</button>\n</div>"
  },
  {
    "path": "desktop/angular/src/app/shared/config/export-dialog/export-dialog.component.ts",
    "content": "import { DOCUMENT } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  OnInit,\n  inject,\n} from '@angular/core';\nimport { SFNG_DIALOG_REF, SfngDialogRef } from '@safing/ui';\nimport { ActionIndicatorService } from '../../action-indicator';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\n\nexport interface ExportConfig {\n  content: string;\n  type: 'setting' | 'profile';\n}\n\n@Component({\n  templateUrl: './export-dialog.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styles: [\n    `\n      :host {\n        @apply flex flex-col gap-2 overflow-hidden;\n        min-height: 24rem;\n        min-width: 24rem;\n        max-height: 40rem;\n        max-width: 40rem;\n      }\n    `,\n  ],\n})\nexport class ExportDialogComponent implements OnInit {\n  readonly dialogRef: SfngDialogRef<\n    ExportDialogComponent,\n    unknown,\n    ExportConfig\n  > = inject(SFNG_DIALOG_REF);\n\n  private readonly elementRef: ElementRef<HTMLElement> = inject(ElementRef);\n  private readonly document = inject(DOCUMENT);\n  private readonly uai = inject(ActionIndicatorService);\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  content = '';\n\n  ngOnInit(): void {\n    this.content = '```yaml\\n' + this.dialogRef.data.content + '\\n```';\n  }\n\n  download() {\n    const blob = new Blob([this.dialogRef.data.content], { type: 'text/yaml' });\n\n    const elem = this.document.createElement('a');\n    elem.href = window.URL.createObjectURL(blob);\n    elem.download = 'export.yaml';\n    this.elementRef.nativeElement.appendChild(elem);\n    elem.click();\n    this.elementRef.nativeElement.removeChild(elem);\n  }\n\n  copyToClipboard() {\n    this.integration.writeToClipboard(this.dialogRef.data.content)\n      .then(() => this.uai.success('Copied to Clipboard'))\n      .catch(() => this.uai.error('Failed to Copy to Clipboard'));\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/filter-lists/filter-list.html",
    "content": "<div class=\"scrollable\">\n\n  <ng-template #treeNode let-node>\n    <div class=\"node\">\n      <div class=\"relative head\">\n        <span *ngIf=\"node.hasSelectedChildren\"\n          class=\"relative block w-1 h-1 rounded-full -left-2.5 -mr-1 -top-0.5 bg-blue\"></span>\n        <input type=\"checkbox\" [ngModel]=\"node.selected\" (ngModelChange)=\"updateNode(node, $event)\">\n\n        <label>\n          <span class=\"flex flex-row items-center gap-2 name\">\n            {{node.name}}\n            <span class=\"id\">({{ node.id }})</span>\n          </span>\n          <span class=\"description\">{{ node.description }}</span>\n        </label>\n\n        <span class=\"details\">\n          {{ !!node.license ? 'License: ' + node.license : '' }}\n        </span>\n        <span class=\"details\">\n          <a *ngIf=\"!!node.website\" href=\"{{node.website}}\">\n            <fa-icon icon=\"external-link-square-alt\"></fa-icon>\n          </a>\n        </span>\n      </div>\n\n      <div class=\"children\" *ngIf=\"node.children.length > 0\">\n        <div class=\"expand\" (click)=\"node.expanded = !node.expanded\">\n          <ng-container *ngIf=\"!node.expanded\">\n            <fa-icon icon=\"chevron-right\"></fa-icon>\n            Expand\n          </ng-container>\n          <ng-container *ngIf=\"node.expanded\">\n            <fa-icon icon=\"chevron-down\"></fa-icon>\n            Collapse\n          </ng-container>\n        </div>\n      </div>\n\n      <div class=\"children\" *ngIf=\"node.children.length > 0\"\n        [@moveInOutList]=\"(node.expanded ? node.children : []).length\">\n        <div class=\"border\" *ngIf=\"node.expanded\"></div>\n        <ng-container *ngFor=\"let child of (node.expanded ? node.children : []); trackBy: trackNode\">\n          <ng-container *ngTemplateOutlet=\"treeNode; context: {$implicit: child}\"></ng-container>\n        </ng-container>\n      </div>\n    </div>\n  </ng-template>\n\n  <ng-container *ngFor=\"let node of nodes; trackBy: trackNode\">\n    <ng-container *ngTemplateOutlet=\"treeNode; context: {$implicit: node}\"></ng-container>\n  </ng-container>\n\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/filter-lists/filter-list.scss",
    "content": ":host {\n  display: block;\n  overflow: hidden;\n\n  @apply bg-cards-secondary;\n  @apply rounded;\n  @apply p-2;\n  @apply h-full;\n}\n\n.node {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n\n  justify-content: flex-start;\n  @apply py-1;\n\n  .head {\n    display: flex;\n    flex-direction: row;\n    align-items: baseline;\n\n    input {\n      @apply mr-2;\n      position: relative;\n      top: 2px;\n    }\n\n    label {\n      display: flex;\n      flex-direction: column;\n      flex-grow: 1;\n    }\n\n    span.details {\n      opacity: 0;\n      text-transform: capitalize;\n      font-size: 0.9em;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      overflow: hidden;\n      max-width: 6rem;\n      @apply text-tertiary;\n    }\n\n    &:hover {\n      span.details {\n        opacity: 1;\n\n      }\n    }\n  }\n\n  span.name {\n    @apply text-primary;\n\n    .id {\n      @apply text-tertiary;\n      font-style: italic;\n    }\n  }\n\n  .description {\n    position: relative;\n    top: -2px;\n\n    @apply text-tertiary;\n  }\n\n  div.expand {\n    cursor: pointer;\n    @apply text-secondary;\n    display: flex;\n    flex-direction: row;\n    align-items: center;\n    @apply pb-2;\n\n    fa-icon {\n      margin-right: 0.25rem;\n    }\n  }\n\n  .children {\n    display: flex;\n    flex-direction: column;\n    margin-left: 1.25rem;\n  }\n\n  .border {\n    position: absolute;\n    top: 1.2rem;\n    bottom: 0.5rem;\n    width: 0.7rem;\n    margin-left: -0.85rem;\n    border: 1px solid;\n    border-right: none;\n    border-top: none;\n    @apply border-cards-tertiary;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/filter-lists/filter-list.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostListener, OnDestroy, OnInit } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { PortapiService, Record } from '@safing/portmaster-api';\nimport { Subscription } from 'rxjs';\nimport { moveInOutListAnimation } from '../../animations';\n\ninterface Category {\n  name: string;\n  id: string;\n  description: string;\n  parent?: string | null;\n}\n\ninterface Source {\n  name: string;\n  id: string;\n  description: string;\n  category: string;\n  // urls: Resource[]; // we don't care about the actual URLs here.\n  website: string;\n  contribute: string;\n  license: string;\n}\n\ninterface FilterListIndex extends Record {\n  version: string;\n  schemaVersion: string;\n  categories: Category[];\n  sources: Source[];\n}\n\ninterface TreeNode {\n  id: string;\n  name: string;\n  description: string;\n  children: TreeNode[];\n  expanded: boolean;\n  selected: boolean;\n  parent?: TreeNode;\n  website?: string;\n  license?: string;\n  hasSelectedChildren: boolean;\n}\n\n@Component({\n  selector: 'app-filter-list',\n  templateUrl: './filter-list.html',\n  styleUrls: ['./filter-list.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => FilterListComponent),\n      multi: true,\n    }\n  ],\n  animations: [\n    moveInOutListAnimation,\n  ]\n})\nexport class FilterListComponent implements OnInit, OnDestroy, ControlValueAccessor {\n  /** The actual filter-list index as loaded from the portmaster. */\n  private index: FilterListIndex | null = null;\n\n  /** @private a list of \"tree-nodes\" to render */\n  nodes: TreeNode[] = [];\n\n  /** A lookup map for fast ID to TreeNode lookups */\n  private lookupMap: Map<string, TreeNode> = new Map();\n\n  /** @private forward blur events to the onTouch callback. */\n  @HostListener('blur')\n  onBlur() {\n    this.onTouch();\n  }\n\n  /** The currently selected IDs. */\n  private selectedIDs: string[] = [];\n\n  /** Subscription to watch the filterlist index. */\n  private watchSubscription = Subscription.EMPTY;\n\n  constructor(private portapi: PortapiService,\n    private changeDetectorRef: ChangeDetectorRef) { }\n\n  ngOnInit() {\n    this.watchSubscription =\n      this.portapi.watch<FilterListIndex>(\"cache:intel/filterlists/index\")\n        .subscribe(\n          index => this.updateIndex(index),\n          err => {\n            // Filter list index not yet loaded.\n            console.error(`failed to get fitlerlist index`, err);\n          }\n        );\n  }\n\n  ngOnDestroy() {\n    this.watchSubscription.unsubscribe();\n  }\n\n  /** The onChange callback registered by ngModel or form controls */\n  private _onChange: (v: string[]) => void = () => { };\n\n  /** Registers the onChange callback required by ControlValueAccessor */\n  registerOnChange(fn: (v: string[]) => void) {\n    this._onChange = fn;\n  }\n\n  /** The _onTouch callback registered by ngModel and form controls */\n  private onTouch: () => void = () => { };\n\n  /** Registeres the onTouch callback required by ControlValueAccessor. */\n  registerOnTouched(fn: () => void) {\n    this.onTouch = fn;\n  }\n\n  /**\n   * Update the currently selected IDs. Used by ngModel\n   * and form controls. Implements ControlValueAccessor.\n   *\n   * @param ids A list of selected IDs\n   */\n  writeValue(ids: string[]) {\n    this.selectedIDs = ids;\n    if (!!this.index) {\n      this.updateIndex(this.index);\n    }\n  }\n\n  /**\n   *\n   * @param index The filter list index.\n   */\n  private updateIndex(index: FilterListIndex) {\n    this.index = index;\n\n    var nodes: TreeNode[] = [];\n    let lm = new Map<string, TreeNode>();\n    let childCategories: Category[] = [];\n\n    // Create a tree-node for each category\n    this.index.categories.forEach(category => {\n      let tn: TreeNode = {\n        id: category.id,\n        description: category.description,\n        name: category.name,\n        children: [],\n        expanded: this.lookupMap.get(category.id)?.expanded || false, // keep it expanded if the user did not change anything.\n        selected: false,\n        hasSelectedChildren: false,\n      };\n\n      lm.set(category.id, tn)\n\n      // if the category does not have a parent\n      // it's a root node.\n      if (!category.parent) {\n        nodes.push(tn);\n      } else {\n        // we need to handle child-categories later.\n        childCategories.push(category);\n      }\n    });\n\n    // iterate over all \"child\" categories and add\n    // them to the correct parent (which must be in lm already.)\n    childCategories.forEach(category => {\n      const tn = lm.get(category.id)!;\n      const parent = lm.get(category.parent!);\n      // if the parent category does not exist ignore it\n      if (!parent) {\n        return;\n      }\n\n      parent.children.push(tn);\n      tn.parent = parent;\n    });\n\n    this.index.sources.forEach(source => {\n      let category = lm.get(source.category);\n      if (!category) {\n        return;\n      }\n\n      let tn: TreeNode = {\n        id: source.id,\n        name: source.name,\n        description: source.description,\n        children: [],\n        expanded: false,\n        selected: false,\n        parent: category,\n        website: source.website,\n        license: source.license,\n        hasSelectedChildren: false\n      }\n\n      // Add the source to the lookup-map\n      lm.set(source.id, tn);\n\n      category.children.push(tn);\n    });\n\n    // make sure we expand all parent categories for\n    // all selected IDs so they are actually visible.\n    this.selectedIDs.forEach(id => {\n      const tn = lm.get(id);\n      if (!tn) {\n        return;\n      }\n\n      this.updateNode(tn, true, true, true, false);\n\n      let parent = tn.parent;\n      while (!!parent) {\n        parent.expanded = true;\n        parent.hasSelectedChildren = true;\n        parent = parent.parent;\n      }\n    });\n\n    this.nodes = nodes;\n    this.lookupMap = lm;\n\n    this.changeDetectorRef.markForCheck();\n  }\n\n  /** Returns all actually selected IDs. */\n  private getIDs() {\n    let ids: string[] = [];\n\n    let collectIds = (n: TreeNode) => {\n      if (n.selected) {\n        // If the parent is selected we can ignore the\n        // childs because they must be selected as well.\n        ids.push(n.id);\n        return;\n      }\n\n      n.children.forEach(child => collectIds(child));\n    }\n\n    this.nodes.forEach(node => collectIds(node))\n\n    return ids;\n  }\n\n  updateNode(node: TreeNode, selected: boolean, updateChildren = true, updateParents = true, emit = true) {\n    if (node.selected === selected) {\n      // Nothing changed\n      return;\n    }\n\n    // update the node an all children\n    node.selected = selected;\n    if (updateChildren) {\n      node.children.forEach(child => this.updateNode(child, selected, true, false, false));\n    }\n\n    // if we have a parent we might need to update\n    // the parent as well.\n    if (!!node.parent && updateParents) {\n      if (selected) {\n        // if we are now selected we might need to \"select\" the\n        // parent if all children are selected now.\n        const hasUnselected = node.parent.children.some(sibling => !sibling.selected);\n        if (!hasUnselected) {\n          // We need to update all parents but updating children\n          // is useless.\n          this.updateNode(node.parent, true, false, true, false);\n        }\n      } else if (node.parent.selected) {\n        // if we are unselected now we might need to \"unselect\" the parent\n        // but select siblings directly\n        const selectedSiblings = node.parent.children.filter(sibling => sibling.selected && sibling !== node);\n        this.updateNode(node.parent, false, false, true, false)\n      }\n    }\n\n    if (emit) {\n      const ids = this.getIDs();\n      this.selectedIDs = ids;\n      this._onChange(this.selectedIDs);\n    }\n  }\n\n  /** @private TrackByFunction for tree nodes. */\n  trackNode(_: number, node: TreeNode) {\n    return node.id;\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/filter-lists/index.ts",
    "content": "export { FilterListComponent } from './filter-list';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/generic-setting/generic-setting.html",
    "content": "<div\n  class=\"relative flex flex-row flex-wrap items-center h-full px-5 py-5 bg-gray-200 border-l border-transparent rounded-r\"\n  [class.pr-8]=\"lockDefaults\" [ngClass]=\"{\n    'border-blue': enableActiveBorder && _setting?.Value !== undefined && !rejected,\n    'border-red': enableActiveBorder &&  rejected,\n    'border-yellow-300': selected,\n    'rounded-l': !rejected && _setting?.Value === undefined,\n    'hidden': selectMode && !userConfigured\n  }\">\n\n  <input class=\"absolute -left-5 my-auto\" type=\"checkbox\" *ngIf=\"selectMode && userConfigured\" [(ngModel)]=\"selected\"\n    (ngModelChange)=\"selectedChange.next($event)\">\n\n  <div class=\"flex flex-col flex-grow\">\n    <div class=\"flex flex-row items-center justify-start space-x-2 w-fit\" *ngIf=\"showHeader\">\n      <h3 [innerHTML]=\"setting?.Name | safe:'html'\" class=\"mb-0 name\"></h3>\n      <sfng-tipup *ngIf=\"setting?.Description\" [key]=\"setting!.Key\" [text]=\"setting?.Description\"\n        [buttons]=\"sfngTipUpButtons\" [title]=\"setting?.Name\"></sfng-tipup>\n\n      <span *ngIf=\"changeAccepted || restartPending || (changeAccepted && uiReloadRequired)\" (click)=\"restartNow()\"\n        class=\"px-1.5 py-0.5 border  rounded inline-flex justify-evenly items-center text-xxs mb-0.5\" [ngClass]=\"{\n          'border-green-300 text-green-300': !_setting?.RequiresRestart,\n          'border-yellow text-yellow cursor-pointer hover:bg-yellow hover:text-gray-200': _setting?.RequiresRestart\n        }\" [@fadeIn]>\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"inline-block w-4 h-4 mr-1\" viewBox=\"0 0 20 20\"\n          fill=\"currentColor\">\n          <path fill-rule=\"evenodd\"\n            d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n            clip-rule=\"evenodd\" />\n        </svg>\n\n        Saved {{ _setting?.RequiresRestart ? ' - Restart required' : (uiReloadRequired ? ' - Reload required' : '') }}\n      </span>\n\n      <span *ngIf=\"rejected\" (click)=\"abortChange()\"\n        class=\"px-1.5 py-0.5 border-red-300 border text-red-300 rounded inline-flex justify-evenly items-center text-xxs hover:bg-red hover:text-white mb-0.5 cursor-pointer\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"inline-block w-4 h-4 mr-1\" *ngIf=\"rejected\" fill=\"none\"\n          viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n            d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n        </svg>\n        Invalid Value: {{ rejected }}\n      </span>\n\n      <span *ngIf=\"_upgradeRequired\" (click)=\"openAccountDetails()\"\n        class=\"px-1.5 py-0.5 border-red-300 border text-red-300 rounded inline-flex justify-evenly items-center text-xxs hover:bg-red hover:text-white mb-0.5 cursor-pointer\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"inline-block w-4 h-4 mr-1\" fill=\"none\" viewBox=\"0 0 24 24\"\n          stroke=\"currentColor\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n            d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n        </svg>\n        This feature requires a subscription.\n      </span>\n    </div>\n\n    <span class=\"flex flex-row items-center justify-start space-x-2\" *ngIf=\"setting?.ReleaseLevel !== releaseLevel.Stable ||\n        setting?.ExpertiseLevel !== expertise.user ||\n        (expertiseLevel|async) === expertiseNames.Developer\">\n\n      <span class=\"inline-block px-1.5 py-0.5 bg-gray-400 rounded text-xxs text-secondary\"\n        *appExpertiseLevel=\"'developer'\">{{setting?.Key}}</span>\n\n      <span class=\"inline-block px-1.5 py-0.5 text-gray-100 bg-yellow-300 rounded text-xxs\"\n        *ngIf=\"setting?.ReleaseLevel === releaseLevel.Beta\">Beta</span>\n\n      <span class=\"inline-block px-1.5 py-0.5 text-white bg-red-300 rounded text-xxs\"\n        *ngIf=\"setting?.ReleaseLevel === releaseLevel.Experimental\">Experimental</span>\n\n      <span class=\"inline-block px-1.5 py-0.5 bg-gray-400 rounded text-xxs text-secondary\"\n        *ngIf=\"setting?.ExpertiseLevel === expertise.expert\">Advanced</span>\n\n      <span class=\"inline-block px-1.5 py-0.5 text-gray-100 bg-yellow-300 rounded text-xxs\"\n        *ngIf=\"setting?.ExpertiseLevel === expertise.developer\">Developer</span>\n\n    </span>\n  </div>\n\n\n  <!-- Quick Settings -->\n  <div *ngIf=\"(quickSettings || []).length > 0 && !disabled\">\n    <app-menu-trigger [menu]=\"quickSettingsMenu\" useContent=\"true\" class=\"text-secondary hover:text-primary\">\n      <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"inline-block w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\"\n        stroke=\"currentColor\">\n        <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n          d=\"M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4\" />\n      </svg>\n      <span class=\"ml-1 text-xs\">Quick Settings</span>\n    </app-menu-trigger>\n\n    <app-menu #quickSettingsMenu>\n      <app-menu-item *ngFor=\"let quick of quickSettings\" (click)=\"applyQuickSetting(quick)\">\n        {{quick.Name}}\n      </app-menu-item>\n    </app-menu>\n  </div>\n\n  <!-- Actual settings input -->\n  <ng-container [ngSwitch]=\"externalOptType(setting)\">\n\n    <!-- Rule lists -->\n    <ng-container *ngSwitchCase=\"optionHint.EndpointList\">\n      <app-rule-list class=\"w-full mt-4\" [readonly]=\"disabled\" [ngModel]=\"_currentValue\"\n        (ngModelChange)=\"updateValue($event, true)\" [symbolMap]=\"symbolMap\"></app-rule-list>\n\n      <div class=\"stacked-values\" *ngIf=\"showStackable\">\n        <h4>This setting stacks on top of the following <a class=\"underline text-tertiary hover:text-primary\"\n            routerLink=\"/settings\" [queryParams]=\"{setting: setting?.Key}\">global setting</a>:</h4>\n        <app-rule-list class=\"w-full mt-4\" [readonly]=\"true\" [symbolMap]=\"symbolMap\" [ngModel]=\"setting?.GlobalDefault\">\n        </app-rule-list>\n      </div>\n    </ng-container>\n\n    <!-- Filter lists -->\n    <ng-container *ngSwitchCase=\"optionHint.FilterList\">\n      <app-filter-list class=\"w-full\" [class.mt-4]=\"showHeader\" [ngModel]=\"_currentValue\"\n        (ngModelChange)=\"updateValue($event, true)\">\n      </app-filter-list>\n    </ng-container>\n\n    <!-- Ordered string lists -->\n    <ng-container *ngSwitchCase=\"optionHint.OrderedList\">\n      <app-ordered-list class=\"w-full mt-4\" [ngModel]=\"_currentValue\" (ngModelChange)=\"updateValue($event, true)\"\n        [readonly]=\"disabled\"></app-ordered-list>\n\n      <div class=\"stacked-values\" *ngIf=\"showStackable\">\n        <h4>This setting stacks on top of the following <a class=\"underline text-tertiary hover:text-primary\"\n            routerLink=\"/settings\" [queryParams]=\"{setting: setting?.Key}\">global setting</a>:</h4>\n        <app-ordered-list class=\"w-full mt-4\" [ngModel]=\"setting?.GlobalDefault\" [readonly]=\"true\"></app-ordered-list>\n      </div>\n    </ng-container>\n\n    <!-- Default if no display hint is given -->\n    <ng-container *ngSwitchDefault>\n      <!-- basic string array with fixed order on optional stacking -->\n      <ng-container *ngIf=\"setting?.OptType === optionType.StringArray; else: basicSetting\">\n        <app-ordered-list class=\"w-full mt-4\" fixedOrder=\"true\" [ngModel]=\"_currentValue\"\n          (ngModelChange)=\"updateValue($event, true)\" [readonly]=\"disabled\">\n        </app-ordered-list>\n\n        <div class=\"stacked-values\" *ngIf=\"showStackable\">\n          <h4>This setting stacks on top of the following <a class=\"underline text-tertiary hover:text-primary\"\n              routerLink=\"/settings\" [queryParams]=\"{setting: setting?.Key}\">global setting</a>:</h4>\n          <app-ordered-list class=\"w-full mt-4\" fixedOrder=\"true\" [ngModel]=\"setting?.GlobalDefault\" [readonly]=\"true\">\n          </app-ordered-list>\n        </div>\n      </ng-container>\n\n      <ng-template #basicSetting>\n        <!-- basic inputs -->\n        <app-basic-setting class=\"block\" [setting]=\"_setting\" [disabled]=\"disabled\" [ngModel]=\"_currentValue\"\n          (ngModelChange)=\"updateValue($event)\"\n          (blured)=\"updateValue(_basicSettingsValueCache!, _currentValue !== _basicSettingsValueCache)\">\n        </app-basic-setting>\n      </ng-template>\n    </ng-container>\n  </ng-container>\n\n  <span class=\"unlock-button\" [class.bg-blue]=\"!isLocked\" [class.bg-gray-500]=\"isLocked\" *ngIf=\"lockDefaults\"\n    snfgTooltipPosition=\"left\" [sfng-tooltip]=\"lockTooltip\" (click)=\"toggleLock()\">\n\n    <svg viewBox=\"0 0 24 24\" class=\"w-4 h-4 text-white\" stroke=\"currentColor\" *ngIf=\"isLocked\">\n      <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" class=\"inner\">\n        <path shape-rendering=\"geometricPrecision\"\n          d=\"M13.7678 10.2322c.976311.976311.976311 2.55922 0 3.53553-.976311.976311-2.55922.976311-3.53553 0-.976311-.976311-.976311-2.55922 0-3.53553.976311-.976311 2.55922-.976311 3.53553 0\" />\n        <path shape-rendering=\"geometricPrecision\"\n          d=\"M14.849 4.12l.583.194c.534.178.895.678.895 1.241v.837c0 .712.568 1.293 1.28 1.308l.838.018c.485.01.925.289 1.142.723l.275.55c.252.504.153 1.112-.245 1.51l-.592.592c-.503.503-.512 1.316-.02 1.83l.58.606c.336.351.45.858.296 1.319l-.194.583c-.178.534-.678.895-1.241.895h-.837c-.712 0-1.293.568-1.308 1.28l-.018.838c-.01.485-.289.925-.723 1.142l-.55.275c-.504.252-1.112.153-1.51-.245l-.592-.592c-.503-.503-1.316-.512-1.83-.02l-.606.58c-.351.336-.858.45-1.319.296l-.583-.194c-.534-.178-.895-.678-.895-1.241v-.837c0-.712-.568-1.293-1.28-1.308l-.838-.018c-.485-.01-.925-.289-1.142-.723l-.275-.55c-.252-.504-.153-1.112.245-1.51l.592-.592c.503-.503.512-1.316.02-1.83l-.58-.606c-.337-.352-.451-.86-.297-1.32l.194-.583c.178-.534.678-.895 1.241-.895h.837c.712 0 1.293-.568 1.308-1.28l.018-.838c.012-.485.29-.925.724-1.142l.55-.275c.504-.252 1.112-.153 1.51.245l.592.592c.503.503 1.316.512 1.83.02l.606-.58c.351-.335.859-.449 1.319-.295z\" />\n      </g>\n    </svg>\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"Layer 1\" viewBox=\"0 0 24 24\" class=\"w-4 h-4 text-white\"\n      fill=\"none\" stroke=\" currentColor\" *ngIf=\"!isLocked\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" fill=\"currentColor\"\n        d=\"M19 21h-3a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2Z\" />\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n        d=\"M19 9h-3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2ZM5 3h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2ZM5 15h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2Z\" />\n    </svg>\n  </span>\n\n  <ng-template #lockTooltip>\n    <ng-template [ngIf]=\"isLocked\" [ngIfElse]=\"unlockedTooltip\">\n      Inherited from <a [routerLink]=\"['/settings']\" [queryParams]=\"{setting: setting?.Key}\"\n        class=\"cursor-pointer hover:underline\">Global Settings</a>\n    </ng-template>\n    <ng-template #unlockedTooltip>\n      App specific configuration\n    </ng-template>\n  </ng-template>\n</div>\n\n<div *ngIf=\"userConfigured\" class=\"flex justify-end mt-2\" [@fadeIn] [@fadeOut]>\n  <span class=\"cursor-pointer text-tertiary hover:text-yellow\" tabindex=\"0\" (click)=\"resetValue()\">\n    {{resetLabelText}}\n  </span>\n</div>\n\n<ng-template #helpTemplate>\n  <div class=\"relative flex flex-col overflow-hidden max-w-1/3vw\">\n    <fa-icon class=\"absolute top-0 right-0 mt-2 mr-2 opacity-50 cursor-pointer hover:opacity\" icon=\"times\"\n      (click)=\"closeHelpDialog()\"></fa-icon>\n    <h1>{{ _setting?.Name }}</h1>\n\n    <markdown emoji [data]=\"_setting?.Help\" class=\"flex-grow block overflow-auto\"></markdown>\n  </div>\n</ng-template>"
  },
  {
    "path": "desktop/angular/src/app/shared/config/generic-setting/generic-setting.scss",
    "content": ":host {\n  @apply block;\n\n  &.ng-invalid {\n    @apply border border-red border-opacity-50;\n  }\n\n  &.rejected {\n    .release-level.rejected {\n      opacity: 1;\n    }\n  }\n\n  &.highlighted:not(.touched) {\n    .name {\n      animation: fade-color 5s ease-out;\n    }\n  }\n}\n\n.stacked-values {\n  margin-top: 0.5rem;\n  opacity: 0.7;\n  @apply w-full;\n}\n\n.unlock-button {\n  @apply flex w-6 h-6 rounded-full;\n\n  justify-content: center;\n  align-items: center;\n  cursor: pointer;\n\n  position: absolute;\n  right: calc(-1.5rem/2);\n  top: calc(50% - 1.5rem/2);\n\n  &:hover {\n    @apply bg-blue;\n  }\n}\n\n.description,\n.help-text {\n  display: block;\n  @apply text-secondary;\n}\n\n.help-text {\n  @apply mb-2;\n}\n\n.notice {\n  display: block;\n  padding-left: 0.5rem;\n  padding-right: 0.5rem;\n  @apply mb-4;\n  @apply text-secondary;\n\n  fa-icon {\n    @apply mr-2;\n  }\n}\n\n.help-text {\n  @apply p-4;\n  @apply bg-cards-secondary;\n  @apply rounded;\n\n  .toggle {\n    position: relative;\n    left: -0.25rem;\n    cursor: pointer;\n\n    fa-icon {\n      @apply pr-1;\n    }\n\n    &:hover {\n      @apply text-primary;\n    }\n  }\n}\n\n@keyframes fade-color {\n  0% {\n    @apply text-blue;\n  }\n\n  90% {\n    @apply text-blue;\n  }\n\n  100% {\n    @apply text-primary;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/generic-setting/generic-setting.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, EventEmitter, HostBinding, Input, OnInit, Output, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { NgModel } from '@angular/forms';\nimport { BaseSetting, ConfigService, ExpertiseLevel, ExpertiseLevelNumber, ExternalOptionHint, OptionType, PortapiService, QuickSetting, ReleaseLevel, SPNService, SettingValueType, UserProfile, WellKnown, applyQuickSetting } from '@safing/portmaster-api';\nimport { SfngDialogRef, SfngDialogService } from '@safing/ui';\nimport { Button } from 'js-yaml-loader!../../../i18n/helptexts.yaml';\nimport { Subject } from 'rxjs';\nimport { debounceTime, tap } from 'rxjs/operators';\nimport { ActionIndicatorService } from '../../action-indicator';\nimport { fadeInAnimation, fadeOutAnimation } from '../../animations';\nimport { ExpertiseService } from '../../expertise/expertise.service';\nimport { SPNAccountDetailsComponent } from '../../spn-account-details';\n\nexport interface SaveSettingEvent<S extends BaseSetting<any, any> = any> {\n  key: string;\n  value: SettingValueType<S>;\n  isDefault: boolean;\n  rejected?: (err: any) => void\n  accepted?: () => void\n}\n\n@Component({\n  selector: 'app-generic-setting',\n  templateUrl: './generic-setting.html',\n  exportAs: 'appGenericSetting',\n  styleUrls: ['./generic-setting.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation\n  ]\n})\nexport class GenericSettingComponent<S extends BaseSetting<any, any>> implements OnInit {\n  //\n  // Constants used in the template.\n  //\n\n  readonly optionHint = ExternalOptionHint;\n  readonly expertiseNames = ExpertiseLevel\n  readonly expertise = ExpertiseLevelNumber;\n  readonly optionType = OptionType;\n  readonly releaseLevel = ReleaseLevel;\n  readonly wellKnown = WellKnown;\n\n  @ViewChild('helpTemplate', { read: TemplateRef, static: true })\n  helpTemplate: TemplateRef<any> | null = null;\n  private helpDialogRef: SfngDialogRef<any> | null = null;\n\n  // Whether or not the user needs to upgrade his/her account before\n  // this setting is valid.\n  _upgradeRequired = false;\n\n  /**\n   * Whether or not the component/setting is disabled and should\n   * be read-only.\n   */\n  @Input()\n  @HostBinding('class.disabled')\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v);\n  }\n  get disabled() {\n    return this._disabled || this._upgradeRequired;\n  }\n  private _disabled: boolean = false;\n\n  /** Returns the symbolMap annoation for endpoint-lists */\n  get symbolMap() {\n    return this.setting?.Annotations[WellKnown.EndpointListVerdictNames] || {\n      '+': 'Allow',\n      '-': 'Block'\n    };\n  }\n\n  /** Whether or not the setting should be in select mode */\n  @Input()\n  set selectMode(v: any) {\n    this._selectMode = coerceBooleanProperty(v)\n\n    if (!this.selectMode) {\n      this.selected = false;\n      this.selectedChange.next(false);\n    }\n  }\n  get selectMode() { return this._selectMode }\n  private _selectMode = false;\n\n  /** Whether or not the setting has been selected */\n  @Input()\n  set selected(v: any) {\n    this._selected = coerceBooleanProperty(v)\n  }\n  get selected() { return this._selected }\n  private _selected = false;\n\n  /** Emits when the user (de-) selectes the setting. Can be used for two-way binding */\n  @Output()\n  selectedChange = new EventEmitter<boolean>();\n\n  /** Controls whether or not header with the setting name and success/failure markers is shown */\n  @Input()\n  set showHeader(v: any) {\n    this._showHeader = coerceBooleanProperty(v);\n  }\n  get showHeader() { return this._showHeader }\n  private _showHeader = true;\n\n  /** Controls whether or not the blue or red status borders are shown */\n  @Input()\n  set enableActiveBorder(v: any) {\n    this._enableActiveBorder = coerceBooleanProperty(v);\n  }\n  get enableActiveBorder() { return this._enableActiveBorder }\n  private _enableActiveBorder = true;\n\n  /**\n   * Whether or not the component should be displayed as \"locked\"\n   * when the default value is used (that is, no 'Value' property\n   * in the setting)\n   */\n  @Input()\n  set lockDefaults(v: any) {\n    this._lockDefaults = coerceBooleanProperty(v);\n  }\n  get lockDefaults() {\n    return this._lockDefaults;\n  }\n  private _lockDefaults: boolean = false;\n\n  /** The label to display in the reset-value button */\n  @Input()\n  resetLabelText = 'Reset';\n\n  /** Emits an event whenever the setting should be saved. */\n  @Output()\n  save = new EventEmitter<SaveSettingEvent<S>>();\n\n  /** Wether or not stackable values should be displayed. */\n  @Input()\n  set displayStackable(v: any) {\n    this._displayStackable = coerceBooleanProperty(v);\n  }\n  get displayStackable() {\n    return this._displayStackable;\n  }\n  private _displayStackable = false;\n\n  /**\n   * Whether or not the help text is currently shown\n   */\n  @Input()\n  set showHelp(v: any) {\n    this._showHelp = coerceBooleanProperty(v);\n  }\n  get showHelp() {\n    return this._showHelp;\n  }\n  private _showHelp = false;\n\n  /** Used internally to publish save events. */\n  private triggerSave = new Subject<void>();\n\n  /** Whether or not the value was reset. */\n  wasReset = false;\n\n  /** Whether or not a save request was rejected */\n  @HostBinding('class.rejected')\n  get rejected() {\n    return this._rejected;\n  }\n  private _rejected = null;\n\n  @HostBinding('class.saved')\n  get changeAccepted() {\n    return this._changeAccepted;\n  }\n  private _changeAccepted = false;\n\n  /**\n   * @private\n   * Returns the external option type hint from a setting.\n   *\n   * @param opt The setting for with to return the external option hint\n   */\n  externalOptType(opt: S | null): ExternalOptionHint | null {\n    return opt?.Annotations?.[WellKnown.DisplayHint] || null;\n  }\n\n  /**\n   * @private\n   * Returns whether or not a restart is pending for this setting\n   * to apply.\n   */\n  get restartPending(): boolean {\n    return !!this._setting?.Annotations?.[WellKnown.RestartPending];\n  }\n\n  /**\n   * @private\n   * Returns whether or not a UI reload is required for this setting\n   * to apply\n   */\n  get uiReloadRequired(): boolean {\n    return this._setting?.Annotations?.[WellKnown.RequiresUIReload] !== undefined;\n  }\n\n  /**\n   * Returns true if the setting has been touched (modified) by the user\n   * since the component has been rendered.\n   */\n  @HostBinding('class.touched')\n  get touched() {\n    return this._touched;\n  }\n  private _touched = false;\n\n  /**\n   * Returns true if the settings is currently locked.\n   */\n  @HostBinding('class.locked')\n  get isLocked() {\n    return (this.wasReset || !this.userConfigured) && this.lockDefaults;\n  }\n\n  /**\n   * Returns true if the user has configured the setting on their\n   * own or if the default value is being used.\n   */\n  @HostBinding('class.changed')\n  get userConfigured() {\n    return this.setting?.Value !== undefined;\n  }\n\n  /**\n   * Returns true if the setting is dirty. That is, the user\n   * has changed the setting in the view but it has not yet\n   * been saved.\n   */\n  @HostBinding('class.dirty')\n  get dirty() {\n    if (typeof this._currentValue !== 'object') {\n      return this._currentValue !== this._savedValue;\n    }\n    // JSON object (OptionType.StringArray) require will\n    // not be the same reference so we need to compare their\n    // string representations. That's a bit more costly but should\n    // still be fast enough.\n    // TODO(ppacher): calculate this only when required.\n    return JSON.stringify(this._currentValue) !== JSON.stringify(this._savedValue)\n  }\n\n  /**\n   * Returns true if the setting is pristine. That is, the\n   * settings default value is used and the user has not yet\n   * changed the value inside the view.\n   */\n  @HostBinding('class.pristine')\n  get pristine() {\n    return !this.dirty && !this.userConfigured\n  }\n\n  /** A list of buttons for the tip-up */\n  sfngTipUpButtons: Button[] = [];\n\n  /**\n   * Unlock the setting if it is locked. Unlocking will\n   * emit the default value to be safed for the setting.\n   */\n  unlock() {\n    if (!this.isLocked || !this.setting) {\n      return;\n    }\n\n    this._touched = true;\n    this.wasReset = false;\n    let value = this.defaultValue;\n\n    if (this.stackable) {\n      // TODO(ppacher): fix this one once string[] options can be\n      // stackable\n      value = [] as SettingValueType<S>;\n    }\n\n    this.updateValue(value, true);\n    // update the settings value now so the UI\n    // responds immediately.\n    this.setting!.Value = value;\n  }\n\n  /** True if the current setting is stackable */\n  get stackable() {\n    return !!this.setting?.Annotations[WellKnown.Stackable];\n  }\n\n  /** Wether or not stackable values should be shown right now */\n  get showStackable() {\n    return this.stackable && this.displayStackable;\n  }\n\n  /**\n   * @private\n   * Toggle Whether or not the help text is displayed\n   */\n  toggleHelp() {\n    this.showHelp = !this.showHelp;\n  }\n\n  /**\n   * @private\n   * Toggle Whether or not the setting is currently locked.\n   */\n  toggleLock() {\n    if (this.isLocked) {\n      this.unlock();\n      return;\n    }\n\n    this.resetValue();\n  }\n\n  /**\n   * @private\n   * Closes the help dialog.\n   */\n  closeHelpDialog() {\n    this.helpDialogRef?.close();\n  }\n\n  @ViewChild(NgModel, { static: false })\n  model: NgModel | null = null;\n\n  /**\n   * The actual setting that should be managed.\n   * The setter also updates the \"currently\" used\n   * value (which is either user configured or\n   * the default). See {@property userConfigured}.\n   */\n  @Input()\n  set setting(s: S | null) {\n    this.sfngTipUpButtons = [];\n\n    this._setting = s;\n    if (!s) {\n      this._currentValue = null;\n      return;\n    }\n\n    if (this._setting?.Help) {\n      this.sfngTipUpButtons = [\n        {\n          name: 'Show More',\n          action: {\n            ID: '',\n            Text: '',\n            Type: 'ui',\n            Visibility: '',\n            Run: async () => {\n              if (!this.helpTemplate) {\n                return;\n              }\n\n              // close any existing help dialog for THIS setting.\n              if (!!this.helpDialogRef) {\n                this.helpDialogRef.close();\n              }\n\n              // Create a new dialog form the helpTemplate\n              const portal = new TemplatePortal(this.helpTemplate, this.viewRef);\n              const ref = this.dialog.create(portal, {\n                // we don't use a backdrop and make the dialog dragable so the user can\n                // move it somewhere else and keep it open while configuring the setting.\n                backdrop: false,\n                dragable: true,\n              });\n\n              // make sure we reset the helpDialogRef to null once it get's clsoed.\n              this.helpDialogRef = ref;\n              this.helpDialogRef.onClose.subscribe(() => {\n                // but only if helpDialogRef still points to the same\n                // dialog reference. Otherwise we got closed because the user\n                // opened a new one and helpDialogRef already points to the new\n                // dialog.\n                if (this.helpDialogRef === ref) {\n                  this.helpDialogRef = null;\n                }\n              });\n            },\n            Payload: undefined,\n          },\n        },\n      ]\n    }\n    this.updateActualValue();\n  }\n  get setting(): S | null {\n    return this._setting;\n  }\n\n  /**\n   * The defaultValue input allows to overwrite the default\n   * value of the setting.\n   */\n  @Input()\n  set defaultValue(val: SettingValueType<S>) {\n    this._defaultValue = val;\n    this.updateActualValue();\n  }\n\n  get defaultValue() {\n    // Return cached value.\n    if (this._defaultValue !== null) {\n      return this._defaultValue;\n    }\n\n    // Stackable options are displayed differently.\n    if (this.stackable) {\n      if (this.setting?.GlobalDefault === undefined && this.setting?.DefaultValue !== null) {\n        return this.setting?.DefaultValue;\n      }\n      return [] as SettingValueType<S>;\n    }\n\n    // Return global, then default value.\n    if (this.setting?.GlobalDefault !== undefined) {\n      return this.setting.GlobalDefault\n    }\n    return this.setting?.DefaultValue\n  }\n\n  /* An optional default value overwrite */\n  _defaultValue: SettingValueType<S> | null = null;\n\n  /* Whether or not the setting has been saved */\n  saved = true;\n\n  /* The settings value, updated by the setting() setter */\n  _setting: S | null = null;\n\n  /* The currently configured value. Updated by the setting() setter */\n  _currentValue: SettingValueType<S> | null = null;\n\n  /* The currently saved value. Updated by the setting() setter */\n  _savedValue: SettingValueType<S> | null = null;\n\n  /* Used to cache the value of a basic-setting because we only want to save that on blur */\n  _basicSettingsValueCache: SettingValueType<S> | null = null\n\n  /** Whether or not the network rating system is enabled. */\n  networkRatingEnabled$ = this.configService.networkRatingEnabled$;\n\n  get expertiseLevel() {\n    return this.expertiseService.change;\n  }\n\n  constructor(\n    private expertiseService: ExpertiseService,\n    private configService: ConfigService,\n    private portapi: PortapiService,\n    private dialog: SfngDialogService,\n    private changeDetectorRef: ChangeDetectorRef,\n    private actionIndicator: ActionIndicatorService,\n    private spn: SPNService,\n    private viewRef: ViewContainerRef,\n    private destryoRef: DestroyRef,\n  ) { }\n\n  ngOnInit() {\n    this.triggerSave\n      .pipe(\n        debounceTime(500),\n        takeUntilDestroyed(this.destryoRef),\n      )\n      .subscribe(() => this.emitSaveRequest())\n\n    // watch the SPN user profile so we know which feature_ids\n    // are available for the user.\n    this.spn.profile$\n      .pipe(takeUntilDestroyed(this.destryoRef))\n      .subscribe((profile: UserProfile | null) => {\n        let value = this.setting?.Annotations[WellKnown.RequiresFeatureID]\n        if (value === undefined) {\n          this._upgradeRequired = false;\n        } else {\n          if (!Array.isArray(value)) {\n            value = [value];\n          }\n\n          this._upgradeRequired = value.some(val => !(profile?.current_plan?.feature_ids || []).includes(val))\n        }\n\n        this.changeDetectorRef.markForCheck();\n      })\n  }\n\n  /**\n   * @private\n   * Resets the value of setting by discarding any user\n   * configured values and reverting back to the default\n   * value.\n   */\n  resetValue() {\n    if (!this._setting) {\n      return;\n    }\n    this._touched = true;\n\n    this._currentValue = this.defaultValue;\n    this.wasReset = true;\n\n    this.triggerSave.next();\n  }\n\n  /**\n   * @private\n   * Aborts/reverts the current change to the value that's\n   * already saved.\n   */\n  abortChange() {\n    this._currentValue = this._savedValue;\n    this._touched = true;\n    this._rejected = null;\n  }\n\n  /**\n   * @private\n   * Update the current value by applying a quick-setting.\n   *\n   * @param qs The quick-settting to apply\n   */\n  applyQuickSetting(qs: QuickSetting<SettingValueType<S>>) {\n    if (this.disabled) {\n      return;\n    }\n\n    const value = applyQuickSetting(this._currentValue, qs);\n    if (value === null) {\n      return;\n    }\n\n    this.updateValue(value, true);\n  }\n\n  openAccountDetails() {\n    this.dialog.create(SPNAccountDetailsComponent, {\n      autoclose: true,\n      backdrop: 'light'\n    })\n  }\n\n  restartNow() {\n    if (this._setting?.RequiresRestart) {\n      this.dialog.confirm({\n        header: 'Restart Portmaster',\n        message: 'Do you want to restart the Portmaster now?',\n        buttons: [\n          {\n            id: 'no',\n            text: 'Maybe Later',\n            class: 'outline',\n          },\n          {\n            id: 'restart',\n            text: 'Restart',\n            class: 'danger'\n          }\n        ]\n      })\n        .onAction('restart', () =>\n          this.portapi.restartPortmaster()\n            .subscribe(this.actionIndicator.httpObserver(\n              'Restarting ...',\n              'Failed to Restart',\n            ))\n        )\n        .onAction('no', () => {\n          this._changeAccepted = false;\n          this.changeDetectorRef.markForCheck();\n        });\n\n      return;\n    }\n\n    if (this.uiReloadRequired) {\n      this.portapi.reloadUI()\n        .pipe(\n          tap(() => {\n            setTimeout(() => window.location.reload(), 1000)\n          })\n        )\n        .subscribe(this.actionIndicator.httpObserver(\n          'Reloading UI ...',\n          'Failed to Reload UI',\n        ))\n    }\n  }\n\n  /**\n   * Emits a save request to the parent component.\n   */\n  private _saveInterval: any;\n  private emitSaveRequest() {\n    const isDefault = this.wasReset;\n    let value = this._setting!['Value'];\n\n    if (isDefault) {\n      delete (this._setting!['Value']);\n    } else {\n      this._setting!.Value = this._currentValue;\n    }\n\n\n    let wasReset = this.wasReset;\n    this.wasReset = false;\n    this._rejected = null;\n    this._changeAccepted = false;\n    if (!!this._saveInterval) {\n      clearTimeout(this._saveInterval);\n    }\n\n    this.save.next({\n      key: this.setting!.Key,\n      isDefault: isDefault,\n      value: this._setting!.Value,\n      rejected: (err: any) => {\n        this._setting!['Value'] = value;\n        this._rejected = err;\n        this.changeDetectorRef.markForCheck();\n      },\n      accepted: () => {\n        if (!wasReset) {\n          this._changeAccepted = true;\n          // if no restart is required fade the \"✔️ Saved\" out after\n          // a few seconds.\n          if (!this._setting?.RequiresRestart) {\n            this._saveInterval = setTimeout(() => {\n              this._changeAccepted = false;\n              this._saveInterval = null;\n              this.changeDetectorRef.markForCheck();\n            }, 4000);\n          }\n        }\n\n        this.changeDetectorRef.markForCheck();\n\n      }\n    })\n  }\n\n  /**\n   * @private\n   * Used in our view as a ngModelChange callback to\n   * update the value.\n   *\n   * @param value The new value as emitted by the view\n   */\n  updateValue(value: SettingValueType<S>, save = false) {\n    this._touched = true;\n\n    this._changeAccepted = false;\n    this._rejected = null;\n    if (!!this._saveInterval) {\n      clearTimeout(this._saveInterval);\n    }\n\n    if (save) {\n\n      this._currentValue = value;\n      this.triggerSave.next();\n    } else {\n      this._basicSettingsValueCache = value;\n    }\n  }\n\n  /**\n   * @private\n   * A list of quick-settings available for the setting.\n   * The getter makes sure to always return an array.\n   */\n  get quickSettings(): QuickSetting<SettingValueType<S>>[] {\n    if (!this.setting || !this.setting.Annotations[WellKnown.QuickSetting]) {\n      return [];\n    }\n\n    const quickSettings = this.setting.Annotations[WellKnown.QuickSetting]!;\n\n    return Array.isArray(quickSettings)\n      ? quickSettings\n      : [quickSettings];\n  }\n\n  /**\n   * Determine the current, actual value of the setting\n   * by taking the settings Value, default Value or global\n   * default into account.\n   */\n  private updateActualValue() {\n    if (!this.setting) {\n      return\n    }\n\n    this.wasReset = false;\n\n    const s = this.setting;\n\n    const value = s.Value === undefined\n      ? this.defaultValue\n      : s.Value;\n\n\n    this._currentValue = value;\n    this._savedValue = value;\n    this._basicSettingsValueCache = value;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/generic-setting/index.ts",
    "content": "export * from './generic-setting';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/import-dialog/cursor.ts",
    "content": "// Credit to Liam (Stack Overflow)\n// https://stackoverflow.com/a/41034697/3480193\nexport class Cursor {\n  static getCurrentCursorPosition(parentElement: Node) {\n    var selection = window.getSelection(),\n      charCount = -1,\n      node;\n\n    if (selection?.focusNode) {\n      if (Cursor._isChildOf(selection.focusNode, parentElement)) {\n        node = selection.focusNode;\n        charCount = selection.focusOffset;\n\n        while (node) {\n          if (node === parentElement) {\n            break;\n          }\n\n          if (node.previousSibling) {\n            node = node.previousSibling;\n            charCount += node.textContent?.length || 0\n          } else {\n            node = node.parentNode;\n            if (node === null) {\n              break;\n            }\n          }\n        }\n      }\n    }\n\n    return charCount;\n  }\n\n  static setCurrentCursorPosition(chars: number, element: Node) {\n    if (chars >= 0) {\n      var selection = window.getSelection();\n\n      let range = Cursor._createRange(element, { count: chars });\n\n      if (range) {\n        range.collapse(false);\n        selection?.removeAllRanges();\n        selection?.addRange(range);\n      }\n    }\n  }\n\n  static _createRange(node: Node, chars: { count: number }, range?: Range): Range {\n    if (!range) {\n      range = document.createRange()\n      range.selectNode(node);\n      range.setStart(node, 0);\n    }\n\n    if (chars.count === 0) {\n      range.setEnd(node, chars.count);\n    } else if (node && chars.count > 0) {\n      if (node.nodeType === Node.TEXT_NODE) {\n        if (node.textContent!.length < chars.count) {\n          chars.count -= node.textContent!.length;\n        } else {\n          range.setEnd(node, chars.count);\n          chars.count = 0;\n        }\n      } else {\n        for (var lp = 0; lp < node.childNodes.length; lp++) {\n          range = Cursor._createRange(node.childNodes[lp], chars, range);\n\n          if (chars.count === 0) {\n            break;\n          }\n        }\n      }\n    }\n\n    return range;\n  }\n\n  static _isChildOf(node: Node, parentElement: Node) {\n    while (node !== null) {\n      if (node === parentElement) {\n        return true;\n      }\n      node = node.parentNode!;\n    }\n\n    return false;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/import-dialog/import-dialog.component.html",
    "content": "<header class=\"flex flex-row justify-between items-center mb-2\">\n  <h1 class=\"m-0 text-sm font-light\">\n    Import {{ dialogRef.data.type === \"setting\" ? \"Settings\" : \"Profile\" }}\n  </h1>\n\n  <svg role=\"img\" aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"\n    class=\"w-3 h-3 cursor-pointer text-secondary hover:text-primary\" (click)=\"dialogRef.close()\">\n    <path fill=\"currentColor\"\n      d=\"M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z\">\n    </path>\n  </svg>\n</header>\n\n<span class=\"text-xs font-light\">Please paste the \"Export Content\" or use \"Choose File\" to select one from\n  your hard disk.</span>\n\n<pre tabindex=\"0\" class=\"block flex-grow w-full rounded border border-gray-500 language-yaml overflow-auto outline-none\"\n  #codeBlock id=\"yaml\" contenteditable=\"true\" (blur)=\"onBlur()\" (mouseleave)=\"onBlur()\" (paste)=\"onPaste($event)\"></pre>\n\n<fieldset class=\"p-2 text-xs font-light bg-gray-400 rounded border border-gray-500 border-solid\">\n  <legend class=\"px-2 py-1 m-0 text-xs w-fit\">Configuration</legend>\n\n  <div class=\"p-2 space-y-2\">\n    <div class=\"flex flex-row gap-2\" *ngIf=\"dialogRef.data.type === 'setting'\">\n      <input type=\"checkbox\" [(ngModel)]=\"reset\" id=\"reset\" />\n      <label class=\"text-primary\" for=\"reset\">Reset all settings to default before importing</label>\n    </div>\n\n    <div class=\"flex flex-row gap-2\" *ngIf=\"result?.containsUnknown\">\n      <input type=\"checkbox\" id=\"allowUnknown\" [(ngModel)]=\"allowUnknown\" />\n      <label class=\"text-primary\" for=\"allowUnknown\">Allow unknown settings</label>\n    </div>\n\n    <!-- Replacing existing profile must be explicitly accepted for profile (but not for settings...) -->\n    <div class=\"flex flex-row gap-2\" *ngIf=\"result?.replacesExisting && dialogRef.data.type === 'profile'\">\n      <input type=\"checkbox\" id=\"allowUnknown\" [(ngModel)]=\"allowReplace\" />\n      <label class=\"text-primary\" for=\"allowUnknown\">Allow replacing an existing profile</label>\n    </div>\n\n    <div class=\"flex flex-row gap-2\" *ngIf=\"result?.restartRequired\">\n      <input type=\"checkbox\" id=\"restart\" [(ngModel)]=\"triggerRestart\" />\n      <label class=\"text-primary\" for=\"restart\">Automatically restart Portmaster after a successfull import</label>\n    </div>\n  </div>\n</fieldset>\n\n<fieldset class=\"p-2 text-xs font-light bg-gray-400 rounded border border-gray-500 border-solid\" *ngIf=\"\n    errorMessage ||\n    (result &&\n      (result.containsUnknown ||\n        result.replacesExisting ||\n        result.restartRequired))\n  \">\n  <legend class=\"px-2 py-1 m-0 text-xs w-fit\">Warning</legend>\n\n  <div *ngIf=\"!!errorMessage\" class=\"flex flex-row gap-2 items-center p-2 w-full text-xs font-normal\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-6 h-6 text-red\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z\" />\n    </svg>\n    <span>{{ errorMessage }}</span>\n  </div>\n\n  <ul *ngIf=\"result\" class=\"px-2 py-2 pl-7 list-disc\">\n    <li *ngIf=\"result.containsUnknown\">\n      This export contains unknown settings. To import it, you must enable\n      \"Allow unknown settings\".\n    </li>\n\n    <li *ngIf=\"result.replacesExisting\">\n      {{\n      dialogRef.data.type === \"setting\"\n      ? \"This export will overwrite settings that have been changed by you.\"\n      : \"This export will overwrite an existing profile.\"\n      }}\n\n      <ng-container *ngIf=\"replacedProfiles.length as count\">\n        And deletes {{ count }} previously merged profile{{ count > 1 ? 's' : '' }}\n      </ng-container>\n    </li>\n\n    <li *ngIf=\"result.restartRequired\">\n      This export will require a restart of the Portmaster to take effect.\n    </li>\n  </ul>\n</fieldset>\n\n<div class=\"flex flex-row justify-between\">\n  <button>\n    <label class=\"block\" for=\"avatarInput\"> Choose File </label>\n  </button>\n\n  <button class=\"text-white bg-blue\" (click)=\"import()\" [disabled]=\"!result\">\n    Import\n  </button>\n</div>\n\n<input name=\"avatarInput\" id=\"avatarInput\" class=\"!hidden\" type=\"file\" (change)=\"loadFile($event)\" />"
  },
  {
    "path": "desktop/angular/src/app/shared/config/import-dialog/import-dialog.component.ts",
    "content": "import {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  ViewChild,\n  inject,\n} from '@angular/core';\nimport { ImportResult, PortapiService, ProfileImportResult } from '@safing/portmaster-api';\nimport { SFNG_DIALOG_REF, SfngDialogRef } from '@safing/ui';\nimport { ActionIndicatorService } from '../../action-indicator';\nimport { getSelectionOffset, setSelectionOffset } from './selection';\nimport { Observable } from 'rxjs';\n\nexport interface ImportConfig {\n  key: string;\n  type: 'setting' | 'profile';\n}\n\n@Component({\n  templateUrl: './import-dialog.component.html',\n  styles: [\n    `\n      :host {\n        @apply flex flex-col gap-2 overflow-hidden;\n        min-height: 24rem;\n        min-width: 24rem;\n        max-height: 40rem;\n        max-width: 40rem;\n      }\n    `,\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ImportDialogComponent {\n  readonly dialogRef: SfngDialogRef<\n    ImportDialogComponent,\n    unknown,\n    ImportConfig\n  > = inject(SFNG_DIALOG_REF);\n\n  private readonly portapi = inject(PortapiService);\n  private readonly uai = inject(ActionIndicatorService);\n  private readonly cdr = inject(ChangeDetectorRef);\n\n  @ViewChild('codeBlock', { static: true, read: ElementRef })\n  codeBlockElement!: ElementRef<HTMLElement>;\n\n  result: ImportResult | ProfileImportResult | null = null;\n  reset = false;\n  allowUnknown = false;\n  triggerRestart = false;\n  allowReplace = false;\n\n  get replacedProfiles() {\n    if (this.result === null) {\n      return []\n    }\n\n    if ('replacesProfiles' in this.result) {\n      return this.result.replacesProfiles || [];\n    }\n\n    return [];\n  }\n\n  errorMessage: string = '';\n\n  get scope() {\n    return this.dialogRef.data;\n  }\n\n  onBlur() {\n    const text = this.codeBlockElement.nativeElement.innerText;\n    this.updateAndValidate(text);\n  }\n\n  onPaste(event: ClipboardEvent) {\n    event.stopPropagation();\n    event.preventDefault();\n\n    // Get pasted data via clipboard API\n    const clipboardData = event.clipboardData || (window as any).clipboardData;\n    const text = clipboardData.getData('Text');\n\n    this.updateAndValidate(text);\n  }\n\n  import() {\n    const text = this.codeBlockElement.nativeElement.innerText;\n\n    let saveFunc: Observable<ImportResult>;\n\n    if (this.dialogRef.data.type === 'setting') {\n      saveFunc = this.portapi.importSettings(\n        text,\n        this.dialogRef.data.key,\n        'text/yaml',\n        this.reset,\n        this.allowUnknown\n      );\n    } else {\n      saveFunc = this.portapi.importProfile(\n        text,\n        'text/yaml',\n        this.reset,\n        this.allowUnknown,\n        this.allowReplace\n      );\n    }\n\n    saveFunc.subscribe({\n      next: (result) => {\n        let msg = '';\n        if (result.restartRequired) {\n          if (this.triggerRestart) {\n            this.portapi.restartPortmaster().subscribe();\n            msg = 'Portmaster will be restarted now.';\n          } else {\n            msg = 'Please restart Portmaster to apply the new settings.';\n          }\n        }\n\n        this.uai.success('Settings Imported Successfully', msg);\n        this.dialogRef.close();\n      },\n      error: (err) => {\n        this.uai.error(\n          'Failed To Import Settings',\n          this.uai.getErrorMessgae(err)\n        );\n      },\n    });\n  }\n\n  updateAndValidate(content: string) {\n    const [start, end] = getSelectionOffset(\n      this.codeBlockElement.nativeElement\n    );\n\n    const p = (window as any).Prism;\n    const blob = p.highlight(content, p.languages.yaml, 'yaml');\n    this.codeBlockElement.nativeElement.innerHTML = blob;\n\n    setSelectionOffset(this.codeBlockElement.nativeElement, start, end);\n\n    if (content === '') {\n      return;\n    }\n\n    window.getSelection()?.removeAllRanges();\n\n    let validateFunc: Observable<ImportResult>;\n\n    if (this.dialogRef.data.type === 'setting') {\n      validateFunc = this.portapi.validateSettingsImport(\n        content,\n        this.dialogRef.data.key,\n        'text/yaml'\n      );\n    } else {\n      validateFunc = this.portapi.validateProfileImport(content, 'text/yaml');\n    }\n\n    validateFunc.subscribe({\n      next: (result) => {\n        this.result = result;\n        this.errorMessage = '';\n\n        this.cdr.markForCheck();\n      },\n      error: (err) => {\n        const msg = this.uai.getErrorMessgae(err);\n        this.errorMessage = msg;\n        this.result = null;\n\n        this.cdr.markForCheck();\n      },\n    });\n  }\n\n  loadFile(event: Event) {\n    const file: File = (event.target as any).files[0];\n    if (!file) {\n      this.updateAndValidate('');\n\n      return;\n    }\n\n    const reader = new FileReader();\n\n    reader.onload = (data) => {\n      (event.target as any).value = '';\n\n      let content = (data.target as any).result;\n      this.updateAndValidate(content);\n    };\n\n    reader.readAsText(file);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/import-dialog/selection.ts",
    "content": "/** return true if node found */\nfunction searchNode(\n  container: Node,\n  startNode: Node,\n  predicate: (node: Node) => boolean,\n  excludeSibling?: boolean,\n): boolean {\n  if (predicate(startNode as Text)) {\n    return true\n  }\n\n  for (let i = 0, len = startNode.childNodes.length; i < len; i++) {\n    if (searchNode(startNode, startNode.childNodes[i], predicate, true)) {\n      return true\n    }\n  }\n\n  if (!excludeSibling) {\n    let parentNode = startNode\n    while (parentNode && parentNode !== container) {\n      let nextSibling = parentNode.nextSibling\n      while (nextSibling) {\n        if (searchNode(container, nextSibling, predicate, true)) {\n          return true\n        }\n        nextSibling = nextSibling.nextSibling\n      }\n      parentNode = parentNode.parentNode!\n    }\n  }\n\n  return false\n}\n\nfunction createRange(container: Node, start: number, end: number): Range {\n  let startNode: any;\n\n  searchNode(container, container, node => {\n    if (node.nodeType === Node.TEXT_NODE) {\n      const dataLength = (node as Text).data.length\n      if (start <= dataLength) {\n        startNode = node\n        return true\n      }\n      start -= dataLength\n      end -= dataLength\n    }\n\n    return false\n  })\n\n  let endNode: any;\n\n  if (startNode) {\n    searchNode(container, startNode, node => {\n      if (node.nodeType === Node.TEXT_NODE) {\n        const dataLength = (node as Text).data.length\n        if (end <= dataLength) {\n          endNode = node\n          return true\n        }\n        end -= dataLength\n      }\n\n      return false\n    })\n  }\n\n  const range = document.createRange()\n  if (startNode) {\n    if (start < startNode.data.length) {\n      range.setStart(startNode, start)\n    } else {\n      range.setStartAfter(startNode)\n    }\n  } else {\n    if (start === 0) {\n      range.setStart(container, 0)\n    } else {\n      range.setStartAfter(container)\n    }\n  }\n\n  if (endNode) {\n    if (end < endNode.data.length) {\n      range.setEnd(endNode, end)\n    } else {\n      range.setEndAfter(endNode)\n    }\n  } else {\n    if (end === 0) {\n      range.setEnd(container, 0)\n    } else {\n      range.setEndAfter(container)\n    }\n  }\n\n  return range\n}\n\nexport function setSelectionOffset(node: Node, start: number, end: number) {\n  const range = createRange(node, start, end)\n  const selection = window.getSelection()!\n  selection.removeAllRanges()\n  selection.addRange(range)\n}\n\n\nfunction getAbsoluteOffset(container: Node, offset: number) {\n  if (container.nodeType === Node.TEXT_NODE) {\n    return offset\n  }\n\n  let absoluteOffset = 0\n  for (let i = 0, len = Math.min(container.childNodes.length, offset); i < len; i++) {\n    const childNode = container.childNodes[i]\n    searchNode(childNode, childNode, node => {\n      if (node.nodeType === Node.TEXT_NODE) {\n        absoluteOffset += (node as Text).data.length\n      }\n      return false\n    })\n  }\n\n  return absoluteOffset\n}\n\nexport function getSelectionOffset(container: Node): [number, number] {\n  let start = 0\n  let end = 0\n\n  const selection = window.getSelection()!\n  for (let i = 0, len = selection.rangeCount; i < len; i++) {\n    const range = selection.getRangeAt(i)\n    if (range.intersectsNode(container)) {\n      const startNode = range.startContainer\n      searchNode(container, container, node => {\n        if (startNode === node) {\n          start += getAbsoluteOffset(node, range.startOffset)\n          return true\n        }\n\n        const dataLength = node.nodeType === Node.TEXT_NODE\n          ? (node as Text).data.length\n          : 0\n\n        start += dataLength\n        end += dataLength\n\n        return false\n      })\n\n      const endNode = range.endContainer\n      searchNode(container, startNode, node => {\n        if (endNode === node) {\n          end += getAbsoluteOffset(node, range.endOffset)\n          return true\n        }\n\n        const dataLength = node.nodeType === Node.TEXT_NODE\n          ? (node as Text).data.length\n          : 0\n\n        end += dataLength\n\n        return false\n      })\n\n      break\n    }\n  }\n\n  return [start, end]\n}\n\nexport function getInnerText(container: Node): string {\n  const buffer: any = []\n  searchNode(container, container, node => {\n    if (node.nodeType === Node.TEXT_NODE) {\n      buffer.push((node as Text).data)\n    }\n    return false\n  })\n  return buffer.join('')\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/index.ts",
    "content": "export * from './basic-setting';\nexport * from './config-settings';\nexport * from './config.module';\nexport * from './filter-lists';\nexport * from './generic-setting';\nexport * from './ordererd-list';\nexport * from './rule-list';\nexport * from './safe.pipe';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/ordererd-list/index.ts",
    "content": "export { OrderedListComponent } from './ordered-list';\nexport { OrderedListItemComponent } from './item';"
  },
  {
    "path": "desktop/angular/src/app/shared/config/ordererd-list/item.html",
    "content": "<div class=\"value\" [class.edit]=\"_edit\">\n  <span *ngIf=\"!_edit; else: editValue\" class=\"flex-grow\">\n    {{value}}\n  </span>\n\n  <ng-template #editValue>\n    <input type=\"text\" [(ngModel)]=\"_value\">\n  </ng-template>\n\n  <div class=\"buttons\" *ngIf=\"!readonly\">\n    <fa-icon [icon]=\"_edit ? 'check' : 'edit'\" (click)=\"toggleEdit()\"></fa-icon>\n    <fa-icon icon=\"times\" (click)=\"reset()\"></fa-icon>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/ordererd-list/item.scss",
    "content": ":host {\n  @apply flex outline-none;\n  @apply space-x-2;\n\n  &>* {\n    @apply rounded;\n    @apply bg-gray-300;\n  }\n}\n\ndiv.value {\n  @apply border-gray-500 border;\n  @apply p-1;\n  @apply px-2;\n\n  &.edit {\n    @apply p-0;\n    @apply bg-gray-400;\n\n    input {\n      margin: 0;\n      width: auto;\n      flex-grow: 1;\n      border: none;\n      @apply shadow-none;\n    }\n\n    input:focus+.buttons {\n      @apply bg-gray-500 border-gray-600 bg-opacity-75 border-opacity-75;\n    }\n  }\n\n  flex-grow : 1;\n  display : flex;\n  justify-content: space-between;\n  align-items : center;\n\n  .buttons {\n    flex-shrink: 0;\n    height: 100%;\n    width: 4rem;\n    @apply flex items-center justify-evenly;\n\n    fa-icon {\n      cursor: pointer;\n      @apply text-primary;\n      @apply p-1;\n      opacity: 0.7;\n      font-size: 0.6rem;\n\n      &:hover {\n        opacity: 1;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/ordererd-list/item.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\n\n@Component({\n  selector: 'app-ordered-list-item',\n  templateUrl: './item.html',\n  styleUrls: ['./item.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class OrderedListItemComponent implements OnInit {\n  @Input()\n  set readonly(v: any) {\n    this._readonly = coerceBooleanProperty(v);\n  }\n  get readonly() {\n    return this._readonly;\n  }\n  private _readonly = false;\n\n  @Input()\n  set value(v: string) {\n    this._value = v;\n    this._savedValue = v;\n  }\n  get value() {\n    return this._value;\n  }\n  _value = '';\n\n  private _savedValue = '';\n\n  @Output()\n  readonly valueChange = new EventEmitter<string>();\n\n  @Output()\n  readonly delete = new EventEmitter<void>();\n\n  @Input()\n  set edit(v: any) {\n    this._edit = coerceBooleanProperty(v);\n  }\n  get edit() {\n    return this._edit;\n  }\n  _edit = false;\n\n  @Output()\n  readonly editChange = new EventEmitter<boolean>();\n\n  ngOnInit() {\n    if (this._value === '' && this._savedValue === '') {\n      this.edit = true;\n    }\n  }\n\n  toggleEdit() {\n    const wasEdit = this._edit;\n    this._edit = !wasEdit;\n    this.editChange.next(this._edit);\n\n    if (!wasEdit) {\n      return;\n    }\n\n    if (this._value !== this._savedValue) {\n      this._value = this._value.trim()\n\n      this.valueChange.next(this.value);\n      this._savedValue = this._value;\n    }\n    this.changeDetectorRef.markForCheck();\n  }\n\n  reset() {\n    if (this._edit) {\n      if (this._value !== '' || this._savedValue !== '') {\n        this._value = this._savedValue;\n        this.changeDetectorRef.markForCheck();\n        return;\n      }\n    }\n\n    this.delete.next();\n  }\n\n  constructor(private changeDetectorRef: ChangeDetectorRef) { }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/ordererd-list/ordered-list.html",
    "content": "<div class=\"list-items\" cdkDropList (cdkDropListDropped)=\"drop($event)\">\n  <div class=\"item\" *ngFor=\"let entry of entries; let index=index; trackBy: trackBy\" cdkDrag\n    [cdkDragDisabled]=\"readonly || fixedOrder\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5 mr-2 text-secondary\" fill=\"none\" viewBox=\"0 0 24 24\"\n      stroke=\"currentColor\" cdkDragHandle [class.opacity-0]=\"readonly || fixedOrder\"\n      [class.cusor-move]=\"!readonly && !fixedOrder\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 9l4-4 4 4m0 6l-4 4-4-4\" />\n    </svg>\n    <app-ordered-list-item [readonly]=\"readonly\" [value]=\"entry\" (valueChange)=\"updateValue(index, $event)\"\n      (delete)=\"deleteEntry(index)\">\n    </app-ordered-list-item>\n  </div>\n</div>\n\n<div class=\"button-list\" *ngIf=\"!readonly\">\n  <button class=\"new-entry\" (click)=\"addEntry()\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n      <path fill-rule=\"evenodd\"\n        d=\"M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z\" clip-rule=\"evenodd\" />\n    </svg>\n    <span>Add</span>\n  </button>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/ordererd-list/ordered-list.scss",
    "content": ":host {\n  outline: none;\n}\n\n.item,\n.cdk-drag-preview {\n  display: flex;\n  align-items: center;\n  padding: 3px;\n\n  fa-icon {\n    cursor: pointer;\n    @apply text-tertiary;\n    @apply text-lg;\n    @apply mr-2;\n  }\n\n  app-ordered-list-item {\n    flex-grow: 1;\n  }\n}\n\n.cdk-drag-placeholder {\n  left: -4px;\n  padding: 1px;\n  padding-left: 4px;\n}\n\n// TODO(ppacher9): move this transition to a mixin\n.list-items.cdk-drop-list-dragging .list:not(.cdk-drag-placeholder) {\n  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.cdk-drag-preview {\n  left: -4px;\n  padding: 1px;\n  padding-left: 4px;\n}\n\n.button-list {\n  @apply mt-2;\n  @apply ml-8;\n}\n\n.new-entry {\n  position: relative;\n  cursor: pointer;\n  @apply w-full;\n  @apply rounded;\n  @apply p-1;\n  @apply border-2;\n  @apply border-dashed;\n  @apply border-buttons-light;\n  @apply bg-background;\n  @apply text-secondary;\n\n  span {\n    @apply font-medium;\n  }\n\n  fa-icon {\n    font-size: 1rem;\n  }\n\n  &:hover {\n    @apply text-primary;\n    @apply bg-cards-secondary;\n\n    span {\n      @apply text-primary;\n    }\n  }\n\n  display : flex;\n  align-items : center;\n  justify-content: center;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/ordererd-list/ordered-list.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostBinding, HostListener, Input } from \"@angular/core\";\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\n\n@Component({\n  selector: 'app-ordered-list',\n  templateUrl: './ordered-list.html',\n  styleUrls: ['./ordered-list.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => OrderedListComponent),\n      multi: true,\n    }\n  ]\n})\nexport class OrderedListComponent implements ControlValueAccessor {\n  @HostBinding('tabindex')\n  readonly tabindex = 0;\n\n  @HostListener('blur')\n  onBlur() {\n    this.onTouch();\n  }\n\n  @Input()\n  set readonly(v: any) {\n    this._readonly = coerceBooleanProperty(v);\n  }\n  get readonly() {\n    return this._readonly;\n  }\n  _readonly = false;\n\n  @Input()\n  set fixedOrder(v: any) {\n    this._fixedOrder = coerceBooleanProperty(v);\n  }\n  get fixedOrder() {\n    return this._fixedOrder;\n  }\n  private _fixedOrder = false;\n\n  entries: string[] = [];\n\n  constructor(private changeDetector: ChangeDetectorRef) { }\n\n  updateValue(index: number, newValue: string) {\n    // we need to make a new object copy here.\n    this.entries = [\n      ...this.entries,\n    ];\n\n    this.entries[index] = newValue;\n    this.onChange(this.entries);\n  }\n\n  deleteEntry(index: number) {\n    this.entries = [...this.entries];\n    this.entries.splice(index, 1);\n    this.onChange(this.entries);\n  }\n\n  addEntry() {\n    // if there's already one empty entry abort\n    if (this.entries.some(e => e.trim() === '')) {\n      return;\n    }\n\n    this.entries = [...this.entries];\n    this.entries.push('');\n    //this.onChange(this.entries);\n  }\n\n  writeValue(value: string[]) {\n    this.entries = value;\n\n    this.changeDetector.markForCheck();\n  }\n\n  onChange = (_: string[]): void => { };\n  registerOnChange(fn: (value: string[]) => void) {\n    this.onChange = fn;\n  }\n\n  onTouch = (): void => { };\n  registerOnTouched(fn: () => void) {\n    this.onTouch = fn;\n  }\n\n  drop(event: CdkDragDrop<string[]>) {\n    if (this._readonly) {\n      return;\n    }\n\n    // create a copy of the array\n    this.entries = [...this.entries];\n    moveItemInArray(this.entries, event.previousIndex, event.currentIndex);\n\n    this.changeDetector.markForCheck();\n    this.onChange(this.entries);\n  }\n\n  trackBy(idx: number, value: string) {\n    return `${value}`;\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/rule-list/index.ts",
    "content": "export * from './list-item';\nexport * from './rule-list';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/rule-list/list-item.html",
    "content": "<div class=\"flex items-center action justify-evenly\" [class.text-green-300]=\"isAllow\" [class.text-red]=\"isBlock\">\n  <ng-container *ngIf=\"!edit; else: selectAction\">\n    <span *ngIf=\"isAllow\">{{ symbolMap[\"+\"] }}</span>\n    <span *ngIf=\"isBlock\">{{ symbolMap[\"-\"] }}</span>\n  </ng-container>\n\n  <ng-template #selectAction>\n    <sfng-select [ngModel]=\"currentAction\" (ngModelChange)=\"setAction($event)\" mode=\"single\" dynamicValues=\"false\">\n      <sfng-select-item *sfngSelectValue=\"'+'\">{{ symbolMap[\"+\"] }}</sfng-select-item>\n      <sfng-select-item *sfngSelectValue=\"'-'\">{{ symbolMap[\"-\"] }}</sfng-select-item>\n    </sfng-select>\n  </ng-template>\n</div>\n<div class=\"value\" [class.edit]=\"edit\">\n  <ng-container *ngIf=\"!edit; else: editValue\">\n    {{ display }}\n  </ng-container>\n\n  <ng-template #editValue>\n    <input type=\"text\" [ngModel]=\"display\" (ngModelChange)=\"setEntity($event)\" (keydown.enter)=\"toggleEdit()\">\n  </ng-template>\n\n  <div class=\"buttons\" *ngIf=\"!readonly\">\n    <fa-icon [icon]=\"edit ? 'check' : 'edit'\" (click)=\"toggleEdit()\"></fa-icon>\n    <fa-icon *ngIf=\"edit\" icon=\"times\" (click)=\"reset()\"></fa-icon>\n    <input type=\"checkbox\" *ngIf=\"!edit\" [(ngModel)]=\"selected\" (ngModelChange)=\"selectedChange.next($event)\">\n  </div>\n\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/rule-list/list-item.scss",
    "content": ":host {\n  display: flex;\n  outline: none;\n  @apply space-x-2;\n\n  &>* {\n    @apply rounded;\n    @apply bg-gray-300;\n  }\n}\n\ndiv.action {\n  @apply border-gray-500 border;\n  flex-shrink: 0;\n  min-width: 6rem;\n  text-align: center;\n}\n\ndiv.value {\n  @apply border-gray-500 border;\n  @apply p-1.5;\n  @apply px-2;\n\n  &.edit {\n    @apply p-0;\n    @apply bg-gray-400;\n\n    input {\n      margin: 0;\n      width: auto;\n      height: 100%;\n      flex-grow: 1;\n      border: none;\n      @apply shadow-none;\n    }\n\n    input:focus+.buttons {\n      @apply bg-gray-500 border-gray-600 bg-opacity-75 border-opacity-75;\n    }\n  }\n\n  flex-grow : 1;\n  display : flex;\n  justify-content: space-between;\n  align-items : center;\n\n  .buttons {\n    flex-shrink: 0;\n    height: 100%;\n    width: 4rem;\n    @apply flex items-center justify-evenly;\n\n    fa-icon {\n      cursor: pointer;\n      @apply text-primary;\n      @apply p-1;\n      opacity: 0.7;\n      font-size: 0.6rem;\n\n      &:hover {\n        opacity: 1;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/rule-list/list-item.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnInit, Output } from '@angular/core';\nimport { fadeInAnimation, fadeOutAnimation } from '../../animations';\n\n@Component({\n  selector: 'app-rule-list-item',\n  templateUrl: 'list-item.html',\n  styleUrls: ['list-item.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation\n  ]\n})\nexport class RuleListItemComponent implements OnInit {\n  /** The host element is going to fade in/out */\n  @HostBinding('@fadeIn')\n  @HostBinding('@fadeOut')\n  readonly animation = true;\n\n  @Input()\n  symbolMap: { [key: string]: string } = {}\n\n  /**\n   * The current value (rule) displayed by this component.\n   * Supports two-way bindings.\n   */\n  @Input()\n  set value(v: string) {\n    this.updateValue(v);\n    this._savedValue = this._value;\n  }\n  private _value = '';\n\n  /** The last actually saved value of this rule. Required for resets */\n  private _savedValue = '';\n\n  /**\n   * Emits whenever the rule value changes.\n   * Supports two-way-bindings on ([value])\n   */\n  @Output()\n  valueChange = new EventEmitter<string>();\n\n  /** Whether or not the rule list item is selected */\n  @Input()\n  set selected(v: any) {\n    this._selected = coerceBooleanProperty(v)\n  }\n  get selected() {\n    return this._selected;\n  }\n  private _selected = false;\n\n  @Output()\n  selectedChange = new EventEmitter<boolean>();\n\n  /**\n   * Whether or not the component is in edit mode.\n   * Supports two-way-bindings on ([edit])\n   */\n  @Input()\n  set edit(v: any) {\n    this._edit = coerceBooleanProperty(v);\n  }\n  get edit() {\n    return this._edit;\n  }\n  private _edit: boolean = false;\n\n  /**\n   * Emits whenever the component switch to or away from edit\n   * mode.\n   * Supports two-way-bindings on ([edit])\n   */\n  @Output()\n  editChange = new EventEmitter<boolean>();\n\n  /**\n   * Whether or not the component should be in read-only mode.\n   */\n  @Input()\n  set readonly(v: any) {\n    this._readonly = coerceBooleanProperty(v);\n  }\n  get readonly() {\n    return this._readonly;\n  }\n  private _readonly: boolean = false;\n\n  /**\n   * Emits when the user presses the delete button of\n   * this rule component.\n   */\n  @Output()\n  delete = new EventEmitter<void>();\n\n  /** @private Whether or not this rule is a \"Allow\" rule - we default to allow since this is what most rules are used for */\n  isAllow = true;\n\n  /** @private Whether or not this rule is a \"Deny\" rule */\n  isBlock = false;\n\n  /** @private the actually displayed rule value (without the verdict) */\n  display = '';\n\n  /** @private the character representation of the current verdict */\n  get currentAction() {\n    if (this.isBlock) {\n      return '-';\n    }\n    if (this.isAllow) {\n      return '+';\n    }\n    return '';\n  }\n\n  constructor(private cdr: ChangeDetectorRef) { }\n\n  ngOnInit() {\n    // new entries always start in edit mode\n    if (!this.isAllow && !this.isBlock) {\n      this._edit = true;\n    }\n  }\n\n  /**\n   * @private\n   * Toggle between edit and view mode. When switching from\n   * edit to view mode, the current value is emitted to the\n   * parent element in case it has been changed.\n   */\n  toggleEdit() {\n    if (this._edit) {\n      // do nothing if the rule is obviously invalid (no verdict or value).\n      if (this.display === '' || !(this.isAllow || this.isBlock)) {\n        return;\n      }\n\n      if (this._value !== this._savedValue) {\n        this.valueChange.next(this._value);\n      }\n    }\n\n    this._edit = !this._edit;\n    this.editChange.next(this._edit);\n  }\n\n  toggleSelection() {\n    this.selected = !this.selected;\n    this.selectedChange.next(this.selected);\n\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * @private\n   * Sets the new rule action. Used as a callback in the drop-down.\n   *\n   * @param action The new action\n   */\n  setAction(action: '+' | '-') {\n    this.updateValue(`${action} ${this.display}`);\n  }\n\n  /**\n   * @private\n   * Update the actual value of the rule.\n   *\n   * @param entity The new rule value\n   */\n  setEntity(entity: string) {\n    const action = this.isAllow ? '+' : '-';\n    this.updateValue(`${action} ${entity}`);\n  }\n\n  /**\n   * @private\n   *\n   * Reset the value to it's previously saved value if it was changed.\n   * If the value is unchanged a reset counts as a delete and triggers\n   * on our delete output.\n   */\n  reset() {\n    if (this._edit) {\n      // if the user did not change anything we can immediately\n      // delete it.\n      if (this._savedValue !== '') {\n        this.value = this._savedValue;\n        this._edit = false;\n        return;\n      }\n    }\n\n    this.delete.next();\n  }\n\n  /**\n   * Updates our internal states to correctly display the rule.\n   *\n   * @param v The actual rule value\n   */\n  private updateValue(v: string) {\n    this._value = v.trim();\n    switch (this._value[0]) {\n      case '+':\n        this.isAllow = true;\n        this.isBlock = false;\n        break;\n      case '-':\n        this.isAllow = false;\n        this.isBlock = true;\n        break;\n      default:\n        // not yet set\n        this.isBlock = this.isAllow = false;\n    }\n\n    this.display = this._value.slice(1).trim();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/rule-list/rule-list.html",
    "content": "<div class=\"list-items\" cdkDropList (cdkDropListDropped)=\"drop($event)\">\n  <div class=\"item\" *ngFor=\"let entry of entries; let index=index; trackBy: trackBy\" cdkDrag\n    [cdkDragDisabled]=\"readonly\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5 mr-2 text-secondary\" fill=\"none\" viewBox=\"0 0 24 24\"\n      stroke=\"currentColor\" cdkDragHandle [class.opacity-0]=\"readonly\" [class.cusor-move]=\"!readonly\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 9l4-4 4 4m0 6l-4 4-4-4\" />\n    </svg>\n    <app-rule-list-item [symbolMap]=\"symbolMap\" [readonly]=\"readonly\" [value]=\"entry\"\n      (valueChange)=\"updateValue(index, $event)\" (selectedChange)=\"selectItem(index, $event)\"\n      (delete)=\"deleteEntry(index)\">\n    </app-rule-list-item>\n  </div>\n</div>\n\n<div class=\"button-list\" *ngIf=\"selectedItems.length === 0\">\n  <div class=\"dotted\" *ngIf=\"!entries?.length && readonly\">\n    No entries available\n  </div>\n\n  <button class=\"new-entry dotted\" (click)=\"addEntry()\"\n    *ngIf=\"!readonly && (!entries?.length || entries[entries.length-1] !== '')\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-5 h-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n      <path fill-rule=\"evenodd\"\n        d=\"M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z\" clip-rule=\"evenodd\" />\n    </svg>\n    <span>Add Rule</span>\n  </button>\n</div>\n\n<div class=\"flex justify-end button-list\" *ngIf=\"selectedItems.length > 0\">\n  <span>\n    <app-menu-trigger [menu]=\"selectionMenu\" [useContent]=\"true\">\n      {{ selectedItems.length }} Rule{{ selectedItems.length > 1 ? 's' : ''}} selected\n      <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"w-5 h-5\">\n        <path fill-rule=\"evenodd\"\n          d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n          clip-rule=\"evenodd\" />\n      </svg>\n    </app-menu-trigger>\n  </span>\n\n  <app-menu #selectionMenu>\n    <app-menu-item (click)=\"removeSelectedItems()\">Remove Rules</app-menu-item>\n    <app-menu-item (click)=\"abortSelection()\">Cancel</app-menu-item>\n  </app-menu>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/rule-list/rule-list.scss",
    "content": ":host {\n  outline: none;\n}\n\n.item,\n.cdk-drag-preview {\n  display: flex;\n  align-items: center;\n  padding: 3px;\n\n  fa-icon {\n    cursor: pointer;\n    @apply text-tertiary;\n    @apply text-lg;\n    @apply mr-2;\n  }\n\n  app-rule-list-item {\n    flex-grow: 1;\n  }\n}\n\n.cdk-drag-placeholder {\n  left: -4px;\n  padding: 1px;\n  padding-left: 4px;\n}\n\n// TODO(ppacher9): move this transition to a mixin\n.list-items.cdk-drop-list-dragging .list:not(.cdk-drag-placeholder) {\n  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.cdk-drag-preview {\n  left: -4px;\n  padding: 1px;\n  padding-left: 4px;\n}\n\n.button-list {\n  @apply mt-2;\n  @apply ml-8;\n}\n\n.dotted {\n  @apply w-full;\n  @apply rounded;\n  @apply p-1;\n  @apply border-2;\n  @apply border-dashed;\n  @apply border-buttons-light;\n  @apply bg-background;\n  @apply text-secondary;\n\n  display: flex;\n  align-items: center;\n  justify-content: center;\n\n  span {\n    @apply font-medium;\n  }\n}\n\n.new-entry {\n  cursor: pointer;\n\n  &:hover {\n    @apply text-primary;\n    @apply bg-gray-300;\n\n    span {\n      @apply text-primary;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/rule-list/rule-list.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostBinding, HostListener, Input, QueryList, ViewChildren } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { SfngDialogService } from '@safing/ui';\nimport { RuleListItemComponent } from './list-item';\n\n@Component({\n  selector: 'app-rule-list',\n  templateUrl: './rule-list.html',\n  styleUrls: ['./rule-list.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => RuleListComponent),\n      multi: true,\n    }\n  ],\n})\nexport class RuleListComponent implements ControlValueAccessor {\n  /** Add the host element into the tab-sequence */\n  @HostBinding('tabindex')\n  readonly tabindex = 0;\n\n  @ViewChildren(RuleListItemComponent)\n  renderedRules!: QueryList<RuleListItemComponent>;\n\n  /** A list of selected rule indexes */\n  selectedItems: number[] = [];\n\n  /**\n   * @private\n   * Mark the component as dirty by calling the onTouch callback of the control-value accessor\n   */\n  @HostListener('blur')\n  onBlur() {\n    this.onTouch();\n  }\n\n  @Input()\n  symbolMap = {\n    '+': 'Allow',\n    '-': 'Block',\n  }\n\n  /**\n   * Whether or not the component should be displayed as read-only.\n   */\n  @Input()\n  set readonly(v: any) {\n    this._readonly = coerceBooleanProperty(v);\n  }\n  get readonly() {\n    return this._readonly;\n  }\n  private _readonly = false;\n\n  /**\n   * @private\n   * The actual rule entries. Displayed as RuleListItemComponent.\n   */\n  entries: string[] = [];\n\n  constructor(\n    private changeDetector: ChangeDetectorRef,\n    private dialog: SfngDialogService\n  ) { }\n\n  /**\n   * @private\n   * Update the value of a rule-list entry. Used as a callback function\n   * for the valueChange output of the RuleListItemComponent.\n   *\n   * @param index The index of the rule list entry to update\n   * @param newValue The new value of the rule\n   */\n  updateValue(index: number, newValue: string) {\n    // we need create a copy of the actual value as\n    // the parent component might still have a reference\n    // to the current values.\n    this.entries = [\n      ...this.entries,\n    ];\n    this.entries[index] = newValue;\n\n    // tell the control that we have a new value\n    this.onChange(this.entries);\n  }\n\n  /**\n   * @private\n   * Delete a rule list entry.\n   *\n   * @param index The index of the rule list entry to delete\n   */\n  deleteEntry(index: number) {\n    this.entries = [...this.entries];\n    this.entries.splice(index, 1);\n    this.onChange(this.entries);\n  }\n\n  /**\n   * @private\n   * Add a new, empty rule list entry at the end of the\n   * list.\n   *\n   * This is a no-op if there's already an empty item\n   * available.\n   */\n  addEntry() {\n    // if there's already one empty entry abort\n    if (this.entries.some(e => e.trim() === '')) {\n      return;\n    }\n\n    this.entries = [...this.entries];\n    this.entries.push('');\n  }\n\n  /**\n   * Set a new value for the rule list. This is the\n   * only way to configure the existing entries and is\n   * used by the control-value-accessor and ngModel.\n   *\n   * @param value The new value set via [ngModel]\n   */\n  writeValue(value: string[]) {\n    this.entries = value;\n\n    this.changeDetector.markForCheck();\n  }\n\n  /** Toggles selection of a rule item */\n  selectItem(index: number, selected: boolean) {\n    if (selected && !this.selectedItems.includes(index)) {\n      this.selectedItems = [\n        ...this.selectedItems,\n        index,\n      ]\n\n      return;\n    }\n\n    if (!selected && this.selectedItems.includes(index)) {\n      this.selectedItems = this.selectedItems.filter(idx => idx !== index)\n\n      return;\n    }\n  }\n\n  /** Removes all selected items after displaying a confirmation dialog. */\n  removeSelectedItems() {\n    this.dialog.confirm({\n      buttons: [\n        {\n          id: 'abort',\n          text: 'Cancel',\n          class: 'outline'\n        },\n        {\n          id: 'delete',\n          text: 'Delete Rules',\n          class: 'danger'\n        }\n      ],\n      canCancel: true,\n      caption: 'Caution',\n      header: 'Rule Deletion',\n      message: 'Do you want to delete the selected rules'\n    })\n      .onAction('delete', () => {\n        this.entries = this.entries.filter((_, idx: number) => !this.selectedItems.includes(idx))\n        this.abortSelection();\n        this.onChange(this.entries);\n      })\n\n  }\n\n  /** Aborts the current selection */\n  abortSelection() {\n    this.selectedItems.forEach(itemIdx => this.renderedRules.get(itemIdx)?.toggleSelection())\n    this.selectedItems = [];\n  }\n\n  /** @private onChange callback registered by ngModel and form controls */\n  onChange = (_: string[]): void => { };\n\n  /** Registers the onChange callback and required for the ControlValueAccessor interface */\n  registerOnChange(fn: (value: string[]) => void) {\n    this.onChange = fn;\n  }\n\n  /** @private onTouch callback registered by ngModel and form controls */\n  onTouch = (): void => { };\n\n  /** Registers the onChange callback and required for the ControlValueAccessor interface */\n  registerOnTouched(fn: () => void) {\n    this.onTouch = fn;\n  }\n\n  /**\n   * @private\n   * Used as a callback for the @angular/cdk drop component\n   * and used to update the actual order of the entries.\n   *\n   * @param event The drop-event\n   */\n  drop(event: CdkDragDrop<string[]>) {\n    if (this._readonly) {\n      return;\n    }\n\n    // create a copy of the array\n    this.entries = [...this.entries];\n    moveItemInArray(this.entries, event.previousIndex, event.currentIndex);\n\n    this.changeDetector.markForCheck();\n    this.onChange(this.entries);\n  }\n\n  /** @private TrackByFunction for entries */\n  trackBy(idx: number, value: string) {\n    return `${value}`;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/safe.pipe.ts",
    "content": "import { Pipe, PipeTransform } from '@angular/core';\nimport { DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';\n\n@Pipe({\n  name: 'safe'\n})\nexport class SafePipe implements PipeTransform {\n\n  constructor(protected sanitizer: DomSanitizer) { }\n\n  public transform(value: any, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {\n    switch (type) {\n      case 'html': return this.sanitizer.bypassSecurityTrustHtml(value);\n      case 'style': return this.sanitizer.bypassSecurityTrustStyle(value);\n      case 'script': return this.sanitizer.bypassSecurityTrustScript(value);\n      case 'url': return this.sanitizer.bypassSecurityTrustUrl(value);\n      case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value);\n      default: throw new Error(`Invalid safe type specified: ${type}`);\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/config/subsystems.ts",
    "content": "import { ExpertiseLevelNumber } from \"@safing/portmaster-api\";\nimport { Subsystem } from \"src/app/services/status.types\";\n\nexport interface SubsystemWithExpertise extends Subsystem {\n  minimumExpertise: ExpertiseLevelNumber;\n  isDisabled: boolean;\n  hasUserDefinedValues: boolean;\n}\n\nexport var subsystems : SubsystemWithExpertise[] = [\n  {\n    minimumExpertise: ExpertiseLevelNumber.developer,\n    isDisabled: false,\n    hasUserDefinedValues: false,\n    ID: \"core\",\n    Name: \"Core\",\n    Description: \"Base Structure and System Integration\",\n    Modules: [\n      {\n        Name: \"core\",\n        Enabled: true\n      },\n      {\n        Name: \"subsystems\",\n        Enabled: true\n      },\n      {\n        Name: \"runtime\",\n        Enabled: true\n      },\n      {\n        Name: \"status\",\n        Enabled: true\n      },\n      {\n        Name: \"ui\",\n        Enabled: true\n      },\n      {\n        Name: \"compat\",\n        Enabled: true\n      },\n      {\n        Name: \"broadcasts\",\n        Enabled: true\n      },\n      {\n        Name: \"sync\",\n        Enabled: true\n      }\n    ],\n    ToggleOptionKey: \"\",\n    ExpertiseLevel: \"user\",\n    ReleaseLevel: 0,\n    ConfigKeySpace: \"config:core/\",\n    _meta: {\n      Created: 0,\n      Modified: 0,\n      Expires: 0,\n      Deleted: 0,\n      Key: \"runtime:subsystems/core\"\n    }\n  },\n  {\n    minimumExpertise: ExpertiseLevelNumber.developer,\n    isDisabled: false,\n    hasUserDefinedValues: false,\n    ID: \"dns\",\n    Name: \"Secure DNS\",\n    Description: \"DNS resolver with scoping and DNS-over-TLS\",\n    Modules: [\n      {\n        Name: \"nameserver\",\n        Enabled: true\n      },\n      {\n        Name: \"resolver\",\n        Enabled: true\n      }\n    ],\n    ToggleOptionKey: \"\",\n    ExpertiseLevel: \"user\",\n    ReleaseLevel: 0,\n    ConfigKeySpace: \"config:dns/\",\n    _meta: {\n      Created: 0,\n      Modified: 0,\n      Expires: 0,\n      Deleted: 0,\n      Key: \"runtime:subsystems/dns\"\n    }\n  },\n  {\n    minimumExpertise: ExpertiseLevelNumber.developer,\n    isDisabled: false,\n    hasUserDefinedValues: false,\n    ID: \"filter\",\n    Name: \"Privacy Filter\",\n    Description: \"DNS and Network Filter\",\n    Modules: [\n      {\n        Name: \"filter\",\n        Enabled: true\n      },\n      {\n        Name: \"interception\",\n        Enabled: true\n      },\n      {\n        Name: \"base\",\n        Enabled: true\n      },\n      {\n        Name: \"database\",\n        Enabled: true\n      },\n      {\n        Name: \"config\",\n        Enabled: true\n      },\n      {\n        Name: \"rng\",\n        Enabled: true\n      },\n      {\n        Name: \"metrics\",\n        Enabled: true\n      },\n      {\n        Name: \"api\",\n        Enabled: true\n      },\n      {\n        Name: \"updates\",\n        Enabled: true\n      },\n      {\n        Name: \"network\",\n        Enabled: true\n      },\n      {\n        Name: \"netenv\",\n        Enabled: true\n      },\n      {\n        Name: \"processes\",\n        Enabled: true\n      },\n      {\n        Name: \"profiles\",\n        Enabled: true\n      },\n      {\n        Name: \"notifications\",\n        Enabled: true\n      },\n      {\n        Name: \"intel\",\n        Enabled: true\n      },\n      {\n        Name: \"geoip\",\n        Enabled: true\n      },\n      {\n        Name: \"filterlists\",\n        Enabled: true\n      },\n      {\n        Name: \"customlists\",\n        Enabled: true\n      }\n    ],\n    ToggleOptionKey: \"\",\n    ExpertiseLevel: \"user\",\n    ReleaseLevel: 0,\n    ConfigKeySpace: \"config:filter/\",\n    _meta: {\n      Created: 0,\n      Modified: 0,\n      Expires: 0,\n      Deleted: 0,\n      Key: \"runtime:subsystems/filter\"\n    }\n  },\n  {\n    minimumExpertise: ExpertiseLevelNumber.developer,\n    isDisabled: false,\n    hasUserDefinedValues: false,\n    ID: \"history\",\n    Name: \"Network History\",\n    Description: \"Keep Network History Data\",\n    Modules: [\n      {\n        Name: \"netquery\",\n        Enabled: true\n      }\n    ],\n    ToggleOptionKey: \"\",\n    ExpertiseLevel: \"user\",\n    ReleaseLevel: 0,\n    ConfigKeySpace: \"config:history/\",\n    _meta: {\n      Created: 0,\n      Modified: 0,\n      Expires: 0,\n      Deleted: 0,\n      Key: \"runtime:subsystems/history\"\n    }\n  },\n  {\n    minimumExpertise: ExpertiseLevelNumber.developer,\n    isDisabled: false,\n    hasUserDefinedValues: false,\n    ID: \"spn\",\n    Name: \"SPN\",\n    Description: \"Safing Privacy Network\",\n    Modules: [\n      {\n        Name: \"captain\",\n        Enabled: false\n      },\n      {\n        Name: \"terminal\",\n        Enabled: false\n      },\n      {\n        Name: \"cabin\",\n        Enabled: false\n      },\n      {\n        Name: \"ships\",\n        Enabled: false\n      },\n      {\n        Name: \"docks\",\n        Enabled: false\n      },\n      {\n        Name: \"access\",\n        Enabled: false\n      },\n      {\n        Name: \"crew\",\n        Enabled: false\n      },\n      {\n        Name: \"navigator\",\n        Enabled: false\n      },\n      {\n        Name: \"sluice\",\n        Enabled: false\n      },\n      {\n        Name: \"patrol\",\n        Enabled: false\n      }\n    ],\n    ToggleOptionKey: \"spn/enable\",\n    ExpertiseLevel: \"user\",\n    ReleaseLevel: 0,\n    ConfigKeySpace: \"config:spn/\",\n    _meta: {\n      Created: 0,\n      Modified: 0,\n      Expires: 0,\n      Deleted: 0,\n      Key: \"runtime:subsystems/spn\"\n    }\n  }\n];\n"
  },
  {
    "path": "desktop/angular/src/app/shared/count-indicator/count-indicator.html",
    "content": "<span class=\"counter\">{{ count | prettyCount }}</span>\n<div class=\"pill\">\n  <div class=\"percentage\" [style.width.%]=\"allowedPercentage\"></div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/count-indicator/count-indicator.module.ts",
    "content": "import { NgModule } from \"@angular/core\";\nimport { CountIndicatorComponent } from \"./count-indicator\";\nimport { PrettyCountPipe } from \"./count.pipe\";\n\n@NgModule({\n  declarations: [\n    CountIndicatorComponent,\n    PrettyCountPipe,\n  ],\n  exports: [\n    CountIndicatorComponent,\n    PrettyCountPipe,\n  ]\n})\nexport class CountIndicatorModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/count-indicator/count-indicator.scss",
    "content": "@import '../../../theme/mixins/_pill.scss';\n\n:host {\n  @include pill-container;\n  @apply pl-2;\n  @apply bg-buttons-dark;\n  @apply w-20;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/count-indicator/count-indicator.ts",
    "content": "import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';\n\n@Component({\n  selector: 'app-count-indicator',\n  templateUrl: './count-indicator.html',\n  styleUrls: ['./count-indicator.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CountIndicatorComponent implements OnChanges {\n  @Input()\n  count = 0;\n\n  @Input()\n  countAllowed: number = 0;\n\n  allowedPercentage: number = 0;\n\n  ngOnChanges() {\n    const ratio = (this.countAllowed / this.count) || 0;\n    this.allowedPercentage = Math.round(ratio * 100);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/count-indicator/count.pipe.ts",
    "content": "import { Pipe, PipeTransform } from \"@angular/core\";\n\n@Pipe({\n  name: 'prettyCount',\n  pure: true\n})\nexport class PrettyCountPipe implements PipeTransform {\n  transform(value: number) {\n    if (value > 999) {\n      const v = Math.floor(value / 1000);\n      if (value === v * 1000) {\n        return `${v}k`;\n      }\n      return `${v}k+`\n    }\n    return `${value}`\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/count-indicator/index.ts",
    "content": "export * from './count-indicator';\nexport * from './count-indicator.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/country-flag/country-flag.ts",
    "content": "import { AfterViewInit, Directive, ElementRef, HostBinding, Input, OnChanges, Renderer2, SimpleChanges } from '@angular/core';\n\n@Directive({\n  selector: 'span[appCountryFlags]',\n})\nexport class CountryFlagDirective implements AfterViewInit, OnChanges {\n  private readonly flagDir = \"/assets/img/flags/\";\n  private readonly OFFSET = 127397;\n\n  @HostBinding('style.text-shadow')\n  textShadow = 'rgba(255, 255, 255, .5) 0px 0px 1px';\n\n  @Input()\n  appCountryFlags: string = '';\n\n  constructor(\n    private el: ElementRef,\n    private renderer: Renderer2\n  ) { }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (!changes['appCountryFlags'].isFirstChange()) {\n      this.update();\n    }\n  }\n\n  ngAfterViewInit() {\n    this.update();\n  }\n\n  private update() {\n    const span = this.el.nativeElement as HTMLSpanElement;\n    const flag = this.toUnicodeFlag(this.appCountryFlags);\n    this.renderer.setAttribute(span, 'data-before', flag);\n\n    span.innerHTML = `<img style=\"display: inline\" src=\"${this.flagDir}${this.appCountryFlags.toLocaleUpperCase()}.png\">`;\n  }\n\n  private toUnicodeFlag(code: string) {\n    const base = 127462 - 65;\n    const cc = code.toUpperCase();\n    const res = String.fromCodePoint(...cc.split('').map(c => base + c.charCodeAt(0)));\n    return res;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/country-flag/country.module.ts",
    "content": "import { NgModule } from '@angular/core';\nimport { CountryFlagDirective } from './country-flag';\n\n@NgModule({\n  declarations: [\n    CountryFlagDirective\n  ],\n  exports: [\n    CountryFlagDirective,\n  ]\n})\nexport class CountryFlagModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/country-flag/index.ts",
    "content": "export * from './country-flag';\nexport * from './country.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/edit-profile-dialog/edit-profile-dialog.html",
    "content": "<h1 class=\"flex flex-row gap-2 items-center\">\n  <img\n    [src]=\"iconObjectURL\"\n    *ngIf=\"imageError === null && !!iconData\"\n    class=\"w-8 h-8 rounded-full border border-gray-400\"\n  />\n\n  {{ isEditMode ? 'Edit App Profile' : 'Create New App Profile' }}\n</h1>\n\n<form #profileForm=\"ngForm\">\n  <sfng-tab-group customHeader=\"false\" linkRouter=\"false\">\n    <sfng-tab title=\"General\">\n      <div *sfngTabContent class=\"tab-content\">\n        <span class=\"py-2 text-secondary\">\n          Configure basic profile information like the profile name, it's\n          description and optionally the profile icon.\n        </span>\n\n        <div class=\"input\" *appExpertiseLevel=\"'developer'\">\n          <label>ID</label>\n          <input\n            type=\"text\"\n            name=\"id\"\n            pattern=\"[a-zA-Z0-9\\-\\._]*\"\n            [(ngModel)]=\"profile.ID\"\n            placeholder=\"A unique identifier for profile. Leave empty to generate a random one.\"\n          />\n        </div>\n\n        <div class=\"input\">\n          <label>Name *</label>\n          <input\n            type=\"text\"\n            required\n            name=\"name\"\n            [(ngModel)]=\"profile.Name\"\n            placeholder=\"A name for labele profile\"\n          />\n        </div>\n\n        <div class=\"input\">\n          <label>Description</label>\n          <input\n            type=\"text\"\n            name=\"description\"\n            [(ngModel)]=\"profile.Description\"\n            placeholder=\"An optional description of the profile\"\n          />\n        </div>\n\n        <div class=\"flex flex-row justify-between\">\n          <div class=\"input\">\n            <label>Icon</label>\n            <div class=\"flex flex-col gap-2 justify-start\">\n              <div class=\"flex flex-row gap-3\">\n                <label\n                  for=\"icon-upload\"\n                  class=\"inline-block p-1 px-4 font-medium whitespace-nowrap bg-opacity-80 rounded-sm cursor-pointer outline-none bg-blue hover:bg-blue text-xxs w-fit\"\n                >\n                  Choose Icon\n                </label>\n                <button\n                  *ngIf=\"!!iconData && profile.Icons?.length\"\n                  (click)=\"resetIcon()\"\n                  class=\"bg-red-300\"\n                >\n                  Reset Icon\n                </button>\n              </div>\n              <span class=\"pl-2 break-normal text-tertiary\"\n                >The icon must be smaller than 10kB and it's dimensions must not\n                exceed 512x512 px. Only JPG and PNG files are supported.</span\n              >\n            </div>\n            <input\n              id=\"icon-upload\"\n              class=\"hidden\"\n              type=\"file\"\n              (change)=\"fileChangeEvent($event)\"\n            />\n            <span *ngIf=\"imageError !== null\" class=\"pl-2 text-red-300 text-xxs\"\n              >{{ imageError }}</span\n            >\n          </div>\n\n          <img\n            [src]=\"iconObjectURL\"\n            *ngIf=\"imageError === null && !!iconData\"\n            class=\"w-12 h-12 rounded-full border border-gray-400\"\n          />\n        </div>\n      </div>\n    </sfng-tab>\n\n    <sfng-tab title=\"Process Matching\">\n      <div *sfngTabContent class=\"flex flex-col tab-content text-xxs\">\n        <span class=\"text-xs text-secondary\"\n          >This profile will be applied to processes that match one of the\n          following fingerprints:</span\n        >\n\n        <div *ngIf=\"!profile.Fingerprints?.length\">\n          No fingerprints configured. Please press \"Add New\" to get started.\n        </div>\n        <div class=\"flex overflow-auto flex-col flex-grow gap-2 px-1\">\n          <div\n            class=\"flex relative flex-row gap-2 justify-evenly items-center p-2 bg-gray-200 border-r border-l border-gray-500\"\n            *ngFor=\"let fp of profile.Fingerprints; let index=index\"\n          >\n            <span\n              class=\"block absolute top-0 left-0 w-2 border-b border-gray-500\"\n            ></span>\n            <span\n              class=\"block absolute bottom-0 left-0 w-2 border-b border-gray-500\"\n            ></span>\n\n            <span\n              class=\"block absolute top-0 right-0 w-2 border-b border-gray-500\"\n            ></span>\n            <span\n              class=\"block absolute right-0 bottom-0 w-2 border-b border-gray-500\"\n            ></span>\n\n            <sfng-select\n              [(ngModel)]=\"fp.Type\"\n              [ngModelOptions]=\"{standalone: true}\"\n            >\n              <sfng-select-item\n                *sfngSelectValue=\"fingerPrintTypes.Tag; label: 'Tag'\"\n              >\n                Tag\n                <sfng-tipup key=\"process-tags\"></sfng-tipup>\n              </sfng-select-item>\n              <sfng-select-item\n                *sfngSelectValue=\"fingerPrintTypes.Cmdline; label: 'Command Line'\"\n                >Command Line\n              </sfng-select-item>\n              <sfng-select-item\n                *sfngSelectValue=\"fingerPrintTypes.Env; label: 'Environment'\"\n                >Environment\n              </sfng-select-item>\n              <sfng-select-item\n                *sfngSelectValue=\"fingerPrintTypes.Path; label: 'Path'\"\n                >Path</sfng-select-item\n              >\n            </sfng-select>\n\n            <input\n              type=\"text\"\n              [(ngModel)]=\"fp.Key\"\n              placeholder=\"Key\"\n              [ngModelOptions]=\"{standalone: true}\"\n              *ngIf=\"fp.Type === 'env'\"\n            />\n\n            <sfng-select\n              [(ngModel)]=\"fp.Key\"\n              placeholder=\"Key\"\n              [ngModelOptions]=\"{standalone: true}\"\n              *ngIf=\"fp.Type === 'tag'\"\n            >\n              <ng-container *ngFor=\"let tag of processTags\">\n                <sfng-select-item *sfngSelectValue=\"tag.ID; label: tag.Name\"\n                  >{{ tag.Name }}</sfng-select-item\n                >\n              </ng-container>\n            </sfng-select>\n\n            <sfng-select\n              [(ngModel)]=\"fp.Operation\"\n              [ngModelOptions]=\"{standalone: true}\"\n            >\n              <sfng-select-item *sfngSelectValue=\"fingerPrintOperations.Equal\"\n                >Equals</sfng-select-item\n              >\n              <sfng-select-item *sfngSelectValue=\"fingerPrintOperations.Prefix\"\n                >Prefix</sfng-select-item\n              >\n              <sfng-select-item *sfngSelectValue=\"fingerPrintOperations.Regex\"\n                >Regex</sfng-select-item\n              >\n            </sfng-select>\n\n            <input\n              type=\"text\"\n              [(ngModel)]=\"fp.Value\"\n              placeholder=\"Value\"\n              [ngModelOptions]=\"{standalone: true}\"\n            />\n\n            <button\n              class=\"bg-opacity-90 bg-red hover:bg-red\"\n              (click)=\"removeFingerprint(index)\"\n            >\n              <svg\n                xmlns=\"http://www.w3.org/2000/svg\"\n                fill=\"none\"\n                viewBox=\"0 0 24 24\"\n                stroke-width=\"1.5\"\n                stroke=\"currentColor\"\n                class=\"my-0.5 w-4 h-4\"\n              >\n                <path\n                  stroke-linecap=\"round\"\n                  stroke-linejoin=\"round\"\n                  d=\"M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0\"\n                />\n              </svg>\n            </button>\n          </div>\n        </div>\n\n        <button (click)=\"addFingerprint()\">Add New</button>\n      </div>\n    </sfng-tab>\n\n    <sfng-tab title=\"Copy Settings\">\n      <div *sfngTabContent class=\"flex flex-col gap-2 tab-content\">\n        <div class=\"flex flex-row gap-2 items-center p-2 bg-gray-200\">\n          <span class=\"text-secondary\"\n            >Select a Profile to copy settings from:</span\n          >\n          <div class=\"flex-grow\"></div>\n          <sfng-select\n            [(ngModel)]=\"selectedCopyFrom\"\n            [ngModelOptions]=\"{standalone: true}\"\n            class=\"flex-grow\"\n            [allowSearch]=\"true\"\n            searchPlaceholder=\"Search Profiles\"\n          >\n            <ng-container *ngFor=\"let p of allProfiles\">\n              <sfng-select-item\n                *sfngSelectValue=\"p; label:p.Name\"\n                class=\"flex flex-row gap-2 items-center\"\n              >\n                <app-icon [profile]=\"p\"></app-icon>\n                {{ p.Name }}\n              </sfng-select-item>\n            </ng-container>\n          </sfng-select>\n          <button\n            [disabled]=\"selectedCopyFrom === null\"\n            (click)=\"addCopyFrom()\"\n          >\n            Add\n          </button>\n        </div>\n\n        <div\n          class=\"flex overflow-auto flex-col flex-grow gap-2\"\n          cdkDropList\n          (cdkDropListDropped)=\"drop($event)\"\n        >\n          <div\n            *ngFor=\"let p of copySettingsFrom; let index=index\"\n            cdkDrag\n            class=\"flex flex-row items-center p-2 bg-gray-200 rounded-sm\"\n          >\n            <svg\n              xmlns=\"http://www.w3.org/2000/svg\"\n              class=\"mr-2 w-5 h-5 cursor-move text-secondary\"\n              fill=\"none\"\n              viewBox=\"0 0 24 24\"\n              stroke=\"currentColor\"\n              cdkDragHandle\n            >\n              <path\n                stroke-linecap=\"round\"\n                stroke-linejoin=\"round\"\n                stroke-width=\"2\"\n                d=\"M8 9l4-4 4 4m0 6l-4 4-4-4\"\n              />\n            </svg>\n            <app-icon [profile]=\"p\"></app-icon>\n            {{ p.Name }}\n            <div class=\"flex-grow\"></div>\n            <button\n              class=\"bg-opacity-90 bg-red hover:bg-red\"\n              (click)=\"removeCopyFrom(index)\"\n            >\n              <svg\n                xmlns=\"http://www.w3.org/2000/svg\"\n                fill=\"none\"\n                viewBox=\"0 0 24 24\"\n                stroke-width=\"1.5\"\n                stroke=\"currentColor\"\n                class=\"my-0.5 w-4 h-4\"\n              >\n                <path\n                  stroke-linecap=\"round\"\n                  stroke-linejoin=\"round\"\n                  d=\"M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0\"\n                />\n              </svg>\n            </button>\n          </div>\n        </div>\n        <span class=\"block text-center break-normal text-secondary text-xxs\">\n          Settings will be copied from all specified profiles in order with\n          settings from higher profiles taking precedence. <br />\n          Existing settings may be overwritten.\n        </span>\n      </div>\n    </sfng-tab>\n  </sfng-tab-group>\n</form>\n\n<div class=\"flex flex-row gap-2 justify-end items-center\">\n  <button *ngIf=\"isEditMode\" (click)=\"deleteProfile()\" class=\"bg-red\">\n    Delete\n  </button>\n  <div class=\"flex-grow\"></div>\n  <button (click)=\"abort()\" class=\"\">Cancel</button>\n  <button\n    (click)=\"save()\"\n    [disabled]=\"!profileForm.valid\"\n    class=\"bg-opacity-80 bg-blue hover:bg-blue\"\n  >\n    Save\n  </button>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/edit-profile-dialog/edit-profile-dialog.scss",
    "content": ":host {\n  @apply flex flex-col gap-4 max-w-2xl;\n  min-width: 500px;\n  width: 60vw;\n}\n\n.tab-content {\n  @apply flex flex-col gap-4 overflow-x-hidden h-96 pt-2;\n}\n\n.input {\n  @apply flex flex-col gap-1;\n\n  label {\n    @apply text-primary uppercase text-xxs relative left-1.5;\n  }\n\n  input[type=\"text\"] {\n    @apply border border-gray-500;\n\n    &.ng-invalid.ng-dirty {\n      @apply border-red-200;\n    }\n  }\n\n  input[type=\"file\"] {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/edit-profile-dialog/edit-profile-dialog.ts",
    "content": "import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\nimport {\n  ChangeDetectorRef,\n  Component,\n  Inject,\n  OnDestroy,\n  OnInit,\n  TrackByFunction,\n} from '@angular/core';\nimport {\n  AppProfile,\n  AppProfileService,\n  FingerpringOperation,\n  Fingerprint,\n  FingerprintType,\n  PORTMASTER_HTTP_API_ENDPOINT,\n  PortapiService,\n  Record,\n  TagDescription,\n  mergeDeep,\n} from '@safing/portmaster-api';\nimport { SFNG_DIALOG_REF, SfngDialogRef, SfngDialogService } from '@safing/ui';\nimport { Observable, Subject, map, of, switchMap, takeUntil } from 'rxjs';\nimport { ActionIndicatorService } from 'src/app/shared/action-indicator';\n\n@Component({\n  templateUrl: './edit-profile-dialog.html',\n  //changeDetection: ChangeDetectionStrategy.OnPush,\n  styleUrls: ['./edit-profile-dialog.scss'],\n})\n// eslint-disable-next-line @angular-eslint/component-class-suffix\nexport class EditProfileDialog implements OnInit, OnDestroy {\n  private destory$ = new Subject<void>();\n\n  profile: Partial<AppProfile> = {\n    ID: '',\n    Source: 'local',\n    Name: '',\n    Description: '',\n    Icons: [],\n    Fingerprints: [],\n  };\n\n  isEditMode = false;\n  iconData: string | ArrayBuffer = '';\n  iconType: string = '';\n  iconChanged = false;\n  iconObjectURL = '';\n  imageError: string | null = null;\n\n  allProfiles: AppProfile[] = [];\n\n  copySettingsFrom: AppProfile[] = [];\n\n  selectedCopyFrom: AppProfile | null = null;\n\n  fingerPrintTypes = FingerprintType;\n  fingerPrintOperations = FingerpringOperation;\n  processTags: TagDescription[] = [];\n\n  trackFingerPrint: TrackByFunction<Fingerprint> = (\n    _: number,\n    fp: Fingerprint\n  ) => `${fp.Type}-${fp.Key}-${fp.Operation}-${fp.Value}`;\n\n  constructor(\n    @Inject(SFNG_DIALOG_REF)\n    private dialgoRef: SfngDialogRef<\n      EditProfileDialog,\n      any,\n      string | null | AppProfile\n    >,\n    private profileService: AppProfileService,\n    private portapi: PortapiService,\n    private actionIndicator: ActionIndicatorService,\n    private dialog: SfngDialogService,\n    private cdr: ChangeDetectorRef,\n    @Inject(PORTMASTER_HTTP_API_ENDPOINT) private httpAPI: string\n  ) { }\n\n  ngOnInit(): void {\n    this.profileService.tagDescriptions().subscribe((result) => {\n      this.processTags = result;\n      this.cdr.markForCheck();\n    });\n\n    this.profileService\n      .watchProfiles()\n      .pipe(takeUntil(this.destory$))\n      .subscribe((profiles) => {\n        this.allProfiles = profiles;\n        this.cdr.markForCheck();\n      });\n\n    if (!!this.dialgoRef.data && typeof this.dialgoRef.data === 'string') {\n      this.isEditMode = true;\n      this.profileService\n        .getAppProfile(this.dialgoRef.data)\n        .subscribe((profile) => {\n          this.profile = profile;\n          this.loadIcon();\n        });\n    } else if (\n      !!this.dialgoRef.data &&\n      typeof this.dialgoRef.data === 'object'\n    ) {\n      this.profile = this.dialgoRef.data;\n      this.loadIcon();\n    }\n  }\n\n  private loadIcon() {\n    if (!this.profile.Icons?.length) {\n      return;\n    }\n\n    const firstIcon = this.profile.Icons[0];\n\n    // get the current icon of the profile\n    switch (firstIcon.Type) {\n      case 'database':\n        this.portapi\n          .get<Record & { iconData: string }>(firstIcon.Value)\n          .subscribe((data) => {\n            this.iconData = data.iconData;\n            this.iconObjectURL = this.iconData;\n            this.cdr.markForCheck();\n          });\n        break;\n\n      case 'api':\n        this.iconData = `${this.httpAPI}/v1/profile/icon/${firstIcon.Value}`;\n        this.iconObjectURL = this.iconData;\n\n        break;\n\n      default:\n        console.error(`Unsupported icon type ${firstIcon.Type}`);\n    }\n\n    this.cdr.markForCheck();\n  }\n\n  ngOnDestroy() {\n    this.destory$.next();\n    this.destory$.complete();\n  }\n\n  addFingerprint() {\n    this.profile.Fingerprints?.push({\n      Key: '',\n      Operation: FingerpringOperation.Equal,\n      Value: '',\n      Type: FingerprintType.Path,\n    });\n  }\n\n  removeFingerprint(idx: number) {\n    this.profile.Fingerprints?.splice(idx, 1);\n    this.profile.Fingerprints = [...this.profile.Fingerprints!];\n  }\n\n  removeCopyFrom(idx: number) {\n    this.copySettingsFrom.splice(idx, 1);\n    this.copySettingsFrom = [...this.copySettingsFrom];\n  }\n\n  addCopyFrom() {\n    this.copySettingsFrom = [...this.copySettingsFrom, this.selectedCopyFrom!];\n    this.selectedCopyFrom = null;\n  }\n\n  drop(event: CdkDragDrop<string[]>) {\n    // create a copy of the array\n    this.copySettingsFrom = [...this.copySettingsFrom];\n    moveItemInArray(\n      this.copySettingsFrom,\n      event.previousIndex,\n      event.currentIndex\n    );\n\n    this.cdr.markForCheck();\n  }\n\n  deleteProfile() {\n    this.dialog\n      .confirm({\n        caption: 'Caution',\n        header: 'Confirm Profile Deletion',\n        message: 'Do you want to delete this profile?',\n        buttons: [\n          {\n            id: 'delete',\n            class: 'danger',\n            text: 'Delete',\n          },\n          {\n            id: 'abort',\n            class: 'outline',\n            text: 'Cancel',\n          },\n        ],\n      })\n      .onAction('delete', () => {\n        this.profileService\n          .deleteProfile(this.profile as AppProfile)\n          .subscribe({\n            next: () => this.dialgoRef.close('deleted'),\n            error: (err) => {\n              this.actionIndicator.error('Failed to delete profile', err);\n            },\n          });\n      });\n  }\n\n  resetIcon() {\n    this.iconChanged = true;\n    this.iconData = '';\n    this.iconType = '';\n    this.iconObjectURL = '';\n  }\n\n  save() {\n    if (!this.profile.ID) {\n      this.profile.ID = this.uuidv4();\n    }\n\n    if (!this.profile.Source) {\n      this.profile.Source = 'local';\n    }\n\n    let updateIcon: Observable<any> = of(undefined);\n\n    if (this.iconChanged) {\n      // delete any previously set icon\n      this.profile.Icons?.forEach((icon) => {\n        if (icon.Type === 'database') {\n          this.portapi.delete(icon.Value).subscribe();\n        }\n\n        // TODO(ppacher): we cannot yet delete API based icons ...\n      });\n\n      if (this.iconData !== '') {\n        // save the new icon in the cache database\n\n        // TODO(ppacher): we currently need to calls because the icon API in portmaster\n        // does not update the profile but just saves the file and returns the filename.\n        // So we still need to update the profile manually.\n        updateIcon = this.profileService\n          .setProfileIcon(this.iconData, this.iconType)\n          .pipe(\n            map(({ filename }) => {\n              this.profile.Icons = [\n                {\n                  Type: 'api',\n                  Value: filename,\n                  Source: 'user',\n                },\n              ];\n            })\n          );\n\n        // TODO(ppacher): reset presentationpath\n      } else {\n        // just clear out that there was an icon\n        this.profile.Icons = [];\n      }\n    }\n\n    if (this.profile.Fingerprints!.length > 1) {\n      this.profile.PresentationPath = '';\n    }\n    const oldConfig = this.profile.Config || {};\n    this.profile.Config = {};\n\n    mergeDeep(\n      this.profile.Config,\n      ...[...this.copySettingsFrom.map((p) => p.Config || {}), oldConfig]\n    );\n\n    updateIcon\n      .pipe(\n        switchMap(() => {\n          return this.profileService.saveProfile(this.profile as AppProfile);\n        })\n      )\n      .subscribe({\n        next: () => {\n          this.actionIndicator.success(\n            this.profile.Name!,\n            'Profile saved successfully'\n          );\n          this.dialgoRef.close('saved');\n        },\n        error: (err) => {\n          this.actionIndicator.error('Failed to save profile', err);\n        },\n      });\n  }\n\n  abort() {\n    this.dialgoRef.close('abort');\n  }\n\n  fileChangeEvent(fileInput: any) {\n    this.imageError = null;\n    this.iconData = '';\n    this.iconChanged = true;\n\n    if (fileInput.target.files && fileInput.target.files[0]) {\n      const max_size = 10 * 1024;\n      const allowed_types = [\n        'image/png',\n        'image/jpeg',\n        'image/svg',\n        'image/gif',\n        'image/tiff',\n      ];\n      const max_height = 512;\n      const max_width = 512;\n      const file: File = fileInput.target.files[0];\n\n      if (file.size > max_size) {\n        this.imageError = 'Maximum size allowed is ' + max_size / 1000 + 'KB';\n      }\n\n      if (!allowed_types.includes(file.type)) {\n        this.imageError = 'Only JPG, PNG, SVG, GIF or Tiff files are allowed';\n      }\n\n      this.iconType = file.type;\n\n      const reader = new FileReader();\n      reader.onload = (e: ProgressEvent<FileReader>) => {\n        const content: ArrayBuffer = e.target!.result! as ArrayBuffer;\n        const blob = new Blob([content], { type: file.type });\n\n        const image = new Image();\n        image.src = URL.createObjectURL(blob);\n        this.iconObjectURL = image.src;\n\n        image.onload = (rs: any) => {\n          const img_height = rs.currentTarget['height']!;\n          const img_width = rs.currentTarget['width'];\n\n          if (img_height > max_height && img_width > max_width) {\n            this.imageError =\n              'Maximum dimentions allowed ' +\n              max_height +\n              '*' +\n              max_width +\n              'px';\n          } else {\n            this.iconData = content;\n          }\n\n          this.cdr.markForCheck();\n        };\n\n        image.onerror = (err: any) => {\n          this.actionIndicator.error(\n            'Failed to get image',\n            this.actionIndicator.getErrorMessgae(err)\n          );\n        };\n\n        this.cdr.markForCheck();\n      };\n\n      reader.onerror = (err: any) => {\n        this.actionIndicator.error(\n          'Failed to get image',\n          this.actionIndicator.getErrorMessgae(err)\n        );\n      };\n\n      reader.readAsArrayBuffer(fileInput.target.files[0]);\n    }\n  }\n\n  private uuidv4(): string {\n    if (typeof crypto.randomUUID === 'function') {\n      return crypto.randomUUID();\n    }\n\n    // This one is not really random and not RFC compliant but serves enough for fallback\n    // purposes if the UI is opened in a browser that does not yet support randomUUID\n    console.warn('Using browser with lacking support for crypto.randomUUID()');\n\n    return Date.now().toString(36) + Math.random().toString(36).substring(2);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/edit-profile-dialog/index.ts",
    "content": "export * from './edit-profile-dialog';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/exit-screen/exit-screen.html",
    "content": "<div class=\"content-wrapper\">\n  <caption>Tip</caption>\n  <fa-icon class=\"close-icon\" icon=\"times\" (click)=\"cancel()\"></fa-icon>\n\n  <h1>Close User Interface</h1>\n\n  <span class=\"message\">Closing the User Interface does not shut down the Portmaster. You can shut down the Portmaster\n    in the Settings or the Tray Notifier.</span>\n\n  <div class=\"actions\">\n    <span>\n      <input name=\"neveragain\" id=\"neveragain\" [(ngModel)]=\"neveragain\" type=\"checkbox\"> <label for=\"neveragain\">Never\n        Show\n        Again</label>\n    </span>\n\n    <button (click)=\"closeUI()\" type=\"button\">Close UI</button>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/exit-screen/exit-screen.scss",
    "content": "caption {\n  @apply text-sm;\n  opacity  : .6;\n  font-size: .6rem;\n}\n\n.content-wrapper {\n  display       : flex;\n  flex-direction: column;\n  align-items   : flex-start;\n\n  h1 {\n    font-size    : 0.85rem;\n    font-weight  : 500;\n    margin-bottom: 1rem;\n  }\n\n  .message,\n  h1 {\n    flex-shrink  : 0;\n    text-overflow: ellipsis;\n    word-break   : normal;\n  }\n\n  .message {\n    font-size: 0.75rem;\n    flex-grow: 1;\n    opacity  : .6;\n  }\n\n  .close-icon {\n    position: absolute;\n    top     : 1rem;\n    right   : 1rem;\n    opacity : .7;\n    cursor  : pointer;\n\n    &:hover {\n      opacity: 1;\n    }\n  }\n\n  .actions {\n    margin-top     : 1rem;\n    width          : 100%;\n    display        : flex;\n    justify-content: space-between;\n    align-items    : center;\n\n    button {\n      @apply bg-info-blue;\n\n      &.danger {\n        @apply bg-info-red;\n      }\n    }\n\n    &>span {\n      display    : flex;\n      align-items: center;\n\n      label {\n        margin-left: .5rem;\n        user-select: none;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/exit-screen/exit-screen.ts",
    "content": "import { OverlayRef } from '@angular/cdk/overlay';\nimport { Component, Inject, InjectionToken } from '@angular/core';\nimport { SfngDialogRef, SFNG_DIALOG_REF } from '@safing/ui';\nimport { Observable, of } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\nimport { UIStateService } from 'src/app/services';\nimport { fadeInAnimation, fadeOutAnimation } from '../animations';\n\nexport const OVERLAYREF = new InjectionToken<OverlayRef>('OverlayRef');\n\n@Component({\n  templateUrl: './exit-screen.html',\n  styleUrls: ['./exit-screen.scss'],\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation,\n  ]\n})\nexport class ExitScreenComponent {\n  constructor(\n    @Inject(SFNG_DIALOG_REF) private _dialogRef: SfngDialogRef<any>,\n    private stateService: UIStateService,\n  ) { }\n\n  /** @private - used as ngModel form the template */\n  neveragain: boolean = false;\n\n  closeUI() {\n    const closeObserver = {\n      next: () => {\n        this._dialogRef.close('exit');\n      }\n    }\n\n    let close: Observable<any> = of(null);\n    if (this.neveragain) {\n      close = this.stateService.uiState()\n        .pipe(\n          map(state => {\n            state.hideExitScreen = true;\n            return state;\n          }),\n          switchMap(state => this.stateService.saveState(state)),\n        )\n    }\n    close.subscribe(closeObserver)\n  }\n\n  cancel() {\n    this._dialogRef.close()\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/exit-screen/exit.service.ts",
    "content": "import { IntegrationService } from './../../integration/integration';\nimport { Injectable, inject } from '@angular/core';\nimport { PortapiService } from '@safing/portmaster-api';\nimport { SfngDialogService } from '@safing/ui';\nimport { BehaviorSubject, merge, of } from 'rxjs';\nimport { catchError, debounceTime, distinctUntilChanged, map, skip, switchMap, tap, timeout } from 'rxjs/operators';\nimport { UIStateService } from 'src/app/services';\nimport { ActionIndicatorService } from '../action-indicator';\nimport { ExitScreenComponent } from './exit-screen';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\n\nconst MessageConnecting = 'Connecting to Portmaster';\nconst MessageShutdown = 'Shutting Down Portmaster';\nconst MessageRestart = 'Restarting Portmaster';\nconst MessageHidden = '';\n\nexport type OverlayMessage = typeof MessageConnecting\n  | typeof MessageShutdown\n  | typeof MessageRestart\n  | typeof MessageHidden;\n\n@Injectable({ providedIn: 'root' })\nexport class ExitService {\n  private integration = inject(INTEGRATION_SERVICE);\n\n  private hasOverlay = false;\n\n  private _showOverlay = new BehaviorSubject<OverlayMessage>(MessageConnecting);\n\n  /**\n   * Emits whenever the \"Connecting to ...\" or \"Restarting ...\" overlays\n   * should be shown. It actually emits the message that should be shown.\n   * An empty string indicates the overlay should be closed.\n   */\n  get showOverlay$() { return this._showOverlay.asObservable() }\n\n  constructor(\n    private stateService: UIStateService,\n    private portapi: PortapiService,\n    private dialog: SfngDialogService,\n    private uai: ActionIndicatorService,\n  ) {\n\n    this.portapi.connected$\n      .pipe(\n        distinctUntilChanged(),\n      )\n      .subscribe(connected => {\n        if (connected) {\n          this._showOverlay.next(MessageHidden);\n        } else if (this._showOverlay.getValue() !== MessageShutdown) {\n          this._showOverlay.next(MessageConnecting)\n        }\n      })\n\n\n    let restartInProgress = false;\n    merge<OverlayMessage[]>(\n      this.portapi.sub('runtime:modules/core/event/shutdown')\n        .pipe(map(() => MessageShutdown)),\n      this.portapi.sub('runtime:modules/core/event/restart')\n        .pipe(\n          tap(() => restartInProgress = true),\n          map(() => MessageRestart)\n        ),\n    )\n      .pipe(\n        tap(msg => this._showOverlay.next(msg)),\n        switchMap(() => this.portapi.connected$),\n        distinctUntilChanged(),\n        skip(1),\n        debounceTime(1000), // make sure we display the \"shutdown\" overlay for at least a second\n      )\n      .subscribe(connected => {\n        if (this._showOverlay.getValue() === MessageShutdown) {\n          setTimeout(() => {\n            this.integration.exitApp();\n          }, 1000)\n        }\n\n        if (connected && restartInProgress) {\n          restartInProgress = false;\n          this.portapi.reloadUI()\n            .pipe(\n              tap(() => {\n                setTimeout(() => window.location.reload(), 1000)\n              })\n            )\n            .subscribe(this.uai.httpObserver(\n              'Reloading UI ...',\n              'Failed to Reload UI',\n            ))\n        }\n      })\n\n    window.addEventListener('beforeunload', () => {\n      // best effort. may not work all the time depending on\n      // the current websocket buffer state\n      this.portapi.bridgeAPI('ui/reload', 'POST').subscribe();\n    })\n\n    this.integration.onExitRequest(() => {\n      this.stateService.uiState()\n        // make sure to not wait for the portmaster to start\n        .pipe(timeout(1000), catchError(() => of(null)))\n        .subscribe(state => {\n          if (state?.hideExitScreen) {\n            this.integration.exitApp();\n            return\n          }\n\n          if (this.hasOverlay) {\n            return;\n          }\n          this.hasOverlay = true;\n\n          this.dialog.create(ExitScreenComponent, { autoclose: true })\n            .onAction('exit', () => this.integration.exitApp())\n            .onClose.subscribe(() => this.hasOverlay = false);\n        })\n    })\n  }\n\n  shutdownPortmaster() {\n    this.dialog.confirm({\n      canCancel: true,\n      header: 'Shutting Down Portmaster',\n      message: 'Shutting down the Portmaster will stop all Portmaster components and will leave your system unprotected!',\n      caption: 'Caution',\n      buttons: [\n        {\n          id: 'shutdown',\n          class: 'danger',\n          text: 'Shut Down Portmaster'\n        }\n      ]\n    })\n      .onAction('shutdown', () => {\n        this.portapi.shutdownPortmaster()\n          .subscribe(this.uai.httpObserver(\n            'Shutting Down ...',\n            'Failed to Shut Down',\n          ))\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/exit-screen/index.ts",
    "content": "export * from './exit.service';\nexport * from './exit-screen';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/expertise/expertise-directive.ts",
    "content": "import { Directive, EmbeddedViewRef, Input, isDevMode, OnDestroy, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';\nimport { ExpertiseLevelNumber } from '@safing/portmaster-api';\nimport { Subscription } from 'rxjs';\nimport { ExpertiseService } from './expertise.service';\n\n// ExpertiseLevelOverwrite may be called to display a DOM node decorated\n// with [appExpertiseLevel] even if the current user setting does not\n// match the required expertise.\nexport type ExpertiseLevelOverwrite<T> = (lvl: ExpertiseLevelNumber, data: T) => boolean;\n@Directive({\n  selector: '[appExpertiseLevel]',\n})\nexport class ExpertiseDirective<T> implements OnInit, OnDestroy {\n  private allowedValue: ExpertiseLevelNumber = ExpertiseLevelNumber.user;\n  private subscription = Subscription.EMPTY;\n  private view: EmbeddedViewRef<any> | null = null;\n\n  @Input()\n  set appExpertiseLevelOverwrite(fn: ExpertiseLevelOverwrite<T>) {\n    this._levelOverwriteFn = fn;\n    this.update();\n  }\n  private _levelOverwriteFn: ExpertiseLevelOverwrite<T> | null = null;\n\n  @Input()\n  set appExpertiseLevelData(d: T) {\n    this._data = d;\n    this.update();\n  }\n  private _data: T | undefined = undefined;\n\n  @Input()\n  set appExpertiseLevel(lvl: ExpertiseLevelNumber | string) {\n    if (typeof lvl === 'string') {\n      lvl = ExpertiseLevelNumber[lvl as any];\n    }\n    if (lvl === undefined) {\n      if (isDevMode()) {\n        throw new Error(`[appExpertiseLevel] got undefined expertise-level value`);\n      }\n      return;\n    }\n    if (lvl !== this.allowedValue) {\n      this.allowedValue = lvl as ExpertiseLevelNumber;\n      this.update();\n    }\n  }\n\n  private update() {\n    const current = ExpertiseLevelNumber[this.expertiseService.currentLevel];\n    let hide = current < this.allowedValue;\n\n    // if there's an overwrite function defined make sue to check that.\n    if (hide && !!this._levelOverwriteFn) {\n      hide = !this._levelOverwriteFn(current, this._data!);\n      if (!hide) {\n        console.log(\"overwritten\", current, this._data);\n      }\n    }\n\n    if (hide) {\n      if (!!this.view) {\n        this.view.destroy();\n        this.viewContainer.clear();\n        this.view = null;\n      }\n      return\n    }\n\n    if (!!this.view) {\n      this.view.markForCheck();\n      return;\n    }\n\n    this.view = this.viewContainer.createEmbeddedView(this.templateRef);\n    this.view.detectChanges();\n  }\n\n  constructor(\n    private expertiseService: ExpertiseService,\n    private templateRef: TemplateRef<any>,\n    private viewContainer: ViewContainerRef\n  ) { }\n\n  ngOnInit() {\n    this.subscription = this.expertiseService.change.subscribe(() => this.update())\n  }\n\n  ngOnDestroy() {\n    this.viewContainer.clear();\n    this.subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/expertise/expertise-switch.html",
    "content": "<sfng-tipup key=\"uiMode\" placement=\"left\" [anchor]=\"host\"></sfng-tipup>\n<sfng-select [ngModel]=\"(currentLevel | async)\" (ngModelChange)=\"selectLevel($event)\" mode=\"single\" sortItems=\"false\">\n  <sfng-select-item *sfngSelectValue=\"expertiseLevels.User\">\n    Simple Interface\n  </sfng-select-item>\n\n  <sfng-select-item *sfngSelectValue=\"expertiseLevels.Expert\">\n    Advanced Interface\n  </sfng-select-item>\n\n  <ng-container *ngIf=\"savedLevel === expertiseLevels.Developer\">\n    <sfng-select-item *sfngSelectValue=\"expertiseLevels.Developer\">\n      Developer Interface\n    </sfng-select-item>\n  </ng-container>\n</sfng-select>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/expertise/expertise-switch.scss",
    "content": ":host {\n  display: flex;\n  @apply pl-2;\n  user-select: none;\n  flex-direction: row;\n  align-items: center;\n  justify-content: center;\n}\n\nsfng-tipup {\n  margin-right: 0.5rem;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/expertise/expertise-switch.ts",
    "content": "import { Component, ElementRef } from '@angular/core';\nimport { ExpertiseLevel } from '@safing/portmaster-api';\nimport { ExpertiseService } from './expertise.service';\n\n@Component({\n  selector: 'app-expertise',\n  templateUrl: './expertise-switch.html',\n  styleUrls: ['./expertise-switch.scss']\n})\nexport class ExpertiseComponent {\n  /** @private provide the expertise-level enums to the template */\n  readonly expertiseLevels = ExpertiseLevel;\n\n  currentLevel = this.expertiseService.change;\n\n  /**\n   * @private\n   * Getter to access the expertise level as saved in the database\n   */\n  get savedLevel() {\n    return this.expertiseService.savedLevel;\n  }\n\n  constructor(\n    private expertiseService: ExpertiseService,\n    public host: ElementRef<any>,\n  ) { }\n\n  /**\n   * @private\n   * Configures a new expertise level\n   *\n   * @param lvl The new expertise level to use\n   */\n  selectLevel(lvl: ExpertiseLevel) {\n    this.expertiseService.setLevel(lvl);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/expertise/expertise.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { FormsModule } from \"@angular/forms\";\nimport { SfngSelectModule, SfngTipUpModule } from \"@safing/ui\";\nimport { ExpertiseDirective } from \"./expertise-directive\";\nimport { ExpertiseComponent } from \"./expertise-switch\";\n\n@NgModule({\n  imports: [\n    SfngSelectModule,\n    CommonModule,\n    SfngTipUpModule,\n    FormsModule,\n  ],\n  declarations: [\n    ExpertiseComponent,\n    ExpertiseDirective,\n  ],\n  exports: [\n    ExpertiseComponent,\n    ExpertiseDirective,\n  ]\n})\nexport class ExpertiseModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/expertise/expertise.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { ConfigService, ExpertiseLevel, StringSetting } from '@safing/portmaster-api';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { distinctUntilChanged, map, repeat, share } from 'rxjs/operators';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class ExpertiseService {\n  /** If the user overwrites the expertise level on a per-page setting we track that here */\n  private _localOverwrite: ExpertiseLevel | null = null;\n  private _currentLevel: ExpertiseLevel = ExpertiseLevel.User;\n\n  /** Watches the expertise level as saved in the configuration */\n  private _savedLevel$ = this.configService.watch<StringSetting>('core/expertiseLevel')\n    .pipe(\n      repeat({ delay: 2000 }),\n      map(upd => {\n        return upd as ExpertiseLevel;\n      }),\n      distinctUntilChanged(),\n      share(),\n    );\n\n  private level$ = new BehaviorSubject(ExpertiseLevel.User);\n\n  get currentLevel() {\n    return this._localOverwrite === null\n      ? this._currentLevel\n      : this._localOverwrite;\n  }\n\n  get savedLevel() {\n    return this._currentLevel;\n  }\n\n  get change(): Observable<ExpertiseLevel> {\n    return this.level$.asObservable();\n  }\n\n  constructor(private configService: ConfigService) {\n    this._savedLevel$\n      .subscribe(lvl => {\n        this._currentLevel = lvl;\n        if (this._localOverwrite === null) {\n          this.level$.next(lvl);\n        }\n      });\n  }\n\n  setLevel(lvl: ExpertiseLevel | null) {\n    if (lvl === this._currentLevel) {\n      lvl = null;\n    }\n\n    this._localOverwrite = lvl;\n    if (!!lvl) {\n      this.level$.next(lvl);\n    } else {\n      this.level$.next(this._currentLevel!);\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/expertise/index.ts",
    "content": "export * from './expertise-directive';\nexport * from './expertise-switch';\nexport * from './expertise.service';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/external-link.directive.ts",
    "content": "import { isPlatformBrowser } from '@angular/common';\nimport {\n  Directive,\n  HostBinding, HostListener, Inject,\n  Input, OnChanges, PLATFORM_ID, inject\n} from '@angular/core';\nimport { INTEGRATION_SERVICE } from '../integration';\n\n@Directive({\n  // eslint-disable-next-line @angular-eslint/directive-selector\n  selector: 'a[href]'\n})\nexport class ExternalLinkDirective implements OnChanges {\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  @HostBinding('attr.rel')\n  relAttr = '';\n\n  @HostBinding('attr.target')\n  targetAttr = '';\n\n  @HostBinding('attr.href')\n  hrefAttr = '';\n\n  @Input()\n  href: string = '';\n\n  constructor(@Inject(PLATFORM_ID) private platformId: string) { }\n\n  @HostListener('click', ['$event'])\n  onClick(event: Event) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.integration.openExternal(this.href);\n  }\n\n  ngOnChanges() {\n    this.hrefAttr = this.href;\n\n    if (this.isLinkExternal()) {\n      this.relAttr = 'noopener';\n      this.targetAttr = '_blank';\n    }\n  }\n\n  private isLinkExternal() {\n    return (\n      isPlatformBrowser(this.platformId) &&\n      !this.href.includes(location.hostname)\n    );\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/feature-scout/feature-scout.html",
    "content": "<ng-container *appExpertiseLevel=\"'developer'\">\n<div *ngIf=\"packageHasSPN || packageHasHistory\" class=\"pb-4\">\n\n  <div class=\"flex flex-row justify-center w-full gap-2\" [routerLink]=\"['/dashboard']\">\n    <span *ngIf=\"packageHasHistory\">\n      <svg\n        xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"\n        width=\"18px\" class=\"feature-icon\" [class.feature-icon-off]=\"!historyEnabled\">\n        <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n          d=\"M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25\" />\n      </svg>\n    </span>\n\n    <span *ngIf=\"packageHasSPN\">\n      <svg\n        xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"\n        width=\"18px\" class=\"feature-icon\" [class.feature-icon-off]=\"!spnEnabled\">\n        <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\">\n          <path\n            d=\"M6.488 15.581c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0M13.415 3.586c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.049-.781 2.83 0M20.343 15.58c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0\">\n          </path>\n          <path\n            d=\"M17.721 18.581C16.269 20.071 14.246 21 12 21c-1.146 0-2.231-.246-3.215-.68M4.293 15.152c-.56-1.999-.352-4.21.769-6.151.574-.995 1.334-1.814 2.205-2.449M13.975 5.254c2.017.512 3.834 1.799 4.957 3.743.569.985.899 2.041 1.018 3.103\">\n          </path>\n        </g>\n      </svg>\n    </span>\n  </div>\n\n  <div *ngIf=\"spnEnabled\" class=\"flex flex-row justify-center w-full gap-2 pt-2\">\n    <div class=\"status-info\" [routerLink]=\"['/spn']\">\n\n      <span [ngSwitch]=\"spnStatus?.Status\" [sfng-tooltip]=\"spnStatus?.Status === 'connected' ? spnTooltipTemplate : null\">\n        <ng-template ngSwitchCase=\"disabled\">\n          SPN is connecting...<br>\n          Fail-safe blocking enabled\n        </ng-template>\n        <ng-template ngSwitchCase=\"failed\">\n          <span class=\"text-red-300\">SPN failed to connect</span><br>\n          Fail-safe blocking enabled\n        </ng-template>\n        <ng-template ngSwitchCase=\"connecting\">\n          SPN is connecting...<br>\n          Fail-safe blocking enabled\n        </ng-template>\n        <ng-template ngSwitchCase=\"connected\">\n          <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12px\" height=\"12px\" fill=\"currentColor\" viewBox=\"0 0 16 16\"\n            class=\"text-tertiary\" class=\"inline-block -mt-0.5\">\n            <path d=\"M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-8 3a3 3 0 1 0 0-6 3 3 0 0 0 0 6z\"/>\n          </svg>\n          {{ spnStatus?.HomeHubName }}\n          <span class=\"text-tertiary\">\n            in\n          </span>\n          <span *ngIf=\"!!spnStatus?.ConnectedCountry?.Code\" [appCountryFlags]=\"spnStatus!.ConnectedCountry!.Code\"></span>\n          {{ spnStatus?.ConnectedCountry?.Name }}\n        </ng-template>\n      </span>\n\n    </div>\n  </div>\n\n    <!-- </div>\n      <h2 class=\"p-0 m-0 font-light outline-none cursor-pointer test-base\" [routerLink]=\"['/spn']\">SPN</h2>\n      <sfng-toggle [ngModel]=\"spnEnabled\" (ngModelChange)=\"setSPNEnabled($event)\" class=\"absolute top-1 right-0\"></sfng-toggle>\n\n      <ng-container *ngIf=\"spnEnabled\">\n        <span [ngSwitch]=\"spnStatus?.Status\" class=\"-mt-1 text-xs font-medium text-secondary\">\n          <ng-template ngSwitchCase=\"disabled\">\n            Disabled\n          </ng-template>\n          <ng-template ngSwitchCase=\"failed\">\n            Failed to connect<br>\n            Fail-safe blocking enabled\n          </ng-template>\n          <ng-template ngSwitchCase=\"connecting\">\n            Connecting...<br>\n            Fail-safe blocking enabled\n          </ng-template>\n          <ng-template ngSwitchCase=\"connected\">\n            You're protected\n          </ng-template>\n        </span>\n        <br>\n        <span class=\"text-secondary text-xxs\" *appExpertiseLevel=\"'advanced'\">\n          Home: <u>{{ spnStatus?.ConnectedIP }}</u> via <u>{{ spnStatus?.ConnectedTransport}}</u>\n        </span>\n      </ng-container>\n    </div>\n\n    <div *ngIf=\"packageHasHistory\" class=\"relative mt-3\">\n      <h2 class=\"p-0 m-0 font-light outline-none cursor-pointer test-base\" [routerLink]=\"['/monitor']\">History</h2>\n      <sfng-toggle [ngModel]=\"historyEnabled\" (ngModelChange)=\"setHistoryEnabled($event)\" class=\"absolute top-1 right-0\"></sfng-toggle>\n    </div> -->\n\n</div>\n</ng-container>\n\n<ng-template #spnTooltipTemplate>\n  SPN Home (Entry) Node\n  <ul class=\"pl-4 list-disc\">\n    <li>Connected to {{ spnStatus?.ConnectedIP }}</li>\n    <li>Uplink is always encrypted</li>\n    <li>Built with transport/decoy {{ spnStatus?.ConnectedTransport }}</li>\n  </ul>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/feature-scout/feature-scout.scss",
    "content": ".feature-icon {\n  @apply text-primary text-opacity-80;\n\n  &.feature-icon-off {\n    opacity: 0.25;\n  }\n}\n\n.status-info {\n  @apply text-primary text-opacity-80 text-xxs text-center;\n\n  &:hover {\n    cursor: default;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/feature-scout/feature-scout.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, OnInit, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { BoolSetting, ConfigService, FeatureID, Netquery, SPNService, SPNStatus, UserProfile } from \"@safing/portmaster-api\";\nimport { catchError, of } from \"rxjs\";\nimport { fadeInAnimation, fadeOutAnimation } from \"../animations\";\nimport { CountryFlagModule } from 'src/app/shared/country-flag';\n\n@Component({\n  selector: 'app-feature-scout',\n  templateUrl: './feature-scout.html',\n  styleUrls: [\n    './feature-scout.scss'\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation,\n  ]\n})\nexport class FeatureScoutComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  /** The current SPN user profile */\n  profile: UserProfile | null = null;\n\n  /** Whether or not the SPN is currently enabled */\n  spnEnabled = false;\n\n  /** The current status of the SPN module */\n  spnStatus: SPNStatus | null = null;\n\n  /** Whether or not the Network History is currently enabled */\n  historyEnabled = false;\n\n  /** Returns whether or not the current package has the SPN feature */\n  get packageHasSPN() {\n    return this.profile?.current_plan?.feature_ids?.includes(FeatureID.SPN)\n  }\n\n  /** Returns whether or not the current package has the Network History feature */\n  get packageHasHistory() {\n    return this.profile?.current_plan?.feature_ids?.includes(FeatureID.History)\n  }\n\n  constructor(\n    private configService: ConfigService,\n    private spnService: SPNService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  ngOnInit(): void {\n    this.spnService\n      .profile$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        catchError(() => of(null))\n      )\n      .subscribe(profile => {\n        this.profile = profile || null;\n\n        this.cdr.markForCheck();\n      });\n\n    this.spnService.status$\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(status => {\n        this.spnStatus = status;\n\n        this.cdr.markForCheck();\n      })\n\n    this.configService.watch<BoolSetting>(\"spn/enable\")\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(value => {\n        this.spnEnabled = value;\n\n        this.cdr.markForCheck();\n      });\n\n    this.configService.watch<BoolSetting>(\"history/enable\")\n    .pipe(takeUntilDestroyed(this.destroyRef))\n    .subscribe(value => {\n      this.historyEnabled = value;\n\n      this.cdr.markForCheck();\n    });\n  }\n\n  setSPNEnabled(v: boolean) {\n    this.configService.save(`spn/enable`, v)\n      .subscribe();\n  }\n\n  setHistoryEnabled(v: boolean) {\n    this.configService.save(`history/enable`, v)\n      .subscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/feature-scout/index.ts",
    "content": "export * from './feature-scout';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/focus/focus.directive.ts",
    "content": "import { coerceBooleanProperty } from \"@angular/cdk/coercion\";\nimport { Directive, ElementRef, Input, OnInit } from \"@angular/core\";\n\n@Directive({\n  // eslint-disable-next-line @angular-eslint/directive-selector\n  selector: '[autoFocus]',\n})\nexport class AutoFocusDirective implements OnInit {\n  private _focus = true;\n  private _afterInit = false;\n\n  @Input('autoFocus')\n  set focus(v: any) {\n    this._focus = coerceBooleanProperty(v) !== false;\n\n    if (this._afterInit && this.elementRef) {\n      this.elementRef.nativeElement.focus()\n    }\n  }\n\n  constructor(private elementRef: ElementRef) { }\n\n  ngOnInit(): void {\n    setTimeout(() => {\n      if (this._focus) {\n        this.elementRef.nativeElement.focus();\n      }\n    }, 100)\n\n    this._afterInit = true;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/focus/focus.module.ts",
    "content": "import { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { AutoFocusDirective } from \"./focus.directive\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n  ],\n  declarations: [\n    AutoFocusDirective,\n  ],\n  exports: [\n    AutoFocusDirective,\n  ]\n})\nexport class SfngFocusModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/focus/index.ts",
    "content": "export { AutoFocusDirective } from './focus.directive';\nexport * from './focus.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/fuzzySearch/fuse.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { deepClone } from '@safing/portmaster-api';\nimport Fuse from 'fuse.js';\n\nexport type FuseResult<T> = Fuse.FuseResult<T & {\n  highlighted?: string;\n}>;\n\nexport interface FuseSearchOpts<T> extends Fuse.IFuseOptions<T> {\n  minSearchTermLength?: number;\n  maximumScore?: number;\n}\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class FuzzySearchService {\n\n  readonly defaultOptions: FuseSearchOpts<any> = {\n    minMatchCharLength: 2,\n    includeMatches: true,\n    includeScore: true,\n    minSearchTermLength: 3,\n  };\n\n  searchList<T extends {}>(list: Array<T>, searchTerms: string, options: FuseSearchOpts<T> & { disableHighlight?: boolean } = {}): Array<FuseResult<T>> {\n    const opts: FuseSearchOpts<T> = {\n      ...this.defaultOptions,\n      ...options,\n    }\n\n    let result: FuseResult<T>[] = [];\n\n\n    if (searchTerms && searchTerms.length >= (opts.minSearchTermLength || 0)) {\n      let fuse = new Fuse(list, opts);\n      result = fuse.search(searchTerms);\n\n    } else {\n      result = list.map((item, index) => ({\n        item: item,\n        refIndex: index,\n        score: 0,\n      }))\n    }\n\n    if (!!options.disableHighlight) {\n      return result;\n    }\n\n    return this.handleHighlight(result, options);\n  }\n\n  private handleHighlight<T extends {}>(result: FuseResult<T>[], options: FuseSearchOpts<T>): FuseResult<T>[] {\n    return result.map(matchObject => {\n      matchObject.item = deepClone(matchObject.item);\n\n      if (!matchObject.matches) {\n        return matchObject;\n      }\n\n      for (let match of matchObject.matches!) {\n        const indices = match.indices;\n\n        let highlightOffset: number = 0;\n\n        for (let indice of indices) {\n          let initialValue = getFromMatch(matchObject, match);\n\n          const startOffset = indice[0] + highlightOffset;\n          const endOffset = indice[1] + highlightOffset + 1;\n\n          if (endOffset - startOffset < 4) {\n            continue\n          }\n\n          let highlightedTerm = initialValue.substring(startOffset, endOffset);\n          let newValue = initialValue.substring(0, startOffset) + '<em class=\"search-result\">' + highlightedTerm + '</em>' + initialValue.substring(endOffset);\n\n          highlightOffset += '<em class=\"search-result\"></em>'.length;\n\n          setOnMatch(matchObject, match, newValue);\n        }\n      }\n\n      return matchObject;\n    });\n  }\n}\n\nfunction getFromMatch<T>(result: Fuse.FuseResult<T>, match: Fuse.FuseResultMatch): string {\n  if (match.refIndex === undefined) {\n    return (result.item as any)[match.key!];\n  }\n  return (result.item as any)[match.key!][match.refIndex];\n}\n\nfunction setOnMatch<T>(result: Fuse.FuseResult<T>, match: Fuse.FuseResultMatch, value: string) {\n  if (match.refIndex === undefined) {\n    (result.item as any)[match.key!] = value;\n    return;\n  }\n\n  (result.item as any)[match.key!][match.refIndex] = value;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/fuzzySearch/index.ts",
    "content": "import Fuse from 'fuse.js';\n\nexport { FuseSearchOpts, FuzzySearchService } from './fuse.service';\nexport { FuzzySearchPipe } from './search-pipe';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/fuzzySearch/search-pipe.ts",
    "content": "import { Pipe, PipeTransform } from '@angular/core';\nimport { FuseResult, FuseSearchOpts, FuzzySearchService } from './fuse.service';\n\n\n@Pipe({\n  name: 'fuzzySearch',\n})\nexport class FuzzySearchPipe implements PipeTransform {\n  constructor(\n    private FusejsService: FuzzySearchService\n  ) { }\n\n  transform<T extends object>(elements: Array<T>,\n    searchTerms: string,\n    options: FuseSearchOpts<T> = {}): Array<FuseResult<T>> {\n\n    return this.FusejsService.searchList(elements, searchTerms, options);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/loading/index.ts",
    "content": "export { LoadingComponent } from './loading';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/loading/loading.html",
    "content": "<span class=\"dot\"></span>\n<span class=\"dot\"></span>\n<span class=\"dot\"></span>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/loading/loading.scss",
    "content": ":host {\n  --internal-dot-size       : var(--dot-size, 5px);\n  --internal-animation-speed: var(--animation-speed, 1.3s);\n\n  display        : flex;\n  position       : relative;\n  justify-content: space-evenly;\n  align-items    : flex-end;\n  width          : var(--animation-width, calc(var(--internal-dot-size) * 5));\n\n  height: calc(var(--internal-dot-size) * 3);\n\n  &.animate {\n    .dot {\n      display    : block;\n      flex-shrink: 0;\n      flex-grow  : 0;\n      width      : var(--internal-dot-size);\n      height     : var(--internal-dot-size);\n\n      @apply shadow-inner-xs;\n      @apply rounded-full;\n      @apply bg-buttons-icon;\n\n      animation: wave var(--internal-animation-speed) linear infinite;\n\n      &:nth-child(2) {\n        animation-delay: -1.1s;\n      }\n\n      &:nth-child(3) {\n        animation-delay: -0.9s;\n      }\n    }\n  }\n\n}\n\n@keyframes wave {\n\n  0%,\n  60%,\n  100% {\n    transform: initial;\n    @apply bg-buttons-light;\n  }\n\n  90% {\n    transform       : translateY(var(--loading-height, -9px));\n    background-color: white;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/loading/loading.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding } from '@angular/core';\n\n@Component({\n  selector: 'app-loading',\n  templateUrl: './loading.html',\n  styleUrls: ['./loading.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class LoadingComponent {\n  @HostBinding('class.animate')\n  _animate = true;\n\n  constructor(private changeDetectorRef: ChangeDetectorRef) { }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/index.ts",
    "content": "export { MenuComponent, MenuTriggerComponent, MenuItemComponent, MenuGroupComponent } from './menu';\nexport * from './menu.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/menu-group.scss",
    "content": ":host {\n  display: block;\n  width: 100%;\n\n  @apply p-1;\n  @apply px-4;\n  @apply text-secondary;\n\n  display: block;\n  text-transform: uppercase;\n  font-size: 0.7rem;\n  opacity: .7;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/menu-item.scss",
    "content": ":host {\n  @apply block w-full;\n\n  cursor: pointer;\n  @apply p-2;\n  @apply px-4 text-primary text-xxs;\n  font-weight: 500;\n\n  &:hover {\n    @apply bg-gray-300;\n  }\n\n  &.disabled {\n    cursor: not-allowed;\n    opacity: 0.5;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/menu-trigger.html",
    "content": "<div (click)=\"toggle($event)\" cdkOverlayOrigin>\n  <div class=\"text-opacity-75 dropdown text-primary hover:text-primary hover:text-opacity-100\">\n    <ng-container *ngIf=\"!useContent\">\n      <svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"Layer 2\" viewBox=\"0 0 11.86 19.86\" fill=\"currentColor\">\n        <circle cx=\"1.93\" cy=\"1.93\" r=\"1.93\" />\n        <circle cx=\"1.93\" cy=\"9.93\" r=\"1.93\" />\n        <circle cx=\"1.93\" cy=\"17.93\" r=\"1.93\" />\n      </svg>\n    </ng-container>\n    <ng-container *ngIf=\"useContent\">\n      <ng-content></ng-content>\n    </ng-container>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/menu-trigger.scss",
    "content": ":host {\n  user-select: none;\n  margin-right: .5rem;\n  display: block;\n  @apply rounded-t-sm;\n}\n\ndiv {\n  cursor: pointer;\n  display: flex;\n  @apply rounded-t;\n  flex-grow: 0;\n  transition: all .1s ease-in-out;\n  justify-content: center;\n  align-items: center;\n  @apply py-1;\n  @apply px-3;\n}\n\n.dropdown {\n  margin-left: 1px;\n  height: auto;\n  padding: 0;\n  margin: 0;\n\n  svg {\n    opacity: 0.7;\n    fill: var(--text-primary);\n    width: 0.51rem;\n    transition: all cubic-bezier(0.175, 0.885, 0.32, 1.275) .2s;\n\n    transform: rotate(90deg);\n    position: relative;\n    top: 3px;\n  }\n}\n\n:host.active {\n  @apply bg-gray-400;\n  color: white !important;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/menu.html",
    "content": "<sfng-dropdown externalTrigger=\"true\" #dropdown=\"sfngDropdown\" [offsetY]=\"offsetY || 0\" [offsetX]=\"offsetX\"\n  [overlayClass]=\"overlayClass  || ''\">\n  <div class=\"flex flex-col flex-grow w-full h-full bg-gray-400 shadow select-none\">\n    <ng-content></ng-content>\n  </div>\n</sfng-dropdown>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/menu.module.ts",
    "content": "import { OverlayModule } from \"@angular/cdk/overlay\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { SfngDropDownModule } from \"@safing/ui\";\nimport { MenuComponent, MenuGroupComponent, MenuItemComponent, MenuTriggerComponent } from \"./menu\";\n\n@NgModule({\n  imports: [\n    SfngDropDownModule,\n    CommonModule,\n    OverlayModule,\n  ],\n  declarations: [\n    MenuComponent,\n    MenuGroupComponent,\n    MenuTriggerComponent,\n    MenuItemComponent,\n  ],\n  exports: [\n    MenuComponent,\n    MenuGroupComponent,\n    MenuTriggerComponent,\n    MenuItemComponent,\n  ],\n})\nexport class SfngMenuModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/menu/menu.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { CdkOverlayOrigin } from '@angular/cdk/overlay';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, EventEmitter, HostBinding, HostListener, Input, Output, QueryList, ViewChild } from '@angular/core';\nimport { SfngDropdownComponent } from '@safing/ui';\n\n@Component({\n  selector: 'app-menu-trigger',\n  templateUrl: './menu-trigger.html',\n  styleUrls: ['./menu-trigger.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MenuTriggerComponent {\n  @ViewChild(CdkOverlayOrigin, { static: true })\n  origin!: CdkOverlayOrigin;\n\n  @Input()\n  menu: MenuComponent | null = null;\n\n  @Input()\n  set useContent(v: any) {\n    this._useContent = coerceBooleanProperty(v);\n  }\n  get useContent() { return this._useContent; }\n  private _useContent: boolean = false;\n\n  @HostBinding('class.active')\n  get isOpen() {\n    if (!this.menu) {\n      return false;\n    }\n\n    return this.menu.dropdown.isOpen;\n  }\n\n  constructor(\n    public changeDetectorRef: ChangeDetectorRef,\n  ) { }\n\n  toggle(event: MouseEvent) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.menu?.dropdown.toggle(this.origin)\n  }\n}\n\n@Component({\n  selector: 'app-menu-item',\n  template: '<ng-content></ng-content>',\n  styleUrls: ['./menu-item.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MenuItemComponent {\n  @Input()\n  @HostBinding('class.disabled')\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v);\n  }\n  get disabled() { return this._disabled; }\n  private _disabled: boolean = false;\n\n  @HostListener('click', ['$event'])\n  closeMenu(event: MouseEvent) {\n    if (this.disabled) {\n      return;\n    }\n    this.activate.next(event);\n    this.menu.dropdown.close();\n  }\n\n  /**\n   * activate fires when the menu item is clicked.\n   * Use activate rather than (click)=\"\" if you want\n   * [disabled] to be considered.\n   */\n  @Output()\n  activate = new EventEmitter<MouseEvent>();\n\n  constructor(private menu: MenuComponent) { }\n}\n\n@Component({\n  selector: 'app-menu-group',\n  template: '<ng-content></ng-content>',\n  styleUrls: ['./menu-group.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MenuGroupComponent { }\n\n@Component({\n  selector: 'app-menu',\n  exportAs: 'appMenu',\n  templateUrl: './menu.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MenuComponent {\n  @ContentChildren(MenuItemComponent)\n  items: QueryList<MenuItemComponent> | null = null;\n\n  @ViewChild(SfngDropdownComponent, { static: true })\n  dropdown!: SfngDropdownComponent;\n\n  @Input()\n  offsetY?: string | number;\n\n  @Input()\n  offsetX?: string | number;\n\n  @Input()\n  overlayClass?: string;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/multi-switch/index.ts",
    "content": "export { MultiSwitchComponent } from './multi-switch';\nexport { SwitchItemComponent } from './switch-item';\nexport * from './multi-switch.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/multi-switch/multi-switch.html",
    "content": "<div class=\"buttons\">\n  <ng-content></ng-content>\n  <sfng-tipup style=\"margin-left: 1rem;\" *ngIf=\"!!tipUpKey\" [key]=\"tipUpKey\" [anchor]=\"host\"></sfng-tipup>\n</div>\n<span #marker class=\"marker\" (mousedown)=\"dragStarted($event)\"></span>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/multi-switch/multi-switch.module.ts",
    "content": "import { DragDropModule } from \"@angular/cdk/drag-drop\";\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule } from \"@angular/core\";\nimport { FormsModule } from \"@angular/forms\";\nimport { SfngTipUpModule, SfngTooltipModule } from \"@safing/ui\";\nimport { MultiSwitchComponent } from \"./multi-switch\";\nimport { SwitchItemComponent } from \"./switch-item\";\n\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    SfngTooltipModule,\n    SfngTipUpModule,\n    DragDropModule,\n  ],\n  declarations: [\n    MultiSwitchComponent,\n    SwitchItemComponent,\n  ],\n  exports: [\n    MultiSwitchComponent,\n    SwitchItemComponent,\n  ],\n})\nexport class SfngMultiSwitchModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/multi-switch/multi-switch.scss",
    "content": ".buttons {\n  display: flex;\n  align-items: flex-end;\n  position: relative;\n  height: 3rem;\n  flex-grow: 0;\n  width: fit-content;\n\n  fa-icon[icon*=\"question-circle\"] {\n    height: 100%;\n    display: flex;\n    align-items: center;\n    margin-left: 1rem;\n  }\n}\n\n.marker {\n  display: block;\n  height: 16px;\n  width: 16px;\n  position: absolute;\n  bottom: -8px;\n  cursor: grab;\n  transition: all .5s cubic-bezier(0.175, 0.885, 0.32, 1.075);\n  @apply rounded-full;\n}\n\n:host {\n  flex-grow: 0;\n  width: fit-content;\n  display: block;\n  outline: none;\n  user-select: none;\n\n  &.disabled {\n    .marker {\n      cursor: unset;\n    }\n  }\n\n  &.grabbing {\n    .marker {\n      cursor: grabbing;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/multi-switch/multi-switch.ts",
    "content": "import { ListKeyManager } from '@angular/cdk/a11y';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, ElementRef, EventEmitter, forwardRef, HostBinding, HostListener, Inject, Input, NgZone, OnDestroy, Output, QueryList, Renderer2, ViewChild } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { animationFrameScheduler, fromEvent, Subscription } from 'rxjs';\nimport { map, startWith, subscribeOn, take, takeUntil } from 'rxjs/operators';\nimport { SwitchItemComponent } from './switch-item';\n\n@Component({\n  selector: 'app-multi-switch',\n  templateUrl: './multi-switch.html',\n  styleUrls: ['./multi-switch.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => MultiSwitchComponent),\n      multi: true,\n    }\n  ]\n})\nexport class MultiSwitchComponent<T> implements OnDestroy, AfterViewInit, ControlValueAccessor {\n  /** Subscription to all button-select changes */\n  private sub = Subscription.EMPTY;\n\n  /** Holds the current x-translation offset for the marker */\n  private markerOffset: number = 0;\n\n  /** Keymanager used for keyboard navigation support */\n  private keyManager: ListKeyManager<SwitchItemComponent<T>> | null = null;\n\n  /** Subscription to the key manager */\n  private keyManagerSub = Subscription.EMPTY;\n\n  @Input()\n  tipUpKey: string = '';\n\n  /** All buttons projected into the multi-switch */\n  @ContentChildren(SwitchItemComponent)\n  buttons: QueryList<SwitchItemComponent<T>> | null = null;\n\n  /** Emits whenever the selected button changes. */\n  @Output()\n  changed = new EventEmitter<T>();\n\n  /** Reference to the marker inside our view container */\n  @ViewChild('marker', { read: ElementRef, static: true })\n  marker: ElementRef | null = null;\n\n  @HostListener('blur')\n  onBlur() {\n    this._onTouch();\n  }\n\n  @HostBinding('attr.tabindex')\n  readonly tabindex = 0;\n\n  @HostListener('keyup', ['$event'])\n  onKeyUp(event: KeyboardEvent) {\n    if (this.disabled) {\n      return;\n    }\n    this.keyManager!.onKeydown(event);\n  }\n\n  /** Whether or not the switch button component is disabled */\n  @Input()\n  @HostBinding('class.disabled')\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v);\n\n    // Update all buttons states as well.\n    if (!!this.buttons) {\n      this.buttons.forEach(btn => btn.disabled = this.disabled);\n    }\n  }\n  get disabled() { return this._disabled; }\n  private _disabled = false;\n\n  @HostBinding('class.grabbing')\n  isGrabbing = false;\n\n  /** External write tracks calls to writeValue so we don't end up re-emitting the values. */\n  private externalWrite = false;\n\n  /** Which button is currently active (and holds the marker) */\n  activeButton: T | null = null;\n\n  constructor(\n    public host: ElementRef,\n    private changeDetectorRef: ChangeDetectorRef,\n    private renderer: Renderer2,\n    private ngZone: NgZone,\n    @Inject(DOCUMENT) private document: Document,\n  ) { }\n\n  /** Registeres the change callback. Required for ControlValueAccessor */\n  registerOnChange(fn: (v: T) => void) {\n    this._onChange = fn;\n  }\n  private _onChange: (value: T) => void = () => { }\n\n  /** Registers the touch callback. Required for ControlValueAccessor */\n  registerOnTouched(fn: () => void) {\n    this._onTouch = fn;\n  }\n  private _onTouch: () => void = () => { };\n\n  /** Disable or enable the button. Required for ControlValueAccessor */\n  setDisabledState(disabled: boolean) {\n    this.disabled = disabled;\n  }\n\n  /** Writes a new value for the multi-line switch */\n  writeValue(value: T) {\n    this.activeButton = value;\n    if (!!this.buttons) {\n      // Set externalWrite to true while we iterate the buttons\n      // and eventually call `setActiveItem` so we don't re-emit\n      // the active item once the keyManager publishes the change\n      // to use.\n      // This workaround is required as we need to inform the\n      // keyManager about the new active item. Otherwise it would\n      // work with a stale internal state the next time the user\n      // uses the keyboard.\n      this.externalWrite = true;\n      this.buttons.forEach(btn => {\n        if (btn.id === value) {\n          this.keyManager!.setActiveItem(btn);\n          this.repositionMarker(btn);\n        }\n      })\n      this.externalWrite = false;\n    }\n  }\n\n  ngAfterViewInit() {\n    if (!this.buttons) {\n      return;\n    }\n\n    this.keyManager = new ListKeyManager(this.buttons)\n      .withHorizontalOrientation('ltr')\n      .withTypeAhead()\n      .withWrap();\n\n    this.keyManagerSub = this.keyManager.change\n      .subscribe(activeIndex => {\n        const active = Array.from(this.buttons!)[activeIndex];\n        this.selectButton(active, !this.externalWrite);\n      });\n\n    // Subscribe to all (clicked) and (selectedChange) events of\n    // all buttons projected into our content.\n    this.buttons.changes\n      .pipe(startWith(null))\n      .subscribe(() => {\n        this.sub.unsubscribe();\n        this.sub = new Subscription();\n\n        this.buttons!.forEach(btn => {\n          btn.disabled = this.disabled;\n          this.sub.add(\n            btn.clicked.subscribe((e: MouseEvent) => {\n              this.keyManager!.setActiveItem(btn);\n            })\n          );\n        });\n\n        // wait until the zone and change-detection stabilizes and\n        // reposition the marker afterwards. Doing it right now will\n        // likely position it wrongly since the DOM has not yet been\n        // fully updated.\n        this.ngZone.onStable.pipe(take(1))\n          .subscribe(() => this.repositionMarker())\n      });\n\n    this.buttons.forEach(btn => {\n      if (this.activeButton === btn.id) {\n        btn.selected = true;\n      }\n    })\n\n    this.repositionMarker();\n  }\n\n  ngOnDestroy() {\n    this.sub.unsubscribe();\n    this.keyManagerSub.unsubscribe();\n  }\n\n  /** Selects a new button and deselects all others. */\n  private selectButton(btn: SwitchItemComponent<T>, emit = true) {\n    if (this.disabled) {\n      return;\n    }\n\n    this.activeButton = btn.id;\n\n    if (emit) {\n      this.changed.next(btn.id!);\n      this._onChange(btn.id!);\n    }\n\n    this.repositionMarker(btn);\n  }\n\n  /** @private View-callback for (mousedown) to start dragging the marker. */\n  dragStarted(event: MouseEvent) {\n    if (this.disabled) {\n      return;\n    }\n\n    this.isGrabbing = true;\n    this.renderer.addClass(this.document.getElementsByTagName(\"body\")[0], 'document-grabbing');\n\n    const mousemove$ = fromEvent<MouseEvent>(this.document, 'mousemove');\n    const hostRect = this.host.nativeElement.getBoundingClientRect();\n    const start = this.markerOffset;\n    const markerWidth = this.marker!.nativeElement.getBoundingClientRect().width;\n\n    // we don't want angular to run change detection all the time we move a pixel\n    // so detach the change-detector for now.\n    this.changeDetectorRef.detach();\n\n    mousemove$\n      .pipe(\n        map(move => {\n          move.preventDefault();\n          return move.clientX - event.clientX;\n        }),\n        takeUntil(fromEvent(document, 'mouseup')),\n        subscribeOn(animationFrameScheduler)\n      )\n      .subscribe({\n        next: diff => {\n          // clip the new offset inside our host-view.\n          let offset = start + diff;\n          if (offset < 0) {\n            offset = 0;\n          } else if (offset > hostRect.width) {\n            offset = hostRect.width;\n          }\n\n          // center the marker at the mouse position.\n          offset -= Math.round(markerWidth / 2);\n\n          this.markerOffset = offset;\n          this.updatePosition(offset);\n\n          let foundTarget = false;\n          let target = this.findTargetButton(offset);\n\n          if (!!target) {\n            this.marker!.nativeElement.style.backgroundColor = target.borderColorActive;\n\n            this.buttons!.forEach(btn => {\n              if (!foundTarget && btn.group === target!.group) {\n                this.renderer.addClass(btn.elementRef.nativeElement, 'selected');\n                btn.elementRef.nativeElement.style.borderColor = btn.borderColorActive;\n              } else {\n                this.renderer.removeClass(btn.elementRef.nativeElement, 'selected');\n                btn.elementRef.nativeElement.style.borderColor = btn.borderColorInactive;\n              }\n\n              if (target === btn) {\n                foundTarget = true;\n              }\n            });\n          }\n        },\n        complete: () => {\n          this.changeDetectorRef.reattach();\n          this.markerDropped();\n\n          // make sure we don't keep the selected class on buttons that\n          // are not selected anymore.\n          this.buttons!.forEach(btn => {\n            if (!btn.selected) {\n              this.renderer.removeClass(btn.elementRef.nativeElement, 'selected');\n              btn.elementRef.nativeElement.style.borderColor = btn.borderColorInactive;\n            }\n          });\n\n          this.isGrabbing = false;\n          this.renderer.removeClass(this.document.getElementsByTagName(\"body\")[0], 'document-grabbing');\n        }\n      });\n  }\n\n  /** Update the markers position by applying a translate3d */\n  private updatePosition(x: number) {\n    this.marker!.nativeElement.style.transform = `translate3d(${x}px, 0px, 0px)`;\n  }\n\n  /** Find the button item that is below x */\n  private findTargetButton(x: number, cb?: (item: SwitchItemComponent<T>, target: boolean) => void): SwitchItemComponent<T> | null {\n    const host = this.host.nativeElement.getBoundingClientRect();\n    let newButton: SwitchItemComponent<T> | null = null;\n    this.buttons?.forEach(btn => {\n      const btnRect = btn.elementRef.nativeElement.getBoundingClientRect();\n      const min = btnRect.x - host.x;\n      const max = min + btnRect.width;\n\n      if (x >= min && x <= max) {\n        newButton = btn;\n\n        if (!!cb) {\n          cb(btn, true);\n        }\n      } else if (!!cb) {\n        cb(btn, false);\n      }\n    });\n\n    return newButton;\n  }\n\n  /** Calculates which button should be activated based on the drop-position of the marker */\n  private markerDropped() {\n    let newButton = this.findTargetButton(this.markerOffset);\n\n    if (!newButton) {\n      newButton = Array.from(this.buttons!)[0];\n    }\n\n    if (!!newButton) {\n      this.keyManager!.setActiveItem(newButton);\n    }\n  }\n\n  /**\n   * Calculates the new position required to center the\n   * marker at the currently selected button.\n   * If `selected` is unset the last button with selected == true is\n   * used.\n   *\n   * @param selected The switch item button to select (optional).\n   */\n  private repositionMarker(selected: SwitchItemComponent<T> | null = null) {\n    // If there's no selected button given search for the last one that\n    // matches selected === true.\n    if (selected === null) {\n      this.buttons?.forEach(btn => {\n        if (btn.selected) {\n          selected = btn;\n        }\n      });\n    }\n\n    // There's not button selected so we move the marker back to the\n    // start.\n    if (selected === null) {\n      this.markerOffset = 0;\n      this.updatePosition(0);\n      return;\n    }\n\n    // Calculate and reposition the marker.\n    const offsetLeft = selected!.elementRef.nativeElement.offsetLeft;\n    const clientWidth = selected!.elementRef.nativeElement.clientWidth;\n\n    this.markerOffset = Math.round(offsetLeft - 8 + clientWidth / 2);\n    this.marker!.nativeElement.style.backgroundColor = selected.borderColorActive;\n\n    this.updatePosition(this.markerOffset);\n    this.changeDetectorRef.markForCheck();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/multi-switch/switch-item.scss",
    "content": ":host {\n  display        : flex;\n  align-items    : center;\n  justify-content: center;\n  width          : 6rem;\n  height         : 2.7rem;\n  position       : relative;\n  bottom         : 0;\n  transition     : all .3s cubic-bezier(0.075, 0.82, 0.165, 1);\n\n  @apply bg-buttons-dark;\n\n  @apply border-b-2;\n\n  &.selected {\n    @apply bg-buttons-light;\n    height: 3rem;\n  }\n\n  &:not(.disabled) {\n    cursor: pointer;\n\n    &:hover {\n      @apply bg-buttons-light;\n    }\n  }\n\n  &:first-of-type {\n    @apply rounded-tl;\n  }\n\n  &:last-of-type {\n    @apply rounded-tr;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/multi-switch/switch-item.ts",
    "content": "import { Component, ChangeDetectionStrategy, Input, isDevMode, OnInit, HostBinding, Output, EventEmitter, HostListener, ElementRef, ChangeDetectorRef } from '@angular/core';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\n\n@Component({\n  selector: 'app-switch-item',\n  template: '<ng-content></ng-content>',\n  styleUrls: ['./switch-item.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SwitchItemComponent<T> implements OnInit {\n  @Input()\n  id: T | null = null;\n\n  @Input()\n  group = '';\n\n  @Output()\n  clicked = new EventEmitter<MouseEvent>();\n\n  @HostListener('click', ['$event'])\n  onClick(e: MouseEvent) {\n    this.clicked.next(e);\n  }\n\n  @Input()\n  borderColorActive: string = 'var(--info-green)';\n\n  @Input()\n  borderColorInactive: string = 'var(--button-light)';\n\n  @HostBinding('style.border-color')\n  get borderColor() {\n    if (this.selected) {\n      return this.borderColorActive;\n    }\n    return this.borderColorInactive;\n  }\n\n  @Input()\n  @HostBinding('class.disabled')\n  set disabled(v: any) {\n    this._disabled = coerceBooleanProperty(v);\n  }\n  get disabled() {\n    return this._disabled;\n  }\n  private _disabled = false;\n\n  @Input()\n  @HostBinding('class.selected')\n  set selected(v: any) {\n    const selected = coerceBooleanProperty(v);\n    if (selected !== this._selected) {\n      this._selected = selected;\n      this.selectedChange.next(selected);\n    }\n  }\n  get selected() {\n    return this._selected;\n  }\n  private _selected = false;\n\n  getLabel() {\n    return this.elementRef.nativeElement.innerText;\n  }\n\n  @Output()\n  selectedChange = new EventEmitter<boolean>();\n\n  ngOnInit() {\n    if (this.id === null && isDevMode()) {\n      throw new Error(`SwitchItemComponent must have an ID`);\n    }\n  }\n\n  constructor(\n    public readonly elementRef: ElementRef,\n    public readonly changeDetectorRef: ChangeDetectorRef,\n  ) { }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/.eslintrc.json",
    "content": "{\n  \"extends\": \"../../../../.eslintrc.json\",\n  \"ignorePatterns\": [\n    \"!**/*\"\n  ],\n  \"overrides\": [\n    {\n      \"files\": [\n        \"*.ts\"\n      ],\n      \"parserOptions\": {\n        \"project\": [\n          \"projects/safing/ui/tsconfig.lib.json\",\n          \"projects/safing/ui/tsconfig.spec.json\"\n        ],\n        \"createDefaultProgram\": true\n      },\n      \"rules\": {\n        \"@angular-eslint/directive-selector\": [\n          \"error\",\n          {\n            \"type\": \"attribute\",\n            \"prefix\": \"sfng\",\n            \"style\": \"camelCase\"\n          }\n        ],\n        \"@angular-eslint/component-selector\": [\n          \"error\",\n          {\n            \"type\": \"element\",\n            \"prefix\": \"sfng\",\n            \"style\": \"kebab-case\"\n          }\n        ]\n      }\n    },\n    {\n      \"files\": [\n        \"*.html\"\n      ],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/add-to-filter/add-to-filter.ts",
    "content": "import { ChangeDetectorRef, Directive, HostBinding, HostListener, Input, OnDestroy, OnInit, inject } from \"@angular/core\";\nimport { NetqueryConnection } from \"@safing/portmaster-api\";\nimport { Subscription, combineLatest } from \"rxjs\";\nimport { ActionIndicatorService } from \"../../action-indicator\";\nimport { NetqueryHelper } from \"../connection-helper.service\";\nimport { INTEGRATION_SERVICE } from \"src/app/integration\";\n\n@Directive({\n  selector: '[sfngAddToFilter]'\n})\nexport class SfngNetqueryAddToFilterDirective implements OnInit, OnDestroy {\n  private subscription = Subscription.EMPTY;\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  @Input('sfngAddToFilter')\n  key: keyof NetqueryConnection | null = null;\n\n  @Input('sfngAddToFilterValue')\n  set value(v: any | any[]) {\n    if (!Array.isArray(v)) {\n      v = [v]\n    }\n    this._values = v;\n  }\n  private _values: any[] = [];\n\n  @HostListener('click', ['$event'])\n  onClick(evt: MouseEvent) {\n    if (!this.key) {\n      return\n    }\n\n    let prevent = false\n    if (evt.shiftKey) {\n      this.helper.addToFilter(this.key, this._values);\n      prevent = true\n    } else if (evt.ctrlKey) {\n      this.integration.writeToClipboard(this._values.join(', '))\n        .then(() => {\n          this.uai.success(\"Copied to clipboard\", \"Successfully copied \" + this._values.join(\", \") + \" to your clipboard\")\n        })\n        .catch(err => {\n          this.uai.error(\"Failed to copy to clipboard\", this.uai.getErrorMessgae(err))\n        })\n\n      prevent = true\n    }\n\n    if (prevent) {\n      evt.preventDefault();\n      evt.stopPropagation();\n    }\n  }\n\n  @HostBinding('class.border-dashed')\n  @HostBinding('class.border-gray-500')\n  @HostBinding('class.hover:border-gray-700')\n  readonly _styleHost = true;\n\n  @HostBinding('class.cursor-pointer')\n  @HostBinding('class.hover:cursor-pointer')\n  @HostBinding('class.border-b')\n  @HostBinding('class.select-none')\n  get shouldHiglight() {\n    return this.isShiftKeyPressed || this.isCtrlKeyPressed\n  }\n\n  isShiftKeyPressed = false;\n  isCtrlKeyPressed = false;\n\n  constructor(\n    private helper: NetqueryHelper,\n    private uai: ActionIndicatorService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  ngOnInit(): void {\n    this.subscription = combineLatest([this.helper.onShiftKey, this.helper.onCtrlKey])\n      .subscribe(([isShiftKeyPressed, isCtrlKeyPressed]) => {\n        if (!this.key) {\n          return;\n        }\n\n        this.isShiftKeyPressed = isShiftKeyPressed;\n        this.isCtrlKeyPressed = isCtrlKeyPressed;\n        this.cdr.markForCheck();\n      })\n  }\n\n  ngOnDestroy(): void {\n    this.subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/add-to-filter/index.ts",
    "content": "export * from './add-to-filter';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/circular-bar-chart/circular-bar-chart.component.ts",
    "content": "import { AfterViewInit, ChangeDetectionStrategy, Component, DestroyRef, ElementRef, Input, OnInit, inject } from '@angular/core';\nimport { QueryResult } from '@safing/portmaster-api';\nimport * as d3 from 'd3';\n\nexport interface CircularBarChartConfig<T> {\n  // stack either holds the attribute name or an accessor function\n  // to determine which serieses belong to the same stack.\n  stack: keyof T | ((d: T) => string);\n\n  // series either holds the attribute name of the key or an accessor function.\n  seriesKey: keyof T | ((d: T) => string);\n\n  seriesLabel?: (s: string) => string;\n\n  // value either holds the attribute name or an accessor function\n  // to get the value of the series.\n  value: keyof T | ((d: T) => number);\n\n  colorAsClass?: boolean;\n\n  // the actual series configuration\n  series?: {\n    [key: string]: {\n      color: string;\n    }\n  };\n\n  // The number of ticks for the y axis\n  ticks?: number;\n\n  formatTick?: (v: number) => string;\n\n  // an optional function to format the value\n  formatValue?: (stack: string, series: string, value: number, data?: T) => string;\n\n  formatStack?: (sel: d3.Selection<SVGGElement, string, SVGGElement, any>, data: T[]) => d3.Selection<any, any, any, any>;\n}\n\n\nexport function splitQueryResult<T extends QueryResult, K extends keyof T>(results: T[], series: K[]): (QueryResult & { series: string, value: number })[] {\n  let mapped: (QueryResult & { series: string, value: number })[] = [];\n\n  results.forEach(row => {\n    series.forEach(seriesKey => {\n      mapped.push({\n        ...row,\n        value: row[seriesKey],\n        series: seriesKey as string,\n      })\n    })\n  })\n\n  return mapped\n}\n\n@Component({\n  selector: 'sfng-netquery-circular-bar-chart',\n  template: '',\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class CircularBarChartComponent<T> implements OnInit, AfterViewInit {\n  private readonly elementRef = inject(ElementRef) as ElementRef<HTMLElement>;\n  private readonly destroyRef = inject(DestroyRef);\n\n  // D3 related members\n  private svg?: d3.Selection<SVGGElement, any, any, any>;\n  private x?: d3.ScaleBand<string>;\n  private y?: d3.ScaleRadial<any, any>;\n  private height = 0;\n  private width = 0;\n\n  @Input()\n  config: CircularBarChartConfig<T> | null = null;\n\n  @Input()\n  innerRadius?: number;\n\n  @Input()\n  set data(d: T[] | null) {\n    this._data = d || [];\n\n    this.prepareChart()\n    this.render();\n  }\n  private _data: T[] = [];\n\n  ngOnInit(): void {\n    this.prepareChart()\n    this.render()\n  }\n\n  ngAfterViewInit(): void {\n    const observer = new ResizeObserver(() => {\n      this.prepareChart()\n      this.render()\n    })\n\n    observer.observe(this.elementRef.nativeElement)\n\n    this.destroyRef.onDestroy(() => observer.disconnect())\n\n    this.prepareChart()\n    this.render();\n  }\n\n  private prepareChart() {\n    if (!!this.svg) {\n      const parent = this.svg.node()?.parentElement\n      parent?.remove()\n    }\n\n    const margin = 0.2\n    const bbox = this.elementRef.nativeElement.getBoundingClientRect();\n\n    const marginLeft = bbox.width * margin;\n    const marginTop = bbox.height * margin;\n    this.width = bbox.width - 2 * marginLeft;\n    this.height = bbox.height - 2 * marginTop;\n\n    this.svg = d3.select(this.elementRef.nativeElement)\n      .append('svg')\n      .attr('width', \"100%\")\n      .attr('height', \"100%\")\n      .append('g')\n      .attr('transform', `translate(${this.width / 2 + marginLeft}, ${this.height / 2 + marginTop})`);\n\n\n    this.x = d3.scaleBand()\n      .range([0, 2 * Math.PI])\n      .align(0);\n\n    this.y = d3.scaleRadial()\n\n    // prepare the SVGGElement that we use for rendering\n    this.svg.append(\"g\")\n      .attr(\"id\", \"chart\")\n\n    this.svg.append(\"g\")\n      .attr(\"id\", \"text\")\n\n    this.svg.append(\"g\")\n      .attr(\"id\", \"legend\")\n\n    this.svg.append(\"g\")\n      .attr(\"id\", \"ticks\")\n  }\n\n  private render() {\n    const x = this.x;\n    const y = this.y;\n\n    if (!this.svg || !x || !y) {\n      console.log(\"not yet ready\")\n      return;\n    }\n\n    let stackName: (d: T) => string;\n    if (typeof this.config?.stack === 'function') {\n      stackName = this.config.stack;\n    } else {\n      stackName = (d: T) => {\n        return d[this.config!.stack as keyof T] + ''\n      }\n    }\n\n    let seriesKey: (d: T) => string;\n    if (typeof this.config?.seriesKey === 'function') {\n      seriesKey = this.config!.seriesKey\n    } else {\n      seriesKey = (d: T) => {\n        return d[this.config!.seriesKey as keyof T] + ''\n      }\n    }\n\n    let value: (d: T) => number;\n    if (typeof this.config?.value === 'function') {\n      value = this.config!.value\n    } else {\n      value = (d: T) => {\n        return +d[this.config!.value as keyof T]\n      }\n    }\n\n    let formatValue: Exclude<CircularBarChartConfig<T>[\"formatValue\"], undefined> = (stack, series, value) => `${stack} ${series}\\n${value}`\n    if (this.config?.formatValue) {\n      formatValue = this.config.formatValue;\n    }\n\n    // Prepare the stacked data\n    const indexed = d3.index(this._data, stackName, seriesKey)\n    const stackGenerator = d3.stack<[string, d3.InternMap<string, T>]>()\n      .keys(d3.union(this._data.map(seriesKey)))\n      .value((data, key) => {\n        const obj = data[1].get(key)\n        if (obj === undefined) {\n          return 0\n        }\n\n        return value(obj);\n      })\n\n    const series = stackGenerator(indexed)\n\n    // Prepare the x domain\n    const labels = new Set<string>();\n    this._data.forEach(d => labels.add(stackName(d)));\n    this.x!.domain(Array.from(labels))\n      .range([0, 2 * Math.PI])\n      .align(0);\n\n    const innerRadius = this.innerRadius || (() => {\n      return (series.length * 25) + 20\n    })()\n\n    // Prepare the x domain\n    const outerRadius = Math.min(this.width, this.height) / 2;\n    const highest = d3.max(series, point => d3.max(point, point => point[1])!)!\n    this.y!.domain([0, highest])\n      .range([innerRadius, outerRadius]);\n\n\n    const arc = d3.arc()\n      .innerRadius((d: any) => y(d[0]))\n      .outerRadius((d: any) => y(d[1]))\n      .startAngle((d: any) => x(d.data[0])!)\n      .endAngle((d: any) => x(d.data[0])! + x.bandwidth())\n      .padAngle(0.01)\n      .padRadius(innerRadius)\n\n    let color: (key: string) => string;\n\n    if (!this.config?.series) {\n      const colorScale: d3.ScaleOrdinal<string, any, any> = d3.scaleOrdinal()\n        .domain(series.map(d => d.key))\n        .range(d3.schemeSpectral)\n        .unknown(\"#ccc\")\n\n      color = key => colorScale(key);\n    } else {\n      color = key => this.config!.series![key].color\n    }\n\n    this.svg.select(\"g#chart\")\n      .selectAll()\n      .data(series)\n      .join(\"g\")\n      .call(g => {\n        if (this.config?.colorAsClass) {\n          g.attr(\"fill\", \"currentColor\")\n            .attr(\"class\", d => color(d.key))\n        } else {\n          g.attr(\"fill\", d => color(d.key))\n        }\n      })\n      .selectAll(\"path\")\n      .data(D => D.map(d => ((d as any).key = D.key, d)))\n      .join(\"path\")\n      .attr(\"d\", arc as any)\n      .append(\"title\")\n      .text(d => {\n        const stack = d.data[0]\n        const series = (d as any).key\n        const data = d.data[1].get(series);\n        const seriesValue = data ? value(data) : 0;\n\n        return formatValue(stack, series, seriesValue, data);\n      })\n\n    const sumPerLabel = this._data.reduce((map, current) => {\n      const stack = stackName(current)\n      let sum = map.get(stack) || 0\n      sum += value(current)\n      map.set(stack, sum)\n\n      return map\n    }, new Map<string, number>());\n\n    this.svg.select(\"g#text\")\n      .attr(\"text-anchor\", \"middle\")\n      .selectAll()\n      .data(x.domain())\n      .join(\"g\")\n      .attr(\"text-anchor\", d => (x(d)! + x.bandwidth() / 2 + Math.PI) % (2 * Math.PI) < Math.PI ? \"end\" : \"start\")\n      .attr(\"transform\", d => \"rotate(\" + ((x(d)! + this.x!.bandwidth() / 2) * 180 / Math.PI - 90) + \")\" + \"translate(\" + (y(sumPerLabel.get(d)!) + 10) + \",0)\")\n      .append(\"g\")\n      .attr(\"transform\", d => (x(d)! + x.bandwidth() / 2 + Math.PI) % (2 * Math.PI) < Math.PI ? \"rotate(180)\" : \"rotate(0)\")\n      .style(\"font-size\", \"11px\")\n      .attr(\"alignment-baseline\", \"middle\")\n      .attr(\"fill\", \"currentColor\")\n      .attr(\"class\", \"text-primary cursor-pointer\")\n      .on(\"mouseenter\", function (data) {\n        d3.select(this)\n          .classed(\"underline\", true)\n      })\n      .on(\"mouseleave\", function (data) {\n        d3.select(this)\n          .classed(\"underline\", false)\n      })\n      .call(g => {\n        if (!this.config?.formatStack) {\n          return g.append(\"text\")\n            .text(d => `${d}`)\n        }\n\n        return this.config.formatStack(g as any, this._data)\n      })\n\n    // y axis\n    const tickCount = this.config?.ticks || Math.floor((outerRadius - innerRadius) / 20)\n    const tickFormat = this.config?.formatTick || y.tickFormat(tickCount, \"s\")\n    this.svg.select(\"g#ticks\")\n      .attr(\"text-anchor\", \"middle\")\n      .selectAll(\"g\")\n      .data(y.ticks(tickCount).slice(1))\n      .join(\"g\")\n      .attr(\"fill\", \"none\")\n      .call(g => g.append(\"circle\")\n        .attr(\"stroke\", \"#fff\")\n        .attr(\"stroke-opacity\", 0.25)\n        .attr(\"r\", y))\n      .call(g => g.append(\"text\")\n        .style(\"font-size\", \"0.6rem\")\n        .attr(\"y\", d => -y(d))\n        .attr(\"dy\", \"0.35em\")\n        .attr(\"fill\", \"currentColor\")\n        .attr(\"class\", \"text-secondary\")\n        .text(tickFormat))\n\n    // color legend\n    this.svg.select(\"g#legend\")\n      .selectAll()\n      .data(series.map(s => s.key))\n      .join(\"g\")\n      .attr(\"transform\", (d, i, nodes) => `translate(-40,${(nodes.length / 2 - i - 1) * 20})`)\n      .call(g => g.append(\"circle\")\n        .attr(\"r\", 5)\n        .call(g => {\n          if (this.config?.colorAsClass) {\n            g.attr(\"fill\", \"currentColor\")\n              .attr(\"class\", d => color(d))\n          } else {\n            g.attr(\"fill\", d => color(d))\n          }\n        }))\n      .call(g => g.append(\"text\")\n        .attr(\"x\", 12)\n        .attr(\"y\", 4)\n        .attr(\"font-size\", \"0.6rem\")\n        .attr(\"fill\", \"#fff\")\n        .text(d => {\n          if (!!this.config?.seriesLabel) {\n            return this.config.seriesLabel(d)\n          }\n\n          return d\n        }));\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/combined-menu.pipe.ts",
    "content": "import { KeyValue } from '@angular/common';\nimport { Pipe, PipeTransform } from \"@angular/core\";\n\ninterface Model {\n  visible: boolean | 'combinedMenu';\n}\n\n@Pipe({\n  pure: true,\n  name: 'combinedMenu'\n})\nexport class CombinedMenuPipe implements PipeTransform {\n  transform<T extends Model>(value: KeyValue<any, T | undefined>[], ...args: any[]) {\n    return value.filter(entry => entry.value?.visible === 'combinedMenu')\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-details/conn-details.html",
    "content": "<section *ngIf=\"conn\">\n  <div>\n    <span sfngAddToFilter=\"started\" [sfngAddToFilterValue]=\"conn.started\">\n      <span>Started:</span>\n      <span>\n        {{ conn.started | date:'medium'}}\n      </span>\n    </span>\n\n    <span sfngAddToFilter=\"ended\" [sfngAddToFilterValue]=\"conn.ended\">\n      <span>Ended:</span>\n      <span *ngIf=\"conn.ended\">\n        {{ conn.ended | date:'medium'}}\n      </span>\n      <span *ngIf=\"!conn.ended\">\n        <fa-icon icon=\"spinner\" [spin]=\"true\"></fa-icon>\n      </span>\n    </span>\n\n    <span *ngIf=\"conn.ended\">\n      <span>Duration:</span>\n      <span >\n        {{ [conn.ended, conn.started] | duration }}\n      </span>\n    </span>\n\n    <span *appExpertiseLevel=\"'developer'\" sfngAddToFilter=\"profile_revision\"\n      [sfngAddToFilterValue]=\"conn.profile_revision\">\n      <span>Profile Revision:</span>\n      <span>\n        {{ conn.profile_revision }}\n      </span>\n    </span>\n\n    <span *appExpertiseLevel=\"'developer'\">\n      <span>Connection ID:</span>\n      <span>\n        {{ conn.id }}\n      </span>\n    </span>\n\n    <span *appExpertiseLevel=\"'expert'\" sfngAddToFilter=\"verdict\" [sfngAddToFilterValue]=\"conn.verdict\">\n      <span>Verdict:</span>\n      <span>\n        {{ verdict[conn.verdict] || 'N/A' }}\n      </span>\n    </span>\n\n    <span *appExpertiseLevel=\"'developer'\" sfngAddToFilter=\"internal\" [sfngAddToFilterValue]=\"conn.internal\">\n      <span>Internal Connection:</span>\n      <span>\n        {{ conn.internal ? 'Yes' : 'No' }}\n      </span>\n    </span>\n\n    <span *appExpertiseLevel=\"'expert'\" sfngAddToFilter=\"local_ip\" [sfngAddToFilterValue]=\"conn.local_ip\">\n      <span>Local Address:</span>\n      <span>\n        {{ conn.local_ip }}\n        <span *ngIf=\"conn.local_port\" class=\"text-tertiary\">{{ ':'+conn.local_port }}</span>\n      </span>\n    </span>\n  </div>\n\n  <div *ngIf=\"conn.type === 'ip'; else: dnsTemplate\">\n    <span sfngAddToFilter=\"direction\" [sfngAddToFilterValue]=\"conn.direction\">\n      <span>Direction:</span>\n      <span>\n        <fa-icon class=\"inline-block mr-1 transform rotate-45\" [ngClass]=\"{'text-gray-600': !!conn.ended}\"\n          [icon]=\"conn.direction === 'inbound' ? 'arrow-down' : 'arrow-up'\">\n        </fa-icon>\n        {{ conn.direction === 'inbound' ? 'Incoming' : 'Outgoing' }}\n      </span>\n    </span>\n    <span sfngAddToFilter=\"ip_protocol\" [sfngAddToFilterValue]=\"conn.ip_protocol\">\n      <span>Protocol:</span>\n      <span>{{ Protocols[conn.ip_protocol] || 'N/A' }}</span>\n    </span>\n    <span sfngAddToFilter=\"encrypted\" [sfngAddToFilterValue]=\"conn.encrypted\">\n      <span>Encrypted:</span>\n      <span>{{ conn.encrypted ? 'yes' : 'no' }}</span>\n    </span>\n    <span sfngAddToFilter=\"tunneled\" [sfngAddToFilterValue]=\"conn.tunneled\">\n      <span>SPN Protected:</span>\n      <span>{{ conn.tunneled ? 'yes' : 'no' }}</span>\n    </span>\n\n    <span *ngIf=\"conn.bytes_received > 0\">\n      <span>Data Received:</span>\n      <span>{{ conn.bytes_received  | bytes }}</span>\n    </span>\n    <span *ngIf=\"conn.bytes_sent > 0\">\n      <span>Data Sent:</span>\n      <span>{{ conn.bytes_sent | bytes }}</span>\n    </span>\n\n    <ng-container *ngIf=\"conn.extra_data?.tls as tls\">\n      <span>\n        <span>TLS Version:</span>\n        <span>{{ tls.Version }}</span>\n      </span>\n      <span>\n        <span>TLS SNI:</span>\n        <span>{{ tls.SNI }}</span>\n      </span>\n      <ng-container *ngIf=\"!!tls.Chain\">\n        <ng-container *ngIf=\"tls.Chain[0] as firstChain\">\n          <span>\n            <span>TLS Certificate:</span>\n            <span>{{ firstChain[0].Subject }} <i class=\"port\">by</i> {{ firstChain[0].Issuer }}</span>\n          </span>\n          <span>\n            <span>Trust-Chain</span>\n            <span>\n              <ol>\n                <li *ngFor=\"let cert of firstChain.slice(1)\">\n                  {{ cert.Subject }} <i class=\"port\">by</i> {{ cert.Issuer }}\n                </li>\n              </ol>\n            </span>\n          </span>\n        </ng-container>\n      </ng-container>\n    </ng-container>\n  </div>\n\n  <ng-template #dnsTemplate>\n    <div *ngIf=\"conn.extra_data?.dns as dns\">\n      <span sfngAddToFilter=\"domain\" [sfngAddToFilterValue]=\"dns.Domain\">\n        <span>Domain:</span>\n        <span>{{dns.Domain}}</span>\n      </span>\n      <span>\n        <span>Query:</span>\n        <span>{{dns.Question}}</span>\n      </span>\n\n      <span>\n        <span>Response:</span>\n        <span>{{dns.RCode}}</span>\n      </span>\n\n      <span *appExpertiseLevel=\"'expert'\">\n        <span>Served from Cache:</span>\n        <span>{{dns.ServedFromCache ? 'yes' : 'no'}}</span>\n      </span>\n\n      <span *appExpertiseLevel=\"'expert'\">\n        <span>Expires:</span>\n        <span>{{dns.Expires | date:'medium'}}</span>\n      </span>\n    </div>\n  </ng-template>\n\n  <div *ngIf=\"conn.type === 'ip'\">\n    <span *ngIf=\"conn.domain\" sfngAddToFilter=\"domain\" [sfngAddToFilterValue]=\"conn.domain\">\n      <span>Domain:</span>\n      <sfng-netquery-scope-label leftRightFix=\"true\" [scope]=\"conn.domain\">\n      </sfng-netquery-scope-label>\n    </span>\n\n    <span *ngIf=\"!conn.domain\">\n      <span>Scope:</span>\n      <ng-container [ngSwitch]=\"conn.scope\">\n        <span *ngSwitchCase=\"scopes.Global\">Internet Peer-to-Peer</span>\n        <span *ngSwitchCase=\"scopes.GlobalMulitcast\">Internet Multicast</span>\n        <span *ngSwitchCase=\"scopes.HostLocal\">Device-Local</span>\n        <span *ngSwitchCase=\"scopes.LinkLocal\">LAN Peer-to-Peer</span>\n        <span *ngSwitchCase=\"scopes.LocalMulticast\">LAN Multicast</span>\n        <span *ngSwitchCase=\"scopes.SiteLocal\">LAN Peer-to-Peer</span>\n\n        <span class=\"text-tertiary\" *ngSwitchCase=\"scopes.Invalid\">N/A</span>\n        <span class=\"text-tertiary\" *ngSwitchCase=\"scopes.Undefined\">N/A</span>\n        <span class=\"text-tertiary\" *ngSwitchDefault>N/A</span>\n      </ng-container>\n\n      <span>{{ conn.direction === 'inbound' ? ' Incoming' : ' Outgoing'}}</span>\n    </span>\n\n    <span sfngAddToFilter=\"remote_ip\" [sfngAddToFilterValue]=\"conn.remote_ip\">\n      <span>Remote Peer:</span>\n      <span>\n        {{ conn.remote_ip || 'DNS Request'}}\n        <span *ngIf=\"conn.remote_port\" class=\"text-tertiary\">{{ ':'+conn.remote_port }}</span>\n      </span>\n    </span>\n    <span sfngAddToFilter=\"country\" [sfngAddToFilterValue]=\"conn.country\">\n      <span>Country:</span>\n      <span *ngIf=\"!!conn.country\" [appCountryFlags]=\"conn.country\"></span>\n      <span>{{ (conn.country | countryName) || 'N/A' }}</span>\n    </span>\n    <span sfngAddToFilter=\"asn\" [sfngAddToFilterValue]=\"conn.asn\">\n      <span>ASN:</span>\n      <span>{{ conn.asn || 'N/A' }}</span>\n    </span>\n    <span sfngAddToFilter=\"as_owner\" [sfngAddToFilterValue]=\"conn.as_owner\">\n      <span>AS Org:</span>\n      <span>{{ conn.as_owner || 'N/A' }}</span>\n    </span>\n  </div>\n\n  <div class=\"col-span-2\">\n    <span sfngAddToFilter=\"path\" [sfngAddToFilterValue]=\"conn.path\">\n      <span>Binary Path:</span>\n      <span class=\"break-normal whitespace-normal\">{{ conn.path }} </span>\n    </span>\n    <span>\n      <span>Reason:</span>\n      <span class=\"break-normal whitespace-normal\">\n        {{conn.extra_data?.reason?.Msg}}\n      </span>\n    </span>\n    <span *ngIf=\"conn.extra_data?.reason?.OptionKey as option\">\n      <span>Applied Setting:</span>\n      <span>\n        <span>{{ helper.settings[option] || '' }}&nbsp;</span>\n        <span class=\"de-emphasize\" style=\"display: inline-block; text-align: left\">&nbsp;from&nbsp;{{\n            !!conn.extra_data?.reason?.Profile ? \"App\" :\n            \"Global\" }} Settings</span>\n      </span>\n    </span>\n  </div>\n\n  <div *ngIf=\"conn.scope === scopes.Global\">\n    <h3 class=\"text-primary text-xxs\">SPN Tunnel</h3>\n    <ng-container [ngSwitch]=\"true\">\n      <span *ngSwitchCase=\"!conn.tunneled\" class=\"inline-flex items-center gap-2 text-secondary\">\n        This connection has not been routed through the Safing Privacy Network.\n        <sfng-tipup key=\"spn\"></sfng-tipup>\n      </span>\n\n      <div *ngSwitchCase=\"!!conn.extra_data?.tunnel\" class=\"meta\">\n        <div *ngIf=\"conn.extra_data?.tunnel as tunnel\">\n          <span>\n            <span></span>\n            <sfng-spn-pin-route [route]=\"tunnel.Path\"></sfng-spn-pin-route>\n          </span>\n        </div>\n        <div *appExpertiseLevel=\"'developer'\" class=\"flex flex-col items-start justify-start gap-1 mt-2\">\n          <span class=\"flex flex-row items-center gap-2\">\n            <span class=\"text-secondary\">Path Costs:</span>\n            <span>{{ conn.extra_data?.tunnel?.PathCost }}</span>\n          </span>\n          <span class=\"flex flex-row items-center gap-2\">\n            <span class=\"text-secondary\">Routing Algorithm:</span>\n            <span>{{ conn.extra_data?.tunnel?.RoutingAlg }}</span>\n          </span>\n        </div>\n      </div>\n\n      <span *ngSwitchDefault class=\"inline-flex items-center gap-2 text-secondary\">\n        The connection was routed through the Safing Privacy Network, but the tunnel information is not available. Try\n        reloading the connections.\n      </span>\n    </ng-container>\n  </div>\n\n  <div *ngIf=\"!!bwData.length\" class=\"col-span-3 block border-t border-gray-400 py-2\">\n    <h2 class=\"text-secondary uppercase w-full text-center text-xxs\">Data Usage</h2>\n    <sfng-netquery-line-chart class=\"block w-full !h-36\" [data]=\"bwData\" [config]=\"{\n      series: {\n        incoming: {\n          lineColor: 'text-green-300',\n          areaColor: 'text-green-200 text-opacity-50',\n        },\n        outgoing: {\n          lineColor: 'text-yellow-300',\n          areaColor: 'text-yellow-200 text-opacity-50',\n        },\n      },\n      time: {\n        from: conn.started,\n        to: conn.ended,\n      },\n      fromMargin: 5,\n      toMargin: 5,\n      valueFormat: formatBytes,\n      timeFormat: formatTime,\n      showDataPoints: true,\n      fillEmptyTicks: {\n        interval: 1\n      },\n      tooltipFormat: tooltipFormat,\n      verticalMarkers: [\n        { text: 'started', time: conn.started },\n        { text: 'ended', time: conn.ended},\n      ]\n    }\"></sfng-netquery-line-chart>\n  </div>\n</section>\n\n<div class=\"flex justify-end border-t border-gray-300 pt-0.5 mt-0.5\" *ngIf=\"!!conn\">\n  <button *ngIf=\"!!process\" (click)=\"openProcessDetails()\" class=\"btn-outline\">Process\n    Details</button>\n  <button class=\"btn-outline\" *appExpertiseLevel=\"'expert'\" (click)=\"helper.dumpConnection(conn)\">Copy JSON</button>\n  <button class=\"btn-outline\" *ngIf=\"(conn | isBlocked); else blockAction\"\n    (click)=\"helper.unblockAll(conn.domain || conn.remote_ip, conn)\" [disabled]=\"!(conn | canUseRules)\">\n    Allow {{ conn.domain ? 'Domain' : 'IP'}}\n  </button>\n  <ng-template #blockAction>\n    <button class=\"btn-outline\" (click)=\"helper.blockAll(conn.domain || conn.remote_ip, conn)\"\n      [disabled]=\"!(conn | canUseRules)\">\n      Block {{ conn.domain ? 'Domain' : 'IP '}}\n    </button>\n  </ng-template>\n  <button class=\"btn-outline\" (click)=\"helper.redirectToSetting('', conn)\" *ngIf=\"!!conn.extra_data?.reason?.OptionKey\">\n    App Setting\n  </button>\n  <button class=\"btn-outline\" (click)=\"helper.redirectToSetting(conn.extra_data!.reason!.OptionKey, conn, true)\"\n    *ngIf=\"!!conn.extra_data?.reason?.OptionKey\">\n    Global Setting\n  </button>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-details/conn-details.scss",
    "content": ":host {\n  section {\n    display: grid;\n\n    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n\n    width: 100%;\n    overflow: hidden;\n    gap: 1.5rem;\n  }\n}\n\nsection {\n  &>div {\n    @apply flex flex-col gap-2 items-start justify-start text-xxs;\n\n    &>span {\n      @apply space-x-1 text-ellipsis block overflow-hidden w-full;\n\n      &>span:first-child {\n        @apply text-secondary whitespace-nowrap;\n      }\n\n      &>span:last-child {\n        @apply whitespace-nowrap;\n      }\n    }\n  }\n}\n\n\n.tunnel-path {\n  position: relative;\n\n  .line {\n    position: absolute;\n    top: 10px;\n    bottom: 10px;\n    left: 8px;\n    width: 1px;\n    background-color: rgba(255, 255, 255, 0.1);\n  }\n\n  .node-tag {\n    border-radius: 1px solid rgba(255, 255, 255, 0.2);\n    background-color: rgba(255, 255, 255, 0.1);\n    padding: 2px;\n    font-size: 85%;\n    border-radius: 2px;\n    transform: scale(0.85);\n  }\n\n  ul {\n    position: relative;\n    padding-left: 20px;\n\n    li:not(:last-of-type) {\n      padding-bottom: 0.35rem;\n    }\n\n    .ip {\n      margin-left: 0.35rem;\n    }\n\n    .hop-icon {\n      display: inline-block;\n      margin-left: -17px;\n      margin-right: 4px;\n      font-weight: 400;\n\n      &.country {\n        margin-left: -20px;\n      }\n    }\n\n    .hop-title {\n      margin-right: 2px;\n    }\n\n    .country {\n      display: inline-block;\n      margin-left: -20px;\n      margin-right: 4px;\n\n      &.unknown {\n        height: 14px;\n        width: 16px;\n        position: relative;\n        top: 3px;\n        border: 1px solid rgba(0, 0, 0, 0.25);\n        opacity: 0.5;\n        border-radius: 3px;\n        @apply bg-buttons-icon;\n      }\n    }\n  }\n}\n\n\n@keyframes arrow_move {\n  0% {\n    top: 0%;\n    opacity: 1;\n  }\n\n  85% {\n    opacity: 1;\n  }\n\n  100% {\n    top: 95%;\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-details/conn-details.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, inject } from \"@angular/core\";\nimport { BandwidthChartResult, ConnectionBandwidthChartResult, IPProtocol, IPScope, IsDenied, IsDNSRequest, Netquery, NetqueryConnection, PortapiService, Process, Verdict } from \"@safing/portmaster-api\";\nimport { SfngDialogService } from '@safing/ui';\nimport { Subscription } from \"rxjs\";\nimport { ProcessDetailsDialogComponent } from '../../process-details-dialog';\nimport { NetqueryHelper } from \"../connection-helper.service\";\nimport { BytesPipe } from \"../../pipes/bytes.pipe\";\nimport { formatDuration } from \"../../pipes\";\n\n\n\n@Component({\n  selector: 'sfng-netquery-conn-details',\n  styleUrls: ['./conn-details.scss'],\n  templateUrl: './conn-details.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngNetqueryConnectionDetailsComponent implements OnInit, OnDestroy, OnChanges {\n  helper = inject(NetqueryHelper)\n  private readonly portapi = inject(PortapiService)\n  private readonly dialog = inject(SfngDialogService)\n  private readonly cdr = inject(ChangeDetectorRef)\n  private readonly netquery = inject(Netquery)\n\n  @Input()\n  conn: NetqueryConnection | null = null;\n\n  process: Process | null = null;\n\n  readonly IsDNS = IsDNSRequest;\n  readonly verdict = Verdict;\n  readonly Protocols = IPProtocol;\n  readonly scopes = IPScope;\n  private _subscription = Subscription.EMPTY;\n\n  formatBytes = (n: d3.NumberValue, seriesKey?: string) => {\n    let prefix = '';\n    if (seriesKey !== undefined) {\n      prefix = seriesKey === 'incoming' ? 'Received: ' : 'Sent: '\n    }\n    return prefix + new BytesPipe().transform(n.valueOf())\n  }\n\n  formatTime = (n: Date) => {\n    const diff = Math.floor(new Date().getTime() - n.getTime())\n    return formatDuration(diff, false, true) + \" ago\"\n  }\n\n  tooltipFormat = (n: BandwidthChartResult<any>) => {\n    const bytes = new BytesPipe().transform\n    const received = `Received: ${bytes(n?.incoming || 0)}`;\n    const sent = `Sent: ${bytes(n?.outgoing || 0)}`\n\n    if ((n?.incoming || 0) > (n?.outgoing || 0)) {\n      return `${received}\\n${sent}`\n    }\n    return `${sent}\\n${received}`\n  }\n\n  connectionNotice: string = '';\n  bwData: ConnectionBandwidthChartResult[] = [];\n\n  ngOnChanges(changes: SimpleChanges) {\n    if (!!changes?.conn) {\n      this.updateConnectionNotice();\n      this.loadBandwidthChart();\n\n      if (this.conn?.extra_data?.pid !== undefined) {\n        this.portapi.get<Process>(`network:tree/${this.conn.extra_data.pid}-${this.conn.extra_data.processCreatedAt}`)\n          .subscribe({\n            next: p => {\n              this.process = p;\n              this.cdr.markForCheck();\n            },\n            error: () => {\n              this.process = null; // the process does not exist anymore\n              this.cdr.markForCheck();\n            }\n          })\n      } else {\n        this.process = null;\n      }\n    }\n  }\n\n  ngOnInit() {\n    this._subscription = this.helper.refresh.subscribe(() => {\n      this.updateConnectionNotice();\n      this.loadBandwidthChart();\n\n      this.cdr.markForCheck();\n    })\n  }\n\n  ngOnDestroy() {\n    this._subscription.unsubscribe();\n  }\n\n  openProcessDetails() {\n    this.dialog.create(ProcessDetailsDialogComponent, {\n      data: this.process,\n      backdrop: true,\n      autoclose: true,\n    })\n  }\n\n  private loadBandwidthChart() {\n    this.bwData = [];\n\n    if (!this.conn) {\n      this.cdr.markForCheck()\n\n      return;\n    }\n\n    this.netquery.connectionBandwidthChart([this.conn!.id], 1)\n      .subscribe(result => {\n        if (!result[this.conn!.id]?.length) {\n          return;\n        }\n\n        this.bwData = result[this.conn!.id];\n\n        this.cdr.markForCheck();\n      });\n  }\n\n  private updateConnectionNotice() {\n    this.connectionNotice = '';\n    if (!this.conn) {\n      return;\n    }\n\n    if (this.conn!.verdict === Verdict.Failed) {\n      this.connectionNotice = 'Failed with previous settings.'\n      return;\n    }\n\n    if (IsDenied(this.conn!.verdict)) {\n      this.connectionNotice = 'Blocked by previous settings.';\n    } else {\n      this.connectionNotice = 'Allowed by previous settings.';\n    }\n\n    this.connectionNotice += ' You current settings could decide differently.'\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-details/index.ts",
    "content": "export * from './conn-details';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-helper.service.ts",
    "content": "import { DOCUMENT } from '@angular/common';\nimport { Inject, Injectable, Renderer2, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { AppProfile, AppProfileService, ConfigService, IPScope, NetqueryConnection, Pin, PossilbeValue, QueryResult, SPNService, Verdict, deepClone, flattenProfileConfig, getAppSetting, setAppSetting } from '@safing/portmaster-api';\nimport { BehaviorSubject, Observable, OperatorFunction, Subject, combineLatest } from 'rxjs';\nimport { distinctUntilChanged, filter, map, switchMap, take, takeUntil } from 'rxjs/operators';\nimport { ActionIndicatorService } from '../action-indicator';\nimport { objKeys } from '../utils';\nimport { SfngSearchbarFields } from './searchbar';\nimport { INTEGRATION_SERVICE } from 'src/app/integration';\n\nexport const IPScopeNames: { [key in IPScope]: string } = {\n  [IPScope.Invalid]: \"Invalid\",\n  [IPScope.Undefined]: \"Undefined\",\n  [IPScope.HostLocal]: \"Device Local\",\n  [IPScope.LinkLocal]: \"Link Local\",\n  [IPScope.SiteLocal]: \"LAN\",\n  [IPScope.Global]: \"Internet\",\n  [IPScope.LocalMulticast]: \"LAN Multicast\",\n  [IPScope.GlobalMulitcast]: \"Internet Multicast\"\n}\n\nexport interface LocalAppProfile extends AppProfile {\n  FlatConfig: { [key: string]: any }\n}\n\n@Injectable()\nexport class NetqueryHelper {\n  readonly settings: { [key: string]: string } = {};\n\n  refresh = new Subject<void>();\n\n  private onShiftKey$ = new BehaviorSubject<boolean>(false);\n  private onCtrlKey$ = new BehaviorSubject<boolean>(false);\n  private addToFilter$ = new Subject<SfngSearchbarFields>();\n  private destroy$ = new Subject<void>();\n  private appProfiles$ = new BehaviorSubject<LocalAppProfile[]>([]);\n  private spnMapPins$ = new BehaviorSubject<Pin[] | null>(null);\n  private readonly integration = inject(INTEGRATION_SERVICE);\n\n  readonly onShiftKey: Observable<boolean>;\n  readonly onCtrlKey: Observable<boolean>;\n\n  constructor(\n    private router: Router,\n    private profileService: AppProfileService,\n    private configService: ConfigService,\n    private actionIndicator: ActionIndicatorService,\n    private renderer: Renderer2,\n    private spnService: SPNService,\n    @Inject(DOCUMENT) private document: Document,\n  ) {\n    const cleanupKeyDown = this.renderer.listen(this.document, 'keydown', (event: KeyboardEvent) => {\n      if (event.shiftKey) {\n        this.onShiftKey$.next(true)\n      }\n      if (event.ctrlKey) {\n        this.onCtrlKey$.next(true);\n      }\n    });\n\n    const cleanupKeyUp = this.renderer.listen(this.document, 'keyup', () => {\n      this.onShiftKey$.next(false);\n      this.onCtrlKey$.next(false);\n    })\n\n    const windowBlur = this.renderer.listen(window, 'blur', () => {\n      this.onShiftKey$.next(false);\n      this.onCtrlKey$.next(false);\n    })\n\n    this.destroy$.subscribe({\n      complete: () => {\n        cleanupKeyDown();\n        cleanupKeyUp();\n        windowBlur();\n      }\n    })\n\n    this.onShiftKey = this.onShiftKey$\n      .pipe(distinctUntilChanged());\n\n    this.onCtrlKey = this.onCtrlKey$\n      .pipe(distinctUntilChanged());\n\n    this.configService.query('')\n      .subscribe(settings => {\n        settings.forEach(setting => {\n          this.settings[setting.Key] = setting.Name;\n        });\n        this.refresh.next();\n      });\n\n    // watch all application profiles\n    this.profileService.watchProfiles()\n      .pipe(takeUntil(this.destroy$))\n      .subscribe(profiles => {\n        this.appProfiles$.next((profiles || []).map(p => {\n          return {\n            ...p,\n            FlatConfig: flattenProfileConfig(p.Config),\n          }\n        }))\n      });\n\n    this.spnService.watchPins()\n      .pipe(takeUntil(this.destroy$))\n      .subscribe(pins => {\n        this.spnMapPins$.next(pins);\n      })\n  }\n\n  decodePrettyValues(field: keyof NetqueryConnection, values: any[]): any[] {\n    if (field === 'verdict') {\n      return values.map(val => Verdict[val]).filter(value => value !== undefined);\n    }\n\n    if (field === 'scope') {\n      return values.map(val => {\n        // check if it's a value of the IPScope enum\n        const scopeValue = IPScope[val];\n        if (!!scopeValue) {\n          return scopeValue;\n        }\n\n        // otherwise check if it's pretty name of the scope translation\n        val = `${val}`.toLocaleLowerCase();\n        return objKeys(IPScopeNames).find(scope => IPScopeNames[scope].toLocaleLowerCase() === val)\n      }).filter(value => value !== undefined);\n    }\n\n    if (field === 'allowed') {\n      return values.map(val => {\n        if (typeof val !== 'string') {\n          return val\n        }\n\n        switch (val.toLocaleLowerCase()) {\n          case 'yes':\n            return true\n          case 'no':\n            return false\n          case 'n/a':\n          case 'null':\n            return null\n          default:\n            return val\n        }\n      })\n    }\n\n    if (field === 'exit_node') {\n      const lm = new Map<string, Pin>();\n      (this.spnMapPins$.getValue() || [])\n        .forEach(pin => lm.set(pin.Name, pin));\n\n      return values.map(val => lm.get(val)?.ID || val)\n    }\n\n    return values;\n  }\n\n  attachProfile(): OperatorFunction<QueryResult[], (QueryResult & { __profile?: LocalAppProfile })[]> {\n    return source => combineLatest([\n      source,\n      this.appProfiles$,\n    ]).pipe(\n      map(([items, profiles]) => {\n        let lm = new Map<string, LocalAppProfile>();\n        profiles.forEach(profile => {\n          lm.set(`${profile.Source}/${profile.ID}`, profile)\n        })\n\n        return items.map(item => {\n          if ('profile' in item) {\n            item.__profile = lm.get(item.profile!)\n          }\n\n          return item;\n        })\n      })\n    )\n  }\n\n  attachPins(): OperatorFunction<QueryResult[], (QueryResult & { __exitNode?: Pin })[]> {\n    return source => combineLatest([\n      source,\n      this.spnMapPins$\n        .pipe(\n          filter(result => result !== null),\n          take(1),\n        ),\n    ]).pipe(\n      map(([items, pins]) => {\n        let lm = new Map<string, Pin>();\n        pins!.forEach(pin => {\n          lm.set(pin.ID, pin)\n        })\n\n        return items.map(item => {\n          if ('exit_node' in item) {\n            item.__exitNode = lm.get(item.exit_node!)\n          }\n\n          return item;\n        })\n      })\n    )\n  }\n\n  encodeToPossibleValues(field: string): OperatorFunction<QueryResult[], (QueryResult & PossilbeValue)[]> {\n    return source => combineLatest([\n      source,\n      this.appProfiles$,\n      this.spnMapPins$,\n    ]).pipe(\n      map(([items, profiles, pins]) => {\n        // convert profile IDs to profile name\n        if (field === 'profile') {\n          let lm = new Map<string, AppProfile>();\n          profiles.forEach(profile => {\n            lm.set(`${profile.Source}/${profile.ID}`, profile)\n          })\n\n          return items.map((item: any) => {\n            const profile = lm.get(item.profile!)\n            return {\n              Name: profile?.Name || `${item.profile}`,\n              Value: item.profile!,\n              Description: '',\n              __profile: profile || null,\n              ...item,\n            }\n          })\n        }\n\n        // convert verdict identifiers to their pretty name.\n        if (field === 'verdict') {\n          return items.map(item => {\n            if (Verdict[item.verdict!] === undefined) {\n              return null\n            }\n\n            return {\n              Name: Verdict[item.verdict!],\n              Value: item.verdict,\n              Description: '',\n              ...item\n            }\n          })\n        }\n\n        // convert the IP scope identifier to a pretty name\n        if (field === 'scope') {\n          return items.map(item => {\n            if (IPScope[item.scope!] === undefined) {\n              return null\n            }\n\n            return {\n              Name: IPScopeNames[item.scope!],\n              Value: item.scope,\n              Description: '',\n              ...item\n            }\n          })\n        }\n\n        if (field === 'allowed') {\n          return items\n            // we remove any \"null\" value from allowed here as it may happen for a really short\n            // period of time and there's no reason to actually filter for them because\n            // from showing a \"null\" value to the user clicking it the connection will have been\n            // verdicted and thus no results will show up for \"null\".\n            .filter(item => typeof item.allowed === 'boolean')\n            .map(item => {\n              return {\n                Name: item.allowed ? 'Yes' : 'No',\n                Value: item.allowed,\n                Description: '',\n                ...item\n              }\n            })\n        }\n\n        if (field === 'exit_node') {\n          const lm = new Map<string, Pin>();\n          pins!.forEach(pin => lm.set(pin.ID, pin));\n\n          return items.map(item => {\n            const pin = lm.get(item.exit_node!);\n            return {\n              Name: pin?.Name || item.exit_node,\n              Value: item.exit_node,\n              Description: 'Operated by ' + (pin?.VerifiedOwner || 'N/A'),\n              ...item\n            }\n          })\n        }\n\n        // the rest is just converted into the {@link PossibleValue} form\n        // by using the value as the \"Name\".\n        return items.map(item => ({\n          Name: `${item[field]}`,\n          Value: item[field],\n          Description: '',\n          ...item,\n        }))\n      }),\n      // finally, remove any values that have been mapped to null in the above stage.\n      // this may happen for values that are not valid for the given model field (i.e. using \"Foobar\" for \"verdict\")\n      map(results => {\n        return results.filter(val => !!val)\n      })\n    )\n  }\n\n  dispose() {\n    this.onShiftKey$.complete();\n\n    this.destroy$.next();\n    this.destroy$.complete();\n  }\n\n  /** Emits added fields whenever addToFilter is called */\n  onFieldsAdded(): Observable<SfngSearchbarFields> {\n    return this.addToFilter$.asObservable();\n  }\n\n  /** Adds a new filter to the current query */\n  addToFilter(key: string, value: any[]) {\n    this.addToFilter$.next({\n      [key]: value,\n    })\n  }\n\n  /**\n   * @private\n   * Returns the class used to color the connection's\n   * verdict.\n   *\n   * @param conn The connection object\n   */\n  getVerdictClass(conn: NetqueryConnection): string {\n    return Verdict[conn.verdict]?.toLocaleLowerCase() || `unknown-verdict<${conn.verdict}>`;\n  }\n\n  /**\n   * @private\n   * Redirect the user to a settings key in the application\n   * profile.\n   *\n   * @param key The settings key to redirect to\n   */\n  redirectToSetting(setting: string, conn: NetqueryConnection, globalSettings = false) {\n    const reason = conn.extra_data?.reason;\n    if (!reason) {\n      return;\n    }\n\n    if (!setting) {\n      setting = reason.OptionKey;\n    }\n\n    if (!setting) {\n      return;\n    }\n\n    if (globalSettings) {\n      this.router.navigate(\n        ['/', 'settings'], {\n        queryParams: {\n          setting: setting,\n        }\n      })\n      return;\n    }\n\n    let profile = conn.profile\n\n    if (!!reason.Profile) {\n      profile = reason.Profile;\n    }\n\n    if (profile.startsWith(\"core:profiles/\")) {\n      profile = profile.replace(\"core:profiles/\", \"\")\n    }\n\n    this.router.navigate(\n      ['/', 'app', ...profile.split(\"/\")], {\n      queryParams: {\n        tab: 'settings',\n        setting: setting,\n      }\n    })\n  }\n\n  /**\n   * @private\n   * Redirect the user to \"outgoing rules\" setting in the\n   * application profile/settings.\n   */\n  redirectToRules(conn: NetqueryConnection) {\n    if (conn.direction === 'inbound') {\n      this.redirectToSetting('filter/serviceEndpoints', conn);\n    } else {\n      this.redirectToSetting('filter/endpoints', conn);\n    }\n  }\n\n  /**\n   * @private\n   * Dump a connection to the console\n   *\n   * @param conn The connection to dump\n   */\n  async dumpConnection(conn: NetqueryConnection) {\n    // Copy to clip-board if supported\n    try {\n      await this.integration.writeToClipboard(JSON.stringify(conn, undefined, \"    \"))\n      this.actionIndicator.info(\"Copied to Clipboard\")\n    } catch (err: any) {\n      this.actionIndicator.error(\"Copy to Clipboard Failed\", err?.message || JSON.stringify(err))\n    }\n  }\n\n  /**\n   * @private\n   * Creates a new \"block domain\" outgoing rules\n   */\n  blockAll(domain: string, conn: NetqueryConnection) {\n    /* Deactivate until exact behavior is specified.\n    if (this.isDomainBlocked(domain)) {\n      this.actionIndicator.info(domain + ' already blocked')\n      return;\n    }\n    */\n\n    domain = domain.replace(/\\.+$/, '');\n    const newRule = `- ${domain}`;\n    this.updateRules(newRule, true, conn)\n  }\n\n  /**\n   * @private\n   * Removes a \"block domain\" rule from the outgoing rules\n   */\n  unblockAll(domain: string, conn: NetqueryConnection) {\n    /* Deactivate until exact behavior is specified.\n    if (!this.isDomainBlocked(domain)) {\n      this.actionIndicator.info(domain + ' already allowed')\n      return;\n    }\n    */\n\n    domain = domain.replace(/\\.+$/, '');\n    const newRule = `+ ${domain}`;\n    this.updateRules(newRule, true, conn);\n  }\n\n  /**\n   * Updates the outgoing rule set and either creates or deletes\n   * a rule. If a rule should be created but already exists\n   * it is moved to the top.\n   *\n   * @param newRule The new rule to create or delete.\n   * @param add  Whether or not to create or delete the rule.\n   */\n  private updateRules(newRule: string, add: boolean, conn: NetqueryConnection) {\n    if (!conn.profile) {\n      return\n    }\n\n    let key = 'filter/endpoints';\n    if (conn.direction === 'inbound') {\n      key = 'filter/serviceEndpoints'\n    }\n\n    this.profileService.getAppProfile(conn.profile)\n      .pipe(\n        switchMap(profile => {\n          let rules = getAppSetting<string[]>(profile.Config, key) || [];\n          rules = rules.filter(rule => rule !== newRule);\n\n          if (add) {\n            rules.splice(0, 0, newRule)\n          }\n\n          const newProfile = deepClone(profile);\n\n          if (newProfile.Config === null || newProfile.Config === undefined) {\n            newProfile.Config = {}\n          }\n\n          setAppSetting(newProfile.Config, key, rules);\n\n          return this.profileService.saveProfile(newProfile)\n        })\n      )\n      .subscribe({\n        next: () => {\n          if (add) {\n            this.actionIndicator.success('Rules Updated', 'Successfully created a new rule.')\n          } else {\n            this.actionIndicator.success('Rules Updated', 'Successfully removed matching rule.')\n          }\n        },\n        error: err => {\n          this.actionIndicator.error('Failed to update rules', JSON.stringify(err))\n        }\n      });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-row/conn-row.html",
    "content": "<div class=\"flex flex-row items-center gap-2\" name=\"first\">\n  <span class=\"flex-shrink-0 verdict\" [ngClass]=\"helper.getVerdictClass(conn)\"\n    [sfng-tooltip]=\"conn.extra_data?.reason?.Msg || null\"></span>\n\n  <ng-container *ngIf=\"conn.domain as domain; else scopeTranslation\">\n    <sfng-netquery-scope-label name=\"domain\" [scope]=\"conn.domain\"\n      class=\"inline-block overflow-hidden overflow-ellipsis\" style=\"direction: rtl\" sfngAddToFilter=\"domain\"\n      [sfngAddToFilterValue]=\"conn.domain\">\n    </sfng-netquery-scope-label>\n  </ng-container>\n\n  <svg xmlns=\"http://www.w3.org/2000/svg\" name=\"internal\" class=\"flex-grow-0 flex-shrink-0 w-4 h-4 text-tertiary\"\n    fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\" *ngIf=\"conn.internal\"\n    sfng-tooltip=\"Internal connections are only displayed in Developer Mode\">\n    <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n      d=\"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21\" />\n  </svg>\n\n  <ng-template #scopeTranslation>\n    <span sfngAddToFilter=\"scope\" [sfngAddToFilterValue]=\"conn.scope\" name=\"scope\"\n      class=\"overflow-hidden text-ellipsis\">\n      <ng-container [ngSwitch]=\"conn.scope\">\n        <span *ngSwitchCase=\"scopes.Global\">Internet Peer-to-Peer</span>\n        <span *ngSwitchCase=\"scopes.GlobalMulitcast\">Internet Multicast</span>\n        <span *ngSwitchCase=\"scopes.HostLocal\">Device-Local</span>\n        <span *ngSwitchCase=\"scopes.LinkLocal\">LAN Peer-to-Peer</span>\n        <span *ngSwitchCase=\"scopes.LocalMulticast\">LAN Multicast</span>\n        <span *ngSwitchCase=\"scopes.SiteLocal\">LAN Peer-to-Peer</span>\n\n        <span class=\"text-tertiary\" *ngSwitchCase=\"scopes.Invalid\">N/A</span>\n        <span class=\"text-tertiary\" *ngSwitchCase=\"scopes.Undefined\">N/A</span>\n        <span class=\"text-tertiary\" *ngSwitchDefault>N/A</span>\n      </ng-container>\n\n      <span>{{ conn.direction === 'inbound' ? ' Incoming' : ' Outgoing'}}</span>\n    </span>\n  </ng-template>\n</div>\n\n<ng-template #countryTooltip>\n  <div class=\"flex flex-row gap-2 items-center justify-start\">\n    <span *ngIf=\"conn.country && conn.type !== 'dns'\" [appCountryFlags]=\"conn.country\"></span>\n    <span>{{ conn.country | countryName }}</span>\n  </div>\n</ng-template>\n\n<div [class.text-tertiary]=\"!conn.country\" class=\"flex-row items-center justify-start hidden gap-1 sfng-md:flex\"\n  name=\"location\" [sfngAddToFilter]=\"!!conn.country ? 'country' : null\" [sfngAddToFilterValue]=\"conn.country\"\n  [sfng-tooltip]=\"conn.country && conn.type !== 'dns' ? countryTooltip : null\">\n  <span *ngIf=\"conn.country && conn.type !== 'dns'\" [appCountryFlags]=\"conn.country\"></span>\n  {{ conn | connectionLocation }}\n</div>\n\n<div>\n  <span *ngIf=\"!!conn.__profile\" class=\"flex flex-row items-center gap-1\" name=\"profile\">\n    <app-icon [profile]=\"conn.__profile\"></app-icon>\n    <span [sfngAddToFilter]=\"'profile'\" [sfngAddToFilterValue]=\"conn.profile\">{{ conn.__profile.Name }}</span>\n  </span>\n</div>\n\n<div class=\"flex flex-row items-center gap-2\" name=\"remote\">\n  <fa-icon class=\"w-4 h-4 transform rotate-45\" [ngClass]=\"{'text-gray-600': !!conn.ended}\"\n    [icon]=\"conn.direction === 'inbound' ? 'arrow-down' : 'arrow-up'\">\n  </fa-icon>\n\n  <span *ngIf=\"conn.type === 'ip'; else dnsRequest\" sfngAddToFilter=\"remote_ip\" [sfngAddToFilterValue]=\"conn.remote_ip\">\n    {{ conn.remote_ip }} <span *ngIf=\"conn.remote_port\" class=\"text-secondary\">:{{ conn.remote_port }}</span>\n  </span>\n  <ng-template #dnsRequest>\n    <span class=\"text-secondary\" sfngAddToFilter=\"type\" sfngAddToFilterValue=\"dns\">\n      DNS Request\n    </span>\n  </ng-template>\n</div>\n\n<div class=\"hidden sfng-md:block text-secondary\" [sfng-tooltip]=\"'Started ' + (conn.started | timeAgo:timeAgoTicker)\">\n  <ng-container *ngIf=\"!!conn.ended\">\n    <span class=\"hidden sfng-xl:inline\">ended&nbsp;&nbsp;</span>\n    {{ conn.ended | timeAgo:timeAgoTicker }}\n  </ng-container>\n\n  <ng-container *ngIf=\"!conn.ended\">\n    <span class=\"hidden sfng-xl:inline\">started&nbsp;&nbsp;</span>\n    {{ conn.started | timeAgo:timeAgoTicker }}\n  </ng-container>\n</div>\n\n<div name=\"reason\" class=\"flex-row items-center justify-start hidden gap-2 sfng-lg:flex\">\n  <ng-container *ngIf=\"conn.extra_data?.reason as reason\">\n    <ng-container *ngIf=\"reason.OptionKey\">\n      <span class=\"hidden sfng-2xl:inline text-tertiary\">applied</span>\n      <span class=\"text-primary\">{{ helper.settings[reason.OptionKey] || '' }}</span>\n\n      <svg viewBox=\"0 0 24 24\" class=\"w-4 h-4\" *ngIf=\"!reason.Profile\" sfng-tooltip=\"from Global Settings\">\n        <g fill=\"none\" stroke-linecap=\"round\" stroke=\"currentColor\" stroke-linejoin=\"round\" stroke-width=\"2\">\n          <path shape-rendering=\"geometricPrecision\"\n            d=\"M13.7678 10.2322c.976311.976311.976311 2.55922 0 3.53553-.976311.976311-2.55922.976311-3.53553 0-.976311-.976311-.976311-2.55922 0-3.53553.976311-.976311 2.55922-.976311 3.53553 0\" />\n          <path shape-rendering=\"geometricPrecision\"\n            d=\"M14.849 4.12l.583.194c.534.178.895.678.895 1.241v.837c0 .712.568 1.293 1.28 1.308l.838.018c.485.01.925.289 1.142.723l.275.55c.252.504.153 1.112-.245 1.51l-.592.592c-.503.503-.512 1.316-.02 1.83l.58.606c.336.351.45.858.296 1.319l-.194.583c-.178.534-.678.895-1.241.895h-.837c-.712 0-1.293.568-1.308 1.28l-.018.838c-.01.485-.289.925-.723 1.142l-.55.275c-.504.252-1.112.153-1.51-.245l-.592-.592c-.503-.503-1.316-.512-1.83-.02l-.606.58c-.351.336-.858.45-1.319.296l-.583-.194c-.534-.178-.895-.678-.895-1.241v-.837c0-.712-.568-1.293-1.28-1.308l-.838-.018c-.485-.01-.925-.289-1.142-.723l-.275-.55c-.252-.504-.153-1.112.245-1.51l.592-.592c.503-.503.512-1.316.02-1.83l-.58-.606c-.337-.352-.451-.86-.297-1.32l.194-.583c.178-.534.678-.895 1.241-.895h.837c.712 0 1.293-.568 1.308-1.28l.018-.838c.012-.485.29-.925.724-1.142l.55-.275c.504-.252 1.112-.153 1.51.245l.592.592c.503.503 1.316.512 1.83.02l.606-.58c.351-.335.859-.449 1.319-.295z\" />\n        </g>\n      </svg>\n\n      <svg *ngIf=\"!!reason.Profile\" sfng-tooltip=\"from Application Settings\" xmlns=\"http://www.w3.org/2000/svg\"\n        data-name=\"Layer 1\" viewBox=\"0 0 24 24\" class=\"w-4 h-4\" stroke=\"currentColor\" fill=\"none\">\n        <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" fill=\"currentColor\"\n          d=\"M19 21h-3a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2Z\" />\n        <path fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n          d=\"M19 9h-3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2ZM5 3h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2ZM5 15h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2Z\" />\n      </svg>\n\n      <span class=\"hidden sfng-xl:inline text-secondary\">{{ reason.Profile ? 'App' : 'Global' }}</span>\n    </ng-container>\n  </ng-container>\n</div>\n\n<div class=\"flex-grow-0 flex-shrink-0 w-6\">\n  <app-menu-trigger [menu]=\"ungroupedConnectionMenu\"></app-menu-trigger>\n  <app-menu #ungroupedConnectionMenu>\n    <ng-container *ngIf=\"conn.extra_data?.reason as reason\">\n      <app-menu-item (activate)=\"helper.redirectToSetting('', conn)\" *ngIf=\"!!reason.OptionKey\">\n        App Setting\n      </app-menu-item>\n\n      <app-menu-item (activate)=\"helper.redirectToSetting('', conn, true)\" *ngIf=\"!!reason.OptionKey\">\n        Global Setting\n      </app-menu-item>\n    </ng-container>\n\n    <app-menu-group class=\"separator\"></app-menu-group>\n\n    <app-menu-item *ngIf=\"(conn | isBlocked); else blockAction\"\n      (activate)=\"helper.unblockAll(conn.domain || conn.remote_ip, conn)\" [disabled]=\"!(conn | canUseRules)\">\n      Allow {{ conn.domain ? 'Domain' : 'IP'}}\n    </app-menu-item>\n\n    <ng-template #blockAction>\n      <app-menu-item (activate)=\"helper.blockAll(conn.domain || conn.remote_ip, conn)\"\n        [disabled]=\"!(conn | canUseRules)\">\n        Block {{ conn.domain ? 'Domain' : 'IP '}}\n      </app-menu-item>\n    </ng-template>\n\n\n    <app-menu-item *appExpertiseLevel=\"'expert'\" (click)=\"helper.dumpConnection(conn)\">Copy JSON</app-menu-item>\n  </app-menu>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-row/conn-row.scss",
    "content": ":host {\n  @apply w-full flex-grow gap-4 grid justify-start items-center overflow-hidden;\n\n  grid-template-columns:\n    1fr 1fr 1fr 2rem;\n\n  grid-auto-rows: 1.5rem;\n  grid-template-rows: none;\n\n  &>* {\n    @apply overflow-hidden whitespace-nowrap;\n\n    &>*:last-child {\n      @apply overflow-hidden text-ellipsis;\n    }\n  }\n\n  --app-icon-size: 20px;\n}\n\n:host-context(.min-width-768px) {\n  :host {\n    grid-template-columns:\n      1fr 4rem 1fr 1fr 5rem 2rem;\n    ;\n  }\n}\n\n:host-context(.min-width-1024px) {\n  :host {\n    grid-template-columns:\n      1fr 4rem 1fr 1fr 5rem 0.5fr 2rem;\n    ;\n  }\n}\n\n:host-context(.min-width-1280px) {\n  :host {\n    grid-template-columns:\n      1fr 4rem 1fr 1fr 8rem 1fr 2rem;\n    ;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-row/conn-row.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from \"@angular/core\";\nimport { AppProfile, IPScope, NetqueryConnection, Verdict } from \"@safing/portmaster-api\";\nimport { interval, Subscription } from \"rxjs\";\nimport { share, startWith } from \"rxjs/operators\";\nimport { NetqueryHelper } from \"../connection-helper.service\";\n\ninterface ProfileAttachedConnection extends NetqueryConnection {\n  __profile?: AppProfile;\n}\n\n@Component({\n  selector: 'sfng-netquery-connection-row',\n  templateUrl: './conn-row.html',\n  styleUrls: [\n    './conn-row.scss'\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngNetqueryConnectionRowComponent implements OnInit, OnDestroy {\n  readonly scopes = IPScope;\n  readonly verdicts = Verdict;\n\n  @Input()\n  set conn(c: ProfileAttachedConnection) {\n    this._conn = c;\n  }\n  get conn() { return this._conn; }\n  _conn!: ProfileAttachedConnection;\n\n  @Input()\n  activeRevision: number | undefined = 0;\n\n  /* timeAgoTicker ticks every 10000 seconds to force a refresh\n     of the timeAgo pipes */\n  timeAgoTicker: number = 0;\n\n  private _subscription = Subscription.EMPTY;\n\n  constructor(\n    public helper: NetqueryHelper,\n    private changeDetectorRef: ChangeDetectorRef,\n  ) { }\n\n  ngOnInit() {\n    this._subscription = new Subscription();\n\n    const tickerSub = interval(10000).pipe(\n      startWith(-1),\n      share()\n    ).subscribe(i => this.timeAgoTicker = i);\n\n    const helperSub = this.helper.refresh.subscribe(() => {\n      this.changeDetectorRef.markForCheck();\n    })\n\n    this._subscription.add(helperSub);\n    this._subscription.add(tickerSub);\n  }\n\n  ngOnDestroy() {\n    this._subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/connection-row/index.ts",
    "content": "export * from './conn-row';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/index.ts",
    "content": "export * from './netquery.component';\nexport * from './netquery.module';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/line-chart/index.ts",
    "content": ""
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/line-chart/line-chart.ts",
    "content": "import { coerceBooleanProperty, coerceNumberProperty, coerceStringArray } from '@angular/cdk/coercion';\nimport { AfterViewInit, ChangeDetectionStrategy, Component, DestroyRef, ElementRef, Input, OnChanges, OnInit, SimpleChanges, inject } from '@angular/core';\nimport { BandwidthChartResult, ChartResult } from '@safing/portmaster-api';\nimport * as d3 from 'd3';\nimport { Selection } from 'd3';\nimport { AppComponent } from 'src/app/app.component';\nimport { formatDuration, timeAgo } from '../../pipes';\nimport { objKeys } from '../../utils';\nimport { BytesPipe } from '../../pipes/bytes.pipe';\n\nexport interface SeriesConfig {\n  lineColor: string;\n  areaColor?: string;\n}\n\nexport interface Marker {\n  text: string;\n  time: Date | number | string;\n}\n\nexport interface ChartConfig<T extends SeriesData> {\n  series: {\n    [key in Exclude<keyof T, 'timestamp'>]?: SeriesConfig;\n  },\n  time?: {\n    from: number | string | Date;\n    to?: number | string | Date;\n  },\n  fromMargin?: number;\n  toMargin?: number;\n  valueFormat?: (n: d3.NumberValue, seriesKey?: string) => string,\n  tooltipFormat?: (data: T) => string;\n  timeFormat?: (n: Date) => string,\n  showDataPoints?: boolean;\n  fillEmptyTicks?: {\n    interval: number;\n  },\n  verticalMarkers?: Marker[];\n}\n\nfunction coerceDate(d: Date | number | string): Date {\n  if (typeof d === 'string') {\n    return new Date(d)\n  }\n\n  if (d instanceof Date) {\n    return d\n  }\n\n  if (d < 0) {\n    return new Date((new Date()).getTime() + d * 1000)\n  }\n\n  return new Date(d * 1000);\n}\n\nexport const DefaultChartConfig: ChartConfig<ChartResult> = {\n  series: {\n    value: {\n      lineColor: 'text-green-200',\n      areaColor: 'text-green-100 text-opacity-25'\n    },\n    countBlocked: {\n      lineColor: 'text-red-200',\n      areaColor: 'text-red-100 text-opacity-25'\n    }\n  },\n}\n\nexport const DefaultBandwidthChartConfig: ChartConfig<BandwidthChartResult<any>> = {\n  series: {\n    outgoing: {\n      lineColor: 'text-deepPurple-500',\n      areaColor: 'text-deepPurple-700 text-opacity-5',\n    },\n    incoming: {\n      lineColor: 'text-cyan-800',\n      areaColor: 'text-cyan-700 text-opacity-5',\n    },\n  },\n  time: {\n    from: -10 * 60,\n  },\n  valueFormat: (n: d3.NumberValue, seriesKey?: string) => {\n    let prefix = '';\n    if (seriesKey !== undefined) {\n      prefix = seriesKey === 'incoming' ? 'Received: ' : 'Sent: '\n    }\n    return prefix + new BytesPipe().transform(n.valueOf())\n  },\n  timeFormat: (n: Date) => {\n    const diff = Math.floor(new Date().getTime() - n.getTime())\n    return formatDuration(diff, false, true) + \" ago\"\n  },\n  tooltipFormat: (n: BandwidthChartResult<any>) => {\n    const bytes = new BytesPipe().transform\n    const received = `Received: ${bytes(n?.incoming || 0)}`;\n    const sent = `Sent: ${bytes(n?.outgoing || 0)}`\n\n    if ((n?.incoming || 0) > (n?.outgoing || 0)) {\n      return `${received}\\n${sent}`\n    }\n    return `${sent}\\n${received}`\n  },\n  showDataPoints: true,\n  fillEmptyTicks: {\n    interval: 60\n  },\n}\n\nexport interface SeriesData {\n  timestamp: number;\n}\n\n@Component({\n  selector: 'sfng-netquery-line-chart',\n  styles: [\n    `\n    :host {\n      @apply block h-full w-full;\n    }\n    `\n  ],\n  template: '',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngNetqueryLineChartComponent<D extends SeriesData = any> implements OnChanges, OnInit, AfterViewInit {\n  private destroyRef = inject(DestroyRef);\n\n  @Input()\n  data: D[] = [];\n\n  private preparedData: D[] = [];\n\n  private width = 700;\n  private height = 250;\n\n  @Input()\n  set margin(v: any) {\n    this._margin = coerceNumberProperty(v);\n  }\n  get margin() { return this._margin; }\n  private _margin = 0;\n\n  @Input()\n  config!: ChartConfig<D>;\n\n  svg!: Selection<any, any, any, any>;\n  svgInner!: Selection<SVGGElement, any, any, any>;\n  yScale!: d3.ScaleLinear<number, number, never>;\n  xScale!: d3.ScaleTime<number, number, never>;\n  xAxis!: Selection<SVGGElement, any, any, any>;\n  yAxis!: Selection<SVGGElement, any, any, any>;\n\n  @Input()\n  set showAxis(v: any) {\n    this._showAxis = coerceBooleanProperty(v);\n  }\n  get showAxis() {\n    return this._showAxis;\n  }\n  private _showAxis = true;\n\n  constructor(\n    public chartElem: ElementRef,\n    private app: AppComponent\n  ) { }\n\n  ngOnInit() {\n    if (!this.config) {\n      this.config = DefaultChartConfig as any;\n    }\n\n    const observer = new ResizeObserver(() => {\n      this.redraw();\n    })\n\n    observer.observe(this.chartElem.nativeElement)\n\n    this.destroyRef.onDestroy(() => observer.disconnect())\n\n  }\n\n  ngAfterViewInit(): void {\n    requestAnimationFrame(() => {\n      this.redraw()\n    })\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (Object.prototype.hasOwnProperty.call(changes, 'config') && this.config) {\n      this.redraw()\n      return\n    }\n\n    if (Object.prototype.hasOwnProperty.call(changes, 'data') && this.data) {\n      this.drawChart();\n    }\n  }\n\n  get yMargin() {\n    if (this.showAxis) {\n      return 16;\n    }\n    return 0;\n  }\n\n  redraw(event?: Event) {\n    if (!!this.svg) {\n      this.svg.remove();\n    }\n\n    this.initializeChart();\n    this.drawChart();\n  }\n\n  private initializeChart(): void {\n    this.width = this.chartElem.nativeElement.getBoundingClientRect().width;\n    this.height = this.chartElem.nativeElement.getBoundingClientRect().height;\n\n    this.svg = d3\n      .select(this.chartElem.nativeElement)\n      .append('svg')\n\n    this.svg.attr('width', this.width);\n    this.svg.attr('height', this.height);\n\n    this.svgInner = this.svg\n      .append('g')\n      .attr('height', '100%');\n\n    this.yScale = d3\n      .scaleLinear()\n\n    this.xScale = d3.scaleTime();\n\n    // setup event handlers to higlight the closest data points\n    let lastClosestIndex = -1;\n\n    if (this.config.showDataPoints) {\n      const self = this;\n      this.svg\n        .on(\"mousemove\", function (event: MouseEvent) {\n          let x = d3.pointer(event)[0];\n\n          let closest = self.data.reduce((best, value, idx) => {\n            let absx = Math.abs(self.xScale(new Date(value.timestamp * 1000)) - x);\n            if (absx < best.value) {\n              return { index: idx, value: absx, timestamp: self.data[idx].timestamp }\n            }\n\n            return best\n\n          }, { index: 0, value: Number.MAX_SAFE_INTEGER, timestamp: 0 })\n\n          if (lastClosestIndex === closest.index) {\n            return;\n          }\n          lastClosestIndex = closest.index;\n\n          if (self.config.tooltipFormat) {\n            // append a title to the parent SVG, this is a quick-fix for showing some\n            // information on the highlighted points\n            // TODO(ppacher): actually render a nice tooltip there.\n            let tooltip = self.svg\n              .select<HTMLTitleElement>('title.tooltip')\n\n            if (tooltip.empty()) {\n              tooltip = self.svg.append(\"title\")\n                .attr(\"class\", \"tooltip\")\n            }\n\n            tooltip\n              .text(self.config.tooltipFormat!(self.data[closest.index]))\n          }\n\n          self.svgInner\n            .select(\".vertical-marker\")\n            .selectAll(\".mouse-position\")\n            .remove()\n\n          self.svgInner\n            .select(\".vertical-marker\")\n            .append(\"line\")\n            .classed(\"mouse-position\", true)\n            .attr(\"x1\", d => self.xScale(closest.timestamp * 1000))\n            .attr(\"y1\", -10)\n            .attr(\"x2\", d => self.xScale(closest.timestamp * 1000))\n            .attr(\"y2\", self.height - self.yMargin)\n            .classed(\"text-secondary text-opacity-50\", true)\n            .attr(\"stroke\", \"currentColor\")\n            .attr(\"stroke-width\", 1)\n            .attr(\"stroke-dasharray\", 2)\n\n          self.svgInner\n            .select(\".points\")\n            .selectAll<SVGCircleElement, [number, number]>(\"circle\")\n            .classed(\"opacity-100\", d => self.xScale.invert(d[0]).getTime() === closest.timestamp * 1000)\n        })\n        .on(\"mouseleave\", function () {\n          lastClosestIndex = -1;\n\n          self.svg.select(\"title.tooltip\")\n            .remove()\n\n          self.svg.select(\"line.mouse-position\")\n            .remove()\n\n          self.svgInner\n            .select(\".points\")\n            .selectAll(\"circle\")\n            .attr(\"r\", 4)\n            .classed(\"opacity-100\", false)\n        })\n    }\n\n    objKeys(this.config.series).forEach(seriesKey => {\n      const seriesConfig = this.config.series[seriesKey]!;\n\n      if (seriesConfig.areaColor) {\n        this.svgInner\n          .append('path')\n          .attr(\"fill\", \"currentColor\")\n          .attr(\"class\", `area-${String(seriesKey)} ${(seriesConfig.areaColor || '')}`)\n      }\n\n      this.svgInner\n        .append('g')\n        .append('path')\n        .style('fill', 'none')\n        .style('stroke', 'currentColor')\n        .style('stroke-width', '1')\n        .attr('class', `line-${String(seriesKey)} ${seriesConfig.lineColor}`)\n    })\n\n    this.svgInner.append(\"g\")\n      .attr(\"class\", \"vertical-marker\")\n\n    this.svgInner.append(\"g\")\n      .attr(\"class\", \"points\")\n\n    if (this.showAxis) {\n      this.yAxis = this.svgInner\n        .append('g')\n        .attr('id', 'y-axis')\n        .attr('class', 'text-secondary text-opacity-75 ')\n        .style('transform', 'translate(' + (this.width - this.yMargin) + 'px,  0)');\n\n      this.xAxis = this.svgInner\n        .append('g')\n        .attr('id', 'x-axis')\n        .attr('class', 'text-secondary text-opacity-50 ')\n        .style('transform', 'translate(0, ' + (this.height - this.yMargin) + 'px)');\n    }\n  }\n\n  private getTimeRange(): { from: Date, to: Date } {\n    const time = {\n      from: this.data[0]?.timestamp || 0,\n      to: this.data[this.data.length - 1]?.timestamp || 0,\n    };\n\n    if (!!this.config.time) {\n      time.from = coerceDate(this.config.time.from).getTime() / 1000\n\n      if (this.config.fromMargin) {\n        time.from = time.from - this.config.fromMargin\n      }\n\n      if (this.config.time.to) {\n        time.to = coerceDate(this.config.time.to).getTime() / 1000\n\n        if (this.config.toMargin) {\n          time.to = time.to + this.config.toMargin\n        }\n      }\n    }\n\n    return {\n      from: new Date(time.from * 1000),\n      to: new Date(time.to * 1000)\n    };\n  }\n\n  private prepareDataSet(data: D[], time: { from: Date, to: Date }) {\n    const toTimestamp = Math.round(time.to.getTime() / 1000)\n    const fromTimestamp = Math.round(time.from.getTime() / 1000)\n\n    // first, filter out all elements that are before or after the to date\n    data = data.filter(d => {\n      return d.timestamp >= fromTimestamp && d.timestamp <= toTimestamp\n    })\n\n    // check if we need to fill empty ticks\n    if (!this.config.fillEmptyTicks) {\n      return data;\n    }\n\n    const interval = this.config.fillEmptyTicks.interval;\n\n    const filledData: D[] = [];\n    const addEmpty = (ts: number) => {\n      const empty: any = {\n        timestamp: ts,\n      }\n\n      Object.keys(this.config.series)\n        .forEach(s => empty[s] = 0)\n\n      filledData.push(empty)\n    }\n\n    if (!data.length) {\n      return [];\n    }\n\n    let firstElement = data[0].timestamp;\n    if (this.config.time?.from) {\n      firstElement = Math.round(coerceDate(this.config.time.from).getTime() / 1000)\n    }\n\n    // add empty values for the start-time until the first element / or the start tme\n    let lastTimeStamp = fromTimestamp - interval;\n    for (let ts = lastTimeStamp; ts <= firstElement; ts += interval) {\n      addEmpty(ts)\n    }\n\n    // add emepty vaues for each missing tick during the dataset\n    lastTimeStamp = firstElement;\n    for (let idx = 0; idx < data.length; idx++) {\n      const elem = data[idx]\n      const elemTs = elem.timestamp;\n\n      for (let ts = lastTimeStamp + interval; ts < elemTs; ts += interval) {\n        addEmpty(ts)\n      }\n\n      filledData.push(elem)\n      lastTimeStamp = elemTs\n    }\n\n    // if there's a specified end-time, add empty ticks from the last datapoint\n    // to the end-time\n    if (this.config.time?.to) {\n      for (let ts = lastTimeStamp + interval; ts <= toTimestamp; ts += interval) {\n        addEmpty(ts)\n      }\n    }\n\n    return filledData\n  }\n\n  private drawChart(): void {\n    if (!this.svg) {\n      return;\n    }\n\n    if (!this.data?.length) {\n      return;\n    }\n\n    this.data.sort((a, b) => a.timestamp - b.timestamp)\n\n    // determine the time range that should be displayed.\n    const time = this.getTimeRange();\n\n    // fill empty ticks depending on the configuration.\n    this.preparedData = this.prepareDataSet(this.data, time)\n\n    this.xScale\n      .range([0, this.width - this.yMargin])\n      .domain([time.from, time.to]);\n\n    this.yScale\n      .range([0, this.height - this.yMargin])\n      .domain([\n        d3.max(this.preparedData.map(d => {\n          return d3.max(\n            objKeys(this.config.series)\n              .map(series => {\n                return d[series] as number\n              })\n          )!\n        }))! * 1.3,  // 30% margin to top\n        0\n      ])\n\n    if (this.showAxis) {\n      const xAxis = d3\n        .axisBottom(this.xScale)\n        .ticks(5)\n        .tickFormat((val, idx) => {\n          if (!!this.config.timeFormat) {\n            return this.config.timeFormat(val as any)\n          }\n          return timeAgo(val as any);\n        })\n\n      this.xAxis.call(xAxis);\n\n      const yAxis = d3\n        .axisLeft(this.yScale)\n        .ticks(2)\n        .tickFormat(d => ((this.config.valueFormat || this.yScale.tickFormat(2)) as any)(d, undefined))\n\n      this.yAxis.call(yAxis);\n    }\n\n    const line = d3\n      .line()\n      .x(d => d[0])\n      .y(d => d[1])\n      .curve(d3.curveMonotoneX);\n\n    // define the area\n    const area = d3.area()\n      .x(d => d[0])\n      .y0(this.height - this.yMargin)\n      .y1(d => d[1])\n      .curve(d3.curveMonotoneX)\n\n    // render vertical markers\n    const markers = (this.config.verticalMarkers || [])\n      .filter(marker => !!marker.time)\n      .map(marker => ({\n        text: marker.text,\n        time: coerceDate(marker.time)\n      }));\n\n    this.svgInner.select('.vertical-marker')\n      .selectAll(\"line.marker\")\n      .data(markers)\n      .join(\"line\")\n      .classed(\"marker\", true)\n      .attr(\"x1\", d => this.xScale(d.time))\n      .attr(\"y1\", -10)\n      .attr(\"x2\", d => this.xScale(d.time))\n      .attr(\"y2\", this.height - this.yMargin)\n      .classed(\"text-secondary text-opacity-50\", true)\n      .attr(\"stroke\", \"currentColor\")\n      .attr(\"stroke-width\", 3)\n      .attr(\"stroke-dasharray\", 4)\n      .append(\"title\")\n      .text(d => d.text)\n\n    // TODO(ppacher): somehow d3 does not recognize which data points must be removed\n    // or re-placed. For now, just remove them all\n    this.svgInner\n      .select('.points')\n      .selectAll(\"circle\")\n      .remove()\n\n    objKeys(this.config.series)\n      .forEach(seriesKey => {\n        const config = this.config.series[seriesKey]!;\n\n        let points: [number, number][] = this.preparedData\n          .map(d => [\n            this.xScale(new Date(d.timestamp * 1000)),\n            this.yScale((d as any)[seriesKey] || 0),\n          ])\n\n        let data: [number, number][] = this.preparedData\n          .map(d => [\n            this.xScale(new Date(d.timestamp * 1000)),\n            this.yScale((d as any)[seriesKey] || 0),\n          ])\n\n        if (config.areaColor) {\n          this.svgInner.selectAll(`.area-${String(seriesKey)}`)\n            .data([data])\n            .attr('d', area(data))\n        }\n\n        this.svgInner.select(`.line-${String(seriesKey)}`)\n          .attr('d', line(data))\n\n        if (this.config?.showDataPoints) {\n          this.svgInner\n            .select('.points')\n            .selectAll(`circle.point-${String(seriesKey)}`)\n            .data(points)\n            .enter()\n            .append(\"circle\")\n            .classed(`points-${String(seriesKey)}`, true)\n            .attr(\"r\", \"4\")\n            .attr(\"fill\", \"currentColor\")\n            .attr(\"class\", `opacity-0 ${config.lineColor}`)\n            .attr(\"cx\", d => d[0])\n            .attr(\"cy\", d => d[1])\n            .append(\"title\")\n            .text(d => ((this.config.valueFormat || this.yScale.tickFormat(2)) as any)(this.yScale.invert(d[1]), String(seriesKey)))\n        }\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/netquery.component.html",
    "content": "<div class=\"sticky top-0 z-50 flex flex-row items-center w-full mb-2 bg-background\" *ngIf=\"tagbarValues?.length\">\n\n  <sfng-netquery-tagbar [(ngModel)]=\"tagbarValues\" (ngModelChange)=\"onTagbarChange($event)\" [labels]=\"keyTranslation\"\n    class=\"p-2 bg-gray-300 rounded-l-sm\">\n  </sfng-netquery-tagbar>\n\n  <div\n    class=\"flex items-center justify-center h-full px-3 py-2 bg-gray-200 rounded-r-sm cursor-pointer hover:text-primary text-tertiary\"\n    (click)=\"copyQuery()\" sfng-tooltip=\"Copy query to clipboard\" snfgTooltipPosition=\"left\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"\n      stroke-width=\"2\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n    </svg>\n  </div>\n\n  <button class=\"bg-transparent hover:bg-transparent ml-2 cursor-pointer text-tertiary text-xxs hover:text-primary p-2\" (click)=\"clearQuery()\" (keyup.enter)=\"clearQuery()\">\n    Clear All\n  </button>\n</div>\n\n<div class=\"flex flex-row items-center w-full gap-2\">\n  <sfng-netquery-searchbar [(ngModel)]=\"textSearch\" (ngModelChange)=\"performSearch()\" class=\"block w-full\"\n    [labels]=\"keyTranslation\" (fieldsParsed)=\"onFieldsParsed($event)\"></sfng-netquery-searchbar>\n  <button type=\"button\" class=\"h-full rounded-r-sm btn\" (click)=\"performSearch()\">Reload</button>\n</div>\n\n<div class=\"flex flex-row flex-wrap items-center w-full gap-3\">\n  <!--\n    Search / Suggestion boxes for most-commonly used filters\n  -->\n  <ng-container *ngFor=\"let field of (models | keyvalue)\">\n    <ng-container *ngIf=\"field.value!.visible === true\">\n      <sfng-select mode=\"multi\" [itemName]=\"keyTranslation[field.key] || field.key\" dynamicValues=\"true\"\n        [placeholder]=\"keyTranslation[field.key] || field.key\" [(ngModel)]=\"field.value!.searchValues\"\n        allowSearch=\"true\" searchItemThreshold=\"5\" itemLimit=\"10\"\n        [searchPlaceholder]=\"'Search' + (keyTranslation[field.key] || field.key)\" minWidth=\"400\" minHeight=\"300\"\n        (ngModelChange)=\"performSearch()\" (opened)=\"loadSuggestion(field.key)\"\n        [dynamicValueTemplate]=\"dynamicValueTemplate\" [sortBy]=\"sortByCount\">\n        <ng-container *ngIf=\"field.value?.loading\">\n          <sfng-select-item *sfngSelectValue=\"null; disabled: true\" class=\"text-secondary\">Loading ...\n          </sfng-select-item>\n        </ng-container>\n\n        <ng-container *ngFor=\"let value of field.value?.suggestions; trackBy: trackSuggestion\">\n          <sfng-select-item\n            *sfngSelectValue=\"value.Value; data:value.count, label:value.Name || (value.Value === '' ? 'N/A' : value.Value)\">\n            <span *ngIf=\"field.key === 'country' && !!value.Name\" [appCountryFlags]=\"value.Name\"></span>\n            <span class=\"flex-grow inline-block overflow-hidden overflow-ellipsis whitespace-nowrap\"\n              style=\"max-width: 20rem; direction: rtl;\">\n              <span style=\"direction: ltr; unicode-bidi: bidi-override;\">\n                {{ value.Name || 'N/A' }}\n              </span>\n            </span>\n            <span class=\"pr-3 text-xxs text-tertiary whitespace-nowrap\">\n              #{{ value.count }} connections\n            </span>\n          </sfng-select-item>\n\n        </ng-container>\n      </sfng-select>\n\n      <ng-template #dynamicValueTemplate let-item>\n        <sfng-select-item>\n          <span *ngIf=\"field.key === 'country' && !!item.value\" [appCountryFlags]=\"item.value\"></span>\n          <span class=\"flex-grow inline-block overflow-hidden overflow-ellipsis whitespace-nowrap\"\n            style=\"max-width: 20rem; direction: rtl;\">\n            <span style=\"direction: ltr; unicode-bidi: bidi-override;\">\n              {{ item.value || 'N/A' }}\n            </span>\n          </span>\n        </sfng-select-item>\n      </ng-template>\n    </ng-container>\n  </ng-container>\n\n\n  <!-- The combinded \"more\" drop-down that should look like a select component -->\n  <ng-template #selectTemplate>\n    <button class=\"sfng-select\" [class.active]=\"customDropdown.isOpen\">\n      <span>More</span>\n      <div class=\"arrow\">\n        <svg viewBox=\"0 0 24 24\" class=\"arrow-icon\">\n          <g fill=\"none\" class=\"inner\">\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2.2\" d=\"M10 16l4-4-4-4\" />\n          </g>\n        </svg>\n      </div>\n    </button>\n  </ng-template>\n\n  <sfng-dropdown #customDropdown [triggerTemplate]=\"selectTemplate\" overlayClass=\"grid grid-cols-4\">\n    <ng-container *ngFor=\"let model of (models | keyvalue | combinedMenu); let last=last\">\n      <div class=\"border-gray-400 sfng-select-dropdown\" [class.border-r]=\"!last\">\n        <h3 class=\"flex items-center gap-2 px-3 py-0.5 mb-0 border-b border-gray-300 text-xxs text-secondary\">\n          <span>Filter by {{ model.value!.menuTitle || model.key }}</span>\n          <sfng-tipup [key]=\"model.value!.tipupKey\" *ngIf=\"!!model.value!.tipupKey\"></sfng-tipup>\n        </h3>\n        <ul>\n          <li class=\"px-3\" *ngFor=\"let value of model.value!.suggestions\" [class.bg-gray-300]=\"value.selected\">\n            <sfng-select-item (click)=\"toggleCombinedMenuFilter(model.key, value)\" class=\"grid w-full grid-cols-3\">\n              <span class=\"col-span-2\">\n                {{ value.Name }}\n              </span>\n\n              <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 transition-all duration-200\" viewBox=\"0 0 20 20\"\n                fill=\"currentColor\" [class.opacity-0]=\"!value.selected\">\n                <path fill-rule=\"evenodd\"\n                  d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n                  clip-rule=\"evenodd\" />\n              </svg>\n            </sfng-select-item>\n          </li>\n        </ul>\n      </div>\n    </ng-container>\n  </sfng-dropdown>\n\n\n  <div class=\"flex-grow\"></div>\n\n  <div class=\"flex flex-row items-center gap-2 px-2 bg-gray-300 border border-gray-300 rounded text-xxs\"\n    *ngIf=\"(canUseHistory$ | async)\">\n    Search History:\n    <nz-range-picker [nzShowTime]=\"false\" class=\"py-0\" [nzRenderExtraFooter]=\"customTimeRange\" [(ngModel)]=\"dateFilter\"\n      [nzBorderless]=\"true\" (ngModelChange)=\"onDateRangeChange($event)\" [nzAllowClear]=\"true\" [nzFormat]=\"dateFormat\">\n    </nz-range-picker>\n\n    <ng-template #customTimeRange>\n      <span class=\"py-2 uppercase text-xxs text-secondary\">Quick Settings</span>\n      <ul class=\"grid grid-flow-row grid-cols-3 py-2 text-xs\">\n        <li tabindex=\"0\" *ngFor=\"let qds of quickDateSettings\" (click)=\"applyQuickDateSetting(qds)\" (keyup.enter)=\"applyQuickDateSetting(qds)\"\n          class=\"cursor-pointer text-secondary hover:text-primary px-2 py-1.5 hover:bg-gray-500 hover:bg-opacity-50 rounded-md\">\n          {{ qds.name }}\n        </li>\n      </ul>\n    </ng-template>\n  </div>\n\n  <div class=\"flex flex-row items-center gap-3\">\n    <!--\n      Group-By selection\n    -->\n    <sfng-select mode=\"multi\" itemName=\"Group By\" placeholder=\"Group By\" allowSearch=\"false\" [(ngModel)]=\"groupByKeys\"\n      (ngModelChange)=\"performSearch()\">\n      <ng-container *ngFor=\"let value of allowedGroupBy\">\n        <sfng-select-item *sfngSelectValue=\"value\">\n          {{ keyTranslation[value] || value }}\n        </sfng-select-item>\n      </ng-container>\n    </sfng-select>\n\n    <!--\n      Order-By selection\n    -->\n    <sfng-select mode=\"multi\" itemName=\"Sort\" placeholder=\"Sort\" allowSearch=\"false\" [(ngModel)]=\"orderByKeys\"\n      (ngModelChange)=\"performSearch()\">\n      <ng-container *ngFor=\"let value of allowedOrderBy\">\n        <sfng-select-item *sfngSelectValue=\"value\">\n          {{ keyTranslation[value] || value }}\n        </sfng-select-item>\n      </ng-container>\n    </sfng-select>\n\n  </div>\n</div>\n\n<div class=\"relative flex-shrink-0 my-1 bg-gray-200 p-2 rounded grid\" [class.grid-cols-2]=\"featureBw$ | async\">\n  <div>\n    <h2 class=\"text-secondary text-xxs uppercase font-light p-0 m-0 mb-1 w-full text-center\">Connections</h2>\n    <div class=\"h-32\">\n      <sfng-netquery-line-chart [data]=\"connectionChartData\" class=\"h-full\" *ngIf=\"connectionChartData.length > 0\" [@fadeIn]></sfng-netquery-line-chart>\n    </div>\n  </div>\n\n  <div *ngIf=\"featureBw$ | async\">\n    <h2 class=\"text-secondary text-xxs uppercase font-light p-0 m-0 mb-1 w-full text-center\">Data Usage</h2>\n    <div class=\"h-32\">\n      <sfng-netquery-line-chart [config]=\"bwChartConfig\" [data]=\"bwChartData\" class=\"h-full\" *ngIf=\"!!bwChartData?.length\" [@fadeIn]></sfng-netquery-line-chart>\n    </div>\n  </div>\n\n  <div class=\"absolute top-0 bottom-0 left-0 right-0 flex items-center justify-center text-secondary\"\n    *ngIf=\"loading || connectionChartData.length === 0\">\n    Loading Chart\n  </div>\n</div>\n\n<ng-template #headerTemplate let-data let-active=\"active\">\n  <div class=\"relative flex flex-row items-center w-full gap-3 px-3 bg-gray-200\"\n    [ngClass]=\"{'rounded-sm': !active, 'rounded-t-sm': active, 'py-2': !!data._group, 'py-1': !data._group}\">\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 transition-all duration-150 transform\"\n      [class.rotate-90]=\"active\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n      <path fill-rule=\"evenodd\"\n        d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\n        clip-rule=\"evenodd\" />\n    </svg>\n\n    <!-- Group-By VIew -->\n    <ng-template [ngIf]=\"!!data._group\" [ngIfElse]=\"connView\">\n      <app-count-indicator [count]=\"data.totalCount\" [countAllowed]=\"data.countAllowed\">\n      </app-count-indicator>\n\n      <span *ngFor=\"let key of groupByKeys\" class=\"flex flex-row items-center gap-1 overflow-hidden whitespace-nowrap\">\n        <span class=\"text-xxs text-secondary\" *ngIf=\"groupByKeys.length !== 1\">{{ keyTranslation[key] || key }}</span>\n\n        <!-- Country specific colum rendering -->\n        <span class=\"text-primary\" *ngIf=\"key === 'country' && !!data[key]\"\n          [appCountryFlags]=\"data[key]\">{{ data[key] || 'N/A' }}</span>\n\n\n        <!-- Profile specific column rendering -->\n        <span *ngIf=\"key === 'profile' && !!data.__profile\" class=\"flex flex-row items-center gap-2\">\n          <app-icon [profile]=\"data.__profile\"></app-icon>\n          <span>{{ data.__profile.Name }}</span>\n        </span>\n\n        <!-- SPN Pin specific column rendering -->\n        <span *ngIf=\"key === 'exit_node' && !!data.__exitNode\" class=\"flex flex-row items-center gap-2\">\n          <span class=\"text-secondary text-xxs\">\n            (\n            <span class=\"text-primary\"\n              *ngIf=\"(data.__exitNode.EntityV4 || data.__exitNode.EntityV6)?.Country as country\"\n              [appCountryFlags]=\"country\"></span>\n            )\n          </span>\n          <span>{{ data.__exitNode.Name }}</span>\n        </span>\n\n        <!-- everything else -->\n        <span style=\"direction: rtl\" *ngIf=\"key !== 'domain' && key !== 'profile' && key !== 'exit_node'\"\n          class=\"overflow-hidden text-primary overflow-ellipsis\">\n          <span style=\"direction: ltr; unicode-bidi: bidi-override;\">\n            {{ data[key] || 'N/A' }}\n          </span>\n        </span>\n\n        <sfng-netquery-scope-label *ngIf=\"key === 'domain'\" [scope]=\"data[key]\" style=\"direction: rtl\"\n          class=\"overflow-hidden text-primary overflow-ellipsis\">\n        </sfng-netquery-scope-label>\n      </span>\n\n      <div class=\"flex-grow\"></div>\n      <div>\n        <app-menu-trigger [menu]=\"groupedMenu\"></app-menu-trigger>\n        <app-menu #groupedMenu>\n          <app-menu-item (activate)=\"useAsFilter(data)\">Use as filter</app-menu-item>\n          <app-menu-item *ngIf=\"data.__profile\"\n            (activate)=\"router.navigate(['/app', data.__profile.Source, data.__profile.ID])\">App Settings\n          </app-menu-item>\n        </app-menu>\n      </div>\n\n      <ng-container *ngIf=\"(data._chart | async) as chartData\" class=\"relative\">\n        <sfng-netquery-line-chart [data]=\"$any(chartData)\" showAxis=\"false\" margin=\"0\"\n          class=\"absolute top-0 bottom-0 right-0 w-64 bg-gray-100 bg-opacity-25 border border-gray-400 border-opacity-25 rounded-r opacity-75 shadow-inner-xs\">\n        </sfng-netquery-line-chart>\n      </ng-container>\n      <!-- placeholder for the chart -->\n      <div style=\"flex-basis: 14.5rem\"></div>\n    </ng-template>\n\n    <ng-template #connView>\n      <sfng-netquery-connection-row [conn]=\"data\"></sfng-netquery-connection-row>\n    </ng-template>\n\n  </div>\n</ng-template>\n\n<!-- \"Total connections & LastReload info \"-->\n<div class=\"flex flex-row items-center justify-start gap-3\">\n\n  <span class=\"text-xxs text-primary\" *ngIf=\"!loading\">{{ totalResultCount }} Results\n    <span class=\"text-secondary\">of {{totalConnCount}} total connections</span>\n  </span>\n  <span class=\"flex-grow\"></span>\n\n  <div class=\"flex flex-row items-center\">\n    <div class=\"flex flex-row\">\n\n      <!-- Auto-Reload Interval selector -->\n      <app-menu-trigger [menu]=\"autoReloadMenu\" useContent=\"true\"\n        class=\"text-secondary hover:text-primary flex !m-0\" \n        >\n        <div class=\"flex flex-row items-center\">\n          <!-- Auto-Reload Interval countdown--->\n          <span *ngIf=\"!!autoReloadIntervalName\" class=\"pr-3 text-xxs text-secondary\" style=\"opacity: 0.5;\" >\n            {{autoReloadIntervalName}} \n            \n            <span *ngIf=\"(autoReloadInterval$ | async) as interval\">\n              <span *ngIf=\"interval > 0 && interval <= 30\">\n                (in {{interval}} sec)\n              </span>\n            </span>            \n          </span>\n\n          <!-- Last Reload Time -->\n          <span class=\"pr-3 text-xxs text-secondary\" [ngClass]=\"{\n            'text-yellow-300': ((lastReloadTicker|async)||0) > 60,\n            'text-red-300': ((lastReloadTicker|async)||0) > 600\n          }\">\n          Last Reload: {{ lastReload | timeAgo:(lastReloadTicker|async) }}\n          </span>\n\n          <svg xmlns=\"http://www.w3.org/2000/svg\" \n            class=\"w-4 h-4\"          \n            fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n            <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n              d=\"M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4\" />\n          </svg>\n        </div>\n      </app-menu-trigger>\n\n      <app-menu #autoReloadMenu>\n        <app-menu-item *ngFor=\"let value of reloadIntervals\" (click)=\"onAutoRefreshChange(value)\">\n        {{value}}\n        </app-menu-item>\n      </app-menu>\n    </div>\n  </div>\n\n</div>\n\n<sfng-pagination *ngIf=\"!loading; else: loadingTemplate\" [source]=\"paginator\" class=\"flex flex-col\">\n  <ng-template [sfngPageContent]>\n    <sfng-accordion-group class=\"flex flex-col gap-2 pr-4\"\n      *ngIf=\"(paginator.pageLoading$ | async) === false; else: loadingTemplate\" [headerTemplate]=\"headerTemplate\"\n      singleMode=\"false\">\n\n      <sfng-accordion [data]=\"result\" #accordion\n        *ngFor=\"let result of (paginator.pageItems$ | async); trackBy: trackPageItem\">\n        <div *ngIf=\"accordion.active\" class=\"p-3 bg-opacity-75 border-gray-300 rounded-b-sm\"\n          [ngClass]=\"{'bg-gray-300 border-t': !result._group}\">\n\n          <!-- nested accordion for connections inside a group -->\n          <ng-container *ngIf=\"result._group !== null; else: connectionDetails\">\n            <sfng-accordion-group class=\"flex flex-col gap-2 ml-4\"\n              *ngIf=\"(result._group | async) as connsPaginator; else: loadingTemplate\" [headerTemplate]=\"headerTemplate\"\n              singleMode=\"false\">\n\n              <div class=\"flex flex-row items-center p-2 text-secondary\" *ngIf=\"connsPaginator.total === 0\">\n                All connections ended more than 10 minutes ago and have been removed.\n              </div>\n\n              <sfng-pagination [source]=\"connsPaginator\" class=\"flex flex-col flex-grow gap-2\">\n                <ng-template [sfngPageContent]>\n                  <sfng-accordion *ngFor=\"let conn of (connsPaginator.pageItems$ | async); trackBy: trackConnection\"\n                    [data]=\"conn\" #subAccordion>\n                    <div *ngIf=\"subAccordion.active\"\n                      class=\"p-3 bg-gray-300 bg-opacity-75 border-t border-gray-300 rounded-b-sm\">\n                      <ng-container *ngTemplateOutlet=\"connectionDetails; context: {$implicit: conn}\"></ng-container>\n                    </div>\n                  </sfng-accordion>\n                </ng-template>\n              </sfng-pagination>\n            </sfng-accordion-group>\n          </ng-container>\n\n          <!-- connection template -->\n          <ng-template #connectionDetails let-conn>\n            <!-- ng-if used to delcare a local variable as an \"alias\" to (conn || result) -->\n            <ng-container *ngIf=\"(conn || result) as data\">\n              <sfng-netquery-conn-details [conn]=\"data\">\n              </sfng-netquery-conn-details>\n            </ng-container>\n          </ng-template>\n        </div>\n      </sfng-accordion>\n    </sfng-accordion-group>\n  </ng-template>\n</sfng-pagination>\n\n\n<ng-template #loadingTemplate>\n  <div class=\"flex flex-col items-center justify-center flex-grow gap-2 text-tertiary\">\n    <svg class=\"w-6 h-6 text-secondary animate-spin\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n      <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n      <path class=\"opacity-75\" fill=\"currentColor\"\n        d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\">\n      </path>\n    </svg>\n    Loading connections ...\n  </div>\n</ng-template>\n\n<div class=\"flex flex-row items-center justify-center flex-shrink-0 w-full gap-1 text-xxs text-tertiary\"\n  *appExpertiseLevel=\"'expert'\">\n  <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-3 h-3 -mt-0.5 text-primary\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n    <path\n      d=\"M11 3a1 1 0 10-2 0v1a1 1 0 102 0V3zM15.657 5.757a1 1 0 00-1.414-1.414l-.707.707a1 1 0 001.414 1.414l.707-.707zM18 10a1 1 0 01-1 1h-1a1 1 0 110-2h1a1 1 0 011 1zM5.05 6.464A1 1 0 106.464 5.05l-.707-.707a1 1 0 00-1.414 1.414l.707.707zM5 10a1 1 0 01-1 1H3a1 1 0 110-2h1a1 1 0 011 1zM8 16v-1h4v1a2 2 0 11-4 0zM12 14c.015-.34.208-.646.477-.859a4 4 0 10-4.954 0c.27.213.462.519.476.859h4.002z\" />\n  </svg>\n  <span class=\"font-semibold text-primary\">Pro Tip:</span>\n  <span class=\"flex items-center gap-1 protip\">\n    <ng-container *ngTemplateOutlet=\"proTips?.get(proTipIdx) || null\"></ng-container>\n  </span>\n</div>\n\n<ng-template #proTip>\n  Press\n  <pre>CTRL + Space</pre>\n  on any page to bring up the quick search box.\n</ng-template>\n\n<ng-template #proTip>\n  Use your keyboard arrows to navigate through the search suggestions. Press\n  <pre>ENTER</pre> to search for the suggestion or use\n  <pre>Shift + Enter</pre> to add it to the search text.\n</ng-template>\n\n<ng-template #proTip>\n  Inside the search box, use\n  <pre>Ctrl + Space</pre> to force loading suggestions.\n</ng-template>\n\n<ng-template #proTip>\n  Use\n  <pre>Shift + Click</pre> to add connection attributes to the current filter.\n</ng-template>\n\n<ng-template #proTip>\n  Hold\n  <pre>Shift</pre> to highlight attributes that can be used in the filter.\n</ng-template>\n\n<ng-template #proTip>\n  Hold\n  <pre>CTRL</pre> and click attributes to copy them to the clipboard.\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/netquery.component.ts",
    "content": "import { coerceArray } from \"@angular/cdk/coercion\";\nimport { FormatWidth, formatDate, getLocaleDateFormat, getLocaleId } from \"@angular/common\";\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, EventEmitter, Input, LOCALE_ID, OnDestroy, OnInit, Output, QueryList, TemplateRef, TrackByFunction, ViewChildren, inject, isDevMode } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { ActivatedRoute, Router } from \"@angular/router\";\nimport { BandwidthChartResult, ChartResult, Condition, Database, FeatureID, GreaterOrEqual, IPScope, LessOrEqual, Netquery, NetqueryConnection, OrderBy, Pin, PossilbeValue, Query, QueryResult, SPNService, Select, Verdict } from \"@safing/portmaster-api\";\nimport { Datasource, DynamicItemsPaginator, SelectOption } from \"@safing/ui\";\nimport { BehaviorSubject, Observable, Subject, combineLatest, forkJoin, interval, merge, of, timer } from \"rxjs\";\nimport { catchError, filter, map, share, skip, startWith, switchMap, take, takeUntil } from \"rxjs/operators\";\nimport { ActionIndicatorService } from \"../action-indicator\";\nimport { ExpertiseService } from \"../expertise\";\nimport { objKeys } from \"../utils\";\nimport { fadeInAnimation } from './../animations';\nimport { IPScopeNames, LocalAppProfile, NetqueryHelper } from \"./connection-helper.service\";\nimport { SfngSearchbarFields } from \"./searchbar\";\nimport { SfngTagbarValue } from \"./tag-bar\";\nimport { Parser } from \"./textql\";\nimport { connectionFieldTranslation, mergeConditions } from \"./utils\";\nimport { DefaultBandwidthChartConfig } from \"./line-chart/line-chart\";\nimport { INTEGRATION_SERVICE } from \"src/app/integration\";\n\ninterface Suggestion<T = any> extends PossilbeValue<T> {\n  count: number;\n  selected?: boolean;\n}\n\ninterface Model<T> {\n  suggestions: Suggestion<T>[];\n  searchValues: any[];\n  visible: boolean | 'combinedMenu';\n  menuTitle?: string;\n  loading: boolean;\n  tipupKey?: string;\n  virtual?: boolean;\n}\n\nconst freeTextSearchFields: (keyof Partial<NetqueryConnection>)[] = [\n  'domain',\n  'as_owner',\n  'path',\n  'profile_name',\n  'remote_ip'\n]\n\nconst groupByKeys: (keyof Partial<NetqueryConnection>)[] = [\n  'domain',\n  'as_owner',\n  'country',\n  'direction',\n  'path',\n  'profile'\n]\n\nconst orderByKeys: (keyof Partial<NetqueryConnection>)[] = [\n  'domain',\n  'as_owner',\n  'country',\n  'direction',\n  'path',\n  'started',\n  'ended',\n  'profile',\n]\n\nexport const reloadIntervalValues: { [key: string]: number } = {\n  \"⏸\\u00A0\\u00A0Don't auto-reload\": 0,\n  \"↻\\u00A0\\u00A0Reload every 10 seconds\": 10,\n  \"↻\\u00A0\\u00A0Reload every 1 minute\": 60,\n  \"↻\\u00A0\\u00A0Reload every 5 minutes\": 300,\n}\n\ninterface LocalQueryResult extends QueryResult {\n  _chart: Observable<ChartResult[]> | null;\n  _group: Observable<DynamicItemsPaginator<NetqueryConnection>> | null;\n  __profile?: LocalAppProfile;\n  __exitNode?: Pin;\n}\n\ninterface QuickDateSetting {\n  name: string;\n  apply: () => [Date, Date];\n}\n\n/**\n * Netquery Viewer\n *\n * This component is the actual viewer component for the netquery subsystem of the Portmaster.\n * It allows the user to specify connection filters in multiple different ways and allows\n * to do a deep-dive into all connections seen by the Portmaster (that are still stored in\n * the in-memory SQLite database of the netquery subsystem).\n *\n * The user is able to modify the filter query by either:\n *  - using the available drop-downs\n *  - using the searchbar which\n *    - supports typed searches for connection fields (i.e. country:AT domain:google.at)\n *    - free-text search across the list of supported \"full-text\" search fields (see freeTextSearchFields)\n *  - by shift-clicking any value that has a SfngAddToFilter directive\n *  - by removing values from the tag bar.\n */\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'sfng-netquery-viewer',\n  templateUrl: './netquery.component.html',\n  providers: [\n    NetqueryHelper,\n  ],\n  styles: [\n    `\n    :host {\n      @apply flex flex-col gap-3 pr-3 min-h-full;\n    }\n\n    .protip pre {\n      @apply inline-block text-xxs uppercase rounded-sm bg-gray-500 bg-opacity-25 font-mono border-gray-500 border px-0.5;\n    }\n    `\n  ],\n  animations: [\n    fadeInAnimation\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\n// eslint-disable-next-line @angular-eslint/component-class-suffix\nexport class SfngNetqueryViewer implements OnInit, OnDestroy, AfterViewInit {\n  /** @private Used to trigger a reload of the current filter */\n  private search$ = new Subject<void>();\n\n  /** @private The DestroyRef of the component, required for takeUntilDestroyed */\n  private destroyRef = inject(DestroyRef);\n\n  /** @private Used to trigger an update of all displayed values in the tag-bar. */\n  private updateTagBar$ = new BehaviorSubject<void>(undefined);\n\n  /** @private Whether or not the next update on ActivatedRoute should be ignored */\n  private skipNextRouteUpdate = false;\n\n  /** @private Whether or not we should update the URL when performSearch() finishes */\n  private skipUrlUpdate = false;\n\n  /** @private The LOCALE_ID to format dates. */\n  private localeId = inject(LOCALE_ID);\n\n  private integration = inject(INTEGRATION_SERVICE);\n\n  /** @private the date format for the nz-range-picker */\n  dateFormat = getLocaleDateFormat(getLocaleId(this.localeId), FormatWidth.Medium)\n\n  /** @private A list of quick-date settings for the nz-range-picker */\n  quickDateSettings: QuickDateSetting[] = [\n    {\n      name: 'Today',\n      apply: () => {\n        const now = new Date();\n        return [\n          new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0),\n          new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, -1),\n        ]\n      }\n    },\n    {\n      name: 'Last 24 Hours',\n      apply: () => {\n        const now = new Date();\n        return [\n          new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours() - 24, now.getMinutes(), now.getSeconds()),\n          now\n        ]\n      }\n    },\n    {\n      name: 'Last 7 Days',\n      apply: () => {\n        const now = new Date();\n        return [\n          new Date(now.getFullYear(), now.getMonth(), now.getDate() - 7, now.getHours(), now.getMinutes(), now.getSeconds()),\n          now,\n        ]\n      }\n    },\n    {\n      name: 'Last Month',\n      apply: () => {\n        const now = new Date();\n        return [\n          new Date(now.getFullYear(), now.getMonth() - 1, now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds()),\n          now,\n        ]\n      }\n    },\n  ]\n\n  applyQuickDateSetting(qds: QuickDateSetting) {\n    const [from, to] = qds.apply()\n\n    const fromStr = formatDate(from, 'medium', this.localeId)\n    const toStr = formatDate(to, 'medium', this.localeId)\n\n    this.onFieldsParsed({\n      from: [fromStr],\n      to: [toStr]\n    }, true)\n  }\n\n  /** @private - The paginator used for the result set */\n  paginator!: DynamicItemsPaginator<LocalQueryResult>;\n\n  /** @private - The total amount of connections without the filter applied */\n  totalConnCount: number = 0;\n\n  /** @private - The total amount of connections with the filter applied */\n  totalResultCount: number = 0;\n\n  /** The value of the free-text search */\n  textSearch: string = '';\n\n  /** The date filter */\n  dateFilter: Date[] = []\n\n  /** a list of allowed group-by keys */\n  readonly allowedGroupBy = groupByKeys;\n\n  /** a list of allowed order-by keys */\n  readonly allowedOrderBy = orderByKeys;\n\n  /** @private Whether or not we are currently loading data */\n  loading = false;\n\n  /** @private The connection chart data */\n  connectionChartData: ChartResult[] = [];\n\n  /** @private The bandwidth chart data */\n  bwChartData: BandwidthChartResult<any>[] = [];\n\n  /** @private The configuration for the bandwidth chart */\n  readonly bwChartConfig = DefaultBandwidthChartConfig;\n\n  /** @private The list of \"pro-tips\" that are defined in the template. Only one pro-tip will be rendered depending on proTipIdx */\n  @ViewChildren('proTip', { read: TemplateRef })\n  proTips!: QueryList<TemplateRef<any>>\n\n  /** @private The index of the pro-tip that is currently rendered. */\n  proTipIdx = 0;\n\n  /** @private The last time the connections were loaded */\n  lastReload: Date = new Date();\n\n  /** @private Used to refresh the \"Last reload xxx ago\" message */\n  private lastReloadTickerForceUpdate$ = new Subject<void>();\n  lastReloadTicker = merge(\n    interval(2000), \n    this.lastReloadTickerForceUpdate$.pipe(takeUntilDestroyed(this.destroyRef))\n  )\n    .pipe(\n      takeUntilDestroyed(this.destroyRef),\n      map(() => Math.floor((new Date()).getTime() - this.lastReload.getTime()) / 1000),\n      share()\n    )\n\n\n  /** Auto-reload: The list of all intervals */\n  readonly reloadIntervals = Object.keys(reloadIntervalValues);\n  /** Auto-reload: The name of the currently selected auto-reload interval */\n  autoReloadIntervalName: string = ''; \n  /** Auto-reload: The timestamp of auto-reload being enabled */\n  autoReloadEnabledTimestamp: Date | null = null;\n  /** Auto-reload: Enable/disable auto-reload and set the interval */\n  onAutoRefreshChange(intervalName: string) {\n    const delaySec = reloadIntervalValues[intervalName] || 0;\n    if (delaySec <= 0) {      \n      this.autoReloadIntervalName = '';     \n      return;\n    }\n    this.autoReloadEnabledTimestamp = new Date();\n    this.autoReloadIntervalName = intervalName;\n  }\n  /** Auto-reload: An observable that emits the remaining seconds until the next reload, and triggers reloads*/\n  autoReloadInterval$ = interval(900) // use less than 1 second to prevent skipping a second\n    .pipe(\n      startWith(0), // Emit immediately when subscribed\n      takeUntilDestroyed(this.destroyRef),\n      filter(() => !!this.autoReloadIntervalName), // Only emit when auto-reload is enabled\n      map(() => {\n        if (this.loading) return 0;\n\n        if (this.dateFilter?.length >= 2 && this.dateFilter[1] && this.dateFilter[1].getTime() <= this.lastReload.getTime()) {\n          // Skip reload when dateFilter[1] (end date) <= lastReload (no new results expected)\n          return 0;\n        }\n\n        const intervalSeconds = reloadIntervalValues[this.autoReloadIntervalName] || 0;\n        if (intervalSeconds <= 0) return 0;\n      \n        const startTime = (this.autoReloadEnabledTimestamp && this.autoReloadEnabledTimestamp > this.lastReload) ? this.autoReloadEnabledTimestamp : this.lastReload;\n        const elapsedSeconds = Math.floor((new Date().getTime() - startTime.getTime()) / 1000);\n        const remainingSeconds = intervalSeconds - elapsedSeconds;\n\n        if (remainingSeconds <= 0) {\n          this.performSearch(); // Trigger reload when time is up\n          return 0;\n        }\n        return remainingSeconds;\n      }),\n      share()\n    );\n\n  // whether or not the history database should be queried as well.\n  get useHistory() {\n    return this.dateFilter?.length;\n  }\n\n  private get databases(): Database[] {\n    if (!this.useHistory) {\n      return [Database.Live];\n    }\n\n    return [Database.Live, Database.History];\n  }\n\n  // whether or not the current use has the history feature available.\n  canUseHistory$ = inject(SPNService).profile$\n    .pipe(\n      map(profile => {\n        if (!profile) {\n          return false;\n        }\n\n        return profile.current_plan?.feature_ids?.includes(FeatureID.History) || false;\n      })\n    );\n\n  featureBw$ = inject(SPNService).profile$\n    .pipe(\n      map(profile => {\n        if (!profile) {\n          return false;\n        }\n\n        return profile.current_plan?.feature_ids?.includes(FeatureID.Bandwidth) || false;\n      })\n    );\n\n  trackPageItem: TrackByFunction<LocalQueryResult> = (_, r) => {\n    if (this.groupByKeys?.length) {\n      return this.groupByKeys.map(key => r[key]).join('-')\n    }\n    return r.id!\n  }\n\n  trackConnection: TrackByFunction<NetqueryConnection> = (_, c) => c.id\n\n  constructor(\n    private netquery: Netquery,\n    private helper: NetqueryHelper,\n    private expertise: ExpertiseService,\n    private cdr: ChangeDetectorRef,\n    private actionIndicator: ActionIndicatorService,\n    private route: ActivatedRoute,\n    public router: Router,\n  ) { }\n\n  @Input()\n  set filters(v: any | keyof this['models'] | (keyof this['models'])[]) {\n    v = coerceArray(v);\n    objKeys(this.models).forEach(key => {\n      // ignore any models that are marked as being shown in the combined-menu.\n      if (this.models[key]?.visible !== 'combinedMenu') {\n        this.models[key]!.visible = false;\n      }\n    })\n\n    v.forEach((val: any) => {\n      if (typeof val !== 'string') {\n        throw new Error(\"invalid value for @Input() filters\")\n      }\n\n      if (!this.isValidFilter(val)) {\n        throw new Error('invalid filter key ' + val)\n      }\n\n      this.models[val]!.visible = true;\n    })\n  }\n\n  /**\n   * mergeFilter input can be used to apply an additional filter condition that cannot be modified by\n   * the user (like forcing a \"profile\" filter for the App View)\n   */\n  @Input()\n  mergeFilter: Condition | null = null;\n\n  /** The filter preset that will be used if no filter is configured otherwise */\n  @Input()\n  filterPreset: string | null = null;\n\n  @Output()\n  filterChange: EventEmitter<string> = new EventEmitter();\n\n  /** @private Holds the value displayed in the tag-bar */\n  tagbarValues: SfngTagbarValue[] = [];\n\n  private updateDateRangeState() {\n    const values = [\n      this.models.from.searchValues[0],\n      this.models.to.searchValues[0],\n    ]\n\n    let fromValueTs = Date.parse(values[0])\n    let toValueTs = Date.parse(values[1])\n\n    // if we failed to parse the date from a string, the user might\n    // just entered the timestamp in seconds\n    if (isNaN(fromValueTs)) {\n      fromValueTs = Number(values[0]) * 1000\n    }\n    if (isNaN(toValueTs)) {\n      toValueTs = Number(values[1]) * 1000\n    }\n\n    const fromValid = !isNaN(fromValueTs)\n    const toValid = !isNaN(toValueTs)\n\n\n    let fromValue = new Date(fromValueTs)\n    let toValue = new Date(toValueTs);\n\n    if (fromValid && toValid && fromValue.getTime() === toValue.getTime()) {\n      fromValue = new Date(fromValue.getFullYear(), fromValue.getMonth(), fromValue.getDate(), 0, 0, 0)\n      toValue = new Date(toValue.getFullYear(), toValue.getMonth(), toValue.getDate() + 1, 0, 0, -1)\n    }\n\n    this.dateFilter = [];\n\n    if (fromValid) {\n      this.dateFilter.push(fromValue)\n      this.models.from.searchValues = [\n        formatDate(fromValue, 'medium', this.localeId)\n      ]\n    }\n\n    if (toValid) {\n      if (!fromValid) {\n        this.dateFilter.push(new Date(2000, 0, 1))\n      }\n\n      this.dateFilter.push(toValue)\n      this.models.to.searchValues = [\n        formatDate(toValue, 'medium', this.localeId)\n      ]\n    }\n\n    this.cdr.markForCheck();\n  }\n\n  private getDateRangeCondition(): Condition | null {\n    this.updateDateRangeState()\n\n    if (!this.dateFilter.length) {\n      return null\n    }\n\n    const cond: GreaterOrEqual & Partial<LessOrEqual> = {\n      $ge: Math.floor(this.dateFilter[0].getTime() / 1000),\n    }\n\n    if (this.dateFilter.length >= 2) {\n      cond['$le'] = Math.floor(this.dateFilter[1].getTime() / 1000)\n    }\n\n    return {\n      started: cond\n    }\n  }\n\n  models: { [key: string]: Model<any> } = initializeModels({\n    domain: {\n      visible: true,\n    },\n    as_owner: {\n      visible: true,\n    },\n    country: {\n      visible: true,\n    },\n    profile: {\n      visible: true\n    },\n    allowed: {\n      visible: true,\n    },\n    path: {},\n    internal: {},\n    type: {},\n    encrypted: {},\n    scope: {\n      visible: 'combinedMenu',\n      menuTitle: 'Network Scope',\n      suggestions: objKeys(IPScopeNames)\n        .sort()\n        .filter(key => key !== IPScope.Undefined)\n        .map(scope => {\n          return {\n            Name: IPScopeNames[scope],\n            Value: scope,\n            count: 0,\n            Description: ''\n          }\n        })\n    },\n    verdict: {},\n    started: {},\n    ended: {},\n    profile_revision: {},\n    remote_ip: {},\n    remote_port: {},\n    local_ip: {},\n    local_port: {},\n    ip_protocol: {},\n    direction: {\n      visible: 'combinedMenu',\n      menuTitle: 'Direction',\n      suggestions: [\n        {\n          Name: 'Inbound',\n          Value: 'inbound',\n          Description: '',\n          count: 0,\n        },\n        {\n          Name: 'Outbound',\n          Value: 'outbound',\n          Description: '',\n          count: 0,\n        }\n      ]\n    },\n    exit_node: {},\n    asn: {},\n    active: {\n      visible: 'combinedMenu',\n      menuTitle: 'Active',\n      suggestions: booleanSuggestionValues(),\n    },\n    tunneled: {\n      visible: 'combinedMenu',\n      menuTitle: 'SPN',\n      suggestions: booleanSuggestionValues(),\n      tipupKey: 'spn'\n    },\n    from: {\n      virtual: true\n    },\n    to: {\n      virtual: true,\n    },\n  })\n\n  /** Translations for the connection field names */\n  keyTranslation = connectionFieldTranslation;\n\n  /** A list of keys for group-by */\n  groupByKeys: string[] = [];\n\n  /** A list of keys for sorting */\n  orderByKeys: string[] = [];\n\n  ngOnInit(): void {\n    // Prepare the datasource that is used to initialize the DynamicItemPaginator.\n    // It basically has a \"view\" function that executes the current page query\n    // but with page-number and page-size applied.\n    // This is used by the paginator to support lazy-loading the different\n    // result pages.\n    const dataSource: Datasource<LocalQueryResult> = {\n      view: (page: number, pageSize: number) => {\n        const query = this.getQuery();\n        query.page = page - 1; // UI starts at page 1 while the backend is 0-based\n        query.pageSize = pageSize;\n\n        return this.netquery.query(query, 'netquery-viewer')\n          .pipe(\n            this.helper.attachProfile(),\n            this.helper.attachPins(),\n            map(results => {\n              return (results || []).map(r => {\n                const grpFilter: Condition = {\n                  ...query.query,\n                };\n                this.groupByKeys.forEach(key => {\n                  grpFilter[key] = r[key];\n                })\n\n                let page = {\n                  ...r,\n                  _chart: !!this.groupByKeys.length ? this.getGroupChart(grpFilter) : null,\n                  _group: !!this.groupByKeys.length ? this.lazyLoadGroup(grpFilter) : null,\n                }\n\n                return page;\n              });\n            })\n          );\n      }\n    }\n\n    // create a new paginator that will use the datasource from above.\n    this.paginator = new DynamicItemsPaginator(dataSource)\n\n    // subscribe to the search observable that emits a value each time we want to perform\n    // a new query.\n    // The actual searching is debounced by second so we don't flood the Portmaster service\n    // with queries while the user is still configuring their filters.\n    this.search$\n      .pipe(        \n        this.adaptiveDebounce(1000, () => this.lastReload.getTime()),\n        switchMap(() => {\n          this.loading = true;\n          this.connectionChartData = [];\n          this.bwChartData = [];\n\n          this.cdr.detectChanges();\n\n          const query = this.getQuery();\n\n          // we only load the overall connection chart, the total connection count for the filter result\n          // as well the the total connection count without any filters here. The actual results are\n          // loaded by the DynamicItemsPaginator using the \"view\" function defined above.\n          return forkJoin({\n            query: of(query),\n            response: this.netquery.batch({\n              totalCount: {\n                ...query,\n                select: { $count: { field: '*', as: 'totalCount' } },\n              },\n\n              totalConnCount: {\n                ...query,\n                select: {\n                  $count: { field: '*', as: 'totalConnCount' }\n                },\n              }\n            })\n              .pipe(\n                map(response => {\n                  // the the correct resulsts here which depend on whether or not\n                  // we're applying a group by.\n                  let totalCount = 0;\n                  if (response?.totalCount) {\n                    if (this.groupByKeys.length === 0 ) {\n                      totalCount = response.totalCount[0].totalCount;\n                    } else {\n                      totalCount = response.totalCount.length;\n                    }\n                  }\n\n                  return {\n                    totalCount,\n                    totalConnCount: response?.totalConnCount || [],\n                  }\n                })\n              ),\n          })\n        }),\n      )\n      .subscribe(result => {\n        this.paginator.pageLoading$\n          .pipe(\n            skip(1),\n            takeUntil(this.search$), // skip loading the chart if the user trigger a subsequent search\n            filter(loading => !loading),\n            take(1),\n            switchMap(() => forkJoin({\n              connectionChart: this.netquery.activeConnectionChart(result.query.query!)\n                .pipe(\n                  catchError(err => {\n                    this.actionIndicator.error(\n                      'Internal Error',\n                      'Failed to load chart: ' + this.actionIndicator.getErrorMessgae(err)\n                    );\n\n                    return of([] as ChartResult[]);\n                  }),\n                ),\n              bwChart: this.netquery.bandwidthChart(result.query.query!, [], 60)\n            })),\n          )\n          .subscribe(chart => {\n            this.connectionChartData = chart.connectionChart;\n            this.bwChartData = chart.bwChart;\n\n            this.cdr.markForCheck();\n          })\n\n        // reset the paginator with the new total result count and\n        // open the first page.\n        this.paginator.reset(result.response.totalCount);\n        this.totalConnCount = result.response?.totalConnCount[0]?.totalConnCount || 0;\n        this.totalResultCount = result.response.totalCount;\n\n        // update the current URL to include the new search\n        // query and make sure we skip the parameter-update emitted by\n        // router.\n        if (!this.skipUrlUpdate) {\n          this.skipNextRouteUpdate = true;\n\n          const queryText = this.getQueryString();\n\n          this.filterChange.next(queryText);\n\n          // note that since we only update the query parameters and stay on\n          // the current route this component will not get re-created but will\n          // rather receive an update on the queryParamMap (see below).\n          this.router.navigate([], {\n            relativeTo: this.route,\n            queryParams: {\n              ...this.route.snapshot.queryParams,\n              q: queryText,\n            },\n          })\n        }\n        this.skipUrlUpdate = false;\n\n        this.lastReload = new Date();\n        this.lastReloadTickerForceUpdate$.next();\n        this.loading = false;\n        this.cdr.markForCheck();\n      })\n\n    // subscribe to router updates so we apply the filter that is part of\n    // the current query parameter \"q\".\n    // We might ignore updates here depending on the value of \"skipNextRouterUpdate\".\n    // This is required as we keep the route parameters in sync with the current filter.\n    this.route.queryParamMap\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(params => {\n        if (this.skipNextRouteUpdate) {\n          this.skipNextRouteUpdate = false;\n          return;\n        }\n\n        const query = params.get(\"q\")\n\n        if (query !== null) {\n          objKeys(this.models).forEach(key => {\n            this.models[key]!.searchValues = [];\n          })\n\n          const result = Parser.parse(query!)\n\n          this.onFieldsParsed({\n            ...result.conditions,\n            groupBy: result.groupBy,\n            orderBy: result.orderBy,\n          });\n          this.textSearch = result.textQuery;\n        }\n\n        this.skipUrlUpdate = true;\n        this.performSearch();\n      })\n\n    // we might get new search values from our helper service\n    // in case the user \"SHIFT-Clicks\" a SfngAddToFilter directive.\n    this.helper.onFieldsAdded()\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(fields => this.onFieldsParsed(fields))\n\n    // updateTagBar$ always emits a value when we need to update the current tag-bar values.\n    // This must always be done if the current search filter has been modified in either of\n    // the supported ways.\n    this.updateTagBar$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        switchMap(() => {\n          const obs: Observable<{ [key: string]: (PossilbeValue & QueryResult)[] }>[] = [];\n\n          // for the tag bar we try to show some pretty names for values that are meant to be\n          // internal (like the number-constants for the verdicts or using the profile name instead\n          // of the profile ID). Since we might need to load data from the Portmaster for this (like\n          // for profile names) we construct a list of observables using helper.encodeToPossibleValues\n          // and use the result for the tagbar.\n          Object.keys(this.models)\n            .sort() // make sure we always output values in a constant order\n            .forEach(modelKey => {\n              const values = this.models[modelKey]!.searchValues;\n\n              if (values.length > 0) {\n                obs.push(\n                  of(values.map(val => ({\n                    [modelKey]: val,\n                  })))\n                    .pipe(\n                      this.helper.encodeToPossibleValues(modelKey),\n                      map(result => ({\n                        [modelKey]: result,\n                      }))\n                    )\n                )\n              }\n            })\n\n          if (obs.length === 0) {\n            return of([]);\n          }\n\n          return combineLatest(obs);\n        })\n      )\n      .subscribe(tagBarValues => {\n        this.tagbarValues = [];\n\n        // reset the \"selected\" field of each model that is shown in the \"combinedMenu\".\n        // we'll set the correct ones as \"selected\" again in the next step.\n        objKeys(this.models).forEach(key => {\n          if (this.models[key]?.visible === 'combinedMenu') {\n            this.models[key]?.suggestions.forEach(val => val.selected = false);\n          }\n        })\n\n        // finally construct a new list of tag-bar values and update the \"selected\" field of\n        // suggested-values for the \"combinedMenu\" items based on the actual search values.\n        tagBarValues.forEach(obj => {\n          objKeys(obj).forEach(key => {\n            if (obj[key].length > 0) {\n              this.tagbarValues.push({\n                key: key as string,\n                values: obj[key],\n              })\n\n              // update the `selected` field of suggested-values for each model that is displayed in the combined-menu\n              const modelsKey = key as keyof NetqueryConnection;\n              if (this.models[modelsKey]?.visible === 'combinedMenu')\n                this.models[modelsKey]?.suggestions.forEach(suggestedValue => {\n                  suggestedValue.selected = obj[key].some(val => val.Value === suggestedValue.Value);\n                })\n            }\n          })\n        })\n\n        this.cdr.markForCheck();\n      })\n\n    // handle any filter preset\n    //\n    if (!!this.filterPreset) {\n      try {\n        const result = Parser.parse(this.filterPreset);\n        this.onFieldsParsed({\n          ...result.conditions,\n          groupBy: result.groupBy,\n          orderBy: result.orderBy,\n        });\n      } catch (err) {\n        // only log the error in dev mode as this is most likely\n        // just bad user input\n        if (isDevMode()) {\n          console.error(err);\n        }\n      }\n    }\n  }\n\n  ngAfterViewInit(): void {\n    // once we are initialized decide which pro-tip we want to show this time...\n    this.proTipIdx = Math.floor(Math.random() * this.proTips.length);\n  }\n\n  ngOnDestroy() {\n    this.paginator.clear();\n    this.search$.complete();\n    this.helper.dispose();\n  }\n\n/**\n * Delays emissions only when last operation was recent.\n * \n * @param minDelayMs - Minimum milliseconds between operations\n * @param getLastOperationTime - Function returning last operation timestamp\n * \n * @example\n * // Delay search only if last search was < 1 second ago\n * this.search$.pipe(adaptiveDebounce(1000, () => this.lastReload.getTime()))\n */\n adaptiveDebounce<T>(  minDelayMs: number,   getLastOperationTime: () => number) {\n  return (source: Observable<T>) => source.pipe(\n    switchMap((value) => {\n      const timeSinceLastOperation = Date.now() - getLastOperationTime();\n      if (timeSinceLastOperation >= minDelayMs) {\n        return of(value); // Execute immediately\n      } else {\n        const remainingDelay = minDelayMs - timeSinceLastOperation;\n        return timer(remainingDelay).pipe(map(() => value));\n      }\n    })\n  );\n}\n\n  // lazyLoadGroup returns an observable that will emit a DynamicItemsPaginator once subscribed.\n  // This is used in \"group-by\" views to lazy-load the content of the group once the user\n  // expands it.\n  lazyLoadGroup(groupFilter: Condition): Observable<DynamicItemsPaginator<NetqueryConnection>> {\n    return new Observable(observer => {\n      this.netquery.query({\n        query: groupFilter,\n        select: [\n          { $count: { field: \"*\", as: \"totalCount\" } }\n        ],\n        orderBy: [\n          { field: 'started', desc: true },\n          { field: 'ended', desc: true }\n        ],\n        databases: this.databases,\n      }, 'netquery-viewer-load-group')\n        .subscribe(result => {\n          const paginator = new DynamicItemsPaginator<NetqueryConnection>({\n            view: (pageNumber: number, pageSize: number) => {\n              return this.netquery.query({\n                query: groupFilter,\n                orderBy: [\n                  { field: 'started', desc: true },\n                  { field: 'ended', desc: true }\n                ],\n                page: pageNumber - 1,\n                pageSize: pageSize,\n                databases: this.databases,\n              }, 'netquery-viewer-group-paginator') as Observable<NetqueryConnection[]>;\n            }\n          }, 25)\n\n          paginator.reset(result[0]?.totalCount || 0)\n\n          observer.next(paginator)\n        })\n    })\n  }\n\n  // Returns an observable that loads the current active connection chart using the\n  // current page query but only for the condition of the displayed group.\n  getGroupChart(groupFilter: Condition): Observable<ChartResult[]> {\n    return this.netquery.activeConnectionChart(groupFilter)\n  }\n\n  // loadSuggestion loads possible values for a given connection field\n  // and updates the \"suggestions\" field of the correct models entry.\n  // It also uses helper.encodeToPossibleValues to make sure we show\n  // pretty names for otherwise \"internal\" values like verdict constants\n  // or profile IDs.\n  loadSuggestion(field: string): void;\n  loadSuggestion<T extends keyof NetqueryConnection>(field: T) {\n    const search = this.getQuery([field]);\n\n    this.models[field]!.loading = !this.models[field]!.suggestions?.length;\n\n    this.netquery.query({\n      select: [\n        field,\n        {\n          $count: {\n            field: \"*\",\n            as: \"count\"\n          },\n        }\n      ],\n      query: search.query,\n      groupBy: [\n        field,\n      ],\n      orderBy: [{ field: \"count\", desc: true }, { field, desc: true }],\n      databases: this.databases,\n    }, 'netquery-viewer-load-suggestions')\n      .pipe(this.helper.encodeToPossibleValues(field))\n      .subscribe(result => {\n        this.models[field]!.loading = false;\n\n        // create a set that we can use to lookup if a value\n        // is currently selected.\n        // This is needed to ensure selected values are sorted to the top.\n        let currentlySelected = new Set<any>();\n        this.models[field]!.searchValues.forEach(\n          val => currentlySelected.add(val)\n        );\n\n        this.models[field]!.suggestions =\n          result\n            .sort((a, b) => {\n              const hasA = currentlySelected.has(a.Value);\n              const hasB = currentlySelected.has(b.Value);\n\n              if (hasA && !hasB) {\n                return -1;\n              }\n              if (hasB && !hasA) {\n                return 1;\n              }\n\n              return b.count - a.count;\n            }) as any;\n\n        this.cdr.markForCheck();\n      })\n  }\n\n  sortByCount(a: SelectOption, b: SelectOption) {\n    return b.data - a.data\n  }\n\n  /** @private Callback for keyboard events on the search-input */\n  onFieldsParsed(fields: SfngSearchbarFields, replace = false) {\n    const allowedKeys = new Set<string>(Object.keys(this.models))\n\n    objKeys(fields).forEach(key => {\n      if (key === 'groupBy') {\n        this.groupByKeys = (fields.groupBy || this.groupByKeys)\n          .filter(val => {\n            // an empty value is just filtered out without an error as this is the only\n            // way to specify \"I don't want grouping\" via the filter\n            if (val === '') {\n              return false;\n            }\n\n            if (!allowedKeys.has(val as any)) {\n              this.actionIndicator.error(\"Invalid search query\", \"Column \" + val + \" is not allowed for groupby\")\n              return false;\n            }\n            return true;\n          })\n\n        return;\n      }\n\n      if (key === 'orderBy') {\n        this.orderByKeys = (fields.orderBy || this.orderByKeys)\n          .filter(val => {\n            if (!allowedKeys.has(val as any)) {\n              this.actionIndicator.error(\"Invalid search query\", \"Column \" + val + \" is not allowed for orderby\")\n              return false;\n            }\n            return true;\n          })\n\n        return;\n      }\n\n      if (!allowedKeys.has(key)) {\n        this.actionIndicator.error(\"Invalid search query\", \"Column \" + key + \" is not allowed for filtering\");\n        return;\n      }\n\n      if (fields[key]?.length === 0 && replace) {\n        this.models[key].searchValues = [];\n      } else {\n        fields[key]!.forEach(val => {\n          // quick fix to make sure domains always end in a period.\n          if (key === 'domain' && typeof val === 'string' && val.length > 0 && !val.endsWith('.')) {\n            val = `${val}.`\n          }\n\n          if (typeof val === 'object' && '$ne' in val) {\n            this.actionIndicator.error(\"NOT conditions are not yet supported\")\n            return;\n          }\n\n          // avoid duplicates\n          if (this.models[key]!.searchValues.includes(val)) {\n            return;\n          }\n\n          if (!replace) {\n            this.models[key]!.searchValues = [\n              ...this.models[key]!.searchValues,\n              val,\n            ]\n          } else {\n            this.models[key]!.searchValues = [val]\n          }\n        })\n      }\n\n      this.updateDateRangeState()\n    })\n\n    this.cdr.markForCheck();\n\n    this.performSearch();\n  }\n\n  /** @private Query the portmaster service for connections matching the current settings */\n  performSearch() {\n    this.loading = true;    \n    this.paginator.clear()\n    this.search$.next();\n    this.updateTagbarValues();\n  }\n\n  /** @private Returns the current query in it's string representation */\n  getQueryString(): string {\n    let result = '';\n\n    objKeys(this.models).forEach(key => {\n      this.models[key]?.searchValues.forEach(val => {\n        // we use JSON.stringify here to make sure the value is\n        // correclty quoted.\n        result += `${key}:${JSON.stringify(val)} `;\n      })\n    })\n\n    if (result.length > 0 && this.textSearch.length > 0) {\n      result += ' '\n    }\n\n    this.groupByKeys.forEach(key => {\n      result += `groupby:\"${key}\" `\n    })\n    this.orderByKeys.forEach(key => {\n      result += `orderby:\"${key}\" `\n    })\n\n    if (result.length > 0 && this.textSearch.length > 0) {\n      result += ' '\n    }\n\n    result += `${this.textSearch}`\n\n    return result;\n  }\n\n  /** @private Copies the current query into the user clipboard */\n  copyQuery() {\n    this.integration.writeToClipboard(this.getQueryString())\n      .then(() => {\n        this.actionIndicator.success(\"Query copied to clipboard\", 'Go ahead and share your query!')\n      })\n      .catch((err) => {\n        this.actionIndicator.error('Failed to copy to clipboard', this.actionIndicator.getErrorMessgae(err))\n      })\n  }\n\n  /** @private Clears the current query */\n  clearQuery() {\n    objKeys(this.models).forEach(key => {\n      this.models[key]!.searchValues = [];\n    })\n    this.textSearch = '';\n\n    this.updateTagbarValues();\n    this.performSearch();\n  }\n\n  /** @private Constructs a query from the current page settings. Supports excluding certain fields from the query. */\n  getQuery(excludeFields: string[] = []): Query {\n    let query: Condition = {}\n    let textSearch: Query['textSearch'];\n\n    const dateQuery = this.getDateRangeCondition()\n    if (dateQuery !== null) {\n      query = mergeConditions(query, dateQuery)\n    }\n\n    // create the query conditions for all keys on this.models\n    Object.keys(this.models).forEach((key: string) => {\n      if (excludeFields.includes(key)) {\n        return;\n      }\n\n      if (this.models[key]!.searchValues.length > 0) {\n        // check if model is virtual, and if, skip adding it to the query\n        if (this.models[key].virtual) {\n          return\n        }\n\n        query[key] = {\n          $in: this.models[key]!.searchValues,\n        }\n      }\n    })\n\n    if (this.expertise.currentLevel !== 'developer') {\n      query[\"internal\"] = {\n        $eq: false,\n      }\n    }\n\n    if (this.textSearch !== '') {\n      textSearch = {\n        fields: freeTextSearchFields,\n        value: this.textSearch\n      }\n    }\n\n    let select: Query['select'] | undefined = undefined;\n    if (!!this.groupByKeys.length) {\n      // we always want to show the total and the number of allowed connections\n      // per group so we need to add those to the select part of the query\n      select = [\n        {\n          $count: {\n            field: \"*\",\n            as: \"totalCount\",\n          },\n        },\n        {\n          $sum: {\n            condition: {\n              verdict: {\n                $in: [\n                  Verdict.Accept,\n                  Verdict.RerouteToNs,\n                  Verdict.RerouteToTunnel\n                ],\n              }\n            },\n            as: \"countAllowed\"\n          }\n        },\n        ...this.groupByKeys,\n      ]\n    }\n\n    let normalizedQuery = mergeConditions(query, this.mergeFilter || {})\n\n    let orderBy: string[] | OrderBy[] = this.orderByKeys;\n    if (!orderBy || orderBy.length === 0) {\n      orderBy = [\n        {\n          field: 'started',\n          desc: true,\n        },\n        {\n          field: 'ended',\n          desc: true,\n        }\n      ]\n    }\n\n    return {\n      select: select,\n      query: normalizedQuery,\n      groupBy: this.groupByKeys,\n      orderBy: orderBy,\n      textSearch,\n      databases: this.databases,\n    }\n  }\n\n  /** @private Updates the current model form all values emited by the tag-bar. */\n  onTagbarChange(tagKinds: SfngTagbarValue[]) {\n    objKeys(this.models).forEach(key => {\n      this.models[key]!.searchValues = [];\n    });\n\n    tagKinds.forEach(kind => {\n      const key = kind.key as keyof NetqueryConnection;\n      this.models[key]!.searchValues = kind.values.map(possibleValue => possibleValue.Value);\n\n      if (this.models[key]?.visible === 'combinedMenu')\n        this.models[key]?.suggestions.forEach(val => {\n          val.selected = this.models[key]!.searchValues.find(searchValue => searchValue === val.Value)\n        })\n    })\n\n    this.updateDateRangeState();\n\n    this.performSearch();\n  }\n\n  onDateRangeChange(event: Date[]) {\n    if (event.length >= 1) {\n      event[0] = new Date(event[0].getFullYear(), event[0].getMonth(), event[0].getDate(), 0, 0, 0)\n      this.onFieldsParsed({ from: [formatDate(event[0], 'medium', this.localeId)] }, true)\n    } else {\n      this.onFieldsParsed({ from: [] }, true)\n    }\n\n    if (event.length >= 2) {\n      event[1] = new Date(event[1].getFullYear(), event[1].getMonth(), event[1].getDate() + 1, 0, 0, -1)\n      this.onFieldsParsed({ to: [formatDate(event[1], 'medium', this.localeId)] }, true)\n    } else {\n      this.onFieldsParsed({ to: [] }, true)\n    }\n  }\n\n  /** Updates the {@link tagbarValues} from {@link models}*/\n  private updateTagbarValues() {\n    this.updateTagBar$.next();\n  }\n\n  private isValidFilter(key: string): key is keyof NetqueryConnection {\n    return Object.keys(this.models).includes(key);\n  }\n\n  useAsFilter(rec: QueryResult) {\n    const keys = new Set(objKeys(this.models))\n\n    // reset the search values\n    keys.forEach(key => {\n      this.models[key]!.searchValues = [];\n    })\n\n    objKeys(rec).forEach(key => {\n      if (keys.has(key as keyof NetqueryConnection)) {\n        this.models[key as keyof NetqueryConnection]!.searchValues = [rec[key]];\n      }\n    })\n\n    // reset the group-by-keys since they don't make any sense anymore.\n    this.groupByKeys = [];\n    this.performSearch();\n  }\n\n  /** @private - used by the combined filter menu */\n  toggleCombinedMenuFilter(key: string, value: Suggestion) {\n    const k = key as keyof NetqueryConnection;\n    if (value.selected) {\n      this.models[k]!.searchValues = this.models[k]?.searchValues.filter(val => val !== value.Value) || [];\n    } else {\n      this.models[k]!.searchValues.push(value.Value)\n    }\n\n    this.updateTagbarValues();\n    this.performSearch();\n  }\n\n  trackSuggestion: TrackByFunction<Suggestion> = (_: number, s: Suggestion) => s.Name + '::' + s.Value;\n}\n\nfunction initializeModels(models: { [key: string]: Partial<Model<any>> }): { [key: string]: Model<any> } {\n  objKeys(models).forEach(key => {\n    models[key] = {\n      suggestions: [],\n      searchValues: [],\n      visible: false,\n      loading: false,\n      ...models[key],\n    }\n  })\n\n  return models as any;\n}\n\nfunction booleanSuggestionValues(): Suggestion<any>[] {\n  return [\n    {\n      Name: 'Yes',\n      Value: true,\n      Description: '',\n      count: 0,\n    },\n    {\n      Name: 'No',\n      Value: false,\n      Description: '',\n      count: 0,\n    },\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/netquery.module.ts",
    "content": "import { A11yModule } from \"@angular/cdk/a11y\";\nimport { OverlayModule } from \"@angular/cdk/overlay\";\nimport { CommonModule } from \"@angular/common\";\nimport { inject, NgModule } from \"@angular/core\";\nimport { FormsModule } from \"@angular/forms\";\nimport { FontAwesomeModule } from \"@fortawesome/angular-fontawesome\";\nimport { SfngAccordionModule, SfngDropDownModule, SfngPaginationModule, SfngSelectModule, SfngTipUpModule, SfngToggleSwitchModule, SfngTooltipModule } from \"@safing/ui\";\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { SfngAppIconModule } from \"../app-icon\";\nimport { CountIndicatorModule } from \"../count-indicator\";\nimport { CountryFlagModule } from \"../country-flag\";\nimport { ExpertiseModule } from \"../expertise/expertise.module\";\nimport { SfngFocusModule } from \"../focus\";\nimport { SfngMenuModule } from \"../menu\";\nimport { CommonPipesModule } from \"../pipes\";\nimport { SPNModule } from './../../pages/spn/spn.module';\nimport { SfngNetqueryAddToFilterDirective } from \"./add-to-filter\";\nimport { CombinedMenuPipe } from \"./combined-menu.pipe\";\nimport { SfngNetqueryConnectionDetailsComponent } from \"./connection-details\";\nimport { SfngNetqueryConnectionRowComponent } from \"./connection-row\";\nimport { SfngNetqueryLineChartComponent } from \"./line-chart/line-chart\";\nimport { SfngNetqueryViewer } from \"./netquery.component\";\nimport { CanShowConnection, CanUseRulesPipe, ConnectionLocationPipe, CountryNamePipe, CountryNameService, IsBlockedConnectionPipe } from \"./pipes\";\nimport { SfngNetqueryScopeLabelComponent } from \"./scope-label\";\nimport { SfngNetquerySearchOverlayComponent } from \"./search-overlay\";\nimport { SfngNetquerySearchbarComponent, SfngNetquerySuggestionDirective } from \"./searchbar\";\nimport { SfngNetqueryTagbarComponent } from \"./tag-bar\";\nimport { CircularBarChartComponent } from './circular-bar-chart/circular-bar-chart.component';\n\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    CountryFlagModule,\n    SfngDropDownModule,\n    SfngSelectModule,\n    SfngTooltipModule,\n    SfngAccordionModule,\n    SfngMenuModule,\n    SfngPaginationModule,\n    SfngFocusModule,\n    SfngAppIconModule,\n    SfngTipUpModule,\n    SfngToggleSwitchModule,\n    A11yModule,\n    ExpertiseModule,\n    OverlayModule,\n    CountIndicatorModule,\n    FontAwesomeModule,\n    CommonPipesModule,\n    SPNModule,\n    NzDatePickerModule,\n  ],\n  exports: [\n    SfngNetqueryViewer,\n    SfngNetqueryLineChartComponent,\n    SfngNetquerySearchOverlayComponent,\n    SfngNetqueryScopeLabelComponent,\n    CircularBarChartComponent,\n  ],\n  declarations: [\n    SfngNetqueryViewer,\n    SfngNetqueryConnectionRowComponent,\n    SfngNetqueryLineChartComponent,\n    SfngNetqueryTagbarComponent,\n    SfngNetquerySearchbarComponent,\n    SfngNetquerySearchOverlayComponent,\n    SfngNetquerySuggestionDirective,\n    SfngNetqueryScopeLabelComponent,\n    SfngNetqueryConnectionDetailsComponent,\n    SfngNetqueryAddToFilterDirective,\n    ConnectionLocationPipe,\n    IsBlockedConnectionPipe,\n    CanUseRulesPipe,\n    CanShowConnection,\n    CombinedMenuPipe,\n    CircularBarChartComponent,\n    CountryNamePipe,\n  ],\n  providers: [\n    CountryNameService\n  ]\n})\nexport class NetqueryModule {\n  private _unusedBootstrap = [\n    inject(CountryNameService), // make sure country names are loaded on bootstrap\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/pipes/can-show.pipe.ts",
    "content": "import { Pipe, PipeTransform } from \"@angular/core\";\nimport { ExpertiseLevel, NetqueryConnection } from \"@safing/portmaster-api\";\n\n\n@Pipe({\n  name: \"canShowConnection\",\n  pure: true,\n})\nexport class CanShowConnection implements PipeTransform {\n  transform(conn: NetqueryConnection, level: ExpertiseLevel) {\n    if (!conn) {\n      return false;\n    }\n    if (level === ExpertiseLevel.Developer) {\n      // we show all connections for developers\n      return true;\n    }\n    // if we are in advanced or simple mode we should\n    // hide internal connections.\n    return !conn.internal;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/pipes/can-use-rules.pipe.ts",
    "content": "\n// the following settings are stronger than rules\n// and cannot be \"fixed\" by creating a new allow/deny\n\nimport { Pipe, PipeTransform } from \"@angular/core\";\nimport { IsDenied, NetqueryConnection } from \"@safing/portmaster-api\";\n\n// rule.\nlet optionKeys = new Set([\n  \"filter/blockInternet\",\n  \"filter/blockLAN\",\n  \"filter/blockLocal\",\n  \"filter/blockP2P\",\n  \"filter/blockInbound\"\n])\n\n@Pipe({\n  name: \"canUseRules\",\n  pure: true,\n})\nexport class CanUseRulesPipe implements PipeTransform {\n  transform(conn: NetqueryConnection): boolean {\n    if (!conn) {\n      return false;\n    }\n    if (!!conn.extra_data?.reason?.OptionKey && IsDenied(conn.verdict)) {\n      return !optionKeys.has(conn.extra_data.reason.OptionKey);\n    }\n    return true;\n  }\n}\n\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/pipes/country-name.pipe.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { Pipe, PipeTransform, Injectable, inject } from '@angular/core';\nimport { GeoCoordinates, SPNService } from '@safing/portmaster-api';\nimport { environment } from 'src/environments/environment';\nimport { ActionIndicatorService } from '../../action-indicator';\nimport { objKeys } from '../../utils';\n\nexport interface CountryListResponse {\n  [countryKey: string]: {\n    Code: string;\n    Name: string;\n    Center: GeoCoordinates;\n    Continent: {\n      Code: string;\n      Region: string;\n      Name: string;\n    }\n  }\n}\n\n@Injectable()\nexport class CountryNameService {\n  private readonly spn = inject(SPNService);\n  private readonly http = inject(HttpClient);\n  private readonly uai = inject(ActionIndicatorService);\n\n  private map: Map<string, string> = new Map();\n\n  constructor() {\n    this.http.get<CountryListResponse>(`${environment.httpAPI}/v1/intel/geoip/countries`)\n      .subscribe({\n        next: response => {\n          objKeys(response)\n            .forEach(key => {\n              this.map.set(key as string, response[key].Name);\n            });\n        },\n        error: err => {\n          this.uai.error('Failed to fetch country data', this.uai.getErrorMessage(err));\n        }\n      })\n  }\n\n  resolveName(code: string): string {\n    return this.map.get(code) || '';\n  }\n}\n\n@Pipe({\n  name: 'countryName',\n  pure: true,\n})\nexport class CountryNamePipe implements PipeTransform {\n  private countryService = inject(CountryNameService);\n\n  transform(countryCode: string) {\n    return this.countryService.resolveName(countryCode);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/pipes/index.ts",
    "content": "export * from './location.pipe';\nexport * from './can-show.pipe';\nexport * from './can-use-rules.pipe';\nexport * from './is-blocked.pipe';\nexport * from './country-name.pipe';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/pipes/is-blocked.pipe.ts",
    "content": "import { Pipe, PipeTransform } from '@angular/core';\nimport { IsDenied, NetqueryConnection } from '@safing/portmaster-api';\n\n@Pipe({\n  name: \"isBlocked\",\n  pure: true\n})\nexport class IsBlockedConnectionPipe implements PipeTransform {\n  transform(conn: NetqueryConnection): boolean {\n    return IsDenied(conn?.verdict);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/pipes/location.pipe.ts",
    "content": "import { Pipe, PipeTransform } from '@angular/core';\nimport { IsGlobalScope, IsLANScope, IsLocalhost, NetqueryConnection } from '@safing/portmaster-api';\n\n@Pipe({\n  name: 'connectionLocation',\n  pure: true,\n})\nexport class ConnectionLocationPipe implements PipeTransform {\n  transform(conn: NetqueryConnection): string {\n    if (conn.type === 'dns') {\n      return '';\n    }\n    if (!!conn.country) {\n      if (conn.country === \"__\") {\n        return \"Anycast\"\n      }\n      return conn.country;\n    }\n\n    const scope = conn.scope;\n\n    if (IsGlobalScope(scope)) {\n      return 'Internet'\n    }\n\n    if (IsLANScope(scope)) {\n      return 'LAN';\n    }\n\n    if (IsLocalhost(scope)) {\n      return 'Device'\n    }\n\n    return '';\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/scope-label/index.ts",
    "content": "export * from './scope-label';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/scope-label/scope-label.html",
    "content": "<ng-container *ngIf=\"!!domain; else: scopeTranslationTemplate\">\n  <span *ngIf=\"!!subdomain\" class=\"text-opacity-75 text-secondary\"\n    style=\"direction: ltr; unicode-bidi: bidi-override;\">{{subdomain}}.</span>\n  <span style=\"direction: ltr; unicode-bidi: bidi-override;\">{{domain}}</span>\n</ng-container>\n<ng-template #scopeTranslationTemplate>\n  {{ scopeTranslation[scope || ''] || 'N/A' }}\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/scope-label/scope-label.ts",
    "content": "import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';\nimport { ScopeTranslation } from '@safing/portmaster-api';\nimport { parseDomain } from '../../utils';\n\n@Component({\n  selector: 'sfng-netquery-scope-label',\n  templateUrl: 'scope-label.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SfngNetqueryScopeLabelComponent implements OnChanges {\n  readonly scopeTranslation = ScopeTranslation;\n\n  @Input()\n  scope?: string = ''\n\n  @Input()\n  set leftRightFix(v: any) {\n    console.warn(\"deprecated @Input usage\")\n  }\n  get leftRightFix() { return false }\n\n  domain: string = '';\n  subdomain: string = '';\n\n  ngOnChanges(change: SimpleChanges) {\n    if (!!change['scope']) {\n      //this.label = change.label.currentValue;\n      const result = parseDomain(change.scope.currentValue || '')\n\n      this.domain = result?.domain || '';\n      this.subdomain = result?.subdomain || '';\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/search-overlay/index.ts",
    "content": "export * from './search-overlay';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/search-overlay/search-overlay.html",
    "content": "<sfng-netquery-searchbar [(ngModel)]=\"textSearch\" (ngModelChange)=\"performSearch()\" class=\"block w-full\"\n  [labels]=\"keyTranslation\" (fieldsParsed)=\"onFieldsParsed($event)\" mode=\"inline\"></sfng-netquery-searchbar>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/search-overlay/search-overlay.ts",
    "content": "import { ChangeDetectionStrategy, Component, Inject } from \"@angular/core\";\nimport { Router } from \"@angular/router\";\nimport { SfngDialogRef, SFNG_DIALOG_REF } from \"@safing/ui\";\nimport { objKeys } from \"../../utils\";\nimport { NetqueryHelper } from \"../connection-helper.service\";\nimport { SfngSearchbarFields } from \"../searchbar\";\nimport { connectionFieldTranslation } from \"../utils\";\n\n@Component({\n  selector: 'sfng-netquery-search-overlay',\n  templateUrl: './search-overlay.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    NetqueryHelper,\n  ],\n  styles: [\n    `\n    :host {\n      @apply block;\n      width: 700px;\n    }\n\n    ::ng-deep sfng-netquery-search-overlay sfng-netquery-searchbar input {\n      border: 1px solid theme(\"colors.gray.200\") !important;\n    }\n    `\n  ]\n})\nexport class SfngNetquerySearchOverlayComponent {\n  keyTranslation = connectionFieldTranslation;\n\n  textSearch = '';\n\n  fields: SfngSearchbarFields = {};\n\n  constructor(\n    @Inject(SFNG_DIALOG_REF) private dialogRef: SfngDialogRef<any>,\n    private router: Router,\n  ) { }\n\n  performSearch() {\n    let query = \"\";\n    const fields = objKeys(this.fields)\n\n    // if there's only one profile key directly navigate the user to the app view\n    if (fields.length === 1 && fields[0] === 'profile' && this.fields.profile!.length === 1) {\n      let profileName: string = this.fields.profile![0] || '';\n      if (!profileName.includes(\"/\")) {\n        profileName = \"local/\" + profileName\n      }\n      this.router.navigate(['/app/' + profileName || ''])\n      this.dialogRef.close();\n      return;\n    }\n\n    fields.forEach(field => {\n      this.fields[field]?.forEach(value => {\n        query += `${field}:${JSON.stringify(value)} `\n      })\n    })\n\n    if (query !== '' && this.textSearch !== '') {\n      query += \" \"\n    }\n    query += this.textSearch;\n\n    this.router.navigate(['/monitor'], {\n      queryParams: {\n        q: query,\n      }\n    })\n\n    this.dialogRef.close();\n  }\n\n  onFieldsParsed(fields: SfngSearchbarFields) {\n    objKeys(fields).forEach(field => {\n      this.fields[field] = [...(this.fields[field] || []), ...(fields[field] || [])];\n    })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/searchbar/index.ts",
    "content": "export * from './searchbar';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/searchbar/searchbar.html",
    "content": "<div class=\"relative flex flex-row items-center bg-gray-300 rounded-sm\" cdkOverlayOrigin>\n  <div class=\"absolute top-0 -mt-0.5 left-0 flex items-center p-2\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 text-secondary\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n      <path fill-rule=\"evenodd\"\n        d=\"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z\"\n        clip-rule=\"evenodd\" />\n    </svg>\n  </div>\n  <input [cdkTrapFocus]=\"false\" [cdkTrapFocusAutoCapture]=\"true\" class=\"w-full !pl-7 rounded-tr-sm\" type=\"text\"\n    [(ngModel)]=\"textSearch\" placeholder=\"Search for connections, press ENTER to apply\"\n    (keydown)=\"onSearchKeyDown($event)\" (blur)=\"onFocusLost($event)\" (ngModelChange)=\"onSearchModelChange($event)\"\n    #searchBar>\n</div>\n\n\n<sfng-dropdown externalTrigger=\"true\" #suggestionDropdown *ngIf=\"mode === 'default'; else: suggestionTemplate\"\n  offsetY=\"0\">\n  <div class=\"bg-gray-300\">\n    <ng-container *ngTemplateOutlet=\"suggestionTemplate\"></ng-container>\n  </div>\n</sfng-dropdown>\n\n<ng-template #suggestionTemplate>\n  <ul class=\"self-stretch p-2\" *ngIf=\"!!textSearch\">\n    <li (click)=\"applySuggestion('_textsearch', null, $event)\" [sfngNetquerySuggestion]=\"textSearch\"\n      [sfngSuggestion]=\"{field: '_textsearch', values: []}\" #suggestion=\"sfngNetquerySuggestion\"\n      class=\"flex flex-row justify-between w-full gap-2 px-2 py-1 rounded-sm cursor-pointer hover:bg-gray-400\"\n      [ngClass]=\"{'bg-gray-400': suggestion.active}\">\n      <span class=\"text-secondary text-xxs\">Full-Text Search: <span\n          class=\"text-xs text-primary\">{{ textSearch }}</span></span>\n    </li>\n  </ul>\n\n  <div class=\"flex flex-col items-start justify-start w-full gap-4 p-3 px-4\" (mouseenter)=\"cancelDropdownClose()\"\n    [@fadeInList]=\"suggestions.length\" (mousemove)=\"resetKeyboardSelection()\">\n\n    <ng-container *ngFor=\"let sug of suggestions; trackBy: trackSuggestion\">\n      <div class=\"flex flex-col items-start self-stretch justify-start gap-1\">\n        <h3 class=\"flex flex-row items-center w-full gap-2 text-xxs text-tertiary\">\n          Filter by {{ labels[sug.field] || sug.field }}\n        </h3>\n        <ul class=\"self-stretch\">\n          <li *ngFor=\"let val of sug.values\" (click)=\"applySuggestion(sug.field, val.value, $event, sug.start)\"\n            [sfngNetquerySuggestion]=\"val.value\" [sfngSuggestion]=\"sug\" #suggestion=\"sfngNetquerySuggestion\"\n            class=\"flex flex-row justify-between w-full gap-2 px-2 py-1 rounded-sm cursor-pointer hover:bg-gray-400\"\n            [ngClass]=\"{'bg-gray-400': suggestion.active}\">\n            <span class=\"text-primary\">{{ val.display || (val.value === '' ? 'N/A' : val.value) }}</span>\n            <span class=\"text-secondary\">#{{ val.count }} connections</span>\n          </li>\n        </ul>\n      </div>\n    </ng-container>\n\n    <div class=\"flex flex-row items-center justify-start w-full gap-2 text-xs border-gray-400 text-primary\" [@fadeIn]\n      *ngIf=\"loading\" [ngClass]=\"{'border-t pt-2': !!suggestions.length}\">\n      <svg class=\"w-4 h-4 animate-spin text-secondary\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\"\n        viewBox=\"0 0 24 24\">\n        <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n        <path class=\"opacity-75\" fill=\"currentColor\"\n          d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\">\n        </path>\n      </svg>\n      Loading suggestions ...\n    </div>\n\n    <ng-container *ngIf=\"!suggestions?.length && !loading\">\n      <span>\n        There are no suggestions for your query. Press\n        <pre\n          class=\"inline-block px-0.5 font-mono uppercase bg-gray-500 bg-opacity-25 rounded-sm border border-gray-500 text-xxs\">Enter</pre>\n        to\n        perform a full text search.\n      </span>\n    </ng-container>\n  </div>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/searchbar/searchbar.ts",
    "content": "import { ListKeyManager } from \"@angular/cdk/a11y\";\nimport { coerceBooleanProperty } from \"@angular/cdk/coercion\";\nimport { CdkOverlayOrigin } from \"@angular/cdk/overlay\";\nimport { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Directive, ElementRef, EventEmitter, forwardRef, HostBinding, HostListener, inject, Input, OnDestroy, OnInit, Output, QueryList, TrackByFunction, ViewChild, ViewChildren } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from \"@angular/forms\";\nimport { Condition, ExpertiseLevel, Netquery, NetqueryConnection } from \"@safing/portmaster-api\";\nimport { SfngDropdownComponent } from \"@safing/ui\";\nimport { combineLatest, Observable, of, Subject } from \"rxjs\";\nimport { catchError, debounceTime, map, switchMap } from \"rxjs/operators\";\nimport { fadeInAnimation, fadeInListAnimation } from \"../../animations\";\nimport { ExpertiseService } from \"../../expertise\";\nimport { objKeys } from \"../../utils\";\nimport { NetqueryHelper } from \"../connection-helper.service\";\nimport { Parser, ParseResult } from \"../textql\";\n\nexport type SfngSearchbarFields = {\n  [key in keyof Partial<NetqueryConnection>]: any[];\n} & {\n  groupBy?: string[];\n  orderBy?: string[];\n  from?: string[];\n  to?: string[];\n}\n\nexport type SfngSearchbarSuggestionValue<K extends keyof NetqueryConnection> = {\n  value: NetqueryConnection[K];\n  display: string;\n  count: number;\n}\n\nexport type SfngSearchbarSuggestion<K extends keyof NetqueryConnection> = {\n  start?: number;\n  field: K | '_textsearch';\n  values: SfngSearchbarSuggestionValue<K>[];\n}\n\n@Directive({\n  selector: '[sfngNetquerySuggestion]',\n  exportAs: 'sfngNetquerySuggestion'\n})\nexport class SfngNetquerySuggestionDirective<K extends keyof NetqueryConnection> {\n  constructor() { }\n\n  @Input()\n  sfngSuggestion?: SfngSearchbarSuggestion<K>;\n\n  @Input()\n  sfngNetquerySuggestion?: SfngSearchbarSuggestionValue<K> | string;\n\n  set active(v: any) {\n    this._active = coerceBooleanProperty(v);\n  }\n  get active() {\n    return this._active;\n  }\n  private _active: boolean = false;\n\n  getLabel(): string {\n    if (typeof this.sfngNetquerySuggestion === 'string') {\n      return this.sfngNetquerySuggestion;\n    }\n    return '' + this.sfngNetquerySuggestion?.value;\n  }\n}\n\n@Component({\n  selector: 'sfng-netquery-searchbar',\n  templateUrl: './searchbar.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInAnimation,\n    fadeInListAnimation\n  ],\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => SfngNetquerySearchbarComponent),\n      multi: true,\n    }\n  ]\n})\nexport class SfngNetquerySearchbarComponent implements ControlValueAccessor, OnInit, OnDestroy, AfterViewInit {\n  private loadSuggestions$ = new Subject<void>();\n  private triggerDropdownClose$ = new Subject<boolean>();\n  private keyManager!: ListKeyManager<SfngNetquerySuggestionDirective<any>>;\n  private destroyRef = inject(DestroyRef);\n\n  /** Whether or not we are currently loading suggestions */\n  loading = false;\n\n  @ViewChild(CdkOverlayOrigin, { static: true })\n  searchBoxOverlayOrigin!: CdkOverlayOrigin;\n\n  @ViewChild(SfngDropdownComponent)\n  suggestionDropDown?: SfngDropdownComponent;\n\n  @ViewChild('searchBar', { static: true, read: ElementRef })\n  searchBar!: ElementRef;\n\n  @ViewChildren(SfngNetquerySuggestionDirective)\n  suggestionValues!: QueryList<SfngNetquerySuggestionDirective<any>>;\n\n  @Output()\n  fieldsParsed = new EventEmitter<SfngSearchbarFields>();\n\n  @Input()\n  labels: { [key: string]: string } = {}\n\n  /** Controls whether or not suggestions are shown as a drop-down or inline */\n  @Input()\n  mode: 'inline' | 'default' = 'default';\n\n  suggestions: SfngSearchbarSuggestion<any>[] = [];\n\n  textSearch = '';\n\n  @HostListener('focus')\n  onFocus() {\n    // move focus forward to the input element\n    this.searchBar.nativeElement.focus();\n  }\n\n  @Input()\n  @HostBinding('tabindex')\n  tabindex = 0;\n\n  writeValue(val: string): void {\n    if (typeof val === 'string') {\n      const result = Parser.parse(val);\n      this.textSearch = result.textQuery;\n    } else {\n      this.textSearch = '';\n    }\n    this.cdr.markForCheck();\n  }\n\n  _onChange: (val: string) => void = () => { }\n  registerOnChange(fn: any): void {\n    this._onChange = fn;\n  }\n\n  _onTouched: () => void = () => { }\n  registerOnTouched(fn: any): void {\n    this._onTouched = fn\n  }\n\n  ngAfterViewInit(): void {\n    this.keyManager = new ListKeyManager(this.suggestionValues)\n      .withVerticalOrientation()\n      .withTypeAhead()\n      .withHomeAndEnd()\n      .withWrap();\n\n    this.keyManager.change\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(idx => {\n        if (!this.suggestionValues.length) {\n          return\n        }\n\n        this.suggestionValues.forEach(val => val.active = false);\n        this.suggestionValues.get(idx)!.active = true;\n        this.cdr.markForCheck();\n      });\n  }\n\n  ngOnInit(): void {\n    this.loadSuggestions$\n      .pipe(\n        debounceTime(500),\n        switchMap(() => {\n          let fields: (keyof NetqueryConnection)[] = [\n            'profile',\n            'domain',\n            'as_owner',\n            'remote_ip',\n          ];\n          let limit = 3;\n\n          const parser = new Parser(this.textSearch);\n          const parseResult = parser.process();\n\n          const queries: Observable<SfngSearchbarSuggestion<any>>[] = [];\n          const queryKeys: (keyof Partial<NetqueryConnection>)[] = [];\n\n          // TODO(ppacher): confirm .type is an actually allowed field\n          if (!!parser.lastUnterminatedCondition) {\n            fields = [parser.lastUnterminatedCondition.type as keyof NetqueryConnection];\n            limit = 0;\n          }\n\n          fields.forEach(field => {\n            let queryField = field;\n\n            // if we are searching the profiles we use the profile name\n            // rather than the profile_id for searching.\n            if (field === 'profile') {\n              queryField = 'profile_name';\n            }\n\n            const query: Condition = {\n              [queryField]: {\n                $like: `%${!!parser.lastUnterminatedCondition ? parser.lastUnterminatedCondition.value : parseResult.textQuery}%`\n              },\n            }\n\n            // hide internal connections if the user is not a developer\n            if (this.expertiseService.currentLevel !== ExpertiseLevel.Developer) {\n              query.internal = {\n                $eq: false\n              }\n            }\n\n            const obs = this.netquery.query({\n              select: [\n                field,\n                {\n                  $count: {\n                    field: \"*\",\n                    as: \"count\"\n                  },\n                }\n              ],\n              query: query,\n              groupBy: [\n                field,\n              ],\n              page: 0,\n              pageSize: limit,\n              orderBy: [{ field: \"count\", desc: true }]\n            }, 'netquery-searchbar-get-counts')\n              .pipe(\n                this.helper.encodeToPossibleValues(field),\n                map(results => {\n                  let val: SfngSearchbarSuggestion<typeof field> = {\n                    field: field,\n                    values: [],\n                    start: parser.lastUnterminatedCondition ? parser.lastUnterminatedCondition.start : undefined,\n                  }\n\n                  results.forEach(res => {\n                    val.values.push({\n                      value: res.Value,\n                      display: res.Name,\n                      count: res.count,\n                    })\n                  })\n\n                  return val;\n                }),\n                catchError(err => {\n                  console.error(err);\n\n                  return of({\n                    field: field,\n                    values: [],\n                  })\n                })\n              )\n\n            queries.push(obs)\n            queryKeys.push(field)\n          })\n\n          return combineLatest(queries)\n        }),\n      )\n      .subscribe(result => {\n        this.loading = false;\n\n        this.suggestions = result\n          .filter((sug: SfngSearchbarSuggestion<any>) => sug.values?.length > 0)\n\n        this.keyManager.setActiveItem(0);\n\n        this.cdr.markForCheck();\n      })\n\n    this.triggerDropdownClose$\n      .pipe(debounceTime(100))\n      .subscribe(shouldClose => {\n        if (shouldClose) {\n          this.suggestionDropDown?.close();\n        }\n      })\n\n    if (this.mode === 'inline') {\n      this.loadSuggestions();\n    }\n  }\n\n  ngOnDestroy(): void {\n    this.loadSuggestions$.complete();\n    this.triggerDropdownClose$.complete();\n  }\n\n  cancelDropdownClose() {\n    this.triggerDropdownClose$.next(false);\n  }\n\n  onSearchModelChange(value: string) {\n    if (value.length >= 3 || this.mode === 'inline') {\n      this.loadSuggestions();\n    } else if (this.suggestionDropDown?.isOpen) {\n      // close the suggestion dropdown if the search input contains less than\n      // 3 characters and we're currently showing the dropdown\n      this.suggestionDropDown?.close();\n    }\n  }\n\n  /** @private Callback for keyboard events on the search-input */\n  onSearchKeyDown(event: KeyboardEvent) {\n    if (event.key === ' ' && event.ctrlKey) {\n      this.loadSuggestions();\n      event.preventDefault();\n      event.stopPropagation()\n      return;\n    }\n\n    if (event.key === 'Enter') {\n\n      const selectedSuggestion = this.suggestionValues.toArray().findIndex(val => val.active);\n      if (selectedSuggestion > 0) { // we must skip 0 here as well as that's the dummy element\n        const sug = this.suggestionValues.get(selectedSuggestion);\n        this.applySuggestion(sug?.sfngSuggestion?.field, sug?.sfngNetquerySuggestion, event, sug?.sfngSuggestion?.start)\n\n        return;\n      }\n\n      this.suggestionDropDown?.close();\n      this.parseAndEmit();\n      this.cdr.markForCheck();\n\n      return;\n    }\n\n    this.keyManager.onKeydown(event);\n  }\n\n  onFocusLost(event: FocusEvent) {\n    this._onTouched();\n  }\n\n  private parseAndEmit() {\n    const result = Parser.parse(this.textSearch);\n    this.textSearch = result.textQuery;\n\n    const keys = objKeys(result.conditions)\n    const meta = {\n      groupBy: result.groupBy || undefined,\n      orderBy: result.orderBy || undefined,\n    }\n    if (keys.length > 0 || meta.groupBy?.length || meta.orderBy?.length) {\n      let updatedConditions: ParseResult['conditions'] = {};\n      keys.forEach(key => {\n        updatedConditions[key] = this.helper.decodePrettyValues(key as keyof NetqueryConnection, result.conditions[key])\n      })\n      this.fieldsParsed.next({ ...updatedConditions, ...meta });\n    }\n\n    this._onChange(this.textSearch);\n  }\n\n  applySuggestion(field: keyof NetqueryConnection | '_textsearch', val: any, event: { shiftKey: boolean }, start?: number) {\n    // this is a full-text search so just emit the value, close the dropdown and we're done\n    if (field === '_textsearch') {\n      this._onChange(this.textSearch);\n      this.suggestionDropDown?.close();\n\n      return\n    }\n\n    if (start !== undefined) {\n      this.textSearch = this.textSearch.slice(0, start)\n    } else if (!event.shiftKey) {\n      this.textSearch = '';\n    } else {\n      // the user pressed shift-key and used free-text search so we remove\n      // the remaining part\n      const parseRes = Parser.parse(this.textSearch);\n      let query = \"\";\n      objKeys(parseRes.conditions).forEach(field => {\n        parseRes.conditions[field]?.forEach(value => {\n          query += `${field}:${JSON.stringify(value)} `\n        })\n      })\n      this.textSearch = query;\n    }\n\n    if (event.shiftKey) {\n      const textqlVal = `${field}:${JSON.stringify(val)}`\n      if (!this.textSearch.includes(textqlVal)) {\n        if (this.textSearch !== '') {\n          this.textSearch += \" \"\n        }\n        this.textSearch += textqlVal + \" \"\n        this.triggerDropdownClose$.next(false)\n        // load new suggestions based on the new input\n        this.loadSuggestions();\n      }\n\n      return;\n    }\n\n    // directly emit the new value and reset the text search\n    this.fieldsParsed.next({\n      [field]: [val]\n    })\n\n    // parse and emit the current search field but without the suggestion value\n    this.parseAndEmit();\n\n    this.suggestionDropDown?.close();\n\n    this.cdr.markForCheck();\n  }\n\n  resetKeyboardSelection() {\n    this.keyManager.setActiveItem(0);\n  }\n\n  loadSuggestions() {\n    this.loading = true;\n    this.loadSuggestions$.next();\n    this.suggestionDropDown?.show(this.searchBoxOverlayOrigin)\n  }\n\n  trackSuggestion: TrackByFunction<SfngSearchbarSuggestion<any>> = (_: number, val: SfngSearchbarSuggestion<any>) => val.field;\n\n  constructor(\n    private cdr: ChangeDetectorRef,\n    private expertiseService: ExpertiseService,\n    private netquery: Netquery,\n    private helper: NetqueryHelper,\n  ) { }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/tag-bar/index.ts",
    "content": "export * from './tag-bar';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/tag-bar/tag-bar.html",
    "content": "<div *ngFor=\"let cat of values; trackBy: trackValue\" class=\"flex flex-row items-center justify-start gap-1\">\n  <ng-container *ngFor=\"let val of cat.values; let index=index\">\n    <div class=\"flex flex-row gap-1 justify-between items-center pl-3 py-0.5 pr-0.5 bg-gray-500 rounded-full text-xxs\">\n      <span class=\"flex flex-row items-center\" [sfng-tooltip]=\"val.Value\">\n        <span class=\"text-secondary\">\n          {{labels[cat.key] || cat.key}}:\n        </span>\n\n        <span class=\"inline-block ml-1 overflow-hidden overflow-ellipsis whitespace-nowrap text-primary\"\n          style=\"direction: rtl\" [ngStyle]=\"{maxWidth: maxTagWidth}\">\n          <span style=\"direction: ltr; unicode-bidi: bidi-override;\">\n            {{ val.Name || (val.Value === '' ? 'N/A' : val) }}\n          </span>\n        </span>\n      </span>\n      <span class=\"p-0.5 rounded-full cursor-pointer hover:text-primary text-secondary hover:bg-gray-100\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-3 h-3\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n          (click)=\"remove(cat.key, index)\">\n          <path fill-rule=\"evenodd\"\n            d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n            clip-rule=\"evenodd\" />\n        </svg>\n      </span>\n    </div>\n  </ng-container>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/tag-bar/tag-bar.ts",
    "content": "import { coerceBooleanProperty, coerceCssPixelValue } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, HostBinding, Input } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { PossilbeValue } from '@safing/portmaster-api';\nimport { fadeInListAnimation } from '../../animations';\nimport { NetqueryHelper } from '../connection-helper.service';\n\nexport interface SfngTagbarValue {\n  key: string;\n  values: PossilbeValue[];\n}\n\n@Component({\n  selector: 'sfng-netquery-tagbar',\n  templateUrl: 'tag-bar.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styles: [\n    `\n    :host {\n      @apply flex flex-row gap-3 w-auto items-center text-xxs flex-wrap;\n    }\n    `\n  ],\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => SfngNetqueryTagbarComponent),\n      multi: true\n    }\n  ],\n  animations: [\n    fadeInListAnimation\n  ]\n})\nexport class SfngNetqueryTagbarComponent implements ControlValueAccessor {\n  @HostBinding('@fadeInList')\n  get itemsLength() {\n    return this.values?.length || 0;\n  }\n\n  /** @private the current tag bar values */\n  values: SfngTagbarValue[] = [];\n\n  /** Whether or not the user can interact with the component */\n  @Input()\n  set disabled(v: any) {\n    this.setDisabledState(v)\n  }\n  get disabled() {\n    return this._disabled;\n  }\n  private _disabled = false;\n\n  /** Translations for the value keys */\n  @Input()\n  labels: { [key: string]: string } = {}\n\n  /** The maximum width of the tag text before being truncated using left-side ellipsis */\n  @Input()\n  set maxTagWidth(width: any) {\n    this._maxTagWidth = coerceCssPixelValue(width)\n  }\n  get maxTagWidth() {\n    return this._maxTagWidth\n  }\n  private _maxTagWidth: string = '8rem'\n\n  /** @private A {@link TrackByFunction} for {@link SfngTagbarValue} */\n  trackValue(_: number, vl: SfngTagbarValue) {\n    return vl.key;\n  }\n\n  /** Implements the {@link ControlValueAccessor} */\n  writeValue(obj: SfngTagbarValue[]): void {\n    this.values = obj;\n    this.cdr.markForCheck();\n  }\n\n  /** Implements the {@link ControlValueAccessor} */\n  registerOnChange(fn: any): void {\n    this._onChange = fn;\n  }\n\n  /** @private - callback registered via registerOnChange */\n  _onChange: (val: SfngTagbarValue[]) => void = () => { }\n\n  /** Implements the {@link ControlValueAccessor} */\n  registerOnTouched(fn: any): void {\n    this._onTouched = fn\n  }\n\n  /** @private - callback registered via registerOnTouched */\n  _onTouched: () => void = () => { }\n\n  /** Implements the {@link ControlValueAccessor} */\n  setDisabledState(v: any) {\n    this._disabled = coerceBooleanProperty(v)\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * remove removes the value at index from the {@link SfngTagbarValue}\n   * that matches key.\n   */\n  remove(key: string, index: number) {\n    if (this.disabled) {\n      return;\n    }\n\n    console.log(this.values);\n\n    let cpy: SfngTagbarValue[] = [];\n\n    this.values.forEach(val => {\n      if (val.key === key) {\n        val.values = [...val.values];\n        val.values.splice(index, 1)\n      }\n      cpy.push({\n        ...val,\n      })\n    });\n\n    this.values = cpy;\n\n    console.log(this.values);\n\n    this._onChange(this.values);\n    this.cdr.markForCheck();\n  }\n\n  constructor(\n    private cdr: ChangeDetectorRef,\n    private helper: NetqueryHelper,\n  ) { }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/textql/helper.ts",
    "content": "import { Token, TokenType } from \"./token\";\n\nexport function isValueToken(tok: Token<any>): tok is Token<TokenType.STRING | TokenType.BOOL | TokenType.NUMBER> {\n  return [TokenType.STRING, TokenType.BOOL, TokenType.NUMBER].includes(tok.type)\n}\n\nexport function isDigit(x: string): boolean {\n  return /[0-9]+/.test(x);\n}\n\nexport function isWhitespace(ch: string): boolean {\n  return /\\s/.test(ch)\n}\n\nexport function isLetter(ch: string): boolean {\n  return new RegExp('[\\/a-zA-Z0-9\\._-]').test(ch)\n}\n\nexport function isIdentChar(ch: string): boolean {\n  return /[a-zA-Z_]/.test(ch);\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/textql/index.ts",
    "content": "export * from './parser';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/textql/input.ts",
    "content": "/** Input stream returns one character at a time */\nexport class InputStream {\n  private _pos: number = 0;\n  private _line: number = 0;\n\n  constructor(private _input: string) { }\n\n  /** Returns the next character and removes it from the stream */\n  next(): string | null {\n    const ch = this._input.charAt(this._pos++);\n    return ch;\n  }\n\n  get pos() {\n    return this._pos;\n  }\n\n  /** Revert moves the current stream position back by `num` characters */\n  revert(num: number) {\n    this._pos -= num;\n  }\n\n  /** Returns the next character in the stream but does not remove it */\n  peek(): string {\n    return this._input.charAt(this._pos);\n  }\n\n  /** Returns true if we reached the end of the stream */\n  eof(): boolean {\n    return this.peek() == '';\n  }\n\n  get left(): string {\n    return this._input.slice(this._pos)\n  }\n\n  /** Throws an error with the current line and column */\n  croak(msg: string): never {\n    throw new Error(`${msg} at ${this._line}:${this.pos}`);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/textql/lexer.ts",
    "content": "import { isDigit, isIdentChar, isLetter, isWhitespace } from \"./helper\";\nimport { InputStream } from \"./input\";\nimport { Token, TokenType } from \"./token\";\n\nexport class Lexer {\n  private _current: Token<any> | null = null;\n  private _input: InputStream;\n\n  constructor(input: string) {\n    this._input = new InputStream(input);\n  }\n\n  /** peek returns the token at the current position in input. */\n  public peek(): Token<any> | null {\n    return this._current || (this._current = this.readNextToken());\n  }\n\n  /** next returns either the current token in input or reads the next one */\n  public next(): Token<any> | null {\n    let tok = this._current;\n    this._current = null;\n    return tok || this.readNextToken();\n  }\n\n  /** eof returns true if the lexer reached the end of the input stream */\n  public eof(): boolean {\n    return this.peek() === null;\n  }\n\n  /** croak throws and error message at the current position in the input stream */\n  public croak(msg: string): never {\n    return this._input.croak(`${msg}. Current token is \"${!!this.peek() ? this.peek()!.literal : null}\"`);\n  }\n\n  /** consumes the input stream as long as predicate returns true */\n  private readWhile(predicate: (ch: string) => boolean): string {\n    let str = '';\n    while (!this._input.eof() && predicate(this._input.peek())) {\n      str += this._input.next();\n    }\n\n    return str;\n  }\n\n  /** reads a number token */\n  private readNumber(): Token<TokenType.NUMBER> | null {\n    const start = this._input.pos;\n\n    let has_dot = false;\n    let number = this.readWhile((ch: string) => {\n      if (ch === '.') {\n        if (has_dot) {\n          return false;\n        }\n\n        has_dot = true;\n        return true;\n      }\n      return isDigit(ch);\n    });\n\n    if (!this._input.eof() && !isWhitespace(this._input.peek())) {\n      this._input.revert(number.length);\n\n      return null;\n    }\n\n    return {\n      type: TokenType.NUMBER,\n      literal: number,\n      value: has_dot ? parseFloat(number) : parseInt(number),\n      start\n    }\n  }\n\n  private readIdent(): Token<TokenType.IDENT | TokenType.BOOL | TokenType.GROUPBY | TokenType.ORDERBY> {\n    const start = this._input.pos;\n\n    const id = this.readWhile(ch => isIdentChar(ch));\n    if (id === 'true' || id === 'yes') {\n      return {\n        type: TokenType.BOOL,\n        literal: id,\n        value: true,\n        start\n      }\n    }\n    if (id === 'false' || id === 'no') {\n      return {\n        type: TokenType.BOOL,\n        literal: id,\n        value: false,\n        start\n      }\n    }\n    if (id === 'groupby') {\n      return {\n        type: TokenType.GROUPBY,\n        literal: id,\n        value: id,\n        start\n      }\n    }\n    if (id === 'orderby') {\n      return {\n        type: TokenType.ORDERBY,\n        literal: id,\n        value: id,\n        start\n      }\n    }\n\n    return {\n      type: TokenType.IDENT,\n      literal: id,\n      value: id,\n      start\n    };\n  }\n\n  private readEscaped(end: string | RegExp, skipStart: boolean): string {\n    let escaped = false;\n    let str = '';\n\n    if (skipStart) {\n      this._input.next();\n    }\n\n    while (!this._input.eof()) {\n      let ch = this._input.next()!;\n      if (escaped) {\n        str += ch;\n        escaped = false;\n      } else if (ch === '\\\\') {\n        escaped = true;\n      } else if ((typeof end === 'string' && ch === end) || (end instanceof RegExp && end.test(ch))) {\n        break;\n      } else {\n        str += ch;\n      }\n    }\n    return str;\n  }\n\n  private readString(quote: string | RegExp, skipStart: boolean): Token<TokenType.STRING> {\n    const start = this._input.pos;\n    const value = this.readEscaped(quote, skipStart)\n    return {\n      type: TokenType.STRING,\n      literal: value,\n      value: value,\n      start\n    }\n  }\n\n  private readWhitespace(): Token<TokenType.WHITESPACE> {\n    const start = this._input.pos;\n    const value = this.readWhile(ch => isWhitespace(ch));\n    return {\n      type: TokenType.WHITESPACE,\n      literal: value,\n      value: value,\n      start,\n    }\n  }\n\n  private readNextToken(): Token<any> | null {\n    const start = this._input.pos;\n    const ch = this._input.peek();\n    if (ch === '') {\n      return null;\n    }\n\n    if (isWhitespace(ch)) {\n      return this.readWhitespace()\n    }\n\n    if (ch === '\"') {\n      return this.readString('\"', true);\n    }\n\n    if (ch === '\\'') {\n      return this.readString('\\'', true);\n    }\n\n    if (isDigit(ch)) {\n      const number = this.readNumber();\n      if (number !== null) {\n        return number;\n      }\n    }\n\n    if (ch === ':') {\n      this._input.next();\n      return {\n        type: TokenType.COLON,\n        value: ':',\n        literal: ':',\n        start\n      }\n    }\n\n    if (ch === '!') {\n      this._input.next();\n      return {\n        type: TokenType.NOT,\n        value: '!',\n        literal: '!',\n        start\n      }\n    }\n\n    if (isIdentChar(ch)) {\n      const ident = this.readIdent();\n\n      const next = this._input.peek();\n      if (!this._input.eof() && (!isWhitespace(next) && next !== ':')) {\n\n        // identifiers should always end in a colon or with a whitespace.\n        // if neither is the case we are in the middle of a token and are\n        // likely parsing a string without quotes.\n        this._input.revert(ident.literal.length);\n\n        // read the string and revert by one as we terminate the string\n        // at the next WHITESPACE token\n        const tok = this.readString(new RegExp('\\\\s'), false)\n        this.revertWhitespace();\n\n        return tok;\n      }\n\n      return ident;\n    }\n\n    if (isLetter(ch)) {\n      const tok = this.readString(new RegExp('\\\\s'), false)\n      // read the string and revert by one as we terminate the string\n      // at the next WHITESPACE token\n      this.revertWhitespace();\n\n      return tok\n    }\n\n    // Failed to handle the input character\n    return this._input.croak(`Can't handle character: ${ch}`);\n  }\n\n  private revertWhitespace() {\n    this._input.revert(1)\n    if (!isWhitespace(this._input.peek())) {\n      this._input.next();\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/textql/parser.ts",
    "content": "import { isDevMode } from '@angular/core';\nimport { isValueToken, isWhitespace } from './helper';\nimport { Lexer } from './lexer';\nimport { Token, TokenType } from './token';\n\n\nexport interface ParseResult {\n  conditions: {\n    [key: string]: (any | { $ne: any })[];\n  };\n  textQuery: string;\n  groupBy?: string[];\n  orderBy?: string[];\n}\n\nexport class Parser {\n  /** The underlying lexer used to tokenize the input */\n  private lexer: Lexer;\n\n  /** Holds the parsed conditions */\n  private conditions: {\n    [key: string]: any[];\n  } = {};\n\n  /** The last condition that has not yet been terminated. Used for scope-based suggestions */\n  private _lastUnterminatedCondition: {\n    start: number;\n    type: string;\n    value: any;\n  } | null = null;\n\n  /** A list of remaining strings/identifiers that are not part of a condition */\n  private remaining: string[] = [];\n\n  /** Returns the last condition that has not yet been terminated. */\n  get lastUnterminatedCondition() {\n    return this._lastUnterminatedCondition;\n  }\n\n  constructor(input: string) {\n    this.lexer = new Lexer(input);\n  }\n\n  static aliases: { [key: string]: string } = {\n    'provider': 'as_owner',\n    'app': 'profile',\n    'ip': 'remote_ip',\n    'port': 'remote_port'\n  }\n\n  /** parse is a shortcut for new Parser(input).process() */\n  static parse(input: string): ParseResult {\n    return new Parser(input).process();\n  }\n\n  /** Process the whole input stream and return the parsed result */\n  process(): ParseResult {\n    let lastIdent: Token<TokenType.IDENT | TokenType.GROUPBY | TokenType.ORDERBY> | null = null;\n    let hasColon = false;\n    let not = false;\n    let groupBy: string[] = [];\n    let orderBy: string[] = [];\n\n    while (true) {\n      const tok = this.lexer.next()\n      if (tok === null) {\n        break;\n      }\n\n      if (isDevMode()) {\n        console.log(tok)\n      }\n\n      // if we find a whitespace token we count it as a termination character\n      // for the last unterminated condition.\n      if (tok.type === TokenType.WHITESPACE) {\n        this._lastUnterminatedCondition = null;\n      }\n\n      // Since we allow the user to enter values without quotes the\n      // lexer might wrongly declare a \"string value\" as an IDENT.\n      // If we have the pattern <IDENT><COLON><IDENT> we re-classify\n      // the last IDENT as a STRING value\n      if (!!lastIdent && hasColon && tok.type === TokenType.IDENT) {\n        tok.type = TokenType.STRING;\n      }\n\n      if (tok.type === TokenType.IDENT || tok.type === TokenType.GROUPBY || tok.type === TokenType.ORDERBY) {\n        // if we had an IDENT token before and got a new one now the\n        // previous one is pushed to the remaining list\n        if (!!lastIdent) {\n          this._lastUnterminatedCondition = null;\n          this.remaining.push(lastIdent.value)\n        }\n        lastIdent = tok;\n        this._lastUnterminatedCondition = {\n          start: tok.start,\n          type: Parser.aliases[lastIdent.value] || lastIdent.value,\n          value: '',\n        }\n\n        continue\n      }\n\n      // if we don't have an preceding IDENT token\n      // this must be part of remaingin\n      if (!lastIdent) {\n        this.remaining.push(tok.literal);\n        this._lastUnterminatedCondition = null;\n\n        continue\n      }\n\n      // we would expect a colon now\n      if (!hasColon) {\n        if (tok.type !== TokenType.COLON) {\n          // we expected a colon but got something else.\n          // this means the last IDENT is part of remaining\n          this.remaining.push(lastIdent.value);\n          lastIdent = null;\n          this._lastUnterminatedCondition = null;\n\n          continue\n        }\n\n        // we have a colon now so proceed to the next token\n        hasColon = true;\n        not = false;\n\n        continue\n      }\n\n      if (lastIdent.type === TokenType.GROUPBY) {\n        groupBy.push(Parser.aliases[tok.literal] || tok.literal)\n        lastIdent = null\n        hasColon = false\n\n        continue\n      }\n\n      if (lastIdent.type == TokenType.ORDERBY) {\n        orderBy.push(Parser.aliases[tok.literal] || tok.literal)\n        lastIdent = null\n        hasColon = false\n\n        continue\n      }\n\n      if (tok.type === TokenType.NOT && not === false) {\n        not = true\n\n        continue\n      }\n\n      if (isValueToken(tok)) {\n        let identValue = Parser.aliases[lastIdent.value] || lastIdent.value;\n\n        if (!this.conditions[identValue]) {\n          this.conditions[identValue] = [];\n        }\n\n        if (!not) {\n          this.conditions[identValue].push(tok.value)\n        } else {\n          this.conditions[identValue].push({ $ne: tok.value })\n        }\n        this._lastUnterminatedCondition!.value = tok.value;\n\n        lastIdent = null\n        hasColon = false\n        not = false\n\n        continue\n      }\n\n      this.remaining.push(lastIdent.value);\n      lastIdent = null;\n      hasColon = false;\n      not = false;\n      this._lastUnterminatedCondition = null;\n    }\n\n    if (!!lastIdent) {\n      this.remaining.push(lastIdent.value);\n\n      if (hasColon) {\n        this._lastUnterminatedCondition = {\n          start: lastIdent.start,\n          type: Parser.aliases[lastIdent.value] || lastIdent.value,\n          value: ''\n        };\n      } else {\n        this._lastUnterminatedCondition = null;\n      }\n    }\n\n    return {\n      groupBy: groupBy.length > 0 ? groupBy : undefined,\n      orderBy: orderBy.length > 0 ? orderBy : undefined,\n      conditions: this.conditions,\n      textQuery: this.remaining.filter(tok => !isWhitespace(tok)).join(\" \"),\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/textql/token.ts",
    "content": "\n/**\n * Language Definition:\n *\n * input:\n *\n *    [EXPR] [EXPR]...\n *\n * with:\n *\n *    EXPR = [IDENT][COLON][NOT?][VALUE]\n *    NOT = \"!\"\n *    VALUE = [STRING][BOOL][NUMBER]\n *    STRING = [a-zA-Z\\.0-9]\n *    BOOL = true | false\n *    NUMBER = [0-9]+\n *    COLON = \":\"\n *\n */\n\nexport enum TokenType {\n  WHITESPACE = 'WHITESPACE',\n  IDENT = 'IDENT',\n  COLON = 'COLON',\n  STRING = 'STRING',\n  NUMBER = 'NUMBER',\n  BOOL = 'BOOL',\n  NOT = 'NOT',\n  GROUPBY = 'GROUPBY',\n  ORDERBY = 'ORDERBY'\n}\n\nexport type TokenValue<T extends TokenType> =\n  T extends TokenType.NUMBER ? number :\n  T extends TokenType.STRING ? string :\n  T extends TokenType.BOOL ? boolean :\n  T extends TokenType.NOT ? '!' :\n  T extends TokenType.GROUPBY ? 'string' :\n  string;\n\nexport interface Token<T extends TokenType> {\n  type: T;\n  literal: string;\n  value: TokenValue<T>;\n  start: number;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/netquery/utils.ts",
    "content": "import { Condition, Matcher } from \"@safing/portmaster-api\";\nimport { objKeys } from \"../utils\";\n\nexport const connectionFieldTranslation: { [key: string]: string } = {\n  domain: \"Domain\",\n  profile: \"App\",\n  path: 'Binary Path',\n  scope: 'Scope',\n  as_owner: \"Provider\",\n  country: \"Country\",\n  direction: 'Direction',\n  started: 'Started',\n  ended: 'Ended',\n  remote_ip: 'Remote IP',\n  verdict: 'Verdict',\n  encrypted: 'Encrypted',\n  internal: 'Internal',\n  asn: 'ASN',\n  tunneled: 'SPN Active',\n  active: 'Active',\n  allowed: 'Allowed',\n  from: 'From',\n  to: 'To',\n  remote_port: 'Port',\n  bytes_sent: 'Bytes Sent',\n  bytes_received: 'Bytes Received'\n}\n\nexport function isMatcher(v: any | Matcher): v is Matcher {\n  return typeof v === 'object' && ('$eq' in v || '$ne' in v || '$like' in v || '$in' in v || '$notin' in v);\n}\n\nexport function mergeConditions(cond1: Condition, cond2: Condition): Condition {\n  const result: Condition = {};\n\n  objKeys(cond1).forEach(key => {\n    let val = cond1[key];\n    if (Array.isArray(val)) {\n      result[key] = val;\n    } else {\n      result[key] = [val];\n    }\n  })\n\n  objKeys(cond2).forEach(key => {\n    let val = cond2[key];\n    if (!Array.isArray(val)) {\n      val = [val]\n    }\n\n    if (!(key in result)) {\n      result[key] = val;\n    } else {\n      result[key] = [\n        ...(result[key] as any), // this must be an array here\n        ...val,\n      ]\n    }\n  })\n\n\n  return result;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/network-scout/index.ts",
    "content": "export * from './network-scout';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/network-scout/network-scout.html",
    "content": "<div class=\"flex flex-row items-center gap-2\">\n  <div class=\"relative w-full\">\n    <input type=\"text\" placeholder=\"SEARCH\" [(ngModel)]=\"searchTerm\" (ngModelChange)=\"triggerSearch.next($event)\"\n      class=\"!pl-7 !pr-16\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n      class=\"absolute w-4 h-4 top-1.5 left-1.5\">\n      <path fill-rule=\"evenodd\"\n        d=\"M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z\"\n        clip-rule=\"evenodd\" />\n    </svg>\n    <span class=\"text-xxs uppercase text-secondary absolute right-1.5 top-2 font-light\">\n      {{allProfiles.length}} Apps\n    </span>\n  </div>\n\n  <ng-template #settingsTrigger>\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n      class=\"w-8 h-full p-1.5 bg-gray-300 rounded cursor-pointer text-secondary hover:text-primary\">\n      <path fill-rule=\"evenodd\"\n        d=\"M2.24 6.8a.75.75 0 001.06-.04l1.95-2.1v8.59a.75.75 0 001.5 0V4.66l1.95 2.1a.75.75 0 101.1-1.02l-3.25-3.5a.75.75 0 00-1.1 0L2.2 5.74a.75.75 0 00.04 1.06zm8 6.4a.75.75 0 00-.04 1.06l3.25 3.5a.75.75 0 001.1 0l3.25-3.5a.75.75 0 10-1.1-1.02l-1.95 2.1V6.75a.75.75 0 00-1.5 0v8.59l-1.95-2.1a.75.75 0 00-1.06-.04z\"\n        clip-rule=\"evenodd\" />\n    </svg>\n  </ng-template>\n\n  <sfng-dropdown [triggerTemplate]=\"settingsTrigger\">\n    <div class=\"flex flex-col gap-2 p-2\">\n      <h4>Sort By</h4>\n      <sfng-select displayMode=\"inline\" [ngModel]=\"sortOrder\" (ngModelChange)=\"updateSortOrder($event)\">\n        <ng-container *ngFor=\"let sortMethod of sortTypes\">\n          <sfng-select-item\n            *sfngSelectValue=\"sortMethod; description:(sortMethod === 'Static' ? 'The default sort order which adds new apps to the bottom' : '')\">\n            {{ sortMethod }}</sfng-select-item>\n        </ng-container>\n      </sfng-select>\n    </div>\n  </sfng-dropdown>\n\n  <ng-container *ngIf=\"spnEnabled\">\n    <svg *ngIf=\"expandCollapseState === 'expand'\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\"\n      stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-8 h-full p-1.5 bg-gray-300 rounded cursor-pointer text-secondary hover:text-primary\"\n      (click)=\"collapseAll()\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25\" />\n    </svg>\n    <svg *ngIf=\"expandCollapseState === 'collapse'\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\"\n      stroke-width=\"1.5\" stroke=\"currentColor\"\n      class=\"w-8 h-full p-1.5 bg-gray-300 rounded cursor-pointer text-secondary hover:text-primary\"\n      (click)=\"expandAll()\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15\" />\n    </svg>\n  </ng-container>\n</div>\n\n<sfng-accordion-group singleMode=\"false\" [headerTemplate]=\"header\" [@fadeInList]=\"profiles.length\"\n  [disabled]=\"!spnEnabled\" class=\"flex flex-col gap-2\">\n  <sfng-accordion *ngFor=\"let profile of profiles; trackBy: trackProfile\" [data]=\"profile\"\n    [(active)]=\"profile.expanded\">\n    <div class=\"relative my-3 border-t border-gray-300\">\n      <span class=\"absolute right-0 block pl-2 bg-gray-100 text-tertiary -top-2 text-xxs\"> {{ profile.exitPins.length }}\n        IDENTITIES</span>\n    </div>\n\n    <span class=\"block w-full p-2 text-center text-secondary text-xxs\" *ngIf=\"profile.identities.length === 0\">\n      Connections from {{ profile.Name }} have not been routed through the SPN.\n    </span>\n\n    <ul class=\"grid grid-cols-2 gap-3 p-3\" [@fadeInList]=\"profile.exitPins.length\">\n      <li\n        *ngFor=\"let identity of (profile.showMore ? profile.exitPins : profile.exitPins.slice(0, 4)); trackBy: trackPin\"\n        class=\"flex flex-col bg-gray-200 rounded outline-none justify-items-stretch\">\n        <span class=\"flex flex-row items-center p-2 bg-gray-300 rounded-t\">\n          <ng-container class=\"flex-grow overflow-hidden\" *ngIf=\"identity.EntityV4 || identity.EntityV6 as entity\">\n            <span class=\"block w-6 text-left\" [appCountryFlags]=\"entity.Country\"></span>\n            <span class=\"overflow-hidden font-medium text-primary text-ellipsis\"> {{ entity.IP }} </span>\n          </ng-container>\n        </span>\n        <div class=\"flex flex-row\">\n          <span class=\"flex-grow p-2 rounded-bl outline-none cursor-pointer text-primary text-xxs hover:bg-gray-400\"\n            [routerLink]=\"['/monitor']\"\n            [queryParams]=\"{q: 'groupby:\\'\\' exit_node:' + identity.ID + ' profile:'+profile.ID}\"\n            (click)=\"$event.stopPropagation()\">\n            {{ identity.count }}\n            <span class=\"font-light text-secondary\">Connections</span>\n          </span>\n          <span\n            class=\"p-2 bg-gray-300 bg-opacity-50 rounded-br outline-none cursor-pointer text-primary text-xxs hover:bg-gray-400\"\n            [routerLink]=\"['/spn']\" [queryParams]=\"{app: profile.ID, pin: identity.ID}\">\n            <span class=\"font-light text-secondary\">HOPS:</span>\n            {{ identity.HopDistance }}\n          </span>\n        </div>\n      </li>\n    </ul>\n\n    <span class=\"block w-full text-center text-secondary text-xxs\" *ngIf=\"profile.exitPins.length > 4\"\n      (click)=\"profile.showMore = !profile.showMore\">\n      {{ profile.showMore ? 'Show Less Identities' : 'Show More Identities'}}\n    </span>\n  </sfng-accordion>\n</sfng-accordion-group>\n\n<ng-template #header let-data let-active=\"active\" let-accordion=\"accordion\">\n  <div class=\"flex flex-row items-center w-full gap-3 px-3 py-2 bg-gray-200 rounded-sm outline-none\"\n    [ngClass]=\"{'cursor-pointer hover:bg-gray-300': !spnEnabled}\" [routerLink]=\"['/app/' + data.ID]\"\n    [queryParams]=\"{tab: 0}\" (click)=\"$event.stopPropagation()\">\n\n    <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"flex-shrink-0 w-4 h-4 transition-all duration-150 transform\"\n      *ngIf=\"spnEnabled\" [class.rotate-90]=\"active\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n      (click)=\"accordion.toggle($event); $event.stopPropagation()\">\n      <path fill-rule=\"evenodd\"\n        d=\"M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z\"\n        clip-rule=\"evenodd\" />\n    </svg>\n\n    <span class=\"flex flex-row items-center flex-grow gap-2 overflow-hidden whitespace-nowrap\">\n      <app-icon [profile]=\"data\"></app-icon>\n      <span class=\"overflow-hidden text-ellipsis\">\n        {{ data.Name }}\n      </span>\n    </span>\n\n    <span class=\"flex self-stretch -top-2 -bottom-2 text-tertiary\">\n      <div class=\"flex items-center justify-center w-6 h-full outline-none cursor-pointer hover:text-primary\"\n        [routerLink]=\"['/spn']\" *ngIf=\"data.identities.length > 0\" [queryParams]=\"{app: data.ID}\"\n        (click)=\"$event.stopPropagation()\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" class=\"w-3.5 h-3.5\" stroke=\"currentColor\">\n          <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\n            <path\n              d=\"M6.488 15.581c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0M13.415 3.586c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.049-.781 2.83 0M20.343 15.58c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0\" />\n            <path\n              d=\"M17.721 18.581C16.269 20.071 14.246 21 12 21c-1.146 0-2.231-.246-3.215-.68M4.293 15.152c-.56-1.999-.352-4.21.769-6.151.574-.995 1.334-1.814 2.205-2.449M13.975 5.254c2.017.512 3.834 1.799 4.957 3.743.569.985.899 2.041 1.018 3.103\" />\n          </g>\n        </svg>\n      </div>\n\n      <div class=\"flex items-center justify-center w-6 h-full outline-none cursor-pointer hover:text-primary\"\n        [routerLink]=\"['/app/' + data.ID]\" [queryParams]=\"{tab: 0}\" (click)=\"$event.stopPropagation()\">\n        <svg viewBox=\"0 0 24 24\" class=\"w-3.5 h-3.5\">\n          <g fill=\"none\" stroke=\"currentColor\">\n            <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n              d=\"M8.464 8.464c-1.953 1.953-1.953 5.118 0 7.071 1.953 1.953 5.118 1.953 7.071 0 1.953-1.953 1.953-5.119 0-7.071C14.559 7.488 13.28 7 12 7\" />\n            <path shape-rendering=\"geometricPrecision\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n              d=\"M5.636 5.636c-3.515 3.515-3.515 9.213 0 12.728 3.515 3.515 9.213 3.515 12.728 0 3.515-3.515 3.515-9.213 0-12.728-2.627-2.627-6.474-3.289-9.717-1.989M5.64 5.64L12 12\" />\n          </g>\n        </svg>\n      </div>\n\n      <div class=\"flex items-center justify-center w-6 h-full outline-none cursor-pointer hover:text-primary\"\n        [routerLink]=\"['/app/' + data.ID]\" [queryParams]=\"{tab: 'settings'}\" (click)=\"$event.stopPropagation()\">\n        <svg xmlns=\"http://www.w3.org/2000/svg\" data-name=\"Layer 1\" viewBox=\"0 0 24 24\" class=\"w-3.5 h-3.5\" fill=\"none\"\n          stroke=\"currentColor\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" fill=\"currentColor\"\n            d=\"M19 21h-3a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2Z\" />\n          <path fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"\n            d=\"M19 9h-3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2ZM5 3h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2ZM5 15h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2Z\" />\n        </svg>\n      </div>\n\n    </span>\n\n    <app-count-indicator *ngIf=\"!isByteSortOrder; else: bytesTemplate\" [count]=\"data.size\" [countAllowed]=\"data.countAllowed\"></app-count-indicator>\n    <ng-template #bytesTemplate>\n      <div style=\"font-size: 0.6rem\" class=\"bg-gray-300 font-light p-0.5 pr-1 rounded-md w-14 flex-shrink-0 flex-grow-0 \">\n        <span class=\"flex flex-row leading-3 justify-between items-center text-deepPurple-200\">\n          <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"w-3 h-3\">\n            <path fill-rule=\"evenodd\" d=\"M10 15a.75.75 0 01-.75-.75V7.612L7.29 9.77a.75.75 0 01-1.08-1.04l3.25-3.5a.75.75 0 011.08 0l3.25 3.5a.75.75 0 11-1.08 1.04l-1.96-2.158v6.638A.75.75 0 0110 15z\" clip-rule=\"evenodd\" />\n          </svg>\n          {{ data.bytes_sent | bytes:\"1.0-0\" }}\n        </span>\n\n        <span class=\"flex flex-row leading-3 justify-between items-center text-cyan-700\">\n          <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"w-3 h-3\">\n            <path fill-rule=\"evenodd\" d=\"M10 5a.75.75 0 01.75.75v6.638l1.96-2.158a.75.75 0 111.08 1.04l-3.25 3.5a.75.75 0 01-1.08 0l-3.25-3.5a.75.75 0 111.08-1.04l1.96 2.158V5.75A.75.75 0 0110 5z\" clip-rule=\"evenodd\" />\n          </svg>\n          {{ data.bytes_received | bytes:\"1.0-0\" }}\n        </span>\n      </div>\n    </ng-template>\n  </div>\n</ng-template>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/network-scout/network-scout.scss",
    "content": ":host {\n  @apply w-full p-2 flex flex-col gap-2;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/network-scout/network-scout.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, OnInit, TrackByFunction, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { BoolSetting, Condition, ConfigService, ExpertiseLevel, IProfileStats, Netquery, Pin, SPNService } from \"@safing/portmaster-api\";\nimport { Subject, combineLatest, debounceTime, filter, finalize, interval, retry, startWith, switchMap, take, takeUntil } from \"rxjs\";\nimport { UIStateService } from \"src/app/services\";\nimport { fadeInListAnimation } from \"../animations\";\nimport { ExpertiseService } from './../expertise/expertise.service';\n\ninterface _Pin extends Pin {\n  count: number;\n}\n\ninterface _Profile extends IProfileStats {\n  exitPins: _Pin[];\n  showMore: boolean;\n  expanded: boolean;\n}\n\nexport enum SortTypes {\n  static = 'Static',\n  aToZ = \"A-Z\",\n  zToA = \"Z-A\",\n  totalConnections = \"Total Connections\",\n  connectionsDenied = \"Denied Connections\",\n  connectionsAllowed = \"Allowed Connections\",\n  spnIdentities = \"SPN Identities\",\n  bytesSent = \"Bytes Sent\",\n  bytesReceived = \"Bytes Received\",\n  totalBytes = \"Total Bytes\"\n}\n\nconst bandwidthSorts: SortTypes[] = [\n  SortTypes.bytesReceived,\n  SortTypes.bytesSent,\n  SortTypes.totalBytes\n]\n\n@Component({\n  selector: 'app-network-scout',\n  templateUrl: './network-scout.html',\n  styleUrls: ['./network-scout.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInListAnimation,\n  ]\n})\nexport class NetworkScoutComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  sortTypes = [\n    SortTypes.static,\n    SortTypes.aToZ,\n    SortTypes.zToA,\n    SortTypes.totalConnections,\n    SortTypes.connectionsDenied,\n    SortTypes.connectionsAllowed,\n    SortTypes.spnIdentities\n  ]\n\n  readonly sortMethods = new Map<SortTypes, any>([\n    // there's not entry for \"Static\" here on purpose because we'll use the sort order\n    // returned by netquery.\n    [SortTypes.aToZ, (a: _Profile, b: _Profile) => a.Name.localeCompare(b.Name)],\n    [SortTypes.zToA, (a: _Profile, b: _Profile) => b.Name.localeCompare(a.Name)],\n    [SortTypes.totalConnections, (a: _Profile, b: _Profile) => (b.countAllowed + b.countUnpermitted) - (a.countAllowed + a.countUnpermitted)],\n    [SortTypes.connectionsAllowed, (a: _Profile, b: _Profile) => b.countAllowed - a.countAllowed],\n    [SortTypes.connectionsDenied, (a: _Profile, b: _Profile) => b.countUnpermitted - a.countUnpermitted],\n    [SortTypes.spnIdentities, (a: _Profile, b: _Profile) => a.identities.length - b.identities.length],\n    [SortTypes.bytesReceived, (a: _Profile, b: _Profile) => b.bytes_received - a.bytes_received],\n    [SortTypes.bytesSent, (a: _Profile, b: _Profile) => b.bytes_sent - a.bytes_sent],\n    [SortTypes.totalBytes, (a: _Profile, b: _Profile) => (b.bytes_received + b.bytes_sent) - (a.bytes_received + a.bytes_sent)]\n  ]);\n\n  /** The current sort order */\n  sortOrder: SortTypes = SortTypes.static;\n\n  get isByteSortOrder() {\n    return bandwidthSorts.includes(this.sortOrder);\n  }\n\n  /** Used to trigger a debounced search from the template */\n  triggerSearch = new Subject<string>();\n\n  /** The current search term as entered in the input[type=\"text\"] */\n  searchTerm: string = '';\n\n  /** A list of all active profiles without any search applied */\n  allProfiles: _Profile[] = [];\n\n  /** Defines if new elements should be expanded or collapsed */\n  expandCollapseState: 'expand' | 'collapse' = 'expand';\n\n  /** Whether or not the SPN is enabled */\n  spnEnabled = false;\n\n  /**\n   * Emits when the user clicks the \"expand all\" or \"collapse all\" buttons.\n   * Once the user did that we stop updating the default state depending on whether the\n   * SPN is enabled or not.\n   */\n  private userChangedState = new Subject<void>();\n\n  /**\n   * A list of profiles that are currently displayed. This is basically allProfiles but with\n   * text search applied.\n   */\n  profiles: _Profile[] = [];\n\n  /** TrackByFunction for the profiles. */\n  trackProfile: TrackByFunction<_Profile> = (_, profile) => profile.ID;\n\n  /** TrackByFunction for the exit pins */\n  trackPin: TrackByFunction<_Pin> = (_, pin) => pin.ID;\n\n  constructor(\n    private netquery: Netquery,\n    private spn: SPNService,\n    private configService: ConfigService,\n    private stateService: UIStateService,\n    private expertise: ExpertiseService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  searchProfiles(term: string) {\n    term = term.trim();\n\n    if (term === '') {\n      this.profiles = [\n        ...this.allProfiles\n      ];\n\n      this.sortProfiles(this.profiles);\n\n      return;\n    }\n\n    const lowerCaseTerm = term.toLocaleLowerCase()\n    this.profiles = this.allProfiles.filter(p => {\n      if (p.ID.toLocaleLowerCase().includes(lowerCaseTerm)) {\n        return true;\n      }\n\n      if (p.Name.toLocaleLowerCase().includes(lowerCaseTerm)) {\n        return true;\n      }\n\n      if (p.exitPins.some(pin => pin.Name.toLocaleLowerCase().includes(lowerCaseTerm))) {\n        return true;\n      }\n\n      return false;\n    })\n\n    this.sortProfiles(this.profiles);\n  }\n\n  sortProfiles(profiles: _Profile[]) {\n    const method = this.sortMethods.get(this.sortOrder);\n    if (!method) {\n      return;\n    }\n\n    profiles.sort(method)\n\n    this.cdr.markForCheck();\n  }\n\n  updateSortOrder(newOrder: SortTypes) {\n    this.sortOrder = newOrder;\n    this.searchProfiles(this.searchTerm);\n\n    this.stateService.set('netscoutSortOrder', newOrder)\n      .subscribe({\n        error: err => {\n          console.error(err);\n        }\n      })\n  }\n\n  expandAll() {\n    this.expandCollapseState = 'expand';\n    this.allProfiles.forEach(profile => profile.expanded = profile.identities.length > 0)\n    this.searchProfiles(this.searchTerm)\n    this.userChangedState.next();\n\n    this.cdr.markForCheck()\n  }\n\n  collapseAll() {\n    this.expandCollapseState = 'collapse';\n    this.allProfiles.forEach(profile => profile.expanded = false)\n    this.searchProfiles(this.searchTerm)\n    this.userChangedState.next();\n\n    this.cdr.markForCheck()\n  }\n\n  ngOnInit(): void {\n    this.stateService.uiState()\n      .pipe(take(1))\n      .subscribe(state => {\n        this.sortOrder = state.netscoutSortOrder;\n\n        this.searchProfiles(this.searchTerm);\n      })\n\n    this.configService.watch<BoolSetting>('spn/enable')\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        takeUntil(this.userChangedState),\n      )\n      .subscribe(enabled => {\n        // if the SPN is enabled and the user did not yet change the\n        // collapse/expand state we switch to \"expand\" for the default.\n        // Otherwise, there will be no identities so there's no reason\n        // to expand them at all so we switch to collapse\n        if (enabled) {\n          this.expandCollapseState = 'expand'\n        } else {\n          this.expandCollapseState = 'collapse'\n        }\n\n        this.spnEnabled = enabled;\n      });\n\n    let updateInProgress = false;\n\n    combineLatest([\n      combineLatest([\n        interval(5000)\n          .pipe(\n            filter(() => !updateInProgress)\n          ),\n        this.expertise.change,\n      ])\n        .pipe(\n          startWith(-1),\n          switchMap(() => {\n            let query: Condition = {};\n            if (this.expertise.currentLevel !== ExpertiseLevel.Developer) {\n              query[\"internal\"] = { $eq: false }\n            }\n\n            updateInProgress = true\n\n            return this.netquery.getProfileStats(query)\n              .pipe(\n                finalize(() => updateInProgress = false)\n              )\n          }),\n          retry({ delay: 5000 })\n        ),\n\n      this.spn.watchPins()\n        .pipe(\n          debounceTime(100),\n          startWith([]),\n        ),\n\n      this.triggerSearch\n        .pipe(\n          debounceTime(100),\n          startWith(''),\n        ),\n    ])\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n      )\n      .subscribe(([res, pins, searchTerm]) => {\n        // create a lookup map for the the SPN map pins\n        const pinLookupMap = new Map<string, Pin>();\n        pins.forEach(p => pinLookupMap.set(p.ID, p))\n\n        // create a lookup map from already known profiles so we can\n        // inherit states like \"showMore\".\n        const profileLookupMap = new Map<string, _Profile>();\n        this.allProfiles.forEach(p => profileLookupMap.set(p.ID, p))\n\n        // map the list of profile statistics to include the exit Pin information\n        // as well.\n        this.allProfiles = res.map(s => {\n          const existing = profileLookupMap.get(s.ID);\n          return {\n            ...s,\n            exitPins: s.identities\n              .map(ident => {\n                const pin = pinLookupMap.get(ident.exit_node);\n                if (!pin) {\n                  return null;\n                }\n\n                return {\n                  count: ident.count,\n                  ...pin\n                }\n              })\n              .filter(pin => !!pin),\n            showMore: existing?.showMore ?? false,\n            expanded: existing?.expanded ?? (this.expandCollapseState === 'expand' && s.identities.length > 1 /* there's always the \"direct\" identity */),\n          } as _Profile\n        });\n\n        this.searchProfiles(searchTerm);\n\n        // check if we have profiles with bandwidth data and\n        // make sure our sort methods are updated.\n        if (this.profiles.some(p => p.bytes_received > 0 || p.bytes_sent > 0)) {\n          if (!this.sortTypes.includes(SortTypes.bytesReceived)) {\n            this.sortTypes.push.apply(this.sortTypes, bandwidthSorts)\n          }\n\n          this.sortTypes = [...this.sortTypes];\n        } else {\n          this.sortTypes = this.sortTypes.filter(type => {\n            return !bandwidthSorts.includes(type)\n          })\n        }\n\n        this.cdr.markForCheck();\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/notification/notification.html",
    "content": "<div class=\"flex flex-col items-start\">\n  <caption *ngIf=\"!notification.isBroadcast\">Notification</caption>\n\n  <caption *ngIf=\"notification.isBroadcast\" sfngTipUpAnchor class=\"flex flex-row gap-2 items-center\">\n    Broadcast Notification\n    <sfng-tipup key=\"broadcast-info\"></sfng-tipup>\n  </caption>\n\n  <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"w-4 h-4 close-icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"\n    (click)=\"ref.close()\">\n    <path fill-rule=\"evenodd\"\n      d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n      clip-rule=\"evenodd\" />\n  </svg>\n\n  <h1>{{notification.Title}}</h1>\n\n  <markdown emoji [data]=\"notification.Message\" class=\"message\"></markdown>\n\n  <div class=\"buttons\">\n    <button *ngFor=\"let action of notification!.AvailableActions\"\n      [class.selected]=\"action.ID === notification!.SelectedActionID\" [disabled]=\"state === 'invalid'\"\n      (click)=\"execute(notification!, action)\">\n      {{action.Text}}\n    </button>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/notification/notification.scss",
    "content": ":host {\n  @apply block;\n  max-width: 24rem;\n}\n\ncaption {\n  @apply text-xxs;\n  opacity: .6;\n}\n\nh1 {\n  @apply text-base font-normal my-4;\n}\n\n.message,\nh1 {\n  flex-shrink: 0;\n  text-overflow: ellipsis;\n  word-break: normal;\n}\n\n.message {\n  flex-grow: 1;\n  padding: 0;\n}\n\n.close-icon {\n  position: absolute;\n  top: 1rem;\n  right: 1rem;\n  opacity: .7;\n  cursor: pointer;\n\n  &:hover {\n    opacity: 1;\n  }\n}\n\n.buttons {\n  width: 100%;\n  display: flex;\n\n  @apply flex flex-row justify-end gap-2;\n}\n\na {\n  text-decoration: underline;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/notification/notification.ts",
    "content": "import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, OnInit, Output, inject } from '@angular/core';\nimport { SFNG_DIALOG_REF } from '@safing/ui';\nimport { Action, NotificationState, NotificationsService, getNotificationTypeString } from '../../services';\nimport { _Notification } from '../notification-list/notification-list.component';\n\n@Component({\n  selector: 'app-notification',\n  templateUrl: './notification.html',\n  styleUrls: ['./notification.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class NotificationComponent implements OnInit {\n  readonly ref = inject(SFNG_DIALOG_REF);\n  readonly notification: _Notification<any> = inject(SFNG_DIALOG_REF).data;\n\n  /**\n   * The host tag of the notification component has the notification type\n   * and the notification state as a class name set.\n   * Examples:\n   *\n   *    notif-action-required notif-prompt\n   */\n  @HostBinding('class')\n  get hostClass(): string {\n    let cls = `notif-${this.state}`;\n    if (!!this.notification) {\n      cls = `${cls} notif-${getNotificationTypeString(this.notification.Type)}`\n    }\n    return cls\n  }\n\n  state: NotificationState = NotificationState.Invalid;\n\n  ngOnInit() {\n    if (!!this.notification) {\n      this.state = this.notification.State || NotificationState.Invalid;\n    } else {\n      this.state = NotificationState.Invalid;\n    }\n  }\n\n  @Input()\n  set allowMarkdown(v: any) {\n    this._markdown = coerceBooleanProperty(v);\n  }\n  get allowMarkdown() { return this._markdown; }\n  private _markdown: boolean = true;\n\n  @Output()\n  actionExecuted: EventEmitter<Action> = new EventEmitter();\n\n  constructor(private notifService: NotificationsService) { }\n\n  execute(n: _Notification<any>, action: Action) {\n    this.notifService.execute(n, action)\n      .subscribe(\n        () => {\n          this.actionExecuted.next(action)\n          this.ref.close();\n        },\n        err => console.error(err),\n      )\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/notification-list/index.ts",
    "content": "export { NotificationListComponent as NotificationWidgetComponent, NotificationWidgetConfig } from './notification-list.component';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/notification-list/notification-list.component.html",
    "content": "<caption class=\"text-xs text-secondary\" *ngIf=\"!!notifications.length\">Notifications</caption>\n\n<div class=\"flex flex-col w-full gap-2\">\n  <div class=\"row\" (click)=\"toggelView(notif)\" *ngFor=\"let notif of notifications; trackBy: trackBy\">\n    <div class=\"type\" [class.info]=\"notif.Type === types.Info\" [class.warning]=\"notif.Type === types.Warning\"\n      [class.error]=\"notif.Type === types.Error\" [class.broadcast]=\"notif.isBroadcast\">\n      <svg *ngIf=\"notif.isBroadcast\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\"\n        viewBox=\"0 0 16 16\">\n        <path\n          d=\"M13 2.5a1.5 1.5 0 0 1 3 0v11a1.5 1.5 0 0 1-3 0v-11zm-1 .724c-2.067.95-4.539 1.481-7 1.656v6.237a25.222 25.222 0 0 1 1.088.085c2.053.204 4.038.668 5.912 1.56V3.224zm-8 7.841V4.934c-.68.027-1.399.043-2.008.053A2.02 2.02 0 0 0 0 7v2c0 1.106.896 1.996 1.994 2.009a68.14 68.14 0 0 1 .496.008 64 64 0 0 1 1.51.048zm1.39 1.081c.285.021.569.047.85.078l.253 1.69a1 1 0 0 1-.983 1.187h-.548a1 1 0 0 1-.916-.599l-1.314-2.48a65.81 65.81 0 0 1 1.692.064c.327.017.65.037.966.06z\" />\n      </svg>\n    </div>\n    <div class=\"preview\">\n      <span>\n        {{notif.Title || notif.Message}}\n      </span>\n      <div class=\"buttons\">\n        <ng-container *ngFor=\"let action of notif!.AvailableActions\">\n          <button *ngIf=\"!action.Visibility || action.Visibility === 'in-app-only'\" (click)=\"execute(notif!, action, $event)\">\n            {{action.Text}}\n          </button>\n        </ng-container>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/notification-list/notification-list.component.scss",
    "content": ":host {\n  @apply flex flex-col justify-start items-center gap-2;\n  @apply w-full px-2;\n\n  @apply border-b border-gray-400 pb-2;\n\n  &>* {\n    /* do not allow to shrink  */\n    flex-shrink: 0;\n  }\n}\n\n.row,\ndiv.placeholder {\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  margin: 0;\n  border: none;\n}\n\n.row {\n  @apply overflow-hidden w-full flex flex-row rounded;\n  @apply h-8;\n\n  .type {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    width: .5rem;\n    flex-shrink: 0;\n    flex-grow: 0;\n    background-color: #202020;\n\n    &.info {\n      background-color: #727272;\n    }\n\n    &.warning {\n      background-color: theme(\"colors.info.yellow\");\n    }\n\n    &.error {\n      background-color: theme(\"colors.info.red\");\n    }\n\n    &.broadcast {\n      width: 2rem;\n      color: #00000080;\n    }\n  }\n\n  .preview {\n    background-color: #292929;\n    cursor: pointer;\n    overflow: hidden;\n    flex-grow: 1;\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding-left: 1rem;\n    border-top-left-radius: 2px;\n    border-bottom-left-radius: 2px;\n    position: relative;\n\n    span {\n      flex-grow: 1;\n      text-overflow: ellipsis;\n      overflow: hidden;\n      word-wrap: none;\n      white-space: nowrap;\n\n      font-size: 0.7rem;\n      font-weight: 500;\n\n      color: #cacaca;\n\n      .category {\n        padding-left: 8px;\n        font-size: 0.65rem;\n        font-weight: 700;\n        text-transform: capitalize;\n        color: #999999c9;\n      }\n    }\n\n    &:hover {\n      background-color: #303030;\n\n      .buttons {\n        opacity: 1;\n        transition: all .05s ease-in-out;\n        transform: translateX(-100%);\n      }\n    }\n\n    .buttons {\n      opacity: 0;\n      transition: all .05s ease-in-out;\n      height: 100%;\n      position: absolute;\n      left: 100%;\n      display: flex;\n      white-space: nowrap;\n      background-color: #303030;\n\n      button {\n        outline: none;\n        @apply bg-transparent;\n        font-size: 0.6rem;\n        background-color: #3a3a3a;\n        padding-left: 1.25rem;\n        padding-right: 1.25rem;\n        text-transform: capitalize;\n        border-radius: 0;\n        font-weight: 500;\n        outline: none;\n        color: hsla(0, 0%, 100%, 0.548);\n        height: 100%;\n\n        &:hover {\n          background-color: #363636;\n          color: #ffffff;\n        }\n\n        &:first-of-type {\n          margin-left: .5rem;\n        }\n\n        &:last-of-type {\n          background: transparent;\n          color: hsla(0, 0%, 100%, 0.562);\n          @apply ml-1;\n          transition: all cubic-bezier(0.175, 0.885, 0.32, 1.275) .2s;\n\n          &:hover {\n            color: #ffffff;\n          }\n        }\n      }\n    }\n  }\n}\n\n/*\n.notification-body {\n  @apply bg-cards-tertiary;\n  flex-grow: 1;\n  @apply rounded-b;\n  position: absolute;\n  top: var(--slot-size);\n  bottom: 0;\n\n  .broadcast-info {\n    background-color: #00000040;\n    width: 100%;\n    padding: 0.5rem;\n    color: white !important;\n    font-weight: 400;\n    bottom: 0;\n    position: absolute;\n    flex-grow: 1;\n    @apply flex items-center justify-center gap-1;\n  }\n}\n*/\n\ndiv.placeholder {\n  @apply font-medium;\n  @apply text-tertiary;\n  @apply flex-grow;\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  user-select: none;\n}\n\napp-loading {\n  opacity: .5;\n  margin-left: auto;\n  margin-right: auto;\n  position: relative;\n  top: 5px;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/notification-list/notification-list.component.ts",
    "content": "import { animate, style, transition, trigger } from '@angular/animations';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, OnDestroy, OnInit, TrackByFunction, inject } from '@angular/core';\nimport { SfngDialogService } from '@safing/ui';\nimport { Subscription } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { Action, Notification, NotificationType, NotificationsService } from 'src/app/services';\nimport { moveInOutAnimation, moveInOutListAnimation } from 'src/app/shared/animations';\nimport { NotificationComponent } from '../notification/notification';\n\nexport interface NotificationWidgetConfig {\n  markdown: boolean;\n}\n\nexport interface _Notification<T = any> extends Notification<T> {\n  isBroadcast: boolean\n}\n\n@Component({\n  selector: 'app-notification-list',\n  templateUrl: './notification-list.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styleUrls: [\n    './notification-list.component.scss'\n  ],\n  animations: [\n    trigger(\n      'fadeIn',\n      [\n        transition(\n          ':enter',\n          [\n            style({ opacity: 0 }),\n            animate('.2s .2s ease-in',\n              style({ opacity: 1 }))\n          ]\n        ),\n      ]\n    ),\n    moveInOutAnimation,\n    moveInOutListAnimation\n  ]\n})\nexport class NotificationListComponent implements OnInit, OnDestroy {\n  readonly types = NotificationType;\n  readonly dialog = inject(SfngDialogService);\n  readonly cdr = inject(ChangeDetectorRef);\n\n  /** Used to set a fixed height when a notification is expanded. */\n  @HostBinding('style.height')\n  height: null | string = null;\n\n  /** Sets the overflow to hidden when a notification is expanded. */\n  @HostBinding('style.overflow')\n  get overflow() {\n    if (this.height === null) {\n      return null;\n    }\n    return 'hidden';\n  }\n\n  @HostBinding('class.empty')\n  get isEmpty() {\n    return this.notifications.length === 0;\n  }\n\n  @HostBinding('@moveInOutList')\n  get length() { return this.notifications.length }\n\n  /** Subscription to notification updates. */\n  private notifSub = Subscription.EMPTY;\n\n  /** All active notifications. */\n  notifications: _Notification<any>[] = [];\n\n  trackBy: TrackByFunction<_Notification> = this.notifsService.trackBy;\n\n  constructor(\n    public elementRef: ElementRef,\n    public notifsService: NotificationsService,\n  ) { }\n\n  ngOnInit(): void {\n    this.notifSub = this.notifsService\n      .new$\n      .pipe(\n        // filter out any prompts as they are handled by a different widget.\n        map(notifs => {\n          return notifs.filter(notif => !notif.SelectedActionID && !(notif.Type === NotificationType.Prompt && notif.EventID.startsWith(\"filter:prompt\")))\n        })\n      )\n      .subscribe(list => {\n        this.notifications = list.map(notification => {\n          return {\n            ...notification,\n            isBroadcast: notification.EventID.startsWith(\"broadcasts:\"),\n          }\n        });\n\n        this.cdr.markForCheck();\n      });\n  }\n\n  ngOnDestroy() {\n    this.notifSub.unsubscribe();\n  }\n\n  /**\n   * @private\n   *\n   * Executes a notification action and updates the \"expanded-notification\"\n   * view if required.\n   *\n   * @param n  The notification object.\n   * @param actionId  The ID of the action to execute.\n   * @param event The mouse click event.\n   */\n  execute(n: _Notification<any>, action: Action, event: MouseEvent) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.notifsService.execute(n, action)\n      .subscribe()\n  }\n\n  /**\n   * @private\n   * Toggles between list mode and notification-view mode.\n   *\n   * @param notif The notification that has been clicked.\n   */\n  toggelView(notif: _Notification<any>) {\n    const ref = this.dialog.create(NotificationComponent, {\n      backdrop: 'light',\n      autoclose: true,\n      data: notif,\n    });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/bytes.pipe.ts",
    "content": "import { DecimalPipe } from \"@angular/common\";\nimport { Pipe, PipeTransform } from \"@angular/core\";\n\n@Pipe({\n  pure: true,\n  name: 'bytes',\n})\nexport class BytesPipe implements PipeTransform {\n  transform(value: any, decimal: string = '1.0-2', ...args: any[]) {\n    value = +value; // convert to number\n\n    const ceilings = [\n      'B',\n      'kB',\n      'MB',\n      'GB',\n      'TB'\n    ]\n\n    let idx = 0;\n    while (value > 1024 && idx < ceilings.length - 1) {\n      value = value / 1024;\n      idx++\n    }\n\n    return (new DecimalPipe('en-US')).transform(value, decimal) + ' ' + ceilings[idx];\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/common-pipes.module.ts",
    "content": "import { NgModule } from \"@angular/core\";\nimport { BytesPipe } from \"./bytes.pipe\";\nimport { TimeAgoPipe } from \"./time-ago.pipe\";\nimport { ToAppProfilePipe } from \"./to-profile.pipe\";\nimport { DurationPipe } from \"./duration.pipe\";\nimport { RoundPipe } from \"./round.pipe\";\nimport { ToSecondsPipe } from \"./to-seconds.pipe\";\n\n@NgModule({\n  declarations: [\n    TimeAgoPipe,\n    BytesPipe,\n    ToAppProfilePipe,\n    DurationPipe,\n    RoundPipe,\n    ToSecondsPipe\n  ],\n  exports: [\n    TimeAgoPipe,\n    BytesPipe,\n    ToAppProfilePipe,\n    DurationPipe,\n    RoundPipe,\n    ToSecondsPipe\n  ]\n})\nexport class CommonPipesModule { }\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/duration.pipe.ts",
    "content": "import { Pipe, PipeTransform } from \"@angular/core\";\n\nconst millisecond = 1;\nconst second = 1000 * millisecond;\nconst minute = 60 * second;\nconst hour = 60 * minute;\nconst day = 24 * hour;\n\nexport function formatDuration(millis: number, skipDays = false, skipMillis = false): string {\n  const sign = millis < 0 ? '-' : '';\n  let val = Math.abs(millis);\n  let str = '';\n\n  if (millis === 0) {\n    return '0';\n  }\n\n  if (!skipDays) {\n    const days = Math.floor(val / day)\n    if (days > 0) {\n      str += days.toString() + 'd ';\n      val -= days * day;\n    }\n  }\n\n  const hours = Math.floor(val / hour);\n  if (hours > 0) {\n    str += hours.toString() + 'h ';\n    val -= hours * hour;\n  }\n\n  const minutes = Math.floor(val / minute);\n  if (minutes > 0) {\n    str += minutes.toString() + 'm ';\n    val -= minutes * minute;\n  }\n\n  const seconds = Math.floor(val / second);\n  if (seconds > 0) {\n    str += seconds.toString() + 's ';\n    val -= seconds * second;\n  }\n\n  if (!skipMillis) {\n    const ms = Math.floor(val / millisecond)\n    if (ms > 0) {\n      str += ms.toString() + 'ms '\n      val -= ms * millisecond\n    }\n  }\n\n  if (str.endsWith(\"\")) {\n    str = str.substring(0, str.length - 1)\n  }\n\n  return sign + str;\n}\n\n@Pipe({\n  name: 'duration',\n  pure: true\n})\nexport class DurationPipe implements PipeTransform {\n  transform(value: number | [string, string] | [Date, Date] | [number, number], ...args: any[]) {\n    if (Array.isArray(value)) {\n      let firstNum: number;\n      let secondNum: number;\n\n      let [first, second] = value;\n      if (first instanceof Date || typeof first === 'string') {\n        first = new Date(first)\n        firstNum = first.getTime()\n      } else {\n        firstNum = first\n      }\n      if (second instanceof Date || typeof second === 'string') {\n        second = new Date(second);\n        secondNum = second.getTime()\n      } else {\n        secondNum = second\n      }\n\n      if (secondNum < firstNum) {\n        const t = firstNum;\n        firstNum = secondNum\n        secondNum = t\n      }\n\n      value = secondNum - firstNum\n    }\n\n    if (value < second) {\n\n    }\n\n    const result = formatDuration(value);\n    if (result === '0') {\n      return '< 1s'\n    }\n\n    return result\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/index.ts",
    "content": "export * from './common-pipes.module';\nexport * from './time-ago.pipe';\nexport * from './to-profile.pipe';\nexport * from './duration.pipe';\nexport * from './to-seconds.pipe';\nexport * from './round.pipe';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/round.pipe.ts",
    "content": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n  name: 'round',\n  pure: true,\n})\nexport class RoundPipe implements PipeTransform {\n  transform(value: number, roundBy: number) {\n    if (isNaN(value)) {\n      return NaN\n    }\n\n    return Math.floor(value / roundBy) * roundBy\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/time-ago.pipe.ts",
    "content": "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n  name: 'timeAgo',\n  pure: true\n})\nexport class TimeAgoPipe implements PipeTransform {\n  transform(value: number | Date | string, ticker?: any): string {\n    return timeAgo(value);\n  }\n}\n\nexport const timeCeilings = [\n  { ceiling: 1, text: \"\" },\n  { ceiling: 60, text: \"sec\" },\n  { ceiling: 3600, text: \"min\" },\n  { ceiling: 86400, text: \"hour\" },\n  { ceiling: 2629744, text: \"day\" },\n  { ceiling: 31556926, text: \"month\" },\n  { ceiling: Infinity, text: \"year\" }\n]\n\nexport function timeAgo(value: number | Date | string) {\n  if (typeof value === 'string') {\n    value = new Date(value)\n  }\n\n  if (value instanceof Date) {\n    value = value.valueOf() / 1000;\n  }\n\n  let suffix = 'ago'\n\n  let diffInSeconds = Math.floor(((new Date()).valueOf() - (value * 1000)) / 1000);\n  if (diffInSeconds < 0) {\n    diffInSeconds = diffInSeconds * -1;\n    suffix = ''\n  }\n\n  for (let i = timeCeilings.length - 1; i >= 0; i--) {\n    const f = timeCeilings[i];\n    let n = Math.floor(diffInSeconds / f.ceiling);\n    if (n > 0) {\n      if (i < 1) {\n        return `< 1 min ` + suffix;\n      }\n      let text = timeCeilings[i + 1].text;\n      if (n > 1) {\n        text += 's';\n      }\n      return `${n} ${text} ` + suffix\n    }\n  }\n\n  return \"< 1 min \" + suffix // actually just now (diffInSeconds == 0)\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/to-profile.pipe.ts",
    "content": "import { ChangeDetectorRef, OnDestroy, Pipe, PipeTransform, inject } from \"@angular/core\";\nimport { AppProfile, AppProfileService } from \"@safing/portmaster-api\";\nimport { Subscription } from \"rxjs\";\n\n@Pipe({\n  name: 'toAppProfile',\n  pure: false\n})\nexport class ToAppProfilePipe implements PipeTransform, OnDestroy {\n  profileService = inject(AppProfileService);\n  cdr = inject(ChangeDetectorRef);\n\n  private _lastProfile: AppProfile | null = null;\n  private _lastKey: string | null = null;\n  private _subscription = Subscription.EMPTY;\n\n  transform(key: string): AppProfile | null {\n    if (key !== this._lastKey) {\n      this._lastKey = key;\n\n      this._subscription.unsubscribe();\n      this._subscription = this.profileService.watchAppProfile(key)\n        .subscribe(value => {\n          this._lastProfile = value;\n          this.cdr.markForCheck();\n        })\n    }\n\n    return this._lastProfile || null;\n  }\n\n  ngOnDestroy(): void {\n    this._subscription.unsubscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/pipes/to-seconds.pipe.ts",
    "content": "import { Pipe, PipeTransform } from \"@angular/core\";\n\n@Pipe({\n  name: 'toSeconds',\n  pure: true,\n})\nexport class ToSecondsPipe implements PipeTransform {\n  transform(value: Date | string, ...args: any[]) {\n    if (value === null || value === undefined) {\n      return NaN\n    }\n\n    if (typeof value === 'string') {\n      value = new Date(value);\n    }\n\n    return Math.floor(value.getTime() / 1000)\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/process-details-dialog/index.ts",
    "content": "export * from './process-details-dialog';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/process-details-dialog/process-details-dialog.html",
    "content": "<h1 class=\"flex flex-row items-center gap-2\">\n  Process Details\n</h1>\n\n<sfng-tab-group linkRouter=\"false\" class=\"flex-grow\">\n  <sfng-tab title=\"General\">\n    <div *sfngTabContent>\n      <table class=\"custom\">\n        <tbody>\n          <tr>\n            <th>Name</th>\n            <td>\n              <div class=\"flex flex-row items-center gap-1\">\n                <app-icon [profile]=\"process\"></app-icon>\n                {{ process.Name }}\n              </div>\n            </td>\n            <td></td>\n          </tr>\n          <tr>\n            <th>User</th>\n            <td>{{ process.UserName }} <span class=\"text-tertiary\" *appExpertiseLevel=\"'expert'\">({{ process.UserID\n                }})</span></td>\n            <td></td>\n          </tr>\n          <tr *appExpertiseLevel=\"'expert'\">\n            <th>Process ID</th>\n            <td>{{ process.Pid }}</td>\n            <td></td>\n          </tr>\n\n          <tr *appExpertiseLevel=\"'expert'\">\n            <th>Process Group ID</th>\n            <td (click)=\"openGroup()\">{{ process.Pgid }}</td>\n            <td></td>\n          </tr>\n\n          <tr *appExpertiseLevel=\"'expert'\">\n            <th>Parent Process ID</th>\n            <td (click)=\"openParent()\">{{ process.ParentPid }}</td>\n            <td></td>\n          </tr>\n          <tr>\n            <th>Path</th>\n            <td>{{ process.Path }} <span *ngIf=\"process.MatchingPath\" class=\"text-tertiary\">({{ process.MatchingPath\n                }})</span></td>\n            <td>\n              <button (click)=\"createProfileForPath()\"\n                sfng-tooltip=\"Create a new profile for all processes with this path\">\n                <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n                  stroke=\"currentColor\" class=\"w-4 h-4\">\n                  <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                    d=\"M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z\" />\n                </svg>\n              </button>\n            </td>\n          </tr>\n          <tr>\n            <th>Executable Name</th>\n            <td>{{ process.ExecName }}</td>\n            <td></td>\n          </tr>\n          <tr>\n            <th>Command Line</th>\n            <td>{{ process.CmdLine }}</td>\n            <td>\n              <button (click)=\"createProfileForCmdline()\"\n                sfng-tooltip=\"Create a new profile for all processes with this command line\">\n                <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n                  stroke=\"currentColor\" class=\"w-4 h-4\">\n                  <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                    d=\"M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z\" />\n                </svg>\n              </button>\n            </td>\n          </tr>\n          <tr>\n            <th>\n              <div class=\"flex flex-row items-center gap-2\">\n                Tags\n                <sfng-tipup key=\"process-tags\"></sfng-tipup>\n              </div>\n            </th>\n            <td>\n              <span *ngIf=\"!process.Tags?.length\">This process does not have any tags.</span>\n              <ul>\n                <li *ngFor=\"let tag of process.Tags\"\n                  class=\"flex flex-row bg-gray-100 border border-gray-500 rounded-sm text-xxs w-fit\">\n                  <span class=\"block px-2 py-1 bg-gray-200 border-r border-gray-500 text-secondary\">{{ tag.Key }}</span>\n                  <span class=\"block px-2 py-1\">{{ tag.Value }}</span>\n                </li>\n              </ul>\n            </td>\n            <td></td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  </sfng-tab>\n\n  <sfng-tab title=\"Environment\">\n    <div *sfngTabContent>\n      <div *ngIf=\"!(process.Env | keyvalue)?.length\" class=\"p-2 text-xs text-center\">\n        <span class=\"text-secondary\">This process does not have any environment variables.</span>\n      </div>\n\n      <table class=\"custom\">\n        <tbody>\n          <tr *ngFor=\"let env of (process.Env | keyvalue)\">\n            <th>{{ env.key }}</th>\n            <td>{{ env.value }}</td>\n            <td class=\"w-8\">\n              <button (click)=\"createProfileForEnv(env)\"\n                sfng-tooltip=\"Create a new profile for all processes with this environment variable\">\n                <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n                  stroke=\"currentColor\" class=\"w-4 h-4\">\n                  <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n                    d=\"M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z\" />\n                </svg>\n              </button>\n            </td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  </sfng-tab>\n</sfng-tab-group>\n\n<div class=\"flex flex-row justify-end gap-2\">\n  <button (click)=\"close()\">Close</button>\n</div>"
  },
  {
    "path": "desktop/angular/src/app/shared/process-details-dialog/process-details-dialog.scss",
    "content": ":host {\n  @apply flex flex-col gap-4 max-w-2xl;\n  min-width: 500px;\n  width: 60vw;\n\n  min-height: 500px;\n  height: 60vh;\n  max-height: 80vh;\n  overflow: hidden;\n}\n\ntable.custom {\n  @apply w-full overflow-hidden;\n\n  th,\n  td {\n    @apply px-2 align-top py-2;\n  }\n\n  th {\n    text-align: left;\n    @apply w-32 text-secondary;\n  }\n\n  td {\n    @apply whitespace-normal break-all;\n  }\n\n  td:last-of-type {\n    @apply p-0;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/process-details-dialog/process-details-dialog.ts",
    "content": "import { KeyValue } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Inject } from '@angular/core';\nimport { AppProfile, AppProfileService, FingerpringOperation, Fingerprint, FingerprintType, PortapiService, Process } from '@safing/portmaster-api';\nimport { SfngDialogRef, SfngDialogService, SFNG_DIALOG_REF } from '@safing/ui';\nimport { EditProfileDialog } from '../edit-profile-dialog';\n\n@Component({\n  selector: 'app-process-details',\n  templateUrl: './process-details-dialog.html',\n  styleUrls: ['./process-details-dialog.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ProcessDetailsDialogComponent {\n  process: (Process & { ID: string });\n\n  constructor(\n    @Inject(SFNG_DIALOG_REF) private dialogRef: SfngDialogRef<any, any, Process>,\n    private dialog: SfngDialogService,\n    private portapi: PortapiService,\n    private profileService: AppProfileService\n  ) {\n    this.process = {\n      ...this.dialogRef.data,\n      ID: this.dialogRef.data.PrimaryProfileID,\n    }\n  }\n\n  close() {\n    this.dialogRef.close();\n  }\n\n  createProfileForPath() {\n    this.createProfileWithFingerprint({\n      Type: FingerprintType.Path,\n      Key: '',\n      Value: this.process.MatchingPath || this.process.Path,\n      Operation: FingerpringOperation.Equal,\n    })\n  }\n\n  createProfileForCmdline() {\n    this.createProfileWithFingerprint({\n      Type: FingerprintType.Cmdline,\n      Key: '',\n      Value: this.process.CmdLine,\n      Operation: FingerpringOperation.Equal,\n    })\n  }\n\n  createProfileForEnv(env: KeyValue<string, string>) {\n    const fp: Fingerprint = {\n      Type: FingerprintType.Env,\n      Key: env.key,\n      Value: env.value,\n      Operation: FingerpringOperation.Equal,\n    }\n\n    this.createProfileWithFingerprint(fp)\n  }\n\n  openParent() {\n    if (!!this.process.ParentPid) {\n      this.portapi.get<Process>(`network:tree/${this.process.ParentPid}-${this.process.ParentCreatedAt}`)\n        .subscribe(process => {\n          this.process = {\n            ...process,\n            ID: process.PrimaryProfileID,\n          };\n        })\n    }\n  }\n\n  openGroup() {\n    this.profileService.getProcessByPid(this.process.Pid)\n      .subscribe(result => {\n        if (!result) {\n          return;\n        }\n\n        this.process = {\n          ...result,\n          ID: result.PrimaryProfileID\n        };\n      })\n  }\n\n  private createProfileWithFingerprint(fp: Fingerprint) {\n    let profilePreset: Partial<AppProfile> = {\n      Fingerprints: [\n        fp\n      ]\n    };\n\n    this.dialog.create(EditProfileDialog, {\n      data: profilePreset,\n      backdrop: true,\n      autoclose: false,\n    })\n\n    this.dialogRef.close();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/prompt-list/index.ts",
    "content": "export { PromptListComponent as PromptWidgetComponent } from './prompt-list.component';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/prompt-list/prompt-list.component.html",
    "content": "<div class=\"flex flex-col scrollable\" [@moveInOutList]=\"profiles.length\">\n  <div class=\"group\" *ngFor=\"let profile of profiles; trackBy: trackProfile\">\n    <div class=\"group-header\">\n      <app-icon [profile]=\"profile\"></app-icon>\n      <span class=\"app-name\">{{ profile.Name }}</span>\n      <span class=\"prompt-count info-circle\">{{ profile.prompts.length }}</span>\n      <app-menu-trigger [menu]=\"menu\"></app-menu-trigger>\n      <app-menu #menu>\n        <app-menu-group>Per Connection</app-menu-group>\n        <app-menu-item (click)=\"allowAll(profile)\">Allow All</app-menu-item>\n        <app-menu-item (click)=\"denyAll(profile)\">Block All</app-menu-item>\n\n        <app-menu-group>Default Action</app-menu-group>\n        <app-menu-item (click)=\"changeDefault(profile, 'permit')\">Allow App</app-menu-item>\n        <app-menu-item (click)=\"changeDefault(profile, 'block')\">Block App</app-menu-item>\n\n        <app-menu-item class=\"item-seperator\" [routerLink]=\"['/', 'app', profile.Source, profile.ID]\"\n          [queryParams]=\"{setting: 'filter/defaultAction', tab: 'settings'}\">Change Default</app-menu-item>\n\n        <app-menu-item class=\"item-seperator\" [routerLink]=\"['/', 'app', profile.Source, profile.ID]\">\n          App Settings\n        </app-menu-item>\n      </app-menu>\n    </div>\n\n    <div class=\"prompts\">\n      <div class=\"border\"></div>\n      <div class=\"prompt-container\"\n        [@moveInOutList]=\"(profile.showAll ? profile.prompts : profile.promptsLimited).length\">\n        <div class=\"prompt\"\n          *ngFor=\"let prompt of (profile.showAll ? profile.prompts : profile.promptsLimited); trackBy: trackPrompts\">\n          <span class=\"entity\">\n            <ng-container *ngIf=\"!prompt.domain; else: domainView\">\n              {{ prompt.EventData?.Entity?.IP || 'N/A' }}\n            </ng-container>\n            <ng-template #domainView>\n              <span *ngIf=\"!!prompt.subdomain\" class=\"subdomain\">{{prompt.subdomain}}.</span>{{prompt.domain}}\n            </ng-template>\n          </span>\n\n          <span class=\"actions\">\n            <button (click)=\"allow(prompt)\">Allow</button>\n            <button (click)=\"block(prompt)\">Block</button>\n          </span>\n        </div>\n        <div class=\"more-available\" *ngIf=\"!profile.showAll\" (click)=\"profile.showAll = true\">\n          {{ profile.prompts.length - profile.promptsLimited.length }}\n          more\n        </div>\n\n        <div class=\"more-available\" *ngIf=\"profile.showAll && profile.promptsLimited.length < profile.prompts.length\"\n          (click)=\"profile.showAll = false\">\n          Show less\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"no-prompts\" *ngIf=\"profiles.length === 0\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1\" stroke=\"currentColor\"\n      class=\"w-12 h-12\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n    </svg>\n\n    No Prompts\n  </div>\n</div>"
  },
  {
    "path": "desktop/angular/src/app/shared/prompt-list/prompt-list.component.scss",
    "content": ":host {\n  overflow: hidden;\n  max-height: 50vh;\n  display: flex;\n  flex-direction: column;\n  min-height: 10rem;\n  @apply w-80;\n  @apply bg-gray-300;\n\n  padding-top: 1px;\n  padding-bottom: 3px;\n}\n\napp-icon {\n  --app-icon-size: 13px;\n}\n\n.scrollable {\n  @apply p-0;\n}\n\n.group {\n  @apply mb-3;\n\n  .group-header {\n    @apply px-2;\n    display: flex;\n    align-items: center;\n    margin-left: 4px;\n    height: 2rem;\n\n    .app-name {\n      flex-grow: 1;\n      font-size: 0.7rem;\n      font-weight: 500;\n      color: #cacaca;\n    }\n\n    span.prompt-count {\n      @apply mr-1;\n      font-size: 0.6rem;\n      font-weight: 600;\n      color: #cacaca;\n      transform: scale(0.95);\n      user-select: none;\n    }\n  }\n}\n\napp-menu-item.item-seperator {\n  @apply border-t;\n  @apply border-buttons-dark\n}\n\n.no-prompts {\n  @apply text-tertiary flex-grow;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n  user-select: none;\n}\n\n.prompts {\n  display: flex;\n\n  .border {\n    margin-left: calc(0.5rem + 9px);\n    width: 0.5rem;\n    border-left-width: 2px;\n    border-bottom-width: 2px;\n    border-color: #292929;\n  }\n\n  .prompt-container,\n  .prompt,\n  .actions {\n    display: flex;\n  }\n\n  .prompt-container {\n    flex-grow: 1;\n    flex-direction: column;\n    padding-left: 0.6rem;\n    padding-right: 0.5rem;\n    padding-top: 0.4rem;\n    padding-bottom: 1rem;\n\n    .prompt {\n      padding-left: 0.75rem;\n      margin-bottom: 4px;\n      background-color: #292929;\n      height: auto;\n      border-radius: 2px;\n      align-items: center;\n      overflow: hidden;\n      position: relative;\n\n      &:hover {\n        background-color: #303030;\n\n        .actions {\n          animation: .07s slidein-left ease-in-out;\n          opacity: 1;\n          transition: all .05s ease-in-out;\n        }\n      }\n\n      .entity {\n        flex-grow: 1;\n        word-break: break-all;\n        white-space: normal;\n        font-size: 0.7rem;\n        font-weight: 500;\n        padding-top: 0.6rem;\n        padding-bottom: 0.6rem;\n        padding-left: 2px;\n        padding-right: 9px;\n        color: #cacaca;\n\n        .subdomain {\n          font-size: 0.7rem;\n          font-weight: 500;\n          color: #999999;\n        }\n      }\n\n      .actions {\n        min-width: 5rem;\n        flex-wrap: wrap;\n        height: 100%;\n        opacity: 0;\n        transition: all .05s ease-in-out;\n        position: absolute;\n        right: 0;\n        background-color: #292929;\n\n        button {\n          outline: none;\n          @apply bg-transparent;\n          font-size: 0.6rem;\n          background-color: #3a3a3a;\n          padding-left: 1.25rem;\n          padding-right: 1.25rem;\n          text-transform: capitalize;\n          border-radius: 0;\n          font-weight: 500;\n          outline: none;\n          color: hsla(0, 0%, 100%, 0.548);\n\n          padding-left: 1.25rem;\n          padding-right: 1.25rem;\n          text-transform: capitalize;\n          border-radius: 0;\n          font-weight: 500;\n          outline: none;\n          color: hsla(0, 0%, 100%, 0.548);\n\n          &:hover {\n            background-color: #363636;\n            color: #ffffff;\n          }\n\n          &:last-of-type {\n            background: transparent;\n            color: hsla(0, 0%, 100%, 0.562);\n            @apply ml-1;\n            transition: all cubic-bezier(0.175, 0.885, 0.32, 1.275) .2s;\n\n            &:hover {\n              color: #ffffff;\n            }\n          }\n        }\n      }\n    }\n  }\n\n  .more-available {\n    position: relative;\n    top: 1.4rem;\n    margin-top: -1rem;\n    cursor: pointer;\n    font-size: 0.7rem;\n    font-weight: 500;\n    color: #999999;\n    user-select: none;\n\n    &:hover {\n      color: #cacaca;\n    }\n  }\n}\n\n@keyframes slidein-left {\n  0% {\n    transform: translateX(100%);\n  }\n\n  100% {\n    transform: translateX(0);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/prompt-list/prompt-list.component.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, OnDestroy, OnInit, TrackByFunction } from '@angular/core';\nimport { AppProfile, AppProfileService, deepClone, setAppSetting } from '@safing/portmaster-api';\nimport { combineLatest, forkJoin, Observable, Subscription } from 'rxjs';\nimport { map, switchMap } from 'rxjs/operators';\nimport { Action, ConnectionPrompt, NotificationsService, NotificationType } from 'src/app/services';\nimport { moveInOutAnimation, moveInOutListAnimation } from 'src/app/shared/animations';\nimport { ParsedDomain, parseDomain } from 'src/app/shared/utils';\nimport { ActionIndicatorService } from '../action-indicator';\n\n// ExtendedConnectionPrompt extends the normal connection prompt\n// with parsed domain information.\ninterface ExtendedConnectionPrompt extends ConnectionPrompt, ParsedDomain { }\n\n// ProfilePrompts extends an application profile with prompt\n// information mainly used for paginagtion.\ninterface ProfilePrompts extends AppProfile {\n  promptsLimited: ExtendedConnectionPrompt[];\n  prompts: ExtendedConnectionPrompt[];\n  showAll: boolean;\n}\n\n// Number of prompts to display per application profile\n// before we start to paginate the list of prompts.\nconst PromptLimit = 3;\n\n@Component({\n  selector: 'app-prompt-list',\n  templateUrl: './prompt-list.component.html',\n  styleUrls: [\n    './prompt-list.component.scss'\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    moveInOutAnimation,\n    moveInOutListAnimation\n  ]\n})\nexport class PromptListComponent implements OnInit, OnDestroy {\n  profiles: ProfilePrompts[] = [];\n\n  /**\n   * @private\n   * Sets \"empty\" class on the host element if no prompts are displayed\n   */\n  @HostBinding('class.empty')\n  get isEmpty() {\n    return this.profiles.length === 0;\n  }\n\n  // Subscription to new prompts and profile updates.\n  private subscription = Subscription.EMPTY;\n\n  constructor(\n    private changeDetectorRef: ChangeDetectorRef,\n    private profileService: AppProfileService,\n    public notifService: NotificationsService,\n    public uai: ActionIndicatorService\n  ) { }\n\n  trackPrompts: TrackByFunction<ExtendedConnectionPrompt> = this.notifService.trackBy;\n\n  ngOnInit() {\n    // filter the stream of all notifications to only emit\n    // prompts that are used by the privacy filter (filter:prompt prefix).\n    const prompts$: Observable<ConnectionPrompt[]> = this.notifService\n      .new$\n      .pipe(\n        map(notifs => notifs.filter(notif => {\n          return notif.Type === NotificationType.Prompt &&\n            notif.EventID.startsWith(\"filter:prompt\");\n        })),\n      );\n\n    // each time the notification list is emitted make sure we have an\n    // up-to-date copy of the linked application profile as well.\n    const profiles$ = prompts$\n      .pipe(\n        switchMap(notifs => {\n          // collect all profile keys in a distict set so we don't load\n          // them more that once.\n          var profileKeys = new Set<string>();\n          notifs.forEach(n => profileKeys.add(\n            this.profileService.getKey(n.EventData!.Profile.Source, n.EventData!.Profile.ID)\n          ));\n          // load all of them in parallel\n          return forkJoin(\n            Array.from(profileKeys).map(key => this.profileService.getAppProfileFromKey(key))\n          )\n        })\n      );\n\n    // subscribe to updates on the prompt list and the related profiles.\n    this.subscription =\n      combineLatest([\n        prompts$,\n        profiles$,\n      ]).subscribe(([prompts, profiles]) => {\n\n        let promptsByProfile = new Map<string, ExtendedConnectionPrompt[]>();\n\n        // for each prompt, make an \"extended\" connection prompt by parsing the\n        // domain and index them by profile key\n        prompts.forEach(prompt => {\n          // prompts must have the connection data attached. If not, ignore it\n          // here.\n          if (!prompt.EventData) {\n            return;\n          }\n\n          // get the list of prompts indexed by the profile ID. if this is\n          // the first prompt for that profile create a new array and place\n          // it at the index.\n          let entries = promptsByProfile.get(prompt.EventData.Profile.ID);\n          if (!entries) {\n            entries = [];\n            promptsByProfile.set(prompt.EventData.Profile.ID, entries);\n          }\n\n          // Create an \"extended\" version of the prompt by parsing\n          // and assigning the domain and subdomain values.\n          let copy: ExtendedConnectionPrompt = {\n            ...prompt,\n            domain: null,\n            subdomain: null,\n          }\n          Object.assign(copy, parseDomain(prompt.EventData.Entity.Domain))\n          entries.push(copy)\n        });\n\n        // Convert the list of application profiles into a set of ProfilePrompts\n        // objects that we can use to actually display the prompts with pagination\n        // applied.\n        this.profiles = profiles\n          .filter(profile => !!promptsByProfile.get(profile.ID))\n          .map(profile => {\n            const prompts = promptsByProfile.get(profile.ID)!;\n            return {\n              ...profile,\n              showAll: prompts.length < PromptLimit,\n              promptsLimited: prompts.slice(0, PromptLimit),\n              prompts: prompts,\n            };\n          })\n          .sort((a, b) => {\n            if (a.ID > b.ID) {\n              return 1;\n            }\n            if (a.ID < b.ID) {\n              return -1;\n            }\n            return 0;\n          });\n\n        this.changeDetectorRef.markForCheck();\n      })\n  }\n\n  allow(prompt: ConnectionPrompt) {\n    let allowActions = [\n      'allow-domain-all',\n      'allow-serving-ip',\n      'allow-ip',\n    ];\n\n    for (let i = 0; i < allowActions.length; i++) {\n      const action = prompt.AvailableActions.find(a => a.ID === allowActions[i])\n      if (!!action) {\n        this.execute(prompt, action);\n        return;\n      }\n    }\n  }\n\n  block(prompt: ConnectionPrompt) {\n    let permitActions = [\n      'block-domain-all',\n      'block-serving-ip',\n      'block-ip',\n    ];\n\n    for (let i = 0; i < permitActions.length; i++) {\n      const action = prompt.AvailableActions.find(a => a.ID === permitActions[i])\n      if (!!action) {\n        this.execute(prompt, action);\n        return;\n      }\n    }\n  }\n\n  changeDefault(profile: ProfilePrompts, newDefault: 'permit' | 'block') {\n\n    this.profileService\n      .getAppProfile(profile.Source, profile.ID)\n      .pipe(\n        map(rawProfile => {\n          const copy = deepClone(rawProfile);\n          setAppSetting(copy.Config || {}, 'filter/defaultAction', newDefault)\n\n          return copy\n        }),\n        switchMap(updatedProfile => this.profileService.saveProfile(updatedProfile)),\n      )\n      .subscribe({\n        error: (err) => {\n          this.uai.error('Failed to change App Settings', this.uai.getErrorMessage(err));\n        }\n      })\n\n\n    setAppSetting(profile.Config || {}, 'filter/defaultAction', newDefault)\n  }\n\n  allowAll(profile: ProfilePrompts) {\n    profile.prompts.forEach(prompt => this.allow(prompt));\n  }\n\n  denyAll(profile: ProfilePrompts) {\n    profile.prompts.forEach(prompt => this.block(prompt));\n  }\n\n  execute(prompt: ConnectionPrompt, action: Action) {\n    this.notifService.execute(prompt, action)\n      .subscribe({\n        error: console.error,\n      });\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe();\n  }\n\n  /** @private - {@link TrackByFunction} for profile prompts */\n  trackProfile(_: number, p: ProfilePrompts) {\n    return p.ID;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/security-lock/index.ts",
    "content": "export * from './security-lock';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/security-lock/security-lock.html",
    "content": "<div class=\"relative flex flex-col items-center justify-center w-full mr-2\">\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"\n    class=\"transition-all duration-200 ease-in-out shield {{lockLevel?.class}}\">\n    <path class=\"shield-three\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.4\"\n      d=\"M20 11.242c0 4.368-3.157 8.462-7.48 9.686-.338.096-.702.096-1.04 0C7.157 19.705 4 15.61 4 11.242V7.214c0-.812.491-1.544 1.243-1.851l4.864-1.99c1.214-.497 2.574-.497 3.787 0l4.864 1.99C19.509 5.67 20 6.402 20 7.214v4.028z\" />\n    <path class=\"shield-two\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.4\"\n      d=\"M20 11.242c0 4.368-3.157 8.462-7.48 9.686-.338.096-.702.096-1.04 0C7.157 19.705 4 15.61 4 11.242V7.214c0-.812.491-1.544 1.243-1.851l4.864-1.99c1.214-.497 2.574-.497 3.787 0l4.864 1.99C19.509 5.67 20 6.402 20 7.214v4.028z\" />\n    <path class=\"shield-one\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.4\"\n      d=\"M20 11.242c0 4.368-3.157 8.462-7.48 9.686-.338.096-.702.096-1.04 0C7.157 19.705 4 15.61 4 11.242V7.214c0-.812.491-1.544 1.243-1.851l4.864-1.99c1.214-.497 2.574-.497 3.787 0l4.864 1.99C19.509 5.67 20 6.402 20 7.214v4.028z\" />\n    <path class=\"shield-ok\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.8\"\n      d=\"M8.712 12.566l2.193 2.193 4.787-4.788\" />\n    <path class=\"shield-warn\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.8\"\n      d=\"M12 11V7.75M12 14.63a.16.16 0 10.16.16.16.16 0 00-.16-.16\" transform=\"translate(-11.09 -7)\" />\n    <path class=\"shield-fail\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.6\"\n      d=\"M14.83 9.17l-5.66 5.66M14.83 14.83L9.17 9.17\" />\n\n  </svg>\n  <ng-container *ngIf=\"mode === 'full'\">\n    <h2 class=\"p-0 m-0 -mt-3.5 text-base font-light\">{{lockLevel?.displayText}}</h2>\n    <span *ngIf=\"!!lockLevel?.class && lockLevel!.class !== 'text-green-300'\" class=\"{{lockLevel?.class}}\" [@fadeIn]\n      [@fadeOut]>\n      See Notifications\n    </span>\n  </ng-container>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/security-lock/security-lock.scss",
    "content": "svg.shield {\n  width: 100%;\n  max-width: 7.25rem;\n\n  transform: scale(0.95);\n\n  path {\n    top: 0px;\n    left: 0px;\n    transform-origin: center center;\n  }\n\n  .shield-one {\n    transform: scale(.62);\n  }\n\n  .shield-two {\n    animation-delay: -1.2s;\n    opacity: .6;\n    transform: scale(.8);\n  }\n\n  .shield-three {\n    animation-delay: -2.5s;\n    opacity: .4;\n    transform: scale(1);\n  }\n\n  &.text-green-300 {\n    filter: saturate(1.4);\n\n    .shield-one {\n      fill: var(--protection-ok-primary);\n    }\n\n\n    .shield-two {\n      fill: var(--protection-ok-secondary);\n    }\n\n    .shield-three {\n      fill: var(--protection-ok-tertiary);\n    }\n\n    .shield-warn,\n    .shield-fail {\n      display: none;\n    }\n\n    .shield-ok {\n      stroke: var(--background);\n      fill: none;\n      transform: scale(.5);\n    }\n  }\n\n  &.text-yellow-300 {\n    filter: saturate(1.3);\n\n    .shield-one {\n      fill: var(--protection-warn-primary);\n    }\n\n    .shield-three,\n    .shield-two {\n      //animation: shield-pulse 3s linear;\n    }\n\n    .shield-two {\n      fill: var(--protection-warn-secondary);\n    }\n\n    .shield-three {\n      fill: var(--protection-warn-tertiary);\n    }\n\n    .shield-ok,\n    .shield-fail {\n      display: none;\n    }\n\n    .shield-warn {\n      stroke: var(--background);\n      fill: none;\n      transform: scale(.5);\n    }\n  }\n\n  &.text-red-300 {\n    filter: saturate(1.3);\n\n    .shield-one {\n      fill: var(--protection-fail-primary);\n    }\n\n    .shield-three,\n    .shield-two {\n      //animation: shield-pulse 3s linear reverse;\n    }\n\n    .shield-two {\n      fill: var(--protection-fail-secondary);\n    }\n\n    .shield-three {\n      fill: var(--protection-fail-tertiary);\n    }\n\n    .shield-warn,\n    .shield-ok {\n      display: none;\n    }\n\n    .shield-fail {\n      stroke: var(--background);\n      fill: none;\n      transform: scale(.45);\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/security-lock/security-lock.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Input, OnInit, inject } from \"@angular/core\";\nimport { SecurityLevel } from \"@safing/portmaster-api\";\nimport { combineLatest } from \"rxjs\";\nimport { StatusService, ModuleStateType, GetModuleState, ControlPauseStateData } from \"src/app/services\";\nimport { fadeInAnimation, fadeOutAnimation } from \"../animations\";\n\ninterface SecurityOption {\n  level: SecurityLevel;\n  displayText: string;\n  class: string;\n  subText?: string;\n}\n\n@Component({\n  selector: 'app-security-lock',\n  templateUrl: './security-lock.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  styleUrls: ['./security-lock.scss'],\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation\n  ]\n})\nexport class SecurityLockComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  lockLevel: SecurityOption | null = null;\n\n  /** The display mode for the security lock */\n  @Input()\n  mode: 'small' | 'full' = 'full'\n\n  constructor(\n    private statusService: StatusService,\n    private cdr: ChangeDetectorRef,\n  ) { }\n\n  ngOnInit(): void {\n      this.statusService.status$.subscribe(status => {\n        // By default the lock is green and we are \"Secure\"\n        this.lockLevel = {\n          level: SecurityLevel.Normal,\n          class: 'text-green-300',\n          displayText: 'Secure',\n        }\n\n        // update the shield depending on the worst state.\n        switch (status.WorstState.Type) {\n          case ModuleStateType.Warning:\n            this.lockLevel = {\n              level: SecurityLevel.High,\n              class: 'text-yellow-300',\n              displayText: 'Warning'\n            }\n            break;\n          case ModuleStateType.Error:\n            this.lockLevel = {\n              level: SecurityLevel.Extreme,\n              class: 'text-red-300',\n              displayText: 'Insecure'\n            }\n            break;\n        }\n\n        // Checking for Control:Paused state\n        const pausedState = GetModuleState(status, 'Control', 'control:paused');\n        if (pausedState?.Data) {\n          const pauseData = pausedState.Data as ControlPauseStateData;\n          if (pauseData.Interception === true) {\n            this.lockLevel.displayText = 'Insecure: PAUSED';\n          } else if (pauseData.SPN === true) {\n            this.lockLevel.displayText = 'Secure (SPN Paused)';\n          }\n        }\n\n        this.cdr.markForCheck();\n      });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-account-details/index.ts",
    "content": "export * from './spn-account-details';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-account-details/spn-account-details.html",
    "content": "<ng-container *ngIf=\"!!currentUser && currentUser.state !== '' && currentUser.state !== 'loggedout'\">\n  <h1 class=\"mb-4 text-xl\">Account Details</h1>\n\n  <!-- TODO: update to fit style -->\n  <div *ngIf=\"currentUser.view?.Message\" class=\"flex bg-yellow-100 rounded-lg p-4 mb-4 text-sm text-yellow-700 font-medium\" role=\"alert\">\n    <svg class=\"w-5 h-5 inline mr-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\"></path></svg>\n    <div>\n      {{ currentUser.view?.Message }}\n    </div>\n  </div>\n\n  <table *ngIf=\"!currentUser.view || currentUser.view?.ShowAccountData\" class=\"table-auto m-6\">\n    <ng-container *ngIf=\"currentUser.subscription\">\n      <ng-container *ngIf=\"currentUser.subscription.state === 'manual'; else: subscription\">\n        <tr>\n          <th>Your Package</th>\n          <td>{{ currentUser.current_plan?.name }}</td>\n        </tr>\n        <tr *ngIf=\"currentUser.subscription.ends_at\">\n          <th>Access Until</th>\n          <td>{{ currentUser.subscription.ends_at | date:'medium' }}</td>\n        </tr>\n      </ng-container>\n      <ng-template #subscription>\n        <tr>\n          <th>Your Subscription</th>\n          <td>{{ currentUser.current_plan?.name }}</td>\n        </tr>\n        <tr>\n          <th>Status</th>\n          <td class=\"capitalize\">{{ currentUser.subscription.state }}</td>\n        </tr>\n        <tr *ngIf=\"currentUser.subscription.state === 'active'\">\n          <th>Next Payment Date</th>\n          <td>\n            {{ currentUser.subscription.next_billing_date | date:'medium' }}\n            via\n            {{ currentUser.subscription.payment_provider }}\n          </td>\n        </tr>\n        <tr *ngIf=\"currentUser.subscription.state === 'cancelled'\">\n          <th>Access Paid Until</th>\n          <td>{{ currentUser.subscription.ends_at | date:'medium' }}</td>\n        </tr>\n      </ng-template>\n    </ng-container>\n\n    <tr class=\"table-section-start\">\n      <th>Username</th>\n      <td>{{ currentUser.username }} </td>\n    </tr>\n    <tr>\n      <th>Device Name</th>\n      <td>{{ currentUser.device?.name }}</td>\n    </tr>\n\n    <ng-container *appExpertiseLevel=\"'developer'\">\n      <tr class=\"table-section-start\">\n        <th>Account State</th>\n        <td>{{ currentUser.state }} </td>\n      </tr>\n      <tr>\n        <th>Features</th>\n        <td>{{ currentUser.current_plan?.feature_ids?.join(\", \") }} </td>\n      </tr>\n      <tr>\n        <th>Device ID</th>\n        <td>{{currentUser.device?.id}}</td>\n      </tr>\n      <tr>\n        <th>Logged in Since</th>\n        <td>{{ currentUser.LoggedInAt | date:'medium' }} </td>\n      </tr>\n    </ng-container>\n  </table>\n\n  <div class=\"flex items-end justify-end w-full space-x-2\">\n    <!-- Always show all buttons, no matter what the view says here. -->\n    <button *ngIf=\"dialogRef\" (click)=\"dialogRef.close()\" class=\"\">Close</button>\n    <div class=\"flex-grow\"></div>\n\n    <a href=\"https://account.safing.io/?source=Portmaster\"\n      class=\"flex flex-row items-center self-stretch justify-center gap-1 px-2 bg-gray-300 rounded hover:bg-gray-200 text-blue whitespace-nowrap\">\n      Open Account Page\n    </a>\n\n    <button (click)=\"logout()\" class=\"bg-info-red\">Logout</button>\n    <button (click)=\"refreshAccount()\" style=\"width: 70px\">\n      <ng-container *ngIf=\"!refreshing; else: loading\">\n        Refresh\n      </ng-container>\n      <ng-template #loading>\n        <fa-icon icon=\"spinner\" [spin]=\"true\"></fa-icon>\n      </ng-template>\n    </button>\n  </div>\n</ng-container>\n\n<app-spn-login\n  *ngIf=\"!loadingProfile && (currentUser === null || currentUser.state === '' || currentUser.state === 'loggedout')\"\n  [forcedLogout]=\"currentUser?.state === 'loggedout'\"></app-spn-login>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-account-details/spn-account-details.scss",
    "content": "table tr {\n  background-color: transparent !important;\n}\n\ntable .table-section-start {\n  border-top: 1.5rem solid transparent;\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-account-details/spn-account-details.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Inject, OnInit, Optional, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { SPNService, UserProfile } from \"@safing/portmaster-api\";\nimport { SFNG_DIALOG_REF, SfngDialogRef } from \"@safing/ui\";\nimport { catchError, delay, of, tap } from \"rxjs\";\nimport { ActionIndicatorService } from \"../action-indicator\";\n\n@Component({\n  templateUrl: './spn-account-details.html',\n  styleUrls: ['./spn-account-details.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SPNAccountDetailsComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  /** Whether or not we're currently refreshing the user profile from the customer agent */\n  refreshing = false;\n\n  /** Whether or not we're still waiting for the user profile to be fetched from the backend */\n  loadingProfile = true;\n\n  currentUser: UserProfile | null = null;\n\n  constructor(\n    private spnService: SPNService,\n    private cdr: ChangeDetectorRef,\n    private uai: ActionIndicatorService,\n    @Inject(SFNG_DIALOG_REF) @Optional() public dialogRef: SfngDialogRef<any>,\n  ) { }\n\n  /**\n   * Force a refresh of the local user account\n   *\n   * @private - template only\n   */\n  refreshAccount() {\n    this.refreshing = true;\n    this.spnService.userProfile(true)\n      .pipe(\n        delay(1000),\n        tap(() => {\n          this.refreshing = false;\n          this.cdr.markForCheck();\n        }),\n      )\n      .subscribe()\n  }\n\n  /**\n   * Logout of your safing account\n   *\n   * @private - template only\n   */\n  logout() {\n    this.spnService.logout()\n      .pipe(tap(() => this.dialogRef?.close()))\n      .subscribe(this.uai.httpObserver('SPN Logout', 'SPN Logout'))\n  }\n\n  ngOnInit(): void {\n    this.loadingProfile = false;\n    this.spnService.profile$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        catchError(err => of(null)),\n      )\n      .subscribe({\n        next: (profile) => {\n          this.loadingProfile = false;\n          this.currentUser = profile || null;\n\n          this.cdr.markForCheck();\n        },\n        complete: () => {\n          // Database entry deletion will complete the observer.\n          this.loadingProfile = false;\n          this.currentUser = null;\n\n          this.cdr.markForCheck();\n        },\n      })\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-login/index.ts",
    "content": "export * from './spn-login';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-login/spn-login.html",
    "content": "<!-- login View -->\n<div class=\"w-full px-5\">\n  <h2 class=\"flex flex-row items-center justify-center w-full gap-4 p-0 pb-4 m-0\">\n    <div class=\"flex flex-col items-center justify-center w-16 h-16 outline-none\">\n      <svg data-name=\"Layer 1\" viewBox=\"0 0 128 128\" class=\"spin reverse logo-image\">\n        <g data-name=\"Main\" fill-rule=\"evenodd\">\n          <path shape-rendering=\"geometricPrecision\" fill=\"#fff\" class=\"inner\"\n            d=\"M176.11 36.73l-5-8.61a41.53 41.53 0 00-14.73 57.22l8.55-5.12a31.58 31.58 0 0111.19-43.49z\"\n            transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n          <path shape-rendering=\"geometricPrecision\" fill=\"#fff\" class=\"inner\"\n            d=\"M222.36 72.63a31.55 31.55 0 01-45 19.35l-4.62 8.84a41.54 41.54 0 0059.17-25.46z\"\n            transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".8\"></path>\n        </g>\n      </svg>\n      <svg data-name=\"Layer 1\" viewBox=\"0 0 128 128\" class=\"spin logo-image\">\n        <g data-name=\"Main\" fill-rule=\"evenodd\">\n          <path shape-rendering=\"geometricPrecision\" fill=\"#fff\" class=\"inner reverse\"\n            d=\"M197 83a19.66 19.66 0 01-19.25-32.57l-4.5-4.27A25.87 25.87 0 00198.59 89z\"\n            transform=\"translate(-127.99 .01)\" style=\"isolation:isolate\" opacity=\".6\"></path>\n        </g>\n      </svg>\n      <svg data-name=\"Layer 1\" viewBox=\"0 0 128 128\" class=\"logo-image\">\n        <g data-name=\"Main\" fill-rule=\"evenodd\">\n          <path shape-rendering=\"geometricPrecision\" fill=\"#fff\"\n            d=\"M192 112.64A48.64 48.64 0 11240.64 64 48.64 48.64 0 01192 112.64zM256 64a64 64 0 10-64 64 64 64 0 0064-64z\"\n            transform=\"translate(-127.99 .1)\"></path>\n        </g>\n      </svg>\n    </div>\n    <span class=\"flex flex-col items-start justify-start\">\n      Safing Account Login\n      <a class=\"text-xs font-medium text-tertiary\" href=\"https://safing.io/spn?source=Portmaster\" target=\"_blank\">\n        Unlock powerful features.\n      </a>\n    </span>\n  </h2>\n\n\n  <div *ngIf=\"forcedLogout\" class=\"w-full px-4 py-2 mb-4 text-center rounded bg-info-red\">\n    You have been logged out by the account server.\n    <br />\n    Please check <a class=\"underline text-primary\" href=\"https://account.safing.io/?source=Portmaster\">your account</a>.\n  </div>\n\n  <form (ngSubmit)=\"login()\">\n    <div class=\"flex flex-col items-stretch mt-4 space-y-6\">\n      <div class=\"flex flex-col justify-items-start\">\n        <label for=\"username\" class=\"font-semibold text-primary\">Username</label>\n        <input type=\"text\" name=\"username\" autocomplete=\"off\" class=\"custom-form-input\" [(ngModel)]=\"username\">\n      </div>\n\n      <div class=\"flex flex-col justify-items-start\">\n        <label for=\"password\" class=\"font-semibold text-primary\">Password</label>\n        <input type=\"password\" name=\"password\" autocomplete=\"off\" class=\"custom-form-input\" [(ngModel)]=\"password\">\n      </div>\n\n      <div>\n        <button\n          class=\"relative w-full p-2 bg-opacity-75 rounded-full custom text-primary bg-blue hover:bg-blue bg-opacity-702\"\n          [disabled]=\"!username || !password\" type=\"submit\">\n          SIGN IN\n        </button>\n        <div class=\"w-full mt-6 text-xs font-semibold text-center text-tertiary\">\n          <span><a class=\"underline\" href=\"https://account.safing.io/?source=Portmaster\">Sign Up and\n              Subscribe</a></span>\n        </div>\n      </div>\n    </div>\n  </form>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-login/spn-login.scss",
    "content": ":host {\n  display: block;\n  width: 100%;\n}\n\n.custom-form-input {\n  background: none;\n  @apply border-0 border-b border-buttons-light text-secondary font-medium px-0;\n\n  &:active,\n  &:focus {\n    background: none;\n  }\n}\n\n.logo-image {\n  @apply w-16 absolute;\n}\n\nsvg.logo-image {\n  animation-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);\n}\n\n.spin {\n  animation-name: spin;\n  animation-duration: 3500ms;\n  animation-iteration-count: infinite;\n  animation-timing-function: linear;\n}\n\n.reverse {\n  animation-name: spin-reverse;\n}\n\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes spin-reverse {\n  0% {\n    transform: rotate(360deg);\n  }\n\n  100% {\n    transform: rotate(0deg);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-login/spn-login.ts",
    "content": "import { coerceBooleanProperty } from \"@angular/cdk/coercion\";\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Input, OnInit, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { SPNService, UserProfile } from \"@safing/portmaster-api\";\nimport { catchError, finalize, of } from \"rxjs\";\nimport { ActionIndicatorService } from \"../action-indicator\";\n\n@Component({\n  selector: 'app-spn-login',\n  templateUrl: './spn-login.html',\n  styleUrls: ['./spn-login.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SPNLoginComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  /** The current user profile if the user is already logged in */\n  profile: UserProfile | null = null;\n\n  /** The value of the username text box */\n  username: string = '';\n\n  /** The value of the password text box */\n  password: string = '';\n\n  @Input()\n  set forcedLogout(v: any) {\n    this._forcedLogout = coerceBooleanProperty(v);\n  }\n  get forcedLogout() { return this._forcedLogout }\n  private _forcedLogout = false;\n\n  constructor(\n    private spnService: SPNService,\n    private uai: ActionIndicatorService,\n    private cdr: ChangeDetectorRef\n  ) { }\n\n  login(): void {\n    if (!this.username || !this.password) {\n      return;\n    }\n\n    this.spnService.login({\n      username: this.username,\n      password: this.password\n    })\n      .pipe(finalize(() => {\n        this.password = '';\n      }))\n      .subscribe(this.uai.httpObserver('SPN Login', 'SPN Login'))\n  }\n\n  ngOnInit(): void {\n    this.spnService.profile$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        catchError(() => of(null))\n      )\n      .subscribe(profile => {\n        this.profile = profile || null;\n\n        if (!!this.profile) {\n          this.username = this.profile.username;\n        }\n\n        this.cdr.markForCheck();\n      });\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-network-status/index.ts",
    "content": "export * from './spn-network-status';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-network-status/spn-network-status.html",
    "content": "  <!-- What's new on the SPN -->\n  <div class=\"flex items-center mb-4 justify-items-center w-80\">\n    <h4 class=\"mr-4\">Network Status</h4>\n    <span class=\"flex-grow inline-block border-b border-buttons-light\"></span>\n  </div>\n\n  <span class=\"text-secondary\" *ngIf=\"!spnIssues.length\">Loading Network Status ...</span>\n  <div class=\"issue-list\">\n    <ul [@fadeInList]=\"spnIssues.slice(0, 8).length\">\n      <li *ngFor=\"let issue of spnIssues.slice(0, 8); trackBy: trackIssue\" (click)=\"issue.expanded = !issue.expanded\"\n        class=\"issue\" [class.expanded]=\"issue.expanded\">\n        <div class=\"header\">\n          <span class=\"title\">{{ issue.title }}</span>\n          <span class=\"meta\">{{ issue.closed ? 'closed' : 'opened'}} by <u>{{ issue.user }}</u>\n            {{\n            issue.createdAt | timeAgo\n            }}</span>\n        </div>\n        <fa-icon [icon]=\"issue.expanded ? 'chevron-up' : 'chevron-down'\"></fa-icon>\n        <div class=\"body\" *ngIf=\"issue.expanded\">\n          <markdown emoji [data]=\"issue.body\"></markdown>\n          <div>\n            <a class=\"underline text-primary\" (click)=\"openIssue(issue)\">Open on Github</a>\n          </div>\n        </div>\n      </li>\n    </ul>\n  </div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-network-status/spn-network-status.scss",
    "content": ":host {\n  @apply block;\n  min-width: 500px;\n  width: 50vw;\n}\n\n.issue-list {\n  width: 100%;\n\n  &,\n  ul {\n    overflow-y: auto;\n  }\n\n  .issue {\n    position: relative;\n    display: flex;\n    flex-direction: column;\n    cursor: pointer;\n    @apply mx-2;\n\n    .header {\n      @apply p-4;\n      display: flex;\n      flex-direction: column;\n      align-items: flex-start;\n      justify-content: center;\n      cursor: pointer;\n    }\n\n    @apply rounded;\n    @apply bg-cards-primary;\n\n    .title {\n      @apply mr-4;\n    }\n\n    span {\n      word-break: keep-all;\n    }\n\n    &:not(:last-child) {\n      margin-bottom: 0.5rem;\n    }\n\n    .body {\n      @apply bg-cards-secondary;\n      @apply rounded-b;\n      @apply p-4;\n    }\n\n    .meta {\n      @apply text-tertiary;\n      @apply font-normal;\n      opacity: .7;\n      font-size: 95%;\n    }\n\n    &:hover {\n      @apply bg-cards-tertiary;\n    }\n\n    fa-icon {\n      position: absolute;\n      right: 1rem;\n      top: 1rem;\n      opacity: .8;\n      cursor: pointer;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-network-status/spn-network-status.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, TrackByFunction, inject } from \"@angular/core\";\nimport { map } from \"rxjs\";\nimport { INTEGRATION_SERVICE } from \"src/app/integration\";\nimport { Issue, SupportHubService } from \"src/app/services\";\n\n/** The name of the SPN repository used to filter SPN support hub issues. */\nconst SPNRepository = \"spn\";\n\n/** A set of issue labels that are eligible to be displayed */\nconst SPNTagSet = new Set<string>([\"network status\"])\n\ninterface _Issue extends Issue {\n  expanded: boolean;\n}\n\n@Component({\n  selector: 'app-spn-network-status',\n  templateUrl: './spn-network-status.html',\n  styleUrls: ['./spn-network-status.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SPNNetworkStatusComponent implements OnInit {\n  private readonly integration = inject(INTEGRATION_SERVICE);\n  private readonly supportHub = inject(SupportHubService);\n  private readonly cdr = inject(ChangeDetectorRef);\n\n  /** trackIssue is used as a track-by function when rendering SPN issues. */\n  trackIssue: TrackByFunction<_Issue> = (_: number, issue: _Issue) => issue.url;\n\n  spnIssues: _Issue[] = [];\n\n  ngOnInit(): void {\n    this.supportHub.loadIssues()\n      .pipe(\n        map(issues => {\n          return issues\n            .filter(issue => issue.repository === SPNRepository && issue.labels?.some(l => {\n              return SPNTagSet.has(l);\n            }))\n            .reverse()\n        })\n      )\n      .subscribe(issues => {\n        let spnIssues: _Issue[] = issues\n          .map(i => {\n            const existing = this.spnIssues.find(existing => existing.url === i.url);\n            return {\n              ...i,\n              expanded: existing !== undefined ? existing.expanded : false\n            }\n          })\n        this.spnIssues = spnIssues;\n        this.cdr.markForCheck();\n      })\n  }\n\n  /**\n   * Open a github issue in a new tab/window\n   *\n   * @private - template only\n   */\n  openIssue(issue: Issue) {\n    this.integration.openExternal(issue.url);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-status/index.ts",
    "content": "export * from './spn-status';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-status/spn-status.html",
    "content": "<div class=\"relative flex flex-col justify-center w-full\">\n  <sfng-netquery-line-chart  *ngIf=\"spnEnabled && !!spnConnChart.length\" [@fadeIn] [@fadeOut]\n    [data]=\"spnConnChart\" showAxis=\"false\"\n          [config]=\"{\n            series: {\n              value: {\n                lineColor: 'text-blue',\n                areaColor: 'text-blue text-opacity-25',\n              }\n            }\n          }\"\n    class=\"absolute bottom-0 left-0 right-0 h-16\">\n  </sfng-netquery-line-chart>\n\n  <div class=\"relative flex flex-col justify-start gap-1 px-8 py-4\">\n    <h2 class=\"p-0 m-0 font-light outline-none cursor-pointer test-base\" [routerLink]=\"['/spn']\">SPN</h2>\n\n    <span [ngSwitch]=\"spnStatus?.Status\" class=\"-mt-1 text-xs font-medium text-secondary\">\n      <ng-template ngSwitchCase=\"disabled\">\n        Increase privacy protection\n      </ng-template>\n      <ng-template ngSwitchCase=\"failed\">\n        Failed to connect\n      </ng-template>\n      <ng-template ngSwitchCase=\"connecting\">\n        Connecting to the SPN ...\n      </ng-template>\n      <ng-template ngSwitchCase=\"connected\">\n        You're protected\n      </ng-template>\n    </span>\n    <ng-container *ngIf=\"spnEnabled\">\n      <span class=\"text-secondary text-xxs\" *appExpertiseLevel=\"'developer'\">\n        Home: <u>{{ spnStatus?.ConnectedIP }}</u> via <u>{{ spnStatus?.ConnectedTransport}}</u>\n      </span>\n    </ng-container>\n\n    <sfng-toggle [ngModel]=\"spnEnabled\" (ngModelChange)=\"setSPNEnabled($event)\"\n      *ngIf=\"spnEnabled || packageHasSPN\"></sfng-toggle>\n\n    <div *ngIf=\"!packageHasSPN\">\n      <button class=\"px-3 py-1.5 uppercase rounded outline-none text-xxs custom bg-blue hover:bg-blue bg-opacity-70\"\n        (click)=\"openOrLogin()\">\n        Upgrade\n      </button>\n    </div>\n  </div>\n  <div class=\"relative flex flex-col items-end justify-end flex-grow pb-4\" *ngIf=\"spnEnabled\">\n    <div class=\"flex flex-col items-center\">\n      <span class=\"-mb-1 leading-3 uppercase text-xxs text-secondary\">Identities</span>\n      <span class=\"text-lg text-primary\">{{ identities }}</span>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "desktop/angular/src/app/shared/spn-status/spn-status.ts",
    "content": "import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, OnInit, inject } from \"@angular/core\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { BoolSetting, ChartResult, ConfigService, FeatureID, Netquery, SPNService, SPNStatus, UserProfile } from \"@safing/portmaster-api\";\nimport { SfngDialogService } from '@safing/ui';\nimport { catchError, forkJoin, interval, of, startWith, switchMap } from \"rxjs\";\nimport { fadeInAnimation, fadeOutAnimation } from \"../animations\";\nimport { SPNAccountDetailsComponent } from '../spn-account-details';\n\n@Component({\n  selector: 'app-spn-status',\n  templateUrl: './spn-status.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  animations: [\n    fadeInAnimation,\n    fadeOutAnimation,\n  ]\n})\nexport class SPNStatusComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n\n  /** Whether or not the SPN is currently enabled */\n  spnEnabled = false;\n\n  /** The chart data for the SPN connection chart */\n  spnConnChart: ChartResult[] = [];\n\n  /** The current amount of SPN identities used */\n  identities: number = 0;\n\n  /** The current SPN user profile */\n  profile: UserProfile | null = null;\n\n  /** The current status of the SPN module */\n  spnStatus: SPNStatus | null = null;\n\n  /** Returns whether or not the current package has the SPN feature */\n  get packageHasSPN() {\n    return this.profile?.current_plan?.feature_ids?.includes(FeatureID.SPN)\n  }\n\n  constructor(\n    private configService: ConfigService,\n    private spnService: SPNService,\n    private netquery: Netquery,\n    private cdr: ChangeDetectorRef,\n    private router: Router,\n    private activeRoute: ActivatedRoute,\n    private dialog: SfngDialogService\n  ) { }\n\n  ngOnInit(): void {\n    this.spnService\n      .profile$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        catchError(() => of(null))\n      )\n      .subscribe(profile => {\n        this.profile = profile || null;\n\n        this.cdr.markForCheck();\n      });\n\n    this.spnService.status$\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(status => {\n        this.spnStatus = status;\n\n        this.cdr.markForCheck();\n      })\n\n    this.configService.watch<BoolSetting>(\"spn/enable\")\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(value => {\n        this.spnEnabled = value;\n\n        // If the user disabled the SPN clear the connection chart\n        // as well.\n        if (!this.spnEnabled) {\n          this.spnConnChart = [];\n        }\n\n        this.cdr.markForCheck();\n      });\n\n    interval(5000)\n      .pipe(\n        startWith(-1),\n        takeUntilDestroyed(this.destroyRef),\n        switchMap(() => forkJoin({\n          chart: this.netquery.activeConnectionChart({ tunneled: { $eq: true } }),\n          identities: this.netquery.query({\n            query: { tunneled: { $eq: true }, exit_node: { $ne: \"\" } },\n            groupBy: ['exit_node'],\n            select: [\n              'exit_node',\n              { $count: { field: '*', as: 'totalCount' } }\n            ]\n          }, 'spn-status-get-connections-count-per-exit-node')\n        }))\n      )\n      .subscribe(data => {\n        this.spnConnChart = data.chart;\n        this.identities = data.identities.length;\n\n        this.cdr.markForCheck();\n      })\n  }\n\n  openOrLogin() {\n    if (this.activeRoute.snapshot.firstChild?.url[0]?.path === \"spn\") {\n      this.dialog.create(SPNAccountDetailsComponent, {\n        autoclose: true,\n        backdrop: 'light'\n      })\n\n      return\n    }\n\n    this.router.navigate(['/spn'])\n  }\n\n  setSPNEnabled(v: boolean) {\n    this.configService.save(`spn/enable`, v)\n      .subscribe();\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/text-placeholder/index.ts",
    "content": "export { PlaceholderComponent } from './placeholder';\n"
  },
  {
    "path": "desktop/angular/src/app/shared/text-placeholder/placeholder.scss",
    "content": ".text-placeholder {\n  display : inline-block;\n  height  : 0.75rem;\n  position: relative;\n\n  .background {\n    @apply rounded;\n    opacity                  : 0.8;\n    animation-duration       : 6s;\n    animation-fill-mode      : forwards;\n    animation-iteration-count: infinite;\n    animation-name           : placeHolderShimmer;\n    animation-timing-function: linear;\n    background               : linear-gradient(to right, #4b4b4b 8%, #5a5a5a 18%, #4b4b4b 33%);\n    position                 : absolute;\n    backface-visibility      : hidden;\n    left                     : 0;\n    right                    : 0;\n    top                      : 2px;\n    bottom                   : 0;\n  }\n}\n\n@keyframes placeHolderShimmer {\n  0% {\n    background-position: 0px 0;\n  }\n\n  100% {\n    background-position: 100em 0;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/text-placeholder/placeholder.ts",
    "content": "import { AfterContentChecked, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input } from '@angular/core';\n\n@Component({\n  selector: 'app-text-placeholder',\n  template: `\n    <span class=\"text-placeholder\" *ngIf=\"loading\">\n      <div class=\"background\" [style.width]=\"width\" ></div>\n    </span>\n    <ng-content *ngIf=\"mode === 'auto' || !loading\"></ng-content>\n  `,\n  styleUrls: ['./placeholder.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PlaceholderComponent implements AfterContentChecked {\n  @Input()\n  set width(v: string | number) {\n    if (typeof v === 'number') {\n      this._width = `${v}px`;\n      return\n    }\n\n    switch (v) {\n      case 'small':\n        this._width = '5rem';\n        break;\n      case 'medium':\n        this._width = '10rem';\n        break;\n      case 'large':\n        this._width = '15rem';\n        break\n      default:\n        this._width = v;\n    }\n  }\n  get width() { return this._width; }\n  private _width: string = '10rem';\n\n  @Input()\n  mode: 'auto' | 'input' = 'auto';\n\n  @Input()\n  loading = true;\n\n  constructor(\n    private elementRef: ElementRef,\n    private changeDetector: ChangeDetectorRef,\n  ) { }\n\n  ngAfterContentChecked() {\n    if (this.mode === 'input') {\n      return;\n    }\n\n    const show = this.elementRef.nativeElement.innerText === '';\n    if (this.loading != show) {\n      this.loading = show;\n      this.changeDetector.detectChanges();\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/app/shared/utils.ts",
    "content": "import { parse } from 'psl';\n\nexport interface ParsedDomain {\n  domain: string | null;\n  subdomain: string | null;\n}\nexport function parseDomain(scope: string): ParsedDomain {\n  // Due to https://github.com/lupomontero/psl/issues/185\n  // parse will throw an error for service-discovery lookups\n  // so make sure we split them apart.\n  const domainParts = scope.split(\".\")\n  const lastUnderscorePart = domainParts.length - [...domainParts].reverse().findIndex(dom => dom.startsWith(\"_\"))\n  let result: ParsedDomain = {\n    domain: null,\n    subdomain: null,\n  }\n\n  let cleanedDomain = scope;\n  let removedPrefix = '';\n  if (lastUnderscorePart <= domainParts.length) {\n    removedPrefix = domainParts.slice(0, lastUnderscorePart).join('.')\n    cleanedDomain = domainParts.slice(lastUnderscorePart).join('.')\n  }\n\n  const parsed = parse(cleanedDomain);\n  if ('listed' in parsed) {\n    result.domain = parsed.domain || scope;\n    result.subdomain = removedPrefix;\n    if (!!parsed.subdomain) {\n      if (removedPrefix != '') {\n        result.subdomain += '.';\n      }\n      result.subdomain += parsed.subdomain;\n    }\n  }\n\n  return result\n}\n\nexport function binarySearch<T>(array: T[], what: T, sortFunc: (a: T, b: T) => number): number {\n  let l = 0;\n  let h = array.length - 1;\n  let currentIndex: number = 0;\n\n  while (l <= h) {\n    currentIndex = (l + h) >>> 1;\n    const result = sortFunc(what, array[currentIndex]);\n    if (result < 0) {\n      l = currentIndex + 1;\n    } else if (result > 0) {\n      h = currentIndex - 1;\n    } else {\n      return currentIndex;\n    }\n  }\n  return ~currentIndex;\n}\n\nexport function binaryInsert<T>(array: T[], what: T, sortFunc: (a: T, b: T) => number, duplicate = false): number {\n  let idx = binarySearch<T>(array, what, sortFunc);\n  if (idx >= 0) {\n    if (!duplicate) {\n      return idx;\n    }\n  } else {\n    // if `what` is not part of `array` than index is the bitwise complement\n    // of the expected index in array.\n    idx = ~idx;\n  }\n  array.splice(idx, 0, what)\n  return idx;\n}\n\nexport function objKeys<T extends object>(obj: T): (keyof T)[] {\n  return Object.keys(obj) as any;\n}\n"
  },
  {
    "path": "desktop/angular/src/electron-app.d.ts",
    "content": "declare global {\n  interface Window {\n    app: AppAPI;\n  }\n}\n\nexport class AppAPI {\n  /** Returns the current platform */\n  getPlatform(): Promise<string>;\n\n  /** The installation directory of portmaster. */\n  getInstallDir(): Promise<string>;\n\n  /**\n   * Open an URL or path using an external application.\n   *\n   * @param pathOrUrl The path or URL to open.\n   */\n  openExternal(pathOrUrl: string): Promise<void>;\n\n  /**\n   * Creates a new URL with the file:// scheme. Works\n   * on any platform.\n   *\n   * @param path The path for the file URL.\n   */\n  createFileURL(path: string): Promise<string>;\n\n  /**\n   * Returns a dataURL for the icon that is used to represent\n   * the path on this platform.\n   * This method only works on windows for now. On all other\n   * platforms an empty string is returned.\n   *\n   * @param path The path the the binary\n   */\n  getFileIcon(path: string): Promise<string>;\n\n  /** Exit the electron appliction. */\n  exitApp(): Promise<void>;\n}\n"
  },
  {
    "path": "desktop/angular/src/environments/environment.prod.ts",
    "content": "export const environment = {\n  production: true,\n  portAPI: `ws://${window.location.host}/api/database/v1`,\n  httpAPI: `http://${window.location.host}/api`,\n  supportHub: \"https://support.safing.io\"\n};"
  },
  {
    "path": "desktop/angular/src/environments/environment.ts",
    "content": "// This file can be replaced during build by using the `fileReplacements` array.\n// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.\n// The list of file replacements can be found in `angular.json`.\n\nexport const environment = {\n  production: false,\n  portAPI: \"ws://127.0.0.1:817/api/database/v1\",\n  httpAPI: \"http://127.0.0.1:817/api\",\n  supportHub: \"https://support.safing.io\"\n};\n\n/*\n * For easier debugging in development mode, you can import the following file\n * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.\n *\n * This import should be commented out in production mode because it will have a negative impact\n * on performance if an error is thrown.\n */\nimport 'zone.js/dist/zone-error';  // Included with Angular CLI.\n"
  },
  {
    "path": "desktop/angular/src/i18n/helptexts.yaml",
    "content": "###########\n### Example\n\nmyKey:\n  title: Tipup Example\n  content: |\n    This is the Markdown formatted content.\n\n    This is a super cool, new feature that you will love!\n    It even supports markdown features like:\n    - order lists\n    - with multiple items\n\n    And :rocket: emojis\n\n    ### :tada: :facepalm:\n  url: https://docs.safing.io/?source=Portmaster\n  urlText: Show me!\n  nextKey: navMonitor\n\n##############\n### Navigation\n\nintroTipup:\n  title: Hey there!\n  content: |\n    Thanks for installing the Portmaster.\n\nintro:\n  title: Portmaster Tips\n  content: |\n    Open tips to learn how the Portmaster work.\n\n    Tips like this one are found throughout the Portmaster. With some tips you can tour an element or a feature, like this:\n  nextKey: navShield\n\nnavShield:\n  title: Status Shield & Dashboard\n  content: |\n    The shield gives you a high level overview of Portmaster's status. If turns any other color than green, look for a notification that tells you what is going on.\n\n    __Click the shield in order to open the dashboard.__\n  nextKey: navMonitor\n\nnavMonitor:\n  title: Network Monitor\n  content: |\n    Oversee and investigate everything happening on your device.\n  nextKey: navApps\n  buttons:\n    - name: Take the tour\n      action:\n        Type: open-page\n        Payload: monitor\n      nextKey: networkMonitor\n\nnavApps:\n  title: Per-App Settings\n  content: |\n    Configure per-app settings which override the global default.\n  nextKey: navMap\n  buttons:\n    - name: Take the tour\n      action:\n        Type: open-page\n        Payload: apps\n      nextKey: appsTitle\n\nnavMap:\n  title: SPN Map\n  content: |\n    View the SPN map and see how your connections are routed.\n  nextKey: navSettings\n\nnavSettings:\n  title: Global Settings\n  content: |\n    Configure global Portmaster settings.\n  nextKey: navSupport\n  buttons:\n    - name: Take the tour\n      action:\n        Type: open-page\n        Payload: settings\n      nextKey: globalSettings\n\nnavSupport:\n  title: Get Help\n  content: |\n    Report a bug, contact support or view the extended Portmaster docs.\n  nextKey: navTools\n  buttons:\n    - name: Open Page\n      action:\n        Type: open-page\n        Payload: support\n\nnavTools:\n  title: Version and Tools\n  content: |\n    View the Portmaster's version and use special actions and tools.\n  nextKey: navPause\n\nnavPause:\n  title: Pause and Resume\n  content: |\n    Temporarily disable Portmaster's protection and network monitoring.\n    \n    Choose to pause SPN only or disable all protection completely.\n  nextKey: navPower\n\nnavPower:\n  title: Shutdown and Restart\n  content: |\n    Shutdown or Restart Portmaster.\n  nextKey: uiMode\n\nuiMode:\n  title: UI Mode\n  content: |\n    Quickly change the amount of settings and information shown.\n\n    Hidden settings are still in effect. After closing the User Interface it changes back to the default.\n  buttons:\n    - name: Change Default UI Mode\n      action:\n        Type: \"open-setting\"\n        Payload:\n          Key: \"core/expertiseLevel\"\n\n############\n### Sidedash\n\npilot-widget:\n  title: Portmaster Status\n  content: |\n    This shield shows you the current state of the Portmaster:\n\n    - 🟢 all is well\n    - 🟡 something is off, please investigate\n    - 🔴 dangerous condition, respond immediately\n\n    This color code is also displayed as part of the icon in the system tray.\n\npilot-widget-NetworkRating:\n  title: Network Rating\n  content: |\n    Control your privacy even when connecting to new networks.\n\n    In the Portmaster you configure settings to be active in one environment but not in the other, like allowing sensitive connections at home but not at the public library.\n\n    The only thing you have to do is to change the network rating whenever you connect to a different network.\n  nextKey: pilot-widget-NetworkRating-Trusted\n\npilot-widget-NetworkRating-Trusted:\n  title: \"Network Rating: Trusted\"\n  content: |\n    You trust the current network to be secure and protect you.\n\n    Examples:\n     - your home network\n     - network of a trusted friends\n  nextKey: pilot-widget-NetworkRating-Untrusted\n\npilot-widget-NetworkRating-Untrusted:\n  title: \"Network Rating: Untrusted\"\n  content: |\n    You do not trust the current network and question if it will keep you secure and private.\n\n    Examples:\n     - public WiFi of a coffeeshop, a library, a train, a hotel, ...\n     - network of a non-tech-savvy relative\n  nextKey: pilot-widget-NetworkRating-Danger\n\npilot-widget-NetworkRating-Danger:\n  title: \"Network Rating: Danger\"\n  content: |\n    You think that the current network is hacked or otherwise hostile towards you.\n\n    Examples:\n     - something suspicious is going on in your home network\n\n    <small>_Note: In the \"Danger\" rating the Portmaster will become very protective. This might break functionality of apps or render them useless._</small>\n\nbroadcast-info:\n  title: Broadcast Notifications\n  content: |\n    Broadcast Notifications are public messages downloaded by the Portmaster when checking for updates.\n\n    The Portmaster then locally decides which messages should be displayed.\n  url: https://github.com/safing/portmaster/issues/703\n  urlText: Learn More\n\n# TODO\n# prompt-widget:\n#   title: Prompts\n#   content: |\n#     This is where you can more easily control the\n#     connections for the specific app for the time being.\n\n#     How to use? In App settings, search for \"Default Action\"\n#     and set it to \"Prompt\".\n\n#     Note: Don't set the \"Prompt\" setting in your browser,\n#     you will be spammed. You have been warned.\n#   nextKey: notification-widget\n\n# TODO\n# notification-widget:\n#   title: Notifications\n#   content: |\n#     This informs you with what's going on with portmaster.\n#     Ie, Updates, Errors, Warring etc\n\n#############\n### Dashboard\n\ndashboardIntro:\n  title: Dashboard\n  content: |\n    The Dashboard gives you a first overview of Portmaster's active features and what is happening on your device.\n\n    Unless noted otherwise, all graphs and statistics shown are based on what Portmaster has seen in the last 10 minutes and are refreshed every 10 seconds.\n\n########################\n### Network Monitor Page\n\nnetworkMonitor:\n  title: Network Activity\n  content: |\n    Oversee everything happening on your device.\n\n    Look at all network connections of all applications and processes that were active in the last 10 minutes. Click on any app or process to investigate further.\n\n# TODO: Wait for overview to be more useful.\n# networkMonitor-Overview:\n#   title: Monitor Overview\n#   content: |\n#     This is just a placeholder for the meantime, but this is\n#     just the Network Monitor with 3 stats on it.\n\n# TODO: Wait for revamp of status indication.\n# networkMonitor-App:\n#   title: App Activity\n#   content: |\n#     There are 3 colours. Ie, Green, Red, Gray.\n\n#     Allowed(Green)\n#     The colour green shows that all the connections are allowed in\n#     the app.\n\n#     Blocked(Red)\n#     The colour red shows that all the connections are blocked in\n#     the app.\n\n#     Allowed/Blocked(Gray)\n#     The colour gray shows that some connections are\n#     allowed and blocked in the app.\n\nnetworkMonitor-App-Focus-connection-history:\n  title: Network Activity\n  content: |\n    Monitor connections as they happen. Click on any connection to view details and to take action.\n    <br /><br />\n    <span class=\"inline-block\">\n      <span class=\"pill-container\">\n        <span class=\"counter\">2k+</span>\n        <span class=\"pill\">\n          <span class=\"percentage\"></span>\n        </span>\n      </span>\n    </span> <b>Status Summary</b>\n    <br /><br />\n    Grouped connections have a colored bar showing the total amount of connections,\n    as well as the percentage between allowed (green) and blocked/failed connections (grey).\n    <br /><br />\n    An individual connection has three states:<br />\n    <span class=\"verdict accept\"></span><span class=\"verdict accept outdated\"></span> <b>Allowed</b> <br />\n    <span class=\"block verdict\"></span><span class=\"block verdict outdated\"></span> <b>Blocked</b> <br />\n    <span class=\"verdict failed\"></span><span class=\"verdict failed outdated\"></span> <b>Failed</b> <br />\n\n    If the circle is full, your _current_ settings allowed or blocked the connection.<br />\n    If the circle is empty, _previous_ settings allowed or blocked the connection.\n    Your current settings could decide differently.\n\n########################\n### Global Settings Page\n\nglobalSettings:\n  title: Global Settings\n  content: |\n    Here you can set system-wide preferences and configure default rules for all your apps and connections.\n\n    It is easy to create a stricter global ruleset and then create exceptions in the app settings, which override the global default.\n\n#########################\n### Per-App Settings Page\n\nappsTitle:\n  title: Application Overview\n  content: |\n    All applications or processes that the Portmaster saw being active on the network are listed and can be configured here.\n\n    Apps are categorized and only appear once:\n\n    - **Active:** apps that are currently active and visible in the Network Monitor\n    - **Recently Used:** apps that were active some time within the last week\n    - **Recently Edited:** apps whose settings were edited within the last week\n    - **Other:** all other apps\n\nappSettings:\n  title: App Settings\n  content: |\n    Here you can configure app-specific settings which override the global settings.\n\n    It is easy to create a stricter global ruleset and then create exceptions in the app settings, which override the global default.\n  nextKey: appSettings-Filter\n\nappSettings-Filter:\n  title: Display Mode\n  content: |\n    Quickly change what settings are displayed:\n\n    **View Active:**<br>\n    Only show app-specific settings which override the global default.\n\n    **View All:**<br>\n    Show all settings. App-specific settings which override the global default are highlighted.\n\nappSettings-QuickSettings:\n  title: Quickly Change the Most Important Settings\n  content: |\n    __Block Connections__\n\n    Set the default action for when nothing else allows or blocks an outgoing connection.\n\n    When other settings might overwrite this, a yellow dot next to the toggle will inform you of possible exceptions.\n\n    __SPN__\n\n    Quickly enable or disable SPN for this app.\n\n    When other settings might overwrite this, a yellow dot next to the toggle will inform you of possible exceptions.\n\n    __Keep History__\n\n    Save connections in a database (on disk) in order to view and search them later.\n    \n    Changes might take a couple minutes to apply to all connections.\n\n#########################\n### Support Page\n\nsupport-page-related-issues:\n  title: Local Issue Search\n  content: |\n    Public issues are only searched for locally so no data leaves your device until you decide so.\n\n    The public GitHub issues are downloaded via our support system to prevent exposure to GitHub.\n\n#########################\n### Configuration Options\n\nspn:\n  title: Safing Privacy Network\n  content: |\n    The Safing Privacy Network (SPN) is a Portmaster Add-On that protects your identity\n    and Internet traffic from prying eyes. It spreads your connections over multiple server,\n    letting you access the Internet from many places at once in order to effectively hide\n    your tracks.\n  url: https://safing.io/spn/?source=Portmaster\n  urlText: Learn More\n\n###########################\n# Process Matching and Fingerprints\nprocess-tags:\n  title: Process Tags\n  content: Tags holds special metadata of processes and are gathered by Portmaster. You can use these tags in fingerprints to better match processes, which would otherwise be a lot more difficult or impossible to match correctly.\n"
  },
  {
    "path": "desktop/angular/src/i18n/helptexts.yaml.d.ts",
    "content": "\ndeclare module 'js-yaml-loader!*' {\n  import { Action } from \"src/app/services/notifications.types\";\n  export interface Button {\n    name: string;\n    action: Action;\n    nextKey?: string;\n  }\n\n  export interface TipUp {\n    title: string;\n    content: string;\n    url?: string;\n    urlText?: string;\n    buttons?: Button[];\n    nextKey?: string;\n  }\n  export interface HelpTexts {\n    [key: string]: TipUp;\n  }\n\n  const content: HelpTexts;\n  export default content;\n}\n"
  },
  {
    "path": "desktop/angular/src/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\">\n  <title>Portmaster</title>\n  <base href=\"/\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <meta http-equiv=\"x-dns-prefetch-control\" content=\"off\">\n\n  <link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"/assets/favicons/apple-icon-57x57.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"60x60\" href=\"/assets/favicons/apple-icon-60x60.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"/assets/favicons/apple-icon-72x72.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"76x76\" href=\"/assets/favicons/apple-icon-76x76.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"/assets/favicons/apple-icon-114x114.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"120x120\" href=\"/assets/favicons/apple-icon-120x120.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"144x144\" href=\"/assets/favicons/apple-icon-144x144.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"152x152\" href=\"/assets/favicons/apple-icon-152x152.png\">\n  <link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"/assets/favicons/apple-icon-180x180.png\">\n  <link rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/assets/favicons/android-icon-192x192.png\">\n  <link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/assets/favicons/favicon-32x32.png\">\n  <link rel=\"icon\" type=\"image/png\" sizes=\"96x96\" href=\"/assets/favicons/favicon-96x96.png\">\n  <link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/assets/favicons/favicon-16x16.png\">\n  <link rel=\"manifest\" href=\"/assets/favicons/manifest.json\">\n  <meta name=\"msapplication-TileColor\" content=\"#121213\">\n  <meta name=\"msapplication-TileImage\" content=\"/assets/favicons/ms-icon-144x144.png\">\n  <meta name=\"theme-color\" content=\"#121213\">\n</head>\n\n<body>\n  <app-root></app-root>\n</body>\n\n</html>\n"
  },
  {
    "path": "desktop/angular/src/main.ts",
    "content": "import { enableProdMode, importProvidersFrom } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n\nimport { AppModule } from './app/app.module';\nimport { environment } from './environments/environment';\nimport { INTEGRATION_SERVICE, integrationServiceFactory } from './app/integration';\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { PromptWidgetComponent } from './app/shared/prompt-list';\nimport { PromptEntryPointComponent } from './app/prompt-entrypoint/prompt-entrypoint';\nimport { provideHttpClient } from '@angular/common/http';\nimport { provideRouter } from '@angular/router';\nimport { PortmasterAPIModule } from '@safing/portmaster-api';\nimport { NotificationsService } from './app/services';\nimport { TauriIntegrationService } from './app/integration/taur-app';\n\nif (environment.production) {\n  enableProdMode();\n}\n\nif (typeof (CSS as any)['registerProperty'] === 'function') {\n  (CSS as any).registerProperty({\n    name: '--lock-color',\n    syntax: '*',\n    inherits: true,\n    initialValue: '10, 10, 10'\n  })\n}\n\nfunction handleExternalResources(e: Event) {\n  // TODO: \n  //    This code executes \"openExternal()\" when any \"<a />\" element in the app is clicked.\n  //    This could potentially be a security issue.\n  //    We should consider restricting this to only external links that belong to a certain domain (e.g., https://safing.io).\n  \n  // get click target\n  let target: HTMLElement | null = e.target as HTMLElement;\n    \n  // traverse until we reach element \"<a />\"\n  while (!!target && target.tagName !== \"A\") {\n    target = target.parentElement;\n  }\n\n  if (!!target) {\n    let href = target.getAttribute(\"href\");\n    if (href?.startsWith(\"blob\")) {\n      return\n    }\n\n    if (!!href && !href.includes(location.hostname)) {\n      e.preventDefault();\n\n      integrationServiceFactory().openExternal(href);\n    }\n  }\n}\n\nif (document.addEventListener) {\n  document.addEventListener(\"click\", handleExternalResources);\n}\n\n// load the font file but make sure to use the slimfix version\n// windows.\n{\n  // we cannot use document.writeXX here as it's not allowed to\n  // write to Document from an async loaded script.\n\n  let linkTag = document.createElement(\"link\");\n  linkTag.rel = \"stylesheet\";\n  linkTag.href = \"/assets/fonts/roboto.css\";\n  if (navigator.platform.startsWith(\"Win\")) {\n    linkTag.href = \"/assets/fonts/roboto-slimfix.css\"\n  }\n\n  document.head.appendChild(linkTag);\n}\n\n\nif (location.pathname !== \"/prompt\") {\n  // bootstrap our normal application\n  platformBrowserDynamic().bootstrapModule(AppModule)\n    .catch(err => console.error(err));\n\n} else {\n  // bootstrap the prompt interface\n  console.log(\"[INFO] Bootstrapping prompt entry point.\");\n  bootstrapApplication(PromptEntryPointComponent, {\n    providers: [\n      provideHttpClient(),\n      importProvidersFrom(PortmasterAPIModule.forRoot({\n        websocketAPI: \"ws://localhost:817/api/database/v1\",\n        httpAPI: \"http://localhost:817/api\"\n      })),\n      NotificationsService,\n      {\n        provide: INTEGRATION_SERVICE,\n        useClass: TauriIntegrationService\n      }\n    ],\n  })\n}\n\n"
  },
  {
    "path": "desktop/angular/src/polyfills.ts",
    "content": "/***************************************************************************************************\n * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.\n */\nimport '@angular/localize/init';\n/**\n * This file includes polyfills needed by Angular and is loaded before the app.\n * You can add your own extra polyfills to this file.\n *\n * This file is divided into 2 sections:\n *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.\n *   2. Application imports. Files imported after ZoneJS that should be loaded before your main\n *      file.\n *\n * The current setup is for so-called \"evergreen\" browsers; the last versions of browsers that\n * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),\n * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.\n *\n * Learn more in https://angular.io/guide/browser-support\n */\n\n/***************************************************************************************************\n * BROWSER POLYFILLS\n */\n\n/**\n * By default, zone.js will patch all possible macroTask and DomEvents\n * user can disable parts of macroTask/DomEvents patch by setting following flags\n * because those flags need to be set before `zone.js` being loaded, and webpack\n * will put import in the top of bundle, so user need to create a separate file\n * in this directory (for example: zone-flags.ts), and put the following flags\n * into that file, and then add the following code before importing zone.js.\n * import './zone-flags';\n *\n * The flags allowed in zone-flags.ts are listed here.\n *\n * The following flags will work for all browsers.\n *\n * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame\n * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick\n * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames\n *\n *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js\n *  with the following flag, it will bypass `zone.js` patch for IE/Edge\n *\n *  (window as any).__Zone_enable_cross_context_check = true;\n *\n */\n\n/***************************************************************************************************\n * Zone JS is required by default for Angular itself.\n */\nimport 'zone.js/dist/zone';  // Included with Angular CLI.\n\n\n/***************************************************************************************************\n * APPLICATION IMPORTS\n */\n"
  },
  {
    "path": "desktop/angular/src/styles.scss",
    "content": "//\n// Import our complete theme, order is important!\n//\n@import 'theme/_colors.scss';\n@import 'theme/_tailwind.scss';\n@import '@angular/cdk/overlay-prebuilt';\n@import 'theme/_button.scss';\n@import 'theme/_drag-n-drop.scss';\n@import 'theme/_inputs.scss';\n@import 'theme/_scroll.scss';\n@import 'theme/_search.scss';\n@import 'theme/_trust-level.scss';\n@import 'theme/_verdict.scss';\n@import 'theme/_typography.scss';\n@import 'theme/_markdown.scss';\n@import 'theme/_card.scss';\n@import 'theme/_breadcrumbs.scss';\n@import 'theme/_dialog.scss';\n@import 'theme/_table.scss';\n@import 'theme/_pill.scss';\n\n@import 'safing/ui/theming';\n\n*[routerlink] {\n  cursor: pointer;\n}\n\n.form-field {\n  display: flex;\n  justify-content: flext-start;\n  align-items: center;\n\n  *:not(:last-child) {\n    @apply mr-1;\n  }\n}\n\n.sidebar {\n  @apply bg-background;\n  height: 100vh;\n  flex-shrink: 0;\n  flex-grow: 0;\n  @apply px-2;\n  display: flex;\n  flex-direction: column;\n\n  &.no-scroll {\n    @apply px-0;\n  }\n}\n\n.main {\n  .content {\n    flex-grow: 1;\n    @apply pl-12;\n    @apply pr-16;\n    @apply mr-4;\n    overflow: auto;\n  }\n\n  .header {\n    display: flex;\n    width: 100%;\n    @apply pl-12;\n    @apply pr-5;\n    @apply mb-2;\n    align-items: center;\n    height: 3rem;\n    flex-shrink: 0;\n\n    &:first-of-type {\n      @apply mt-2;\n    }\n\n    >* {\n      flex-grow: 1;\n      margin: 0;\n    }\n\n    >app-expertise {\n      flex-grow: 0;\n      flex-shrink: 0;\n    }\n  }\n}\n\n.tableFixHead {\n  overflow-y: auto;\n}\n\n.tableFixHead thead th {\n  position: sticky;\n  top: 0;\n}\n\n\nfa-icon.tipup,\nfa-icon[icon=\"question-circle\"],\nfa-icon[icon=\"question\"] {\n  max-width: 10px;\n  max-height: 10px;\n  opacity: 0.8;\n  display: inline-block;\n  font-size: 0.75rem;\n  color: rgb(250 250 250 / 55%);\n  margin-left: 3px;\n\n  &:hover {\n    opacity: unset;\n  }\n}\n\n.tipup-preview {\n  transition: all .25s ease-in-out !important;\n  opacity: 0 !important;\n\n  &.visible {\n    opacity: 1 !important;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/test.ts",
    "content": "// This file is required by karma.conf.js and loads recursively all the .spec and framework files\n\nimport 'zone.js/dist/zone-testing';\nimport { getTestBed } from '@angular/core/testing';\nimport {\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting\n} from '@angular/platform-browser-dynamic/testing';\n\n// First, initialize the Angular testing environment.\ngetTestBed().initTestEnvironment(\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting()\n);\n"
  },
  {
    "path": "desktop/angular/src/theme/_breadcrumbs.scss",
    "content": "h4.breadcrumbs {\n  * {\n    margin-left : 0.125rem;\n    margin-right: 0.125rem;\n  }\n\n  span {\n    outline: none;\n    @apply text-secondary;\n\n    &:hover {\n      @apply text-primary;\n      text-decoration: underline;\n    }\n\n    &:last-of-type {\n      @apply text-primary;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_button.scss",
    "content": "@layer components {\n  button {\n    @apply text-xs;\n    @apply bg-buttons-dark;\n    @apply p-1;\n    @apply px-4;\n    @apply capitalize;\n    @apply rounded-sm;\n    @apply font-medium;\n    @apply focus:underline focus:underline-offset-4;\n\n    user-select: none;\n    outline: none;\n    cursor: pointer;\n    font-size: 0.7rem;\n\n    &.btn-outline {\n      background: transparent;\n      opacity: 0.6;\n    }\n\n    &:hover {\n      &:not(.outline):not(.bg-blue) {\n        @apply bg-buttons-light;\n      }\n\n      opacity: 1;\n    }\n\n    &:disabled {\n      @apply cursor-default;\n      opacity: 0.3;\n\n      &:not(.outline):hover {\n        @apply bg-buttons-dark;\n      }\n    }\n\n    &:active {\n      @apply bg-buttons-dark;\n    }\n\n    &:hover,\n    &:focus,\n    &:active {\n      outline: none;\n    }\n  }\n\n  .info-circle {\n    width: 18px;\n    height: 18px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    font-size: 0.8em;\n    @apply rounded-full;\n    @apply bg-buttons-dark;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_card.scss",
    "content": ".card-header {\n  display        : flex;\n  align-items    : center;\n  cursor         : pointer;\n  outline        : none;\n  justify-content: space-between;\n  @apply text-xs;\n  @apply font-medium;\n  margin-top             : 5px;\n  padding-top            : 0.65rem;\n  padding-bottom         : 0.65rem;\n  padding-left           : 0.65rem;\n  padding-right          : 0.65rem;\n  border-top-left-radius : 4px;\n  border-top-right-radius: 4px;\n  background-color       : #202020e0;\n\n  &:not(.open) {\n    border-radius: 4px;\n  }\n\n  &>*:not(:last-child) {\n    @apply mr-1;\n  }\n\n  &>app-icon:not(:last-child) {\n    @apply mr-2;\n  }\n\n  &:hover {\n    background-color: #292929b0;\n  }\n\n  &.active {\n    background-color: #303030;\n\n    app-count-indicator {\n      background-color: #474747;\n\n      div.state {\n        background-color: #5c5c5c;\n\n      }\n    }\n  }\n\n  &>app-icon {\n    --app-icon-size: 22px;\n  }\n\n  .card-title {\n    flex-grow    : 1;\n    overflow     : hidden;\n    white-space  : nowrap;\n    text-overflow: ellipsis;\n    font-size    : 0.7rem;\n    font-weight  : 600;\n    color        : #cacaca;\n    margin-left  : 3px;\n\n    .card-sub-title {\n      display   : block;\n      font-size : 0.8em;\n      margin-top: -3px;\n      @apply text-tertiary;\n      text-overflow: ellipsis;\n      overflow     : hidden;\n    }\n  }\n\n  .card-actions {\n    @apply mr-2;\n\n    span {\n      display   : inline-block;\n      text-align: center;\n      min-width : 5rem;\n      @apply px-2;\n      @apply rounded;\n      @apply text-xs;\n\n      padding-top   : 0.1rem;\n      padding-bottom: 0.1rem;\n\n      // TODO(ppacher): this is actually a \"toggle-switch\" / radio-button\n      // component. make it one.\n      &.selected {\n        @apply bg-buttons-dark;\n      }\n\n      &:hover {\n        @apply bg-buttons-light;\n      }\n    }\n  }\n}\n\n.card-content {\n  @apply bg-cards-secondary;\n  @apply rounded-b;\n\n  @apply py-2;\n  @apply px-4;\n  @apply mb-2;\n\n  display        : flex;\n  flex-direction : column;\n  flex           : 1 0;\n  justify-content: space-between;\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_colors.scss",
    "content": "/**\n * For debugging purposes, we define all our colors as\n * CSS3 variables and make tailwind put a reference to those\n * variables. This way we will see the variable name in the\n * developer-tools instead of the hex/rgba values.\n *\n * You're welcome 🚀\n */\n:root {\n  --background: #121213;\n\n  --text-primary  : #ffffff;\n  --text-secondary: #ababab;\n  --text-tertiary : #888888;\n\n  --cards-primary      : #222222;\n  --cards-secondary    : #1b1b1b;\n  --cards-secondary-rgb: 27, 27, 27;\n  --cards-tertiary     : #2c2c2c;\n\n  --button-icon : #ababab;\n  --button-dark : #343434;\n  --button-light: #474747;\n\n  --info-green     : #3df57f;\n  --info-red       : #d12e2e;\n  --info-gray      : #ababab;\n  --info-blue      : #4e97fa;\n  --info-yellow    : #e9d31d;\n  --info-yellow-rgb: 233, 211, 29;\n\n  --protection-ok-primary  : rgb(29, 233, 102);\n  --protection-ok-secondary: rgb(24, 130, 61);\n  --protection-ok-tertiary : rgb(20, 61, 36);\n\n  --protection-warn-primary  : rgb(233, 216, 29);\n  --protection-warn-secondary: rgb(130, 121, 24);\n  --protection-warn-tertiary : rgb(61, 58, 20);\n\n  --protection-fail-primary  : rgb(224, 29, 29);\n  --protection-fail-secondary: rgb(129, 24, 24);\n  --protection-fail-tertiary : rgb(61, 20, 20);\n\n  --portmaster-plus: #2fcfae;\n  --portmaster-pro: #029ad0;\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_dialog.scss",
    "content": ".dialog-screen-backdrop {\n  backdrop-filter : blur(10px);\n  background-color: rgba(#000000, 0.7);\n}\n\n.dialog-screen-backdrop-light {\n  backdrop-filter : blur(3px);\n  background-color: rgba(#000000, 0.4);\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_drag-n-drop.scss",
    "content": ".cdk-drag {\n  .widget {\n    user-select: none;\n\n    fa-icon {\n      opacity: 1;\n    }\n  }\n}\n\n.cdk-drag-placeholder {\n  user-select: none;\n  position: relative;\n  opacity: 0.5;\n  box-sizing: border-box;\n  cursor: grabbing !important;\n  @apply border-2;\n  @apply rounded;\n  @apply border-dashed;\n  border-color: #292929;\n}\n\n.cdk-drag-animating {\n  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n  user-select: none;\n}\n\n.cdk-drag-preview {\n  user-select: none;\n  box-sizing: border-box;\n  cursor: grabbing !important;\n\n  @apply rounded;\n  @apply border-2;\n  @apply border-dashed;\n  border-color: #292929;\n  @apply text-primary;\n}\n\n.cdk-drag-handle {\n  cursor: grab !important;\n}\n\n.document-grabbing {\n  cursor: grabbing !important;\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_inputs.scss",
    "content": "input:not([type=\"checkbox\"]),\ntextarea,\nselect {\n  @apply outline-none w-full block;\n  @apply bg-gray-300 rounded;\n  @apply text-xs text-primary;\n  @apply border border-gray-300;\n  @apply rounded-sm font-medium;\n  @apply p-1.5;\n\n  transition: border cubic-bezier(0.175, 0.885, 0.32, 1.275) .3s;\n\n  &::placeholder {\n    @apply text-secondary text-xxs;\n  }\n\n  &:active,\n  &:focus {\n    @apply text-primary;\n    @apply bg-gray-500 border-gray-400 bg-opacity-75 border-opacity-75;\n\n    &::placeholder {\n      @apply text-tertiary;\n    }\n  }\n}\n\n\ninput,\ntextarea,\nselect {\n  .ng-invalid {\n    @apply border-red;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_markdown.scss",
    "content": "// Mostly taken from https://github.com/sindresorhus/github-markdown-css/blob/gh-pages/license\n\nmarkdown {\n  width: 100%;\n  @apply p-2;\n  color: white !important;\n  @apply font-normal;\n\n  details {\n    display: block;\n  }\n\n  summary {\n    display: list-item;\n  }\n\n  a {\n    background-color: initial;\n  }\n\n  a:active,\n  a:hover {\n    outline-width: 0;\n  }\n\n  strong {\n    font-weight: inherit;\n    font-weight: bolder;\n  }\n\n  h1 {\n    font-size: 2rem;\n    margin: .67rem 0;\n  }\n\n  img {\n    border-style: none;\n  }\n\n  code,\n  kbd,\n  pre {\n    font-family: monospace, monospace;\n    font-size: 1rem;\n  }\n\n  hr {\n    box-sizing: initial;\n    height: 0;\n    overflow: visible;\n  }\n\n  input {\n    font: inherit;\n    margin: 0;\n  }\n\n  input {\n    overflow: visible;\n  }\n\n  [type=checkbox] {\n    box-sizing: border-box;\n    padding: 0;\n  }\n\n  * {\n    box-sizing: border-box;\n  }\n\n  input {\n    font-family: inherit;\n    font-size: inherit;\n    line-height: inherit;\n  }\n\n  a {\n    text-decoration: none;\n  }\n\n  a:hover {\n    text-decoration: underline;\n  }\n\n  strong {\n    font-weight: 600;\n  }\n\n  hr {\n    height: 0;\n    margin: 15px 0;\n    overflow: hidden;\n    background: transparent;\n    border: 0;\n    border-bottom: 1px solid #dfe2e5;\n  }\n\n  hr:after,\n  hr:before {\n    display: table;\n    content: \"\";\n  }\n\n  hr:after {\n    clear: both;\n  }\n\n  table {\n    border-spacing: 0;\n    border-collapse: collapse;\n  }\n\n  td,\n  th {\n    padding: 0;\n  }\n\n  details summary {\n    cursor: pointer;\n  }\n\n  kbd {\n    display: inline-block;\n    padding: 3px 5px;\n    font: 11px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;\n    line-height: 10px;\n    vertical-align: middle;\n    background-color: #fafbfc;\n    border: 1px solid #d1d5da;\n    border-radius: 3px;\n    box-shadow: inset 0 -1px 0 #d1d5da;\n  }\n\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6 {\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n\n  h1 {\n    font-size: 32px;\n  }\n\n  h1,\n  h2 {\n    font-weight: 600;\n  }\n\n  h2 {\n    font-size: 24px;\n  }\n\n  h3 {\n    font-size: 20px;\n  }\n\n  h3,\n  h4 {\n    font-weight: 600;\n  }\n\n  h4 {\n    font-size: 16px;\n  }\n\n  h5 {\n    font-size: 14px;\n  }\n\n  h5,\n  h6 {\n    font-weight: 600;\n  }\n\n  h6 {\n    font-size: 12px;\n  }\n\n  p {\n    margin-top: 0;\n    margin-bottom: 10px;\n  }\n\n  blockquote {\n    margin: 0;\n  }\n\n  ol,\n  ul {\n    padding-left: 0;\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n\n  ol {\n    list-style-type: decimal;\n  }\n\n  ul {\n    list-style-type: circle;\n  }\n\n  ol ol,\n  ul ol {\n    list-style-type: lower-roman;\n  }\n\n  ol ol ol,\n  ol ul ol,\n  ul ol ol,\n  ul ul ol {\n    list-style-type: lower-alpha;\n  }\n\n  dd {\n    margin-left: 0;\n  }\n\n  code,\n  pre {\n    font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;\n    font-size: 12px;\n  }\n\n  pre {\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n\n  input::-webkit-inner-spin-button,\n  input::-webkit-outer-spin-button {\n    margin: 0;\n    -webkit-appearance: none;\n    appearance: none;\n  }\n\n  a:not([href]) {\n    color: inherit;\n    text-decoration: none;\n  }\n\n  blockquote,\n  details,\n  dl,\n  ol,\n  p,\n  pre,\n  table,\n  ul {\n    margin-top: 0;\n    // be carefully when ever changing this!\n    margin-bottom: 16px;\n  }\n\n  hr {\n    height: .25rem;\n    padding: 0;\n    margin: 24px 0;\n    background-color: #e1e4e8;\n    border: 0;\n  }\n\n  blockquote {\n    padding: 0 1rem;\n    border-left: .25rem solid #dfe2e5;\n  }\n\n  blockquote>:first-child {\n    margin-top: 0;\n  }\n\n  blockquote>:last-child {\n    margin-bottom: 0;\n  }\n\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6 {\n    margin-top: 24px;\n    margin-bottom: 16px;\n    font-weight: 600;\n    line-height: 1.25;\n  }\n\n  h1 {\n    font-size: 2rem;\n  }\n\n  h1,\n  h2 {\n    padding-bottom: .3rem;\n    border-bottom: 1px solid #eaecef;\n  }\n\n  h2 {\n    font-size: 1.5rem;\n  }\n\n  h3 {\n    font-size: 1.25rem;\n  }\n\n  h4 {\n    font-size: 1rem;\n  }\n\n  h5 {\n    font-size: .875rem;\n  }\n\n  h6 {\n    font-size: .85rem;\n  }\n\n  ol,\n  ul {\n    padding-left: 2rem;\n  }\n\n  ol ol,\n  ol ul,\n  ul ol,\n  ul ul {\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n\n  li {\n    word-wrap: break-all;\n  }\n\n  li>p {\n    margin-top: 16px;\n  }\n\n  li+li {\n    margin-top: .25rem;\n  }\n\n  dl {\n    padding: 0;\n  }\n\n  dl dt {\n    padding: 0;\n    margin-top: 16px;\n    font-size: 1rem;\n    font-style: italic;\n    font-weight: 600;\n  }\n\n  dl dd {\n    padding: 0 16px;\n    margin-bottom: 16px;\n  }\n\n  table {\n    display: block;\n    width: 100%;\n    overflow: auto;\n  }\n\n  table th {\n    font-weight: 600;\n  }\n\n  table td,\n  table th {\n    padding: 6px 13px;\n    border: 1px solid #dfe2e5;\n  }\n\n  table tr {\n    background-color: #fff;\n    border-top: 1px solid #c6cbd1;\n  }\n\n  table tr:nth-child(2n) {\n    background-color: #f6f8fa;\n  }\n\n  img {\n    max-width: 100%;\n    box-sizing: initial;\n    background-color: #fff;\n  }\n\n  img[align=right] {\n    padding-left: 20px;\n  }\n\n  img[align=left] {\n    padding-right: 20px;\n  }\n\n  code {\n    padding: .2rem .4rem;\n    margin: 0;\n    font-size: 95%;\n    background-color: rgba(27, 31, 35, .05);\n    border-radius: 3px;\n  }\n\n  pre {\n    word-wrap: normal;\n  }\n\n  pre>code {\n    padding: 0;\n    margin: 0;\n    font-size: 100%;\n    word-break: normal;\n    white-space: pre;\n    background: transparent;\n    border: 0;\n  }\n\n  .highlight {\n    margin-bottom: 16px;\n  }\n\n  .highlight pre {\n    margin-bottom: 0;\n    word-break: normal;\n  }\n\n  .highlight pre,\n  pre {\n    padding: 16px;\n    overflow: auto;\n    font-size: 90%;\n    line-height: 1.45;\n    background-color: #f6f8fa;\n    border-radius: 3px;\n  }\n\n  pre code {\n    display: inline;\n    max-width: auto;\n    padding: 0;\n    margin: 0;\n    overflow: visible;\n    line-height: inherit;\n    word-wrap: normal;\n    background-color: initial;\n    border: 0;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_pill.scss",
    "content": "@import 'mixins/_pill.scss';\n\n.pill-container {\n  @include pill-container;\n  @apply pl-2;\n  @apply bg-buttons-dark;\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_scroll.scss",
    "content": "html,\nbody {\n  scroll-behavior: smooth;\n}\n\n::-webkit-scrollbar {\n  @apply bg-buttons-dark;\n  width: 4px;\n}\n\n::-webkit-scrollbar-thumb {\n  @apply bg-buttons-light;\n  @apply rounded;\n  cursor: pointer;\n}\n\n.no-scroll {\n  overflow: hidden;\n}\n\n.scrollable {\n  width     : 100%;\n  max-height: 100%;\n  overflow  : auto;\n  overflow-x: hidden;\n  flex-grow : 1;\n  @apply px-3;\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_search.scss",
    "content": "em.search-result {\n  @apply text-background;\n  @apply bg-yellow;\n  @apply border;\n  @apply border-yellow;\n  @apply rounded-sm;\n\n  text-decoration: none;\n  font-style: inherit;\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_table.scss",
    "content": "table:not(.custom) {\n  width: 100%;\n\n  th,\n  tr,\n  td {\n    @apply text-xs;\n  }\n\n  th {\n    text-align: left;\n    @apply text-secondary;\n    z-index: 1;\n  }\n\n  td,\n  th {\n    @apply p-2;\n    @apply font-medium;\n  }\n\n  tr:nth-child(even) {\n    @apply bg-cards-secondary;\n    --bg-opacity: 0.5;\n  }\n\n  tr:nth-child(odd) {\n    @apply bg-cards-tertiary;\n    --bg-opacity: 0.6;\n  }\n\n  tr.cdk-header-row th {\n    @apply bg-cards-tertiary;\n    --bg-opacity: 1;\n\n    // we cannot use borders directly due to\n    // the sticky header. Use a box-shadow to\n    // simulate a border.\n    box-shadow: 0 2px rgba(0, 0, 0, 0.3);\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_tailwind.scss",
    "content": "/** The tailwind post-processor will inject all tailwind styles here **/\n@import 'tailwindcss/base';\n@import 'tailwindcss/components';\n@import 'tailwindcss/utilities';\n"
  },
  {
    "path": "desktop/angular/src/theme/_trust-level.scss",
    "content": "span.trust-level {\n  display    : inline-block;\n  position   : relative;\n  width      : 6px;\n  user-select: none;\n  overflow   : visible;\n\n  &~* {\n    @apply ml-2;\n  }\n\n  &:before {\n    content      : \"\";\n    display      : block;\n    position     : relative;\n    height       : 6px;\n    width        : 6px;\n    top          : -1px;\n    left         : 0px;\n    border-radius: 50%;\n  }\n\n  &.centered:before {\n    top: 0px;\n  }\n\n  &:before {\n    background-color: var(--bg-color);\n    @apply shadow-inner-xs;\n  }\n\n  &.pulse:before {\n    animation : pulsate-trust 1s ease-out infinite;\n    box-shadow: 0 0 10px var(--glow-color);\n  }\n\n  &.off {\n    --bg-color  : theme('colors.info.gray');\n    --glow-color: theme('colors.info.gray');\n  }\n\n  &.auto {\n    --bg-color  : theme('colors.info.blue');\n    --glow-color: theme('colors.info.blue');\n  }\n\n  &.low {\n    --bg-color  : theme('colors.info.green');\n    --glow-color: theme('colors.info.green');\n  }\n\n  &.medium {\n    --bg-color  : theme('colors.info.yellow');\n    --glow-color: theme('colors.info.yellow');\n  }\n\n  &.high {\n    --bg-color  : theme('colors.info.red');\n    --glow-color: theme('colors.info.red');\n  }\n}\n\n@keyframes pulsate-trust {\n  100% {\n    opacity: 0.8;\n  }\n\n  0% {\n    background: var(--glow-color);\n    box-shadow: 0 0 0 var(--glow-color);\n    opacity   : 1;\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_typography.scss",
    "content": "html,\nbody {\n  font-family: 'Roboto', sans-serif;\n  @apply text-primary;\n  @apply font-medium;\n}\n\nbody,\n.primary-text,\n.secondary-text {\n  @apply text-xs;\n  @apply font-medium;\n}\n\nlabel,\n.secondary-text {\n  @apply text-secondary;\n}\n\n.primary-text {\n  @apply text-primary;\n}\n\n.tertiary-text {\n  @apply text-tertiary;\n}\n\nh1,\nh2,\nh3 {\n  @apply text-primary;\n}\n\nh1 {\n  display: block;\n\n  @apply mb-1;\n  @apply text-xl;\n  @apply font-normal;\n  @apply mb-2;\n}\n\nh2 {\n  @apply p-2;\n  @apply ml-2;\n  @apply text-lg;\n  @apply font-medium;\n  letter-spacing: -0.01rem;\n}\n\nh3 {\n  @apply mb-1;\n  @apply text-base;\n  @apply font-medium;\n}\n\nh4 {\n  @apply text-xs;\n  @apply font-medium;\n  @apply text-tertiary;\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/_verdict.scss",
    "content": "span.verdict {\n  display     : inline-block;\n  position    : relative;\n  width       : 12px;\n  height      : 9px;\n  align-self  : center;\n  justify-self: center;\n  user-select : none;\n  overflow    : visible;\n\n  &:before {\n    content         : \"\";\n    display         : block;\n    position        : absolute;\n    height          : 8px;\n    width           : 8px;\n    top             : 0px;\n    left            : 0px;\n    border-radius   : 50%;\n    background-color: var(--bg-color);\n    border          : 1px solid var(--bg-color);\n    @apply shadow-inner-xs;\n  }\n\n  &.failed {\n    --bg-color: theme('colors.info.yellow');\n  }\n\n  &.accept,\n  &.reroutetons,\n  &.reroutetotunnel {\n    --bg-color: theme('colors.info.green');\n  }\n\n  &.block,\n  &.drop {\n    --bg-color: theme('colors.info.red');\n  }\n\n  &.outdated {\n    &:before {\n      background-color: transparent;\n      border-color    : var(--bg-color);\n      opacity         : .85;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme/mixins/_pill.scss",
    "content": "@mixin pill-container {\n  display        : flex;\n  width          : auto;\n  height         : 18px;\n  align-items    : center;\n  justify-content: flex-end;\n  font-size      : 0.6rem;\n  line-height    : 18px;\n\n  border-radius: 0.5rem;\n  transform    : scale(0.95);\n\n  .counter {\n    flex-grow    : 1;\n    display      : inline-block;\n    text-align   : right;\n    padding-right: 4px;\n    padding-left : 2px;\n    color        : #999999ee;\n    font-size    : 0.65rem;\n    font-weight  : 800;\n    width        : max-content;\n  }\n\n  .pill {\n    display         : inline-block;\n    width           : 29px;\n    height          : 5px;\n    background-color: #686868;\n    border-radius   : 1rem;\n    overflow        : hidden;\n    margin-left     : 0.2rem;\n    margin-right    : 0.6rem;\n\n    .percentage {\n      display         : block;\n      height          : 100%;\n      width           : 75%;\n      background-color: #21ad58;\n    }\n  }\n}\n"
  },
  {
    "path": "desktop/angular/src/theme.less",
    "content": "\n// Custom Theming for NG-ZORRO\n// For more information: https://ng.ant.design/docs/customize-theme/en\n@import \"../node_modules/ng-zorro-antd/ng-zorro-antd.dark.less\";\n"
  },
  {
    "path": "desktop/angular/tailwind.config.js",
    "content": "const plugin = require(\"tailwindcss/plugin\");\n\nmodule.exports = {\n  content: [\n    \"./src/**/*.{html,scss,css,ts}\",\n    \"./projects/**/*.{html,scss,css,ts}\",\n  ],\n  theme: {\n    colors: {\n      transparent: \"transparent\",\n      current: \"currentColor\",\n      white: \"#ffffff\",\n      background: \"#121213\",\n\n      gray: {\n        100: \"#131111\",\n        200: \"#1b1b1b\",\n        300: \"#222222\",\n        400: \"#2c2c2c\",\n        500: \"#474747\",\n        600: \"#888888\",\n        700: \"#ababab\",\n        DEFAULT: \"#ababab\",\n      },\n\n      green: {\n        100: \"#143d24\",\n        200: \"#18823d\",\n        300: \"#1de966\",\n        DEFAULT: \"#18823d\",\n      },\n\n      red: {\n        100: \"#3d1414\",\n        200: \"#811818\",\n        300: \"#e01d1d\",\n        DEFAULT: \"#d12e2e\",\n      },\n\n      yellow: {\n        100: \"#3d3a14\",\n        200: \"#827918\",\n        300: \"#e9d81d\",\n        DEFAULT: \"#e9d81d\",\n      },\n\n      cyan: {\n        100: \"#b2ebf2\",\n        200: \"#80deea\",\n        300: \"#4dd0e1\",\n        400: \"#26c6da\",\n        500: \"#00bcd4\",\n        600: \"#00acc1\",\n        700: \"#0097a7\",\n        800: \"#00838f\",\n        900: \"#006064\",\n      },\n\n      deepPurple: {\n        50: \"#ede7f6\",\n        100: \"#d1c4e9\",\n        200: \"#b39ddb\",\n        300: \"#9575cd\",\n        400: \"#7e57c2\",\n        500: \"#673ab7\",\n        600: \"#5e35b1\",\n        700: \"#512da8\",\n        800: \"#4527a0\",\n        900: \"#311b92\",\n      },\n\n      blue: {\n        DEFAULT: \"#4e97fa\",\n      },\n\n      // Legacy color definitions\n\n      // The overall application background color\n\n      // Text shades\n      cards: {\n        primary: \"var(--cards-primary)\",\n        secondary: \"var(--cards-secondary)\",\n        tertiary: \"var(--cards-tertiary)\",\n      },\n\n      buttons: {\n        icon: \"var(--button-icon)\",\n        dark: \"var(--button-dark)\",\n        light: \"var(--button-light)\",\n      },\n\n      info: {\n        green: \"var(--info-green)\",\n        red: \"var(--info-red)\",\n        gray: \"var(--info-gray)\",\n        blue: \"var(--info-blue)\",\n        yellow: \"var(--info-yellow)\",\n      },\n    },\n    textColor: (theme) => {\n      return {\n        primary: theme(\"colors.white\"),\n        secondary: theme(\"colors.gray.700\"),\n        tertiary: theme(\"colors.gray.600\"),\n\n        ...theme(\"colors\"),\n      };\n    },\n    extend: {\n      boxShadow: {\n        xs: \"0 0 0 1px rgba(0, 0, 0, 0.05)\",\n        \"inner-xs\": \"inset 0 2px 4px 0 rgba(0, 0, 0, 0.16)\",\n      },\n      fontSize: {\n        xxs: \"0.7rem\",\n      },\n    },\n  },\n  plugins: [\n    plugin(function ({ addVariant, theme }) {\n      Object.keys(theme(\"screens\")).forEach((key) => {\n        addVariant(\"sfng-\" + key, \".min-width-\" + theme(\"screens\")[key] + \" &\");\n      });\n    }),\n  ],\n};\n"
  },
  {
    "path": "desktop/angular/tsconfig.app.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./out-tsc/app\",\n    \"types\": [\n    ]\n  },\n  \"files\": [\n    \"src/main.ts\",\n    \"src/polyfills.ts\"\n  ],\n  \"include\": [\n    \"src/**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/angular/tsconfig.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@safing/portmaster-api\": [\n        \"dist-lib/safing/portmaster-api\"\n      ],\n      \"@safing/ui\": [\n        \"dist-lib/safing/ui\"\n      ]\n    },\n    \"baseUrl\": \"./\",\n    \"outDir\": \"./dist/out-tsc\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"sourceMap\": true,\n    \"declaration\": false,\n    \"downlevelIteration\": true,\n    \"experimentalDecorators\": true,\n    \"moduleResolution\": \"node\",\n    \"importHelpers\": true,\n    \"target\": \"ES2022\",\n    \"module\": \"es2020\",\n    \"lib\": [\n      \"es2018\",\n      \"dom\"\n    ],\n    \"types\": [\n      \"./src/electron-app.d.ts\",\n      \"chrome\"\n    ],\n    \"useDefineForClassFields\": false\n  },\n  \"angularCompilerOptions\": {\n    \"strictInjectionParameters\": true,\n    \"strictTemplates\": true\n  }\n}\n"
  },
  {
    "path": "desktop/angular/tsconfig.spec.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./out-tsc/spec\",\n    \"types\": [\n      \"jasmine\"\n    ]\n  },\n  \"files\": [\n    \"src/test.ts\",\n    \"src/polyfills.ts\"\n  ],\n  \"include\": [\n    \"src/**/*.spec.ts\",\n    \"src/**/*.d.ts\",\n    \"src/app/widgets/status-widget-factory/settings.ts\"\n  ]\n}\n"
  },
  {
    "path": "desktop/tauri/.cargo/config.toml",
    "content": "[target.aarch64-unknown-linux-gnu]\nlinker = \"aarch64-linux-gnu-gcc\"\nrustflags = [\"-C\", \"link-args=-L/usr/lib/aarch64-linux-gnu/\"]\n\n[target.armv7-unknown-linux-gnueabihf]\nlinker = \"arm-linux-gnueabihf-gcc\"\nrustflags = [\"-C\", \"link-args=-L/usr/lib/arm-linux-gnueabihf/\"]\n"
  },
  {
    "path": "desktop/tauri/.vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n\n    // How to debug Tauri project:\n    //    https://v2.tauri.app/develop/debug/\n    //\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n      {\n        \"type\": \"lldb\",                 // `vscode-lldb` extension has to be installed (https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)\n        \"request\": \"launch\",\n        \"name\": \"Debug Dev\",\n        \"cargo\": {\"args\": [\"build\", \"--manifest-path=./src-tauri/Cargo.toml\", \"--no-default-features\"]},\n        \"env\": { \"TAURI_PM_URL\": \"http://127.0.0.1:817\" }\n      },\n      {\n        \"type\": \"lldb\",\n        \"request\": \"launch\",\n        \"name\": \"Debug Prod\",\n        \"cargo\": {\"args\": [\"build\", \"--manifest-path=./src-tauri/Cargo.toml\", \"--release\"]},\n      },\n      {\n        \"name\": \"Debug Dev (VS Win Debugger)\",\n        \"type\": \"cppvsdbg\",\n        \"request\": \"launch\",\n        \"program\": \"${workspaceRoot}/src-tauri/target/debug/portmaster.exe\",\n        \"cwd\": \"${workspaceRoot}\",\n        \"preLaunchTask\": \"build:debug\",\n        \"env\": { \"TAURI_PM_URL\": \"http://127.0.0.1:817\" }\n      }\n    ]\n  }"
  },
  {
    "path": "desktop/tauri/.vscode/tasks.json",
    "content": "{\n    // See https://go.microsoft.com/fwlink/?LinkId=733558\n    // for the documentation about the tasks.json format\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n      {\n        \"label\": \"build:debug\",\n        \"type\": \"cargo\",\n        \"command\": \"build\",\n        \"args\": [\"--manifest-path=./src-tauri/Cargo.toml\", \"--no-default-features\"]\n      }\n    ]\n  }"
  },
  {
    "path": "desktop/tauri/src-tauri/.gitignore",
    "content": "# Generated by Cargo\n# will have compiled files and executables\n/target/\n"
  },
  {
    "path": "desktop/tauri/src-tauri/Cargo.toml",
    "content": "[package]\nname = \"portmaster\"\nversion = \"2.1.8\"\ndescription = \"Portmaster UI\"\nauthors = [\"Safing\"]\nlicense = \"\"\nrepository = \"\"\ndefault-run = \"portmaster\"\nedition = \"2021\"\nrust-version = \"1.64\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[build-dependencies]\ntauri-build = { version = \"2.0.5\", features = [] }\n\n[dependencies]\n# Tauri\ntauri = { version = \"2.2.5\", features = [\"tray-icon\", \"image-png\", \"config-json5\", \"devtools\"] }\ntauri-plugin-shell = \"2.2.1\"\ntauri-plugin-dialog = \"2.2.0\"\ntauri-plugin-clipboard-manager = \"2.1.11\"\ntauri-plugin-os = \"2.2.0\"\ntauri-plugin-single-instance = \"2.2.1\"\ntauri-plugin-notification = \"2.2.1\"\ntauri-plugin-log = \"2.2.1\"\ntauri-plugin-window-state = \"2.2.1\"\ntauri-plugin-websocket = \"2\"\n\nclap_lex = \"0.7.2\"\n\n# General\nserde_json = \"1.0\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nfutures-util = { version = \"0.3\", features = [\"sink\"] }\ndirs = \"1.0\"\nrust-ini = \"0.20.0\"\ndataurl = \"0.1.2\"\nuuid = \"1.6.1\"\nlazy_static = \"1.4.0\"\ntokio = { version = \"1.44.2\", features = [\"macros\"] }\ncached = \"0.46.1\"\nnotify-rust = \"4.10.0\"\nassert_matches = \"1.5.0\"\nbytes = \"1.5\"\ntokio-websockets = { version = \"0.5.0\", features = [\"client\", \"ring\", \"rand\"] }\nsha = \"1.0.3\"\nhttp = \"1.0.0\"\nurl = \"2.5.0\"\nthiserror = \"1.0\"\nlog = \"0.4.21\"\nreqwest = { version = \"0.12\", features = [\"cookies\", \"json\"] }\n\nrfd = { version = \"*\", default-features = false, features = [ \"tokio\", \"gtk3\", \"common-controls-v6\" ] }\nopen = \"5.1.3\"\nchrono = { version = \"0.4\", features = [\"serde\"] }\n\ndark-light = \"2.0.0\"\n\n# Linux only\n[target.'cfg(target_os = \"linux\")'.dependencies]\nglib = \"0.18.4\"\ngtk-sys = \"0.18.0\"\nglib-sys = \"0.18.1\"\ngdk-pixbuf = \"0.18.3\"\ngdk-pixbuf-sys = \"0.18.0\"\ngio-sys = \"0.18.1\"\n\n# Windows only\n[target.'cfg(target_os = \"windows\")'.dependencies]\nwindows-service = \"0.6.0\"\nwindows = { version = \"0.54.0\", features = [\"Win32_Foundation\", \"Win32_UI_Shell\", \"Win32_UI_WindowsAndMessaging\"] }\ntauri-winrt-notification = \"0.3.0\"\n\n[dev-dependencies]\nwhich = \"6.0.0\"\ngtk = \"0.18\"\nctor = \"0.2.6\"\n\n[features]\n# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.\n# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.\n# DO NOT REMOVE!!\ncustom-protocol = [ \"tauri/custom-protocol\" ]\n\n[package.metadata.clippy]\nallow = [\"clippy::collapsible_else_if\"]\n"
  },
  {
    "path": "desktop/tauri/src-tauri/Cross.toml",
    "content": "[target.aarch64-unknown-linux-gnu]\nimage = \"ghcr.io/cross-rs/aarch64-unknown-linux-gnu:main\"\n\npre-build = [\n    \"dpkg --add-architecture $CROSS_DEB_ARCH\", \n    \"apt-get update && apt-get --assume-yes install libssl-dev:$CROSS_DEB_ARCH libjavascriptcoregtk-4.0-dev:$CROSS_DEB_ARCH librsvg2-dev libayatana-appindicator3-dev libwebkit2gtk-4.0-dev libsoup2.4-dev libgtk-3-dev\"\n]\n"
  },
  {
    "path": "desktop/tauri/src-tauri/README.md",
    "content": "# Update Tauri guide\n\nCheck latest versions of tauri packages and update them accordingly (https://crates.io/)  \nCargo.toml:  \n```toml\n[build-dependencies]\ntauri-build = { version = \"2.0.0-beta.19\", features = [] } # Update to latest\n\n[dependencies]\n# Tauri\ntauri = { version = \"2.0.0-beta.24\", features = [\"tray-icon\", \"image-png\", \"config-json5\", \"devtools\"] } # Update to latest\ntauri-plugin-shell = \"2.0.0-beta\"\ntauri-plugin-dialog = \"2.0.0-beta\"\ntauri-plugin-clipboard-manager = \"2.0.0-beta\"\ntauri-plugin-os = \"2.0.0-beta\"\ntauri-plugin-single-instance = \"2.0.0-beta\"\ntauri-plugin-cli = \"2.0.0-beta\"\ntauri-plugin-notification = \"2.0.0-beta\"\ntauri-plugin-log = \"2.0.0-beta\"\ntauri-plugin-window-state = \"2.0.0-beta\"\n\ntauri-cli = \"2.0.0-beta.21\" # Update to latest\n```\n\nRun:\n```sh\ncargo update\n```\n\n> Make sure to update the npm tauri plugin dependencies to have the same version as the rust plugins. (desktop/angular)\n\n## Update WIX installer template\n\n> If the migration functionality is not needed anymore remove the template, this will cause tauri to use its default template and not call the migration script.\n\n1. Get the latest [main.wxs](https://github.com/tauri-apps/tauri/blob/dev/tooling/bundler/src/bundle/windows/templates/main.wxs) template from the repository.\n2. Replace the contents of `templates/wix/main_original.wxs` with the repository version. (The file is kept only for reference)\n3. Replace the contents of `templates/wix/main.wsx` and add the fallowing lines at the end of the file, inside the `Product` tag. \n```xml\n    <!-- Service fragments -->\n    <CustomActionRef Id='MigrationPropertySet' />\n    <CustomActionRef Id='Migration' />\n    <!-- Uncommenting the next line will cause the installer to check if the old service is running and fail. Without it, it will automatically stop and remove the old service without notifying the user. -->\n    <!-- <CustomActionRef Id='CheckServiceStatus' /> -->\n    <!-- End Service fragments -->\n```\n"
  },
  {
    "path": "desktop/tauri/src-tauri/build.rs",
    "content": "fn main() {\n  tauri_build::build()\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/capabilities/default.json",
    "content": "{\n  \"$schema\": \"../gen/schemas/desktop-schema.json\",\n  \"identifier\": \"default\",\n  \"description\": \"Capability for the main window\",\n  \"windows\": [\n    \"main\",\n    \"splash\"\n  ],\n  \"remote\": {\n    \"urls\": [\n      \"http://127.0.0.1:817\"\n    ]\n  },\n  \"permissions\": [\n    \"core:path:default\",\n    \"core:event:allow-listen\",\n    \"core:event:allow-unlisten\",\n    \"core:event:allow-emit\",\n    \"core:event:allow-emit-to\",\n    \"core:window:allow-hide\",\n    \"core:window:allow-show\",\n    \"core:window:allow-is-visible\",\n    \"core:window:allow-set-focus\",\n    \"core:window:allow-close\",\n    \"core:window:allow-get-all-windows\",\n    \"core:app:default\",\n    \"core:image:default\",\n    \"core:resources:default\",\n    \"core:menu:default\",\n    \"core:tray:default\",\n    \"core:webview:allow-set-webview-zoom\",\n    \"shell:allow-open\",\n    \"notification:default\",\n    \"window-state:allow-save-window-state\",\n    \"window-state:allow-restore-state\",\n    \"clipboard-manager:allow-read-text\",\n    \"clipboard-manager:allow-write-text\",    \n    \"websocket:default\"\n  ]\n}"
  },
  {
    "path": "desktop/tauri/src-tauri/src/cli.rs",
    "content": "use log::LevelFilter;\n\n// #[cfg(not(debug_assertions))]\n// const DEFAULT_LOG_LEVEL: log::LevelFilter = log::LevelFilter::Warn;\n\n// #[cfg(debug_assertions)]\nconst DEFAULT_LOG_LEVEL: log::LevelFilter = log::LevelFilter::Debug;\n\n#[derive(Debug)]\npub struct CliArguments {\n    // Path to the installation directory\n    pub data: Option<String>,\n\n    // Log level to use: off, error, warn, info, debug, trace\n    pub log_level: log::LevelFilter,\n\n    // Start in the background without opening a window\n    pub background: bool,\n\n    // Enable experimental notifications via Tauri. Replaces the notifier app.\n    pub with_prompts: bool,\n\n    // Enable experimental prompt support via Tauri. Replaces the notifier app.\n    pub with_notifications: bool,\n}\n\nimpl CliArguments {\n    fn parse_log(&mut self, level: String) {\n        self.log_level = match level.as_ref() {\n            \"off\" => LevelFilter::Off,\n            \"error\" => LevelFilter::Error,\n            \"warn\" => LevelFilter::Warn,\n            \"info\" => LevelFilter::Info,\n            \"debug\" => LevelFilter::Debug,\n            \"trace\" => LevelFilter::Trace,\n            _ => DEFAULT_LOG_LEVEL,\n        }\n    }\n}\n\npub fn parse(raw: impl IntoIterator<Item = impl Into<std::ffi::OsString>>) -> CliArguments {\n    let mut cli = CliArguments {\n        data: None,\n        log_level: DEFAULT_LOG_LEVEL,\n        background: false,\n        with_prompts: true,\n        with_notifications: true,\n    };\n\n    let raw = clap_lex::RawArgs::new(raw);\n    let mut cursor = raw.cursor();\n    raw.next(&mut cursor); // Skip the bin\n\n    while let Some(arg) = raw.next(&mut cursor) {\n        if let Some((long, value)) = arg.to_long() {\n            match long {\n                Ok(\"data\") => {\n                    if let Some(value) = value {\n                        cli.data = Some(value.to_string_lossy().into_owned());\n                    }\n                }\n                Ok(\"log\") => {\n                    if let Some(value) = value {\n                        cli.parse_log(value.to_string_lossy().into_owned());\n                    }\n                }\n                Ok(\"background\") => {\n                    cli.background = true;\n                }\n                Ok(\"no-prompts\") => {\n                    cli.with_prompts = false;\n                }\n                Ok(\"no-notifications\") => {\n                    cli.with_notifications = false;\n                }\n                _ => {\n                    // Ignore unexpected flags\n                }\n            }\n        } else if let Some(mut shorts) = arg.to_short() {\n            while let Some(short) = shorts.next() {\n                match short {\n                    Ok('l') => {\n                        if let Some(value) = shorts.next_value_os() {\n                            let mut str = value.to_string_lossy().into_owned();\n                            _ = str.remove(0); // remove first \"=\" from value (in -l=warn value will be \"=warn\")\n                            cli.parse_log(str);\n                        }\n                    }\n                    Ok('d') => {\n                        if let Some(value) = shorts.next_value_os() {\n                            let mut str = value.to_string_lossy().into_owned();\n                            _ = str.remove(0); // remove first \"=\" from value (in -d=/data value will be \"=/data\")\n                            cli.data = Some(str);\n                        }\n                    }\n                    Ok('b') => cli.background = true,\n                    _ => {\n                        // Ignore unexpected flags\n                    }\n                }\n            }\n        }\n    }\n\n    cli\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/commands/mod.rs",
    "content": "pub mod tauri_http;"
  },
  {
    "path": "desktop/tauri/src-tauri/src/commands/tauri_http.rs",
    "content": "use tauri::State;\nuse reqwest::{Client, Method}; \nuse serde::{Deserialize, Serialize};\n\n/// Creates and configures a shared HTTP client for application-wide use.\n/// \n/// Returns a reqwest Client configured with:\n/// - Connection pooling\n/// - Persistent cookie store\n/// \n/// Client can be accessed from UI through the exposed Tauri command `send_tauri_http_request(...)`\n/// Such requests execute directly from the Tauri app binary, not from the WebView process\npub fn create_http_client() -> Client {\n    Client::builder()\n        // Maximum idle connections per host\n        .pool_max_idle_per_host(10)\n        // Enable cookie support\n        .cookie_store(true)\n        .user_agent(\"Portmaster UI\")\n        .build()\n        .expect(\"failed to build HTTP client\")\n}\n\n#[derive(Deserialize)]\npub struct HttpRequestOptions {\n  method: String,\n  headers: Vec<(String, String)>,\n  body: Option<Vec<u8>>,\n}\n\n#[derive(Serialize)]\npub struct HttpResponse {\n  status: u16,\n  status_text: String,\n  headers: Vec<(String, String)>,\n  body: Vec<u8>,\n}\n\n#[tauri::command]\npub async fn send_tauri_http_request(\n  client: State<'_, Client>,\n  url: String,\n  opts: HttpRequestOptions\n) -> Result<HttpResponse, String> {\n  //println!(\"URL: {}\", url);\n\n  // Build the request\n  let mut req = client\n    .request(Method::from_bytes(opts.method.as_bytes()).map_err(|e| e.to_string())?, &url);\n\n  // Apply headers\n  for (k, v) in opts.headers {\n    req = req.header(&k, &v);\n  }\n\n  // Attach body if present\n  if let Some(body) = opts.body {\n    req = req.body(body);\n  }\n\n  // Send and await the response\n  let resp = req.send().await.map_err(|e| e.to_string())?;\n\n  // Read status, headers, and body\n  let status = resp.status().as_u16();\n  let status_text = resp.status().canonical_reason().unwrap_or(\"\").to_string();\n  let headers = resp\n    .headers()\n    .iter()\n    .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or(\"\").to_string()))\n    .collect();\n  let body = resp.bytes().await.map_err(|e| e.to_string())?.to_vec();\n\n  Ok(HttpResponse { status, status_text, headers, body })\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/config.rs",
    "content": "use std::fs;\n\nuse log::{debug, error};\nuse serde::{Deserialize, Serialize};\nuse tauri::{AppHandle, Manager};\n\n#[derive(Serialize, Deserialize)]\npub enum Theme {\n    Light,\n    Dark,\n    System,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Config {\n    pub theme: Theme,\n}\n\nconst CONFIG_FILE_NAME: &str = \"config.json\";\n\npub fn save(app: &AppHandle, config: Config) -> tauri::Result<()> {\n    let config_dir = app.path().app_config_dir()?;\n\n    let config_path = config_dir.join(CONFIG_FILE_NAME);\n    debug!(\"saving config file: {:?}\", config_path);\n    let json = serde_json::to_string_pretty(&config)?;\n    fs::write(config_path, json)?;\n    Ok(())\n}\n\npub fn load(app: &AppHandle) -> tauri::Result<Config> {\n    let config_dir = app.path().app_config_dir()?;\n\n    let config_path = config_dir.join(CONFIG_FILE_NAME);\n    if let Ok(json) = fs::read_to_string(config_path) {\n        if let Ok(config) = serde_json::from_str(&json) {\n            return Ok(config);\n        }\n    }\n\n    error!(\"failed to load config file returning default config\");\n    Ok(Config {\n        theme: Theme::System,\n    })\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/main.rs",
    "content": "// Prevents additional console window on Windows in release, DO NOT REMOVE!!\n#![cfg_attr(not(debug_assertions), windows_subsystem = \"windows\")]\n\nuse std::{env, time::Duration};\n\nuse tauri::{AppHandle, Emitter, Listener, Manager, RunEvent, WindowEvent};\n\n// Library crates\nmod portapi;\nmod service;\n\n#[cfg(target_os = \"linux\")]\nmod xdg;\n\n// App modules\nmod cli;\nmod config;\nmod portmaster;\nmod traymenu;\nmod window;\nmod commands;\n\nuse log::{debug, error, info};\nuse portmaster::PortmasterExt;\nuse tauri_plugin_log::RotationStrategy;\nuse traymenu::setup_tray_menu;\nuse window::{close_splash_window, create_main_window, hide_splash_window, create_debounced_window_state_saver};\nuse tauri_plugin_window_state::{AppHandleExt, StateFlags};\n\n#[macro_use]\nextern crate lazy_static;\n\nconst FALLBACK_TO_OLD_UI_EXIT_CODE: i32 = 77;\n\n// Window state configuration: save all properties except visibility to avoid \n// interference with the \"--background\" command line argument\nconst WINDOW_STATE_FLAGS_TO_SAVE: StateFlags = StateFlags::from_bits_truncate(\n    StateFlags::all().bits() & !StateFlags::VISIBLE.bits()\n);\n// Default timeout for debounced window state saving\nconst WINDOW_STATE_SAVE_TIMEOUT: Duration = Duration::from_secs(3);\n\n#[derive(Clone, serde::Serialize)]\nstruct Payload {\n    args: Vec<String>,\n    cwd: String,\n}\n\nstruct WsHandler {\n    handle: AppHandle,\n    background: bool,\n\n    is_first_connect: bool,\n}\n\nimpl portmaster::Handler for WsHandler {\n    fn name(&self) -> String {\n        \"main-handler\".to_string()\n    }\n\n    fn on_connect(&mut self, cli: portapi::client::PortAPI) {\n        info!(\"connection established, creating main window\");\n\n        // we successfully connected to Portmaster. Set is_first_connect to false\n        // so we don't show the splash-screen when we loose connection.\n        self.is_first_connect = false;\n\n        // The order is important. If all current windows are destroyed tauri will exit.\n        // First create the main ui window then destroy the splash screen.\n\n        // Hide splash screen. Will be closed after main window is created.\n        if let Err(err) = hide_splash_window(&self.handle) {\n            error!(\"failed to close splash window: {}\", err.to_string());\n        }\n\n        // create the main window now. It's not automatically visible by default.\n        // Rather, the angular application will show the window itself when it finished\n        // bootstrapping.\n        if let Err(err) = create_main_window(&self.handle) {\n            error!(\"failed to create main window: {}\", err.to_string());\n        } else {\n            debug!(\"created main window\")\n        }\n\n        // Now it is safe to destroy the splash window.\n        if let Err(err) = close_splash_window(&self.handle) {\n            error!(\"failed to close splash window: {}\", err.to_string());\n        }\n\n        // Cancel the previous tray handler task if it exists\n        let portmaster = self.handle.portmaster();\n        if let Ok(mut task_guard) = portmaster.tray_handler_task.lock() {\n            if let Some(old_task) = task_guard.take() {\n                debug!(\"Aborting previous tray handler task\");\n                old_task.abort();\n            }\n\n            // Start new tray handler and store the task handle\n            let handle = self.handle.clone();\n            let task = tauri::async_runtime::spawn(async move {\n                traymenu::tray_handler(cli, handle).await;\n            });\n            *task_guard = Some(task);\n        }\n    }\n\n    fn on_disconnect(&mut self) {\n        // if we're not running in background and this was the first connection attempt\n        // then display the splash-screen.\n        //\n        // Once we had a successful connection the splash-screen will not be shown anymore\n        // since there's already a main window with the angular application.\n        if !self.background && self.is_first_connect {\n            let _ = window::create_splash_window(&self.handle.clone());\n            self.is_first_connect = false\n        }\n    }\n}\n\nfn show_webview_not_installed_dialog() -> i32 {\n    use rfd::MessageDialog;\n\n    let result = MessageDialog::new()\n        .set_title(\"Portmaster\")\n        .set_description(\"Webkit is not installed. Please install it and run portmaster again\")\n        .set_buttons(rfd::MessageButtons::OkCancelCustom(\n            \"Go to install page\".to_owned(),\n            \"Use old UI\".to_owned(),\n        ))\n        .show();\n    println!(\"{:?}\", result);\n    if let rfd::MessageDialogResult::Custom(result) = result {\n        if result.eq(\"Go to install page\") {\n            _ = open::that(\"https://wiki.safing.io/en/Portmaster/Install/Webview\");\n            std::thread::sleep(Duration::from_secs(2));\n            return 0;\n        }\n    }\n\n    FALLBACK_TO_OLD_UI_EXIT_CODE\n}\n\nfn main() {\n    if tauri::webview_version().is_err() {\n        std::process::exit(show_webview_not_installed_dialog());\n    }\n\n    let cli_args = cli::parse(std::env::args());\n\n    // TODO(vladimir): Support for other log targets?\n    #[cfg(target_os = \"linux\")]\n    let log_target = tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout);\n    // let log_target = if let Some(data_dir) = cli_args.data {\n    //     tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Folder {\n    //         path: Path::new(&format!(\"{}/logs/app2\", data_dir)).into(),\n    //         file_name: None,\n    //     })\n    // } else {\n    // };\n\n    // TODO(vladimir): Permission for logs/app2 folder are not guaranteed. Use the default location for now.\n    #[cfg(target_os = \"windows\")]\n    let log_target = if let Some(_) = cli_args.data {\n        tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::LogDir { file_name: None })\n    } else {\n        tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout)\n    };\n\n    // Create a single HTTP client that:\n    // - Pools and reuses connections for better performance\n    // - Is exposed to UI through 'send_tauri_http_request()' command\n    // - Such requests execute directly from the Tauri app binary, not from the WebView process\n    let http_client = commands::tauri_http::create_http_client();\n\n    let app = tauri::Builder::default()\n        // make HTTP client accessible in commands ('send_tauri_http_request()')\n        .manage(http_client) \n        .plugin(tauri_plugin_websocket::init())\n        // Shell plugin for open_external support\n        .plugin(tauri_plugin_shell::init())\n        // Initialize Logging plugin.\n        .plugin(\n            tauri_plugin_log::Builder::default()\n                .level(cli_args.log_level)\n                .rotation_strategy(RotationStrategy::KeepAll)\n                .clear_targets()\n                .target(log_target)\n                .build(),\n        )\n        // Clipboard support\n        .plugin(tauri_plugin_clipboard_manager::init())\n        // Dialog (Save/Open) support\n        .plugin(tauri_plugin_dialog::init())\n        // OS Version and Architecture support\n        .plugin(tauri_plugin_os::init())\n        // Initialize save windows state plugin.\n        .plugin(tauri_plugin_window_state::Builder::default()\n            // Don't save visibility state, so it will not interfere with \"--background\" command line argument \n            .with_state_flags(WINDOW_STATE_FLAGS_TO_SAVE) \n            // Don't save splash window state\n            .with_denylist(&[\"splash\",])\n            .build())\n        // Single instance guard\n        .plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {\n            // Send info to already dunning instance.\n            let _ = app.emit(\"single-instance\", Payload { args: argv, cwd });\n        }))\n        // Notification support\n        .plugin(tauri_plugin_notification::init())\n        .invoke_handler(tauri::generate_handler![\n            portmaster::commands::get_app_info,\n            portmaster::commands::get_service_manager_status,\n            portmaster::commands::start_service,\n            portmaster::commands::get_state,\n            portmaster::commands::set_state,\n            portmaster::commands::should_show,\n            portmaster::commands::should_handle_prompts,\n            commands::tauri_http::send_tauri_http_request,\n        ])\n        // Setup the app an any listeners\n        .setup(move |app| {\n            setup_tray_menu(app)?;\n            portmaster::setup(app.handle().clone());\n            // Setup the single-instance event listener that will create/focus the main window\n            // or the splash-screen.\n            let handle = app.handle().clone();\n            app.listen_any(\"single-instance\", move |_event| {\n                let _ = window::open_window(&handle);\n            });\n\n            // Handle cli flags:\n            app.portmaster()\n                .set_show_after_bootstrap(!cli_args.background);\n            app.portmaster()\n                .with_notification_support(cli_args.with_notifications);\n            app.portmaster()\n                .with_connection_prompts(cli_args.with_prompts);\n\n            // prepare a custom portmaster plugin handler that will show the splash-screen\n            // (if not in --background) and launch the tray-icon handler.\n            let handler = WsHandler {\n                handle: app.handle().clone(),\n                background: cli_args.background,\n                is_first_connect: true,\n            };\n\n            // register the custom handler\n            app.portmaster().register_handler(handler);\n\n            // Setup window state saving on move/resize events with debouncing\n            let save_trigger = create_debounced_window_state_saver(app, \n                WINDOW_STATE_FLAGS_TO_SAVE, \n                WINDOW_STATE_SAVE_TIMEOUT);\n            let tx_move = save_trigger.clone();\n            let tx_resize = save_trigger;\n            app.listen_any(\"tauri://move\",   move |_event| { let _ = tx_move.try_send(()); });\n            app.listen_any(\"tauri://resize\", move |_event| { let _ = tx_resize.try_send(()); });\n\n            Ok(())\n        })\n        .any_thread()\n        .build(tauri::generate_context!())\n        .expect(\"error while running tauri application\");\n\n    app.run(|handle, e| {\n        match e {\n            RunEvent::WindowEvent { label, event, .. } => {\n                if label != \"main\" {\n                    // We only have one window at most so any other label is unexpected\n                    return;\n                }\n\n                // Do not let the user close the window, instead send an event to the main\n                // window so we can show the \"will not stop portmaster\" dialog and let the window\n                // close itself using\n                //\n                //    window.__TAURI__.window.getCurrent().close()\n                //\n                // Note: the above javascript does NOT trigger the CloseRequested event so\n                // there's no need to handle that case here.\n                if let WindowEvent::CloseRequested { api, .. } = event {\n                    debug!(\n                        \"window (label={}) close request received, forwarding to user-interface.\",\n                        label\n                    );\n\n                    // Manually save the window state on close attempt. \n                    // This ensures the state is saved since we prevent the close event.\n                    let _ = handle.save_window_state(WINDOW_STATE_FLAGS_TO_SAVE);\n\n                    api.prevent_close();\n                    if let Some(window) = handle.get_webview_window(label.as_str()) {\n                        let result = window.emit(\"exit-requested\", \"\");\n                        if let Err(err) = result {\n                            error!(\"failed to emit event: {}\", err.to_string());\n                        }\n                    } else {\n                        error!(\"window was None\");\n                    }\n                }\n            }\n            RunEvent::ExitRequested { .. } => {\n                debug!(\"Application exit requested, shutting down websocket\");\n                portmaster::websocket::shutdown_websocket();\n            }\n            _ => {}\n        }\n    });\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/client.rs",
    "content": "use futures_util::{SinkExt, StreamExt};\nuse http::Uri;\nuse log::{debug, error, warn};\nuse std::collections::HashMap;\nuse std::sync::atomic::{AtomicUsize, Ordering};\nuse tokio::sync::mpsc::{channel, Receiver, Sender};\nuse tokio::sync::RwLock;\nuse tokio::time::{interval, Duration, Instant};\nuse tokio_websockets::{ClientBuilder, Error};\nuse bytes::Bytes;\n\nuse super::message::*;\nuse super::types::*;\n\n/// An internal representation of a Command that\n/// contains the PortAPI message as well as a response\n/// channel that will receive all responses sent from the\n/// server.\n///\n/// Users should normally not need to use the Command struct\n/// directly since `PortAPI` already abstracts the creation of\n/// mpsc channels.\nstruct Command {\n    msg: Message,\n    response: Sender<Response>,\n}\n\n/// The client implementation for PortAPI.\n#[derive(Clone)]\npub struct PortAPI {\n    dispatch: Sender<Command>,\n}\n\n/// The map type used to store message subscribers.\ntype SubscriberMap = RwLock<HashMap<usize, Sender<Response>>>;\n\n/// Connect to PortAPI at the specified URI.\n///\n/// This method will launch a new async thread on the `tauri::async_runtime`\n/// that will handle message to transmit and also multiplex server responses\n/// to the appropriate subscriber.\npub async fn connect(uri: &str) -> Result<PortAPI, Error> {\n    let parsed = match uri.parse::<Uri>() {\n        Ok(u) => u,\n        Err(_e) => {\n            return Err(Error::NoUriConfigured); // TODO(ppacher): fix the return error type.\n        }\n    };\n\n    let (mut client, _) = ClientBuilder::from_uri(parsed).connect().await?;\n    let (tx, mut dispatch) = channel::<Command>(64);\n\n    tauri::async_runtime::spawn(async move {\n        let subscribers: SubscriberMap = RwLock::new(HashMap::new());\n        let next_id = AtomicUsize::new(0);\n        \n        // Ping/pong keep-alive mechanism\n        let mut ping_interval = interval(Duration::from_secs(10));  // Send ping every 10 seconds\n        let mut timeout_check = interval(Duration::from_secs(1));   // Check for timeout every 1 second\n        let mut last_ping = Instant::now();\n        let mut last_pong = Instant::now();\n        const PONG_TIMEOUT: Duration = Duration::from_secs(5);      // Declare connection dead if no pong within 5 seconds after ping\n\n        loop {\n            tokio::select! {\n                _ = ping_interval.tick() => {\n                    // Send ping frame\n                    if let Err(err) = client.send(tokio_websockets::Message::ping(Bytes::new())).await {\n                        error!(\"failed to send ping: {}\", err);\n                        dispatch.close();\n                        return;\n                    }\n                    last_ping = Instant::now();\n                    // debug!(\"sent websocket ping\");\n                },\n\n                _ = timeout_check.tick() => {\n                    // Check if pong timeout expired after last ping\n                    if last_ping > last_pong && last_ping.elapsed() > PONG_TIMEOUT {\n                        warn!(\"no pong received for {:?} after ping, connection appears dead\", PONG_TIMEOUT);\n                        dispatch.close();\n                        return;\n                    }\n                },\n\n                msg = client.next() => {\n                    let msg = match msg {\n                        Some(msg) => msg,\n                        None => {\n                            warn!(\"websocket connection lost\");\n\n                            dispatch.close();\n                            return;\n                        }\n                    };\n\n                    match msg {\n                        Err(err) => {\n                            error!(\"failed to receive frame from websocket: {}\", err);\n\n                            dispatch.close();\n                            return;\n                        },\n                        Ok(msg) => {\n                            // Handle pong frames\n                            if msg.is_pong() {\n                                last_pong = Instant::now();\n                                // debug!(\"received websocket pong\");\n                                continue;\n                            }\n\n                            if msg.is_ping() {\n                                // debug!(\"received websocket ping\");\n                                continue;\n                            }\n                            \n                            let text = unsafe {\n                                std::str::from_utf8_unchecked(msg.as_payload())\n                            };\n\n                            match text.parse::<Message>() {\n                                Ok(msg) => {\n                                    let id = msg.id;\n                                    let map = subscribers\n                                        .read()\n                                        .await;\n\n                                    if let Some(sub) = map.get(&id) {\n                                        let res: Result<Response, MessageError> = msg.try_into();\n                                        match res {\n                                            Ok(response) => {\n                                                if let Err(err) = sub.send(response).await {\n                                                    // The receiver side has been closed already,\n                                                    // drop the read lock and remove the subscriber\n                                                    // from our hashmap\n                                                    drop(map);\n\n                                                    subscribers\n                                                        .write()\n                                                        .await\n                                                        .remove(&id);\n\n                                                    debug!(\"subscriber for command {} closed read side: {}\", id, err);\n                                                }\n                                            },\n                                            Err(err) => {\n                                                error!(\"invalid command: {}\", err);\n                                            }\n                                        }\n                                    }\n                                },\n                                Err(err) => {\n                                    error!(\"failed to deserialize message: {}\", err)\n                                }\n                            }\n                        }\n                    }\n\n                },\n\n                Some(mut cmd) = dispatch.recv() => {\n                    let id = next_id.fetch_add(1, Ordering::Relaxed);\n                    cmd.msg.id = id;\n                    let blob: String = cmd.msg.into();\n\n                    debug!(\"Sending websocket frame: {}\", blob);\n\n                    match client.send(tokio_websockets::Message::text(blob)).await {\n                        Ok(_) => {\n                            subscribers\n                                .write()\n                                .await\n                                .insert(id, cmd.response);\n                        },\n                        Err(err) => {\n                            error!(\"failed to dispatch command: {}\", err);\n\n                            // TODO(ppacher): we should send some error to cmd.response here.\n                            // Otherwise, the sender of cmd might get stuck waiting for responses\n                            // if they don't check for PortAPI.is_closed().\n\n                            return\n                        }\n                    }\n                }\n            }\n        }\n    });\n\n    Ok(PortAPI { dispatch: tx })\n}\n\nimpl PortAPI {\n    /// `request` sends a PortAPI `portapi::types::Request` to the server and returns a mpsc receiver channel\n    /// where all server responses are forwarded.\n    ///\n    /// If the caller does not intend to read any responses the returned receiver may be closed or\n    /// dropped. As soon as the async-thread launched in `connect` detects a closed receiver it is remove\n    /// from the subscription map.\n    ///\n    /// The default buffer size for the channel is 64. Use `request_with_buffer_size` to specify a dedicated buffer size.\n    pub async fn request(\n        &self,\n        r: Request,\n    ) -> std::result::Result<Receiver<Response>, MessageError> {\n        self.request_with_buffer_size(r, 64).await\n    }\n\n    // Like `request` but supports explicitly specifying a channel buffer size.\n    pub async fn request_with_buffer_size(\n        &self,\n        r: Request,\n        buffer: usize,\n    ) -> std::result::Result<Receiver<Response>, MessageError> {\n        let (tx, rx) = channel(buffer);\n\n        let msg: Message = r.try_into()?;\n\n        let _ = self.dispatch.send(Command { response: tx, msg }).await;\n\n        Ok(rx)\n    }\n\n    /// Reports whether or not the websocket connection to the Portmaster Database API has been closed\n    /// due to errors.\n    ///\n    /// Users are expected to check this field on a regular interval to detect any issues and perform\n    /// a clean re-connect by calling `connect` again.\n    pub fn is_closed(&self) -> bool {\n        self.dispatch.is_closed()\n    }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/message.rs",
    "content": "use thiserror::Error;\n\n/// MessageError describes any error that is encountered when parsing\n/// PortAPI messages or when converting between the Request/Response types.\n#[derive(Debug, Error)]\npub enum MessageError {\n    #[error(\"missing command id\")]\n    MissingID,\n\n    #[error(\"invalid command id\")]\n    InvalidID,\n\n    #[error(\"missing command\")]\n    MissingCommand,\n\n    #[error(\"missing key\")]\n    MissingKey,\n\n    #[error(\"missing payload\")]\n    MissingPayload,\n\n    #[error(\"unknown or unsupported command: {0}\")]\n    UnknownCommand(String),\n\n    #[error(transparent)]\n    InvalidPayload(#[from] serde_json::Error),\n}\n\n/// Payload defines the payload type and content of a PortAPI message.\n///\n/// For the time being, only JSON payloads (indicated by a prefixed 'J' of the payload content)\n/// is directly supported in `Payload::parse()`.\n///\n/// For other payload types (like CBOR, BSON, ...) it's the user responsibility to figure out\n/// appropriate decoding from the `Payload::UNKNOWN` variant.\n#[derive(PartialEq, Debug, Clone)]\npub enum Payload {\n    Json(String),\n    Unknown(String),\n}\n\n/// ParseError is returned from `Payload::parse()`.\n#[derive(Debug, Error)]\npub enum ParseError {\n    #[error(transparent)]\n    Json(#[from] serde_json::Error),\n\n    #[error(\"unknown error while parsing\")]\n    Unknown,\n}\n\nimpl Payload {\n    /// Parse the payload into T.\n    ///\n    /// Only JSON parsing is supported for now. See [Payload] for more information.\n    pub fn parse<'a, T>(&'a self) -> std::result::Result<T, ParseError>\n    where\n        T: serde::de::Deserialize<'a>,\n    {\n        match self {\n            Payload::Json(blob) => Ok(serde_json::from_str::<T>(blob.as_str())?),\n            Payload::Unknown(_) => Err(ParseError::Unknown),\n        }\n    }\n}\n\n/// Supports creating a Payload instance from a String.\n///\n/// See [Payload] for more information.\nimpl std::convert::From<String> for Payload {\n    fn from(value: String) -> Payload {\n        let mut chars = value.chars();\n        let first = chars.next();\n        let rest = chars.as_str().to_string();\n\n        match first {\n            Some(c) => match c {\n                'J' => Payload::Json(rest),\n                _ => Payload::Unknown(value),\n            },\n            None => Payload::Unknown(\"\".to_string()),\n        }\n    }\n}\n\n/// Display implementation for Payload that just displays the raw payload.\nimpl std::fmt::Display for Payload {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Payload::Json(payload) => {\n                write!(f, \"J{}\", payload)\n            }\n            Payload::Unknown(payload) => {\n                write!(f, \"{}\", payload)\n            }\n        }\n    }\n}\n\n/// Message is an internal representation of a PortAPI message.\n/// Users should more likely use `portapi::types::Request` and `portapi::types::Response`\n/// instead of directly using `Message`.\n///\n/// The struct is still public since it might be useful for debugging or to implement new\n/// commands not yet supported by the `portapi::types` crate.\n#[derive(PartialEq, Debug, Clone)]\npub struct Message {\n    pub id: usize,\n    pub cmd: String,\n    pub key: Option<String>,\n    pub payload: Option<Payload>,\n}\n\n/// Implementation to marshal a PortAPI message into it's wire-format representation\n/// (which is a string).\n///\n/// Note that this conversion does not check for invalid messages!\nimpl std::convert::From<Message> for String {\n    fn from(value: Message) -> Self {\n        let mut result = String::new();\n\n        result.push_str(value.id.to_string().as_str());\n        result.push('|');\n        result.push_str(&value.cmd);\n\n        if let Some(key) = value.key {\n            result.push('|');\n            result.push_str(key.as_str());\n        }\n\n        if let Some(payload) = value.payload {\n            result.push('|');\n            result.push_str(payload.to_string().as_str())\n        }\n\n        result\n    }\n}\n\n/// An implementation for `String::parse()` to convert a wire-format representation\n/// of a PortAPI message to a Message instance.\n///\n/// Any errors returned from `String::parse()` will be of type `MessageError`\nimpl std::str::FromStr for Message {\n    type Err = MessageError;\n\n    fn from_str(line: &str) -> Result<Self, Self::Err> {\n        let parts = line.split('|').collect::<Vec<&str>>();\n\n        let id = match parts.first() {\n            Some(s) => match (*s).parse::<usize>() {\n                Ok(id) => Ok(id),\n                Err(_) => Err(MessageError::InvalidID),\n            },\n            None => Err(MessageError::MissingID),\n        }?;\n\n        let cmd = match parts.get(1) {\n            Some(s) => Ok(*s),\n            None => Err(MessageError::MissingCommand),\n        }?\n        .to_string();\n\n        let key = parts.get(2).map(|key| key.to_string());\n        let payload: Option<Payload> = parts.get(3).map(|p| p.to_string().into());\n\n        Ok(Message {\n            id,\n            cmd,\n            key,\n            payload,\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use serde::Deserialize;\n\n    #[derive(Debug, PartialEq, Deserialize)]\n    struct Test {\n        a: i64,\n        s: String,\n    }\n\n    #[test]\n    fn payload_to_string() {\n        let p = Payload::Json(\"{}\".to_string());\n        assert_eq!(p.to_string(), \"J{}\");\n\n        let p = Payload::Unknown(\"some unknown content\".to_string());\n        assert_eq!(p.to_string(), \"some unknown content\");\n    }\n\n    #[test]\n    fn payload_from_string() {\n        let p: Payload = \"J{}\".to_string().into();\n        assert_eq!(p, Payload::Json(\"{}\".to_string()));\n\n        let p: Payload = \"some unknown content\".to_string().into();\n        assert_eq!(p, Payload::Unknown(\"some unknown content\".to_string()));\n    }\n\n    #[test]\n    fn payload_parse() {\n        let p: Payload = \"J{\\\"a\\\": 100, \\\"s\\\": \\\"string\\\"}\".to_string().into();\n\n        let t: Test = p.parse().expect(\"Expected payload parsing to work\");\n\n        assert_eq!(\n            t,\n            Test {\n                a: 100,\n                s: \"string\".to_string(),\n            }\n        );\n    }\n\n    #[test]\n    fn parse_message() {\n        let m = \"10|insert|some:key|J{}\"\n            .parse::<Message>()\n            .expect(\"Expected message to parse\");\n\n        assert_eq!(\n            m,\n            Message {\n                id: 10,\n                cmd: \"insert\".to_string(),\n                key: Some(\"some:key\".to_string()),\n                payload: Some(Payload::Json(\"{}\".to_string())),\n            }\n        );\n\n        let m = \"1|done\"\n            .parse::<Message>()\n            .expect(\"Expected message to parse\");\n\n        assert_eq!(\n            m,\n            Message {\n                id: 1,\n                cmd: \"done\".to_string(),\n                key: None,\n                payload: None\n            }\n        );\n\n        let m = \"\".parse::<Message>().expect_err(\"Expected parsing to fail\");\n        if let MessageError::InvalidID = m {\n        } else {\n            panic!(\"unexpected error value: {}\", m)\n        }\n\n        let m = \"1\"\n            .parse::<Message>()\n            .expect_err(\"Expected parsing to fail\");\n\n        if let MessageError::MissingCommand = m {\n        } else {\n            panic!(\"unexpected error value: {}\", m)\n        }\n    }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/mod.rs",
    "content": "pub mod client;\npub mod message;\npub mod types;\npub mod models;"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/models/config.rs",
    "content": "use super::super::message::Payload;\nuse serde::*;\n\n#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]\npub struct BooleanValue {\n    #[serde(rename = \"Value\")]\n    pub value: Option<bool>,\n}\n\nimpl TryInto<Payload> for BooleanValue {\n    type Error = serde_json::Error;\n\n    fn try_into(self) -> Result<Payload, Self::Error> {\n        let str = serde_json::to_string(&self)?;\n\n        Ok(Payload::Json(str))\n    }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/models/mod.rs",
    "content": "pub mod config;\npub mod spn;\npub mod notification;\npub mod system_status_types;"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/models/notification.rs",
    "content": "use serde::*;\n\n#[derive(Serialize, Deserialize, Debug, PartialEq)]\npub struct Notification {\n    #[serde(rename = \"EventID\")]\n    pub event_id: String,\n\n    #[serde(rename = \"GUID\")]\n    pub guid: String,\n\n    #[serde(rename = \"Type\")]\n    pub notification_type: NotificationType,\n\n    #[serde(rename = \"Message\")]\n    pub message: String,\n\n    #[serde(rename = \"Title\")]\n    pub title: String,\n    #[serde(rename = \"Category\")]\n    pub category: String,\n\n    #[serde(rename = \"EventData\")]\n    pub data: serde_json::Value,\n\n    #[serde(rename = \"Expires\")]\n    pub expires: u64,\n\n    #[serde(rename = \"State\")]\n    pub state: String,\n\n    #[serde(rename = \"AvailableActions\")]\n    pub actions: Vec<Action>,\n\n    #[serde(rename = \"SelectedActionID\")]\n    pub selected_action_id: String,\n\n    #[serde(rename = \"ShowOnSystem\")]\n    pub show_on_system: bool,\n}\n\n#[derive(Serialize, Deserialize, Debug, PartialEq)]\npub struct Action {\n    #[serde(rename = \"ID\")]\n    pub id: String,\n\n    #[serde(rename = \"Text\")]\n    pub text: String,\n\n    #[serde(rename = \"Type\")]\n    pub action_type: String,\n\n    #[serde(rename = \"Payload\")]\n    pub payload: serde_json::Value,\n\n    #[serde(rename = \"Visibility\")]\n    pub visibility:  String, // \"\" - default, \"detailed\" - only show if the notification is expanded\n}\n\n#[derive(Serialize, Deserialize, Debug, PartialEq)]\npub struct NotificationType(i32);\n\n#[allow(dead_code)]\npub const INFO: NotificationType = NotificationType(0);\n\n#[allow(dead_code)]\npub const WARN: NotificationType = NotificationType(1);\n\n#[allow(dead_code)]\npub const PROMPT: NotificationType = NotificationType(2);\n\n#[allow(dead_code)]\npub const ERROR: NotificationType = NotificationType(3);\n\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/models/spn.rs",
    "content": "use serde::*;\n\n\n#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]\npub struct SPNStatus {\n    #[serde(rename = \"Status\")]\n    pub status: String,\n}"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/models/system_status_types.rs",
    "content": "use serde::{Deserialize, Serialize};\n\n#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"lowercase\")]\npub enum StateType {\n    #[serde(rename = \"\")]\n    Undefined,\n    #[serde(rename = \"hint\")]\n    Hint,\n    #[serde(rename = \"warning\")]\n    Warning,\n    #[serde(rename = \"error\")]\n    Error,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct State {\n    #[serde(rename = \"ID\")]\n    pub id: String,\n    #[serde(rename = \"Name\")]\n    pub name: String,\n    #[serde(rename = \"Message\")]\n    pub message: Option<String>,\n    #[serde(rename = \"Type\")]\n    pub state_type: Option<StateType>,\n    #[serde(rename = \"Time\")]\n    pub time: Option<String>, // time.Time serialized by GoLang\n    #[serde(rename = \"Data\")]\n    pub data: Option<serde_json::Value>, // any type\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct StateUpdate {\n    #[serde(rename = \"Module\")]\n    pub module: String,\n    #[serde(rename = \"States\")]\n    pub states: Option<Vec<State>>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct WorstState {\n    #[serde(rename = \"Module\")]\n    pub module: String,\n    #[serde(flatten)]\n    pub state: State,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct SystemStatus {\n    #[serde(rename = \"Modules\")]\n    pub modules: Vec<StateUpdate>,\n    #[serde(rename = \"WorstState\")]\n    pub worst_state: Option<WorstState>,\n\n    // add more fields when needed\n    // ...\n}\n\n// PauseInfo represents pause status data from \"control:paused\" state in Control module\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct PauseInfo {\n    #[serde(rename = \"Interception\")]\n    pub interception: bool,\n    #[serde(rename = \"SPN\")]  \n    pub spn: bool,\n    #[serde(rename = \"TillTime\")]\n    pub till_time: String, // time.Time serialized as string by GoLang\n}\n\n\nimpl SystemStatus {\n    pub fn get_module_state(&self, module_name: &str, state_id: &str) -> Option<&State> {\n        if let Some(module) = self.modules.iter().find(|m| m.module == module_name) {\n            if let Some(states) = &module.states {\n                return states.iter().find(|s| s.id == state_id);\n            }\n        }\n        None\n    }\n    \n}"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portapi/types.rs",
    "content": "\nuse super::message::*;\n\n/// Request is a strongly typed request message\n/// that can be converted to a `portapi::message::Message`\n/// object for further use by the client (`portapi::client::PortAPI`).\n#[derive(PartialEq, Debug)]\npub enum Request {\n    Get(String),\n    Query(String),\n    Subscribe(String),\n    QuerySubscribe(String),\n    Create(String, Payload),\n    Update(String, Payload),\n    Insert(String, Payload),\n    Delete(String),\n    Cancel,\n}\n\n/// Implementation to convert a internal `portapi::message::Message` to a valid\n/// `Request` variant.\n/// \n/// Any error returned will be of type `portapi::message::MessageError`.\nimpl std::convert::TryFrom<Message> for Request {\n    type Error = MessageError;\n\n    fn try_from(value: Message) -> Result<Self, Self::Error> {\n        match value.cmd.as_str() {\n            \"get\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                Ok(Request::Get(key))\n            },\n            \"query\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                Ok(Request::Query(key))\n            },\n            \"sub\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                Ok(Request::Subscribe(key))\n            },\n            \"qsub\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                Ok(Request::QuerySubscribe(key))\n            },\n            \"create\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                let payload = value.payload.ok_or(MessageError::MissingPayload)?;\n                Ok(Request::Create(key, payload))\n            },\n            \"update\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                let payload = value.payload.ok_or(MessageError::MissingPayload)?;\n                Ok(Request::Update(key, payload))\n            },\n            \"insert\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                let payload = value.payload.ok_or(MessageError::MissingPayload)?;\n                Ok(Request::Insert(key, payload))\n            },\n            \"delete\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                Ok(Request::Delete(key))\n            },\n            \"cancel\" => {\n                Ok(Request::Cancel)\n            },\n            cmd => {\n                Err(MessageError::UnknownCommand(cmd.to_string()))\n            }\n        }     \n    }\n}\n\n/// An implementation to try to convert a `Request` variant into a valid \n/// `portapi::message::Message` struct.\n/// \n/// While this implementation does not yet return any errors, it's expected that\n/// additional validation will be added in the future so users should already expect\n/// to receive `portapi::message::MessageError`s.\nimpl std::convert::TryFrom<Request> for Message {\n    type Error = MessageError;\n\n    fn try_from(value: Request) -> Result<Self, Self::Error> {\n        match value {\n            Request::Get(key) => Ok(Message { id: 0, cmd: \"get\".to_string(), key: Some(key), payload: None }),\n            Request::Query(key) => Ok(Message { id: 0, cmd: \"query\".to_string(), key: Some(key), payload: None }),\n            Request::Subscribe(key) => Ok(Message { id: 0, cmd: \"sub\".to_string(), key: Some(key), payload: None }),\n            Request::QuerySubscribe(key) => Ok(Message { id: 0, cmd: \"qsub\".to_string(), key: Some(key), payload: None }),\n            Request::Create(key, value) => Ok(Message{ id: 0, cmd: \"create\".to_string(), key: Some(key), payload: Some(value)}),\n            Request::Update(key, value) => Ok(Message{ id: 0, cmd: \"update\".to_string(), key: Some(key), payload: Some(value)}),\n            Request::Insert(key, value) => Ok(Message{ id: 0, cmd: \"insert\".to_string(), key: Some(key), payload: Some(value)}),\n            Request::Delete(key) => Ok(Message { id: 0, cmd: \"delete\".to_string(), key: Some(key), payload: None }),\n            Request::Cancel => Ok(Message { id: 0, cmd: \"cancel\".to_string(), key: None, payload: None }),\n        }\n    }\n}\n\n\n/// Response is strongly types PortAPI response message.\n/// that can be converted to a `portapi::message::Message`\n/// object for further use by the client (`portapi::client::PortAPI`).\n#[derive(PartialEq, Debug)]\npub enum Response {\n    Ok(String, Payload),\n    Update(String, Payload),\n    New(String, Payload),\n    Delete(String),\n    Success,\n    Error(String),\n    Warning(String),\n    Done\n}\n\n/// Implementation to convert a internal `portapi::message::Message` to a valid\n/// `Response` variant.\n/// \n/// Any error returned will be of type `portapi::message::MessageError`.\nimpl std::convert::TryFrom<Message> for Response {\n    type Error = MessageError;\n\n    fn try_from(value: Message) -> Result<Self, MessageError> {\n        match value.cmd.as_str() {\n            \"ok\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                let payload = value.payload.ok_or(MessageError::MissingPayload)?;\n\n                Ok(Response::Ok(key, payload))\n            },\n            \"upd\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                let payload = value.payload.ok_or(MessageError::MissingPayload)?;\n\n                Ok(Response::Update(key, payload))\n            },\n            \"new\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n                let payload = value.payload.ok_or(MessageError::MissingPayload)?;\n\n                Ok(Response::New(key, payload))\n            },\n            \"del\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n\n                Ok(Response::Delete(key))\n            },\n            \"success\" => {\n                Ok(Response::Success)\n            },\n            \"error\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n\n                Ok(Response::Error(key))\n            },\n            \"warning\" => {\n                let key = value.key.ok_or(MessageError::MissingKey)?;\n\n                Ok(Response::Warning(key))\n            },\n            \"done\" => {\n                Ok(Response::Done)\n            },\n            cmd => Err(MessageError::UnknownCommand(cmd.to_string()))\n        }\n    }\n}\n\n/// An implementation to try to convert a `Response` variant into a valid \n/// `portapi::message::Message` struct.\n/// \n/// While this implementation does not yet return any errors, it's expected that\n/// additional validation will be added in the future so users should already expect\n/// to receive `portapi::message::MessageError`s.\nimpl std::convert::TryFrom<Response> for Message {\n    type Error = MessageError;\n\n    fn try_from(value: Response) -> Result<Self, Self::Error> {\n        match value {\n            Response::Ok(key, payload) => Ok(Message{id: 0, cmd: \"ok\".to_string(), key: Some(key), payload: Some(payload)}),\n            Response::Update(key, payload) => Ok(Message{id: 0, cmd: \"upd\".to_string(), key: Some(key), payload: Some(payload)}),\n            Response::New(key, payload) => Ok(Message{id: 0, cmd: \"new\".to_string(), key: Some(key), payload: Some(payload)}),\n            Response::Delete(key ) => Ok(Message{id: 0, cmd: \"del\".to_string(), key: Some(key), payload: None}),\n            Response::Success => Ok(Message{id: 0, cmd: \"success\".to_string(), key: None, payload: None}),\n            Response::Warning(key) => Ok(Message{id: 0, cmd: \"warning\".to_string(), key: Some(key), payload: None}),\n            Response::Error(key) => Ok(Message{id: 0, cmd: \"error\".to_string(), key: Some(key), payload: None}),\n            Response::Done => Ok(Message{id: 0, cmd: \"done\".to_string(), key: None, payload: None}),\n        }\n    }\n}"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portmaster/commands.rs",
    "content": "use super::PortmasterInterface;\nuse crate::service::get_service_manager;\nuse crate::service::ServiceManager;\nuse log::debug;\nuse std::sync::atomic::Ordering;\nuse tauri::{Emitter, Runtime, State, Window};\n\npub type Result = std::result::Result<String, String>;\n\n#[derive(Clone, serde::Serialize, serde::Deserialize)]\npub struct Error {\n    pub error: String,\n}\n\n#[tauri::command]\npub fn should_show<R: Runtime>(\n    _window: Window<R>,\n    portmaster: State<'_, PortmasterInterface<R>>,\n) -> Result {\n    if portmaster.get_show_after_bootstrap() {\n        debug!(\"[tauri:rpc:should_show] application should show after bootstrap\");\n\n        Ok(\"show\".to_string())\n    } else {\n        debug!(\"[tauri:rpc:should_show] application should hide after bootstrap\");\n\n        Ok(\"hide\".to_string())\n    }\n}\n\n#[tauri::command]\npub fn should_handle_prompts<R: Runtime>(\n    _window: Window<R>,\n    portmaster: State<'_, PortmasterInterface<R>>,\n) -> Result {\n    if portmaster.handle_prompts.load(Ordering::Relaxed) {\n        Ok(\"true\".to_string())\n    } else {\n        Ok(\"false\".to_string())\n    }\n}\n\n#[tauri::command]\npub fn get_state<R: Runtime>(\n    _window: Window<R>,\n    portmaster: State<'_, PortmasterInterface<R>>,\n    key: String,\n) -> Result {\n    let value = portmaster.get_state(key);\n\n    if let Some(value) = value {\n        Ok(value)\n    } else {\n        Ok(\"\".to_string())\n    }\n}\n\n#[tauri::command]\npub fn set_state<R: Runtime>(\n    _window: Window<R>,\n    portmaster: State<'_, PortmasterInterface<R>>,\n    key: String,\n    value: String,\n) -> Result {\n    portmaster.set_state(key, value);\n\n    Ok(\"\".to_string())\n}\n\n#[cfg(target_os = \"linux\")]\n#[tauri::command]\npub fn get_app_info<R: Runtime>(\n    window: Window<R>,\n    response_id: String,\n    matching_path: String,\n    exec_path: String,\n    pid: i64,\n    cmdline: String,\n) -> Result {\n    let mut id = response_id;\n\n    let info = crate::xdg::ProcessInfo {\n        cmdline,\n        exec_path,\n        pid,\n        matching_path,\n    };\n\n    if id.is_empty() {\n        id = uuid::Uuid::new_v4().to_string()\n    }\n    let cloned = id.clone();\n\n    // GTK calls are not thread-safe and must run on the main thread. \n    // Schedule the work on the GTK/GLib main thread to avoid random segfaults.\n    glib::idle_add_local(move || {\n        let _ = match crate::xdg::get_app_info(info.clone()) {\n            Ok(info) => window.emit(&id, info),\n            Err(err) => window.emit(\n                &id,\n                Error {\n                    error: err.to_string(),\n                },\n            ),\n        };\n        glib::ControlFlow::Break\n    });\n\n    Ok(cloned)\n}\n\n#[cfg(target_os = \"windows\")]\n#[tauri::command]\npub fn get_app_info<R: Runtime>(\n    window: Window<R>,\n    response_id: String,\n    _matching_path: String,\n    _exec_path: String,\n    _pid: i64,\n    _cmdline: String,\n) -> Result {\n    let mut id = response_id;\n\n    if id == \"\" {\n        id = uuid::Uuid::new_v4().to_string()\n    }\n    let cloned = id.clone();\n\n    std::thread::spawn(move || {\n        let _ = window.emit(\n            &id,\n            Error {\n                error: \"Unsupported OS\".to_string(),\n            },\n        );\n    });\n\n    Ok(cloned)\n}\n\n#[tauri::command]\npub fn get_service_manager_status<R: Runtime>(window: Window<R>, response_id: String) -> Result {\n    let mut id = response_id;\n\n    if id.is_empty() {\n        id = uuid::Uuid::new_v4().to_string();\n    }\n    let cloned = id.clone();\n\n    std::thread::spawn(move || {\n        let result = match get_service_manager() {\n            Ok(sm) => sm.status().map_err(|err| err.to_string()),\n            Err(err) => Err(err.to_string()),\n        };\n\n        match result {\n            Ok(result) => window.emit(&id, &result),\n            Err(err) => window.emit(&id, Error { error: err }),\n        }\n    });\n\n    Ok(cloned)\n}\n\n#[tauri::command]\npub fn start_service<R: Runtime>(window: Window<R>, response_id: String) -> Result {\n    let mut id = response_id;\n\n    if id.is_empty() {\n        id = uuid::Uuid::new_v4().to_string();\n    }\n    let cloned = id.clone();\n\n    std::thread::spawn(move || {\n        let result = match get_service_manager() {\n            Ok(sm) => sm.start().map_err(|err| err.to_string()),\n            Err(err) => Err(err.to_string()),\n        };\n\n        match result {\n            Ok(result) => window.emit(&id, &result),\n            Err(err) => window.emit(&id, Error { error: err }),\n        }\n    });\n\n    Ok(cloned)\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portmaster/mod.rs",
    "content": "/// This module contains a custom tauri plugin that handles all communication\n/// with the angular app loaded from the portmaster api.\n///\n/// Using a custom-plugin for this has the advantage that all code that has\n/// access to a tauri::Window or a tauri::AppHandle can get access to the\n/// portmaster plugin using the Runtime/Manager extension by just calling\n/// window.portmaster() or app_handle.portmaster().\n///\n/// Any portmaster related features (like changing a portmaster setting) should\n/// live in this module.\n///\n/// Code that handles windows should NOT live here but should rather be placed\n/// in the crate root.\n// The commands module contains tauri commands that are available to Javascript\n// using the invoke() and our custom invokeAsync() command.\npub mod commands;\n\n// The websocket module spawns an async function on tauri's runtime that manages\n// a persistent connection to the Portmaster websocket API and updates the tauri Portmaster\n// Plugin instance.\npub mod websocket;\n\n// The notification module manages system notifications from portmaster.\nmod notifications;\n\nuse crate::portapi::{\n    client::PortAPI, message::Payload, models::config::BooleanValue, types::Request,\n};\nuse std::{\n    collections::HashMap,\n    sync::atomic::{AtomicBool, Ordering},\n};\n\nuse log::{debug, error};\nuse std::sync::Mutex;\nuse tauri::{AppHandle, Emitter, Manager, Runtime};\n\nconst PORTMASTER_BASE_URL: &str = \"http://127.0.0.1:817/api/v1/\";\n\npub trait Handler {\n    fn on_connect(&mut self, cli: PortAPI);\n    fn on_disconnect(&mut self);\n    fn name(&self) -> String;\n}\n\npub struct PortmasterInterface<R: Runtime> {\n    #[allow(dead_code)]\n    app: AppHandle<R>,\n\n    // state allows the angular application to store arbitrary values in the\n    // tauri application memory using the get_state and set_state\n    // tauri::commands.\n    state: Mutex<HashMap<String, String>>,\n\n    // an atomic boolean that indicates if we're currently connected to\n    // portmaster or not.\n    is_reachable: AtomicBool,\n\n    // holds the portapi client if any.\n    api: Mutex<Option<PortAPI>>,\n\n    // a vector of handlers that should be invoked on connect and disconnect of\n    // the portmaster API.\n    handlers: Mutex<Vec<Box<dyn Handler + Send>>>,\n\n    // whether or not we should handle notifications here.\n    handle_notifications: AtomicBool,\n\n    // whether or not we should handle prompts.\n    handle_prompts: AtomicBool,\n\n    // whether or not the angular application should call window.show after it\n    // finished bootstrapping.\n    should_show_after_bootstrap: AtomicBool,\n\n    // handle to the tray handler task so we can abort it when reconnecting\n    pub tray_handler_task: Mutex<Option<tauri::async_runtime::JoinHandle<()>>>,\n}\n\nimpl<R: Runtime> PortmasterInterface<R> {\n    /// Returns a state stored in the portmaster plugin.\n    pub fn get_state(&self, key: String) -> Option<String> {\n        let map = self.state.lock();\n\n        if let Ok(map) = map {\n            map.get(&key).cloned()\n        } else {\n            None\n        }\n    }\n\n    /// Adds a new state to the portmaster plugin.\n    pub fn set_state(&self, key: String, value: String) {\n        let map = self.state.lock();\n\n        if let Ok(mut map) = map {\n            map.insert(key, value);\n        }\n    }\n\n    /// Reports wheter or not we're currently connected to the Portmaster API.\n    pub fn is_reachable(&self) -> bool {\n        self.is_reachable.load(Ordering::Relaxed)\n    }\n\n    /// Registers a new connection handler that is called on connect\n    /// and disconnect of the Portmaster websocket API.\n    pub fn register_handler(&self, mut handler: impl Handler + Send + 'static) {\n        if let Ok(mut handlers) = self.handlers.lock() {\n            // register_handler can only be invoked after the plugin setup\n            // completed. in this case, the websocket thread is already spawned and\n            // we might already be connected or know that the connection failed.\n            // Call the respective handler method immediately now.\n            if let Some(api) = self.get_api() {\n                debug!(\"already connected to Portmaster API, calling on_connect()\");\n\n                handler.on_connect(api);\n            } else {\n                debug!(\"not yet connected to Portmaster API, calling on_disconnect()\");\n\n                handler.on_disconnect();\n            }\n\n            handlers.push(Box::new(handler));\n            debug!(\"number of registered handlers: {}\", handlers.len());\n        }\n    }\n\n    /// Returns the current portapi client.\n    pub fn get_api(&self) -> Option<PortAPI> {\n        if let Ok(api) = self.api.lock() {\n            (*api).clone()\n        } else {\n            None\n        }\n    }\n\n    /// Feature functions (enable/disable certain features).\n\n    /// Configures whether or not our tauri app should show system\n    /// notifications. This excludes connection prompts. Use\n    /// with_connection_prompts to enable handling of connection prompts.\n    pub fn with_notification_support(&self, enable: bool) {\n        self.handle_notifications.store(enable, Ordering::Relaxed);\n\n        // kick of the notification handler if we are connected.\n        if enable {\n            self.start_notification_handler();\n        }\n    }\n\n    /// Configures whether or not our angular application should show connection\n    /// prompts via tauri.\n    pub fn with_connection_prompts(&self, enable: bool) {\n        self.handle_prompts.store(enable, Ordering::Relaxed);\n    }\n\n    /// Whether or not the angular application should call window.show after it\n    /// finished bootstrapping.\n    pub fn set_show_after_bootstrap(&self, show: bool) {\n        self.should_show_after_bootstrap\n            .store(show, Ordering::Relaxed);\n    }\n\n    /// Returns whether or not the angular application should call window.show\n    /// after it finished bootstrapping.\n    pub fn get_show_after_bootstrap(&self) -> bool {\n        self.should_show_after_bootstrap.load(Ordering::Relaxed)\n    }\n\n    /// Tells the angular application to show the window by emitting an event.\n    /// It calls set_show_after_bootstrap(true) automatically so the application\n    /// also shows after bootstrapping.\n    pub fn show_window(&self) {\n        debug!(\"[tauri] showing main window\");\n\n        // set show_after_bootstrap to true so the app will even show if it\n        // misses the event below because it's still bootstrapping.\n        self.set_show_after_bootstrap(true);\n\n        if let Err(err) = self.app.emit(\"portmaster:show\", \"\") {\n            error!(\"failed to emit show event: {}\", err.to_string());\n        }\n    }\n\n    /// Enables or disables the SPN.\n    pub fn set_spn_enabled(&self, enabled: bool) {\n        if let Some(api) = self.get_api() {\n            let body: Result<Payload, serde_json::Error> = BooleanValue {\n                value: Some(enabled),\n            }\n            .try_into();\n\n            if let Ok(payload) = body {\n                tauri::async_runtime::spawn(async move {\n                    _ = api\n                        .request(Request::Update(\"config:spn/enable\".to_string(), payload))\n                        .await;\n                });\n            }\n        }\n    }\n\n    /// Send Shutdown request to portmaster\n    pub fn trigger_shutdown(&self) {\n        tauri::async_runtime::spawn(async move {\n            let client = reqwest::Client::new();\n            match client\n                .post(format!(\"{}core/shutdown\", PORTMASTER_BASE_URL))\n                .send()\n                .await\n            {\n                Ok(v) => {\n                    debug!(\"shutdown request sent {:?}\", v);\n                }\n                Err(err) => {\n                    error!(\"failed to send shutdown request {}\", err);\n                }\n            }\n        });\n    }\n\n    pub fn set_resume(&self) {\n        tauri::async_runtime::spawn(async move {\n            let client = reqwest::Client::new();\n            match client\n                .post(format!(\"{}control/resume\", PORTMASTER_BASE_URL))\n                .send()\n                .await\n            {\n                Ok(v) => {\n                    debug!(\"resume request sent {:?}\", v);\n                }\n                Err(err) => {\n                    error!(\"failed to send resume request {}\", err);\n                }\n            }\n        });\n    }\n\n\n    pub fn set_pause(&self, duration_seconds: u64, spn_only: bool) {\n        tauri::async_runtime::spawn(async move {\n            let client = reqwest::Client::new();\n            match client\n                .post(format!(\"{}control/pause\", PORTMASTER_BASE_URL))\n                .json(&serde_json::json!({\n                \"duration\": duration_seconds,\n                \"onlySPN\": spn_only\n            }))\n                .send()\n                .await\n            {\n                Ok(v) => {\n                    debug!(\"pause request sent {:?}\", v);\n                }\n                Err(err) => {\n                    error!(\"failed to send pause request {}\", err);\n                }\n            }\n        });\n    }\n\n    //// Internal functions\n    fn start_notification_handler(&self) {\n        if let Some(api) = self.get_api() {\n            tauri::async_runtime::spawn(async move {\n                notifications::notification_handler(api).await;\n            });\n        }\n    }\n\n    /// Internal method to call all on_connect handlers\n    fn on_connect(&self, api: PortAPI) {\n        debug!(\"connection to portmaster established, calling handlers\");\n\n        self.is_reachable.store(true, Ordering::Relaxed);\n\n        // store the new api client.\n        {\n            let mut guard = self.api.lock().unwrap();\n            *guard = Some(api.clone());\n        }\n\n        // fire-off the notification handler.\n        if self.handle_notifications.load(Ordering::Relaxed) {\n            self.start_notification_handler();\n        }\n\n        if let Ok(mut handlers) = self.handlers.lock() {\n            debug!(\"executing handler.on_connect()\");\n\n            for handler in handlers.iter_mut() {\n                debug!(\"calling registered handler: {}\", handler.name());\n                handler.on_connect(api.clone());\n            }\n        } else {\n            error!(\"failed to lock handlers\")\n        }\n    }\n\n    /// Internal method to call all on_disconnect handlers\n    fn on_disconnect(&self) {\n        self.is_reachable.store(false, Ordering::Relaxed);\n\n        // Abort the tray handler task if it's running\n        if let Ok(mut task_guard) = self.tray_handler_task.lock() {\n            if let Some(task) = task_guard.take() {\n                debug!(\"Aborting tray handler task\");\n                task.abort();\n            }\n        }\n\n        // clear the current api client reference.\n        {\n            let mut guard = self.api.lock().unwrap();\n            *guard = None;\n        }\n\n        if let Ok(mut handlers) = self.handlers.lock() {\n            for handler in handlers.iter_mut() {\n                handler.on_disconnect();\n            }\n        }\n    }\n}\n\npub trait PortmasterExt<R: Runtime> {\n    fn portmaster(&self) -> &PortmasterInterface<R>;\n}\n\nimpl<R: Runtime, T: Manager<R>> PortmasterExt<R> for T {\n    fn portmaster(&self) -> &PortmasterInterface<R> {\n        self.state::<PortmasterInterface<R>>().inner()\n    }\n}\n\npub fn setup(app: AppHandle) {\n    let interface = PortmasterInterface {\n        app: app.clone(),\n        state: Mutex::new(HashMap::new()),\n        is_reachable: AtomicBool::new(false),\n        handlers: Mutex::new(Vec::new()),\n        api: Mutex::new(None),\n        handle_notifications: AtomicBool::new(false),\n        handle_prompts: AtomicBool::new(false),\n        should_show_after_bootstrap: AtomicBool::new(true),\n        tray_handler_task: Mutex::new(None),\n    };\n\n    app.manage(interface);\n\n    // fire of the websocket handler\n    websocket::start_websocket_thread(app.clone());\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portmaster/notifications.rs",
    "content": "use crate::portapi::client::*;\nuse crate::portapi::message::*;\nuse crate::portapi::models::notification::*;\nuse crate::portapi::types::*;\nuse log::error;\nuse serde_json::json;\nuse tauri::async_runtime;\n\npub async fn notification_handler(cli: PortAPI) {\n    let res = cli\n        .request(Request::QuerySubscribe(\"query notifications:\".to_string()))\n        .await;\n\n    if let Ok(mut rx) = res {\n        while let Some(msg) = rx.recv().await {\n            let res = match msg {\n                Response::Ok(key, payload) => Some((key, payload)),\n                Response::New(key, payload) => Some((key, payload)),\n                Response::Update(key, payload) => Some((key, payload)),\n                _ => None,\n            };\n\n            if let Some((key, payload)) = res {\n                match payload.parse::<Notification>() {\n                    Ok(n) => {\n                        // Skip if this one should not be shown using the system notifications\n                        if !n.show_on_system {\n                            continue;\n                        }\n\n                        // Skip if this action has already been acted on\n                        if !n.selected_action_id.is_empty() {\n                            continue;\n                        }\n                        show_notification(&cli, key, n).await;\n                    }\n                    Err(err) => match err {\n                        ParseError::Json(err) => {\n                            error!(\"failed to parse notification: {}\", err);\n                        }\n                        _ => {\n                            error!(\"unknown error when parsing notifications payload\");\n                        }\n                    },\n                }\n            }\n        }\n    }\n}\n\n#[cfg(target_os = \"linux\")]\npub async fn show_notification(cli: &PortAPI, key: String, n: Notification) {\n    let mut notif = notify_rust::Notification::new();\n    notif.body(&n.message);\n    notif.timeout(notify_rust::Timeout::Never); // TODO(ppacher): use n.expires to calculate the timeout.\n    notif.summary(&n.title);\n    notif.icon(\"portmaster\");\n\n    for action in n.actions {\n        if !action.visibility.is_empty() {\n            continue\n        }\n        notif.action(&action.id, &action.text);\n    }\n\n    {\n        let cli_clone = cli.clone();\n        async_runtime::spawn(async move {\n            let res = notif.show();\n            // TODO(ppacher): keep a reference of open notifications and close them\n            // if the user reacted inside the UI:\n            match res {\n                Ok(handle) => {\n                    handle.wait_for_action(|action| {\n                        match action {\n                            \"__closed\" => {\n                                // timeout\n                            }\n\n                            value => {\n                                let value = value.to_string().clone();\n\n                                async_runtime::spawn(async move {\n                                    let _ = cli_clone\n                                        .request(Request::Update(\n                                            key,\n                                            Payload::Json(\n                                                json!({\n                                                    \"SelectedActionID\": value\n                                                })\n                                                .to_string(),\n                                            ),\n                                        ))\n                                        .await;\n                                });\n                            }\n                        }\n                    })\n                }\n                Err(err) => {\n                    error!(\"failed to display notification: {}\", err);\n                }\n            }\n        });\n    }\n}\n\n#[cfg(target_os = \"windows\")]\npub async fn show_notification(cli: &PortAPI, key: String, n: Notification) {\n    use tauri_winrt_notification::{Duration, Sound, Toast};\n\n    let mut toast = Toast::new(\"io.safing.portmaster\")\n        .title(&n.title)\n        .text1(&n.message)\n        .sound(Some(Sound::Default))\n        .duration(Duration::Long);\n\n    for action in n.actions {\n        if !action.visibility.is_empty() {\n            continue\n        }\n        toast = toast.add_button(&action.text, &action.id);\n    }\n    {\n        let cli = cli.clone();\n        toast = toast.on_activated(move |action| -> windows::core::Result<()> {\n            if let Some(value) = action {\n                let cli = cli.clone();\n                let key = key.clone();\n                async_runtime::spawn(async move {\n                    let _ = cli\n                        .request(Request::Update(\n                            key,\n                            Payload::Json(\n                                json!({\n                                    \"SelectedActionID\": value\n                                })\n                                .to_string(),\n                            ),\n                        ))\n                        .await;\n                });\n            } else {               \n                error!(\"Notification clicked but no action associated.\");\n                // TODO(vladimir): If Action is None, the user clicked on the notification. Focus on the UI.\n            }\n            Ok(())\n        });\n    }\n    toast.show().expect(\"unable to send notification\");\n    // TODO(vladimir): keep a reference of open notifications and close them\n    // if the user reacted inside the UI:\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/portmaster/websocket.rs",
    "content": "use super::PortmasterExt;\nuse crate::portapi::client::connect;\nuse log::{debug, error, info, warn};\nuse std::sync::atomic::{AtomicBool, Ordering};\nuse tauri::{AppHandle, Runtime};\nuse tokio::time::{sleep, Duration};\n\nstatic WEBSOCKET_SHUTDOWN: AtomicBool = AtomicBool::new(false);\n\n/// Signals the websocket thread to stop reconnecting and shut down gracefully.\npub fn shutdown_websocket() {\n    WEBSOCKET_SHUTDOWN.store(true, Ordering::Release);\n}\n\n/// Starts a backround thread (via tauri::async_runtime) that connects to the Portmaster\n/// Websocket database API.\npub fn start_websocket_thread<R: Runtime>(app: AppHandle<R>) {\n    let app = app.clone();\n\n    tauri::async_runtime::spawn(async move {\n        loop {\n            // Check if we should shutdown before attempting to connect\n            if WEBSOCKET_SHUTDOWN.load(Ordering::Acquire) {\n                debug!(\"WebSocket thread shutting down gracefully\");\n                break;\n            }\n\n            debug!(\"Trying to connect to websocket endpoint\");\n\n            let api = connect(\"ws://127.0.0.1:817/api/database/v1\").await;\n\n            match api {\n                Ok(cli) => {\n                    let portmaster = app.portmaster();\n\n                    info!(\"Successfully connected to portmaster\");\n\n                    portmaster.on_connect(cli.clone());\n\n                    // Monitor connection status\n                    loop {\n                        if WEBSOCKET_SHUTDOWN.load(Ordering::Acquire) {\n                            debug!(\"Shutdown signal received, closing connection\");\n                            break;\n                        }\n                        \n                        if cli.is_closed() {\n                            warn!(\"Connection to portmaster lost\");\n                            break;\n                        }\n                        \n                        sleep(Duration::from_secs(1)).await;\n                    }\n\n                    portmaster.on_disconnect();\n\n                    // If shutdown was requested, exit the loop\n                    if WEBSOCKET_SHUTDOWN.load(Ordering::Acquire) {\n                        debug!(\"Exiting websocket thread after disconnect\");\n                        break;\n                    }\n\n                    warn!(\"lost connection to portmaster, retrying ....\")\n                }\n                Err(err) => {\n                    error!(\"failed to create portapi client: {}\", err);\n\n                    app.portmaster().on_disconnect();\n\n                    // Check shutdown flag before sleeping\n                    if WEBSOCKET_SHUTDOWN.load(Ordering::Acquire) {\n                        debug!(\"Shutdown requested, not retrying connection\");\n                        break;\n                    }\n\n                    // Sleep and retry with constant 2 second delay\n                    sleep(Duration::from_secs(2)).await;\n                }\n            }\n        }\n        \n        info!(\"WebSocket thread terminated\");\n    });\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/service/manager.rs",
    "content": "use std::process::{Command, ExitStatus, Stdio};\nuse std::{fs, io};\n\nuse thiserror::Error;\n\n#[cfg(target_os = \"linux\")]\nuse std::os::unix::fs::PermissionsExt;\n\nuse super::status::StatusResult;\n\nstatic SYSTEMCTL: &str = \"systemctl\";\n// TODO(ppacher): add support for kdesudo and gksudo\n\nenum SudoCommand {\n    Pkexec,\n    Gksu,\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/service/mod.rs",
    "content": "// pub mod manager;\npub mod status;\n\n#[cfg(target_os = \"linux\")]\nmod systemd;\n\n#[cfg(target_os = \"windows\")]\nmod windows_service;\n\nuse std::process::ExitStatus;\n\n#[cfg(target_os = \"linux\")]\nuse crate::service::systemd::SystemdServiceManager;\n\nuse thiserror::Error;\n\nuse self::status::StatusResult;\n\n#[allow(dead_code)]\n#[derive(Error, Debug)]\npub enum ServiceManagerError {\n    #[error(\"unsupported service manager\")]\n    UnsupportedServiceManager,\n\n    #[error(\"unsupported operating system\")]\n    UnsupportedOperatingSystem,\n\n    #[error(transparent)]\n    FromUtf8Error(#[from] std::string::FromUtf8Error),\n\n    #[error(transparent)]\n    IoError(#[from] std::io::Error),\n\n    #[error(\"{0} output={1}\")]\n    Other(ExitStatus, String),\n\n    #[error(\"{0}\")]\n    WindowsError(String),\n}\n\npub type Result<T> = std::result::Result<T, ServiceManagerError>;\n\n/// A common interface to the system manager service (might be systemd, openrc, sc.exe, ...)\npub trait ServiceManager {\n    fn status(&self) -> Result<StatusResult>;\n    fn start(&self) -> Result<StatusResult>;\n}\n\n#[allow(dead_code)]\nstruct EmptyServiceManager();\n\nimpl ServiceManager for EmptyServiceManager {\n    fn status(&self) -> Result<StatusResult> {\n        Err(ServiceManagerError::UnsupportedServiceManager)\n    }\n\n    fn start(&self) -> Result<StatusResult> {\n        Err(ServiceManagerError::UnsupportedServiceManager)\n    }\n}\n\npub fn get_service_manager() -> Result<impl ServiceManager> {\n    #[cfg(target_os = \"linux\")]\n    {\n        if SystemdServiceManager::is_installed() {\n            log::info!(\"system service manager: systemd\");\n\n            Ok(SystemdServiceManager {})\n        } else {\n            Err(ServiceManagerError::UnsupportedServiceManager)\n        }\n    }\n\n    #[cfg(target_os = \"windows\")]\n    return Ok(windows_service::SERVICE_MANGER.clone());\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/service/status.rs",
    "content": "use serde::{Serialize, Deserialize};\n\n/// SystemResult defines the \"success\" codes when querying or starting\n/// a system service. \n#[derive(Serialize, Deserialize, Debug, PartialEq)]\npub enum StatusResult {\n    // The requested system service is installed and currently running.\n    Running,\n\n    // The requested system service is installed but currently stopped.\n    Stopped,\n\n    // NotFound is returned when the system service (systemd unit for linux)\n    // has not been found and the system and likely means the Portmaster installtion\n    // is broken all together. \n    NotFound,\n}\n\nimpl std::fmt::Display for StatusResult {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            StatusResult::Running => write!(f, \"running\"),\n            StatusResult::Stopped => write!(f, \"stopped\"),\n            StatusResult::NotFound => write!(f, \"not installed\")\n        }\n    }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/service/systemd.rs",
    "content": "use log::{debug, error};\n\nuse super::status::StatusResult;\nuse super::{Result, ServiceManager, ServiceManagerError};\nuse std::os::unix::fs::PermissionsExt;\nuse std::{\n    fs, io,\n    process::{Command, ExitStatus, Stdio},\n};\n\nstatic SYSTEMCTL: &str = \"systemctl\";\n// TODO(ppacher): add support for kdesudo and gksudo\n\nenum SudoCommand {\n    Pkexec,\n    Gksu,\n}\n\nimpl From<std::process::Output> for ServiceManagerError {\n    fn from(output: std::process::Output) -> Self {\n        let msg = String::from_utf8(output.stderr)\n            .ok()\n            .filter(|s| !s.trim().is_empty())\n            .or_else(|| {\n                String::from_utf8(output.stdout)\n                    .ok()\n                    .filter(|s| !s.trim().is_empty())\n            })\n            .unwrap_or_else(|| \"Failed to run `systemctl`\".to_string());\n\n        ServiceManagerError::Other(output.status, msg)\n    }\n}\n\n/// System Service manager implementation for Linux based distros.\npub struct SystemdServiceManager {}\n\nimpl SystemdServiceManager {\n    /// Checks if systemctl is available in /sbin/ /bin, /usr/bin or /usr/sbin.\n    ///\n    /// Note that we explicitly check those paths to avoid returning true in case\n    /// there's a systemctl binary in the cwd and PATH includes . since this may\n    /// pose a security risk of running an untrusted binary with root privileges.\n    pub fn is_installed() -> bool {\n        let paths = vec![\n            \"/sbin/systemctl\",\n            \"/bin/systemctl\",\n            \"/usr/sbin/systemctl\",\n            \"/usr/bin/systemctl\",\n        ];\n\n        for path in paths {\n            debug!(\"checking for systemctl at path {}\", path);\n\n            match fs::metadata(path) {\n                Ok(md) => {\n                    debug!(\"found systemctl at path {} \", path);\n\n                    if md.is_file() && md.permissions().mode() & 0o111 != 0 {\n                        return true;\n                    }\n\n                    error!(\n                        \"systemctl binary found but invalid permissions: {}\",\n                        md.permissions().mode().to_string()\n                    );\n                }\n                Err(err) => {\n                    error!(\n                        \"failed to check systemctl binary at {}: {}\",\n                        path,\n                        err.to_string()\n                    );\n\n                    continue;\n                }\n            };\n        }\n\n        error!(\"failed to find systemctl binary\");\n\n        false\n    }\n}\n\nimpl ServiceManager for SystemdServiceManager {\n    fn status(&self) -> super::Result<StatusResult> {\n        let name = \"portmaster.service\";\n        let result = systemctl(\"is-active\", name, false);\n\n        match result {\n            // If `systemctl is-active` returns without an error code and stdout matches \"active\" (just to guard againt\n            // unhandled cases), the service can be considered running.\n            Ok(stdout) => {\n                let mut copy = stdout.to_owned();\n                trim_newline(&mut copy);\n\n                if copy != \"active\" {\n                    // make sure the output is as we expected\n                    Err(ServiceManagerError::Other(ExitStatus::default(), stdout))\n                } else {\n                    Ok(StatusResult::Running)\n                }\n            }\n\n            Err(e) => {\n                if let ServiceManagerError::Other(_err, ref output) = e {\n                    let mut copy = output.to_owned();\n                    trim_newline(&mut copy);\n\n                    if copy == \"inactive\" {\n                        return Ok(StatusResult::Stopped);\n                    }\n                } else {\n                    error!(\"failed to run 'systemctl is-active': {}\", e.to_string());\n                }\n\n                // Failed to check if the unit is running\n                match systemctl(\"cat\", name, false) {\n                    // \"systemctl cat\" seems to no have stable exit codes so we need\n                    // to check the output if it looks like \"No files found for yyyy.service\"\n                    // At least, the exit code are not documented for systemd v255 (newest at the time of writing)\n                    Err(ServiceManagerError::Other(status, msg)) => {\n                        if msg.contains(\"No files found for\") {\n                            Ok(StatusResult::NotFound)\n                        } else {\n                            Err(ServiceManagerError::Other(status, msg))\n                        }\n                    }\n\n                    // Any other error type means something went completely wrong while running systemctl altogether.\n                    Err(e) => Err(e),\n\n                    // Fine, systemctl cat worked so if the output is \"inactive\" we know the service is installed\n                    // but stopped.\n                    Ok(_) => {\n                        // Unit seems to be installed so check the output of result\n                        let mut stderr = e.to_string();\n                        trim_newline(&mut stderr);\n\n                        if stderr == \"inactive\" {\n                            Ok(StatusResult::Stopped)\n                        } else {\n                            Err(e)\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    fn start(&self) -> Result<StatusResult> {\n        let name = \"portmaster.service\";\n\n        // This time we need to run as root through pkexec or similar binaries like kdesudo/gksudo.\n        systemctl(\"start\", name, true)?;\n\n        // Check the status again to be sure it's started now\n        self.status()\n    }\n}\n\nfn systemctl(\n    cmd: &str,\n    unit: &str,\n    run_as_root: bool,\n) -> std::result::Result<String, ServiceManagerError> {\n    let output = run(run_as_root, SYSTEMCTL, vec![cmd, unit])?;\n\n    // The command have been able to run (i.e. has been spawned and executed by the kernel).\n    // We now need to check the exit code and \"stdout/stderr\" output in case of an error.\n    if output.status.success() {\n        Ok(String::from_utf8(output.stdout)?)\n    } else {\n        Err(output.into())\n    }\n}\n\nfn run<'a>(root: bool, cmd: &'a str, args: Vec<&'a str>) -> std::io::Result<std::process::Output> {\n    // clone the args vector so we can insert the actual command in case we're running\n    // through pkexec or friends. This is just callled a couple of times on start-up\n    // so cloning the vector does not add any mentionable performance impact here and it's better\n    // than expecting a mutalble vector in the first place.\n\n    let mut args = args.to_vec();\n\n    let mut command = match root {\n        true => {\n            // if we run through pkexec and friends we need to append cmd as the second argument.\n\n            args.insert(0, cmd);\n            match get_sudo_cmd() {\n                Ok(cmd) => {\n                    match cmd {\n                        SudoCommand::Pkexec => {\n                            // disable the internal text-based prompt agent from pkexec because it won't work anyway.\n                            args.insert(0, \"--disable-internal-agent\");\n                            Command::new(\"/usr/bin/pkexec\")\n                        }\n                        SudoCommand::Gksu => {\n                            args.insert(0, \"--message=Please enter your password:\");\n                            args.insert(1, \"--sudo-mode\");\n\n                            Command::new(\"/usr/bin/gksudo\")\n                        }\n                    }\n                }\n                Err(err) => return Err(err),\n            }\n        }\n        false => Command::new(cmd),\n    };\n\n    command.env(\"LC_ALL\", \"C\");\n\n    command\n        .stdin(Stdio::null())\n        .stdout(Stdio::piped())\n        .stderr(Stdio::piped());\n\n    command.args(args).output()\n}\n\nfn trim_newline(s: &mut String) {\n    if s.ends_with('\\n') {\n        s.pop();\n        if s.ends_with('\\r') {\n            s.pop();\n        }\n    }\n}\n\nfn get_sudo_cmd() -> std::result::Result<SudoCommand, std::io::Error> {\n    if fs::metadata(\"/usr/bin/pkexec\").is_ok() {\n        return Ok(SudoCommand::Pkexec);\n    }\n\n    if fs::metadata(\"/usr/bin/gksudo\").is_ok() {\n        return Ok(SudoCommand::Gksu);\n    }\n\n    Err(std::io::Error::new(\n        io::ErrorKind::NotFound,\n        \"failed to detect sudo command\",\n    ))\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/service/windows_service.rs",
    "content": "use std::{\n    sync::{Arc, Mutex},\n    time::Duration,\n};\n\nuse windows::{\n    core::{HSTRING, PCWSTR},\n    Win32::{Foundation::HWND, UI::WindowsAndMessaging::SHOW_WINDOW_CMD},\n};\nuse windows_service::{\n    service::{Service, ServiceAccess},\n    service_manager::{ServiceManager, ServiceManagerAccess},\n};\n\nconst SERVICE_NAME: &str = \"PortmasterCore\";\n\npub struct WindowsServiceManager {\n    manager: Option<ServiceManager>,\n    service: Option<Service>,\n}\n\nlazy_static! {\n    pub static ref SERVICE_MANGER: Arc<Mutex<WindowsServiceManager>> =\n        Arc::new(Mutex::new(WindowsServiceManager::new()));\n}\n\nimpl WindowsServiceManager {\n    pub fn new() -> Self {\n        Self {\n            manager: None,\n            service: None,\n        }\n    }\n\n    fn init_manager(&mut self) -> super::Result<()> {\n        // Initialize service manager. This connects to the active service database and can query status.\n        let manager = match ServiceManager::local_computer(\n            None::<&str>,\n            ServiceManagerAccess::ENUMERATE_SERVICE, // Only query status is allowed form non privileged application.\n        ) {\n            Ok(manager) => manager,\n            Err(err) => {\n                return Err(windows_to_manager_err(err));\n            }\n        };\n        self.manager = Some(manager);\n        Ok(())\n    }\n\n    fn open_service(&mut self) -> super::Result<bool> {\n        if let None = self.manager {\n            self.init_manager()?;\n        }\n\n        if let Some(manager) = &self.manager {\n            let service = match manager.open_service(SERVICE_NAME, ServiceAccess::QUERY_STATUS) {\n                Ok(service) => service,\n                Err(_) => {\n                    return Ok(false); // Service is not installed.\n                }\n            };\n            // Service is installed and the state can be queried.\n            self.service = Some(service);\n            return Ok(true);\n        }\n\n        return Err(super::ServiceManagerError::WindowsError(\n            \"failed to initialize manager\".to_string(),\n        ));\n    }\n}\n\nimpl super::ServiceManager for Arc<Mutex<WindowsServiceManager>> {\n    fn status(&self) -> super::Result<super::status::StatusResult> {\n        if let Ok(mut manager) = self.lock() {\n            if let None = manager.service {\n                // Try to open service\n                if !manager.open_service()? {\n                    // Service is not installed.\n                    return Ok(super::status::StatusResult::NotFound);\n                }\n            }\n\n            if let Some(service) = &manager.service {\n                match service.query_status() {\n                    Ok(status) => match status.current_state {\n                        windows_service::service::ServiceState::Stopped\n                        | windows_service::service::ServiceState::StopPending\n                        | windows_service::service::ServiceState::PausePending\n                        | windows_service::service::ServiceState::StartPending\n                        | windows_service::service::ServiceState::ContinuePending\n                        | windows_service::service::ServiceState::Paused => {\n                            // Stopped or in a transition state.\n                            return Ok(super::status::StatusResult::Stopped);\n                        }\n                        windows_service::service::ServiceState::Running => {\n                            // Everything expect Running state is considered stopped.\n                            return Ok(super::status::StatusResult::Running);\n                        }\n                    },\n                    Err(err) => {\n                        return Err(super::ServiceManagerError::WindowsError(err.to_string()));\n                    }\n                }\n            }\n        }\n        // This should be unreachable.\n        Ok(super::status::StatusResult::NotFound)\n    }\n\n    fn start(&self) -> super::Result<super::status::StatusResult> {\n        if let Ok(mut service_manager) = self.lock() {\n            // Check if service is installed.\n            if let None = &service_manager.service {\n                if let Err(_) = service_manager.open_service() {\n                    return Ok(super::status::StatusResult::NotFound);\n                }\n            }\n\n            // Run service manager with elevated privileges. This will show access popup.\n            unsafe {\n                windows::Win32::UI::Shell::ShellExecuteW(\n                    HWND::default(),\n                    &HSTRING::from(\"runas\"),\n                    &HSTRING::from(\"C:\\\\Windows\\\\System32\\\\sc.exe\"),\n                    &HSTRING::from(format!(\"start {}\", SERVICE_NAME)),\n                    PCWSTR::null(),\n                    SHOW_WINDOW_CMD(0),\n                );\n            }\n\n            // Wait for service to start. Timeout 10s (100 * 100ms).\n            if let Some(service) = &service_manager.service {\n                for _ in 0..100 {\n                    match service.query_status() {\n                        Ok(status) => {\n                            if let windows_service::service::ServiceState::Running =\n                                status.current_state\n                            {\n                                return Ok(super::status::StatusResult::Running);\n                            } else {\n                                std::thread::sleep(Duration::from_millis(100));\n                            }\n                        }\n                        Err(err) => return Err(windows_to_manager_err(err)),\n                    }\n                }\n            }\n            // Timeout starting the service.\n            return Ok(super::status::StatusResult::Stopped);\n        }\n        return Err(super::ServiceManagerError::WindowsError(\n            \"failed to start service\".to_string(),\n        ));\n    }\n}\n\nfn windows_to_manager_err(err: windows_service::Error) -> super::ServiceManagerError {\n    if let windows_service::Error::Winapi(_) = err {\n        // Winapi does not contain the full error. Get the actual error from windows.\n        return super::ServiceManagerError::WindowsError(\n            windows::core::Error::from_win32().to_string(), // Internally will call `GetLastError()` and parse the result.\n        );\n    } else {\n        return super::ServiceManagerError::WindowsError(err.to_string());\n    }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/traymenu.rs",
    "content": "use std::ops::Deref;\nuse std::sync::atomic::AtomicBool;\nuse std::sync::RwLock;\nuse std::{sync::atomic::Ordering};\nuse chrono::{DateTime, Local};\n\nuse log::{debug, error};\nuse tauri::{\n    image::Image,\n    menu::{Menu, MenuBuilder, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder},\n    tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder},\n    Manager, Wry,\n};\nuse tauri_plugin_window_state::{AppHandleExt, StateFlags};\n\nuse crate::config;\nuse crate::{\n    portapi::{\n        client::PortAPI,\n        message::{ParseError},\n        models::{\n            config::BooleanValue,\n            spn::SPNStatus,\n            system_status_types::{self, SystemStatus},\n        },\n        types::{Request, Response},\n    },\n    portmaster::PortmasterExt,\n    window::{create_main_window, may_navigate_to_ui, open_window},\n};\nuse tauri_plugin_dialog::{DialogExt, MessageDialogButtons};\n\npub type AppIcon = TrayIcon<Wry>;\npub type ContextMenu = Menu<Wry>;\n\nstatic SPN_STATE: AtomicBool = AtomicBool::new(false);\n\n#[derive(Copy, Clone)]\nenum IconColor {\n    Red,\n    Green,\n    Blue,\n    Yellow,\n}\n\nstatic CURRENT_ICON_COLOR: RwLock<IconColor> = RwLock::new(IconColor::Red);\npub static USER_THEME: RwLock<dark_light::Mode> = RwLock::new(dark_light::Mode::Unspecified);\nconst OPEN_KEY: &str = \"open\";\nconst EXIT_UI_KEY: &str = \"exit_ui\";\nconst SPN_STATUS_KEY: &str = \"spn_status\";\nconst SPN_BUTTON_KEY: &str = \"spn_toggle\";\nconst GLOBAL_STATUS_KEY: &str = \"global_status\";\nconst SHUTDOWN_KEY: &str = \"shutdown\";\nconst SYSTEM_THEME_KEY: &str = \"system_theme\";\nconst LIGHT_THEME_KEY: &str = \"light_theme\";\nconst DARK_THEME_KEY: &str = \"dark_theme\";\nconst RELOAD_KEY: &str = \"reload\";\nconst FORCE_SHOW_KEY: &str = \"force-show\";\n\nconst PM_TRAY_ICON_ID: &str = \"pm_icon\";\nconst PM_TRAY_MENU_ID: &str = \"pm_tray_menu\";\n\nconst PAUSE_SPN_5_KEY: &str = \"pause_spn_5\";\nconst PAUSE_SPN_15_KEY: &str = \"pause_spn_15\";\nconst PAUSE_SPN_60_KEY: &str = \"pause_spn_60\";\nconst PAUSE_PM_5_KEY: &str = \"pause_pm_5\";\nconst PAUSE_PM_15_KEY: &str = \"pause_pm_15\";\nconst PAUSE_PM_60_KEY: &str = \"pause_pm_60\";\nconst RESUME_KEY: &str = \"resume_all\";\nconst PAUSE_INFO_KEY: &str = \"pause_info\";\nconst PAUSE_INFO_TIME_KEY: &str = \"pause_info_time\";\n\n// Icons\n\nfn get_theme_mode() -> dark_light::Mode {\n    if let Ok(value) = USER_THEME.read() {\n        return *value.deref();\n    }\n    dark_light::detect().unwrap_or(dark_light::Mode::Unspecified)\n}\n\nfn get_green_icon() -> &'static [u8] {\n    const LIGHT_GREEN_ICON: &[u8] =\n        include_bytes!(\"../../../../assets/data/icons/pm_light_green_64.png\");\n    const DARK_GREEN_ICON: &[u8] =\n        include_bytes!(\"../../../../assets/data/icons/pm_dark_green_64.png\");\n\n    match get_theme_mode() {\n        dark_light::Mode::Light => DARK_GREEN_ICON,\n        _ => LIGHT_GREEN_ICON,\n    }\n}\n\nfn get_blue_icon() -> &'static [u8] {\n    const LIGHT_BLUE_ICON: &[u8] =\n        include_bytes!(\"../../../../assets/data/icons/pm_light_blue_64.png\");\n    const DARK_BLUE_ICON: &[u8] =\n        include_bytes!(\"../../../../assets/data/icons/pm_dark_blue_64.png\");\n    match get_theme_mode() {\n        dark_light::Mode::Light => DARK_BLUE_ICON,\n        _ => LIGHT_BLUE_ICON,\n    }\n}\n\nfn get_red_icon() -> &'static [u8] {\n    const LIGHT_RED_ICON: &[u8] =\n        include_bytes!(\"../../../../assets/data/icons/pm_light_red_64.png\");\n    const DARK_RED_ICON: &[u8] = include_bytes!(\"../../../../assets/data/icons/pm_dark_red_64.png\");\n    match get_theme_mode() {\n        dark_light::Mode::Light => DARK_RED_ICON,\n        _ => LIGHT_RED_ICON,\n    }\n}\n\nfn get_yellow_icon() -> &'static [u8] {\n    const LIGHT_YELLOW_ICON: &[u8] =\n        include_bytes!(\"../../../../assets/data/icons/pm_light_yellow_64.png\");\n    const DARK_YELLOW_ICON: &[u8] =\n        include_bytes!(\"../../../../assets/data/icons/pm_dark_yellow_64.png\");\n    match get_theme_mode() {\n        dark_light::Mode::Light => DARK_YELLOW_ICON,\n        _ => LIGHT_YELLOW_ICON,\n    }\n}\n\nfn get_icon(icon: IconColor) -> &'static [u8] {\n    match icon {\n        IconColor::Red => get_red_icon(),\n        IconColor::Green => get_green_icon(),\n        IconColor::Blue => get_blue_icon(),\n        IconColor::Yellow => get_yellow_icon(),\n    }\n}\n\nfn build_tray_menu(\n    app: &tauri::AppHandle,\n    status: &str,\n    spn_status_text: &str,\n    pause_info: &system_status_types::PauseInfo,\n) -> core::result::Result<ContextMenu, Box<dyn std::error::Error>> {\n    load_theme(app);\n\n    let open_btn = MenuItemBuilder::with_id(OPEN_KEY, \"Open App\").build(app)?;\n    let exit_ui_btn = MenuItemBuilder::with_id(EXIT_UI_KEY, \"Exit UI\").build(app)?;\n    let shutdown_btn = MenuItemBuilder::with_id(SHUTDOWN_KEY, \"Shut Down Portmaster\").build(app)?;\n\n    // Global status\n    let global_status_text = if pause_info.interception {\n        format!(\"Status: {} (PAUSED)\", status)\n    } else {\n        format!(\"Status: {}\", status)\n    };\n    let global_status = MenuItemBuilder::with_id(GLOBAL_STATUS_KEY, global_status_text)\n        .enabled(false)\n        .build(app)\n        .unwrap();\n\n    // Pause items\n    let (pause_status_item, pause_status_time_item, resume_item) = if pause_info.interception || pause_info.spn {\n        let status_text = match (pause_info.interception, pause_info.spn) {\n            (true, true) => \"Portmaster and SPN are paused\",\n            (true, false) => \"Portmaster is paused\", \n            (false, true) => \"SPN is paused\",\n            _ => unreachable!(), // We already checked at least one is true\n        };\n        let status_item = MenuItemBuilder::with_id(PAUSE_INFO_KEY, status_text).enabled(false).build(app).ok();\n        \n        let time_item = if let Ok(resume_time) = DateTime::parse_from_rfc3339(&pause_info.till_time) {\n            let resume_time_local = resume_time.with_timezone(&Local);            \n            if resume_time_local > Local::now() {\n                let formatted_time = resume_time_local.format(\"%H:%M:%S\").to_string();\n                MenuItemBuilder::with_id(PAUSE_INFO_TIME_KEY, format!(\"Auto-resume at {}\", formatted_time)).enabled(false).build(app).ok()\n            } else {\n                None\n            }\n        } else {\n            None\n        };\n        \n        let resume_item = MenuItemBuilder::with_id(RESUME_KEY, \"Resume now\").build(app).ok();\n        (status_item, time_item, resume_item)\n    } else {\n        (None, None, None)\n    };\n\n    // SPN button    \n    let (spn_enabled, spn_button_text ) = match spn_status_text {\n        \"disabled\" => { (false, \"Enable SPN\") }\n        _ => { (true, \"Disable SPN\") },\n    };\n    \n    let spn_status = MenuItemBuilder::with_id(SPN_STATUS_KEY, format!(\"SPN: {}\", spn_status_text))\n        .enabled(false)\n        .build(app)\n        .unwrap();\n    let spn_button = MenuItemBuilder::with_id(SPN_BUTTON_KEY, spn_button_text)\n        .build(app)\n        .unwrap();\n\n    // Setup Icon theme submenu\n    let system_theme = MenuItemBuilder::with_id(SYSTEM_THEME_KEY, \"System\")\n        .build(app)\n        .unwrap();\n    let light_theme = MenuItemBuilder::with_id(LIGHT_THEME_KEY, \"Light\")\n        .build(app)\n        .unwrap();\n    let dark_theme = MenuItemBuilder::with_id(DARK_THEME_KEY, \"Dark\")\n        .build(app)\n        .unwrap();\n    let theme_menu = SubmenuBuilder::new(app, \"Icon Theme\")\n        .items(&[&system_theme, &light_theme, &dark_theme])\n        .build()?;\n\n\n    // Setup Pause/Resume menu items\n    let disabled_spn_pause = (!spn_enabled && !pause_info.spn) || pause_info.interception;\n    let pause_spn_5min_item = MenuItemBuilder::with_id(PAUSE_SPN_5_KEY, \"Pause SPN for 5 minutes\").enabled(!disabled_spn_pause).build(app)?;\n    let pause_spn_15min_item = MenuItemBuilder::with_id(PAUSE_SPN_15_KEY, \"Pause SPN for 15 minutes\").enabled(!disabled_spn_pause).build(app)?;\n    let pause_spn_1hour_item = MenuItemBuilder::with_id(PAUSE_SPN_60_KEY, \"Pause SPN for 1 hour\").enabled(!disabled_spn_pause).build(app)?;\n\n    let pause_pm_5min_item = MenuItemBuilder::with_id(PAUSE_PM_5_KEY, \"Pause for 5 minutes\").build(app)?;\n    let pause_pm_15min_item = MenuItemBuilder::with_id(PAUSE_PM_15_KEY, \"Pause for 15 minutes\").build(app)?;\n    let pause_pm_1hour_item = MenuItemBuilder::with_id(PAUSE_PM_60_KEY, \"Pause for 1 hour\").build(app)?;\n\n    let pause_menu =  if !spn_enabled && !pause_info.spn {\n        SubmenuBuilder::new(app, \"Pause\")\n            .items(&[\n                &pause_pm_5min_item,\n                &pause_pm_15min_item,\n                &pause_pm_1hour_item,\n            ])\n            .build()?\n    } else {\n        SubmenuBuilder::new(app, \"Pause\")\n            .items(&[\n                &pause_spn_5min_item,\n                &pause_spn_15min_item,\n                &pause_spn_1hour_item,\n                &PredefinedMenuItem::separator(app)?,\n                &pause_pm_5min_item,\n                &pause_pm_15min_item,\n                &pause_pm_1hour_item,\n            ])\n            .build()?\n    };\n\n    /* DEV MENU\n    let force_show_window = MenuItemBuilder::with_id(FORCE_SHOW_KEY, \"Force Show UI\").build(app)?;\n    let reload_btn = MenuItemBuilder::with_id(RELOAD_KEY, \"Reload User Interface\").build(app)?;\n    let developer_menu = SubmenuBuilder::new(app, \"Developer\")\n        .items(&[&reload_btn, &force_show_window])\n        .build()?;\n    */\n    \n    // Assemble menu items\n    let s = PredefinedMenuItem::separator(app)?;\n    let mut items: Vec<&dyn tauri::menu::IsMenuItem<Wry>> = Vec::new();\n\n\n\n    items.push(&global_status);    \n    items.push(&s);\n\n    if let Some(ref pause_status_item) = pause_status_item {\n        items.push(pause_status_item);\n    }\n    if let Some(ref pause_status_time_item) = pause_status_time_item {\n        items.push(pause_status_time_item);\n    }\n    if let Some(ref resume_item) = resume_item {\n        items.push(resume_item);\n    }\n    items.push(&pause_menu);\n    items.push(&s);\n\n    items.push(&spn_status);\n    items.push(&spn_button);\n    items.push(&s);\n\n    items.push(&theme_menu);\n    items.push(&s);\n    \n    items.push(&open_btn);\n    items.push(&s);\n\n    items.push(&exit_ui_btn);\n    items.push(&shutdown_btn);\n    //items.push(&developer_menu);\n    \n    let menu = MenuBuilder::with_id(app, PM_TRAY_MENU_ID)\n        .items(&items)\n        .build()?;\n\n    return Ok(menu);\n}\n\npub fn setup_tray_menu(\n    app: &mut tauri::App,\n) -> core::result::Result<AppIcon, Box<dyn std::error::Error>> {\n    let menu = build_tray_menu(app.handle(), \"unknown\", \"disabled\", &system_status_types::PauseInfo::default())?;\n\n    let icon = TrayIconBuilder::with_id(PM_TRAY_ICON_ID)\n        .icon(Image::from_bytes(get_red_icon()).unwrap())\n        .menu(&menu)\n        .on_menu_event(move |app, event| match event.id().as_ref() {\n            EXIT_UI_KEY => {\n                let handle = app.clone();\n                app.dialog()\n                    .message(\"This does not stop the Portmaster system service\")\n                    .title(\"Do you really want to quit the user interface?\")\n                    .buttons(MessageDialogButtons::OkCancelCustom(\n                        \"Yes, exit\".to_owned(),\n                        \"No\".to_owned(),\n                    ))\n                    .show(move |answer| {\n                        if answer {\n                            // let _ = handle.emit(\"exit-requested\", \"\");\n                            handle.exit(0);\n                        }\n                    });\n            }\n            OPEN_KEY => {\n                let _ = open_window(app);\n            }\n            RELOAD_KEY => {\n                if let Ok(mut win) = open_window(app) {\n                    may_navigate_to_ui(&mut win, true);\n                }\n            }\n            FORCE_SHOW_KEY => {\n                match create_main_window(app) {\n                    Ok(mut win) => {\n                        may_navigate_to_ui(&mut win, true);\n                        if let Err(err) = win.show() {\n                            error!(\"[tauri] failed to show window: {}\", err.to_string());\n                        };\n                    }\n                    Err(err) => {\n                        error!(\"[tauri] failed to create main window: {}\", err.to_string());\n                    }\n                };\n            }\n            SPN_BUTTON_KEY => {\n                if SPN_STATE.load(Ordering::Acquire) {\n                    app.portmaster().set_spn_enabled(false);\n                } else {\n                    app.portmaster().set_spn_enabled(true);\n                }\n            }\n            SHUTDOWN_KEY => {\n                app.portmaster().trigger_shutdown();\n            }\n            SYSTEM_THEME_KEY => update_icon_theme(app, dark_light::Mode::Unspecified),\n            DARK_THEME_KEY => update_icon_theme(app, dark_light::Mode::Dark),\n            LIGHT_THEME_KEY => update_icon_theme(app, dark_light::Mode::Light),\n\n            PAUSE_SPN_5_KEY => app.portmaster().set_pause(60*5, true),\n            PAUSE_SPN_15_KEY => app.portmaster().set_pause(60*15, true),\n            PAUSE_SPN_60_KEY => app.portmaster().set_pause(60*60, true),\n            PAUSE_PM_5_KEY => app.portmaster().set_pause(60*5, false),\n            PAUSE_PM_15_KEY => app.portmaster().set_pause(60*15, false),\n            PAUSE_PM_60_KEY => app.portmaster().set_pause(60*60, false),\n            RESUME_KEY => app.portmaster().set_resume(),\n\n            other => {\n                error!(\"unknown menu event id: {}\", other);\n            }\n        })\n        .on_tray_icon_event(|tray, event| {\n            // not supported on linux\n\n            if let tauri::tray::TrayIconEvent::Click {\n                id: _,\n                position: _,\n                rect: _,\n                button,\n                button_state,\n            } = event\n            {\n                if let (MouseButton::Left, MouseButtonState::Down) = (button, button_state) {\n                    let _ = open_window(tray.app_handle());\n                }\n            }\n        })\n        .build(app)?;\n\n    Ok(icon)\n}\n\npub fn update_icon(icon: AppIcon, system_status: SystemStatus, spn_status: String) {\n    // Extract the worst state type \n    let worst_state_type = system_status.worst_state\n        .as_ref()\n        .and_then(|ws| ws.state.state_type.clone())\n        .unwrap_or(system_status_types::StateType::Undefined);\n\n    // Determine status and icon color in a single match expression\n    let (status, icon_color) = match worst_state_type {\n        system_status_types::StateType::Error => (\"Insecure\", IconColor::Red),\n        system_status_types::StateType::Warning => (\"Insecure\", IconColor::Yellow),\n        _ => {\n            let color = match spn_status.as_str() {\n                \"connected\" | \"connecting\" => IconColor::Blue,\n                _ => IconColor::Green,\n            };\n            (\"Secured\", color)\n        }\n    };\n\n    // Extract pause info from system status\n    let pause_info = system_status\n        .get_module_state(\"Control\", \"control:paused\")\n        .and_then(|state| state.data.as_ref())\n        .and_then(|data| serde_json::from_value::<system_status_types::PauseInfo>(data.clone()).ok())\n        .unwrap_or_default();\n\n    // Rebuild and set the tray menu\n    if let Ok(menu) = build_tray_menu(icon.app_handle(), status, spn_status.as_str(), &pause_info) {\n        if let Err(err) = icon.set_menu(Some(menu)) {\n            error!(\"failed to set menu on tray icon: {}\", err.to_string());\n        }\n    }\n\n    update_icon_color(&icon, icon_color);\n}\n\npub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {\n    let icon = match app.tray_by_id(PM_TRAY_ICON_ID) {\n        Some(icon) => icon,\n        None => {\n            error!(\"cancel try_handler: missing try icon\");\n            return;\n        }\n    };\n\n    let mut system_status_subscription = match cli\n        .request(Request::QuerySubscribe(\n            \"query runtime:system/status\".to_string(),\n        ))\n        .await\n    {\n        Ok(rx) => rx,\n        Err(err) => {\n            error!(\n                \"cancel try_handler: failed to subscribe to 'runtime:system/status': {}\",\n                err\n            );\n            return;\n        }\n    };\n\n    let mut spn_status_subscription = match cli\n        .request(Request::QuerySubscribe(\n            \"query runtime:spn/status\".to_string(),\n        ))\n        .await\n    {\n        Ok(rx) => rx,\n        Err(err) => {\n            error!(\n                \"cancel try_handler: failed to subscribe to 'runtime:spn/status': {}\",\n                err\n            );\n            return;\n        }\n    };\n\n    let mut spn_config_subscription = match cli\n        .request(Request::QuerySubscribe(\n            \"query config:spn/enable\".to_string(),\n        ))\n        .await\n    {\n        Ok(rx) => rx,\n        Err(err) => {\n            error!(\n                \"cancel try_handler: failed to subscribe to 'runtime:spn/enable': {}\",\n                err\n            );\n            return;\n        }\n    };\n\n    let mut portmaster_shutdown_event_subscription = match cli\n        .request(Request::Subscribe(\n            \"query runtime:modules/core/event/shutdown\".to_string(),\n        ))\n        .await\n    {\n        Ok(rx) => rx,\n        Err(err) => {\n            error!(\n                \"cancel try_handler: failed to subscribe to 'runtime:modules/core/event/shutdown': {}\",\n                err\n            );\n            return;\n        }\n    };\n\n    update_icon_color(&icon, IconColor::Blue);\n\n    let mut system_status = SystemStatus::default();\n    let mut spn_status: String = \"\".to_string();\n\n    loop {\n        tokio::select! {\n            msg = system_status_subscription.recv() => {\n                let msg = match msg {\n                    Some(m) => m,\n                    None => { break }\n                };\n\n                let res = match msg {\n                    Response::Ok(key, payload) => Some((key, payload)),\n                    Response::New(key, payload) => Some((key, payload)),\n                    Response::Update(key, payload) => Some((key, payload)),\n                    _ => None,\n                };\n\n                if let Some((_, payload)) = res {\n                    match payload.parse::<SystemStatus>() {\n                        Ok(system_status_update) => {\n                            system_status.clone_from(&system_status_update);\n                            update_icon(icon.clone(), system_status.clone(), spn_status.clone());\n                        },\n                        Err(err) => match err {\n                            ParseError::Json(err) => {\n                                error!(\"failed to parse SystemStatus: {}\", err);\n                            }\n                            _ => {\n                                error!(\"unknown error when parsing SystemStatus payload\");\n                            }\n                        },\n                    }\n                }\n            },\n            msg = spn_status_subscription.recv() => {\n                let msg = match msg {\n                    Some(m) => m,\n                    None => { break }\n                };\n\n                let res = match msg {\n                    Response::Ok(key, payload) => Some((key, payload)),\n                    Response::New(key, payload) => Some((key, payload)),\n                    Response::Update(key, payload) => Some((key, payload)),\n                    _ => None,\n                };\n\n                if let Some((_, payload)) = res {\n                    match payload.parse::<SPNStatus>() {\n                        Ok(value) => {\n                            debug!(\"SPN status update: {}\", value.status);\n                            spn_status.clone_from(&value.status);\n                            update_icon(icon.clone(), system_status.clone(), spn_status.clone());\n                        },\n                        Err(err) => match err {\n                            ParseError::Json(err) => {\n                                error!(\"failed to parse spn status value: {}\", err)\n                            },\n                            _ => {\n                                error!(\"unknown error when parsing spn status value\")\n                            }\n                        }\n                    }\n                }\n            },\n            msg = spn_config_subscription.recv() => {\n                let msg = match msg {\n                    Some(m) => m,\n                    None => { break }\n                };\n\n                let res = match msg {\n                    Response::Ok(key, payload) => Some((key, payload)),\n                    Response::New(key, payload) => Some((key, payload)),\n                    Response::Update(key, payload) => Some((key, payload)),\n                    _ => None,\n                };\n\n                if let Some((_, payload)) = res {\n                    match payload.parse::<BooleanValue>() {\n                        Ok(value) => {\n                            SPN_STATE.store(value.value.unwrap_or(false), Ordering::Release);\n                        },\n                        Err(err) => match err {\n                            ParseError::Json(err) => {\n                                error!(\"failed to parse config value: {}\", err)\n                            },\n                            _ => {\n                                error!(\"unknown error when parsing config value\")\n                            }\n                        }\n                    }\n                }\n            },\n            msg = portmaster_shutdown_event_subscription.recv() => {\n                let msg = match msg {\n                    Some(m) => m,\n                    None => { break }\n                };\n                debug!(\"Shutdown request received: {:?}\", msg);\n                match msg {\n                    Response::Ok(msg, _) | Response::New(msg, _) | Response::Update(msg, _) => {\n                        if let Err(err) = app.save_window_state(StateFlags::SIZE | StateFlags::POSITION) {\n                            error!(\"failed to save window state: {}\", err);\n                        }\n                        debug!(\"shutting down: {}\", msg);\n                        app.exit(0)\n                    },\n                    _ => {},\n                }\n            }\n        }\n    }\n\n    update_icon_nostate(icon.clone());\n}\n\npub fn update_icon_nostate(icon: AppIcon) {\n    update_icon_color(&icon, IconColor::Red);\n\n    if let Ok(menu) = build_tray_menu(icon.app_handle(), \"unknown\",  \"unknown\", &system_status_types::PauseInfo::default()) {\n        if let Err(err) = icon.set_menu(Some(menu)) {\n            error!(\"failed to set menu on tray icon: {}\", err.to_string());\n        }\n    }\n}\n\nfn update_icon_color(icon: &AppIcon, new_color: IconColor) {\n    if let Ok(mut value) = CURRENT_ICON_COLOR.write() {\n        *value = new_color;\n    }\n    _ = icon.set_icon(Some(Image::from_bytes(get_icon(new_color)).unwrap()));\n}\n\nfn update_icon_theme(app: &tauri::AppHandle, theme: dark_light::Mode) {\n    if let Ok(mut value) = USER_THEME.write() {\n        *value = theme;\n    }\n    let icon = match app.tray_by_id(PM_TRAY_ICON_ID) {\n        Some(icon) => icon,\n        None => {\n            error!(\"cancel theme update: missing try icon\");\n            return;\n        }\n    };\n    if let Ok(value) = CURRENT_ICON_COLOR.read() {\n        _ = icon.set_icon(Some(Image::from_bytes(get_icon(*value)).unwrap()));\n    }\n    for (_, v) in app.webview_windows() {\n        super::window::set_window_icon(&v);\n    }\n    save_theme(app, theme);\n}\n\nfn load_theme(app: &tauri::AppHandle) {\n    match config::load(app) {\n        Ok(config) => {\n            let theme = match config.theme {\n                config::Theme::Light => dark_light::Mode::Light,\n                config::Theme::Dark => dark_light::Mode::Dark,\n                config::Theme::System => dark_light::Mode::Unspecified,\n            };\n\n            if let Ok(mut value) = USER_THEME.write() {\n                *value = theme;\n            }\n        }\n        Err(err) => error!(\"failed to load config file: {}\", err),\n    }\n}\n\nfn save_theme(app: &tauri::AppHandle, mode: dark_light::Mode) {\n    match config::load(app) {\n        Ok(mut config) => {\n            let theme = match mode {\n                dark_light::Mode::Dark => config::Theme::Dark,\n                dark_light::Mode::Light => config::Theme::Light,\n                dark_light::Mode::Unspecified => config::Theme::System,\n            };\n            config.theme = theme;\n            if let Err(err) = config::save(app, config) {\n                error!(\"failed to save config file: {}\", err)\n            } else {\n                debug!(\"config updated\");\n            }\n        }\n        Err(err) => error!(\"failed to load config file: {}\", err),\n    }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/window.rs",
    "content": "use log::{debug, error};\nuse tauri::{\n    image::Image, AppHandle, Listener, Manager, Result, Theme, UserAttentionType, WebviewUrl,\n    WebviewWindow, WebviewWindowBuilder,\n};\nuse std::sync::{atomic::{AtomicBool, Ordering}};\nuse tauri_plugin_window_state::{AppHandleExt, StateFlags};\n\nuse crate::{portmaster::PortmasterExt, traymenu};\n\nconst LIGHT_PM_ICON: &[u8] = include_bytes!(\"../../../../assets/data/icons/pm_light_512.png\");\nconst DARK_PM_ICON: &[u8] = include_bytes!(\"../../../../assets/data/icons/pm_dark_512.png\");\n\nconst CUSTOM_ENVVAR_FOR_WEBVIEW_PROCESS: &str = \"PORTMASTER_UI_WEBVIEW_PROCESS\";\n\nstatic UI_PROCESS_ENV_VAR_DEFINED_FLAG: AtomicBool = AtomicBool::new(false);\n\n/// Either returns the existing \"main\" window or creates a new one.\n///\n/// The window is not automatically shown (i.e it starts hidden).\n/// If a new main window is created (i.e. the tauri app was minimized to system-tray)\n/// then the window will be automatically navigated to the Portmaster UI endpoint\n/// if ::websocket::is_portapi_reachable returns true.\n///\n/// Either the existing or the newly created window is returned.\npub fn create_main_window(app: &AppHandle) -> Result<WebviewWindow> {\n    let mut window = if let Some(window) = app.get_webview_window(\"main\") {\n        debug!(\"[tauri] main window already created\");\n        window\n    } else {\n        debug!(\"[tauri] creating main window\");\n\n        do_before_any_window_create(); // required operations before window creation\n        let res = WebviewWindowBuilder::new(app, \"main\", WebviewUrl::App(\"index.html\".into()))\n            .title(\"Portmaster\")\n            .visible(false)\n            .inner_size(1200.0, 700.0)\n            .min_inner_size(800.0, 600.0)\n            .zoom_hotkeys_enabled(true)\n            .theme(Some(Theme::Dark))\n            .on_page_load(|_window, _event| {\n                debug!(\"[tauri] main window page loaded: {}\", _event.url());\n                do_after_main_window_created(); // required operations after Main window creation\n            })\n            .on_navigation(|url| {\n                debug!(\"[tauri] main window navigation event: {}\", url);\n                if url.as_str() == \"about:blank\" {\n                    debug!(\"[tauri] blocking navigation to about:blank\");\n                    return false;\n                }\n                return true;\n            })\n            .build();\n\n        match res {\n            Ok(win) => {\n                win.once(\"tauri://error\", |event| {\n                    error!(\"failed to open tauri window: {}\", event.payload());\n                });\n\n                #[cfg(target_os = \"linux\")]\n                {\n                    // Workaround for KDE/Wayland environments on Linux:\n                    // On KDE with Wayland, after hiding and showing the window,\n                    // the title-bar buttons (close, minimize, maximize) may stop working.\n                    // Toggling the resizable property appears to resolve this issue.\n                    // Issue: https://github.com/safing/portmaster/issues/1909\n                    // Additional info: https://github.com/tauri-apps/tauri/issues/6162#issuecomment-1423304398\n                    let win_clone = win.clone();\n                    win.listen(\"tauri://focus\", move |_event| {\n                        let _ = win_clone.set_resizable(false);\n                        let _ = win_clone.set_resizable(true);\n                    });\n                }\n\n                win\n            }\n            Err(err) => {\n                error!(\"[tauri] failed to create main window: {}\", err.to_string());\n\n                return Err(err);\n            }\n        }\n    };\n\n    // If the window is not yet navigated to the Portmaster UI, do it now.\n    may_navigate_to_ui(&mut window, false);\n    set_window_icon(&window);\n\n    #[cfg(debug_assertions)]\n    if std::env::var(\"TAURI_SHOW_IMMEDIATELY\").is_ok() {\n        debug!(\"[tauri] TAURI_SHOW_IMMEDIATELY is set, opening window\");\n\n        if let Err(err) = window.show() {\n            error!(\"[tauri] failed to show window: {}\", err.to_string());\n        }\n    }\n\n    Ok(window)\n}\n\npub fn create_splash_window(app: &AppHandle) -> Result<WebviewWindow> {\n    if let Some(window) = app.get_webview_window(\"splash\") {\n        let _ = window.show();\n        Ok(window)\n    } else {\n\n        do_before_any_window_create(); // required operations before window creation\n        let window = WebviewWindowBuilder::new(app, \"splash\", WebviewUrl::App(\"index.html\".into()))\n            .center()\n            .closable(false)\n            .focused(true)\n            .resizable(false)\n            .visible(true)\n            .title(\"Portmaster\")\n            .inner_size(600.0, 250.0)\n            .zoom_hotkeys_enabled(true)\n            .build()?;\n        set_window_icon(&window);\n\n        let _ = window.request_user_attention(Some(UserAttentionType::Informational));\n\n        Ok(window)\n    }\n}\n\npub fn close_splash_window(app: &AppHandle) -> Result<()> {\n    if let Some(window) = app.get_webview_window(\"splash\") {\n        let _ = window.hide();\n        return window.destroy();\n    }\n    Err(tauri::Error::WindowNotFound)\n}\n\npub fn hide_splash_window(app: &AppHandle) -> Result<()> {\n    if let Some(window) = app.get_webview_window(\"splash\") {\n        return window.hide();\n    }\n    Err(tauri::Error::WindowNotFound)\n}\n\npub fn set_window_icon(window: &WebviewWindow) {\n    let mut mode = if let Ok(value) = traymenu::USER_THEME.read() {\n        *value\n    } else {\n        dark_light::Mode::Unspecified\n    };\n\n    if mode == dark_light::Mode::Unspecified {\n        mode = dark_light::detect().unwrap_or(dark_light::Mode::Dark);\n    }\n\n    let _ = match mode {\n        dark_light::Mode::Light => window.set_icon(Image::from_bytes(DARK_PM_ICON).unwrap()),\n        _ => window.set_icon(Image::from_bytes(LIGHT_PM_ICON).unwrap()),\n    };\n}\n\n/// This function must be called before any window is created.\n/// \n/// Temporarily sets the environment variable `PORTMASTER_WEBVIEW_UI_PROCESS` to \"true\".\n/// This ensures that any child process (i.e., the WebView process) spawned during window creation\n/// will inherit this environment variable. This allows portmaster-core to detect that the process\n/// is a child WebView of the main process.\n/// \n/// IMPORTANT: After the 'Main' window is created, you must call `do_after_main_window_created()` to remove\n/// the environment variable from the main process environment.\n/// This ensures that any subsequent child processes (such as those created by \"open external\" functionality)\n/// will not inherit this environment variable, correctly indicating that they are not part of the\n/// Portmaster UI WebView process.\npub fn do_before_any_window_create() {\n    UI_PROCESS_ENV_VAR_DEFINED_FLAG.store(true, Ordering::SeqCst);\n    std::env::set_var(CUSTOM_ENVVAR_FOR_WEBVIEW_PROCESS, \"true\");\n}\n\n/// This function must be called after the Main window is created.\n/// \n/// Removes the `PORTMASTER_WEBVIEW_UI_PROCESS` environment variable from the main process.\n/// This ensures that only the child WebView process has the variable set, and the main process\n/// does not retain it.\npub fn do_after_main_window_created() {\n     let flag_was_set = UI_PROCESS_ENV_VAR_DEFINED_FLAG.compare_exchange(\n        true, false, Ordering::SeqCst, Ordering::SeqCst\n    ).is_ok();\n\n    if flag_was_set {\n        std::env::remove_var(CUSTOM_ENVVAR_FOR_WEBVIEW_PROCESS);\n    }\n} \n\n/// Opens a window for the tauri application.\n///\n/// If the main window has already been created, it is instructed to\n/// show even if we're currently not connected to Portmaster.\n/// This is safe since the main-window will only be created if Portmaster API\n/// was reachable so the angular application must have finished bootstrapping.\n///\n/// If there's not main window and the Portmaster API is reachable we create a new\n/// main window.\n///\n/// If the Portmaster API is unreachable and there's no main window yet, we show the\n/// splash-screen window.\npub fn open_window(app: &AppHandle) -> Result<WebviewWindow> {\n    if app.portmaster().is_reachable() {\n        match app.get_webview_window(\"main\") {\n            Some(win) => {\n                if let Ok(true) = win.is_minimized() {\n                    let _ = win.unminimize();\n                }\n                app.portmaster().show_window();\n                let _ = win.show();\n                let _ = win.set_focus();\n                set_window_icon(&win);\n                Ok(win)\n            }\n            None => {\n                app.portmaster().show_window();\n\n                create_main_window(app)\n            }\n        }\n    } else {\n        debug!(\"Show splash screen\");\n        create_splash_window(app)\n    }\n}\n\n/// If the Portmaster Websocket database API is reachable the window will be navigated\n/// to the HTTP endpoint of Portmaster to load the UI from there.\n///\n/// Note that only happens if the window URL does not already point to the PM API.\n///\n/// In #[cfg(debug_assertions)] the TAURI_PM_URL environment variable will be used\n/// if set.\n/// Otherwise or in release builds, it will be navigated to http://127.0.0.1:817.\npub fn may_navigate_to_ui(win: &mut WebviewWindow, force: bool) {\n    if !win.app_handle().portmaster().is_reachable() && !force {\n        error!(\"[tauri] portmaster API is not reachable, not navigating\");\n\n        return;\n    }\n    if force || win.label().eq(\"main\") {\n        #[cfg(debug_assertions)]\n        if let Ok(target_url) = std::env::var(\"TAURI_PM_URL\") {\n            debug!(\"[tauri] navigating to {}\", target_url);\n\n            _ = win.navigate(target_url.parse().unwrap());\n\n            return;\n        }\n\n        #[cfg(debug_assertions)]\n        {\n            // Only for dev build\n            // Allow connection to http://localhost:4200\n            let capabilities = include_str!(\"../capabilities/default.json\")\n                .replace(\"http://127.0.0.1:817\", \"http://127.0.0.1:4200\");\n            let _ = win.add_capability(capabilities);\n            debug!(\"[tauri] navigating to http://127.0.0.1:4200\");\n            _ = win.navigate(\"http://127.0.0.1:4200\".parse().unwrap());\n        }\n\n        #[cfg(not(debug_assertions))]\n        {\n            _ = win.navigate(\"http://127.0.0.1:817\".parse().unwrap());\n        }\n    } else {\n        error!(\n            \"not navigating to user interface: current url: {}\",\n            win.url().unwrap().as_str()\n        );\n    }\n}\n\n/// Creates a debounced window state saver that waits for a quiet period before saving.\n///\n/// Returns a sender that can be used to trigger save events. Multiple rapid events\n/// will be debounced - only saving after the specified timeout with no new events.\n///\n/// # Example\n/// ```rust\n/// let save_trigger = create_debounced_window_state_saver(app, state_flags, Duration::from_secs(5));\n/// let _ = save_trigger.try_send(()); // Trigger a save (will be debounced)\n/// ```\npub fn create_debounced_window_state_saver(\n    app: &tauri::App, \n    state_flags: StateFlags,\n    debounce_timeout: std::time::Duration,\n) -> tokio::sync::mpsc::Sender<()> {\n    \n    let app_handle = app.handle().clone();\n    let (tx, mut rx) = tokio::sync::mpsc::channel::<()>(10);\n    \n    // Spawn debouncer task - saves state after the specified timeout following the last event\n    tauri::async_runtime::spawn(async move {\n        loop {\n            if rx.recv().await.is_none() {\n                break; // Channel closed\n            }\n\n            loop {\n                match tokio::time::timeout(debounce_timeout, rx.recv()).await {\n                    Ok(Some(_)) => {                        \n                        continue; // Received another event within timeout period, restart the timer\n                    }\n                    Ok(None) => {                        \n                        return; // Channel closed\n                    }\n                    Err(_) => {\n                        // Timeout: specified duration passed without new events, save state\n                        if let Err(e) = app_handle.save_window_state(state_flags) {\n                            debug!(\"Failed to save window state: {}\", e);\n                        } \n                        break; // Exit inner loop and wait for next event\n                    }\n                }\n            }\n        }\n    });\n\n    tx\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/src/xdg/mod.rs",
    "content": "use cached::proc_macro::once;\nuse dataurl::DataUrl;\nuse gdk_pixbuf::{Pixbuf, PixbufError};\nuse gtk_sys::{\n    gtk_icon_info_free, gtk_icon_info_get_filename, gtk_icon_theme_get_default,\n    gtk_icon_theme_lookup_icon,\n};\nuse log::{debug, error};\nuse std::collections::HashMap;\nuse std::ffi::{c_char, c_int};\nuse std::ffi::{CStr, CString};\nuse std::io;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, RwLock};\nuse std::{\n    env, fs,\n    io::{Error, ErrorKind},\n};\nuse thiserror::Error;\n\nuse ini::{Ini, ParseOption};\n\nlazy_static! {\n    static ref APP_INFO_CACHE: Arc<RwLock<HashMap<String, Option<AppInfo>>>> =\n        Arc::new(RwLock::new(HashMap::new()));\n}\n\n#[derive(Debug, Error)]\npub enum LookupError {\n    #[error(transparent)]\n    IoError(#[from] std::io::Error),\n}\n\npub type Result<T> = std::result::Result<T, LookupError>;\n\n#[derive(Clone, serde::Serialize)]\npub struct AppInfo {\n    pub icon_name: String,\n    pub app_name: String,\n    pub icon_dataurl: String,\n    pub comment: String,\n}\n\nimpl Default for AppInfo {\n    fn default() -> Self {\n        AppInfo {\n            icon_dataurl: \"\".to_string(),\n            icon_name: \"\".to_string(),\n            app_name: \"\".to_string(),\n            comment: \"\".to_string(),\n        }\n    }\n}\n\n#[derive(Clone, serde::Serialize, Debug)]\npub struct ProcessInfo {\n    pub exec_path: String,\n    pub cmdline: String,\n    pub pid: i64,\n    pub matching_path: String,\n}\n\nimpl std::fmt::Display for ProcessInfo {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"{} (cmdline={}) (pid={}) (matching_path={})\",\n            self.exec_path, self.cmdline, self.pid, self.matching_path\n        )\n    }\n}\n\npub fn get_app_info(process_info: ProcessInfo) -> Result<AppInfo> {\n    {\n        let cache = APP_INFO_CACHE.read().unwrap();\n\n        if let Some(value) = cache.get(process_info.exec_path.as_str()) {\n            match value {\n                Some(app_info) => return Ok(app_info.clone()),\n                None => {\n                    return Err(LookupError::IoError(io::Error::new(\n                        io::ErrorKind::NotFound,\n                        \"not found\",\n                    )))\n                }\n            }\n        }\n    }\n\n    let mut needles = Vec::new();\n    if !process_info.exec_path.is_empty() {\n        needles.push(process_info.exec_path.as_str())\n    }\n    if !process_info.cmdline.is_empty() {\n        needles.push(process_info.cmdline.as_str())\n    }\n    if !process_info.matching_path.is_empty() {\n        needles.push(process_info.matching_path.as_str())\n    }\n\n    // sort and deduplicate\n    needles.sort();\n    needles.dedup();\n\n    debug!(\"Searching app info for {:?}\", process_info);\n\n    let mut desktop_files = Vec::new();\n    for dir in get_application_directories()? {\n        let mut files = find_desktop_files(dir.as_path())?;\n        desktop_files.append(&mut files);\n    }\n\n    let mut matches = Vec::new();\n    for needle in needles.clone() {\n        debug!(\"Trying needle {} on exec path\", needle);\n\n        match try_get_app_info(needle, CheckType::Exec, &desktop_files) {\n            Ok(mut result) => {\n                matches.append(&mut result);\n            }\n            Err(LookupError::IoError(ioerr)) => {\n                if ioerr.kind() != ErrorKind::NotFound {\n                    return Err(ioerr.into());\n                }\n            }\n        };\n\n        match try_get_app_info(needle, CheckType::Name, &desktop_files) {\n            Ok(mut result) => {\n                matches.append(&mut result);\n            }\n            Err(LookupError::IoError(ioerr)) => {\n                if ioerr.kind() != ErrorKind::NotFound {\n                    return Err(ioerr.into());\n                }\n            }\n        };\n    }\n\n    if matches.is_empty() {\n        APP_INFO_CACHE\n            .write()\n            .unwrap()\n            .insert(process_info.exec_path, None);\n\n        Err(Error::new(ErrorKind::NotFound, \"failed to find app info\".to_string()).into())\n    } else {\n        // sort matches by length\n        matches.sort_by(|a, b| a.1.cmp(&b.1));\n\n        for mut info in matches {\n            match get_icon_as_png_dataurl(&info.0.icon_name, 32) {\n                Ok(du) => {\n                    debug!(\n                        \"[xdg] best match for {:?} is {:?} with len {}\",\n                        process_info, info.0.icon_name, info.1\n                    );\n\n                    info.0.icon_dataurl = du.1;\n\n                    APP_INFO_CACHE\n                        .write()\n                        .unwrap()\n                        .insert(process_info.exec_path, Some(info.0.clone()));\n\n                    return Ok(info.0);\n                }\n                Err(err) => {\n                    dbg!(\n                        \"{}: failed to get icon: {}\",\n                        info.0.icon_name,\n                        err.to_string()\n                    );\n                }\n            };\n        }\n\n        Err(Error::new(ErrorKind::NotFound, \"failed to find app info\".to_string()).into())\n    }\n}\n\n/// Returns a vector of application directories that are expected\n/// to contain all .desktop files the current user has access to.\n/// The result of this function is cached for 5 minutes as it's not expected\n/// that application directories actually change.\n#[once(time = 300, sync_writes = true, result = true)]\nfn get_application_directories() -> Result<Vec<PathBuf>> {\n    let xdg_home = match env::var_os(\"XDG_DATA_HOME\") {\n        Some(path) => PathBuf::from(path),\n        None => {\n            let home = dirs::home_dir()\n                .ok_or(Error::new(ErrorKind::Other, \"Failed to get home directory\"))?;\n\n            home.join(\".local/share\")\n        }\n    };\n\n    let extra_application_dirs = match env::var_os(\"XDG_DATA_DIRS\") {\n        Some(paths) => env::split_paths(&paths).map(PathBuf::from).collect(),\n        None => {\n            // Fallback if XDG_DATA_DIRS is not set. If it's set, it normally already contains /usr/share and\n            // /usr/local/share\n            vec![\n                PathBuf::from(\"/usr/share\"),\n                PathBuf::from(\"/usr/local/share\"),\n            ]\n        }\n    };\n\n    let mut app_dirs = Vec::new();\n    for extra_dir in extra_application_dirs {\n        app_dirs.push(extra_dir.join(\"applications\"));\n    }\n\n    app_dirs.push(xdg_home.join(\"applications\"));\n\n    Ok(app_dirs)\n}\n\n// TODO(ppacher): cache the result of find_desktop_files as well.\n// Though, seems like we cannot use the #[cached::proc_macro::cached] or #[cached::proc_macro::once] macros here\n// because [`Result<Vec<fs::DirEntry>>>`] does not implement [`Clone`]\nfn find_desktop_files(path: &Path) -> Result<Vec<fs::DirEntry>> {\n    match path.read_dir() {\n        Ok(files) => {\n            let desktop_files = files\n                .filter_map(|entry| entry.ok())\n                .filter(|entry| match entry.file_type() {\n                    Ok(ft) => ft.is_file() || ft.is_symlink(),\n                    _ => false,\n                })\n                .filter(|entry| entry.file_name().to_string_lossy().ends_with(\".desktop\"))\n                .collect::<Vec<_>>();\n\n            Ok(desktop_files)\n        }\n        Err(err) => {\n            // We ignore NotFound errors here because not all application\n            // directories need to exist.\n            if err.kind() == ErrorKind::NotFound {\n                Ok(Vec::new())\n            } else {\n                Err(err.into())\n            }\n        }\n    }\n}\n\nenum CheckType {\n    Name,\n    Exec,\n}\n\nfn try_get_app_info(\n    needle: &str,\n    check: CheckType,\n    desktop_files: &Vec<fs::DirEntry>,\n) -> Result<Vec<(AppInfo, usize)>> {\n    let path = PathBuf::from(needle);\n\n    let file_name = path.as_path().file_name().unwrap_or_default().to_str();\n\n    let mut result = Vec::new();\n\n    for file in desktop_files {\n        let content = Ini::load_from_file_opt(\n            file.path(),\n            ParseOption {\n                enabled_escape: false,\n                enabled_quote: true,\n            },\n        )\n        .map_err(|err| Error::new(ErrorKind::Other, err.to_string()))?;\n\n        let desktop_section = match content.section(Some(\"Desktop Entry\")) {\n            Some(section) => section,\n            None => {\n                continue;\n            }\n        };\n\n        let matches = match check {\n            CheckType::Name => {\n                let name = match desktop_section.get(\"Name\") {\n                    Some(name) => name,\n                    None => {\n                        continue;\n                    }\n                };\n\n                if let Some(file_name) = file_name {\n                    if name.to_lowercase().contains(file_name) {\n                        file_name.len()\n                    } else {\n                        0\n                    }\n                } else {\n                    0\n                }\n            }\n            CheckType::Exec => {\n                let exec = match desktop_section.get(\"Exec\") {\n                    Some(exec) => exec,\n                    None => {\n                        continue;\n                    }\n                };\n\n                if exec.to_lowercase().contains(needle) {\n                    needle.len()\n                } else if let Some(file_name) = file_name {\n                    if exec.to_lowercase().starts_with(file_name) {\n                        file_name.len()\n                    } else {\n                        0\n                    }\n                } else {\n                    0\n                }\n            }\n        };\n\n        if matches > 0 {\n            debug!(\n                \"[xdg] found matching desktop for needle {} file at {}\",\n                needle,\n                file.path().to_string_lossy()\n            );\n\n            let info = parse_app_info(desktop_section);\n\n            result.push((info, matches));\n        }\n    }\n\n    if !result.is_empty() {\n        Ok(result)\n    } else {\n        Err(Error::new(ErrorKind::NotFound, \"no matching .desktop files found\").into())\n    }\n}\n\nfn parse_app_info(props: &ini::Properties) -> AppInfo {\n    AppInfo {\n        icon_dataurl: \"\".to_string(),\n        app_name: props.get(\"Name\").unwrap_or_default().to_string(),\n        comment: props.get(\"Comment\").unwrap_or_default().to_string(),\n        icon_name: props.get(\"Icon\").unwrap_or_default().to_string(),\n    }\n}\n\nfn get_icon_as_png_dataurl(name: &str, size: i8) -> Result<(String, String)> {\n    // gtk_icon_theme_get_default() is lightweight - it returns a borrowed reference to GTK's singleton icon theme\n    let theme = unsafe { gtk_icon_theme_get_default() };\n    if theme.is_null() {\n        return Err(Error::new(ErrorKind::Other, \"GTK not initialized\").into());\n    }\n\n    let mut icons = Vec::new();\n\n    // push the name\n    icons.push(name);\n\n    // if we don't find the icon by it's name and it includes an extension,\n    // drop the extension and try without.\n    let name_without_ext;\n    if let Some(ext) = PathBuf::from(name).extension() {\n        let ext = ext.to_str().unwrap();\n\n        let mut ext_dot = String::from(\".\").to_owned();\n        ext_dot.push_str(ext);\n\n        name_without_ext = name.replace(ext_dot.as_str(), \"\");\n        icons.push(name_without_ext.as_str());\n    } else {\n        name_without_ext = String::from(name);\n    }\n\n    // The xdg-desktop icon specification allows a fallback for icons that contains dashes.\n    // i.e. the following lookup order is used:\n    //      - network-wired-secure\n    //      - network-wired\n    //      - network\n    //\n    name_without_ext\n        .split('-')\n        .for_each(|part| icons.push(part));\n\n    for name in icons {\n        debug!(\"trying to load icon {}\", name);\n\n        unsafe {\n            let c_str = CString::new(name).unwrap();\n\n            let icon_info = gtk_icon_theme_lookup_icon(\n                theme,\n                c_str.as_ptr() as *const c_char,\n                size as c_int,\n                0,\n            );\n            if icon_info.is_null() {\n                dbg!(\"failed to lookup icon {}\", name);\n\n                continue;\n            }\n\n            let filename = gtk_icon_info_get_filename(icon_info);\n\n            let filename = CStr::from_ptr(filename).to_str().unwrap().to_string();\n\n            gtk_icon_info_free(icon_info);\n\n            match read_and_convert_pixbuf(filename.clone()) {\n                Ok(pb) => return Ok((filename, pb)),\n                Err(err) => {\n                    dbg!(\"failed to load icon from {}: {}\", filename, err.to_string());\n\n                    continue;\n                }\n            }\n        }\n    }\n\n    Err(Error::new(ErrorKind::NotFound, \"failed to find icon\").into())\n}\n\n/*\nfn get_icon_as_file_2(ext: &str, size: i32) -> io::Result<(String, Vec<u8>)> {\n    let result: String;\n    let buf: Vec<u8>;\n\n    unsafe {\n        let filename = CString::new(ext).unwrap();\n        let null: u8 = 0;\n        let p_null = &null as *const u8;\n        let nullsize: usize = 0;\n        let mut res = 0;\n        let p_res = &mut res as *mut i32;\n        let p_res = gio_sys::g_content_type_guess(filename.as_ptr(), p_null, nullsize, p_res);\n        let icon = gio_sys::g_content_type_get_icon(p_res);\n        g_free(p_res as *mut c_void);\n        if DEFAULT_THEME.is_none() {\n            let theme = gtk_icon_theme_get_default();\n            if theme.is_null() {\n                println!(\"You have to initialize GTK!\");\n                return Err(io::Error::new(io::ErrorKind::Other, \"You have to initialize GTK!\"))\n            }\n            let theme = gtk_icon_theme_get_default();\n            DEFAULT_THEME = Some(theme);\n        }\n        let icon_names = gio_sys::g_themed_icon_get_names(icon as *mut GThemedIcon) as *mut *const i8;\n        let icon_info = gtk_icon_theme_choose_icon(DEFAULT_THEME.unwrap(), icon_names, size, GTK_ICON_LOOKUP_NO_SVG);\n        let filename = gtk_icon_info_get_filename(icon_info);\n\n        gtk_icon_info_free(icon_info);\n\n        result = CStr::from_ptr(filename).to_str().unwrap().to_string();\n\n        buf = match read_and_convert_pixbuf(result.clone()) {\n            Ok(pb) => pb,\n            Err(_) => Vec::new(),\n        };\n\n        g_object_unref(icon as *mut GObject);\n    }\n\n    Ok((result, buf))\n\n}\n*/\n\nfn read_and_convert_pixbuf(result: String) -> std::result::Result<String, glib::Error> {\n    let pixbuf = match Pixbuf::from_file(result.clone()) {\n        Ok(data) => Ok(data),\n        Err(err) => {\n            error!(\"failed to load icon pixbuf: {}\", err.to_string());\n\n            Pixbuf::from_resource(result.clone().as_str())\n        }\n    };\n\n    match pixbuf {\n        Ok(data) => match data.save_to_bufferv(\"png\", &[]) {\n            Ok(data) => {\n                let mut du = DataUrl::new();\n\n                du.set_media_type(Some(\"image/png\".to_string()));\n                du.set_data(&data);\n\n                Ok(du.to_string())\n            }\n            Err(err) => {\n                return Err(glib::Error::new(\n                    PixbufError::Failed,\n                    err.to_string().as_str(),\n                ));\n            }\n        },\n        Err(err) => Err(err),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use ctor::ctor;\n    use log::warn;\n    use which::which;\n\n    // Use the ctor create to setup a global initializer before our tests are executed.\n    #[ctor]\n    fn init() {\n        // we need to initialize GTK before running our tests.\n        // This is only required when unit tests are executed as\n        // GTK will otherwise be initialize by Tauri.\n\n        gtk::init().expect(\"failed to initialize GTK for tests\")\n    }\n\n    #[test]\n    fn test_find_info_success() {\n        // we expect at least one of the following binaries to be installed\n        // on a linux system\n        let test_binaries = vec![\n            \"vim\",             // vim is mostly bundled with a .desktop file\n            \"blueman-manager\", // blueman-manager is the default bluetooth manager on most DEs\n            \"nautilus\",        // nautlis: file-manager on GNOME DE\n            \"thunar\",          // thunar: file-manager on XFCE\n            \"dolphin\",         // dolphin: file-manager on KDE\n        ];\n\n        let mut bin_found = false;\n\n        for cmd in test_binaries {\n            match which(cmd) {\n                Ok(bin) => {\n                    bin_found = true;\n\n                    let bin = bin.to_string_lossy().to_string();\n\n                    let result = get_app_info(ProcessInfo {\n                        cmdline: cmd.to_string(),\n                        exec_path: bin.clone(),\n                        matching_path: bin.clone(),\n                        pid: 0,\n                    })\n                    .unwrap_or_else(|_| panic!(\"expected to find app info for {} ({})\", bin, cmd));\n                    let empty_string = String::from(\"\");\n\n                    // just make sure all fields are populated\n                    assert_ne!(result.app_name, empty_string);\n                    assert_ne!(result.comment, empty_string);\n                    assert_ne!(result.icon_name, empty_string);\n                    assert_ne!(result.icon_dataurl, empty_string);\n                }\n                Err(_) => {\n                    // binary not found\n                    continue;\n                }\n            }\n        }\n\n        if !bin_found {\n            warn!(\"test_find_info_success: no test binary found, test was skipped\")\n        }\n    }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/tauri.conf.json5",
    "content": "{\n  \"build\": {\n    \"beforeDevCommand\": {\n      \"script\": \"npm run tauri-dev\",\n      \"cwd\": \"../../angular\",\n      \"wait\": false\n    },\n    \"frontendDist\": \"../../angular/dist/tauri-builtin\",\n    \"devUrl\": \"http://localhost:4100\"\n  },\n  \"plugins\": {\n    \"cli\": {\n      \"args\": [\n        {\n          \"short\": \"d\",\n          \"name\": \"data\",\n          \"description\": \"Path to the installation directory\",\n          \"takesValue\": true\n        },\n        {\n          \"short\": \"b\",\n          \"name\": \"background\",\n          \"description\": \"Start in the background without opening a window\"\n        },\n        {\n          \"name\": \"log\",\n          \"description\": \"Log level to use: off, error, warn, info, debug, trace\",\n          \"takesValue\": true\n        },\n        {\n          \"name\": \"no-notifications\",\n          \"description\": \"Disable notifications via Tauri.\"\n        },\n        {\n          \"name\": \"no-prompts\",\n          \"description\": \"Disable prompt support via Tauri.\"\n        },\n      ]\n    }\n  },\n  \"productName\": \"Portmaster\",\n  \"identifier\": \"io.safing.portmaster\", // this is added as a property to the shortcut on windows (ApplicationUserModelID). Used for notifications.\n  \"app\": {\n    \"withGlobalTauri\": true,\n    \"enableGTKAppId\": false,\n    \"security\": {\n      \"csp\": null\n    }\n  },\n  \"bundle\": {\n    \"active\": true,\n    \"category\": \"Utility\",\n    \"copyright\": \"Safing Limited Inc\",\n    \"linux\": {\n      \"deb\": {\n        \"depends\": [\n          \"libayatana-appindicator3-1\"\n        ],\n        \"desktopTemplate\": \"../../../packaging/linux/portmaster.desktop\",\n        \"files\": {\n          // Service file\n          \"/usr/lib/systemd/system/portmaster.service\": \"../../../packaging/linux/portmaster.service\",\n\n          // Binary files\n          \"/usr/lib/portmaster/portmaster-core\": \"binary/portmaster-core\",\n          \"/usr/lib/portmaster/portmaster.zip\": \"binary/portmaster.zip\",\n          \"/usr/lib/portmaster/assets.zip\": \"binary/assets.zip\",\n\n          // Intel files\n          \"/var/lib/portmaster/intel/index.json\": \"intel/index.json\",\n          \"/var/lib/portmaster/intel/base.dsdl\": \"intel/base.dsdl\",\n          \"/var/lib/portmaster/intel/geoipv4.mmdb\": \"intel/geoipv4.mmdb\",\n          \"/var/lib/portmaster/intel/geoipv6.mmdb\": \"intel/geoipv6.mmdb\",\n          \"/var/lib/portmaster/intel/index.dsd\": \"intel/index.dsd\",\n          \"/var/lib/portmaster/intel/intermediate.dsdl\": \"intel/intermediate.dsdl\",\n          \"/var/lib/portmaster/intel/urgent.dsdl\": \"intel/urgent.dsdl\",\n\n          \"/var/lib/portmaster/intel/main-intel.yaml\"   : \"intel/main-intel.yaml\",\n          \"/var/lib/portmaster/intel/notifications.yaml\": \"intel/notifications.yaml\",\n          \"/var/lib/portmaster/intel/news.yaml\"         : \"intel/news.yaml\",\n\n          // Shortcut\n          \"/etc/xdg/autostart/portmaster.desktop\": \"../../../packaging/linux/portmaster-autostart.desktop\"\n        },\n        \"postInstallScript\": \"../../../packaging/linux/postinst\",\n        \"postRemoveScript\": \"../../../packaging/linux/postrm\"\n      },\n      \"rpm\": {\n        \"depends\": [\n          \"libayatana-appindicator-gtk3\"\n        ],\n        \"desktopTemplate\": \"../../../packaging/linux/portmaster.desktop\",\n        \"release\": \"1\",\n        \"files\": {\n          // Service file\n          \"/usr/lib/systemd/system/portmaster.service\": \"../../../packaging/linux/portmaster.service\",\n\n          // Binary files\n          \"/usr/lib/portmaster/portmaster-core\": \"binary/portmaster-core\",\n          \"/usr/lib/portmaster/portmaster.zip\": \"binary/portmaster.zip\",\n          \"/usr/lib/portmaster/assets.zip\": \"binary/assets.zip\",\n\n          // Intel files\n          \"/var/lib/portmaster/intel/index.json\": \"intel/index.json\",\n          \"/var/lib/portmaster/intel/base.dsdl\": \"intel/base.dsdl\",\n          \"/var/lib/portmaster/intel/geoipv4.mmdb\": \"intel/geoipv4.mmdb\",\n          \"/var/lib/portmaster/intel/geoipv6.mmdb\": \"intel/geoipv6.mmdb\",\n          \"/var/lib/portmaster/intel/index.dsd\": \"intel/index.dsd\",\n          \"/var/lib/portmaster/intel/intermediate.dsdl\": \"intel/intermediate.dsdl\",\n          \"/var/lib/portmaster/intel/urgent.dsdl\": \"intel/urgent.dsdl\",\n\n          \"/var/lib/portmaster/intel/main-intel.yaml\"   : \"intel/main-intel.yaml\",\n          \"/var/lib/portmaster/intel/notifications.yaml\": \"intel/notifications.yaml\",\n          \"/var/lib/portmaster/intel/news.yaml\"         : \"intel/news.yaml\",\n\n          // Shortcut\n          \"/etc/xdg/autostart/portmaster.desktop\": \"../../../packaging/linux/portmaster-autostart.desktop\"\n        },\n        \"postInstallScript\": \"../../../packaging/linux/postinst\",\n        \"postRemoveScript\": \"../../../packaging/linux/postrm\"\n      }\n    },\n    \"windows\": {\n      \"nsis\": {\n        \"installMode\": \"perMachine\",\n        \"installerHooks\": \"templates/nsis/install_hooks.nsh\",\n        \"installerIcon\": \"../../../assets/data/icons/pm_light_contrast.ico\"\n      },\n      \"wix\": {\n        \"fragmentPaths\": [\n          \"templates/wix/files.wxs\",\n          \"templates/wix/old_service_check.wxs\",\n          \"templates/wix/migration.wxs\",\n        ],\n        \"componentGroupRefs\": [\"BinaryAndIntelFiles\"],\n        \"template\": \"templates/wix/main.wxs\"\n      }\n    },\n    \"targets\": [\n      \"deb\",\n      \"rpm\",\n      \"nsis\"  //,      \"msi\"\n    ],\n    \"icon\": [      \n      \"../../../assets/data/icons/pm_dark_512.png\",\n      \"../../../assets/data/icons/pm_light_contrast.ico\",\n      \"../../../assets/data/icons/pm_dark.ico\",\n      \"../../../assets/data/icons/pm_light_512.png\",\n      \"../../../assets/data/icons/pm_light.ico\"\n    ]\n  }\n}\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/License.txt",
    "content": "SimpleSC - NSIS Service Control Plugin - License Agreement \n\nThis plugin is subject to the Mozilla Public License Version 1.1 (the \"License\"); \nYou may not use this plugin except in compliance with the License. You may \nobtain a copy of the License at http://www.mozilla.org/MPL. \n\nAlternatively, you may redistribute this library, use and/or modify it \nunder the terms of the GNU Lesser General Public License as published \nby the Free Software Foundation; either version 2.1 of the License, \nor (at your option) any later version. You may obtain a copy \nof the LGPL at www.gnu.org/copyleft. \n\nSoftware distributed under the License is distributed on an \"AS IS\" basis, \nWITHOUT WARRANTY OF ANY KIND, either express or implied. See the License \nfor the specific language governing rights and limitations under the License. \n\nCopyright \n\nPortions of this software are Copyright (C) 2001 - Peter Windridge, 2003 by \nBernhard Mayer, Fixed and formatted by Brett Dever http://editor.nfscheats.com/\n\nThe original code is ServiceControl.pas, released April 16, 2007. \n\nThe initial developer of the original code is Rainer Budde (http://www.speed-soft.de). \n\nSimpleSC - NSIS Service Control Plugin is written, published and maintaned by \nRainer Budde (rainer@speed-soft.de)."
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/Readme.txt",
    "content": "NSIS Simple Service Plugin\n\nThis plugin contains basic service functions like start, stop the \nservice or checking the service status. It also contains advanced \nservice functions for example setting the service description, changed\nthe logon account, granting or removing the service logon privilege.\n\n\n\n\n== Short Reference ==\n\n\nSimpleSC::InstallService [name_of_service] [display_name] [service_type] [start_type] [binary_path] [dependencies] [account] [password]\nSimpleSC::RemoveService [name_of_service]\n\nSimpleSC::StartService [name_of_service] [arguments] [timeout]\nSimpleSC::StopService [name_of_service] [wait_for_file_release] [timeout]\nSimpleSC::PauseService [name_of_service] [timeout]\nSimpleSC::ContinueService [name_of_service] [timeout]\nSimpleSC::RestartService [name_of_service] [arguments] [timeout]\nSimpleSC::ExistsService [name_of_service]\n\nSimpleSC::GetServiceDisplayName [name_of_service]\nSimpleSC::GetServiceName [display_name]\nSimpleSC::GetServiceStatus [name_of_service]\nSimpleSC::GetServiceDescription [name_of_service]\nSimpleSC::GetServiceStartType [name_of_service]\nSimpleSC::GetServiceBinaryPath [name_of_service]\nSimpleSC::GetServiceLogon [name_of_service]\nSimpleSC::GetServiceFailure [name_of_service]\nSimpleSC::GetServiceFailureFlag [name_of_service]\nSimpleSC::GetServiceDelayedAutoStartInfo [name_of_service]\n\nSimpleSC::SetServiceDescription [name_of_service] [service_description]\nSimpleSC::SetServiceStartType [name_of_service] [start_type]\nSimpleSC::SetServiceBinaryPath [name_of_service] [binary_path]\nSimpleSC::SetServiceLogon [name_of_service] [account] [password]\nSimpleSC::SetServiceFailure [name_of_service] [reset_period] [reboot_message] [command] [action_type_1] [action_delay_1] [action_type_2] [action_delay_2] [action_type_3] [action_delay_3] \nSimpleSC::SetServiceFailureFlag [name_of_service] [failure_actions_on_non_crash_failures]\nSimpleSC::SetServiceDelayedAutoStartInfo [name_of_service] [delayed_autostart]\n\nSimpleSC::GrantServiceLogonPrivilege [account]\nSimpleSC::RemoveServiceLogonPrivilege [account]\n\nSimpleSC::ServiceIsPaused [name_of_service]\nSimpleSC::ServiceIsRunning [name_of_service]\nSimpleSC::ServiceIsStopped [name_of_service]\n\nSimpleSC::GetErrorMessage [error_code]\n\n\nParameters:\n\nname_of_service - The name of the service used for Start/Stop commands and all further commands \n\ndisplay_name - The name as shown in the service control manager applet in system control \n\nservice_type - One of the following codes \n  1 - SERVICE_KERNEL_DRIVER - Driver service.\n  2 - SERVICE_FILE_SYSTEM_DRIVER - File system driver service.\n  16 - SERVICE_WIN32_OWN_PROCESS - Service that runs in its own process. (Should be used in most cases)\n  32 - SERVICE_WIN32_SHARE_PROCESS - Service that shares a process with one or more other services. \n  256 - SERVICE_INTERACTIVE_PROCESS - The service can interact with the desktop. \n      Note: If you specify either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, \n            and the service is running in the context of the LocalSystem account, \n            you can also specify this value. \n            Example: SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS - (16 or 256) = 272\n      Note: Services cannot directly interact with a user as of Windows Vista. \n            Therefore, this technique should not be used in new code.\n            See for more information: http://msdn2.microsoft.com/en-us/library/ms683502(VS.85).aspx          \n\nstart_type - one of the following codes \n  0 - SERVICE_BOOT_START - Driver boot stage start \n  1 - SERVICE_SYSTEM_START - Driver scm stage start \n  2 - SERVICE_AUTO_START - Service auto start (Should be used in most cases)\n  3 - SERVICE_DEMAND_START - Driver/service manual start \n  4 - SERVICE_DISABLED - Driver/service disabled\n\nservice_status - one of the following codes\n  1 - SERVICE_STOPPED\n  2 - SERVICE_START_PENDING\n  3 - SERVICE_STOP_PENDING\n  4 - SERVICE_RUNNING\n  5 - SERVICE_CONTINUE_PENDING\n  6 - SERVICE_PAUSE_PENDING\n  7 - SERVICE_PAUSED\n\nbinary_path - The path to the binary including all necessary parameters \n\ndependencies - Needed services, controls which services have to be started before this one; use the forward slash \"/\" to add more more than one service\n\naccount - The username/account which should be used \n\npassword - Password of the aforementioned account to be able to logon as a service \n           Note: If you do not specify account/password, the local system account will be used to run the service\n\narguments - Arguments passed to the service main function. \n            Note: Driver services do not receive these arguments.\n\nreset_period - The time after which to reset the failure count to zero if there are no failures, in seconds. Specify 0 (INFINITE) to indicate that this value should never be reset\n\nreboot_message - The message to be broadcast to server users before rebooting\n\ncommand - The command line of the process to execute in response to the SC_ACTION_RUN_COMMAND service controller action. This process runs under the same account as the service\n\ntimeout - Timeout in seconds of the function\n\naction_type_x - one of the following codes for the action to be performed\n  0 - SC_ACTION_NONE - No action\n  1 - SC_ACTION_RESTART - Restart the service\n  2 - SC_ACTION_REBOOT - Reboot the computer (Note: The service user must have the SE_SHUTDOWN_NAME privilege)\n  3 - SC_ACTION_RUN_COMMAND - Run a command\n\naction_delay_x - The time to wait before performing the specified action, in milliseconds\n\nfailure_actions_on_non_crash_failures - This setting determines when failure actions are to be executed\n  0 - The failure actions executed only if the service terminates without reporting a status of SERVICE_STOPPED\n  1 - The failure actions executed if the status of a service is SERVICE_STOPPED but the exit code of the service is not 0\n\ndelayed_autostart - The delayed auto-start setting of an auto-start service\n  0 - The service will be started during system boot.\n  1 - The service will be started after other auto-start services are started plus a short delay\n\nerror_code - Error code of a function\n\nservice_description - The description as shown in the service control manager applet in system control \n\nwait_for_file_release - Wait for file release after the service is stopped. This is useful if the binary file will be overwritten after stopping the service.\n  0 - NO_WAIT - No wait for file release\n  1 - WAIT - Wait for file release \n  Note: If SERVICE_WIN32_OWN_PROCESS is used this option should be set to WAIT.\n\tIf SERVICE_WIN32_SHARE_PROCESS is used this option should only be set to WAIT if the last service\n        in the process is stopped.\n\n\n\n\n== The Sample Script ==\n\n\n; Install a service - ServiceType own process - StartType automatic - NoDependencies - Logon as System Account\n  SimpleSC::InstallService \"MyService\" \"My Service Display Name\" \"16\" \"2\" \"C:\\MyPath\\MyService.exe\" \"\" \"\" \"\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Install a service - ServiceType interact with desktop - StartType automatic - Dependencies on \"Windows Time Service\" (w32time) and \"WWW Publishing Service\" (w3svc) - Logon as System Account\n  SimpleSC::InstallService \"MyService\" \"My Service Display Name\" \"272\" \"2\" \"C:\\MyPath\\MyService.exe\" \"w32time/w3svc\" \"\" \"\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Remove a service\n  SimpleSC::RemoveService \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Start a service\n  SimpleSC::StartService \"MyService\" \"\" 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Start a service with two arguments \"/param1=true\" \"/param2=1\"\n  SimpleSC::StartService \"MyService\" \"/param1=true /param2=1\" 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n \n; Start a service with two arguments \"-p param1\" \"-param2\"\n  SimpleSC::StartService \"MyService\" '\"-p param1\" -param2' 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Stop a service and waits for file release\n  SimpleSC::StopService \"MyService\" 1 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Stops two services and waits for file release after the last service is stopped\n  SimpleSC::StopService \"MyService1\" 0 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  SimpleSC::StopService \"MyService2\" 1 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Pause a service\n  SimpleSC::PauseService \"MyService\" 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Continue a service\n  SimpleSC::ContinueService \"MyService\" 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Restart a service\n  SimpleSC::RestartService \"MyService\" \"\" 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Restart a service with two arguments \"/param1=true\" \"/param2=1\"\n  SimpleSC::RestartService \"MyService\" \"/param1=true /param2=1\" 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Start a service with two arguments \"-p param1\" \"-param2\"\n  SimpleSC::RestartService \"MyService\" '\"-p param1\" -param2' 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Check if the service exists\n  SimpleSC::ExistsService \"MyService\"\n  Pop $0 ; returns an errorcode if the service doesnt exists (<>0)/service exists (0)\n\n; Get the displayname of a service\n  SimpleSC::GetServiceDisplayName \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the displayname of the service\n\n; Get the servicename of a service by the displayname\n  SimpleSC::GetServiceName \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the servicename of the service\n\n; Get the current status of a service\n  SimpleSC::GetServiceStatus \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; return the status of the service (See \"service_status\" in the parameters)\n\n; Get the description of a service\n  SimpleSC::GetServiceDescription \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the description of the service\n \n; Get the start type of the service\n  SimpleSC::GetServiceStartType \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the start type of the service (see \"start_type\" in the parameters)\n\n; Get the binary path of a service\n  SimpleSC::GetServiceBinaryPath \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the binary path of the service\n\n; Get the logon user of the service\n  SimpleSC::GetServiceLogon \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the logon username of the service  \n\n; Get the failure configuration of a service\n  SimpleSC::GetServiceFailure \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the reset period \n  Pop $2 ; returns the reboot message\n  Pop $3 ; returns the command\n  Pop $4 ; returns the first action (See \"action_type_x\" in the parameters)\n  Pop $5 ; returns the first action delay \n  Pop $6 ; returns the second action (See \"action_type_x\" in the parameters)\n  Pop $7 ; returns the second action delay \n  Pop $8 ; returns the third action (See \"action_type_x\" in the parameters)\n  Pop $9 ; returns the third action delay \n\n; Get the failure flag configuration of a service\n  SimpleSC::GetServiceFailureFlag \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the service flag\n\n; Get the delayed auto-start configuration of a service\n  SimpleSC::GetServiceDelayedAutoStartInfo \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns the delayed auto-start configuration\n\n; Set the description of a service\n  SimpleSC::SetServiceDescription \"MyService\" \"Sample Description\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Set the starttype to automatic of a service\n  SimpleSC::SetServiceStartType \"MyService\" \"2\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Sets the service binary path\n  SimpleSC::SetServiceBinaryPath \"MyService\" \"C:\\MySoftware\\MyService.exe\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Sets the service logon to a user and grant the user the \"SeServiceLogonPrivilege\"\n  SimpleSC::SetServiceLogon \"MyService\" \"MyServiceUser\" \"MyServiceUserPassword\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  IntCmp $0 0 +1 Done Done ; If successful grant the service logon privilege to \"MyServiceUser\"\n    ; Note: Every serviceuser must have the ServiceLogonPrivilege to start the service\n    SimpleSC::GrantServiceLogonPrivilege \"MyServiceUser\"\n    Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Done:\n\n; Sets the service failure configuration - First action: Restart the service after one minute - Second action: Reboot the computer after five minutes\n  SimpleSC::SetServiceFailure \"MyService\" \"0\" \"\" \"\" \"1\" \"60000\" \"2\" \"300000\" \"0\" \"0\" \n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Sets the failure flag configuration of a service\n  SimpleSC::SetServiceFailureFlag \"MyService\" \"1\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Sets the delayed auto-start configuration of a service\n  SimpleSC::SetServiceDelayedAutoStartInfo \"MyService\" \"1\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Remove the \"SeServiceLogonPrivilege\" from a user\n  SimpleSC::RemoveServiceLogonPrivilege \"MyServiceUser\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n\n; Check if the service is paused\n  SimpleSC::ServiceIsPaused \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns 1 (service is paused) - returns 0 (service is not paused)\n\n; Check if the service is running\n  SimpleSC::ServiceIsRunning \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)\n\n; Check if the service is stopped\n  SimpleSC::ServiceIsStopped \"MyService\"\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  Pop $1 ; returns 1 (service is stopped) - returns 0 (service is not stopped)\n\n; Show the error message if a function fails \n  SimpleSC::StopService \"MyService\" 1 30\n  Pop $0 ; returns an errorcode (<>0) otherwise success (0)\n  IntCmp $0 0 Done +1 +1 \n    Push $0\n    SimpleSC::GetErrorMessage\n    Pop $0\n    MessageBox MB_OK|MB_ICONSTOP \"Stopping fails - Reason: $0\"\n  Done:\n\n\n\n\n== Important Notes ==\n- The function \"SetServiceLogon\" only works if the servicetype is \n  \"SERVICE_WIN32_OWN_PROCESS\".\n- The functions \"GetServiceDescription\", \"SetServiceDescription\", \"GetServiceFailure\" and \n  \"SetServiceFailure\" are only available on systems higher than Windows NT. \n- The function \"GetServiceFailureFlag\", \"SetServiceFailureFlag\", \"GetServiceDelayedAutoStartInfo\" and \n  \"SetServiceDelayedAutoStartInfo\" are only available on systems higher than Windows 2003.\n- If you change the logon of an service to a new user you have to grant him \n  the Service Logon Privilege. Otherwise the service cannot be started by \n  the user you have assigned.\n- The functions StartService, StopService, PauseService and ContinueService uses\n  a timeout of 30 seconds. This means the function must be executed within 30 seconds, \n  otherwise the functions will return an error."
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/Source/LSASecurityControl.pas",
    "content": "{\nLicense Agreement\n\nThis content is subject to the Mozilla Public License Version 1.1 (the \"License\");\nYou may not use this plugin except in compliance with the License. You may \nobtain a copy of the License at http://www.mozilla.org/MPL. \n\nAlternatively, you may redistribute this library, use and/or modify it \nunder the terms of the GNU Lesser General Public License as published \nby the Free Software Foundation; either version 2.1 of the License, \nor (at your option) any later version. You may obtain a copy \nof the LGPL at www.gnu.org/copyleft. \n\nSoftware distributed under the License is distributed on an \"AS IS\" basis, \nWITHOUT WARRANTY OF ANY KIND, either express or implied. See the License \nfor the specific language governing rights and limitations under the License. \n\nThe original code is LSASecurityControl.pas, released April 16, 2007. \n\nThe initial developer of the original code is Rainer Dpke\n(Formerly: Rainer Budde) (https://www.speed-soft.de).\n\nSimpleSC - NSIS Service Control Plugin is written, published and maintained by\nRainer Dpke (rainer@speed-soft.de).\n}\nunit LSASecurityControl;\n\ninterface\n\nuses\n  Winapi.Windows;\n\n  function GrantPrivilege(AccountName: String; PrivilegeName: String): Integer;\n  function RemovePrivilege(AccountName: String; PrivilegeName: String): Integer;\n  function EnablePrivilege(PrivilegeName: String): Integer;\n  function DisablePrivilege(PrivilegeName: String): Integer;\n\nimplementation\n\ntype\n  LSA_HANDLE = Pointer;\n  TLSAHandle = LSA_HANDLE;\n\n  LSA_UNICODE_STRING = record\n    Length: Word;\n    MaximumLength: Word;\n    Buffer: PWideChar;\n  end;\n  TLSAUnicodeString = LSA_UNICODE_STRING;\n  PLSAUnicodeString = ^TLSAUnicodeString;\n\n  LSA_OBJECT_ATTRIBUTES = record\n    Length: ULONG;\n    RootDirectory: THandle;\n    ObjectName: PLSAUnicodeString;\n    Attributes: ULONG;\n    SecurityDescriptor: Pointer;\n    SecurityQualityOfService: Pointer; \n  end;\n  TLsaObjectAttributes = LSA_OBJECT_ATTRIBUTES;\n  PLsaObjectAttributes = ^TLsaObjectAttributes;\n\n  function LsaOpenPolicy(SystemName: PLSAUnicodeString; var ObjectAttributes: TLsaObjectAttributes; DesiredAccess: ACCESS_MASK;  var PolicyHandle: LSA_HANDLE): DWORD; stdcall; external 'advapi32.dll';\n  function LsaAddAccountRights(PolicyHandle: LSA_HANDLE; AccountSid: PSID; UserRights: PLSAUnicodeString; CountOfRights: ULONG): DWORD; stdcall; external 'advapi32.dll';\n  function LsaRemoveAccountRights(PolicyHandle: LSA_HANDLE; AccountSid: PSID; AllRights: Boolean; UserRights: PLSAUnicodeString; CountOfRights: ULONG): DWORD; stdcall; external 'advapi32.dll';\n  function LsaClose(ObjectHandle: LSA_HANDLE): DWORD; stdcall; external 'advapi32.dll';\n\n\nfunction GetAccountSid(const AccountName: String; var Sid: PSID): Integer;\nvar\n  DomainSize: LongWord;\n  SidSize: LongWord;\n  Domain: String;\n  Use: SID_NAME_USE;\nbegin\n  Result := 0;\n\n  SidSize := 0;\n  DomainSize := 0;\n\n  if not LookupAccountName(nil, PChar(AccountName), nil, SidSize, nil, DomainSize, Use) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n  begin\n    SetLength(Domain, DomainSize);\n    Sid := AllocMem(SidSize);\n\n    if not LookupAccountName(nil, PChar(AccountName), Sid, SidSize, PChar(Domain), DomainSize, Use) then\n    begin\n      Result := GetLastError;\n      FreeMem(Sid);\n      Sid := nil;\n    end;\n  end\n  else\n    Result := GetLastError;\nend;\n\nfunction GrantPrivilege(AccountName: String; PrivilegeName: String): Integer;\nconst\n  UNICODE_NULL = WCHAR(0);\n  POLICY_CREATE_ACCOUNT = $00000010;\n  POLICY_LOOKUP_NAMES = $00000800;\nvar\n  SID: PSID;\n  PolicyHandle: TLSAHandle;\n  LSAPrivilegeName: TLSAUnicodeString;\n  LSAObjectAttributes: TLsaObjectAttributes;\n  pwszPrivilegeName: PWideChar;\n  PrivilegeNameLength: Cardinal;\n  Status: DWORD;\nbegin\n  Result := 0;\n\n  GetMem(pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);\n  StringToWideChar(PrivilegeName, pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);\n  ZeroMemory(@LSAObjectAttributes, SizeOf(TLsaObjectAttributes));\n  PrivilegeNameLength := Length(pwszPrivilegeName);\n\n  if PrivilegeNameLength > 0 then\n  begin\n    Result := GetAccountSid(AccountName, SID);\n\n    if Result = 0 then\n    begin\n      LSAPrivilegeName.Length := PrivilegeNameLength * SizeOf(WideChar);\n      LSAPrivilegeName.MaximumLength := LSAPrivilegeName.Length + SizeOf(UNICODE_NULL);\n      LSAPrivilegeName.Buffer := pwszPrivilegeName;\n\n      Status := LsaOpenPolicy(nil, LSAObjectAttributes, POLICY_LOOKUP_NAMES or POLICY_CREATE_ACCOUNT, PolicyHandle);\n      try\n        if Status = 0 then\n          Result := LsaAddAccountRights(PolicyHandle, Sid, @LSAPrivilegeName, 1)\n        else\n          Result := Status;\n      finally\n        LsaClose(PolicyHandle);\n      end;\n    end;\n\n  end;\n    \n  FreeMem(pwszPrivilegeName);\nend;\n\nfunction RemovePrivilege(AccountName: String; PrivilegeName: String): Integer;\nconst\n  UNICODE_NULL = WCHAR(0);\n  POLICY_CREATE_ACCOUNT = $00000010;\n  POLICY_LOOKUP_NAMES = $00000800;\nvar\n  SID: PSID;\n  PolicyHandle: TLSAHandle;\n  LSAPrivilegeName: TLSAUnicodeString;\n  LSAObjectAttributes: TLsaObjectAttributes;\n  pwszPrivilegeName: PWideChar;\n  PrivilegeNameLength: Cardinal;\n  Status: DWORD;\nbegin\n  Result := 0;\n\n  GetMem(pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);\n  StringToWideChar(PrivilegeName, pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);\n  ZeroMemory(@LSAObjectAttributes, SizeOf(TLsaObjectAttributes));\n  PrivilegeNameLength := Length(pwszPrivilegeName);\n\n  if PrivilegeNameLength > 0 then\n  begin\n    Result := GetAccountSid(AccountName, SID);\n\n    if Result = 0 then\n    begin\n      LSAPrivilegeName.Length := PrivilegeNameLength * SizeOf(WideChar);\n      LSAPrivilegeName.MaximumLength := LSAPrivilegeName.Length + SizeOf(UNICODE_NULL);\n      LSAPrivilegeName.Buffer := pwszPrivilegeName;\n\n      Status := LsaOpenPolicy(nil, LSAObjectAttributes, POLICY_LOOKUP_NAMES or POLICY_CREATE_ACCOUNT, PolicyHandle);\n\n      try\n        if Status = 0 then\n          Result := LsaRemoveAccountRights(PolicyHandle, Sid, False, @LSAPrivilegeName, 1)\n        else\n          Result := Status;\n      finally\n        LsaClose(PolicyHandle);\n      end;\n    end;\n\n  end;\n    \n  FreeMem(pwszPrivilegeName);\nend;\n\nfunction EnablePrivilege(PrivilegeName: String): Integer;\nvar\n  TokenHandle: THandle;\n  TokenPrivileges: TOKEN_PRIVILEGES;\n  PreviousState: TOKEN_PRIVILEGES;\n  ReturnLength: Cardinal;\nbegin\n  Result := 0;\n\n  if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then\n  begin\n    try\n\n      if LookupPrivilegeValue(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid) then\n      begin\n        TokenPrivileges.PrivilegeCount := 1;\n        TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;\n\n        if not AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, SizeOf(TokenPrivileges), PreviousState, ReturnLength) then\n          Result := System.GetLastError;\n      end\n      else\n        Result := System.GetLastError;\n\n    finally\n      CloseHandle(TokenHandle);\n    end;\n  end\n  else\n    Result := System.GetLastError;\n\nend;\n\nfunction DisablePrivilege(PrivilegeName: String): Integer;\nvar\n  TokenHandle: THandle;\n  TokenPrivileges: TOKEN_PRIVILEGES;\n  PreviousState: TOKEN_PRIVILEGES;\n  ReturnLength: Cardinal;\nbegin\n\n  Result := 0;\n\n  if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then\n  begin\n    try\n\n      if LookupPrivilegeValue(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid) then\n      begin\n        TokenPrivileges.PrivilegeCount := 1;\n        TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;\n\n        if not AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, SizeOf(TokenPrivileges), PreviousState, ReturnLength) then\n          Result := System.GetLastError;\n      end\n      else\n        Result := System.GetLastError;\n\n    finally\n      CloseHandle(TokenHandle);\n    end;\n  end\n  else\n    Result := System.GetLastError;\n\nend;\n\nend.\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/Source/NSIS Plugins.groupproj",
    "content": "﻿<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n    <PropertyGroup>\n        <ProjectGuid>{0AF40426-B62C-4F43-8B49-19A70AEA0832}</ProjectGuid>\n    </PropertyGroup>\n    <ItemGroup>\n        <Projects Include=\"SimpleSC.dproj\">\n            <Dependencies/>\n        </Projects>\n    </ItemGroup>\n    <ProjectExtensions>\n        <Borland.Personality>Default.Personality.12</Borland.Personality>\n        <Borland.ProjectType/>\n        <BorlandProject>\n            <Default.Personality/>\n        </BorlandProject>\n    </ProjectExtensions>\n    <Target Name=\"SimpleSC\">\n        <MSBuild Projects=\"SimpleSC.dproj\"/>\n    </Target>\n    <Target Name=\"SimpleSC:Clean\">\n        <MSBuild Projects=\"SimpleSC.dproj\" Targets=\"Clean\"/>\n    </Target>\n    <Target Name=\"SimpleSC:Make\">\n        <MSBuild Projects=\"SimpleSC.dproj\" Targets=\"Make\"/>\n    </Target>\n    <Target Name=\"Build\">\n        <CallTarget Targets=\"SimpleSC\"/>\n    </Target>\n    <Target Name=\"Clean\">\n        <CallTarget Targets=\"SimpleSC:Clean\"/>\n    </Target>\n    <Target Name=\"Make\">\n        <CallTarget Targets=\"SimpleSC:Make\"/>\n    </Target>\n    <Import Project=\"$(BDS)\\Bin\\CodeGear.Group.Targets\" Condition=\"Exists('$(BDS)\\Bin\\CodeGear.Group.Targets')\"/>\n</Project>\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/Source/NSIS.pas",
    "content": "{\n    Original Code from\n    (C) 2001 - Peter Windridge\n\n    Code in separate unit and some changes\n    2003 by Bernhard Mayer\n\n    Fixed and formatted by Brett Dever\n    http://editor.nfscheats.com/\n\n    simply include this unit in your plugin project and export\n    functions as needed\n}\n\nunit nsis;\n\ninterface\n\nuses\n  Winapi.Windows, Winapi.CommCtrl, System.SysUtils;\n\ntype\n  VarConstants = (\n    INST_0,       // $0\n    INST_1,       // $1\n    INST_2,       // $2\n    INST_3,       // $3\n    INST_4,       // $4\n    INST_5,       // $5\n    INST_6,       // $6\n    INST_7,       // $7\n    INST_8,       // $8\n    INST_9,       // $9\n    INST_R0,      // $R0\n    INST_R1,      // $R1\n    INST_R2,      // $R2\n    INST_R3,      // $R3\n    INST_R4,      // $R4\n    INST_R5,      // $R5\n    INST_R6,      // $R6\n    INST_R7,      // $R7\n    INST_R8,      // $R8\n    INST_R9,      // $R9\n    INST_CMDLINE, // $CMDLINE\n    INST_INSTDIR, // $INSTDIR\n    INST_OUTDIR,  // $OUTDIR\n    INST_EXEDIR,  // $EXEDIR\n    INST_LANG,    // $LANGUAGE\n    __INST_LAST\n    );\n  TVariableList = INST_0..__INST_LAST;\n\ntype\n  PluginCallbackMessages = (\n    NSPIM_UNLOAD,   // This is the last message a plugin gets, do final cleanup\n    NSPIM_GUIUNLOAD // Called after .onGUIEnd\n    );\n  TNSPIM = NSPIM_UNLOAD..NSPIM_GUIUNLOAD;\n\n  //TPluginCallback = function (const NSPIM: Integer): Pointer; cdecl;\n\n  TExecuteCodeSegment = function (const funct_id: Integer; const parent: HWND): Integer;  stdcall;\n  Tvalidate_filename = procedure (const filename: PChar); stdcall;\n  TRegisterPluginCallback = function (const DllInstance: HMODULE; const CallbackFunction: Pointer): Integer; stdcall;\n\n  pexec_flags_t = ^exec_flags_t;\n  exec_flags_t = record\n    autoclose: Integer;\n    all_user_var: Integer;\n    exec_error: Integer;\n    abort: Integer;\n    exec_reboot: Integer;\n    reboot_called: Integer;\n    XXX_cur_insttype: Integer;\n    plugin_api_version: Integer;\n    silent: Integer;\n    instdir_error: Integer;\n    rtl: Integer;\n    errlvl: Integer;\n    alter_reg_view: Integer;\n    status_update: Integer;\n  end;\n\n  pextrap_t = ^extrap_t;\n  extrap_t = record\n    exec_flags: Pointer; // exec_flags_t;\n    exec_code_segment: TExecuteCodeSegment; //  TFarProc;\n    validate_filename: Pointer; // Tvalidate_filename;\n    RegisterPluginCallback: Pointer; //TRegisterPluginCallback;\n  end;\n\n  pstack_t = ^stack_t;\n  stack_t = record\n    next: pstack_t;\n    text: PChar;\n  end;\n\nvar\n  g_stringsize: integer;\n  g_stacktop: ^pstack_t;\n  g_variables: PChar;\n  g_hwndParent: HWND;\n  g_hwndList: HWND;\n  g_hwndLogList: HWND;\n  g_extraparameters: pextrap_t;\n\nprocedure Init(const hwndParent: HWND; const string_size: integer; const variables: PChar; const stacktop: pointer; const extraparameters: pointer = nil);\n\nfunction LogMessage(Msg : String): BOOL;\nfunction Call(NSIS_func : String) : Integer;\nfunction PopString(): string;\nprocedure PushString(const str: string='');\nfunction GetUserVariable(const varnum: TVariableList): string;\nprocedure SetUserVariable(const varnum: TVariableList; const value: string);\nprocedure NSISDialog(const text, caption: string; const buttons: integer);\n\nimplementation\n\nprocedure Init(const hwndParent: HWND; const string_size: integer; const variables: PChar; const stacktop: pointer; const extraparameters: pointer = nil);\nbegin\n  g_stringsize := string_size;\n  g_hwndParent := hwndParent;\n  g_stacktop   := stacktop;\n  g_variables  := variables;\n  g_hwndList   := FindWindowEx(FindWindowEx(g_hwndParent, 0, '#32770', nil), 0,'SysListView32', nil);\n  g_extraparameters := extraparameters;\nend;\n\n\nfunction Call(NSIS_func : String) : Integer;\nvar\n  codeoffset: Integer; //The ID of nsis function\nbegin\n  Result := 0;\n  codeoffset := StrToIntDef(NSIS_func, 0);\n  if (codeoffset <> 0) and (g_extraparameters <> nil) then\n    begin\n    codeoffset := codeoffset - 1;\n    Result := g_extraparameters.exec_code_segment(codeoffset, g_hwndParent);\n    end;\nend;\n\nfunction LogMessage(Msg : String): BOOL;\nvar\n  ItemCount : Integer;\n  item: TLVItem;\nbegin\n  Result := FAlse;\n  if g_hwndList = 0 then exit;\n  FillChar( item, sizeof(item), 0 );\n  ItemCount := SendMessage(g_hwndList, LVM_GETITEMCOUNT, 0, 0);\n  item.iItem := ItemCount;\n  item.mask := LVIF_TEXT;\n  item.pszText := PChar(Msg);\n  ListView_InsertItem(g_hwndList, item);\n  ListView_EnsureVisible(g_hwndList, ItemCount, TRUE);\nend;\n\nfunction PopString(): string;\nvar\n  th: pstack_t;\nbegin\n  if integer(g_stacktop^) <> 0 then begin\n    th := g_stacktop^;\n    Result := PChar(@th.text);\n    g_stacktop^ := th.next;\n    GlobalFree(HGLOBAL(th));\n  end;\nend;\n\nprocedure PushString(const str: string='');\nvar\n  th: pstack_t;\nbegin\n  if integer(g_stacktop) <> 0 then begin\n    th := pstack_t(GlobalAlloc(GPTR, SizeOf(stack_t) + g_stringsize));\n    lstrcpyn(@th.text, PChar(str), g_stringsize);\n    th.next := g_stacktop^;\n    g_stacktop^ := th;\n  end;\nend;\n\nfunction GetUserVariable(const varnum: TVariableList): string;\nbegin\n  if (integer(varnum) >= 0) and (integer(varnum) < integer(__INST_LAST)) then\n    Result := g_variables + integer(varnum) * g_stringsize\n  else\n    Result := '';\nend;\n\nprocedure SetUserVariable(const varnum: TVariableList; const value: string);\nbegin\n  if (value <> '') and (integer(varnum) >= 0) and (integer(varnum) < integer(__INST_LAST)) then\n    lstrcpy(g_variables + integer(varnum) * g_stringsize, PChar(value))\nend;\n\nprocedure NSISDialog(const text, caption: string; const buttons: integer);\nvar\n  hwndOwner: HWND;\nbegin\n  hwndOwner := g_hwndParent;\n  if not IsWindow(g_hwndParent) then hwndOwner := 0; // g_hwndParent is not valid in NSPIM_[GUI]UNLOAD\n  MessageBox(hwndOwner, PChar(text), PChar(caption), buttons);\nend;\n\nbegin\n\nend.\n\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/Source/ServiceControl.pas",
    "content": "{\nLicense Agreement\n\nThis content is subject to the Mozilla Public License Version 1.1 (the \"License\");\nYou may not use this plugin except in compliance with the License. You may\nobtain a copy of the License at http://www.mozilla.org/MPL.\n\nAlternatively, you may redistribute this library, use and/or modify it\nunder the terms of the GNU Lesser General Public License as published\nby the Free Software Foundation; either version 2.1 of the License,\nor (at your option) any later version. You may obtain a copy\nof the LGPL at www.gnu.org/copyleft.\n\nSoftware distributed under the License is distributed on an \"AS IS\" basis,\nWITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\nfor the specific language governing rights and limitations under the License.\n\nThe original code is ServiceControl.pas, released April 16, 2007.\n\nThe initial developer of the original code is Rainer Dpke\n(Formerly: Rainer Budde) (https://www.speed-soft.de).\n\nSimpleSC - NSIS Service Control Plugin is written, published and maintained by\nRainer Dpke (rainer@speed-soft.de).\n}\nunit ServiceControl;\n\ninterface\n\nuses\n  Winapi.Windows, Winapi.WinSvc, System.SysUtils, System.DateUtils;\n\n  function InstallService(ServiceName, DisplayName: String; ServiceType: DWORD; StartType: DWORD; BinaryPathName: String; Dependencies: String; Username: String; Password: String): Integer;\n  function RemoveService(ServiceName: String): Integer;\n  function GetServiceName(DisplayName: String; var Name: String): Integer;\n  function GetServiceDisplayName(ServiceName: String; var Name: String): Integer;\n  function GetServiceStatus(ServiceName: String; var Status: DWORD): Integer;\n  function GetServiceBinaryPath(ServiceName: String; var BinaryPath: String): Integer;\n  function GetServiceStartType(ServiceName: String; var StartType: DWORD): Integer;\n  function GetServiceDescription(ServiceName: String; var Description: String): Integer;\n  function GetServiceLogon(ServiceName: String; var Username: String): Integer;\n  function GetServiceFailure(ServiceName: String; var ResetPeriod: DWORD; var RebootMessage: String; var Command: String; var Action1: Integer; var ActionDelay1: DWORD; var Action2: Integer; var ActionDelay2: DWORD; var Action3: Integer; var ActionDelay3: DWORD): Integer;\n  function GetServiceFailureFlag(ServiceName: String; var FailureActionsOnNonCrashFailures: Boolean): Integer;\n  function GetServiceDelayedAutoStartInfo(ServiceName: String; var DelayedAutostart: Boolean): Integer;\n  function SetServiceStartType(ServiceName: String; StartType: DWORD): Integer;\n  function SetServiceDescription(ServiceName: String; Description: String): Integer;\n  function SetServiceLogon(ServiceName: String; Username: String; Password: String): Integer;\n  function SetServiceBinaryPath(ServiceName: String; BinaryPath: String): Integer;\n  function SetServiceFailure(ServiceName: String; ResetPeriod: DWORD; RebootMessage: String; Command: String; Action1: Integer; ActionDelay1: DWORD; Action2: Integer; ActionDelay2: DWORD; Action3: Integer; ActionDelay3: DWORD): Integer;\n  function SetServiceFailureFlag(ServiceName: String; FailureActionsOnNonCrashFailures: Boolean): Integer;\n  function SetServiceDelayedAutoStartInfo(ServiceName: String; DelayedAutostart: Boolean): Integer;\n  function ServiceIsRunning(ServiceName: String; var IsRunning: Boolean): Integer;\n  function ServiceIsStopped(ServiceName: String; var IsStopped: Boolean): Integer;\n  function ServiceIsPaused(ServiceName: String; var IsPaused: Boolean): Integer;\n  function StartService(ServiceName: String; ServiceArguments: String; Timeout: Integer): Integer;\n  function StopService(ServiceName: String; WaitForFileRelease: Boolean; Timeout: Integer): Integer;\n  function PauseService(ServiceName: String; Timeout: Integer): Integer;\n  function ContinueService(ServiceName: String; Timeout: Integer): Integer;\n  function RestartService(ServiceName: String; ServiceArguments: String; Timeout: Integer): Integer;\n  function ExistsService(ServiceName: String): Integer;\n  function GetErrorMessage(ErrorCode: Integer): String;\n  function WaitForFileRelease(ServiceName: String; Timeout: Integer): Integer;\n  function WaitForStatus(ServiceName: String; Status: DWORD; Timeout: Integer): Integer;\n\nimplementation\n\nfunction WaitForFileRelease(ServiceName: String; Timeout: Integer): Integer;\n\n  function GetFilename(ServiceFileName: String): String;\n  var\n    FilePath: String;\n    FileName: String;\n  const\n    ParameterDelimiter = ' ';\n  begin\n    FilePath := ExtractFilePath(ServiceFileName);\n\n    FileName := Copy(ServiceFileName, Length(FilePath) + 1, Length(ServiceFileName) - Length(FilePath));\n\n    if Pos(ParameterDelimiter, Filename) <> 0 then\n      FileName := Copy(FileName, 0, Pos(ParameterDelimiter, Filename) - Length(ParameterDelimiter));\n\n    Result := FilePath + FileName;\n  end;\n\nvar\n  StatusReached: Boolean;\n  TimeOutReached: Boolean;\n  TimeoutDate: TDateTime;\n  ServiceResult: Integer;\n  ServiceFileName: String;\n  FileName: String;\n  FileHandle: Cardinal;\nconst\n  WAIT_TIMEOUT = 250;\nbegin\n  Result := 0;\n\n  StatusReached := False;\n  TimeOutReached := False;\n\n  ServiceResult := GetServiceBinaryPath(ServiceName, ServiceFileName);\n\n  if ServiceResult = 0 then\n  begin\n\n    Filename := GetFilename(ServiceFileName);\n\n    if FileExists(FileName) then\n    begin\n      TimeoutDate := IncSecond(Now, Timeout);\n\n      while not StatusReached and not TimeOutReached do\n      begin\n        FileHandle := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0,\n                                 nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);\n\n        if FileHandle <> INVALID_HANDLE_VALUE then\n        begin\n          CloseHandle(FileHandle);\n          StatusReached := True;\n        end;\n\n        if not StatusReached and (TimeoutDate < Now) then\n        begin\n          TimeOutReached := True;\n          Result := WAIT_TIMEOUT;\n        end;\n      end;\n\n    end;\n\n  end\n  else\n    Result := ServiceResult;\n\nend;\n\nfunction WaitForStatus(ServiceName: String; Status: DWORD; Timeout: Integer): Integer;\nvar\n  CurrentStatus: DWORD;\n  StatusResult: Integer;\n  StatusReached: Boolean;\n  TimeOutReached: Boolean;\n  ErrorOccured: Boolean;\n  TimeoutDate: TDateTime;\nconst\n  WAIT_TIMEOUT = 250;\nbegin\n  Result := 0;\n\n  StatusReached := False;\n  TimeOutReached := False;\n  ErrorOccured := False;\n\n  TimeoutDate := IncSecond(Now, Timeout);\n\n  while not StatusReached and not ErrorOccured and not TimeOutReached do\n  begin\n    StatusResult := GetServiceStatus(ServiceName, CurrentStatus);\n\n    if StatusResult = 0 then\n    begin\n      if Status = CurrentStatus then\n        StatusReached := True\n      else\n        Sleep(WAIT_TIMEOUT);\n    end\n    else\n    begin\n      ErrorOccured := True;\n      Result := StatusResult;\n    end;\n\n    if not StatusReached and not ErrorOccured and (TimeoutDate < Now) then\n    begin\n      TimeOutReached := True;\n      Result := ERROR_SERVICE_REQUEST_TIMEOUT;\n    end;\n  end;\n\nend;\n\nfunction ExistsService(ServiceName: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n      CloseServiceHandle(ServiceHandle)\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction StartService(ServiceName: String; ServiceArguments: String; Timeout: Integer): Integer;\ntype\n  TArguments = Array of PChar;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  ServiceArgVectors: TArguments;\n  NumServiceArgs: DWORD;\nconst\n  ArgDelimitterQuote: String = '\"';\n  ArgDelimitterWhiteSpace: String = ' ';\n\n  procedure GetServiceArguments(ServiceArguments: String; var NumServiceArgs: DWORD; var ServiceArgVectors: TArguments);\n  var\n    Param: String;\n    Split: Boolean;\n    Quoted: Boolean;\n    CharIsDelimitter: Boolean;\n  begin\n    ServiceArgVectors := nil;\n    NumServiceArgs := 0;\n\n    Quoted := False;\n\n    while Length(ServiceArguments) > 0 do\n    begin\n      Split := False;\n      CharIsDelimitter := False;\n\n      if ServiceArguments[1] = ' ' then\n        if not Quoted then\n        begin\n          CharIsDelimitter := True;\n          Split := True;\n        end;\n\n      if ServiceArguments[1] = '\"' then\n      begin\n        Quoted := not Quoted;\n        CharIsDelimitter := True;\n\n        if not Quoted then\n          Split := True;\n      end;\n\n      if not CharIsDelimitter then\n        Param := Param + ServiceArguments[1];\n\n      if Split or (Length(ServiceArguments) = 1) then\n      begin\n        SetLength(ServiceArgVectors, Length(ServiceArgVectors) + 1);\n        GetMem(ServiceArgVectors[Length(ServiceArgVectors) -1], Length(Param) * SizeOf(Char) + 1);\n        StrPCopy(ServiceArgVectors[Length(ServiceArgVectors) -1], Param);\n\n        Param := '';\n\n        Delete(ServiceArguments, 1, 1);\n        ServiceArguments := Trim(ServiceArguments);\n      end\n      else\n        Delete(ServiceArguments, 1, 1);\n\n    end;\n\n    if Length(ServiceArgVectors) > 0 then\n      NumServiceArgs := Length(ServiceArgVectors);\n  end;\n\n  procedure FreeServiceArguments(ServiceArgVectors: TArguments);\n  var\n    i: Integer;\n  begin\n    if Length(ServiceArgVectors) > 0 then\n      for i := 0 to Length(ServiceArgVectors) -1 do\n        FreeMem(ServiceArgVectors[i]);\n  end;\n\nbegin\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_START);\n\n    if ServiceHandle > 0 then\n    begin\n      GetServiceArguments(ServiceArguments, NumServiceArgs, ServiceArgVectors);\n\n      if Winapi.WinSvc.StartService(ServiceHandle, NumServiceArgs, ServiceArgVectors[0]) then\n        Result := WaitForStatus(ServiceName, SERVICE_RUNNING, Timeout)\n      else\n        Result := System.GetLastError;\n\n      FreeServiceArguments(ServiceArgVectors);\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction StopService(ServiceName: String; WaitForFileRelease: Boolean; Timeout: Integer): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  ServiceStatus: TServiceStatus;\n  Dependencies: PEnumServiceStatus;\n  BytesNeeded: Cardinal;\n  ServicesReturned: Cardinal;\n  ServicesEnumerated: Boolean;\n  EnumerationSuccess: Boolean;\n  i: Cardinal;\nbegin\n  Result := 0;\n\n  BytesNeeded := 0;\n  ServicesReturned := 0;\n\n  Dependencies := nil;\n  ServicesEnumerated := False;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT or SC_MANAGER_ENUMERATE_SERVICE);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_STOP or SERVICE_ENUMERATE_DEPENDENTS);\n\n    if ServiceHandle > 0 then\n    begin\n      if not EnumDependentServices(ServiceHandle, SERVICE_ACTIVE, Dependencies^, 0, BytesNeeded, ServicesReturned) then\n      begin\n        ServicesEnumerated := True;\n        GetMem(Dependencies, BytesNeeded);\n\n        EnumerationSuccess := EnumDependentServices(ServiceHandle, SERVICE_ACTIVE, Dependencies^, BytesNeeded, BytesNeeded, ServicesReturned);\n\n        if EnumerationSuccess and (ServicesReturned > 0) then\n        begin\n          for i := 1 to ServicesReturned do\n          begin\n            Result := StopService(Dependencies.lpServiceName, False, Timeout);\n\n            if Result <> 0 then\n              Break;\n\n            Inc(Dependencies);\n          end;\n        end\n        else\n          Result := System.GetLastError;\n      end;\n\n      if (ServicesEnumerated and (Result = 0)) or not ServicesEnumerated then\n      begin\n        if ControlService(ServiceHandle, SERVICE_CONTROL_STOP, ServiceStatus) then\n          Result := WaitForStatus(ServiceName, SERVICE_STOPPED, Timeout)\n        else\n          Result := System.GetLastError\n      end;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\n\n  if (Result = 0) and WaitForFileRelease then\n    Result := ServiceControl.WaitForFileRelease(ServiceName, Timeout);\nend;\n\nfunction PauseService(ServiceName: String; Timeout: Integer): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  ServiceStatus: TServiceStatus;\nbegin\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_PAUSE_CONTINUE);\n\n    if ServiceHandle > 0 then\n    begin\n\n      if ControlService(ServiceHandle, SERVICE_CONTROL_PAUSE, ServiceStatus) then\n        Result := WaitForStatus(ServiceName, SERVICE_PAUSED, Timeout)\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction ContinueService(ServiceName: String; Timeout: Integer): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  ServiceStatus: TServiceStatus;\nbegin\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_PAUSE_CONTINUE);\n\n    if ServiceHandle > 0 then\n    begin\n\n      if ControlService(ServiceHandle, SERVICE_CONTROL_CONTINUE, ServiceStatus) then\n        Result := WaitForStatus(ServiceName, SERVICE_RUNNING, Timeout)\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceName(DisplayName: String; var Name: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceName: PChar;\n  ServiceBuffer: Cardinal;\nbegin\n  Result := 0;\n\n  ServiceBuffer := 255;\n  ServiceName := StrAlloc(ServiceBuffer+1);\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    if Winapi.WinSvc.GetServiceKeyName(ManagerHandle, PChar(DisplayName), ServiceName, ServiceBuffer) then\n      Name := ServiceName\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceDisplayName(ServiceName: String; var Name: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  DisplayName: PChar;\n  ServiceBuffer: Cardinal;\nbegin\n  Result := 0;\n\n  ServiceBuffer := 255;\n  DisplayName := StrAlloc(ServiceBuffer+1);\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    if Winapi.WinSvc.GetServiceDisplayName(ManagerHandle, PChar(ServiceName), DisplayName, ServiceBuffer) then\n      Name := DisplayName\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceStatus(ServiceName: String; var Status: DWORD): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  ServiceStatus: TServiceStatus;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_STATUS);\n\n    if ServiceHandle > 0 then\n    begin\n      if QueryServiceStatus(ServiceHandle, ServiceStatus) then\n        Status := ServiceStatus.dwCurrentState\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceBinaryPath(ServiceName: String; var BinaryPath: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  BytesNeeded: DWORD;\n  ServiceConfig: LPQUERY_SERVICE_CONFIG;\nbegin\n  Result := 0;\n  ServiceConfig := nil;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n\n      if not QueryServiceConfig(ServiceHandle, ServiceConfig, 0, BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n      begin\n        GetMem(ServiceConfig, BytesNeeded);\n\n        if QueryServiceConfig(ServiceHandle, ServiceConfig, BytesNeeded, BytesNeeded) then\n          BinaryPath := ServiceConfig^.lpBinaryPathName\n        else\n          Result := System.GetLastError;\n\n        FreeMem(ServiceConfig);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceStartType(ServiceName: String; var StartType: DWORD): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  BytesNeeded: DWORD;\n  ServiceConfig: LPQUERY_SERVICE_CONFIG;\nbegin\n  Result := 0;\n  ServiceConfig := nil;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n\n      if not QueryServiceConfig(ServiceHandle, ServiceConfig, 0, BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n      begin\n        GetMem(ServiceConfig, BytesNeeded);\n\n        if QueryServiceConfig(ServiceHandle, ServiceConfig, BytesNeeded, BytesNeeded) then\n          StartType := ServiceConfig^.dwStartType\n        else\n          Result := System.GetLastError;\n\n        FreeMem(ServiceConfig);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceDescription(ServiceName: String; var Description: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  BytesNeeded: DWORD;\n  ServiceDescription: LPSERVICE_DESCRIPTION;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n\n        if not QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_DESCRIPTION, nil, 0, @BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n        begin\n          GetMem(ServiceDescription, BytesNeeded);\n\n          if QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_DESCRIPTION, PByte(ServiceDescription), BytesNeeded, @BytesNeeded) then\n            Description := ServiceDescription.lpDescription\n          else\n            Result := System.GetLastError;\n\n          FreeMem(ServiceDescription);\n        end\n        else\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceLogon(ServiceName: String; var Username: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  BytesNeeded: DWORD;\n  ServiceConfig: LPQUERY_SERVICE_CONFIG;\nbegin\n  Result := 0;\n  ServiceConfig := nil;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_CONNECT);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n\n      if not QueryServiceConfig(ServiceHandle, ServiceConfig, 0, BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n      begin\n        GetMem(ServiceConfig, BytesNeeded);\n\n        if QueryServiceConfig(ServiceHandle, ServiceConfig, BytesNeeded, BytesNeeded) then\n          Username := ServiceConfig^.lpServiceStartName\n        else\n          Result := System.GetLastError;\n\n        FreeMem(ServiceConfig);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetServiceFailure(ServiceName: String; var ResetPeriod: DWORD;\n  var RebootMessage: String; var Command: String; var Action1: Integer; var ActionDelay1: DWORD;\n  var Action2: Integer; var ActionDelay2: DWORD; var Action3: Integer; var ActionDelay3: DWORD): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  BytesNeeded: DWORD;\n  ServiceFailureAction: LPSERVICE_FAILURE_ACTIONS;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n\n        if not QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, nil, 0, @BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n        begin\n          GetMem(ServiceFailureAction, BytesNeeded);\n\n          if QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, PByte(ServiceFailureAction), BytesNeeded, @BytesNeeded) then\n          begin\n            ResetPeriod := ServiceFailureAction.dwResetPeriod;\n            RebootMessage := ServiceFailureAction.lpRebootMsg;\n            Command := ServiceFailureAction.lpCommand;\n\n            if ServiceFailureAction.cActions >= 1 then\n            begin\n              Action1 := Integer(ServiceFailureAction.lpsaActions.&Type);\n              ActionDelay1 := ServiceFailureAction.lpsaActions.Delay;\n            end;\n\n            if ServiceFailureAction.cActions >= 2 then\n            begin\n              Inc(ServiceFailureAction.lpsaActions);\n              Action2 := Integer(ServiceFailureAction.lpsaActions.&Type);\n              ActionDelay2 := ServiceFailureAction.lpsaActions.Delay;\n            end;\n\n            if ServiceFailureAction.cActions >= 3 then\n            begin\n              Inc(ServiceFailureAction.lpsaActions);\n              Action3 := Integer(ServiceFailureAction.lpsaActions.&Type);\n              ActionDelay3 := ServiceFailureAction.lpsaActions.Delay;\n            end;\n          end\n          else\n            Result := System.GetLastError;\n\n          FreeMem(ServiceFailureAction);\n        end\n        else\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\n\nend;\n\nfunction GetServiceFailureFlag(ServiceName: String; var FailureActionsOnNonCrashFailures: Boolean): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  BytesNeeded: DWORD;\n  ServiceFailureActionsFlag: LPSERVICE_FAILURE_ACTIONS_FLAG;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n\n        if not QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, nil, 0, @BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n        begin\n          GetMem(ServiceFailureActionsFlag, BytesNeeded);\n\n          if QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, PByte(ServiceFailureActionsFlag), BytesNeeded, @BytesNeeded) then\n            FailureActionsOnNonCrashFailures := ServiceFailureActionsFlag.fFailureActionsOnNonCrashFailures\n          else\n            Result := System.GetLastError;\n\n          FreeMem(ServiceFailureActionsFlag);\n        end\n        else\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\n\nend;\n\nfunction GetServiceDelayedAutoStartInfo(ServiceName: String; var DelayedAutostart: Boolean): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  BytesNeeded: DWORD;\n  ServiceDelayedAutoStartInfo: LPSERVICE_DELAYED_AUTO_START_INFO;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_QUERY_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n\n        if not QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, nil, 0, @BytesNeeded) and (System.GetLastError = ERROR_INSUFFICIENT_BUFFER) then\n        begin\n          GetMem(ServiceDelayedAutoStartInfo, BytesNeeded);\n\n          if QueryServiceConfig2(ServiceHandle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, PByte(ServiceDelayedAutoStartInfo), BytesNeeded, @BytesNeeded) then\n            DelayedAutostart := Boolean(ServiceDelayedAutoStartInfo.fDelayedAutostart)\n          else\n            Result := System.GetLastError;\n\n          FreeMem(ServiceDelayedAutoStartInfo);\n        end\n        else\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\n\nend;\n    \nfunction SetServiceDescription(ServiceName: String; Description: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        if not ChangeServiceConfig2(ServiceHandle, SERVICE_CONFIG_DESCRIPTION, @Description) then\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction SetServiceStartType(ServiceName: String; StartType: DWORD): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        if not ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, StartType, SERVICE_NO_CHANGE, nil, nil, nil, nil, nil, nil, nil) then\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction SetServiceLogon(ServiceName: String; Username: String; Password: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if Pos('\\', Username) = 0 then\n    Username := '.\\' + Username;\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        if not ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, nil, nil, nil, nil, PChar(Username), PChar(Password), nil) then\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction SetServiceBinaryPath(ServiceName: String; BinaryPath: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\nbegin\n  Result := 0;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        if not ChangeServiceConfig(ServiceHandle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, PChar(BinaryPath), nil, nil, nil, nil, nil, nil) then\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction SetServiceFailure(ServiceName: String; ResetPeriod: DWORD;\n  RebootMessage: String; Command: String; Action1: Integer; ActionDelay1: DWORD;\n  Action2: Integer; ActionDelay2: DWORD; Action3: Integer; ActionDelay3: DWORD): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  ServiceFailureAction: SERVICE_FAILURE_ACTIONS;\n  ServiceActions: array[0..2] of SC_ACTION;\n  ServiceAccessType: Integer;\nbegin\n  Result := 0;\n\n  if (SC_ACTION_TYPE(Action1) = SC_ACTION_RESTART) or (SC_ACTION_TYPE(Action2) = SC_ACTION_RESTART) or (SC_ACTION_TYPE(Action3) = SC_ACTION_RESTART) then\n    ServiceAccessType := SERVICE_CHANGE_CONFIG or SERVICE_START\n  else\n    ServiceAccessType := SERVICE_ALL_ACCESS;\n\n  ServiceActions[0].&Type := SC_ACTION_TYPE(Action1);\n  ServiceActions[0].Delay := ActionDelay1;\n  ServiceActions[1].&Type := SC_ACTION_TYPE(Action2);\n  ServiceActions[1].Delay := ActionDelay2;\n  ServiceActions[2].&Type := SC_ACTION_TYPE(Action3);\n  ServiceActions[2].Delay := ActionDelay3;\n\n  ServiceFailureAction.dwResetPeriod := ResetPeriod;\n  ServiceFailureAction.lpRebootMsg := PChar(RebootMessage);\n  ServiceFailureAction.lpCommand := PChar(Command);\n  ServiceFailureAction.cActions := Length(ServiceActions);\n  ServiceFailureAction.lpsaActions := @ServiceActions;\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), ServiceAccessType);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        if not ChangeServiceConfig2W(ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, @ServiceFailureAction) then\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\n\nend;\n\nfunction SetServiceFailureFlag(ServiceName: String; FailureActionsOnNonCrashFailures: Boolean): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  ServiceFailureActionsFlag: SERVICE_FAILURE_ACTIONS_FLAG;\nbegin\n  Result := 0;\n\n  DWORD(ServiceFailureActionsFlag.fFailureActionsOnNonCrashFailures) := DWORD(FailureActionsOnNonCrashFailures);\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        if not ChangeServiceConfig2(ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, @ServiceFailureActionsFlag) then\n           Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\n    \nend;\n\nfunction SetServiceDelayedAutoStartInfo(ServiceName: String; DelayedAutostart: Boolean): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  ServiceDelayedAutoStartInfo: SERVICE_DELAYED_AUTO_START_INFO;\nbegin\n  Result := 0;\n\n  DWORD(ServiceDelayedAutoStartInfo.fDelayedAutostart) := DWORD(DelayedAutostart);\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_LOCK);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_CHANGE_CONFIG);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        if not ChangeServiceConfig2(ServiceHandle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, @ServiceDelayedAutoStartInfo) then\n           Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\n    \nend;\n\nfunction ServiceIsRunning(ServiceName: String; var IsRunning: Boolean): Integer;\nvar\n  Status: DWORD;\nbegin\n  Result := GetServiceStatus(ServiceName, Status);\n\n  if Result = 0 then\n    IsRunning := Status = SERVICE_RUNNING\n  else\n    IsRunning := False;\nend;\n\nfunction ServiceIsStopped(ServiceName: String; var IsStopped: Boolean): Integer;\nvar\n  Status: DWORD;\nbegin\n  Result := GetServiceStatus(ServiceName, Status);\n\n  if Result = 0 then\n    IsStopped := Status = SERVICE_STOPPED\n  else\n    IsStopped := False;\nend;\n\nfunction ServiceIsPaused(ServiceName: String; var IsPaused: Boolean): Integer;\nvar\n  Status: DWORD;\nbegin\n  Result := GetServiceStatus(ServiceName, Status);\n\n  if Result = 0 then\n    IsPaused := Status = SERVICE_PAUSED\n  else\n    IsPaused := False;\nend;\n\nfunction RestartService(ServiceName: String; ServiceArguments: String; Timeout: Integer): Integer;\nbegin\n  Result := StopService(ServiceName, False, Timeout);\n\n  if Result = 0 then\n    Result := StartService(ServiceName, ServiceArguments, Timeout);\nend;\n\nfunction InstallService(ServiceName, DisplayName: String; ServiceType: DWORD;\n  StartType: DWORD; BinaryPathName: String; Dependencies: String;\n  Username: String; Password: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  PDependencies: PChar;\n  PUsername: PChar;\n  PPassword: PChar;\nconst\n  ReplaceDelimitter: String = '/';\n\n  function Replace(Value: String): String;\n  begin\n    while Pos(ReplaceDelimitter, Value) <> 0 do\n    begin\n      Result := Result + Copy(Value, 1, Pos(ReplaceDelimitter, Value) -1) + Chr(0);\n      Delete(Value, 1, Pos(ReplaceDelimitter, Value));\n    end;\n\n    Result := Result + Value + Chr(0) + Chr(0);\n\n  end;\n\nbegin\n  Result := 0;\n\n  if Dependencies = '' then\n    PDependencies := nil\n  else\n    PDependencies := PChar(Replace(Dependencies));\n\n  if UserName = '' then\n    PUsername := nil\n  else\n  begin\n    if Pos('\\', Username) = 0 then\n      Username := '.\\' + Username;\n\n    PUsername := PChar(Username);\n  end;\n\n  if Password = '' then\n    PPassword := nil\n  else\n    PPassword := PChar(Password);\n\n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_ALL_ACCESS);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := CreateService(ManagerHandle,\n                                   PChar(ServiceName),\n                                   PChar(DisplayName),\n                                   SERVICE_START or SERVICE_QUERY_STATUS or _DELETE,\n                                   ServiceType,\n                                   StartType,\n                                   SERVICE_ERROR_NORMAL,\n                                   PChar(BinaryPathName),\n                                   nil,\n                                   nil,\n                                   PDependencies,\n                                   PUsername,\n                                   PPassword);\n\n    if ServiceHandle <> 0 then\n      CloseServiceHandle(ServiceHandle)\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction RemoveService(ServiceName: String): Integer;\nvar\n  ManagerHandle: SC_HANDLE;\n  ServiceHandle: SC_HANDLE;\n  LockHandle: SC_LOCK;\n  Deleted: Boolean;\nbegin\n  Result := 0;\n  \n  ManagerHandle := OpenSCManager('', nil, SC_MANAGER_ALL_ACCESS);\n\n  if ManagerHandle > 0 then\n  begin\n    ServiceHandle := OpenService(ManagerHandle, PChar(ServiceName), SERVICE_ALL_ACCESS);\n\n    if ServiceHandle > 0 then\n    begin\n      LockHandle := LockServiceDatabase(ManagerHandle);\n\n      if LockHandle <> nil then\n      begin\n        Deleted := DeleteService(ServiceHandle);\n\n        if not Deleted then\n          Result := System.GetLastError;\n\n        UnlockServiceDatabase(LockHandle);\n      end\n      else\n        Result := System.GetLastError;\n\n      CloseServiceHandle(ServiceHandle);\n    end\n    else\n      Result := System.GetLastError;\n\n    CloseServiceHandle(ManagerHandle);\n  end\n  else\n    Result := System.GetLastError;\nend;\n\nfunction GetErrorMessage(ErrorCode: Integer): String;\nbegin\n  Result := SysErrorMessage(ErrorCode);\nend;\n\nend.\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/Source/SimpleSC.dpr",
    "content": "library SimpleSC;\n\nuses\n  Winapi.Windows,\n  System.SysUtils,\n  NSIS in 'NSIS.pas',\n  ServiceControl in 'ServiceControl.pas',\n  LSASecurityControl in 'LSASecurityControl.pas';\n\nfunction BoolToStr(Value: Boolean): String;\nbegin\n  if Value then\n    Result := '1'\n  else\n    Result := '0';\nend;\n\nfunction StrToBool(Value: String): Boolean;\nbegin\n  Result := Value = '1';\nend;\n\nprocedure InstallService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  DisplayName: String;\n  ServiceType: Cardinal;\n  StartType: Cardinal;\n  BinaryPath: String;\n  Dependencies: String;\n  Username: String;\n  Password: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  DisplayName := PopString;\n  ServiceType := StrToInt(PopString);\n  StartType := StrToInt(PopString);\n  BinaryPath := PopString;\n  Dependencies := PopString;\n  Username := PopString;\n  Password := PopString;\n\n  ServiceResult := IntToStr(ServiceControl.InstallService(ServiceName, DisplayName, ServiceType, StartType, BinaryPath, Dependencies, Username, Password));\n  PushString(ServiceResult);\nend;\n\nprocedure RemoveService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n\n  ServiceResult := IntToStr(ServiceControl.RemoveService(ServiceName));\n  PushString(ServiceResult);\nend;\n\nprocedure StartService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  ServiceArguments: String;\n  Timeout: Integer;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceArguments := PopString;\n  Timeout := StrToInt(PopString);\n\n  ServiceResult := IntToStr(ServiceControl.StartService(ServiceName, ServiceArguments, Timeout));\n\n  PushString(ServiceResult);\nend;\n\nprocedure StopService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  WaitForFileRelease: Boolean;\n  Timeout: Integer;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n\n  WaitForFileRelease := StrToBool(PopString);\n  Timeout := StrToInt(PopString);\n\n  ServiceResult := IntToStr(ServiceControl.StopService(ServiceName, WaitForFileRelease, Timeout));\n  PushString(ServiceResult);\nend;\n\nprocedure PauseService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  Timeout: Integer;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  Timeout := StrToInt(PopString);\n  ServiceResult := IntToStr(ServiceControl.PauseService(ServiceName, Timeout));\n  PushString(ServiceResult)\nend;\n\nprocedure ContinueService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  Timeout: Integer;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  Timeout := StrToInt(PopString);\n  ServiceResult := IntToStr(ServiceControl.ContinueService(ServiceName, Timeout));\n  PushString(ServiceResult)\nend;\n\nprocedure GetServiceName(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nVar\n  DisplayName: String;\n  ServiceResult: String;\n  ServiceName: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  DisplayName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceName(DisplayName, ServiceName));\n  PushString(ServiceName);\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceDisplayName(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nVar\n  ServiceName: String;\n  DisplayName: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceDisplayName(ServiceName, DisplayName));\n  PushString(DisplayName);\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceStatus(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  Status: DWORD;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceStatus(ServiceName, Status));\n  PushString(IntToStr(Status));\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceBinaryPath(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  BinaryPath: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceBinaryPath(ServiceName, BinaryPath));\n  PushString(BinaryPath);\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceDescription(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  Description: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceDescription(ServiceName, Description));\n  PushString(Description);\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceStartType(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  StartType: DWORD;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceStartType(ServiceName, StartType));\n  PushString(IntToStr(StartType));\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceLogon(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  Username: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceLogon(ServiceName, Username));\n  PushString(Username);\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceFailure(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  ResetPeriod: DWORD;\n  RebootMessage: String;\n  Command: String;\n  Action1: Integer;\n  ActionDelay1: DWORD;\n  Action2: Integer;\n  ActionDelay2: DWORD;\n  Action3: Integer;\n  ActionDelay3: DWORD;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceFailure(ServiceName, ResetPeriod, RebootMessage, Command, Action1, ActionDelay1, Action2, ActionDelay2, Action3, ActionDelay3));\n  PushString(IntToStr(ActionDelay3));\n  PushString(IntToStr(Action3));\n  PushString(IntToStr(ActionDelay2));\n  PushString(IntToStr(Action2));\n  PushString(IntToStr(ActionDelay1));\n  PushString(IntToStr(Action1));\n  PushString(Command);\n  PushString(RebootMessage);\n  PushString(IntToStr(ResetPeriod));\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceFailureFlag(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  FailureActionsOnNonCrashFailures: Boolean;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceFailureFlag(ServiceName, FailureActionsOnNonCrashFailures));\n  PushString(BoolToStr(FailureActionsOnNonCrashFailures));\n  PushString(ServiceResult);\nend;\n\nprocedure GetServiceDelayedAutoStartInfo(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  DelayedAutostart: Boolean;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.GetServiceDelayedAutoStartInfo(ServiceName, DelayedAutostart));\n  PushString(BoolToStr(DelayedAutostart));\n  PushString(ServiceResult);\nend;\n\nprocedure SetServiceDescription(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  Description: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  Description := PopString;\n  ServiceResult := IntToStr(ServiceControl.SetServiceDescription(ServiceName, Description));\n  PushString(ServiceResult);\nend;\n\nprocedure SetServiceStartType(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  ServiceStartType: DWORD;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceStartType := StrToInt(PopString);\n  ServiceResult := IntToStr(ServiceControl.SetServiceStartType(ServiceName, ServiceStartType));\n  PushString(ServiceResult);\nend;\n\nprocedure SetServiceLogon(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  Username: String;\n  Password: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  Username := PopString;\n  Password := PopString;\n\n  ServiceResult := IntToStr(ServiceControl.SetServiceLogon(ServiceName, Username, Password));\n  PushString(ServiceResult);\nend;\n\nprocedure SetServiceBinaryPath(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  BinaryPath: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  BinaryPath := PopString;\n\n  ServiceResult := IntToStr(ServiceControl.SetServiceBinaryPath(ServiceName, BinaryPath));\n  PushString(ServiceResult);\nend;\n\nprocedure SetServiceFailure(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  ResetPeriod: DWORD;\n  RebootMessage: String;\n  Command: String;\n  Action1: Integer;\n  ActionDelay1: DWORD;\n  Action2: Integer;\n  ActionDelay2: DWORD;\n  Action3: Integer;\n  ActionDelay3: DWORD;\n  ServiceResult: Integer;\n  PrivilegeResult: Integer;\nconst\n  SE_SHUTDOWN_PRIVILEGE = 'SeShutdownPrivilege';\n  SC_ACTION_REBOOT = 2;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ResetPeriod := StrToInt(PopString);\n  RebootMessage := PopString;\n  Command := PopString;\n  Action1 := StrToInt(PopString);\n  ActionDelay1 := StrToInt(PopString);\n  Action2 := StrToInt(PopString);\n  ActionDelay2 := StrToInt(PopString);\n  Action3 := StrToInt(PopString);\n  ActionDelay3 := StrToInt(PopString);\n\n  if (Action1 = SC_ACTION_REBOOT) or (Action2 = SC_ACTION_REBOOT) or (Action3 = SC_ACTION_REBOOT) then\n  begin\n    PrivilegeResult := LSASecurityControl.EnablePrivilege(SE_SHUTDOWN_PRIVILEGE);\n\n    if not PrivilegeResult = 0 then\n    begin\n      PushString(IntToStr(PrivilegeResult));\n      Exit;\n    end;\n  end;\n\n  ServiceResult := ServiceControl.SetServiceFailure(ServiceName, ResetPeriod, RebootMessage, Command, Action1, ActionDelay1,\n                                                    Action2, ActionDelay2, Action3, ActionDelay3);\n\n\n  if (Action1 = SC_ACTION_REBOOT) or (Action2 = SC_ACTION_REBOOT) or (Action3 = SC_ACTION_REBOOT) then\n  begin\n    PrivilegeResult := LSASecurityControl.DisablePrivilege(SE_SHUTDOWN_PRIVILEGE);\n\n    if not PrivilegeResult = 0 then\n    begin\n      PushString(IntToStr(PrivilegeResult));\n      Exit;\n    end;\n  end;\n\n  PushString(IntToStr(ServiceResult));\n\nend;\n\nprocedure SetServiceFailureFlag(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  FailureActionsOnNonCrashFailures: Boolean;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  FailureActionsOnNonCrashFailures := StrToBool(PopString);\n  ServiceResult := IntToStr(ServiceControl.SetServiceFailureFlag(ServiceName, FailureActionsOnNonCrashFailures));\n  PushString(ServiceResult)\nend;\n\nprocedure SetServiceDelayedAutoStartInfo(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  DelayedAutostart: Boolean;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  DelayedAutostart := StrToBool(PopString);\n  ServiceResult := IntToStr(ServiceControl.SetServiceDelayedAutoStartInfo(ServiceName, DelayedAutostart));\n  PushString(ServiceResult)\nend;\n\nprocedure ServiceIsRunning(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  IsRunning: Boolean;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.ServiceIsRunning(ServiceName, IsRunning));\n  PushString(BoolToStr(IsRunning));\n  PushString(ServiceResult);\nend;\n\nprocedure ServiceIsStopped(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  IsStopped: Boolean;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.ServiceIsStopped(ServiceName, IsStopped));\n  PushString(BoolToStr(IsStopped));\n  PushString(ServiceResult);\nend;\n\nprocedure ServiceIsPaused(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  IsPaused: Boolean;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceResult := IntToStr(ServiceControl.ServiceIsPaused(ServiceName, IsPaused));\n  PushString(BoolToStr(IsPaused));\n  PushString(ServiceResult);\nend;\n\nprocedure RestartService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  ServiceArguments: String;\n  Timeout: Integer;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n  ServiceArguments := PopString;\n  Timeout := StrToInt(PopString);\n  ServiceResult := IntToStr(ServiceControl.RestartService(ServiceName, ServiceArguments, Timeout));\n  PushString(ServiceResult);\nend;\n\nprocedure ExistsService(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ServiceName: String;\n  ServiceResult: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ServiceName := PopString;\n\n  ServiceResult := IntToStr(ServiceControl.ExistsService(ServiceName));\n  PushString(ServiceResult);\nend;\n\nprocedure GrantServiceLogonPrivilege(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  AccountName: String;\n  LSAResult: String;\nconst\n  SE_SERVICE_LOGON_RIGHT = 'SeServiceLogonRight';\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  AccountName := PopString;\n\n  LSAResult := IntToStr(LSASecurityControl.GrantPrivilege(AccountName, SE_SERVICE_LOGON_RIGHT));\n  PushString(LSAResult);\nend;\n\nprocedure RemoveServiceLogonPrivilege(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  AccountName: String;\n  LSAResult: String;\nconst\n  SE_SERVICE_LOGON_RIGHT = 'SeServiceLogonRight';\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  AccountName := PopString;\n\n  LSAResult := IntToStr(LSASecurityControl.RemovePrivilege(AccountName, SE_SERVICE_LOGON_RIGHT));\n  PushString(LSAResult);\nend;\n\nprocedure GetErrorMessage(const hwndParent: HWND; const string_size: integer;\n  const variables: PChar; const stacktop: pointer); cdecl;\nvar\n  ErrorCode: Integer;\n  ErrorMessage: String;\nbegin\n  Init(hwndParent, string_size, variables, stacktop);\n\n  ErrorCode := StrToInt(PopString);\n\n  ErrorMessage := ServiceControl.GetErrorMessage(ErrorCode);\n  PushString(ErrorMessage);\nend;\n\nexports InstallService;\nexports ExistsService;\nexports RemoveService;\nexports StartService;\nexports StopService;\nexports PauseService;\nexports ContinueService;\nexports GetServiceName;\nexports GetServiceDisplayName;\nexports GetServiceStatus;\nexports GetServiceBinaryPath;\nexports GetServiceDescription;\nexports GetServiceStartType;\nexports GetServiceLogon;\nexports GetServiceFailure;\nexports GetServiceFailureFlag;\nexports GetServiceDelayedAutoStartInfo;\nexports SetServiceDescription;\nexports SetServiceStartType;\nexports SetServiceLogon;\nexports SetServiceBinaryPath;\nexports SetServiceFailure;\nexports SetServiceFailureFlag;\nexports SetServiceDelayedAutoStartInfo;\nexports ServiceIsRunning;\nexports ServiceIsStopped;\nexports ServiceIsPaused;\nexports RestartService;\nexports GrantServiceLogonPrivilege;\nexports RemoveServiceLogonPrivilege;\nexports GetErrorMessage;\n\nend.\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/NSIS_Simple_Service_Plugin_Unicode_1.30/Source/SimpleSC.dproj",
    "content": "﻿<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n    <PropertyGroup>\n        <ProjectGuid>{9A1C1FE1-FB44-40C4-9E22-99CAE6325532}</ProjectGuid>\n        <ProjectVersion>18.8</ProjectVersion>\n        <FrameworkType>None</FrameworkType>\n        <MainSource>SimpleSC.dpr</MainSource>\n        <Base>True</Base>\n        <Config Condition=\"'$(Config)'==''\">Release</Config>\n        <Platform Condition=\"'$(Platform)'==''\">Win32</Platform>\n        <TargetedPlatforms>1</TargetedPlatforms>\n        <AppType>Library</AppType>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"'$(Config)'=='Base' or '$(Base)'!=''\">\n        <Base>true</Base>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''\">\n        <Base_Win32>true</Base_Win32>\n        <CfgParent>Base</CfgParent>\n        <Base>true</Base>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''\">\n        <Base_Win64>true</Base_Win64>\n        <CfgParent>Base</CfgParent>\n        <Base>true</Base>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"'$(Config)'=='Release' or '$(Cfg_2)'!=''\">\n        <Cfg_2>true</Cfg_2>\n        <CfgParent>Base</CfgParent>\n        <Base>true</Base>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''\">\n        <Cfg_2_Win32>true</Cfg_2_Win32>\n        <CfgParent>Cfg_2</CfgParent>\n        <Cfg_2>true</Cfg_2>\n        <Base>true</Base>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"'$(Base)'!=''\">\n        <DCC_UsePackage>bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;soaprtl;DBXOracleDriver;dsnap;DBXInformixDriver;IndyCore;fmxase;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IPIndyImpl;$(DCC_UsePackage)</DCC_UsePackage>\n        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>\n        <GenDll>true</GenDll>\n        <DCC_DcuOutput>.\\$(Platform)\\$(Config)</DCC_DcuOutput>\n        <DCC_ExeOutput>.\\$(Platform)\\$(Config)</DCC_ExeOutput>\n        <DCC_E>false</DCC_E>\n        <DCC_N>false</DCC_N>\n        <DCC_S>false</DCC_S>\n        <DCC_F>false</DCC_F>\n        <DCC_K>false</DCC_K>\n        <SanitizedProjectName>SimpleSC</SanitizedProjectName>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"'$(Base_Win32)'!=''\">\n        <Manifest_File>None</Manifest_File>\n        <DCC_ExeOutput>C:\\Developing\\NSIS Simple Service Control - Unicode\\</DCC_ExeOutput>\n        <DCC_DcuOutput>C:\\Developing\\NSIS Simple Service Control - Unicode\\</DCC_DcuOutput>\n        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>\n        <DCC_UsePackage>frx16;TeeDB;Rave100VCL;vclib;Tee;inetdbbde;DBXOdbcDriver;svnui;ibxpress;DBXSybaseASEDriver;vclimg;frxDB16;intrawebdb_120_160;fmi;fs16;TeeUI;vclactnband;FMXTee;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;Intraweb_120_160;DBXDb2Driver;websnap;vclribbon;frxe16;fsDB16;vcl;DataSnapConnectors;CloudService;DBXMSSQLDriver;FmxTeeUI;dsnapcon;vclx;webdsnap;svn;bdertl;CodeSiteExpressPkg;adortl;vcldbx;VclSmp;$(DCC_UsePackage)</DCC_UsePackage>\n        <VerInfo_Locale>1033</VerInfo_Locale>\n        <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"'$(Base_Win64)'!=''\">\n        <DCC_UsePackage>DBXOdbcDriver;DBXSybaseASEDriver;vclimg;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;vcl;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;VclSmp;$(DCC_UsePackage)</DCC_UsePackage>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"'$(Cfg_2)'!=''\">\n        <Manifest_File>None</Manifest_File>\n        <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>\n        <DCC_ImportedDataReferences>false</DCC_ImportedDataReferences>\n        <VerInfo_Locale>1031</VerInfo_Locale>\n        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>\n        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>\n        <DCC_DebugInformation>0</DCC_DebugInformation>\n    </PropertyGroup>\n    <PropertyGroup Condition=\"'$(Cfg_2_Win32)'!=''\">\n        <DCC_ExeOutput>C:\\Developing\\NSIS Simple Service Control - Unicode\\</DCC_ExeOutput>\n        <DCC_DcuOutput>C:\\Developing\\NSIS Simple Service Control - Unicode\\</DCC_DcuOutput>\n        <VerInfo_Locale>1033</VerInfo_Locale>\n        <Manifest_File>(Ohne)</Manifest_File>\n    </PropertyGroup>\n    <ItemGroup>\n        <DelphiCompile Include=\"$(MainSource)\">\n            <MainSource>MainSource</MainSource>\n        </DelphiCompile>\n        <DCCReference Include=\"NSIS.pas\"/>\n        <DCCReference Include=\"ServiceControl.pas\"/>\n        <DCCReference Include=\"LSASecurityControl.pas\"/>\n        <BuildConfiguration Include=\"Release\">\n            <Key>Cfg_2</Key>\n            <CfgParent>Base</CfgParent>\n        </BuildConfiguration>\n        <BuildConfiguration Include=\"Base\">\n            <Key>Base</Key>\n        </BuildConfiguration>\n    </ItemGroup>\n    <ProjectExtensions>\n        <Borland.Personality>Delphi.Personality.12</Borland.Personality>\n        <Borland.ProjectType/>\n        <BorlandProject>\n            <Delphi.Personality>\n                <VersionInfo>\n                    <VersionInfo Name=\"IncludeVerInfo\">False</VersionInfo>\n                    <VersionInfo Name=\"AutoIncBuild\">False</VersionInfo>\n                    <VersionInfo Name=\"MajorVer\">1</VersionInfo>\n                    <VersionInfo Name=\"MinorVer\">0</VersionInfo>\n                    <VersionInfo Name=\"Release\">0</VersionInfo>\n                    <VersionInfo Name=\"Build\">0</VersionInfo>\n                    <VersionInfo Name=\"Debug\">False</VersionInfo>\n                    <VersionInfo Name=\"PreRelease\">False</VersionInfo>\n                    <VersionInfo Name=\"Special\">False</VersionInfo>\n                    <VersionInfo Name=\"Private\">False</VersionInfo>\n                    <VersionInfo Name=\"DLL\">False</VersionInfo>\n                    <VersionInfo Name=\"Locale\">1031</VersionInfo>\n                    <VersionInfo Name=\"CodePage\">1252</VersionInfo>\n                </VersionInfo>\n                <VersionInfoKeys>\n                    <VersionInfoKeys Name=\"CompanyName\"/>\n                    <VersionInfoKeys Name=\"FileDescription\"/>\n                    <VersionInfoKeys Name=\"FileVersion\">1.0.0.0</VersionInfoKeys>\n                    <VersionInfoKeys Name=\"InternalName\"/>\n                    <VersionInfoKeys Name=\"LegalCopyright\"/>\n                    <VersionInfoKeys Name=\"LegalTrademarks\"/>\n                    <VersionInfoKeys Name=\"OriginalFilename\"/>\n                    <VersionInfoKeys Name=\"ProductName\"/>\n                    <VersionInfoKeys Name=\"ProductVersion\">1.0.0.0</VersionInfoKeys>\n                    <VersionInfoKeys Name=\"Comments\"/>\n                </VersionInfoKeys>\n                <Source>\n                    <Source Name=\"MainSource\">SimpleSC.dpr</Source>\n                </Source>\n                <Excluded_Packages>\n                    <Excluded_Packages Name=\"$(BDSBIN)\\dcloffice2k260.bpl\">Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver</Excluded_Packages>\n                    <Excluded_Packages Name=\"$(BDSBIN)\\dclofficexp260.bpl\">Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server</Excluded_Packages>\n                </Excluded_Packages>\n            </Delphi.Personality>\n            <Deployment Version=\"3\">\n                <DeployFile LocalName=\"$(BDS)\\Redist\\osx32\\libcgunwind.1.0.dylib\" Class=\"DependencyModule\">\n                    <Platform Name=\"OSX32\">\n                        <Overwrite>true</Overwrite>\n                    </Platform>\n                </DeployFile>\n                <DeployFile LocalName=\"$(BDS)\\Redist\\iossimulator\\libcgunwind.1.0.dylib\" Class=\"DependencyModule\">\n                    <Platform Name=\"iOSSimulator\">\n                        <Overwrite>true</Overwrite>\n                    </Platform>\n                </DeployFile>\n                <DeployFile LocalName=\"$(BDS)\\Redist\\iossimulator\\libpcre.dylib\" Class=\"DependencyModule\">\n                    <Platform Name=\"iOSSimulator\">\n                        <Overwrite>true</Overwrite>\n                    </Platform>\n                </DeployFile>\n                <DeployClass Name=\"AdditionalDebugSymbols\">\n                    <Platform Name=\"OSX32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Win32\">\n                        <Operation>0</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidClassesDexFile\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>classes</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>classes</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidFileProvider\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\xml</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\xml</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidGDBServer\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>library\\lib\\armeabi-v7a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidLibnativeArmeabiFile\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>library\\lib\\armeabi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>library\\lib\\armeabi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidLibnativeArmeabiv7aFile\">\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>library\\lib\\armeabi-v7a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidLibnativeMipsFile\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>library\\lib\\mips</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>library\\lib\\mips</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidServiceOutput\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>library\\lib\\armeabi-v7a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>library\\lib\\arm64-v8a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidServiceOutput_Android32\">\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>library\\lib\\armeabi-v7a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidSplashImageDef\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidSplashStyles\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\values</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\values</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"AndroidSplashStylesV21\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\values-v21</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\values-v21</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_Colors\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\values</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\values</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_DefaultAppIcon\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_LauncherIcon144\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-xxhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-xxhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_LauncherIcon36\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-ldpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-ldpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_LauncherIcon48\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-mdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-mdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_LauncherIcon72\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-hdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-hdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_LauncherIcon96\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-xhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-xhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_NotificationIcon24\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-mdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-mdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_NotificationIcon36\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-hdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-hdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_NotificationIcon48\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-xhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-xhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_NotificationIcon72\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-xxhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-xxhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_NotificationIcon96\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-xxxhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-xxxhdpi</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_SplashImage426\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-small</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-small</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_SplashImage470\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-normal</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-normal</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_SplashImage640\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-large</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-large</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_SplashImage960\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\drawable-xlarge</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\drawable-xlarge</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"Android_Strings\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>res\\values</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>res\\values</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"DebugSymbols\">\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"OSX32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Win32\">\n                        <Operation>0</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"DependencyFramework\">\n                    <Platform Name=\"OSX32\">\n                        <Operation>1</Operation>\n                        <Extensions>.framework</Extensions>\n                    </Platform>\n                    <Platform Name=\"OSX64\">\n                        <Operation>1</Operation>\n                        <Extensions>.framework</Extensions>\n                    </Platform>\n                    <Platform Name=\"Win32\">\n                        <Operation>0</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"DependencyModule\">\n                    <Platform Name=\"OSX32\">\n                        <Operation>1</Operation>\n                        <Extensions>.dylib</Extensions>\n                    </Platform>\n                    <Platform Name=\"OSX64\">\n                        <Operation>1</Operation>\n                        <Extensions>.dylib</Extensions>\n                    </Platform>\n                    <Platform Name=\"Win32\">\n                        <Operation>0</Operation>\n                        <Extensions>.dll;.bpl</Extensions>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Required=\"true\" Name=\"DependencyPackage\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                        <Extensions>.dylib</Extensions>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                        <Extensions>.dylib</Extensions>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                        <Extensions>.dylib</Extensions>\n                    </Platform>\n                    <Platform Name=\"OSX32\">\n                        <Operation>1</Operation>\n                        <Extensions>.dylib</Extensions>\n                    </Platform>\n                    <Platform Name=\"OSX64\">\n                        <Operation>1</Operation>\n                        <Extensions>.dylib</Extensions>\n                    </Platform>\n                    <Platform Name=\"Win32\">\n                        <Operation>0</Operation>\n                        <Extensions>.bpl</Extensions>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"File\">\n                    <Platform Name=\"Android\">\n                        <Operation>0</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <Operation>0</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>0</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>0</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>0</Operation>\n                    </Platform>\n                    <Platform Name=\"OSX32\">\n                        <Operation>0</Operation>\n                    </Platform>\n                    <Platform Name=\"OSX64\">\n                        <Operation>0</Operation>\n                    </Platform>\n                    <Platform Name=\"Win32\">\n                        <Operation>0</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch1024x768\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch1536x2048\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch1668\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch1668x2388\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch2048x1536\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch2048x2732\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch2224\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch2388x1668\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch2732x2048\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPad_Launch768x1024\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch1125\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch1136x640\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch1242\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch1242x2688\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch1334\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch1792\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch2208\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch2436\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch2688x1242\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch320\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch640\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch640x1136\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch750\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"iPhone_Launch828\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"ProjectAndroidManifest\">\n                    <Platform Name=\"Android\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"ProjectiOSDeviceDebug\">\n                    <Platform Name=\"iOSDevice32\">\n                        <RemoteDir>..\\$(PROJECTNAME).app.dSYM\\Contents\\Resources\\DWARF</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <RemoteDir>..\\$(PROJECTNAME).app.dSYM\\Contents\\Resources\\DWARF</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"ProjectiOSDeviceResourceRules\"/>\n                <DeployClass Name=\"ProjectiOSEntitlements\"/>\n                <DeployClass Name=\"ProjectiOSInfoPList\"/>\n                <DeployClass Name=\"ProjectiOSResource\">\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"ProjectOSXDebug\"/>\n                <DeployClass Name=\"ProjectOSXEntitlements\"/>\n                <DeployClass Name=\"ProjectOSXInfoPList\"/>\n                <DeployClass Name=\"ProjectOSXResource\">\n                    <Platform Name=\"OSX32\">\n                        <RemoteDir>Contents\\Resources</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"OSX64\">\n                        <RemoteDir>Contents\\Resources</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Required=\"true\" Name=\"ProjectOutput\">\n                    <Platform Name=\"Android\">\n                        <RemoteDir>library\\lib\\armeabi-v7a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>library\\lib\\arm64-v8a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSDevice64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"iOSSimulator\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Linux64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"OSX32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"OSX64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Win32\">\n                        <Operation>0</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"ProjectOutput_Android32\">\n                    <Platform Name=\"Android64\">\n                        <RemoteDir>library\\lib\\armeabi-v7a</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"ProjectUWPManifest\">\n                    <Platform Name=\"Win32\">\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Win64\">\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"UWP_DelphiLogo150\">\n                    <Platform Name=\"Win32\">\n                        <RemoteDir>Assets</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Win64\">\n                        <RemoteDir>Assets</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <DeployClass Name=\"UWP_DelphiLogo44\">\n                    <Platform Name=\"Win32\">\n                        <RemoteDir>Assets</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                    <Platform Name=\"Win64\">\n                        <RemoteDir>Assets</RemoteDir>\n                        <Operation>1</Operation>\n                    </Platform>\n                </DeployClass>\n                <ProjectRoot Platform=\"iOSDevice64\" Name=\"$(PROJECTNAME).app\"/>\n                <ProjectRoot Platform=\"Win64\" Name=\"$(PROJECTNAME)\"/>\n                <ProjectRoot Platform=\"iOSDevice32\" Name=\"$(PROJECTNAME).app\"/>\n                <ProjectRoot Platform=\"Linux64\" Name=\"$(PROJECTNAME)\"/>\n                <ProjectRoot Platform=\"Win32\" Name=\"$(PROJECTNAME)\"/>\n                <ProjectRoot Platform=\"OSX32\" Name=\"$(PROJECTNAME)\"/>\n                <ProjectRoot Platform=\"Android\" Name=\"$(PROJECTNAME)\"/>\n                <ProjectRoot Platform=\"OSX64\" Name=\"$(PROJECTNAME)\"/>\n                <ProjectRoot Platform=\"iOSSimulator\" Name=\"$(PROJECTNAME).app\"/>\n                <ProjectRoot Platform=\"Android64\" Name=\"$(PROJECTNAME)\"/>\n            </Deployment>\n            <Platforms>\n                <Platform value=\"Win32\">True</Platform>\n                <Platform value=\"Win64\">False</Platform>\n            </Platforms>\n            <ModelSupport>False</ModelSupport>\n        </BorlandProject>\n        <ProjectFileVersion>12</ProjectFileVersion>\n    </ProjectExtensions>\n    <Import Condition=\"Exists('$(BDS)\\Bin\\CodeGear.Delphi.Targets')\" Project=\"$(BDS)\\Bin\\CodeGear.Delphi.Targets\"/>\n    <Import Condition=\"Exists('$(APPDATA)\\Embarcadero\\$(BDSAPPDATABASEDIR)\\$(PRODUCTVERSION)\\UserTools.proj')\" Project=\"$(APPDATA)\\Embarcadero\\$(BDSAPPDATABASEDIR)\\$(PRODUCTVERSION)\\UserTools.proj\"/>\n    <Import Project=\"$(MSBuildProjectName).deployproj\" Condition=\"Exists('$(MSBuildProjectName).deployproj')\"/>\n</Project>\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/nsis/install_hooks.nsh",
    "content": "!include LogicLib.nsh\n\n!addplugindir \"..\\..\\..\\..\\templates\\NSIS_Simple_Service_Plugin_Unicode_1.30\"\n\nvar oldInstallationDir\nvar dataDir\n\n!macro NSIS_HOOK_PREINSTALL\n  ; Try to stop the service if it's running\n  SimpleSC::ServiceIsStopped \"PortmasterCore\"\n  Pop $0\n  Pop $1\n  ${If} $0 == 0\n    ${If} $1 == 0\n\n      DetailPrint \"PortmasterCore service is running. Stopping service ...\"\n      SimpleSC::StopService \"PortmasterCore\" 1 60\n      Pop $0\n      ${If} $0 != 0\n        DetailPrint \"Failed to stop PortmasterCore service. Error: $0\"\n        MessageBox MB_OK \"PortmasterCore service is running. Stop it and run the installer again.\"\n        Abort\n      ${EndIf}\n      \n      ; wait a little (give change for service to fully stop)\n      Sleep 2000\n\n    ${EndIf}\n  ${EndIf}\n\n  File \"..\\..\\..\\..\\binary\\portmaster-core.exe\"\n  File \"..\\..\\..\\..\\binary\\portmaster-kext.sys\"\n  File \"..\\..\\..\\..\\binary\\portmaster-core.dll\"\n  File \"..\\..\\..\\..\\binary\\WebView2Loader.dll\"\n  File \"..\\..\\..\\..\\binary\\portmaster.zip\"\n  File \"..\\..\\..\\..\\binary\\assets.zip\"\n\n  SetOutPath \"$COMMONPROGRAMDATA\\Portmaster\\intel\"\n\n  File \"..\\..\\..\\..\\intel\\index.json\"\n  File \"..\\..\\..\\..\\intel\\base.dsdl\"\n  File \"..\\..\\..\\..\\intel\\geoipv4.mmdb\"\n  File \"..\\..\\..\\..\\intel\\geoipv6.mmdb\"\n  File \"..\\..\\..\\..\\intel\\index.dsd\"\n  File \"..\\..\\..\\..\\intel\\intermediate.dsdl\"\n  File \"..\\..\\..\\..\\intel\\urgent.dsdl\"\n  File \"..\\..\\..\\..\\intel\\main-intel.yaml\"\n  File \"..\\..\\..\\..\\intel\\notifications.yaml\"\n  File \"..\\..\\..\\..\\intel\\news.yaml\"\n\n  ; restire previous state\n  SetOutPath \"$INSTDIR\"\n\n!macroend\n\n;--------------------------------------------------\n; Post-install hook:\n; - Remove old service\n; - Installs the service\n!macro NSIS_HOOK_POSTINSTALL\n  DetailPrint \"Installing service\"\n  ; Remove old service\n  SimpleSC::RemoveService \"PortmasterCore\"\n\n  ; Install the service:\n  ; Parameters:\n  ;   1. Service Name: \"PortmasterCore\"\n  ;   2. Display Name: \"Portmaster Core\"\n  ;   3. Service Type: \"16\" for SERVICE_WIN32_OWN_PROCESS\n  ;   4. Start Type: \"2\" for SERVICE_AUTO_START\n  ;   5. Binary Path: Executable with arguments.\n  ;   6 & 7. Dependencies and account info (empty uses defaults).\n  SimpleSC::InstallService \"PortmasterCore\" \"Portmaster Core\" 16 2 \"$INSTDIR\\portmaster-core.exe --log-dir=%PROGRAMDATA%\\Portmaster\\logs\" \"\" \"\" \"\"\n  Pop $0  ; returns error code (0 on success)\n  ${If} $0 != 0\n    SimpleSC::GetErrorMessage $0\n    Pop $0\n    MessageBox MB_OK \"Service creation failed. Error: $0\"\n    Abort\n  ${EndIf}\n\n  SimpleSC::SetServiceDescription \"PortmasterCore\" \"Portmaster Application Firewall - Core Service\"\n\n  ; \n  ; Auto start the UI\n  ;\n  DetailPrint \"Creating registry entry for autostart\"\n  WriteRegStr HKLM \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\" \"Portmaster\" '\"$INSTDIR\\portmaster.exe\" --with-prompts --with-notifications --background'\n\n  ;\n  ; MIGRATION FROM PMv1 TO PMv2\n  ;\n  StrCpy $oldInstallationDir \"$COMMONPROGRAMDATA\\Safing\\Portmaster\"\n  StrCpy $dataDir \"$COMMONPROGRAMDATA\\Portmaster\"\n\n  ; Check if the folder exists\n  IfFileExists \"$oldInstallationDir\\*.*\" 0 Finish\n\n  ; Stop if the migration flag(file) already exists.\n  IfFileExists \"$oldInstallationDir\\migrated.txt\" Finish 0\n\n  ; Copy files\n  DetailPrint \"Migrating config from old installation: $oldInstallationDir\"\n\n  CreateDirectory \"$dataDir\"\n  CreateDirectory \"$dataDir\\databases\"\n  CopyFiles \"$oldInstallationDir\\config.json\" \"$dataDir\"\n  CopyFiles \"$oldInstallationDir\\databases\\*.*\" \"$dataDir\\databases\"\n\n  ; Create empty file to indicate that the data has already been migrated.\n  FileOpen $0 \"$oldInstallationDir\\migrated.txt\" w\n  FileClose $0\n\n  ; Delete v1 shortcuts\n  RMDir /r \"$SMPROGRAMS\\Portmaster\"\n  Delete \"$SMSTARTUP\\Portmaster Notifier.lnk\"\n\n  ; Delete v1 old binaries\n  Delete \"$oldInstallationDir\\portmaster-uninstaller.exe\"\n  Delete \"$oldInstallationDir\\portmaster-start.exe\"\n  Delete \"$oldInstallationDir\\portmaster.ico\"\n  RMDir /r \"$oldInstallationDir\\exec\"\n  RMDir /r \"$oldInstallationDir\\updates\"\n  RMDir /r \"$oldInstallationDir\\databases\\cache\"\n  RMDir /r \"$oldInstallationDir\\intel\"\n\n  ; Delete the link to the ProgramData folder\n  RMDir /r \"$PROGRAMFILES64\\Safing\"\n\n  ; Delete v1 user shortcut if its there.\n  SetShellVarContext current\n  Delete \"$AppData\\Microsoft\\Windows\\Start Menu\\Programs\\Portmaster.lnk\"\n  SetShellVarContext all\n\n  ; Delete v1 registry values\n  DeleteRegKey HKLM \"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Portmaster\"\n\n  Finish:\n\n!macroend\n\n;--------------------------------------------------\n; Pre-uninstall hook:\n; - Stops and removes the service.\n!macro NSIS_HOOK_PREUNINSTALL\n  DetailPrint \"Stopping service\"\n  ; Trigger service stop. In the worst case the service should stop in ~60 seconds.\n  SimpleSC::StopService \"PortmasterCore\" 1 60\n  Pop $0\n  ${If} $0 != 0\n    DetailPrint \"Failed to stop PortmasterCore service. Error: $0\"\n  ${Else}\n    DetailPrint \"Service PortmasterCore stopped successfully.\"\n  ${EndIf}\n\n  DetailPrint \"Removing service\"\n  SimpleSC::RemoveService \"PortmasterCore\"\n  Pop $0\n  ${If} $0 != 0\n    DetailPrint \"Failed to remove PortmasterCore service. Error: $0\"\n  ${Else}\n    DetailPrint \"Service PortmasterCore removed successfully.\"\n  ${EndIf}\n!macroend\n\n;--------------------------------------------------\n; Post-uninstall hook:\n; - Delete files\n!macro NSIS_HOOK_POSTUNINSTALL\n  ; Delete binaries\n  Delete /REBOOTOK \"$INSTDIR\\index.json\"\n  Delete /REBOOTOK \"$INSTDIR\\portmaster-core.exe\"\n  Delete /REBOOTOK \"$INSTDIR\\portmaster-kext.sys\"\n  Delete /REBOOTOK \"$INSTDIR\\portmaster-core.dll\"\n  Delete /REBOOTOK \"$INSTDIR\\WebView2Loader.dll\"\n  Delete /REBOOTOK \"$INSTDIR\\portmaster.zip\"\n  Delete /REBOOTOK \"$INSTDIR\\assets.zip\"\n  RMDir /r /REBOOTOK \"$INSTDIR\"\n\n  ; remove the registry entry for the autostart\n  DetailPrint \"Removing registry entry for autostart\"\n  DeleteRegKey HKLM \"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\"\n\n  ; delete data files\n  Delete  /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\\databases\\history.db\"\n  RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\\databases\\cache\"\n  RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\\intel\"\n  RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\\download_intel\"\n  RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\\download_binaries\"\n  RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\\exec\"\n  RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\\logs\"\n\n  ; Remove PMv1 migration flag\n  Delete /REBOOTOK \"$COMMONPROGRAMDATA\\Safing\\Portmaster\\migrated.txt\"\n\n  ${If} $DeleteAppDataCheckboxState = 1\n    DetailPrint \"Deleting the application data...\"\n    RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Portmaster\"\n    RMDir /r /REBOOTOK \"$COMMONPROGRAMDATA\\Safing\"\n  ${Else}\n    DetailPrint \"Application data kept as requested by the user.\"\n  ${EndIf}\n\n!macroend"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/wix/CheckServiceStatus.vbs",
    "content": "Option Explicit\n\nDim objShell, objExec, strOutput, arrLines, i, arrStatus\n\n' Create an instance of the WScript.Shell object\nSet objShell = CreateObject(\"WScript.Shell\")\n\n' Run the sc.exe command to query the service\nSet objExec = objShell.Exec(\"cmd /c sc.exe query PortmasterCore\")\n\n' Initialize an empty string to store the output\nstrOutput = \"\"\n\n' Read all output from the command line\nDo While Not objExec.StdOut.AtEndOfStream\n    strOutput = strOutput & objExec.StdOut.ReadLine() & vbCrLf\nLoop\n\n' Split the output into lines\narrLines = Split(strOutput, vbCrLf)\n\n' Example Output\n' SERVICE_NAME: PortmasterCore\n'         TYPE               : 10  WIN32_OWN_PROCESS\n'         STATE              : 1  STOPPED\n'         WIN32_EXIT_CODE    : 1077  (0x435)\n'         SERVICE_EXIT_CODE  : 0  (0x0)\n'         CHECKPOINT         : 0x0\n'         WAIT_HINT          : 0x0\n\nFor i = LBound(arrLines) To UBound(arrLines)\n\t' Example line: STATE              : 1  STOPPED\n    If InStr(arrLines(i), \"STATE\") > 0 Then\n        ' Extract and display the service state\n\t\t' Example string: \"1  STOPPED\"\n\t\tarrStatus = Split(Trim(Mid(arrLines(i), InStr(arrLines(i), \":\") + 1)), \" \")\n\t\t' Anything other the STOPPED consider as running\n\t\tIf Not arrStatus(2) = \"STOPPED\" Then\n\t\t\t MsgBox(\"Portmaster service is running. Stop it and run the installer again.\")\n\t\t\t ' Notify the installer that it should fail.\n\t\t\t WScript.Quit 1\n\t\tEnd If\n    End If\nNext"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/wix/Migration.vbs",
    "content": "Dim FSO\nSet FSO = CreateObject(\"Scripting.FileSystemObject\")\n\nDim customData, args, oldInstallationDir, migrationFlagFile, newDataDir, doMigration\ncustomData = Session.Property(\"CustomActionData\")\n\n' Split the string by commas\nargs = Split(customData, \",\")\n\n' Access individual arguments\nDim commonAppDataFolder, programMenuFolder, startupFolder, appDataFolder\ncommonAppDataFolder = Trim(args(0))\nprogramMenuFolder = Trim(args(1))\nstartupFolder = Trim(args(2))\nappDataFolder = Trim(args(3))\n\n' Read variables from the session object\noldInstallationDir = commonAppDataFolder & \"Safing\\Portmaster\\\"\nnewDataDir = commonAppDataFolder & \"Portmaster\"\nmigrationFlagFile = oldInstallationDir & \"migrated.txt\"\ndoMigration = true\n\n' Check for existing installtion\nIf Not fso.FolderExists(oldInstallationDir) Then\n\tdoMigration = false\nEnd If\n\n' Check if migration was already done\nIf fso.FileExists(migrationFlagFile) Then\n\tdoMigration = false\nEnd If\n\nIf doMigration Then\n\t' Copy the config file\n\tdim configFile\n\tconfigFile = \"config.json\"\n\tIf fso.FileExists(oldInstallationDir & configFile) Then\n\t\tfso.CopyFile oldInstallationDir & configFile, newDataDir & configFile\n\tEnd If\n\n\t' Copy the database folder\n\tdim databaseFolder\n\tdatabaseFolder = \"databases\"\n\tIf fso.FolderExists(oldInstallationDir & databaseFolder) Then\n\t\tfso.CopyFolder oldInstallationDir & databaseFolder, newDataDir & databaseFolder\n\tEnd If\n\n\t' Delete shortcuts\n\tdim shortcutsFolder\n\tnotifierShortcut = programMenuFolder & \"Portmaster/Portmaster Notifier.lnk\"\n\tIf fso.FileExists(notifierShortcut) Then\n\t\tfso.DeleteFile notifierShortcut, True\n\tEnd If\n\n\t' Delete startup shortcut\n\tdim srartupFile\n\tsrartupFile = startupFolder & \"Portmaster Notifier.lnk\"\n\tIf fso.FileExists(srartupFile) Then\n\t\tfso.DeleteFile srartupFile, True\n\tEnd If\n\n\t' Delete shortuct in user folder\n\tdim userShortcut\n\tuserShortcut = appDataFolder & \"Microsoft\\Windows\\Start Menu\\Programs\\Portmaster.lnk\"\n\tIf fso.FileExists(userShortcut) Then\n\t\tfso.DeleteFile userShortcut, True\n\tEnd If\n\n\t' Delete the old installer\n\tdim oldUninstaller\n\toldUninstaller = oldInstallationDir & \"portmaster-uninstaller.exe\"\n\tIf fso.FileExists(oldUninstaller) Then\n\t\tfso.DeleteFile oldUninstaller, True\n\tEnd If\n\n\t' Set the migration flag file\n\tfso.CreateTextFile(migrationFlagFile).Close\nEnd If"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/wix/files.wxs",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n  <Fragment>\n    <DirectoryRef Id=\"TARGETDIR\">\n      <Directory Id=\"CommonAppDataFolder\" Name=\"CommonAppData\">\n        <Directory Id=\"PortmasterDir\" Name=\"Portmaster\">\n          <Directory Id=\"IntelDir\" Name=\"intel\" />\n        </Directory>\n      </Directory>\n    </DirectoryRef>\n  </Fragment>\n\n  <Fragment>\n    <Component Id=\"BinaryFiles\" Directory=\"INSTALLDIR\" Guid=\"850cdd31-424d-45f5-b8f0-95df950ebd0d\">\n      <File Id=\"PortmasterCoreDLL\" Source=\"..\\..\\..\\..\\binary\\portmaster-core.dll\" />\n      <File Id=\"PortmasterKextSys\" Source=\"..\\..\\..\\..\\binary\\portmaster-kext.sys\" />\n      <File Id=\"WebView2Loader\" Source=\"..\\..\\..\\..\\binary\\WebView2Loader.dll\" />\n      <File Id=\"PortmasterZip\" Source=\"..\\..\\..\\..\\binary\\portmaster.zip\" />\n      <File Id=\"AssetsZip\" Source=\"..\\..\\..\\..\\binary\\assets.zip\" />\n    </Component>\n\n    <Component Id=\"IntelFiles\" Directory=\"IntelDir\" Guid=\"0bb439f1-2075-45b0-95bf-78ed3dffeb69\">\n      <File Id=\"IntelIndexJson\" Source=\"..\\..\\..\\..\\intel\\index.json\" />\n      <File Id=\"BaseDsdl\" Source=\"..\\..\\..\\..\\intel\\base.dsdl\" />\n      <File Id=\"Geoipv4Mmdb\" Source=\"..\\..\\..\\..\\intel\\geoipv4.mmdb\" />\n      <File Id=\"Geoipv6Mmdb\" Source=\"..\\..\\..\\..\\intel\\geoipv6.mmdb\" />\n      <File Id=\"IndexDsd\" Source=\"..\\..\\..\\..\\intel\\index.dsd\" />\n      <File Id=\"IntermediateDsdl\" Source=\"..\\..\\..\\..\\intel\\intermediate.dsdl\" />\n      <File Id=\"UrgentDsdl\" Source=\"..\\..\\..\\..\\intel\\urgent.dsdl\" />\n      <File Id=\"MainIntelYaml\" Source=\"..\\..\\..\\..\\intel\\main-intel.yaml\" />\n      <File Id=\"NotificationsYaml\" Source=\"..\\..\\..\\..\\intel\\notifications.yaml\" />\n      <File Id=\"NewsYaml\" Source=\"..\\..\\..\\..\\intel\\news.yaml\" />\n    </Component>\n\n    <Component Id=\"PortmasterCoreService\" Directory=\"INSTALLDIR\" Guid=\"76ebd748-d620-484b-9035-5a64bbe2c26d\">\n      <File Id=\"PortmasterCoreExe\" Source=\"..\\..\\..\\..\\binary\\portmaster-core.exe\" />\n      <ServiceInstall\n          Id=\"PortmasterServiceInstall\"\n          Type=\"ownProcess\"\n          Name=\"PortmasterCore\"\n          DisplayName=\"Portmaster Core\"\n          Description=\"Portmaster Application Firewall - Core Service\"\n          Start=\"auto\"\n          ErrorControl=\"normal\"\n          Vital=\"yes\"\n          Interactive=\"no\"\n          Arguments=\"--log-dir=%PROGRAMDATA%\\Portmaster\\logs\"\n          Account=\"LocalSystem\" />\n\n      <ServiceControl\n          Id=\"PortmasterServiceDeleteExisting\"\n          Name=\"PortmasterCore\"\n          Remove=\"uninstall\"\n          Stop=\"both\"\n          Wait=\"yes\"\n          />\n    </Component>\n  </Fragment>\n\n  <Fragment>\n    <ComponentGroup Id=\"BinaryAndIntelFiles\">\n      <ComponentRef Id=\"BinaryFiles\" />\n      <ComponentRef Id=\"IntelFiles\" />\n      <ComponentRef Id=\"PortmasterCoreService\" />\n    </ComponentGroup>\n  </Fragment>\n</Wix>"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/wix/main.wxs",
    "content": "<?if $(sys.BUILDARCH)=\"x86\"?>\n    <?define Win64 = \"no\" ?>\n    <?define PlatformProgramFilesFolder = \"ProgramFilesFolder\" ?>\n<?elseif $(sys.BUILDARCH)=\"x64\"?>\n    <?define Win64 = \"yes\" ?>\n    <?define PlatformProgramFilesFolder = \"ProgramFiles64Folder\" ?>\n<?elseif $(sys.BUILDARCH)=\"arm64\"?>\n    <?define Win64 = \"yes\" ?>\n    <?define PlatformProgramFilesFolder = \"ProgramFiles64Folder\" ?>\n<?else?>\n    <?error Unsupported value of sys.BUILDARCH=$(sys.BUILDARCH)?>\n<?endif?>\n\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n    <Product\n            Id=\"*\"\n            Name=\"{{product_name}}\"\n            UpgradeCode=\"{{upgrade_code}}\"\n            Language=\"!(loc.TauriLanguage)\"\n            Manufacturer=\"{{manufacturer}}\"\n            Version=\"{{version}}\">\n\n        <Package Id=\"*\"\n                 Keywords=\"Installer\"\n                 InstallerVersion=\"450\"\n                 Languages=\"0\"\n                 Compressed=\"yes\"\n                 InstallScope=\"perMachine\"\n                 SummaryCodepage=\"!(loc.TauriCodepage)\"/>\n\n        <!-- https://docs.microsoft.com/en-us/windows/win32/msi/reinstallmode -->\n        <!-- reinstall all files; rewrite all registry entries; reinstall all shortcuts -->\n        <Property Id=\"REINSTALLMODE\" Value=\"amus\" />\n\n        <!-- Auto launch app after installation, useful for passive mode which usually used in updates -->\n        <Property Id=\"AUTOLAUNCHAPP\" Secure=\"yes\" />\n        <!-- Property to forward cli args to the launched app to not lose those of the pre-update instance -->\n        <Property Id=\"LAUNCHAPPARGS\" Secure=\"yes\" />\n\n        {{#if allow_downgrades}}\n            <MajorUpgrade Schedule=\"afterInstallInitialize\" AllowDowngrades=\"yes\" />\n        {{else}}\n            <MajorUpgrade Schedule=\"afterInstallInitialize\" DowngradeErrorMessage=\"!(loc.DowngradeErrorMessage)\" AllowSameVersionUpgrades=\"yes\" />\n        {{/if}}\n\n        <InstallExecuteSequence>\n            <RemoveShortcuts>Installed AND NOT UPGRADINGPRODUCTCODE</RemoveShortcuts>\n        </InstallExecuteSequence>\n\n        <Media Id=\"1\" Cabinet=\"app.cab\" EmbedCab=\"yes\" />\n\n        {{#if banner_path}}\n        <WixVariable Id=\"WixUIBannerBmp\" Value=\"{{banner_path}}\" />\n        {{/if}}\n        {{#if dialog_image_path}}\n        <WixVariable Id=\"WixUIDialogBmp\" Value=\"{{dialog_image_path}}\" />\n        {{/if}}\n        {{#if license}}\n        <WixVariable Id=\"WixUILicenseRtf\" Value=\"{{license}}\" />\n        {{/if}}\n\n        <Icon Id=\"ProductIcon\" SourceFile=\"{{icon_path}}\"/>\n        <Property Id=\"ARPPRODUCTICON\" Value=\"ProductIcon\" />\n        <Property Id=\"ARPNOREPAIR\" Value=\"yes\" Secure=\"yes\" />      <!-- Remove repair -->\n        <SetProperty Id=\"ARPNOMODIFY\" Value=\"1\" After=\"InstallValidate\" Sequence=\"execute\"/>\n\n        {{#if homepage}}\n        <Property Id=\"ARPURLINFOABOUT\" Value=\"{{homepage}}\"/>\n        <Property Id=\"ARPHELPLINK\" Value=\"{{homepage}}\"/>\n        <Property Id=\"ARPURLUPDATEINFO\" Value=\"{{homepage}}\"/>\n        {{/if}}\n\n        <Property Id=\"INSTALLDIR\">\n          <!-- First attempt: Search for \"InstallDir\" -->\n          <RegistrySearch Id=\"PrevInstallDirWithName\" Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Name=\"InstallDir\" Type=\"raw\" />\n\n          <!-- Second attempt: If the first fails, search for the default key value (this is how the nsis installer currently stores the path) -->\n          <RegistrySearch Id=\"PrevInstallDirNoName\" Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Type=\"raw\" />\n        </Property>\n\n        <!-- launch app checkbox -->\n        <Property Id=\"WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT\" Value=\"!(loc.LaunchApp)\" />\n        <Property Id=\"WIXUI_EXITDIALOGOPTIONALCHECKBOX\" Value=\"1\"/>\n        <CustomAction Id=\"LaunchApplication\" Impersonate=\"yes\" FileKey=\"Path\" ExeCommand=\"[LAUNCHAPPARGS]\" Return=\"asyncNoWait\" />\n\n        <UI>\n            <!-- launch app checkbox -->\n            <Publish Dialog=\"ExitDialog\" Control=\"Finish\" Event=\"DoAction\" Value=\"LaunchApplication\">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>\n\n            <Property Id=\"WIXUI_INSTALLDIR\" Value=\"INSTALLDIR\" />\n\n            {{#unless license}}\n            <!-- Skip license dialog -->\n            <Publish Dialog=\"WelcomeDlg\"\n                     Control=\"Next\"\n                     Event=\"NewDialog\"\n                     Value=\"InstallDirDlg\"\n                     Order=\"2\">1</Publish>\n            <Publish Dialog=\"InstallDirDlg\"\n                     Control=\"Back\"\n                     Event=\"NewDialog\"\n                     Value=\"WelcomeDlg\"\n                     Order=\"2\">1</Publish>\n            {{/unless}}\n        </UI>\n\n        <UIRef Id=\"WixUI_InstallDir\" />\n\n        <Directory Id=\"TARGETDIR\" Name=\"SourceDir\">\n            <Directory Id=\"DesktopFolder\" Name=\"Desktop\">\n                <Component Id=\"ApplicationShortcutDesktop\" Guid=\"*\">\n                    <Shortcut Id=\"ApplicationDesktopShortcut\" Name=\"{{product_name}}\" Description=\"Runs {{product_name}}\" Target=\"[!Path]\" WorkingDirectory=\"INSTALLDIR\" />\n                    <RemoveFolder Id=\"DesktopFolder\" On=\"uninstall\" />\n                    <RegistryValue Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Name=\"Desktop Shortcut\" Type=\"integer\" Value=\"1\" KeyPath=\"yes\" />\n                </Component>\n            </Directory>\n            <Directory Id=\"$(var.PlatformProgramFilesFolder)\" Name=\"PFiles\">\n                <Directory Id=\"INSTALLDIR\" Name=\"{{product_name}}\"/>\n            </Directory>\n            <Directory Id=\"ProgramMenuFolder\">\n                <Directory Id=\"ApplicationProgramsFolder\" Name=\"{{product_name}}\"/>\n            </Directory>\n        </Directory>\n\n        <DirectoryRef Id=\"INSTALLDIR\">\n            <Component Id=\"RegistryEntries\" Guid=\"*\">\n                <RegistryKey Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\">\n                    <RegistryValue Name=\"InstallDir\" Type=\"string\" Value=\"[INSTALLDIR]\" KeyPath=\"yes\" />\n                </RegistryKey>\n                <!-- Change the Root to HKCU for perUser installations -->\n                {{#each deep_link_protocols as |protocol| ~}}\n                <RegistryKey Root=\"HKLM\" Key=\"Software\\Classes\\\\{{protocol}}\">\n                    <RegistryValue Type=\"string\" Name=\"URL Protocol\" Value=\"\"/>\n                    <RegistryValue Type=\"string\" Value=\"URL:{{bundle_id}} protocol\"/>\n                    <RegistryKey Key=\"DefaultIcon\">\n                        <RegistryValue Type=\"string\" Value=\"&quot;[!Path]&quot;,0\" />\n                    </RegistryKey>\n                    <RegistryKey Key=\"shell\\open\\command\">\n                        <RegistryValue Type=\"string\" Value=\"&quot;[!Path]&quot; &quot;%1&quot;\" />\n                    </RegistryKey>\n                </RegistryKey>\n                {{/each~}}\n            </Component>\n            <Component Id=\"Path\" Guid=\"{{path_component_guid}}\" Win64=\"$(var.Win64)\">\n                <File Id=\"Path\" Source=\"{{main_binary_path}}\" KeyPath=\"yes\" Checksum=\"yes\"/>\n                {{#each file_associations as |association| ~}}\n                {{#each association.ext as |ext| ~}}\n                <ProgId Id=\"{{../../product_name}}.{{ext}}\" Advertise=\"yes\" Description=\"{{association.description}}\">\n                    <Extension Id=\"{{ext}}\" Advertise=\"yes\">\n                        <Verb Id=\"open\" Command=\"Open with {{../../product_name}}\" Argument=\"&quot;%1&quot;\" />\n                    </Extension>\n                </ProgId>\n                {{/each~}}\n                {{/each~}}\n            </Component>\n            {{#each binaries as |bin| ~}}\n            <Component Id=\"{{ bin.id }}\" Guid=\"{{bin.guid}}\" Win64=\"$(var.Win64)\">\n                <File Id=\"Bin_{{ bin.id }}\" Source=\"{{bin.path}}\" KeyPath=\"yes\"/>\n            </Component>\n            {{/each~}}\n            {{#if enable_elevated_update_task}}\n            <Component Id=\"UpdateTask\" Guid=\"C492327D-9720-4CD5-8DB8-F09082AF44BE\" Win64=\"$(var.Win64)\">\n                <File Id=\"UpdateTask\" Source=\"update.xml\" KeyPath=\"yes\" Checksum=\"yes\"/>\n            </Component>\n            <Component Id=\"UpdateTaskInstaller\" Guid=\"011F25ED-9BE3-50A7-9E9B-3519ED2B9932\" Win64=\"$(var.Win64)\">\n                <File Id=\"UpdateTaskInstaller\" Source=\"install-task.ps1\" KeyPath=\"yes\" Checksum=\"yes\"/>\n                \n            </Component>\n            <Component Id=\"UpdateTaskUninstaller\" Guid=\"D4F6CC3F-32DC-5FD0-95E8-782FFD7BBCE1\" Win64=\"$(var.Win64)\">\n                <File Id=\"UpdateTaskUninstaller\" Source=\"uninstall-task.ps1\" KeyPath=\"yes\" Checksum=\"yes\"/>\n            </Component>\n            {{/if}}\n            {{resources}}\n            <Component Id=\"CMP_UninstallShortcut\" Guid=\"*\">\n\n                <Shortcut Id=\"UninstallShortcut\"\n\t\t\t\t\t\t  Name=\"Uninstall {{product_name}}\"\n\t\t\t\t\t\t  Description=\"Uninstalls {{product_name}}\"\n\t\t\t\t\t\t  Target=\"[System64Folder]msiexec.exe\"\n\t\t\t\t\t\t  Arguments=\"/x [ProductCode]\" />\n\n\t\t\t\t<RemoveFolder Id=\"INSTALLDIR\"\n\t\t\t\t\t\t\t  On=\"uninstall\" />\n\n\t\t\t\t<RegistryValue Root=\"HKCU\"\n\t\t\t\t\t\t\t   Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\"\n\t\t\t\t\t\t\t   Name=\"Uninstaller Shortcut\"\n\t\t\t\t\t\t\t   Type=\"integer\"\n\t\t\t\t\t\t\t   Value=\"1\"\n\t\t\t\t\t\t\t   KeyPath=\"yes\" />\n            </Component>\n        </DirectoryRef>\n\n        <DirectoryRef Id=\"ApplicationProgramsFolder\">\n            <Component Id=\"ApplicationShortcut\" Guid=\"*\">\n                <Shortcut Id=\"ApplicationStartMenuShortcut\"\n                    Name=\"{{product_name}}\"\n                    Description=\"Runs {{product_name}}\"\n                    Target=\"[!Path]\"\n                    Icon=\"ProductIcon\"\n                    WorkingDirectory=\"INSTALLDIR\">\n                    <ShortcutProperty Key=\"System.AppUserModel.ID\" Value=\"{{bundle_id}}\"/>\n                </Shortcut>\n                <RemoveFolder Id=\"ApplicationProgramsFolder\" On=\"uninstall\"/>\n                <RegistryValue Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Name=\"Start Menu Shortcut\" Type=\"integer\" Value=\"1\" KeyPath=\"yes\"/>\n           </Component>\n        </DirectoryRef>\n\n        {{#each merge_modules as |msm| ~}}\n        <DirectoryRef Id=\"TARGETDIR\">\n            <Merge Id=\"{{ msm.name }}\" SourceFile=\"{{ msm.path }}\" DiskId=\"1\" Language=\"!(loc.TauriLanguage)\" />\n        </DirectoryRef>\n\n        <Feature Id=\"{{ msm.name }}\" Title=\"{{ msm.name }}\" AllowAdvertise=\"no\" Display=\"hidden\" Level=\"1\">\n            <MergeRef Id=\"{{ msm.name }}\"/>\n        </Feature>\n        {{/each~}}\n\n        <Feature\n                Id=\"MainProgram\"\n                Title=\"Application\"\n                Description=\"!(loc.InstallAppFeature)\"\n                Level=\"1\"\n                ConfigurableDirectory=\"INSTALLDIR\"\n                AllowAdvertise=\"no\"\n                Display=\"expand\"\n                Absent=\"disallow\">\n\n            <ComponentRef Id=\"RegistryEntries\"/>\n\n            {{#each resource_file_ids as |resource_file_id| ~}}\n                <ComponentRef Id=\"{{ resource_file_id }}\"/>\n            {{/each~}}\n\n            {{#if enable_elevated_update_task}}\n                <ComponentRef Id=\"UpdateTask\" />\n                <ComponentRef Id=\"UpdateTaskInstaller\" />\n                <ComponentRef Id=\"UpdateTaskUninstaller\" />\n            {{/if}}\n\n            <Feature Id=\"ShortcutsFeature\"\n                Title=\"Shortcuts\"\n                Level=\"1\">\n                <ComponentRef Id=\"Path\"/>\n                <ComponentRef Id=\"CMP_UninstallShortcut\" />\n                <ComponentRef Id=\"ApplicationShortcut\" />\n                <ComponentRef Id=\"ApplicationShortcutDesktop\" />\n            </Feature>\n\n            <Feature\n                Id=\"Environment\"\n                Title=\"PATH Environment Variable\"\n                Description=\"!(loc.PathEnvVarFeature)\"\n                Level=\"1\"\n                Absent=\"allow\">\n            <ComponentRef Id=\"Path\"/>\n            {{#each binaries as |bin| ~}}\n            <ComponentRef Id=\"{{ bin.id }}\"/>\n            {{/each~}}\n            </Feature>\n        </Feature>\n\n        <Feature Id=\"External\" AllowAdvertise=\"no\" Absent=\"disallow\">\n            {{#each component_group_refs as |id| ~}}\n            <ComponentGroupRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each component_refs as |id| ~}}\n            <ComponentRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each feature_group_refs as |id| ~}}\n            <FeatureGroupRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each feature_refs as |id| ~}}\n            <FeatureRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each merge_refs as |id| ~}}\n            <MergeRef Id=\"{{ id }}\"/>\n            {{/each~}}\n        </Feature>\n\n        {{#if install_webview}}\n        <!-- WebView2 -->\n        <Property Id=\"WVRTINSTALLED\">\n            <RegistrySearch Id=\"WVRTInstalledSystem\" Root=\"HKLM\" Key=\"SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}\" Name=\"pv\" Type=\"raw\" Win64=\"no\" />\n            <RegistrySearch Id=\"WVRTInstalledUser\" Root=\"HKCU\" Key=\"SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}\" Name=\"pv\" Type=\"raw\"/>\n        </Property>\n\n        {{#if download_bootstrapper}}\n        <CustomAction Id='DownloadAndInvokeBootstrapper' Directory=\"INSTALLDIR\" Execute=\"deferred\" ExeCommand='powershell.exe -NoProfile -windowstyle hidden try [\\{] [\\[]Net.ServicePointManager[\\]]::SecurityProtocol = [\\[]Net.SecurityProtocolType[\\]]::Tls12 [\\}] catch [\\{][\\}]; Invoke-WebRequest -Uri \"https://go.microsoft.com/fwlink/p/?LinkId=2124703\" -OutFile \"$env:TEMP\\MicrosoftEdgeWebview2Setup.exe\" ; Start-Process -FilePath \"$env:TEMP\\MicrosoftEdgeWebview2Setup.exe\" -ArgumentList ({{webview_installer_args}} &apos;/install&apos;) -Wait' Return='check'/>\n        <InstallExecuteSequence>\n            <Custom Action='DownloadAndInvokeBootstrapper' Before='InstallFinalize'>\n                <![CDATA[NOT(REMOVE OR WVRTINSTALLED)]]>\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        <!-- Embedded webview bootstrapper mode -->\n        {{#if webview2_bootstrapper_path}}\n        <Binary Id=\"MicrosoftEdgeWebview2Setup.exe\" SourceFile=\"{{webview2_bootstrapper_path}}\"/>\n        <CustomAction Id='InvokeBootstrapper' BinaryKey='MicrosoftEdgeWebview2Setup.exe' Execute=\"deferred\" ExeCommand='{{webview_installer_args}} /install' Return='check' />\n        <InstallExecuteSequence>\n            <Custom Action='InvokeBootstrapper' Before='InstallFinalize'>\n                <![CDATA[NOT(REMOVE OR WVRTINSTALLED)]]>\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        <!-- Embedded offline installer -->\n        {{#if webview2_installer_path}}\n        <Binary Id=\"MicrosoftEdgeWebView2RuntimeInstaller.exe\" SourceFile=\"{{webview2_installer_path}}\"/>\n        <CustomAction Id='InvokeStandalone' BinaryKey='MicrosoftEdgeWebView2RuntimeInstaller.exe' Execute=\"deferred\" ExeCommand='{{webview_installer_args}} /install' Return='check' />\n        <InstallExecuteSequence>\n            <Custom Action='InvokeStandalone' Before='InstallFinalize'>\n                <![CDATA[NOT(REMOVE OR WVRTINSTALLED)]]>\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        {{/if}}\n\n        {{#if enable_elevated_update_task}}\n        <!-- Install an elevated update task within Windows Task Scheduler -->\n        <CustomAction\n            Id=\"CreateUpdateTask\"\n            Return=\"check\"\n            Directory=\"INSTALLDIR\"\n            Execute=\"commit\"\n            Impersonate=\"yes\"\n            ExeCommand=\"powershell.exe -WindowStyle hidden .\\install-task.ps1\" />\n\n        <InstallExecuteSequence>\n            <Custom Action='CreateUpdateTask' Before='InstallFinalize'>\n                NOT(REMOVE)\n            </Custom>\n        </InstallExecuteSequence>\n        <!-- Remove elevated update task during uninstall -->\n        <CustomAction\n            Id=\"DeleteUpdateTask\"\n            Return=\"check\"\n            Directory=\"INSTALLDIR\"\n            ExeCommand=\"powershell.exe -WindowStyle hidden .\\uninstall-task.ps1\" />\n        <InstallExecuteSequence>\n            <Custom Action=\"DeleteUpdateTask\" Before='InstallFinalize'>\n                (REMOVE = \"ALL\") AND NOT UPGRADINGPRODUCTCODE\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        <InstallExecuteSequence>\n          <Custom Action=\"LaunchApplication\" After=\"InstallFinalize\">AUTOLAUNCHAPP AND NOT Installed</Custom>\n        </InstallExecuteSequence>\n\n        <SetProperty Id=\"ARPINSTALLLOCATION\" Value=\"[INSTALLDIR]\" After=\"CostFinalize\"/>\n\n        <!-- Service fragments -->\n        <CustomActionRef Id='MigrationPropertySet' />\n        <CustomActionRef Id='Migration' />\n        <!-- Uncommenting the next line will cause the installer to check if the old service is running and fail. Without, it will automatically stop and remove the old service without notifing the user. -->\n        <!-- <CustomActionRef Id='CheckServiceStatus' /> -->\n        <!-- End Service fragments -->\n\n    </Product>\n</Wix>"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/wix/main_original.wxs",
    "content": "<?if $(sys.BUILDARCH)=\"x86\"?>\n    <?define Win64 = \"no\" ?>\n    <?define PlatformProgramFilesFolder = \"ProgramFilesFolder\" ?>\n<?elseif $(sys.BUILDARCH)=\"x64\"?>\n    <?define Win64 = \"yes\" ?>\n    <?define PlatformProgramFilesFolder = \"ProgramFiles64Folder\" ?>\n<?elseif $(sys.BUILDARCH)=\"arm64\"?>\n    <?define Win64 = \"yes\" ?>\n    <?define PlatformProgramFilesFolder = \"ProgramFiles64Folder\" ?>\n<?else?>\n    <?error Unsupported value of sys.BUILDARCH=$(sys.BUILDARCH)?>\n<?endif?>\n\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n    <Product\n            Id=\"*\"\n            Name=\"{{product_name}}\"\n            UpgradeCode=\"{{upgrade_code}}\"\n            Language=\"!(loc.TauriLanguage)\"\n            Manufacturer=\"{{manufacturer}}\"\n            Version=\"{{version}}\">\n\n        <Package Id=\"*\"\n                 Keywords=\"Installer\"\n                 InstallerVersion=\"450\"\n                 Languages=\"0\"\n                 Compressed=\"yes\"\n                 InstallScope=\"perMachine\"\n                 SummaryCodepage=\"!(loc.TauriCodepage)\"/>\n\n        <!-- https://docs.microsoft.com/en-us/windows/win32/msi/reinstallmode -->\n        <!-- reinstall all files; rewrite all registry entries; reinstall all shortcuts -->\n        <Property Id=\"REINSTALLMODE\" Value=\"amus\" />\n\n        <!-- Auto launch app after installation, useful for passive mode which usually used in updates -->\n        <Property Id=\"AUTOLAUNCHAPP\" Secure=\"yes\" />\n        <!-- Property to forward cli args to the launched app to not lose those of the pre-update instance -->\n        <Property Id=\"LAUNCHAPPARGS\" Secure=\"yes\" />\n\n        {{#if allow_downgrades}}\n            <MajorUpgrade Schedule=\"afterInstallInitialize\" AllowDowngrades=\"yes\" />\n        {{else}}\n            <MajorUpgrade Schedule=\"afterInstallInitialize\" DowngradeErrorMessage=\"!(loc.DowngradeErrorMessage)\" AllowSameVersionUpgrades=\"yes\" />\n        {{/if}}\n\n        <InstallExecuteSequence>\n            <RemoveShortcuts>Installed AND NOT UPGRADINGPRODUCTCODE</RemoveShortcuts>\n        </InstallExecuteSequence>\n\n        <Media Id=\"1\" Cabinet=\"app.cab\" EmbedCab=\"yes\" />\n\n        {{#if banner_path}}\n        <WixVariable Id=\"WixUIBannerBmp\" Value=\"{{banner_path}}\" />\n        {{/if}}\n        {{#if dialog_image_path}}\n        <WixVariable Id=\"WixUIDialogBmp\" Value=\"{{dialog_image_path}}\" />\n        {{/if}}\n        {{#if license}}\n        <WixVariable Id=\"WixUILicenseRtf\" Value=\"{{license}}\" />\n        {{/if}}\n\n        <Icon Id=\"ProductIcon\" SourceFile=\"{{icon_path}}\"/>\n        <Property Id=\"ARPPRODUCTICON\" Value=\"ProductIcon\" />\n        <Property Id=\"ARPNOREPAIR\" Value=\"yes\" Secure=\"yes\" />      <!-- Remove repair -->\n        <SetProperty Id=\"ARPNOMODIFY\" Value=\"1\" After=\"InstallValidate\" Sequence=\"execute\"/>\n\n        {{#if homepage}}\n        <Property Id=\"ARPURLINFOABOUT\" Value=\"{{homepage}}\"/>\n        <Property Id=\"ARPHELPLINK\" Value=\"{{homepage}}\"/>\n        <Property Id=\"ARPURLUPDATEINFO\" Value=\"{{homepage}}\"/>\n        {{/if}}\n\n        <Property Id=\"INSTALLDIR\">\n          <!-- First attempt: Search for \"InstallDir\" -->\n          <RegistrySearch Id=\"PrevInstallDirWithName\" Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Name=\"InstallDir\" Type=\"raw\" />\n\n          <!-- Second attempt: If the first fails, search for the default key value (this is how the nsis installer currently stores the path) -->\n          <RegistrySearch Id=\"PrevInstallDirNoName\" Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Type=\"raw\" />\n        </Property>\n\n        <!-- launch app checkbox -->\n        <Property Id=\"WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT\" Value=\"!(loc.LaunchApp)\" />\n        <Property Id=\"WIXUI_EXITDIALOGOPTIONALCHECKBOX\" Value=\"1\"/>\n        <CustomAction Id=\"LaunchApplication\" Impersonate=\"yes\" FileKey=\"Path\" ExeCommand=\"[LAUNCHAPPARGS]\" Return=\"asyncNoWait\" />\n\n        <UI>\n            <!-- launch app checkbox -->\n            <Publish Dialog=\"ExitDialog\" Control=\"Finish\" Event=\"DoAction\" Value=\"LaunchApplication\">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>\n\n            <Property Id=\"WIXUI_INSTALLDIR\" Value=\"INSTALLDIR\" />\n\n            {{#unless license}}\n            <!-- Skip license dialog -->\n            <Publish Dialog=\"WelcomeDlg\"\n                     Control=\"Next\"\n                     Event=\"NewDialog\"\n                     Value=\"InstallDirDlg\"\n                     Order=\"2\">1</Publish>\n            <Publish Dialog=\"InstallDirDlg\"\n                     Control=\"Back\"\n                     Event=\"NewDialog\"\n                     Value=\"WelcomeDlg\"\n                     Order=\"2\">1</Publish>\n            {{/unless}}\n        </UI>\n\n        <UIRef Id=\"WixUI_InstallDir\" />\n\n        <Directory Id=\"TARGETDIR\" Name=\"SourceDir\">\n            <Directory Id=\"DesktopFolder\" Name=\"Desktop\">\n                <Component Id=\"ApplicationShortcutDesktop\" Guid=\"*\">\n                    <Shortcut Id=\"ApplicationDesktopShortcut\" Name=\"{{product_name}}\" Description=\"Runs {{product_name}}\" Target=\"[!Path]\" WorkingDirectory=\"INSTALLDIR\" />\n                    <RemoveFolder Id=\"DesktopFolder\" On=\"uninstall\" />\n                    <RegistryValue Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Name=\"Desktop Shortcut\" Type=\"integer\" Value=\"1\" KeyPath=\"yes\" />\n                </Component>\n            </Directory>\n            <Directory Id=\"$(var.PlatformProgramFilesFolder)\" Name=\"PFiles\">\n                <Directory Id=\"INSTALLDIR\" Name=\"{{product_name}}\"/>\n            </Directory>\n            <Directory Id=\"ProgramMenuFolder\">\n                <Directory Id=\"ApplicationProgramsFolder\" Name=\"{{product_name}}\"/>\n            </Directory>\n        </Directory>\n\n        <DirectoryRef Id=\"INSTALLDIR\">\n            <Component Id=\"RegistryEntries\" Guid=\"*\">\n                <RegistryKey Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\">\n                    <RegistryValue Name=\"InstallDir\" Type=\"string\" Value=\"[INSTALLDIR]\" KeyPath=\"yes\" />\n                </RegistryKey>\n                <!-- Change the Root to HKCU for perUser installations -->\n                {{#each deep_link_protocols as |protocol| ~}}\n                <RegistryKey Root=\"HKLM\" Key=\"Software\\Classes\\\\{{protocol}}\">\n                    <RegistryValue Type=\"string\" Name=\"URL Protocol\" Value=\"\"/>\n                    <RegistryValue Type=\"string\" Value=\"URL:{{bundle_id}} protocol\"/>\n                    <RegistryKey Key=\"DefaultIcon\">\n                        <RegistryValue Type=\"string\" Value=\"&quot;[!Path]&quot;,0\" />\n                    </RegistryKey>\n                    <RegistryKey Key=\"shell\\open\\command\">\n                        <RegistryValue Type=\"string\" Value=\"&quot;[!Path]&quot; &quot;%1&quot;\" />\n                    </RegistryKey>\n                </RegistryKey>\n                {{/each~}}\n            </Component>\n            <Component Id=\"Path\" Guid=\"{{path_component_guid}}\" Win64=\"$(var.Win64)\">\n                <File Id=\"Path\" Source=\"{{main_binary_path}}\" KeyPath=\"yes\" Checksum=\"yes\"/>\n                {{#each file_associations as |association| ~}}\n                {{#each association.ext as |ext| ~}}\n                <ProgId Id=\"{{../../product_name}}.{{ext}}\" Advertise=\"yes\" Description=\"{{association.description}}\">\n                    <Extension Id=\"{{ext}}\" Advertise=\"yes\">\n                        <Verb Id=\"open\" Command=\"Open with {{../../product_name}}\" Argument=\"&quot;%1&quot;\" />\n                    </Extension>\n                </ProgId>\n                {{/each~}}\n                {{/each~}}\n            </Component>\n            {{#each binaries as |bin| ~}}\n            <Component Id=\"{{ bin.id }}\" Guid=\"{{bin.guid}}\" Win64=\"$(var.Win64)\">\n                <File Id=\"Bin_{{ bin.id }}\" Source=\"{{bin.path}}\" KeyPath=\"yes\"/>\n            </Component>\n            {{/each~}}\n            {{#if enable_elevated_update_task}}\n            <Component Id=\"UpdateTask\" Guid=\"C492327D-9720-4CD5-8DB8-F09082AF44BE\" Win64=\"$(var.Win64)\">\n                <File Id=\"UpdateTask\" Source=\"update.xml\" KeyPath=\"yes\" Checksum=\"yes\"/>\n            </Component>\n            <Component Id=\"UpdateTaskInstaller\" Guid=\"011F25ED-9BE3-50A7-9E9B-3519ED2B9932\" Win64=\"$(var.Win64)\">\n                <File Id=\"UpdateTaskInstaller\" Source=\"install-task.ps1\" KeyPath=\"yes\" Checksum=\"yes\"/>\n            </Component>\n            <Component Id=\"UpdateTaskUninstaller\" Guid=\"D4F6CC3F-32DC-5FD0-95E8-782FFD7BBCE1\" Win64=\"$(var.Win64)\">\n                <File Id=\"UpdateTaskUninstaller\" Source=\"uninstall-task.ps1\" KeyPath=\"yes\" Checksum=\"yes\"/>\n            </Component>\n            {{/if}}\n            {{resources}}\n            <Component Id=\"CMP_UninstallShortcut\" Guid=\"*\">\n\n                <Shortcut Id=\"UninstallShortcut\"\n\t\t\t\t\t\t  Name=\"Uninstall {{product_name}}\"\n\t\t\t\t\t\t  Description=\"Uninstalls {{product_name}}\"\n\t\t\t\t\t\t  Target=\"[System64Folder]msiexec.exe\"\n\t\t\t\t\t\t  Arguments=\"/x [ProductCode]\" />\n\n\t\t\t\t<RemoveFolder Id=\"INSTALLDIR\"\n\t\t\t\t\t\t\t  On=\"uninstall\" />\n\n\t\t\t\t<RegistryValue Root=\"HKCU\"\n\t\t\t\t\t\t\t   Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\"\n\t\t\t\t\t\t\t   Name=\"Uninstaller Shortcut\"\n\t\t\t\t\t\t\t   Type=\"integer\"\n\t\t\t\t\t\t\t   Value=\"1\"\n\t\t\t\t\t\t\t   KeyPath=\"yes\" />\n            </Component>\n        </DirectoryRef>\n\n        <DirectoryRef Id=\"ApplicationProgramsFolder\">\n            <Component Id=\"ApplicationShortcut\" Guid=\"*\">\n                <Shortcut Id=\"ApplicationStartMenuShortcut\"\n                    Name=\"{{product_name}}\"\n                    Description=\"Runs {{product_name}}\"\n                    Target=\"[!Path]\"\n                    Icon=\"ProductIcon\"\n                    WorkingDirectory=\"INSTALLDIR\">\n                    <ShortcutProperty Key=\"System.AppUserModel.ID\" Value=\"{{bundle_id}}\"/>\n                </Shortcut>\n                <RemoveFolder Id=\"ApplicationProgramsFolder\" On=\"uninstall\"/>\n                <RegistryValue Root=\"HKCU\" Key=\"Software\\\\{{manufacturer}}\\\\{{product_name}}\" Name=\"Start Menu Shortcut\" Type=\"integer\" Value=\"1\" KeyPath=\"yes\"/>\n           </Component>\n        </DirectoryRef>\n\n        {{#each merge_modules as |msm| ~}}\n        <DirectoryRef Id=\"TARGETDIR\">\n            <Merge Id=\"{{ msm.name }}\" SourceFile=\"{{ msm.path }}\" DiskId=\"1\" Language=\"!(loc.TauriLanguage)\" />\n        </DirectoryRef>\n\n        <Feature Id=\"{{ msm.name }}\" Title=\"{{ msm.name }}\" AllowAdvertise=\"no\" Display=\"hidden\" Level=\"1\">\n            <MergeRef Id=\"{{ msm.name }}\"/>\n        </Feature>\n        {{/each~}}\n\n        <Feature\n                Id=\"MainProgram\"\n                Title=\"Application\"\n                Description=\"!(loc.InstallAppFeature)\"\n                Level=\"1\"\n                ConfigurableDirectory=\"INSTALLDIR\"\n                AllowAdvertise=\"no\"\n                Display=\"expand\"\n                Absent=\"disallow\">\n\n            <ComponentRef Id=\"RegistryEntries\"/>\n\n            {{#each resource_file_ids as |resource_file_id| ~}}\n                <ComponentRef Id=\"{{ resource_file_id }}\"/>\n            {{/each~}}\n\n            {{#if enable_elevated_update_task}}\n                <ComponentRef Id=\"UpdateTask\" />\n                <ComponentRef Id=\"UpdateTaskInstaller\" />\n                <ComponentRef Id=\"UpdateTaskUninstaller\" />\n            {{/if}}\n\n            <Feature Id=\"ShortcutsFeature\"\n                Title=\"Shortcuts\"\n                Level=\"1\">\n                <ComponentRef Id=\"Path\"/>\n                <ComponentRef Id=\"CMP_UninstallShortcut\" />\n                <ComponentRef Id=\"ApplicationShortcut\" />\n                <ComponentRef Id=\"ApplicationShortcutDesktop\" />\n            </Feature>\n\n            <Feature\n                Id=\"Environment\"\n                Title=\"PATH Environment Variable\"\n                Description=\"!(loc.PathEnvVarFeature)\"\n                Level=\"1\"\n                Absent=\"allow\">\n            <ComponentRef Id=\"Path\"/>\n            {{#each binaries as |bin| ~}}\n            <ComponentRef Id=\"{{ bin.id }}\"/>\n            {{/each~}}\n            </Feature>\n        </Feature>\n\n        <Feature Id=\"External\" AllowAdvertise=\"no\" Absent=\"disallow\">\n            {{#each component_group_refs as |id| ~}}\n            <ComponentGroupRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each component_refs as |id| ~}}\n            <ComponentRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each feature_group_refs as |id| ~}}\n            <FeatureGroupRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each feature_refs as |id| ~}}\n            <FeatureRef Id=\"{{ id }}\"/>\n            {{/each~}}\n            {{#each merge_refs as |id| ~}}\n            <MergeRef Id=\"{{ id }}\"/>\n            {{/each~}}\n        </Feature>\n\n        {{#if install_webview}}\n        <!-- WebView2 -->\n        <Property Id=\"WVRTINSTALLED\">\n            <RegistrySearch Id=\"WVRTInstalledSystem\" Root=\"HKLM\" Key=\"SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}\" Name=\"pv\" Type=\"raw\" Win64=\"no\" />\n            <RegistrySearch Id=\"WVRTInstalledUser\" Root=\"HKCU\" Key=\"SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}\" Name=\"pv\" Type=\"raw\"/>\n        </Property>\n\n        {{#if download_bootstrapper}}\n        <CustomAction Id='DownloadAndInvokeBootstrapper' Directory=\"INSTALLDIR\" Execute=\"deferred\" ExeCommand='powershell.exe -NoProfile -windowstyle hidden try [\\{] [\\[]Net.ServicePointManager[\\]]::SecurityProtocol = [\\[]Net.SecurityProtocolType[\\]]::Tls12 [\\}] catch [\\{][\\}]; Invoke-WebRequest -Uri \"https://go.microsoft.com/fwlink/p/?LinkId=2124703\" -OutFile \"$env:TEMP\\MicrosoftEdgeWebview2Setup.exe\" ; Start-Process -FilePath \"$env:TEMP\\MicrosoftEdgeWebview2Setup.exe\" -ArgumentList ({{webview_installer_args}} &apos;/install&apos;) -Wait' Return='check'/>\n        <InstallExecuteSequence>\n            <Custom Action='DownloadAndInvokeBootstrapper' Before='InstallFinalize'>\n                <![CDATA[NOT(REMOVE OR WVRTINSTALLED)]]>\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        <!-- Embedded webview bootstrapper mode -->\n        {{#if webview2_bootstrapper_path}}\n        <Binary Id=\"MicrosoftEdgeWebview2Setup.exe\" SourceFile=\"{{webview2_bootstrapper_path}}\"/>\n        <CustomAction Id='InvokeBootstrapper' BinaryKey='MicrosoftEdgeWebview2Setup.exe' Execute=\"deferred\" ExeCommand='{{webview_installer_args}} /install' Return='check' />\n        <InstallExecuteSequence>\n            <Custom Action='InvokeBootstrapper' Before='InstallFinalize'>\n                <![CDATA[NOT(REMOVE OR WVRTINSTALLED)]]>\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        <!-- Embedded offline installer -->\n        {{#if webview2_installer_path}}\n        <Binary Id=\"MicrosoftEdgeWebView2RuntimeInstaller.exe\" SourceFile=\"{{webview2_installer_path}}\"/>\n        <CustomAction Id='InvokeStandalone' BinaryKey='MicrosoftEdgeWebView2RuntimeInstaller.exe' Execute=\"deferred\" ExeCommand='{{webview_installer_args}} /install' Return='check' />\n        <InstallExecuteSequence>\n            <Custom Action='InvokeStandalone' Before='InstallFinalize'>\n                <![CDATA[NOT(REMOVE OR WVRTINSTALLED)]]>\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        {{/if}}\n\n        {{#if enable_elevated_update_task}}\n        <!-- Install an elevated update task within Windows Task Scheduler -->\n        <CustomAction\n            Id=\"CreateUpdateTask\"\n            Return=\"check\"\n            Directory=\"INSTALLDIR\"\n            Execute=\"commit\"\n            Impersonate=\"yes\"\n            ExeCommand=\"powershell.exe -WindowStyle hidden .\\install-task.ps1\" />\n        <InstallExecuteSequence>\n            <Custom Action='CreateUpdateTask' Before='InstallFinalize'>\n                NOT(REMOVE)\n            </Custom>\n        </InstallExecuteSequence>\n        <!-- Remove elevated update task during uninstall -->\n        <CustomAction\n            Id=\"DeleteUpdateTask\"\n            Return=\"check\"\n            Directory=\"INSTALLDIR\"\n            ExeCommand=\"powershell.exe -WindowStyle hidden .\\uninstall-task.ps1\" />\n        <InstallExecuteSequence>\n            <Custom Action=\"DeleteUpdateTask\" Before='InstallFinalize'>\n                (REMOVE = \"ALL\") AND NOT UPGRADINGPRODUCTCODE\n            </Custom>\n        </InstallExecuteSequence>\n        {{/if}}\n\n        <InstallExecuteSequence>\n          <Custom Action=\"LaunchApplication\" After=\"InstallFinalize\">AUTOLAUNCHAPP AND NOT Installed</Custom>\n        </InstallExecuteSequence>\n\n        <SetProperty Id=\"ARPINSTALLLOCATION\" Value=\"[INSTALLDIR]\" After=\"CostFinalize\"/>\n    </Product>\n</Wix>"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/wix/migration.wxs",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n\t<Fragment>\n\n\t  <!-- Load the VBscript -->\n    <Binary Id=\"Migration.vbs\" SourceFile=\"..\\..\\..\\..\\templates\\wix\\Migration.vbs\" />\n\n    <!-- VBscript script to copy the files from the old installation -->\n    <CustomAction\n      Id=\"Migration\"\n      VBScriptCall=\"\"\n      BinaryKey=\"Migration.vbs\"\n      Return=\"check\"\n      Impersonate=\"no\"\n      Execute=\"deferred\"\n       />\n\n\t  <!-- This passes the path to CommonAppDataFolder path (usually \"C:\\ProgramData\\\") to the vbscirt custom action -->\n    <CustomAction Id=\"MigrationPropertySet\" Property=\"Migration\" Value=\"[CommonAppDataFolder], [ProgramMenuFolder], [StartupFolder], [AppDataFolder]\" />\n\n    <!-- Check if service is running -->\n    <InstallExecuteSequence>\n      <Custom Action=\"MigrationPropertySet\" Before=\"Migration\">NOT(REMOVE)</Custom>\n      <Custom Action=\"Migration\" Before=\"InstallFinalize\">NOT(REMOVE)</Custom>\n    </InstallExecuteSequence>\n\n\t</Fragment>\n</Wix>\n"
  },
  {
    "path": "desktop/tauri/src-tauri/templates/wix/old_service_check.wxs",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n\t<Fragment>\n\t  <!-- Load the VBscript -->\n    <Binary Id=\"CheckServiceStatusScript\" SourceFile=\"..\\..\\..\\..\\templates\\wix\\CheckServiceStatus.vbs\" />\n\n    <!-- VBscript script custom action to check if the service is running -->\n    <CustomAction\n      Id=\"CheckServiceStatus\"\n      VBScriptCall=\"\"\n      BinaryKey=\"CheckServiceStatusScript\"\n      Return=\"check\" />\n\n    <!-- Check if service is running -->\n    <InstallExecuteSequence>\n      <Custom Action=\"CheckServiceStatus\" Before=\"InstallInitialize\">NOT(REMOVE)</Custom>\n    </InstallExecuteSequence>\n\n\t</Fragment>\n</Wix>\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/safing/portmaster\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/VictoriaMetrics/metrics v1.40.2\n\tgithub.com/Xuanwo/go-locale v1.1.3\n\tgithub.com/aarondl/opt v0.0.0-20250607033636-982744e1bd65\n\tgithub.com/aead/serpent v0.0.0-20160714141033-fba169763ea6\n\tgithub.com/agext/levenshtein v1.2.3\n\tgithub.com/armon/go-radix v1.0.0\n\tgithub.com/awalterschulze/gographviz v2.0.3+incompatible\n\tgithub.com/bluele/gcache v0.0.2\n\tgithub.com/brianvoe/gofakeit v3.18.0+incompatible\n\tgithub.com/cilium/ebpf v0.20.0\n\tgithub.com/coreos/go-iptables v0.8.0\n\tgithub.com/davecgh/go-spew v1.1.1\n\tgithub.com/dgraph-io/badger v1.6.2\n\tgithub.com/florianl/go-conntrack v0.4.0\n\tgithub.com/florianl/go-nfqueue v1.3.2\n\tgithub.com/fogleman/gg v1.3.0\n\tgithub.com/ghodss/yaml v1.0.0\n\tgithub.com/gobwas/glob v0.2.3\n\tgithub.com/godbus/dbus/v5 v5.1.0\n\tgithub.com/gofrs/uuid v4.4.0+incompatible\n\tgithub.com/google/gopacket v1.1.19\n\tgithub.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510\n\tgithub.com/gorilla/mux v1.8.1\n\tgithub.com/gorilla/websocket v1.5.3\n\tgithub.com/hashicorp/go-multierror v1.1.1\n\tgithub.com/hashicorp/go-version v1.7.0\n\tgithub.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb\n\tgithub.com/ivpn/desktop-app/daemon/protocol/ivpnclient v0.0.0-20260310125040-62c0e3e2eca6\n\tgithub.com/jackc/puddle/v2 v2.2.2\n\tgithub.com/jaswdr/faker/v2 v2.9.0\n\tgithub.com/lmittmann/tint v1.1.2\n\tgithub.com/maruel/panicparse/v2 v2.5.0\n\tgithub.com/mattn/go-colorable v0.1.14\n\tgithub.com/mattn/go-isatty v0.0.20\n\tgithub.com/miekg/dns v1.1.68\n\tgithub.com/mitchellh/copystructure v1.2.0\n\tgithub.com/mitchellh/go-server-timing v1.0.1\n\tgithub.com/mr-tron/base58 v1.2.0\n\tgithub.com/oschwald/maxminddb-golang v1.13.1\n\tgithub.com/r3labs/diff/v3 v3.0.2\n\tgithub.com/rot256/pblind v0.0.0-20250826112722-8244c3966ed3\n\tgithub.com/rubenv/sql-migrate v1.8.0\n\tgithub.com/safing/jess v0.3.5\n\tgithub.com/safing/structures v1.2.0\n\tgithub.com/seehuhn/fortuna v1.0.2\n\tgithub.com/shirou/gopsutil v3.21.11+incompatible\n\tgithub.com/simukti/sqldb-logger v0.0.0-20230108155151-646c1a075551\n\tgithub.com/spf13/cobra v1.10.1\n\tgithub.com/spkg/zipfs v0.7.1\n\tgithub.com/stephenafamo/bob v0.41.1\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/tannerryan/ring v1.1.2\n\tgithub.com/tc-hib/winres v0.3.1\n\tgithub.com/tevino/abool v1.2.0\n\tgithub.com/tidwall/gjson v1.18.0\n\tgithub.com/tidwall/sjson v1.2.5\n\tgithub.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26\n\tgithub.com/varlink/go v0.4.0\n\tgithub.com/vincent-petithory/dataurl v1.0.0\n\tgo.etcd.io/bbolt v1.4.3\n\tgolang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546\n\tgolang.org/x/image v0.33.0\n\tgolang.org/x/net v0.49.0\n\tgolang.org/x/sync v0.19.0\n\tgolang.org/x/sys v0.41.0\n\tgopkg.in/yaml.v3 v3.0.1\n\tmodernc.org/sqlite v1.40.0\n\tzombiezen.com/go/sqlite v1.4.2\n)\n\nrequire (\n\tal.essio.dev/pkg/shellescape v1.6.0 // indirect\n\tdario.cat/mergo v1.0.1 // indirect\n\tgithub.com/antlr4-go/antlr/v4 v4.13.1 // indirect\n\tgithub.com/sergeymakinen/go-bmp v1.0.0 // indirect\n\tgithub.com/stephenafamo/sqlparser v0.0.0-20250521201114-5cfed001272d // indirect\n)\n\nrequire (\n\tfilippo.io/edwards25519 v1.1.0 // indirect\n\tgithub.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect\n\tgithub.com/Masterminds/goutils v1.1.1 // indirect\n\tgithub.com/Masterminds/semver/v3 v3.3.0 // indirect\n\tgithub.com/Masterminds/sprig/v3 v3.3.0 // indirect\n\tgithub.com/aead/ecdh v0.2.0 // indirect\n\tgithub.com/bgentry/speakeasy v0.1.0 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect\n\tgithub.com/danieljoos/wincred v1.2.3 // indirect\n\tgithub.com/denisenkom/go-mssqldb v0.9.0 // indirect\n\tgithub.com/dgraph-io/ristretto v0.2.0 // indirect\n\tgithub.com/dustin/go-humanize v1.0.1 // indirect\n\tgithub.com/fatih/color v1.13.0 // indirect\n\tgithub.com/felixge/httpsnoop v1.0.4 // indirect\n\tgithub.com/fsnotify/fsnotify v1.6.0 // indirect\n\tgithub.com/fxamacker/cbor/v2 v2.9.0 // indirect\n\tgithub.com/go-gorp/gorp/v3 v3.1.0 // indirect\n\tgithub.com/go-logfmt/logfmt v0.6.0 // indirect\n\tgithub.com/go-ole/go-ole v1.3.0 // indirect\n\tgithub.com/go-sql-driver/mysql v1.7.2-0.20231213112541-0004702b931d // indirect\n\tgithub.com/go-viper/mapstructure/v2 v2.4.0 // indirect\n\tgithub.com/godror/godror v0.40.4 // indirect\n\tgithub.com/godror/knownpb v0.1.1 // indirect\n\tgithub.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect\n\tgithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect\n\tgithub.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/huandu/xstrings v1.5.0 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.3.0 // indirect\n\tgithub.com/knadh/koanf/maps v0.1.1 // indirect\n\tgithub.com/knadh/koanf/parsers/yaml v0.1.0 // indirect\n\tgithub.com/knadh/koanf/providers/confmap v0.1.0 // indirect\n\tgithub.com/knadh/koanf/providers/env v0.1.0 // indirect\n\tgithub.com/knadh/koanf/providers/file v0.1.0 // indirect\n\tgithub.com/knadh/koanf/v2 v2.1.0 // indirect\n\tgithub.com/lib/pq v1.10.9 // indirect\n\tgithub.com/mattn/go-oci8 v0.1.1 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.9 // indirect\n\tgithub.com/mattn/go-sqlite3 v1.14.19 // indirect\n\tgithub.com/mdlayher/netlink v1.8.0 // indirect\n\tgithub.com/mdlayher/socket v0.5.1 // indirect\n\tgithub.com/mitchellh/cli v1.1.5 // indirect\n\tgithub.com/mitchellh/reflectwalk v1.0.2 // indirect\n\tgithub.com/ncruces/go-strftime v1.0.0 // indirect\n\tgithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect\n\tgithub.com/olekukonko/tablewriter v0.0.5 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/posener/complete v1.2.3 // indirect\n\tgithub.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 // indirect\n\tgithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect\n\tgithub.com/russross/blackfriday/v2 v2.1.0 // indirect\n\tgithub.com/satori/go.uuid v1.2.0 // indirect\n\tgithub.com/seehuhn/sha256d v1.0.0 // indirect\n\tgithub.com/sergeymakinen/go-ico v1.0.0\n\tgithub.com/shopspring/decimal v1.4.0 // indirect\n\tgithub.com/spf13/cast v1.7.0 // indirect\n\tgithub.com/spf13/pflag v1.0.10 // indirect\n\tgithub.com/stephenafamo/scan v0.7.0 // indirect\n\tgithub.com/tidwall/match v1.2.0 // indirect\n\tgithub.com/tidwall/pretty v1.2.1 // indirect\n\tgithub.com/tklauser/go-sysconf v0.3.15 // indirect\n\tgithub.com/tklauser/numcpus v0.10.0 // indirect\n\tgithub.com/urfave/cli/v2 v2.23.7 // indirect\n\tgithub.com/valyala/fastrand v1.1.0 // indirect\n\tgithub.com/valyala/histogram v1.2.0 // indirect\n\tgithub.com/vmihailenco/msgpack/v5 v5.4.1 // indirect\n\tgithub.com/vmihailenco/tagparser/v2 v2.0.0 // indirect\n\tgithub.com/volatiletech/inflect v0.0.1 // indirect\n\tgithub.com/volatiletech/strmangle v0.0.6 // indirect\n\tgithub.com/x448/float16 v0.8.4 // indirect\n\tgithub.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect\n\tgithub.com/yusufpapurcu/wmi v1.2.4 // indirect\n\tgithub.com/zalando/go-keyring v0.2.6 // indirect\n\tgithub.com/zeebo/blake3 v0.2.4 // indirect\n\tgolang.org/x/crypto v0.48.0 // indirect\n\tgolang.org/x/mod v0.32.0 // indirect\n\tgolang.org/x/text v0.34.0 // indirect\n\tgolang.org/x/tools v0.41.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.10 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tmodernc.org/libc v1.66.10 // indirect\n\tmodernc.org/mathutil v1.7.1 // indirect\n\tmodernc.org/memory v1.11.0 // indirect\n\tmvdan.cc/gofumpt v0.7.0 // indirect\n)\n\ntool (\n\tgithub.com/rubenv/sql-migrate/sql-migrate\n\tgithub.com/stephenafamo/bob/gen/bobgen-sqlite\n)\n"
  },
  {
    "path": "go.sum",
    "content": "al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA=\nal.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=\ncloud.google.com/go v0.16.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ndario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=\ndario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=\nfilippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=\nfilippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=\ngithub.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=\ngithub.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=\ngithub.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=\ngithub.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=\ngithub.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=\ngithub.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=\ngithub.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=\ngithub.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=\ngithub.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=\ngithub.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=\ngithub.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/UNO-SOFT/zlog v0.8.1 h1:TEFkGJHtUfTRgMkLZiAjLSHALjwSBdw6/zByMC5GJt4=\ngithub.com/UNO-SOFT/zlog v0.8.1/go.mod h1:yqFOjn3OhvJ4j7ArJqQNA+9V+u6t9zSAyIZdWdMweWc=\ngithub.com/VictoriaMetrics/metrics v1.40.2 h1:OVSjKcQEx6JAwGeu8/KQm9Su5qJ72TMEW4xYn5vw3Ac=\ngithub.com/VictoriaMetrics/metrics v1.40.2/go.mod h1:XE4uudAAIRaJE614Tl5HMrtoEU6+GDZO4QTnNSsZRuA=\ngithub.com/Xuanwo/go-locale v1.1.3 h1:EWZZJJt5rqPHHbqPRH1zFCn5D7xHjjebODctA4aUO3A=\ngithub.com/Xuanwo/go-locale v1.1.3/go.mod h1:REn+F/c+AtGSWYACBSYZgl23AP+0lfQC+SEFPN+hj30=\ngithub.com/aarondl/opt v0.0.0-20250607033636-982744e1bd65 h1:lbdPe4LBNmNDzeQFwNhEc88w90841qv737MI4+aXSYU=\ngithub.com/aarondl/opt v0.0.0-20250607033636-982744e1bd65/go.mod h1:+xKBXrTAUOvrDXO5PRwIr4E1wciHY3Glgl+6OkCXknU=\ngithub.com/aead/ecdh v0.2.0 h1:pYop54xVaq/CEREFEcukHRZfTdjiWvYIsZDXXrBapQQ=\ngithub.com/aead/ecdh v0.2.0/go.mod h1:a9HHtXuSo8J1Js1MwLQx2mBhkXMT6YwUmVVEY4tTB8U=\ngithub.com/aead/serpent v0.0.0-20160714141033-fba169763ea6 h1:5L8Mj9Co9sJVgW3TpYk2gxGJnDjsYuboNTcRmbtGKGs=\ngithub.com/aead/serpent v0.0.0-20160714141033-fba169763ea6/go.mod h1:3HgLJ9d18kXMLQlJvIY3+FszZYMxCz8WfE2MQ7hDY0w=\ngithub.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=\ngithub.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=\ngithub.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=\ngithub.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=\ngithub.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=\ngithub.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=\ngithub.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=\ngithub.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=\ngithub.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=\ngithub.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8=\ngithub.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc=\ngithub.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=\ngithub.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=\ngithub.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=\ngithub.com/cilium/ebpf v0.20.0 h1:atwWj9d3NffHyPZzVlx3hmw1on5CLe9eljR8VuHTwhM=\ngithub.com/cilium/ebpf v0.20.0/go.mod h1:pzLjFymM+uZPLk/IXZUL63xdx5VXEo+enTzxkZXdycw=\ngithub.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=\ngithub.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=\ngithub.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=\ngithub.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=\ngithub.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=\ngithub.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=\ngithub.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=\ngithub.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=\ngithub.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=\ngithub.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=\ngithub.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=\ngithub.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc=\ngithub.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=\ngithub.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=\ngithub.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=\ngithub.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=\ngithub.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=\ngithub.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=\ngithub.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=\ngithub.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=\ngithub.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=\ngithub.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=\ngithub.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=\ngithub.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=\ngithub.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=\ngithub.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=\ngithub.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=\ngithub.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=\ngithub.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=\ngithub.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=\ngithub.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/felixge/httpsnoop v1.0.0/go.mod h1:3+D9sFq0ahK/JeJPhCBUV1xlf4/eIYrUQaxulT0VzX8=\ngithub.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=\ngithub.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18=\ngithub.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8=\ngithub.com/florianl/go-nfqueue v1.3.2 h1:8DPzhKJHywpHJAE/4ktgcqveCL7qmMLsEsVD68C4x4I=\ngithub.com/florianl/go-nfqueue v1.3.2/go.mod h1:eSnAor2YCfMCVYrVNEhkLGN/r1L+J4uDjc0EUy0tfq4=\ngithub.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=\ngithub.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk=\ngithub.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI=\ngithub.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=\ngithub.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=\ngithub.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=\ngithub.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=\ngithub.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=\ngithub.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=\ngithub.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=\ngithub.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=\ngithub.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=\ngithub.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=\ngithub.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=\ngithub.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=\ngithub.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=\ngithub.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s=\ngithub.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI=\ngithub.com/go-sql-driver/mysql v1.7.2-0.20231213112541-0004702b931d h1:QQP1nE4qh5aHTGvI1LgOFxZYVxYoGeMfbNHikogPyoA=\ngithub.com/go-sql-driver/mysql v1.7.2-0.20231213112541-0004702b931d/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=\ngithub.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=\ngithub.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=\ngithub.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=\ngithub.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=\ngithub.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=\ngithub.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/godror/godror v0.40.4 h1:X1e7hUd02GDaLWKZj40Z7L0CP0W9TrGgmPQZw6+anBg=\ngithub.com/godror/godror v0.40.4/go.mod h1:i8YtVTHUJKfFT3wTat4A9UoqScUtZXiYB9Rf3SVARgc=\ngithub.com/godror/knownpb v0.1.1 h1:A4J7jdx7jWBhJm18NntafzSC//iZDHkDi1+juwQ5pTI=\ngithub.com/godror/knownpb v0.1.1/go.mod h1:4nRFbQo1dDuwKnblRXDxrfCFYeT4hjg3GjMqef58eRE=\ngithub.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=\ngithub.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=\ngithub.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=\ngithub.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=\ngithub.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg=\ngithub.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4=\ngithub.com/golang/lint v0.0.0-20170918230701-e5d664eb928e/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=\ngithub.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=\ngithub.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=\ngithub.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=\ngithub.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=\ngithub.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=\ngithub.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=\ngithub.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=\ngithub.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=\ngithub.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb h1:PGufWXXDq9yaev6xX1YQauaO1MV90e6Mpoq1I7Lz/VM=\ngithub.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E=\ngithub.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=\ngithub.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=\ngithub.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/ivpn/desktop-app/daemon/protocol/ivpnclient v0.0.0-20260310125040-62c0e3e2eca6 h1:7rX8Ci6YSrA6TkB9BVQiM0YyA2WU5Wa9q2f1YFFImPQ=\ngithub.com/ivpn/desktop-app/daemon/protocol/ivpnclient v0.0.0-20260310125040-62c0e3e2eca6/go.mod h1:dvedOGgEXvFCK/gz+BJQhd5BSTQvIygmOr/22xPdgIw=\ngithub.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=\ngithub.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=\ngithub.com/jaswdr/faker/v2 v2.9.0 h1:Sqqpp+pxduDO+MGOhYE3UHtI9Sowt9j95f8h8nVvips=\ngithub.com/jaswdr/faker/v2 v2.9.0/go.mod h1:jZq+qzNQr8/P+5fHd9t3txe2GNPnthrTfohtnJ7B+68=\ngithub.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786 h1:N527AHMa793TP5z5GNAn/VLPzlc0ewzWdeP/25gDfgQ=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs=\ngithub.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM=\ngithub.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=\ngithub.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=\ngithub.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=\ngithub.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=\ngithub.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=\ngithub.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=\ngithub.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=\ngithub.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w=\ngithub.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=\ngithub.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU=\ngithub.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU=\ngithub.com/knadh/koanf/providers/env v0.1.0 h1:LqKteXqfOWyx5Ab9VfGHmjY9BvRXi+clwyZozgVRiKg=\ngithub.com/knadh/koanf/providers/env v0.1.0/go.mod h1:RE8K9GbACJkeEnkl8L/Qcj8p4ZyPXZIQ191HJi44ZaQ=\ngithub.com/knadh/koanf/providers/file v0.1.0 h1:fs6U7nrV58d3CFAFh8VTde8TM262ObYf3ODrc//Lp+c=\ngithub.com/knadh/koanf/providers/file v0.1.0/go.mod h1:rjJ/nHQl64iYCtAW2QQnF0eSmDEX/YZ/eNFj5yR6BvA=\ngithub.com/knadh/koanf/v2 v2.1.0 h1:eh4QmHHBuU8BybfIJ8mB8K8gsGCD/AUQTdwGq/GzId8=\ngithub.com/knadh/koanf/v2 v2.1.0/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=\ngithub.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=\ngithub.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=\ngithub.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=\ngithub.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=\ngithub.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/maruel/panicparse/v2 v2.5.0 h1:yCtuS0FWjfd0RTYMXGpDvWcb0kINm8xJGu18/xMUh00=\ngithub.com/maruel/panicparse/v2 v2.5.0/go.mod h1:DA2fDiBk63bKfBf4CVZP9gb4fuvzdPbLDsSI873hweQ=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-oci8 v0.1.1 h1:aEUDxNAyDG0tv8CA3TArnDQNyc4EhnWlsfxRgDHABHM=\ngithub.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=\ngithub.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=\ngithub.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=\ngithub.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=\ngithub.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE=\ngithub.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=\ngithub.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=\ngithub.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=\ngithub.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=\ngithub.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=\ngithub.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=\ngithub.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=\ngithub.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=\ngithub.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=\ngithub.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=\ngithub.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q=\ngithub.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ=\ngithub.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=\ngithub.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5YyvvlM=\ngithub.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594=\ngithub.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc=\ngithub.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g=\ngithub.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=\ngithub.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=\ngithub.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=\ngithub.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=\ngithub.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=\ngithub.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=\ngithub.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng=\ngithub.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=\ngithub.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=\ngithub.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=\ngithub.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-server-timing v1.0.1 h1:f00/aIe8T3MrnLhQHu3tSWvnwc5GV/p5eutuu3hF/tE=\ngithub.com/mitchellh/go-server-timing v1.0.1/go.mod h1:Mo6GKi9FSLwWFAMn3bqVPWe20y5ri5QGQuO9D9MCOxk=\ngithub.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=\ngithub.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=\ngithub.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=\ngithub.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=\ngithub.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=\ngithub.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=\ngithub.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=\ngithub.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=\ngithub.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=\ngithub.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=\ngithub.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=\ngithub.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=\ngithub.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=\ngithub.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=\ngithub.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=\ngithub.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=\ngithub.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=\ngithub.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=\ngithub.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=\ngithub.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=\ngithub.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=\ngithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=\ngithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=\ngithub.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE=\ngithub.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=\ngithub.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=\ngithub.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=\ngithub.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=\ngithub.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=\ngithub.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=\ngithub.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=\ngithub.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=\ngithub.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=\ngithub.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=\ngithub.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=\ngithub.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=\ngithub.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=\ngithub.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=\ngithub.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=\ngithub.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=\ngithub.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=\ngithub.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc=\ngithub.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4=\ngithub.com/r3labs/diff/v3 v3.0.2 h1:yVuxAY1V6MeM4+HNur92xkS39kB/N+cFi2hMkY06BbA=\ngithub.com/r3labs/diff/v3 v3.0.2/go.mod h1:Cy542hv0BAEmhDYWtGxXRQ4kqRsVIcEjG9gChUlTmkw=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=\ngithub.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=\ngithub.com/rot256/pblind v0.0.0-20250826112722-8244c3966ed3 h1:ymYWkLrwKuEaatWZboGryvjZnqap+9v0HX4gcozmZOo=\ngithub.com/rot256/pblind v0.0.0-20250826112722-8244c3966ed3/go.mod h1:rHhYqxx18ekqo/Y4U7dKP6/H8ZaUDY/pIHGKhq4DKxc=\ngithub.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o=\ngithub.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw=\ngithub.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=\ngithub.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/safing/jess v0.3.5 h1:KS5elTKfWcDUow8SUoCj5QdyyGJNoExJNySerNkbxUU=\ngithub.com/safing/jess v0.3.5/go.mod h1:+B6UJnXVxi406Wk08SDnoC5NNBL7t3N0vZGokEbkVQI=\ngithub.com/safing/structures v1.2.0 h1:S6EzKxxGYTO6P9P3Dkab9gisLOrfAyvy7JzFOUSkOUk=\ngithub.com/safing/structures v1.2.0/go.mod h1:zIun7mz3xV0dJ3vXRZuU71ATzT8D/0hGJO+u+bk5Kvs=\ngithub.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=\ngithub.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=\ngithub.com/seehuhn/fortuna v1.0.2 h1:eU/UhTlFVpK/IuSiTlWyZY/S39Lbye+jjZdzNADHYEc=\ngithub.com/seehuhn/fortuna v1.0.2/go.mod h1:LX8ubejCnUoT/hX+1aKUtbKls2H6DRkqzkc7TdR3iis=\ngithub.com/seehuhn/sha256d v1.0.0 h1:TXTsAuEWr02QjRm153Fnvvb6fXXDo7Bmy1FizxarGYw=\ngithub.com/seehuhn/sha256d v1.0.0/go.mod h1:PEuxg9faClSveVuFXacQmi+NtDI/PX8bpKjtNzf2+s4=\ngithub.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=\ngithub.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=\ngithub.com/sergeymakinen/go-ico v1.0.0 h1:uL3khgvKkY6WfAetA+RqsguClBuu7HpvBB/nq/Jvr80=\ngithub.com/sergeymakinen/go-ico v1.0.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk=\ngithub.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=\ngithub.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=\ngithub.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=\ngithub.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=\ngithub.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=\ngithub.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=\ngithub.com/simukti/sqldb-logger v0.0.0-20230108155151-646c1a075551 h1:+EXKKt7RC4HyE/iE8zSeFL+7YBL8Z7vpBaEE3c7lCnk=\ngithub.com/simukti/sqldb-logger v0.0.0-20230108155151-646c1a075551/go.mod h1:ztTX0ctjRZ1wn9OXrzhonvNmv43yjFUXJYJR95JQAJE=\ngithub.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=\ngithub.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=\ngithub.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=\ngithub.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=\ngithub.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=\ngithub.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=\ngithub.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=\ngithub.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=\ngithub.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=\ngithub.com/spkg/zipfs v0.7.1 h1:+2X5lvNHTybnDMQZAIHgedRXZK1WXdc+94R/P5v2XWE=\ngithub.com/spkg/zipfs v0.7.1/go.mod h1:48LW+/Rh1G7aAav1ew1PdlYn52T+LM+ARmSHfDNJvg8=\ngithub.com/stephenafamo/bob v0.41.1 h1:xcRPuRMCwtZZ9tS4JIVbZ5Erdm5Dy5dIvbS5kivwPpA=\ngithub.com/stephenafamo/bob v0.41.1/go.mod h1:8l55917DM36gF518Iz1MHjLds7KGAfkitJfxISYlth8=\ngithub.com/stephenafamo/fakedb v0.0.0-20221230081958-0b86f816ed97 h1:XItoZNmhOih06TC02jK7l3wlpZ0XT/sPQYutDcGOQjg=\ngithub.com/stephenafamo/fakedb v0.0.0-20221230081958-0b86f816ed97/go.mod h1:bM3Vmw1IakoaXocHmMIGgJFYob0vuK+CFWiJHQvz0jQ=\ngithub.com/stephenafamo/scan v0.7.0 h1:lfFiD9H5+n4AdK3qNzXQjj2M3NfTOpmWBIA39NwB94c=\ngithub.com/stephenafamo/scan v0.7.0/go.mod h1:FhIUJ8pLNyex36xGFiazDJJ5Xry0UkAi+RkWRrEcRMg=\ngithub.com/stephenafamo/sqlparser v0.0.0-20250521201114-5cfed001272d h1:YmPQh4pYOjqGWllnvJ2EoMZe1a8RgAyBrw4cH2FfabY=\ngithub.com/stephenafamo/sqlparser v0.0.0-20250521201114-5cfed001272d/go.mod h1:2ATW++wFz7Mvc/N+nUtQnU+9VIGAxrn8m9JCLDSWMsQ=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tannerryan/ring v1.1.2 h1:iXayOjqHQOLzuy9GwSKuG3nhWfzQkldMlQivcgIr7gQ=\ngithub.com/tannerryan/ring v1.1.2/go.mod h1:DkELJEjbZhJBtFKR9Xziwj3HKZnb/knRgljNqp65vH4=\ngithub.com/tc-hib/winres v0.3.1 h1:CwRjEGrKdbi5CvZ4ID+iyVhgyfatxFoizjPhzez9Io4=\ngithub.com/tc-hib/winres v0.3.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=\ngithub.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw=\ngithub.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w=\ngithub.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=\ngithub.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=\ngithub.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=\ngithub.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM=\ngithub.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=\ngithub.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=\ngithub.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=\ngithub.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=\ngithub.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=\ngithub.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=\ngithub.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=\ngithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=\ngithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=\ngithub.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=\ngithub.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 h1:UFHFmFfixpmfRBcxuu+LA9l8MdURWVdVNUHxO5n1d2w=\ngithub.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26/go.mod h1:IGhd0qMDsUa9acVjsbsT7bu3ktadtGOHI79+idTew/M=\ngithub.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY=\ngithub.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=\ngithub.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8=\ngithub.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=\ngithub.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ=\ngithub.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY=\ngithub.com/varlink/go v0.4.0 h1:+/BQoUO9eJK/+MTSHwFcJch7TMsb6N6Dqp6g0qaXXRo=\ngithub.com/varlink/go v0.4.0/go.mod h1:DKg9Y2ctoNkesREGAEak58l+jOC6JU2aqZvUYs5DynU=\ngithub.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI=\ngithub.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U=\ngithub.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=\ngithub.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=\ngithub.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU=\ngithub.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA=\ngithub.com/volatiletech/strmangle v0.0.6 h1:AdOYE3B2ygRDq4rXDij/MMwq6KVK/pWAYxpC7CLrkKQ=\ngithub.com/volatiletech/strmangle v0.0.6/go.mod h1:ycDvbDkjDvhC0NUU8w3fWwl5JEMTV56vTKXzR3GeR+0=\ngithub.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=\ngithub.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=\ngithub.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=\ngithub.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=\ngithub.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=\ngithub.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=\ngithub.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s=\ngithub.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI=\ngithub.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=\ngithub.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=\ngithub.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=\ngithub.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=\ngithub.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=\ngithub.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=\ngo.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=\ngo.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=\ngo.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=\ngo.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=\ngo.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=\ngo.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=\ngo.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=\ngo.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=\ngolang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=\ngolang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=\ngolang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=\ngolang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=\ngolang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=\ngolang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=\ngolang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=\ngolang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=\ngolang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=\ngolang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=\ngolang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=\ngolang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=\ngolang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=\ngolang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=\ngolang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=\ngolang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=\ngolang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=\ngolang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=\ngolang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngoogle.golang.org/api v0.0.0-20170921000349-586095a6e407/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=\ngoogle.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=\ngoogle.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=\nhonnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=\nmodernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4=\nmodernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=\nmodernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A=\nmodernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q=\nmodernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=\nmodernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=\nmodernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=\nmodernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=\nmodernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=\nmodernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=\nmodernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A=\nmodernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I=\nmodernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=\nmodernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=\nmodernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=\nmodernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=\nmodernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=\nmodernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=\nmodernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=\nmodernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=\nmodernc.org/sqlite v1.40.0 h1:bNWEDlYhNPAUdUdBzjAvn8icAs/2gaKlj4vM+tQ6KdQ=\nmodernc.org/sqlite v1.40.0/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=\nmodernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=\nmodernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=\nmodernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=\nmodernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=\nmvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=\nmvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=\nzombiezen.com/go/sqlite v1.4.2 h1:KZXLrBuJ7tKNEm+VJcApLMeQbhmAUOKA5VWS93DfFRo=\nzombiezen.com/go/sqlite v1.4.2/go.mod h1:5Kd4taTAD4MkBzT25mQ9uaAlLjyR0rFhsR6iINO70jc=\n"
  },
  {
    "path": "packaging/README.md",
    "content": "# Generate Windows installer\n\n## Prerequisites\n\nEarthly release prep step must be executed and the output `dist` folder should be present in the root directory of the repository. (Probably needs to be done on separate machine running linux or downloaded from the CI)\n```\n  earthly +release-prep\n```\n\n## Building the installers\n\nIn the root directory of the repository, run the PowerShell script to generate the installers:\n```\n./packaging\\windows\\generate_windows_installers.ps1\n```\n\nThis will output both .exe (NSIS) and .msi (WIX) installers inside the dist folder:\n```\n...\\Portmaster\\dist\\windows_amd64\\Portmaster_0.1.0_x64-setup.exe\n...\\Portmaster\\dist\\windows_amd64\\Portmaster_0.1.0_x64_en-US.msi\n```\n\n## Manual build\n\n### Prerequisites\n\nEnsure you have Rust and Cargo installed.\nInstall Tauri CLI by running:\n```\ncargo install tauri-cli --version \"^2.0.0\" --locked\n```\n\n### Folder structure\n\nCreate binary and intel folder inside the tauri project folder and place all the necessary files inside.\nThe folder structure should look like this:\n```\n...\\Portmaster\\desktop\\tauri\\src-tauri\\binary\n    assets.zip\n    index.json\n    portmaster-core.dll\n    portmaster-core.exe\n    portmaster-kext.dll\n    portmaster-kext.sys\n    portmaster.zip\n    WebView2Loader.dll\n\n...\\Portmaster\\desktop\\tauri\\src-tauri\\intel\n    base.dsdl\n    geoipv4.mmdb\n    geoipv6.mmdb\n    index.dsd\n    index.json\n    intermediate.dsdl\n    main-intel.yaml\n    news.yaml\n    notifications.yaml\n    urgent.dsdl\n```\n\n### Building the Installer\n\nNavigate to the `src-tauri` directory:\n```\ncd desktop/tauri/src-tauri\n```\n\nRun the following commands to build the installers:\n\nFor both NSIS and WIX installers:\n```\ncargo tauri bundle\n```\n\nFor NSIS installer only:\n```\ncargo tauri bundle --bundles nsis\n```\n\nFor WIX installer only:\n```\ncargo tauri bundle --bundles wix\n```\n\nThe produced files will be in:\n```\ntarget\\release\\bundle\\msi\\\ntarget\\release\\bundle\\nsis\\\n```\n\n## Debug MSI Installer\n\nTo see error messages during the build of the installer, run the bundler with the verbose flag:\n```\ncargo tauri bundle --bundles msi --verbose\n```\n\nTo examine the logs during installation, run the installer with the following command:\n```\nmsiexec /i \"target\\release\\bundle\\msi\\Portmaster_0.1.0_x64_en-US.msi\" /lv install.log\n```"
  },
  {
    "path": "packaging/linux/dev_helpers/build_tauri.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# This script builds the Tauri application for Portmaster on Linux.\n# It optionally builds the required Angular tauri-builtin project first.\n# The script assumes that all necessary dependencies (Node.js, Angular CLI, Rust, cargo-tauri) are installed.\n# Output file: dist/portmaster\n\n# Resolve script directory and project root\nSCRIPT_DIR=\"$(cd -- \"$(dirname -- \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_ROOT=\"$(cd -- \"${SCRIPT_DIR}/../../../\" && pwd)\"\nORIGINAL_DIR=\"$(pwd)\"\n\n# Create output directory\nOUTPUT_DIR=\"${SCRIPT_DIR}/dist\"\nmkdir -p \"${OUTPUT_DIR}\"\n\n# Helper: check for command availability\nhave() { command -v \"$1\" >/dev/null 2>&1; }\n\n# Optional: build Angular tauri-builtin\nread -r -p \"Build Angular tauri-builtin project? (Y/N, default: Y) \" REPLY\nREPLY=${REPLY:-Y}\nif [[ ! ${REPLY} =~ ^[Nn]$ ]]; then\n  # Ensure Angular CLI is available\n  if ! have ng; then\n    echo \"Error: Angular CLI 'ng' not found in PATH.\" >&2\n    echo \"Install via: npm install -g @angular/cli\" >&2\n    exit 1\n  fi\n  # Navigate to Angular project\n  pushd \"${PROJECT_ROOT}/desktop/angular\" >/dev/null\n  # Build tauri-builtin with production config\n  ng build --configuration production --base-href / tauri-builtin || {\n    popd >/dev/null\n    cd \"${ORIGINAL_DIR}\"\n    exit 1\n  }\n  popd >/dev/null\nfi\n\n# Navigate to Tauri src-tauri directory\npushd \"${PROJECT_ROOT}/desktop/tauri/src-tauri\" >/dev/null\n\n# Ensure cargo and tauri plugin are available\nif ! have cargo; then\n  echo \"Error: cargo not found. Install Rust toolchain (rustup).\" >&2\n  exit 1\nfi\nif ! cargo tauri --help >/dev/null 2>&1; then\n  echo \"Error: cargo-tauri not installed.\" >&2\n  echo \"Install via: cargo install tauri-cli\" >&2\n  popd >/dev/null\n  exit 1\nfi\n\n# Build Tauri project (no bundle)\ncargo tauri build --no-bundle\n\n# Copy built binary to dist\nTAURI_OUTPUT_DIR=\"$(pwd)/target/release\"\nif [[ -f \"${TAURI_OUTPUT_DIR}/portmaster\" ]]; then\n  cp -f \"${TAURI_OUTPUT_DIR}/portmaster\" \"${OUTPUT_DIR}/\"\n  echo \"Build completed successfully: ${OUTPUT_DIR}/portmaster\"\nelse\n  echo \"Error: Built binary not found at ${TAURI_OUTPUT_DIR}/portmaster\" >&2\n  popd >/dev/null\n  exit 1\nfi\n\n# Return to original directory\npopd >/dev/null\ncd \"${ORIGINAL_DIR}\"\n"
  },
  {
    "path": "packaging/linux/portmaster-autostart.desktop",
    "content": "[Desktop Entry]\nName=Portmaster\nGenericName=Application Firewall Notifier\nExec=/usr/bin/portmaster --with-prompts --with-notifications --background\nIcon=portmaster\nTerminal=false\nType=Application\nCategories=System\nNoDisplay=true"
  },
  {
    "path": "packaging/linux/portmaster.desktop",
    "content": "[Desktop Entry]\nName=Portmaster\nGenericName=Application Firewall\nExec={{exec}} --data=/opt/safing/portmaster --with-prompts --with-notifications \nIcon={{icon}}\nStartupWMClass=portmaster\nTerminal=false\nType=Application\nCategories=System\n"
  },
  {
    "path": "packaging/linux/portmaster.service",
    "content": "[Unit]\nDescription=Portmaster by Safing\nDocumentation=https://safing.io\nDocumentation=https://docs.safing.io\nBefore=nss-lookup.target network.target shutdown.target\nAfter=systemd-networkd.service\nConflicts=shutdown.target\nConflicts=firewalld.service\nWants=nss-lookup.target\n\n[Service]\nType=simple\nRestart=on-failure\nRestartSec=10\nRestartPreventExitStatus=24\nLockPersonality=yes\nMemoryDenyWriteExecute=yes\nMemoryLow=2G\nNoNewPrivileges=yes\nPrivateTmp=yes\nPIDFile=/var/lib/portmaster/core-lock.pid\nEnvironment=LOGLEVEL=info\nEnvironment=PORTMASTER_ARGS=\nEnvironmentFile=-/etc/default/portmaster\nProtectSystem=true\nReadWritePaths=/usr/lib/portmaster\nRestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6\nRestrictNamespaces=yes\nProtectHome=read-only\nProtectKernelTunables=yes\nProtectKernelLogs=yes\nProtectControlGroups=yes\nPrivateDevices=yes\nAmbientCapabilities=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_net_broadcast cap_net_raw cap_sys_module cap_sys_ptrace cap_dac_override cap_fowner cap_fsetid cap_sys_resource cap_bpf cap_perfmon\nCapabilityBoundingSet=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_net_broadcast cap_net_raw cap_sys_module cap_sys_ptrace cap_dac_override cap_fowner cap_fsetid cap_sys_resource cap_bpf cap_perfmon\nStateDirectory=portmaster\n# TODO(ppacher): add --disable-software-updates once it's merged and the release process changed.\nWorkingDirectory=/var/lib/portmaster\nExecStart=/usr/lib/portmaster/portmaster-core --log-dir=/var/lib/portmaster/log -- $PORTMASTER_ARGS\nExecStopPost=-/usr/lib/portmaster/portmaster-core --recover-iptables\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "packaging/linux/postinst",
    "content": "#!/bin/bash\n\necho \"[ ] Post-Install script [arg1='$1' arg2='$2']\"\n\necho \"[ ] Stopping old service (if exists)\"\nsystemctl stop portmaster.service\nsystemctl disable portmaster.service\n\n#\n# Migration from v1\n#\nOLD_INSTALLATION_DIR=\"/opt/safing/portmaster\"\nMIGRATED_FILE_FLAG=\"$OLD_INSTALLATION_DIR/migrated.txt\"\nif [ -d \"$OLD_INSTALLATION_DIR\" ]; then\n    if [ ! -e \"$MIGRATED_FILE_FLAG\" ]; then\n        echo \"[ ] Starting migration form v1 ...\"\n        \n        # Because the service file need to change path, first the links to the old service needs to be removed.\n        echo \"[ ] V1 migration: Removing old service\"\n        rm /etc/systemd/system/portmaster.service # new V2 service registered at \"/usr/lib/systemd/system/portmaster.service\"\n\n        # Migrate config\n        echo \"[ ] V1 migration: Copying V1 configuration\"\n        cp -r $OLD_INSTALLATION_DIR/databases /var/lib/portmaster\n        cp -r $OLD_INSTALLATION_DIR/config.json /var/lib/portmaster/config.json\n\n        # Remove shortcut\n        echo \"[ ] V1 migration: Removing V1 shortcuts\"\n        rm /etc/xdg/autostart/portmaster_notifier.desktop\n        rm /usr/share/applications/portmaster_notifier.desktop\n        # app V1 shortcut\n        # NOTE: new V2 shortcut registered as \"Portmaster.desktop\" (first letter uppercase), so we can distinguish between V1 and V2 shortcuts.\n        rm /usr/share/applications/portmaster.desktop \n\n        # Remove V1 files (except configuration)\n        # (keeping V1 configuration for a smooth downgrade, if needed)\n        echo \"[ ] V1 migration: Removing V1 files\"\n        rm -fr $OLD_INSTALLATION_DIR/exec\n        rm -fr $OLD_INSTALLATION_DIR/logs\n        rm -fr $OLD_INSTALLATION_DIR/updates\n        rm -fr $OLD_INSTALLATION_DIR/databases/cache\n        rm -fr $OLD_INSTALLATION_DIR/databases/icons\n        rm -fr $OLD_INSTALLATION_DIR/databases/history.db\n\n        for file in $OLD_INSTALLATION_DIR/*; do\n            if [ -f \"$file\" ] && [ \"$(basename \"$file\")\" != \"config.json\" ]; then\n                rm \"$file\"\n            fi\n        done\n\n        touch $MIGRATED_FILE_FLAG\n        echo \"[ ] Migration complete\"\n    fi\nfi\n\n#\n# Fix selinux permissions for portmaster-core if we have semanage available.\n#\nif command -V semanage >/dev/null 2>&1; then\n    echo \"[ ] Fixing SELinux permissions\"\n    semanage fcontext -a -t bin_t -s system_u $(realpath /usr/lib)'/portmaster/portmaster-core' || :\n    restorecon -R /usr/lib/portmaster/portmaster-core 2>/dev/null >&2 || :\nfi\n\necho \"[ ] Initializing binary files\"\nmv /usr/bin/portmaster /usr/lib/portmaster/portmaster\nln -s /usr/lib/portmaster/portmaster /usr/bin/portmaster \n\nchmod +x /usr/lib/portmaster/portmaster-core\n\necho \"[ ] Enabling service\"\nsystemctl daemon-reload\nsystemctl enable portmaster.service\n\necho \"[ ] Done. Please reboot your system\"\n"
  },
  {
    "path": "packaging/linux/postrm",
    "content": "#!/bin/bash\n\necho \"[ ] Post-Remove script [arg1='$1' arg2='$2']\"\n\n# DEB argument on upgrade - 'upgrade'; RPM - '1'\nif [ \"$1\" = \"upgrade\" ] || [ \"$1\" = \"1\" ] ; then\n    echo \"[ ] Post-Remove script: This is an upgrade.\"\n    exit 0\nfi\n\n#\n# Remove selinux permissions for portmaster-core if we have semanage available.\n#\nif command -V semanage >/dev/null 2>&1; then\n    echo \"[ ] Removing SELinux permissions\"\n    semanage fcontext --delete $(realpath /usr/lib)'/portmaster/portmaster-core' || :\n    restorecon -R /usr/lib/portmaster/portmaster-core 2>/dev/null >&2 || :\nfi\n\necho \"[ ] Stopping and disabling service\"\nsystemctl stop portmaster.service\nsystemctl disable portmaster.service\n\necho \"[ ] Removing files\"\n# Remove binaries folder\nsudo rm -fr /usr/lib/portmaster\n# Remove data folder\nsudo rm -fr /var/lib/portmaster\n\n# remove V1 migration flag (if exists)\nMIGRATED_FILE_FLAG=\"/opt/safing/portmaster/migrated.txt\"\nif [ -e \"$MIGRATED_FILE_FLAG\" ]; then\n    echo \"[ ] Removing V1 migration flag\"\n    rm \"$MIGRATED_FILE_FLAG\"\nfi\n"
  },
  {
    "path": "packaging/linux/readme.md",
    "content": "# Installation scripts order\n\nExecution order of installation scripts (`preInstallScript, preRemoveScript, postInstallScript, postRemoveScript`) is different for DEB and RPM packages.\n**NOTE!** 'remove' scripts is using from old version!\n\n## DEB scripts order\n\nUseful link: https://wiki.debian.org/MaintainerScripts\n```\nDEB (apt) Install v2.2.2:\n   [*] Before install (2.2.2 : deb : install)\n   [*] After  install (2.2.2 : deb : configure)\n\nDEB (apt) Upgrade v1.1.1 -> v2.2.2:\n   [*] Before remove  (1.1.1 : deb : upgrade)\n   [*] Before install (2.2.2 : deb : upgrade)\n   [*] After  remove  (1.1.1 : deb : upgrade)\n   [*] After  install (2.2.2 : deb : configure)\n\n DEB (apt) Remove:\n   [*] Before remove  (1.1.1 : deb : remove)\n   [*] After  remove  (1.1.1 : deb : remove)\n```\n\n## RPM scripts order\n\nUseful link: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/\n\nWhen scriptlets are called, they will be supplied with an argument.\nThis argument, accessed via $1 (for shell scripts) is the number of packages of this name\nwhich will be left on the system when the action completes.\n\n```\n RPM (dnf) install:\n   [*] Before install (2.2.2 : rpm : 1)\n   [*] After  install (2.2.2 : rpm : 1)\n\n RPM (dnf) upgrade:\n   [*] Before install (2.2.2 : rpm : 2)\n   [*] After  install (2.2.2 : rpm : 2)\n   [*] Before remove  (1.1.1 : rpm : 1)\n   [*] After  remove  (1.1.1 : rpm : 1)\n\n RPM (dnf) remove:\n   [*] Before remove  (2.2.2 : rpm : 0)\n   [*] After  remove  (2.2.2 : rpm : 0)\n```"
  },
  {
    "path": "packaging/windows/.gitkeep",
    "content": ""
  },
  {
    "path": "packaging/windows/dev_helpers/build_angular.ps1",
    "content": "# This script builds the Angular project for the Portmaster application and packages it into a zip file.\n# The script assumes that all necessary dependencies are installed and available.\n# Output file: dist/portmaster.zip\n\n[CmdletBinding()]\nparam (\n    [Parameter(Mandatory=$false)]\n    [Alias(\"d\")]\n    [switch]$Development,\n    \n    [Parameter(Mandatory=$false)]\n    [Alias(\"i\")]\n    [switch]$Interactive\n)\n\n# Store original directory and find project root\n$originalDir = Get-Location\n$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path\n$projectRoot = (Get-Item $scriptDir).Parent.Parent.Parent.FullName\n\ntry {\n    # Create output directory\n    $outputDir = Join-Path $scriptDir \"dist\"\n    New-Item -ItemType Directory -Path $outputDir -Force | Out-Null\n\n    # Navigate to Angular project\n    Set-Location (Join-Path $projectRoot \"desktop\\angular\")\n\n    # npm install - always run in non-interactive mode, ask in interactive mode\n    if (!$Interactive -or (Read-Host \"Run 'npm install'? (Y/N, default: Y)\") -notmatch '^[Nn]$') {\n        npm install\n        if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }\n    }\n\n    # build libs - always run in non-interactive mode, ask in interactive mode\n    if (!$Interactive -or (Read-Host \"Build shared libraries? (Y/N, default: Y)\") -notmatch '^[Nn]$') {\n        if ($Development) {\n            Write-Host \"Building shared libraries in development mode\" -ForegroundColor Yellow\n            npm run build-libs:dev\n        } else {\n            Write-Host \"Building shared libraries in production mode\" -ForegroundColor Yellow\n            npm run build-libs\n        }\n        if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }\n    }\n\n    # Build Angular project\n    if ($Development) {\n        Write-Host \"Building Angular project in development mode\" -ForegroundColor Yellow\n        ng build --configuration development --base-href /ui/modules/portmaster/ portmaster\n    } else {\n        Write-Host \"Building Angular project in production mode\" -ForegroundColor Yellow\n        ng build --configuration production --base-href /ui/modules/portmaster/ portmaster\n    }\n    if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }\n\n    # Create zip archive\n    Write-Host \"Creating zip archive\" -ForegroundColor Yellow\n    Set-Location dist\n    $destinationZip = Join-Path $outputDir \"portmaster.zip\"\n    if ($PSVersionTable.PSVersion.Major -ge 5) {\n        # Option 1: Use .NET Framework directly (faster than Compress-Archive)\n        Write-Host \"Using System.IO.Compression for faster archiving\" -ForegroundColor Yellow\n        if (Test-Path $destinationZip) { Remove-Item $destinationZip -Force }    # Remove existing zip if it exists\n        Add-Type -AssemblyName System.IO.Compression.FileSystem\n        $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal \n        [System.IO.Compression.ZipFile]::CreateFromDirectory((Get-Location), $destinationZip, $compressionLevel, $false)\n    } \n    else {\n        # Fall back to Compress-Archive\n        Compress-Archive -Path * -DestinationPath $destinationZip -Force\n    }\n    \n    Write-Host \"Build completed successfully: $(Join-Path $outputDir \"portmaster.zip\")\" -ForegroundColor Green\n}\nfinally {\n    # Return to original directory - this will execute even if Ctrl+C is pressed\n    Set-Location $originalDir\n}"
  },
  {
    "path": "packaging/windows/dev_helpers/build_tauri.ps1",
    "content": "# This script builds the Tauri application for Portmaster on Windows.\n# It optionally builds the required Angular tauri-builtin project first.\n# The script assumes that all necessary dependencies (Node.js, Rust, etc.) are installed.\n# Output file: dist/portmaster.exe\n\n# Store original directory and find project root\n$originalDir = Get-Location\n$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path\n$projectRoot = (Get-Item $scriptDir).Parent.Parent.Parent.FullName\n\n# Create output directory\n$outputDir = Join-Path $scriptDir \"dist\"\nNew-Item -ItemType Directory -Path $outputDir -Force | Out-Null\n\n# Ask if user wants to build the Angular tauri-builtin project\nif ((Read-Host \"Build Angular tauri-builtin project? (Y/N, default: Y)\") -notmatch '^[Nn]$') {\n    # Navigate to Angular project\n    Set-Location (Join-Path $projectRoot \"desktop\\angular\")\n    \n    # Build tauri-builtin project\n    ng build --configuration production --base-href / tauri-builtin\n    if ($LASTEXITCODE -ne 0) { Set-Location $originalDir; exit $LASTEXITCODE }\n}\n\n# Navigate to Tauri project directory\nSet-Location (Join-Path $projectRoot \"desktop\\tauri\\src-tauri\")\n\n# Build Tauri project for Windows\ncargo tauri build --no-bundle\nif ($LASTEXITCODE -ne 0) { Set-Location $originalDir; exit $LASTEXITCODE }\n\n# Copy the output files to the script's dist directory\n$tauriOutput = Join-Path (Get-Location) \"target\\release\"\nCopy-Item -Path \"$tauriOutput\\portmaster.exe\" -Destination $outputDir -Force\n\n# Return to original directory\nSet-Location $originalDir\nWrite-Host \"Build completed successfully: $outputDir\\portmaster.exe\" -ForegroundColor Green"
  },
  {
    "path": "packaging/windows/generate_windows_installers.ps1",
    "content": "#------------------------------------------------------------------------------\n# Portmaster Windows Installer Generator\n#------------------------------------------------------------------------------\n# This script creates Windows installers (MSI and NSIS) for Portmaster application\n# by combining pre-compiled binaries and packaging them with Tauri.\n#\n# ## Workflow for creating Portmaster Windows installers:\n#\n# 1. Compile Core Binaries (Linux environment)\n#    ```\n#    earthly +release-prep\n#\n#    # Or use command to do the same AND build Linux packages:\n#    # earthly +all-artifacts\n#    ```\n#    This compiles and places files into the 'dist' folder with the required structure.\n#    Note: Latest KEXT binaries and Intel data will be downloaded from https://updates.safing.io\n#\n# 2. Compile Windows-Specific Binaries (Windows environment)\n#    Some files cannot be compiled by Earthly and require Windows.\n#    - Compile 'portmaster-core.dll' from the /windows_core_dll folder\n#    - Copy the compiled DLL to <project-root>/dist/downloaded/windows_amd64\n#\n# 3. Sign All Binaries (Windows environment)\n#    ```\n#    .\\packaging\\windows\\sign_binaries_in_dist.ps1 -certSha1 d3bf5973eb1ec3dbd6ec45d77d556881a350acd2\n#    ```\n#    This signs all binary files in the dist directory\n#\n# 4. Create Installers (Windows environment)\n#    Note! You can run it from docker container (see example bellow).\n#    ```\n#    .\\generate_windows_installers.ps1\n#    ```\n#    Installers will be placed in <project-root>/dist/windows_amd64\n#\n# 5. Sign Installers (Windows environment)\n#    ```\n#    .\\packaging\\windows\\sign_binaries_in_dist.ps1 -certSha1 <SHA1_of_the_certificate>\n#    ```\n#    This signs the newly created installer files\n#\n#------------------------------------------------------------------------------\n# Running inside Docker container\n#       Tested with docker image 'abrarov/msvc-2022:latest'\n#       sha256:f49435d194108cd56f173ad5bc6a27c70eed98b7e8cd54488f5acd85efbd51c9\n# \n# Note! Ensure you switched Docker Desktop to use Windows containers.\n# Start powershell and cd to the root of the project.\n# Then run:\n#   $path = Convert-Path .  # Get the absolute path of the current directory\n#   docker run -it --rm -v \"${path}:C:/app\" -w \"C:/app\" abrarov/msvc-2022 powershell -NoProfile -File C:/app/packaging/windows/generate_windows_installers.ps1\n#------------------------------------------------------------------------------\n#\n# Optional arguments:\n# -i: (interactive) Can prompt for user input (e.g. when a file is not found in the primary folder but found in the alternate folder)\n# -v: (version)     Explicitly set the version to use for the installer file name\n# -e: (erase)       Just erase work directories\n#------------------------------------------------------------------------------\nparam (\n    [Alias('i')]\n    [switch]$interactive,\n\n    [Alias('v')]\n    [string]$version,\n\n    [Alias('e')]\n    [switch]$erase\n)\n\n# Save the current directory\n$originalDirectory = Get-Location\n\n# <<<<<<<<<<<<<<<<<<<<<<< Functions <<<<<<<<<<<<<<<<<<<<<<<\n\n# Function to copy a file, with fallback to an alternative location and detailed logging\n# Parameters:\n#   $SourceDir         - Primary directory to search for the file\n#   $File              - Name of the file to copy\n#   $DestinationDir    - Directory where the file will be copied to\n#   $AlternateSourceDir - Fallback directory if file is not found in $SourceDir\n# \n# Behavior:\n# - Checks if the file exists in the primary source directory\n# - If not found and an alternate directory is provided, checks there\n# - In interactive mode, asks for confirmation before using the alternate source\n# - Logs details about the copied file (path, size, timestamp, version)\n# - Returns error and exits if file cannot be found or copied\nfunction Find-And-Copy-File {\n    param (\n        [string]$SourceDir,        \n        [string]$File,\n        [string]$DestinationDir,\n        [string[]]$AlternateSourceDirs  # Changed from single string to array\n    )\n    $destinationPath = \"$DestinationDir/$File\"\n    $fullSourcePath  = if ($SourceDir) { \"$SourceDir/$File\" } else { \"\" }    \n    \n    if ($AlternateSourceDirs -and (-not $fullSourcePath -or -not (Test-Path -Path $fullSourcePath))) {\n        # File doesn't exist, check in alternate folders\n        $foundInAlternate = $false\n        \n        foreach ($altDir in $AlternateSourceDirs) {\n            $fallbackSourcePath = \"$altDir/$File\"    \n            if (Test-Path -Path $fallbackSourcePath) {\n                if ($interactive -and $fullSourcePath) { # Do not prompt if the sourceDir is empty or \"interactive\" mode is not set\n                    $response = Read-Host \"    [?] The file '$File' found in fallback '$altDir' folder.`n    Do you want to use it? (y/n)\"\n                    if ($response -ne 'y' -and $response -ne 'Y') {\n                        continue  # Try next alternate directory\n                    } \n                }           \n                $fullSourcePath = $fallbackSourcePath\n                $foundInAlternate = $true\n                break  # Found a usable file, stop searching\n            }\n        }\n        \n        if (-not $foundInAlternate) {\n            $altDirsString = $AlternateSourceDirs -join \"', '\"\n            Write-Error \"Required file '$File' not found in: '$SourceDir', '$altDirsString'\"\n            exit 1\n        }\n    }\n\n    try {\n        # Print details about the file\n        $fileInfo = Get-Item -Path $fullSourcePath\n        $fileHash = (Get-FileHash -Path $fullSourcePath -Algorithm SHA256).Hash\n        $hashShort = $fileHash.Substring(0, 4) + \"...\" + $fileHash.Substring($fileHash.Length - 8)\n        $output = \"{0,-22}: {1,-29} -> {2,-38} [{3}{4}]\" -f \n               $File,\n               $(Split-Path -Path $fullSourcePath -Parent),\n               $(Split-Path -Path $destinationPath -Parent),               \n               \"SHA256: $hashShort\",\n               $(if ($fileInfo.VersionInfo.FileVersion) { \"; v$($fileInfo.VersionInfo.FileVersion)\" } else { \"\" })\n        Write-Output \"$output\"\n\n        # Create destination directory if not exists\n        if (-not (Test-Path -Path $DestinationDir)) {\n            New-Item -ItemType Directory -Path $DestinationDir -ErrorAction Stop > $null\n        }\n        # Copy the file\n        Copy-Item -Force -Path \"${fullSourcePath}\" -Destination \"${destinationPath}\" -ErrorAction Stop\n    } catch {\n        Write-Error \"Failed to copy file from '$fullSourcePath' to '$destinationPath'.`nError: $_\"\n        exit 1\n    }\n}\n\n# Function to set and restore Cargo.toml version\nfunction Set-CargoVersion { \n    param ([string]$Version)\n    if (-not (Test-Path \"Cargo.toml.bak\")) {        \n        Copy-Item \"Cargo.toml\" \"Cargo.toml.bak\" -Force\n    }\n    # Update the version in Cargo.toml.\n    # This will allow the Tauri CLI to set the correct filename for the installer.\n    # NOTE: This works only when the version is not explicitly defined in tauri.conf.json5.\n    (Get-Content \"Cargo.toml\" -Raw) -replace '(\\[package\\][^\\[]*?)version\\s*=\\s*\"[^\"]+\"', ('$1version = \"' + $Version + '\"') | Set-Content \"Cargo.toml\"\n}\nfunction Restore-CargoVersion {\n    if (Test-Path \"Cargo.toml.bak\") {\n        Copy-Item \"Cargo.toml.bak\" \"Cargo.toml\" -Force\n        Remove-Item \"Cargo.toml.bak\" -Force\n    }\n}\n\nfunction Get-GitTagVersion {\n    # Check if running in Docker and configure Git accordingly\n    if ($env:ComputerName -like \"*container*\" -or $env:USERNAME -eq \"ContainerAdministrator\") {\n        $currentDir = (Get-Location).Path        \n        git config --global --add safe.directory $currentDir\n    }\n\n    # Try to get exact tag pointing to current commit\n    $version = $(git tag --points-at 2>$null)    \n    # If no tag points to current commit, use most recent tag\n    if ([string]::IsNullOrEmpty($version)) {\n        $devVersion = $(git describe --tags --first-parent --abbrev=0 2>$null)\n        if (-not [string]::IsNullOrEmpty($devVersion)) {\n            $version = \"${devVersion}\"\n        }\n    }\n    $version = $version -replace '^v', ''\n    return $version\n}\n# >>>>>>>>>>>>>>>>>>>>>>> End Functions >>>>>>>>>>>>>>>>>>>>>>>>\n\n# Set-Location relative to the script location \"../..\" (root of the project). So that the script can be run from any location.\nSet-Location -Path (Join-Path -Path $PSScriptRoot -ChildPath \"../..\")\ntry {\n    # CONSTANTS\n    $destinationDir = \"desktop/tauri/src-tauri\"\n    $binaryDir = \"$destinationDir/binary\"           #portmaster\\desktop\\tauri\\src-tauri\\binary\n    $intelDir  = \"$destinationDir/intel\"            #portmaster\\desktop\\tauri\\src-tauri\\intel\n    $targetBase= \"$destinationDir/target\"           #portmaster\\desktop\\tauri\\src-tauri\\target\n    $targetDir = \"$targetBase/release\"              #portmaster\\desktop\\tauri\\src-tauri\\target\\release\n\n    # Erasing work directories\n    Write-Output \"[+] Erasing work directories: '$binaryDir', '$intelDir', '$targetBase'\"\n    Remove-Item -Recurse -Force -Path $binaryDir -ErrorAction SilentlyContinue\n    Remove-Item -Recurse -Force -Path $intelDir -ErrorAction SilentlyContinue\n    Remove-Item -Recurse -Force -Path $targetBase -ErrorAction SilentlyContinue\n    if ($erase) {\n        Write-Output \"[ ] Done\"\n        exit 0\n    }\n\n    # Copying BINARY FILES\n    Write-Output \"`n[+] Copying binary files:\"\n    $filesToCopy = @(\n        @{Folder=\"dist/downloaded/windows_amd64\";   File=\"portmaster-kext.sys\";     Destination=$binaryDir; },\n        @{Folder=\"dist/downloaded/windows_amd64\";   File=\"portmaster-core.dll\";     Destination=$binaryDir; },\n        @{Folder=\"dist/binary/windows_amd64\";   File=\"portmaster-core.exe\";     Destination=$binaryDir; },\n        @{Folder=\"dist/binary/windows_amd64\";   File=\"WebView2Loader.dll\";      Destination=$binaryDir; },\n        @{Folder=\"dist/binary/all\";             File=\"portmaster.zip\";          Destination=$binaryDir; },\n        @{Folder=\"dist/binary/all\";             File=\"assets.zip\";              Destination=$binaryDir; },\n        @{Folder=\"dist/binary/windows_amd64\";   File=\"portmaster.exe\";          Destination=$targetDir; }\n    )\n    foreach ($file in $filesToCopy) {    \n        Find-And-Copy-File -SourceDir $file.Folder -File $file.File -DestinationDir $file.Destination -AlternateSourceDirs $file.AlternateSourceDirs\n    }\n\n    # Copying INTEL FILES\n    Write-Output \"`n[+] Copying intel files\"\n    if (-not (Test-Path -Path $intelDir)) {\n        New-Item -ItemType Directory -Path $intelDir -ErrorAction Stop > $null\n    }\n    Copy-Item -Force -Path \"dist/intel/*\" -Destination \"$intelDir/\" -ErrorAction Stop\n} catch {\n    Set-Location $originalDirectory\n    Write-Error \"[!] Failed! Error: $_\"\n    exit 1\n}\n\n$VERSION_GIT_TAG    = Get-GitTagVersion\n\n# Check versions of UI and Core binaries\n$VERSION_UI         = (Get-Item \"$targetDir/portmaster.exe\").VersionInfo.FileVersion\n$VERSION_CORE       = (& \"$binaryDir/portmaster-core.exe\" version | Select-String -Pattern \"Portmaster\\s+(\\d+\\.\\d+\\.\\d+)\" | ForEach-Object { $_.Matches.Groups[1].Value })\n$VERSION_KEXT       = (Get-Item \"$binaryDir/portmaster-kext.sys\").VersionInfo.FileVersion\nWrite-Output \"`n[i] VERSIONS INFO:\"\nWrite-Output \"    VERSION_GIT_TAG : $VERSION_GIT_TAG\"\nWrite-Output \"    VERSION_CORE    : $VERSION_CORE\"\nWrite-Output \"    VERSION_UI      : $VERSION_UI\"\nWrite-Output \"    VERSION_KEXT    : $VERSION_KEXT\"\nif ($VERSION_UI -ne $VERSION_CORE -or $VERSION_CORE -ne $VERSION_GIT_TAG) {\n    Write-Warning \"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"\n    Write-Warning \"Version mismatch between UI($VERSION_UI), Core($VERSION_CORE) and GitTag($VERSION_GIT_TAG)!\"\n    Write-Warning \"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"\n    if ($interactive) {\n        $response = Read-Host \"[?] Continue anyway? (y/n)\"\n        if ($response -ne 'y' -and $response -ne 'Y') {\n            Write-Error \"Cancelled. Version mismatch between UI and Core binaries.\"\n            exit 1\n        }     \n    } \n}\n# Determine which version to use for building\nif ($version) {\n    Write-Output \"`n[i] Using explicitly provided version ($version) for installer file name`n\"\n    $VERSION_TO_USE  = $version\n} else {\n    Write-Output \"`n[i] Using Core version version ($VERSION_CORE) for installer file name`n\"\n    $VERSION_TO_USE  = $VERSION_CORE    \n}\n\nSet-Location $destinationDir\ntry {\n    # Ensure Rust toolchain is installed\n    if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {\n        Write-Output \"[+] Installing rust toolchain...\"        \n        Start-BitsTransfer -Source \"https://win.rustup.rs/x86_64\" -Destination \"rustup.exe\"\n        ./rustup.exe install --no-self-update stable\n        $env:PATH += \";C:\\Users\\ContainerAdministrator\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\\bin\\\"\n    } \n\n    # Ensure Tauri CLI is available\n    $cargoTauriCommand = \"cargo-tauri.exe\"\n    if (-not (Get-Command $cargoTauriCommand -ErrorAction SilentlyContinue)) {    \n        if (-not (Test-Path \"./tauri-cli/cargo-tauri.exe\")) {\n            Write-Output \"[+] Tauri CLI not found. Downloading tauri-cli\"\n            Start-BitsTransfer -Source \"https://github.com/tauri-apps/tauri/releases/download/tauri-cli-v2.2.7/cargo-tauri-x86_64-pc-windows-msvc.zip\" -Destination \"tauri-cli.zip\"\n            Expand-Archive -Force tauri-cli.zip\n        }\n        if (-not (Test-Path \"./tauri-cli/cargo-tauri.exe\")) {\n            Write-Error \"Tauri CLI not found. Download failed.\"\n            exit 1\n        }\n        $cargoTauriCommand = \"./tauri-cli/cargo-tauri.exe\"\n    }\n\n    Write-Output \"[i] Tools versions info:\"\n    Write-Output \"    Tauri CLI: $((& $cargoTauriCommand -V | Out-String).Trim().Replace(\"`r`n\", \" \"))\"\n    Write-Output \"    Rust     : $((rustc -V | Out-String).Trim().Replace(\"`r`n\", \" \")); $((cargo -V | Out-String).Trim().Replace(\"`r`n\", \" \"))\"\n    Write-Output \"\"\n\n    # Building Tauri app bundle\n    try {\n        Write-Output \"[+] Building Tauri app bundle with version $VERSION_TO_USE\"\n        Set-CargoVersion -Version $VERSION_TO_USE\n        & $cargoTauriCommand bundle\n        if ($LASTEXITCODE -ne 0) {\n            throw \"Tauri bundle command failed with exit code $LASTEXITCODE\"         \n        }\n    }\n    catch {\n        Write-Error \"[!] Bundle failed: $_\"\n        exit 1\n    }\n    finally {\n       Restore-CargoVersion\n    }\n\n    Write-Output \"[+] Copying generated bundles\"\n    $installerDist = \"..\\..\\..\\dist\\windows_amd64\\\"\n    if (-not (Test-Path -Path $installerDist)) {\n        New-Item -ItemType Directory -Path $installerDist -ErrorAction Stop > $null\n    }\n    #Copy-Item -Path \".\\target\\release\\bundle\\msi\\*\"  -Destination $installerDist -ErrorAction Stop\n    Copy-Item -Path \".\\target\\release\\bundle\\nsis\\*\" -Destination $installerDist -ErrorAction Stop\n\n    Write-Output \"[i] Done.\"\n    Write-Output \"    Installer files are available in:  $(Resolve-Path $installerDist)\"\n} catch {\n    Write-Error \"[!] Failed! Error: $_\"\n    exit 1\n}\nfinally {\n    # Restore the original directory if not already done\n    Set-Location $originalDirectory\n}"
  },
  {
    "path": "packaging/windows/sign_binaries_in_dist.ps1",
    "content": "param (\n    [Parameter(Mandatory=$false)]\n    [string]$certSha1,\n    \n    [Parameter(Mandatory=$false)]\n    [string]$timestampServer = \"http://timestamp.digicert.com\"\n)\n\nfunction Show-Help {\n    Write-Host \"Usage: sign_binaries_in_dist.ps1 -certSha1 <CERT_SHA1> [-timestampServer <TIMESTAMP_SERVER>]\"\n    Write-Host \"\"\n    Write-Host \"This script signs all binary files located under the '<project root>\\dist\\' directory recursively.\"\n    Write-Host \"Which should be done before creating the Portmaster installer.\"\n    Write-Host \"\"\n    Write-Host \"Arguments:\"\n    Write-Host \"  -certSha1        The SHA1 hash of the certificate to use for signing (code signing certificate).\"\n    Write-Host \"  -timestampServer The timestamp server URL to use (optional). Default is http://timestamp.digicert.com.\"\n    Write-Host \"\"\n    Write-Host \"Example:\"\n    Write-Host \"  .\\sign_binaries_in_dist.ps1 -certSha1 ABCDEF1234567890ABCDEF1234567890ABCDEF12\"\n}\n\n# Show help if no certificate SHA1 provided or help flag used\nif (-not $certSha1 -or ($args -contains \"-h\") -or ($args -contains \"-help\") -or ($args -contains \"/h\")) {\n    Show-Help\n    exit 0\n}\n\n# Find signtool.exe - simplified approach\nfunction Find-SignTool {\n    # First try the PATH\n    $signtool = Get-Command signtool.exe -ErrorAction SilentlyContinue\n    if ($signtool) { return $signtool }\n\n    Write-Host \"[+] signtool.exe not found in PATH. Searching in common locations...\"\n\n    # Common locations for signtool\n    $commonLocations = @(\n        # Windows SDK paths\n        \"${env:ProgramFiles(x86)}\\Windows Kits\\10\\bin\\*\\x64\\signtool.exe\",\n        \"${env:ProgramFiles(x86)}\\Windows Kits\\10\\bin\\*\\x86\\signtool.exe\",\n        \n        # Visual Studio paths via vswhere\n        (& \"${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -latest -products * -requires Microsoft.Component.MSBuild -find \"**/signtool.exe\" -ErrorAction SilentlyContinue)\n    )\n\n    foreach ($location in $commonLocations) {\n        $tools = Get-ChildItem -Path $location -ErrorAction SilentlyContinue | \n                 Sort-Object -Property FullName -Descending\n        if ($tools -and $tools.Count -gt 0) {\n            return $tools[0]  # Return the first match\n        }\n    }\n\n    return $null\n}\n\nfunction Get-SignatureInfo {\n    param(\n        [string]$filePath\n    )    \n    # Get the raw output from signtool\n    $rawOutput = & $signtool verify /pa /v $filePath 2>&1    \n    \n    # Filter output to exclude everything after the timestamp line\n    $filteredOutput = @()\n    foreach ($line in $rawOutput) {\n        if ($line -match \"The signature is timestamped:\") {\n            break\n        }\n        $filteredOutput += $line\n    }    \n    # Extract last subject in the signing chain - it's typically the last \"Issued to:\" entry\n    $lastSubject = ($filteredOutput | Select-String -Pattern \"Issued to: (.*)$\" | Select-Object -Last 1 | ForEach-Object { $_.Matches.Groups[1].Value })    \n    # Create signature info object\n    $signInfo = @{\n        \"IsSigned\" = $LASTEXITCODE -eq 0\n        \"Subject\" = ($filteredOutput | Select-String -Pattern \"Issued to: (.*)$\" | ForEach-Object { $_.Matches.Groups[1].Value }) -join \", \"\n        \"Issuer\" = ($filteredOutput | Select-String -Pattern \"Issued by: (.*)$\" | ForEach-Object { $_.Matches.Groups[1].Value }) -join \", \"\n        \"ExpirationDate\" = ($filteredOutput | Select-String -Pattern \"Expires: (.*)$\" | ForEach-Object { $_.Matches.Groups[1].Value }) -join \", \"\n        \"SubjectLast\" = $lastSubject\n        \"SignedBySameCert\" = $false\n    }\n\n    # Check if signed by our certificate\n    $null = & $signtool verify /pa /sha1 $certSha1 $filePath 2>&1\n    $signInfo.SignedBySameCert = $LASTEXITCODE -eq 0\n    \n    return $signInfo\n}\n\n# Find dist directory relative to script location\n$distDir = Join-Path $PSScriptRoot \"../../dist\"\nif (-not (Test-Path -Path $distDir)) {\n    Write-Host \"The directory '$distDir' does not exist.\" -ForegroundColor Red\n    exit 1\n}\n$distDir = Resolve-Path (Join-Path $PSScriptRoot \"../../dist\") # normalize path\n\n# Find signtool.exe\n$signtool = Find-SignTool\nif (-not $signtool) {\n    Write-Host \"signtool.exe not found in any standard location.\" -ForegroundColor Red\n    Write-Host \"Please install one of the following:\" -ForegroundColor Yellow\n    Write-Host \"- Windows SDK\" -ForegroundColor Yellow\n    Write-Host \"- Visual Studio with the 'Desktop development with C++' workload\" -ForegroundColor Yellow\n    Write-Host \"- Visual Studio Build Tools with the 'Desktop development with C++' workload\" -ForegroundColor Yellow\n    exit 1\n}\n\nWrite-Host \"[i] Using signtool: $($signtool)\"\n\n# Sign all binary files in the dist directory\ntry {\n    # Define extensions for files that should be signed\n    $binaryExtensions = @('.exe', '.dll', '.sys', '.msi')\n    \n    # Get all files with binary extensions\n    $files = Get-ChildItem -Path $distDir -Recurse -File | Where-Object { \n        $extension = [System.IO.Path]::GetExtension($_.Name).ToLower()\n        $binaryExtensions -contains $extension\n    }\n    \n    $totalFiles = $files.Count\n    $signedFiles = 0\n    $alreadySignedFiles = 0\n    $wrongCertFiles = 0\n    $filesToSign = @()\n    \n    Write-Host \"[+] Found $totalFiles binary files to process\" -ForegroundColor Green    \n    foreach ($file in $files) {\n        $relativeFileName = $file.FullName.Replace(\"$distDir\\\", \"\")\n        # Get signature information\n        $signInfo = Get-SignatureInfo -filePath $file.FullName\n                \n        if ($signInfo.IsSigned) {\n            if ($signInfo.SignedBySameCert) {\n                Write-Host -NoNewline \"  [signed OK ]\" -ForegroundColor Green\n                Write-Host -NoNewline \" $($relativeFileName)\" -ForegroundColor Blue\n                Write-Host \"`t: signed by our certificate\"\n                $alreadySignedFiles++\n            } else {\n                Write-Host -NoNewline \"  [different ]\" -ForegroundColor Yellow\n                Write-Host -NoNewline \" $($relativeFileName)\" -ForegroundColor Blue\n                Write-Host \"`t: signed by different certificate [$($signInfo.SubjectLast)]\"\n                $wrongCertFiles++                \n            }\n        } else {\n            Write-Host -NoNewline \"  [NOT signed]\" -ForegroundColor Red\n            Write-Host -NoNewline \" $($relativeFileName)\" -ForegroundColor Blue\n            Write-Host \"`t: not signed\"\n            $filesToSign += $file.FullName\n        }\n    }\n    \n    # Batch sign files\n    if ($filesToSign.Count -gt 0) {\n        Write-Host \"`n[+] Signing $($filesToSign.Count) files in batch...\" -ForegroundColor Green\n        \n        & $signtool sign /tr $timestampServer /td sha256 /fd sha256 /sha1 $certSha1 /v $filesToSign       \n        if ($LASTEXITCODE -ne 0) {\n            Write-Host \"Failed to sign files!\" -ForegroundColor Red\n            exit 1\n        }\n\n        $signedFiles = $filesToSign.Count\n    } else {\n        Write-Host \"`n[+] No files need signing.\" -ForegroundColor Green\n    }\n\n    Write-Host \"`n[+] Summary:\" -ForegroundColor Green\n    Write-Host \"    - Total binary files found: $totalFiles\"\n    Write-Host \"    - Files already signed with our certificate: $alreadySignedFiles\"\n    Write-Host \"    - Files signed with different certificate: $wrongCertFiles\"\n    Write-Host \"    - Files newly signed: $signedFiles\"\n} catch {\n    Write-Host \"An error occurred: $_\" -ForegroundColor Red\n    exit 1\n}"
  },
  {
    "path": "runtime/.gitkeep",
    "content": ""
  },
  {
    "path": "service/broadcasts/api.go",
    "content": "package broadcasts\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/portmaster/service/interop/ivpn\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `broadcasts/matching-data`,\n\t\tRead:        api.PermitAdmin,\n\t\tStructFunc:  handleMatchingData,\n\t\tName:        \"Get Broadcast Notifications Matching Data\",\n\t\tDescription: \"Returns the data used by the broadcast notifications to match the instance.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `broadcasts/reset-state`,\n\t\tWrite:       api.PermitAdmin,\n\t\tWriteMethod: http.MethodPost,\n\t\tActionFunc:  handleResetState,\n\t\tName:        \"Reset Notification States\",\n\t\tDescription: \"Deletes the cached state of broadcast and other notifications, causing them to appear again.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `broadcasts/simulate`,\n\t\tWrite:       api.PermitAdmin,\n\t\tWriteMethod: http.MethodPost,\n\t\tActionFunc:  handleSimulate,\n\t\tName:        \"Simulate Broadcast Notifications\",\n\t\tDescription: \"Test broadcast notifications by sending a valid source file in the body.\",\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodPost,\n\t\t\t\tField:       \"state\",\n\t\t\t\tValue:       \"true\",\n\t\t\t\tDescription: \"Check against state when deciding to display a broadcast notification. Acknowledgements are always saved.\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleMatchingData(ar *api.Request) (i interface{}, err error) {\n\treturn collectData(), nil\n}\n\nfunc handleResetState(ar *api.Request) (msg string, err error) {\n\terr = db.Delete(broadcastStatesDBKey)\n\tif err != nil && !errors.Is(err, database.ErrNotFound) {\n\t\treturn \"\", err\n\t}\n\n\t_ = db.Delete(ivpn.Notification_DB_ID_IvpnDetectSuppressed)\n\t_ = db.Delete(resolver.Notification_DB_ID_StaleCacheSuppressed)\n\n\treturn \"Reset complete. Some notifications require a restart to reappear.\", nil\n}\n\nfunc handleSimulate(ar *api.Request) (msg string, err error) {\n\t// Parse broadcast notification data.\n\tbroadcasts, err := parseBroadcastSource(ar.InputData)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to parse broadcast notifications update: %w\", err)\n\t}\n\n\t// Get and marshal matching data.\n\tmatchingData := collectData()\n\tmatchingJSON, err := json.Marshal(matchingData)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to marshal broadcast notifications matching data: %w\", err)\n\t}\n\tmatchingDataAccessor := accessor.NewJSONBytesAccessor(&matchingJSON)\n\n\tvar bss *BroadcastStates\n\tif ar.URL.Query().Get(\"state\") == \"true\" {\n\t\t// Get broadcast notification states.\n\t\tbss, err = getBroadcastStates()\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to get broadcast notifications states: %w\", err)\n\t\t\t}\n\t\t\tbss = newBroadcastStates()\n\t\t}\n\t}\n\n\t// Go through all broadcast nofications and check if they match.\n\tvar results []string\n\tfor _, bn := range broadcasts.Notifications {\n\t\terr := handleBroadcast(bn, matchingDataAccessor, bss)\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\tresults = append(results, fmt.Sprintf(\"%30s: displayed\", bn.id))\n\t\tcase errors.Is(err, ErrSkip):\n\t\t\tresults = append(results, fmt.Sprintf(\"%30s: %s\", bn.id, err))\n\t\tdefault:\n\t\t\tresults = append(results, fmt.Sprintf(\"FAILED %23s: %s\", bn.id, err))\n\t\t}\n\t}\n\n\treturn strings.Join(results, \"\\n\"), nil\n}\n"
  },
  {
    "path": "service/broadcasts/data.go",
    "content": "package broadcasts\n\nimport (\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/core\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/access/account\"\n\t\"github.com/safing/portmaster/spn/captain\"\n)\n\nvar portmasterStarted = time.Now()\n\nfunc collectData() interface{} {\n\tdata := make(map[string]interface{})\n\n\t// Get data about versions.\n\tversions := core.GetSimpleVersions()\n\tdata[\"Updates\"] = versions\n\tdata[\"Version\"] = versions.Build.Version\n\tnumericVersion, err := MakeNumericVersion(versions.Build.Version)\n\tif err != nil {\n\t\tdata[\"NumericVersion\"] = &DataError{\n\t\t\tError: err,\n\t\t}\n\t} else {\n\t\tdata[\"NumericVersion\"] = numericVersion\n\t}\n\n\t// Get data about install.\n\tinstallInfo, err := GetInstallInfo()\n\tif err != nil {\n\t\tdata[\"Install\"] = &DataError{\n\t\t\tError: err,\n\t\t}\n\t} else {\n\t\tdata[\"Install\"] = installInfo\n\t}\n\n\t// Get global configuration.\n\tdata[\"Config\"] = config.GetActiveConfigValues()\n\n\t// Get data about device location.\n\tlocs, ok := netenv.GetInternetLocation()\n\tif ok && locs.Best().LocationOrNil() != nil {\n\t\tloc := locs.Best()\n\t\tdata[\"Location\"] = &Location{\n\t\t\tCountry:        loc.Location.Country.Code,\n\t\t\tCoordinates:    loc.Location.Coordinates,\n\t\t\tASN:            loc.Location.AutonomousSystemNumber,\n\t\t\tASOrg:          loc.Location.AutonomousSystemOrganization,\n\t\t\tSource:         loc.Source,\n\t\t\tSourceAccuracy: loc.SourceAccuracy,\n\t\t}\n\t}\n\n\t// Get data about SPN status.\n\tdata[\"SPN\"] = captain.GetSPNStatus()\n\n\t// Get data about account.\n\tuserRecord, err := access.GetUser()\n\tif err != nil {\n\t\tdata[\"Account\"] = &DataError{\n\t\t\tError: err,\n\t\t}\n\t} else {\n\t\taccount := &Account{\n\t\t\tUserRecord: userRecord,\n\t\t\tActive:     userRecord.MayUse(\"\"),\n\t\t\tUpToDate:   userRecord.Meta().Modified > time.Now().Add(-7*24*time.Hour).Unix(),\n\t\t}\n\t\t// Only add feature IDs when account is active.\n\t\tif account.Active {\n\t\t\taccount.FeatureIDs = userRecord.CurrentPlan.FeatureIDs\n\t\t}\n\t\tdata[\"Account\"] = account\n\t}\n\n\t// Time running.\n\tdata[\"UptimeHours\"] = int(time.Since(portmasterStarted).Hours())\n\n\t// Get current time and date.\n\tnow := time.Now()\n\tdata[\"Current\"] = &Current{\n\t\tUnixTime: now.Unix(),\n\t\tUTC:      makeDateTimeInfo(now.UTC()),\n\t\tLocal:    makeDateTimeInfo(now),\n\t}\n\n\treturn data\n}\n\n// Location holds location matching data.\ntype Location struct {\n\tCountry        string\n\tCoordinates    geoip.Coordinates\n\tASN            uint\n\tASOrg          string\n\tSource         netenv.DeviceLocationSource\n\tSourceAccuracy int\n}\n\n// Account holds SPN account matching data.\ntype Account struct {\n\t*access.UserRecord\n\tActive     bool\n\tUpToDate   bool\n\tFeatureIDs []account.FeatureID\n}\n\n// DataError represents an error getting some matching data.\ntype DataError struct {\n\tError error\n}\n\n// Current holds current date and time data.\ntype Current struct {\n\tUnixTime int64\n\tUTC      *DateTime\n\tLocal    *DateTime\n}\n\n// DateTime holds date and time data in different formats.\ntype DateTime struct {\n\tNumericDateTime int64\n\tNumericDate     int64\n\tNumericTime     int64\n}\n\nfunc makeDateTimeInfo(t time.Time) *DateTime {\n\tinfo := &DateTime{}\n\tinfo.NumericDateTime, _ = strconv.ParseInt(t.Format(\"20060102150405\"), 10, 64)\n\tinfo.NumericDate, _ = strconv.ParseInt(t.Format(\"20060102\"), 10, 64)\n\tinfo.NumericTime, _ = strconv.ParseInt(t.Format(\"150405\"), 10, 64)\n\n\treturn info\n}\n"
  },
  {
    "path": "service/broadcasts/install_info.go",
    "content": "package broadcasts\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tsemver \"github.com/hashicorp/go-version\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst installInfoDBKey = \"core:status/install-info\"\n\n// InstallInfo holds generic info about the install.\ntype InstallInfo struct {\n\trecord.Base\n\tsync.Mutex\n\n\tVersion        string\n\tNumericVersion int64\n\n\tTime             time.Time\n\tNumericDate      int64\n\tDaysSinceInstall int64\n\tUnixTimestamp    int64\n}\n\n// GetInstallInfo returns the install info from the database.\nfunc GetInstallInfo() (*InstallInfo, error) {\n\tr, err := db.Get(installInfoDBKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Unwrap.\n\tif r.IsWrapped() {\n\t\t// Only allocate a new struct, if we need it.\n\t\tnewRecord := &InstallInfo{}\n\t\terr = record.Unwrap(r, newRecord)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newRecord, nil\n\t}\n\n\t// or adjust type\n\tnewRecord, ok := r.(*InstallInfo)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *InstallInfo, but %T\", r)\n\t}\n\treturn newRecord, nil\n}\n\nfunc ensureInstallInfo() {\n\t// Get current install info from database.\n\tinstallInfo, err := GetInstallInfo()\n\tif err != nil {\n\t\tinstallInfo = &InstallInfo{}\n\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\tlog.Warningf(\"updates: failed to load install info: %s\", err)\n\t\t}\n\t}\n\n\t// Fill in missing data and save.\n\tinstallInfo.checkAll()\n\tif err := installInfo.save(); err != nil {\n\t\tlog.Warningf(\"updates: failed to save install info: %s\", err)\n\t}\n}\n\nfunc (ii *InstallInfo) save() error {\n\tif !ii.KeyIsSet() {\n\t\tii.SetKey(installInfoDBKey)\n\t}\n\treturn db.Put(ii)\n}\n\nfunc (ii *InstallInfo) checkAll() {\n\tii.checkVersion()\n\tii.checkInstallDate()\n}\n\nfunc (ii *InstallInfo) checkVersion() {\n\t// Check if everything is present.\n\tif ii.Version != \"\" && ii.NumericVersion > 0 {\n\t\treturn\n\t}\n\n\t// Update version information.\n\tversionInfo := info.GetInfo()\n\tii.Version = versionInfo.Version\n\n\t// Update numeric version.\n\tif versionInfo.Version != \"\" {\n\t\tnumericVersion, err := MakeNumericVersion(versionInfo.Version)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"updates: failed to make numeric version: %s\", err)\n\t\t} else {\n\t\t\tii.NumericVersion = numericVersion\n\t\t}\n\t}\n}\n\n// MakeNumericVersion makes a numeric version with the first three version\n// segment always using three digits.\nfunc MakeNumericVersion(version string) (numericVersion int64, err error) {\n\t// Remove any comments.\n\tversion = strings.SplitN(version, \" \", 2)[0]\n\n\t// Parse version string.\n\tver, err := semver.NewVersion(version)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to parse core version: %w\", err)\n\t}\n\n\t// Transform version for numeric representation.\n\tsegments := ver.Segments()\n\tfor i := 0; i < 3 && i < len(segments); i++ {\n\t\tsegmentNumber := int64(segments[i])\n\t\tif segmentNumber > 999 {\n\t\t\tsegmentNumber = 999\n\t\t}\n\t\tswitch i {\n\t\tcase 0:\n\t\t\tnumericVersion += segmentNumber * 1000000\n\t\tcase 1:\n\t\t\tnumericVersion += segmentNumber * 1000\n\t\tcase 2:\n\t\t\tnumericVersion += segmentNumber\n\t\t}\n\t}\n\n\treturn numericVersion, nil\n}\n\nfunc (ii *InstallInfo) checkInstallDate() {\n\t// Check if everything is present.\n\tif ii.UnixTimestamp > 0 &&\n\t\tii.NumericDate > 0 &&\n\t\tii.DaysSinceInstall > 0 &&\n\t\t!ii.Time.IsZero() {\n\t\treturn\n\t}\n\n\t// Find oldest created database entry and use it as install time.\n\toldest := time.Now().Unix()\n\tit, err := db.Query(query.New(\"core\"))\n\tif err != nil {\n\t\tlog.Warningf(\"updates: failed to create iterator for searching DB for install time: %s\", err)\n\t\treturn\n\t}\n\tdefer it.Cancel()\n\tfor r := range it.Next {\n\t\tif oldest > r.Meta().Created {\n\t\t\toldest = r.Meta().Created\n\t\t}\n\t}\n\n\t// Set data.\n\tii.UnixTimestamp = oldest\n\tii.Time = time.Unix(oldest, 0)\n\tii.DaysSinceInstall = int64(time.Since(ii.Time).Hours()) / 24\n\n\t// Transform date for numeric representation.\n\tnumericDate, err := strconv.ParseInt(ii.Time.Format(\"20060102\"), 10, 64)\n\tif err != nil {\n\t\tlog.Warningf(\"updates: failed to make numeric date from %s: %s\", ii.Time, err)\n\t} else {\n\t\tii.NumericDate = numericDate\n\t}\n}\n"
  },
  {
    "path": "service/broadcasts/module.go",
    "content": "package broadcasts\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype Broadcasts struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tstates *mgr.StateMgr\n}\n\nfunc (b *Broadcasts) Manager() *mgr.Manager {\n\treturn b.mgr\n}\n\nfunc (b *Broadcasts) Start() error {\n\treturn start()\n}\n\nfunc (b *Broadcasts) Stop() error {\n\treturn nil\n}\n\nfunc (b *Broadcasts) States() *mgr.StateMgr {\n\treturn b.states\n}\n\nvar (\n\tdb = database.NewInterface(&database.Options{\n\t\tLocal:    true,\n\t\tInternal: true,\n\t})\n\n\tstartOnce sync.Once\n)\n\nfunc prep() error {\n\t// Register API endpoints.\n\tif err := registerAPIEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc start() error {\n\t// Ensure the install info is up to date.\n\tensureInstallInfo()\n\n\t// Start broadcast notifier task.\n\tstartOnce.Do(func() {\n\t\tmodule.mgr.Repeat(\"broadcast notifier\", 10*time.Minute, broadcastNotify)\n\t})\n\n\treturn nil\n}\n\nvar (\n\tmodule     *Broadcasts\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Config module.\nfunc New(instance instance) (*Broadcasts, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Broadcasts\")\n\tmodule = &Broadcasts{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t\tstates:   m.NewStateMgr(),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tIntelUpdates() *updates.Updater\n}\n"
  },
  {
    "path": "service/broadcasts/notify.go",
    "content": "package broadcasts\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/ghodss/yaml\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/accessor\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nconst (\n\tbroadcastsResourceName = \"notifications.yaml\"\n\n\tbroadcastNotificationIDPrefix = \"broadcasts:\"\n\n\tminRepeatDuration = 1 * time.Hour\n)\n\n// Errors.\nvar (\n\tErrSkip                  = errors.New(\"broadcast skipped\")\n\tErrSkipDoesNotMatch      = fmt.Errorf(\"%w: does not match\", ErrSkip)\n\tErrSkipAlreadyActive     = fmt.Errorf(\"%w: already active\", ErrSkip)\n\tErrSkipAlreadyShown      = fmt.Errorf(\"%w: already shown\", ErrSkip)\n\tErrSkipRemovedByMismatch = fmt.Errorf(\"%w: removed due to mismatch\", ErrSkip)\n\tErrSkipRemovedBySource   = fmt.Errorf(\"%w: removed by source\", ErrSkip)\n)\n\n// BroadcastNotifications holds the data structure of the broadcast\n// notifications update file.\ntype BroadcastNotifications struct {\n\tNotifications map[string]*BroadcastNotification\n}\n\n// BroadcastNotification is a single broadcast notification.\ntype BroadcastNotification struct {\n\t*notifications.Notification\n\tid string\n\n\t// Match holds a query string that needs to match the local matching data in\n\t// order for the broadcast to be displayed.\n\tMatch         string\n\tmatchingQuery *query.Query\n\t// AttachToModule signifies if the broadcast notification should be attached to the module.\n\tAttachToModule bool\n\t// Remove signifies that the broadcast should be canceled and its state removed.\n\tRemove bool\n\t// Permanent signifies that the broadcast cannot be acknowledge by the user\n\t// and remains in the UI indefinitely.\n\tPermanent bool\n\t// Repeat specifies a duration after which the broadcast should be shown again.\n\tRepeat         string\n\trepeatDuration time.Duration\n}\n\nfunc broadcastNotify(ctx *mgr.WorkerCtx) error {\n\t// Get broadcast notifications file, load it from disk and parse it.\n\tbroadcastsResource, err := module.instance.IntelUpdates().GetFile(broadcastsResourceName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get broadcast notifications update: %w\", err)\n\t}\n\tbroadcastsData, err := os.ReadFile(broadcastsResource.Path())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to load broadcast notifications update: %w\", err)\n\t}\n\tbroadcasts, err := parseBroadcastSource(broadcastsData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse broadcast notifications update: %w\", err)\n\t}\n\n\t// Get and marshal matching data.\n\tmatchingData := collectData()\n\tmatchingJSON, err := json.Marshal(matchingData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal broadcast notifications matching data: %w\", err)\n\t}\n\tmatchingDataAccessor := accessor.NewJSONBytesAccessor(&matchingJSON)\n\n\t// Get broadcast notification states.\n\tbss, err := getBroadcastStates()\n\tif err != nil {\n\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\treturn fmt.Errorf(\"failed to get broadcast notifications states: %w\", err)\n\t\t}\n\t\tbss = newBroadcastStates()\n\t}\n\n\t// Go through all broadcast nofications and check if they match.\n\tfor _, bn := range broadcasts.Notifications {\n\t\terr := handleBroadcast(bn, matchingDataAccessor, bss)\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\tlog.Infof(\"broadcasts: displaying broadcast %s\", bn.id)\n\t\tcase errors.Is(err, ErrSkip):\n\t\t\tlog.Tracef(\"broadcasts: skipped displaying broadcast %s: %s\", bn.id, err)\n\t\tdefault:\n\t\t\tlog.Warningf(\"broadcasts: failed to handle broadcast %s: %s\", bn.id, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc parseBroadcastSource(yamlData []byte) (*BroadcastNotifications, error) {\n\t// Parse data.\n\tbroadcasts := &BroadcastNotifications{}\n\terr := yaml.Unmarshal(yamlData, broadcasts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Add IDs to struct for easier handling.\n\tfor id, bn := range broadcasts.Notifications {\n\t\tbn.id = id\n\n\t\t// Parse matching query.\n\t\tif bn.Match != \"\" {\n\t\t\tq, err := query.ParseQuery(\"query / where \" + bn.Match)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse query of broadcast notification %s: %w\", bn.id, err)\n\t\t\t}\n\t\t\tbn.matchingQuery = q\n\t\t}\n\n\t\t// Parse the repeat duration.\n\t\tif bn.Repeat != \"\" {\n\t\t\tduration, err := time.ParseDuration(bn.Repeat)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse repeat duration of broadcast notification %s: %w\", bn.id, err)\n\t\t\t}\n\t\t\tbn.repeatDuration = duration\n\t\t\t// Raise duration to minimum.\n\t\t\tif bn.repeatDuration < minRepeatDuration {\n\t\t\t\tbn.repeatDuration = minRepeatDuration\n\t\t\t}\n\t\t}\n\t}\n\n\treturn broadcasts, nil\n}\n\nfunc handleBroadcast(bn *BroadcastNotification, matchingDataAccessor accessor.Accessor, bss *BroadcastStates) error {\n\t// Check if broadcast was already shown.\n\tif bss != nil {\n\t\tstate, ok := bss.States[bn.id]\n\t\tswitch {\n\t\tcase !ok || state.Read.IsZero():\n\t\t\t// Was never shown, continue.\n\t\tcase bn.repeatDuration == 0:\n\t\t\t// Was already shown and is not repeated, skip.\n\t\t\treturn ErrSkipAlreadyShown\n\t\tcase time.Now().Before(state.Read.Add(bn.repeatDuration)):\n\t\t\t// Was already shown and should be repeated - but not yet, skip.\n\t\t\treturn ErrSkipAlreadyShown\n\t\t}\n\t}\n\n\t// Check if broadcast should be removed.\n\tif bn.Remove {\n\t\tremoveBroadcast(bn, bss)\n\t\treturn ErrSkipRemovedBySource\n\t}\n\n\t// Skip if broadcast does not match.\n\tif bn.matchingQuery != nil && !bn.matchingQuery.MatchesAccessor(matchingDataAccessor) {\n\t\tremoved := removeBroadcast(bn, bss)\n\t\tif removed {\n\t\t\treturn ErrSkipRemovedByMismatch\n\t\t}\n\t\treturn ErrSkipDoesNotMatch\n\t}\n\n\t// Check if there is already an active notification for this.\n\teventID := broadcastNotificationIDPrefix + bn.id\n\tn := notifications.Get(eventID)\n\tif n != nil {\n\t\t// Already active!\n\t\treturn ErrSkipAlreadyActive\n\t}\n\n\t// Prepare notification for displaying.\n\tn = bn.Notification\n\tn.EventID = eventID\n\tn.GUID = \"\"\n\tn.State = \"\"\n\tn.SelectedActionID = \"\"\n\n\t// It is okay to edit the notification, as they are loaded from the file every time.\n\t// Add dismiss button if the notification is not permanent.\n\tif !bn.Permanent {\n\t\tn.AvailableActions = append(n.AvailableActions, &notifications.Action{\n\t\t\tID:   \"ack\",\n\t\t\tText: \"Got it!\",\n\t\t})\n\t}\n\tn.SetActionFunction(markBroadcastAsRead)\n\n\t// Display notification.\n\tn.Save()\n\tif bn.AttachToModule {\n\t\tn.SyncWithState(module.states)\n\t}\n\n\treturn nil\n}\n\nfunc removeBroadcast(bn *BroadcastNotification, bss *BroadcastStates) (removed bool) {\n\t// Remove any active notification.\n\tn := notifications.Get(broadcastNotificationIDPrefix + bn.id)\n\tif n != nil {\n\t\tremoved = true\n\t\tn.Delete()\n\t}\n\n\t// Remove any state.\n\tif bss != nil {\n\t\tdelete(bss.States, bn.id)\n\t}\n\n\treturn\n}\n\nvar savingBroadcastStateLock sync.Mutex\n\nfunc markBroadcastAsRead(ctx context.Context, n *notifications.Notification) error {\n\t// Lock persisting broadcast state.\n\tsavingBroadcastStateLock.Lock()\n\tdefer savingBroadcastStateLock.Unlock()\n\n\t// Get notification data.\n\tvar broadcastID, actionID string\n\tfunc() {\n\t\tn.Lock()\n\t\tdefer n.Unlock()\n\t\tbroadcastID = strings.TrimPrefix(n.EventID, broadcastNotificationIDPrefix)\n\t\tactionID = n.SelectedActionID\n\t}()\n\n\t// Check response.\n\tswitch actionID {\n\tcase \"ack\":\n\tcase \"\":\n\t\treturn fmt.Errorf(\"no action ID for %s\", broadcastID)\n\tdefault:\n\t\treturn fmt.Errorf(\"unexpected action ID for %s: %s\", broadcastID, actionID)\n\t}\n\n\t// Get broadcast notification states.\n\tbss, err := getBroadcastStates()\n\tif err != nil {\n\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\treturn fmt.Errorf(\"failed to get broadcast notifications states: %w\", err)\n\t\t}\n\t\tbss = newBroadcastStates()\n\t}\n\n\t// Get state for this notification.\n\tbs, ok := bss.States[broadcastID]\n\tif !ok {\n\t\tbs = &BroadcastState{}\n\t\tbss.States[broadcastID] = bs\n\t}\n\n\t// Delete to allow for timely repeats.\n\tn.Delete()\n\n\t// Mark as read and save to DB.\n\tlog.Infof(\"broadcasts: user acknowledged broadcast %s\", broadcastID)\n\tbs.Read = time.Now()\n\treturn bss.save()\n}\n"
  },
  {
    "path": "service/broadcasts/state.go",
    "content": "package broadcasts\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nconst broadcastStatesDBKey = \"core:broadcasts/state\"\n\n// BroadcastStates holds states for broadcast notifications.\ntype BroadcastStates struct {\n\trecord.Base\n\tsync.Mutex\n\n\tStates map[string]*BroadcastState\n}\n\n// BroadcastState holds state for a single broadcast notifications.\ntype BroadcastState struct {\n\tRead time.Time\n}\n\nfunc (bss *BroadcastStates) save() error {\n\treturn db.Put(bss)\n}\n\n// getbroadcastStates returns the broadcast states from the database.\nfunc getBroadcastStates() (*BroadcastStates, error) {\n\tr, err := db.Get(broadcastStatesDBKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Unwrap.\n\tif r.IsWrapped() {\n\t\t// Only allocate a new struct, if we need it.\n\t\tnewRecord := &BroadcastStates{}\n\t\terr = record.Unwrap(r, newRecord)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newRecord, nil\n\t}\n\n\t// or adjust type\n\tnewRecord, ok := r.(*BroadcastStates)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *BroadcastStates, but %T\", r)\n\t}\n\treturn newRecord, nil\n}\n\n// newBroadcastStates returns a new BroadcastStates.\nfunc newBroadcastStates() *BroadcastStates {\n\tbss := &BroadcastStates{\n\t\tStates: make(map[string]*BroadcastState),\n\t}\n\tbss.SetKey(broadcastStatesDBKey)\n\n\treturn bss\n}\n"
  },
  {
    "path": "service/compat/api.go",
    "content": "package compat\n\nimport (\n\t\"github.com/safing/portmaster/base/api\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"compat/self-check\",\n\t\tRead:        api.PermitUser,\n\t\tActionFunc:  selfcheckViaAPI,\n\t\tName:        \"Run Integration Self-Check\",\n\t\tDescription: \"Runs a couple integration self-checks in order to see if the system integration works.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc selfcheckViaAPI(ar *api.Request) (msg string, err error) {\n\t_, err = selfcheck(ar.Context())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn \"self-check successful\", nil\n}\n"
  },
  {
    "path": "service/compat/callbacks.go",
    "content": "package compat\n\nimport (\n\t\"net\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/process\"\n)\n\n// SubmitSystemIntegrationCheckPacket submit a packet for the system integrity check.\nfunc SubmitSystemIntegrationCheckPacket(p packet.Packet) {\n\tselect {\n\tcase systemIntegrationCheckPackets <- p:\n\tdefault:\n\t}\n}\n\n// SubmitDNSCheckDomain submits a subdomain for the dns check.\nfunc SubmitDNSCheckDomain(subdomain string) (respondWith net.IP) {\n\t// Submit queried domain.\n\tselect {\n\tcase dnsCheckReceivedDomain <- subdomain:\n\tdefault:\n\t}\n\n\t// Return the answer.\n\tdnsCheckAnswerLock.Lock()\n\tdefer dnsCheckAnswerLock.Unlock()\n\treturn dnsCheckAnswer\n}\n\n// ReportSecureDNSBypassIssue reports a DNS bypassing issue for the given process.\nfunc ReportSecureDNSBypassIssue(p *process.Process) {\n\tmodule.mgr.Go(\"report secure dns bypass issue\", func(w *mgr.WorkerCtx) error {\n\t\tsecureDNSBypassIssue.notify(p)\n\t\treturn nil\n\t})\n}\n\n// ReportMultiPeerUDPTunnelIssue reports a multi-peer UDP tunnel for the given process.\nfunc ReportMultiPeerUDPTunnelIssue(p *process.Process) {\n\tmodule.mgr.Go(\"report multi-peer udp tunnel issue\", func(w *mgr.WorkerCtx) error {\n\t\tmultiPeerUDPTunnelIssue.notify(p)\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "service/compat/debug_default.go",
    "content": "//go:build !windows && !linux\n\npackage compat\n\nimport \"github.com/safing/portmaster/base/utils/debug\"\n\n// AddToDebugInfo adds compatibility data to the given debug.Info.\nfunc AddToDebugInfo(di *debug.Info) {\n\t// Not yet implemented on this platform.\n}\n"
  },
  {
    "path": "service/compat/debug_linux.go",
    "content": "package compat\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/utils/debug\"\n)\n\n// AddToDebugInfo adds compatibility data to the given debug.Info.\nfunc AddToDebugInfo(di *debug.Info) {\n\t// Get iptables state and add error info if it fails.\n\tchains, err := GetIPTablesChains()\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Compatibility: IPTables Chains (failed)\",\n\t\t\tdebug.UseCodeSection,\n\t\t\terr.Error(),\n\t\t)\n\t\treturn\n\t}\n\n\t// Add data as section.\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Compatibility: IPTables Chains (%d)\", len(chains)-10),\n\t\tdebug.UseCodeSection|debug.AddContentLineBreaks,\n\t\tchains...,\n\t)\n}\n"
  },
  {
    "path": "service/compat/debug_windows.go",
    "content": "package compat\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/utils/debug\"\n)\n\n// AddToDebugInfo adds compatibility data to the given debug.Info.\nfunc AddToDebugInfo(di *debug.Info) {\n\t// Get WFP state and add error info if it fails.\n\twfp, err := GetWFPState()\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Compatibility: WFP State (failed)\",\n\t\t\tdebug.UseCodeSection,\n\t\t\terr.Error(),\n\t\t)\n\t\treturn\n\t}\n\n\t// Add data as section.\n\twfpTable := wfp.AsTable()\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Compatibility: WFP State (%d)\", strings.Count(wfpTable, \"\\n\")),\n\t\tdebug.UseCodeSection,\n\t\twfpTable,\n\t)\n}\n"
  },
  {
    "path": "service/compat/iptables.go",
    "content": "//go:build linux\n\npackage compat\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/coreos/go-iptables/iptables\"\n)\n\nvar (\n\tiptProtocols = []iptables.Protocol{\n\t\tiptables.ProtocolIPv4,\n\t\tiptables.ProtocolIPv6,\n\t}\n\tiptTables = []string{\n\t\t\"filter\",\n\t\t\"nat\",\n\t\t\"mangle\",\n\t\t\"raw\",\n\t}\n)\n\n// GetIPTablesChains returns the chain names currently in ip(6)tables.\nfunc GetIPTablesChains() ([]string, error) {\n\tchains := make([]string, 0, 100)\n\n\t// Iterate over protocols.\n\tfor _, protocol := range iptProtocols {\n\t\tif protocol == iptables.ProtocolIPv4 {\n\t\t\tchains = append(chains, \"v4\")\n\t\t} else {\n\t\t\tchains = append(chains, \"v6\")\n\t\t}\n\n\t\t// Get iptables access for protocol.\n\t\ttbls, err := iptables.NewWithProtocol(protocol)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Iterate over tables.\n\t\tfor _, table := range iptTables {\n\t\t\tchains = append(chains, \"  \"+table)\n\n\t\t\t// Get chain names\n\t\t\tchainNames, err := tbls.ListChains(table)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get chains of table %s: %w\", table, err)\n\t\t\t}\n\n\t\t\t// Add chain names to list.\n\t\t\tfor _, name := range chainNames {\n\t\t\t\tchains = append(chains, \"    \"+name)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chains, nil\n}\n"
  },
  {
    "path": "service/compat/iptables_test.go",
    "content": "//go:build linux\n\npackage compat\n\nimport (\n\t\"testing\"\n)\n\nfunc TestIPTablesChains(t *testing.T) {\n\t// Skip in CI.\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\tt.Parallel()\n\n\tchain, err := GetIPTablesChains()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(chain) < 35 {\n\t\tt.Errorf(\"Expected at least 35 output lines, not %d\", len(chain))\n\t}\n}\n"
  },
  {
    "path": "service/compat/module.go",
    "content": "package compat\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\n// Compat is the compatibility check module.\ntype Compat struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tselfcheckWorkerMgr            *mgr.WorkerMgr\n\tcleanNotifyThresholdWorkerMgr *mgr.WorkerMgr\n\n\tstates *mgr.StateMgr\n}\n\n// Manager returns the module manager.\nfunc (u *Compat) Manager() *mgr.Manager {\n\treturn u.mgr\n}\n\n// States returns the module state manager.\nfunc (u *Compat) States() *mgr.StateMgr {\n\treturn u.states\n}\n\n// Start starts the module.\nfunc (u *Compat) Start() error {\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (u *Compat) Stop() error {\n\treturn stop()\n}\n\nvar (\n\tselfcheckTaskRetryAfter = 15 * time.Second\n\n\t// selfCheckIsFailing holds whether or not the self-check is currently\n\t// failing. This helps other failure systems to not make noise when there is\n\t// an underlying failure.\n\tselfCheckIsFailing = abool.New()\n\n\t// selfcheckFails counts how often the self check failed successively.\n\t// selfcheckFails is not locked as it is only accessed by the self-check task.\n\tselfcheckFails int\n\n\t// selfcheckNetworkChangedFlag is used to track changed to the network for\n\t// the self-check.\n\tselfcheckNetworkChangedFlag = netenv.GetNetworkChangedFlag()\n)\n\n// selfcheckFailThreshold holds the threshold of how many times the selfcheck\n// must fail before it is reported.\nconst selfcheckFailThreshold = 10\n\nfunc init() {\n\t// Workaround resolver integration.\n\t// See resolver/compat.go for details.\n\tresolver.CompatDNSCheckInternalDomainScope = DNSCheckInternalDomainScope\n\tresolver.CompatSelfCheckIsFailing = SelfCheckIsFailing\n\tresolver.CompatSubmitDNSCheckDomain = SubmitDNSCheckDomain\n}\n\nfunc prep() error {\n\treturn registerAPIEndpoints()\n}\n\nfunc start() error {\n\t// Create fresh worker managers on Start() to enable clean restarts after Stop().\n\t// (after module.Manager().Stop() has been called, all workers are stopped and cannot be reused)\n\tmodule.selfcheckWorkerMgr = module.Manager().NewWorkerMgr(\"compatibility self-check\", selfcheckTaskFunc, nil)\n\tmodule.cleanNotifyThresholdWorkerMgr = module.Manager().NewWorkerMgr(\"clean notify thresholds\", cleanNotifyThreshold, nil)\n\n\tstartNotify()\n\n\tselfcheckNetworkChangedFlag.Refresh()\n\n\t// Schedule periodic self-checks.\n\tmodule.selfcheckWorkerMgr.Repeat(5 * time.Minute).Delay(selfcheckTaskRetryAfter)\n\tmodule.cleanNotifyThresholdWorkerMgr.Repeat(1 * time.Hour)\n\n\t// Add network change callback to trigger immediate self-check.\n\tmodule.instance.NetEnv().EventNetworkChange.AddCallback(\"trigger compat self-check\", func(_ *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\tmodule.selfcheckWorkerMgr.Delay(selfcheckTaskRetryAfter)\n\t\treturn false, nil\n\t})\n\treturn nil\n}\n\nfunc stop() error {\n\tresetSelfCheckState()\n\treturn nil\n}\n\nfunc selfcheckTaskFunc(wc *mgr.WorkerCtx) error {\n\n\t// Create tracing logger.\n\tctx, tracer := log.AddTracer(wc.Ctx())\n\tdefer tracer.Submit()\n\ttracer.Tracef(\"compat: running self-check\")\n\n\t// Run selfcheck and return if successful.\n\tissue, err := selfcheck(ctx)\n\tswitch {\n\tcase err == nil:\n\t\t// Successful.\n\t\ttracer.Debugf(\"compat: self-check successful\")\n\tcase errors.Is(err, errSelfcheckSkipped):\n\t\t// Skipped.\n\t\ttracer.Debugf(\"compat: %s\", err)\n\tcase issue == nil:\n\t\t// Internal error.\n\t\ttracer.Warningf(\"compat: %s\", err)\n\tcase selfcheckNetworkChangedFlag.IsSet():\n\t\t// The network changed, ignore the issue.\n\tdefault:\n\t\t// The self-check failed.\n\n\t\t// Set state and increase counter.\n\t\tselfCheckIsFailing.Set()\n\t\tselfcheckFails++\n\n\t\t// Log and notify.\n\t\ttracer.Errorf(\"compat: %s\", err)\n\t\tif selfcheckFails >= selfcheckFailThreshold {\n\t\t\tissue.notify(err)\n\t\t}\n\n\t\t// Retry quicker when failed.\n\t\tmodule.selfcheckWorkerMgr.Delay(selfcheckTaskRetryAfter)\n\n\t\treturn nil\n\t}\n\n\t// Reset self-check state.\n\tresetSelfCheckState()\n\n\treturn nil\n}\n\nfunc resetSelfCheckState() {\n\tselfcheckNetworkChangedFlag.Refresh()\n\tselfCheckIsFailing.UnSet()\n\tselfcheckFails = 0\n\tresetSystemIssue()\n}\n\n// SelfCheckIsFailing returns whether the self check is currently failing.\n// This returns true after the first check fails, and does not wait for the\n// failing threshold to be met.\nfunc SelfCheckIsFailing() bool {\n\treturn selfCheckIsFailing.IsSet()\n}\n\nvar (\n\tmodule     *Compat\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Compat module.\nfunc New(instance instance) (*Compat, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Compat\")\n\tmodule = &Compat{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t\tstates:   mgr.NewStateMgr(m),\n\t}\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tNetEnv() *netenv.NetEnv\n\tResolver() *resolver.ResolverModule\n}\n"
  },
  {
    "path": "service/compat/notify.go",
    "content": "package compat\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\ntype baseIssue struct {\n\tid      string                  //nolint:structcheck // Inherited.\n\ttitle   string                  //nolint:structcheck // Inherited.\n\tmessage string                  //nolint:structcheck // Inherited.\n\tlevel   notifications.Type      //nolint:structcheck // Inherited.\n\tactions []*notifications.Action //nolint:structcheck // Inherited.\n}\n\ntype systemIssue baseIssue\n\ntype appIssue baseIssue\n\nvar (\n\t// Copy of firewall.CfgOptionDNSQueryInterceptionKey.\n\tcfgOptionDNSQueryInterceptionKey = \"filter/dnsQueryInterception\"\n\tdnsQueryInterception             config.BoolOption\n\n\tsystemIssueNotification     *notifications.Notification\n\tsystemIssueNotificationLock sync.Mutex\n\n\tsystemIntegrationIssue = &systemIssue{\n\t\tid:      \"compat:system-integration-issue\",\n\t\ttitle:   \"Detected System Integration Issue\",\n\t\tmessage: \"Portmaster detected a problem with its system integration. You can try to restart or reinstall the Portmaster. If that does not help, [get support here](https://safing.io/support/).\",\n\t\tlevel:   notifications.Error,\n\t}\n\tsystemCompatibilityIssue = &systemIssue{\n\t\tid:      \"compat:compatibility-issue\",\n\t\ttitle:   \"Detected Compatibility Issue\",\n\t\tmessage: \"Portmaster detected that something is interfering with its operation. This could be a VPN, an Anti-Virus or another network protection software. Please check if you are running an incompatible [VPN client](https://docs.safing.io/portmaster/install/status/vpn-compatibility) or [software](https://docs.safing.io/portmaster/install/status/software-compatibility) and disable it. If that does not help, [get support here](https://safing.io/support/).\",\n\t\tlevel:   notifications.Error,\n\t}\n\t// manualDNSSetupRequired is additionally initialized in startNotify().\n\tmanualDNSSetupRequired = &systemIssue{\n\t\tid:    \"compat:manual-dns-setup-required\",\n\t\ttitle: \"Manual DNS Setup Required\",\n\t\tlevel: notifications.Error,\n\t\tactions: []*notifications.Action{\n\t\t\t{\n\t\t\t\tText: \"Revert\",\n\t\t\t\tType: notifications.ActionTypeOpenSetting,\n\t\t\t\tPayload: &notifications.ActionTypeOpenSettingPayload{\n\t\t\t\t\tKey: cfgOptionDNSQueryInterceptionKey,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tmanualDNSSetupRequiredMessage = \"You have disabled Seamless DNS Integration. As a result, Portmaster can no longer protect you or filter connections reliably. To fix this, you have to manually configure %s as the DNS Server in your system and in any conflicting application. This message will disappear some time after correct configuration.\"\n\n\tsecureDNSBypassIssue = &appIssue{\n\t\tid:      \"compat:secure-dns-bypass-%s\",\n\t\ttitle:   \"Blocked Bypass Attempt by %s\",\n\t\tmessage: `[APPNAME] is using its own Secure DNS resolver, which would bypass Portmaster's firewall protections. If [APPNAME] experiences problems, disable Secure DNS within [APPNAME] to restore functionality. Rest assured that Portmaster handles Secure DNS for your whole device, including [APPNAME].`,\n\t\t// TODO: Add this when the new docs page is finished:\n\t\t// , or [find out about other options](link to new docs page)\n\t\tlevel: notifications.Warning,\n\t}\n\tmultiPeerUDPTunnelIssue = &appIssue{\n\t\tid:      \"compat:multi-peer-udp-tunnel-%s\",\n\t\ttitle:   \"Detected SPN Incompatibility in %s\",\n\t\tmessage: \"Portmaster detected that [APPNAME] is trying to connect to multiple servers via the SPN using a single UDP connection. This is common for technologies such as torrents. Unfortunately, the SPN does not support this feature currently. You can try to change this behavior within the affected app or you could exempt it from using the SPN.\",\n\t\tlevel:   notifications.Warning,\n\t}\n)\n\nfunc startNotify() {\n\tdnsQueryInterception = config.Concurrent.GetAsBool(cfgOptionDNSQueryInterceptionKey, true)\n\n\tsystemIssueNotificationLock.Lock()\n\tdefer systemIssueNotificationLock.Unlock()\n\n\tmanualDNSSetupRequired.message = fmt.Sprintf(\n\t\tmanualDNSSetupRequiredMessage,\n\t\t`\"127.0.0.1\"`,\n\t)\n}\n\n// SetNameserverListenIP sets the IP address the nameserver is listening on.\n// The IP address is used in compatibility notifications.\nfunc SetNameserverListenIP(ip net.IP) {\n\tsystemIssueNotificationLock.Lock()\n\tdefer systemIssueNotificationLock.Unlock()\n\n\tmanualDNSSetupRequired.message = fmt.Sprintf(\n\t\tmanualDNSSetupRequiredMessage,\n\t\t`\"`+ip.String()+`\"`,\n\t)\n}\n\nfunc systemCompatOrManualDNSIssue() *systemIssue {\n\tif dnsQueryInterception() {\n\t\treturn systemCompatibilityIssue\n\t}\n\treturn manualDNSSetupRequired\n}\n\nfunc (issue *systemIssue) notify(err error) { //nolint // TODO: Should we use the error?\n\tsystemIssueNotificationLock.Lock()\n\tdefer systemIssueNotificationLock.Unlock()\n\n\tif systemIssueNotification != nil {\n\t\t// Ignore duplicate notification.\n\t\tif issue.id == systemIssueNotification.EventID {\n\t\t\treturn\n\t\t}\n\n\t\t// Remove old notification.\n\t\tsystemIssueNotification.Delete()\n\t}\n\n\t// Create new notification.\n\tn := &notifications.Notification{\n\t\tEventID:          issue.id,\n\t\tType:             issue.level,\n\t\tTitle:            issue.title,\n\t\tMessage:          issue.message,\n\t\tShowOnSystem:     true,\n\t\tAvailableActions: issue.actions,\n\t}\n\tnotifications.Notify(n)\n\n\tsystemIssueNotification = n\n\tn.SyncWithState(module.states)\n}\n\nfunc resetSystemIssue() {\n\tsystemIssueNotificationLock.Lock()\n\tdefer systemIssueNotificationLock.Unlock()\n\n\tif systemIssueNotification != nil {\n\t\tsystemIssueNotification.Delete()\n\t}\n\tsystemIssueNotification = nil\n}\n\nfunc (issue *appIssue) notify(proc *process.Process) {\n\t// Get profile from process.\n\tp := proc.Profile().LocalProfile()\n\tif p == nil {\n\t\treturn\n\t}\n\n\t// Ignore notifications for unidentified processes.\n\tif p.ID == profile.UnidentifiedProfileID {\n\t\treturn\n\t}\n\n\t// Log warning.\n\tlog.Warningf(\n\t\t\"compat: detected %s issue with %s\",\n\t\tstrings.ReplaceAll(\n\t\t\tstrings.TrimPrefix(\n\t\t\t\tstrings.TrimSuffix(issue.id, \"-%s\"),\n\t\t\t\t\"compat:\",\n\t\t\t),\n\t\t\t\"-\", \" \",\n\t\t),\n\t\tproc.Path,\n\t)\n\n\t// Check if we already have this notification.\n\teventID := fmt.Sprintf(issue.id, p.ID)\n\tn := notifications.Get(eventID)\n\tif n != nil {\n\t\treturn\n\t}\n\n\t// Check if we reach the threshold to actually send a notification.\n\tif !isOverThreshold(eventID) {\n\t\treturn\n\t}\n\n\t// Build message.\n\tmessage := strings.ReplaceAll(issue.message, \"[APPNAME]\", p.Name)\n\n\t// Create a new notification.\n\tn = &notifications.Notification{\n\t\tEventID:          eventID,\n\t\tType:             issue.level,\n\t\tTitle:            fmt.Sprintf(issue.title, p.Name),\n\t\tMessage:          message,\n\t\tShowOnSystem:     true,\n\t\tAvailableActions: issue.actions,\n\t}\n\tif len(n.AvailableActions) == 0 {\n\t\tn.AvailableActions = []*notifications.Action{\n\t\t\t{\n\t\t\t\tID:   \"ack\",\n\t\t\t\tText: \"OK\",\n\t\t\t},\n\t\t}\n\t}\n\tnotifications.Notify(n)\n\n\t// Set warning on profile.\n\tmodule.mgr.Go(\"set app compat warning\", func(ctx *mgr.WorkerCtx) error {\n\t\tvar changed bool\n\n\t\tfunc() {\n\t\t\tp.Lock()\n\t\t\tdefer p.Unlock()\n\n\t\t\tif p.Warning != message || time.Now().Add(-1*time.Hour).After(p.WarningLastUpdated) {\n\t\t\t\tp.Warning = message\n\t\t\t\tp.WarningLastUpdated = time.Now()\n\t\t\t\tchanged = true\n\t\t\t}\n\t\t}()\n\n\t\tif changed {\n\t\t\treturn p.Save()\n\t\t}\n\t\treturn nil\n\t})\n}\n\nconst (\n\tnotifyThresholdMinIncidents = 10\n\tnotifyThresholdResetAfter   = 2 * time.Minute\n)\n\nvar (\n\tnotifyThresholds     = make(map[string]*notifyThreshold)\n\tnotifyThresholdsLock sync.Mutex\n)\n\ntype notifyThreshold struct {\n\tFirstSeen time.Time\n\tIncidents uint\n}\n\nfunc (nt *notifyThreshold) expired() bool {\n\treturn time.Now().Add(-notifyThresholdResetAfter).After(nt.FirstSeen)\n}\n\nfunc isOverThreshold(id string) bool {\n\tnotifyThresholdsLock.Lock()\n\tdefer notifyThresholdsLock.Unlock()\n\n\t// Get notify threshold and check if we reach the minimum incidents.\n\tnt, ok := notifyThresholds[id]\n\tif ok && !nt.expired() {\n\t\tnt.Incidents++\n\t\treturn nt.Incidents >= notifyThresholdMinIncidents\n\t}\n\n\t// Add new entry.\n\tnotifyThresholds[id] = &notifyThreshold{\n\t\tFirstSeen: time.Now(),\n\t\tIncidents: 1,\n\t}\n\treturn false\n}\n\nfunc cleanNotifyThreshold(ctx *mgr.WorkerCtx) error {\n\tnotifyThresholdsLock.Lock()\n\tdefer notifyThresholdsLock.Unlock()\n\n\tfor id, nt := range notifyThresholds {\n\t\tif nt.expired() {\n\t\t\tdelete(notifyThresholds, id)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/compat/selfcheck.go",
    "content": "package compat\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\nvar (\n\tselfcheckLock sync.Mutex\n\n\t// SystemIntegrationCheckDstIP is the IP address to send a packet to for the\n\t// system integration test.\n\tSystemIntegrationCheckDstIP = net.IPv4(127, 65, 67, 75)\n\t// SystemIntegrationCheckProtocol is the IP protocol to use for the system\n\t// integration test.\n\tSystemIntegrationCheckProtocol = packet.AnyHostInternalProtocol61\n\n\tsystemIntegrationCheckDialNet      = fmt.Sprintf(\"ip4:%d\", uint8(SystemIntegrationCheckProtocol))\n\tsystemIntegrationCheckDialIP       = SystemIntegrationCheckDstIP.String()\n\tsystemIntegrationCheckPackets      = make(chan packet.Packet, 1)\n\tsystemIntegrationCheckWaitDuration = 45 * time.Second\n\n\t// DNSCheckInternalDomainScope is the domain scope to use for dns checks.\n\tDNSCheckInternalDomainScope = \".self-check.\" + resolver.InternalSpecialUseDomain\n\tdnsCheckReceivedDomain      = make(chan string, 1)\n\tdnsCheckWaitDuration        = 45 * time.Second\n\tdnsCheckAnswerLock          sync.Mutex\n\tdnsCheckAnswer              net.IP\n\n\terrSelfcheckSkipped = errors.New(\"self-check skipped\")\n)\n\nfunc selfcheck(ctx context.Context) (issue *systemIssue, err error) {\n\tselfcheckLock.Lock()\n\tdefer selfcheckLock.Unlock()\n\n\t// Step 0: Check if self-check makes sense.\n\tif !netenv.Online() {\n\t\treturn nil, fmt.Errorf(\"%w: device is offline or in limited network\", errSelfcheckSkipped)\n\t}\n\n\t// Step 1: Check if the system integration sees a packet.\n\n\t// Empty recv channel.\n\tselect {\n\tcase <-systemIntegrationCheckPackets:\n\tcase <-ctx.Done():\n\t\treturn nil, context.Canceled\n\tdefault:\n\t}\n\n\t// Send packet.\n\tconn, err := net.DialTimeout(\n\t\tsystemIntegrationCheckDialNet,\n\t\tsystemIntegrationCheckDialIP,\n\t\ttime.Second,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create system integration conn: %w\", err)\n\t}\n\t_, err = conn.Write([]byte(\"PORTMASTER SELF CHECK\"))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to send system integration packet: %w\", err)\n\t}\n\n\t// Wait for packet.\n\tselect {\n\tcase <-systemIntegrationCheckPackets:\n\t\t// Check passed!\n\t\tlog.Tracer(ctx).Tracef(\"compat: self-check #1: system integration check passed\")\n\tcase <-time.After(systemIntegrationCheckWaitDuration):\n\t\treturn systemIntegrationIssue, fmt.Errorf(\"self-check #1: system integration check failed: did not receive test packet after %s\", systemIntegrationCheckWaitDuration)\n\tcase <-ctx.Done():\n\t\treturn nil, context.Canceled\n\t}\n\n\t// Step 2: Check if a DNS request arrives at the nameserver\n\t// This step necessary also includes some setup for step 3.\n\n\t// Generate random subdomain.\n\trandomSubdomainBytes, err := rng.Bytes(16)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"self-check #2: failed to get random bytes for subdomain check: %w\", err)\n\t}\n\trandomSubdomain := \"a\" + strings.ToLower(hex.EncodeToString(randomSubdomainBytes)) + \"b\"\n\n\t// Generate random answer.\n\tvar B, C, D uint64\n\tB, err = rng.Number(255)\n\tif err == nil {\n\t\tC, err = rng.Number(255)\n\t}\n\tif err == nil {\n\t\tD, err = rng.Number(255)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"self-check #2: failed to get random number for subdomain check response: %w\", err)\n\t}\n\trandomAnswer := net.IPv4(127, byte(B), byte(C), byte(D))\n\tfunc() {\n\t\tdnsCheckAnswerLock.Lock()\n\t\tdefer dnsCheckAnswerLock.Unlock()\n\t\tdnsCheckAnswer = randomAnswer\n\t}()\n\n\t// Setup variables for lookup worker.\n\tvar (\n\t\tdnsCheckReturnedIP  net.IP\n\t\tdnsCheckLookupError = make(chan error)\n\t)\n\n\t// Empty recv channel.\n\tselect {\n\tcase <-dnsCheckReceivedDomain:\n\tcase <-ctx.Done():\n\t\treturn nil, context.Canceled\n\tdefault:\n\t}\n\n\t// Start worker for the DNS lookup.\n\tmodule.mgr.Go(\"dns check lookup\", func(_ *mgr.WorkerCtx) error {\n\t\tips, err := net.LookupIP(randomSubdomain + DNSCheckInternalDomainScope)\n\t\tif err == nil && len(ips) > 0 {\n\t\t\tdnsCheckReturnedIP = ips[0]\n\t\t}\n\t\tselect {\n\t\tcase dnsCheckLookupError <- err:\n\t\tcase <-time.After(dnsCheckWaitDuration * 2):\n\t\tcase <-ctx.Done():\n\t\t}\n\n\t\treturn nil\n\t})\n\n\t// Wait for the resolver to receive the query.\n\tselect {\n\tcase receivedTestDomain := <-dnsCheckReceivedDomain:\n\t\tif receivedTestDomain != randomSubdomain {\n\t\t\treturn systemCompatOrManualDNSIssue(), fmt.Errorf(\"self-check #2: dns integration check failed: received unmatching subdomain %q\", receivedTestDomain)\n\t\t}\n\tcase <-time.After(dnsCheckWaitDuration):\n\t\treturn systemCompatOrManualDNSIssue(), fmt.Errorf(\"self-check #2: dns integration check failed: did not receive test query after %s\", dnsCheckWaitDuration)\n\t}\n\tlog.Tracer(ctx).Tracef(\"compat: self-check #2: dns integration query check passed\")\n\n\t// Step 3: Have the nameserver respond with random data in the answer section.\n\n\t// Check if the resolver is enabled\n\tif module.instance.Resolver().IsDisabled() {\n\t\t// There is no control over the response, there is nothing more that can be checked.\n\t\treturn nil, nil\n\t}\n\n\t// Wait for the reply from the resolver.\n\tselect {\n\tcase err := <-dnsCheckLookupError:\n\t\tif err != nil {\n\t\t\treturn systemCompatibilityIssue, fmt.Errorf(\"self-check #3: dns integration check failed: failed to receive test response: %w\", err)\n\t\t}\n\tcase <-time.After(dnsCheckWaitDuration):\n\t\treturn systemCompatibilityIssue, fmt.Errorf(\"self-check #3: dns integration check failed: did not receive test response after %s\", dnsCheckWaitDuration)\n\tcase <-ctx.Done():\n\t\treturn nil, context.Canceled\n\t}\n\n\t// Check response.\n\tif !dnsCheckReturnedIP.Equal(randomAnswer) {\n\t\treturn systemCompatibilityIssue, fmt.Errorf(\"self-check #3: dns integration check failed: received unmatching response %q\", dnsCheckReturnedIP)\n\t}\n\tlog.Tracer(ctx).Tracef(\"compat: self-check #3: dns integration response check passed\")\n\n\treturn nil, nil\n}\n\n/*\n\n*   Check if the system integration sees a packet:\n    *   Send raw IP packet with random content and protocol, report finding to compat module.\n        *   use `Dial(\"ip4:61\", \"127.65.67.75\")`.\n        *   Firewall reports back the data seen on `ip4:61` to IP `127.65.67.75`.\n        *   If this fails, the system integration is broken. -&gt; Integration Issue\n*   Check if a DNS request arrives at the nameserver:\n    *   Send A question for `[random-subdomain].self-check.portmaster.home.arpa.`.\n    *   Nameserver reports back the data seen.\n    *   If this fails, redirection to the nameserver fails.\n        *   This means there is another software interfering with DNS. -&gt; Compatibility Issue\n*   Have the nameserver respond with random data in the answer section.\n    *   Compat provides nameserver with random response data.\n    *   Compat module checks if the received data matches.\n    *   If this fails, redirection to the nameserver fails.\n        *   This means there is another software interfering with DNS on the return path. -&gt; Compatibility Issue\n*   DROPPED: If resolvers are reported failing, but we are online:\n    *   Send out plain DNS requests to one.one.one.one. and dns.quad9.net via the Go standard lookup and check if the responses are correct.\n    *   If not, something is blocking the Portmaster -&gt; Secure DNS Issue\n    *   Discuss if this is necessary:\n        *   Does this improve from only having a failed TCP connection to the resolver?\n        *   Could another program block port 853, but fully leave requests for one.one.one.one. to port 53 alone?\n\n*/\n"
  },
  {
    "path": "service/compat/wfpstate.go",
    "content": "package compat\n\nimport (\n\t\"bytes\"\n\t\"encoding/xml\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/safing/portmaster/base/utils/osdetail\"\n)\n\n// GetWFPState queries the system for the WFP state and returns a simplified\n// and cleaned version.\nfunc GetWFPState() (*SimplifiedWFPState, error) {\n\t// Use a file to get the wfp state, as the terminal isn't able to return the\n\t// data encoded in UTF-8.\n\ttmpDir, err := os.MkdirTemp(\"\", \"portmaster-debug-data-wfpstate\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create tmp dir for wfpstate: %w\", err)\n\t}\n\tdefer func() {\n\t\t_ = os.RemoveAll(tmpDir)\n\t}()\n\ttmpFile := filepath.Join(tmpDir, \"wfpstate.xml\")\n\n\t// Get wfp state and write it to the tmp file.\n\t_, err = osdetail.RunCmd(\n\t\t\"netsh.exe\",\n\t\t\"wfp\",\n\t\t\"show\",\n\t\t\"state\",\n\t\ttmpFile,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write wfp state to tmp file: %w\", err)\n\t}\n\n\t// Get tmp file contents.\n\toutput, err := os.ReadFile(tmpFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read wfp state to tmp file: %w\", err)\n\t}\n\tif len(output) == 0 {\n\t\treturn nil, errors.New(\"wfp state tmp file was empty\")\n\t}\n\n\t// Parse wfp state.\n\tparsedState, err := parseWFPState(output)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse wfpstate: %w\", err)\n\t}\n\n\t// Return simplified and cleaned state.\n\treturn parsedState.simplified(), nil\n}\n\n/*\nInteresting data is found at:\n\nproviders->item[]\n\t->displayData->name\n\t->displayData->description\n\t->providerKey\n\nsubLayers->item[]\n\t->displayData->name\n\t->displayData->description\n\t->subLayerKey\n\nlayers->item[]->callouts->item[]\n\t->displayData->name\n\t->displayData->description\n\t->calloutKey\n\t->providerKey\n\t->applicableLayer\n\nlayers->item[]->filters->item[]\n\t->displayData->name\n\t->displayData->description\n\t->filterKey\n\t->providerKey\n\t->layerKey\n\t->subLayerKey\n*/\n\n// SimplifiedWFPState is a simplified version of the full WFP state.\ntype SimplifiedWFPState struct {\n\tProviders []*WFPProvider\n\tSubLayers []*WFPSubLayer\n\tCallouts  []*WFPCallout\n\tFilters   []*WFPFilter\n}\n\n// WFPProvider represents a WFP Provider.\ntype WFPProvider struct {\n\tName        string\n\tDescription string\n\tProviderKey string\n}\n\n// WFPSubLayer represents a WFP SubLayer.\ntype WFPSubLayer struct {\n\tName        string\n\tDescription string\n\tSubLayerKey string\n}\n\n// WFPCallout represents a WFP Callout.\ntype WFPCallout struct {\n\tName            string\n\tDescription     string\n\tCalloutKey      string\n\tProviderKey     string\n\tApplicableLayer string\n}\n\n// WFPFilter represents a WFP Filter.\ntype WFPFilter struct {\n\tName        string\n\tDescription string\n\tFilterKey   string\n\tProviderKey string\n\tLayerKey    string\n\tSubLayerKey string\n}\n\n// Keys returns all keys found in the WFP state.\nfunc (sw *SimplifiedWFPState) Keys() map[string]struct{} {\n\tlookupMap := make(map[string]struct{}, len(sw.Providers)+len(sw.SubLayers)+len(sw.Callouts)+len(sw.Filters))\n\n\t// Collect keys.\n\tfor _, provider := range sw.Providers {\n\t\tlookupMap[provider.ProviderKey] = struct{}{}\n\t}\n\tfor _, subLayer := range sw.SubLayers {\n\t\tlookupMap[subLayer.SubLayerKey] = struct{}{}\n\t}\n\tfor _, callout := range sw.Callouts {\n\t\tlookupMap[callout.CalloutKey] = struct{}{}\n\t}\n\tfor _, filter := range sw.Filters {\n\t\tlookupMap[filter.FilterKey] = struct{}{}\n\t}\n\n\treturn lookupMap\n}\n\n// AsTable formats the simplified WFP state as a table.\nfunc (sw *SimplifiedWFPState) AsTable() string {\n\trows := make([]string, 0, len(sw.Providers)+len(sw.SubLayers)+len(sw.Callouts)+len(sw.Filters))\n\n\t// Collect data and put it into rows.\n\tfor _, provider := range sw.Providers {\n\t\trows = append(rows, strings.Join([]string{\n\t\t\tprovider.Name,\n\t\t\t\"Provider\",\n\t\t\tprovider.Description,\n\t\t\tprovider.ProviderKey,\n\t\t}, \"\\t\"))\n\t}\n\tfor _, subLayer := range sw.SubLayers {\n\t\trows = append(rows, strings.Join([]string{\n\t\t\tsubLayer.Name,\n\t\t\t\"SubLayer\",\n\t\t\tsubLayer.Description,\n\t\t\tsubLayer.SubLayerKey,\n\t\t}, \"\\t\"))\n\t}\n\tfor _, callout := range sw.Callouts {\n\t\trows = append(rows, strings.Join([]string{\n\t\t\tcallout.Name,\n\t\t\t\"Callout\",\n\t\t\tcallout.Description,\n\t\t\tcallout.CalloutKey,\n\t\t\tcallout.ProviderKey,\n\t\t\tcallout.ApplicableLayer,\n\t\t}, \"\\t\"))\n\t}\n\tfor _, filter := range sw.Filters {\n\t\trows = append(rows, strings.Join([]string{\n\t\t\tfilter.Name,\n\t\t\t\"Filter\",\n\t\t\tfilter.Description,\n\t\t\tfilter.FilterKey,\n\t\t\tfilter.ProviderKey,\n\t\t\tfilter.LayerKey,\n\t\t\tfilter.SubLayerKey,\n\t\t}, \"\\t\"))\n\t}\n\n\t// Sort and build table.\n\tsort.Strings(rows)\n\tbuf := bytes.NewBuffer(nil)\n\ttabWriter := tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)\n\tfor _, row := range rows {\n\t\tfmt.Fprint(tabWriter, row)\n\t\tfmt.Fprint(tabWriter, \"\\n\")\n\t}\n\t_ = tabWriter.Flush()\n\n\treturn buf.String()\n}\n\n// wfpState is the WFP state as returned by `netsh.exe wfp show state -`.\ntype wfpState struct {\n\tXMLName   xml.Name `xml:\"wfpstate\"`\n\tText      string   `xml:\",chardata\"`\n\tTimeStamp string   `xml:\"timeStamp\"`\n\tProviders struct {\n\t\tText     string `xml:\",chardata\"`\n\t\tNumItems string `xml:\"numItems,attr\"`\n\t\tItem     []struct {\n\t\t\tText        string `xml:\",chardata\"`\n\t\t\tProviderKey string `xml:\"providerKey\"`\n\t\t\tDisplayData struct {\n\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\tName        string `xml:\"name\"`\n\t\t\t\tDescription string `xml:\"description\"`\n\t\t\t} `xml:\"displayData\"`\n\t\t\tFlags struct {\n\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\tNumItems string `xml:\"numItems,attr\"`\n\t\t\t\tItem     string `xml:\"item\"`\n\t\t\t} `xml:\"flags\"`\n\t\t\tProviderData string `xml:\"providerData\"`\n\t\t\tServiceName  string `xml:\"serviceName\"`\n\t\t} `xml:\"item\"`\n\t} `xml:\"providers\"`\n\tSubLayers struct {\n\t\tText     string `xml:\",chardata\"`\n\t\tNumItems string `xml:\"numItems,attr\"`\n\t\tItem     []struct {\n\t\t\tText        string `xml:\",chardata\"`\n\t\t\tSubLayerKey string `xml:\"subLayerKey\"`\n\t\t\tDisplayData struct {\n\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\tName        string `xml:\"name\"`\n\t\t\t\tDescription string `xml:\"description\"`\n\t\t\t} `xml:\"displayData\"`\n\t\t\tFlags struct {\n\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\tNumItems string `xml:\"numItems,attr\"`\n\t\t\t\tItem     string `xml:\"item\"`\n\t\t\t} `xml:\"flags\"`\n\t\t\tProviderKey  string `xml:\"providerKey\"`\n\t\t\tProviderData string `xml:\"providerData\"`\n\t\t\tWeight       string `xml:\"weight\"`\n\t\t} `xml:\"item\"`\n\t} `xml:\"subLayers\"`\n\tLayers struct {\n\t\tText     string `xml:\",chardata\"`\n\t\tNumItems string `xml:\"numItems,attr\"`\n\t\tItem     []struct {\n\t\t\tText  string `xml:\",chardata\"`\n\t\t\tLayer struct {\n\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\tLayerKey    string `xml:\"layerKey\"`\n\t\t\t\tDisplayData struct {\n\t\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\t\tName        string `xml:\"name\"`\n\t\t\t\t\tDescription string `xml:\"description\"`\n\t\t\t\t} `xml:\"displayData\"`\n\t\t\t\tFlags struct {\n\t\t\t\t\tText     string   `xml:\",chardata\"`\n\t\t\t\t\tNumItems string   `xml:\"numItems,attr\"`\n\t\t\t\t\tItem     []string `xml:\"item\"`\n\t\t\t\t} `xml:\"flags\"`\n\t\t\t\tField struct {\n\t\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\t\tNumItems string `xml:\"numItems,attr\"`\n\t\t\t\t\tItem     []struct {\n\t\t\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\t\t\tFieldKey string `xml:\"fieldKey\"`\n\t\t\t\t\t\tType     string `xml:\"type\"`\n\t\t\t\t\t\tDataType string `xml:\"dataType\"`\n\t\t\t\t\t} `xml:\"item\"`\n\t\t\t\t} `xml:\"field\"`\n\t\t\t\tDefaultSubLayerKey string `xml:\"defaultSubLayerKey\"`\n\t\t\t\tLayerID            string `xml:\"layerId\"`\n\t\t\t} `xml:\"layer\"`\n\t\t\tCallouts struct {\n\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\tNumItems string `xml:\"numItems,attr\"`\n\t\t\t\tItem     []struct {\n\t\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\t\tCalloutKey  string `xml:\"calloutKey\"`\n\t\t\t\t\tDisplayData struct {\n\t\t\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\t\t\tName        string `xml:\"name\"`\n\t\t\t\t\t\tDescription string `xml:\"description\"`\n\t\t\t\t\t} `xml:\"displayData\"`\n\t\t\t\t\tFlags struct {\n\t\t\t\t\t\tText     string   `xml:\",chardata\"`\n\t\t\t\t\t\tNumItems string   `xml:\"numItems,attr\"`\n\t\t\t\t\t\tItem     []string `xml:\"item\"`\n\t\t\t\t\t} `xml:\"flags\"`\n\t\t\t\t\tProviderKey     string `xml:\"providerKey\"`\n\t\t\t\t\tProviderData    string `xml:\"providerData\"`\n\t\t\t\t\tApplicableLayer string `xml:\"applicableLayer\"`\n\t\t\t\t\tCalloutID       string `xml:\"calloutId\"`\n\t\t\t\t} `xml:\"item\"`\n\t\t\t} `xml:\"callouts\"`\n\t\t\tFilters struct {\n\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\tNumItems string `xml:\"numItems,attr\"`\n\t\t\t\tItem     []struct {\n\t\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\t\tFilterKey   string `xml:\"filterKey\"`\n\t\t\t\t\tDisplayData struct {\n\t\t\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\t\t\tName        string `xml:\"name\"`\n\t\t\t\t\t\tDescription string `xml:\"description\"`\n\t\t\t\t\t} `xml:\"displayData\"`\n\t\t\t\t\tFlags struct {\n\t\t\t\t\t\tText     string   `xml:\",chardata\"`\n\t\t\t\t\t\tNumItems string   `xml:\"numItems,attr\"`\n\t\t\t\t\t\tItem     []string `xml:\"item\"`\n\t\t\t\t\t} `xml:\"flags\"`\n\t\t\t\t\tProviderKey  string `xml:\"providerKey\"`\n\t\t\t\t\tProviderData struct {\n\t\t\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\t\t\tData     string `xml:\"data\"`\n\t\t\t\t\t\tAsString string `xml:\"asString\"`\n\t\t\t\t\t} `xml:\"providerData\"`\n\t\t\t\t\tLayerKey    string `xml:\"layerKey\"`\n\t\t\t\t\tSubLayerKey string `xml:\"subLayerKey\"`\n\t\t\t\t\tWeight      struct {\n\t\t\t\t\t\tText   string `xml:\",chardata\"`\n\t\t\t\t\t\tType   string `xml:\"type\"`\n\t\t\t\t\t\tUint8  string `xml:\"uint8\"`\n\t\t\t\t\t\tUint64 string `xml:\"uint64\"`\n\t\t\t\t\t} `xml:\"weight\"`\n\t\t\t\t\tFilterCondition struct {\n\t\t\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\t\t\tNumItems string `xml:\"numItems,attr\"`\n\t\t\t\t\t\tItem     []struct {\n\t\t\t\t\t\t\tText           string `xml:\",chardata\"`\n\t\t\t\t\t\t\tFieldKey       string `xml:\"fieldKey\"`\n\t\t\t\t\t\t\tMatchType      string `xml:\"matchType\"`\n\t\t\t\t\t\t\tConditionValue struct {\n\t\t\t\t\t\t\t\tText       string `xml:\",chardata\"`\n\t\t\t\t\t\t\t\tType       string `xml:\"type\"`\n\t\t\t\t\t\t\t\tUint32     string `xml:\"uint32\"`\n\t\t\t\t\t\t\t\tUint16     string `xml:\"uint16\"`\n\t\t\t\t\t\t\t\tRangeValue struct {\n\t\t\t\t\t\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\t\t\t\t\t\tValueLow struct {\n\t\t\t\t\t\t\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\t\t\t\t\t\t\tType        string `xml:\"type\"`\n\t\t\t\t\t\t\t\t\t\tUint16      string `xml:\"uint16\"`\n\t\t\t\t\t\t\t\t\t\tUint32      string `xml:\"uint32\"`\n\t\t\t\t\t\t\t\t\t\tByteArray16 string `xml:\"byteArray16\"`\n\t\t\t\t\t\t\t\t\t} `xml:\"valueLow\"`\n\t\t\t\t\t\t\t\t\tValueHigh struct {\n\t\t\t\t\t\t\t\t\t\tText        string `xml:\",chardata\"`\n\t\t\t\t\t\t\t\t\t\tType        string `xml:\"type\"`\n\t\t\t\t\t\t\t\t\t\tUint16      string `xml:\"uint16\"`\n\t\t\t\t\t\t\t\t\t\tUint32      string `xml:\"uint32\"`\n\t\t\t\t\t\t\t\t\t\tByteArray16 string `xml:\"byteArray16\"`\n\t\t\t\t\t\t\t\t\t} `xml:\"valueHigh\"`\n\t\t\t\t\t\t\t\t} `xml:\"rangeValue\"`\n\t\t\t\t\t\t\t\tUint8    string `xml:\"uint8\"`\n\t\t\t\t\t\t\t\tByteBlob struct {\n\t\t\t\t\t\t\t\t\tText     string `xml:\",chardata\"`\n\t\t\t\t\t\t\t\t\tData     string `xml:\"data\"`\n\t\t\t\t\t\t\t\t\tAsString string `xml:\"asString\"`\n\t\t\t\t\t\t\t\t} `xml:\"byteBlob\"`\n\t\t\t\t\t\t\t\tSd     string `xml:\"sd\"`\n\t\t\t\t\t\t\t\tSid    string `xml:\"sid\"`\n\t\t\t\t\t\t\t\tUint64 string `xml:\"uint64\"`\n\t\t\t\t\t\t\t} `xml:\"conditionValue\"`\n\t\t\t\t\t\t} `xml:\"item\"`\n\t\t\t\t\t} `xml:\"filterCondition\"`\n\t\t\t\t\tAction struct {\n\t\t\t\t\t\tText       string `xml:\",chardata\"`\n\t\t\t\t\t\tType       string `xml:\"type\"`\n\t\t\t\t\t\tFilterType string `xml:\"filterType\"`\n\t\t\t\t\t} `xml:\"action\"`\n\t\t\t\t\tRawContext      string `xml:\"rawContext\"`\n\t\t\t\t\tReserved        string `xml:\"reserved\"`\n\t\t\t\t\tFilterID        string `xml:\"filterId\"`\n\t\t\t\t\tEffectiveWeight struct {\n\t\t\t\t\t\tText   string `xml:\",chardata\"`\n\t\t\t\t\t\tType   string `xml:\"type\"`\n\t\t\t\t\t\tUint64 string `xml:\"uint64\"`\n\t\t\t\t\t} `xml:\"effectiveWeight\"`\n\t\t\t\t\tProviderContextKey string `xml:\"providerContextKey\"`\n\t\t\t\t} `xml:\"item\"`\n\t\t\t} `xml:\"filters\"`\n\t\t} `xml:\"item\"`\n\t} `xml:\"layers\"`\n}\n\nfunc parseWFPState(data []byte) (*wfpState, error) {\n\tw := &wfpState{}\n\terr := xml.Unmarshal(data, w)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn w, nil\n}\n\nfunc (w *wfpState) simplified() *SimplifiedWFPState {\n\tsw := &SimplifiedWFPState{\n\t\tProviders: make([]*WFPProvider, 0, len(w.Providers.Item)),\n\t\tSubLayers: make([]*WFPSubLayer, 0, len(w.SubLayers.Item)),\n\t\tCallouts:  make([]*WFPCallout, 0, len(w.Layers.Item)),\n\t\tFilters:   make([]*WFPFilter, 0, len(w.Layers.Item)),\n\t}\n\n\t// Collect data.\n\tfor _, provider := range w.Providers.Item {\n\t\tif isIgnoredProvider(provider.DisplayData.Name, provider.ProviderKey) {\n\t\t\tcontinue\n\t\t}\n\n\t\tsw.Providers = append(sw.Providers, &WFPProvider{\n\t\t\tName:        defaultTo(provider.DisplayData.Name, \"[no name]\"),\n\t\t\tDescription: defaultTo(provider.DisplayData.Description, \"[no description]\"),\n\t\t\tProviderKey: defaultTo(provider.ProviderKey, \"[no provider key]\"),\n\t\t})\n\t}\n\tfor _, subLayer := range w.SubLayers.Item {\n\t\tif isIgnoredProvider(subLayer.DisplayData.Name, \"\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tsw.SubLayers = append(sw.SubLayers, &WFPSubLayer{\n\t\t\tName:        defaultTo(subLayer.DisplayData.Name, \"[no name]\"),\n\t\t\tDescription: defaultTo(subLayer.DisplayData.Description, \"[no description]\"),\n\t\t\tSubLayerKey: defaultTo(subLayer.SubLayerKey, \"[no sublayer key]\"),\n\t\t})\n\t}\n\tfor _, layer := range w.Layers.Item {\n\t\tfor _, callout := range layer.Callouts.Item {\n\t\t\tif isIgnoredProvider(callout.DisplayData.Name, callout.ProviderKey) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsw.Callouts = append(sw.Callouts, &WFPCallout{\n\t\t\t\tName:            defaultTo(callout.DisplayData.Name, \"[no name]\"),\n\t\t\t\tDescription:     defaultTo(callout.DisplayData.Description, \"[no description]\"),\n\t\t\t\tCalloutKey:      defaultTo(callout.CalloutKey, \"[no callout key]\"),\n\t\t\t\tProviderKey:     defaultTo(callout.ProviderKey, \"[no provider key]\"),\n\t\t\t\tApplicableLayer: defaultTo(callout.ApplicableLayer, \"[no applicable layer]\"),\n\t\t\t})\n\t\t}\n\t\tfor _, filter := range layer.Filters.Item {\n\t\t\tif isIgnoredProvider(filter.DisplayData.Name, filter.ProviderKey) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsw.Filters = append(sw.Filters, &WFPFilter{\n\t\t\t\tName:        defaultTo(filter.DisplayData.Name, \"[no name]\"),\n\t\t\t\tDescription: defaultTo(filter.DisplayData.Description, \"[no description]\"),\n\t\t\t\tFilterKey:   defaultTo(filter.FilterKey, \"[no filter key]\"),\n\t\t\t\tProviderKey: defaultTo(filter.ProviderKey, \"[no provider key]\"),\n\t\t\t\tLayerKey:    defaultTo(filter.LayerKey, \"[no layer key]\"),\n\t\t\t\tSubLayerKey: defaultTo(filter.SubLayerKey, \"[no sublayer key]\"),\n\t\t\t})\n\t\t}\n\t}\n\n\treturn sw\n}\n\nfunc isIgnoredProvider(name, key string) bool {\n\t// Check provider key.\n\tif key != \"\" {\n\t\tmatched := true\n\t\tswitch key {\n\t\tcase \"{1bebc969-61a5-4732-a177-847a0817862a}\": // Microsoft Windows Defender Firewall IPsec Provider.\n\t\tcase \"{4b153735-1049-4480-aab4-d1b9bdc03710}\": // Microsoft Windows Defender Firewall Provider.\n\t\tcase \"{893a4f22-9bba-49b7-8c66-3d40929c8fd5}\": // Microsoft Windows Teredo firewall provider.\n\t\tcase \"{8e44982a-f477-11df-85ce-78e7d1810190}\": // Windows Network Data Usage (NDU) Provider.\n\t\tcase \"{9c2532b4-0314-434f-8274-0cbaebdbda56}\": // Microsoft Windows edge traversal socket option authorization provider.\n\t\tcase \"{aa6a7d87-7f8f-4d2a-be53-fda555cd5fe3}\": // Microsoft Windows Defender Firewall IPsec Provider.\n\t\tcase \"{c698301d-9129-450c-937c-f4b834bfb374}\": // Microsoft Windows edge traversal socket option authorization provider.\n\t\tcase \"{decc16ca-3f33-4346-be1e-8fb4ae0f3d62}\": // Microsoft Windows Defender Firewall Provider.\n\t\tcase \"FWPM_PROVIDER_IKEEXT\": // Microsoft Windows WFP Built-in IKEEXT provider used to identify filters added by IKE/AuthIP.\n\t\tcase \"FWPM_PROVIDER_IPSEC_DOSP_CONFIG\": // Microsoft Windows WFP Built-in IPsec DoS Protection configuration provider used to identify filters added by IPsec Denial of Service Protection.\n\t\tcase \"FWPM_PROVIDER_MPSSVC_APP_ISOLATION\": // Microsoft Windows WFP Built-in MPSSVC App Isolation provider.\n\t\tcase \"FWPM_PROVIDER_MPSSVC_EDP\": // Microsoft Windows WFP Built-in MPSSVC Enterprise Data Protection provider.\n\t\tcase \"FWPM_PROVIDER_MPSSVC_TENANT_RESTRICTIONS\": // Microsoft Windows WFP Built-in MPSSVC Tenant Restrictions provider.\n\t\tcase \"FWPM_PROVIDER_MPSSVC_WF\": // Microsoft Windows WFP Built-in MPSSVC Windows Firewall provider.\n\t\tcase \"FWPM_PROVIDER_MPSSVC_WSH\": // Microsoft Windows WFP Built-in MPSSVC Windows Service Hardening and Quarantine provider.\n\t\tcase \"FWPM_PROVIDER_TCP_CHIMNEY_OFFLOAD\": // Microsoft Windows WFP Built-in TCP Chimney Offload provider used to identify filters added by TCP Chimney Offload.\n\t\tcase \"FWPM_PROVIDER_TCP_TEMPLATES\": // Microsoft Windows WFP Built-in TCP Templates provider used to identify filters added by TCP Template based configuration.\n\t\tdefault:\n\t\t\tmatched = false\n\t\t}\n\t\tif matched {\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// Some entries don't have a provider key (set).\n\t// These are pretty generic, but the output strings are localized.\n\tif name != \"\" {\n\t\tswitch {\n\t\tcase strings.Contains(name, \"Microsoft Corporation\"):\n\t\t\treturn true\n\t\tcase strings.Contains(name, \"windefend\"):\n\t\t\treturn true\n\t\tcase strings.Contains(name, \"WFP\"):\n\t\t\treturn true\n\t\tcase strings.Contains(name, \"RPC\"):\n\t\t\treturn true\n\t\tcase strings.Contains(name, \"NDU\"):\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc defaultTo(a, b string) string {\n\tif a != \"\" {\n\t\treturn a\n\t}\n\treturn b\n}\n"
  },
  {
    "path": "service/compat/wfpstate_test.go",
    "content": "package compat\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestWFPState(t *testing.T) {\n\tt.Parallel()\n\n\tw, err := parseWFPState(wfpTestData)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\toutput := w.simplified().AsTable()\n\tfmt.Println(output)\n\n\toutputLines := strings.Count(output, \"\\n\")\n\tif outputLines != 10 {\n\t\tt.Errorf(\"Expected 10 output lines, not %d\", outputLines)\n\t}\n}\n\nvar wfpTestData = []byte(`<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<wfpstate>\n\t<layers numItems=\"97\">\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_IPPACKET_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound IP Packet v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>0</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{05c55149-4732-4857-8d10-f178f3a06f8c}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterInboundV4Callout</name>\n\t\t\t\t\t\t<description>This callout is used by the Portmaster to intercept inbound IPv4 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_IPPACKET_V4</applicableLayer>\n\t\t\t\t\t<calloutId>290</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fb2f56c5-3883-475a-8c78-047d1f93b5a9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterInboundV4Filter</name>\n\t\t\t\t\t\t<description>This filter is used by the Portmaster to intercept inbound IPv4 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_IPPACKET_V4</layerKey>\n\t\t\t\t\t<subLayerKey>{a87fb472-fc68-4805-8559-c6ae774773e0}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>15</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{05c55149-4732-4857-8d10-f178f3a06f8c}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68136</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>17293822569102704640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_IPPACKET_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound IP Packet v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>1</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_IPPACKET_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound IP Packet v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>2</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{ceff1df7-2baa-44c5-a6e5-73a95849bcff}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterInboundV6Callout</name>\n\t\t\t\t\t\t<description>This callout is used by the Portmaster to intercept inbound IPv6 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_IPPACKET_V6</applicableLayer>\n\t\t\t\t\t<calloutId>292</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{778afeeb-9680-4a59-82d5-abc33b3fb183}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterInboundV6Filter</name>\n\t\t\t\t\t\t<description>This filter is used by the Portmaster to intercept inbound IPv6 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_IPPACKET_V6</layerKey>\n\t\t\t\t\t<subLayerKey>{a87fb472-fc68-4805-8559-c6ae774773e0}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>15</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{ceff1df7-2baa-44c5-a6e5-73a95849bcff}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68138</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>17293822569102704640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_IPPACKET_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound IP Packet v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>3</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_IPPACKET_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound IP Packet v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>4</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{41162b9e-8473-4b88-a5eb-04cf1d276b06}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterOutboundV4Callout</name>\n\t\t\t\t\t\t<description>This callout is used by the Portmaster to intercept outbound IPv4 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_IPPACKET_V4</applicableLayer>\n\t\t\t\t\t<calloutId>291</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{609b24b3-7b9a-48e1-8994-c72a42bbd319}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterOutboundV4Filter</name>\n\t\t\t\t\t\t<description>This filter is used by the Portmaster to intercept outbound IPv4 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_IPPACKET_V4</layerKey>\n\t\t\t\t\t<subLayerKey>{a87fb472-fc68-4805-8559-c6ae774773e0}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>15</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{41162b9e-8473-4b88-a5eb-04cf1d276b06}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68137</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>17293822569102704640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_IPPACKET_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound IP Packet v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>5</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_IPPACKET_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound IP Packet v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>6</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{32bad112-6af4-4109-809b-c07570ba01b4}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterOutboundV6Callout</name>\n\t\t\t\t\t\t<description>This callout is used by the Portmaster to intercept outbound IPv6 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_IPPACKET_V6</applicableLayer>\n\t\t\t\t\t<calloutId>293</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{23ae199a-7949-4059-b799-67e7a1a57fcb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>PortmasterOutboundV6Filter</name>\n\t\t\t\t\t\t<description>This filter is used by the Portmaster to intercept outbound IPv6 traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_IPPACKET_V6</layerKey>\n\t\t\t\t\t<subLayerKey>{a87fb472-fc68-4805-8559-c6ae774773e0}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>15</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{32bad112-6af4-4109-809b-c07570ba01b4}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68139</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>17293822569102704640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound IP Packet v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>7</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPFORWARD_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IP Forward v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_FORWARD_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>8</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Forward Inbound Tunnel v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each received packet that is supposed to arrive over a tunnel mode security association arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_IPFORWARD_V4</applicableLayer>\n\t\t\t\t\t<calloutId>9</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Forward Outbound Tunnel v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Indicates to IPsec the outbound traffic that must be secured over a tunnel mode security association.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_IPFORWARD_V4</applicableLayer>\n\t\t\t\t\t<calloutId>11</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{935b7f48-0ede-44dd-9bc2-e00bb635cda3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_IPFORWARD_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>786432</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66238</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>4</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPFORWARD_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IP Forward v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_FORWARD_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>9</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPFORWARD_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IP Forward v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_FORWARD_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>10</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Forward Inbound Tunnel v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each received packet that is supposed to arrive over a tunnel mode security association arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_IPFORWARD_V6</applicableLayer>\n\t\t\t\t\t<calloutId>10</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Forward Outbound Tunnel v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Indicates to IPsec the outbound traffic that must be secured over a tunnel mode security association.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_IPFORWARD_V6</applicableLayer>\n\t\t\t\t\t<calloutId>12</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{941dad9d-7b1a-4354-997b-00cf1aa9b35c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_IPFORWARD_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>786432</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66239</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>4</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPFORWARD_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IP Forward v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_FORWARD_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SOURCE_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DESTINATION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PHYSICAL_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>11</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Transport v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>12</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Transport v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each received packet that is supposed to arrive over a transport mode security association arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000260</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_TRANSPORT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>1</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Tunnel v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each received packet that is supposed to arrive over a tunnel mode security association arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_TRANSPORT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>5</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Transport v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>13</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_WFP_TRANSPORT_LAYER_V4_SILENT_DROP</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Silent Drop Transport v4 Discard Layer Callout</name>\n\t\t\t\t\t\t<description>Implements stealth-mode filtering by silently dropping all incoming packets for which TCP does not have a listening endpoint.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000240</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>17</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"4\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{03c67493-1802-44a0-ad5f-3ae741e25c15}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68060</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{29ccd323-aecf-4990-b96a-c5384222b0c9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68062</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{92ff43ac-9df0-49e9-b3b3-d6f8421edcca}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_WFP_TRANSPORT_LAYER_V4_SILENT_DROP</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68064</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b2a53430-2096-4b30-ae54-260f96a82028}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>12</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_WFP_TRANSPORT_LAYER_V4_SILENT_DROP</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68066</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>13835058055349272576</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Transport v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>14</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Transport v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each received packet that is supposed to arrive over a transport mode security association arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000260</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_TRANSPORT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>2</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Tunnel v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each received packet that is supposed to arrive over a tunnel mode security association arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_TRANSPORT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>6</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Transport v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"15\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>15</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_WFP_TRANSPORT_LAYER_V6_SILENT_DROP</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Silent Drop Transport v6 Discard Layer Callout</name>\n\t\t\t\t\t\t<description>Implements stealth-mode filtering by silently dropping all incoming packets for which TCP does not have a listening endpoint.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000240</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>18</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"4\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{57175e0d-0212-4ddd-b229-559795b43af7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68061</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d979d760-083e-489d-9360-1f377b606ef1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68063</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{22b3ef06-6428-47ac-868f-b4a968fe995c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_WFP_TRANSPORT_LAYER_V6_SILENT_DROP</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68065</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f3ecd3f5-9498-4dce-a76d-da32be01382f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>12</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_WFP_TRANSPORT_LAYER_V6_SILENT_DROP</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68067</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>13835058055298940928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_TRANSPORT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Transport v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>16</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Outbound Transport v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Indicates to IPsec the outbound traffic that must be secured over transport mode security associations.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000260</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_TRANSPORT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>3</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Outbound Tunnel v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Indicates to IPsec the outbound traffic that must be secured over tunnel mode security associations.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_TRANSPORT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>7</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Transport v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>17</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_TRANSPORT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Transport v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>18</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Outbound Transport v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Indicates to IPsec the outbound traffic that must be secured over transport mode security associations.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000260</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_TRANSPORT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>4</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Outbound Tunnel v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Indicates to IPsec the outbound traffic that must be secured over tunnel mode security associations.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000020</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_TRANSPORT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>8</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Transport v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>19</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Stream v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUFFERED</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>20</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0414}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Connection-oriented protocol packet inspection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_STREAM_V4</applicableLayer>\n\t\t\t\t\t<calloutId>288</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{d67b238d-d80c-4ba7-96df-4a0c83464fa7}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_stream_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_STREAM_V4</applicableLayer>\n\t\t\t\t\t<calloutId>294</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{821997be-23bb-4240-87a2-2615caec3d1f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Deep Protocol Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter implements deep inspection for FTP protocols.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0414}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68050</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{42e67750-e0ae-4ec7-aa42-97c6605b1c96}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_stream_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V4</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{d67b238d-d80c-4ba7-96df-4a0c83464fa7}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68276</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Stream v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUFFERED</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>21</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Stream v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUFFERED</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>22</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0416}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Connection-oriented protocol packet inspection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_STREAM_V6</applicableLayer>\n\t\t\t\t\t<calloutId>289</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{36d4cf95-fd3a-4bb8-90a9-ffdb3749237f}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_stream_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_STREAM_V6</applicableLayer>\n\t\t\t\t\t<calloutId>295</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ecdc6e7a-8981-4a13-92d7-fb12f8d0ea9f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Deep Protocol Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter implements deep inspection for FTP protocols.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0416}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68051</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{094b9bb6-e451-4069-ac23-5fe695ec9662}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_stream_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V6</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{36d4cf95-fd3a-4bb8-90a9-ffdb3749237f}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68277</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_STREAM_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Stream v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUFFERED</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>23</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_DATAGRAM_DATA_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Datagram Data v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>24</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{b2d11c73-b4ef-47d1-b665-58e6ba9fe200}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_datagram_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_DATAGRAM_DATA_V4</applicableLayer>\n\t\t\t\t\t<calloutId>300</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{67dc47f0-7a3b-4705-a4e7-bb8756a3e69f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_datagram_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_DATAGRAM_DATA_V4</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{b2d11c73-b4ef-47d1-b665-58e6ba9fe200}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68282</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_DATAGRAM_DATA_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Datagram Data v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>25</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_DATAGRAM_DATA_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Datagram Data v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>26</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{80cece9d-0b53-4672-ac43-4524416c0353}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_datagram_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_DATAGRAM_DATA_V6</applicableLayer>\n\t\t\t\t\t<calloutId>301</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f875d7d9-b132-436d-a729-479ef4e4ef08}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_datagram_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_DATAGRAM_DATA_V6</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>{80cece9d-0b53-4672-ac43-4524416c0353}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68283</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_DATAGRAM_DATA_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Datagram Data v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>27</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound ICMP Error v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"22\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>28</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters numItems=\"6\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0c41d586-9c19-4e01-9d66-b5b98a97576e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66212</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4d9581d2-aef8-4993-84cd-b986ced80d42}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66216</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{074f7f68-ee10-428a-89d1-ba78f6c327ca}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66224</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{91ffecf0-0a9e-4572-95f1-a7111af86967}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66228</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{08f09e8d-2754-4cc2-b595-7260f3a8df9d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67629</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854775812</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b8b57642-80b0-49d5-b5d6-34834967743d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67637</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound ICMP Error v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"22\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>29</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e011d}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>276</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound ICMP Error v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"22\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>30</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters numItems=\"6\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{12c38916-82ac-4737-8f38-b6957ffebad6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66213</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{be7cbdf4-b192-4aa5-94f8-1fb5c5ee07bc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66217</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c016105c-eb34-4519-a5fd-5f4e4ad4d18e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66225</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{64e55933-15a5-495d-a928-ccca43d44875}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66229</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cc44ca04-e1d0-42ef-8fd1-ffe89f6ed166}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67633</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854775812</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{49ec4b6a-348d-41ae-8777-f7c59ec17f26}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67641</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound ICMP Error v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"22\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_EMBEDDED_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>31</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e011f}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>277</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound ICMP Error v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>32</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters numItems=\"15\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{07a24961-a760-4e80-b263-6d275e1b09cb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66220</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b308b233-cd6c-401d-9f09-3a80217f778e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67643</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854775812</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{bfe4943b-6e61-4ae6-a187-d62d68351430}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67647</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c313817b-32a7-4160-95b2-4673a26e0cab}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68068</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372586040164364</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3228da2c-00c2-4f05-8f8c-682315fe7530}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>12</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68069</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372585771728908</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a2fd53b1-e627-4962-aede-c508dac25267}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>14</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>255</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68070</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372584463106060</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2260bd8b-6481-4879-93f1-9435d24d2528}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68073</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372586040164364</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7224a028-a279-4c7b-b136-40f7516b88cc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>12</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68074</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372585771728908</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3339fd71-a0e9-4714-87f6-e9ec698fab6b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>14</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>255</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68075</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372584463106060</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9eaf6f7b-ed11-48fb-b3c5-592921db1103}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68078</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ef4ccd1e-f08d-4199-85e1-3ef56963f09e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>12</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68079</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0365edae-cbe6-4657-8943-2d16058c98c2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>14</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>255</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68080</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c2b8dc84-bfca-4c6d-ba88-5325839ea39f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68083</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d5afb3be-9eb2-40c3-8fa9-3e8ee38948c5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>12</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68084</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4c7ffc63-9f38-44b9-8624-b85abd89b7a6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>14</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>255</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68085</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound ICMP Error v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>33</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0121}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>272</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound ICMP Error v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>34</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters numItems=\"11\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5b0cb2e2-ab87-4974-9f1c-2f22a654eeb9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66221</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{da00b2e8-656f-40cc-9a37-444f32c5e58a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67645</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854775812</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{70fb0d21-2477-44bc-967b-494c061e96eb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67649</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b9b272fb-b866-4e48-9385-c1bee91957da}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68071</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372070677643276</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{331a54f2-38e6-43de-943b-9742b565db8c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68072</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372071155793932</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{722d30ec-406b-423a-b027-d7dd8a306836}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68076</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372070677643276</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c6a5f146-bbad-4cad-8de4-0c3a4d349f77}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68077</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372071155793932</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a6c63b22-fa8c-4afc-88ab-3f0a8faf213a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68081</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{45648f6f-4589-44e3-8959-75b391aa0038}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68082</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{dd1e0820-fc15-4492-9403-ef2c61e329bb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68086</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4d5e5002-239a-4d48-a681-d7c3c49517d1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Port Scanning Prevention Filter</name>\n\t\t\t\t\t\t<description>This filter prevents port scanning. This many times means there are no listeners. If debugging ensure your scenario has one.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>0</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68087</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744069414584322</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound ICMP Error v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>35</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0123}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>273</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Resource Assignment v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PROMISCUOUS_MODE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>36</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"3\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Edge Traversal ALE Resource Assignment v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Signals Windows when an application is attempting to bind to an interface and has opted in for edge traversing traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000014</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>27</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0024}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Notifies the user.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>268</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{58d7275b-2fd2-4b6c-b93a-30037e577d7e}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_resource_assignment_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>296</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"21\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fec997ae-7462-4ec1-b9af-99c4751fd489}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>9</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0024}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67628</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223442268161048576</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e71db8d0-e58f-45fa-8d34-6e66c5ec8cc1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>9</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0024}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67636</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458834745126813696</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cd49bc81-9428-4bfe-9fad-d20504a480a2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67663</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003905476198400</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d0db3fd9-fa82-4abf-aa82-87a9645636de}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67664</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003905476198400</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{69f35305-c344-4543-891f-28168fbd3f31}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol (DHCP-In)</name>\n\t\t\t\t\t\t<description>Allows DHCP (Dynamic Host Configuration Protocol) messages for stateful auto-configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9f00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67677</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003905476198400</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{77c9fe79-5402-402e-8226-c8b570fd6388}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol for IPv6(DHCPV6-In)</name>\n\t\t\t\t\t\t<description>Allows DHCPV6 (Dynamic Host Configuration Protocol for IPv6) messages for stateful and stateless configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67681</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003905476198400</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8235388e-e851-4838-a33f-fb98db5a3e5a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67773</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363875846062080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{eeb93afc-0f8e-4b50-b378-4517aeacf07a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67785</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363875846062080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8bbc020b-4c16-4c42-9147-0c7f61f2a27b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67797</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363875846062080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a2b54f0b-3d87-462c-bfe7-5aff5618a7b3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67809</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363875846062080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8db0f20c-e041-4c94-93c3-2acdf0380dc4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67824</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363841486323712</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2d6dcea9-f654-406c-bad0-c12935683e86}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67829</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363875846062080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c5f25e64-ac27-4d08-ac2e-fc083d790752}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67841</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363875846062080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{68ce3ad4-d6a7-4f3b-94bf-9d7ddbbfd856}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00350036005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.56\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67852</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003871116460032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1e498170-bf78-40d0-8534-89420cdeb047}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c0065006400670065005c006100700070006c00690063006100740069006f006e005c006d00730065006400670065002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edge\\application\\msedge.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67868</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003871116460032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{965c8ce5-bb4c-4ece-9b94-fbab1f02bd61}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>be00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00360032005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.62\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67872</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003871116460032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1663d17f-13ac-4339-a87d-0b8177c6a161}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [UDP 5004-5009]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open UDP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1f01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5000</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5020</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68214</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11212626031653421056</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2c0936a0-ca0e-45fd-8ca2-f7a00123be5c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFD ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for the WLAN Service to allow coordination protocol for WFD Service sessions [UDP 7235]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2201000000000000</data>\n\t\t\t\t\t\t<asString>\".......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68234</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003905476198400</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d89bb141-b39a-4088-96b4-558cb5f9f818}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>mDNS (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for mDNS traffic [UDP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2601000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-859482183-879914841-863379149-1145462774-2388618682)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68246</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11529003905476198400</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{26501d40-8df2-4445-9f4b-a8a19f2afeb8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_resource_assignment_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{58d7275b-2fd2-4b6c-b93a-30037e577d7e}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68278</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ba25c88a-4995-4529-bbd9-095462c2ab55}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_RESOURCE_ASSIGNMENT_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68285</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376363875846062080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Resource Assignment v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PROMISCUOUS_MODE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>37</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Resource Assignment v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PROMISCUOUS_MODE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>38</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"3\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Edge Traversal ALE Resource Assignment v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Signals Windows when an application is attempting to bind to an interface and has opted in for edge traversing traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000014</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>28</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0026}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Notifies the user.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>269</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{ced78e5f-1dd1-485a-9d35-7e44cc9d784d}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_resource_assignment_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>297</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"21\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{233dc13e-f91d-4576-8c0a-c258350a7620}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>9</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0026}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67632</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223511674839891968</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d6ac0d0d-5259-4e91-b3da-6dd38df859a0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>9</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0026}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67640</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458904151805657088</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cb5e3e43-13f9-4f37-a3d8-c0a6ee6a157b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67668</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792558725496832</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9c5b7174-b5ba-4ebe-87f3-49d42065c090}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67669</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792558725496832</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ccb39a7c-ffcc-41e1-b3d5-5508c22d7ae8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol (DHCP-In)</name>\n\t\t\t\t\t\t<description>Allows DHCP (Dynamic Host Configuration Protocol) messages for stateful auto-configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9f00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67679</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792558725496832</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6bfcb550-a334-493c-bfa9-0fd5778762d3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol for IPv6(DHCPV6-In)</name>\n\t\t\t\t\t\t<description>Allows DHCPV6 (Dynamic Host Configuration Protocol for IPv6) messages for stateful and stateless configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67683</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792558725496832</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f1d77b93-024f-4ced-96fa-583e3777c094}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67778</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376434004072071168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4ad1f317-75d8-4c41-b699-586bdc947b61}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67790</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376434004072071168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5856855b-110b-411a-9edb-c83af7970e2a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67802</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376434004072071168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{449e8fbb-acaf-4cfe-a93c-01c8b5a04e2f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67814</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376434004072071168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b0f609a0-8de9-4641-93e8-322951f06806}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67826</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376433729194164224</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{efbc5936-c530-4944-a424-354d0f15516f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67834</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376434004072071168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{65a89691-b6bc-453a-ba4f-60b8f2f5afce}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67846</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376434004072071168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2429f54d-a7e7-428b-8b99-db319e9fbeec}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00350036005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.56\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67854</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792283847589888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6f59015a-2f44-4527-95c2-ef891e2ee42e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c0065006400670065005c006100700070006c00690063006100740069006f006e005c006d00730065006400670065002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edge\\application\\msedge.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67870</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792283847589888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4373e6d8-0cba-416a-8957-5346f3a3810f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>be00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00360032005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.62\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67874</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792283847589888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e4be4ec1-3874-4bb7-91f4-ef1252a96e4a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [UDP 5004-5009]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open UDP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1f01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5000</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5020</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68217</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11212414684902719488</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{95d5968b-f1ce-43f6-8edd-f24b0776f8b0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFD ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for the WLAN Service to allow coordination protocol for WFD Service sessions [UDP 7235]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2201000000000000</data>\n\t\t\t\t\t\t<asString>\".......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68237</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792558725496832</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c98871d1-4f49-4853-9a6e-35cae1fa3f17}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>mDNS (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for mDNS traffic [UDP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2601000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-859482183-879914841-863379149-1145462774-2388618682)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68249</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>11528792558725496832</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8c0045d4-35b0-4a88-bf37-3c5bbe7a37bc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_resource_assignment_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{ced78e5f-1dd1-485a-9d35-7e44cc9d784d}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68279</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{16dfd892-4fa5-4dc8-bf0f-2e94ffe6f1ba}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_RESOURCE_ASSIGNMENT_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68290</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376434004072071168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Resource Assignment v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PROMISCUOUS_MODE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>39</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Listen v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>40</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Edge Traversal ALE Listen v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Signals Windows when an application is attempting to listen on an interface and has opted in for edge traversing traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000014</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_LISTEN_V4</applicableLayer>\n\t\t\t\t\t<calloutId>29</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0028}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Notifies the user.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_LISTEN_V4</applicableLayer>\n\t\t\t\t\t<calloutId>270</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"15\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{93f12f2b-665e-44f2-a229-f5af613fe690}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0028}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67627</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854775840</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8f1a4c58-25f3-4358-84e9-4aaec8ab1398}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0028}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67635</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540960</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{85bce91c-5ad3-4c13-978f-edfd66523835}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67696</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293542535364544</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{18f77a24-0d44-4919-98e7-f42eb1002af3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67697</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293542535364544</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1a3b3a34-55b4-4791-aa77-28e1c9f4f78a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wireless Display Infrastructure Back Channel (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Wireless Display Infrastructure back channel [TCP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0063006100730074007300720076002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\castsrv.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7250</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67709</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293542535364480</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7fb5698e-c641-4fbc-b851-13c666f5e3aa}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67772</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c3711cf1-9bff-4f13-abcb-3ffdc68015d3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67784</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fa41fb18-1600-4eb8-a46e-b1e892bdc894}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67796</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0ee2b732-6452-42b4-9a5e-bdb97e3a925a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67808</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a11e4118-9942-4da1-bdbf-698fde8b5697}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67820</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622912</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{066a6860-5fb4-4dd2-bbc9-8bac48b6a4d4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67828</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{185af45b-b8b0-4110-a5a3-9732ccf1a36a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67840</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6ed9f2bc-535f-4575-a1b3-56e98dfc52ad}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68220</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293542535364544</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{86edf865-f5c6-4b10-9eaa-63371a7287a1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8558</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68223</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293542379542720</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a8c97be3-77f0-4ea7-b5f8-10d91d382e1e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_EDGE_TRAVERSAL_ALE_LISTEN_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68284</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Listen v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>41</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Listen v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>42</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"2\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Edge Traversal ALE Listen v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Signals Windows when an application is attempting to listen on an interface and has opted in for edge traversing traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000014</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_LISTEN_V6</applicableLayer>\n\t\t\t\t\t<calloutId>30</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e002a}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Notifies the user.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_LISTEN_V6</applicableLayer>\n\t\t\t\t\t<calloutId>271</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"15\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a8568747-7e3e-4077-adc4-4ad699d10d4b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e002a}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67631</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854775840</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9412dbc5-7e4a-4296-9b6b-309a61de48b4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e002a}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67639</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540960</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{05a88866-6122-4377-9ca8-432cbe8f64c2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67701</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541528731584</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8b44e0b3-d691-4d4b-a7ff-4ab5c957d05e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67702</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541528731584</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9d45f132-f86f-4c7b-8f71-32000ba2136a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wireless Display Infrastructure Back Channel (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Wireless Display Infrastructure back channel [TCP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0063006100730074007300720076002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\castsrv.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7250</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67711</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541528731520</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{89449f5a-57ae-4ae5-ac86-e4b758669e07}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67777</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{aedc9943-eac8-497d-acc6-0e7175b5074b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67789</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8a3fa42a-2fab-485a-afad-8bcfbf876471}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67801</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{09bda0cc-b7d7-4eea-84a5-587667ae638a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67813</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{72f3c3d1-c6ff-4dc5-a385-a4cb9aad45f3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67822</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622912</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f4ed1f0f-7a1a-4025-89e2-38e6bebc3db8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67833</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b452f283-2ec7-44cd-92aa-7b832d56e019}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67845</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{109e4154-56f4-4c4f-92d4-40cd1dc644ce}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68226</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541528731584</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ea58a6ce-9d6b-46f2-9d4c-a1977a154b5b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8558</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68229</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541518992832</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e65cf284-71bb-4869-b2ba-c9a7051d20fc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_TERMINATING</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_TEREDO_ALE_LISTEN_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68289</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293541461622976</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_LISTEN_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Listen v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_LOCAL_INTERFACE_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>43</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Receive/Accept v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"35\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_NAP_CONTEXT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>44</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"7\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Initiate Secure v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each incoming connection that is supposed to arrive secure arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>13</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_CHIMNEY_ACCEPT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Chimney Offload ALE Receive/Accept v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Enables or disables TCP Chimney Offload for each incoming connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>21</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Tunnel ALE Receive/Accept v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Permits IPsec tunnel mode IP-in-IP packets when they get classified at the ALE receive/accept layer.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>25</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_TEMPLATES_ACCEPT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Templates ALE Receive/Accept v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Applies TCP Template for each incoming connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>35</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_SET_OPTIONS_AUTH_RECV_ACCEPT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Set Option ALE Receive/Accept v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Sets classify options on inbound flows.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>39</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_POLICY_SILENT_MODE_AUTH_RECV_ACCEPT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Policy Silent Mode ALE Receive/Accept v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Audit and log policy for incoming connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>43</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e022c}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Allows secondary connections.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>284</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"114\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c970a45d-57f9-4e32-a5bd-886a9662641e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>8388608</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66214</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{716b48eb-0a35-4a76-92ab-1d987230d288}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>8388608</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66218</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a47525e2-725b-4888-8af1-ba5a60c04f4d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66226</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{13bfd422-6f75-4408-8924-9400ec0cb19c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66230</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c42f1cd6-3a95-4ae2-a513-793c3ae610c7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66235</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>35165044736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3697a558-3ed3-49be-a4c1-c1a4448653b4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66237</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>35165044736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d870c96c-75ee-46a6-8a02-8e4401a73423}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Block</name>\n\t\t\t\t\t\t<description>This filter blocks any inbound non-loopback packets when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66241</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>34359738368</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4137b143-2770-43d4-91a2-55bb0a069830}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Tunnel Exception</name>\n\t\t\t\t\t\t<description>This filter allows for tunneling when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66247</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1152921539503456256</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{17043d46-fac2-4561-bca1-0c7a05e95f5f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Next Hop Tunnel Exception</name>\n\t\t\t\t\t\t<description>This filter allows for tunneling when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66249</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1152921539503456256</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4e718c57-c397-4221-9fbb-14fd51701d6a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound DHCP Exception</name>\n\t\t\t\t\t\t<description>This filter allows for DHCP connections when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>67</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66251</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1154899560384954368</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{916c0dbf-7cec-40f9-9dd9-a5e68b904510}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Loopback Exception</name>\n\t\t\t\t\t\t<description>This filter allows loopback packets when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66599</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{89a89b7c-b5ab-4ed6-bf05-d3059281a5c5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerBoottimeFilter</name>\n\t\t\t\t\t\t<description>Boottime filter for App Containers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4194304</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66995</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e72646bc-7d3f-4c5c-a679-b3716f8c6cc8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerBoottimeFilter</name>\n\t\t\t\t\t\t<description>Boottime filter for App Containers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4194304</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66997</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{21c48193-9ccd-4faf-9590-99b6e4c8af2c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows non-AppContainers to receive loopback traffic from other non-AppContainers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>8388608</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67190</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7a5bb72c-0e75-4ad6-ae8a-9ffd591bb744}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows non-AppContainers to receive loopback traffic from by policy allowed AppContainers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>16777216</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67192</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{19a19270-e1ff-433e-a9a7-c2fd8fb46bcb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows an AppContainer to receive loopback traffic from itself</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4194304</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67194</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1ea45d61-721b-47aa-9b19-81422ba8fdec}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter blocks AppContainer loopback traffic</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1)(A;;CC;;;S-1-15-3-2)(A;;CC;;;S-1-15-3-3)(A;;CC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67200</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{558d57ba-cc4e-4bde-8ea0-8120605580b4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>6755399441055744</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67453</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>4503633987108866</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4ff11138-2d2f-4fcf-a884-d0be3936bc57}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>6755399441055744</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67454</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>4503633987108866</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b1686938-d80f-429d-b7d8-735a34b3605b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>10000001</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>1689399632855040</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67457</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>4503633987108866</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f708e179-0005-47bc-9659-9c9af4525161}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>10000001</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>1689399632855040</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67458</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>4503633987108866</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3668a51e-18e1-4b90-a348-1b26820075ee}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67630</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854776704</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{996c5681-e762-4131-ba41-a4b2ba434af4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67638</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e4bf8fce-257a-409d-82a9-c1d0de1706ef}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>UWP Default Inbound Block Rule</name>\n\t\t\t\t\t\t<description>This is the UWP Default Inbound Block filter. This filter blocks any inbound packets to UWP apps that do not have the correct capability tokens for listening to a resource.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{b36473ef-bf42-49b9-ac24-adba245e825c}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67657</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>549755813888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f6ac8f41-9cbd-478e-97ca-93406509632b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - IPv6 (IPv6-In)</name>\n\t\t\t\t\t\t<description>Inbound rule required to permit IPv6 traffic for ISATAP (Intra-Site Automatic Tunnel Addressing Protocol) and 6to4 tunnelling services.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9b00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>41</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67661</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10377982941077700608</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{46ea0820-54e9-4671-9ee4-b5efa03e7fb2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67665</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264690932318208</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9ed57c1d-5a7c-4821-85c1-bb4d5b005495}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67666</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264691737624576</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{20aa0d80-0876-40ab-9060-81fa4852b804}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67667</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264726097362944</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1d948ce2-c67e-4612-9a13-a86146c93899}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Destination Unreachable Fragmentation Needed (ICMPv4-In)</name>\n\t\t\t\t\t\t<description>Destination Unreachable Fragmentation Needed error messages are sent from any node that a packet traverses which is unable to forward the packet because fragmentation was needed and the don't fragment bit was set.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9e00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67676</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378272112635805696</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4a6c385c-4d41-422e-80e2-a0a8ed98e329}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol (DHCP-In)</name>\n\t\t\t\t\t\t<description>Allows DHCP (Dynamic Host Configuration Protocol) messages for stateful auto-configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9f00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>67</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67678</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378272387513712640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9858d0f0-9bcd-4854-b300-54482931a983}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol for IPv6(DHCPV6-In)</name>\n\t\t\t\t\t\t<description>Allows DHCPV6 (Dynamic Host Configuration Protocol for IPv6) messages for stateful and stateless configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>547</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67682</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378272387513712640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d864789f-7916-44d6-92d2-89c3cb3339ce}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67698</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264690932318208</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fa6ddfcb-e0e4-4e81-851e-bcc403c08a55}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67699</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264691737624576</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{626051d7-734b-4953-9c98-0b07643b6ca2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67700</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264726097362944</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{db7d8fea-b0d0-47b8-ac4c-926e2d6fa47f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wireless Display Infrastructure Back Channel (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Wireless Display Infrastructure back channel [TCP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0063006100730074007300720076002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\castsrv.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7250</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67710</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264416054411264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{be661f2c-e574-4046-8c33-f35b7d29a7e4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Internet Group Management Protocol (IGMP-In)</name>\n\t\t\t\t\t\t<description>IGMP messages are sent and received by nodes to create, join and depart multicast groups.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ac00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>2</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67747</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10377982941077700608</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ead521c1-9552-4d43-8a5c-ceb57aca1dc8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67774</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366095343616</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1c30209e-d2ce-4392-9e8f-f377efb005e5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67775</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366900649984</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{22519d4f-2ea3-4e42-8963-d6f0b7733aa2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67776</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294401260388352</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{29c7768e-567b-4383-9274-88ce90b281c8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67786</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366095343616</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d6953602-d25c-44c8-89be-32af54554764}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67787</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366900649984</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1d52280a-5200-4f1b-b9f2-ff576ef4721e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67788</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294401260388352</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{22d44aac-6653-4e7b-aa73-9e3f59633d4f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67798</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366095343616</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d6346862-1e03-4aeb-ba63-df5639ea6fec}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67799</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366900649984</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6f8d75fc-f3b5-4016-81e2-4f2df77168cf}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67800</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294401260388352</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c041bcbc-c3b0-4002-9e12-424d925ac610}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67810</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366095343616</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ed0b7196-2d26-4cf8-8de9-ae943554347d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67811</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366900649984</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d45600c9-f182-43ae-b1ea-40ebdeea9b99}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67812</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294401260388352</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b6cc72ea-22a1-483e-9636-090bb5302940}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67821</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10377982941077700608</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5bd7313e-64c8-4956-a5d5-a598afeeaea0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67825</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10377982941077700608</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ec36ba3d-18ff-43c9-a323-bd61ebf5cdf9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67830</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366095343616</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{50aedebf-9228-41e5-826c-880c0dfeeeb9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67831</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366900649984</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fce876c5-0650-4cf0-a8e5-32763f4572db}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67832</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294401260388352</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8075d897-3b61-4b0d-a1b7-8cf360304598}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67842</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366095343616</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e2918c6c-304d-4dba-a100-4c19a688541d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67843</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366900649984</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{41000d2a-eba0-40b3-93b1-42d9352f0b1f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67844</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294401260388352</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e7abd6b3-64e1-456b-9de4-80bd51c45892}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00350036005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.56\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67853</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264416054411264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3474e056-188f-44cd-bf0e-f2b9395d00b1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c0065006400670065005c006100700070006c00690063006100740069006f006e005c006d00730065006400670065002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edge\\application\\msedge.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67869</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264416054411264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3bba491b-aba5-4198-9599-0560f76b1c4d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>be00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00360032005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.62\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67873</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10378264416054411264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6236913c-4c2a-430b-817d-4c4fcde825ee}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to CDPSvc port 5050</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5050</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67878</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{66924806-dccf-403e-97a9-14fcc9d64f9a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP traffic to CDPSvc from any port to port 5160 (Wi-Fi Direct Transport)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5160</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67888</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1cf98e43-5bb6-4020-8666-ff5dc7a76123}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP traffic to CDPSvc from any port to port 5040</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5040</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67892</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{215327fd-5d26-4b42-9e18-ee1e1f871285}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block inbound traffic to omadmclient.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ca00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006f006d00610064006d0063006c00690065006e0074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\omadmclient.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{a8b55da6-3aba-41f3-b7ba-443233f64fce}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67894</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>549755813888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9bce6a19-81a8-4ff2-8fe8-e63940b2f706}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block inbound traffic to deviceenroller.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006500760069006300650065006e0072006f006c006c00650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\deviceenroller.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{c4e61e5c-3e66-4efb-b22b-87f8e56cf9c2}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67896</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>549755813888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2ea83abb-f047-4edc-857d-4776be7ddb86}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block inbound traffic to dmcertinst.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006d00630065007200740069006e00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\dmcertinst.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{616fdcf3-1169-46b5-8224-cffc7276af2e}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67906</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>549755813888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{dd658fab-9acd-48c8-9faf-a0e67d88ca4c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>67</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67916</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1978846052089856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{38119412-b39e-48a6-8fcd-1e7dedc4be5e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>547</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67918</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1978846052089856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f4e952f7-52be-4ea6-abb2-90f88debea25}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow RPC/TCP traffic to EventLog</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-880578595-1860270145-482643319-2788375705-1540778122)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67924</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689691673853952</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c76886bf-c4ec-4208-8833-3b243baba297}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to fdphost port 3702</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>da00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67926</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{01569aae-88e0-4cfd-98c5-714f5a86ee63}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to fdphost port 1900</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>dc00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1900</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67930</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4e359e41-d670-4727-a4df-48984e785c40}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP traffic to AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>9955</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67940</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{88e8faac-2f47-487a-a93f-709d1cb0bf7b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67942</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689674493984768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ac4aaa1b-a5f2-41fa-b624-39f34a249fe4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow Grouping to receive from port 3587</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3587</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67948</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1f67d6c0-f1de-4524-a4a7-8a93b03238b2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow PNRP to send to port 3540</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3540</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67952</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c68ac2bf-ad79-4aaf-a764-a9de591a17f3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>IPsec Policy Agent service hardening - Remote Management</name>\n\t\t\t\t\t\t<description>Allow IPsec Policy Agent inbound RPC/TCP traffic for Remote Management</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>eb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67960</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689691673853952</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9b2018aa-486c-4b5e-9a4c-a1b96ecf2cbc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block all inbound traffic to SearchFilterHost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ec00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c00730065006100720063006800660069006c0074006500720068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchfilterhost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{3a5e8a34-82df-4083-a6ed-87ea8ed3507a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67962</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>549755813888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{27db903a-7e87-41ff-8a17-31ca20c9fb16}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block all inbound traffic to SearchProtocolHost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ef00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c00730065006100720063006800700072006f0074006f0063006f006c0068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchprotocolhost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{c0cedbe2-34f4-4491-bd19-152a55b1b6e0}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67968</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>549755813888</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{bd84fe34-f5b3-48c8-90f7-3f647e9bebe3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to SNMPTRAP service</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073006e006d00700074007200610070002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\snmptrap.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3964583643-2633443559-2834438935-3739664028-1580655619)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67970</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689674493984768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c718ce9d-2f72-430c-beeb-789fa9d7c5ea}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow all inbound TCP and RPC to SPPEXTCOMOBJ</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007000700065007800740063006f006d006f0062006a002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\sppextcomobj.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67972</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689674493984768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{bdc0147f-ebdd-4b25-a20a-5c3ed10cbd3f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>TermServiceLOM</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-446051430-1559341753-4161941529-1950928533-810483104)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67976</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689674493984768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3ddc2b0e-33e3-417b-a578-019a4df4b502}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>TermServiceLOM</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-446051430-1559341753-4161941529-1950928533-810483104)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_SET_OPTIONS_AUTH_RECV_ACCEPT_LAYER_V4</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{2ea412db-5c9d-4bbd-9af2-4914d2dbfe17}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67977</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d9a39ed3-698d-434e-83e1-f8a75a5b6a31}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming RPC traffic to VDS</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c007600640073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\vds.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2196396108-1448510645-203779624-3888580976-3789157697)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67980</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689691673853952</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ff843ce9-c5e3-49a0-84d2-cdfa59928fc7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP ports 389 and 636 traffic for vmicheartbeat</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67982</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{810b03cc-8f67-4991-bf02-fe78e19477c2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP ports 389 and 636 traffic for vmicheartbeat</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>636</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67983</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4e788a24-1c9a-4fe2-bfbc-a7c10bd5bd7e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to NTP port 123</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4267341169-2882910712-659946508-2704364837-2204554466)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67988</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b14b6b1e-1bfe-4dfd-8a8e-393da4d4b226}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound RPC traffic to the Block Level Backup service (wbengine) over TCP</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c007700620065006e00670069006e0065002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\wbengine.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1549550529-11381693-4027442525-4081535042-2424139505)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67992</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689691673853952</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{865a8428-bb5e-4b7b-8473-b06bf1b69edb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cast to Device streaming server hardening rules for RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Cast to Device streaming server</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0201000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006d00640065007300650072007600650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\mdeserver.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>23554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68014</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1970874592788480</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d12a44b6-3150-4214-997f-0735fad61441}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cast to Device streaming server hardening rules for RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Cast to Device streaming server</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0201000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006d00640065007300650072007600650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\mdeserver.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>23555</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68015</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1970874592788480</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{690e53fb-c3c2-4e74-a58a-b627852bff69}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cast to Device streaming server hardening rules for RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Cast to Device streaming server</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0201000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006d00640065007300650072007600650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\mdeserver.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>23556</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68016</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1970874592788480</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c3b150a5-0e63-4acf-99d8-93fa101c9f4c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming TCP to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0301000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68020</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1689674493984768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cc829f3a-8ac5-461d-bf9e-b53fa92bf4a6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Media Player Network Sharing Service service hardening - RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Windows Media Player Network Sharing Service</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0901000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730020006d006500640069006100200070006c0061007900650072005c0077006d0070006e006500740077006b002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windows media player\\wmpnetwk.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2375682873-768044350-3534595160-1005545032-2873800392)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68040</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{81b5a3ad-8373-4dda-8234-524b6d6411f7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Media Player Network Sharing Service service hardening - RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Windows Media Player Network Sharing Service</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0901000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730020006d006500640069006100200070006c0061007900650072005c0077006d0070006e006500740077006b002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windows media player\\wmpnetwk.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2375682873-768044350-3534595160-1005545032-2873800392)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68041</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1971149470695424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6c2e5205-ac93-4a93-945a-9d07d7f97ff7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WSH Default Inbound Block</name>\n\t\t\t\t\t\t<description>Blocks all inbound traffic for services who have been network hardened</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>D:(A;NP;CC;;;S-1-5-80-2676549577-1911656217-2625096541-4178041876-1366760775)(A;NP;CC;;;S-1-5-80-1580948945-3239616721-2529237571-3761093093-1214243633)(A;NP;CC;;;S-1-5-80-1058592404-331734164-3167594226-3910907650-1299295147)(A;NP;CC;;;S-1-5-80-1383147646-27650227-2710666058-1662982300-1023958487)(A;NP;CC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)(A;NP;CC;;;S-1-5-80-2611951811-1959136347-1062071333-3982815153-2811717512)(A;NP;CC;;;S-1-5-80-2839768381-3691089589-2614646340-3191585287-3380622033)(A;NP;CC;;;S-1-5-80-538170410-2190149038-799223143-2506663053-4165713448)(A;NP;CC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)(A;NP;CC;;;S-1-5-80-3914275374-678031271-1603343729-3906112567-2888048264)(A;NP;CC;;;S-1-5-80-3787436395-2174616005-3003730137-1094982900-1570567328)(A;NP;CC;;;S-1-5-80-2970612574-78537857-698502321-558674196-1451644582)(A;NP;CC;;;S-1-5-80-880578595-1860270145-482643319-2788375705-1540778122)(A;NP;CC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)(A;NP;CC;;;S-1-5-80-2617507558-3328795327-711547822-311560295-1636921165)(A;NP;CC;;;S-1-5-80-89818136-74175777-88572358-3912780041-2421659406)(A;NP;CC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)(A;NP;CC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)(A;NP;CC;;;S-1-5-80-3088073201-1464728630-1879813800-1107566885-823218052)(A;NP;CC;;;S-1-5-80-2898649604-2335086160-1904548223-3761738420-3855444835)(A;NP;CC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)(A;NP;CC;;;S-1-5-80-967499406-1694984581-2959056265-2481940682-939264259)(A;NP;CC;;;S-1-5-80-1948712186-1330865447-943413596-1669284603-1648638051)(A;NP;CC;;;S-1-5-80-3596911058-2952229928-1888671852-1743692427-614402820)(A;NP;CC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)(A;NP;CC;;;S-1-5-80-3141781312-1794533130-3616533224-2008760771-2116720301)(A;NP;CC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)(A;NP;CC;;;S-1-5-80-117416528-2204451360-1913602512-1355018040-1234992034)(A;NP;CC;;;S-1-5-80-3964583643-2633443559-2834438935-3739664028-1580655619)(A;NP;CC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)(A;NP;CC;;;S-1-5-80-2590341223-3996088049-3993122417-23640849-324535191)(A;NP;CC;;;S-1-5-80-949921180-3923668869-394927020-528789358-3592448931)(A;NP;CC;;;S-1-5-80-768763963-4214222998-2156221936-2953597973-713500239)(A;NP;CC;;;S-1-5-80-2014626298-1656748749-3847481816-918933055-2469338456)(A;NP;CC;;;S-1-5-80-1989757894-211065159-731672622-1783776043-3948168785)(A;NP;CC;;;S-1-5-80-2196396108-1448510645-203779624-3888580976-3789157697)(A;NP;CC;;;S-1-5-80-3074984378-4122987768-2130325677-2031866499-3405430279)(A;NP;CC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)(A;NP;CC;;;S-1-5-80-1877308096-3090306141-3032871208-3115266146-1400827410)(A;NP;CC;;;S-1-5-80-3076811988-2254870394-2658297454-3934945422-2393138642)(A;NP;CC;;;S-1-5-80-3110303136-3426481729-3186938678-1087894076-2178433439)(A;NP;CC;;;S-1-5-80-3098585136-2538892366-1097114017-2832417424-2016953023)(A;NP;CC;;;S-1-5-80-235582178-102246843-358262472-4132936818-1867412993)(A;NP;CC;;;S-1-5-80-1752088424-1054500994-3489791022-3310831482-3926524968)(A;NP;CC;;;S-1-5-80-1549550529-11381693-4027442525-4081535042-2424139505)(A;NP;CC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)(A;NP;CC;;;S-1-5-80-3524758515-3090971750-345616940-2322499744-3530715838)(A;NP;CC;;;S-1-5-80-3299868208-4286319593-1091140620-3583751967-1732444380)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)(A;NP;CC;;;S-1-5-80-2455429942-3131183193-3617688776-595395669-3772047725)(A;NP;CC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)(A;NP;CC;;;S-1-5-80-3916113136-2435487254-2535488001-4050622930-2364918814)(A;NP;CC;;;S-1-5-80-3232712927-1625117661-2590453128-1738570065-3637376297)(A;NP;CC;;;S-1-5-80-3981856537-581775623-1136376035-2066872258-409572886)(A;NP;CC;;;S-1-5-80-689100834-1985168674-2379302174-2224748125-4125308070)(A;NP;CC;;;S-1-5-80-2119957892-4152124429-3625998117-4006912763-1737903618)(A;NP;CC;;;S-1-5-80-1987853863-1639573247-1110726908-1137832616-3599624523)(A;NP;CC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)(A;NP;CC;;;S-1-5-80-113310567-2163499630-2787090463-221477905-209227094)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)S:NO_ACCESS_CONTROL</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{de04f4bd-a953-47f6-b1b6-eb6e24a546d6}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68047</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>274877906944</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{36e4f41f-09b7-4858-a3f7-1f07b2f62dcf}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1024</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e022c}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68052</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{52c05a69-b7bd-471e-90f6-b4165265dee2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>InternetClientServer Inbound Default Rule</name>\n\t\t\t\t\t\t<description>InternetClientServer Inbound Default Rule</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1c01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>0.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>255.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;S-1-15-3-2)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68208</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>824633721848</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{de8c0919-fdae-4263-9186-3209ef7a9203}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [UDP 5004-5009]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open UDP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1f01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5000</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5020</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68215</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882588684629049344</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2f69ffa4-769a-4f40-a565-b54847821e5b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [UDP 5004-5009]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open UDP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1f01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5000</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5020</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68216</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882588718988787712</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{11dd8bd8-1210-4a7e-adb2-460cf2b6a1c1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68221</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882667849466249216</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d9e43dad-f679-4f2f-973d-26827bb8c8d3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68222</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882667883825987584</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9ce6ee0e-7cfb-4b36-bc70-a57d7a63f100}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8558</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68224</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882623869001138176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{80750116-2e93-43ec-8465-40d3dbf5c900}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8558</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68225</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882623903360876544</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e43d0b2d-6a0f-432b-91a1-504f070a7035}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFD ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for the WLAN Service to allow coordination protocol for WFD Service sessions [UDP 7235]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2201000000000000</data>\n\t\t\t\t\t\t<asString>\".......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68235</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882675546047643648</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1c5d0851-defc-4241-8f7f-20f4ce925d56}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFD ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for the WLAN Service to allow coordination protocol for WFD Service sessions [UDP 7235]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2201000000000000</data>\n\t\t\t\t\t\t<asString>\".......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"9\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68236</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882675580407382016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{353edb90-351b-439f-bb1a-499f3ee0d611}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>mDNS (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for mDNS traffic [UDP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2601000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-859482183-879914841-863379149-1145462774-2388618682)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68247</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882667849466249216</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{acfb0f39-be2d-43a6-a260-1b6ea1aa107d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>mDNS (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for mDNS traffic [UDP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2601000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-859482183-879914841-863379149-1145462774-2388618682)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68248</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10882667883825987584</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9f4f259a-998a-4cad-b318-aeab2fccb2d1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2701000000000000</data>\n\t\t\t\t\t\t<asString>'.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68252</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>506382004586020864</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{826bf713-3f53-422d-9ab6-f66251968bdf}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2701000000000000</data>\n\t\t\t\t\t\t<asString>'.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"9\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68253</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>506382038945759232</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f7b10da2-52b3-4496-af84-a4141986b1fb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2901000000000000</data>\n\t\t\t\t\t\t<asString>).......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68260</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>506374308004626432</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a2e9e943-0681-4a0e-8c58-485b3ceff496}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2901000000000000</data>\n\t\t\t\t\t\t<asString>).......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68261</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>506374342364364800</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0ae65187-1f62-4d22-9fde-4f60caac6393}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2a01000000000000</data>\n\t\t\t\t\t\t<asString>*.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68264</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>506100529609310208</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7184c665-64f2-476c-af5a-01cc74b700da}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2a01000000000000</data>\n\t\t\t\t\t\t<asString>*.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68265</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>506100563969048576</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d69d41e1-ee28-47d3-90a0-4e0eef6a868f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68286</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366095343616</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4442f710-abac-421f-9d4f-f02939d23c63}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68287</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294366900649984</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d68c9ba7-1425-44da-b537-7642ce5bbe9d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68288</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376294401260388352</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Receive/Accept v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"35\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_NAP_CONTEXT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>45</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e012d}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>278</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Receive/Accept v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"35\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_NAP_CONTEXT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>46</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"7\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_INITIATE_SECURE_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Initiate Secure v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Verifies that each incoming connection that is supposed to arrive secure arrives securely.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>14</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_CHIMNEY_ACCEPT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Chimney Offload ALE Receive/Accept v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Enables or disables TCP Chimney Offload for each incoming connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>22</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec Inbound Tunnel ALE Receive/Accept v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Permits IPsec tunnel mode IP-in-IP packets when they get classified at the ALE receive/accept layer.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>26</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_TEMPLATES_ACCEPT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Templates ALE Receive/Accept v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Applies TCP Template for each incoming connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>36</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_SET_OPTIONS_AUTH_RECV_ACCEPT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Set Option ALE Receive/Accept v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Sets classify options on inbound flows.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>40</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_POLICY_SILENT_MODE_AUTH_RECV_ACCEPT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Policy Silent Mode ALE Receive/Accept v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Audit and log policy for incoming connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>44</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e022e}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Allows secondary connections.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>285</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"202\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{dc95b53e-01cf-4058-821d-350b3d0d4676}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66210</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1153167795211468800</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f444c576-6e60-4ea2-9faa-80d57ed12cd2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66211</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1153167795211468800</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0c3be01b-fe70-4cc4-89dc-c07996b67e6d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>8388608</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66215</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1165065e-4996-4338-abaf-4b8556b4d431}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>8388608</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66219</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0ccc96a3-8c5c-45e2-b80e-7e37b16cc1ad}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66227</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cbfb56db-3c85-4543-9bc2-76ea28cdd74e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66231</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2dd96961-5757-434f-b617-34e732517c0e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66232</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>8992587776</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{375fb39b-08c6-40f2-bdf2-08fa63f970a2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66233</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>8992587776</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2db25e6c-f07a-44f4-b6c8-50a330d2790b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66234</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>8992587776</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b6fdab6b-dcc6-43e3-99ce-7aeca65063a4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66236</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>8992587776</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b02a4013-b6b5-4859-9168-1e3299e43b24}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Block</name>\n\t\t\t\t\t\t<description>This filter blocks any inbound non-loopback packets when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66240</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>8589934592</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8b50e2ec-7cf0-4b71-b42e-5b0536f6cab8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Tunnel Exception</name>\n\t\t\t\t\t\t<description>This filter allows for tunneling when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66246</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1152921513465217024</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3180114b-8338-4740-9a16-444134ad62f4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Next Hop Tunnel Exception</name>\n\t\t\t\t\t\t<description>This filter allows for tunneling when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66248</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1152921513465217024</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{567d3836-3f5b-4067-b9c4-952f677010a2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Neighbor Discovery Exception</name>\n\t\t\t\t\t\t<description>This filter allows for Neighbor Discovery when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66250</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1153167795211468800</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3a90a266-1519-4d23-911b-e84cd0f02ab8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound DHCP Exception</name>\n\t\t\t\t\t\t<description>This filter allows for DHCP connections when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>547</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66252</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1153169727946752000</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0593d9b7-8e2b-44b1-9f9e-2831da1c9bd9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Loopback Exception</name>\n\t\t\t\t\t\t<description>This filter allows loopback packets when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66598</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{70694559-714a-4a38-a0cd-51439e06f1d8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound ICMP Exception</name>\n\t\t\t\t\t\t<description>This filter allows for ICMP connections when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"4\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>1</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66602</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1225225526688350208</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{84750a0c-b836-48e3-ab80-104985c857db}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerBoottimeFilter</name>\n\t\t\t\t\t\t<description>Boottime filter for App Containers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_BOOTTIME</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4194304</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66996</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b98b75dc-17c0-4e84-bd4e-2080527ca6a6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerBoottimeFilter</name>\n\t\t\t\t\t\t<description>Boottime filter for App Containers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4194304</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66998</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5e48f4ad-9f6c-4c4e-a83a-d1ac10317436}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Teredo socket option opt out block filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>{c698301d-9129-450c-937c-f4b834bfb374}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>{7b6b11f6-cbb5-433c-ae06-6a4f0076e49e}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67005</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6109847e-3461-46a7-8bbb-58bd48643bf0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows non-AppContainers to receive loopback traffic from other non-AppContainers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>8388608</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67191</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1f1a43af-2fa5-4f1a-8d8e-395b07d53b24}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows non-AppContainers to receive loopback traffic from by policy allowed AppContainers</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>16777216</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67193</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a974e5b7-ff22-43d9-a813-01c5d1283b2e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows an AppContainer to receive loopback traffic from itself</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4194304</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67195</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e3ac824d-4754-4603-80fb-48fe7450e46b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter blocks AppContainer loopback traffic</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1)(A;;CC;;;S-1-15-3-2)(A;;CC;;;S-1-15-3-3)(A;;CC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67201</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{36bb2266-0f81-4937-af6b-63086254e9df}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>6755399441055744</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67455</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>562958543355906</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d3e85111-30f5-4ff0-850f-8622624aadcf}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>0</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>6755399441055744</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67456</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>562958543355906</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8c9a53ad-9d03-4280-9e0a-53754eb303bd}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>10000002</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>1689399632855040</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67459</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>562958543355906</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8540bba7-40c4-4959-85fd-c082688a1176}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Un-quarantine filter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>0</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>10000002</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t\t\t<uint64>1689399632855040</uint64>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67460</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>562958543355906</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6fc5fe31-8779-4b15-9576-3ba7ff0b0ce4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67634</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854776768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{569702e8-0383-45e2-a938-743a0b269a89}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Query User</name>\n\t\t\t\t\t\t<description>Prompt the User for a decision corresponding to Inbound Traffic. This filter blocks any inbound packets for which there is no explicit rule to allow the packet, unless the user has allowed through the Query User pop up.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67642</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c833a355-c4ff-4504-ba03-e56b2edcf0b2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>UWP Default Inbound Block Rule</name>\n\t\t\t\t\t\t<description>This is the UWP Default Inbound Block filter. This filter blocks any inbound packets to UWP apps that do not have the correct capability tokens for listening to a resource.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{b36473ef-bf42-49b9-ac24-adba245e825c}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67658</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1c63c63e-acc4-4ef8-b31e-a3c7156292df}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - IPv6 (IPv6-In)</name>\n\t\t\t\t\t\t<description>Inbound rule required to permit IPv6 traffic for ISATAP (Intra-Site Automatic Tunnel Addressing Protocol) and 6to4 tunnelling services.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9b00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>41</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67662</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376504785133109248</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b9346349-afa6-45c1-875e-5e12437b1648}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67670</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540038224674816</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e0e890e5-0dbb-449d-926f-36ecc0d32307}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67671</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540038627328000</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{79923371-5423-4aa7-9d60-86afaac5ce75}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67672</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540047217262592</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e67d1661-76e2-4fdf-bbab-5f1cd28e3ea4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67673</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540038627328000</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{72a57651-9ca9-4550-ba15-cb5c797b3281}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9c00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67674</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540047217262592</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9ee8af53-7d0c-48f1-892e-3038f67c8771}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Router Advertisement (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Router Advertisement messages are sent by routers to other nodes for stateless auto-configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9d00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67675</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10664770345656909824</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{269d6a27-dcd7-4d83-8e64-34e06f1fab75}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol (DHCP-In)</name>\n\t\t\t\t\t\t<description>Allows DHCP (Dynamic Host Configuration Protocol) messages for stateful auto-configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9f00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>67</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67680</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376541962370023424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4f4f8d89-0d09-4170-91e5-b50e05fd12ba}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Dynamic Host Configuration Protocol for IPv6(DHCPV6-In)</name>\n\t\t\t\t\t\t<description>Allows DHCPV6 (Dynamic Host Configuration Protocol for IPv6) messages for stateful and stateless configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>547</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67684</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376541962370023424</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{dc4fed41-3e88-48ec-8363-d1dabe968953}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Solicitation (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Solicitations are sent by nodes to discover the link-layer address of another on-link IPv6 node.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67685</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{24a4ff08-78cb-425a-8412-de0c6eee513f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Solicitation (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Solicitations are sent by nodes to discover the link-layer address of another on-link IPv6 node.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67686</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{925f3a0e-53c9-4c55-8506-1a50be54a688}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Solicitation (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Solicitations are sent by nodes to discover the link-layer address of another on-link IPv6 node.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67687</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b0c5f46c-f20b-455a-94a5-ba616b03ba89}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Solicitation (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Solicitations are sent by nodes to discover the link-layer address of another on-link IPv6 node.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67688</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7c5bf10d-2519-47ac-9864-28272c35ecd6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Solicitation (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Solicitations are sent by nodes to discover the link-layer address of another on-link IPv6 node.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67689</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b0a2ee9b-60e1-4c3a-a2e8-db6ffaec87e2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67703</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540038224674816</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e5c30a1f-bd12-46f2-9eb5-0dfa08e13499}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67704</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540038627328000</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0921d09f-c82d-41d2-814f-6ac23cfb74f5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67705</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540047217262592</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{31d9ed8a-a509-4a04-a9fc-c09be2ae87af}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67706</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540038627328000</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{78a6c883-2926-4fa7-82ed-335f51c3b5bd}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Delivery Optimization (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule to allow Delivery Optimization to connect to remote endpoints</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3055155277-3816794035-3994065555-2874236192-2193176987)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7680</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67707</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376540047217262592</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{076c0bad-60b8-4a49-a4ce-83bdc9a879f0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Router Solicitation (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Router Solicitation messages are sent by nodes seeking routers to provide stateless auto-configuration.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67708</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{45791038-5827-4a2e-993b-7ebfdccffa6a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wireless Display Infrastructure Back Channel (TCP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Wireless Display Infrastructure back channel [TCP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0063006100730074007300720076002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\castsrv.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7250</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67712</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0f24cc1b-3e3d-44e1-90a0-f20ac3e4462e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Advertisement (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Advertisement messages are sent by nodes to notify other nodes of link-layer address changes or in response to a Neighbour Discovery Solicitation request.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67713</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{52dc6841-c31e-4d63-bc57-4e0e2b9b9671}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Advertisement (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Advertisement messages are sent by nodes to notify other nodes of link-layer address changes or in response to a Neighbour Discovery Solicitation request.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67714</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{42f19b9f-5956-45b5-a51c-5b5267d5005a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Advertisement (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Advertisement messages are sent by nodes to notify other nodes of link-layer address changes or in response to a Neighbour Discovery Solicitation request.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67715</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2d1be467-dab7-4309-89bc-0e16efbeb1e7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Advertisement (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Advertisement messages are sent by nodes to notify other nodes of link-layer address changes or in response to a Neighbour Discovery Solicitation request.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67716</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c094b7da-b5e2-4cac-bf03-d3f8dd685948}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Neighbour Discovery Advertisement (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Neighbour Discovery Advertisement messages are sent by nodes to notify other nodes of link-layer address changes or in response to a Neighbour Discovery Solicitation request.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67717</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4aee5ef2-93d5-46e6-bee0-725d8e4cdc07}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Parameter Problem (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Parameter Problem error messages are sent by nodes as a result of incorrectly generated packets.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67730</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4887adbb-3a7a-48f0-a6b1-9243969c1d1c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Parameter Problem (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Parameter Problem error messages are sent by nodes as a result of incorrectly generated packets.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67731</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{56a02554-23d2-4984-95a9-2f461cc4fa66}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Parameter Problem (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Parameter Problem error messages are sent by nodes as a result of incorrectly generated packets.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67732</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{13668b24-1745-4eef-8097-a78f1683cf37}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Parameter Problem (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Parameter Problem error messages are sent by nodes as a result of incorrectly generated packets.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67733</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d9f3965a-d5ba-402c-be4b-fd46d258c1e8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Parameter Problem (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Parameter Problem error messages are sent by nodes as a result of incorrectly generated packets.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>4</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67734</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{630130e6-d0ee-4f95-917f-727386eef3d2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Packet Too Big (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Packet Too Big error messages are sent from any node that a packet traverses which is unable to forward the packet because the packet is too large for the next link.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67735</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{24a965e8-7b7e-4248-b6fa-b4f93990c49a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Packet Too Big (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Packet Too Big error messages are sent from any node that a packet traverses which is unable to forward the packet because the packet is too large for the next link.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67736</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1f160125-9b36-460c-a743-a7e17c45ed4f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Packet Too Big (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Packet Too Big error messages are sent from any node that a packet traverses which is unable to forward the packet because the packet is too large for the next link.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67737</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5cdc61d6-8697-400d-91c3-ff55d00ff9a9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Packet Too Big (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Packet Too Big error messages are sent from any node that a packet traverses which is unable to forward the packet because the packet is too large for the next link.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67738</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{412c57e1-2038-40cf-a4eb-1006cc161782}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Packet Too Big (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Packet Too Big error messages are sent from any node that a packet traverses which is unable to forward the packet because the packet is too large for the next link.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>a900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>2</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67739</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{33ea4c7f-33e0-4ebc-934e-5c4d8c6bb21e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Destination Unreachable (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Destination Unreachable error messages are sent from any node that a packet traverses which is unable to forward the packet for any reason except congestion.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ab00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67742</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5c2001c6-fed1-458f-a2e5-f05059ba33b3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Destination Unreachable (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Destination Unreachable error messages are sent from any node that a packet traverses which is unable to forward the packet for any reason except congestion.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ab00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67743</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{11917a18-01cd-4f40-94a2-c11700ffd140}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Destination Unreachable (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Destination Unreachable error messages are sent from any node that a packet traverses which is unable to forward the packet for any reason except congestion.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ab00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67744</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{65a7e69a-8dda-48bf-8f7f-77f85ef66d4d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Destination Unreachable (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Destination Unreachable error messages are sent from any node that a packet traverses which is unable to forward the packet for any reason except congestion.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ab00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67745</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0c139d5c-00c0-40fe-a291-119da3eb65a1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Destination Unreachable (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Destination Unreachable error messages are sent from any node that a packet traverses which is unable to forward the packet for any reason except congestion.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ab00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67746</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d91c02d3-8acf-4ca8-b00e-c70abeb4e4f4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Internet Group Management Protocol (IGMP-In)</name>\n\t\t\t\t\t\t<description>IGMP messages are sent and received by nodes to create, join and depart multicast groups.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ac00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>2</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67748</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376504785133109248</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e67bf87-b3ab-4faa-966d-0374819472f1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Time Exceeded (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Time Exceeded error messages are generated from any node that a packet traverses if the Hop Limit value is decremented to zero at any point on the path.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67761</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{03d3765e-5cbb-482f-92e2-b1c2813d43a0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Time Exceeded (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Time Exceeded error messages are generated from any node that a packet traverses if the Hop Limit value is decremented to zero at any point on the path.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67762</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7e3d00b3-7372-4d01-9d99-0ad72294a64e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Time Exceeded (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Time Exceeded error messages are generated from any node that a packet traverses if the Hop Limit value is decremented to zero at any point on the path.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67763</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f4ad030a-de57-4da0-aae8-34007c10742c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Time Exceeded (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Time Exceeded error messages are generated from any node that a packet traverses if the Hop Limit value is decremented to zero at any point on the path.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67764</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969907851264</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{db8b7e5e-dfe4-4a20-9ce2-94970713653f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Time Exceeded (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Time Exceeded error messages are generated from any node that a packet traverses if the Hop Limit value is decremented to zero at any point on the path.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67765</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539978497785856</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6fe6052c-9f1b-449f-80e6-1933bd00c2bd}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67779</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293747620052992</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{25113d41-4bfd-4f42-b8ed-0782825d5cef}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67780</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e33d2046-cd76-4858-82c6-4604a02f215f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67781</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c67dd978-8cee-43a5-b7c5-7394d13639dd}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67782</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{577f1fbd-6697-4374-831d-ab4957b5d82a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/DisplayName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Win32WebViewHost_10.0.22000.1_neutral_neutral_cw5n1h2txyewy?ms-resource://Windows.Win32WebViewHost/resources/Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67783</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{497778bf-d906-447e-97c6-3d90e01faf13}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67791</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293747620052992</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fa37a31f-edf8-45f1-a12a-3979b049b980}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67792</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7348c729-bea7-4ce3-9126-91bacbf060ab}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67793</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{245b69e4-1a3a-4fe8-9121-f716a7758498}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67794</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{06682e90-222d-41d9-a82a-c80c77bd5d24}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>XING</name>\n\t\t\t\t\t\t<description>XING</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-830604253-3178213212-3804702845-3552981612-1670190244-297742492-2307346640</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67795</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f8fe4921-4cac-4e53-9a94-6f3ba592041f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67803</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293747620052992</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{54e08d95-dd62-45d7-89d8-aaa4b6ef259b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67804</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{219df051-7115-4bae-844c-ff5b93b401c5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67805</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{bfec4abb-9fae-4382-9946-0f22c6cc800a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67806</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7951db55-918d-43fc-b66a-21a5f9c754e5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName}</name>\n\t\t\t\t\t\t<description>@{microsoft.windowscommunicationsapps_16005.14326.20544.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_Description}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2551677095-2355568638-4209445997-2436930744-3692183382-387691378-1866284433</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67807</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2743ed06-9818-463f-8aa4-b97a298ee1e3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67815</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293747620052992</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6e4a1c0a-729d-431d-9f8d-0a1df4f16f2f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67816</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{173e4b5d-3445-413c-a0a6-f1900681f228}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67817</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f5f65248-7c4f-4a2a-bf44-ef3d8385796f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67818</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{95150dd6-5f6b-4d72-a721-bd90f0f3e1e3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Xbox Game Bar</name>\n\t\t\t\t\t\t<description>Xbox Game Bar</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1714399563-1326177402-2048222277-143663168-2151391019-765408921-4098702777</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67819</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5e458804-9d6b-4374-aeb0-0fab8ebfa394}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67823</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376504785133109248</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f767a292-c59e-40a5-a090-99dbd8574026}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Teams</name>\n\t\t\t\t\t\t<description>Microsoft Teams</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730061007000700073005c006d006900630072006f0073006f00660074007400650061006d0073005f00320032003000300036002e003600300030002e0031003100330033002e0037003400300039005f007800360034005f005f003800770065006b007900620033006400380062006200770065005c006d0073007400650061006d0073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windowsapps\\microsoftteams_22006.600.1133.7409_x64__8wekyb3d8bbwe\\msteams.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67827</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376504785133109248</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5c28dd7c-af06-4a4c-876c-0dc6ab29ee70}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67835</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293747620052992</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{559be0e2-e31c-4860-b8f4-f535b5f067ba}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67836</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{16aba0dc-3359-47fe-acf5-496ac83cbaa8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67837</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{54f2e6d9-ec87-40ef-91a5-e48f51fbce78}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67838</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c176404f-b6b6-470b-b3be-7c5db41a3c08}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</name>\n\t\t\t\t\t\t<description>@{Microsoft.Windows.Photos_2021.21120.8011.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Windows.Photos/Resources/AppStoreName}</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>b900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-2226957697-3030467180-2301525-4248967783-2024719031-2325529081-2915787518</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67839</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0bfafb37-da2b-4b57-96c4-dd5e14ef9b9b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67847</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293747620052992</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2756a9a2-8940-469d-b0e4-d093e24b8737}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67848</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0b19d824-b94d-4b8c-8eb0-fb82a74f4c5b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67849</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ee6e661b-040e-43b2-9443-46047eaf059e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67850</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{42de4209-2a60-449b-81c9-feda0c9914be}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cortana</name>\n\t\t\t\t\t\t<description>Cortana</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ba00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1880626798-2296700190-2192216202-2581987570-949377748-777141861-2889999867</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67851</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c808a57d-2fb7-4e7d-a772-5667a9bdbc70}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00350036005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.56\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67855</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{639e9c00-79c8-4dfb-a3f1-dd6713b27868}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>bd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c0065006400670065005c006100700070006c00690063006100740069006f006e005c006d00730065006400670065002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edge\\application\\msedge.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67871</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1256e94d-6137-4f0d-b73a-f8f9ccb8d64a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Edge (mDNS-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for Microsoft Edge to allow mDNS traffic.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>be00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073002000280078003800360029005c006d006900630072006f0073006f00660074005c00650064006700650077006500620076006900650077005c006100700070006c00690063006100740069006f006e005c00390038002e0030002e0031003100300038002e00360032005c006d0073006500640067006500770065006200760069006500770032002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files (x86)\\microsoft\\edgewebview\\application\\98.0.1108.62\\msedgewebview2.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67875</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376539969505198080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5eb6cad8-1d8a-4c51-b026-807f3e3d92e0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to CDPSvc port 5050</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5050</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67879</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{211c67b6-5dec-468d-9bf9-564f606ad8be}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP traffic to CDPSvc from any port to port 5160 (Wi-Fi Direct Transport)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5160</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67889</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d9f11c8c-075e-4271-8012-655bb3f9dde1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP traffic to CDPSvc from any port to port 5040</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5040</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67893</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{42b88eb0-34e6-478f-908b-585607fbe41a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block inbound traffic to omadmclient.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ca00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006f006d00610064006d0063006c00690065006e0074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\omadmclient.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{a8b55da6-3aba-41f3-b7ba-443233f64fce}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67895</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{475d5508-5d3a-46d5-9805-e407589473ec}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block inbound traffic to deviceenroller.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006500760069006300650065006e0072006f006c006c00650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\deviceenroller.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{c4e61e5c-3e66-4efb-b22b-87f8e56cf9c2}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67897</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f0faf4fb-252e-47b9-af71-f9a81a7a650d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block inbound traffic to dmcertinst.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006d00630065007200740069006e00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\dmcertinst.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{616fdcf3-1169-46b5-8224-cffc7276af2e}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67907</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{62af150d-b92a-423a-ab03-b55021e030ef}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>67</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67917</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>248420908400640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e53b388f-16cd-408e-8e6b-1aa8dfdc1ccc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>547</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67919</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>248420908400640</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{388a863a-333e-4270-8ea8-3756df7eb475}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow RPC/TCP traffic to EventLog</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-880578595-1860270145-482643319-2788375705-1540778122)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67925</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211316685930496</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ac41a204-b76a-46b4-b943-a8c24d3c5336}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to fdphost port 3702</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>da00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67927</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cb0601b2-92ec-40b8-8422-c92875ed2d56}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to fdphost port 1900</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>dc00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1900</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67931</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e76e740-04c4-4d35-a298-11f7dc596749}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP traffic to AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>9955</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67941</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{19ed4871-1493-432b-8d8c-0ccc59f25f6d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67943</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211312390963200</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{84c3250b-945e-4d9e-821e-09efa2c38757}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow Grouping to receive from port 3587</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3587</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67949</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{75fe5296-4bc2-4582-a285-7442b870bf8e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow PNRP to send to port 3540</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3540</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67953</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ad422266-d71d-4380-b44a-fb3e2e95868b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>IPsec Policy Agent service hardening - Remote Management</name>\n\t\t\t\t\t\t<description>Allow IPsec Policy Agent inbound RPC/TCP traffic for Remote Management</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>eb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67961</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211316685930496</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{19682e8b-d911-49dc-900a-54cef7765f40}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block all inbound traffic to SearchFilterHost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ec00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c00730065006100720063006800660069006c0074006500720068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchfilterhost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{3a5e8a34-82df-4083-a6ed-87ea8ed3507a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67963</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2be90617-8637-421f-acca-fb35be82a866}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block all inbound traffic to SearchProtocolHost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ef00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c00730065006100720063006800700072006f0074006f0063006f006c0068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchprotocolhost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{c0cedbe2-34f4-4491-bd19-152a55b1b6e0}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67969</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8dba5a64-72a1-4fcd-bf10-7350fdfe0e60}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to SNMPTRAP service</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073006e006d00700074007200610070002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\snmptrap.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3964583643-2633443559-2834438935-3739664028-1580655619)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67971</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211312390963200</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{031039e8-157e-4c49-a1b7-831802af44ea}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow all inbound TCP and RPC to SPPEXTCOMOBJ</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007000700065007800740063006f006d006f0062006a002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\sppextcomobj.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67973</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211312390963200</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0adc1095-75ad-4dbe-a1ff-a2cfa50c9182}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>TermServiceLOM</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-446051430-1559341753-4161941529-1950928533-810483104)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67978</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211312390963200</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{569847e2-c2ad-471a-a0aa-7db6eda39cce}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>TermServiceLOM</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-446051430-1559341753-4161941529-1950928533-810483104)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>FWPM_CALLOUT_SET_OPTIONS_AUTH_RECV_ACCEPT_LAYER_V6</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{2ea412db-5c9d-4bbd-9af2-4914d2dbfe17}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67979</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{aeb06403-14b2-4f11-911c-d2e71406b781}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming RPC traffic to VDS</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c007600640073002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\vds.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2196396108-1448510645-203779624-3888580976-3789157697)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67981</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211316685930496</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{06ec84e9-0aaf-4282-b849-ffe57c1b0d6a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP ports 389 and 636 traffic for vmicheartbeat</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67984</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e32e6791-5d61-4ba0-a2c7-6b02831e6a45}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound TCP ports 389 and 636 traffic for vmicheartbeat</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>636</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67985</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c6c6d63a-882b-4f39-8ceb-36c8f7555219}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound UDP traffic to NTP port 123</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4267341169-2882910712-659946508-2704364837-2204554466)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67989</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0c2c073b-bf6b-4c9f-9606-9ce2126c2f50}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow inbound RPC traffic to the Block Level Backup service (wbengine) over TCP</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c007700620065006e00670069006e0065002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\wbengine.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1549550529-11381693-4027442525-4081535042-2424139505)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67993</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211316685930496</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7414eaee-1713-4f1a-836e-a33cf8e7f5ee}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cast to Device streaming server hardening rules for RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Cast to Device streaming server</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0201000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006d00640065007300650072007600650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\mdeserver.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>23554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68017</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246428043575296</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{74e34cf5-b726-4da8-b473-4740ac1dacfe}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cast to Device streaming server hardening rules for RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Cast to Device streaming server</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0201000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006d00640065007300650072007600650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\mdeserver.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>23555</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68018</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246428043575296</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7e0a5145-d1e5-42f7-9d4e-d4dd9196b7b0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Cast to Device streaming server hardening rules for RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Cast to Device streaming server</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0201000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006d00640065007300650072007600650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\mdeserver.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>23556</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68019</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246428043575296</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{54d6e8b9-dec2-46f8-a998-91264ad65362}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming TCP to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0301000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68021</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>211312390963200</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{80d42d94-a6d0-4a5d-b8c6-20cdeda245cb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Media Player Network Sharing Service service hardening - RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Windows Media Player Network Sharing Service</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0901000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730020006d006500640069006100200070006c0061007900650072005c0077006d0070006e006500740077006b002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windows media player\\wmpnetwk.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2375682873-768044350-3534595160-1005545032-2873800392)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68042</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b4aeacd5-c926-446e-addd-dc86b9979b64}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Media Player Network Sharing Service service hardening - RTSP</name>\n\t\t\t\t\t\t<description>Allow incoming RTSP connections to the Windows Media Player Network Sharing Service</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0901000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f007700730020006d006500640069006100200070006c0061007900650072005c0077006d0070006e006500740077006b002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windows media player\\wmpnetwk.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2375682873-768044350-3534595160-1005545032-2873800392)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68043</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>246496763052032</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ec51a54f-1281-48b4-9a56-386529896692}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WSH Default Inbound Block</name>\n\t\t\t\t\t\t<description>Blocks all inbound traffic for services who have been network hardened</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>D:(A;NP;CC;;;S-1-5-80-2676549577-1911656217-2625096541-4178041876-1366760775)(A;NP;CC;;;S-1-5-80-1580948945-3239616721-2529237571-3761093093-1214243633)(A;NP;CC;;;S-1-5-80-1058592404-331734164-3167594226-3910907650-1299295147)(A;NP;CC;;;S-1-5-80-1383147646-27650227-2710666058-1662982300-1023958487)(A;NP;CC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)(A;NP;CC;;;S-1-5-80-2611951811-1959136347-1062071333-3982815153-2811717512)(A;NP;CC;;;S-1-5-80-2839768381-3691089589-2614646340-3191585287-3380622033)(A;NP;CC;;;S-1-5-80-538170410-2190149038-799223143-2506663053-4165713448)(A;NP;CC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)(A;NP;CC;;;S-1-5-80-3914275374-678031271-1603343729-3906112567-2888048264)(A;NP;CC;;;S-1-5-80-3787436395-2174616005-3003730137-1094982900-1570567328)(A;NP;CC;;;S-1-5-80-2970612574-78537857-698502321-558674196-1451644582)(A;NP;CC;;;S-1-5-80-880578595-1860270145-482643319-2788375705-1540778122)(A;NP;CC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)(A;NP;CC;;;S-1-5-80-2617507558-3328795327-711547822-311560295-1636921165)(A;NP;CC;;;S-1-5-80-89818136-74175777-88572358-3912780041-2421659406)(A;NP;CC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)(A;NP;CC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)(A;NP;CC;;;S-1-5-80-3088073201-1464728630-1879813800-1107566885-823218052)(A;NP;CC;;;S-1-5-80-2898649604-2335086160-1904548223-3761738420-3855444835)(A;NP;CC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)(A;NP;CC;;;S-1-5-80-967499406-1694984581-2959056265-2481940682-939264259)(A;NP;CC;;;S-1-5-80-1948712186-1330865447-943413596-1669284603-1648638051)(A;NP;CC;;;S-1-5-80-3596911058-2952229928-1888671852-1743692427-614402820)(A;NP;CC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)(A;NP;CC;;;S-1-5-80-3141781312-1794533130-3616533224-2008760771-2116720301)(A;NP;CC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)(A;NP;CC;;;S-1-5-80-117416528-2204451360-1913602512-1355018040-1234992034)(A;NP;CC;;;S-1-5-80-3964583643-2633443559-2834438935-3739664028-1580655619)(A;NP;CC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)(A;NP;CC;;;S-1-5-80-2590341223-3996088049-3993122417-23640849-324535191)(A;NP;CC;;;S-1-5-80-949921180-3923668869-394927020-528789358-3592448931)(A;NP;CC;;;S-1-5-80-768763963-4214222998-2156221936-2953597973-713500239)(A;NP;CC;;;S-1-5-80-2014626298-1656748749-3847481816-918933055-2469338456)(A;NP;CC;;;S-1-5-80-1989757894-211065159-731672622-1783776043-3948168785)(A;NP;CC;;;S-1-5-80-2196396108-1448510645-203779624-3888580976-3789157697)(A;NP;CC;;;S-1-5-80-3074984378-4122987768-2130325677-2031866499-3405430279)(A;NP;CC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)(A;NP;CC;;;S-1-5-80-1877308096-3090306141-3032871208-3115266146-1400827410)(A;NP;CC;;;S-1-5-80-3076811988-2254870394-2658297454-3934945422-2393138642)(A;NP;CC;;;S-1-5-80-3110303136-3426481729-3186938678-1087894076-2178433439)(A;NP;CC;;;S-1-5-80-3098585136-2538892366-1097114017-2832417424-2016953023)(A;NP;CC;;;S-1-5-80-235582178-102246843-358262472-4132936818-1867412993)(A;NP;CC;;;S-1-5-80-1752088424-1054500994-3489791022-3310831482-3926524968)(A;NP;CC;;;S-1-5-80-1549550529-11381693-4027442525-4081535042-2424139505)(A;NP;CC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)(A;NP;CC;;;S-1-5-80-3524758515-3090971750-345616940-2322499744-3530715838)(A;NP;CC;;;S-1-5-80-3299868208-4286319593-1091140620-3583751967-1732444380)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)(A;NP;CC;;;S-1-5-80-2455429942-3131183193-3617688776-595395669-3772047725)(A;NP;CC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)(A;NP;CC;;;S-1-5-80-3916113136-2435487254-2535488001-4050622930-2364918814)(A;NP;CC;;;S-1-5-80-3232712927-1625117661-2590453128-1738570065-3637376297)(A;NP;CC;;;S-1-5-80-3981856537-581775623-1136376035-2066872258-409572886)(A;NP;CC;;;S-1-5-80-689100834-1985168674-2379302174-2224748125-4125308070)(A;NP;CC;;;S-1-5-80-2119957892-4152124429-3625998117-4006912763-1737903618)(A;NP;CC;;;S-1-5-80-1987853863-1639573247-1110726908-1137832616-3599624523)(A;NP;CC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)(A;NP;CC;;;S-1-5-80-113310567-2163499630-2787090463-221477905-209227094)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)S:NO_ACCESS_CONTROL</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{de04f4bd-a953-47f6-b1b6-eb6e24a546d6}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68046</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>68719476736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{27d0382a-b7fd-4536-a470-71a5ea27cb99}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1024</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e022e}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68053</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{58fd9e51-dfb2-4b8b-9f4e-fbe76618a080}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68088</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{98b70176-3bcc-4734-b93b-4eaeeeb6a37b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68089</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a300f22a-ae94-4b5f-aa5f-33ff9fbbfce7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68090</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d90cbaa3-eaf3-4021-a70a-c130bc327519}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68091</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c364ce80-e89b-489f-b7ab-ba5da061dc31}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68092</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{941565df-dade-42f5-b5cb-ed48e857a508}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68093</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{00ea3695-8388-45b7-9aaf-49947f97dec5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68094</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{73508c22-0149-461b-b1f2-3cdc929feea1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68095</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{198ff4f2-5d0a-40bf-b43e-1d4684b11b65}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68096</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7f8a98cc-cc4b-410d-ad3c-2d0dd1aebe0e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68097</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d2e40d8a-cc87-4ad1-b496-bd28937f886e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68098</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6c68a273-fac7-4be9-a9d1-fe56ffa5981d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>135</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68099</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5f7e61e7-2af6-4f12-9a07-5522f61f4b86}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68100</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{19590b9d-8cbb-42c2-9a7a-ab0775ecd93b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68101</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{29f7b740-30f9-4972-adc7-cbfa92803082}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68102</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6dfc4acb-0027-4d5a-b527-f452291ec069}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68103</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b1e42ad1-a690-42c2-abf2-57ce5aded578}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68104</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{eb76a71a-600b-4489-be24-d5cf94512966}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68105</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fed10772-760a-4002-a372-699758835bb5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68106</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0ce6b8ef-3f7b-44c7-b923-538b5c6f85cf}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68107</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{40e896f7-d6fa-48a0-8d3d-b89e5c480196}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68108</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7bead13c-ef8a-406c-b796-15424030645a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68109</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0ef1dbc6-5f1c-46fa-a4be-7b601943da68}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68110</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{56610786-c7ca-41fc-abce-e661c467a692}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>134</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68111</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0677b532-ed94-451f-a801-b69c51ae8932}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>InternetClientServer Inbound Default Rule</name>\n\t\t\t\t\t\t<description>InternetClientServer Inbound Default Rule</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1c01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;S-1-15-3-2)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68209</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>206158431224</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1582a99d-c924-4a69-8c31-38c3e811b06e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [UDP 5004-5009]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open UDP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1f01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5000</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5020</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68218</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700788216413290496</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{77733464-f8b8-4139-82ce-d711bf56aa0c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [UDP 5004-5009]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open UDP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1f01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5000</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>5020</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68219</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700788225003225088</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b12e5bff-8fa5-42bd-a2d5-9904d7ca9d03}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68227</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799211529568256</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{bb69d143-1985-454a-b089-308e8e8dc13e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>554</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68228</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799220119502848</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5acc61db-fd65-4cb1-bc32-8ca12e976908}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8558</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68230</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700792614459801600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{aab1ec78-7ee4-49d1-98fc-8c3b631ae069}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Media Foundation Network Source IN [TCP 554]</name>\n\t\t\t\t\t\t<description>InBound Rule for the Microsoft Media Foundation's Capture SVC to open TCP port to enable RTSP</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2001000000000000</data>\n\t\t\t\t\t\t<asString> .......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3915894004-2104103821-3047269622-1811662266-774708259)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8554</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>8558</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68231</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700792623049736192</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{35a7aaa5-1838-4ae3-817a-69cb1c19cd18}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Done (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Multicast Listener Done messages inform local routers that there are no longer any members remaining for a specific multicast address on the subnet.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2101000000000000</data>\n\t\t\t\t\t\t<asString>!.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>132</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68232</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799142810091520</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f93ea8eb-52e1-42c1-9ad4-7c36ffb021d6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Done (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Multicast Listener Done messages inform local routers that there are no longer any members remaining for a specific multicast address on the subnet.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2101000000000000</data>\n\t\t\t\t\t\t<asString>!.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>132</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68233</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799151400026112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a06c507e-0e22-4963-8f44-87618653a39c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFD ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for the WLAN Service to allow coordination protocol for WFD Service sessions [UDP 7235]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2201000000000000</data>\n\t\t\t\t\t\t<asString>\".......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68238</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700801135674916864</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{33989d24-4033-4bd0-b74f-9bcf3d09dbeb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFD ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for the WLAN Service to allow coordination protocol for WFD Service sessions [UDP 7235]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2201000000000000</data>\n\t\t\t\t\t\t<asString>\".......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"9\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68239</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700801144264851456</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6a14e12f-4cc9-4ba8-8087-ce034ce64aa9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Report v2 (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Multicast Listener Report v2 message is used by a listening node to either immediately report its interest in receiving multicast traffic at a specific multicast address or in response to a Multicast Listener Query.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2301000000000000</data>\n\t\t\t\t\t\t<asString>#.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>143</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68240</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799142810091520</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b39cb12b-597e-47f5-8e3f-9dd402f046f7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Report v2 (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>Multicast Listener Report v2 message is used by a listening node to either immediately report its interest in receiving multicast traffic at a specific multicast address or in response to a Multicast Listener Query.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2301000000000000</data>\n\t\t\t\t\t\t<asString>#.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>143</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68241</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799151400026112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{58df562c-0db6-447a-9f51-a1a9ca36a7da}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Query (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>An IPv6 multicast-capable router uses the Multicast Listener Query message to query a link for multicast group membership.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2401000000000000</data>\n\t\t\t\t\t\t<asString>$.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>130</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68242</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799142810091520</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{422c78ee-d74f-4287-92cb-f7ebd9b13d7f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Query (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>An IPv6 multicast-capable router uses the Multicast Listener Query message to query a link for multicast group membership.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2401000000000000</data>\n\t\t\t\t\t\t<asString>$.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>130</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68243</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799151400026112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c86577a4-f769-4666-8ef8-da0d20234c50}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Report (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>The Multicast Listener Report message is used by a listening node to either immediately report its interest in receiving multicast traffic at a specific multicast address or in response to a Multicast Listener Query.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2501000000000000</data>\n\t\t\t\t\t\t<asString>%.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"6\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>131</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68244</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799142810091520</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7aebe37a-9063-4a41-bfe2-c5f36fc48aa1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Core Networking - Multicast Listener Report (ICMPv6-In)</name>\n\t\t\t\t\t\t<description>The Multicast Listener Report message is used by a listening node to either immediately report its interest in receiving multicast traffic at a specific multicast address or in response to a Multicast Listener Query.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2501000000000000</data>\n\t\t\t\t\t\t<asString>%.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>530079007300740065006d000000</data>\n\t\t\t\t\t\t\t\t\t<asString>System</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>131</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68245</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799151400026112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c60857b2-86f1-4479-ac73-2d5cc8d478cb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>mDNS (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for mDNS traffic [UDP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2601000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-859482183-879914841-863379149-1145462774-2388618682)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68250</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799211529568256</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{47eea8d3-5188-4143-acdf-202833261322}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>mDNS (UDP-In)</name>\n\t\t\t\t\t\t<description>Inbound rule for mDNS traffic [UDP]</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2601000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-859482183-879914841-863379149-1145462774-2388618682)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5353</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68251</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10700799220119502848</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{efc20c2d-6c5a-4e5b-8a34-98b4483999a2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2701000000000000</data>\n\t\t\t\t\t\t<asString>'.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68254</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>324507594213294080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{35413795-c6d4-4215-a986-4f6430c1d790}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-In)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2701000000000000</data>\n\t\t\t\t\t\t<asString>'.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"9\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68255</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>324507602803228672</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d6b96843-703f-4584-bd03-4031d5af55ea}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2901000000000000</data>\n\t\t\t\t\t\t<asString>).......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68262</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>324505670067945472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2cbbf8db-968e-4981-9676-5e84aba688c6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2901000000000000</data>\n\t\t\t\t\t\t<asString>).......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68263</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>324505678657880064</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ab7af7b8-34b2-47a2-bb0d-cfac2a1a824e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2a01000000000000</data>\n\t\t\t\t\t\t<asString>*.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68266</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>324472409841205248</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{15f2650a-c099-4d56-a815-a14736393443}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow incoming WSD to PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2a01000000000000</data>\n\t\t\t\t\t\t<asString>*.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68267</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>324472418431139840</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{69bf11f7-0703-41a2-933f-5699bf1ebbb4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68291</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293747620052992</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{436b36f0-9320-423f-a04f-1a9ca00007fb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68292</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{00117075-341a-482a-acc5-e8b238826759}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68293</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c5399251-8bef-439b-8544-8f21ffa7ba41}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68294</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293748022706176</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{82915472-9da4-48af-b908-8c7a02f6ddaf}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Microsoft Store</name>\n\t\t\t\t\t\t<description>Microsoft Store</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2d01000000000000</data>\n\t\t\t\t\t\t<asString>-.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>9</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-15-2-1609473798-1231923017-684268153-4268514328-882773646-2760585773-1760938157</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-21-3172917561-344687468-1323853919-1001)(A;;CCRC;;;AC)(A;;CCRC;;;S-1-15-3-1)(A;;CCRC;;;S-1-15-3-2)(A;;CCRC;;;S-1-15-3-3)(A;;CCRC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68295</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>10376293756612640768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Receive/Accept v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"35\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SIO_FIREWALL_SYSTEM_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_NAP_CONTEXT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>47</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e012f}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>279</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Connect v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"37\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PEER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_EFFECTIVE_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>48</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"8\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_ALE_CONNECT_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec ALE Connect v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Applies IPsec policy modifiers to client applications.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>15</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_CHIMNEY_CONNECT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Chimney Offload ALE Connect v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Enables or disables TCP Chimney Offload for each outgoing connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>19</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_SET_OPTIONS_AUTH_CONNECT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Set Option ALE Connect v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Sets classify options on outbound flows.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>23</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_TEMPLATES_CONNECT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Templates ALE Connect v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Applies TCP Template for each outgoing connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>33</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_RESERVED_AUTH_CONNECT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Reserved callout</name>\n\t\t\t\t\t\t<description>WFP Built-in Reserved callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>37</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_POLICY_SILENT_MODE_AUTH_CONNECT_LAYER_V4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Policy Silent Mode ALE Connect v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Audit and log policy for outgoing connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>41</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_BUILT_IN_RESERVED_3</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Accept Redirect Proxy Tag ALE Connect v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Tags the outgoing connection from an accept redirected proxy app to prevent infinite redirection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>47</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0230}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Allows secondary connections.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>282</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"58\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b6b2ca61-fb98-4422-adc2-e7cf56b3680c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66222</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{082edf36-12d7-4698-858a-cf274b78d09a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Loopback Exception</name>\n\t\t\t\t\t\t<description>This filter allows loopback packets when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66601</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{304a339a-845d-47b1-9ad9-df3b55c31f26}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows outbound AppContainer loopback traffic</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67196</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a167c347-5706-417d-ab3f-dc24cdd9c69b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter blocks loopback traffic to port 137</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>137</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1)(A;;CC;;;S-1-15-3-2)(A;;CC;;;S-1-15-3-3)(A;;CC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67198</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6b9edc4a-2d53-465e-8c54-13b65024e3b6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter blocks AppContainer loopback traffic</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1)(A;;CC;;;S-1-15-3-2)(A;;CC;;;S-1-15-3-3)(A;;CC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67202</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0a023b5d-ef1a-45a7-9cde-efcb260348a6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67644</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854777848</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3bcbc8e4-3be2-43d5-8c7e-765d0de1b129}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67648</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f7a47614-e0ec-4d6a-9cf2-99b8f993d1b7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>UWP Default Outbound Block Rule</name>\n\t\t\t\t\t\t<description>This is the UWP Default Outbound Block filter. This filter blocks any outbound packets from UWP apps that do not have the correct capability tokens for the resource they are trying to reach.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9a00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{11ec8831-cda4-4bab-aa69-cb45e32f4ea9}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67659</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{81fe2467-61a3-46dc-8c59-a6a3277920ff}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AxInstSV TCP outbound allow</name>\n\t\t\t\t\t\t<description>Allow only outbound TCP traffic from AxInstSV</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1058592404-331734164-3167594226-3910907650-1299295147)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67876</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8b7fd125-5491-4c7a-96cb-10aacbccc7d9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from CDPSvc from any port to port 5040</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5040</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67880</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1ce149fd-f072-4c78-998c-aa9be7b13469}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from any port to CDPSvc port 5050</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5050</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67882</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{71a8a4a8-65c6-4a5b-9d97-f15febdc067a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from CDPSvc port 5050</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5050</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67884</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1055737321095168</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2c84d584-7bc5-40db-b6c8-b28d4e40a483}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from CDPSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67886</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{672ccb84-0882-4542-8404-7650c867a918}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from CDPSvc from any port to port 5160 (Wi-Fi Direct Transport)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5160</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67890</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{185c4b7a-6d3f-46ab-9a41-146c6ec220be}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block outbound traffic from deviceenroller.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cc00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006500760069006300650065006e0072006f006c006c00650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\deviceenroller.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{4dd4109f-8980-4e66-b307-887227d761a4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67898</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b832287d-98a4-4509-9edf-e796cf1a363f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from deviceenroller.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006500760069006300650065006e0072006f006c006c00650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\deviceenroller.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67900</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985299857440768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7d008627-122e-4757-94f3-40fd1e6a32ab}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block outbound traffic from omadmclient.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ce00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006f006d00610064006d0063006c00690065006e0074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\omadmclient.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{f876928c-1566-4b9a-a110-57d531115565}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67902</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4d0e90b1-9d99-4847-afad-63b5336d414a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from omadmclient.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cf00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006f006d00610064006d0063006c00690065006e0074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\omadmclient.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67904</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985299857440768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{af29eee0-e0d3-4834-8d51-668e799215c9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block outbound traffic from dmcertinst.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006d00630065007200740069006e00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\dmcertinst.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{3742db91-517a-4f69-b378-08c5c09364b3}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67908</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4fdcd4c6-c326-4b60-b320-84fc25c10cec}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from dmcertinst.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006d00630065007200740069006e00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\dmcertinst.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67910</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985299857440768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a93ec3cd-e423-4bd5-a38d-3593f40c2fe6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from DMEnrollment</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-538170410-2190149038-799223143-2506663053-4165713448)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67912</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c830f042-5e91-4521-9d1a-c08aeac73a48}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>67</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67914</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1057661466443776</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{bd69a0ac-3eec-43c2-8e77-57159930f77f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>547</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67920</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1057661466443776</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e9f93da5-9659-46c5-9525-93d80021b23f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Device Metadata Retrieval</name>\n\t\t\t\t\t\t<description>Allow dmrc communication with WMIS</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-286057374-2594772386-1471686342-3682429118-820474675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>80</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67922</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{180cd47b-5d74-4505-a1ff-cd84de1d2af5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from fdphost port 3702</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>db00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67928</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e168718-b7a5-4ae5-80ee-67e629a24d19}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from fdphost port 1900</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>dd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1900</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67932</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b0589e60-9f9a-43aa-9d6b-5f8d52dafd90}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from fdphost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>de00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67934</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{04419b91-af39-4843-9b6a-7676f52111a6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic to LMHosts port 53</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>df00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>53</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67936</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{5ba31685-5a93-4ec1-8559-7e4dc41cd4a0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic to LMHosts port 53</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>53</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67938</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{03d2ca8b-de9c-4271-9379-2c7e01346d1d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67944</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{beec7dba-4e91-4b23-a7b7-4b946d7b0a03}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67946</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0f4eb248-1eb1-44e8-af26-3139fc422409}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow Grouping to send to port 3587</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3587</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67950</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8b18ea82-9285-46f1-9d5c-8825be7defbb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow PNRP to send to port 3540</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3540</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1024</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67954</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1056012199002112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{48f7051b-b0ca-4b0d-b025-7331aa9463cc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>IPsec Policy Agent service hardening - LDAP/TCP</name>\n\t\t\t\t\t\t<description>Allow IPsec Policy Agent outbound LDAP/TCP traffic to Active Directory</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67956</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2b4cfcf1-3509-4705-ab10-1385dd1b35e3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>IPsec Policy Agent service hardening - LDAP/UDP</name>\n\t\t\t\t\t\t<description>Allow IPsec Policy Agent outbound LDAP/UDP traffic to Active Directory</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ea00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67958</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{58ee92c1-2cae-43e7-ab8a-b4063a731c8a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block all outbound traffic from SearchFilterHost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ed00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c00730065006100720063006800660069006c0074006500720068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchfilterhost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{03843031-9e01-449d-b94b-047c6fbe714c}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67964</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>137438953472</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{59fe49fe-991b-4b1c-bba1-70fef8bbd4c6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound LDAP traffic from SearchIndexer</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ee00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073006500610072006300680069006e00640065007800650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchindexer.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-117416528-2204451360-1913602512-1355018040-1234992034)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67966</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0391cc05-7e9f-4eef-be8f-7ba037e44a34}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow all outbound TCP and RPC from SPPEXTCOMOBJ</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007000700065007800740063006f006d006f0062006a002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\sppextcomobj.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67974</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2d002771-07b6-494c-abea-3ab1a1b89169}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow all outbound TCP ports traffic for vmicheartbeat</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67986</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985643454824448</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{79d5cc16-49fc-4996-b3a5-2f02a2d79e01}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from local NTP port 123 to remote NTP port 123</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4267341169-2882910712-659946508-2704364837-2204554466)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67990</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>1057661466443776</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{06fc5b6e-ce4e-4355-ae4f-5b3a5c4ccf25}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow TCP traffic from Wcmsvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fa00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67994</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0f6315c7-96ec-4ed5-9553-6c3ba0363148}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow NTP traffic from Wcmsvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67996</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{13f46409-d68e-488e-ad18-7f4fb2fe2b64}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow Out TCP traffic from WinDefend</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fc00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f0077007300200064006500660065006e006400650072005c006d0073006d00700065006e0067002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windows defender\\msmpeng.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67998</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{aef21544-e454-4d2f-a571-e803b3a9e120}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from WinHttpAutoProxySvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2455429942-3131183193-3617688776-595395669-3772047725)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68000</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8915b586-51f3-4e71-9282-cff4dbeca20c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow TCP traffic from lpasvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0001000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3916113136-2435487254-2535488001-4050622930-2364918814)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68010</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ee4f6b00-cba1-40d4-8d89-0310b8975f30}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow HTTP traffic from cloudidsvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0101000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2119957892-4152124429-3625998117-4006912763-1737903618)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>443</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68012</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>987292722266112</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ca791cd5-85a3-4b7f-8b6b-9d9cb02ac722}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing TCP from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0401000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68022</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4c5f7c67-c7ce-4313-a45b-70f03fbad5fc}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WinDefend Outbound for TCP</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0a01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d0064006100740061005c006d006900630072006f0073006f00660074005c00770069006e0064006f0077007300200064006500660065006e006400650072005c0070006c006100740066006f0072006d005c0034002e00310038002e0032003200300031002e00310030002d0030005c006d0073006d00700065006e0067002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\programdata\\microsoft\\windows defender\\platform\\4.18.2201.10-0\\msmpeng.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68044</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>985368576917504</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d07a9c84-a50f-40c9-80f5-303ab4951d68}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WSH Default Outbound Block</name>\n\t\t\t\t\t\t<description>Blocks all outbound traffic for services who have been network hardened</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>D:(A;NP;CC;;;S-1-5-80-2676549577-1911656217-2625096541-4178041876-1366760775)(A;NP;CC;;;S-1-5-80-1580948945-3239616721-2529237571-3761093093-1214243633)(A;NP;CC;;;S-1-5-80-1058592404-331734164-3167594226-3910907650-1299295147)(A;NP;CC;;;S-1-5-80-1383147646-27650227-2710666058-1662982300-1023958487)(A;NP;CC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)(A;NP;CC;;;S-1-5-80-2611951811-1959136347-1062071333-3982815153-2811717512)(A;NP;CC;;;S-1-5-80-2839768381-3691089589-2614646340-3191585287-3380622033)(A;NP;CC;;;S-1-5-80-538170410-2190149038-799223143-2506663053-4165713448)(A;NP;CC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)(A;NP;CC;;;S-1-5-80-2627155378-1124895651-3977206752-2157268346-3811978089)(A;NP;CC;;;S-1-5-80-3787436395-2174616005-3003730137-1094982900-1570567328)(A;NP;CC;;;S-1-5-80-2970612574-78537857-698502321-558674196-1451644582)(A;NP;CC;;;S-1-5-80-880578595-1860270145-482643319-2788375705-1540778122)(A;NP;CC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)(A;NP;CC;;;S-1-5-80-2617507558-3328795327-711547822-311560295-1636921165)(A;NP;CC;;;S-1-5-80-89818136-74175777-88572358-3912780041-2421659406)(A;NP;CC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)(A;NP;CC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)(A;NP;CC;;;S-1-5-80-3088073201-1464728630-1879813800-1107566885-823218052)(A;NP;CC;;;S-1-5-80-2898649604-2335086160-1904548223-3761738420-3855444835)(A;NP;CC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)(A;NP;CC;;;S-1-5-80-967499406-1694984581-2959056265-2481940682-939264259)(A;NP;CC;;;S-1-5-80-1948712186-1330865447-943413596-1669284603-1648638051)(A;NP;CC;;;S-1-5-80-3596911058-2952229928-1888671852-1743692427-614402820)(A;NP;CC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)(A;NP;CC;;;S-1-5-80-3141781312-1794533130-3616533224-2008760771-2116720301)(A;NP;CC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)(A;NP;CC;;;S-1-5-80-117416528-2204451360-1913602512-1355018040-1234992034)(A;NP;CC;;;S-1-5-80-3964583643-2633443559-2834438935-3739664028-1580655619)(A;NP;CC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)(A;NP;CC;;;S-1-5-80-2590341223-3996088049-3993122417-23640849-324535191)(A;NP;CC;;;S-1-5-80-949921180-3923668869-394927020-528789358-3592448931)(A;NP;CC;;;S-1-5-80-768763963-4214222998-2156221936-2953597973-713500239)(A;NP;CC;;;S-1-5-80-2014626298-1656748749-3847481816-918933055-2469338456)(A;NP;CC;;;S-1-5-80-1989757894-211065159-731672622-1783776043-3948168785)(A;NP;CC;;;S-1-5-80-3074984378-4122987768-2130325677-2031866499-3405430279)(A;NP;CC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)(A;NP;CC;;;S-1-5-80-1877308096-3090306141-3032871208-3115266146-1400827410)(A;NP;CC;;;S-1-5-80-3076811988-2254870394-2658297454-3934945422-2393138642)(A;NP;CC;;;S-1-5-80-3110303136-3426481729-3186938678-1087894076-2178433439)(A;NP;CC;;;S-1-5-80-3098585136-2538892366-1097114017-2832417424-2016953023)(A;NP;CC;;;S-1-5-80-235582178-102246843-358262472-4132936818-1867412993)(A;NP;CC;;;S-1-5-80-1752088424-1054500994-3489791022-3310831482-3926524968)(A;NP;CC;;;S-1-5-80-1549550529-11381693-4027442525-4081535042-2424139505)(A;NP;CC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)(A;NP;CC;;;S-1-5-80-3524758515-3090971750-345616940-2322499744-3530715838)(A;NP;CC;;;S-1-5-80-3299868208-4286319593-1091140620-3583751967-1732444380)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)(A;NP;CC;;;S-1-5-80-2455429942-3131183193-3617688776-595395669-3772047725)(A;NP;CC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)(A;NP;CC;;;S-1-5-80-3916113136-2435487254-2535488001-4050622930-2364918814)(A;NP;CC;;;S-1-5-80-3232712927-1625117661-2590453128-1738570065-3637376297)(A;NP;CC;;;S-1-5-80-3981856537-581775623-1136376035-2066872258-409572886)(A;NP;CC;;;S-1-5-80-689100834-1985168674-2379302174-2224748125-4125308070)(A;NP;CC;;;S-1-5-80-2119957892-4152124429-3625998117-4006912763-1737903618)(A;NP;CC;;;S-1-5-80-1987853863-1639573247-1110726908-1137832616-3599624523)(A;NP;CC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)(A;NP;CC;;;S-1-5-80-113310567-2163499630-2787090463-221477905-209227094)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)S:NO_ACCESS_CONTROL</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{de04f4bd-a953-47f6-b1b6-eb6e24a546d6}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68049</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>68719476736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{e4639f53-f9fd-4949-aec7-e3eefd4e43b4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1024</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0230}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68054</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{44a498f6-139a-41f2-8d9b-a4ec3885601a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>InternetClientServer Outbound Default Rule</name>\n\t\t\t\t\t\t<description>InternetClientServer Outbound Default Rule</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1d01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>0.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>255.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;S-1-15-3-2)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68210</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>206158432248</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4c0965e1-a644-4286-b045-9dd0db4c0ac6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>InternetClient Default Rule</name>\n\t\t\t\t\t\t<description>InternetClient Default Rule</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1e01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>0.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>255.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;S-1-15-3-1)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68212</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>206158432248</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c70ec623-3900-4841-b0d8-57ba37b02d03}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-Out)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2801000000000000</data>\n\t\t\t\t\t\t<asString>(.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68256</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>253259241672933376</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{825d479b-33b3-47ee-9667-cddf6646c94a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-Out)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2801000000000000</data>\n\t\t\t\t\t\t<asString>(.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"9\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68257</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>253259276032671744</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{7f29d8b2-c34e-4676-a939-0a56f30f4fb2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2b01000000000000</data>\n\t\t\t\t\t\t<asString>+.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68268</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>253257317527584768</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{71d65205-3137-4c02-a833-96c6b1ee73d8}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2b01000000000000</data>\n\t\t\t\t\t\t<asString>+.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68269</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>253257351887323136</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{427a2740-809d-4a32-8a1e-03584c5ca624}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2c01000000000000</data>\n\t\t\t\t\t\t<asString>,.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68272</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>253188872928755712</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4d84d151-4c1c-40c9-a0e6-d2be2bdb3bf2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2c01000000000000</data>\n\t\t\t\t\t\t<asString>,.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>10.0.2.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>224.0.0.0</uint32>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t\t\t<uint32>239.255.255.255</uint32>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68273</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>253188907288494080</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Connect v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"37\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PEER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_EFFECTIVE_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>49</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0131}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V4_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>274</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Connect v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"37\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PEER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_EFFECTIVE_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>50</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"8\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_IPSEC_ALE_CONNECT_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in IPsec ALE Connect v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Applies IPsec policy modifiers to client applications.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>16</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_CHIMNEY_CONNECT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Chimney Offload ALE Connect v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Enables or disables TCP Chimney Offload for each outgoing connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>20</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_SET_OPTIONS_AUTH_CONNECT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Set Option ALE Connect v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Sets classify options on outbound flows.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>24</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_TCP_TEMPLATES_CONNECT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in TCP Templates ALE Connect v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Applies TCP Template for each outgoing connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>34</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_RESERVED_AUTH_CONNECT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Reserved callout</name>\n\t\t\t\t\t\t<description>WFP Built-in Reserved callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>38</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_POLICY_SILENT_MODE_AUTH_CONNECT_LAYER_V6</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Policy Silent Mode ALE Connect v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Audit and log policy for outgoing connection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>42</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_BUILT_IN_RESERVED_4</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Accept Redirect Proxy Tag ALE Connect v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Tags the outgoing connection from an accept redirected proxy app to prevent infinite redirection.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>48</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0232}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Allows secondary connections.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>283</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"82\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0aa7fff8-919f-453c-928c-28a12122ba38}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66223</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{15d327cf-89c3-4032-9ded-774ae6b0b49f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Quarantine Default Inbound Loopback Exception</name>\n\t\t\t\t\t\t<description>This filter allows loopback packets when the network was in quarantine state. The quarantine state was triggered by a network state change.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_PERSISTENT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66600</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2c73ec55-e34c-4ebd-8e2e-6268206bc153}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter allows outbound AppContainer loopback traffic</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67197</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d26fbfe7-0a28-45b2-83fd-95b733e1a9fd}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter blocks loopback traffic to port 137</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>137</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1)(A;;CC;;;S-1-15-3-2)(A;;CC;;;S-1-15-3-3)(A;;CC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67199</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c5fbb5ec-e4fc-4aac-810a-4219a166cf1c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AppContainerLoopback</name>\n\t\t\t\t\t\t<description>This filter blocks AppContainer loopback traffic</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;AC)(A;;CC;;;S-1-15-3-1)(A;;CC;;;S-1-15-3-2)(A;;CC;;;S-1-15-3-3)(A;;CC;;;S-1-15-3-4214768333-1334025770-122408079-3919188833)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67203</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551614</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8c247d5b-b402-40bb-a35b-a55ec3043f1a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>8</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67646</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>9223372036854776824</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0c22b647-52e8-484c-aaea-f3d7f4d9dc11}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Default Outbound</name>\n\t\t\t\t\t\t<description>This is the default outbound filter which blocks or permits traffic based on user configured default settings</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67650</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>3458764513820540928</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{3af696f6-6a4c-47bb-b032-e6c4faf8cb88}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>UWP Default Outbound Block Rule</name>\n\t\t\t\t\t\t<description>This is the UWP Default Outbound Block filter. This filter blocks any outbound packets from UWP apps that do not have the correct capability tokens for the resource they are trying to reach.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>9a00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{11ec8831-cda4-4bab-aa69-cb45e32f4ea9}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67660</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>68719476736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{091b498c-ac44-4e38-8c3d-f40842f71020}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>AxInstSV TCP outbound allow</name>\n\t\t\t\t\t\t<description>Allow only outbound TCP traffic from AxInstSV</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1058592404-331734164-3167594226-3910907650-1299295147)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67877</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{66fc1e24-94a1-4f94-8737-a817f1f93509}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from CDPSvc from any port to port 5040</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5040</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67881</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cab91dde-a33b-4d6d-a373-6f1a085eeee2}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from any port to CDPSvc port 5050</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5050</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67883</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{12268eee-a96f-414e-ada7-93a9394ae68b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from CDPSvc port 5050</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c500000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5050</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67885</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>123248381526016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2bea35b9-7546-4ba2-bc6d-a11e73d8837b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from CDPSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67887</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2a9440fb-0bb0-4ff6-8154-d72d60d909a7}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from CDPSvc from any port to port 5160 (Wi-Fi Direct Transport)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>c800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>5160</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67891</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8f1aa30f-7e4d-48d2-8fdf-35af8b7e5b61}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block outbound traffic from deviceenroller.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cc00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006500760069006300650065006e0072006f006c006c00650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\deviceenroller.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{4dd4109f-8980-4e66-b307-887227d761a4}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67899</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>68719476736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6ce0ad1a-cbde-40c6-b942-6c6e066d8c2a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from deviceenroller.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006500760069006300650065006e0072006f006c006c00650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\deviceenroller.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67901</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105621835743232</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f30f70ce-47ff-49f7-ba7c-145a3a153449}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block outbound traffic from omadmclient.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ce00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006f006d00610064006d0063006c00690065006e0074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\omadmclient.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{f876928c-1566-4b9a-a110-57d531115565}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67903</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>68719476736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d44825a1-c9fc-485f-98ce-3dd7eecc4876}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from omadmclient.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>cf00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c006f006d00610064006d0063006c00690065006e0074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\omadmclient.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67905</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105621835743232</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{30e3a6fe-4e5f-4560-8c1b-62c80250709a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block outbound traffic from dmcertinst.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d100000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006d00630065007200740069006e00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\dmcertinst.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{3742db91-517a-4f69-b378-08c5c09364b3}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67909</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>68719476736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fd5d3521-ac9a-4868-9645-f41db0a96e6a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from dmcertinst.exe</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0064006d00630065007200740069006e00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\dmcertinst.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67911</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105621835743232</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1e6890f9-a50c-4153-a5fc-33c0ba2a1836}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from DMEnrollment</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-538170410-2190149038-799223143-2506663053-4165713448)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67913</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0036b900-9ed0-4134-bb44-eea7ec2cedee}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>68</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>67</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67915</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>123660698386432</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{296e7a35-573a-40e4-b4e4-b9b262f32db0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>DhcpFirewallPolicy</name>\n\t\t\t\t\t\t<description>DhcpFirewallPolicy</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d700000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>546</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>547</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67921</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>123660698386432</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{166a1317-b522-45a1-80ea-9e19153e6b25}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Device Metadata Retrieval</name>\n\t\t\t\t\t\t<description>Allow dmrc communication with WMIS</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>d800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-286057374-2594772386-1471686342-3682429118-820474675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>80</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67923</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a777788c-4705-40a1-ab2b-5a19760caed9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from fdphost port 3702</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>db00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67929</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f0c77ee0-11f9-4b1c-a42d-8f616ae354f3}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from fdphost port 1900</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>dd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>1900</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67933</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{69327dfd-e878-4369-929c-e3b6e676fbfd}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from fdphost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>de00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67935</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{626987bd-a33b-47b9-9615-37f568d01d82}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic to LMHosts port 53</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>df00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>53</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67937</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c29ccedf-39ff-434c-9a77-dcbf23e65d78}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic to LMHosts port 53</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e000000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>53</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67939</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c0781e20-e98e-4edd-8629-83265170d024}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e300000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67945</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{19a3f689-f230-43bc-a1c6-ea367563c31f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from AJRouter</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e400000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67947</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{eb9eb551-58b9-438d-93e3-5e9bfd3fa4a4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow Grouping to send to port 3587</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3587</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67951</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{72db2410-37d0-4a0c-ab90-2f27b91f8fa6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow PNRP to send to port 3540</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3540</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1024</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67955</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>123385820479488</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fc565d30-798d-41ae-9037-248e9c9ce633}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>IPsec Policy Agent service hardening - LDAP/TCP</name>\n\t\t\t\t\t\t<description>Allow IPsec Policy Agent outbound LDAP/TCP traffic to Active Directory</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>e900000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67957</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{051461c3-1d6e-4214-9e67-820fc2e2d10a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>IPsec Policy Agent service hardening - LDAP/UDP</name>\n\t\t\t\t\t\t<description>Allow IPsec Policy Agent outbound LDAP/UDP traffic to Active Directory</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ea00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67959</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{755391ea-bc1b-4822-907e-1102749cfb38}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Block all outbound traffic from SearchFilterHost</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ed00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c00730065006100720063006800660069006c0074006500720068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchfilterhost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{03843031-9e01-449d-b94b-047c6fbe714c}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67965</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>68719476736</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6a06e8ac-2968-42da-8e51-0e4a0d3b92a4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound LDAP traffic from SearchIndexer</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ee00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073006500610072006300680069006e00640065007800650072002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\searchindexer.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-117416528-2204451360-1913602512-1355018040-1234992034)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>389</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67967</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{25a4c983-4191-4c5a-8895-590d672049e0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow all outbound TCP and RPC from SPPEXTCOMOBJ</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f200000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007000700065007800740063006f006d006f0062006a002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\sppextcomobj.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67975</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4222b1e0-05d8-45ef-b1d6-eda36f16a14f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow all outbound TCP ports traffic for vmicheartbeat</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f600000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67987</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105793634435072</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1b42b924-8daa-4a22-a438-4ce931610f24}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound UDP traffic from local NTP port 123 to remote NTP port 123</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>f800000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4267341169-2882910712-659946508-2704364837-2204554466)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67991</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>123660698386432</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f79665c6-3633-4d7b-9c44-461d448be8be}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow TCP traffic from Wcmsvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fa00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67995</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{6b276741-4138-4dd3-8d90-394998728306}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow NTP traffic from Wcmsvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fb00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>123</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67997</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{65ad8ec4-5659-493a-998e-f37f54973c02}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow Out TCP traffic from WinDefend</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fc00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d002000660069006c00650073005c00770069006e0064006f0077007300200064006500660065006e006400650072005c006d0073006d00700065006e0067002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\program files\\windows defender\\msmpeng.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67999</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{023dae46-b7c7-40c8-90ca-45c70ba97068}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outbound TCP traffic from WinHttpAutoProxySvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>fd00000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2455429942-3131183193-3617688776-595395669-3772047725)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68001</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{734e929d-2a7b-45e8-a576-1721a9075413}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow TCP traffic from lpasvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0001000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3916113136-2435487254-2535488001-4050622930-2364918814)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68011</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0999a296-1a9e-40e5-bd28-08bf5f4fa7a6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow HTTP traffic from cloudidsvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0101000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-2119957892-4152124429-3625998117-4006912763-1737903618)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>443</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68013</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>106068512342016</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{d60de164-082e-49f2-8c7f-1fc5f5749f53}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing TCP from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0401000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68023</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c0d7b9ed-5246-4d59-87fc-1d39339b02c4}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WinDefend Outbound for TCP</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>0a01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"3\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00700072006f006700720061006d0064006100740061005c006d006900630072006f0073006f00660074005c00770069006e0064006f0077007300200064006500660065006e006400650072005c0070006c006100740066006f0072006d005c0034002e00310038002e0032003200300031002e00310030002d0030005c006d0073006d00700065006e0067002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\programdata\\microsoft\\windows defender\\platform\\4.18.2201.10-0\\msmpeng.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68045</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>105656195481600</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{05baa320-a8d8-40e3-b310-3b7d7c115dac}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WSH Default Outbound Block</name>\n\t\t\t\t\t\t<description>Blocks all outbound traffic for services who have been network hardened</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>D:(A;NP;CC;;;S-1-5-80-2676549577-1911656217-2625096541-4178041876-1366760775)(A;NP;CC;;;S-1-5-80-1580948945-3239616721-2529237571-3761093093-1214243633)(A;NP;CC;;;S-1-5-80-1058592404-331734164-3167594226-3910907650-1299295147)(A;NP;CC;;;S-1-5-80-1383147646-27650227-2710666058-1662982300-1023958487)(A;NP;CC;;;S-1-5-80-3433512109-503559027-1389316256-1766580070-2256751264)(A;NP;CC;;;S-1-5-80-2611951811-1959136347-1062071333-3982815153-2811717512)(A;NP;CC;;;S-1-5-80-2839768381-3691089589-2614646340-3191585287-3380622033)(A;NP;CC;;;S-1-5-80-538170410-2190149038-799223143-2506663053-4165713448)(A;NP;CC;;;S-1-5-80-2940520708-3855866260-481812779-327648279-1710889582)(A;NP;CC;;;S-1-5-80-2627155378-1124895651-3977206752-2157268346-3811978089)(A;NP;CC;;;S-1-5-80-3787436395-2174616005-3003730137-1094982900-1570567328)(A;NP;CC;;;S-1-5-80-2970612574-78537857-698502321-558674196-1451644582)(A;NP;CC;;;S-1-5-80-880578595-1860270145-482643319-2788375705-1540778122)(A;NP;CC;;;S-1-5-80-364023826-931424190-487969545-1024119571-74567675)(A;NP;CC;;;S-1-5-80-2617507558-3328795327-711547822-311560295-1636921165)(A;NP;CC;;;S-1-5-80-89818136-74175777-88572358-3912780041-2421659406)(A;NP;CC;;;S-1-5-80-172094073-716411664-54255058-185476446-2329512179)(A;NP;CC;;;S-1-5-80-3532809085-2652327567-2620918877-1058261733-582902671)(A;NP;CC;;;S-1-5-80-3088073201-1464728630-1879813800-1107566885-823218052)(A;NP;CC;;;S-1-5-80-2898649604-2335086160-1904548223-3761738420-3855444835)(A;NP;CC;;;S-1-5-80-1971585524-2528565899-3324366483-1300752743-2325226580)(A;NP;CC;;;S-1-5-80-967499406-1694984581-2959056265-2481940682-939264259)(A;NP;CC;;;S-1-5-80-1948712186-1330865447-943413596-1669284603-1648638051)(A;NP;CC;;;S-1-5-80-3596911058-2952229928-1888671852-1743692427-614402820)(A;NP;CC;;;S-1-5-80-372467825-374176116-1198570892-3192490889-1232022613)(A;NP;CC;;;S-1-5-80-3141781312-1794533130-3616533224-2008760771-2116720301)(A;NP;CC;;;S-1-5-80-3044542841-3639452079-4096941652-1606687743-1256249853)(A;NP;CC;;;S-1-5-80-117416528-2204451360-1913602512-1355018040-1234992034)(A;NP;CC;;;S-1-5-80-3964583643-2633443559-2834438935-3739664028-1580655619)(A;NP;CC;;;S-1-5-80-3895724531-1583119856-3186271294-3795977770-3211684703)(A;NP;CC;;;S-1-5-80-2590341223-3996088049-3993122417-23640849-324535191)(A;NP;CC;;;S-1-5-80-949921180-3923668869-394927020-528789358-3592448931)(A;NP;CC;;;S-1-5-80-768763963-4214222998-2156221936-2953597973-713500239)(A;NP;CC;;;S-1-5-80-2014626298-1656748749-3847481816-918933055-2469338456)(A;NP;CC;;;S-1-5-80-1989757894-211065159-731672622-1783776043-3948168785)(A;NP;CC;;;S-1-5-80-3074984378-4122987768-2130325677-2031866499-3405430279)(A;NP;CC;;;S-1-5-80-534935901-3437432317-481271085-1710633381-983106267)(A;NP;CC;;;S-1-5-80-1877308096-3090306141-3032871208-3115266146-1400827410)(A;NP;CC;;;S-1-5-80-3076811988-2254870394-2658297454-3934945422-2393138642)(A;NP;CC;;;S-1-5-80-3110303136-3426481729-3186938678-1087894076-2178433439)(A;NP;CC;;;S-1-5-80-3098585136-2538892366-1097114017-2832417424-2016953023)(A;NP;CC;;;S-1-5-80-235582178-102246843-358262472-4132936818-1867412993)(A;NP;CC;;;S-1-5-80-1752088424-1054500994-3489791022-3310831482-3926524968)(A;NP;CC;;;S-1-5-80-1549550529-11381693-4027442525-4081535042-2424139505)(A;NP;CC;;;S-1-5-80-4155767994-3874329934-3800885181-2130851812-726865888)(A;NP;CC;;;S-1-5-80-3524758515-3090971750-345616940-2322499744-3530715838)(A;NP;CC;;;S-1-5-80-3299868208-4286319593-1091140620-3583751967-1732444380)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)(A;NP;CC;;;S-1-5-80-2455429942-3131183193-3617688776-595395669-3772047725)(A;NP;CC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)(A;NP;CC;;;S-1-5-80-3916113136-2435487254-2535488001-4050622930-2364918814)(A;NP;CC;;;S-1-5-80-3232712927-1625117661-2590453128-1738570065-3637376297)(A;NP;CC;;;S-1-5-80-3981856537-581775623-1136376035-2066872258-409572886)(A;NP;CC;;;S-1-5-80-689100834-1985168674-2379302174-2224748125-4125308070)(A;NP;CC;;;S-1-5-80-2119957892-4152124429-3625998117-4006912763-1737903618)(A;NP;CC;;;S-1-5-80-1987853863-1639573247-1110726908-1137832616-3599624523)(A;NP;CC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)(A;NP;CC;;;S-1-5-80-113310567-2163499630-2787090463-221477905-209227094)(A;NP;CC;;;S-1-5-80-1913148863-3492339771-4165695881-2087618961-4109116736)S:NO_ACCESS_CONTROL</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_BLOCK</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{de04f4bd-a953-47f6-b1b6-eb6e24a546d6}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68048</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>34359738368</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{892a3cae-0c40-4a8a-8aa4-cf539bbed38a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>1024</uint16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t\t\t<uint16>65535</uint16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_UNKNOWN</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0232}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68055</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8b1704e1-3f4f-4fe2-bc92-0b013dd74bdb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68112</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9b3fa2c3-4e42-4c0f-8afb-e9f0d58e9261}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68113</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4bfd4120-6a07-4b97-81fa-455048c76e4a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68114</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{fcdc301b-92d9-44bb-b257-88b581b56248}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68115</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{408fb9f7-e31d-4c1a-9056-0660f482826f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68116</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b0b78a7e-20d4-45d6-987c-57a5783592fb}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68117</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{2f99501c-4c59-413b-b954-3ff993fdbfae}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68118</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f8157303-181c-4c8d-b79c-47bfde1aeaf0}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68119</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b17cc3b4-a615-46f3-b2c6-2687d34fab02}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68120</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9b7b4e38-e234-44d2-b571-d374e27a4e0b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68121</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a1619fd8-02a0-47b7-b5e0-cfa96070a783}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68122</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{c08500c7-668a-4bac-945c-34b70d89be0b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>136</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68123</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{58083807-89f3-4df3-9a42-0030b4a28be1}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68124</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{cc4f4f68-e749-4deb-9532-8eeecc65fd2e}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68125</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8c5974d0-a252-4be3-8805-88649820ec32}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68126</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{1a3d3203-0424-42d8-8027-248351309474}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68127</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{0b8840ae-0286-4003-a653-1918f0bb88e6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68128</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{59c1253f-d019-4d86-9d10-a620dedbf830}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68129</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{75410a3a-fb4b-4c4e-a43b-65fa2f6b12b6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68130</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8a3541a0-0456-4909-91bc-a016060fc4ba}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68131</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{bad0a5c5-8e42-4b2e-907d-43d004424df9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68132</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{85fd608d-794c-47d5-9819-86dddddd6fb6}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>3</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68133</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f09da621-2d41-44ef-80d0-142da1df005b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>2</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68134</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{88bbe0f8-8dfc-4699-a847-a9349a4af991}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Boot Time Filter</name>\n\t\t\t\t\t\t<description>This filter is in effect before the service starts.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_HAS_FILTER_ORIGIN</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>58</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>133</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>3</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>131</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>14</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68135</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{429c6993-632c-4633-b930-65684a5b7300}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>InternetClientServer Outbound Default Rule</name>\n\t\t\t\t\t\t<description>InternetClientServer Outbound Default Rule</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1d01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;S-1-15-3-2)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68211</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>103079216120</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{82e6ae67-453a-49bd-b6e2-7b46d586602a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>InternetClient Default Rule</name>\n\t\t\t\t\t\t<description>InternetClient Default Rule</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>1e01000000000000</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"5\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_NOT_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SID</type>\n\t\t\t\t\t\t\t\t<sid>S-1-0-0</sid>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:LSD:(A;;CC;;;S-1-15-3-1)(A;;CC;;;WD)(A;;CC;;;AN)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68213</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>103079216120</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{9a8412a0-0fd5-462c-a11f-eb5ec9fc9709}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-Out)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2801000000000000</data>\n\t\t\t\t\t\t<asString>(.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68258</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>162253247820595200</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ad448bcc-9e58-4f9d-9d01-844b5628280b}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Wi-Fi Direct ASP Coordination Protocol (UDP-Out)</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2801000000000000</data>\n\t\t\t\t\t\t<asString>(.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"9\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-1428027539-3309602793-2678353003-1498846795-3763184142)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>7235</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68259</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>162253265000464384</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{ca82888c-e15c-4d97-9deb-f172bcc2c55c}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2b01000000000000</data>\n\t\t\t\t\t\t<asString>+.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68270</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>162252835503734784</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{413958f1-052c-41bb-9600-59345c58297d}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2b01000000000000</data>\n\t\t\t\t\t\t<asString>+.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68271</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>162252852683603968</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b5b94431-92bb-4993-ae20-dca728cb6a3f}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2c01000000000000</data>\n\t\t\t\t\t\t<asString>,.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"7\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68274</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>162235655634550784</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{f3611be4-ea21-41ad-bfbb-ff12ffc536f9}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Allow outgoing WSD from PeerDistSvc</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_FILTER_FLAG_INDEXED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>2c01000000000000</data>\n\t\t\t\t\t\t<asString>,.......</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"8\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_BYTE_BLOB_TYPE</type>\n\t\t\t\t\t\t\t\t<byteBlob>\n\t\t\t\t\t\t\t\t\t<data>5c006400650076006900630065005c0068006100720064006400690073006b0076006f006c0075006d00650033005c00770069006e0064006f00770073005c00730079007300740065006d00330032005c0073007600630068006f00730074002e006500780065000000</data>\n\t\t\t\t\t\t\t\t\t<asString>\\device\\harddiskvolume3\\windows\\system32\\svchost.exe</asString>\n\t\t\t\t\t\t\t\t</byteBlob>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_SECURITY_DESCRIPTOR_TYPE</type>\n\t\t\t\t\t\t\t\t<sd>O:SYG:SYD:(A;;CCRC;;;S-1-5-80-3124040864-3101396827-3094488734-3028845762-1939139329)</sd>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>fe80::ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_RANGE</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_RANGE_TYPE</type>\n\t\t\t\t\t\t\t\t<rangeValue>\n\t\t\t\t\t\t\t\t\t<valueLow>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ff00::</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueLow>\n\t\t\t\t\t\t\t\t\t<valueHigh>\n\t\t\t\t\t\t\t\t\t\t<type>FWP_BYTE_ARRAY16_TYPE</type>\n\t\t\t\t\t\t\t\t\t\t<byteArray16>ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff</byteArray16>\n\t\t\t\t\t\t\t\t\t</valueHigh>\n\t\t\t\t\t\t\t\t</rangeValue>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>3702</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_ALL_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>4</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_PERMIT</type>\n\t\t\t\t\t\t<filterType/>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68275</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>162235672814419968</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_AUTH_CONNECT_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Connect v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"37\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_ARRIVAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ARRIVAL_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_NEXTHOP_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NEXTHOP_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REAUTHORIZE_REASON</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PEER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ORIGINAL_ICMP_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_QUARANTINE_EPOCH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_EFFECTIVE_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>51</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0133}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_AUTH_CONNECT_V6_DISCARD</applicableLayer>\n\t\t\t\t\t<calloutId>275</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Flow Established v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"20\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>52</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"4\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8e44982b-f477-11df-85ce-78e7d1810190}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Flow Established V4 Callout</name>\n\t\t\t\t\t\t<description>NDU Flow Established V4 Callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000360</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</applicableLayer>\n\t\t\t\t\t<calloutId>262</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0134}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</applicableLayer>\n\t\t\t\t\t<calloutId>280</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0334}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Initiates deep protocol inspection on the flow.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</applicableLayer>\n\t\t\t\t\t<calloutId>286</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{f762e452-8bfd-47f6-9425-368d888b01dc}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_flow_established_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</applicableLayer>\n\t\t\t\t\t<calloutId>298</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"4\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e44982c-f477-11df-85ce-78e7d1810190}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Flow Established V4 SubLayer Filter</name>\n\t\t\t\t\t\t<description>NDU Flow Established V4 SubLayer Filter</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_INSPECTION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{8e44982b-f477-11df-85ce-78e7d1810190}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>66999</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>2</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a5ce04ca-2cda-423e-8fef-52fb9e9fcf3a}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>21</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0334}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68056</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a70ef9b7-c790-4db0-a376-0378f9815b02}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>21</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0334}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68058</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{a1dd6389-d3b1-4f46-9300-611216024728}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_flow_established_v4</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{f762e452-8bfd-47f6-9425-368d888b01dc}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68280</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>532575961056</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Flow Established v4 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"20\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>53</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Flow Established v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"20\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>54</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"4\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8e44982d-f477-11df-85ce-78e7d1810190}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Flow Established V6 Callout</name>\n\t\t\t\t\t\t<description>NDU Flow Established V6 Callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000360</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</applicableLayer>\n\t\t\t\t\t<calloutId>263</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0136}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Performs logging.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000200</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</applicableLayer>\n\t\t\t\t\t<calloutId>281</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{c3dbed20-0bb6-4bf3-828d-96732e1e0336}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Windows Firewall: callout</name>\n\t\t\t\t\t\t<description>Initiates deep protocol inspection on the flow.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</applicableLayer>\n\t\t\t\t\t<calloutId>287</calloutId>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{31114833-2891-4edd-a8ec-2ff8549aa491}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_flow_established_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</applicableLayer>\n\t\t\t\t\t<calloutId>299</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"4\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e44982e-f477-11df-85ce-78e7d1810190}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Flow Established V6 SubLayer Filter</name>\n\t\t\t\t\t\t<description>NDU Flow Established V6 SubLayer Filter</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_INSPECTION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"1\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{8e44982d-f477-11df-85ce-78e7d1810190}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67000</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>2</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8076bfdc-eed9-4602-9570-29b6e402fba5}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>21</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0336}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68057</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{b6c1c213-7518-4af8-9bcf-eeabe82c63ac}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>FTP Inspection Filter</name>\n\t\t\t\t\t\t<description>This filter enables inspection of FTP.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t\t\t<providerData>\n\t\t\t\t\t\t<data>ffffffffffffffff</data>\n\t\t\t\t\t\t<asString>........</asString>\n\t\t\t\t\t</providerData>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT16</type>\n\t\t\t\t\t\t\t\t<uint16>21</uint16>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{c3dbed20-0bb6-4bf3-828d-96732e1e0336}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68059</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>18446744073709551615</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{4994b7fe-47d8-4ac5-8fa8-77b203c5b640}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>windefend_flow_established_v6</name>\n\t\t\t\t\t\t<description>windefend</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6</layerKey>\n\t\t\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition numItems=\"4\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>0</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>6</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t\t<matchType>FWP_MATCH_EQUAL</matchType>\n\t\t\t\t\t\t\t<conditionValue>\n\t\t\t\t\t\t\t\t<type>FWP_UINT8</type>\n\t\t\t\t\t\t\t\t<uint8>17</uint8>\n\t\t\t\t\t\t\t</conditionValue>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</filterCondition>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{31114833-2891-4edd-a8ec-2ff8549aa491}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>68281</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>33286004704</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Flow Established v6 Discard Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"20\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_REMOTE_MACHINE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>55</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_MAC_FRAME_ETHERNET</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Ethernet Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"12\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_MAC_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_REMOTE_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ETHER_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>56</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_MAC_FRAME_ETHERNET</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Ethernet Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"12\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_MAC_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_REMOTE_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ETHER_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>57</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Native MAC Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_MEDIA_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_PHYSICAL_MEDIA_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>58</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Native MAC Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_MEDIA_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_PHYSICAL_MEDIA_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_NDIS_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>59</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_NAME_RESOLUTION_CACHE_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Name Resolution Cache v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"5\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PEER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>60</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_NAME_RESOLUTION_CACHE_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Name Resolution Cache v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"5\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PEER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>61</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_RELEASE_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Resource Release v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"11\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>62</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_RESOURCE_RELEASE_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Resource Release v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"11\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>63</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Endpoint Closure v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"13\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>64</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Endpoint Closure v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"13\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>65</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_CONNECT_REDIRECT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Connect Redirect v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>66</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_CONNECT_REDIRECT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Connect Redirect v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_ORIGINAL_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>67</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_BIND_REDIRECT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Bind Redirect v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>68</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8bc14e84-4287-4c9e-81da-532335532058}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Binding Callout</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_BIND_REDIRECT_V4</applicableLayer>\n\t\t\t\t\t<calloutId>258</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_ALE_BIND_REDIRECT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Bind Redirect v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"10\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>69</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8bc14e84-4287-4c9e-81da-532335532059}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>Interface Binding Callout</name>\n\t\t\t\t\t\t<description/>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_ALE_BIND_REDIRECT_V6</applicableLayer>\n\t\t\t\t\t<calloutId>259</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_STREAM_PACKET_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Stream Packet v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"12\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>70</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_STREAM_PACKET_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Stream Packet v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"12\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SUB_INTERFACE_INDEX</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_TUNNEL_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>71</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INGRESS_VSWITCH_ETHERNET</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Ingress vSwitch Ethernet layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_SOURCE_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ETHER_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_TENANT_NETWORK_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_NETWORK_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>72</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_EGRESS_VSWITCH_ETHERNET</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Egress vSwitch Ethernet layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"17\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_SOURCE_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY6_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_MAC_DESTINATION_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ETHER_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_TENANT_NETWORK_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_NETWORK_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>73</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INGRESS_VSWITCH_TRANSPORT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Ingress vSwitch Transport v4 layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_TENANT_NETWORK_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_NETWORK_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>74</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INGRESS_VSWITCH_TRANSPORT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Ingress vSwitch Transport v6 layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_TENANT_NETWORK_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_NETWORK_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>75</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_EGRESS_VSWITCH_TRANSPORT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Egress vSwitch Transport v4 layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"17\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_TENANT_NETWORK_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_NETWORK_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>76</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_EGRESS_VSWITCH_TRANSPORT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Egress vSwitch Transport v6 layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"17\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_SOURCE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_DESTINATION_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VLAN_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_TENANT_NETWORK_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_NETWORK_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_SOURCE_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_INTERFACE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_INTERFACE_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_VSWITCH_DESTINATION_VM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_L2_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>77</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_FAST</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Transport v4 Layer fast</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field/>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>78</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8e44982f-f477-11df-85ce-78e7d1810190}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Inbound Transport Callout</name>\n\t\t\t\t\t\t<description>NDU Inbound Transport Callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000360</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_TRANSPORT_FAST</applicableLayer>\n\t\t\t\t\t<calloutId>264</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e449830-f477-11df-85ce-78e7d1810190}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Inbound Transport SubLayer Filter</name>\n\t\t\t\t\t\t<description>NDU Inbound Transport SubLayer Filter</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_FAST</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_INSPECTION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{8e44982f-f477-11df-85ce-78e7d1810190}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67001</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>576460752303423487</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_TRANSPORT_FAST</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Transport v4 Layer fast</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field/>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>79</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8e449833-f477-11df-85ce-78e7d1810190}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Outbound Transport Callout</name>\n\t\t\t\t\t\t<description>NDU Outbound Transport Callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000360</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_TRANSPORT_FAST</applicableLayer>\n\t\t\t\t\t<calloutId>265</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e449834-f477-11df-85ce-78e7d1810190}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Outbound Transport SubLayer Filter</name>\n\t\t\t\t\t\t<description>NDU Outbound Transport SubLayer Filter</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_TRANSPORT_FAST</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_INSPECTION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{8e449833-f477-11df-85ce-78e7d1810190}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67002</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>576460752303423487</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE_FAST</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound Native MAC Layer fast</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field/>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>80</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8e449837-f477-11df-85ce-78e7d1810190}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Inbound Mac Frame Native Callout</name>\n\t\t\t\t\t\t<description>NDU Inbound Mac Frame Native Callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>000003E0</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE_FAST</applicableLayer>\n\t\t\t\t\t<calloutId>266</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e449838-f477-11df-85ce-78e7d1810190}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Inbound Mac Frame Native SubLayer Filter</name>\n\t\t\t\t\t\t<description>NDU Inbound Mac Frame Native SubLayer Filter</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE_FAST</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_INSPECTION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{8e449837-f477-11df-85ce-78e7d1810190}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67003</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>576460752303423487</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE_FAST</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Outbound Native MAC Layer fast </name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field/>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>81</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>{8e449839-f477-11df-85ce-78e7d1810190}</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Outbound Mac Frame Native Callout</name>\n\t\t\t\t\t\t<description>NDU Outbound Mac Frame Native Callout</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWP_CALLOUT_FLAG_ALLOW_OFFLOAD</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>000003E0</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE_FAST</applicableLayer>\n\t\t\t\t\t<calloutId>267</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<filterKey>{8e44983a-f477-11df-85ce-78e7d1810190}</filterKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>NDU Outbound Mac Frame Native SubLayer Filter</name>\n\t\t\t\t\t\t<description>NDU Outbound Mac Frame Native SubLayer Filter</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags/>\n\t\t\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<layerKey>FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE_FAST</layerKey>\n\t\t\t\t\t<subLayerKey>FWPM_SUBLAYER_INSPECTION</subLayerKey>\n\t\t\t\t\t<weight>\n\t\t\t\t\t\t<type>FWP_EMPTY</type>\n\t\t\t\t\t</weight>\n\t\t\t\t\t<filterCondition/>\n\t\t\t\t\t<action>\n\t\t\t\t\t\t<type>FWP_ACTION_CALLOUT_INSPECTION</type>\n\t\t\t\t\t\t<filterType>{8e449839-f477-11df-85ce-78e7d1810190}</filterType>\n\t\t\t\t\t</action>\n\t\t\t\t\t<rawContext>0</rawContext>\n\t\t\t\t\t<reserved/>\n\t\t\t\t\t<filterId>67004</filterId>\n\t\t\t\t\t<effectiveWeight>\n\t\t\t\t\t\t<type>FWP_UINT64</type>\n\t\t\t\t\t\t<uint64>576460752303423487</uint64>\n\t\t\t\t\t</effectiveWeight>\n\t\t\t\t</item>\n\t\t\t</filters>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_INBOUND_RESERVED2</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Inbound HTTP Reserved Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"16\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED0</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED1</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED2</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED3</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED4</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED5</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED6</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED7</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED8</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED9</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED10</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED11</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED12</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED13</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED14</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RESERVED15</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>82</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>{29243af8-ecaf-4436-a44e-f9fb7070aa04}</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Accept Redirect v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"12\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>83</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_BUILT_IN_RESERVED_1</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Proxy Connection ALE Accept Redirect v4 Layer Callout</name>\n\t\t\t\t\t\t<description>Redirects the inbound connection to the address in the provider context.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>{29243af8-ecaf-4436-a44e-f9fb7070aa04}</applicableLayer>\n\t\t\t\t\t<calloutId>45</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>{c9809347-218f-4b7f-a742-b281a3f631b4}</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>ALE Accept Redirect v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_KERNEL</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"12\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_USER_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_ACCESS_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_PACKAGE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_SID</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_ALE_SECURITY_ATTRIBUTE_FQBN_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_COMPARTMENT_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>84</layerId>\n\t\t\t</layer>\n\t\t\t<callouts numItems=\"1\">\n\t\t\t\t<item>\n\t\t\t\t\t<calloutKey>FWPM_CALLOUT_BUILT_IN_RESERVED_2</calloutKey>\n\t\t\t\t\t<displayData>\n\t\t\t\t\t\t<name>WFP Built-in Proxy Connection ALE Accept Redirect v6 Layer Callout</name>\n\t\t\t\t\t\t<description>Redirects the inbound connection to the address in the provider context.</description>\n\t\t\t\t\t</displayData>\n\t\t\t\t\t<flags numItems=\"3\">\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT</item>\n\t\t\t\t\t\t<item>FWPM_CALLOUT_FLAG_REGISTERED</item>\n\t\t\t\t\t\t<item>00000300</item>\n\t\t\t\t\t</flags>\n\t\t\t\t\t<providerKey/>\n\t\t\t\t\t<providerData/>\n\t\t\t\t\t<applicableLayer>{c9809347-218f-4b7f-a742-b281a3f631b4}</applicableLayer>\n\t\t\t\t\t<calloutId>46</calloutId>\n\t\t\t\t</item>\n\t\t\t</callouts>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPSEC_KM_DEMUX_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IPsec KM Demux v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"6\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_QM_MODE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>85</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPSEC_KM_DEMUX_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IPsec KM Demux v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"6\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_QM_MODE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>86</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPSEC_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IPsec v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>87</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IPSEC_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IPsec v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>88</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IKEEXT_V4</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IKE v4 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"5\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>89</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_IKEEXT_V6</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>IKE v6 Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"5\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_INTERFACE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT64</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CURRENT_PROFILE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_SECURITY_REALM_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>90</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_RPC_UM</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>RPC UM Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"17\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REMOTE_USER_TOKEN</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_IF_UUID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_IF_VERSION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_IF_FLAG</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DCOM_APP_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IMAGE_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_AUTH_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_AUTH_LEVEL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SEC_ENCRYPT_ALGORITHM</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SEC_KEY_SIZE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_V4</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_V6</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PIPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS_V4</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS_V6</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>91</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_RPC_EPMAP</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>RPC EPMAP Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"14\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REMOTE_USER_TOKEN</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_IF_UUID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_IF_VERSION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_AUTH_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_AUTH_LEVEL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SEC_ENCRYPT_ALGORITHM</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_SEC_KEY_SIZE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_V4</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_ADDRESS_V6</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_LOCAL_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PIPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS_V4</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IP_REMOTE_ADDRESS_V6</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_IP_ADDRESS</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>92</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_RPC_EP_ADD</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>RPC EP ADD Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"4\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_PROCESS_WITH_RPC_IF_UUID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_PROTOCOL</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT8</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_EP_VALUE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_EP_FLAGS</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_FLAGS</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>93</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_RPC_PROXY_CONN</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>RPC Proxy Connect Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"6\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CLIENT_TOKEN</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_SERVER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_SERVER_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_PROXY_AUTH_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CLIENT_CERT_KEY_LENGTH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CLIENT_CERT_OID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>94</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_RPC_PROXY_IF</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>RPC Proxy Interface Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"8\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CLIENT_TOKEN</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_IF_UUID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_IF_VERSION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_SERVER_NAME</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_SERVER_PORT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT16</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_RPC_PROXY_AUTH_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CLIENT_CERT_KEY_LENGTH</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_CLIENT_CERT_OID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_BLOB_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>95</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t\t<item>\n\t\t\t<layer>\n\t\t\t\t<layerKey>FWPM_LAYER_KM_AUTHORIZATION</layerKey>\n\t\t\t\t<displayData>\n\t\t\t\t\t<name>Keying Module Authorization Layer</name>\n\t\t\t\t\t<description/>\n\t\t\t\t</displayData>\n\t\t\t\t<flags numItems=\"2\">\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_BUILTIN</item>\n\t\t\t\t\t<item>FWPM_LAYER_FLAG_CLASSIFY_MOSTLY</item>\n\t\t\t\t</flags>\n\t\t\t\t<field numItems=\"7\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_REMOTE_ID</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_TOKEN_INFORMATION_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_AUTHENTICATION_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_KM_TYPE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_DIRECTION</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_KM_MODE</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_IPSEC_POLICY_KEY</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_BYTE_ARRAY16_TYPE</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<fieldKey>FWPM_CONDITION_KM_AUTH_NAP_CONTEXT</fieldKey>\n\t\t\t\t\t\t<type>FWPM_FIELD_RAW_DATA</type>\n\t\t\t\t\t\t<dataType>FWP_UINT32</dataType>\n\t\t\t\t\t</item>\n\t\t\t\t</field>\n\t\t\t\t<defaultSubLayerKey>FWPM_SUBLAYER_UNIVERSAL</defaultSubLayerKey>\n\t\t\t\t<layerId>96</layerId>\n\t\t\t</layer>\n\t\t\t<callouts/>\n\t\t\t<filters/>\n\t\t</item>\n\t</layers>\n\t<providers numItems=\"13\">\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_IKEEXT</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in IKEEXT provider used to identify filters added by IKE/AuthIP.</description>\n\t\t\t</displayData>\n\t\t\t<flags numItems=\"1\">\n\t\t\t\t<item>FWPM_PROVIDER_FLAG_DISABLED</item>\n\t\t\t</flags>\n\t\t\t<providerData/>\n\t\t\t<serviceName>IKEEXT</serviceName>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_TCP_CHIMNEY_OFFLOAD</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in TCP Chimney Offload provider used to identify filters added by TCP Chimney Offload.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName/>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>@bfe.dll,-1217</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in MPSSVC App Isolation provider.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName>mpssvc</serviceName>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in MPSSVC Windows Service Hardening and Quarantine provider.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName>mpssvc</serviceName>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_EDP</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in MPSSVC Enterprise Data Protection provider.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName>mpssvc</serviceName>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>{c698301d-9129-450c-937c-f4b834bfb374}</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows edge traversal socket option authorization provider</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName/>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>{893a4f22-9bba-49b7-8c66-3d40929c8fd5}</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows Teredo firewall provider</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName/>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in MPSSVC Windows Firewall provider.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName>mpssvc</serviceName>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_IPSEC_DOSP_CONFIG</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in IPsec DoS Protection configuration provider used to identify filters added by IPsec Denial of Service Protection.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName/>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_TCP_TEMPLATES</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in TCP Templates provider used to identify filters added by TCP Template based configuration.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName/>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_TENANT_RESTRICTIONS</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in MPSSVC Tenant Restrictions Sublayer</name>\n\t\t\t\t<description>Microsoft Windows WFP Built-in MPSSVC Tenant Restrictions provider.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName>mpssvc</serviceName>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>{1bebc969-61a5-4732-a177-847a0817862a}</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Microsoft Windows Defender Firewall IPsec Provider</description>\n\t\t\t</displayData>\n\t\t\t<flags numItems=\"1\">\n\t\t\t\t<item>FWPM_PROVIDER_FLAG_PERSISTENT</item>\n\t\t\t</flags>\n\t\t\t<providerData/>\n\t\t\t<serviceName>MPSSVC</serviceName>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerKey>{8e44982a-f477-11df-85ce-78e7d1810190}</providerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description>Windows Network Data Usage (NDU) Provider</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerData/>\n\t\t\t<serviceName>NDU</serviceName>\n\t\t</item>\n\t</providers>\n\t<providerContexts numItems=\"329\">\n\t\t<item>\n\t\t\t<providerContextKey>FWPM_PROVIDER_CONTEXT_SECURE_SOCKET_AUTHIP</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in Default Secure Socket AuthIP Policy Provider Context</name>\n\t\t\t\t<description>Authenticated Internet Protocol (AuthIP) main mode default policy for secure sockets.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_IPSEC_AUTHIP_MM_CONTEXT</type>\n\t\t\t<authIpMmPolicy>\n\t\t\t\t<softExpirationTime>0</softExpirationTime>\n\t\t\t\t<authenticationMethods numItems=\"1\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<authenticationMethodType>IKEEXT_ANONYMOUS</authenticationMethodType>\n\t\t\t\t\t</item>\n\t\t\t\t</authenticationMethods>\n\t\t\t\t<initiatorImpersonationType>IKEEXT_IMPERSONATION_NONE</initiatorImpersonationType>\n\t\t\t\t<ikeProposals numItems=\"2\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<cipherAlgorithm>\n\t\t\t\t\t\t\t<algoIdentifier>IKEEXT_CIPHER_AES_128</algoIdentifier>\n\t\t\t\t\t\t\t<keyLen>0</keyLen>\n\t\t\t\t\t\t\t<rounds>0</rounds>\n\t\t\t\t\t\t</cipherAlgorithm>\n\t\t\t\t\t\t<integrityAlgorithm>\n\t\t\t\t\t\t\t<algoIdentifier>IKEEXT_INTEGRITY_SHA1</algoIdentifier>\n\t\t\t\t\t\t</integrityAlgorithm>\n\t\t\t\t\t\t<maxLifetimeSeconds>7200</maxLifetimeSeconds>\n\t\t\t\t\t\t<dhGroup>IKEEXT_DH_ECP_256</dhGroup>\n\t\t\t\t\t\t<quickModeLimit>0</quickModeLimit>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<cipherAlgorithm>\n\t\t\t\t\t\t\t<algoIdentifier>IKEEXT_CIPHER_3DES</algoIdentifier>\n\t\t\t\t\t\t\t<keyLen>0</keyLen>\n\t\t\t\t\t\t\t<rounds>0</rounds>\n\t\t\t\t\t\t</cipherAlgorithm>\n\t\t\t\t\t\t<integrityAlgorithm>\n\t\t\t\t\t\t\t<algoIdentifier>IKEEXT_INTEGRITY_SHA1</algoIdentifier>\n\t\t\t\t\t\t</integrityAlgorithm>\n\t\t\t\t\t\t<maxLifetimeSeconds>7200</maxLifetimeSeconds>\n\t\t\t\t\t\t<dhGroup>IKEEXT_DH_GROUP_2</dhGroup>\n\t\t\t\t\t\t<quickModeLimit>0</quickModeLimit>\n\t\t\t\t\t</item>\n\t\t\t\t</ikeProposals>\n\t\t\t\t<flags/>\n\t\t\t\t<maxDynamicFilters>0</maxDynamicFilters>\n\t\t\t\t<retransmitDurationSecs>0</retransmitDurationSecs>\n\t\t\t</authIpMmPolicy>\n\t\t\t<providerContextId>9223372036854775808</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>FWPM_PROVIDER_CONTEXT_SECURE_SOCKET_IPSEC</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in Default Secure Socket IPsec Policy Provider Context</name>\n\t\t\t\t<description>Internet Protocol Security (IPsec) quick mode default policy for secure sockets.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_IPSEC_AUTHIP_QM_TRANSPORT_CONTEXT</type>\n\t\t\t<authipQmTransportPolicy>\n\t\t\t\t<ipsecProposals numItems=\"4\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<lifetime>\n\t\t\t\t\t\t\t<lifetimeSeconds>3600</lifetimeSeconds>\n\t\t\t\t\t\t\t<lifetimeKilobytes>56320</lifetimeKilobytes>\n\t\t\t\t\t\t\t<lifetimePackets>2147483647</lifetimePackets>\n\t\t\t\t\t\t</lifetime>\n\t\t\t\t\t\t<saTransforms numItems=\"1\">\n\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t<ipsecTransformType>IPSEC_TRANSFORM_ESP_AUTH</ipsecTransformType>\n\t\t\t\t\t\t\t\t<espAuthTransform>\n\t\t\t\t\t\t\t\t\t<authTransformId>\n\t\t\t\t\t\t\t\t\t\t<authType>IPSEC_AUTH_SHA_1</authType>\n\t\t\t\t\t\t\t\t\t\t<authConfig>IPSEC_AUTH_CONFIG_HMAC_SHA_1_96</authConfig>\n\t\t\t\t\t\t\t\t\t</authTransformId>\n\t\t\t\t\t\t\t\t\t<cryptoModuleId/>\n\t\t\t\t\t\t\t\t</espAuthTransform>\n\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t</saTransforms>\n\t\t\t\t\t\t<pfsGroup>IPSEC_PFS_NONE</pfsGroup>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<lifetime>\n\t\t\t\t\t\t\t<lifetimeSeconds>3600</lifetimeSeconds>\n\t\t\t\t\t\t\t<lifetimeKilobytes>56320</lifetimeKilobytes>\n\t\t\t\t\t\t\t<lifetimePackets>2147483647</lifetimePackets>\n\t\t\t\t\t\t</lifetime>\n\t\t\t\t\t\t<saTransforms numItems=\"1\">\n\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t<ipsecTransformType>IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER</ipsecTransformType>\n\t\t\t\t\t\t\t\t<espAuthAndCipherTransform>\n\t\t\t\t\t\t\t\t\t<authTransform>\n\t\t\t\t\t\t\t\t\t\t<authTransformId>\n\t\t\t\t\t\t\t\t\t\t\t<authType>IPSEC_AUTH_SHA_1</authType>\n\t\t\t\t\t\t\t\t\t\t\t<authConfig>IPSEC_AUTH_CONFIG_HMAC_SHA_1_96</authConfig>\n\t\t\t\t\t\t\t\t\t\t</authTransformId>\n\t\t\t\t\t\t\t\t\t\t<cryptoModuleId/>\n\t\t\t\t\t\t\t\t\t</authTransform>\n\t\t\t\t\t\t\t\t\t<cipherTransform>\n\t\t\t\t\t\t\t\t\t\t<cipherTransformId>\n\t\t\t\t\t\t\t\t\t\t\t<cipherType>IPSEC_CIPHER_TYPE_AES_128</cipherType>\n\t\t\t\t\t\t\t\t\t\t\t<cipherConfig>IPSEC_CIPHER_CONFIG_CBC_AES_128</cipherConfig>\n\t\t\t\t\t\t\t\t\t\t</cipherTransformId>\n\t\t\t\t\t\t\t\t\t\t<cryptoModuleId/>\n\t\t\t\t\t\t\t\t\t</cipherTransform>\n\t\t\t\t\t\t\t\t</espAuthAndCipherTransform>\n\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t</saTransforms>\n\t\t\t\t\t\t<pfsGroup>IPSEC_PFS_NONE</pfsGroup>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<lifetime>\n\t\t\t\t\t\t\t<lifetimeSeconds>3600</lifetimeSeconds>\n\t\t\t\t\t\t\t<lifetimeKilobytes>56320</lifetimeKilobytes>\n\t\t\t\t\t\t\t<lifetimePackets>2147483647</lifetimePackets>\n\t\t\t\t\t\t</lifetime>\n\t\t\t\t\t\t<saTransforms numItems=\"1\">\n\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t<ipsecTransformType>IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER</ipsecTransformType>\n\t\t\t\t\t\t\t\t<espAuthAndCipherTransform>\n\t\t\t\t\t\t\t\t\t<authTransform>\n\t\t\t\t\t\t\t\t\t\t<authTransformId>\n\t\t\t\t\t\t\t\t\t\t\t<authType>IPSEC_AUTH_SHA_1</authType>\n\t\t\t\t\t\t\t\t\t\t\t<authConfig>IPSEC_AUTH_CONFIG_HMAC_SHA_1_96</authConfig>\n\t\t\t\t\t\t\t\t\t\t</authTransformId>\n\t\t\t\t\t\t\t\t\t\t<cryptoModuleId/>\n\t\t\t\t\t\t\t\t\t</authTransform>\n\t\t\t\t\t\t\t\t\t<cipherTransform>\n\t\t\t\t\t\t\t\t\t\t<cipherTransformId>\n\t\t\t\t\t\t\t\t\t\t\t<cipherType>IPSEC_CIPHER_TYPE_3DES</cipherType>\n\t\t\t\t\t\t\t\t\t\t\t<cipherConfig>IPSEC_CIPHER_CONFIG_CBC_3DES</cipherConfig>\n\t\t\t\t\t\t\t\t\t\t</cipherTransformId>\n\t\t\t\t\t\t\t\t\t\t<cryptoModuleId/>\n\t\t\t\t\t\t\t\t\t</cipherTransform>\n\t\t\t\t\t\t\t\t</espAuthAndCipherTransform>\n\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t</saTransforms>\n\t\t\t\t\t\t<pfsGroup>IPSEC_PFS_NONE</pfsGroup>\n\t\t\t\t\t</item>\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<lifetime>\n\t\t\t\t\t\t\t<lifetimeSeconds>3600</lifetimeSeconds>\n\t\t\t\t\t\t\t<lifetimeKilobytes>56320</lifetimeKilobytes>\n\t\t\t\t\t\t\t<lifetimePackets>2147483647</lifetimePackets>\n\t\t\t\t\t\t</lifetime>\n\t\t\t\t\t\t<saTransforms numItems=\"1\">\n\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t<ipsecTransformType>IPSEC_TRANSFORM_AH</ipsecTransformType>\n\t\t\t\t\t\t\t\t<ahTransform>\n\t\t\t\t\t\t\t\t\t<authTransformId>\n\t\t\t\t\t\t\t\t\t\t<authType>IPSEC_AUTH_SHA_1</authType>\n\t\t\t\t\t\t\t\t\t\t<authConfig>IPSEC_AUTH_CONFIG_HMAC_SHA_1_96</authConfig>\n\t\t\t\t\t\t\t\t\t</authTransformId>\n\t\t\t\t\t\t\t\t\t<cryptoModuleId/>\n\t\t\t\t\t\t\t\t</ahTransform>\n\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t</saTransforms>\n\t\t\t\t\t\t<pfsGroup>IPSEC_PFS_NONE</pfsGroup>\n\t\t\t\t\t</item>\n\t\t\t\t</ipsecProposals>\n\t\t\t\t<flags numItems=\"1\">\n\t\t\t\t\t<item>IPSEC_POLICY_FLAG_ND_BOUNDARY</item>\n\t\t\t\t</flags>\n\t\t\t\t<ndAllowClearTimeoutSeconds>10</ndAllowClearTimeoutSeconds>\n\t\t\t\t<saIdleTimeout>\n\t\t\t\t\t<idleTimeoutSeconds>300</idleTimeoutSeconds>\n\t\t\t\t\t<idleTimeoutSecondsFailOver>60</idleTimeoutSecondsFailOver>\n\t\t\t\t</saIdleTimeout>\n\t\t\t\t<emPolicy>\n\t\t\t\t\t<authenticationMethods numItems=\"2\">\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<authenticationMethodType>IKEEXT_KERBEROS</authenticationMethodType>\n\t\t\t\t\t\t\t<kerberosAuthentication>\n\t\t\t\t\t\t\t\t<flags/>\n\t\t\t\t\t\t\t\t<proxyServer/>\n\t\t\t\t\t\t\t</kerberosAuthentication>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t<authenticationMethodType>IKEEXT_SSL</authenticationMethodType>\n\t\t\t\t\t\t\t<sslAuthentication>\n\t\t\t\t\t\t\t\t<inboundConfigType>IKEEXT_CERT_CONFIG_TRUSTED_ROOT_STORE</inboundConfigType>\n\t\t\t\t\t\t\t\t<inboundTrustedRootStoreCriteria numItems=\"1\">\n\t\t\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t\t\t<certData/>\n\t\t\t\t\t\t\t\t\t\t<certHash/>\n\t\t\t\t\t\t\t\t\t\t<eku>\n\t\t\t\t\t\t\t\t\t\t\t<numEku>1</numEku>\n\t\t\t\t\t\t\t\t\t\t\t<eku numItems=\"1\">\n\t\t\t\t\t\t\t\t\t\t\t\t<item>1.3.6.1.5.5.7.3.2</item>\n\t\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t<name/>\n\t\t\t\t\t\t\t\t\t\t<flags/>\n\t\t\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t\t\t</inboundTrustedRootStoreCriteria>\n\t\t\t\t\t\t\t\t<outboundConfigType>IKEEXT_CERT_CONFIG_TRUSTED_ROOT_STORE</outboundConfigType>\n\t\t\t\t\t\t\t\t<outboundTrustedRootStoreCriteria numItems=\"4\">\n\t\t\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t\t\t<certData/>\n\t\t\t\t\t\t\t\t\t\t<certHash/>\n\t\t\t\t\t\t\t\t\t\t<eku>\n\t\t\t\t\t\t\t\t\t\t\t<numEku>2</numEku>\n\t\t\t\t\t\t\t\t\t\t\t<eku numItems=\"2\">\n\t\t\t\t\t\t\t\t\t\t\t\t<item>1.3.6.1.5.5.7.3.2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t<item>1.3.6.1.5.5.8.2.2</item>\n\t\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t<name/>\n\t\t\t\t\t\t\t\t\t\t<flags/>\n\t\t\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t\t\t<certData/>\n\t\t\t\t\t\t\t\t\t\t<certHash/>\n\t\t\t\t\t\t\t\t\t\t<eku>\n\t\t\t\t\t\t\t\t\t\t\t<numEku>1</numEku>\n\t\t\t\t\t\t\t\t\t\t\t<eku numItems=\"1\">\n\t\t\t\t\t\t\t\t\t\t\t\t<item>1.3.6.1.5.5.7.3.2</item>\n\t\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t<name/>\n\t\t\t\t\t\t\t\t\t\t<flags/>\n\t\t\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t\t\t<certData/>\n\t\t\t\t\t\t\t\t\t\t<certHash/>\n\t\t\t\t\t\t\t\t\t\t<eku>\n\t\t\t\t\t\t\t\t\t\t\t<numEku>1</numEku>\n\t\t\t\t\t\t\t\t\t\t\t<eku numItems=\"1\">\n\t\t\t\t\t\t\t\t\t\t\t\t<item>1.3.6.1.5.5.8.2.2</item>\n\t\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t</eku>\n\t\t\t\t\t\t\t\t\t\t<name/>\n\t\t\t\t\t\t\t\t\t\t<flags/>\n\t\t\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t\t\t\t<item>\n\t\t\t\t\t\t\t\t\t\t<certData/>\n\t\t\t\t\t\t\t\t\t\t<certHash/>\n\t\t\t\t\t\t\t\t\t\t<eku/>\n\t\t\t\t\t\t\t\t\t\t<name/>\n\t\t\t\t\t\t\t\t\t\t<flags/>\n\t\t\t\t\t\t\t\t\t</item>\n\t\t\t\t\t\t\t\t</outboundTrustedRootStoreCriteria>\n\t\t\t\t\t\t\t\t<flags/>\n\t\t\t\t\t\t\t\t<localCertLocationUrl/>\n\t\t\t\t\t\t\t</sslAuthentication>\n\t\t\t\t\t\t</item>\n\t\t\t\t\t</authenticationMethods>\n\t\t\t\t\t<initiatorImpersonationType>IKEEXT_IMPERSONATION_SOCKET_PRINCIPAL</initiatorImpersonationType>\n\t\t\t\t</emPolicy>\n\t\t\t</authipQmTransportPolicy>\n\t\t\t<providerContextId>9223372036854775809</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{30433c31-b05f-421f-8fde-018ea4c68af4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags numItems=\"1\">\n\t\t\t\t<item>FWPM_PROVIDER_CONTEXT_FLAG_PERSISTENT</item>\n\t\t\t</flags>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>510075006100720061006e00740069006e0065002000440065006600610075006c0074000000</data>\n\t\t\t\t<asString>Q.u.a.r.a.n.t.i.n.e. .D.e.f.a.u.l.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854775810</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{93132c36-6e06-4e6f-a10b-218787cd49cf}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags numItems=\"1\">\n\t\t\t\t<item>FWPM_PROVIDER_CONTEXT_FLAG_PERSISTENT</item>\n\t\t\t</flags>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>42006f006f007400740069006d0065002000440065006600610075006c0074000000</data>\n\t\t\t\t<asString>B.o.o.t.t.i.m.e. .D.e.f.a.u.l.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854775811</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{252fe349-15c1-48d5-82a6-e62a2e483dcf}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>State Management Provider Context</name>\n\t\t\t\t<description>Contains State Management Options</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_CLASSIFY_OPTIONS_CONTEXT</type>\n\t\t\t<classifyOptions>\n\t\t\t\t<options numItems=\"1\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<type>FWP_CLASSIFY_OPTION_LOOSE_SOURCE_MAPPING</type>\n\t\t\t\t\t\t<value>\n\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t</value>\n\t\t\t\t\t</item>\n\t\t\t\t</options>\n\t\t\t</classifyOptions>\n\t\t\t<providerContextId>9223372036854775812</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2ea412db-5c9d-4bbd-9af2-4914d2dbfe17}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>State Management Provider Context</name>\n\t\t\t\t<description>Contains State Management Options</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_CLASSIFY_OPTIONS_CONTEXT</type>\n\t\t\t<classifyOptions>\n\t\t\t\t<options numItems=\"1\">\n\t\t\t\t\t<item>\n\t\t\t\t\t\t<type>FWP_CLASSIFY_OPTION_LOCAL_ONLY_MAPPING</type>\n\t\t\t\t\t\t<value>\n\t\t\t\t\t\t\t<type>FWP_UINT32</type>\n\t\t\t\t\t\t\t<uint32>1</uint32>\n\t\t\t\t\t\t</value>\n\t\t\t\t\t</item>\n\t\t\t\t</options>\n\t\t\t</classifyOptions>\n\t\t\t<providerContextId>9223372036854775813</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9889f02d-6a85-49b4-8928-884e5ab5ee59}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Policy Silent Mode Provider Context</name>\n\t\t\t\t<description>The policy is inspected only but not enforced</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50006f006c00690063007900530069006c0065006e0074004d006f0064006500500072006f00760069006400650072000000</data>\n\t\t\t\t<asString>P.o.l.i.c.y.S.i.l.e.n.t.M.o.d.e.P.r.o.v.i.d.e.r...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854775814</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{de04f4bd-a953-47f6-b1b6-eb6e24a546d6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5700530048002000440065006600610075006c0074000000</data>\n\t\t\t\t<asString>W.S.H. .D.e.f.a.u.l.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854775815</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{feb49053-a00e-42a7-ab12-6f0b07ae1b2b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>51007500650072007900200055007300650072002000440065006600610075006c0074000000</data>\n\t\t\t\t<asString>Q.u.e.r.y. .U.s.e.r. .D.e.f.a.u.l.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854775816</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7f0fdfe9-b5aa-4df8-98c2-8bb515bbc12a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>41007000700043006f006e007400610069006e006500720020004c006f006f0070006200610063006b000000</data>\n\t\t\t\t<asString>A.p.p.C.o.n.t.a.i.n.e.r. .L.o.o.p.b.a.c.k...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854775817</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{999ba50e-b870-4b5c-84e6-33a0e61cc8d1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53007400650061006c00740068000000</data>\n\t\t\t\t<asString>S.t.e.a.l.t.h...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854775818</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{20f3bb11-bbf6-4e60-aeb3-e651c675d642}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c0064006500640020004d00610069006e002000520075006c0065000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .M.a.i.n. .R.u.l.e...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776151</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{28127d58-a9af-43ee-bfe2-a06cb632fa4e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>440065006600610075006c007400200049006e0062006f0075006e0064000000</data>\n\t\t\t\t<asString>D.e.f.a.u.l.t. .I.n.b.o.u.n.d...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776154</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{df7bad3c-1c14-4ad9-ab82-5eb01bc9d76b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c0064006500640020004d00610069006e002000520075006c0065000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .M.a.i.n. .R.u.l.e...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776157</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{396a665b-ae9f-4c00-a33d-098abf605990}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>440065006600610075006c007400200049006e0062006f0075006e0064000000</data>\n\t\t\t\t<asString>D.e.f.a.u.l.t. .I.n.b.o.u.n.d...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776160</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7a06a358-d5e2-4304-8970-c724ca7c9674}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c0064006500640020004d00610069006e002000520075006c0065000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .M.a.i.n. .R.u.l.e...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776163</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{abf0b72d-a22e-427e-9139-ebca0193e5d9}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>440065006600610075006c007400200049006e0062006f0075006e0064000000</data>\n\t\t\t\t<asString>D.e.f.a.u.l.t. .I.n.b.o.u.n.d...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776166</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b36473ef-bf42-49b9-ac24-adba245e825c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5500570050002000440065006600610075006c007400200049006e0062006f0075006e006400200042006c006f0063006b002000520075006c0065000000</data>\n\t\t\t\t<asString>U.W.P. .D.e.f.a.u.l.t. .I.n.b.o.u.n.d. .B.l.o.c.k. .R.u.l.e...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776169</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{11ec8831-cda4-4bab-aa69-cb45e32f4ea9}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5500570050002000440065006600610075006c00740020004f007500740062006f0075006e006400200042006c006f0063006b002000520075006c0065000000</data>\n\t\t\t\t<asString>U.W.P. .D.e.f.a.u.l.t. .O.u.t.b.o.u.n.d. .B.l.o.c.k. .R.u.l.e...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776170</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{13fd7ae8-4dad-4362-9178-9991d6ac4670}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>41007500640069006f007300720076002d0031000000</data>\n\t\t\t\t<asString>A.u.d.i.o.s.r.v.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776171</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{74eff966-472f-46ce-9391-ad9e1303f145}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>41007500640069006f007300720076002d0032000000</data>\n\t\t\t\t<asString>A.u.d.i.o.s.r.v.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776172</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ac7ae3b6-0cf9-4ae4-9212-6c452f977570}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4100560045006e00640070006f0069006e0074004200750069006c006400650072002d0031000000</data>\n\t\t\t\t<asString>A.V.E.n.d.p.o.i.n.t.B.u.i.l.d.e.r.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776173</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2153ec13-392d-4ffd-aedb-b4818c4dc9f7}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4100560045006e00640070006f0069006e0074004200750069006c006400650072002d0032000000</data>\n\t\t\t\t<asString>A.V.E.n.d.p.o.i.n.t.B.u.i.l.d.e.r.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776174</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a16428ab-a823-4c1e-aee4-9bce9dd30989}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4100780049006e0073007400530056002d0031000000</data>\n\t\t\t\t<asString>A.x.I.n.s.t.S.V.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776175</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3cec65bf-a4e1-4376-b287-0691e08a6f63}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4100780049006e0073007400530056002d0033000000</data>\n\t\t\t\t<asString>A.x.I.n.s.t.S.V.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776176</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9066c4f6-66a6-41fc-a268-07d1b287af42}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4200460045002d0031000000</data>\n\t\t\t\t<asString>B.F.E.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776177</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{dbc25b5e-745f-46f2-800b-2178e7367202}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4200460045002d0032000000</data>\n\t\t\t\t<asString>B.F.E.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776178</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{074c3ea9-af96-4a28-a6c6-db9b0335adb0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4300440050005300760063002d0032000000</data>\n\t\t\t\t<asString>C.D.P.S.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776179</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e26c5b51-f344-4e59-b535-2ce78d16974c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4300440050005300760063002d0036000000</data>\n\t\t\t\t<asString>C.D.P.S.v.c.-.6...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776180</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{8966736d-4524-4694-9e2e-ee9f1387e011}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>63006c0072005f006f007000740069006d0069007a006100740069006f006e005f00760034002e0030002e00330030003300310039005f00330032002d0031000000</data>\n\t\t\t\t<asString>c.l.r._.o.p.t.i.m.i.z.a.t.i.o.n._.v.4...0...3.0.3.1.9._.3.2.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776181</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{bd49f24b-1801-46be-969c-e0cf5afd621a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>63006c0072005f006f007000740069006d0069007a006100740069006f006e005f00760034002e0030002e00330030003300310039005f00330032002d0032000000</data>\n\t\t\t\t<asString>c.l.r._.o.p.t.i.m.i.z.a.t.i.o.n._.v.4...0...3.0.3.1.9._.3.2.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776182</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{cc755386-b9e1-4342-a317-790c4f0a9534}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>63006c0072005f006f007000740069006d0069007a006100740069006f006e005f00760034002e0030002e00330030003300310039005f00360034002d0031000000</data>\n\t\t\t\t<asString>c.l.r._.o.p.t.i.m.i.z.a.t.i.o.n._.v.4...0...3.0.3.1.9._.6.4.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776183</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{bfa85b2e-3c06-4d69-b4e1-f149cff4661e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>63006c0072005f006f007000740069006d0069007a006100740069006f006e005f00760034002e0030002e00330030003300310039005f00360034002d0032000000</data>\n\t\t\t\t<asString>c.l.r._.o.p.t.i.m.i.z.a.t.i.o.n._.v.4...0...3.0.3.1.9._.6.4.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776184</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a8b55da6-3aba-41f3-b7ba-443233f64fce}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d0031000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776185</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c4e61e5c-3e66-4efb-b22b-87f8e56cf9c2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d00310030000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.1.0...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776186</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4dd4109f-8980-4e66-b307-887227d761a4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d00310031000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.1.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776187</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f876928c-1566-4b9a-a110-57d531115565}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d0032000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776188</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{616fdcf3-1169-46b5-8224-cffc7276af2e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d0034000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.4...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776189</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3742db91-517a-4f69-b378-08c5c09364b3}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d0035000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.5...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776190</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{49208958-c95e-48da-832f-60636a24827a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d0037000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.7...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776191</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{70f84089-a6de-44ab-88ba-681a2d87204e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400650076006900630065004d0061006e006100670065006d0065006e0074002d0038000000</data>\n\t\t\t\t<asString>D.e.v.i.c.e.M.a.n.a.g.e.m.e.n.t.-.8...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776192</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{acc4c150-270a-47dc-91d0-23dcf4b073f4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>44004800430050002d0034000000</data>\n\t\t\t\t<asString>D.H.C.P.-.4...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776193</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{fa7bff4f-61db-455f-8fec-220c1122cda0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>44004800430050002d0035000000</data>\n\t\t\t\t<asString>D.H.C.P.-.5...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776194</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{140da811-71af-4719-aea9-3e3196bb2c73}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>44006900730070006c006100790045006e00680061006e00630065006d0065006e00740053006500720076006900630065002000440065006e007900200041006c006c00200049006e0062006f0075006e0064000000</data>\n\t\t\t\t<asString>D.i.s.p.l.a.y.E.n.h.a.n.c.e.m.e.n.t.S.e.r.v.i.c.e. .D.e.n.y. .A.l.l. .I.n.b.o.u.n.d...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776195</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e8b4f949-15cf-4ef0-8c72-4b472a399374}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>44006900730070006c006100790045006e00680061006e00630065006d0065006e00740053006500720076006900630065002000440065006e007900200041006c006c0020004f007500740062006f0075006e0064000000</data>\n\t\t\t\t<asString>D.i.s.p.l.a.y.E.n.h.a.n.c.e.m.e.n.t.S.e.r.v.i.c.e. .D.e.n.y. .A.l.l. .O.u.t.b.o.u.n.d...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776196</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{29442789-6efc-46ed-b261-a526c4b07a9b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>64006f00740033007300760063002d0031000000</data>\n\t\t\t\t<asString>d.o.t.3.s.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776197</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{39e96b50-7896-45bf-8a32-6df85e30668a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>64006f00740033007300760063002d0032000000</data>\n\t\t\t\t<asString>d.o.t.3.s.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776198</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b9e16b36-f84a-4ada-8ad6-72303a132d9c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400500053002d0031000000</data>\n\t\t\t\t<asString>D.P.S.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776199</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d7138c16-5c23-4147-8aa2-26c31ffa3282}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4400500053002d0032000000</data>\n\t\t\t\t<asString>D.P.S.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776200</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{56ca2cdd-1a5b-49db-b1b1-0c7ecda76a96}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4500760065006e0074006c006f0067002d0032000000</data>\n\t\t\t\t<asString>E.v.e.n.t.l.o.g.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776201</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{66d12cf5-d1c3-4fcf-beec-60486740a808}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4500760065006e0074006c006f0067002d0033000000</data>\n\t\t\t\t<asString>E.v.e.n.t.l.o.g.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776202</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{766e17d2-0adf-4c0c-a05f-bd0e3a611a0d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>66006400700068006f00730074002d0031000000</data>\n\t\t\t\t<asString>f.d.p.h.o.s.t.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776203</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{82c89ca7-9d25-44bf-b763-ae9a0fc19072}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>66006400700068006f00730074002d0032000000</data>\n\t\t\t\t<asString>f.d.p.h.o.s.t.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776204</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d8d7429a-458d-419c-903a-72b1770c2fa5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>660068007300760063002d0031000000</data>\n\t\t\t\t<asString>f.h.s.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776205</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e4c31fb1-c4d0-4425-80cb-13aeaf564696}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>660068007300760063002d0032000000</data>\n\t\t\t\t<asString>f.h.s.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776206</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4d390cf4-706e-4f3a-afc5-75de5af9327e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>48006900640053006500720076002d0031000000</data>\n\t\t\t\t<asString>H.i.d.S.e.r.v.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776207</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a03a74d6-9d42-487f-9ebf-0576fb284312}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>48006900640053006500720076002d0032000000</data>\n\t\t\t\t<asString>H.i.d.S.e.r.v.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776208</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{dc9f453d-1eaa-4912-8a95-ec50252e8abd}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4c004d0048006f007300740073002d0033000000</data>\n\t\t\t\t<asString>L.M.H.o.s.t.s.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776209</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7c926fc6-603b-4a56-bd0e-683fc579cb4b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4c004d0048006f007300740073002d0034000000</data>\n\t\t\t\t<asString>L.M.H.o.s.t.s.-.4...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776210</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{482ea2c8-fdf2-41e7-8c58-b77891b9e26e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d0041006c006c004a006f0079006e002d0052006f0075007400650072002d0042006c006f0063006b002d0049006e002d0041006c006c0045006c00730065000000</data>\n\t\t\t\t<asString>M.i.c.r.o.s.o.f.t.-.W.i.n.d.o.w.s.-.A.l.l.J.o.y.n.-.R.o.u.t.e.r.-.B.l.o.c.k.-.I.n.-.A.l.l.E.l.s.e...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776211</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b91e477a-b12b-4ffe-8036-fb467a589bb5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d0041006c006c004a006f0079006e002d0052006f0075007400650072002d0042006c006f0063006b002d004f00750074002d0041006c006c0045006c00730065000000</data>\n\t\t\t\t<asString>M.i.c.r.o.s.o.f.t.-.W.i.n.d.o.w.s.-.A.l.l.J.o.y.n.-.R.o.u.t.e.r.-.B.l.o.c.k.-.O.u.t.-.A.l.l.E.l.s.e...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776212</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{84a6277c-c2cf-4550-8617-4766635b0978}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4d00500053005300560043002d0031000000</data>\n\t\t\t\t<asString>M.P.S.S.V.C.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776213</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9dc391c3-71d8-4649-b1d5-75ed10f360a9}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4d00500053005300560043002d0032000000</data>\n\t\t\t\t<asString>M.P.S.S.V.C.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776214</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0565668f-d3c2-489b-86fc-63eaa40816b7}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4e00650074006d0061006e002d0031000000</data>\n\t\t\t\t<asString>N.e.t.m.a.n.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776215</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e66edf14-6359-4ebf-a197-ba3f7537af1b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>4e00650074006d0061006e002d0032000000</data>\n\t\t\t\t<asString>N.e.t.m.a.n.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776216</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a8703831-1566-41ef-a65d-e1810ef57048}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5000320050002000470072006f007500700069006e006700200042006c006f0063006b00200049006e000000</data>\n\t\t\t\t<asString>P.2.P. .G.r.o.u.p.i.n.g. .B.l.o.c.k. .I.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776217</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{07e62e11-172d-4a30-af90-caf4e66d513b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5000320050002000470072006f007500700069006e006700200042006c006f0063006b0020004f00750074000000</data>\n\t\t\t\t<asString>P.2.P. .G.r.o.u.p.i.n.g. .B.l.o.c.k. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776218</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{1e2445fb-9e48-41aa-98ff-d540234e8a15}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50003200500020004900640065006e007400200042006c006f0063006b00200049006e000000</data>\n\t\t\t\t<asString>P.2.P. .I.d.e.n.t. .B.l.o.c.k. .I.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776219</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4fbe1969-bcf9-4b68-8e7f-12bdb7f4b5c5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50003200500020004900640065006e007400200042006c006f0063006b0020004f00750074000000</data>\n\t\t\t\t<asString>P.2.P. .I.d.e.n.t. .B.l.o.c.k. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776220</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2ec90dcd-0a0b-46e8-a930-97e228065a8d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5000630061005300760063002d0031000000</data>\n\t\t\t\t<asString>P.c.a.S.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776221</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{023d6954-db44-4559-875b-c888101ce60c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5000630061005300760063002d0032000000</data>\n\t\t\t\t<asString>P.c.a.S.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776222</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0f745c88-3d06-4f3f-836a-246ed1fdb397}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>500065007200660048006f00730074002d0031000000</data>\n\t\t\t\t<asString>P.e.r.f.H.o.s.t.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776223</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3f019c77-26df-4344-96a3-327d030483fd}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>500065007200660048006f00730074002d0032000000</data>\n\t\t\t\t<asString>P.e.r.f.H.o.s.t.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776224</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e39d0a93-3337-4e1e-b56a-d00861b1f26a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50004e0052005000200042006c006f0063006b00200049006e000000</data>\n\t\t\t\t<asString>P.N.R.P. .B.l.o.c.k. .I.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776225</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c4c5bf1b-6190-4fdc-95ec-0d4ba3d09dbc}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50004e0052005000200042006c006f0063006b0020004f00750074000000</data>\n\t\t\t\t<asString>P.N.R.P. .B.l.o.c.k. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776226</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d7744c01-2520-4e53-9d09-1b4c41561898}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50006e00720070004100750074006f00200042006c006f0063006b00200049006e000000</data>\n\t\t\t\t<asString>P.n.r.p.A.u.t.o. .B.l.o.c.k. .I.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776227</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f293ff68-0301-4ecb-9c6f-b0b73b0c0f99}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50006e00720070004100750074006f00200042006c006f0063006b0020004f00750074000000</data>\n\t\t\t\t<asString>P.n.r.p.A.u.t.o. .B.l.o.c.k. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776228</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{08edbc40-f085-4664-8cf6-cfb6e9ebe8f6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50006f006c006900630079004100670065006e0074002d0034000000</data>\n\t\t\t\t<asString>P.o.l.i.c.y.A.g.e.n.t.-.4...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776229</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{542d5137-d23a-4bb4-8d90-9c30857d84bc}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50006f006c006900630079004100670065006e0074002d0035000000</data>\n\t\t\t\t<asString>P.o.l.i.c.y.A.g.e.n.t.-.5...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776230</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3a5e8a34-82df-4083-a6ed-87ea8ed3507a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>530065006100720063006800460069006c0074006500720048006f00730074002d0031000000</data>\n\t\t\t\t<asString>S.e.a.r.c.h.F.i.l.t.e.r.H.o.s.t.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776231</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{03843031-9e01-449d-b94b-047c6fbe714c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>530065006100720063006800460069006c0074006500720048006f00730074002d0032000000</data>\n\t\t\t\t<asString>S.e.a.r.c.h.F.i.l.t.e.r.H.o.s.t.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776232</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{bbe3095e-afe8-4c43-8de5-b9994738a268}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006500610072006300680049006e00640065007800650072002d0031000000</data>\n\t\t\t\t<asString>S.e.a.r.c.h.I.n.d.e.x.e.r.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776233</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c7031a73-1778-4847-9b46-8ce7fa8798c1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006500610072006300680049006e00640065007800650072002d0032000000</data>\n\t\t\t\t<asString>S.e.a.r.c.h.I.n.d.e.x.e.r.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776234</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c0cedbe2-34f4-4491-bd19-152a55b1b6e0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>530065006100720063006800500072006f0074006f0063006f006c0048006f00730074002d0031000000</data>\n\t\t\t\t<asString>S.e.a.r.c.h.P.r.o.t.o.c.o.l.H.o.s.t.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776235</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{be0ee23e-c670-47d6-8112-7cf182d22041}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53004e004d00500054005200410050002d0032000000</data>\n\t\t\t\t<asString>S.N.M.P.T.R.A.P.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776236</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b508cf8d-5dbe-44e9-bc10-85402404c8f4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53004e004d00500054005200410050002d0033000000</data>\n\t\t\t\t<asString>S.N.M.P.T.R.A.P.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776237</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7b84e8bb-fa4a-42c3-b61d-6e2b0532fdc5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53005000500045005800540043004f004d004f0042004a002d0033000000</data>\n\t\t\t\t<asString>S.P.P.E.X.T.C.O.M.O.B.J.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776238</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6cc74acd-ca95-45f6-8c3b-5e62000940b0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53005000500045005800540043004f004d004f0042004a002d0034000000</data>\n\t\t\t\t<asString>S.P.P.E.X.T.C.O.M.O.B.J.-.4...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776239</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f63fb925-3743-4a88-95ed-a842472b93fc}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5300790073006d00610069006e002d0031000000</data>\n\t\t\t\t<asString>S.y.s.m.a.i.n.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776240</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0613da54-aa3d-4d9d-afd6-d4d64f655001}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5300790073006d00610069006e002d0032000000</data>\n\t\t\t\t<asString>S.y.s.m.a.i.n.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776241</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d8e3c9f1-31ab-441a-896a-8c4b0d3b2019}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5400610062006c006500740049006e0070007500740053006500720076006900630065002d0031000000</data>\n\t\t\t\t<asString>T.a.b.l.e.t.I.n.p.u.t.S.e.r.v.i.c.e.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776242</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{cfcaf1e6-48d2-47d1-a1e3-d7b017af03ee}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5400610062006c006500740049006e0070007500740053006500720076006900630065002d0032000000</data>\n\t\t\t\t<asString>T.a.b.l.e.t.I.n.p.u.t.S.e.r.v.i.c.e.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776243</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7b6dc94c-eb68-4c29-9f34-589b83c2f93a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>540072006b0077006b0073002d0031000000</data>\n\t\t\t\t<asString>T.r.k.w.k.s.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776244</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{42e3bde9-8223-45ae-a948-b331cfad1178}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>540072006b0077006b0073002d0032000000</data>\n\t\t\t\t<asString>T.r.k.w.k.s.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776245</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f5ce7aa1-73b7-4368-8117-1b81a708a5b8}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>55006d0052006400700053006500720076006900630065002d0031000000</data>\n\t\t\t\t<asString>U.m.R.d.p.S.e.r.v.i.c.e.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776246</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{09581f72-a5fa-4f0d-83c1-e0a072bb2e5c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>55006d0052006400700053006500720076006900630065002d0032000000</data>\n\t\t\t\t<asString>U.m.R.d.p.S.e.r.v.i.c.e.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776247</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{89946940-1d3d-4828-baf2-ef863ff4d926}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5600610063005300760063002d0031000000</data>\n\t\t\t\t<asString>V.a.c.S.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776248</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{09c48c05-27b6-4ee0-99f7-a39203499a80}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5600610063005300760063002d0032000000</data>\n\t\t\t\t<asString>V.a.c.S.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776249</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{20ba781c-7644-4706-9a3d-3cadb206da34}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5600440053002d0031000000</data>\n\t\t\t\t<asString>V.D.S.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776250</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{de982dfe-87db-49d3-ab9e-fd063af6cf3e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063006700750065007300740069006e0074006500720066006100630065002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.g.u.e.s.t.i.n.t.e.r.f.a.c.e.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776251</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{66d956e2-2f1d-424c-9d3c-48ae68b15ed6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063006700750065007300740069006e0074006500720066006100630065002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.g.u.e.s.t.i.n.t.e.r.f.a.c.e.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776252</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{36a4e3cc-ec47-49eb-977f-e55f10f19083}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063006800650061007200740062006500610074002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.h.e.a.r.t.b.e.a.t.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776253</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{8293ae37-bed3-4430-a7a4-68b06342c2e2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063006800650061007200740062006500610074002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.h.e.a.r.t.b.e.a.t.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776254</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{fcc62406-2a46-4704-8605-51da6478c028}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063006b0076007000650078006300680061006e00670065002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.k.v.p.e.x.c.h.a.n.g.e.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776255</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{996f6ad1-478b-49a3-9ac5-9278bbfdab90}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063006b0076007000650078006300680061006e00670065002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.k.v.p.e.x.c.h.a.n.g.e.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776256</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c9a666f9-bc1e-4e39-9ee6-52940117aad8}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063007200640076002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.r.d.v.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776257</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{19d55ef7-9fd1-43d0-b47c-b7752e875f3e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063007200640076002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.r.d.v.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776258</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{79d972a5-c160-4af7-b091-58da324a4ff0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d0069006300730068007500740064006f0077006e002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.s.h.u.t.d.o.w.n.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776259</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2c1956cf-17bc-4820-b44d-522f9985dc29}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d0069006300730068007500740064006f0077006e002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.s.h.u.t.d.o.w.n.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776260</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0c6406d9-1628-4c44-b2da-b5f8ca525a44}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d0069006300740069006d006500730079006e0063002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.t.i.m.e.s.y.n.c.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776261</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f245355c-3927-4d7a-b7eb-57a3db7827c6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d0069006300740069006d006500730079006e0063002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.t.i.m.e.s.y.n.c.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776262</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b4fc7eca-e42d-4ae1-a29e-bc721cde5535}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d006900630076006d00730065007300730069006f006e002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.v.m.s.e.s.s.i.o.n.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776263</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3c267f8e-944d-4068-acad-75ba5821575b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d006900630076006d00730065007300730069006f006e002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.v.m.s.e.s.s.i.o.n.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776264</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c58cd9f2-b4e4-43f5-b494-d7260d82f973}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063007600730073002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>v.m.i.c.v.s.s.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776265</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{1622032e-7b49-4f11-b377-d2c73c90bcc8}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>76006d00690063007600730073002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>v.m.i.c.v.s.s.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776266</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a5086f3a-f5e4-481e-8caf-1ff0204b001c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7700620065006e00670069006e0065002d0031000000</data>\n\t\t\t\t<asString>w.b.e.n.g.i.n.e.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776267</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c2733d72-d500-4045-94f2-09606cd6dbc6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7700620065006e00670069006e0065002d0033000000</data>\n\t\t\t\t<asString>w.b.e.n.g.i.n.e.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776268</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c6f5a818-b954-42a7-b596-45591ca10f6a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570063006d007300760063002d0031000000</data>\n\t\t\t\t<asString>W.c.m.s.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776269</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f87d269f-537e-4352-b018-87e5976976f7}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570063006d007300760063002d0033000000</data>\n\t\t\t\t<asString>W.c.m.s.v.c.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776270</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0c3cddb6-de83-4012-8dca-52a7682f97da}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570064006900530079007300740065006d0048006f00730074002d0031000000</data>\n\t\t\t\t<asString>W.d.i.S.y.s.t.e.m.H.o.s.t.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776271</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ffd72c64-50dc-4b5b-8b1e-1dfe782f4d0d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570064006900530079007300740065006d0048006f00730074002d0032000000</data>\n\t\t\t\t<asString>W.d.i.S.y.s.t.e.m.H.o.s.t.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776272</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9a09d870-2858-4be6-9e2f-ce10b4907fa0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5700650072005300760063002d0031000000</data>\n\t\t\t\t<asString>W.e.r.S.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776273</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c54b278f-9127-40bf-aa5e-86674fa65c76}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5700650072005300760063002d0032000000</data>\n\t\t\t\t<asString>W.e.r.S.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776274</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{690f4ad8-bc37-48b7-bed6-bfa7a526a895}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570069006e0064006f007700730044006500660065006e006400650072002d0032000000</data>\n\t\t\t\t<asString>W.i.n.d.o.w.s.D.e.f.e.n.d.e.r.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776275</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{cdfd6c38-1499-44b4-a900-60aa4e8936c2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570069006e0064006f007700730044006500660065006e006400650072002d0033000000</data>\n\t\t\t\t<asString>W.i.n.d.o.w.s.D.e.f.e.n.d.e.r.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776276</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{22d7902a-15f9-4e7c-85fa-062e993aa6d5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570069006e0048007400740070004100750074006f00500072006f00780079005300760063002d0032000000</data>\n\t\t\t\t<asString>W.i.n.H.t.t.p.A.u.t.o.P.r.o.x.y.S.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776277</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2810cbd2-88bb-47d7-a215-409c6cd87bee}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>570069006e0048007400740070004100750074006f00500072006f00780079005300760063002d0033000000</data>\n\t\t\t\t<asString>W.i.n.H.t.t.p.A.u.t.o.P.r.o.x.y.S.v.c.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776278</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{359ad55a-40a5-45e0-91ba-c921ac9cb876}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>57006c0061006e007300760063002d0031000000</data>\n\t\t\t\t<asString>W.l.a.n.s.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776279</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c9368850-7641-4a64-9c8d-91c38550f267}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>57006c0061006e007300760063002d0032000000</data>\n\t\t\t\t<asString>W.l.a.n.s.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776280</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e4bb7146-61ab-49c8-b9f3-57e9d27207e1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>77006c00700061007300760063002d0031000000</data>\n\t\t\t\t<asString>w.l.p.a.s.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776281</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{478442b4-ce51-424a-991f-9207b636722c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>77006c00700061007300760063002d0033000000</data>\n\t\t\t\t<asString>w.l.p.a.s.v.c.-.3...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776282</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{10cc650c-46e4-40e3-b9d8-1e34fee2055f}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5700530043002000440065006e007900200041006c006c00200049006e0062006f0075006e0064000000</data>\n\t\t\t\t<asString>W.S.C. .D.e.n.y. .A.l.l. .I.n.b.o.u.n.d...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776283</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{fece87b4-8033-4dbe-a385-6bc285eb6d78}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5700530043002000440065006e007900200041006c006c0020004f007500740062006f0075006e0064000000</data>\n\t\t\t\t<asString>W.S.C. .D.e.n.y. .A.l.l. .O.u.t.b.o.u.n.d...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776284</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9724c57d-1990-4c1f-b17d-8847702bfcef}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5700770061006e005300760063002d0031000000</data>\n\t\t\t\t<asString>W.w.a.n.S.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776285</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c0ff73ea-8d25-4280-a754-96b67c932869}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>5700770061006e005300760063002d0032000000</data>\n\t\t\t\t<asString>W.w.a.n.S.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776286</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ed046545-5b2c-4368-b04e-e93ca55def93}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>410073007300690067006e00650064004100630063006500730073004d0061006e0061006700650072005300760063002d0031000000</data>\n\t\t\t\t<asString>A.s.s.i.g.n.e.d.A.c.c.e.s.s.M.a.n.a.g.e.r.S.v.c.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776287</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{1b7af7da-20ed-4fb5-9eb4-3e63fcb7536c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>410073007300690067006e00650064004100630063006500730073004d0061006e0061006700650072005300760063002d0032000000</data>\n\t\t\t\t<asString>A.s.s.i.g.n.e.d.A.c.c.e.s.s.M.a.n.a.g.e.r.S.v.c.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776288</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6796b00a-0007-4eeb-b176-41c6807585a4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>63006c006f0075006400690064007300760063002d0062006c006f0063006b002d0069006e000000</data>\n\t\t\t\t<asString>c.l.o.u.d.i.d.s.v.c.-.b.l.o.c.k.-.i.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776289</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{774ac201-15c6-444f-82c9-1dcdff4326f2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>63006c006f0075006400690064007300760063002d0062006c006f0063006b002d006f00750074000000</data>\n\t\t\t\t<asString>c.l.o.u.d.i.d.s.v.c.-.b.l.o.c.k.-.o.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776290</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b47fa28f-cdca-41e8-8360-733d8216d7f9}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>43007300630053006500720076006900630065002d0031000000</data>\n\t\t\t\t<asString>C.s.c.S.e.r.v.i.c.e.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776291</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6e9a9b45-a4cb-4723-bd55-60149243222d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>43007300630053006500720076006900630065002d0032000000</data>\n\t\t\t\t<asString>C.s.c.S.e.r.v.i.c.e.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776292</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{5845f29b-b4a1-4df2-b66e-609e5f902183}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50006500650072004400690073007400200042006c006f0063006b00200049006e000000</data>\n\t\t\t\t<asString>P.e.e.r.D.i.s.t. .B.l.o.c.k. .I.n...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776293</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e22f0814-cca5-4de3-8991-4f296ccec7a5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>50006500650072004400690073007400200042006c006f0063006b0020004f00750074000000</data>\n\t\t\t\t<asString>P.e.e.r.D.i.s.t. .B.l.o.c.k. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776294</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{66e8985e-169a-4c11-9701-40419c45a9cc}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>57005000440042005500530045004e0055004d002d0031000000</data>\n\t\t\t\t<asString>W.P.D.B.U.S.E.N.U.M.-.1...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776295</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{cfef2756-ac04-449a-b6c6-ed010f460651}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>57005000440042005500530045004e0055004d002d0032000000</data>\n\t\t\t\t<asString>W.P.D.B.U.S.E.N.U.M.-.2...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776296</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2d39a837-d11e-4242-aa55-d55d0d92ae68}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>640064003400340036003600360033002d0030003000380036002d0034006100390037002d0038003000370061002d006100380033006500390035006400640038003400640038000000</data>\n\t\t\t\t<asString>d.d.4.4.6.6.6.3.-.0.0.8.6.-.4.a.9.7.-.8.0.7.a.-.a.8.3.e.9.5.d.d.8.4.d.8...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776297</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{19d6b0d9-e808-4803-a59f-92ae87bf4b00}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>300033006400320066006500650030002d0031006100640065002d0034003800610036002d0061003700640030002d003100390033006200610064003000310035003100330038000000</data>\n\t\t\t\t<asString>0.3.d.2.f.e.e.0.-.1.a.d.e.-.4.8.a.6.-.a.7.d.0.-.1.9.3.b.a.d.0.1.5.1.3.8...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776298</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{522717a3-989a-403d-8bd9-2301754f6bd4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340038003500440036003700310044002d0041003500330037002d0034003800410037002d0039003000440035002d003600370038003300380041003500420041004100320045007d000000</data>\n\t\t\t\t<asString>{.4.8.5.D.6.7.1.D.-.A.5.3.7.-.4.8.A.7.-.9.0.D.5.-.6.7.8.3.8.A.5.B.A.A.2.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776299</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{fcb5f99f-cabd-4580-b4f4-d8bb7629abd2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310043003100420039003600340036002d0032004200340046002d0034003300450046002d0038004300350042002d003300460039003000300042003700310034004100410042007d000000</data>\n\t\t\t\t<asString>{.1.C.1.B.9.6.4.6.-.2.B.4.F.-.4.3.E.F.-.8.C.5.B.-.3.F.9.0.0.B.7.1.4.A.A.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776300</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{68d4ff07-c138-454b-aa7e-316622d0a73c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310044004400440045003200300038002d0032004500330032002d0034003200410045002d0038003800380046002d004200440043003200380038003000380036004500300032007d000000</data>\n\t\t\t\t<asString>{.1.D.D.D.E.2.0.8.-.2.E.3.2.-.4.2.A.E.-.8.8.8.F.-.B.D.C.2.8.8.0.8.6.E.0.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776301</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4237d279-1e81-4828-958f-467bf3a5349b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360038003600420038003300350039002d0031003200330043002d0034003100370032002d0042003100330033002d004200390032003000350030003900320036003300440033007d000000</data>\n\t\t\t\t<asString>{.6.8.6.B.8.3.5.9.-.1.2.3.C.-.4.1.7.2.-.B.1.3.3.-.B.9.2.0.5.0.9.2.6.3.D.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776302</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6a19fa7f-ef2b-42cf-b2d6-8139181d816b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450045003400340044004100450041002d0034003100390036002d0034003000450036002d0041003900370030002d003500340038003500330043004400460045003900440041007d000000</data>\n\t\t\t\t<asString>{.E.E.4.4.D.A.E.A.-.4.1.9.6.-.4.0.E.6.-.A.9.7.0.-.5.4.8.5.3.C.D.F.E.9.D.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776303</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{52026488-b6af-4372-9685-0d69706e6683}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330038004300380037004200360045002d0034004600410031002d0034004400440043002d0042004300460043002d003600360033004500450035003600450030004300430030007d000000</data>\n\t\t\t\t<asString>{.3.8.C.8.7.B.6.E.-.4.F.A.1.-.4.D.D.C.-.B.C.F.C.-.6.6.3.E.E.5.6.E.0.C.C.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776304</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{249d04ff-49a5-4e08-87e9-0e68e2019df7}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00460041004400390039003200330043002d0034003900320030002d0034003200310030002d0038004400300042002d003400310030004600300039003100440043004300300043007d000000</data>\n\t\t\t\t<asString>{.F.A.D.9.9.2.3.C.-.4.9.2.0.-.4.2.1.0.-.8.D.0.B.-.4.1.0.F.0.9.1.D.C.C.0.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776305</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{cbc261c4-d5fd-4e97-8de5-9c64f045fbb0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440034004100460032003900380030002d0039004600370038002d0034004300390041002d0039003700430030002d003800390046003300360030004300390042004300380039007d000000</data>\n\t\t\t\t<asString>{.D.4.A.F.2.9.8.0.-.9.F.7.8.-.4.C.9.A.-.9.7.C.0.-.8.9.F.3.6.0.C.9.B.C.8.9.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776306</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f369fb4f-039a-40d7-89c4-e9d1636f38e1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00460033004300450030003900350037002d0042004600320039002d0034003200300035002d0038003000350046002d003800450033004400350045003000390037003300340042007d000000</data>\n\t\t\t\t<asString>{.F.3.C.E.0.9.5.7.-.B.F.2.9.-.4.2.0.5.-.8.0.5.F.-.8.E.3.D.5.E.0.9.7.3.4.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776307</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c29535e1-3bbf-4491-bfe8-020381591955}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370044003900370038003700380042002d0043003900310041002d0034003200460034002d0038003700360034002d003300440037004500320030003400310038003400370030007d000000</data>\n\t\t\t\t<asString>{.7.D.9.7.8.7.8.B.-.C.9.1.A.-.4.2.F.4.-.8.7.6.4.-.3.D.7.E.2.0.4.1.8.4.7.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776308</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b1f4be4b-02f3-4fe6-9da0-489362bd0b71}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410042003600410042004400320035002d0038003300420030002d0034003200390030002d0041003700420045002d003400340035003300410042003000370035003100460031007d000000</data>\n\t\t\t\t<asString>{.A.B.6.A.B.D.2.5.-.8.3.B.0.-.4.2.9.0.-.A.7.B.E.-.4.4.5.3.A.B.0.7.5.1.F.1.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776309</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7eb2b4ea-2142-4c7e-a44f-ebb62240040d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360038003300380041003400340035002d0030004200460033002d0034004500390046002d0042004500410044002d004400320045003900420044003700320042004500460044007d000000</data>\n\t\t\t\t<asString>{.6.8.3.8.A.4.4.5.-.0.B.F.3.-.4.E.9.F.-.B.E.A.D.-.D.2.E.9.B.D.7.2.B.E.F.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776310</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{176827d1-c164-4c39-8c31-3afecc6a8b87}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430044003500440034003000450046002d0042004500350036002d0034003500440034002d0042003400300035002d003900350031003500450038004400310034003300410037007d000000</data>\n\t\t\t\t<asString>{.C.D.5.D.4.0.E.F.-.B.E.5.6.-.4.5.D.4.-.B.4.0.5.-.9.5.1.5.E.8.D.1.4.3.A.7.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776311</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{5f6a0bbb-a184-4846-b780-05f78b81c312}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370034004600340043004500410031002d0032003600430031002d0034003100440036002d0038003900450042002d004400430033003700450037004600310039003600410033007d000000</data>\n\t\t\t\t<asString>{.7.4.F.4.C.E.A.1.-.2.6.C.1.-.4.1.D.6.-.8.9.E.B.-.D.C.3.7.E.7.F.1.9.6.A.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776312</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2b60bea0-0fb8-431e-b6bc-2ecb692ddb06}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390035003700300036004600330030002d0045004400300035002d0034004500370043002d0041003800440041002d003300350045004500360037003700420036003000360042007d000000</data>\n\t\t\t\t<asString>{.9.5.7.0.6.F.3.0.-.E.D.0.5.-.4.E.7.C.-.A.8.D.A.-.3.5.E.E.6.7.7.B.6.0.6.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776313</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{39ba4b09-2547-445d-a928-30377b0904fc}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450032004500430033003600380038002d0046003000300035002d0034004200430036002d0041003700420046002d003100360032003900410042004600350031003000300041007d000000</data>\n\t\t\t\t<asString>{.E.2.E.C.3.6.8.8.-.F.0.0.5.-.4.B.C.6.-.A.7.B.F.-.1.6.2.9.A.B.F.5.1.0.0.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776314</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{eab91178-7ca7-4e7c-9c51-b0fb5529aeec}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310034003500420039003500350046002d0038003200430041002d0034003700360036002d0038004600430037002d004500360033003700330039003000370042004400390046007d000000</data>\n\t\t\t\t<asString>{.1.4.5.B.9.5.5.F.-.8.2.C.A.-.4.7.6.6.-.8.F.C.7.-.E.6.3.7.3.9.0.7.B.D.9.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776315</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{172590db-b33f-47df-9a24-df562ac3ec0f}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320032003000370041004400310042002d0034003600330036002d0034003100340033002d0038004100390034002d004100310041003400330041003100310032004300330042007d000000</data>\n\t\t\t\t<asString>{.2.2.0.7.A.D.1.B.-.4.6.3.6.-.4.1.4.3.-.8.A.9.4.-.A.1.A.4.3.A.1.1.2.C.3.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776316</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6a3f64d4-864f-42ed-9dd8-30a826e49a5a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320046004500440031003700460037002d0033003000300039002d0034003800440043002d0041003600320036002d003200360030004400420046004500370039003400310035007d000000</data>\n\t\t\t\t<asString>{.2.F.E.D.1.7.F.7.-.3.0.0.9.-.4.8.D.C.-.A.6.2.6.-.2.6.0.D.B.F.E.7.9.4.1.5.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776317</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{74988442-3bfb-451c-9a63-9eabb07c4485}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300031003200340036004100430030002d0043003800340039002d0034003100370036002d0042003400330030002d003500440046003000350046004600330041003200370036007d000000</data>\n\t\t\t\t<asString>{.0.1.2.4.6.A.C.0.-.C.8.4.9.-.4.1.7.6.-.B.4.3.0.-.5.D.F.0.5.F.F.3.A.2.7.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776318</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{5f35226f-d9fa-4d44-8136-27a1c662a034}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410033004400440044004200360043002d0041003800300043002d0034004300450033002d0039003400420036002d003400320035004500390045004400380037004200390044007d000000</data>\n\t\t\t\t<asString>{.A.3.D.D.D.B.6.C.-.A.8.0.C.-.4.C.E.3.-.9.4.B.6.-.4.2.5.E.9.E.D.8.7.B.9.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776319</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ee701874-f029-4ad6-b10b-a96448806f5e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360030003700390035003700380033002d0037004100340043002d0034003700380035002d0041003100300037002d003600380043003900350036004100330042004500380037007d000000</data>\n\t\t\t\t<asString>{.6.0.7.9.5.7.8.3.-.7.A.4.C.-.4.7.8.5.-.A.1.0.7.-.6.8.C.9.5.6.A.3.B.E.8.7.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776320</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f51c59dd-efbf-4d67-8098-1ed8362db864}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310037004200450034004600360034002d0033004500360031002d0034004200420037002d0039003400450031002d003200330042004500320042003800320038004600330038007d000000</data>\n\t\t\t\t<asString>{.1.7.B.E.4.F.6.4.-.3.E.6.1.-.4.B.B.7.-.9.4.E.1.-.2.3.B.E.2.B.8.2.8.F.3.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776321</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4118e8a8-7bc3-4cfa-bc76-b58807f4b331}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300037004500340031004500350039002d0032004100330036002d0034003700300036002d0039003200310041002d003500420038003200410037003900380043004600350042007d000000</data>\n\t\t\t\t<asString>{.0.7.E.4.1.E.5.9.-.2.A.3.6.-.4.7.0.6.-.9.2.1.A.-.5.B.8.2.A.7.9.8.C.F.5.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776322</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4cb1e008-1717-41de-b54b-002f7f5ee7ed}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410041003900420033003900370044002d0030003700360042002d0034003700390042002d0042004600310046002d003500390034003100350044004400430030004300390046007d000000</data>\n\t\t\t\t<asString>{.A.A.9.B.3.9.7.D.-.0.7.6.B.-.4.7.9.B.-.B.F.1.F.-.5.9.4.1.5.D.D.C.0.C.9.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776323</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c78cca83-d284-4994-afa2-36f2d141092d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440046003600310037004500420035002d0042003400450044002d0034004500410038002d0039003700420039002d004100360038003300460045004400330035004500350031007d000000</data>\n\t\t\t\t<asString>{.D.F.6.1.7.E.B.5.-.B.4.E.D.-.4.E.A.8.-.9.7.B.9.-.A.6.8.3.F.E.D.3.5.E.5.1.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776324</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3992e37e-b141-4b1e-97c7-91a13aad3f4d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430032003800340030004100430043002d0032003500300034002d0034003300430046002d0038003900460045002d004200380035004500440044003600360034003400320032007d000000</data>\n\t\t\t\t<asString>{.C.2.8.4.0.A.C.C.-.2.5.0.4.-.4.3.C.F.-.8.9.F.E.-.B.8.5.E.D.D.6.6.4.4.2.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776325</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{05ec7931-2f4c-41be-a2ea-6d51d1bbbece}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00460044003800390030003600430042002d0045004400430033002d0034003500320031002d0038003000370037002d004600330036004600410038004400320038003900410044007d000000</data>\n\t\t\t\t<asString>{.F.D.8.9.0.6.C.B.-.E.D.C.3.-.4.5.2.1.-.8.0.7.7.-.F.3.6.F.A.8.D.2.8.9.A.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776326</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{99d123c2-3b7b-4ed4-9ec8-db4045ecab9c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370037003800310044003600460038002d0036003100420046002d0034004500310030002d0042003400310042002d003000350045004200420045003800340036004500390045007d000000</data>\n\t\t\t\t<asString>{.7.7.8.1.D.6.F.8.-.6.1.B.F.-.4.E.1.0.-.B.4.1.B.-.0.5.E.B.B.E.8.4.6.E.9.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776327</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f1e8ae28-b94f-4ea4-8146-effcf1aab52d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350037003800340038004300320043002d0044003800310034002d0034003600450036002d0041003500360030002d003000330043003700390035003700330039003400330041007d000000</data>\n\t\t\t\t<asString>{.5.7.8.4.8.C.2.C.-.D.8.1.4.-.4.6.E.6.-.A.5.6.0.-.0.3.C.7.9.5.7.3.9.4.3.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776328</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f110ffcf-96c3-4478-bb37-1b945cb78a70}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370030003400320031004100330042002d0045003900410039002d0034003000360043002d0039003400350036002d003400430044003000380030003300430046003000350041007d000000</data>\n\t\t\t\t<asString>{.7.0.4.2.1.A.3.B.-.E.9.A.9.-.4.0.6.C.-.9.4.5.6.-.4.C.D.0.8.0.3.C.F.0.5.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776329</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f981bff2-8c56-445e-8cb7-96a027e9f6b1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00420041004500300032004400420044002d0032003600420031002d0034004100340037002d0039003200390030002d003400300030003200360043003800380043003900390034007d000000</data>\n\t\t\t\t<asString>{.B.A.E.0.2.D.B.D.-.2.6.B.1.-.4.A.4.7.-.9.2.9.0.-.4.0.0.2.6.C.8.8.C.9.9.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776330</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{fefb887e-0b75-460c-9c27-d56487aac61a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320033003600390033004600450030002d0031003800380039002d0034003500320044002d0039004600450030002d004100390045004600420030003000390033003700330042007d000000</data>\n\t\t\t\t<asString>{.2.3.6.9.3.F.E.0.-.1.8.8.9.-.4.5.2.D.-.9.F.E.0.-.A.9.E.F.B.0.0.9.3.7.3.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776331</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{160c36c9-0822-478c-95ee-e5f979416fbb}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350033003200380036004400320043002d0043004400460046002d0034003900450035002d0039004600320039002d004400370043004500450043004100440037003900410036007d000000</data>\n\t\t\t\t<asString>{.5.3.2.8.6.D.2.C.-.C.D.F.F.-.4.9.E.5.-.9.F.2.9.-.D.7.C.E.E.C.A.D.7.9.A.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776332</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a005febd-1b7b-4a86-90cc-92d03d4ef881}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440041003700430032004600380033002d0030004200370031002d0034004600300044002d0042004200350030002d003700460039003300390032004200380031003000380032007d000000</data>\n\t\t\t\t<asString>{.D.A.7.C.2.F.8.3.-.0.B.7.1.-.4.F.0.D.-.B.B.5.0.-.7.F.9.3.9.2.B.8.1.0.8.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776333</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d1a7f6b9-32b7-43f3-9c54-729684ef4756}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00460037003400360033003500310031002d0039004400300030002d0034004300420045002d0041003300420031002d003900430031004100350031003100360042004100310032007d000000</data>\n\t\t\t\t<asString>{.F.7.4.6.3.5.1.1.-.9.D.0.0.-.4.C.B.E.-.A.3.B.1.-.9.C.1.A.5.1.1.6.B.A.1.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776334</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{eb407abd-ec36-44d8-8fc6-881762cd0741}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430038004300410039004500310043002d0039003800370038002d0034004100440044002d0038003000450033002d003700420045003700360035003000330041004600340045007d000000</data>\n\t\t\t\t<asString>{.C.8.C.A.9.E.1.C.-.9.8.7.8.-.4.A.D.D.-.8.0.E.3.-.7.B.E.7.6.5.0.3.A.F.4.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776335</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f38530b7-9907-4f2e-be76-f1071e6395f0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340039004600330032003800430042002d0044003500320046002d0034004100340044002d0041003800430032002d003900320036004200440034003600300037003800360038007d000000</data>\n\t\t\t\t<asString>{.4.9.F.3.2.8.C.B.-.D.5.2.F.-.4.A.4.D.-.A.8.C.2.-.9.2.6.B.D.4.6.0.7.8.6.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776336</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{45f882ef-306e-4e41-bf2b-e06259932b00}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00380031003400440032003200450033002d0046003000440042002d0034003900380034002d0039003800330046002d004200430033003200360039003600420045003000460031007d000000</data>\n\t\t\t\t<asString>{.8.1.4.D.2.2.E.3.-.F.0.D.B.-.4.9.8.4.-.9.8.3.F.-.B.C.3.2.6.9.6.B.E.0.F.1.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776337</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2e30c355-e9ed-49ce-a635-266a4440be9e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440045003400300036003700420035002d0044003000310044002d0034004600370046002d0039003500420039002d004200430041003500360045004100430041004600410041007d000000</data>\n\t\t\t\t<asString>{.D.E.4.0.6.7.B.5.-.D.0.1.D.-.4.F.7.F.-.9.5.B.9.-.B.C.A.5.6.E.A.C.A.F.A.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776338</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a5a5784f-7482-4fb0-8f7d-d76ea07b5573}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300035003400460038004100420046002d0039003200330039002d0034003800460032002d0041004300450031002d003000360038003000310030003200420042004100430036007d000000</data>\n\t\t\t\t<asString>{.0.5.4.F.8.A.B.F.-.9.2.3.9.-.4.8.F.2.-.A.C.E.1.-.0.6.8.0.1.0.2.B.B.A.C.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776339</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e5c91f00-cb28-4d70-8ef2-9351c595e63e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00420032004300330045003700330045002d0035004400390038002d0034004200330037002d0038004100440032002d004600410036003900300035003400350037003800320045007d000000</data>\n\t\t\t\t<asString>{.B.2.C.3.E.7.3.E.-.5.D.9.8.-.4.B.3.7.-.8.A.D.2.-.F.A.6.9.0.5.4.5.7.8.2.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776340</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{13e654d8-0311-4b2b-937c-1f01e46ffbb2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310046003500430043003400460036002d0030004100440042002d0034003200450044002d0042003500430043002d003100350045004200350045004200390030003100430034007d000000</data>\n\t\t\t\t<asString>{.1.F.5.C.C.4.F.6.-.0.A.D.B.-.4.2.E.D.-.B.5.C.C.-.1.5.E.B.5.E.B.9.0.1.C.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776341</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{df298d75-3e7f-4e8d-8b55-f56b4926c82f}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450034004500330044003300310033002d0038003500450033002d0034004300450030002d0041003100330030002d003500380035004400430039003600370041004400360036007d000000</data>\n\t\t\t\t<asString>{.E.4.E.3.D.3.1.3.-.8.5.E.3.-.4.C.E.0.-.A.1.3.0.-.5.8.5.D.C.9.6.7.A.D.6.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776342</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9521e687-22a1-418f-bce2-7eb7fe25070a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340033003000310042004300350039002d0032004100450045002d0034003500410038002d0039003600340038002d004600360031004200330035003400320030003500320046007d000000</data>\n\t\t\t\t<asString>{.4.3.0.1.B.C.5.9.-.2.A.E.E.-.4.5.A.8.-.9.6.4.8.-.F.6.1.B.3.5.4.2.0.5.2.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776343</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{db42024e-f9e7-4f03-b4c3-94fb3db7f934}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390044003600420033003300320041002d0046003500320032002d0034003400430036002d0042003400380044002d003900430043004300340035003200330037003900380036007d000000</data>\n\t\t\t\t<asString>{.9.D.6.B.3.3.2.A.-.F.5.2.2.-.4.4.C.6.-.B.4.8.D.-.9.C.C.C.4.5.2.3.7.9.8.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776344</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{35f3ec13-352d-4b4d-80e7-0745db50321e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350041003300330032003700430037002d0033003500380035002d0034004600460043002d0039004200390042002d004100380044004400310037004400380031004600380033007d000000</data>\n\t\t\t\t<asString>{.5.A.3.3.2.7.C.7.-.3.5.8.5.-.4.F.F.C.-.9.B.9.B.-.A.8.D.D.1.7.D.8.1.F.8.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776345</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0de8b3b5-a43a-4651-9397-f7a2a5c86ec6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360038003900310046003600460036002d0032003500320035002d0034004600420032002d0039003300330045002d003900450046003000370046003300380033003300350044007d000000</data>\n\t\t\t\t<asString>{.6.8.9.1.F.6.F.6.-.2.5.2.5.-.4.F.B.2.-.9.3.3.E.-.9.E.F.0.7.F.3.8.3.3.5.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776346</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{23729a28-9e77-4000-a175-0d3ace63d138}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330034003800390034003600390032002d0036003500380031002d0034003500440035002d0041004200450044002d003000440036003400350039003500360032004400320041007d000000</data>\n\t\t\t\t<asString>{.3.4.8.9.4.6.9.2.-.6.5.8.1.-.4.5.D.5.-.A.B.E.D.-.0.D.6.4.5.9.5.6.2.D.2.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776347</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{1588f8a1-b166-48f6-bef3-a2918b2b4b2e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440036004200430039003000420046002d0035004400340043002d0034003200420038002d0042004200380031002d004400330030004200350045003500390033003300300043007d000000</data>\n\t\t\t\t<asString>{.D.6.B.C.9.0.B.F.-.5.D.4.C.-.4.2.B.8.-.B.B.8.1.-.D.3.0.B.5.E.5.9.3.3.0.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776348</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{eeefb14f-6d56-4ad8-9a0d-6906e0f27143}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370036003900310046003900420034002d0031004400310031002d0034003900360030002d0038003800310045002d003400320030003100440045003100330031004100340034007d000000</data>\n\t\t\t\t<asString>{.7.6.9.1.F.9.B.4.-.1.D.1.1.-.4.9.6.0.-.8.8.1.E.-.4.2.0.1.D.E.1.3.1.A.4.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776349</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ef018b97-7b72-4cdb-8f9e-6cda465099ad}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320042003100440036003200350045002d0041004500350039002d0034004300430037002d0039003500300044002d004200320035004400340046004600340043004100370039007d000000</data>\n\t\t\t\t<asString>{.2.B.1.D.6.2.5.E.-.A.E.5.9.-.4.C.C.7.-.9.5.0.D.-.B.2.5.D.4.F.F.4.C.A.7.9.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776350</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{70e5215e-c496-4954-a024-485e29f64ed1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320030004400330039003200300030002d0034004600330044002d0034004300330037002d0039004500370035002d004600370037003400310032004500430045003900300036007d000000</data>\n\t\t\t\t<asString>{.2.0.D.3.9.2.0.0.-.4.F.3.D.-.4.C.3.7.-.9.E.7.5.-.F.7.7.4.1.2.E.C.E.9.0.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776351</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{57ca4bf8-eb85-4596-b0f5-93f3f457c9da}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340031003500440041003600430045002d0035004500390041002d0034003400360032002d0039004100310046002d004400370039004600340037003700460031003900410035007d000000</data>\n\t\t\t\t<asString>{.4.1.5.D.A.6.C.E.-.5.E.9.A.-.4.4.6.2.-.9.A.1.F.-.D.7.9.F.4.7.7.F.1.9.A.5.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776352</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4b3fce1f-7c65-4f21-9cb6-12610863dc49}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440037004100460035003800320034002d0042003100430044002d0034004300360037002d0042003100440033002d003800350044003500330038003800310041004100340039007d000000</data>\n\t\t\t\t<asString>{.D.7.A.F.5.8.2.4.-.B.1.C.D.-.4.C.6.7.-.B.1.D.3.-.8.5.D.5.3.8.8.1.A.A.4.9.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776353</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a0789b38-a6a5-44c8-aee7-cb273954a2c0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430035003500330035004200370043002d0031003900390044002d0034003000380032002d0041003100380034002d004400430030003300350043003300430035003800390038007d000000</data>\n\t\t\t\t<asString>{.C.5.5.3.5.B.7.C.-.1.9.9.D.-.4.0.8.2.-.A.1.8.4.-.D.C.0.3.5.C.3.C.5.8.9.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776354</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7954653e-00d4-493b-bf75-a7df7811caca}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330032003000320037004200410041002d0046004400420044002d0034003200330030002d0041003900450035002d004100460034004600330037003200410037003400350042007d000000</data>\n\t\t\t\t<asString>{.3.2.0.2.7.B.A.A.-.F.D.B.D.-.4.2.3.0.-.A.9.E.5.-.A.F.4.F.3.7.2.A.7.4.5.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776355</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{986ffd0c-9682-4e34-93ee-18282e6fc7e4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410043003200410042003000430045002d0045004400390036002d0034003500350041002d0039003100430035002d003100440039004200430046004100330043003100380037007d000000</data>\n\t\t\t\t<asString>{.A.C.2.A.B.0.C.E.-.E.D.9.6.-.4.5.5.A.-.9.1.C.5.-.1.D.9.B.C.F.A.3.C.1.8.7.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776356</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c4a200b8-5ef7-4b22-990c-3de8576a89c2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00460042003400320039004600380038002d0039003400340039002d0034004300440046002d0041003600390032002d003700450034003800440035003200450045004500460041007d000000</data>\n\t\t\t\t<asString>{.F.B.4.2.9.F.8.8.-.9.4.4.9.-.4.C.D.F.-.A.6.9.2.-.7.E.4.8.D.5.2.E.E.E.F.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776357</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{5504179a-041a-4796-902c-9d29d6461739}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350037003300300032004100430032002d0036003000460039002d0034003700410034002d0038003400330035002d004600420041004600450030003800300036004400320041007d000000</data>\n\t\t\t\t<asString>{.5.7.3.0.2.A.C.2.-.6.0.F.9.-.4.7.A.4.-.8.4.3.5.-.F.B.A.F.E.0.8.0.6.D.2.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776358</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f8a49d92-f357-4994-8b2a-a3cbed9d995b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00420039003900340034004300370046002d0037003100390030002d0034004300340045002d0041004100380046002d004400370033003600460034004200370042003900340041007d000000</data>\n\t\t\t\t<asString>{.B.9.9.4.4.C.7.F.-.7.1.9.0.-.4.C.4.E.-.A.A.8.F.-.D.7.3.6.F.4.B.7.B.9.4.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776359</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ccee2909-294e-4ad6-b0ef-fa93cdf3d2b5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340045003100450038003500330036002d0046004600450037002d0034003200420039002d0042003500340035002d003900380030004400330045003200300030003700300044007d000000</data>\n\t\t\t\t<asString>{.4.E.1.E.8.5.3.6.-.F.F.E.7.-.4.2.B.9.-.B.5.4.5.-.9.8.0.D.3.E.2.0.0.7.0.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776360</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3aaefe3a-4f84-40da-a38a-319c198ac067}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00380042003100390046003900440034002d0033004200460045002d0034003900300030002d0041004200430033002d004400410039003100380037003600410044003400320043007d000000</data>\n\t\t\t\t<asString>{.8.B.1.9.F.9.D.4.-.3.B.F.E.-.4.9.0.0.-.A.B.C.3.-.D.A.9.1.8.7.6.A.D.4.2.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776361</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2fceaed8-43de-431e-9e1c-248e4f8f43e1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320041004400370033004500310035002d0041004400380041002d0034004500310037002d0042004200450030002d004200420038003200450039003600360046003900360045007d000000</data>\n\t\t\t\t<asString>{.2.A.D.7.3.E.1.5.-.A.D.8.A.-.4.E.1.7.-.B.B.E.0.-.B.B.8.2.E.9.6.6.F.9.6.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776362</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a2ddf546-d32c-4a74-b522-12c269bee88f}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390035003500410034003800350041002d0039004600300036002d0034004100360043002d0041003900360044002d004100330042003500430046003600390046004200350042007d000000</data>\n\t\t\t\t<asString>{.9.5.5.A.4.8.5.A.-.9.F.0.6.-.4.A.6.C.-.A.9.6.D.-.A.3.B.5.C.F.6.9.F.B.5.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776363</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{8852c503-6be2-4850-b366-41a3600b3c14}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370043003100330033003900300038002d0030003500330045002d0034003800350039002d0039004400360034002d004600300031003300440031004100410035003600300036007d000000</data>\n\t\t\t\t<asString>{.7.C.1.3.3.9.0.8.-.0.5.3.E.-.4.8.5.9.-.9.D.6.4.-.F.0.1.3.D.1.A.A.5.6.0.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776364</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d02a7aa2-6454-4fd6-82fb-b198cef82a49}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430043003100410039004200390046002d0046004200420033002d0034003300300045002d0039004200350033002d004300380039003800420035003400380039003100430036007d000000</data>\n\t\t\t\t<asString>{.C.C.1.A.9.B.9.F.-.F.B.B.3.-.4.3.0.E.-.9.B.5.3.-.C.8.9.8.B.5.4.8.9.1.C.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776365</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{577bdf7b-b66e-4aa7-8c1e-0056a2312d4d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360032003500340043003500440044002d0036004600430039002d0034003900460030002d0038004300350039002d003400350030004200440033004600320039003100390038007d000000</data>\n\t\t\t\t<asString>{.6.2.5.4.C.5.D.D.-.6.F.C.9.-.4.9.F.0.-.8.C.5.9.-.4.5.0.B.D.3.F.2.9.1.9.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776366</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e972b787-cefb-4018-8a07-cb56fb335d05}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440043004200370044003300310041002d0043003600440030002d0034004500340037002d0042003300380034002d003200460039003400430030003400440030003300360034007d000000</data>\n\t\t\t\t<asString>{.D.C.B.7.D.3.1.A.-.C.6.D.0.-.4.E.4.7.-.B.3.8.4.-.2.F.9.4.C.0.4.D.0.3.6.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776367</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a1c1ada8-14c5-436e-a4c1-9ed9a31cf907}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430037004200320036004100450043002d0038003800440044002d0034004300390030002d0039003100310043002d004100410037003500350031003500440039003600360041007d000000</data>\n\t\t\t\t<asString>{.C.7.B.2.6.A.E.C.-.8.8.D.D.-.4.C.9.0.-.9.1.1.C.-.A.A.7.5.5.1.5.D.9.6.6.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776368</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{000023c2-38de-4459-b661-d03163e40e3a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360046004400350033003700420035002d0036004300330031002d0034003500380042002d0038003900310033002d003400440042004100440041003700430030003000340030007d000000</data>\n\t\t\t\t<asString>{.6.F.D.5.3.7.B.5.-.6.C.3.1.-.4.5.8.B.-.8.9.1.3.-.4.D.B.A.D.A.7.C.0.0.4.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776369</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{98008b68-29a7-4a99-ab26-95244c6f3f54}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320037003400320035004500360031002d0031003600450037002d0034003400370030002d0038004600410042002d003600440041004400430041004600320038003000380035007d000000</data>\n\t\t\t\t<asString>{.2.7.4.2.5.E.6.1.-.1.6.E.7.-.4.4.7.0.-.8.F.A.B.-.6.D.A.D.C.A.F.2.8.0.8.5.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776370</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{43241563-341c-4081-a5c8-5936cf234f41}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450030004400420037003000330041002d0036003800410045002d0034003200410045002d0042004600410035002d003200390036003400390039004200300033004200450031007d000000</data>\n\t\t\t\t<asString>{.E.0.D.B.7.0.3.A.-.6.8.A.E.-.4.2.A.E.-.B.F.A.5.-.2.9.6.4.9.9.B.0.3.B.E.1.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776371</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{447f6038-491e-4529-bc1e-a587cba618a3}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450041003900330032004500410041002d0036004300460043002d0034003200390042002d0042003700320035002d003000370044004100440033004400330035003000450044007d000000</data>\n\t\t\t\t<asString>{.E.A.9.3.2.E.A.A.-.6.C.F.C.-.4.2.9.B.-.B.7.2.5.-.0.7.D.A.D.3.D.3.5.0.E.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776372</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{5c41bff6-8bf5-48af-b42e-3b913be0d81f}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350031004200450041003600460041002d0042004400350033002d0034003200350038002d0041003600420035002d003500430044003400410044003300300031004600310033007d000000</data>\n\t\t\t\t<asString>{.5.1.B.E.A.6.F.A.-.B.D.5.3.-.4.2.5.8.-.A.6.B.5.-.5.C.D.4.A.D.3.0.1.F.1.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776373</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{978930af-c0d6-4296-ae53-cabba5589a56}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440035003500360034004100350046002d0039003800320038002d0034003600360031002d0039004600430043002d004200460045003200320039003200460043003300370033007d000000</data>\n\t\t\t\t<asString>{.D.5.5.6.4.A.5.F.-.9.8.2.8.-.4.6.6.1.-.9.F.C.C.-.B.F.E.2.2.9.2.F.C.3.7.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776374</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{848b440e-9599-4a74-b7d7-e85f5eabbee0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330035003700410044004300300030002d0041003400450044002d0034004200370035002d0039003500460033002d003700410030003600370035004600440036003800320045007d000000</data>\n\t\t\t\t<asString>{.3.5.7.A.D.C.0.0.-.A.4.E.D.-.4.B.7.5.-.9.5.F.3.-.7.A.0.6.7.5.F.D.6.8.2.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776375</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{074dbf65-e26f-4e48-bcf6-2e6308011093}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390045003900320033003700390041002d0031004600370044002d0034003400430044002d0042004400380046002d004400450041003400300033003600360031003000330045007d000000</data>\n\t\t\t\t<asString>{.9.E.9.2.3.7.9.A.-.1.F.7.D.-.4.4.C.D.-.B.D.8.F.-.D.E.A.4.0.3.6.6.1.0.3.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776376</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{8ebcef68-f34d-4139-8b85-7b57334b9329}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310037003100350031003900310046002d0035003100450038002d0034003900320046002d0038003800460044002d004500440043003000330044003500370045004600370042007d000000</data>\n\t\t\t\t<asString>{.1.7.1.5.1.9.1.F.-.5.1.E.8.-.4.9.2.F.-.8.8.F.D.-.E.D.C.0.3.D.5.7.E.F.7.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776377</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{152c9c3b-b07e-486e-a750-7d561d75f843}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450043003600410039003600330039002d0035003300360035002d0034003600430041002d0042004400460042002d004500350041004100300039003300420035004200460045007d000000</data>\n\t\t\t\t<asString>{.E.C.6.A.9.6.3.9.-.5.3.6.5.-.4.6.C.A.-.B.D.F.B.-.E.5.A.A.0.9.3.B.5.B.F.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776378</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4c37bb57-9bdf-4ab2-891f-cccdbc2b0d0c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440041003600320046003000300041002d0041003000350034002d0034004600420032002d0038004600370033002d003100370031004100370034003900360045003500360036007d000000</data>\n\t\t\t\t<asString>{.D.A.6.2.F.0.0.A.-.A.0.5.4.-.4.F.B.2.-.8.F.7.3.-.1.7.1.A.7.4.9.6.E.5.6.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776379</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6f3f53ac-3323-445c-9236-0794fb401551}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440042004300410038003200380035002d0035003400330042002d0034003000330035002d0042003900330035002d004200390039004500320033003100350037003500360031007d000000</data>\n\t\t\t\t<asString>{.D.B.C.A.8.2.8.5.-.5.4.3.B.-.4.0.3.5.-.B.9.3.5.-.B.9.9.E.2.3.1.5.7.5.6.1.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776380</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{02438bea-ea89-467b-95c8-818ba1d1c792}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300039003200340033003100330033002d0033004400350041002d0034004500340034002d0041003800310041002d003700440030003100330034004300300031003800440030007d000000</data>\n\t\t\t\t<asString>{.0.9.2.4.3.1.3.3.-.3.D.5.A.-.4.E.4.4.-.A.8.1.A.-.7.D.0.1.3.4.C.0.1.8.D.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776381</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{86b5cc90-9f68-470a-b4ea-a0649192dc04}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330033003100430046004600440038002d0046003100320041002d0034004200410044002d0041004200410043002d004100410039004100300035003500460041003800370037007d000000</data>\n\t\t\t\t<asString>{.3.3.1.C.F.F.D.8.-.F.1.2.A.-.4.B.A.D.-.A.B.A.C.-.A.A.9.A.0.5.5.F.A.8.7.7.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776382</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c7e71c4d-4300-492f-9531-78b23a4270af}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340034003100360030004200370037002d0042003100340043002d0034003100380042002d0041004600420037002d003500350034004200330032003900420034003600310041007d000000</data>\n\t\t\t\t<asString>{.4.4.1.6.0.B.7.7.-.B.1.4.C.-.4.1.8.B.-.A.F.B.7.-.5.5.4.B.3.2.9.B.4.6.1.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776383</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ba1eb0dc-09b8-4985-9a99-40696b5eb363}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300038004600420044003100370037002d0046003100330033002d0034003500390036002d0042003800380037002d003200430042004600420042003900440044003300420032007d000000</data>\n\t\t\t\t<asString>{.0.8.F.B.D.1.7.7.-.F.1.3.3.-.4.5.9.6.-.B.8.8.7.-.2.C.B.F.B.B.9.D.D.3.B.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776384</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{bdfe501c-4d70-448d-939f-01ee41bd1d51}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440039004100370033003800330034002d0038004100310037002d0034004400370043002d0042003600460034002d003500330038004300350032003000450033004100440036007d000000</data>\n\t\t\t\t<asString>{.D.9.A.7.3.8.3.4.-.8.A.1.7.-.4.D.7.C.-.B.6.F.4.-.5.3.8.C.5.2.0.E.3.A.D.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776385</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{84f429fe-9e92-4f64-9e85-1638507af4bb}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430042004300370037003300320035002d0044003300420032002d0034003300350032002d0039004300380043002d004300350034003300330036003800460032003100330030007d000000</data>\n\t\t\t\t<asString>{.C.B.C.7.7.3.2.5.-.D.3.B.2.-.4.3.5.2.-.9.C.8.C.-.C.5.4.3.3.6.8.F.2.1.3.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776386</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c517f12a-4314-4b91-a3e3-cffa9ba1151c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360032004300430045004500330042002d0035003800300030002d0034004500430036002d0038003200450041002d003700330035003300330030004400320033004100370041007d000000</data>\n\t\t\t\t<asString>{.6.2.C.C.E.E.3.B.-.5.8.0.0.-.4.E.C.6.-.8.2.E.A.-.7.3.5.3.3.0.D.2.3.A.7.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776387</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4e4daac0-5ff3-4fd0-b89b-8515c76d2b39}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350035004100360038003800460033002d0037004300410032002d0034004300330038002d0042004600300035002d004200350035004300340042003900390041004500330030007d000000</data>\n\t\t\t\t<asString>{.5.5.A.6.8.8.F.3.-.7.C.A.2.-.4.C.3.8.-.B.F.0.5.-.B.5.5.C.4.B.9.9.A.E.3.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776388</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2cbac533-c29f-4914-9c3d-39c8c547a017}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440038003800330041003700450039002d0037003600420031002d0034003000350041002d0042003900380034002d003800430033003600360032003200450033004600310036007d000000</data>\n\t\t\t\t<asString>{.D.8.8.3.A.7.E.9.-.7.6.B.1.-.4.0.5.A.-.B.9.8.4.-.8.C.3.6.6.2.2.E.3.F.1.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776389</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b09b0efc-578d-48b1-ab44-ad43ae7e0180}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300042004200300036003800340038002d0031004100450035002d0034004600310041002d0042003100310041002d004500380030003600360035003900420041003900370037007d000000</data>\n\t\t\t\t<asString>{.0.B.B.0.6.8.4.8.-.1.A.E.5.-.4.F.1.A.-.B.1.1.A.-.E.8.0.6.6.5.9.B.A.9.7.7.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776390</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{df4b6bcf-364f-4b59-be2e-708a2cf34736}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440032003200380042003800430043002d0037003700320043002d0034003000420046002d0041004100460046002d003700370042003600360031003500450039003300310033007d000000</data>\n\t\t\t\t<asString>{.D.2.2.8.B.8.C.C.-.7.7.2.C.-.4.0.B.F.-.A.A.F.F.-.7.7.B.6.6.1.5.E.9.3.1.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776391</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f1e8ead7-7365-4b62-98e0-07d8c7a70f69}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440032003400340033003300320041002d0038003100320044002d0034004600350045002d0039004300390045002d004400330035004500300032003100300044003900450034007d000000</data>\n\t\t\t\t<asString>{.D.2.4.4.3.3.2.A.-.8.1.2.D.-.4.F.5.E.-.9.C.9.E.-.D.3.5.E.0.2.1.0.D.9.E.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776392</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{54c215ee-3737-4395-b870-3c39a92d6e14}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00380034003900460036003100310038002d0037003000430038002d0034003100370036002d0039004300450033002d004100390037003600320042004100300034003500460034007d000000</data>\n\t\t\t\t<asString>{.8.4.9.F.6.1.1.8.-.7.0.C.8.-.4.1.7.6.-.9.C.E.3.-.A.9.7.6.2.B.A.0.4.5.F.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776393</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{dc9e7dac-335e-4ac9-86c7-4ec827dfa623}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360039003000390044004400360038002d0030004200390034002d0034003400330038002d0042003200450034002d003000450043003000450043003500340039004400430035007d000000</data>\n\t\t\t\t<asString>{.6.9.0.9.D.D.6.8.-.0.B.9.4.-.4.4.3.8.-.B.2.E.4.-.0.E.C.0.E.C.5.4.9.D.C.5.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776394</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e34c6afe-4306-4659-93f3-4d97ec7172c6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410046004500320030003100380033002d0035003900310031002d0034003900380042002d0038004200320030002d003500420031004100440032003400430044003200330031007d000000</data>\n\t\t\t\t<asString>{.A.F.E.2.0.1.8.3.-.5.9.1.1.-.4.9.8.B.-.8.B.2.0.-.5.B.1.A.D.2.4.C.D.2.3.1.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776395</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f2910211-63cc-46f9-b8e7-cd75d195b804}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330038004300450046003000410033002d0039004100310032002d0034004400310042002d0042003400430046002d003200460043003300330041003500350031003500380046007d000000</data>\n\t\t\t\t<asString>{.3.8.C.E.F.0.A.3.-.9.A.1.2.-.4.D.1.B.-.B.4.C.F.-.2.F.C.3.3.A.5.5.1.5.8.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776396</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{34d3c4b0-f3dd-408d-8f06-aef15eb33e99}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300039003000310043004600320035002d0031003600430030002d0034004200360034002d0039003000390032002d003000390039003400370034004300350044003000450042007d000000</data>\n\t\t\t\t<asString>{.0.9.0.1.C.F.2.5.-.1.6.C.0.-.4.B.6.4.-.9.0.9.2.-.0.9.9.4.7.4.C.5.D.0.E.B.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776397</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6256af2d-05dd-4bbd-81b0-b65cf3505cc7}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350035003600300039003000390031002d0033004600350043002d0034003500410031002d0041004600420038002d004500340032003300460046003700350043004200300035007d000000</data>\n\t\t\t\t<asString>{.5.5.6.0.9.0.9.1.-.3.F.5.C.-.4.5.A.1.-.A.F.B.8.-.E.4.2.3.F.F.7.5.C.B.0.5.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776398</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{b656da4a-de0d-4d0e-8f93-4273211ec8de}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300032004400390038003000390036002d0039004100380031002d0034004600370034002d0042003900310046002d004600300042004400450030004400430034003100460041007d000000</data>\n\t\t\t\t<asString>{.0.2.D.9.8.0.9.6.-.9.A.8.1.-.4.F.7.4.-.B.9.1.F.-.F.0.B.D.E.0.D.C.4.1.F.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776399</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{db9854c8-9f5a-4731-a881-ac02fa59715d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00360032003500460030003500450038002d0045003000360046002d0034003500460035002d0042003300380036002d003700330044003000430043003500320034004100440041007d000000</data>\n\t\t\t\t<asString>{.6.2.5.F.0.5.E.8.-.E.0.6.F.-.4.5.F.5.-.B.3.8.6.-.7.3.D.0.C.C.5.2.4.A.D.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776400</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{278afac0-96f3-483f-b065-daf09e88e006}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00380030003000460046003400330045002d0035004400320030002d0034004100320034002d0041003600450045002d003000450033004200320035003600320038003600310030007d000000</data>\n\t\t\t\t<asString>{.8.0.0.F.F.4.3.E.-.5.D.2.0.-.4.A.2.4.-.A.6.E.E.-.0.E.3.B.2.5.6.2.8.6.1.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776401</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{83ff194c-2394-4712-bf17-d5ec5c46f605}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300032003100390031003700360042002d0037004300340030002d0034003400320043002d0042003000370033002d003400450045003600450042004300300032004100300043007d000000</data>\n\t\t\t\t<asString>{.0.2.1.9.1.7.6.B.-.7.C.4.0.-.4.4.2.C.-.B.0.7.3.-.4.E.E.6.E.B.C.0.2.A.0.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776402</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d44012ee-bfc1-40ec-8efe-d82a7572b0f4}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410037004100310046003400340031002d0030003800360031002d0034003500320036002d0041004300310039002d004300300045004600410039003100330033003300430034007d000000</data>\n\t\t\t\t<asString>{.A.7.A.1.F.4.4.1.-.0.8.6.1.-.4.5.2.6.-.A.C.1.9.-.C.0.E.F.A.9.1.3.3.3.C.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776403</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6cc13dd8-dd41-4153-9f2c-b73d772dbef3}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300030003600360030003200300039002d0039003000340039002d0034004300450033002d0038003100450030002d004200320039004300300031004400310035003900460043007d000000</data>\n\t\t\t\t<asString>{.0.0.6.6.0.2.0.9.-.9.0.4.9.-.4.C.E.3.-.8.1.E.0.-.B.2.9.C.0.1.D.1.5.9.F.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776404</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ff24c069-f535-479a-8c11-f081dd0ac319}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320033003600450033003900320033002d0039003200320032002d0034003000330035002d0038003500410046002d003100390031003100410035004200380042003900340035007d000000</data>\n\t\t\t\t<asString>{.2.3.6.E.3.9.2.3.-.9.2.2.2.-.4.0.3.5.-.8.5.A.F.-.1.9.1.1.A.5.B.8.B.9.4.5.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776405</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4d5c2e53-a292-49ca-a085-a5576bb43cbf}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310031004600430030003200420045002d0030004100410037002d0034003300330043002d0041003700430033002d004500310046004100360037004200340046004300410034007d000000</data>\n\t\t\t\t<asString>{.1.1.F.C.0.2.B.E.-.0.A.A.7.-.4.3.3.C.-.A.7.C.3.-.E.1.F.A.6.7.B.4.F.C.A.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776406</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{10fff4e2-b1f1-4ad9-8621-d8312897f70d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370035003500380031004100380039002d0030003600300032002d0034004300380044002d0038003000310030002d003600440044003300340036003100440035003500330045007d000000</data>\n\t\t\t\t<asString>{.7.5.5.8.1.A.8.9.-.0.6.0.2.-.4.C.8.D.-.8.0.1.0.-.6.D.D.3.4.6.1.D.5.5.3.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776407</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{368c1f37-db34-4e36-ae3e-1a894777a379}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440043004600330045003900310032002d0036003600390035002d0034004100430039002d0038004100430039002d003700390033003300340038003200430039003400330037007d000000</data>\n\t\t\t\t<asString>{.D.C.F.3.E.9.1.2.-.6.6.9.5.-.4.A.C.9.-.8.A.C.9.-.7.9.3.3.4.8.2.C.9.4.3.7.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776408</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{488dae1d-fa1e-404f-a365-32b5f9a97209}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430033003600420031003000370036002d0034003700450043002d0034004200450045002d0039003500300037002d004500300035004500330041003400360036004300340045007d000000</data>\n\t\t\t\t<asString>{.C.3.6.B.1.0.7.6.-.4.7.E.C.-.4.B.E.E.-.9.5.0.7.-.E.0.5.E.3.A.4.6.6.C.4.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776411</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6f8faa8d-e741-4380-a25e-079570bee209}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430038003300330037003200310044002d0039003500300034002d0034004400310041002d0039003900340042002d004500360036003300380043004200320041003500370045007d000000</data>\n\t\t\t\t<asString>{.C.8.3.3.7.2.1.D.-.9.5.0.4.-.4.D.1.A.-.9.9.4.B.-.E.6.6.3.8.C.B.2.A.5.7.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776412</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7252f45c-99e4-4b10-a885-6e89864ddbdf}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440030004400460045003600420034002d0037003700350042002d0034003200360037002d0041003300340035002d003700390033004300440034003300340043003900410041007d000000</data>\n\t\t\t\t<asString>{.D.0.D.F.E.6.B.4.-.7.7.5.B.-.4.2.6.7.-.A.3.4.5.-.7.9.3.C.D.4.3.4.C.9.A.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776413</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{cc263db7-a803-4ddc-915b-c28786aa1106}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430042003200430043004500370033002d0033003300380045002d0034003400410045002d0038003600350044002d003100370039003400420041004100460039003300430044007d000000</data>\n\t\t\t\t<asString>{.C.B.2.C.C.E.7.3.-.3.3.8.E.-.4.4.A.E.-.8.6.5.D.-.1.7.9.4.B.A.A.F.9.3.C.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776414</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{41d435c4-374c-4379-81c5-e77b5ac3b000}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340034004500450037003200430034002d0032003300450035002d0034004100340030002d0042003900340033002d003900310044004300450036003000310043003600420045007d000000</data>\n\t\t\t\t<asString>{.4.4.E.E.7.2.C.4.-.2.3.E.5.-.4.A.4.0.-.B.9.4.3.-.9.1.D.C.E.6.0.1.C.6.B.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776415</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{61b04769-24ce-41d7-a0db-551604ba286c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300046003800460043003500310032002d0038003100410034002d0034003600410038002d0039003300390036002d004400440041004500420036004300350046004200370034007d000000</data>\n\t\t\t\t<asString>{.0.F.8.F.C.5.1.2.-.8.1.A.4.-.4.6.A.8.-.9.3.9.6.-.D.D.A.E.B.6.C.5.F.B.7.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776416</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ea99112d-7c47-468c-97a2-0f8d8b8d9434}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00420038004300450030003900440031002d0044003800390033002d0034003200340042002d0039003500370045002d003900360030004600350035004400460036003400370041007d000000</data>\n\t\t\t\t<asString>{.B.8.C.E.0.9.D.1.-.D.8.9.3.-.4.2.4.B.-.9.5.7.E.-.9.6.0.F.5.5.D.F.6.4.7.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776417</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{cce03e11-69e7-4526-b635-6c4d3d4d9e60}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320045003000320042003700450034002d0034004300320038002d0034004300460045002d0038003000360036002d003600350039003800440046003400410039003700300041007d000000</data>\n\t\t\t\t<asString>{.2.E.0.2.B.7.E.4.-.4.C.2.8.-.4.C.F.E.-.8.0.6.6.-.6.5.9.8.D.F.4.A.9.7.0.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776418</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9e93f20a-fa57-4f9e-a74e-b92fb120b2cd}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350035003100350042004500420044002d0031003600430043002d0034003800420037002d0042003500430044002d003000440036003200320038003900360035004300380032007d000000</data>\n\t\t\t\t<asString>{.5.5.1.5.B.E.B.D.-.1.6.C.C.-.4.8.B.7.-.B.5.C.D.-.0.D.6.2.2.8.9.6.5.C.8.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776419</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d7494c94-88e8-4e5e-9a7a-b5ceda82fff6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430034003600380031003400350034002d0036004200330038002d0034003700360037002d0038003500440045002d004600340037004400420039004500310046004600310039007d000000</data>\n\t\t\t\t<asString>{.C.4.6.8.1.4.5.4.-.6.B.3.8.-.4.7.6.7.-.8.5.D.E.-.F.4.7.D.B.9.E.1.F.F.1.9.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776420</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{39b3a2c0-9c09-4442-b2f2-43214a54b45a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450035004600460033003900460030002d0045004100370032002d0034003300440031002d0042004100410044002d003500390031003700330039004300330043003300380039007d000000</data>\n\t\t\t\t<asString>{.E.5.F.F.3.9.F.0.-.E.A.7.2.-.4.3.D.1.-.B.A.A.D.-.5.9.1.7.3.9.C.3.C.3.8.9.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776421</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{2baa143c-6dbe-49e8-9267-5cc0059ed12d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350044004600460036004500300030002d0044003800310041002d0034004300460035002d0041003300410034002d003800320045003600360033003600380036004100360041007d000000</data>\n\t\t\t\t<asString>{.5.D.F.F.6.E.0.0.-.D.8.1.A.-.4.C.F.5.-.A.3.A.4.-.8.2.E.6.6.3.6.8.6.A.6.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776422</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{26af65c1-8005-4cf0-ada0-9aa571a1365e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00380035003200380031004100330031002d0034004100420033002d0034003100310032002d0039004100390037002d004300430038003700390045003900430044003500440039007d000000</data>\n\t\t\t\t<asString>{.8.5.2.8.1.A.3.1.-.4.A.B.3.-.4.1.1.2.-.9.A.9.7.-.C.C.8.7.9.E.9.C.D.5.D.9.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776423</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ea23c737-f8b8-4a7d-ab55-3396e8d029f2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440043003500430044003200380046002d0039004300350044002d0034004300300042002d0041003100370043002d003100300045003800390030004200450037004100390043007d000000</data>\n\t\t\t\t<asString>{.D.C.5.C.D.2.8.F.-.9.C.5.D.-.4.C.0.B.-.A.1.7.C.-.1.0.E.8.9.0.B.E.7.A.9.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776424</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{bff5e1d1-5465-49b3-b3c6-c812334ae432}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370039004200450034003500330045002d0031003300340031002d0034004200320045002d0039003000460031002d004300370044003300300033003500350038003900450041007d000000</data>\n\t\t\t\t<asString>{.7.9.B.E.4.5.3.E.-.1.3.4.1.-.4.B.2.E.-.9.0.F.1.-.C.7.D.3.0.3.5.5.8.9.E.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776425</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a7a81b7f-2287-4d4a-b34e-eafa46a56fed}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410036004200430039004300340030002d0034003400390041002d0034003100340043002d0038003200310038002d003700390042004100330044004200410038003000390043007d000000</data>\n\t\t\t\t<asString>{.A.6.B.C.9.C.4.0.-.4.4.9.A.-.4.1.4.C.-.8.2.1.8.-.7.9.B.A.3.D.B.A.8.0.9.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776426</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0dfc39e6-df49-4ff4-ad33-a67704cd209b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00410041003400310039004300440038002d0033003800440030002d0034003800390036002d0039004200350030002d003100350046003600300037003700440032003600370032007d000000</data>\n\t\t\t\t<asString>{.A.A.4.1.9.C.D.8.-.3.8.D.0.-.4.8.9.6.-.9.B.5.0.-.1.5.F.6.0.7.7.D.2.6.7.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776427</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e014bc02-d4a9-413d-8213-199172a7df9e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330043003900350045003100460041002d0046004400370038002d0034004400320042002d0038004200430041002d003000420045004400420038004500460035003300350034007d000000</data>\n\t\t\t\t<asString>{.3.C.9.5.E.1.F.A.-.F.D.7.8.-.4.D.2.B.-.8.B.C.A.-.0.B.E.D.B.8.E.F.5.3.5.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776428</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{21f5906e-61ef-4d15-87b2-89f4786ec5d0}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300036003800450035004300340033002d0042003800390042002d0034003200350041002d0039003700430039002d003300310036003100390041003300410038004400440030007d000000</data>\n\t\t\t\t<asString>{.0.6.8.E.5.C.4.3.-.B.8.9.B.-.4.2.5.A.-.9.7.C.9.-.3.1.6.1.9.A.3.A.8.D.D.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776429</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a6088cfc-cd47-4787-b825-f9182c0e5bfe}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00380044003000430035004600310043002d0033003400440032002d0034003700450046002d0042004200340043002d003500330043004400350046003000300031003900310045007d000000</data>\n\t\t\t\t<asString>{.8.D.0.C.5.F.1.C.-.3.4.D.2.-.4.7.E.F.-.B.B.4.C.-.5.3.C.D.5.F.0.0.1.9.1.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776430</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{816e87d6-82f6-4a64-8f51-5ce17e19ce41}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350042003000460030004500440045002d0031003000430046002d0034003900440036002d0041003300440033002d003800360036004300320031003800420038003400300046007d000000</data>\n\t\t\t\t<asString>{.5.B.0.F.0.E.D.E.-.1.0.C.F.-.4.9.D.6.-.A.3.D.3.-.8.6.6.C.2.1.8.B.8.4.0.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776431</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ddb485c7-523d-473e-aa7c-006050a20609}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00460039003000410039003400460044002d0038003700390045002d0034004100380035002d0041003200300036002d004400320037004600360034003000330039003200350038007d000000</data>\n\t\t\t\t<asString>{.F.9.0.A.9.4.F.D.-.8.7.9.E.-.4.A.8.5.-.A.2.0.6.-.D.2.7.F.6.4.0.3.9.2.5.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776432</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{aab2b3fd-6d4d-4a30-8f5d-4562010bd49e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00420032003800410046003000450035002d0044003000420037002d0034003800420036002d0039004500300030002d003300430031003100320030004600430043004300460034007d000000</data>\n\t\t\t\t<asString>{.B.2.8.A.F.0.E.5.-.D.0.B.7.-.4.8.B.6.-.9.E.0.0.-.3.C.1.1.2.0.F.C.C.C.F.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776433</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{5f3612b3-d154-4a81-a87f-9812b69d879f}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320034003100380043004400430037002d0033003100410036002d0034003400310044002d0038004500390034002d003200430030003800310033003300430034003500340041007d000000</data>\n\t\t\t\t<asString>{.2.4.1.8.C.D.C.7.-.3.1.A.6.-.4.4.1.D.-.8.E.9.4.-.2.C.0.8.1.3.3.C.4.5.4.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776434</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{abb7f935-dc63-46d8-b66c-f0cc5c1e5280}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390033004200440033004100370031002d0031003000320036002d0034003600450031002d0041004100320032002d003700360030004100460035003500430038004200320034007d000000</data>\n\t\t\t\t<asString>{.9.3.B.D.3.A.7.1.-.1.0.2.6.-.4.6.E.1.-.A.A.2.2.-.7.6.0.A.F.5.5.C.8.B.2.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776435</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{54883c72-078c-4ac9-ba34-a84418454eca}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310046003100300039004300340033002d0035003900310038002d0034004600460043002d0039003600410030002d004600310039003900450033003500420043003200410032007d000000</data>\n\t\t\t\t<asString>{.1.F.1.0.9.C.4.3.-.5.9.1.8.-.4.F.F.C.-.9.6.A.0.-.F.1.9.9.E.3.5.B.C.2.A.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776436</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{70e256b2-922a-432a-9f93-0da28403e285}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310037004200340039003100450032002d0042004600310034002d0034004100380033002d0042003300450037002d004300390039004200390044003700390039003800340036007d000000</data>\n\t\t\t\t<asString>{.1.7.B.4.9.1.E.2.-.B.F.1.4.-.4.A.8.3.-.B.3.E.7.-.C.9.9.B.9.D.7.9.9.8.4.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776439</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{768024ef-bdcf-4652-87ba-6bab3d4c5188}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450039004500420045003000310038002d0041003000300034002d0034004100320030002d0039003400450036002d003500350036004600450030003400440038003600340044007d000000</data>\n\t\t\t\t<asString>{.E.9.E.B.E.0.1.8.-.A.0.0.4.-.4.A.2.0.-.9.4.E.6.-.5.5.6.F.E.0.4.D.8.6.4.D.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776440</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3b994b2a-f242-4c76-855c-03b815f2060b}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450038003900360042003900450042002d0037003900420041002d0034003700430043002d0039003000390045002d003800410038003900420039004200370044003200370037007d000000</data>\n\t\t\t\t<asString>{.E.8.9.6.B.9.E.B.-.7.9.B.A.-.4.7.C.C.-.9.0.9.E.-.8.A.8.9.B.9.B.7.D.2.7.7.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776441</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6df8b345-0230-43d9-8d8e-12dc278a5da6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300034003300330035004500380033002d0036004400330044002d0034003400380039002d0041003800420044002d003400360031004500300031003200390046004300450036007d000000</data>\n\t\t\t\t<asString>{.0.4.3.3.5.E.8.3.-.6.D.3.D.-.4.4.8.9.-.A.8.B.D.-.4.6.1.E.0.1.2.9.F.C.E.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776442</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f24769c1-3640-4f68-afde-76aa79179219}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340031004100320034003700320045002d0046004600440036002d0034003600450032002d0041003000330035002d004300430038004600450031003000300034004500410038007d000000</data>\n\t\t\t\t<asString>{.4.1.A.2.4.7.2.E.-.F.F.D.6.-.4.6.E.2.-.A.0.3.5.-.C.C.8.F.E.1.0.0.4.E.A.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776443</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{aefe901c-5a83-4e4c-9d5e-178ff2082943}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00380046003100310042003900390034002d0044003100390031002d0034003000340038002d0042003900430042002d003000460044003500380045003600330030003600390036007d000000</data>\n\t\t\t\t<asString>{.8.F.1.1.B.9.9.4.-.D.1.9.1.-.4.0.4.8.-.B.9.C.B.-.0.F.D.5.8.E.6.3.0.6.9.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776444</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{78518afb-c587-4564-a904-4e6be35bf900}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390044003400440034004500370032002d0038004600350044002d0034003000340041002d0039003400380036002d003400420035003400320039004600460035003800330031007d000000</data>\n\t\t\t\t<asString>{.9.D.4.D.4.E.7.2.-.8.F.5.D.-.4.0.4.A.-.9.4.8.6.-.4.B.5.4.2.9.F.F.5.8.3.1.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776445</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{95555d1b-c7d8-4915-b994-00260f75e514}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310038003400440030003600440041002d0044003100370037002d0034004600450045002d0041004300460032002d003900350042003700380032004100420035003900390046007d000000</data>\n\t\t\t\t<asString>{.1.8.4.D.0.6.D.A.-.D.1.7.7.-.4.F.E.E.-.A.C.F.2.-.9.5.B.7.8.2.A.B.5.9.9.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776446</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0b587fb8-2b5d-4186-84ca-ff54e76304fa}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00340046003200340043004200390039002d0034003900430038002d0034004300340036002d0038003200350042002d004400370031004100390037003800360043004200440034007d000000</data>\n\t\t\t\t<asString>{.4.F.2.4.C.B.9.9.-.4.9.C.8.-.4.C.4.6.-.8.2.5.B.-.D.7.1.A.9.7.8.6.C.B.D.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776447</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{805b81fa-6d7a-43a3-91c1-f13f1a1a9162}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450034004500380046003900330036002d0043004600380036002d0034003200410036002d0039003900450031002d003400370045004200390033003400380042003700420030007d000000</data>\n\t\t\t\t<asString>{.E.4.E.8.F.9.3.6.-.C.F.8.6.-.4.2.A.6.-.9.9.E.1.-.4.7.E.B.9.3.4.8.B.7.B.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776448</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{4069af0d-2fc4-448f-807f-9c6876d0a3ea}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390041003500440033003800450041002d0046003300350043002d0034003100380043002d0041003700310033002d003300340044003000360031004500360033003500420046007d000000</data>\n\t\t\t\t<asString>{.9.A.5.D.3.8.E.A.-.F.3.5.C.-.4.1.8.C.-.A.7.1.3.-.3.4.D.0.6.1.E.6.3.5.B.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776449</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{a5bfc811-4153-4f33-8718-d8f4522e2091}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390038003700360044003800450035002d0046003300310035002d0034004500460043002d0039004500440043002d003800420039003300410046003100360031004300330045007d000000</data>\n\t\t\t\t<asString>{.9.8.7.6.D.8.E.5.-.F.3.1.5.-.4.E.F.C.-.9.E.D.C.-.8.B.9.3.A.F.1.6.1.C.3.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776450</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{1a89d52d-bdc9-4413-bd14-8e6e834da99c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00350041003900440046004100340039002d0039004100350030002d0034003400450036002d0038004400460046002d004100460039003500450032004500430038004400390032007d000000</data>\n\t\t\t\t<asString>{.5.A.9.D.F.A.4.9.-.9.A.5.0.-.4.4.E.6.-.8.D.F.F.-.A.F.9.5.E.2.E.C.8.D.9.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776451</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{804b6c1e-62a6-440e-a4e1-45fd8949dce6}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430043004100300043003400320032002d0037003400310041002d0034004500350044002d0038004100300045002d003300360038003700350041004300440036003100420038007d000000</data>\n\t\t\t\t<asString>{.C.C.A.0.C.4.2.2.-.7.4.1.A.-.4.E.5.D.-.8.A.0.E.-.3.6.8.7.5.A.C.D.6.1.B.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776452</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c99679ae-a6f8-497d-b6eb-94821d27a44d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440038004600430033003500310035002d0043003200360037002d0034003700420042002d0039003700430045002d003900330032003000300035003800300043003600330045007d000000</data>\n\t\t\t\t<asString>{.D.8.F.C.3.5.1.5.-.C.2.6.7.-.4.7.B.B.-.9.7.C.E.-.9.3.2.0.0.5.8.0.C.6.3.E.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776453</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{221b7254-8807-42ab-bfa5-0cd2dbd0f0d5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440046003100340037003300440037002d0030003800330033002d0034003500300042002d0039003900310041002d003100420039003800380044003300300038004400360039007d000000</data>\n\t\t\t\t<asString>{.D.F.1.4.7.3.D.7.-.0.8.3.3.-.4.5.0.B.-.9.9.1.A.-.1.B.9.8.8.D.3.0.8.D.6.9.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776454</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{0f24b893-b964-4d88-8875-d462390251e5}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450038003900360034004100340044002d0045003800380046002d0034003400330043002d0042003600360046002d004300420037003000450039003700410036004200380038007d000000</data>\n\t\t\t\t<asString>{.E.8.9.6.4.A.4.D.-.E.8.8.F.-.4.4.3.C.-.B.6.6.F.-.C.B.7.0.E.9.7.A.6.B.8.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776455</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c8e8b63f-05ac-4b2c-858a-d3b66b9bca94}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300038003400420039004500320036002d0046003900320046002d0034003100350039002d0042003700370043002d003000460046003900410032003600360046004400390041007d000000</data>\n\t\t\t\t<asString>{.0.8.4.B.9.E.2.6.-.F.9.2.F.-.4.1.5.9.-.B.7.7.C.-.0.F.F.9.A.2.6.6.F.D.9.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776456</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{934834f5-e0a5-441b-85c2-73fd9be9463f}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370045004600430031003900320033002d0038003000460042002d0034003900440046002d0042003000430033002d004100350033004400430038003800450033004300430030007d000000</data>\n\t\t\t\t<asString>{.7.E.F.C.1.9.2.3.-.8.0.F.B.-.4.9.D.F.-.B.0.C.3.-.A.5.3.D.C.8.8.E.3.C.C.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776457</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f0e85dc1-2a2a-4fc0-b501-a30cbac74a8e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450044004200330043004400310045002d0042004600370041002d0034003500440036002d0041003800390034002d003300340046003300360039003400370034003400380041007d000000</data>\n\t\t\t\t<asString>{.E.D.B.3.C.D.1.E.-.B.F.7.A.-.4.5.D.6.-.A.8.9.4.-.3.4.F.3.6.9.4.7.4.4.8.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776458</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{09a98b8a-115e-495c-836b-42b475630183}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00450030004400420042004100410031002d0043004200330035002d0034003100450037002d0039003900350043002d003300370041004200360043003500380035003400300038007d000000</data>\n\t\t\t\t<asString>{.E.0.D.B.B.A.A.1.-.C.B.3.5.-.4.1.E.7.-.9.9.5.C.-.3.7.A.B.6.C.5.8.5.4.0.8.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776461</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{400124d1-e3bc-4c21-84f1-9c2fdd660eaa}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00390031003000440039003100450031002d0032003900320038002d0034003600420032002d0038003600450046002d003600410045003100460032004400380045003200410043007d000000</data>\n\t\t\t\t<asString>{.9.1.0.D.9.1.E.1.-.2.9.2.8.-.4.6.B.2.-.8.6.E.F.-.6.A.E.1.F.2.D.8.E.2.A.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776462</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{f9f5ba6c-d936-4b6f-9503-aa2fc28d2bb8}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440046004400410045004600310031002d0046004100420043002d0034003400460031002d0039003400450036002d003300440043003600320035003800460038003500420036007d000000</data>\n\t\t\t\t<asString>{.D.F.D.A.E.F.1.1.-.F.A.B.C.-.4.4.F.1.-.9.4.E.6.-.3.D.C.6.2.5.8.F.8.5.B.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776463</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{fbb9b711-0218-4bd3-bc24-5f88cdd9fcec}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310034003400450038003900370032002d0030004500310030002d0034003600350033002d0038004400440032002d003600420031003400350038003000440046004600300046007d000000</data>\n\t\t\t\t<asString>{.1.4.4.E.8.9.7.2.-.0.E.1.0.-.4.6.5.3.-.8.D.D.2.-.6.B.1.4.5.8.0.D.F.F.0.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776464</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{60847319-40c2-4c6b-9b63-67b1fdef219d}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00300043003000420030003500410046002d0046003100450043002d0034003000310039002d0038004400340032002d004300350034004400350044004400340031004500420041007d000000</data>\n\t\t\t\t<asString>{.0.C.0.B.0.5.A.F.-.F.1.E.C.-.4.0.1.9.-.8.D.4.2.-.C.5.4.D.5.D.D.4.1.E.B.A.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776467</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6b9eebdb-a4d1-451c-9830-de157ab09a0a}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00430045004300380041003000420044002d0042004500320041002d0034003900440034002d0038004200310044002d004400440032003900340035004300440039003300440046007d000000</data>\n\t\t\t\t<asString>{.C.E.C.8.A.0.B.D.-.B.E.2.A.-.4.9.D.4.-.8.B.1.D.-.D.D.2.9.4.5.C.D.9.3.D.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776468</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3e440dea-e76d-48aa-b372-560e409b30f1}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>49005000730065006300200041006400640072006500730073002000490073006f006c006100740069006f006e00200066006f0072002000530065006300750072006500200043006f006e005300650063002000520075006c00650073000000</data>\n\t\t\t\t<asString>I.P.s.e.c. .A.d.d.r.e.s.s. .I.s.o.l.a.t.i.o.n. .f.o.r. .S.e.c.u.r.e. .C.o.n.S.e.c. .R.u.l.e.s...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776481</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{9d6ea685-ea31-45e1-b8da-a022482c5663}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>49005000730065006300200041006400640072006500730073002000490073006f006c006100740069006f006e00200066006f0072002000530065006300750072006500200043006f006e005300650063002000520075006c00650073000000</data>\n\t\t\t\t<asString>I.P.s.e.c. .A.d.d.r.e.s.s. .I.s.o.l.a.t.i.o.n. .f.o.r. .S.e.c.u.r.e. .C.o.n.S.e.c. .R.u.l.e.s...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776482</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e6cbde25-ce3a-4f6c-ad20-2430fc3be2ec}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>49005000730065006300200041006400640072006500730073002000490073006f006c006100740069006f006e00200066006f0072002000530065006300750072006500200043006f006e005300650063002000520075006c00650073000000</data>\n\t\t\t\t<asString>I.P.s.e.c. .A.d.d.r.e.s.s. .I.s.o.l.a.t.i.o.n. .f.o.r. .S.e.c.u.r.e. .C.o.n.S.e.c. .R.u.l.e.s...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776483</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d67aa0d4-e024-4a5e-b849-9b0a4411f2c7}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>49005000730065006300200041006400640072006500730073002000490073006f006c006100740069006f006e00200066006f0072002000530065006300750072006500200043006f006e005300650063002000520075006c00650073000000</data>\n\t\t\t\t<asString>I.P.s.e.c. .A.d.d.r.e.s.s. .I.s.o.l.a.t.i.o.n. .f.o.r. .S.e.c.u.r.e. .C.o.n.S.e.c. .R.u.l.e.s...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776484</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{e7d69b11-d4ea-4140-afc1-3bd5e7bc77d3}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>49005000730065006300200041006400640072006500730073002000490073006f006c006100740069006f006e00200066006f0072002000530065006300750072006500200043006f006e005300650063002000520075006c00650073000000</data>\n\t\t\t\t<asString>I.P.s.e.c. .A.d.d.r.e.s.s. .I.s.o.l.a.t.i.o.n. .f.o.r. .S.e.c.u.r.e. .C.o.n.S.e.c. .R.u.l.e.s...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776485</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d4108881-9c33-48bd-9ba2-da4340a6d656}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>49005000730065006300200041006400640072006500730073002000490073006f006c006100740069006f006e00200066006f0072002000530065006300750072006500200043006f006e005300650063002000520075006c00650073000000</data>\n\t\t\t\t<asString>I.P.s.e.c. .A.d.d.r.e.s.s. .I.s.o.l.a.t.i.o.n. .f.o.r. .S.e.c.u.r.e. .C.o.n.S.e.c. .R.u.l.e.s...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776486</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{321945bf-7e0d-4d0b-ba60-4c35526d1059}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00370034003000390038003700450033002d0038004200460039002d0034003000330033002d0038004400330032002d004200440030003200340036003900430035003500360032007d000000</data>\n\t\t\t\t<asString>{.7.4.0.9.8.7.E.3.-.8.B.F.9.-.4.0.3.3.-.8.D.3.2.-.B.D.0.2.4.6.9.C.5.5.6.2.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776489</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{fd7430b7-c11f-4981-beb4-57061db06e47}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310033004400310037003200340045002d0043003100300041002d0034004200360044002d0042003000300039002d003900370033004600320032003600440043004400340046007d000000</data>\n\t\t\t\t<asString>{.1.3.D.1.7.2.4.E.-.C.1.0.A.-.4.B.6.D.-.B.0.0.9.-.9.7.3.F.2.2.6.D.C.D.4.F.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776490</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{3576462a-269e-4a46-9f90-72d5b7c9c10e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c006400650064002000490043004d00500020007600340020004f00750074000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .I.C.M.P. .v.4. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776491</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{5848fa86-7a5a-4193-9e0b-e6a3e69395f8}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c006400650064002000490043004d00500020007600360020004f00750074000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .I.C.M.P. .v.6. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776492</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{8ab03769-319b-4d2e-81dd-8edc91cbbb8c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c006400650064002000490043004d00500020007600340020004f00750074000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .I.C.M.P. .v.4. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776493</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{302e8ae9-db45-4f11-bf3d-20e0807f3804}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c006400650064002000490043004d00500020007600360020004f00750074000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .I.C.M.P. .v.6. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776494</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{aa4a4221-6f16-4b9c-9a07-b4b4ba6a6bf2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c006400650064002000490043004d00500020007600340020004f00750074000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .I.C.M.P. .v.4. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776495</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{11a26e34-bc51-40d3-b421-822ad6efbb3e}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>53006800690065006c006400650064002000490043004d00500020007600360020004f00750074000000</data>\n\t\t\t\t<asString>S.h.i.e.l.d.e.d. .I.C.M.P. .v.6. .O.u.t...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776496</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{7b4bd8fd-5d1f-4b8c-9836-4a01a350e746}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00320033004300340039003900450031002d0043003700360042002d0034003700300035002d0041003700310031002d004400450041004400360032004300380033003800440033007d000000</data>\n\t\t\t\t<asString>{.2.3.C.4.9.9.E.1.-.C.7.6.B.-.4.7.0.5.-.A.7.1.1.-.D.E.A.D.6.2.C.8.3.8.D.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776497</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ab88322b-f465-4441-9345-715826fcab31}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00420045003800300036004300350034002d0041003800410046002d0034003200330043002d0039004500350036002d004300350041003800300033004600450041003300310033007d000000</data>\n\t\t\t\t<asString>{.B.E.8.0.6.C.5.4.-.A.8.A.F.-.4.2.3.C.-.9.E.5.6.-.C.5.A.8.0.3.F.E.A.3.1.3.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776498</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{d6011340-9eba-4253-9ed0-a763c7ef7b6c}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00310042004100420031003400360035002d0034003000430045002d0034003500390039002d0039004500420032002d003200340035003600440030004600420041003300330043007d000000</data>\n\t\t\t\t<asString>{.1.B.A.B.1.4.6.5.-.4.0.C.E.-.4.5.9.9.-.9.E.B.2.-.2.4.5.6.D.0.F.B.A.3.3.C.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776499</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{6186f5b6-f4b7-414d-ba20-a82103204847}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00440031003000440041003000340039002d0041004500340035002d0034003200370032002d0039003900450032002d004600370046003800350035003200450046003700420030007d000000</data>\n\t\t\t\t<asString>{.D.1.0.D.A.0.4.9.-.A.E.4.5.-.4.2.7.2.-.9.9.E.2.-.F.7.F.8.5.5.2.E.F.7.B.0.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776500</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{c4f20cf5-f405-49a7-b6a4-97b66f9cf587}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00420041004500420032003100440043002d0039003100330043002d0034004100300037002d0039004400440042002d004400320034003400360041003400390041003200360036007d000000</data>\n\t\t\t\t<asString>{.B.A.E.B.2.1.D.C.-.9.1.3.C.-.4.A.0.7.-.9.D.D.B.-.D.2.4.4.6.A.4.9.A.2.6.6.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776501</providerContextId>\n\t\t</item>\n\t\t<item>\n\t\t\t<providerContextKey>{ba22195c-728b-4815-be61-4a4f69743fe2}</providerContextKey>\n\t\t\t<displayData>\n\t\t\t\t<name>MPSSVC</name>\n\t\t\t\t<description>Stores filter origin</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<type>FWPM_GENERAL_CONTEXT</type>\n\t\t\t<dataBuffer>\n\t\t\t\t<data>7b00330030003600350032004100450030002d0035003300320031002d0034003200390033002d0041004100430042002d003200440045003300300042004500360033003600340034007d000000</data>\n\t\t\t\t<asString>{.3.0.6.5.2.A.E.0.-.5.3.2.1.-.4.2.9.3.-.A.A.C.B.-.2.D.E.3.0.B.E.6.3.6.4.4.}...</asString>\n\t\t\t</dataBuffer>\n\t\t\t<providerContextId>9223372036854776502</providerContextId>\n\t\t</item>\n\t</providerContexts>\n\t<subLayers numItems=\"22\">\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_INSPECTION</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in Inspection Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>0</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_TEREDO</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in Edge Traversal Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>1</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WF</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in MPSSVC Windows Firewall Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WF</providerKey>\n\t\t\t<providerData/>\n\t\t\t<weight>2</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_WSH</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in MPSSVC Windows Service Hardening Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t<providerData/>\n\t\t\t<weight>3</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_QUARANTINE</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in MPSSVC Quarantine Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_WSH</providerKey>\n\t\t\t<providerData/>\n\t\t\t<weight>4</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_EDP</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in MPSSVC Enterprise Data Protection Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_EDP</providerKey>\n\t\t\t<providerData/>\n\t\t\t<weight>5</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_TENANT_RESTRICTIONS</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in MPSSVC Tenant Restrictions Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_TENANT_RESTRICTIONS</providerKey>\n\t\t\t<providerData/>\n\t\t\t<weight>6</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_MPSSVC_APP_ISOLATION</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in MPSSVC App Isolation Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey>FWPM_PROVIDER_MPSSVC_APP_ISOLATION</providerKey>\n\t\t\t<providerData/>\n\t\t\t<weight>7</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>{7b6b11f6-cbb5-433c-ae06-6a4f0076e49e}</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Edge traversal Teredo Authorization Sublayer</name>\n\t\t\t\t<description>Edge traversal Teredo Authorization Sublayer</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>8</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>{3c1cd879-1b8c-4ab4-8f83-5ed129176ef3}</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>windefend</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>4096</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_TCP_CHIMNEY_OFFLOAD</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in TCP Chimney Offload Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>8192</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_TCP_TEMPLATES</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in TCP Templates Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>8704</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_IPSEC_SECURITY_REALM</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in IPsec Security Realm Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>12288</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_SECURE_SOCKET</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in Secure Socket Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>16384</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_LIPS</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in Legacy IPsec Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>32767</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_UNIVERSAL</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in Universal Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>32768</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_IPSEC_DOSP</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in IPsec DoS Protection Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>34816</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in IPsec Forward Outbound Tunnel Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>36864</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_IPSEC_TUNNEL</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>WFP Built-in IPsec Tunnel Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>40960</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>{9ba30013-c84e-47e5-ac6e-1e1aed72fa69}</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>Microsoft Corporation</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags numItems=\"1\">\n\t\t\t\t<item>FWPM_SUBLAYER_FLAG_PERSISTENT</item>\n\t\t\t</flags>\n\t\t\t<providerKey>{1bebc969-61a5-4732-a177-847a0817862a}</providerKey>\n\t\t\t<providerData/>\n\t\t\t<weight>40961</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>FWPM_SUBLAYER_RPC_AUDIT</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>RPC Built-in Audit Sublayer</name>\n\t\t\t\t<description/>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>49152</weight>\n\t\t</item>\n\t\t<item>\n\t\t\t<subLayerKey>{a87fb472-fc68-4805-8559-c6ae774773e0}</subLayerKey>\n\t\t\t<displayData>\n\t\t\t\t<name>PortmasterSublayer</name>\n\t\t\t\t<description>The Portmaster sublayer holds all it's filters.</description>\n\t\t\t</displayData>\n\t\t\t<flags/>\n\t\t\t<providerKey/>\n\t\t\t<providerData/>\n\t\t\t<weight>65535</weight>\n\t\t</item>\n\t</subLayers>\n</wfpstate>`)\n"
  },
  {
    "path": "service/config.go",
    "content": "package service\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/configure\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype ServiceConfig struct {\n\tBinDir  string\n\tDataDir string\n\n\tLogToStdout bool\n\tLogDir      string\n\tLogLevel    string\n\n\tBinariesIndexURLs   []string\n\tIntelIndexURLs      []string\n\tVerifyBinaryUpdates jess.TrustStore\n\tVerifyIntelUpdates  jess.TrustStore\n}\n\nfunc (sc *ServiceConfig) Init() error {\n\t// Check directories.\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\t// Fall back to defaults.\n\t\tif sc.BinDir == \"\" {\n\t\t\texeDir, err := getCurrentBinaryFolder() // Default: C:/Program Files/Portmaster\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"derive bin dir from running exe: %w\", err)\n\t\t\t}\n\t\t\tsc.BinDir = exeDir\n\t\t}\n\t\tif sc.DataDir == \"\" {\n\t\t\tsc.DataDir = filepath.FromSlash(\"$ProgramData/Portmaster\")\n\t\t}\n\t\tif sc.LogDir == \"\" {\n\t\t\tsc.LogDir = filepath.Join(sc.DataDir, \"logs\")\n\t\t}\n\n\tcase \"linux\":\n\t\t// Fall back to defaults.\n\t\tif sc.BinDir == \"\" {\n\t\t\tsc.BinDir = \"/usr/lib/portmaster\"\n\t\t}\n\t\tif sc.DataDir == \"\" {\n\t\t\tsc.DataDir = \"/var/lib/portmaster\"\n\t\t}\n\t\tif sc.LogDir == \"\" {\n\t\t\tsc.LogDir = \"/var/log/portmaster\"\n\t\t}\n\n\tdefault:\n\t\t// Fail if not configured on other platforms.\n\t\tif sc.BinDir == \"\" {\n\t\t\treturn errors.New(\"binary directory must be configured - auto-detection not supported on this platform\")\n\t\t}\n\t\tif sc.DataDir == \"\" {\n\t\t\treturn errors.New(\"binary directory must be configured - auto-detection not supported on this platform\")\n\t\t}\n\t\tif !sc.LogToStdout && sc.LogDir == \"\" {\n\t\t\treturn errors.New(\"logging directory must be configured - auto-detection not supported on this platform\")\n\t\t}\n\t}\n\n\t// Expand path variables.\n\tsc.BinDir = os.ExpandEnv(sc.BinDir)\n\tsc.DataDir = os.ExpandEnv(sc.DataDir)\n\tsc.LogDir = os.ExpandEnv(sc.LogDir)\n\n\t// Apply defaults for required fields.\n\tif len(sc.BinariesIndexURLs) == 0 {\n\t\tsc.BinariesIndexURLs = configure.DefaultStableBinaryIndexURLs\n\t}\n\tif len(sc.IntelIndexURLs) == 0 {\n\t\tsc.IntelIndexURLs = configure.DefaultIntelIndexURLs\n\t}\n\n\t// Check log level.\n\tif sc.LogLevel != \"\" && log.ParseLevel(sc.LogLevel) == 0 {\n\t\treturn fmt.Errorf(\"invalid log level %q\", sc.LogLevel)\n\t}\n\n\treturn nil\n}\n\n// returns the absolute path of the currently running executable\nfunc getCurrentBinaryPath() (string, error) {\n\t// Get the path of the currently running executable\n\texePath, err := os.Executable()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to get executable path: %w\", err)\n\t}\n\n\t// Get the absolute path\n\tabsPath, err := filepath.Abs(exePath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to get absolute path: %w\", err)\n\t}\n\n\treturn absPath, nil\n}\n\nfunc getCurrentBinaryFolder() (string, error) {\n\t// Get the absolute path of the currently running executable\n\tabsPath, err := getCurrentBinaryPath()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Get the directory of the executable\n\tinstallDir := filepath.Dir(absPath)\n\n\treturn installDir, nil\n}\n\nfunc MakeUpdateConfigs(svcCfg *ServiceConfig) (binaryUpdateConfig, intelUpdateConfig *updates.Config, err error) {\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\tbinaryUpdateConfig = &updates.Config{\n\t\t\tName:              configure.DefaultBinaryIndexName,\n\t\t\tDirectory:         svcCfg.BinDir,\n\t\t\tDownloadDirectory: filepath.Join(svcCfg.DataDir, \"download_binaries\"),\n\t\t\tPurgeDirectory:    filepath.Join(svcCfg.BinDir, \"upgrade_obsolete_binaries\"),\n\t\t\tIgnore:            []string{\"uninstall.exe\"}, // \"databases\", \"intel\" and \"config.json\" not needed here since they are not in the bin dir.\n\t\t\tIndexURLs:         svcCfg.BinariesIndexURLs,  // May be changed by config during instance startup.\n\t\t\tIndexFile:         \"index.json\",\n\t\t\tVerify:            svcCfg.VerifyBinaryUpdates,\n\t\t\tAutoCheck:         true, // May be changed by config during instance startup.\n\t\t\tAutoDownload:      false,\n\t\t\tAutoApply:         false,\n\t\t\tNeedsRestart:      true,\n\t\t\tNotify:            true,\n\t\t}\n\t\tintelUpdateConfig = &updates.Config{\n\t\t\tName:              configure.DefaultIntelIndexName,\n\t\t\tDirectory:         filepath.Join(svcCfg.DataDir, \"intel\"),\n\t\t\tDownloadDirectory: filepath.Join(svcCfg.DataDir, \"download_intel\"),\n\t\t\tPurgeDirectory:    filepath.Join(svcCfg.DataDir, \"upgrade_obsolete_intel\"),\n\t\t\tIndexURLs:         svcCfg.IntelIndexURLs,\n\t\t\tIndexFile:         \"index.json\",\n\t\t\tVerify:            svcCfg.VerifyIntelUpdates,\n\t\t\tAutoCheck:         true, // May be changed by config during instance startup.\n\t\t\tAutoDownload:      true,\n\t\t\tAutoApply:         true,\n\t\t\tNeedsRestart:      false,\n\t\t\tNotify:            false,\n\t\t}\n\n\tcase \"linux\":\n\t\tbinaryUpdateConfig = &updates.Config{\n\t\t\tName:              configure.DefaultBinaryIndexName,\n\t\t\tDirectory:         svcCfg.BinDir,\n\t\t\tDownloadDirectory: filepath.Join(svcCfg.DataDir, \"download_binaries\"),\n\t\t\tPurgeDirectory:    filepath.Join(svcCfg.DataDir, \"upgrade_obsolete_binaries\"),\n\t\t\tIgnore:            []string{},               // \"databases\", \"intel\" and \"config.json\" not needed here since they are not in the bin dir.\n\t\t\tIndexURLs:         svcCfg.BinariesIndexURLs, // May be changed by config during instance startup.\n\t\t\tIndexFile:         \"index.json\",\n\t\t\tVerify:            svcCfg.VerifyBinaryUpdates,\n\t\t\tAutoCheck:         true, // May be changed by config during instance startup.\n\t\t\tAutoDownload:      false,\n\t\t\tAutoApply:         false,\n\t\t\tNeedsRestart:      true,\n\t\t\tNotify:            true,\n\t\t}\n\t\tif binPath, err := getCurrentBinaryPath(); err == nil {\n\t\t\tbinaryUpdateConfig.PostUpgradeCommands = []updates.UpdateCommandConfig{\n\t\t\t\t// Restore SELinux context for the new core binary after upgrade\n\t\t\t\t// (`restorecon /usr/lib/portmaster/portmaster-core`)\n\t\t\t\t{\n\t\t\t\t\tCommand:              \"restorecon\",\n\t\t\t\t\tArgs:                 []string{binPath},\n\t\t\t\t\tTriggerArtifactFName: binPath,\n\t\t\t\t\tFailOnError:          false, // Ignore error: 'restorecon' may not be available on a non-SELinux systems.\n\t\t\t\t},\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to get current binary path: %w\", err)\n\t\t}\n\n\t\tintelUpdateConfig = &updates.Config{\n\t\t\tName:              configure.DefaultIntelIndexName,\n\t\t\tDirectory:         filepath.Join(svcCfg.DataDir, \"intel\"),\n\t\t\tDownloadDirectory: filepath.Join(svcCfg.DataDir, \"download_intel\"),\n\t\t\tPurgeDirectory:    filepath.Join(svcCfg.DataDir, \"upgrade_obsolete_intel\"),\n\t\t\tIndexURLs:         svcCfg.IntelIndexURLs,\n\t\t\tIndexFile:         \"index.json\",\n\t\t\tVerify:            svcCfg.VerifyIntelUpdates,\n\t\t\tAutoCheck:         true, // May be changed by config during instance startup.\n\t\t\tAutoDownload:      true,\n\t\t\tAutoApply:         true,\n\t\t\tNeedsRestart:      false,\n\t\t\tNotify:            false,\n\t\t}\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "service/configure/updates.go",
    "content": "package configure\n\nimport (\n\t\"github.com/safing/jess\"\n)\n\nvar (\n\tDefaultBinaryIndexName = \"Portmaster Binaries\"\n\tDefaultIntelIndexName  = \"Portmaster Intel\"\n\n\tDefaultStableBinaryIndexURLs = []string{\n\t\t\"https://updates.safing.io/stable.v3.json\",\n\t}\n\tDefaultBetaBinaryIndexURLs = []string{\n\t\t\"https://updates.safing.io/beta.v3.json\",\n\t}\n\tDefaultStagingBinaryIndexURLs = []string{\n\t\t\"https://updates.safing.io/staging.v3.json\",\n\t}\n\tDefaultSupportBinaryIndexURLs = []string{\n\t\t\"https://updates.safing.io/support.v3.json\",\n\t}\n\n\tDefaultIntelIndexURLs = []string{\n\t\t\"https://updates.safing.io/intel.v3.json\",\n\t}\n\n\t// BinarySigningKeys holds the signing keys in text format.\n\tBinarySigningKeys = []string{\n\t\t// Safing Code Signing Key #1\n\t\t\"recipient:public-ed25519-key:safing-code-signing-key-1:92bgBLneQUWrhYLPpBDjqHbpFPuNVCPAaivQ951A4aq72HcTiw7R1QmPJwFM1mdePAvEVDjkeb8S4fp2pmRCsRa8HrCvWQEjd88rfZ6TznJMfY4g7P8ioGFjfpyx2ZJ8WCZJG5Qt4Z9nkabhxo2Nbi3iywBTYDLSbP5CXqi7jryW7BufWWuaRVufFFzhwUC2ryWFWMdkUmsAZcvXwde4KLN9FrkWAy61fGaJ8GCwGnGCSitANnU2cQrsGBXZzxmzxwrYD\",\n\t\t// Safing Code Signing Key #2\n\t\t\"recipient:public-ed25519-key:safing-code-signing-key-2:92bgBLneQUWrhYLPpBDjqHbPC2d1o5JMyZFdavWBNVtdvbPfzDewLW95ScXfYPHd3QvWHSWCtB4xpthaYWxSkK1kYiGp68DPa2HaU8yQ5dZhaAUuV4Kzv42pJcWkCeVnBYqgGBXobuz52rFqhDJy3rz7soXEmYhJEJWwLwMeioK3VzN3QmGSYXXjosHMMNC76rjufSoLNtUQUWZDSnHmqbuxbKMCCsjFXUGGhtZVyb7bnu7QLTLk6SKHBJDMB6zdL9sw3\",\n\t}\n\n\t// BinarySigningTrustStore is an in-memory trust store with the signing keys.\n\tBinarySigningTrustStore = jess.NewMemTrustStore()\n)\n\nfunc init() {\n\tfor _, signingKey := range BinarySigningKeys {\n\t\trcpt, err := jess.RecipientFromTextFormat(signingKey)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\terr = BinarySigningTrustStore.StoreSignet(rcpt)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\n// GetBinaryUpdateURLs returns the correct binary update URLs for the given release channel.\n// Silently falls back to stable if release channel is invalid.\nfunc GetBinaryUpdateURLs(releaseChannel string) []string {\n\tswitch releaseChannel {\n\tcase \"stable\":\n\t\treturn DefaultStableBinaryIndexURLs\n\tcase \"beta\":\n\t\treturn DefaultBetaBinaryIndexURLs\n\tcase \"staging\":\n\t\treturn DefaultStagingBinaryIndexURLs\n\tcase \"support\":\n\t\treturn DefaultSupportBinaryIndexURLs\n\tdefault:\n\t\treturn DefaultStableBinaryIndexURLs\n\t}\n}\n"
  },
  {
    "path": "service/control/api.go",
    "content": "package control\r\n\r\nimport (\r\n\t\"encoding/json\"\r\n\t\"fmt\"\r\n\t\"net/http\"\r\n\t\"time\"\r\n\r\n\t\"github.com/safing/portmaster/base/api\"\r\n)\r\n\r\nconst (\r\n\tAPIEndpointPause  = \"control/pause\"\r\n\tAPIEndpointResume = \"control/resume\"\r\n)\r\n\r\ntype pauseRequestParams struct {\r\n\tDuration int  `json:\"duration\"` // Duration in seconds\r\n\tOnlySPN  bool `json:\"onlySPN\"`  // Whether to pause only the SPN service\r\n}\r\n\r\nfunc (c *Control) registerAPIEndpoints() error {\r\n\r\n\tif err := api.RegisterEndpoint(api.Endpoint{\r\n\t\tPath:        APIEndpointPause,\r\n\t\tWrite:       api.PermitAdmin,\r\n\t\tActionFunc:  c.handlePause,\r\n\t\tName:        \"Pause Portmaster\",\r\n\t\tDescription: \"Pause the Portmaster Core Service.\",\r\n\t\tParameters: []api.Parameter{\r\n\t\t\t{\r\n\t\t\t\tMethod:      http.MethodPost,\r\n\t\t\t\tField:       \"duration\",\r\n\t\t\t\tDescription: \"Specify the duration to pause the service in seconds.\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tMethod:      http.MethodPost,\r\n\t\t\t\tField:       \"onlySPN\",\r\n\t\t\t\tValue:       \"false\",\r\n\t\t\t\tDescription: \"Specify whether to pause only the SPN service.\",\r\n\t\t\t}},\r\n\t}); err != nil {\r\n\t\treturn err\r\n\t}\r\n\r\n\tif err := api.RegisterEndpoint(api.Endpoint{\r\n\t\tPath:        APIEndpointResume,\r\n\t\tWrite:       api.PermitAdmin,\r\n\t\tActionFunc:  c.handleResume,\r\n\t\tName:        \"Resume Portmaster\",\r\n\t\tDescription: \"Resume the Portmaster Core Service.\",\r\n\t}); err != nil {\r\n\t\treturn err\r\n\t}\r\n\r\n\treturn nil\r\n}\r\n\r\nfunc (c *Control) handlePause(r *api.Request) (msg string, err error) {\r\n\tparams := pauseRequestParams{}\r\n\tif r.InputData != nil {\r\n\t\tif err := json.Unmarshal(r.InputData, &params); err != nil {\r\n\t\t\treturn \"Bad Request: invalid input data\", err\r\n\t\t}\r\n\t}\r\n\r\n\tif params.OnlySPN {\r\n\t\tc.mgr.Info(fmt.Sprintf(\"Received SPN Pause(%v) action request \", params.Duration))\r\n\t} else {\r\n\t\tc.mgr.Info(fmt.Sprintf(\"Received Pause(%v) action request \", params.Duration))\r\n\t}\r\n\r\n\tif err := c.pause(time.Duration(params.Duration)*time.Second, params.OnlySPN); err != nil {\r\n\t\treturn \"Failed to pause\", err\r\n\t}\r\n\treturn \"Pause initiated\", nil\r\n}\r\n\r\nfunc (c *Control) handleResume(_ *api.Request) (msg string, err error) {\r\n\tc.mgr.Info(\"Received Resume action request\")\r\n\r\n\tif err := c.resume(); err != nil {\r\n\t\treturn \"Failed to resume\", err\r\n\t}\r\n\treturn \"Resume initiated\", nil\r\n}\r\n"
  },
  {
    "path": "service/control/module.go",
    "content": "package control\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"sync\"\r\n\t\"sync/atomic\"\r\n\t\"time\"\r\n\r\n\t\"github.com/safing/portmaster/base/config\"\r\n\t\"github.com/safing/portmaster/base/notifications\"\r\n\t\"github.com/safing/portmaster/service/mgr\"\r\n)\r\n\r\ntype PauseInfo struct {\r\n\tInterception bool      // Whether Portmaster interception is paused\r\n\tSPN          bool      // Whether SPN is paused\r\n\tTillTime     time.Time // When the pause will end\r\n}\r\n\r\ntype Control struct {\r\n\tmgr      *mgr.Manager\r\n\tinstance instance\r\n\tstates   *mgr.StateMgr\r\n\r\n\tlocker            sync.Mutex\r\n\tresumeWorker      *mgr.WorkerMgr\r\n\tpauseNotification *notifications.Notification\r\n\tpauseInfo         PauseInfo\r\n\r\n\tcfgSpnEnabled config.BoolOption\r\n}\r\n\r\ntype instance interface {\r\n\tConfig() *config.Config\r\n\tInterceptionGroup() *mgr.GroupModule\r\n\tSPNGroup() *mgr.ExtendedGroup\r\n\tIsShuttingDown() bool\r\n}\r\n\r\nvar (\r\n\tsingleton atomic.Bool\r\n)\r\n\r\nfunc New(instance instance) (*Control, error) {\r\n\tif !singleton.CompareAndSwap(false, true) {\r\n\t\treturn nil, fmt.Errorf(\"control: New failed: instance already created\")\r\n\t}\r\n\r\n\tm := mgr.New(\"Control\")\r\n\tmodule := &Control{\r\n\t\tmgr:           m,\r\n\t\tinstance:      instance,\r\n\t\tstates:        mgr.NewStateMgr(m),\r\n\t\tcfgSpnEnabled: config.GetAsBool(\"spn/enable\", false),\r\n\t}\r\n\tif err := module.prep(); err != nil {\r\n\t\treturn nil, err\r\n\t}\r\n\treturn module, nil\r\n}\r\n\r\nfunc (c *Control) Manager() *mgr.Manager {\r\n\treturn c.mgr\r\n}\r\n\r\nfunc (u *Control) States() *mgr.StateMgr {\r\n\treturn u.states\r\n}\r\n\r\nfunc (c *Control) Start() error {\r\n\treturn nil\r\n}\r\n\r\nfunc (c *Control) Stop() error {\r\n\tc.locker.Lock()\r\n\tdefer c.locker.Unlock()\r\n\tc.stopResumeWorker()\r\n\r\n\treturn nil\r\n}\r\n\r\nfunc (c *Control) prep() error {\r\n\treturn c.registerAPIEndpoints()\r\n}\r\n"
  },
  {
    "path": "service/control/pause.go",
    "content": "package control\r\n\r\nimport (\r\n\t\"errors\"\r\n\t\"fmt\"\r\n\t\"time\"\r\n\r\n\t\"github.com/safing/portmaster/base/config\"\r\n\t\"github.com/safing/portmaster/base/notifications\"\r\n\t\"github.com/safing/portmaster/service/mgr\"\r\n)\r\n\r\nfunc (c *Control) pause(duration time.Duration, onlySPN bool) (retErr error) {\r\n\tif c.instance.IsShuttingDown() {\r\n\t\tc.mgr.Debug(\"Cannot pause: system is shutting down\")\r\n\t\treturn nil\r\n\t}\r\n\r\n\tc.locker.Lock()\r\n\tdefer c.locker.Unlock()\r\n\r\n\tdefer func() {\r\n\t\t// update states after pause attempt\r\n\t\tc.updateStatesAndNotify()\r\n\t\t// log error if pause failed\r\n\t\tif retErr != nil {\r\n\t\t\tc.mgr.Error(\"Failed to pause: \" + retErr.Error())\r\n\t\t}\r\n\t}()\r\n\r\n\tif duration <= 0 {\r\n\t\treturn errors.New(\"invalid pause duration\")\r\n\t}\r\n\r\n\tif onlySPN {\r\n\t\tif c.pauseInfo.Interception {\r\n\t\t\treturn errors.New(\"cannot pause SPN separately when core is paused\")\r\n\t\t}\r\n\t\t// If SPN is not running and not already paused, cannot pause it or change pause duration.\r\n\t\tif !c.cfgSpnEnabled() && !c.pauseInfo.SPN {\r\n\t\t\treturn errors.New(\"cannot pause SPN when it is not running\")\r\n\t\t}\r\n\t}\r\n\r\n\t// Stop resume worker if running and start a new one later.\r\n\tc.stopResumeWorker()\r\n\tdefer func() {\r\n\t\tif retErr == nil {\r\n\t\t\t// start new resume worker (with new duration) if no error\r\n\t\t\tc.startResumeWorker(duration)\r\n\t\t}\r\n\t}()\r\n\r\n\t// Pause SPN if not already paused.\r\n\tif !c.pauseInfo.SPN {\r\n\t\tif c.cfgSpnEnabled() {\r\n\t\t\t// \"spn/access\" module is responsible for starting/stopping SPN service.\r\n\t\t\t// Here we just change the config to notify it to stop SPN.\r\n\t\t\t// TODO: the 'pause' state must not make permanent config changes.\r\n\t\t\t//       Consider possibility to not store permanent config changes.\r\n\t\t\t//       E.g. SPN enabled -> pause SPN -> restart PC/Portmaster -> SPN should be enabled again.\r\n\t\t\tconfig.SetConfigOption(\"spn/enable\", false)\r\n\r\n\t\t\t// Wait until SPN is fully stopped with timeout 30s.\r\n\t\t\terr := c.waitSPNStopped(time.Second * 30)\r\n\t\t\tif err != nil {\r\n\t\t\t\tconfig.SetConfigOption(\"spn/enable\", true) // revert config change on error\r\n\t\t\t\treturn err\r\n\t\t\t}\r\n\r\n\t\t\tc.mgr.Info(\"SPN paused\")\r\n\t\t\tc.pauseInfo.SPN = true\r\n\t\t}\r\n\t}\r\n\r\n\tif onlySPN {\r\n\t\treturn nil\r\n\t}\r\n\r\n\tif !c.pauseInfo.Interception {\r\n\t\tif err := c.instance.InterceptionGroup().Stop(); err != nil {\r\n\t\t\treturn err\r\n\t\t}\r\n\t\tc.mgr.Info(\"interception paused\")\r\n\t\tc.pauseInfo.Interception = true\r\n\t}\r\n\r\n\treturn nil\r\n}\r\n\r\nfunc (c *Control) resume() (retErr error) {\r\n\tif c.instance.IsShuttingDown() {\r\n\t\tc.mgr.Debug(\"Cannot resume: system is shutting down\")\r\n\t\treturn nil\r\n\t}\r\n\r\n\tc.locker.Lock()\r\n\tdefer c.locker.Unlock()\r\n\r\n\tdefer func() {\r\n\t\tif retErr != nil {\r\n\t\t\tc.updateStatesAndNotifyError(\"Resume operation failed\", retErr)\r\n\t\t\tc.mgr.Error(\"Error occurred while resuming: \" + retErr.Error())\r\n\t\t} else {\r\n\t\t\tc.updateStatesAndNotify()\r\n\t\t}\r\n\t}()\r\n\r\n\tc.stopResumeWorker()\r\n\r\n\tif c.pauseInfo.Interception {\r\n\t\tif err := c.instance.InterceptionGroup().Start(); err != nil {\r\n\t\t\treturn err\r\n\t\t}\r\n\t\tc.mgr.Info(\"interception resumed\")\r\n\t\tc.pauseInfo.Interception = false\r\n\t}\r\n\r\n\tif c.pauseInfo.SPN {\r\n\t\t// \"spn/access\" module is responsible for starting/stopping SPN service.\r\n\t\t// Here we just change the config to notify it to start SPN.\r\n\t\tif !c.cfgSpnEnabled() {\r\n\t\t\tconfig.SetConfigOption(\"spn/enable\", true)\r\n\t\t\tc.mgr.Info(\"SPN resumed\")\r\n\t\t}\r\n\t\tc.pauseInfo.SPN = false\r\n\t}\r\n\r\n\treturn nil\r\n}\r\n\r\n// stopResumeWorker stops any existing resume worker.\r\n// No thread safety, caller must hold c.locker.\r\nfunc (c *Control) stopResumeWorker() {\r\n\tc.pauseInfo.TillTime = time.Time{}\r\n\r\n\tif c.resumeWorker != nil {\r\n\t\tc.resumeWorker.Stop()\r\n\t\tc.resumeWorker = nil\r\n\t}\r\n}\r\n\r\n// startResumeWorker starts a worker that will resume normal operation after the specified duration.\r\n// No thread safety, caller must hold c.locker.\r\nfunc (c *Control) startResumeWorker(duration time.Duration) {\r\n\t// Strip monotonic clock from deadline to force wall-clock comparison.\r\n\t// This is critical for VM suspend/resume and system sleep scenarios.\r\n\tdeadline := time.Now().Round(0).Add(duration)\r\n\tc.pauseInfo.TillTime = deadline\r\n\r\n\tresumerWorkerFunc := func(wc *mgr.WorkerCtx) error {\r\n\t\twc.Info(fmt.Sprintf(\"Scheduling resume in %v\", duration))\r\n\r\n\t\t// Subscribe to config changes to detect SPN enable.\r\n\t\tcfgChangeEvt := c.instance.Config().EventConfigChange.Subscribe(\"control: spn enable check\", 10)\r\n\t\tdefer cfgChangeEvt.Cancel()\r\n\r\n\t\t// Timer for the deadline.\r\n\t\ttimer := time.NewTimer(time.Until(deadline))\r\n\t\tdefer timer.Stop()\r\n\t\t// Periodically check resume time to handle unexpected wall-clock changes.\r\n\t\tticker := time.NewTicker(15 * time.Second)\r\n\t\tdefer ticker.Stop()\r\n\r\n\t\t// Wait until duration elapses or SPN is enabled by user.\r\n\t\tneedToAutoResume := false\r\n\t\tfor !needToAutoResume {\r\n\t\t\tselect {\r\n\t\t\tcase <-wc.Ctx().Done():\r\n\t\t\t\treturn nil\r\n\t\t\tcase <-cfgChangeEvt.Events():\r\n\t\t\t\tif c.cfgSpnEnabled() {\r\n\t\t\t\t\tcfgChangeEvt.Cancel() // we do not need it anymore (no problem to cancel multiple times)\r\n\t\t\t\t\twc.Info(\"SPN enabled by user. Auto-resume initiated.\")\r\n\t\t\t\t\tneedToAutoResume = true\r\n\t\t\t\t}\r\n\t\t\tcase <-ticker.C:\r\n\t\t\t\t// Check wall-clock time.\r\n\t\t\t\tif time.Now().Round(0).After(deadline) {\r\n\t\t\t\t\tneedToAutoResume = true\r\n\t\t\t\t}\r\n\t\t\tcase <-timer.C:\r\n\t\t\t\tneedToAutoResume = true\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Time to resume\r\n\t\twc.Info(\"Resuming...\")\r\n\t\terr := c.resume()\r\n\t\tif err == nil {\r\n\t\t\tn := &notifications.Notification{\r\n\t\t\t\tEventID:      \"control:resumed\",\r\n\t\t\t\tType:         notifications.Info,\r\n\t\t\t\tTitle:        \"Resumed\",\r\n\t\t\t\tMessage:      \"Automatically resumed from pause state\",\r\n\t\t\t\tShowOnSystem: true,\r\n\t\t\t\tExpires:      time.Now().Add(15 * time.Second).Unix(),\r\n\t\t\t\tAvailableActions: []*notifications.Action{\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tID:   \"ack\",\r\n\t\t\t\t\t\tText: \"OK\",\r\n\t\t\t\t\t},\r\n\t\t\t\t},\r\n\t\t\t}\r\n\t\t\tnotifications.Notify(n)\r\n\t\t}\r\n\t\treturn err\r\n\t}\r\n\r\n\tc.resumeWorker = c.mgr.NewWorkerMgr(\"resumer\", resumerWorkerFunc, nil)\r\n\tc.resumeWorker.Go()\r\n}\r\n\r\n// updateStatesAndNotify updates the paused states and sends notifications accordingly.\r\n// No thread safety, caller must hold c.locker.\r\nfunc (c *Control) updateStatesAndNotify() {\r\n\tif !c.pauseInfo.Interception && !c.pauseInfo.SPN {\r\n\t\tif c.pauseNotification != nil {\r\n\t\t\tc.pauseNotification.Delete()\r\n\t\t\tc.pauseNotification = nil\r\n\t\t}\r\n\t\treturn\r\n\t}\r\n\r\n\ttitle := \"\"\r\n\tnType := notifications.Warning\r\n\tif c.pauseInfo.Interception && c.pauseInfo.SPN {\r\n\t\ttitle = \"Portmaster and SPN paused\"\r\n\t} else if c.pauseInfo.Interception {\r\n\t\ttitle = \"Portmaster paused\"\r\n\t} else if c.pauseInfo.SPN {\r\n\t\ttitle = \"SPN paused\"\r\n\t\tnType = notifications.Info // less severe notification for SPN-only pause\r\n\t}\r\n\tmessage := fmt.Sprintf(\"%s until %v\", title, c.pauseInfo.TillTime.Format(time.TimeOnly))\r\n\r\n\tc.pauseNotification = &notifications.Notification{\r\n\t\tEventID:      \"control:paused\",\r\n\t\tType:         nType,\r\n\t\tTitle:        title,\r\n\t\tMessage:      message,\r\n\t\tShowOnSystem: false, // TODO: Before enabling, ensure that UI client (Tauri implementation) supports ActionTypeWebhook.\r\n\t\tEventData:    &c.pauseInfo,\r\n\t\tAvailableActions: []*notifications.Action{\r\n\t\t\t{\r\n\t\t\t\tText: \"Resume\",\r\n\t\t\t\tType: notifications.ActionTypeWebhook,\r\n\t\t\t\tPayload: &notifications.ActionTypeWebhookPayload{\r\n\t\t\t\t\tURL:          APIEndpointResume,\r\n\t\t\t\t\tResultAction: \"display\",\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t}\r\n\r\n\tnotifications.Notify(c.pauseNotification)\r\n\tc.pauseNotification.SyncWithState(c.states)\r\n}\r\n\r\n// updateStatesAndNotifyError updates the paused states and sends an error notification.\r\n// No thread safety, caller must hold c.locker.\r\nfunc (c *Control) updateStatesAndNotifyError(errDescription string, err error) {\r\n\tif err == nil {\r\n\t\treturn\r\n\t}\r\n\r\n\tif errDescription == \"\" {\r\n\t\terrDescription = \"Error\"\r\n\t}\r\n\r\n\t// Error notification\r\n\tc.pauseNotification = &notifications.Notification{\r\n\t\tEventID:   \"control:error\",\r\n\t\tType:      notifications.Error,\r\n\t\tTitle:     errDescription,\r\n\t\tMessage:   err.Error(),\r\n\t\tEventData: &c.pauseInfo,\r\n\t}\r\n\tnotifications.Notify(c.pauseNotification)\r\n\tc.pauseNotification.SyncWithState(c.states)\r\n}\r\n\r\nfunc (c *Control) showNotification(title, message string) *notifications.Notification {\r\n\tn := &notifications.Notification{\r\n\t\tEventID: \"control:status_info\",\r\n\t\tType:    notifications.Info,\r\n\t\tTitle:   title,\r\n\t\tMessage: message,\r\n\t}\r\n\tnotifications.Notify(n)\r\n\treturn n\r\n}\r\n\r\nfunc (c *Control) waitSPNStopped(stopTimeout time.Duration) error {\r\n\tvar notification *notifications.Notification\r\n\tdefer func() {\r\n\t\tif notification != nil {\r\n\t\t\tnotification.Delete()\r\n\t\t}\r\n\t}()\r\n\r\n\tstartTime := time.Now()\r\n\tisStopped, _ := c.instance.SPNGroup().IsStopped()\r\n\tfor !isStopped {\r\n\t\tvar err error\r\n\r\n\t\ttime.Sleep(200 * time.Millisecond)\r\n\r\n\t\tif c.mgr.IsDone() || c.instance.IsShuttingDown() {\r\n\t\t\treturn errors.New(\"shutting down\")\r\n\t\t}\r\n\r\n\t\tisStopped, err = c.instance.SPNGroup().IsStopped()\r\n\t\tif err != nil {\r\n\t\t\treturn fmt.Errorf(\"failed to stop SPN: %w\", err)\r\n\t\t}\r\n\t\tif time.Since(startTime) > stopTimeout {\r\n\t\t\treturn errors.New(\"timeout waiting for SPN to stop\")\r\n\t\t}\r\n\t\tif notification == nil && time.Since(startTime) > time.Second {\r\n\t\t\tnotification = c.showNotification(\"Waiting for SPN to stop...\", \"\")\r\n\t\t}\r\n\t\tif c.cfgSpnEnabled() {\r\n\t\t\treturn errors.New(\"SPN enabled again\")\r\n\t\t}\r\n\t}\r\n\treturn nil\r\n}\r\n"
  },
  {
    "path": "service/core/api.go",
    "content": "package core\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/ghodss/yaml\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/compat\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/resolver\"\n\t\"github.com/safing/portmaster/service/status\"\n\t\"github.com/safing/portmaster/spn/captain\"\n)\n\nvar errInvalidReadPermission = errors.New(\"invalid read permission\")\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:  \"core/shutdown\",\n\t\tWrite: api.PermitSelf,\n\t\t// Do NOT register as belonging to the module, so that the API is available\n\t\t// when something fails during starting of this module or a dependency.\n\t\tActionFunc:  shutdown,\n\t\tName:        \"Shut Down Portmaster\",\n\t\tDescription: \"Shut down the Portmaster Core Service and all UI components.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:  \"core/restart\",\n\t\tWrite: api.PermitAdmin,\n\t\t// Do NOT register as belonging to the module, so that the API is available\n\t\t// when something fails during starting of this module or a dependency.\n\t\tActionFunc:  restart,\n\t\tName:        \"Restart Portmaster\",\n\t\tDescription: \"Restart the Portmaster Core Service.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"debug/core\",\n\t\tRead:        api.PermitAnyone,\n\t\tDataFunc:    debugInfo,\n\t\tName:        \"Get Debug Information\",\n\t\tDescription: \"Returns network debugging information, similar to debug/info, but with system status data.\",\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"style\",\n\t\t\tValue:       \"github\",\n\t\t\tDescription: \"Specify the formatting style. The default is simple markdown formatting.\",\n\t\t}},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:       \"app/auth\",\n\t\tRead:       api.PermitAnyone,\n\t\tStructFunc: authorizeApp,\n\t\tName:       \"Request an authentication token with a given set of permissions. The user will be prompted to either authorize or deny the request. Used for external or third-party tool integrations.\",\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"app-name\",\n\t\t\t\tDescription: \"The name of the application requesting access\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"read\",\n\t\t\t\tDescription: \"The requested read permission\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"write\",\n\t\t\t\tDescription: \"The requested write permission\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"ttl\",\n\t\t\t\tDescription: \"The time-to-live for the new access token. Defaults to 24h\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:       \"app/profile\",\n\t\tRead:       api.PermitUser,\n\t\tStructFunc: getMyProfile,\n\t\tName:       \"Get the ID of the calling profile\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"updates/check\",\n\t\tWriteMethod: \"POST\",\n\t\tWrite:       api.PermitUser,\n\t\tActionFunc: func(ar *api.Request) (string, error) {\n\t\t\tmodule.instance.BinaryUpdates().TriggerUpdateCheck()\n\t\t\tmodule.instance.IntelUpdates().TriggerUpdateCheck()\n\t\t\treturn \"update check triggered\", nil\n\t\t},\n\t\tName: \"Trigger updates check event\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"updates/apply\",\n\t\tWriteMethod: \"POST\",\n\t\tWrite:       api.PermitUser,\n\t\tActionFunc: func(ar *api.Request) (string, error) {\n\t\t\tmodule.instance.BinaryUpdates().TriggerApplyUpdates()\n\t\t\tmodule.instance.IntelUpdates().TriggerApplyUpdates()\n\t\t\treturn \"upgrade triggered\", nil\n\t\t},\n\t\tName: \"Trigger updates apply event\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"updates/from-url\",\n\t\tWriteMethod: \"POST\",\n\t\tWrite:       api.PermitAnyone,\n\t\tActionFunc: func(ar *api.Request) (string, error) {\n\t\t\terr := module.instance.BinaryUpdates().UpdateFromURL(string(ar.InputData))\n\t\t\tif err != nil {\n\t\t\t\treturn err.Error(), err\n\t\t\t}\n\t\t\treturn \"upgrade triggered\", nil\n\t\t},\n\t\tName: \"Replace current version from the version supplied in the URL\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Get Resource\",\n\t\tDescription: \"Returns the requested resource from the update system\",\n\t\tPath:        `updates/get/{artifact_path:[A-Za-z0-9/\\.\\-_]{1,255}}/{artifact_name:[A-Za-z0-9\\.\\-_]{1,255}}`,\n\t\tRead:        api.PermitUser,\n\t\tReadMethod:  http.MethodGet,\n\t\tHandlerFunc: getUpdateResource,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// shutdown shuts the Portmaster down.\nfunc shutdown(_ *api.Request) (msg string, err error) {\n\tlog.Warning(\"core: user requested shutdown via action\")\n\n\tmodule.instance.Shutdown()\n\treturn \"shutdown initiated\", nil\n}\n\n// restart restarts the Portmaster.\nfunc restart(_ *api.Request) (msg string, err error) {\n\tlog.Info(\"core: user requested restart via action\")\n\n\t// Trigger restart\n\tmodule.instance.Restart()\n\n\treturn \"restart initiated\", nil\n}\n\nfunc getUpdateResource(w http.ResponseWriter, r *http.Request) {\n\t// Get identifier from URL.\n\tvar identifier string\n\tif ar := api.GetAPIRequest(r); ar != nil {\n\t\tidentifier = ar.URLVars[\"artifact_name\"]\n\t}\n\tif identifier == \"\" {\n\t\thttp.Error(w, \"no resource specified\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Get resource.\n\tartifact, err := module.instance.BinaryUpdates().GetFile(identifier)\n\tif err != nil {\n\t\tintelArtifact, intelErr := module.instance.IntelUpdates().GetFile(identifier)\n\t\tif intelErr == nil {\n\t\t\tartifact = intelArtifact\n\t\t} else {\n\t\t\thttp.Error(w, err.Error(), http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Open file for reading.\n\tfile, err := os.Open(artifact.Path())\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tdefer file.Close() //nolint:errcheck,gosec\n\n\t// Assign file to reader\n\tvar reader io.Reader = file\n\n\t// Add version and hash to header.\n\tif artifact.Version != \"\" {\n\t\tw.Header().Set(\"Resource-Version\", artifact.Version)\n\t}\n\tif artifact.SHA256 != \"\" {\n\t\tw.Header().Set(\"Resource-SHA256\", artifact.SHA256)\n\t}\n\n\t// Set Content-Type.\n\tcontentType, _ := utils.MimeTypeByExtension(filepath.Ext(artifact.Path()))\n\tw.Header().Set(\"Content-Type\", contentType)\n\n\t// Check if the content type may be returned.\n\taccept := r.Header.Get(\"Accept\")\n\tif accept != \"\" {\n\t\tmimeTypes := strings.Split(accept, \",\")\n\t\t// First, clean mime types.\n\t\tfor i, mimeType := range mimeTypes {\n\t\t\tmimeType = strings.TrimSpace(mimeType)\n\t\t\tmimeType, _, _ = strings.Cut(mimeType, \";\")\n\t\t\tmimeTypes[i] = mimeType\n\t\t}\n\t\t// Second, check if we may return anything.\n\t\tvar acceptsAny bool\n\t\tfor _, mimeType := range mimeTypes {\n\t\t\tswitch mimeType {\n\t\t\tcase \"*\", \"*/*\":\n\t\t\t\tacceptsAny = true\n\t\t\t}\n\t\t}\n\t\t// Third, check if we can convert.\n\t\tif !acceptsAny {\n\t\t\tvar converted bool\n\t\t\tsourceType, _, _ := strings.Cut(contentType, \";\")\n\t\tfindConvertiblePair:\n\t\t\tfor _, mimeType := range mimeTypes {\n\t\t\t\tswitch {\n\t\t\t\tcase sourceType == \"application/yaml\" && mimeType == \"application/json\":\n\t\t\t\t\tyamlData, err := io.ReadAll(reader)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tjsonData, err := yaml.YAMLToJSON(yamlData)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\treader = bytes.NewReader(jsonData)\n\t\t\t\t\tconverted = true\n\t\t\t\t\tbreak findConvertiblePair\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we could not convert to acceptable format, return an error.\n\t\t\tif !converted {\n\t\t\t\thttp.Error(w, \"conversion to requested format not supported\", http.StatusNotAcceptable)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Write file.\n\tw.WriteHeader(http.StatusOK)\n\tif r.Method != http.MethodHead {\n\t\t_, err = io.Copy(w, reader)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"updates: failed to serve resource file: %s\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// debugInfo returns the debugging information for support requests.\nfunc debugInfo(ar *api.Request) (data []byte, err error) {\n\t// Create debug information helper.\n\tdi := new(debug.Info)\n\tdi.Style = ar.Request.URL.Query().Get(\"style\")\n\n\t// Add debug information.\n\n\t// Very basic information at the start.\n\tdi.AddVersionInfo()\n\tdi.AddPlatformInfo(ar.Context())\n\n\t// Unexpected logs.\n\tdi.AddLastUnexpectedLogs()\n\n\t// Status Information from various modules.\n\tstatus.AddToDebugInfo(di)\n\tcaptain.AddToDebugInfo(di)\n\tresolver.AddToDebugInfo(di)\n\tconfig.AddToDebugInfo(di)\n\n\t// Detailed information.\n\tAddVersionsToDebugInfo(di)\n\tcompat.AddToDebugInfo(di)\n\tmodule.instance.AddWorkerInfoToDebugInfo(di)\n\tdi.AddGoroutineStack()\n\n\t// Return data.\n\treturn di.Bytes(), nil\n}\n\n// getSavePermission returns the requested api.Permission from p.\n// It only allows \"user\" and \"admin\" as external processes should\n// never be able to request \"self\".\nfunc getSavePermission(p string) api.Permission {\n\tswitch p {\n\tcase \"user\":\n\t\treturn api.PermitUser\n\tcase \"admin\":\n\t\treturn api.PermitAdmin\n\tdefault:\n\t\treturn api.NotSupported\n\t}\n}\n\nfunc getMyProfile(ar *api.Request) (interface{}, error) {\n\tproc, err := process.GetProcessByRequestOrigin(ar)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlocalProfile := proc.Profile().LocalProfile()\n\n\treturn map[string]interface{}{\n\t\t\"profile\": localProfile.ID,\n\t\t\"source\":  localProfile.Source,\n\t\t\"name\":    localProfile.Name,\n\t}, nil\n}\n\nfunc authorizeApp(ar *api.Request) (interface{}, error) {\n\tappName := ar.Request.URL.Query().Get(\"app-name\")\n\treadPermStr := ar.Request.URL.Query().Get(\"read\")\n\twritePermStr := ar.Request.URL.Query().Get(\"write\")\n\n\tttl := time.Hour * 24\n\tif ttlStr := ar.Request.URL.Query().Get(\"ttl\"); ttlStr != \"\" {\n\t\tvar err error\n\t\tttl, err = time.ParseDuration(ttlStr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// convert the requested read and write permissions to their api.Permission\n\t// value. This ensures only \"user\" or \"admin\" permissions can be requested.\n\tif getSavePermission(readPermStr) <= api.NotSupported {\n\t\treturn nil, errInvalidReadPermission\n\t}\n\tif getSavePermission(writePermStr) <= api.NotSupported {\n\t\treturn nil, errInvalidReadPermission\n\t}\n\n\tproc, err := process.GetProcessByRequestOrigin(ar)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to identify requesting process: %w\", err)\n\t}\n\n\tn := notifications.Notification{\n\t\tType:         notifications.Prompt,\n\t\tEventID:      \"core:authorize-app-\" + time.Now().String(),\n\t\tTitle:        \"An app requests access to the Portmaster\",\n\t\tMessage:      \"Allow \" + appName + \" (\" + proc.Profile().LocalProfile().Name + \") to query and modify the Portmaster?\\n\\nBinary: \" + proc.Path,\n\t\tShowOnSystem: true,\n\t\tExpires:      time.Now().Add(time.Minute).Unix(),\n\t\tAvailableActions: []*notifications.Action{\n\t\t\t{\n\t\t\t\tID:   \"allow\",\n\t\t\t\tText: \"Authorize\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:   \"deny\",\n\t\t\t\tText: \"Deny\",\n\t\t\t},\n\t\t},\n\t}\n\n\tch := make(chan string)\n\n\tvalidUntil := time.Now().Add(ttl)\n\n\tn.SetActionFunction(func(ctx context.Context, n *notifications.Notification) error {\n\t\tn.Lock()\n\t\tdefer n.Unlock()\n\n\t\tif n.SelectedActionID != \"allow\" {\n\t\t\tclose(ch)\n\t\t\treturn nil\n\t\t}\n\n\t\tkeys := config.Concurrent.GetAsStringArray(api.CfgAPIKeys, []string{})()\n\n\t\tnewKeyData, err := rng.Bytes(8)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnewKeyHex := hex.EncodeToString(newKeyData)\n\n\t\tquery := url.Values{\n\t\t\t\"read\":    []string{readPermStr},\n\t\t\t\"write\":   []string{writePermStr},\n\t\t\t\"expires\": []string{validUntil.Format(time.RFC3339)},\n\t\t}\n\n\t\tkeys = append(keys, fmt.Sprintf(\"%s?%s\", newKeyHex, query.Encode()))\n\n\t\tif err := config.SetConfigOption(api.CfgAPIKeys, keys); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tch <- newKeyHex\n\n\t\treturn nil\n\t})\n\n\tn.Save()\n\n\tselect {\n\tcase key := <-ch:\n\t\tif len(key) == 0 {\n\t\t\treturn nil, errors.New(\"access denied\")\n\t\t}\n\n\t\treturn map[string]interface{}{\n\t\t\t\"key\":        key,\n\t\t\t\"validUntil\": validUntil,\n\t\t}, nil\n\tcase <-ar.Context().Done():\n\t\treturn nil, errors.New(\"timeout\")\n\t}\n}\n"
  },
  {
    "path": "service/core/base/databases.go",
    "content": "package base\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t_ \"github.com/safing/portmaster/base/database/storage/bbolt\"\n\t_ \"github.com/safing/portmaster/base/database/storage/sqlite\"\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\n// Default Values (changeable for testing).\nvar (\n\tDefaultDatabaseStorageType = \"sqlite\"\n)\n\nfunc registerDatabases() error {\n\t// If there is an existing bbolt core database, use it instead.\n\tcoreStorageType := DefaultDatabaseStorageType\n\tif utils.PathExists(filepath.Join(module.instance.DataDir(), \"databases\", \"core\", \"bbolt\")) {\n\t\tcoreStorageType = \"bbolt\"\n\t}\n\n\t// Register core database.\n\t_, err := database.Register(&database.Database{\n\t\tName:        \"core\",\n\t\tDescription: \"Holds core data, such as settings and profiles\",\n\t\tStorageType: coreStorageType,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// If there is an existing cache bbolt database, use it instead.\n\tcacheStorageType := DefaultDatabaseStorageType\n\tif utils.PathExists(filepath.Join(module.instance.DataDir(), \"databases\", \"cache\", \"bbolt\")) {\n\t\tcacheStorageType = \"bbolt\"\n\t}\n\n\t// Register cache database.\n\t_, err = database.Register(&database.Database{\n\t\tName:        \"cache\",\n\t\tDescription: \"Cached data, such as Intelligence and DNS Records\",\n\t\tStorageType: cacheStorageType,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/core/base/logs.go",
    "content": "package base\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nconst (\n\tlogTTL        = 30 * 24 * time.Hour\n\tlogFileDir    = \"logs\"\n\tlogFileSuffix = \".log\"\n)\n\nfunc registerLogCleaner() {\n\t_ = module.mgr.Delay(\"log cleaner\", 15*time.Minute, logCleaner).Repeat(24 * time.Hour)\n}\n\nfunc logCleaner(_ *mgr.WorkerCtx) error {\n\tageThreshold := time.Now().Add(-logTTL)\n\n\treturn filepath.Walk(\n\t\tfilepath.Join(module.instance.DataDir(), logFileDir),\n\t\tfunc(path string, info os.FileInfo, err error) error {\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\tlog.Warningf(\"core: failed to access %s while deleting old log files: %s\", path, err)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase !info.Mode().IsRegular():\n\t\t\t\t// Only delete regular files.\n\t\t\tcase !strings.HasSuffix(path, logFileSuffix):\n\t\t\t\t// Only delete files that end with the correct suffix.\n\t\t\tcase info.ModTime().After(ageThreshold):\n\t\t\t\t// Only delete files that are older that the log TTL.\n\t\t\tdefault:\n\t\t\t\t// Delete log file.\n\t\t\t\terr := os.Remove(path)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warningf(\"core: failed to delete old log file %s: %s\", path, err)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Tracef(\"core: deleted old log file %s\", path)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n}\n"
  },
  {
    "path": "service/core/base/module.go",
    "content": "package base\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// DefaultAPIListenAddress is the default listen address for the API.\nvar DefaultAPIListenAddress = \"127.0.0.1:817\"\n\n// Base is the base module.\ntype Base struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\n// Manager returns the module manager.\nfunc (b *Base) Manager() *mgr.Manager {\n\treturn b.mgr\n}\n\n// Start starts the module.\nfunc (b *Base) Start() error {\n\tstartProfiling()\n\t// registerLogCleaner()\n\n\treturn nil\n}\n\n// Stop stops the module.\nfunc (b *Base) Stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *Base\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Base module.\nfunc New(instance instance) (*Base, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Base\")\n\tmodule = &Base{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\t// Set api listen address.\n\tapi.SetDefaultAPIListenAddress(DefaultAPIListenAddress)\n\n\tif err := registerDatabases(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tDataDir() string\n\tSetCmdLineOperation(f func() error)\n}\n"
  },
  {
    "path": "service/core/base/profiling.go",
    "content": "package base\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/pprof\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar cpuProfile string\n\nfunc init() {\n\tflag.StringVar(&cpuProfile, \"cpuprofile\", \"\", \"write cpu profile to `file`\")\n}\n\nfunc startProfiling() {\n\tif cpuProfile != \"\" {\n\t\tmodule.mgr.Go(\"cpu profiler\", cpuProfiler)\n\t}\n}\n\nfunc cpuProfiler(ctx *mgr.WorkerCtx) error {\n\tf, err := os.Create(cpuProfile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not create CPU profile: %w\", err)\n\t}\n\tif err := pprof.StartCPUProfile(f); err != nil {\n\t\treturn fmt.Errorf(\"could not start CPU profile: %w\", err)\n\t}\n\n\t// wait for shutdown\n\t<-ctx.Done()\n\n\tpprof.StopCPUProfile()\n\terr = f.Close()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to close CPU profile file: %w\", err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/core/config.go",
    "content": "package core\n\nimport (\n\t\"flag\"\n\n\tlocale \"github.com/Xuanwo/go-locale\"\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// Configuration Keys.\nvar (\n\t// CfgDevModeKey was previously defined here.\n\tCfgDevModeKey = config.CfgDevModeKey\n\n\tCfgNetworkServiceKey      = \"core/networkService\"\n\tdefaultNetworkServiceMode bool\n\n\tCfgLocaleKey = \"core/locale\"\n)\n\nfunc init() {\n\tflag.BoolVar(\n\t\t&defaultNetworkServiceMode,\n\t\t\"network-service\",\n\t\tfalse,\n\t\t\"set default network service mode; configuration is stronger\",\n\t)\n}\n\nfunc registerConfig() error {\n\tif err := config.Register(&config.Option{\n\t\tName:           \"Network Service\",\n\t\tKey:            CfgNetworkServiceKey,\n\t\tDescription:    \"Use the Portmaster as a network service, where applicable. You will have to take care of lots of network setup yourself in order to run this properly and securely.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tReleaseLevel:   config.ReleaseLevelExperimental,\n\t\tDefaultValue:   defaultNetworkServiceMode,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: 513,\n\t\t\tconfig.CategoryAnnotation:     \"Network Service\",\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := config.Register(&config.Option{\n\t\tName:           \"Time and Date Format\",\n\t\tKey:            CfgLocaleKey,\n\t\tDescription:    \"Configures the time and date format for the user interface. Selection is an example and correct formatting in the UI is a continual work in progress.\",\n\t\tOptType:        config.OptTypeString,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   getDefaultLocale(),\n\t\tPossibleValues: []config.PossibleValue{\n\t\t\t{\n\t\t\t\tName:  \"24h DD-MM-YYYY\",\n\t\t\t\tValue: enGBLocale,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"12h MM/DD/YYYY\",\n\t\t\t\tValue: enUSLocale,\n\t\t\t},\n\t\t},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.CategoryAnnotation:         \"User Interface\",\n\t\t\tconfig.DisplayHintAnnotation:      config.DisplayHintOneOf,\n\t\t\tconfig.RequiresUIReloadAnnotation: true,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc getDefaultLocale() string {\n\t// Get locales from system.\n\tdetectedLocales, err := locale.DetectAll()\n\tif err != nil {\n\t\tlog.Warningf(\"core: failed to detect locale: %s\", err)\n\t\treturn enGBLocale\n\t}\n\n\t// log.Debugf(\"core: detected locales: %s\", detectedLocales)\n\n\t// Check if there is a locale that corresponds to the en-US locale.\n\tfor _, detectedLocale := range detectedLocales {\n\t\tif slices.Contains[[]string, string](defaultEnUSLocales, detectedLocale.String()) {\n\t\t\treturn enUSLocale\n\t\t}\n\t}\n\n\t// Otherwise, return the en-GB locale as default.\n\treturn enGBLocale\n}\n\nvar (\n\tenGBLocale = \"en-GB\"\n\tenUSLocale = \"en-US\"\n\n\tdefaultEnUSLocales = []string{\n\t\t\"en-AS\", // English (American Samoa)\n\t\t\"en-GU\", // English (Guam)\n\t\t\"en-UM\", // English (U.S. Minor Outlying Islands)\n\t\t\"en-US\", // English (United States)\n\t\t\"en-VI\", // English (U.S. Virgin Islands)\n\t}\n)\n"
  },
  {
    "path": "service/core/core.go",
    "content": "package core\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t_ \"github.com/safing/portmaster/service/netenv\"\n\t_ \"github.com/safing/portmaster/service/netquery\"\n\t_ \"github.com/safing/portmaster/service/status\"\n\t_ \"github.com/safing/portmaster/service/sync\"\n\t_ \"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nvar db = database.NewInterface(&database.Options{\n\tLocal:    true,\n\tInternal: true,\n})\n\n// Core is the core service module.\ntype Core struct {\n\tm        *mgr.Manager\n\tinstance instance\n\n\tEventShutdown *mgr.EventMgr[struct{}]\n\tEventRestart  *mgr.EventMgr[struct{}]\n}\n\n// Manager returns the manager.\nfunc (c *Core) Manager() *mgr.Manager {\n\treturn c.m\n}\n\n// Start starts the module.\nfunc (c *Core) Start() error {\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (c *Core) Stop() error {\n\treturn nil\n}\n\nfunc prep() error {\n\t// init config\n\tif err := registerConfig(); err != nil {\n\t\treturn err\n\t}\n\tif err := registerUpdateConfig(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerAPIEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := initModulesIntegration(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc start() error {\n\tif err := startPlatformSpecific(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start plattform-specific components: %w\", err)\n\t}\n\n\t// Setup update system.\n\tinitUpdateConfig()\n\tinitVersionExport()\n\n\t// Enable persistent metrics.\n\tif err := metrics.EnableMetricPersistence(\"core:metrics/storage\"); err != nil {\n\t\tlog.Warningf(\"core: failed to enable persisted metrics: %s\", err)\n\t}\n\n\treturn nil\n}\n\nvar (\n\tmodule     *Core\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new NetEnv module.\nfunc New(instance instance) (*Core, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"Core\")\n\tmodule = &Core{\n\t\tm:        m,\n\t\tinstance: instance,\n\n\t\tEventShutdown: mgr.NewEventMgr[struct{}](\"shutdown\", m),\n\t\tEventRestart:  mgr.NewEventMgr[struct{}](\"restart\", m),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tShutdown()\n\tRestart()\n\tAddWorkerInfoToDebugInfo(di *debug.Info)\n\tConfig() *config.Config\n\tBinaryUpdates() *updates.Updater\n\tIntelUpdates() *updates.Updater\n}\n"
  },
  {
    "path": "service/core/events.go",
    "content": "package core\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar modulesIntegrationUpdatePusher func(...record.Record)\n\nfunc initModulesIntegration() (err error) {\n\tmodulesIntegrationUpdatePusher, err = runtime.Register(\"modules/\", &ModulesIntegration{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Push events via API.\n\tmodule.EventRestart.AddCallback(\"expose restart event\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\t// Send event as runtime:modules/core/event/restart\n\t\tpushModuleEvent(\"core\", \"restart\", false, nil)\n\t\treturn false, nil\n\t})\n\tmodule.EventShutdown.AddCallback(\"expose shutdown event\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\t// Send event as runtime:modules/core/event/shutdown\n\t\tpushModuleEvent(\"core\", \"shutdown\", false, nil)\n\t\treturn false, nil\n\t})\n\n\treturn nil\n}\n\n// ModulesIntegration provides integration with the modules system.\ntype ModulesIntegration struct{}\n\n// Set is called when the value is set from outside.\n// If the runtime value is considered read-only ErrReadOnly\n// should be returned. It is guaranteed that the key of\n// the record passed to Set is prefixed with the key used\n// to register the value provider.\nfunc (mi *ModulesIntegration) Set(record.Record) (record.Record, error) {\n\treturn nil, runtime.ErrReadOnly\n}\n\n// Get should return one or more records that match keyOrPrefix.\n// keyOrPrefix is guaranteed to be at least the prefix used to\n// register the ValueProvider.\nfunc (mi *ModulesIntegration) Get(keyOrPrefix string) ([]record.Record, error) {\n\treturn nil, database.ErrNotFound\n}\n\ntype eventData struct {\n\trecord.Base\n\tsync.Mutex\n\tData interface{}\n}\n\nfunc pushModuleEvent(moduleName, eventName string, internal bool, data interface{}) {\n\t// Create event record and set key.\n\teventRecord := &eventData{\n\t\tData: data,\n\t}\n\teventRecord.SetKey(fmt.Sprintf(\n\t\t\"runtime:modules/%s/event/%s\",\n\t\tmoduleName,\n\t\teventName,\n\t))\n\teventRecord.UpdateMeta()\n\tif internal {\n\t\teventRecord.Meta().MakeSecret()\n\t\teventRecord.Meta().MakeCrownJewel()\n\t}\n\n\t// Push event to database subscriptions.\n\tmodulesIntegrationUpdatePusher(eventRecord)\n}\n"
  },
  {
    "path": "service/core/os_default.go",
    "content": "//go:build !windows\n\npackage core\n\n// only return on Fatal error!\nfunc startPlatformSpecific() error {\n\treturn nil\n}\n"
  },
  {
    "path": "service/core/os_windows.go",
    "content": "package core\n\nimport (\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils/osdetail\"\n)\n\n// only return on Fatal error!\nfunc startPlatformSpecific() error {\n\t// We can't catch errors when calling WindowsNTVersion() in logging, so we call the function here, just to catch possible errors\n\tif _, err := osdetail.WindowsNTVersion(); err != nil {\n\t\tlog.Errorf(\"failed to obtain WindowsNTVersion: %s\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/core/update_config.go",
    "content": "package core\n\nimport (\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/configure\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// Release Channel Configuration Keys.\nconst (\n\tReleaseChannelKey     = \"core/releaseChannel\"\n\tReleaseChannelJSONKey = \"core.releaseChannel\"\n)\n\n// Release Channels.\nconst (\n\tReleaseChannelStable  = \"stable\"\n\tReleaseChannelBeta    = \"beta\"\n\tReleaseChannelStaging = \"staging\"\n\tReleaseChannelSupport = \"support\"\n)\n\nconst (\n\tenableSoftwareUpdatesKey = \"core/automaticUpdates\"\n\tenableIntelUpdatesKey    = \"core/automaticIntelUpdates\"\n)\n\nvar (\n\treleaseChannel        config.StringOption\n\tenableSoftwareUpdates config.BoolOption\n\tenableIntelUpdates    config.BoolOption\n\n\tinitialReleaseChannel string\n)\n\nfunc registerUpdateConfig() error {\n\terr := config.Register(&config.Option{\n\t\tName:            \"Release Channel\",\n\t\tKey:             ReleaseChannelKey,\n\t\tDescription:     `Use \"Stable\" for the best experience. The \"Beta\" channel will have the newest features and fixes, but may also break and cause interruption. Use others only temporarily and when instructed.`,\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    ReleaseChannelStable,\n\t\tPossibleValues: []config.PossibleValue{\n\t\t\t{\n\t\t\t\tName:        \"Stable\",\n\t\t\t\tDescription: \"Production releases.\",\n\t\t\t\tValue:       ReleaseChannelStable,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Beta\",\n\t\t\t\tDescription: \"Production releases for testing new features that may break and cause interruption.\",\n\t\t\t\tValue:       ReleaseChannelBeta,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Support\",\n\t\t\t\tDescription: \"Support releases or version changes for troubleshooting. Only use temporarily and when instructed.\",\n\t\t\t\tValue:       ReleaseChannelSupport,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Staging\",\n\t\t\t\tDescription: \"Dangerous development releases for testing random things and experimenting. Only use temporarily and when instructed.\",\n\t\t\t\tValue:       ReleaseChannelStaging,\n\t\t\t},\n\t\t},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: -4,\n\t\t\tconfig.DisplayHintAnnotation:  config.DisplayHintOneOf,\n\t\t\tconfig.CategoryAnnotation:     \"Updates\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Automatic Software Updates\",\n\t\tKey:             enableSoftwareUpdatesKey,\n\t\tDescription:     \"Automatically check for and download software updates. This does not include intelligence data updates.\",\n\t\tOptType:         config.OptTypeBool,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tRequiresRestart: false,\n\t\tDefaultValue:    true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: -12,\n\t\t\tconfig.CategoryAnnotation:     \"Updates\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Automatic Intelligence Data Updates\",\n\t\tKey:             enableIntelUpdatesKey,\n\t\tDescription:     \"Automatically check for and download intelligence data updates. This includes filter lists, geo-ip data, and more. Does not include software updates.\",\n\t\tOptType:         config.OptTypeBool,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tRequiresRestart: false,\n\t\tDefaultValue:    true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: -11,\n\t\t\tconfig.CategoryAnnotation:     \"Updates\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc initUpdateConfig() {\n\treleaseChannel = config.Concurrent.GetAsString(ReleaseChannelKey, ReleaseChannelStable)\n\tenableSoftwareUpdates = config.Concurrent.GetAsBool(enableSoftwareUpdatesKey, true)\n\tenableIntelUpdates = config.Concurrent.GetAsBool(enableIntelUpdatesKey, true)\n\n\tinitialReleaseChannel = releaseChannel()\n\n\tmodule.instance.Config().EventConfigChange.AddCallback(\"configure updates\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\tconfigureUpdates()\n\t\treturn false, nil\n\t})\n\tconfigureUpdates()\n}\n\nfunc configureUpdates() {\n\tmodule.instance.BinaryUpdates().Configure(enableSoftwareUpdates(), configure.GetBinaryUpdateURLs(releaseChannel()))\n\tmodule.instance.IntelUpdates().Configure(enableIntelUpdates(), configure.DefaultIntelIndexURLs)\n}\n"
  },
  {
    "path": "service/core/update_versions.go",
    "content": "package core\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sync\"\n\t\"text/tabwriter\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nconst (\n\t// versionsDBKey is the database key for update version information.\n\tversionsDBKey = \"core:status/versions\"\n\n\t// versionsDBKey is the database key for simple update version information.\n\tsimpleVersionsDBKey = \"core:status/simple-versions\"\n)\n\n// Versions holds update versions and status information.\ntype Versions struct {\n\trecord.Base\n\tsync.Mutex\n\n\tCore      *info.Info\n\tResources map[string]*updates.Artifact\n\tChannel   string\n\tBeta      bool\n\tStaging   bool\n}\n\n// SimpleVersions holds simplified update versions and status information.\ntype SimpleVersions struct {\n\trecord.Base\n\tsync.Mutex\n\n\tBuild     *info.Info\n\tResources map[string]*SimplifiedResourceVersion\n\tChannel   string\n}\n\n// SimplifiedResourceVersion holds version information about one resource.\ntype SimplifiedResourceVersion struct {\n\tVersion string\n}\n\n// GetVersions returns the update versions and status information.\n// Resources must be locked when accessed.\nfunc GetVersions() *Versions {\n\t// Get all artifacts.\n\tresources := make(map[string]*updates.Artifact)\n\tif artifacts, err := module.instance.BinaryUpdates().GetFiles(); err == nil {\n\t\tfor _, artifact := range artifacts {\n\t\t\tresources[artifact.Filename] = artifact\n\t\t}\n\t}\n\tif artifacts, err := module.instance.IntelUpdates().GetFiles(); err == nil {\n\t\tfor _, artifact := range artifacts {\n\t\t\tresources[artifact.Filename] = artifact\n\t\t}\n\t}\n\n\treturn &Versions{\n\t\tCore:      info.GetInfo(),\n\t\tResources: resources,\n\t\tChannel:   initialReleaseChannel,\n\t\tBeta:      initialReleaseChannel == ReleaseChannelBeta,\n\t\tStaging:   initialReleaseChannel == ReleaseChannelStaging,\n\t}\n}\n\n// GetSimpleVersions returns the simplified update versions and status information.\nfunc GetSimpleVersions() *SimpleVersions {\n\t// Get all artifacts, simply map.\n\tresources := make(map[string]*SimplifiedResourceVersion)\n\tif artifacts, err := module.instance.BinaryUpdates().GetFiles(); err == nil {\n\t\tfor _, artifact := range artifacts {\n\t\t\tresources[artifact.Filename] = &SimplifiedResourceVersion{\n\t\t\t\tVersion: artifact.Version,\n\t\t\t}\n\t\t}\n\t}\n\tif artifacts, err := module.instance.IntelUpdates().GetFiles(); err == nil {\n\t\tfor _, artifact := range artifacts {\n\t\t\tresources[artifact.Filename] = &SimplifiedResourceVersion{\n\t\t\t\tVersion: artifact.Version,\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fill base info.\n\treturn &SimpleVersions{\n\t\tBuild:     info.GetInfo(),\n\t\tResources: resources,\n\t\tChannel:   initialReleaseChannel,\n\t}\n}\n\nfunc initVersionExport() {\n\tmodule.instance.BinaryUpdates().EventResourcesUpdated.AddCallback(\"export version status\", export)\n\tmodule.instance.IntelUpdates().EventResourcesUpdated.AddCallback(\"export version status\", export)\n\n\t_, _ = export(nil, struct{}{})\n}\n\nfunc (v *Versions) save() error {\n\tif !v.KeyIsSet() {\n\t\tv.SetKey(versionsDBKey)\n\t}\n\treturn db.Put(v)\n}\n\nfunc (v *SimpleVersions) save() error {\n\tif !v.KeyIsSet() {\n\t\tv.SetKey(simpleVersionsDBKey)\n\t}\n\treturn db.Put(v)\n}\n\n// export is an event hook.\nfunc export(_ *mgr.WorkerCtx, _ struct{}) (cancel bool, err error) {\n\t// Export versions.\n\tif err := GetVersions().save(); err != nil {\n\t\treturn false, err\n\t}\n\tif err := GetSimpleVersions().save(); err != nil {\n\t\treturn false, err\n\t}\n\n\treturn false, nil\n}\n\n// AddVersionsToDebugInfo adds the update system status to the given debug.Info.\nfunc AddVersionsToDebugInfo(di *debug.Info) {\n\toverviewBuf := bytes.NewBuffer(nil)\n\ttableBuf := bytes.NewBuffer(nil)\n\ttabWriter := tabwriter.NewWriter(tableBuf, 8, 4, 3, ' ', 0)\n\tfmt.Fprint(tabWriter, \"\\nFile\\tVersion\\tIndex\\tSHA256\\n\")\n\n\t// Collect data for debug info.\n\tvar cnt int\n\tif index, err := module.instance.BinaryUpdates().GetIndex(); err == nil {\n\t\tfmt.Fprintf(overviewBuf, \"Binaries Index: v%s from %s\\n\", index.Version, index.Published)\n\t\tfor _, artifact := range index.Artifacts {\n\t\t\tfmt.Fprintf(tabWriter, \"\\n%s\\t%s\\t%s\\t%s\", artifact.Filename, vStr(artifact.Version), \"binaries\", artifact.SHA256)\n\t\t\tcnt++\n\t\t}\n\t}\n\tif index, err := module.instance.IntelUpdates().GetIndex(); err == nil {\n\t\tfmt.Fprintf(overviewBuf, \"Intel Index: v%s from %s\\n\", index.Version, index.Published)\n\t\tfor _, artifact := range index.Artifacts {\n\t\t\tfmt.Fprintf(tabWriter, \"\\n%s\\t%s\\t%s\\t%s\", artifact.Filename, vStr(artifact.Version), \"intel\", artifact.SHA256)\n\t\t\tcnt++\n\t\t}\n\t}\n\t_ = tabWriter.Flush()\n\n\t// Add section.\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Updates: %s (%d)\", initialReleaseChannel, cnt),\n\t\tdebug.UseCodeSection,\n\t\toverviewBuf.String(),\n\t\ttableBuf.String(),\n\t)\n}\n\nfunc vStr(v string) string {\n\tif v != \"\" {\n\t\treturn v\n\t}\n\treturn \"unknown\"\n}\n"
  },
  {
    "path": "service/debug.go",
    "content": "package service\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"runtime\"\n\n\t\"github.com/maruel/panicparse/v2/stack\"\n\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// GetWorkerInfo returns the worker info of all running workers.\nfunc (i *Instance) GetWorkerInfo() (*mgr.WorkerInfo, error) {\n\tsnapshot, _, err := stack.ScanSnapshot(bytes.NewReader(fullStack()), io.Discard, stack.DefaultOpts())\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"get stack: %w\", err)\n\t}\n\n\tinfos := make([]*mgr.WorkerInfo, 0, 32)\n\tfor _, m := range i.serviceGroup.Modules() {\n\t\twi, _ := m.Manager().WorkerInfo(snapshot) // Does not fail when we provide a snapshot.\n\t\tinfos = append(infos, wi)\n\n\t\t// Check if module is a nested modules group\n\t\tif gm, ok := m.(*mgr.GroupModule); ok {\n\t\t\tfor _, sm := range gm.Modules() {\n\t\t\t\twi, _ := sm.Manager().WorkerInfo(snapshot) // Does not fail when we provide a snapshot.\n\t\t\t\tinfos = append(infos, wi)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, m := range i.SpnGroup.Modules() {\n\t\twi, _ := m.Manager().WorkerInfo(snapshot) // Does not fail when we provide a snapshot.\n\t\tinfos = append(infos, wi)\n\n\t\t// Check if module is a nested modules group\n\t\tif gm, ok := m.(*mgr.GroupModule); ok {\n\t\t\tfor _, sm := range gm.Modules() {\n\t\t\t\twi, _ := sm.Manager().WorkerInfo(snapshot) // Does not fail when we provide a snapshot.\n\t\t\t\tinfos = append(infos, wi)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn mgr.MergeWorkerInfo(infos...), nil\n}\n\n// AddWorkerInfoToDebugInfo adds the worker info of all running workers to the debug info.\nfunc (i *Instance) AddWorkerInfoToDebugInfo(di *debug.Info) {\n\tinfo, err := i.GetWorkerInfo()\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Worker Status Failed\",\n\t\t\tdebug.UseCodeSection,\n\t\t\terr.Error(),\n\t\t)\n\t\treturn\n\t}\n\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Worker Status: %d/%d (%d?)\", info.Running, len(info.Workers), info.Missing+info.Other),\n\t\tdebug.UseCodeSection,\n\t\tinfo.Format(),\n\t)\n}\n\nfunc fullStack() []byte {\n\tbuf := make([]byte, 8096)\n\tfor {\n\t\tn := runtime.Stack(buf, true)\n\t\tif n < len(buf) {\n\t\t\treturn buf[:n]\n\t\t}\n\t\tbuf = make([]byte, 2*len(buf))\n\t}\n}\n"
  },
  {
    "path": "service/debug_test.go",
    "content": "package service\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc TestDebug(t *testing.T) {\n\tt.Parallel()\n\n\t// Create test instance with at least one worker.\n\ti := &Instance{}\n\tn, err := notifications.New(i)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ti.serviceGroup = mgr.NewGroup(n)\n\ti.SpnGroup = mgr.NewExtendedGroup()\n\terr = i.Start()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttime.Sleep(100 * time.Millisecond)\n\n\tinfo, err := i.GetWorkerInfo()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Log(info)\n}\n"
  },
  {
    "path": "service/detection/dga/lms.go",
    "content": "package dga\n\nimport (\n\t\"strings\"\n)\n\n// LmsScoreOfDomain calculates the mean longest meaningful substring of a domain.\n// It follows some special rules to increase accuracy. It returns a value between\n// 0 and 100, representing the length-based percentage of the meaningful substring.\nfunc LmsScoreOfDomain(domain string) float64 {\n\tvar totalScore float64\n\tdomain = strings.ToLower(domain)\n\tsubjects := strings.Split(domain, \".\")\n\tvar totalLength int\n\tfor _, subject := range subjects {\n\t\ttotalLength += len(subject)\n\t}\n\tfor _, subject := range subjects {\n\t\t// calculate score, weigh it and add it\n\t\tif len(subject) > 0 {\n\t\t\ttotalScore += LmsScore(subject) * (float64(len(subject)) / float64(totalLength))\n\t\t}\n\t}\n\treturn totalScore\n}\n\n// LmsScore calculates the longest meaningful substring of a domain. It returns a\n// value between 0 and 100, representing the length-based percentage of the\n// meaningful substring.\nfunc LmsScore(subject string) float64 {\n\tlmsStart := -1\n\tlmsStop := -1\n\tlongestLms := 0\n\n\tfor i, c := range subject {\n\t\tif int(c) >= int('a') && int(c) <= int('z') {\n\t\t\tif lmsStart == -1 {\n\t\t\t\tlmsStart = i\n\t\t\t}\n\t\t} else {\n\t\t\tif lmsStart > -1 {\n\t\t\t\tlmsStop = i\n\t\t\t\tif lmsStop-lmsStart > longestLms {\n\t\t\t\t\tlongestLms = lmsStop - lmsStart\n\t\t\t\t}\n\t\t\t\tlmsStart = -1\n\t\t\t}\n\t\t}\n\t}\n\tif lmsStop == -1 {\n\t\tlongestLms = len(subject)\n\t}\n\t// fmt.Printf(\"algs: lms score of %s is %.2f\\n\", subject, (float64(longest_lms) * 100.0 / float64(len(subject))))\n\treturn (float64(longestLms) * 100.0 / float64(len(subject)))\n}\n"
  },
  {
    "path": "service/detection/dga/lms_test.go",
    "content": "package dga\n\nimport \"testing\"\n\nfunc TestLmsScoreOfDomain(t *testing.T) {\n\tt.Parallel()\n\n\ttestDomain(t, \"g.symcd.com.\", 100, 100)\n\ttestDomain(t, \"www.google.com.\", 100, 100)\n\ttestDomain(t, \"55ttt5.12abc3.test.com.\", 68, 69)\n\ttestDomain(t, \"mbtq6opnuodp34gcrma65fxacgxv5ukr7lq6xuhr4mhoibe7.yvqptrozfbnqyemchpovw3q5xwjibuxfsgb72mix3znhpfhc.i2n7jh2gadqaadck3zs3vg3hbv5pkmwzeay4gc75etyettbb.isi5mhmowtfriu33uxzmgvjur5g2p3tloynwohfrggee6fkn.meop7kqyd5gwxxa3.er.spotify.com.\", 0, 31)\n}\n\nfunc testDomain(t *testing.T, domain string, min, max float64) {\n\tt.Helper()\n\n\tscore := LmsScoreOfDomain(domain)\n\tif score < min || score > max {\n\t\tt.Errorf(\"domain %s has scored %.2f, but should be between %.0f and %.0f\", domain, score, min, max)\n\t}\n}\n"
  },
  {
    "path": "service/firewall/api.go",
    "content": "package firewall\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/process\"\n)\n\nconst (\n\tdeniedMsgUnidentified = `%wFailed to identify the requesting process. Reload to try again.`\n\n\tdeniedMsgSystem = `%wSystem access to the Portmaster API is not permitted.\nYou can enable the Development Mode to disable API authentication for development purposes.`\n\n\tdeniedMsgUnauthorized = `%wThe requesting process is not authorized to access the Portmaster API.\nChecked process paths:\n%s\n\nThe authorized root path is %s.\nYou can enable the Development Mode to disable API authentication for development purposes.\nFor production use please create an API key in the settings.`\n\n\tdeniedMsgMisconfigured = `%wThe authentication system is misconfigured.`\n)\n\nvar (\n\tapiPortSet bool\n\tapiIP      net.IP\n\tapiPort    uint16\n)\n\nfunc prepAPIAuth() error {\n\treturn api.SetAuthenticator(apiAuthenticator)\n}\n\nfunc startAPIAuth() {\n\tvar err error\n\tapiIP, apiPort, err = netutils.ParseIPPort(apiListenAddress())\n\tif err != nil {\n\t\tlog.Warningf(\"filter: failed to parse API address for improved api auth mechanism: %s\", err)\n\t\treturn\n\t}\n\tapiPortSet = true\n\tlog.Tracef(\"filter: api port set to %d\", apiPort)\n}\n\nfunc apiAuthenticator(r *http.Request, s *http.Server) (token *api.AuthToken, err error) {\n\tif configReady.IsSet() && devMode() {\n\t\treturn &api.AuthToken{\n\t\t\tRead:  api.PermitSelf,\n\t\t\tWrite: api.PermitSelf,\n\t\t}, nil\n\t}\n\n\t// get local IP/Port\n\tlocalIP, localPort, err := netutils.ParseIPPort(s.Addr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get local IP/Port: %w\", err)\n\t}\n\t// Correct 0.0.0.0 to 127.0.0.1 to fix local process-based authentication,\n\t// if 0.0.0.0 is used as the API listen address.\n\tif localIP.Equal(net.IPv4zero) {\n\t\tlocalIP = net.IPv4(127, 0, 0, 1)\n\t}\n\n\t// get remote IP/Port\n\tremoteIP, remotePort, err := netutils.ParseIPPort(r.RemoteAddr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get remote IP/Port: %w\", err)\n\t}\n\n\t// Check if the request is even local.\n\tmyIP, err := netenv.IsMyIP(remoteIP)\n\tif err == nil && !myIP {\n\t\t// Return to caller that the request was not handled.\n\t\treturn nil, nil\n\t}\n\n\tlog.Tracer(r.Context()).Tracef(\"filter: authenticating API request from %s\", r.RemoteAddr)\n\n\t// It is important that this works, retry 5 times: every 500ms for 2.5s.\n\tvar retry bool\n\tfor range 5 {\n\t\tretry, err = authenticateAPIRequest(\n\t\t\tr.Context(),\n\t\t\t&packet.Info{\n\t\t\t\tInbound:  false, // outbound as we are looking for the process of the source address\n\t\t\t\tVersion:  packet.IPv4,\n\t\t\t\tProtocol: packet.TCP,\n\t\t\t\tSrc:      remoteIP,   // source as in the process we are looking for\n\t\t\t\tSrcPort:  remotePort, // source as in the process we are looking for\n\t\t\t\tDst:      localIP,\n\t\t\t\tDstPort:  localPort,\n\t\t\t\tPID:      process.UndefinedProcessID,\n\t\t\t},\n\t\t)\n\t\tif !retry {\n\t\t\tbreak\n\t\t}\n\t\t// wait a little\n\t\ttime.Sleep(500 * time.Millisecond)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &api.AuthToken{\n\t\tRead:  api.PermitSelf,\n\t\tWrite: api.PermitSelf,\n\t}, nil\n}\n\nfunc authenticateAPIRequest(ctx context.Context, pktInfo *packet.Info) (retry bool, err error) {\n\tvar procsChecked []string\n\tvar originalPid int\n\n\t// Get authenticated path.\n\tauthenticatedPath := module.instance.BinaryUpdates().GetMainDir()\n\tif authenticatedPath == \"\" {\n\t\treturn false, fmt.Errorf(deniedMsgMisconfigured, api.ErrAPIAccessDeniedMessage) //nolint:stylecheck // message for user\n\t}\n\t// Get real path.\n\tauthenticatedPath, err = filepath.EvalSymlinks(authenticatedPath)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(deniedMsgUnidentified, api.ErrAPIAccessDeniedMessage) //nolint:stylecheck // message for user\n\t}\n\t// Add filepath separator to confine to directory.\n\tauthenticatedPath += string(filepath.Separator)\n\n\t// Get process of request.\n\tpid, _, _ := process.GetPidOfConnection(ctx, pktInfo)\n\tif pid < 0 {\n\t\treturn false, fmt.Errorf(deniedMsgUnidentified, api.ErrAPIAccessDeniedMessage) //nolint:stylecheck // message for user\n\t}\n\tproc, err := process.GetOrFindProcess(ctx, pid)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Debugf(\"filter: failed to get process of api request: %s\", err)\n\t\toriginalPid = process.UnidentifiedProcessID\n\t} else {\n\t\toriginalPid = proc.Pid\n\t\tvar previousPid int\n\n\t\t// Find parent for up to two levels, if we don't match the path.\n\t\tcheckLevels := 2\n\tcheckLevelsLoop:\n\t\tfor i := range checkLevels + 1 {\n\t\t\t// Check for eligible path.\n\t\t\tswitch proc.Pid {\n\t\t\tcase process.UnidentifiedProcessID, process.SystemProcessID:\n\t\t\t\tbreak checkLevelsLoop\n\t\t\tdefault: // normal process\n\t\t\t\t// Check if the requesting process is in database root / updates dir.\n\t\t\t\tif realPath, err := filepath.EvalSymlinks(proc.Path); err == nil {\n\n\t\t\t\t\t// check if the client has been allowed by flag\n\t\t\t\t\tif slices.Contains(allowedClients, realPath) {\n\t\t\t\t\t\treturn false, nil\n\t\t\t\t\t}\n\n\t\t\t\t\tif strings.HasPrefix(realPath, authenticatedPath) {\n\t\t\t\t\t\treturn false, nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add checked path to list.\n\t\t\tprocsChecked = append(procsChecked, proc.Path)\n\n\t\t\t// Get the parent process.\n\t\t\tif i < checkLevels {\n\t\t\t\t// save previous PID\n\t\t\t\tpreviousPid = proc.Pid\n\n\t\t\t\t// get parent process\n\t\t\t\tproc, err = process.GetOrFindProcess(ctx, proc.ParentPid)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Tracer(ctx).Debugf(\"filter: failed to get parent process of api request: %s\", err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// abort if we are looping\n\t\t\t\tif proc.Pid == previousPid {\n\t\t\t\t\t// this also catches -1 pid loops\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch originalPid {\n\tcase process.UnidentifiedProcessID:\n\t\tlog.Tracer(ctx).Warningf(\"filter: denying api access: failed to identify process\")\n\t\treturn true, fmt.Errorf(deniedMsgUnidentified, api.ErrAPIAccessDeniedMessage) //nolint:stylecheck // message for user\n\n\tcase process.SystemProcessID:\n\t\tlog.Tracer(ctx).Warningf(\"filter: denying api access: request by system\")\n\t\treturn false, fmt.Errorf(deniedMsgSystem, api.ErrAPIAccessDeniedMessage) //nolint:stylecheck // message for user\n\n\tdefault: // normal process\n\t\tlog.Tracer(ctx).Warningf(\"filter: denying api access to %s - also checked %s (trusted root is %s)\", procsChecked[0], strings.Join(procsChecked[1:], \" \"), module.instance.BinDir())\n\t\treturn false, fmt.Errorf( //nolint:stylecheck // message for user\n\t\t\tdeniedMsgUnauthorized,\n\t\t\tapi.ErrAPIAccessDeniedMessage,\n\t\t\tstrings.Join(procsChecked, \"\\n\"),\n\t\t\tauthenticatedPath,\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "service/firewall/bypassing.go",
    "content": "package firewall\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/compat\"\n\t\"github.com/safing/portmaster/service/nameserver/nsutil\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\nvar resolverFilterLists = []string{\"17-DNS\"}\n\n// PreventBypassing checks if the connection should be denied or permitted\n// based on some bypass protection checks.\nfunc PreventBypassing(ctx context.Context, conn *network.Connection) (endpoints.EPResult, string, nsutil.Responder) {\n\t// Exclude incoming connections.\n\tif conn.Inbound {\n\t\treturn endpoints.NoMatch, \"\", nil\n\t}\n\n\t// Exclude ICMP.\n\tswitch packet.IPProtocol(conn.Entity.Protocol) { //nolint:exhaustive // Checking for specific values only.\n\tcase packet.ICMP, packet.ICMPv6:\n\t\treturn endpoints.NoMatch, \"\", nil\n\t}\n\n\t// Block firefox canary domain to disable DoH.\n\t// This MUST also affect the System Resolver, because the return value must\n\t// be correct for this to work.\n\tif strings.ToLower(conn.Entity.Domain) == \"use-application-dns.net.\" {\n\t\treturn endpoints.Denied,\n\t\t\t\"blocked canary domain to prevent enabling of DNS-over-HTTPs\",\n\t\t\tnsutil.NxDomain()\n\t}\n\n\t// Exclude DNS requests coming from the System Resolver.\n\t// This MUST also affect entities in the secure dns filter list, else the\n\t// System Resolver is wrongly accused of bypassing.\n\tif conn.Type == network.DNSRequest && conn.Process().IsSystemResolver() {\n\t\treturn endpoints.NoMatch, \"\", nil\n\t}\n\n\t// If Portmaster resolver is disabled allow requests going to system dns resolver.\n\t// And allow all connections out of the System Resolver.\n\tif module.instance.Resolver().IsDisabled() {\n\t\t// TODO(vladimir): Is there a more specific check that can be done?\n\t\tif conn.Process().IsSystemResolver() {\n\t\t\treturn endpoints.NoMatch, \"\", nil\n\t\t}\n\t\tif conn.Entity.Port == 53 && conn.Entity.IPScope.IsLocalhost() {\n\t\t\treturn endpoints.NoMatch, \"\", nil\n\t\t}\n\t}\n\n\t// Block bypass attempts using an (encrypted) DNS server.\n\tswitch {\n\tcase looksLikeOutgoingDNSRequest(conn) && module.instance.Resolver().IsDisabled():\n\t\t// Allow. Packet will be analyzed and blocked if its not a dns request, before sent.\n\t\tconn.Inspecting = true\n\t\treturn endpoints.NoMatch, \"\", nil\n\tcase conn.Entity.Port == 53:\n\t\treturn endpoints.Denied,\n\t\t\t\"blocked DNS query, manual dns setup required\",\n\t\t\tnsutil.BlockIP()\n\tcase conn.Entity.Port == 853:\n\t\t// Block connections to port 853 - DNS over TLS.\n\t\tfallthrough\n\tcase conn.Entity.MatchLists(resolverFilterLists):\n\t\t// Block connection entities in the secure dns filter list.\n\t\tcompat.ReportSecureDNSBypassIssue(conn.Process())\n\t\treturn endpoints.Denied,\n\t\t\t\"blocked rogue connection to DNS resolver\",\n\t\t\tnsutil.BlockIP()\n\t}\n\n\treturn endpoints.NoMatch, \"\", nil\n}\n\nfunc looksLikeOutgoingDNSRequest(conn *network.Connection) bool {\n\t// Outbound on remote port 53, UDP.\n\tif conn.Inbound {\n\t\treturn false\n\t}\n\tif conn.Entity.Port != 53 {\n\t\treturn false\n\t}\n\tif conn.IPProtocol != packet.UDP {\n\t\treturn false\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "service/firewall/config.go",
    "content": "package firewall\n\nimport (\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/core\"\n\t\"github.com/safing/portmaster/spn/captain\"\n)\n\n// Configuration Keys.\nvar (\n\tCfgOptionEnableFilterKey = \"filter/enable\"\n\tfilterEnabled            config.BoolOption\n\n\tCfgOptionAskWithSystemNotificationsKey   = \"filter/askWithSystemNotifications\"\n\tcfgOptionAskWithSystemNotificationsOrder = 2\n\taskWithSystemNotifications               config.BoolOption\n\n\tCfgOptionAskTimeoutKey   = \"filter/askTimeout\"\n\tcfgOptionAskTimeoutOrder = 3\n\taskTimeout               config.IntOption\n\n\tCfgOptionPermanentVerdictsKey   = \"filter/permanentVerdicts\"\n\tcfgOptionPermanentVerdictsOrder = 80\n\tpermanentVerdicts               config.BoolOption\n\n\tCfgOptionDNSQueryInterceptionKey   = \"filter/dnsQueryInterception\"\n\tcfgOptionDNSQueryInterceptionOrder = 81\n\tdnsQueryInterception               config.BoolOption\n)\n\nfunc registerConfig() error {\n\terr := config.Register(&config.Option{\n\t\tName:           \"Enable Privacy Filter\",\n\t\tKey:            CfgOptionEnableFilterKey,\n\t\tDescription:    \"Enable the Privacy Filter. If turned off, all privacy filter protections are fully disabled on this device. Not meant to be disabled in production - only turn off for testing.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   config.ReleaseLevelExperimental,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.CategoryAnnotation: \"General\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tfilterEnabled = config.Concurrent.GetAsBool(CfgOptionEnableFilterKey, true)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Permanent Verdicts\",\n\t\tKey:            CfgOptionPermanentVerdictsKey,\n\t\tDescription:    \"The Portmaster's system integration intercepts every single packet. Usually the first packet is enough for the Portmaster to set the verdict for a connection - ie. to allow or deny it. Making these verdicts permanent means that the Portmaster will tell the system integration that is does not want to see any more packets of that single connection. This brings a major performance increase.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   config.ReleaseLevelExperimental,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionPermanentVerdictsOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Advanced\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpermanentVerdicts = config.Concurrent.GetAsBool(CfgOptionPermanentVerdictsKey, true)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Seamless DNS Integration\",\n\t\tKey:            CfgOptionDNSQueryInterceptionKey,\n\t\tDescription:    \"Intercept and redirect astray DNS queries to the Portmaster's internal DNS server. This enables seamless DNS integration without having to configure the system or other software. However, this may lead to compatibility issues with other software that attempts the same.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   config.ReleaseLevelExperimental,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionDNSQueryInterceptionOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Advanced\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdnsQueryInterception = config.Concurrent.GetAsBool(CfgOptionDNSQueryInterceptionKey, true)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Prompt Desktop Notifications\",\n\t\tKey:            CfgOptionAskWithSystemNotificationsKey,\n\t\tDescription:    `In addition to showing prompt notifications in the Portmaster App, also send them to the Desktop. This requires the Portmaster Notifier to be running. Requires Desktop Notifications to be enabled.`,\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionAskWithSystemNotificationsOrder,\n\t\t\tconfig.CategoryAnnotation:     \"General\",\n\t\t\tconfig.RequiresAnnotation: config.ValueRequirement{\n\t\t\t\tKey:   notifications.CfgUseSystemNotificationsKey,\n\t\t\t\tValue: true,\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\taskWithSystemNotifications = config.Concurrent.GetAsBool(CfgOptionAskWithSystemNotificationsKey, true)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Prompt Timeout\",\n\t\tKey:            CfgOptionAskTimeoutKey,\n\t\tDescription:    \"How long the Portmaster will wait for a reply to a prompt notification. Please note that Desktop Notifications might not respect this or have their own limits.\",\n\t\tOptType:        config.OptTypeInt,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tDefaultValue:   60,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionAskTimeoutOrder,\n\t\t\tconfig.UnitAnnotation:         \"seconds\",\n\t\t\tconfig.CategoryAnnotation:     \"General\",\n\t\t},\n\t\tValidationRegex: `^[1-9][0-9]{1,5}$`,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\taskTimeout = config.Concurrent.GetAsInt(CfgOptionAskTimeoutKey, 60)\n\n\treturn nil\n}\n\n// Config variables for interception and filter module.\n// Everything is registered by the interception module, as the filter module\n// can be disabled.\nvar (\n\tdevMode          config.BoolOption\n\tapiListenAddress config.StringOption\n\n\ttunnelEnabled     config.BoolOption\n\tuseCommunityNodes config.BoolOption\n\n\tconfigReady = abool.New()\n)\n\nfunc getConfig() {\n\tdevMode = config.Concurrent.GetAsBool(core.CfgDevModeKey, false)\n\tapiListenAddress = config.GetAsString(api.CfgDefaultListenAddressKey, \"\")\n\n\ttunnelEnabled = config.Concurrent.GetAsBool(captain.CfgOptionEnableSPNKey, false)\n\tuseCommunityNodes = config.Concurrent.GetAsBool(captain.CfgOptionUseCommunityNodesKey, true)\n\n\tconfigReady.Set()\n}\n"
  },
  {
    "path": "service/firewall/dns.go",
    "content": "package firewall\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\nfunc filterDNSSection(\n\tctx context.Context,\n\tentries []dns.RR,\n\tp *profile.LayeredProfile,\n\tresolverScope netutils.IPScope,\n\tsysResolver bool,\n) ([]dns.RR, []string, int, string) {\n\t// Will be filled 1:1 most of the time.\n\tgoodEntries := make([]dns.RR, 0, len(entries))\n\n\t// Will stay empty most of the time.\n\tvar filteredRecords []string\n\n\t// keeps track of the number of valid and allowed\n\t// A and AAAA records.\n\tvar allowedAddressRecords int\n\tvar interveningOptionKey string\n\n\tfor _, rr := range entries {\n\t\t// get IP and classification\n\t\tvar ip net.IP\n\t\tswitch v := rr.(type) {\n\t\tcase *dns.A:\n\t\t\tip = v.A\n\t\tcase *dns.AAAA:\n\t\t\tip = v.AAAA\n\t\tdefault:\n\t\t\t// add non A/AAAA entries\n\t\t\t// TODO: Add support for dns.SVCB and dns.HTTPS\n\t\t\tgoodEntries = append(goodEntries, rr)\n\t\t\tcontinue\n\t\t}\n\t\tipScope := netutils.GetIPScope(ip)\n\n\t\tif p.RemoveOutOfScopeDNS() {\n\t\t\tswitch {\n\t\t\tcase ipScope.IsLocalhost():\n\t\t\t\t// No DNS should return localhost addresses\n\t\t\t\tfilteredRecords = append(filteredRecords, formatRR(rr))\n\t\t\t\tinterveningOptionKey = profile.CfgOptionRemoveOutOfScopeDNSKey\n\t\t\t\tlog.Tracer(ctx).Tracef(\"filter: RR violates resolver scope: %s\", formatRR(rr))\n\t\t\t\tcontinue\n\n\t\t\tcase resolverScope.IsGlobal() && ipScope.IsLAN() && !sysResolver:\n\t\t\t\t// No global DNS should return LAN addresses\n\t\t\t\tfilteredRecords = append(filteredRecords, formatRR(rr))\n\t\t\t\tinterveningOptionKey = profile.CfgOptionRemoveOutOfScopeDNSKey\n\t\t\t\tlog.Tracer(ctx).Tracef(\"filter: RR violates resolver scope: %s\", formatRR(rr))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif p.RemoveBlockedDNS() && !sysResolver {\n\t\t\t// filter by flags\n\t\t\tswitch {\n\t\t\tcase p.BlockScopeInternet() && ipScope.IsGlobal():\n\t\t\t\tfilteredRecords = append(filteredRecords, formatRR(rr))\n\t\t\t\tinterveningOptionKey = profile.CfgOptionBlockScopeInternetKey\n\t\t\t\tlog.Tracer(ctx).Tracef(\"filter: RR is in blocked scope Internet: %s\", formatRR(rr))\n\t\t\t\tcontinue\n\n\t\t\tcase p.BlockScopeLAN() && ipScope.IsLAN():\n\t\t\t\tfilteredRecords = append(filteredRecords, formatRR(rr))\n\t\t\t\tinterveningOptionKey = profile.CfgOptionBlockScopeLANKey\n\t\t\t\tlog.Tracer(ctx).Tracef(\"filter: RR is in blocked scope LAN: %s\", formatRR(rr))\n\t\t\t\tcontinue\n\n\t\t\tcase p.BlockScopeLocal() && ipScope.IsLocalhost():\n\t\t\t\tfilteredRecords = append(filteredRecords, formatRR(rr))\n\t\t\t\tinterveningOptionKey = profile.CfgOptionBlockScopeLocalKey\n\t\t\t\tlog.Tracer(ctx).Tracef(\"filter: RR is in blocked scope Localhost: %s\", formatRR(rr))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// TODO: filter by endpoint list (IP only)\n\t\t}\n\n\t\t// if survived, add to good entries\n\t\tallowedAddressRecords++\n\t\tgoodEntries = append(goodEntries, rr)\n\t}\n\n\treturn goodEntries, filteredRecords, allowedAddressRecords, interveningOptionKey\n}\n\nfunc filterDNSResponse(\n\tctx context.Context,\n\tconn *network.Connection,\n\tp *profile.LayeredProfile,\n\trrCache *resolver.RRCache,\n\tsysResolver bool,\n) *resolver.RRCache {\n\t// do not modify own queries\n\tif conn.Process().Pid == ownPID {\n\t\treturn rrCache\n\t}\n\n\t// check if DNS response filtering is completely turned off\n\tif !p.RemoveOutOfScopeDNS() && !p.RemoveBlockedDNS() {\n\t\treturn rrCache\n\t}\n\n\tvar filteredRecords []string\n\tvar validIPs int\n\tvar interveningOptionKey string\n\n\trrCache.Answer, filteredRecords, validIPs, interveningOptionKey = filterDNSSection(ctx, rrCache.Answer, p, rrCache.Resolver.IPScope, sysResolver)\n\tif len(filteredRecords) > 0 {\n\t\trrCache.FilteredEntries = append(rrCache.FilteredEntries, filteredRecords...)\n\t}\n\n\t// Don't count the valid IPs in the extra section.\n\trrCache.Extra, filteredRecords, _, _ = filterDNSSection(ctx, rrCache.Extra, p, rrCache.Resolver.IPScope, sysResolver)\n\tif len(filteredRecords) > 0 {\n\t\trrCache.FilteredEntries = append(rrCache.FilteredEntries, filteredRecords...)\n\t}\n\n\tif len(rrCache.FilteredEntries) > 0 {\n\t\trrCache.Filtered = true\n\t\tif validIPs == 0 {\n\t\t\tswitch interveningOptionKey {\n\t\t\tcase profile.CfgOptionBlockScopeInternetKey:\n\t\t\t\tconn.Block(\"Internet access blocked\", interveningOptionKey)\n\t\t\tcase profile.CfgOptionBlockScopeLANKey:\n\t\t\t\tconn.Block(\"LAN access blocked\", interveningOptionKey)\n\t\t\tcase profile.CfgOptionBlockScopeLocalKey:\n\t\t\t\tconn.Block(\"Localhost access blocked\", interveningOptionKey)\n\t\t\tcase profile.CfgOptionRemoveOutOfScopeDNSKey:\n\t\t\t\tconn.Block(\"DNS global/private split-view violation\", interveningOptionKey)\n\t\t\tdefault:\n\t\t\t\tconn.Block(\"DNS response only contained to-be-blocked IPs\", interveningOptionKey)\n\t\t\t}\n\n\t\t\treturn rrCache\n\t\t}\n\t}\n\n\treturn rrCache\n}\n\n// FilterResolvedDNS filters a dns response according to the application\n// profile and settings.\nfunc FilterResolvedDNS(\n\tctx context.Context,\n\tconn *network.Connection,\n\tq *resolver.Query,\n\trrCache *resolver.RRCache,\n) *resolver.RRCache {\n\t// Check if we have a process and profile.\n\tlayeredProfile := conn.Process().Profile()\n\tif layeredProfile == nil {\n\t\tlog.Tracer(ctx).Warning(\"unknown process or profile\")\n\t\treturn nil\n\t}\n\n\t// Don't filter env responses.\n\tif rrCache.Resolver.Type == resolver.ServerTypeEnv {\n\t\treturn rrCache\n\t}\n\n\t// special grant for connectivity domains\n\tif checkConnectivityDomain(ctx, conn, layeredProfile, nil) {\n\t\t// returns true if check triggered\n\t\treturn rrCache\n\t}\n\n\t// Only filter critical things if request comes from the system resolver.\n\tsysResolver := conn.Process().IsSystemResolver()\n\n\t// Filter dns records and return if the query is blocked.\n\trrCache = filterDNSResponse(ctx, conn, layeredProfile, rrCache, sysResolver)\n\tif conn.Verdict == network.VerdictBlock {\n\t\treturn rrCache\n\t}\n\n\t// Block by CNAMEs.\n\tif !sysResolver {\n\t\tmayBlockCNAMEs(ctx, conn, layeredProfile)\n\t}\n\n\treturn rrCache\n}\n\nfunc mayBlockCNAMEs(ctx context.Context, conn *network.Connection, p *profile.LayeredProfile) bool {\n\t// if we have CNAMEs and the profile is configured to filter them\n\t// we need to re-check the lists and endpoints here\n\tif p.FilterCNAMEs() {\n\t\tconn.Entity.ResetLists()\n\t\tconn.Entity.EnableCNAMECheck(ctx, true)\n\n\t\tresult, reason := p.MatchEndpoint(ctx, conn.Entity)\n\t\tif result == endpoints.Denied {\n\t\t\tconn.BlockWithContext(reason.String(), profile.CfgOptionFilterCNAMEKey, reason.Context())\n\t\t\treturn true\n\t\t}\n\n\t\tif result == endpoints.NoMatch {\n\t\t\tresult, reason = p.MatchFilterLists(ctx, conn.Entity)\n\t\t\tif result == endpoints.Denied {\n\t\t\t\tconn.BlockWithContext(reason.String(), profile.CfgOptionFilterCNAMEKey, reason.Context())\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\n// UpdateIPsAndCNAMEs saves all the IP->Name mappings to the cache database and\n// updates the CNAMEs in the Connection's Entity.\nfunc UpdateIPsAndCNAMEs(q *resolver.Query, rrCache *resolver.RRCache, conn *network.Connection) {\n\t// Sanity check input, as this is called from defer.\n\tif q == nil || rrCache == nil {\n\t\treturn\n\t}\n\n\t// Get profileID for scoping IPInfo.\n\tvar profileID string\n\tlocalProfile := conn.Process().Profile().LocalProfile()\n\tswitch localProfile.ID {\n\tcase profile.UnidentifiedProfileID,\n\t\tprofile.SystemResolverProfileID:\n\t\tprofileID = resolver.IPInfoProfileScopeGlobal\n\tdefault:\n\t\tprofileID = localProfile.ID\n\t}\n\n\t// Collect IPs and CNAMEs.\n\tcnames := make(map[string]string)\n\tips := make([]net.IP, 0, len(rrCache.Answer))\n\n\tfor _, rr := range append(rrCache.Answer, rrCache.Extra...) {\n\t\tswitch v := rr.(type) {\n\t\tcase *dns.CNAME:\n\t\t\tcnames[v.Hdr.Name] = v.Target\n\n\t\tcase *dns.A:\n\t\t\tips = append(ips, v.A)\n\n\t\tcase *dns.AAAA:\n\t\t\tips = append(ips, v.AAAA)\n\n\t\tcase *dns.SVCB:\n\t\t\tif len(v.Target) >= 2 { // Ignore \"\" and \".\".\n\t\t\t\tcnames[v.Hdr.Name] = v.Target\n\t\t\t}\n\t\t\tfor _, pair := range v.Value {\n\t\t\t\tswitch svcbParam := pair.(type) {\n\t\t\t\tcase *dns.SVCBIPv4Hint:\n\t\t\t\t\tips = append(ips, svcbParam.Hint...)\n\t\t\t\tcase *dns.SVCBIPv6Hint:\n\t\t\t\t\tips = append(ips, svcbParam.Hint...)\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *dns.HTTPS:\n\t\t\tif len(v.Target) >= 2 { // Ignore \"\" and \".\".\n\t\t\t\tcnames[v.Hdr.Name] = v.Target\n\t\t\t}\n\t\t\tfor _, pair := range v.Value {\n\t\t\t\tswitch svcbParam := pair.(type) {\n\t\t\t\tcase *dns.SVCBIPv4Hint:\n\t\t\t\t\tips = append(ips, svcbParam.Hint...)\n\t\t\t\tcase *dns.SVCBIPv6Hint:\n\t\t\t\t\tips = append(ips, svcbParam.Hint...)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Create new record for this IP.\n\trecord := resolver.ResolvedDomain{\n\t\tDomain:            q.FQDN,\n\t\tResolver:          rrCache.Resolver,\n\t\tDNSRequestContext: rrCache.ToDNSRequestContext(),\n\t\tExpires:           rrCache.Expires,\n\t}\n\t// Process CNAMEs\n\trecord.AddCNAMEs(cnames)\n\t// Link connection with cnames.\n\tif conn.Type == network.DNSRequest {\n\t\tconn.Entity.CNAME = record.CNAMEs\n\t}\n\n\tSaveIPsInCache(ips, profileID, record)\n}\n\n// formatRR is a friendlier alternative to miekg/dns.RR.String().\nfunc formatRR(rr dns.RR) string {\n\treturn strings.ReplaceAll(rr.String(), \"\\t\", \" \")\n}\n\n// SaveIPsInCache saves the provided ips in the dns cashe assoseted with the record Domain and CNAMEs.\nfunc SaveIPsInCache(ips []net.IP, profileID string, record resolver.ResolvedDomain) {\n\t// Package IPs and CNAMEs into IPInfo structs.\n\tfor _, ip := range ips {\n\t\t// Never save domain attributions for localhost IPs.\n\t\tif netutils.GetIPScope(ip) == netutils.HostLocal {\n\t\t\tcontinue\n\t\t}\n\n\t\tipString := ip.String()\n\t\tinfo, err := resolver.GetIPInfo(profileID, ipString)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\t\tlog.Errorf(\"nameserver: failed to search for IP info record: %s\", err)\n\t\t\t}\n\n\t\t\tinfo = &resolver.IPInfo{\n\t\t\t\tIP:        ipString,\n\t\t\t\tProfileID: profileID,\n\t\t\t}\n\t\t}\n\n\t\t// Add the new record to the resolved domains for this IP and scope.\n\t\tinfo.AddDomain(record)\n\n\t\t// Save if the record is new or has been updated.\n\t\tif err := info.Save(); err != nil {\n\t\t\tlog.Errorf(\"nameserver: failed to save IP info record: %s\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/firewall/inspection/inspection.go",
    "content": "package inspection\n\nimport (\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n//nolint:golint,stylecheck\nconst (\n\tDO_NOTHING uint8 = iota\n\tBLOCK_PACKET\n\tDROP_PACKET\n\tBLOCK_CONN\n\tDROP_CONN\n\tSTOP_INSPECTING\n)\n\ntype inspectorFn func(*network.Connection, packet.Packet) uint8\n\nvar (\n\tinspectors      []inspectorFn\n\tinspectorNames  []string\n\tinspectVerdicts []network.Verdict\n\tinspectorsLock  sync.Mutex\n)\n\n// RegisterInspector registers a traffic inspector.\nfunc RegisterInspector(name string, inspector inspectorFn, inspectVerdict network.Verdict) (index int) {\n\tinspectorsLock.Lock()\n\tdefer inspectorsLock.Unlock()\n\tindex = len(inspectors)\n\tinspectors = append(inspectors, inspector)\n\tinspectorNames = append(inspectorNames, name)\n\tinspectVerdicts = append(inspectVerdicts, inspectVerdict)\n\treturn\n}\n\n// RunInspectors runs all the applicable inspectors on the given packet.\nfunc RunInspectors(conn *network.Connection, pkt packet.Packet) (network.Verdict, bool) {\n\t// inspectorsLock.Lock()\n\t// defer inspectorsLock.Unlock()\n\n\tactiveInspectors := conn.GetActiveInspectors()\n\tif activeInspectors == nil {\n\t\tactiveInspectors = make([]bool, len(inspectors))\n\t\tconn.SetActiveInspectors(activeInspectors)\n\t}\n\n\tinspectorData := conn.GetInspectorData()\n\tif inspectorData == nil {\n\t\tinspectorData = make(map[uint8]interface{})\n\t\tconn.SetInspectorData(inspectorData)\n\t}\n\n\tcontinueInspection := false\n\tverdict := network.VerdictUndecided\n\n\tfor key, skip := range activeInspectors {\n\n\t\tif skip {\n\t\t\tcontinue\n\t\t}\n\n\t\t// check if the active verdict is already past the inspection criteria.\n\t\tif conn.Verdict > inspectVerdicts[key] {\n\t\t\tactiveInspectors[key] = true\n\t\t\tcontinue\n\t\t}\n\n\t\taction := inspectors[key](conn, pkt) // Actually run inspector\n\t\tswitch action {\n\t\tcase DO_NOTHING:\n\t\t\tif verdict < network.VerdictAccept {\n\t\t\t\tverdict = network.VerdictAccept\n\t\t\t}\n\t\t\tcontinueInspection = true\n\t\tcase BLOCK_PACKET:\n\t\t\tif verdict < network.VerdictBlock {\n\t\t\t\tverdict = network.VerdictBlock\n\t\t\t}\n\t\t\tcontinueInspection = true\n\t\tcase DROP_PACKET:\n\t\t\tverdict = network.VerdictDrop\n\t\t\tcontinueInspection = true\n\t\tcase BLOCK_CONN:\n\t\t\tconn.SetVerdict(network.VerdictBlock, \"\", \"\", nil)\n\t\t\tverdict = conn.Verdict\n\t\t\tactiveInspectors[key] = true\n\t\tcase DROP_CONN:\n\t\t\tconn.SetVerdict(network.VerdictDrop, \"\", \"\", nil)\n\t\t\tverdict = conn.Verdict\n\t\t\tactiveInspectors[key] = true\n\t\tcase STOP_INSPECTING:\n\t\t\tactiveInspectors[key] = true\n\t\t}\n\n\t}\n\n\treturn verdict, continueInspection\n}\n"
  },
  {
    "path": "service/firewall/interception/dnsmonitor/etwlink_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage dnsmonitor\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/integration\"\n\t\"golang.org/x/sys/windows\"\n)\n\ntype ETWSession struct {\n\ti *integration.ETWFunctions\n\n\tshutdownGuard atomic.Bool\n\tshutdownMutex sync.Mutex\n\n\ttraceEnded chan struct{}\n\n\tstate uintptr\n}\n\n// NewSession creates new ETW event listener and initializes it. This is a low level interface, make sure to call DestroySession when you are done using it.\nfunc NewSession(etwInterface *integration.ETWFunctions, callback func(domain string, pid uint32, result string)) (*ETWSession, error) {\n\tif etwInterface == nil {\n\t\treturn nil, fmt.Errorf(\"etw interface was nil\")\n\t}\n\tetwSession := &ETWSession{\n\t\ti:          etwInterface,\n\t\ttraceEnded: make(chan struct{}),\n\t}\n\n\t// Make sure session from previous instances are not running.\n\t_ = etwSession.i.StopOldSession()\n\n\t// Initialize notification activated callback\n\twin32Callback := windows.NewCallback(func(domain *uint16, pid uint32, result *uint16) uintptr {\n\t\tcallback(windows.UTF16PtrToString(domain), pid, windows.UTF16PtrToString(result))\n\t\treturn 0\n\t})\n\t// The function only allocates memory it will not fail.\n\tetwSession.state = etwSession.i.CreateState(win32Callback)\n\n\t// Make sure DestroySession is called even if caller forgets to call it.\n\t// TODO: (stenya) Finalizer directly calls i.DestroySession() bypassing synchronization in DestroySession().\n\t//                This could crash if StartTrace() is running. Consider using s.DestroySession() instead.\n\truntime.SetFinalizer(etwSession, func(s *ETWSession) {\n\t\t_ = s.i.DestroySession(s.state)\n\t})\n\n\t// Initialize session.\n\terr := etwSession.i.InitializeSession(etwSession.state)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize session: %q\", err)\n\t}\n\n\treturn etwSession, nil\n}\n\n// StartTrace starts the tracing session of dns events. This is a blocking call. It will not return until the trace is stopped.\nfunc (l *ETWSession) StartTrace() error {\n\tdefer close(l.traceEnded)\n\treturn l.i.StartTrace(l.state)\n}\n\n// IsRunning returns true if DestroySession has NOT been called.\nfunc (l *ETWSession) IsRunning() bool {\n\treturn !l.shutdownGuard.Load()\n}\n\n// FlushTrace flushes the trace buffer.\nfunc (l *ETWSession) FlushTrace() error {\n\tif l.i == nil {\n\t\treturn fmt.Errorf(\"session not initialized\")\n\t}\n\n\tl.shutdownMutex.Lock()\n\tdefer l.shutdownMutex.Unlock()\n\n\t// Make sure session is still running.\n\tif l.shutdownGuard.Load() {\n\t\treturn nil\n\t}\n\n\treturn l.i.FlushTrace(l.state)\n}\n\n// StopTrace stops the trace. This will cause StartTrace to return.\nfunc (l *ETWSession) StopTrace() error {\n\treturn l.i.StopTrace(l.state)\n}\n\n// DestroySession closes the session and frees the allocated memory. Listener cannot be used after this function is called.\nfunc (l *ETWSession) DestroySession() error {\n\tif l.i == nil {\n\t\treturn fmt.Errorf(\"session not initialized\")\n\t}\n\tl.shutdownMutex.Lock()\n\tdefer l.shutdownMutex.Unlock()\n\n\tif l.shutdownGuard.Swap(true) {\n\t\treturn nil\n\t}\n\n\t// Waiting for StartTrace() to return\n\tselect {\n\tcase <-l.traceEnded:\n\tcase <-time.After(15 * time.Second):\n\t\tlog.Warning(\"DNSMonitor: (ETWSession) Timeout waiting for trace to end before destroying session\")\n\t}\n\n\terr := l.i.DestroySession(l.state)\n\tif err != nil {\n\t\treturn err\n\t}\n\tl.state = 0\n\treturn nil\n}\n"
  },
  {
    "path": "service/firewall/interception/dnsmonitor/eventlistener.go",
    "content": "//go:build !linux && !windows\n// +build !linux,!windows\n\npackage dnsmonitor\n\ntype Listener struct{}\n\nfunc newListener(_ *DNSMonitor) (*Listener, error) {\n\treturn &Listener{}, nil\n}\n\nfunc (l *Listener) flush() error {\n\t// Nothing to flush\n\treturn nil\n}\n\nfunc (l *Listener) stop() error {\n\treturn nil\n}\n"
  },
  {
    "path": "service/firewall/interception/dnsmonitor/eventlistener_linux.go",
    "content": "//go:build linux\n// +build linux\n\npackage dnsmonitor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\n\t\"github.com/miekg/dns\"\n\t\"github.com/varlink/go/varlink\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\ntype Listener struct {\n\tvarlinkConn *varlink.Connection\n}\n\nfunc newListener(module *DNSMonitor) (*Listener, error) {\n\t// Set source of the resolver.\n\tResolverInfo.Source = resolver.ServerSourceSystemd\n\n\t// Check if the system has systemd-resolver.\n\t_, err := os.Stat(\"/run/systemd/resolve/io.systemd.Resolve.Monitor\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"system does not support systemd resolver monitor\")\n\t}\n\n\tlistener := &Listener{}\n\n\trestartAttempts := 0\n\n\tmodule.mgr.Go(\"systemd-resolver-event-listener\", func(w *mgr.WorkerCtx) error {\n\t\t// Abort initialization if the connection failed after too many tries.\n\t\tif restartAttempts > 10 {\n\t\t\treturn nil\n\t\t}\n\t\trestartAttempts += 1\n\n\t\t// Initialize varlink connection\n\t\tvarlinkConn, err := varlink.NewConnection(module.mgr.Ctx(), \"unix:/run/systemd/resolve/io.systemd.Resolve.Monitor\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to connect to systemd-resolver varlink service: %w\", err)\n\t\t}\n\t\tdefer func() {\n\t\t\tif varlinkConn != nil {\n\t\t\t\terr = varlinkConn.Close()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(\"dnsmonitor: failed to close varlink connection: %s\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\n\t\tlistener.varlinkConn = varlinkConn\n\t\t// Subscribe to the dns query events\n\t\treceive, err := listener.varlinkConn.Send(w.Ctx(), \"io.systemd.Resolve.Monitor.SubscribeQueryResults\", nil, varlink.More)\n\t\tif err != nil {\n\t\t\tvar varlinkErr *varlink.Error\n\t\t\tif errors.As(err, &varlinkErr) {\n\t\t\t\treturn fmt.Errorf(\"failed to issue Varlink call: %+v\", varlinkErr.Parameters)\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"failed to issue Varlink call: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor {\n\t\t\tqueryResult := QueryResult{}\n\t\t\t// Receive the next event from the resolver.\n\t\t\tflags, err := receive(w.Ctx(), &queryResult)\n\t\t\tif err != nil {\n\t\t\t\tvar varlinkErr *varlink.Error\n\t\t\t\tif errors.As(err, &varlinkErr) {\n\t\t\t\t\treturn fmt.Errorf(\"failed to receive Varlink reply: %+v\", varlinkErr.Parameters)\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"failed to receive Varlink reply: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if the reply indicates the end of the stream\n\t\t\tif flags&varlink.Continues == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Ignore if there is no question.\n\t\t\tif queryResult.Question == nil || len(*queryResult.Question) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Protmaster self check\n\t\t\tdomain := (*queryResult.Question)[0].Name\n\t\t\tif processIfSelfCheckDomain(dns.Fqdn(domain)) {\n\t\t\t\t// Not need to process result.\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif queryResult.Rcode != nil {\n\t\t\t\tcontinue // Ignore DNS errors\n\t\t\t}\n\n\t\t\tlistener.processAnswer(domain, &queryResult)\n\t\t}\n\t\treturn nil\n\t})\n\treturn listener, nil\n}\n\nfunc (l *Listener) flush() error {\n\t// Nothing to flush\n\treturn nil\n}\n\nfunc (l *Listener) stop() error {\n\treturn nil\n}\n\nfunc (l *Listener) processAnswer(domain string, queryResult *QueryResult) {\n\t// Allocated data struct for the parsed result.\n\tcnames := make(map[string]string)\n\tips := make([]net.IP, 0, 5)\n\n\t// Check if the query is valid\n\tif queryResult.Answer == nil {\n\t\treturn\n\t}\n\n\t// Go trough each answer entry.\n\tfor _, a := range *queryResult.Answer {\n\t\tif a.RR.Address != nil {\n\t\t\tip := net.IP(*a.RR.Address)\n\t\t\t// Answer contains ip address.\n\t\t\tips = append(ips, ip)\n\n\t\t} else if a.RR.Name != nil {\n\t\t\t// Answer is a CNAME.\n\t\t\tcnames[domain] = *a.RR.Name\n\t\t}\n\t}\n\n\tsaveDomain(domain, ips, cnames, resolver.IPInfoProfileScopeGlobal)\n}\n"
  },
  {
    "path": "service/firewall/interception/dnsmonitor/eventlistener_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage dnsmonitor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\ntype Listener struct {\n\tetw *ETWSession\n}\n\nfunc newListener(module *DNSMonitor) (*Listener, error) {\n\t// Set source of the resolver.\n\tResolverInfo.Source = resolver.ServerSourceETW\n\n\tlistener := &Listener{}\n\t// Initialize new dns event session.\n\terr := initializeSessions(module, listener)\n\tif err != nil {\n\t\t// Listen for event if the dll has been loaded\n\t\tmodule.instance.OSIntegration().OnInitializedEvent.AddCallback(\"loader-listener\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\t\terr = initializeSessions(module, listener)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\treturn true, nil\n\t\t})\n\t}\n\treturn listener, nil\n}\n\nfunc initializeSessions(module *DNSMonitor, listener *Listener) error {\n\tvar err error\n\tlistener.etw, err = NewSession(module.instance.OSIntegration().GetETWInterface(), listener.processEvent)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Start listener\n\tmodule.mgr.Go(\"etw-dns-event-listener\", func(w *mgr.WorkerCtx) error {\n\t\treturn listener.etw.StartTrace()\n\t})\n\treturn nil\n}\n\nfunc (l *Listener) flush() error {\n\tif l.etw == nil {\n\t\treturn fmt.Errorf(\"etw not initialized\")\n\t}\n\treturn l.etw.FlushTrace()\n}\n\nfunc (l *Listener) stop() error {\n\tif l == nil {\n\t\treturn fmt.Errorf(\"listener is nil\")\n\t}\n\tif l.etw == nil {\n\t\treturn fmt.Errorf(\"invalid etw session\")\n\t}\n\t// Stop and destroy trace. Destroy should be called even if stop fails for some reason.\n\terr := l.etw.StopTrace()\n\terr2 := l.etw.DestroySession()\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"StopTrace failed: %w\", err)\n\t}\n\n\tif err2 != nil {\n\t\treturn fmt.Errorf(\"DestroySession failed: %w\", err2)\n\t}\n\treturn nil\n}\n\nfunc (l *Listener) processEvent(domain string, pid uint32, result string) {\n\tif processIfSelfCheckDomain(dns.Fqdn(domain)) {\n\t\t// Not need to process result.\n\t\treturn\n\t}\n\n\t// Ignore empty results\n\tif len(result) == 0 {\n\t\treturn\n\t}\n\n\tprofileScope := resolver.IPInfoProfileScopeGlobal\n\t// Get the profile ID if the process can be found\n\tif proc, err := process.GetOrFindProcess(context.Background(), int(pid)); err == nil {\n\t\tif profile := proc.Profile(); profile != nil {\n\t\t\tif localProfile := profile.LocalProfile(); localProfile != nil {\n\t\t\t\tprofileScope = localProfile.ID\n\t\t\t}\n\t\t}\n\t}\n\tcnames := make(map[string]string)\n\tips := []net.IP{}\n\n\tresultArray := strings.Split(result, \";\")\n\tfor _, r := range resultArray {\n\t\t// For results other than IP addresses, the string starts with \"type:\"\n\t\tif strings.HasPrefix(r, \"type:\") {\n\t\t\tdnsValueArray := strings.Split(r, \" \")\n\t\t\tif len(dnsValueArray) < 3 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Ignore everything except CNAME records\n\t\t\tif value, err := strconv.ParseInt(dnsValueArray[1], 10, 16); err == nil && value == int64(dns.TypeCNAME) {\n\t\t\t\tcnames[domain] = dnsValueArray[2]\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If the event doesn't start with \"type:\", it's an IP address\n\t\t\tip := net.ParseIP(r)\n\t\t\tif ip != nil {\n\t\t\t\tips = append(ips, ip)\n\t\t\t}\n\t\t}\n\t}\n\tsaveDomain(domain, ips, cnames, profileScope)\n}\n"
  },
  {
    "path": "service/firewall/interception/dnsmonitor/module.go",
    "content": "package dnsmonitor\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/compat\"\n\t\"github.com/safing/portmaster/service/integration\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\nvar ResolverInfo = resolver.ResolverInfo{\n\tName: \"SystemResolver\",\n\tType: resolver.ServerTypeMonitor,\n}\n\ntype DNSMonitor struct {\n\tinstance instance\n\tmgr      *mgr.Manager\n\n\tlistener *Listener\n}\n\n// Manager returns the module manager.\nfunc (dl *DNSMonitor) Manager() *mgr.Manager {\n\treturn dl.mgr\n}\n\n// Start starts the module.\nfunc (dl *DNSMonitor) Start() error {\n\t// Initialize dns event listener\n\tvar err error\n\tdl.listener, err = newListener(dl)\n\tif err != nil {\n\t\tlog.Warningf(\"dnsmonitor: failed to start dns listener: %s\", err)\n\t}\n\n\treturn nil\n}\n\n// Stop stops the module.\nfunc (dl *DNSMonitor) Stop() error {\n\tif dl.listener != nil {\n\t\terr := dl.listener.stop()\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"dnsmonitor: failed to close listener: %s\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Flush flushes the buffer forcing all events to be processed.\nfunc (dl *DNSMonitor) Flush() error {\n\treturn dl.listener.flush()\n}\n\nfunc saveDomain(domain string, ips []net.IP, cnames map[string]string, profileScope string) {\n\tfqdn := dns.Fqdn(domain)\n\t// Create new record for this IP.\n\trecord := resolver.ResolvedDomain{\n\t\tDomain:            fqdn,\n\t\tResolver:          &ResolverInfo,\n\t\tDNSRequestContext: &resolver.DNSRequestContext{},\n\t\tExpires:           0,\n\t}\n\n\t// Process cnames\n\trecord.AddCNAMEs(cnames)\n\n\t// Add to cache\n\tsaveIPsInCache(ips, profileScope, record)\n}\n\nfunc New(instance instance) (*DNSMonitor, error) {\n\t// Initialize module\n\tm := mgr.New(\"DNSMonitor\")\n\tmodule := &DNSMonitor{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tOSIntegration() *integration.OSIntegration\n}\n\nfunc processIfSelfCheckDomain(fqdn string) bool {\n\t// Check for compat check dns request.\n\tif strings.HasSuffix(fqdn, compat.DNSCheckInternalDomainScope) {\n\t\tsubdomain := strings.TrimSuffix(fqdn, compat.DNSCheckInternalDomainScope)\n\t\t_ = compat.SubmitDNSCheckDomain(subdomain)\n\t\tlog.Infof(\"dnsmonitor: self-check domain received\")\n\t\t// No need to parse the answer.\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// saveIPsInCache saves the provided ips in the dns cashe assoseted with the record Domain and CNAMEs.\nfunc saveIPsInCache(ips []net.IP, profileID string, record resolver.ResolvedDomain) {\n\t// Package IPs and CNAMEs into IPInfo structs.\n\tfor _, ip := range ips {\n\t\t// Never save domain attributions for localhost IPs.\n\t\tif netutils.GetIPScope(ip) == netutils.HostLocal {\n\t\t\tcontinue\n\t\t}\n\n\t\tipString := ip.String()\n\t\tinfo, err := resolver.GetIPInfo(profileID, ipString)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\t\tlog.Errorf(\"dnsmonitor: failed to search for IP info record: %s\", err)\n\t\t\t}\n\n\t\t\tinfo = &resolver.IPInfo{\n\t\t\t\tIP:        ipString,\n\t\t\t\tProfileID: profileID,\n\t\t\t}\n\t\t}\n\n\t\t// Add the new record to the resolved domains for this IP and scope.\n\t\tinfo.AddDomain(record)\n\n\t\t// Save if the record is new or has been updated.\n\t\tif err := info.Save(); err != nil {\n\t\t\tlog.Errorf(\"dnsmonitor: failed to save IP info record: %s\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/firewall/interception/dnsmonitor/varlinktypes.go",
    "content": "//go:build linux\n// +build linux\n\npackage dnsmonitor\n\n// List of struct that define the systemd-resolver varlink dns event protocol.\n// Source: `sudo varlinkctl introspect /run/systemd/resolve/io.systemd.Resolve.Monitor io.systemd.Resolve.Monitor`\n\ntype ResourceKey struct {\n\tClass int    `json:\"class\"`\n\tType  int    `json:\"type\"`\n\tName  string `json:\"name\"`\n}\n\ntype ResourceRecord struct {\n\tKey     ResourceKey `json:\"key\"`\n\tName    *string     `json:\"name,omitempty\"`\n\tAddress *[]byte     `json:\"address,omitempty\"`\n\t// Rest of the fields are not used.\n\t// Priority     *int        `json:\"priority,omitempty\"`\n\t// Weight       *int        `json:\"weight,omitempty\"`\n\t// Port         *int        `json:\"port,omitempty\"`\n\t// CPU          *string     `json:\"cpu,omitempty\"`\n\t// OS           *string     `json:\"os,omitempty\"`\n\t// Items        *[]string   `json:\"items,omitempty\"`\n\t// MName        *string     `json:\"mname,omitempty\"`\n\t// RName        *string     `json:\"rname,omitempty\"`\n\t// Serial       *int        `json:\"serial,omitempty\"`\n\t// Refresh      *int        `json:\"refresh,omitempty\"`\n\t// Expire       *int        `json:\"expire,omitempty\"`\n\t// Minimum      *int        `json:\"minimum,omitempty\"`\n\t// Exchange     *string     `json:\"exchange,omitempty\"`\n\t// Version      *int        `json:\"version,omitempty\"`\n\t// Size         *int        `json:\"size,omitempty\"`\n\t// HorizPre     *int        `json:\"horiz_pre,omitempty\"`\n\t// VertPre      *int        `json:\"vert_pre,omitempty\"`\n\t// Latitude     *int        `json:\"latitude,omitempty\"`\n\t// Longitude    *int        `json:\"longitude,omitempty\"`\n\t// Altitude     *int        `json:\"altitude,omitempty\"`\n\t// KeyTag       *int        `json:\"key_tag,omitempty\"`\n\t// Algorithm    *int        `json:\"algorithm,omitempty\"`\n\t// DigestType   *int        `json:\"digest_type,omitempty\"`\n\t// Digest       *string     `json:\"digest,omitempty\"`\n\t// FPType       *int        `json:\"fptype,omitempty\"`\n\t// Fingerprint  *string     `json:\"fingerprint,omitempty\"`\n\t// Flags        *int        `json:\"flags,omitempty\"`\n\t// Protocol     *int        `json:\"protocol,omitempty\"`\n\t// DNSKey       *string     `json:\"dnskey,omitempty\"`\n\t// Signer       *string     `json:\"signer,omitempty\"`\n\t// TypeCovered  *int        `json:\"type_covered,omitempty\"`\n\t// Labels       *int        `json:\"labels,omitempty\"`\n\t// OriginalTTL  *int        `json:\"original_ttl,omitempty\"`\n\t// Expiration   *int        `json:\"expiration,omitempty\"`\n\t// Inception    *int        `json:\"inception,omitempty\"`\n\t// Signature    *string     `json:\"signature,omitempty\"`\n\t// NextDomain   *string     `json:\"next_domain,omitempty\"`\n\t// Types        *[]int      `json:\"types,omitempty\"`\n\t// Iterations   *int        `json:\"iterations,omitempty\"`\n\t// Salt         *string     `json:\"salt,omitempty\"`\n\t// Hash         *string     `json:\"hash,omitempty\"`\n\t// CertUsage    *int        `json:\"cert_usage,omitempty\"`\n\t// Selector     *int        `json:\"selector,omitempty\"`\n\t// MatchingType *int        `json:\"matching_type,omitempty\"`\n\t// Data         *string     `json:\"data,omitempty\"`\n\t// Tag          *string     `json:\"tag,omitempty\"`\n\t// Value        *string     `json:\"value,omitempty\"`\n}\n\ntype Answer struct {\n\tRR      *ResourceRecord `json:\"rr,omitempty\"`\n\tRaw     string          `json:\"raw\"`\n\tIfIndex *int            `json:\"ifindex,omitempty\"`\n}\n\ntype QueryResult struct {\n\tReady              *bool          `json:\"ready,omitempty\"`\n\tState              *string        `json:\"state,omitempty\"`\n\tRcode              *int           `json:\"rcode,omitempty\"`\n\tErrno              *int           `json:\"errno,omitempty\"`\n\tQuestion           *[]ResourceKey `json:\"question,omitempty\"`\n\tCollectedQuestions *[]ResourceKey `json:\"collectedQuestions,omitempty\"`\n\tAnswer             *[]Answer      `json:\"answer,omitempty\"`\n}\n"
  },
  {
    "path": "service/firewall/interception/ebpf/bandwidth/bpf_bpfeb.go",
    "content": "// Code generated by bpf2go; DO NOT EDIT.\n//go:build arm64be || armbe || mips || mips64 || mips64p32 || ppc64 || s390 || s390x || sparc || sparc64\n\npackage ebpf\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/cilium/ebpf\"\n)\n\ntype bpfSkInfo struct {\n\tRx       uint64\n\tTx       uint64\n\tReported uint64\n}\n\ntype bpfSkKey struct {\n\tSrcIp    [4]uint32\n\tDstIp    [4]uint32\n\tSrcPort  uint16\n\tDstPort  uint16\n\tProtocol uint8\n\tIpv6     uint8\n\t_        [2]byte\n}\n\n// loadBpf returns the embedded CollectionSpec for bpf.\nfunc loadBpf() (*ebpf.CollectionSpec, error) {\n\treader := bytes.NewReader(_BpfBytes)\n\tspec, err := ebpf.LoadCollectionSpecFromReader(reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't load bpf: %w\", err)\n\t}\n\n\treturn spec, err\n}\n\n// loadBpfObjects loads bpf and converts it into a struct.\n//\n// The following types are suitable as obj argument:\n//\n//\t*bpfObjects\n//\t*bpfPrograms\n//\t*bpfMaps\n//\n// See ebpf.CollectionSpec.LoadAndAssign documentation for details.\nfunc loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error {\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn spec.LoadAndAssign(obj, opts)\n}\n\n// bpfSpecs contains maps and programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfSpecs struct {\n\tbpfProgramSpecs\n\tbpfMapSpecs\n}\n\n// bpfSpecs contains programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfProgramSpecs struct {\n\tSocketOperations *ebpf.ProgramSpec `ebpf:\"socket_operations\"`\n\tUdpRecvmsg       *ebpf.ProgramSpec `ebpf:\"udp_recvmsg\"`\n\tUdpSendmsg       *ebpf.ProgramSpec `ebpf:\"udp_sendmsg\"`\n\tUdpv6Recvmsg     *ebpf.ProgramSpec `ebpf:\"udpv6_recvmsg\"`\n\tUdpv6Sendmsg     *ebpf.ProgramSpec `ebpf:\"udpv6_sendmsg\"`\n}\n\n// bpfMapSpecs contains maps before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfMapSpecs struct {\n\tPmBandwidthMap *ebpf.MapSpec `ebpf:\"pm_bandwidth_map\"`\n}\n\n// bpfObjects contains all objects after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfObjects struct {\n\tbpfPrograms\n\tbpfMaps\n}\n\nfunc (o *bpfObjects) Close() error {\n\treturn _BpfClose(\n\t\t&o.bpfPrograms,\n\t\t&o.bpfMaps,\n\t)\n}\n\n// bpfMaps contains all maps after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfMaps struct {\n\tPmBandwidthMap *ebpf.Map `ebpf:\"pm_bandwidth_map\"`\n}\n\nfunc (m *bpfMaps) Close() error {\n\treturn _BpfClose(\n\t\tm.PmBandwidthMap,\n\t)\n}\n\n// bpfPrograms contains all programs after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfPrograms struct {\n\tSocketOperations *ebpf.Program `ebpf:\"socket_operations\"`\n\tUdpRecvmsg       *ebpf.Program `ebpf:\"udp_recvmsg\"`\n\tUdpSendmsg       *ebpf.Program `ebpf:\"udp_sendmsg\"`\n\tUdpv6Recvmsg     *ebpf.Program `ebpf:\"udpv6_recvmsg\"`\n\tUdpv6Sendmsg     *ebpf.Program `ebpf:\"udpv6_sendmsg\"`\n}\n\nfunc (p *bpfPrograms) Close() error {\n\treturn _BpfClose(\n\t\tp.SocketOperations,\n\t\tp.UdpRecvmsg,\n\t\tp.UdpSendmsg,\n\t\tp.Udpv6Recvmsg,\n\t\tp.Udpv6Sendmsg,\n\t)\n}\n\nfunc _BpfClose(closers ...io.Closer) error {\n\tfor _, closer := range closers {\n\t\tif err := closer.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Do not access this directly.\n//\n//go:embed bpf_bpfeb.o\nvar _BpfBytes []byte\n"
  },
  {
    "path": "service/firewall/interception/ebpf/bandwidth/bpf_bpfel.go",
    "content": "// Code generated by bpf2go; DO NOT EDIT.\n//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64\n\npackage ebpf\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/cilium/ebpf\"\n)\n\ntype bpfSkInfo struct {\n\tRx       uint64\n\tTx       uint64\n\tReported uint64\n}\n\ntype bpfSkKey struct {\n\tSrcIp    [4]uint32\n\tDstIp    [4]uint32\n\tSrcPort  uint16\n\tDstPort  uint16\n\tProtocol uint8\n\tIpv6     uint8\n\t_        [2]byte\n}\n\n// loadBpf returns the embedded CollectionSpec for bpf.\nfunc loadBpf() (*ebpf.CollectionSpec, error) {\n\treader := bytes.NewReader(_BpfBytes)\n\tspec, err := ebpf.LoadCollectionSpecFromReader(reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't load bpf: %w\", err)\n\t}\n\n\treturn spec, err\n}\n\n// loadBpfObjects loads bpf and converts it into a struct.\n//\n// The following types are suitable as obj argument:\n//\n//\t*bpfObjects\n//\t*bpfPrograms\n//\t*bpfMaps\n//\n// See ebpf.CollectionSpec.LoadAndAssign documentation for details.\nfunc loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error {\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn spec.LoadAndAssign(obj, opts)\n}\n\n// bpfSpecs contains maps and programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfSpecs struct {\n\tbpfProgramSpecs\n\tbpfMapSpecs\n}\n\n// bpfSpecs contains programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfProgramSpecs struct {\n\tSocketOperations *ebpf.ProgramSpec `ebpf:\"socket_operations\"`\n\tUdpRecvmsg       *ebpf.ProgramSpec `ebpf:\"udp_recvmsg\"`\n\tUdpSendmsg       *ebpf.ProgramSpec `ebpf:\"udp_sendmsg\"`\n\tUdpv6Recvmsg     *ebpf.ProgramSpec `ebpf:\"udpv6_recvmsg\"`\n\tUdpv6Sendmsg     *ebpf.ProgramSpec `ebpf:\"udpv6_sendmsg\"`\n}\n\n// bpfMapSpecs contains maps before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfMapSpecs struct {\n\tPmBandwidthMap *ebpf.MapSpec `ebpf:\"pm_bandwidth_map\"`\n}\n\n// bpfObjects contains all objects after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfObjects struct {\n\tbpfPrograms\n\tbpfMaps\n}\n\nfunc (o *bpfObjects) Close() error {\n\treturn _BpfClose(\n\t\t&o.bpfPrograms,\n\t\t&o.bpfMaps,\n\t)\n}\n\n// bpfMaps contains all maps after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfMaps struct {\n\tPmBandwidthMap *ebpf.Map `ebpf:\"pm_bandwidth_map\"`\n}\n\nfunc (m *bpfMaps) Close() error {\n\treturn _BpfClose(\n\t\tm.PmBandwidthMap,\n\t)\n}\n\n// bpfPrograms contains all programs after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfPrograms struct {\n\tSocketOperations *ebpf.Program `ebpf:\"socket_operations\"`\n\tUdpRecvmsg       *ebpf.Program `ebpf:\"udp_recvmsg\"`\n\tUdpSendmsg       *ebpf.Program `ebpf:\"udp_sendmsg\"`\n\tUdpv6Recvmsg     *ebpf.Program `ebpf:\"udpv6_recvmsg\"`\n\tUdpv6Sendmsg     *ebpf.Program `ebpf:\"udpv6_sendmsg\"`\n}\n\nfunc (p *bpfPrograms) Close() error {\n\treturn _BpfClose(\n\t\tp.SocketOperations,\n\t\tp.UdpRecvmsg,\n\t\tp.UdpSendmsg,\n\t\tp.Udpv6Recvmsg,\n\t\tp.Udpv6Sendmsg,\n\t)\n}\n\nfunc _BpfClose(closers ...io.Closer) error {\n\tfor _, closer := range closers {\n\t\tif err := closer.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Do not access this directly.\n//\n//go:embed bpf_bpfel.o\nvar _BpfBytes []byte\n"
  },
  {
    "path": "service/firewall/interception/ebpf/bandwidth/interface.go",
    "content": "package ebpf\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net\"\n\t\"path/filepath\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/cilium/ebpf\"\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/rlimit\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -cflags \"-O2 -g -Wall -Werror\" bpf ../programs/bandwidth.c\n\nvar ebpfLoadingFailed atomic.Uint32\n\n// BandwidthStatsWorker monitors connection bandwidth using ebpf.\nfunc BandwidthStatsWorker(ctx context.Context, collectInterval time.Duration, bandwidthUpdates chan *packet.BandwidthUpdate) error {\n\t// Allow the current process to lock memory for eBPF resources.\n\terr := rlimit.RemoveMemlock()\n\tif err != nil {\n\t\tif ebpfLoadingFailed.Add(1) >= 5 {\n\t\t\tlog.Warningf(\"ebpf: failed to remove memlock 5 times, giving up with error %s\", err)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"ebpf: failed to remove memlock: %w\", err)\n\t}\n\n\t// Load pre-compiled programs and maps into the kernel.\n\tobjs := bpfObjects{}\n\tif err := loadBpfObjects(&objs, nil); err != nil {\n\t\tif ebpfLoadingFailed.Add(1) >= 5 {\n\t\t\tlog.Warningf(\"ebpf: failed to load ebpf object 5 times, giving up with error %s\", err)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"ebpf: failed to load ebpf object: %w\", err)\n\t}\n\tdefer objs.Close() //nolint:errcheck\n\n\t// Find the cgroup path\n\tpath, err := findCgroupPath()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to find cgroup paths: %w\", err)\n\t}\n\n\t// Attach socket options for monitoring connections\n\tsockOptionsLink, err := link.AttachCgroup(link.CgroupOptions{\n\t\tPath:    path,\n\t\tProgram: objs.bpfPrograms.SocketOperations,\n\t\tAttach:  ebpf.AttachCGroupSockOps,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to open module sockops: %w\", err)\n\t}\n\tdefer sockOptionsLink.Close() //nolint:errcheck\n\n\t// Attach Udp Ipv4 recive message tracing\n\tudpv4RMLink, err := link.AttachTracing(link.TracingOptions{\n\t\tProgram: objs.bpfPrograms.UdpRecvmsg,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to open trace Udp IPv4 recvmsg: %w\", err)\n\t}\n\tdefer udpv4RMLink.Close() //nolint:errcheck\n\n\t// Attach UDP IPv4 send message tracing\n\tudpv4SMLink, err := link.AttachTracing(link.TracingOptions{\n\t\tProgram: objs.bpfPrograms.UdpSendmsg,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to open trace Udp IPv4 sendmsg: %w\", err)\n\t}\n\tdefer udpv4SMLink.Close() //nolint:errcheck\n\n\t// Attach UDP IPv6 receive message tracing\n\tudpv6RMLink, err := link.AttachTracing(link.TracingOptions{\n\t\tProgram: objs.bpfPrograms.Udpv6Recvmsg,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to open trace Udp IPv6 recvmsg: %w\", err)\n\t}\n\tdefer udpv6RMLink.Close() //nolint:errcheck\n\n\t// Attach UDP IPv6 send message tracing\n\tudpv6SMLink, err := link.AttachTracing(link.TracingOptions{\n\t\tProgram: objs.bpfPrograms.Udpv6Sendmsg,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to open trace Udp IPv6 sendmsg: %w\", err)\n\t}\n\tdefer udpv6SMLink.Close() //nolint:errcheck\n\n\t// Setup ticker.\n\tticker := time.NewTicker(collectInterval)\n\tdefer ticker.Stop()\n\n\t// Collect bandwidth at every tick.\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\treportBandwidth(ctx, objs, bandwidthUpdates)\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n// reportBandwidth reports the bandwidth to the given updates channel.\nfunc reportBandwidth(ctx context.Context, objs bpfObjects, bandwidthUpdates chan *packet.BandwidthUpdate) {\n\tvar (\n\t\tskKey   bpfSkKey\n\t\tskInfo  bpfSkInfo\n\t\tupdated int\n\t\tskipped int\n\t)\n\n\titer := objs.bpfMaps.PmBandwidthMap.Iterate()\n\tfor iter.Next(&skKey, &skInfo) {\n\t\t// Check if already reported.\n\t\tif skInfo.Reported >= 1 {\n\t\t\tskipped++\n\t\t\tcontinue\n\t\t}\n\t\t// Mark as reported and update the map.\n\t\tskInfo.Reported = 1\n\t\tif err := objs.bpfMaps.PmBandwidthMap.Update(&skKey, &skInfo, ebpf.UpdateExist); err != nil {\n\t\t\tlog.Debugf(\"ebpf: failed to mark bandwidth map entry as reported: %s\", err)\n\t\t}\n\n\t\tconnID := packet.CreateConnectionID(\n\t\t\tpacket.IPProtocol(skKey.Protocol),\n\t\t\tconvertArrayToIP(skKey.SrcIp, skKey.Ipv6 == 1), skKey.SrcPort,\n\t\t\tconvertArrayToIP(skKey.DstIp, skKey.Ipv6 == 1), skKey.DstPort,\n\t\t\tfalse,\n\t\t)\n\t\tupdate := &packet.BandwidthUpdate{\n\t\t\tConnID:        connID,\n\t\t\tBytesReceived: skInfo.Rx,\n\t\t\tBytesSent:     skInfo.Tx,\n\t\t\tMethod:        packet.Absolute,\n\t\t}\n\t\tselect {\n\t\tcase bandwidthUpdates <- update:\n\t\t\tupdated++\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tdefault:\n\t\t\tlog.Warningf(\"ebpf: bandwidth update queue is full (updated=%d, skipped=%d), ignoring rest of batch\", updated, skipped)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// findCgroupPath returns the default unified path of the cgroup.\nfunc findCgroupPath() (string, error) {\n\tcgroupPath := \"/sys/fs/cgroup\"\n\n\tvar st syscall.Statfs_t\n\terr := syscall.Statfs(cgroupPath, &st)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tisCgroupV2Enabled := st.Type == unix.CGROUP2_SUPER_MAGIC\n\tif !isCgroupV2Enabled {\n\t\tcgroupPath = filepath.Join(cgroupPath, \"unified\")\n\t}\n\treturn cgroupPath, nil\n}\n\n// convertArrayToIP converts an array of uint32 values to a net.IP address.\nfunc convertArrayToIP(input [4]uint32, ipv6 bool) net.IP {\n\tif !ipv6 {\n\t\taddressBuf := make([]byte, 4)\n\t\tbinary.LittleEndian.PutUint32(addressBuf, input[0])\n\t\treturn net.IP(addressBuf)\n\t} else {\n\t\taddressBuf := make([]byte, 16)\n\t\tfor i := range 4 {\n\t\t\tbinary.LittleEndian.PutUint32(addressBuf[i*4:i*4+4], input[i])\n\t\t}\n\t\treturn net.IP(addressBuf)\n\t}\n}\n"
  },
  {
    "path": "service/firewall/interception/ebpf/connection_listener/bpf_bpfeb.go",
    "content": "// Code generated by bpf2go; DO NOT EDIT.\n//go:build mips || mips64 || ppc64 || s390x\n\npackage ebpf\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/cilium/ebpf\"\n)\n\ntype bpfEvent struct {\n\tSaddr     [4]uint32\n\tDaddr     [4]uint32\n\tSport     uint16\n\tDport     uint16\n\tPid       uint32\n\tIpVersion uint8\n\tProtocol  uint8\n\tDirection uint8\n\t_         [1]byte\n}\n\n// loadBpf returns the embedded CollectionSpec for bpf.\nfunc loadBpf() (*ebpf.CollectionSpec, error) {\n\treader := bytes.NewReader(_BpfBytes)\n\tspec, err := ebpf.LoadCollectionSpecFromReader(reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't load bpf: %w\", err)\n\t}\n\n\treturn spec, err\n}\n\n// loadBpfObjects loads bpf and converts it into a struct.\n//\n// The following types are suitable as obj argument:\n//\n//\t*bpfObjects\n//\t*bpfPrograms\n//\t*bpfMaps\n//\n// See ebpf.CollectionSpec.LoadAndAssign documentation for details.\nfunc loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error {\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn spec.LoadAndAssign(obj, opts)\n}\n\n// bpfSpecs contains maps and programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfSpecs struct {\n\tbpfProgramSpecs\n\tbpfMapSpecs\n}\n\n// bpfSpecs contains programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfProgramSpecs struct {\n\tTcpConnect   *ebpf.ProgramSpec `ebpf:\"tcp_connect\"`\n\tUdpV4Connect *ebpf.ProgramSpec `ebpf:\"udp_v4_connect\"`\n\tUdpV6Connect *ebpf.ProgramSpec `ebpf:\"udp_v6_connect\"`\n}\n\n// bpfMapSpecs contains maps before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfMapSpecs struct {\n\tPmConnectionEvents *ebpf.MapSpec `ebpf:\"pm_connection_events\"`\n}\n\n// bpfObjects contains all objects after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfObjects struct {\n\tbpfPrograms\n\tbpfMaps\n}\n\nfunc (o *bpfObjects) Close() error {\n\treturn _BpfClose(\n\t\t&o.bpfPrograms,\n\t\t&o.bpfMaps,\n\t)\n}\n\n// bpfMaps contains all maps after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfMaps struct {\n\tPmConnectionEvents *ebpf.Map `ebpf:\"pm_connection_events\"`\n}\n\nfunc (m *bpfMaps) Close() error {\n\treturn _BpfClose(\n\t\tm.PmConnectionEvents,\n\t)\n}\n\n// bpfPrograms contains all programs after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfPrograms struct {\n\tTcpConnect   *ebpf.Program `ebpf:\"tcp_connect\"`\n\tUdpV4Connect *ebpf.Program `ebpf:\"udp_v4_connect\"`\n\tUdpV6Connect *ebpf.Program `ebpf:\"udp_v6_connect\"`\n}\n\nfunc (p *bpfPrograms) Close() error {\n\treturn _BpfClose(\n\t\tp.TcpConnect,\n\t\tp.UdpV4Connect,\n\t\tp.UdpV6Connect,\n\t)\n}\n\nfunc _BpfClose(closers ...io.Closer) error {\n\tfor _, closer := range closers {\n\t\tif err := closer.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Do not access this directly.\n//\n//go:embed bpf_bpfeb.o\nvar _BpfBytes []byte\n"
  },
  {
    "path": "service/firewall/interception/ebpf/connection_listener/bpf_bpfel.go",
    "content": "// Code generated by bpf2go; DO NOT EDIT.\n//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64\n\npackage ebpf\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/cilium/ebpf\"\n)\n\ntype bpfEvent struct {\n\tSaddr     [4]uint32\n\tDaddr     [4]uint32\n\tSport     uint16\n\tDport     uint16\n\tPid       uint32\n\tIpVersion uint8\n\tProtocol  uint8\n\tDirection uint8\n\t_         [1]byte\n}\n\n// loadBpf returns the embedded CollectionSpec for bpf.\nfunc loadBpf() (*ebpf.CollectionSpec, error) {\n\treader := bytes.NewReader(_BpfBytes)\n\tspec, err := ebpf.LoadCollectionSpecFromReader(reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't load bpf: %w\", err)\n\t}\n\n\treturn spec, err\n}\n\n// loadBpfObjects loads bpf and converts it into a struct.\n//\n// The following types are suitable as obj argument:\n//\n//\t*bpfObjects\n//\t*bpfPrograms\n//\t*bpfMaps\n//\n// See ebpf.CollectionSpec.LoadAndAssign documentation for details.\nfunc loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error {\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn spec.LoadAndAssign(obj, opts)\n}\n\n// bpfSpecs contains maps and programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfSpecs struct {\n\tbpfProgramSpecs\n\tbpfMapSpecs\n}\n\n// bpfSpecs contains programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfProgramSpecs struct {\n\tTcpConnect   *ebpf.ProgramSpec `ebpf:\"tcp_connect\"`\n\tUdpV4Connect *ebpf.ProgramSpec `ebpf:\"udp_v4_connect\"`\n\tUdpV6Connect *ebpf.ProgramSpec `ebpf:\"udp_v6_connect\"`\n}\n\n// bpfMapSpecs contains maps before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfMapSpecs struct {\n\tPmConnectionEvents *ebpf.MapSpec `ebpf:\"pm_connection_events\"`\n}\n\n// bpfObjects contains all objects after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfObjects struct {\n\tbpfPrograms\n\tbpfMaps\n}\n\nfunc (o *bpfObjects) Close() error {\n\treturn _BpfClose(\n\t\t&o.bpfPrograms,\n\t\t&o.bpfMaps,\n\t)\n}\n\n// bpfMaps contains all maps after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfMaps struct {\n\tPmConnectionEvents *ebpf.Map `ebpf:\"pm_connection_events\"`\n}\n\nfunc (m *bpfMaps) Close() error {\n\treturn _BpfClose(\n\t\tm.PmConnectionEvents,\n\t)\n}\n\n// bpfPrograms contains all programs after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfPrograms struct {\n\tTcpConnect   *ebpf.Program `ebpf:\"tcp_connect\"`\n\tUdpV4Connect *ebpf.Program `ebpf:\"udp_v4_connect\"`\n\tUdpV6Connect *ebpf.Program `ebpf:\"udp_v6_connect\"`\n}\n\nfunc (p *bpfPrograms) Close() error {\n\treturn _BpfClose(\n\t\tp.TcpConnect,\n\t\tp.UdpV4Connect,\n\t\tp.UdpV6Connect,\n\t)\n}\n\nfunc _BpfClose(closers ...io.Closer) error {\n\tfor _, closer := range closers {\n\t\tif err := closer.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Do not access this directly.\n//\n//go:embed bpf_bpfel.o\nvar _BpfBytes []byte\n"
  },
  {
    "path": "service/firewall/interception/ebpf/connection_listener/worker.go",
    "content": "package ebpf\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/cilium/ebpf\"\n\t\"github.com/cilium/ebpf/btf\"\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/ringbuf\"\n\t\"github.com/cilium/ebpf/rlimit\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -cflags \"-O2 -g -Wall -Werror\" -type Event bpf ../programs/monitor.c\n\nvar ebpfLoadingFailed atomic.Uint32\n\n// ConnectionListenerWorker listens to new connections using ebpf.\nfunc ConnectionListenerWorker(ctx context.Context, packets chan packet.Packet) error {\n\t// Allow the current process to lock memory for eBPF resources.\n\tif err := rlimit.RemoveMemlock(); err != nil {\n\t\tif ebpfLoadingFailed.Add(1) >= 5 {\n\t\t\tlog.Warningf(\"ebpf: failed to remove memlock 5 times, giving up with error %s\", err)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"ebpf: failed to remove ebpf memlock: %w\", err)\n\t}\n\n\t// Load pre-compiled programs and maps into the kernel.\n\tobjs := bpfObjects{}\n\tif err := loadBpfObjects_Ex(&objs, nil); err != nil {\n\t\tif ebpfLoadingFailed.Add(1) >= 5 {\n\t\t\tlog.Warningf(\"ebpf: failed to load ebpf object 5 times, giving up with error %s\", err)\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"ebpf: failed to load ebpf object: %w\", err)\n\t}\n\tdefer objs.Close() //nolint:errcheck\n\n\t// Create a link to the tcp_connect program.\n\tlinkTCPConnect, err := link.AttachTracing(link.TracingOptions{\n\t\tProgram: objs.bpfPrograms.TcpConnect,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to attach to tcp_v4_connect: %w\", err)\n\t}\n\tdefer linkTCPConnect.Close() //nolint:errcheck\n\n\t// Create a link to the udp_v4_connect program.\n\tlinkUDPV4, err := link.AttachTracing(link.TracingOptions{\n\t\tProgram: objs.bpfPrograms.UdpV4Connect,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to attach to udp_v4_connect: %w\", err)\n\t}\n\tdefer linkUDPV4.Close() //nolint:errcheck\n\n\t// Create a link to the udp_v6_connect program.\n\tlinkUDPV6, err := link.AttachTracing(link.TracingOptions{\n\t\tProgram: objs.bpfPrograms.UdpV6Connect,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to attach to udp_v6_connect: %w\", err)\n\t}\n\tdefer linkUDPV6.Close() //nolint:errcheck\n\n\t// Create new reader to read events.\n\trd, err := ringbuf.NewReader(objs.bpfMaps.PmConnectionEvents)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to open ring buffer: %w\", err)\n\t}\n\tdefer rd.Close() //nolint:errcheck\n\n\t// Start watcher to close the reader when the context is canceled.\n\t// TODO: Can we put this into a worker?\n\tgo func() {\n\t\t<-ctx.Done()\n\n\t\tif err := rd.Close(); err != nil {\n\t\t\tlog.Errorf(\"ebpf: failed closing ringbuf reader: %s\", err)\n\t\t}\n\t}()\n\n\tfor {\n\t\t// Read next event\n\t\trecord, err := rd.Read()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, ringbuf.ErrClosed) {\n\t\t\t\t// Normal return\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tlog.Errorf(\"ebpf: failed to read from ring buffer: %s\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tvar event bpfEvent\n\t\t// Parse the ringbuf event entry into a bpfEvent structure.\n\t\tif err := binary.Read(bytes.NewBuffer(record.RawSample), binary.BigEndian, &event); err != nil {\n\t\t\tlog.Errorf(\"ebpf: failed to parse ringbuf event: %s\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tpkt := packet.NewInfoPacket(packet.Info{\n\t\t\tInbound:  event.Direction == 1,\n\t\t\tInTunnel: false,\n\t\t\tVersion:  packet.IPVersion(event.IpVersion),\n\t\t\tProtocol: packet.IPProtocol(event.Protocol),\n\t\t\tSrcPort:  event.Sport,\n\t\t\tDstPort:  event.Dport,\n\t\t\tSrc:      convertArrayToIPv4(event.Saddr, packet.IPVersion(event.IpVersion)),\n\t\t\tDst:      convertArrayToIPv4(event.Daddr, packet.IPVersion(event.IpVersion)),\n\t\t\tPID:      int(event.Pid),\n\t\t\tSeenAt:   time.Now(),\n\t\t})\n\t\tif isEventValid(event) {\n\t\t\t// DEBUG:\n\t\t\t// log.Debugf(\"ebpf: received valid connect event: PID: %d Conn: %s\", pkt.Info().PID, pkt)\n\t\t\tpackets <- pkt\n\t\t} else {\n\t\t\tlog.Warningf(\"ebpf: received invalid connect event: PID: %d Conn: %s\", pkt.Info().PID, pkt)\n\t\t}\n\t}\n}\n\n// loadBpfObjects_Ex loads eBPF objects with kernel-aware attach point selection.\n// (it extends the standard loadBpfObjects())\n//\n// This enhanced loader automatically detects available kernel functions and selects\n// appropriate attach points for maximum compatibility across kernel versions. It handles\n// the transition from legacy function names (e.g., ip4_datagram_connect) to modern ones\n// (e.g., udp_connect) introduced in Linux 6.13+.\nfunc loadBpfObjects_Ex(objs interface{}, opts *ebpf.CollectionOptions) error {\n\t// Load pre-compiled programs\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to load ebpf spec: %w\", err)\n\t}\n\t// Modify the attach points of the eBPF programs, if necessary.\n\tif err := modifyProgramsAttachPoints(spec); err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to modify program attach points: %w\", err)\n\t}\n\t// Load the eBPF programs and maps into the kernel.\n\tif err := spec.LoadAndAssign(objs, opts); err != nil {\n\t\treturn fmt.Errorf(\"ebpf: failed to load and assign ebpf objects: %w\", err)\n\t}\n\treturn nil\n}\n\n// modifyProgramAttachPoints modifies the attach points of the eBPF programs, if necessary.\n// This is needed to ensure compatibility with different kernel versions.\nfunc modifyProgramsAttachPoints(spec *ebpf.CollectionSpec) error {\n\t// Load the kernel spec\n\tkspec, err := btf.LoadKernelSpec()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Function to update the attach point to a single BPF program\n\tupdateIfNeeded := func(bpfProgramName, attachPoint, attachPointLegacy string) error {\n\t\tps, ok := spec.Programs[bpfProgramName]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"ebpf: program %q not found in spec\", bpfProgramName)\n\t\t}\n\t\tvar fn *btf.Func\n\t\tif err := kspec.TypeByName(attachPoint, &fn); err == nil {\n\t\t\tif !strings.EqualFold(ps.AttachTo, attachPoint) {\n\t\t\t\tps.AttachTo = attachPoint\n\t\t\t\tlog.Debugf(\"ebpf: using attach point %q for %q program\", attachPoint, bpfProgramName)\n\t\t\t}\n\t\t} else {\n\t\t\tif !strings.EqualFold(ps.AttachTo, attachPointLegacy) {\n\t\t\t\tps.AttachTo = attachPointLegacy\n\t\t\t\tlog.Debugf(\"ebpf: using legacy attach point %q for %q program\", attachPointLegacy, bpfProgramName)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\t// 'udp_v4_connect' program is designed to attach to the `udp_connect` function in the kernel.\n\t// If the kernel does not support this function, we fall back to using the `ip4_datagram_connect` function.\n\t//\n\t// Kernel compatibility note:\n\t// - Linux kernels < 6.13: use `ip4_datagram_connect` function\n\t//   https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997\n\t// - Linux kernels >= 6.13: function renamed to `udp_connect`\n\t//   https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131\n\tconst (\n\t\tudpV4ConnectProgramName       = \"udp_v4_connect\"\n\t\tudpV4ConnectAttachPoint       = \"udp_connect\"\n\t\tudpV4ConnectAttachPointLegacy = \"ip4_datagram_connect\"\n\t)\n\tif err := updateIfNeeded(udpV4ConnectProgramName, udpV4ConnectAttachPoint, udpV4ConnectAttachPointLegacy); err != nil {\n\t\treturn err\n\t}\n\n\t// 'udp_v6_connect' program is designed to attach to the `udpv6_connect` function in the kernel.\n\t// If the kernel does not support this function, we fall back to using the `ip6_datagram_connect` function.\n\t//\n\t// Kernel compatibility note:\n\t// - Linux kernels < 6.13: use `ip6_datagram_connect` function\n\t//   https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997\n\t// - Linux kernels >= 6.13: function renamed to `udpv6_connect`\n\t//   https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131\n\tconst (\n\t\tudpV6ConnectProgramName       = \"udp_v6_connect\"\n\t\tudpV6ConnectAttachPoint       = \"udpv6_connect\"\n\t\tudpV6ConnectAttachPointLegacy = \"ip6_datagram_connect\"\n\t)\n\tif err := updateIfNeeded(udpV6ConnectProgramName, udpV6ConnectAttachPoint, udpV6ConnectAttachPointLegacy); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// isEventValid checks whether the given bpfEvent is valid or not.\n// It returns true if the event is valid, otherwise false.\nfunc isEventValid(event bpfEvent) bool {\n\t// Check if the destination port is 0\n\tif event.Dport == 0 {\n\t\treturn false\n\t}\n\n\t// Check if the source port is 0\n\tif event.Sport == 0 {\n\t\treturn false\n\t}\n\n\t// Check if the process ID is 0\n\tif event.Pid == 0 {\n\t\treturn false\n\t}\n\n\t// If the IP version is IPv4\n\tif event.IpVersion == 4 {\n\t\tif event.Saddr[0] == 0 {\n\t\t\treturn false\n\t\t}\n\n\t\tif event.Daddr[0] == 0 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// convertArrayToIPv4 converts an array of uint32 values to an IPv4 net.IP address.\nfunc convertArrayToIPv4(input [4]uint32, ipVersion packet.IPVersion) net.IP {\n\tif ipVersion == packet.IPv4 {\n\t\taddressBuf := make([]byte, 4)\n\t\tbinary.LittleEndian.PutUint32(addressBuf, input[0])\n\t\treturn net.IP(addressBuf)\n\t}\n\n\taddressBuf := make([]byte, 16)\n\tfor i := range 4 {\n\t\tbinary.LittleEndian.PutUint32(addressBuf[i*4:i*4+4], input[i])\n\t}\n\treturn net.IP(addressBuf)\n}\n"
  },
  {
    "path": "service/firewall/interception/ebpf/exec/bpf_bpfeb.go",
    "content": "// Code generated by bpf2go; DO NOT EDIT.\n//go:build arm64be || armbe || mips || mips64 || mips64p32 || ppc64 || s390 || s390x || sparc || sparc64\n\npackage ebpf\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/cilium/ebpf\"\n)\n\n// loadBpf returns the embedded CollectionSpec for bpf.\nfunc loadBpf() (*ebpf.CollectionSpec, error) {\n\treader := bytes.NewReader(_BpfBytes)\n\tspec, err := ebpf.LoadCollectionSpecFromReader(reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't load bpf: %w\", err)\n\t}\n\n\treturn spec, err\n}\n\n// loadBpfObjects loads bpf and converts it into a struct.\n//\n// The following types are suitable as obj argument:\n//\n//\t*bpfObjects\n//\t*bpfPrograms\n//\t*bpfMaps\n//\n// See ebpf.CollectionSpec.LoadAndAssign documentation for details.\nfunc loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error {\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn spec.LoadAndAssign(obj, opts)\n}\n\n// bpfSpecs contains maps and programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfSpecs struct {\n\tbpfProgramSpecs\n\tbpfMapSpecs\n}\n\n// bpfSpecs contains programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfProgramSpecs struct {\n\tEnterExecve *ebpf.ProgramSpec `ebpf:\"enter_execve\"`\n}\n\n// bpfMapSpecs contains maps before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfMapSpecs struct {\n\tPmExecMap *ebpf.MapSpec `ebpf:\"pm_exec_map\"`\n}\n\n// bpfObjects contains all objects after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfObjects struct {\n\tbpfPrograms\n\tbpfMaps\n}\n\nfunc (o *bpfObjects) Close() error {\n\treturn _BpfClose(\n\t\t&o.bpfPrograms,\n\t\t&o.bpfMaps,\n\t)\n}\n\n// bpfMaps contains all maps after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfMaps struct {\n\tPmExecMap *ebpf.Map `ebpf:\"pm_exec_map\"`\n}\n\nfunc (m *bpfMaps) Close() error {\n\treturn _BpfClose(\n\t\tm.PmExecMap,\n\t)\n}\n\n// bpfPrograms contains all programs after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfPrograms struct {\n\tEnterExecve *ebpf.Program `ebpf:\"enter_execve\"`\n}\n\nfunc (p *bpfPrograms) Close() error {\n\treturn _BpfClose(\n\t\tp.EnterExecve,\n\t)\n}\n\nfunc _BpfClose(closers ...io.Closer) error {\n\tfor _, closer := range closers {\n\t\tif err := closer.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Do not access this directly.\n//\n//go:embed bpf_bpfeb.o\nvar _BpfBytes []byte\n"
  },
  {
    "path": "service/firewall/interception/ebpf/exec/bpf_bpfel.go",
    "content": "// Code generated by bpf2go; DO NOT EDIT.\n//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64\n\npackage ebpf\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/cilium/ebpf\"\n)\n\n// loadBpf returns the embedded CollectionSpec for bpf.\nfunc loadBpf() (*ebpf.CollectionSpec, error) {\n\treader := bytes.NewReader(_BpfBytes)\n\tspec, err := ebpf.LoadCollectionSpecFromReader(reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't load bpf: %w\", err)\n\t}\n\n\treturn spec, err\n}\n\n// loadBpfObjects loads bpf and converts it into a struct.\n//\n// The following types are suitable as obj argument:\n//\n//\t*bpfObjects\n//\t*bpfPrograms\n//\t*bpfMaps\n//\n// See ebpf.CollectionSpec.LoadAndAssign documentation for details.\nfunc loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error {\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn spec.LoadAndAssign(obj, opts)\n}\n\n// bpfSpecs contains maps and programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfSpecs struct {\n\tbpfProgramSpecs\n\tbpfMapSpecs\n}\n\n// bpfSpecs contains programs before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfProgramSpecs struct {\n\tEnterExecve *ebpf.ProgramSpec `ebpf:\"enter_execve\"`\n}\n\n// bpfMapSpecs contains maps before they are loaded into the kernel.\n//\n// It can be passed ebpf.CollectionSpec.Assign.\ntype bpfMapSpecs struct {\n\tPmExecMap *ebpf.MapSpec `ebpf:\"pm_exec_map\"`\n}\n\n// bpfObjects contains all objects after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfObjects struct {\n\tbpfPrograms\n\tbpfMaps\n}\n\nfunc (o *bpfObjects) Close() error {\n\treturn _BpfClose(\n\t\t&o.bpfPrograms,\n\t\t&o.bpfMaps,\n\t)\n}\n\n// bpfMaps contains all maps after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfMaps struct {\n\tPmExecMap *ebpf.Map `ebpf:\"pm_exec_map\"`\n}\n\nfunc (m *bpfMaps) Close() error {\n\treturn _BpfClose(\n\t\tm.PmExecMap,\n\t)\n}\n\n// bpfPrograms contains all programs after they have been loaded into the kernel.\n//\n// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign.\ntype bpfPrograms struct {\n\tEnterExecve *ebpf.Program `ebpf:\"enter_execve\"`\n}\n\nfunc (p *bpfPrograms) Close() error {\n\treturn _BpfClose(\n\t\tp.EnterExecve,\n\t)\n}\n\nfunc _BpfClose(closers ...io.Closer) error {\n\tfor _, closer := range closers {\n\t\tif err := closer.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Do not access this directly.\n//\n//go:embed bpf_bpfel.o\nvar _BpfBytes []byte\n"
  },
  {
    "path": "service/firewall/interception/ebpf/exec/exec.go",
    "content": "package ebpf\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/ringbuf\"\n\t\"github.com/cilium/ebpf/rlimit\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -cflags \"-O2 -g -Wall -Werror\" bpf ../programs/exec.c\n\n// These constants are defined in `bpf/handler.c` and must be kept in sync.\nconst (\n\targlen  = 32\n\targsize = 1024\n)\n\nvar errTracerClosed = errors.New(\"tracer is closed\")\n\n// event contains details about each exec call, sent from the eBPF program to\n// userspace through a perf ring buffer. This type must be kept in sync with\n// `event_t` in `bpf/handler.c`.\ntype event struct {\n\t// Details about the process being launched.\n\tFilename [argsize]byte\n\tArgv     [arglen][argsize]byte\n\tArgc     uint32\n\tUID      uint32\n\tGID      uint32\n\tPID      uint32\n\n\t// Name of the calling process.\n\tComm [argsize]byte\n}\n\n// Event contains data about each exec event with many fields for easy\n// filtering and logging.\ntype Event struct {\n\tFilename string `json:\"filename\"`\n\t// Argv contains the raw argv supplied to the process, including argv[0]\n\t// (which is equal to `filepath.Base(e.Filename)` in most circumstances).\n\tArgv []string `json:\"argv\"`\n\t// Truncated is true if we were unable to read all process arguments into\n\t// Argv because there were more than ARGLEN arguments.\n\tTruncated bool `json:\"truncated\"`\n\n\t// These values are of the new process. Keep in mind that the exec call may\n\t// fail and the PID will be released in such a case.\n\tPID uint32 `json:\"pid\"`\n\tUID uint32 `json:\"uid\"`\n\tGID uint32 `json:\"gid\"`\n\n\t// Comm is the \"name\" of the parent process, usually the filename of the\n\t// executable (but not always).\n\tComm string `json:\"comm\"`\n}\n\n// Tracer is the exec tracer itself.\n// It must be closed after use.\ntype Tracer struct {\n\tobjs bpfObjects\n\ttp   link.Link\n\trb   *ringbuf.Reader\n\n\tcloseLock sync.Mutex\n\tclosed    chan struct{}\n}\n\n// New instantiates all of the BPF objects into the running kernel, starts\n// tracing, and returns the created Tracer. After calling this successfully, the\n// caller should immediately attach a for loop running `h.Read()`.\n//\n// The returned Tracer MUST be closed when not needed anymore otherwise kernel\n// resources may be leaked.\nfunc New() (*Tracer, error) {\n\tt := &Tracer{\n\t\ttp: nil,\n\t\trb: nil,\n\n\t\tcloseLock: sync.Mutex{},\n\t\tclosed:    make(chan struct{}),\n\t}\n\n\tif err := loadBpfObjects(&t.objs, nil); err != nil {\n\t\treturn nil, fmt.Errorf(\"ebpf: failed to load ebpf object: %w\", err)\n\t}\n\n\tif err := t.start(); err != nil {\n\t\t// Best effort.\n\t\t_ = t.Close()\n\t\treturn nil, fmt.Errorf(\"start tracer: %w\", err)\n\t}\n\n\t// It could be very bad if someone forgot to close this, so we'll try to\n\t// detect when it doesn't get closed and log a warning.\n\tstack := debug.Stack()\n\truntime.SetFinalizer(t, func(t *Tracer) {\n\t\terr := t.Close()\n\t\tif errors.Is(err, errTracerClosed) {\n\t\t\treturn\n\t\t}\n\n\t\tlog.Infof(\"tracer was finalized but was not closed, created at: %s\", stack)\n\t\tlog.Infof(\"tracers must be closed when finished with to avoid leaked kernel resources\")\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"closing tracer failed: %+v\", err)\n\t\t}\n\t})\n\n\treturn t, nil\n}\n\n// start loads the eBPF programs and maps into the kernel and starts them.\n// You should immediately attach a for loop running `h.Read()` after calling\n// this successfully.\nfunc (t *Tracer) start() error {\n\t// If we don't startup successfully, we need to make sure all of the\n\t// stuff is cleaned up properly or we'll be leaking kernel resources.\n\tok := false\n\tdefer func() {\n\t\tif !ok {\n\t\t\t// Best effort.\n\t\t\t_ = t.Close()\n\t\t}\n\t}()\n\n\t// Allow the current process to lock memory for eBPF resources. This\n\t// does nothing on 5.11+ kernels which don't need this.\n\terr := rlimit.RemoveMemlock()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"remove memlock: %w\", err)\n\t}\n\n\t// Attach the eBPF program to the `sys_enter_execve` tracepoint, which\n\t// is triggered at the beginning of each `execve()` syscall.\n\tt.tp, err = link.Tracepoint(\"syscalls\", \"sys_enter_execve\", t.objs.EnterExecve, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open tracepoint: %w\", err)\n\t}\n\n\t// Create the reader for the event ringbuf.\n\tt.rb, err = ringbuf.NewReader(t.objs.PmExecMap)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open ringbuf reader: %w\", err)\n\t}\n\n\tok = true\n\treturn nil\n}\n\n// Read reads an event from the eBPF program via the ringbuf, parses it and\n// returns it. If the *tracer is closed during the blocked call, and error that\n// wraps io.EOF will be returned.\nfunc (t *Tracer) Read() (*Event, error) {\n\trb := t.rb\n\tif rb == nil {\n\t\treturn nil, errors.New(\"ringbuf reader is not initialized, tracer may not be open or may have been closed\")\n\t}\n\n\trecord, err := rb.Read()\n\tif err != nil {\n\t\tif errors.Is(err, ringbuf.ErrClosed) {\n\t\t\treturn nil, fmt.Errorf(\"tracer closed: %w\", io.EOF)\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"read from ringbuf: %w\", err)\n\t}\n\n\t// Parse the ringbuf event entry into an event structure.\n\tvar rawEvent event\n\terr = binary.Read(bytes.NewBuffer(record.RawSample), binary.NativeEndian, &rawEvent)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse raw ringbuf entry into event struct: %w\", err)\n\t}\n\n\tev := &Event{\n\t\tFilename:  unix.ByteSliceToString(rawEvent.Filename[:]),\n\t\tArgv:      []string{}, // populated below\n\t\tTruncated: rawEvent.Argc == arglen+1,\n\t\tPID:       rawEvent.PID,\n\t\tUID:       rawEvent.UID,\n\t\tGID:       rawEvent.GID,\n\t\tComm:      unix.ByteSliceToString(rawEvent.Comm[:]),\n\t}\n\n\t// Copy only the args we're allowed to read from the array. If we read more\n\t// than rawEvent.Argc, we could be copying non-zeroed memory.\n\targc := int(rawEvent.Argc)\n\tif argc > arglen {\n\t\targc = arglen\n\t}\n\tfor i := range argc {\n\t\tstr := unix.ByteSliceToString(rawEvent.Argv[i][:])\n\t\tif strings.TrimSpace(str) != \"\" {\n\t\t\tev.Argv = append(ev.Argv, str)\n\t\t}\n\t}\n\n\treturn ev, nil\n}\n\n// Close gracefully closes and frees all resources associated with the eBPF\n// tracepoints, maps and other resources. Any blocked `Read()` operations will\n// return an error that wraps `io.EOF`.\nfunc (t *Tracer) Close() error {\n\tt.closeLock.Lock()\n\tdefer t.closeLock.Unlock()\n\tselect {\n\tcase <-t.closed:\n\t\treturn errTracerClosed\n\tdefault:\n\t}\n\tclose(t.closed)\n\truntime.SetFinalizer(t, nil)\n\n\t// Close everything started in h.Start() in reverse order.\n\tvar merr error\n\tif t.rb != nil {\n\t\terr := t.rb.Close()\n\t\tif err != nil {\n\t\t\tmerr = multierror.Append(merr, fmt.Errorf(\"close ringbuf reader: %w\", err))\n\t\t}\n\t}\n\tif t.tp != nil {\n\t\terr := t.tp.Close()\n\t\tif err != nil {\n\t\t\tmerr = multierror.Append(merr, fmt.Errorf(\"close tracepoint: %w\", err))\n\t\t}\n\t}\n\terr := t.objs.Close()\n\tif err != nil {\n\t\tmerr = multierror.Append(merr, fmt.Errorf(\"close eBPF objects: %w\", err))\n\t}\n\n\treturn merr\n}\n"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/bandwidth.c",
    "content": "#include \"vmlinux-x86.h\"\n#include \"bpf/bpf_helpers.h\"\n#include \"bpf/bpf_tracing.h\"\n#include \"bpf/bpf_core_read.h\"\n\n#define AF_INET 2\n#define AF_INET6 10\n\n#define PROTOCOL_TCP 6\n#define PROTOCOL_UDP 17\n\nchar __license[] SEC(\"license\") = \"GPL\";\n\nstruct sk_key {\n\tu32 src_ip[4];\n\tu32 dst_ip[4];\n\tu16 src_port;\n\tu16 dst_port;\n\tu8 protocol;\n\tu8 ipv6;\n};\n\nstruct sk_info {\n\tu64 rx;\n\tu64 tx;\n\tu64 reported;\n};\n\n// Max number of connections that will be kept. Increse the number if it's not enough.\n#define SOCKOPS_MAP_SIZE 5000\nstruct {\n\t__uint(type, BPF_MAP_TYPE_LRU_HASH);\n\t__uint(max_entries, SOCKOPS_MAP_SIZE);\n\t__type(key, struct sk_key);\n\t__type(value, struct sk_info);\n} pm_bandwidth_map SEC(\".maps\");\n\nSEC(\"sockops\")\nint socket_operations(struct bpf_sock_ops *skops) {\n\tswitch (skops->op) {\n\tcase BPF_SOCK_OPS_TCP_CONNECT_CB: // Outgoing connections\n\t\t// Set flag so any modification on the socket, will trigger this function.\n\t\tbpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_ALL_CB_FLAGS);\n\t\treturn 0;\n\tcase BPF_SOCK_OPS_TCP_LISTEN_CB: // Listening ports\n\t\tbpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_ALL_CB_FLAGS);\n\t\t// No rx tx data for this socket object.\n\t\treturn 0;\n\tcase BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: // Incoming connections\n\t\t// Set flag so any modification on the socket, will trigger this function.\n\t\tbpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_ALL_CB_FLAGS);\n\t\treturn 0;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tstruct bpf_sock *sk = skops->sk;\n\tif (sk == NULL) {\n\t\treturn 0;\n\t}\n\n\tstruct sk_key key = {0};\n\tkey.protocol = PROTOCOL_TCP;\n\tif(sk->family == AF_INET) {\n\t\t// Generate key for IPv4\n\t\tkey.src_ip[0] = sk->src_ip4;\n\t\tkey.src_port = sk->src_port;\n\t\tkey.dst_ip[0] = sk->dst_ip4;\n\t\tkey.dst_port = __builtin_bswap16(sk->dst_port);\n\t\tkey.ipv6 = 0;\n\n\t\tstruct sk_info newInfo = {0};\n\t\tnewInfo.rx = skops->bytes_received;\n\t\tnewInfo.tx = skops->bytes_acked;\n\n\t\tbpf_map_update_elem(&pm_bandwidth_map, &key, &newInfo, BPF_ANY);\n\t} else if(sk->family == AF_INET6){\n\t\t// Generate key for IPv6\n\t\tkey.src_ip[0] = sk->src_ip6[0];\n\t\tkey.src_ip[1] = sk->src_ip6[1];\n\t\tkey.src_ip[2] = sk->src_ip6[2];\n\t\tkey.src_ip[3] = sk->src_ip6[3];\n\t\tkey.src_port = sk->src_port;\n\n\t\tkey.dst_ip[0] = sk->dst_ip6[0];\n\t\tkey.dst_ip[1] = sk->dst_ip6[1];\n\t\tkey.dst_ip[2] = sk->dst_ip6[2];\n\t\tkey.dst_ip[3] = sk->dst_ip6[3];\n\t\tkey.dst_port = __builtin_bswap16(sk->dst_port);\n\n\t\tkey.ipv6 = 1;\n\n\t\tstruct sk_info newInfo = {0};\n\t\tnewInfo.rx = skops->bytes_received;\n\t\tnewInfo.tx = skops->bytes_acked;\n\n\t\tbpf_map_update_elem(&pm_bandwidth_map, &key, &newInfo, BPF_ANY);\n\t}\n\n\treturn 0;\n}\n\n// udp_sendmsg hookes to the respective kernel function and saves the bandwidth data\nSEC(\"fentry/udp_sendmsg\")\nint BPF_PROG(udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t len) {\n\tstruct sock_common *skc = &sk->__sk_common;\n\n\t// Create a key for the map and set all the nececery information.\n\tstruct sk_key key = {0};\n\tkey.protocol = PROTOCOL_UDP;\n\tkey.src_ip[0] = skc->skc_rcv_saddr;\n\tkey.dst_ip[0] = skc->skc_daddr;\n\tkey.src_port = skc->skc_num;\n\tkey.dst_port = __builtin_bswap16(skc->skc_dport);\n\tkey.ipv6 = 0;\n\n\t// Update the map with the new information\n\tstruct sk_info *info = bpf_map_lookup_elem(&pm_bandwidth_map, &key);\n\tif (info != NULL) {\n\t\t__sync_fetch_and_add(&info->tx, len); // TODO: Use atomic instead.\n\t\t__sync_fetch_and_and(&info->reported, 0); // TODO: Use atomic instead.\n\t} else {\n\t\tstruct sk_info newInfo = {0};\n\n\t\tnewInfo.tx = len;\n\t\tbpf_map_update_elem(&pm_bandwidth_map, &key, &newInfo, BPF_ANY);\n\t}\n\n\treturn 0;\n};\n\n// udp_recvmsg hookes to the respective kernel function and saves the bandwidth data\nSEC(\"fentry/udp_recvmsg\")\nint BPF_PROG(udp_recvmsg, struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len) {\n\tstruct sock_common *skc = &sk->__sk_common;\n\n\t// Create a key for the map and set all the nececery information.\n\tstruct sk_key key = {0};\n\tkey.protocol = PROTOCOL_UDP;\n\tkey.src_ip[0] = skc->skc_rcv_saddr;\n\tkey.dst_ip[0] = skc->skc_daddr;\n\tkey.src_port = skc->skc_num;\n\tkey.dst_port = __builtin_bswap16(skc->skc_dport);\n\tkey.ipv6 = 0;\n\n\t// Update the map with the new information\n\tstruct sk_info *info = bpf_map_lookup_elem(&pm_bandwidth_map, &key);\n\tif (info != NULL) {\n\t\t__sync_fetch_and_add(&info->rx, len); // TODO: Use atomic instead.\n\t\t__sync_fetch_and_and(&info->reported, 0); // TODO: Use atomic instead.\n\t} else {\n\t\tstruct sk_info newInfo = {0};\n\n\t\tnewInfo.rx = len;\n\t\tbpf_map_update_elem(&pm_bandwidth_map, &key, &newInfo, BPF_ANY);\n\t}\n\n\treturn 0;\n};\n\n// udpv6_sendmsg hookes to the respective kernel function and saves the bandwidth data\nSEC(\"fentry/udpv6_sendmsg\")\nint BPF_PROG(udpv6_sendmsg, struct sock *sk, struct msghdr *msg, size_t len) {\n\tstruct sock_common *skc = &sk->__sk_common;\n\n\t// Create a key for the map and set all the nececery information.\n\tstruct sk_key key = {0};\n\tkey.protocol = PROTOCOL_UDP;\n\tfor (int i = 0; i < 4; i++) {\n\t\tkey.src_ip[i] = skc->skc_v6_rcv_saddr.in6_u.u6_addr32[i];\n\t\tkey.dst_ip[i] = skc->skc_v6_rcv_saddr.in6_u.u6_addr32[i];\n\t}\n\tkey.src_port = skc->skc_num;\n\tkey.dst_port = __builtin_bswap16(skc->skc_dport);\n\tkey.ipv6 = 1;\n\n\t// Update the map with the new information\n\tstruct sk_info *info = bpf_map_lookup_elem(&pm_bandwidth_map, &key);\n\tif (info != NULL) {\n\t\t__sync_fetch_and_add(&info->tx, len); // TODO: Use atomic instead.\n\t\t__sync_fetch_and_and(&info->reported, 0); // TODO: Use atomic instead.\n\t} else {\n\t\tstruct sk_info newInfo = {0};\n\t\tnewInfo.tx = len;\n\t\tbpf_map_update_elem(&pm_bandwidth_map, &key, &newInfo, BPF_ANY);\n\t}\n\n\treturn 0;\n}\n\n// udpv6_recvmsg hookes to the respective kernel function and saves the bandwidth data\nSEC(\"fentry/udpv6_recvmsg\")\nint BPF_PROG(udpv6_recvmsg, struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len) {\n\tstruct sock_common *skc = &sk->__sk_common;\n\n\t// Create a key for the map and set all the nececery information.\n\tstruct sk_key key = {0};\n\tkey.protocol = PROTOCOL_UDP;\n\tfor (int i = 0; i < 4; i++) {\n\t\tkey.src_ip[i] = skc->skc_v6_rcv_saddr.in6_u.u6_addr32[i];\n\t\tkey.dst_ip[i] = skc->skc_v6_rcv_saddr.in6_u.u6_addr32[i];\n\t}\n\tkey.src_port = skc->skc_num;\n\tkey.dst_port = __builtin_bswap16(skc->skc_dport);\n\tkey.ipv6 = 1;\n\n\t// Update the map with the new information\n\tstruct sk_info *info = bpf_map_lookup_elem(&pm_bandwidth_map, &key);\n\tif (info != NULL) {\n\t\t__sync_fetch_and_add(&info->rx, len); // TODO: Use atomic instead.\n\t\t__sync_fetch_and_and(&info->reported, 0); // TODO: Use atomic instead.\n\t} else {\n\t\tstruct sk_info newInfo = {0};\n\t\tnewInfo.rx = len;\n\t\tbpf_map_update_elem(&pm_bandwidth_map, &key, &newInfo, BPF_ANY);\n\t}\n\n\treturn 0;\n}"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/bpf/bpf_core_read.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n#ifndef __BPF_CORE_READ_H__\n#define __BPF_CORE_READ_H__\n\n/*\n * enum bpf_field_info_kind is passed as a second argument into\n * __builtin_preserve_field_info() built-in to get a specific aspect of\n * a field, captured as a first argument. __builtin_preserve_field_info(field,\n * info_kind) returns __u32 integer and produces BTF field relocation, which\n * is understood and processed by libbpf during BPF object loading. See\n * selftests/bpf for examples.\n */\nenum bpf_field_info_kind {\n\tBPF_FIELD_BYTE_OFFSET = 0,\t/* field byte offset */\n\tBPF_FIELD_BYTE_SIZE = 1,\n\tBPF_FIELD_EXISTS = 2,\t\t/* field existence in target kernel */\n\tBPF_FIELD_SIGNED = 3,\n\tBPF_FIELD_LSHIFT_U64 = 4,\n\tBPF_FIELD_RSHIFT_U64 = 5,\n};\n\n/* second argument to __builtin_btf_type_id() built-in */\nenum bpf_type_id_kind {\n\tBPF_TYPE_ID_LOCAL = 0,\t\t/* BTF type ID in local program */\n\tBPF_TYPE_ID_TARGET = 1,\t\t/* BTF type ID in target kernel */\n};\n\n/* second argument to __builtin_preserve_type_info() built-in */\nenum bpf_type_info_kind {\n\tBPF_TYPE_EXISTS = 0,\t\t/* type existence in target kernel */\n\tBPF_TYPE_SIZE = 1,\t\t/* type size in target kernel */\n\tBPF_TYPE_MATCHES = 2,\t\t/* type match in target kernel */\n};\n\n/* second argument to __builtin_preserve_enum_value() built-in */\nenum bpf_enum_value_kind {\n\tBPF_ENUMVAL_EXISTS = 0,\t\t/* enum value existence in kernel */\n\tBPF_ENUMVAL_VALUE = 1,\t\t/* enum value value relocation */\n};\n\n#define __CORE_RELO(src, field, info)\t\t\t\t\t      \\\n\t__builtin_preserve_field_info((src)->field, BPF_FIELD_##info)\n\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#define __CORE_BITFIELD_PROBE_READ(dst, src, fld)\t\t\t      \\\n\tbpf_probe_read_kernel(\t\t\t\t\t\t      \\\n\t\t\t(void *)dst,\t\t\t\t      \\\n\t\t\t__CORE_RELO(src, fld, BYTE_SIZE),\t\t      \\\n\t\t\t(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))\n#else\n/* semantics of LSHIFT_64 assumes loading values into low-ordered bytes, so\n * for big-endian we need to adjust destination pointer accordingly, based on\n * field byte size\n */\n#define __CORE_BITFIELD_PROBE_READ(dst, src, fld)\t\t\t      \\\n\tbpf_probe_read_kernel(\t\t\t\t\t\t      \\\n\t\t\t(void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \\\n\t\t\t__CORE_RELO(src, fld, BYTE_SIZE),\t\t      \\\n\t\t\t(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))\n#endif\n\n/*\n * Extract bitfield, identified by s->field, and return its value as u64.\n * All this is done in relocatable manner, so bitfield changes such as\n * signedness, bit size, offset changes, this will be handled automatically.\n * This version of macro is using bpf_probe_read_kernel() to read underlying\n * integer storage. Macro functions as an expression and its return type is\n * bpf_probe_read_kernel()'s return value: 0, on success, <0 on error.\n */\n#define BPF_CORE_READ_BITFIELD_PROBED(s, field) ({\t\t\t      \\\n\tunsigned long long val = 0;\t\t\t\t\t      \\\n\t\t\t\t\t\t\t\t\t      \\\n\t__CORE_BITFIELD_PROBE_READ(&val, s, field);\t\t\t      \\\n\tval <<= __CORE_RELO(s, field, LSHIFT_U64);\t\t\t      \\\n\tif (__CORE_RELO(s, field, SIGNED))\t\t\t\t      \\\n\t\tval = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64);  \\\n\telse\t\t\t\t\t\t\t\t      \\\n\t\tval = val >> __CORE_RELO(s, field, RSHIFT_U64);\t\t      \\\n\tval;\t\t\t\t\t\t\t\t      \\\n})\n\n/*\n * Extract bitfield, identified by s->field, and return its value as u64.\n * This version of macro is using direct memory reads and should be used from\n * BPF program types that support such functionality (e.g., typed raw\n * tracepoints).\n */\n#define BPF_CORE_READ_BITFIELD(s, field) ({\t\t\t\t      \\\n\tconst void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \\\n\tunsigned long long val;\t\t\t\t\t\t      \\\n\t\t\t\t\t\t\t\t\t      \\\n\t/* This is a so-called barrier_var() operation that makes specified   \\\n\t * variable \"a black box\" for optimizing compiler.\t\t      \\\n\t * It forces compiler to perform BYTE_OFFSET relocation on p and use  \\\n\t * its calculated value in the switch below, instead of applying      \\\n\t * the same relocation 4 times for each individual memory load.       \\\n\t */\t\t\t\t\t\t\t\t      \\\n\tasm volatile(\"\" : \"=r\"(p) : \"0\"(p));\t\t\t\t      \\\n\t\t\t\t\t\t\t\t\t      \\\n\tswitch (__CORE_RELO(s, field, BYTE_SIZE)) {\t\t\t      \\\n\tcase 1: val = *(const unsigned char *)p; break;\t\t\t      \\\n\tcase 2: val = *(const unsigned short *)p; break;\t\t      \\\n\tcase 4: val = *(const unsigned int *)p; break;\t\t\t      \\\n\tcase 8: val = *(const unsigned long long *)p; break;\t\t      \\\n\t}\t\t\t\t\t\t\t\t      \\\n\tval <<= __CORE_RELO(s, field, LSHIFT_U64);\t\t\t      \\\n\tif (__CORE_RELO(s, field, SIGNED))\t\t\t\t      \\\n\t\tval = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64);  \\\n\telse\t\t\t\t\t\t\t\t      \\\n\t\tval = val >> __CORE_RELO(s, field, RSHIFT_U64);\t\t      \\\n\tval;\t\t\t\t\t\t\t\t      \\\n})\n\n#define ___bpf_field_ref1(field)\t(field)\n#define ___bpf_field_ref2(type, field)\t(((typeof(type) *)0)->field)\n#define ___bpf_field_ref(args...)\t\t\t\t\t    \\\n\t___bpf_apply(___bpf_field_ref, ___bpf_narg(args))(args)\n\n/*\n * Convenience macro to check that field actually exists in target kernel's.\n * Returns:\n *    1, if matching field is present in target kernel;\n *    0, if no matching field found.\n *\n * Supports two forms:\n *   - field reference through variable access:\n *     bpf_core_field_exists(p->my_field);\n *   - field reference through type and field names:\n *     bpf_core_field_exists(struct my_type, my_field).\n */\n#define bpf_core_field_exists(field...)\t\t\t\t\t    \\\n\t__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_EXISTS)\n\n/*\n * Convenience macro to get the byte size of a field. Works for integers,\n * struct/unions, pointers, arrays, and enums.\n *\n * Supports two forms:\n *   - field reference through variable access:\n *     bpf_core_field_size(p->my_field);\n *   - field reference through type and field names:\n *     bpf_core_field_size(struct my_type, my_field).\n */\n#define bpf_core_field_size(field...)\t\t\t\t\t    \\\n\t__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_SIZE)\n\n/*\n * Convenience macro to get field's byte offset.\n *\n * Supports two forms:\n *   - field reference through variable access:\n *     bpf_core_field_offset(p->my_field);\n *   - field reference through type and field names:\n *     bpf_core_field_offset(struct my_type, my_field).\n */\n#define bpf_core_field_offset(field...)\t\t\t\t\t    \\\n\t__builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_OFFSET)\n\n/*\n * Convenience macro to get BTF type ID of a specified type, using a local BTF\n * information. Return 32-bit unsigned integer with type ID from program's own\n * BTF. Always succeeds.\n */\n#define bpf_core_type_id_local(type)\t\t\t\t\t    \\\n\t__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL)\n\n/*\n * Convenience macro to get BTF type ID of a target kernel's type that matches\n * specified local type.\n * Returns:\n *    - valid 32-bit unsigned type ID in kernel BTF;\n *    - 0, if no matching type was found in a target kernel BTF.\n */\n#define bpf_core_type_id_kernel(type)\t\t\t\t\t    \\\n\t__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET)\n\n/*\n * Convenience macro to check that provided named type\n * (struct/union/enum/typedef) exists in a target kernel.\n * Returns:\n *    1, if such type is present in target kernel's BTF;\n *    0, if no matching type is found.\n */\n#define bpf_core_type_exists(type)\t\t\t\t\t    \\\n\t__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)\n\n/*\n * Convenience macro to check that provided named type\n * (struct/union/enum/typedef) \"matches\" that in a target kernel.\n * Returns:\n *    1, if the type matches in the target kernel's BTF;\n *    0, if the type does not match any in the target kernel\n */\n#define bpf_core_type_matches(type)\t\t\t\t\t    \\\n\t__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_MATCHES)\n\n/*\n * Convenience macro to get the byte size of a provided named type\n * (struct/union/enum/typedef) in a target kernel.\n * Returns:\n *    >= 0 size (in bytes), if type is present in target kernel's BTF;\n *    0, if no matching type is found.\n */\n#define bpf_core_type_size(type)\t\t\t\t\t    \\\n\t__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE)\n\n/*\n * Convenience macro to check that provided enumerator value is defined in\n * a target kernel.\n * Returns:\n *    1, if specified enum type and its enumerator value are present in target\n *    kernel's BTF;\n *    0, if no matching enum and/or enum value within that enum is found.\n */\n#define bpf_core_enum_value_exists(enum_type, enum_value)\t\t    \\\n\t__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS)\n\n/*\n * Convenience macro to get the integer value of an enumerator value in\n * a target kernel.\n * Returns:\n *    64-bit value, if specified enum type and its enumerator value are\n *    present in target kernel's BTF;\n *    0, if no matching enum and/or enum value within that enum is found.\n */\n#define bpf_core_enum_value(enum_type, enum_value)\t\t\t    \\\n\t__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE)\n\n/*\n * bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures\n * offset relocation for source address using __builtin_preserve_access_index()\n * built-in, provided by Clang.\n *\n * __builtin_preserve_access_index() takes as an argument an expression of\n * taking an address of a field within struct/union. It makes compiler emit\n * a relocation, which records BTF type ID describing root struct/union and an\n * accessor string which describes exact embedded field that was used to take\n * an address. See detailed description of this relocation format and\n * semantics in comments to struct bpf_field_reloc in libbpf_internal.h.\n *\n * This relocation allows libbpf to adjust BPF instruction to use correct\n * actual field offset, based on target kernel BTF type that matches original\n * (local) BTF, used to record relocation.\n */\n#define bpf_core_read(dst, sz, src)\t\t\t\t\t    \\\n\tbpf_probe_read_kernel(dst, sz, (const void *)__builtin_preserve_access_index(src))\n\n/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */\n#define bpf_core_read_user(dst, sz, src)\t\t\t\t    \\\n\tbpf_probe_read_user(dst, sz, (const void *)__builtin_preserve_access_index(src))\n/*\n * bpf_core_read_str() is a thin wrapper around bpf_probe_read_str()\n * additionally emitting BPF CO-RE field relocation for specified source\n * argument.\n */\n#define bpf_core_read_str(dst, sz, src)\t\t\t\t\t    \\\n\tbpf_probe_read_kernel_str(dst, sz, (const void *)__builtin_preserve_access_index(src))\n\n/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */\n#define bpf_core_read_user_str(dst, sz, src)\t\t\t\t    \\\n\tbpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src))\n\n#define ___concat(a, b) a ## b\n#define ___apply(fn, n) ___concat(fn, n)\n#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N\n\n/*\n * return number of provided arguments; used for switch-based variadic macro\n * definitions (see ___last, ___arrow, etc below)\n */\n#define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)\n/*\n * return 0 if no arguments are passed, N - otherwise; used for\n * recursively-defined macros to specify termination (0) case, and generic\n * (N) case (e.g., ___read_ptrs, ___core_read)\n */\n#define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0)\n\n#define ___last1(x) x\n#define ___last2(a, x) x\n#define ___last3(a, b, x) x\n#define ___last4(a, b, c, x) x\n#define ___last5(a, b, c, d, x) x\n#define ___last6(a, b, c, d, e, x) x\n#define ___last7(a, b, c, d, e, f, x) x\n#define ___last8(a, b, c, d, e, f, g, x) x\n#define ___last9(a, b, c, d, e, f, g, h, x) x\n#define ___last10(a, b, c, d, e, f, g, h, i, x) x\n#define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__)\n\n#define ___nolast2(a, _) a\n#define ___nolast3(a, b, _) a, b\n#define ___nolast4(a, b, c, _) a, b, c\n#define ___nolast5(a, b, c, d, _) a, b, c, d\n#define ___nolast6(a, b, c, d, e, _) a, b, c, d, e\n#define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f\n#define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g\n#define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h\n#define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i\n#define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__)\n\n#define ___arrow1(a) a\n#define ___arrow2(a, b) a->b\n#define ___arrow3(a, b, c) a->b->c\n#define ___arrow4(a, b, c, d) a->b->c->d\n#define ___arrow5(a, b, c, d, e) a->b->c->d->e\n#define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f\n#define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g\n#define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h\n#define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i\n#define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j\n#define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__)\n\n#define ___type(...) typeof(___arrow(__VA_ARGS__))\n\n#define ___read(read_fn, dst, src_type, src, accessor)\t\t\t    \\\n\tread_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)\n\n/* \"recursively\" read a sequence of inner pointers using local __t var */\n#define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a);\n#define ___rd_last(fn, ...)\t\t\t\t\t\t    \\\n\t___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));\n#define ___rd_p1(fn, ...) const void *__t; ___rd_first(fn, __VA_ARGS__)\n#define ___rd_p2(fn, ...) ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p3(fn, ...) ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p4(fn, ...) ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p5(fn, ...) ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p6(fn, ...) ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p7(fn, ...) ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p8(fn, ...) ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p9(fn, ...) ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___read_ptrs(fn, src, ...)\t\t\t\t\t    \\\n\t___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__)\n\n#define ___core_read0(fn, fn_ptr, dst, src, a)\t\t\t\t    \\\n\t___read(fn, dst, ___type(src), src, a);\n#define ___core_readN(fn, fn_ptr, dst, src, ...)\t\t\t    \\\n\t___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__))\t\t    \\\n\t___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t,\t    \\\n\t\t___last(__VA_ARGS__));\n#define ___core_read(fn, fn_ptr, dst, src, a, ...)\t\t\t    \\\n\t___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst,\t    \\\n\t\t\t\t\t\t      src, a, ##__VA_ARGS__)\n\n/*\n * BPF_CORE_READ_INTO() is a more performance-conscious variant of\n * BPF_CORE_READ(), in which final field is read into user-provided storage.\n * See BPF_CORE_READ() below for more details on general usage.\n */\n#define BPF_CORE_READ_INTO(dst, src, a, ...) ({\t\t\t\t    \\\n\t___core_read(bpf_core_read, bpf_core_read,\t\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * Variant of BPF_CORE_READ_INTO() for reading from user-space memory.\n *\n * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.\n */\n#define BPF_CORE_READ_USER_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_core_read_user, bpf_core_read_user,\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ_INTO() */\n#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_probe_read_kernel, bpf_probe_read_kernel,\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ_USER_INTO().\n *\n * As no CO-RE relocations are emitted, source types can be arbitrary and are\n * not restricted to kernel types only.\n */\n#define BPF_PROBE_READ_USER_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_probe_read_user, bpf_probe_read_user,\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * BPF_CORE_READ_STR_INTO() does same \"pointer chasing\" as\n * BPF_CORE_READ() for intermediate pointers, but then executes (and returns\n * corresponding error code) bpf_core_read_str() for final string read.\n */\n#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_core_read_str, bpf_core_read,\t\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * Variant of BPF_CORE_READ_STR_INTO() for reading from user-space memory.\n *\n * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.\n */\n#define BPF_CORE_READ_USER_STR_INTO(dst, src, a, ...) ({\t\t    \\\n\t___core_read(bpf_core_read_user_str, bpf_core_read_user,\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */\n#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_probe_read_kernel_str, bpf_probe_read_kernel,\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * Non-CO-RE variant of BPF_CORE_READ_USER_STR_INTO().\n *\n * As no CO-RE relocations are emitted, source types can be arbitrary and are\n * not restricted to kernel types only.\n */\n#define BPF_PROBE_READ_USER_STR_INTO(dst, src, a, ...) ({\t\t    \\\n\t___core_read(bpf_probe_read_user_str, bpf_probe_read_user,\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially\n * when there are few pointer chasing steps.\n * E.g., what in non-BPF world (or in BPF w/ BCC) would be something like:\n *\tint x = s->a.b.c->d.e->f->g;\n * can be succinctly achieved using BPF_CORE_READ as:\n *\tint x = BPF_CORE_READ(s, a.b.c, d.e, f, g);\n *\n * BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF\n * CO-RE relocatable bpf_probe_read_kernel() wrapper) calls, logically\n * equivalent to:\n * 1. const void *__t = s->a.b.c;\n * 2. __t = __t->d.e;\n * 3. __t = __t->f;\n * 4. return __t->g;\n *\n * Equivalence is logical, because there is a heavy type casting/preservation\n * involved, as well as all the reads are happening through\n * bpf_probe_read_kernel() calls using __builtin_preserve_access_index() to\n * emit CO-RE relocations.\n *\n * N.B. Only up to 9 \"field accessors\" are supported, which should be more\n * than enough for any practical purpose.\n */\n#define BPF_CORE_READ(src, a, ...) ({\t\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__);\t\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n/*\n * Variant of BPF_CORE_READ() for reading from user-space memory.\n *\n * NOTE: all the source types involved are still *kernel types* and need to\n * exist in kernel (or kernel module) BTF, otherwise CO-RE relocation will\n * fail. Custom user types are not relocatable with CO-RE.\n * The typical situation in which BPF_CORE_READ_USER() might be used is to\n * read kernel UAPI types from the user-space memory passed in as a syscall\n * input argument.\n */\n#define BPF_CORE_READ_USER(src, a, ...) ({\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_CORE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__);\t\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ() */\n#define BPF_PROBE_READ(src, a, ...) ({\t\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_PROBE_READ_INTO(&__r, (src), a, ##__VA_ARGS__);\t\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n/*\n * Non-CO-RE variant of BPF_CORE_READ_USER().\n *\n * As no CO-RE relocations are emitted, source types can be arbitrary and are\n * not restricted to kernel types only.\n */\n#define BPF_PROBE_READ_USER(src, a, ...) ({\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_PROBE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__);\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n#endif\n\n"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/bpf/bpf_helper_defs.h",
    "content": "/* This is auto-generated file. See bpf_doc.py for details. */\n\n/* Forward declarations of BPF structs */\nstruct bpf_fib_lookup;\nstruct bpf_sk_lookup;\nstruct bpf_perf_event_data;\nstruct bpf_perf_event_value;\nstruct bpf_pidns_info;\nstruct bpf_redir_neigh;\nstruct bpf_sock;\nstruct bpf_sock_addr;\nstruct bpf_sock_ops;\nstruct bpf_sock_tuple;\nstruct bpf_spin_lock;\nstruct bpf_sysctl;\nstruct bpf_tcp_sock;\nstruct bpf_tunnel_key;\nstruct bpf_xfrm_state;\nstruct linux_binprm;\nstruct pt_regs;\nstruct sk_reuseport_md;\nstruct sockaddr;\nstruct tcphdr;\nstruct seq_file;\nstruct tcp6_sock;\nstruct tcp_sock;\nstruct tcp_timewait_sock;\nstruct tcp_request_sock;\nstruct udp6_sock;\nstruct unix_sock;\nstruct task_struct;\nstruct cgroup;\nstruct __sk_buff;\nstruct sk_msg_md;\nstruct xdp_md;\nstruct path;\nstruct btf_ptr;\nstruct inode;\nstruct socket;\nstruct file;\nstruct bpf_timer;\nstruct mptcp_sock;\nstruct bpf_dynptr;\nstruct iphdr;\nstruct ipv6hdr;\n\n/*\n * bpf_map_lookup_elem\n *\n * \tPerform a lookup in *map* for an entry associated to *key*.\n *\n * Returns\n * \tMap value associated to *key*, or **NULL** if no entry was\n * \tfound.\n */\nstatic void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1;\n\n/*\n * bpf_map_update_elem\n *\n * \tAdd or update the value of the entry associated to *key* in\n * \t*map* with *value*. *flags* is one of:\n *\n * \t**BPF_NOEXIST**\n * \t\tThe entry for *key* must not exist in the map.\n * \t**BPF_EXIST**\n * \t\tThe entry for *key* must already exist in the map.\n * \t**BPF_ANY**\n * \t\tNo condition on the existence of the entry for *key*.\n *\n * \tFlag value **BPF_NOEXIST** cannot be used for maps of types\n * \t**BPF_MAP_TYPE_ARRAY** or **BPF_MAP_TYPE_PERCPU_ARRAY**  (all\n * \telements always exist), the helper would return an error.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_update_elem)(void *map, const void *key, const void *value, __u64 flags) = (void *) 2;\n\n/*\n * bpf_map_delete_elem\n *\n * \tDelete entry with *key* from *map*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_delete_elem)(void *map, const void *key) = (void *) 3;\n\n/*\n * bpf_probe_read\n *\n * \tFor tracing programs, safely attempt to read *size* bytes from\n * \tkernel space address *unsafe_ptr* and store the data in *dst*.\n *\n * \tGenerally, use **bpf_probe_read_user**\\ () or\n * \t**bpf_probe_read_kernel**\\ () instead.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_read)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 4;\n\n/*\n * bpf_ktime_get_ns\n *\n * \tReturn the time elapsed since system boot, in nanoseconds.\n * \tDoes not include time the system was suspended.\n * \tSee: **clock_gettime**\\ (**CLOCK_MONOTONIC**)\n *\n * Returns\n * \tCurrent *ktime*.\n */\nstatic __u64 (*bpf_ktime_get_ns)(void) = (void *) 5;\n\n/*\n * bpf_trace_printk\n *\n * \tThis helper is a \"printk()-like\" facility for debugging. It\n * \tprints a message defined by format *fmt* (of size *fmt_size*)\n * \tto file *\\/sys/kernel/tracing/trace* from TraceFS, if\n * \tavailable. It can take up to three additional **u64**\n * \targuments (as an eBPF helpers, the total number of arguments is\n * \tlimited to five).\n *\n * \tEach time the helper is called, it appends a line to the trace.\n * \tLines are discarded while *\\/sys/kernel/tracing/trace* is\n * \topen, use *\\/sys/kernel/tracing/trace_pipe* to avoid this.\n * \tThe format of the trace is customizable, and the exact output\n * \tone will get depends on the options set in\n * \t*\\/sys/kernel/tracing/trace_options* (see also the\n * \t*README* file under the same directory). However, it usually\n * \tdefaults to something like:\n *\n * \t::\n *\n * \t\ttelnet-470   [001] .N.. 419421.045894: 0x00000001: <formatted msg>\n *\n * \tIn the above:\n *\n * \t\t* ``telnet`` is the name of the current task.\n * \t\t* ``470`` is the PID of the current task.\n * \t\t* ``001`` is the CPU number on which the task is\n * \t\t  running.\n * \t\t* In ``.N..``, each character refers to a set of\n * \t\t  options (whether irqs are enabled, scheduling\n * \t\t  options, whether hard/softirqs are running, level of\n * \t\t  preempt_disabled respectively). **N** means that\n * \t\t  **TIF_NEED_RESCHED** and **PREEMPT_NEED_RESCHED**\n * \t\t  are set.\n * \t\t* ``419421.045894`` is a timestamp.\n * \t\t* ``0x00000001`` is a fake value used by BPF for the\n * \t\t  instruction pointer register.\n * \t\t* ``<formatted msg>`` is the message formatted with\n * \t\t  *fmt*.\n *\n * \tThe conversion specifiers supported by *fmt* are similar, but\n * \tmore limited than for printk(). They are **%d**, **%i**,\n * \t**%u**, **%x**, **%ld**, **%li**, **%lu**, **%lx**, **%lld**,\n * \t**%lli**, **%llu**, **%llx**, **%p**, **%s**. No modifier (size\n * \tof field, padding with zeroes, etc.) is available, and the\n * \thelper will return **-EINVAL** (but print nothing) if it\n * \tencounters an unknown specifier.\n *\n * \tAlso, note that **bpf_trace_printk**\\ () is slow, and should\n * \tonly be used for debugging purposes. For this reason, a notice\n * \tblock (spanning several lines) is printed to kernel logs and\n * \tstates that the helper should not be used \"for production use\"\n * \tthe first time this helper is used (or more precisely, when\n * \t**trace_printk**\\ () buffers are allocated). For passing values\n * \tto user space, perf events should be preferred.\n *\n * Returns\n * \tThe number of bytes written to the buffer, or a negative error\n * \tin case of failure.\n */\nstatic long (*bpf_trace_printk)(const char *fmt, __u32 fmt_size, ...) = (void *) 6;\n\n/*\n * bpf_get_prandom_u32\n *\n * \tGet a pseudo-random number.\n *\n * \tFrom a security point of view, this helper uses its own\n * \tpseudo-random internal state, and cannot be used to infer the\n * \tseed of other random functions in the kernel. However, it is\n * \tessential to note that the generator used by the helper is not\n * \tcryptographically secure.\n *\n * Returns\n * \tA random 32-bit unsigned value.\n */\nstatic __u32 (*bpf_get_prandom_u32)(void) = (void *) 7;\n\n/*\n * bpf_get_smp_processor_id\n *\n * \tGet the SMP (symmetric multiprocessing) processor id. Note that\n * \tall programs run with migration disabled, which means that the\n * \tSMP processor id is stable during all the execution of the\n * \tprogram.\n *\n * Returns\n * \tThe SMP id of the processor running the program.\n */\nstatic __u32 (*bpf_get_smp_processor_id)(void) = (void *) 8;\n\n/*\n * bpf_skb_store_bytes\n *\n * \tStore *len* bytes from address *from* into the packet\n * \tassociated to *skb*, at *offset*. *flags* are a combination of\n * \t**BPF_F_RECOMPUTE_CSUM** (automatically recompute the\n * \tchecksum for the packet after storing the bytes) and\n * \t**BPF_F_INVALIDATE_HASH** (set *skb*\\ **->hash**, *skb*\\\n * \t**->swhash** and *skb*\\ **->l4hash** to 0).\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_store_bytes)(struct __sk_buff *skb, __u32 offset, const void *from, __u32 len, __u64 flags) = (void *) 9;\n\n/*\n * bpf_l3_csum_replace\n *\n * \tRecompute the layer 3 (e.g. IP) checksum for the packet\n * \tassociated to *skb*. Computation is incremental, so the helper\n * \tmust know the former value of the header field that was\n * \tmodified (*from*), the new value of this field (*to*), and the\n * \tnumber of bytes (2 or 4) for this field, stored in *size*.\n * \tAlternatively, it is possible to store the difference between\n * \tthe previous and the new values of the header field in *to*, by\n * \tsetting *from* and *size* to 0. For both methods, *offset*\n * \tindicates the location of the IP checksum within the packet.\n *\n * \tThis helper works in combination with **bpf_csum_diff**\\ (),\n * \twhich does not update the checksum in-place, but offers more\n * \tflexibility and can handle sizes larger than 2 or 4 for the\n * \tchecksum to update.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_l3_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 from, __u64 to, __u64 size) = (void *) 10;\n\n/*\n * bpf_l4_csum_replace\n *\n * \tRecompute the layer 4 (e.g. TCP, UDP or ICMP) checksum for the\n * \tpacket associated to *skb*. Computation is incremental, so the\n * \thelper must know the former value of the header field that was\n * \tmodified (*from*), the new value of this field (*to*), and the\n * \tnumber of bytes (2 or 4) for this field, stored on the lowest\n * \tfour bits of *flags*. Alternatively, it is possible to store\n * \tthe difference between the previous and the new values of the\n * \theader field in *to*, by setting *from* and the four lowest\n * \tbits of *flags* to 0. For both methods, *offset* indicates the\n * \tlocation of the IP checksum within the packet. In addition to\n * \tthe size of the field, *flags* can be added (bitwise OR) actual\n * \tflags. With **BPF_F_MARK_MANGLED_0**, a null checksum is left\n * \tuntouched (unless **BPF_F_MARK_ENFORCE** is added as well), and\n * \tfor updates resulting in a null checksum the value is set to\n * \t**CSUM_MANGLED_0** instead. Flag **BPF_F_PSEUDO_HDR** indicates\n * \tthe checksum is to be computed against a pseudo-header.\n *\n * \tThis helper works in combination with **bpf_csum_diff**\\ (),\n * \twhich does not update the checksum in-place, but offers more\n * \tflexibility and can handle sizes larger than 2 or 4 for the\n * \tchecksum to update.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_l4_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 from, __u64 to, __u64 flags) = (void *) 11;\n\n/*\n * bpf_tail_call\n *\n * \tThis special helper is used to trigger a \"tail call\", or in\n * \tother words, to jump into another eBPF program. The same stack\n * \tframe is used (but values on stack and in registers for the\n * \tcaller are not accessible to the callee). This mechanism allows\n * \tfor program chaining, either for raising the maximum number of\n * \tavailable eBPF instructions, or to execute given programs in\n * \tconditional blocks. For security reasons, there is an upper\n * \tlimit to the number of successive tail calls that can be\n * \tperformed.\n *\n * \tUpon call of this helper, the program attempts to jump into a\n * \tprogram referenced at index *index* in *prog_array_map*, a\n * \tspecial map of type **BPF_MAP_TYPE_PROG_ARRAY**, and passes\n * \t*ctx*, a pointer to the context.\n *\n * \tIf the call succeeds, the kernel immediately runs the first\n * \tinstruction of the new program. This is not a function call,\n * \tand it never returns to the previous program. If the call\n * \tfails, then the helper has no effect, and the caller continues\n * \tto run its subsequent instructions. A call can fail if the\n * \tdestination program for the jump does not exist (i.e. *index*\n * \tis superior to the number of entries in *prog_array_map*), or\n * \tif the maximum number of tail calls has been reached for this\n * \tchain of programs. This limit is defined in the kernel by the\n * \tmacro **MAX_TAIL_CALL_CNT** (not accessible to user space),\n * \twhich is currently set to 33.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_tail_call)(void *ctx, void *prog_array_map, __u32 index) = (void *) 12;\n\n/*\n * bpf_clone_redirect\n *\n * \tClone and redirect the packet associated to *skb* to another\n * \tnet device of index *ifindex*. Both ingress and egress\n * \tinterfaces can be used for redirection. The **BPF_F_INGRESS**\n * \tvalue in *flags* is used to make the distinction (ingress path\n * \tis selected if the flag is present, egress path otherwise).\n * \tThis is the only flag supported for now.\n *\n * \tIn comparison with **bpf_redirect**\\ () helper,\n * \t**bpf_clone_redirect**\\ () has the associated cost of\n * \tduplicating the packet buffer, but this can be executed out of\n * \tthe eBPF program. Conversely, **bpf_redirect**\\ () is more\n * \tefficient, but it is handled through an action code where the\n * \tredirection happens only after the eBPF program has returned.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_clone_redirect)(struct __sk_buff *skb, __u32 ifindex, __u64 flags) = (void *) 13;\n\n/*\n * bpf_get_current_pid_tgid\n *\n * \tGet the current pid and tgid.\n *\n * Returns\n * \tA 64-bit integer containing the current tgid and pid, and\n * \tcreated as such:\n * \t*current_task*\\ **->tgid << 32 \\|**\n * \t*current_task*\\ **->pid**.\n */\nstatic __u64 (*bpf_get_current_pid_tgid)(void) = (void *) 14;\n\n/*\n * bpf_get_current_uid_gid\n *\n * \tGet the current uid and gid.\n *\n * Returns\n * \tA 64-bit integer containing the current GID and UID, and\n * \tcreated as such: *current_gid* **<< 32 \\|** *current_uid*.\n */\nstatic __u64 (*bpf_get_current_uid_gid)(void) = (void *) 15;\n\n/*\n * bpf_get_current_comm\n *\n * \tCopy the **comm** attribute of the current task into *buf* of\n * \t*size_of_buf*. The **comm** attribute contains the name of\n * \tthe executable (excluding the path) for the current task. The\n * \t*size_of_buf* must be strictly positive. On success, the\n * \thelper makes sure that the *buf* is NUL-terminated. On failure,\n * \tit is filled with zeroes.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_get_current_comm)(void *buf, __u32 size_of_buf) = (void *) 16;\n\n/*\n * bpf_get_cgroup_classid\n *\n * \tRetrieve the classid for the current task, i.e. for the net_cls\n * \tcgroup to which *skb* belongs.\n *\n * \tThis helper can be used on TC egress path, but not on ingress.\n *\n * \tThe net_cls cgroup provides an interface to tag network packets\n * \tbased on a user-provided identifier for all traffic coming from\n * \tthe tasks belonging to the related cgroup. See also the related\n * \tkernel documentation, available from the Linux sources in file\n * \t*Documentation/admin-guide/cgroup-v1/net_cls.rst*.\n *\n * \tThe Linux kernel has two versions for cgroups: there are\n * \tcgroups v1 and cgroups v2. Both are available to users, who can\n * \tuse a mixture of them, but note that the net_cls cgroup is for\n * \tcgroup v1 only. This makes it incompatible with BPF programs\n * \trun on cgroups, which is a cgroup-v2-only feature (a socket can\n * \tonly hold data for one version of cgroups at a time).\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_CGROUP_NET_CLASSID** configuration option set to\n * \t\"**y**\" or to \"**m**\".\n *\n * Returns\n * \tThe classid, or 0 for the default unconfigured classid.\n */\nstatic __u32 (*bpf_get_cgroup_classid)(struct __sk_buff *skb) = (void *) 17;\n\n/*\n * bpf_skb_vlan_push\n *\n * \tPush a *vlan_tci* (VLAN tag control information) of protocol\n * \t*vlan_proto* to the packet associated to *skb*, then update\n * \tthe checksum. Note that if *vlan_proto* is different from\n * \t**ETH_P_8021Q** and **ETH_P_8021AD**, it is considered to\n * \tbe **ETH_P_8021Q**.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_vlan_push)(struct __sk_buff *skb, __be16 vlan_proto, __u16 vlan_tci) = (void *) 18;\n\n/*\n * bpf_skb_vlan_pop\n *\n * \tPop a VLAN header from the packet associated to *skb*.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_vlan_pop)(struct __sk_buff *skb) = (void *) 19;\n\n/*\n * bpf_skb_get_tunnel_key\n *\n * \tGet tunnel metadata. This helper takes a pointer *key* to an\n * \tempty **struct bpf_tunnel_key** of **size**, that will be\n * \tfilled with tunnel metadata for the packet associated to *skb*.\n * \tThe *flags* can be set to **BPF_F_TUNINFO_IPV6**, which\n * \tindicates that the tunnel is based on IPv6 protocol instead of\n * \tIPv4.\n *\n * \tThe **struct bpf_tunnel_key** is an object that generalizes the\n * \tprincipal parameters used by various tunneling protocols into a\n * \tsingle struct. This way, it can be used to easily make a\n * \tdecision based on the contents of the encapsulation header,\n * \t\"summarized\" in this struct. In particular, it holds the IP\n * \taddress of the remote end (IPv4 or IPv6, depending on the case)\n * \tin *key*\\ **->remote_ipv4** or *key*\\ **->remote_ipv6**. Also,\n * \tthis struct exposes the *key*\\ **->tunnel_id**, which is\n * \tgenerally mapped to a VNI (Virtual Network Identifier), making\n * \tit programmable together with the **bpf_skb_set_tunnel_key**\\\n * \t() helper.\n *\n * \tLet's imagine that the following code is part of a program\n * \tattached to the TC ingress interface, on one end of a GRE\n * \ttunnel, and is supposed to filter out all messages coming from\n * \tremote ends with IPv4 address other than 10.0.0.1:\n *\n * \t::\n *\n * \t\tint ret;\n * \t\tstruct bpf_tunnel_key key = {};\n *\n * \t\tret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);\n * \t\tif (ret < 0)\n * \t\t\treturn TC_ACT_SHOT;\t// drop packet\n *\n * \t\tif (key.remote_ipv4 != 0x0a000001)\n * \t\t\treturn TC_ACT_SHOT;\t// drop packet\n *\n * \t\treturn TC_ACT_OK;\t\t// accept packet\n *\n * \tThis interface can also be used with all encapsulation devices\n * \tthat can operate in \"collect metadata\" mode: instead of having\n * \tone network device per specific configuration, the \"collect\n * \tmetadata\" mode only requires a single device where the\n * \tconfiguration can be extracted from this helper.\n *\n * \tThis can be used together with various tunnels such as VXLan,\n * \tGeneve, GRE or IP in IP (IPIP).\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_get_tunnel_key)(struct __sk_buff *skb, struct bpf_tunnel_key *key, __u32 size, __u64 flags) = (void *) 20;\n\n/*\n * bpf_skb_set_tunnel_key\n *\n * \tPopulate tunnel metadata for packet associated to *skb.* The\n * \ttunnel metadata is set to the contents of *key*, of *size*. The\n * \t*flags* can be set to a combination of the following values:\n *\n * \t**BPF_F_TUNINFO_IPV6**\n * \t\tIndicate that the tunnel is based on IPv6 protocol\n * \t\tinstead of IPv4.\n * \t**BPF_F_ZERO_CSUM_TX**\n * \t\tFor IPv4 packets, add a flag to tunnel metadata\n * \t\tindicating that checksum computation should be skipped\n * \t\tand checksum set to zeroes.\n * \t**BPF_F_DONT_FRAGMENT**\n * \t\tAdd a flag to tunnel metadata indicating that the\n * \t\tpacket should not be fragmented.\n * \t**BPF_F_SEQ_NUMBER**\n * \t\tAdd a flag to tunnel metadata indicating that a\n * \t\tsequence number should be added to tunnel header before\n * \t\tsending the packet. This flag was added for GRE\n * \t\tencapsulation, but might be used with other protocols\n * \t\tas well in the future.\n * \t**BPF_F_NO_TUNNEL_KEY**\n * \t\tAdd a flag to tunnel metadata indicating that no tunnel\n * \t\tkey should be set in the resulting tunnel header.\n *\n * \tHere is a typical usage on the transmit path:\n *\n * \t::\n *\n * \t\tstruct bpf_tunnel_key key;\n * \t\t     populate key ...\n * \t\tbpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);\n * \t\tbpf_clone_redirect(skb, vxlan_dev_ifindex, 0);\n *\n * \tSee also the description of the **bpf_skb_get_tunnel_key**\\ ()\n * \thelper for additional information.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_set_tunnel_key)(struct __sk_buff *skb, struct bpf_tunnel_key *key, __u32 size, __u64 flags) = (void *) 21;\n\n/*\n * bpf_perf_event_read\n *\n * \tRead the value of a perf event counter. This helper relies on a\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The nature of\n * \tthe perf event counter is selected when *map* is updated with\n * \tperf event file descriptors. The *map* is an array whose size\n * \tis the number of available CPUs, and each cell contains a value\n * \trelative to one CPU. The value to retrieve is indicated by\n * \t*flags*, that contains the index of the CPU to look up, masked\n * \twith **BPF_F_INDEX_MASK**. Alternatively, *flags* can be set to\n * \t**BPF_F_CURRENT_CPU** to indicate that the value for the\n * \tcurrent CPU should be retrieved.\n *\n * \tNote that before Linux 4.13, only hardware perf event can be\n * \tretrieved.\n *\n * \tAlso, be aware that the newer helper\n * \t**bpf_perf_event_read_value**\\ () is recommended over\n * \t**bpf_perf_event_read**\\ () in general. The latter has some ABI\n * \tquirks where error and counter value are used as a return code\n * \t(which is wrong to do since ranges may overlap). This issue is\n * \tfixed with **bpf_perf_event_read_value**\\ (), which at the same\n * \ttime provides more features over the **bpf_perf_event_read**\\\n * \t() interface. Please refer to the description of\n * \t**bpf_perf_event_read_value**\\ () for details.\n *\n * Returns\n * \tThe value of the perf event counter read from the map, or a\n * \tnegative error code in case of failure.\n */\nstatic __u64 (*bpf_perf_event_read)(void *map, __u64 flags) = (void *) 22;\n\n/*\n * bpf_redirect\n *\n * \tRedirect the packet to another net device of index *ifindex*.\n * \tThis helper is somewhat similar to **bpf_clone_redirect**\\\n * \t(), except that the packet is not cloned, which provides\n * \tincreased performance.\n *\n * \tExcept for XDP, both ingress and egress interfaces can be used\n * \tfor redirection. The **BPF_F_INGRESS** value in *flags* is used\n * \tto make the distinction (ingress path is selected if the flag\n * \tis present, egress path otherwise). Currently, XDP only\n * \tsupports redirection to the egress interface, and accepts no\n * \tflag at all.\n *\n * \tThe same effect can also be attained with the more generic\n * \t**bpf_redirect_map**\\ (), which uses a BPF map to store the\n * \tredirect target instead of providing it directly to the helper.\n *\n * Returns\n * \tFor XDP, the helper returns **XDP_REDIRECT** on success or\n * \t**XDP_ABORTED** on error. For other program types, the values\n * \tare **TC_ACT_REDIRECT** on success or **TC_ACT_SHOT** on\n * \terror.\n */\nstatic long (*bpf_redirect)(__u32 ifindex, __u64 flags) = (void *) 23;\n\n/*\n * bpf_get_route_realm\n *\n * \tRetrieve the realm or the route, that is to say the\n * \t**tclassid** field of the destination for the *skb*. The\n * \tidentifier retrieved is a user-provided tag, similar to the\n * \tone used with the net_cls cgroup (see description for\n * \t**bpf_get_cgroup_classid**\\ () helper), but here this tag is\n * \theld by a route (a destination entry), not by a task.\n *\n * \tRetrieving this identifier works with the clsact TC egress hook\n * \t(see also **tc-bpf(8)**), or alternatively on conventional\n * \tclassful egress qdiscs, but not on TC ingress path. In case of\n * \tclsact TC egress hook, this has the advantage that, internally,\n * \tthe destination entry has not been dropped yet in the transmit\n * \tpath. Therefore, the destination entry does not need to be\n * \tartificially held via **netif_keep_dst**\\ () for a classful\n * \tqdisc until the *skb* is freed.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_IP_ROUTE_CLASSID** configuration option.\n *\n * Returns\n * \tThe realm of the route for the packet associated to *skb*, or 0\n * \tif none was found.\n */\nstatic __u32 (*bpf_get_route_realm)(struct __sk_buff *skb) = (void *) 24;\n\n/*\n * bpf_perf_event_output\n *\n * \tWrite raw *data* blob into a special BPF perf event held by\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf\n * \tevent must have the following attributes: **PERF_SAMPLE_RAW**\n * \tas **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and\n * \t**PERF_COUNT_SW_BPF_OUTPUT** as **config**.\n *\n * \tThe *flags* are used to indicate the index in *map* for which\n * \tthe value must be put, masked with **BPF_F_INDEX_MASK**.\n * \tAlternatively, *flags* can be set to **BPF_F_CURRENT_CPU**\n * \tto indicate that the index of the current CPU core should be\n * \tused.\n *\n * \tThe value to write, of *size*, is passed through eBPF stack and\n * \tpointed by *data*.\n *\n * \tThe context of the program *ctx* needs also be passed to the\n * \thelper.\n *\n * \tOn user space, a program willing to read the values needs to\n * \tcall **perf_event_open**\\ () on the perf event (either for\n * \tone or for all CPUs) and to store the file descriptor into the\n * \t*map*. This must be done before the eBPF program can send data\n * \tinto it. An example is available in file\n * \t*samples/bpf/trace_output_user.c* in the Linux kernel source\n * \ttree (the eBPF program counterpart is in\n * \t*samples/bpf/trace_output_kern.c*).\n *\n * \t**bpf_perf_event_output**\\ () achieves better performance\n * \tthan **bpf_trace_printk**\\ () for sharing data with user\n * \tspace, and is much better suitable for streaming data from eBPF\n * \tprograms.\n *\n * \tNote that this helper is not restricted to tracing use cases\n * \tand can be used with programs attached to TC or XDP as well,\n * \twhere it allows for passing data to user space listeners. Data\n * \tcan be:\n *\n * \t* Only custom structs,\n * \t* Only the packet payload, or\n * \t* A combination of both.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_perf_event_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 25;\n\n/*\n * bpf_skb_load_bytes\n *\n * \tThis helper was provided as an easy way to load data from a\n * \tpacket. It can be used to load *len* bytes from *offset* from\n * \tthe packet associated to *skb*, into the buffer pointed by\n * \t*to*.\n *\n * \tSince Linux 4.7, usage of this helper has mostly been replaced\n * \tby \"direct packet access\", enabling packet data to be\n * \tmanipulated with *skb*\\ **->data** and *skb*\\ **->data_end**\n * \tpointing respectively to the first byte of packet data and to\n * \tthe byte after the last byte of packet data. However, it\n * \tremains useful if one wishes to read large quantities of data\n * \tat once from a packet into the eBPF stack.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_load_bytes)(const void *skb, __u32 offset, void *to, __u32 len) = (void *) 26;\n\n/*\n * bpf_get_stackid\n *\n * \tWalk a user or a kernel stack and return its id. To achieve\n * \tthis, the helper needs *ctx*, which is a pointer to the context\n * \ton which the tracing program is executed, and a pointer to a\n * \t*map* of type **BPF_MAP_TYPE_STACK_TRACE**.\n *\n * \tThe last argument, *flags*, holds the number of stack frames to\n * \tskip (from 0 to 255), masked with\n * \t**BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set\n * \ta combination of the following flags:\n *\n * \t**BPF_F_USER_STACK**\n * \t\tCollect a user space stack instead of a kernel stack.\n * \t**BPF_F_FAST_STACK_CMP**\n * \t\tCompare stacks by hash only.\n * \t**BPF_F_REUSE_STACKID**\n * \t\tIf two different stacks hash into the same *stackid*,\n * \t\tdiscard the old one.\n *\n * \tThe stack id retrieved is a 32 bit long integer handle which\n * \tcan be further combined with other data (including other stack\n * \tids) and used as a key into maps. This can be useful for\n * \tgenerating a variety of graphs (such as flame graphs or off-cpu\n * \tgraphs).\n *\n * \tFor walking a stack, this helper is an improvement over\n * \t**bpf_probe_read**\\ (), which can be used with unrolled loops\n * \tbut is not efficient and consumes a lot of eBPF instructions.\n * \tInstead, **bpf_get_stackid**\\ () can collect up to\n * \t**PERF_MAX_STACK_DEPTH** both kernel and user frames. Note that\n * \tthis limit can be controlled with the **sysctl** program, and\n * \tthat it should be manually increased in order to profile long\n * \tuser stacks (such as stacks for Java programs). To do so, use:\n *\n * \t::\n *\n * \t\t# sysctl kernel.perf_event_max_stack=<new value>\n *\n * Returns\n * \tThe positive or null stack id on success, or a negative error\n * \tin case of failure.\n */\nstatic long (*bpf_get_stackid)(void *ctx, void *map, __u64 flags) = (void *) 27;\n\n/*\n * bpf_csum_diff\n *\n * \tCompute a checksum difference, from the raw buffer pointed by\n * \t*from*, of length *from_size* (that must be a multiple of 4),\n * \ttowards the raw buffer pointed by *to*, of size *to_size*\n * \t(same remark). An optional *seed* can be added to the value\n * \t(this can be cascaded, the seed may come from a previous call\n * \tto the helper).\n *\n * \tThis is flexible enough to be used in several ways:\n *\n * \t* With *from_size* == 0, *to_size* > 0 and *seed* set to\n * \t  checksum, it can be used when pushing new data.\n * \t* With *from_size* > 0, *to_size* == 0 and *seed* set to\n * \t  checksum, it can be used when removing data from a packet.\n * \t* With *from_size* > 0, *to_size* > 0 and *seed* set to 0, it\n * \t  can be used to compute a diff. Note that *from_size* and\n * \t  *to_size* do not need to be equal.\n *\n * \tThis helper can be used in combination with\n * \t**bpf_l3_csum_replace**\\ () and **bpf_l4_csum_replace**\\ (), to\n * \twhich one can feed in the difference computed with\n * \t**bpf_csum_diff**\\ ().\n *\n * Returns\n * \tThe checksum result, or a negative error code in case of\n * \tfailure.\n */\nstatic __s64 (*bpf_csum_diff)(__be32 *from, __u32 from_size, __be32 *to, __u32 to_size, __wsum seed) = (void *) 28;\n\n/*\n * bpf_skb_get_tunnel_opt\n *\n * \tRetrieve tunnel options metadata for the packet associated to\n * \t*skb*, and store the raw tunnel option data to the buffer *opt*\n * \tof *size*.\n *\n * \tThis helper can be used with encapsulation devices that can\n * \toperate in \"collect metadata\" mode (please refer to the related\n * \tnote in the description of **bpf_skb_get_tunnel_key**\\ () for\n * \tmore details). A particular example where this can be used is\n * \tin combination with the Geneve encapsulation protocol, where it\n * \tallows for pushing (with **bpf_skb_get_tunnel_opt**\\ () helper)\n * \tand retrieving arbitrary TLVs (Type-Length-Value headers) from\n * \tthe eBPF program. This allows for full customization of these\n * \theaders.\n *\n * Returns\n * \tThe size of the option data retrieved.\n */\nstatic long (*bpf_skb_get_tunnel_opt)(struct __sk_buff *skb, void *opt, __u32 size) = (void *) 29;\n\n/*\n * bpf_skb_set_tunnel_opt\n *\n * \tSet tunnel options metadata for the packet associated to *skb*\n * \tto the option data contained in the raw buffer *opt* of *size*.\n *\n * \tSee also the description of the **bpf_skb_get_tunnel_opt**\\ ()\n * \thelper for additional information.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_set_tunnel_opt)(struct __sk_buff *skb, void *opt, __u32 size) = (void *) 30;\n\n/*\n * bpf_skb_change_proto\n *\n * \tChange the protocol of the *skb* to *proto*. Currently\n * \tsupported are transition from IPv4 to IPv6, and from IPv6 to\n * \tIPv4. The helper takes care of the groundwork for the\n * \ttransition, including resizing the socket buffer. The eBPF\n * \tprogram is expected to fill the new headers, if any, via\n * \t**skb_store_bytes**\\ () and to recompute the checksums with\n * \t**bpf_l3_csum_replace**\\ () and **bpf_l4_csum_replace**\\\n * \t(). The main case for this helper is to perform NAT64\n * \toperations out of an eBPF program.\n *\n * \tInternally, the GSO type is marked as dodgy so that headers are\n * \tchecked and segments are recalculated by the GSO/GRO engine.\n * \tThe size for GSO target is adapted as well.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_proto)(struct __sk_buff *skb, __be16 proto, __u64 flags) = (void *) 31;\n\n/*\n * bpf_skb_change_type\n *\n * \tChange the packet type for the packet associated to *skb*. This\n * \tcomes down to setting *skb*\\ **->pkt_type** to *type*, except\n * \tthe eBPF program does not have a write access to *skb*\\\n * \t**->pkt_type** beside this helper. Using a helper here allows\n * \tfor graceful handling of errors.\n *\n * \tThe major use case is to change incoming *skb*s to\n * \t**PACKET_HOST** in a programmatic way instead of having to\n * \trecirculate via **redirect**\\ (..., **BPF_F_INGRESS**), for\n * \texample.\n *\n * \tNote that *type* only allows certain values. At this time, they\n * \tare:\n *\n * \t**PACKET_HOST**\n * \t\tPacket is for us.\n * \t**PACKET_BROADCAST**\n * \t\tSend packet to all.\n * \t**PACKET_MULTICAST**\n * \t\tSend packet to group.\n * \t**PACKET_OTHERHOST**\n * \t\tSend packet to someone else.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_type)(struct __sk_buff *skb, __u32 type) = (void *) 32;\n\n/*\n * bpf_skb_under_cgroup\n *\n * \tCheck whether *skb* is a descendant of the cgroup2 held by\n * \t*map* of type **BPF_MAP_TYPE_CGROUP_ARRAY**, at *index*.\n *\n * Returns\n * \tThe return value depends on the result of the test, and can be:\n *\n * \t* 0, if the *skb* failed the cgroup2 descendant test.\n * \t* 1, if the *skb* succeeded the cgroup2 descendant test.\n * \t* A negative error code, if an error occurred.\n */\nstatic long (*bpf_skb_under_cgroup)(struct __sk_buff *skb, void *map, __u32 index) = (void *) 33;\n\n/*\n * bpf_get_hash_recalc\n *\n * \tRetrieve the hash of the packet, *skb*\\ **->hash**. If it is\n * \tnot set, in particular if the hash was cleared due to mangling,\n * \trecompute this hash. Later accesses to the hash can be done\n * \tdirectly with *skb*\\ **->hash**.\n *\n * \tCalling **bpf_set_hash_invalid**\\ (), changing a packet\n * \tprototype with **bpf_skb_change_proto**\\ (), or calling\n * \t**bpf_skb_store_bytes**\\ () with the\n * \t**BPF_F_INVALIDATE_HASH** are actions susceptible to clear\n * \tthe hash and to trigger a new computation for the next call to\n * \t**bpf_get_hash_recalc**\\ ().\n *\n * Returns\n * \tThe 32-bit hash.\n */\nstatic __u32 (*bpf_get_hash_recalc)(struct __sk_buff *skb) = (void *) 34;\n\n/*\n * bpf_get_current_task\n *\n * \tGet the current task.\n *\n * Returns\n * \tA pointer to the current task struct.\n */\nstatic __u64 (*bpf_get_current_task)(void) = (void *) 35;\n\n/*\n * bpf_probe_write_user\n *\n * \tAttempt in a safe way to write *len* bytes from the buffer\n * \t*src* to *dst* in memory. It only works for threads that are in\n * \tuser context, and *dst* must be a valid user space address.\n *\n * \tThis helper should not be used to implement any kind of\n * \tsecurity mechanism because of TOC-TOU attacks, but rather to\n * \tdebug, divert, and manipulate execution of semi-cooperative\n * \tprocesses.\n *\n * \tKeep in mind that this feature is meant for experiments, and it\n * \thas a risk of crashing the system and running programs.\n * \tTherefore, when an eBPF program using this helper is attached,\n * \ta warning including PID and process name is printed to kernel\n * \tlogs.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_write_user)(void *dst, const void *src, __u32 len) = (void *) 36;\n\n/*\n * bpf_current_task_under_cgroup\n *\n * \tCheck whether the probe is being run is the context of a given\n * \tsubset of the cgroup2 hierarchy. The cgroup2 to test is held by\n * \t*map* of type **BPF_MAP_TYPE_CGROUP_ARRAY**, at *index*.\n *\n * Returns\n * \tThe return value depends on the result of the test, and can be:\n *\n * \t* 1, if current task belongs to the cgroup2.\n * \t* 0, if current task does not belong to the cgroup2.\n * \t* A negative error code, if an error occurred.\n */\nstatic long (*bpf_current_task_under_cgroup)(void *map, __u32 index) = (void *) 37;\n\n/*\n * bpf_skb_change_tail\n *\n * \tResize (trim or grow) the packet associated to *skb* to the\n * \tnew *len*. The *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThe basic idea is that the helper performs the needed work to\n * \tchange the size of the packet, then the eBPF program rewrites\n * \tthe rest via helpers like **bpf_skb_store_bytes**\\ (),\n * \t**bpf_l3_csum_replace**\\ (), **bpf_l3_csum_replace**\\ ()\n * \tand others. This helper is a slow path utility intended for\n * \treplies with control messages. And because it is targeted for\n * \tslow path, the helper itself can afford to be slow: it\n * \timplicitly linearizes, unclones and drops offloads from the\n * \t*skb*.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_tail)(struct __sk_buff *skb, __u32 len, __u64 flags) = (void *) 38;\n\n/*\n * bpf_skb_pull_data\n *\n * \tPull in non-linear data in case the *skb* is non-linear and not\n * \tall of *len* are part of the linear section. Make *len* bytes\n * \tfrom *skb* readable and writable. If a zero value is passed for\n * \t*len*, then all bytes in the linear part of *skb* will be made\n * \treadable and writable.\n *\n * \tThis helper is only needed for reading and writing with direct\n * \tpacket access.\n *\n * \tFor direct packet access, testing that offsets to access\n * \tare within packet boundaries (test on *skb*\\ **->data_end**) is\n * \tsusceptible to fail if offsets are invalid, or if the requested\n * \tdata is in non-linear parts of the *skb*. On failure the\n * \tprogram can just bail out, or in the case of a non-linear\n * \tbuffer, use a helper to make the data available. The\n * \t**bpf_skb_load_bytes**\\ () helper is a first solution to access\n * \tthe data. Another one consists in using **bpf_skb_pull_data**\n * \tto pull in once the non-linear parts, then retesting and\n * \teventually access the data.\n *\n * \tAt the same time, this also makes sure the *skb* is uncloned,\n * \twhich is a necessary condition for direct write. As this needs\n * \tto be an invariant for the write part only, the verifier\n * \tdetects writes and adds a prologue that is calling\n * \t**bpf_skb_pull_data()** to effectively unclone the *skb* from\n * \tthe very beginning in case it is indeed cloned.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_pull_data)(struct __sk_buff *skb, __u32 len) = (void *) 39;\n\n/*\n * bpf_csum_update\n *\n * \tAdd the checksum *csum* into *skb*\\ **->csum** in case the\n * \tdriver has supplied a checksum for the entire packet into that\n * \tfield. Return an error otherwise. This helper is intended to be\n * \tused in combination with **bpf_csum_diff**\\ (), in particular\n * \twhen the checksum needs to be updated after data has been\n * \twritten into the packet through direct packet access.\n *\n * Returns\n * \tThe checksum on success, or a negative error code in case of\n * \tfailure.\n */\nstatic __s64 (*bpf_csum_update)(struct __sk_buff *skb, __wsum csum) = (void *) 40;\n\n/*\n * bpf_set_hash_invalid\n *\n * \tInvalidate the current *skb*\\ **->hash**. It can be used after\n * \tmangling on headers through direct packet access, in order to\n * \tindicate that the hash is outdated and to trigger a\n * \trecalculation the next time the kernel tries to access this\n * \thash or when the **bpf_get_hash_recalc**\\ () helper is called.\n *\n * Returns\n * \tvoid.\n */\nstatic void (*bpf_set_hash_invalid)(struct __sk_buff *skb) = (void *) 41;\n\n/*\n * bpf_get_numa_node_id\n *\n * \tReturn the id of the current NUMA node. The primary use case\n * \tfor this helper is the selection of sockets for the local NUMA\n * \tnode, when the program is attached to sockets using the\n * \t**SO_ATTACH_REUSEPORT_EBPF** option (see also **socket(7)**),\n * \tbut the helper is also available to other eBPF program types,\n * \tsimilarly to **bpf_get_smp_processor_id**\\ ().\n *\n * Returns\n * \tThe id of current NUMA node.\n */\nstatic long (*bpf_get_numa_node_id)(void) = (void *) 42;\n\n/*\n * bpf_skb_change_head\n *\n * \tGrows headroom of packet associated to *skb* and adjusts the\n * \toffset of the MAC header accordingly, adding *len* bytes of\n * \tspace. It automatically extends and reallocates memory as\n * \trequired.\n *\n * \tThis helper can be used on a layer 3 *skb* to push a MAC header\n * \tfor redirection into a layer 2 device.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_head)(struct __sk_buff *skb, __u32 len, __u64 flags) = (void *) 43;\n\n/*\n * bpf_xdp_adjust_head\n *\n * \tAdjust (move) *xdp_md*\\ **->data** by *delta* bytes. Note that\n * \tit is possible to use a negative value for *delta*. This helper\n * \tcan be used to prepare the packet for pushing or popping\n * \theaders.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_adjust_head)(struct xdp_md *xdp_md, int delta) = (void *) 44;\n\n/*\n * bpf_probe_read_str\n *\n * \tCopy a NUL terminated string from an unsafe kernel address\n * \t*unsafe_ptr* to *dst*. See **bpf_probe_read_kernel_str**\\ () for\n * \tmore details.\n *\n * \tGenerally, use **bpf_probe_read_user_str**\\ () or\n * \t**bpf_probe_read_kernel_str**\\ () instead.\n *\n * Returns\n * \tOn success, the strictly positive length of the string,\n * \tincluding the trailing NUL character. On error, a negative\n * \tvalue.\n */\nstatic long (*bpf_probe_read_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 45;\n\n/*\n * bpf_get_socket_cookie\n *\n * \tIf the **struct sk_buff** pointed by *skb* has a known socket,\n * \tretrieve the cookie (generated by the kernel) of this socket.\n * \tIf no cookie has been set yet, generate a new cookie. Once\n * \tgenerated, the socket cookie remains stable for the life of the\n * \tsocket. This helper can be useful for monitoring per socket\n * \tnetworking traffic statistics as it provides a global socket\n * \tidentifier that can be assumed unique.\n *\n * Returns\n * \tA 8-byte long unique number on success, or 0 if the socket\n * \tfield is missing inside *skb*.\n */\nstatic __u64 (*bpf_get_socket_cookie)(void *ctx) = (void *) 46;\n\n/*\n * bpf_get_socket_uid\n *\n * \tGet the owner UID of the socked associated to *skb*.\n *\n * Returns\n * \tThe owner UID of the socket associated to *skb*. If the socket\n * \tis **NULL**, or if it is not a full socket (i.e. if it is a\n * \ttime-wait or a request socket instead), **overflowuid** value\n * \tis returned (note that **overflowuid** might also be the actual\n * \tUID value for the socket).\n */\nstatic __u32 (*bpf_get_socket_uid)(struct __sk_buff *skb) = (void *) 47;\n\n/*\n * bpf_set_hash\n *\n * \tSet the full hash for *skb* (set the field *skb*\\ **->hash**)\n * \tto value *hash*.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_set_hash)(struct __sk_buff *skb, __u32 hash) = (void *) 48;\n\n/*\n * bpf_setsockopt\n *\n * \tEmulate a call to **setsockopt()** on the socket associated to\n * \t*bpf_socket*, which must be a full socket. The *level* at\n * \twhich the option resides and the name *optname* of the option\n * \tmust be specified, see **setsockopt(2)** for more information.\n * \tThe option value of length *optlen* is pointed by *optval*.\n *\n * \t*bpf_socket* should be one of the following:\n *\n * \t* **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**.\n * \t* **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**\n * \t  and **BPF_CGROUP_INET6_CONNECT**.\n *\n * \tThis helper actually implements a subset of **setsockopt()**.\n * \tIt supports the following *level*\\ s:\n *\n * \t* **SOL_SOCKET**, which supports the following *optname*\\ s:\n * \t  **SO_RCVBUF**, **SO_SNDBUF**, **SO_MAX_PACING_RATE**,\n * \t  **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**,\n * \t  **SO_BINDTODEVICE**, **SO_KEEPALIVE**, **SO_REUSEADDR**,\n * \t  **SO_REUSEPORT**, **SO_BINDTOIFINDEX**, **SO_TXREHASH**.\n * \t* **IPPROTO_TCP**, which supports the following *optname*\\ s:\n * \t  **TCP_CONGESTION**, **TCP_BPF_IW**,\n * \t  **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**,\n * \t  **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**,\n * \t  **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,\n * \t  **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,\n * \t  **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,\n * \t  **TCP_BPF_RTO_MIN**.\n * \t* **IPPROTO_IP**, which supports *optname* **IP_TOS**.\n * \t* **IPPROTO_IPV6**, which supports the following *optname*\\ s:\n * \t  **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_setsockopt)(void *bpf_socket, int level, int optname, void *optval, int optlen) = (void *) 49;\n\n/*\n * bpf_skb_adjust_room\n *\n * \tGrow or shrink the room for data in the packet associated to\n * \t*skb* by *len_diff*, and according to the selected *mode*.\n *\n * \tBy default, the helper will reset any offloaded checksum\n * \tindicator of the skb to CHECKSUM_NONE. This can be avoided\n * \tby the following flag:\n *\n * \t* **BPF_F_ADJ_ROOM_NO_CSUM_RESET**: Do not reset offloaded\n * \t  checksum data of the skb to CHECKSUM_NONE.\n *\n * \tThere are two supported modes at this time:\n *\n * \t* **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer\n * \t  (room space is added or removed between the layer 2 and\n * \t  layer 3 headers).\n *\n * \t* **BPF_ADJ_ROOM_NET**: Adjust room at the network layer\n * \t  (room space is added or removed between the layer 3 and\n * \t  layer 4 headers).\n *\n * \tThe following flags are supported at this time:\n *\n * \t* **BPF_F_ADJ_ROOM_FIXED_GSO**: Do not adjust gso_size.\n * \t  Adjusting mss in this way is not allowed for datagrams.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4**,\n * \t  **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6**:\n * \t  Any new space is reserved to hold a tunnel header.\n * \t  Configure skb offsets and other fields accordingly.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L4_GRE**,\n * \t  **BPF_F_ADJ_ROOM_ENCAP_L4_UDP**:\n * \t  Use with ENCAP_L3 flags to further specify the tunnel type.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L2**\\ (*len*):\n * \t  Use with ENCAP_L3/L4 flags to further specify the tunnel\n * \t  type; *len* is the length of the inner MAC header.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L2_ETH**:\n * \t  Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the\n * \t  L2 type as Ethernet.\n *\n * \t* **BPF_F_ADJ_ROOM_DECAP_L3_IPV4**,\n * \t  **BPF_F_ADJ_ROOM_DECAP_L3_IPV6**:\n * \t  Indicate the new IP header version after decapsulating the outer\n * \t  IP header. Used when the inner and outer IP versions are different.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_adjust_room)(struct __sk_buff *skb, __s32 len_diff, __u32 mode, __u64 flags) = (void *) 50;\n\n/*\n * bpf_redirect_map\n *\n * \tRedirect the packet to the endpoint referenced by *map* at\n * \tindex *key*. Depending on its type, this *map* can contain\n * \treferences to net devices (for forwarding packets through other\n * \tports), or to CPUs (for redirecting XDP frames to another CPU;\n * \tbut this is only implemented for native XDP (with driver\n * \tsupport) as of this writing).\n *\n * \tThe lower two bits of *flags* are used as the return code if\n * \tthe map lookup fails. This is so that the return value can be\n * \tone of the XDP program return codes up to **XDP_TX**, as chosen\n * \tby the caller. The higher bits of *flags* can be set to\n * \tBPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below.\n *\n * \tWith BPF_F_BROADCAST the packet will be broadcasted to all the\n * \tinterfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress\n * \tinterface will be excluded when do broadcasting.\n *\n * \tSee also **bpf_redirect**\\ (), which only supports redirecting\n * \tto an ifindex, but doesn't require a map to do so.\n *\n * Returns\n * \t**XDP_REDIRECT** on success, or the value of the two lower bits\n * \tof the *flags* argument on error.\n */\nstatic long (*bpf_redirect_map)(void *map, __u64 key, __u64 flags) = (void *) 51;\n\n/*\n * bpf_sk_redirect_map\n *\n * \tRedirect the packet to the socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress path otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_sk_redirect_map)(struct __sk_buff *skb, void *map, __u32 key, __u64 flags) = (void *) 52;\n\n/*\n * bpf_sock_map_update\n *\n * \tAdd an entry to, or update a *map* referencing sockets. The\n * \t*skops* is used as a new value for the entry associated to\n * \t*key*. *flags* is one of:\n *\n * \t**BPF_NOEXIST**\n * \t\tThe entry for *key* must not exist in the map.\n * \t**BPF_EXIST**\n * \t\tThe entry for *key* must already exist in the map.\n * \t**BPF_ANY**\n * \t\tNo condition on the existence of the entry for *key*.\n *\n * \tIf the *map* has eBPF programs (parser and verdict), those will\n * \tbe inherited by the socket being added. If the socket is\n * \talready attached to eBPF programs, this results in an error.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sock_map_update)(struct bpf_sock_ops *skops, void *map, void *key, __u64 flags) = (void *) 53;\n\n/*\n * bpf_xdp_adjust_meta\n *\n * \tAdjust the address pointed by *xdp_md*\\ **->data_meta** by\n * \t*delta* (which can be positive or negative). Note that this\n * \toperation modifies the address stored in *xdp_md*\\ **->data**,\n * \tso the latter must be loaded only after the helper has been\n * \tcalled.\n *\n * \tThe use of *xdp_md*\\ **->data_meta** is optional and programs\n * \tare not required to use it. The rationale is that when the\n * \tpacket is processed with XDP (e.g. as DoS filter), it is\n * \tpossible to push further meta data along with it before passing\n * \tto the stack, and to give the guarantee that an ingress eBPF\n * \tprogram attached as a TC classifier on the same device can pick\n * \tthis up for further post-processing. Since TC works with socket\n * \tbuffers, it remains possible to set from XDP the **mark** or\n * \t**priority** pointers, or other pointers for the socket buffer.\n * \tHaving this scratch space generic and programmable allows for\n * \tmore flexibility as the user is free to store whatever meta\n * \tdata they need.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_adjust_meta)(struct xdp_md *xdp_md, int delta) = (void *) 54;\n\n/*\n * bpf_perf_event_read_value\n *\n * \tRead the value of a perf event counter, and store it into *buf*\n * \tof size *buf_size*. This helper relies on a *map* of type\n * \t**BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The nature of the perf event\n * \tcounter is selected when *map* is updated with perf event file\n * \tdescriptors. The *map* is an array whose size is the number of\n * \tavailable CPUs, and each cell contains a value relative to one\n * \tCPU. The value to retrieve is indicated by *flags*, that\n * \tcontains the index of the CPU to look up, masked with\n * \t**BPF_F_INDEX_MASK**. Alternatively, *flags* can be set to\n * \t**BPF_F_CURRENT_CPU** to indicate that the value for the\n * \tcurrent CPU should be retrieved.\n *\n * \tThis helper behaves in a way close to\n * \t**bpf_perf_event_read**\\ () helper, save that instead of\n * \tjust returning the value observed, it fills the *buf*\n * \tstructure. This allows for additional data to be retrieved: in\n * \tparticular, the enabled and running times (in *buf*\\\n * \t**->enabled** and *buf*\\ **->running**, respectively) are\n * \tcopied. In general, **bpf_perf_event_read_value**\\ () is\n * \trecommended over **bpf_perf_event_read**\\ (), which has some\n * \tABI issues and provides fewer functionalities.\n *\n * \tThese values are interesting, because hardware PMU (Performance\n * \tMonitoring Unit) counters are limited resources. When there are\n * \tmore PMU based perf events opened than available counters,\n * \tkernel will multiplex these events so each event gets certain\n * \tpercentage (but not all) of the PMU time. In case that\n * \tmultiplexing happens, the number of samples or counter value\n * \twill not reflect the case compared to when no multiplexing\n * \toccurs. This makes comparison between different runs difficult.\n * \tTypically, the counter value should be normalized before\n * \tcomparing to other experiments. The usual normalization is done\n * \tas follows.\n *\n * \t::\n *\n * \t\tnormalized_counter = counter * t_enabled / t_running\n *\n * \tWhere t_enabled is the time enabled for event and t_running is\n * \tthe time running for event since last normalization. The\n * \tenabled and running times are accumulated since the perf event\n * \topen. To achieve scaling factor between two invocations of an\n * \teBPF program, users can use CPU id as the key (which is\n * \ttypical for perf array usage model) to remember the previous\n * \tvalue and do the calculation inside the eBPF program.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_perf_event_read_value)(void *map, __u64 flags, struct bpf_perf_event_value *buf, __u32 buf_size) = (void *) 55;\n\n/*\n * bpf_perf_prog_read_value\n *\n * \tFor an eBPF program attached to a perf event, retrieve the\n * \tvalue of the event counter associated to *ctx* and store it in\n * \tthe structure pointed by *buf* and of size *buf_size*. Enabled\n * \tand running times are also stored in the structure (see\n * \tdescription of helper **bpf_perf_event_read_value**\\ () for\n * \tmore details).\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_perf_prog_read_value)(struct bpf_perf_event_data *ctx, struct bpf_perf_event_value *buf, __u32 buf_size) = (void *) 56;\n\n/*\n * bpf_getsockopt\n *\n * \tEmulate a call to **getsockopt()** on the socket associated to\n * \t*bpf_socket*, which must be a full socket. The *level* at\n * \twhich the option resides and the name *optname* of the option\n * \tmust be specified, see **getsockopt(2)** for more information.\n * \tThe retrieved value is stored in the structure pointed by\n * \t*opval* and of length *optlen*.\n *\n * \t*bpf_socket* should be one of the following:\n *\n * \t* **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**.\n * \t* **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**\n * \t  and **BPF_CGROUP_INET6_CONNECT**.\n *\n * \tThis helper actually implements a subset of **getsockopt()**.\n * \tIt supports the same set of *optname*\\ s that is supported by\n * \tthe **bpf_setsockopt**\\ () helper.  The exceptions are\n * \t**TCP_BPF_*** is **bpf_setsockopt**\\ () only and\n * \t**TCP_SAVED_SYN** is **bpf_getsockopt**\\ () only.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_getsockopt)(void *bpf_socket, int level, int optname, void *optval, int optlen) = (void *) 57;\n\n/*\n * bpf_override_return\n *\n * \tUsed for error injection, this helper uses kprobes to override\n * \tthe return value of the probed function, and to set it to *rc*.\n * \tThe first argument is the context *regs* on which the kprobe\n * \tworks.\n *\n * \tThis helper works by setting the PC (program counter)\n * \tto an override function which is run in place of the original\n * \tprobed function. This means the probed function is not run at\n * \tall. The replacement function just returns with the required\n * \tvalue.\n *\n * \tThis helper has security implications, and thus is subject to\n * \trestrictions. It is only available if the kernel was compiled\n * \twith the **CONFIG_BPF_KPROBE_OVERRIDE** configuration\n * \toption, and in this case it only works on functions tagged with\n * \t**ALLOW_ERROR_INJECTION** in the kernel code.\n *\n * \tAlso, the helper is only available for the architectures having\n * \tthe CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing,\n * \tx86 architecture is the only one to support this feature.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_override_return)(struct pt_regs *regs, __u64 rc) = (void *) 58;\n\n/*\n * bpf_sock_ops_cb_flags_set\n *\n * \tAttempt to set the value of the **bpf_sock_ops_cb_flags** field\n * \tfor the full TCP socket associated to *bpf_sock_ops* to\n * \t*argval*.\n *\n * \tThe primary use of this field is to determine if there should\n * \tbe calls to eBPF programs of type\n * \t**BPF_PROG_TYPE_SOCK_OPS** at various points in the TCP\n * \tcode. A program of the same type can change its value, per\n * \tconnection and as necessary, when the connection is\n * \testablished. This field is directly accessible for reading, but\n * \tthis helper must be used for updates in order to return an\n * \terror if an eBPF program tries to set a callback that is not\n * \tsupported in the current kernel.\n *\n * \t*argval* is a flag array which can combine these flags:\n *\n * \t* **BPF_SOCK_OPS_RTO_CB_FLAG** (retransmission time out)\n * \t* **BPF_SOCK_OPS_RETRANS_CB_FLAG** (retransmission)\n * \t* **BPF_SOCK_OPS_STATE_CB_FLAG** (TCP state change)\n * \t* **BPF_SOCK_OPS_RTT_CB_FLAG** (every RTT)\n *\n * \tTherefore, this function can be used to clear a callback flag by\n * \tsetting the appropriate bit to zero. e.g. to disable the RTO\n * \tcallback:\n *\n * \t**bpf_sock_ops_cb_flags_set(bpf_sock,**\n * \t\t**bpf_sock->bpf_sock_ops_cb_flags & ~BPF_SOCK_OPS_RTO_CB_FLAG)**\n *\n * \tHere are some examples of where one could call such eBPF\n * \tprogram:\n *\n * \t* When RTO fires.\n * \t* When a packet is retransmitted.\n * \t* When the connection terminates.\n * \t* When a packet is sent.\n * \t* When a packet is received.\n *\n * Returns\n * \tCode **-EINVAL** if the socket is not a full TCP socket;\n * \totherwise, a positive number containing the bits that could not\n * \tbe set is returned (which comes down to 0 if all bits were set\n * \tas required).\n */\nstatic long (*bpf_sock_ops_cb_flags_set)(struct bpf_sock_ops *bpf_sock, int argval) = (void *) 59;\n\n/*\n * bpf_msg_redirect_map\n *\n * \tThis helper is used in programs implementing policies at the\n * \tsocket level. If the message *msg* is allowed to pass (i.e. if\n * \tthe verdict eBPF program returns **SK_PASS**), redirect it to\n * \tthe socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress path otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_msg_redirect_map)(struct sk_msg_md *msg, void *map, __u32 key, __u64 flags) = (void *) 60;\n\n/*\n * bpf_msg_apply_bytes\n *\n * \tFor socket policies, apply the verdict of the eBPF program to\n * \tthe next *bytes* (number of bytes) of message *msg*.\n *\n * \tFor example, this helper can be used in the following cases:\n *\n * \t* A single **sendmsg**\\ () or **sendfile**\\ () system call\n * \t  contains multiple logical messages that the eBPF program is\n * \t  supposed to read and for which it should apply a verdict.\n * \t* An eBPF program only cares to read the first *bytes* of a\n * \t  *msg*. If the message has a large payload, then setting up\n * \t  and calling the eBPF program repeatedly for all bytes, even\n * \t  though the verdict is already known, would create unnecessary\n * \t  overhead.\n *\n * \tWhen called from within an eBPF program, the helper sets a\n * \tcounter internal to the BPF infrastructure, that is used to\n * \tapply the last verdict to the next *bytes*. If *bytes* is\n * \tsmaller than the current data being processed from a\n * \t**sendmsg**\\ () or **sendfile**\\ () system call, the first\n * \t*bytes* will be sent and the eBPF program will be re-run with\n * \tthe pointer for start of data pointing to byte number *bytes*\n * \t**+ 1**. If *bytes* is larger than the current data being\n * \tprocessed, then the eBPF verdict will be applied to multiple\n * \t**sendmsg**\\ () or **sendfile**\\ () calls until *bytes* are\n * \tconsumed.\n *\n * \tNote that if a socket closes with the internal counter holding\n * \ta non-zero value, this is not a problem because data is not\n * \tbeing buffered for *bytes* and is sent as it is received.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_msg_apply_bytes)(struct sk_msg_md *msg, __u32 bytes) = (void *) 61;\n\n/*\n * bpf_msg_cork_bytes\n *\n * \tFor socket policies, prevent the execution of the verdict eBPF\n * \tprogram for message *msg* until *bytes* (byte number) have been\n * \taccumulated.\n *\n * \tThis can be used when one needs a specific number of bytes\n * \tbefore a verdict can be assigned, even if the data spans\n * \tmultiple **sendmsg**\\ () or **sendfile**\\ () calls. The extreme\n * \tcase would be a user calling **sendmsg**\\ () repeatedly with\n * \t1-byte long message segments. Obviously, this is bad for\n * \tperformance, but it is still valid. If the eBPF program needs\n * \t*bytes* bytes to validate a header, this helper can be used to\n * \tprevent the eBPF program to be called again until *bytes* have\n * \tbeen accumulated.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_msg_cork_bytes)(struct sk_msg_md *msg, __u32 bytes) = (void *) 62;\n\n/*\n * bpf_msg_pull_data\n *\n * \tFor socket policies, pull in non-linear data from user space\n * \tfor *msg* and set pointers *msg*\\ **->data** and *msg*\\\n * \t**->data_end** to *start* and *end* bytes offsets into *msg*,\n * \trespectively.\n *\n * \tIf a program of type **BPF_PROG_TYPE_SK_MSG** is run on a\n * \t*msg* it can only parse data that the (**data**, **data_end**)\n * \tpointers have already consumed. For **sendmsg**\\ () hooks this\n * \tis likely the first scatterlist element. But for calls relying\n * \ton the **sendpage** handler (e.g. **sendfile**\\ ()) this will\n * \tbe the range (**0**, **0**) because the data is shared with\n * \tuser space and by default the objective is to avoid allowing\n * \tuser space to modify data while (or after) eBPF verdict is\n * \tbeing decided. This helper can be used to pull in data and to\n * \tset the start and end pointer to given values. Data will be\n * \tcopied if necessary (i.e. if data was not linear and if start\n * \tand end pointers do not point to the same chunk).\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_msg_pull_data)(struct sk_msg_md *msg, __u32 start, __u32 end, __u64 flags) = (void *) 63;\n\n/*\n * bpf_bind\n *\n * \tBind the socket associated to *ctx* to the address pointed by\n * \t*addr*, of length *addr_len*. This allows for making outgoing\n * \tconnection from the desired IP address, which can be useful for\n * \texample when all processes inside a cgroup should use one\n * \tsingle IP address on a host that has multiple IP configured.\n *\n * \tThis helper works for IPv4 and IPv6, TCP and UDP sockets. The\n * \tdomain (*addr*\\ **->sa_family**) must be **AF_INET** (or\n * \t**AF_INET6**). It's advised to pass zero port (**sin_port**\n * \tor **sin6_port**) which triggers IP_BIND_ADDRESS_NO_PORT-like\n * \tbehavior and lets the kernel efficiently pick up an unused\n * \tport as long as 4-tuple is unique. Passing non-zero port might\n * \tlead to degraded performance.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_bind)(struct bpf_sock_addr *ctx, struct sockaddr *addr, int addr_len) = (void *) 64;\n\n/*\n * bpf_xdp_adjust_tail\n *\n * \tAdjust (move) *xdp_md*\\ **->data_end** by *delta* bytes. It is\n * \tpossible to both shrink and grow the packet tail.\n * \tShrink done via *delta* being a negative integer.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_adjust_tail)(struct xdp_md *xdp_md, int delta) = (void *) 65;\n\n/*\n * bpf_skb_get_xfrm_state\n *\n * \tRetrieve the XFRM state (IP transform framework, see also\n * \t**ip-xfrm(8)**) at *index* in XFRM \"security path\" for *skb*.\n *\n * \tThe retrieved value is stored in the **struct bpf_xfrm_state**\n * \tpointed by *xfrm_state* and of length *size*.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_XFRM** configuration option.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_get_xfrm_state)(struct __sk_buff *skb, __u32 index, struct bpf_xfrm_state *xfrm_state, __u32 size, __u64 flags) = (void *) 66;\n\n/*\n * bpf_get_stack\n *\n * \tReturn a user or a kernel stack in bpf program provided buffer.\n * \tTo achieve this, the helper needs *ctx*, which is a pointer\n * \tto the context on which the tracing program is executed.\n * \tTo store the stacktrace, the bpf program provides *buf* with\n * \ta nonnegative *size*.\n *\n * \tThe last argument, *flags*, holds the number of stack frames to\n * \tskip (from 0 to 255), masked with\n * \t**BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set\n * \tthe following flags:\n *\n * \t**BPF_F_USER_STACK**\n * \t\tCollect a user space stack instead of a kernel stack.\n * \t**BPF_F_USER_BUILD_ID**\n * \t\tCollect (build_id, file_offset) instead of ips for user\n * \t\tstack, only valid if **BPF_F_USER_STACK** is also\n * \t\tspecified.\n *\n * \t\t*file_offset* is an offset relative to the beginning\n * \t\tof the executable or shared object file backing the vma\n * \t\twhich the *ip* falls in. It is *not* an offset relative\n * \t\tto that object's base address. Accordingly, it must be\n * \t\tadjusted by adding (sh_addr - sh_offset), where\n * \t\tsh_{addr,offset} correspond to the executable section\n * \t\tcontaining *file_offset* in the object, for comparisons\n * \t\tto symbols' st_value to be valid.\n *\n * \t**bpf_get_stack**\\ () can collect up to\n * \t**PERF_MAX_STACK_DEPTH** both kernel and user frames, subject\n * \tto sufficient large buffer size. Note that\n * \tthis limit can be controlled with the **sysctl** program, and\n * \tthat it should be manually increased in order to profile long\n * \tuser stacks (such as stacks for Java programs). To do so, use:\n *\n * \t::\n *\n * \t\t# sysctl kernel.perf_event_max_stack=<new value>\n *\n * Returns\n * \tThe non-negative copied *buf* length equal to or less than\n * \t*size* on success, or a negative error in case of failure.\n */\nstatic long (*bpf_get_stack)(void *ctx, void *buf, __u32 size, __u64 flags) = (void *) 67;\n\n/*\n * bpf_skb_load_bytes_relative\n *\n * \tThis helper is similar to **bpf_skb_load_bytes**\\ () in that\n * \tit provides an easy way to load *len* bytes from *offset*\n * \tfrom the packet associated to *skb*, into the buffer pointed\n * \tby *to*. The difference to **bpf_skb_load_bytes**\\ () is that\n * \ta fifth argument *start_header* exists in order to select a\n * \tbase offset to start from. *start_header* can be one of:\n *\n * \t**BPF_HDR_START_MAC**\n * \t\tBase offset to load data from is *skb*'s mac header.\n * \t**BPF_HDR_START_NET**\n * \t\tBase offset to load data from is *skb*'s network header.\n *\n * \tIn general, \"direct packet access\" is the preferred method to\n * \taccess packet data, however, this helper is in particular useful\n * \tin socket filters where *skb*\\ **->data** does not always point\n * \tto the start of the mac header and where \"direct packet access\"\n * \tis not available.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_load_bytes_relative)(const void *skb, __u32 offset, void *to, __u32 len, __u32 start_header) = (void *) 68;\n\n/*\n * bpf_fib_lookup\n *\n * \tDo FIB lookup in kernel tables using parameters in *params*.\n * \tIf lookup is successful and result shows packet is to be\n * \tforwarded, the neighbor tables are searched for the nexthop.\n * \tIf successful (ie., FIB lookup shows forwarding and nexthop\n * \tis resolved), the nexthop address is returned in ipv4_dst\n * \tor ipv6_dst based on family, smac is set to mac address of\n * \tegress device, dmac is set to nexthop mac address, rt_metric\n * \tis set to metric from route (IPv4/IPv6 only), and ifindex\n * \tis set to the device index of the nexthop from the FIB lookup.\n *\n * \t*plen* argument is the size of the passed in struct.\n * \t*flags* argument can be a combination of one or more of the\n * \tfollowing values:\n *\n * \t**BPF_FIB_LOOKUP_DIRECT**\n * \t\tDo a direct table lookup vs full lookup using FIB\n * \t\trules.\n * \t**BPF_FIB_LOOKUP_OUTPUT**\n * \t\tPerform lookup from an egress perspective (default is\n * \t\tingress).\n * \t**BPF_FIB_LOOKUP_SKIP_NEIGH**\n * \t\tSkip the neighbour table lookup. *params*->dmac\n * \t\tand *params*->smac will not be set as output. A common\n * \t\tuse case is to call **bpf_redirect_neigh**\\ () after\n * \t\tdoing **bpf_fib_lookup**\\ ().\n *\n * \t*ctx* is either **struct xdp_md** for XDP programs or\n * \t**struct sk_buff** tc cls_act programs.\n *\n * Returns\n * \t* < 0 if any input argument is invalid\n * \t*   0 on success (packet is forwarded, nexthop neighbor exists)\n * \t* > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the\n * \t  packet is not forwarded or needs assist from full stack\n *\n * \tIf lookup fails with BPF_FIB_LKUP_RET_FRAG_NEEDED, then the MTU\n * \twas exceeded and output params->mtu_result contains the MTU.\n */\nstatic long (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, int plen, __u32 flags) = (void *) 69;\n\n/*\n * bpf_sock_hash_update\n *\n * \tAdd an entry to, or update a sockhash *map* referencing sockets.\n * \tThe *skops* is used as a new value for the entry associated to\n * \t*key*. *flags* is one of:\n *\n * \t**BPF_NOEXIST**\n * \t\tThe entry for *key* must not exist in the map.\n * \t**BPF_EXIST**\n * \t\tThe entry for *key* must already exist in the map.\n * \t**BPF_ANY**\n * \t\tNo condition on the existence of the entry for *key*.\n *\n * \tIf the *map* has eBPF programs (parser and verdict), those will\n * \tbe inherited by the socket being added. If the socket is\n * \talready attached to eBPF programs, this results in an error.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sock_hash_update)(struct bpf_sock_ops *skops, void *map, void *key, __u64 flags) = (void *) 70;\n\n/*\n * bpf_msg_redirect_hash\n *\n * \tThis helper is used in programs implementing policies at the\n * \tsocket level. If the message *msg* is allowed to pass (i.e. if\n * \tthe verdict eBPF program returns **SK_PASS**), redirect it to\n * \tthe socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress path otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_msg_redirect_hash)(struct sk_msg_md *msg, void *map, void *key, __u64 flags) = (void *) 71;\n\n/*\n * bpf_sk_redirect_hash\n *\n * \tThis helper is used in programs implementing policies at the\n * \tskb socket level. If the sk_buff *skb* is allowed to pass (i.e.\n * \tif the verdict eBPF program returns **SK_PASS**), redirect it\n * \tto the socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_sk_redirect_hash)(struct __sk_buff *skb, void *map, void *key, __u64 flags) = (void *) 72;\n\n/*\n * bpf_lwt_push_encap\n *\n * \tEncapsulate the packet associated to *skb* within a Layer 3\n * \tprotocol header. This header is provided in the buffer at\n * \taddress *hdr*, with *len* its size in bytes. *type* indicates\n * \tthe protocol of the header and can be one of:\n *\n * \t**BPF_LWT_ENCAP_SEG6**\n * \t\tIPv6 encapsulation with Segment Routing Header\n * \t\t(**struct ipv6_sr_hdr**). *hdr* only contains the SRH,\n * \t\tthe IPv6 header is computed by the kernel.\n * \t**BPF_LWT_ENCAP_SEG6_INLINE**\n * \t\tOnly works if *skb* contains an IPv6 packet. Insert a\n * \t\tSegment Routing Header (**struct ipv6_sr_hdr**) inside\n * \t\tthe IPv6 header.\n * \t**BPF_LWT_ENCAP_IP**\n * \t\tIP encapsulation (GRE/GUE/IPIP/etc). The outer header\n * \t\tmust be IPv4 or IPv6, followed by zero or more\n * \t\tadditional headers, up to **LWT_BPF_MAX_HEADROOM**\n * \t\ttotal bytes in all prepended headers. Please note that\n * \t\tif **skb_is_gso**\\ (*skb*) is true, no more than two\n * \t\theaders can be prepended, and the inner header, if\n * \t\tpresent, should be either GRE or UDP/GUE.\n *\n * \t**BPF_LWT_ENCAP_SEG6**\\ \\* types can be called by BPF programs\n * \tof type **BPF_PROG_TYPE_LWT_IN**; **BPF_LWT_ENCAP_IP** type can\n * \tbe called by bpf programs of types **BPF_PROG_TYPE_LWT_IN** and\n * \t**BPF_PROG_TYPE_LWT_XMIT**.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_push_encap)(struct __sk_buff *skb, __u32 type, void *hdr, __u32 len) = (void *) 73;\n\n/*\n * bpf_lwt_seg6_store_bytes\n *\n * \tStore *len* bytes from address *from* into the packet\n * \tassociated to *skb*, at *offset*. Only the flags, tag and TLVs\n * \tinside the outermost IPv6 Segment Routing Header can be\n * \tmodified through this helper.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_seg6_store_bytes)(struct __sk_buff *skb, __u32 offset, const void *from, __u32 len) = (void *) 74;\n\n/*\n * bpf_lwt_seg6_adjust_srh\n *\n * \tAdjust the size allocated to TLVs in the outermost IPv6\n * \tSegment Routing Header contained in the packet associated to\n * \t*skb*, at position *offset* by *delta* bytes. Only offsets\n * \tafter the segments are accepted. *delta* can be as well\n * \tpositive (growing) as negative (shrinking).\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_seg6_adjust_srh)(struct __sk_buff *skb, __u32 offset, __s32 delta) = (void *) 75;\n\n/*\n * bpf_lwt_seg6_action\n *\n * \tApply an IPv6 Segment Routing action of type *action* to the\n * \tpacket associated to *skb*. Each action takes a parameter\n * \tcontained at address *param*, and of length *param_len* bytes.\n * \t*action* can be one of:\n *\n * \t**SEG6_LOCAL_ACTION_END_X**\n * \t\tEnd.X action: Endpoint with Layer-3 cross-connect.\n * \t\tType of *param*: **struct in6_addr**.\n * \t**SEG6_LOCAL_ACTION_END_T**\n * \t\tEnd.T action: Endpoint with specific IPv6 table lookup.\n * \t\tType of *param*: **int**.\n * \t**SEG6_LOCAL_ACTION_END_B6**\n * \t\tEnd.B6 action: Endpoint bound to an SRv6 policy.\n * \t\tType of *param*: **struct ipv6_sr_hdr**.\n * \t**SEG6_LOCAL_ACTION_END_B6_ENCAP**\n * \t\tEnd.B6.Encap action: Endpoint bound to an SRv6\n * \t\tencapsulation policy.\n * \t\tType of *param*: **struct ipv6_sr_hdr**.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_seg6_action)(struct __sk_buff *skb, __u32 action, void *param, __u32 param_len) = (void *) 76;\n\n/*\n * bpf_rc_repeat\n *\n * \tThis helper is used in programs implementing IR decoding, to\n * \treport a successfully decoded repeat key message. This delays\n * \tthe generation of a key up event for previously generated\n * \tkey down event.\n *\n * \tSome IR protocols like NEC have a special IR message for\n * \trepeating last button, for when a button is held down.\n *\n * \tThe *ctx* should point to the lirc sample as passed into\n * \tthe program.\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_BPF_LIRC_MODE2** configuration option set to\n * \t\"**y**\".\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_rc_repeat)(void *ctx) = (void *) 77;\n\n/*\n * bpf_rc_keydown\n *\n * \tThis helper is used in programs implementing IR decoding, to\n * \treport a successfully decoded key press with *scancode*,\n * \t*toggle* value in the given *protocol*. The scancode will be\n * \ttranslated to a keycode using the rc keymap, and reported as\n * \tan input key down event. After a period a key up event is\n * \tgenerated. This period can be extended by calling either\n * \t**bpf_rc_keydown**\\ () again with the same values, or calling\n * \t**bpf_rc_repeat**\\ ().\n *\n * \tSome protocols include a toggle bit, in case the button was\n * \treleased and pressed again between consecutive scancodes.\n *\n * \tThe *ctx* should point to the lirc sample as passed into\n * \tthe program.\n *\n * \tThe *protocol* is the decoded protocol number (see\n * \t**enum rc_proto** for some predefined values).\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_BPF_LIRC_MODE2** configuration option set to\n * \t\"**y**\".\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_rc_keydown)(void *ctx, __u32 protocol, __u64 scancode, __u32 toggle) = (void *) 78;\n\n/*\n * bpf_skb_cgroup_id\n *\n * \tReturn the cgroup v2 id of the socket associated with the *skb*.\n * \tThis is roughly similar to the **bpf_get_cgroup_classid**\\ ()\n * \thelper for cgroup v1 by providing a tag resp. identifier that\n * \tcan be matched on or used for map lookups e.g. to implement\n * \tpolicy. The cgroup v2 id of a given path in the hierarchy is\n * \texposed in user space through the f_handle API in order to get\n * \tto the same 64-bit id.\n *\n * \tThis helper can be used on TC egress path, but not on ingress,\n * \tand is available only if the kernel was compiled with the\n * \t**CONFIG_SOCK_CGROUP_DATA** configuration option.\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_skb_cgroup_id)(struct __sk_buff *skb) = (void *) 79;\n\n/*\n * bpf_get_current_cgroup_id\n *\n * \tGet the current cgroup id based on the cgroup within which\n * \tthe current task is running.\n *\n * Returns\n * \tA 64-bit integer containing the current cgroup id based\n * \ton the cgroup within which the current task is running.\n */\nstatic __u64 (*bpf_get_current_cgroup_id)(void) = (void *) 80;\n\n/*\n * bpf_get_local_storage\n *\n * \tGet the pointer to the local storage area.\n * \tThe type and the size of the local storage is defined\n * \tby the *map* argument.\n * \tThe *flags* meaning is specific for each map type,\n * \tand has to be 0 for cgroup local storage.\n *\n * \tDepending on the BPF program type, a local storage area\n * \tcan be shared between multiple instances of the BPF program,\n * \trunning simultaneously.\n *\n * \tA user should care about the synchronization by himself.\n * \tFor example, by using the **BPF_ATOMIC** instructions to alter\n * \tthe shared data.\n *\n * Returns\n * \tA pointer to the local storage area.\n */\nstatic void *(*bpf_get_local_storage)(void *map, __u64 flags) = (void *) 81;\n\n/*\n * bpf_sk_select_reuseport\n *\n * \tSelect a **SO_REUSEPORT** socket from a\n * \t**BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*.\n * \tIt checks the selected socket is matching the incoming\n * \trequest in the socket buffer.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sk_select_reuseport)(struct sk_reuseport_md *reuse, void *map, void *key, __u64 flags) = (void *) 82;\n\n/*\n * bpf_skb_ancestor_cgroup_id\n *\n * \tReturn id of cgroup v2 that is ancestor of cgroup associated\n * \twith the *skb* at the *ancestor_level*.  The root cgroup is at\n * \t*ancestor_level* zero and each step down the hierarchy\n * \tincrements the level. If *ancestor_level* == level of cgroup\n * \tassociated with *skb*, then return value will be same as that\n * \tof **bpf_skb_cgroup_id**\\ ().\n *\n * \tThe helper is useful to implement policies based on cgroups\n * \tthat are upper in hierarchy than immediate cgroup associated\n * \twith *skb*.\n *\n * \tThe format of returned id and helper limitations are same as in\n * \t**bpf_skb_cgroup_id**\\ ().\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_skb_ancestor_cgroup_id)(struct __sk_buff *skb, int ancestor_level) = (void *) 83;\n\n/*\n * bpf_sk_lookup_tcp\n *\n * \tLook for TCP socket matching *tuple*, optionally in a child\n * \tnetwork namespace *netns*. The return value must be checked,\n * \tand if non-**NULL**, released via **bpf_sk_release**\\ ().\n *\n * \tThe *ctx* should point to the context of the program, such as\n * \tthe skb or socket (depending on the hook in use). This is used\n * \tto determine the base network namespace for the lookup.\n *\n * \t*tuple_size* must be one of:\n *\n * \t**sizeof**\\ (*tuple*\\ **->ipv4**)\n * \t\tLook for an IPv4 socket.\n * \t**sizeof**\\ (*tuple*\\ **->ipv6**)\n * \t\tLook for an IPv6 socket.\n *\n * \tIf the *netns* is a negative signed 32-bit integer, then the\n * \tsocket lookup table in the netns associated with the *ctx*\n * \twill be used. For the TC hooks, this is the netns of the device\n * \tin the skb. For socket hooks, this is the netns of the socket.\n * \tIf *netns* is any other signed 32-bit value greater than or\n * \tequal to zero then it specifies the ID of the netns relative to\n * \tthe netns associated with the *ctx*. *netns* values beyond the\n * \trange of 32-bit integers are reserved for future use.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_NET** configuration option.\n *\n * Returns\n * \tPointer to **struct bpf_sock**, or **NULL** in case of failure.\n * \tFor sockets with reuseport option, the **struct bpf_sock**\n * \tresult is from *reuse*\\ **->socks**\\ [] using the hash of the\n * \ttuple.\n */\nstatic struct bpf_sock *(*bpf_sk_lookup_tcp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 84;\n\n/*\n * bpf_sk_lookup_udp\n *\n * \tLook for UDP socket matching *tuple*, optionally in a child\n * \tnetwork namespace *netns*. The return value must be checked,\n * \tand if non-**NULL**, released via **bpf_sk_release**\\ ().\n *\n * \tThe *ctx* should point to the context of the program, such as\n * \tthe skb or socket (depending on the hook in use). This is used\n * \tto determine the base network namespace for the lookup.\n *\n * \t*tuple_size* must be one of:\n *\n * \t**sizeof**\\ (*tuple*\\ **->ipv4**)\n * \t\tLook for an IPv4 socket.\n * \t**sizeof**\\ (*tuple*\\ **->ipv6**)\n * \t\tLook for an IPv6 socket.\n *\n * \tIf the *netns* is a negative signed 32-bit integer, then the\n * \tsocket lookup table in the netns associated with the *ctx*\n * \twill be used. For the TC hooks, this is the netns of the device\n * \tin the skb. For socket hooks, this is the netns of the socket.\n * \tIf *netns* is any other signed 32-bit value greater than or\n * \tequal to zero then it specifies the ID of the netns relative to\n * \tthe netns associated with the *ctx*. *netns* values beyond the\n * \trange of 32-bit integers are reserved for future use.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_NET** configuration option.\n *\n * Returns\n * \tPointer to **struct bpf_sock**, or **NULL** in case of failure.\n * \tFor sockets with reuseport option, the **struct bpf_sock**\n * \tresult is from *reuse*\\ **->socks**\\ [] using the hash of the\n * \ttuple.\n */\nstatic struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 85;\n\n/*\n * bpf_sk_release\n *\n * \tRelease the reference held by *sock*. *sock* must be a\n * \tnon-**NULL** pointer that was returned from\n * \t**bpf_sk_lookup_xxx**\\ ().\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sk_release)(void *sock) = (void *) 86;\n\n/*\n * bpf_map_push_elem\n *\n * \tPush an element *value* in *map*. *flags* is one of:\n *\n * \t**BPF_EXIST**\n * \t\tIf the queue/stack is full, the oldest element is\n * \t\tremoved to make room for this.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_push_elem)(void *map, const void *value, __u64 flags) = (void *) 87;\n\n/*\n * bpf_map_pop_elem\n *\n * \tPop an element from *map*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_pop_elem)(void *map, void *value) = (void *) 88;\n\n/*\n * bpf_map_peek_elem\n *\n * \tGet an element from *map* without removing it.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_peek_elem)(void *map, void *value) = (void *) 89;\n\n/*\n * bpf_msg_push_data\n *\n * \tFor socket policies, insert *len* bytes into *msg* at offset\n * \t*start*.\n *\n * \tIf a program of type **BPF_PROG_TYPE_SK_MSG** is run on a\n * \t*msg* it may want to insert metadata or options into the *msg*.\n * \tThis can later be read and used by any of the lower layer BPF\n * \thooks.\n *\n * \tThis helper may fail if under memory pressure (a malloc\n * \tfails) in these cases BPF programs will get an appropriate\n * \terror and BPF programs will need to handle them.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_msg_push_data)(struct sk_msg_md *msg, __u32 start, __u32 len, __u64 flags) = (void *) 90;\n\n/*\n * bpf_msg_pop_data\n *\n * \tWill remove *len* bytes from a *msg* starting at byte *start*.\n * \tThis may result in **ENOMEM** errors under certain situations if\n * \tan allocation and copy are required due to a full ring buffer.\n * \tHowever, the helper will try to avoid doing the allocation\n * \tif possible. Other errors can occur if input parameters are\n * \tinvalid either due to *start* byte not being valid part of *msg*\n * \tpayload and/or *pop* value being to large.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_msg_pop_data)(struct sk_msg_md *msg, __u32 start, __u32 len, __u64 flags) = (void *) 91;\n\n/*\n * bpf_rc_pointer_rel\n *\n * \tThis helper is used in programs implementing IR decoding, to\n * \treport a successfully decoded pointer movement.\n *\n * \tThe *ctx* should point to the lirc sample as passed into\n * \tthe program.\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_BPF_LIRC_MODE2** configuration option set to\n * \t\"**y**\".\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_rc_pointer_rel)(void *ctx, __s32 rel_x, __s32 rel_y) = (void *) 92;\n\n/*\n * bpf_spin_lock\n *\n * \tAcquire a spinlock represented by the pointer *lock*, which is\n * \tstored as part of a value of a map. Taking the lock allows to\n * \tsafely update the rest of the fields in that value. The\n * \tspinlock can (and must) later be released with a call to\n * \t**bpf_spin_unlock**\\ (\\ *lock*\\ ).\n *\n * \tSpinlocks in BPF programs come with a number of restrictions\n * \tand constraints:\n *\n * \t* **bpf_spin_lock** objects are only allowed inside maps of\n * \t  types **BPF_MAP_TYPE_HASH** and **BPF_MAP_TYPE_ARRAY** (this\n * \t  list could be extended in the future).\n * \t* BTF description of the map is mandatory.\n * \t* The BPF program can take ONE lock at a time, since taking two\n * \t  or more could cause dead locks.\n * \t* Only one **struct bpf_spin_lock** is allowed per map element.\n * \t* When the lock is taken, calls (either BPF to BPF or helpers)\n * \t  are not allowed.\n * \t* The **BPF_LD_ABS** and **BPF_LD_IND** instructions are not\n * \t  allowed inside a spinlock-ed region.\n * \t* The BPF program MUST call **bpf_spin_unlock**\\ () to release\n * \t  the lock, on all execution paths, before it returns.\n * \t* The BPF program can access **struct bpf_spin_lock** only via\n * \t  the **bpf_spin_lock**\\ () and **bpf_spin_unlock**\\ ()\n * \t  helpers. Loading or storing data into the **struct\n * \t  bpf_spin_lock** *lock*\\ **;** field of a map is not allowed.\n * \t* To use the **bpf_spin_lock**\\ () helper, the BTF description\n * \t  of the map value must be a struct and have **struct\n * \t  bpf_spin_lock** *anyname*\\ **;** field at the top level.\n * \t  Nested lock inside another struct is not allowed.\n * \t* The **struct bpf_spin_lock** *lock* field in a map value must\n * \t  be aligned on a multiple of 4 bytes in that value.\n * \t* Syscall with command **BPF_MAP_LOOKUP_ELEM** does not copy\n * \t  the **bpf_spin_lock** field to user space.\n * \t* Syscall with command **BPF_MAP_UPDATE_ELEM**, or update from\n * \t  a BPF program, do not update the **bpf_spin_lock** field.\n * \t* **bpf_spin_lock** cannot be on the stack or inside a\n * \t  networking packet (it can only be inside of a map values).\n * \t* **bpf_spin_lock** is available to root only.\n * \t* Tracing programs and socket filter programs cannot use\n * \t  **bpf_spin_lock**\\ () due to insufficient preemption checks\n * \t  (but this may change in the future).\n * \t* **bpf_spin_lock** is not allowed in inner maps of map-in-map.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_spin_lock)(struct bpf_spin_lock *lock) = (void *) 93;\n\n/*\n * bpf_spin_unlock\n *\n * \tRelease the *lock* previously locked by a call to\n * \t**bpf_spin_lock**\\ (\\ *lock*\\ ).\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_spin_unlock)(struct bpf_spin_lock *lock) = (void *) 94;\n\n/*\n * bpf_sk_fullsock\n *\n * \tThis helper gets a **struct bpf_sock** pointer such\n * \tthat all the fields in this **bpf_sock** can be accessed.\n *\n * Returns\n * \tA **struct bpf_sock** pointer on success, or **NULL** in\n * \tcase of failure.\n */\nstatic struct bpf_sock *(*bpf_sk_fullsock)(struct bpf_sock *sk) = (void *) 95;\n\n/*\n * bpf_tcp_sock\n *\n * \tThis helper gets a **struct bpf_tcp_sock** pointer from a\n * \t**struct bpf_sock** pointer.\n *\n * Returns\n * \tA **struct bpf_tcp_sock** pointer on success, or **NULL** in\n * \tcase of failure.\n */\nstatic struct bpf_tcp_sock *(*bpf_tcp_sock)(struct bpf_sock *sk) = (void *) 96;\n\n/*\n * bpf_skb_ecn_set_ce\n *\n * \tSet ECN (Explicit Congestion Notification) field of IP header\n * \tto **CE** (Congestion Encountered) if current value is **ECT**\n * \t(ECN Capable Transport). Otherwise, do nothing. Works with IPv6\n * \tand IPv4.\n *\n * Returns\n * \t1 if the **CE** flag is set (either by the current helper call\n * \tor because it was already present), 0 if it is not set.\n */\nstatic long (*bpf_skb_ecn_set_ce)(struct __sk_buff *skb) = (void *) 97;\n\n/*\n * bpf_get_listener_sock\n *\n * \tReturn a **struct bpf_sock** pointer in **TCP_LISTEN** state.\n * \t**bpf_sk_release**\\ () is unnecessary and not allowed.\n *\n * Returns\n * \tA **struct bpf_sock** pointer on success, or **NULL** in\n * \tcase of failure.\n */\nstatic struct bpf_sock *(*bpf_get_listener_sock)(struct bpf_sock *sk) = (void *) 98;\n\n/*\n * bpf_skc_lookup_tcp\n *\n * \tLook for TCP socket matching *tuple*, optionally in a child\n * \tnetwork namespace *netns*. The return value must be checked,\n * \tand if non-**NULL**, released via **bpf_sk_release**\\ ().\n *\n * \tThis function is identical to **bpf_sk_lookup_tcp**\\ (), except\n * \tthat it also returns timewait or request sockets. Use\n * \t**bpf_sk_fullsock**\\ () or **bpf_tcp_sock**\\ () to access the\n * \tfull structure.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_NET** configuration option.\n *\n * Returns\n * \tPointer to **struct bpf_sock**, or **NULL** in case of failure.\n * \tFor sockets with reuseport option, the **struct bpf_sock**\n * \tresult is from *reuse*\\ **->socks**\\ [] using the hash of the\n * \ttuple.\n */\nstatic struct bpf_sock *(*bpf_skc_lookup_tcp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 99;\n\n/*\n * bpf_tcp_check_syncookie\n *\n * \tCheck whether *iph* and *th* contain a valid SYN cookie ACK for\n * \tthe listening socket in *sk*.\n *\n * \t*iph* points to the start of the IPv4 or IPv6 header, while\n * \t*iph_len* contains **sizeof**\\ (**struct iphdr**) or\n * \t**sizeof**\\ (**struct ipv6hdr**).\n *\n * \t*th* points to the start of the TCP header, while *th_len*\n * \tcontains the length of the TCP header (at least\n * \t**sizeof**\\ (**struct tcphdr**)).\n *\n * Returns\n * \t0 if *iph* and *th* are a valid SYN cookie ACK, or a negative\n * \terror otherwise.\n */\nstatic long (*bpf_tcp_check_syncookie)(void *sk, void *iph, __u32 iph_len, struct tcphdr *th, __u32 th_len) = (void *) 100;\n\n/*\n * bpf_sysctl_get_name\n *\n * \tGet name of sysctl in /proc/sys/ and copy it into provided by\n * \tprogram buffer *buf* of size *buf_len*.\n *\n * \tThe buffer is always NUL terminated, unless it's zero-sized.\n *\n * \tIf *flags* is zero, full name (e.g. \"net/ipv4/tcp_mem\") is\n * \tcopied. Use **BPF_F_SYSCTL_BASE_NAME** flag to copy base name\n * \tonly (e.g. \"tcp_mem\").\n *\n * Returns\n * \tNumber of character copied (not including the trailing NUL).\n *\n * \t**-E2BIG** if the buffer wasn't big enough (*buf* will contain\n * \ttruncated name in this case).\n */\nstatic long (*bpf_sysctl_get_name)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len, __u64 flags) = (void *) 101;\n\n/*\n * bpf_sysctl_get_current_value\n *\n * \tGet current value of sysctl as it is presented in /proc/sys\n * \t(incl. newline, etc), and copy it as a string into provided\n * \tby program buffer *buf* of size *buf_len*.\n *\n * \tThe whole value is copied, no matter what file position user\n * \tspace issued e.g. sys_read at.\n *\n * \tThe buffer is always NUL terminated, unless it's zero-sized.\n *\n * Returns\n * \tNumber of character copied (not including the trailing NUL).\n *\n * \t**-E2BIG** if the buffer wasn't big enough (*buf* will contain\n * \ttruncated name in this case).\n *\n * \t**-EINVAL** if current value was unavailable, e.g. because\n * \tsysctl is uninitialized and read returns -EIO for it.\n */\nstatic long (*bpf_sysctl_get_current_value)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len) = (void *) 102;\n\n/*\n * bpf_sysctl_get_new_value\n *\n * \tGet new value being written by user space to sysctl (before\n * \tthe actual write happens) and copy it as a string into\n * \tprovided by program buffer *buf* of size *buf_len*.\n *\n * \tUser space may write new value at file position > 0.\n *\n * \tThe buffer is always NUL terminated, unless it's zero-sized.\n *\n * Returns\n * \tNumber of character copied (not including the trailing NUL).\n *\n * \t**-E2BIG** if the buffer wasn't big enough (*buf* will contain\n * \ttruncated name in this case).\n *\n * \t**-EINVAL** if sysctl is being read.\n */\nstatic long (*bpf_sysctl_get_new_value)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len) = (void *) 103;\n\n/*\n * bpf_sysctl_set_new_value\n *\n * \tOverride new value being written by user space to sysctl with\n * \tvalue provided by program in buffer *buf* of size *buf_len*.\n *\n * \t*buf* should contain a string in same form as provided by user\n * \tspace on sysctl write.\n *\n * \tUser space may write new value at file position > 0. To override\n * \tthe whole sysctl value file position should be set to zero.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-E2BIG** if the *buf_len* is too big.\n *\n * \t**-EINVAL** if sysctl is being read.\n */\nstatic long (*bpf_sysctl_set_new_value)(struct bpf_sysctl *ctx, const char *buf, unsigned long buf_len) = (void *) 104;\n\n/*\n * bpf_strtol\n *\n * \tConvert the initial part of the string from buffer *buf* of\n * \tsize *buf_len* to a long integer according to the given base\n * \tand save the result in *res*.\n *\n * \tThe string may begin with an arbitrary amount of white space\n * \t(as determined by **isspace**\\ (3)) followed by a single\n * \toptional '**-**' sign.\n *\n * \tFive least significant bits of *flags* encode base, other bits\n * \tare currently unused.\n *\n * \tBase must be either 8, 10, 16 or 0 to detect it automatically\n * \tsimilar to user space **strtol**\\ (3).\n *\n * Returns\n * \tNumber of characters consumed on success. Must be positive but\n * \tno more than *buf_len*.\n *\n * \t**-EINVAL** if no valid digits were found or unsupported base\n * \twas provided.\n *\n * \t**-ERANGE** if resulting value was out of range.\n */\nstatic long (*bpf_strtol)(const char *buf, unsigned long buf_len, __u64 flags, long *res) = (void *) 105;\n\n/*\n * bpf_strtoul\n *\n * \tConvert the initial part of the string from buffer *buf* of\n * \tsize *buf_len* to an unsigned long integer according to the\n * \tgiven base and save the result in *res*.\n *\n * \tThe string may begin with an arbitrary amount of white space\n * \t(as determined by **isspace**\\ (3)).\n *\n * \tFive least significant bits of *flags* encode base, other bits\n * \tare currently unused.\n *\n * \tBase must be either 8, 10, 16 or 0 to detect it automatically\n * \tsimilar to user space **strtoul**\\ (3).\n *\n * Returns\n * \tNumber of characters consumed on success. Must be positive but\n * \tno more than *buf_len*.\n *\n * \t**-EINVAL** if no valid digits were found or unsupported base\n * \twas provided.\n *\n * \t**-ERANGE** if resulting value was out of range.\n */\nstatic long (*bpf_strtoul)(const char *buf, unsigned long buf_len, __u64 flags, unsigned long *res) = (void *) 106;\n\n/*\n * bpf_sk_storage_get\n *\n * \tGet a bpf-local-storage from a *sk*.\n *\n * \tLogically, it could be thought of getting the value from\n * \ta *map* with *sk* as the **key**.  From this\n * \tperspective,  the usage is not much different from\n * \t**bpf_map_lookup_elem**\\ (*map*, **&**\\ *sk*) except this\n * \thelper enforces the key must be a full socket and the map must\n * \tbe a **BPF_MAP_TYPE_SK_STORAGE** also.\n *\n * \tUnderneath, the value is stored locally at *sk* instead of\n * \tthe *map*.  The *map* is used as the bpf-local-storage\n * \t\"type\". The bpf-local-storage \"type\" (i.e. the *map*) is\n * \tsearched against all bpf-local-storages residing at *sk*.\n *\n * \t*sk* is a kernel **struct sock** pointer for LSM program.\n * \t*sk* is a **struct bpf_sock** pointer for other program types.\n *\n * \tAn optional *flags* (**BPF_SK_STORAGE_GET_F_CREATE**) can be\n * \tused such that a new bpf-local-storage will be\n * \tcreated if one does not exist.  *value* can be used\n * \ttogether with **BPF_SK_STORAGE_GET_F_CREATE** to specify\n * \tthe initial value of a bpf-local-storage.  If *value* is\n * \t**NULL**, the new bpf-local-storage will be zero initialized.\n *\n * Returns\n * \tA bpf-local-storage pointer is returned on success.\n *\n * \t**NULL** if not found or there was an error in adding\n * \ta new bpf-local-storage.\n */\nstatic void *(*bpf_sk_storage_get)(void *map, void *sk, void *value, __u64 flags) = (void *) 107;\n\n/*\n * bpf_sk_storage_delete\n *\n * \tDelete a bpf-local-storage from a *sk*.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-ENOENT** if the bpf-local-storage cannot be found.\n * \t**-EINVAL** if sk is not a fullsock (e.g. a request_sock).\n */\nstatic long (*bpf_sk_storage_delete)(void *map, void *sk) = (void *) 108;\n\n/*\n * bpf_send_signal\n *\n * \tSend signal *sig* to the process of the current task.\n * \tThe signal may be delivered to any of this process's threads.\n *\n * Returns\n * \t0 on success or successfully queued.\n *\n * \t**-EBUSY** if work queue under nmi is full.\n *\n * \t**-EINVAL** if *sig* is invalid.\n *\n * \t**-EPERM** if no permission to send the *sig*.\n *\n * \t**-EAGAIN** if bpf program can try again.\n */\nstatic long (*bpf_send_signal)(__u32 sig) = (void *) 109;\n\n/*\n * bpf_tcp_gen_syncookie\n *\n * \tTry to issue a SYN cookie for the packet with corresponding\n * \tIP/TCP headers, *iph* and *th*, on the listening socket in *sk*.\n *\n * \t*iph* points to the start of the IPv4 or IPv6 header, while\n * \t*iph_len* contains **sizeof**\\ (**struct iphdr**) or\n * \t**sizeof**\\ (**struct ipv6hdr**).\n *\n * \t*th* points to the start of the TCP header, while *th_len*\n * \tcontains the length of the TCP header with options (at least\n * \t**sizeof**\\ (**struct tcphdr**)).\n *\n * Returns\n * \tOn success, lower 32 bits hold the generated SYN cookie in\n * \tfollowed by 16 bits which hold the MSS value for that cookie,\n * \tand the top 16 bits are unused.\n *\n * \tOn failure, the returned value is one of the following:\n *\n * \t**-EINVAL** SYN cookie cannot be issued due to error\n *\n * \t**-ENOENT** SYN cookie should not be issued (no SYN flood)\n *\n * \t**-EOPNOTSUPP** kernel configuration does not enable SYN cookies\n *\n * \t**-EPROTONOSUPPORT** IP packet version is not 4 or 6\n */\nstatic __s64 (*bpf_tcp_gen_syncookie)(void *sk, void *iph, __u32 iph_len, struct tcphdr *th, __u32 th_len) = (void *) 110;\n\n/*\n * bpf_skb_output\n *\n * \tWrite raw *data* blob into a special BPF perf event held by\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf\n * \tevent must have the following attributes: **PERF_SAMPLE_RAW**\n * \tas **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and\n * \t**PERF_COUNT_SW_BPF_OUTPUT** as **config**.\n *\n * \tThe *flags* are used to indicate the index in *map* for which\n * \tthe value must be put, masked with **BPF_F_INDEX_MASK**.\n * \tAlternatively, *flags* can be set to **BPF_F_CURRENT_CPU**\n * \tto indicate that the index of the current CPU core should be\n * \tused.\n *\n * \tThe value to write, of *size*, is passed through eBPF stack and\n * \tpointed by *data*.\n *\n * \t*ctx* is a pointer to in-kernel struct sk_buff.\n *\n * \tThis helper is similar to **bpf_perf_event_output**\\ () but\n * \trestricted to raw_tracepoint bpf programs.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 111;\n\n/*\n * bpf_probe_read_user\n *\n * \tSafely attempt to read *size* bytes from user space address\n * \t*unsafe_ptr* and store the data in *dst*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_read_user)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 112;\n\n/*\n * bpf_probe_read_kernel\n *\n * \tSafely attempt to read *size* bytes from kernel space address\n * \t*unsafe_ptr* and store the data in *dst*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_read_kernel)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 113;\n\n/*\n * bpf_probe_read_user_str\n *\n * \tCopy a NUL terminated string from an unsafe user address\n * \t*unsafe_ptr* to *dst*. The *size* should include the\n * \tterminating NUL byte. In case the string length is smaller than\n * \t*size*, the target is not padded with further NUL bytes. If the\n * \tstring length is larger than *size*, just *size*-1 bytes are\n * \tcopied and the last byte is set to NUL.\n *\n * \tOn success, returns the number of bytes that were written,\n * \tincluding the terminal NUL. This makes this helper useful in\n * \ttracing programs for reading strings, and more importantly to\n * \tget its length at runtime. See the following snippet:\n *\n * \t::\n *\n * \t\tSEC(\"kprobe/sys_open\")\n * \t\tvoid bpf_sys_open(struct pt_regs *ctx)\n * \t\t{\n * \t\t        char buf[PATHLEN]; // PATHLEN is defined to 256\n * \t\t        int res = bpf_probe_read_user_str(buf, sizeof(buf),\n * \t\t\t                                  ctx->di);\n *\n * \t\t\t// Consume buf, for example push it to\n * \t\t\t// userspace via bpf_perf_event_output(); we\n * \t\t\t// can use res (the string length) as event\n * \t\t\t// size, after checking its boundaries.\n * \t\t}\n *\n * \tIn comparison, using **bpf_probe_read_user**\\ () helper here\n * \tinstead to read the string would require to estimate the length\n * \tat compile time, and would often result in copying more memory\n * \tthan necessary.\n *\n * \tAnother useful use case is when parsing individual process\n * \targuments or individual environment variables navigating\n * \t*current*\\ **->mm->arg_start** and *current*\\\n * \t**->mm->env_start**: using this helper and the return value,\n * \tone can quickly iterate at the right offset of the memory area.\n *\n * Returns\n * \tOn success, the strictly positive length of the output string,\n * \tincluding the trailing NUL character. On error, a negative\n * \tvalue.\n */\nstatic long (*bpf_probe_read_user_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 114;\n\n/*\n * bpf_probe_read_kernel_str\n *\n * \tCopy a NUL terminated string from an unsafe kernel address *unsafe_ptr*\n * \tto *dst*. Same semantics as with **bpf_probe_read_user_str**\\ () apply.\n *\n * Returns\n * \tOn success, the strictly positive length of the string, including\n * \tthe trailing NUL character. On error, a negative value.\n */\nstatic long (*bpf_probe_read_kernel_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 115;\n\n/*\n * bpf_tcp_send_ack\n *\n * \tSend out a tcp-ack. *tp* is the in-kernel struct **tcp_sock**.\n * \t*rcv_nxt* is the ack_seq to be sent out.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_tcp_send_ack)(void *tp, __u32 rcv_nxt) = (void *) 116;\n\n/*\n * bpf_send_signal_thread\n *\n * \tSend signal *sig* to the thread corresponding to the current task.\n *\n * Returns\n * \t0 on success or successfully queued.\n *\n * \t**-EBUSY** if work queue under nmi is full.\n *\n * \t**-EINVAL** if *sig* is invalid.\n *\n * \t**-EPERM** if no permission to send the *sig*.\n *\n * \t**-EAGAIN** if bpf program can try again.\n */\nstatic long (*bpf_send_signal_thread)(__u32 sig) = (void *) 117;\n\n/*\n * bpf_jiffies64\n *\n * \tObtain the 64bit jiffies\n *\n * Returns\n * \tThe 64 bit jiffies\n */\nstatic __u64 (*bpf_jiffies64)(void) = (void *) 118;\n\n/*\n * bpf_read_branch_records\n *\n * \tFor an eBPF program attached to a perf event, retrieve the\n * \tbranch records (**struct perf_branch_entry**) associated to *ctx*\n * \tand store it in the buffer pointed by *buf* up to size\n * \t*size* bytes.\n *\n * Returns\n * \tOn success, number of bytes written to *buf*. On error, a\n * \tnegative value.\n *\n * \tThe *flags* can be set to **BPF_F_GET_BRANCH_RECORDS_SIZE** to\n * \tinstead return the number of bytes required to store all the\n * \tbranch entries. If this flag is set, *buf* may be NULL.\n *\n * \t**-EINVAL** if arguments invalid or **size** not a multiple\n * \tof **sizeof**\\ (**struct perf_branch_entry**\\ ).\n *\n * \t**-ENOENT** if architecture does not support branch records.\n */\nstatic long (*bpf_read_branch_records)(struct bpf_perf_event_data *ctx, void *buf, __u32 size, __u64 flags) = (void *) 119;\n\n/*\n * bpf_get_ns_current_pid_tgid\n *\n * \tReturns 0 on success, values for *pid* and *tgid* as seen from the current\n * \t*namespace* will be returned in *nsdata*.\n *\n * Returns\n * \t0 on success, or one of the following in case of failure:\n *\n * \t**-EINVAL** if dev and inum supplied don't match dev_t and inode number\n * \twith nsfs of current task, or if dev conversion to dev_t lost high bits.\n *\n * \t**-ENOENT** if pidns does not exists for the current task.\n */\nstatic long (*bpf_get_ns_current_pid_tgid)(__u64 dev, __u64 ino, struct bpf_pidns_info *nsdata, __u32 size) = (void *) 120;\n\n/*\n * bpf_xdp_output\n *\n * \tWrite raw *data* blob into a special BPF perf event held by\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf\n * \tevent must have the following attributes: **PERF_SAMPLE_RAW**\n * \tas **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and\n * \t**PERF_COUNT_SW_BPF_OUTPUT** as **config**.\n *\n * \tThe *flags* are used to indicate the index in *map* for which\n * \tthe value must be put, masked with **BPF_F_INDEX_MASK**.\n * \tAlternatively, *flags* can be set to **BPF_F_CURRENT_CPU**\n * \tto indicate that the index of the current CPU core should be\n * \tused.\n *\n * \tThe value to write, of *size*, is passed through eBPF stack and\n * \tpointed by *data*.\n *\n * \t*ctx* is a pointer to in-kernel struct xdp_buff.\n *\n * \tThis helper is similar to **bpf_perf_eventoutput**\\ () but\n * \trestricted to raw_tracepoint bpf programs.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 121;\n\n/*\n * bpf_get_netns_cookie\n *\n * \tRetrieve the cookie (generated by the kernel) of the network\n * \tnamespace the input *ctx* is associated with. The network\n * \tnamespace cookie remains stable for its lifetime and provides\n * \ta global identifier that can be assumed unique. If *ctx* is\n * \tNULL, then the helper returns the cookie for the initial\n * \tnetwork namespace. The cookie itself is very similar to that\n * \tof **bpf_get_socket_cookie**\\ () helper, but for network\n * \tnamespaces instead of sockets.\n *\n * Returns\n * \tA 8-byte long opaque number.\n */\nstatic __u64 (*bpf_get_netns_cookie)(void *ctx) = (void *) 122;\n\n/*\n * bpf_get_current_ancestor_cgroup_id\n *\n * \tReturn id of cgroup v2 that is ancestor of the cgroup associated\n * \twith the current task at the *ancestor_level*. The root cgroup\n * \tis at *ancestor_level* zero and each step down the hierarchy\n * \tincrements the level. If *ancestor_level* == level of cgroup\n * \tassociated with the current task, then return value will be the\n * \tsame as that of **bpf_get_current_cgroup_id**\\ ().\n *\n * \tThe helper is useful to implement policies based on cgroups\n * \tthat are upper in hierarchy than immediate cgroup associated\n * \twith the current task.\n *\n * \tThe format of returned id and helper limitations are same as in\n * \t**bpf_get_current_cgroup_id**\\ ().\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_get_current_ancestor_cgroup_id)(int ancestor_level) = (void *) 123;\n\n/*\n * bpf_sk_assign\n *\n * \tHelper is overloaded depending on BPF program type. This\n * \tdescription applies to **BPF_PROG_TYPE_SCHED_CLS** and\n * \t**BPF_PROG_TYPE_SCHED_ACT** programs.\n *\n * \tAssign the *sk* to the *skb*. When combined with appropriate\n * \trouting configuration to receive the packet towards the socket,\n * \twill cause *skb* to be delivered to the specified socket.\n * \tSubsequent redirection of *skb* via  **bpf_redirect**\\ (),\n * \t**bpf_clone_redirect**\\ () or other methods outside of BPF may\n * \tinterfere with successful delivery to the socket.\n *\n * \tThis operation is only valid from TC ingress path.\n *\n * \tThe *flags* argument must be zero.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure:\n *\n * \t**-EINVAL** if specified *flags* are not supported.\n *\n * \t**-ENOENT** if the socket is unavailable for assignment.\n *\n * \t**-ENETUNREACH** if the socket is unreachable (wrong netns).\n *\n * \t**-EOPNOTSUPP** if the operation is not supported, for example\n * \ta call from outside of TC ingress.\n *\n * \t**-ESOCKTNOSUPPORT** if the socket type is not supported\n * \t(reuseport).\n */\nstatic long (*bpf_sk_assign)(void *ctx, void *sk, __u64 flags) = (void *) 124;\n\n/*\n * bpf_ktime_get_boot_ns\n *\n * \tReturn the time elapsed since system boot, in nanoseconds.\n * \tDoes include the time the system was suspended.\n * \tSee: **clock_gettime**\\ (**CLOCK_BOOTTIME**)\n *\n * Returns\n * \tCurrent *ktime*.\n */\nstatic __u64 (*bpf_ktime_get_boot_ns)(void) = (void *) 125;\n\n/*\n * bpf_seq_printf\n *\n * \t**bpf_seq_printf**\\ () uses seq_file **seq_printf**\\ () to print\n * \tout the format string.\n * \tThe *m* represents the seq_file. The *fmt* and *fmt_size* are for\n * \tthe format string itself. The *data* and *data_len* are format string\n * \targuments. The *data* are a **u64** array and corresponding format string\n * \tvalues are stored in the array. For strings and pointers where pointees\n * \tare accessed, only the pointer values are stored in the *data* array.\n * \tThe *data_len* is the size of *data* in bytes - must be a multiple of 8.\n *\n * \tFormats **%s**, **%p{i,I}{4,6}** requires to read kernel memory.\n * \tReading kernel memory may fail due to either invalid address or\n * \tvalid address but requiring a major memory fault. If reading kernel memory\n * \tfails, the string for **%s** will be an empty string, and the ip\n * \taddress for **%p{i,I}{4,6}** will be 0. Not returning error to\n * \tbpf program is consistent with what **bpf_trace_printk**\\ () does for now.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure:\n *\n * \t**-EBUSY** if per-CPU memory copy buffer is busy, can try again\n * \tby returning 1 from bpf program.\n *\n * \t**-EINVAL** if arguments are invalid, or if *fmt* is invalid/unsupported.\n *\n * \t**-E2BIG** if *fmt* contains too many format specifiers.\n *\n * \t**-EOVERFLOW** if an overflow happened: The same object will be tried again.\n */\nstatic long (*bpf_seq_printf)(struct seq_file *m, const char *fmt, __u32 fmt_size, const void *data, __u32 data_len) = (void *) 126;\n\n/*\n * bpf_seq_write\n *\n * \t**bpf_seq_write**\\ () uses seq_file **seq_write**\\ () to write the data.\n * \tThe *m* represents the seq_file. The *data* and *len* represent the\n * \tdata to write in bytes.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure:\n *\n * \t**-EOVERFLOW** if an overflow happened: The same object will be tried again.\n */\nstatic long (*bpf_seq_write)(struct seq_file *m, const void *data, __u32 len) = (void *) 127;\n\n/*\n * bpf_sk_cgroup_id\n *\n * \tReturn the cgroup v2 id of the socket *sk*.\n *\n * \t*sk* must be a non-**NULL** pointer to a socket, e.g. one\n * \treturned from **bpf_sk_lookup_xxx**\\ (),\n * \t**bpf_sk_fullsock**\\ (), etc. The format of returned id is\n * \tsame as in **bpf_skb_cgroup_id**\\ ().\n *\n * \tThis helper is available only if the kernel was compiled with\n * \tthe **CONFIG_SOCK_CGROUP_DATA** configuration option.\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_sk_cgroup_id)(void *sk) = (void *) 128;\n\n/*\n * bpf_sk_ancestor_cgroup_id\n *\n * \tReturn id of cgroup v2 that is ancestor of cgroup associated\n * \twith the *sk* at the *ancestor_level*.  The root cgroup is at\n * \t*ancestor_level* zero and each step down the hierarchy\n * \tincrements the level. If *ancestor_level* == level of cgroup\n * \tassociated with *sk*, then return value will be same as that\n * \tof **bpf_sk_cgroup_id**\\ ().\n *\n * \tThe helper is useful to implement policies based on cgroups\n * \tthat are upper in hierarchy than immediate cgroup associated\n * \twith *sk*.\n *\n * \tThe format of returned id and helper limitations are same as in\n * \t**bpf_sk_cgroup_id**\\ ().\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_sk_ancestor_cgroup_id)(void *sk, int ancestor_level) = (void *) 129;\n\n/*\n * bpf_ringbuf_output\n *\n * \tCopy *size* bytes from *data* into a ring buffer *ringbuf*.\n * \tIf **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification\n * \tof new data availability is sent.\n * \tIf **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification\n * \tof new data availability is sent unconditionally.\n * \tIf **0** is specified in *flags*, an adaptive notification\n * \tof new data availability is sent.\n *\n * \tAn adaptive notification is a notification sent whenever the user-space\n * \tprocess has caught up and consumed all available payloads. In case the user-space\n * \tprocess is still processing a previous payload, then no notification is needed\n * \tas it will process the newly added payload automatically.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_ringbuf_output)(void *ringbuf, void *data, __u64 size, __u64 flags) = (void *) 130;\n\n/*\n * bpf_ringbuf_reserve\n *\n * \tReserve *size* bytes of payload in a ring buffer *ringbuf*.\n * \t*flags* must be 0.\n *\n * Returns\n * \tValid pointer with *size* bytes of memory available; NULL,\n * \totherwise.\n */\nstatic void *(*bpf_ringbuf_reserve)(void *ringbuf, __u64 size, __u64 flags) = (void *) 131;\n\n/*\n * bpf_ringbuf_submit\n *\n * \tSubmit reserved ring buffer sample, pointed to by *data*.\n * \tIf **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification\n * \tof new data availability is sent.\n * \tIf **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification\n * \tof new data availability is sent unconditionally.\n * \tIf **0** is specified in *flags*, an adaptive notification\n * \tof new data availability is sent.\n *\n * \tSee 'bpf_ringbuf_output()' for the definition of adaptive notification.\n *\n * Returns\n * \tNothing. Always succeeds.\n */\nstatic void (*bpf_ringbuf_submit)(void *data, __u64 flags) = (void *) 132;\n\n/*\n * bpf_ringbuf_discard\n *\n * \tDiscard reserved ring buffer sample, pointed to by *data*.\n * \tIf **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification\n * \tof new data availability is sent.\n * \tIf **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification\n * \tof new data availability is sent unconditionally.\n * \tIf **0** is specified in *flags*, an adaptive notification\n * \tof new data availability is sent.\n *\n * \tSee 'bpf_ringbuf_output()' for the definition of adaptive notification.\n *\n * Returns\n * \tNothing. Always succeeds.\n */\nstatic void (*bpf_ringbuf_discard)(void *data, __u64 flags) = (void *) 133;\n\n/*\n * bpf_ringbuf_query\n *\n * \tQuery various characteristics of provided ring buffer. What\n * \texactly is queries is determined by *flags*:\n *\n * \t* **BPF_RB_AVAIL_DATA**: Amount of data not yet consumed.\n * \t* **BPF_RB_RING_SIZE**: The size of ring buffer.\n * \t* **BPF_RB_CONS_POS**: Consumer position (can wrap around).\n * \t* **BPF_RB_PROD_POS**: Producer(s) position (can wrap around).\n *\n * \tData returned is just a momentary snapshot of actual values\n * \tand could be inaccurate, so this facility should be used to\n * \tpower heuristics and for reporting, not to make 100% correct\n * \tcalculation.\n *\n * Returns\n * \tRequested value, or 0, if *flags* are not recognized.\n */\nstatic __u64 (*bpf_ringbuf_query)(void *ringbuf, __u64 flags) = (void *) 134;\n\n/*\n * bpf_csum_level\n *\n * \tChange the skbs checksum level by one layer up or down, or\n * \treset it entirely to none in order to have the stack perform\n * \tchecksum validation. The level is applicable to the following\n * \tprotocols: TCP, UDP, GRE, SCTP, FCOE. For example, a decap of\n * \t| ETH | IP | UDP | GUE | IP | TCP | into | ETH | IP | TCP |\n * \tthrough **bpf_skb_adjust_room**\\ () helper with passing in\n * \t**BPF_F_ADJ_ROOM_NO_CSUM_RESET** flag would require one\tcall\n * \tto **bpf_csum_level**\\ () with **BPF_CSUM_LEVEL_DEC** since\n * \tthe UDP header is removed. Similarly, an encap of the latter\n * \tinto the former could be accompanied by a helper call to\n * \t**bpf_csum_level**\\ () with **BPF_CSUM_LEVEL_INC** if the\n * \tskb is still intended to be processed in higher layers of the\n * \tstack instead of just egressing at tc.\n *\n * \tThere are three supported level settings at this time:\n *\n * \t* **BPF_CSUM_LEVEL_INC**: Increases skb->csum_level for skbs\n * \t  with CHECKSUM_UNNECESSARY.\n * \t* **BPF_CSUM_LEVEL_DEC**: Decreases skb->csum_level for skbs\n * \t  with CHECKSUM_UNNECESSARY.\n * \t* **BPF_CSUM_LEVEL_RESET**: Resets skb->csum_level to 0 and\n * \t  sets CHECKSUM_NONE to force checksum validation by the stack.\n * \t* **BPF_CSUM_LEVEL_QUERY**: No-op, returns the current\n * \t  skb->csum_level.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure. In the\n * \tcase of **BPF_CSUM_LEVEL_QUERY**, the current skb->csum_level\n * \tis returned or the error code -EACCES in case the skb is not\n * \tsubject to CHECKSUM_UNNECESSARY.\n */\nstatic long (*bpf_csum_level)(struct __sk_buff *skb, __u64 level) = (void *) 135;\n\n/*\n * bpf_skc_to_tcp6_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp6_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp6_sock *(*bpf_skc_to_tcp6_sock)(void *sk) = (void *) 136;\n\n/*\n * bpf_skc_to_tcp_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp_sock *(*bpf_skc_to_tcp_sock)(void *sk) = (void *) 137;\n\n/*\n * bpf_skc_to_tcp_timewait_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp_timewait_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp_timewait_sock *(*bpf_skc_to_tcp_timewait_sock)(void *sk) = (void *) 138;\n\n/*\n * bpf_skc_to_tcp_request_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp_request_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp_request_sock *(*bpf_skc_to_tcp_request_sock)(void *sk) = (void *) 139;\n\n/*\n * bpf_skc_to_udp6_sock\n *\n * \tDynamically cast a *sk* pointer to a *udp6_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct udp6_sock *(*bpf_skc_to_udp6_sock)(void *sk) = (void *) 140;\n\n/*\n * bpf_get_task_stack\n *\n * \tReturn a user or a kernel stack in bpf program provided buffer.\n * \tTo achieve this, the helper needs *task*, which is a valid\n * \tpointer to **struct task_struct**. To store the stacktrace, the\n * \tbpf program provides *buf* with a nonnegative *size*.\n *\n * \tThe last argument, *flags*, holds the number of stack frames to\n * \tskip (from 0 to 255), masked with\n * \t**BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set\n * \tthe following flags:\n *\n * \t**BPF_F_USER_STACK**\n * \t\tCollect a user space stack instead of a kernel stack.\n * \t**BPF_F_USER_BUILD_ID**\n * \t\tCollect buildid+offset instead of ips for user stack,\n * \t\tonly valid if **BPF_F_USER_STACK** is also specified.\n *\n * \t**bpf_get_task_stack**\\ () can collect up to\n * \t**PERF_MAX_STACK_DEPTH** both kernel and user frames, subject\n * \tto sufficient large buffer size. Note that\n * \tthis limit can be controlled with the **sysctl** program, and\n * \tthat it should be manually increased in order to profile long\n * \tuser stacks (such as stacks for Java programs). To do so, use:\n *\n * \t::\n *\n * \t\t# sysctl kernel.perf_event_max_stack=<new value>\n *\n * Returns\n * \tThe non-negative copied *buf* length equal to or less than\n * \t*size* on success, or a negative error in case of failure.\n */\nstatic long (*bpf_get_task_stack)(struct task_struct *task, void *buf, __u32 size, __u64 flags) = (void *) 141;\n\n/*\n * bpf_load_hdr_opt\n *\n * \tLoad header option.  Support reading a particular TCP header\n * \toption for bpf program (**BPF_PROG_TYPE_SOCK_OPS**).\n *\n * \tIf *flags* is 0, it will search the option from the\n * \t*skops*\\ **->skb_data**.  The comment in **struct bpf_sock_ops**\n * \thas details on what skb_data contains under different\n * \t*skops*\\ **->op**.\n *\n * \tThe first byte of the *searchby_res* specifies the\n * \tkind that it wants to search.\n *\n * \tIf the searching kind is an experimental kind\n * \t(i.e. 253 or 254 according to RFC6994).  It also\n * \tneeds to specify the \"magic\" which is either\n * \t2 bytes or 4 bytes.  It then also needs to\n * \tspecify the size of the magic by using\n * \tthe 2nd byte which is \"kind-length\" of a TCP\n * \theader option and the \"kind-length\" also\n * \tincludes the first 2 bytes \"kind\" and \"kind-length\"\n * \titself as a normal TCP header option also does.\n *\n * \tFor example, to search experimental kind 254 with\n * \t2 byte magic 0xeB9F, the searchby_res should be\n * \t[ 254, 4, 0xeB, 0x9F, 0, 0, .... 0 ].\n *\n * \tTo search for the standard window scale option (3),\n * \tthe *searchby_res* should be [ 3, 0, 0, .... 0 ].\n * \tNote, kind-length must be 0 for regular option.\n *\n * \tSearching for No-Op (0) and End-of-Option-List (1) are\n * \tnot supported.\n *\n * \t*len* must be at least 2 bytes which is the minimal size\n * \tof a header option.\n *\n * \tSupported flags:\n *\n * \t* **BPF_LOAD_HDR_OPT_TCP_SYN** to search from the\n * \t  saved_syn packet or the just-received syn packet.\n *\n *\n * Returns\n * \t> 0 when found, the header option is copied to *searchby_res*.\n * \tThe return value is the total length copied. On failure, a\n * \tnegative error code is returned:\n *\n * \t**-EINVAL** if a parameter is invalid.\n *\n * \t**-ENOMSG** if the option is not found.\n *\n * \t**-ENOENT** if no syn packet is available when\n * \t**BPF_LOAD_HDR_OPT_TCP_SYN** is used.\n *\n * \t**-ENOSPC** if there is not enough space.  Only *len* number of\n * \tbytes are copied.\n *\n * \t**-EFAULT** on failure to parse the header options in the\n * \tpacket.\n *\n * \t**-EPERM** if the helper cannot be used under the current\n * \t*skops*\\ **->op**.\n */\nstatic long (*bpf_load_hdr_opt)(struct bpf_sock_ops *skops, void *searchby_res, __u32 len, __u64 flags) = (void *) 142;\n\n/*\n * bpf_store_hdr_opt\n *\n * \tStore header option.  The data will be copied\n * \tfrom buffer *from* with length *len* to the TCP header.\n *\n * \tThe buffer *from* should have the whole option that\n * \tincludes the kind, kind-length, and the actual\n * \toption data.  The *len* must be at least kind-length\n * \tlong.  The kind-length does not have to be 4 byte\n * \taligned.  The kernel will take care of the padding\n * \tand setting the 4 bytes aligned value to th->doff.\n *\n * \tThis helper will check for duplicated option\n * \tby searching the same option in the outgoing skb.\n *\n * \tThis helper can only be called during\n * \t**BPF_SOCK_OPS_WRITE_HDR_OPT_CB**.\n *\n *\n * Returns\n * \t0 on success, or negative error in case of failure:\n *\n * \t**-EINVAL** If param is invalid.\n *\n * \t**-ENOSPC** if there is not enough space in the header.\n * \tNothing has been written\n *\n * \t**-EEXIST** if the option already exists.\n *\n * \t**-EFAULT** on failure to parse the existing header options.\n *\n * \t**-EPERM** if the helper cannot be used under the current\n * \t*skops*\\ **->op**.\n */\nstatic long (*bpf_store_hdr_opt)(struct bpf_sock_ops *skops, const void *from, __u32 len, __u64 flags) = (void *) 143;\n\n/*\n * bpf_reserve_hdr_opt\n *\n * \tReserve *len* bytes for the bpf header option.  The\n * \tspace will be used by **bpf_store_hdr_opt**\\ () later in\n * \t**BPF_SOCK_OPS_WRITE_HDR_OPT_CB**.\n *\n * \tIf **bpf_reserve_hdr_opt**\\ () is called multiple times,\n * \tthe total number of bytes will be reserved.\n *\n * \tThis helper can only be called during\n * \t**BPF_SOCK_OPS_HDR_OPT_LEN_CB**.\n *\n *\n * Returns\n * \t0 on success, or negative error in case of failure:\n *\n * \t**-EINVAL** if a parameter is invalid.\n *\n * \t**-ENOSPC** if there is not enough space in the header.\n *\n * \t**-EPERM** if the helper cannot be used under the current\n * \t*skops*\\ **->op**.\n */\nstatic long (*bpf_reserve_hdr_opt)(struct bpf_sock_ops *skops, __u32 len, __u64 flags) = (void *) 144;\n\n/*\n * bpf_inode_storage_get\n *\n * \tGet a bpf_local_storage from an *inode*.\n *\n * \tLogically, it could be thought of as getting the value from\n * \ta *map* with *inode* as the **key**.  From this\n * \tperspective,  the usage is not much different from\n * \t**bpf_map_lookup_elem**\\ (*map*, **&**\\ *inode*) except this\n * \thelper enforces the key must be an inode and the map must also\n * \tbe a **BPF_MAP_TYPE_INODE_STORAGE**.\n *\n * \tUnderneath, the value is stored locally at *inode* instead of\n * \tthe *map*.  The *map* is used as the bpf-local-storage\n * \t\"type\". The bpf-local-storage \"type\" (i.e. the *map*) is\n * \tsearched against all bpf_local_storage residing at *inode*.\n *\n * \tAn optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be\n * \tused such that a new bpf_local_storage will be\n * \tcreated if one does not exist.  *value* can be used\n * \ttogether with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify\n * \tthe initial value of a bpf_local_storage.  If *value* is\n * \t**NULL**, the new bpf_local_storage will be zero initialized.\n *\n * Returns\n * \tA bpf_local_storage pointer is returned on success.\n *\n * \t**NULL** if not found or there was an error in adding\n * \ta new bpf_local_storage.\n */\nstatic void *(*bpf_inode_storage_get)(void *map, void *inode, void *value, __u64 flags) = (void *) 145;\n\n/*\n * bpf_inode_storage_delete\n *\n * \tDelete a bpf_local_storage from an *inode*.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-ENOENT** if the bpf_local_storage cannot be found.\n */\nstatic int (*bpf_inode_storage_delete)(void *map, void *inode) = (void *) 146;\n\n/*\n * bpf_d_path\n *\n * \tReturn full path for given **struct path** object, which\n * \tneeds to be the kernel BTF *path* object. The path is\n * \treturned in the provided buffer *buf* of size *sz* and\n * \tis zero terminated.\n *\n *\n * Returns\n * \tOn success, the strictly positive length of the string,\n * \tincluding the trailing NUL character. On error, a negative\n * \tvalue.\n */\nstatic long (*bpf_d_path)(struct path *path, char *buf, __u32 sz) = (void *) 147;\n\n/*\n * bpf_copy_from_user\n *\n * \tRead *size* bytes from user space address *user_ptr* and store\n * \tthe data in *dst*. This is a wrapper of **copy_from_user**\\ ().\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_copy_from_user)(void *dst, __u32 size, const void *user_ptr) = (void *) 148;\n\n/*\n * bpf_snprintf_btf\n *\n * \tUse BTF to store a string representation of *ptr*->ptr in *str*,\n * \tusing *ptr*->type_id.  This value should specify the type\n * \tthat *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1)\n * \tcan be used to look up vmlinux BTF type ids. Traversing the\n * \tdata structure using BTF, the type information and values are\n * \tstored in the first *str_size* - 1 bytes of *str*.  Safe copy of\n * \tthe pointer data is carried out to avoid kernel crashes during\n * \toperation.  Smaller types can use string space on the stack;\n * \tlarger programs can use map data to store the string\n * \trepresentation.\n *\n * \tThe string can be subsequently shared with userspace via\n * \tbpf_perf_event_output() or ring buffer interfaces.\n * \tbpf_trace_printk() is to be avoided as it places too small\n * \ta limit on string size to be useful.\n *\n * \t*flags* is a combination of\n *\n * \t**BTF_F_COMPACT**\n * \t\tno formatting around type information\n * \t**BTF_F_NONAME**\n * \t\tno struct/union member names/types\n * \t**BTF_F_PTR_RAW**\n * \t\tshow raw (unobfuscated) pointer values;\n * \t\tequivalent to printk specifier %px.\n * \t**BTF_F_ZERO**\n * \t\tshow zero-valued struct/union members; they\n * \t\tare not displayed by default\n *\n *\n * Returns\n * \tThe number of bytes that were written (or would have been\n * \twritten if output had to be truncated due to string size),\n * \tor a negative error in cases of failure.\n */\nstatic long (*bpf_snprintf_btf)(char *str, __u32 str_size, struct btf_ptr *ptr, __u32 btf_ptr_size, __u64 flags) = (void *) 149;\n\n/*\n * bpf_seq_printf_btf\n *\n * \tUse BTF to write to seq_write a string representation of\n * \t*ptr*->ptr, using *ptr*->type_id as per bpf_snprintf_btf().\n * \t*flags* are identical to those used for bpf_snprintf_btf.\n *\n * Returns\n * \t0 on success or a negative error in case of failure.\n */\nstatic long (*bpf_seq_printf_btf)(struct seq_file *m, struct btf_ptr *ptr, __u32 ptr_size, __u64 flags) = (void *) 150;\n\n/*\n * bpf_skb_cgroup_classid\n *\n * \tSee **bpf_get_cgroup_classid**\\ () for the main description.\n * \tThis helper differs from **bpf_get_cgroup_classid**\\ () in that\n * \tthe cgroup v1 net_cls class is retrieved only from the *skb*'s\n * \tassociated socket instead of the current process.\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_skb_cgroup_classid)(struct __sk_buff *skb) = (void *) 151;\n\n/*\n * bpf_redirect_neigh\n *\n * \tRedirect the packet to another net device of index *ifindex*\n * \tand fill in L2 addresses from neighboring subsystem. This helper\n * \tis somewhat similar to **bpf_redirect**\\ (), except that it\n * \tpopulates L2 addresses as well, meaning, internally, the helper\n * \trelies on the neighbor lookup for the L2 address of the nexthop.\n *\n * \tThe helper will perform a FIB lookup based on the skb's\n * \tnetworking header to get the address of the next hop, unless\n * \tthis is supplied by the caller in the *params* argument. The\n * \t*plen* argument indicates the len of *params* and should be set\n * \tto 0 if *params* is NULL.\n *\n * \tThe *flags* argument is reserved and must be 0. The helper is\n * \tcurrently only supported for tc BPF program types, and enabled\n * \tfor IPv4 and IPv6 protocols.\n *\n * Returns\n * \tThe helper returns **TC_ACT_REDIRECT** on success or\n * \t**TC_ACT_SHOT** on error.\n */\nstatic long (*bpf_redirect_neigh)(__u32 ifindex, struct bpf_redir_neigh *params, int plen, __u64 flags) = (void *) 152;\n\n/*\n * bpf_per_cpu_ptr\n *\n * \tTake a pointer to a percpu ksym, *percpu_ptr*, and return a\n * \tpointer to the percpu kernel variable on *cpu*. A ksym is an\n * \textern variable decorated with '__ksym'. For ksym, there is a\n * \tglobal var (either static or global) defined of the same name\n * \tin the kernel. The ksym is percpu if the global var is percpu.\n * \tThe returned pointer points to the global percpu var on *cpu*.\n *\n * \tbpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the\n * \tkernel, except that bpf_per_cpu_ptr() may return NULL. This\n * \thappens if *cpu* is larger than nr_cpu_ids. The caller of\n * \tbpf_per_cpu_ptr() must check the returned value.\n *\n * Returns\n * \tA pointer pointing to the kernel percpu variable on *cpu*, or\n * \tNULL, if *cpu* is invalid.\n */\nstatic void *(*bpf_per_cpu_ptr)(const void *percpu_ptr, __u32 cpu) = (void *) 153;\n\n/*\n * bpf_this_cpu_ptr\n *\n * \tTake a pointer to a percpu ksym, *percpu_ptr*, and return a\n * \tpointer to the percpu kernel variable on this cpu. See the\n * \tdescription of 'ksym' in **bpf_per_cpu_ptr**\\ ().\n *\n * \tbpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in\n * \tthe kernel. Different from **bpf_per_cpu_ptr**\\ (), it would\n * \tnever return NULL.\n *\n * Returns\n * \tA pointer pointing to the kernel percpu variable on this cpu.\n */\nstatic void *(*bpf_this_cpu_ptr)(const void *percpu_ptr) = (void *) 154;\n\n/*\n * bpf_redirect_peer\n *\n * \tRedirect the packet to another net device of index *ifindex*.\n * \tThis helper is somewhat similar to **bpf_redirect**\\ (), except\n * \tthat the redirection happens to the *ifindex*' peer device and\n * \tthe netns switch takes place from ingress to ingress without\n * \tgoing through the CPU's backlog queue.\n *\n * \tThe *flags* argument is reserved and must be 0. The helper is\n * \tcurrently only supported for tc BPF program types at the ingress\n * \thook and for veth device types. The peer device must reside in a\n * \tdifferent network namespace.\n *\n * Returns\n * \tThe helper returns **TC_ACT_REDIRECT** on success or\n * \t**TC_ACT_SHOT** on error.\n */\nstatic long (*bpf_redirect_peer)(__u32 ifindex, __u64 flags) = (void *) 155;\n\n/*\n * bpf_task_storage_get\n *\n * \tGet a bpf_local_storage from the *task*.\n *\n * \tLogically, it could be thought of as getting the value from\n * \ta *map* with *task* as the **key**.  From this\n * \tperspective,  the usage is not much different from\n * \t**bpf_map_lookup_elem**\\ (*map*, **&**\\ *task*) except this\n * \thelper enforces the key must be a task_struct and the map must also\n * \tbe a **BPF_MAP_TYPE_TASK_STORAGE**.\n *\n * \tUnderneath, the value is stored locally at *task* instead of\n * \tthe *map*.  The *map* is used as the bpf-local-storage\n * \t\"type\". The bpf-local-storage \"type\" (i.e. the *map*) is\n * \tsearched against all bpf_local_storage residing at *task*.\n *\n * \tAn optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be\n * \tused such that a new bpf_local_storage will be\n * \tcreated if one does not exist.  *value* can be used\n * \ttogether with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify\n * \tthe initial value of a bpf_local_storage.  If *value* is\n * \t**NULL**, the new bpf_local_storage will be zero initialized.\n *\n * Returns\n * \tA bpf_local_storage pointer is returned on success.\n *\n * \t**NULL** if not found or there was an error in adding\n * \ta new bpf_local_storage.\n */\nstatic void *(*bpf_task_storage_get)(void *map, struct task_struct *task, void *value, __u64 flags) = (void *) 156;\n\n/*\n * bpf_task_storage_delete\n *\n * \tDelete a bpf_local_storage from a *task*.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-ENOENT** if the bpf_local_storage cannot be found.\n */\nstatic long (*bpf_task_storage_delete)(void *map, struct task_struct *task) = (void *) 157;\n\n/*\n * bpf_get_current_task_btf\n *\n * \tReturn a BTF pointer to the \"current\" task.\n * \tThis pointer can also be used in helpers that accept an\n * \t*ARG_PTR_TO_BTF_ID* of type *task_struct*.\n *\n * Returns\n * \tPointer to the current task.\n */\nstatic struct task_struct *(*bpf_get_current_task_btf)(void) = (void *) 158;\n\n/*\n * bpf_bprm_opts_set\n *\n * \tSet or clear certain options on *bprm*:\n *\n * \t**BPF_F_BPRM_SECUREEXEC** Set the secureexec bit\n * \twhich sets the **AT_SECURE** auxv for glibc. The bit\n * \tis cleared if the flag is not specified.\n *\n * Returns\n * \t**-EINVAL** if invalid *flags* are passed, zero otherwise.\n */\nstatic long (*bpf_bprm_opts_set)(struct linux_binprm *bprm, __u64 flags) = (void *) 159;\n\n/*\n * bpf_ktime_get_coarse_ns\n *\n * \tReturn a coarse-grained version of the time elapsed since\n * \tsystem boot, in nanoseconds. Does not include time the system\n * \twas suspended.\n *\n * \tSee: **clock_gettime**\\ (**CLOCK_MONOTONIC_COARSE**)\n *\n * Returns\n * \tCurrent *ktime*.\n */\nstatic __u64 (*bpf_ktime_get_coarse_ns)(void) = (void *) 160;\n\n/*\n * bpf_ima_inode_hash\n *\n * \tReturns the stored IMA hash of the *inode* (if it's available).\n * \tIf the hash is larger than *size*, then only *size*\n * \tbytes will be copied to *dst*\n *\n * Returns\n * \tThe **hash_algo** is returned on success,\n * \t**-EOPNOTSUP** if IMA is disabled or **-EINVAL** if\n * \tinvalid arguments are passed.\n */\nstatic long (*bpf_ima_inode_hash)(struct inode *inode, void *dst, __u32 size) = (void *) 161;\n\n/*\n * bpf_sock_from_file\n *\n * \tIf the given file represents a socket, returns the associated\n * \tsocket.\n *\n * Returns\n * \tA pointer to a struct socket on success or NULL if the file is\n * \tnot a socket.\n */\nstatic struct socket *(*bpf_sock_from_file)(struct file *file) = (void *) 162;\n\n/*\n * bpf_check_mtu\n *\n * \tCheck packet size against exceeding MTU of net device (based\n * \ton *ifindex*).  This helper will likely be used in combination\n * \twith helpers that adjust/change the packet size.\n *\n * \tThe argument *len_diff* can be used for querying with a planned\n * \tsize change. This allows to check MTU prior to changing packet\n * \tctx. Providing a *len_diff* adjustment that is larger than the\n * \tactual packet size (resulting in negative packet size) will in\n * \tprinciple not exceed the MTU, which is why it is not considered\n * \ta failure.  Other BPF helpers are needed for performing the\n * \tplanned size change; therefore the responsibility for catching\n * \ta negative packet size belongs in those helpers.\n *\n * \tSpecifying *ifindex* zero means the MTU check is performed\n * \tagainst the current net device.  This is practical if this isn't\n * \tused prior to redirect.\n *\n * \tOn input *mtu_len* must be a valid pointer, else verifier will\n * \treject BPF program.  If the value *mtu_len* is initialized to\n * \tzero then the ctx packet size is use.  When value *mtu_len* is\n * \tprovided as input this specify the L3 length that the MTU check\n * \tis done against. Remember XDP and TC length operate at L2, but\n * \tthis value is L3 as this correlate to MTU and IP-header tot_len\n * \tvalues which are L3 (similar behavior as bpf_fib_lookup).\n *\n * \tThe Linux kernel route table can configure MTUs on a more\n * \tspecific per route level, which is not provided by this helper.\n * \tFor route level MTU checks use the **bpf_fib_lookup**\\ ()\n * \thelper.\n *\n * \t*ctx* is either **struct xdp_md** for XDP programs or\n * \t**struct sk_buff** for tc cls_act programs.\n *\n * \tThe *flags* argument can be a combination of one or more of the\n * \tfollowing values:\n *\n * \t**BPF_MTU_CHK_SEGS**\n * \t\tThis flag will only works for *ctx* **struct sk_buff**.\n * \t\tIf packet context contains extra packet segment buffers\n * \t\t(often knows as GSO skb), then MTU check is harder to\n * \t\tcheck at this point, because in transmit path it is\n * \t\tpossible for the skb packet to get re-segmented\n * \t\t(depending on net device features).  This could still be\n * \t\ta MTU violation, so this flag enables performing MTU\n * \t\tcheck against segments, with a different violation\n * \t\treturn code to tell it apart. Check cannot use len_diff.\n *\n * \tOn return *mtu_len* pointer contains the MTU value of the net\n * \tdevice.  Remember the net device configured MTU is the L3 size,\n * \twhich is returned here and XDP and TC length operate at L2.\n * \tHelper take this into account for you, but remember when using\n * \tMTU value in your BPF-code.\n *\n *\n * Returns\n * \t* 0 on success, and populate MTU value in *mtu_len* pointer.\n *\n * \t* < 0 if any input argument is invalid (*mtu_len* not updated)\n *\n * \tMTU violations return positive values, but also populate MTU\n * \tvalue in *mtu_len* pointer, as this can be needed for\n * \timplementing PMTU handing:\n *\n * \t* **BPF_MTU_CHK_RET_FRAG_NEEDED**\n * \t* **BPF_MTU_CHK_RET_SEGS_TOOBIG**\n */\nstatic long (*bpf_check_mtu)(void *ctx, __u32 ifindex, __u32 *mtu_len, __s32 len_diff, __u64 flags) = (void *) 163;\n\n/*\n * bpf_for_each_map_elem\n *\n * \tFor each element in **map**, call **callback_fn** function with\n * \t**map**, **callback_ctx** and other map-specific parameters.\n * \tThe **callback_fn** should be a static function and\n * \tthe **callback_ctx** should be a pointer to the stack.\n * \tThe **flags** is used to control certain aspects of the helper.\n * \tCurrently, the **flags** must be 0.\n *\n * \tThe following are a list of supported map types and their\n * \trespective expected callback signatures:\n *\n * \tBPF_MAP_TYPE_HASH, BPF_MAP_TYPE_PERCPU_HASH,\n * \tBPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH,\n * \tBPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PERCPU_ARRAY\n *\n * \tlong (\\*callback_fn)(struct bpf_map \\*map, const void \\*key, void \\*value, void \\*ctx);\n *\n * \tFor per_cpu maps, the map_value is the value on the cpu where the\n * \tbpf_prog is running.\n *\n * \tIf **callback_fn** return 0, the helper will continue to the next\n * \telement. If return value is 1, the helper will skip the rest of\n * \telements and return. Other return values are not used now.\n *\n *\n * Returns\n * \tThe number of traversed map elements for success, **-EINVAL** for\n * \tinvalid **flags**.\n */\nstatic long (*bpf_for_each_map_elem)(void *map, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 164;\n\n/*\n * bpf_snprintf\n *\n * \tOutputs a string into the **str** buffer of size **str_size**\n * \tbased on a format string stored in a read-only map pointed by\n * \t**fmt**.\n *\n * \tEach format specifier in **fmt** corresponds to one u64 element\n * \tin the **data** array. For strings and pointers where pointees\n * \tare accessed, only the pointer values are stored in the *data*\n * \tarray. The *data_len* is the size of *data* in bytes - must be\n * \ta multiple of 8.\n *\n * \tFormats **%s** and **%p{i,I}{4,6}** require to read kernel\n * \tmemory. Reading kernel memory may fail due to either invalid\n * \taddress or valid address but requiring a major memory fault. If\n * \treading kernel memory fails, the string for **%s** will be an\n * \tempty string, and the ip address for **%p{i,I}{4,6}** will be 0.\n * \tNot returning error to bpf program is consistent with what\n * \t**bpf_trace_printk**\\ () does for now.\n *\n *\n * Returns\n * \tThe strictly positive length of the formatted string, including\n * \tthe trailing zero character. If the return value is greater than\n * \t**str_size**, **str** contains a truncated string, guaranteed to\n * \tbe zero-terminated except when **str_size** is 0.\n *\n * \tOr **-EBUSY** if the per-CPU memory copy buffer is busy.\n */\nstatic long (*bpf_snprintf)(char *str, __u32 str_size, const char *fmt, __u64 *data, __u32 data_len) = (void *) 165;\n\n/*\n * bpf_sys_bpf\n *\n * \tExecute bpf syscall with given arguments.\n *\n * Returns\n * \tA syscall result.\n */\nstatic long (*bpf_sys_bpf)(__u32 cmd, void *attr, __u32 attr_size) = (void *) 166;\n\n/*\n * bpf_btf_find_by_name_kind\n *\n * \tFind BTF type with given name and kind in vmlinux BTF or in module's BTFs.\n *\n * Returns\n * \tReturns btf_id and btf_obj_fd in lower and upper 32 bits.\n */\nstatic long (*bpf_btf_find_by_name_kind)(char *name, int name_sz, __u32 kind, int flags) = (void *) 167;\n\n/*\n * bpf_sys_close\n *\n * \tExecute close syscall for given FD.\n *\n * Returns\n * \tA syscall result.\n */\nstatic long (*bpf_sys_close)(__u32 fd) = (void *) 168;\n\n/*\n * bpf_timer_init\n *\n * \tInitialize the timer.\n * \tFirst 4 bits of *flags* specify clockid.\n * \tOnly CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed.\n * \tAll other bits of *flags* are reserved.\n * \tThe verifier will reject the program if *timer* is not from\n * \tthe same *map*.\n *\n * Returns\n * \t0 on success.\n * \t**-EBUSY** if *timer* is already initialized.\n * \t**-EINVAL** if invalid *flags* are passed.\n * \t**-EPERM** if *timer* is in a map that doesn't have any user references.\n * \tThe user space should either hold a file descriptor to a map with timers\n * \tor pin such map in bpffs. When map is unpinned or file descriptor is\n * \tclosed all timers in the map will be cancelled and freed.\n */\nstatic long (*bpf_timer_init)(struct bpf_timer *timer, void *map, __u64 flags) = (void *) 169;\n\n/*\n * bpf_timer_set_callback\n *\n * \tConfigure the timer to call *callback_fn* static function.\n *\n * Returns\n * \t0 on success.\n * \t**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.\n * \t**-EPERM** if *timer* is in a map that doesn't have any user references.\n * \tThe user space should either hold a file descriptor to a map with timers\n * \tor pin such map in bpffs. When map is unpinned or file descriptor is\n * \tclosed all timers in the map will be cancelled and freed.\n */\nstatic long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn) = (void *) 170;\n\n/*\n * bpf_timer_start\n *\n * \tSet timer expiration N nanoseconds from the current time. The\n * \tconfigured callback will be invoked in soft irq context on some cpu\n * \tand will not repeat unless another bpf_timer_start() is made.\n * \tIn such case the next invocation can migrate to a different cpu.\n * \tSince struct bpf_timer is a field inside map element the map\n * \towns the timer. The bpf_timer_set_callback() will increment refcnt\n * \tof BPF program to make sure that callback_fn code stays valid.\n * \tWhen user space reference to a map reaches zero all timers\n * \tin a map are cancelled and corresponding program's refcnts are\n * \tdecremented. This is done to make sure that Ctrl-C of a user\n * \tprocess doesn't leave any timers running. If map is pinned in\n * \tbpffs the callback_fn can re-arm itself indefinitely.\n * \tbpf_map_update/delete_elem() helpers and user space sys_bpf commands\n * \tcancel and free the timer in the given map element.\n * \tThe map can contain timers that invoke callback_fn-s from different\n * \tprograms. The same callback_fn can serve different timers from\n * \tdifferent maps if key/value layout matches across maps.\n * \tEvery bpf_timer_set_callback() can have different callback_fn.\n *\n * \t*flags* can be one of:\n *\n * \t**BPF_F_TIMER_ABS**\n * \t\tStart the timer in absolute expire value instead of the\n * \t\tdefault relative one.\n *\n *\n * Returns\n * \t0 on success.\n * \t**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier\n * \tor invalid *flags* are passed.\n */\nstatic long (*bpf_timer_start)(struct bpf_timer *timer, __u64 nsecs, __u64 flags) = (void *) 171;\n\n/*\n * bpf_timer_cancel\n *\n * \tCancel the timer and wait for callback_fn to finish if it was running.\n *\n * Returns\n * \t0 if the timer was not active.\n * \t1 if the timer was active.\n * \t**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.\n * \t**-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its\n * \town timer which would have led to a deadlock otherwise.\n */\nstatic long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *) 172;\n\n/*\n * bpf_get_func_ip\n *\n * \tGet address of the traced function (for tracing and kprobe programs).\n *\n * Returns\n * \tAddress of the traced function.\n * \t0 for kprobes placed within the function (not at the entry).\n */\nstatic __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173;\n\n/*\n * bpf_get_attach_cookie\n *\n * \tGet bpf_cookie value provided (optionally) during the program\n * \tattachment. It might be different for each individual\n * \tattachment, even if BPF program itself is the same.\n * \tExpects BPF program context *ctx* as a first argument.\n *\n * \tSupported for the following program types:\n * \t\t- kprobe/uprobe;\n * \t\t- tracepoint;\n * \t\t- perf_event.\n *\n * Returns\n * \tValue specified by user at BPF link creation/attachment time\n * \tor 0, if it was not specified.\n */\nstatic __u64 (*bpf_get_attach_cookie)(void *ctx) = (void *) 174;\n\n/*\n * bpf_task_pt_regs\n *\n * \tGet the struct pt_regs associated with **task**.\n *\n * Returns\n * \tA pointer to struct pt_regs.\n */\nstatic long (*bpf_task_pt_regs)(struct task_struct *task) = (void *) 175;\n\n/*\n * bpf_get_branch_snapshot\n *\n * \tGet branch trace from hardware engines like Intel LBR. The\n * \thardware engine is stopped shortly after the helper is\n * \tcalled. Therefore, the user need to filter branch entries\n * \tbased on the actual use case. To capture branch trace\n * \tbefore the trigger point of the BPF program, the helper\n * \tshould be called at the beginning of the BPF program.\n *\n * \tThe data is stored as struct perf_branch_entry into output\n * \tbuffer *entries*. *size* is the size of *entries* in bytes.\n * \t*flags* is reserved for now and must be zero.\n *\n *\n * Returns\n * \tOn success, number of bytes written to *buf*. On error, a\n * \tnegative value.\n *\n * \t**-EINVAL** if *flags* is not zero.\n *\n * \t**-ENOENT** if architecture does not support branch records.\n */\nstatic long (*bpf_get_branch_snapshot)(void *entries, __u32 size, __u64 flags) = (void *) 176;\n\n/*\n * bpf_trace_vprintk\n *\n * \tBehaves like **bpf_trace_printk**\\ () helper, but takes an array of u64\n * \tto format and can handle more format args as a result.\n *\n * \tArguments are to be used as in **bpf_seq_printf**\\ () helper.\n *\n * Returns\n * \tThe number of bytes written to the buffer, or a negative error\n * \tin case of failure.\n */\nstatic long (*bpf_trace_vprintk)(const char *fmt, __u32 fmt_size, const void *data, __u32 data_len) = (void *) 177;\n\n/*\n * bpf_skc_to_unix_sock\n *\n * \tDynamically cast a *sk* pointer to a *unix_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct unix_sock *(*bpf_skc_to_unix_sock)(void *sk) = (void *) 178;\n\n/*\n * bpf_kallsyms_lookup_name\n *\n * \tGet the address of a kernel symbol, returned in *res*. *res* is\n * \tset to 0 if the symbol is not found.\n *\n * Returns\n * \tOn success, zero. On error, a negative value.\n *\n * \t**-EINVAL** if *flags* is not zero.\n *\n * \t**-EINVAL** if string *name* is not the same size as *name_sz*.\n *\n * \t**-ENOENT** if symbol is not found.\n *\n * \t**-EPERM** if caller does not have permission to obtain kernel address.\n */\nstatic long (*bpf_kallsyms_lookup_name)(const char *name, int name_sz, int flags, __u64 *res) = (void *) 179;\n\n/*\n * bpf_find_vma\n *\n * \tFind vma of *task* that contains *addr*, call *callback_fn*\n * \tfunction with *task*, *vma*, and *callback_ctx*.\n * \tThe *callback_fn* should be a static function and\n * \tthe *callback_ctx* should be a pointer to the stack.\n * \tThe *flags* is used to control certain aspects of the helper.\n * \tCurrently, the *flags* must be 0.\n *\n * \tThe expected callback signature is\n *\n * \tlong (\\*callback_fn)(struct task_struct \\*task, struct vm_area_struct \\*vma, void \\*callback_ctx);\n *\n *\n * Returns\n * \t0 on success.\n * \t**-ENOENT** if *task->mm* is NULL, or no vma contains *addr*.\n * \t**-EBUSY** if failed to try lock mmap_lock.\n * \t**-EINVAL** for invalid **flags**.\n */\nstatic long (*bpf_find_vma)(struct task_struct *task, __u64 addr, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 180;\n\n/*\n * bpf_loop\n *\n * \tFor **nr_loops**, call **callback_fn** function\n * \twith **callback_ctx** as the context parameter.\n * \tThe **callback_fn** should be a static function and\n * \tthe **callback_ctx** should be a pointer to the stack.\n * \tThe **flags** is used to control certain aspects of the helper.\n * \tCurrently, the **flags** must be 0. Currently, nr_loops is\n * \tlimited to 1 << 23 (~8 million) loops.\n *\n * \tlong (\\*callback_fn)(u32 index, void \\*ctx);\n *\n * \twhere **index** is the current index in the loop. The index\n * \tis zero-indexed.\n *\n * \tIf **callback_fn** returns 0, the helper will continue to the next\n * \tloop. If return value is 1, the helper will skip the rest of\n * \tthe loops and return. Other return values are not used now,\n * \tand will be rejected by the verifier.\n *\n *\n * Returns\n * \tThe number of loops performed, **-EINVAL** for invalid **flags**,\n * \t**-E2BIG** if **nr_loops** exceeds the maximum number of loops.\n */\nstatic long (*bpf_loop)(__u32 nr_loops, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 181;\n\n/*\n * bpf_strncmp\n *\n * \tDo strncmp() between **s1** and **s2**. **s1** doesn't need\n * \tto be null-terminated and **s1_sz** is the maximum storage\n * \tsize of **s1**. **s2** must be a read-only string.\n *\n * Returns\n * \tAn integer less than, equal to, or greater than zero\n * \tif the first **s1_sz** bytes of **s1** is found to be\n * \tless than, to match, or be greater than **s2**.\n */\nstatic long (*bpf_strncmp)(const char *s1, __u32 s1_sz, const char *s2) = (void *) 182;\n\n/*\n * bpf_get_func_arg\n *\n * \tGet **n**-th argument register (zero based) of the traced function (for tracing programs)\n * \treturned in **value**.\n *\n *\n * Returns\n * \t0 on success.\n * \t**-EINVAL** if n >= argument register count of traced function.\n */\nstatic long (*bpf_get_func_arg)(void *ctx, __u32 n, __u64 *value) = (void *) 183;\n\n/*\n * bpf_get_func_ret\n *\n * \tGet return value of the traced function (for tracing programs)\n * \tin **value**.\n *\n *\n * Returns\n * \t0 on success.\n * \t**-EOPNOTSUPP** for tracing programs other than BPF_TRACE_FEXIT or BPF_MODIFY_RETURN.\n */\nstatic long (*bpf_get_func_ret)(void *ctx, __u64 *value) = (void *) 184;\n\n/*\n * bpf_get_func_arg_cnt\n *\n * \tGet number of registers of the traced function (for tracing programs) where\n * \tfunction arguments are stored in these registers.\n *\n *\n * Returns\n * \tThe number of argument registers of the traced function.\n */\nstatic long (*bpf_get_func_arg_cnt)(void *ctx) = (void *) 185;\n\n/*\n * bpf_get_retval\n *\n * \tGet the BPF program's return value that will be returned to the upper layers.\n *\n * \tThis helper is currently supported by cgroup programs and only by the hooks\n * \twhere BPF program's return value is returned to the userspace via errno.\n *\n * Returns\n * \tThe BPF program's return value.\n */\nstatic int (*bpf_get_retval)(void) = (void *) 186;\n\n/*\n * bpf_set_retval\n *\n * \tSet the BPF program's return value that will be returned to the upper layers.\n *\n * \tThis helper is currently supported by cgroup programs and only by the hooks\n * \twhere BPF program's return value is returned to the userspace via errno.\n *\n * \tNote that there is the following corner case where the program exports an error\n * \tvia bpf_set_retval but signals success via 'return 1':\n *\n * \t\tbpf_set_retval(-EPERM);\n * \t\treturn 1;\n *\n * \tIn this case, the BPF program's return value will use helper's -EPERM. This\n * \tstill holds true for cgroup/bind{4,6} which supports extra 'return 3' success case.\n *\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic int (*bpf_set_retval)(int retval) = (void *) 187;\n\n/*\n * bpf_xdp_get_buff_len\n *\n * \tGet the total size of a given xdp buff (linear and paged area)\n *\n * Returns\n * \tThe total size of a given xdp buffer.\n */\nstatic __u64 (*bpf_xdp_get_buff_len)(struct xdp_md *xdp_md) = (void *) 188;\n\n/*\n * bpf_xdp_load_bytes\n *\n * \tThis helper is provided as an easy way to load data from a\n * \txdp buffer. It can be used to load *len* bytes from *offset* from\n * \tthe frame associated to *xdp_md*, into the buffer pointed by\n * \t*buf*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_load_bytes)(struct xdp_md *xdp_md, __u32 offset, void *buf, __u32 len) = (void *) 189;\n\n/*\n * bpf_xdp_store_bytes\n *\n * \tStore *len* bytes from buffer *buf* into the frame\n * \tassociated to *xdp_md*, at *offset*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_store_bytes)(struct xdp_md *xdp_md, __u32 offset, void *buf, __u32 len) = (void *) 190;\n\n/*\n * bpf_copy_from_user_task\n *\n * \tRead *size* bytes from user space address *user_ptr* in *tsk*'s\n * \taddress space, and stores the data in *dst*. *flags* is not\n * \tused yet and is provided for future extensibility. This helper\n * \tcan only be used by sleepable programs.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure. On error\n * \t*dst* buffer is zeroed out.\n */\nstatic long (*bpf_copy_from_user_task)(void *dst, __u32 size, const void *user_ptr, struct task_struct *tsk, __u64 flags) = (void *) 191;\n\n/*\n * bpf_skb_set_tstamp\n *\n * \tChange the __sk_buff->tstamp_type to *tstamp_type*\n * \tand set *tstamp* to the __sk_buff->tstamp together.\n *\n * \tIf there is no need to change the __sk_buff->tstamp_type,\n * \tthe tstamp value can be directly written to __sk_buff->tstamp\n * \tinstead.\n *\n * \tBPF_SKB_TSTAMP_DELIVERY_MONO is the only tstamp that\n * \twill be kept during bpf_redirect_*().  A non zero\n * \t*tstamp* must be used with the BPF_SKB_TSTAMP_DELIVERY_MONO\n * \t*tstamp_type*.\n *\n * \tA BPF_SKB_TSTAMP_UNSPEC *tstamp_type* can only be used\n * \twith a zero *tstamp*.\n *\n * \tOnly IPv4 and IPv6 skb->protocol are supported.\n *\n * \tThis function is most useful when it needs to set a\n * \tmono delivery time to __sk_buff->tstamp and then\n * \tbpf_redirect_*() to the egress of an iface.  For example,\n * \tchanging the (rcv) timestamp in __sk_buff->tstamp at\n * \tingress to a mono delivery time and then bpf_redirect_*()\n * \tto sch_fq@phy-dev.\n *\n * Returns\n * \t0 on success.\n * \t**-EINVAL** for invalid input\n * \t**-EOPNOTSUPP** for unsupported protocol\n */\nstatic long (*bpf_skb_set_tstamp)(struct __sk_buff *skb, __u64 tstamp, __u32 tstamp_type) = (void *) 192;\n\n/*\n * bpf_ima_file_hash\n *\n * \tReturns a calculated IMA hash of the *file*.\n * \tIf the hash is larger than *size*, then only *size*\n * \tbytes will be copied to *dst*\n *\n * Returns\n * \tThe **hash_algo** is returned on success,\n * \t**-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if\n * \tinvalid arguments are passed.\n */\nstatic long (*bpf_ima_file_hash)(struct file *file, void *dst, __u32 size) = (void *) 193;\n\n/*\n * bpf_kptr_xchg\n *\n * \tExchange kptr at pointer *map_value* with *ptr*, and return the\n * \told value. *ptr* can be NULL, otherwise it must be a referenced\n * \tpointer which will be released when this helper is called.\n *\n * Returns\n * \tThe old value of kptr (which can be NULL). The returned pointer\n * \tif not NULL, is a reference which must be released using its\n * \tcorresponding release function, or moved into a BPF map before\n * \tprogram exit.\n */\nstatic void *(*bpf_kptr_xchg)(void *map_value, void *ptr) = (void *) 194;\n\n/*\n * bpf_map_lookup_percpu_elem\n *\n * \tPerform a lookup in *percpu map* for an entry associated to\n * \t*key* on *cpu*.\n *\n * Returns\n * \tMap value associated to *key* on *cpu*, or **NULL** if no entry\n * \twas found or *cpu* is invalid.\n */\nstatic void *(*bpf_map_lookup_percpu_elem)(void *map, const void *key, __u32 cpu) = (void *) 195;\n\n/*\n * bpf_skc_to_mptcp_sock\n *\n * \tDynamically cast a *sk* pointer to a *mptcp_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct mptcp_sock *(*bpf_skc_to_mptcp_sock)(void *sk) = (void *) 196;\n\n/*\n * bpf_dynptr_from_mem\n *\n * \tGet a dynptr to local memory *data*.\n *\n * \t*data* must be a ptr to a map value.\n * \tThe maximum *size* supported is DYNPTR_MAX_SIZE.\n * \t*flags* is currently unused.\n *\n * Returns\n * \t0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE,\n * \t-EINVAL if flags is not 0.\n */\nstatic long (*bpf_dynptr_from_mem)(void *data, __u32 size, __u64 flags, struct bpf_dynptr *ptr) = (void *) 197;\n\n/*\n * bpf_ringbuf_reserve_dynptr\n *\n * \tReserve *size* bytes of payload in a ring buffer *ringbuf*\n * \tthrough the dynptr interface. *flags* must be 0.\n *\n * \tPlease note that a corresponding bpf_ringbuf_submit_dynptr or\n * \tbpf_ringbuf_discard_dynptr must be called on *ptr*, even if the\n * \treservation fails. This is enforced by the verifier.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_ringbuf_reserve_dynptr)(void *ringbuf, __u32 size, __u64 flags, struct bpf_dynptr *ptr) = (void *) 198;\n\n/*\n * bpf_ringbuf_submit_dynptr\n *\n * \tSubmit reserved ring buffer sample, pointed to by *data*,\n * \tthrough the dynptr interface. This is a no-op if the dynptr is\n * \tinvalid/null.\n *\n * \tFor more information on *flags*, please see\n * \t'bpf_ringbuf_submit'.\n *\n * Returns\n * \tNothing. Always succeeds.\n */\nstatic void (*bpf_ringbuf_submit_dynptr)(struct bpf_dynptr *ptr, __u64 flags) = (void *) 199;\n\n/*\n * bpf_ringbuf_discard_dynptr\n *\n * \tDiscard reserved ring buffer sample through the dynptr\n * \tinterface. This is a no-op if the dynptr is invalid/null.\n *\n * \tFor more information on *flags*, please see\n * \t'bpf_ringbuf_discard'.\n *\n * Returns\n * \tNothing. Always succeeds.\n */\nstatic void (*bpf_ringbuf_discard_dynptr)(struct bpf_dynptr *ptr, __u64 flags) = (void *) 200;\n\n/*\n * bpf_dynptr_read\n *\n * \tRead *len* bytes from *src* into *dst*, starting from *offset*\n * \tinto *src*.\n * \t*flags* is currently unused.\n *\n * Returns\n * \t0 on success, -E2BIG if *offset* + *len* exceeds the length\n * \tof *src*'s data, -EINVAL if *src* is an invalid dynptr or if\n * \t*flags* is not 0.\n */\nstatic long (*bpf_dynptr_read)(void *dst, __u32 len, const struct bpf_dynptr *src, __u32 offset, __u64 flags) = (void *) 201;\n\n/*\n * bpf_dynptr_write\n *\n * \tWrite *len* bytes from *src* into *dst*, starting from *offset*\n * \tinto *dst*.\n *\n * \t*flags* must be 0 except for skb-type dynptrs.\n *\n * \tFor skb-type dynptrs:\n * \t    *  All data slices of the dynptr are automatically\n * \t       invalidated after **bpf_dynptr_write**\\ (). This is\n * \t       because writing may pull the skb and change the\n * \t       underlying packet buffer.\n *\n * \t    *  For *flags*, please see the flags accepted by\n * \t       **bpf_skb_store_bytes**\\ ().\n *\n * Returns\n * \t0 on success, -E2BIG if *offset* + *len* exceeds the length\n * \tof *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*\n * \tis a read-only dynptr or if *flags* is not correct. For skb-type dynptrs,\n * \tother errors correspond to errors returned by **bpf_skb_store_bytes**\\ ().\n */\nstatic long (*bpf_dynptr_write)(const struct bpf_dynptr *dst, __u32 offset, void *src, __u32 len, __u64 flags) = (void *) 202;\n\n/*\n * bpf_dynptr_data\n *\n * \tGet a pointer to the underlying dynptr data.\n *\n * \t*len* must be a statically known value. The returned data slice\n * \tis invalidated whenever the dynptr is invalidated.\n *\n * \tskb and xdp type dynptrs may not use bpf_dynptr_data. They should\n * \tinstead use bpf_dynptr_slice and bpf_dynptr_slice_rdwr.\n *\n * Returns\n * \tPointer to the underlying dynptr data, NULL if the dynptr is\n * \tread-only, if the dynptr is invalid, or if the offset and length\n * \tis out of bounds.\n */\nstatic void *(*bpf_dynptr_data)(const struct bpf_dynptr *ptr, __u32 offset, __u32 len) = (void *) 203;\n\n/*\n * bpf_tcp_raw_gen_syncookie_ipv4\n *\n * \tTry to issue a SYN cookie for the packet with corresponding\n * \tIPv4/TCP headers, *iph* and *th*, without depending on a\n * \tlistening socket.\n *\n * \t*iph* points to the IPv4 header.\n *\n * \t*th* points to the start of the TCP header, while *th_len*\n * \tcontains the length of the TCP header (at least\n * \t**sizeof**\\ (**struct tcphdr**)).\n *\n * Returns\n * \tOn success, lower 32 bits hold the generated SYN cookie in\n * \tfollowed by 16 bits which hold the MSS value for that cookie,\n * \tand the top 16 bits are unused.\n *\n * \tOn failure, the returned value is one of the following:\n *\n * \t**-EINVAL** if *th_len* is invalid.\n */\nstatic __s64 (*bpf_tcp_raw_gen_syncookie_ipv4)(struct iphdr *iph, struct tcphdr *th, __u32 th_len) = (void *) 204;\n\n/*\n * bpf_tcp_raw_gen_syncookie_ipv6\n *\n * \tTry to issue a SYN cookie for the packet with corresponding\n * \tIPv6/TCP headers, *iph* and *th*, without depending on a\n * \tlistening socket.\n *\n * \t*iph* points to the IPv6 header.\n *\n * \t*th* points to the start of the TCP header, while *th_len*\n * \tcontains the length of the TCP header (at least\n * \t**sizeof**\\ (**struct tcphdr**)).\n *\n * Returns\n * \tOn success, lower 32 bits hold the generated SYN cookie in\n * \tfollowed by 16 bits which hold the MSS value for that cookie,\n * \tand the top 16 bits are unused.\n *\n * \tOn failure, the returned value is one of the following:\n *\n * \t**-EINVAL** if *th_len* is invalid.\n *\n * \t**-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.\n */\nstatic __s64 (*bpf_tcp_raw_gen_syncookie_ipv6)(struct ipv6hdr *iph, struct tcphdr *th, __u32 th_len) = (void *) 205;\n\n/*\n * bpf_tcp_raw_check_syncookie_ipv4\n *\n * \tCheck whether *iph* and *th* contain a valid SYN cookie ACK\n * \twithout depending on a listening socket.\n *\n * \t*iph* points to the IPv4 header.\n *\n * \t*th* points to the TCP header.\n *\n * Returns\n * \t0 if *iph* and *th* are a valid SYN cookie ACK.\n *\n * \tOn failure, the returned value is one of the following:\n *\n * \t**-EACCES** if the SYN cookie is not valid.\n */\nstatic long (*bpf_tcp_raw_check_syncookie_ipv4)(struct iphdr *iph, struct tcphdr *th) = (void *) 206;\n\n/*\n * bpf_tcp_raw_check_syncookie_ipv6\n *\n * \tCheck whether *iph* and *th* contain a valid SYN cookie ACK\n * \twithout depending on a listening socket.\n *\n * \t*iph* points to the IPv6 header.\n *\n * \t*th* points to the TCP header.\n *\n * Returns\n * \t0 if *iph* and *th* are a valid SYN cookie ACK.\n *\n * \tOn failure, the returned value is one of the following:\n *\n * \t**-EACCES** if the SYN cookie is not valid.\n *\n * \t**-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.\n */\nstatic long (*bpf_tcp_raw_check_syncookie_ipv6)(struct ipv6hdr *iph, struct tcphdr *th) = (void *) 207;\n\n/*\n * bpf_ktime_get_tai_ns\n *\n * \tA nonsettable system-wide clock derived from wall-clock time but\n * \tignoring leap seconds.  This clock does not experience\n * \tdiscontinuities and backwards jumps caused by NTP inserting leap\n * \tseconds as CLOCK_REALTIME does.\n *\n * \tSee: **clock_gettime**\\ (**CLOCK_TAI**)\n *\n * Returns\n * \tCurrent *ktime*.\n */\nstatic __u64 (*bpf_ktime_get_tai_ns)(void) = (void *) 208;\n\n/*\n * bpf_user_ringbuf_drain\n *\n * \tDrain samples from the specified user ring buffer, and invoke\n * \tthe provided callback for each such sample:\n *\n * \tlong (\\*callback_fn)(const struct bpf_dynptr \\*dynptr, void \\*ctx);\n *\n * \tIf **callback_fn** returns 0, the helper will continue to try\n * \tand drain the next sample, up to a maximum of\n * \tBPF_MAX_USER_RINGBUF_SAMPLES samples. If the return value is 1,\n * \tthe helper will skip the rest of the samples and return. Other\n * \treturn values are not used now, and will be rejected by the\n * \tverifier.\n *\n * Returns\n * \tThe number of drained samples if no error was encountered while\n * \tdraining samples, or 0 if no samples were present in the ring\n * \tbuffer. If a user-space producer was epoll-waiting on this map,\n * \tand at least one sample was drained, they will receive an event\n * \tnotification notifying them of available space in the ring\n * \tbuffer. If the BPF_RB_NO_WAKEUP flag is passed to this\n * \tfunction, no wakeup notification will be sent. If the\n * \tBPF_RB_FORCE_WAKEUP flag is passed, a wakeup notification will\n * \tbe sent even if no sample was drained.\n *\n * \tOn failure, the returned value is one of the following:\n *\n * \t**-EBUSY** if the ring buffer is contended, and another calling\n * \tcontext was concurrently draining the ring buffer.\n *\n * \t**-EINVAL** if user-space is not properly tracking the ring\n * \tbuffer due to the producer position not being aligned to 8\n * \tbytes, a sample not being aligned to 8 bytes, or the producer\n * \tposition not matching the advertised length of a sample.\n *\n * \t**-E2BIG** if user-space has tried to publish a sample which is\n * \tlarger than the size of the ring buffer, or which cannot fit\n * \twithin a struct bpf_dynptr.\n */\nstatic long (*bpf_user_ringbuf_drain)(void *map, void *callback_fn, void *ctx, __u64 flags) = (void *) 209;\n\n/*\n * bpf_cgrp_storage_get\n *\n * \tGet a bpf_local_storage from the *cgroup*.\n *\n * \tLogically, it could be thought of as getting the value from\n * \ta *map* with *cgroup* as the **key**.  From this\n * \tperspective,  the usage is not much different from\n * \t**bpf_map_lookup_elem**\\ (*map*, **&**\\ *cgroup*) except this\n * \thelper enforces the key must be a cgroup struct and the map must also\n * \tbe a **BPF_MAP_TYPE_CGRP_STORAGE**.\n *\n * \tIn reality, the local-storage value is embedded directly inside of the\n * \t*cgroup* object itself, rather than being located in the\n * \t**BPF_MAP_TYPE_CGRP_STORAGE** map. When the local-storage value is\n * \tqueried for some *map* on a *cgroup* object, the kernel will perform an\n * \tO(n) iteration over all of the live local-storage values for that\n * \t*cgroup* object until the local-storage value for the *map* is found.\n *\n * \tAn optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be\n * \tused such that a new bpf_local_storage will be\n * \tcreated if one does not exist.  *value* can be used\n * \ttogether with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify\n * \tthe initial value of a bpf_local_storage.  If *value* is\n * \t**NULL**, the new bpf_local_storage will be zero initialized.\n *\n * Returns\n * \tA bpf_local_storage pointer is returned on success.\n *\n * \t**NULL** if not found or there was an error in adding\n * \ta new bpf_local_storage.\n */\nstatic void *(*bpf_cgrp_storage_get)(void *map, struct cgroup *cgroup, void *value, __u64 flags) = (void *) 210;\n\n/*\n * bpf_cgrp_storage_delete\n *\n * \tDelete a bpf_local_storage from a *cgroup*.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-ENOENT** if the bpf_local_storage cannot be found.\n */\nstatic long (*bpf_cgrp_storage_delete)(void *map, struct cgroup *cgroup) = (void *) 211;\n\n\n"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/bpf/bpf_helpers.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n#ifndef __BPF_HELPERS__\n#define __BPF_HELPERS__\n\n/*\n * Note that bpf programs need to include either\n * vmlinux.h (auto-generated from BTF) or linux/types.h\n * in advance since bpf_helper_defs.h uses such types\n * as __u64.\n */\n#include \"bpf_helper_defs.h\"\n\n#define __uint(name, val) int (*name)[val]\n#define __type(name, val) typeof(val) *name\n#define __array(name, val) typeof(val) *name[]\n\n/*\n * Helper macro to place programs, maps, license in\n * different sections in elf_bpf file. Section names\n * are interpreted by libbpf depending on the context (BPF programs, BPF maps,\n * extern variables, etc).\n * To allow use of SEC() with externs (e.g., for extern .maps declarations),\n * make sure __attribute__((unused)) doesn't trigger compilation warning.\n */\n#if __GNUC__ && !__clang__\n\n/*\n * Pragma macros are broken on GCC\n * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578\n * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90400\n */\n#define SEC(name) __attribute__((section(name), used))\n\n#else\n\n#define SEC(name) \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wignored-attributes\\\"\")\t    \\\n\t__attribute__((section(name), used))\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n\n#endif\n\n/* Avoid 'linux/stddef.h' definition of '__always_inline'. */\n#undef __always_inline\n#define __always_inline inline __attribute__((always_inline))\n\n#ifndef __noinline\n#define __noinline __attribute__((noinline))\n#endif\n#ifndef __weak\n#define __weak __attribute__((weak))\n#endif\n\n/*\n * Use __hidden attribute to mark a non-static BPF subprogram effectively\n * static for BPF verifier's verification algorithm purposes, allowing more\n * extensive and permissive BPF verification process, taking into account\n * subprogram's caller context.\n */\n#define __hidden __attribute__((visibility(\"hidden\")))\n\n/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include\n * any system-level headers (such as stddef.h, linux/version.h, etc), and\n * commonly-used macros like NULL and KERNEL_VERSION aren't available through\n * vmlinux.h. This just adds unnecessary hurdles and forces users to re-define\n * them on their own. So as a convenience, provide such definitions here.\n */\n#ifndef NULL\n#define NULL ((void *)0)\n#endif\n\n#ifndef KERNEL_VERSION\n#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))\n#endif\n\n/*\n * Helper macros to manipulate data structures\n */\n#ifndef offsetof\n#define offsetof(TYPE, MEMBER)\t((unsigned long)&((TYPE *)0)->MEMBER)\n#endif\n#ifndef container_of\n#define container_of(ptr, type, member)\t\t\t\t\\\n\t({\t\t\t\t\t\t\t\\\n\t\tvoid *__mptr = (void *)(ptr);\t\t\t\\\n\t\t((type *)(__mptr - offsetof(type, member)));\t\\\n\t})\n#endif\n\n/*\n * Compiler (optimization) barrier.\n */\n#ifndef barrier\n#define barrier() asm volatile(\"\" ::: \"memory\")\n#endif\n\n/* Variable-specific compiler (optimization) barrier. It's a no-op which makes\n * compiler believe that there is some black box modification of a given\n * variable and thus prevents compiler from making extra assumption about its\n * value and potential simplifications and optimizations on this variable.\n *\n * E.g., compiler might often delay or even omit 32-bit to 64-bit casting of\n * a variable, making some code patterns unverifiable. Putting barrier_var()\n * in place will ensure that cast is performed before the barrier_var()\n * invocation, because compiler has to pessimistically assume that embedded\n * asm section might perform some extra operations on that variable.\n *\n * This is a variable-specific variant of more global barrier().\n */\n#ifndef barrier_var\n#define barrier_var(var) asm volatile(\"\" : \"+r\"(var))\n#endif\n\n/*\n * Helper macro to throw a compilation error if __bpf_unreachable() gets\n * built into the resulting code. This works given BPF back end does not\n * implement __builtin_trap(). This is useful to assert that certain paths\n * of the program code are never used and hence eliminated by the compiler.\n *\n * For example, consider a switch statement that covers known cases used by\n * the program. __bpf_unreachable() can then reside in the default case. If\n * the program gets extended such that a case is not covered in the switch\n * statement, then it will throw a build error due to the default case not\n * being compiled out.\n */\n#ifndef __bpf_unreachable\n# define __bpf_unreachable()\t__builtin_trap()\n#endif\n\n/*\n * Helper function to perform a tail call with a constant/immediate map slot.\n */\n#if __clang_major__ >= 8 && defined(__bpf__)\nstatic __always_inline void\nbpf_tail_call_static(void *ctx, const void *map, const __u32 slot)\n{\n\tif (!__builtin_constant_p(slot))\n\t\t__bpf_unreachable();\n\n\t/*\n\t * Provide a hard guarantee that LLVM won't optimize setting r2 (map\n\t * pointer) and r3 (constant map index) from _different paths_ ending\n\t * up at the _same_ call insn as otherwise we won't be able to use the\n\t * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel\n\t * given they mismatch. See also d2e4c1e6c294 (\"bpf: Constant map key\n\t * tracking for prog array pokes\") for details on verifier tracking.\n\t *\n\t * Note on clobber list: we need to stay in-line with BPF calling\n\t * convention, so even if we don't end up using r0, r4, r5, we need\n\t * to mark them as clobber so that LLVM doesn't end up using them\n\t * before / after the call.\n\t */\n\tasm volatile(\"r1 = %[ctx]\\n\\t\"\n\t\t     \"r2 = %[map]\\n\\t\"\n\t\t     \"r3 = %[slot]\\n\\t\"\n\t\t     \"call 12\"\n\t\t     :: [ctx]\"r\"(ctx), [map]\"r\"(map), [slot]\"i\"(slot)\n\t\t     : \"r0\", \"r1\", \"r2\", \"r3\", \"r4\", \"r5\");\n}\n#endif\n\nenum libbpf_pin_type {\n\tLIBBPF_PIN_NONE,\n\t/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */\n\tLIBBPF_PIN_BY_NAME,\n};\n\nenum libbpf_tristate {\n\tTRI_NO = 0,\n\tTRI_YES = 1,\n\tTRI_MODULE = 2,\n};\n\n#define __kconfig __attribute__((section(\".kconfig\")))\n#define __ksym __attribute__((section(\".ksyms\")))\n#define __kptr_untrusted __attribute__((btf_type_tag(\"kptr_untrusted\")))\n#define __kptr __attribute__((btf_type_tag(\"kptr\")))\n\n#define bpf_ksym_exists(sym) ({\t\t\t\t\t\t\t\t\t\\\n\t_Static_assert(!__builtin_constant_p(!!sym), #sym \" should be marked as __weak\");\t\\\n\t!!sym;\t\t\t\t\t\t\t\t\t\t\t\\\n})\n\n#ifndef ___bpf_concat\n#define ___bpf_concat(a, b) a ## b\n#endif\n#ifndef ___bpf_apply\n#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)\n#endif\n#ifndef ___bpf_nth\n#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N\n#endif\n#ifndef ___bpf_narg\n#define ___bpf_narg(...) \\\n\t___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)\n#endif\n\n#define ___bpf_fill0(arr, p, x) do {} while (0)\n#define ___bpf_fill1(arr, p, x) arr[p] = x\n#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args)\n#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args)\n#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args)\n#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args)\n#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args)\n#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args)\n#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args)\n#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args)\n#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args)\n#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args)\n#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args)\n#define ___bpf_fill(arr, args...) \\\n\t___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args)\n\n/*\n * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values\n * in a structure.\n */\n#define BPF_SEQ_PRINTF(seq, fmt, args...)\t\t\t\\\n({\t\t\t\t\t\t\t\t\\\n\tstatic const char ___fmt[] = fmt;\t\t\t\\\n\tunsigned long long ___param[___bpf_narg(args)];\t\t\\\n\t\t\t\t\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\\\n\t___bpf_fill(___param, args);\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\\\n\t\t\t\t\t\t\t\t\\\n\tbpf_seq_printf(seq, ___fmt, sizeof(___fmt),\t\t\\\n\t\t       ___param, sizeof(___param));\t\t\\\n})\n\n/*\n * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of\n * an array of u64.\n */\n#define BPF_SNPRINTF(out, out_size, fmt, args...)\t\t\\\n({\t\t\t\t\t\t\t\t\\\n\tstatic const char ___fmt[] = fmt;\t\t\t\\\n\tunsigned long long ___param[___bpf_narg(args)];\t\t\\\n\t\t\t\t\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\\\n\t___bpf_fill(___param, args);\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\\\n\t\t\t\t\t\t\t\t\\\n\tbpf_snprintf(out, out_size, ___fmt,\t\t\t\\\n\t\t     ___param, sizeof(___param));\t\t\\\n})\n\n#ifdef BPF_NO_GLOBAL_DATA\n#define BPF_PRINTK_FMT_MOD\n#else\n#define BPF_PRINTK_FMT_MOD static const\n#endif\n\n#define __bpf_printk(fmt, ...)\t\t\t\t\\\n({\t\t\t\t\t\t\t\\\n\tBPF_PRINTK_FMT_MOD char ____fmt[] = fmt;\t\\\n\tbpf_trace_printk(____fmt, sizeof(____fmt),\t\\\n\t\t\t ##__VA_ARGS__);\t\t\\\n})\n\n/*\n * __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments\n * instead of an array of u64.\n */\n#define __bpf_vprintk(fmt, args...)\t\t\t\t\\\n({\t\t\t\t\t\t\t\t\\\n\tstatic const char ___fmt[] = fmt;\t\t\t\\\n\tunsigned long long ___param[___bpf_narg(args)];\t\t\\\n\t\t\t\t\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\\\n\t___bpf_fill(___param, args);\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\\\n\t\t\t\t\t\t\t\t\\\n\tbpf_trace_vprintk(___fmt, sizeof(___fmt),\t\t\\\n\t\t\t  ___param, sizeof(___param));\t\t\\\n})\n\n/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args\n * Otherwise use __bpf_vprintk\n */\n#define ___bpf_pick_printk(...) \\\n\t___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk,\t\\\n\t\t   __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk,\t\t\\\n\t\t   __bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\\\n\t\t   __bpf_printk /*1*/, __bpf_printk /*0*/)\n\n/* Helper macro to print out debug messages */\n#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)\n\nstruct bpf_iter_num;\n\nextern int bpf_iter_num_new(struct bpf_iter_num *it, int start, int end) __weak __ksym;\nextern int *bpf_iter_num_next(struct bpf_iter_num *it) __weak __ksym;\nextern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym;\n\n#ifndef bpf_for_each\n/* bpf_for_each(iter_type, cur_elem, args...) provides generic construct for\n * using BPF open-coded iterators without having to write mundane explicit\n * low-level loop logic. Instead, it provides for()-like generic construct\n * that can be used pretty naturally. E.g., for some hypothetical cgroup\n * iterator, you'd write:\n *\n * struct cgroup *cg, *parent_cg = <...>;\n *\n * bpf_for_each(cgroup, cg, parent_cg, CG_ITER_CHILDREN) {\n *     bpf_printk(\"Child cgroup id = %d\", cg->cgroup_id);\n *     if (cg->cgroup_id == 123)\n *         break;\n * }\n *\n * I.e., it looks almost like high-level for each loop in other languages,\n * supports continue/break, and is verifiable by BPF verifier.\n *\n * For iterating integers, the difference betwen bpf_for_each(num, i, N, M)\n * and bpf_for(i, N, M) is in that bpf_for() provides additional proof to\n * verifier that i is in [N, M) range, and in bpf_for_each() case i is `int\n * *`, not just `int`. So for integers bpf_for() is more convenient.\n *\n * Note: this macro relies on C99 feature of allowing to declare variables\n * inside for() loop, bound to for() loop lifetime. It also utilizes GCC\n * extension: __attribute__((cleanup(<func>))), supported by both GCC and\n * Clang.\n */\n#define bpf_for_each(type, cur, args...) for (\t\t\t\t\t\t\t\\\n\t/* initialize and define destructor */\t\t\t\t\t\t\t\\\n\tstruct bpf_iter_##type ___it __attribute__((aligned(8), /* enforce, just in case */,\t\\\n\t\t\t\t\t\t    cleanup(bpf_iter_##type##_destroy))),\t\\\n\t/* ___p pointer is just to call bpf_iter_##type##_new() *once* to init ___it */\t\t\\\n\t\t\t       *___p __attribute__((unused)) = (\t\t\t\t\\\n\t\t\t\t\tbpf_iter_##type##_new(&___it, ##args),\t\t\t\\\n\t/* this is a workaround for Clang bug: it currently doesn't emit BTF */\t\t\t\\\n\t/* for bpf_iter_##type##_destroy() when used from cleanup() attribute */\t\t\\\n\t\t\t\t\t(void)bpf_iter_##type##_destroy, (void *)0);\t\t\\\n\t/* iteration and termination check */\t\t\t\t\t\t\t\\\n\t(((cur) = bpf_iter_##type##_next(&___it)));\t\t\t\t\t\t\\\n)\n#endif /* bpf_for_each */\n\n#ifndef bpf_for\n/* bpf_for(i, start, end) implements a for()-like looping construct that sets\n * provided integer variable *i* to values starting from *start* through,\n * but not including, *end*. It also proves to BPF verifier that *i* belongs\n * to range [start, end), so this can be used for accessing arrays without\n * extra checks.\n *\n * Note: *start* and *end* are assumed to be expressions with no side effects\n * and whose values do not change throughout bpf_for() loop execution. They do\n * not have to be statically known or constant, though.\n *\n * Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()\n * loop bound variables and cleanup attribute, supported by GCC and Clang.\n */\n#define bpf_for(i, start, end) for (\t\t\t\t\t\t\t\t\\\n\t/* initialize and define destructor */\t\t\t\t\t\t\t\\\n\tstruct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */\t\\\n\t\t\t\t\t\t cleanup(bpf_iter_num_destroy))),\t\t\\\n\t/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */\t\t\\\n\t\t\t    *___p __attribute__((unused)) = (\t\t\t\t\t\\\n\t\t\t\tbpf_iter_num_new(&___it, (start), (end)),\t\t\t\\\n\t/* this is a workaround for Clang bug: it currently doesn't emit BTF */\t\t\t\\\n\t/* for bpf_iter_num_destroy() when used from cleanup() attribute */\t\t\t\\\n\t\t\t\t(void)bpf_iter_num_destroy, (void *)0);\t\t\t\t\\\n\t({\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t/* iteration step */\t\t\t\t\t\t\t\t\\\n\t\tint *___t = bpf_iter_num_next(&___it);\t\t\t\t\t\t\\\n\t\t/* termination and bounds check */\t\t\t\t\t\t\\\n\t\t(___t && ((i) = *___t, (i) >= (start) && (i) < (end)));\t\t\t\t\\\n\t});\t\t\t\t\t\t\t\t\t\t\t\\\n)\n#endif /* bpf_for */\n\n#ifndef bpf_repeat\n/* bpf_repeat(N) performs N iterations without exposing iteration number\n *\n * Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for()\n * loop bound variables and cleanup attribute, supported by GCC and Clang.\n */\n#define bpf_repeat(N) for (\t\t\t\t\t\t\t\t\t\\\n\t/* initialize and define destructor */\t\t\t\t\t\t\t\\\n\tstruct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */\t\\\n\t\t\t\t\t\t cleanup(bpf_iter_num_destroy))),\t\t\\\n\t/* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */\t\t\\\n\t\t\t    *___p __attribute__((unused)) = (\t\t\t\t\t\\\n\t\t\t\tbpf_iter_num_new(&___it, 0, (N)),\t\t\t\t\\\n\t/* this is a workaround for Clang bug: it currently doesn't emit BTF */\t\t\t\\\n\t/* for bpf_iter_num_destroy() when used from cleanup() attribute */\t\t\t\\\n\t\t\t\t(void)bpf_iter_num_destroy, (void *)0);\t\t\t\t\\\n\tbpf_iter_num_next(&___it);\t\t\t\t\t\t\t\t\\\n\t/* nothing here  */\t\t\t\t\t\t\t\t\t\\\n)\n#endif /* bpf_repeat */\n\n#endif\n"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/bpf/bpf_tracing.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n#ifndef __BPF_TRACING_H__\n#define __BPF_TRACING_H__\n\n// #include <bpf/bpf_helpers.h>\n#include \"bpf_helpers.h\"\n\n/* Scan the ARCH passed in from ARCH env variable (see Makefile) */\n#if defined(__TARGET_ARCH_x86)\n\t#define bpf_target_x86\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_s390)\n\t#define bpf_target_s390\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_arm)\n\t#define bpf_target_arm\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_arm64)\n\t#define bpf_target_arm64\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_mips)\n\t#define bpf_target_mips\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_powerpc)\n\t#define bpf_target_powerpc\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_sparc)\n\t#define bpf_target_sparc\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_riscv)\n\t#define bpf_target_riscv\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_arc)\n\t#define bpf_target_arc\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_loongarch)\n\t#define bpf_target_loongarch\n\t#define bpf_target_defined\n#else\n\n/* Fall back to what the compiler says */\n#if defined(__x86_64__)\n\t#define bpf_target_x86\n\t#define bpf_target_defined\n#elif defined(__s390__)\n\t#define bpf_target_s390\n\t#define bpf_target_defined\n#elif defined(__arm__)\n\t#define bpf_target_arm\n\t#define bpf_target_defined\n#elif defined(__aarch64__)\n\t#define bpf_target_arm64\n\t#define bpf_target_defined\n#elif defined(__mips__)\n\t#define bpf_target_mips\n\t#define bpf_target_defined\n#elif defined(__powerpc__)\n\t#define bpf_target_powerpc\n\t#define bpf_target_defined\n#elif defined(__sparc__)\n\t#define bpf_target_sparc\n\t#define bpf_target_defined\n#elif defined(__riscv) && __riscv_xlen == 64\n\t#define bpf_target_riscv\n\t#define bpf_target_defined\n#elif defined(__arc__)\n\t#define bpf_target_arc\n\t#define bpf_target_defined\n#elif defined(__loongarch__)\n\t#define bpf_target_loongarch\n\t#define bpf_target_defined\n#endif /* no compiler target */\n\n#endif\n\n#ifndef __BPF_TARGET_MISSING\n#define __BPF_TARGET_MISSING \"GCC error \\\"Must specify a BPF target arch via __TARGET_ARCH_xxx\\\"\"\n#endif\n\n#if defined(bpf_target_x86)\n\n/*\n * https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI\n */\n\n#if defined(__KERNEL__) || defined(__VMLINUX_H__)\n\n#define __PT_PARM1_REG di\n#define __PT_PARM2_REG si\n#define __PT_PARM3_REG dx\n#define __PT_PARM4_REG cx\n#define __PT_PARM5_REG r8\n#define __PT_PARM6_REG r9\n/*\n * Syscall uses r10 for PARM4. See arch/x86/entry/entry_64.S:entry_SYSCALL_64\n * comments in Linux sources. And refer to syscall(2) manpage.\n */\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG r10\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n\n#define __PT_RET_REG sp\n#define __PT_FP_REG bp\n#define __PT_RC_REG ax\n#define __PT_SP_REG sp\n#define __PT_IP_REG ip\n\n#else\n\n#ifdef __i386__\n\n/* i386 kernel is built with -mregparm=3 */\n#define __PT_PARM1_REG eax\n#define __PT_PARM2_REG edx\n#define __PT_PARM3_REG ecx\n/* i386 syscall ABI is very different, refer to syscall(2) manpage */\n#define __PT_PARM1_SYSCALL_REG ebx\n#define __PT_PARM2_SYSCALL_REG ecx\n#define __PT_PARM3_SYSCALL_REG edx\n#define __PT_PARM4_SYSCALL_REG esi\n#define __PT_PARM5_SYSCALL_REG edi\n#define __PT_PARM6_SYSCALL_REG ebp\n\n#define __PT_RET_REG esp\n#define __PT_FP_REG ebp\n#define __PT_RC_REG eax\n#define __PT_SP_REG esp\n#define __PT_IP_REG eip\n\n#else /* __i386__ */\n\n#define __PT_PARM1_REG rdi\n#define __PT_PARM2_REG rsi\n#define __PT_PARM3_REG rdx\n#define __PT_PARM4_REG rcx\n#define __PT_PARM5_REG r8\n#define __PT_PARM6_REG r9\n\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG r10\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n\n#define __PT_RET_REG rsp\n#define __PT_FP_REG rbp\n#define __PT_RC_REG rax\n#define __PT_SP_REG rsp\n#define __PT_IP_REG rip\n\n#endif /* __i386__ */\n\n#endif /* __KERNEL__ || __VMLINUX_H__ */\n\n#elif defined(bpf_target_s390)\n\n/*\n * https://github.com/IBM/s390x-abi/releases/download/v1.6/lzsabi_s390x.pdf\n */\n\nstruct pt_regs___s390 {\n\tunsigned long orig_gpr2;\n};\n\n/* s390 provides user_pt_regs instead of struct pt_regs to userspace */\n#define __PT_REGS_CAST(x) ((const user_pt_regs *)(x))\n#define __PT_PARM1_REG gprs[2]\n#define __PT_PARM2_REG gprs[3]\n#define __PT_PARM3_REG gprs[4]\n#define __PT_PARM4_REG gprs[5]\n#define __PT_PARM5_REG gprs[6]\n\n#define __PT_PARM1_SYSCALL_REG orig_gpr2\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG gprs[7]\n#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)\n#define PT_REGS_PARM1_CORE_SYSCALL(x) \\\n\tBPF_CORE_READ((const struct pt_regs___s390 *)(x), __PT_PARM1_SYSCALL_REG)\n\n#define __PT_RET_REG gprs[14]\n#define __PT_FP_REG gprs[11]\t/* Works only with CONFIG_FRAME_POINTER */\n#define __PT_RC_REG gprs[2]\n#define __PT_SP_REG gprs[15]\n#define __PT_IP_REG psw.addr\n\n#elif defined(bpf_target_arm)\n\n/*\n * https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#machine-registers\n */\n\n#define __PT_PARM1_REG uregs[0]\n#define __PT_PARM2_REG uregs[1]\n#define __PT_PARM3_REG uregs[2]\n#define __PT_PARM4_REG uregs[3]\n\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG uregs[4]\n#define __PT_PARM6_SYSCALL_REG uregs[5]\n#define __PT_PARM7_SYSCALL_REG uregs[6]\n\n#define __PT_RET_REG uregs[14]\n#define __PT_FP_REG uregs[11]\t/* Works only with CONFIG_FRAME_POINTER */\n#define __PT_RC_REG uregs[0]\n#define __PT_SP_REG uregs[13]\n#define __PT_IP_REG uregs[12]\n\n#elif defined(bpf_target_arm64)\n\n/*\n * https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#machine-registers\n */\n\nstruct pt_regs___arm64 {\n\tunsigned long orig_x0;\n};\n\n/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */\n#define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x))\n#define __PT_PARM1_REG regs[0]\n#define __PT_PARM2_REG regs[1]\n#define __PT_PARM3_REG regs[2]\n#define __PT_PARM4_REG regs[3]\n#define __PT_PARM5_REG regs[4]\n#define __PT_PARM6_REG regs[5]\n#define __PT_PARM7_REG regs[6]\n#define __PT_PARM8_REG regs[7]\n\n#define __PT_PARM1_SYSCALL_REG orig_x0\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n#define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x)\n#define PT_REGS_PARM1_CORE_SYSCALL(x) \\\n\tBPF_CORE_READ((const struct pt_regs___arm64 *)(x), __PT_PARM1_SYSCALL_REG)\n\n#define __PT_RET_REG regs[30]\n#define __PT_FP_REG regs[29]\t/* Works only with CONFIG_FRAME_POINTER */\n#define __PT_RC_REG regs[0]\n#define __PT_SP_REG sp\n#define __PT_IP_REG pc\n\n#elif defined(bpf_target_mips)\n\n/*\n * N64 ABI is assumed right now.\n * https://en.wikipedia.org/wiki/MIPS_architecture#Calling_conventions\n */\n\n#define __PT_PARM1_REG regs[4]\n#define __PT_PARM2_REG regs[5]\n#define __PT_PARM3_REG regs[6]\n#define __PT_PARM4_REG regs[7]\n#define __PT_PARM5_REG regs[8]\n#define __PT_PARM6_REG regs[9]\n#define __PT_PARM7_REG regs[10]\n#define __PT_PARM8_REG regs[11]\n\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG /* only N32/N64 */\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG /* only N32/N64 */\n\n#define __PT_RET_REG regs[31]\n#define __PT_FP_REG regs[30]\t/* Works only with CONFIG_FRAME_POINTER */\n#define __PT_RC_REG regs[2]\n#define __PT_SP_REG regs[29]\n#define __PT_IP_REG cp0_epc\n\n#elif defined(bpf_target_powerpc)\n\n/*\n * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf (page 3-14,\n * section \"Function Calling Sequence\")\n */\n\n#define __PT_PARM1_REG gpr[3]\n#define __PT_PARM2_REG gpr[4]\n#define __PT_PARM3_REG gpr[5]\n#define __PT_PARM4_REG gpr[6]\n#define __PT_PARM5_REG gpr[7]\n#define __PT_PARM6_REG gpr[8]\n#define __PT_PARM7_REG gpr[9]\n#define __PT_PARM8_REG gpr[10]\n\n/* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */\n#define PT_REGS_SYSCALL_REGS(ctx) ctx\n#define __PT_PARM1_SYSCALL_REG orig_gpr3\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n#if !defined(__arch64__)\n#define __PT_PARM7_SYSCALL_REG __PT_PARM7_REG /* only powerpc (not powerpc64) */\n#endif\n\n#define __PT_RET_REG regs[31]\n#define __PT_FP_REG __unsupported__\n#define __PT_RC_REG gpr[3]\n#define __PT_SP_REG sp\n#define __PT_IP_REG nip\n\n#elif defined(bpf_target_sparc)\n\n/*\n * https://en.wikipedia.org/wiki/Calling_convention#SPARC\n */\n\n#define __PT_PARM1_REG u_regs[UREG_I0]\n#define __PT_PARM2_REG u_regs[UREG_I1]\n#define __PT_PARM3_REG u_regs[UREG_I2]\n#define __PT_PARM4_REG u_regs[UREG_I3]\n#define __PT_PARM5_REG u_regs[UREG_I4]\n#define __PT_PARM6_REG u_regs[UREG_I5]\n\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n\n#define __PT_RET_REG u_regs[UREG_I7]\n#define __PT_FP_REG __unsupported__\n#define __PT_RC_REG u_regs[UREG_I0]\n#define __PT_SP_REG u_regs[UREG_FP]\n/* Should this also be a bpf_target check for the sparc case? */\n#if defined(__arch64__)\n#define __PT_IP_REG tpc\n#else\n#define __PT_IP_REG pc\n#endif\n\n#elif defined(bpf_target_riscv)\n\n/*\n * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#risc-v-calling-conventions\n */\n\n#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))\n#define __PT_PARM1_REG a0\n#define __PT_PARM2_REG a1\n#define __PT_PARM3_REG a2\n#define __PT_PARM4_REG a3\n#define __PT_PARM5_REG a4\n#define __PT_PARM6_REG a5\n#define __PT_PARM7_REG a6\n#define __PT_PARM8_REG a7\n\n/* riscv does not select ARCH_HAS_SYSCALL_WRAPPER. */\n#define PT_REGS_SYSCALL_REGS(ctx) ctx\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n\n#define __PT_RET_REG ra\n#define __PT_FP_REG s0\n#define __PT_RC_REG a0\n#define __PT_SP_REG sp\n#define __PT_IP_REG pc\n\n#elif defined(bpf_target_arc)\n\n/*\n * Section \"Function Calling Sequence\" (page 24):\n * https://raw.githubusercontent.com/wiki/foss-for-synopsys-dwc-arc-processors/toolchain/files/ARCv2_ABI.pdf\n */\n\n/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */\n#define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x))\n#define __PT_PARM1_REG scratch.r0\n#define __PT_PARM2_REG scratch.r1\n#define __PT_PARM3_REG scratch.r2\n#define __PT_PARM4_REG scratch.r3\n#define __PT_PARM5_REG scratch.r4\n#define __PT_PARM6_REG scratch.r5\n#define __PT_PARM7_REG scratch.r6\n#define __PT_PARM8_REG scratch.r7\n\n/* arc does not select ARCH_HAS_SYSCALL_WRAPPER. */\n#define PT_REGS_SYSCALL_REGS(ctx) ctx\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n\n#define __PT_RET_REG scratch.blink\n#define __PT_FP_REG scratch.fp\n#define __PT_RC_REG scratch.r0\n#define __PT_SP_REG scratch.sp\n#define __PT_IP_REG scratch.ret\n\n#elif defined(bpf_target_loongarch)\n\n/*\n * https://docs.kernel.org/loongarch/introduction.html\n * https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html\n */\n\n/* loongarch provides struct user_pt_regs instead of struct pt_regs to userspace */\n#define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x))\n#define __PT_PARM1_REG regs[4]\n#define __PT_PARM2_REG regs[5]\n#define __PT_PARM3_REG regs[6]\n#define __PT_PARM4_REG regs[7]\n#define __PT_PARM5_REG regs[8]\n#define __PT_PARM6_REG regs[9]\n#define __PT_PARM7_REG regs[10]\n#define __PT_PARM8_REG regs[11]\n\n/* loongarch does not select ARCH_HAS_SYSCALL_WRAPPER. */\n#define PT_REGS_SYSCALL_REGS(ctx) ctx\n#define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG\n#define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG\n#define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG\n#define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG\n#define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG\n#define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG\n\n#define __PT_RET_REG regs[1]\n#define __PT_FP_REG regs[22]\n#define __PT_RC_REG regs[4]\n#define __PT_SP_REG regs[3]\n#define __PT_IP_REG csr_era\n\n#endif\n\n#if defined(bpf_target_defined)\n\nstruct pt_regs;\n\n/* allow some architectures to override `struct pt_regs` */\n#ifndef __PT_REGS_CAST\n#define __PT_REGS_CAST(x) (x)\n#endif\n\n/*\n * Different architectures support different number of arguments passed\n * through registers. i386 supports just 3, some arches support up to 8.\n */\n#ifndef __PT_PARM4_REG\n#define __PT_PARM4_REG __unsupported__\n#endif\n#ifndef __PT_PARM5_REG\n#define __PT_PARM5_REG __unsupported__\n#endif\n#ifndef __PT_PARM6_REG\n#define __PT_PARM6_REG __unsupported__\n#endif\n#ifndef __PT_PARM7_REG\n#define __PT_PARM7_REG __unsupported__\n#endif\n#ifndef __PT_PARM8_REG\n#define __PT_PARM8_REG __unsupported__\n#endif\n/*\n * Similarly, syscall-specific conventions might differ between function call\n * conventions within each architecutre. All supported architectures pass\n * either 6 or 7 syscall arguments in registers.\n *\n * See syscall(2) manpage for succinct table with information on each arch.\n */\n#ifndef __PT_PARM7_SYSCALL_REG\n#define __PT_PARM7_SYSCALL_REG __unsupported__\n#endif\n\n#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)\n#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)\n#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)\n#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)\n#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)\n#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG)\n#define PT_REGS_PARM7(x) (__PT_REGS_CAST(x)->__PT_PARM7_REG)\n#define PT_REGS_PARM8(x) (__PT_REGS_CAST(x)->__PT_PARM8_REG)\n#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)\n#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)\n#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)\n#define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG)\n#define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM1_REG)\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM2_REG)\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_REG)\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_REG)\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_REG)\n#define PT_REGS_PARM6_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_REG)\n#define PT_REGS_PARM7_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_REG)\n#define PT_REGS_PARM8_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM8_REG)\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RET_REG)\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_FP_REG)\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RC_REG)\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_SP_REG)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_IP_REG)\n\n#if defined(bpf_target_powerpc)\n\n#define BPF_KPROBE_READ_RET_IP(ip, ctx)\t\t({ (ip) = (ctx)->link; })\n#define BPF_KRETPROBE_READ_RET_IP\t\tBPF_KPROBE_READ_RET_IP\n\n#elif defined(bpf_target_sparc)\n\n#define BPF_KPROBE_READ_RET_IP(ip, ctx)\t\t({ (ip) = PT_REGS_RET(ctx); })\n#define BPF_KRETPROBE_READ_RET_IP\t\tBPF_KPROBE_READ_RET_IP\n\n#else\n\n#define BPF_KPROBE_READ_RET_IP(ip, ctx)\t\t\t\t\t    \\\n\t({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })\n#define BPF_KRETPROBE_READ_RET_IP(ip, ctx)\t\t\t\t    \\\n\t({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)(PT_REGS_FP(ctx) + sizeof(ip))); })\n\n#endif\n\n#ifndef PT_REGS_PARM1_SYSCALL\n#define PT_REGS_PARM1_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM1_SYSCALL_REG)\n#define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM1_SYSCALL_REG)\n#endif\n#ifndef PT_REGS_PARM2_SYSCALL\n#define PT_REGS_PARM2_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM2_SYSCALL_REG)\n#define PT_REGS_PARM2_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM2_SYSCALL_REG)\n#endif\n#ifndef PT_REGS_PARM3_SYSCALL\n#define PT_REGS_PARM3_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM3_SYSCALL_REG)\n#define PT_REGS_PARM3_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_SYSCALL_REG)\n#endif\n#ifndef PT_REGS_PARM4_SYSCALL\n#define PT_REGS_PARM4_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM4_SYSCALL_REG)\n#define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_SYSCALL_REG)\n#endif\n#ifndef PT_REGS_PARM5_SYSCALL\n#define PT_REGS_PARM5_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM5_SYSCALL_REG)\n#define PT_REGS_PARM5_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_SYSCALL_REG)\n#endif\n#ifndef PT_REGS_PARM6_SYSCALL\n#define PT_REGS_PARM6_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM6_SYSCALL_REG)\n#define PT_REGS_PARM6_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_SYSCALL_REG)\n#endif\n#ifndef PT_REGS_PARM7_SYSCALL\n#define PT_REGS_PARM7_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM7_SYSCALL_REG)\n#define PT_REGS_PARM7_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_SYSCALL_REG)\n#endif\n\n#else /* defined(bpf_target_defined) */\n\n#define PT_REGS_PARM1(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM2(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM6(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM7(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM8(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_SP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_IP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#define PT_REGS_PARM1_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM2_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM6_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM7_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM8_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_SP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_IP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM2_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM3_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM4_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM5_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM6_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM7_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#define PT_REGS_PARM1_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM2_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM3_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM4_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM5_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM6_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM7_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#endif /* defined(bpf_target_defined) */\n\n/*\n * When invoked from a syscall handler kprobe, returns a pointer to a\n * struct pt_regs containing syscall arguments and suitable for passing to\n * PT_REGS_PARMn_SYSCALL() and PT_REGS_PARMn_CORE_SYSCALL().\n */\n#ifndef PT_REGS_SYSCALL_REGS\n/* By default, assume that the arch selects ARCH_HAS_SYSCALL_WRAPPER. */\n#define PT_REGS_SYSCALL_REGS(ctx) ((struct pt_regs *)PT_REGS_PARM1(ctx))\n#endif\n\n#ifndef ___bpf_concat\n#define ___bpf_concat(a, b) a ## b\n#endif\n#ifndef ___bpf_apply\n#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)\n#endif\n#ifndef ___bpf_nth\n#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N\n#endif\n#ifndef ___bpf_narg\n#define ___bpf_narg(...) ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)\n#endif\n\n#define ___bpf_ctx_cast0()            ctx\n#define ___bpf_ctx_cast1(x)           ___bpf_ctx_cast0(), (void *)ctx[0]\n#define ___bpf_ctx_cast2(x, args...)  ___bpf_ctx_cast1(args), (void *)ctx[1]\n#define ___bpf_ctx_cast3(x, args...)  ___bpf_ctx_cast2(args), (void *)ctx[2]\n#define ___bpf_ctx_cast4(x, args...)  ___bpf_ctx_cast3(args), (void *)ctx[3]\n#define ___bpf_ctx_cast5(x, args...)  ___bpf_ctx_cast4(args), (void *)ctx[4]\n#define ___bpf_ctx_cast6(x, args...)  ___bpf_ctx_cast5(args), (void *)ctx[5]\n#define ___bpf_ctx_cast7(x, args...)  ___bpf_ctx_cast6(args), (void *)ctx[6]\n#define ___bpf_ctx_cast8(x, args...)  ___bpf_ctx_cast7(args), (void *)ctx[7]\n#define ___bpf_ctx_cast9(x, args...)  ___bpf_ctx_cast8(args), (void *)ctx[8]\n#define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), (void *)ctx[9]\n#define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), (void *)ctx[10]\n#define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), (void *)ctx[11]\n#define ___bpf_ctx_cast(args...)      ___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args)\n\n/*\n * BPF_PROG is a convenience wrapper for generic tp_btf/fentry/fexit and\n * similar kinds of BPF programs, that accept input arguments as a single\n * pointer to untyped u64 array, where each u64 can actually be a typed\n * pointer or integer of different size. Instead of requring user to write\n * manual casts and work with array elements by index, BPF_PROG macro\n * allows user to declare a list of named and typed input arguments in the\n * same syntax as for normal C function. All the casting is hidden and\n * performed transparently, while user code can just assume working with\n * function arguments of specified type and name.\n *\n * Original raw context argument is preserved as well as 'ctx' argument.\n * This is useful when using BPF helpers that expect original context\n * as one of the parameters (e.g., for bpf_perf_event_output()).\n */\n#define BPF_PROG(name, args...)\t\t\t\t\t\t    \\\nname(unsigned long long *ctx);\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0))\t\t\t\t\t    \\\n____##name(unsigned long long *ctx, ##args);\t\t\t\t    \\\ntypeof(name(0)) name(unsigned long long *ctx)\t\t\t\t    \\\n{\t\t\t\t\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\t    \\\n\treturn ____##name(___bpf_ctx_cast(args));\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n}\t\t\t\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0))\t\t\t\t\t    \\\n____##name(unsigned long long *ctx, ##args)\n\n#ifndef ___bpf_nth2\n#define ___bpf_nth2(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13,\t\\\n\t\t    _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, N, ...) N\n#endif\n#ifndef ___bpf_narg2\n#define ___bpf_narg2(...)\t\\\n\t___bpf_nth2(_, ##__VA_ARGS__, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7,\t\\\n\t\t    6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0)\n#endif\n\n#define ___bpf_treg_cnt(t) \\\n\t__builtin_choose_expr(sizeof(t) == 1, 1,\t\\\n\t__builtin_choose_expr(sizeof(t) == 2, 1,\t\\\n\t__builtin_choose_expr(sizeof(t) == 4, 1,\t\\\n\t__builtin_choose_expr(sizeof(t) == 8, 1,\t\\\n\t__builtin_choose_expr(sizeof(t) == 16, 2,\t\\\n\t\t\t      (void)0)))))\n\n#define ___bpf_reg_cnt0()\t\t(0)\n#define ___bpf_reg_cnt1(t, x)\t\t(___bpf_reg_cnt0() + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt2(t, x, args...)\t(___bpf_reg_cnt1(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt3(t, x, args...)\t(___bpf_reg_cnt2(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt4(t, x, args...)\t(___bpf_reg_cnt3(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt5(t, x, args...)\t(___bpf_reg_cnt4(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt6(t, x, args...)\t(___bpf_reg_cnt5(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt7(t, x, args...)\t(___bpf_reg_cnt6(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt8(t, x, args...)\t(___bpf_reg_cnt7(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt9(t, x, args...)\t(___bpf_reg_cnt8(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt10(t, x, args...)\t(___bpf_reg_cnt9(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt11(t, x, args...)\t(___bpf_reg_cnt10(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt12(t, x, args...)\t(___bpf_reg_cnt11(args) + ___bpf_treg_cnt(t))\n#define ___bpf_reg_cnt(args...)\t ___bpf_apply(___bpf_reg_cnt, ___bpf_narg2(args))(args)\n\n#define ___bpf_union_arg(t, x, n) \\\n\t__builtin_choose_expr(sizeof(t) == 1, ({ union { __u8 z[1]; t x; } ___t = { .z = {ctx[n]}}; ___t.x; }), \\\n\t__builtin_choose_expr(sizeof(t) == 2, ({ union { __u16 z[1]; t x; } ___t = { .z = {ctx[n]} }; ___t.x; }), \\\n\t__builtin_choose_expr(sizeof(t) == 4, ({ union { __u32 z[1]; t x; } ___t = { .z = {ctx[n]} }; ___t.x; }), \\\n\t__builtin_choose_expr(sizeof(t) == 8, ({ union { __u64 z[1]; t x; } ___t = {.z = {ctx[n]} }; ___t.x; }), \\\n\t__builtin_choose_expr(sizeof(t) == 16, ({ union { __u64 z[2]; t x; } ___t = {.z = {ctx[n], ctx[n + 1]} }; ___t.x; }), \\\n\t\t\t      (void)0)))))\n\n#define ___bpf_ctx_arg0(n, args...)\n#define ___bpf_ctx_arg1(n, t, x)\t\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt1(t, x))\n#define ___bpf_ctx_arg2(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt2(t, x, args)) ___bpf_ctx_arg1(n, args)\n#define ___bpf_ctx_arg3(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt3(t, x, args)) ___bpf_ctx_arg2(n, args)\n#define ___bpf_ctx_arg4(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt4(t, x, args)) ___bpf_ctx_arg3(n, args)\n#define ___bpf_ctx_arg5(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt5(t, x, args)) ___bpf_ctx_arg4(n, args)\n#define ___bpf_ctx_arg6(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt6(t, x, args)) ___bpf_ctx_arg5(n, args)\n#define ___bpf_ctx_arg7(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt7(t, x, args)) ___bpf_ctx_arg6(n, args)\n#define ___bpf_ctx_arg8(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt8(t, x, args)) ___bpf_ctx_arg7(n, args)\n#define ___bpf_ctx_arg9(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt9(t, x, args)) ___bpf_ctx_arg8(n, args)\n#define ___bpf_ctx_arg10(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt10(t, x, args)) ___bpf_ctx_arg9(n, args)\n#define ___bpf_ctx_arg11(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt11(t, x, args)) ___bpf_ctx_arg10(n, args)\n#define ___bpf_ctx_arg12(n, t, x, args...)\t, ___bpf_union_arg(t, x, n - ___bpf_reg_cnt12(t, x, args)) ___bpf_ctx_arg11(n, args)\n#define ___bpf_ctx_arg(args...)\t___bpf_apply(___bpf_ctx_arg, ___bpf_narg2(args))(___bpf_reg_cnt(args), args)\n\n#define ___bpf_ctx_decl0()\n#define ___bpf_ctx_decl1(t, x)\t\t\t, t x\n#define ___bpf_ctx_decl2(t, x, args...)\t\t, t x ___bpf_ctx_decl1(args)\n#define ___bpf_ctx_decl3(t, x, args...)\t\t, t x ___bpf_ctx_decl2(args)\n#define ___bpf_ctx_decl4(t, x, args...)\t\t, t x ___bpf_ctx_decl3(args)\n#define ___bpf_ctx_decl5(t, x, args...)\t\t, t x ___bpf_ctx_decl4(args)\n#define ___bpf_ctx_decl6(t, x, args...)\t\t, t x ___bpf_ctx_decl5(args)\n#define ___bpf_ctx_decl7(t, x, args...)\t\t, t x ___bpf_ctx_decl6(args)\n#define ___bpf_ctx_decl8(t, x, args...)\t\t, t x ___bpf_ctx_decl7(args)\n#define ___bpf_ctx_decl9(t, x, args...)\t\t, t x ___bpf_ctx_decl8(args)\n#define ___bpf_ctx_decl10(t, x, args...)\t, t x ___bpf_ctx_decl9(args)\n#define ___bpf_ctx_decl11(t, x, args...)\t, t x ___bpf_ctx_decl10(args)\n#define ___bpf_ctx_decl12(t, x, args...)\t, t x ___bpf_ctx_decl11(args)\n#define ___bpf_ctx_decl(args...)\t___bpf_apply(___bpf_ctx_decl, ___bpf_narg2(args))(args)\n\n/*\n * BPF_PROG2 is an enhanced version of BPF_PROG in order to handle struct\n * arguments. Since each struct argument might take one or two u64 values\n * in the trampoline stack, argument type size is needed to place proper number\n * of u64 values for each argument. Therefore, BPF_PROG2 has different\n * syntax from BPF_PROG. For example, for the following BPF_PROG syntax:\n *\n *   int BPF_PROG(test2, int a, int b) { ... }\n *\n * the corresponding BPF_PROG2 syntax is:\n *\n *   int BPF_PROG2(test2, int, a, int, b) { ... }\n *\n * where type and the corresponding argument name are separated by comma.\n *\n * Use BPF_PROG2 macro if one of the arguments might be a struct/union larger\n * than 8 bytes:\n *\n *   int BPF_PROG2(test_struct_arg, struct bpf_testmod_struct_arg_1, a, int, b,\n *\t\t   int, c, int, d, struct bpf_testmod_struct_arg_2, e, int, ret)\n *   {\n *        // access a, b, c, d, e, and ret directly\n *        ...\n *   }\n */\n#define BPF_PROG2(name, args...)\t\t\t\t\t\t\\\nname(unsigned long long *ctx);\t\t\t\t\t\t\t\\\nstatic __always_inline typeof(name(0))\t\t\t\t\t\t\\\n____##name(unsigned long long *ctx ___bpf_ctx_decl(args));\t\t\t\\\ntypeof(name(0)) name(unsigned long long *ctx)\t\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\t\\\n\treturn ____##name(ctx ___bpf_ctx_arg(args));\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\t\\\nstatic __always_inline typeof(name(0))\t\t\t\t\t\t\\\n____##name(unsigned long long *ctx ___bpf_ctx_decl(args))\n\nstruct pt_regs;\n\n#define ___bpf_kprobe_args0()           ctx\n#define ___bpf_kprobe_args1(x)          ___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx)\n#define ___bpf_kprobe_args2(x, args...) ___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx)\n#define ___bpf_kprobe_args3(x, args...) ___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)\n#define ___bpf_kprobe_args4(x, args...) ___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)\n#define ___bpf_kprobe_args5(x, args...) ___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)\n#define ___bpf_kprobe_args6(x, args...) ___bpf_kprobe_args5(args), (void *)PT_REGS_PARM6(ctx)\n#define ___bpf_kprobe_args7(x, args...) ___bpf_kprobe_args6(args), (void *)PT_REGS_PARM7(ctx)\n#define ___bpf_kprobe_args8(x, args...) ___bpf_kprobe_args7(args), (void *)PT_REGS_PARM8(ctx)\n#define ___bpf_kprobe_args(args...)     ___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)\n\n/*\n * BPF_KPROBE serves the same purpose for kprobes as BPF_PROG for\n * tp_btf/fentry/fexit BPF programs. It hides the underlying platform-specific\n * low-level way of getting kprobe input arguments from struct pt_regs, and\n * provides a familiar typed and named function arguments syntax and\n * semantics of accessing kprobe input paremeters.\n *\n * Original struct pt_regs* context is preserved as 'ctx' argument. This might\n * be necessary when using BPF helpers like bpf_perf_event_output().\n */\n#define BPF_KPROBE(name, args...)\t\t\t\t\t    \\\nname(struct pt_regs *ctx);\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0))\t\t\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args);\t\t\t\t    \\\ntypeof(name(0)) name(struct pt_regs *ctx)\t\t\t\t    \\\n{\t\t\t\t\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\t    \\\n\treturn ____##name(___bpf_kprobe_args(args));\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n}\t\t\t\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0))\t\t\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args)\n\n#define ___bpf_kretprobe_args0()       ctx\n#define ___bpf_kretprobe_args1(x)      ___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx)\n#define ___bpf_kretprobe_args(args...) ___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args)\n\n/*\n * BPF_KRETPROBE is similar to BPF_KPROBE, except, it only provides optional\n * return value (in addition to `struct pt_regs *ctx`), but no input\n * arguments, because they will be clobbered by the time probed function\n * returns.\n */\n#define BPF_KRETPROBE(name, args...)\t\t\t\t\t    \\\nname(struct pt_regs *ctx);\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0))\t\t\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args);\t\t\t\t    \\\ntypeof(name(0)) name(struct pt_regs *ctx)\t\t\t\t    \\\n{\t\t\t\t\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\t    \\\n\treturn ____##name(___bpf_kretprobe_args(args));\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n}\t\t\t\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)\n\n/* If kernel has CONFIG_ARCH_HAS_SYSCALL_WRAPPER, read pt_regs directly */\n#define ___bpf_syscall_args0()           ctx\n#define ___bpf_syscall_args1(x)          ___bpf_syscall_args0(), (void *)PT_REGS_PARM1_SYSCALL(regs)\n#define ___bpf_syscall_args2(x, args...) ___bpf_syscall_args1(args), (void *)PT_REGS_PARM2_SYSCALL(regs)\n#define ___bpf_syscall_args3(x, args...) ___bpf_syscall_args2(args), (void *)PT_REGS_PARM3_SYSCALL(regs)\n#define ___bpf_syscall_args4(x, args...) ___bpf_syscall_args3(args), (void *)PT_REGS_PARM4_SYSCALL(regs)\n#define ___bpf_syscall_args5(x, args...) ___bpf_syscall_args4(args), (void *)PT_REGS_PARM5_SYSCALL(regs)\n#define ___bpf_syscall_args6(x, args...) ___bpf_syscall_args5(args), (void *)PT_REGS_PARM6_SYSCALL(regs)\n#define ___bpf_syscall_args7(x, args...) ___bpf_syscall_args6(args), (void *)PT_REGS_PARM7_SYSCALL(regs)\n#define ___bpf_syscall_args(args...)     ___bpf_apply(___bpf_syscall_args, ___bpf_narg(args))(args)\n\n/* If kernel doesn't have CONFIG_ARCH_HAS_SYSCALL_WRAPPER, we have to BPF_CORE_READ from pt_regs */\n#define ___bpf_syswrap_args0()           ctx\n#define ___bpf_syswrap_args1(x)          ___bpf_syswrap_args0(), (void *)PT_REGS_PARM1_CORE_SYSCALL(regs)\n#define ___bpf_syswrap_args2(x, args...) ___bpf_syswrap_args1(args), (void *)PT_REGS_PARM2_CORE_SYSCALL(regs)\n#define ___bpf_syswrap_args3(x, args...) ___bpf_syswrap_args2(args), (void *)PT_REGS_PARM3_CORE_SYSCALL(regs)\n#define ___bpf_syswrap_args4(x, args...) ___bpf_syswrap_args3(args), (void *)PT_REGS_PARM4_CORE_SYSCALL(regs)\n#define ___bpf_syswrap_args5(x, args...) ___bpf_syswrap_args4(args), (void *)PT_REGS_PARM5_CORE_SYSCALL(regs)\n#define ___bpf_syswrap_args6(x, args...) ___bpf_syswrap_args5(args), (void *)PT_REGS_PARM6_CORE_SYSCALL(regs)\n#define ___bpf_syswrap_args7(x, args...) ___bpf_syswrap_args6(args), (void *)PT_REGS_PARM7_CORE_SYSCALL(regs)\n#define ___bpf_syswrap_args(args...)     ___bpf_apply(___bpf_syswrap_args, ___bpf_narg(args))(args)\n\n/*\n * BPF_KSYSCALL is a variant of BPF_KPROBE, which is intended for\n * tracing syscall functions, like __x64_sys_close. It hides the underlying\n * platform-specific low-level way of getting syscall input arguments from\n * struct pt_regs, and provides a familiar typed and named function arguments\n * syntax and semantics of accessing syscall input parameters.\n *\n * Original struct pt_regs * context is preserved as 'ctx' argument. This might\n * be necessary when using BPF helpers like bpf_perf_event_output().\n *\n * At the moment BPF_KSYSCALL does not transparently handle all the calling\n * convention quirks for the following syscalls:\n *\n * - mmap(): __ARCH_WANT_SYS_OLD_MMAP.\n * - clone(): CONFIG_CLONE_BACKWARDS, CONFIG_CLONE_BACKWARDS2 and\n *            CONFIG_CLONE_BACKWARDS3.\n * - socket-related syscalls: __ARCH_WANT_SYS_SOCKETCALL.\n * - compat syscalls.\n *\n * This may or may not change in the future. User needs to take extra measures\n * to handle such quirks explicitly, if necessary.\n *\n * This macro relies on BPF CO-RE support and virtual __kconfig externs.\n */\n#define BPF_KSYSCALL(name, args...)\t\t\t\t\t    \\\nname(struct pt_regs *ctx);\t\t\t\t\t\t    \\\nextern _Bool LINUX_HAS_SYSCALL_WRAPPER __kconfig;\t\t\t    \\\nstatic __always_inline typeof(name(0))\t\t\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args);\t\t\t\t    \\\ntypeof(name(0)) name(struct pt_regs *ctx)\t\t\t\t    \\\n{\t\t\t\t\t\t\t\t\t    \\\n\tstruct pt_regs *regs = LINUX_HAS_SYSCALL_WRAPPER\t\t    \\\n\t\t\t       ? (struct pt_regs *)PT_REGS_PARM1(ctx)\t    \\\n\t\t\t       : ctx;\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\t    \\\n\tif (LINUX_HAS_SYSCALL_WRAPPER)\t\t\t\t\t    \\\n\t\treturn ____##name(___bpf_syswrap_args(args));\t\t    \\\n\telse\t\t\t\t\t\t\t\t    \\\n\t\treturn ____##name(___bpf_syscall_args(args));\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n}\t\t\t\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0))\t\t\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args)\n\n#define BPF_KPROBE_SYSCALL BPF_KSYSCALL\n\n/* BPF_UPROBE and BPF_URETPROBE are identical to BPF_KPROBE and BPF_KRETPROBE,\n * but are named way less confusingly for SEC(\"uprobe\") and SEC(\"uretprobe\")\n * use cases.\n */\n#define BPF_UPROBE(name, args...)  BPF_KPROBE(name, ##args)\n#define BPF_URETPROBE(name, args...)  BPF_KRETPROBE(name, ##args)\n\n#endif\n"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/exec.c",
    "content": "#include \"vmlinux-x86.h\"\n#include \"bpf/bpf_helpers.h\"\n#include \"bpf/bpf_tracing.h\"\n\n#define ARGLEN  32   // maximum amount of args in argv we'll copy\n#define ARGSIZE 1024 // maximum byte length of each arg in argv we'll copy\n\nchar __license[] SEC(\"license\") = \"GPL\";\n\n// Ring buffer for all connection events\nstruct {\n\t__uint(type, BPF_MAP_TYPE_RINGBUF);\n\t__uint(max_entries, 1 << 24);\n} pm_exec_map SEC(\".maps\");\n\n// This struct is defined according to\n// /sys/kernel/debug/tracing/events/syscalls/sys_enter_execve/format\nstruct exec_info {\n\tu16 common_type;            // offset=0,  size=2\n\tu8  common_flags;           // offset=2,  size=1\n\tu8  common_preempt_count;   // offset=3,  size=1\n\ts32 common_pid;             // offset=4,  size=4\n\n\ts32             syscall_nr; // offset=8,  size=4\n\tu32             pad;        // offset=12, size=4 (pad)\n\tconst u8        *filename;  // offset=16, size=8 (ptr)\n\tconst u8 *const *argv;      // offset=24, size=8 (ptr)\n\tconst u8 *const *envp;      // offset=32, size=8 (ptr)\n};\n\n// The event struct. This struct must be kept in sync with the Golang\n// counterpart.\nstruct event_t {\n\t// Details about the process being launched.\n\tu8  filename[ARGSIZE];\n\tu8  argv[ARGLEN][ARGSIZE];\n\tu32 argc; // set to ARGLEN + 1 if there were more than ARGLEN arguments\n\tu32 uid;\n\tu32 gid;\n\tu32 pid;\n\n\t// Name of the calling process.\n\tu8  comm[ARGSIZE];\n};\n\n// Tracepoint at the top of execve() syscall.\nSEC(\"tracepoint/syscalls/sys_enter_execve\")\ns32 enter_execve(struct exec_info *ctx) {\n\t// Reserve memory for our event on the `events` ring buffer defined above.\n\tstruct event_t *event;\n\tevent = bpf_ringbuf_reserve(&pm_exec_map, sizeof(struct event_t), 0);\n\tif (!event) {\n\t\tbpf_printk(\"could not reserve ringbuf memory\");\n\n\t\treturn 1;\n\t}\n\n\t// Store process/calling process details.\n\tu64 uidgid = bpf_get_current_uid_gid();\n\tu64 pidtgid = bpf_get_current_pid_tgid();\n\tevent->uid = uidgid;       // uid is the first 32 bits\n\tevent->gid = uidgid >> 32; // gid is the last 32 bits NOLINT(readability-magic-numbers)\n\tevent->pid = pidtgid;      // pid is the first 32 bits\n\ts32 ret = bpf_get_current_comm(&event->comm, sizeof(event->comm));\n\tif (ret) {\n\t\tbpf_printk(\"could not get current comm: %d\", ret);\n\t\tbpf_ringbuf_discard(event, 0);\n\t\treturn 1;\n\t}\n\n\t// Write the filename in addition to argv[0] because the filename contains\n\t// the full path to the file which could be more useful in some situations.\n\tret = bpf_probe_read_user_str(event->filename, sizeof(event->filename), ctx->filename);\n\tif (ret < 0) {\n\t\tbpf_printk(\"could not read filename into event struct: %d\", ret);\n\t\tbpf_ringbuf_discard(event, 0);\n\t\treturn 1;\n\t}\n\n\t// Copy everything from ctx->argv to event->argv, incrementing event->argc\n\t// as we go.\n\tfor (s32 i = 0; i < ARGLEN; i++) {\n\t\tif (!(&ctx->argv[i])) {\n\t\t\tgoto out;\n\t\t}\n\n\t\t// Copying the arg into it's own variable before copying it into\n\t\t// event->argv[i] prevents memory corruption.\n\t\tconst u8 *argp = NULL;\n\t\tret = bpf_probe_read_user(&argp, sizeof(argp), &ctx->argv[i]);\n\t\tif (ret || !argp) {\n\t\t\tgoto out;\n\t\t}\n\n\t\t// Copy argp to event->argv[i].\n\t\tret = bpf_probe_read_user_str(event->argv[i], sizeof(event->argv[i]), argp);\n\t\tif (ret < 0) {\n\t\t\tbpf_printk(\"read argv %d: %d\", i, ret);\n\t\t\tgoto out;\n\t\t}\n\n\t\tevent->argc++;\n\t}\n\n\t// This won't get hit if we `goto out` in the loop above. This is to signify\n\t// to userspace that we couldn't copy all of the arguments because it\n\t// exceeded ARGLEN.\n\tevent->argc++;\n\nout:\n\t// Write the event to the ring buffer and notify userspace. This will cause\n\t// the `Read()` call in userspace to return if it was blocked.\n\tbpf_ringbuf_submit(event, 0);\n\n\treturn 0;\n}"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/monitor.c",
    "content": "#include \"vmlinux-x86.h\"\n#include \"bpf/bpf_helpers.h\"\n#include \"bpf/bpf_tracing.h\"\n\n// IP Version\n#define AF_INET 2\n#define AF_INET6 10\n\n// Protocols\n#define TCP     6\n#define UDP     17\n#define UDPLite 136\n\n#define OUTBOUND 0\n#define INBOUND 1\n\nchar __license[] SEC(\"license\") = \"GPL\";\n\n// Ring buffer for all connection events\nstruct {\n\t__uint(type, BPF_MAP_TYPE_RINGBUF);\n\t__uint(max_entries, 1 << 24);\n} pm_connection_events SEC(\".maps\");\n\n// Event struct that will be sent to Go on each new connection. (The name should be the same as the go generate command)\nstruct Event {\n\tu32 saddr[4];\n\tu32 daddr[4];\n\tu16 sport;\n\tu16 dport;\n\tu32 pid;\n\tu8 ipVersion;\n\tu8 protocol;\n\tu8 direction;\n};\nstruct Event *unused __attribute__((unused));\n\n// Fentry of tcp_connect will be executed when equivalent kernel function is called.\n// In the kernel all IP address and ports should be set before tcp_connect is called. [this-function] -> tcp_connect \nSEC(\"fentry/tcp_connect\")\nint BPF_PROG(tcp_connect, struct sock *sk) {\n\t// Alloc space for the event\n\tstruct Event *tcp_info;\n\ttcp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);\n\tif (!tcp_info) {\n\t\treturn 0;\n\t}\n\n\t// Read PID (Careful: This is the Thread Group ID in kernel speak!)\n\ttcp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));\n\n\t// Set protocol\n\ttcp_info->protocol = TCP;\n\n\t// Set direction\n\ttcp_info->direction = OUTBOUND;\n\n\t// Set src and dist ports\n\ttcp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);\n\ttcp_info->dport = sk->__sk_common.skc_dport;\n\n\t// Set src and dist IPs\n\tif (sk->__sk_common.skc_family == AF_INET) {\n\t\ttcp_info->saddr[0] = __builtin_bswap32(sk->__sk_common.skc_rcv_saddr);\n\t\ttcp_info->daddr[0] = __builtin_bswap32(sk->__sk_common.skc_daddr);\n\t\t// Set IP version\n\t\ttcp_info->ipVersion = 4;\n\t} else if (sk->__sk_common.skc_family == AF_INET6) {\n\t\tfor(int i = 0; i < 4; i++) {\n\t\t\ttcp_info->saddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[i]);\n\t\t}\n\t\tfor(int i = 0; i < 4; i++) {\n\t\t\ttcp_info->daddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[i]);\n\t\t}\n\t\t// Set IP version\n\t\ttcp_info->ipVersion = 6;\n\t}\n\n\t// Send event\n\tbpf_ringbuf_submit(tcp_info, 0);\n\treturn 0;\n};\n\n// Fexit(function exit) of `udp_v4_connect` will be executed after the `udp_connect` kernel function is called.\n//\n// Kernel compatibility note:\n// - Linux kernels < 6.13: use `ip4_datagram_connect` function \n//   https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997\n// - Linux kernels >= 6.13: function renamed to `udp_connect` \n//   https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131\n//\nSEC(\"fexit/udp_connect\") // Note: This attach point name may be overwritten (see worker.go: modifyProgramsAttachPoints())\nint BPF_PROG(udp_v4_connect, struct sock *sk) {\n\t// Ignore everything else then IPv4\n\tif (sk->__sk_common.skc_family != AF_INET) {\n\t\treturn 0;\n\t}\n\n\t// ip4_datagram_connect return error\n\tif (sk->__sk_common.skc_dport == 0) {\n\t\treturn 0;\n\t}\n\n\t// Allocate space for the event.\n\tstruct Event *udp_info;\n\tudp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);\n\tif (!udp_info) {\n\t\treturn 0;\n\t}\n\n\t// Read PID (Careful: This is the Thread Group ID in kernel speak!)\n\tudp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));\n\n\t// Set src and dst ports\n\tudp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);\n\tudp_info->dport = sk->__sk_common.skc_dport;\n\n\t// Set src and dst IPs\n\tudp_info->saddr[0] = __builtin_bswap32(sk->__sk_common.skc_rcv_saddr);\n\tudp_info->daddr[0] = __builtin_bswap32(sk->__sk_common.skc_daddr);\n\n\t// Set IP version\n\tudp_info->ipVersion = 4;\n\n\t// Set protocol\n\tif(sk->sk_protocol == IPPROTO_UDPLITE) {\n\t\tudp_info->protocol = UDPLite;\n\t} else {\n\t\tudp_info->protocol = UDP;\n\t}\n\n\t// Send event\n\tbpf_ringbuf_submit(udp_info, 0);\n\treturn 0;\n}\n\n// Fentry(function enter) of `udp_v6_connect` will be executed after the `udpv6_connect` kernel function is called.\n//\n// Kernel compatibility note:\n// - Linux kernels < 6.13: use `ip6_datagram_connect` function \n//   https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997\n// - Linux kernels >= 6.13: function renamed to `udpv6_connect` \n//   https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131\n//\nSEC(\"fexit/udpv6_connect\") // Note: This attach point name may be overwritten (see worker.go: modifyProgramsAttachPoints())\nint BPF_PROG(udp_v6_connect, struct sock *sk) {\n\t// Ignore everything else then IPv6\n\tif (sk->__sk_common.skc_family != AF_INET6) {\n\t\treturn 0;\n\t}\n\n\t// ip6_datagram_connect return error\n\tif (sk->__sk_common.skc_dport == 0) {\n\t\treturn 0;\n\t}\n\n\t// Make sure its udp6 socket\n\tstruct udp6_sock *us = bpf_skc_to_udp6_sock(sk);\n\tif (!us) {\n\t\treturn 0;\n\t}\n\n\t// Allocate space for the event.\n\tstruct Event *udp_info;\n\tudp_info = bpf_ringbuf_reserve(&pm_connection_events, sizeof(struct Event), 0);\n\tif (!udp_info) {\n\t\treturn 0;\n\t}\n\n\t// Read PID (Careful: This is the Thread Group ID in kernel speak!)\n\tudp_info->pid = __builtin_bswap32((u32)(bpf_get_current_pid_tgid() >> 32));\n\n\t// Set src and dst ports\n\tudp_info->sport = __builtin_bswap16(sk->__sk_common.skc_num);\n\tudp_info->dport = sk->__sk_common.skc_dport;\n\n\t// Set src and dst IPs\n\tfor(int i = 0; i < 4; i++) {\n\t\tudp_info->saddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[i]);\n\t}\n\tfor(int i = 0; i < 4; i++) {\n\t\tudp_info->daddr[i] = __builtin_bswap32(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[i]);\n\t}\n\n\t// IP version\n\tudp_info->ipVersion = 6;\n\n\t// Set protocol\n\tif(sk->sk_protocol == IPPROTO_UDPLITE) {\n\t\tudp_info->protocol = UDPLite;\n\t} else {\n\t\tudp_info->protocol = UDP;\n\t}\n\n\t// Send event\n\tbpf_ringbuf_submit(udp_info, 0);\n\treturn 0;\n}"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/update.sh",
    "content": "#!/usr/bin/env bash\n\n# Version of libbpf to fetch headers from\nLIBBPF_VERSION=1.2.0\n\n# The headers we want\nprefix=libbpf-\"$LIBBPF_VERSION\"\nheaders=(\n    \"$prefix\"/src/bpf_core_read.h\n    \"$prefix\"/src/bpf_helper_defs.h\n    \"$prefix\"/src/bpf_helpers.h\n    \"$prefix\"/src/bpf_tracing.h\n)\n\n# Fetch libbpf release and extract the desired headers\ncurl -sL \"https://github.com/libbpf/libbpf/archive/refs/tags/v${LIBBPF_VERSION}.tar.gz\" | \\\n    tar -xz --xform='s#.*/#bpf/#' \"${headers[@]}\"\n\n# To generate the vmlinux header file\n# See \"Export kernel information\" at https://docs.ebpf.io/concepts/core/btf\n#\n#   bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux-x86.h\n"
  },
  {
    "path": "service/firewall/interception/ebpf/programs/vmlinux-x86.h",
    "content": "#ifndef __VMLINUX_H__\n#define __VMLINUX_H__\n\n#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n#endif\n\ntypedef unsigned char __u8;\n\ntypedef short int __s16;\n\ntypedef short unsigned int __u16;\n\ntypedef int __s32;\n\ntypedef unsigned int __u32;\n\ntypedef long long int __s64;\n\ntypedef long long unsigned int __u64;\n\ntypedef __u8 u8;\n\ntypedef __s16 s16;\n\ntypedef __u16 u16;\n\ntypedef __s32 s32;\n\ntypedef __u32 u32;\n\ntypedef __s64 s64;\n\ntypedef __u64 u64;\n\nenum {\n\tfalse = 0,\n\ttrue = 1,\n};\n\ntypedef long int __kernel_long_t;\n\ntypedef long unsigned int __kernel_ulong_t;\n\ntypedef int __kernel_pid_t;\n\ntypedef unsigned int __kernel_uid32_t;\n\ntypedef unsigned int __kernel_gid32_t;\n\ntypedef __kernel_ulong_t __kernel_size_t;\n\ntypedef __kernel_long_t __kernel_ssize_t;\n\ntypedef long long int __kernel_loff_t;\n\ntypedef long long int __kernel_time64_t;\n\ntypedef __kernel_long_t __kernel_clock_t;\n\ntypedef int __kernel_timer_t;\n\ntypedef int __kernel_clockid_t;\n\ntypedef unsigned int __poll_t;\n\ntypedef u32 __kernel_dev_t;\n\ntypedef __kernel_dev_t dev_t;\n\ntypedef short unsigned int umode_t;\n\ntypedef __kernel_pid_t pid_t;\n\ntypedef __kernel_clockid_t clockid_t;\n\ntypedef _Bool bool;\n\ntypedef __kernel_uid32_t uid_t;\n\ntypedef __kernel_gid32_t gid_t;\n\ntypedef __kernel_loff_t loff_t;\n\ntypedef __kernel_size_t size_t;\n\ntypedef __kernel_ssize_t ssize_t;\n\ntypedef s32 int32_t;\n\ntypedef u32 uint32_t;\n\ntypedef u64 sector_t;\n\ntypedef u64 blkcnt_t;\n\ntypedef unsigned int gfp_t;\n\ntypedef unsigned int fmode_t;\n\ntypedef u64 phys_addr_t;\n\ntypedef struct {\n\tint counter;\n} atomic_t;\n\ntypedef struct {\n\ts64 counter;\n} atomic64_t;\n\nstruct list_head {\n\tstruct list_head *next;\n\tstruct list_head *prev;\n};\n\nstruct hlist_node;\n\nstruct hlist_head {\n\tstruct hlist_node *first;\n};\n\nstruct hlist_node {\n\tstruct hlist_node *next;\n\tstruct hlist_node **pprev;\n};\n\nstruct callback_head {\n\tstruct callback_head *next;\n\tvoid (*func)(struct callback_head *);\n};\n\nstruct lock_class_key {};\n\nstruct fs_context;\n\nstruct fs_parameter_spec;\n\nstruct dentry;\n\nstruct super_block;\n\nstruct module;\n\nstruct file_system_type {\n\tconst char *name;\n\tint fs_flags;\n\tint (*init_fs_context)(struct fs_context *);\n\tconst struct fs_parameter_spec *parameters;\n\tstruct dentry * (*mount)(struct file_system_type *, int, const char *, void *);\n\tvoid (*kill_sb)(struct super_block *);\n\tstruct module *owner;\n\tstruct file_system_type *next;\n\tstruct hlist_head fs_supers;\n\tstruct lock_class_key s_lock_key;\n\tstruct lock_class_key s_umount_key;\n\tstruct lock_class_key s_vfs_rename_key;\n\tstruct lock_class_key s_writers_key[3];\n\tstruct lock_class_key i_lock_key;\n\tstruct lock_class_key i_mutex_key;\n\tstruct lock_class_key i_mutex_dir_key;\n};\n\nstruct qspinlock {\n\tunion {\n\t\tatomic_t val;\n\t\tstruct {\n\t\t\tu8 locked;\n\t\t\tu8 pending;\n\t\t};\n\t\tstruct {\n\t\t\tu16 locked_pending;\n\t\t\tu16 tail;\n\t\t};\n\t};\n};\n\ntypedef struct qspinlock arch_spinlock_t;\n\nstruct qrwlock {\n\tunion {\n\t\tatomic_t cnts;\n\t\tstruct {\n\t\t\tu8 wlocked;\n\t\t\tu8 __lstate[3];\n\t\t};\n\t};\n\tarch_spinlock_t wait_lock;\n};\n\ntypedef struct qrwlock arch_rwlock_t;\n\nstruct raw_spinlock {\n\tarch_spinlock_t raw_lock;\n};\n\ntypedef struct raw_spinlock raw_spinlock_t;\n\nstruct spinlock {\n\tunion {\n\t\tstruct raw_spinlock rlock;\n\t};\n};\n\ntypedef struct spinlock spinlock_t;\n\ntypedef struct {\n\tarch_rwlock_t raw_lock;\n} rwlock_t;\n\nstruct ratelimit_state {\n\traw_spinlock_t lock;\n\tint interval;\n\tint burst;\n\tint printed;\n\tint missed;\n\tlong unsigned int begin;\n\tlong unsigned int flags;\n};\n\ntypedef void *fl_owner_t;\n\nstruct file;\n\nstruct kiocb;\n\nstruct iov_iter;\n\nstruct dir_context;\n\nstruct poll_table_struct;\n\nstruct vm_area_struct;\n\nstruct inode;\n\nstruct file_lock;\n\nstruct page;\n\nstruct pipe_inode_info;\n\nstruct seq_file;\n\nstruct file_operations {\n\tstruct module *owner;\n\tloff_t (*llseek)(struct file *, loff_t, int);\n\tssize_t (*read)(struct file *, char *, size_t, loff_t *);\n\tssize_t (*write)(struct file *, const char *, size_t, loff_t *);\n\tssize_t (*read_iter)(struct kiocb *, struct iov_iter *);\n\tssize_t (*write_iter)(struct kiocb *, struct iov_iter *);\n\tint (*iopoll)(struct kiocb *, bool);\n\tint (*iterate)(struct file *, struct dir_context *);\n\tint (*iterate_shared)(struct file *, struct dir_context *);\n\t__poll_t (*poll)(struct file *, struct poll_table_struct *);\n\tlong int (*unlocked_ioctl)(struct file *, unsigned int, long unsigned int);\n\tlong int (*compat_ioctl)(struct file *, unsigned int, long unsigned int);\n\tint (*mmap)(struct file *, struct vm_area_struct *);\n\tlong unsigned int mmap_supported_flags;\n\tint (*open)(struct inode *, struct file *);\n\tint (*flush)(struct file *, fl_owner_t);\n\tint (*release)(struct inode *, struct file *);\n\tint (*fsync)(struct file *, loff_t, loff_t, int);\n\tint (*fasync)(int, struct file *, int);\n\tint (*lock)(struct file *, int, struct file_lock *);\n\tssize_t (*sendpage)(struct file *, struct page *, int, size_t, loff_t *, int);\n\tlong unsigned int (*get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int);\n\tint (*check_flags)(int);\n\tint (*flock)(struct file *, int, struct file_lock *);\n\tssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);\n\tssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);\n\tint (*setlease)(struct file *, long int, struct file_lock **, void **);\n\tlong int (*fallocate)(struct file *, int, loff_t, loff_t);\n\tvoid (*show_fdinfo)(struct seq_file *, struct file *);\n\tssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int);\n\tloff_t (*remap_file_range)(struct file *, loff_t, struct file *, loff_t, loff_t, unsigned int);\n\tint (*fadvise)(struct file *, loff_t, loff_t, int);\n};\n\ntypedef __s64 time64_t;\n\nstruct __kernel_timespec {\n\t__kernel_time64_t tv_sec;\n\tlong long int tv_nsec;\n};\n\nstruct timespec64 {\n\ttime64_t tv_sec;\n\tlong int tv_nsec;\n};\n\nenum timespec_type {\n\tTT_NONE = 0,\n\tTT_NATIVE = 1,\n\tTT_COMPAT = 2,\n};\n\ntypedef s32 old_time32_t;\n\nstruct old_timespec32 {\n\told_time32_t tv_sec;\n\ts32 tv_nsec;\n};\n\nstruct pollfd;\n\nstruct restart_block {\n\tlong unsigned int arch_data;\n\tlong int (*fn)(struct restart_block *);\n\tunion {\n\t\tstruct {\n\t\t\tu32 *uaddr;\n\t\t\tu32 val;\n\t\t\tu32 flags;\n\t\t\tu32 bitset;\n\t\t\tu64 time;\n\t\t\tu32 *uaddr2;\n\t\t} futex;\n\t\tstruct {\n\t\t\tclockid_t clockid;\n\t\t\tenum timespec_type type;\n\t\t\tunion {\n\t\t\t\tstruct __kernel_timespec *rmtp;\n\t\t\t\tstruct old_timespec32 *compat_rmtp;\n\t\t\t};\n\t\t\tu64 expires;\n\t\t} nanosleep;\n\t\tstruct {\n\t\t\tstruct pollfd *ufds;\n\t\t\tint nfds;\n\t\t\tint has_timeout;\n\t\t\tlong unsigned int tv_sec;\n\t\t\tlong unsigned int tv_nsec;\n\t\t} poll;\n\t};\n};\n\nstruct thread_info {\n\tlong unsigned int flags;\n\tlong unsigned int syscall_work;\n\tu32 status;\n};\n\nstruct refcount_struct {\n\tatomic_t refs;\n};\n\ntypedef struct refcount_struct refcount_t;\n\nstruct llist_node {\n\tstruct llist_node *next;\n};\n\nstruct __call_single_node {\n\tstruct llist_node llist;\n\tunion {\n\t\tunsigned int u_flags;\n\t\tatomic_t a_flags;\n\t};\n\tu16 src;\n\tu16 dst;\n};\n\nstruct load_weight {\n\tlong unsigned int weight;\n\tu32 inv_weight;\n};\n\nstruct rb_node {\n\tlong unsigned int __rb_parent_color;\n\tstruct rb_node *rb_right;\n\tstruct rb_node *rb_left;\n};\n\nstruct sched_statistics {\n\tu64 wait_start;\n\tu64 wait_max;\n\tu64 wait_count;\n\tu64 wait_sum;\n\tu64 iowait_count;\n\tu64 iowait_sum;\n\tu64 sleep_start;\n\tu64 sleep_max;\n\ts64 sum_sleep_runtime;\n\tu64 block_start;\n\tu64 block_max;\n\tu64 exec_max;\n\tu64 slice_max;\n\tu64 nr_migrations_cold;\n\tu64 nr_failed_migrations_affine;\n\tu64 nr_failed_migrations_running;\n\tu64 nr_failed_migrations_hot;\n\tu64 nr_forced_migrations;\n\tu64 nr_wakeups;\n\tu64 nr_wakeups_sync;\n\tu64 nr_wakeups_migrate;\n\tu64 nr_wakeups_local;\n\tu64 nr_wakeups_remote;\n\tu64 nr_wakeups_affine;\n\tu64 nr_wakeups_affine_attempts;\n\tu64 nr_wakeups_passive;\n\tu64 nr_wakeups_idle;\n};\n\nstruct util_est {\n\tunsigned int enqueued;\n\tunsigned int ewma;\n};\n\nstruct sched_avg {\n\tu64 last_update_time;\n\tu64 load_sum;\n\tu64 runnable_sum;\n\tu32 util_sum;\n\tu32 period_contrib;\n\tlong unsigned int load_avg;\n\tlong unsigned int runnable_avg;\n\tlong unsigned int util_avg;\n\tstruct util_est util_est;\n};\n\nstruct cfs_rq;\n\nstruct sched_entity {\n\tstruct load_weight load;\n\tstruct rb_node run_node;\n\tstruct list_head group_node;\n\tunsigned int on_rq;\n\tu64 exec_start;\n\tu64 sum_exec_runtime;\n\tu64 vruntime;\n\tu64 prev_sum_exec_runtime;\n\tu64 nr_migrations;\n\tstruct sched_statistics statistics;\n\tint depth;\n\tstruct sched_entity *parent;\n\tstruct cfs_rq *cfs_rq;\n\tstruct cfs_rq *my_q;\n\tlong unsigned int runnable_weight;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct sched_avg avg;\n};\n\nstruct sched_rt_entity {\n\tstruct list_head run_list;\n\tlong unsigned int timeout;\n\tlong unsigned int watchdog_stamp;\n\tunsigned int time_slice;\n\tshort unsigned int on_rq;\n\tshort unsigned int on_list;\n\tstruct sched_rt_entity *back;\n};\n\ntypedef s64 ktime_t;\n\nstruct timerqueue_node {\n\tstruct rb_node node;\n\tktime_t expires;\n};\n\nenum hrtimer_restart {\n\tHRTIMER_NORESTART = 0,\n\tHRTIMER_RESTART = 1,\n};\n\nstruct hrtimer_clock_base;\n\nstruct hrtimer {\n\tstruct timerqueue_node node;\n\tktime_t _softexpires;\n\tenum hrtimer_restart (*function)(struct hrtimer *);\n\tstruct hrtimer_clock_base *base;\n\tu8 state;\n\tu8 is_rel;\n\tu8 is_soft;\n\tu8 is_hard;\n};\n\nstruct sched_dl_entity {\n\tstruct rb_node rb_node;\n\tu64 dl_runtime;\n\tu64 dl_deadline;\n\tu64 dl_period;\n\tu64 dl_bw;\n\tu64 dl_density;\n\ts64 runtime;\n\tu64 deadline;\n\tunsigned int flags;\n\tunsigned int dl_throttled: 1;\n\tunsigned int dl_yielded: 1;\n\tunsigned int dl_non_contending: 1;\n\tunsigned int dl_overrun: 1;\n\tstruct hrtimer dl_timer;\n\tstruct hrtimer inactive_timer;\n\tstruct sched_dl_entity *pi_se;\n};\n\nstruct uclamp_se {\n\tunsigned int value: 11;\n\tunsigned int bucket_id: 3;\n\tunsigned int active: 1;\n\tunsigned int user_defined: 1;\n};\n\nstruct cpumask {\n\tlong unsigned int bits[5];\n};\n\ntypedef struct cpumask cpumask_t;\n\nunion rcu_special {\n\tstruct {\n\t\tu8 blocked;\n\t\tu8 need_qs;\n\t\tu8 exp_hint;\n\t\tu8 need_mb;\n\t} b;\n\tu32 s;\n};\n\nstruct sched_info {\n\tlong unsigned int pcount;\n\tlong long unsigned int run_delay;\n\tlong long unsigned int last_arrival;\n\tlong long unsigned int last_queued;\n};\n\nstruct plist_node {\n\tint prio;\n\tstruct list_head prio_list;\n\tstruct list_head node_list;\n};\n\nstruct vmacache {\n\tu64 seqnum;\n\tstruct vm_area_struct *vmas[4];\n};\n\nstruct task_rss_stat {\n\tint events;\n\tint count[4];\n};\n\nstruct prev_cputime {\n\tu64 utime;\n\tu64 stime;\n\traw_spinlock_t lock;\n};\n\nstruct rb_root {\n\tstruct rb_node *rb_node;\n};\n\nstruct rb_root_cached {\n\tstruct rb_root rb_root;\n\tstruct rb_node *rb_leftmost;\n};\n\nstruct timerqueue_head {\n\tstruct rb_root_cached rb_root;\n};\n\nstruct posix_cputimer_base {\n\tu64 nextevt;\n\tstruct timerqueue_head tqhead;\n};\n\nstruct posix_cputimers {\n\tstruct posix_cputimer_base bases[3];\n\tunsigned int timers_active;\n\tunsigned int expiry_active;\n};\n\nstruct posix_cputimers_work {\n\tstruct callback_head work;\n\tunsigned int scheduled;\n};\n\nstruct sem_undo_list;\n\nstruct sysv_sem {\n\tstruct sem_undo_list *undo_list;\n};\n\nstruct sysv_shm {\n\tstruct list_head shm_clist;\n};\n\ntypedef struct {\n\tlong unsigned int sig[1];\n} sigset_t;\n\nstruct sigpending {\n\tstruct list_head list;\n\tsigset_t signal;\n};\n\ntypedef struct {\n\tuid_t val;\n} kuid_t;\n\nstruct seccomp_filter;\n\nstruct seccomp {\n\tint mode;\n\tatomic_t filter_count;\n\tstruct seccomp_filter *filter;\n};\n\nstruct syscall_user_dispatch {\n\tchar *selector;\n\tlong unsigned int offset;\n\tlong unsigned int len;\n\tbool on_dispatch;\n};\n\nstruct wake_q_node {\n\tstruct wake_q_node *next;\n};\n\nstruct task_io_accounting {\n\tu64 rchar;\n\tu64 wchar;\n\tu64 syscr;\n\tu64 syscw;\n\tu64 read_bytes;\n\tu64 write_bytes;\n\tu64 cancelled_write_bytes;\n};\n\ntypedef struct {\n\tlong unsigned int bits[1];\n} nodemask_t;\n\nstruct seqcount {\n\tunsigned int sequence;\n};\n\ntypedef struct seqcount seqcount_t;\n\nstruct seqcount_spinlock {\n\tseqcount_t seqcount;\n};\n\ntypedef struct seqcount_spinlock seqcount_spinlock_t;\n\ntypedef atomic64_t atomic_long_t;\n\nstruct optimistic_spin_queue {\n\tatomic_t tail;\n};\n\nstruct mutex {\n\tatomic_long_t owner;\n\tspinlock_t wait_lock;\n\tstruct optimistic_spin_queue osq;\n\tstruct list_head wait_list;\n};\n\nstruct arch_tlbflush_unmap_batch {\n\tstruct cpumask cpumask;\n};\n\nstruct tlbflush_unmap_batch {\n\tstruct arch_tlbflush_unmap_batch arch;\n\tbool flush_required;\n\tbool writable;\n};\n\nstruct page_frag {\n\tstruct page *page;\n\t__u32 offset;\n\t__u32 size;\n};\n\nstruct latency_record {\n\tlong unsigned int backtrace[12];\n\tunsigned int count;\n\tlong unsigned int time;\n\tlong unsigned int max;\n};\n\nstruct kmap_ctrl {};\n\nstruct llist_head {\n\tstruct llist_node *first;\n};\n\nstruct desc_struct {\n\tu16 limit0;\n\tu16 base0;\n\tu16 base1: 8;\n\tu16 type: 4;\n\tu16 s: 1;\n\tu16 dpl: 2;\n\tu16 p: 1;\n\tu16 limit1: 4;\n\tu16 avl: 1;\n\tu16 l: 1;\n\tu16 d: 1;\n\tu16 g: 1;\n\tu16 base2: 8;\n};\n\nstruct fregs_state {\n\tu32 cwd;\n\tu32 swd;\n\tu32 twd;\n\tu32 fip;\n\tu32 fcs;\n\tu32 foo;\n\tu32 fos;\n\tu32 st_space[20];\n\tu32 status;\n};\n\nstruct fxregs_state {\n\tu16 cwd;\n\tu16 swd;\n\tu16 twd;\n\tu16 fop;\n\tunion {\n\t\tstruct {\n\t\t\tu64 rip;\n\t\t\tu64 rdp;\n\t\t};\n\t\tstruct {\n\t\t\tu32 fip;\n\t\t\tu32 fcs;\n\t\t\tu32 foo;\n\t\t\tu32 fos;\n\t\t};\n\t};\n\tu32 mxcsr;\n\tu32 mxcsr_mask;\n\tu32 st_space[32];\n\tu32 xmm_space[64];\n\tu32 padding[12];\n\tunion {\n\t\tu32 padding1[12];\n\t\tu32 sw_reserved[12];\n\t};\n};\n\nstruct math_emu_info;\n\nstruct swregs_state {\n\tu32 cwd;\n\tu32 swd;\n\tu32 twd;\n\tu32 fip;\n\tu32 fcs;\n\tu32 foo;\n\tu32 fos;\n\tu32 st_space[20];\n\tu8 ftop;\n\tu8 changed;\n\tu8 lookahead;\n\tu8 no_update;\n\tu8 rm;\n\tu8 alimit;\n\tstruct math_emu_info *info;\n\tu32 entry_eip;\n};\n\nstruct xstate_header {\n\tu64 xfeatures;\n\tu64 xcomp_bv;\n\tu64 reserved[6];\n};\n\nstruct xregs_state {\n\tstruct fxregs_state i387;\n\tstruct xstate_header header;\n\tu8 extended_state_area[0];\n};\n\nunion fpregs_state {\n\tstruct fregs_state fsave;\n\tstruct fxregs_state fxsave;\n\tstruct swregs_state soft;\n\tstruct xregs_state xsave;\n\tu8 __padding[4096];\n};\n\nstruct fpu {\n\tunsigned int last_cpu;\n\tlong unsigned int avx512_timestamp;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tunion fpregs_state state;\n};\n\nstruct perf_event;\n\nstruct io_bitmap;\n\nstruct thread_struct {\n\tstruct desc_struct tls_array[3];\n\tlong unsigned int sp;\n\tshort unsigned int es;\n\tshort unsigned int ds;\n\tshort unsigned int fsindex;\n\tshort unsigned int gsindex;\n\tlong unsigned int fsbase;\n\tlong unsigned int gsbase;\n\tstruct perf_event *ptrace_bps[4];\n\tlong unsigned int virtual_dr6;\n\tlong unsigned int ptrace_dr7;\n\tlong unsigned int cr2;\n\tlong unsigned int trap_nr;\n\tlong unsigned int error_code;\n\tstruct io_bitmap *io_bitmap;\n\tlong unsigned int iopl_emul;\n\tunsigned int sig_on_uaccess_err: 1;\n\tu32 pkru;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct fpu fpu;\n};\n\nstruct sched_class;\n\nstruct task_group;\n\nstruct rcu_node;\n\nstruct mm_struct;\n\nstruct pid;\n\nstruct completion;\n\nstruct cred;\n\nstruct key;\n\nstruct nameidata;\n\nstruct fs_struct;\n\nstruct files_struct;\n\nstruct io_uring_task;\n\nstruct nsproxy;\n\nstruct signal_struct;\n\nstruct sighand_struct;\n\nstruct audit_context;\n\nstruct rt_mutex_waiter;\n\nstruct bio_list;\n\nstruct blk_plug;\n\nstruct reclaim_state;\n\nstruct backing_dev_info;\n\nstruct io_context;\n\nstruct capture_control;\n\nstruct kernel_siginfo;\n\ntypedef struct kernel_siginfo kernel_siginfo_t;\n\nstruct css_set;\n\nstruct robust_list_head;\n\nstruct compat_robust_list_head;\n\nstruct futex_pi_state;\n\nstruct perf_event_context;\n\nstruct mempolicy;\n\nstruct numa_group;\n\nstruct rseq;\n\nstruct task_delay_info;\n\nstruct ftrace_ret_stack;\n\nstruct mem_cgroup;\n\nstruct request_queue;\n\nstruct uprobe_task;\n\nstruct vm_struct;\n\nstruct bpf_local_storage;\n\nstruct task_struct {\n\tstruct thread_info thread_info;\n\tunsigned int __state;\n\tvoid *stack;\n\trefcount_t usage;\n\tunsigned int flags;\n\tunsigned int ptrace;\n\tint on_cpu;\n\tstruct __call_single_node wake_entry;\n\tunsigned int cpu;\n\tunsigned int wakee_flips;\n\tlong unsigned int wakee_flip_decay_ts;\n\tstruct task_struct *last_wakee;\n\tint recent_used_cpu;\n\tint wake_cpu;\n\tint on_rq;\n\tint prio;\n\tint static_prio;\n\tint normal_prio;\n\tunsigned int rt_priority;\n\tconst struct sched_class *sched_class;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct sched_entity se;\n\tstruct sched_rt_entity rt;\n\tstruct sched_dl_entity dl;\n\tstruct rb_node core_node;\n\tlong unsigned int core_cookie;\n\tunsigned int core_occupation;\n\tstruct task_group *sched_task_group;\n\tstruct uclamp_se uclamp_req[2];\n\tstruct uclamp_se uclamp[2];\n\tstruct hlist_head preempt_notifiers;\n\tunsigned int btrace_seq;\n\tunsigned int policy;\n\tint nr_cpus_allowed;\n\tconst cpumask_t *cpus_ptr;\n\tcpumask_t cpus_mask;\n\tvoid *migration_pending;\n\tshort unsigned int migration_disabled;\n\tshort unsigned int migration_flags;\n\tint rcu_read_lock_nesting;\n\tunion rcu_special rcu_read_unlock_special;\n\tstruct list_head rcu_node_entry;\n\tstruct rcu_node *rcu_blocked_node;\n\tlong unsigned int rcu_tasks_nvcsw;\n\tu8 rcu_tasks_holdout;\n\tu8 rcu_tasks_idx;\n\tint rcu_tasks_idle_cpu;\n\tstruct list_head rcu_tasks_holdout_list;\n\tint trc_reader_nesting;\n\tint trc_ipi_to_cpu;\n\tunion rcu_special trc_reader_special;\n\tbool trc_reader_checked;\n\tstruct list_head trc_holdout_list;\n\tstruct sched_info sched_info;\n\tstruct list_head tasks;\n\tstruct plist_node pushable_tasks;\n\tstruct rb_node pushable_dl_tasks;\n\tstruct mm_struct *mm;\n\tstruct mm_struct *active_mm;\n\tstruct vmacache vmacache;\n\tstruct task_rss_stat rss_stat;\n\tint exit_state;\n\tint exit_code;\n\tint exit_signal;\n\tint pdeath_signal;\n\tlong unsigned int jobctl;\n\tunsigned int personality;\n\tunsigned int sched_reset_on_fork: 1;\n\tunsigned int sched_contributes_to_load: 1;\n\tunsigned int sched_migrated: 1;\n\tunsigned int sched_psi_wake_requeue: 1;\n\tint: 28;\n\tunsigned int sched_remote_wakeup: 1;\n\tunsigned int in_execve: 1;\n\tunsigned int in_iowait: 1;\n\tunsigned int restore_sigmask: 1;\n\tunsigned int in_user_fault: 1;\n\tunsigned int no_cgroup_migration: 1;\n\tunsigned int frozen: 1;\n\tunsigned int use_memdelay: 1;\n\tunsigned int in_memstall: 1;\n\tlong unsigned int atomic_flags;\n\tstruct restart_block restart_block;\n\tpid_t pid;\n\tpid_t tgid;\n\tlong unsigned int stack_canary;\n\tstruct task_struct *real_parent;\n\tstruct task_struct *parent;\n\tstruct list_head children;\n\tstruct list_head sibling;\n\tstruct task_struct *group_leader;\n\tstruct list_head ptraced;\n\tstruct list_head ptrace_entry;\n\tstruct pid *thread_pid;\n\tstruct hlist_node pid_links[4];\n\tstruct list_head thread_group;\n\tstruct list_head thread_node;\n\tstruct completion *vfork_done;\n\tint *set_child_tid;\n\tint *clear_child_tid;\n\tvoid *pf_io_worker;\n\tu64 utime;\n\tu64 stime;\n\tu64 gtime;\n\tstruct prev_cputime prev_cputime;\n\tlong unsigned int nvcsw;\n\tlong unsigned int nivcsw;\n\tu64 start_time;\n\tu64 start_boottime;\n\tlong unsigned int min_flt;\n\tlong unsigned int maj_flt;\n\tstruct posix_cputimers posix_cputimers;\n\tstruct posix_cputimers_work posix_cputimers_work;\n\tconst struct cred *ptracer_cred;\n\tconst struct cred *real_cred;\n\tconst struct cred *cred;\n\tstruct key *cached_requested_key;\n\tchar comm[16];\n\tstruct nameidata *nameidata;\n\tstruct sysv_sem sysvsem;\n\tstruct sysv_shm sysvshm;\n\tlong unsigned int last_switch_count;\n\tlong unsigned int last_switch_time;\n\tstruct fs_struct *fs;\n\tstruct files_struct *files;\n\tstruct io_uring_task *io_uring;\n\tstruct nsproxy *nsproxy;\n\tstruct signal_struct *signal;\n\tstruct sighand_struct *sighand;\n\tsigset_t blocked;\n\tsigset_t real_blocked;\n\tsigset_t saved_sigmask;\n\tstruct sigpending pending;\n\tlong unsigned int sas_ss_sp;\n\tsize_t sas_ss_size;\n\tunsigned int sas_ss_flags;\n\tstruct callback_head *task_works;\n\tstruct audit_context *audit_context;\n\tkuid_t loginuid;\n\tunsigned int sessionid;\n\tstruct seccomp seccomp;\n\tstruct syscall_user_dispatch syscall_dispatch;\n\tu64 parent_exec_id;\n\tu64 self_exec_id;\n\tspinlock_t alloc_lock;\n\traw_spinlock_t pi_lock;\n\tstruct wake_q_node wake_q;\n\tstruct rb_root_cached pi_waiters;\n\tstruct task_struct *pi_top_task;\n\tstruct rt_mutex_waiter *pi_blocked_on;\n\tvoid *journal_info;\n\tstruct bio_list *bio_list;\n\tstruct blk_plug *plug;\n\tstruct reclaim_state *reclaim_state;\n\tstruct backing_dev_info *backing_dev_info;\n\tstruct io_context *io_context;\n\tstruct capture_control *capture_control;\n\tlong unsigned int ptrace_message;\n\tkernel_siginfo_t *last_siginfo;\n\tstruct task_io_accounting ioac;\n\tunsigned int psi_flags;\n\tu64 acct_rss_mem1;\n\tu64 acct_vm_mem1;\n\tu64 acct_timexpd;\n\tnodemask_t mems_allowed;\n\tseqcount_spinlock_t mems_allowed_seq;\n\tint cpuset_mem_spread_rotor;\n\tint cpuset_slab_spread_rotor;\n\tstruct css_set *cgroups;\n\tstruct list_head cg_list;\n\tu32 closid;\n\tu32 rmid;\n\tstruct robust_list_head *robust_list;\n\tstruct compat_robust_list_head *compat_robust_list;\n\tstruct list_head pi_state_list;\n\tstruct futex_pi_state *pi_state_cache;\n\tstruct mutex futex_exit_mutex;\n\tunsigned int futex_state;\n\tstruct perf_event_context *perf_event_ctxp[2];\n\tstruct mutex perf_event_mutex;\n\tstruct list_head perf_event_list;\n\tstruct mempolicy *mempolicy;\n\tshort int il_prev;\n\tshort int pref_node_fork;\n\tint numa_scan_seq;\n\tunsigned int numa_scan_period;\n\tunsigned int numa_scan_period_max;\n\tint numa_preferred_nid;\n\tlong unsigned int numa_migrate_retry;\n\tu64 node_stamp;\n\tu64 last_task_numa_placement;\n\tu64 last_sum_exec_runtime;\n\tstruct callback_head numa_work;\n\tstruct numa_group *numa_group;\n\tlong unsigned int *numa_faults;\n\tlong unsigned int total_numa_faults;\n\tlong unsigned int numa_faults_locality[3];\n\tlong unsigned int numa_pages_migrated;\n\tstruct rseq *rseq;\n\tu32 rseq_sig;\n\tlong unsigned int rseq_event_mask;\n\tstruct tlbflush_unmap_batch tlb_ubc;\n\tunion {\n\t\trefcount_t rcu_users;\n\t\tstruct callback_head rcu;\n\t};\n\tstruct pipe_inode_info *splice_pipe;\n\tstruct page_frag task_frag;\n\tstruct task_delay_info *delays;\n\tint nr_dirtied;\n\tint nr_dirtied_pause;\n\tlong unsigned int dirty_paused_when;\n\tint latency_record_count;\n\tstruct latency_record latency_record[32];\n\tu64 timer_slack_ns;\n\tu64 default_timer_slack_ns;\n\tint curr_ret_stack;\n\tint curr_ret_depth;\n\tstruct ftrace_ret_stack *ret_stack;\n\tlong long unsigned int ftrace_timestamp;\n\tatomic_t trace_overrun;\n\tatomic_t tracing_graph_pause;\n\tlong unsigned int trace;\n\tlong unsigned int trace_recursion;\n\tstruct mem_cgroup *memcg_in_oom;\n\tgfp_t memcg_oom_gfp_mask;\n\tint memcg_oom_order;\n\tunsigned int memcg_nr_pages_over_high;\n\tstruct mem_cgroup *active_memcg;\n\tstruct request_queue *throttle_queue;\n\tstruct uprobe_task *utask;\n\tunsigned int sequential_io;\n\tunsigned int sequential_io_avg;\n\tstruct kmap_ctrl kmap_ctrl;\n\tint pagefault_disabled;\n\tstruct task_struct *oom_reaper_list;\n\tstruct vm_struct *stack_vm_area;\n\trefcount_t stack_refcount;\n\tvoid *security;\n\tstruct bpf_local_storage *bpf_storage;\n\tvoid *mce_vaddr;\n\t__u64 mce_kflags;\n\tu64 mce_addr;\n\t__u64 mce_ripv: 1;\n\t__u64 mce_whole_page: 1;\n\t__u64 __mce_reserved: 62;\n\tstruct callback_head mce_kill_me;\n\tstruct llist_head kretprobe_instances;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct thread_struct thread;\n};\n\nstruct screen_info {\n\t__u8 orig_x;\n\t__u8 orig_y;\n\t__u16 ext_mem_k;\n\t__u16 orig_video_page;\n\t__u8 orig_video_mode;\n\t__u8 orig_video_cols;\n\t__u8 flags;\n\t__u8 unused2;\n\t__u16 orig_video_ega_bx;\n\t__u16 unused3;\n\t__u8 orig_video_lines;\n\t__u8 orig_video_isVGA;\n\t__u16 orig_video_points;\n\t__u16 lfb_width;\n\t__u16 lfb_height;\n\t__u16 lfb_depth;\n\t__u32 lfb_base;\n\t__u32 lfb_size;\n\t__u16 cl_magic;\n\t__u16 cl_offset;\n\t__u16 lfb_linelength;\n\t__u8 red_size;\n\t__u8 red_pos;\n\t__u8 green_size;\n\t__u8 green_pos;\n\t__u8 blue_size;\n\t__u8 blue_pos;\n\t__u8 rsvd_size;\n\t__u8 rsvd_pos;\n\t__u16 vesapm_seg;\n\t__u16 vesapm_off;\n\t__u16 pages;\n\t__u16 vesa_attributes;\n\t__u32 capabilities;\n\t__u32 ext_lfb_base;\n\t__u8 _reserved[2];\n} __attribute__((packed));\n\nstruct apm_bios_info {\n\t__u16 version;\n\t__u16 cseg;\n\t__u32 offset;\n\t__u16 cseg_16;\n\t__u16 dseg;\n\t__u16 flags;\n\t__u16 cseg_len;\n\t__u16 cseg_16_len;\n\t__u16 dseg_len;\n};\n\nstruct edd_device_params {\n\t__u16 length;\n\t__u16 info_flags;\n\t__u32 num_default_cylinders;\n\t__u32 num_default_heads;\n\t__u32 sectors_per_track;\n\t__u64 number_of_sectors;\n\t__u16 bytes_per_sector;\n\t__u32 dpte_ptr;\n\t__u16 key;\n\t__u8 device_path_info_length;\n\t__u8 reserved2;\n\t__u16 reserved3;\n\t__u8 host_bus_type[4];\n\t__u8 interface_type[8];\n\tunion {\n\t\tstruct {\n\t\t\t__u16 base_address;\n\t\t\t__u16 reserved1;\n\t\t\t__u32 reserved2;\n\t\t} isa;\n\t\tstruct {\n\t\t\t__u8 bus;\n\t\t\t__u8 slot;\n\t\t\t__u8 function;\n\t\t\t__u8 channel;\n\t\t\t__u32 reserved;\n\t\t} pci;\n\t\tstruct {\n\t\t\t__u64 reserved;\n\t\t} ibnd;\n\t\tstruct {\n\t\t\t__u64 reserved;\n\t\t} xprs;\n\t\tstruct {\n\t\t\t__u64 reserved;\n\t\t} htpt;\n\t\tstruct {\n\t\t\t__u64 reserved;\n\t\t} unknown;\n\t} interface_path;\n\tunion {\n\t\tstruct {\n\t\t\t__u8 device;\n\t\t\t__u8 reserved1;\n\t\t\t__u16 reserved2;\n\t\t\t__u32 reserved3;\n\t\t\t__u64 reserved4;\n\t\t} ata;\n\t\tstruct {\n\t\t\t__u8 device;\n\t\t\t__u8 lun;\n\t\t\t__u8 reserved1;\n\t\t\t__u8 reserved2;\n\t\t\t__u32 reserved3;\n\t\t\t__u64 reserved4;\n\t\t} atapi;\n\t\tstruct {\n\t\t\t__u16 id;\n\t\t\t__u64 lun;\n\t\t\t__u16 reserved1;\n\t\t\t__u32 reserved2;\n\t\t} __attribute__((packed)) scsi;\n\t\tstruct {\n\t\t\t__u64 serial_number;\n\t\t\t__u64 reserved;\n\t\t} usb;\n\t\tstruct {\n\t\t\t__u64 eui;\n\t\t\t__u64 reserved;\n\t\t} i1394;\n\t\tstruct {\n\t\t\t__u64 wwid;\n\t\t\t__u64 lun;\n\t\t} fibre;\n\t\tstruct {\n\t\t\t__u64 identity_tag;\n\t\t\t__u64 reserved;\n\t\t} i2o;\n\t\tstruct {\n\t\t\t__u32 array_number;\n\t\t\t__u32 reserved1;\n\t\t\t__u64 reserved2;\n\t\t} raid;\n\t\tstruct {\n\t\t\t__u8 device;\n\t\t\t__u8 reserved1;\n\t\t\t__u16 reserved2;\n\t\t\t__u32 reserved3;\n\t\t\t__u64 reserved4;\n\t\t} sata;\n\t\tstruct {\n\t\t\t__u64 reserved1;\n\t\t\t__u64 reserved2;\n\t\t} unknown;\n\t} device_path;\n\t__u8 reserved4;\n\t__u8 checksum;\n} __attribute__((packed));\n\nstruct edd_info {\n\t__u8 device;\n\t__u8 version;\n\t__u16 interface_support;\n\t__u16 legacy_max_cylinder;\n\t__u8 legacy_max_head;\n\t__u8 legacy_sectors_per_track;\n\tstruct edd_device_params params;\n} __attribute__((packed));\n\nstruct ist_info {\n\t__u32 signature;\n\t__u32 command;\n\t__u32 event;\n\t__u32 perf_level;\n};\n\nstruct edid_info {\n\tunsigned char dummy[128];\n};\n\nstruct setup_header {\n\t__u8 setup_sects;\n\t__u16 root_flags;\n\t__u32 syssize;\n\t__u16 ram_size;\n\t__u16 vid_mode;\n\t__u16 root_dev;\n\t__u16 boot_flag;\n\t__u16 jump;\n\t__u32 header;\n\t__u16 version;\n\t__u32 realmode_swtch;\n\t__u16 start_sys_seg;\n\t__u16 kernel_version;\n\t__u8 type_of_loader;\n\t__u8 loadflags;\n\t__u16 setup_move_size;\n\t__u32 code32_start;\n\t__u32 ramdisk_image;\n\t__u32 ramdisk_size;\n\t__u32 bootsect_kludge;\n\t__u16 heap_end_ptr;\n\t__u8 ext_loader_ver;\n\t__u8 ext_loader_type;\n\t__u32 cmd_line_ptr;\n\t__u32 initrd_addr_max;\n\t__u32 kernel_alignment;\n\t__u8 relocatable_kernel;\n\t__u8 min_alignment;\n\t__u16 xloadflags;\n\t__u32 cmdline_size;\n\t__u32 hardware_subarch;\n\t__u64 hardware_subarch_data;\n\t__u32 payload_offset;\n\t__u32 payload_length;\n\t__u64 setup_data;\n\t__u64 pref_address;\n\t__u32 init_size;\n\t__u32 handover_offset;\n\t__u32 kernel_info_offset;\n} __attribute__((packed));\n\nstruct sys_desc_table {\n\t__u16 length;\n\t__u8 table[14];\n};\n\nstruct olpc_ofw_header {\n\t__u32 ofw_magic;\n\t__u32 ofw_version;\n\t__u32 cif_handler;\n\t__u32 irq_desc_table;\n};\n\nstruct efi_info {\n\t__u32 efi_loader_signature;\n\t__u32 efi_systab;\n\t__u32 efi_memdesc_size;\n\t__u32 efi_memdesc_version;\n\t__u32 efi_memmap;\n\t__u32 efi_memmap_size;\n\t__u32 efi_systab_hi;\n\t__u32 efi_memmap_hi;\n};\n\nstruct boot_e820_entry {\n\t__u64 addr;\n\t__u64 size;\n\t__u32 type;\n} __attribute__((packed));\n\nstruct boot_params {\n\tstruct screen_info screen_info;\n\tstruct apm_bios_info apm_bios_info;\n\t__u8 _pad2[4];\n\t__u64 tboot_addr;\n\tstruct ist_info ist_info;\n\t__u64 acpi_rsdp_addr;\n\t__u8 _pad3[8];\n\t__u8 hd0_info[16];\n\t__u8 hd1_info[16];\n\tstruct sys_desc_table sys_desc_table;\n\tstruct olpc_ofw_header olpc_ofw_header;\n\t__u32 ext_ramdisk_image;\n\t__u32 ext_ramdisk_size;\n\t__u32 ext_cmd_line_ptr;\n\t__u8 _pad4[116];\n\tstruct edid_info edid_info;\n\tstruct efi_info efi_info;\n\t__u32 alt_mem_k;\n\t__u32 scratch;\n\t__u8 e820_entries;\n\t__u8 eddbuf_entries;\n\t__u8 edd_mbr_sig_buf_entries;\n\t__u8 kbd_status;\n\t__u8 secure_boot;\n\t__u8 _pad5[2];\n\t__u8 sentinel;\n\t__u8 _pad6[1];\n\tstruct setup_header hdr;\n\t__u8 _pad7[36];\n\t__u32 edd_mbr_sig_buffer[16];\n\tstruct boot_e820_entry e820_table[128];\n\t__u8 _pad8[48];\n\tstruct edd_info eddbuf[6];\n\t__u8 _pad9[276];\n} __attribute__((packed));\n\nenum x86_hardware_subarch {\n\tX86_SUBARCH_PC = 0,\n\tX86_SUBARCH_LGUEST = 1,\n\tX86_SUBARCH_XEN = 2,\n\tX86_SUBARCH_INTEL_MID = 3,\n\tX86_SUBARCH_CE4100 = 4,\n\tX86_NR_SUBARCHS = 5,\n};\n\nstruct range {\n\tu64 start;\n\tu64 end;\n};\n\nstruct pt_regs {\n\tlong unsigned int r15;\n\tlong unsigned int r14;\n\tlong unsigned int r13;\n\tlong unsigned int r12;\n\tlong unsigned int bp;\n\tlong unsigned int bx;\n\tlong unsigned int r11;\n\tlong unsigned int r10;\n\tlong unsigned int r9;\n\tlong unsigned int r8;\n\tlong unsigned int ax;\n\tlong unsigned int cx;\n\tlong unsigned int dx;\n\tlong unsigned int si;\n\tlong unsigned int di;\n\tlong unsigned int orig_ax;\n\tlong unsigned int ip;\n\tlong unsigned int cs;\n\tlong unsigned int flags;\n\tlong unsigned int sp;\n\tlong unsigned int ss;\n};\n\nenum {\n\tGATE_INTERRUPT = 14,\n\tGATE_TRAP = 15,\n\tGATE_CALL = 12,\n\tGATE_TASK = 5,\n};\n\nstruct idt_bits {\n\tu16 ist: 3;\n\tu16 zero: 5;\n\tu16 type: 5;\n\tu16 dpl: 2;\n\tu16 p: 1;\n};\n\nstruct idt_data {\n\tunsigned int vector;\n\tunsigned int segment;\n\tstruct idt_bits bits;\n\tconst void *addr;\n};\n\nstruct gate_struct {\n\tu16 offset_low;\n\tu16 segment;\n\tstruct idt_bits bits;\n\tu16 offset_middle;\n\tu32 offset_high;\n\tu32 reserved;\n};\n\ntypedef struct gate_struct gate_desc;\n\nstruct desc_ptr {\n\tshort unsigned int size;\n\tlong unsigned int address;\n} __attribute__((packed));\n\ntypedef long unsigned int pteval_t;\n\ntypedef long unsigned int pmdval_t;\n\ntypedef long unsigned int pudval_t;\n\ntypedef long unsigned int p4dval_t;\n\ntypedef long unsigned int pgdval_t;\n\ntypedef long unsigned int pgprotval_t;\n\ntypedef struct {\n\tpteval_t pte;\n} pte_t;\n\nstruct pgprot {\n\tpgprotval_t pgprot;\n};\n\ntypedef struct pgprot pgprot_t;\n\ntypedef struct {\n\tpgdval_t pgd;\n} pgd_t;\n\ntypedef struct {\n\tp4dval_t p4d;\n} p4d_t;\n\ntypedef struct {\n\tpudval_t pud;\n} pud_t;\n\ntypedef struct {\n\tpmdval_t pmd;\n} pmd_t;\n\ntypedef struct page *pgtable_t;\n\nstruct address_space;\n\nstruct page_pool;\n\nstruct kmem_cache;\n\nstruct dev_pagemap;\n\nstruct page {\n\tlong unsigned int flags;\n\tunion {\n\t\tstruct {\n\t\t\tstruct list_head lru;\n\t\t\tstruct address_space *mapping;\n\t\t\tlong unsigned int index;\n\t\t\tlong unsigned int private;\n\t\t};\n\t\tstruct {\n\t\t\tlong unsigned int pp_magic;\n\t\t\tstruct page_pool *pp;\n\t\t\tlong unsigned int _pp_mapping_pad;\n\t\t\tlong unsigned int dma_addr[2];\n\t\t};\n\t\tstruct {\n\t\t\tunion {\n\t\t\t\tstruct list_head slab_list;\n\t\t\t\tstruct {\n\t\t\t\t\tstruct page *next;\n\t\t\t\t\tint pages;\n\t\t\t\t\tint pobjects;\n\t\t\t\t};\n\t\t\t};\n\t\t\tstruct kmem_cache *slab_cache;\n\t\t\tvoid *freelist;\n\t\t\tunion {\n\t\t\t\tvoid *s_mem;\n\t\t\t\tlong unsigned int counters;\n\t\t\t\tstruct {\n\t\t\t\t\tunsigned int inuse: 16;\n\t\t\t\t\tunsigned int objects: 15;\n\t\t\t\t\tunsigned int frozen: 1;\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\tstruct {\n\t\t\tlong unsigned int compound_head;\n\t\t\tunsigned char compound_dtor;\n\t\t\tunsigned char compound_order;\n\t\t\tatomic_t compound_mapcount;\n\t\t\tunsigned int compound_nr;\n\t\t};\n\t\tstruct {\n\t\t\tlong unsigned int _compound_pad_1;\n\t\t\tatomic_t hpage_pinned_refcount;\n\t\t\tstruct list_head deferred_list;\n\t\t};\n\t\tstruct {\n\t\t\tlong unsigned int _pt_pad_1;\n\t\t\tpgtable_t pmd_huge_pte;\n\t\t\tlong unsigned int _pt_pad_2;\n\t\t\tunion {\n\t\t\t\tstruct mm_struct *pt_mm;\n\t\t\t\tatomic_t pt_frag_refcount;\n\t\t\t};\n\t\t\tspinlock_t ptl;\n\t\t};\n\t\tstruct {\n\t\t\tstruct dev_pagemap *pgmap;\n\t\t\tvoid *zone_device_data;\n\t\t};\n\t\tstruct callback_head callback_head;\n\t};\n\tunion {\n\t\tatomic_t _mapcount;\n\t\tunsigned int page_type;\n\t\tunsigned int active;\n\t\tint units;\n\t};\n\tatomic_t _refcount;\n\tlong unsigned int memcg_data;\n};\n\nstruct paravirt_callee_save {\n\tvoid *func;\n};\n\nstruct pv_lazy_ops {\n\tvoid (*enter)();\n\tvoid (*leave)();\n\tvoid (*flush)();\n};\n\nstruct pv_cpu_ops {\n\tvoid (*io_delay)();\n\tlong unsigned int (*get_debugreg)(int);\n\tvoid (*set_debugreg)(int, long unsigned int);\n\tlong unsigned int (*read_cr0)();\n\tvoid (*write_cr0)(long unsigned int);\n\tvoid (*write_cr4)(long unsigned int);\n\tvoid (*load_tr_desc)();\n\tvoid (*load_gdt)(const struct desc_ptr *);\n\tvoid (*load_idt)(const struct desc_ptr *);\n\tvoid (*set_ldt)(const void *, unsigned int);\n\tlong unsigned int (*store_tr)();\n\tvoid (*load_tls)(struct thread_struct *, unsigned int);\n\tvoid (*load_gs_index)(unsigned int);\n\tvoid (*write_ldt_entry)(struct desc_struct *, int, const void *);\n\tvoid (*write_gdt_entry)(struct desc_struct *, int, const void *, int);\n\tvoid (*write_idt_entry)(gate_desc *, int, const gate_desc *);\n\tvoid (*alloc_ldt)(struct desc_struct *, unsigned int);\n\tvoid (*free_ldt)(struct desc_struct *, unsigned int);\n\tvoid (*load_sp0)(long unsigned int);\n\tvoid (*invalidate_io_bitmap)();\n\tvoid (*update_io_bitmap)();\n\tvoid (*wbinvd)();\n\tvoid (*cpuid)(unsigned int *, unsigned int *, unsigned int *, unsigned int *);\n\tu64 (*read_msr)(unsigned int);\n\tvoid (*write_msr)(unsigned int, unsigned int, unsigned int);\n\tu64 (*read_msr_safe)(unsigned int, int *);\n\tint (*write_msr_safe)(unsigned int, unsigned int, unsigned int);\n\tu64 (*read_pmc)(int);\n\tvoid (*start_context_switch)(struct task_struct *);\n\tvoid (*end_context_switch)(struct task_struct *);\n};\n\nstruct pv_irq_ops {\n\tstruct paravirt_callee_save save_fl;\n\tstruct paravirt_callee_save irq_disable;\n\tstruct paravirt_callee_save irq_enable;\n\tvoid (*safe_halt)();\n\tvoid (*halt)();\n};\n\nstruct flush_tlb_info;\n\nstruct mmu_gather;\n\nstruct pv_mmu_ops {\n\tvoid (*flush_tlb_user)();\n\tvoid (*flush_tlb_kernel)();\n\tvoid (*flush_tlb_one_user)(long unsigned int);\n\tvoid (*flush_tlb_multi)(const struct cpumask *, const struct flush_tlb_info *);\n\tvoid (*tlb_remove_table)(struct mmu_gather *, void *);\n\tvoid (*exit_mmap)(struct mm_struct *);\n\tstruct paravirt_callee_save read_cr2;\n\tvoid (*write_cr2)(long unsigned int);\n\tlong unsigned int (*read_cr3)();\n\tvoid (*write_cr3)(long unsigned int);\n\tvoid (*activate_mm)(struct mm_struct *, struct mm_struct *);\n\tvoid (*dup_mmap)(struct mm_struct *, struct mm_struct *);\n\tint (*pgd_alloc)(struct mm_struct *);\n\tvoid (*pgd_free)(struct mm_struct *, pgd_t *);\n\tvoid (*alloc_pte)(struct mm_struct *, long unsigned int);\n\tvoid (*alloc_pmd)(struct mm_struct *, long unsigned int);\n\tvoid (*alloc_pud)(struct mm_struct *, long unsigned int);\n\tvoid (*alloc_p4d)(struct mm_struct *, long unsigned int);\n\tvoid (*release_pte)(long unsigned int);\n\tvoid (*release_pmd)(long unsigned int);\n\tvoid (*release_pud)(long unsigned int);\n\tvoid (*release_p4d)(long unsigned int);\n\tvoid (*set_pte)(pte_t *, pte_t);\n\tvoid (*set_pmd)(pmd_t *, pmd_t);\n\tpte_t (*ptep_modify_prot_start)(struct vm_area_struct *, long unsigned int, pte_t *);\n\tvoid (*ptep_modify_prot_commit)(struct vm_area_struct *, long unsigned int, pte_t *, pte_t);\n\tstruct paravirt_callee_save pte_val;\n\tstruct paravirt_callee_save make_pte;\n\tstruct paravirt_callee_save pgd_val;\n\tstruct paravirt_callee_save make_pgd;\n\tvoid (*set_pud)(pud_t *, pud_t);\n\tstruct paravirt_callee_save pmd_val;\n\tstruct paravirt_callee_save make_pmd;\n\tstruct paravirt_callee_save pud_val;\n\tstruct paravirt_callee_save make_pud;\n\tvoid (*set_p4d)(p4d_t *, p4d_t);\n\tstruct paravirt_callee_save p4d_val;\n\tstruct paravirt_callee_save make_p4d;\n\tvoid (*set_pgd)(pgd_t *, pgd_t);\n\tstruct pv_lazy_ops lazy_mode;\n\tvoid (*set_fixmap)(unsigned int, phys_addr_t, pgprot_t);\n};\n\nstruct flush_tlb_info {\n\tstruct mm_struct *mm;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tu64 new_tlb_gen;\n\tunsigned int initiating_cpu;\n\tu8 stride_shift;\n\tu8 freed_tables;\n};\n\nstruct rw_semaphore {\n\tatomic_long_t count;\n\tatomic_long_t owner;\n\tstruct optimistic_spin_queue osq;\n\traw_spinlock_t wait_lock;\n\tstruct list_head wait_list;\n};\n\nstruct mm_rss_stat {\n\tatomic_long_t count[4];\n};\n\nstruct ldt_struct;\n\nstruct vdso_image;\n\ntypedef struct {\n\tu64 ctx_id;\n\tatomic64_t tlb_gen;\n\tstruct rw_semaphore ldt_usr_sem;\n\tstruct ldt_struct *ldt;\n\tshort unsigned int flags;\n\tstruct mutex lock;\n\tvoid *vdso;\n\tconst struct vdso_image *vdso_image;\n\tatomic_t perf_rdpmc_allowed;\n\tu16 pkey_allocation_map;\n\ts16 execute_only_pkey;\n} mm_context_t;\n\nstruct xol_area;\n\nstruct uprobes_state {\n\tstruct xol_area *xol_area;\n};\n\nstruct work_struct;\n\ntypedef void (*work_func_t)(struct work_struct *);\n\nstruct work_struct {\n\tatomic_long_t data;\n\tstruct list_head entry;\n\twork_func_t func;\n};\n\nstruct linux_binfmt;\n\nstruct core_state;\n\nstruct kioctx_table;\n\nstruct user_namespace;\n\nstruct mmu_notifier_subscriptions;\n\nstruct mm_struct {\n\tstruct {\n\t\tstruct vm_area_struct *mmap;\n\t\tstruct rb_root mm_rb;\n\t\tu64 vmacache_seqnum;\n\t\tlong unsigned int (*get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int);\n\t\tlong unsigned int mmap_base;\n\t\tlong unsigned int mmap_legacy_base;\n\t\tlong unsigned int mmap_compat_base;\n\t\tlong unsigned int mmap_compat_legacy_base;\n\t\tlong unsigned int task_size;\n\t\tlong unsigned int highest_vm_end;\n\t\tpgd_t *pgd;\n\t\tatomic_t membarrier_state;\n\t\tatomic_t mm_users;\n\t\tatomic_t mm_count;\n\t\tatomic_long_t pgtables_bytes;\n\t\tint map_count;\n\t\tspinlock_t page_table_lock;\n\t\tstruct rw_semaphore mmap_lock;\n\t\tstruct list_head mmlist;\n\t\tlong unsigned int hiwater_rss;\n\t\tlong unsigned int hiwater_vm;\n\t\tlong unsigned int total_vm;\n\t\tlong unsigned int locked_vm;\n\t\tatomic64_t pinned_vm;\n\t\tlong unsigned int data_vm;\n\t\tlong unsigned int exec_vm;\n\t\tlong unsigned int stack_vm;\n\t\tlong unsigned int def_flags;\n\t\tseqcount_t write_protect_seq;\n\t\tspinlock_t arg_lock;\n\t\tlong unsigned int start_code;\n\t\tlong unsigned int end_code;\n\t\tlong unsigned int start_data;\n\t\tlong unsigned int end_data;\n\t\tlong unsigned int start_brk;\n\t\tlong unsigned int brk;\n\t\tlong unsigned int start_stack;\n\t\tlong unsigned int arg_start;\n\t\tlong unsigned int arg_end;\n\t\tlong unsigned int env_start;\n\t\tlong unsigned int env_end;\n\t\tlong unsigned int saved_auxv[48];\n\t\tstruct mm_rss_stat rss_stat;\n\t\tstruct linux_binfmt *binfmt;\n\t\tmm_context_t context;\n\t\tlong unsigned int flags;\n\t\tstruct core_state *core_state;\n\t\tspinlock_t ioctx_lock;\n\t\tstruct kioctx_table *ioctx_table;\n\t\tstruct task_struct *owner;\n\t\tstruct user_namespace *user_ns;\n\t\tstruct file *exe_file;\n\t\tstruct mmu_notifier_subscriptions *notifier_subscriptions;\n\t\tlong unsigned int numa_next_scan;\n\t\tlong unsigned int numa_scan_offset;\n\t\tint numa_scan_seq;\n\t\tatomic_t tlb_flush_pending;\n\t\tbool tlb_flush_batched;\n\t\tstruct uprobes_state uprobes_state;\n\t\tatomic_long_t hugetlb_usage;\n\t\tstruct work_struct async_put_work;\n\t\tu32 pasid;\n\t};\n\tlong unsigned int cpu_bitmap[0];\n};\n\nstruct userfaultfd_ctx;\n\nstruct vm_userfaultfd_ctx {\n\tstruct userfaultfd_ctx *ctx;\n};\n\nstruct anon_vma;\n\nstruct vm_operations_struct;\n\nstruct vm_area_struct {\n\tlong unsigned int vm_start;\n\tlong unsigned int vm_end;\n\tstruct vm_area_struct *vm_next;\n\tstruct vm_area_struct *vm_prev;\n\tstruct rb_node vm_rb;\n\tlong unsigned int rb_subtree_gap;\n\tstruct mm_struct *vm_mm;\n\tpgprot_t vm_page_prot;\n\tlong unsigned int vm_flags;\n\tstruct {\n\t\tstruct rb_node rb;\n\t\tlong unsigned int rb_subtree_last;\n\t} shared;\n\tstruct list_head anon_vma_chain;\n\tstruct anon_vma *anon_vma;\n\tconst struct vm_operations_struct *vm_ops;\n\tlong unsigned int vm_pgoff;\n\tstruct file *vm_file;\n\tvoid *vm_private_data;\n\tatomic_long_t swap_readahead_info;\n\tstruct mempolicy *vm_policy;\n\tstruct vm_userfaultfd_ctx vm_userfaultfd_ctx;\n};\n\nstruct pv_lock_ops {\n\tvoid (*queued_spin_lock_slowpath)(struct qspinlock *, u32);\n\tstruct paravirt_callee_save queued_spin_unlock;\n\tvoid (*wait)(u8 *, u8);\n\tvoid (*kick)(int);\n\tstruct paravirt_callee_save vcpu_is_preempted;\n};\n\nstruct paravirt_patch_template {\n\tstruct pv_cpu_ops cpu;\n\tstruct pv_irq_ops irq;\n\tstruct pv_mmu_ops mmu;\n\tstruct pv_lock_ops lock;\n};\n\nstruct math_emu_info {\n\tlong int ___orig_eip;\n\tstruct pt_regs *regs;\n};\n\nenum {\n\tUNAME26 = 131072,\n\tADDR_NO_RANDOMIZE = 262144,\n\tFDPIC_FUNCPTRS = 524288,\n\tMMAP_PAGE_ZERO = 1048576,\n\tADDR_COMPAT_LAYOUT = 2097152,\n\tREAD_IMPLIES_EXEC = 4194304,\n\tADDR_LIMIT_32BIT = 8388608,\n\tSHORT_INODE = 16777216,\n\tWHOLE_SECONDS = 33554432,\n\tSTICKY_TIMEOUTS = 67108864,\n\tADDR_LIMIT_3GB = 134217728,\n};\n\nenum tlb_infos {\n\tENTRIES = 0,\n\tNR_INFO = 1,\n};\n\nenum pcpu_fc {\n\tPCPU_FC_AUTO = 0,\n\tPCPU_FC_EMBED = 1,\n\tPCPU_FC_PAGE = 2,\n\tPCPU_FC_NR = 3,\n};\n\nstruct vm_struct {\n\tstruct vm_struct *next;\n\tvoid *addr;\n\tlong unsigned int size;\n\tlong unsigned int flags;\n\tstruct page **pages;\n\tunsigned int nr_pages;\n\tphys_addr_t phys_addr;\n\tconst void *caller;\n};\n\nstruct wait_queue_head {\n\tspinlock_t lock;\n\tstruct list_head head;\n};\n\ntypedef struct wait_queue_head wait_queue_head_t;\n\nstruct seqcount_raw_spinlock {\n\tseqcount_t seqcount;\n};\n\ntypedef struct seqcount_raw_spinlock seqcount_raw_spinlock_t;\n\ntypedef struct {\n\tseqcount_spinlock_t seqcount;\n\tspinlock_t lock;\n} seqlock_t;\n\nenum node_states {\n\tN_POSSIBLE = 0,\n\tN_ONLINE = 1,\n\tN_NORMAL_MEMORY = 2,\n\tN_HIGH_MEMORY = 2,\n\tN_MEMORY = 3,\n\tN_CPU = 4,\n\tN_GENERIC_INITIATOR = 5,\n\tNR_NODE_STATES = 6,\n};\n\nenum {\n\tMM_FILEPAGES = 0,\n\tMM_ANONPAGES = 1,\n\tMM_SWAPENTS = 2,\n\tMM_SHMEMPAGES = 3,\n\tNR_MM_COUNTERS = 4,\n};\n\nstruct swait_queue_head {\n\traw_spinlock_t lock;\n\tstruct list_head task_list;\n};\n\nstruct completion {\n\tunsigned int done;\n\tstruct swait_queue_head wait;\n};\n\nstruct arch_uprobe_task {\n\tlong unsigned int saved_scratch_register;\n\tunsigned int saved_trap_nr;\n\tunsigned int saved_tf;\n};\n\nenum uprobe_task_state {\n\tUTASK_RUNNING = 0,\n\tUTASK_SSTEP = 1,\n\tUTASK_SSTEP_ACK = 2,\n\tUTASK_SSTEP_TRAPPED = 3,\n};\n\nstruct uprobe;\n\nstruct return_instance;\n\nstruct uprobe_task {\n\tenum uprobe_task_state state;\n\tunion {\n\t\tstruct {\n\t\t\tstruct arch_uprobe_task autask;\n\t\t\tlong unsigned int vaddr;\n\t\t};\n\t\tstruct {\n\t\t\tstruct callback_head dup_xol_work;\n\t\t\tlong unsigned int dup_xol_addr;\n\t\t};\n\t};\n\tstruct uprobe *active_uprobe;\n\tlong unsigned int xol_vaddr;\n\tstruct return_instance *return_instances;\n\tunsigned int depth;\n};\n\nstruct return_instance {\n\tstruct uprobe *uprobe;\n\tlong unsigned int func;\n\tlong unsigned int stack;\n\tlong unsigned int orig_ret_vaddr;\n\tbool chained;\n\tstruct return_instance *next;\n};\n\nstruct vdso_image {\n\tvoid *data;\n\tlong unsigned int size;\n\tlong unsigned int alt;\n\tlong unsigned int alt_len;\n\tlong unsigned int extable_base;\n\tlong unsigned int extable_len;\n\tconst void *extable;\n\tlong int sym_vvar_start;\n\tlong int sym_vvar_page;\n\tlong int sym_pvclock_page;\n\tlong int sym_hvclock_page;\n\tlong int sym_timens_page;\n\tlong int sym_VDSO32_NOTE_MASK;\n\tlong int sym___kernel_sigreturn;\n\tlong int sym___kernel_rt_sigreturn;\n\tlong int sym___kernel_vsyscall;\n\tlong int sym_int80_landing_pad;\n\tlong int sym_vdso32_sigreturn_landing_pad;\n\tlong int sym_vdso32_rt_sigreturn_landing_pad;\n};\n\nstruct xarray {\n\tspinlock_t xa_lock;\n\tgfp_t xa_flags;\n\tvoid *xa_head;\n};\n\ntypedef u32 errseq_t;\n\nstruct address_space_operations;\n\nstruct address_space {\n\tstruct inode *host;\n\tstruct xarray i_pages;\n\tgfp_t gfp_mask;\n\tatomic_t i_mmap_writable;\n\tatomic_t nr_thps;\n\tstruct rb_root_cached i_mmap;\n\tstruct rw_semaphore i_mmap_rwsem;\n\tlong unsigned int nrpages;\n\tlong unsigned int writeback_index;\n\tconst struct address_space_operations *a_ops;\n\tlong unsigned int flags;\n\terrseq_t wb_err;\n\tspinlock_t private_lock;\n\tstruct list_head private_list;\n\tvoid *private_data;\n};\n\nstruct vmem_altmap {\n\tlong unsigned int base_pfn;\n\tconst long unsigned int end_pfn;\n\tconst long unsigned int reserve;\n\tlong unsigned int free;\n\tlong unsigned int align;\n\tlong unsigned int alloc;\n};\n\nstruct percpu_ref_data;\n\nstruct percpu_ref {\n\tlong unsigned int percpu_count_ptr;\n\tstruct percpu_ref_data *data;\n};\n\nenum memory_type {\n\tMEMORY_DEVICE_PRIVATE = 1,\n\tMEMORY_DEVICE_FS_DAX = 2,\n\tMEMORY_DEVICE_GENERIC = 3,\n\tMEMORY_DEVICE_PCI_P2PDMA = 4,\n};\n\nstruct dev_pagemap_ops;\n\nstruct dev_pagemap {\n\tstruct vmem_altmap altmap;\n\tstruct percpu_ref *ref;\n\tstruct percpu_ref internal_ref;\n\tstruct completion done;\n\tenum memory_type type;\n\tunsigned int flags;\n\tconst struct dev_pagemap_ops *ops;\n\tvoid *owner;\n\tint nr_range;\n\tunion {\n\t\tstruct range range;\n\t\tstruct range ranges[0];\n\t};\n};\n\nstruct vfsmount;\n\nstruct path {\n\tstruct vfsmount *mnt;\n\tstruct dentry *dentry;\n};\n\nenum rw_hint {\n\tWRITE_LIFE_NOT_SET = 0,\n\tWRITE_LIFE_NONE = 1,\n\tWRITE_LIFE_SHORT = 2,\n\tWRITE_LIFE_MEDIUM = 3,\n\tWRITE_LIFE_LONG = 4,\n\tWRITE_LIFE_EXTREME = 5,\n};\n\nenum pid_type {\n\tPIDTYPE_PID = 0,\n\tPIDTYPE_TGID = 1,\n\tPIDTYPE_PGID = 2,\n\tPIDTYPE_SID = 3,\n\tPIDTYPE_MAX = 4,\n};\n\nstruct fown_struct {\n\trwlock_t lock;\n\tstruct pid *pid;\n\tenum pid_type pid_type;\n\tkuid_t uid;\n\tkuid_t euid;\n\tint signum;\n};\n\nstruct file_ra_state {\n\tlong unsigned int start;\n\tunsigned int size;\n\tunsigned int async_size;\n\tunsigned int ra_pages;\n\tunsigned int mmap_miss;\n\tloff_t prev_pos;\n};\n\nstruct file {\n\tunion {\n\t\tstruct llist_node fu_llist;\n\t\tstruct callback_head fu_rcuhead;\n\t} f_u;\n\tstruct path f_path;\n\tstruct inode *f_inode;\n\tconst struct file_operations *f_op;\n\tspinlock_t f_lock;\n\tenum rw_hint f_write_hint;\n\tatomic_long_t f_count;\n\tunsigned int f_flags;\n\tfmode_t f_mode;\n\tstruct mutex f_pos_lock;\n\tloff_t f_pos;\n\tstruct fown_struct f_owner;\n\tconst struct cred *f_cred;\n\tstruct file_ra_state f_ra;\n\tu64 f_version;\n\tvoid *f_security;\n\tvoid *private_data;\n\tstruct hlist_head *f_ep;\n\tstruct address_space *f_mapping;\n\terrseq_t f_wb_err;\n\terrseq_t f_sb_err;\n};\n\ntypedef unsigned int vm_fault_t;\n\nenum page_entry_size {\n\tPE_SIZE_PTE = 0,\n\tPE_SIZE_PMD = 1,\n\tPE_SIZE_PUD = 2,\n};\n\nstruct vm_fault;\n\nstruct vm_operations_struct {\n\tvoid (*open)(struct vm_area_struct *);\n\tvoid (*close)(struct vm_area_struct *);\n\tint (*may_split)(struct vm_area_struct *, long unsigned int);\n\tint (*mremap)(struct vm_area_struct *);\n\tint (*mprotect)(struct vm_area_struct *, long unsigned int, long unsigned int, long unsigned int);\n\tvm_fault_t (*fault)(struct vm_fault *);\n\tvm_fault_t (*huge_fault)(struct vm_fault *, enum page_entry_size);\n\tvm_fault_t (*map_pages)(struct vm_fault *, long unsigned int, long unsigned int);\n\tlong unsigned int (*pagesize)(struct vm_area_struct *);\n\tvm_fault_t (*page_mkwrite)(struct vm_fault *);\n\tvm_fault_t (*pfn_mkwrite)(struct vm_fault *);\n\tint (*access)(struct vm_area_struct *, long unsigned int, void *, int, int);\n\tconst char * (*name)(struct vm_area_struct *);\n\tint (*set_policy)(struct vm_area_struct *, struct mempolicy *);\n\tstruct mempolicy * (*get_policy)(struct vm_area_struct *, long unsigned int);\n\tstruct page * (*find_special_page)(struct vm_area_struct *, long unsigned int);\n};\n\nstruct core_thread {\n\tstruct task_struct *task;\n\tstruct core_thread *next;\n};\n\nstruct core_state {\n\tatomic_t nr_threads;\n\tstruct core_thread dumper;\n\tstruct completion startup;\n};\n\nenum fault_flag {\n\tFAULT_FLAG_WRITE = 1,\n\tFAULT_FLAG_MKWRITE = 2,\n\tFAULT_FLAG_ALLOW_RETRY = 4,\n\tFAULT_FLAG_RETRY_NOWAIT = 8,\n\tFAULT_FLAG_KILLABLE = 16,\n\tFAULT_FLAG_TRIED = 32,\n\tFAULT_FLAG_USER = 64,\n\tFAULT_FLAG_REMOTE = 128,\n\tFAULT_FLAG_INSTRUCTION = 256,\n\tFAULT_FLAG_INTERRUPTIBLE = 512,\n};\n\nstruct vm_fault {\n\tconst struct {\n\t\tstruct vm_area_struct *vma;\n\t\tgfp_t gfp_mask;\n\t\tlong unsigned int pgoff;\n\t\tlong unsigned int address;\n\t};\n\tenum fault_flag flags;\n\tpmd_t *pmd;\n\tpud_t *pud;\n\tunion {\n\t\tpte_t orig_pte;\n\t\tpmd_t orig_pmd;\n\t};\n\tstruct page *cow_page;\n\tstruct page *page;\n\tpte_t *pte;\n\tspinlock_t *ptl;\n\tpgtable_t prealloc_pte;\n};\n\nenum migratetype {\n\tMIGRATE_UNMOVABLE = 0,\n\tMIGRATE_MOVABLE = 1,\n\tMIGRATE_RECLAIMABLE = 2,\n\tMIGRATE_PCPTYPES = 3,\n\tMIGRATE_HIGHATOMIC = 3,\n\tMIGRATE_CMA = 4,\n\tMIGRATE_ISOLATE = 5,\n\tMIGRATE_TYPES = 6,\n};\n\nenum numa_stat_item {\n\tNUMA_HIT = 0,\n\tNUMA_MISS = 1,\n\tNUMA_FOREIGN = 2,\n\tNUMA_INTERLEAVE_HIT = 3,\n\tNUMA_LOCAL = 4,\n\tNUMA_OTHER = 5,\n\tNR_VM_NUMA_EVENT_ITEMS = 6,\n};\n\nenum zone_stat_item {\n\tNR_FREE_PAGES = 0,\n\tNR_ZONE_LRU_BASE = 1,\n\tNR_ZONE_INACTIVE_ANON = 1,\n\tNR_ZONE_ACTIVE_ANON = 2,\n\tNR_ZONE_INACTIVE_FILE = 3,\n\tNR_ZONE_ACTIVE_FILE = 4,\n\tNR_ZONE_UNEVICTABLE = 5,\n\tNR_ZONE_WRITE_PENDING = 6,\n\tNR_MLOCK = 7,\n\tNR_BOUNCE = 8,\n\tNR_ZSPAGES = 9,\n\tNR_FREE_CMA_PAGES = 10,\n\tNR_VM_ZONE_STAT_ITEMS = 11,\n};\n\nenum node_stat_item {\n\tNR_LRU_BASE = 0,\n\tNR_INACTIVE_ANON = 0,\n\tNR_ACTIVE_ANON = 1,\n\tNR_INACTIVE_FILE = 2,\n\tNR_ACTIVE_FILE = 3,\n\tNR_UNEVICTABLE = 4,\n\tNR_SLAB_RECLAIMABLE_B = 5,\n\tNR_SLAB_UNRECLAIMABLE_B = 6,\n\tNR_ISOLATED_ANON = 7,\n\tNR_ISOLATED_FILE = 8,\n\tWORKINGSET_NODES = 9,\n\tWORKINGSET_REFAULT_BASE = 10,\n\tWORKINGSET_REFAULT_ANON = 10,\n\tWORKINGSET_REFAULT_FILE = 11,\n\tWORKINGSET_ACTIVATE_BASE = 12,\n\tWORKINGSET_ACTIVATE_ANON = 12,\n\tWORKINGSET_ACTIVATE_FILE = 13,\n\tWORKINGSET_RESTORE_BASE = 14,\n\tWORKINGSET_RESTORE_ANON = 14,\n\tWORKINGSET_RESTORE_FILE = 15,\n\tWORKINGSET_NODERECLAIM = 16,\n\tNR_ANON_MAPPED = 17,\n\tNR_FILE_MAPPED = 18,\n\tNR_FILE_PAGES = 19,\n\tNR_FILE_DIRTY = 20,\n\tNR_WRITEBACK = 21,\n\tNR_WRITEBACK_TEMP = 22,\n\tNR_SHMEM = 23,\n\tNR_SHMEM_THPS = 24,\n\tNR_SHMEM_PMDMAPPED = 25,\n\tNR_FILE_THPS = 26,\n\tNR_FILE_PMDMAPPED = 27,\n\tNR_ANON_THPS = 28,\n\tNR_VMSCAN_WRITE = 29,\n\tNR_VMSCAN_IMMEDIATE = 30,\n\tNR_DIRTIED = 31,\n\tNR_WRITTEN = 32,\n\tNR_KERNEL_MISC_RECLAIMABLE = 33,\n\tNR_FOLL_PIN_ACQUIRED = 34,\n\tNR_FOLL_PIN_RELEASED = 35,\n\tNR_KERNEL_STACK_KB = 36,\n\tNR_PAGETABLE = 37,\n\tNR_SWAPCACHE = 38,\n\tNR_VM_NODE_STAT_ITEMS = 39,\n};\n\nenum lru_list {\n\tLRU_INACTIVE_ANON = 0,\n\tLRU_ACTIVE_ANON = 1,\n\tLRU_INACTIVE_FILE = 2,\n\tLRU_ACTIVE_FILE = 3,\n\tLRU_UNEVICTABLE = 4,\n\tNR_LRU_LISTS = 5,\n};\n\ntypedef unsigned int isolate_mode_t;\n\nenum zone_watermarks {\n\tWMARK_MIN = 0,\n\tWMARK_LOW = 1,\n\tWMARK_HIGH = 2,\n\tNR_WMARK = 3,\n};\n\nenum {\n\tZONELIST_FALLBACK = 0,\n\tZONELIST_NOFALLBACK = 1,\n\tMAX_ZONELISTS = 2,\n};\n\ntypedef void percpu_ref_func_t(struct percpu_ref *);\n\nstruct percpu_ref_data {\n\tatomic_long_t count;\n\tpercpu_ref_func_t *release;\n\tpercpu_ref_func_t *confirm_switch;\n\tbool force_atomic: 1;\n\tbool allow_reinit: 1;\n\tstruct callback_head rcu;\n\tstruct percpu_ref *ref;\n};\n\nstruct shrink_control {\n\tgfp_t gfp_mask;\n\tint nid;\n\tlong unsigned int nr_to_scan;\n\tlong unsigned int nr_scanned;\n\tstruct mem_cgroup *memcg;\n};\n\nstruct shrinker {\n\tlong unsigned int (*count_objects)(struct shrinker *, struct shrink_control *);\n\tlong unsigned int (*scan_objects)(struct shrinker *, struct shrink_control *);\n\tlong int batch;\n\tint seeks;\n\tunsigned int flags;\n\tstruct list_head list;\n\tint id;\n\tatomic_long_t *nr_deferred;\n};\n\nstruct rlimit {\n\t__kernel_ulong_t rlim_cur;\n\t__kernel_ulong_t rlim_max;\n};\n\nstruct dev_pagemap_ops {\n\tvoid (*page_free)(struct page *);\n\tvoid (*kill)(struct dev_pagemap *);\n\tvoid (*cleanup)(struct dev_pagemap *);\n\tvm_fault_t (*migrate_to_ram)(struct vm_fault *);\n};\n\nstruct pid_namespace;\n\nstruct upid {\n\tint nr;\n\tstruct pid_namespace *ns;\n};\n\nstruct pid {\n\trefcount_t count;\n\tunsigned int level;\n\tspinlock_t lock;\n\tstruct hlist_head tasks[4];\n\tstruct hlist_head inodes;\n\twait_queue_head_t wait_pidfd;\n\tstruct callback_head rcu;\n\tstruct upid numbers[1];\n};\n\ntypedef struct {\n\tgid_t val;\n} kgid_t;\n\nstruct hrtimer_cpu_base;\n\nstruct hrtimer_clock_base {\n\tstruct hrtimer_cpu_base *cpu_base;\n\tunsigned int index;\n\tclockid_t clockid;\n\tseqcount_raw_spinlock_t seq;\n\tstruct hrtimer *running;\n\tstruct timerqueue_head active;\n\tktime_t (*get_time)();\n\tktime_t offset;\n};\n\nstruct hrtimer_cpu_base {\n\traw_spinlock_t lock;\n\tunsigned int cpu;\n\tunsigned int active_bases;\n\tunsigned int clock_was_set_seq;\n\tunsigned int hres_active: 1;\n\tunsigned int in_hrtirq: 1;\n\tunsigned int hang_detected: 1;\n\tunsigned int softirq_activated: 1;\n\tunsigned int nr_events;\n\tshort unsigned int nr_retries;\n\tshort unsigned int nr_hangs;\n\tunsigned int max_hang_time;\n\tktime_t expires_next;\n\tstruct hrtimer *next_timer;\n\tktime_t softirq_expires_next;\n\tstruct hrtimer *softirq_next_timer;\n\tstruct hrtimer_clock_base clock_base[8];\n};\n\nenum hrtimer_base_type {\n\tHRTIMER_BASE_MONOTONIC = 0,\n\tHRTIMER_BASE_REALTIME = 1,\n\tHRTIMER_BASE_BOOTTIME = 2,\n\tHRTIMER_BASE_TAI = 3,\n\tHRTIMER_BASE_MONOTONIC_SOFT = 4,\n\tHRTIMER_BASE_REALTIME_SOFT = 5,\n\tHRTIMER_BASE_BOOTTIME_SOFT = 6,\n\tHRTIMER_BASE_TAI_SOFT = 7,\n\tHRTIMER_MAX_CLOCK_BASES = 8,\n};\n\ntypedef void __signalfn_t(int);\n\ntypedef __signalfn_t *__sighandler_t;\n\ntypedef void __restorefn_t();\n\ntypedef __restorefn_t *__sigrestore_t;\n\nunion sigval {\n\tint sival_int;\n\tvoid *sival_ptr;\n};\n\ntypedef union sigval sigval_t;\n\nunion __sifields {\n\tstruct {\n\t\t__kernel_pid_t _pid;\n\t\t__kernel_uid32_t _uid;\n\t} _kill;\n\tstruct {\n\t\t__kernel_timer_t _tid;\n\t\tint _overrun;\n\t\tsigval_t _sigval;\n\t\tint _sys_private;\n\t} _timer;\n\tstruct {\n\t\t__kernel_pid_t _pid;\n\t\t__kernel_uid32_t _uid;\n\t\tsigval_t _sigval;\n\t} _rt;\n\tstruct {\n\t\t__kernel_pid_t _pid;\n\t\t__kernel_uid32_t _uid;\n\t\tint _status;\n\t\t__kernel_clock_t _utime;\n\t\t__kernel_clock_t _stime;\n\t} _sigchld;\n\tstruct {\n\t\tvoid *_addr;\n\t\tunion {\n\t\t\tint _trapno;\n\t\t\tshort int _addr_lsb;\n\t\t\tstruct {\n\t\t\t\tchar _dummy_bnd[8];\n\t\t\t\tvoid *_lower;\n\t\t\t\tvoid *_upper;\n\t\t\t} _addr_bnd;\n\t\t\tstruct {\n\t\t\t\tchar _dummy_pkey[8];\n\t\t\t\t__u32 _pkey;\n\t\t\t} _addr_pkey;\n\t\t\tstruct {\n\t\t\t\tlong unsigned int _data;\n\t\t\t\t__u32 _type;\n\t\t\t} _perf;\n\t\t};\n\t} _sigfault;\n\tstruct {\n\t\tlong int _band;\n\t\tint _fd;\n\t} _sigpoll;\n\tstruct {\n\t\tvoid *_call_addr;\n\t\tint _syscall;\n\t\tunsigned int _arch;\n\t} _sigsys;\n};\n\nstruct kernel_siginfo {\n\tstruct {\n\t\tint si_signo;\n\t\tint si_errno;\n\t\tint si_code;\n\t\tunion __sifields _sifields;\n\t};\n};\n\nstruct sigaction {\n\t__sighandler_t sa_handler;\n\tlong unsigned int sa_flags;\n\t__sigrestore_t sa_restorer;\n\tsigset_t sa_mask;\n};\n\nstruct k_sigaction {\n\tstruct sigaction sa;\n};\n\nstruct cpu_itimer {\n\tu64 expires;\n\tu64 incr;\n};\n\nstruct task_cputime_atomic {\n\tatomic64_t utime;\n\tatomic64_t stime;\n\tatomic64_t sum_exec_runtime;\n};\n\nstruct thread_group_cputimer {\n\tstruct task_cputime_atomic cputime_atomic;\n};\n\nstruct pacct_struct {\n\tint ac_flag;\n\tlong int ac_exitcode;\n\tlong unsigned int ac_mem;\n\tu64 ac_utime;\n\tu64 ac_stime;\n\tlong unsigned int ac_minflt;\n\tlong unsigned int ac_majflt;\n};\n\nstruct tty_struct;\n\nstruct autogroup;\n\nstruct taskstats;\n\nstruct tty_audit_buf;\n\nstruct signal_struct {\n\trefcount_t sigcnt;\n\tatomic_t live;\n\tint nr_threads;\n\tstruct list_head thread_head;\n\twait_queue_head_t wait_chldexit;\n\tstruct task_struct *curr_target;\n\tstruct sigpending shared_pending;\n\tstruct hlist_head multiprocess;\n\tint group_exit_code;\n\tint notify_count;\n\tstruct task_struct *group_exit_task;\n\tint group_stop_count;\n\tunsigned int flags;\n\tunsigned int is_child_subreaper: 1;\n\tunsigned int has_child_subreaper: 1;\n\tint posix_timer_id;\n\tstruct list_head posix_timers;\n\tstruct hrtimer real_timer;\n\tktime_t it_real_incr;\n\tstruct cpu_itimer it[2];\n\tstruct thread_group_cputimer cputimer;\n\tstruct posix_cputimers posix_cputimers;\n\tstruct pid *pids[4];\n\tstruct pid *tty_old_pgrp;\n\tint leader;\n\tstruct tty_struct *tty;\n\tstruct autogroup *autogroup;\n\tseqlock_t stats_lock;\n\tu64 utime;\n\tu64 stime;\n\tu64 cutime;\n\tu64 cstime;\n\tu64 gtime;\n\tu64 cgtime;\n\tstruct prev_cputime prev_cputime;\n\tlong unsigned int nvcsw;\n\tlong unsigned int nivcsw;\n\tlong unsigned int cnvcsw;\n\tlong unsigned int cnivcsw;\n\tlong unsigned int min_flt;\n\tlong unsigned int maj_flt;\n\tlong unsigned int cmin_flt;\n\tlong unsigned int cmaj_flt;\n\tlong unsigned int inblock;\n\tlong unsigned int oublock;\n\tlong unsigned int cinblock;\n\tlong unsigned int coublock;\n\tlong unsigned int maxrss;\n\tlong unsigned int cmaxrss;\n\tstruct task_io_accounting ioac;\n\tlong long unsigned int sum_sched_runtime;\n\tstruct rlimit rlim[16];\n\tstruct pacct_struct pacct;\n\tstruct taskstats *stats;\n\tunsigned int audit_tty;\n\tstruct tty_audit_buf *tty_audit_buf;\n\tbool oom_flag_origin;\n\tshort int oom_score_adj;\n\tshort int oom_score_adj_min;\n\tstruct mm_struct *oom_mm;\n\tstruct mutex cred_guard_mutex;\n\tstruct rw_semaphore exec_update_lock;\n};\n\nenum rseq_cs_flags_bit {\n\tRSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0,\n\tRSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1,\n\tRSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2,\n};\n\nstruct rseq {\n\t__u32 cpu_id_start;\n\t__u32 cpu_id;\n\tunion {\n\t\t__u64 ptr64;\n\t\t__u64 ptr;\n\t} rseq_cs;\n\t__u32 flags;\n\tlong: 32;\n\tlong: 64;\n};\n\nenum uclamp_id {\n\tUCLAMP_MIN = 0,\n\tUCLAMP_MAX = 1,\n\tUCLAMP_CNT = 2,\n};\n\nenum perf_event_task_context {\n\tperf_invalid_context = 4294967295,\n\tperf_hw_context = 0,\n\tperf_sw_context = 1,\n\tperf_nr_task_contexts = 2,\n};\n\nstruct rq;\n\nstruct rq_flags;\n\nstruct sched_class {\n\tint uclamp_enabled;\n\tvoid (*enqueue_task)(struct rq *, struct task_struct *, int);\n\tvoid (*dequeue_task)(struct rq *, struct task_struct *, int);\n\tvoid (*yield_task)(struct rq *);\n\tbool (*yield_to_task)(struct rq *, struct task_struct *);\n\tvoid (*check_preempt_curr)(struct rq *, struct task_struct *, int);\n\tstruct task_struct * (*pick_next_task)(struct rq *);\n\tvoid (*put_prev_task)(struct rq *, struct task_struct *);\n\tvoid (*set_next_task)(struct rq *, struct task_struct *, bool);\n\tint (*balance)(struct rq *, struct task_struct *, struct rq_flags *);\n\tint (*select_task_rq)(struct task_struct *, int, int);\n\tstruct task_struct * (*pick_task)(struct rq *);\n\tvoid (*migrate_task_rq)(struct task_struct *, int);\n\tvoid (*task_woken)(struct rq *, struct task_struct *);\n\tvoid (*set_cpus_allowed)(struct task_struct *, const struct cpumask *, u32);\n\tvoid (*rq_online)(struct rq *);\n\tvoid (*rq_offline)(struct rq *);\n\tstruct rq * (*find_lock_rq)(struct task_struct *, struct rq *);\n\tvoid (*task_tick)(struct rq *, struct task_struct *, int);\n\tvoid (*task_fork)(struct task_struct *);\n\tvoid (*task_dead)(struct task_struct *);\n\tvoid (*switched_from)(struct rq *, struct task_struct *);\n\tvoid (*switched_to)(struct rq *, struct task_struct *);\n\tvoid (*prio_changed)(struct rq *, struct task_struct *, int);\n\tunsigned int (*get_rr_interval)(struct rq *, struct task_struct *);\n\tvoid (*update_curr)(struct rq *);\n\tvoid (*task_change_group)(struct task_struct *, int);\n};\n\nstruct kernel_cap_struct {\n\t__u32 cap[2];\n};\n\ntypedef struct kernel_cap_struct kernel_cap_t;\n\nstruct user_struct;\n\nstruct ucounts;\n\nstruct group_info;\n\nstruct cred {\n\tatomic_t usage;\n\tkuid_t uid;\n\tkgid_t gid;\n\tkuid_t suid;\n\tkgid_t sgid;\n\tkuid_t euid;\n\tkgid_t egid;\n\tkuid_t fsuid;\n\tkgid_t fsgid;\n\tunsigned int securebits;\n\tkernel_cap_t cap_inheritable;\n\tkernel_cap_t cap_permitted;\n\tkernel_cap_t cap_effective;\n\tkernel_cap_t cap_bset;\n\tkernel_cap_t cap_ambient;\n\tunsigned char jit_keyring;\n\tstruct key *session_keyring;\n\tstruct key *process_keyring;\n\tstruct key *thread_keyring;\n\tstruct key *request_key_auth;\n\tvoid *security;\n\tstruct user_struct *user;\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tstruct group_info *group_info;\n\tunion {\n\t\tint non_rcu;\n\t\tstruct callback_head rcu;\n\t};\n};\n\ntypedef int32_t key_serial_t;\n\ntypedef uint32_t key_perm_t;\n\nstruct key_type;\n\nstruct key_tag;\n\nstruct keyring_index_key {\n\tlong unsigned int hash;\n\tunion {\n\t\tstruct {\n\t\t\tu16 desc_len;\n\t\t\tchar desc[6];\n\t\t};\n\t\tlong unsigned int x;\n\t};\n\tstruct key_type *type;\n\tstruct key_tag *domain_tag;\n\tconst char *description;\n};\n\nunion key_payload {\n\tvoid *rcu_data0;\n\tvoid *data[4];\n};\n\nstruct assoc_array_ptr;\n\nstruct assoc_array {\n\tstruct assoc_array_ptr *root;\n\tlong unsigned int nr_leaves_on_tree;\n};\n\nstruct watch_list;\n\nstruct key_user;\n\nstruct key_restriction;\n\nstruct key {\n\trefcount_t usage;\n\tkey_serial_t serial;\n\tunion {\n\t\tstruct list_head graveyard_link;\n\t\tstruct rb_node serial_node;\n\t};\n\tstruct watch_list *watchers;\n\tstruct rw_semaphore sem;\n\tstruct key_user *user;\n\tvoid *security;\n\tunion {\n\t\ttime64_t expiry;\n\t\ttime64_t revoked_at;\n\t};\n\ttime64_t last_used_at;\n\tkuid_t uid;\n\tkgid_t gid;\n\tkey_perm_t perm;\n\tshort unsigned int quotalen;\n\tshort unsigned int datalen;\n\tshort int state;\n\tlong unsigned int flags;\n\tunion {\n\t\tstruct keyring_index_key index_key;\n\t\tstruct {\n\t\t\tlong unsigned int hash;\n\t\t\tlong unsigned int len_desc;\n\t\t\tstruct key_type *type;\n\t\t\tstruct key_tag *domain_tag;\n\t\t\tchar *description;\n\t\t};\n\t};\n\tunion {\n\t\tunion key_payload payload;\n\t\tstruct {\n\t\t\tstruct list_head name_link;\n\t\t\tstruct assoc_array keys;\n\t\t};\n\t};\n\tstruct key_restriction *restrict_link;\n};\n\nstruct sighand_struct {\n\tspinlock_t siglock;\n\trefcount_t count;\n\twait_queue_head_t signalfd_wqh;\n\tstruct k_sigaction action[64];\n};\n\nstruct io_cq;\n\nstruct io_context {\n\tatomic_long_t refcount;\n\tatomic_t active_ref;\n\tatomic_t nr_tasks;\n\tspinlock_t lock;\n\tshort unsigned int ioprio;\n\tstruct xarray icq_tree;\n\tstruct io_cq *icq_hint;\n\tstruct hlist_head icq_list;\n\tstruct work_struct release_work;\n};\n\nenum rseq_event_mask_bits {\n\tRSEQ_EVENT_PREEMPT_BIT = 0,\n\tRSEQ_EVENT_SIGNAL_BIT = 1,\n\tRSEQ_EVENT_MIGRATE_BIT = 2,\n};\n\nenum fixed_addresses {\n\tVSYSCALL_PAGE = 511,\n\tFIX_DBGP_BASE = 512,\n\tFIX_EARLYCON_MEM_BASE = 513,\n\tFIX_APIC_BASE = 514,\n\tFIX_IO_APIC_BASE_0 = 515,\n\tFIX_IO_APIC_BASE_END = 642,\n\tFIX_PARAVIRT_BOOTMAP = 643,\n\tFIX_APEI_GHES_IRQ = 644,\n\tFIX_APEI_GHES_NMI = 645,\n\t__end_of_permanent_fixed_addresses = 646,\n\tFIX_BTMAP_END = 1024,\n\tFIX_BTMAP_BEGIN = 1535,\n\t__end_of_fixed_addresses = 1536,\n};\n\nstruct hlist_bl_node;\n\nstruct hlist_bl_head {\n\tstruct hlist_bl_node *first;\n};\n\nstruct hlist_bl_node {\n\tstruct hlist_bl_node *next;\n\tstruct hlist_bl_node **pprev;\n};\n\nstruct lockref {\n\tunion {\n\t\t__u64 lock_count;\n\t\tstruct {\n\t\t\tspinlock_t lock;\n\t\t\tint count;\n\t\t};\n\t};\n};\n\nstruct qstr {\n\tunion {\n\t\tstruct {\n\t\t\tu32 hash;\n\t\t\tu32 len;\n\t\t};\n\t\tu64 hash_len;\n\t};\n\tconst unsigned char *name;\n};\n\nstruct dentry_operations;\n\nstruct dentry {\n\tunsigned int d_flags;\n\tseqcount_spinlock_t d_seq;\n\tstruct hlist_bl_node d_hash;\n\tstruct dentry *d_parent;\n\tstruct qstr d_name;\n\tstruct inode *d_inode;\n\tunsigned char d_iname[32];\n\tstruct lockref d_lockref;\n\tconst struct dentry_operations *d_op;\n\tstruct super_block *d_sb;\n\tlong unsigned int d_time;\n\tvoid *d_fsdata;\n\tunion {\n\t\tstruct list_head d_lru;\n\t\twait_queue_head_t *d_wait;\n\t};\n\tstruct list_head d_child;\n\tstruct list_head d_subdirs;\n\tunion {\n\t\tstruct hlist_node d_alias;\n\t\tstruct hlist_bl_node d_in_lookup_hash;\n\t\tstruct callback_head d_rcu;\n\t} d_u;\n};\n\nstruct posix_acl;\n\nstruct inode_operations;\n\nstruct bdi_writeback;\n\nstruct file_lock_context;\n\nstruct cdev;\n\nstruct fsnotify_mark_connector;\n\nstruct fscrypt_info;\n\nstruct fsverity_info;\n\nstruct inode {\n\tumode_t i_mode;\n\tshort unsigned int i_opflags;\n\tkuid_t i_uid;\n\tkgid_t i_gid;\n\tunsigned int i_flags;\n\tstruct posix_acl *i_acl;\n\tstruct posix_acl *i_default_acl;\n\tconst struct inode_operations *i_op;\n\tstruct super_block *i_sb;\n\tstruct address_space *i_mapping;\n\tvoid *i_security;\n\tlong unsigned int i_ino;\n\tunion {\n\t\tconst unsigned int i_nlink;\n\t\tunsigned int __i_nlink;\n\t};\n\tdev_t i_rdev;\n\tloff_t i_size;\n\tstruct timespec64 i_atime;\n\tstruct timespec64 i_mtime;\n\tstruct timespec64 i_ctime;\n\tspinlock_t i_lock;\n\tshort unsigned int i_bytes;\n\tu8 i_blkbits;\n\tu8 i_write_hint;\n\tblkcnt_t i_blocks;\n\tlong unsigned int i_state;\n\tstruct rw_semaphore i_rwsem;\n\tlong unsigned int dirtied_when;\n\tlong unsigned int dirtied_time_when;\n\tstruct hlist_node i_hash;\n\tstruct list_head i_io_list;\n\tstruct bdi_writeback *i_wb;\n\tint i_wb_frn_winner;\n\tu16 i_wb_frn_avg_time;\n\tu16 i_wb_frn_history;\n\tstruct list_head i_lru;\n\tstruct list_head i_sb_list;\n\tstruct list_head i_wb_list;\n\tunion {\n\t\tstruct hlist_head i_dentry;\n\t\tstruct callback_head i_rcu;\n\t};\n\tatomic64_t i_version;\n\tatomic64_t i_sequence;\n\tatomic_t i_count;\n\tatomic_t i_dio_count;\n\tatomic_t i_writecount;\n\tatomic_t i_readcount;\n\tunion {\n\t\tconst struct file_operations *i_fop;\n\t\tvoid (*free_inode)(struct inode *);\n\t};\n\tstruct file_lock_context *i_flctx;\n\tstruct address_space i_data;\n\tstruct list_head i_devices;\n\tunion {\n\t\tstruct pipe_inode_info *i_pipe;\n\t\tstruct cdev *i_cdev;\n\t\tchar *i_link;\n\t\tunsigned int i_dir_seq;\n\t};\n\t__u32 i_generation;\n\t__u32 i_fsnotify_mask;\n\tstruct fsnotify_mark_connector *i_fsnotify_marks;\n\tstruct fscrypt_info *i_crypt_info;\n\tstruct fsverity_info *i_verity_info;\n\tvoid *i_private;\n};\n\nstruct dentry_operations {\n\tint (*d_revalidate)(struct dentry *, unsigned int);\n\tint (*d_weak_revalidate)(struct dentry *, unsigned int);\n\tint (*d_hash)(const struct dentry *, struct qstr *);\n\tint (*d_compare)(const struct dentry *, unsigned int, const char *, const struct qstr *);\n\tint (*d_delete)(const struct dentry *);\n\tint (*d_init)(struct dentry *);\n\tvoid (*d_release)(struct dentry *);\n\tvoid (*d_prune)(struct dentry *);\n\tvoid (*d_iput)(struct dentry *, struct inode *);\n\tchar * (*d_dname)(struct dentry *, char *, int);\n\tstruct vfsmount * (*d_automount)(struct path *);\n\tint (*d_manage)(const struct path *, bool);\n\tstruct dentry * (*d_real)(struct dentry *, const struct inode *);\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct mtd_info;\n\ntypedef long long int qsize_t;\n\nstruct quota_format_type;\n\nstruct mem_dqinfo {\n\tstruct quota_format_type *dqi_format;\n\tint dqi_fmt_id;\n\tstruct list_head dqi_dirty_list;\n\tlong unsigned int dqi_flags;\n\tunsigned int dqi_bgrace;\n\tunsigned int dqi_igrace;\n\tqsize_t dqi_max_spc_limit;\n\tqsize_t dqi_max_ino_limit;\n\tvoid *dqi_priv;\n};\n\nstruct quota_format_ops;\n\nstruct quota_info {\n\tunsigned int flags;\n\tstruct rw_semaphore dqio_sem;\n\tstruct inode *files[3];\n\tstruct mem_dqinfo info[3];\n\tconst struct quota_format_ops *ops[3];\n};\n\nstruct rcu_sync {\n\tint gp_state;\n\tint gp_count;\n\twait_queue_head_t gp_wait;\n\tstruct callback_head cb_head;\n};\n\nstruct rcuwait {\n\tstruct task_struct *task;\n};\n\nstruct percpu_rw_semaphore {\n\tstruct rcu_sync rss;\n\tunsigned int *read_count;\n\tstruct rcuwait writer;\n\twait_queue_head_t waiters;\n\tatomic_t block;\n};\n\nstruct sb_writers {\n\tint frozen;\n\twait_queue_head_t wait_unfrozen;\n\tstruct percpu_rw_semaphore rw_sem[3];\n};\n\ntypedef struct {\n\t__u8 b[16];\n} uuid_t;\n\nstruct list_lru_node;\n\nstruct list_lru {\n\tstruct list_lru_node *node;\n\tstruct list_head list;\n\tint shrinker_id;\n\tbool memcg_aware;\n};\n\nstruct super_operations;\n\nstruct dquot_operations;\n\nstruct quotactl_ops;\n\nstruct export_operations;\n\nstruct xattr_handler;\n\nstruct fscrypt_operations;\n\nstruct fsverity_operations;\n\nstruct unicode_map;\n\nstruct block_device;\n\nstruct workqueue_struct;\n\nstruct super_block {\n\tstruct list_head s_list;\n\tdev_t s_dev;\n\tunsigned char s_blocksize_bits;\n\tlong unsigned int s_blocksize;\n\tloff_t s_maxbytes;\n\tstruct file_system_type *s_type;\n\tconst struct super_operations *s_op;\n\tconst struct dquot_operations *dq_op;\n\tconst struct quotactl_ops *s_qcop;\n\tconst struct export_operations *s_export_op;\n\tlong unsigned int s_flags;\n\tlong unsigned int s_iflags;\n\tlong unsigned int s_magic;\n\tstruct dentry *s_root;\n\tstruct rw_semaphore s_umount;\n\tint s_count;\n\tatomic_t s_active;\n\tvoid *s_security;\n\tconst struct xattr_handler **s_xattr;\n\tconst struct fscrypt_operations *s_cop;\n\tstruct key *s_master_keys;\n\tconst struct fsverity_operations *s_vop;\n\tstruct unicode_map *s_encoding;\n\t__u16 s_encoding_flags;\n\tstruct hlist_bl_head s_roots;\n\tstruct list_head s_mounts;\n\tstruct block_device *s_bdev;\n\tstruct backing_dev_info *s_bdi;\n\tstruct mtd_info *s_mtd;\n\tstruct hlist_node s_instances;\n\tunsigned int s_quota_types;\n\tstruct quota_info s_dquot;\n\tstruct sb_writers s_writers;\n\tvoid *s_fs_info;\n\tu32 s_time_gran;\n\ttime64_t s_time_min;\n\ttime64_t s_time_max;\n\t__u32 s_fsnotify_mask;\n\tstruct fsnotify_mark_connector *s_fsnotify_marks;\n\tchar s_id[32];\n\tuuid_t s_uuid;\n\tunsigned int s_max_links;\n\tfmode_t s_mode;\n\tstruct mutex s_vfs_rename_mutex;\n\tconst char *s_subtype;\n\tconst struct dentry_operations *s_d_op;\n\tint cleancache_poolid;\n\tstruct shrinker s_shrink;\n\tatomic_long_t s_remove_count;\n\tatomic_long_t s_fsnotify_inode_refs;\n\tint s_readonly_remount;\n\terrseq_t s_wb_err;\n\tstruct workqueue_struct *s_dio_done_wq;\n\tstruct hlist_head s_pins;\n\tstruct user_namespace *s_user_ns;\n\tstruct list_lru s_dentry_lru;\n\tstruct list_lru s_inode_lru;\n\tstruct callback_head rcu;\n\tstruct work_struct destroy_work;\n\tstruct mutex s_sync_lock;\n\tint s_stack_depth;\n\tint: 32;\n\tspinlock_t s_inode_list_lock;\n\tstruct list_head s_inodes;\n\tspinlock_t s_inode_wblist_lock;\n\tstruct list_head s_inodes_wb;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct vfsmount {\n\tstruct dentry *mnt_root;\n\tstruct super_block *mnt_sb;\n\tint mnt_flags;\n\tstruct user_namespace *mnt_userns;\n};\n\nstruct kstat {\n\tu32 result_mask;\n\tumode_t mode;\n\tunsigned int nlink;\n\tuint32_t blksize;\n\tu64 attributes;\n\tu64 attributes_mask;\n\tu64 ino;\n\tdev_t dev;\n\tdev_t rdev;\n\tkuid_t uid;\n\tkgid_t gid;\n\tloff_t size;\n\tstruct timespec64 atime;\n\tstruct timespec64 mtime;\n\tstruct timespec64 ctime;\n\tstruct timespec64 btime;\n\tu64 blocks;\n\tu64 mnt_id;\n};\n\nstruct list_lru_one {\n\tstruct list_head list;\n\tlong int nr_items;\n};\n\nstruct list_lru_memcg {\n\tstruct callback_head rcu;\n\tstruct list_lru_one *lru[0];\n};\n\nstruct list_lru_node {\n\tspinlock_t lock;\n\tstruct list_lru_one lru;\n\tstruct list_lru_memcg *memcg_lrus;\n\tlong int nr_items;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum migrate_mode {\n\tMIGRATE_ASYNC = 0,\n\tMIGRATE_SYNC_LIGHT = 1,\n\tMIGRATE_SYNC = 2,\n\tMIGRATE_SYNC_NO_COPY = 3,\n};\n\nstruct key_tag {\n\tstruct callback_head rcu;\n\trefcount_t usage;\n\tbool removed;\n};\n\ntypedef int (*request_key_actor_t)(struct key *, void *);\n\nstruct key_preparsed_payload;\n\nstruct key_match_data;\n\nstruct kernel_pkey_params;\n\nstruct kernel_pkey_query;\n\nstruct key_type {\n\tconst char *name;\n\tsize_t def_datalen;\n\tunsigned int flags;\n\tint (*vet_description)(const char *);\n\tint (*preparse)(struct key_preparsed_payload *);\n\tvoid (*free_preparse)(struct key_preparsed_payload *);\n\tint (*instantiate)(struct key *, struct key_preparsed_payload *);\n\tint (*update)(struct key *, struct key_preparsed_payload *);\n\tint (*match_preparse)(struct key_match_data *);\n\tvoid (*match_free)(struct key_match_data *);\n\tvoid (*revoke)(struct key *);\n\tvoid (*destroy)(struct key *);\n\tvoid (*describe)(const struct key *, struct seq_file *);\n\tlong int (*read)(const struct key *, char *, size_t);\n\trequest_key_actor_t request_key;\n\tstruct key_restriction * (*lookup_restriction)(const char *);\n\tint (*asym_query)(const struct kernel_pkey_params *, struct kernel_pkey_query *);\n\tint (*asym_eds_op)(struct kernel_pkey_params *, const void *, void *);\n\tint (*asym_verify_signature)(struct kernel_pkey_params *, const void *, const void *);\n\tstruct list_head link;\n\tstruct lock_class_key lock_class;\n};\n\ntypedef int (*key_restrict_link_func_t)(struct key *, const struct key_type *, const union key_payload *, struct key *);\n\nstruct key_restriction {\n\tkey_restrict_link_func_t check;\n\tstruct key *key;\n\tstruct key_type *keytype;\n};\n\nstruct user_struct {\n\trefcount_t __count;\n\tatomic_long_t epoll_watches;\n\tlong unsigned int unix_inflight;\n\tatomic_long_t pipe_bufs;\n\tstruct hlist_node uidhash_node;\n\tkuid_t uid;\n\tatomic_long_t locked_vm;\n\tatomic_t nr_watches;\n\tstruct ratelimit_state ratelimit;\n};\n\nstruct group_info {\n\tatomic_t usage;\n\tint ngroups;\n\tkgid_t gid[0];\n};\n\nstruct delayed_call {\n\tvoid (*fn)(void *);\n\tvoid *arg;\n};\n\nstruct io_cq {\n\tstruct request_queue *q;\n\tstruct io_context *ioc;\n\tunion {\n\t\tstruct list_head q_node;\n\t\tstruct kmem_cache *__rcu_icq_cache;\n\t};\n\tunion {\n\t\tstruct hlist_node ioc_node;\n\t\tstruct callback_head __rcu_head;\n\t};\n\tunsigned int flags;\n};\n\nstruct wait_page_queue;\n\nstruct kiocb {\n\tstruct file *ki_filp;\n\tloff_t ki_pos;\n\tvoid (*ki_complete)(struct kiocb *, long int, long int);\n\tvoid *private;\n\tint ki_flags;\n\tu16 ki_hint;\n\tu16 ki_ioprio;\n\tunion {\n\t\tunsigned int ki_cookie;\n\t\tstruct wait_page_queue *ki_waitq;\n\t};\n};\n\nstruct iattr {\n\tunsigned int ia_valid;\n\tumode_t ia_mode;\n\tkuid_t ia_uid;\n\tkgid_t ia_gid;\n\tloff_t ia_size;\n\tstruct timespec64 ia_atime;\n\tstruct timespec64 ia_mtime;\n\tstruct timespec64 ia_ctime;\n\tstruct file *ia_file;\n};\n\ntypedef __kernel_uid32_t projid_t;\n\ntypedef struct {\n\tprojid_t val;\n} kprojid_t;\n\nenum quota_type {\n\tUSRQUOTA = 0,\n\tGRPQUOTA = 1,\n\tPRJQUOTA = 2,\n};\n\nstruct kqid {\n\tunion {\n\t\tkuid_t uid;\n\t\tkgid_t gid;\n\t\tkprojid_t projid;\n\t};\n\tenum quota_type type;\n};\n\nstruct mem_dqblk {\n\tqsize_t dqb_bhardlimit;\n\tqsize_t dqb_bsoftlimit;\n\tqsize_t dqb_curspace;\n\tqsize_t dqb_rsvspace;\n\tqsize_t dqb_ihardlimit;\n\tqsize_t dqb_isoftlimit;\n\tqsize_t dqb_curinodes;\n\ttime64_t dqb_btime;\n\ttime64_t dqb_itime;\n};\n\nstruct dquot {\n\tstruct hlist_node dq_hash;\n\tstruct list_head dq_inuse;\n\tstruct list_head dq_free;\n\tstruct list_head dq_dirty;\n\tstruct mutex dq_lock;\n\tspinlock_t dq_dqb_lock;\n\tatomic_t dq_count;\n\tstruct super_block *dq_sb;\n\tstruct kqid dq_id;\n\tloff_t dq_off;\n\tlong unsigned int dq_flags;\n\tstruct mem_dqblk dq_dqb;\n};\n\nenum {\n\tDQF_ROOT_SQUASH_B = 0,\n\tDQF_SYS_FILE_B = 16,\n\tDQF_PRIVATE = 17,\n};\n\nstruct quota_format_type {\n\tint qf_fmt_id;\n\tconst struct quota_format_ops *qf_ops;\n\tstruct module *qf_owner;\n\tstruct quota_format_type *qf_next;\n};\n\nenum {\n\tDQST_LOOKUPS = 0,\n\tDQST_DROPS = 1,\n\tDQST_READS = 2,\n\tDQST_WRITES = 3,\n\tDQST_CACHE_HITS = 4,\n\tDQST_ALLOC_DQUOTS = 5,\n\tDQST_FREE_DQUOTS = 6,\n\tDQST_SYNCS = 7,\n\t_DQST_DQSTAT_LAST = 8,\n};\n\nstruct quota_format_ops {\n\tint (*check_quota_file)(struct super_block *, int);\n\tint (*read_file_info)(struct super_block *, int);\n\tint (*write_file_info)(struct super_block *, int);\n\tint (*free_file_info)(struct super_block *, int);\n\tint (*read_dqblk)(struct dquot *);\n\tint (*commit_dqblk)(struct dquot *);\n\tint (*release_dqblk)(struct dquot *);\n\tint (*get_next_id)(struct super_block *, struct kqid *);\n};\n\nstruct dquot_operations {\n\tint (*write_dquot)(struct dquot *);\n\tstruct dquot * (*alloc_dquot)(struct super_block *, int);\n\tvoid (*destroy_dquot)(struct dquot *);\n\tint (*acquire_dquot)(struct dquot *);\n\tint (*release_dquot)(struct dquot *);\n\tint (*mark_dirty)(struct dquot *);\n\tint (*write_info)(struct super_block *, int);\n\tqsize_t * (*get_reserved_space)(struct inode *);\n\tint (*get_projid)(struct inode *, kprojid_t *);\n\tint (*get_inode_usage)(struct inode *, qsize_t *);\n\tint (*get_next_id)(struct super_block *, struct kqid *);\n};\n\nstruct qc_dqblk {\n\tint d_fieldmask;\n\tu64 d_spc_hardlimit;\n\tu64 d_spc_softlimit;\n\tu64 d_ino_hardlimit;\n\tu64 d_ino_softlimit;\n\tu64 d_space;\n\tu64 d_ino_count;\n\ts64 d_ino_timer;\n\ts64 d_spc_timer;\n\tint d_ino_warns;\n\tint d_spc_warns;\n\tu64 d_rt_spc_hardlimit;\n\tu64 d_rt_spc_softlimit;\n\tu64 d_rt_space;\n\ts64 d_rt_spc_timer;\n\tint d_rt_spc_warns;\n};\n\nstruct qc_type_state {\n\tunsigned int flags;\n\tunsigned int spc_timelimit;\n\tunsigned int ino_timelimit;\n\tunsigned int rt_spc_timelimit;\n\tunsigned int spc_warnlimit;\n\tunsigned int ino_warnlimit;\n\tunsigned int rt_spc_warnlimit;\n\tlong long unsigned int ino;\n\tblkcnt_t blocks;\n\tblkcnt_t nextents;\n};\n\nstruct qc_state {\n\tunsigned int s_incoredqs;\n\tstruct qc_type_state s_state[3];\n};\n\nstruct qc_info {\n\tint i_fieldmask;\n\tunsigned int i_flags;\n\tunsigned int i_spc_timelimit;\n\tunsigned int i_ino_timelimit;\n\tunsigned int i_rt_spc_timelimit;\n\tunsigned int i_spc_warnlimit;\n\tunsigned int i_ino_warnlimit;\n\tunsigned int i_rt_spc_warnlimit;\n};\n\nstruct quotactl_ops {\n\tint (*quota_on)(struct super_block *, int, int, const struct path *);\n\tint (*quota_off)(struct super_block *, int);\n\tint (*quota_enable)(struct super_block *, unsigned int);\n\tint (*quota_disable)(struct super_block *, unsigned int);\n\tint (*quota_sync)(struct super_block *, int);\n\tint (*set_info)(struct super_block *, int, struct qc_info *);\n\tint (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *);\n\tint (*get_nextdqblk)(struct super_block *, struct kqid *, struct qc_dqblk *);\n\tint (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *);\n\tint (*get_state)(struct super_block *, struct qc_state *);\n\tint (*rm_xquota)(struct super_block *, unsigned int);\n};\n\nstruct writeback_control;\n\nstruct readahead_control;\n\nstruct swap_info_struct;\n\nstruct address_space_operations {\n\tint (*writepage)(struct page *, struct writeback_control *);\n\tint (*readpage)(struct file *, struct page *);\n\tint (*writepages)(struct address_space *, struct writeback_control *);\n\tint (*set_page_dirty)(struct page *);\n\tint (*readpages)(struct file *, struct address_space *, struct list_head *, unsigned int);\n\tvoid (*readahead)(struct readahead_control *);\n\tint (*write_begin)(struct file *, struct address_space *, loff_t, unsigned int, unsigned int, struct page **, void **);\n\tint (*write_end)(struct file *, struct address_space *, loff_t, unsigned int, unsigned int, struct page *, void *);\n\tsector_t (*bmap)(struct address_space *, sector_t);\n\tvoid (*invalidatepage)(struct page *, unsigned int, unsigned int);\n\tint (*releasepage)(struct page *, gfp_t);\n\tvoid (*freepage)(struct page *);\n\tssize_t (*direct_IO)(struct kiocb *, struct iov_iter *);\n\tint (*migratepage)(struct address_space *, struct page *, struct page *, enum migrate_mode);\n\tbool (*isolate_page)(struct page *, isolate_mode_t);\n\tvoid (*putback_page)(struct page *);\n\tint (*launder_page)(struct page *);\n\tint (*is_partially_uptodate)(struct page *, long unsigned int, long unsigned int);\n\tvoid (*is_dirty_writeback)(struct page *, bool *, bool *);\n\tint (*error_remove_page)(struct address_space *, struct page *);\n\tint (*swap_activate)(struct swap_info_struct *, struct file *, sector_t *);\n\tvoid (*swap_deactivate)(struct file *);\n};\n\nstruct fiemap_extent_info;\n\nstruct fileattr;\n\nstruct inode_operations {\n\tstruct dentry * (*lookup)(struct inode *, struct dentry *, unsigned int);\n\tconst char * (*get_link)(struct dentry *, struct inode *, struct delayed_call *);\n\tint (*permission)(struct user_namespace *, struct inode *, int);\n\tstruct posix_acl * (*get_acl)(struct inode *, int);\n\tint (*readlink)(struct dentry *, char *, int);\n\tint (*create)(struct user_namespace *, struct inode *, struct dentry *, umode_t, bool);\n\tint (*link)(struct dentry *, struct inode *, struct dentry *);\n\tint (*unlink)(struct inode *, struct dentry *);\n\tint (*symlink)(struct user_namespace *, struct inode *, struct dentry *, const char *);\n\tint (*mkdir)(struct user_namespace *, struct inode *, struct dentry *, umode_t);\n\tint (*rmdir)(struct inode *, struct dentry *);\n\tint (*mknod)(struct user_namespace *, struct inode *, struct dentry *, umode_t, dev_t);\n\tint (*rename)(struct user_namespace *, struct inode *, struct dentry *, struct inode *, struct dentry *, unsigned int);\n\tint (*setattr)(struct user_namespace *, struct dentry *, struct iattr *);\n\tint (*getattr)(struct user_namespace *, const struct path *, struct kstat *, u32, unsigned int);\n\tssize_t (*listxattr)(struct dentry *, char *, size_t);\n\tint (*fiemap)(struct inode *, struct fiemap_extent_info *, u64, u64);\n\tint (*update_time)(struct inode *, struct timespec64 *, int);\n\tint (*atomic_open)(struct inode *, struct dentry *, struct file *, unsigned int, umode_t);\n\tint (*tmpfile)(struct user_namespace *, struct inode *, struct dentry *, umode_t);\n\tint (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int);\n\tint (*fileattr_set)(struct user_namespace *, struct dentry *, struct fileattr *);\n\tint (*fileattr_get)(struct dentry *, struct fileattr *);\n\tlong: 64;\n};\n\nstruct file_lock_context {\n\tspinlock_t flc_lock;\n\tstruct list_head flc_flock;\n\tstruct list_head flc_posix;\n\tstruct list_head flc_lease;\n};\n\nstruct file_lock_operations {\n\tvoid (*fl_copy_lock)(struct file_lock *, struct file_lock *);\n\tvoid (*fl_release_private)(struct file_lock *);\n};\n\nstruct nlm_lockowner;\n\nstruct nfs_lock_info {\n\tu32 state;\n\tstruct nlm_lockowner *owner;\n\tstruct list_head list;\n};\n\nstruct nfs4_lock_state;\n\nstruct nfs4_lock_info {\n\tstruct nfs4_lock_state *owner;\n};\n\nstruct fasync_struct;\n\nstruct lock_manager_operations;\n\nstruct file_lock {\n\tstruct file_lock *fl_blocker;\n\tstruct list_head fl_list;\n\tstruct hlist_node fl_link;\n\tstruct list_head fl_blocked_requests;\n\tstruct list_head fl_blocked_member;\n\tfl_owner_t fl_owner;\n\tunsigned int fl_flags;\n\tunsigned char fl_type;\n\tunsigned int fl_pid;\n\tint fl_link_cpu;\n\twait_queue_head_t fl_wait;\n\tstruct file *fl_file;\n\tloff_t fl_start;\n\tloff_t fl_end;\n\tstruct fasync_struct *fl_fasync;\n\tlong unsigned int fl_break_time;\n\tlong unsigned int fl_downgrade_time;\n\tconst struct file_lock_operations *fl_ops;\n\tconst struct lock_manager_operations *fl_lmops;\n\tunion {\n\t\tstruct nfs_lock_info nfs_fl;\n\t\tstruct nfs4_lock_info nfs4_fl;\n\t\tstruct {\n\t\t\tstruct list_head link;\n\t\t\tint state;\n\t\t\tunsigned int debug_id;\n\t\t} afs;\n\t} fl_u;\n};\n\nstruct lock_manager_operations {\n\tfl_owner_t (*lm_get_owner)(fl_owner_t);\n\tvoid (*lm_put_owner)(fl_owner_t);\n\tvoid (*lm_notify)(struct file_lock *);\n\tint (*lm_grant)(struct file_lock *, int);\n\tbool (*lm_break)(struct file_lock *);\n\tint (*lm_change)(struct file_lock *, int, struct list_head *);\n\tvoid (*lm_setup)(struct file_lock *, void **);\n\tbool (*lm_breaker_owns_lease)(struct file_lock *);\n};\n\nstruct fasync_struct {\n\trwlock_t fa_lock;\n\tint magic;\n\tint fa_fd;\n\tstruct fasync_struct *fa_next;\n\tstruct file *fa_file;\n\tstruct callback_head fa_rcu;\n};\n\nenum {\n\tSB_UNFROZEN = 0,\n\tSB_FREEZE_WRITE = 1,\n\tSB_FREEZE_PAGEFAULT = 2,\n\tSB_FREEZE_FS = 3,\n\tSB_FREEZE_COMPLETE = 4,\n};\n\nstruct kstatfs;\n\nstruct super_operations {\n\tstruct inode * (*alloc_inode)(struct super_block *);\n\tvoid (*destroy_inode)(struct inode *);\n\tvoid (*free_inode)(struct inode *);\n\tvoid (*dirty_inode)(struct inode *, int);\n\tint (*write_inode)(struct inode *, struct writeback_control *);\n\tint (*drop_inode)(struct inode *);\n\tvoid (*evict_inode)(struct inode *);\n\tvoid (*put_super)(struct super_block *);\n\tint (*sync_fs)(struct super_block *, int);\n\tint (*freeze_super)(struct super_block *);\n\tint (*freeze_fs)(struct super_block *);\n\tint (*thaw_super)(struct super_block *);\n\tint (*unfreeze_fs)(struct super_block *);\n\tint (*statfs)(struct dentry *, struct kstatfs *);\n\tint (*remount_fs)(struct super_block *, int *, char *);\n\tvoid (*umount_begin)(struct super_block *);\n\tint (*show_options)(struct seq_file *, struct dentry *);\n\tint (*show_devname)(struct seq_file *, struct dentry *);\n\tint (*show_path)(struct seq_file *, struct dentry *);\n\tint (*show_stats)(struct seq_file *, struct dentry *);\n\tssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);\n\tssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);\n\tstruct dquot ** (*get_dquots)(struct inode *);\n\tlong int (*nr_cached_objects)(struct super_block *, struct shrink_control *);\n\tlong int (*free_cached_objects)(struct super_block *, struct shrink_control *);\n};\n\nstruct iomap;\n\nstruct fid;\n\nstruct export_operations {\n\tint (*encode_fh)(struct inode *, __u32 *, int *, struct inode *);\n\tstruct dentry * (*fh_to_dentry)(struct super_block *, struct fid *, int, int);\n\tstruct dentry * (*fh_to_parent)(struct super_block *, struct fid *, int, int);\n\tint (*get_name)(struct dentry *, char *, struct dentry *);\n\tstruct dentry * (*get_parent)(struct dentry *);\n\tint (*commit_metadata)(struct inode *);\n\tint (*get_uuid)(struct super_block *, u8 *, u32 *, u64 *);\n\tint (*map_blocks)(struct inode *, loff_t, u64, struct iomap *, bool, u32 *);\n\tint (*commit_blocks)(struct inode *, struct iomap *, int, struct iattr *);\n\tu64 (*fetch_iversion)(struct inode *);\n\tlong unsigned int flags;\n};\n\nstruct xattr_handler {\n\tconst char *name;\n\tconst char *prefix;\n\tint flags;\n\tbool (*list)(struct dentry *);\n\tint (*get)(const struct xattr_handler *, struct dentry *, struct inode *, const char *, void *, size_t);\n\tint (*set)(const struct xattr_handler *, struct user_namespace *, struct dentry *, struct inode *, const char *, const void *, size_t, int);\n};\n\nunion fscrypt_policy;\n\nstruct fscrypt_operations {\n\tunsigned int flags;\n\tconst char *key_prefix;\n\tint (*get_context)(struct inode *, void *, size_t);\n\tint (*set_context)(struct inode *, const void *, size_t, void *);\n\tconst union fscrypt_policy * (*get_dummy_policy)(struct super_block *);\n\tbool (*empty_dir)(struct inode *);\n\tunsigned int max_namelen;\n\tbool (*has_stable_inodes)(struct super_block *);\n\tvoid (*get_ino_and_lblk_bits)(struct super_block *, int *, int *);\n\tint (*get_num_devices)(struct super_block *);\n\tvoid (*get_devices)(struct super_block *, struct request_queue **);\n};\n\nstruct fsverity_operations {\n\tint (*begin_enable_verity)(struct file *);\n\tint (*end_enable_verity)(struct file *, const void *, size_t, u64);\n\tint (*get_verity_descriptor)(struct inode *, void *, size_t);\n\tstruct page * (*read_merkle_tree_page)(struct inode *, long unsigned int, long unsigned int);\n\tint (*write_merkle_tree_block)(struct inode *, const void *, u64, int);\n};\n\ntypedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64, unsigned int);\n\nstruct dir_context {\n\tfilldir_t actor;\n\tloff_t pos;\n};\n\nstruct p_log;\n\nstruct fs_parameter;\n\nstruct fs_parse_result;\n\ntypedef int fs_param_type(struct p_log *, const struct fs_parameter_spec *, struct fs_parameter *, struct fs_parse_result *);\n\nstruct fs_parameter_spec {\n\tconst char *name;\n\tfs_param_type *type;\n\tu8 opt;\n\tshort unsigned int flags;\n\tconst void *data;\n};\n\nenum compound_dtor_id {\n\tNULL_COMPOUND_DTOR = 0,\n\tCOMPOUND_PAGE_DTOR = 1,\n\tHUGETLB_PAGE_DTOR = 2,\n\tTRANSHUGE_PAGE_DTOR = 3,\n\tNR_COMPOUND_DTORS = 4,\n};\n\nenum vm_event_item {\n\tPGPGIN = 0,\n\tPGPGOUT = 1,\n\tPSWPIN = 2,\n\tPSWPOUT = 3,\n\tPGALLOC_DMA = 4,\n\tPGALLOC_DMA32 = 5,\n\tPGALLOC_NORMAL = 6,\n\tPGALLOC_MOVABLE = 7,\n\tALLOCSTALL_DMA = 8,\n\tALLOCSTALL_DMA32 = 9,\n\tALLOCSTALL_NORMAL = 10,\n\tALLOCSTALL_MOVABLE = 11,\n\tPGSCAN_SKIP_DMA = 12,\n\tPGSCAN_SKIP_DMA32 = 13,\n\tPGSCAN_SKIP_NORMAL = 14,\n\tPGSCAN_SKIP_MOVABLE = 15,\n\tPGFREE = 16,\n\tPGACTIVATE = 17,\n\tPGDEACTIVATE = 18,\n\tPGLAZYFREE = 19,\n\tPGFAULT = 20,\n\tPGMAJFAULT = 21,\n\tPGLAZYFREED = 22,\n\tPGREFILL = 23,\n\tPGREUSE = 24,\n\tPGSTEAL_KSWAPD = 25,\n\tPGSTEAL_DIRECT = 26,\n\tPGSCAN_KSWAPD = 27,\n\tPGSCAN_DIRECT = 28,\n\tPGSCAN_DIRECT_THROTTLE = 29,\n\tPGSCAN_ANON = 30,\n\tPGSCAN_FILE = 31,\n\tPGSTEAL_ANON = 32,\n\tPGSTEAL_FILE = 33,\n\tPGSCAN_ZONE_RECLAIM_FAILED = 34,\n\tPGINODESTEAL = 35,\n\tSLABS_SCANNED = 36,\n\tKSWAPD_INODESTEAL = 37,\n\tKSWAPD_LOW_WMARK_HIT_QUICKLY = 38,\n\tKSWAPD_HIGH_WMARK_HIT_QUICKLY = 39,\n\tPAGEOUTRUN = 40,\n\tPGROTATED = 41,\n\tDROP_PAGECACHE = 42,\n\tDROP_SLAB = 43,\n\tOOM_KILL = 44,\n\tNUMA_PTE_UPDATES = 45,\n\tNUMA_HUGE_PTE_UPDATES = 46,\n\tNUMA_HINT_FAULTS = 47,\n\tNUMA_HINT_FAULTS_LOCAL = 48,\n\tNUMA_PAGE_MIGRATE = 49,\n\tPGMIGRATE_SUCCESS = 50,\n\tPGMIGRATE_FAIL = 51,\n\tTHP_MIGRATION_SUCCESS = 52,\n\tTHP_MIGRATION_FAIL = 53,\n\tTHP_MIGRATION_SPLIT = 54,\n\tCOMPACTMIGRATE_SCANNED = 55,\n\tCOMPACTFREE_SCANNED = 56,\n\tCOMPACTISOLATED = 57,\n\tCOMPACTSTALL = 58,\n\tCOMPACTFAIL = 59,\n\tCOMPACTSUCCESS = 60,\n\tKCOMPACTD_WAKE = 61,\n\tKCOMPACTD_MIGRATE_SCANNED = 62,\n\tKCOMPACTD_FREE_SCANNED = 63,\n\tHTLB_BUDDY_PGALLOC = 64,\n\tHTLB_BUDDY_PGALLOC_FAIL = 65,\n\tCMA_ALLOC_SUCCESS = 66,\n\tCMA_ALLOC_FAIL = 67,\n\tUNEVICTABLE_PGCULLED = 68,\n\tUNEVICTABLE_PGSCANNED = 69,\n\tUNEVICTABLE_PGRESCUED = 70,\n\tUNEVICTABLE_PGMLOCKED = 71,\n\tUNEVICTABLE_PGMUNLOCKED = 72,\n\tUNEVICTABLE_PGCLEARED = 73,\n\tUNEVICTABLE_PGSTRANDED = 74,\n\tTHP_FAULT_ALLOC = 75,\n\tTHP_FAULT_FALLBACK = 76,\n\tTHP_FAULT_FALLBACK_CHARGE = 77,\n\tTHP_COLLAPSE_ALLOC = 78,\n\tTHP_COLLAPSE_ALLOC_FAILED = 79,\n\tTHP_FILE_ALLOC = 80,\n\tTHP_FILE_FALLBACK = 81,\n\tTHP_FILE_FALLBACK_CHARGE = 82,\n\tTHP_FILE_MAPPED = 83,\n\tTHP_SPLIT_PAGE = 84,\n\tTHP_SPLIT_PAGE_FAILED = 85,\n\tTHP_DEFERRED_SPLIT_PAGE = 86,\n\tTHP_SPLIT_PMD = 87,\n\tTHP_SPLIT_PUD = 88,\n\tTHP_ZERO_PAGE_ALLOC = 89,\n\tTHP_ZERO_PAGE_ALLOC_FAILED = 90,\n\tTHP_SWPOUT = 91,\n\tTHP_SWPOUT_FALLBACK = 92,\n\tBALLOON_INFLATE = 93,\n\tBALLOON_DEFLATE = 94,\n\tBALLOON_MIGRATE = 95,\n\tSWAP_RA = 96,\n\tSWAP_RA_HIT = 97,\n\tDIRECT_MAP_LEVEL2_SPLIT = 98,\n\tDIRECT_MAP_LEVEL3_SPLIT = 99,\n\tNR_VM_EVENT_ITEMS = 100,\n};\n\nstruct tlb_context {\n\tu64 ctx_id;\n\tu64 tlb_gen;\n};\n\nstruct tlb_state {\n\tstruct mm_struct *loaded_mm;\n\tunion {\n\t\tstruct mm_struct *last_user_mm;\n\t\tlong unsigned int last_user_mm_ibpb;\n\t};\n\tu16 loaded_mm_asid;\n\tu16 next_asid;\n\tbool invalidate_other;\n\tshort unsigned int user_pcid_flush_mask;\n\tlong unsigned int cr4;\n\tstruct tlb_context ctxs[6];\n};\n\nstruct boot_params_to_save {\n\tunsigned int start;\n\tunsigned int len;\n};\n\nenum cpu_idle_type {\n\tCPU_IDLE = 0,\n\tCPU_NOT_IDLE = 1,\n\tCPU_NEWLY_IDLE = 2,\n\tCPU_MAX_IDLE_TYPES = 3,\n};\n\nenum {\n\t__SD_BALANCE_NEWIDLE = 0,\n\t__SD_BALANCE_EXEC = 1,\n\t__SD_BALANCE_FORK = 2,\n\t__SD_BALANCE_WAKE = 3,\n\t__SD_WAKE_AFFINE = 4,\n\t__SD_ASYM_CPUCAPACITY = 5,\n\t__SD_ASYM_CPUCAPACITY_FULL = 6,\n\t__SD_SHARE_CPUCAPACITY = 7,\n\t__SD_SHARE_PKG_RESOURCES = 8,\n\t__SD_SERIALIZE = 9,\n\t__SD_ASYM_PACKING = 10,\n\t__SD_PREFER_SIBLING = 11,\n\t__SD_OVERLAP = 12,\n\t__SD_NUMA = 13,\n\t__SD_FLAG_CNT = 14,\n};\n\nstruct x86_legacy_devices {\n\tint pnpbios;\n};\n\nenum x86_legacy_i8042_state {\n\tX86_LEGACY_I8042_PLATFORM_ABSENT = 0,\n\tX86_LEGACY_I8042_FIRMWARE_ABSENT = 1,\n\tX86_LEGACY_I8042_EXPECTED_PRESENT = 2,\n};\n\nstruct x86_legacy_features {\n\tenum x86_legacy_i8042_state i8042;\n\tint rtc;\n\tint warm_reset;\n\tint no_vga;\n\tint reserve_bios_regions;\n\tstruct x86_legacy_devices devices;\n};\n\nstruct ghcb;\n\nstruct x86_hyper_runtime {\n\tvoid (*pin_vcpu)(int);\n\tvoid (*sev_es_hcall_prepare)(struct ghcb *, struct pt_regs *);\n\tbool (*sev_es_hcall_finish)(struct ghcb *, struct pt_regs *);\n};\n\nstruct x86_platform_ops {\n\tlong unsigned int (*calibrate_cpu)();\n\tlong unsigned int (*calibrate_tsc)();\n\tvoid (*get_wallclock)(struct timespec64 *);\n\tint (*set_wallclock)(const struct timespec64 *);\n\tvoid (*iommu_shutdown)();\n\tbool (*is_untracked_pat_range)(u64, u64);\n\tvoid (*nmi_init)();\n\tunsigned char (*get_nmi_reason)();\n\tvoid (*save_sched_clock_state)();\n\tvoid (*restore_sched_clock_state)();\n\tvoid (*apic_post_init)();\n\tstruct x86_legacy_features legacy;\n\tvoid (*set_legacy_features)();\n\tstruct x86_hyper_runtime hyper;\n};\n\ntypedef signed char __s8;\n\ntypedef __s8 s8;\n\ntypedef __u32 __le32;\n\ntypedef long unsigned int irq_hw_number_t;\n\nstruct kernel_symbol {\n\tint value_offset;\n\tint name_offset;\n\tint namespace_offset;\n};\n\ntypedef int (*initcall_t)();\n\ntypedef int initcall_entry_t;\n\nstruct obs_kernel_param {\n\tconst char *str;\n\tint (*setup_func)(char *);\n\tint early;\n};\n\nstruct lockdep_map {};\n\nstruct jump_entry {\n\ts32 code;\n\ts32 target;\n\tlong int key;\n};\n\nstruct static_key_mod;\n\nstruct static_key {\n\tatomic_t enabled;\n\tunion {\n\t\tlong unsigned int type;\n\t\tstruct jump_entry *entries;\n\t\tstruct static_key_mod *next;\n\t};\n};\n\nstruct static_key_true {\n\tstruct static_key key;\n};\n\nstruct static_key_false {\n\tstruct static_key key;\n};\n\nstruct _ddebug {\n\tconst char *modname;\n\tconst char *function;\n\tconst char *filename;\n\tconst char *format;\n\tunsigned int lineno: 18;\n\tunsigned int flags: 8;\n\tunion {\n\t\tstruct static_key_true dd_key_true;\n\t\tstruct static_key_false dd_key_false;\n\t} key;\n};\n\nstruct static_call_site {\n\ts32 addr;\n\ts32 key;\n};\n\nstruct static_call_mod {\n\tstruct static_call_mod *next;\n\tstruct module *mod;\n\tstruct static_call_site *sites;\n};\n\nstruct static_call_key {\n\tvoid *func;\n\tunion {\n\t\tlong unsigned int type;\n\t\tstruct static_call_mod *mods;\n\t\tstruct static_call_site *sites;\n\t};\n};\n\nenum system_states {\n\tSYSTEM_BOOTING = 0,\n\tSYSTEM_SCHEDULING = 1,\n\tSYSTEM_RUNNING = 2,\n\tSYSTEM_HALT = 3,\n\tSYSTEM_POWER_OFF = 4,\n\tSYSTEM_RESTART = 5,\n\tSYSTEM_SUSPEND = 6,\n};\n\nstruct orc_entry {\n\ts16 sp_offset;\n\ts16 bp_offset;\n\tunsigned int sp_reg: 4;\n\tunsigned int bp_reg: 4;\n\tunsigned int type: 2;\n\tunsigned int end: 1;\n} __attribute__((packed));\n\nstruct bug_entry {\n\tint bug_addr_disp;\n\tint file_disp;\n\tshort unsigned int line;\n\tshort unsigned int flags;\n};\n\ntypedef struct cpumask cpumask_var_t[1];\n\nstruct tracepoint_func {\n\tvoid *func;\n\tvoid *data;\n\tint prio;\n};\n\nstruct tracepoint {\n\tconst char *name;\n\tstruct static_key key;\n\tstruct static_call_key *static_call_key;\n\tvoid *static_call_tramp;\n\tvoid *iterator;\n\tint (*regfunc)();\n\tvoid (*unregfunc)();\n\tstruct tracepoint_func *funcs;\n};\n\ntypedef const int tracepoint_ptr_t;\n\nstruct bpf_raw_event_map {\n\tstruct tracepoint *tp;\n\tvoid *bpf_func;\n\tu32 num_args;\n\tu32 writable_size;\n\tlong: 64;\n};\n\nstruct seq_operations {\n\tvoid * (*start)(struct seq_file *, loff_t *);\n\tvoid (*stop)(struct seq_file *, void *);\n\tvoid * (*next)(struct seq_file *, void *, loff_t *);\n\tint (*show)(struct seq_file *, void *);\n};\n\nstruct fixed_percpu_data {\n\tchar gs_base[40];\n\tlong unsigned int stack_canary;\n};\n\nenum perf_event_state {\n\tPERF_EVENT_STATE_DEAD = 4294967292,\n\tPERF_EVENT_STATE_EXIT = 4294967293,\n\tPERF_EVENT_STATE_ERROR = 4294967294,\n\tPERF_EVENT_STATE_OFF = 4294967295,\n\tPERF_EVENT_STATE_INACTIVE = 0,\n\tPERF_EVENT_STATE_ACTIVE = 1,\n};\n\ntypedef struct {\n\tatomic_long_t a;\n} local_t;\n\ntypedef struct {\n\tlocal_t a;\n} local64_t;\n\nstruct perf_event_attr {\n\t__u32 type;\n\t__u32 size;\n\t__u64 config;\n\tunion {\n\t\t__u64 sample_period;\n\t\t__u64 sample_freq;\n\t};\n\t__u64 sample_type;\n\t__u64 read_format;\n\t__u64 disabled: 1;\n\t__u64 inherit: 1;\n\t__u64 pinned: 1;\n\t__u64 exclusive: 1;\n\t__u64 exclude_user: 1;\n\t__u64 exclude_kernel: 1;\n\t__u64 exclude_hv: 1;\n\t__u64 exclude_idle: 1;\n\t__u64 mmap: 1;\n\t__u64 comm: 1;\n\t__u64 freq: 1;\n\t__u64 inherit_stat: 1;\n\t__u64 enable_on_exec: 1;\n\t__u64 task: 1;\n\t__u64 watermark: 1;\n\t__u64 precise_ip: 2;\n\t__u64 mmap_data: 1;\n\t__u64 sample_id_all: 1;\n\t__u64 exclude_host: 1;\n\t__u64 exclude_guest: 1;\n\t__u64 exclude_callchain_kernel: 1;\n\t__u64 exclude_callchain_user: 1;\n\t__u64 mmap2: 1;\n\t__u64 comm_exec: 1;\n\t__u64 use_clockid: 1;\n\t__u64 context_switch: 1;\n\t__u64 write_backward: 1;\n\t__u64 namespaces: 1;\n\t__u64 ksymbol: 1;\n\t__u64 bpf_event: 1;\n\t__u64 aux_output: 1;\n\t__u64 cgroup: 1;\n\t__u64 text_poke: 1;\n\t__u64 build_id: 1;\n\t__u64 inherit_thread: 1;\n\t__u64 remove_on_exec: 1;\n\t__u64 sigtrap: 1;\n\t__u64 __reserved_1: 26;\n\tunion {\n\t\t__u32 wakeup_events;\n\t\t__u32 wakeup_watermark;\n\t};\n\t__u32 bp_type;\n\tunion {\n\t\t__u64 bp_addr;\n\t\t__u64 kprobe_func;\n\t\t__u64 uprobe_path;\n\t\t__u64 config1;\n\t};\n\tunion {\n\t\t__u64 bp_len;\n\t\t__u64 kprobe_addr;\n\t\t__u64 probe_offset;\n\t\t__u64 config2;\n\t};\n\t__u64 branch_sample_type;\n\t__u64 sample_regs_user;\n\t__u32 sample_stack_user;\n\t__s32 clockid;\n\t__u64 sample_regs_intr;\n\t__u32 aux_watermark;\n\t__u16 sample_max_stack;\n\t__u16 __reserved_2;\n\t__u32 aux_sample_size;\n\t__u32 __reserved_3;\n\t__u64 sig_data;\n};\n\nstruct hw_perf_event_extra {\n\tu64 config;\n\tunsigned int reg;\n\tint alloc;\n\tint idx;\n};\n\nstruct arch_hw_breakpoint {\n\tlong unsigned int address;\n\tlong unsigned int mask;\n\tu8 len;\n\tu8 type;\n};\n\nstruct hw_perf_event {\n\tunion {\n\t\tstruct {\n\t\t\tu64 config;\n\t\t\tu64 last_tag;\n\t\t\tlong unsigned int config_base;\n\t\t\tlong unsigned int event_base;\n\t\t\tint event_base_rdpmc;\n\t\t\tint idx;\n\t\t\tint last_cpu;\n\t\t\tint flags;\n\t\t\tstruct hw_perf_event_extra extra_reg;\n\t\t\tstruct hw_perf_event_extra branch_reg;\n\t\t};\n\t\tstruct {\n\t\t\tstruct hrtimer hrtimer;\n\t\t};\n\t\tstruct {\n\t\t\tstruct list_head tp_list;\n\t\t};\n\t\tstruct {\n\t\t\tu64 pwr_acc;\n\t\t\tu64 ptsc;\n\t\t};\n\t\tstruct {\n\t\t\tstruct arch_hw_breakpoint info;\n\t\t\tstruct list_head bp_list;\n\t\t};\n\t\tstruct {\n\t\t\tu8 iommu_bank;\n\t\t\tu8 iommu_cntr;\n\t\t\tu16 padding;\n\t\t\tu64 conf;\n\t\t\tu64 conf1;\n\t\t};\n\t};\n\tstruct task_struct *target;\n\tvoid *addr_filters;\n\tlong unsigned int addr_filters_gen;\n\tint state;\n\tlocal64_t prev_count;\n\tu64 sample_period;\n\tunion {\n\t\tstruct {\n\t\t\tu64 last_period;\n\t\t\tlocal64_t period_left;\n\t\t};\n\t\tstruct {\n\t\t\tu64 saved_metric;\n\t\t\tu64 saved_slots;\n\t\t};\n\t};\n\tu64 interrupts_seq;\n\tu64 interrupts;\n\tu64 freq_time_stamp;\n\tu64 freq_count_stamp;\n};\n\nstruct irq_work {\n\tstruct __call_single_node node;\n\tvoid (*func)(struct irq_work *);\n};\n\nstruct perf_addr_filters_head {\n\tstruct list_head list;\n\traw_spinlock_t lock;\n\tunsigned int nr_file_filters;\n};\n\nstruct perf_sample_data;\n\ntypedef void (*perf_overflow_handler_t)(struct perf_event *, struct perf_sample_data *, struct pt_regs *);\n\nstruct ftrace_ops;\n\nstruct ftrace_regs;\n\ntypedef void (*ftrace_func_t)(long unsigned int, long unsigned int, struct ftrace_ops *, struct ftrace_regs *);\n\nstruct ftrace_hash;\n\nstruct ftrace_ops_hash {\n\tstruct ftrace_hash *notrace_hash;\n\tstruct ftrace_hash *filter_hash;\n\tstruct mutex regex_lock;\n};\n\nstruct ftrace_ops {\n\tftrace_func_t func;\n\tstruct ftrace_ops *next;\n\tlong unsigned int flags;\n\tvoid *private;\n\tftrace_func_t saved_func;\n\tstruct ftrace_ops_hash local_hash;\n\tstruct ftrace_ops_hash *func_hash;\n\tstruct ftrace_ops_hash old_hash;\n\tlong unsigned int trampoline;\n\tlong unsigned int trampoline_size;\n\tstruct list_head list;\n};\n\nstruct pmu;\n\nstruct perf_buffer;\n\nstruct perf_addr_filter_range;\n\nstruct bpf_prog;\n\nstruct trace_event_call;\n\nstruct event_filter;\n\nstruct perf_cgroup;\n\nstruct perf_event {\n\tstruct list_head event_entry;\n\tstruct list_head sibling_list;\n\tstruct list_head active_list;\n\tstruct rb_node group_node;\n\tu64 group_index;\n\tstruct list_head migrate_entry;\n\tstruct hlist_node hlist_entry;\n\tstruct list_head active_entry;\n\tint nr_siblings;\n\tint event_caps;\n\tint group_caps;\n\tstruct perf_event *group_leader;\n\tstruct pmu *pmu;\n\tvoid *pmu_private;\n\tenum perf_event_state state;\n\tunsigned int attach_state;\n\tlocal64_t count;\n\tatomic64_t child_count;\n\tu64 total_time_enabled;\n\tu64 total_time_running;\n\tu64 tstamp;\n\tu64 shadow_ctx_time;\n\tstruct perf_event_attr attr;\n\tu16 header_size;\n\tu16 id_header_size;\n\tu16 read_size;\n\tstruct hw_perf_event hw;\n\tstruct perf_event_context *ctx;\n\tatomic_long_t refcount;\n\tatomic64_t child_total_time_enabled;\n\tatomic64_t child_total_time_running;\n\tstruct mutex child_mutex;\n\tstruct list_head child_list;\n\tstruct perf_event *parent;\n\tint oncpu;\n\tint cpu;\n\tstruct list_head owner_entry;\n\tstruct task_struct *owner;\n\tstruct mutex mmap_mutex;\n\tatomic_t mmap_count;\n\tstruct perf_buffer *rb;\n\tstruct list_head rb_entry;\n\tlong unsigned int rcu_batches;\n\tint rcu_pending;\n\twait_queue_head_t waitq;\n\tstruct fasync_struct *fasync;\n\tint pending_wakeup;\n\tint pending_kill;\n\tint pending_disable;\n\tlong unsigned int pending_addr;\n\tstruct irq_work pending;\n\tatomic_t event_limit;\n\tstruct perf_addr_filters_head addr_filters;\n\tstruct perf_addr_filter_range *addr_filter_ranges;\n\tlong unsigned int addr_filters_gen;\n\tstruct perf_event *aux_event;\n\tvoid (*destroy)(struct perf_event *);\n\tstruct callback_head callback_head;\n\tstruct pid_namespace *ns;\n\tu64 id;\n\tu64 (*clock)();\n\tperf_overflow_handler_t overflow_handler;\n\tvoid *overflow_handler_context;\n\tperf_overflow_handler_t orig_overflow_handler;\n\tstruct bpf_prog *prog;\n\tstruct trace_event_call *tp_event;\n\tstruct event_filter *filter;\n\tstruct ftrace_ops ftrace_ops;\n\tstruct perf_cgroup *cgrp;\n\tvoid *security;\n\tstruct list_head sb_list;\n};\n\nstruct uid_gid_extent {\n\tu32 first;\n\tu32 lower_first;\n\tu32 count;\n};\n\nstruct uid_gid_map {\n\tu32 nr_extents;\n\tunion {\n\t\tstruct uid_gid_extent extent[5];\n\t\tstruct {\n\t\t\tstruct uid_gid_extent *forward;\n\t\t\tstruct uid_gid_extent *reverse;\n\t\t};\n\t};\n};\n\nstruct proc_ns_operations;\n\nstruct ns_common {\n\tatomic_long_t stashed;\n\tconst struct proc_ns_operations *ops;\n\tunsigned int inum;\n\trefcount_t count;\n};\n\nstruct ctl_table;\n\nstruct ctl_table_root;\n\nstruct ctl_table_set;\n\nstruct ctl_dir;\n\nstruct ctl_node;\n\nstruct ctl_table_header {\n\tunion {\n\t\tstruct {\n\t\t\tstruct ctl_table *ctl_table;\n\t\t\tint used;\n\t\t\tint count;\n\t\t\tint nreg;\n\t\t};\n\t\tstruct callback_head rcu;\n\t};\n\tstruct completion *unregistering;\n\tstruct ctl_table *ctl_table_arg;\n\tstruct ctl_table_root *root;\n\tstruct ctl_table_set *set;\n\tstruct ctl_dir *parent;\n\tstruct ctl_node *node;\n\tstruct hlist_head inodes;\n};\n\nstruct ctl_dir {\n\tstruct ctl_table_header header;\n\tstruct rb_root root;\n};\n\nstruct ctl_table_set {\n\tint (*is_seen)(struct ctl_table_set *);\n\tstruct ctl_dir dir;\n};\n\nstruct user_namespace {\n\tstruct uid_gid_map uid_map;\n\tstruct uid_gid_map gid_map;\n\tstruct uid_gid_map projid_map;\n\tstruct user_namespace *parent;\n\tint level;\n\tkuid_t owner;\n\tkgid_t group;\n\tstruct ns_common ns;\n\tlong unsigned int flags;\n\tbool parent_could_setfcap;\n\tstruct list_head keyring_name_list;\n\tstruct key *user_keyring_register;\n\tstruct rw_semaphore keyring_sem;\n\tstruct key *persistent_keyring_register;\n\tstruct work_struct work;\n\tstruct ctl_table_set set;\n\tstruct ctl_table_header *sysctls;\n\tstruct ucounts *ucounts;\n\tlong int ucount_max[16];\n};\n\nstruct pollfd {\n\tint fd;\n\tshort int events;\n\tshort int revents;\n};\n\ntypedef void (*smp_call_func_t)(void *);\n\nstruct __call_single_data {\n\tstruct __call_single_node node;\n\tsmp_call_func_t func;\n\tvoid *info;\n};\n\nstruct smp_ops {\n\tvoid (*smp_prepare_boot_cpu)();\n\tvoid (*smp_prepare_cpus)(unsigned int);\n\tvoid (*smp_cpus_done)(unsigned int);\n\tvoid (*stop_other_cpus)(int);\n\tvoid (*crash_stop_other_cpus)();\n\tvoid (*smp_send_reschedule)(int);\n\tint (*cpu_up)(unsigned int, struct task_struct *);\n\tint (*cpu_disable)();\n\tvoid (*cpu_die)(unsigned int);\n\tvoid (*play_dead)();\n\tvoid (*send_call_func_ipi)(const struct cpumask *);\n\tvoid (*send_call_func_single_ipi)(int);\n};\n\nstruct wait_queue_entry;\n\ntypedef int (*wait_queue_func_t)(struct wait_queue_entry *, unsigned int, int, void *);\n\nstruct wait_queue_entry {\n\tunsigned int flags;\n\tvoid *private;\n\twait_queue_func_t func;\n\tstruct list_head entry;\n};\n\ntypedef struct wait_queue_entry wait_queue_entry_t;\n\nstruct timer_list {\n\tstruct hlist_node entry;\n\tlong unsigned int expires;\n\tvoid (*function)(struct timer_list *);\n\tu32 flags;\n};\n\nstruct delayed_work {\n\tstruct work_struct work;\n\tstruct timer_list timer;\n\tstruct workqueue_struct *wq;\n\tint cpu;\n};\n\nstruct rcu_work {\n\tstruct work_struct work;\n\tstruct callback_head rcu;\n\tstruct workqueue_struct *wq;\n};\n\nstruct rcu_segcblist {\n\tstruct callback_head *head;\n\tstruct callback_head **tails[4];\n\tlong unsigned int gp_seq[4];\n\tlong int len;\n\tlong int seglen[4];\n\tu8 flags;\n};\n\nstruct srcu_node;\n\nstruct srcu_struct;\n\nstruct srcu_data {\n\tlong unsigned int srcu_lock_count[2];\n\tlong unsigned int srcu_unlock_count[2];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tspinlock_t lock;\n\tstruct rcu_segcblist srcu_cblist;\n\tlong unsigned int srcu_gp_seq_needed;\n\tlong unsigned int srcu_gp_seq_needed_exp;\n\tbool srcu_cblist_invoking;\n\tstruct timer_list delay_work;\n\tstruct work_struct work;\n\tstruct callback_head srcu_barrier_head;\n\tstruct srcu_node *mynode;\n\tlong unsigned int grpmask;\n\tint cpu;\n\tstruct srcu_struct *ssp;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct srcu_node {\n\tspinlock_t lock;\n\tlong unsigned int srcu_have_cbs[4];\n\tlong unsigned int srcu_data_have_cbs[4];\n\tlong unsigned int srcu_gp_seq_needed_exp;\n\tstruct srcu_node *srcu_parent;\n\tint grplo;\n\tint grphi;\n};\n\nstruct srcu_struct {\n\tstruct srcu_node node[21];\n\tstruct srcu_node *level[3];\n\tstruct mutex srcu_cb_mutex;\n\tspinlock_t lock;\n\tstruct mutex srcu_gp_mutex;\n\tunsigned int srcu_idx;\n\tlong unsigned int srcu_gp_seq;\n\tlong unsigned int srcu_gp_seq_needed;\n\tlong unsigned int srcu_gp_seq_needed_exp;\n\tlong unsigned int srcu_last_gp_end;\n\tstruct srcu_data *sda;\n\tlong unsigned int srcu_barrier_seq;\n\tstruct mutex srcu_barrier_mutex;\n\tstruct completion srcu_barrier_completion;\n\tatomic_t srcu_barrier_cpu_cnt;\n\tstruct delayed_work work;\n\tstruct lockdep_map dep_map;\n};\n\nstruct anon_vma {\n\tstruct anon_vma *root;\n\tstruct rw_semaphore rwsem;\n\tatomic_t refcount;\n\tunsigned int degree;\n\tstruct anon_vma *parent;\n\tstruct rb_root_cached rb_root;\n};\n\nstruct mempolicy {\n\tatomic_t refcnt;\n\tshort unsigned int mode;\n\tshort unsigned int flags;\n\tnodemask_t nodes;\n\tunion {\n\t\tnodemask_t cpuset_mems_allowed;\n\t\tnodemask_t user_nodemask;\n\t} w;\n};\n\nstruct linux_binprm;\n\nstruct coredump_params;\n\nstruct linux_binfmt {\n\tstruct list_head lh;\n\tstruct module *module;\n\tint (*load_binary)(struct linux_binprm *);\n\tint (*load_shlib)(struct file *);\n\tint (*core_dump)(struct coredump_params *);\n\tlong unsigned int min_coredump;\n};\n\nstruct free_area {\n\tstruct list_head free_list[6];\n\tlong unsigned int nr_free;\n};\n\nstruct zone_padding {\n\tchar x[0];\n};\n\nstruct pglist_data;\n\nstruct lruvec {\n\tstruct list_head lists[5];\n\tspinlock_t lru_lock;\n\tlong unsigned int anon_cost;\n\tlong unsigned int file_cost;\n\tatomic_long_t nonresident_age;\n\tlong unsigned int refaults[2];\n\tlong unsigned int flags;\n\tstruct pglist_data *pgdat;\n};\n\nstruct per_cpu_pages;\n\nstruct per_cpu_zonestat;\n\nstruct zone {\n\tlong unsigned int _watermark[3];\n\tlong unsigned int watermark_boost;\n\tlong unsigned int nr_reserved_highatomic;\n\tlong int lowmem_reserve[5];\n\tint node;\n\tstruct pglist_data *zone_pgdat;\n\tstruct per_cpu_pages *per_cpu_pageset;\n\tstruct per_cpu_zonestat *per_cpu_zonestats;\n\tint pageset_high;\n\tint pageset_batch;\n\tlong unsigned int zone_start_pfn;\n\tatomic_long_t managed_pages;\n\tlong unsigned int spanned_pages;\n\tlong unsigned int present_pages;\n\tlong unsigned int cma_pages;\n\tconst char *name;\n\tlong unsigned int nr_isolate_pageblock;\n\tseqlock_t span_seqlock;\n\tint initialized;\n\tint: 32;\n\tstruct zone_padding _pad1_;\n\tstruct free_area free_area[11];\n\tlong unsigned int flags;\n\tspinlock_t lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct zone_padding _pad2_;\n\tlong unsigned int percpu_drift_mark;\n\tlong unsigned int compact_cached_free_pfn;\n\tlong unsigned int compact_cached_migrate_pfn[2];\n\tlong unsigned int compact_init_migrate_pfn;\n\tlong unsigned int compact_init_free_pfn;\n\tunsigned int compact_considered;\n\tunsigned int compact_defer_shift;\n\tint compact_order_failed;\n\tbool compact_blockskip_flush;\n\tbool contiguous;\n\tshort: 16;\n\tstruct zone_padding _pad3_;\n\tatomic_long_t vm_stat[11];\n\tatomic_long_t vm_numa_event[6];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct zoneref {\n\tstruct zone *zone;\n\tint zone_idx;\n};\n\nstruct zonelist {\n\tstruct zoneref _zonerefs[161];\n};\n\nenum zone_type {\n\tZONE_DMA = 0,\n\tZONE_DMA32 = 1,\n\tZONE_NORMAL = 2,\n\tZONE_MOVABLE = 3,\n\tZONE_DEVICE = 4,\n\t__MAX_NR_ZONES = 5,\n};\n\nstruct deferred_split {\n\tspinlock_t split_queue_lock;\n\tstruct list_head split_queue;\n\tlong unsigned int split_queue_len;\n};\n\nstruct per_cpu_nodestat;\n\nstruct pglist_data {\n\tstruct zone node_zones[5];\n\tstruct zonelist node_zonelists[2];\n\tint nr_zones;\n\tspinlock_t node_size_lock;\n\tlong unsigned int node_start_pfn;\n\tlong unsigned int node_present_pages;\n\tlong unsigned int node_spanned_pages;\n\tint node_id;\n\twait_queue_head_t kswapd_wait;\n\twait_queue_head_t pfmemalloc_wait;\n\tstruct task_struct *kswapd;\n\tint kswapd_order;\n\tenum zone_type kswapd_highest_zoneidx;\n\tint kswapd_failures;\n\tint kcompactd_max_order;\n\tenum zone_type kcompactd_highest_zoneidx;\n\twait_queue_head_t kcompactd_wait;\n\tstruct task_struct *kcompactd;\n\tlong unsigned int totalreserve_pages;\n\tlong unsigned int min_unmapped_pages;\n\tlong unsigned int min_slab_pages;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct zone_padding _pad1_;\n\tstruct deferred_split deferred_split_queue;\n\tstruct lruvec __lruvec;\n\tlong unsigned int flags;\n\tlong: 64;\n\tstruct zone_padding _pad2_;\n\tstruct per_cpu_nodestat *per_cpu_nodestats;\n\tatomic_long_t vm_stat[39];\n};\n\nstruct per_cpu_pages {\n\tint count;\n\tint high;\n\tint batch;\n\tshort int free_factor;\n\tshort int expire;\n\tstruct list_head lists[15];\n};\n\nstruct per_cpu_zonestat {\n\ts8 vm_stat_diff[11];\n\ts8 stat_threshold;\n\tlong unsigned int vm_numa_event[6];\n};\n\nstruct per_cpu_nodestat {\n\ts8 stat_threshold;\n\ts8 vm_node_stat_diff[39];\n};\n\ntypedef struct pglist_data pg_data_t;\n\nenum irq_domain_bus_token {\n\tDOMAIN_BUS_ANY = 0,\n\tDOMAIN_BUS_WIRED = 1,\n\tDOMAIN_BUS_GENERIC_MSI = 2,\n\tDOMAIN_BUS_PCI_MSI = 3,\n\tDOMAIN_BUS_PLATFORM_MSI = 4,\n\tDOMAIN_BUS_NEXUS = 5,\n\tDOMAIN_BUS_IPI = 6,\n\tDOMAIN_BUS_FSL_MC_MSI = 7,\n\tDOMAIN_BUS_TI_SCI_INTA_MSI = 8,\n\tDOMAIN_BUS_WAKEUP = 9,\n\tDOMAIN_BUS_VMD_MSI = 10,\n};\n\nstruct irq_domain_ops;\n\nstruct fwnode_handle;\n\nstruct irq_domain_chip_generic;\n\nstruct irq_data;\n\nstruct irq_domain {\n\tstruct list_head link;\n\tconst char *name;\n\tconst struct irq_domain_ops *ops;\n\tvoid *host_data;\n\tunsigned int flags;\n\tunsigned int mapcount;\n\tstruct fwnode_handle *fwnode;\n\tenum irq_domain_bus_token bus_token;\n\tstruct irq_domain_chip_generic *gc;\n\tstruct irq_domain *parent;\n\tirq_hw_number_t hwirq_max;\n\tunsigned int revmap_size;\n\tstruct xarray revmap_tree;\n\tstruct mutex revmap_mutex;\n\tstruct irq_data *revmap[0];\n};\n\ntypedef int proc_handler(struct ctl_table *, int, void *, size_t *, loff_t *);\n\nstruct ctl_table_poll;\n\nstruct ctl_table {\n\tconst char *procname;\n\tvoid *data;\n\tint maxlen;\n\tumode_t mode;\n\tstruct ctl_table *child;\n\tproc_handler *proc_handler;\n\tstruct ctl_table_poll *poll;\n\tvoid *extra1;\n\tvoid *extra2;\n};\n\nstruct ctl_table_poll {\n\tatomic_t event;\n\twait_queue_head_t wait;\n};\n\nstruct ctl_node {\n\tstruct rb_node node;\n\tstruct ctl_table_header *header;\n};\n\nstruct ctl_table_root {\n\tstruct ctl_table_set default_set;\n\tstruct ctl_table_set * (*lookup)(struct ctl_table_root *);\n\tvoid (*set_ownership)(struct ctl_table_header *, struct ctl_table *, kuid_t *, kgid_t *);\n\tint (*permissions)(struct ctl_table_header *, struct ctl_table *);\n};\n\nenum umh_disable_depth {\n\tUMH_ENABLED = 0,\n\tUMH_FREEZING = 1,\n\tUMH_DISABLED = 2,\n};\n\ntypedef __u64 Elf64_Addr;\n\ntypedef __u16 Elf64_Half;\n\ntypedef __u32 Elf64_Word;\n\ntypedef __u64 Elf64_Xword;\n\nstruct elf64_sym {\n\tElf64_Word st_name;\n\tunsigned char st_info;\n\tunsigned char st_other;\n\tElf64_Half st_shndx;\n\tElf64_Addr st_value;\n\tElf64_Xword st_size;\n};\n\ntypedef struct elf64_sym Elf64_Sym;\n\nstruct idr {\n\tstruct xarray idr_rt;\n\tunsigned int idr_base;\n\tunsigned int idr_next;\n};\n\nstruct kernfs_root;\n\nstruct kernfs_elem_dir {\n\tlong unsigned int subdirs;\n\tstruct rb_root children;\n\tstruct kernfs_root *root;\n};\n\nstruct kernfs_node;\n\nstruct kernfs_syscall_ops;\n\nstruct kernfs_root {\n\tstruct kernfs_node *kn;\n\tunsigned int flags;\n\tstruct idr ino_idr;\n\tu32 last_id_lowbits;\n\tu32 id_highbits;\n\tstruct kernfs_syscall_ops *syscall_ops;\n\tstruct list_head supers;\n\twait_queue_head_t deactivate_waitq;\n};\n\nstruct kernfs_elem_symlink {\n\tstruct kernfs_node *target_kn;\n};\n\nstruct kernfs_ops;\n\nstruct kernfs_open_node;\n\nstruct kernfs_elem_attr {\n\tconst struct kernfs_ops *ops;\n\tstruct kernfs_open_node *open;\n\tloff_t size;\n\tstruct kernfs_node *notify_next;\n};\n\nstruct kernfs_iattrs;\n\nstruct kernfs_node {\n\tatomic_t count;\n\tatomic_t active;\n\tstruct kernfs_node *parent;\n\tconst char *name;\n\tstruct rb_node rb;\n\tconst void *ns;\n\tunsigned int hash;\n\tunion {\n\t\tstruct kernfs_elem_dir dir;\n\t\tstruct kernfs_elem_symlink symlink;\n\t\tstruct kernfs_elem_attr attr;\n\t};\n\tvoid *priv;\n\tu64 id;\n\tshort unsigned int flags;\n\tumode_t mode;\n\tstruct kernfs_iattrs *iattr;\n};\n\nstruct kernfs_open_file;\n\nstruct kernfs_ops {\n\tint (*open)(struct kernfs_open_file *);\n\tvoid (*release)(struct kernfs_open_file *);\n\tint (*seq_show)(struct seq_file *, void *);\n\tvoid * (*seq_start)(struct seq_file *, loff_t *);\n\tvoid * (*seq_next)(struct seq_file *, void *, loff_t *);\n\tvoid (*seq_stop)(struct seq_file *, void *);\n\tssize_t (*read)(struct kernfs_open_file *, char *, size_t, loff_t);\n\tsize_t atomic_write_len;\n\tbool prealloc;\n\tssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t);\n\t__poll_t (*poll)(struct kernfs_open_file *, struct poll_table_struct *);\n\tint (*mmap)(struct kernfs_open_file *, struct vm_area_struct *);\n};\n\nstruct kernfs_syscall_ops {\n\tint (*show_options)(struct seq_file *, struct kernfs_root *);\n\tint (*mkdir)(struct kernfs_node *, const char *, umode_t);\n\tint (*rmdir)(struct kernfs_node *);\n\tint (*rename)(struct kernfs_node *, struct kernfs_node *, const char *);\n\tint (*show_path)(struct seq_file *, struct kernfs_node *, struct kernfs_root *);\n};\n\nstruct seq_file {\n\tchar *buf;\n\tsize_t size;\n\tsize_t from;\n\tsize_t count;\n\tsize_t pad_until;\n\tloff_t index;\n\tloff_t read_pos;\n\tstruct mutex lock;\n\tconst struct seq_operations *op;\n\tint poll_event;\n\tconst struct file *file;\n\tvoid *private;\n};\n\nstruct kernfs_open_file {\n\tstruct kernfs_node *kn;\n\tstruct file *file;\n\tstruct seq_file *seq_file;\n\tvoid *priv;\n\tstruct mutex mutex;\n\tstruct mutex prealloc_mutex;\n\tint event;\n\tstruct list_head list;\n\tchar *prealloc_buf;\n\tsize_t atomic_write_len;\n\tbool mmapped: 1;\n\tbool released: 1;\n\tconst struct vm_operations_struct *vm_ops;\n};\n\ntypedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);\n\nstruct poll_table_struct {\n\tpoll_queue_proc _qproc;\n\t__poll_t _key;\n};\n\nenum kobj_ns_type {\n\tKOBJ_NS_TYPE_NONE = 0,\n\tKOBJ_NS_TYPE_NET = 1,\n\tKOBJ_NS_TYPES = 2,\n};\n\nstruct sock;\n\nstruct kobj_ns_type_operations {\n\tenum kobj_ns_type type;\n\tbool (*current_may_mount)();\n\tvoid * (*grab_current_ns)();\n\tconst void * (*netlink_ns)(struct sock *);\n\tconst void * (*initial_ns)();\n\tvoid (*drop_ns)(void *);\n};\n\nstruct attribute {\n\tconst char *name;\n\tumode_t mode;\n};\n\nstruct kobject;\n\nstruct bin_attribute;\n\nstruct attribute_group {\n\tconst char *name;\n\tumode_t (*is_visible)(struct kobject *, struct attribute *, int);\n\tumode_t (*is_bin_visible)(struct kobject *, struct bin_attribute *, int);\n\tstruct attribute **attrs;\n\tstruct bin_attribute **bin_attrs;\n};\n\nstruct kref {\n\trefcount_t refcount;\n};\n\nstruct kset;\n\nstruct kobj_type;\n\nstruct kobject {\n\tconst char *name;\n\tstruct list_head entry;\n\tstruct kobject *parent;\n\tstruct kset *kset;\n\tstruct kobj_type *ktype;\n\tstruct kernfs_node *sd;\n\tstruct kref kref;\n\tunsigned int state_initialized: 1;\n\tunsigned int state_in_sysfs: 1;\n\tunsigned int state_add_uevent_sent: 1;\n\tunsigned int state_remove_uevent_sent: 1;\n\tunsigned int uevent_suppress: 1;\n};\n\nstruct bin_attribute {\n\tstruct attribute attr;\n\tsize_t size;\n\tvoid *private;\n\tstruct address_space *mapping;\n\tssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t);\n\tssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t);\n\tint (*mmap)(struct file *, struct kobject *, struct bin_attribute *, struct vm_area_struct *);\n};\n\nstruct sysfs_ops {\n\tssize_t (*show)(struct kobject *, struct attribute *, char *);\n\tssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);\n};\n\nenum refcount_saturation_type {\n\tREFCOUNT_ADD_NOT_ZERO_OVF = 0,\n\tREFCOUNT_ADD_OVF = 1,\n\tREFCOUNT_ADD_UAF = 2,\n\tREFCOUNT_SUB_UAF = 3,\n\tREFCOUNT_DEC_LEAK = 4,\n};\n\nstruct kset_uevent_ops;\n\nstruct kset {\n\tstruct list_head list;\n\tspinlock_t list_lock;\n\tstruct kobject kobj;\n\tconst struct kset_uevent_ops *uevent_ops;\n};\n\nstruct kobj_type {\n\tvoid (*release)(struct kobject *);\n\tconst struct sysfs_ops *sysfs_ops;\n\tstruct attribute **default_attrs;\n\tconst struct attribute_group **default_groups;\n\tconst struct kobj_ns_type_operations * (*child_ns_type)(struct kobject *);\n\tconst void * (*namespace)(struct kobject *);\n\tvoid (*get_ownership)(struct kobject *, kuid_t *, kgid_t *);\n};\n\nstruct kobj_uevent_env {\n\tchar *argv[3];\n\tchar *envp[64];\n\tint envp_idx;\n\tchar buf[2048];\n\tint buflen;\n};\n\nstruct kset_uevent_ops {\n\tint (* const filter)(struct kset *, struct kobject *);\n\tconst char * (* const name)(struct kset *, struct kobject *);\n\tint (* const uevent)(struct kset *, struct kobject *, struct kobj_uevent_env *);\n};\n\nstruct kernel_param;\n\nstruct kernel_param_ops {\n\tunsigned int flags;\n\tint (*set)(const char *, const struct kernel_param *);\n\tint (*get)(char *, const struct kernel_param *);\n\tvoid (*free)(void *);\n};\n\nstruct kparam_string;\n\nstruct kparam_array;\n\nstruct kernel_param {\n\tconst char *name;\n\tstruct module *mod;\n\tconst struct kernel_param_ops *ops;\n\tconst u16 perm;\n\ts8 level;\n\tu8 flags;\n\tunion {\n\t\tvoid *arg;\n\t\tconst struct kparam_string *str;\n\t\tconst struct kparam_array *arr;\n\t};\n};\n\nstruct kparam_string {\n\tunsigned int maxlen;\n\tchar *string;\n};\n\nstruct kparam_array {\n\tunsigned int max;\n\tunsigned int elemsize;\n\tunsigned int *num;\n\tconst struct kernel_param_ops *ops;\n\tvoid *elem;\n};\n\nenum module_state {\n\tMODULE_STATE_LIVE = 0,\n\tMODULE_STATE_COMING = 1,\n\tMODULE_STATE_GOING = 2,\n\tMODULE_STATE_UNFORMED = 3,\n};\n\nstruct module_param_attrs;\n\nstruct module_kobject {\n\tstruct kobject kobj;\n\tstruct module *mod;\n\tstruct kobject *drivers_dir;\n\tstruct module_param_attrs *mp;\n\tstruct completion *kobj_completion;\n};\n\nstruct latch_tree_node {\n\tstruct rb_node node[2];\n};\n\nstruct mod_tree_node {\n\tstruct module *mod;\n\tstruct latch_tree_node node;\n};\n\nstruct module_layout {\n\tvoid *base;\n\tunsigned int size;\n\tunsigned int text_size;\n\tunsigned int ro_size;\n\tunsigned int ro_after_init_size;\n\tstruct mod_tree_node mtn;\n};\n\nstruct mod_arch_specific {\n\tunsigned int num_orcs;\n\tint *orc_unwind_ip;\n\tstruct orc_entry *orc_unwind;\n};\n\nstruct mod_kallsyms {\n\tElf64_Sym *symtab;\n\tunsigned int num_symtab;\n\tchar *strtab;\n\tchar *typetab;\n};\n\nstruct module_attribute;\n\nstruct exception_table_entry;\n\nstruct module_sect_attrs;\n\nstruct module_notes_attrs;\n\nstruct trace_eval_map;\n\nstruct error_injection_entry;\n\nstruct module {\n\tenum module_state state;\n\tstruct list_head list;\n\tchar name[56];\n\tunsigned char build_id[20];\n\tstruct module_kobject mkobj;\n\tstruct module_attribute *modinfo_attrs;\n\tconst char *version;\n\tconst char *srcversion;\n\tstruct kobject *holders_dir;\n\tconst struct kernel_symbol *syms;\n\tconst s32 *crcs;\n\tunsigned int num_syms;\n\tstruct mutex param_lock;\n\tstruct kernel_param *kp;\n\tunsigned int num_kp;\n\tunsigned int num_gpl_syms;\n\tconst struct kernel_symbol *gpl_syms;\n\tconst s32 *gpl_crcs;\n\tbool using_gplonly_symbols;\n\tbool sig_ok;\n\tbool async_probe_requested;\n\tunsigned int num_exentries;\n\tstruct exception_table_entry *extable;\n\tint (*init)();\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct module_layout core_layout;\n\tstruct module_layout init_layout;\n\tstruct mod_arch_specific arch;\n\tlong unsigned int taints;\n\tunsigned int num_bugs;\n\tstruct list_head bug_list;\n\tstruct bug_entry *bug_table;\n\tstruct mod_kallsyms *kallsyms;\n\tstruct mod_kallsyms core_kallsyms;\n\tstruct module_sect_attrs *sect_attrs;\n\tstruct module_notes_attrs *notes_attrs;\n\tchar *args;\n\tvoid *percpu;\n\tunsigned int percpu_size;\n\tvoid *noinstr_text_start;\n\tunsigned int noinstr_text_size;\n\tunsigned int num_tracepoints;\n\ttracepoint_ptr_t *tracepoints_ptrs;\n\tunsigned int num_srcu_structs;\n\tstruct srcu_struct **srcu_struct_ptrs;\n\tunsigned int num_bpf_raw_events;\n\tstruct bpf_raw_event_map *bpf_raw_events;\n\tunsigned int btf_data_size;\n\tvoid *btf_data;\n\tstruct jump_entry *jump_entries;\n\tunsigned int num_jump_entries;\n\tunsigned int num_trace_bprintk_fmt;\n\tconst char **trace_bprintk_fmt_start;\n\tstruct trace_event_call **trace_events;\n\tunsigned int num_trace_events;\n\tstruct trace_eval_map **trace_evals;\n\tunsigned int num_trace_evals;\n\tunsigned int num_ftrace_callsites;\n\tlong unsigned int *ftrace_callsites;\n\tvoid *kprobes_text_start;\n\tunsigned int kprobes_text_size;\n\tlong unsigned int *kprobe_blacklist;\n\tunsigned int num_kprobe_blacklist;\n\tint num_static_call_sites;\n\tstruct static_call_site *static_call_sites;\n\tstruct list_head source_list;\n\tstruct list_head target_list;\n\tvoid (*exit)();\n\tatomic_t refcnt;\n\tstruct error_injection_entry *ei_funcs;\n\tunsigned int num_ei_funcs;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct error_injection_entry {\n\tlong unsigned int addr;\n\tint etype;\n};\n\nstruct module_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct module_attribute *, struct module_kobject *, char *);\n\tssize_t (*store)(struct module_attribute *, struct module_kobject *, const char *, size_t);\n\tvoid (*setup)(struct module *, const char *);\n\tint (*test)(struct module *);\n\tvoid (*free)(struct module *);\n};\n\nstruct exception_table_entry {\n\tint insn;\n\tint fixup;\n\tint handler;\n};\n\nstruct trace_event_functions;\n\nstruct trace_event {\n\tstruct hlist_node node;\n\tstruct list_head list;\n\tint type;\n\tstruct trace_event_functions *funcs;\n};\n\nstruct trace_event_class;\n\nstruct bpf_prog_array;\n\nstruct trace_event_call {\n\tstruct list_head list;\n\tstruct trace_event_class *class;\n\tunion {\n\t\tchar *name;\n\t\tstruct tracepoint *tp;\n\t};\n\tstruct trace_event event;\n\tchar *print_fmt;\n\tstruct event_filter *filter;\n\tvoid *mod;\n\tvoid *data;\n\tint flags;\n\tint perf_refcount;\n\tstruct hlist_head *perf_events;\n\tstruct bpf_prog_array *prog_array;\n\tint (*perf_perm)(struct trace_event_call *, struct perf_event *);\n};\n\nstruct trace_eval_map {\n\tconst char *system;\n\tconst char *eval_string;\n\tlong unsigned int eval_value;\n};\n\nstruct cgroup;\n\nstruct cgroup_subsys;\n\nstruct cgroup_subsys_state {\n\tstruct cgroup *cgroup;\n\tstruct cgroup_subsys *ss;\n\tstruct percpu_ref refcnt;\n\tstruct list_head sibling;\n\tstruct list_head children;\n\tstruct list_head rstat_css_node;\n\tint id;\n\tunsigned int flags;\n\tu64 serial_nr;\n\tatomic_t online_cnt;\n\tstruct work_struct destroy_work;\n\tstruct rcu_work destroy_rwork;\n\tstruct cgroup_subsys_state *parent;\n};\n\nstruct mem_cgroup_id {\n\tint id;\n\trefcount_t ref;\n};\n\nstruct page_counter {\n\tatomic_long_t usage;\n\tlong unsigned int min;\n\tlong unsigned int low;\n\tlong unsigned int high;\n\tlong unsigned int max;\n\tlong unsigned int emin;\n\tatomic_long_t min_usage;\n\tatomic_long_t children_min_usage;\n\tlong unsigned int elow;\n\tatomic_long_t low_usage;\n\tatomic_long_t children_low_usage;\n\tlong unsigned int watermark;\n\tlong unsigned int failcnt;\n\tstruct page_counter *parent;\n};\n\nstruct vmpressure {\n\tlong unsigned int scanned;\n\tlong unsigned int reclaimed;\n\tlong unsigned int tree_scanned;\n\tlong unsigned int tree_reclaimed;\n\tspinlock_t sr_lock;\n\tstruct list_head events;\n\tstruct mutex events_lock;\n\tstruct work_struct work;\n};\n\nstruct cgroup_file {\n\tstruct kernfs_node *kn;\n\tlong unsigned int notified_at;\n\tstruct timer_list notify_timer;\n};\n\nstruct mem_cgroup_threshold_ary;\n\nstruct mem_cgroup_thresholds {\n\tstruct mem_cgroup_threshold_ary *primary;\n\tstruct mem_cgroup_threshold_ary *spare;\n};\n\nstruct memcg_padding {\n\tchar x[0];\n};\n\nstruct memcg_vmstats {\n\tlong int state[42];\n\tlong unsigned int events[100];\n\tlong int state_pending[42];\n\tlong unsigned int events_pending[100];\n};\n\nenum memcg_kmem_state {\n\tKMEM_NONE = 0,\n\tKMEM_ALLOCATED = 1,\n\tKMEM_ONLINE = 2,\n};\n\nstruct percpu_counter {\n\traw_spinlock_t lock;\n\ts64 count;\n\tstruct list_head list;\n\ts32 *counters;\n};\n\nstruct fprop_global {\n\tstruct percpu_counter events;\n\tunsigned int period;\n\tseqcount_t sequence;\n};\n\nstruct wb_domain {\n\tspinlock_t lock;\n\tstruct fprop_global completions;\n\tstruct timer_list period_timer;\n\tlong unsigned int period_time;\n\tlong unsigned int dirty_limit_tstamp;\n\tlong unsigned int dirty_limit;\n};\n\nstruct wb_completion {\n\tatomic_t cnt;\n\twait_queue_head_t *waitq;\n};\n\nstruct memcg_cgwb_frn {\n\tu64 bdi_id;\n\tint memcg_id;\n\tu64 at;\n\tstruct wb_completion done;\n};\n\nstruct obj_cgroup;\n\nstruct memcg_vmstats_percpu;\n\nstruct mem_cgroup_per_node;\n\nstruct mem_cgroup {\n\tstruct cgroup_subsys_state css;\n\tstruct mem_cgroup_id id;\n\tstruct page_counter memory;\n\tunion {\n\t\tstruct page_counter swap;\n\t\tstruct page_counter memsw;\n\t};\n\tstruct page_counter kmem;\n\tstruct page_counter tcpmem;\n\tstruct work_struct high_work;\n\tlong unsigned int soft_limit;\n\tstruct vmpressure vmpressure;\n\tbool oom_group;\n\tbool oom_lock;\n\tint under_oom;\n\tint swappiness;\n\tint oom_kill_disable;\n\tstruct cgroup_file events_file;\n\tstruct cgroup_file events_local_file;\n\tstruct cgroup_file swap_events_file;\n\tstruct mutex thresholds_lock;\n\tstruct mem_cgroup_thresholds thresholds;\n\tstruct mem_cgroup_thresholds memsw_thresholds;\n\tstruct list_head oom_notify;\n\tlong unsigned int move_charge_at_immigrate;\n\tspinlock_t move_lock;\n\tlong unsigned int move_lock_flags;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct memcg_padding _pad1_;\n\tstruct memcg_vmstats vmstats;\n\tatomic_long_t memory_events[8];\n\tatomic_long_t memory_events_local[8];\n\tlong unsigned int socket_pressure;\n\tbool tcpmem_active;\n\tint tcpmem_pressure;\n\tint kmemcg_id;\n\tenum memcg_kmem_state kmem_state;\n\tstruct obj_cgroup *objcg;\n\tstruct list_head objcg_list;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct memcg_padding _pad2_;\n\tatomic_t moving_account;\n\tstruct task_struct *move_lock_task;\n\tstruct memcg_vmstats_percpu *vmstats_percpu;\n\tstruct list_head cgwb_list;\n\tstruct wb_domain cgwb_domain;\n\tstruct memcg_cgwb_frn cgwb_frn[4];\n\tstruct list_head event_list;\n\tspinlock_t event_list_lock;\n\tstruct deferred_split deferred_split_queue;\n\tstruct mem_cgroup_per_node *nodeinfo[0];\n\tlong: 64;\n};\n\nstruct fs_pin;\n\nstruct pid_namespace {\n\tstruct idr idr;\n\tstruct callback_head rcu;\n\tunsigned int pid_allocated;\n\tstruct task_struct *child_reaper;\n\tstruct kmem_cache *pid_cachep;\n\tunsigned int level;\n\tstruct pid_namespace *parent;\n\tstruct fs_pin *bacct;\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tint reboot;\n\tstruct ns_common ns;\n};\n\nstruct ucounts {\n\tstruct hlist_node node;\n\tstruct user_namespace *ns;\n\tkuid_t uid;\n\tatomic_t count;\n\tatomic_long_t ucount[16];\n};\n\nstruct task_cputime {\n\tu64 stime;\n\tu64 utime;\n\tlong long unsigned int sum_exec_runtime;\n};\n\nstruct uts_namespace;\n\nstruct ipc_namespace;\n\nstruct mnt_namespace;\n\nstruct net;\n\nstruct time_namespace;\n\nstruct cgroup_namespace;\n\nstruct nsproxy {\n\tatomic_t count;\n\tstruct uts_namespace *uts_ns;\n\tstruct ipc_namespace *ipc_ns;\n\tstruct mnt_namespace *mnt_ns;\n\tstruct pid_namespace *pid_ns_for_children;\n\tstruct net *net_ns;\n\tstruct time_namespace *time_ns;\n\tstruct time_namespace *time_ns_for_children;\n\tstruct cgroup_namespace *cgroup_ns;\n};\n\nstruct bio;\n\nstruct bio_list {\n\tstruct bio *head;\n\tstruct bio *tail;\n};\n\nstruct blk_plug {\n\tstruct list_head mq_list;\n\tstruct list_head cb_list;\n\tshort unsigned int rq_count;\n\tbool multiple_queues;\n\tbool nowait;\n};\n\nstruct reclaim_state {\n\tlong unsigned int reclaimed_slab;\n};\n\nstruct fprop_local_percpu {\n\tstruct percpu_counter events;\n\tunsigned int period;\n\traw_spinlock_t lock;\n};\n\nenum wb_reason {\n\tWB_REASON_BACKGROUND = 0,\n\tWB_REASON_VMSCAN = 1,\n\tWB_REASON_SYNC = 2,\n\tWB_REASON_PERIODIC = 3,\n\tWB_REASON_LAPTOP_TIMER = 4,\n\tWB_REASON_FS_FREE_SPACE = 5,\n\tWB_REASON_FORKER_THREAD = 6,\n\tWB_REASON_FOREIGN_FLUSH = 7,\n\tWB_REASON_MAX = 8,\n};\n\nstruct bdi_writeback {\n\tstruct backing_dev_info *bdi;\n\tlong unsigned int state;\n\tlong unsigned int last_old_flush;\n\tstruct list_head b_dirty;\n\tstruct list_head b_io;\n\tstruct list_head b_more_io;\n\tstruct list_head b_dirty_time;\n\tspinlock_t list_lock;\n\tstruct percpu_counter stat[4];\n\tlong unsigned int congested;\n\tlong unsigned int bw_time_stamp;\n\tlong unsigned int dirtied_stamp;\n\tlong unsigned int written_stamp;\n\tlong unsigned int write_bandwidth;\n\tlong unsigned int avg_write_bandwidth;\n\tlong unsigned int dirty_ratelimit;\n\tlong unsigned int balanced_dirty_ratelimit;\n\tstruct fprop_local_percpu completions;\n\tint dirty_exceeded;\n\tenum wb_reason start_all_reason;\n\tspinlock_t work_lock;\n\tstruct list_head work_list;\n\tstruct delayed_work dwork;\n\tlong unsigned int dirty_sleep;\n\tstruct list_head bdi_node;\n\tstruct percpu_ref refcnt;\n\tstruct fprop_local_percpu memcg_completions;\n\tstruct cgroup_subsys_state *memcg_css;\n\tstruct cgroup_subsys_state *blkcg_css;\n\tstruct list_head memcg_node;\n\tstruct list_head blkcg_node;\n\tstruct list_head b_attached;\n\tstruct list_head offline_node;\n\tunion {\n\t\tstruct work_struct release_work;\n\t\tstruct callback_head rcu;\n\t};\n};\n\nstruct device;\n\nstruct backing_dev_info {\n\tu64 id;\n\tstruct rb_node rb_node;\n\tstruct list_head bdi_list;\n\tlong unsigned int ra_pages;\n\tlong unsigned int io_pages;\n\tstruct kref refcnt;\n\tunsigned int capabilities;\n\tunsigned int min_ratio;\n\tunsigned int max_ratio;\n\tunsigned int max_prop_frac;\n\tatomic_long_t tot_write_bandwidth;\n\tstruct bdi_writeback wb;\n\tstruct list_head wb_list;\n\tstruct xarray cgwb_tree;\n\tstruct mutex cgwb_release_mutex;\n\tstruct rw_semaphore wb_switch_rwsem;\n\twait_queue_head_t wb_waitq;\n\tstruct device *dev;\n\tchar dev_name[64];\n\tstruct device *owner;\n\tstruct timer_list laptop_mode_wb_timer;\n\tstruct dentry *debug_dir;\n};\n\nstruct css_set {\n\tstruct cgroup_subsys_state *subsys[14];\n\trefcount_t refcount;\n\tstruct css_set *dom_cset;\n\tstruct cgroup *dfl_cgrp;\n\tint nr_tasks;\n\tstruct list_head tasks;\n\tstruct list_head mg_tasks;\n\tstruct list_head dying_tasks;\n\tstruct list_head task_iters;\n\tstruct list_head e_cset_node[14];\n\tstruct list_head threaded_csets;\n\tstruct list_head threaded_csets_node;\n\tstruct hlist_node hlist;\n\tstruct list_head cgrp_links;\n\tstruct list_head mg_preload_node;\n\tstruct list_head mg_node;\n\tstruct cgroup *mg_src_cgrp;\n\tstruct cgroup *mg_dst_cgrp;\n\tstruct css_set *mg_dst_cset;\n\tbool dead;\n\tstruct callback_head callback_head;\n};\n\ntypedef u32 compat_uptr_t;\n\nstruct compat_robust_list {\n\tcompat_uptr_t next;\n};\n\ntypedef s32 compat_long_t;\n\nstruct compat_robust_list_head {\n\tstruct compat_robust_list list;\n\tcompat_long_t futex_offset;\n\tcompat_uptr_t list_op_pending;\n};\n\nstruct perf_event_groups {\n\tstruct rb_root tree;\n\tu64 index;\n};\n\nstruct perf_event_context {\n\tstruct pmu *pmu;\n\traw_spinlock_t lock;\n\tstruct mutex mutex;\n\tstruct list_head active_ctx_list;\n\tstruct perf_event_groups pinned_groups;\n\tstruct perf_event_groups flexible_groups;\n\tstruct list_head event_list;\n\tstruct list_head pinned_active;\n\tstruct list_head flexible_active;\n\tint nr_events;\n\tint nr_active;\n\tint is_active;\n\tint nr_stat;\n\tint nr_freq;\n\tint rotate_disable;\n\tint rotate_necessary;\n\trefcount_t refcount;\n\tstruct task_struct *task;\n\tu64 time;\n\tu64 timestamp;\n\tstruct perf_event_context *parent_ctx;\n\tu64 parent_gen;\n\tu64 generation;\n\tint pin_count;\n\tint nr_cgroups;\n\tvoid *task_ctx_data;\n\tstruct callback_head callback_head;\n};\n\nstruct task_delay_info {\n\traw_spinlock_t lock;\n\tunsigned int flags;\n\tu64 blkio_start;\n\tu64 blkio_delay;\n\tu64 swapin_delay;\n\tu32 blkio_count;\n\tu32 swapin_count;\n\tu64 freepages_start;\n\tu64 freepages_delay;\n\tu64 thrashing_start;\n\tu64 thrashing_delay;\n\tu32 freepages_count;\n\tu32 thrashing_count;\n};\n\nstruct ftrace_ret_stack {\n\tlong unsigned int ret;\n\tlong unsigned int func;\n\tlong long unsigned int calltime;\n\tlong long unsigned int subtime;\n\tlong unsigned int *retp;\n};\n\nstruct blk_integrity_profile;\n\nstruct blk_integrity {\n\tconst struct blk_integrity_profile *profile;\n\tunsigned char flags;\n\tunsigned char tuple_size;\n\tunsigned char interval_exp;\n\tunsigned char tag_size;\n};\n\nenum rpm_status {\n\tRPM_ACTIVE = 0,\n\tRPM_RESUMING = 1,\n\tRPM_SUSPENDED = 2,\n\tRPM_SUSPENDING = 3,\n};\n\nstruct blk_rq_stat {\n\tu64 mean;\n\tu64 min;\n\tu64 max;\n\tu32 nr_samples;\n\tu64 batch;\n};\n\nstruct sbitmap_word;\n\nstruct sbitmap {\n\tunsigned int depth;\n\tunsigned int shift;\n\tunsigned int map_nr;\n\tbool round_robin;\n\tstruct sbitmap_word *map;\n\tunsigned int *alloc_hint;\n};\n\nstruct sbq_wait_state;\n\nstruct sbitmap_queue {\n\tstruct sbitmap sb;\n\tunsigned int wake_batch;\n\tatomic_t wake_index;\n\tstruct sbq_wait_state *ws;\n\tatomic_t ws_active;\n\tunsigned int min_shallow_depth;\n};\n\nenum blk_bounce {\n\tBLK_BOUNCE_NONE = 0,\n\tBLK_BOUNCE_HIGH = 1,\n};\n\nenum blk_zoned_model {\n\tBLK_ZONED_NONE = 0,\n\tBLK_ZONED_HA = 1,\n\tBLK_ZONED_HM = 2,\n};\n\nstruct queue_limits {\n\tenum blk_bounce bounce;\n\tlong unsigned int seg_boundary_mask;\n\tlong unsigned int virt_boundary_mask;\n\tunsigned int max_hw_sectors;\n\tunsigned int max_dev_sectors;\n\tunsigned int chunk_sectors;\n\tunsigned int max_sectors;\n\tunsigned int max_segment_size;\n\tunsigned int physical_block_size;\n\tunsigned int logical_block_size;\n\tunsigned int alignment_offset;\n\tunsigned int io_min;\n\tunsigned int io_opt;\n\tunsigned int max_discard_sectors;\n\tunsigned int max_hw_discard_sectors;\n\tunsigned int max_write_same_sectors;\n\tunsigned int max_write_zeroes_sectors;\n\tunsigned int max_zone_append_sectors;\n\tunsigned int discard_granularity;\n\tunsigned int discard_alignment;\n\tunsigned int zone_write_granularity;\n\tshort unsigned int max_segments;\n\tshort unsigned int max_integrity_segments;\n\tshort unsigned int max_discard_segments;\n\tunsigned char misaligned;\n\tunsigned char discard_misaligned;\n\tunsigned char raid_partial_stripes_expensive;\n\tenum blk_zoned_model zoned;\n};\n\nstruct bsg_ops;\n\nstruct bsg_class_device {\n\tstruct device *class_dev;\n\tint minor;\n\tstruct request_queue *queue;\n\tconst struct bsg_ops *ops;\n};\n\ntypedef void *mempool_alloc_t(gfp_t, void *);\n\ntypedef void mempool_free_t(void *, void *);\n\nstruct mempool_s {\n\tspinlock_t lock;\n\tint min_nr;\n\tint curr_nr;\n\tvoid **elements;\n\tvoid *pool_data;\n\tmempool_alloc_t *alloc;\n\tmempool_free_t *free;\n\twait_queue_head_t wait;\n};\n\ntypedef struct mempool_s mempool_t;\n\nstruct bio_set {\n\tstruct kmem_cache *bio_slab;\n\tunsigned int front_pad;\n\tmempool_t bio_pool;\n\tmempool_t bvec_pool;\n\tmempool_t bio_integrity_pool;\n\tmempool_t bvec_integrity_pool;\n\tunsigned int back_pad;\n\tspinlock_t rescue_lock;\n\tstruct bio_list rescue_list;\n\tstruct work_struct rescue_work;\n\tstruct workqueue_struct *rescue_workqueue;\n};\n\nstruct request;\n\nstruct elevator_queue;\n\nstruct blk_queue_stats;\n\nstruct rq_qos;\n\nstruct blk_mq_ops;\n\nstruct blk_mq_ctx;\n\nstruct blk_mq_hw_ctx;\n\nstruct blk_keyslot_manager;\n\nstruct blk_stat_callback;\n\nstruct blkcg_gq;\n\nstruct blk_trace;\n\nstruct blk_flush_queue;\n\nstruct throtl_data;\n\nstruct blk_mq_tag_set;\n\nstruct request_queue {\n\tstruct request *last_merge;\n\tstruct elevator_queue *elevator;\n\tstruct percpu_ref q_usage_counter;\n\tstruct blk_queue_stats *stats;\n\tstruct rq_qos *rq_qos;\n\tconst struct blk_mq_ops *mq_ops;\n\tstruct blk_mq_ctx *queue_ctx;\n\tunsigned int queue_depth;\n\tstruct blk_mq_hw_ctx **queue_hw_ctx;\n\tunsigned int nr_hw_queues;\n\tstruct backing_dev_info *backing_dev_info;\n\tvoid *queuedata;\n\tlong unsigned int queue_flags;\n\tatomic_t pm_only;\n\tint id;\n\tspinlock_t queue_lock;\n\tstruct kobject kobj;\n\tstruct kobject *mq_kobj;\n\tstruct blk_integrity integrity;\n\tstruct device *dev;\n\tenum rpm_status rpm_status;\n\tlong unsigned int nr_requests;\n\tunsigned int dma_pad_mask;\n\tunsigned int dma_alignment;\n\tstruct blk_keyslot_manager *ksm;\n\tunsigned int rq_timeout;\n\tint poll_nsec;\n\tstruct blk_stat_callback *poll_cb;\n\tstruct blk_rq_stat poll_stat[16];\n\tstruct timer_list timeout;\n\tstruct work_struct timeout_work;\n\tatomic_t nr_active_requests_shared_sbitmap;\n\tstruct sbitmap_queue sched_bitmap_tags;\n\tstruct sbitmap_queue sched_breserved_tags;\n\tstruct list_head icq_list;\n\tlong unsigned int blkcg_pols[1];\n\tstruct blkcg_gq *root_blkg;\n\tstruct list_head blkg_list;\n\tstruct queue_limits limits;\n\tunsigned int required_elevator_features;\n\tunsigned int nr_zones;\n\tlong unsigned int *conv_zones_bitmap;\n\tlong unsigned int *seq_zones_wlock;\n\tunsigned int max_open_zones;\n\tunsigned int max_active_zones;\n\tunsigned int sg_timeout;\n\tunsigned int sg_reserved_size;\n\tint node;\n\tstruct mutex debugfs_mutex;\n\tstruct blk_trace *blk_trace;\n\tstruct blk_flush_queue *fq;\n\tstruct list_head requeue_list;\n\tspinlock_t requeue_lock;\n\tstruct delayed_work requeue_work;\n\tstruct mutex sysfs_lock;\n\tstruct mutex sysfs_dir_lock;\n\tstruct list_head unused_hctx_list;\n\tspinlock_t unused_hctx_lock;\n\tint mq_freeze_depth;\n\tstruct bsg_class_device bsg_dev;\n\tstruct throtl_data *td;\n\tstruct callback_head callback_head;\n\twait_queue_head_t mq_freeze_wq;\n\tstruct mutex mq_freeze_lock;\n\tstruct blk_mq_tag_set *tag_set;\n\tstruct list_head tag_set_list;\n\tstruct bio_set bio_split;\n\tstruct dentry *debugfs_dir;\n\tstruct dentry *sched_debugfs_dir;\n\tstruct dentry *rqos_debugfs_dir;\n\tbool mq_sysfs_init_done;\n\tsize_t cmd_size;\n\tu64 write_hints[5];\n};\n\nstruct cgroup_base_stat {\n\tstruct task_cputime cputime;\n};\n\nstruct psi_group_cpu;\n\nstruct psi_group {\n\tstruct mutex avgs_lock;\n\tstruct psi_group_cpu *pcpu;\n\tu64 avg_total[6];\n\tu64 avg_last_update;\n\tu64 avg_next_update;\n\tstruct delayed_work avgs_work;\n\tu64 total[12];\n\tlong unsigned int avg[18];\n\tstruct task_struct *poll_task;\n\tstruct timer_list poll_timer;\n\twait_queue_head_t poll_wait;\n\tatomic_t poll_wakeup;\n\tstruct mutex trigger_lock;\n\tstruct list_head triggers;\n\tu32 nr_triggers[6];\n\tu32 poll_states;\n\tu64 poll_min_period;\n\tu64 polling_total[6];\n\tu64 polling_next_update;\n\tu64 polling_until;\n};\n\nstruct cgroup_bpf {\n\tstruct bpf_prog_array *effective[41];\n\tstruct list_head progs[41];\n\tu32 flags[41];\n\tstruct list_head storages;\n\tstruct bpf_prog_array *inactive;\n\tstruct percpu_ref refcnt;\n\tstruct work_struct release_work;\n};\n\nstruct cgroup_freezer_state {\n\tbool freeze;\n\tint e_freeze;\n\tint nr_frozen_descendants;\n\tint nr_frozen_tasks;\n};\n\nstruct cgroup_root;\n\nstruct cgroup_rstat_cpu;\n\nstruct cgroup {\n\tstruct cgroup_subsys_state self;\n\tlong unsigned int flags;\n\tint level;\n\tint max_depth;\n\tint nr_descendants;\n\tint nr_dying_descendants;\n\tint max_descendants;\n\tint nr_populated_csets;\n\tint nr_populated_domain_children;\n\tint nr_populated_threaded_children;\n\tint nr_threaded_children;\n\tstruct kernfs_node *kn;\n\tstruct cgroup_file procs_file;\n\tstruct cgroup_file events_file;\n\tu16 subtree_control;\n\tu16 subtree_ss_mask;\n\tu16 old_subtree_control;\n\tu16 old_subtree_ss_mask;\n\tstruct cgroup_subsys_state *subsys[14];\n\tstruct cgroup_root *root;\n\tstruct list_head cset_links;\n\tstruct list_head e_csets[14];\n\tstruct cgroup *dom_cgrp;\n\tstruct cgroup *old_dom_cgrp;\n\tstruct cgroup_rstat_cpu *rstat_cpu;\n\tstruct list_head rstat_css_list;\n\tstruct cgroup_base_stat last_bstat;\n\tstruct cgroup_base_stat bstat;\n\tstruct prev_cputime prev_cputime;\n\tstruct list_head pidlists;\n\tstruct mutex pidlist_mutex;\n\twait_queue_head_t offline_waitq;\n\tstruct work_struct release_agent_work;\n\tstruct psi_group psi;\n\tstruct cgroup_bpf bpf;\n\tatomic_t congestion_count;\n\tstruct cgroup_freezer_state freezer;\n\tu64 ancestor_ids[0];\n};\n\nstruct taskstats {\n\t__u16 version;\n\t__u32 ac_exitcode;\n\t__u8 ac_flag;\n\t__u8 ac_nice;\n\t__u64 cpu_count;\n\t__u64 cpu_delay_total;\n\t__u64 blkio_count;\n\t__u64 blkio_delay_total;\n\t__u64 swapin_count;\n\t__u64 swapin_delay_total;\n\t__u64 cpu_run_real_total;\n\t__u64 cpu_run_virtual_total;\n\tchar ac_comm[32];\n\t__u8 ac_sched;\n\t__u8 ac_pad[3];\n\tint: 32;\n\t__u32 ac_uid;\n\t__u32 ac_gid;\n\t__u32 ac_pid;\n\t__u32 ac_ppid;\n\t__u32 ac_btime;\n\t__u64 ac_etime;\n\t__u64 ac_utime;\n\t__u64 ac_stime;\n\t__u64 ac_minflt;\n\t__u64 ac_majflt;\n\t__u64 coremem;\n\t__u64 virtmem;\n\t__u64 hiwater_rss;\n\t__u64 hiwater_vm;\n\t__u64 read_char;\n\t__u64 write_char;\n\t__u64 read_syscalls;\n\t__u64 write_syscalls;\n\t__u64 read_bytes;\n\t__u64 write_bytes;\n\t__u64 cancelled_write_bytes;\n\t__u64 nvcsw;\n\t__u64 nivcsw;\n\t__u64 ac_utimescaled;\n\t__u64 ac_stimescaled;\n\t__u64 cpu_scaled_run_real_total;\n\t__u64 freepages_count;\n\t__u64 freepages_delay_total;\n\t__u64 thrashing_count;\n\t__u64 thrashing_delay_total;\n\t__u64 ac_btime64;\n};\n\ntypedef struct {\n\t__u8 b[16];\n} guid_t;\n\nstruct wait_page_queue {\n\tstruct page *page;\n\tint bit_nr;\n\twait_queue_entry_t wait;\n};\n\nenum writeback_sync_modes {\n\tWB_SYNC_NONE = 0,\n\tWB_SYNC_ALL = 1,\n};\n\nstruct writeback_control {\n\tlong int nr_to_write;\n\tlong int pages_skipped;\n\tloff_t range_start;\n\tloff_t range_end;\n\tenum writeback_sync_modes sync_mode;\n\tunsigned int for_kupdate: 1;\n\tunsigned int for_background: 1;\n\tunsigned int tagged_writepages: 1;\n\tunsigned int for_reclaim: 1;\n\tunsigned int range_cyclic: 1;\n\tunsigned int for_sync: 1;\n\tunsigned int no_cgroup_owner: 1;\n\tunsigned int punt_to_cgroup: 1;\n\tstruct bdi_writeback *wb;\n\tstruct inode *inode;\n\tint wb_id;\n\tint wb_lcand_id;\n\tint wb_tcand_id;\n\tsize_t wb_bytes;\n\tsize_t wb_lcand_bytes;\n\tsize_t wb_tcand_bytes;\n};\n\nstruct readahead_control {\n\tstruct file *file;\n\tstruct address_space *mapping;\n\tstruct file_ra_state *ra;\n\tlong unsigned int _index;\n\tunsigned int _nr_pages;\n\tunsigned int _batch_count;\n};\n\nstruct iovec;\n\nstruct kvec;\n\nstruct bio_vec;\n\nstruct iov_iter {\n\tu8 iter_type;\n\tbool data_source;\n\tsize_t iov_offset;\n\tsize_t count;\n\tunion {\n\t\tconst struct iovec *iov;\n\t\tconst struct kvec *kvec;\n\t\tconst struct bio_vec *bvec;\n\t\tstruct xarray *xarray;\n\t\tstruct pipe_inode_info *pipe;\n\t};\n\tunion {\n\t\tlong unsigned int nr_segs;\n\t\tstruct {\n\t\t\tunsigned int head;\n\t\t\tunsigned int start_head;\n\t\t};\n\t\tloff_t xarray_start;\n\t};\n};\n\nstruct swap_cluster_info {\n\tspinlock_t lock;\n\tunsigned int data: 24;\n\tunsigned int flags: 8;\n};\n\nstruct swap_cluster_list {\n\tstruct swap_cluster_info head;\n\tstruct swap_cluster_info tail;\n};\n\nstruct percpu_cluster;\n\nstruct swap_info_struct {\n\tstruct percpu_ref users;\n\tlong unsigned int flags;\n\tshort int prio;\n\tstruct plist_node list;\n\tsigned char type;\n\tunsigned int max;\n\tunsigned char *swap_map;\n\tstruct swap_cluster_info *cluster_info;\n\tstruct swap_cluster_list free_clusters;\n\tunsigned int lowest_bit;\n\tunsigned int highest_bit;\n\tunsigned int pages;\n\tunsigned int inuse_pages;\n\tunsigned int cluster_next;\n\tunsigned int cluster_nr;\n\tunsigned int *cluster_next_cpu;\n\tstruct percpu_cluster *percpu_cluster;\n\tstruct rb_root swap_extent_root;\n\tstruct block_device *bdev;\n\tstruct file *swap_file;\n\tunsigned int old_block_size;\n\tstruct completion comp;\n\tlong unsigned int *frontswap_map;\n\tatomic_t frontswap_pages;\n\tspinlock_t lock;\n\tspinlock_t cont_lock;\n\tstruct work_struct discard_work;\n\tstruct swap_cluster_list discard_clusters;\n\tstruct plist_node avail_lists[0];\n};\n\nstruct cdev {\n\tstruct kobject kobj;\n\tstruct module *owner;\n\tconst struct file_operations *ops;\n\tstruct list_head list;\n\tdev_t dev;\n\tunsigned int count;\n};\n\nenum dl_dev_state {\n\tDL_DEV_NO_DRIVER = 0,\n\tDL_DEV_PROBING = 1,\n\tDL_DEV_DRIVER_BOUND = 2,\n\tDL_DEV_UNBINDING = 3,\n};\n\nstruct dev_links_info {\n\tstruct list_head suppliers;\n\tstruct list_head consumers;\n\tstruct list_head defer_sync;\n\tenum dl_dev_state status;\n};\n\nstruct pm_message {\n\tint event;\n};\n\ntypedef struct pm_message pm_message_t;\n\nenum rpm_request {\n\tRPM_REQ_NONE = 0,\n\tRPM_REQ_IDLE = 1,\n\tRPM_REQ_SUSPEND = 2,\n\tRPM_REQ_AUTOSUSPEND = 3,\n\tRPM_REQ_RESUME = 4,\n};\n\nstruct wakeup_source;\n\nstruct wake_irq;\n\nstruct pm_subsys_data;\n\nstruct dev_pm_qos;\n\nstruct dev_pm_info {\n\tpm_message_t power_state;\n\tunsigned int can_wakeup: 1;\n\tunsigned int async_suspend: 1;\n\tbool in_dpm_list: 1;\n\tbool is_prepared: 1;\n\tbool is_suspended: 1;\n\tbool is_noirq_suspended: 1;\n\tbool is_late_suspended: 1;\n\tbool no_pm: 1;\n\tbool early_init: 1;\n\tbool direct_complete: 1;\n\tu32 driver_flags;\n\tspinlock_t lock;\n\tstruct list_head entry;\n\tstruct completion completion;\n\tstruct wakeup_source *wakeup;\n\tbool wakeup_path: 1;\n\tbool syscore: 1;\n\tbool no_pm_callbacks: 1;\n\tunsigned int must_resume: 1;\n\tunsigned int may_skip_resume: 1;\n\tstruct hrtimer suspend_timer;\n\tu64 timer_expires;\n\tstruct work_struct work;\n\twait_queue_head_t wait_queue;\n\tstruct wake_irq *wakeirq;\n\tatomic_t usage_count;\n\tatomic_t child_count;\n\tunsigned int disable_depth: 3;\n\tunsigned int idle_notification: 1;\n\tunsigned int request_pending: 1;\n\tunsigned int deferred_resume: 1;\n\tunsigned int needs_force_resume: 1;\n\tunsigned int runtime_auto: 1;\n\tbool ignore_children: 1;\n\tunsigned int no_callbacks: 1;\n\tunsigned int irq_safe: 1;\n\tunsigned int use_autosuspend: 1;\n\tunsigned int timer_autosuspends: 1;\n\tunsigned int memalloc_noio: 1;\n\tunsigned int links_count;\n\tenum rpm_request request;\n\tenum rpm_status runtime_status;\n\tint runtime_error;\n\tint autosuspend_delay;\n\tu64 last_busy;\n\tu64 active_time;\n\tu64 suspended_time;\n\tu64 accounting_timestamp;\n\tstruct pm_subsys_data *subsys_data;\n\tvoid (*set_latency_tolerance)(struct device *, s32);\n\tstruct dev_pm_qos *qos;\n};\n\nstruct dev_archdata {};\n\nenum device_removable {\n\tDEVICE_REMOVABLE_NOT_SUPPORTED = 0,\n\tDEVICE_REMOVABLE_UNKNOWN = 1,\n\tDEVICE_FIXED = 2,\n\tDEVICE_REMOVABLE = 3,\n};\n\nstruct device_private;\n\nstruct device_type;\n\nstruct bus_type;\n\nstruct device_driver;\n\nstruct dev_pm_domain;\n\nstruct em_perf_domain;\n\nstruct dev_pin_info;\n\nstruct dma_map_ops;\n\nstruct bus_dma_region;\n\nstruct device_dma_parameters;\n\nstruct cma;\n\nstruct device_node;\n\nstruct class;\n\nstruct iommu_group;\n\nstruct dev_iommu;\n\nstruct device {\n\tstruct kobject kobj;\n\tstruct device *parent;\n\tstruct device_private *p;\n\tconst char *init_name;\n\tconst struct device_type *type;\n\tstruct bus_type *bus;\n\tstruct device_driver *driver;\n\tvoid *platform_data;\n\tvoid *driver_data;\n\tstruct mutex mutex;\n\tstruct dev_links_info links;\n\tstruct dev_pm_info power;\n\tstruct dev_pm_domain *pm_domain;\n\tstruct em_perf_domain *em_pd;\n\tstruct irq_domain *msi_domain;\n\tstruct dev_pin_info *pins;\n\traw_spinlock_t msi_lock;\n\tstruct list_head msi_list;\n\tconst struct dma_map_ops *dma_ops;\n\tu64 *dma_mask;\n\tu64 coherent_dma_mask;\n\tu64 bus_dma_limit;\n\tconst struct bus_dma_region *dma_range_map;\n\tstruct device_dma_parameters *dma_parms;\n\tstruct list_head dma_pools;\n\tstruct cma *cma_area;\n\tstruct dev_archdata archdata;\n\tstruct device_node *of_node;\n\tstruct fwnode_handle *fwnode;\n\tint numa_node;\n\tdev_t devt;\n\tu32 id;\n\tspinlock_t devres_lock;\n\tstruct list_head devres_head;\n\tstruct class *class;\n\tconst struct attribute_group **groups;\n\tvoid (*release)(struct device *);\n\tstruct iommu_group *iommu_group;\n\tstruct dev_iommu *iommu;\n\tenum device_removable removable;\n\tbool offline_disabled: 1;\n\tbool offline: 1;\n\tbool of_node_reused: 1;\n\tbool state_synced: 1;\n\tbool can_match: 1;\n};\n\nstruct disk_stats;\n\nstruct gendisk;\n\nstruct partition_meta_info;\n\nstruct block_device {\n\tsector_t bd_start_sect;\n\tstruct disk_stats *bd_stats;\n\tlong unsigned int bd_stamp;\n\tbool bd_read_only;\n\tdev_t bd_dev;\n\tint bd_openers;\n\tstruct inode *bd_inode;\n\tstruct super_block *bd_super;\n\tvoid *bd_claiming;\n\tstruct device bd_device;\n\tvoid *bd_holder;\n\tint bd_holders;\n\tbool bd_write_holder;\n\tstruct list_head bd_holder_disks;\n\tstruct kobject *bd_holder_dir;\n\tu8 bd_partno;\n\tspinlock_t bd_size_lock;\n\tstruct gendisk *bd_disk;\n\tstruct backing_dev_info *bd_bdi;\n\tint bd_fsfreeze_count;\n\tstruct mutex bd_fsfreeze_mutex;\n\tstruct super_block *bd_fsfreeze_sb;\n\tstruct partition_meta_info *bd_meta_info;\n};\n\nstruct fc_log;\n\nstruct p_log {\n\tconst char *prefix;\n\tstruct fc_log *log;\n};\n\nenum fs_context_purpose {\n\tFS_CONTEXT_FOR_MOUNT = 0,\n\tFS_CONTEXT_FOR_SUBMOUNT = 1,\n\tFS_CONTEXT_FOR_RECONFIGURE = 2,\n};\n\nenum fs_context_phase {\n\tFS_CONTEXT_CREATE_PARAMS = 0,\n\tFS_CONTEXT_CREATING = 1,\n\tFS_CONTEXT_AWAITING_MOUNT = 2,\n\tFS_CONTEXT_AWAITING_RECONF = 3,\n\tFS_CONTEXT_RECONF_PARAMS = 4,\n\tFS_CONTEXT_RECONFIGURING = 5,\n\tFS_CONTEXT_FAILED = 6,\n};\n\nstruct fs_context_operations;\n\nstruct fs_context {\n\tconst struct fs_context_operations *ops;\n\tstruct mutex uapi_mutex;\n\tstruct file_system_type *fs_type;\n\tvoid *fs_private;\n\tvoid *sget_key;\n\tstruct dentry *root;\n\tstruct user_namespace *user_ns;\n\tstruct net *net_ns;\n\tconst struct cred *cred;\n\tstruct p_log log;\n\tconst char *source;\n\tvoid *security;\n\tvoid *s_fs_info;\n\tunsigned int sb_flags;\n\tunsigned int sb_flags_mask;\n\tunsigned int s_iflags;\n\tunsigned int lsm_flags;\n\tenum fs_context_purpose purpose: 8;\n\tenum fs_context_phase phase: 8;\n\tbool need_free: 1;\n\tbool global: 1;\n\tbool oldapi: 1;\n};\n\nstruct audit_names;\n\nstruct filename {\n\tconst char *name;\n\tconst char *uptr;\n\tint refcnt;\n\tstruct audit_names *aname;\n\tconst char iname[0];\n};\n\ntypedef u8 blk_status_t;\n\nstruct bvec_iter {\n\tsector_t bi_sector;\n\tunsigned int bi_size;\n\tunsigned int bi_idx;\n\tunsigned int bi_bvec_done;\n};\n\ntypedef void bio_end_io_t(struct bio *);\n\nstruct bio_issue {\n\tu64 value;\n};\n\nstruct bio_vec {\n\tstruct page *bv_page;\n\tunsigned int bv_len;\n\tunsigned int bv_offset;\n};\n\nstruct bio_crypt_ctx;\n\nstruct bio_integrity_payload;\n\nstruct bio {\n\tstruct bio *bi_next;\n\tstruct block_device *bi_bdev;\n\tunsigned int bi_opf;\n\tshort unsigned int bi_flags;\n\tshort unsigned int bi_ioprio;\n\tshort unsigned int bi_write_hint;\n\tblk_status_t bi_status;\n\tatomic_t __bi_remaining;\n\tstruct bvec_iter bi_iter;\n\tbio_end_io_t *bi_end_io;\n\tvoid *bi_private;\n\tstruct blkcg_gq *bi_blkg;\n\tstruct bio_issue bi_issue;\n\tu64 bi_iocost_cost;\n\tstruct bio_crypt_ctx *bi_crypt_context;\n\tunion {\n\t\tstruct bio_integrity_payload *bi_integrity;\n\t};\n\tshort unsigned int bi_vcnt;\n\tshort unsigned int bi_max_vecs;\n\tatomic_t __bi_cnt;\n\tstruct bio_vec *bi_io_vec;\n\tstruct bio_set *bi_pool;\n\tstruct bio_vec bi_inline_vecs[0];\n};\n\nstruct linux_binprm {\n\tstruct vm_area_struct *vma;\n\tlong unsigned int vma_pages;\n\tstruct mm_struct *mm;\n\tlong unsigned int p;\n\tlong unsigned int argmin;\n\tunsigned int have_execfd: 1;\n\tunsigned int execfd_creds: 1;\n\tunsigned int secureexec: 1;\n\tunsigned int point_of_no_return: 1;\n\tstruct file *executable;\n\tstruct file *interpreter;\n\tstruct file *file;\n\tstruct cred *cred;\n\tint unsafe;\n\tunsigned int per_clear;\n\tint argc;\n\tint envc;\n\tconst char *filename;\n\tconst char *interp;\n\tconst char *fdpath;\n\tunsigned int interp_flags;\n\tint execfd;\n\tlong unsigned int loader;\n\tlong unsigned int exec;\n\tstruct rlimit rlim_stack;\n\tchar buf[256];\n};\n\nstruct coredump_params {\n\tconst kernel_siginfo_t *siginfo;\n\tstruct pt_regs *regs;\n\tstruct file *file;\n\tlong unsigned int limit;\n\tlong unsigned int mm_flags;\n\tloff_t written;\n\tloff_t pos;\n\tloff_t to_skip;\n};\n\nstruct em_perf_state {\n\tlong unsigned int frequency;\n\tlong unsigned int power;\n\tlong unsigned int cost;\n};\n\nstruct em_perf_domain {\n\tstruct em_perf_state *table;\n\tint nr_perf_states;\n\tint milliwatts;\n\tlong unsigned int cpus[0];\n};\n\nstruct dev_pm_ops {\n\tint (*prepare)(struct device *);\n\tvoid (*complete)(struct device *);\n\tint (*suspend)(struct device *);\n\tint (*resume)(struct device *);\n\tint (*freeze)(struct device *);\n\tint (*thaw)(struct device *);\n\tint (*poweroff)(struct device *);\n\tint (*restore)(struct device *);\n\tint (*suspend_late)(struct device *);\n\tint (*resume_early)(struct device *);\n\tint (*freeze_late)(struct device *);\n\tint (*thaw_early)(struct device *);\n\tint (*poweroff_late)(struct device *);\n\tint (*restore_early)(struct device *);\n\tint (*suspend_noirq)(struct device *);\n\tint (*resume_noirq)(struct device *);\n\tint (*freeze_noirq)(struct device *);\n\tint (*thaw_noirq)(struct device *);\n\tint (*poweroff_noirq)(struct device *);\n\tint (*restore_noirq)(struct device *);\n\tint (*runtime_suspend)(struct device *);\n\tint (*runtime_resume)(struct device *);\n\tint (*runtime_idle)(struct device *);\n};\n\nstruct pm_domain_data;\n\nstruct pm_subsys_data {\n\tspinlock_t lock;\n\tunsigned int refcount;\n\tunsigned int clock_op_might_sleep;\n\tstruct mutex clock_mutex;\n\tstruct list_head clock_list;\n\tstruct pm_domain_data *domain_data;\n};\n\nstruct wakeup_source {\n\tconst char *name;\n\tint id;\n\tstruct list_head entry;\n\tspinlock_t lock;\n\tstruct wake_irq *wakeirq;\n\tstruct timer_list timer;\n\tlong unsigned int timer_expires;\n\tktime_t total_time;\n\tktime_t max_time;\n\tktime_t last_time;\n\tktime_t start_prevent_time;\n\tktime_t prevent_sleep_time;\n\tlong unsigned int event_count;\n\tlong unsigned int active_count;\n\tlong unsigned int relax_count;\n\tlong unsigned int expire_count;\n\tlong unsigned int wakeup_count;\n\tstruct device *dev;\n\tbool active: 1;\n\tbool autosleep_enabled: 1;\n};\n\nstruct dev_pm_domain {\n\tstruct dev_pm_ops ops;\n\tint (*start)(struct device *);\n\tvoid (*detach)(struct device *, bool);\n\tint (*activate)(struct device *);\n\tvoid (*sync)(struct device *);\n\tvoid (*dismiss)(struct device *);\n};\n\nstruct iommu_ops;\n\nstruct subsys_private;\n\nstruct bus_type {\n\tconst char *name;\n\tconst char *dev_name;\n\tstruct device *dev_root;\n\tconst struct attribute_group **bus_groups;\n\tconst struct attribute_group **dev_groups;\n\tconst struct attribute_group **drv_groups;\n\tint (*match)(struct device *, struct device_driver *);\n\tint (*uevent)(struct device *, struct kobj_uevent_env *);\n\tint (*probe)(struct device *);\n\tvoid (*sync_state)(struct device *);\n\tint (*remove)(struct device *);\n\tvoid (*shutdown)(struct device *);\n\tint (*online)(struct device *);\n\tint (*offline)(struct device *);\n\tint (*suspend)(struct device *, pm_message_t);\n\tint (*resume)(struct device *);\n\tint (*num_vf)(struct device *);\n\tint (*dma_configure)(struct device *);\n\tconst struct dev_pm_ops *pm;\n\tconst struct iommu_ops *iommu_ops;\n\tstruct subsys_private *p;\n\tstruct lock_class_key lock_key;\n\tbool need_parent_lock;\n};\n\nenum probe_type {\n\tPROBE_DEFAULT_STRATEGY = 0,\n\tPROBE_PREFER_ASYNCHRONOUS = 1,\n\tPROBE_FORCE_SYNCHRONOUS = 2,\n};\n\nstruct of_device_id;\n\nstruct acpi_device_id;\n\nstruct driver_private;\n\nstruct device_driver {\n\tconst char *name;\n\tstruct bus_type *bus;\n\tstruct module *owner;\n\tconst char *mod_name;\n\tbool suppress_bind_attrs;\n\tenum probe_type probe_type;\n\tconst struct of_device_id *of_match_table;\n\tconst struct acpi_device_id *acpi_match_table;\n\tint (*probe)(struct device *);\n\tvoid (*sync_state)(struct device *);\n\tint (*remove)(struct device *);\n\tvoid (*shutdown)(struct device *);\n\tint (*suspend)(struct device *, pm_message_t);\n\tint (*resume)(struct device *);\n\tconst struct attribute_group **groups;\n\tconst struct attribute_group **dev_groups;\n\tconst struct dev_pm_ops *pm;\n\tvoid (*coredump)(struct device *);\n\tstruct driver_private *p;\n};\n\nenum iommu_cap {\n\tIOMMU_CAP_CACHE_COHERENCY = 0,\n\tIOMMU_CAP_INTR_REMAP = 1,\n\tIOMMU_CAP_NOEXEC = 2,\n};\n\ntypedef u64 dma_addr_t;\n\nenum iommu_dev_features {\n\tIOMMU_DEV_FEAT_AUX = 0,\n\tIOMMU_DEV_FEAT_SVA = 1,\n\tIOMMU_DEV_FEAT_IOPF = 2,\n};\n\nstruct iommu_domain;\n\nstruct iommu_iotlb_gather;\n\nstruct iommu_device;\n\nstruct iommu_resv_region;\n\nstruct of_phandle_args;\n\nstruct iommu_sva;\n\nstruct iommu_fault_event;\n\nstruct iommu_page_response;\n\nstruct iommu_cache_invalidate_info;\n\nstruct iommu_gpasid_bind_data;\n\nstruct iommu_ops {\n\tbool (*capable)(enum iommu_cap);\n\tstruct iommu_domain * (*domain_alloc)(unsigned int);\n\tvoid (*domain_free)(struct iommu_domain *);\n\tint (*attach_dev)(struct iommu_domain *, struct device *);\n\tvoid (*detach_dev)(struct iommu_domain *, struct device *);\n\tint (*map)(struct iommu_domain *, long unsigned int, phys_addr_t, size_t, int, gfp_t);\n\tsize_t (*unmap)(struct iommu_domain *, long unsigned int, size_t, struct iommu_iotlb_gather *);\n\tvoid (*flush_iotlb_all)(struct iommu_domain *);\n\tvoid (*iotlb_sync_map)(struct iommu_domain *, long unsigned int, size_t);\n\tvoid (*iotlb_sync)(struct iommu_domain *, struct iommu_iotlb_gather *);\n\tphys_addr_t (*iova_to_phys)(struct iommu_domain *, dma_addr_t);\n\tstruct iommu_device * (*probe_device)(struct device *);\n\tvoid (*release_device)(struct device *);\n\tvoid (*probe_finalize)(struct device *);\n\tstruct iommu_group * (*device_group)(struct device *);\n\tint (*enable_nesting)(struct iommu_domain *);\n\tint (*set_pgtable_quirks)(struct iommu_domain *, long unsigned int);\n\tvoid (*get_resv_regions)(struct device *, struct list_head *);\n\tvoid (*put_resv_regions)(struct device *, struct list_head *);\n\tvoid (*apply_resv_region)(struct device *, struct iommu_domain *, struct iommu_resv_region *);\n\tint (*of_xlate)(struct device *, struct of_phandle_args *);\n\tbool (*is_attach_deferred)(struct iommu_domain *, struct device *);\n\tbool (*dev_has_feat)(struct device *, enum iommu_dev_features);\n\tbool (*dev_feat_enabled)(struct device *, enum iommu_dev_features);\n\tint (*dev_enable_feat)(struct device *, enum iommu_dev_features);\n\tint (*dev_disable_feat)(struct device *, enum iommu_dev_features);\n\tint (*aux_attach_dev)(struct iommu_domain *, struct device *);\n\tvoid (*aux_detach_dev)(struct iommu_domain *, struct device *);\n\tint (*aux_get_pasid)(struct iommu_domain *, struct device *);\n\tstruct iommu_sva * (*sva_bind)(struct device *, struct mm_struct *, void *);\n\tvoid (*sva_unbind)(struct iommu_sva *);\n\tu32 (*sva_get_pasid)(struct iommu_sva *);\n\tint (*page_response)(struct device *, struct iommu_fault_event *, struct iommu_page_response *);\n\tint (*cache_invalidate)(struct iommu_domain *, struct device *, struct iommu_cache_invalidate_info *);\n\tint (*sva_bind_gpasid)(struct iommu_domain *, struct device *, struct iommu_gpasid_bind_data *);\n\tint (*sva_unbind_gpasid)(struct device *, u32);\n\tint (*def_domain_type)(struct device *);\n\tlong unsigned int pgsize_bitmap;\n\tstruct module *owner;\n};\n\nstruct device_type {\n\tconst char *name;\n\tconst struct attribute_group **groups;\n\tint (*uevent)(struct device *, struct kobj_uevent_env *);\n\tchar * (*devnode)(struct device *, umode_t *, kuid_t *, kgid_t *);\n\tvoid (*release)(struct device *);\n\tconst struct dev_pm_ops *pm;\n};\n\nstruct class {\n\tconst char *name;\n\tstruct module *owner;\n\tconst struct attribute_group **class_groups;\n\tconst struct attribute_group **dev_groups;\n\tstruct kobject *dev_kobj;\n\tint (*dev_uevent)(struct device *, struct kobj_uevent_env *);\n\tchar * (*devnode)(struct device *, umode_t *);\n\tvoid (*class_release)(struct class *);\n\tvoid (*dev_release)(struct device *);\n\tint (*shutdown_pre)(struct device *);\n\tconst struct kobj_ns_type_operations *ns_type;\n\tconst void * (*namespace)(struct device *);\n\tvoid (*get_ownership)(struct device *, kuid_t *, kgid_t *);\n\tconst struct dev_pm_ops *pm;\n\tstruct subsys_private *p;\n};\n\nstruct of_device_id {\n\tchar name[32];\n\tchar type[32];\n\tchar compatible[128];\n\tconst void *data;\n};\n\ntypedef long unsigned int kernel_ulong_t;\n\nstruct acpi_device_id {\n\t__u8 id[9];\n\tkernel_ulong_t driver_data;\n\t__u32 cls;\n\t__u32 cls_msk;\n};\n\nstruct device_dma_parameters {\n\tunsigned int max_segment_size;\n\tunsigned int min_align_mask;\n\tlong unsigned int segment_boundary_mask;\n};\n\nenum dma_data_direction {\n\tDMA_BIDIRECTIONAL = 0,\n\tDMA_TO_DEVICE = 1,\n\tDMA_FROM_DEVICE = 2,\n\tDMA_NONE = 3,\n};\n\nstruct sg_table;\n\nstruct scatterlist;\n\nstruct dma_map_ops {\n\tvoid * (*alloc)(struct device *, size_t, dma_addr_t *, gfp_t, long unsigned int);\n\tvoid (*free)(struct device *, size_t, void *, dma_addr_t, long unsigned int);\n\tstruct page * (*alloc_pages)(struct device *, size_t, dma_addr_t *, enum dma_data_direction, gfp_t);\n\tvoid (*free_pages)(struct device *, size_t, struct page *, dma_addr_t, enum dma_data_direction);\n\tstruct sg_table * (*alloc_noncontiguous)(struct device *, size_t, enum dma_data_direction, gfp_t, long unsigned int);\n\tvoid (*free_noncontiguous)(struct device *, size_t, struct sg_table *, enum dma_data_direction);\n\tint (*mmap)(struct device *, struct vm_area_struct *, void *, dma_addr_t, size_t, long unsigned int);\n\tint (*get_sgtable)(struct device *, struct sg_table *, void *, dma_addr_t, size_t, long unsigned int);\n\tdma_addr_t (*map_page)(struct device *, struct page *, long unsigned int, size_t, enum dma_data_direction, long unsigned int);\n\tvoid (*unmap_page)(struct device *, dma_addr_t, size_t, enum dma_data_direction, long unsigned int);\n\tint (*map_sg)(struct device *, struct scatterlist *, int, enum dma_data_direction, long unsigned int);\n\tvoid (*unmap_sg)(struct device *, struct scatterlist *, int, enum dma_data_direction, long unsigned int);\n\tdma_addr_t (*map_resource)(struct device *, phys_addr_t, size_t, enum dma_data_direction, long unsigned int);\n\tvoid (*unmap_resource)(struct device *, dma_addr_t, size_t, enum dma_data_direction, long unsigned int);\n\tvoid (*sync_single_for_cpu)(struct device *, dma_addr_t, size_t, enum dma_data_direction);\n\tvoid (*sync_single_for_device)(struct device *, dma_addr_t, size_t, enum dma_data_direction);\n\tvoid (*sync_sg_for_cpu)(struct device *, struct scatterlist *, int, enum dma_data_direction);\n\tvoid (*sync_sg_for_device)(struct device *, struct scatterlist *, int, enum dma_data_direction);\n\tvoid (*cache_sync)(struct device *, void *, size_t, enum dma_data_direction);\n\tint (*dma_supported)(struct device *, u64);\n\tu64 (*get_required_mask)(struct device *);\n\tsize_t (*max_mapping_size)(struct device *);\n\tlong unsigned int (*get_merge_boundary)(struct device *);\n};\n\nstruct bus_dma_region {\n\tphys_addr_t cpu_start;\n\tdma_addr_t dma_start;\n\tu64 size;\n\tu64 offset;\n};\n\ntypedef u32 phandle;\n\nstruct fwnode_operations;\n\nstruct fwnode_handle {\n\tstruct fwnode_handle *secondary;\n\tconst struct fwnode_operations *ops;\n\tstruct device *dev;\n\tstruct list_head suppliers;\n\tstruct list_head consumers;\n\tu8 flags;\n};\n\nstruct property;\n\nstruct device_node {\n\tconst char *name;\n\tphandle phandle;\n\tconst char *full_name;\n\tstruct fwnode_handle fwnode;\n\tstruct property *properties;\n\tstruct property *deadprops;\n\tstruct device_node *parent;\n\tstruct device_node *child;\n\tstruct device_node *sibling;\n\tlong unsigned int _flags;\n\tvoid *data;\n};\n\nenum cpuhp_state {\n\tCPUHP_INVALID = 4294967295,\n\tCPUHP_OFFLINE = 0,\n\tCPUHP_CREATE_THREADS = 1,\n\tCPUHP_PERF_PREPARE = 2,\n\tCPUHP_PERF_X86_PREPARE = 3,\n\tCPUHP_PERF_X86_AMD_UNCORE_PREP = 4,\n\tCPUHP_PERF_POWER = 5,\n\tCPUHP_PERF_SUPERH = 6,\n\tCPUHP_X86_HPET_DEAD = 7,\n\tCPUHP_X86_APB_DEAD = 8,\n\tCPUHP_X86_MCE_DEAD = 9,\n\tCPUHP_VIRT_NET_DEAD = 10,\n\tCPUHP_SLUB_DEAD = 11,\n\tCPUHP_DEBUG_OBJ_DEAD = 12,\n\tCPUHP_MM_WRITEBACK_DEAD = 13,\n\tCPUHP_MM_VMSTAT_DEAD = 14,\n\tCPUHP_SOFTIRQ_DEAD = 15,\n\tCPUHP_NET_MVNETA_DEAD = 16,\n\tCPUHP_CPUIDLE_DEAD = 17,\n\tCPUHP_ARM64_FPSIMD_DEAD = 18,\n\tCPUHP_ARM_OMAP_WAKE_DEAD = 19,\n\tCPUHP_IRQ_POLL_DEAD = 20,\n\tCPUHP_BLOCK_SOFTIRQ_DEAD = 21,\n\tCPUHP_ACPI_CPUDRV_DEAD = 22,\n\tCPUHP_S390_PFAULT_DEAD = 23,\n\tCPUHP_BLK_MQ_DEAD = 24,\n\tCPUHP_FS_BUFF_DEAD = 25,\n\tCPUHP_PRINTK_DEAD = 26,\n\tCPUHP_MM_MEMCQ_DEAD = 27,\n\tCPUHP_PERCPU_CNT_DEAD = 28,\n\tCPUHP_RADIX_DEAD = 29,\n\tCPUHP_PAGE_ALLOC = 30,\n\tCPUHP_NET_DEV_DEAD = 31,\n\tCPUHP_PCI_XGENE_DEAD = 32,\n\tCPUHP_IOMMU_IOVA_DEAD = 33,\n\tCPUHP_LUSTRE_CFS_DEAD = 34,\n\tCPUHP_AP_ARM_CACHE_B15_RAC_DEAD = 35,\n\tCPUHP_PADATA_DEAD = 36,\n\tCPUHP_WORKQUEUE_PREP = 37,\n\tCPUHP_POWER_NUMA_PREPARE = 38,\n\tCPUHP_HRTIMERS_PREPARE = 39,\n\tCPUHP_PROFILE_PREPARE = 40,\n\tCPUHP_X2APIC_PREPARE = 41,\n\tCPUHP_SMPCFD_PREPARE = 42,\n\tCPUHP_RELAY_PREPARE = 43,\n\tCPUHP_SLAB_PREPARE = 44,\n\tCPUHP_MD_RAID5_PREPARE = 45,\n\tCPUHP_RCUTREE_PREP = 46,\n\tCPUHP_CPUIDLE_COUPLED_PREPARE = 47,\n\tCPUHP_POWERPC_PMAC_PREPARE = 48,\n\tCPUHP_POWERPC_MMU_CTX_PREPARE = 49,\n\tCPUHP_XEN_PREPARE = 50,\n\tCPUHP_XEN_EVTCHN_PREPARE = 51,\n\tCPUHP_ARM_SHMOBILE_SCU_PREPARE = 52,\n\tCPUHP_SH_SH3X_PREPARE = 53,\n\tCPUHP_NET_FLOW_PREPARE = 54,\n\tCPUHP_TOPOLOGY_PREPARE = 55,\n\tCPUHP_NET_IUCV_PREPARE = 56,\n\tCPUHP_ARM_BL_PREPARE = 57,\n\tCPUHP_TRACE_RB_PREPARE = 58,\n\tCPUHP_MM_ZS_PREPARE = 59,\n\tCPUHP_MM_ZSWP_MEM_PREPARE = 60,\n\tCPUHP_MM_ZSWP_POOL_PREPARE = 61,\n\tCPUHP_KVM_PPC_BOOK3S_PREPARE = 62,\n\tCPUHP_ZCOMP_PREPARE = 63,\n\tCPUHP_TIMERS_PREPARE = 64,\n\tCPUHP_MIPS_SOC_PREPARE = 65,\n\tCPUHP_BP_PREPARE_DYN = 66,\n\tCPUHP_BP_PREPARE_DYN_END = 86,\n\tCPUHP_BRINGUP_CPU = 87,\n\tCPUHP_AP_IDLE_DEAD = 88,\n\tCPUHP_AP_OFFLINE = 89,\n\tCPUHP_AP_SCHED_STARTING = 90,\n\tCPUHP_AP_RCUTREE_DYING = 91,\n\tCPUHP_AP_CPU_PM_STARTING = 92,\n\tCPUHP_AP_IRQ_GIC_STARTING = 93,\n\tCPUHP_AP_IRQ_HIP04_STARTING = 94,\n\tCPUHP_AP_IRQ_APPLE_AIC_STARTING = 95,\n\tCPUHP_AP_IRQ_ARMADA_XP_STARTING = 96,\n\tCPUHP_AP_IRQ_BCM2836_STARTING = 97,\n\tCPUHP_AP_IRQ_MIPS_GIC_STARTING = 98,\n\tCPUHP_AP_IRQ_RISCV_STARTING = 99,\n\tCPUHP_AP_IRQ_SIFIVE_PLIC_STARTING = 100,\n\tCPUHP_AP_ARM_MVEBU_COHERENCY = 101,\n\tCPUHP_AP_MICROCODE_LOADER = 102,\n\tCPUHP_AP_PERF_X86_AMD_UNCORE_STARTING = 103,\n\tCPUHP_AP_PERF_X86_STARTING = 104,\n\tCPUHP_AP_PERF_X86_AMD_IBS_STARTING = 105,\n\tCPUHP_AP_PERF_X86_CQM_STARTING = 106,\n\tCPUHP_AP_PERF_X86_CSTATE_STARTING = 107,\n\tCPUHP_AP_PERF_XTENSA_STARTING = 108,\n\tCPUHP_AP_MIPS_OP_LOONGSON3_STARTING = 109,\n\tCPUHP_AP_ARM_SDEI_STARTING = 110,\n\tCPUHP_AP_ARM_VFP_STARTING = 111,\n\tCPUHP_AP_ARM64_DEBUG_MONITORS_STARTING = 112,\n\tCPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING = 113,\n\tCPUHP_AP_PERF_ARM_ACPI_STARTING = 114,\n\tCPUHP_AP_PERF_ARM_STARTING = 115,\n\tCPUHP_AP_ARM_L2X0_STARTING = 116,\n\tCPUHP_AP_EXYNOS4_MCT_TIMER_STARTING = 117,\n\tCPUHP_AP_ARM_ARCH_TIMER_STARTING = 118,\n\tCPUHP_AP_ARM_GLOBAL_TIMER_STARTING = 119,\n\tCPUHP_AP_JCORE_TIMER_STARTING = 120,\n\tCPUHP_AP_ARM_TWD_STARTING = 121,\n\tCPUHP_AP_QCOM_TIMER_STARTING = 122,\n\tCPUHP_AP_TEGRA_TIMER_STARTING = 123,\n\tCPUHP_AP_ARMADA_TIMER_STARTING = 124,\n\tCPUHP_AP_MARCO_TIMER_STARTING = 125,\n\tCPUHP_AP_MIPS_GIC_TIMER_STARTING = 126,\n\tCPUHP_AP_ARC_TIMER_STARTING = 127,\n\tCPUHP_AP_RISCV_TIMER_STARTING = 128,\n\tCPUHP_AP_CLINT_TIMER_STARTING = 129,\n\tCPUHP_AP_CSKY_TIMER_STARTING = 130,\n\tCPUHP_AP_TI_GP_TIMER_STARTING = 131,\n\tCPUHP_AP_HYPERV_TIMER_STARTING = 132,\n\tCPUHP_AP_KVM_STARTING = 133,\n\tCPUHP_AP_KVM_ARM_VGIC_INIT_STARTING = 134,\n\tCPUHP_AP_KVM_ARM_VGIC_STARTING = 135,\n\tCPUHP_AP_KVM_ARM_TIMER_STARTING = 136,\n\tCPUHP_AP_DUMMY_TIMER_STARTING = 137,\n\tCPUHP_AP_ARM_XEN_STARTING = 138,\n\tCPUHP_AP_ARM_CORESIGHT_STARTING = 139,\n\tCPUHP_AP_ARM_CORESIGHT_CTI_STARTING = 140,\n\tCPUHP_AP_ARM64_ISNDEP_STARTING = 141,\n\tCPUHP_AP_SMPCFD_DYING = 142,\n\tCPUHP_AP_X86_TBOOT_DYING = 143,\n\tCPUHP_AP_ARM_CACHE_B15_RAC_DYING = 144,\n\tCPUHP_AP_ONLINE = 145,\n\tCPUHP_TEARDOWN_CPU = 146,\n\tCPUHP_AP_ONLINE_IDLE = 147,\n\tCPUHP_AP_SCHED_WAIT_EMPTY = 148,\n\tCPUHP_AP_SMPBOOT_THREADS = 149,\n\tCPUHP_AP_X86_VDSO_VMA_ONLINE = 150,\n\tCPUHP_AP_IRQ_AFFINITY_ONLINE = 151,\n\tCPUHP_AP_BLK_MQ_ONLINE = 152,\n\tCPUHP_AP_ARM_MVEBU_SYNC_CLOCKS = 153,\n\tCPUHP_AP_X86_INTEL_EPB_ONLINE = 154,\n\tCPUHP_AP_PERF_ONLINE = 155,\n\tCPUHP_AP_PERF_X86_ONLINE = 156,\n\tCPUHP_AP_PERF_X86_UNCORE_ONLINE = 157,\n\tCPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE = 158,\n\tCPUHP_AP_PERF_X86_AMD_POWER_ONLINE = 159,\n\tCPUHP_AP_PERF_X86_RAPL_ONLINE = 160,\n\tCPUHP_AP_PERF_X86_CQM_ONLINE = 161,\n\tCPUHP_AP_PERF_X86_CSTATE_ONLINE = 162,\n\tCPUHP_AP_PERF_X86_IDXD_ONLINE = 163,\n\tCPUHP_AP_PERF_S390_CF_ONLINE = 164,\n\tCPUHP_AP_PERF_S390_SF_ONLINE = 165,\n\tCPUHP_AP_PERF_ARM_CCI_ONLINE = 166,\n\tCPUHP_AP_PERF_ARM_CCN_ONLINE = 167,\n\tCPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE = 168,\n\tCPUHP_AP_PERF_ARM_HISI_HHA_ONLINE = 169,\n\tCPUHP_AP_PERF_ARM_HISI_L3_ONLINE = 170,\n\tCPUHP_AP_PERF_ARM_HISI_PA_ONLINE = 171,\n\tCPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE = 172,\n\tCPUHP_AP_PERF_ARM_L2X0_ONLINE = 173,\n\tCPUHP_AP_PERF_ARM_QCOM_L2_ONLINE = 174,\n\tCPUHP_AP_PERF_ARM_QCOM_L3_ONLINE = 175,\n\tCPUHP_AP_PERF_ARM_APM_XGENE_ONLINE = 176,\n\tCPUHP_AP_PERF_ARM_CAVIUM_TX2_UNCORE_ONLINE = 177,\n\tCPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE = 178,\n\tCPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE = 179,\n\tCPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE = 180,\n\tCPUHP_AP_PERF_POWERPC_TRACE_IMC_ONLINE = 181,\n\tCPUHP_AP_PERF_POWERPC_HV_24x7_ONLINE = 182,\n\tCPUHP_AP_PERF_POWERPC_HV_GPCI_ONLINE = 183,\n\tCPUHP_AP_PERF_CSKY_ONLINE = 184,\n\tCPUHP_AP_WATCHDOG_ONLINE = 185,\n\tCPUHP_AP_WORKQUEUE_ONLINE = 186,\n\tCPUHP_AP_RCUTREE_ONLINE = 187,\n\tCPUHP_AP_BASE_CACHEINFO_ONLINE = 188,\n\tCPUHP_AP_ONLINE_DYN = 189,\n\tCPUHP_AP_ONLINE_DYN_END = 219,\n\tCPUHP_AP_X86_HPET_ONLINE = 220,\n\tCPUHP_AP_X86_KVM_CLK_ONLINE = 221,\n\tCPUHP_AP_DTPM_CPU_ONLINE = 222,\n\tCPUHP_AP_ACTIVE = 223,\n\tCPUHP_ONLINE = 224,\n};\n\nstruct ring_buffer_event {\n\tu32 type_len: 5;\n\tu32 time_delta: 27;\n\tu32 array[0];\n};\n\nstruct seq_buf {\n\tchar *buffer;\n\tsize_t size;\n\tsize_t len;\n\tloff_t readpos;\n};\n\nstruct trace_seq {\n\tchar buffer[4096];\n\tstruct seq_buf seq;\n\tint full;\n};\n\nenum perf_sw_ids {\n\tPERF_COUNT_SW_CPU_CLOCK = 0,\n\tPERF_COUNT_SW_TASK_CLOCK = 1,\n\tPERF_COUNT_SW_PAGE_FAULTS = 2,\n\tPERF_COUNT_SW_CONTEXT_SWITCHES = 3,\n\tPERF_COUNT_SW_CPU_MIGRATIONS = 4,\n\tPERF_COUNT_SW_PAGE_FAULTS_MIN = 5,\n\tPERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,\n\tPERF_COUNT_SW_ALIGNMENT_FAULTS = 7,\n\tPERF_COUNT_SW_EMULATION_FAULTS = 8,\n\tPERF_COUNT_SW_DUMMY = 9,\n\tPERF_COUNT_SW_BPF_OUTPUT = 10,\n\tPERF_COUNT_SW_CGROUP_SWITCHES = 11,\n\tPERF_COUNT_SW_MAX = 12,\n};\n\nunion perf_mem_data_src {\n\t__u64 val;\n\tstruct {\n\t\t__u64 mem_op: 5;\n\t\t__u64 mem_lvl: 14;\n\t\t__u64 mem_snoop: 5;\n\t\t__u64 mem_lock: 2;\n\t\t__u64 mem_dtlb: 7;\n\t\t__u64 mem_lvl_num: 4;\n\t\t__u64 mem_remote: 1;\n\t\t__u64 mem_snoopx: 2;\n\t\t__u64 mem_blk: 3;\n\t\t__u64 mem_rsvd: 21;\n\t};\n};\n\nstruct perf_branch_entry {\n\t__u64 from;\n\t__u64 to;\n\t__u64 mispred: 1;\n\t__u64 predicted: 1;\n\t__u64 in_tx: 1;\n\t__u64 abort: 1;\n\t__u64 cycles: 16;\n\t__u64 type: 4;\n\t__u64 reserved: 40;\n};\n\nunion perf_sample_weight {\n\t__u64 full;\n\tstruct {\n\t\t__u32 var1_dw;\n\t\t__u16 var2_w;\n\t\t__u16 var3_w;\n\t};\n};\n\nstruct new_utsname {\n\tchar sysname[65];\n\tchar nodename[65];\n\tchar release[65];\n\tchar version[65];\n\tchar machine[65];\n\tchar domainname[65];\n};\n\nstruct uts_namespace {\n\tstruct new_utsname name;\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tstruct ns_common ns;\n};\n\nstruct cgroup_namespace {\n\tstruct ns_common ns;\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tstruct css_set *root_cset;\n};\n\nstruct nsset {\n\tunsigned int flags;\n\tstruct nsproxy *nsproxy;\n\tstruct fs_struct *fs;\n\tconst struct cred *cred;\n};\n\nstruct proc_ns_operations {\n\tconst char *name;\n\tconst char *real_ns_name;\n\tint type;\n\tstruct ns_common * (*get)(struct task_struct *);\n\tvoid (*put)(struct ns_common *);\n\tint (*install)(struct nsset *, struct ns_common *);\n\tstruct user_namespace * (*owner)(struct ns_common *);\n\tstruct ns_common * (*get_parent)(struct ns_common *);\n};\n\nstruct perf_cpu_context;\n\nstruct perf_output_handle;\n\nstruct pmu {\n\tstruct list_head entry;\n\tstruct module *module;\n\tstruct device *dev;\n\tconst struct attribute_group **attr_groups;\n\tconst struct attribute_group **attr_update;\n\tconst char *name;\n\tint type;\n\tint capabilities;\n\tint *pmu_disable_count;\n\tstruct perf_cpu_context *pmu_cpu_context;\n\tatomic_t exclusive_cnt;\n\tint task_ctx_nr;\n\tint hrtimer_interval_ms;\n\tunsigned int nr_addr_filters;\n\tvoid (*pmu_enable)(struct pmu *);\n\tvoid (*pmu_disable)(struct pmu *);\n\tint (*event_init)(struct perf_event *);\n\tvoid (*event_mapped)(struct perf_event *, struct mm_struct *);\n\tvoid (*event_unmapped)(struct perf_event *, struct mm_struct *);\n\tint (*add)(struct perf_event *, int);\n\tvoid (*del)(struct perf_event *, int);\n\tvoid (*start)(struct perf_event *, int);\n\tvoid (*stop)(struct perf_event *, int);\n\tvoid (*read)(struct perf_event *);\n\tvoid (*start_txn)(struct pmu *, unsigned int);\n\tint (*commit_txn)(struct pmu *);\n\tvoid (*cancel_txn)(struct pmu *);\n\tint (*event_idx)(struct perf_event *);\n\tvoid (*sched_task)(struct perf_event_context *, bool);\n\tstruct kmem_cache *task_ctx_cache;\n\tvoid (*swap_task_ctx)(struct perf_event_context *, struct perf_event_context *);\n\tvoid * (*setup_aux)(struct perf_event *, void **, int, bool);\n\tvoid (*free_aux)(void *);\n\tlong int (*snapshot_aux)(struct perf_event *, struct perf_output_handle *, long unsigned int);\n\tint (*addr_filters_validate)(struct list_head *);\n\tvoid (*addr_filters_sync)(struct perf_event *);\n\tint (*aux_output_match)(struct perf_event *);\n\tint (*filter_match)(struct perf_event *);\n\tint (*check_period)(struct perf_event *, u64);\n};\n\nstruct ftrace_regs {\n\tstruct pt_regs regs;\n};\n\nstruct iovec {\n\tvoid *iov_base;\n\t__kernel_size_t iov_len;\n};\n\nstruct kvec {\n\tvoid *iov_base;\n\tsize_t iov_len;\n};\n\nstruct perf_regs {\n\t__u64 abi;\n\tstruct pt_regs *regs;\n};\n\nstruct u64_stats_sync {};\n\nstruct bpf_cgroup_storage_key {\n\t__u64 cgroup_inode_id;\n\t__u32 attach_type;\n};\n\nenum kmalloc_cache_type {\n\tKMALLOC_NORMAL = 0,\n\tKMALLOC_CGROUP = 1,\n\tKMALLOC_RECLAIM = 2,\n\tKMALLOC_DMA = 3,\n\tNR_KMALLOC_TYPES = 4,\n};\n\nstruct bpf_cgroup_storage;\n\nstruct bpf_prog_array_item {\n\tstruct bpf_prog *prog;\n\tstruct bpf_cgroup_storage *cgroup_storage[2];\n};\n\nstruct bpf_storage_buffer;\n\nstruct bpf_cgroup_storage_map;\n\nstruct bpf_cgroup_storage {\n\tunion {\n\t\tstruct bpf_storage_buffer *buf;\n\t\tvoid *percpu_buf;\n\t};\n\tstruct bpf_cgroup_storage_map *map;\n\tstruct bpf_cgroup_storage_key key;\n\tstruct list_head list_map;\n\tstruct list_head list_cg;\n\tstruct rb_node node;\n\tstruct callback_head rcu;\n};\n\nstruct bpf_prog_array {\n\tstruct callback_head rcu;\n\tstruct bpf_prog_array_item items[0];\n};\n\nstruct bpf_storage_buffer {\n\tstruct callback_head rcu;\n\tchar data[0];\n};\n\nstruct psi_group_cpu {\n\tseqcount_t seq;\n\tunsigned int tasks[4];\n\tu32 state_mask;\n\tu32 times[7];\n\tu64 state_start;\n\tu32 times_prev[14];\n\tlong: 64;\n};\n\nstruct cgroup_taskset;\n\nstruct cftype;\n\nstruct cgroup_subsys {\n\tstruct cgroup_subsys_state * (*css_alloc)(struct cgroup_subsys_state *);\n\tint (*css_online)(struct cgroup_subsys_state *);\n\tvoid (*css_offline)(struct cgroup_subsys_state *);\n\tvoid (*css_released)(struct cgroup_subsys_state *);\n\tvoid (*css_free)(struct cgroup_subsys_state *);\n\tvoid (*css_reset)(struct cgroup_subsys_state *);\n\tvoid (*css_rstat_flush)(struct cgroup_subsys_state *, int);\n\tint (*css_extra_stat_show)(struct seq_file *, struct cgroup_subsys_state *);\n\tint (*can_attach)(struct cgroup_taskset *);\n\tvoid (*cancel_attach)(struct cgroup_taskset *);\n\tvoid (*attach)(struct cgroup_taskset *);\n\tvoid (*post_attach)();\n\tint (*can_fork)(struct task_struct *, struct css_set *);\n\tvoid (*cancel_fork)(struct task_struct *, struct css_set *);\n\tvoid (*fork)(struct task_struct *);\n\tvoid (*exit)(struct task_struct *);\n\tvoid (*release)(struct task_struct *);\n\tvoid (*bind)(struct cgroup_subsys_state *);\n\tbool early_init: 1;\n\tbool implicit_on_dfl: 1;\n\tbool threaded: 1;\n\tint id;\n\tconst char *name;\n\tconst char *legacy_name;\n\tstruct cgroup_root *root;\n\tstruct idr css_idr;\n\tstruct list_head cfts;\n\tstruct cftype *dfl_cftypes;\n\tstruct cftype *legacy_cftypes;\n\tunsigned int depends_on;\n};\n\nstruct cgroup_rstat_cpu {\n\tstruct u64_stats_sync bsync;\n\tstruct cgroup_base_stat bstat;\n\tstruct cgroup_base_stat last_bstat;\n\tstruct cgroup *updated_children;\n\tstruct cgroup *updated_next;\n};\n\nstruct cgroup_root {\n\tstruct kernfs_root *kf_root;\n\tunsigned int subsys_mask;\n\tint hierarchy_id;\n\tstruct cgroup cgrp;\n\tu64 cgrp_ancestor_id_storage;\n\tatomic_t nr_cgrps;\n\tstruct list_head root_list;\n\tunsigned int flags;\n\tchar release_agent_path[4096];\n\tchar name[64];\n};\n\nstruct cftype {\n\tchar name[64];\n\tlong unsigned int private;\n\tsize_t max_write_len;\n\tunsigned int flags;\n\tunsigned int file_offset;\n\tstruct cgroup_subsys *ss;\n\tstruct list_head node;\n\tstruct kernfs_ops *kf_ops;\n\tint (*open)(struct kernfs_open_file *);\n\tvoid (*release)(struct kernfs_open_file *);\n\tu64 (*read_u64)(struct cgroup_subsys_state *, struct cftype *);\n\ts64 (*read_s64)(struct cgroup_subsys_state *, struct cftype *);\n\tint (*seq_show)(struct seq_file *, void *);\n\tvoid * (*seq_start)(struct seq_file *, loff_t *);\n\tvoid * (*seq_next)(struct seq_file *, void *, loff_t *);\n\tvoid (*seq_stop)(struct seq_file *, void *);\n\tint (*write_u64)(struct cgroup_subsys_state *, struct cftype *, u64);\n\tint (*write_s64)(struct cgroup_subsys_state *, struct cftype *, s64);\n\tssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t);\n\t__poll_t (*poll)(struct kernfs_open_file *, struct poll_table_struct *);\n};\n\nstruct perf_callchain_entry {\n\t__u64 nr;\n\t__u64 ip[0];\n};\n\ntypedef long unsigned int (*perf_copy_f)(void *, const void *, long unsigned int, long unsigned int);\n\nstruct perf_raw_frag {\n\tunion {\n\t\tstruct perf_raw_frag *next;\n\t\tlong unsigned int pad;\n\t};\n\tperf_copy_f copy;\n\tvoid *data;\n\tu32 size;\n} __attribute__((packed));\n\nstruct perf_raw_record {\n\tstruct perf_raw_frag frag;\n\tu32 size;\n};\n\nstruct perf_branch_stack {\n\t__u64 nr;\n\t__u64 hw_idx;\n\tstruct perf_branch_entry entries[0];\n};\n\nstruct perf_cpu_context {\n\tstruct perf_event_context ctx;\n\tstruct perf_event_context *task_ctx;\n\tint active_oncpu;\n\tint exclusive;\n\traw_spinlock_t hrtimer_lock;\n\tstruct hrtimer hrtimer;\n\tktime_t hrtimer_interval;\n\tunsigned int hrtimer_active;\n\tstruct perf_cgroup *cgrp;\n\tstruct list_head cgrp_cpuctx_entry;\n\tstruct list_head sched_cb_entry;\n\tint sched_cb_usage;\n\tint online;\n\tint heap_size;\n\tstruct perf_event **heap;\n\tstruct perf_event *heap_default[2];\n};\n\nstruct perf_output_handle {\n\tstruct perf_event *event;\n\tstruct perf_buffer *rb;\n\tlong unsigned int wakeup;\n\tlong unsigned int size;\n\tu64 aux_flags;\n\tunion {\n\t\tvoid *addr;\n\t\tlong unsigned int head;\n\t};\n\tint page;\n};\n\nstruct perf_addr_filter_range {\n\tlong unsigned int start;\n\tlong unsigned int size;\n};\n\nstruct perf_sample_data {\n\tu64 addr;\n\tstruct perf_raw_record *raw;\n\tstruct perf_branch_stack *br_stack;\n\tu64 period;\n\tunion perf_sample_weight weight;\n\tu64 txn;\n\tunion perf_mem_data_src data_src;\n\tu64 type;\n\tu64 ip;\n\tstruct {\n\t\tu32 pid;\n\t\tu32 tid;\n\t} tid_entry;\n\tu64 time;\n\tu64 id;\n\tu64 stream_id;\n\tstruct {\n\t\tu32 cpu;\n\t\tu32 reserved;\n\t} cpu_entry;\n\tstruct perf_callchain_entry *callchain;\n\tu64 aux_size;\n\tstruct perf_regs regs_user;\n\tstruct perf_regs regs_intr;\n\tu64 stack_user_size;\n\tu64 phys_addr;\n\tu64 cgroup;\n\tu64 data_page_size;\n\tu64 code_page_size;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct perf_cgroup_info;\n\nstruct perf_cgroup {\n\tstruct cgroup_subsys_state css;\n\tstruct perf_cgroup_info *info;\n};\n\nstruct perf_cgroup_info {\n\tu64 time;\n\tu64 timestamp;\n};\n\nstruct trace_entry {\n\tshort unsigned int type;\n\tunsigned char flags;\n\tunsigned char preempt_count;\n\tint pid;\n};\n\nstruct trace_array;\n\nstruct tracer;\n\nstruct array_buffer;\n\nstruct ring_buffer_iter;\n\nstruct trace_iterator {\n\tstruct trace_array *tr;\n\tstruct tracer *trace;\n\tstruct array_buffer *array_buffer;\n\tvoid *private;\n\tint cpu_file;\n\tstruct mutex mutex;\n\tstruct ring_buffer_iter **buffer_iter;\n\tlong unsigned int iter_flags;\n\tvoid *temp;\n\tunsigned int temp_size;\n\tchar *fmt;\n\tunsigned int fmt_size;\n\tstruct trace_seq tmp_seq;\n\tcpumask_var_t started;\n\tbool snapshot;\n\tstruct trace_seq seq;\n\tstruct trace_entry *ent;\n\tlong unsigned int lost_events;\n\tint leftover;\n\tint ent_size;\n\tint cpu;\n\tu64 ts;\n\tloff_t pos;\n\tlong int idx;\n};\n\nenum print_line_t {\n\tTRACE_TYPE_PARTIAL_LINE = 0,\n\tTRACE_TYPE_HANDLED = 1,\n\tTRACE_TYPE_UNHANDLED = 2,\n\tTRACE_TYPE_NO_CONSUME = 3,\n};\n\ntypedef enum print_line_t (*trace_print_func)(struct trace_iterator *, int, struct trace_event *);\n\nstruct trace_event_functions {\n\ttrace_print_func trace;\n\ttrace_print_func raw;\n\ttrace_print_func hex;\n\ttrace_print_func binary;\n};\n\nenum trace_reg {\n\tTRACE_REG_REGISTER = 0,\n\tTRACE_REG_UNREGISTER = 1,\n\tTRACE_REG_PERF_REGISTER = 2,\n\tTRACE_REG_PERF_UNREGISTER = 3,\n\tTRACE_REG_PERF_OPEN = 4,\n\tTRACE_REG_PERF_CLOSE = 5,\n\tTRACE_REG_PERF_ADD = 6,\n\tTRACE_REG_PERF_DEL = 7,\n};\n\nstruct trace_event_fields {\n\tconst char *type;\n\tunion {\n\t\tstruct {\n\t\t\tconst char *name;\n\t\t\tconst int size;\n\t\t\tconst int align;\n\t\t\tconst int is_signed;\n\t\t\tconst int filter_type;\n\t\t};\n\t\tint (*define_fields)(struct trace_event_call *);\n\t};\n};\n\nstruct trace_event_class {\n\tconst char *system;\n\tvoid *probe;\n\tvoid *perf_probe;\n\tint (*reg)(struct trace_event_call *, enum trace_reg, void *);\n\tstruct trace_event_fields *fields_array;\n\tstruct list_head * (*get_fields)(struct trace_event_call *);\n\tstruct list_head fields;\n\tint (*raw_init)(struct trace_event_call *);\n};\n\nstruct trace_buffer;\n\nstruct trace_event_file;\n\nstruct trace_event_buffer {\n\tstruct trace_buffer *buffer;\n\tstruct ring_buffer_event *event;\n\tstruct trace_event_file *trace_file;\n\tvoid *entry;\n\tunsigned int trace_ctx;\n\tstruct pt_regs *regs;\n};\n\nstruct trace_subsystem_dir;\n\nstruct trace_event_file {\n\tstruct list_head list;\n\tstruct trace_event_call *event_call;\n\tstruct event_filter *filter;\n\tstruct dentry *dir;\n\tstruct trace_array *tr;\n\tstruct trace_subsystem_dir *system;\n\tstruct list_head triggers;\n\tlong unsigned int flags;\n\tatomic_t sm_ref;\n\tatomic_t tm_ref;\n};\n\nenum {\n\tTRACE_EVENT_FL_FILTERED_BIT = 0,\n\tTRACE_EVENT_FL_CAP_ANY_BIT = 1,\n\tTRACE_EVENT_FL_NO_SET_FILTER_BIT = 2,\n\tTRACE_EVENT_FL_IGNORE_ENABLE_BIT = 3,\n\tTRACE_EVENT_FL_TRACEPOINT_BIT = 4,\n\tTRACE_EVENT_FL_KPROBE_BIT = 5,\n\tTRACE_EVENT_FL_UPROBE_BIT = 6,\n};\n\nenum {\n\tTRACE_EVENT_FL_FILTERED = 1,\n\tTRACE_EVENT_FL_CAP_ANY = 2,\n\tTRACE_EVENT_FL_NO_SET_FILTER = 4,\n\tTRACE_EVENT_FL_IGNORE_ENABLE = 8,\n\tTRACE_EVENT_FL_TRACEPOINT = 16,\n\tTRACE_EVENT_FL_KPROBE = 32,\n\tTRACE_EVENT_FL_UPROBE = 64,\n};\n\nenum {\n\tEVENT_FILE_FL_ENABLED_BIT = 0,\n\tEVENT_FILE_FL_RECORDED_CMD_BIT = 1,\n\tEVENT_FILE_FL_RECORDED_TGID_BIT = 2,\n\tEVENT_FILE_FL_FILTERED_BIT = 3,\n\tEVENT_FILE_FL_NO_SET_FILTER_BIT = 4,\n\tEVENT_FILE_FL_SOFT_MODE_BIT = 5,\n\tEVENT_FILE_FL_SOFT_DISABLED_BIT = 6,\n\tEVENT_FILE_FL_TRIGGER_MODE_BIT = 7,\n\tEVENT_FILE_FL_TRIGGER_COND_BIT = 8,\n\tEVENT_FILE_FL_PID_FILTER_BIT = 9,\n\tEVENT_FILE_FL_WAS_ENABLED_BIT = 10,\n};\n\nenum {\n\tEVENT_FILE_FL_ENABLED = 1,\n\tEVENT_FILE_FL_RECORDED_CMD = 2,\n\tEVENT_FILE_FL_RECORDED_TGID = 4,\n\tEVENT_FILE_FL_FILTERED = 8,\n\tEVENT_FILE_FL_NO_SET_FILTER = 16,\n\tEVENT_FILE_FL_SOFT_MODE = 32,\n\tEVENT_FILE_FL_SOFT_DISABLED = 64,\n\tEVENT_FILE_FL_TRIGGER_MODE = 128,\n\tEVENT_FILE_FL_TRIGGER_COND = 256,\n\tEVENT_FILE_FL_PID_FILTER = 512,\n\tEVENT_FILE_FL_WAS_ENABLED = 1024,\n};\n\nenum event_trigger_type {\n\tETT_NONE = 0,\n\tETT_TRACE_ONOFF = 1,\n\tETT_SNAPSHOT = 2,\n\tETT_STACKTRACE = 4,\n\tETT_EVENT_ENABLE = 8,\n\tETT_EVENT_HIST = 16,\n\tETT_HIST_ENABLE = 32,\n};\n\nenum {\n\tFILTER_OTHER = 0,\n\tFILTER_STATIC_STRING = 1,\n\tFILTER_DYN_STRING = 2,\n\tFILTER_PTR_STRING = 3,\n\tFILTER_TRACE_FN = 4,\n\tFILTER_COMM = 5,\n\tFILTER_CPU = 6,\n};\n\nstruct fwnode_reference_args;\n\nstruct fwnode_endpoint;\n\nstruct fwnode_operations {\n\tstruct fwnode_handle * (*get)(struct fwnode_handle *);\n\tvoid (*put)(struct fwnode_handle *);\n\tbool (*device_is_available)(const struct fwnode_handle *);\n\tconst void * (*device_get_match_data)(const struct fwnode_handle *, const struct device *);\n\tbool (*property_present)(const struct fwnode_handle *, const char *);\n\tint (*property_read_int_array)(const struct fwnode_handle *, const char *, unsigned int, void *, size_t);\n\tint (*property_read_string_array)(const struct fwnode_handle *, const char *, const char **, size_t);\n\tconst char * (*get_name)(const struct fwnode_handle *);\n\tconst char * (*get_name_prefix)(const struct fwnode_handle *);\n\tstruct fwnode_handle * (*get_parent)(const struct fwnode_handle *);\n\tstruct fwnode_handle * (*get_next_child_node)(const struct fwnode_handle *, struct fwnode_handle *);\n\tstruct fwnode_handle * (*get_named_child_node)(const struct fwnode_handle *, const char *);\n\tint (*get_reference_args)(const struct fwnode_handle *, const char *, const char *, unsigned int, unsigned int, struct fwnode_reference_args *);\n\tstruct fwnode_handle * (*graph_get_next_endpoint)(const struct fwnode_handle *, struct fwnode_handle *);\n\tstruct fwnode_handle * (*graph_get_remote_endpoint)(const struct fwnode_handle *);\n\tstruct fwnode_handle * (*graph_get_port_parent)(struct fwnode_handle *);\n\tint (*graph_parse_endpoint)(const struct fwnode_handle *, struct fwnode_endpoint *);\n\tint (*add_links)(struct fwnode_handle *);\n};\n\nstruct fwnode_endpoint {\n\tunsigned int port;\n\tunsigned int id;\n\tconst struct fwnode_handle *local_fwnode;\n};\n\nstruct fwnode_reference_args {\n\tstruct fwnode_handle *fwnode;\n\tunsigned int nargs;\n\tu64 args[8];\n};\n\nstruct property {\n\tchar *name;\n\tint length;\n\tvoid *value;\n\tstruct property *next;\n};\n\nstruct irq_fwspec {\n\tstruct fwnode_handle *fwnode;\n\tint param_count;\n\tu32 param[16];\n};\n\nstruct irq_domain_ops {\n\tint (*match)(struct irq_domain *, struct device_node *, enum irq_domain_bus_token);\n\tint (*select)(struct irq_domain *, struct irq_fwspec *, enum irq_domain_bus_token);\n\tint (*map)(struct irq_domain *, unsigned int, irq_hw_number_t);\n\tvoid (*unmap)(struct irq_domain *, unsigned int);\n\tint (*xlate)(struct irq_domain *, struct device_node *, const u32 *, unsigned int, long unsigned int *, unsigned int *);\n\tint (*alloc)(struct irq_domain *, unsigned int, unsigned int, void *);\n\tvoid (*free)(struct irq_domain *, unsigned int, unsigned int);\n\tint (*activate)(struct irq_domain *, struct irq_data *, bool);\n\tvoid (*deactivate)(struct irq_domain *, struct irq_data *);\n\tint (*translate)(struct irq_domain *, struct irq_fwspec *, long unsigned int *, unsigned int *);\n};\n\nstruct xbc_node {\n\tu16 next;\n\tu16 child;\n\tu16 parent;\n\tu16 data;\n};\n\nenum wb_stat_item {\n\tWB_RECLAIMABLE = 0,\n\tWB_WRITEBACK = 1,\n\tWB_DIRTIED = 2,\n\tWB_WRITTEN = 3,\n\tNR_WB_STAT_ITEMS = 4,\n};\n\nstruct block_device_operations;\n\nstruct timer_rand_state;\n\nstruct disk_events;\n\nstruct cdrom_device_info;\n\nstruct badblocks;\n\nstruct gendisk {\n\tint major;\n\tint first_minor;\n\tint minors;\n\tchar disk_name[32];\n\tshort unsigned int events;\n\tshort unsigned int event_flags;\n\tstruct xarray part_tbl;\n\tstruct block_device *part0;\n\tconst struct block_device_operations *fops;\n\tstruct request_queue *queue;\n\tvoid *private_data;\n\tint flags;\n\tlong unsigned int state;\n\tstruct mutex open_mutex;\n\tunsigned int open_partitions;\n\tstruct kobject *slave_dir;\n\tstruct timer_rand_state *random;\n\tatomic_t sync_io;\n\tstruct disk_events *ev;\n\tstruct kobject integrity_kobj;\n\tstruct cdrom_device_info *cdi;\n\tint node_id;\n\tstruct badblocks *bb;\n\tstruct lockdep_map lockdep_map;\n};\n\nstruct partition_meta_info {\n\tchar uuid[37];\n\tu8 volname[64];\n};\n\nstruct bio_integrity_payload {\n\tstruct bio *bip_bio;\n\tstruct bvec_iter bip_iter;\n\tshort unsigned int bip_vcnt;\n\tshort unsigned int bip_max_vcnt;\n\tshort unsigned int bip_flags;\n\tstruct bvec_iter bio_iter;\n\tstruct work_struct bip_work;\n\tstruct bio_vec *bip_vec;\n\tstruct bio_vec bip_inline_vecs[0];\n};\n\nstruct blkg_iostat {\n\tu64 bytes[3];\n\tu64 ios[3];\n};\n\nstruct blkg_iostat_set {\n\tstruct u64_stats_sync sync;\n\tstruct blkg_iostat cur;\n\tstruct blkg_iostat last;\n};\n\nstruct blkcg;\n\nstruct blkg_policy_data;\n\nstruct blkcg_gq {\n\tstruct request_queue *q;\n\tstruct list_head q_node;\n\tstruct hlist_node blkcg_node;\n\tstruct blkcg *blkcg;\n\tstruct blkcg_gq *parent;\n\tstruct percpu_ref refcnt;\n\tbool online;\n\tstruct blkg_iostat_set *iostat_cpu;\n\tstruct blkg_iostat_set iostat;\n\tstruct blkg_policy_data *pd[6];\n\tspinlock_t async_bio_lock;\n\tstruct bio_list async_bios;\n\tstruct work_struct async_bio_work;\n\tatomic_t use_delay;\n\tatomic64_t delay_nsec;\n\tatomic64_t delay_start;\n\tu64 last_delay;\n\tint last_use;\n\tstruct callback_head callback_head;\n};\n\ntypedef unsigned int blk_qc_t;\n\nstruct blk_integrity_iter;\n\ntypedef blk_status_t integrity_processing_fn(struct blk_integrity_iter *);\n\ntypedef void integrity_prepare_fn(struct request *);\n\ntypedef void integrity_complete_fn(struct request *, unsigned int);\n\nstruct blk_integrity_profile {\n\tintegrity_processing_fn *generate_fn;\n\tintegrity_processing_fn *verify_fn;\n\tintegrity_prepare_fn *prepare_fn;\n\tintegrity_complete_fn *complete_fn;\n\tconst char *name;\n};\n\nstruct blk_zone;\n\ntypedef int (*report_zones_cb)(struct blk_zone *, unsigned int, void *);\n\nstruct hd_geometry;\n\nstruct pr_ops;\n\nstruct block_device_operations {\n\tblk_qc_t (*submit_bio)(struct bio *);\n\tint (*open)(struct block_device *, fmode_t);\n\tvoid (*release)(struct gendisk *, fmode_t);\n\tint (*rw_page)(struct block_device *, sector_t, struct page *, unsigned int);\n\tint (*ioctl)(struct block_device *, fmode_t, unsigned int, long unsigned int);\n\tint (*compat_ioctl)(struct block_device *, fmode_t, unsigned int, long unsigned int);\n\tunsigned int (*check_events)(struct gendisk *, unsigned int);\n\tvoid (*unlock_native_capacity)(struct gendisk *);\n\tint (*getgeo)(struct block_device *, struct hd_geometry *);\n\tint (*set_read_only)(struct block_device *, bool);\n\tvoid (*swap_slot_free_notify)(struct block_device *, long unsigned int);\n\tint (*report_zones)(struct gendisk *, sector_t, unsigned int, report_zones_cb, void *);\n\tchar * (*devnode)(struct gendisk *, umode_t *);\n\tstruct module *owner;\n\tconst struct pr_ops *pr_ops;\n};\n\nstruct sg_io_v4 {\n\t__s32 guard;\n\t__u32 protocol;\n\t__u32 subprotocol;\n\t__u32 request_len;\n\t__u64 request;\n\t__u64 request_tag;\n\t__u32 request_attr;\n\t__u32 request_priority;\n\t__u32 request_extra;\n\t__u32 max_response_len;\n\t__u64 response;\n\t__u32 dout_iovec_count;\n\t__u32 dout_xfer_len;\n\t__u32 din_iovec_count;\n\t__u32 din_xfer_len;\n\t__u64 dout_xferp;\n\t__u64 din_xferp;\n\t__u32 timeout;\n\t__u32 flags;\n\t__u64 usr_ptr;\n\t__u32 spare_in;\n\t__u32 driver_status;\n\t__u32 transport_status;\n\t__u32 device_status;\n\t__u32 retry_delay;\n\t__u32 info;\n\t__u32 duration;\n\t__u32 response_len;\n\t__s32 din_resid;\n\t__s32 dout_resid;\n\t__u64 generated_tag;\n\t__u32 spare_out;\n\t__u32 padding;\n};\n\nstruct bsg_ops {\n\tint (*check_proto)(struct sg_io_v4 *);\n\tint (*fill_hdr)(struct request *, struct sg_io_v4 *, fmode_t);\n\tint (*complete_rq)(struct request *, struct sg_io_v4 *);\n\tvoid (*free_rq)(struct request *);\n};\n\ntypedef __u32 req_flags_t;\n\ntypedef void rq_end_io_fn(struct request *, blk_status_t);\n\nenum mq_rq_state {\n\tMQ_RQ_IDLE = 0,\n\tMQ_RQ_IN_FLIGHT = 1,\n\tMQ_RQ_COMPLETE = 2,\n};\n\nstruct blk_ksm_keyslot;\n\nstruct request {\n\tstruct request_queue *q;\n\tstruct blk_mq_ctx *mq_ctx;\n\tstruct blk_mq_hw_ctx *mq_hctx;\n\tunsigned int cmd_flags;\n\treq_flags_t rq_flags;\n\tint tag;\n\tint internal_tag;\n\tunsigned int __data_len;\n\tsector_t __sector;\n\tstruct bio *bio;\n\tstruct bio *biotail;\n\tstruct list_head queuelist;\n\tunion {\n\t\tstruct hlist_node hash;\n\t\tstruct llist_node ipi_list;\n\t};\n\tunion {\n\t\tstruct rb_node rb_node;\n\t\tstruct bio_vec special_vec;\n\t\tvoid *completion_data;\n\t\tint error_count;\n\t};\n\tunion {\n\t\tstruct {\n\t\t\tstruct io_cq *icq;\n\t\t\tvoid *priv[2];\n\t\t} elv;\n\t\tstruct {\n\t\t\tunsigned int seq;\n\t\t\tstruct list_head list;\n\t\t\trq_end_io_fn *saved_end_io;\n\t\t} flush;\n\t};\n\tstruct gendisk *rq_disk;\n\tstruct block_device *part;\n\tu64 alloc_time_ns;\n\tu64 start_time_ns;\n\tu64 io_start_time_ns;\n\tshort unsigned int wbt_flags;\n\tshort unsigned int stats_sectors;\n\tshort unsigned int nr_phys_segments;\n\tshort unsigned int nr_integrity_segments;\n\tstruct bio_crypt_ctx *crypt_ctx;\n\tstruct blk_ksm_keyslot *crypt_keyslot;\n\tshort unsigned int write_hint;\n\tshort unsigned int ioprio;\n\tenum mq_rq_state state;\n\trefcount_t ref;\n\tunsigned int timeout;\n\tlong unsigned int deadline;\n\tunion {\n\t\tstruct __call_single_data csd;\n\t\tu64 fifo_time;\n\t};\n\trq_end_io_fn *end_io;\n\tvoid *end_io_data;\n};\n\nstruct blk_zone {\n\t__u64 start;\n\t__u64 len;\n\t__u64 wp;\n\t__u8 type;\n\t__u8 cond;\n\t__u8 non_seq;\n\t__u8 reset;\n\t__u8 resv[4];\n\t__u64 capacity;\n\t__u8 reserved[24];\n};\n\nstruct sbitmap_word {\n\tlong unsigned int depth;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong unsigned int word;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong unsigned int cleared;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct sbq_wait_state {\n\tatomic_t wait_cnt;\n\twait_queue_head_t wait;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum elv_merge {\n\tELEVATOR_NO_MERGE = 0,\n\tELEVATOR_FRONT_MERGE = 1,\n\tELEVATOR_BACK_MERGE = 2,\n\tELEVATOR_DISCARD_MERGE = 3,\n};\n\nstruct elevator_type;\n\nstruct blk_mq_alloc_data;\n\nstruct elevator_mq_ops {\n\tint (*init_sched)(struct request_queue *, struct elevator_type *);\n\tvoid (*exit_sched)(struct elevator_queue *);\n\tint (*init_hctx)(struct blk_mq_hw_ctx *, unsigned int);\n\tvoid (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int);\n\tvoid (*depth_updated)(struct blk_mq_hw_ctx *);\n\tbool (*allow_merge)(struct request_queue *, struct request *, struct bio *);\n\tbool (*bio_merge)(struct request_queue *, struct bio *, unsigned int);\n\tint (*request_merge)(struct request_queue *, struct request **, struct bio *);\n\tvoid (*request_merged)(struct request_queue *, struct request *, enum elv_merge);\n\tvoid (*requests_merged)(struct request_queue *, struct request *, struct request *);\n\tvoid (*limit_depth)(unsigned int, struct blk_mq_alloc_data *);\n\tvoid (*prepare_request)(struct request *);\n\tvoid (*finish_request)(struct request *);\n\tvoid (*insert_requests)(struct blk_mq_hw_ctx *, struct list_head *, bool);\n\tstruct request * (*dispatch_request)(struct blk_mq_hw_ctx *);\n\tbool (*has_work)(struct blk_mq_hw_ctx *);\n\tvoid (*completed_request)(struct request *, u64);\n\tvoid (*requeue_request)(struct request *);\n\tstruct request * (*former_request)(struct request_queue *, struct request *);\n\tstruct request * (*next_request)(struct request_queue *, struct request *);\n\tvoid (*init_icq)(struct io_cq *);\n\tvoid (*exit_icq)(struct io_cq *);\n};\n\nstruct elv_fs_entry;\n\nstruct blk_mq_debugfs_attr;\n\nstruct elevator_type {\n\tstruct kmem_cache *icq_cache;\n\tstruct elevator_mq_ops ops;\n\tsize_t icq_size;\n\tsize_t icq_align;\n\tstruct elv_fs_entry *elevator_attrs;\n\tconst char *elevator_name;\n\tconst char *elevator_alias;\n\tconst unsigned int elevator_features;\n\tstruct module *elevator_owner;\n\tconst struct blk_mq_debugfs_attr *queue_debugfs_attrs;\n\tconst struct blk_mq_debugfs_attr *hctx_debugfs_attrs;\n\tchar icq_cache_name[22];\n\tstruct list_head list;\n};\n\nstruct elevator_queue {\n\tstruct elevator_type *type;\n\tvoid *elevator_data;\n\tstruct kobject kobj;\n\tstruct mutex sysfs_lock;\n\tunsigned int registered: 1;\n\tstruct hlist_head hash[64];\n};\n\nstruct elv_fs_entry {\n\tstruct attribute attr;\n\tssize_t (*show)(struct elevator_queue *, char *);\n\tssize_t (*store)(struct elevator_queue *, const char *, size_t);\n};\n\nstruct blk_mq_debugfs_attr {\n\tconst char *name;\n\tumode_t mode;\n\tint (*show)(void *, struct seq_file *);\n\tssize_t (*write)(void *, const char *, size_t, loff_t *);\n\tconst struct seq_operations *seq_ops;\n};\n\nenum blk_eh_timer_return {\n\tBLK_EH_DONE = 0,\n\tBLK_EH_RESET_TIMER = 1,\n};\n\nstruct blk_mq_queue_data;\n\nstruct blk_mq_ops {\n\tblk_status_t (*queue_rq)(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *);\n\tvoid (*commit_rqs)(struct blk_mq_hw_ctx *);\n\tint (*get_budget)(struct request_queue *);\n\tvoid (*put_budget)(struct request_queue *, int);\n\tvoid (*set_rq_budget_token)(struct request *, int);\n\tint (*get_rq_budget_token)(struct request *);\n\tenum blk_eh_timer_return (*timeout)(struct request *, bool);\n\tint (*poll)(struct blk_mq_hw_ctx *);\n\tvoid (*complete)(struct request *);\n\tint (*init_hctx)(struct blk_mq_hw_ctx *, void *, unsigned int);\n\tvoid (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int);\n\tint (*init_request)(struct blk_mq_tag_set *, struct request *, unsigned int, unsigned int);\n\tvoid (*exit_request)(struct blk_mq_tag_set *, struct request *, unsigned int);\n\tvoid (*initialize_rq_fn)(struct request *);\n\tvoid (*cleanup_rq)(struct request *);\n\tbool (*busy)(struct request_queue *);\n\tint (*map_queues)(struct blk_mq_tag_set *);\n\tvoid (*show_rq)(struct seq_file *, struct request *);\n};\n\nstruct blk_integrity_iter {\n\tvoid *prot_buf;\n\tvoid *data_buf;\n\tsector_t seed;\n\tunsigned int data_size;\n\tshort unsigned int interval;\n\tconst char *disk_name;\n};\n\nenum pr_type {\n\tPR_WRITE_EXCLUSIVE = 1,\n\tPR_EXCLUSIVE_ACCESS = 2,\n\tPR_WRITE_EXCLUSIVE_REG_ONLY = 3,\n\tPR_EXCLUSIVE_ACCESS_REG_ONLY = 4,\n\tPR_WRITE_EXCLUSIVE_ALL_REGS = 5,\n\tPR_EXCLUSIVE_ACCESS_ALL_REGS = 6,\n};\n\nstruct pr_ops {\n\tint (*pr_register)(struct block_device *, u64, u64, u32);\n\tint (*pr_reserve)(struct block_device *, u64, enum pr_type, u32);\n\tint (*pr_release)(struct block_device *, u64, enum pr_type);\n\tint (*pr_preempt)(struct block_device *, u64, u64, enum pr_type, bool);\n\tint (*pr_clear)(struct block_device *, u64);\n};\n\nenum blkg_iostat_type {\n\tBLKG_IOSTAT_READ = 0,\n\tBLKG_IOSTAT_WRITE = 1,\n\tBLKG_IOSTAT_DISCARD = 2,\n\tBLKG_IOSTAT_NR = 3,\n};\n\nstruct blkcg_policy_data;\n\nstruct blkcg {\n\tstruct cgroup_subsys_state css;\n\tspinlock_t lock;\n\trefcount_t online_pin;\n\tstruct xarray blkg_tree;\n\tstruct blkcg_gq *blkg_hint;\n\tstruct hlist_head blkg_list;\n\tstruct blkcg_policy_data *cpd[6];\n\tstruct list_head all_blkcgs_node;\n\tchar fc_app_id[129];\n\tstruct list_head cgwb_list;\n};\n\nstruct blkcg_policy_data {\n\tstruct blkcg *blkcg;\n\tint plid;\n};\n\nstruct blkg_policy_data {\n\tstruct blkcg_gq *blkg;\n\tint plid;\n};\n\ntypedef long unsigned int efi_status_t;\n\ntypedef u8 efi_bool_t;\n\ntypedef u16 efi_char16_t;\n\ntypedef guid_t efi_guid_t;\n\ntypedef struct {\n\tu64 signature;\n\tu32 revision;\n\tu32 headersize;\n\tu32 crc32;\n\tu32 reserved;\n} efi_table_hdr_t;\n\ntypedef struct {\n\tu32 type;\n\tu32 pad;\n\tu64 phys_addr;\n\tu64 virt_addr;\n\tu64 num_pages;\n\tu64 attribute;\n} efi_memory_desc_t;\n\ntypedef struct {\n\tefi_guid_t guid;\n\tu32 headersize;\n\tu32 flags;\n\tu32 imagesize;\n} efi_capsule_header_t;\n\ntypedef struct {\n\tu16 year;\n\tu8 month;\n\tu8 day;\n\tu8 hour;\n\tu8 minute;\n\tu8 second;\n\tu8 pad1;\n\tu32 nanosecond;\n\ts16 timezone;\n\tu8 daylight;\n\tu8 pad2;\n} efi_time_t;\n\ntypedef struct {\n\tu32 resolution;\n\tu32 accuracy;\n\tu8 sets_to_zero;\n} efi_time_cap_t;\n\ntypedef struct {\n\tefi_table_hdr_t hdr;\n\tu32 get_time;\n\tu32 set_time;\n\tu32 get_wakeup_time;\n\tu32 set_wakeup_time;\n\tu32 set_virtual_address_map;\n\tu32 convert_pointer;\n\tu32 get_variable;\n\tu32 get_next_variable;\n\tu32 set_variable;\n\tu32 get_next_high_mono_count;\n\tu32 reset_system;\n\tu32 update_capsule;\n\tu32 query_capsule_caps;\n\tu32 query_variable_info;\n} efi_runtime_services_32_t;\n\ntypedef efi_status_t efi_get_time_t(efi_time_t *, efi_time_cap_t *);\n\ntypedef efi_status_t efi_set_time_t(efi_time_t *);\n\ntypedef efi_status_t efi_get_wakeup_time_t(efi_bool_t *, efi_bool_t *, efi_time_t *);\n\ntypedef efi_status_t efi_set_wakeup_time_t(efi_bool_t, efi_time_t *);\n\ntypedef efi_status_t efi_get_variable_t(efi_char16_t *, efi_guid_t *, u32 *, long unsigned int *, void *);\n\ntypedef efi_status_t efi_get_next_variable_t(long unsigned int *, efi_char16_t *, efi_guid_t *);\n\ntypedef efi_status_t efi_set_variable_t(efi_char16_t *, efi_guid_t *, u32, long unsigned int, void *);\n\ntypedef efi_status_t efi_get_next_high_mono_count_t(u32 *);\n\ntypedef void efi_reset_system_t(int, efi_status_t, long unsigned int, efi_char16_t *);\n\ntypedef efi_status_t efi_query_variable_info_t(u32, u64 *, u64 *, u64 *);\n\ntypedef efi_status_t efi_update_capsule_t(efi_capsule_header_t **, long unsigned int, long unsigned int);\n\ntypedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **, long unsigned int, u64 *, int *);\n\ntypedef union {\n\tstruct {\n\t\tefi_table_hdr_t hdr;\n\t\tefi_status_t (*get_time)(efi_time_t *, efi_time_cap_t *);\n\t\tefi_status_t (*set_time)(efi_time_t *);\n\t\tefi_status_t (*get_wakeup_time)(efi_bool_t *, efi_bool_t *, efi_time_t *);\n\t\tefi_status_t (*set_wakeup_time)(efi_bool_t, efi_time_t *);\n\t\tefi_status_t (*set_virtual_address_map)(long unsigned int, long unsigned int, u32, efi_memory_desc_t *);\n\t\tvoid *convert_pointer;\n\t\tefi_status_t (*get_variable)(efi_char16_t *, efi_guid_t *, u32 *, long unsigned int *, void *);\n\t\tefi_status_t (*get_next_variable)(long unsigned int *, efi_char16_t *, efi_guid_t *);\n\t\tefi_status_t (*set_variable)(efi_char16_t *, efi_guid_t *, u32, long unsigned int, void *);\n\t\tefi_status_t (*get_next_high_mono_count)(u32 *);\n\t\tvoid (*reset_system)(int, efi_status_t, long unsigned int, efi_char16_t *);\n\t\tefi_status_t (*update_capsule)(efi_capsule_header_t **, long unsigned int, long unsigned int);\n\t\tefi_status_t (*query_capsule_caps)(efi_capsule_header_t **, long unsigned int, u64 *, int *);\n\t\tefi_status_t (*query_variable_info)(u32, u64 *, u64 *, u64 *);\n\t};\n\tefi_runtime_services_32_t mixed_mode;\n} efi_runtime_services_t;\n\nstruct efi_memory_map {\n\tphys_addr_t phys_map;\n\tvoid *map;\n\tvoid *map_end;\n\tint nr_map;\n\tlong unsigned int desc_version;\n\tlong unsigned int desc_size;\n\tlong unsigned int flags;\n};\n\nstruct efi {\n\tconst efi_runtime_services_t *runtime;\n\tunsigned int runtime_version;\n\tunsigned int runtime_supported_mask;\n\tlong unsigned int acpi;\n\tlong unsigned int acpi20;\n\tlong unsigned int smbios;\n\tlong unsigned int smbios3;\n\tlong unsigned int esrt;\n\tlong unsigned int tpm_log;\n\tlong unsigned int tpm_final_log;\n\tlong unsigned int mokvar_table;\n\tefi_get_time_t *get_time;\n\tefi_set_time_t *set_time;\n\tefi_get_wakeup_time_t *get_wakeup_time;\n\tefi_set_wakeup_time_t *set_wakeup_time;\n\tefi_get_variable_t *get_variable;\n\tefi_get_next_variable_t *get_next_variable;\n\tefi_set_variable_t *set_variable;\n\tefi_set_variable_t *set_variable_nonblocking;\n\tefi_query_variable_info_t *query_variable_info;\n\tefi_query_variable_info_t *query_variable_info_nonblocking;\n\tefi_update_capsule_t *update_capsule;\n\tefi_query_capsule_caps_t *query_capsule_caps;\n\tefi_get_next_high_mono_count_t *get_next_high_mono_count;\n\tefi_reset_system_t *reset_system;\n\tstruct efi_memory_map memmap;\n\tlong unsigned int flags;\n};\n\nenum memcg_stat_item {\n\tMEMCG_SWAP = 39,\n\tMEMCG_SOCK = 40,\n\tMEMCG_PERCPU_B = 41,\n\tMEMCG_NR_STAT = 42,\n};\n\nenum memcg_memory_event {\n\tMEMCG_LOW = 0,\n\tMEMCG_HIGH = 1,\n\tMEMCG_MAX = 2,\n\tMEMCG_OOM = 3,\n\tMEMCG_OOM_KILL = 4,\n\tMEMCG_SWAP_HIGH = 5,\n\tMEMCG_SWAP_MAX = 6,\n\tMEMCG_SWAP_FAIL = 7,\n\tMEMCG_NR_MEMORY_EVENTS = 8,\n};\n\nenum mem_cgroup_events_target {\n\tMEM_CGROUP_TARGET_THRESH = 0,\n\tMEM_CGROUP_TARGET_SOFTLIMIT = 1,\n\tMEM_CGROUP_NTARGETS = 2,\n};\n\nstruct memcg_vmstats_percpu {\n\tlong int state[42];\n\tlong unsigned int events[100];\n\tlong int state_prev[42];\n\tlong unsigned int events_prev[100];\n\tlong unsigned int nr_page_events;\n\tlong unsigned int targets[2];\n};\n\nstruct mem_cgroup_reclaim_iter {\n\tstruct mem_cgroup *position;\n\tunsigned int generation;\n};\n\nstruct lruvec_stat {\n\tlong int count[39];\n};\n\nstruct batched_lruvec_stat {\n\ts32 count[39];\n};\n\nstruct shrinker_info {\n\tstruct callback_head rcu;\n\tatomic_long_t *nr_deferred;\n\tlong unsigned int *map;\n};\n\nstruct mem_cgroup_per_node {\n\tstruct lruvec lruvec;\n\tstruct lruvec_stat *lruvec_stat_local;\n\tstruct batched_lruvec_stat *lruvec_stat_cpu;\n\tatomic_long_t lruvec_stat[39];\n\tlong unsigned int lru_zone_size[25];\n\tstruct mem_cgroup_reclaim_iter iter;\n\tstruct shrinker_info *shrinker_info;\n\tstruct rb_node tree_node;\n\tlong unsigned int usage_in_excess;\n\tbool on_tree;\n\tstruct mem_cgroup *memcg;\n};\n\nstruct eventfd_ctx;\n\nstruct mem_cgroup_threshold {\n\tstruct eventfd_ctx *eventfd;\n\tlong unsigned int threshold;\n};\n\nstruct mem_cgroup_threshold_ary {\n\tint current_threshold;\n\tunsigned int size;\n\tstruct mem_cgroup_threshold entries[0];\n};\n\nstruct obj_cgroup {\n\tstruct percpu_ref refcnt;\n\tstruct mem_cgroup *memcg;\n\tatomic_t nr_charged_bytes;\n\tunion {\n\t\tstruct list_head list;\n\t\tstruct callback_head rcu;\n\t};\n};\n\nstruct percpu_cluster {\n\tstruct swap_cluster_info index;\n\tunsigned int next;\n};\n\nenum fs_value_type {\n\tfs_value_is_undefined = 0,\n\tfs_value_is_flag = 1,\n\tfs_value_is_string = 2,\n\tfs_value_is_blob = 3,\n\tfs_value_is_filename = 4,\n\tfs_value_is_file = 5,\n};\n\nstruct fs_parameter {\n\tconst char *key;\n\tenum fs_value_type type: 8;\n\tunion {\n\t\tchar *string;\n\t\tvoid *blob;\n\t\tstruct filename *name;\n\t\tstruct file *file;\n\t};\n\tsize_t size;\n\tint dirfd;\n};\n\nstruct fc_log {\n\trefcount_t usage;\n\tu8 head;\n\tu8 tail;\n\tu8 need_free;\n\tstruct module *owner;\n\tchar *buffer[8];\n};\n\nstruct fs_context_operations {\n\tvoid (*free)(struct fs_context *);\n\tint (*dup)(struct fs_context *, struct fs_context *);\n\tint (*parse_param)(struct fs_context *, struct fs_parameter *);\n\tint (*parse_monolithic)(struct fs_context *, void *);\n\tint (*get_tree)(struct fs_context *);\n\tint (*reconfigure)(struct fs_context *);\n};\n\nstruct fs_parse_result {\n\tbool negated;\n\tunion {\n\t\tbool boolean;\n\t\tint int_32;\n\t\tunsigned int uint_32;\n\t\tu64 uint_64;\n\t};\n};\n\nstruct trace_event_raw_initcall_level {\n\tstruct trace_entry ent;\n\tu32 __data_loc_level;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_initcall_start {\n\tstruct trace_entry ent;\n\tinitcall_t func;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_initcall_finish {\n\tstruct trace_entry ent;\n\tinitcall_t func;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_initcall_level {\n\tu32 level;\n};\n\nstruct trace_event_data_offsets_initcall_start {};\n\nstruct trace_event_data_offsets_initcall_finish {};\n\ntypedef void (*btf_trace_initcall_level)(void *, const char *);\n\ntypedef void (*btf_trace_initcall_start)(void *, initcall_t);\n\ntypedef void (*btf_trace_initcall_finish)(void *, initcall_t, int);\n\nstruct blacklist_entry {\n\tstruct list_head next;\n\tchar *buf;\n};\n\ntypedef __u32 Elf32_Word;\n\nstruct elf32_note {\n\tElf32_Word n_namesz;\n\tElf32_Word n_descsz;\n\tElf32_Word n_type;\n};\n\nenum {\n\tPROC_ROOT_INO = 1,\n\tPROC_IPC_INIT_INO = 4026531839,\n\tPROC_UTS_INIT_INO = 4026531838,\n\tPROC_USER_INIT_INO = 4026531837,\n\tPROC_PID_INIT_INO = 4026531836,\n\tPROC_CGROUP_INIT_INO = 4026531835,\n\tPROC_TIME_INIT_INO = 4026531834,\n};\n\ntypedef __u16 __le16;\n\ntypedef __u16 __be16;\n\ntypedef __u32 __be32;\n\ntypedef __u64 __be64;\n\ntypedef __u32 __wsum;\n\ntypedef unsigned int slab_flags_t;\n\nstruct notifier_block;\n\ntypedef int (*notifier_fn_t)(struct notifier_block *, long unsigned int, void *);\n\nstruct notifier_block {\n\tnotifier_fn_t notifier_call;\n\tstruct notifier_block *next;\n\tint priority;\n};\n\nstruct blocking_notifier_head {\n\tstruct rw_semaphore rwsem;\n\tstruct notifier_block *head;\n};\n\nstruct raw_notifier_head {\n\tstruct notifier_block *head;\n};\n\nstruct page_pool_params {\n\tunsigned int flags;\n\tunsigned int order;\n\tunsigned int pool_size;\n\tint nid;\n\tstruct device *dev;\n\tenum dma_data_direction dma_dir;\n\tunsigned int max_len;\n\tunsigned int offset;\n};\n\nstruct pp_alloc_cache {\n\tu32 count;\n\tstruct page *cache[128];\n};\n\nstruct ptr_ring {\n\tint producer;\n\tspinlock_t producer_lock;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tint consumer_head;\n\tint consumer_tail;\n\tspinlock_t consumer_lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tint size;\n\tint batch;\n\tvoid **queue;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct page_pool {\n\tstruct page_pool_params p;\n\tstruct delayed_work release_dw;\n\tvoid (*disconnect)(void *);\n\tlong unsigned int defer_start;\n\tlong unsigned int defer_warn;\n\tu32 pages_state_hold_cnt;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct pp_alloc_cache alloc;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct ptr_ring ring;\n\tatomic_t pages_state_release_cnt;\n\trefcount_t user_cnt;\n\tu64 destroy_cnt;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\ntypedef __u64 __addrpair;\n\ntypedef __u32 __portpair;\n\ntypedef struct {\n\tstruct net *net;\n} possible_net_t;\n\nstruct in6_addr {\n\tunion {\n\t\t__u8 u6_addr8[16];\n\t\t__be16 u6_addr16[8];\n\t\t__be32 u6_addr32[4];\n\t} in6_u;\n};\n\nstruct hlist_nulls_node {\n\tstruct hlist_nulls_node *next;\n\tstruct hlist_nulls_node **pprev;\n};\n\nstruct proto;\n\nstruct inet_timewait_death_row;\n\nstruct sock_common {\n\tunion {\n\t\t__addrpair skc_addrpair;\n\t\tstruct {\n\t\t\t__be32 skc_daddr;\n\t\t\t__be32 skc_rcv_saddr;\n\t\t};\n\t};\n\tunion {\n\t\tunsigned int skc_hash;\n\t\t__u16 skc_u16hashes[2];\n\t};\n\tunion {\n\t\t__portpair skc_portpair;\n\t\tstruct {\n\t\t\t__be16 skc_dport;\n\t\t\t__u16 skc_num;\n\t\t};\n\t};\n\tshort unsigned int skc_family;\n\tvolatile unsigned char skc_state;\n\tunsigned char skc_reuse: 4;\n\tunsigned char skc_reuseport: 1;\n\tunsigned char skc_ipv6only: 1;\n\tunsigned char skc_net_refcnt: 1;\n\tint skc_bound_dev_if;\n\tunion {\n\t\tstruct hlist_node skc_bind_node;\n\t\tstruct hlist_node skc_portaddr_node;\n\t};\n\tstruct proto *skc_prot;\n\tpossible_net_t skc_net;\n\tstruct in6_addr skc_v6_daddr;\n\tstruct in6_addr skc_v6_rcv_saddr;\n\tatomic64_t skc_cookie;\n\tunion {\n\t\tlong unsigned int skc_flags;\n\t\tstruct sock *skc_listener;\n\t\tstruct inet_timewait_death_row *skc_tw_dr;\n\t};\n\tint skc_dontcopy_begin[0];\n\tunion {\n\t\tstruct hlist_node skc_node;\n\t\tstruct hlist_nulls_node skc_nulls_node;\n\t};\n\tshort unsigned int skc_tx_queue_mapping;\n\tshort unsigned int skc_rx_queue_mapping;\n\tunion {\n\t\tint skc_incoming_cpu;\n\t\tu32 skc_rcv_wnd;\n\t\tu32 skc_tw_rcv_nxt;\n\t};\n\trefcount_t skc_refcnt;\n\tint skc_dontcopy_end[0];\n\tunion {\n\t\tu32 skc_rxhash;\n\t\tu32 skc_window_clamp;\n\t\tu32 skc_tw_snd_nxt;\n\t};\n};\n\ntypedef struct {\n\tspinlock_t slock;\n\tint owned;\n\twait_queue_head_t wq;\n} socket_lock_t;\n\nstruct sk_buff;\n\nstruct sk_buff_head {\n\tstruct sk_buff *next;\n\tstruct sk_buff *prev;\n\t__u32 qlen;\n\tspinlock_t lock;\n};\n\ntypedef u64 netdev_features_t;\n\nstruct sock_cgroup_data {\n\tunion {\n\t\tstruct {\n\t\t\tu8 is_data: 1;\n\t\t\tu8 no_refcnt: 1;\n\t\t\tu8 unused: 6;\n\t\t\tu8 padding;\n\t\t\tu16 prioidx;\n\t\t\tu32 classid;\n\t\t};\n\t\tu64 val;\n\t};\n};\n\nstruct sk_filter;\n\nstruct socket_wq;\n\nstruct xfrm_policy;\n\nstruct dst_entry;\n\nstruct socket;\n\nstruct net_device;\n\nstruct sock_reuseport;\n\nstruct sock {\n\tstruct sock_common __sk_common;\n\tsocket_lock_t sk_lock;\n\tatomic_t sk_drops;\n\tint sk_rcvlowat;\n\tstruct sk_buff_head sk_error_queue;\n\tstruct sk_buff *sk_rx_skb_cache;\n\tstruct sk_buff_head sk_receive_queue;\n\tstruct {\n\t\tatomic_t rmem_alloc;\n\t\tint len;\n\t\tstruct sk_buff *head;\n\t\tstruct sk_buff *tail;\n\t} sk_backlog;\n\tint sk_forward_alloc;\n\tunsigned int sk_ll_usec;\n\tunsigned int sk_napi_id;\n\tint sk_rcvbuf;\n\tstruct sk_filter *sk_filter;\n\tunion {\n\t\tstruct socket_wq *sk_wq;\n\t\tstruct socket_wq *sk_wq_raw;\n\t};\n\tstruct xfrm_policy *sk_policy[2];\n\tstruct dst_entry *sk_rx_dst;\n\tstruct dst_entry *sk_dst_cache;\n\tatomic_t sk_omem_alloc;\n\tint sk_sndbuf;\n\tint sk_wmem_queued;\n\trefcount_t sk_wmem_alloc;\n\tlong unsigned int sk_tsq_flags;\n\tunion {\n\t\tstruct sk_buff *sk_send_head;\n\t\tstruct rb_root tcp_rtx_queue;\n\t};\n\tstruct sk_buff *sk_tx_skb_cache;\n\tstruct sk_buff_head sk_write_queue;\n\t__s32 sk_peek_off;\n\tint sk_write_pending;\n\t__u32 sk_dst_pending_confirm;\n\tu32 sk_pacing_status;\n\tlong int sk_sndtimeo;\n\tstruct timer_list sk_timer;\n\t__u32 sk_priority;\n\t__u32 sk_mark;\n\tlong unsigned int sk_pacing_rate;\n\tlong unsigned int sk_max_pacing_rate;\n\tstruct page_frag sk_frag;\n\tnetdev_features_t sk_route_caps;\n\tnetdev_features_t sk_route_nocaps;\n\tnetdev_features_t sk_route_forced_caps;\n\tint sk_gso_type;\n\tunsigned int sk_gso_max_size;\n\tgfp_t sk_allocation;\n\t__u32 sk_txhash;\n\tu8 sk_padding: 1;\n\tu8 sk_kern_sock: 1;\n\tu8 sk_no_check_tx: 1;\n\tu8 sk_no_check_rx: 1;\n\tu8 sk_userlocks: 4;\n\tu8 sk_pacing_shift;\n\tu16 sk_type;\n\tu16 sk_protocol;\n\tu16 sk_gso_max_segs;\n\tlong unsigned int sk_lingertime;\n\tstruct proto *sk_prot_creator;\n\trwlock_t sk_callback_lock;\n\tint sk_err;\n\tint sk_err_soft;\n\tu32 sk_ack_backlog;\n\tu32 sk_max_ack_backlog;\n\tkuid_t sk_uid;\n\tu8 sk_prefer_busy_poll;\n\tu16 sk_busy_poll_budget;\n\tstruct pid *sk_peer_pid;\n\tconst struct cred *sk_peer_cred;\n\tlong int sk_rcvtimeo;\n\tktime_t sk_stamp;\n\tu16 sk_tsflags;\n\tint sk_bind_phc;\n\tu8 sk_shutdown;\n\tu32 sk_tskey;\n\tatomic_t sk_zckey;\n\tu8 sk_clockid;\n\tu8 sk_txtime_deadline_mode: 1;\n\tu8 sk_txtime_report_errors: 1;\n\tu8 sk_txtime_unused: 6;\n\tstruct socket *sk_socket;\n\tvoid *sk_user_data;\n\tvoid *sk_security;\n\tstruct sock_cgroup_data sk_cgrp_data;\n\tstruct mem_cgroup *sk_memcg;\n\tvoid (*sk_state_change)(struct sock *);\n\tvoid (*sk_data_ready)(struct sock *);\n\tvoid (*sk_write_space)(struct sock *);\n\tvoid (*sk_error_report)(struct sock *);\n\tint (*sk_backlog_rcv)(struct sock *, struct sk_buff *);\n\tstruct sk_buff * (*sk_validate_xmit_skb)(struct sock *, struct net_device *, struct sk_buff *);\n\tvoid (*sk_destruct)(struct sock *);\n\tstruct sock_reuseport *sk_reuseport_cb;\n\tstruct bpf_local_storage *sk_bpf_storage;\n\tstruct callback_head sk_rcu;\n};\n\nstruct rhash_head {\n\tstruct rhash_head *next;\n};\n\nstruct rhashtable;\n\nstruct rhashtable_compare_arg {\n\tstruct rhashtable *ht;\n\tconst void *key;\n};\n\ntypedef u32 (*rht_hashfn_t)(const void *, u32, u32);\n\ntypedef u32 (*rht_obj_hashfn_t)(const void *, u32, u32);\n\ntypedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *, const void *);\n\nstruct rhashtable_params {\n\tu16 nelem_hint;\n\tu16 key_len;\n\tu16 key_offset;\n\tu16 head_offset;\n\tunsigned int max_size;\n\tu16 min_size;\n\tbool automatic_shrinking;\n\trht_hashfn_t hashfn;\n\trht_obj_hashfn_t obj_hashfn;\n\trht_obj_cmpfn_t obj_cmpfn;\n};\n\nstruct bucket_table;\n\nstruct rhashtable {\n\tstruct bucket_table *tbl;\n\tunsigned int key_len;\n\tunsigned int max_elems;\n\tstruct rhashtable_params p;\n\tbool rhlist;\n\tstruct work_struct run_work;\n\tstruct mutex mutex;\n\tspinlock_t lock;\n\tatomic_t nelems;\n};\n\nstruct fs_struct {\n\tint users;\n\tspinlock_t lock;\n\tseqcount_spinlock_t seq;\n\tint umask;\n\tint in_exec;\n\tstruct path root;\n\tstruct path pwd;\n};\n\nstruct pipe_buffer;\n\nstruct watch_queue;\n\nstruct pipe_inode_info {\n\tstruct mutex mutex;\n\twait_queue_head_t rd_wait;\n\twait_queue_head_t wr_wait;\n\tunsigned int head;\n\tunsigned int tail;\n\tunsigned int max_usage;\n\tunsigned int ring_size;\n\tbool note_loss;\n\tunsigned int nr_accounted;\n\tunsigned int readers;\n\tunsigned int writers;\n\tunsigned int files;\n\tunsigned int r_counter;\n\tunsigned int w_counter;\n\tunsigned int poll_usage;\n\tstruct page *tmp_page;\n\tstruct fasync_struct *fasync_readers;\n\tstruct fasync_struct *fasync_writers;\n\tstruct pipe_buffer *bufs;\n\tstruct user_struct *user;\n\tstruct watch_queue *watch_queue;\n};\n\ntypedef short unsigned int __kernel_sa_family_t;\n\ntypedef __kernel_sa_family_t sa_family_t;\n\nstruct sockaddr {\n\tsa_family_t sa_family;\n\tchar sa_data[14];\n};\n\nstruct msghdr {\n\tvoid *msg_name;\n\tint msg_namelen;\n\tstruct iov_iter msg_iter;\n\tunion {\n\t\tvoid *msg_control;\n\t\tvoid *msg_control_user;\n\t};\n\tbool msg_control_is_user: 1;\n\t__kernel_size_t msg_controllen;\n\tunsigned int msg_flags;\n\tstruct kiocb *msg_iocb;\n};\n\ntypedef struct {\n\tunsigned int clock_rate;\n\tunsigned int clock_type;\n\tshort unsigned int loopback;\n} sync_serial_settings;\n\ntypedef struct {\n\tunsigned int clock_rate;\n\tunsigned int clock_type;\n\tshort unsigned int loopback;\n\tunsigned int slot_map;\n} te1_settings;\n\ntypedef struct {\n\tshort unsigned int encoding;\n\tshort unsigned int parity;\n} raw_hdlc_proto;\n\ntypedef struct {\n\tunsigned int t391;\n\tunsigned int t392;\n\tunsigned int n391;\n\tunsigned int n392;\n\tunsigned int n393;\n\tshort unsigned int lmi;\n\tshort unsigned int dce;\n} fr_proto;\n\ntypedef struct {\n\tunsigned int dlci;\n} fr_proto_pvc;\n\ntypedef struct {\n\tunsigned int dlci;\n\tchar master[16];\n} fr_proto_pvc_info;\n\ntypedef struct {\n\tunsigned int interval;\n\tunsigned int timeout;\n} cisco_proto;\n\ntypedef struct {\n\tshort unsigned int dce;\n\tunsigned int modulo;\n\tunsigned int window;\n\tunsigned int t1;\n\tunsigned int t2;\n\tunsigned int n2;\n} x25_hdlc_proto;\n\nstruct ifmap {\n\tlong unsigned int mem_start;\n\tlong unsigned int mem_end;\n\tshort unsigned int base_addr;\n\tunsigned char irq;\n\tunsigned char dma;\n\tunsigned char port;\n};\n\nstruct if_settings {\n\tunsigned int type;\n\tunsigned int size;\n\tunion {\n\t\traw_hdlc_proto *raw_hdlc;\n\t\tcisco_proto *cisco;\n\t\tfr_proto *fr;\n\t\tfr_proto_pvc *fr_pvc;\n\t\tfr_proto_pvc_info *fr_pvc_info;\n\t\tx25_hdlc_proto *x25;\n\t\tsync_serial_settings *sync;\n\t\tte1_settings *te1;\n\t} ifs_ifsu;\n};\n\nstruct ifreq {\n\tunion {\n\t\tchar ifrn_name[16];\n\t} ifr_ifrn;\n\tunion {\n\t\tstruct sockaddr ifru_addr;\n\t\tstruct sockaddr ifru_dstaddr;\n\t\tstruct sockaddr ifru_broadaddr;\n\t\tstruct sockaddr ifru_netmask;\n\t\tstruct sockaddr ifru_hwaddr;\n\t\tshort int ifru_flags;\n\t\tint ifru_ivalue;\n\t\tint ifru_mtu;\n\t\tstruct ifmap ifru_map;\n\t\tchar ifru_slave[16];\n\t\tchar ifru_newname[16];\n\t\tvoid *ifru_data;\n\t\tstruct if_settings ifru_settings;\n\t} ifr_ifru;\n};\n\nstruct ld_semaphore {\n\tatomic_long_t count;\n\traw_spinlock_t wait_lock;\n\tunsigned int wait_readers;\n\tstruct list_head read_wait;\n\tstruct list_head write_wait;\n};\n\ntypedef unsigned int tcflag_t;\n\ntypedef unsigned char cc_t;\n\ntypedef unsigned int speed_t;\n\nstruct ktermios {\n\ttcflag_t c_iflag;\n\ttcflag_t c_oflag;\n\ttcflag_t c_cflag;\n\ttcflag_t c_lflag;\n\tcc_t c_line;\n\tcc_t c_cc[19];\n\tspeed_t c_ispeed;\n\tspeed_t c_ospeed;\n};\n\nstruct winsize {\n\tshort unsigned int ws_row;\n\tshort unsigned int ws_col;\n\tshort unsigned int ws_xpixel;\n\tshort unsigned int ws_ypixel;\n};\n\nstruct tty_driver;\n\nstruct tty_operations;\n\nstruct tty_ldisc;\n\nstruct tty_port;\n\nstruct tty_struct {\n\tint magic;\n\tstruct kref kref;\n\tstruct device *dev;\n\tstruct tty_driver *driver;\n\tconst struct tty_operations *ops;\n\tint index;\n\tstruct ld_semaphore ldisc_sem;\n\tstruct tty_ldisc *ldisc;\n\tstruct mutex atomic_write_lock;\n\tstruct mutex legacy_mutex;\n\tstruct mutex throttle_mutex;\n\tstruct rw_semaphore termios_rwsem;\n\tstruct mutex winsize_mutex;\n\tstruct ktermios termios;\n\tstruct ktermios termios_locked;\n\tchar name[64];\n\tlong unsigned int flags;\n\tint count;\n\tstruct winsize winsize;\n\tstruct {\n\t\tspinlock_t lock;\n\t\tbool stopped;\n\t\tbool tco_stopped;\n\t\tlong unsigned int unused[0];\n\t} flow;\n\tstruct {\n\t\tspinlock_t lock;\n\t\tstruct pid *pgrp;\n\t\tstruct pid *session;\n\t\tunsigned char pktstatus;\n\t\tbool packet;\n\t\tlong unsigned int unused[0];\n\t} ctrl;\n\tint hw_stopped;\n\tunsigned int receive_room;\n\tint flow_change;\n\tstruct tty_struct *link;\n\tstruct fasync_struct *fasync;\n\twait_queue_head_t write_wait;\n\twait_queue_head_t read_wait;\n\tstruct work_struct hangup_work;\n\tvoid *disc_data;\n\tvoid *driver_data;\n\tspinlock_t files_lock;\n\tstruct list_head tty_files;\n\tint closing;\n\tunsigned char *write_buf;\n\tint write_cnt;\n\tstruct work_struct SAK_work;\n\tstruct tty_port *port;\n};\n\ntypedef struct {\n\tsize_t written;\n\tsize_t count;\n\tunion {\n\t\tchar *buf;\n\t\tvoid *data;\n\t} arg;\n\tint error;\n} read_descriptor_t;\n\nstruct posix_acl_entry {\n\tshort int e_tag;\n\tshort unsigned int e_perm;\n\tunion {\n\t\tkuid_t e_uid;\n\t\tkgid_t e_gid;\n\t};\n};\n\nstruct posix_acl {\n\trefcount_t a_refcount;\n\tstruct callback_head a_rcu;\n\tunsigned int a_count;\n\tstruct posix_acl_entry a_entries[0];\n};\n\nstruct serial_icounter_struct;\n\nstruct serial_struct;\n\nstruct tty_operations {\n\tstruct tty_struct * (*lookup)(struct tty_driver *, struct file *, int);\n\tint (*install)(struct tty_driver *, struct tty_struct *);\n\tvoid (*remove)(struct tty_driver *, struct tty_struct *);\n\tint (*open)(struct tty_struct *, struct file *);\n\tvoid (*close)(struct tty_struct *, struct file *);\n\tvoid (*shutdown)(struct tty_struct *);\n\tvoid (*cleanup)(struct tty_struct *);\n\tint (*write)(struct tty_struct *, const unsigned char *, int);\n\tint (*put_char)(struct tty_struct *, unsigned char);\n\tvoid (*flush_chars)(struct tty_struct *);\n\tunsigned int (*write_room)(struct tty_struct *);\n\tunsigned int (*chars_in_buffer)(struct tty_struct *);\n\tint (*ioctl)(struct tty_struct *, unsigned int, long unsigned int);\n\tlong int (*compat_ioctl)(struct tty_struct *, unsigned int, long unsigned int);\n\tvoid (*set_termios)(struct tty_struct *, struct ktermios *);\n\tvoid (*throttle)(struct tty_struct *);\n\tvoid (*unthrottle)(struct tty_struct *);\n\tvoid (*stop)(struct tty_struct *);\n\tvoid (*start)(struct tty_struct *);\n\tvoid (*hangup)(struct tty_struct *);\n\tint (*break_ctl)(struct tty_struct *, int);\n\tvoid (*flush_buffer)(struct tty_struct *);\n\tvoid (*set_ldisc)(struct tty_struct *);\n\tvoid (*wait_until_sent)(struct tty_struct *, int);\n\tvoid (*send_xchar)(struct tty_struct *, char);\n\tint (*tiocmget)(struct tty_struct *);\n\tint (*tiocmset)(struct tty_struct *, unsigned int, unsigned int);\n\tint (*resize)(struct tty_struct *, struct winsize *);\n\tint (*get_icount)(struct tty_struct *, struct serial_icounter_struct *);\n\tint (*get_serial)(struct tty_struct *, struct serial_struct *);\n\tint (*set_serial)(struct tty_struct *, struct serial_struct *);\n\tvoid (*show_fdinfo)(struct tty_struct *, struct seq_file *);\n\tint (*proc_show)(struct seq_file *, void *);\n};\n\nstruct proc_dir_entry;\n\nstruct tty_driver {\n\tint magic;\n\tstruct kref kref;\n\tstruct cdev **cdevs;\n\tstruct module *owner;\n\tconst char *driver_name;\n\tconst char *name;\n\tint name_base;\n\tint major;\n\tint minor_start;\n\tunsigned int num;\n\tshort int type;\n\tshort int subtype;\n\tstruct ktermios init_termios;\n\tlong unsigned int flags;\n\tstruct proc_dir_entry *proc_entry;\n\tstruct tty_driver *other;\n\tstruct tty_struct **ttys;\n\tstruct tty_port **ports;\n\tstruct ktermios **termios;\n\tvoid *driver_state;\n\tconst struct tty_operations *ops;\n\tstruct list_head tty_drivers;\n};\n\nstruct tty_buffer {\n\tunion {\n\t\tstruct tty_buffer *next;\n\t\tstruct llist_node free;\n\t};\n\tint used;\n\tint size;\n\tint commit;\n\tint read;\n\tint flags;\n\tlong unsigned int data[0];\n};\n\nstruct tty_bufhead {\n\tstruct tty_buffer *head;\n\tstruct work_struct work;\n\tstruct mutex lock;\n\tatomic_t priority;\n\tstruct tty_buffer sentinel;\n\tstruct llist_head free;\n\tatomic_t mem_used;\n\tint mem_limit;\n\tstruct tty_buffer *tail;\n};\n\nstruct tty_port_operations;\n\nstruct tty_port_client_operations;\n\nstruct tty_port {\n\tstruct tty_bufhead buf;\n\tstruct tty_struct *tty;\n\tstruct tty_struct *itty;\n\tconst struct tty_port_operations *ops;\n\tconst struct tty_port_client_operations *client_ops;\n\tspinlock_t lock;\n\tint blocked_open;\n\tint count;\n\twait_queue_head_t open_wait;\n\twait_queue_head_t delta_msr_wait;\n\tlong unsigned int flags;\n\tlong unsigned int iflags;\n\tunsigned char console: 1;\n\tstruct mutex mutex;\n\tstruct mutex buf_mutex;\n\tunsigned char *xmit_buf;\n\tunsigned int close_delay;\n\tunsigned int closing_wait;\n\tint drain_delay;\n\tstruct kref kref;\n\tvoid *client_data;\n};\n\nstruct tty_ldisc_ops {\n\tchar *name;\n\tint num;\n\tint flags;\n\tint (*open)(struct tty_struct *);\n\tvoid (*close)(struct tty_struct *);\n\tvoid (*flush_buffer)(struct tty_struct *);\n\tssize_t (*read)(struct tty_struct *, struct file *, unsigned char *, size_t, void **, long unsigned int);\n\tssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t);\n\tint (*ioctl)(struct tty_struct *, struct file *, unsigned int, long unsigned int);\n\tint (*compat_ioctl)(struct tty_struct *, struct file *, unsigned int, long unsigned int);\n\tvoid (*set_termios)(struct tty_struct *, struct ktermios *);\n\t__poll_t (*poll)(struct tty_struct *, struct file *, struct poll_table_struct *);\n\tint (*hangup)(struct tty_struct *);\n\tvoid (*receive_buf)(struct tty_struct *, const unsigned char *, const char *, int);\n\tvoid (*write_wakeup)(struct tty_struct *);\n\tvoid (*dcd_change)(struct tty_struct *, unsigned int);\n\tint (*receive_buf2)(struct tty_struct *, const unsigned char *, const char *, int);\n\tstruct module *owner;\n};\n\nstruct tty_ldisc {\n\tstruct tty_ldisc_ops *ops;\n\tstruct tty_struct *tty;\n};\n\nstruct tty_port_operations {\n\tint (*carrier_raised)(struct tty_port *);\n\tvoid (*dtr_rts)(struct tty_port *, int);\n\tvoid (*shutdown)(struct tty_port *);\n\tint (*activate)(struct tty_port *, struct tty_struct *);\n\tvoid (*destruct)(struct tty_port *);\n};\n\nstruct tty_port_client_operations {\n\tint (*receive_buf)(struct tty_port *, const unsigned char *, const unsigned char *, size_t);\n\tvoid (*write_wakeup)(struct tty_port *);\n};\n\nstruct prot_inuse;\n\nstruct netns_core {\n\tstruct ctl_table_header *sysctl_hdr;\n\tint sysctl_somaxconn;\n\tint *sock_inuse;\n\tstruct prot_inuse *prot_inuse;\n};\n\nstruct ipstats_mib;\n\nstruct tcp_mib;\n\nstruct linux_mib;\n\nstruct udp_mib;\n\nstruct linux_xfrm_mib;\n\nstruct linux_tls_mib;\n\nstruct mptcp_mib;\n\nstruct icmp_mib;\n\nstruct icmpmsg_mib;\n\nstruct icmpv6_mib;\n\nstruct icmpv6msg_mib;\n\nstruct netns_mib {\n\tstruct ipstats_mib *ip_statistics;\n\tstruct ipstats_mib *ipv6_statistics;\n\tstruct tcp_mib *tcp_statistics;\n\tstruct linux_mib *net_statistics;\n\tstruct udp_mib *udp_statistics;\n\tstruct udp_mib *udp_stats_in6;\n\tstruct linux_xfrm_mib *xfrm_statistics;\n\tstruct linux_tls_mib *tls_statistics;\n\tstruct mptcp_mib *mptcp_statistics;\n\tstruct udp_mib *udplite_statistics;\n\tstruct udp_mib *udplite_stats_in6;\n\tstruct icmp_mib *icmp_statistics;\n\tstruct icmpmsg_mib *icmpmsg_statistics;\n\tstruct icmpv6_mib *icmpv6_statistics;\n\tstruct icmpv6msg_mib *icmpv6msg_statistics;\n\tstruct proc_dir_entry *proc_net_devsnmp6;\n};\n\nstruct netns_packet {\n\tstruct mutex sklist_lock;\n\tstruct hlist_head sklist;\n};\n\nstruct netns_unix {\n\tint sysctl_max_dgram_qlen;\n\tstruct ctl_table_header *ctl;\n};\n\nstruct netns_nexthop {\n\tstruct rb_root rb_root;\n\tstruct hlist_head *devhash;\n\tunsigned int seq;\n\tu32 last_id_allocated;\n\tstruct blocking_notifier_head notifier_chain;\n};\n\nstruct inet_hashinfo;\n\nstruct inet_timewait_death_row {\n\tatomic_t tw_count;\n\tchar tw_pad[60];\n\tstruct inet_hashinfo *hashinfo;\n\tint sysctl_max_tw_buckets;\n};\n\nstruct local_ports {\n\tseqlock_t lock;\n\tint range[2];\n\tbool warned;\n};\n\nstruct ping_group_range {\n\tseqlock_t lock;\n\tkgid_t range[2];\n};\n\ntypedef struct {\n\tu64 key[2];\n} siphash_key_t;\n\nstruct ipv4_devconf;\n\nstruct ip_ra_chain;\n\nstruct fib_rules_ops;\n\nstruct fib_table;\n\nstruct inet_peer_base;\n\nstruct fqdir;\n\nstruct tcp_congestion_ops;\n\nstruct tcp_fastopen_context;\n\nstruct fib_notifier_ops;\n\nstruct netns_ipv4 {\n\tstruct inet_timewait_death_row tcp_death_row;\n\tstruct ctl_table_header *forw_hdr;\n\tstruct ctl_table_header *frags_hdr;\n\tstruct ctl_table_header *ipv4_hdr;\n\tstruct ctl_table_header *route_hdr;\n\tstruct ctl_table_header *xfrm4_hdr;\n\tstruct ipv4_devconf *devconf_all;\n\tstruct ipv4_devconf *devconf_dflt;\n\tstruct ip_ra_chain *ra_chain;\n\tstruct mutex ra_mutex;\n\tstruct fib_rules_ops *rules_ops;\n\tstruct fib_table *fib_main;\n\tstruct fib_table *fib_default;\n\tunsigned int fib_rules_require_fldissect;\n\tbool fib_has_custom_rules;\n\tbool fib_has_custom_local_routes;\n\tbool fib_offload_disabled;\n\tint fib_num_tclassid_users;\n\tstruct hlist_head *fib_table_hash;\n\tstruct sock *fibnl;\n\tstruct sock **icmp_sk;\n\tstruct sock *mc_autojoin_sk;\n\tstruct inet_peer_base *peers;\n\tstruct sock **tcp_sk;\n\tstruct fqdir *fqdir;\n\tu8 sysctl_icmp_echo_ignore_all;\n\tu8 sysctl_icmp_echo_enable_probe;\n\tu8 sysctl_icmp_echo_ignore_broadcasts;\n\tu8 sysctl_icmp_ignore_bogus_error_responses;\n\tu8 sysctl_icmp_errors_use_inbound_ifaddr;\n\tint sysctl_icmp_ratelimit;\n\tint sysctl_icmp_ratemask;\n\tstruct local_ports ip_local_ports;\n\tu8 sysctl_tcp_ecn;\n\tu8 sysctl_tcp_ecn_fallback;\n\tu8 sysctl_ip_default_ttl;\n\tu8 sysctl_ip_no_pmtu_disc;\n\tu8 sysctl_ip_fwd_use_pmtu;\n\tu8 sysctl_ip_fwd_update_priority;\n\tu8 sysctl_ip_nonlocal_bind;\n\tu8 sysctl_ip_autobind_reuse;\n\tu8 sysctl_ip_dynaddr;\n\tu8 sysctl_ip_early_demux;\n\tu8 sysctl_raw_l3mdev_accept;\n\tu8 sysctl_tcp_early_demux;\n\tu8 sysctl_udp_early_demux;\n\tu8 sysctl_nexthop_compat_mode;\n\tu8 sysctl_fwmark_reflect;\n\tu8 sysctl_tcp_fwmark_accept;\n\tu8 sysctl_tcp_l3mdev_accept;\n\tu8 sysctl_tcp_mtu_probing;\n\tint sysctl_tcp_mtu_probe_floor;\n\tint sysctl_tcp_base_mss;\n\tint sysctl_tcp_min_snd_mss;\n\tint sysctl_tcp_probe_threshold;\n\tu32 sysctl_tcp_probe_interval;\n\tint sysctl_tcp_keepalive_time;\n\tint sysctl_tcp_keepalive_intvl;\n\tu8 sysctl_tcp_keepalive_probes;\n\tu8 sysctl_tcp_syn_retries;\n\tu8 sysctl_tcp_synack_retries;\n\tu8 sysctl_tcp_syncookies;\n\tu8 sysctl_tcp_migrate_req;\n\tint sysctl_tcp_reordering;\n\tu8 sysctl_tcp_retries1;\n\tu8 sysctl_tcp_retries2;\n\tu8 sysctl_tcp_orphan_retries;\n\tu8 sysctl_tcp_tw_reuse;\n\tint sysctl_tcp_fin_timeout;\n\tunsigned int sysctl_tcp_notsent_lowat;\n\tu8 sysctl_tcp_sack;\n\tu8 sysctl_tcp_window_scaling;\n\tu8 sysctl_tcp_timestamps;\n\tu8 sysctl_tcp_early_retrans;\n\tu8 sysctl_tcp_recovery;\n\tu8 sysctl_tcp_thin_linear_timeouts;\n\tu8 sysctl_tcp_slow_start_after_idle;\n\tu8 sysctl_tcp_retrans_collapse;\n\tu8 sysctl_tcp_stdurg;\n\tu8 sysctl_tcp_rfc1337;\n\tu8 sysctl_tcp_abort_on_overflow;\n\tu8 sysctl_tcp_fack;\n\tint sysctl_tcp_max_reordering;\n\tint sysctl_tcp_adv_win_scale;\n\tu8 sysctl_tcp_dsack;\n\tu8 sysctl_tcp_app_win;\n\tu8 sysctl_tcp_frto;\n\tu8 sysctl_tcp_nometrics_save;\n\tu8 sysctl_tcp_no_ssthresh_metrics_save;\n\tu8 sysctl_tcp_moderate_rcvbuf;\n\tu8 sysctl_tcp_tso_win_divisor;\n\tu8 sysctl_tcp_workaround_signed_windows;\n\tint sysctl_tcp_limit_output_bytes;\n\tint sysctl_tcp_challenge_ack_limit;\n\tint sysctl_tcp_min_rtt_wlen;\n\tu8 sysctl_tcp_min_tso_segs;\n\tu8 sysctl_tcp_autocorking;\n\tu8 sysctl_tcp_reflect_tos;\n\tu8 sysctl_tcp_comp_sack_nr;\n\tint sysctl_tcp_invalid_ratelimit;\n\tint sysctl_tcp_pacing_ss_ratio;\n\tint sysctl_tcp_pacing_ca_ratio;\n\tint sysctl_tcp_wmem[3];\n\tint sysctl_tcp_rmem[3];\n\tlong unsigned int sysctl_tcp_comp_sack_delay_ns;\n\tlong unsigned int sysctl_tcp_comp_sack_slack_ns;\n\tint sysctl_max_syn_backlog;\n\tint sysctl_tcp_fastopen;\n\tconst struct tcp_congestion_ops *tcp_congestion_control;\n\tstruct tcp_fastopen_context *tcp_fastopen_ctx;\n\tspinlock_t tcp_fastopen_ctx_lock;\n\tunsigned int sysctl_tcp_fastopen_blackhole_timeout;\n\tatomic_t tfo_active_disable_times;\n\tlong unsigned int tfo_active_disable_stamp;\n\tint sysctl_udp_wmem_min;\n\tint sysctl_udp_rmem_min;\n\tu8 sysctl_fib_notify_on_flag_change;\n\tu8 sysctl_udp_l3mdev_accept;\n\tu8 sysctl_igmp_llm_reports;\n\tint sysctl_igmp_max_memberships;\n\tint sysctl_igmp_max_msf;\n\tint sysctl_igmp_qrv;\n\tstruct ping_group_range ping_group_range;\n\tatomic_t dev_addr_genid;\n\tlong unsigned int *sysctl_local_reserved_ports;\n\tint sysctl_ip_prot_sock;\n\tstruct list_head mr_tables;\n\tstruct fib_rules_ops *mr_rules_ops;\n\tu32 sysctl_fib_multipath_hash_fields;\n\tu8 sysctl_fib_multipath_use_neigh;\n\tu8 sysctl_fib_multipath_hash_policy;\n\tstruct fib_notifier_ops *notifier_ops;\n\tunsigned int fib_seq;\n\tstruct fib_notifier_ops *ipmr_notifier_ops;\n\tunsigned int ipmr_seq;\n\tatomic_t rt_genid;\n\tsiphash_key_t ip_id_key;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct neighbour;\n\nstruct dst_ops {\n\tshort unsigned int family;\n\tunsigned int gc_thresh;\n\tint (*gc)(struct dst_ops *);\n\tstruct dst_entry * (*check)(struct dst_entry *, __u32);\n\tunsigned int (*default_advmss)(const struct dst_entry *);\n\tunsigned int (*mtu)(const struct dst_entry *);\n\tu32 * (*cow_metrics)(struct dst_entry *, long unsigned int);\n\tvoid (*destroy)(struct dst_entry *);\n\tvoid (*ifdown)(struct dst_entry *, struct net_device *, int);\n\tstruct dst_entry * (*negative_advice)(struct dst_entry *);\n\tvoid (*link_failure)(struct sk_buff *);\n\tvoid (*update_pmtu)(struct dst_entry *, struct sock *, struct sk_buff *, u32, bool);\n\tvoid (*redirect)(struct dst_entry *, struct sock *, struct sk_buff *);\n\tint (*local_out)(struct net *, struct sock *, struct sk_buff *);\n\tstruct neighbour * (*neigh_lookup)(const struct dst_entry *, struct sk_buff *, const void *);\n\tvoid (*confirm_neigh)(const struct dst_entry *, const void *);\n\tstruct kmem_cache *kmem_cachep;\n\tstruct percpu_counter pcpuc_entries;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct netns_sysctl_ipv6 {\n\tstruct ctl_table_header *hdr;\n\tstruct ctl_table_header *route_hdr;\n\tstruct ctl_table_header *icmp_hdr;\n\tstruct ctl_table_header *frags_hdr;\n\tstruct ctl_table_header *xfrm6_hdr;\n\tint flush_delay;\n\tint ip6_rt_max_size;\n\tint ip6_rt_gc_min_interval;\n\tint ip6_rt_gc_timeout;\n\tint ip6_rt_gc_interval;\n\tint ip6_rt_gc_elasticity;\n\tint ip6_rt_mtu_expires;\n\tint ip6_rt_min_advmss;\n\tu32 multipath_hash_fields;\n\tu8 multipath_hash_policy;\n\tu8 bindv6only;\n\tu8 flowlabel_consistency;\n\tu8 auto_flowlabels;\n\tint icmpv6_time;\n\tu8 icmpv6_echo_ignore_all;\n\tu8 icmpv6_echo_ignore_multicast;\n\tu8 icmpv6_echo_ignore_anycast;\n\tlong unsigned int icmpv6_ratemask[4];\n\tlong unsigned int *icmpv6_ratemask_ptr;\n\tu8 anycast_src_echo_reply;\n\tu8 ip_nonlocal_bind;\n\tu8 fwmark_reflect;\n\tu8 flowlabel_state_ranges;\n\tint idgen_retries;\n\tint idgen_delay;\n\tint flowlabel_reflect;\n\tint max_dst_opts_cnt;\n\tint max_hbh_opts_cnt;\n\tint max_dst_opts_len;\n\tint max_hbh_opts_len;\n\tint seg6_flowlabel;\n\tbool skip_notify_on_dev_down;\n\tu8 fib_notify_on_flag_change;\n};\n\nstruct ipv6_devconf;\n\nstruct fib6_info;\n\nstruct rt6_info;\n\nstruct rt6_statistics;\n\nstruct fib6_table;\n\nstruct seg6_pernet_data;\n\nstruct netns_ipv6 {\n\tstruct dst_ops ip6_dst_ops;\n\tstruct netns_sysctl_ipv6 sysctl;\n\tstruct ipv6_devconf *devconf_all;\n\tstruct ipv6_devconf *devconf_dflt;\n\tstruct inet_peer_base *peers;\n\tstruct fqdir *fqdir;\n\tstruct fib6_info *fib6_null_entry;\n\tstruct rt6_info *ip6_null_entry;\n\tstruct rt6_statistics *rt6_stats;\n\tstruct timer_list ip6_fib_timer;\n\tstruct hlist_head *fib_table_hash;\n\tstruct fib6_table *fib6_main_tbl;\n\tstruct list_head fib6_walkers;\n\trwlock_t fib6_walker_lock;\n\tspinlock_t fib6_gc_lock;\n\tunsigned int ip6_rt_gc_expire;\n\tlong unsigned int ip6_rt_last_gc;\n\tunsigned int fib6_rules_require_fldissect;\n\tbool fib6_has_custom_rules;\n\tunsigned int fib6_routes_require_src;\n\tstruct rt6_info *ip6_prohibit_entry;\n\tstruct rt6_info *ip6_blk_hole_entry;\n\tstruct fib6_table *fib6_local_tbl;\n\tstruct fib_rules_ops *fib6_rules_ops;\n\tstruct sock **icmp_sk;\n\tstruct sock *ndisc_sk;\n\tstruct sock *tcp_sk;\n\tstruct sock *igmp_sk;\n\tstruct sock *mc_autojoin_sk;\n\tstruct list_head mr6_tables;\n\tstruct fib_rules_ops *mr6_rules_ops;\n\tatomic_t dev_addr_genid;\n\tatomic_t fib6_sernum;\n\tstruct seg6_pernet_data *seg6_data;\n\tstruct fib_notifier_ops *notifier_ops;\n\tstruct fib_notifier_ops *ip6mr_notifier_ops;\n\tunsigned int ipmr_seq;\n\tstruct {\n\t\tstruct hlist_head head;\n\t\tspinlock_t lock;\n\t\tu32 seq;\n\t} ip6addrlbl_table;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct netns_sysctl_lowpan {\n\tstruct ctl_table_header *frags_hdr;\n};\n\nstruct netns_ieee802154_lowpan {\n\tstruct netns_sysctl_lowpan sysctl;\n\tstruct fqdir *fqdir;\n};\n\nstruct sctp_mib;\n\nstruct netns_sctp {\n\tstruct sctp_mib *sctp_statistics;\n\tstruct proc_dir_entry *proc_net_sctp;\n\tstruct ctl_table_header *sysctl_header;\n\tstruct sock *ctl_sock;\n\tstruct sock *udp4_sock;\n\tstruct sock *udp6_sock;\n\tint udp_port;\n\tint encap_port;\n\tstruct list_head local_addr_list;\n\tstruct list_head addr_waitq;\n\tstruct timer_list addr_wq_timer;\n\tstruct list_head auto_asconf_splist;\n\tspinlock_t addr_wq_lock;\n\tspinlock_t local_addr_lock;\n\tunsigned int rto_initial;\n\tunsigned int rto_min;\n\tunsigned int rto_max;\n\tint rto_alpha;\n\tint rto_beta;\n\tint max_burst;\n\tint cookie_preserve_enable;\n\tchar *sctp_hmac_alg;\n\tunsigned int valid_cookie_life;\n\tunsigned int sack_timeout;\n\tunsigned int hb_interval;\n\tunsigned int probe_interval;\n\tint max_retrans_association;\n\tint max_retrans_path;\n\tint max_retrans_init;\n\tint pf_retrans;\n\tint ps_retrans;\n\tint pf_enable;\n\tint pf_expose;\n\tint sndbuf_policy;\n\tint rcvbuf_policy;\n\tint default_auto_asconf;\n\tint addip_enable;\n\tint addip_noauth;\n\tint prsctp_enable;\n\tint reconf_enable;\n\tint auth_enable;\n\tint intl_enable;\n\tint ecn_enable;\n\tint scope_policy;\n\tint rwnd_upd_shift;\n\tlong unsigned int max_autoclose;\n};\n\nstruct nf_queue_handler;\n\nstruct nf_logger;\n\nstruct nf_hook_entries;\n\nstruct netns_nf {\n\tstruct proc_dir_entry *proc_netfilter;\n\tconst struct nf_queue_handler *queue_handler;\n\tconst struct nf_logger *nf_loggers[13];\n\tstruct ctl_table_header *nf_log_dir_header;\n\tstruct nf_hook_entries *hooks_ipv4[5];\n\tstruct nf_hook_entries *hooks_ipv6[5];\n\tstruct nf_hook_entries *hooks_arp[3];\n\tstruct nf_hook_entries *hooks_bridge[5];\n};\n\nstruct netns_xt {\n\tbool notrack_deprecated_warning;\n\tbool clusterip_deprecated_warning;\n};\n\nstruct nf_generic_net {\n\tunsigned int timeout;\n};\n\nstruct nf_tcp_net {\n\tunsigned int timeouts[14];\n\tu8 tcp_loose;\n\tu8 tcp_be_liberal;\n\tu8 tcp_max_retrans;\n\tu8 tcp_ignore_invalid_rst;\n\tunsigned int offload_timeout;\n};\n\nstruct nf_udp_net {\n\tunsigned int timeouts[2];\n\tunsigned int offload_timeout;\n};\n\nstruct nf_icmp_net {\n\tunsigned int timeout;\n};\n\nstruct nf_dccp_net {\n\tu8 dccp_loose;\n\tunsigned int dccp_timeout[10];\n};\n\nstruct nf_sctp_net {\n\tunsigned int timeouts[10];\n};\n\nstruct nf_gre_net {\n\tstruct list_head keymap_list;\n\tunsigned int timeouts[2];\n};\n\nstruct nf_ip_net {\n\tstruct nf_generic_net generic;\n\tstruct nf_tcp_net tcp;\n\tstruct nf_udp_net udp;\n\tstruct nf_icmp_net icmp;\n\tstruct nf_icmp_net icmpv6;\n\tstruct nf_dccp_net dccp;\n\tstruct nf_sctp_net sctp;\n\tstruct nf_gre_net gre;\n};\n\nstruct ct_pcpu;\n\nstruct ip_conntrack_stat;\n\nstruct nf_ct_event_notifier;\n\nstruct nf_exp_event_notifier;\n\nstruct netns_ct {\n\tbool ecache_dwork_pending;\n\tu8 sysctl_log_invalid;\n\tu8 sysctl_events;\n\tu8 sysctl_acct;\n\tu8 sysctl_auto_assign_helper;\n\tu8 sysctl_tstamp;\n\tu8 sysctl_checksum;\n\tstruct ct_pcpu *pcpu_lists;\n\tstruct ip_conntrack_stat *stat;\n\tstruct nf_ct_event_notifier *nf_conntrack_event_cb;\n\tstruct nf_exp_event_notifier *nf_expect_event_cb;\n\tstruct nf_ip_net nf_ct_proto;\n\tunsigned int labels_used;\n};\n\nstruct netns_nftables {\n\tu8 gencursor;\n};\n\nstruct netns_bpf {\n\tstruct bpf_prog_array *run_array[2];\n\tstruct bpf_prog *progs[2];\n\tstruct list_head links[2];\n};\n\nstruct xfrm_policy_hash {\n\tstruct hlist_head *table;\n\tunsigned int hmask;\n\tu8 dbits4;\n\tu8 sbits4;\n\tu8 dbits6;\n\tu8 sbits6;\n};\n\nstruct xfrm_policy_hthresh {\n\tstruct work_struct work;\n\tseqlock_t lock;\n\tu8 lbits4;\n\tu8 rbits4;\n\tu8 lbits6;\n\tu8 rbits6;\n};\n\nstruct netns_xfrm {\n\tstruct list_head state_all;\n\tstruct hlist_head *state_bydst;\n\tstruct hlist_head *state_bysrc;\n\tstruct hlist_head *state_byspi;\n\tstruct hlist_head *state_byseq;\n\tunsigned int state_hmask;\n\tunsigned int state_num;\n\tstruct work_struct state_hash_work;\n\tstruct list_head policy_all;\n\tstruct hlist_head *policy_byidx;\n\tunsigned int policy_idx_hmask;\n\tstruct hlist_head policy_inexact[3];\n\tstruct xfrm_policy_hash policy_bydst[3];\n\tunsigned int policy_count[6];\n\tstruct work_struct policy_hash_work;\n\tstruct xfrm_policy_hthresh policy_hthresh;\n\tstruct list_head inexact_bins;\n\tstruct sock *nlsk;\n\tstruct sock *nlsk_stash;\n\tu32 sysctl_aevent_etime;\n\tu32 sysctl_aevent_rseqth;\n\tint sysctl_larval_drop;\n\tu32 sysctl_acq_expires;\n\tstruct ctl_table_header *sysctl_hdr;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct dst_ops xfrm4_dst_ops;\n\tstruct dst_ops xfrm6_dst_ops;\n\tspinlock_t xfrm_state_lock;\n\tseqcount_spinlock_t xfrm_state_hash_generation;\n\tseqcount_spinlock_t xfrm_policy_hash_generation;\n\tspinlock_t xfrm_policy_lock;\n\tstruct mutex xfrm_cfg_mutex;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct netns_ipvs;\n\nstruct mpls_route;\n\nstruct netns_mpls {\n\tint ip_ttl_propagate;\n\tint default_ttl;\n\tsize_t platform_labels;\n\tstruct mpls_route **platform_label;\n\tstruct ctl_table_header *ctl;\n};\n\nstruct can_dev_rcv_lists;\n\nstruct can_pkg_stats;\n\nstruct can_rcv_lists_stats;\n\nstruct netns_can {\n\tstruct proc_dir_entry *proc_dir;\n\tstruct proc_dir_entry *pde_stats;\n\tstruct proc_dir_entry *pde_reset_stats;\n\tstruct proc_dir_entry *pde_rcvlist_all;\n\tstruct proc_dir_entry *pde_rcvlist_fil;\n\tstruct proc_dir_entry *pde_rcvlist_inv;\n\tstruct proc_dir_entry *pde_rcvlist_sff;\n\tstruct proc_dir_entry *pde_rcvlist_eff;\n\tstruct proc_dir_entry *pde_rcvlist_err;\n\tstruct proc_dir_entry *bcmproc_dir;\n\tstruct can_dev_rcv_lists *rx_alldev_list;\n\tspinlock_t rcvlists_lock;\n\tstruct timer_list stattimer;\n\tstruct can_pkg_stats *pkg_stats;\n\tstruct can_rcv_lists_stats *rcv_lists_stats;\n\tstruct hlist_head cgw_list;\n};\n\nstruct netns_xdp {\n\tstruct mutex lock;\n\tstruct hlist_head list;\n};\n\nstruct smc_stats;\n\nstruct smc_stats_rsn;\n\nstruct netns_smc {\n\tstruct smc_stats *smc_stats;\n\tstruct mutex mutex_fback_rsn;\n\tstruct smc_stats_rsn *fback_rsn;\n};\n\nstruct uevent_sock;\n\nstruct net_generic;\n\nstruct net {\n\trefcount_t passive;\n\tspinlock_t rules_mod_lock;\n\tunsigned int dev_unreg_count;\n\tunsigned int dev_base_seq;\n\tint ifindex;\n\tspinlock_t nsid_lock;\n\tatomic_t fnhe_genid;\n\tstruct list_head list;\n\tstruct list_head exit_list;\n\tstruct llist_node cleanup_list;\n\tstruct key_tag *key_domain;\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tstruct idr netns_ids;\n\tstruct ns_common ns;\n\tstruct list_head dev_base_head;\n\tstruct proc_dir_entry *proc_net;\n\tstruct proc_dir_entry *proc_net_stat;\n\tstruct ctl_table_set sysctls;\n\tstruct sock *rtnl;\n\tstruct sock *genl_sock;\n\tstruct uevent_sock *uevent_sock;\n\tstruct hlist_head *dev_name_head;\n\tstruct hlist_head *dev_index_head;\n\tstruct raw_notifier_head netdev_chain;\n\tu32 hash_mix;\n\tstruct net_device *loopback_dev;\n\tstruct list_head rules_ops;\n\tstruct netns_core core;\n\tstruct netns_mib mib;\n\tstruct netns_packet packet;\n\tstruct netns_unix unx;\n\tstruct netns_nexthop nexthop;\n\tstruct netns_ipv4 ipv4;\n\tstruct netns_ipv6 ipv6;\n\tstruct netns_ieee802154_lowpan ieee802154_lowpan;\n\tstruct netns_sctp sctp;\n\tstruct netns_nf nf;\n\tstruct netns_xt xt;\n\tstruct netns_ct ct;\n\tstruct netns_nftables nft;\n\tstruct sk_buff_head wext_nlevents;\n\tstruct net_generic *gen;\n\tstruct netns_bpf bpf;\n\tlong: 64;\n\tlong: 64;\n\tstruct netns_xfrm xfrm;\n\tu64 net_cookie;\n\tstruct netns_ipvs *ipvs;\n\tstruct netns_mpls mpls;\n\tstruct netns_can can;\n\tstruct netns_xdp xdp;\n\tstruct sock *crypto_nlsk;\n\tstruct sock *diag_nlsk;\n\tstruct netns_smc smc;\n\tlong: 64;\n};\n\ntypedef struct {\n\tlocal64_t v;\n} u64_stats_t;\n\nstruct bpf_insn {\n\t__u8 code;\n\t__u8 dst_reg: 4;\n\t__u8 src_reg: 4;\n\t__s16 off;\n\t__s32 imm;\n};\n\nenum bpf_map_type {\n\tBPF_MAP_TYPE_UNSPEC = 0,\n\tBPF_MAP_TYPE_HASH = 1,\n\tBPF_MAP_TYPE_ARRAY = 2,\n\tBPF_MAP_TYPE_PROG_ARRAY = 3,\n\tBPF_MAP_TYPE_PERF_EVENT_ARRAY = 4,\n\tBPF_MAP_TYPE_PERCPU_HASH = 5,\n\tBPF_MAP_TYPE_PERCPU_ARRAY = 6,\n\tBPF_MAP_TYPE_STACK_TRACE = 7,\n\tBPF_MAP_TYPE_CGROUP_ARRAY = 8,\n\tBPF_MAP_TYPE_LRU_HASH = 9,\n\tBPF_MAP_TYPE_LRU_PERCPU_HASH = 10,\n\tBPF_MAP_TYPE_LPM_TRIE = 11,\n\tBPF_MAP_TYPE_ARRAY_OF_MAPS = 12,\n\tBPF_MAP_TYPE_HASH_OF_MAPS = 13,\n\tBPF_MAP_TYPE_DEVMAP = 14,\n\tBPF_MAP_TYPE_SOCKMAP = 15,\n\tBPF_MAP_TYPE_CPUMAP = 16,\n\tBPF_MAP_TYPE_XSKMAP = 17,\n\tBPF_MAP_TYPE_SOCKHASH = 18,\n\tBPF_MAP_TYPE_CGROUP_STORAGE = 19,\n\tBPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20,\n\tBPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21,\n\tBPF_MAP_TYPE_QUEUE = 22,\n\tBPF_MAP_TYPE_STACK = 23,\n\tBPF_MAP_TYPE_SK_STORAGE = 24,\n\tBPF_MAP_TYPE_DEVMAP_HASH = 25,\n\tBPF_MAP_TYPE_STRUCT_OPS = 26,\n\tBPF_MAP_TYPE_RINGBUF = 27,\n\tBPF_MAP_TYPE_INODE_STORAGE = 28,\n\tBPF_MAP_TYPE_TASK_STORAGE = 29,\n};\n\nenum bpf_prog_type {\n\tBPF_PROG_TYPE_UNSPEC = 0,\n\tBPF_PROG_TYPE_SOCKET_FILTER = 1,\n\tBPF_PROG_TYPE_KPROBE = 2,\n\tBPF_PROG_TYPE_SCHED_CLS = 3,\n\tBPF_PROG_TYPE_SCHED_ACT = 4,\n\tBPF_PROG_TYPE_TRACEPOINT = 5,\n\tBPF_PROG_TYPE_XDP = 6,\n\tBPF_PROG_TYPE_PERF_EVENT = 7,\n\tBPF_PROG_TYPE_CGROUP_SKB = 8,\n\tBPF_PROG_TYPE_CGROUP_SOCK = 9,\n\tBPF_PROG_TYPE_LWT_IN = 10,\n\tBPF_PROG_TYPE_LWT_OUT = 11,\n\tBPF_PROG_TYPE_LWT_XMIT = 12,\n\tBPF_PROG_TYPE_SOCK_OPS = 13,\n\tBPF_PROG_TYPE_SK_SKB = 14,\n\tBPF_PROG_TYPE_CGROUP_DEVICE = 15,\n\tBPF_PROG_TYPE_SK_MSG = 16,\n\tBPF_PROG_TYPE_RAW_TRACEPOINT = 17,\n\tBPF_PROG_TYPE_CGROUP_SOCK_ADDR = 18,\n\tBPF_PROG_TYPE_LWT_SEG6LOCAL = 19,\n\tBPF_PROG_TYPE_LIRC_MODE2 = 20,\n\tBPF_PROG_TYPE_SK_REUSEPORT = 21,\n\tBPF_PROG_TYPE_FLOW_DISSECTOR = 22,\n\tBPF_PROG_TYPE_CGROUP_SYSCTL = 23,\n\tBPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 24,\n\tBPF_PROG_TYPE_CGROUP_SOCKOPT = 25,\n\tBPF_PROG_TYPE_TRACING = 26,\n\tBPF_PROG_TYPE_STRUCT_OPS = 27,\n\tBPF_PROG_TYPE_EXT = 28,\n\tBPF_PROG_TYPE_LSM = 29,\n\tBPF_PROG_TYPE_SK_LOOKUP = 30,\n\tBPF_PROG_TYPE_SYSCALL = 31,\n};\n\nenum bpf_attach_type {\n\tBPF_CGROUP_INET_INGRESS = 0,\n\tBPF_CGROUP_INET_EGRESS = 1,\n\tBPF_CGROUP_INET_SOCK_CREATE = 2,\n\tBPF_CGROUP_SOCK_OPS = 3,\n\tBPF_SK_SKB_STREAM_PARSER = 4,\n\tBPF_SK_SKB_STREAM_VERDICT = 5,\n\tBPF_CGROUP_DEVICE = 6,\n\tBPF_SK_MSG_VERDICT = 7,\n\tBPF_CGROUP_INET4_BIND = 8,\n\tBPF_CGROUP_INET6_BIND = 9,\n\tBPF_CGROUP_INET4_CONNECT = 10,\n\tBPF_CGROUP_INET6_CONNECT = 11,\n\tBPF_CGROUP_INET4_POST_BIND = 12,\n\tBPF_CGROUP_INET6_POST_BIND = 13,\n\tBPF_CGROUP_UDP4_SENDMSG = 14,\n\tBPF_CGROUP_UDP6_SENDMSG = 15,\n\tBPF_LIRC_MODE2 = 16,\n\tBPF_FLOW_DISSECTOR = 17,\n\tBPF_CGROUP_SYSCTL = 18,\n\tBPF_CGROUP_UDP4_RECVMSG = 19,\n\tBPF_CGROUP_UDP6_RECVMSG = 20,\n\tBPF_CGROUP_GETSOCKOPT = 21,\n\tBPF_CGROUP_SETSOCKOPT = 22,\n\tBPF_TRACE_RAW_TP = 23,\n\tBPF_TRACE_FENTRY = 24,\n\tBPF_TRACE_FEXIT = 25,\n\tBPF_MODIFY_RETURN = 26,\n\tBPF_LSM_MAC = 27,\n\tBPF_TRACE_ITER = 28,\n\tBPF_CGROUP_INET4_GETPEERNAME = 29,\n\tBPF_CGROUP_INET6_GETPEERNAME = 30,\n\tBPF_CGROUP_INET4_GETSOCKNAME = 31,\n\tBPF_CGROUP_INET6_GETSOCKNAME = 32,\n\tBPF_XDP_DEVMAP = 33,\n\tBPF_CGROUP_INET_SOCK_RELEASE = 34,\n\tBPF_XDP_CPUMAP = 35,\n\tBPF_SK_LOOKUP = 36,\n\tBPF_XDP = 37,\n\tBPF_SK_SKB_VERDICT = 38,\n\tBPF_SK_REUSEPORT_SELECT = 39,\n\tBPF_SK_REUSEPORT_SELECT_OR_MIGRATE = 40,\n\t__MAX_BPF_ATTACH_TYPE = 41,\n};\n\nunion bpf_attr {\n\tstruct {\n\t\t__u32 map_type;\n\t\t__u32 key_size;\n\t\t__u32 value_size;\n\t\t__u32 max_entries;\n\t\t__u32 map_flags;\n\t\t__u32 inner_map_fd;\n\t\t__u32 numa_node;\n\t\tchar map_name[16];\n\t\t__u32 map_ifindex;\n\t\t__u32 btf_fd;\n\t\t__u32 btf_key_type_id;\n\t\t__u32 btf_value_type_id;\n\t\t__u32 btf_vmlinux_value_type_id;\n\t};\n\tstruct {\n\t\t__u32 map_fd;\n\t\t__u64 key;\n\t\tunion {\n\t\t\t__u64 value;\n\t\t\t__u64 next_key;\n\t\t};\n\t\t__u64 flags;\n\t};\n\tstruct {\n\t\t__u64 in_batch;\n\t\t__u64 out_batch;\n\t\t__u64 keys;\n\t\t__u64 values;\n\t\t__u32 count;\n\t\t__u32 map_fd;\n\t\t__u64 elem_flags;\n\t\t__u64 flags;\n\t} batch;\n\tstruct {\n\t\t__u32 prog_type;\n\t\t__u32 insn_cnt;\n\t\t__u64 insns;\n\t\t__u64 license;\n\t\t__u32 log_level;\n\t\t__u32 log_size;\n\t\t__u64 log_buf;\n\t\t__u32 kern_version;\n\t\t__u32 prog_flags;\n\t\tchar prog_name[16];\n\t\t__u32 prog_ifindex;\n\t\t__u32 expected_attach_type;\n\t\t__u32 prog_btf_fd;\n\t\t__u32 func_info_rec_size;\n\t\t__u64 func_info;\n\t\t__u32 func_info_cnt;\n\t\t__u32 line_info_rec_size;\n\t\t__u64 line_info;\n\t\t__u32 line_info_cnt;\n\t\t__u32 attach_btf_id;\n\t\tunion {\n\t\t\t__u32 attach_prog_fd;\n\t\t\t__u32 attach_btf_obj_fd;\n\t\t};\n\t\t__u64 fd_array;\n\t};\n\tstruct {\n\t\t__u64 pathname;\n\t\t__u32 bpf_fd;\n\t\t__u32 file_flags;\n\t};\n\tstruct {\n\t\t__u32 target_fd;\n\t\t__u32 attach_bpf_fd;\n\t\t__u32 attach_type;\n\t\t__u32 attach_flags;\n\t\t__u32 replace_bpf_fd;\n\t};\n\tstruct {\n\t\t__u32 prog_fd;\n\t\t__u32 retval;\n\t\t__u32 data_size_in;\n\t\t__u32 data_size_out;\n\t\t__u64 data_in;\n\t\t__u64 data_out;\n\t\t__u32 repeat;\n\t\t__u32 duration;\n\t\t__u32 ctx_size_in;\n\t\t__u32 ctx_size_out;\n\t\t__u64 ctx_in;\n\t\t__u64 ctx_out;\n\t\t__u32 flags;\n\t\t__u32 cpu;\n\t} test;\n\tstruct {\n\t\tunion {\n\t\t\t__u32 start_id;\n\t\t\t__u32 prog_id;\n\t\t\t__u32 map_id;\n\t\t\t__u32 btf_id;\n\t\t\t__u32 link_id;\n\t\t};\n\t\t__u32 next_id;\n\t\t__u32 open_flags;\n\t};\n\tstruct {\n\t\t__u32 bpf_fd;\n\t\t__u32 info_len;\n\t\t__u64 info;\n\t} info;\n\tstruct {\n\t\t__u32 target_fd;\n\t\t__u32 attach_type;\n\t\t__u32 query_flags;\n\t\t__u32 attach_flags;\n\t\t__u64 prog_ids;\n\t\t__u32 prog_cnt;\n\t} query;\n\tstruct {\n\t\t__u64 name;\n\t\t__u32 prog_fd;\n\t} raw_tracepoint;\n\tstruct {\n\t\t__u64 btf;\n\t\t__u64 btf_log_buf;\n\t\t__u32 btf_size;\n\t\t__u32 btf_log_size;\n\t\t__u32 btf_log_level;\n\t};\n\tstruct {\n\t\t__u32 pid;\n\t\t__u32 fd;\n\t\t__u32 flags;\n\t\t__u32 buf_len;\n\t\t__u64 buf;\n\t\t__u32 prog_id;\n\t\t__u32 fd_type;\n\t\t__u64 probe_offset;\n\t\t__u64 probe_addr;\n\t} task_fd_query;\n\tstruct {\n\t\t__u32 prog_fd;\n\t\tunion {\n\t\t\t__u32 target_fd;\n\t\t\t__u32 target_ifindex;\n\t\t};\n\t\t__u32 attach_type;\n\t\t__u32 flags;\n\t\tunion {\n\t\t\t__u32 target_btf_id;\n\t\t\tstruct {\n\t\t\t\t__u64 iter_info;\n\t\t\t\t__u32 iter_info_len;\n\t\t\t};\n\t\t};\n\t} link_create;\n\tstruct {\n\t\t__u32 link_fd;\n\t\t__u32 new_prog_fd;\n\t\t__u32 flags;\n\t\t__u32 old_prog_fd;\n\t} link_update;\n\tstruct {\n\t\t__u32 link_fd;\n\t} link_detach;\n\tstruct {\n\t\t__u32 type;\n\t} enable_stats;\n\tstruct {\n\t\t__u32 link_fd;\n\t\t__u32 flags;\n\t} iter_create;\n\tstruct {\n\t\t__u32 prog_fd;\n\t\t__u32 map_fd;\n\t\t__u32 flags;\n\t} prog_bind_map;\n};\n\nstruct bpf_func_info {\n\t__u32 insn_off;\n\t__u32 type_id;\n};\n\nstruct bpf_line_info {\n\t__u32 insn_off;\n\t__u32 file_name_off;\n\t__u32 line_off;\n\t__u32 line_col;\n};\n\ntypedef struct {\n\tunion {\n\t\tvoid *kernel;\n\t\tvoid *user;\n\t};\n\tbool is_kernel: 1;\n} sockptr_t;\n\nstruct bpf_iter_aux_info;\n\ntypedef int (*bpf_iter_init_seq_priv_t)(void *, struct bpf_iter_aux_info *);\n\nstruct bpf_map;\n\nstruct bpf_iter_aux_info {\n\tstruct bpf_map *map;\n};\n\ntypedef void (*bpf_iter_fini_seq_priv_t)(void *);\n\nstruct bpf_iter_seq_info {\n\tconst struct seq_operations *seq_ops;\n\tbpf_iter_init_seq_priv_t init_seq_private;\n\tbpf_iter_fini_seq_priv_t fini_seq_private;\n\tu32 seq_priv_size;\n};\n\nstruct btf;\n\nstruct btf_type;\n\nstruct bpf_prog_aux;\n\nstruct bpf_local_storage_map;\n\nstruct bpf_verifier_env;\n\nstruct bpf_func_state;\n\nstruct bpf_map_ops {\n\tint (*map_alloc_check)(union bpf_attr *);\n\tstruct bpf_map * (*map_alloc)(union bpf_attr *);\n\tvoid (*map_release)(struct bpf_map *, struct file *);\n\tvoid (*map_free)(struct bpf_map *);\n\tint (*map_get_next_key)(struct bpf_map *, void *, void *);\n\tvoid (*map_release_uref)(struct bpf_map *);\n\tvoid * (*map_lookup_elem_sys_only)(struct bpf_map *, void *);\n\tint (*map_lookup_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *);\n\tint (*map_lookup_and_delete_elem)(struct bpf_map *, void *, void *, u64);\n\tint (*map_lookup_and_delete_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *);\n\tint (*map_update_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *);\n\tint (*map_delete_batch)(struct bpf_map *, const union bpf_attr *, union bpf_attr *);\n\tvoid * (*map_lookup_elem)(struct bpf_map *, void *);\n\tint (*map_update_elem)(struct bpf_map *, void *, void *, u64);\n\tint (*map_delete_elem)(struct bpf_map *, void *);\n\tint (*map_push_elem)(struct bpf_map *, void *, u64);\n\tint (*map_pop_elem)(struct bpf_map *, void *);\n\tint (*map_peek_elem)(struct bpf_map *, void *);\n\tvoid * (*map_fd_get_ptr)(struct bpf_map *, struct file *, int);\n\tvoid (*map_fd_put_ptr)(void *);\n\tint (*map_gen_lookup)(struct bpf_map *, struct bpf_insn *);\n\tu32 (*map_fd_sys_lookup_elem)(void *);\n\tvoid (*map_seq_show_elem)(struct bpf_map *, void *, struct seq_file *);\n\tint (*map_check_btf)(const struct bpf_map *, const struct btf *, const struct btf_type *, const struct btf_type *);\n\tint (*map_poke_track)(struct bpf_map *, struct bpf_prog_aux *);\n\tvoid (*map_poke_untrack)(struct bpf_map *, struct bpf_prog_aux *);\n\tvoid (*map_poke_run)(struct bpf_map *, u32, struct bpf_prog *, struct bpf_prog *);\n\tint (*map_direct_value_addr)(const struct bpf_map *, u64 *, u32);\n\tint (*map_direct_value_meta)(const struct bpf_map *, u64, u32 *);\n\tint (*map_mmap)(struct bpf_map *, struct vm_area_struct *);\n\t__poll_t (*map_poll)(struct bpf_map *, struct file *, struct poll_table_struct *);\n\tint (*map_local_storage_charge)(struct bpf_local_storage_map *, void *, u32);\n\tvoid (*map_local_storage_uncharge)(struct bpf_local_storage_map *, void *, u32);\n\tstruct bpf_local_storage ** (*map_owner_storage_ptr)(void *);\n\tint (*map_redirect)(struct bpf_map *, u32, u64);\n\tbool (*map_meta_equal)(const struct bpf_map *, const struct bpf_map *);\n\tint (*map_set_for_each_callback_args)(struct bpf_verifier_env *, struct bpf_func_state *, struct bpf_func_state *);\n\tint (*map_for_each_callback)(struct bpf_map *, void *, void *, u64);\n\tconst char * const map_btf_name;\n\tint *map_btf_id;\n\tconst struct bpf_iter_seq_info *iter_seq_info;\n};\n\nstruct bpf_map {\n\tconst struct bpf_map_ops *ops;\n\tstruct bpf_map *inner_map_meta;\n\tvoid *security;\n\tenum bpf_map_type map_type;\n\tu32 key_size;\n\tu32 value_size;\n\tu32 max_entries;\n\tu32 map_flags;\n\tint spin_lock_off;\n\tu32 id;\n\tint numa_node;\n\tu32 btf_key_type_id;\n\tu32 btf_value_type_id;\n\tstruct btf *btf;\n\tstruct mem_cgroup *memcg;\n\tchar name[16];\n\tu32 btf_vmlinux_value_type_id;\n\tbool bypass_spec_v1;\n\tbool frozen;\n\tlong: 16;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tatomic64_t refcnt;\n\tatomic64_t usercnt;\n\tstruct work_struct work;\n\tstruct mutex freeze_mutex;\n\tu64 writecnt;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct btf_header {\n\t__u16 magic;\n\t__u8 version;\n\t__u8 flags;\n\t__u32 hdr_len;\n\t__u32 type_off;\n\t__u32 type_len;\n\t__u32 str_off;\n\t__u32 str_len;\n};\n\nstruct btf {\n\tvoid *data;\n\tstruct btf_type **types;\n\tu32 *resolved_ids;\n\tu32 *resolved_sizes;\n\tconst char *strings;\n\tvoid *nohdr_data;\n\tstruct btf_header hdr;\n\tu32 nr_types;\n\tu32 types_size;\n\tu32 data_size;\n\trefcount_t refcnt;\n\tu32 id;\n\tstruct callback_head rcu;\n\tstruct btf *base_btf;\n\tu32 start_id;\n\tu32 start_str_off;\n\tchar name[56];\n\tbool kernel_btf;\n};\n\nstruct btf_type {\n\t__u32 name_off;\n\t__u32 info;\n\tunion {\n\t\t__u32 size;\n\t\t__u32 type;\n\t};\n};\n\nstruct bpf_ksym {\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tchar name[128];\n\tstruct list_head lnode;\n\tstruct latch_tree_node tnode;\n\tbool prog;\n};\n\nstruct bpf_ctx_arg_aux;\n\nstruct bpf_trampoline;\n\nstruct bpf_jit_poke_descriptor;\n\nstruct bpf_kfunc_desc_tab;\n\nstruct bpf_prog_ops;\n\nstruct btf_mod_pair;\n\nstruct bpf_prog_offload;\n\nstruct bpf_func_info_aux;\n\nstruct bpf_prog_aux {\n\tatomic64_t refcnt;\n\tu32 used_map_cnt;\n\tu32 used_btf_cnt;\n\tu32 max_ctx_offset;\n\tu32 max_pkt_offset;\n\tu32 max_tp_access;\n\tu32 stack_depth;\n\tu32 id;\n\tu32 func_cnt;\n\tu32 func_idx;\n\tu32 attach_btf_id;\n\tu32 ctx_arg_info_size;\n\tu32 max_rdonly_access;\n\tu32 max_rdwr_access;\n\tstruct btf *attach_btf;\n\tconst struct bpf_ctx_arg_aux *ctx_arg_info;\n\tstruct mutex dst_mutex;\n\tstruct bpf_prog *dst_prog;\n\tstruct bpf_trampoline *dst_trampoline;\n\tenum bpf_prog_type saved_dst_prog_type;\n\tenum bpf_attach_type saved_dst_attach_type;\n\tbool verifier_zext;\n\tbool offload_requested;\n\tbool attach_btf_trace;\n\tbool func_proto_unreliable;\n\tbool sleepable;\n\tbool tail_call_reachable;\n\tstruct hlist_node tramp_hlist;\n\tconst struct btf_type *attach_func_proto;\n\tconst char *attach_func_name;\n\tstruct bpf_prog **func;\n\tvoid *jit_data;\n\tstruct bpf_jit_poke_descriptor *poke_tab;\n\tstruct bpf_kfunc_desc_tab *kfunc_tab;\n\tu32 size_poke_tab;\n\tstruct bpf_ksym ksym;\n\tconst struct bpf_prog_ops *ops;\n\tstruct bpf_map **used_maps;\n\tstruct mutex used_maps_mutex;\n\tstruct btf_mod_pair *used_btfs;\n\tstruct bpf_prog *prog;\n\tstruct user_struct *user;\n\tu64 load_time;\n\tstruct bpf_map *cgroup_storage[2];\n\tchar name[16];\n\tvoid *security;\n\tstruct bpf_prog_offload *offload;\n\tstruct btf *btf;\n\tstruct bpf_func_info *func_info;\n\tstruct bpf_func_info_aux *func_info_aux;\n\tstruct bpf_line_info *linfo;\n\tvoid **jited_linfo;\n\tu32 func_info_cnt;\n\tu32 nr_linfo;\n\tu32 linfo_idx;\n\tu32 num_exentries;\n\tstruct exception_table_entry *extable;\n\tunion {\n\t\tstruct work_struct work;\n\t\tstruct callback_head rcu;\n\t};\n};\n\nstruct sock_filter {\n\t__u16 code;\n\t__u8 jt;\n\t__u8 jf;\n\t__u32 k;\n};\n\nstruct bpf_prog_stats;\n\nstruct sock_fprog_kern;\n\nstruct bpf_prog {\n\tu16 pages;\n\tu16 jited: 1;\n\tu16 jit_requested: 1;\n\tu16 gpl_compatible: 1;\n\tu16 cb_access: 1;\n\tu16 dst_needed: 1;\n\tu16 blinded: 1;\n\tu16 is_func: 1;\n\tu16 kprobe_override: 1;\n\tu16 has_callchain_buf: 1;\n\tu16 enforce_expected_attach_type: 1;\n\tu16 call_get_stack: 1;\n\tenum bpf_prog_type type;\n\tenum bpf_attach_type expected_attach_type;\n\tu32 len;\n\tu32 jited_len;\n\tu8 tag[8];\n\tstruct bpf_prog_stats *stats;\n\tint *active;\n\tunsigned int (*bpf_func)(const void *, const struct bpf_insn *);\n\tstruct bpf_prog_aux *aux;\n\tstruct sock_fprog_kern *orig_prog;\n\tstruct sock_filter insns[0];\n\tstruct bpf_insn insnsi[0];\n};\n\nstruct bpf_offloaded_map;\n\nstruct bpf_map_dev_ops {\n\tint (*map_get_next_key)(struct bpf_offloaded_map *, void *, void *);\n\tint (*map_lookup_elem)(struct bpf_offloaded_map *, void *, void *);\n\tint (*map_update_elem)(struct bpf_offloaded_map *, void *, void *, u64);\n\tint (*map_delete_elem)(struct bpf_offloaded_map *, void *);\n};\n\nstruct bpf_offloaded_map {\n\tstruct bpf_map map;\n\tstruct net_device *netdev;\n\tconst struct bpf_map_dev_ops *dev_ops;\n\tvoid *dev_priv;\n\tstruct list_head offloads;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct net_device_stats {\n\tlong unsigned int rx_packets;\n\tlong unsigned int tx_packets;\n\tlong unsigned int rx_bytes;\n\tlong unsigned int tx_bytes;\n\tlong unsigned int rx_errors;\n\tlong unsigned int tx_errors;\n\tlong unsigned int rx_dropped;\n\tlong unsigned int tx_dropped;\n\tlong unsigned int multicast;\n\tlong unsigned int collisions;\n\tlong unsigned int rx_length_errors;\n\tlong unsigned int rx_over_errors;\n\tlong unsigned int rx_crc_errors;\n\tlong unsigned int rx_frame_errors;\n\tlong unsigned int rx_fifo_errors;\n\tlong unsigned int rx_missed_errors;\n\tlong unsigned int tx_aborted_errors;\n\tlong unsigned int tx_carrier_errors;\n\tlong unsigned int tx_fifo_errors;\n\tlong unsigned int tx_heartbeat_errors;\n\tlong unsigned int tx_window_errors;\n\tlong unsigned int rx_compressed;\n\tlong unsigned int tx_compressed;\n};\n\nstruct netdev_hw_addr_list {\n\tstruct list_head list;\n\tint count;\n};\n\nstruct tipc_bearer;\n\nstruct mpls_dev;\n\nenum rx_handler_result {\n\tRX_HANDLER_CONSUMED = 0,\n\tRX_HANDLER_ANOTHER = 1,\n\tRX_HANDLER_EXACT = 2,\n\tRX_HANDLER_PASS = 3,\n};\n\ntypedef enum rx_handler_result rx_handler_result_t;\n\ntypedef rx_handler_result_t rx_handler_func_t(struct sk_buff **);\n\nenum netdev_ml_priv_type {\n\tML_PRIV_NONE = 0,\n\tML_PRIV_CAN = 1,\n};\n\nstruct pcpu_dstats;\n\nstruct garp_port;\n\nstruct mrp_port;\n\nstruct netdev_tc_txq {\n\tu16 count;\n\tu16 offset;\n};\n\nstruct macsec_ops;\n\nstruct udp_tunnel_nic;\n\nstruct bpf_xdp_link;\n\nstruct bpf_xdp_entity {\n\tstruct bpf_prog *prog;\n\tstruct bpf_xdp_link *link;\n};\n\nstruct netdev_name_node;\n\nstruct dev_ifalias;\n\nstruct net_device_ops;\n\nstruct iw_handler_def;\n\nstruct iw_public_data;\n\nstruct ethtool_ops;\n\nstruct l3mdev_ops;\n\nstruct ndisc_ops;\n\nstruct xfrmdev_ops;\n\nstruct tlsdev_ops;\n\nstruct header_ops;\n\nstruct vlan_info;\n\nstruct dsa_port;\n\nstruct in_device;\n\nstruct inet6_dev;\n\nstruct wireless_dev;\n\nstruct wpan_dev;\n\nstruct netdev_rx_queue;\n\nstruct mini_Qdisc;\n\nstruct netdev_queue;\n\nstruct cpu_rmap;\n\nstruct Qdisc;\n\nstruct xdp_dev_bulk_queue;\n\nstruct xps_dev_maps;\n\nstruct netpoll_info;\n\nstruct pcpu_lstats;\n\nstruct pcpu_sw_netstats;\n\nstruct rtnl_link_ops;\n\nstruct dcbnl_rtnl_ops;\n\nstruct netprio_map;\n\nstruct phy_device;\n\nstruct sfp_bus;\n\nstruct udp_tunnel_nic_info;\n\nstruct net_device {\n\tchar name[16];\n\tstruct netdev_name_node *name_node;\n\tstruct dev_ifalias *ifalias;\n\tlong unsigned int mem_end;\n\tlong unsigned int mem_start;\n\tlong unsigned int base_addr;\n\tlong unsigned int state;\n\tstruct list_head dev_list;\n\tstruct list_head napi_list;\n\tstruct list_head unreg_list;\n\tstruct list_head close_list;\n\tstruct list_head ptype_all;\n\tstruct list_head ptype_specific;\n\tstruct {\n\t\tstruct list_head upper;\n\t\tstruct list_head lower;\n\t} adj_list;\n\tunsigned int flags;\n\tunsigned int priv_flags;\n\tconst struct net_device_ops *netdev_ops;\n\tint ifindex;\n\tshort unsigned int gflags;\n\tshort unsigned int hard_header_len;\n\tunsigned int mtu;\n\tshort unsigned int needed_headroom;\n\tshort unsigned int needed_tailroom;\n\tnetdev_features_t features;\n\tnetdev_features_t hw_features;\n\tnetdev_features_t wanted_features;\n\tnetdev_features_t vlan_features;\n\tnetdev_features_t hw_enc_features;\n\tnetdev_features_t mpls_features;\n\tnetdev_features_t gso_partial_features;\n\tunsigned int min_mtu;\n\tunsigned int max_mtu;\n\tshort unsigned int type;\n\tunsigned char min_header_len;\n\tunsigned char name_assign_type;\n\tint group;\n\tstruct net_device_stats stats;\n\tatomic_long_t rx_dropped;\n\tatomic_long_t tx_dropped;\n\tatomic_long_t rx_nohandler;\n\tatomic_t carrier_up_count;\n\tatomic_t carrier_down_count;\n\tconst struct iw_handler_def *wireless_handlers;\n\tstruct iw_public_data *wireless_data;\n\tconst struct ethtool_ops *ethtool_ops;\n\tconst struct l3mdev_ops *l3mdev_ops;\n\tconst struct ndisc_ops *ndisc_ops;\n\tconst struct xfrmdev_ops *xfrmdev_ops;\n\tconst struct tlsdev_ops *tlsdev_ops;\n\tconst struct header_ops *header_ops;\n\tunsigned char operstate;\n\tunsigned char link_mode;\n\tunsigned char if_port;\n\tunsigned char dma;\n\tunsigned char perm_addr[32];\n\tunsigned char addr_assign_type;\n\tunsigned char addr_len;\n\tunsigned char upper_level;\n\tunsigned char lower_level;\n\tshort unsigned int neigh_priv_len;\n\tshort unsigned int dev_id;\n\tshort unsigned int dev_port;\n\tshort unsigned int padded;\n\tspinlock_t addr_list_lock;\n\tint irq;\n\tstruct netdev_hw_addr_list uc;\n\tstruct netdev_hw_addr_list mc;\n\tstruct netdev_hw_addr_list dev_addrs;\n\tstruct kset *queues_kset;\n\tunsigned int promiscuity;\n\tunsigned int allmulti;\n\tbool uc_promisc;\n\tstruct vlan_info *vlan_info;\n\tstruct dsa_port *dsa_ptr;\n\tstruct tipc_bearer *tipc_ptr;\n\tvoid *atalk_ptr;\n\tstruct in_device *ip_ptr;\n\tstruct inet6_dev *ip6_ptr;\n\tvoid *ax25_ptr;\n\tstruct wireless_dev *ieee80211_ptr;\n\tstruct wpan_dev *ieee802154_ptr;\n\tstruct mpls_dev *mpls_ptr;\n\tunsigned char *dev_addr;\n\tstruct netdev_rx_queue *_rx;\n\tunsigned int num_rx_queues;\n\tunsigned int real_num_rx_queues;\n\tstruct bpf_prog *xdp_prog;\n\tlong unsigned int gro_flush_timeout;\n\tint napi_defer_hard_irqs;\n\trx_handler_func_t *rx_handler;\n\tvoid *rx_handler_data;\n\tstruct mini_Qdisc *miniq_ingress;\n\tstruct netdev_queue *ingress_queue;\n\tstruct nf_hook_entries *nf_hooks_ingress;\n\tunsigned char broadcast[32];\n\tstruct cpu_rmap *rx_cpu_rmap;\n\tstruct hlist_node index_hlist;\n\tlong: 64;\n\tstruct netdev_queue *_tx;\n\tunsigned int num_tx_queues;\n\tunsigned int real_num_tx_queues;\n\tstruct Qdisc *qdisc;\n\tunsigned int tx_queue_len;\n\tspinlock_t tx_global_lock;\n\tstruct xdp_dev_bulk_queue *xdp_bulkq;\n\tstruct xps_dev_maps *xps_maps[2];\n\tstruct mini_Qdisc *miniq_egress;\n\tstruct hlist_head qdisc_hash[16];\n\tstruct timer_list watchdog_timer;\n\tint watchdog_timeo;\n\tu32 proto_down_reason;\n\tstruct list_head todo_list;\n\tint *pcpu_refcnt;\n\tstruct list_head link_watch_list;\n\tenum {\n\t\tNETREG_UNINITIALIZED = 0,\n\t\tNETREG_REGISTERED = 1,\n\t\tNETREG_UNREGISTERING = 2,\n\t\tNETREG_UNREGISTERED = 3,\n\t\tNETREG_RELEASED = 4,\n\t\tNETREG_DUMMY = 5,\n\t} reg_state: 8;\n\tbool dismantle;\n\tenum {\n\t\tRTNL_LINK_INITIALIZED = 0,\n\t\tRTNL_LINK_INITIALIZING = 1,\n\t} rtnl_link_state: 16;\n\tbool needs_free_netdev;\n\tvoid (*priv_destructor)(struct net_device *);\n\tstruct netpoll_info *npinfo;\n\tpossible_net_t nd_net;\n\tvoid *ml_priv;\n\tenum netdev_ml_priv_type ml_priv_type;\n\tunion {\n\t\tstruct pcpu_lstats *lstats;\n\t\tstruct pcpu_sw_netstats *tstats;\n\t\tstruct pcpu_dstats *dstats;\n\t};\n\tstruct garp_port *garp_port;\n\tstruct mrp_port *mrp_port;\n\tstruct device dev;\n\tconst struct attribute_group *sysfs_groups[4];\n\tconst struct attribute_group *sysfs_rx_queue_group;\n\tconst struct rtnl_link_ops *rtnl_link_ops;\n\tunsigned int gso_max_size;\n\tu16 gso_max_segs;\n\tconst struct dcbnl_rtnl_ops *dcbnl_ops;\n\ts16 num_tc;\n\tstruct netdev_tc_txq tc_to_txq[16];\n\tu8 prio_tc_map[16];\n\tunsigned int fcoe_ddp_xid;\n\tstruct netprio_map *priomap;\n\tstruct phy_device *phydev;\n\tstruct sfp_bus *sfp_bus;\n\tstruct lock_class_key *qdisc_tx_busylock;\n\tstruct lock_class_key *qdisc_running_key;\n\tbool proto_down;\n\tunsigned int wol_enabled: 1;\n\tunsigned int threaded: 1;\n\tstruct list_head net_notifier_list;\n\tconst struct macsec_ops *macsec_ops;\n\tconst struct udp_tunnel_nic_info *udp_tunnel_nic_info;\n\tstruct udp_tunnel_nic *udp_tunnel_nic;\n\tstruct bpf_xdp_entity xdp_state[3];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum bpf_reg_type {\n\tNOT_INIT = 0,\n\tSCALAR_VALUE = 1,\n\tPTR_TO_CTX = 2,\n\tCONST_PTR_TO_MAP = 3,\n\tPTR_TO_MAP_VALUE = 4,\n\tPTR_TO_MAP_VALUE_OR_NULL = 5,\n\tPTR_TO_STACK = 6,\n\tPTR_TO_PACKET_META = 7,\n\tPTR_TO_PACKET = 8,\n\tPTR_TO_PACKET_END = 9,\n\tPTR_TO_FLOW_KEYS = 10,\n\tPTR_TO_SOCKET = 11,\n\tPTR_TO_SOCKET_OR_NULL = 12,\n\tPTR_TO_SOCK_COMMON = 13,\n\tPTR_TO_SOCK_COMMON_OR_NULL = 14,\n\tPTR_TO_TCP_SOCK = 15,\n\tPTR_TO_TCP_SOCK_OR_NULL = 16,\n\tPTR_TO_TP_BUFFER = 17,\n\tPTR_TO_XDP_SOCK = 18,\n\tPTR_TO_BTF_ID = 19,\n\tPTR_TO_BTF_ID_OR_NULL = 20,\n\tPTR_TO_MEM = 21,\n\tPTR_TO_MEM_OR_NULL = 22,\n\tPTR_TO_RDONLY_BUF = 23,\n\tPTR_TO_RDONLY_BUF_OR_NULL = 24,\n\tPTR_TO_RDWR_BUF = 25,\n\tPTR_TO_RDWR_BUF_OR_NULL = 26,\n\tPTR_TO_PERCPU_BTF_ID = 27,\n\tPTR_TO_FUNC = 28,\n\tPTR_TO_MAP_KEY = 29,\n\t__BPF_REG_TYPE_MAX = 30,\n};\n\nstruct bpf_prog_ops {\n\tint (*test_run)(struct bpf_prog *, const union bpf_attr *, union bpf_attr *);\n};\n\nstruct bpf_offload_dev;\n\nstruct bpf_prog_offload {\n\tstruct bpf_prog *prog;\n\tstruct net_device *netdev;\n\tstruct bpf_offload_dev *offdev;\n\tvoid *dev_priv;\n\tstruct list_head offloads;\n\tbool dev_state;\n\tbool opt_failed;\n\tvoid *jited_image;\n\tu32 jited_len;\n};\n\nstruct btf_func_model {\n\tu8 ret_size;\n\tu8 nr_args;\n\tu8 arg_size[12];\n};\n\nstruct bpf_tramp_image {\n\tvoid *image;\n\tstruct bpf_ksym ksym;\n\tstruct percpu_ref pcref;\n\tvoid *ip_after_call;\n\tvoid *ip_epilogue;\n\tunion {\n\t\tstruct callback_head rcu;\n\t\tstruct work_struct work;\n\t};\n};\n\nstruct bpf_trampoline {\n\tstruct hlist_node hlist;\n\tstruct mutex mutex;\n\trefcount_t refcnt;\n\tu64 key;\n\tstruct {\n\t\tstruct btf_func_model model;\n\t\tvoid *addr;\n\t\tbool ftrace_managed;\n\t} func;\n\tstruct bpf_prog *extension_prog;\n\tstruct hlist_head progs_hlist[3];\n\tint progs_cnt[3];\n\tstruct bpf_tramp_image *cur_image;\n\tu64 selector;\n\tstruct module *mod;\n};\n\nstruct bpf_func_info_aux {\n\tu16 linkage;\n\tbool unreliable;\n};\n\nstruct bpf_jit_poke_descriptor {\n\tvoid *tailcall_target;\n\tvoid *tailcall_bypass;\n\tvoid *bypass_addr;\n\tvoid *aux;\n\tunion {\n\t\tstruct {\n\t\t\tstruct bpf_map *map;\n\t\t\tu32 key;\n\t\t} tail_call;\n\t};\n\tbool tailcall_target_stable;\n\tu8 adj_off;\n\tu16 reason;\n\tu32 insn_idx;\n};\n\nstruct bpf_ctx_arg_aux {\n\tu32 offset;\n\tenum bpf_reg_type reg_type;\n\tu32 btf_id;\n};\n\nstruct btf_mod_pair {\n\tstruct btf *btf;\n\tstruct module *module;\n};\n\ntypedef unsigned int sk_buff_data_t;\n\nstruct skb_ext;\n\nstruct sk_buff {\n\tunion {\n\t\tstruct {\n\t\t\tstruct sk_buff *next;\n\t\t\tstruct sk_buff *prev;\n\t\t\tunion {\n\t\t\t\tstruct net_device *dev;\n\t\t\t\tlong unsigned int dev_scratch;\n\t\t\t};\n\t\t};\n\t\tstruct rb_node rbnode;\n\t\tstruct list_head list;\n\t};\n\tunion {\n\t\tstruct sock *sk;\n\t\tint ip_defrag_offset;\n\t};\n\tunion {\n\t\tktime_t tstamp;\n\t\tu64 skb_mstamp_ns;\n\t};\n\tchar cb[48];\n\tunion {\n\t\tstruct {\n\t\t\tlong unsigned int _skb_refdst;\n\t\t\tvoid (*destructor)(struct sk_buff *);\n\t\t};\n\t\tstruct list_head tcp_tsorted_anchor;\n\t\tlong unsigned int _sk_redir;\n\t};\n\tlong unsigned int _nfct;\n\tunsigned int len;\n\tunsigned int data_len;\n\t__u16 mac_len;\n\t__u16 hdr_len;\n\t__u16 queue_mapping;\n\t__u8 __cloned_offset[0];\n\t__u8 cloned: 1;\n\t__u8 nohdr: 1;\n\t__u8 fclone: 2;\n\t__u8 peeked: 1;\n\t__u8 head_frag: 1;\n\t__u8 pfmemalloc: 1;\n\t__u8 pp_recycle: 1;\n\t__u8 active_extensions;\n\t__u32 headers_start[0];\n\t__u8 __pkt_type_offset[0];\n\t__u8 pkt_type: 3;\n\t__u8 ignore_df: 1;\n\t__u8 nf_trace: 1;\n\t__u8 ip_summed: 2;\n\t__u8 ooo_okay: 1;\n\t__u8 l4_hash: 1;\n\t__u8 sw_hash: 1;\n\t__u8 wifi_acked_valid: 1;\n\t__u8 wifi_acked: 1;\n\t__u8 no_fcs: 1;\n\t__u8 encapsulation: 1;\n\t__u8 encap_hdr_csum: 1;\n\t__u8 csum_valid: 1;\n\t__u8 __pkt_vlan_present_offset[0];\n\t__u8 vlan_present: 1;\n\t__u8 csum_complete_sw: 1;\n\t__u8 csum_level: 2;\n\t__u8 csum_not_inet: 1;\n\t__u8 dst_pending_confirm: 1;\n\t__u8 ndisc_nodetype: 2;\n\t__u8 ipvs_property: 1;\n\t__u8 inner_protocol_type: 1;\n\t__u8 remcsum_offload: 1;\n\t__u8 offload_fwd_mark: 1;\n\t__u8 offload_l3_fwd_mark: 1;\n\t__u8 tc_skip_classify: 1;\n\t__u8 tc_at_ingress: 1;\n\t__u8 redirected: 1;\n\t__u8 from_ingress: 1;\n\t__u8 decrypted: 1;\n\t__u16 tc_index;\n\tunion {\n\t\t__wsum csum;\n\t\tstruct {\n\t\t\t__u16 csum_start;\n\t\t\t__u16 csum_offset;\n\t\t};\n\t};\n\t__u32 priority;\n\tint skb_iif;\n\t__u32 hash;\n\t__be16 vlan_proto;\n\t__u16 vlan_tci;\n\tunion {\n\t\tunsigned int napi_id;\n\t\tunsigned int sender_cpu;\n\t};\n\t__u32 secmark;\n\tunion {\n\t\t__u32 mark;\n\t\t__u32 reserved_tailroom;\n\t};\n\tunion {\n\t\t__be16 inner_protocol;\n\t\t__u8 inner_ipproto;\n\t};\n\t__u16 inner_transport_header;\n\t__u16 inner_network_header;\n\t__u16 inner_mac_header;\n\t__be16 protocol;\n\t__u16 transport_header;\n\t__u16 network_header;\n\t__u16 mac_header;\n\t__u32 headers_end[0];\n\tsk_buff_data_t tail;\n\tsk_buff_data_t end;\n\tunsigned char *head;\n\tunsigned char *data;\n\tunsigned int truesize;\n\trefcount_t users;\n\tstruct skb_ext *extensions;\n};\n\nstruct scatterlist {\n\tlong unsigned int page_link;\n\tunsigned int offset;\n\tunsigned int length;\n\tdma_addr_t dma_address;\n\tunsigned int dma_length;\n};\n\nenum {\n\tRoot_NFS = 255,\n\tRoot_CIFS = 254,\n\tRoot_RAM0 = 1048576,\n\tRoot_RAM1 = 1048577,\n\tRoot_FD0 = 2097152,\n\tRoot_HDA1 = 3145729,\n\tRoot_HDA2 = 3145730,\n\tRoot_SDA1 = 8388609,\n\tRoot_SDA2 = 8388610,\n\tRoot_HDC1 = 23068673,\n\tRoot_SR0 = 11534336,\n};\n\nstruct flowi_tunnel {\n\t__be64 tun_id;\n};\n\nstruct flowi_common {\n\tint flowic_oif;\n\tint flowic_iif;\n\t__u32 flowic_mark;\n\t__u8 flowic_tos;\n\t__u8 flowic_scope;\n\t__u8 flowic_proto;\n\t__u8 flowic_flags;\n\t__u32 flowic_secid;\n\tkuid_t flowic_uid;\n\tstruct flowi_tunnel flowic_tun_key;\n\t__u32 flowic_multipath_hash;\n};\n\nunion flowi_uli {\n\tstruct {\n\t\t__be16 dport;\n\t\t__be16 sport;\n\t} ports;\n\tstruct {\n\t\t__u8 type;\n\t\t__u8 code;\n\t} icmpt;\n\tstruct {\n\t\t__le16 dport;\n\t\t__le16 sport;\n\t} dnports;\n\t__be32 gre_key;\n\tstruct {\n\t\t__u8 type;\n\t} mht;\n};\n\nstruct flowi4 {\n\tstruct flowi_common __fl_common;\n\t__be32 saddr;\n\t__be32 daddr;\n\tunion flowi_uli uli;\n};\n\nstruct flowi6 {\n\tstruct flowi_common __fl_common;\n\tstruct in6_addr daddr;\n\tstruct in6_addr saddr;\n\t__be32 flowlabel;\n\tunion flowi_uli uli;\n\t__u32 mp_hash;\n};\n\nstruct flowidn {\n\tstruct flowi_common __fl_common;\n\t__le16 daddr;\n\t__le16 saddr;\n\tunion flowi_uli uli;\n};\n\nstruct flowi {\n\tunion {\n\t\tstruct flowi_common __fl_common;\n\t\tstruct flowi4 ip4;\n\t\tstruct flowi6 ip6;\n\t\tstruct flowidn dn;\n\t} u;\n};\n\nstruct ipstats_mib {\n\tu64 mibs[37];\n\tstruct u64_stats_sync syncp;\n};\n\nstruct icmp_mib {\n\tlong unsigned int mibs[28];\n};\n\nstruct icmpmsg_mib {\n\tatomic_long_t mibs[512];\n};\n\nstruct icmpv6_mib {\n\tlong unsigned int mibs[6];\n};\n\nstruct icmpv6_mib_device {\n\tatomic_long_t mibs[6];\n};\n\nstruct icmpv6msg_mib {\n\tatomic_long_t mibs[512];\n};\n\nstruct icmpv6msg_mib_device {\n\tatomic_long_t mibs[512];\n};\n\nstruct tcp_mib {\n\tlong unsigned int mibs[16];\n};\n\nstruct udp_mib {\n\tlong unsigned int mibs[10];\n};\n\nstruct linux_mib {\n\tlong unsigned int mibs[126];\n};\n\nstruct linux_xfrm_mib {\n\tlong unsigned int mibs[29];\n};\n\nstruct linux_tls_mib {\n\tlong unsigned int mibs[11];\n};\n\nstruct inet_frags;\n\nstruct fqdir {\n\tlong int high_thresh;\n\tlong int low_thresh;\n\tint timeout;\n\tint max_dist;\n\tstruct inet_frags *f;\n\tstruct net *net;\n\tbool dead;\n\tlong: 56;\n\tlong: 64;\n\tlong: 64;\n\tstruct rhashtable rhashtable;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tatomic_long_t mem;\n\tstruct work_struct destroy_work;\n\tstruct llist_node free_list;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct inet_frag_queue;\n\nstruct inet_frags {\n\tunsigned int qsize;\n\tvoid (*constructor)(struct inet_frag_queue *, const void *);\n\tvoid (*destructor)(struct inet_frag_queue *);\n\tvoid (*frag_expire)(struct timer_list *);\n\tstruct kmem_cache *frags_cachep;\n\tconst char *frags_cache_name;\n\tstruct rhashtable_params rhash_params;\n\trefcount_t refcnt;\n\tstruct completion completion;\n};\n\nstruct frag_v4_compare_key {\n\t__be32 saddr;\n\t__be32 daddr;\n\tu32 user;\n\tu32 vif;\n\t__be16 id;\n\tu16 protocol;\n};\n\nstruct frag_v6_compare_key {\n\tstruct in6_addr saddr;\n\tstruct in6_addr daddr;\n\tu32 user;\n\t__be32 id;\n\tu32 iif;\n};\n\nstruct inet_frag_queue {\n\tstruct rhash_head node;\n\tunion {\n\t\tstruct frag_v4_compare_key v4;\n\t\tstruct frag_v6_compare_key v6;\n\t} key;\n\tstruct timer_list timer;\n\tspinlock_t lock;\n\trefcount_t refcnt;\n\tstruct rb_root rb_fragments;\n\tstruct sk_buff *fragments_tail;\n\tstruct sk_buff *last_run_head;\n\tktime_t stamp;\n\tint len;\n\tint meat;\n\t__u8 flags;\n\tu16 max_size;\n\tstruct fqdir *fqdir;\n\tstruct callback_head rcu;\n};\n\nstruct fib_rule;\n\nstruct fib_lookup_arg;\n\nstruct fib_rule_hdr;\n\nstruct nlattr;\n\nstruct netlink_ext_ack;\n\nstruct nla_policy;\n\nstruct fib_rules_ops {\n\tint family;\n\tstruct list_head list;\n\tint rule_size;\n\tint addr_size;\n\tint unresolved_rules;\n\tint nr_goto_rules;\n\tunsigned int fib_rules_seq;\n\tint (*action)(struct fib_rule *, struct flowi *, int, struct fib_lookup_arg *);\n\tbool (*suppress)(struct fib_rule *, struct fib_lookup_arg *);\n\tint (*match)(struct fib_rule *, struct flowi *, int);\n\tint (*configure)(struct fib_rule *, struct sk_buff *, struct fib_rule_hdr *, struct nlattr **, struct netlink_ext_ack *);\n\tint (*delete)(struct fib_rule *);\n\tint (*compare)(struct fib_rule *, struct fib_rule_hdr *, struct nlattr **);\n\tint (*fill)(struct fib_rule *, struct sk_buff *, struct fib_rule_hdr *);\n\tsize_t (*nlmsg_payload)(struct fib_rule *);\n\tvoid (*flush_cache)(struct fib_rules_ops *);\n\tint nlgroup;\n\tconst struct nla_policy *policy;\n\tstruct list_head rules_list;\n\tstruct module *owner;\n\tstruct net *fro_net;\n\tstruct callback_head rcu;\n};\n\nenum tcp_ca_event {\n\tCA_EVENT_TX_START = 0,\n\tCA_EVENT_CWND_RESTART = 1,\n\tCA_EVENT_COMPLETE_CWR = 2,\n\tCA_EVENT_LOSS = 3,\n\tCA_EVENT_ECN_NO_CE = 4,\n\tCA_EVENT_ECN_IS_CE = 5,\n};\n\nstruct ack_sample;\n\nstruct rate_sample;\n\nunion tcp_cc_info;\n\nstruct tcp_congestion_ops {\n\tu32 (*ssthresh)(struct sock *);\n\tvoid (*cong_avoid)(struct sock *, u32, u32);\n\tvoid (*set_state)(struct sock *, u8);\n\tvoid (*cwnd_event)(struct sock *, enum tcp_ca_event);\n\tvoid (*in_ack_event)(struct sock *, u32);\n\tvoid (*pkts_acked)(struct sock *, const struct ack_sample *);\n\tu32 (*min_tso_segs)(struct sock *);\n\tvoid (*cong_control)(struct sock *, const struct rate_sample *);\n\tu32 (*undo_cwnd)(struct sock *);\n\tu32 (*sndbuf_expand)(struct sock *);\n\tsize_t (*get_info)(struct sock *, u32, int *, union tcp_cc_info *);\n\tchar name[16];\n\tstruct module *owner;\n\tstruct list_head list;\n\tu32 key;\n\tu32 flags;\n\tvoid (*init)(struct sock *);\n\tvoid (*release)(struct sock *);\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct fib_notifier_ops {\n\tint family;\n\tstruct list_head list;\n\tunsigned int (*fib_seq_read)(struct net *);\n\tint (*fib_dump)(struct net *, struct notifier_block *, struct netlink_ext_ack *);\n\tstruct module *owner;\n\tstruct callback_head rcu;\n};\n\nstruct xfrm_state;\n\nstruct lwtunnel_state;\n\nstruct dst_entry {\n\tstruct net_device *dev;\n\tstruct dst_ops *ops;\n\tlong unsigned int _metrics;\n\tlong unsigned int expires;\n\tstruct xfrm_state *xfrm;\n\tint (*input)(struct sk_buff *);\n\tint (*output)(struct net *, struct sock *, struct sk_buff *);\n\tshort unsigned int flags;\n\tshort int obsolete;\n\tshort unsigned int header_len;\n\tshort unsigned int trailer_len;\n\tatomic_t __refcnt;\n\tint __use;\n\tlong unsigned int lastuse;\n\tstruct lwtunnel_state *lwtstate;\n\tstruct callback_head callback_head;\n\tshort int error;\n\tshort int __pad;\n\t__u32 tclassid;\n};\n\nstruct hh_cache {\n\tunsigned int hh_len;\n\tseqlock_t hh_lock;\n\tlong unsigned int hh_data[16];\n};\n\nstruct neigh_table;\n\nstruct neigh_parms;\n\nstruct neigh_ops;\n\nstruct neighbour {\n\tstruct neighbour *next;\n\tstruct neigh_table *tbl;\n\tstruct neigh_parms *parms;\n\tlong unsigned int confirmed;\n\tlong unsigned int updated;\n\trwlock_t lock;\n\trefcount_t refcnt;\n\tunsigned int arp_queue_len_bytes;\n\tstruct sk_buff_head arp_queue;\n\tstruct timer_list timer;\n\tlong unsigned int used;\n\tatomic_t probes;\n\t__u8 flags;\n\t__u8 nud_state;\n\t__u8 type;\n\t__u8 dead;\n\tu8 protocol;\n\tseqlock_t ha_lock;\n\tint: 32;\n\tunsigned char ha[32];\n\tstruct hh_cache hh;\n\tint (*output)(struct neighbour *, struct sk_buff *);\n\tconst struct neigh_ops *ops;\n\tstruct list_head gc_list;\n\tstruct callback_head rcu;\n\tstruct net_device *dev;\n\tu8 primary_key[0];\n};\n\nstruct ipv6_stable_secret {\n\tbool initialized;\n\tstruct in6_addr secret;\n};\n\nstruct ipv6_devconf {\n\t__s32 forwarding;\n\t__s32 hop_limit;\n\t__s32 mtu6;\n\t__s32 accept_ra;\n\t__s32 accept_redirects;\n\t__s32 autoconf;\n\t__s32 dad_transmits;\n\t__s32 rtr_solicits;\n\t__s32 rtr_solicit_interval;\n\t__s32 rtr_solicit_max_interval;\n\t__s32 rtr_solicit_delay;\n\t__s32 force_mld_version;\n\t__s32 mldv1_unsolicited_report_interval;\n\t__s32 mldv2_unsolicited_report_interval;\n\t__s32 use_tempaddr;\n\t__s32 temp_valid_lft;\n\t__s32 temp_prefered_lft;\n\t__s32 regen_max_retry;\n\t__s32 max_desync_factor;\n\t__s32 max_addresses;\n\t__s32 accept_ra_defrtr;\n\t__u32 ra_defrtr_metric;\n\t__s32 accept_ra_min_hop_limit;\n\t__s32 accept_ra_pinfo;\n\t__s32 ignore_routes_with_linkdown;\n\t__s32 accept_ra_rtr_pref;\n\t__s32 rtr_probe_interval;\n\t__s32 accept_ra_rt_info_min_plen;\n\t__s32 accept_ra_rt_info_max_plen;\n\t__s32 proxy_ndp;\n\t__s32 accept_source_route;\n\t__s32 accept_ra_from_local;\n\t__s32 optimistic_dad;\n\t__s32 use_optimistic;\n\t__s32 mc_forwarding;\n\t__s32 disable_ipv6;\n\t__s32 drop_unicast_in_l2_multicast;\n\t__s32 accept_dad;\n\t__s32 force_tllao;\n\t__s32 ndisc_notify;\n\t__s32 suppress_frag_ndisc;\n\t__s32 accept_ra_mtu;\n\t__s32 drop_unsolicited_na;\n\tstruct ipv6_stable_secret stable_secret;\n\t__s32 use_oif_addrs_only;\n\t__s32 keep_addr_on_down;\n\t__s32 seg6_enabled;\n\t__s32 seg6_require_hmac;\n\t__u32 enhanced_dad;\n\t__u32 addr_gen_mode;\n\t__s32 disable_policy;\n\t__s32 ndisc_tclass;\n\t__s32 rpl_seg_enabled;\n\tstruct ctl_table_header *sysctl_header;\n};\n\nstruct nf_queue_entry;\n\nstruct nf_queue_handler {\n\tint (*outfn)(struct nf_queue_entry *, unsigned int);\n\tvoid (*nf_hook_drop)(struct net *);\n};\n\nenum nf_log_type {\n\tNF_LOG_TYPE_LOG = 0,\n\tNF_LOG_TYPE_ULOG = 1,\n\tNF_LOG_TYPE_MAX = 2,\n};\n\ntypedef u8 u_int8_t;\n\nstruct nf_loginfo;\n\ntypedef void nf_logfn(struct net *, u_int8_t, unsigned int, const struct sk_buff *, const struct net_device *, const struct net_device *, const struct nf_loginfo *, const char *);\n\nstruct nf_logger {\n\tchar *name;\n\tenum nf_log_type type;\n\tnf_logfn *logfn;\n\tstruct module *me;\n};\n\nstruct hlist_nulls_head {\n\tstruct hlist_nulls_node *first;\n};\n\nstruct ip_conntrack_stat {\n\tunsigned int found;\n\tunsigned int invalid;\n\tunsigned int insert;\n\tunsigned int insert_failed;\n\tunsigned int clash_resolve;\n\tunsigned int drop;\n\tunsigned int early_drop;\n\tunsigned int error;\n\tunsigned int expect_new;\n\tunsigned int expect_create;\n\tunsigned int expect_delete;\n\tunsigned int search_restart;\n};\n\nstruct ct_pcpu {\n\tspinlock_t lock;\n\tstruct hlist_nulls_head unconfirmed;\n\tstruct hlist_nulls_head dying;\n};\n\ntypedef enum {\n\tSS_FREE = 0,\n\tSS_UNCONNECTED = 1,\n\tSS_CONNECTING = 2,\n\tSS_CONNECTED = 3,\n\tSS_DISCONNECTING = 4,\n} socket_state;\n\nstruct socket_wq {\n\twait_queue_head_t wait;\n\tstruct fasync_struct *fasync_list;\n\tlong unsigned int flags;\n\tstruct callback_head rcu;\n\tlong: 64;\n};\n\nstruct proto_ops;\n\nstruct socket {\n\tsocket_state state;\n\tshort int type;\n\tlong unsigned int flags;\n\tstruct file *file;\n\tstruct sock *sk;\n\tconst struct proto_ops *ops;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct socket_wq wq;\n};\n\ntypedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, unsigned int, size_t);\n\nstruct proto_ops {\n\tint family;\n\tstruct module *owner;\n\tint (*release)(struct socket *);\n\tint (*bind)(struct socket *, struct sockaddr *, int);\n\tint (*connect)(struct socket *, struct sockaddr *, int, int);\n\tint (*socketpair)(struct socket *, struct socket *);\n\tint (*accept)(struct socket *, struct socket *, int, bool);\n\tint (*getname)(struct socket *, struct sockaddr *, int);\n\t__poll_t (*poll)(struct file *, struct socket *, struct poll_table_struct *);\n\tint (*ioctl)(struct socket *, unsigned int, long unsigned int);\n\tint (*compat_ioctl)(struct socket *, unsigned int, long unsigned int);\n\tint (*gettstamp)(struct socket *, void *, bool, bool);\n\tint (*listen)(struct socket *, int);\n\tint (*shutdown)(struct socket *, int);\n\tint (*setsockopt)(struct socket *, int, int, sockptr_t, unsigned int);\n\tint (*getsockopt)(struct socket *, int, int, char *, int *);\n\tvoid (*show_fdinfo)(struct seq_file *, struct socket *);\n\tint (*sendmsg)(struct socket *, struct msghdr *, size_t);\n\tint (*recvmsg)(struct socket *, struct msghdr *, size_t, int);\n\tint (*mmap)(struct file *, struct socket *, struct vm_area_struct *);\n\tssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);\n\tssize_t (*splice_read)(struct socket *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);\n\tint (*set_peek_off)(struct sock *, int);\n\tint (*peek_len)(struct socket *);\n\tint (*read_sock)(struct sock *, read_descriptor_t *, sk_read_actor_t);\n\tint (*sendpage_locked)(struct sock *, struct page *, int, size_t, int);\n\tint (*sendmsg_locked)(struct sock *, struct msghdr *, size_t);\n\tint (*set_rcvlowat)(struct sock *, int);\n};\n\nstruct pipe_buf_operations;\n\nstruct pipe_buffer {\n\tstruct page *page;\n\tunsigned int offset;\n\tunsigned int len;\n\tconst struct pipe_buf_operations *ops;\n\tunsigned int flags;\n\tlong unsigned int private;\n};\n\nstruct pipe_buf_operations {\n\tint (*confirm)(struct pipe_inode_info *, struct pipe_buffer *);\n\tvoid (*release)(struct pipe_inode_info *, struct pipe_buffer *);\n\tbool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);\n\tbool (*get)(struct pipe_inode_info *, struct pipe_buffer *);\n};\n\nstruct skb_ext {\n\trefcount_t refcnt;\n\tu8 offset[4];\n\tu8 chunks;\n\tlong: 56;\n\tchar data[0];\n};\n\nstruct dql {\n\tunsigned int num_queued;\n\tunsigned int adj_limit;\n\tunsigned int last_obj_cnt;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tunsigned int limit;\n\tunsigned int num_completed;\n\tunsigned int prev_ovlimit;\n\tunsigned int prev_num_queued;\n\tunsigned int prev_last_obj_cnt;\n\tunsigned int lowest_slack;\n\tlong unsigned int slack_start_time;\n\tunsigned int max_limit;\n\tunsigned int min_limit;\n\tunsigned int slack_hold_time;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct ieee_ets {\n\t__u8 willing;\n\t__u8 ets_cap;\n\t__u8 cbs;\n\t__u8 tc_tx_bw[8];\n\t__u8 tc_rx_bw[8];\n\t__u8 tc_tsa[8];\n\t__u8 prio_tc[8];\n\t__u8 tc_reco_bw[8];\n\t__u8 tc_reco_tsa[8];\n\t__u8 reco_prio_tc[8];\n};\n\nstruct ieee_maxrate {\n\t__u64 tc_maxrate[8];\n};\n\nstruct ieee_qcn {\n\t__u8 rpg_enable[8];\n\t__u32 rppp_max_rps[8];\n\t__u32 rpg_time_reset[8];\n\t__u32 rpg_byte_reset[8];\n\t__u32 rpg_threshold[8];\n\t__u32 rpg_max_rate[8];\n\t__u32 rpg_ai_rate[8];\n\t__u32 rpg_hai_rate[8];\n\t__u32 rpg_gd[8];\n\t__u32 rpg_min_dec_fac[8];\n\t__u32 rpg_min_rate[8];\n\t__u32 cndd_state_machine[8];\n};\n\nstruct ieee_qcn_stats {\n\t__u64 rppp_rp_centiseconds[8];\n\t__u32 rppp_created_rps[8];\n};\n\nstruct ieee_pfc {\n\t__u8 pfc_cap;\n\t__u8 pfc_en;\n\t__u8 mbc;\n\t__u16 delay;\n\t__u64 requests[8];\n\t__u64 indications[8];\n};\n\nstruct dcbnl_buffer {\n\t__u8 prio2buffer[8];\n\t__u32 buffer_size[8];\n\t__u32 total_size;\n};\n\nstruct cee_pg {\n\t__u8 willing;\n\t__u8 error;\n\t__u8 pg_en;\n\t__u8 tcs_supported;\n\t__u8 pg_bw[8];\n\t__u8 prio_pg[8];\n};\n\nstruct cee_pfc {\n\t__u8 willing;\n\t__u8 error;\n\t__u8 pfc_en;\n\t__u8 tcs_supported;\n};\n\nstruct dcb_app {\n\t__u8 selector;\n\t__u8 priority;\n\t__u16 protocol;\n};\n\nstruct dcb_peer_app_info {\n\t__u8 willing;\n\t__u8 error;\n};\n\nstruct dcbnl_rtnl_ops {\n\tint (*ieee_getets)(struct net_device *, struct ieee_ets *);\n\tint (*ieee_setets)(struct net_device *, struct ieee_ets *);\n\tint (*ieee_getmaxrate)(struct net_device *, struct ieee_maxrate *);\n\tint (*ieee_setmaxrate)(struct net_device *, struct ieee_maxrate *);\n\tint (*ieee_getqcn)(struct net_device *, struct ieee_qcn *);\n\tint (*ieee_setqcn)(struct net_device *, struct ieee_qcn *);\n\tint (*ieee_getqcnstats)(struct net_device *, struct ieee_qcn_stats *);\n\tint (*ieee_getpfc)(struct net_device *, struct ieee_pfc *);\n\tint (*ieee_setpfc)(struct net_device *, struct ieee_pfc *);\n\tint (*ieee_getapp)(struct net_device *, struct dcb_app *);\n\tint (*ieee_setapp)(struct net_device *, struct dcb_app *);\n\tint (*ieee_delapp)(struct net_device *, struct dcb_app *);\n\tint (*ieee_peer_getets)(struct net_device *, struct ieee_ets *);\n\tint (*ieee_peer_getpfc)(struct net_device *, struct ieee_pfc *);\n\tu8 (*getstate)(struct net_device *);\n\tu8 (*setstate)(struct net_device *, u8);\n\tvoid (*getpermhwaddr)(struct net_device *, u8 *);\n\tvoid (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8);\n\tvoid (*setpgbwgcfgtx)(struct net_device *, int, u8);\n\tvoid (*setpgtccfgrx)(struct net_device *, int, u8, u8, u8, u8);\n\tvoid (*setpgbwgcfgrx)(struct net_device *, int, u8);\n\tvoid (*getpgtccfgtx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *);\n\tvoid (*getpgbwgcfgtx)(struct net_device *, int, u8 *);\n\tvoid (*getpgtccfgrx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *);\n\tvoid (*getpgbwgcfgrx)(struct net_device *, int, u8 *);\n\tvoid (*setpfccfg)(struct net_device *, int, u8);\n\tvoid (*getpfccfg)(struct net_device *, int, u8 *);\n\tu8 (*setall)(struct net_device *);\n\tu8 (*getcap)(struct net_device *, int, u8 *);\n\tint (*getnumtcs)(struct net_device *, int, u8 *);\n\tint (*setnumtcs)(struct net_device *, int, u8);\n\tu8 (*getpfcstate)(struct net_device *);\n\tvoid (*setpfcstate)(struct net_device *, u8);\n\tvoid (*getbcncfg)(struct net_device *, int, u32 *);\n\tvoid (*setbcncfg)(struct net_device *, int, u32);\n\tvoid (*getbcnrp)(struct net_device *, int, u8 *);\n\tvoid (*setbcnrp)(struct net_device *, int, u8);\n\tint (*setapp)(struct net_device *, u8, u16, u8);\n\tint (*getapp)(struct net_device *, u8, u16);\n\tu8 (*getfeatcfg)(struct net_device *, int, u8 *);\n\tu8 (*setfeatcfg)(struct net_device *, int, u8);\n\tu8 (*getdcbx)(struct net_device *);\n\tu8 (*setdcbx)(struct net_device *, u8);\n\tint (*peer_getappinfo)(struct net_device *, struct dcb_peer_app_info *, u16 *);\n\tint (*peer_getapptable)(struct net_device *, struct dcb_app *);\n\tint (*cee_peer_getpg)(struct net_device *, struct cee_pg *);\n\tint (*cee_peer_getpfc)(struct net_device *, struct cee_pfc *);\n\tint (*dcbnl_getbuffer)(struct net_device *, struct dcbnl_buffer *);\n\tint (*dcbnl_setbuffer)(struct net_device *, struct dcbnl_buffer *);\n};\n\nstruct netprio_map {\n\tstruct callback_head rcu;\n\tu32 priomap_len;\n\tu32 priomap[0];\n};\n\nstruct xdp_mem_info {\n\tu32 type;\n\tu32 id;\n};\n\nstruct xdp_rxq_info {\n\tstruct net_device *dev;\n\tu32 queue_index;\n\tu32 reg_state;\n\tstruct xdp_mem_info mem;\n\tunsigned int napi_id;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct xdp_frame {\n\tvoid *data;\n\tu16 len;\n\tu16 headroom;\n\tu32 metasize: 8;\n\tu32 frame_sz: 24;\n\tstruct xdp_mem_info mem;\n\tstruct net_device *dev_rx;\n};\n\nstruct nlmsghdr {\n\t__u32 nlmsg_len;\n\t__u16 nlmsg_type;\n\t__u16 nlmsg_flags;\n\t__u32 nlmsg_seq;\n\t__u32 nlmsg_pid;\n};\n\nstruct nlattr {\n\t__u16 nla_len;\n\t__u16 nla_type;\n};\n\nstruct netlink_ext_ack {\n\tconst char *_msg;\n\tconst struct nlattr *bad_attr;\n\tconst struct nla_policy *policy;\n\tu8 cookie[20];\n\tu8 cookie_len;\n};\n\nstruct netlink_range_validation;\n\nstruct netlink_range_validation_signed;\n\nstruct nla_policy {\n\tu8 type;\n\tu8 validation_type;\n\tu16 len;\n\tunion {\n\t\tconst u32 bitfield32_valid;\n\t\tconst u32 mask;\n\t\tconst char *reject_message;\n\t\tconst struct nla_policy *nested_policy;\n\t\tstruct netlink_range_validation *range;\n\t\tstruct netlink_range_validation_signed *range_signed;\n\t\tstruct {\n\t\t\ts16 min;\n\t\t\ts16 max;\n\t\t};\n\t\tint (*validate)(const struct nlattr *, struct netlink_ext_ack *);\n\t\tu16 strict_start_type;\n\t};\n};\n\nstruct netlink_callback {\n\tstruct sk_buff *skb;\n\tconst struct nlmsghdr *nlh;\n\tint (*dump)(struct sk_buff *, struct netlink_callback *);\n\tint (*done)(struct netlink_callback *);\n\tvoid *data;\n\tstruct module *module;\n\tstruct netlink_ext_ack *extack;\n\tu16 family;\n\tu16 answer_flags;\n\tu32 min_dump_alloc;\n\tunsigned int prev_seq;\n\tunsigned int seq;\n\tbool strict_check;\n\tunion {\n\t\tu8 ctx[48];\n\t\tlong int args[6];\n\t};\n};\n\nstruct ndmsg {\n\t__u8 ndm_family;\n\t__u8 ndm_pad1;\n\t__u16 ndm_pad2;\n\t__s32 ndm_ifindex;\n\t__u16 ndm_state;\n\t__u8 ndm_flags;\n\t__u8 ndm_type;\n};\n\nstruct rtnl_link_stats64 {\n\t__u64 rx_packets;\n\t__u64 tx_packets;\n\t__u64 rx_bytes;\n\t__u64 tx_bytes;\n\t__u64 rx_errors;\n\t__u64 tx_errors;\n\t__u64 rx_dropped;\n\t__u64 tx_dropped;\n\t__u64 multicast;\n\t__u64 collisions;\n\t__u64 rx_length_errors;\n\t__u64 rx_over_errors;\n\t__u64 rx_crc_errors;\n\t__u64 rx_frame_errors;\n\t__u64 rx_fifo_errors;\n\t__u64 rx_missed_errors;\n\t__u64 tx_aborted_errors;\n\t__u64 tx_carrier_errors;\n\t__u64 tx_fifo_errors;\n\t__u64 tx_heartbeat_errors;\n\t__u64 tx_window_errors;\n\t__u64 rx_compressed;\n\t__u64 tx_compressed;\n\t__u64 rx_nohandler;\n};\n\nstruct ifla_vf_guid {\n\t__u32 vf;\n\t__u64 guid;\n};\n\nstruct ifla_vf_stats {\n\t__u64 rx_packets;\n\t__u64 tx_packets;\n\t__u64 rx_bytes;\n\t__u64 tx_bytes;\n\t__u64 broadcast;\n\t__u64 multicast;\n\t__u64 rx_dropped;\n\t__u64 tx_dropped;\n};\n\nstruct ifla_vf_info {\n\t__u32 vf;\n\t__u8 mac[32];\n\t__u32 vlan;\n\t__u32 qos;\n\t__u32 spoofchk;\n\t__u32 linkstate;\n\t__u32 min_tx_rate;\n\t__u32 max_tx_rate;\n\t__u32 rss_query_en;\n\t__u32 trusted;\n\t__be16 vlan_proto;\n};\n\nstruct tc_stats {\n\t__u64 bytes;\n\t__u32 packets;\n\t__u32 drops;\n\t__u32 overlimits;\n\t__u32 bps;\n\t__u32 pps;\n\t__u32 qlen;\n\t__u32 backlog;\n};\n\nstruct tc_sizespec {\n\tunsigned char cell_log;\n\tunsigned char size_log;\n\tshort int cell_align;\n\tint overhead;\n\tunsigned int linklayer;\n\tunsigned int mpu;\n\tunsigned int mtu;\n\tunsigned int tsize;\n};\n\nenum netdev_tx {\n\t__NETDEV_TX_MIN = 2147483648,\n\tNETDEV_TX_OK = 0,\n\tNETDEV_TX_BUSY = 16,\n};\n\ntypedef enum netdev_tx netdev_tx_t;\n\nstruct header_ops {\n\tint (*create)(struct sk_buff *, struct net_device *, short unsigned int, const void *, const void *, unsigned int);\n\tint (*parse)(const struct sk_buff *, unsigned char *);\n\tint (*cache)(const struct neighbour *, struct hh_cache *, __be16);\n\tvoid (*cache_update)(struct hh_cache *, const struct net_device *, const unsigned char *);\n\tbool (*validate)(const char *, unsigned int);\n\t__be16 (*parse_protocol)(const struct sk_buff *);\n};\n\nstruct xsk_buff_pool;\n\nstruct netdev_queue {\n\tstruct net_device *dev;\n\tstruct Qdisc *qdisc;\n\tstruct Qdisc *qdisc_sleeping;\n\tstruct kobject kobj;\n\tint numa_node;\n\tlong unsigned int tx_maxrate;\n\tlong unsigned int trans_timeout;\n\tstruct net_device *sb_dev;\n\tstruct xsk_buff_pool *pool;\n\tspinlock_t _xmit_lock;\n\tint xmit_lock_owner;\n\tlong unsigned int trans_start;\n\tlong unsigned int state;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct dql dql;\n};\n\nstruct net_rate_estimator;\n\nstruct qdisc_skb_head {\n\tstruct sk_buff *head;\n\tstruct sk_buff *tail;\n\t__u32 qlen;\n\tspinlock_t lock;\n};\n\nstruct gnet_stats_basic_packed {\n\t__u64 bytes;\n\t__u64 packets;\n};\n\nstruct gnet_stats_queue {\n\t__u32 qlen;\n\t__u32 backlog;\n\t__u32 drops;\n\t__u32 requeues;\n\t__u32 overlimits;\n};\n\nstruct Qdisc_ops;\n\nstruct qdisc_size_table;\n\nstruct gnet_stats_basic_cpu;\n\nstruct Qdisc {\n\tint (*enqueue)(struct sk_buff *, struct Qdisc *, struct sk_buff **);\n\tstruct sk_buff * (*dequeue)(struct Qdisc *);\n\tunsigned int flags;\n\tu32 limit;\n\tconst struct Qdisc_ops *ops;\n\tstruct qdisc_size_table *stab;\n\tstruct hlist_node hash;\n\tu32 handle;\n\tu32 parent;\n\tstruct netdev_queue *dev_queue;\n\tstruct net_rate_estimator *rate_est;\n\tstruct gnet_stats_basic_cpu *cpu_bstats;\n\tstruct gnet_stats_queue *cpu_qstats;\n\tint pad;\n\trefcount_t refcnt;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct sk_buff_head gso_skb;\n\tstruct qdisc_skb_head q;\n\tstruct gnet_stats_basic_packed bstats;\n\tseqcount_t running;\n\tstruct gnet_stats_queue qstats;\n\tlong unsigned int state;\n\tstruct Qdisc *next_sched;\n\tstruct sk_buff_head skb_bad_txq;\n\tspinlock_t busylock;\n\tspinlock_t seqlock;\n\tstruct callback_head rcu;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong int privdata[0];\n};\n\nstruct rps_map {\n\tunsigned int len;\n\tstruct callback_head rcu;\n\tu16 cpus[0];\n};\n\nstruct rps_dev_flow {\n\tu16 cpu;\n\tu16 filter;\n\tunsigned int last_qtail;\n};\n\nstruct rps_dev_flow_table {\n\tunsigned int mask;\n\tstruct callback_head rcu;\n\tstruct rps_dev_flow flows[0];\n};\n\nstruct netdev_rx_queue {\n\tstruct rps_map *rps_map;\n\tstruct rps_dev_flow_table *rps_flow_table;\n\tstruct kobject kobj;\n\tstruct net_device *dev;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct xdp_rxq_info xdp_rxq;\n\tstruct xsk_buff_pool *pool;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct xps_map {\n\tunsigned int len;\n\tunsigned int alloc_len;\n\tstruct callback_head rcu;\n\tu16 queues[0];\n};\n\nstruct xps_dev_maps {\n\tstruct callback_head rcu;\n\tunsigned int nr_ids;\n\ts16 num_tc;\n\tstruct xps_map *attr_map[0];\n};\n\nstruct netdev_fcoe_hbainfo {\n\tchar manufacturer[64];\n\tchar serial_number[64];\n\tchar hardware_version[64];\n\tchar driver_version[64];\n\tchar optionrom_version[64];\n\tchar firmware_version[64];\n\tchar model[256];\n\tchar model_description[256];\n};\n\nstruct netdev_phys_item_id {\n\tunsigned char id[32];\n\tunsigned char id_len;\n};\n\nenum net_device_path_type {\n\tDEV_PATH_ETHERNET = 0,\n\tDEV_PATH_VLAN = 1,\n\tDEV_PATH_BRIDGE = 2,\n\tDEV_PATH_PPPOE = 3,\n\tDEV_PATH_DSA = 4,\n};\n\nstruct net_device_path {\n\tenum net_device_path_type type;\n\tconst struct net_device *dev;\n\tunion {\n\t\tstruct {\n\t\t\tu16 id;\n\t\t\t__be16 proto;\n\t\t\tu8 h_dest[6];\n\t\t} encap;\n\t\tstruct {\n\t\t\tenum {\n\t\t\t\tDEV_PATH_BR_VLAN_KEEP = 0,\n\t\t\t\tDEV_PATH_BR_VLAN_TAG = 1,\n\t\t\t\tDEV_PATH_BR_VLAN_UNTAG = 2,\n\t\t\t\tDEV_PATH_BR_VLAN_UNTAG_HW = 3,\n\t\t\t} vlan_mode;\n\t\t\tu16 vlan_id;\n\t\t\t__be16 vlan_proto;\n\t\t} bridge;\n\t\tstruct {\n\t\t\tint port;\n\t\t\tu16 proto;\n\t\t} dsa;\n\t};\n};\n\nstruct net_device_path_ctx {\n\tconst struct net_device *dev;\n\tconst u8 *daddr;\n\tint num_vlans;\n\tstruct {\n\t\tu16 id;\n\t\t__be16 proto;\n\t} vlan[2];\n};\n\nenum tc_setup_type {\n\tTC_SETUP_QDISC_MQPRIO = 0,\n\tTC_SETUP_CLSU32 = 1,\n\tTC_SETUP_CLSFLOWER = 2,\n\tTC_SETUP_CLSMATCHALL = 3,\n\tTC_SETUP_CLSBPF = 4,\n\tTC_SETUP_BLOCK = 5,\n\tTC_SETUP_QDISC_CBS = 6,\n\tTC_SETUP_QDISC_RED = 7,\n\tTC_SETUP_QDISC_PRIO = 8,\n\tTC_SETUP_QDISC_MQ = 9,\n\tTC_SETUP_QDISC_ETF = 10,\n\tTC_SETUP_ROOT_QDISC = 11,\n\tTC_SETUP_QDISC_GRED = 12,\n\tTC_SETUP_QDISC_TAPRIO = 13,\n\tTC_SETUP_FT = 14,\n\tTC_SETUP_QDISC_ETS = 15,\n\tTC_SETUP_QDISC_TBF = 16,\n\tTC_SETUP_QDISC_FIFO = 17,\n\tTC_SETUP_QDISC_HTB = 18,\n};\n\nenum bpf_netdev_command {\n\tXDP_SETUP_PROG = 0,\n\tXDP_SETUP_PROG_HW = 1,\n\tBPF_OFFLOAD_MAP_ALLOC = 2,\n\tBPF_OFFLOAD_MAP_FREE = 3,\n\tXDP_SETUP_XSK_POOL = 4,\n};\n\nstruct netdev_bpf {\n\tenum bpf_netdev_command command;\n\tunion {\n\t\tstruct {\n\t\t\tu32 flags;\n\t\t\tstruct bpf_prog *prog;\n\t\t\tstruct netlink_ext_ack *extack;\n\t\t};\n\t\tstruct {\n\t\t\tstruct bpf_offloaded_map *offmap;\n\t\t};\n\t\tstruct {\n\t\t\tstruct xsk_buff_pool *pool;\n\t\t\tu16 queue_id;\n\t\t} xsk;\n\t};\n};\n\nstruct xfrmdev_ops {\n\tint (*xdo_dev_state_add)(struct xfrm_state *);\n\tvoid (*xdo_dev_state_delete)(struct xfrm_state *);\n\tvoid (*xdo_dev_state_free)(struct xfrm_state *);\n\tbool (*xdo_dev_offload_ok)(struct sk_buff *, struct xfrm_state *);\n\tvoid (*xdo_dev_state_advance_esn)(struct xfrm_state *);\n};\n\nstruct dev_ifalias {\n\tstruct callback_head rcuhead;\n\tchar ifalias[0];\n};\n\nstruct netdev_name_node {\n\tstruct hlist_node hlist;\n\tstruct list_head list;\n\tstruct net_device *dev;\n\tconst char *name;\n};\n\nstruct devlink_port;\n\nstruct ip_tunnel_parm;\n\nstruct net_device_ops {\n\tint (*ndo_init)(struct net_device *);\n\tvoid (*ndo_uninit)(struct net_device *);\n\tint (*ndo_open)(struct net_device *);\n\tint (*ndo_stop)(struct net_device *);\n\tnetdev_tx_t (*ndo_start_xmit)(struct sk_buff *, struct net_device *);\n\tnetdev_features_t (*ndo_features_check)(struct sk_buff *, struct net_device *, netdev_features_t);\n\tu16 (*ndo_select_queue)(struct net_device *, struct sk_buff *, struct net_device *);\n\tvoid (*ndo_change_rx_flags)(struct net_device *, int);\n\tvoid (*ndo_set_rx_mode)(struct net_device *);\n\tint (*ndo_set_mac_address)(struct net_device *, void *);\n\tint (*ndo_validate_addr)(struct net_device *);\n\tint (*ndo_do_ioctl)(struct net_device *, struct ifreq *, int);\n\tint (*ndo_set_config)(struct net_device *, struct ifmap *);\n\tint (*ndo_change_mtu)(struct net_device *, int);\n\tint (*ndo_neigh_setup)(struct net_device *, struct neigh_parms *);\n\tvoid (*ndo_tx_timeout)(struct net_device *, unsigned int);\n\tvoid (*ndo_get_stats64)(struct net_device *, struct rtnl_link_stats64 *);\n\tbool (*ndo_has_offload_stats)(const struct net_device *, int);\n\tint (*ndo_get_offload_stats)(int, const struct net_device *, void *);\n\tstruct net_device_stats * (*ndo_get_stats)(struct net_device *);\n\tint (*ndo_vlan_rx_add_vid)(struct net_device *, __be16, u16);\n\tint (*ndo_vlan_rx_kill_vid)(struct net_device *, __be16, u16);\n\tvoid (*ndo_poll_controller)(struct net_device *);\n\tint (*ndo_netpoll_setup)(struct net_device *, struct netpoll_info *);\n\tvoid (*ndo_netpoll_cleanup)(struct net_device *);\n\tint (*ndo_set_vf_mac)(struct net_device *, int, u8 *);\n\tint (*ndo_set_vf_vlan)(struct net_device *, int, u16, u8, __be16);\n\tint (*ndo_set_vf_rate)(struct net_device *, int, int, int);\n\tint (*ndo_set_vf_spoofchk)(struct net_device *, int, bool);\n\tint (*ndo_set_vf_trust)(struct net_device *, int, bool);\n\tint (*ndo_get_vf_config)(struct net_device *, int, struct ifla_vf_info *);\n\tint (*ndo_set_vf_link_state)(struct net_device *, int, int);\n\tint (*ndo_get_vf_stats)(struct net_device *, int, struct ifla_vf_stats *);\n\tint (*ndo_set_vf_port)(struct net_device *, int, struct nlattr **);\n\tint (*ndo_get_vf_port)(struct net_device *, int, struct sk_buff *);\n\tint (*ndo_get_vf_guid)(struct net_device *, int, struct ifla_vf_guid *, struct ifla_vf_guid *);\n\tint (*ndo_set_vf_guid)(struct net_device *, int, u64, int);\n\tint (*ndo_set_vf_rss_query_en)(struct net_device *, int, bool);\n\tint (*ndo_setup_tc)(struct net_device *, enum tc_setup_type, void *);\n\tint (*ndo_fcoe_enable)(struct net_device *);\n\tint (*ndo_fcoe_disable)(struct net_device *);\n\tint (*ndo_fcoe_ddp_setup)(struct net_device *, u16, struct scatterlist *, unsigned int);\n\tint (*ndo_fcoe_ddp_done)(struct net_device *, u16);\n\tint (*ndo_fcoe_ddp_target)(struct net_device *, u16, struct scatterlist *, unsigned int);\n\tint (*ndo_fcoe_get_hbainfo)(struct net_device *, struct netdev_fcoe_hbainfo *);\n\tint (*ndo_fcoe_get_wwn)(struct net_device *, u64 *, int);\n\tint (*ndo_rx_flow_steer)(struct net_device *, const struct sk_buff *, u16, u32);\n\tint (*ndo_add_slave)(struct net_device *, struct net_device *, struct netlink_ext_ack *);\n\tint (*ndo_del_slave)(struct net_device *, struct net_device *);\n\tstruct net_device * (*ndo_get_xmit_slave)(struct net_device *, struct sk_buff *, bool);\n\tstruct net_device * (*ndo_sk_get_lower_dev)(struct net_device *, struct sock *);\n\tnetdev_features_t (*ndo_fix_features)(struct net_device *, netdev_features_t);\n\tint (*ndo_set_features)(struct net_device *, netdev_features_t);\n\tint (*ndo_neigh_construct)(struct net_device *, struct neighbour *);\n\tvoid (*ndo_neigh_destroy)(struct net_device *, struct neighbour *);\n\tint (*ndo_fdb_add)(struct ndmsg *, struct nlattr **, struct net_device *, const unsigned char *, u16, u16, struct netlink_ext_ack *);\n\tint (*ndo_fdb_del)(struct ndmsg *, struct nlattr **, struct net_device *, const unsigned char *, u16);\n\tint (*ndo_fdb_dump)(struct sk_buff *, struct netlink_callback *, struct net_device *, struct net_device *, int *);\n\tint (*ndo_fdb_get)(struct sk_buff *, struct nlattr **, struct net_device *, const unsigned char *, u16, u32, u32, struct netlink_ext_ack *);\n\tint (*ndo_bridge_setlink)(struct net_device *, struct nlmsghdr *, u16, struct netlink_ext_ack *);\n\tint (*ndo_bridge_getlink)(struct sk_buff *, u32, u32, struct net_device *, u32, int);\n\tint (*ndo_bridge_dellink)(struct net_device *, struct nlmsghdr *, u16);\n\tint (*ndo_change_carrier)(struct net_device *, bool);\n\tint (*ndo_get_phys_port_id)(struct net_device *, struct netdev_phys_item_id *);\n\tint (*ndo_get_port_parent_id)(struct net_device *, struct netdev_phys_item_id *);\n\tint (*ndo_get_phys_port_name)(struct net_device *, char *, size_t);\n\tvoid * (*ndo_dfwd_add_station)(struct net_device *, struct net_device *);\n\tvoid (*ndo_dfwd_del_station)(struct net_device *, void *);\n\tint (*ndo_set_tx_maxrate)(struct net_device *, int, u32);\n\tint (*ndo_get_iflink)(const struct net_device *);\n\tint (*ndo_change_proto_down)(struct net_device *, bool);\n\tint (*ndo_fill_metadata_dst)(struct net_device *, struct sk_buff *);\n\tvoid (*ndo_set_rx_headroom)(struct net_device *, int);\n\tint (*ndo_bpf)(struct net_device *, struct netdev_bpf *);\n\tint (*ndo_xdp_xmit)(struct net_device *, int, struct xdp_frame **, u32);\n\tint (*ndo_xsk_wakeup)(struct net_device *, u32, u32);\n\tstruct devlink_port * (*ndo_get_devlink_port)(struct net_device *);\n\tint (*ndo_tunnel_ctl)(struct net_device *, struct ip_tunnel_parm *, int);\n\tstruct net_device * (*ndo_get_peer_dev)(struct net_device *);\n\tint (*ndo_fill_forward_path)(struct net_device_path_ctx *, struct net_device_path *);\n};\n\nstruct neigh_parms {\n\tpossible_net_t net;\n\tstruct net_device *dev;\n\tstruct list_head list;\n\tint (*neigh_setup)(struct neighbour *);\n\tstruct neigh_table *tbl;\n\tvoid *sysctl_table;\n\tint dead;\n\trefcount_t refcnt;\n\tstruct callback_head callback_head;\n\tint reachable_time;\n\tint data[13];\n\tlong unsigned int data_state[1];\n};\n\nstruct pcpu_lstats {\n\tu64_stats_t packets;\n\tu64_stats_t bytes;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct pcpu_sw_netstats {\n\tu64 rx_packets;\n\tu64 rx_bytes;\n\tu64 tx_packets;\n\tu64 tx_bytes;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct iw_request_info;\n\nunion iwreq_data;\n\ntypedef int (*iw_handler)(struct net_device *, struct iw_request_info *, union iwreq_data *, char *);\n\nstruct iw_priv_args;\n\nstruct iw_statistics;\n\nstruct iw_handler_def {\n\tconst iw_handler *standard;\n\t__u16 num_standard;\n\t__u16 num_private;\n\t__u16 num_private_args;\n\tconst iw_handler *private;\n\tconst struct iw_priv_args *private_args;\n\tstruct iw_statistics * (*get_wireless_stats)(struct net_device *);\n};\n\nenum ethtool_phys_id_state {\n\tETHTOOL_ID_INACTIVE = 0,\n\tETHTOOL_ID_ACTIVE = 1,\n\tETHTOOL_ID_ON = 2,\n\tETHTOOL_ID_OFF = 3,\n};\n\nstruct ethtool_drvinfo;\n\nstruct ethtool_regs;\n\nstruct ethtool_wolinfo;\n\nstruct ethtool_link_ext_state_info;\n\nstruct ethtool_eeprom;\n\nstruct ethtool_coalesce;\n\nstruct ethtool_ringparam;\n\nstruct ethtool_pause_stats;\n\nstruct ethtool_pauseparam;\n\nstruct ethtool_test;\n\nstruct ethtool_stats;\n\nstruct ethtool_rxnfc;\n\nstruct ethtool_flash;\n\nstruct ethtool_channels;\n\nstruct ethtool_dump;\n\nstruct ethtool_ts_info;\n\nstruct ethtool_modinfo;\n\nstruct ethtool_eee;\n\nstruct ethtool_tunable;\n\nstruct ethtool_link_ksettings;\n\nstruct ethtool_fec_stats;\n\nstruct ethtool_fecparam;\n\nstruct ethtool_module_eeprom;\n\nstruct ethtool_eth_phy_stats;\n\nstruct ethtool_eth_mac_stats;\n\nstruct ethtool_eth_ctrl_stats;\n\nstruct ethtool_rmon_stats;\n\nstruct ethtool_rmon_hist_range;\n\nstruct ethtool_ops {\n\tu32 cap_link_lanes_supported: 1;\n\tu32 supported_coalesce_params;\n\tvoid (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);\n\tint (*get_regs_len)(struct net_device *);\n\tvoid (*get_regs)(struct net_device *, struct ethtool_regs *, void *);\n\tvoid (*get_wol)(struct net_device *, struct ethtool_wolinfo *);\n\tint (*set_wol)(struct net_device *, struct ethtool_wolinfo *);\n\tu32 (*get_msglevel)(struct net_device *);\n\tvoid (*set_msglevel)(struct net_device *, u32);\n\tint (*nway_reset)(struct net_device *);\n\tu32 (*get_link)(struct net_device *);\n\tint (*get_link_ext_state)(struct net_device *, struct ethtool_link_ext_state_info *);\n\tint (*get_eeprom_len)(struct net_device *);\n\tint (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);\n\tint (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);\n\tint (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);\n\tint (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);\n\tvoid (*get_ringparam)(struct net_device *, struct ethtool_ringparam *);\n\tint (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);\n\tvoid (*get_pause_stats)(struct net_device *, struct ethtool_pause_stats *);\n\tvoid (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam *);\n\tint (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam *);\n\tvoid (*self_test)(struct net_device *, struct ethtool_test *, u64 *);\n\tvoid (*get_strings)(struct net_device *, u32, u8 *);\n\tint (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);\n\tvoid (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);\n\tint (*begin)(struct net_device *);\n\tvoid (*complete)(struct net_device *);\n\tu32 (*get_priv_flags)(struct net_device *);\n\tint (*set_priv_flags)(struct net_device *, u32);\n\tint (*get_sset_count)(struct net_device *, int);\n\tint (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, u32 *);\n\tint (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);\n\tint (*flash_device)(struct net_device *, struct ethtool_flash *);\n\tint (*reset)(struct net_device *, u32 *);\n\tu32 (*get_rxfh_key_size)(struct net_device *);\n\tu32 (*get_rxfh_indir_size)(struct net_device *);\n\tint (*get_rxfh)(struct net_device *, u32 *, u8 *, u8 *);\n\tint (*set_rxfh)(struct net_device *, const u32 *, const u8 *, const u8);\n\tint (*get_rxfh_context)(struct net_device *, u32 *, u8 *, u8 *, u32);\n\tint (*set_rxfh_context)(struct net_device *, const u32 *, const u8 *, const u8, u32 *, bool);\n\tvoid (*get_channels)(struct net_device *, struct ethtool_channels *);\n\tint (*set_channels)(struct net_device *, struct ethtool_channels *);\n\tint (*get_dump_flag)(struct net_device *, struct ethtool_dump *);\n\tint (*get_dump_data)(struct net_device *, struct ethtool_dump *, void *);\n\tint (*set_dump)(struct net_device *, struct ethtool_dump *);\n\tint (*get_ts_info)(struct net_device *, struct ethtool_ts_info *);\n\tint (*get_module_info)(struct net_device *, struct ethtool_modinfo *);\n\tint (*get_module_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);\n\tint (*get_eee)(struct net_device *, struct ethtool_eee *);\n\tint (*set_eee)(struct net_device *, struct ethtool_eee *);\n\tint (*get_tunable)(struct net_device *, const struct ethtool_tunable *, void *);\n\tint (*set_tunable)(struct net_device *, const struct ethtool_tunable *, const void *);\n\tint (*get_per_queue_coalesce)(struct net_device *, u32, struct ethtool_coalesce *);\n\tint (*set_per_queue_coalesce)(struct net_device *, u32, struct ethtool_coalesce *);\n\tint (*get_link_ksettings)(struct net_device *, struct ethtool_link_ksettings *);\n\tint (*set_link_ksettings)(struct net_device *, const struct ethtool_link_ksettings *);\n\tvoid (*get_fec_stats)(struct net_device *, struct ethtool_fec_stats *);\n\tint (*get_fecparam)(struct net_device *, struct ethtool_fecparam *);\n\tint (*set_fecparam)(struct net_device *, struct ethtool_fecparam *);\n\tvoid (*get_ethtool_phy_stats)(struct net_device *, struct ethtool_stats *, u64 *);\n\tint (*get_phy_tunable)(struct net_device *, const struct ethtool_tunable *, void *);\n\tint (*set_phy_tunable)(struct net_device *, const struct ethtool_tunable *, const void *);\n\tint (*get_module_eeprom_by_page)(struct net_device *, const struct ethtool_module_eeprom *, struct netlink_ext_ack *);\n\tvoid (*get_eth_phy_stats)(struct net_device *, struct ethtool_eth_phy_stats *);\n\tvoid (*get_eth_mac_stats)(struct net_device *, struct ethtool_eth_mac_stats *);\n\tvoid (*get_eth_ctrl_stats)(struct net_device *, struct ethtool_eth_ctrl_stats *);\n\tvoid (*get_rmon_stats)(struct net_device *, struct ethtool_rmon_stats *, const struct ethtool_rmon_hist_range **);\n};\n\nstruct l3mdev_ops {\n\tu32 (*l3mdev_fib_table)(const struct net_device *);\n\tstruct sk_buff * (*l3mdev_l3_rcv)(struct net_device *, struct sk_buff *, u16);\n\tstruct sk_buff * (*l3mdev_l3_out)(struct net_device *, struct sock *, struct sk_buff *, u16);\n\tstruct dst_entry * (*l3mdev_link_scope_lookup)(const struct net_device *, struct flowi6 *);\n};\n\nstruct nd_opt_hdr;\n\nstruct ndisc_options;\n\nstruct prefix_info;\n\nstruct ndisc_ops {\n\tint (*is_useropt)(u8);\n\tint (*parse_options)(const struct net_device *, struct nd_opt_hdr *, struct ndisc_options *);\n\tvoid (*update)(const struct net_device *, struct neighbour *, u32, u8, const struct ndisc_options *);\n\tint (*opt_addr_space)(const struct net_device *, u8, struct neighbour *, u8 *, u8 **);\n\tvoid (*fill_addr_option)(const struct net_device *, struct sk_buff *, u8, const u8 *);\n\tvoid (*prefix_rcv_add_addr)(struct net *, struct net_device *, const struct prefix_info *, struct inet6_dev *, struct in6_addr *, int, u32, bool, bool, __u32, u32, bool);\n};\n\nenum tls_offload_ctx_dir {\n\tTLS_OFFLOAD_CTX_DIR_RX = 0,\n\tTLS_OFFLOAD_CTX_DIR_TX = 1,\n};\n\nstruct tls_crypto_info;\n\nstruct tls_context;\n\nstruct tlsdev_ops {\n\tint (*tls_dev_add)(struct net_device *, struct sock *, enum tls_offload_ctx_dir, struct tls_crypto_info *, u32);\n\tvoid (*tls_dev_del)(struct net_device *, struct tls_context *, enum tls_offload_ctx_dir);\n\tint (*tls_dev_resync)(struct net_device *, struct sock *, u32, u8 *, enum tls_offload_ctx_dir);\n};\n\nstruct ipv6_devstat {\n\tstruct proc_dir_entry *proc_dir_entry;\n\tstruct ipstats_mib *ipv6;\n\tstruct icmpv6_mib_device *icmpv6dev;\n\tstruct icmpv6msg_mib_device *icmpv6msgdev;\n};\n\nstruct ifmcaddr6;\n\nstruct ifacaddr6;\n\nstruct inet6_dev {\n\tstruct net_device *dev;\n\tstruct list_head addr_list;\n\tstruct ifmcaddr6 *mc_list;\n\tstruct ifmcaddr6 *mc_tomb;\n\tunsigned char mc_qrv;\n\tunsigned char mc_gq_running;\n\tunsigned char mc_ifc_count;\n\tunsigned char mc_dad_count;\n\tlong unsigned int mc_v1_seen;\n\tlong unsigned int mc_qi;\n\tlong unsigned int mc_qri;\n\tlong unsigned int mc_maxdelay;\n\tstruct delayed_work mc_gq_work;\n\tstruct delayed_work mc_ifc_work;\n\tstruct delayed_work mc_dad_work;\n\tstruct delayed_work mc_query_work;\n\tstruct delayed_work mc_report_work;\n\tstruct sk_buff_head mc_query_queue;\n\tstruct sk_buff_head mc_report_queue;\n\tspinlock_t mc_query_lock;\n\tspinlock_t mc_report_lock;\n\tstruct mutex mc_lock;\n\tstruct ifacaddr6 *ac_list;\n\trwlock_t lock;\n\trefcount_t refcnt;\n\t__u32 if_flags;\n\tint dead;\n\tu32 desync_factor;\n\tstruct list_head tempaddr_list;\n\tstruct in6_addr token;\n\tstruct neigh_parms *nd_parms;\n\tstruct ipv6_devconf cnf;\n\tstruct ipv6_devstat stats;\n\tstruct timer_list rs_timer;\n\t__s32 rs_interval;\n\t__u8 rs_probes;\n\tlong unsigned int tstamp;\n\tstruct callback_head rcu;\n};\n\nstruct tcf_proto;\n\nstruct tcf_block;\n\nstruct mini_Qdisc {\n\tstruct tcf_proto *filter_list;\n\tstruct tcf_block *block;\n\tstruct gnet_stats_basic_cpu *cpu_bstats;\n\tstruct gnet_stats_queue *cpu_qstats;\n\tstruct callback_head rcu;\n};\n\nstruct rtnl_link_ops {\n\tstruct list_head list;\n\tconst char *kind;\n\tsize_t priv_size;\n\tstruct net_device * (*alloc)(struct nlattr **, const char *, unsigned char, unsigned int, unsigned int);\n\tvoid (*setup)(struct net_device *);\n\tbool netns_refund;\n\tunsigned int maxtype;\n\tconst struct nla_policy *policy;\n\tint (*validate)(struct nlattr **, struct nlattr **, struct netlink_ext_ack *);\n\tint (*newlink)(struct net *, struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *);\n\tint (*changelink)(struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *);\n\tvoid (*dellink)(struct net_device *, struct list_head *);\n\tsize_t (*get_size)(const struct net_device *);\n\tint (*fill_info)(struct sk_buff *, const struct net_device *);\n\tsize_t (*get_xstats_size)(const struct net_device *);\n\tint (*fill_xstats)(struct sk_buff *, const struct net_device *);\n\tunsigned int (*get_num_tx_queues)();\n\tunsigned int (*get_num_rx_queues)();\n\tunsigned int slave_maxtype;\n\tconst struct nla_policy *slave_policy;\n\tint (*slave_changelink)(struct net_device *, struct net_device *, struct nlattr **, struct nlattr **, struct netlink_ext_ack *);\n\tsize_t (*get_slave_size)(const struct net_device *, const struct net_device *);\n\tint (*fill_slave_info)(struct sk_buff *, const struct net_device *, const struct net_device *);\n\tstruct net * (*get_link_net)(const struct net_device *);\n\tsize_t (*get_linkxstats_size)(const struct net_device *, int);\n\tint (*fill_linkxstats)(struct sk_buff *, const struct net_device *, int *, int);\n};\n\nstruct udp_tunnel_nic_table_info {\n\tunsigned int n_entries;\n\tunsigned int tunnel_types;\n};\n\nstruct udp_tunnel_info;\n\nstruct udp_tunnel_nic_shared;\n\nstruct udp_tunnel_nic_info {\n\tint (*set_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *);\n\tint (*unset_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *);\n\tint (*sync_table)(struct net_device *, unsigned int);\n\tstruct udp_tunnel_nic_shared *shared;\n\tunsigned int flags;\n\tstruct udp_tunnel_nic_table_info tables[4];\n};\n\nenum {\n\tRTAX_UNSPEC = 0,\n\tRTAX_LOCK = 1,\n\tRTAX_MTU = 2,\n\tRTAX_WINDOW = 3,\n\tRTAX_RTT = 4,\n\tRTAX_RTTVAR = 5,\n\tRTAX_SSTHRESH = 6,\n\tRTAX_CWND = 7,\n\tRTAX_ADVMSS = 8,\n\tRTAX_REORDERING = 9,\n\tRTAX_HOPLIMIT = 10,\n\tRTAX_INITCWND = 11,\n\tRTAX_FEATURES = 12,\n\tRTAX_RTO_MIN = 13,\n\tRTAX_INITRWND = 14,\n\tRTAX_QUICKACK = 15,\n\tRTAX_CC_ALGO = 16,\n\tRTAX_FASTOPEN_NO_COOKIE = 17,\n\t__RTAX_MAX = 18,\n};\n\nstruct tcmsg {\n\tunsigned char tcm_family;\n\tunsigned char tcm__pad1;\n\tshort unsigned int tcm__pad2;\n\tint tcm_ifindex;\n\t__u32 tcm_handle;\n\t__u32 tcm_parent;\n\t__u32 tcm_info;\n};\n\nstruct gnet_stats_basic_cpu {\n\tstruct gnet_stats_basic_packed bstats;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct gnet_dump {\n\tspinlock_t *lock;\n\tstruct sk_buff *skb;\n\tstruct nlattr *tail;\n\tint compat_tc_stats;\n\tint compat_xstats;\n\tint padattr;\n\tvoid *xstats;\n\tint xstats_len;\n\tstruct tc_stats tc_stats;\n};\n\nstruct netlink_range_validation {\n\tu64 min;\n\tu64 max;\n};\n\nstruct netlink_range_validation_signed {\n\ts64 min;\n\ts64 max;\n};\n\nenum flow_action_hw_stats_bit {\n\tFLOW_ACTION_HW_STATS_IMMEDIATE_BIT = 0,\n\tFLOW_ACTION_HW_STATS_DELAYED_BIT = 1,\n\tFLOW_ACTION_HW_STATS_DISABLED_BIT = 2,\n\tFLOW_ACTION_HW_STATS_NUM_BITS = 3,\n};\n\nstruct flow_block {\n\tstruct list_head cb_list;\n};\n\ntypedef int flow_setup_cb_t(enum tc_setup_type, void *, void *);\n\nstruct qdisc_size_table {\n\tstruct callback_head rcu;\n\tstruct list_head list;\n\tstruct tc_sizespec szopts;\n\tint refcnt;\n\tu16 data[0];\n};\n\nstruct Qdisc_class_ops;\n\nstruct Qdisc_ops {\n\tstruct Qdisc_ops *next;\n\tconst struct Qdisc_class_ops *cl_ops;\n\tchar id[16];\n\tint priv_size;\n\tunsigned int static_flags;\n\tint (*enqueue)(struct sk_buff *, struct Qdisc *, struct sk_buff **);\n\tstruct sk_buff * (*dequeue)(struct Qdisc *);\n\tstruct sk_buff * (*peek)(struct Qdisc *);\n\tint (*init)(struct Qdisc *, struct nlattr *, struct netlink_ext_ack *);\n\tvoid (*reset)(struct Qdisc *);\n\tvoid (*destroy)(struct Qdisc *);\n\tint (*change)(struct Qdisc *, struct nlattr *, struct netlink_ext_ack *);\n\tvoid (*attach)(struct Qdisc *);\n\tint (*change_tx_queue_len)(struct Qdisc *, unsigned int);\n\tint (*dump)(struct Qdisc *, struct sk_buff *);\n\tint (*dump_stats)(struct Qdisc *, struct gnet_dump *);\n\tvoid (*ingress_block_set)(struct Qdisc *, u32);\n\tvoid (*egress_block_set)(struct Qdisc *, u32);\n\tu32 (*ingress_block_get)(struct Qdisc *);\n\tu32 (*egress_block_get)(struct Qdisc *);\n\tstruct module *owner;\n};\n\nstruct qdisc_walker;\n\nstruct Qdisc_class_ops {\n\tunsigned int flags;\n\tstruct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *);\n\tint (*graft)(struct Qdisc *, long unsigned int, struct Qdisc *, struct Qdisc **, struct netlink_ext_ack *);\n\tstruct Qdisc * (*leaf)(struct Qdisc *, long unsigned int);\n\tvoid (*qlen_notify)(struct Qdisc *, long unsigned int);\n\tlong unsigned int (*find)(struct Qdisc *, u32);\n\tint (*change)(struct Qdisc *, u32, u32, struct nlattr **, long unsigned int *, struct netlink_ext_ack *);\n\tint (*delete)(struct Qdisc *, long unsigned int, struct netlink_ext_ack *);\n\tvoid (*walk)(struct Qdisc *, struct qdisc_walker *);\n\tstruct tcf_block * (*tcf_block)(struct Qdisc *, long unsigned int, struct netlink_ext_ack *);\n\tlong unsigned int (*bind_tcf)(struct Qdisc *, long unsigned int, u32);\n\tvoid (*unbind_tcf)(struct Qdisc *, long unsigned int);\n\tint (*dump)(struct Qdisc *, long unsigned int, struct sk_buff *, struct tcmsg *);\n\tint (*dump_stats)(struct Qdisc *, long unsigned int, struct gnet_dump *);\n};\n\nstruct tcf_chain;\n\nstruct tcf_block {\n\tstruct mutex lock;\n\tstruct list_head chain_list;\n\tu32 index;\n\tu32 classid;\n\trefcount_t refcnt;\n\tstruct net *net;\n\tstruct Qdisc *q;\n\tstruct rw_semaphore cb_lock;\n\tstruct flow_block flow_block;\n\tstruct list_head owner_list;\n\tbool keep_dst;\n\tatomic_t offloadcnt;\n\tunsigned int nooffloaddevcnt;\n\tunsigned int lockeddevcnt;\n\tstruct {\n\t\tstruct tcf_chain *chain;\n\t\tstruct list_head filter_chain_list;\n\t} chain0;\n\tstruct callback_head rcu;\n\tstruct hlist_head proto_destroy_ht[128];\n\tstruct mutex proto_destroy_lock;\n};\n\nstruct tcf_result;\n\nstruct tcf_proto_ops;\n\nstruct tcf_proto {\n\tstruct tcf_proto *next;\n\tvoid *root;\n\tint (*classify)(struct sk_buff *, const struct tcf_proto *, struct tcf_result *);\n\t__be16 protocol;\n\tu32 prio;\n\tvoid *data;\n\tconst struct tcf_proto_ops *ops;\n\tstruct tcf_chain *chain;\n\tspinlock_t lock;\n\tbool deleting;\n\trefcount_t refcnt;\n\tstruct callback_head rcu;\n\tstruct hlist_node destroy_ht_node;\n};\n\nstruct tcf_result {\n\tunion {\n\t\tstruct {\n\t\t\tlong unsigned int class;\n\t\t\tu32 classid;\n\t\t};\n\t\tconst struct tcf_proto *goto_tp;\n\t\tstruct {\n\t\t\tbool ingress;\n\t\t\tstruct gnet_stats_queue *qstats;\n\t\t};\n\t};\n};\n\nstruct tcf_walker;\n\nstruct tcf_proto_ops {\n\tstruct list_head head;\n\tchar kind[16];\n\tint (*classify)(struct sk_buff *, const struct tcf_proto *, struct tcf_result *);\n\tint (*init)(struct tcf_proto *);\n\tvoid (*destroy)(struct tcf_proto *, bool, struct netlink_ext_ack *);\n\tvoid * (*get)(struct tcf_proto *, u32);\n\tvoid (*put)(struct tcf_proto *, void *);\n\tint (*change)(struct net *, struct sk_buff *, struct tcf_proto *, long unsigned int, u32, struct nlattr **, void **, bool, bool, struct netlink_ext_ack *);\n\tint (*delete)(struct tcf_proto *, void *, bool *, bool, struct netlink_ext_ack *);\n\tbool (*delete_empty)(struct tcf_proto *);\n\tvoid (*walk)(struct tcf_proto *, struct tcf_walker *, bool);\n\tint (*reoffload)(struct tcf_proto *, bool, flow_setup_cb_t *, void *, struct netlink_ext_ack *);\n\tvoid (*hw_add)(struct tcf_proto *, void *);\n\tvoid (*hw_del)(struct tcf_proto *, void *);\n\tvoid (*bind_class)(void *, u32, long unsigned int, void *, long unsigned int);\n\tvoid * (*tmplt_create)(struct net *, struct tcf_chain *, struct nlattr **, struct netlink_ext_ack *);\n\tvoid (*tmplt_destroy)(void *);\n\tint (*dump)(struct net *, struct tcf_proto *, void *, struct sk_buff *, struct tcmsg *, bool);\n\tint (*terse_dump)(struct net *, struct tcf_proto *, void *, struct sk_buff *, struct tcmsg *, bool);\n\tint (*tmplt_dump)(struct sk_buff *, struct net *, void *);\n\tstruct module *owner;\n\tint flags;\n};\n\nstruct tcf_chain {\n\tstruct mutex filter_chain_lock;\n\tstruct tcf_proto *filter_chain;\n\tstruct list_head list;\n\tstruct tcf_block *block;\n\tu32 index;\n\tunsigned int refcnt;\n\tunsigned int action_refcnt;\n\tbool explicitly_created;\n\tbool flushing;\n\tconst struct tcf_proto_ops *tmplt_ops;\n\tvoid *tmplt_priv;\n\tstruct callback_head rcu;\n};\n\nstruct sock_fprog_kern {\n\tu16 len;\n\tstruct sock_filter *filter;\n};\n\nstruct bpf_prog_stats {\n\tu64 cnt;\n\tu64 nsecs;\n\tu64 misses;\n\tstruct u64_stats_sync syncp;\n\tlong: 64;\n};\n\nstruct sk_filter {\n\trefcount_t refcnt;\n\tstruct callback_head rcu;\n\tstruct bpf_prog *prog;\n};\n\nenum {\n\tNEIGH_VAR_MCAST_PROBES = 0,\n\tNEIGH_VAR_UCAST_PROBES = 1,\n\tNEIGH_VAR_APP_PROBES = 2,\n\tNEIGH_VAR_MCAST_REPROBES = 3,\n\tNEIGH_VAR_RETRANS_TIME = 4,\n\tNEIGH_VAR_BASE_REACHABLE_TIME = 5,\n\tNEIGH_VAR_DELAY_PROBE_TIME = 6,\n\tNEIGH_VAR_GC_STALETIME = 7,\n\tNEIGH_VAR_QUEUE_LEN_BYTES = 8,\n\tNEIGH_VAR_PROXY_QLEN = 9,\n\tNEIGH_VAR_ANYCAST_DELAY = 10,\n\tNEIGH_VAR_PROXY_DELAY = 11,\n\tNEIGH_VAR_LOCKTIME = 12,\n\tNEIGH_VAR_QUEUE_LEN = 13,\n\tNEIGH_VAR_RETRANS_TIME_MS = 14,\n\tNEIGH_VAR_BASE_REACHABLE_TIME_MS = 15,\n\tNEIGH_VAR_GC_INTERVAL = 16,\n\tNEIGH_VAR_GC_THRESH1 = 17,\n\tNEIGH_VAR_GC_THRESH2 = 18,\n\tNEIGH_VAR_GC_THRESH3 = 19,\n\tNEIGH_VAR_MAX = 20,\n};\n\nstruct pneigh_entry;\n\nstruct neigh_statistics;\n\nstruct neigh_hash_table;\n\nstruct neigh_table {\n\tint family;\n\tunsigned int entry_size;\n\tunsigned int key_len;\n\t__be16 protocol;\n\t__u32 (*hash)(const void *, const struct net_device *, __u32 *);\n\tbool (*key_eq)(const struct neighbour *, const void *);\n\tint (*constructor)(struct neighbour *);\n\tint (*pconstructor)(struct pneigh_entry *);\n\tvoid (*pdestructor)(struct pneigh_entry *);\n\tvoid (*proxy_redo)(struct sk_buff *);\n\tint (*is_multicast)(const void *);\n\tbool (*allow_add)(const struct net_device *, struct netlink_ext_ack *);\n\tchar *id;\n\tstruct neigh_parms parms;\n\tstruct list_head parms_list;\n\tint gc_interval;\n\tint gc_thresh1;\n\tint gc_thresh2;\n\tint gc_thresh3;\n\tlong unsigned int last_flush;\n\tstruct delayed_work gc_work;\n\tstruct timer_list proxy_timer;\n\tstruct sk_buff_head proxy_queue;\n\tatomic_t entries;\n\tatomic_t gc_entries;\n\tstruct list_head gc_list;\n\trwlock_t lock;\n\tlong unsigned int last_rand;\n\tstruct neigh_statistics *stats;\n\tstruct neigh_hash_table *nht;\n\tstruct pneigh_entry **phash_buckets;\n};\n\nstruct neigh_statistics {\n\tlong unsigned int allocs;\n\tlong unsigned int destroys;\n\tlong unsigned int hash_grows;\n\tlong unsigned int res_failed;\n\tlong unsigned int lookups;\n\tlong unsigned int hits;\n\tlong unsigned int rcv_probes_mcast;\n\tlong unsigned int rcv_probes_ucast;\n\tlong unsigned int periodic_gc_runs;\n\tlong unsigned int forced_gc_runs;\n\tlong unsigned int unres_discards;\n\tlong unsigned int table_fulls;\n};\n\nstruct neigh_ops {\n\tint family;\n\tvoid (*solicit)(struct neighbour *, struct sk_buff *);\n\tvoid (*error_report)(struct neighbour *, struct sk_buff *);\n\tint (*output)(struct neighbour *, struct sk_buff *);\n\tint (*connected_output)(struct neighbour *, struct sk_buff *);\n};\n\nstruct pneigh_entry {\n\tstruct pneigh_entry *next;\n\tpossible_net_t net;\n\tstruct net_device *dev;\n\tu8 flags;\n\tu8 protocol;\n\tu8 key[0];\n};\n\nstruct neigh_hash_table {\n\tstruct neighbour **hash_buckets;\n\tunsigned int hash_shift;\n\t__u32 hash_rnd[4];\n\tstruct callback_head rcu;\n};\n\nenum {\n\tTCP_ESTABLISHED = 1,\n\tTCP_SYN_SENT = 2,\n\tTCP_SYN_RECV = 3,\n\tTCP_FIN_WAIT1 = 4,\n\tTCP_FIN_WAIT2 = 5,\n\tTCP_TIME_WAIT = 6,\n\tTCP_CLOSE = 7,\n\tTCP_CLOSE_WAIT = 8,\n\tTCP_LAST_ACK = 9,\n\tTCP_LISTEN = 10,\n\tTCP_CLOSING = 11,\n\tTCP_NEW_SYN_RECV = 12,\n\tTCP_MAX_STATES = 13,\n};\n\nstruct fib_rule_hdr {\n\t__u8 family;\n\t__u8 dst_len;\n\t__u8 src_len;\n\t__u8 tos;\n\t__u8 table;\n\t__u8 res1;\n\t__u8 res2;\n\t__u8 action;\n\t__u32 flags;\n};\n\nstruct fib_rule_port_range {\n\t__u16 start;\n\t__u16 end;\n};\n\nstruct fib_kuid_range {\n\tkuid_t start;\n\tkuid_t end;\n};\n\nstruct fib_rule {\n\tstruct list_head list;\n\tint iifindex;\n\tint oifindex;\n\tu32 mark;\n\tu32 mark_mask;\n\tu32 flags;\n\tu32 table;\n\tu8 action;\n\tu8 l3mdev;\n\tu8 proto;\n\tu8 ip_proto;\n\tu32 target;\n\t__be64 tun_id;\n\tstruct fib_rule *ctarget;\n\tstruct net *fr_net;\n\trefcount_t refcnt;\n\tu32 pref;\n\tint suppress_ifgroup;\n\tint suppress_prefixlen;\n\tchar iifname[16];\n\tchar oifname[16];\n\tstruct fib_kuid_range uid_range;\n\tstruct fib_rule_port_range sport_range;\n\tstruct fib_rule_port_range dport_range;\n\tstruct callback_head rcu;\n};\n\nstruct fib_lookup_arg {\n\tvoid *lookup_ptr;\n\tconst void *lookup_data;\n\tvoid *result;\n\tstruct fib_rule *rule;\n\tu32 table;\n\tint flags;\n};\n\nstruct smc_hashinfo;\n\nstruct sk_psock;\n\nstruct request_sock_ops;\n\nstruct timewait_sock_ops;\n\nstruct udp_table;\n\nstruct raw_hashinfo;\n\nstruct proto {\n\tvoid (*close)(struct sock *, long int);\n\tint (*pre_connect)(struct sock *, struct sockaddr *, int);\n\tint (*connect)(struct sock *, struct sockaddr *, int);\n\tint (*disconnect)(struct sock *, int);\n\tstruct sock * (*accept)(struct sock *, int, int *, bool);\n\tint (*ioctl)(struct sock *, int, long unsigned int);\n\tint (*init)(struct sock *);\n\tvoid (*destroy)(struct sock *);\n\tvoid (*shutdown)(struct sock *, int);\n\tint (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int);\n\tint (*getsockopt)(struct sock *, int, int, char *, int *);\n\tvoid (*keepalive)(struct sock *, int);\n\tint (*compat_ioctl)(struct sock *, unsigned int, long unsigned int);\n\tint (*sendmsg)(struct sock *, struct msghdr *, size_t);\n\tint (*recvmsg)(struct sock *, struct msghdr *, size_t, int, int, int *);\n\tint (*sendpage)(struct sock *, struct page *, int, size_t, int);\n\tint (*bind)(struct sock *, struct sockaddr *, int);\n\tint (*bind_add)(struct sock *, struct sockaddr *, int);\n\tint (*backlog_rcv)(struct sock *, struct sk_buff *);\n\tbool (*bpf_bypass_getsockopt)(int, int);\n\tvoid (*release_cb)(struct sock *);\n\tint (*hash)(struct sock *);\n\tvoid (*unhash)(struct sock *);\n\tvoid (*rehash)(struct sock *);\n\tint (*get_port)(struct sock *, short unsigned int);\n\tint (*psock_update_sk_prot)(struct sock *, struct sk_psock *, bool);\n\tunsigned int inuse_idx;\n\tbool (*stream_memory_free)(const struct sock *, int);\n\tbool (*stream_memory_read)(const struct sock *);\n\tvoid (*enter_memory_pressure)(struct sock *);\n\tvoid (*leave_memory_pressure)(struct sock *);\n\tatomic_long_t *memory_allocated;\n\tstruct percpu_counter *sockets_allocated;\n\tlong unsigned int *memory_pressure;\n\tlong int *sysctl_mem;\n\tint *sysctl_wmem;\n\tint *sysctl_rmem;\n\tu32 sysctl_wmem_offset;\n\tu32 sysctl_rmem_offset;\n\tint max_header;\n\tbool no_autobind;\n\tstruct kmem_cache *slab;\n\tunsigned int obj_size;\n\tslab_flags_t slab_flags;\n\tunsigned int useroffset;\n\tunsigned int usersize;\n\tstruct percpu_counter *orphan_count;\n\tstruct request_sock_ops *rsk_prot;\n\tstruct timewait_sock_ops *twsk_prot;\n\tunion {\n\t\tstruct inet_hashinfo *hashinfo;\n\t\tstruct udp_table *udp_table;\n\t\tstruct raw_hashinfo *raw_hash;\n\t\tstruct smc_hashinfo *smc_hash;\n\t} h;\n\tstruct module *owner;\n\tchar name[32];\n\tstruct list_head node;\n\tint (*diag_destroy)(struct sock *, int);\n};\n\nstruct request_sock;\n\nstruct request_sock_ops {\n\tint family;\n\tunsigned int obj_size;\n\tstruct kmem_cache *slab;\n\tchar *slab_name;\n\tint (*rtx_syn_ack)(const struct sock *, struct request_sock *);\n\tvoid (*send_ack)(const struct sock *, struct sk_buff *, struct request_sock *);\n\tvoid (*send_reset)(const struct sock *, struct sk_buff *);\n\tvoid (*destructor)(struct request_sock *);\n\tvoid (*syn_ack_timeout)(const struct request_sock *);\n};\n\nstruct timewait_sock_ops {\n\tstruct kmem_cache *twsk_slab;\n\tchar *twsk_slab_name;\n\tunsigned int twsk_obj_size;\n\tint (*twsk_unique)(struct sock *, struct sock *, void *);\n\tvoid (*twsk_destructor)(struct sock *);\n};\n\nstruct saved_syn;\n\nstruct request_sock {\n\tstruct sock_common __req_common;\n\tstruct request_sock *dl_next;\n\tu16 mss;\n\tu8 num_retrans;\n\tu8 syncookie: 1;\n\tu8 num_timeout: 7;\n\tu32 ts_recent;\n\tstruct timer_list rsk_timer;\n\tconst struct request_sock_ops *rsk_ops;\n\tstruct sock *sk;\n\tstruct saved_syn *saved_syn;\n\tu32 secid;\n\tu32 peer_secid;\n};\n\nstruct saved_syn {\n\tu32 mac_hdrlen;\n\tu32 network_hdrlen;\n\tu32 tcp_hdrlen;\n\tu8 data[0];\n};\n\nenum tsq_enum {\n\tTSQ_THROTTLED = 0,\n\tTSQ_QUEUED = 1,\n\tTCP_TSQ_DEFERRED = 2,\n\tTCP_WRITE_TIMER_DEFERRED = 3,\n\tTCP_DELACK_TIMER_DEFERRED = 4,\n\tTCP_MTU_REDUCED_DEFERRED = 5,\n};\n\nstruct ip6_sf_list {\n\tstruct ip6_sf_list *sf_next;\n\tstruct in6_addr sf_addr;\n\tlong unsigned int sf_count[2];\n\tunsigned char sf_gsresp;\n\tunsigned char sf_oldin;\n\tunsigned char sf_crcount;\n\tstruct callback_head rcu;\n};\n\nstruct ifmcaddr6 {\n\tstruct in6_addr mca_addr;\n\tstruct inet6_dev *idev;\n\tstruct ifmcaddr6 *next;\n\tstruct ip6_sf_list *mca_sources;\n\tstruct ip6_sf_list *mca_tomb;\n\tunsigned int mca_sfmode;\n\tunsigned char mca_crcount;\n\tlong unsigned int mca_sfcount[2];\n\tstruct delayed_work mca_work;\n\tunsigned int mca_flags;\n\tint mca_users;\n\trefcount_t mca_refcnt;\n\tlong unsigned int mca_cstamp;\n\tlong unsigned int mca_tstamp;\n\tstruct callback_head rcu;\n};\n\nstruct ifacaddr6 {\n\tstruct in6_addr aca_addr;\n\tstruct fib6_info *aca_rt;\n\tstruct ifacaddr6 *aca_next;\n\tstruct hlist_node aca_addr_lst;\n\tint aca_users;\n\trefcount_t aca_refcnt;\n\tlong unsigned int aca_cstamp;\n\tlong unsigned int aca_tstamp;\n\tstruct callback_head rcu;\n};\n\nenum {\n\t__ND_OPT_PREFIX_INFO_END = 0,\n\tND_OPT_SOURCE_LL_ADDR = 1,\n\tND_OPT_TARGET_LL_ADDR = 2,\n\tND_OPT_PREFIX_INFO = 3,\n\tND_OPT_REDIRECT_HDR = 4,\n\tND_OPT_MTU = 5,\n\tND_OPT_NONCE = 14,\n\t__ND_OPT_ARRAY_MAX = 15,\n\tND_OPT_ROUTE_INFO = 24,\n\tND_OPT_RDNSS = 25,\n\tND_OPT_DNSSL = 31,\n\tND_OPT_6CO = 34,\n\tND_OPT_CAPTIVE_PORTAL = 37,\n\tND_OPT_PREF64 = 38,\n\t__ND_OPT_MAX = 39,\n};\n\nstruct nd_opt_hdr {\n\t__u8 nd_opt_type;\n\t__u8 nd_opt_len;\n};\n\nstruct ndisc_options {\n\tstruct nd_opt_hdr *nd_opt_array[15];\n\tstruct nd_opt_hdr *nd_opts_ri;\n\tstruct nd_opt_hdr *nd_opts_ri_end;\n\tstruct nd_opt_hdr *nd_useropts;\n\tstruct nd_opt_hdr *nd_useropts_end;\n\tstruct nd_opt_hdr *nd_802154_opt_array[3];\n};\n\nstruct prefix_info {\n\t__u8 type;\n\t__u8 length;\n\t__u8 prefix_len;\n\t__u8 reserved: 6;\n\t__u8 autoconf: 1;\n\t__u8 onlink: 1;\n\t__be32 valid;\n\t__be32 prefered;\n\t__be32 reserved2;\n\tstruct in6_addr prefix;\n};\n\nenum nfs_opnum4 {\n\tOP_ACCESS = 3,\n\tOP_CLOSE = 4,\n\tOP_COMMIT = 5,\n\tOP_CREATE = 6,\n\tOP_DELEGPURGE = 7,\n\tOP_DELEGRETURN = 8,\n\tOP_GETATTR = 9,\n\tOP_GETFH = 10,\n\tOP_LINK = 11,\n\tOP_LOCK = 12,\n\tOP_LOCKT = 13,\n\tOP_LOCKU = 14,\n\tOP_LOOKUP = 15,\n\tOP_LOOKUPP = 16,\n\tOP_NVERIFY = 17,\n\tOP_OPEN = 18,\n\tOP_OPENATTR = 19,\n\tOP_OPEN_CONFIRM = 20,\n\tOP_OPEN_DOWNGRADE = 21,\n\tOP_PUTFH = 22,\n\tOP_PUTPUBFH = 23,\n\tOP_PUTROOTFH = 24,\n\tOP_READ = 25,\n\tOP_READDIR = 26,\n\tOP_READLINK = 27,\n\tOP_REMOVE = 28,\n\tOP_RENAME = 29,\n\tOP_RENEW = 30,\n\tOP_RESTOREFH = 31,\n\tOP_SAVEFH = 32,\n\tOP_SECINFO = 33,\n\tOP_SETATTR = 34,\n\tOP_SETCLIENTID = 35,\n\tOP_SETCLIENTID_CONFIRM = 36,\n\tOP_VERIFY = 37,\n\tOP_WRITE = 38,\n\tOP_RELEASE_LOCKOWNER = 39,\n\tOP_BACKCHANNEL_CTL = 40,\n\tOP_BIND_CONN_TO_SESSION = 41,\n\tOP_EXCHANGE_ID = 42,\n\tOP_CREATE_SESSION = 43,\n\tOP_DESTROY_SESSION = 44,\n\tOP_FREE_STATEID = 45,\n\tOP_GET_DIR_DELEGATION = 46,\n\tOP_GETDEVICEINFO = 47,\n\tOP_GETDEVICELIST = 48,\n\tOP_LAYOUTCOMMIT = 49,\n\tOP_LAYOUTGET = 50,\n\tOP_LAYOUTRETURN = 51,\n\tOP_SECINFO_NO_NAME = 52,\n\tOP_SEQUENCE = 53,\n\tOP_SET_SSV = 54,\n\tOP_TEST_STATEID = 55,\n\tOP_WANT_DELEGATION = 56,\n\tOP_DESTROY_CLIENTID = 57,\n\tOP_RECLAIM_COMPLETE = 58,\n\tOP_ALLOCATE = 59,\n\tOP_COPY = 60,\n\tOP_COPY_NOTIFY = 61,\n\tOP_DEALLOCATE = 62,\n\tOP_IO_ADVISE = 63,\n\tOP_LAYOUTERROR = 64,\n\tOP_LAYOUTSTATS = 65,\n\tOP_OFFLOAD_CANCEL = 66,\n\tOP_OFFLOAD_STATUS = 67,\n\tOP_READ_PLUS = 68,\n\tOP_SEEK = 69,\n\tOP_WRITE_SAME = 70,\n\tOP_CLONE = 71,\n\tOP_GETXATTR = 72,\n\tOP_SETXATTR = 73,\n\tOP_LISTXATTRS = 74,\n\tOP_REMOVEXATTR = 75,\n\tOP_ILLEGAL = 10044,\n};\n\nenum perf_branch_sample_type_shift {\n\tPERF_SAMPLE_BRANCH_USER_SHIFT = 0,\n\tPERF_SAMPLE_BRANCH_KERNEL_SHIFT = 1,\n\tPERF_SAMPLE_BRANCH_HV_SHIFT = 2,\n\tPERF_SAMPLE_BRANCH_ANY_SHIFT = 3,\n\tPERF_SAMPLE_BRANCH_ANY_CALL_SHIFT = 4,\n\tPERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT = 5,\n\tPERF_SAMPLE_BRANCH_IND_CALL_SHIFT = 6,\n\tPERF_SAMPLE_BRANCH_ABORT_TX_SHIFT = 7,\n\tPERF_SAMPLE_BRANCH_IN_TX_SHIFT = 8,\n\tPERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9,\n\tPERF_SAMPLE_BRANCH_COND_SHIFT = 10,\n\tPERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11,\n\tPERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12,\n\tPERF_SAMPLE_BRANCH_CALL_SHIFT = 13,\n\tPERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT = 14,\n\tPERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT = 15,\n\tPERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT = 16,\n\tPERF_SAMPLE_BRANCH_HW_INDEX_SHIFT = 17,\n\tPERF_SAMPLE_BRANCH_MAX_SHIFT = 18,\n};\n\nenum exception_stack_ordering {\n\tESTACK_DF = 0,\n\tESTACK_NMI = 1,\n\tESTACK_DB = 2,\n\tESTACK_MCE = 3,\n\tESTACK_VC = 4,\n\tESTACK_VC2 = 5,\n\tN_EXCEPTION_STACKS = 6,\n};\n\nenum {\n\tTSK_TRACE_FL_TRACE_BIT = 0,\n\tTSK_TRACE_FL_GRAPH_BIT = 1,\n};\n\nstruct uuidcmp {\n\tconst char *uuid;\n\tint len;\n};\n\nstruct subprocess_info {\n\tstruct work_struct work;\n\tstruct completion *complete;\n\tconst char *path;\n\tchar **argv;\n\tchar **envp;\n\tint wait;\n\tint retval;\n\tint (*init)(struct subprocess_info *, struct cred *);\n\tvoid (*cleanup)(struct subprocess_info *);\n\tvoid *data;\n};\n\ntypedef phys_addr_t resource_size_t;\n\nstruct __va_list_tag {\n\tunsigned int gp_offset;\n\tunsigned int fp_offset;\n\tvoid *overflow_arg_area;\n\tvoid *reg_save_area;\n};\n\ntypedef __builtin_va_list __gnuc_va_list;\n\ntypedef __gnuc_va_list va_list;\n\nstruct resource {\n\tresource_size_t start;\n\tresource_size_t end;\n\tconst char *name;\n\tlong unsigned int flags;\n\tlong unsigned int desc;\n\tstruct resource *parent;\n\tstruct resource *sibling;\n\tstruct resource *child;\n};\n\ntypedef u64 async_cookie_t;\n\ntypedef void (*async_func_t)(void *, async_cookie_t);\n\nstruct async_domain {\n\tstruct list_head pending;\n\tunsigned int registered: 1;\n};\n\nstruct hash {\n\tint ino;\n\tint minor;\n\tint major;\n\tumode_t mode;\n\tstruct hash *next;\n\tchar name[4098];\n};\n\nstruct dir_entry {\n\tstruct list_head list;\n\tchar *name;\n\ttime64_t mtime;\n};\n\nenum state {\n\tStart = 0,\n\tCollect = 1,\n\tGotHeader = 2,\n\tSkipIt = 3,\n\tGotName = 4,\n\tCopyFile = 5,\n\tGotSymlink = 6,\n\tReset = 7,\n};\n\ntypedef int (*decompress_fn)(unsigned char *, long int, long int (*)(void *, long unsigned int), long int (*)(void *, long unsigned int), unsigned char *, long int *, void (*)(char *));\n\nenum {\n\tHI_SOFTIRQ = 0,\n\tTIMER_SOFTIRQ = 1,\n\tNET_TX_SOFTIRQ = 2,\n\tNET_RX_SOFTIRQ = 3,\n\tBLOCK_SOFTIRQ = 4,\n\tIRQ_POLL_SOFTIRQ = 5,\n\tTASKLET_SOFTIRQ = 6,\n\tSCHED_SOFTIRQ = 7,\n\tHRTIMER_SOFTIRQ = 8,\n\tRCU_SOFTIRQ = 9,\n\tNR_SOFTIRQS = 10,\n};\n\nenum ucount_type {\n\tUCOUNT_USER_NAMESPACES = 0,\n\tUCOUNT_PID_NAMESPACES = 1,\n\tUCOUNT_UTS_NAMESPACES = 2,\n\tUCOUNT_IPC_NAMESPACES = 3,\n\tUCOUNT_NET_NAMESPACES = 4,\n\tUCOUNT_MNT_NAMESPACES = 5,\n\tUCOUNT_CGROUP_NAMESPACES = 6,\n\tUCOUNT_TIME_NAMESPACES = 7,\n\tUCOUNT_INOTIFY_INSTANCES = 8,\n\tUCOUNT_INOTIFY_WATCHES = 9,\n\tUCOUNT_FANOTIFY_GROUPS = 10,\n\tUCOUNT_FANOTIFY_MARKS = 11,\n\tUCOUNT_RLIMIT_NPROC = 12,\n\tUCOUNT_RLIMIT_MSGQUEUE = 13,\n\tUCOUNT_RLIMIT_SIGPENDING = 14,\n\tUCOUNT_RLIMIT_MEMLOCK = 15,\n\tUCOUNT_COUNTS = 16,\n};\n\nenum flow_dissector_key_id {\n\tFLOW_DISSECTOR_KEY_CONTROL = 0,\n\tFLOW_DISSECTOR_KEY_BASIC = 1,\n\tFLOW_DISSECTOR_KEY_IPV4_ADDRS = 2,\n\tFLOW_DISSECTOR_KEY_IPV6_ADDRS = 3,\n\tFLOW_DISSECTOR_KEY_PORTS = 4,\n\tFLOW_DISSECTOR_KEY_PORTS_RANGE = 5,\n\tFLOW_DISSECTOR_KEY_ICMP = 6,\n\tFLOW_DISSECTOR_KEY_ETH_ADDRS = 7,\n\tFLOW_DISSECTOR_KEY_TIPC = 8,\n\tFLOW_DISSECTOR_KEY_ARP = 9,\n\tFLOW_DISSECTOR_KEY_VLAN = 10,\n\tFLOW_DISSECTOR_KEY_FLOW_LABEL = 11,\n\tFLOW_DISSECTOR_KEY_GRE_KEYID = 12,\n\tFLOW_DISSECTOR_KEY_MPLS_ENTROPY = 13,\n\tFLOW_DISSECTOR_KEY_ENC_KEYID = 14,\n\tFLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS = 15,\n\tFLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS = 16,\n\tFLOW_DISSECTOR_KEY_ENC_CONTROL = 17,\n\tFLOW_DISSECTOR_KEY_ENC_PORTS = 18,\n\tFLOW_DISSECTOR_KEY_MPLS = 19,\n\tFLOW_DISSECTOR_KEY_TCP = 20,\n\tFLOW_DISSECTOR_KEY_IP = 21,\n\tFLOW_DISSECTOR_KEY_CVLAN = 22,\n\tFLOW_DISSECTOR_KEY_ENC_IP = 23,\n\tFLOW_DISSECTOR_KEY_ENC_OPTS = 24,\n\tFLOW_DISSECTOR_KEY_META = 25,\n\tFLOW_DISSECTOR_KEY_CT = 26,\n\tFLOW_DISSECTOR_KEY_HASH = 27,\n\tFLOW_DISSECTOR_KEY_MAX = 28,\n};\n\nenum {\n\tIPSTATS_MIB_NUM = 0,\n\tIPSTATS_MIB_INPKTS = 1,\n\tIPSTATS_MIB_INOCTETS = 2,\n\tIPSTATS_MIB_INDELIVERS = 3,\n\tIPSTATS_MIB_OUTFORWDATAGRAMS = 4,\n\tIPSTATS_MIB_OUTPKTS = 5,\n\tIPSTATS_MIB_OUTOCTETS = 6,\n\tIPSTATS_MIB_INHDRERRORS = 7,\n\tIPSTATS_MIB_INTOOBIGERRORS = 8,\n\tIPSTATS_MIB_INNOROUTES = 9,\n\tIPSTATS_MIB_INADDRERRORS = 10,\n\tIPSTATS_MIB_INUNKNOWNPROTOS = 11,\n\tIPSTATS_MIB_INTRUNCATEDPKTS = 12,\n\tIPSTATS_MIB_INDISCARDS = 13,\n\tIPSTATS_MIB_OUTDISCARDS = 14,\n\tIPSTATS_MIB_OUTNOROUTES = 15,\n\tIPSTATS_MIB_REASMTIMEOUT = 16,\n\tIPSTATS_MIB_REASMREQDS = 17,\n\tIPSTATS_MIB_REASMOKS = 18,\n\tIPSTATS_MIB_REASMFAILS = 19,\n\tIPSTATS_MIB_FRAGOKS = 20,\n\tIPSTATS_MIB_FRAGFAILS = 21,\n\tIPSTATS_MIB_FRAGCREATES = 22,\n\tIPSTATS_MIB_INMCASTPKTS = 23,\n\tIPSTATS_MIB_OUTMCASTPKTS = 24,\n\tIPSTATS_MIB_INBCASTPKTS = 25,\n\tIPSTATS_MIB_OUTBCASTPKTS = 26,\n\tIPSTATS_MIB_INMCASTOCTETS = 27,\n\tIPSTATS_MIB_OUTMCASTOCTETS = 28,\n\tIPSTATS_MIB_INBCASTOCTETS = 29,\n\tIPSTATS_MIB_OUTBCASTOCTETS = 30,\n\tIPSTATS_MIB_CSUMERRORS = 31,\n\tIPSTATS_MIB_NOECTPKTS = 32,\n\tIPSTATS_MIB_ECT1PKTS = 33,\n\tIPSTATS_MIB_ECT0PKTS = 34,\n\tIPSTATS_MIB_CEPKTS = 35,\n\tIPSTATS_MIB_REASM_OVERLAPS = 36,\n\t__IPSTATS_MIB_MAX = 37,\n};\n\nenum {\n\tICMP_MIB_NUM = 0,\n\tICMP_MIB_INMSGS = 1,\n\tICMP_MIB_INERRORS = 2,\n\tICMP_MIB_INDESTUNREACHS = 3,\n\tICMP_MIB_INTIMEEXCDS = 4,\n\tICMP_MIB_INPARMPROBS = 5,\n\tICMP_MIB_INSRCQUENCHS = 6,\n\tICMP_MIB_INREDIRECTS = 7,\n\tICMP_MIB_INECHOS = 8,\n\tICMP_MIB_INECHOREPS = 9,\n\tICMP_MIB_INTIMESTAMPS = 10,\n\tICMP_MIB_INTIMESTAMPREPS = 11,\n\tICMP_MIB_INADDRMASKS = 12,\n\tICMP_MIB_INADDRMASKREPS = 13,\n\tICMP_MIB_OUTMSGS = 14,\n\tICMP_MIB_OUTERRORS = 15,\n\tICMP_MIB_OUTDESTUNREACHS = 16,\n\tICMP_MIB_OUTTIMEEXCDS = 17,\n\tICMP_MIB_OUTPARMPROBS = 18,\n\tICMP_MIB_OUTSRCQUENCHS = 19,\n\tICMP_MIB_OUTREDIRECTS = 20,\n\tICMP_MIB_OUTECHOS = 21,\n\tICMP_MIB_OUTECHOREPS = 22,\n\tICMP_MIB_OUTTIMESTAMPS = 23,\n\tICMP_MIB_OUTTIMESTAMPREPS = 24,\n\tICMP_MIB_OUTADDRMASKS = 25,\n\tICMP_MIB_OUTADDRMASKREPS = 26,\n\tICMP_MIB_CSUMERRORS = 27,\n\t__ICMP_MIB_MAX = 28,\n};\n\nenum {\n\tICMP6_MIB_NUM = 0,\n\tICMP6_MIB_INMSGS = 1,\n\tICMP6_MIB_INERRORS = 2,\n\tICMP6_MIB_OUTMSGS = 3,\n\tICMP6_MIB_OUTERRORS = 4,\n\tICMP6_MIB_CSUMERRORS = 5,\n\t__ICMP6_MIB_MAX = 6,\n};\n\nenum {\n\tTCP_MIB_NUM = 0,\n\tTCP_MIB_RTOALGORITHM = 1,\n\tTCP_MIB_RTOMIN = 2,\n\tTCP_MIB_RTOMAX = 3,\n\tTCP_MIB_MAXCONN = 4,\n\tTCP_MIB_ACTIVEOPENS = 5,\n\tTCP_MIB_PASSIVEOPENS = 6,\n\tTCP_MIB_ATTEMPTFAILS = 7,\n\tTCP_MIB_ESTABRESETS = 8,\n\tTCP_MIB_CURRESTAB = 9,\n\tTCP_MIB_INSEGS = 10,\n\tTCP_MIB_OUTSEGS = 11,\n\tTCP_MIB_RETRANSSEGS = 12,\n\tTCP_MIB_INERRS = 13,\n\tTCP_MIB_OUTRSTS = 14,\n\tTCP_MIB_CSUMERRORS = 15,\n\t__TCP_MIB_MAX = 16,\n};\n\nenum {\n\tUDP_MIB_NUM = 0,\n\tUDP_MIB_INDATAGRAMS = 1,\n\tUDP_MIB_NOPORTS = 2,\n\tUDP_MIB_INERRORS = 3,\n\tUDP_MIB_OUTDATAGRAMS = 4,\n\tUDP_MIB_RCVBUFERRORS = 5,\n\tUDP_MIB_SNDBUFERRORS = 6,\n\tUDP_MIB_CSUMERRORS = 7,\n\tUDP_MIB_IGNOREDMULTI = 8,\n\tUDP_MIB_MEMERRORS = 9,\n\t__UDP_MIB_MAX = 10,\n};\n\nenum {\n\tLINUX_MIB_NUM = 0,\n\tLINUX_MIB_SYNCOOKIESSENT = 1,\n\tLINUX_MIB_SYNCOOKIESRECV = 2,\n\tLINUX_MIB_SYNCOOKIESFAILED = 3,\n\tLINUX_MIB_EMBRYONICRSTS = 4,\n\tLINUX_MIB_PRUNECALLED = 5,\n\tLINUX_MIB_RCVPRUNED = 6,\n\tLINUX_MIB_OFOPRUNED = 7,\n\tLINUX_MIB_OUTOFWINDOWICMPS = 8,\n\tLINUX_MIB_LOCKDROPPEDICMPS = 9,\n\tLINUX_MIB_ARPFILTER = 10,\n\tLINUX_MIB_TIMEWAITED = 11,\n\tLINUX_MIB_TIMEWAITRECYCLED = 12,\n\tLINUX_MIB_TIMEWAITKILLED = 13,\n\tLINUX_MIB_PAWSACTIVEREJECTED = 14,\n\tLINUX_MIB_PAWSESTABREJECTED = 15,\n\tLINUX_MIB_DELAYEDACKS = 16,\n\tLINUX_MIB_DELAYEDACKLOCKED = 17,\n\tLINUX_MIB_DELAYEDACKLOST = 18,\n\tLINUX_MIB_LISTENOVERFLOWS = 19,\n\tLINUX_MIB_LISTENDROPS = 20,\n\tLINUX_MIB_TCPHPHITS = 21,\n\tLINUX_MIB_TCPPUREACKS = 22,\n\tLINUX_MIB_TCPHPACKS = 23,\n\tLINUX_MIB_TCPRENORECOVERY = 24,\n\tLINUX_MIB_TCPSACKRECOVERY = 25,\n\tLINUX_MIB_TCPSACKRENEGING = 26,\n\tLINUX_MIB_TCPSACKREORDER = 27,\n\tLINUX_MIB_TCPRENOREORDER = 28,\n\tLINUX_MIB_TCPTSREORDER = 29,\n\tLINUX_MIB_TCPFULLUNDO = 30,\n\tLINUX_MIB_TCPPARTIALUNDO = 31,\n\tLINUX_MIB_TCPDSACKUNDO = 32,\n\tLINUX_MIB_TCPLOSSUNDO = 33,\n\tLINUX_MIB_TCPLOSTRETRANSMIT = 34,\n\tLINUX_MIB_TCPRENOFAILURES = 35,\n\tLINUX_MIB_TCPSACKFAILURES = 36,\n\tLINUX_MIB_TCPLOSSFAILURES = 37,\n\tLINUX_MIB_TCPFASTRETRANS = 38,\n\tLINUX_MIB_TCPSLOWSTARTRETRANS = 39,\n\tLINUX_MIB_TCPTIMEOUTS = 40,\n\tLINUX_MIB_TCPLOSSPROBES = 41,\n\tLINUX_MIB_TCPLOSSPROBERECOVERY = 42,\n\tLINUX_MIB_TCPRENORECOVERYFAIL = 43,\n\tLINUX_MIB_TCPSACKRECOVERYFAIL = 44,\n\tLINUX_MIB_TCPRCVCOLLAPSED = 45,\n\tLINUX_MIB_TCPDSACKOLDSENT = 46,\n\tLINUX_MIB_TCPDSACKOFOSENT = 47,\n\tLINUX_MIB_TCPDSACKRECV = 48,\n\tLINUX_MIB_TCPDSACKOFORECV = 49,\n\tLINUX_MIB_TCPABORTONDATA = 50,\n\tLINUX_MIB_TCPABORTONCLOSE = 51,\n\tLINUX_MIB_TCPABORTONMEMORY = 52,\n\tLINUX_MIB_TCPABORTONTIMEOUT = 53,\n\tLINUX_MIB_TCPABORTONLINGER = 54,\n\tLINUX_MIB_TCPABORTFAILED = 55,\n\tLINUX_MIB_TCPMEMORYPRESSURES = 56,\n\tLINUX_MIB_TCPMEMORYPRESSURESCHRONO = 57,\n\tLINUX_MIB_TCPSACKDISCARD = 58,\n\tLINUX_MIB_TCPDSACKIGNOREDOLD = 59,\n\tLINUX_MIB_TCPDSACKIGNOREDNOUNDO = 60,\n\tLINUX_MIB_TCPSPURIOUSRTOS = 61,\n\tLINUX_MIB_TCPMD5NOTFOUND = 62,\n\tLINUX_MIB_TCPMD5UNEXPECTED = 63,\n\tLINUX_MIB_TCPMD5FAILURE = 64,\n\tLINUX_MIB_SACKSHIFTED = 65,\n\tLINUX_MIB_SACKMERGED = 66,\n\tLINUX_MIB_SACKSHIFTFALLBACK = 67,\n\tLINUX_MIB_TCPBACKLOGDROP = 68,\n\tLINUX_MIB_PFMEMALLOCDROP = 69,\n\tLINUX_MIB_TCPMINTTLDROP = 70,\n\tLINUX_MIB_TCPDEFERACCEPTDROP = 71,\n\tLINUX_MIB_IPRPFILTER = 72,\n\tLINUX_MIB_TCPTIMEWAITOVERFLOW = 73,\n\tLINUX_MIB_TCPREQQFULLDOCOOKIES = 74,\n\tLINUX_MIB_TCPREQQFULLDROP = 75,\n\tLINUX_MIB_TCPRETRANSFAIL = 76,\n\tLINUX_MIB_TCPRCVCOALESCE = 77,\n\tLINUX_MIB_TCPBACKLOGCOALESCE = 78,\n\tLINUX_MIB_TCPOFOQUEUE = 79,\n\tLINUX_MIB_TCPOFODROP = 80,\n\tLINUX_MIB_TCPOFOMERGE = 81,\n\tLINUX_MIB_TCPCHALLENGEACK = 82,\n\tLINUX_MIB_TCPSYNCHALLENGE = 83,\n\tLINUX_MIB_TCPFASTOPENACTIVE = 84,\n\tLINUX_MIB_TCPFASTOPENACTIVEFAIL = 85,\n\tLINUX_MIB_TCPFASTOPENPASSIVE = 86,\n\tLINUX_MIB_TCPFASTOPENPASSIVEFAIL = 87,\n\tLINUX_MIB_TCPFASTOPENLISTENOVERFLOW = 88,\n\tLINUX_MIB_TCPFASTOPENCOOKIEREQD = 89,\n\tLINUX_MIB_TCPFASTOPENBLACKHOLE = 90,\n\tLINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES = 91,\n\tLINUX_MIB_BUSYPOLLRXPACKETS = 92,\n\tLINUX_MIB_TCPAUTOCORKING = 93,\n\tLINUX_MIB_TCPFROMZEROWINDOWADV = 94,\n\tLINUX_MIB_TCPTOZEROWINDOWADV = 95,\n\tLINUX_MIB_TCPWANTZEROWINDOWADV = 96,\n\tLINUX_MIB_TCPSYNRETRANS = 97,\n\tLINUX_MIB_TCPORIGDATASENT = 98,\n\tLINUX_MIB_TCPHYSTARTTRAINDETECT = 99,\n\tLINUX_MIB_TCPHYSTARTTRAINCWND = 100,\n\tLINUX_MIB_TCPHYSTARTDELAYDETECT = 101,\n\tLINUX_MIB_TCPHYSTARTDELAYCWND = 102,\n\tLINUX_MIB_TCPACKSKIPPEDSYNRECV = 103,\n\tLINUX_MIB_TCPACKSKIPPEDPAWS = 104,\n\tLINUX_MIB_TCPACKSKIPPEDSEQ = 105,\n\tLINUX_MIB_TCPACKSKIPPEDFINWAIT2 = 106,\n\tLINUX_MIB_TCPACKSKIPPEDTIMEWAIT = 107,\n\tLINUX_MIB_TCPACKSKIPPEDCHALLENGE = 108,\n\tLINUX_MIB_TCPWINPROBE = 109,\n\tLINUX_MIB_TCPKEEPALIVE = 110,\n\tLINUX_MIB_TCPMTUPFAIL = 111,\n\tLINUX_MIB_TCPMTUPSUCCESS = 112,\n\tLINUX_MIB_TCPDELIVERED = 113,\n\tLINUX_MIB_TCPDELIVEREDCE = 114,\n\tLINUX_MIB_TCPACKCOMPRESSED = 115,\n\tLINUX_MIB_TCPZEROWINDOWDROP = 116,\n\tLINUX_MIB_TCPRCVQDROP = 117,\n\tLINUX_MIB_TCPWQUEUETOOBIG = 118,\n\tLINUX_MIB_TCPFASTOPENPASSIVEALTKEY = 119,\n\tLINUX_MIB_TCPTIMEOUTREHASH = 120,\n\tLINUX_MIB_TCPDUPLICATEDATAREHASH = 121,\n\tLINUX_MIB_TCPDSACKRECVSEGS = 122,\n\tLINUX_MIB_TCPDSACKIGNOREDDUBIOUS = 123,\n\tLINUX_MIB_TCPMIGRATEREQSUCCESS = 124,\n\tLINUX_MIB_TCPMIGRATEREQFAILURE = 125,\n\t__LINUX_MIB_MAX = 126,\n};\n\nenum {\n\tLINUX_MIB_XFRMNUM = 0,\n\tLINUX_MIB_XFRMINERROR = 1,\n\tLINUX_MIB_XFRMINBUFFERERROR = 2,\n\tLINUX_MIB_XFRMINHDRERROR = 3,\n\tLINUX_MIB_XFRMINNOSTATES = 4,\n\tLINUX_MIB_XFRMINSTATEPROTOERROR = 5,\n\tLINUX_MIB_XFRMINSTATEMODEERROR = 6,\n\tLINUX_MIB_XFRMINSTATESEQERROR = 7,\n\tLINUX_MIB_XFRMINSTATEEXPIRED = 8,\n\tLINUX_MIB_XFRMINSTATEMISMATCH = 9,\n\tLINUX_MIB_XFRMINSTATEINVALID = 10,\n\tLINUX_MIB_XFRMINTMPLMISMATCH = 11,\n\tLINUX_MIB_XFRMINNOPOLS = 12,\n\tLINUX_MIB_XFRMINPOLBLOCK = 13,\n\tLINUX_MIB_XFRMINPOLERROR = 14,\n\tLINUX_MIB_XFRMOUTERROR = 15,\n\tLINUX_MIB_XFRMOUTBUNDLEGENERROR = 16,\n\tLINUX_MIB_XFRMOUTBUNDLECHECKERROR = 17,\n\tLINUX_MIB_XFRMOUTNOSTATES = 18,\n\tLINUX_MIB_XFRMOUTSTATEPROTOERROR = 19,\n\tLINUX_MIB_XFRMOUTSTATEMODEERROR = 20,\n\tLINUX_MIB_XFRMOUTSTATESEQERROR = 21,\n\tLINUX_MIB_XFRMOUTSTATEEXPIRED = 22,\n\tLINUX_MIB_XFRMOUTPOLBLOCK = 23,\n\tLINUX_MIB_XFRMOUTPOLDEAD = 24,\n\tLINUX_MIB_XFRMOUTPOLERROR = 25,\n\tLINUX_MIB_XFRMFWDHDRERROR = 26,\n\tLINUX_MIB_XFRMOUTSTATEINVALID = 27,\n\tLINUX_MIB_XFRMACQUIREERROR = 28,\n\t__LINUX_MIB_XFRMMAX = 29,\n};\n\nenum {\n\tLINUX_MIB_TLSNUM = 0,\n\tLINUX_MIB_TLSCURRTXSW = 1,\n\tLINUX_MIB_TLSCURRRXSW = 2,\n\tLINUX_MIB_TLSCURRTXDEVICE = 3,\n\tLINUX_MIB_TLSCURRRXDEVICE = 4,\n\tLINUX_MIB_TLSTXSW = 5,\n\tLINUX_MIB_TLSRXSW = 6,\n\tLINUX_MIB_TLSTXDEVICE = 7,\n\tLINUX_MIB_TLSRXDEVICE = 8,\n\tLINUX_MIB_TLSDECRYPTERROR = 9,\n\tLINUX_MIB_TLSRXDEVICERESYNC = 10,\n\t__LINUX_MIB_TLSMAX = 11,\n};\n\nenum nf_inet_hooks {\n\tNF_INET_PRE_ROUTING = 0,\n\tNF_INET_LOCAL_IN = 1,\n\tNF_INET_FORWARD = 2,\n\tNF_INET_LOCAL_OUT = 3,\n\tNF_INET_POST_ROUTING = 4,\n\tNF_INET_NUMHOOKS = 5,\n\tNF_INET_INGRESS = 5,\n};\n\nenum {\n\tNFPROTO_UNSPEC = 0,\n\tNFPROTO_INET = 1,\n\tNFPROTO_IPV4 = 2,\n\tNFPROTO_ARP = 3,\n\tNFPROTO_NETDEV = 5,\n\tNFPROTO_BRIDGE = 7,\n\tNFPROTO_IPV6 = 10,\n\tNFPROTO_DECNET = 12,\n\tNFPROTO_NUMPROTO = 13,\n};\n\nenum tcp_conntrack {\n\tTCP_CONNTRACK_NONE = 0,\n\tTCP_CONNTRACK_SYN_SENT = 1,\n\tTCP_CONNTRACK_SYN_RECV = 2,\n\tTCP_CONNTRACK_ESTABLISHED = 3,\n\tTCP_CONNTRACK_FIN_WAIT = 4,\n\tTCP_CONNTRACK_CLOSE_WAIT = 5,\n\tTCP_CONNTRACK_LAST_ACK = 6,\n\tTCP_CONNTRACK_TIME_WAIT = 7,\n\tTCP_CONNTRACK_CLOSE = 8,\n\tTCP_CONNTRACK_LISTEN = 9,\n\tTCP_CONNTRACK_MAX = 10,\n\tTCP_CONNTRACK_IGNORE = 11,\n\tTCP_CONNTRACK_RETRANS = 12,\n\tTCP_CONNTRACK_UNACK = 13,\n\tTCP_CONNTRACK_TIMEOUT_MAX = 14,\n};\n\nenum ct_dccp_states {\n\tCT_DCCP_NONE = 0,\n\tCT_DCCP_REQUEST = 1,\n\tCT_DCCP_RESPOND = 2,\n\tCT_DCCP_PARTOPEN = 3,\n\tCT_DCCP_OPEN = 4,\n\tCT_DCCP_CLOSEREQ = 5,\n\tCT_DCCP_CLOSING = 6,\n\tCT_DCCP_TIMEWAIT = 7,\n\tCT_DCCP_IGNORE = 8,\n\tCT_DCCP_INVALID = 9,\n\t__CT_DCCP_MAX = 10,\n};\n\nenum ip_conntrack_dir {\n\tIP_CT_DIR_ORIGINAL = 0,\n\tIP_CT_DIR_REPLY = 1,\n\tIP_CT_DIR_MAX = 2,\n};\n\nenum sctp_conntrack {\n\tSCTP_CONNTRACK_NONE = 0,\n\tSCTP_CONNTRACK_CLOSED = 1,\n\tSCTP_CONNTRACK_COOKIE_WAIT = 2,\n\tSCTP_CONNTRACK_COOKIE_ECHOED = 3,\n\tSCTP_CONNTRACK_ESTABLISHED = 4,\n\tSCTP_CONNTRACK_SHUTDOWN_SENT = 5,\n\tSCTP_CONNTRACK_SHUTDOWN_RECD = 6,\n\tSCTP_CONNTRACK_SHUTDOWN_ACK_SENT = 7,\n\tSCTP_CONNTRACK_HEARTBEAT_SENT = 8,\n\tSCTP_CONNTRACK_HEARTBEAT_ACKED = 9,\n\tSCTP_CONNTRACK_MAX = 10,\n};\n\nenum udp_conntrack {\n\tUDP_CT_UNREPLIED = 0,\n\tUDP_CT_REPLIED = 1,\n\tUDP_CT_MAX = 2,\n};\n\nenum gre_conntrack {\n\tGRE_CT_UNREPLIED = 0,\n\tGRE_CT_REPLIED = 1,\n\tGRE_CT_MAX = 2,\n};\n\nenum {\n\tXFRM_POLICY_IN = 0,\n\tXFRM_POLICY_OUT = 1,\n\tXFRM_POLICY_FWD = 2,\n\tXFRM_POLICY_MASK = 3,\n\tXFRM_POLICY_MAX = 3,\n};\n\nenum netns_bpf_attach_type {\n\tNETNS_BPF_INVALID = 4294967295,\n\tNETNS_BPF_FLOW_DISSECTOR = 0,\n\tNETNS_BPF_SK_LOOKUP = 1,\n\tMAX_NETNS_BPF_ATTACH_TYPE = 2,\n};\n\nenum skb_ext_id {\n\tSKB_EXT_BRIDGE_NF = 0,\n\tSKB_EXT_SEC_PATH = 1,\n\tTC_SKB_EXT = 2,\n\tSKB_EXT_MPTCP = 3,\n\tSKB_EXT_NUM = 4,\n};\n\nenum audit_ntp_type {\n\tAUDIT_NTP_OFFSET = 0,\n\tAUDIT_NTP_FREQ = 1,\n\tAUDIT_NTP_STATUS = 2,\n\tAUDIT_NTP_TAI = 3,\n\tAUDIT_NTP_TICK = 4,\n\tAUDIT_NTP_ADJUST = 5,\n\tAUDIT_NTP_NVALS = 6,\n};\n\ntypedef long int (*sys_call_ptr_t)(const struct pt_regs *);\n\nstruct io_bitmap {\n\tu64 sequence;\n\trefcount_t refcnt;\n\tunsigned int max;\n\tlong unsigned int bitmap[1024];\n};\n\nenum irqreturn {\n\tIRQ_NONE = 0,\n\tIRQ_HANDLED = 1,\n\tIRQ_WAKE_THREAD = 2,\n};\n\ntypedef enum irqreturn irqreturn_t;\n\ntypedef struct {\n\tu16 __softirq_pending;\n\tu8 kvm_cpu_l1tf_flush_l1d;\n\tunsigned int __nmi_count;\n\tunsigned int apic_timer_irqs;\n\tunsigned int irq_spurious_count;\n\tunsigned int icr_read_retry_count;\n\tunsigned int kvm_posted_intr_ipis;\n\tunsigned int kvm_posted_intr_wakeup_ipis;\n\tunsigned int kvm_posted_intr_nested_ipis;\n\tunsigned int x86_platform_ipis;\n\tunsigned int apic_perf_irqs;\n\tunsigned int apic_irq_work_irqs;\n\tunsigned int irq_resched_count;\n\tunsigned int irq_call_count;\n\tunsigned int irq_tlb_count;\n\tunsigned int irq_thermal_count;\n\tunsigned int irq_threshold_count;\n\tunsigned int irq_deferred_error_count;\n\tunsigned int irq_hv_callback_count;\n\tunsigned int irq_hv_reenlightenment_count;\n\tunsigned int hyperv_stimer0_count;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n} irq_cpustat_t;\n\ntypedef irqreturn_t (*irq_handler_t)(int, void *);\n\nstruct irqaction {\n\tirq_handler_t handler;\n\tvoid *dev_id;\n\tvoid *percpu_dev_id;\n\tstruct irqaction *next;\n\tirq_handler_t thread_fn;\n\tstruct task_struct *thread;\n\tstruct irqaction *secondary;\n\tunsigned int irq;\n\tunsigned int flags;\n\tlong unsigned int thread_flags;\n\tlong unsigned int thread_mask;\n\tconst char *name;\n\tstruct proc_dir_entry *dir;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct irq_affinity_notify {\n\tunsigned int irq;\n\tstruct kref kref;\n\tstruct work_struct work;\n\tvoid (*notify)(struct irq_affinity_notify *, const cpumask_t *);\n\tvoid (*release)(struct kref *);\n};\n\nstruct irq_affinity_desc {\n\tstruct cpumask mask;\n\tunsigned int is_managed: 1;\n};\n\nenum irqchip_irq_state {\n\tIRQCHIP_STATE_PENDING = 0,\n\tIRQCHIP_STATE_ACTIVE = 1,\n\tIRQCHIP_STATE_MASKED = 2,\n\tIRQCHIP_STATE_LINE_LEVEL = 3,\n};\n\nenum {\n\tEI_ETYPE_NONE = 0,\n\tEI_ETYPE_NULL = 1,\n\tEI_ETYPE_ERRNO = 2,\n\tEI_ETYPE_ERRNO_NULL = 3,\n\tEI_ETYPE_TRUE = 4,\n};\n\nstruct syscall_metadata {\n\tconst char *name;\n\tint syscall_nr;\n\tint nb_args;\n\tconst char **types;\n\tconst char **args;\n\tstruct list_head enter_fields;\n\tstruct trace_event_call *enter_event;\n\tstruct trace_event_call *exit_event;\n};\n\nstruct irqentry_state {\n\tunion {\n\t\tbool exit_rcu;\n\t\tbool lockdep;\n\t};\n};\n\ntypedef struct irqentry_state irqentry_state_t;\n\nstruct irq_desc;\n\ntypedef void (*irq_flow_handler_t)(struct irq_desc *);\n\nstruct msi_desc;\n\nstruct irq_common_data {\n\tunsigned int state_use_accessors;\n\tunsigned int node;\n\tvoid *handler_data;\n\tstruct msi_desc *msi_desc;\n\tcpumask_var_t affinity;\n\tcpumask_var_t effective_affinity;\n};\n\nstruct irq_chip;\n\nstruct irq_data {\n\tu32 mask;\n\tunsigned int irq;\n\tlong unsigned int hwirq;\n\tstruct irq_common_data *common;\n\tstruct irq_chip *chip;\n\tstruct irq_domain *domain;\n\tstruct irq_data *parent_data;\n\tvoid *chip_data;\n};\n\nstruct irq_desc {\n\tstruct irq_common_data irq_common_data;\n\tstruct irq_data irq_data;\n\tunsigned int *kstat_irqs;\n\tirq_flow_handler_t handle_irq;\n\tstruct irqaction *action;\n\tunsigned int status_use_accessors;\n\tunsigned int core_internal_state__do_not_mess_with_it;\n\tunsigned int depth;\n\tunsigned int wake_depth;\n\tunsigned int tot_count;\n\tunsigned int irq_count;\n\tlong unsigned int last_unhandled;\n\tunsigned int irqs_unhandled;\n\tatomic_t threads_handled;\n\tint threads_handled_last;\n\traw_spinlock_t lock;\n\tstruct cpumask *percpu_enabled;\n\tconst struct cpumask *percpu_affinity;\n\tconst struct cpumask *affinity_hint;\n\tstruct irq_affinity_notify *affinity_notify;\n\tcpumask_var_t pending_mask;\n\tlong unsigned int threads_oneshot;\n\tatomic_t threads_active;\n\twait_queue_head_t wait_for_threads;\n\tunsigned int nr_actions;\n\tunsigned int no_suspend_depth;\n\tunsigned int cond_suspend_depth;\n\tunsigned int force_resume_depth;\n\tstruct proc_dir_entry *dir;\n\tstruct callback_head rcu;\n\tstruct kobject kobj;\n\tstruct mutex request_mutex;\n\tint parent_irq;\n\tstruct module *owner;\n\tconst char *name;\n\tlong: 64;\n};\n\nstruct x86_msi_addr_lo {\n\tunion {\n\t\tstruct {\n\t\t\tu32 reserved_0: 2;\n\t\t\tu32 dest_mode_logical: 1;\n\t\t\tu32 redirect_hint: 1;\n\t\t\tu32 reserved_1: 1;\n\t\t\tu32 virt_destid_8_14: 7;\n\t\t\tu32 destid_0_7: 8;\n\t\t\tu32 base_address: 12;\n\t\t};\n\t\tstruct {\n\t\t\tu32 dmar_reserved_0: 2;\n\t\t\tu32 dmar_index_15: 1;\n\t\t\tu32 dmar_subhandle_valid: 1;\n\t\t\tu32 dmar_format: 1;\n\t\t\tu32 dmar_index_0_14: 15;\n\t\t\tu32 dmar_base_address: 12;\n\t\t};\n\t};\n};\n\ntypedef struct x86_msi_addr_lo arch_msi_msg_addr_lo_t;\n\nstruct x86_msi_addr_hi {\n\tu32 reserved: 8;\n\tu32 destid_8_31: 24;\n};\n\ntypedef struct x86_msi_addr_hi arch_msi_msg_addr_hi_t;\n\nstruct x86_msi_data {\n\tu32 vector: 8;\n\tu32 delivery_mode: 3;\n\tu32 dest_mode_logical: 1;\n\tu32 reserved: 2;\n\tu32 active_low: 1;\n\tu32 is_level: 1;\n\tu32 dmar_subhandle;\n} __attribute__((packed));\n\ntypedef struct x86_msi_data arch_msi_msg_data_t;\n\nstruct msi_msg {\n\tunion {\n\t\tu32 address_lo;\n\t\tarch_msi_msg_addr_lo_t arch_addr_lo;\n\t};\n\tunion {\n\t\tu32 address_hi;\n\t\tarch_msi_msg_addr_hi_t arch_addr_hi;\n\t};\n\tunion {\n\t\tu32 data;\n\t\tarch_msi_msg_data_t arch_data;\n\t};\n};\n\nstruct platform_msi_priv_data;\n\nstruct platform_msi_desc {\n\tstruct platform_msi_priv_data *msi_priv_data;\n\tu16 msi_index;\n};\n\nstruct fsl_mc_msi_desc {\n\tu16 msi_index;\n};\n\nstruct ti_sci_inta_msi_desc {\n\tu16 dev_index;\n};\n\nstruct msi_desc {\n\tstruct list_head list;\n\tunsigned int irq;\n\tunsigned int nvec_used;\n\tstruct device *dev;\n\tstruct msi_msg msg;\n\tstruct irq_affinity_desc *affinity;\n\tconst void *iommu_cookie;\n\tvoid (*write_msi_msg)(struct msi_desc *, void *);\n\tvoid *write_msi_msg_data;\n\tunion {\n\t\tstruct {\n\t\t\tu32 masked;\n\t\t\tstruct {\n\t\t\t\tu8 is_msix: 1;\n\t\t\t\tu8 multiple: 3;\n\t\t\t\tu8 multi_cap: 3;\n\t\t\t\tu8 maskbit: 1;\n\t\t\t\tu8 is_64: 1;\n\t\t\t\tu8 is_virtual: 1;\n\t\t\t\tu16 entry_nr;\n\t\t\t\tunsigned int default_irq;\n\t\t\t} msi_attrib;\n\t\t\tunion {\n\t\t\t\tu8 mask_pos;\n\t\t\t\tvoid *mask_base;\n\t\t\t};\n\t\t};\n\t\tstruct platform_msi_desc platform;\n\t\tstruct fsl_mc_msi_desc fsl_mc;\n\t\tstruct ti_sci_inta_msi_desc inta;\n\t};\n};\n\nstruct irq_chip {\n\tstruct device *parent_device;\n\tconst char *name;\n\tunsigned int (*irq_startup)(struct irq_data *);\n\tvoid (*irq_shutdown)(struct irq_data *);\n\tvoid (*irq_enable)(struct irq_data *);\n\tvoid (*irq_disable)(struct irq_data *);\n\tvoid (*irq_ack)(struct irq_data *);\n\tvoid (*irq_mask)(struct irq_data *);\n\tvoid (*irq_mask_ack)(struct irq_data *);\n\tvoid (*irq_unmask)(struct irq_data *);\n\tvoid (*irq_eoi)(struct irq_data *);\n\tint (*irq_set_affinity)(struct irq_data *, const struct cpumask *, bool);\n\tint (*irq_retrigger)(struct irq_data *);\n\tint (*irq_set_type)(struct irq_data *, unsigned int);\n\tint (*irq_set_wake)(struct irq_data *, unsigned int);\n\tvoid (*irq_bus_lock)(struct irq_data *);\n\tvoid (*irq_bus_sync_unlock)(struct irq_data *);\n\tvoid (*irq_cpu_online)(struct irq_data *);\n\tvoid (*irq_cpu_offline)(struct irq_data *);\n\tvoid (*irq_suspend)(struct irq_data *);\n\tvoid (*irq_resume)(struct irq_data *);\n\tvoid (*irq_pm_shutdown)(struct irq_data *);\n\tvoid (*irq_calc_mask)(struct irq_data *);\n\tvoid (*irq_print_chip)(struct irq_data *, struct seq_file *);\n\tint (*irq_request_resources)(struct irq_data *);\n\tvoid (*irq_release_resources)(struct irq_data *);\n\tvoid (*irq_compose_msi_msg)(struct irq_data *, struct msi_msg *);\n\tvoid (*irq_write_msi_msg)(struct irq_data *, struct msi_msg *);\n\tint (*irq_get_irqchip_state)(struct irq_data *, enum irqchip_irq_state, bool *);\n\tint (*irq_set_irqchip_state)(struct irq_data *, enum irqchip_irq_state, bool);\n\tint (*irq_set_vcpu_affinity)(struct irq_data *, void *);\n\tvoid (*ipi_send_single)(struct irq_data *, unsigned int);\n\tvoid (*ipi_send_mask)(struct irq_data *, const struct cpumask *);\n\tint (*irq_nmi_setup)(struct irq_data *);\n\tvoid (*irq_nmi_teardown)(struct irq_data *);\n\tlong unsigned int flags;\n};\n\nstruct irq_chip_regs {\n\tlong unsigned int enable;\n\tlong unsigned int disable;\n\tlong unsigned int mask;\n\tlong unsigned int ack;\n\tlong unsigned int eoi;\n\tlong unsigned int type;\n\tlong unsigned int polarity;\n};\n\nstruct irq_chip_type {\n\tstruct irq_chip chip;\n\tstruct irq_chip_regs regs;\n\tirq_flow_handler_t handler;\n\tu32 type;\n\tu32 mask_cache_priv;\n\tu32 *mask_cache;\n};\n\nstruct irq_chip_generic {\n\traw_spinlock_t lock;\n\tvoid *reg_base;\n\tu32 (*reg_readl)(void *);\n\tvoid (*reg_writel)(u32, void *);\n\tvoid (*suspend)(struct irq_chip_generic *);\n\tvoid (*resume)(struct irq_chip_generic *);\n\tunsigned int irq_base;\n\tunsigned int irq_cnt;\n\tu32 mask_cache;\n\tu32 type_cache;\n\tu32 polarity_cache;\n\tu32 wake_enabled;\n\tu32 wake_active;\n\tunsigned int num_ct;\n\tvoid *private;\n\tlong unsigned int installed;\n\tlong unsigned int unused;\n\tstruct irq_domain *domain;\n\tstruct list_head list;\n\tstruct irq_chip_type chip_types[0];\n};\n\nenum irq_gc_flags {\n\tIRQ_GC_INIT_MASK_CACHE = 1,\n\tIRQ_GC_INIT_NESTED_LOCK = 2,\n\tIRQ_GC_MASK_CACHE_PER_TYPE = 4,\n\tIRQ_GC_NO_MASK = 8,\n\tIRQ_GC_BE_IO = 16,\n};\n\nstruct irq_domain_chip_generic {\n\tunsigned int irqs_per_chip;\n\tunsigned int num_chips;\n\tunsigned int irq_flags_to_clear;\n\tunsigned int irq_flags_to_set;\n\tenum irq_gc_flags gc_flags;\n\tstruct irq_chip_generic *gc[0];\n};\n\nstruct alt_instr {\n\ts32 instr_offset;\n\ts32 repl_offset;\n\tu16 cpuid;\n\tu8 instrlen;\n\tu8 replacementlen;\n};\n\nstruct timens_offset {\n\ts64 sec;\n\tu64 nsec;\n};\n\nenum vm_fault_reason {\n\tVM_FAULT_OOM = 1,\n\tVM_FAULT_SIGBUS = 2,\n\tVM_FAULT_MAJOR = 4,\n\tVM_FAULT_WRITE = 8,\n\tVM_FAULT_HWPOISON = 16,\n\tVM_FAULT_HWPOISON_LARGE = 32,\n\tVM_FAULT_SIGSEGV = 64,\n\tVM_FAULT_NOPAGE = 256,\n\tVM_FAULT_LOCKED = 512,\n\tVM_FAULT_RETRY = 1024,\n\tVM_FAULT_FALLBACK = 2048,\n\tVM_FAULT_DONE_COW = 4096,\n\tVM_FAULT_NEEDDSYNC = 8192,\n\tVM_FAULT_HINDEX_MASK = 983040,\n};\n\nstruct vm_special_mapping {\n\tconst char *name;\n\tstruct page **pages;\n\tvm_fault_t (*fault)(const struct vm_special_mapping *, struct vm_area_struct *, struct vm_fault *);\n\tint (*mremap)(const struct vm_special_mapping *, struct vm_area_struct *);\n};\n\nstruct timens_offsets {\n\tstruct timespec64 monotonic;\n\tstruct timespec64 boottime;\n};\n\nstruct time_namespace {\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tstruct ns_common ns;\n\tstruct timens_offsets offsets;\n\tstruct page *vvar_page;\n\tbool frozen_offsets;\n};\n\nstruct pvclock_vcpu_time_info {\n\tu32 version;\n\tu32 pad0;\n\tu64 tsc_timestamp;\n\tu64 system_time;\n\tu32 tsc_to_system_mul;\n\ts8 tsc_shift;\n\tu8 flags;\n\tu8 pad[2];\n};\n\nstruct pvclock_vsyscall_time_info {\n\tstruct pvclock_vcpu_time_info pvti;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum vdso_clock_mode {\n\tVDSO_CLOCKMODE_NONE = 0,\n\tVDSO_CLOCKMODE_TSC = 1,\n\tVDSO_CLOCKMODE_PVCLOCK = 2,\n\tVDSO_CLOCKMODE_HVCLOCK = 3,\n\tVDSO_CLOCKMODE_MAX = 4,\n\tVDSO_CLOCKMODE_TIMENS = 2147483647,\n};\n\nstruct arch_vdso_data {};\n\nstruct vdso_timestamp {\n\tu64 sec;\n\tu64 nsec;\n};\n\nstruct vdso_data {\n\tu32 seq;\n\ts32 clock_mode;\n\tu64 cycle_last;\n\tu64 mask;\n\tu32 mult;\n\tu32 shift;\n\tunion {\n\t\tstruct vdso_timestamp basetime[12];\n\t\tstruct timens_offset offset[12];\n\t};\n\ts32 tz_minuteswest;\n\ts32 tz_dsttime;\n\tu32 hrtimer_res;\n\tu32 __unused;\n\tstruct arch_vdso_data arch_data;\n};\n\nstruct ms_hyperv_tsc_page {\n\tvolatile u32 tsc_sequence;\n\tu32 reserved1;\n\tvolatile u64 tsc_scale;\n\tvolatile s64 tsc_offset;\n};\n\nenum {\n\tTASKSTATS_CMD_UNSPEC = 0,\n\tTASKSTATS_CMD_GET = 1,\n\tTASKSTATS_CMD_NEW = 2,\n\t__TASKSTATS_CMD_MAX = 3,\n};\n\nenum cpu_usage_stat {\n\tCPUTIME_USER = 0,\n\tCPUTIME_NICE = 1,\n\tCPUTIME_SYSTEM = 2,\n\tCPUTIME_SOFTIRQ = 3,\n\tCPUTIME_IRQ = 4,\n\tCPUTIME_IDLE = 5,\n\tCPUTIME_IOWAIT = 6,\n\tCPUTIME_STEAL = 7,\n\tCPUTIME_GUEST = 8,\n\tCPUTIME_GUEST_NICE = 9,\n\tNR_STATS = 10,\n};\n\nenum bpf_cgroup_storage_type {\n\tBPF_CGROUP_STORAGE_SHARED = 0,\n\tBPF_CGROUP_STORAGE_PERCPU = 1,\n\t__BPF_CGROUP_STORAGE_MAX = 2,\n};\n\nenum bpf_tramp_prog_type {\n\tBPF_TRAMP_FENTRY = 0,\n\tBPF_TRAMP_FEXIT = 1,\n\tBPF_TRAMP_MODIFY_RETURN = 2,\n\tBPF_TRAMP_MAX = 3,\n\tBPF_TRAMP_REPLACE = 4,\n};\n\nenum psi_task_count {\n\tNR_IOWAIT = 0,\n\tNR_MEMSTALL = 1,\n\tNR_RUNNING = 2,\n\tNR_ONCPU = 3,\n\tNR_PSI_TASK_COUNTS = 4,\n};\n\nenum psi_states {\n\tPSI_IO_SOME = 0,\n\tPSI_IO_FULL = 1,\n\tPSI_MEM_SOME = 2,\n\tPSI_MEM_FULL = 3,\n\tPSI_CPU_SOME = 4,\n\tPSI_CPU_FULL = 5,\n\tPSI_NONIDLE = 6,\n\tNR_PSI_STATES = 7,\n};\n\nenum psi_aggregators {\n\tPSI_AVGS = 0,\n\tPSI_POLL = 1,\n\tNR_PSI_AGGREGATORS = 2,\n};\n\nenum cgroup_subsys_id {\n\tcpuset_cgrp_id = 0,\n\tcpu_cgrp_id = 1,\n\tcpuacct_cgrp_id = 2,\n\tio_cgrp_id = 3,\n\tmemory_cgrp_id = 4,\n\tdevices_cgrp_id = 5,\n\tfreezer_cgrp_id = 6,\n\tnet_cls_cgrp_id = 7,\n\tperf_event_cgrp_id = 8,\n\tnet_prio_cgrp_id = 9,\n\thugetlb_cgrp_id = 10,\n\tpids_cgrp_id = 11,\n\trdma_cgrp_id = 12,\n\tmisc_cgrp_id = 13,\n\tCGROUP_SUBSYS_COUNT = 14,\n};\n\nstruct vdso_exception_table_entry {\n\tint insn;\n\tint fixup;\n};\n\nstruct cpuinfo_x86 {\n\t__u8 x86;\n\t__u8 x86_vendor;\n\t__u8 x86_model;\n\t__u8 x86_stepping;\n\tint x86_tlbsize;\n\t__u32 vmx_capability[3];\n\t__u8 x86_virt_bits;\n\t__u8 x86_phys_bits;\n\t__u8 x86_coreid_bits;\n\t__u8 cu_id;\n\t__u32 extended_cpuid_level;\n\tint cpuid_level;\n\tunion {\n\t\t__u32 x86_capability[21];\n\t\tlong unsigned int x86_capability_alignment;\n\t};\n\tchar x86_vendor_id[16];\n\tchar x86_model_id[64];\n\tunsigned int x86_cache_size;\n\tint x86_cache_alignment;\n\tint x86_cache_max_rmid;\n\tint x86_cache_occ_scale;\n\tint x86_cache_mbm_width_offset;\n\tint x86_power;\n\tlong unsigned int loops_per_jiffy;\n\tu16 x86_max_cores;\n\tu16 apicid;\n\tu16 initial_apicid;\n\tu16 x86_clflush_size;\n\tu16 booted_cores;\n\tu16 phys_proc_id;\n\tu16 logical_proc_id;\n\tu16 cpu_core_id;\n\tu16 cpu_die_id;\n\tu16 logical_die_id;\n\tu16 cpu_index;\n\tu32 microcode;\n\tu8 x86_cache_bits;\n\tunsigned int initialized: 1;\n};\n\nenum syscall_work_bit {\n\tSYSCALL_WORK_BIT_SECCOMP = 0,\n\tSYSCALL_WORK_BIT_SYSCALL_TRACEPOINT = 1,\n\tSYSCALL_WORK_BIT_SYSCALL_TRACE = 2,\n\tSYSCALL_WORK_BIT_SYSCALL_EMU = 3,\n\tSYSCALL_WORK_BIT_SYSCALL_AUDIT = 4,\n\tSYSCALL_WORK_BIT_SYSCALL_USER_DISPATCH = 5,\n\tSYSCALL_WORK_BIT_SYSCALL_EXIT_TRAP = 6,\n};\n\nstruct seccomp_data {\n\tint nr;\n\t__u32 arch;\n\t__u64 instruction_pointer;\n\t__u64 args[6];\n};\n\nenum x86_pf_error_code {\n\tX86_PF_PROT = 1,\n\tX86_PF_WRITE = 2,\n\tX86_PF_USER = 4,\n\tX86_PF_RSVD = 8,\n\tX86_PF_INSTR = 16,\n\tX86_PF_PK = 32,\n\tX86_PF_SGX = 32768,\n};\n\nstruct trace_event_raw_emulate_vsyscall {\n\tstruct trace_entry ent;\n\tint nr;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_emulate_vsyscall {};\n\ntypedef void (*btf_trace_emulate_vsyscall)(void *, int);\n\nenum {\n\tEMULATE = 0,\n\tXONLY = 1,\n\tNONE = 2,\n};\n\nenum perf_type_id {\n\tPERF_TYPE_HARDWARE = 0,\n\tPERF_TYPE_SOFTWARE = 1,\n\tPERF_TYPE_TRACEPOINT = 2,\n\tPERF_TYPE_HW_CACHE = 3,\n\tPERF_TYPE_RAW = 4,\n\tPERF_TYPE_BREAKPOINT = 5,\n\tPERF_TYPE_MAX = 6,\n};\n\nenum perf_hw_id {\n\tPERF_COUNT_HW_CPU_CYCLES = 0,\n\tPERF_COUNT_HW_INSTRUCTIONS = 1,\n\tPERF_COUNT_HW_CACHE_REFERENCES = 2,\n\tPERF_COUNT_HW_CACHE_MISSES = 3,\n\tPERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,\n\tPERF_COUNT_HW_BRANCH_MISSES = 5,\n\tPERF_COUNT_HW_BUS_CYCLES = 6,\n\tPERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,\n\tPERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,\n\tPERF_COUNT_HW_REF_CPU_CYCLES = 9,\n\tPERF_COUNT_HW_MAX = 10,\n};\n\nenum perf_hw_cache_id {\n\tPERF_COUNT_HW_CACHE_L1D = 0,\n\tPERF_COUNT_HW_CACHE_L1I = 1,\n\tPERF_COUNT_HW_CACHE_LL = 2,\n\tPERF_COUNT_HW_CACHE_DTLB = 3,\n\tPERF_COUNT_HW_CACHE_ITLB = 4,\n\tPERF_COUNT_HW_CACHE_BPU = 5,\n\tPERF_COUNT_HW_CACHE_NODE = 6,\n\tPERF_COUNT_HW_CACHE_MAX = 7,\n};\n\nenum perf_hw_cache_op_id {\n\tPERF_COUNT_HW_CACHE_OP_READ = 0,\n\tPERF_COUNT_HW_CACHE_OP_WRITE = 1,\n\tPERF_COUNT_HW_CACHE_OP_PREFETCH = 2,\n\tPERF_COUNT_HW_CACHE_OP_MAX = 3,\n};\n\nenum perf_hw_cache_op_result_id {\n\tPERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,\n\tPERF_COUNT_HW_CACHE_RESULT_MISS = 1,\n\tPERF_COUNT_HW_CACHE_RESULT_MAX = 2,\n};\n\nenum perf_event_sample_format {\n\tPERF_SAMPLE_IP = 1,\n\tPERF_SAMPLE_TID = 2,\n\tPERF_SAMPLE_TIME = 4,\n\tPERF_SAMPLE_ADDR = 8,\n\tPERF_SAMPLE_READ = 16,\n\tPERF_SAMPLE_CALLCHAIN = 32,\n\tPERF_SAMPLE_ID = 64,\n\tPERF_SAMPLE_CPU = 128,\n\tPERF_SAMPLE_PERIOD = 256,\n\tPERF_SAMPLE_STREAM_ID = 512,\n\tPERF_SAMPLE_RAW = 1024,\n\tPERF_SAMPLE_BRANCH_STACK = 2048,\n\tPERF_SAMPLE_REGS_USER = 4096,\n\tPERF_SAMPLE_STACK_USER = 8192,\n\tPERF_SAMPLE_WEIGHT = 16384,\n\tPERF_SAMPLE_DATA_SRC = 32768,\n\tPERF_SAMPLE_IDENTIFIER = 65536,\n\tPERF_SAMPLE_TRANSACTION = 131072,\n\tPERF_SAMPLE_REGS_INTR = 262144,\n\tPERF_SAMPLE_PHYS_ADDR = 524288,\n\tPERF_SAMPLE_AUX = 1048576,\n\tPERF_SAMPLE_CGROUP = 2097152,\n\tPERF_SAMPLE_DATA_PAGE_SIZE = 4194304,\n\tPERF_SAMPLE_CODE_PAGE_SIZE = 8388608,\n\tPERF_SAMPLE_WEIGHT_STRUCT = 16777216,\n\tPERF_SAMPLE_MAX = 33554432,\n\t__PERF_SAMPLE_CALLCHAIN_EARLY = 0,\n};\n\nenum perf_branch_sample_type {\n\tPERF_SAMPLE_BRANCH_USER = 1,\n\tPERF_SAMPLE_BRANCH_KERNEL = 2,\n\tPERF_SAMPLE_BRANCH_HV = 4,\n\tPERF_SAMPLE_BRANCH_ANY = 8,\n\tPERF_SAMPLE_BRANCH_ANY_CALL = 16,\n\tPERF_SAMPLE_BRANCH_ANY_RETURN = 32,\n\tPERF_SAMPLE_BRANCH_IND_CALL = 64,\n\tPERF_SAMPLE_BRANCH_ABORT_TX = 128,\n\tPERF_SAMPLE_BRANCH_IN_TX = 256,\n\tPERF_SAMPLE_BRANCH_NO_TX = 512,\n\tPERF_SAMPLE_BRANCH_COND = 1024,\n\tPERF_SAMPLE_BRANCH_CALL_STACK = 2048,\n\tPERF_SAMPLE_BRANCH_IND_JUMP = 4096,\n\tPERF_SAMPLE_BRANCH_CALL = 8192,\n\tPERF_SAMPLE_BRANCH_NO_FLAGS = 16384,\n\tPERF_SAMPLE_BRANCH_NO_CYCLES = 32768,\n\tPERF_SAMPLE_BRANCH_TYPE_SAVE = 65536,\n\tPERF_SAMPLE_BRANCH_HW_INDEX = 131072,\n\tPERF_SAMPLE_BRANCH_MAX = 262144,\n};\n\nstruct perf_event_mmap_page {\n\t__u32 version;\n\t__u32 compat_version;\n\t__u32 lock;\n\t__u32 index;\n\t__s64 offset;\n\t__u64 time_enabled;\n\t__u64 time_running;\n\tunion {\n\t\t__u64 capabilities;\n\t\tstruct {\n\t\t\t__u64 cap_bit0: 1;\n\t\t\t__u64 cap_bit0_is_deprecated: 1;\n\t\t\t__u64 cap_user_rdpmc: 1;\n\t\t\t__u64 cap_user_time: 1;\n\t\t\t__u64 cap_user_time_zero: 1;\n\t\t\t__u64 cap_user_time_short: 1;\n\t\t\t__u64 cap_____res: 58;\n\t\t};\n\t};\n\t__u16 pmc_width;\n\t__u16 time_shift;\n\t__u32 time_mult;\n\t__u64 time_offset;\n\t__u64 time_zero;\n\t__u32 size;\n\t__u32 __reserved_1;\n\t__u64 time_cycles;\n\t__u64 time_mask;\n\t__u8 __reserved[928];\n\t__u64 data_head;\n\t__u64 data_tail;\n\t__u64 data_offset;\n\t__u64 data_size;\n\t__u64 aux_head;\n\t__u64 aux_tail;\n\t__u64 aux_offset;\n\t__u64 aux_size;\n};\n\nstruct pv_info {\n\tu16 extra_user_64bit_cs;\n\tconst char *name;\n};\n\ntypedef bool (*smp_cond_func_t)(int, void *);\n\nstruct ldt_struct {\n\tstruct desc_struct *entries;\n\tunsigned int nr_entries;\n\tint slot;\n};\n\nenum apic_delivery_modes {\n\tAPIC_DELIVERY_MODE_FIXED = 0,\n\tAPIC_DELIVERY_MODE_LOWESTPRIO = 1,\n\tAPIC_DELIVERY_MODE_SMI = 2,\n\tAPIC_DELIVERY_MODE_NMI = 4,\n\tAPIC_DELIVERY_MODE_INIT = 5,\n\tAPIC_DELIVERY_MODE_EXTINT = 7,\n};\n\nstruct physid_mask {\n\tlong unsigned int mask[512];\n};\n\ntypedef struct physid_mask physid_mask_t;\n\nstruct x86_pmu_capability {\n\tint version;\n\tint num_counters_gp;\n\tint num_counters_fixed;\n\tint bit_width_gp;\n\tint bit_width_fixed;\n\tunsigned int events_mask;\n\tint events_mask_len;\n};\n\nstruct debug_store {\n\tu64 bts_buffer_base;\n\tu64 bts_index;\n\tu64 bts_absolute_maximum;\n\tu64 bts_interrupt_threshold;\n\tu64 pebs_buffer_base;\n\tu64 pebs_index;\n\tu64 pebs_absolute_maximum;\n\tu64 pebs_interrupt_threshold;\n\tu64 pebs_event_reset[12];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum stack_type {\n\tSTACK_TYPE_UNKNOWN = 0,\n\tSTACK_TYPE_TASK = 1,\n\tSTACK_TYPE_IRQ = 2,\n\tSTACK_TYPE_SOFTIRQ = 3,\n\tSTACK_TYPE_ENTRY = 4,\n\tSTACK_TYPE_EXCEPTION = 5,\n\tSTACK_TYPE_EXCEPTION_LAST = 10,\n};\n\nstruct stack_info {\n\tenum stack_type type;\n\tlong unsigned int *begin;\n\tlong unsigned int *end;\n\tlong unsigned int *next_sp;\n};\n\nstruct stack_frame {\n\tstruct stack_frame *next_frame;\n\tlong unsigned int return_address;\n};\n\nstruct stack_frame_ia32 {\n\tu32 next_frame;\n\tu32 return_address;\n};\n\nstruct perf_guest_switch_msr {\n\tunsigned int msr;\n\tu64 host;\n\tu64 guest;\n};\n\nstruct perf_guest_info_callbacks {\n\tint (*is_in_guest)();\n\tint (*is_user_mode)();\n\tlong unsigned int (*get_guest_ip)();\n\tvoid (*handle_intel_pt_intr)();\n};\n\nstruct device_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct device *, struct device_attribute *, char *);\n\tssize_t (*store)(struct device *, struct device_attribute *, const char *, size_t);\n};\n\nenum perf_event_x86_regs {\n\tPERF_REG_X86_AX = 0,\n\tPERF_REG_X86_BX = 1,\n\tPERF_REG_X86_CX = 2,\n\tPERF_REG_X86_DX = 3,\n\tPERF_REG_X86_SI = 4,\n\tPERF_REG_X86_DI = 5,\n\tPERF_REG_X86_BP = 6,\n\tPERF_REG_X86_SP = 7,\n\tPERF_REG_X86_IP = 8,\n\tPERF_REG_X86_FLAGS = 9,\n\tPERF_REG_X86_CS = 10,\n\tPERF_REG_X86_SS = 11,\n\tPERF_REG_X86_DS = 12,\n\tPERF_REG_X86_ES = 13,\n\tPERF_REG_X86_FS = 14,\n\tPERF_REG_X86_GS = 15,\n\tPERF_REG_X86_R8 = 16,\n\tPERF_REG_X86_R9 = 17,\n\tPERF_REG_X86_R10 = 18,\n\tPERF_REG_X86_R11 = 19,\n\tPERF_REG_X86_R12 = 20,\n\tPERF_REG_X86_R13 = 21,\n\tPERF_REG_X86_R14 = 22,\n\tPERF_REG_X86_R15 = 23,\n\tPERF_REG_X86_32_MAX = 16,\n\tPERF_REG_X86_64_MAX = 24,\n\tPERF_REG_X86_XMM0 = 32,\n\tPERF_REG_X86_XMM1 = 34,\n\tPERF_REG_X86_XMM2 = 36,\n\tPERF_REG_X86_XMM3 = 38,\n\tPERF_REG_X86_XMM4 = 40,\n\tPERF_REG_X86_XMM5 = 42,\n\tPERF_REG_X86_XMM6 = 44,\n\tPERF_REG_X86_XMM7 = 46,\n\tPERF_REG_X86_XMM8 = 48,\n\tPERF_REG_X86_XMM9 = 50,\n\tPERF_REG_X86_XMM10 = 52,\n\tPERF_REG_X86_XMM11 = 54,\n\tPERF_REG_X86_XMM12 = 56,\n\tPERF_REG_X86_XMM13 = 58,\n\tPERF_REG_X86_XMM14 = 60,\n\tPERF_REG_X86_XMM15 = 62,\n\tPERF_REG_X86_XMM_MAX = 64,\n};\n\nstruct perf_callchain_entry_ctx {\n\tstruct perf_callchain_entry *entry;\n\tu32 max_stack;\n\tu32 nr;\n\tshort int contexts;\n\tbool contexts_maxed;\n};\n\nstruct perf_pmu_events_attr {\n\tstruct device_attribute attr;\n\tu64 id;\n\tconst char *event_str;\n};\n\nstruct perf_pmu_events_ht_attr {\n\tstruct device_attribute attr;\n\tu64 id;\n\tconst char *event_str_ht;\n\tconst char *event_str_noht;\n};\n\nstruct perf_pmu_events_hybrid_attr {\n\tstruct device_attribute attr;\n\tu64 id;\n\tconst char *event_str;\n\tu64 pmu_type;\n};\n\nstruct apic {\n\tvoid (*eoi_write)(u32, u32);\n\tvoid (*native_eoi_write)(u32, u32);\n\tvoid (*write)(u32, u32);\n\tu32 (*read)(u32);\n\tvoid (*wait_icr_idle)();\n\tu32 (*safe_wait_icr_idle)();\n\tvoid (*send_IPI)(int, int);\n\tvoid (*send_IPI_mask)(const struct cpumask *, int);\n\tvoid (*send_IPI_mask_allbutself)(const struct cpumask *, int);\n\tvoid (*send_IPI_allbutself)(int);\n\tvoid (*send_IPI_all)(int);\n\tvoid (*send_IPI_self)(int);\n\tu32 disable_esr;\n\tenum apic_delivery_modes delivery_mode;\n\tbool dest_mode_logical;\n\tu32 (*calc_dest_apicid)(unsigned int);\n\tu64 (*icr_read)();\n\tvoid (*icr_write)(u32, u32);\n\tint (*probe)();\n\tint (*acpi_madt_oem_check)(char *, char *);\n\tint (*apic_id_valid)(u32);\n\tint (*apic_id_registered)();\n\tbool (*check_apicid_used)(physid_mask_t *, int);\n\tvoid (*init_apic_ldr)();\n\tvoid (*ioapic_phys_id_map)(physid_mask_t *, physid_mask_t *);\n\tvoid (*setup_apic_routing)();\n\tint (*cpu_present_to_apicid)(int);\n\tvoid (*apicid_to_cpu_present)(int, physid_mask_t *);\n\tint (*check_phys_apicid_present)(int);\n\tint (*phys_pkg_id)(int, int);\n\tu32 (*get_apic_id)(long unsigned int);\n\tu32 (*set_apic_id)(unsigned int);\n\tint (*wakeup_secondary_cpu)(int, long unsigned int);\n\tvoid (*inquire_remote_apic)(int);\n\tchar *name;\n};\n\nenum {\n\tNMI_LOCAL = 0,\n\tNMI_UNKNOWN = 1,\n\tNMI_SERR = 2,\n\tNMI_IO_CHECK = 3,\n\tNMI_MAX = 4,\n};\n\ntypedef int (*nmi_handler_t)(unsigned int, struct pt_regs *);\n\nstruct nmiaction {\n\tstruct list_head list;\n\tnmi_handler_t handler;\n\tu64 max_duration;\n\tlong unsigned int flags;\n\tconst char *name;\n};\n\nstruct gdt_page {\n\tstruct desc_struct gdt[16];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct cyc2ns_data {\n\tu32 cyc2ns_mul;\n\tu32 cyc2ns_shift;\n\tu64 cyc2ns_offset;\n};\n\nstruct unwind_state {\n\tstruct stack_info stack_info;\n\tlong unsigned int stack_mask;\n\tstruct task_struct *task;\n\tint graph_idx;\n\tbool error;\n\tbool signal;\n\tbool full_regs;\n\tlong unsigned int sp;\n\tlong unsigned int bp;\n\tlong unsigned int ip;\n\tstruct pt_regs *regs;\n\tstruct pt_regs *prev_regs;\n};\n\nenum extra_reg_type {\n\tEXTRA_REG_NONE = 4294967295,\n\tEXTRA_REG_RSP_0 = 0,\n\tEXTRA_REG_RSP_1 = 1,\n\tEXTRA_REG_LBR = 2,\n\tEXTRA_REG_LDLAT = 3,\n\tEXTRA_REG_FE = 4,\n\tEXTRA_REG_MAX = 5,\n};\n\nstruct event_constraint {\n\tunion {\n\t\tlong unsigned int idxmsk[1];\n\t\tu64 idxmsk64;\n\t};\n\tu64 code;\n\tu64 cmask;\n\tint weight;\n\tint overlap;\n\tint flags;\n\tunsigned int size;\n};\n\nstruct amd_nb {\n\tint nb_id;\n\tint refcnt;\n\tstruct perf_event *owners[64];\n\tstruct event_constraint event_constraints[64];\n};\n\nstruct er_account {\n\traw_spinlock_t lock;\n\tu64 config;\n\tu64 reg;\n\tatomic_t ref;\n};\n\nstruct intel_shared_regs {\n\tstruct er_account regs[5];\n\tint refcnt;\n\tunsigned int core_id;\n};\n\nenum intel_excl_state_type {\n\tINTEL_EXCL_UNUSED = 0,\n\tINTEL_EXCL_SHARED = 1,\n\tINTEL_EXCL_EXCLUSIVE = 2,\n};\n\nstruct intel_excl_states {\n\tenum intel_excl_state_type state[64];\n\tbool sched_started;\n};\n\nstruct intel_excl_cntrs {\n\traw_spinlock_t lock;\n\tstruct intel_excl_states states[2];\n\tunion {\n\t\tu16 has_exclusive[2];\n\t\tu32 exclusive_present;\n\t};\n\tint refcnt;\n\tunsigned int core_id;\n};\n\nenum {\n\tX86_PERF_KFREE_SHARED = 0,\n\tX86_PERF_KFREE_EXCL = 1,\n\tX86_PERF_KFREE_MAX = 2,\n};\n\nstruct cpu_hw_events {\n\tstruct perf_event *events[64];\n\tlong unsigned int active_mask[1];\n\tlong unsigned int dirty[1];\n\tint enabled;\n\tint n_events;\n\tint n_added;\n\tint n_txn;\n\tint n_txn_pair;\n\tint n_txn_metric;\n\tint assign[64];\n\tu64 tags[64];\n\tstruct perf_event *event_list[64];\n\tstruct event_constraint *event_constraint[64];\n\tint n_excl;\n\tunsigned int txn_flags;\n\tint is_fake;\n\tstruct debug_store *ds;\n\tvoid *ds_pebs_vaddr;\n\tvoid *ds_bts_vaddr;\n\tu64 pebs_enabled;\n\tint n_pebs;\n\tint n_large_pebs;\n\tint n_pebs_via_pt;\n\tint pebs_output;\n\tu64 pebs_data_cfg;\n\tu64 active_pebs_data_cfg;\n\tint pebs_record_size;\n\tint lbr_users;\n\tint lbr_pebs_users;\n\tstruct perf_branch_stack lbr_stack;\n\tstruct perf_branch_entry lbr_entries[32];\n\tunion {\n\t\tstruct er_account *lbr_sel;\n\t\tstruct er_account *lbr_ctl;\n\t};\n\tu64 br_sel;\n\tvoid *last_task_ctx;\n\tint last_log_id;\n\tint lbr_select;\n\tvoid *lbr_xsave;\n\tu64 intel_ctrl_guest_mask;\n\tu64 intel_ctrl_host_mask;\n\tstruct perf_guest_switch_msr guest_switch_msrs[64];\n\tu64 intel_cp_status;\n\tstruct intel_shared_regs *shared_regs;\n\tstruct event_constraint *constraint_list;\n\tstruct intel_excl_cntrs *excl_cntrs;\n\tint excl_thread_id;\n\tu64 tfa_shadow;\n\tint n_metric;\n\tstruct amd_nb *amd_nb;\n\tu64 perf_ctr_virt_mask;\n\tint n_pair;\n\tvoid *kfree_on_online[2];\n\tstruct pmu *pmu;\n};\n\nstruct extra_reg {\n\tunsigned int event;\n\tunsigned int msr;\n\tu64 config_mask;\n\tu64 valid_mask;\n\tint idx;\n\tbool extra_msr_access;\n};\n\nunion perf_capabilities {\n\tstruct {\n\t\tu64 lbr_format: 6;\n\t\tu64 pebs_trap: 1;\n\t\tu64 pebs_arch_reg: 1;\n\t\tu64 pebs_format: 4;\n\t\tu64 smm_freeze: 1;\n\t\tu64 full_width_write: 1;\n\t\tu64 pebs_baseline: 1;\n\t\tu64 perf_metrics: 1;\n\t\tu64 pebs_output_pt_available: 1;\n\t\tu64 anythread_deprecated: 1;\n\t};\n\tu64 capabilities;\n};\n\nstruct x86_pmu_quirk {\n\tstruct x86_pmu_quirk *next;\n\tvoid (*func)();\n};\n\nenum {\n\tx86_lbr_exclusive_lbr = 0,\n\tx86_lbr_exclusive_bts = 1,\n\tx86_lbr_exclusive_pt = 2,\n\tx86_lbr_exclusive_max = 3,\n};\n\nstruct x86_hybrid_pmu {\n\tstruct pmu pmu;\n\tconst char *name;\n\tu8 cpu_type;\n\tcpumask_t supported_cpus;\n\tunion perf_capabilities intel_cap;\n\tu64 intel_ctrl;\n\tint max_pebs_events;\n\tint num_counters;\n\tint num_counters_fixed;\n\tstruct event_constraint unconstrained;\n\tu64 hw_cache_event_ids[42];\n\tu64 hw_cache_extra_regs[42];\n\tstruct event_constraint *event_constraints;\n\tstruct event_constraint *pebs_constraints;\n\tstruct extra_reg *extra_regs;\n\tunsigned int late_ack: 1;\n\tunsigned int mid_ack: 1;\n\tunsigned int enabled_ack: 1;\n};\n\nenum hybrid_pmu_type {\n\thybrid_big = 64,\n\thybrid_small = 32,\n\thybrid_big_small = 96,\n};\n\nstruct x86_pmu {\n\tconst char *name;\n\tint version;\n\tint (*handle_irq)(struct pt_regs *);\n\tvoid (*disable_all)();\n\tvoid (*enable_all)(int);\n\tvoid (*enable)(struct perf_event *);\n\tvoid (*disable)(struct perf_event *);\n\tvoid (*add)(struct perf_event *);\n\tvoid (*del)(struct perf_event *);\n\tvoid (*read)(struct perf_event *);\n\tint (*hw_config)(struct perf_event *);\n\tint (*schedule_events)(struct cpu_hw_events *, int, int *);\n\tunsigned int eventsel;\n\tunsigned int perfctr;\n\tint (*addr_offset)(int, bool);\n\tint (*rdpmc_index)(int);\n\tu64 (*event_map)(int);\n\tint max_events;\n\tint num_counters;\n\tint num_counters_fixed;\n\tint cntval_bits;\n\tu64 cntval_mask;\n\tunion {\n\t\tlong unsigned int events_maskl;\n\t\tlong unsigned int events_mask[1];\n\t};\n\tint events_mask_len;\n\tint apic;\n\tu64 max_period;\n\tstruct event_constraint * (*get_event_constraints)(struct cpu_hw_events *, int, struct perf_event *);\n\tvoid (*put_event_constraints)(struct cpu_hw_events *, struct perf_event *);\n\tvoid (*start_scheduling)(struct cpu_hw_events *);\n\tvoid (*commit_scheduling)(struct cpu_hw_events *, int, int);\n\tvoid (*stop_scheduling)(struct cpu_hw_events *);\n\tstruct event_constraint *event_constraints;\n\tstruct x86_pmu_quirk *quirks;\n\tint perfctr_second_write;\n\tu64 (*limit_period)(struct perf_event *, u64);\n\tunsigned int late_ack: 1;\n\tunsigned int mid_ack: 1;\n\tunsigned int enabled_ack: 1;\n\tint attr_rdpmc_broken;\n\tint attr_rdpmc;\n\tstruct attribute **format_attrs;\n\tssize_t (*events_sysfs_show)(char *, u64);\n\tconst struct attribute_group **attr_update;\n\tlong unsigned int attr_freeze_on_smi;\n\tint (*cpu_prepare)(int);\n\tvoid (*cpu_starting)(int);\n\tvoid (*cpu_dying)(int);\n\tvoid (*cpu_dead)(int);\n\tvoid (*check_microcode)();\n\tvoid (*sched_task)(struct perf_event_context *, bool);\n\tu64 intel_ctrl;\n\tunion perf_capabilities intel_cap;\n\tunsigned int bts: 1;\n\tunsigned int bts_active: 1;\n\tunsigned int pebs: 1;\n\tunsigned int pebs_active: 1;\n\tunsigned int pebs_broken: 1;\n\tunsigned int pebs_prec_dist: 1;\n\tunsigned int pebs_no_tlb: 1;\n\tunsigned int pebs_no_isolation: 1;\n\tunsigned int pebs_block: 1;\n\tint pebs_record_size;\n\tint pebs_buffer_size;\n\tint max_pebs_events;\n\tvoid (*drain_pebs)(struct pt_regs *, struct perf_sample_data *);\n\tstruct event_constraint *pebs_constraints;\n\tvoid (*pebs_aliases)(struct perf_event *);\n\tlong unsigned int large_pebs_flags;\n\tu64 rtm_abort_event;\n\tunsigned int lbr_tos;\n\tunsigned int lbr_from;\n\tunsigned int lbr_to;\n\tunsigned int lbr_info;\n\tunsigned int lbr_nr;\n\tunion {\n\t\tu64 lbr_sel_mask;\n\t\tu64 lbr_ctl_mask;\n\t};\n\tunion {\n\t\tconst int *lbr_sel_map;\n\t\tint *lbr_ctl_map;\n\t};\n\tbool lbr_double_abort;\n\tbool lbr_pt_coexist;\n\tunsigned int lbr_depth_mask: 8;\n\tunsigned int lbr_deep_c_reset: 1;\n\tunsigned int lbr_lip: 1;\n\tunsigned int lbr_cpl: 1;\n\tunsigned int lbr_filter: 1;\n\tunsigned int lbr_call_stack: 1;\n\tunsigned int lbr_mispred: 1;\n\tunsigned int lbr_timed_lbr: 1;\n\tunsigned int lbr_br_type: 1;\n\tvoid (*lbr_reset)();\n\tvoid (*lbr_read)(struct cpu_hw_events *);\n\tvoid (*lbr_save)(void *);\n\tvoid (*lbr_restore)(void *);\n\tatomic_t lbr_exclusive[3];\n\tint num_topdown_events;\n\tu64 (*update_topdown_event)(struct perf_event *);\n\tint (*set_topdown_event_period)(struct perf_event *);\n\tvoid (*swap_task_ctx)(struct perf_event_context *, struct perf_event_context *);\n\tunsigned int amd_nb_constraints: 1;\n\tu64 perf_ctr_pair_en;\n\tstruct extra_reg *extra_regs;\n\tunsigned int flags;\n\tstruct perf_guest_switch_msr * (*guest_get_msrs)(int *);\n\tint (*check_period)(struct perf_event *, u64);\n\tint (*aux_output_match)(struct perf_event *);\n\tint (*filter_match)(struct perf_event *);\n\tint num_hybrid_pmus;\n\tstruct x86_hybrid_pmu *hybrid_pmu;\n\tu8 (*get_hybrid_cpu_type)();\n};\n\nstruct sched_state {\n\tint weight;\n\tint event;\n\tint counter;\n\tint unassigned;\n\tint nr_gp;\n\tu64 used;\n};\n\nstruct perf_sched {\n\tint max_weight;\n\tint max_events;\n\tint max_gp;\n\tint saved_states;\n\tstruct event_constraint **constraints;\n\tstruct sched_state state;\n\tstruct sched_state saved[2];\n};\n\nstruct perf_msr {\n\tu64 msr;\n\tstruct attribute_group *grp;\n\tbool (*test)(int, void *);\n\tbool no_check;\n\tu64 mask;\n};\n\nstruct amd_uncore {\n\tint id;\n\tint refcnt;\n\tint cpu;\n\tint num_counters;\n\tint rdpmc_base;\n\tu32 msr_base;\n\tcpumask_t *active_mask;\n\tstruct pmu *pmu;\n\tstruct perf_event *events[6];\n\tstruct hlist_node node;\n};\n\ntypedef int pci_power_t;\n\ntypedef unsigned int pci_channel_state_t;\n\ntypedef short unsigned int pci_dev_flags_t;\n\nstruct pci_bus;\n\nstruct pci_slot;\n\nstruct aer_stats;\n\nstruct rcec_ea;\n\nstruct pci_driver;\n\nstruct pcie_link_state;\n\nstruct pci_vpd;\n\nstruct pci_sriov;\n\nstruct pci_p2pdma;\n\nstruct pci_dev {\n\tstruct list_head bus_list;\n\tstruct pci_bus *bus;\n\tstruct pci_bus *subordinate;\n\tvoid *sysdata;\n\tstruct proc_dir_entry *procent;\n\tstruct pci_slot *slot;\n\tunsigned int devfn;\n\tshort unsigned int vendor;\n\tshort unsigned int device;\n\tshort unsigned int subsystem_vendor;\n\tshort unsigned int subsystem_device;\n\tunsigned int class;\n\tu8 revision;\n\tu8 hdr_type;\n\tu16 aer_cap;\n\tstruct aer_stats *aer_stats;\n\tstruct rcec_ea *rcec_ea;\n\tstruct pci_dev *rcec;\n\tu8 pcie_cap;\n\tu8 msi_cap;\n\tu8 msix_cap;\n\tu8 pcie_mpss: 3;\n\tu8 rom_base_reg;\n\tu8 pin;\n\tu16 pcie_flags_reg;\n\tlong unsigned int *dma_alias_mask;\n\tstruct pci_driver *driver;\n\tu64 dma_mask;\n\tstruct device_dma_parameters dma_parms;\n\tpci_power_t current_state;\n\tunsigned int imm_ready: 1;\n\tu8 pm_cap;\n\tunsigned int pme_support: 5;\n\tunsigned int pme_poll: 1;\n\tunsigned int d1_support: 1;\n\tunsigned int d2_support: 1;\n\tunsigned int no_d1d2: 1;\n\tunsigned int no_d3cold: 1;\n\tunsigned int bridge_d3: 1;\n\tunsigned int d3cold_allowed: 1;\n\tunsigned int mmio_always_on: 1;\n\tunsigned int wakeup_prepared: 1;\n\tunsigned int runtime_d3cold: 1;\n\tunsigned int skip_bus_pm: 1;\n\tunsigned int ignore_hotplug: 1;\n\tunsigned int hotplug_user_indicators: 1;\n\tunsigned int clear_retrain_link: 1;\n\tunsigned int d3hot_delay;\n\tunsigned int d3cold_delay;\n\tstruct pcie_link_state *link_state;\n\tunsigned int ltr_path: 1;\n\tu16 l1ss;\n\tunsigned int eetlp_prefix_path: 1;\n\tpci_channel_state_t error_state;\n\tstruct device dev;\n\tint cfg_size;\n\tunsigned int irq;\n\tstruct resource resource[17];\n\tbool match_driver;\n\tunsigned int transparent: 1;\n\tunsigned int io_window: 1;\n\tunsigned int pref_window: 1;\n\tunsigned int pref_64_window: 1;\n\tunsigned int multifunction: 1;\n\tunsigned int is_busmaster: 1;\n\tunsigned int no_msi: 1;\n\tunsigned int no_64bit_msi: 1;\n\tunsigned int block_cfg_access: 1;\n\tunsigned int broken_parity_status: 1;\n\tunsigned int irq_reroute_variant: 2;\n\tunsigned int msi_enabled: 1;\n\tunsigned int msix_enabled: 1;\n\tunsigned int ari_enabled: 1;\n\tunsigned int ats_enabled: 1;\n\tunsigned int pasid_enabled: 1;\n\tunsigned int pri_enabled: 1;\n\tunsigned int is_managed: 1;\n\tunsigned int needs_freset: 1;\n\tunsigned int state_saved: 1;\n\tunsigned int is_physfn: 1;\n\tunsigned int is_virtfn: 1;\n\tunsigned int reset_fn: 1;\n\tunsigned int is_hotplug_bridge: 1;\n\tunsigned int shpc_managed: 1;\n\tunsigned int is_thunderbolt: 1;\n\tunsigned int untrusted: 1;\n\tunsigned int external_facing: 1;\n\tunsigned int broken_intx_masking: 1;\n\tunsigned int io_window_1k: 1;\n\tunsigned int irq_managed: 1;\n\tunsigned int non_compliant_bars: 1;\n\tunsigned int is_probed: 1;\n\tunsigned int link_active_reporting: 1;\n\tunsigned int no_vf_scan: 1;\n\tunsigned int no_command_memory: 1;\n\tpci_dev_flags_t dev_flags;\n\tatomic_t enable_cnt;\n\tu32 saved_config_space[16];\n\tstruct hlist_head saved_cap_space;\n\tint rom_attr_enabled;\n\tstruct bin_attribute *res_attr[17];\n\tstruct bin_attribute *res_attr_wc[17];\n\tunsigned int broken_cmd_compl: 1;\n\tunsigned int ptm_root: 1;\n\tunsigned int ptm_enabled: 1;\n\tu8 ptm_granularity;\n\tconst struct attribute_group **msi_irq_groups;\n\tstruct pci_vpd *vpd;\n\tu16 dpc_cap;\n\tunsigned int dpc_rp_extensions: 1;\n\tu8 dpc_rp_log_size;\n\tunion {\n\t\tstruct pci_sriov *sriov;\n\t\tstruct pci_dev *physfn;\n\t};\n\tu16 ats_cap;\n\tu8 ats_stu;\n\tu16 pri_cap;\n\tu32 pri_reqs_alloc;\n\tunsigned int pasid_required: 1;\n\tu16 pasid_cap;\n\tu16 pasid_features;\n\tstruct pci_p2pdma *p2pdma;\n\tu16 acs_cap;\n\tphys_addr_t rom;\n\tsize_t romlen;\n\tchar *driver_override;\n\tlong unsigned int priv_flags;\n};\n\nstruct pci_device_id {\n\t__u32 vendor;\n\t__u32 device;\n\t__u32 subvendor;\n\t__u32 subdevice;\n\t__u32 class;\n\t__u32 class_mask;\n\tkernel_ulong_t driver_data;\n};\n\nstruct hotplug_slot;\n\nstruct pci_slot {\n\tstruct pci_bus *bus;\n\tstruct list_head list;\n\tstruct hotplug_slot *hotplug;\n\tunsigned char number;\n\tstruct kobject kobj;\n};\n\ntypedef short unsigned int pci_bus_flags_t;\n\nstruct pci_ops;\n\nstruct pci_bus {\n\tstruct list_head node;\n\tstruct pci_bus *parent;\n\tstruct list_head children;\n\tstruct list_head devices;\n\tstruct pci_dev *self;\n\tstruct list_head slots;\n\tstruct resource *resource[4];\n\tstruct list_head resources;\n\tstruct resource busn_res;\n\tstruct pci_ops *ops;\n\tvoid *sysdata;\n\tstruct proc_dir_entry *procdir;\n\tunsigned char number;\n\tunsigned char primary;\n\tunsigned char max_bus_speed;\n\tunsigned char cur_bus_speed;\n\tchar name[48];\n\tshort unsigned int bridge_ctl;\n\tpci_bus_flags_t bus_flags;\n\tstruct device *bridge;\n\tstruct device dev;\n\tstruct bin_attribute *legacy_io;\n\tstruct bin_attribute *legacy_mem;\n\tunsigned int is_added: 1;\n};\n\nenum {\n\tPCI_STD_RESOURCES = 0,\n\tPCI_STD_RESOURCE_END = 5,\n\tPCI_ROM_RESOURCE = 6,\n\tPCI_IOV_RESOURCES = 7,\n\tPCI_IOV_RESOURCE_END = 12,\n\tPCI_BRIDGE_RESOURCES = 13,\n\tPCI_BRIDGE_RESOURCE_END = 16,\n\tPCI_NUM_RESOURCES = 17,\n\tDEVICE_COUNT_RESOURCE = 17,\n};\n\ntypedef unsigned int pcie_reset_state_t;\n\nstruct pci_dynids {\n\tspinlock_t lock;\n\tstruct list_head list;\n};\n\nstruct pci_error_handlers;\n\nstruct pci_driver {\n\tstruct list_head node;\n\tconst char *name;\n\tconst struct pci_device_id *id_table;\n\tint (*probe)(struct pci_dev *, const struct pci_device_id *);\n\tvoid (*remove)(struct pci_dev *);\n\tint (*suspend)(struct pci_dev *, pm_message_t);\n\tint (*resume)(struct pci_dev *);\n\tvoid (*shutdown)(struct pci_dev *);\n\tint (*sriov_configure)(struct pci_dev *, int);\n\tint (*sriov_set_msix_vec_count)(struct pci_dev *, int);\n\tu32 (*sriov_get_vf_total_msix)(struct pci_dev *);\n\tconst struct pci_error_handlers *err_handler;\n\tconst struct attribute_group **groups;\n\tconst struct attribute_group **dev_groups;\n\tstruct device_driver driver;\n\tstruct pci_dynids dynids;\n};\n\nstruct pci_ops {\n\tint (*add_bus)(struct pci_bus *);\n\tvoid (*remove_bus)(struct pci_bus *);\n\tvoid * (*map_bus)(struct pci_bus *, unsigned int, int);\n\tint (*read)(struct pci_bus *, unsigned int, int, int, u32 *);\n\tint (*write)(struct pci_bus *, unsigned int, int, int, u32);\n};\n\ntypedef unsigned int pci_ers_result_t;\n\nstruct pci_error_handlers {\n\tpci_ers_result_t (*error_detected)(struct pci_dev *, pci_channel_state_t);\n\tpci_ers_result_t (*mmio_enabled)(struct pci_dev *);\n\tpci_ers_result_t (*slot_reset)(struct pci_dev *);\n\tvoid (*reset_prepare)(struct pci_dev *);\n\tvoid (*reset_done)(struct pci_dev *);\n\tvoid (*resume)(struct pci_dev *);\n};\n\nstruct syscore_ops {\n\tstruct list_head node;\n\tint (*suspend)();\n\tvoid (*resume)();\n\tvoid (*shutdown)();\n};\n\nenum ibs_states {\n\tIBS_ENABLED = 0,\n\tIBS_STARTED = 1,\n\tIBS_STOPPING = 2,\n\tIBS_STOPPED = 3,\n\tIBS_MAX_STATES = 4,\n};\n\nstruct cpu_perf_ibs {\n\tstruct perf_event *event;\n\tlong unsigned int state[1];\n};\n\nstruct perf_ibs {\n\tstruct pmu pmu;\n\tunsigned int msr;\n\tu64 config_mask;\n\tu64 cnt_mask;\n\tu64 enable_mask;\n\tu64 valid_mask;\n\tu64 max_period;\n\tlong unsigned int offset_mask[1];\n\tint offset_max;\n\tunsigned int fetch_count_reset_broken: 1;\n\tunsigned int fetch_ignore_if_zero_rip: 1;\n\tstruct cpu_perf_ibs *pcpu;\n\tstruct attribute **format_attrs;\n\tstruct attribute_group format_group;\n\tconst struct attribute_group *attr_groups[2];\n\tu64 (*get_count)(u64);\n};\n\nstruct perf_ibs_data {\n\tu32 size;\n\tunion {\n\t\tu32 data[0];\n\t\tu32 caps;\n\t};\n\tu64 regs[8];\n};\n\nstruct amd_iommu;\n\nstruct perf_amd_iommu {\n\tstruct list_head list;\n\tstruct pmu pmu;\n\tstruct amd_iommu *iommu;\n\tchar name[16];\n\tu8 max_banks;\n\tu8 max_counters;\n\tu64 cntr_assign_mask;\n\traw_spinlock_t lock;\n};\n\nstruct amd_iommu_event_desc {\n\tstruct device_attribute attr;\n\tconst char *event;\n};\n\nenum perf_msr_id {\n\tPERF_MSR_TSC = 0,\n\tPERF_MSR_APERF = 1,\n\tPERF_MSR_MPERF = 2,\n\tPERF_MSR_PPERF = 3,\n\tPERF_MSR_SMI = 4,\n\tPERF_MSR_PTSC = 5,\n\tPERF_MSR_IRPERF = 6,\n\tPERF_MSR_THERM = 7,\n\tPERF_MSR_EVENT_MAX = 8,\n};\n\nstruct x86_cpu_desc {\n\tu8 x86_family;\n\tu8 x86_vendor;\n\tu8 x86_model;\n\tu8 x86_stepping;\n\tu32 x86_microcode_rev;\n};\n\nunion cpuid10_eax {\n\tstruct {\n\t\tunsigned int version_id: 8;\n\t\tunsigned int num_counters: 8;\n\t\tunsigned int bit_width: 8;\n\t\tunsigned int mask_length: 8;\n\t} split;\n\tunsigned int full;\n};\n\nunion cpuid10_ebx {\n\tstruct {\n\t\tunsigned int no_unhalted_core_cycles: 1;\n\t\tunsigned int no_instructions_retired: 1;\n\t\tunsigned int no_unhalted_reference_cycles: 1;\n\t\tunsigned int no_llc_reference: 1;\n\t\tunsigned int no_llc_misses: 1;\n\t\tunsigned int no_branch_instruction_retired: 1;\n\t\tunsigned int no_branch_misses_retired: 1;\n\t} split;\n\tunsigned int full;\n};\n\nunion cpuid10_edx {\n\tstruct {\n\t\tunsigned int num_counters_fixed: 5;\n\t\tunsigned int bit_width_fixed: 8;\n\t\tunsigned int reserved1: 2;\n\t\tunsigned int anythread_deprecated: 1;\n\t\tunsigned int reserved2: 16;\n\t} split;\n\tunsigned int full;\n};\n\nstruct perf_pmu_format_hybrid_attr {\n\tstruct device_attribute attr;\n\tu64 pmu_type;\n};\n\nenum {\n\tLBR_FORMAT_32 = 0,\n\tLBR_FORMAT_LIP = 1,\n\tLBR_FORMAT_EIP = 2,\n\tLBR_FORMAT_EIP_FLAGS = 3,\n\tLBR_FORMAT_EIP_FLAGS2 = 4,\n\tLBR_FORMAT_INFO = 5,\n\tLBR_FORMAT_TIME = 6,\n\tLBR_FORMAT_MAX_KNOWN = 6,\n};\n\nunion x86_pmu_config {\n\tstruct {\n\t\tu64 event: 8;\n\t\tu64 umask: 8;\n\t\tu64 usr: 1;\n\t\tu64 os: 1;\n\t\tu64 edge: 1;\n\t\tu64 pc: 1;\n\t\tu64 interrupt: 1;\n\t\tu64 __reserved1: 1;\n\t\tu64 en: 1;\n\t\tu64 inv: 1;\n\t\tu64 cmask: 8;\n\t\tu64 event2: 4;\n\t\tu64 __reserved2: 4;\n\t\tu64 go: 1;\n\t\tu64 ho: 1;\n\t} bits;\n\tu64 value;\n};\n\nenum pageflags {\n\tPG_locked = 0,\n\tPG_referenced = 1,\n\tPG_uptodate = 2,\n\tPG_dirty = 3,\n\tPG_lru = 4,\n\tPG_active = 5,\n\tPG_workingset = 6,\n\tPG_waiters = 7,\n\tPG_error = 8,\n\tPG_slab = 9,\n\tPG_owner_priv_1 = 10,\n\tPG_arch_1 = 11,\n\tPG_reserved = 12,\n\tPG_private = 13,\n\tPG_private_2 = 14,\n\tPG_writeback = 15,\n\tPG_head = 16,\n\tPG_mappedtodisk = 17,\n\tPG_reclaim = 18,\n\tPG_swapbacked = 19,\n\tPG_unevictable = 20,\n\tPG_mlocked = 21,\n\tPG_uncached = 22,\n\tPG_hwpoison = 23,\n\tPG_young = 24,\n\tPG_idle = 25,\n\tPG_arch_2 = 26,\n\t__NR_PAGEFLAGS = 27,\n\tPG_checked = 10,\n\tPG_swapcache = 10,\n\tPG_fscache = 14,\n\tPG_pinned = 10,\n\tPG_savepinned = 3,\n\tPG_foreign = 10,\n\tPG_xen_remapped = 10,\n\tPG_slob_free = 13,\n\tPG_double_map = 6,\n\tPG_isolated = 18,\n\tPG_reported = 2,\n};\n\nstruct bts_ctx {\n\tstruct perf_output_handle handle;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct debug_store ds_back;\n\tint state;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum {\n\tBTS_STATE_STOPPED = 0,\n\tBTS_STATE_INACTIVE = 1,\n\tBTS_STATE_ACTIVE = 2,\n};\n\nstruct bts_phys {\n\tstruct page *page;\n\tlong unsigned int size;\n\tlong unsigned int offset;\n\tlong unsigned int displacement;\n};\n\nstruct bts_buffer {\n\tsize_t real_size;\n\tunsigned int nr_pages;\n\tunsigned int nr_bufs;\n\tunsigned int cur_buf;\n\tbool snapshot;\n\tlocal_t data_size;\n\tlocal_t head;\n\tlong unsigned int end;\n\tvoid **data_pages;\n\tstruct bts_phys buf[0];\n};\n\nstruct lbr_entry {\n\tu64 from;\n\tu64 to;\n\tu64 info;\n};\n\nstruct x86_hw_tss {\n\tu32 reserved1;\n\tu64 sp0;\n\tu64 sp1;\n\tu64 sp2;\n\tu64 reserved2;\n\tu64 ist[7];\n\tu32 reserved3;\n\tu32 reserved4;\n\tu16 reserved5;\n\tu16 io_bitmap_base;\n} __attribute__((packed));\n\nstruct entry_stack {\n\tchar stack[4096];\n};\n\nstruct entry_stack_page {\n\tstruct entry_stack stack;\n};\n\nstruct x86_io_bitmap {\n\tu64 prev_sequence;\n\tunsigned int prev_max;\n\tlong unsigned int bitmap[1025];\n\tlong unsigned int mapall[1025];\n};\n\nstruct tss_struct {\n\tstruct x86_hw_tss x86_tss;\n\tstruct x86_io_bitmap io_bitmap;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct debug_store_buffers {\n\tchar bts_buffer[65536];\n\tchar pebs_buffer[65536];\n};\n\nstruct cea_exception_stacks {\n\tchar DF_stack_guard[4096];\n\tchar DF_stack[4096];\n\tchar NMI_stack_guard[4096];\n\tchar NMI_stack[4096];\n\tchar DB_stack_guard[4096];\n\tchar DB_stack[4096];\n\tchar MCE_stack_guard[4096];\n\tchar MCE_stack[4096];\n\tchar VC_stack_guard[4096];\n\tchar VC_stack[4096];\n\tchar VC2_stack_guard[4096];\n\tchar VC2_stack[4096];\n\tchar IST_top_guard[4096];\n};\n\nstruct cpu_entry_area {\n\tchar gdt[4096];\n\tstruct entry_stack_page entry_stack_page;\n\tstruct tss_struct tss;\n\tstruct cea_exception_stacks estacks;\n\tstruct debug_store cpu_debug_store;\n\tstruct debug_store_buffers cpu_debug_buffers;\n};\n\nstruct pebs_basic {\n\tu64 format_size;\n\tu64 ip;\n\tu64 applicable_counters;\n\tu64 tsc;\n};\n\nstruct pebs_meminfo {\n\tu64 address;\n\tu64 aux;\n\tu64 latency;\n\tu64 tsx_tuning;\n};\n\nstruct pebs_gprs {\n\tu64 flags;\n\tu64 ip;\n\tu64 ax;\n\tu64 cx;\n\tu64 dx;\n\tu64 bx;\n\tu64 sp;\n\tu64 bp;\n\tu64 si;\n\tu64 di;\n\tu64 r8;\n\tu64 r9;\n\tu64 r10;\n\tu64 r11;\n\tu64 r12;\n\tu64 r13;\n\tu64 r14;\n\tu64 r15;\n};\n\nstruct pebs_xmm {\n\tu64 xmm[32];\n};\n\nstruct x86_perf_regs {\n\tstruct pt_regs regs;\n\tu64 *xmm_regs;\n};\n\ntypedef unsigned int insn_attr_t;\n\ntypedef unsigned char insn_byte_t;\n\ntypedef int insn_value_t;\n\nstruct insn_field {\n\tunion {\n\t\tinsn_value_t value;\n\t\tinsn_byte_t bytes[4];\n\t};\n\tunsigned char got;\n\tunsigned char nbytes;\n};\n\nstruct insn {\n\tstruct insn_field prefixes;\n\tstruct insn_field rex_prefix;\n\tstruct insn_field vex_prefix;\n\tstruct insn_field opcode;\n\tstruct insn_field modrm;\n\tstruct insn_field sib;\n\tstruct insn_field displacement;\n\tunion {\n\t\tstruct insn_field immediate;\n\t\tstruct insn_field moffset1;\n\t\tstruct insn_field immediate1;\n\t};\n\tunion {\n\t\tstruct insn_field moffset2;\n\t\tstruct insn_field immediate2;\n\t};\n\tint emulate_prefix_size;\n\tinsn_attr_t attr;\n\tunsigned char opnd_bytes;\n\tunsigned char addr_bytes;\n\tunsigned char length;\n\tunsigned char x86_64;\n\tconst insn_byte_t *kaddr;\n\tconst insn_byte_t *end_kaddr;\n\tconst insn_byte_t *next_byte;\n};\n\nenum {\n\tPERF_TXN_ELISION = 1,\n\tPERF_TXN_TRANSACTION = 2,\n\tPERF_TXN_SYNC = 4,\n\tPERF_TXN_ASYNC = 8,\n\tPERF_TXN_RETRY = 16,\n\tPERF_TXN_CONFLICT = 32,\n\tPERF_TXN_CAPACITY_WRITE = 64,\n\tPERF_TXN_CAPACITY_READ = 128,\n\tPERF_TXN_MAX = 256,\n\tPERF_TXN_ABORT_MASK = 0,\n\tPERF_TXN_ABORT_SHIFT = 32,\n};\n\nstruct perf_event_header {\n\t__u32 type;\n\t__u16 misc;\n\t__u16 size;\n};\n\nunion intel_x86_pebs_dse {\n\tu64 val;\n\tstruct {\n\t\tunsigned int ld_dse: 4;\n\t\tunsigned int ld_stlb_miss: 1;\n\t\tunsigned int ld_locked: 1;\n\t\tunsigned int ld_data_blk: 1;\n\t\tunsigned int ld_addr_blk: 1;\n\t\tunsigned int ld_reserved: 24;\n\t};\n\tstruct {\n\t\tunsigned int st_l1d_hit: 1;\n\t\tunsigned int st_reserved1: 3;\n\t\tunsigned int st_stlb_miss: 1;\n\t\tunsigned int st_locked: 1;\n\t\tunsigned int st_reserved2: 26;\n\t};\n\tstruct {\n\t\tunsigned int st_lat_dse: 4;\n\t\tunsigned int st_lat_stlb_miss: 1;\n\t\tunsigned int st_lat_locked: 1;\n\t\tunsigned int ld_reserved3: 26;\n\t};\n};\n\nstruct pebs_record_core {\n\tu64 flags;\n\tu64 ip;\n\tu64 ax;\n\tu64 bx;\n\tu64 cx;\n\tu64 dx;\n\tu64 si;\n\tu64 di;\n\tu64 bp;\n\tu64 sp;\n\tu64 r8;\n\tu64 r9;\n\tu64 r10;\n\tu64 r11;\n\tu64 r12;\n\tu64 r13;\n\tu64 r14;\n\tu64 r15;\n};\n\nstruct pebs_record_nhm {\n\tu64 flags;\n\tu64 ip;\n\tu64 ax;\n\tu64 bx;\n\tu64 cx;\n\tu64 dx;\n\tu64 si;\n\tu64 di;\n\tu64 bp;\n\tu64 sp;\n\tu64 r8;\n\tu64 r9;\n\tu64 r10;\n\tu64 r11;\n\tu64 r12;\n\tu64 r13;\n\tu64 r14;\n\tu64 r15;\n\tu64 status;\n\tu64 dla;\n\tu64 dse;\n\tu64 lat;\n};\n\nunion hsw_tsx_tuning {\n\tstruct {\n\t\tu32 cycles_last_block: 32;\n\t\tu32 hle_abort: 1;\n\t\tu32 rtm_abort: 1;\n\t\tu32 instruction_abort: 1;\n\t\tu32 non_instruction_abort: 1;\n\t\tu32 retry: 1;\n\t\tu32 data_conflict: 1;\n\t\tu32 capacity_writes: 1;\n\t\tu32 capacity_reads: 1;\n\t};\n\tu64 value;\n};\n\nstruct pebs_record_skl {\n\tu64 flags;\n\tu64 ip;\n\tu64 ax;\n\tu64 bx;\n\tu64 cx;\n\tu64 dx;\n\tu64 si;\n\tu64 di;\n\tu64 bp;\n\tu64 sp;\n\tu64 r8;\n\tu64 r9;\n\tu64 r10;\n\tu64 r11;\n\tu64 r12;\n\tu64 r13;\n\tu64 r14;\n\tu64 r15;\n\tu64 status;\n\tu64 dla;\n\tu64 dse;\n\tu64 lat;\n\tu64 real_ip;\n\tu64 tsx_tuning;\n\tu64 tsc;\n};\n\nstruct bts_record {\n\tu64 from;\n\tu64 to;\n\tu64 flags;\n};\n\nenum {\n\tPERF_BR_UNKNOWN = 0,\n\tPERF_BR_COND = 1,\n\tPERF_BR_UNCOND = 2,\n\tPERF_BR_IND = 3,\n\tPERF_BR_CALL = 4,\n\tPERF_BR_IND_CALL = 5,\n\tPERF_BR_RET = 6,\n\tPERF_BR_SYSCALL = 7,\n\tPERF_BR_SYSRET = 8,\n\tPERF_BR_COND_CALL = 9,\n\tPERF_BR_COND_RET = 10,\n\tPERF_BR_MAX = 11,\n};\n\nenum xfeature {\n\tXFEATURE_FP = 0,\n\tXFEATURE_SSE = 1,\n\tXFEATURE_YMM = 2,\n\tXFEATURE_BNDREGS = 3,\n\tXFEATURE_BNDCSR = 4,\n\tXFEATURE_OPMASK = 5,\n\tXFEATURE_ZMM_Hi256 = 6,\n\tXFEATURE_Hi16_ZMM = 7,\n\tXFEATURE_PT_UNIMPLEMENTED_SO_FAR = 8,\n\tXFEATURE_PKRU = 9,\n\tXFEATURE_PASID = 10,\n\tXFEATURE_RSRVD_COMP_11 = 11,\n\tXFEATURE_RSRVD_COMP_12 = 12,\n\tXFEATURE_RSRVD_COMP_13 = 13,\n\tXFEATURE_RSRVD_COMP_14 = 14,\n\tXFEATURE_LBR = 15,\n\tXFEATURE_MAX = 16,\n};\n\nstruct arch_lbr_state {\n\tu64 lbr_ctl;\n\tu64 lbr_depth;\n\tu64 ler_from;\n\tu64 ler_to;\n\tu64 ler_info;\n\tstruct lbr_entry entries[0];\n};\n\nunion cpuid28_eax {\n\tstruct {\n\t\tunsigned int lbr_depth_mask: 8;\n\t\tunsigned int reserved: 22;\n\t\tunsigned int lbr_deep_c_reset: 1;\n\t\tunsigned int lbr_lip: 1;\n\t} split;\n\tunsigned int full;\n};\n\nunion cpuid28_ebx {\n\tstruct {\n\t\tunsigned int lbr_cpl: 1;\n\t\tunsigned int lbr_filter: 1;\n\t\tunsigned int lbr_call_stack: 1;\n\t} split;\n\tunsigned int full;\n};\n\nunion cpuid28_ecx {\n\tstruct {\n\t\tunsigned int lbr_mispred: 1;\n\t\tunsigned int lbr_timed_lbr: 1;\n\t\tunsigned int lbr_br_type: 1;\n\t} split;\n\tunsigned int full;\n};\n\nstruct x86_pmu_lbr {\n\tunsigned int nr;\n\tunsigned int from;\n\tunsigned int to;\n\tunsigned int info;\n};\n\nstruct x86_perf_task_context_opt {\n\tint lbr_callstack_users;\n\tint lbr_stack_state;\n\tint log_id;\n};\n\nstruct x86_perf_task_context {\n\tu64 lbr_sel;\n\tint tos;\n\tint valid_lbrs;\n\tstruct x86_perf_task_context_opt opt;\n\tstruct lbr_entry lbr[32];\n};\n\nstruct x86_perf_task_context_arch_lbr {\n\tstruct x86_perf_task_context_opt opt;\n\tstruct lbr_entry entries[0];\n};\n\nstruct x86_perf_task_context_arch_lbr_xsave {\n\tstruct x86_perf_task_context_opt opt;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tunion {\n\t\tstruct xregs_state xsave;\n\t\tstruct {\n\t\t\tstruct fxregs_state i387;\n\t\t\tstruct xstate_header header;\n\t\t\tstruct arch_lbr_state lbr;\n\t\t\tlong: 64;\n\t\t\tlong: 64;\n\t\t\tlong: 64;\n\t\t};\n\t};\n};\n\nenum {\n\tX86_BR_NONE = 0,\n\tX86_BR_USER = 1,\n\tX86_BR_KERNEL = 2,\n\tX86_BR_CALL = 4,\n\tX86_BR_RET = 8,\n\tX86_BR_SYSCALL = 16,\n\tX86_BR_SYSRET = 32,\n\tX86_BR_INT = 64,\n\tX86_BR_IRET = 128,\n\tX86_BR_JCC = 256,\n\tX86_BR_JMP = 512,\n\tX86_BR_IRQ = 1024,\n\tX86_BR_IND_CALL = 2048,\n\tX86_BR_ABORT = 4096,\n\tX86_BR_IN_TX = 8192,\n\tX86_BR_NO_TX = 16384,\n\tX86_BR_ZERO_CALL = 32768,\n\tX86_BR_CALL_STACK = 65536,\n\tX86_BR_IND_JMP = 131072,\n\tX86_BR_TYPE_SAVE = 262144,\n};\n\nenum {\n\tLBR_NONE = 0,\n\tLBR_VALID = 1,\n};\n\nenum {\n\tARCH_LBR_BR_TYPE_JCC = 0,\n\tARCH_LBR_BR_TYPE_NEAR_IND_JMP = 1,\n\tARCH_LBR_BR_TYPE_NEAR_REL_JMP = 2,\n\tARCH_LBR_BR_TYPE_NEAR_IND_CALL = 3,\n\tARCH_LBR_BR_TYPE_NEAR_REL_CALL = 4,\n\tARCH_LBR_BR_TYPE_NEAR_RET = 5,\n\tARCH_LBR_BR_TYPE_KNOWN_MAX = 5,\n\tARCH_LBR_BR_TYPE_MAP_MAX = 16,\n};\n\nenum P4_EVENTS {\n\tP4_EVENT_TC_DELIVER_MODE = 0,\n\tP4_EVENT_BPU_FETCH_REQUEST = 1,\n\tP4_EVENT_ITLB_REFERENCE = 2,\n\tP4_EVENT_MEMORY_CANCEL = 3,\n\tP4_EVENT_MEMORY_COMPLETE = 4,\n\tP4_EVENT_LOAD_PORT_REPLAY = 5,\n\tP4_EVENT_STORE_PORT_REPLAY = 6,\n\tP4_EVENT_MOB_LOAD_REPLAY = 7,\n\tP4_EVENT_PAGE_WALK_TYPE = 8,\n\tP4_EVENT_BSQ_CACHE_REFERENCE = 9,\n\tP4_EVENT_IOQ_ALLOCATION = 10,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES = 11,\n\tP4_EVENT_FSB_DATA_ACTIVITY = 12,\n\tP4_EVENT_BSQ_ALLOCATION = 13,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES = 14,\n\tP4_EVENT_SSE_INPUT_ASSIST = 15,\n\tP4_EVENT_PACKED_SP_UOP = 16,\n\tP4_EVENT_PACKED_DP_UOP = 17,\n\tP4_EVENT_SCALAR_SP_UOP = 18,\n\tP4_EVENT_SCALAR_DP_UOP = 19,\n\tP4_EVENT_64BIT_MMX_UOP = 20,\n\tP4_EVENT_128BIT_MMX_UOP = 21,\n\tP4_EVENT_X87_FP_UOP = 22,\n\tP4_EVENT_TC_MISC = 23,\n\tP4_EVENT_GLOBAL_POWER_EVENTS = 24,\n\tP4_EVENT_TC_MS_XFER = 25,\n\tP4_EVENT_UOP_QUEUE_WRITES = 26,\n\tP4_EVENT_RETIRED_MISPRED_BRANCH_TYPE = 27,\n\tP4_EVENT_RETIRED_BRANCH_TYPE = 28,\n\tP4_EVENT_RESOURCE_STALL = 29,\n\tP4_EVENT_WC_BUFFER = 30,\n\tP4_EVENT_B2B_CYCLES = 31,\n\tP4_EVENT_BNR = 32,\n\tP4_EVENT_SNOOP = 33,\n\tP4_EVENT_RESPONSE = 34,\n\tP4_EVENT_FRONT_END_EVENT = 35,\n\tP4_EVENT_EXECUTION_EVENT = 36,\n\tP4_EVENT_REPLAY_EVENT = 37,\n\tP4_EVENT_INSTR_RETIRED = 38,\n\tP4_EVENT_UOPS_RETIRED = 39,\n\tP4_EVENT_UOP_TYPE = 40,\n\tP4_EVENT_BRANCH_RETIRED = 41,\n\tP4_EVENT_MISPRED_BRANCH_RETIRED = 42,\n\tP4_EVENT_X87_ASSIST = 43,\n\tP4_EVENT_MACHINE_CLEAR = 44,\n\tP4_EVENT_INSTR_COMPLETED = 45,\n};\n\nenum P4_EVENT_OPCODES {\n\tP4_EVENT_TC_DELIVER_MODE_OPCODE = 257,\n\tP4_EVENT_BPU_FETCH_REQUEST_OPCODE = 768,\n\tP4_EVENT_ITLB_REFERENCE_OPCODE = 6147,\n\tP4_EVENT_MEMORY_CANCEL_OPCODE = 517,\n\tP4_EVENT_MEMORY_COMPLETE_OPCODE = 2050,\n\tP4_EVENT_LOAD_PORT_REPLAY_OPCODE = 1026,\n\tP4_EVENT_STORE_PORT_REPLAY_OPCODE = 1282,\n\tP4_EVENT_MOB_LOAD_REPLAY_OPCODE = 770,\n\tP4_EVENT_PAGE_WALK_TYPE_OPCODE = 260,\n\tP4_EVENT_BSQ_CACHE_REFERENCE_OPCODE = 3079,\n\tP4_EVENT_IOQ_ALLOCATION_OPCODE = 774,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES_OPCODE = 6662,\n\tP4_EVENT_FSB_DATA_ACTIVITY_OPCODE = 5894,\n\tP4_EVENT_BSQ_ALLOCATION_OPCODE = 1287,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES_OPCODE = 1543,\n\tP4_EVENT_SSE_INPUT_ASSIST_OPCODE = 13313,\n\tP4_EVENT_PACKED_SP_UOP_OPCODE = 2049,\n\tP4_EVENT_PACKED_DP_UOP_OPCODE = 3073,\n\tP4_EVENT_SCALAR_SP_UOP_OPCODE = 2561,\n\tP4_EVENT_SCALAR_DP_UOP_OPCODE = 3585,\n\tP4_EVENT_64BIT_MMX_UOP_OPCODE = 513,\n\tP4_EVENT_128BIT_MMX_UOP_OPCODE = 6657,\n\tP4_EVENT_X87_FP_UOP_OPCODE = 1025,\n\tP4_EVENT_TC_MISC_OPCODE = 1537,\n\tP4_EVENT_GLOBAL_POWER_EVENTS_OPCODE = 4870,\n\tP4_EVENT_TC_MS_XFER_OPCODE = 1280,\n\tP4_EVENT_UOP_QUEUE_WRITES_OPCODE = 2304,\n\tP4_EVENT_RETIRED_MISPRED_BRANCH_TYPE_OPCODE = 1282,\n\tP4_EVENT_RETIRED_BRANCH_TYPE_OPCODE = 1026,\n\tP4_EVENT_RESOURCE_STALL_OPCODE = 257,\n\tP4_EVENT_WC_BUFFER_OPCODE = 1285,\n\tP4_EVENT_B2B_CYCLES_OPCODE = 5635,\n\tP4_EVENT_BNR_OPCODE = 2051,\n\tP4_EVENT_SNOOP_OPCODE = 1539,\n\tP4_EVENT_RESPONSE_OPCODE = 1027,\n\tP4_EVENT_FRONT_END_EVENT_OPCODE = 2053,\n\tP4_EVENT_EXECUTION_EVENT_OPCODE = 3077,\n\tP4_EVENT_REPLAY_EVENT_OPCODE = 2309,\n\tP4_EVENT_INSTR_RETIRED_OPCODE = 516,\n\tP4_EVENT_UOPS_RETIRED_OPCODE = 260,\n\tP4_EVENT_UOP_TYPE_OPCODE = 514,\n\tP4_EVENT_BRANCH_RETIRED_OPCODE = 1541,\n\tP4_EVENT_MISPRED_BRANCH_RETIRED_OPCODE = 772,\n\tP4_EVENT_X87_ASSIST_OPCODE = 773,\n\tP4_EVENT_MACHINE_CLEAR_OPCODE = 517,\n\tP4_EVENT_INSTR_COMPLETED_OPCODE = 1796,\n};\n\nenum P4_ESCR_EMASKS {\n\tP4_EVENT_TC_DELIVER_MODE__DD = 512,\n\tP4_EVENT_TC_DELIVER_MODE__DB = 1024,\n\tP4_EVENT_TC_DELIVER_MODE__DI = 2048,\n\tP4_EVENT_TC_DELIVER_MODE__BD = 4096,\n\tP4_EVENT_TC_DELIVER_MODE__BB = 8192,\n\tP4_EVENT_TC_DELIVER_MODE__BI = 16384,\n\tP4_EVENT_TC_DELIVER_MODE__ID = 32768,\n\tP4_EVENT_BPU_FETCH_REQUEST__TCMISS = 512,\n\tP4_EVENT_ITLB_REFERENCE__HIT = 512,\n\tP4_EVENT_ITLB_REFERENCE__MISS = 1024,\n\tP4_EVENT_ITLB_REFERENCE__HIT_UK = 2048,\n\tP4_EVENT_MEMORY_CANCEL__ST_RB_FULL = 2048,\n\tP4_EVENT_MEMORY_CANCEL__64K_CONF = 4096,\n\tP4_EVENT_MEMORY_COMPLETE__LSC = 512,\n\tP4_EVENT_MEMORY_COMPLETE__SSC = 1024,\n\tP4_EVENT_LOAD_PORT_REPLAY__SPLIT_LD = 1024,\n\tP4_EVENT_STORE_PORT_REPLAY__SPLIT_ST = 1024,\n\tP4_EVENT_MOB_LOAD_REPLAY__NO_STA = 1024,\n\tP4_EVENT_MOB_LOAD_REPLAY__NO_STD = 4096,\n\tP4_EVENT_MOB_LOAD_REPLAY__PARTIAL_DATA = 8192,\n\tP4_EVENT_MOB_LOAD_REPLAY__UNALGN_ADDR = 16384,\n\tP4_EVENT_PAGE_WALK_TYPE__DTMISS = 512,\n\tP4_EVENT_PAGE_WALK_TYPE__ITMISS = 1024,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_HITS = 512,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_HITE = 1024,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_HITM = 2048,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_HITS = 4096,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_HITE = 8192,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_HITM = 16384,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_2ndL_MISS = 131072,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__RD_3rdL_MISS = 262144,\n\tP4_EVENT_BSQ_CACHE_REFERENCE__WR_2ndL_MISS = 524288,\n\tP4_EVENT_IOQ_ALLOCATION__DEFAULT = 512,\n\tP4_EVENT_IOQ_ALLOCATION__ALL_READ = 16384,\n\tP4_EVENT_IOQ_ALLOCATION__ALL_WRITE = 32768,\n\tP4_EVENT_IOQ_ALLOCATION__MEM_UC = 65536,\n\tP4_EVENT_IOQ_ALLOCATION__MEM_WC = 131072,\n\tP4_EVENT_IOQ_ALLOCATION__MEM_WT = 262144,\n\tP4_EVENT_IOQ_ALLOCATION__MEM_WP = 524288,\n\tP4_EVENT_IOQ_ALLOCATION__MEM_WB = 1048576,\n\tP4_EVENT_IOQ_ALLOCATION__OWN = 4194304,\n\tP4_EVENT_IOQ_ALLOCATION__OTHER = 8388608,\n\tP4_EVENT_IOQ_ALLOCATION__PREFETCH = 16777216,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__DEFAULT = 512,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__ALL_READ = 16384,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__ALL_WRITE = 32768,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_UC = 65536,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WC = 131072,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WT = 262144,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WP = 524288,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__MEM_WB = 1048576,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__OWN = 4194304,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__OTHER = 8388608,\n\tP4_EVENT_IOQ_ACTIVE_ENTRIES__PREFETCH = 16777216,\n\tP4_EVENT_FSB_DATA_ACTIVITY__DRDY_DRV = 512,\n\tP4_EVENT_FSB_DATA_ACTIVITY__DRDY_OWN = 1024,\n\tP4_EVENT_FSB_DATA_ACTIVITY__DRDY_OTHER = 2048,\n\tP4_EVENT_FSB_DATA_ACTIVITY__DBSY_DRV = 4096,\n\tP4_EVENT_FSB_DATA_ACTIVITY__DBSY_OWN = 8192,\n\tP4_EVENT_FSB_DATA_ACTIVITY__DBSY_OTHER = 16384,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_TYPE0 = 512,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_TYPE1 = 1024,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_LEN0 = 2048,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_LEN1 = 4096,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_IO_TYPE = 16384,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_LOCK_TYPE = 32768,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_CACHE_TYPE = 65536,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_SPLIT_TYPE = 131072,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_DEM_TYPE = 262144,\n\tP4_EVENT_BSQ_ALLOCATION__REQ_ORD_TYPE = 524288,\n\tP4_EVENT_BSQ_ALLOCATION__MEM_TYPE0 = 1048576,\n\tP4_EVENT_BSQ_ALLOCATION__MEM_TYPE1 = 2097152,\n\tP4_EVENT_BSQ_ALLOCATION__MEM_TYPE2 = 4194304,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_TYPE0 = 512,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_TYPE1 = 1024,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_LEN0 = 2048,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_LEN1 = 4096,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_IO_TYPE = 16384,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_LOCK_TYPE = 32768,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_CACHE_TYPE = 65536,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_SPLIT_TYPE = 131072,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_DEM_TYPE = 262144,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__REQ_ORD_TYPE = 524288,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__MEM_TYPE0 = 1048576,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__MEM_TYPE1 = 2097152,\n\tP4_EVENT_BSQ_ACTIVE_ENTRIES__MEM_TYPE2 = 4194304,\n\tP4_EVENT_SSE_INPUT_ASSIST__ALL = 16777216,\n\tP4_EVENT_PACKED_SP_UOP__ALL = 16777216,\n\tP4_EVENT_PACKED_DP_UOP__ALL = 16777216,\n\tP4_EVENT_SCALAR_SP_UOP__ALL = 16777216,\n\tP4_EVENT_SCALAR_DP_UOP__ALL = 16777216,\n\tP4_EVENT_64BIT_MMX_UOP__ALL = 16777216,\n\tP4_EVENT_128BIT_MMX_UOP__ALL = 16777216,\n\tP4_EVENT_X87_FP_UOP__ALL = 16777216,\n\tP4_EVENT_TC_MISC__FLUSH = 8192,\n\tP4_EVENT_GLOBAL_POWER_EVENTS__RUNNING = 512,\n\tP4_EVENT_TC_MS_XFER__CISC = 512,\n\tP4_EVENT_UOP_QUEUE_WRITES__FROM_TC_BUILD = 512,\n\tP4_EVENT_UOP_QUEUE_WRITES__FROM_TC_DELIVER = 1024,\n\tP4_EVENT_UOP_QUEUE_WRITES__FROM_ROM = 2048,\n\tP4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__CONDITIONAL = 1024,\n\tP4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__CALL = 2048,\n\tP4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__RETURN = 4096,\n\tP4_EVENT_RETIRED_MISPRED_BRANCH_TYPE__INDIRECT = 8192,\n\tP4_EVENT_RETIRED_BRANCH_TYPE__CONDITIONAL = 1024,\n\tP4_EVENT_RETIRED_BRANCH_TYPE__CALL = 2048,\n\tP4_EVENT_RETIRED_BRANCH_TYPE__RETURN = 4096,\n\tP4_EVENT_RETIRED_BRANCH_TYPE__INDIRECT = 8192,\n\tP4_EVENT_RESOURCE_STALL__SBFULL = 16384,\n\tP4_EVENT_WC_BUFFER__WCB_EVICTS = 512,\n\tP4_EVENT_WC_BUFFER__WCB_FULL_EVICTS = 1024,\n\tP4_EVENT_FRONT_END_EVENT__NBOGUS = 512,\n\tP4_EVENT_FRONT_END_EVENT__BOGUS = 1024,\n\tP4_EVENT_EXECUTION_EVENT__NBOGUS0 = 512,\n\tP4_EVENT_EXECUTION_EVENT__NBOGUS1 = 1024,\n\tP4_EVENT_EXECUTION_EVENT__NBOGUS2 = 2048,\n\tP4_EVENT_EXECUTION_EVENT__NBOGUS3 = 4096,\n\tP4_EVENT_EXECUTION_EVENT__BOGUS0 = 8192,\n\tP4_EVENT_EXECUTION_EVENT__BOGUS1 = 16384,\n\tP4_EVENT_EXECUTION_EVENT__BOGUS2 = 32768,\n\tP4_EVENT_EXECUTION_EVENT__BOGUS3 = 65536,\n\tP4_EVENT_REPLAY_EVENT__NBOGUS = 512,\n\tP4_EVENT_REPLAY_EVENT__BOGUS = 1024,\n\tP4_EVENT_INSTR_RETIRED__NBOGUSNTAG = 512,\n\tP4_EVENT_INSTR_RETIRED__NBOGUSTAG = 1024,\n\tP4_EVENT_INSTR_RETIRED__BOGUSNTAG = 2048,\n\tP4_EVENT_INSTR_RETIRED__BOGUSTAG = 4096,\n\tP4_EVENT_UOPS_RETIRED__NBOGUS = 512,\n\tP4_EVENT_UOPS_RETIRED__BOGUS = 1024,\n\tP4_EVENT_UOP_TYPE__TAGLOADS = 1024,\n\tP4_EVENT_UOP_TYPE__TAGSTORES = 2048,\n\tP4_EVENT_BRANCH_RETIRED__MMNP = 512,\n\tP4_EVENT_BRANCH_RETIRED__MMNM = 1024,\n\tP4_EVENT_BRANCH_RETIRED__MMTP = 2048,\n\tP4_EVENT_BRANCH_RETIRED__MMTM = 4096,\n\tP4_EVENT_MISPRED_BRANCH_RETIRED__NBOGUS = 512,\n\tP4_EVENT_X87_ASSIST__FPSU = 512,\n\tP4_EVENT_X87_ASSIST__FPSO = 1024,\n\tP4_EVENT_X87_ASSIST__POAO = 2048,\n\tP4_EVENT_X87_ASSIST__POAU = 4096,\n\tP4_EVENT_X87_ASSIST__PREA = 8192,\n\tP4_EVENT_MACHINE_CLEAR__CLEAR = 512,\n\tP4_EVENT_MACHINE_CLEAR__MOCLEAR = 1024,\n\tP4_EVENT_MACHINE_CLEAR__SMCLEAR = 2048,\n\tP4_EVENT_INSTR_COMPLETED__NBOGUS = 512,\n\tP4_EVENT_INSTR_COMPLETED__BOGUS = 1024,\n};\n\nenum P4_PEBS_METRIC {\n\tP4_PEBS_METRIC__none = 0,\n\tP4_PEBS_METRIC__1stl_cache_load_miss_retired = 1,\n\tP4_PEBS_METRIC__2ndl_cache_load_miss_retired = 2,\n\tP4_PEBS_METRIC__dtlb_load_miss_retired = 3,\n\tP4_PEBS_METRIC__dtlb_store_miss_retired = 4,\n\tP4_PEBS_METRIC__dtlb_all_miss_retired = 5,\n\tP4_PEBS_METRIC__tagged_mispred_branch = 6,\n\tP4_PEBS_METRIC__mob_load_replay_retired = 7,\n\tP4_PEBS_METRIC__split_load_retired = 8,\n\tP4_PEBS_METRIC__split_store_retired = 9,\n\tP4_PEBS_METRIC__max = 10,\n};\n\nstruct p4_event_bind {\n\tunsigned int opcode;\n\tunsigned int escr_msr[2];\n\tunsigned int escr_emask;\n\tunsigned int shared;\n\tchar cntr[6];\n};\n\nstruct p4_pebs_bind {\n\tunsigned int metric_pebs;\n\tunsigned int metric_vert;\n};\n\nstruct p4_event_alias {\n\tu64 original;\n\tu64 alternative;\n};\n\nenum cpuid_regs_idx {\n\tCPUID_EAX = 0,\n\tCPUID_EBX = 1,\n\tCPUID_ECX = 2,\n\tCPUID_EDX = 3,\n};\n\nstruct dev_ext_attribute {\n\tstruct device_attribute attr;\n\tvoid *var;\n};\n\nenum pt_capabilities {\n\tPT_CAP_max_subleaf = 0,\n\tPT_CAP_cr3_filtering = 1,\n\tPT_CAP_psb_cyc = 2,\n\tPT_CAP_ip_filtering = 3,\n\tPT_CAP_mtc = 4,\n\tPT_CAP_ptwrite = 5,\n\tPT_CAP_power_event_trace = 6,\n\tPT_CAP_topa_output = 7,\n\tPT_CAP_topa_multiple_entries = 8,\n\tPT_CAP_single_range_output = 9,\n\tPT_CAP_output_subsys = 10,\n\tPT_CAP_payloads_lip = 11,\n\tPT_CAP_num_address_ranges = 12,\n\tPT_CAP_mtc_periods = 13,\n\tPT_CAP_cycle_thresholds = 14,\n\tPT_CAP_psb_periods = 15,\n};\n\nenum perf_addr_filter_action_t {\n\tPERF_ADDR_FILTER_ACTION_STOP = 0,\n\tPERF_ADDR_FILTER_ACTION_START = 1,\n\tPERF_ADDR_FILTER_ACTION_FILTER = 2,\n};\n\nstruct perf_addr_filter {\n\tstruct list_head entry;\n\tstruct path path;\n\tlong unsigned int offset;\n\tlong unsigned int size;\n\tenum perf_addr_filter_action_t action;\n};\n\nstruct topa_entry {\n\tu64 end: 1;\n\tu64 rsvd0: 1;\n\tu64 intr: 1;\n\tu64 rsvd1: 1;\n\tu64 stop: 1;\n\tu64 rsvd2: 1;\n\tu64 size: 4;\n\tu64 rsvd3: 2;\n\tu64 base: 36;\n\tu64 rsvd4: 16;\n};\n\nstruct pt_pmu {\n\tstruct pmu pmu;\n\tu32 caps[8];\n\tbool vmx;\n\tbool branch_en_always_on;\n\tlong unsigned int max_nonturbo_ratio;\n\tunsigned int tsc_art_num;\n\tunsigned int tsc_art_den;\n};\n\nstruct topa;\n\nstruct pt_buffer {\n\tstruct list_head tables;\n\tstruct topa *first;\n\tstruct topa *last;\n\tstruct topa *cur;\n\tunsigned int cur_idx;\n\tsize_t output_off;\n\tlong unsigned int nr_pages;\n\tlocal_t data_size;\n\tlocal64_t head;\n\tbool snapshot;\n\tbool single;\n\tlong int stop_pos;\n\tlong int intr_pos;\n\tstruct topa_entry *stop_te;\n\tstruct topa_entry *intr_te;\n\tvoid **data_pages;\n};\n\nstruct topa {\n\tstruct list_head list;\n\tu64 offset;\n\tsize_t size;\n\tint last;\n\tunsigned int z_count;\n};\n\nstruct pt_filter {\n\tlong unsigned int msr_a;\n\tlong unsigned int msr_b;\n\tlong unsigned int config;\n};\n\nstruct pt_filters {\n\tstruct pt_filter filter[4];\n\tunsigned int nr_filters;\n};\n\nstruct pt {\n\tstruct perf_output_handle handle;\n\tstruct pt_filters filters;\n\tint handle_nmi;\n\tint vmx_on;\n\tu64 output_base;\n\tu64 output_mask;\n};\n\nstruct pt_cap_desc {\n\tconst char *name;\n\tu32 leaf;\n\tu8 reg;\n\tu32 mask;\n};\n\nstruct pt_address_range {\n\tlong unsigned int msr_a;\n\tlong unsigned int msr_b;\n\tunsigned int reg_off;\n};\n\nstruct topa_page {\n\tstruct topa_entry table[507];\n\tstruct topa topa;\n};\n\ntypedef s8 int8_t;\n\ntypedef u8 uint8_t;\n\ntypedef u64 uint64_t;\n\nstruct atomic_notifier_head {\n\tspinlock_t lock;\n\tstruct notifier_block *head;\n};\n\nenum xen_domain_type {\n\tXEN_NATIVE = 0,\n\tXEN_PV_DOMAIN = 1,\n\tXEN_HVM_DOMAIN = 2,\n};\n\ntypedef long unsigned int xen_pfn_t;\n\ntypedef long unsigned int xen_ulong_t;\n\nstruct arch_shared_info {\n\tlong unsigned int max_pfn;\n\txen_pfn_t pfn_to_mfn_frame_list_list;\n\tlong unsigned int nmi_reason;\n\tlong unsigned int p2m_cr3;\n\tlong unsigned int p2m_vaddr;\n\tlong unsigned int p2m_generation;\n};\n\nstruct arch_vcpu_info {\n\tlong unsigned int cr2;\n\tlong unsigned int pad;\n};\n\nstruct pvclock_wall_clock {\n\tu32 version;\n\tu32 sec;\n\tu32 nsec;\n};\n\nstruct vcpu_info {\n\tuint8_t evtchn_upcall_pending;\n\tuint8_t evtchn_upcall_mask;\n\txen_ulong_t evtchn_pending_sel;\n\tstruct arch_vcpu_info arch;\n\tstruct pvclock_vcpu_time_info time;\n};\n\nstruct shared_info {\n\tstruct vcpu_info vcpu_info[32];\n\txen_ulong_t evtchn_pending[64];\n\txen_ulong_t evtchn_mask[64];\n\tstruct pvclock_wall_clock wc;\n\tuint32_t wc_sec_hi;\n\tstruct arch_shared_info arch;\n};\n\nstruct start_info {\n\tchar magic[32];\n\tlong unsigned int nr_pages;\n\tlong unsigned int shared_info;\n\tuint32_t flags;\n\txen_pfn_t store_mfn;\n\tuint32_t store_evtchn;\n\tunion {\n\t\tstruct {\n\t\t\txen_pfn_t mfn;\n\t\t\tuint32_t evtchn;\n\t\t} domU;\n\t\tstruct {\n\t\t\tuint32_t info_off;\n\t\t\tuint32_t info_size;\n\t\t} dom0;\n\t} console;\n\tlong unsigned int pt_base;\n\tlong unsigned int nr_pt_frames;\n\tlong unsigned int mfn_list;\n\tlong unsigned int mod_start;\n\tlong unsigned int mod_len;\n\tint8_t cmd_line[1024];\n\tlong unsigned int first_p2m_pfn;\n\tlong unsigned int nr_p2m_frames;\n};\n\nstruct sched_shutdown {\n\tunsigned int reason;\n};\n\nstruct sched_pin_override {\n\tint32_t pcpu;\n};\n\nstruct vcpu_register_vcpu_info {\n\tuint64_t mfn;\n\tuint32_t offset;\n\tuint32_t rsvd;\n};\n\nstruct xmaddr {\n\tphys_addr_t maddr;\n};\n\ntypedef struct xmaddr xmaddr_t;\n\nstruct xpaddr {\n\tphys_addr_t paddr;\n};\n\ntypedef struct xpaddr xpaddr_t;\n\ntypedef s16 int16_t;\n\ntypedef u16 uint16_t;\n\nenum clocksource_ids {\n\tCSID_GENERIC = 0,\n\tCSID_ARM_ARCH_COUNTER = 1,\n\tCSID_MAX = 2,\n};\n\nstruct clocksource {\n\tu64 (*read)(struct clocksource *);\n\tu64 mask;\n\tu32 mult;\n\tu32 shift;\n\tu64 max_idle_ns;\n\tu32 maxadj;\n\tu32 uncertainty_margin;\n\tu64 max_cycles;\n\tconst char *name;\n\tstruct list_head list;\n\tint rating;\n\tenum clocksource_ids id;\n\tenum vdso_clock_mode vdso_clock_mode;\n\tlong unsigned int flags;\n\tint (*enable)(struct clocksource *);\n\tvoid (*disable)(struct clocksource *);\n\tvoid (*suspend)(struct clocksource *);\n\tvoid (*resume)(struct clocksource *);\n\tvoid (*mark_unstable)(struct clocksource *);\n\tvoid (*tick_stable)(struct clocksource *);\n\tstruct list_head wd_list;\n\tu64 cs_last;\n\tu64 wd_last;\n\tstruct module *owner;\n};\n\nstruct x86_init_mpparse {\n\tvoid (*setup_ioapic_ids)();\n\tvoid (*find_smp_config)();\n\tvoid (*get_smp_config)(unsigned int);\n};\n\nstruct x86_init_resources {\n\tvoid (*probe_roms)();\n\tvoid (*reserve_resources)();\n\tchar * (*memory_setup)();\n};\n\nstruct x86_init_irqs {\n\tvoid (*pre_vector_init)();\n\tvoid (*intr_init)();\n\tvoid (*intr_mode_select)();\n\tvoid (*intr_mode_init)();\n\tstruct irq_domain * (*create_pci_msi_domain)();\n};\n\nstruct x86_init_oem {\n\tvoid (*arch_setup)();\n\tvoid (*banner)();\n};\n\nstruct x86_init_paging {\n\tvoid (*pagetable_init)();\n};\n\nstruct x86_init_timers {\n\tvoid (*setup_percpu_clockev)();\n\tvoid (*timer_init)();\n\tvoid (*wallclock_init)();\n};\n\nstruct x86_init_iommu {\n\tint (*iommu_init)();\n};\n\nstruct x86_init_pci {\n\tint (*arch_init)();\n\tint (*init)();\n\tvoid (*init_irq)();\n\tvoid (*fixup_irqs)();\n};\n\nstruct x86_hyper_init {\n\tvoid (*init_platform)();\n\tvoid (*guest_late_init)();\n\tbool (*x2apic_available)();\n\tbool (*msi_ext_dest_id)();\n\tvoid (*init_mem_mapping)();\n\tvoid (*init_after_bootmem)();\n};\n\nstruct x86_init_acpi {\n\tvoid (*set_root_pointer)(u64);\n\tu64 (*get_root_pointer)();\n\tvoid (*reduced_hw_early_init)();\n};\n\nstruct x86_init_ops {\n\tstruct x86_init_resources resources;\n\tstruct x86_init_mpparse mpparse;\n\tstruct x86_init_irqs irqs;\n\tstruct x86_init_oem oem;\n\tstruct x86_init_paging paging;\n\tstruct x86_init_timers timers;\n\tstruct x86_init_iommu iommu;\n\tstruct x86_init_pci pci;\n\tstruct x86_hyper_init hyper;\n\tstruct x86_init_acpi acpi;\n};\n\nstruct x86_cpuinit_ops {\n\tvoid (*setup_percpu_clockev)();\n\tvoid (*early_percpu_clock_init)();\n\tvoid (*fixup_cpu_id)(struct cpuinfo_x86 *, int);\n};\n\nenum clock_event_state {\n\tCLOCK_EVT_STATE_DETACHED = 0,\n\tCLOCK_EVT_STATE_SHUTDOWN = 1,\n\tCLOCK_EVT_STATE_PERIODIC = 2,\n\tCLOCK_EVT_STATE_ONESHOT = 3,\n\tCLOCK_EVT_STATE_ONESHOT_STOPPED = 4,\n};\n\nstruct clock_event_device {\n\tvoid (*event_handler)(struct clock_event_device *);\n\tint (*set_next_event)(long unsigned int, struct clock_event_device *);\n\tint (*set_next_ktime)(ktime_t, struct clock_event_device *);\n\tktime_t next_event;\n\tu64 max_delta_ns;\n\tu64 min_delta_ns;\n\tu32 mult;\n\tu32 shift;\n\tenum clock_event_state state_use_accessors;\n\tunsigned int features;\n\tlong unsigned int retries;\n\tint (*set_state_periodic)(struct clock_event_device *);\n\tint (*set_state_oneshot)(struct clock_event_device *);\n\tint (*set_state_oneshot_stopped)(struct clock_event_device *);\n\tint (*set_state_shutdown)(struct clock_event_device *);\n\tint (*tick_resume)(struct clock_event_device *);\n\tvoid (*broadcast)(const struct cpumask *);\n\tvoid (*suspend)(struct clock_event_device *);\n\tvoid (*resume)(struct clock_event_device *);\n\tlong unsigned int min_delta_ticks;\n\tlong unsigned int max_delta_ticks;\n\tconst char *name;\n\tint rating;\n\tint irq;\n\tint bound_on;\n\tconst struct cpumask *cpumask;\n\tstruct list_head list;\n\tstruct module *owner;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct tk_read_base {\n\tstruct clocksource *clock;\n\tu64 mask;\n\tu64 cycle_last;\n\tu32 mult;\n\tu32 shift;\n\tu64 xtime_nsec;\n\tktime_t base;\n\tu64 base_real;\n};\n\nstruct timekeeper {\n\tstruct tk_read_base tkr_mono;\n\tstruct tk_read_base tkr_raw;\n\tu64 xtime_sec;\n\tlong unsigned int ktime_sec;\n\tstruct timespec64 wall_to_monotonic;\n\tktime_t offs_real;\n\tktime_t offs_boot;\n\tktime_t offs_tai;\n\ts32 tai_offset;\n\tunsigned int clock_was_set_seq;\n\tu8 cs_was_changed_seq;\n\tktime_t next_leap_ktime;\n\tu64 raw_sec;\n\tstruct timespec64 monotonic_to_boot;\n\tu64 cycle_interval;\n\tu64 xtime_interval;\n\ts64 xtime_remainder;\n\tu64 raw_interval;\n\tu64 ntp_tick;\n\ts64 ntp_error;\n\tu32 ntp_error_shift;\n\tu32 ntp_err_mult;\n\tu32 skip_second_overflow;\n};\n\ntypedef unsigned char *__guest_handle_uchar;\n\ntypedef char *__guest_handle_char;\n\ntypedef void *__guest_handle_void;\n\ntypedef uint64_t *__guest_handle_uint64_t;\n\ntypedef uint32_t *__guest_handle_uint32_t;\n\nstruct vcpu_time_info {\n\tuint32_t version;\n\tuint32_t pad0;\n\tuint64_t tsc_timestamp;\n\tuint64_t system_time;\n\tuint32_t tsc_to_system_mul;\n\tint8_t tsc_shift;\n\tint8_t pad1[3];\n};\n\nstruct xenpf_settime32 {\n\tuint32_t secs;\n\tuint32_t nsecs;\n\tuint64_t system_time;\n};\n\nstruct xenpf_settime64 {\n\tuint64_t secs;\n\tuint32_t nsecs;\n\tuint32_t mbz;\n\tuint64_t system_time;\n};\n\nstruct xenpf_add_memtype {\n\txen_pfn_t mfn;\n\tuint64_t nr_mfns;\n\tuint32_t type;\n\tuint32_t handle;\n\tuint32_t reg;\n};\n\nstruct xenpf_del_memtype {\n\tuint32_t handle;\n\tuint32_t reg;\n};\n\nstruct xenpf_read_memtype {\n\tuint32_t reg;\n\txen_pfn_t mfn;\n\tuint64_t nr_mfns;\n\tuint32_t type;\n};\n\nstruct xenpf_microcode_update {\n\t__guest_handle_void data;\n\tuint32_t length;\n};\n\nstruct xenpf_platform_quirk {\n\tuint32_t quirk_id;\n};\n\nstruct xenpf_efi_time {\n\tuint16_t year;\n\tuint8_t month;\n\tuint8_t day;\n\tuint8_t hour;\n\tuint8_t min;\n\tuint8_t sec;\n\tuint32_t ns;\n\tint16_t tz;\n\tuint8_t daylight;\n};\n\nstruct xenpf_efi_guid {\n\tuint32_t data1;\n\tuint16_t data2;\n\tuint16_t data3;\n\tuint8_t data4[8];\n};\n\nstruct xenpf_efi_runtime_call {\n\tuint32_t function;\n\tuint32_t misc;\n\txen_ulong_t status;\n\tunion {\n\t\tstruct {\n\t\t\tstruct xenpf_efi_time time;\n\t\t\tuint32_t resolution;\n\t\t\tuint32_t accuracy;\n\t\t} get_time;\n\t\tstruct xenpf_efi_time set_time;\n\t\tstruct xenpf_efi_time get_wakeup_time;\n\t\tstruct xenpf_efi_time set_wakeup_time;\n\t\tstruct {\n\t\t\t__guest_handle_void name;\n\t\t\txen_ulong_t size;\n\t\t\t__guest_handle_void data;\n\t\t\tstruct xenpf_efi_guid vendor_guid;\n\t\t} get_variable;\n\t\tstruct {\n\t\t\t__guest_handle_void name;\n\t\t\txen_ulong_t size;\n\t\t\t__guest_handle_void data;\n\t\t\tstruct xenpf_efi_guid vendor_guid;\n\t\t} set_variable;\n\t\tstruct {\n\t\t\txen_ulong_t size;\n\t\t\t__guest_handle_void name;\n\t\t\tstruct xenpf_efi_guid vendor_guid;\n\t\t} get_next_variable_name;\n\t\tstruct {\n\t\t\tuint32_t attr;\n\t\t\tuint64_t max_store_size;\n\t\t\tuint64_t remain_store_size;\n\t\t\tuint64_t max_size;\n\t\t} query_variable_info;\n\t\tstruct {\n\t\t\t__guest_handle_void capsule_header_array;\n\t\t\txen_ulong_t capsule_count;\n\t\t\tuint64_t max_capsule_size;\n\t\t\tuint32_t reset_type;\n\t\t} query_capsule_capabilities;\n\t\tstruct {\n\t\t\t__guest_handle_void capsule_header_array;\n\t\t\txen_ulong_t capsule_count;\n\t\t\tuint64_t sg_list;\n\t\t} update_capsule;\n\t} u;\n};\n\nunion xenpf_efi_info {\n\tuint32_t version;\n\tstruct {\n\t\tuint64_t addr;\n\t\tuint32_t nent;\n\t} cfg;\n\tstruct {\n\t\tuint32_t revision;\n\t\tuint32_t bufsz;\n\t\t__guest_handle_void name;\n\t} vendor;\n\tstruct {\n\t\tuint64_t addr;\n\t\tuint64_t size;\n\t\tuint64_t attr;\n\t\tuint32_t type;\n\t} mem;\n};\n\nstruct xenpf_firmware_info {\n\tuint32_t type;\n\tuint32_t index;\n\tunion {\n\t\tstruct {\n\t\t\tuint8_t device;\n\t\t\tuint8_t version;\n\t\t\tuint16_t interface_support;\n\t\t\tuint16_t legacy_max_cylinder;\n\t\t\tuint8_t legacy_max_head;\n\t\t\tuint8_t legacy_sectors_per_track;\n\t\t\t__guest_handle_void edd_params;\n\t\t} disk_info;\n\t\tstruct {\n\t\t\tuint8_t device;\n\t\t\tuint32_t mbr_signature;\n\t\t} disk_mbr_signature;\n\t\tstruct {\n\t\t\tuint8_t capabilities;\n\t\t\tuint8_t edid_transfer_time;\n\t\t\t__guest_handle_uchar edid;\n\t\t} vbeddc_info;\n\t\tunion xenpf_efi_info efi_info;\n\t\tuint8_t kbd_shift_flags;\n\t} u;\n};\n\nstruct xenpf_enter_acpi_sleep {\n\tuint16_t val_a;\n\tuint16_t val_b;\n\tuint32_t sleep_state;\n\tuint32_t flags;\n};\n\nstruct xenpf_change_freq {\n\tuint32_t flags;\n\tuint32_t cpu;\n\tuint64_t freq;\n};\n\nstruct xenpf_getidletime {\n\t__guest_handle_uchar cpumap_bitmap;\n\tuint32_t cpumap_nr_cpus;\n\t__guest_handle_uint64_t idletime;\n\tuint64_t now;\n};\n\nstruct xen_power_register {\n\tuint32_t space_id;\n\tuint32_t bit_width;\n\tuint32_t bit_offset;\n\tuint32_t access_size;\n\tuint64_t address;\n};\n\nstruct xen_processor_csd {\n\tuint32_t domain;\n\tuint32_t coord_type;\n\tuint32_t num;\n};\n\ntypedef struct xen_processor_csd *__guest_handle_xen_processor_csd;\n\nstruct xen_processor_cx {\n\tstruct xen_power_register reg;\n\tuint8_t type;\n\tuint32_t latency;\n\tuint32_t power;\n\tuint32_t dpcnt;\n\t__guest_handle_xen_processor_csd dp;\n};\n\ntypedef struct xen_processor_cx *__guest_handle_xen_processor_cx;\n\nstruct xen_processor_flags {\n\tuint32_t bm_control: 1;\n\tuint32_t bm_check: 1;\n\tuint32_t has_cst: 1;\n\tuint32_t power_setup_done: 1;\n\tuint32_t bm_rld_set: 1;\n};\n\nstruct xen_processor_power {\n\tuint32_t count;\n\tstruct xen_processor_flags flags;\n\t__guest_handle_xen_processor_cx states;\n};\n\nstruct xen_pct_register {\n\tuint8_t descriptor;\n\tuint16_t length;\n\tuint8_t space_id;\n\tuint8_t bit_width;\n\tuint8_t bit_offset;\n\tuint8_t reserved;\n\tuint64_t address;\n};\n\nstruct xen_processor_px {\n\tuint64_t core_frequency;\n\tuint64_t power;\n\tuint64_t transition_latency;\n\tuint64_t bus_master_latency;\n\tuint64_t control;\n\tuint64_t status;\n};\n\ntypedef struct xen_processor_px *__guest_handle_xen_processor_px;\n\nstruct xen_psd_package {\n\tuint64_t num_entries;\n\tuint64_t revision;\n\tuint64_t domain;\n\tuint64_t coord_type;\n\tuint64_t num_processors;\n};\n\nstruct xen_processor_performance {\n\tuint32_t flags;\n\tuint32_t platform_limit;\n\tstruct xen_pct_register control_register;\n\tstruct xen_pct_register status_register;\n\tuint32_t state_count;\n\t__guest_handle_xen_processor_px states;\n\tstruct xen_psd_package domain_info;\n\tuint32_t shared_type;\n};\n\nstruct xenpf_set_processor_pminfo {\n\tuint32_t id;\n\tuint32_t type;\n\tunion {\n\t\tstruct xen_processor_power power;\n\t\tstruct xen_processor_performance perf;\n\t\t__guest_handle_uint32_t pdc;\n\t};\n};\n\nstruct xenpf_pcpuinfo {\n\tuint32_t xen_cpuid;\n\tuint32_t max_present;\n\tuint32_t flags;\n\tuint32_t apic_id;\n\tuint32_t acpi_id;\n};\n\nstruct xenpf_cpu_ol {\n\tuint32_t cpuid;\n};\n\nstruct xenpf_cpu_hotadd {\n\tuint32_t apic_id;\n\tuint32_t acpi_id;\n\tuint32_t pxm;\n};\n\nstruct xenpf_mem_hotadd {\n\tuint64_t spfn;\n\tuint64_t epfn;\n\tuint32_t pxm;\n\tuint32_t flags;\n};\n\nstruct xenpf_core_parking {\n\tuint32_t type;\n\tuint32_t idle_nums;\n};\n\nstruct xenpf_symdata {\n\tuint32_t namelen;\n\tuint32_t symnum;\n\t__guest_handle_char name;\n\tuint64_t address;\n\tchar type;\n};\n\nstruct xen_platform_op {\n\tuint32_t cmd;\n\tuint32_t interface_version;\n\tunion {\n\t\tstruct xenpf_settime32 settime32;\n\t\tstruct xenpf_settime64 settime64;\n\t\tstruct xenpf_add_memtype add_memtype;\n\t\tstruct xenpf_del_memtype del_memtype;\n\t\tstruct xenpf_read_memtype read_memtype;\n\t\tstruct xenpf_microcode_update microcode;\n\t\tstruct xenpf_platform_quirk platform_quirk;\n\t\tstruct xenpf_efi_runtime_call efi_runtime_call;\n\t\tstruct xenpf_firmware_info firmware_info;\n\t\tstruct xenpf_enter_acpi_sleep enter_acpi_sleep;\n\t\tstruct xenpf_change_freq change_freq;\n\t\tstruct xenpf_getidletime getidletime;\n\t\tstruct xenpf_set_processor_pminfo set_pminfo;\n\t\tstruct xenpf_pcpuinfo pcpu_info;\n\t\tstruct xenpf_cpu_ol cpu_ol;\n\t\tstruct xenpf_cpu_hotadd cpu_add;\n\t\tstruct xenpf_mem_hotadd mem_add;\n\t\tstruct xenpf_core_parking core_parking;\n\t\tstruct xenpf_symdata symdata;\n\t\tuint8_t pad[128];\n\t} u;\n};\n\nstruct vcpu_set_singleshot_timer {\n\tuint64_t timeout_abs_ns;\n\tuint32_t flags;\n};\n\ntypedef struct vcpu_time_info *__guest_handle_vcpu_time_info;\n\nstruct vcpu_register_time_memory_area {\n\tunion {\n\t\t__guest_handle_vcpu_time_info h;\n\t\tstruct pvclock_vcpu_time_info *v;\n\t\tuint64_t p;\n\t} addr;\n};\n\nstruct xen_clock_event_device {\n\tstruct clock_event_device evt;\n\tchar name[16];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\ntypedef int (*pte_fn_t)(pte_t *, long unsigned int, void *);\n\ntypedef uint16_t grant_status_t;\n\nstruct grant_frames {\n\txen_pfn_t *pfn;\n\tunsigned int count;\n\tvoid *vaddr;\n};\n\nstruct gnttab_vm_area {\n\tstruct vm_struct *area;\n\tpte_t **ptes;\n\tint idx;\n};\n\nenum acpi_irq_model_id {\n\tACPI_IRQ_MODEL_PIC = 0,\n\tACPI_IRQ_MODEL_IOAPIC = 1,\n\tACPI_IRQ_MODEL_IOSAPIC = 2,\n\tACPI_IRQ_MODEL_PLATFORM = 3,\n\tACPI_IRQ_MODEL_GIC = 4,\n\tACPI_IRQ_MODEL_COUNT = 5,\n};\n\ntypedef uint16_t domid_t;\n\nstruct xen_add_to_physmap {\n\tdomid_t domid;\n\tuint16_t size;\n\tunsigned int space;\n\txen_ulong_t idx;\n\txen_pfn_t gpfn;\n};\n\nstruct machine_ops {\n\tvoid (*restart)(char *);\n\tvoid (*halt)();\n\tvoid (*power_off)();\n\tvoid (*shutdown)();\n\tvoid (*crash_shutdown)(struct pt_regs *);\n\tvoid (*emergency_restart)();\n};\n\nenum x86_hypervisor_type {\n\tX86_HYPER_NATIVE = 0,\n\tX86_HYPER_VMWARE = 1,\n\tX86_HYPER_MS_HYPERV = 2,\n\tX86_HYPER_XEN_PV = 3,\n\tX86_HYPER_XEN_HVM = 4,\n\tX86_HYPER_KVM = 5,\n\tX86_HYPER_JAILHOUSE = 6,\n\tX86_HYPER_ACRN = 7,\n};\n\nstruct hypervisor_x86 {\n\tconst char *name;\n\tuint32_t (*detect)();\n\tenum x86_hypervisor_type type;\n\tstruct x86_hyper_init init;\n\tstruct x86_hyper_runtime runtime;\n\tbool ignore_nopv;\n};\n\nenum e820_type {\n\tE820_TYPE_RAM = 1,\n\tE820_TYPE_RESERVED = 2,\n\tE820_TYPE_ACPI = 3,\n\tE820_TYPE_NVS = 4,\n\tE820_TYPE_UNUSABLE = 5,\n\tE820_TYPE_PMEM = 7,\n\tE820_TYPE_PRAM = 12,\n\tE820_TYPE_SOFT_RESERVED = 4026531839,\n\tE820_TYPE_RESERVED_KERN = 128,\n};\n\nstruct xen_hvm_pagetable_dying {\n\tdomid_t domid;\n\t__u64 gpa;\n};\n\nenum hvmmem_type_t {\n\tHVMMEM_ram_rw = 0,\n\tHVMMEM_ram_ro = 1,\n\tHVMMEM_mmio_dm = 2,\n};\n\nstruct xen_hvm_get_mem_type {\n\tdomid_t domid;\n\tuint16_t mem_type;\n\tuint16_t pad[2];\n\tuint64_t pfn;\n};\n\nstruct e820_entry {\n\tu64 addr;\n\tu64 size;\n\tenum e820_type type;\n} __attribute__((packed));\n\nstruct e820_table {\n\t__u32 nr_entries;\n\tstruct e820_entry entries[224];\n} __attribute__((packed));\n\ntypedef xen_pfn_t *__guest_handle_xen_pfn_t;\n\ntypedef long unsigned int xen_callback_t;\n\nstruct mmu_update {\n\tuint64_t ptr;\n\tuint64_t val;\n};\n\nstruct xen_memory_region {\n\tlong unsigned int start_pfn;\n\tlong unsigned int n_pfns;\n};\n\nstruct callback_register {\n\tuint16_t type;\n\tuint16_t flags;\n\txen_callback_t address;\n};\n\nstruct xen_memory_reservation {\n\t__guest_handle_xen_pfn_t extent_start;\n\txen_ulong_t nr_extents;\n\tunsigned int extent_order;\n\tunsigned int address_bits;\n\tdomid_t domid;\n};\n\nstruct xen_memory_map {\n\tunsigned int nr_entries;\n\t__guest_handle_void buffer;\n};\n\nstruct x86_apic_ops {\n\tunsigned int (*io_apic_read)(unsigned int, unsigned int);\n\tvoid (*restore)();\n};\n\nstruct physdev_apic {\n\tlong unsigned int apic_physbase;\n\tuint32_t reg;\n\tuint32_t value;\n};\n\ntypedef long unsigned int uintptr_t;\n\nstruct xen_pmu_amd_ctxt {\n\tuint32_t counters;\n\tuint32_t ctrls;\n\tuint64_t regs[0];\n};\n\nstruct xen_pmu_cntr_pair {\n\tuint64_t counter;\n\tuint64_t control;\n};\n\nstruct xen_pmu_intel_ctxt {\n\tuint32_t fixed_counters;\n\tuint32_t arch_counters;\n\tuint64_t global_ctrl;\n\tuint64_t global_ovf_ctrl;\n\tuint64_t global_status;\n\tuint64_t fixed_ctrl;\n\tuint64_t ds_area;\n\tuint64_t pebs_enable;\n\tuint64_t debugctl;\n\tuint64_t regs[0];\n};\n\nstruct xen_pmu_regs {\n\tuint64_t ip;\n\tuint64_t sp;\n\tuint64_t flags;\n\tuint16_t cs;\n\tuint16_t ss;\n\tuint8_t cpl;\n\tuint8_t pad[3];\n};\n\nstruct xen_pmu_arch {\n\tunion {\n\t\tstruct xen_pmu_regs regs;\n\t\tuint8_t pad[64];\n\t} r;\n\tuint64_t pmu_flags;\n\tunion {\n\t\tuint32_t lapic_lvtpc;\n\t\tuint64_t pad;\n\t} l;\n\tunion {\n\t\tstruct xen_pmu_amd_ctxt amd;\n\t\tstruct xen_pmu_intel_ctxt intel;\n\t\tuint8_t pad[128];\n\t} c;\n};\n\nstruct xen_pmu_params {\n\tstruct {\n\t\tuint32_t maj;\n\t\tuint32_t min;\n\t} version;\n\tuint64_t val;\n\tuint32_t vcpu;\n\tuint32_t pad;\n};\n\nstruct xen_pmu_data {\n\tuint32_t vcpu_id;\n\tuint32_t pcpu_id;\n\tdomid_t domain_id;\n\tuint8_t pad[6];\n\tstruct xen_pmu_arch pmu;\n};\n\nstruct xenpmu {\n\tstruct xen_pmu_data *xenpmu_data;\n\tuint8_t flags;\n};\n\nenum pg_level {\n\tPG_LEVEL_NONE = 0,\n\tPG_LEVEL_4K = 1,\n\tPG_LEVEL_2M = 2,\n\tPG_LEVEL_1G = 3,\n\tPG_LEVEL_512G = 4,\n\tPG_LEVEL_NUM = 5,\n};\n\ntypedef uint32_t grant_ref_t;\n\ntypedef uint32_t grant_handle_t;\n\nstruct gnttab_map_grant_ref {\n\tuint64_t host_addr;\n\tuint32_t flags;\n\tgrant_ref_t ref;\n\tdomid_t dom;\n\tint16_t status;\n\tgrant_handle_t handle;\n\tuint64_t dev_bus_addr;\n};\n\nstruct gnttab_unmap_grant_ref {\n\tuint64_t host_addr;\n\tuint64_t dev_bus_addr;\n\tgrant_handle_t handle;\n\tint16_t status;\n};\n\nenum {\n\tDESC_TSS = 9,\n\tDESC_LDT = 2,\n\tDESCTYPE_S = 16,\n};\n\nenum paravirt_lazy_mode {\n\tPARAVIRT_LAZY_NONE = 0,\n\tPARAVIRT_LAZY_MMU = 1,\n\tPARAVIRT_LAZY_CPU = 2,\n};\n\nstruct plist_head {\n\tstruct list_head node_list;\n};\n\nenum pm_qos_type {\n\tPM_QOS_UNITIALIZED = 0,\n\tPM_QOS_MAX = 1,\n\tPM_QOS_MIN = 2,\n};\n\nstruct pm_qos_constraints {\n\tstruct plist_head list;\n\ts32 target_value;\n\ts32 default_value;\n\ts32 no_constraint_value;\n\tenum pm_qos_type type;\n\tstruct blocking_notifier_head *notifiers;\n};\n\nstruct freq_constraints {\n\tstruct pm_qos_constraints min_freq;\n\tstruct blocking_notifier_head min_freq_notifiers;\n\tstruct pm_qos_constraints max_freq;\n\tstruct blocking_notifier_head max_freq_notifiers;\n};\n\nstruct pm_qos_flags {\n\tstruct list_head list;\n\ts32 effective_flags;\n};\n\nstruct dev_pm_qos_request;\n\nstruct dev_pm_qos {\n\tstruct pm_qos_constraints resume_latency;\n\tstruct pm_qos_constraints latency_tolerance;\n\tstruct freq_constraints freq;\n\tstruct pm_qos_flags flags;\n\tstruct dev_pm_qos_request *resume_latency_req;\n\tstruct dev_pm_qos_request *latency_tolerance_req;\n\tstruct dev_pm_qos_request *flags_req;\n};\n\ntypedef long int xen_long_t;\n\nstruct trap_info {\n\tuint8_t vector;\n\tuint8_t flags;\n\tuint16_t cs;\n\tlong unsigned int address;\n};\n\nstruct mmuext_op {\n\tunsigned int cmd;\n\tunion {\n\t\txen_pfn_t mfn;\n\t\tlong unsigned int linear_addr;\n\t} arg1;\n\tunion {\n\t\tunsigned int nr_ents;\n\t\tvoid *vcpumask;\n\t\txen_pfn_t src_mfn;\n\t} arg2;\n};\n\nstruct multicall_entry {\n\txen_ulong_t op;\n\txen_long_t result;\n\txen_ulong_t args[6];\n};\n\nstruct dom0_vga_console_info {\n\tuint8_t video_type;\n\tunion {\n\t\tstruct {\n\t\t\tuint16_t font_height;\n\t\t\tuint16_t cursor_x;\n\t\t\tuint16_t cursor_y;\n\t\t\tuint16_t rows;\n\t\t\tuint16_t columns;\n\t\t} text_mode_3;\n\t\tstruct {\n\t\t\tuint16_t width;\n\t\t\tuint16_t height;\n\t\t\tuint16_t bytes_per_line;\n\t\t\tuint16_t bits_per_pixel;\n\t\t\tuint32_t lfb_base;\n\t\t\tuint32_t lfb_size;\n\t\t\tuint8_t red_pos;\n\t\t\tuint8_t red_size;\n\t\t\tuint8_t green_pos;\n\t\t\tuint8_t green_size;\n\t\t\tuint8_t blue_pos;\n\t\t\tuint8_t blue_size;\n\t\t\tuint8_t rsvd_pos;\n\t\t\tuint8_t rsvd_size;\n\t\t\tuint32_t gbl_caps;\n\t\t\tuint16_t mode_attrs;\n\t\t} vesa_lfb;\n\t} u;\n};\n\nstruct physdev_set_iopl {\n\tuint32_t iopl;\n};\n\nstruct physdev_set_iobitmap {\n\tuint8_t *bitmap;\n\tuint32_t nr_ports;\n};\n\nstruct xen_extraversion {\n\tchar extraversion[16];\n};\n\ntypedef u32 acpi_status;\n\nstruct pm_qos_flags_request {\n\tstruct list_head node;\n\ts32 flags;\n};\n\nenum freq_qos_req_type {\n\tFREQ_QOS_MIN = 1,\n\tFREQ_QOS_MAX = 2,\n};\n\nstruct freq_qos_request {\n\tenum freq_qos_req_type type;\n\tstruct plist_node pnode;\n\tstruct freq_constraints *qos;\n};\n\nenum dev_pm_qos_req_type {\n\tDEV_PM_QOS_RESUME_LATENCY = 1,\n\tDEV_PM_QOS_LATENCY_TOLERANCE = 2,\n\tDEV_PM_QOS_MIN_FREQUENCY = 3,\n\tDEV_PM_QOS_MAX_FREQUENCY = 4,\n\tDEV_PM_QOS_FLAGS = 5,\n};\n\nstruct dev_pm_qos_request {\n\tenum dev_pm_qos_req_type type;\n\tunion {\n\t\tstruct plist_node pnode;\n\t\tstruct pm_qos_flags_request flr;\n\t\tstruct freq_qos_request freq;\n\t} data;\n\tstruct device *dev;\n};\n\nstruct multicall_space {\n\tstruct multicall_entry *mc;\n\tvoid *args;\n};\n\nstruct tls_descs {\n\tstruct desc_struct desc[3];\n};\n\nstruct trap_array_entry {\n\tvoid (*orig)();\n\tvoid (*xen)();\n\tbool ist_okay;\n};\n\nstruct mmu_gather_batch {\n\tstruct mmu_gather_batch *next;\n\tunsigned int nr;\n\tunsigned int max;\n\tstruct page *pages[0];\n};\n\nstruct mmu_table_batch;\n\nstruct mmu_gather {\n\tstruct mm_struct *mm;\n\tstruct mmu_table_batch *batch;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tunsigned int fullmm: 1;\n\tunsigned int need_flush_all: 1;\n\tunsigned int freed_tables: 1;\n\tunsigned int cleared_ptes: 1;\n\tunsigned int cleared_pmds: 1;\n\tunsigned int cleared_puds: 1;\n\tunsigned int cleared_p4ds: 1;\n\tunsigned int vma_exec: 1;\n\tunsigned int vma_huge: 1;\n\tunsigned int batch_count;\n\tstruct mmu_gather_batch *active;\n\tstruct mmu_gather_batch local;\n\tstruct page *__pages[8];\n};\n\nstruct mmu_table_batch {\n\tstruct callback_head rcu;\n\tunsigned int nr;\n\tvoid *tables[0];\n};\n\nstruct xen_memory_exchange {\n\tstruct xen_memory_reservation in;\n\tstruct xen_memory_reservation out;\n\txen_ulong_t nr_exchanged;\n};\n\nstruct xen_machphys_mapping {\n\txen_ulong_t v_start;\n\txen_ulong_t v_end;\n\txen_ulong_t max_mfn;\n};\n\nenum pt_level {\n\tPT_PGD = 0,\n\tPT_P4D = 1,\n\tPT_PUD = 2,\n\tPT_PMD = 3,\n\tPT_PTE = 4,\n};\n\nstruct remap_data {\n\txen_pfn_t *pfn;\n\tbool contiguous;\n\tbool no_translate;\n\tpgprot_t prot;\n\tstruct mmu_update *mmu_update;\n};\n\nenum xen_mc_flush_reason {\n\tXEN_MC_FL_NONE = 0,\n\tXEN_MC_FL_BATCH = 1,\n\tXEN_MC_FL_ARGS = 2,\n\tXEN_MC_FL_CALLBACK = 3,\n};\n\nenum xen_mc_extend_args {\n\tXEN_MC_XE_OK = 0,\n\tXEN_MC_XE_BAD_OP = 1,\n\tXEN_MC_XE_NO_SPACE = 2,\n};\n\ntypedef void (*xen_mc_callback_fn_t)(void *);\n\nstruct callback {\n\tvoid (*fn)(void *);\n\tvoid *data;\n};\n\nstruct mc_buffer {\n\tunsigned int mcidx;\n\tunsigned int argidx;\n\tunsigned int cbidx;\n\tstruct multicall_entry entries[32];\n\tunsigned char args[512];\n\tstruct callback callbacks[32];\n};\n\nstruct hvm_start_info {\n\tuint32_t magic;\n\tuint32_t version;\n\tuint32_t flags;\n\tuint32_t nr_modules;\n\tuint64_t modlist_paddr;\n\tuint64_t cmdline_paddr;\n\tuint64_t rsdp_paddr;\n\tuint64_t memmap_paddr;\n\tuint32_t memmap_entries;\n\tuint32_t reserved;\n};\n\nstruct trace_event_raw_xen_mc__batch {\n\tstruct trace_entry ent;\n\tenum paravirt_lazy_mode mode;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mc_entry {\n\tstruct trace_entry ent;\n\tunsigned int op;\n\tunsigned int nargs;\n\tlong unsigned int args[6];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mc_entry_alloc {\n\tstruct trace_entry ent;\n\tsize_t args;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mc_callback {\n\tstruct trace_entry ent;\n\txen_mc_callback_fn_t fn;\n\tvoid *data;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mc_flush_reason {\n\tstruct trace_entry ent;\n\tenum xen_mc_flush_reason reason;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mc_flush {\n\tstruct trace_entry ent;\n\tunsigned int mcidx;\n\tunsigned int argidx;\n\tunsigned int cbidx;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mc_extend_args {\n\tstruct trace_entry ent;\n\tunsigned int op;\n\tsize_t args;\n\tenum xen_mc_extend_args res;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu__set_pte {\n\tstruct trace_entry ent;\n\tpte_t *ptep;\n\tpteval_t pteval;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_set_pmd {\n\tstruct trace_entry ent;\n\tpmd_t *pmdp;\n\tpmdval_t pmdval;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_set_pud {\n\tstruct trace_entry ent;\n\tpud_t *pudp;\n\tpudval_t pudval;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_set_p4d {\n\tstruct trace_entry ent;\n\tp4d_t *p4dp;\n\tp4d_t *user_p4dp;\n\tp4dval_t p4dval;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_ptep_modify_prot {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tlong unsigned int addr;\n\tpte_t *ptep;\n\tpteval_t pteval;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_alloc_ptpage {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tlong unsigned int pfn;\n\tunsigned int level;\n\tbool pinned;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_release_ptpage {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tunsigned int level;\n\tbool pinned;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_pgd {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tpgd_t *pgd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_flush_tlb_one_user {\n\tstruct trace_entry ent;\n\tlong unsigned int addr;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_flush_tlb_multi {\n\tstruct trace_entry ent;\n\tunsigned int ncpus;\n\tstruct mm_struct *mm;\n\tlong unsigned int addr;\n\tlong unsigned int end;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_mmu_write_cr3 {\n\tstruct trace_entry ent;\n\tbool kernel;\n\tlong unsigned int cr3;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_cpu_write_ldt_entry {\n\tstruct trace_entry ent;\n\tstruct desc_struct *dt;\n\tint entrynum;\n\tu64 desc;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_cpu_write_idt_entry {\n\tstruct trace_entry ent;\n\tgate_desc *dt;\n\tint entrynum;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_cpu_load_idt {\n\tstruct trace_entry ent;\n\tlong unsigned int addr;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_cpu_write_gdt_entry {\n\tstruct trace_entry ent;\n\tu64 desc;\n\tstruct desc_struct *dt;\n\tint entrynum;\n\tint type;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xen_cpu_set_ldt {\n\tstruct trace_entry ent;\n\tconst void *addr;\n\tunsigned int entries;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_xen_mc__batch {};\n\nstruct trace_event_data_offsets_xen_mc_entry {};\n\nstruct trace_event_data_offsets_xen_mc_entry_alloc {};\n\nstruct trace_event_data_offsets_xen_mc_callback {};\n\nstruct trace_event_data_offsets_xen_mc_flush_reason {};\n\nstruct trace_event_data_offsets_xen_mc_flush {};\n\nstruct trace_event_data_offsets_xen_mc_extend_args {};\n\nstruct trace_event_data_offsets_xen_mmu__set_pte {};\n\nstruct trace_event_data_offsets_xen_mmu_set_pmd {};\n\nstruct trace_event_data_offsets_xen_mmu_set_pud {};\n\nstruct trace_event_data_offsets_xen_mmu_set_p4d {};\n\nstruct trace_event_data_offsets_xen_mmu_ptep_modify_prot {};\n\nstruct trace_event_data_offsets_xen_mmu_alloc_ptpage {};\n\nstruct trace_event_data_offsets_xen_mmu_release_ptpage {};\n\nstruct trace_event_data_offsets_xen_mmu_pgd {};\n\nstruct trace_event_data_offsets_xen_mmu_flush_tlb_one_user {};\n\nstruct trace_event_data_offsets_xen_mmu_flush_tlb_multi {};\n\nstruct trace_event_data_offsets_xen_mmu_write_cr3 {};\n\nstruct trace_event_data_offsets_xen_cpu_write_ldt_entry {};\n\nstruct trace_event_data_offsets_xen_cpu_write_idt_entry {};\n\nstruct trace_event_data_offsets_xen_cpu_load_idt {};\n\nstruct trace_event_data_offsets_xen_cpu_write_gdt_entry {};\n\nstruct trace_event_data_offsets_xen_cpu_set_ldt {};\n\ntypedef void (*btf_trace_xen_mc_batch)(void *, enum paravirt_lazy_mode);\n\ntypedef void (*btf_trace_xen_mc_issue)(void *, enum paravirt_lazy_mode);\n\ntypedef void (*btf_trace_xen_mc_entry)(void *, struct multicall_entry *, unsigned int);\n\ntypedef void (*btf_trace_xen_mc_entry_alloc)(void *, size_t);\n\ntypedef void (*btf_trace_xen_mc_callback)(void *, xen_mc_callback_fn_t, void *);\n\ntypedef void (*btf_trace_xen_mc_flush_reason)(void *, enum xen_mc_flush_reason);\n\ntypedef void (*btf_trace_xen_mc_flush)(void *, unsigned int, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_xen_mc_extend_args)(void *, long unsigned int, size_t, enum xen_mc_extend_args);\n\ntypedef void (*btf_trace_xen_mmu_set_pte)(void *, pte_t *, pte_t);\n\ntypedef void (*btf_trace_xen_mmu_set_pmd)(void *, pmd_t *, pmd_t);\n\ntypedef void (*btf_trace_xen_mmu_set_pud)(void *, pud_t *, pud_t);\n\ntypedef void (*btf_trace_xen_mmu_set_p4d)(void *, p4d_t *, p4d_t *, p4d_t);\n\ntypedef void (*btf_trace_xen_mmu_ptep_modify_prot_start)(void *, struct mm_struct *, long unsigned int, pte_t *, pte_t);\n\ntypedef void (*btf_trace_xen_mmu_ptep_modify_prot_commit)(void *, struct mm_struct *, long unsigned int, pte_t *, pte_t);\n\ntypedef void (*btf_trace_xen_mmu_alloc_ptpage)(void *, struct mm_struct *, long unsigned int, unsigned int, bool);\n\ntypedef void (*btf_trace_xen_mmu_release_ptpage)(void *, long unsigned int, unsigned int, bool);\n\ntypedef void (*btf_trace_xen_mmu_pgd_pin)(void *, struct mm_struct *, pgd_t *);\n\ntypedef void (*btf_trace_xen_mmu_pgd_unpin)(void *, struct mm_struct *, pgd_t *);\n\ntypedef void (*btf_trace_xen_mmu_flush_tlb_one_user)(void *, long unsigned int);\n\ntypedef void (*btf_trace_xen_mmu_flush_tlb_multi)(void *, const struct cpumask *, struct mm_struct *, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_xen_mmu_write_cr3)(void *, bool, long unsigned int);\n\ntypedef void (*btf_trace_xen_cpu_write_ldt_entry)(void *, struct desc_struct *, int, u64);\n\ntypedef void (*btf_trace_xen_cpu_write_idt_entry)(void *, gate_desc *, int, const gate_desc *);\n\ntypedef void (*btf_trace_xen_cpu_load_idt)(void *, const struct desc_ptr *);\n\ntypedef void (*btf_trace_xen_cpu_write_gdt_entry)(void *, struct desc_struct *, int, const void *, int);\n\ntypedef void (*btf_trace_xen_cpu_set_ldt)(void *, const void *, unsigned int);\n\nenum ipi_vector {\n\tXEN_RESCHEDULE_VECTOR = 0,\n\tXEN_CALL_FUNCTION_VECTOR = 1,\n\tXEN_CALL_FUNCTION_SINGLE_VECTOR = 2,\n\tXEN_SPIN_UNLOCK_VECTOR = 3,\n\tXEN_IRQ_WORK_VECTOR = 4,\n\tXEN_NMI_VECTOR = 5,\n\tXEN_NR_IPIS = 6,\n};\n\nstruct xen_common_irq {\n\tint irq;\n\tchar *name;\n};\n\nstruct cpu_user_regs {\n\tuint64_t r15;\n\tuint64_t r14;\n\tuint64_t r13;\n\tuint64_t r12;\n\tunion {\n\t\tuint64_t rbp;\n\t\tuint64_t ebp;\n\t\tuint32_t _ebp;\n\t};\n\tunion {\n\t\tuint64_t rbx;\n\t\tuint64_t ebx;\n\t\tuint32_t _ebx;\n\t};\n\tuint64_t r11;\n\tuint64_t r10;\n\tuint64_t r9;\n\tuint64_t r8;\n\tunion {\n\t\tuint64_t rax;\n\t\tuint64_t eax;\n\t\tuint32_t _eax;\n\t};\n\tunion {\n\t\tuint64_t rcx;\n\t\tuint64_t ecx;\n\t\tuint32_t _ecx;\n\t};\n\tunion {\n\t\tuint64_t rdx;\n\t\tuint64_t edx;\n\t\tuint32_t _edx;\n\t};\n\tunion {\n\t\tuint64_t rsi;\n\t\tuint64_t esi;\n\t\tuint32_t _esi;\n\t};\n\tunion {\n\t\tuint64_t rdi;\n\t\tuint64_t edi;\n\t\tuint32_t _edi;\n\t};\n\tuint32_t error_code;\n\tuint32_t entry_vector;\n\tunion {\n\t\tuint64_t rip;\n\t\tuint64_t eip;\n\t\tuint32_t _eip;\n\t};\n\tuint16_t cs;\n\tuint16_t _pad0[1];\n\tuint8_t saved_upcall_mask;\n\tuint8_t _pad1[3];\n\tunion {\n\t\tuint64_t rflags;\n\t\tuint64_t eflags;\n\t\tuint32_t _eflags;\n\t};\n\tunion {\n\t\tuint64_t rsp;\n\t\tuint64_t esp;\n\t\tuint32_t _esp;\n\t};\n\tuint16_t ss;\n\tuint16_t _pad2[3];\n\tuint16_t es;\n\tuint16_t _pad3[3];\n\tuint16_t ds;\n\tuint16_t _pad4[3];\n\tuint16_t fs;\n\tuint16_t _pad5[3];\n\tuint16_t gs;\n\tuint16_t _pad6[3];\n};\n\nstruct vcpu_guest_context {\n\tstruct {\n\t\tchar x[512];\n\t} fpu_ctxt;\n\tlong unsigned int flags;\n\tstruct cpu_user_regs user_regs;\n\tstruct trap_info trap_ctxt[256];\n\tlong unsigned int ldt_base;\n\tlong unsigned int ldt_ents;\n\tlong unsigned int gdt_frames[16];\n\tlong unsigned int gdt_ents;\n\tlong unsigned int kernel_ss;\n\tlong unsigned int kernel_sp;\n\tlong unsigned int ctrlreg[8];\n\tlong unsigned int debugreg[8];\n\tlong unsigned int event_callback_eip;\n\tlong unsigned int failsafe_callback_eip;\n\tlong unsigned int syscall_callback_eip;\n\tlong unsigned int vm_assist;\n\tuint64_t fs_base;\n\tuint64_t gs_base_kernel;\n\tuint64_t gs_base_user;\n};\n\nstruct sg_table {\n\tstruct scatterlist *sgl;\n\tunsigned int nents;\n\tunsigned int orig_nents;\n};\n\nenum swiotlb_force {\n\tSWIOTLB_NORMAL = 0,\n\tSWIOTLB_FORCE = 1,\n\tSWIOTLB_NO_FORCE = 2,\n};\n\nstruct iommu_table_entry {\n\tinitcall_t detect;\n\tinitcall_t depend;\n\tvoid (*early_init)();\n\tvoid (*late_init)();\n\tint flags;\n};\n\nunion efi_boot_services;\n\ntypedef union efi_boot_services efi_boot_services_t;\n\ntypedef struct {\n\tefi_table_hdr_t hdr;\n\tu32 fw_vendor;\n\tu32 fw_revision;\n\tu32 con_in_handle;\n\tu32 con_in;\n\tu32 con_out_handle;\n\tu32 con_out;\n\tu32 stderr_handle;\n\tu32 stderr;\n\tu32 runtime;\n\tu32 boottime;\n\tu32 nr_tables;\n\tu32 tables;\n} efi_system_table_32_t;\n\nunion efi_simple_text_input_protocol;\n\ntypedef union efi_simple_text_input_protocol efi_simple_text_input_protocol_t;\n\nunion efi_simple_text_output_protocol;\n\ntypedef union efi_simple_text_output_protocol efi_simple_text_output_protocol_t;\n\ntypedef union {\n\tstruct {\n\t\tefi_table_hdr_t hdr;\n\t\tlong unsigned int fw_vendor;\n\t\tu32 fw_revision;\n\t\tlong unsigned int con_in_handle;\n\t\tefi_simple_text_input_protocol_t *con_in;\n\t\tlong unsigned int con_out_handle;\n\t\tefi_simple_text_output_protocol_t *con_out;\n\t\tlong unsigned int stderr_handle;\n\t\tlong unsigned int stderr;\n\t\tefi_runtime_services_t *runtime;\n\t\tefi_boot_services_t *boottime;\n\t\tlong unsigned int nr_tables;\n\t\tlong unsigned int tables;\n\t};\n\tefi_system_table_32_t mixed_mode;\n} efi_system_table_t;\n\nenum efi_secureboot_mode {\n\tefi_secureboot_mode_unset = 0,\n\tefi_secureboot_mode_unknown = 1,\n\tefi_secureboot_mode_disabled = 2,\n\tefi_secureboot_mode_enabled = 3,\n};\n\nstruct hvm_modlist_entry {\n\tuint64_t paddr;\n\tuint64_t size;\n\tuint64_t cmdline_paddr;\n\tuint64_t reserved;\n};\n\nstruct hvm_memmap_table_entry {\n\tuint64_t addr;\n\tuint64_t size;\n\tuint32_t type;\n\tuint32_t reserved;\n};\n\nenum {\n\tWORK_STRUCT_PENDING_BIT = 0,\n\tWORK_STRUCT_DELAYED_BIT = 1,\n\tWORK_STRUCT_PWQ_BIT = 2,\n\tWORK_STRUCT_LINKED_BIT = 3,\n\tWORK_STRUCT_COLOR_SHIFT = 4,\n\tWORK_STRUCT_COLOR_BITS = 4,\n\tWORK_STRUCT_PENDING = 1,\n\tWORK_STRUCT_DELAYED = 2,\n\tWORK_STRUCT_PWQ = 4,\n\tWORK_STRUCT_LINKED = 8,\n\tWORK_STRUCT_STATIC = 0,\n\tWORK_NR_COLORS = 15,\n\tWORK_NO_COLOR = 15,\n\tWORK_CPU_UNBOUND = 320,\n\tWORK_STRUCT_FLAG_BITS = 8,\n\tWORK_OFFQ_FLAG_BASE = 4,\n\t__WORK_OFFQ_CANCELING = 4,\n\tWORK_OFFQ_CANCELING = 16,\n\tWORK_OFFQ_FLAG_BITS = 1,\n\tWORK_OFFQ_POOL_SHIFT = 5,\n\tWORK_OFFQ_LEFT = 59,\n\tWORK_OFFQ_POOL_BITS = 31,\n\tWORK_OFFQ_POOL_NONE = 2147483647,\n\tWORK_STRUCT_FLAG_MASK = 255,\n\tWORK_STRUCT_WQ_DATA_MASK = 4294967040,\n\tWORK_STRUCT_NO_POOL = 4294967264,\n\tWORK_BUSY_PENDING = 1,\n\tWORK_BUSY_RUNNING = 2,\n\tWORKER_DESC_LEN = 24,\n};\n\nenum {\n\tMEMREMAP_WB = 1,\n\tMEMREMAP_WT = 2,\n\tMEMREMAP_WC = 4,\n\tMEMREMAP_ENC = 8,\n\tMEMREMAP_DEC = 16,\n};\n\nenum hv_isolation_type {\n\tHV_ISOLATION_TYPE_NONE = 0,\n\tHV_ISOLATION_TYPE_VBS = 1,\n\tHV_ISOLATION_TYPE_SNP = 2,\n};\n\nunion hv_x64_msr_hypercall_contents {\n\tu64 as_uint64;\n\tstruct {\n\t\tu64 enable: 1;\n\t\tu64 reserved: 11;\n\t\tu64 guest_physical_address: 52;\n\t};\n};\n\nstruct hv_reenlightenment_control {\n\t__u64 vector: 8;\n\t__u64 reserved1: 8;\n\t__u64 enabled: 1;\n\t__u64 reserved2: 15;\n\t__u64 target_vp: 32;\n};\n\nstruct hv_tsc_emulation_control {\n\t__u64 enabled: 1;\n\t__u64 reserved: 63;\n};\n\nstruct hv_tsc_emulation_status {\n\t__u64 inprogress: 1;\n\t__u64 reserved: 63;\n};\n\nstruct hv_nested_enlightenments_control {\n\tstruct {\n\t\t__u32 directhypercall: 1;\n\t\t__u32 reserved: 31;\n\t} features;\n\tstruct {\n\t\t__u32 reserved;\n\t} hypercallControls;\n};\n\nstruct hv_vp_assist_page {\n\t__u32 apic_assist;\n\t__u32 reserved1;\n\t__u64 vtl_control[3];\n\tstruct hv_nested_enlightenments_control nested_control;\n\t__u8 enlighten_vmentry;\n\t__u8 reserved2[7];\n\t__u64 current_nested_vmcs;\n};\n\nstruct hv_get_partition_id {\n\tu64 partition_id;\n};\n\nstruct ms_hyperv_info {\n\tu32 features;\n\tu32 priv_high;\n\tu32 misc_features;\n\tu32 hints;\n\tu32 nested_features;\n\tu32 max_vp_index;\n\tu32 max_lp_index;\n\tu32 isolation_config_a;\n\tu32 isolation_config_b;\n};\n\nenum HV_GENERIC_SET_FORMAT {\n\tHV_GENERIC_SET_SPARSE_4K = 0,\n\tHV_GENERIC_SET_ALL = 1,\n};\n\nstruct hv_vpset {\n\tu64 format;\n\tu64 valid_bank_mask;\n\tu64 bank_contents[0];\n};\n\nstruct hv_tlb_flush {\n\tu64 address_space;\n\tu64 flags;\n\tu64 processor_mask;\n\tu64 gva_list[0];\n};\n\nstruct hv_tlb_flush_ex {\n\tu64 address_space;\n\tu64 flags;\n\tstruct hv_vpset hv_vp_set;\n\tu64 gva_list[0];\n};\n\nstruct trace_event_raw_hyperv_mmu_flush_tlb_multi {\n\tstruct trace_entry ent;\n\tunsigned int ncpus;\n\tstruct mm_struct *mm;\n\tlong unsigned int addr;\n\tlong unsigned int end;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hyperv_nested_flush_guest_mapping {\n\tstruct trace_entry ent;\n\tu64 as;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hyperv_nested_flush_guest_mapping_range {\n\tstruct trace_entry ent;\n\tu64 as;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hyperv_send_ipi_mask {\n\tstruct trace_entry ent;\n\tunsigned int ncpus;\n\tint vector;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hyperv_send_ipi_one {\n\tstruct trace_entry ent;\n\tint cpu;\n\tint vector;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_hyperv_mmu_flush_tlb_multi {};\n\nstruct trace_event_data_offsets_hyperv_nested_flush_guest_mapping {};\n\nstruct trace_event_data_offsets_hyperv_nested_flush_guest_mapping_range {};\n\nstruct trace_event_data_offsets_hyperv_send_ipi_mask {};\n\nstruct trace_event_data_offsets_hyperv_send_ipi_one {};\n\ntypedef void (*btf_trace_hyperv_mmu_flush_tlb_multi)(void *, const struct cpumask *, const struct flush_tlb_info *);\n\ntypedef void (*btf_trace_hyperv_nested_flush_guest_mapping)(void *, u64, int);\n\ntypedef void (*btf_trace_hyperv_nested_flush_guest_mapping_range)(void *, u64, int);\n\ntypedef void (*btf_trace_hyperv_send_ipi_mask)(void *, const struct cpumask *, int);\n\ntypedef void (*btf_trace_hyperv_send_ipi_one)(void *, int, int);\n\nstruct hv_guest_mapping_flush {\n\tu64 address_space;\n\tu64 flags;\n};\n\nunion hv_gpa_page_range {\n\tu64 address_space;\n\tstruct {\n\t\tu64 additional_pages: 11;\n\t\tu64 largepage: 1;\n\t\tu64 basepfn: 52;\n\t} page;\n\tstruct {\n\t\tu64 reserved: 12;\n\t\tu64 page_size: 1;\n\t\tu64 reserved1: 8;\n\t\tu64 base_large_pfn: 43;\n\t};\n};\n\nstruct hv_guest_mapping_flush_list {\n\tu64 address_space;\n\tu64 flags;\n\tunion hv_gpa_page_range gpa_list[510];\n};\n\ntypedef int (*hyperv_fill_flush_list_func)(struct hv_guest_mapping_flush_list *, void *);\n\nstruct acpi_device;\n\nstruct pci_sysdata {\n\tint domain;\n\tint node;\n\tstruct acpi_device *companion;\n\tvoid *iommu;\n\tvoid *fwnode;\n\tstruct pci_dev *vmd_dev;\n};\n\nenum {\n\tIRQCHIP_SET_TYPE_MASKED = 1,\n\tIRQCHIP_EOI_IF_HANDLED = 2,\n\tIRQCHIP_MASK_ON_SUSPEND = 4,\n\tIRQCHIP_ONOFFLINE_ENABLED = 8,\n\tIRQCHIP_SKIP_SET_WAKE = 16,\n\tIRQCHIP_ONESHOT_SAFE = 32,\n\tIRQCHIP_EOI_THREADED = 64,\n\tIRQCHIP_SUPPORTS_LEVEL_MSI = 128,\n\tIRQCHIP_SUPPORTS_NMI = 256,\n\tIRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = 512,\n\tIRQCHIP_AFFINITY_PRE_STARTUP = 1024,\n};\n\nenum irq_alloc_type {\n\tX86_IRQ_ALLOC_TYPE_IOAPIC = 1,\n\tX86_IRQ_ALLOC_TYPE_HPET = 2,\n\tX86_IRQ_ALLOC_TYPE_PCI_MSI = 3,\n\tX86_IRQ_ALLOC_TYPE_PCI_MSIX = 4,\n\tX86_IRQ_ALLOC_TYPE_DMAR = 5,\n\tX86_IRQ_ALLOC_TYPE_AMDVI = 6,\n\tX86_IRQ_ALLOC_TYPE_UV = 7,\n};\n\nstruct ioapic_alloc_info {\n\tint pin;\n\tint node;\n\tu32 is_level: 1;\n\tu32 active_low: 1;\n\tu32 valid: 1;\n};\n\nstruct uv_alloc_info {\n\tint limit;\n\tint blade;\n\tlong unsigned int offset;\n\tchar *name;\n};\n\nstruct irq_alloc_info {\n\tenum irq_alloc_type type;\n\tu32 flags;\n\tu32 devid;\n\tirq_hw_number_t hwirq;\n\tconst struct cpumask *mask;\n\tstruct msi_desc *desc;\n\tvoid *data;\n\tunion {\n\t\tstruct ioapic_alloc_info ioapic;\n\t\tstruct uv_alloc_info uv;\n\t};\n};\n\nstruct irq_cfg {\n\tunsigned int dest_apicid;\n\tunsigned int vector;\n};\n\nenum {\n\tIRQCHIP_FWNODE_REAL = 0,\n\tIRQCHIP_FWNODE_NAMED = 1,\n\tIRQCHIP_FWNODE_NAMED_ID = 2,\n};\n\ntypedef struct irq_alloc_info msi_alloc_info_t;\n\nstruct msi_domain_info;\n\nstruct msi_domain_ops {\n\tirq_hw_number_t (*get_hwirq)(struct msi_domain_info *, msi_alloc_info_t *);\n\tint (*msi_init)(struct irq_domain *, struct msi_domain_info *, unsigned int, irq_hw_number_t, msi_alloc_info_t *);\n\tvoid (*msi_free)(struct irq_domain *, struct msi_domain_info *, unsigned int);\n\tint (*msi_check)(struct irq_domain *, struct msi_domain_info *, struct device *);\n\tint (*msi_prepare)(struct irq_domain *, struct device *, int, msi_alloc_info_t *);\n\tvoid (*msi_finish)(msi_alloc_info_t *, int);\n\tvoid (*set_desc)(msi_alloc_info_t *, struct msi_desc *);\n\tint (*handle_error)(struct irq_domain *, struct msi_desc *, int);\n\tint (*domain_alloc_irqs)(struct irq_domain *, struct device *, int);\n\tvoid (*domain_free_irqs)(struct irq_domain *, struct device *);\n};\n\nstruct msi_domain_info {\n\tu32 flags;\n\tstruct msi_domain_ops *ops;\n\tstruct irq_chip *chip;\n\tvoid *chip_data;\n\tirq_flow_handler_t handler;\n\tvoid *handler_data;\n\tconst char *handler_name;\n\tvoid *data;\n};\n\nenum {\n\tMSI_FLAG_USE_DEF_DOM_OPS = 1,\n\tMSI_FLAG_USE_DEF_CHIP_OPS = 2,\n\tMSI_FLAG_MULTI_PCI_MSI = 4,\n\tMSI_FLAG_PCI_MSIX = 8,\n\tMSI_FLAG_ACTIVATE_EARLY = 16,\n\tMSI_FLAG_MUST_REACTIVATE = 32,\n\tMSI_FLAG_LEVEL_CAPABLE = 64,\n};\n\nenum hv_interrupt_type {\n\tHV_X64_INTERRUPT_TYPE_FIXED = 0,\n\tHV_X64_INTERRUPT_TYPE_LOWESTPRIORITY = 1,\n\tHV_X64_INTERRUPT_TYPE_SMI = 2,\n\tHV_X64_INTERRUPT_TYPE_REMOTEREAD = 3,\n\tHV_X64_INTERRUPT_TYPE_NMI = 4,\n\tHV_X64_INTERRUPT_TYPE_INIT = 5,\n\tHV_X64_INTERRUPT_TYPE_SIPI = 6,\n\tHV_X64_INTERRUPT_TYPE_EXTINT = 7,\n\tHV_X64_INTERRUPT_TYPE_LOCALINT0 = 8,\n\tHV_X64_INTERRUPT_TYPE_LOCALINT1 = 9,\n\tHV_X64_INTERRUPT_TYPE_MAXIMUM = 10,\n};\n\nunion hv_msi_address_register {\n\tu32 as_uint32;\n\tstruct {\n\t\tu32 reserved1: 2;\n\t\tu32 destination_mode: 1;\n\t\tu32 redirection_hint: 1;\n\t\tu32 reserved2: 8;\n\t\tu32 destination_id: 8;\n\t\tu32 msi_base: 12;\n\t};\n};\n\nunion hv_msi_data_register {\n\tu32 as_uint32;\n\tstruct {\n\t\tu32 vector: 8;\n\t\tu32 delivery_mode: 3;\n\t\tu32 reserved1: 3;\n\t\tu32 level_assert: 1;\n\t\tu32 trigger_mode: 1;\n\t\tu32 reserved2: 16;\n\t};\n};\n\nunion hv_msi_entry {\n\tu64 as_uint64;\n\tstruct {\n\t\tunion hv_msi_address_register address;\n\t\tunion hv_msi_data_register data;\n\t};\n};\n\nunion hv_ioapic_rte {\n\tu64 as_uint64;\n\tstruct {\n\t\tu32 vector: 8;\n\t\tu32 delivery_mode: 3;\n\t\tu32 destination_mode: 1;\n\t\tu32 delivery_status: 1;\n\t\tu32 interrupt_polarity: 1;\n\t\tu32 remote_irr: 1;\n\t\tu32 trigger_mode: 1;\n\t\tu32 interrupt_mask: 1;\n\t\tu32 reserved1: 15;\n\t\tu32 reserved2: 24;\n\t\tu32 destination_id: 8;\n\t};\n\tstruct {\n\t\tu32 low_uint32;\n\t\tu32 high_uint32;\n\t};\n};\n\nstruct hv_interrupt_entry {\n\tu32 source;\n\tu32 reserved1;\n\tunion {\n\t\tunion hv_msi_entry msi_entry;\n\t\tunion hv_ioapic_rte ioapic_rte;\n\t};\n};\n\nstruct hv_device_interrupt_target {\n\tu32 vector;\n\tu32 flags;\n\tunion {\n\t\tu64 vp_mask;\n\t\tstruct hv_vpset vp_set;\n\t};\n};\n\nenum hv_device_type {\n\tHV_DEVICE_TYPE_LOGICAL = 0,\n\tHV_DEVICE_TYPE_PCI = 1,\n\tHV_DEVICE_TYPE_IOAPIC = 2,\n\tHV_DEVICE_TYPE_ACPI = 3,\n};\n\ntypedef u16 hv_pci_rid;\n\ntypedef u16 hv_pci_segment;\n\nunion hv_pci_bdf {\n\tu16 as_uint16;\n\tstruct {\n\t\tu8 function: 3;\n\t\tu8 device: 5;\n\t\tu8 bus;\n\t};\n};\n\nunion hv_pci_bus_range {\n\tu16 as_uint16;\n\tstruct {\n\t\tu8 subordinate_bus;\n\t\tu8 secondary_bus;\n\t};\n};\n\nunion hv_device_id {\n\tu64 as_uint64;\n\tstruct {\n\t\tu64 reserved0: 62;\n\t\tu64 device_type: 2;\n\t};\n\tstruct {\n\t\tu64 id: 62;\n\t\tu64 device_type: 2;\n\t} logical;\n\tstruct {\n\t\tunion {\n\t\t\thv_pci_rid rid;\n\t\t\tunion hv_pci_bdf bdf;\n\t\t};\n\t\thv_pci_segment segment;\n\t\tunion hv_pci_bus_range shadow_bus_range;\n\t\tu16 phantom_function_bits: 2;\n\t\tu16 source_shadow: 1;\n\t\tu16 rsvdz0: 11;\n\t\tu16 device_type: 2;\n\t} pci;\n\tstruct {\n\t\tu8 ioapic_id;\n\t\tu8 rsvdz0;\n\t\tu16 rsvdz1;\n\t\tu16 rsvdz2;\n\t\tu16 rsvdz3: 14;\n\t\tu16 device_type: 2;\n\t} ioapic;\n\tstruct {\n\t\tu32 input_mapping_base;\n\t\tu32 input_mapping_count: 30;\n\t\tu32 device_type: 2;\n\t} acpi;\n};\n\nenum hv_interrupt_trigger_mode {\n\tHV_INTERRUPT_TRIGGER_MODE_EDGE = 0,\n\tHV_INTERRUPT_TRIGGER_MODE_LEVEL = 1,\n};\n\nstruct hv_device_interrupt_descriptor {\n\tu32 interrupt_type;\n\tu32 trigger_mode;\n\tu32 vector_count;\n\tu32 reserved;\n\tstruct hv_device_interrupt_target target;\n};\n\nstruct hv_input_map_device_interrupt {\n\tu64 partition_id;\n\tu64 device_id;\n\tu64 flags;\n\tstruct hv_interrupt_entry logical_interrupt_entry;\n\tstruct hv_device_interrupt_descriptor interrupt_descriptor;\n};\n\nstruct hv_output_map_device_interrupt {\n\tstruct hv_interrupt_entry interrupt_entry;\n};\n\nstruct hv_input_unmap_device_interrupt {\n\tu64 partition_id;\n\tu64 device_id;\n\tstruct hv_interrupt_entry interrupt_entry;\n};\n\nstruct rid_data {\n\tstruct pci_dev *bridge;\n\tu32 rid;\n};\n\nstruct hv_send_ipi {\n\tu32 vector;\n\tu32 reserved;\n\tu64 cpu_mask;\n};\n\nstruct hv_send_ipi_ex {\n\tu32 vector;\n\tu32 reserved;\n\tstruct hv_vpset vp_set;\n};\n\nstruct hv_deposit_memory {\n\tu64 partition_id;\n\tu64 gpa_page_list[0];\n};\n\nstruct hv_proximity_domain_flags {\n\tu32 proximity_preferred: 1;\n\tu32 reserved: 30;\n\tu32 proximity_info_valid: 1;\n};\n\nunion hv_proximity_domain_info {\n\tstruct {\n\t\tu32 domain_id;\n\t\tstruct hv_proximity_domain_flags flags;\n\t};\n\tu64 as_uint64;\n};\n\nstruct hv_lp_startup_status {\n\tu64 hv_status;\n\tu64 substatus1;\n\tu64 substatus2;\n\tu64 substatus3;\n\tu64 substatus4;\n\tu64 substatus5;\n\tu64 substatus6;\n};\n\nstruct hv_add_logical_processor_in {\n\tu32 lp_index;\n\tu32 apic_id;\n\tunion hv_proximity_domain_info proximity_domain_info;\n\tu64 flags;\n};\n\nstruct hv_add_logical_processor_out {\n\tstruct hv_lp_startup_status startup_status;\n};\n\nenum HV_SUBNODE_TYPE {\n\tHvSubnodeAny = 0,\n\tHvSubnodeSocket = 1,\n\tHvSubnodeAmdNode = 2,\n\tHvSubnodeL3 = 3,\n\tHvSubnodeCount = 4,\n\tHvSubnodeInvalid = 4294967295,\n};\n\nstruct hv_create_vp {\n\tu64 partition_id;\n\tu32 vp_index;\n\tu8 padding[3];\n\tu8 subnode_type;\n\tu64 subnode_id;\n\tunion hv_proximity_domain_info proximity_domain_info;\n\tu64 flags;\n};\n\nstruct real_mode_header {\n\tu32 text_start;\n\tu32 ro_end;\n\tu32 trampoline_start;\n\tu32 trampoline_header;\n\tu32 sev_es_trampoline_start;\n\tu32 trampoline_pgd;\n\tu32 wakeup_start;\n\tu32 wakeup_header;\n\tu32 machine_real_restart_asm;\n\tu32 machine_real_restart_seg;\n};\n\nstruct trampoline_header {\n\tu64 start;\n\tu64 efer;\n\tu32 cr4;\n\tu32 flags;\n};\n\nenum show_regs_mode {\n\tSHOW_REGS_SHORT = 0,\n\tSHOW_REGS_USER = 1,\n\tSHOW_REGS_ALL = 2,\n};\n\nstruct resctrl_pqr_state {\n\tu32 cur_rmid;\n\tu32 cur_closid;\n\tu32 default_rmid;\n\tu32 default_closid;\n};\n\nenum which_selector {\n\tFS = 0,\n\tGS = 1,\n};\n\nstruct sigcontext_64 {\n\t__u64 r8;\n\t__u64 r9;\n\t__u64 r10;\n\t__u64 r11;\n\t__u64 r12;\n\t__u64 r13;\n\t__u64 r14;\n\t__u64 r15;\n\t__u64 di;\n\t__u64 si;\n\t__u64 bp;\n\t__u64 bx;\n\t__u64 dx;\n\t__u64 ax;\n\t__u64 cx;\n\t__u64 sp;\n\t__u64 ip;\n\t__u64 flags;\n\t__u16 cs;\n\t__u16 gs;\n\t__u16 fs;\n\t__u16 ss;\n\t__u64 err;\n\t__u64 trapno;\n\t__u64 oldmask;\n\t__u64 cr2;\n\t__u64 fpstate;\n\t__u64 reserved1[8];\n};\n\nstruct sigaltstack {\n\tvoid *ss_sp;\n\tint ss_flags;\n\tsize_t ss_size;\n};\n\ntypedef struct sigaltstack stack_t;\n\nstruct siginfo {\n\tunion {\n\t\tstruct {\n\t\t\tint si_signo;\n\t\t\tint si_errno;\n\t\t\tint si_code;\n\t\t\tunion __sifields _sifields;\n\t\t};\n\t\tint _si_pad[32];\n\t};\n};\n\ntypedef struct siginfo siginfo_t;\n\nstruct ksignal {\n\tstruct k_sigaction ka;\n\tkernel_siginfo_t info;\n\tint sig;\n};\n\nstruct __large_struct {\n\tlong unsigned int buf[100];\n};\n\ntypedef u32 compat_sigset_word;\n\ntypedef struct {\n\tcompat_sigset_word sig[2];\n} compat_sigset_t;\n\nstruct ucontext {\n\tlong unsigned int uc_flags;\n\tstruct ucontext *uc_link;\n\tstack_t uc_stack;\n\tstruct sigcontext_64 uc_mcontext;\n\tsigset_t uc_sigmask;\n};\n\nstruct kernel_vm86_regs {\n\tstruct pt_regs pt;\n\tshort unsigned int es;\n\tshort unsigned int __esh;\n\tshort unsigned int ds;\n\tshort unsigned int __dsh;\n\tshort unsigned int fs;\n\tshort unsigned int __fsh;\n\tshort unsigned int gs;\n\tshort unsigned int __gsh;\n};\n\nstruct rt_sigframe {\n\tchar *pretcode;\n\tstruct ucontext uc;\n\tstruct siginfo info;\n};\n\ntypedef s32 compat_clock_t;\n\ntypedef s32 compat_pid_t;\n\ntypedef s32 compat_timer_t;\n\ntypedef s32 compat_int_t;\n\ntypedef u32 compat_ulong_t;\n\ntypedef u32 __compat_uid32_t;\n\nunion compat_sigval {\n\tcompat_int_t sival_int;\n\tcompat_uptr_t sival_ptr;\n};\n\ntypedef union compat_sigval compat_sigval_t;\n\nstruct compat_siginfo {\n\tint si_signo;\n\tint si_errno;\n\tint si_code;\n\tunion {\n\t\tint _pad[29];\n\t\tstruct {\n\t\t\tcompat_pid_t _pid;\n\t\t\t__compat_uid32_t _uid;\n\t\t} _kill;\n\t\tstruct {\n\t\t\tcompat_timer_t _tid;\n\t\t\tint _overrun;\n\t\t\tcompat_sigval_t _sigval;\n\t\t} _timer;\n\t\tstruct {\n\t\t\tcompat_pid_t _pid;\n\t\t\t__compat_uid32_t _uid;\n\t\t\tcompat_sigval_t _sigval;\n\t\t} _rt;\n\t\tstruct {\n\t\t\tcompat_pid_t _pid;\n\t\t\t__compat_uid32_t _uid;\n\t\t\tint _status;\n\t\t\tcompat_clock_t _utime;\n\t\t\tcompat_clock_t _stime;\n\t\t} _sigchld;\n\t\tstruct {\n\t\t\tcompat_uptr_t _addr;\n\t\t\tunion {\n\t\t\t\tint _trapno;\n\t\t\t\tshort int _addr_lsb;\n\t\t\t\tstruct {\n\t\t\t\t\tchar _dummy_bnd[4];\n\t\t\t\t\tcompat_uptr_t _lower;\n\t\t\t\t\tcompat_uptr_t _upper;\n\t\t\t\t} _addr_bnd;\n\t\t\t\tstruct {\n\t\t\t\t\tchar _dummy_pkey[4];\n\t\t\t\t\tu32 _pkey;\n\t\t\t\t} _addr_pkey;\n\t\t\t\tstruct {\n\t\t\t\t\tcompat_ulong_t _data;\n\t\t\t\t\tu32 _type;\n\t\t\t\t} _perf;\n\t\t\t};\n\t\t} _sigfault;\n\t\tstruct {\n\t\t\tcompat_long_t _band;\n\t\t\tint _fd;\n\t\t} _sigpoll;\n\t\tstruct {\n\t\t\tcompat_uptr_t _call_addr;\n\t\t\tint _syscall;\n\t\t\tunsigned int _arch;\n\t\t} _sigsys;\n\t} _sifields;\n};\n\ntypedef struct compat_siginfo compat_siginfo_t;\n\nenum bug_trap_type {\n\tBUG_TRAP_TYPE_NONE = 0,\n\tBUG_TRAP_TYPE_WARN = 1,\n\tBUG_TRAP_TYPE_BUG = 2,\n};\n\nenum insn_mode {\n\tINSN_MODE_32 = 0,\n\tINSN_MODE_64 = 1,\n\tINSN_MODE_KERN = 2,\n\tINSN_NUM_MODES = 3,\n};\n\ntypedef u8 kprobe_opcode_t;\n\nstruct kprobe;\n\nstruct arch_specific_insn {\n\tkprobe_opcode_t *insn;\n\tunsigned int boostable: 1;\n\tunsigned char size;\n\tunion {\n\t\tunsigned char opcode;\n\t\tstruct {\n\t\t\tunsigned char type;\n\t\t} jcc;\n\t\tstruct {\n\t\t\tunsigned char type;\n\t\t\tunsigned char asize;\n\t\t} loop;\n\t\tstruct {\n\t\t\tunsigned char reg;\n\t\t} indirect;\n\t};\n\ts32 rel32;\n\tvoid (*emulate_op)(struct kprobe *, struct pt_regs *);\n\tint tp_len;\n};\n\ntypedef int (*kprobe_pre_handler_t)(struct kprobe *, struct pt_regs *);\n\ntypedef void (*kprobe_post_handler_t)(struct kprobe *, struct pt_regs *, long unsigned int);\n\nstruct kprobe {\n\tstruct hlist_node hlist;\n\tstruct list_head list;\n\tlong unsigned int nmissed;\n\tkprobe_opcode_t *addr;\n\tconst char *symbol_name;\n\tunsigned int offset;\n\tkprobe_pre_handler_t pre_handler;\n\tkprobe_post_handler_t post_handler;\n\tkprobe_opcode_t opcode;\n\tstruct arch_specific_insn ainsn;\n\tu32 flags;\n};\n\nenum die_val {\n\tDIE_OOPS = 1,\n\tDIE_INT3 = 2,\n\tDIE_DEBUG = 3,\n\tDIE_PANIC = 4,\n\tDIE_NMI = 5,\n\tDIE_DIE = 6,\n\tDIE_KERNELDEBUG = 7,\n\tDIE_TRAP = 8,\n\tDIE_GPF = 9,\n\tDIE_CALL = 10,\n\tDIE_PAGE_FAULT = 11,\n\tDIE_NMIUNKNOWN = 12,\n};\n\nenum kernel_gp_hint {\n\tGP_NO_HINT = 0,\n\tGP_NON_CANONICAL = 1,\n\tGP_CANONICAL = 2,\n};\n\nstruct bad_iret_stack {\n\tvoid *error_entry_ret;\n\tstruct pt_regs regs;\n};\n\ntypedef struct irq_desc *vector_irq_t[256];\n\nstruct trace_event_raw_x86_irq_vector {\n\tstruct trace_entry ent;\n\tint vector;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_config {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tunsigned int vector;\n\tunsigned int cpu;\n\tunsigned int apicdest;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_mod {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tunsigned int vector;\n\tunsigned int cpu;\n\tunsigned int prev_vector;\n\tunsigned int prev_cpu;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_reserve {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_alloc {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tunsigned int vector;\n\tbool reserved;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_alloc_managed {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tunsigned int vector;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_activate {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tbool is_managed;\n\tbool can_reserve;\n\tbool reserve;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_teardown {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tbool is_managed;\n\tbool has_reserved;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_setup {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tbool is_legacy;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_vector_free_moved {\n\tstruct trace_entry ent;\n\tunsigned int irq;\n\tunsigned int cpu;\n\tunsigned int vector;\n\tbool is_managed;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_x86_irq_vector {};\n\nstruct trace_event_data_offsets_vector_config {};\n\nstruct trace_event_data_offsets_vector_mod {};\n\nstruct trace_event_data_offsets_vector_reserve {};\n\nstruct trace_event_data_offsets_vector_alloc {};\n\nstruct trace_event_data_offsets_vector_alloc_managed {};\n\nstruct trace_event_data_offsets_vector_activate {};\n\nstruct trace_event_data_offsets_vector_teardown {};\n\nstruct trace_event_data_offsets_vector_setup {};\n\nstruct trace_event_data_offsets_vector_free_moved {};\n\ntypedef void (*btf_trace_local_timer_entry)(void *, int);\n\ntypedef void (*btf_trace_local_timer_exit)(void *, int);\n\ntypedef void (*btf_trace_spurious_apic_entry)(void *, int);\n\ntypedef void (*btf_trace_spurious_apic_exit)(void *, int);\n\ntypedef void (*btf_trace_error_apic_entry)(void *, int);\n\ntypedef void (*btf_trace_error_apic_exit)(void *, int);\n\ntypedef void (*btf_trace_x86_platform_ipi_entry)(void *, int);\n\ntypedef void (*btf_trace_x86_platform_ipi_exit)(void *, int);\n\ntypedef void (*btf_trace_irq_work_entry)(void *, int);\n\ntypedef void (*btf_trace_irq_work_exit)(void *, int);\n\ntypedef void (*btf_trace_reschedule_entry)(void *, int);\n\ntypedef void (*btf_trace_reschedule_exit)(void *, int);\n\ntypedef void (*btf_trace_call_function_entry)(void *, int);\n\ntypedef void (*btf_trace_call_function_exit)(void *, int);\n\ntypedef void (*btf_trace_call_function_single_entry)(void *, int);\n\ntypedef void (*btf_trace_call_function_single_exit)(void *, int);\n\ntypedef void (*btf_trace_threshold_apic_entry)(void *, int);\n\ntypedef void (*btf_trace_threshold_apic_exit)(void *, int);\n\ntypedef void (*btf_trace_deferred_error_apic_entry)(void *, int);\n\ntypedef void (*btf_trace_deferred_error_apic_exit)(void *, int);\n\ntypedef void (*btf_trace_thermal_apic_entry)(void *, int);\n\ntypedef void (*btf_trace_thermal_apic_exit)(void *, int);\n\ntypedef void (*btf_trace_vector_config)(void *, unsigned int, unsigned int, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_vector_update)(void *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_vector_clear)(void *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_vector_reserve_managed)(void *, unsigned int, int);\n\ntypedef void (*btf_trace_vector_reserve)(void *, unsigned int, int);\n\ntypedef void (*btf_trace_vector_alloc)(void *, unsigned int, unsigned int, bool, int);\n\ntypedef void (*btf_trace_vector_alloc_managed)(void *, unsigned int, unsigned int, int);\n\ntypedef void (*btf_trace_vector_activate)(void *, unsigned int, bool, bool, bool);\n\ntypedef void (*btf_trace_vector_deactivate)(void *, unsigned int, bool, bool, bool);\n\ntypedef void (*btf_trace_vector_teardown)(void *, unsigned int, bool, bool);\n\ntypedef void (*btf_trace_vector_setup)(void *, unsigned int, bool, int);\n\ntypedef void (*btf_trace_vector_free_moved)(void *, unsigned int, unsigned int, unsigned int, bool);\n\nstruct irq_stack {\n\tchar stack[16384];\n};\n\nstruct estack_pages {\n\tu32 offs;\n\tu16 size;\n\tu16 type;\n};\n\nenum lockdown_reason {\n\tLOCKDOWN_NONE = 0,\n\tLOCKDOWN_MODULE_SIGNATURE = 1,\n\tLOCKDOWN_DEV_MEM = 2,\n\tLOCKDOWN_EFI_TEST = 3,\n\tLOCKDOWN_KEXEC = 4,\n\tLOCKDOWN_HIBERNATION = 5,\n\tLOCKDOWN_PCI_ACCESS = 6,\n\tLOCKDOWN_IOPORT = 7,\n\tLOCKDOWN_MSR = 8,\n\tLOCKDOWN_ACPI_TABLES = 9,\n\tLOCKDOWN_PCMCIA_CIS = 10,\n\tLOCKDOWN_TIOCSSERIAL = 11,\n\tLOCKDOWN_MODULE_PARAMETERS = 12,\n\tLOCKDOWN_MMIOTRACE = 13,\n\tLOCKDOWN_DEBUGFS = 14,\n\tLOCKDOWN_XMON_WR = 15,\n\tLOCKDOWN_BPF_WRITE_USER = 16,\n\tLOCKDOWN_INTEGRITY_MAX = 17,\n\tLOCKDOWN_KCORE = 18,\n\tLOCKDOWN_KPROBES = 19,\n\tLOCKDOWN_BPF_READ_KERNEL = 20,\n\tLOCKDOWN_PERF = 21,\n\tLOCKDOWN_TRACEFS = 22,\n\tLOCKDOWN_XMON_RW = 23,\n\tLOCKDOWN_XFRM_SECRET = 24,\n\tLOCKDOWN_CONFIDENTIALITY_MAX = 25,\n};\n\nenum lockdep_ok {\n\tLOCKDEP_STILL_OK = 0,\n\tLOCKDEP_NOW_UNRELIABLE = 1,\n};\n\nstruct trace_event_raw_nmi_handler {\n\tstruct trace_entry ent;\n\tvoid *handler;\n\ts64 delta_ns;\n\tint handled;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_nmi_handler {};\n\ntypedef void (*btf_trace_nmi_handler)(void *, void *, s64, int);\n\nstruct nmi_desc {\n\traw_spinlock_t lock;\n\tstruct list_head head;\n};\n\nstruct nmi_stats {\n\tunsigned int normal;\n\tunsigned int unknown;\n\tunsigned int external;\n\tunsigned int swallow;\n};\n\nenum nmi_states {\n\tNMI_NOT_RUNNING = 0,\n\tNMI_EXECUTING = 1,\n\tNMI_LATCHED = 2,\n};\n\nstruct user_desc {\n\tunsigned int entry_number;\n\tunsigned int base_addr;\n\tunsigned int limit;\n\tunsigned int seg_32bit: 1;\n\tunsigned int contents: 2;\n\tunsigned int read_exec_only: 1;\n\tunsigned int limit_in_pages: 1;\n\tunsigned int seg_not_present: 1;\n\tunsigned int useable: 1;\n\tunsigned int lm: 1;\n};\n\nenum con_scroll {\n\tSM_UP = 0,\n\tSM_DOWN = 1,\n};\n\nenum vc_intensity {\n\tVCI_HALF_BRIGHT = 0,\n\tVCI_NORMAL = 1,\n\tVCI_BOLD = 2,\n\tVCI_MASK = 3,\n};\n\nstruct vc_data;\n\nstruct console_font;\n\nstruct consw {\n\tstruct module *owner;\n\tconst char * (*con_startup)();\n\tvoid (*con_init)(struct vc_data *, int);\n\tvoid (*con_deinit)(struct vc_data *);\n\tvoid (*con_clear)(struct vc_data *, int, int, int, int);\n\tvoid (*con_putc)(struct vc_data *, int, int, int);\n\tvoid (*con_putcs)(struct vc_data *, const short unsigned int *, int, int, int);\n\tvoid (*con_cursor)(struct vc_data *, int);\n\tbool (*con_scroll)(struct vc_data *, unsigned int, unsigned int, enum con_scroll, unsigned int);\n\tint (*con_switch)(struct vc_data *);\n\tint (*con_blank)(struct vc_data *, int, int);\n\tint (*con_font_set)(struct vc_data *, struct console_font *, unsigned int);\n\tint (*con_font_get)(struct vc_data *, struct console_font *);\n\tint (*con_font_default)(struct vc_data *, struct console_font *, char *);\n\tint (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int);\n\tvoid (*con_set_palette)(struct vc_data *, const unsigned char *);\n\tvoid (*con_scrolldelta)(struct vc_data *, int);\n\tint (*con_set_origin)(struct vc_data *);\n\tvoid (*con_save_screen)(struct vc_data *);\n\tu8 (*con_build_attr)(struct vc_data *, u8, enum vc_intensity, bool, bool, bool, bool);\n\tvoid (*con_invert_region)(struct vc_data *, u16 *, int);\n\tu16 * (*con_screen_pos)(const struct vc_data *, int);\n\tlong unsigned int (*con_getxy)(struct vc_data *, long unsigned int, int *, int *);\n\tvoid (*con_flush_scrollback)(struct vc_data *);\n\tint (*con_debug_enter)(struct vc_data *);\n\tint (*con_debug_leave)(struct vc_data *);\n};\n\nstruct vc_state {\n\tunsigned int x;\n\tunsigned int y;\n\tunsigned char color;\n\tunsigned char Gx_charset[2];\n\tunsigned int charset: 1;\n\tenum vc_intensity intensity;\n\tbool italic;\n\tbool underline;\n\tbool blink;\n\tbool reverse;\n};\n\nstruct console_font {\n\tunsigned int width;\n\tunsigned int height;\n\tunsigned int charcount;\n\tunsigned char *data;\n};\n\nstruct vt_mode {\n\tchar mode;\n\tchar waitv;\n\tshort int relsig;\n\tshort int acqsig;\n\tshort int frsig;\n};\n\nstruct uni_pagedir;\n\nstruct uni_screen;\n\nstruct vc_data {\n\tstruct tty_port port;\n\tstruct vc_state state;\n\tstruct vc_state saved_state;\n\tshort unsigned int vc_num;\n\tunsigned int vc_cols;\n\tunsigned int vc_rows;\n\tunsigned int vc_size_row;\n\tunsigned int vc_scan_lines;\n\tunsigned int vc_cell_height;\n\tlong unsigned int vc_origin;\n\tlong unsigned int vc_scr_end;\n\tlong unsigned int vc_visible_origin;\n\tunsigned int vc_top;\n\tunsigned int vc_bottom;\n\tconst struct consw *vc_sw;\n\tshort unsigned int *vc_screenbuf;\n\tunsigned int vc_screenbuf_size;\n\tunsigned char vc_mode;\n\tunsigned char vc_attr;\n\tunsigned char vc_def_color;\n\tunsigned char vc_ulcolor;\n\tunsigned char vc_itcolor;\n\tunsigned char vc_halfcolor;\n\tunsigned int vc_cursor_type;\n\tshort unsigned int vc_complement_mask;\n\tshort unsigned int vc_s_complement_mask;\n\tlong unsigned int vc_pos;\n\tshort unsigned int vc_hi_font_mask;\n\tstruct console_font vc_font;\n\tshort unsigned int vc_video_erase_char;\n\tunsigned int vc_state;\n\tunsigned int vc_npar;\n\tunsigned int vc_par[16];\n\tstruct vt_mode vt_mode;\n\tstruct pid *vt_pid;\n\tint vt_newvt;\n\twait_queue_head_t paste_wait;\n\tunsigned int vc_disp_ctrl: 1;\n\tunsigned int vc_toggle_meta: 1;\n\tunsigned int vc_decscnm: 1;\n\tunsigned int vc_decom: 1;\n\tunsigned int vc_decawm: 1;\n\tunsigned int vc_deccm: 1;\n\tunsigned int vc_decim: 1;\n\tunsigned int vc_priv: 3;\n\tunsigned int vc_need_wrap: 1;\n\tunsigned int vc_can_do_color: 1;\n\tunsigned int vc_report_mouse: 2;\n\tunsigned char vc_utf: 1;\n\tunsigned char vc_utf_count;\n\tint vc_utf_char;\n\tlong unsigned int vc_tab_stop[4];\n\tunsigned char vc_palette[48];\n\tshort unsigned int *vc_translate;\n\tunsigned int vc_resize_user;\n\tunsigned int vc_bell_pitch;\n\tunsigned int vc_bell_duration;\n\tshort unsigned int vc_cur_blink_ms;\n\tstruct vc_data **vc_display_fg;\n\tstruct uni_pagedir *vc_uni_pagedir;\n\tstruct uni_pagedir **vc_uni_pagedir_loc;\n\tstruct uni_screen *vc_uni_screen;\n};\n\nstruct edd {\n\tunsigned int mbr_signature[16];\n\tstruct edd_info edd_info[6];\n\tunsigned char mbr_signature_nr;\n\tunsigned char edd_info_nr;\n};\n\nstruct setup_data {\n\t__u64 next;\n\t__u32 type;\n\t__u32 len;\n\t__u8 data[0];\n};\n\nstruct setup_indirect {\n\t__u32 type;\n\t__u32 reserved;\n\t__u64 len;\n\t__u64 addr;\n};\n\nenum memblock_flags {\n\tMEMBLOCK_NONE = 0,\n\tMEMBLOCK_HOTPLUG = 1,\n\tMEMBLOCK_MIRROR = 2,\n\tMEMBLOCK_NOMAP = 4,\n};\n\nstruct memblock_region {\n\tphys_addr_t base;\n\tphys_addr_t size;\n\tenum memblock_flags flags;\n\tint nid;\n};\n\nstruct memblock_type {\n\tlong unsigned int cnt;\n\tlong unsigned int max;\n\tphys_addr_t total_size;\n\tstruct memblock_region *regions;\n\tchar *name;\n};\n\nstruct memblock {\n\tbool bottom_up;\n\tphys_addr_t current_limit;\n\tstruct memblock_type memory;\n\tstruct memblock_type reserved;\n};\n\nstruct x86_msi_ops {\n\tvoid (*restore_msi_irqs)(struct pci_dev *);\n};\n\nstruct legacy_pic {\n\tint nr_legacy_irqs;\n\tstruct irq_chip *chip;\n\tvoid (*mask)(unsigned int);\n\tvoid (*unmask)(unsigned int);\n\tvoid (*mask_all)();\n\tvoid (*restore_mask)();\n\tvoid (*init)(int);\n\tint (*probe)();\n\tint (*irq_pending)(unsigned int);\n\tvoid (*make_irq)(unsigned int);\n};\n\nenum jump_label_type {\n\tJUMP_LABEL_NOP = 0,\n\tJUMP_LABEL_JMP = 1,\n};\n\nunion text_poke_insn {\n\tu8 text[5];\n\tstruct {\n\t\tu8 opcode;\n\t\ts32 disp;\n\t} __attribute__((packed));\n};\n\nstruct jump_label_patch {\n\tconst void *code;\n\tint size;\n};\n\nenum {\n\tJL_STATE_START = 0,\n\tJL_STATE_NO_UPDATE = 1,\n\tJL_STATE_UPDATE = 2,\n};\n\ntypedef short unsigned int __kernel_old_uid_t;\n\ntypedef short unsigned int __kernel_old_gid_t;\n\ntypedef struct {\n\tint val[2];\n} __kernel_fsid_t;\n\ntypedef __kernel_old_uid_t old_uid_t;\n\ntypedef __kernel_old_gid_t old_gid_t;\n\nstruct kernel_clone_args {\n\tu64 flags;\n\tint *pidfd;\n\tint *child_tid;\n\tint *parent_tid;\n\tint exit_signal;\n\tlong unsigned int stack;\n\tlong unsigned int stack_size;\n\tlong unsigned int tls;\n\tpid_t *set_tid;\n\tsize_t set_tid_size;\n\tint cgroup;\n\tint io_thread;\n\tstruct cgroup *cgrp;\n\tstruct css_set *cset;\n};\n\nstruct kstatfs {\n\tlong int f_type;\n\tlong int f_bsize;\n\tu64 f_blocks;\n\tu64 f_bfree;\n\tu64 f_bavail;\n\tu64 f_files;\n\tu64 f_ffree;\n\t__kernel_fsid_t f_fsid;\n\tlong int f_namelen;\n\tlong int f_frsize;\n\tlong int f_flags;\n\tlong int f_spare[4];\n};\n\nstruct stat64 {\n\tlong long unsigned int st_dev;\n\tunsigned char __pad0[4];\n\tunsigned int __st_ino;\n\tunsigned int st_mode;\n\tunsigned int st_nlink;\n\tunsigned int st_uid;\n\tunsigned int st_gid;\n\tlong long unsigned int st_rdev;\n\tunsigned char __pad3[4];\n\tlong long int st_size;\n\tunsigned int st_blksize;\n\tlong long int st_blocks;\n\tunsigned int st_atime;\n\tunsigned int st_atime_nsec;\n\tunsigned int st_mtime;\n\tunsigned int st_mtime_nsec;\n\tunsigned int st_ctime;\n\tunsigned int st_ctime_nsec;\n\tlong long unsigned int st_ino;\n} __attribute__((packed));\n\nstruct mmap_arg_struct32 {\n\tunsigned int addr;\n\tunsigned int len;\n\tunsigned int prot;\n\tunsigned int flags;\n\tunsigned int fd;\n\tunsigned int offset;\n};\n\nstruct vm_unmapped_area_info {\n\tlong unsigned int flags;\n\tlong unsigned int length;\n\tlong unsigned int low_limit;\n\tlong unsigned int high_limit;\n\tlong unsigned int align_mask;\n\tlong unsigned int align_offset;\n};\n\nenum align_flags {\n\tALIGN_VA_32 = 1,\n\tALIGN_VA_64 = 2,\n};\n\nstruct va_alignment {\n\tint flags;\n\tlong unsigned int mask;\n\tlong unsigned int bits;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct kobj_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct kobject *, struct kobj_attribute *, char *);\n\tssize_t (*store)(struct kobject *, struct kobj_attribute *, const char *, size_t);\n};\n\ntypedef void (*swap_func_t)(void *, void *, int);\n\ntypedef int (*cmp_func_t)(const void *, const void *);\n\nenum {\n\tIORES_DESC_NONE = 0,\n\tIORES_DESC_CRASH_KERNEL = 1,\n\tIORES_DESC_ACPI_TABLES = 2,\n\tIORES_DESC_ACPI_NV_STORAGE = 3,\n\tIORES_DESC_PERSISTENT_MEMORY = 4,\n\tIORES_DESC_PERSISTENT_MEMORY_LEGACY = 5,\n\tIORES_DESC_DEVICE_PRIVATE_MEMORY = 6,\n\tIORES_DESC_RESERVED = 7,\n\tIORES_DESC_SOFT_RESERVED = 8,\n};\n\nstruct change_member {\n\tstruct e820_entry *entry;\n\tlong long unsigned int addr;\n};\n\nstruct iommu_fault_param;\n\nstruct iopf_device_param;\n\nstruct iommu_fwspec;\n\nstruct dev_iommu {\n\tstruct mutex lock;\n\tstruct iommu_fault_param *fault_param;\n\tstruct iopf_device_param *iopf_param;\n\tstruct iommu_fwspec *fwspec;\n\tstruct iommu_device *iommu_dev;\n\tvoid *priv;\n};\n\nstruct of_phandle_args {\n\tstruct device_node *np;\n\tint args_count;\n\tuint32_t args[16];\n};\n\nstruct iommu_fault_unrecoverable {\n\t__u32 reason;\n\t__u32 flags;\n\t__u32 pasid;\n\t__u32 perm;\n\t__u64 addr;\n\t__u64 fetch_addr;\n};\n\nstruct iommu_fault_page_request {\n\t__u32 flags;\n\t__u32 pasid;\n\t__u32 grpid;\n\t__u32 perm;\n\t__u64 addr;\n\t__u64 private_data[2];\n};\n\nstruct iommu_fault {\n\t__u32 type;\n\t__u32 padding;\n\tunion {\n\t\tstruct iommu_fault_unrecoverable event;\n\t\tstruct iommu_fault_page_request prm;\n\t\t__u8 padding2[56];\n\t};\n};\n\nstruct iommu_page_response {\n\t__u32 argsz;\n\t__u32 version;\n\t__u32 flags;\n\t__u32 pasid;\n\t__u32 grpid;\n\t__u32 code;\n};\n\nstruct iommu_inv_addr_info {\n\t__u32 flags;\n\t__u32 archid;\n\t__u64 pasid;\n\t__u64 addr;\n\t__u64 granule_size;\n\t__u64 nb_granules;\n};\n\nstruct iommu_inv_pasid_info {\n\t__u32 flags;\n\t__u32 archid;\n\t__u64 pasid;\n};\n\nstruct iommu_cache_invalidate_info {\n\t__u32 argsz;\n\t__u32 version;\n\t__u8 cache;\n\t__u8 granularity;\n\t__u8 padding[6];\n\tunion {\n\t\tstruct iommu_inv_pasid_info pasid_info;\n\t\tstruct iommu_inv_addr_info addr_info;\n\t} granu;\n};\n\nstruct iommu_gpasid_bind_data_vtd {\n\t__u64 flags;\n\t__u32 pat;\n\t__u32 emt;\n};\n\nstruct iommu_gpasid_bind_data {\n\t__u32 argsz;\n\t__u32 version;\n\t__u32 format;\n\t__u32 addr_width;\n\t__u64 flags;\n\t__u64 gpgd;\n\t__u64 hpasid;\n\t__u64 gpasid;\n\t__u8 padding[8];\n\tunion {\n\t\tstruct iommu_gpasid_bind_data_vtd vtd;\n\t} vendor;\n};\n\ntypedef int (*iommu_fault_handler_t)(struct iommu_domain *, struct device *, long unsigned int, int, void *);\n\nstruct iommu_domain_geometry {\n\tdma_addr_t aperture_start;\n\tdma_addr_t aperture_end;\n\tbool force_aperture;\n};\n\nstruct iommu_domain {\n\tunsigned int type;\n\tconst struct iommu_ops *ops;\n\tlong unsigned int pgsize_bitmap;\n\tiommu_fault_handler_t handler;\n\tvoid *handler_token;\n\tstruct iommu_domain_geometry geometry;\n\tvoid *iova_cookie;\n};\n\ntypedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *);\n\nenum iommu_resv_type {\n\tIOMMU_RESV_DIRECT = 0,\n\tIOMMU_RESV_DIRECT_RELAXABLE = 1,\n\tIOMMU_RESV_RESERVED = 2,\n\tIOMMU_RESV_MSI = 3,\n\tIOMMU_RESV_SW_MSI = 4,\n};\n\nstruct iommu_resv_region {\n\tstruct list_head list;\n\tphys_addr_t start;\n\tsize_t length;\n\tint prot;\n\tenum iommu_resv_type type;\n};\n\nstruct iommu_iotlb_gather {\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tsize_t pgsize;\n\tstruct page *freelist;\n};\n\nstruct iommu_device {\n\tstruct list_head list;\n\tconst struct iommu_ops *ops;\n\tstruct fwnode_handle *fwnode;\n\tstruct device *dev;\n};\n\nstruct iommu_sva {\n\tstruct device *dev;\n};\n\nstruct iommu_fault_event {\n\tstruct iommu_fault fault;\n\tstruct list_head list;\n};\n\nstruct iommu_fault_param {\n\tiommu_dev_fault_handler_t handler;\n\tvoid *data;\n\tstruct list_head faults;\n\tstruct mutex lock;\n};\n\nstruct iommu_fwspec {\n\tconst struct iommu_ops *ops;\n\tstruct fwnode_handle *iommu_fwnode;\n\tu32 flags;\n\tunsigned int num_ids;\n\tu32 ids[0];\n};\n\nenum dmi_field {\n\tDMI_NONE = 0,\n\tDMI_BIOS_VENDOR = 1,\n\tDMI_BIOS_VERSION = 2,\n\tDMI_BIOS_DATE = 3,\n\tDMI_BIOS_RELEASE = 4,\n\tDMI_EC_FIRMWARE_RELEASE = 5,\n\tDMI_SYS_VENDOR = 6,\n\tDMI_PRODUCT_NAME = 7,\n\tDMI_PRODUCT_VERSION = 8,\n\tDMI_PRODUCT_SERIAL = 9,\n\tDMI_PRODUCT_UUID = 10,\n\tDMI_PRODUCT_SKU = 11,\n\tDMI_PRODUCT_FAMILY = 12,\n\tDMI_BOARD_VENDOR = 13,\n\tDMI_BOARD_NAME = 14,\n\tDMI_BOARD_VERSION = 15,\n\tDMI_BOARD_SERIAL = 16,\n\tDMI_BOARD_ASSET_TAG = 17,\n\tDMI_CHASSIS_VENDOR = 18,\n\tDMI_CHASSIS_TYPE = 19,\n\tDMI_CHASSIS_VERSION = 20,\n\tDMI_CHASSIS_SERIAL = 21,\n\tDMI_CHASSIS_ASSET_TAG = 22,\n\tDMI_STRING_MAX = 23,\n\tDMI_OEM_STRING = 24,\n};\n\nenum {\n\tNONE_FORCE_HPET_RESUME = 0,\n\tOLD_ICH_FORCE_HPET_RESUME = 1,\n\tICH_FORCE_HPET_RESUME = 2,\n\tVT8237_FORCE_HPET_RESUME = 3,\n\tNVIDIA_FORCE_HPET_RESUME = 4,\n\tATI_FORCE_HPET_RESUME = 5,\n};\n\nenum meminit_context {\n\tMEMINIT_EARLY = 0,\n\tMEMINIT_HOTPLUG = 1,\n};\n\nstruct cpu {\n\tint node_id;\n\tint hotpluggable;\n\tstruct device dev;\n};\n\nstruct x86_cpu {\n\tstruct cpu cpu;\n};\n\nstruct debugfs_blob_wrapper {\n\tvoid *data;\n\tlong unsigned int size;\n};\n\nstruct setup_data_node {\n\tu64 paddr;\n\tu32 type;\n\tu32 len;\n};\n\nstruct paravirt_patch_site {\n\tu8 *instr;\n\tu8 type;\n\tu8 len;\n};\n\nstruct die_args {\n\tstruct pt_regs *regs;\n\tconst char *str;\n\tlong int err;\n\tint trapnr;\n\tint signr;\n};\n\nstruct tlb_state_shared {\n\tbool is_lazy;\n};\n\nstruct smp_alt_module {\n\tstruct module *mod;\n\tchar *name;\n\tconst s32 *locks;\n\tconst s32 *locks_end;\n\tu8 *text;\n\tu8 *text_end;\n\tstruct list_head next;\n};\n\ntypedef struct {\n\tstruct mm_struct *mm;\n} temp_mm_state_t;\n\nstruct text_poke_loc {\n\ts32 rel_addr;\n\ts32 rel32;\n\tu8 opcode;\n\tconst u8 text[5];\n\tu8 old;\n};\n\nstruct bp_patching_desc {\n\tstruct text_poke_loc *vec;\n\tint nr_entries;\n\tatomic_t refs;\n};\n\nenum {\n\tHW_BREAKPOINT_LEN_1 = 1,\n\tHW_BREAKPOINT_LEN_2 = 2,\n\tHW_BREAKPOINT_LEN_3 = 3,\n\tHW_BREAKPOINT_LEN_4 = 4,\n\tHW_BREAKPOINT_LEN_5 = 5,\n\tHW_BREAKPOINT_LEN_6 = 6,\n\tHW_BREAKPOINT_LEN_7 = 7,\n\tHW_BREAKPOINT_LEN_8 = 8,\n};\n\nenum {\n\tHW_BREAKPOINT_EMPTY = 0,\n\tHW_BREAKPOINT_R = 1,\n\tHW_BREAKPOINT_W = 2,\n\tHW_BREAKPOINT_RW = 3,\n\tHW_BREAKPOINT_X = 4,\n\tHW_BREAKPOINT_INVALID = 7,\n};\n\ntypedef unsigned int u_int;\n\ntypedef long long unsigned int cycles_t;\n\nstruct system_counterval_t {\n\tu64 cycles;\n\tstruct clocksource *cs;\n};\n\ntypedef struct {\n\tseqcount_t seqcount;\n} seqcount_latch_t;\n\nenum cpufreq_table_sorting {\n\tCPUFREQ_TABLE_UNSORTED = 0,\n\tCPUFREQ_TABLE_SORTED_ASCENDING = 1,\n\tCPUFREQ_TABLE_SORTED_DESCENDING = 2,\n};\n\nstruct cpufreq_cpuinfo {\n\tunsigned int max_freq;\n\tunsigned int min_freq;\n\tunsigned int transition_latency;\n};\n\nstruct clk;\n\nstruct cpufreq_governor;\n\nstruct cpufreq_frequency_table;\n\nstruct cpufreq_stats;\n\nstruct thermal_cooling_device;\n\nstruct cpufreq_policy {\n\tcpumask_var_t cpus;\n\tcpumask_var_t related_cpus;\n\tcpumask_var_t real_cpus;\n\tunsigned int shared_type;\n\tunsigned int cpu;\n\tstruct clk *clk;\n\tstruct cpufreq_cpuinfo cpuinfo;\n\tunsigned int min;\n\tunsigned int max;\n\tunsigned int cur;\n\tunsigned int suspend_freq;\n\tunsigned int policy;\n\tunsigned int last_policy;\n\tstruct cpufreq_governor *governor;\n\tvoid *governor_data;\n\tchar last_governor[16];\n\tstruct work_struct update;\n\tstruct freq_constraints constraints;\n\tstruct freq_qos_request *min_freq_req;\n\tstruct freq_qos_request *max_freq_req;\n\tstruct cpufreq_frequency_table *freq_table;\n\tenum cpufreq_table_sorting freq_table_sorted;\n\tstruct list_head policy_list;\n\tstruct kobject kobj;\n\tstruct completion kobj_unregister;\n\tstruct rw_semaphore rwsem;\n\tbool fast_switch_possible;\n\tbool fast_switch_enabled;\n\tbool strict_target;\n\tunsigned int transition_delay_us;\n\tbool dvfs_possible_from_any_cpu;\n\tunsigned int cached_target_freq;\n\tunsigned int cached_resolved_idx;\n\tbool transition_ongoing;\n\tspinlock_t transition_lock;\n\twait_queue_head_t transition_wait;\n\tstruct task_struct *transition_task;\n\tstruct cpufreq_stats *stats;\n\tvoid *driver_data;\n\tstruct thermal_cooling_device *cdev;\n\tstruct notifier_block nb_min;\n\tstruct notifier_block nb_max;\n};\n\nstruct cpufreq_governor {\n\tchar name[16];\n\tint (*init)(struct cpufreq_policy *);\n\tvoid (*exit)(struct cpufreq_policy *);\n\tint (*start)(struct cpufreq_policy *);\n\tvoid (*stop)(struct cpufreq_policy *);\n\tvoid (*limits)(struct cpufreq_policy *);\n\tssize_t (*show_setspeed)(struct cpufreq_policy *, char *);\n\tint (*store_setspeed)(struct cpufreq_policy *, unsigned int);\n\tstruct list_head governor_list;\n\tstruct module *owner;\n\tu8 flags;\n};\n\nstruct cpufreq_frequency_table {\n\tunsigned int flags;\n\tunsigned int driver_data;\n\tunsigned int frequency;\n};\n\nstruct cpufreq_freqs {\n\tstruct cpufreq_policy *policy;\n\tunsigned int old;\n\tunsigned int new;\n\tu8 flags;\n};\n\nstruct cyc2ns {\n\tstruct cyc2ns_data data[2];\n\tseqcount_latch_t seq;\n};\n\nstruct x86_cpu_id {\n\t__u16 vendor;\n\t__u16 family;\n\t__u16 model;\n\t__u16 steppings;\n\t__u16 feature;\n\tkernel_ulong_t driver_data;\n};\n\nstruct muldiv {\n\tu32 multiplier;\n\tu32 divider;\n};\n\nstruct freq_desc {\n\tbool use_msr_plat;\n\tstruct muldiv muldiv[16];\n\tu32 freqs[16];\n\tu32 mask;\n};\n\nstruct dmi_strmatch {\n\tunsigned char slot: 7;\n\tunsigned char exact_match: 1;\n\tchar substr[79];\n};\n\nstruct dmi_system_id {\n\tint (*callback)(const struct dmi_system_id *);\n\tconst char *ident;\n\tstruct dmi_strmatch matches[4];\n\tvoid *driver_data;\n};\n\nstruct pdev_archdata {};\n\nstruct platform_device_id;\n\nstruct mfd_cell;\n\nstruct platform_device {\n\tconst char *name;\n\tint id;\n\tbool id_auto;\n\tstruct device dev;\n\tu64 platform_dma_mask;\n\tstruct device_dma_parameters dma_parms;\n\tu32 num_resources;\n\tstruct resource *resource;\n\tconst struct platform_device_id *id_entry;\n\tchar *driver_override;\n\tstruct mfd_cell *mfd_cell;\n\tstruct pdev_archdata archdata;\n};\n\nstruct platform_device_id {\n\tchar name[20];\n\tkernel_ulong_t driver_data;\n};\n\nstruct rtc_time {\n\tint tm_sec;\n\tint tm_min;\n\tint tm_hour;\n\tint tm_mday;\n\tint tm_mon;\n\tint tm_year;\n\tint tm_wday;\n\tint tm_yday;\n\tint tm_isdst;\n};\n\nstruct pnp_device_id {\n\t__u8 id[8];\n\tkernel_ulong_t driver_data;\n};\n\nstruct pnp_card_device_id {\n\t__u8 id[8];\n\tkernel_ulong_t driver_data;\n\tstruct {\n\t\t__u8 id[8];\n\t} devs[8];\n};\n\nstruct acpi_table_header {\n\tchar signature[4];\n\tu32 length;\n\tu8 revision;\n\tu8 checksum;\n\tchar oem_id[6];\n\tchar oem_table_id[8];\n\tu32 oem_revision;\n\tchar asl_compiler_id[4];\n\tu32 asl_compiler_revision;\n};\n\nstruct acpi_generic_address {\n\tu8 space_id;\n\tu8 bit_width;\n\tu8 bit_offset;\n\tu8 access_width;\n\tu64 address;\n} __attribute__((packed));\n\nstruct acpi_table_fadt {\n\tstruct acpi_table_header header;\n\tu32 facs;\n\tu32 dsdt;\n\tu8 model;\n\tu8 preferred_profile;\n\tu16 sci_interrupt;\n\tu32 smi_command;\n\tu8 acpi_enable;\n\tu8 acpi_disable;\n\tu8 s4_bios_request;\n\tu8 pstate_control;\n\tu32 pm1a_event_block;\n\tu32 pm1b_event_block;\n\tu32 pm1a_control_block;\n\tu32 pm1b_control_block;\n\tu32 pm2_control_block;\n\tu32 pm_timer_block;\n\tu32 gpe0_block;\n\tu32 gpe1_block;\n\tu8 pm1_event_length;\n\tu8 pm1_control_length;\n\tu8 pm2_control_length;\n\tu8 pm_timer_length;\n\tu8 gpe0_block_length;\n\tu8 gpe1_block_length;\n\tu8 gpe1_base;\n\tu8 cst_control;\n\tu16 c2_latency;\n\tu16 c3_latency;\n\tu16 flush_size;\n\tu16 flush_stride;\n\tu8 duty_offset;\n\tu8 duty_width;\n\tu8 day_alarm;\n\tu8 month_alarm;\n\tu8 century;\n\tu16 boot_flags;\n\tu8 reserved;\n\tu32 flags;\n\tstruct acpi_generic_address reset_register;\n\tu8 reset_value;\n\tu16 arm_boot_flags;\n\tu8 minor_revision;\n\tu64 Xfacs;\n\tu64 Xdsdt;\n\tstruct acpi_generic_address xpm1a_event_block;\n\tstruct acpi_generic_address xpm1b_event_block;\n\tstruct acpi_generic_address xpm1a_control_block;\n\tstruct acpi_generic_address xpm1b_control_block;\n\tstruct acpi_generic_address xpm2_control_block;\n\tstruct acpi_generic_address xpm_timer_block;\n\tstruct acpi_generic_address xgpe0_block;\n\tstruct acpi_generic_address xgpe1_block;\n\tstruct acpi_generic_address sleep_control;\n\tstruct acpi_generic_address sleep_status;\n\tu64 hypervisor_id;\n} __attribute__((packed));\n\nstruct pnp_protocol;\n\nstruct pnp_id;\n\nstruct pnp_card {\n\tstruct device dev;\n\tunsigned char number;\n\tstruct list_head global_list;\n\tstruct list_head protocol_list;\n\tstruct list_head devices;\n\tstruct pnp_protocol *protocol;\n\tstruct pnp_id *id;\n\tchar name[50];\n\tunsigned char pnpver;\n\tunsigned char productver;\n\tunsigned int serial;\n\tunsigned char checksum;\n\tstruct proc_dir_entry *procdir;\n};\n\nstruct pnp_dev;\n\nstruct pnp_protocol {\n\tstruct list_head protocol_list;\n\tchar *name;\n\tint (*get)(struct pnp_dev *);\n\tint (*set)(struct pnp_dev *);\n\tint (*disable)(struct pnp_dev *);\n\tbool (*can_wakeup)(struct pnp_dev *);\n\tint (*suspend)(struct pnp_dev *, pm_message_t);\n\tint (*resume)(struct pnp_dev *);\n\tunsigned char number;\n\tstruct device dev;\n\tstruct list_head cards;\n\tstruct list_head devices;\n};\n\nstruct pnp_id {\n\tchar id[8];\n\tstruct pnp_id *next;\n};\n\nstruct pnp_card_driver;\n\nstruct pnp_card_link {\n\tstruct pnp_card *card;\n\tstruct pnp_card_driver *driver;\n\tvoid *driver_data;\n\tpm_message_t pm_state;\n};\n\nstruct pnp_driver {\n\tconst char *name;\n\tconst struct pnp_device_id *id_table;\n\tunsigned int flags;\n\tint (*probe)(struct pnp_dev *, const struct pnp_device_id *);\n\tvoid (*remove)(struct pnp_dev *);\n\tvoid (*shutdown)(struct pnp_dev *);\n\tint (*suspend)(struct pnp_dev *, pm_message_t);\n\tint (*resume)(struct pnp_dev *);\n\tstruct device_driver driver;\n};\n\nstruct pnp_card_driver {\n\tstruct list_head global_list;\n\tchar *name;\n\tconst struct pnp_card_device_id *id_table;\n\tunsigned int flags;\n\tint (*probe)(struct pnp_card_link *, const struct pnp_card_device_id *);\n\tvoid (*remove)(struct pnp_card_link *);\n\tint (*suspend)(struct pnp_card_link *, pm_message_t);\n\tint (*resume)(struct pnp_card_link *);\n\tstruct pnp_driver link;\n};\n\nstruct pnp_dev {\n\tstruct device dev;\n\tu64 dma_mask;\n\tunsigned int number;\n\tint status;\n\tstruct list_head global_list;\n\tstruct list_head protocol_list;\n\tstruct list_head card_list;\n\tstruct list_head rdev_list;\n\tstruct pnp_protocol *protocol;\n\tstruct pnp_card *card;\n\tstruct pnp_driver *driver;\n\tstruct pnp_card_link *card_link;\n\tstruct pnp_id *id;\n\tint active;\n\tint capabilities;\n\tunsigned int num_dependent_sets;\n\tstruct list_head resources;\n\tstruct list_head options;\n\tchar name[50];\n\tint flags;\n\tstruct proc_dir_entry *procent;\n\tvoid *data;\n};\n\nenum insn_type {\n\tCALL = 0,\n\tNOP = 1,\n\tJMP = 2,\n\tRET = 3,\n};\n\nstruct ldttss_desc {\n\tu16 limit0;\n\tu16 base0;\n\tu16 base1: 8;\n\tu16 type: 5;\n\tu16 dpl: 2;\n\tu16 p: 1;\n\tu16 limit1: 4;\n\tu16 zero0: 3;\n\tu16 g: 1;\n\tu16 base2: 8;\n\tu32 base3;\n\tu32 zero1;\n};\n\ntypedef struct ldttss_desc tss_desc;\n\nenum idle_boot_override {\n\tIDLE_NO_OVERRIDE = 0,\n\tIDLE_HALT = 1,\n\tIDLE_NOMWAIT = 2,\n\tIDLE_POLL = 3,\n};\n\nenum tick_broadcast_mode {\n\tTICK_BROADCAST_OFF = 0,\n\tTICK_BROADCAST_ON = 1,\n\tTICK_BROADCAST_FORCE = 2,\n};\n\nenum tick_broadcast_state {\n\tTICK_BROADCAST_EXIT = 0,\n\tTICK_BROADCAST_ENTER = 1,\n};\n\nstruct inactive_task_frame {\n\tlong unsigned int r15;\n\tlong unsigned int r14;\n\tlong unsigned int r13;\n\tlong unsigned int r12;\n\tlong unsigned int bx;\n\tlong unsigned int bp;\n\tlong unsigned int ret_addr;\n};\n\nstruct fork_frame {\n\tstruct inactive_task_frame frame;\n\tstruct pt_regs regs;\n};\n\nstruct ssb_state {\n\tstruct ssb_state *shared_state;\n\traw_spinlock_t lock;\n\tunsigned int disable_state;\n\tlong unsigned int local_state;\n};\n\nstruct trace_event_raw_x86_fpu {\n\tstruct trace_entry ent;\n\tstruct fpu *fpu;\n\tbool load_fpu;\n\tu64 xfeatures;\n\tu64 xcomp_bv;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_x86_fpu {};\n\ntypedef void (*btf_trace_x86_fpu_before_save)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_after_save)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_before_restore)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_after_restore)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_regs_activated)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_regs_deactivated)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_init_state)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_dropped)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_copy_src)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_copy_dst)(void *, struct fpu *);\n\ntypedef void (*btf_trace_x86_fpu_xstate_check_failed)(void *, struct fpu *);\n\nstruct _fpreg {\n\t__u16 significand[4];\n\t__u16 exponent;\n};\n\nstruct _fpxreg {\n\t__u16 significand[4];\n\t__u16 exponent;\n\t__u16 padding[3];\n};\n\nstruct user_i387_ia32_struct {\n\tu32 cwd;\n\tu32 swd;\n\tu32 twd;\n\tu32 fip;\n\tu32 fcs;\n\tu32 foo;\n\tu32 fos;\n\tu32 st_space[20];\n};\n\nstruct user32_fxsr_struct {\n\tshort unsigned int cwd;\n\tshort unsigned int swd;\n\tshort unsigned int twd;\n\tshort unsigned int fop;\n\tint fip;\n\tint fcs;\n\tint foo;\n\tint fos;\n\tint mxcsr;\n\tint reserved;\n\tint st_space[32];\n\tint xmm_space[32];\n\tint padding[56];\n};\n\nenum xstate_copy_mode {\n\tXSTATE_COPY_FP = 0,\n\tXSTATE_COPY_FX = 1,\n\tXSTATE_COPY_XSAVE = 2,\n};\n\nstruct membuf {\n\tvoid *p;\n\tsize_t left;\n};\n\nstruct user_regset;\n\ntypedef int user_regset_active_fn(struct task_struct *, const struct user_regset *);\n\ntypedef int user_regset_get2_fn(struct task_struct *, const struct user_regset *, struct membuf);\n\ntypedef int user_regset_set_fn(struct task_struct *, const struct user_regset *, unsigned int, unsigned int, const void *, const void *);\n\ntypedef int user_regset_writeback_fn(struct task_struct *, const struct user_regset *, int);\n\nstruct user_regset {\n\tuser_regset_get2_fn *regset_get;\n\tuser_regset_set_fn *set;\n\tuser_regset_active_fn *active;\n\tuser_regset_writeback_fn *writeback;\n\tunsigned int n;\n\tunsigned int size;\n\tunsigned int align;\n\tunsigned int bias;\n\tunsigned int core_note_type;\n};\n\nstruct _fpx_sw_bytes {\n\t__u32 magic1;\n\t__u32 extended_size;\n\t__u64 xfeatures;\n\t__u32 xstate_size;\n\t__u32 padding[7];\n};\n\nstruct _xmmreg {\n\t__u32 element[4];\n};\n\nstruct _fpstate_32 {\n\t__u32 cw;\n\t__u32 sw;\n\t__u32 tag;\n\t__u32 ipoff;\n\t__u32 cssel;\n\t__u32 dataoff;\n\t__u32 datasel;\n\tstruct _fpreg _st[8];\n\t__u16 status;\n\t__u16 magic;\n\t__u32 _fxsr_env[6];\n\t__u32 mxcsr;\n\t__u32 reserved;\n\tstruct _fpxreg _fxsr_st[8];\n\tstruct _xmmreg _xmm[8];\n\tunion {\n\t\t__u32 padding1[44];\n\t\t__u32 padding[44];\n\t};\n\tunion {\n\t\t__u32 padding2[12];\n\t\tstruct _fpx_sw_bytes sw_reserved;\n\t};\n};\n\nstruct pkru_state {\n\tu32 pkru;\n\tu32 pad;\n};\n\nstruct user_regset_view {\n\tconst char *name;\n\tconst struct user_regset *regsets;\n\tunsigned int n;\n\tu32 e_flags;\n\tu16 e_machine;\n\tu8 ei_osabi;\n};\n\nenum x86_regset {\n\tREGSET_GENERAL = 0,\n\tREGSET_FP = 1,\n\tREGSET_XFP = 2,\n\tREGSET_IOPERM64 = 2,\n\tREGSET_XSTATE = 3,\n\tREGSET_TLS = 4,\n\tREGSET_IOPERM32 = 5,\n};\n\nstruct pt_regs_offset {\n\tconst char *name;\n\tint offset;\n};\n\ntypedef bool (*stack_trace_consume_fn)(void *, long unsigned int);\n\nstruct stack_frame_user {\n\tconst void *next_fp;\n\tlong unsigned int ret_addr;\n};\n\nenum cache_type {\n\tCACHE_TYPE_NOCACHE = 0,\n\tCACHE_TYPE_INST = 1,\n\tCACHE_TYPE_DATA = 2,\n\tCACHE_TYPE_SEPARATE = 3,\n\tCACHE_TYPE_UNIFIED = 4,\n};\n\nstruct cacheinfo {\n\tunsigned int id;\n\tenum cache_type type;\n\tunsigned int level;\n\tunsigned int coherency_line_size;\n\tunsigned int number_of_sets;\n\tunsigned int ways_of_associativity;\n\tunsigned int physical_line_partition;\n\tunsigned int size;\n\tcpumask_t shared_cpu_map;\n\tunsigned int attributes;\n\tvoid *fw_token;\n\tbool disable_sysfs;\n\tvoid *priv;\n};\n\nstruct cpu_cacheinfo {\n\tstruct cacheinfo *info_list;\n\tunsigned int num_levels;\n\tunsigned int num_leaves;\n\tbool cpu_map_populated;\n};\n\nstruct amd_l3_cache {\n\tunsigned int indices;\n\tu8 subcaches[4];\n};\n\nstruct threshold_block {\n\tunsigned int block;\n\tunsigned int bank;\n\tunsigned int cpu;\n\tu32 address;\n\tu16 interrupt_enable;\n\tbool interrupt_capable;\n\tu16 threshold_limit;\n\tstruct kobject kobj;\n\tstruct list_head miscj;\n};\n\nstruct threshold_bank {\n\tstruct kobject *kobj;\n\tstruct threshold_block *blocks;\n\trefcount_t cpus;\n\tunsigned int shared;\n};\n\nstruct amd_northbridge {\n\tstruct pci_dev *root;\n\tstruct pci_dev *misc;\n\tstruct pci_dev *link;\n\tstruct amd_l3_cache l3_cache;\n\tstruct threshold_bank *bank4;\n};\n\nstruct _cache_table {\n\tunsigned char descriptor;\n\tchar cache_type;\n\tshort int size;\n};\n\nenum _cache_type {\n\tCTYPE_NULL = 0,\n\tCTYPE_DATA = 1,\n\tCTYPE_INST = 2,\n\tCTYPE_UNIFIED = 3,\n};\n\nunion _cpuid4_leaf_eax {\n\tstruct {\n\t\tenum _cache_type type: 5;\n\t\tunsigned int level: 3;\n\t\tunsigned int is_self_initializing: 1;\n\t\tunsigned int is_fully_associative: 1;\n\t\tunsigned int reserved: 4;\n\t\tunsigned int num_threads_sharing: 12;\n\t\tunsigned int num_cores_on_die: 6;\n\t} split;\n\tu32 full;\n};\n\nunion _cpuid4_leaf_ebx {\n\tstruct {\n\t\tunsigned int coherency_line_size: 12;\n\t\tunsigned int physical_line_partition: 10;\n\t\tunsigned int ways_of_associativity: 10;\n\t} split;\n\tu32 full;\n};\n\nunion _cpuid4_leaf_ecx {\n\tstruct {\n\t\tunsigned int number_of_sets: 32;\n\t} split;\n\tu32 full;\n};\n\nstruct _cpuid4_info_regs {\n\tunion _cpuid4_leaf_eax eax;\n\tunion _cpuid4_leaf_ebx ebx;\n\tunion _cpuid4_leaf_ecx ecx;\n\tunsigned int id;\n\tlong unsigned int size;\n\tstruct amd_northbridge *nb;\n};\n\nunion l1_cache {\n\tstruct {\n\t\tunsigned int line_size: 8;\n\t\tunsigned int lines_per_tag: 8;\n\t\tunsigned int assoc: 8;\n\t\tunsigned int size_in_kb: 8;\n\t};\n\tunsigned int val;\n};\n\nunion l2_cache {\n\tstruct {\n\t\tunsigned int line_size: 8;\n\t\tunsigned int lines_per_tag: 4;\n\t\tunsigned int assoc: 4;\n\t\tunsigned int size_in_kb: 16;\n\t};\n\tunsigned int val;\n};\n\nunion l3_cache {\n\tstruct {\n\t\tunsigned int line_size: 8;\n\t\tunsigned int lines_per_tag: 4;\n\t\tunsigned int assoc: 4;\n\t\tunsigned int res: 2;\n\t\tunsigned int size_encoded: 14;\n\t};\n\tunsigned int val;\n};\n\nstruct cpuid_bit {\n\tu16 feature;\n\tu8 reg;\n\tu8 bit;\n\tu32 level;\n\tu32 sub_leaf;\n};\n\nenum cpuid_leafs {\n\tCPUID_1_EDX = 0,\n\tCPUID_8000_0001_EDX = 1,\n\tCPUID_8086_0001_EDX = 2,\n\tCPUID_LNX_1 = 3,\n\tCPUID_1_ECX = 4,\n\tCPUID_C000_0001_EDX = 5,\n\tCPUID_8000_0001_ECX = 6,\n\tCPUID_LNX_2 = 7,\n\tCPUID_LNX_3 = 8,\n\tCPUID_7_0_EBX = 9,\n\tCPUID_D_1_EAX = 10,\n\tCPUID_LNX_4 = 11,\n\tCPUID_7_1_EAX = 12,\n\tCPUID_8000_0008_EBX = 13,\n\tCPUID_6_EAX = 14,\n\tCPUID_8000_000A_EDX = 15,\n\tCPUID_7_ECX = 16,\n\tCPUID_8000_0007_EBX = 17,\n\tCPUID_7_EDX = 18,\n\tCPUID_8000_001F_EAX = 19,\n};\n\nstruct cpu_dev {\n\tconst char *c_vendor;\n\tconst char *c_ident[2];\n\tvoid (*c_early_init)(struct cpuinfo_x86 *);\n\tvoid (*c_bsp_init)(struct cpuinfo_x86 *);\n\tvoid (*c_init)(struct cpuinfo_x86 *);\n\tvoid (*c_identify)(struct cpuinfo_x86 *);\n\tvoid (*c_detect_tlb)(struct cpuinfo_x86 *);\n\tint c_x86_vendor;\n};\n\nstruct cpuid_dependent_feature {\n\tu32 feature;\n\tu32 level;\n};\n\nenum spectre_v2_mitigation {\n\tSPECTRE_V2_NONE = 0,\n\tSPECTRE_V2_RETPOLINE_GENERIC = 1,\n\tSPECTRE_V2_RETPOLINE_AMD = 2,\n\tSPECTRE_V2_IBRS_ENHANCED = 3,\n};\n\nenum spectre_v2_user_mitigation {\n\tSPECTRE_V2_USER_NONE = 0,\n\tSPECTRE_V2_USER_STRICT = 1,\n\tSPECTRE_V2_USER_STRICT_PREFERRED = 2,\n\tSPECTRE_V2_USER_PRCTL = 3,\n\tSPECTRE_V2_USER_SECCOMP = 4,\n};\n\nenum ssb_mitigation {\n\tSPEC_STORE_BYPASS_NONE = 0,\n\tSPEC_STORE_BYPASS_DISABLE = 1,\n\tSPEC_STORE_BYPASS_PRCTL = 2,\n\tSPEC_STORE_BYPASS_SECCOMP = 3,\n};\n\nenum l1tf_mitigations {\n\tL1TF_MITIGATION_OFF = 0,\n\tL1TF_MITIGATION_FLUSH_NOWARN = 1,\n\tL1TF_MITIGATION_FLUSH = 2,\n\tL1TF_MITIGATION_FLUSH_NOSMT = 3,\n\tL1TF_MITIGATION_FULL = 4,\n\tL1TF_MITIGATION_FULL_FORCE = 5,\n};\n\nenum mds_mitigations {\n\tMDS_MITIGATION_OFF = 0,\n\tMDS_MITIGATION_FULL = 1,\n\tMDS_MITIGATION_VMWERV = 2,\n};\n\nenum cpuhp_smt_control {\n\tCPU_SMT_ENABLED = 0,\n\tCPU_SMT_DISABLED = 1,\n\tCPU_SMT_FORCE_DISABLED = 2,\n\tCPU_SMT_NOT_SUPPORTED = 3,\n\tCPU_SMT_NOT_IMPLEMENTED = 4,\n};\n\nenum vmx_l1d_flush_state {\n\tVMENTER_L1D_FLUSH_AUTO = 0,\n\tVMENTER_L1D_FLUSH_NEVER = 1,\n\tVMENTER_L1D_FLUSH_COND = 2,\n\tVMENTER_L1D_FLUSH_ALWAYS = 3,\n\tVMENTER_L1D_FLUSH_EPT_DISABLED = 4,\n\tVMENTER_L1D_FLUSH_NOT_REQUIRED = 5,\n};\n\nenum taa_mitigations {\n\tTAA_MITIGATION_OFF = 0,\n\tTAA_MITIGATION_UCODE_NEEDED = 1,\n\tTAA_MITIGATION_VERW = 2,\n\tTAA_MITIGATION_TSX_DISABLED = 3,\n};\n\nenum srbds_mitigations {\n\tSRBDS_MITIGATION_OFF = 0,\n\tSRBDS_MITIGATION_UCODE_NEEDED = 1,\n\tSRBDS_MITIGATION_FULL = 2,\n\tSRBDS_MITIGATION_TSX_OFF = 3,\n\tSRBDS_MITIGATION_HYPERVISOR = 4,\n};\n\nenum spectre_v1_mitigation {\n\tSPECTRE_V1_MITIGATION_NONE = 0,\n\tSPECTRE_V1_MITIGATION_AUTO = 1,\n};\n\nenum spectre_v2_mitigation_cmd {\n\tSPECTRE_V2_CMD_NONE = 0,\n\tSPECTRE_V2_CMD_AUTO = 1,\n\tSPECTRE_V2_CMD_FORCE = 2,\n\tSPECTRE_V2_CMD_RETPOLINE = 3,\n\tSPECTRE_V2_CMD_RETPOLINE_GENERIC = 4,\n\tSPECTRE_V2_CMD_RETPOLINE_AMD = 5,\n};\n\nenum spectre_v2_user_cmd {\n\tSPECTRE_V2_USER_CMD_NONE = 0,\n\tSPECTRE_V2_USER_CMD_AUTO = 1,\n\tSPECTRE_V2_USER_CMD_FORCE = 2,\n\tSPECTRE_V2_USER_CMD_PRCTL = 3,\n\tSPECTRE_V2_USER_CMD_PRCTL_IBPB = 4,\n\tSPECTRE_V2_USER_CMD_SECCOMP = 5,\n\tSPECTRE_V2_USER_CMD_SECCOMP_IBPB = 6,\n};\n\nenum ssb_mitigation_cmd {\n\tSPEC_STORE_BYPASS_CMD_NONE = 0,\n\tSPEC_STORE_BYPASS_CMD_AUTO = 1,\n\tSPEC_STORE_BYPASS_CMD_ON = 2,\n\tSPEC_STORE_BYPASS_CMD_PRCTL = 3,\n\tSPEC_STORE_BYPASS_CMD_SECCOMP = 4,\n};\n\nenum hk_flags {\n\tHK_FLAG_TIMER = 1,\n\tHK_FLAG_RCU = 2,\n\tHK_FLAG_MISC = 4,\n\tHK_FLAG_SCHED = 8,\n\tHK_FLAG_TICK = 16,\n\tHK_FLAG_DOMAIN = 32,\n\tHK_FLAG_WQ = 64,\n\tHK_FLAG_MANAGED_IRQ = 128,\n\tHK_FLAG_KTHREAD = 256,\n};\n\nstruct aperfmperf_sample {\n\tunsigned int khz;\n\tatomic_t scfpending;\n\tktime_t time;\n\tu64 aperf;\n\tu64 mperf;\n};\n\nstruct cpuid_dep {\n\tunsigned int feature;\n\tunsigned int depends;\n};\n\nenum vmx_feature_leafs {\n\tMISC_FEATURES = 0,\n\tPRIMARY_CTLS = 1,\n\tSECONDARY_CTLS = 2,\n\tNR_VMX_FEATURE_WORDS = 3,\n};\n\nstruct _tlb_table {\n\tunsigned char descriptor;\n\tchar tlb_type;\n\tunsigned int entries;\n\tchar info[128];\n};\n\nenum tsx_ctrl_states {\n\tTSX_CTRL_ENABLE = 0,\n\tTSX_CTRL_DISABLE = 1,\n\tTSX_CTRL_RTM_ALWAYS_ABORT = 2,\n\tTSX_CTRL_NOT_SUPPORTED = 3,\n};\n\nenum split_lock_detect_state {\n\tsld_off = 0,\n\tsld_warn = 1,\n\tsld_fatal = 2,\n\tsld_ratelimit = 3,\n};\n\nstruct sku_microcode {\n\tu8 model;\n\tu8 stepping;\n\tu32 microcode;\n};\n\nstruct cpuid_regs {\n\tu32 eax;\n\tu32 ebx;\n\tu32 ecx;\n\tu32 edx;\n};\n\nenum pconfig_target {\n\tINVALID_TARGET = 0,\n\tMKTME_TARGET = 1,\n\tPCONFIG_TARGET_NR = 2,\n};\n\nenum {\n\tPCONFIG_CPUID_SUBLEAF_INVALID = 0,\n\tPCONFIG_CPUID_SUBLEAF_TARGETID = 1,\n};\n\nenum task_work_notify_mode {\n\tTWA_NONE = 0,\n\tTWA_RESUME = 1,\n\tTWA_SIGNAL = 2,\n};\n\nenum mf_flags {\n\tMF_COUNT_INCREASED = 1,\n\tMF_ACTION_REQUIRED = 2,\n\tMF_MUST_KILL = 4,\n\tMF_SOFT_OFFLINE = 8,\n};\n\nstruct mce {\n\t__u64 status;\n\t__u64 misc;\n\t__u64 addr;\n\t__u64 mcgstatus;\n\t__u64 ip;\n\t__u64 tsc;\n\t__u64 time;\n\t__u8 cpuvendor;\n\t__u8 inject_flags;\n\t__u8 severity;\n\t__u8 pad;\n\t__u32 cpuid;\n\t__u8 cs;\n\t__u8 bank;\n\t__u8 cpu;\n\t__u8 finished;\n\t__u32 extcpu;\n\t__u32 socketid;\n\t__u32 apicid;\n\t__u64 mcgcap;\n\t__u64 synd;\n\t__u64 ipid;\n\t__u64 ppin;\n\t__u32 microcode;\n\t__u64 kflags;\n};\n\nenum mce_notifier_prios {\n\tMCE_PRIO_LOWEST = 0,\n\tMCE_PRIO_MCELOG = 1,\n\tMCE_PRIO_EDAC = 2,\n\tMCE_PRIO_NFIT = 3,\n\tMCE_PRIO_EXTLOG = 4,\n\tMCE_PRIO_UC = 5,\n\tMCE_PRIO_EARLY = 6,\n\tMCE_PRIO_CEC = 7,\n\tMCE_PRIO_HIGHEST = 7,\n};\n\ntypedef long unsigned int mce_banks_t[1];\n\nenum mcp_flags {\n\tMCP_TIMESTAMP = 1,\n\tMCP_UC = 2,\n\tMCP_DONTLOG = 4,\n};\n\nenum severity_level {\n\tMCE_NO_SEVERITY = 0,\n\tMCE_DEFERRED_SEVERITY = 1,\n\tMCE_UCNA_SEVERITY = 1,\n\tMCE_KEEP_SEVERITY = 2,\n\tMCE_SOME_SEVERITY = 3,\n\tMCE_AO_SEVERITY = 4,\n\tMCE_UC_SEVERITY = 5,\n\tMCE_AR_SEVERITY = 6,\n\tMCE_PANIC_SEVERITY = 7,\n};\n\nstruct mce_evt_llist {\n\tstruct llist_node llnode;\n\tstruct mce mce;\n};\n\nstruct mca_config {\n\tbool dont_log_ce;\n\tbool cmci_disabled;\n\tbool ignore_ce;\n\tbool print_all;\n\t__u64 lmce_disabled: 1;\n\t__u64 disabled: 1;\n\t__u64 ser: 1;\n\t__u64 recovery: 1;\n\t__u64 bios_cmci_threshold: 1;\n\tint: 27;\n\t__u64 __reserved: 59;\n\ts8 bootlog;\n\tint tolerant;\n\tint monarch_timeout;\n\tint panic_timeout;\n\tu32 rip_msr;\n};\n\nstruct mce_vendor_flags {\n\t__u64 overflow_recov: 1;\n\t__u64 succor: 1;\n\t__u64 smca: 1;\n\t__u64 amd_threshold: 1;\n\t__u64 __reserved_0: 60;\n};\n\nstruct mca_msr_regs {\n\tu32 (*ctl)(int);\n\tu32 (*status)(int);\n\tu32 (*addr)(int);\n\tu32 (*misc)(int);\n};\n\nstruct trace_event_raw_mce_record {\n\tstruct trace_entry ent;\n\tu64 mcgcap;\n\tu64 mcgstatus;\n\tu64 status;\n\tu64 addr;\n\tu64 misc;\n\tu64 synd;\n\tu64 ipid;\n\tu64 ip;\n\tu64 tsc;\n\tu64 walltime;\n\tu32 cpu;\n\tu32 cpuid;\n\tu32 apicid;\n\tu32 socketid;\n\tu8 cs;\n\tu8 bank;\n\tu8 cpuvendor;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mce_record {};\n\ntypedef void (*btf_trace_mce_record)(void *, struct mce *);\n\nstruct mce_bank {\n\tu64 ctl;\n\tbool init;\n};\n\nstruct mce_bank_dev {\n\tstruct device_attribute attr;\n\tchar attrname[16];\n\tu8 bank;\n};\n\nenum handler_type {\n\tEX_HANDLER_NONE = 0,\n\tEX_HANDLER_FAULT = 1,\n\tEX_HANDLER_UACCESS = 2,\n\tEX_HANDLER_OTHER = 3,\n};\n\nenum context {\n\tIN_KERNEL = 1,\n\tIN_USER = 2,\n\tIN_KERNEL_RECOV = 3,\n};\n\nenum ser {\n\tSER_REQUIRED = 1,\n\tNO_SER = 2,\n};\n\nenum exception {\n\tEXCP_CONTEXT = 1,\n\tNO_EXCP = 2,\n};\n\nstruct severity {\n\tu64 mask;\n\tu64 result;\n\tunsigned char sev;\n\tunsigned char mcgmask;\n\tunsigned char mcgres;\n\tunsigned char ser;\n\tunsigned char context;\n\tunsigned char excp;\n\tunsigned char covered;\n\tunsigned char cpu_model;\n\tunsigned char cpu_minstepping;\n\tunsigned char bank_lo;\n\tunsigned char bank_hi;\n\tchar *msg;\n};\n\nstruct gen_pool;\n\ntypedef long unsigned int (*genpool_algo_t)(long unsigned int *, long unsigned int, long unsigned int, unsigned int, void *, struct gen_pool *, long unsigned int);\n\nstruct gen_pool {\n\tspinlock_t lock;\n\tstruct list_head chunks;\n\tint min_alloc_order;\n\tgenpool_algo_t algo;\n\tvoid *data;\n\tconst char *name;\n};\n\nenum {\n\tCMCI_STORM_NONE = 0,\n\tCMCI_STORM_ACTIVE = 1,\n\tCMCI_STORM_SUBSIDED = 2,\n};\n\nenum kobject_action {\n\tKOBJ_ADD = 0,\n\tKOBJ_REMOVE = 1,\n\tKOBJ_CHANGE = 2,\n\tKOBJ_MOVE = 3,\n\tKOBJ_ONLINE = 4,\n\tKOBJ_OFFLINE = 5,\n\tKOBJ_BIND = 6,\n\tKOBJ_UNBIND = 7,\n};\n\nenum smca_bank_types {\n\tSMCA_LS = 0,\n\tSMCA_LS_V2 = 1,\n\tSMCA_IF = 2,\n\tSMCA_L2_CACHE = 3,\n\tSMCA_DE = 4,\n\tSMCA_RESERVED = 5,\n\tSMCA_EX = 6,\n\tSMCA_FP = 7,\n\tSMCA_L3_CACHE = 8,\n\tSMCA_CS = 9,\n\tSMCA_CS_V2 = 10,\n\tSMCA_PIE = 11,\n\tSMCA_UMC = 12,\n\tSMCA_UMC_V2 = 13,\n\tSMCA_PB = 14,\n\tSMCA_PSP = 15,\n\tSMCA_PSP_V2 = 16,\n\tSMCA_SMU = 17,\n\tSMCA_SMU_V2 = 18,\n\tSMCA_MP5 = 19,\n\tSMCA_NBIO = 20,\n\tSMCA_PCIE = 21,\n\tSMCA_PCIE_V2 = 22,\n\tSMCA_XGMI_PCS = 23,\n\tSMCA_XGMI_PHY = 24,\n\tSMCA_WAFL_PHY = 25,\n\tN_SMCA_BANK_TYPES = 26,\n};\n\nstruct smca_hwid {\n\tunsigned int bank_type;\n\tu32 hwid_mcatype;\n\tu8 count;\n};\n\nstruct smca_bank {\n\tstruct smca_hwid *hwid;\n\tu32 id;\n\tu8 sysfs_id;\n};\n\nstruct smca_bank_name {\n\tconst char *name;\n\tconst char *long_name;\n};\n\nstruct thresh_restart {\n\tstruct threshold_block *b;\n\tint reset;\n\tint set_lvt_off;\n\tint lvt_off;\n\tu16 old_limit;\n};\n\nstruct threshold_attr {\n\tstruct attribute attr;\n\tssize_t (*show)(struct threshold_block *, char *);\n\tssize_t (*store)(struct threshold_block *, const char *, size_t);\n};\n\nenum {\n\tCPER_SEV_RECOVERABLE = 0,\n\tCPER_SEV_FATAL = 1,\n\tCPER_SEV_CORRECTED = 2,\n\tCPER_SEV_INFORMATIONAL = 3,\n};\n\nstruct cper_record_header {\n\tchar signature[4];\n\tu16 revision;\n\tu32 signature_end;\n\tu16 section_count;\n\tu32 error_severity;\n\tu32 validation_bits;\n\tu32 record_length;\n\tu64 timestamp;\n\tguid_t platform_id;\n\tguid_t partition_id;\n\tguid_t creator_id;\n\tguid_t notification_type;\n\tu64 record_id;\n\tu32 flags;\n\tu64 persistence_information;\n\tu8 reserved[12];\n} __attribute__((packed));\n\nstruct cper_section_descriptor {\n\tu32 section_offset;\n\tu32 section_length;\n\tu16 revision;\n\tu8 validation_bits;\n\tu8 reserved;\n\tu32 flags;\n\tguid_t section_type;\n\tguid_t fru_id;\n\tu32 section_severity;\n\tu8 fru_text[20];\n};\n\nstruct cper_ia_proc_ctx {\n\tu16 reg_ctx_type;\n\tu16 reg_arr_size;\n\tu32 msr_addr;\n\tu64 mm_reg_addr;\n};\n\nstruct cper_sec_mem_err {\n\tu64 validation_bits;\n\tu64 error_status;\n\tu64 physical_addr;\n\tu64 physical_addr_mask;\n\tu16 node;\n\tu16 card;\n\tu16 module;\n\tu16 bank;\n\tu16 device;\n\tu16 row;\n\tu16 column;\n\tu16 bit_pos;\n\tu64 requestor_id;\n\tu64 responder_id;\n\tu64 target_id;\n\tu8 error_type;\n\tu8 extended;\n\tu16 rank;\n\tu16 mem_array_handle;\n\tu16 mem_dev_handle;\n};\n\nenum {\n\tGHES_SEV_NO = 0,\n\tGHES_SEV_CORRECTED = 1,\n\tGHES_SEV_RECOVERABLE = 2,\n\tGHES_SEV_PANIC = 3,\n};\n\nstruct cper_mce_record {\n\tstruct cper_record_header hdr;\n\tstruct cper_section_descriptor sec_hdr;\n\tstruct mce mce;\n};\n\ntypedef int (*cpu_stop_fn_t)(void *);\n\ntypedef __u8 mtrr_type;\n\nstruct mtrr_ops {\n\tu32 vendor;\n\tu32 use_intel_if;\n\tvoid (*set)(unsigned int, long unsigned int, long unsigned int, mtrr_type);\n\tvoid (*set_all)();\n\tvoid (*get)(unsigned int, long unsigned int *, long unsigned int *, mtrr_type *);\n\tint (*get_free_region)(long unsigned int, long unsigned int, int);\n\tint (*validate_add_page)(long unsigned int, long unsigned int, unsigned int);\n\tint (*have_wrcomb)();\n};\n\nstruct set_mtrr_data {\n\tlong unsigned int smp_base;\n\tlong unsigned int smp_size;\n\tunsigned int smp_reg;\n\tmtrr_type smp_type;\n};\n\nstruct mtrr_value {\n\tmtrr_type ltype;\n\tlong unsigned int lbase;\n\tlong unsigned int lsize;\n};\n\nstruct proc_ops {\n\tunsigned int proc_flags;\n\tint (*proc_open)(struct inode *, struct file *);\n\tssize_t (*proc_read)(struct file *, char *, size_t, loff_t *);\n\tssize_t (*proc_read_iter)(struct kiocb *, struct iov_iter *);\n\tssize_t (*proc_write)(struct file *, const char *, size_t, loff_t *);\n\tloff_t (*proc_lseek)(struct file *, loff_t, int);\n\tint (*proc_release)(struct inode *, struct file *);\n\t__poll_t (*proc_poll)(struct file *, struct poll_table_struct *);\n\tlong int (*proc_ioctl)(struct file *, unsigned int, long unsigned int);\n\tlong int (*proc_compat_ioctl)(struct file *, unsigned int, long unsigned int);\n\tint (*proc_mmap)(struct file *, struct vm_area_struct *);\n\tlong unsigned int (*proc_get_unmapped_area)(struct file *, long unsigned int, long unsigned int, long unsigned int, long unsigned int);\n};\n\nstruct mtrr_sentry {\n\t__u64 base;\n\t__u32 size;\n\t__u32 type;\n};\n\nstruct mtrr_gentry {\n\t__u64 base;\n\t__u32 size;\n\t__u32 regnum;\n\t__u32 type;\n\t__u32 _pad;\n};\n\ntypedef u32 compat_uint_t;\n\nstruct mtrr_sentry32 {\n\tcompat_ulong_t base;\n\tcompat_uint_t size;\n\tcompat_uint_t type;\n};\n\nstruct mtrr_gentry32 {\n\tcompat_ulong_t regnum;\n\tcompat_uint_t base;\n\tcompat_uint_t size;\n\tcompat_uint_t type;\n};\n\nstruct mtrr_var_range {\n\t__u32 base_lo;\n\t__u32 base_hi;\n\t__u32 mask_lo;\n\t__u32 mask_hi;\n};\n\nstruct mtrr_state_type {\n\tstruct mtrr_var_range var_ranges[256];\n\tmtrr_type fixed_ranges[88];\n\tunsigned char enabled;\n\tunsigned char have_fixed;\n\tmtrr_type def_type;\n};\n\nstruct fixed_range_block {\n\tint base_msr;\n\tint ranges;\n};\n\nstruct var_mtrr_range_state {\n\tlong unsigned int base_pfn;\n\tlong unsigned int size_pfn;\n\tmtrr_type type;\n};\n\nstruct var_mtrr_state {\n\tlong unsigned int range_startk;\n\tlong unsigned int range_sizek;\n\tlong unsigned int chunk_sizek;\n\tlong unsigned int gran_sizek;\n\tunsigned int reg;\n};\n\nstruct mtrr_cleanup_result {\n\tlong unsigned int gran_sizek;\n\tlong unsigned int chunk_sizek;\n\tlong unsigned int lose_cover_sizek;\n\tunsigned int num_reg;\n\tint bad;\n};\n\nstruct subsys_interface {\n\tconst char *name;\n\tstruct bus_type *subsys;\n\tstruct list_head node;\n\tint (*add_dev)(struct device *, struct subsys_interface *);\n\tvoid (*remove_dev)(struct device *, struct subsys_interface *);\n};\n\nstruct property_entry;\n\nstruct platform_device_info {\n\tstruct device *parent;\n\tstruct fwnode_handle *fwnode;\n\tbool of_node_reused;\n\tconst char *name;\n\tint id;\n\tconst struct resource *res;\n\tunsigned int num_res;\n\tconst void *data;\n\tsize_t size_data;\n\tu64 dma_mask;\n\tconst struct property_entry *properties;\n};\n\nenum dev_prop_type {\n\tDEV_PROP_U8 = 0,\n\tDEV_PROP_U16 = 1,\n\tDEV_PROP_U32 = 2,\n\tDEV_PROP_U64 = 3,\n\tDEV_PROP_STRING = 4,\n\tDEV_PROP_REF = 5,\n};\n\nstruct property_entry {\n\tconst char *name;\n\tsize_t length;\n\tbool is_inline;\n\tenum dev_prop_type type;\n\tunion {\n\t\tconst void *pointer;\n\t\tunion {\n\t\t\tu8 u8_data[8];\n\t\t\tu16 u16_data[4];\n\t\t\tu32 u32_data[2];\n\t\t\tu64 u64_data[1];\n\t\t\tconst char *str[1];\n\t\t} value;\n\t};\n};\n\nstruct builtin_fw {\n\tchar *name;\n\tvoid *data;\n\tlong unsigned int size;\n};\n\nstruct cpio_data {\n\tvoid *data;\n\tsize_t size;\n\tchar name[18];\n};\n\nstruct cpu_signature {\n\tunsigned int sig;\n\tunsigned int pf;\n\tunsigned int rev;\n};\n\nenum ucode_state {\n\tUCODE_OK = 0,\n\tUCODE_NEW = 1,\n\tUCODE_UPDATED = 2,\n\tUCODE_NFOUND = 3,\n\tUCODE_ERROR = 4,\n};\n\nstruct microcode_ops {\n\tenum ucode_state (*request_microcode_user)(int, const void *, size_t);\n\tenum ucode_state (*request_microcode_fw)(int, struct device *, bool);\n\tvoid (*microcode_fini_cpu)(int);\n\tenum ucode_state (*apply_microcode)(int);\n\tint (*collect_cpu_info)(int, struct cpu_signature *);\n};\n\nstruct ucode_cpu_info {\n\tstruct cpu_signature cpu_sig;\n\tint valid;\n\tvoid *mc;\n};\n\nstruct cpu_info_ctx {\n\tstruct cpu_signature *cpu_sig;\n\tint err;\n};\n\nstruct firmware {\n\tsize_t size;\n\tconst u8 *data;\n\tvoid *priv;\n};\n\nstruct ucode_patch {\n\tstruct list_head plist;\n\tvoid *data;\n\tu32 patch_id;\n\tu16 equiv_cpu;\n};\n\nstruct microcode_header_intel {\n\tunsigned int hdrver;\n\tunsigned int rev;\n\tunsigned int date;\n\tunsigned int sig;\n\tunsigned int cksum;\n\tunsigned int ldrver;\n\tunsigned int pf;\n\tunsigned int datasize;\n\tunsigned int totalsize;\n\tunsigned int reserved[3];\n};\n\nstruct microcode_intel {\n\tstruct microcode_header_intel hdr;\n\tunsigned int bits[0];\n};\n\nstruct extended_signature {\n\tunsigned int sig;\n\tunsigned int pf;\n\tunsigned int cksum;\n};\n\nstruct extended_sigtable {\n\tunsigned int count;\n\tunsigned int cksum;\n\tunsigned int reserved[3];\n\tstruct extended_signature sigs[0];\n};\n\nstruct equiv_cpu_entry {\n\tu32 installed_cpu;\n\tu32 fixed_errata_mask;\n\tu32 fixed_errata_compare;\n\tu16 equiv_cpu;\n\tu16 res;\n};\n\nstruct microcode_header_amd {\n\tu32 data_code;\n\tu32 patch_id;\n\tu16 mc_patch_data_id;\n\tu8 mc_patch_data_len;\n\tu8 init_flag;\n\tu32 mc_patch_data_checksum;\n\tu32 nb_dev_id;\n\tu32 sb_dev_id;\n\tu16 processor_rev_id;\n\tu8 nb_rev_id;\n\tu8 sb_rev_id;\n\tu8 bios_api_rev;\n\tu8 reserved1[3];\n\tu32 match_reg[8];\n};\n\nstruct microcode_amd {\n\tstruct microcode_header_amd hdr;\n\tunsigned int mpb[0];\n};\n\nstruct equiv_cpu_table {\n\tunsigned int num_entries;\n\tstruct equiv_cpu_entry *entry;\n};\n\nstruct cont_desc {\n\tstruct microcode_amd *mc;\n\tu32 cpuid_1_eax;\n\tu32 psize;\n\tu8 *data;\n\tsize_t size;\n};\n\ntypedef void (*exitcall_t)();\n\nenum rdt_group_type {\n\tRDTCTRL_GROUP = 0,\n\tRDTMON_GROUP = 1,\n\tRDT_NUM_GROUP = 2,\n};\n\nstruct rdtgroup;\n\nstruct mongroup {\n\tstruct kernfs_node *mon_data_kn;\n\tstruct rdtgroup *parent;\n\tstruct list_head crdtgrp_list;\n\tu32 rmid;\n};\n\nenum rdtgrp_mode {\n\tRDT_MODE_SHAREABLE = 0,\n\tRDT_MODE_EXCLUSIVE = 1,\n\tRDT_MODE_PSEUDO_LOCKSETUP = 2,\n\tRDT_MODE_PSEUDO_LOCKED = 3,\n\tRDT_NUM_MODES = 4,\n};\n\nstruct pseudo_lock_region;\n\nstruct rdtgroup {\n\tstruct kernfs_node *kn;\n\tstruct list_head rdtgroup_list;\n\tu32 closid;\n\tstruct cpumask cpu_mask;\n\tint flags;\n\tatomic_t waitcount;\n\tenum rdt_group_type type;\n\tstruct mongroup mon;\n\tenum rdtgrp_mode mode;\n\tstruct pseudo_lock_region *plr;\n};\n\nstruct rdt_cache {\n\tunsigned int cbm_len;\n\tunsigned int min_cbm_bits;\n\tunsigned int cbm_idx_mult;\n\tunsigned int cbm_idx_offset;\n\tunsigned int shareable_bits;\n\tbool arch_has_sparse_bitmaps;\n\tbool arch_has_empty_bitmaps;\n\tbool arch_has_per_cpu_cfg;\n};\n\nenum membw_throttle_mode {\n\tTHREAD_THROTTLE_UNDEFINED = 0,\n\tTHREAD_THROTTLE_MAX = 1,\n\tTHREAD_THROTTLE_PER_THREAD = 2,\n};\n\nstruct rdt_membw {\n\tu32 min_bw;\n\tu32 bw_gran;\n\tu32 delay_linear;\n\tbool arch_needs_linear;\n\tenum membw_throttle_mode throttle_mode;\n\tbool mba_sc;\n\tu32 *mb_map;\n};\n\nstruct rdt_domain;\n\nstruct msr_param;\n\nstruct rdt_parse_data;\n\nstruct rdt_resource {\n\tint rid;\n\tbool alloc_enabled;\n\tbool mon_enabled;\n\tbool alloc_capable;\n\tbool mon_capable;\n\tchar *name;\n\tint num_closid;\n\tint cache_level;\n\tu32 default_ctrl;\n\tunsigned int msr_base;\n\tvoid (*msr_update)(struct rdt_domain *, struct msr_param *, struct rdt_resource *);\n\tint data_width;\n\tstruct list_head domains;\n\tstruct rdt_cache cache;\n\tstruct rdt_membw membw;\n\tconst char *format_str;\n\tint (*parse_ctrlval)(struct rdt_parse_data *, struct rdt_resource *, struct rdt_domain *);\n\tstruct list_head evt_list;\n\tint num_rmid;\n\tunsigned int mon_scale;\n\tunsigned int mbm_width;\n\tlong unsigned int fflags;\n};\n\nstruct mbm_state;\n\nstruct rdt_domain {\n\tstruct list_head list;\n\tint id;\n\tstruct cpumask cpu_mask;\n\tlong unsigned int *rmid_busy_llc;\n\tstruct mbm_state *mbm_total;\n\tstruct mbm_state *mbm_local;\n\tstruct delayed_work mbm_over;\n\tstruct delayed_work cqm_limbo;\n\tint mbm_work_cpu;\n\tint cqm_work_cpu;\n\tu32 *ctrl_val;\n\tu32 *mbps_val;\n\tu32 new_ctrl;\n\tbool have_new_ctrl;\n\tstruct pseudo_lock_region *plr;\n};\n\nstruct pseudo_lock_region {\n\tstruct rdt_resource *r;\n\tstruct rdt_domain *d;\n\tu32 cbm;\n\twait_queue_head_t lock_thread_wq;\n\tint thread_done;\n\tint cpu;\n\tunsigned int line_size;\n\tunsigned int size;\n\tvoid *kmem;\n\tunsigned int minor;\n\tstruct dentry *debugfs_dir;\n\tstruct list_head pm_reqs;\n};\n\nstruct mbm_state {\n\tu64 chunks;\n\tu64 prev_msr;\n\tu64 prev_bw_msr;\n\tu32 prev_bw;\n\tu32 delta_bw;\n\tbool delta_comp;\n};\n\nstruct msr_param {\n\tstruct rdt_resource *res;\n\tint low;\n\tint high;\n};\n\nstruct rdt_parse_data {\n\tstruct rdtgroup *rdtgrp;\n\tchar *buf;\n};\n\nenum {\n\tRDT_RESOURCE_L3 = 0,\n\tRDT_RESOURCE_L3DATA = 1,\n\tRDT_RESOURCE_L3CODE = 2,\n\tRDT_RESOURCE_L2 = 3,\n\tRDT_RESOURCE_L2DATA = 4,\n\tRDT_RESOURCE_L2CODE = 5,\n\tRDT_RESOURCE_MBA = 6,\n\tRDT_NUM_RESOURCES = 7,\n};\n\nunion cpuid_0x10_1_eax {\n\tstruct {\n\t\tunsigned int cbm_len: 5;\n\t} split;\n\tunsigned int full;\n};\n\nunion cpuid_0x10_3_eax {\n\tstruct {\n\t\tunsigned int max_delay: 12;\n\t} split;\n\tunsigned int full;\n};\n\nunion cpuid_0x10_x_edx {\n\tstruct {\n\t\tunsigned int cos_max: 16;\n\t} split;\n\tunsigned int full;\n};\n\nenum {\n\tRDT_FLAG_CMT = 0,\n\tRDT_FLAG_MBM_TOTAL = 1,\n\tRDT_FLAG_MBM_LOCAL = 2,\n\tRDT_FLAG_L3_CAT = 3,\n\tRDT_FLAG_L3_CDP = 4,\n\tRDT_FLAG_L2_CAT = 5,\n\tRDT_FLAG_L2_CDP = 6,\n\tRDT_FLAG_MBA = 7,\n};\n\nstruct rdt_options {\n\tchar *name;\n\tint flag;\n\tbool force_off;\n\tbool force_on;\n};\n\ntypedef unsigned int uint;\n\nenum kernfs_node_type {\n\tKERNFS_DIR = 1,\n\tKERNFS_FILE = 2,\n\tKERNFS_LINK = 4,\n};\n\nenum kernfs_root_flag {\n\tKERNFS_ROOT_CREATE_DEACTIVATED = 1,\n\tKERNFS_ROOT_EXTRA_OPEN_PERM_CHECK = 2,\n\tKERNFS_ROOT_SUPPORT_EXPORTOP = 4,\n\tKERNFS_ROOT_SUPPORT_USER_XATTR = 8,\n};\n\nstruct kernfs_fs_context {\n\tstruct kernfs_root *root;\n\tvoid *ns_tag;\n\tlong unsigned int magic;\n\tbool new_sb_created;\n};\n\nstruct rdt_fs_context {\n\tstruct kernfs_fs_context kfc;\n\tbool enable_cdpl2;\n\tbool enable_cdpl3;\n\tbool enable_mba_mbps;\n};\n\nstruct mon_evt {\n\tu32 evtid;\n\tchar *name;\n\tstruct list_head list;\n};\n\nunion mon_data_bits {\n\tvoid *priv;\n\tstruct {\n\t\tunsigned int rid: 10;\n\t\tunsigned int evtid: 8;\n\t\tunsigned int domid: 14;\n\t} u;\n};\n\nstruct rmid_read {\n\tstruct rdtgroup *rgrp;\n\tstruct rdt_resource *r;\n\tstruct rdt_domain *d;\n\tint evtid;\n\tbool first;\n\tu64 val;\n};\n\nstruct rftype {\n\tchar *name;\n\tumode_t mode;\n\tconst struct kernfs_ops *kf_ops;\n\tlong unsigned int flags;\n\tlong unsigned int fflags;\n\tint (*seq_show)(struct kernfs_open_file *, struct seq_file *, void *);\n\tssize_t (*write)(struct kernfs_open_file *, char *, size_t, loff_t);\n};\n\nenum rdt_param {\n\tOpt_cdp = 0,\n\tOpt_cdpl2 = 1,\n\tOpt_mba_mbps = 2,\n\tnr__rdt_params = 3,\n};\n\nstruct rmid_entry {\n\tu32 rmid;\n\tint busy;\n\tstruct list_head list;\n};\n\nstruct mbm_correction_factor_table {\n\tu32 rmidthreshold;\n\tu64 cf;\n};\n\nstruct trace_event_raw_pseudo_lock_mem_latency {\n\tstruct trace_entry ent;\n\tu32 latency;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_pseudo_lock_l2 {\n\tstruct trace_entry ent;\n\tu64 l2_hits;\n\tu64 l2_miss;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_pseudo_lock_l3 {\n\tstruct trace_entry ent;\n\tu64 l3_hits;\n\tu64 l3_miss;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_pseudo_lock_mem_latency {};\n\nstruct trace_event_data_offsets_pseudo_lock_l2 {};\n\nstruct trace_event_data_offsets_pseudo_lock_l3 {};\n\ntypedef void (*btf_trace_pseudo_lock_mem_latency)(void *, u32);\n\ntypedef void (*btf_trace_pseudo_lock_l2)(void *, u64, u64);\n\ntypedef void (*btf_trace_pseudo_lock_l3)(void *, u64, u64);\n\nstruct pseudo_lock_pm_req {\n\tstruct list_head list;\n\tstruct dev_pm_qos_request req;\n};\n\nstruct residency_counts {\n\tu64 miss_before;\n\tu64 hits_before;\n\tu64 miss_after;\n\tu64 hits_after;\n};\n\nstruct miscdevice {\n\tint minor;\n\tconst char *name;\n\tconst struct file_operations *fops;\n\tstruct list_head list;\n\tstruct device *parent;\n\tstruct device *this_device;\n\tconst struct attribute_group **groups;\n\tconst char *nodename;\n\tumode_t mode;\n};\n\nenum mmu_notifier_event {\n\tMMU_NOTIFY_UNMAP = 0,\n\tMMU_NOTIFY_CLEAR = 1,\n\tMMU_NOTIFY_PROTECTION_VMA = 2,\n\tMMU_NOTIFY_PROTECTION_PAGE = 3,\n\tMMU_NOTIFY_SOFT_DIRTY = 4,\n\tMMU_NOTIFY_RELEASE = 5,\n\tMMU_NOTIFY_MIGRATE = 6,\n\tMMU_NOTIFY_EXCLUSIVE = 7,\n};\n\nstruct mmu_notifier;\n\nstruct mmu_notifier_range;\n\nstruct mmu_notifier_ops {\n\tvoid (*release)(struct mmu_notifier *, struct mm_struct *);\n\tint (*clear_flush_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int);\n\tint (*clear_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int);\n\tint (*test_young)(struct mmu_notifier *, struct mm_struct *, long unsigned int);\n\tvoid (*change_pte)(struct mmu_notifier *, struct mm_struct *, long unsigned int, pte_t);\n\tint (*invalidate_range_start)(struct mmu_notifier *, const struct mmu_notifier_range *);\n\tvoid (*invalidate_range_end)(struct mmu_notifier *, const struct mmu_notifier_range *);\n\tvoid (*invalidate_range)(struct mmu_notifier *, struct mm_struct *, long unsigned int, long unsigned int);\n\tstruct mmu_notifier * (*alloc_notifier)(struct mm_struct *);\n\tvoid (*free_notifier)(struct mmu_notifier *);\n};\n\nstruct mmu_notifier {\n\tstruct hlist_node hlist;\n\tconst struct mmu_notifier_ops *ops;\n\tstruct mm_struct *mm;\n\tstruct callback_head rcu;\n\tunsigned int users;\n};\n\nstruct mmu_notifier_range {\n\tstruct vm_area_struct *vma;\n\tstruct mm_struct *mm;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tunsigned int flags;\n\tenum mmu_notifier_event event;\n\tvoid *owner;\n};\n\nenum sgx_page_type {\n\tSGX_PAGE_TYPE_SECS = 0,\n\tSGX_PAGE_TYPE_TCS = 1,\n\tSGX_PAGE_TYPE_REG = 2,\n\tSGX_PAGE_TYPE_VA = 3,\n\tSGX_PAGE_TYPE_TRIM = 4,\n};\n\nstruct sgx_encl_page;\n\nstruct sgx_epc_page {\n\tunsigned int section;\n\tunsigned int flags;\n\tstruct sgx_encl_page *owner;\n\tstruct list_head list;\n};\n\nstruct sgx_encl;\n\nstruct sgx_va_page;\n\nstruct sgx_encl_page {\n\tlong unsigned int desc;\n\tlong unsigned int vm_max_prot_bits;\n\tstruct sgx_epc_page *epc_page;\n\tstruct sgx_encl *encl;\n\tstruct sgx_va_page *va_page;\n};\n\nstruct sgx_encl {\n\tlong unsigned int base;\n\tlong unsigned int size;\n\tlong unsigned int flags;\n\tunsigned int page_cnt;\n\tunsigned int secs_child_cnt;\n\tstruct mutex lock;\n\tstruct xarray page_array;\n\tstruct sgx_encl_page secs;\n\tlong unsigned int attributes;\n\tlong unsigned int attributes_mask;\n\tcpumask_t cpumask;\n\tstruct file *backing;\n\tstruct kref refcount;\n\tstruct list_head va_pages;\n\tlong unsigned int mm_list_version;\n\tstruct list_head mm_list;\n\tspinlock_t mm_lock;\n\tstruct srcu_struct srcu;\n};\n\nstruct sgx_va_page {\n\tstruct sgx_epc_page *epc_page;\n\tlong unsigned int slots[8];\n\tstruct list_head list;\n};\n\nstruct sgx_encl_mm {\n\tstruct sgx_encl *encl;\n\tstruct mm_struct *mm;\n\tstruct list_head list;\n\tstruct mmu_notifier mmu_notifier;\n};\n\ntypedef unsigned int xa_mark_t;\n\nstruct xa_node {\n\tunsigned char shift;\n\tunsigned char offset;\n\tunsigned char count;\n\tunsigned char nr_values;\n\tstruct xa_node *parent;\n\tstruct xarray *array;\n\tunion {\n\t\tstruct list_head private_list;\n\t\tstruct callback_head callback_head;\n\t};\n\tvoid *slots[64];\n\tunion {\n\t\tlong unsigned int tags[3];\n\t\tlong unsigned int marks[3];\n\t};\n};\n\ntypedef void (*xa_update_node_t)(struct xa_node *);\n\nstruct xa_state {\n\tstruct xarray *xa;\n\tlong unsigned int xa_index;\n\tunsigned char xa_shift;\n\tunsigned char xa_sibs;\n\tunsigned char xa_offset;\n\tunsigned char xa_pad;\n\tstruct xa_node *xa_node;\n\tstruct xa_node *xa_alloc;\n\txa_update_node_t xa_update;\n};\n\nenum {\n\tXA_CHECK_SCHED = 4096,\n};\n\nenum sgx_encls_function {\n\tECREATE = 0,\n\tEADD = 1,\n\tEINIT = 2,\n\tEREMOVE = 3,\n\tEDGBRD = 4,\n\tEDGBWR = 5,\n\tEEXTEND = 6,\n\tELDU = 8,\n\tEBLOCK = 9,\n\tEPA = 10,\n\tEWB = 11,\n\tETRACK = 12,\n\tEAUG = 13,\n\tEMODPR = 14,\n\tEMODT = 15,\n};\n\nstruct sgx_pageinfo {\n\tu64 addr;\n\tu64 contents;\n\tu64 metadata;\n\tu64 secs;\n};\n\nstruct sgx_numa_node {\n\tstruct list_head free_page_list;\n\tspinlock_t lock;\n};\n\nstruct sgx_epc_section {\n\tlong unsigned int phys_addr;\n\tvoid *virt_addr;\n\tstruct sgx_epc_page *pages;\n\tstruct sgx_numa_node *node;\n};\n\nenum sgx_encl_flags {\n\tSGX_ENCL_IOCTL = 1,\n\tSGX_ENCL_DEBUG = 2,\n\tSGX_ENCL_CREATED = 4,\n\tSGX_ENCL_INITIALIZED = 8,\n};\n\nstruct sgx_backing {\n\tlong unsigned int page_index;\n\tstruct page *contents;\n\tstruct page *pcmd;\n\tlong unsigned int pcmd_offset;\n};\n\nenum sgx_return_code {\n\tSGX_NOT_TRACKED = 11,\n\tSGX_CHILD_PRESENT = 13,\n\tSGX_INVALID_EINITTOKEN = 16,\n\tSGX_UNMASKED_EVENT = 128,\n};\n\nenum sgx_attribute {\n\tSGX_ATTR_INIT = 1,\n\tSGX_ATTR_DEBUG = 2,\n\tSGX_ATTR_MODE64BIT = 4,\n\tSGX_ATTR_PROVISIONKEY = 16,\n\tSGX_ATTR_EINITTOKENKEY = 32,\n\tSGX_ATTR_KSS = 128,\n};\n\nstruct sgx_secs {\n\tu64 size;\n\tu64 base;\n\tu32 ssa_frame_size;\n\tu32 miscselect;\n\tu8 reserved1[24];\n\tu64 attributes;\n\tu64 xfrm;\n\tu32 mrenclave[8];\n\tu8 reserved2[32];\n\tu32 mrsigner[8];\n\tu8 reserved3[32];\n\tu32 config_id[16];\n\tu16 isv_prod_id;\n\tu16 isv_svn;\n\tu16 config_svn;\n\tu8 reserved4[3834];\n};\n\nenum sgx_secinfo_flags {\n\tSGX_SECINFO_R = 1,\n\tSGX_SECINFO_W = 2,\n\tSGX_SECINFO_X = 4,\n\tSGX_SECINFO_SECS = 0,\n\tSGX_SECINFO_TCS = 256,\n\tSGX_SECINFO_REG = 512,\n\tSGX_SECINFO_VA = 768,\n\tSGX_SECINFO_TRIM = 1024,\n};\n\nstruct sgx_secinfo {\n\tu64 flags;\n\tu8 reserved[56];\n};\n\nstruct sgx_sigstruct_header {\n\tu64 header1[2];\n\tu32 vendor;\n\tu32 date;\n\tu64 header2[2];\n\tu32 swdefined;\n\tu8 reserved1[84];\n};\n\nstruct sgx_sigstruct_body {\n\tu32 miscselect;\n\tu32 misc_mask;\n\tu8 reserved2[20];\n\tu64 attributes;\n\tu64 xfrm;\n\tu64 attributes_mask;\n\tu64 xfrm_mask;\n\tu8 mrenclave[32];\n\tu8 reserved3[32];\n\tu16 isvprodid;\n\tu16 isvsvn;\n} __attribute__((packed));\n\nstruct sgx_sigstruct {\n\tstruct sgx_sigstruct_header header;\n\tu8 modulus[384];\n\tu32 exponent;\n\tu8 signature[384];\n\tstruct sgx_sigstruct_body body;\n\tu8 reserved4[12];\n\tu8 q1[384];\n\tu8 q2[384];\n} __attribute__((packed));\n\nstruct crypto_alg;\n\nstruct crypto_tfm {\n\tu32 crt_flags;\n\tint node;\n\tvoid (*exit)(struct crypto_tfm *);\n\tstruct crypto_alg *__crt_alg;\n\tvoid *__crt_ctx[0];\n};\n\nstruct cipher_alg {\n\tunsigned int cia_min_keysize;\n\tunsigned int cia_max_keysize;\n\tint (*cia_setkey)(struct crypto_tfm *, const u8 *, unsigned int);\n\tvoid (*cia_encrypt)(struct crypto_tfm *, u8 *, const u8 *);\n\tvoid (*cia_decrypt)(struct crypto_tfm *, u8 *, const u8 *);\n};\n\nstruct compress_alg {\n\tint (*coa_compress)(struct crypto_tfm *, const u8 *, unsigned int, u8 *, unsigned int *);\n\tint (*coa_decompress)(struct crypto_tfm *, const u8 *, unsigned int, u8 *, unsigned int *);\n};\n\nstruct crypto_istat_aead {\n\tatomic64_t encrypt_cnt;\n\tatomic64_t encrypt_tlen;\n\tatomic64_t decrypt_cnt;\n\tatomic64_t decrypt_tlen;\n\tatomic64_t err_cnt;\n};\n\nstruct crypto_istat_akcipher {\n\tatomic64_t encrypt_cnt;\n\tatomic64_t encrypt_tlen;\n\tatomic64_t decrypt_cnt;\n\tatomic64_t decrypt_tlen;\n\tatomic64_t verify_cnt;\n\tatomic64_t sign_cnt;\n\tatomic64_t err_cnt;\n};\n\nstruct crypto_istat_cipher {\n\tatomic64_t encrypt_cnt;\n\tatomic64_t encrypt_tlen;\n\tatomic64_t decrypt_cnt;\n\tatomic64_t decrypt_tlen;\n\tatomic64_t err_cnt;\n};\n\nstruct crypto_istat_compress {\n\tatomic64_t compress_cnt;\n\tatomic64_t compress_tlen;\n\tatomic64_t decompress_cnt;\n\tatomic64_t decompress_tlen;\n\tatomic64_t err_cnt;\n};\n\nstruct crypto_istat_hash {\n\tatomic64_t hash_cnt;\n\tatomic64_t hash_tlen;\n\tatomic64_t err_cnt;\n};\n\nstruct crypto_istat_kpp {\n\tatomic64_t setsecret_cnt;\n\tatomic64_t generate_public_key_cnt;\n\tatomic64_t compute_shared_secret_cnt;\n\tatomic64_t err_cnt;\n};\n\nstruct crypto_istat_rng {\n\tatomic64_t generate_cnt;\n\tatomic64_t generate_tlen;\n\tatomic64_t seed_cnt;\n\tatomic64_t err_cnt;\n};\n\nstruct crypto_type;\n\nstruct crypto_alg {\n\tstruct list_head cra_list;\n\tstruct list_head cra_users;\n\tu32 cra_flags;\n\tunsigned int cra_blocksize;\n\tunsigned int cra_ctxsize;\n\tunsigned int cra_alignmask;\n\tint cra_priority;\n\trefcount_t cra_refcnt;\n\tchar cra_name[128];\n\tchar cra_driver_name[128];\n\tconst struct crypto_type *cra_type;\n\tunion {\n\t\tstruct cipher_alg cipher;\n\t\tstruct compress_alg compress;\n\t} cra_u;\n\tint (*cra_init)(struct crypto_tfm *);\n\tvoid (*cra_exit)(struct crypto_tfm *);\n\tvoid (*cra_destroy)(struct crypto_alg *);\n\tstruct module *cra_module;\n\tunion {\n\t\tstruct crypto_istat_aead aead;\n\t\tstruct crypto_istat_akcipher akcipher;\n\t\tstruct crypto_istat_cipher cipher;\n\t\tstruct crypto_istat_compress compress;\n\t\tstruct crypto_istat_hash hash;\n\t\tstruct crypto_istat_rng rng;\n\t\tstruct crypto_istat_kpp kpp;\n\t} stats;\n};\n\nstruct crypto_instance;\n\nstruct crypto_type {\n\tunsigned int (*ctxsize)(struct crypto_alg *, u32, u32);\n\tunsigned int (*extsize)(struct crypto_alg *);\n\tint (*init)(struct crypto_tfm *, u32, u32);\n\tint (*init_tfm)(struct crypto_tfm *);\n\tvoid (*show)(struct seq_file *, struct crypto_alg *);\n\tint (*report)(struct sk_buff *, struct crypto_alg *);\n\tvoid (*free)(struct crypto_instance *);\n\tunsigned int type;\n\tunsigned int maskclear;\n\tunsigned int maskset;\n\tunsigned int tfmsize;\n};\n\nstruct crypto_shash;\n\nstruct shash_desc {\n\tstruct crypto_shash *tfm;\n\tvoid *__ctx[0];\n};\n\nstruct crypto_shash {\n\tunsigned int descsize;\n\tstruct crypto_tfm base;\n};\n\nenum sgx_page_flags {\n\tSGX_PAGE_MEASURE = 1,\n};\n\nstruct sgx_enclave_create {\n\t__u64 src;\n};\n\nstruct sgx_enclave_add_pages {\n\t__u64 src;\n\t__u64 offset;\n\t__u64 length;\n\t__u64 secinfo;\n\t__u64 flags;\n\t__u64 count;\n};\n\nstruct sgx_enclave_init {\n\t__u64 sigstruct;\n};\n\nstruct sgx_enclave_provision {\n\t__u64 fd;\n};\n\nstruct sgx_vepc {\n\tstruct xarray page_array;\n\tstruct mutex lock;\n};\n\nstruct vmcb_seg {\n\tu16 selector;\n\tu16 attrib;\n\tu32 limit;\n\tu64 base;\n};\n\nstruct vmcb_save_area {\n\tstruct vmcb_seg es;\n\tstruct vmcb_seg cs;\n\tstruct vmcb_seg ss;\n\tstruct vmcb_seg ds;\n\tstruct vmcb_seg fs;\n\tstruct vmcb_seg gs;\n\tstruct vmcb_seg gdtr;\n\tstruct vmcb_seg ldtr;\n\tstruct vmcb_seg idtr;\n\tstruct vmcb_seg tr;\n\tu8 reserved_1[43];\n\tu8 cpl;\n\tu8 reserved_2[4];\n\tu64 efer;\n\tu8 reserved_3[104];\n\tu64 xss;\n\tu64 cr4;\n\tu64 cr3;\n\tu64 cr0;\n\tu64 dr7;\n\tu64 dr6;\n\tu64 rflags;\n\tu64 rip;\n\tu8 reserved_4[88];\n\tu64 rsp;\n\tu8 reserved_5[24];\n\tu64 rax;\n\tu64 star;\n\tu64 lstar;\n\tu64 cstar;\n\tu64 sfmask;\n\tu64 kernel_gs_base;\n\tu64 sysenter_cs;\n\tu64 sysenter_esp;\n\tu64 sysenter_eip;\n\tu64 cr2;\n\tu8 reserved_6[32];\n\tu64 g_pat;\n\tu64 dbgctl;\n\tu64 br_from;\n\tu64 br_to;\n\tu64 last_excp_from;\n\tu64 last_excp_to;\n\tu8 reserved_7[72];\n\tu32 spec_ctrl;\n\tu8 reserved_7b[4];\n\tu32 pkru;\n\tu8 reserved_7a[20];\n\tu64 reserved_8;\n\tu64 rcx;\n\tu64 rdx;\n\tu64 rbx;\n\tu64 reserved_9;\n\tu64 rbp;\n\tu64 rsi;\n\tu64 rdi;\n\tu64 r8;\n\tu64 r9;\n\tu64 r10;\n\tu64 r11;\n\tu64 r12;\n\tu64 r13;\n\tu64 r14;\n\tu64 r15;\n\tu8 reserved_10[16];\n\tu64 sw_exit_code;\n\tu64 sw_exit_info_1;\n\tu64 sw_exit_info_2;\n\tu64 sw_scratch;\n\tu8 reserved_11[56];\n\tu64 xcr0;\n\tu8 valid_bitmap[16];\n\tu64 x87_state_gpa;\n};\n\nstruct ghcb {\n\tstruct vmcb_save_area save;\n\tu8 reserved_save[1016];\n\tu8 shared_buffer[2032];\n\tu8 reserved_1[10];\n\tu16 protocol_version;\n\tu32 ghcb_usage;\n};\n\nenum intercept_words {\n\tINTERCEPT_CR = 0,\n\tINTERCEPT_DR = 1,\n\tINTERCEPT_EXCEPTION = 2,\n\tINTERCEPT_WORD3 = 3,\n\tINTERCEPT_WORD4 = 4,\n\tINTERCEPT_WORD5 = 5,\n\tMAX_INTERCEPT = 6,\n};\n\nstruct vmware_steal_time {\n\tunion {\n\t\tuint64_t clock;\n\t\tstruct {\n\t\t\tuint32_t clock_low;\n\t\t\tuint32_t clock_high;\n\t\t};\n\t};\n\tuint64_t reserved[7];\n};\n\nstruct mpc_intsrc {\n\tunsigned char type;\n\tunsigned char irqtype;\n\tshort unsigned int irqflag;\n\tunsigned char srcbus;\n\tunsigned char srcbusirq;\n\tunsigned char dstapic;\n\tunsigned char dstirq;\n};\n\nenum mp_irq_source_types {\n\tmp_INT = 0,\n\tmp_NMI = 1,\n\tmp_SMI = 2,\n\tmp_ExtINT = 3,\n};\n\ntypedef u64 acpi_io_address;\n\ntypedef u64 acpi_physical_address;\n\ntypedef char *acpi_string;\n\ntypedef void *acpi_handle;\n\ntypedef u32 acpi_object_type;\n\ntypedef u8 acpi_adr_space_type;\n\nunion acpi_object {\n\tacpi_object_type type;\n\tstruct {\n\t\tacpi_object_type type;\n\t\tu64 value;\n\t} integer;\n\tstruct {\n\t\tacpi_object_type type;\n\t\tu32 length;\n\t\tchar *pointer;\n\t} string;\n\tstruct {\n\t\tacpi_object_type type;\n\t\tu32 length;\n\t\tu8 *pointer;\n\t} buffer;\n\tstruct {\n\t\tacpi_object_type type;\n\t\tu32 count;\n\t\tunion acpi_object *elements;\n\t} package;\n\tstruct {\n\t\tacpi_object_type type;\n\t\tacpi_object_type actual_type;\n\t\tacpi_handle handle;\n\t} reference;\n\tstruct {\n\t\tacpi_object_type type;\n\t\tu32 proc_id;\n\t\tacpi_io_address pblk_address;\n\t\tu32 pblk_length;\n\t} processor;\n\tstruct {\n\t\tacpi_object_type type;\n\t\tu32 system_level;\n\t\tu32 resource_order;\n\t} power_resource;\n};\n\nstruct acpi_object_list {\n\tu32 count;\n\tunion acpi_object *pointer;\n};\n\nstruct acpi_subtable_header {\n\tu8 type;\n\tu8 length;\n};\n\nstruct acpi_table_boot {\n\tstruct acpi_table_header header;\n\tu8 cmos_index;\n\tu8 reserved[3];\n};\n\nstruct acpi_hmat_structure {\n\tu16 type;\n\tu16 reserved;\n\tu32 length;\n};\n\nstruct acpi_table_hpet {\n\tstruct acpi_table_header header;\n\tu32 id;\n\tstruct acpi_generic_address address;\n\tu8 sequence;\n\tu16 minimum_tick;\n\tu8 flags;\n} __attribute__((packed));\n\nstruct acpi_table_madt {\n\tstruct acpi_table_header header;\n\tu32 address;\n\tu32 flags;\n};\n\nenum acpi_madt_type {\n\tACPI_MADT_TYPE_LOCAL_APIC = 0,\n\tACPI_MADT_TYPE_IO_APIC = 1,\n\tACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2,\n\tACPI_MADT_TYPE_NMI_SOURCE = 3,\n\tACPI_MADT_TYPE_LOCAL_APIC_NMI = 4,\n\tACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5,\n\tACPI_MADT_TYPE_IO_SAPIC = 6,\n\tACPI_MADT_TYPE_LOCAL_SAPIC = 7,\n\tACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,\n\tACPI_MADT_TYPE_LOCAL_X2APIC = 9,\n\tACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10,\n\tACPI_MADT_TYPE_GENERIC_INTERRUPT = 11,\n\tACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12,\n\tACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13,\n\tACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14,\n\tACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15,\n\tACPI_MADT_TYPE_MULTIPROC_WAKEUP = 16,\n\tACPI_MADT_TYPE_RESERVED = 17,\n};\n\nstruct acpi_madt_local_apic {\n\tstruct acpi_subtable_header header;\n\tu8 processor_id;\n\tu8 id;\n\tu32 lapic_flags;\n};\n\nstruct acpi_madt_io_apic {\n\tstruct acpi_subtable_header header;\n\tu8 id;\n\tu8 reserved;\n\tu32 address;\n\tu32 global_irq_base;\n};\n\nstruct acpi_madt_interrupt_override {\n\tstruct acpi_subtable_header header;\n\tu8 bus;\n\tu8 source_irq;\n\tu32 global_irq;\n\tu16 inti_flags;\n} __attribute__((packed));\n\nstruct acpi_madt_nmi_source {\n\tstruct acpi_subtable_header header;\n\tu16 inti_flags;\n\tu32 global_irq;\n};\n\nstruct acpi_madt_local_apic_nmi {\n\tstruct acpi_subtable_header header;\n\tu8 processor_id;\n\tu16 inti_flags;\n\tu8 lint;\n} __attribute__((packed));\n\nstruct acpi_madt_local_apic_override {\n\tstruct acpi_subtable_header header;\n\tu16 reserved;\n\tu64 address;\n} __attribute__((packed));\n\nstruct acpi_madt_local_sapic {\n\tstruct acpi_subtable_header header;\n\tu8 processor_id;\n\tu8 id;\n\tu8 eid;\n\tu8 reserved[3];\n\tu32 lapic_flags;\n\tu32 uid;\n\tchar uid_string[1];\n} __attribute__((packed));\n\nstruct acpi_madt_local_x2apic {\n\tstruct acpi_subtable_header header;\n\tu16 reserved;\n\tu32 local_apic_id;\n\tu32 lapic_flags;\n\tu32 uid;\n};\n\nstruct acpi_madt_local_x2apic_nmi {\n\tstruct acpi_subtable_header header;\n\tu16 inti_flags;\n\tu32 uid;\n\tu8 lint;\n\tu8 reserved[3];\n};\n\nstruct acpi_prmt_module_header {\n\tu16 revision;\n\tu16 length;\n};\n\nunion acpi_subtable_headers {\n\tstruct acpi_subtable_header common;\n\tstruct acpi_hmat_structure hmat;\n\tstruct acpi_prmt_module_header prmt;\n};\n\ntypedef int (*acpi_tbl_table_handler)(struct acpi_table_header *);\n\ntypedef int (*acpi_tbl_entry_handler)(union acpi_subtable_headers *, const long unsigned int);\n\nstruct acpi_subtable_proc {\n\tint id;\n\tacpi_tbl_entry_handler handler;\n\tint count;\n};\n\ntypedef u32 phys_cpuid_t;\n\nstruct serial_icounter_struct {\n\tint cts;\n\tint dsr;\n\tint rng;\n\tint dcd;\n\tint rx;\n\tint tx;\n\tint frame;\n\tint overrun;\n\tint parity;\n\tint brk;\n\tint buf_overrun;\n\tint reserved[9];\n};\n\nstruct serial_struct {\n\tint type;\n\tint line;\n\tunsigned int port;\n\tint irq;\n\tint flags;\n\tint xmit_fifo_size;\n\tint custom_divisor;\n\tint baud_base;\n\tshort unsigned int close_delay;\n\tchar io_type;\n\tchar reserved_char[1];\n\tint hub6;\n\tshort unsigned int closing_wait;\n\tshort unsigned int closing_wait2;\n\tunsigned char *iomem_base;\n\tshort unsigned int iomem_reg_shift;\n\tunsigned int port_high;\n\tlong unsigned int iomap_base;\n};\n\nenum ioapic_domain_type {\n\tIOAPIC_DOMAIN_INVALID = 0,\n\tIOAPIC_DOMAIN_LEGACY = 1,\n\tIOAPIC_DOMAIN_STRICT = 2,\n\tIOAPIC_DOMAIN_DYNAMIC = 3,\n};\n\nstruct ioapic_domain_cfg {\n\tenum ioapic_domain_type type;\n\tconst struct irq_domain_ops *ops;\n\tstruct device_node *dev;\n};\n\nstruct wakeup_header {\n\tu16 video_mode;\n\tu32 pmode_entry;\n\tu16 pmode_cs;\n\tu32 pmode_cr0;\n\tu32 pmode_cr3;\n\tu32 pmode_cr4;\n\tu32 pmode_efer_low;\n\tu32 pmode_efer_high;\n\tu64 pmode_gdt;\n\tu32 pmode_misc_en_low;\n\tu32 pmode_misc_en_high;\n\tu32 pmode_behavior;\n\tu32 realmode_flags;\n\tu32 real_magic;\n\tu32 signature;\n} __attribute__((packed));\n\nstruct acpi_hest_header {\n\tu16 type;\n\tu16 source_id;\n};\n\nstruct acpi_hest_ia_error_bank {\n\tu8 bank_number;\n\tu8 clear_status_on_init;\n\tu8 status_format;\n\tu8 reserved;\n\tu32 control_register;\n\tu64 control_data;\n\tu32 status_register;\n\tu32 address_register;\n\tu32 misc_register;\n} __attribute__((packed));\n\nstruct acpi_hest_notify {\n\tu8 type;\n\tu8 length;\n\tu16 config_write_enable;\n\tu32 poll_interval;\n\tu32 vector;\n\tu32 polling_threshold_value;\n\tu32 polling_threshold_window;\n\tu32 error_threshold_value;\n\tu32 error_threshold_window;\n};\n\nstruct acpi_hest_ia_corrected {\n\tstruct acpi_hest_header header;\n\tu16 reserved1;\n\tu8 flags;\n\tu8 enabled;\n\tu32 records_to_preallocate;\n\tu32 max_sections_per_record;\n\tstruct acpi_hest_notify notify;\n\tu8 num_hardware_banks;\n\tu8 reserved2[3];\n};\n\nstruct cpc_reg {\n\tu8 descriptor;\n\tu16 length;\n\tu8 space_id;\n\tu8 bit_width;\n\tu8 bit_offset;\n\tu8 access_width;\n\tu64 address;\n} __attribute__((packed));\n\nstruct acpi_power_register {\n\tu8 descriptor;\n\tu16 length;\n\tu8 space_id;\n\tu8 bit_width;\n\tu8 bit_offset;\n\tu8 access_size;\n\tu64 address;\n} __attribute__((packed));\n\nstruct acpi_processor_cx {\n\tu8 valid;\n\tu8 type;\n\tu32 address;\n\tu8 entry_method;\n\tu8 index;\n\tu32 latency;\n\tu8 bm_sts_skip;\n\tchar desc[32];\n};\n\nstruct acpi_processor_flags {\n\tu8 power: 1;\n\tu8 performance: 1;\n\tu8 throttling: 1;\n\tu8 limit: 1;\n\tu8 bm_control: 1;\n\tu8 bm_check: 1;\n\tu8 has_cst: 1;\n\tu8 has_lpi: 1;\n\tu8 power_setup_done: 1;\n\tu8 bm_rld_set: 1;\n\tu8 need_hotplug_init: 1;\n};\n\nstruct cstate_entry {\n\tstruct {\n\t\tunsigned int eax;\n\t\tunsigned int ecx;\n\t} states[8];\n};\n\nenum reboot_mode {\n\tREBOOT_UNDEFINED = 4294967295,\n\tREBOOT_COLD = 0,\n\tREBOOT_WARM = 1,\n\tREBOOT_HARD = 2,\n\tREBOOT_SOFT = 3,\n\tREBOOT_GPIO = 4,\n};\n\nenum reboot_type {\n\tBOOT_TRIPLE = 116,\n\tBOOT_KBD = 107,\n\tBOOT_BIOS = 98,\n\tBOOT_ACPI = 97,\n\tBOOT_EFI = 101,\n\tBOOT_CF9_FORCE = 112,\n\tBOOT_CF9_SAFE = 113,\n};\n\ntypedef void (*nmi_shootdown_cb)(int, struct pt_regs *);\n\nenum allow_write_msrs {\n\tMSR_WRITES_ON = 0,\n\tMSR_WRITES_OFF = 1,\n\tMSR_WRITES_DEFAULT = 2,\n};\n\ntypedef struct __call_single_data call_single_data_t;\n\nstruct cpuid_regs_done {\n\tstruct cpuid_regs regs;\n\tstruct completion done;\n};\n\nstruct intel_early_ops {\n\tresource_size_t (*stolen_size)(int, int, int);\n\tresource_size_t (*stolen_base)(int, int, int, resource_size_t);\n};\n\nstruct chipset {\n\tu32 vendor;\n\tu32 device;\n\tu32 class;\n\tu32 class_mask;\n\tu32 flags;\n\tvoid (*f)(int, int, int);\n};\n\nenum {\n\tSD_BALANCE_NEWIDLE = 1,\n\tSD_BALANCE_EXEC = 2,\n\tSD_BALANCE_FORK = 4,\n\tSD_BALANCE_WAKE = 8,\n\tSD_WAKE_AFFINE = 16,\n\tSD_ASYM_CPUCAPACITY = 32,\n\tSD_ASYM_CPUCAPACITY_FULL = 64,\n\tSD_SHARE_CPUCAPACITY = 128,\n\tSD_SHARE_PKG_RESOURCES = 256,\n\tSD_SERIALIZE = 512,\n\tSD_ASYM_PACKING = 1024,\n\tSD_PREFER_SIBLING = 2048,\n\tSD_OVERLAP = 4096,\n\tSD_NUMA = 8192,\n};\n\nstruct sched_domain_shared {\n\tatomic_t ref;\n\tatomic_t nr_busy_cpus;\n\tint has_idle_cores;\n};\n\nstruct sched_group;\n\nstruct sched_domain {\n\tstruct sched_domain *parent;\n\tstruct sched_domain *child;\n\tstruct sched_group *groups;\n\tlong unsigned int min_interval;\n\tlong unsigned int max_interval;\n\tunsigned int busy_factor;\n\tunsigned int imbalance_pct;\n\tunsigned int cache_nice_tries;\n\tint nohz_idle;\n\tint flags;\n\tint level;\n\tlong unsigned int last_balance;\n\tunsigned int balance_interval;\n\tunsigned int nr_balance_failed;\n\tu64 max_newidle_lb_cost;\n\tlong unsigned int next_decay_max_lb_cost;\n\tu64 avg_scan_cost;\n\tunsigned int lb_count[3];\n\tunsigned int lb_failed[3];\n\tunsigned int lb_balanced[3];\n\tunsigned int lb_imbalance[3];\n\tunsigned int lb_gained[3];\n\tunsigned int lb_hot_gained[3];\n\tunsigned int lb_nobusyg[3];\n\tunsigned int lb_nobusyq[3];\n\tunsigned int alb_count;\n\tunsigned int alb_failed;\n\tunsigned int alb_pushed;\n\tunsigned int sbe_count;\n\tunsigned int sbe_balanced;\n\tunsigned int sbe_pushed;\n\tunsigned int sbf_count;\n\tunsigned int sbf_balanced;\n\tunsigned int sbf_pushed;\n\tunsigned int ttwu_wake_remote;\n\tunsigned int ttwu_move_affine;\n\tunsigned int ttwu_move_balance;\n\tchar *name;\n\tunion {\n\t\tvoid *private;\n\t\tstruct callback_head rcu;\n\t};\n\tstruct sched_domain_shared *shared;\n\tunsigned int span_weight;\n\tlong unsigned int span[0];\n};\n\ntypedef const struct cpumask * (*sched_domain_mask_f)(int);\n\ntypedef int (*sched_domain_flags_f)();\n\nstruct sched_group_capacity;\n\nstruct sd_data {\n\tstruct sched_domain **sd;\n\tstruct sched_domain_shared **sds;\n\tstruct sched_group **sg;\n\tstruct sched_group_capacity **sgc;\n};\n\nstruct sched_domain_topology_level {\n\tsched_domain_mask_f mask;\n\tsched_domain_flags_f sd_flags;\n\tint flags;\n\tint numa_level;\n\tstruct sd_data data;\n\tchar *name;\n};\n\nenum apic_intr_mode_id {\n\tAPIC_PIC = 0,\n\tAPIC_VIRTUAL_WIRE = 1,\n\tAPIC_VIRTUAL_WIRE_NO_CONFIG = 2,\n\tAPIC_SYMMETRIC_IO = 3,\n\tAPIC_SYMMETRIC_IO_NO_ROUTING = 4,\n};\n\nstruct cppc_perf_caps {\n\tu32 guaranteed_perf;\n\tu32 highest_perf;\n\tu32 nominal_perf;\n\tu32 lowest_perf;\n\tu32 lowest_nonlinear_perf;\n\tu32 lowest_freq;\n\tu32 nominal_freq;\n};\n\nstruct tsc_adjust {\n\ts64 bootval;\n\ts64 adjusted;\n\tlong unsigned int nextcheck;\n\tbool warned;\n};\n\ntypedef void * (*pcpu_fc_alloc_fn_t)(unsigned int, size_t, size_t);\n\ntypedef void (*pcpu_fc_free_fn_t)(void *, size_t);\n\ntypedef void (*pcpu_fc_populate_pte_fn_t)(long unsigned int);\n\ntypedef int pcpu_fc_cpu_distance_fn_t(unsigned int, unsigned int);\n\nenum {\n\tDUMP_PREFIX_NONE = 0,\n\tDUMP_PREFIX_ADDRESS = 1,\n\tDUMP_PREFIX_OFFSET = 2,\n};\n\nstruct mpf_intel {\n\tchar signature[4];\n\tunsigned int physptr;\n\tunsigned char length;\n\tunsigned char specification;\n\tunsigned char checksum;\n\tunsigned char feature1;\n\tunsigned char feature2;\n\tunsigned char feature3;\n\tunsigned char feature4;\n\tunsigned char feature5;\n};\n\nstruct mpc_table {\n\tchar signature[4];\n\tshort unsigned int length;\n\tchar spec;\n\tchar checksum;\n\tchar oem[8];\n\tchar productid[12];\n\tunsigned int oemptr;\n\tshort unsigned int oemsize;\n\tshort unsigned int oemcount;\n\tunsigned int lapic;\n\tunsigned int reserved;\n};\n\nstruct mpc_cpu {\n\tunsigned char type;\n\tunsigned char apicid;\n\tunsigned char apicver;\n\tunsigned char cpuflag;\n\tunsigned int cpufeature;\n\tunsigned int featureflag;\n\tunsigned int reserved[2];\n};\n\nstruct mpc_bus {\n\tunsigned char type;\n\tunsigned char busid;\n\tunsigned char bustype[6];\n};\n\nstruct mpc_ioapic {\n\tunsigned char type;\n\tunsigned char apicid;\n\tunsigned char apicver;\n\tunsigned char flags;\n\tunsigned int apicaddr;\n};\n\nstruct mpc_lintsrc {\n\tunsigned char type;\n\tunsigned char irqtype;\n\tshort unsigned int irqflag;\n\tunsigned char srcbusid;\n\tunsigned char srcbusirq;\n\tunsigned char destapic;\n\tunsigned char destapiclint;\n};\n\nenum page_cache_mode {\n\t_PAGE_CACHE_MODE_WB = 0,\n\t_PAGE_CACHE_MODE_WC = 1,\n\t_PAGE_CACHE_MODE_UC_MINUS = 2,\n\t_PAGE_CACHE_MODE_UC = 3,\n\t_PAGE_CACHE_MODE_WT = 4,\n\t_PAGE_CACHE_MODE_WP = 5,\n\t_PAGE_CACHE_MODE_NUM = 8,\n};\n\nenum {\n\tIRQ_REMAP_XAPIC_MODE = 0,\n\tIRQ_REMAP_X2APIC_MODE = 1,\n};\n\nunion apic_ir {\n\tlong unsigned int map[4];\n\tu32 regs[8];\n};\n\nenum {\n\tX2APIC_OFF = 0,\n\tX2APIC_ON = 1,\n\tX2APIC_DISABLED = 2,\n};\n\nenum {\n\tIRQ_SET_MASK_OK = 0,\n\tIRQ_SET_MASK_OK_NOCOPY = 1,\n\tIRQ_SET_MASK_OK_DONE = 2,\n};\n\nenum {\n\tIRQD_TRIGGER_MASK = 15,\n\tIRQD_SETAFFINITY_PENDING = 256,\n\tIRQD_ACTIVATED = 512,\n\tIRQD_NO_BALANCING = 1024,\n\tIRQD_PER_CPU = 2048,\n\tIRQD_AFFINITY_SET = 4096,\n\tIRQD_LEVEL = 8192,\n\tIRQD_WAKEUP_STATE = 16384,\n\tIRQD_MOVE_PCNTXT = 32768,\n\tIRQD_IRQ_DISABLED = 65536,\n\tIRQD_IRQ_MASKED = 131072,\n\tIRQD_IRQ_INPROGRESS = 262144,\n\tIRQD_WAKEUP_ARMED = 524288,\n\tIRQD_FORWARDED_TO_VCPU = 1048576,\n\tIRQD_AFFINITY_MANAGED = 2097152,\n\tIRQD_IRQ_STARTED = 4194304,\n\tIRQD_MANAGED_SHUTDOWN = 8388608,\n\tIRQD_SINGLE_TARGET = 16777216,\n\tIRQD_DEFAULT_TRIGGER_SET = 33554432,\n\tIRQD_CAN_RESERVE = 67108864,\n\tIRQD_MSI_NOMASK_QUIRK = 134217728,\n\tIRQD_HANDLE_ENFORCE_IRQCTX = 268435456,\n\tIRQD_AFFINITY_ON_ACTIVATE = 536870912,\n\tIRQD_IRQ_ENABLED_ON_SUSPEND = 1073741824,\n};\n\nenum {\n\tX86_IRQ_ALLOC_CONTIGUOUS_VECTORS = 1,\n\tX86_IRQ_ALLOC_LEGACY = 2,\n};\n\nstruct apic_chip_data {\n\tstruct irq_cfg hw_irq_cfg;\n\tunsigned int vector;\n\tunsigned int prev_vector;\n\tunsigned int cpu;\n\tunsigned int prev_cpu;\n\tunsigned int irq;\n\tstruct hlist_node clist;\n\tunsigned int move_in_progress: 1;\n\tunsigned int is_managed: 1;\n\tunsigned int can_reserve: 1;\n\tunsigned int has_reserved: 1;\n};\n\nstruct irq_matrix;\n\nenum {\n\tIRQ_TYPE_NONE = 0,\n\tIRQ_TYPE_EDGE_RISING = 1,\n\tIRQ_TYPE_EDGE_FALLING = 2,\n\tIRQ_TYPE_EDGE_BOTH = 3,\n\tIRQ_TYPE_LEVEL_HIGH = 4,\n\tIRQ_TYPE_LEVEL_LOW = 8,\n\tIRQ_TYPE_LEVEL_MASK = 12,\n\tIRQ_TYPE_SENSE_MASK = 15,\n\tIRQ_TYPE_DEFAULT = 15,\n\tIRQ_TYPE_PROBE = 16,\n\tIRQ_LEVEL = 256,\n\tIRQ_PER_CPU = 512,\n\tIRQ_NOPROBE = 1024,\n\tIRQ_NOREQUEST = 2048,\n\tIRQ_NOAUTOEN = 4096,\n\tIRQ_NO_BALANCING = 8192,\n\tIRQ_MOVE_PCNTXT = 16384,\n\tIRQ_NESTED_THREAD = 32768,\n\tIRQ_NOTHREAD = 65536,\n\tIRQ_PER_CPU_DEVID = 131072,\n\tIRQ_IS_POLLED = 262144,\n\tIRQ_DISABLE_UNLAZY = 524288,\n\tIRQ_HIDDEN = 1048576,\n\tIRQ_NO_DEBUG = 2097152,\n};\n\nstruct clock_event_device___2;\n\nunion IO_APIC_reg_00 {\n\tu32 raw;\n\tstruct {\n\t\tu32 __reserved_2: 14;\n\t\tu32 LTS: 1;\n\t\tu32 delivery_type: 1;\n\t\tu32 __reserved_1: 8;\n\t\tu32 ID: 8;\n\t} bits;\n};\n\nunion IO_APIC_reg_01 {\n\tu32 raw;\n\tstruct {\n\t\tu32 version: 8;\n\t\tu32 __reserved_2: 7;\n\t\tu32 PRQ: 1;\n\t\tu32 entries: 8;\n\t\tu32 __reserved_1: 8;\n\t} bits;\n};\n\nunion IO_APIC_reg_02 {\n\tu32 raw;\n\tstruct {\n\t\tu32 __reserved_2: 24;\n\t\tu32 arbitration: 4;\n\t\tu32 __reserved_1: 4;\n\t} bits;\n};\n\nunion IO_APIC_reg_03 {\n\tu32 raw;\n\tstruct {\n\t\tu32 boot_DT: 1;\n\t\tu32 __reserved_1: 31;\n\t} bits;\n};\n\nstruct IO_APIC_route_entry {\n\tunion {\n\t\tstruct {\n\t\t\tu64 vector: 8;\n\t\t\tu64 delivery_mode: 3;\n\t\t\tu64 dest_mode_logical: 1;\n\t\t\tu64 delivery_status: 1;\n\t\t\tu64 active_low: 1;\n\t\t\tu64 irr: 1;\n\t\t\tu64 is_level: 1;\n\t\t\tu64 masked: 1;\n\t\t\tu64 reserved_0: 15;\n\t\t\tu64 reserved_1: 17;\n\t\t\tu64 virt_destid_8_14: 7;\n\t\t\tu64 destid_0_7: 8;\n\t\t};\n\t\tstruct {\n\t\t\tu64 ir_shared_0: 8;\n\t\t\tu64 ir_zero: 3;\n\t\t\tu64 ir_index_15: 1;\n\t\t\tu64 ir_shared_1: 5;\n\t\t\tu64 ir_reserved_0: 31;\n\t\t\tu64 ir_format: 1;\n\t\t\tu64 ir_index_0_14: 15;\n\t\t};\n\t\tstruct {\n\t\t\tu64 w1: 32;\n\t\t\tu64 w2: 32;\n\t\t};\n\t};\n};\n\nstruct irq_pin_list {\n\tstruct list_head list;\n\tint apic;\n\tint pin;\n};\n\nstruct mp_chip_data {\n\tstruct list_head irq_2_pin;\n\tstruct IO_APIC_route_entry entry;\n\tbool is_level;\n\tbool active_low;\n\tbool isa_irq;\n\tu32 count;\n};\n\nstruct mp_ioapic_gsi {\n\tu32 gsi_base;\n\tu32 gsi_end;\n};\n\nstruct ioapic {\n\tint nr_registers;\n\tstruct IO_APIC_route_entry *saved_registers;\n\tstruct mpc_ioapic mp_config;\n\tstruct mp_ioapic_gsi gsi_config;\n\tstruct ioapic_domain_cfg irqdomain_cfg;\n\tstruct irq_domain *irqdomain;\n\tstruct resource *iomem_res;\n};\n\nstruct io_apic {\n\tunsigned int index;\n\tunsigned int unused[3];\n\tunsigned int data;\n\tunsigned int unused2[11];\n\tunsigned int eoi;\n};\n\nenum {\n\tIRQ_DOMAIN_FLAG_HIERARCHY = 1,\n\tIRQ_DOMAIN_NAME_ALLOCATED = 2,\n\tIRQ_DOMAIN_FLAG_IPI_PER_CPU = 4,\n\tIRQ_DOMAIN_FLAG_IPI_SINGLE = 8,\n\tIRQ_DOMAIN_FLAG_MSI = 16,\n\tIRQ_DOMAIN_FLAG_MSI_REMAP = 32,\n\tIRQ_DOMAIN_MSI_NOMASK_QUIRK = 64,\n\tIRQ_DOMAIN_FLAG_NO_MAP = 128,\n\tIRQ_DOMAIN_FLAG_NONCORE = 65536,\n};\n\nstruct cluster_mask {\n\tunsigned int clusterid;\n\tint node;\n\tstruct cpumask mask;\n};\n\nstruct dyn_arch_ftrace {};\n\nenum {\n\tFTRACE_OPS_FL_ENABLED = 1,\n\tFTRACE_OPS_FL_DYNAMIC = 2,\n\tFTRACE_OPS_FL_SAVE_REGS = 4,\n\tFTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 8,\n\tFTRACE_OPS_FL_RECURSION = 16,\n\tFTRACE_OPS_FL_STUB = 32,\n\tFTRACE_OPS_FL_INITIALIZED = 64,\n\tFTRACE_OPS_FL_DELETED = 128,\n\tFTRACE_OPS_FL_ADDING = 256,\n\tFTRACE_OPS_FL_REMOVING = 512,\n\tFTRACE_OPS_FL_MODIFYING = 1024,\n\tFTRACE_OPS_FL_ALLOC_TRAMP = 2048,\n\tFTRACE_OPS_FL_IPMODIFY = 4096,\n\tFTRACE_OPS_FL_PID = 8192,\n\tFTRACE_OPS_FL_RCU = 16384,\n\tFTRACE_OPS_FL_TRACE_ARRAY = 32768,\n\tFTRACE_OPS_FL_PERMANENT = 65536,\n\tFTRACE_OPS_FL_DIRECT = 131072,\n};\n\nenum {\n\tFTRACE_FL_ENABLED = 2147483648,\n\tFTRACE_FL_REGS = 1073741824,\n\tFTRACE_FL_REGS_EN = 536870912,\n\tFTRACE_FL_TRAMP = 268435456,\n\tFTRACE_FL_TRAMP_EN = 134217728,\n\tFTRACE_FL_IPMODIFY = 67108864,\n\tFTRACE_FL_DISABLED = 33554432,\n\tFTRACE_FL_DIRECT = 16777216,\n\tFTRACE_FL_DIRECT_EN = 8388608,\n};\n\nstruct dyn_ftrace {\n\tlong unsigned int ip;\n\tlong unsigned int flags;\n\tstruct dyn_arch_ftrace arch;\n};\n\nenum {\n\tFTRACE_UPDATE_IGNORE = 0,\n\tFTRACE_UPDATE_MAKE_CALL = 1,\n\tFTRACE_UPDATE_MODIFY_CALL = 2,\n\tFTRACE_UPDATE_MAKE_NOP = 3,\n};\n\nunion ftrace_op_code_union {\n\tchar code[7];\n\tstruct {\n\t\tchar op[3];\n\t\tint offset;\n\t} __attribute__((packed));\n};\n\nstruct ftrace_rec_iter;\n\ntypedef __u64 Elf64_Off;\n\ntypedef __s64 Elf64_Sxword;\n\nstruct elf64_rela {\n\tElf64_Addr r_offset;\n\tElf64_Xword r_info;\n\tElf64_Sxword r_addend;\n};\n\ntypedef struct elf64_rela Elf64_Rela;\n\nstruct elf64_hdr {\n\tunsigned char e_ident[16];\n\tElf64_Half e_type;\n\tElf64_Half e_machine;\n\tElf64_Word e_version;\n\tElf64_Addr e_entry;\n\tElf64_Off e_phoff;\n\tElf64_Off e_shoff;\n\tElf64_Word e_flags;\n\tElf64_Half e_ehsize;\n\tElf64_Half e_phentsize;\n\tElf64_Half e_phnum;\n\tElf64_Half e_shentsize;\n\tElf64_Half e_shnum;\n\tElf64_Half e_shstrndx;\n};\n\ntypedef struct elf64_hdr Elf64_Ehdr;\n\nstruct elf64_shdr {\n\tElf64_Word sh_name;\n\tElf64_Word sh_type;\n\tElf64_Xword sh_flags;\n\tElf64_Addr sh_addr;\n\tElf64_Off sh_offset;\n\tElf64_Xword sh_size;\n\tElf64_Word sh_link;\n\tElf64_Word sh_info;\n\tElf64_Xword sh_addralign;\n\tElf64_Xword sh_entsize;\n};\n\ntypedef struct elf64_shdr Elf64_Shdr;\n\nstruct kimage_arch {\n\tp4d_t *p4d;\n\tpud_t *pud;\n\tpmd_t *pmd;\n\tpte_t *pte;\n};\n\ntypedef long unsigned int kimage_entry_t;\n\nstruct kexec_segment {\n\tunion {\n\t\tvoid *buf;\n\t\tvoid *kbuf;\n\t};\n\tsize_t bufsz;\n\tlong unsigned int mem;\n\tsize_t memsz;\n};\n\nstruct purgatory_info {\n\tconst Elf64_Ehdr *ehdr;\n\tElf64_Shdr *sechdrs;\n\tvoid *purgatory_buf;\n};\n\ntypedef int kexec_probe_t(const char *, long unsigned int);\n\nstruct kimage;\n\ntypedef void *kexec_load_t(struct kimage *, char *, long unsigned int, char *, long unsigned int, char *, long unsigned int);\n\nstruct kexec_file_ops;\n\nstruct kimage {\n\tkimage_entry_t head;\n\tkimage_entry_t *entry;\n\tkimage_entry_t *last_entry;\n\tlong unsigned int start;\n\tstruct page *control_code_page;\n\tstruct page *swap_page;\n\tvoid *vmcoreinfo_data_copy;\n\tlong unsigned int nr_segments;\n\tstruct kexec_segment segment[16];\n\tstruct list_head control_pages;\n\tstruct list_head dest_pages;\n\tstruct list_head unusable_pages;\n\tlong unsigned int control_page;\n\tunsigned int type: 1;\n\tunsigned int preserve_context: 1;\n\tunsigned int file_mode: 1;\n\tstruct kimage_arch arch;\n\tvoid *kernel_buf;\n\tlong unsigned int kernel_buf_len;\n\tvoid *initrd_buf;\n\tlong unsigned int initrd_buf_len;\n\tchar *cmdline_buf;\n\tlong unsigned int cmdline_buf_len;\n\tconst struct kexec_file_ops *fops;\n\tvoid *image_loader_data;\n\tstruct purgatory_info purgatory_info;\n\tvoid *elf_headers;\n\tlong unsigned int elf_headers_sz;\n\tlong unsigned int elf_load_addr;\n};\n\ntypedef int kexec_cleanup_t(void *);\n\nstruct kexec_file_ops {\n\tkexec_probe_t *probe;\n\tkexec_load_t *load;\n\tkexec_cleanup_t *cleanup;\n};\n\nstruct x86_mapping_info {\n\tvoid * (*alloc_pgt_page)(void *);\n\tvoid *context;\n\tlong unsigned int page_flag;\n\tlong unsigned int offset;\n\tbool direct_gbpages;\n\tlong unsigned int kernpg_flag;\n};\n\nstruct init_pgtable_data {\n\tstruct x86_mapping_info *info;\n\tpgd_t *level4p;\n};\n\ntypedef void crash_vmclear_fn();\n\nstruct kexec_buf {\n\tstruct kimage *image;\n\tvoid *buffer;\n\tlong unsigned int bufsz;\n\tlong unsigned int mem;\n\tlong unsigned int memsz;\n\tlong unsigned int buf_align;\n\tlong unsigned int buf_min;\n\tlong unsigned int buf_max;\n\tbool top_down;\n};\n\nstruct crash_mem_range {\n\tu64 start;\n\tu64 end;\n};\n\nstruct crash_mem {\n\tunsigned int max_nr_ranges;\n\tunsigned int nr_ranges;\n\tstruct crash_mem_range ranges[0];\n};\n\nstruct crash_memmap_data {\n\tstruct boot_params *params;\n\tunsigned int type;\n};\n\nstruct kexec_entry64_regs {\n\tuint64_t rax;\n\tuint64_t rcx;\n\tuint64_t rdx;\n\tuint64_t rbx;\n\tuint64_t rsp;\n\tuint64_t rbp;\n\tuint64_t rsi;\n\tuint64_t rdi;\n\tuint64_t r8;\n\tuint64_t r9;\n\tuint64_t r10;\n\tuint64_t r11;\n\tuint64_t r12;\n\tuint64_t r13;\n\tuint64_t r14;\n\tuint64_t r15;\n\tuint64_t rip;\n};\n\nenum key_being_used_for {\n\tVERIFYING_MODULE_SIGNATURE = 0,\n\tVERIFYING_FIRMWARE_SIGNATURE = 1,\n\tVERIFYING_KEXEC_PE_SIGNATURE = 2,\n\tVERIFYING_KEY_SIGNATURE = 3,\n\tVERIFYING_KEY_SELF_SIGNATURE = 4,\n\tVERIFYING_UNSPECIFIED_SIGNATURE = 5,\n\tNR__KEY_BEING_USED_FOR = 6,\n};\n\nstruct efi_setup_data {\n\tu64 fw_vendor;\n\tu64 __unused;\n\tu64 tables;\n\tu64 smbios;\n\tu64 reserved[8];\n};\n\nstruct bzimage64_data {\n\tvoid *bootparams_buf;\n};\n\nstruct freelist_node {\n\tatomic_t refs;\n\tstruct freelist_node *next;\n};\n\nstruct freelist_head {\n\tstruct freelist_node *head;\n};\n\nstruct prev_kprobe {\n\tstruct kprobe *kp;\n\tlong unsigned int status;\n\tlong unsigned int old_flags;\n\tlong unsigned int saved_flags;\n};\n\nstruct kprobe_ctlblk {\n\tlong unsigned int kprobe_status;\n\tlong unsigned int kprobe_old_flags;\n\tlong unsigned int kprobe_saved_flags;\n\tstruct prev_kprobe prev_kprobe;\n};\n\nstruct kretprobe_instance;\n\ntypedef int (*kretprobe_handler_t)(struct kretprobe_instance *, struct pt_regs *);\n\nstruct kretprobe_holder;\n\nstruct kretprobe_instance {\n\tunion {\n\t\tstruct freelist_node freelist;\n\t\tstruct callback_head rcu;\n\t};\n\tstruct llist_node llist;\n\tstruct kretprobe_holder *rph;\n\tkprobe_opcode_t *ret_addr;\n\tvoid *fp;\n\tchar data[0];\n};\n\nstruct kretprobe;\n\nstruct kretprobe_holder {\n\tstruct kretprobe *rp;\n\trefcount_t ref;\n};\n\nstruct kretprobe {\n\tstruct kprobe kp;\n\tkretprobe_handler_t handler;\n\tkretprobe_handler_t entry_handler;\n\tint maxactive;\n\tint nmissed;\n\tsize_t data_size;\n\tstruct freelist_head freelist;\n\tstruct kretprobe_holder *rph;\n};\n\nstruct kretprobe_blackpoint {\n\tconst char *name;\n\tvoid *addr;\n};\n\nstruct kprobe_insn_cache {\n\tstruct mutex mutex;\n\tvoid * (*alloc)();\n\tvoid (*free)(void *);\n\tconst char *sym;\n\tstruct list_head pages;\n\tsize_t insn_size;\n\tint nr_garbage;\n};\n\nstruct __arch_relative_insn {\n\tu8 op;\n\ts32 raddr;\n} __attribute__((packed));\n\nstruct arch_optimized_insn {\n\tkprobe_opcode_t copied_insn[4];\n\tkprobe_opcode_t *insn;\n\tsize_t size;\n};\n\nstruct optimized_kprobe {\n\tstruct kprobe kp;\n\tstruct list_head list;\n\tstruct arch_optimized_insn optinsn;\n};\n\nenum {\n\tTRACE_FTRACE_BIT = 0,\n\tTRACE_FTRACE_NMI_BIT = 1,\n\tTRACE_FTRACE_IRQ_BIT = 2,\n\tTRACE_FTRACE_SIRQ_BIT = 3,\n\tTRACE_INTERNAL_BIT = 4,\n\tTRACE_INTERNAL_NMI_BIT = 5,\n\tTRACE_INTERNAL_IRQ_BIT = 6,\n\tTRACE_INTERNAL_SIRQ_BIT = 7,\n\tTRACE_BRANCH_BIT = 8,\n\tTRACE_IRQ_BIT = 9,\n\tTRACE_GRAPH_BIT = 10,\n\tTRACE_GRAPH_DEPTH_START_BIT = 11,\n\tTRACE_GRAPH_DEPTH_END_BIT = 12,\n\tTRACE_GRAPH_NOTRACE_BIT = 13,\n\tTRACE_TRANSITION_BIT = 14,\n\tTRACE_RECORD_RECURSION_BIT = 15,\n};\n\nenum {\n\tTRACE_CTX_NMI = 0,\n\tTRACE_CTX_IRQ = 1,\n\tTRACE_CTX_SOFTIRQ = 2,\n\tTRACE_CTX_NORMAL = 3,\n};\n\nstruct console {\n\tchar name[16];\n\tvoid (*write)(struct console *, const char *, unsigned int);\n\tint (*read)(struct console *, char *, unsigned int);\n\tstruct tty_driver * (*device)(struct console *, int *);\n\tvoid (*unblank)();\n\tint (*setup)(struct console *, char *);\n\tint (*exit)(struct console *);\n\tint (*match)(struct console *, char *, int, char *);\n\tshort int flags;\n\tshort int index;\n\tint cflag;\n\tvoid *data;\n\tstruct console *next;\n};\n\nstruct hpet_data {\n\tlong unsigned int hd_phys_address;\n\tvoid *hd_address;\n\tshort unsigned int hd_nirqs;\n\tunsigned int hd_state;\n\tunsigned int hd_irq[32];\n};\n\ntypedef irqreturn_t (*rtc_irq_handler)(int, void *);\n\nenum hpet_mode {\n\tHPET_MODE_UNUSED = 0,\n\tHPET_MODE_LEGACY = 1,\n\tHPET_MODE_CLOCKEVT = 2,\n\tHPET_MODE_DEVICE = 3,\n};\n\nstruct hpet_channel {\n\tstruct clock_event_device evt;\n\tunsigned int num;\n\tunsigned int cpu;\n\tunsigned int irq;\n\tunsigned int in_use;\n\tenum hpet_mode mode;\n\tunsigned int boot_cfg;\n\tchar name[10];\n\tlong: 48;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct hpet_base {\n\tunsigned int nr_channels;\n\tunsigned int nr_clockevents;\n\tunsigned int boot_cfg;\n\tstruct hpet_channel *channels;\n};\n\nunion hpet_lock {\n\tstruct {\n\t\tarch_spinlock_t lock;\n\t\tu32 value;\n\t};\n\tu64 lockval;\n};\n\nstruct amd_nb_bus_dev_range {\n\tu8 bus;\n\tu8 dev_base;\n\tu8 dev_limit;\n};\n\nstruct amd_northbridge_info {\n\tu16 num;\n\tu64 flags;\n\tstruct amd_northbridge *nb;\n};\n\nstruct swait_queue {\n\tstruct task_struct *task;\n\tstruct list_head task_list;\n};\n\nstruct kvm_steal_time {\n\t__u64 steal;\n\t__u32 version;\n\t__u32 flags;\n\t__u8 preempted;\n\t__u8 u8_pad[3];\n\t__u32 pad[11];\n};\n\nstruct kvm_vcpu_pv_apf_data {\n\t__u32 flags;\n\t__u32 token;\n\t__u8 pad[56];\n\t__u32 enabled;\n};\n\nstruct kvm_task_sleep_node {\n\tstruct hlist_node link;\n\tstruct swait_queue_head wq;\n\tu32 token;\n\tint cpu;\n};\n\nstruct kvm_task_sleep_head {\n\traw_spinlock_t lock;\n\tstruct hlist_head list;\n};\n\ntypedef struct ldttss_desc ldt_desc;\n\nstruct branch {\n\tunsigned char opcode;\n\tu32 delta;\n} __attribute__((packed));\n\ntypedef long unsigned int ulong;\n\nstruct jailhouse_setup_data {\n\tstruct {\n\t\t__u16 version;\n\t\t__u16 compatible_version;\n\t} hdr;\n\tstruct {\n\t\t__u16 pm_timer_address;\n\t\t__u16 num_cpus;\n\t\t__u64 pci_mmconfig_base;\n\t\t__u32 tsc_khz;\n\t\t__u32 apic_khz;\n\t\t__u8 standard_ioapic;\n\t\t__u8 cpu_ids[255];\n\t} __attribute__((packed)) v1;\n\tstruct {\n\t\t__u32 flags;\n\t} v2;\n} __attribute__((packed));\n\nstruct circ_buf {\n\tchar *buf;\n\tint head;\n\tint tail;\n};\n\nstruct serial_rs485 {\n\t__u32 flags;\n\t__u32 delay_rts_before_send;\n\t__u32 delay_rts_after_send;\n\t__u32 padding[5];\n};\n\nstruct serial_iso7816 {\n\t__u32 flags;\n\t__u32 tg;\n\t__u32 sc_fi;\n\t__u32 sc_di;\n\t__u32 clk;\n\t__u32 reserved[5];\n};\n\nstruct uart_port;\n\nstruct uart_ops {\n\tunsigned int (*tx_empty)(struct uart_port *);\n\tvoid (*set_mctrl)(struct uart_port *, unsigned int);\n\tunsigned int (*get_mctrl)(struct uart_port *);\n\tvoid (*stop_tx)(struct uart_port *);\n\tvoid (*start_tx)(struct uart_port *);\n\tvoid (*throttle)(struct uart_port *);\n\tvoid (*unthrottle)(struct uart_port *);\n\tvoid (*send_xchar)(struct uart_port *, char);\n\tvoid (*stop_rx)(struct uart_port *);\n\tvoid (*enable_ms)(struct uart_port *);\n\tvoid (*break_ctl)(struct uart_port *, int);\n\tint (*startup)(struct uart_port *);\n\tvoid (*shutdown)(struct uart_port *);\n\tvoid (*flush_buffer)(struct uart_port *);\n\tvoid (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *);\n\tvoid (*set_ldisc)(struct uart_port *, struct ktermios *);\n\tvoid (*pm)(struct uart_port *, unsigned int, unsigned int);\n\tconst char * (*type)(struct uart_port *);\n\tvoid (*release_port)(struct uart_port *);\n\tint (*request_port)(struct uart_port *);\n\tvoid (*config_port)(struct uart_port *, int);\n\tint (*verify_port)(struct uart_port *, struct serial_struct *);\n\tint (*ioctl)(struct uart_port *, unsigned int, long unsigned int);\n};\n\nstruct uart_icount {\n\t__u32 cts;\n\t__u32 dsr;\n\t__u32 rng;\n\t__u32 dcd;\n\t__u32 rx;\n\t__u32 tx;\n\t__u32 frame;\n\t__u32 overrun;\n\t__u32 parity;\n\t__u32 brk;\n\t__u32 buf_overrun;\n};\n\ntypedef unsigned int upf_t;\n\ntypedef unsigned int upstat_t;\n\nstruct gpio_desc;\n\nstruct uart_state;\n\nstruct uart_port {\n\tspinlock_t lock;\n\tlong unsigned int iobase;\n\tunsigned char *membase;\n\tunsigned int (*serial_in)(struct uart_port *, int);\n\tvoid (*serial_out)(struct uart_port *, int, int);\n\tvoid (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *);\n\tvoid (*set_ldisc)(struct uart_port *, struct ktermios *);\n\tunsigned int (*get_mctrl)(struct uart_port *);\n\tvoid (*set_mctrl)(struct uart_port *, unsigned int);\n\tunsigned int (*get_divisor)(struct uart_port *, unsigned int, unsigned int *);\n\tvoid (*set_divisor)(struct uart_port *, unsigned int, unsigned int, unsigned int);\n\tint (*startup)(struct uart_port *);\n\tvoid (*shutdown)(struct uart_port *);\n\tvoid (*throttle)(struct uart_port *);\n\tvoid (*unthrottle)(struct uart_port *);\n\tint (*handle_irq)(struct uart_port *);\n\tvoid (*pm)(struct uart_port *, unsigned int, unsigned int);\n\tvoid (*handle_break)(struct uart_port *);\n\tint (*rs485_config)(struct uart_port *, struct serial_rs485 *);\n\tint (*iso7816_config)(struct uart_port *, struct serial_iso7816 *);\n\tunsigned int irq;\n\tlong unsigned int irqflags;\n\tunsigned int uartclk;\n\tunsigned int fifosize;\n\tunsigned char x_char;\n\tunsigned char regshift;\n\tunsigned char iotype;\n\tunsigned char quirks;\n\tunsigned int read_status_mask;\n\tunsigned int ignore_status_mask;\n\tstruct uart_state *state;\n\tstruct uart_icount icount;\n\tstruct console *cons;\n\tupf_t flags;\n\tupstat_t status;\n\tint hw_stopped;\n\tunsigned int mctrl;\n\tunsigned int timeout;\n\tunsigned int type;\n\tconst struct uart_ops *ops;\n\tunsigned int custom_divisor;\n\tunsigned int line;\n\tunsigned int minor;\n\tresource_size_t mapbase;\n\tresource_size_t mapsize;\n\tstruct device *dev;\n\tlong unsigned int sysrq;\n\tunsigned int sysrq_ch;\n\tunsigned char has_sysrq;\n\tunsigned char sysrq_seq;\n\tunsigned char hub6;\n\tunsigned char suspended;\n\tunsigned char console_reinit;\n\tconst char *name;\n\tstruct attribute_group *attr_group;\n\tconst struct attribute_group **tty_groups;\n\tstruct serial_rs485 rs485;\n\tstruct gpio_desc *rs485_term_gpio;\n\tstruct serial_iso7816 iso7816;\n\tvoid *private_data;\n};\n\nenum uart_pm_state {\n\tUART_PM_STATE_ON = 0,\n\tUART_PM_STATE_OFF = 3,\n\tUART_PM_STATE_UNDEFINED = 4,\n};\n\nstruct uart_state {\n\tstruct tty_port port;\n\tenum uart_pm_state pm_state;\n\tstruct circ_buf xmit;\n\tatomic_t refcount;\n\twait_queue_head_t remove_wait;\n\tstruct uart_port *uart_port;\n};\n\nstruct pci_mmcfg_region {\n\tstruct list_head list;\n\tstruct resource res;\n\tu64 address;\n\tchar *virt;\n\tu16 segment;\n\tu8 start_bus;\n\tu8 end_bus;\n\tchar name[30];\n};\n\nstruct scan_area {\n\tu64 addr;\n\tu64 size;\n};\n\nstruct uprobe_xol_ops;\n\nstruct arch_uprobe {\n\tunion {\n\t\tu8 insn[16];\n\t\tu8 ixol[16];\n\t};\n\tconst struct uprobe_xol_ops *ops;\n\tunion {\n\t\tstruct {\n\t\t\ts32 offs;\n\t\t\tu8 ilen;\n\t\t\tu8 opc1;\n\t\t} branch;\n\t\tstruct {\n\t\t\tu8 fixups;\n\t\t\tu8 ilen;\n\t\t} defparam;\n\t\tstruct {\n\t\t\tu8 reg_offset;\n\t\t\tu8 ilen;\n\t\t} push;\n\t};\n};\n\nstruct uprobe_xol_ops {\n\tbool (*emulate)(struct arch_uprobe *, struct pt_regs *);\n\tint (*pre_xol)(struct arch_uprobe *, struct pt_regs *);\n\tint (*post_xol)(struct arch_uprobe *, struct pt_regs *);\n\tvoid (*abort)(struct arch_uprobe *, struct pt_regs *);\n};\n\nenum rp_check {\n\tRP_CHECK_CALL = 0,\n\tRP_CHECK_CHAIN_CALL = 1,\n\tRP_CHECK_RET = 2,\n};\n\nstruct simplefb_platform_data {\n\tu32 width;\n\tu32 height;\n\tu32 stride;\n\tconst char *format;\n};\n\nenum {\n\tM_I17 = 0,\n\tM_I20 = 1,\n\tM_I20_SR = 2,\n\tM_I24 = 3,\n\tM_I24_8_1 = 4,\n\tM_I24_10_1 = 5,\n\tM_I27_11_1 = 6,\n\tM_MINI = 7,\n\tM_MINI_3_1 = 8,\n\tM_MINI_4_1 = 9,\n\tM_MB = 10,\n\tM_MB_2 = 11,\n\tM_MB_3 = 12,\n\tM_MB_5_1 = 13,\n\tM_MB_6_1 = 14,\n\tM_MB_7_1 = 15,\n\tM_MB_SR = 16,\n\tM_MBA = 17,\n\tM_MBA_3 = 18,\n\tM_MBP = 19,\n\tM_MBP_2 = 20,\n\tM_MBP_2_2 = 21,\n\tM_MBP_SR = 22,\n\tM_MBP_4 = 23,\n\tM_MBP_5_1 = 24,\n\tM_MBP_5_2 = 25,\n\tM_MBP_5_3 = 26,\n\tM_MBP_6_1 = 27,\n\tM_MBP_6_2 = 28,\n\tM_MBP_7_1 = 29,\n\tM_MBP_8_2 = 30,\n\tM_UNKNOWN = 31,\n};\n\nstruct efifb_dmi_info {\n\tchar *optname;\n\tlong unsigned int base;\n\tint stride;\n\tint width;\n\tint height;\n\tint flags;\n};\n\nenum {\n\tOVERRIDE_NONE = 0,\n\tOVERRIDE_BASE = 1,\n\tOVERRIDE_STRIDE = 2,\n\tOVERRIDE_HEIGHT = 4,\n\tOVERRIDE_WIDTH = 8,\n};\n\nenum perf_sample_regs_abi {\n\tPERF_SAMPLE_REGS_ABI_NONE = 0,\n\tPERF_SAMPLE_REGS_ABI_32 = 1,\n\tPERF_SAMPLE_REGS_ABI_64 = 2,\n};\n\nstruct va_format {\n\tconst char *fmt;\n\tva_list *va;\n};\n\nenum es_result {\n\tES_OK = 0,\n\tES_UNSUPPORTED = 1,\n\tES_VMM_ERROR = 2,\n\tES_DECODE_FAILED = 3,\n\tES_EXCEPTION = 4,\n\tES_RETRY = 5,\n};\n\nstruct es_fault_info {\n\tlong unsigned int vector;\n\tlong unsigned int error_code;\n\tlong unsigned int cr2;\n};\n\nstruct es_em_ctxt {\n\tstruct pt_regs *regs;\n\tstruct insn insn;\n\tstruct es_fault_info fi;\n};\n\nstruct sev_es_runtime_data {\n\tstruct ghcb ghcb_page;\n\tchar ist_stack[4096];\n\tchar fallback_stack[4096];\n\tstruct ghcb backup_ghcb;\n\tbool ghcb_active;\n\tbool backup_ghcb_active;\n\tlong unsigned int dr7;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct ghcb_state {\n\tstruct ghcb *ghcb;\n};\n\nstruct pci_hostbridge_probe {\n\tu32 bus;\n\tu32 slot;\n\tu32 vendor;\n\tu32 device;\n};\n\nstruct trace_print_flags {\n\tlong unsigned int mask;\n\tconst char *name;\n};\n\nenum tlb_flush_reason {\n\tTLB_FLUSH_ON_TASK_SWITCH = 0,\n\tTLB_REMOTE_SHOOTDOWN = 1,\n\tTLB_LOCAL_SHOOTDOWN = 2,\n\tTLB_LOCAL_MM_SHOOTDOWN = 3,\n\tTLB_REMOTE_SEND_IPI = 4,\n\tNR_TLB_FLUSH_REASONS = 5,\n};\n\nenum {\n\tREGION_INTERSECTS = 0,\n\tREGION_DISJOINT = 1,\n\tREGION_MIXED = 2,\n};\n\nstruct trace_event_raw_tlb_flush {\n\tstruct trace_entry ent;\n\tint reason;\n\tlong unsigned int pages;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_tlb_flush {};\n\ntypedef void (*btf_trace_tlb_flush)(void *, int, long unsigned int);\n\nstruct map_range {\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tunsigned int page_size_mask;\n};\n\nstruct mhp_params {\n\tstruct vmem_altmap *altmap;\n\tpgprot_t pgprot;\n};\n\nstruct mem_section_usage {\n\tlong unsigned int subsection_map[1];\n\tlong unsigned int pageblock_flags[0];\n};\n\nstruct mem_section {\n\tlong unsigned int section_mem_map;\n\tstruct mem_section_usage *usage;\n};\n\nenum kcore_type {\n\tKCORE_TEXT = 0,\n\tKCORE_VMALLOC = 1,\n\tKCORE_RAM = 2,\n\tKCORE_VMEMMAP = 3,\n\tKCORE_USER = 4,\n};\n\nstruct kcore_list {\n\tstruct list_head list;\n\tlong unsigned int addr;\n\tsize_t size;\n\tint type;\n};\n\nenum {\n\tMEMORY_HOTPLUG_MIN_BOOTMEM_TYPE = 12,\n\tSECTION_INFO = 12,\n\tMIX_SECTION_INFO = 13,\n\tNODE_INFO = 14,\n\tMEMORY_HOTPLUG_MAX_BOOTMEM_TYPE = 14,\n};\n\nstruct hstate {\n\tstruct mutex resize_lock;\n\tint next_nid_to_alloc;\n\tint next_nid_to_free;\n\tunsigned int order;\n\tlong unsigned int mask;\n\tlong unsigned int max_huge_pages;\n\tlong unsigned int nr_huge_pages;\n\tlong unsigned int free_huge_pages;\n\tlong unsigned int resv_huge_pages;\n\tlong unsigned int surplus_huge_pages;\n\tlong unsigned int nr_overcommit_huge_pages;\n\tstruct list_head hugepage_activelist;\n\tstruct list_head hugepage_freelists[32];\n\tunsigned int nr_huge_pages_node[32];\n\tunsigned int free_huge_pages_node[32];\n\tunsigned int surplus_huge_pages_node[32];\n\tunsigned int nr_free_vmemmap_pages;\n\tstruct cftype cgroup_files_dfl[7];\n\tstruct cftype cgroup_files_legacy[9];\n\tchar name[32];\n};\n\nstruct trace_event_raw_x86_exceptions {\n\tstruct trace_entry ent;\n\tlong unsigned int address;\n\tlong unsigned int ip;\n\tlong unsigned int error_code;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_x86_exceptions {};\n\ntypedef void (*btf_trace_page_fault_user)(void *, long unsigned int, struct pt_regs *, long unsigned int);\n\ntypedef void (*btf_trace_page_fault_kernel)(void *, long unsigned int, struct pt_regs *, long unsigned int);\n\nenum {\n\tIORES_MAP_SYSTEM_RAM = 1,\n\tIORES_MAP_ENCRYPTED = 2,\n};\n\nstruct ioremap_desc {\n\tunsigned int flags;\n};\n\ntypedef bool (*ex_handler_t)(const struct exception_table_entry *, struct pt_regs *, int, long unsigned int, long unsigned int);\n\nstruct hugepage_subpool {\n\tspinlock_t lock;\n\tlong int count;\n\tlong int max_hpages;\n\tlong int used_hpages;\n\tstruct hstate *hstate;\n\tlong int min_hpages;\n\tlong int rsv_hpages;\n};\n\nstruct hugetlbfs_sb_info {\n\tlong int max_inodes;\n\tlong int free_inodes;\n\tspinlock_t stat_lock;\n\tstruct hstate *hstate;\n\tstruct hugepage_subpool *spool;\n\tkuid_t uid;\n\tkgid_t gid;\n\tumode_t mode;\n};\n\nstruct exception_stacks {\n\tchar DF_stack_guard[0];\n\tchar DF_stack[4096];\n\tchar NMI_stack_guard[0];\n\tchar NMI_stack[4096];\n\tchar DB_stack_guard[0];\n\tchar DB_stack[4096];\n\tchar MCE_stack_guard[0];\n\tchar MCE_stack[4096];\n\tchar VC_stack_guard[0];\n\tchar VC_stack[0];\n\tchar VC2_stack_guard[0];\n\tchar VC2_stack[0];\n\tchar IST_top_guard[0];\n};\n\nstruct vm_event_state {\n\tlong unsigned int event[100];\n};\n\nstruct cpa_data {\n\tlong unsigned int *vaddr;\n\tpgd_t *pgd;\n\tpgprot_t mask_set;\n\tpgprot_t mask_clr;\n\tlong unsigned int numpages;\n\tlong unsigned int curpage;\n\tlong unsigned int pfn;\n\tunsigned int flags;\n\tunsigned int force_split: 1;\n\tunsigned int force_static_prot: 1;\n\tunsigned int force_flush_all: 1;\n\tstruct page **pages;\n};\n\nenum cpa_warn {\n\tCPA_CONFLICT = 0,\n\tCPA_PROTECT = 1,\n\tCPA_DETECT = 2,\n};\n\ntypedef struct {\n\tu64 val;\n} pfn_t;\n\nstruct memtype {\n\tu64 start;\n\tu64 end;\n\tu64 subtree_max_end;\n\tenum page_cache_mode type;\n\tstruct rb_node rb;\n};\n\nenum {\n\tPAT_UC = 0,\n\tPAT_WC = 1,\n\tPAT_WT = 4,\n\tPAT_WP = 5,\n\tPAT_WB = 6,\n\tPAT_UC_MINUS = 7,\n};\n\nstruct pagerange_state {\n\tlong unsigned int cur_pfn;\n\tint ram;\n\tint not_ram;\n};\n\nstruct rb_augment_callbacks {\n\tvoid (*propagate)(struct rb_node *, struct rb_node *);\n\tvoid (*copy)(struct rb_node *, struct rb_node *);\n\tvoid (*rotate)(struct rb_node *, struct rb_node *);\n};\n\nenum {\n\tMEMTYPE_EXACT_MATCH = 0,\n\tMEMTYPE_END_MATCH = 1,\n};\n\nstruct ptdump_range {\n\tlong unsigned int start;\n\tlong unsigned int end;\n};\n\nstruct ptdump_state {\n\tvoid (*note_page)(struct ptdump_state *, long unsigned int, int, u64);\n\tvoid (*effective_prot)(struct ptdump_state *, int, u64);\n\tconst struct ptdump_range *range;\n};\n\nstruct addr_marker;\n\nstruct pg_state {\n\tstruct ptdump_state ptdump;\n\tint level;\n\tpgprotval_t current_prot;\n\tpgprotval_t effective_prot;\n\tpgprotval_t prot_levels[5];\n\tlong unsigned int start_address;\n\tconst struct addr_marker *marker;\n\tlong unsigned int lines;\n\tbool to_dmesg;\n\tbool check_wx;\n\tlong unsigned int wx_pages;\n\tstruct seq_file *seq;\n};\n\nstruct addr_marker {\n\tlong unsigned int start_address;\n\tconst char *name;\n\tlong unsigned int max_lines;\n};\n\nenum address_markers_idx {\n\tUSER_SPACE_NR = 0,\n\tKERNEL_SPACE_NR = 1,\n\tLDT_NR = 2,\n\tLOW_KERNEL_NR = 3,\n\tVMALLOC_START_NR = 4,\n\tVMEMMAP_START_NR = 5,\n\tCPU_ENTRY_AREA_NR = 6,\n\tESPFIX_START_NR = 7,\n\tEFI_END_NR = 8,\n\tHIGH_KERNEL_NR = 9,\n\tMODULES_VADDR_NR = 10,\n\tMODULES_END_NR = 11,\n\tFIXADDR_START_NR = 12,\n\tEND_OF_SPACE_NR = 13,\n};\n\ntypedef void (*rcu_callback_t)(struct callback_head *);\n\nstruct kmmio_probe;\n\ntypedef void (*kmmio_pre_handler_t)(struct kmmio_probe *, struct pt_regs *, long unsigned int);\n\ntypedef void (*kmmio_post_handler_t)(struct kmmio_probe *, long unsigned int, struct pt_regs *);\n\nstruct kmmio_probe {\n\tstruct list_head list;\n\tlong unsigned int addr;\n\tlong unsigned int len;\n\tkmmio_pre_handler_t pre_handler;\n\tkmmio_post_handler_t post_handler;\n\tvoid *private;\n};\n\nstruct kmmio_fault_page {\n\tstruct list_head list;\n\tstruct kmmio_fault_page *release_next;\n\tlong unsigned int addr;\n\tpteval_t old_presence;\n\tbool armed;\n\tint count;\n\tbool scheduled_for_release;\n};\n\nstruct kmmio_delayed_release {\n\tstruct callback_head rcu;\n\tstruct kmmio_fault_page *release_list;\n};\n\nstruct kmmio_context {\n\tstruct kmmio_fault_page *fpage;\n\tstruct kmmio_probe *probe;\n\tlong unsigned int saved_flags;\n\tlong unsigned int addr;\n\tint active;\n};\n\nenum reason_type {\n\tNOT_ME = 0,\n\tNOTHING = 1,\n\tREG_READ = 2,\n\tREG_WRITE = 3,\n\tIMM_WRITE = 4,\n\tOTHERS = 5,\n};\n\nstruct prefix_bits {\n\tunsigned int shorted: 1;\n\tunsigned int enlarged: 1;\n\tunsigned int rexr: 1;\n\tunsigned int rex: 1;\n};\n\nenum {\n\targ_AL = 0,\n\targ_CL = 1,\n\targ_DL = 2,\n\targ_BL = 3,\n\targ_AH = 4,\n\targ_CH = 5,\n\targ_DH = 6,\n\targ_BH = 7,\n\targ_AX = 0,\n\targ_CX = 1,\n\targ_DX = 2,\n\targ_BX = 3,\n\targ_SP = 4,\n\targ_BP = 5,\n\targ_SI = 6,\n\targ_DI = 7,\n\targ_R8 = 8,\n\targ_R9 = 9,\n\targ_R10 = 10,\n\targ_R11 = 11,\n\targ_R12 = 12,\n\targ_R13 = 13,\n\targ_R14 = 14,\n\targ_R15 = 15,\n};\n\nenum mm_io_opcode {\n\tMMIO_READ = 1,\n\tMMIO_WRITE = 2,\n\tMMIO_PROBE = 3,\n\tMMIO_UNPROBE = 4,\n\tMMIO_UNKNOWN_OP = 5,\n};\n\nstruct mmiotrace_rw {\n\tresource_size_t phys;\n\tlong unsigned int value;\n\tlong unsigned int pc;\n\tint map_id;\n\tunsigned char opcode;\n\tunsigned char width;\n};\n\nstruct mmiotrace_map {\n\tresource_size_t phys;\n\tlong unsigned int virt;\n\tlong unsigned int len;\n\tint map_id;\n\tunsigned char opcode;\n};\n\nstruct trap_reason {\n\tlong unsigned int addr;\n\tlong unsigned int ip;\n\tenum reason_type type;\n\tint active_traces;\n};\n\nstruct remap_trace {\n\tstruct list_head list;\n\tstruct kmmio_probe probe;\n\tresource_size_t phys;\n\tlong unsigned int id;\n};\n\nstruct numa_memblk {\n\tu64 start;\n\tu64 end;\n\tint nid;\n};\n\nstruct numa_meminfo {\n\tint nr_blks;\n\tstruct numa_memblk blk[64];\n};\n\nstruct acpi_srat_cpu_affinity {\n\tstruct acpi_subtable_header header;\n\tu8 proximity_domain_lo;\n\tu8 apic_id;\n\tu32 flags;\n\tu8 local_sapic_eid;\n\tu8 proximity_domain_hi[3];\n\tu32 clock_domain;\n};\n\nstruct acpi_srat_x2apic_cpu_affinity {\n\tstruct acpi_subtable_header header;\n\tu16 reserved;\n\tu32 proximity_domain;\n\tu32 apic_id;\n\tu32 flags;\n\tu32 clock_domain;\n\tu32 reserved2;\n};\n\nenum uv_system_type {\n\tUV_NONE = 0,\n\tUV_LEGACY_APIC = 1,\n\tUV_X2APIC = 2,\n};\n\nstruct rnd_state {\n\t__u32 s1;\n\t__u32 s2;\n\t__u32 s3;\n\t__u32 s4;\n};\n\nstruct kaslr_memory_region {\n\tlong unsigned int *base;\n\tlong unsigned int size_tb;\n};\n\nenum pti_mode {\n\tPTI_AUTO = 0,\n\tPTI_FORCE_OFF = 1,\n\tPTI_FORCE_ON = 2,\n};\n\nenum pti_clone_level {\n\tPTI_CLONE_PMD = 0,\n\tPTI_CLONE_PTE = 1,\n};\n\nstruct sme_populate_pgd_data {\n\tvoid *pgtable_area;\n\tpgd_t *pgd;\n\tpmdval_t pmd_flags;\n\tpteval_t pte_flags;\n\tlong unsigned int paddr;\n\tlong unsigned int vaddr;\n\tlong unsigned int vaddr_end;\n};\n\nstruct sigcontext_32 {\n\t__u16 gs;\n\t__u16 __gsh;\n\t__u16 fs;\n\t__u16 __fsh;\n\t__u16 es;\n\t__u16 __esh;\n\t__u16 ds;\n\t__u16 __dsh;\n\t__u32 di;\n\t__u32 si;\n\t__u32 bp;\n\t__u32 sp;\n\t__u32 bx;\n\t__u32 dx;\n\t__u32 cx;\n\t__u32 ax;\n\t__u32 trapno;\n\t__u32 err;\n\t__u32 ip;\n\t__u16 cs;\n\t__u16 __csh;\n\t__u32 flags;\n\t__u32 sp_at_signal;\n\t__u16 ss;\n\t__u16 __ssh;\n\t__u32 fpstate;\n\t__u32 oldmask;\n\t__u32 cr2;\n};\n\ntypedef u32 compat_size_t;\n\nstruct compat_sigaltstack {\n\tcompat_uptr_t ss_sp;\n\tint ss_flags;\n\tcompat_size_t ss_size;\n};\n\ntypedef struct compat_sigaltstack compat_stack_t;\n\nstruct ucontext_ia32 {\n\tunsigned int uc_flags;\n\tunsigned int uc_link;\n\tcompat_stack_t uc_stack;\n\tstruct sigcontext_32 uc_mcontext;\n\tcompat_sigset_t uc_sigmask;\n};\n\nstruct sigframe_ia32 {\n\tu32 pretcode;\n\tint sig;\n\tstruct sigcontext_32 sc;\n\tstruct _fpstate_32 fpstate_unused;\n\tunsigned int extramask[1];\n\tchar retcode[8];\n};\n\nstruct rt_sigframe_ia32 {\n\tu32 pretcode;\n\tint sig;\n\tu32 pinfo;\n\tu32 puc;\n\tcompat_siginfo_t info;\n\tstruct ucontext_ia32 uc;\n\tchar retcode[8];\n};\n\ntypedef struct {\n\tefi_guid_t guid;\n\tu64 table;\n} efi_config_table_64_t;\n\nstruct efi_memory_map_data {\n\tphys_addr_t phys_map;\n\tlong unsigned int size;\n\tlong unsigned int desc_version;\n\tlong unsigned int desc_size;\n\tlong unsigned int flags;\n};\n\nstruct efi_mem_range {\n\tstruct range range;\n\tu64 attribute;\n};\n\nenum efi_rts_ids {\n\tEFI_NONE = 0,\n\tEFI_GET_TIME = 1,\n\tEFI_SET_TIME = 2,\n\tEFI_GET_WAKEUP_TIME = 3,\n\tEFI_SET_WAKEUP_TIME = 4,\n\tEFI_GET_VARIABLE = 5,\n\tEFI_GET_NEXT_VARIABLE = 6,\n\tEFI_SET_VARIABLE = 7,\n\tEFI_QUERY_VARIABLE_INFO = 8,\n\tEFI_GET_NEXT_HIGH_MONO_COUNT = 9,\n\tEFI_RESET_SYSTEM = 10,\n\tEFI_UPDATE_CAPSULE = 11,\n\tEFI_QUERY_CAPSULE_CAPS = 12,\n};\n\nstruct efi_runtime_work {\n\tvoid *arg1;\n\tvoid *arg2;\n\tvoid *arg3;\n\tvoid *arg4;\n\tvoid *arg5;\n\tefi_status_t status;\n\tstruct work_struct work;\n\tenum efi_rts_ids efi_rts_id;\n\tstruct completion efi_rts_comp;\n};\n\ntypedef struct {\n\tefi_guid_t guid;\n\tu32 table;\n} efi_config_table_32_t;\n\ntypedef union {\n\tstruct {\n\t\tefi_guid_t guid;\n\t\tvoid *table;\n\t};\n\tefi_config_table_32_t mixed_mode;\n} efi_config_table_t;\n\ntypedef struct {\n\tefi_guid_t guid;\n\tlong unsigned int *ptr;\n\tconst char name[16];\n} efi_config_table_type_t;\n\ntypedef struct {\n\tefi_table_hdr_t hdr;\n\tu64 fw_vendor;\n\tu32 fw_revision;\n\tu32 __pad1;\n\tu64 con_in_handle;\n\tu64 con_in;\n\tu64 con_out_handle;\n\tu64 con_out;\n\tu64 stderr_handle;\n\tu64 stderr;\n\tu64 runtime;\n\tu64 boottime;\n\tu32 nr_tables;\n\tu32 __pad2;\n\tu64 tables;\n} efi_system_table_64_t;\n\ntypedef struct {\n\tu32 version;\n\tu32 length;\n\tu64 memory_protection_attribute;\n} efi_properties_table_t;\n\ntypedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *);\n\ntypedef u16 ucs2_char_t;\n\nstruct pm_qos_request {\n\tstruct plist_node node;\n\tstruct pm_qos_constraints *qos;\n};\n\nenum {\n\tBPF_REG_0 = 0,\n\tBPF_REG_1 = 1,\n\tBPF_REG_2 = 2,\n\tBPF_REG_3 = 3,\n\tBPF_REG_4 = 4,\n\tBPF_REG_5 = 5,\n\tBPF_REG_6 = 6,\n\tBPF_REG_7 = 7,\n\tBPF_REG_8 = 8,\n\tBPF_REG_9 = 9,\n\tBPF_REG_10 = 10,\n\t__MAX_BPF_REG = 11,\n};\n\nstruct bpf_tramp_progs {\n\tstruct bpf_prog *progs[38];\n\tint nr_progs;\n};\n\nenum bpf_jit_poke_reason {\n\tBPF_POKE_REASON_TAIL_CALL = 0,\n};\n\nstruct bpf_array_aux {\n\tenum bpf_prog_type type;\n\tbool jited;\n\tstruct list_head poke_progs;\n\tstruct bpf_map *map;\n\tstruct mutex poke_mutex;\n\tstruct work_struct work;\n};\n\nstruct bpf_array {\n\tstruct bpf_map map;\n\tu32 elem_size;\n\tu32 index_mask;\n\tstruct bpf_array_aux *aux;\n\tunion {\n\t\tchar value[0];\n\t\tvoid *ptrs[0];\n\t\tvoid *pptrs[0];\n\t};\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum bpf_text_poke_type {\n\tBPF_MOD_CALL = 0,\n\tBPF_MOD_JUMP = 1,\n};\n\nstruct bpf_binary_header {\n\tu32 pages;\n\tint: 32;\n\tu8 image[0];\n};\n\ntypedef void (*bpf_jit_fill_hole_t)(void *, unsigned int);\n\nstruct jit_context {\n\tint cleanup_addr;\n};\n\nstruct x64_jit_data {\n\tstruct bpf_binary_header *header;\n\tint *addrs;\n\tu8 *image;\n\tint proglen;\n\tstruct jit_context ctx;\n};\n\nenum tk_offsets {\n\tTK_OFFS_REAL = 0,\n\tTK_OFFS_BOOT = 1,\n\tTK_OFFS_TAI = 2,\n\tTK_OFFS_MAX = 3,\n};\n\ntypedef long unsigned int vm_flags_t;\n\nstruct clone_args {\n\t__u64 flags;\n\t__u64 pidfd;\n\t__u64 child_tid;\n\t__u64 parent_tid;\n\t__u64 exit_signal;\n\t__u64 stack;\n\t__u64 stack_size;\n\t__u64 tls;\n\t__u64 set_tid;\n\t__u64 set_tid_size;\n\t__u64 cgroup;\n};\n\nenum hrtimer_mode {\n\tHRTIMER_MODE_ABS = 0,\n\tHRTIMER_MODE_REL = 1,\n\tHRTIMER_MODE_PINNED = 2,\n\tHRTIMER_MODE_SOFT = 4,\n\tHRTIMER_MODE_HARD = 8,\n\tHRTIMER_MODE_ABS_PINNED = 2,\n\tHRTIMER_MODE_REL_PINNED = 3,\n\tHRTIMER_MODE_ABS_SOFT = 4,\n\tHRTIMER_MODE_REL_SOFT = 5,\n\tHRTIMER_MODE_ABS_PINNED_SOFT = 6,\n\tHRTIMER_MODE_REL_PINNED_SOFT = 7,\n\tHRTIMER_MODE_ABS_HARD = 8,\n\tHRTIMER_MODE_REL_HARD = 9,\n\tHRTIMER_MODE_ABS_PINNED_HARD = 10,\n\tHRTIMER_MODE_REL_PINNED_HARD = 11,\n};\n\nstruct fdtable {\n\tunsigned int max_fds;\n\tstruct file **fd;\n\tlong unsigned int *close_on_exec;\n\tlong unsigned int *open_fds;\n\tlong unsigned int *full_fds_bits;\n\tstruct callback_head rcu;\n};\n\nstruct files_struct {\n\tatomic_t count;\n\tbool resize_in_progress;\n\twait_queue_head_t resize_wait;\n\tstruct fdtable *fdt;\n\tstruct fdtable fdtab;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tspinlock_t file_lock;\n\tunsigned int next_fd;\n\tlong unsigned int close_on_exec_init[1];\n\tlong unsigned int open_fds_init[1];\n\tlong unsigned int full_fds_bits_init[1];\n\tstruct file *fd_array[64];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct robust_list {\n\tstruct robust_list *next;\n};\n\nstruct robust_list_head {\n\tstruct robust_list list;\n\tlong int futex_offset;\n\tstruct robust_list *list_op_pending;\n};\n\nstruct multiprocess_signals {\n\tsigset_t signal;\n\tstruct hlist_node node;\n};\n\ntypedef int (*proc_visitor)(struct task_struct *, void *);\n\nenum {\n\tIOPRIO_CLASS_NONE = 0,\n\tIOPRIO_CLASS_RT = 1,\n\tIOPRIO_CLASS_BE = 2,\n\tIOPRIO_CLASS_IDLE = 3,\n};\n\ntypedef struct poll_table_struct poll_table;\n\nenum {\n\tFUTEX_STATE_OK = 0,\n\tFUTEX_STATE_EXITING = 1,\n\tFUTEX_STATE_DEAD = 2,\n};\n\nenum proc_hidepid {\n\tHIDEPID_OFF = 0,\n\tHIDEPID_NO_ACCESS = 1,\n\tHIDEPID_INVISIBLE = 2,\n\tHIDEPID_NOT_PTRACEABLE = 4,\n};\n\nenum proc_pidonly {\n\tPROC_PIDONLY_OFF = 0,\n\tPROC_PIDONLY_ON = 1,\n};\n\nstruct proc_fs_info {\n\tstruct pid_namespace *pid_ns;\n\tstruct dentry *proc_self;\n\tstruct dentry *proc_thread_self;\n\tkgid_t pid_gid;\n\tenum proc_hidepid hide_pid;\n\tenum proc_pidonly pidonly;\n};\n\nstruct trace_event_raw_task_newtask {\n\tstruct trace_entry ent;\n\tpid_t pid;\n\tchar comm[16];\n\tlong unsigned int clone_flags;\n\tshort int oom_score_adj;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_task_rename {\n\tstruct trace_entry ent;\n\tpid_t pid;\n\tchar oldcomm[16];\n\tchar newcomm[16];\n\tshort int oom_score_adj;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_task_newtask {};\n\nstruct trace_event_data_offsets_task_rename {};\n\ntypedef void (*btf_trace_task_newtask)(void *, struct task_struct *, long unsigned int);\n\ntypedef void (*btf_trace_task_rename)(void *, struct task_struct *, const char *);\n\nstruct taint_flag {\n\tchar c_true;\n\tchar c_false;\n\tbool module;\n};\n\nenum ftrace_dump_mode {\n\tDUMP_NONE = 0,\n\tDUMP_ALL = 1,\n\tDUMP_ORIG = 2,\n};\n\nenum kmsg_dump_reason {\n\tKMSG_DUMP_UNDEF = 0,\n\tKMSG_DUMP_PANIC = 1,\n\tKMSG_DUMP_OOPS = 2,\n\tKMSG_DUMP_EMERG = 3,\n\tKMSG_DUMP_SHUTDOWN = 4,\n\tKMSG_DUMP_MAX = 5,\n};\n\nenum con_flush_mode {\n\tCONSOLE_FLUSH_PENDING = 0,\n\tCONSOLE_REPLAY_ALL = 1,\n};\n\nstruct warn_args {\n\tconst char *fmt;\n\tva_list args;\n};\n\nstruct smp_hotplug_thread {\n\tstruct task_struct **store;\n\tstruct list_head list;\n\tint (*thread_should_run)(unsigned int);\n\tvoid (*thread_fn)(unsigned int);\n\tvoid (*create)(unsigned int);\n\tvoid (*setup)(unsigned int);\n\tvoid (*cleanup)(unsigned int, bool);\n\tvoid (*park)(unsigned int);\n\tvoid (*unpark)(unsigned int);\n\tbool selfparking;\n\tconst char *thread_comm;\n};\n\nstruct trace_event_raw_cpuhp_enter {\n\tstruct trace_entry ent;\n\tunsigned int cpu;\n\tint target;\n\tint idx;\n\tvoid *fun;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cpuhp_multi_enter {\n\tstruct trace_entry ent;\n\tunsigned int cpu;\n\tint target;\n\tint idx;\n\tvoid *fun;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cpuhp_exit {\n\tstruct trace_entry ent;\n\tunsigned int cpu;\n\tint state;\n\tint idx;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_cpuhp_enter {};\n\nstruct trace_event_data_offsets_cpuhp_multi_enter {};\n\nstruct trace_event_data_offsets_cpuhp_exit {};\n\ntypedef void (*btf_trace_cpuhp_enter)(void *, unsigned int, int, int, int (*)(unsigned int));\n\ntypedef void (*btf_trace_cpuhp_multi_enter)(void *, unsigned int, int, int, int (*)(unsigned int, struct hlist_node *), struct hlist_node *);\n\ntypedef void (*btf_trace_cpuhp_exit)(void *, unsigned int, int, int, int);\n\nstruct cpuhp_cpu_state {\n\tenum cpuhp_state state;\n\tenum cpuhp_state target;\n\tenum cpuhp_state fail;\n\tstruct task_struct *thread;\n\tbool should_run;\n\tbool rollback;\n\tbool single;\n\tbool bringup;\n\tint cpu;\n\tstruct hlist_node *node;\n\tstruct hlist_node *last;\n\tenum cpuhp_state cb_state;\n\tint result;\n\tstruct completion done_up;\n\tstruct completion done_down;\n};\n\nstruct cpuhp_step {\n\tconst char *name;\n\tunion {\n\t\tint (*single)(unsigned int);\n\t\tint (*multi)(unsigned int, struct hlist_node *);\n\t} startup;\n\tunion {\n\t\tint (*single)(unsigned int);\n\t\tint (*multi)(unsigned int, struct hlist_node *);\n\t} teardown;\n\tstruct hlist_head list;\n\tbool cant_stop;\n\tbool multi_instance;\n};\n\nenum cpu_mitigations {\n\tCPU_MITIGATIONS_OFF = 0,\n\tCPU_MITIGATIONS_AUTO = 1,\n\tCPU_MITIGATIONS_AUTO_NOSMT = 2,\n};\n\nstruct __kernel_old_timeval {\n\t__kernel_long_t tv_sec;\n\t__kernel_long_t tv_usec;\n};\n\nstruct old_timeval32 {\n\told_time32_t tv_sec;\n\ts32 tv_usec;\n};\n\nstruct rusage {\n\tstruct __kernel_old_timeval ru_utime;\n\tstruct __kernel_old_timeval ru_stime;\n\t__kernel_long_t ru_maxrss;\n\t__kernel_long_t ru_ixrss;\n\t__kernel_long_t ru_idrss;\n\t__kernel_long_t ru_isrss;\n\t__kernel_long_t ru_minflt;\n\t__kernel_long_t ru_majflt;\n\t__kernel_long_t ru_nswap;\n\t__kernel_long_t ru_inblock;\n\t__kernel_long_t ru_oublock;\n\t__kernel_long_t ru_msgsnd;\n\t__kernel_long_t ru_msgrcv;\n\t__kernel_long_t ru_nsignals;\n\t__kernel_long_t ru_nvcsw;\n\t__kernel_long_t ru_nivcsw;\n};\n\ntypedef struct {} mm_segment_t;\n\nstruct compat_rusage {\n\tstruct old_timeval32 ru_utime;\n\tstruct old_timeval32 ru_stime;\n\tcompat_long_t ru_maxrss;\n\tcompat_long_t ru_ixrss;\n\tcompat_long_t ru_idrss;\n\tcompat_long_t ru_isrss;\n\tcompat_long_t ru_minflt;\n\tcompat_long_t ru_majflt;\n\tcompat_long_t ru_nswap;\n\tcompat_long_t ru_inblock;\n\tcompat_long_t ru_oublock;\n\tcompat_long_t ru_msgsnd;\n\tcompat_long_t ru_msgrcv;\n\tcompat_long_t ru_nsignals;\n\tcompat_long_t ru_nvcsw;\n\tcompat_long_t ru_nivcsw;\n};\n\nstruct waitid_info {\n\tpid_t pid;\n\tuid_t uid;\n\tint status;\n\tint cause;\n};\n\nstruct wait_opts {\n\tenum pid_type wo_type;\n\tint wo_flags;\n\tstruct pid *wo_pid;\n\tstruct waitid_info *wo_info;\n\tint wo_stat;\n\tstruct rusage *wo_rusage;\n\twait_queue_entry_t child_wait;\n\tint notask_error;\n};\n\nstruct softirq_action {\n\tvoid (*action)(struct softirq_action *);\n};\n\nstruct tasklet_struct {\n\tstruct tasklet_struct *next;\n\tlong unsigned int state;\n\tatomic_t count;\n\tbool use_callback;\n\tunion {\n\t\tvoid (*func)(long unsigned int);\n\t\tvoid (*callback)(struct tasklet_struct *);\n\t};\n\tlong unsigned int data;\n};\n\nenum {\n\tTASKLET_STATE_SCHED = 0,\n\tTASKLET_STATE_RUN = 1,\n};\n\nstruct kernel_stat {\n\tlong unsigned int irqs_sum;\n\tunsigned int softirqs[10];\n};\n\nstruct wait_bit_key {\n\tvoid *flags;\n\tint bit_nr;\n\tlong unsigned int timeout;\n};\n\nstruct wait_bit_queue_entry {\n\tstruct wait_bit_key key;\n\tstruct wait_queue_entry wq_entry;\n};\n\nstruct trace_event_raw_irq_handler_entry {\n\tstruct trace_entry ent;\n\tint irq;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_irq_handler_exit {\n\tstruct trace_entry ent;\n\tint irq;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_softirq {\n\tstruct trace_entry ent;\n\tunsigned int vec;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_irq_handler_entry {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_irq_handler_exit {};\n\nstruct trace_event_data_offsets_softirq {};\n\ntypedef void (*btf_trace_irq_handler_entry)(void *, int, struct irqaction *);\n\ntypedef void (*btf_trace_irq_handler_exit)(void *, int, struct irqaction *, int);\n\ntypedef void (*btf_trace_softirq_entry)(void *, unsigned int);\n\ntypedef void (*btf_trace_softirq_exit)(void *, unsigned int);\n\ntypedef void (*btf_trace_softirq_raise)(void *, unsigned int);\n\nstruct tasklet_head {\n\tstruct tasklet_struct *head;\n\tstruct tasklet_struct **tail;\n};\n\nstruct pseudo_fs_context {\n\tconst struct super_operations *ops;\n\tconst struct xattr_handler **xattr;\n\tconst struct dentry_operations *dops;\n\tlong unsigned int magic;\n};\n\ntypedef void (*dr_release_t)(struct device *, void *);\n\ntypedef int (*dr_match_t)(struct device *, void *, void *);\n\nstruct resource_entry {\n\tstruct list_head node;\n\tstruct resource *res;\n\tresource_size_t offset;\n\tstruct resource __res;\n};\n\nstruct resource_constraint {\n\tresource_size_t min;\n\tresource_size_t max;\n\tresource_size_t align;\n\tresource_size_t (*alignf)(void *, const struct resource *, resource_size_t, resource_size_t);\n\tvoid *alignf_data;\n};\n\nenum {\n\tMAX_IORES_LEVEL = 5,\n};\n\nstruct region_devres {\n\tstruct resource *parent;\n\tresource_size_t start;\n\tresource_size_t n;\n};\n\ntypedef __kernel_clock_t clock_t;\n\nstruct dentry_stat_t {\n\tlong int nr_dentry;\n\tlong int nr_unused;\n\tlong int age_limit;\n\tlong int want_pages;\n\tlong int nr_negative;\n\tlong int dummy;\n};\n\nstruct files_stat_struct {\n\tlong unsigned int nr_files;\n\tlong unsigned int nr_free_files;\n\tlong unsigned int max_files;\n};\n\nstruct inodes_stat_t {\n\tlong int nr_inodes;\n\tlong int nr_unused;\n\tlong int dummy[5];\n};\n\nenum sysctl_writes_mode {\n\tSYSCTL_WRITES_LEGACY = 4294967295,\n\tSYSCTL_WRITES_WARN = 0,\n\tSYSCTL_WRITES_STRICT = 1,\n};\n\nstruct do_proc_dointvec_minmax_conv_param {\n\tint *min;\n\tint *max;\n};\n\nstruct do_proc_douintvec_minmax_conv_param {\n\tunsigned int *min;\n\tunsigned int *max;\n};\n\nstruct __user_cap_header_struct {\n\t__u32 version;\n\tint pid;\n};\n\ntypedef struct __user_cap_header_struct *cap_user_header_t;\n\nstruct __user_cap_data_struct {\n\t__u32 effective;\n\t__u32 permitted;\n\t__u32 inheritable;\n};\n\ntypedef struct __user_cap_data_struct *cap_user_data_t;\n\nstruct sigqueue {\n\tstruct list_head list;\n\tint flags;\n\tkernel_siginfo_t info;\n\tstruct ucounts *ucounts;\n};\n\ntypedef int wait_bit_action_f(struct wait_bit_key *, int);\n\nstruct ptrace_peeksiginfo_args {\n\t__u64 off;\n\t__u32 flags;\n\t__s32 nr;\n};\n\nstruct ptrace_syscall_info {\n\t__u8 op;\n\t__u8 pad[3];\n\t__u32 arch;\n\t__u64 instruction_pointer;\n\t__u64 stack_pointer;\n\tunion {\n\t\tstruct {\n\t\t\t__u64 nr;\n\t\t\t__u64 args[6];\n\t\t} entry;\n\t\tstruct {\n\t\t\t__s64 rval;\n\t\t\t__u8 is_error;\n\t\t} exit;\n\t\tstruct {\n\t\t\t__u64 nr;\n\t\t\t__u64 args[6];\n\t\t\t__u32 ret_data;\n\t\t} seccomp;\n\t};\n};\n\nstruct ptrace_rseq_configuration {\n\t__u64 rseq_abi_pointer;\n\t__u32 rseq_abi_size;\n\t__u32 signature;\n\t__u32 flags;\n\t__u32 pad;\n};\n\nstruct compat_iovec {\n\tcompat_uptr_t iov_base;\n\tcompat_size_t iov_len;\n};\n\ntypedef long unsigned int old_sigset_t;\n\nenum siginfo_layout {\n\tSIL_KILL = 0,\n\tSIL_TIMER = 1,\n\tSIL_POLL = 2,\n\tSIL_FAULT = 3,\n\tSIL_FAULT_TRAPNO = 4,\n\tSIL_FAULT_MCEERR = 5,\n\tSIL_FAULT_BNDERR = 6,\n\tSIL_FAULT_PKUERR = 7,\n\tSIL_PERF_EVENT = 8,\n\tSIL_CHLD = 9,\n\tSIL_RT = 10,\n\tSIL_SYS = 11,\n};\n\nstruct fd {\n\tstruct file *file;\n\tunsigned int flags;\n};\n\ntypedef u32 compat_old_sigset_t;\n\nstruct compat_sigaction {\n\tcompat_uptr_t sa_handler;\n\tcompat_ulong_t sa_flags;\n\tcompat_uptr_t sa_restorer;\n\tcompat_sigset_t sa_mask;\n};\n\nstruct compat_old_sigaction {\n\tcompat_uptr_t sa_handler;\n\tcompat_old_sigset_t sa_mask;\n\tcompat_ulong_t sa_flags;\n\tcompat_uptr_t sa_restorer;\n};\n\nenum {\n\tTRACE_SIGNAL_DELIVERED = 0,\n\tTRACE_SIGNAL_IGNORED = 1,\n\tTRACE_SIGNAL_ALREADY_PENDING = 2,\n\tTRACE_SIGNAL_OVERFLOW_FAIL = 3,\n\tTRACE_SIGNAL_LOSE_INFO = 4,\n};\n\nstruct trace_event_raw_signal_generate {\n\tstruct trace_entry ent;\n\tint sig;\n\tint errno;\n\tint code;\n\tchar comm[16];\n\tpid_t pid;\n\tint group;\n\tint result;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_signal_deliver {\n\tstruct trace_entry ent;\n\tint sig;\n\tint errno;\n\tint code;\n\tlong unsigned int sa_handler;\n\tlong unsigned int sa_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_signal_generate {};\n\nstruct trace_event_data_offsets_signal_deliver {};\n\ntypedef void (*btf_trace_signal_generate)(void *, int, struct kernel_siginfo *, struct task_struct *, int, int);\n\ntypedef void (*btf_trace_signal_deliver)(void *, int, struct kernel_siginfo *, struct k_sigaction *);\n\nstruct sysinfo {\n\t__kernel_long_t uptime;\n\t__kernel_ulong_t loads[3];\n\t__kernel_ulong_t totalram;\n\t__kernel_ulong_t freeram;\n\t__kernel_ulong_t sharedram;\n\t__kernel_ulong_t bufferram;\n\t__kernel_ulong_t totalswap;\n\t__kernel_ulong_t freeswap;\n\t__u16 procs;\n\t__u16 pad;\n\t__kernel_ulong_t totalhigh;\n\t__kernel_ulong_t freehigh;\n\t__u32 mem_unit;\n\tchar _f[0];\n};\n\nenum {\n\tPER_LINUX = 0,\n\tPER_LINUX_32BIT = 8388608,\n\tPER_LINUX_FDPIC = 524288,\n\tPER_SVR4 = 68157441,\n\tPER_SVR3 = 83886082,\n\tPER_SCOSVR3 = 117440515,\n\tPER_OSR5 = 100663299,\n\tPER_WYSEV386 = 83886084,\n\tPER_ISCR4 = 67108869,\n\tPER_BSD = 6,\n\tPER_SUNOS = 67108870,\n\tPER_XENIX = 83886087,\n\tPER_LINUX32 = 8,\n\tPER_LINUX32_3GB = 134217736,\n\tPER_IRIX32 = 67108873,\n\tPER_IRIXN32 = 67108874,\n\tPER_IRIX64 = 67108875,\n\tPER_RISCOS = 12,\n\tPER_SOLARIS = 67108877,\n\tPER_UW7 = 68157454,\n\tPER_OSF4 = 15,\n\tPER_HPUX = 16,\n\tPER_MASK = 255,\n};\n\nstruct rlimit64 {\n\t__u64 rlim_cur;\n\t__u64 rlim_max;\n};\n\nstruct oldold_utsname {\n\tchar sysname[9];\n\tchar nodename[9];\n\tchar release[9];\n\tchar version[9];\n\tchar machine[9];\n};\n\nstruct old_utsname {\n\tchar sysname[65];\n\tchar nodename[65];\n\tchar release[65];\n\tchar version[65];\n\tchar machine[65];\n};\n\nenum uts_proc {\n\tUTS_PROC_OSTYPE = 0,\n\tUTS_PROC_OSRELEASE = 1,\n\tUTS_PROC_VERSION = 2,\n\tUTS_PROC_HOSTNAME = 3,\n\tUTS_PROC_DOMAINNAME = 4,\n};\n\nstruct prctl_mm_map {\n\t__u64 start_code;\n\t__u64 end_code;\n\t__u64 start_data;\n\t__u64 end_data;\n\t__u64 start_brk;\n\t__u64 brk;\n\t__u64 start_stack;\n\t__u64 arg_start;\n\t__u64 arg_end;\n\t__u64 env_start;\n\t__u64 env_end;\n\t__u64 *auxv;\n\t__u32 auxv_size;\n\t__u32 exe_fd;\n};\n\nstruct compat_tms {\n\tcompat_clock_t tms_utime;\n\tcompat_clock_t tms_stime;\n\tcompat_clock_t tms_cutime;\n\tcompat_clock_t tms_cstime;\n};\n\nstruct compat_rlimit {\n\tcompat_ulong_t rlim_cur;\n\tcompat_ulong_t rlim_max;\n};\n\nstruct tms {\n\t__kernel_clock_t tms_utime;\n\t__kernel_clock_t tms_stime;\n\t__kernel_clock_t tms_cutime;\n\t__kernel_clock_t tms_cstime;\n};\n\nstruct getcpu_cache {\n\tlong unsigned int blob[16];\n};\n\nstruct compat_sysinfo {\n\ts32 uptime;\n\tu32 loads[3];\n\tu32 totalram;\n\tu32 freeram;\n\tu32 sharedram;\n\tu32 bufferram;\n\tu32 totalswap;\n\tu32 freeswap;\n\tu16 procs;\n\tu16 pad;\n\tu32 totalhigh;\n\tu32 freehigh;\n\tu32 mem_unit;\n\tchar _f[8];\n};\n\nstruct wq_flusher;\n\nstruct worker;\n\nstruct workqueue_attrs;\n\nstruct pool_workqueue;\n\nstruct wq_device;\n\nstruct workqueue_struct {\n\tstruct list_head pwqs;\n\tstruct list_head list;\n\tstruct mutex mutex;\n\tint work_color;\n\tint flush_color;\n\tatomic_t nr_pwqs_to_flush;\n\tstruct wq_flusher *first_flusher;\n\tstruct list_head flusher_queue;\n\tstruct list_head flusher_overflow;\n\tstruct list_head maydays;\n\tstruct worker *rescuer;\n\tint nr_drainers;\n\tint saved_max_active;\n\tstruct workqueue_attrs *unbound_attrs;\n\tstruct pool_workqueue *dfl_pwq;\n\tstruct wq_device *wq_dev;\n\tchar name[24];\n\tstruct callback_head rcu;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tunsigned int flags;\n\tstruct pool_workqueue *cpu_pwqs;\n\tstruct pool_workqueue *numa_pwq_tbl[0];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct workqueue_attrs {\n\tint nice;\n\tcpumask_var_t cpumask;\n\tbool no_numa;\n};\n\nstruct execute_work {\n\tstruct work_struct work;\n};\n\nenum {\n\tWQ_UNBOUND = 2,\n\tWQ_FREEZABLE = 4,\n\tWQ_MEM_RECLAIM = 8,\n\tWQ_HIGHPRI = 16,\n\tWQ_CPU_INTENSIVE = 32,\n\tWQ_SYSFS = 64,\n\tWQ_POWER_EFFICIENT = 128,\n\t__WQ_DRAINING = 65536,\n\t__WQ_ORDERED = 131072,\n\t__WQ_LEGACY = 262144,\n\t__WQ_ORDERED_EXPLICIT = 524288,\n\tWQ_MAX_ACTIVE = 512,\n\tWQ_MAX_UNBOUND_PER_CPU = 4,\n\tWQ_DFL_ACTIVE = 256,\n};\n\nenum xa_lock_type {\n\tXA_LOCK_IRQ = 1,\n\tXA_LOCK_BH = 2,\n};\n\nstruct ida {\n\tstruct xarray xa;\n};\n\nstruct __una_u32 {\n\tu32 x;\n};\n\nstruct worker_pool;\n\nstruct worker {\n\tunion {\n\t\tstruct list_head entry;\n\t\tstruct hlist_node hentry;\n\t};\n\tstruct work_struct *current_work;\n\twork_func_t current_func;\n\tstruct pool_workqueue *current_pwq;\n\tstruct list_head scheduled;\n\tstruct task_struct *task;\n\tstruct worker_pool *pool;\n\tstruct list_head node;\n\tlong unsigned int last_active;\n\tunsigned int flags;\n\tint id;\n\tint sleeping;\n\tchar desc[24];\n\tstruct workqueue_struct *rescue_wq;\n\twork_func_t last_func;\n};\n\nstruct pool_workqueue {\n\tstruct worker_pool *pool;\n\tstruct workqueue_struct *wq;\n\tint work_color;\n\tint flush_color;\n\tint refcnt;\n\tint nr_in_flight[15];\n\tint nr_active;\n\tint max_active;\n\tstruct list_head delayed_works;\n\tstruct list_head pwqs_node;\n\tstruct list_head mayday_node;\n\tstruct work_struct unbound_release_work;\n\tstruct callback_head rcu;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct worker_pool {\n\traw_spinlock_t lock;\n\tint cpu;\n\tint node;\n\tint id;\n\tunsigned int flags;\n\tlong unsigned int watchdog_ts;\n\tstruct list_head worklist;\n\tint nr_workers;\n\tint nr_idle;\n\tstruct list_head idle_list;\n\tstruct timer_list idle_timer;\n\tstruct timer_list mayday_timer;\n\tstruct hlist_head busy_hash[64];\n\tstruct worker *manager;\n\tstruct list_head workers;\n\tstruct completion *detach_completion;\n\tstruct ida worker_ida;\n\tstruct workqueue_attrs *attrs;\n\tstruct hlist_node hash_node;\n\tint refcnt;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tatomic_t nr_running;\n\tstruct callback_head rcu;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum {\n\tPOOL_MANAGER_ACTIVE = 1,\n\tPOOL_DISASSOCIATED = 4,\n\tWORKER_DIE = 2,\n\tWORKER_IDLE = 4,\n\tWORKER_PREP = 8,\n\tWORKER_CPU_INTENSIVE = 64,\n\tWORKER_UNBOUND = 128,\n\tWORKER_REBOUND = 256,\n\tWORKER_NOT_RUNNING = 456,\n\tNR_STD_WORKER_POOLS = 2,\n\tUNBOUND_POOL_HASH_ORDER = 6,\n\tBUSY_WORKER_HASH_ORDER = 6,\n\tMAX_IDLE_WORKERS_RATIO = 4,\n\tIDLE_WORKER_TIMEOUT = 90000,\n\tMAYDAY_INITIAL_TIMEOUT = 3,\n\tMAYDAY_INTERVAL = 30,\n\tCREATE_COOLDOWN = 300,\n\tRESCUER_NICE_LEVEL = 4294967276,\n\tHIGHPRI_NICE_LEVEL = 4294967276,\n\tWQ_NAME_LEN = 24,\n};\n\nstruct wq_flusher {\n\tstruct list_head list;\n\tint flush_color;\n\tstruct completion done;\n};\n\nstruct wq_device {\n\tstruct workqueue_struct *wq;\n\tstruct device dev;\n};\n\nstruct trace_event_raw_workqueue_queue_work {\n\tstruct trace_entry ent;\n\tvoid *work;\n\tvoid *function;\n\tu32 __data_loc_workqueue;\n\tunsigned int req_cpu;\n\tunsigned int cpu;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_workqueue_activate_work {\n\tstruct trace_entry ent;\n\tvoid *work;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_workqueue_execute_start {\n\tstruct trace_entry ent;\n\tvoid *work;\n\tvoid *function;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_workqueue_execute_end {\n\tstruct trace_entry ent;\n\tvoid *work;\n\tvoid *function;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_workqueue_queue_work {\n\tu32 workqueue;\n};\n\nstruct trace_event_data_offsets_workqueue_activate_work {};\n\nstruct trace_event_data_offsets_workqueue_execute_start {};\n\nstruct trace_event_data_offsets_workqueue_execute_end {};\n\ntypedef void (*btf_trace_workqueue_queue_work)(void *, unsigned int, struct pool_workqueue *, struct work_struct *);\n\ntypedef void (*btf_trace_workqueue_activate_work)(void *, struct work_struct *);\n\ntypedef void (*btf_trace_workqueue_execute_start)(void *, struct work_struct *);\n\ntypedef void (*btf_trace_workqueue_execute_end)(void *, struct work_struct *, work_func_t);\n\nstruct wq_barrier {\n\tstruct work_struct work;\n\tstruct completion done;\n\tstruct task_struct *task;\n};\n\nstruct cwt_wait {\n\twait_queue_entry_t wait;\n\tstruct work_struct *work;\n};\n\nstruct apply_wqattrs_ctx {\n\tstruct workqueue_struct *wq;\n\tstruct workqueue_attrs *attrs;\n\tstruct list_head list;\n\tstruct pool_workqueue *dfl_pwq;\n\tstruct pool_workqueue *pwq_tbl[0];\n};\n\nstruct work_for_cpu {\n\tstruct work_struct work;\n\tlong int (*fn)(void *);\n\tvoid *arg;\n\tlong int ret;\n};\n\ntypedef struct {} local_lock_t;\n\nstruct radix_tree_preload {\n\tlocal_lock_t lock;\n\tunsigned int nr;\n\tstruct xa_node *nodes;\n};\n\ntypedef void (*task_work_func_t)(struct callback_head *);\n\nenum {\n\tKERNEL_PARAM_OPS_FL_NOARG = 1,\n};\n\nenum {\n\tKERNEL_PARAM_FL_UNSAFE = 1,\n\tKERNEL_PARAM_FL_HWPARAM = 2,\n};\n\nstruct param_attribute {\n\tstruct module_attribute mattr;\n\tconst struct kernel_param *param;\n};\n\nstruct module_param_attrs {\n\tunsigned int num;\n\tstruct attribute_group grp;\n\tstruct param_attribute attrs[0];\n};\n\nstruct module_version_attribute {\n\tstruct module_attribute mattr;\n\tconst char *module_name;\n\tconst char *version;\n};\n\nstruct kmalloced_param {\n\tstruct list_head list;\n\tchar val[0];\n};\n\nstruct sched_param {\n\tint sched_priority;\n};\n\nenum {\n\t__PERCPU_REF_ATOMIC = 1,\n\t__PERCPU_REF_DEAD = 2,\n\t__PERCPU_REF_ATOMIC_DEAD = 3,\n\t__PERCPU_REF_FLAG_BITS = 2,\n};\n\nstruct kthread_work;\n\ntypedef void (*kthread_work_func_t)(struct kthread_work *);\n\nstruct kthread_worker;\n\nstruct kthread_work {\n\tstruct list_head node;\n\tkthread_work_func_t func;\n\tstruct kthread_worker *worker;\n\tint canceling;\n};\n\nenum {\n\tKTW_FREEZABLE = 1,\n};\n\nstruct kthread_worker {\n\tunsigned int flags;\n\traw_spinlock_t lock;\n\tstruct list_head work_list;\n\tstruct list_head delayed_work_list;\n\tstruct task_struct *task;\n\tstruct kthread_work *current_work;\n};\n\nstruct kthread_delayed_work {\n\tstruct kthread_work work;\n\tstruct timer_list timer;\n};\n\nenum {\n\tCSS_NO_REF = 1,\n\tCSS_ONLINE = 2,\n\tCSS_RELEASED = 4,\n\tCSS_VISIBLE = 8,\n\tCSS_DYING = 16,\n};\n\nstruct kthread_create_info {\n\tint (*threadfn)(void *);\n\tvoid *data;\n\tint node;\n\tstruct task_struct *result;\n\tstruct completion *done;\n\tstruct list_head list;\n};\n\nstruct kthread {\n\tlong unsigned int flags;\n\tunsigned int cpu;\n\tint (*threadfn)(void *);\n\tvoid *data;\n\tmm_segment_t oldfs;\n\tstruct completion parked;\n\tstruct completion exited;\n\tstruct cgroup_subsys_state *blkcg_css;\n};\n\nenum KTHREAD_BITS {\n\tKTHREAD_IS_PER_CPU = 0,\n\tKTHREAD_SHOULD_STOP = 1,\n\tKTHREAD_SHOULD_PARK = 2,\n};\n\nstruct kthread_flush_work {\n\tstruct kthread_work work;\n\tstruct completion done;\n};\n\nstruct pt_regs___2;\n\nstruct ipc_ids {\n\tint in_use;\n\tshort unsigned int seq;\n\tstruct rw_semaphore rwsem;\n\tstruct idr ipcs_idr;\n\tint max_idx;\n\tint last_idx;\n\tint next_id;\n\tstruct rhashtable key_ht;\n};\n\nstruct ipc_namespace {\n\tstruct ipc_ids ids[3];\n\tint sem_ctls[4];\n\tint used_sems;\n\tunsigned int msg_ctlmax;\n\tunsigned int msg_ctlmnb;\n\tunsigned int msg_ctlmni;\n\tatomic_t msg_bytes;\n\tatomic_t msg_hdrs;\n\tsize_t shm_ctlmax;\n\tsize_t shm_ctlall;\n\tlong unsigned int shm_tot;\n\tint shm_ctlmni;\n\tint shm_rmid_forced;\n\tstruct notifier_block ipcns_nb;\n\tstruct vfsmount *mq_mnt;\n\tunsigned int mq_queues_count;\n\tunsigned int mq_queues_max;\n\tunsigned int mq_msg_max;\n\tunsigned int mq_msgsize_max;\n\tunsigned int mq_msg_default;\n\tunsigned int mq_msgsize_default;\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tstruct llist_node mnt_llist;\n\tstruct ns_common ns;\n};\n\nstruct srcu_notifier_head {\n\tstruct mutex mutex;\n\tstruct srcu_struct srcu;\n\tstruct notifier_block *head;\n};\n\nenum what {\n\tPROC_EVENT_NONE = 0,\n\tPROC_EVENT_FORK = 1,\n\tPROC_EVENT_EXEC = 2,\n\tPROC_EVENT_UID = 4,\n\tPROC_EVENT_GID = 64,\n\tPROC_EVENT_SID = 128,\n\tPROC_EVENT_PTRACE = 256,\n\tPROC_EVENT_COMM = 512,\n\tPROC_EVENT_COREDUMP = 1073741824,\n\tPROC_EVENT_EXIT = 2147483648,\n};\n\nstruct async_entry {\n\tstruct list_head domain_list;\n\tstruct list_head global_list;\n\tstruct work_struct work;\n\tasync_cookie_t cookie;\n\tasync_func_t func;\n\tvoid *data;\n\tstruct async_domain *domain;\n};\n\nstruct smpboot_thread_data {\n\tunsigned int cpu;\n\tunsigned int status;\n\tstruct smp_hotplug_thread *ht;\n};\n\nenum {\n\tHP_THREAD_NONE = 0,\n\tHP_THREAD_ACTIVE = 1,\n\tHP_THREAD_PARKED = 2,\n};\n\nstruct umd_info {\n\tconst char *driver_name;\n\tstruct file *pipe_to_umh;\n\tstruct file *pipe_from_umh;\n\tstruct path wd;\n\tstruct pid *tgid;\n};\n\nstruct pin_cookie {};\n\nstruct preempt_notifier;\n\nstruct preempt_ops {\n\tvoid (*sched_in)(struct preempt_notifier *, int);\n\tvoid (*sched_out)(struct preempt_notifier *, struct task_struct *);\n};\n\nstruct preempt_notifier {\n\tstruct hlist_node link;\n\tstruct preempt_ops *ops;\n};\n\nenum {\n\tCSD_FLAG_LOCK = 1,\n\tIRQ_WORK_PENDING = 1,\n\tIRQ_WORK_BUSY = 2,\n\tIRQ_WORK_LAZY = 4,\n\tIRQ_WORK_HARD_IRQ = 8,\n\tIRQ_WORK_CLAIMED = 3,\n\tCSD_TYPE_ASYNC = 0,\n\tCSD_TYPE_SYNC = 16,\n\tCSD_TYPE_IRQ_WORK = 32,\n\tCSD_TYPE_TTWU = 48,\n\tCSD_FLAG_TYPE_MASK = 240,\n};\n\nstruct dl_bw {\n\traw_spinlock_t lock;\n\tu64 bw;\n\tu64 total_bw;\n};\n\nstruct cpudl_item;\n\nstruct cpudl {\n\traw_spinlock_t lock;\n\tint size;\n\tcpumask_var_t free_cpus;\n\tstruct cpudl_item *elements;\n};\n\nstruct cpupri_vec {\n\tatomic_t count;\n\tcpumask_var_t mask;\n};\n\nstruct cpupri {\n\tstruct cpupri_vec pri_to_cpu[101];\n\tint *cpu_to_pri;\n};\n\nstruct perf_domain;\n\nstruct root_domain {\n\tatomic_t refcount;\n\tatomic_t rto_count;\n\tstruct callback_head rcu;\n\tcpumask_var_t span;\n\tcpumask_var_t online;\n\tint overload;\n\tint overutilized;\n\tcpumask_var_t dlo_mask;\n\tatomic_t dlo_count;\n\tstruct dl_bw dl_bw;\n\tstruct cpudl cpudl;\n\tu64 visit_gen;\n\tstruct irq_work rto_push_work;\n\traw_spinlock_t rto_lock;\n\tint rto_loop;\n\tint rto_cpu;\n\tatomic_t rto_loop_next;\n\tatomic_t rto_loop_start;\n\tcpumask_var_t rto_mask;\n\tstruct cpupri cpupri;\n\tlong unsigned int max_cpu_capacity;\n\tstruct perf_domain *pd;\n};\n\nstruct cfs_rq {\n\tstruct load_weight load;\n\tunsigned int nr_running;\n\tunsigned int h_nr_running;\n\tunsigned int idle_h_nr_running;\n\tu64 exec_clock;\n\tu64 min_vruntime;\n\tunsigned int forceidle_seq;\n\tu64 min_vruntime_fi;\n\tstruct rb_root_cached tasks_timeline;\n\tstruct sched_entity *curr;\n\tstruct sched_entity *next;\n\tstruct sched_entity *last;\n\tstruct sched_entity *skip;\n\tunsigned int nr_spread_over;\n\tlong: 32;\n\tlong: 64;\n\tstruct sched_avg avg;\n\tstruct {\n\t\traw_spinlock_t lock;\n\t\tint nr;\n\t\tlong unsigned int load_avg;\n\t\tlong unsigned int util_avg;\n\t\tlong unsigned int runnable_avg;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t} removed;\n\tlong unsigned int tg_load_avg_contrib;\n\tlong int propagate;\n\tlong int prop_runnable_sum;\n\tlong unsigned int h_load;\n\tu64 last_h_load_update;\n\tstruct sched_entity *h_load_next;\n\tstruct rq *rq;\n\tint on_list;\n\tstruct list_head leaf_cfs_rq_list;\n\tstruct task_group *tg;\n\tint runtime_enabled;\n\ts64 runtime_remaining;\n\tu64 throttled_clock;\n\tu64 throttled_clock_task;\n\tu64 throttled_clock_task_time;\n\tint throttled;\n\tint throttle_count;\n\tstruct list_head throttled_list;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct cfs_bandwidth {\n\traw_spinlock_t lock;\n\tktime_t period;\n\tu64 quota;\n\tu64 runtime;\n\tu64 burst;\n\ts64 hierarchical_quota;\n\tu8 idle;\n\tu8 period_active;\n\tu8 slack_started;\n\tstruct hrtimer period_timer;\n\tstruct hrtimer slack_timer;\n\tstruct list_head throttled_cfs_rq;\n\tint nr_periods;\n\tint nr_throttled;\n\tu64 throttled_time;\n};\n\nstruct task_group {\n\tstruct cgroup_subsys_state css;\n\tstruct sched_entity **se;\n\tstruct cfs_rq **cfs_rq;\n\tlong unsigned int shares;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tatomic_long_t load_avg;\n\tstruct callback_head rcu;\n\tstruct list_head list;\n\tstruct task_group *parent;\n\tstruct list_head siblings;\n\tstruct list_head children;\n\tstruct autogroup *autogroup;\n\tstruct cfs_bandwidth cfs_bandwidth;\n\tunsigned int uclamp_pct[2];\n\tstruct uclamp_se uclamp_req[2];\n\tstruct uclamp_se uclamp[2];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct sched_domain_attr {\n\tint relax_domain_level;\n};\n\nstruct sched_group {\n\tstruct sched_group *next;\n\tatomic_t ref;\n\tunsigned int group_weight;\n\tstruct sched_group_capacity *sgc;\n\tint asym_prefer_cpu;\n\tlong unsigned int cpumask[0];\n};\n\nstruct sched_group_capacity {\n\tatomic_t ref;\n\tlong unsigned int capacity;\n\tlong unsigned int min_capacity;\n\tlong unsigned int max_capacity;\n\tlong unsigned int next_update;\n\tint imbalance;\n\tint id;\n\tlong unsigned int cpumask[0];\n};\n\nstruct autogroup {\n\tstruct kref kref;\n\tstruct task_group *tg;\n\tstruct rw_semaphore lock;\n\tlong unsigned int id;\n\tint nice;\n};\n\nenum ctx_state {\n\tCONTEXT_DISABLED = 4294967295,\n\tCONTEXT_KERNEL = 0,\n\tCONTEXT_USER = 1,\n\tCONTEXT_GUEST = 2,\n};\n\nstruct kernel_cpustat {\n\tu64 cpustat[10];\n};\n\nenum {\n\tMEMBARRIER_STATE_PRIVATE_EXPEDITED_READY = 1,\n\tMEMBARRIER_STATE_PRIVATE_EXPEDITED = 2,\n\tMEMBARRIER_STATE_GLOBAL_EXPEDITED_READY = 4,\n\tMEMBARRIER_STATE_GLOBAL_EXPEDITED = 8,\n\tMEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY = 16,\n\tMEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE = 32,\n\tMEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ_READY = 64,\n\tMEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ = 128,\n};\n\nenum {\n\tCFTYPE_ONLY_ON_ROOT = 1,\n\tCFTYPE_NOT_ON_ROOT = 2,\n\tCFTYPE_NS_DELEGATABLE = 4,\n\tCFTYPE_NO_PREFIX = 8,\n\tCFTYPE_WORLD_WRITABLE = 16,\n\tCFTYPE_DEBUG = 32,\n\tCFTYPE_PRESSURE = 64,\n\t__CFTYPE_ONLY_ON_DFL = 65536,\n\t__CFTYPE_NOT_ON_DFL = 131072,\n};\n\nstruct css_task_iter {\n\tstruct cgroup_subsys *ss;\n\tunsigned int flags;\n\tstruct list_head *cset_pos;\n\tstruct list_head *cset_head;\n\tstruct list_head *tcset_pos;\n\tstruct list_head *tcset_head;\n\tstruct list_head *task_pos;\n\tstruct list_head *cur_tasks_head;\n\tstruct css_set *cur_cset;\n\tstruct css_set *cur_dcset;\n\tstruct task_struct *cur_task;\n\tstruct list_head iters_node;\n};\n\nstruct trace_event_raw_sched_kthread_stop {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_kthread_stop_ret {\n\tstruct trace_entry ent;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_kthread_work_queue_work {\n\tstruct trace_entry ent;\n\tvoid *work;\n\tvoid *function;\n\tvoid *worker;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_kthread_work_execute_start {\n\tstruct trace_entry ent;\n\tvoid *work;\n\tvoid *function;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_kthread_work_execute_end {\n\tstruct trace_entry ent;\n\tvoid *work;\n\tvoid *function;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_wakeup_template {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tint prio;\n\tint target_cpu;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_switch {\n\tstruct trace_entry ent;\n\tchar prev_comm[16];\n\tpid_t prev_pid;\n\tint prev_prio;\n\tlong int prev_state;\n\tchar next_comm[16];\n\tpid_t next_pid;\n\tint next_prio;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_migrate_task {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tint prio;\n\tint orig_cpu;\n\tint dest_cpu;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_process_template {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tint prio;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_process_wait {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tint prio;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_process_fork {\n\tstruct trace_entry ent;\n\tchar parent_comm[16];\n\tpid_t parent_pid;\n\tchar child_comm[16];\n\tpid_t child_pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_process_exec {\n\tstruct trace_entry ent;\n\tu32 __data_loc_filename;\n\tpid_t pid;\n\tpid_t old_pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_stat_template {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tu64 delay;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_stat_runtime {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tu64 runtime;\n\tu64 vruntime;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_pi_setprio {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tint oldprio;\n\tint newprio;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_process_hang {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tpid_t pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_move_numa {\n\tstruct trace_entry ent;\n\tpid_t pid;\n\tpid_t tgid;\n\tpid_t ngid;\n\tint src_cpu;\n\tint src_nid;\n\tint dst_cpu;\n\tint dst_nid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_numa_pair_template {\n\tstruct trace_entry ent;\n\tpid_t src_pid;\n\tpid_t src_tgid;\n\tpid_t src_ngid;\n\tint src_cpu;\n\tint src_nid;\n\tpid_t dst_pid;\n\tpid_t dst_tgid;\n\tpid_t dst_ngid;\n\tint dst_cpu;\n\tint dst_nid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sched_wake_idle_without_ipi {\n\tstruct trace_entry ent;\n\tint cpu;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_sched_kthread_stop {};\n\nstruct trace_event_data_offsets_sched_kthread_stop_ret {};\n\nstruct trace_event_data_offsets_sched_kthread_work_queue_work {};\n\nstruct trace_event_data_offsets_sched_kthread_work_execute_start {};\n\nstruct trace_event_data_offsets_sched_kthread_work_execute_end {};\n\nstruct trace_event_data_offsets_sched_wakeup_template {};\n\nstruct trace_event_data_offsets_sched_switch {};\n\nstruct trace_event_data_offsets_sched_migrate_task {};\n\nstruct trace_event_data_offsets_sched_process_template {};\n\nstruct trace_event_data_offsets_sched_process_wait {};\n\nstruct trace_event_data_offsets_sched_process_fork {};\n\nstruct trace_event_data_offsets_sched_process_exec {\n\tu32 filename;\n};\n\nstruct trace_event_data_offsets_sched_stat_template {};\n\nstruct trace_event_data_offsets_sched_stat_runtime {};\n\nstruct trace_event_data_offsets_sched_pi_setprio {};\n\nstruct trace_event_data_offsets_sched_process_hang {};\n\nstruct trace_event_data_offsets_sched_move_numa {};\n\nstruct trace_event_data_offsets_sched_numa_pair_template {};\n\nstruct trace_event_data_offsets_sched_wake_idle_without_ipi {};\n\ntypedef void (*btf_trace_sched_kthread_stop)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_kthread_stop_ret)(void *, int);\n\ntypedef void (*btf_trace_sched_kthread_work_queue_work)(void *, struct kthread_worker *, struct kthread_work *);\n\ntypedef void (*btf_trace_sched_kthread_work_execute_start)(void *, struct kthread_work *);\n\ntypedef void (*btf_trace_sched_kthread_work_execute_end)(void *, struct kthread_work *, kthread_work_func_t);\n\ntypedef void (*btf_trace_sched_waking)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_wakeup)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_wakeup_new)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_switch)(void *, bool, struct task_struct *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_migrate_task)(void *, struct task_struct *, int);\n\ntypedef void (*btf_trace_sched_process_free)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_process_exit)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_wait_task)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_process_wait)(void *, struct pid *);\n\ntypedef void (*btf_trace_sched_process_fork)(void *, struct task_struct *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_process_exec)(void *, struct task_struct *, pid_t, struct linux_binprm *);\n\ntypedef void (*btf_trace_sched_stat_wait)(void *, struct task_struct *, u64);\n\ntypedef void (*btf_trace_sched_stat_sleep)(void *, struct task_struct *, u64);\n\ntypedef void (*btf_trace_sched_stat_iowait)(void *, struct task_struct *, u64);\n\ntypedef void (*btf_trace_sched_stat_blocked)(void *, struct task_struct *, u64);\n\ntypedef void (*btf_trace_sched_stat_runtime)(void *, struct task_struct *, u64, u64);\n\ntypedef void (*btf_trace_sched_pi_setprio)(void *, struct task_struct *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_process_hang)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_sched_move_numa)(void *, struct task_struct *, int, int);\n\ntypedef void (*btf_trace_sched_stick_numa)(void *, struct task_struct *, int, struct task_struct *, int);\n\ntypedef void (*btf_trace_sched_swap_numa)(void *, struct task_struct *, int, struct task_struct *, int);\n\ntypedef void (*btf_trace_sched_wake_idle_without_ipi)(void *, int);\n\ntypedef void (*btf_trace_pelt_cfs_tp)(void *, struct cfs_rq *);\n\ntypedef void (*btf_trace_pelt_rt_tp)(void *, struct rq *);\n\nstruct uclamp_bucket {\n\tlong unsigned int value: 11;\n\tlong unsigned int tasks: 53;\n};\n\nstruct uclamp_rq {\n\tunsigned int value;\n\tstruct uclamp_bucket bucket[5];\n};\n\nstruct rt_prio_array {\n\tlong unsigned int bitmap[2];\n\tstruct list_head queue[100];\n};\n\nstruct rt_rq {\n\tstruct rt_prio_array active;\n\tunsigned int rt_nr_running;\n\tunsigned int rr_nr_running;\n\tstruct {\n\t\tint curr;\n\t\tint next;\n\t} highest_prio;\n\tunsigned int rt_nr_migratory;\n\tunsigned int rt_nr_total;\n\tint overloaded;\n\tstruct plist_head pushable_tasks;\n\tint rt_queued;\n\tint rt_throttled;\n\tu64 rt_time;\n\tu64 rt_runtime;\n\traw_spinlock_t rt_runtime_lock;\n};\n\nstruct dl_rq {\n\tstruct rb_root_cached root;\n\tunsigned int dl_nr_running;\n\tstruct {\n\t\tu64 curr;\n\t\tu64 next;\n\t} earliest_dl;\n\tunsigned int dl_nr_migratory;\n\tint overloaded;\n\tstruct rb_root_cached pushable_dl_tasks_root;\n\tu64 running_bw;\n\tu64 this_bw;\n\tu64 extra_bw;\n\tu64 bw_ratio;\n};\n\nstruct cpu_stop_done;\n\nstruct cpu_stop_work {\n\tstruct list_head list;\n\tcpu_stop_fn_t fn;\n\tlong unsigned int caller;\n\tvoid *arg;\n\tstruct cpu_stop_done *done;\n};\n\nstruct cpuidle_state;\n\nstruct rq {\n\traw_spinlock_t __lock;\n\tunsigned int nr_running;\n\tunsigned int nr_numa_running;\n\tunsigned int nr_preferred_running;\n\tunsigned int numa_migrate_on;\n\tlong unsigned int last_blocked_load_update_tick;\n\tunsigned int has_blocked_load;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tcall_single_data_t nohz_csd;\n\tunsigned int nohz_tick_stopped;\n\tatomic_t nohz_flags;\n\tunsigned int ttwu_pending;\n\tu64 nr_switches;\n\tlong: 64;\n\tstruct uclamp_rq uclamp[2];\n\tunsigned int uclamp_flags;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct cfs_rq cfs;\n\tstruct rt_rq rt;\n\tstruct dl_rq dl;\n\tstruct list_head leaf_cfs_rq_list;\n\tstruct list_head *tmp_alone_branch;\n\tunsigned int nr_uninterruptible;\n\tstruct task_struct *curr;\n\tstruct task_struct *idle;\n\tstruct task_struct *stop;\n\tlong unsigned int next_balance;\n\tstruct mm_struct *prev_mm;\n\tunsigned int clock_update_flags;\n\tu64 clock;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu64 clock_task;\n\tu64 clock_pelt;\n\tlong unsigned int lost_idle_time;\n\tatomic_t nr_iowait;\n\tu64 last_seen_need_resched_ns;\n\tint ticks_without_resched;\n\tint membarrier_state;\n\tstruct root_domain *rd;\n\tstruct sched_domain *sd;\n\tlong unsigned int cpu_capacity;\n\tlong unsigned int cpu_capacity_orig;\n\tstruct callback_head *balance_callback;\n\tunsigned char nohz_idle_balance;\n\tunsigned char idle_balance;\n\tlong unsigned int misfit_task_load;\n\tint active_balance;\n\tint push_cpu;\n\tstruct cpu_stop_work active_balance_work;\n\tint cpu;\n\tint online;\n\tstruct list_head cfs_tasks;\n\tlong: 64;\n\tstruct sched_avg avg_rt;\n\tstruct sched_avg avg_dl;\n\tstruct sched_avg avg_irq;\n\tu64 idle_stamp;\n\tu64 avg_idle;\n\tlong unsigned int wake_stamp;\n\tu64 wake_avg_idle;\n\tu64 max_idle_balance_cost;\n\tstruct rcuwait hotplug_wait;\n\tu64 prev_irq_time;\n\tu64 prev_steal_time;\n\tu64 prev_steal_time_rq;\n\tlong unsigned int calc_load_update;\n\tlong int calc_load_active;\n\tlong: 64;\n\tcall_single_data_t hrtick_csd;\n\tstruct hrtimer hrtick_timer;\n\tktime_t hrtick_time;\n\tstruct sched_info rq_sched_info;\n\tlong long unsigned int rq_cpu_time;\n\tunsigned int yld_count;\n\tunsigned int sched_count;\n\tunsigned int sched_goidle;\n\tunsigned int ttwu_count;\n\tunsigned int ttwu_local;\n\tstruct cpuidle_state *idle_state;\n\tunsigned int nr_pinned;\n\tunsigned int push_busy;\n\tstruct cpu_stop_work push_work;\n\tstruct rq *core;\n\tstruct task_struct *core_pick;\n\tunsigned int core_enabled;\n\tunsigned int core_sched_seq;\n\tstruct rb_root core_tree;\n\tunsigned int core_task_seq;\n\tunsigned int core_pick_seq;\n\tlong unsigned int core_cookie;\n\tunsigned char core_forceidle;\n\tunsigned int core_forceidle_seq;\n};\n\ntypedef void (*btf_trace_pelt_dl_tp)(void *, struct rq *);\n\ntypedef void (*btf_trace_pelt_thermal_tp)(void *, struct rq *);\n\ntypedef void (*btf_trace_pelt_irq_tp)(void *, struct rq *);\n\ntypedef void (*btf_trace_pelt_se_tp)(void *, struct sched_entity *);\n\ntypedef void (*btf_trace_sched_cpu_capacity_tp)(void *, struct rq *);\n\ntypedef void (*btf_trace_sched_overutilized_tp)(void *, struct root_domain *, bool);\n\ntypedef void (*btf_trace_sched_util_est_cfs_tp)(void *, struct cfs_rq *);\n\ntypedef void (*btf_trace_sched_util_est_se_tp)(void *, struct sched_entity *);\n\ntypedef void (*btf_trace_sched_update_nr_running_tp)(void *, struct rq *, int);\n\nstruct wake_q_head {\n\tstruct wake_q_node *first;\n\tstruct wake_q_node **lastp;\n};\n\nstruct sched_attr {\n\t__u32 size;\n\t__u32 sched_policy;\n\t__u64 sched_flags;\n\t__s32 sched_nice;\n\t__u32 sched_priority;\n\t__u64 sched_runtime;\n\t__u64 sched_deadline;\n\t__u64 sched_period;\n\t__u32 sched_util_min;\n\t__u32 sched_util_max;\n};\n\nstruct cpuidle_state_usage {\n\tlong long unsigned int disable;\n\tlong long unsigned int usage;\n\tu64 time_ns;\n\tlong long unsigned int above;\n\tlong long unsigned int below;\n\tlong long unsigned int rejected;\n\tlong long unsigned int s2idle_usage;\n\tlong long unsigned int s2idle_time;\n};\n\nstruct cpuidle_device;\n\nstruct cpuidle_driver;\n\nstruct cpuidle_state {\n\tchar name[16];\n\tchar desc[32];\n\ts64 exit_latency_ns;\n\ts64 target_residency_ns;\n\tunsigned int flags;\n\tunsigned int exit_latency;\n\tint power_usage;\n\tunsigned int target_residency;\n\tint (*enter)(struct cpuidle_device *, struct cpuidle_driver *, int);\n\tint (*enter_dead)(struct cpuidle_device *, int);\n\tint (*enter_s2idle)(struct cpuidle_device *, struct cpuidle_driver *, int);\n};\n\nstruct cpuidle_driver_kobj;\n\nstruct cpuidle_state_kobj;\n\nstruct cpuidle_device_kobj;\n\nstruct cpuidle_device {\n\tunsigned int registered: 1;\n\tunsigned int enabled: 1;\n\tunsigned int poll_time_limit: 1;\n\tunsigned int cpu;\n\tktime_t next_hrtimer;\n\tint last_state_idx;\n\tu64 last_residency_ns;\n\tu64 poll_limit_ns;\n\tu64 forced_idle_latency_limit_ns;\n\tstruct cpuidle_state_usage states_usage[10];\n\tstruct cpuidle_state_kobj *kobjs[10];\n\tstruct cpuidle_driver_kobj *kobj_driver;\n\tstruct cpuidle_device_kobj *kobj_dev;\n\tstruct list_head device_list;\n};\n\nstruct cpuidle_driver {\n\tconst char *name;\n\tstruct module *owner;\n\tunsigned int bctimer: 1;\n\tstruct cpuidle_state states[10];\n\tint state_count;\n\tint safe_state_index;\n\tstruct cpumask *cpumask;\n\tconst char *governor;\n};\n\nstruct cpudl_item {\n\tu64 dl;\n\tint cpu;\n\tint idx;\n};\n\nstruct rt_bandwidth {\n\traw_spinlock_t rt_runtime_lock;\n\tktime_t rt_period;\n\tu64 rt_runtime;\n\tstruct hrtimer rt_period_timer;\n\tunsigned int rt_period_active;\n};\n\nstruct dl_bandwidth {\n\traw_spinlock_t dl_runtime_lock;\n\tu64 dl_runtime;\n\tu64 dl_period;\n};\n\ntypedef int (*tg_visitor)(struct task_group *, void *);\n\nstruct perf_domain {\n\tstruct em_perf_domain *em_pd;\n\tstruct perf_domain *next;\n\tstruct callback_head rcu;\n};\n\nstruct rq_flags {\n\tlong unsigned int flags;\n\tstruct pin_cookie cookie;\n\tunsigned int clock_update_flags;\n};\n\nenum {\n\t__SCHED_FEAT_GENTLE_FAIR_SLEEPERS = 0,\n\t__SCHED_FEAT_START_DEBIT = 1,\n\t__SCHED_FEAT_NEXT_BUDDY = 2,\n\t__SCHED_FEAT_LAST_BUDDY = 3,\n\t__SCHED_FEAT_CACHE_HOT_BUDDY = 4,\n\t__SCHED_FEAT_WAKEUP_PREEMPTION = 5,\n\t__SCHED_FEAT_HRTICK = 6,\n\t__SCHED_FEAT_HRTICK_DL = 7,\n\t__SCHED_FEAT_DOUBLE_TICK = 8,\n\t__SCHED_FEAT_NONTASK_CAPACITY = 9,\n\t__SCHED_FEAT_TTWU_QUEUE = 10,\n\t__SCHED_FEAT_SIS_PROP = 11,\n\t__SCHED_FEAT_WARN_DOUBLE_CLOCK = 12,\n\t__SCHED_FEAT_RT_PUSH_IPI = 13,\n\t__SCHED_FEAT_RT_RUNTIME_SHARE = 14,\n\t__SCHED_FEAT_LB_MIN = 15,\n\t__SCHED_FEAT_ATTACH_AGE_LOAD = 16,\n\t__SCHED_FEAT_WA_IDLE = 17,\n\t__SCHED_FEAT_WA_WEIGHT = 18,\n\t__SCHED_FEAT_WA_BIAS = 19,\n\t__SCHED_FEAT_UTIL_EST = 20,\n\t__SCHED_FEAT_UTIL_EST_FASTUP = 21,\n\t__SCHED_FEAT_LATENCY_WARN = 22,\n\t__SCHED_FEAT_ALT_PERIOD = 23,\n\t__SCHED_FEAT_BASE_SLICE = 24,\n\t__SCHED_FEAT_NR = 25,\n};\n\nstruct irqtime {\n\tu64 total;\n\tu64 tick_delta;\n\tu64 irq_start_time;\n\tstruct u64_stats_sync sync;\n};\n\nenum cpu_util_type {\n\tFREQUENCY_UTIL = 0,\n\tENERGY_UTIL = 1,\n};\n\nstruct set_affinity_pending;\n\nstruct migration_arg {\n\tstruct task_struct *task;\n\tint dest_cpu;\n\tstruct set_affinity_pending *pending;\n};\n\nstruct set_affinity_pending {\n\trefcount_t refs;\n\tunsigned int stop_pending;\n\tstruct completion done;\n\tstruct cpu_stop_work stop_work;\n\tstruct migration_arg arg;\n};\n\nstruct migration_swap_arg {\n\tstruct task_struct *src_task;\n\tstruct task_struct *dst_task;\n\tint src_cpu;\n\tint dst_cpu;\n};\n\nenum {\n\tpreempt_dynamic_none = 0,\n\tpreempt_dynamic_voluntary = 1,\n\tpreempt_dynamic_full = 2,\n};\n\nstruct uclamp_request {\n\ts64 percent;\n\tu64 util;\n\tint ret;\n};\n\nstruct cfs_schedulable_data {\n\tstruct task_group *tg;\n\tu64 period;\n\tu64 quota;\n};\n\nenum {\n\tcpuset = 0,\n\tpossible = 1,\n\tfail = 2,\n};\n\nenum tick_dep_bits {\n\tTICK_DEP_BIT_POSIX_TIMER = 0,\n\tTICK_DEP_BIT_PERF_EVENTS = 1,\n\tTICK_DEP_BIT_SCHED = 2,\n\tTICK_DEP_BIT_CLOCK_UNSTABLE = 3,\n\tTICK_DEP_BIT_RCU = 4,\n\tTICK_DEP_BIT_RCU_EXP = 5,\n};\n\nstruct sched_clock_data {\n\tu64 tick_raw;\n\tu64 tick_gtod;\n\tu64 clock;\n};\n\nenum s2idle_states {\n\tS2IDLE_STATE_NONE = 0,\n\tS2IDLE_STATE_ENTER = 1,\n\tS2IDLE_STATE_WAKE = 2,\n};\n\nstruct idle_timer {\n\tstruct hrtimer timer;\n\tint done;\n};\n\nstruct numa_group {\n\trefcount_t refcount;\n\tspinlock_t lock;\n\tint nr_tasks;\n\tpid_t gid;\n\tint active_nodes;\n\tstruct callback_head rcu;\n\tlong unsigned int total_faults;\n\tlong unsigned int max_faults_cpu;\n\tlong unsigned int *faults_cpu;\n\tlong unsigned int faults[0];\n};\n\nstruct update_util_data {\n\tvoid (*func)(struct update_util_data *, u64, unsigned int);\n};\n\nenum sched_tunable_scaling {\n\tSCHED_TUNABLESCALING_NONE = 0,\n\tSCHED_TUNABLESCALING_LOG = 1,\n\tSCHED_TUNABLESCALING_LINEAR = 2,\n\tSCHED_TUNABLESCALING_END = 3,\n};\n\nenum numa_topology_type {\n\tNUMA_DIRECT = 0,\n\tNUMA_GLUELESS_MESH = 1,\n\tNUMA_BACKPLANE = 2,\n};\n\nenum numa_faults_stats {\n\tNUMA_MEM = 0,\n\tNUMA_CPU = 1,\n\tNUMA_MEMBUF = 2,\n\tNUMA_CPUBUF = 3,\n};\n\nenum numa_type {\n\tnode_has_spare = 0,\n\tnode_fully_busy = 1,\n\tnode_overloaded = 2,\n};\n\nstruct numa_stats {\n\tlong unsigned int load;\n\tlong unsigned int runnable;\n\tlong unsigned int util;\n\tlong unsigned int compute_capacity;\n\tunsigned int nr_running;\n\tunsigned int weight;\n\tenum numa_type node_type;\n\tint idle_cpu;\n};\n\nstruct task_numa_env {\n\tstruct task_struct *p;\n\tint src_cpu;\n\tint src_nid;\n\tint dst_cpu;\n\tint dst_nid;\n\tstruct numa_stats src_stats;\n\tstruct numa_stats dst_stats;\n\tint imbalance_pct;\n\tint dist;\n\tstruct task_struct *best_task;\n\tlong int best_imp;\n\tint best_cpu;\n};\n\nenum fbq_type {\n\tregular = 0,\n\tremote = 1,\n\tall = 2,\n};\n\nenum group_type {\n\tgroup_has_spare = 0,\n\tgroup_fully_busy = 1,\n\tgroup_misfit_task = 2,\n\tgroup_asym_packing = 3,\n\tgroup_imbalanced = 4,\n\tgroup_overloaded = 5,\n};\n\nenum migration_type {\n\tmigrate_load = 0,\n\tmigrate_util = 1,\n\tmigrate_task = 2,\n\tmigrate_misfit = 3,\n};\n\nstruct lb_env {\n\tstruct sched_domain *sd;\n\tstruct rq *src_rq;\n\tint src_cpu;\n\tint dst_cpu;\n\tstruct rq *dst_rq;\n\tstruct cpumask *dst_grpmask;\n\tint new_dst_cpu;\n\tenum cpu_idle_type idle;\n\tlong int imbalance;\n\tstruct cpumask *cpus;\n\tunsigned int flags;\n\tunsigned int loop;\n\tunsigned int loop_break;\n\tunsigned int loop_max;\n\tenum fbq_type fbq_type;\n\tenum migration_type migration_type;\n\tstruct list_head tasks;\n};\n\nstruct sg_lb_stats {\n\tlong unsigned int avg_load;\n\tlong unsigned int group_load;\n\tlong unsigned int group_capacity;\n\tlong unsigned int group_util;\n\tlong unsigned int group_runnable;\n\tunsigned int sum_nr_running;\n\tunsigned int sum_h_nr_running;\n\tunsigned int idle_cpus;\n\tunsigned int group_weight;\n\tenum group_type group_type;\n\tunsigned int group_asym_packing;\n\tlong unsigned int group_misfit_task_load;\n\tunsigned int nr_numa_running;\n\tunsigned int nr_preferred_running;\n};\n\nstruct sd_lb_stats {\n\tstruct sched_group *busiest;\n\tstruct sched_group *local;\n\tlong unsigned int total_load;\n\tlong unsigned int total_capacity;\n\tlong unsigned int avg_load;\n\tunsigned int prefer_sibling;\n\tstruct sg_lb_stats busiest_stat;\n\tstruct sg_lb_stats local_stat;\n};\n\ntypedef struct rt_rq *rt_rq_iter_t;\n\nstruct sd_flag_debug {\n\tunsigned int meta_flags;\n\tchar *name;\n};\n\nstruct s_data {\n\tstruct sched_domain **sd;\n\tstruct root_domain *rd;\n};\n\nenum s_alloc {\n\tsa_rootdomain = 0,\n\tsa_sd = 1,\n\tsa_sd_storage = 2,\n\tsa_none = 3,\n};\n\nstruct asym_cap_data {\n\tstruct list_head link;\n\tlong unsigned int capacity;\n\tlong unsigned int cpus[0];\n};\n\nenum cpuacct_stat_index {\n\tCPUACCT_STAT_USER = 0,\n\tCPUACCT_STAT_SYSTEM = 1,\n\tCPUACCT_STAT_NSTATS = 2,\n};\n\nstruct cpuacct_usage {\n\tu64 usages[2];\n};\n\nstruct cpuacct {\n\tstruct cgroup_subsys_state css;\n\tstruct cpuacct_usage *cpuusage;\n\tstruct kernel_cpustat *cpustat;\n};\n\nstruct gov_attr_set {\n\tstruct kobject kobj;\n\tstruct list_head policy_list;\n\tstruct mutex update_lock;\n\tint usage_count;\n};\n\nstruct governor_attr {\n\tstruct attribute attr;\n\tssize_t (*show)(struct gov_attr_set *, char *);\n\tssize_t (*store)(struct gov_attr_set *, const char *, size_t);\n};\n\nstruct sugov_tunables {\n\tstruct gov_attr_set attr_set;\n\tunsigned int rate_limit_us;\n};\n\nstruct sugov_policy {\n\tstruct cpufreq_policy *policy;\n\tstruct sugov_tunables *tunables;\n\tstruct list_head tunables_hook;\n\traw_spinlock_t update_lock;\n\tu64 last_freq_update_time;\n\ts64 freq_update_delay_ns;\n\tunsigned int next_freq;\n\tunsigned int cached_raw_freq;\n\tstruct irq_work irq_work;\n\tstruct kthread_work work;\n\tstruct mutex work_lock;\n\tstruct kthread_worker worker;\n\tstruct task_struct *thread;\n\tbool work_in_progress;\n\tbool limits_changed;\n\tbool need_freq_update;\n};\n\nstruct sugov_cpu {\n\tstruct update_util_data update_util;\n\tstruct sugov_policy *sg_policy;\n\tunsigned int cpu;\n\tbool iowait_boost_pending;\n\tunsigned int iowait_boost;\n\tu64 last_update;\n\tlong unsigned int util;\n\tlong unsigned int bw_dl;\n\tlong unsigned int max;\n\tlong unsigned int saved_idle_calls;\n};\n\nenum {\n\tMEMBARRIER_FLAG_SYNC_CORE = 1,\n\tMEMBARRIER_FLAG_RSEQ = 2,\n};\n\nenum membarrier_cmd {\n\tMEMBARRIER_CMD_QUERY = 0,\n\tMEMBARRIER_CMD_GLOBAL = 1,\n\tMEMBARRIER_CMD_GLOBAL_EXPEDITED = 2,\n\tMEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = 4,\n\tMEMBARRIER_CMD_PRIVATE_EXPEDITED = 8,\n\tMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = 16,\n\tMEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = 32,\n\tMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = 64,\n\tMEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ = 128,\n\tMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ = 256,\n\tMEMBARRIER_CMD_SHARED = 1,\n};\n\nenum membarrier_cmd_flag {\n\tMEMBARRIER_CMD_FLAG_CPU = 1,\n};\n\nenum psi_res {\n\tPSI_IO = 0,\n\tPSI_MEM = 1,\n\tPSI_CPU = 2,\n\tNR_PSI_RESOURCES = 3,\n};\n\nstruct psi_window {\n\tu64 size;\n\tu64 start_time;\n\tu64 start_value;\n\tu64 prev_growth;\n};\n\nstruct psi_trigger {\n\tenum psi_states state;\n\tu64 threshold;\n\tstruct list_head node;\n\tstruct psi_group *group;\n\twait_queue_head_t event_wait;\n\tint event;\n\tstruct psi_window win;\n\tu64 last_event_time;\n\tstruct kref refcount;\n};\n\nstruct sched_core_cookie {\n\trefcount_t refcnt;\n};\n\nstruct ww_acquire_ctx;\n\nstruct ww_mutex {\n\tstruct mutex base;\n\tstruct ww_acquire_ctx *ctx;\n};\n\nstruct ww_acquire_ctx {\n\tstruct task_struct *task;\n\tlong unsigned int stamp;\n\tunsigned int acquired;\n\tshort unsigned int wounded;\n\tshort unsigned int is_wait_die;\n};\n\nstruct mutex_waiter {\n\tstruct list_head list;\n\tstruct task_struct *task;\n\tstruct ww_acquire_ctx *ww_ctx;\n};\n\nstruct semaphore {\n\traw_spinlock_t lock;\n\tunsigned int count;\n\tstruct list_head wait_list;\n};\n\nstruct semaphore_waiter {\n\tstruct list_head list;\n\tstruct task_struct *task;\n\tbool up;\n};\n\nenum lock_events {\n\tLOCKEVENT_pv_hash_hops = 0,\n\tLOCKEVENT_pv_kick_unlock = 1,\n\tLOCKEVENT_pv_kick_wake = 2,\n\tLOCKEVENT_pv_latency_kick = 3,\n\tLOCKEVENT_pv_latency_wake = 4,\n\tLOCKEVENT_pv_lock_stealing = 5,\n\tLOCKEVENT_pv_spurious_wakeup = 6,\n\tLOCKEVENT_pv_wait_again = 7,\n\tLOCKEVENT_pv_wait_early = 8,\n\tLOCKEVENT_pv_wait_head = 9,\n\tLOCKEVENT_pv_wait_node = 10,\n\tLOCKEVENT_lock_pending = 11,\n\tLOCKEVENT_lock_slowpath = 12,\n\tLOCKEVENT_lock_use_node2 = 13,\n\tLOCKEVENT_lock_use_node3 = 14,\n\tLOCKEVENT_lock_use_node4 = 15,\n\tLOCKEVENT_lock_no_node = 16,\n\tLOCKEVENT_rwsem_sleep_reader = 17,\n\tLOCKEVENT_rwsem_sleep_writer = 18,\n\tLOCKEVENT_rwsem_wake_reader = 19,\n\tLOCKEVENT_rwsem_wake_writer = 20,\n\tLOCKEVENT_rwsem_opt_lock = 21,\n\tLOCKEVENT_rwsem_opt_fail = 22,\n\tLOCKEVENT_rwsem_opt_nospin = 23,\n\tLOCKEVENT_rwsem_rlock = 24,\n\tLOCKEVENT_rwsem_rlock_steal = 25,\n\tLOCKEVENT_rwsem_rlock_fast = 26,\n\tLOCKEVENT_rwsem_rlock_fail = 27,\n\tLOCKEVENT_rwsem_rlock_handoff = 28,\n\tLOCKEVENT_rwsem_wlock = 29,\n\tLOCKEVENT_rwsem_wlock_fail = 30,\n\tLOCKEVENT_rwsem_wlock_handoff = 31,\n\tlockevent_num = 32,\n\tLOCKEVENT_reset_cnts = 32,\n};\n\nenum rwsem_waiter_type {\n\tRWSEM_WAITING_FOR_WRITE = 0,\n\tRWSEM_WAITING_FOR_READ = 1,\n};\n\nstruct rwsem_waiter {\n\tstruct list_head list;\n\tstruct task_struct *task;\n\tenum rwsem_waiter_type type;\n\tlong unsigned int timeout;\n};\n\nenum rwsem_wake_type {\n\tRWSEM_WAKE_ANY = 0,\n\tRWSEM_WAKE_READERS = 1,\n\tRWSEM_WAKE_READ_OWNED = 2,\n};\n\nenum writer_wait_state {\n\tWRITER_NOT_FIRST = 0,\n\tWRITER_FIRST = 1,\n\tWRITER_HANDOFF = 2,\n};\n\nenum owner_state {\n\tOWNER_NULL = 1,\n\tOWNER_WRITER = 2,\n\tOWNER_READER = 4,\n\tOWNER_NONSPINNABLE = 8,\n};\n\nstruct optimistic_spin_node {\n\tstruct optimistic_spin_node *next;\n\tstruct optimistic_spin_node *prev;\n\tint locked;\n\tint cpu;\n};\n\nstruct mcs_spinlock {\n\tstruct mcs_spinlock *next;\n\tint locked;\n\tint count;\n};\n\nstruct qnode {\n\tstruct mcs_spinlock mcs;\n\tlong int reserved[2];\n};\n\nenum vcpu_state {\n\tvcpu_running = 0,\n\tvcpu_halted = 1,\n\tvcpu_hashed = 2,\n};\n\nstruct pv_node {\n\tstruct mcs_spinlock mcs;\n\tint cpu;\n\tu8 state;\n};\n\nstruct pv_hash_entry {\n\tstruct qspinlock *lock;\n\tstruct pv_node *node;\n};\n\nstruct hrtimer_sleeper {\n\tstruct hrtimer timer;\n\tstruct task_struct *task;\n};\n\nstruct rt_mutex;\n\nstruct rt_mutex_waiter {\n\tstruct rb_node tree_entry;\n\tstruct rb_node pi_tree_entry;\n\tstruct task_struct *task;\n\tstruct rt_mutex *lock;\n\tint prio;\n\tu64 deadline;\n};\n\nstruct rt_mutex {\n\traw_spinlock_t wait_lock;\n\tstruct rb_root_cached waiters;\n\tstruct task_struct *owner;\n};\n\nenum rtmutex_chainwalk {\n\tRT_MUTEX_MIN_CHAINWALK = 0,\n\tRT_MUTEX_FULL_CHAINWALK = 1,\n};\n\nenum pm_qos_req_action {\n\tPM_QOS_ADD_REQ = 0,\n\tPM_QOS_UPDATE_REQ = 1,\n\tPM_QOS_REMOVE_REQ = 2,\n};\n\ntypedef int suspend_state_t;\n\nenum suspend_stat_step {\n\tSUSPEND_FREEZE = 1,\n\tSUSPEND_PREPARE = 2,\n\tSUSPEND_SUSPEND = 3,\n\tSUSPEND_SUSPEND_LATE = 4,\n\tSUSPEND_SUSPEND_NOIRQ = 5,\n\tSUSPEND_RESUME_NOIRQ = 6,\n\tSUSPEND_RESUME_EARLY = 7,\n\tSUSPEND_RESUME = 8,\n};\n\nstruct suspend_stats {\n\tint success;\n\tint fail;\n\tint failed_freeze;\n\tint failed_prepare;\n\tint failed_suspend;\n\tint failed_suspend_late;\n\tint failed_suspend_noirq;\n\tint failed_resume;\n\tint failed_resume_early;\n\tint failed_resume_noirq;\n\tint last_failed_dev;\n\tchar failed_devs[80];\n\tint last_failed_errno;\n\tint errno[2];\n\tint last_failed_step;\n\tenum suspend_stat_step failed_steps[2];\n};\n\nenum {\n\tTEST_NONE = 0,\n\tTEST_CORE = 1,\n\tTEST_CPUS = 2,\n\tTEST_PLATFORM = 3,\n\tTEST_DEVICES = 4,\n\tTEST_FREEZER = 5,\n\t__TEST_AFTER_LAST = 6,\n};\n\nstruct pm_vt_switch {\n\tstruct list_head head;\n\tstruct device *dev;\n\tbool required;\n};\n\nstruct platform_suspend_ops {\n\tint (*valid)(suspend_state_t);\n\tint (*begin)(suspend_state_t);\n\tint (*prepare)();\n\tint (*prepare_late)();\n\tint (*enter)(suspend_state_t);\n\tvoid (*wake)();\n\tvoid (*finish)();\n\tbool (*suspend_again)();\n\tvoid (*end)();\n\tvoid (*recover)();\n};\n\nstruct platform_s2idle_ops {\n\tint (*begin)();\n\tint (*prepare)();\n\tint (*prepare_late)();\n\tbool (*wake)();\n\tvoid (*restore_early)();\n\tvoid (*restore)();\n\tvoid (*end)();\n};\n\nstruct platform_hibernation_ops {\n\tint (*begin)(pm_message_t);\n\tvoid (*end)();\n\tint (*pre_snapshot)();\n\tvoid (*finish)();\n\tint (*prepare)();\n\tint (*enter)();\n\tvoid (*leave)();\n\tint (*pre_restore)();\n\tvoid (*restore_cleanup)();\n\tvoid (*recover)();\n};\n\nenum {\n\tHIBERNATION_INVALID = 0,\n\tHIBERNATION_PLATFORM = 1,\n\tHIBERNATION_SHUTDOWN = 2,\n\tHIBERNATION_REBOOT = 3,\n\tHIBERNATION_SUSPEND = 4,\n\tHIBERNATION_TEST_RESUME = 5,\n\t__HIBERNATION_AFTER_LAST = 6,\n};\n\nstruct pbe {\n\tvoid *address;\n\tvoid *orig_address;\n\tstruct pbe *next;\n};\n\nstruct swsusp_info {\n\tstruct new_utsname uts;\n\tu32 version_code;\n\tlong unsigned int num_physpages;\n\tint cpus;\n\tlong unsigned int image_pages;\n\tlong unsigned int pages;\n\tlong unsigned int size;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct snapshot_handle {\n\tunsigned int cur;\n\tvoid *buffer;\n\tint sync_read;\n};\n\nstruct linked_page {\n\tstruct linked_page *next;\n\tchar data[4088];\n};\n\nstruct chain_allocator {\n\tstruct linked_page *chain;\n\tunsigned int used_space;\n\tgfp_t gfp_mask;\n\tint safe_needed;\n};\n\nstruct rtree_node {\n\tstruct list_head list;\n\tlong unsigned int *data;\n};\n\nstruct mem_zone_bm_rtree {\n\tstruct list_head list;\n\tstruct list_head nodes;\n\tstruct list_head leaves;\n\tlong unsigned int start_pfn;\n\tlong unsigned int end_pfn;\n\tstruct rtree_node *rtree;\n\tint levels;\n\tunsigned int blocks;\n};\n\nstruct bm_position {\n\tstruct mem_zone_bm_rtree *zone;\n\tstruct rtree_node *node;\n\tlong unsigned int node_pfn;\n\tint node_bit;\n};\n\nstruct memory_bitmap {\n\tstruct list_head zones;\n\tstruct linked_page *p_list;\n\tstruct bm_position cur;\n};\n\nstruct mem_extent {\n\tstruct list_head hook;\n\tlong unsigned int start;\n\tlong unsigned int end;\n};\n\nstruct nosave_region {\n\tstruct list_head list;\n\tlong unsigned int start_pfn;\n\tlong unsigned int end_pfn;\n};\n\ntypedef struct {\n\tlong unsigned int val;\n} swp_entry_t;\n\nenum {\n\tBIO_NO_PAGE_REF = 0,\n\tBIO_CLONED = 1,\n\tBIO_BOUNCED = 2,\n\tBIO_WORKINGSET = 3,\n\tBIO_QUIET = 4,\n\tBIO_CHAIN = 5,\n\tBIO_REFFED = 6,\n\tBIO_THROTTLED = 7,\n\tBIO_TRACE_COMPLETION = 8,\n\tBIO_CGROUP_ACCT = 9,\n\tBIO_TRACKED = 10,\n\tBIO_REMAPPED = 11,\n\tBIO_ZONE_WRITE_LOCKED = 12,\n\tBIO_FLAG_LAST = 13,\n};\n\nenum req_opf {\n\tREQ_OP_READ = 0,\n\tREQ_OP_WRITE = 1,\n\tREQ_OP_FLUSH = 2,\n\tREQ_OP_DISCARD = 3,\n\tREQ_OP_SECURE_ERASE = 5,\n\tREQ_OP_WRITE_SAME = 7,\n\tREQ_OP_WRITE_ZEROES = 9,\n\tREQ_OP_ZONE_OPEN = 10,\n\tREQ_OP_ZONE_CLOSE = 11,\n\tREQ_OP_ZONE_FINISH = 12,\n\tREQ_OP_ZONE_APPEND = 13,\n\tREQ_OP_ZONE_RESET = 15,\n\tREQ_OP_ZONE_RESET_ALL = 17,\n\tREQ_OP_DRV_IN = 34,\n\tREQ_OP_DRV_OUT = 35,\n\tREQ_OP_LAST = 36,\n};\n\nenum req_flag_bits {\n\t__REQ_FAILFAST_DEV = 8,\n\t__REQ_FAILFAST_TRANSPORT = 9,\n\t__REQ_FAILFAST_DRIVER = 10,\n\t__REQ_SYNC = 11,\n\t__REQ_META = 12,\n\t__REQ_PRIO = 13,\n\t__REQ_NOMERGE = 14,\n\t__REQ_IDLE = 15,\n\t__REQ_INTEGRITY = 16,\n\t__REQ_FUA = 17,\n\t__REQ_PREFLUSH = 18,\n\t__REQ_RAHEAD = 19,\n\t__REQ_BACKGROUND = 20,\n\t__REQ_NOWAIT = 21,\n\t__REQ_CGROUP_PUNT = 22,\n\t__REQ_NOUNMAP = 23,\n\t__REQ_HIPRI = 24,\n\t__REQ_DRV = 25,\n\t__REQ_SWAP = 26,\n\t__REQ_NR_BITS = 27,\n};\n\nstruct swap_map_page {\n\tsector_t entries[511];\n\tsector_t next_swap;\n};\n\nstruct swap_map_page_list {\n\tstruct swap_map_page *map;\n\tstruct swap_map_page_list *next;\n};\n\nstruct swap_map_handle {\n\tstruct swap_map_page *cur;\n\tstruct swap_map_page_list *maps;\n\tsector_t cur_swap;\n\tsector_t first_sector;\n\tunsigned int k;\n\tlong unsigned int reqd_free_pages;\n\tu32 crc32;\n};\n\nstruct swsusp_header {\n\tchar reserved[4060];\n\tu32 crc32;\n\tsector_t image;\n\tunsigned int flags;\n\tchar orig_sig[10];\n\tchar sig[10];\n};\n\nstruct swsusp_extent {\n\tstruct rb_node node;\n\tlong unsigned int start;\n\tlong unsigned int end;\n};\n\nstruct hib_bio_batch {\n\tatomic_t count;\n\twait_queue_head_t wait;\n\tblk_status_t error;\n\tstruct blk_plug plug;\n};\n\nstruct crc_data {\n\tstruct task_struct *thr;\n\tatomic_t ready;\n\tatomic_t stop;\n\tunsigned int run_threads;\n\twait_queue_head_t go;\n\twait_queue_head_t done;\n\tu32 *crc32;\n\tsize_t *unc_len[3];\n\tunsigned char *unc[3];\n};\n\nstruct cmp_data {\n\tstruct task_struct *thr;\n\tatomic_t ready;\n\tatomic_t stop;\n\tint ret;\n\twait_queue_head_t go;\n\twait_queue_head_t done;\n\tsize_t unc_len;\n\tsize_t cmp_len;\n\tunsigned char unc[131072];\n\tunsigned char cmp[143360];\n\tunsigned char wrk[16384];\n};\n\nstruct dec_data {\n\tstruct task_struct *thr;\n\tatomic_t ready;\n\tatomic_t stop;\n\tint ret;\n\twait_queue_head_t go;\n\twait_queue_head_t done;\n\tsize_t unc_len;\n\tsize_t cmp_len;\n\tunsigned char unc[131072];\n\tunsigned char cmp[143360];\n};\n\ntypedef s64 compat_loff_t;\n\nstruct resume_swap_area {\n\t__kernel_loff_t offset;\n\t__u32 dev;\n} __attribute__((packed));\n\nstruct snapshot_data {\n\tstruct snapshot_handle handle;\n\tint swap;\n\tint mode;\n\tbool frozen;\n\tbool ready;\n\tbool platform_support;\n\tbool free_bitmaps;\n\tdev_t dev;\n};\n\nstruct compat_resume_swap_area {\n\tcompat_loff_t offset;\n\tu32 dev;\n} __attribute__((packed));\n\nstruct sysrq_key_op {\n\tvoid (* const handler)(int);\n\tconst char * const help_msg;\n\tconst char * const action_msg;\n\tconst int enable_mask;\n};\n\nstruct em_data_callback {\n\tint (*active_power)(long unsigned int *, long unsigned int *, struct device *);\n};\n\nstruct dev_printk_info {\n\tchar subsystem[16];\n\tchar device[48];\n};\n\nstruct kmsg_dump_iter {\n\tu64 cur_seq;\n\tu64 next_seq;\n};\n\nstruct kmsg_dumper {\n\tstruct list_head list;\n\tvoid (*dump)(struct kmsg_dumper *, enum kmsg_dump_reason);\n\tenum kmsg_dump_reason max_reason;\n\tbool registered;\n};\n\nstruct trace_event_raw_console {\n\tstruct trace_entry ent;\n\tu32 __data_loc_msg;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_console {\n\tu32 msg;\n};\n\ntypedef void (*btf_trace_console)(void *, const char *, size_t);\n\nstruct printk_info {\n\tu64 seq;\n\tu64 ts_nsec;\n\tu16 text_len;\n\tu8 facility;\n\tu8 flags: 5;\n\tu8 level: 3;\n\tu32 caller_id;\n\tstruct dev_printk_info dev_info;\n};\n\nstruct printk_record {\n\tstruct printk_info *info;\n\tchar *text_buf;\n\tunsigned int text_buf_size;\n};\n\nstruct prb_data_blk_lpos {\n\tlong unsigned int begin;\n\tlong unsigned int next;\n};\n\nstruct prb_desc {\n\tatomic_long_t state_var;\n\tstruct prb_data_blk_lpos text_blk_lpos;\n};\n\nstruct prb_data_ring {\n\tunsigned int size_bits;\n\tchar *data;\n\tatomic_long_t head_lpos;\n\tatomic_long_t tail_lpos;\n};\n\nstruct prb_desc_ring {\n\tunsigned int count_bits;\n\tstruct prb_desc *descs;\n\tstruct printk_info *infos;\n\tatomic_long_t head_id;\n\tatomic_long_t tail_id;\n};\n\nstruct printk_ringbuffer {\n\tstruct prb_desc_ring desc_ring;\n\tstruct prb_data_ring text_data_ring;\n\tatomic_long_t fail;\n};\n\nstruct prb_reserved_entry {\n\tstruct printk_ringbuffer *rb;\n\tlong unsigned int irqflags;\n\tlong unsigned int id;\n\tunsigned int text_space;\n};\n\nenum desc_state {\n\tdesc_miss = 4294967295,\n\tdesc_reserved = 0,\n\tdesc_committed = 1,\n\tdesc_finalized = 2,\n\tdesc_reusable = 3,\n};\n\nstruct console_cmdline {\n\tchar name[16];\n\tint index;\n\tbool user_specified;\n\tchar *options;\n\tchar *brl_options;\n};\n\nenum devkmsg_log_bits {\n\t__DEVKMSG_LOG_BIT_ON = 0,\n\t__DEVKMSG_LOG_BIT_OFF = 1,\n\t__DEVKMSG_LOG_BIT_LOCK = 2,\n};\n\nenum devkmsg_log_masks {\n\tDEVKMSG_LOG_MASK_ON = 1,\n\tDEVKMSG_LOG_MASK_OFF = 2,\n\tDEVKMSG_LOG_MASK_LOCK = 4,\n};\n\nenum con_msg_format_flags {\n\tMSG_FORMAT_DEFAULT = 0,\n\tMSG_FORMAT_SYSLOG = 1,\n};\n\nenum log_flags {\n\tLOG_NEWLINE = 2,\n\tLOG_CONT = 8,\n};\n\nstruct latched_seq {\n\tseqcount_latch_t latch;\n\tu64 val[2];\n};\n\nstruct devkmsg_user {\n\tatomic64_t seq;\n\tstruct ratelimit_state rs;\n\tstruct mutex lock;\n\tchar buf[8192];\n\tstruct printk_info info;\n\tchar text_buf[8192];\n\tstruct printk_record record;\n};\n\nstruct printk_safe_seq_buf {\n\tatomic_t len;\n\tatomic_t message_lost;\n\tstruct irq_work work;\n\tunsigned char buffer[8160];\n};\n\nstruct dev_printk_info___2;\n\nstruct prb_data_block {\n\tlong unsigned int id;\n\tchar data[0];\n};\n\nenum {\n\tIRQS_AUTODETECT = 1,\n\tIRQS_SPURIOUS_DISABLED = 2,\n\tIRQS_POLL_INPROGRESS = 8,\n\tIRQS_ONESHOT = 32,\n\tIRQS_REPLAY = 64,\n\tIRQS_WAITING = 128,\n\tIRQS_PENDING = 512,\n\tIRQS_SUSPENDED = 2048,\n\tIRQS_TIMINGS = 4096,\n\tIRQS_NMI = 8192,\n};\n\nenum {\n\t_IRQ_DEFAULT_INIT_FLAGS = 0,\n\t_IRQ_PER_CPU = 512,\n\t_IRQ_LEVEL = 256,\n\t_IRQ_NOPROBE = 1024,\n\t_IRQ_NOREQUEST = 2048,\n\t_IRQ_NOTHREAD = 65536,\n\t_IRQ_NOAUTOEN = 4096,\n\t_IRQ_MOVE_PCNTXT = 16384,\n\t_IRQ_NO_BALANCING = 8192,\n\t_IRQ_NESTED_THREAD = 32768,\n\t_IRQ_PER_CPU_DEVID = 131072,\n\t_IRQ_IS_POLLED = 262144,\n\t_IRQ_DISABLE_UNLAZY = 524288,\n\t_IRQ_HIDDEN = 1048576,\n\t_IRQ_NO_DEBUG = 2097152,\n\t_IRQF_MODIFY_MASK = 2096911,\n};\n\nenum {\n\tIRQTF_RUNTHREAD = 0,\n\tIRQTF_WARNED = 1,\n\tIRQTF_AFFINITY = 2,\n\tIRQTF_FORCED_THREAD = 3,\n};\n\nenum {\n\tIRQC_IS_HARDIRQ = 0,\n\tIRQC_IS_NESTED = 1,\n};\n\nenum {\n\tIRQ_STARTUP_NORMAL = 0,\n\tIRQ_STARTUP_MANAGED = 1,\n\tIRQ_STARTUP_ABORT = 2,\n};\n\nstruct irq_devres {\n\tunsigned int irq;\n\tvoid *dev_id;\n};\n\nstruct irq_desc_devres {\n\tunsigned int from;\n\tunsigned int cnt;\n};\n\nstruct irq_generic_chip_devres {\n\tstruct irq_chip_generic *gc;\n\tu32 msk;\n\tunsigned int clr;\n\tunsigned int set;\n};\n\nstruct irqchip_fwid {\n\tstruct fwnode_handle fwnode;\n\tunsigned int type;\n\tchar *name;\n\tphys_addr_t *pa;\n};\n\nstruct irq_sim_work_ctx {\n\tstruct irq_work work;\n\tint irq_base;\n\tunsigned int irq_count;\n\tlong unsigned int *pending;\n\tstruct irq_domain *domain;\n};\n\nstruct irq_sim_irq_ctx {\n\tint irqnum;\n\tbool enabled;\n\tstruct irq_sim_work_ctx *work_ctx;\n};\n\nenum {\n\tAFFINITY = 0,\n\tAFFINITY_LIST = 1,\n\tEFFECTIVE = 2,\n\tEFFECTIVE_LIST = 3,\n};\n\nstruct irq_affinity {\n\tunsigned int pre_vectors;\n\tunsigned int post_vectors;\n\tunsigned int nr_sets;\n\tunsigned int set_size[4];\n\tvoid (*calc_sets)(struct irq_affinity *, unsigned int);\n\tvoid *priv;\n};\n\nstruct node_vectors {\n\tunsigned int id;\n\tunion {\n\t\tunsigned int nvectors;\n\t\tunsigned int ncpus;\n\t};\n};\n\nstruct cpumap {\n\tunsigned int available;\n\tunsigned int allocated;\n\tunsigned int managed;\n\tunsigned int managed_allocated;\n\tbool initialized;\n\tbool online;\n\tlong unsigned int alloc_map[4];\n\tlong unsigned int managed_map[4];\n};\n\nstruct irq_matrix___2 {\n\tunsigned int matrix_bits;\n\tunsigned int alloc_start;\n\tunsigned int alloc_end;\n\tunsigned int alloc_size;\n\tunsigned int global_available;\n\tunsigned int global_reserved;\n\tunsigned int systembits_inalloc;\n\tunsigned int total_allocated;\n\tunsigned int online_maps;\n\tstruct cpumap *maps;\n\tlong unsigned int scratch_map[4];\n\tlong unsigned int system_map[4];\n};\n\nstruct trace_event_raw_irq_matrix_global {\n\tstruct trace_entry ent;\n\tunsigned int online_maps;\n\tunsigned int global_available;\n\tunsigned int global_reserved;\n\tunsigned int total_allocated;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_irq_matrix_global_update {\n\tstruct trace_entry ent;\n\tint bit;\n\tunsigned int online_maps;\n\tunsigned int global_available;\n\tunsigned int global_reserved;\n\tunsigned int total_allocated;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_irq_matrix_cpu {\n\tstruct trace_entry ent;\n\tint bit;\n\tunsigned int cpu;\n\tbool online;\n\tunsigned int available;\n\tunsigned int allocated;\n\tunsigned int managed;\n\tunsigned int online_maps;\n\tunsigned int global_available;\n\tunsigned int global_reserved;\n\tunsigned int total_allocated;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_irq_matrix_global {};\n\nstruct trace_event_data_offsets_irq_matrix_global_update {};\n\nstruct trace_event_data_offsets_irq_matrix_cpu {};\n\ntypedef void (*btf_trace_irq_matrix_online)(void *, struct irq_matrix___2 *);\n\ntypedef void (*btf_trace_irq_matrix_offline)(void *, struct irq_matrix___2 *);\n\ntypedef void (*btf_trace_irq_matrix_reserve)(void *, struct irq_matrix___2 *);\n\ntypedef void (*btf_trace_irq_matrix_remove_reserved)(void *, struct irq_matrix___2 *);\n\ntypedef void (*btf_trace_irq_matrix_assign_system)(void *, int, struct irq_matrix___2 *);\n\ntypedef void (*btf_trace_irq_matrix_alloc_reserved)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *);\n\ntypedef void (*btf_trace_irq_matrix_reserve_managed)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *);\n\ntypedef void (*btf_trace_irq_matrix_remove_managed)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *);\n\ntypedef void (*btf_trace_irq_matrix_alloc_managed)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *);\n\ntypedef void (*btf_trace_irq_matrix_assign)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *);\n\ntypedef void (*btf_trace_irq_matrix_alloc)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *);\n\ntypedef void (*btf_trace_irq_matrix_free)(void *, int, unsigned int, struct irq_matrix___2 *, struct cpumap *);\n\ntypedef void (*call_rcu_func_t)(struct callback_head *, rcu_callback_t);\n\nstruct rcu_synchronize {\n\tstruct callback_head head;\n\tstruct completion completion;\n};\n\nstruct trace_event_raw_rcu_utilization {\n\tstruct trace_entry ent;\n\tconst char *s;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rcu_stall_warning {\n\tstruct trace_entry ent;\n\tconst char *rcuname;\n\tconst char *msg;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_rcu_utilization {};\n\nstruct trace_event_data_offsets_rcu_stall_warning {};\n\ntypedef void (*btf_trace_rcu_utilization)(void *, const char *);\n\ntypedef void (*btf_trace_rcu_stall_warning)(void *, const char *, const char *);\n\nstruct rcu_tasks;\n\ntypedef void (*rcu_tasks_gp_func_t)(struct rcu_tasks *);\n\ntypedef void (*pregp_func_t)();\n\ntypedef void (*pertask_func_t)(struct task_struct *, struct list_head *);\n\ntypedef void (*postscan_func_t)(struct list_head *);\n\ntypedef void (*holdouts_func_t)(struct list_head *, bool, bool *);\n\ntypedef void (*postgp_func_t)(struct rcu_tasks *);\n\nstruct rcu_tasks {\n\tstruct callback_head *cbs_head;\n\tstruct callback_head **cbs_tail;\n\tstruct wait_queue_head cbs_wq;\n\traw_spinlock_t cbs_lock;\n\tint gp_state;\n\tint gp_sleep;\n\tint init_fract;\n\tlong unsigned int gp_jiffies;\n\tlong unsigned int gp_start;\n\tlong unsigned int n_gps;\n\tlong unsigned int n_ipis;\n\tlong unsigned int n_ipis_fails;\n\tstruct task_struct *kthread_ptr;\n\trcu_tasks_gp_func_t gp_func;\n\tpregp_func_t pregp_func;\n\tpertask_func_t pertask_func;\n\tpostscan_func_t postscan_func;\n\tholdouts_func_t holdouts_func;\n\tpostgp_func_t postgp_func;\n\tcall_rcu_func_t call_func;\n\tchar *name;\n\tchar *kname;\n};\n\nenum {\n\tGP_IDLE = 0,\n\tGP_ENTER = 1,\n\tGP_PASSED = 2,\n\tGP_EXIT = 3,\n\tGP_REPLAY = 4,\n};\n\nstruct rcu_cblist {\n\tstruct callback_head *head;\n\tstruct callback_head **tail;\n\tlong int len;\n};\n\nenum rcutorture_type {\n\tRCU_FLAVOR = 0,\n\tRCU_TASKS_FLAVOR = 1,\n\tRCU_TASKS_RUDE_FLAVOR = 2,\n\tRCU_TASKS_TRACING_FLAVOR = 3,\n\tRCU_TRIVIAL_FLAVOR = 4,\n\tSRCU_FLAVOR = 5,\n\tINVALID_RCU_FLAVOR = 6,\n};\n\nstruct rcu_exp_work {\n\tlong unsigned int rew_s;\n\tstruct work_struct rew_work;\n};\n\nstruct rcu_node {\n\traw_spinlock_t lock;\n\tlong unsigned int gp_seq;\n\tlong unsigned int gp_seq_needed;\n\tlong unsigned int completedqs;\n\tlong unsigned int qsmask;\n\tlong unsigned int rcu_gp_init_mask;\n\tlong unsigned int qsmaskinit;\n\tlong unsigned int qsmaskinitnext;\n\tlong unsigned int ofl_seq;\n\tlong unsigned int expmask;\n\tlong unsigned int expmaskinit;\n\tlong unsigned int expmaskinitnext;\n\tlong unsigned int cbovldmask;\n\tlong unsigned int ffmask;\n\tlong unsigned int grpmask;\n\tint grplo;\n\tint grphi;\n\tu8 grpnum;\n\tu8 level;\n\tbool wait_blkd_tasks;\n\tstruct rcu_node *parent;\n\tstruct list_head blkd_tasks;\n\tstruct list_head *gp_tasks;\n\tstruct list_head *exp_tasks;\n\tstruct list_head *boost_tasks;\n\tstruct rt_mutex boost_mtx;\n\tlong unsigned int boost_time;\n\tstruct task_struct *boost_kthread_task;\n\tunsigned int boost_kthread_status;\n\tlong unsigned int n_boosts;\n\tlong: 64;\n\traw_spinlock_t fqslock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tspinlock_t exp_lock;\n\tlong unsigned int exp_seq_rq;\n\twait_queue_head_t exp_wq[4];\n\tstruct rcu_exp_work rew;\n\tbool exp_need_flush;\n\tlong: 56;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nunion rcu_noqs {\n\tstruct {\n\t\tu8 norm;\n\t\tu8 exp;\n\t} b;\n\tu16 s;\n};\n\nstruct rcu_data {\n\tlong unsigned int gp_seq;\n\tlong unsigned int gp_seq_needed;\n\tunion rcu_noqs cpu_no_qs;\n\tbool core_needs_qs;\n\tbool beenonline;\n\tbool gpwrap;\n\tbool exp_deferred_qs;\n\tbool cpu_started;\n\tstruct rcu_node *mynode;\n\tlong unsigned int grpmask;\n\tlong unsigned int ticks_this_gp;\n\tstruct irq_work defer_qs_iw;\n\tbool defer_qs_iw_pending;\n\tstruct work_struct strict_work;\n\tstruct rcu_segcblist cblist;\n\tlong int qlen_last_fqs_check;\n\tlong unsigned int n_cbs_invoked;\n\tlong unsigned int n_force_qs_snap;\n\tlong int blimit;\n\tint dynticks_snap;\n\tlong int dynticks_nesting;\n\tlong int dynticks_nmi_nesting;\n\tatomic_t dynticks;\n\tbool rcu_need_heavy_qs;\n\tbool rcu_urgent_qs;\n\tbool rcu_forced_tick;\n\tbool rcu_forced_tick_exp;\n\tlong unsigned int last_accelerate;\n\tlong unsigned int last_advance_all;\n\tint tick_nohz_enabled_snap;\n\tstruct callback_head barrier_head;\n\tint exp_dynticks_snap;\n\tstruct task_struct *rcu_cpu_kthread_task;\n\tunsigned int rcu_cpu_kthread_status;\n\tchar rcu_cpu_has_work;\n\tunsigned int softirq_snap;\n\tstruct irq_work rcu_iw;\n\tbool rcu_iw_pending;\n\tlong unsigned int rcu_iw_gp_seq;\n\tlong unsigned int rcu_ofl_gp_seq;\n\tshort int rcu_ofl_gp_flags;\n\tlong unsigned int rcu_onl_gp_seq;\n\tshort int rcu_onl_gp_flags;\n\tlong unsigned int last_fqs_resched;\n\tint cpu;\n};\n\nstruct rcu_state {\n\tstruct rcu_node node[21];\n\tstruct rcu_node *level[3];\n\tint ncpus;\n\tint n_online_cpus;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu8 boost;\n\tlong unsigned int gp_seq;\n\tlong unsigned int gp_max;\n\tstruct task_struct *gp_kthread;\n\tstruct swait_queue_head gp_wq;\n\tshort int gp_flags;\n\tshort int gp_state;\n\tlong unsigned int gp_wake_time;\n\tlong unsigned int gp_wake_seq;\n\tstruct mutex barrier_mutex;\n\tatomic_t barrier_cpu_count;\n\tstruct completion barrier_completion;\n\tlong unsigned int barrier_sequence;\n\tstruct mutex exp_mutex;\n\tstruct mutex exp_wake_mutex;\n\tlong unsigned int expedited_sequence;\n\tatomic_t expedited_need_qs;\n\tstruct swait_queue_head expedited_wq;\n\tint ncpus_snap;\n\tu8 cbovld;\n\tu8 cbovldnext;\n\tlong unsigned int jiffies_force_qs;\n\tlong unsigned int jiffies_kick_kthreads;\n\tlong unsigned int n_force_qs;\n\tlong unsigned int gp_start;\n\tlong unsigned int gp_end;\n\tlong unsigned int gp_activity;\n\tlong unsigned int gp_req_activity;\n\tlong unsigned int jiffies_stall;\n\tlong unsigned int jiffies_resched;\n\tlong unsigned int n_force_qs_gpstart;\n\tconst char *name;\n\tchar abbr;\n\tlong: 56;\n\tlong: 64;\n\tlong: 64;\n\traw_spinlock_t ofl_lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct kvfree_rcu_bulk_data {\n\tlong unsigned int nr_records;\n\tstruct kvfree_rcu_bulk_data *next;\n\tvoid *records[0];\n};\n\nstruct kfree_rcu_cpu;\n\nstruct kfree_rcu_cpu_work {\n\tstruct rcu_work rcu_work;\n\tstruct callback_head *head_free;\n\tstruct kvfree_rcu_bulk_data *bkvhead_free[2];\n\tstruct kfree_rcu_cpu *krcp;\n};\n\nstruct kfree_rcu_cpu {\n\tstruct callback_head *head;\n\tstruct kvfree_rcu_bulk_data *bkvhead[2];\n\tstruct kfree_rcu_cpu_work krw_arr[2];\n\traw_spinlock_t lock;\n\tstruct delayed_work monitor_work;\n\tbool monitor_todo;\n\tbool initialized;\n\tint count;\n\tstruct delayed_work page_cache_work;\n\tatomic_t backoff_page_cache_fill;\n\tatomic_t work_in_progress;\n\tstruct hrtimer hrtimer;\n\tstruct llist_head bkvcache;\n\tint nr_bkv_objs;\n};\n\nstruct rcu_stall_chk_rdr {\n\tint nesting;\n\tunion rcu_special rs;\n\tbool on_blkd_list;\n};\n\nstruct io_tlb_slot {\n\tphys_addr_t orig_addr;\n\tsize_t alloc_size;\n\tunsigned int list;\n};\n\nstruct io_tlb_mem {\n\tphys_addr_t start;\n\tphys_addr_t end;\n\tlong unsigned int nslabs;\n\tlong unsigned int used;\n\tunsigned int index;\n\tspinlock_t lock;\n\tstruct dentry *debugfs;\n\tbool late_alloc;\n\tstruct io_tlb_slot slots[0];\n};\n\nstruct dma_sgt_handle {\n\tstruct sg_table sgt;\n\tstruct page **pages;\n};\n\nstruct dma_devres {\n\tsize_t size;\n\tvoid *vaddr;\n\tdma_addr_t dma_handle;\n\tlong unsigned int attrs;\n};\n\nstruct debugfs_u32_array {\n\tu32 *array;\n\tu32 n_elements;\n};\n\nstruct cma_kobject;\n\nstruct cma {\n\tlong unsigned int base_pfn;\n\tlong unsigned int count;\n\tlong unsigned int *bitmap;\n\tunsigned int order_per_bit;\n\tspinlock_t lock;\n\tstruct hlist_head mem_head;\n\tspinlock_t mem_head_lock;\n\tstruct debugfs_u32_array dfs_bitmap;\n\tchar name[64];\n\tatomic64_t nr_pages_succeeded;\n\tatomic64_t nr_pages_failed;\n\tstruct cma_kobject *cma_kobj;\n};\n\nstruct trace_event_raw_swiotlb_bounced {\n\tstruct trace_entry ent;\n\tu32 __data_loc_dev_name;\n\tu64 dma_mask;\n\tdma_addr_t dev_addr;\n\tsize_t size;\n\tenum swiotlb_force swiotlb_force;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_swiotlb_bounced {\n\tu32 dev_name;\n};\n\ntypedef void (*btf_trace_swiotlb_bounced)(void *, struct device *, dma_addr_t, size_t, enum swiotlb_force);\n\nstruct trace_event_raw_sys_enter {\n\tstruct trace_entry ent;\n\tlong int id;\n\tlong unsigned int args[6];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sys_exit {\n\tstruct trace_entry ent;\n\tlong int id;\n\tlong int ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_sys_enter {};\n\nstruct trace_event_data_offsets_sys_exit {};\n\ntypedef void (*btf_trace_sys_enter)(void *, struct pt_regs *, long int);\n\ntypedef void (*btf_trace_sys_exit)(void *, struct pt_regs *, long int);\n\nstruct kvm_regs {\n\t__u64 rax;\n\t__u64 rbx;\n\t__u64 rcx;\n\t__u64 rdx;\n\t__u64 rsi;\n\t__u64 rdi;\n\t__u64 rsp;\n\t__u64 rbp;\n\t__u64 r8;\n\t__u64 r9;\n\t__u64 r10;\n\t__u64 r11;\n\t__u64 r12;\n\t__u64 r13;\n\t__u64 r14;\n\t__u64 r15;\n\t__u64 rip;\n\t__u64 rflags;\n};\n\nstruct kvm_segment {\n\t__u64 base;\n\t__u32 limit;\n\t__u16 selector;\n\t__u8 type;\n\t__u8 present;\n\t__u8 dpl;\n\t__u8 db;\n\t__u8 s;\n\t__u8 l;\n\t__u8 g;\n\t__u8 avl;\n\t__u8 unusable;\n\t__u8 padding;\n};\n\nstruct kvm_dtable {\n\t__u64 base;\n\t__u16 limit;\n\t__u16 padding[3];\n};\n\nstruct kvm_sregs {\n\tstruct kvm_segment cs;\n\tstruct kvm_segment ds;\n\tstruct kvm_segment es;\n\tstruct kvm_segment fs;\n\tstruct kvm_segment gs;\n\tstruct kvm_segment ss;\n\tstruct kvm_segment tr;\n\tstruct kvm_segment ldt;\n\tstruct kvm_dtable gdt;\n\tstruct kvm_dtable idt;\n\t__u64 cr0;\n\t__u64 cr2;\n\t__u64 cr3;\n\t__u64 cr4;\n\t__u64 cr8;\n\t__u64 efer;\n\t__u64 apic_base;\n\t__u64 interrupt_bitmap[4];\n};\n\nstruct kvm_msr_entry {\n\t__u32 index;\n\t__u32 reserved;\n\t__u64 data;\n};\n\nstruct kvm_cpuid_entry2 {\n\t__u32 function;\n\t__u32 index;\n\t__u32 flags;\n\t__u32 eax;\n\t__u32 ebx;\n\t__u32 ecx;\n\t__u32 edx;\n\t__u32 padding[3];\n};\n\nstruct kvm_debug_exit_arch {\n\t__u32 exception;\n\t__u32 pad;\n\t__u64 pc;\n\t__u64 dr6;\n\t__u64 dr7;\n};\n\nstruct kvm_vcpu_events {\n\tstruct {\n\t\t__u8 injected;\n\t\t__u8 nr;\n\t\t__u8 has_error_code;\n\t\t__u8 pending;\n\t\t__u32 error_code;\n\t} exception;\n\tstruct {\n\t\t__u8 injected;\n\t\t__u8 nr;\n\t\t__u8 soft;\n\t\t__u8 shadow;\n\t} interrupt;\n\tstruct {\n\t\t__u8 injected;\n\t\t__u8 pending;\n\t\t__u8 masked;\n\t\t__u8 pad;\n\t} nmi;\n\t__u32 sipi_vector;\n\t__u32 flags;\n\tstruct {\n\t\t__u8 smm;\n\t\t__u8 pending;\n\t\t__u8 smm_inside_nmi;\n\t\t__u8 latched_init;\n\t} smi;\n\t__u8 reserved[27];\n\t__u8 exception_has_payload;\n\t__u64 exception_payload;\n};\n\nstruct kvm_sync_regs {\n\tstruct kvm_regs regs;\n\tstruct kvm_sregs sregs;\n\tstruct kvm_vcpu_events events;\n};\n\nstruct kvm_vmx_nested_state_data {\n\t__u8 vmcs12[4096];\n\t__u8 shadow_vmcs12[4096];\n};\n\nstruct kvm_vmx_nested_state_hdr {\n\t__u64 vmxon_pa;\n\t__u64 vmcs12_pa;\n\tstruct {\n\t\t__u16 flags;\n\t} smm;\n\t__u16 pad;\n\t__u32 flags;\n\t__u64 preemption_timer_deadline;\n};\n\nstruct kvm_svm_nested_state_data {\n\t__u8 vmcb12[4096];\n};\n\nstruct kvm_svm_nested_state_hdr {\n\t__u64 vmcb_pa;\n};\n\nstruct kvm_nested_state {\n\t__u16 flags;\n\t__u16 format;\n\t__u32 size;\n\tunion {\n\t\tstruct kvm_vmx_nested_state_hdr vmx;\n\t\tstruct kvm_svm_nested_state_hdr svm;\n\t\t__u8 pad[120];\n\t} hdr;\n\tunion {\n\t\tstruct kvm_vmx_nested_state_data vmx[0];\n\t\tstruct kvm_svm_nested_state_data svm[0];\n\t} data;\n};\n\nstruct kvm_pmu_event_filter {\n\t__u32 action;\n\t__u32 nevents;\n\t__u32 fixed_counter_bitmap;\n\t__u32 flags;\n\t__u32 pad[4];\n\t__u64 events[0];\n};\n\nstruct kvm_hyperv_exit {\n\t__u32 type;\n\t__u32 pad1;\n\tunion {\n\t\tstruct {\n\t\t\t__u32 msr;\n\t\t\t__u32 pad2;\n\t\t\t__u64 control;\n\t\t\t__u64 evt_page;\n\t\t\t__u64 msg_page;\n\t\t} synic;\n\t\tstruct {\n\t\t\t__u64 input;\n\t\t\t__u64 result;\n\t\t\t__u64 params[2];\n\t\t} hcall;\n\t\tstruct {\n\t\t\t__u32 msr;\n\t\t\t__u32 pad2;\n\t\t\t__u64 control;\n\t\t\t__u64 status;\n\t\t\t__u64 send_page;\n\t\t\t__u64 recv_page;\n\t\t\t__u64 pending_page;\n\t\t} syndbg;\n\t} u;\n};\n\nstruct kvm_xen_exit {\n\t__u32 type;\n\tunion {\n\t\tstruct {\n\t\t\t__u32 longmode;\n\t\t\t__u32 cpl;\n\t\t\t__u64 input;\n\t\t\t__u64 result;\n\t\t\t__u64 params[6];\n\t\t} hcall;\n\t} u;\n};\n\nstruct kvm_run {\n\t__u8 request_interrupt_window;\n\t__u8 immediate_exit;\n\t__u8 padding1[6];\n\t__u32 exit_reason;\n\t__u8 ready_for_interrupt_injection;\n\t__u8 if_flag;\n\t__u16 flags;\n\t__u64 cr8;\n\t__u64 apic_base;\n\tunion {\n\t\tstruct {\n\t\t\t__u64 hardware_exit_reason;\n\t\t} hw;\n\t\tstruct {\n\t\t\t__u64 hardware_entry_failure_reason;\n\t\t\t__u32 cpu;\n\t\t} fail_entry;\n\t\tstruct {\n\t\t\t__u32 exception;\n\t\t\t__u32 error_code;\n\t\t} ex;\n\t\tstruct {\n\t\t\t__u8 direction;\n\t\t\t__u8 size;\n\t\t\t__u16 port;\n\t\t\t__u32 count;\n\t\t\t__u64 data_offset;\n\t\t} io;\n\t\tstruct {\n\t\t\tstruct kvm_debug_exit_arch arch;\n\t\t} debug;\n\t\tstruct {\n\t\t\t__u64 phys_addr;\n\t\t\t__u8 data[8];\n\t\t\t__u32 len;\n\t\t\t__u8 is_write;\n\t\t} mmio;\n\t\tstruct {\n\t\t\t__u64 nr;\n\t\t\t__u64 args[6];\n\t\t\t__u64 ret;\n\t\t\t__u32 longmode;\n\t\t\t__u32 pad;\n\t\t} hypercall;\n\t\tstruct {\n\t\t\t__u64 rip;\n\t\t\t__u32 is_write;\n\t\t\t__u32 pad;\n\t\t} tpr_access;\n\t\tstruct {\n\t\t\t__u8 icptcode;\n\t\t\t__u16 ipa;\n\t\t\t__u32 ipb;\n\t\t} s390_sieic;\n\t\t__u64 s390_reset_flags;\n\t\tstruct {\n\t\t\t__u64 trans_exc_code;\n\t\t\t__u32 pgm_code;\n\t\t} s390_ucontrol;\n\t\tstruct {\n\t\t\t__u32 dcrn;\n\t\t\t__u32 data;\n\t\t\t__u8 is_write;\n\t\t} dcr;\n\t\tstruct {\n\t\t\t__u32 suberror;\n\t\t\t__u32 ndata;\n\t\t\t__u64 data[16];\n\t\t} internal;\n\t\tstruct {\n\t\t\t__u32 suberror;\n\t\t\t__u32 ndata;\n\t\t\t__u64 flags;\n\t\t\t__u8 insn_size;\n\t\t\t__u8 insn_bytes[15];\n\t\t} emulation_failure;\n\t\tstruct {\n\t\t\t__u64 gprs[32];\n\t\t} osi;\n\t\tstruct {\n\t\t\t__u64 nr;\n\t\t\t__u64 ret;\n\t\t\t__u64 args[9];\n\t\t} papr_hcall;\n\t\tstruct {\n\t\t\t__u16 subchannel_id;\n\t\t\t__u16 subchannel_nr;\n\t\t\t__u32 io_int_parm;\n\t\t\t__u32 io_int_word;\n\t\t\t__u32 ipb;\n\t\t\t__u8 dequeued;\n\t\t} s390_tsch;\n\t\tstruct {\n\t\t\t__u32 epr;\n\t\t} epr;\n\t\tstruct {\n\t\t\t__u32 type;\n\t\t\t__u64 flags;\n\t\t} system_event;\n\t\tstruct {\n\t\t\t__u64 addr;\n\t\t\t__u8 ar;\n\t\t\t__u8 reserved;\n\t\t\t__u8 fc;\n\t\t\t__u8 sel1;\n\t\t\t__u16 sel2;\n\t\t} s390_stsi;\n\t\tstruct {\n\t\t\t__u8 vector;\n\t\t} eoi;\n\t\tstruct kvm_hyperv_exit hyperv;\n\t\tstruct {\n\t\t\t__u64 esr_iss;\n\t\t\t__u64 fault_ipa;\n\t\t} arm_nisv;\n\t\tstruct {\n\t\t\t__u8 error;\n\t\t\t__u8 pad[7];\n\t\t\t__u32 reason;\n\t\t\t__u32 index;\n\t\t\t__u64 data;\n\t\t} msr;\n\t\tstruct kvm_xen_exit xen;\n\t\tchar padding[256];\n\t};\n\t__u64 kvm_valid_regs;\n\t__u64 kvm_dirty_regs;\n\tunion {\n\t\tstruct kvm_sync_regs regs;\n\t\tchar padding[2048];\n\t} s;\n};\n\nstruct kvm_coalesced_mmio {\n\t__u64 phys_addr;\n\t__u32 len;\n\tunion {\n\t\t__u32 pad;\n\t\t__u32 pio;\n\t};\n\t__u8 data[8];\n};\n\nstruct kvm_coalesced_mmio_ring {\n\t__u32 first;\n\t__u32 last;\n\tstruct kvm_coalesced_mmio coalesced_mmio[0];\n};\n\nstruct kvm_xen_hvm_config {\n\t__u32 flags;\n\t__u32 msr;\n\t__u64 blob_addr_32;\n\t__u64 blob_addr_64;\n\t__u8 blob_size_32;\n\t__u8 blob_size_64;\n\t__u8 pad2[30];\n};\n\nstruct kvm_enc_region {\n\t__u64 addr;\n\t__u64 size;\n};\n\nstruct kvm_dirty_gfn {\n\t__u32 flags;\n\t__u32 slot;\n\t__u64 offset;\n};\n\nstruct kvm_stats_desc {\n\t__u32 flags;\n\t__s16 exponent;\n\t__u16 size;\n\t__u32 offset;\n\t__u32 unused;\n\tchar name[0];\n};\n\ntypedef long unsigned int gva_t;\n\ntypedef u64 gpa_t;\n\ntypedef u64 gfn_t;\n\ntypedef u64 hpa_t;\n\ntypedef u64 hfn_t;\n\ntypedef hfn_t kvm_pfn_t;\n\nstruct kvm_memory_slot;\n\nstruct gfn_to_hva_cache {\n\tu64 generation;\n\tgpa_t gpa;\n\tlong unsigned int hva;\n\tlong unsigned int len;\n\tstruct kvm_memory_slot *memslot;\n};\n\nstruct kvm_rmap_head;\n\nstruct kvm_lpage_info;\n\nstruct kvm_arch_memory_slot {\n\tstruct kvm_rmap_head *rmap[3];\n\tstruct kvm_lpage_info *lpage_info[2];\n\tshort unsigned int *gfn_track[1];\n};\n\nstruct kvm_memory_slot {\n\tgfn_t base_gfn;\n\tlong unsigned int npages;\n\tlong unsigned int *dirty_bitmap;\n\tstruct kvm_arch_memory_slot arch;\n\tlong unsigned int userspace_addr;\n\tu32 flags;\n\tshort int id;\n\tu16 as_id;\n};\n\nstruct gfn_to_pfn_cache {\n\tu64 generation;\n\tgfn_t gfn;\n\tkvm_pfn_t pfn;\n\tbool dirty;\n};\n\nstruct kvm_mmu_memory_cache {\n\tint nobjs;\n\tgfp_t gfp_zero;\n\tstruct kmem_cache *kmem_cache;\n\tvoid *objects[40];\n};\n\nstruct kvm_vm_stat_generic {\n\tu64 remote_tlb_flush;\n};\n\nstruct kvm_vcpu_stat_generic {\n\tu64 halt_successful_poll;\n\tu64 halt_attempted_poll;\n\tu64 halt_poll_invalid;\n\tu64 halt_wakeup;\n\tu64 halt_poll_success_ns;\n\tu64 halt_poll_fail_ns;\n};\n\nstruct hv_partition_assist_pg {\n\tu32 tlb_lock_count;\n};\n\nunion hv_message_flags {\n\t__u8 asu8;\n\tstruct {\n\t\t__u8 msg_pending: 1;\n\t\t__u8 reserved: 7;\n\t};\n};\n\nunion hv_port_id {\n\t__u32 asu32;\n\tstruct {\n\t\t__u32 id: 24;\n\t\t__u32 reserved: 8;\n\t} u;\n};\n\nstruct hv_message_header {\n\t__u32 message_type;\n\t__u8 payload_size;\n\tunion hv_message_flags message_flags;\n\t__u8 reserved[2];\n\tunion {\n\t\t__u64 sender;\n\t\tunion hv_port_id port;\n\t};\n};\n\nstruct hv_message {\n\tstruct hv_message_header header;\n\tunion {\n\t\t__u64 payload[30];\n\t} u;\n};\n\nunion hv_stimer_config {\n\tu64 as_uint64;\n\tstruct {\n\t\tu64 enable: 1;\n\t\tu64 periodic: 1;\n\t\tu64 lazy: 1;\n\t\tu64 auto_enable: 1;\n\t\tu64 apic_vector: 8;\n\t\tu64 direct_mode: 1;\n\t\tu64 reserved_z0: 3;\n\t\tu64 sintx: 4;\n\t\tu64 reserved_z1: 44;\n\t};\n};\n\nenum kvm_page_track_mode {\n\tKVM_PAGE_TRACK_WRITE = 0,\n\tKVM_PAGE_TRACK_MAX = 1,\n};\n\nstruct kvm_page_track_notifier_head {\n\tstruct srcu_struct track_srcu;\n\tstruct hlist_head track_notifier_list;\n};\n\nstruct kvm_vcpu;\n\nstruct kvm;\n\nstruct kvm_page_track_notifier_node {\n\tstruct hlist_node node;\n\tvoid (*track_write)(struct kvm_vcpu *, gpa_t, const u8 *, int, struct kvm_page_track_notifier_node *);\n\tvoid (*track_flush_slot)(struct kvm *, struct kvm_memory_slot *, struct kvm_page_track_notifier_node *);\n};\n\nstruct kvm_mmio_fragment {\n\tgpa_t gpa;\n\tvoid *data;\n\tunsigned int len;\n};\n\nstruct kvm_lapic;\n\nstruct x86_exception;\n\nstruct kvm_mmu_page;\n\nunion kvm_mmu_page_role {\n\tu32 word;\n\tstruct {\n\t\tunsigned int level: 4;\n\t\tunsigned int gpte_is_8_bytes: 1;\n\t\tunsigned int quadrant: 2;\n\t\tunsigned int direct: 1;\n\t\tunsigned int access: 3;\n\t\tunsigned int invalid: 1;\n\t\tunsigned int efer_nx: 1;\n\t\tunsigned int cr0_wp: 1;\n\t\tunsigned int smep_andnot_wp: 1;\n\t\tunsigned int smap_andnot_wp: 1;\n\t\tunsigned int ad_disabled: 1;\n\t\tunsigned int guest_mode: 1;\n\t\tchar: 6;\n\t\tunsigned int smm: 8;\n\t};\n};\n\nunion kvm_mmu_extended_role {\n\tu32 word;\n\tstruct {\n\t\tunsigned int valid: 1;\n\t\tunsigned int execonly: 1;\n\t\tunsigned int cr0_pg: 1;\n\t\tunsigned int cr4_pae: 1;\n\t\tunsigned int cr4_pse: 1;\n\t\tunsigned int cr4_pke: 1;\n\t\tunsigned int cr4_smap: 1;\n\t\tunsigned int cr4_smep: 1;\n\t\tunsigned int cr4_la57: 1;\n\t};\n};\n\nunion kvm_mmu_role {\n\tu64 as_u64;\n\tstruct {\n\t\tunion kvm_mmu_page_role base;\n\t\tunion kvm_mmu_extended_role ext;\n\t};\n};\n\nstruct kvm_mmu_root_info {\n\tgpa_t pgd;\n\thpa_t hpa;\n};\n\nstruct rsvd_bits_validate {\n\tu64 rsvd_bits_mask[10];\n\tu64 bad_mt_xwr;\n};\n\nstruct kvm_mmu {\n\tlong unsigned int (*get_guest_pgd)(struct kvm_vcpu *);\n\tu64 (*get_pdptr)(struct kvm_vcpu *, int);\n\tint (*page_fault)(struct kvm_vcpu *, gpa_t, u32, bool);\n\tvoid (*inject_page_fault)(struct kvm_vcpu *, struct x86_exception *);\n\tgpa_t (*gva_to_gpa)(struct kvm_vcpu *, gpa_t, u32, struct x86_exception *);\n\tgpa_t (*translate_gpa)(struct kvm_vcpu *, gpa_t, u32, struct x86_exception *);\n\tint (*sync_page)(struct kvm_vcpu *, struct kvm_mmu_page *);\n\tvoid (*invlpg)(struct kvm_vcpu *, gva_t, hpa_t);\n\thpa_t root_hpa;\n\tgpa_t root_pgd;\n\tunion kvm_mmu_role mmu_role;\n\tu8 root_level;\n\tu8 shadow_root_level;\n\tu8 ept_ad;\n\tbool direct_map;\n\tstruct kvm_mmu_root_info prev_roots[3];\n\tu8 permissions[16];\n\tu32 pkru_mask;\n\tu64 *pae_root;\n\tu64 *pml4_root;\n\tstruct rsvd_bits_validate shadow_zero_check;\n\tstruct rsvd_bits_validate guest_rsvd_check;\n\tu64 pdptrs[4];\n};\n\nstruct kvm_pio_request {\n\tlong unsigned int linear_rip;\n\tlong unsigned int count;\n\tint in;\n\tint port;\n\tint size;\n};\n\nstruct kvm_queued_exception {\n\tbool pending;\n\tbool injected;\n\tbool has_error_code;\n\tu8 nr;\n\tu32 error_code;\n\tlong unsigned int payload;\n\tbool has_payload;\n\tu8 nested_apf;\n};\n\nstruct kvm_queued_interrupt {\n\tbool injected;\n\tbool soft;\n\tu8 nr;\n};\n\nstruct x86_emulate_ctxt;\n\nstruct kvm_mtrr_range {\n\tu64 base;\n\tu64 mask;\n\tstruct list_head node;\n};\n\nstruct kvm_mtrr {\n\tstruct kvm_mtrr_range var_ranges[8];\n\tmtrr_type fixed_ranges[88];\n\tu64 deftype;\n\tstruct list_head head;\n};\n\nenum pmc_type {\n\tKVM_PMC_GP = 0,\n\tKVM_PMC_FIXED = 1,\n};\n\nstruct kvm_pmc {\n\tenum pmc_type type;\n\tu8 idx;\n\tu64 counter;\n\tu64 eventsel;\n\tstruct perf_event *perf_event;\n\tstruct kvm_vcpu *vcpu;\n\tu64 current_config;\n};\n\nstruct kvm_pmu {\n\tunsigned int nr_arch_gp_counters;\n\tunsigned int nr_arch_fixed_counters;\n\tunsigned int available_event_types;\n\tu64 fixed_ctr_ctrl;\n\tu64 global_ctrl;\n\tu64 global_status;\n\tu64 global_ovf_ctrl;\n\tu64 counter_bitmask[2];\n\tu64 global_ctrl_mask;\n\tu64 global_ovf_ctrl_mask;\n\tu64 reserved_bits;\n\tu8 version;\n\tstruct kvm_pmc gp_counters[32];\n\tstruct kvm_pmc fixed_counters[4];\n\tstruct irq_work irq_work;\n\tlong unsigned int reprogram_pmi[1];\n\tlong unsigned int all_valid_pmc_idx[1];\n\tlong unsigned int pmc_in_use[1];\n\tbool need_cleanup;\n\tu8 event_count;\n};\n\nstruct kvm_vcpu_xen {\n\tu64 hypercall_rip;\n\tu32 current_runstate;\n\tbool vcpu_info_set;\n\tbool vcpu_time_info_set;\n\tbool runstate_set;\n\tstruct gfn_to_hva_cache vcpu_info_cache;\n\tstruct gfn_to_hva_cache vcpu_time_info_cache;\n\tstruct gfn_to_hva_cache runstate_cache;\n\tu64 last_steal;\n\tu64 runstate_entry_time;\n\tu64 runstate_times[4];\n};\n\nstruct kvm_vcpu_hv;\n\nstruct kvm_vcpu_arch {\n\tlong unsigned int regs[17];\n\tu32 regs_avail;\n\tu32 regs_dirty;\n\tlong unsigned int cr0;\n\tlong unsigned int cr0_guest_owned_bits;\n\tlong unsigned int cr2;\n\tlong unsigned int cr3;\n\tlong unsigned int cr4;\n\tlong unsigned int cr4_guest_owned_bits;\n\tlong unsigned int cr4_guest_rsvd_bits;\n\tlong unsigned int cr8;\n\tu32 host_pkru;\n\tu32 pkru;\n\tu32 hflags;\n\tu64 efer;\n\tu64 apic_base;\n\tstruct kvm_lapic *apic;\n\tbool apicv_active;\n\tbool load_eoi_exitmap_pending;\n\tlong unsigned int ioapic_handled_vectors[4];\n\tlong unsigned int apic_attention;\n\tint32_t apic_arb_prio;\n\tint mp_state;\n\tu64 ia32_misc_enable_msr;\n\tu64 smbase;\n\tu64 smi_count;\n\tbool tpr_access_reporting;\n\tbool xsaves_enabled;\n\tu64 ia32_xss;\n\tu64 microcode_version;\n\tu64 arch_capabilities;\n\tu64 perf_capabilities;\n\tstruct kvm_mmu *mmu;\n\tstruct kvm_mmu root_mmu;\n\tstruct kvm_mmu guest_mmu;\n\tstruct kvm_mmu nested_mmu;\n\tstruct kvm_mmu *walk_mmu;\n\tstruct kvm_mmu_memory_cache mmu_pte_list_desc_cache;\n\tstruct kvm_mmu_memory_cache mmu_shadow_page_cache;\n\tstruct kvm_mmu_memory_cache mmu_gfn_array_cache;\n\tstruct kvm_mmu_memory_cache mmu_page_header_cache;\n\tstruct fpu *user_fpu;\n\tstruct fpu *guest_fpu;\n\tu64 xcr0;\n\tu64 guest_supported_xcr0;\n\tstruct kvm_pio_request pio;\n\tvoid *pio_data;\n\tvoid *guest_ins_data;\n\tu8 event_exit_inst_len;\n\tstruct kvm_queued_exception exception;\n\tstruct kvm_queued_interrupt interrupt;\n\tint halt_request;\n\tint cpuid_nent;\n\tstruct kvm_cpuid_entry2 *cpuid_entries;\n\tu64 reserved_gpa_bits;\n\tint maxphyaddr;\n\tint max_tdp_level;\n\tstruct x86_emulate_ctxt *emulate_ctxt;\n\tbool emulate_regs_need_sync_to_vcpu;\n\tbool emulate_regs_need_sync_from_vcpu;\n\tint (*complete_userspace_io)(struct kvm_vcpu *);\n\tgpa_t time;\n\tstruct pvclock_vcpu_time_info hv_clock;\n\tunsigned int hw_tsc_khz;\n\tstruct gfn_to_hva_cache pv_time;\n\tbool pv_time_enabled;\n\tbool pvclock_set_guest_stopped_request;\n\tstruct {\n\t\tu8 preempted;\n\t\tu64 msr_val;\n\t\tu64 last_steal;\n\t\tstruct gfn_to_pfn_cache cache;\n\t} st;\n\tu64 l1_tsc_offset;\n\tu64 tsc_offset;\n\tu64 last_guest_tsc;\n\tu64 last_host_tsc;\n\tu64 tsc_offset_adjustment;\n\tu64 this_tsc_nsec;\n\tu64 this_tsc_write;\n\tu64 this_tsc_generation;\n\tbool tsc_catchup;\n\tbool tsc_always_catchup;\n\ts8 virtual_tsc_shift;\n\tu32 virtual_tsc_mult;\n\tu32 virtual_tsc_khz;\n\ts64 ia32_tsc_adjust_msr;\n\tu64 msr_ia32_power_ctl;\n\tu64 l1_tsc_scaling_ratio;\n\tu64 tsc_scaling_ratio;\n\tatomic_t nmi_queued;\n\tunsigned int nmi_pending;\n\tbool nmi_injected;\n\tbool smi_pending;\n\tstruct kvm_mtrr mtrr_state;\n\tu64 pat;\n\tunsigned int switch_db_regs;\n\tlong unsigned int db[4];\n\tlong unsigned int dr6;\n\tlong unsigned int dr7;\n\tlong unsigned int eff_db[4];\n\tlong unsigned int guest_debug_dr7;\n\tu64 msr_platform_info;\n\tu64 msr_misc_features_enables;\n\tu64 mcg_cap;\n\tu64 mcg_status;\n\tu64 mcg_ctl;\n\tu64 mcg_ext_ctl;\n\tu64 *mce_banks;\n\tu64 mmio_gva;\n\tunsigned int mmio_access;\n\tgfn_t mmio_gfn;\n\tu64 mmio_gen;\n\tstruct kvm_pmu pmu;\n\tlong unsigned int singlestep_rip;\n\tbool hyperv_enabled;\n\tstruct kvm_vcpu_hv *hyperv;\n\tstruct kvm_vcpu_xen xen;\n\tcpumask_var_t wbinvd_dirty_mask;\n\tlong unsigned int last_retry_eip;\n\tlong unsigned int last_retry_addr;\n\tstruct {\n\t\tbool halted;\n\t\tgfn_t gfns[64];\n\t\tstruct gfn_to_hva_cache data;\n\t\tu64 msr_en_val;\n\t\tu64 msr_int_val;\n\t\tu16 vec;\n\t\tu32 id;\n\t\tbool send_user_only;\n\t\tu32 host_apf_flags;\n\t\tlong unsigned int nested_apf_token;\n\t\tbool delivery_as_pf_vmexit;\n\t\tbool pageready_pending;\n\t} apf;\n\tstruct {\n\t\tu64 length;\n\t\tu64 status;\n\t} osvw;\n\tstruct {\n\t\tu64 msr_val;\n\t\tstruct gfn_to_hva_cache data;\n\t} pv_eoi;\n\tu64 msr_kvm_poll_control;\n\tbool write_fault_to_shadow_pgtable;\n\tlong unsigned int exit_qualification;\n\tstruct {\n\t\tbool pv_unhalted;\n\t} pv;\n\tint pending_ioapic_eoi;\n\tint pending_external_vector;\n\tbool preempted_in_kernel;\n\tbool l1tf_flush_l1d;\n\tint last_vmentry_cpu;\n\tu64 msr_hwcr;\n\tstruct {\n\t\tu32 features;\n\t\tbool enforce;\n\t} pv_cpuid;\n\tbool guest_state_protected;\n\tbool pdptrs_from_userspace;\n\thpa_t hv_root_tdp;\n};\n\nstruct kvm_vcpu_stat {\n\tstruct kvm_vcpu_stat_generic generic;\n\tu64 pf_fixed;\n\tu64 pf_guest;\n\tu64 tlb_flush;\n\tu64 invlpg;\n\tu64 exits;\n\tu64 io_exits;\n\tu64 mmio_exits;\n\tu64 signal_exits;\n\tu64 irq_window_exits;\n\tu64 nmi_window_exits;\n\tu64 l1d_flush;\n\tu64 halt_exits;\n\tu64 request_irq_exits;\n\tu64 irq_exits;\n\tu64 host_state_reload;\n\tu64 fpu_reload;\n\tu64 insn_emulation;\n\tu64 insn_emulation_fail;\n\tu64 hypercalls;\n\tu64 irq_injections;\n\tu64 nmi_injections;\n\tu64 req_event;\n\tu64 nested_run;\n\tu64 directed_yield_attempted;\n\tu64 directed_yield_successful;\n\tu64 guest_mode;\n};\n\nstruct kvm_dirty_ring {\n\tu32 dirty_index;\n\tu32 reset_index;\n\tu32 size;\n\tu32 soft_limit;\n\tstruct kvm_dirty_gfn *dirty_gfns;\n\tint index;\n};\n\nstruct kvm_vcpu {\n\tstruct kvm *kvm;\n\tstruct preempt_notifier preempt_notifier;\n\tint cpu;\n\tint vcpu_id;\n\tint vcpu_idx;\n\tint srcu_idx;\n\tint mode;\n\tu64 requests;\n\tlong unsigned int guest_debug;\n\tint pre_pcpu;\n\tstruct list_head blocked_vcpu_list;\n\tstruct mutex mutex;\n\tstruct kvm_run *run;\n\tstruct rcuwait wait;\n\tstruct pid *pid;\n\tint sigset_active;\n\tsigset_t sigset;\n\tunsigned int halt_poll_ns;\n\tbool valid_wakeup;\n\tint mmio_needed;\n\tint mmio_read_completed;\n\tint mmio_is_write;\n\tint mmio_cur_fragment;\n\tint mmio_nr_fragments;\n\tstruct kvm_mmio_fragment mmio_fragments[2];\n\tstruct {\n\t\tu32 queued;\n\t\tstruct list_head queue;\n\t\tstruct list_head done;\n\t\tspinlock_t lock;\n\t} async_pf;\n\tstruct {\n\t\tbool in_spin_loop;\n\t\tbool dy_eligible;\n\t} spin_loop;\n\tbool preempted;\n\tbool ready;\n\tstruct kvm_vcpu_arch arch;\n\tstruct kvm_vcpu_stat stat;\n\tchar stats_id[48];\n\tstruct kvm_dirty_ring dirty_ring;\n};\n\nstruct kvm_vm_stat {\n\tstruct kvm_vm_stat_generic generic;\n\tu64 mmu_shadow_zapped;\n\tu64 mmu_pte_write;\n\tu64 mmu_pde_zapped;\n\tu64 mmu_flooded;\n\tu64 mmu_recycled;\n\tu64 mmu_cache_miss;\n\tu64 mmu_unsync;\n\tu64 lpages;\n\tu64 nx_lpage_splits;\n\tu64 max_mmu_page_hash_collisions;\n};\n\nstruct kvm_pic;\n\nstruct kvm_ioapic;\n\nstruct kvm_pit;\n\nenum hv_tsc_page_status {\n\tHV_TSC_PAGE_UNSET = 0,\n\tHV_TSC_PAGE_GUEST_CHANGED = 1,\n\tHV_TSC_PAGE_HOST_CHANGED = 2,\n\tHV_TSC_PAGE_SET = 3,\n\tHV_TSC_PAGE_UPDATING = 4,\n\tHV_TSC_PAGE_BROKEN = 5,\n};\n\nstruct kvm_hv_syndbg {\n\tstruct {\n\t\tu64 control;\n\t\tu64 status;\n\t\tu64 send_page;\n\t\tu64 recv_page;\n\t\tu64 pending_page;\n\t} control;\n\tu64 options;\n};\n\nstruct kvm_hv {\n\tstruct mutex hv_lock;\n\tu64 hv_guest_os_id;\n\tu64 hv_hypercall;\n\tu64 hv_tsc_page;\n\tenum hv_tsc_page_status hv_tsc_page_status;\n\tu64 hv_crash_param[5];\n\tu64 hv_crash_ctl;\n\tstruct ms_hyperv_tsc_page tsc_ref;\n\tstruct idr conn_to_evt;\n\tu64 hv_reenlightenment_control;\n\tu64 hv_tsc_emulation_control;\n\tu64 hv_tsc_emulation_status;\n\tatomic_t num_mismatched_vp_indexes;\n\tstruct hv_partition_assist_pg *hv_pa_pg;\n\tstruct kvm_hv_syndbg hv_syndbg;\n};\n\nstruct kvm_xen {\n\tbool long_mode;\n\tbool shinfo_set;\n\tu8 upcall_vector;\n\tstruct gfn_to_hva_cache shinfo_cache;\n};\n\nenum kvm_irqchip_mode {\n\tKVM_IRQCHIP_NONE = 0,\n\tKVM_IRQCHIP_KERNEL = 1,\n\tKVM_IRQCHIP_SPLIT = 2,\n};\n\nstruct kvm_apic_map;\n\nstruct kvm_x86_msr_filter;\n\nstruct kvm_arch {\n\tlong unsigned int n_used_mmu_pages;\n\tlong unsigned int n_requested_mmu_pages;\n\tlong unsigned int n_max_mmu_pages;\n\tunsigned int indirect_shadow_pages;\n\tu8 mmu_valid_gen;\n\tstruct hlist_head mmu_page_hash[4096];\n\tstruct list_head active_mmu_pages;\n\tstruct list_head zapped_obsolete_pages;\n\tstruct list_head lpage_disallowed_mmu_pages;\n\tstruct kvm_page_track_notifier_node mmu_sp_tracker;\n\tstruct kvm_page_track_notifier_head track_notifier_head;\n\tspinlock_t mmu_unsync_pages_lock;\n\tstruct list_head assigned_dev_head;\n\tstruct iommu_domain *iommu_domain;\n\tbool iommu_noncoherent;\n\tatomic_t noncoherent_dma_count;\n\tatomic_t assigned_device_count;\n\tstruct kvm_pic *vpic;\n\tstruct kvm_ioapic *vioapic;\n\tstruct kvm_pit *vpit;\n\tatomic_t vapics_in_nmi_mode;\n\tstruct mutex apic_map_lock;\n\tstruct kvm_apic_map *apic_map;\n\tatomic_t apic_map_dirty;\n\tbool apic_access_memslot_enabled;\n\tlong unsigned int apicv_inhibit_reasons;\n\tgpa_t wall_clock;\n\tbool mwait_in_guest;\n\tbool hlt_in_guest;\n\tbool pause_in_guest;\n\tbool cstate_in_guest;\n\tlong unsigned int irq_sources_bitmap;\n\ts64 kvmclock_offset;\n\traw_spinlock_t tsc_write_lock;\n\tu64 last_tsc_nsec;\n\tu64 last_tsc_write;\n\tu32 last_tsc_khz;\n\tu64 cur_tsc_nsec;\n\tu64 cur_tsc_write;\n\tu64 cur_tsc_offset;\n\tu64 cur_tsc_generation;\n\tint nr_vcpus_matched_tsc;\n\tspinlock_t pvclock_gtod_sync_lock;\n\tbool use_master_clock;\n\tu64 master_kernel_ns;\n\tu64 master_cycle_now;\n\tstruct delayed_work kvmclock_update_work;\n\tstruct delayed_work kvmclock_sync_work;\n\tstruct kvm_xen_hvm_config xen_hvm_config;\n\tstruct hlist_head mask_notifier_list;\n\tstruct kvm_hv hyperv;\n\tstruct kvm_xen xen;\n\tint audit_point;\n\tbool backwards_tsc_observed;\n\tbool boot_vcpu_runs_old_kvmclock;\n\tu32 bsp_vcpu_id;\n\tu64 disabled_quirks;\n\tint cpu_dirty_logging_count;\n\tenum kvm_irqchip_mode irqchip_mode;\n\tu8 nr_reserved_ioapic_pins;\n\tbool disabled_lapic_found;\n\tbool x2apic_format;\n\tbool x2apic_broadcast_quirk_disabled;\n\tbool guest_can_read_msr_platform_info;\n\tbool exception_payload_enabled;\n\tbool bus_lock_detection_enabled;\n\tbool exit_on_emulation_error;\n\tu32 user_space_msr_mask;\n\tstruct kvm_x86_msr_filter *msr_filter;\n\tu32 hypercall_exit_enabled;\n\tbool sgx_provisioning_allowed;\n\tstruct kvm_pmu_event_filter *pmu_event_filter;\n\tstruct task_struct *nx_lpage_recovery_thread;\n\tbool tdp_mmu_enabled;\n\tstruct list_head tdp_mmu_roots;\n\tstruct list_head tdp_mmu_pages;\n\tspinlock_t tdp_mmu_pages_lock;\n\tbool memslots_have_rmaps;\n\thpa_t hv_root_tdp;\n\tspinlock_t hv_root_tdp_lock;\n};\n\nstruct kvm_memslots;\n\nstruct kvm_io_bus;\n\nstruct kvm_irq_routing_table;\n\nstruct kvm_stat_data;\n\nstruct kvm {\n\trwlock_t mmu_lock;\n\tstruct mutex slots_lock;\n\tstruct mutex slots_arch_lock;\n\tstruct mm_struct *mm;\n\tstruct kvm_memslots *memslots[2];\n\tstruct kvm_vcpu *vcpus[288];\n\tatomic_t online_vcpus;\n\tint created_vcpus;\n\tint last_boosted_vcpu;\n\tstruct list_head vm_list;\n\tstruct mutex lock;\n\tstruct kvm_io_bus *buses[4];\n\tstruct {\n\t\tspinlock_t lock;\n\t\tstruct list_head items;\n\t\tstruct list_head resampler_list;\n\t\tstruct mutex resampler_lock;\n\t} irqfds;\n\tstruct list_head ioeventfds;\n\tstruct kvm_vm_stat stat;\n\tstruct kvm_arch arch;\n\trefcount_t users_count;\n\tstruct kvm_coalesced_mmio_ring *coalesced_mmio_ring;\n\tspinlock_t ring_lock;\n\tstruct list_head coalesced_zones;\n\tstruct mutex irq_lock;\n\tstruct kvm_irq_routing_table *irq_routing;\n\tstruct hlist_head irq_ack_notifier_list;\n\tstruct mmu_notifier mmu_notifier;\n\tlong unsigned int mmu_notifier_seq;\n\tlong int mmu_notifier_count;\n\tlong unsigned int mmu_notifier_range_start;\n\tlong unsigned int mmu_notifier_range_end;\n\tlong int tlbs_dirty;\n\tstruct list_head devices;\n\tu64 manual_dirty_log_protect;\n\tstruct dentry *debugfs_dentry;\n\tstruct kvm_stat_data **debugfs_stat_data;\n\tstruct srcu_struct srcu;\n\tstruct srcu_struct irq_srcu;\n\tpid_t userspace_pid;\n\tunsigned int max_halt_poll_ns;\n\tu32 dirty_ring_size;\n\tstruct notifier_block pm_notifier;\n\tchar stats_id[48];\n};\n\nenum kvm_reg {\n\tVCPU_REGS_RAX = 0,\n\tVCPU_REGS_RCX = 1,\n\tVCPU_REGS_RDX = 2,\n\tVCPU_REGS_RBX = 3,\n\tVCPU_REGS_RSP = 4,\n\tVCPU_REGS_RBP = 5,\n\tVCPU_REGS_RSI = 6,\n\tVCPU_REGS_RDI = 7,\n\tVCPU_REGS_R8 = 8,\n\tVCPU_REGS_R9 = 9,\n\tVCPU_REGS_R10 = 10,\n\tVCPU_REGS_R11 = 11,\n\tVCPU_REGS_R12 = 12,\n\tVCPU_REGS_R13 = 13,\n\tVCPU_REGS_R14 = 14,\n\tVCPU_REGS_R15 = 15,\n\tVCPU_REGS_RIP = 16,\n\tNR_VCPU_REGS = 17,\n\tVCPU_EXREG_PDPTR = 17,\n\tVCPU_EXREG_CR0 = 18,\n\tVCPU_EXREG_CR3 = 19,\n\tVCPU_EXREG_CR4 = 20,\n\tVCPU_EXREG_RFLAGS = 21,\n\tVCPU_EXREG_SEGMENTS = 22,\n\tVCPU_EXREG_EXIT_INFO_1 = 23,\n\tVCPU_EXREG_EXIT_INFO_2 = 24,\n};\n\nenum exit_fastpath_completion {\n\tEXIT_FASTPATH_NONE = 0,\n\tEXIT_FASTPATH_REENTER_GUEST = 1,\n\tEXIT_FASTPATH_EXIT_HANDLED = 2,\n};\n\nstruct kvm_rmap_head {\n\tlong unsigned int val;\n};\n\nstruct kvm_tlb_range {\n\tu64 start_gfn;\n\tu64 pages;\n};\n\nstruct kvm_vcpu_hv_stimer {\n\tstruct hrtimer timer;\n\tint index;\n\tunion hv_stimer_config config;\n\tu64 count;\n\tu64 exp_time;\n\tstruct hv_message msg;\n\tbool msg_pending;\n};\n\nstruct kvm_vcpu_hv_synic {\n\tu64 version;\n\tu64 control;\n\tu64 msg_page;\n\tu64 evt_page;\n\tatomic64_t sint[16];\n\tatomic_t sint_to_gsi[16];\n\tlong unsigned int auto_eoi_bitmap[4];\n\tlong unsigned int vec_bitmap[4];\n\tbool active;\n\tbool dont_zero_synic_pages;\n};\n\nstruct kvm_vcpu_hv {\n\tstruct kvm_vcpu *vcpu;\n\tu32 vp_index;\n\tu64 hv_vapic;\n\ts64 runtime_offset;\n\tstruct kvm_vcpu_hv_synic synic;\n\tstruct kvm_hyperv_exit exit;\n\tstruct kvm_vcpu_hv_stimer stimer[4];\n\tlong unsigned int stimer_pending_bitmap[1];\n\tcpumask_t tlb_flush;\n\tbool enforce_cpuid;\n\tstruct {\n\t\tu32 features_eax;\n\t\tu32 features_ebx;\n\t\tu32 features_edx;\n\t\tu32 enlightenments_eax;\n\t\tu32 enlightenments_ebx;\n\t\tu32 syndbg_cap_eax;\n\t} cpuid_cache;\n};\n\nstruct kvm_lpage_info {\n\tint disallow_lpage;\n};\n\nstruct kvm_apic_map {\n\tstruct callback_head rcu;\n\tu8 mode;\n\tu32 max_apic_id;\n\tunion {\n\t\tstruct kvm_lapic *xapic_flat_map[8];\n\t\tstruct kvm_lapic *xapic_cluster_map[64];\n\t};\n\tstruct kvm_lapic *phys_map[0];\n};\n\nstruct msr_bitmap_range {\n\tu32 flags;\n\tu32 nmsrs;\n\tu32 base;\n\tlong unsigned int *bitmap;\n};\n\nstruct kvm_x86_msr_filter {\n\tu8 count;\n\tbool default_allow: 1;\n\tstruct msr_bitmap_range ranges[16];\n};\n\nstruct msr_data {\n\tbool host_initiated;\n\tu32 index;\n\tu64 data;\n};\n\nstruct x86_instruction_info;\n\nenum x86_intercept_stage;\n\nstruct kvm_pmu_ops;\n\nstruct kvm_x86_nested_ops;\n\nstruct kvm_x86_ops {\n\tint (*hardware_enable)();\n\tvoid (*hardware_disable)();\n\tvoid (*hardware_unsetup)();\n\tbool (*cpu_has_accelerated_tpr)();\n\tbool (*has_emulated_msr)(struct kvm *, u32);\n\tvoid (*vcpu_after_set_cpuid)(struct kvm_vcpu *);\n\tunsigned int vm_size;\n\tint (*vm_init)(struct kvm *);\n\tvoid (*vm_destroy)(struct kvm *);\n\tint (*vcpu_create)(struct kvm_vcpu *);\n\tvoid (*vcpu_free)(struct kvm_vcpu *);\n\tvoid (*vcpu_reset)(struct kvm_vcpu *, bool);\n\tvoid (*prepare_guest_switch)(struct kvm_vcpu *);\n\tvoid (*vcpu_load)(struct kvm_vcpu *, int);\n\tvoid (*vcpu_put)(struct kvm_vcpu *);\n\tvoid (*update_exception_bitmap)(struct kvm_vcpu *);\n\tint (*get_msr)(struct kvm_vcpu *, struct msr_data *);\n\tint (*set_msr)(struct kvm_vcpu *, struct msr_data *);\n\tu64 (*get_segment_base)(struct kvm_vcpu *, int);\n\tvoid (*get_segment)(struct kvm_vcpu *, struct kvm_segment *, int);\n\tint (*get_cpl)(struct kvm_vcpu *);\n\tvoid (*set_segment)(struct kvm_vcpu *, struct kvm_segment *, int);\n\tvoid (*get_cs_db_l_bits)(struct kvm_vcpu *, int *, int *);\n\tvoid (*set_cr0)(struct kvm_vcpu *, long unsigned int);\n\tbool (*is_valid_cr4)(struct kvm_vcpu *, long unsigned int);\n\tvoid (*set_cr4)(struct kvm_vcpu *, long unsigned int);\n\tint (*set_efer)(struct kvm_vcpu *, u64);\n\tvoid (*get_idt)(struct kvm_vcpu *, struct desc_ptr *);\n\tvoid (*set_idt)(struct kvm_vcpu *, struct desc_ptr *);\n\tvoid (*get_gdt)(struct kvm_vcpu *, struct desc_ptr *);\n\tvoid (*set_gdt)(struct kvm_vcpu *, struct desc_ptr *);\n\tvoid (*sync_dirty_debug_regs)(struct kvm_vcpu *);\n\tvoid (*set_dr7)(struct kvm_vcpu *, long unsigned int);\n\tvoid (*cache_reg)(struct kvm_vcpu *, enum kvm_reg);\n\tlong unsigned int (*get_rflags)(struct kvm_vcpu *);\n\tvoid (*set_rflags)(struct kvm_vcpu *, long unsigned int);\n\tvoid (*tlb_flush_all)(struct kvm_vcpu *);\n\tvoid (*tlb_flush_current)(struct kvm_vcpu *);\n\tint (*tlb_remote_flush)(struct kvm *);\n\tint (*tlb_remote_flush_with_range)(struct kvm *, struct kvm_tlb_range *);\n\tvoid (*tlb_flush_gva)(struct kvm_vcpu *, gva_t);\n\tvoid (*tlb_flush_guest)(struct kvm_vcpu *);\n\tenum exit_fastpath_completion (*run)(struct kvm_vcpu *);\n\tint (*handle_exit)(struct kvm_vcpu *, enum exit_fastpath_completion);\n\tint (*skip_emulated_instruction)(struct kvm_vcpu *);\n\tvoid (*update_emulated_instruction)(struct kvm_vcpu *);\n\tvoid (*set_interrupt_shadow)(struct kvm_vcpu *, int);\n\tu32 (*get_interrupt_shadow)(struct kvm_vcpu *);\n\tvoid (*patch_hypercall)(struct kvm_vcpu *, unsigned char *);\n\tvoid (*set_irq)(struct kvm_vcpu *);\n\tvoid (*set_nmi)(struct kvm_vcpu *);\n\tvoid (*queue_exception)(struct kvm_vcpu *);\n\tvoid (*cancel_injection)(struct kvm_vcpu *);\n\tint (*interrupt_allowed)(struct kvm_vcpu *, bool);\n\tint (*nmi_allowed)(struct kvm_vcpu *, bool);\n\tbool (*get_nmi_mask)(struct kvm_vcpu *);\n\tvoid (*set_nmi_mask)(struct kvm_vcpu *, bool);\n\tvoid (*enable_nmi_window)(struct kvm_vcpu *);\n\tvoid (*enable_irq_window)(struct kvm_vcpu *);\n\tvoid (*update_cr8_intercept)(struct kvm_vcpu *, int, int);\n\tbool (*check_apicv_inhibit_reasons)(ulong);\n\tvoid (*pre_update_apicv_exec_ctrl)(struct kvm *, bool);\n\tvoid (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *);\n\tvoid (*hwapic_irr_update)(struct kvm_vcpu *, int);\n\tvoid (*hwapic_isr_update)(struct kvm_vcpu *, int);\n\tbool (*guest_apic_has_interrupt)(struct kvm_vcpu *);\n\tvoid (*load_eoi_exitmap)(struct kvm_vcpu *, u64 *);\n\tvoid (*set_virtual_apic_mode)(struct kvm_vcpu *);\n\tvoid (*set_apic_access_page_addr)(struct kvm_vcpu *);\n\tint (*deliver_posted_interrupt)(struct kvm_vcpu *, int);\n\tint (*sync_pir_to_irr)(struct kvm_vcpu *);\n\tint (*set_tss_addr)(struct kvm *, unsigned int);\n\tint (*set_identity_map_addr)(struct kvm *, u64);\n\tu64 (*get_mt_mask)(struct kvm_vcpu *, gfn_t, bool);\n\tvoid (*load_mmu_pgd)(struct kvm_vcpu *, hpa_t, int);\n\tbool (*has_wbinvd_exit)();\n\tu64 (*get_l2_tsc_offset)(struct kvm_vcpu *);\n\tu64 (*get_l2_tsc_multiplier)(struct kvm_vcpu *);\n\tvoid (*write_tsc_offset)(struct kvm_vcpu *, u64);\n\tvoid (*write_tsc_multiplier)(struct kvm_vcpu *, u64);\n\tvoid (*get_exit_info)(struct kvm_vcpu *, u64 *, u64 *, u32 *, u32 *);\n\tint (*check_intercept)(struct kvm_vcpu *, struct x86_instruction_info *, enum x86_intercept_stage, struct x86_exception *);\n\tvoid (*handle_exit_irqoff)(struct kvm_vcpu *);\n\tvoid (*request_immediate_exit)(struct kvm_vcpu *);\n\tvoid (*sched_in)(struct kvm_vcpu *, int);\n\tint cpu_dirty_log_size;\n\tvoid (*update_cpu_dirty_logging)(struct kvm_vcpu *);\n\tconst struct kvm_pmu_ops *pmu_ops;\n\tconst struct kvm_x86_nested_ops *nested_ops;\n\tint (*pre_block)(struct kvm_vcpu *);\n\tvoid (*post_block)(struct kvm_vcpu *);\n\tvoid (*vcpu_blocking)(struct kvm_vcpu *);\n\tvoid (*vcpu_unblocking)(struct kvm_vcpu *);\n\tint (*update_pi_irte)(struct kvm *, unsigned int, uint32_t, bool);\n\tvoid (*start_assignment)(struct kvm *);\n\tvoid (*apicv_post_state_restore)(struct kvm_vcpu *);\n\tbool (*dy_apicv_has_pending_interrupt)(struct kvm_vcpu *);\n\tint (*set_hv_timer)(struct kvm_vcpu *, u64, bool *);\n\tvoid (*cancel_hv_timer)(struct kvm_vcpu *);\n\tvoid (*setup_mce)(struct kvm_vcpu *);\n\tint (*smi_allowed)(struct kvm_vcpu *, bool);\n\tint (*enter_smm)(struct kvm_vcpu *, char *);\n\tint (*leave_smm)(struct kvm_vcpu *, const char *);\n\tvoid (*enable_smi_window)(struct kvm_vcpu *);\n\tint (*mem_enc_op)(struct kvm *, void *);\n\tint (*mem_enc_reg_region)(struct kvm *, struct kvm_enc_region *);\n\tint (*mem_enc_unreg_region)(struct kvm *, struct kvm_enc_region *);\n\tint (*vm_copy_enc_context_from)(struct kvm *, unsigned int);\n\tint (*get_msr_feature)(struct kvm_msr_entry *);\n\tbool (*can_emulate_instruction)(struct kvm_vcpu *, void *, int);\n\tbool (*apic_init_signal_blocked)(struct kvm_vcpu *);\n\tint (*enable_direct_tlbflush)(struct kvm_vcpu *);\n\tvoid (*migrate_timers)(struct kvm_vcpu *);\n\tvoid (*msr_filter_changed)(struct kvm_vcpu *);\n\tint (*complete_emulated_msr)(struct kvm_vcpu *, int);\n\tvoid (*vcpu_deliver_sipi_vector)(struct kvm_vcpu *, u8);\n};\n\nstruct kvm_x86_nested_ops {\n\tint (*check_events)(struct kvm_vcpu *);\n\tbool (*hv_timer_pending)(struct kvm_vcpu *);\n\tvoid (*triple_fault)(struct kvm_vcpu *);\n\tint (*get_state)(struct kvm_vcpu *, struct kvm_nested_state *, unsigned int);\n\tint (*set_state)(struct kvm_vcpu *, struct kvm_nested_state *, struct kvm_nested_state *);\n\tbool (*get_nested_state_pages)(struct kvm_vcpu *);\n\tint (*write_log_dirty)(struct kvm_vcpu *, gpa_t);\n\tint (*enable_evmcs)(struct kvm_vcpu *, uint16_t *);\n\tuint16_t (*get_evmcs_version)(struct kvm_vcpu *);\n};\n\nstruct kvm_io_device;\n\nstruct kvm_io_range {\n\tgpa_t addr;\n\tint len;\n\tstruct kvm_io_device *dev;\n};\n\nstruct kvm_io_bus {\n\tint dev_count;\n\tint ioeventfd_count;\n\tstruct kvm_io_range range[0];\n};\n\nenum kvm_bus {\n\tKVM_MMIO_BUS = 0,\n\tKVM_PIO_BUS = 1,\n\tKVM_VIRTIO_CCW_NOTIFY_BUS = 2,\n\tKVM_FAST_MMIO_BUS = 3,\n\tKVM_NR_BUSES = 4,\n};\n\nstruct kvm_irq_routing_table {\n\tint chip[72];\n\tu32 nr_rt_entries;\n\tstruct hlist_head map[0];\n};\n\nstruct kvm_memslots {\n\tu64 generation;\n\tshort int id_to_index[32767];\n\tatomic_t lru_slot;\n\tint used_slots;\n\tstruct kvm_memory_slot memslots[0];\n};\n\nenum kvm_stat_kind {\n\tKVM_STAT_VM = 0,\n\tKVM_STAT_VCPU = 1,\n};\n\nstruct _kvm_stats_desc;\n\nstruct kvm_stat_data {\n\tstruct kvm *kvm;\n\tconst struct _kvm_stats_desc *desc;\n\tenum kvm_stat_kind kind;\n};\n\nstruct _kvm_stats_desc {\n\tstruct kvm_stats_desc desc;\n\tchar name[48];\n};\n\nenum kcmp_type {\n\tKCMP_FILE = 0,\n\tKCMP_VM = 1,\n\tKCMP_FILES = 2,\n\tKCMP_FS = 3,\n\tKCMP_SIGHAND = 4,\n\tKCMP_IO = 5,\n\tKCMP_SYSVSEM = 6,\n\tKCMP_EPOLL_TFD = 7,\n\tKCMP_TYPES = 8,\n};\n\nstruct kcmp_epoll_slot {\n\t__u32 efd;\n\t__u32 tfd;\n\t__u32 toff;\n};\n\nenum profile_type {\n\tPROFILE_TASK_EXIT = 0,\n\tPROFILE_MUNMAP = 1,\n};\n\nstruct profile_hit {\n\tu32 pc;\n\tu32 hits;\n};\n\nstruct stacktrace_cookie {\n\tlong unsigned int *store;\n\tunsigned int size;\n\tunsigned int skip;\n\tunsigned int len;\n};\n\ntypedef __kernel_long_t __kernel_suseconds_t;\n\ntypedef __kernel_long_t __kernel_old_time_t;\n\ntypedef __kernel_suseconds_t suseconds_t;\n\ntypedef __u64 timeu64_t;\n\nstruct __kernel_itimerspec {\n\tstruct __kernel_timespec it_interval;\n\tstruct __kernel_timespec it_value;\n};\n\nstruct timezone {\n\tint tz_minuteswest;\n\tint tz_dsttime;\n};\n\nstruct itimerspec64 {\n\tstruct timespec64 it_interval;\n\tstruct timespec64 it_value;\n};\n\nstruct old_itimerspec32 {\n\tstruct old_timespec32 it_interval;\n\tstruct old_timespec32 it_value;\n};\n\nstruct old_timex32 {\n\tu32 modes;\n\ts32 offset;\n\ts32 freq;\n\ts32 maxerror;\n\ts32 esterror;\n\ts32 status;\n\ts32 constant;\n\ts32 precision;\n\ts32 tolerance;\n\tstruct old_timeval32 time;\n\ts32 tick;\n\ts32 ppsfreq;\n\ts32 jitter;\n\ts32 shift;\n\ts32 stabil;\n\ts32 jitcnt;\n\ts32 calcnt;\n\ts32 errcnt;\n\ts32 stbcnt;\n\ts32 tai;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct __kernel_timex_timeval {\n\t__kernel_time64_t tv_sec;\n\tlong long int tv_usec;\n};\n\nstruct __kernel_timex {\n\tunsigned int modes;\n\tlong long int offset;\n\tlong long int freq;\n\tlong long int maxerror;\n\tlong long int esterror;\n\tint status;\n\tlong long int constant;\n\tlong long int precision;\n\tlong long int tolerance;\n\tstruct __kernel_timex_timeval time;\n\tlong long int tick;\n\tlong long int ppsfreq;\n\tlong long int jitter;\n\tint shift;\n\tlong long int stabil;\n\tlong long int jitcnt;\n\tlong long int calcnt;\n\tlong long int errcnt;\n\tlong long int stbcnt;\n\tint tai;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct trace_event_raw_timer_class {\n\tstruct trace_entry ent;\n\tvoid *timer;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_timer_start {\n\tstruct trace_entry ent;\n\tvoid *timer;\n\tvoid *function;\n\tlong unsigned int expires;\n\tlong unsigned int now;\n\tunsigned int flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_timer_expire_entry {\n\tstruct trace_entry ent;\n\tvoid *timer;\n\tlong unsigned int now;\n\tvoid *function;\n\tlong unsigned int baseclk;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hrtimer_init {\n\tstruct trace_entry ent;\n\tvoid *hrtimer;\n\tclockid_t clockid;\n\tenum hrtimer_mode mode;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hrtimer_start {\n\tstruct trace_entry ent;\n\tvoid *hrtimer;\n\tvoid *function;\n\ts64 expires;\n\ts64 softexpires;\n\tenum hrtimer_mode mode;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hrtimer_expire_entry {\n\tstruct trace_entry ent;\n\tvoid *hrtimer;\n\ts64 now;\n\tvoid *function;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hrtimer_class {\n\tstruct trace_entry ent;\n\tvoid *hrtimer;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_itimer_state {\n\tstruct trace_entry ent;\n\tint which;\n\tlong long unsigned int expires;\n\tlong int value_sec;\n\tlong int value_nsec;\n\tlong int interval_sec;\n\tlong int interval_nsec;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_itimer_expire {\n\tstruct trace_entry ent;\n\tint which;\n\tpid_t pid;\n\tlong long unsigned int now;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_tick_stop {\n\tstruct trace_entry ent;\n\tint success;\n\tint dependency;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_timer_class {};\n\nstruct trace_event_data_offsets_timer_start {};\n\nstruct trace_event_data_offsets_timer_expire_entry {};\n\nstruct trace_event_data_offsets_hrtimer_init {};\n\nstruct trace_event_data_offsets_hrtimer_start {};\n\nstruct trace_event_data_offsets_hrtimer_expire_entry {};\n\nstruct trace_event_data_offsets_hrtimer_class {};\n\nstruct trace_event_data_offsets_itimer_state {};\n\nstruct trace_event_data_offsets_itimer_expire {};\n\nstruct trace_event_data_offsets_tick_stop {};\n\ntypedef void (*btf_trace_timer_init)(void *, struct timer_list *);\n\ntypedef void (*btf_trace_timer_start)(void *, struct timer_list *, long unsigned int, unsigned int);\n\ntypedef void (*btf_trace_timer_expire_entry)(void *, struct timer_list *, long unsigned int);\n\ntypedef void (*btf_trace_timer_expire_exit)(void *, struct timer_list *);\n\ntypedef void (*btf_trace_timer_cancel)(void *, struct timer_list *);\n\ntypedef void (*btf_trace_hrtimer_init)(void *, struct hrtimer *, clockid_t, enum hrtimer_mode);\n\ntypedef void (*btf_trace_hrtimer_start)(void *, struct hrtimer *, enum hrtimer_mode);\n\ntypedef void (*btf_trace_hrtimer_expire_entry)(void *, struct hrtimer *, ktime_t *);\n\ntypedef void (*btf_trace_hrtimer_expire_exit)(void *, struct hrtimer *);\n\ntypedef void (*btf_trace_hrtimer_cancel)(void *, struct hrtimer *);\n\ntypedef void (*btf_trace_itimer_state)(void *, int, const struct itimerspec64 * const, long long unsigned int);\n\ntypedef void (*btf_trace_itimer_expire)(void *, int, struct pid *, long long unsigned int);\n\ntypedef void (*btf_trace_tick_stop)(void *, int, int);\n\nstruct timer_base {\n\traw_spinlock_t lock;\n\tstruct timer_list *running_timer;\n\tlong unsigned int clk;\n\tlong unsigned int next_expiry;\n\tunsigned int cpu;\n\tbool next_expiry_recalc;\n\tbool is_idle;\n\tbool timers_pending;\n\tlong unsigned int pending_map[9];\n\tstruct hlist_head vectors[576];\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct process_timer {\n\tstruct timer_list timer;\n\tstruct task_struct *task;\n};\n\nenum tick_device_mode {\n\tTICKDEV_MODE_PERIODIC = 0,\n\tTICKDEV_MODE_ONESHOT = 1,\n};\n\nstruct tick_device {\n\tstruct clock_event_device *evtdev;\n\tenum tick_device_mode mode;\n};\n\nstruct ktime_timestamps {\n\tu64 mono;\n\tu64 boot;\n\tu64 real;\n};\n\nstruct system_time_snapshot {\n\tu64 cycles;\n\tktime_t real;\n\tktime_t raw;\n\tenum clocksource_ids cs_id;\n\tunsigned int clock_was_set_seq;\n\tu8 cs_was_changed_seq;\n};\n\nstruct system_device_crosststamp {\n\tktime_t device;\n\tktime_t sys_realtime;\n\tktime_t sys_monoraw;\n};\n\nstruct audit_ntp_val {\n\tlong long int oldval;\n\tlong long int newval;\n};\n\nstruct audit_ntp_data {\n\tstruct audit_ntp_val vals[6];\n};\n\nenum timekeeping_adv_mode {\n\tTK_ADV_TICK = 0,\n\tTK_ADV_FREQ = 1,\n};\n\nstruct tk_fast {\n\tseqcount_latch_t seq;\n\tstruct tk_read_base base[2];\n};\n\nstruct rtc_wkalrm {\n\tunsigned char enabled;\n\tunsigned char pending;\n\tstruct rtc_time time;\n};\n\nstruct rtc_class_ops {\n\tint (*ioctl)(struct device *, unsigned int, long unsigned int);\n\tint (*read_time)(struct device *, struct rtc_time *);\n\tint (*set_time)(struct device *, struct rtc_time *);\n\tint (*read_alarm)(struct device *, struct rtc_wkalrm *);\n\tint (*set_alarm)(struct device *, struct rtc_wkalrm *);\n\tint (*proc)(struct device *, struct seq_file *);\n\tint (*alarm_irq_enable)(struct device *, unsigned int);\n\tint (*read_offset)(struct device *, long int *);\n\tint (*set_offset)(struct device *, long int);\n};\n\nstruct rtc_device;\n\nstruct rtc_timer {\n\tstruct timerqueue_node node;\n\tktime_t period;\n\tvoid (*func)(struct rtc_device *);\n\tstruct rtc_device *rtc;\n\tint enabled;\n};\n\nstruct rtc_device {\n\tstruct device dev;\n\tstruct module *owner;\n\tint id;\n\tconst struct rtc_class_ops *ops;\n\tstruct mutex ops_lock;\n\tstruct cdev char_dev;\n\tlong unsigned int flags;\n\tlong unsigned int irq_data;\n\tspinlock_t irq_lock;\n\twait_queue_head_t irq_queue;\n\tstruct fasync_struct *async_queue;\n\tint irq_freq;\n\tint max_user_freq;\n\tstruct timerqueue_head timerqueue;\n\tstruct rtc_timer aie_timer;\n\tstruct rtc_timer uie_rtctimer;\n\tstruct hrtimer pie_timer;\n\tint pie_enabled;\n\tstruct work_struct irqwork;\n\tint uie_unsupported;\n\tlong unsigned int set_offset_nsec;\n\tlong unsigned int features[1];\n\ttime64_t range_min;\n\ttimeu64_t range_max;\n\ttime64_t start_secs;\n\ttime64_t offset_secs;\n\tbool set_start_time;\n\tstruct work_struct uie_task;\n\tstruct timer_list uie_timer;\n\tunsigned int oldsecs;\n\tunsigned int uie_irq_active: 1;\n\tunsigned int stop_uie_polling: 1;\n\tunsigned int uie_task_active: 1;\n\tunsigned int uie_timer_active: 1;\n};\n\ntypedef s64 int64_t;\n\nenum tick_nohz_mode {\n\tNOHZ_MODE_INACTIVE = 0,\n\tNOHZ_MODE_LOWRES = 1,\n\tNOHZ_MODE_HIGHRES = 2,\n};\n\nstruct tick_sched {\n\tstruct hrtimer sched_timer;\n\tlong unsigned int check_clocks;\n\tenum tick_nohz_mode nohz_mode;\n\tunsigned int inidle: 1;\n\tunsigned int tick_stopped: 1;\n\tunsigned int idle_active: 1;\n\tunsigned int do_timer_last: 1;\n\tunsigned int got_idle_tick: 1;\n\tktime_t last_tick;\n\tktime_t next_tick;\n\tlong unsigned int idle_jiffies;\n\tlong unsigned int idle_calls;\n\tlong unsigned int idle_sleeps;\n\tktime_t idle_entrytime;\n\tktime_t idle_waketime;\n\tktime_t idle_exittime;\n\tktime_t idle_sleeptime;\n\tktime_t iowait_sleeptime;\n\tlong unsigned int last_jiffies;\n\tu64 timer_expires;\n\tu64 timer_expires_base;\n\tu64 next_timer;\n\tktime_t idle_expires;\n\tatomic_t tick_dep_mask;\n};\n\nstruct timer_list_iter {\n\tint cpu;\n\tbool second_pass;\n\tu64 now;\n};\n\nstruct tm {\n\tint tm_sec;\n\tint tm_min;\n\tint tm_hour;\n\tint tm_mday;\n\tint tm_mon;\n\tlong int tm_year;\n\tint tm_wday;\n\tint tm_yday;\n};\n\nstruct cyclecounter {\n\tu64 (*read)(const struct cyclecounter *);\n\tu64 mask;\n\tu32 mult;\n\tu32 shift;\n};\n\nstruct timecounter {\n\tconst struct cyclecounter *cc;\n\tu64 cycle_last;\n\tu64 nsec;\n\tu64 mask;\n\tu64 frac;\n};\n\ntypedef __kernel_timer_t timer_t;\n\nenum alarmtimer_type {\n\tALARM_REALTIME = 0,\n\tALARM_BOOTTIME = 1,\n\tALARM_NUMTYPE = 2,\n\tALARM_REALTIME_FREEZER = 3,\n\tALARM_BOOTTIME_FREEZER = 4,\n};\n\nenum alarmtimer_restart {\n\tALARMTIMER_NORESTART = 0,\n\tALARMTIMER_RESTART = 1,\n};\n\nstruct alarm {\n\tstruct timerqueue_node node;\n\tstruct hrtimer timer;\n\tenum alarmtimer_restart (*function)(struct alarm *, ktime_t);\n\tenum alarmtimer_type type;\n\tint state;\n\tvoid *data;\n};\n\nstruct cpu_timer {\n\tstruct timerqueue_node node;\n\tstruct timerqueue_head *head;\n\tstruct pid *pid;\n\tstruct list_head elist;\n\tint firing;\n};\n\nstruct k_clock;\n\nstruct k_itimer {\n\tstruct list_head list;\n\tstruct hlist_node t_hash;\n\tspinlock_t it_lock;\n\tconst struct k_clock *kclock;\n\tclockid_t it_clock;\n\ttimer_t it_id;\n\tint it_active;\n\ts64 it_overrun;\n\ts64 it_overrun_last;\n\tint it_requeue_pending;\n\tint it_sigev_notify;\n\tktime_t it_interval;\n\tstruct signal_struct *it_signal;\n\tunion {\n\t\tstruct pid *it_pid;\n\t\tstruct task_struct *it_process;\n\t};\n\tstruct sigqueue *sigq;\n\tunion {\n\t\tstruct {\n\t\t\tstruct hrtimer timer;\n\t\t} real;\n\t\tstruct cpu_timer cpu;\n\t\tstruct {\n\t\t\tstruct alarm alarmtimer;\n\t\t} alarm;\n\t} it;\n\tstruct callback_head rcu;\n};\n\nstruct k_clock {\n\tint (*clock_getres)(const clockid_t, struct timespec64 *);\n\tint (*clock_set)(const clockid_t, const struct timespec64 *);\n\tint (*clock_get_timespec)(const clockid_t, struct timespec64 *);\n\tktime_t (*clock_get_ktime)(const clockid_t);\n\tint (*clock_adj)(const clockid_t, struct __kernel_timex *);\n\tint (*timer_create)(struct k_itimer *);\n\tint (*nsleep)(const clockid_t, int, const struct timespec64 *);\n\tint (*timer_set)(struct k_itimer *, int, struct itimerspec64 *, struct itimerspec64 *);\n\tint (*timer_del)(struct k_itimer *);\n\tvoid (*timer_get)(struct k_itimer *, struct itimerspec64 *);\n\tvoid (*timer_rearm)(struct k_itimer *);\n\ts64 (*timer_forward)(struct k_itimer *, ktime_t);\n\tktime_t (*timer_remaining)(struct k_itimer *, ktime_t);\n\tint (*timer_try_to_cancel)(struct k_itimer *);\n\tvoid (*timer_arm)(struct k_itimer *, ktime_t, bool, bool);\n\tvoid (*timer_wait_running)(struct k_itimer *);\n};\n\nstruct class_interface {\n\tstruct list_head node;\n\tstruct class *class;\n\tint (*add_dev)(struct device *, struct class_interface *);\n\tvoid (*remove_dev)(struct device *, struct class_interface *);\n};\n\nstruct platform_driver {\n\tint (*probe)(struct platform_device *);\n\tint (*remove)(struct platform_device *);\n\tvoid (*shutdown)(struct platform_device *);\n\tint (*suspend)(struct platform_device *, pm_message_t);\n\tint (*resume)(struct platform_device *);\n\tstruct device_driver driver;\n\tconst struct platform_device_id *id_table;\n\tbool prevent_deferred_probe;\n};\n\nstruct trace_event_raw_alarmtimer_suspend {\n\tstruct trace_entry ent;\n\ts64 expires;\n\tunsigned char alarm_type;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_alarm_class {\n\tstruct trace_entry ent;\n\tvoid *alarm;\n\tunsigned char alarm_type;\n\ts64 expires;\n\ts64 now;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_alarmtimer_suspend {};\n\nstruct trace_event_data_offsets_alarm_class {};\n\ntypedef void (*btf_trace_alarmtimer_suspend)(void *, ktime_t, int);\n\ntypedef void (*btf_trace_alarmtimer_fired)(void *, struct alarm *, ktime_t);\n\ntypedef void (*btf_trace_alarmtimer_start)(void *, struct alarm *, ktime_t);\n\ntypedef void (*btf_trace_alarmtimer_cancel)(void *, struct alarm *, ktime_t);\n\nstruct alarm_base {\n\tspinlock_t lock;\n\tstruct timerqueue_head timerqueue;\n\tktime_t (*get_ktime)();\n\tvoid (*get_timespec)(struct timespec64 *);\n\tclockid_t base_clockid;\n};\n\nstruct sigevent {\n\tsigval_t sigev_value;\n\tint sigev_signo;\n\tint sigev_notify;\n\tunion {\n\t\tint _pad[12];\n\t\tint _tid;\n\t\tstruct {\n\t\t\tvoid (*_function)(sigval_t);\n\t\t\tvoid *_attribute;\n\t\t} _sigev_thread;\n\t} _sigev_un;\n};\n\ntypedef struct sigevent sigevent_t;\n\nstruct compat_sigevent {\n\tcompat_sigval_t sigev_value;\n\tcompat_int_t sigev_signo;\n\tcompat_int_t sigev_notify;\n\tunion {\n\t\tcompat_int_t _pad[13];\n\t\tcompat_int_t _tid;\n\t\tstruct {\n\t\t\tcompat_uptr_t _function;\n\t\t\tcompat_uptr_t _attribute;\n\t\t} _sigev_thread;\n\t} _sigev_un;\n};\n\nstruct posix_clock;\n\nstruct posix_clock_operations {\n\tstruct module *owner;\n\tint (*clock_adjtime)(struct posix_clock *, struct __kernel_timex *);\n\tint (*clock_gettime)(struct posix_clock *, struct timespec64 *);\n\tint (*clock_getres)(struct posix_clock *, struct timespec64 *);\n\tint (*clock_settime)(struct posix_clock *, const struct timespec64 *);\n\tlong int (*ioctl)(struct posix_clock *, unsigned int, long unsigned int);\n\tint (*open)(struct posix_clock *, fmode_t);\n\t__poll_t (*poll)(struct posix_clock *, struct file *, poll_table *);\n\tint (*release)(struct posix_clock *);\n\tssize_t (*read)(struct posix_clock *, uint, char *, size_t);\n};\n\nstruct posix_clock {\n\tstruct posix_clock_operations ops;\n\tstruct cdev cdev;\n\tstruct device *dev;\n\tstruct rw_semaphore rwsem;\n\tbool zombie;\n};\n\nstruct posix_clock_desc {\n\tstruct file *fp;\n\tstruct posix_clock *clk;\n};\n\nstruct __kernel_old_itimerval {\n\tstruct __kernel_old_timeval it_interval;\n\tstruct __kernel_old_timeval it_value;\n};\n\nstruct old_itimerval32 {\n\tstruct old_timeval32 it_interval;\n\tstruct old_timeval32 it_value;\n};\n\nstruct ce_unbind {\n\tstruct clock_event_device *ce;\n\tint res;\n};\n\nstruct proc_timens_offset {\n\tint clockid;\n\tstruct timespec64 val;\n};\n\nunion futex_key {\n\tstruct {\n\t\tu64 i_seq;\n\t\tlong unsigned int pgoff;\n\t\tunsigned int offset;\n\t} shared;\n\tstruct {\n\t\tunion {\n\t\t\tstruct mm_struct *mm;\n\t\t\tu64 __tmp;\n\t\t};\n\t\tlong unsigned int address;\n\t\tunsigned int offset;\n\t} private;\n\tstruct {\n\t\tu64 ptr;\n\t\tlong unsigned int word;\n\t\tunsigned int offset;\n\t} both;\n};\n\nstruct futex_pi_state {\n\tstruct list_head list;\n\tstruct rt_mutex pi_mutex;\n\tstruct task_struct *owner;\n\trefcount_t refcount;\n\tunion futex_key key;\n};\n\nstruct futex_q {\n\tstruct plist_node list;\n\tstruct task_struct *task;\n\tspinlock_t *lock_ptr;\n\tunion futex_key key;\n\tstruct futex_pi_state *pi_state;\n\tstruct rt_mutex_waiter *rt_waiter;\n\tunion futex_key *requeue_pi_key;\n\tu32 bitset;\n};\n\nstruct futex_hash_bucket {\n\tatomic_t waiters;\n\tspinlock_t lock;\n\tstruct plist_head chain;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum futex_access {\n\tFUTEX_READ = 0,\n\tFUTEX_WRITE = 1,\n};\n\nstruct dma_chan {\n\tint lock;\n\tconst char *device_id;\n};\n\nstruct cfd_percpu {\n\tcall_single_data_t csd;\n};\n\nstruct call_function_data {\n\tstruct cfd_percpu *pcpu;\n\tcpumask_var_t cpumask;\n\tcpumask_var_t cpumask_ipi;\n};\n\nstruct smp_call_on_cpu_struct {\n\tstruct work_struct work;\n\tstruct completion done;\n\tint (*func)(void *);\n\tvoid *data;\n\tint ret;\n\tint cpu;\n};\n\nstruct latch_tree_root {\n\tseqcount_latch_t seq;\n\tstruct rb_root tree[2];\n};\n\nstruct latch_tree_ops {\n\tbool (*less)(struct latch_tree_node *, struct latch_tree_node *);\n\tint (*comp)(void *, struct latch_tree_node *);\n};\n\nstruct module_use {\n\tstruct list_head source_list;\n\tstruct list_head target_list;\n\tstruct module *source;\n\tstruct module *target;\n};\n\nstruct module_sect_attr {\n\tstruct bin_attribute battr;\n\tlong unsigned int address;\n};\n\nstruct module_sect_attrs {\n\tstruct attribute_group grp;\n\tunsigned int nsections;\n\tstruct module_sect_attr attrs[0];\n};\n\nstruct module_notes_attrs {\n\tstruct kobject *dir;\n\tunsigned int notes;\n\tstruct bin_attribute attrs[0];\n};\n\nenum kernel_read_file_id {\n\tREADING_UNKNOWN = 0,\n\tREADING_FIRMWARE = 1,\n\tREADING_MODULE = 2,\n\tREADING_KEXEC_IMAGE = 3,\n\tREADING_KEXEC_INITRAMFS = 4,\n\tREADING_POLICY = 5,\n\tREADING_X509_CERTIFICATE = 6,\n\tREADING_MAX_ID = 7,\n};\n\nenum kernel_load_data_id {\n\tLOADING_UNKNOWN = 0,\n\tLOADING_FIRMWARE = 1,\n\tLOADING_MODULE = 2,\n\tLOADING_KEXEC_IMAGE = 3,\n\tLOADING_KEXEC_INITRAMFS = 4,\n\tLOADING_POLICY = 5,\n\tLOADING_X509_CERTIFICATE = 6,\n\tLOADING_MAX_ID = 7,\n};\n\nenum {\n\tPROC_ENTRY_PERMANENT = 1,\n};\n\nstruct load_info {\n\tconst char *name;\n\tstruct module *mod;\n\tElf64_Ehdr *hdr;\n\tlong unsigned int len;\n\tElf64_Shdr *sechdrs;\n\tchar *secstrings;\n\tchar *strtab;\n\tlong unsigned int symoffs;\n\tlong unsigned int stroffs;\n\tlong unsigned int init_typeoffs;\n\tlong unsigned int core_typeoffs;\n\tstruct _ddebug *debug;\n\tunsigned int num_debug;\n\tbool sig_ok;\n\tlong unsigned int mod_kallsyms_init_off;\n\tstruct {\n\t\tunsigned int sym;\n\t\tunsigned int str;\n\t\tunsigned int mod;\n\t\tunsigned int vers;\n\t\tunsigned int info;\n\t\tunsigned int pcpu;\n\t} index;\n};\n\nstruct trace_event_raw_module_load {\n\tstruct trace_entry ent;\n\tunsigned int taints;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_module_free {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_module_refcnt {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n\tint refcnt;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_module_request {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n\tbool wait;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_module_load {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_module_free {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_module_refcnt {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_module_request {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_module_load)(void *, struct module *);\n\ntypedef void (*btf_trace_module_free)(void *, struct module *);\n\ntypedef void (*btf_trace_module_get)(void *, struct module *, long unsigned int);\n\ntypedef void (*btf_trace_module_put)(void *, struct module *, long unsigned int);\n\ntypedef void (*btf_trace_module_request)(void *, char *, bool, long unsigned int);\n\nstruct mod_tree_root {\n\tstruct latch_tree_root root;\n\tlong unsigned int addr_min;\n\tlong unsigned int addr_max;\n};\n\nenum mod_license {\n\tNOT_GPL_ONLY = 0,\n\tGPL_ONLY = 1,\n};\n\nstruct symsearch {\n\tconst struct kernel_symbol *start;\n\tconst struct kernel_symbol *stop;\n\tconst s32 *crcs;\n\tenum mod_license license;\n};\n\nstruct find_symbol_arg {\n\tconst char *name;\n\tbool gplok;\n\tbool warn;\n\tstruct module *owner;\n\tconst s32 *crc;\n\tconst struct kernel_symbol *sym;\n\tenum mod_license license;\n};\n\nstruct mod_initfree {\n\tstruct llist_node node;\n\tvoid *module_init;\n};\n\nstruct module_signature {\n\tu8 algo;\n\tu8 hash;\n\tu8 id_type;\n\tu8 signer_len;\n\tu8 key_id_len;\n\tu8 __pad[3];\n\t__be32 sig_len;\n};\n\nenum pkey_id_type {\n\tPKEY_ID_PGP = 0,\n\tPKEY_ID_X509 = 1,\n\tPKEY_ID_PKCS7 = 2,\n};\n\nstruct kallsym_iter {\n\tloff_t pos;\n\tloff_t pos_arch_end;\n\tloff_t pos_mod_end;\n\tloff_t pos_ftrace_mod_end;\n\tloff_t pos_bpf_end;\n\tlong unsigned int value;\n\tunsigned int nameoff;\n\tchar type;\n\tchar name[128];\n\tchar module_name[56];\n\tint exported;\n\tint show_value;\n};\n\ntypedef __u16 comp_t;\n\nstruct acct_v3 {\n\tchar ac_flag;\n\tchar ac_version;\n\t__u16 ac_tty;\n\t__u32 ac_exitcode;\n\t__u32 ac_uid;\n\t__u32 ac_gid;\n\t__u32 ac_pid;\n\t__u32 ac_ppid;\n\t__u32 ac_btime;\n\t__u32 ac_etime;\n\tcomp_t ac_utime;\n\tcomp_t ac_stime;\n\tcomp_t ac_mem;\n\tcomp_t ac_io;\n\tcomp_t ac_rw;\n\tcomp_t ac_minflt;\n\tcomp_t ac_majflt;\n\tcomp_t ac_swaps;\n\tchar ac_comm[16];\n};\n\ntypedef struct acct_v3 acct_t;\n\nstruct fs_pin {\n\twait_queue_head_t wait;\n\tint done;\n\tstruct hlist_node s_list;\n\tstruct hlist_node m_list;\n\tvoid (*kill)(struct fs_pin *);\n};\n\nstruct bsd_acct_struct {\n\tstruct fs_pin pin;\n\tatomic_long_t count;\n\tstruct callback_head rcu;\n\tstruct mutex lock;\n\tint active;\n\tlong unsigned int needcheck;\n\tstruct file *file;\n\tstruct pid_namespace *ns;\n\tstruct work_struct work;\n\tstruct completion done;\n};\n\nstruct elf64_note {\n\tElf64_Word n_namesz;\n\tElf64_Word n_descsz;\n\tElf64_Word n_type;\n};\n\ntypedef long unsigned int elf_greg_t;\n\ntypedef elf_greg_t elf_gregset_t[27];\n\nstruct elf_siginfo {\n\tint si_signo;\n\tint si_code;\n\tint si_errno;\n};\n\nstruct elf_prstatus_common {\n\tstruct elf_siginfo pr_info;\n\tshort int pr_cursig;\n\tlong unsigned int pr_sigpend;\n\tlong unsigned int pr_sighold;\n\tpid_t pr_pid;\n\tpid_t pr_ppid;\n\tpid_t pr_pgrp;\n\tpid_t pr_sid;\n\tstruct __kernel_old_timeval pr_utime;\n\tstruct __kernel_old_timeval pr_stime;\n\tstruct __kernel_old_timeval pr_cutime;\n\tstruct __kernel_old_timeval pr_cstime;\n};\n\nstruct elf_prstatus {\n\tstruct elf_prstatus_common common;\n\telf_gregset_t pr_reg;\n\tint pr_fpvalid;\n};\n\ntypedef u32 note_buf_t[92];\n\nstruct compat_kexec_segment {\n\tcompat_uptr_t buf;\n\tcompat_size_t bufsz;\n\tcompat_ulong_t mem;\n\tcompat_size_t memsz;\n};\n\nstruct elf64_phdr {\n\tElf64_Word p_type;\n\tElf64_Word p_flags;\n\tElf64_Off p_offset;\n\tElf64_Addr p_vaddr;\n\tElf64_Addr p_paddr;\n\tElf64_Xword p_filesz;\n\tElf64_Xword p_memsz;\n\tElf64_Xword p_align;\n};\n\ntypedef struct elf64_phdr Elf64_Phdr;\n\nstruct shash_alg {\n\tint (*init)(struct shash_desc *);\n\tint (*update)(struct shash_desc *, const u8 *, unsigned int);\n\tint (*final)(struct shash_desc *, u8 *);\n\tint (*finup)(struct shash_desc *, const u8 *, unsigned int, u8 *);\n\tint (*digest)(struct shash_desc *, const u8 *, unsigned int, u8 *);\n\tint (*export)(struct shash_desc *, void *);\n\tint (*import)(struct shash_desc *, const void *);\n\tint (*setkey)(struct crypto_shash *, const u8 *, unsigned int);\n\tint (*init_tfm)(struct crypto_shash *);\n\tvoid (*exit_tfm)(struct crypto_shash *);\n\tunsigned int descsize;\n\tint: 32;\n\tunsigned int digestsize;\n\tunsigned int statesize;\n\tstruct crypto_alg base;\n};\n\nstruct kexec_sha_region {\n\tlong unsigned int start;\n\tlong unsigned int len;\n};\n\nenum migrate_reason {\n\tMR_COMPACTION = 0,\n\tMR_MEMORY_FAILURE = 1,\n\tMR_MEMORY_HOTPLUG = 2,\n\tMR_SYSCALL = 3,\n\tMR_MEMPOLICY_MBIND = 4,\n\tMR_NUMA_MISPLACED = 5,\n\tMR_CONTIG_RANGE = 6,\n\tMR_LONGTERM_PIN = 7,\n\tMR_TYPES = 8,\n};\n\ntypedef __kernel_ulong_t ino_t;\n\nenum bpf_link_type {\n\tBPF_LINK_TYPE_UNSPEC = 0,\n\tBPF_LINK_TYPE_RAW_TRACEPOINT = 1,\n\tBPF_LINK_TYPE_TRACING = 2,\n\tBPF_LINK_TYPE_CGROUP = 3,\n\tBPF_LINK_TYPE_ITER = 4,\n\tBPF_LINK_TYPE_NETNS = 5,\n\tBPF_LINK_TYPE_XDP = 6,\n\tMAX_BPF_LINK_TYPE = 7,\n};\n\nstruct bpf_link_info {\n\t__u32 type;\n\t__u32 id;\n\t__u32 prog_id;\n\tunion {\n\t\tstruct {\n\t\t\t__u64 tp_name;\n\t\t\t__u32 tp_name_len;\n\t\t} raw_tracepoint;\n\t\tstruct {\n\t\t\t__u32 attach_type;\n\t\t\t__u32 target_obj_id;\n\t\t\t__u32 target_btf_id;\n\t\t} tracing;\n\t\tstruct {\n\t\t\t__u64 cgroup_id;\n\t\t\t__u32 attach_type;\n\t\t} cgroup;\n\t\tstruct {\n\t\t\t__u64 target_name;\n\t\t\t__u32 target_name_len;\n\t\t\tunion {\n\t\t\t\tstruct {\n\t\t\t\t\t__u32 map_id;\n\t\t\t\t} map;\n\t\t\t};\n\t\t} iter;\n\t\tstruct {\n\t\t\t__u32 netns_ino;\n\t\t\t__u32 attach_type;\n\t\t} netns;\n\t\tstruct {\n\t\t\t__u32 ifindex;\n\t\t} xdp;\n\t};\n};\n\nstruct bpf_link_ops;\n\nstruct bpf_link {\n\tatomic64_t refcnt;\n\tu32 id;\n\tenum bpf_link_type type;\n\tconst struct bpf_link_ops *ops;\n\tstruct bpf_prog *prog;\n\tstruct work_struct work;\n};\n\nstruct bpf_link_ops {\n\tvoid (*release)(struct bpf_link *);\n\tvoid (*dealloc)(struct bpf_link *);\n\tint (*detach)(struct bpf_link *);\n\tint (*update_prog)(struct bpf_link *, struct bpf_prog *, struct bpf_prog *);\n\tvoid (*show_fdinfo)(const struct bpf_link *, struct seq_file *);\n\tint (*fill_link_info)(const struct bpf_link *, struct bpf_link_info *);\n};\n\nstruct bpf_cgroup_link {\n\tstruct bpf_link link;\n\tstruct cgroup *cgroup;\n\tenum bpf_attach_type type;\n};\n\nenum {\n\tCGRP_NOTIFY_ON_RELEASE = 0,\n\tCGRP_CPUSET_CLONE_CHILDREN = 1,\n\tCGRP_FREEZE = 2,\n\tCGRP_FROZEN = 3,\n\tCGRP_KILL = 4,\n};\n\nenum {\n\tCGRP_ROOT_NOPREFIX = 2,\n\tCGRP_ROOT_XATTR = 4,\n\tCGRP_ROOT_NS_DELEGATE = 8,\n\tCGRP_ROOT_CPUSET_V2_MODE = 16,\n\tCGRP_ROOT_MEMORY_LOCAL_EVENTS = 32,\n\tCGRP_ROOT_MEMORY_RECURSIVE_PROT = 64,\n};\n\nstruct cgroup_taskset {\n\tstruct list_head src_csets;\n\tstruct list_head dst_csets;\n\tint nr_tasks;\n\tint ssid;\n\tstruct list_head *csets;\n\tstruct css_set *cur_cset;\n\tstruct task_struct *cur_task;\n};\n\nstruct cgroup_fs_context {\n\tstruct kernfs_fs_context kfc;\n\tstruct cgroup_root *root;\n\tstruct cgroup_namespace *ns;\n\tunsigned int flags;\n\tbool cpuset_clone_children;\n\tbool none;\n\tbool all_ss;\n\tu16 subsys_mask;\n\tchar *name;\n\tchar *release_agent;\n};\n\nstruct cgrp_cset_link {\n\tstruct cgroup *cgrp;\n\tstruct css_set *cset;\n\tstruct list_head cset_link;\n\tstruct list_head cgrp_link;\n};\n\nstruct cgroup_mgctx {\n\tstruct list_head preloaded_src_csets;\n\tstruct list_head preloaded_dst_csets;\n\tstruct cgroup_taskset tset;\n\tu16 ss_mask;\n};\n\nstruct trace_event_raw_cgroup_root {\n\tstruct trace_entry ent;\n\tint root;\n\tu16 ss_mask;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cgroup {\n\tstruct trace_entry ent;\n\tint root;\n\tint id;\n\tint level;\n\tu32 __data_loc_path;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cgroup_migrate {\n\tstruct trace_entry ent;\n\tint dst_root;\n\tint dst_id;\n\tint dst_level;\n\tint pid;\n\tu32 __data_loc_dst_path;\n\tu32 __data_loc_comm;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cgroup_event {\n\tstruct trace_entry ent;\n\tint root;\n\tint id;\n\tint level;\n\tu32 __data_loc_path;\n\tint val;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_cgroup_root {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_cgroup {\n\tu32 path;\n};\n\nstruct trace_event_data_offsets_cgroup_migrate {\n\tu32 dst_path;\n\tu32 comm;\n};\n\nstruct trace_event_data_offsets_cgroup_event {\n\tu32 path;\n};\n\ntypedef void (*btf_trace_cgroup_setup_root)(void *, struct cgroup_root *);\n\ntypedef void (*btf_trace_cgroup_destroy_root)(void *, struct cgroup_root *);\n\ntypedef void (*btf_trace_cgroup_remount)(void *, struct cgroup_root *);\n\ntypedef void (*btf_trace_cgroup_mkdir)(void *, struct cgroup *, const char *);\n\ntypedef void (*btf_trace_cgroup_rmdir)(void *, struct cgroup *, const char *);\n\ntypedef void (*btf_trace_cgroup_release)(void *, struct cgroup *, const char *);\n\ntypedef void (*btf_trace_cgroup_rename)(void *, struct cgroup *, const char *);\n\ntypedef void (*btf_trace_cgroup_freeze)(void *, struct cgroup *, const char *);\n\ntypedef void (*btf_trace_cgroup_unfreeze)(void *, struct cgroup *, const char *);\n\ntypedef void (*btf_trace_cgroup_attach_task)(void *, struct cgroup *, const char *, struct task_struct *, bool);\n\ntypedef void (*btf_trace_cgroup_transfer_tasks)(void *, struct cgroup *, const char *, struct task_struct *, bool);\n\ntypedef void (*btf_trace_cgroup_notify_populated)(void *, struct cgroup *, const char *, int);\n\ntypedef void (*btf_trace_cgroup_notify_frozen)(void *, struct cgroup *, const char *, int);\n\nenum cgroup_opt_features {\n\tOPT_FEATURE_PRESSURE = 0,\n\tOPT_FEATURE_COUNT = 1,\n};\n\nenum cgroup2_param {\n\tOpt_nsdelegate = 0,\n\tOpt_memory_localevents = 1,\n\tOpt_memory_recursiveprot = 2,\n\tnr__cgroup2_params = 3,\n};\n\nstruct cgroupstats {\n\t__u64 nr_sleeping;\n\t__u64 nr_running;\n\t__u64 nr_stopped;\n\t__u64 nr_uninterruptible;\n\t__u64 nr_io_wait;\n};\n\nenum cgroup_filetype {\n\tCGROUP_FILE_PROCS = 0,\n\tCGROUP_FILE_TASKS = 1,\n};\n\nstruct cgroup_pidlist {\n\tstruct {\n\t\tenum cgroup_filetype type;\n\t\tstruct pid_namespace *ns;\n\t} key;\n\tpid_t *list;\n\tint length;\n\tstruct list_head links;\n\tstruct cgroup *owner;\n\tstruct delayed_work destroy_dwork;\n};\n\nenum cgroup1_param {\n\tOpt_all = 0,\n\tOpt_clone_children = 1,\n\tOpt_cpuset_v2_mode = 2,\n\tOpt_name = 3,\n\tOpt_none = 4,\n\tOpt_noprefix = 5,\n\tOpt_release_agent = 6,\n\tOpt_xattr = 7,\n};\n\nenum freezer_state_flags {\n\tCGROUP_FREEZER_ONLINE = 1,\n\tCGROUP_FREEZING_SELF = 2,\n\tCGROUP_FREEZING_PARENT = 4,\n\tCGROUP_FROZEN = 8,\n\tCGROUP_FREEZING = 6,\n};\n\nstruct freezer {\n\tstruct cgroup_subsys_state css;\n\tunsigned int state;\n};\n\nstruct pids_cgroup {\n\tstruct cgroup_subsys_state css;\n\tatomic64_t counter;\n\tatomic64_t limit;\n\tstruct cgroup_file events_file;\n\tatomic64_t events_limit;\n};\n\ntypedef struct {\n\tchar *from;\n\tchar *to;\n} substring_t;\n\nenum rdmacg_resource_type {\n\tRDMACG_RESOURCE_HCA_HANDLE = 0,\n\tRDMACG_RESOURCE_HCA_OBJECT = 1,\n\tRDMACG_RESOURCE_MAX = 2,\n};\n\nstruct rdma_cgroup {\n\tstruct cgroup_subsys_state css;\n\tstruct list_head rpools;\n};\n\nstruct rdmacg_device {\n\tstruct list_head dev_node;\n\tstruct list_head rpools;\n\tchar *name;\n};\n\nenum rdmacg_file_type {\n\tRDMACG_RESOURCE_TYPE_MAX = 0,\n\tRDMACG_RESOURCE_TYPE_STAT = 1,\n};\n\nstruct rdmacg_resource {\n\tint max;\n\tint usage;\n};\n\nstruct rdmacg_resource_pool {\n\tstruct rdmacg_device *device;\n\tstruct rdmacg_resource resources[2];\n\tstruct list_head cg_node;\n\tstruct list_head dev_node;\n\tu64 usage_sum;\n\tint num_max_cnt;\n};\n\nstruct root_domain___2;\n\nstruct fmeter {\n\tint cnt;\n\tint val;\n\ttime64_t time;\n\tspinlock_t lock;\n};\n\nstruct cpuset {\n\tstruct cgroup_subsys_state css;\n\tlong unsigned int flags;\n\tcpumask_var_t cpus_allowed;\n\tnodemask_t mems_allowed;\n\tcpumask_var_t effective_cpus;\n\tnodemask_t effective_mems;\n\tcpumask_var_t subparts_cpus;\n\tnodemask_t old_mems_allowed;\n\tstruct fmeter fmeter;\n\tint attach_in_progress;\n\tint pn;\n\tint relax_domain_level;\n\tint nr_subparts_cpus;\n\tint partition_root_state;\n\tint use_parent_ecpus;\n\tint child_ecpus_count;\n};\n\nstruct tmpmasks {\n\tcpumask_var_t addmask;\n\tcpumask_var_t delmask;\n\tcpumask_var_t new_cpus;\n};\n\ntypedef enum {\n\tCS_ONLINE = 0,\n\tCS_CPU_EXCLUSIVE = 1,\n\tCS_MEM_EXCLUSIVE = 2,\n\tCS_MEM_HARDWALL = 3,\n\tCS_MEMORY_MIGRATE = 4,\n\tCS_SCHED_LOAD_BALANCE = 5,\n\tCS_SPREAD_PAGE = 6,\n\tCS_SPREAD_SLAB = 7,\n} cpuset_flagbits_t;\n\nenum subparts_cmd {\n\tpartcmd_enable = 0,\n\tpartcmd_disable = 1,\n\tpartcmd_update = 2,\n};\n\nstruct cpuset_migrate_mm_work {\n\tstruct work_struct work;\n\tstruct mm_struct *mm;\n\tnodemask_t from;\n\tnodemask_t to;\n};\n\ntypedef enum {\n\tFILE_MEMORY_MIGRATE = 0,\n\tFILE_CPULIST = 1,\n\tFILE_MEMLIST = 2,\n\tFILE_EFFECTIVE_CPULIST = 3,\n\tFILE_EFFECTIVE_MEMLIST = 4,\n\tFILE_SUBPARTS_CPULIST = 5,\n\tFILE_CPU_EXCLUSIVE = 6,\n\tFILE_MEM_EXCLUSIVE = 7,\n\tFILE_MEM_HARDWALL = 8,\n\tFILE_SCHED_LOAD_BALANCE = 9,\n\tFILE_PARTITION_ROOT = 10,\n\tFILE_SCHED_RELAX_DOMAIN_LEVEL = 11,\n\tFILE_MEMORY_PRESSURE_ENABLED = 12,\n\tFILE_MEMORY_PRESSURE = 13,\n\tFILE_SPREAD_PAGE = 14,\n\tFILE_SPREAD_SLAB = 15,\n} cpuset_filetype_t;\n\nenum misc_res_type {\n\tMISC_CG_RES_SEV = 0,\n\tMISC_CG_RES_SEV_ES = 1,\n\tMISC_CG_RES_TYPES = 2,\n};\n\nstruct misc_res {\n\tlong unsigned int max;\n\tatomic_long_t usage;\n\tbool failed;\n};\n\nstruct misc_cg {\n\tstruct cgroup_subsys_state css;\n\tstruct misc_res res[2];\n};\n\nstruct kernel_pkey_query {\n\t__u32 supported_ops;\n\t__u32 key_size;\n\t__u16 max_data_size;\n\t__u16 max_sig_size;\n\t__u16 max_enc_size;\n\t__u16 max_dec_size;\n};\n\nenum kernel_pkey_operation {\n\tkernel_pkey_encrypt = 0,\n\tkernel_pkey_decrypt = 1,\n\tkernel_pkey_sign = 2,\n\tkernel_pkey_verify = 3,\n};\n\nstruct kernel_pkey_params {\n\tstruct key *key;\n\tconst char *encoding;\n\tconst char *hash_algo;\n\tchar *info;\n\t__u32 in_len;\n\tunion {\n\t\t__u32 out_len;\n\t\t__u32 in2_len;\n\t};\n\tenum kernel_pkey_operation op: 8;\n};\n\nstruct key_preparsed_payload {\n\tconst char *orig_description;\n\tchar *description;\n\tunion key_payload payload;\n\tconst void *data;\n\tsize_t datalen;\n\tsize_t quotalen;\n\ttime64_t expiry;\n};\n\nstruct key_match_data {\n\tbool (*cmp)(const struct key *, const struct key_match_data *);\n\tconst void *raw_data;\n\tvoid *preparsed;\n\tunsigned int lookup_type;\n};\n\nstruct idmap_key {\n\tbool map_up;\n\tu32 id;\n\tu32 count;\n};\n\nstruct ctl_path {\n\tconst char *procname;\n};\n\nstruct cpu_stop_done {\n\tatomic_t nr_todo;\n\tint ret;\n\tstruct completion completion;\n};\n\nstruct cpu_stopper {\n\tstruct task_struct *thread;\n\traw_spinlock_t lock;\n\tbool enabled;\n\tstruct list_head works;\n\tstruct cpu_stop_work stop_work;\n\tlong unsigned int caller;\n\tcpu_stop_fn_t fn;\n};\n\nenum multi_stop_state {\n\tMULTI_STOP_NONE = 0,\n\tMULTI_STOP_PREPARE = 1,\n\tMULTI_STOP_DISABLE_IRQ = 2,\n\tMULTI_STOP_RUN = 3,\n\tMULTI_STOP_EXIT = 4,\n};\n\nstruct multi_stop_data {\n\tcpu_stop_fn_t fn;\n\tvoid *data;\n\tunsigned int num_threads;\n\tconst struct cpumask *active_cpus;\n\tenum multi_stop_state state;\n\tatomic_t thread_ack;\n};\n\ntypedef int __kernel_mqd_t;\n\ntypedef __kernel_mqd_t mqd_t;\n\nenum audit_state {\n\tAUDIT_STATE_DISABLED = 0,\n\tAUDIT_STATE_BUILD = 1,\n\tAUDIT_STATE_RECORD = 2,\n};\n\nstruct audit_cap_data {\n\tkernel_cap_t permitted;\n\tkernel_cap_t inheritable;\n\tunion {\n\t\tunsigned int fE;\n\t\tkernel_cap_t effective;\n\t};\n\tkernel_cap_t ambient;\n\tkuid_t rootid;\n};\n\nstruct audit_names {\n\tstruct list_head list;\n\tstruct filename *name;\n\tint name_len;\n\tbool hidden;\n\tlong unsigned int ino;\n\tdev_t dev;\n\tumode_t mode;\n\tkuid_t uid;\n\tkgid_t gid;\n\tdev_t rdev;\n\tu32 osid;\n\tstruct audit_cap_data fcap;\n\tunsigned int fcap_ver;\n\tunsigned char type;\n\tbool should_free;\n};\n\nstruct mq_attr {\n\t__kernel_long_t mq_flags;\n\t__kernel_long_t mq_maxmsg;\n\t__kernel_long_t mq_msgsize;\n\t__kernel_long_t mq_curmsgs;\n\t__kernel_long_t __reserved[4];\n};\n\nstruct audit_proctitle {\n\tint len;\n\tchar *value;\n};\n\nstruct audit_aux_data;\n\nstruct __kernel_sockaddr_storage;\n\nstruct audit_tree_refs;\n\nstruct audit_context {\n\tint dummy;\n\tint in_syscall;\n\tenum audit_state state;\n\tenum audit_state current_state;\n\tunsigned int serial;\n\tint major;\n\tstruct timespec64 ctime;\n\tlong unsigned int argv[4];\n\tlong int return_code;\n\tu64 prio;\n\tint return_valid;\n\tstruct audit_names preallocated_names[5];\n\tint name_count;\n\tstruct list_head names_list;\n\tchar *filterkey;\n\tstruct path pwd;\n\tstruct audit_aux_data *aux;\n\tstruct audit_aux_data *aux_pids;\n\tstruct __kernel_sockaddr_storage *sockaddr;\n\tsize_t sockaddr_len;\n\tpid_t pid;\n\tpid_t ppid;\n\tkuid_t uid;\n\tkuid_t euid;\n\tkuid_t suid;\n\tkuid_t fsuid;\n\tkgid_t gid;\n\tkgid_t egid;\n\tkgid_t sgid;\n\tkgid_t fsgid;\n\tlong unsigned int personality;\n\tint arch;\n\tpid_t target_pid;\n\tkuid_t target_auid;\n\tkuid_t target_uid;\n\tunsigned int target_sessionid;\n\tu32 target_sid;\n\tchar target_comm[16];\n\tstruct audit_tree_refs *trees;\n\tstruct audit_tree_refs *first_trees;\n\tstruct list_head killed_trees;\n\tint tree_count;\n\tint type;\n\tunion {\n\t\tstruct {\n\t\t\tint nargs;\n\t\t\tlong int args[6];\n\t\t} socketcall;\n\t\tstruct {\n\t\t\tkuid_t uid;\n\t\t\tkgid_t gid;\n\t\t\tumode_t mode;\n\t\t\tu32 osid;\n\t\t\tint has_perm;\n\t\t\tuid_t perm_uid;\n\t\t\tgid_t perm_gid;\n\t\t\tumode_t perm_mode;\n\t\t\tlong unsigned int qbytes;\n\t\t} ipc;\n\t\tstruct {\n\t\t\tmqd_t mqdes;\n\t\t\tstruct mq_attr mqstat;\n\t\t} mq_getsetattr;\n\t\tstruct {\n\t\t\tmqd_t mqdes;\n\t\t\tint sigev_signo;\n\t\t} mq_notify;\n\t\tstruct {\n\t\t\tmqd_t mqdes;\n\t\t\tsize_t msg_len;\n\t\t\tunsigned int msg_prio;\n\t\t\tstruct timespec64 abs_timeout;\n\t\t} mq_sendrecv;\n\t\tstruct {\n\t\t\tint oflag;\n\t\t\tumode_t mode;\n\t\t\tstruct mq_attr attr;\n\t\t} mq_open;\n\t\tstruct {\n\t\t\tpid_t pid;\n\t\t\tstruct audit_cap_data cap;\n\t\t} capset;\n\t\tstruct {\n\t\t\tint fd;\n\t\t\tint flags;\n\t\t} mmap;\n\t\tstruct {\n\t\t\tint argc;\n\t\t} execve;\n\t\tstruct {\n\t\t\tchar *name;\n\t\t} module;\n\t};\n\tint fds[2];\n\tstruct audit_proctitle proctitle;\n};\n\nstruct __kernel_sockaddr_storage {\n\tunion {\n\t\tstruct {\n\t\t\t__kernel_sa_family_t ss_family;\n\t\t\tchar __data[126];\n\t\t};\n\t\tvoid *__align;\n\t};\n};\n\nenum audit_nlgrps {\n\tAUDIT_NLGRP_NONE = 0,\n\tAUDIT_NLGRP_READLOG = 1,\n\t__AUDIT_NLGRP_MAX = 2,\n};\n\nstruct audit_status {\n\t__u32 mask;\n\t__u32 enabled;\n\t__u32 failure;\n\t__u32 pid;\n\t__u32 rate_limit;\n\t__u32 backlog_limit;\n\t__u32 lost;\n\t__u32 backlog;\n\tunion {\n\t\t__u32 version;\n\t\t__u32 feature_bitmap;\n\t};\n\t__u32 backlog_wait_time;\n\t__u32 backlog_wait_time_actual;\n};\n\nstruct audit_features {\n\t__u32 vers;\n\t__u32 mask;\n\t__u32 features;\n\t__u32 lock;\n};\n\nstruct audit_tty_status {\n\t__u32 enabled;\n\t__u32 log_passwd;\n};\n\nstruct audit_sig_info {\n\tuid_t uid;\n\tpid_t pid;\n\tchar ctx[0];\n};\n\nstruct net_generic {\n\tunion {\n\t\tstruct {\n\t\t\tunsigned int len;\n\t\t\tstruct callback_head rcu;\n\t\t} s;\n\t\tvoid *ptr[0];\n\t};\n};\n\nstruct pernet_operations {\n\tstruct list_head list;\n\tint (*init)(struct net *);\n\tvoid (*pre_exit)(struct net *);\n\tvoid (*exit)(struct net *);\n\tvoid (*exit_batch)(struct list_head *);\n\tunsigned int *id;\n\tsize_t size;\n};\n\nstruct scm_creds {\n\tu32 pid;\n\tkuid_t uid;\n\tkgid_t gid;\n};\n\nstruct netlink_skb_parms {\n\tstruct scm_creds creds;\n\t__u32 portid;\n\t__u32 dst_group;\n\t__u32 flags;\n\tstruct sock *sk;\n\tbool nsid_is_set;\n\tint nsid;\n};\n\nstruct netlink_kernel_cfg {\n\tunsigned int groups;\n\tunsigned int flags;\n\tvoid (*input)(struct sk_buff *);\n\tstruct mutex *cb_mutex;\n\tint (*bind)(struct net *, int);\n\tvoid (*unbind)(struct net *, int);\n\tbool (*compare)(struct net *, struct sock *);\n};\n\nstruct audit_netlink_list {\n\t__u32 portid;\n\tstruct net *net;\n\tstruct sk_buff_head q;\n};\n\nstruct audit_net {\n\tstruct sock *sk;\n};\n\nstruct auditd_connection {\n\tstruct pid *pid;\n\tu32 portid;\n\tstruct net *net;\n\tstruct callback_head rcu;\n};\n\nstruct audit_ctl_mutex {\n\tstruct mutex lock;\n\tvoid *owner;\n};\n\nstruct audit_buffer {\n\tstruct sk_buff *skb;\n\tstruct audit_context *ctx;\n\tgfp_t gfp_mask;\n};\n\nstruct audit_reply {\n\t__u32 portid;\n\tstruct net *net;\n\tstruct sk_buff *skb;\n};\n\nenum {\n\tAudit_equal = 0,\n\tAudit_not_equal = 1,\n\tAudit_bitmask = 2,\n\tAudit_bittest = 3,\n\tAudit_lt = 4,\n\tAudit_gt = 5,\n\tAudit_le = 6,\n\tAudit_ge = 7,\n\tAudit_bad = 8,\n};\n\nstruct audit_rule_data {\n\t__u32 flags;\n\t__u32 action;\n\t__u32 field_count;\n\t__u32 mask[64];\n\t__u32 fields[64];\n\t__u32 values[64];\n\t__u32 fieldflags[64];\n\t__u32 buflen;\n\tchar buf[0];\n};\n\nstruct audit_field;\n\nstruct audit_watch;\n\nstruct audit_tree;\n\nstruct audit_fsnotify_mark;\n\nstruct audit_krule {\n\tu32 pflags;\n\tu32 flags;\n\tu32 listnr;\n\tu32 action;\n\tu32 mask[64];\n\tu32 buflen;\n\tu32 field_count;\n\tchar *filterkey;\n\tstruct audit_field *fields;\n\tstruct audit_field *arch_f;\n\tstruct audit_field *inode_f;\n\tstruct audit_watch *watch;\n\tstruct audit_tree *tree;\n\tstruct audit_fsnotify_mark *exe;\n\tstruct list_head rlist;\n\tstruct list_head list;\n\tu64 prio;\n};\n\nstruct audit_field {\n\tu32 type;\n\tunion {\n\t\tu32 val;\n\t\tkuid_t uid;\n\t\tkgid_t gid;\n\t\tstruct {\n\t\t\tchar *lsm_str;\n\t\t\tvoid *lsm_rule;\n\t\t};\n\t};\n\tu32 op;\n};\n\nstruct audit_entry {\n\tstruct list_head list;\n\tstruct callback_head rcu;\n\tstruct audit_krule rule;\n};\n\nstruct audit_buffer___2;\n\ntypedef int __kernel_key_t;\n\ntypedef __kernel_key_t key_t;\n\nstruct cpu_vfs_cap_data {\n\t__u32 magic_etc;\n\tkernel_cap_t permitted;\n\tkernel_cap_t inheritable;\n\tkuid_t rootid;\n};\n\nstruct kern_ipc_perm {\n\tspinlock_t lock;\n\tbool deleted;\n\tint id;\n\tkey_t key;\n\tkuid_t uid;\n\tkgid_t gid;\n\tkuid_t cuid;\n\tkgid_t cgid;\n\tumode_t mode;\n\tlong unsigned int seq;\n\tvoid *security;\n\tstruct rhash_head khtnode;\n\tstruct callback_head rcu;\n\trefcount_t refcount;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\ntypedef struct fsnotify_mark_connector *fsnotify_connp_t;\n\nstruct fsnotify_mark_connector {\n\tspinlock_t lock;\n\tshort unsigned int type;\n\tshort unsigned int flags;\n\t__kernel_fsid_t fsid;\n\tunion {\n\t\tfsnotify_connp_t *obj;\n\t\tstruct fsnotify_mark_connector *destroy_next;\n\t};\n\tstruct hlist_head list;\n};\n\nenum audit_nfcfgop {\n\tAUDIT_XT_OP_REGISTER = 0,\n\tAUDIT_XT_OP_REPLACE = 1,\n\tAUDIT_XT_OP_UNREGISTER = 2,\n\tAUDIT_NFT_OP_TABLE_REGISTER = 3,\n\tAUDIT_NFT_OP_TABLE_UNREGISTER = 4,\n\tAUDIT_NFT_OP_CHAIN_REGISTER = 5,\n\tAUDIT_NFT_OP_CHAIN_UNREGISTER = 6,\n\tAUDIT_NFT_OP_RULE_REGISTER = 7,\n\tAUDIT_NFT_OP_RULE_UNREGISTER = 8,\n\tAUDIT_NFT_OP_SET_REGISTER = 9,\n\tAUDIT_NFT_OP_SET_UNREGISTER = 10,\n\tAUDIT_NFT_OP_SETELEM_REGISTER = 11,\n\tAUDIT_NFT_OP_SETELEM_UNREGISTER = 12,\n\tAUDIT_NFT_OP_GEN_REGISTER = 13,\n\tAUDIT_NFT_OP_OBJ_REGISTER = 14,\n\tAUDIT_NFT_OP_OBJ_UNREGISTER = 15,\n\tAUDIT_NFT_OP_OBJ_RESET = 16,\n\tAUDIT_NFT_OP_FLOWTABLE_REGISTER = 17,\n\tAUDIT_NFT_OP_FLOWTABLE_UNREGISTER = 18,\n\tAUDIT_NFT_OP_INVALID = 19,\n};\n\nenum fsnotify_obj_type {\n\tFSNOTIFY_OBJ_TYPE_INODE = 0,\n\tFSNOTIFY_OBJ_TYPE_PARENT = 1,\n\tFSNOTIFY_OBJ_TYPE_VFSMOUNT = 2,\n\tFSNOTIFY_OBJ_TYPE_SB = 3,\n\tFSNOTIFY_OBJ_TYPE_COUNT = 4,\n\tFSNOTIFY_OBJ_TYPE_DETACHED = 4,\n};\n\nstruct audit_aux_data {\n\tstruct audit_aux_data *next;\n\tint type;\n};\n\nstruct audit_chunk;\n\nstruct audit_tree_refs {\n\tstruct audit_tree_refs *next;\n\tstruct audit_chunk *c[31];\n};\n\nstruct audit_aux_data_pids {\n\tstruct audit_aux_data d;\n\tpid_t target_pid[16];\n\tkuid_t target_auid[16];\n\tkuid_t target_uid[16];\n\tunsigned int target_sessionid[16];\n\tu32 target_sid[16];\n\tchar target_comm[256];\n\tint pid_count;\n};\n\nstruct audit_aux_data_bprm_fcaps {\n\tstruct audit_aux_data d;\n\tstruct audit_cap_data fcap;\n\tunsigned int fcap_ver;\n\tstruct audit_cap_data old_pcap;\n\tstruct audit_cap_data new_pcap;\n};\n\nstruct audit_nfcfgop_tab {\n\tenum audit_nfcfgop op;\n\tconst char *s;\n};\n\nstruct audit_parent;\n\nstruct audit_watch {\n\trefcount_t count;\n\tdev_t dev;\n\tchar *path;\n\tlong unsigned int ino;\n\tstruct audit_parent *parent;\n\tstruct list_head wlist;\n\tstruct list_head rules;\n};\n\nstruct fsnotify_group;\n\nstruct fsnotify_iter_info;\n\nstruct fsnotify_mark;\n\nstruct fsnotify_event;\n\nstruct fsnotify_ops {\n\tint (*handle_event)(struct fsnotify_group *, u32, const void *, int, struct inode *, const struct qstr *, u32, struct fsnotify_iter_info *);\n\tint (*handle_inode_event)(struct fsnotify_mark *, u32, struct inode *, struct inode *, const struct qstr *, u32);\n\tvoid (*free_group_priv)(struct fsnotify_group *);\n\tvoid (*freeing_mark)(struct fsnotify_mark *, struct fsnotify_group *);\n\tvoid (*free_event)(struct fsnotify_event *);\n\tvoid (*free_mark)(struct fsnotify_mark *);\n};\n\nstruct inotify_group_private_data {\n\tspinlock_t idr_lock;\n\tstruct idr idr;\n\tstruct ucounts *ucounts;\n};\n\nstruct fanotify_group_private_data {\n\tstruct hlist_head *merge_hash;\n\tstruct list_head access_list;\n\twait_queue_head_t access_waitq;\n\tint flags;\n\tint f_flags;\n\tstruct ucounts *ucounts;\n};\n\nstruct fsnotify_group {\n\tconst struct fsnotify_ops *ops;\n\trefcount_t refcnt;\n\tspinlock_t notification_lock;\n\tstruct list_head notification_list;\n\twait_queue_head_t notification_waitq;\n\tunsigned int q_len;\n\tunsigned int max_events;\n\tunsigned int priority;\n\tbool shutdown;\n\tstruct mutex mark_mutex;\n\tatomic_t user_waits;\n\tstruct list_head marks_list;\n\tstruct fasync_struct *fsn_fa;\n\tstruct fsnotify_event *overflow_event;\n\tstruct mem_cgroup *memcg;\n\tunion {\n\t\tvoid *private;\n\t\tstruct inotify_group_private_data inotify_data;\n\t\tstruct fanotify_group_private_data fanotify_data;\n\t};\n};\n\nstruct fsnotify_iter_info {\n\tstruct fsnotify_mark *marks[4];\n\tunsigned int report_mask;\n\tint srcu_idx;\n};\n\nstruct fsnotify_mark {\n\t__u32 mask;\n\trefcount_t refcnt;\n\tstruct fsnotify_group *group;\n\tstruct list_head g_list;\n\tspinlock_t lock;\n\tstruct hlist_node obj_list;\n\tstruct fsnotify_mark_connector *connector;\n\t__u32 ignored_mask;\n\tunsigned int flags;\n};\n\nstruct fsnotify_event {\n\tstruct list_head list;\n};\n\nstruct audit_parent {\n\tstruct list_head watches;\n\tstruct fsnotify_mark mark;\n};\n\nstruct audit_fsnotify_mark {\n\tdev_t dev;\n\tlong unsigned int ino;\n\tchar *path;\n\tstruct fsnotify_mark mark;\n\tstruct audit_krule *rule;\n};\n\nstruct audit_chunk___2;\n\nstruct audit_tree {\n\trefcount_t count;\n\tint goner;\n\tstruct audit_chunk___2 *root;\n\tstruct list_head chunks;\n\tstruct list_head rules;\n\tstruct list_head list;\n\tstruct list_head same_root;\n\tstruct callback_head head;\n\tchar pathname[0];\n};\n\nstruct node {\n\tstruct list_head list;\n\tstruct audit_tree *owner;\n\tunsigned int index;\n};\n\nstruct audit_chunk___2 {\n\tstruct list_head hash;\n\tlong unsigned int key;\n\tstruct fsnotify_mark *mark;\n\tstruct list_head trees;\n\tint count;\n\tatomic_long_t refs;\n\tstruct callback_head head;\n\tstruct node owners[0];\n};\n\nstruct audit_tree_mark {\n\tstruct fsnotify_mark mark;\n\tstruct audit_chunk___2 *chunk;\n};\n\nenum {\n\tHASH_SIZE = 128,\n};\n\nstruct kprobe_blacklist_entry {\n\tstruct list_head list;\n\tlong unsigned int start_addr;\n\tlong unsigned int end_addr;\n};\n\nenum perf_record_ksymbol_type {\n\tPERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0,\n\tPERF_RECORD_KSYMBOL_TYPE_BPF = 1,\n\tPERF_RECORD_KSYMBOL_TYPE_OOL = 2,\n\tPERF_RECORD_KSYMBOL_TYPE_MAX = 3,\n};\n\nstruct kprobe_insn_page {\n\tstruct list_head list;\n\tkprobe_opcode_t *insns;\n\tstruct kprobe_insn_cache *cache;\n\tint nused;\n\tint ngarbage;\n\tchar slot_used[0];\n};\n\nenum kprobe_slot_state {\n\tSLOT_CLEAN = 0,\n\tSLOT_DIRTY = 1,\n\tSLOT_USED = 2,\n};\n\nstruct seccomp_notif_sizes {\n\t__u16 seccomp_notif;\n\t__u16 seccomp_notif_resp;\n\t__u16 seccomp_data;\n};\n\nstruct seccomp_notif {\n\t__u64 id;\n\t__u32 pid;\n\t__u32 flags;\n\tstruct seccomp_data data;\n};\n\nstruct seccomp_notif_resp {\n\t__u64 id;\n\t__s64 val;\n\t__s32 error;\n\t__u32 flags;\n};\n\nstruct seccomp_notif_addfd {\n\t__u64 id;\n\t__u32 flags;\n\t__u32 srcfd;\n\t__u32 newfd;\n\t__u32 newfd_flags;\n};\n\nstruct action_cache {\n\tlong unsigned int allow_native[7];\n\tlong unsigned int allow_compat[7];\n};\n\nstruct notification;\n\nstruct seccomp_filter {\n\trefcount_t refs;\n\trefcount_t users;\n\tbool log;\n\tstruct action_cache cache;\n\tstruct seccomp_filter *prev;\n\tstruct bpf_prog *prog;\n\tstruct notification *notif;\n\tstruct mutex notify_lock;\n\twait_queue_head_t wqh;\n};\n\nstruct seccomp_metadata {\n\t__u64 filter_off;\n\t__u64 flags;\n};\n\nstruct sock_fprog {\n\tshort unsigned int len;\n\tstruct sock_filter *filter;\n};\n\nstruct compat_sock_fprog {\n\tu16 len;\n\tcompat_uptr_t filter;\n};\n\ntypedef int (*bpf_aux_classic_check_t)(struct sock_filter *, unsigned int);\n\nenum notify_state {\n\tSECCOMP_NOTIFY_INIT = 0,\n\tSECCOMP_NOTIFY_SENT = 1,\n\tSECCOMP_NOTIFY_REPLIED = 2,\n};\n\nstruct seccomp_knotif {\n\tstruct task_struct *task;\n\tu64 id;\n\tconst struct seccomp_data *data;\n\tenum notify_state state;\n\tint error;\n\tlong int val;\n\tu32 flags;\n\tstruct completion ready;\n\tstruct list_head list;\n\tstruct list_head addfd;\n};\n\nstruct seccomp_kaddfd {\n\tstruct file *file;\n\tint fd;\n\tunsigned int flags;\n\t__u32 ioctl_flags;\n\tunion {\n\t\tbool setfd;\n\t\tint ret;\n\t};\n\tstruct completion completion;\n\tstruct list_head list;\n};\n\nstruct notification {\n\tstruct semaphore request;\n\tu64 next_id;\n\tstruct list_head notifications;\n};\n\nstruct seccomp_log_name {\n\tu32 log;\n\tconst char *name;\n};\n\nstruct rchan;\n\nstruct rchan_buf {\n\tvoid *start;\n\tvoid *data;\n\tsize_t offset;\n\tsize_t subbufs_produced;\n\tsize_t subbufs_consumed;\n\tstruct rchan *chan;\n\twait_queue_head_t read_wait;\n\tstruct irq_work wakeup_work;\n\tstruct dentry *dentry;\n\tstruct kref kref;\n\tstruct page **page_array;\n\tunsigned int page_count;\n\tunsigned int finalized;\n\tsize_t *padding;\n\tsize_t prev_padding;\n\tsize_t bytes_consumed;\n\tsize_t early_bytes;\n\tunsigned int cpu;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct rchan_callbacks;\n\nstruct rchan {\n\tu32 version;\n\tsize_t subbuf_size;\n\tsize_t n_subbufs;\n\tsize_t alloc_size;\n\tconst struct rchan_callbacks *cb;\n\tstruct kref kref;\n\tvoid *private_data;\n\tsize_t last_toobig;\n\tstruct rchan_buf **buf;\n\tint is_global;\n\tstruct list_head list;\n\tstruct dentry *parent;\n\tint has_base_filename;\n\tchar base_filename[255];\n};\n\nstruct rchan_callbacks {\n\tint (*subbuf_start)(struct rchan_buf *, void *, void *, size_t);\n\tstruct dentry * (*create_buf_file)(const char *, struct dentry *, umode_t, struct rchan_buf *, int *);\n\tint (*remove_buf_file)(struct dentry *);\n};\n\nstruct partial_page {\n\tunsigned int offset;\n\tunsigned int len;\n\tlong unsigned int private;\n};\n\nstruct splice_pipe_desc {\n\tstruct page **pages;\n\tstruct partial_page *partial;\n\tint nr_pages;\n\tunsigned int nr_pages_max;\n\tconst struct pipe_buf_operations *ops;\n\tvoid (*spd_release)(struct splice_pipe_desc *, unsigned int);\n};\n\nstruct rchan_percpu_buf_dispatcher {\n\tstruct rchan_buf *buf;\n\tstruct dentry *dentry;\n};\n\nenum {\n\tTASKSTATS_TYPE_UNSPEC = 0,\n\tTASKSTATS_TYPE_PID = 1,\n\tTASKSTATS_TYPE_TGID = 2,\n\tTASKSTATS_TYPE_STATS = 3,\n\tTASKSTATS_TYPE_AGGR_PID = 4,\n\tTASKSTATS_TYPE_AGGR_TGID = 5,\n\tTASKSTATS_TYPE_NULL = 6,\n\t__TASKSTATS_TYPE_MAX = 7,\n};\n\nenum {\n\tTASKSTATS_CMD_ATTR_UNSPEC = 0,\n\tTASKSTATS_CMD_ATTR_PID = 1,\n\tTASKSTATS_CMD_ATTR_TGID = 2,\n\tTASKSTATS_CMD_ATTR_REGISTER_CPUMASK = 3,\n\tTASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = 4,\n\t__TASKSTATS_CMD_ATTR_MAX = 5,\n};\n\nenum {\n\tCGROUPSTATS_CMD_UNSPEC = 3,\n\tCGROUPSTATS_CMD_GET = 4,\n\tCGROUPSTATS_CMD_NEW = 5,\n\t__CGROUPSTATS_CMD_MAX = 6,\n};\n\nenum {\n\tCGROUPSTATS_TYPE_UNSPEC = 0,\n\tCGROUPSTATS_TYPE_CGROUP_STATS = 1,\n\t__CGROUPSTATS_TYPE_MAX = 2,\n};\n\nenum {\n\tCGROUPSTATS_CMD_ATTR_UNSPEC = 0,\n\tCGROUPSTATS_CMD_ATTR_FD = 1,\n\t__CGROUPSTATS_CMD_ATTR_MAX = 2,\n};\n\nstruct genlmsghdr {\n\t__u8 cmd;\n\t__u8 version;\n\t__u16 reserved;\n};\n\nenum {\n\tNLA_UNSPEC = 0,\n\tNLA_U8 = 1,\n\tNLA_U16 = 2,\n\tNLA_U32 = 3,\n\tNLA_U64 = 4,\n\tNLA_STRING = 5,\n\tNLA_FLAG = 6,\n\tNLA_MSECS = 7,\n\tNLA_NESTED = 8,\n\tNLA_NESTED_ARRAY = 9,\n\tNLA_NUL_STRING = 10,\n\tNLA_BINARY = 11,\n\tNLA_S8 = 12,\n\tNLA_S16 = 13,\n\tNLA_S32 = 14,\n\tNLA_S64 = 15,\n\tNLA_BITFIELD32 = 16,\n\tNLA_REJECT = 17,\n\t__NLA_TYPE_MAX = 18,\n};\n\nstruct genl_multicast_group {\n\tchar name[16];\n\tu8 flags;\n};\n\nstruct genl_ops;\n\nstruct genl_info;\n\nstruct genl_small_ops;\n\nstruct genl_family {\n\tint id;\n\tunsigned int hdrsize;\n\tchar name[16];\n\tunsigned int version;\n\tunsigned int maxattr;\n\tunsigned int mcgrp_offset;\n\tu8 netnsok: 1;\n\tu8 parallel_ops: 1;\n\tu8 n_ops;\n\tu8 n_small_ops;\n\tu8 n_mcgrps;\n\tconst struct nla_policy *policy;\n\tint (*pre_doit)(const struct genl_ops *, struct sk_buff *, struct genl_info *);\n\tvoid (*post_doit)(const struct genl_ops *, struct sk_buff *, struct genl_info *);\n\tconst struct genl_ops *ops;\n\tconst struct genl_small_ops *small_ops;\n\tconst struct genl_multicast_group *mcgrps;\n\tstruct module *module;\n};\n\nstruct genl_ops {\n\tint (*doit)(struct sk_buff *, struct genl_info *);\n\tint (*start)(struct netlink_callback *);\n\tint (*dumpit)(struct sk_buff *, struct netlink_callback *);\n\tint (*done)(struct netlink_callback *);\n\tconst struct nla_policy *policy;\n\tunsigned int maxattr;\n\tu8 cmd;\n\tu8 internal_flags;\n\tu8 flags;\n\tu8 validate;\n};\n\nstruct genl_info {\n\tu32 snd_seq;\n\tu32 snd_portid;\n\tstruct nlmsghdr *nlhdr;\n\tstruct genlmsghdr *genlhdr;\n\tvoid *userhdr;\n\tstruct nlattr **attrs;\n\tpossible_net_t _net;\n\tvoid *user_ptr[2];\n\tstruct netlink_ext_ack *extack;\n};\n\nstruct genl_small_ops {\n\tint (*doit)(struct sk_buff *, struct genl_info *);\n\tint (*dumpit)(struct sk_buff *, struct netlink_callback *);\n\tu8 cmd;\n\tu8 internal_flags;\n\tu8 flags;\n\tu8 validate;\n};\n\nenum genl_validate_flags {\n\tGENL_DONT_VALIDATE_STRICT = 1,\n\tGENL_DONT_VALIDATE_DUMP = 2,\n\tGENL_DONT_VALIDATE_DUMP_STRICT = 4,\n};\n\nstruct listener {\n\tstruct list_head list;\n\tpid_t pid;\n\tchar valid;\n};\n\nstruct listener_list {\n\tstruct rw_semaphore sem;\n\tstruct list_head list;\n};\n\nenum actions {\n\tREGISTER = 0,\n\tDEREGISTER = 1,\n\tCPU_DONT_CARE = 2,\n};\n\nstruct tp_module {\n\tstruct list_head list;\n\tstruct module *mod;\n};\n\nenum tp_func_state {\n\tTP_FUNC_0 = 0,\n\tTP_FUNC_1 = 1,\n\tTP_FUNC_2 = 2,\n\tTP_FUNC_N = 3,\n};\n\nenum tp_transition_sync {\n\tTP_TRANSITION_SYNC_1_0_1 = 0,\n\tTP_TRANSITION_SYNC_N_2_1 = 1,\n\t_NR_TP_TRANSITION_SYNC = 2,\n};\n\nstruct tp_transition_snapshot {\n\tlong unsigned int rcu;\n\tlong unsigned int srcu;\n\tbool ongoing;\n};\n\nstruct tp_probes {\n\tstruct callback_head rcu;\n\tstruct tracepoint_func probes[0];\n};\n\nstruct ftrace_hash {\n\tlong unsigned int size_bits;\n\tstruct hlist_head *buckets;\n\tlong unsigned int count;\n\tlong unsigned int flags;\n\tstruct callback_head rcu;\n};\n\nstruct ftrace_func_entry {\n\tstruct hlist_node hlist;\n\tlong unsigned int ip;\n\tlong unsigned int direct;\n};\n\nenum ftrace_bug_type {\n\tFTRACE_BUG_UNKNOWN = 0,\n\tFTRACE_BUG_INIT = 1,\n\tFTRACE_BUG_NOP = 2,\n\tFTRACE_BUG_CALL = 3,\n\tFTRACE_BUG_UPDATE = 4,\n};\n\nenum {\n\tFTRACE_UPDATE_CALLS = 1,\n\tFTRACE_DISABLE_CALLS = 2,\n\tFTRACE_UPDATE_TRACE_FUNC = 4,\n\tFTRACE_START_FUNC_RET = 8,\n\tFTRACE_STOP_FUNC_RET = 16,\n\tFTRACE_MAY_SLEEP = 32,\n};\n\nenum {\n\tFTRACE_ITER_FILTER = 1,\n\tFTRACE_ITER_NOTRACE = 2,\n\tFTRACE_ITER_PRINTALL = 4,\n\tFTRACE_ITER_DO_PROBES = 8,\n\tFTRACE_ITER_PROBE = 16,\n\tFTRACE_ITER_MOD = 32,\n\tFTRACE_ITER_ENABLED = 64,\n};\n\nstruct ftrace_graph_ent {\n\tlong unsigned int func;\n\tint depth;\n} __attribute__((packed));\n\nstruct ftrace_graph_ret {\n\tlong unsigned int func;\n\tint depth;\n\tunsigned int overrun;\n\tlong long unsigned int calltime;\n\tlong long unsigned int rettime;\n};\n\ntypedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *);\n\ntypedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *);\n\nstruct fgraph_ops {\n\ttrace_func_graph_ent_t entryfunc;\n\ttrace_func_graph_ret_t retfunc;\n};\n\nstruct prog_entry;\n\nstruct event_filter {\n\tstruct prog_entry *prog;\n\tchar *filter_string;\n};\n\nstruct trace_array_cpu;\n\nstruct array_buffer {\n\tstruct trace_array *tr;\n\tstruct trace_buffer *buffer;\n\tstruct trace_array_cpu *data;\n\tu64 time_start;\n\tint cpu;\n};\n\nstruct trace_pid_list;\n\nstruct trace_options;\n\nstruct cond_snapshot;\n\nstruct trace_func_repeats;\n\nstruct trace_array {\n\tstruct list_head list;\n\tchar *name;\n\tstruct array_buffer array_buffer;\n\tstruct array_buffer max_buffer;\n\tbool allocated_snapshot;\n\tlong unsigned int max_latency;\n\tstruct dentry *d_max_latency;\n\tstruct work_struct fsnotify_work;\n\tstruct irq_work fsnotify_irqwork;\n\tstruct trace_pid_list *filtered_pids;\n\tstruct trace_pid_list *filtered_no_pids;\n\tarch_spinlock_t max_lock;\n\tint buffer_disabled;\n\tint sys_refcount_enter;\n\tint sys_refcount_exit;\n\tstruct trace_event_file *enter_syscall_files[448];\n\tstruct trace_event_file *exit_syscall_files[448];\n\tint stop_count;\n\tint clock_id;\n\tint nr_topts;\n\tbool clear_trace;\n\tint buffer_percent;\n\tunsigned int n_err_log_entries;\n\tstruct tracer *current_trace;\n\tunsigned int trace_flags;\n\tunsigned char trace_flags_index[32];\n\tunsigned int flags;\n\traw_spinlock_t start_lock;\n\tstruct list_head err_log;\n\tstruct dentry *dir;\n\tstruct dentry *options;\n\tstruct dentry *percpu_dir;\n\tstruct dentry *event_dir;\n\tstruct trace_options *topts;\n\tstruct list_head systems;\n\tstruct list_head events;\n\tstruct trace_event_file *trace_marker_file;\n\tcpumask_var_t tracing_cpumask;\n\tint ref;\n\tint trace_ref;\n\tstruct ftrace_ops *ops;\n\tstruct trace_pid_list *function_pids;\n\tstruct trace_pid_list *function_no_pids;\n\tstruct list_head func_probes;\n\tstruct list_head mod_trace;\n\tstruct list_head mod_notrace;\n\tint function_enabled;\n\tint no_filter_buffering_ref;\n\tstruct list_head hist_vars;\n\tstruct cond_snapshot *cond_snapshot;\n\tstruct trace_func_repeats *last_func_repeats;\n};\n\nstruct tracer_flags;\n\nstruct tracer {\n\tconst char *name;\n\tint (*init)(struct trace_array *);\n\tvoid (*reset)(struct trace_array *);\n\tvoid (*start)(struct trace_array *);\n\tvoid (*stop)(struct trace_array *);\n\tint (*update_thresh)(struct trace_array *);\n\tvoid (*open)(struct trace_iterator *);\n\tvoid (*pipe_open)(struct trace_iterator *);\n\tvoid (*close)(struct trace_iterator *);\n\tvoid (*pipe_close)(struct trace_iterator *);\n\tssize_t (*read)(struct trace_iterator *, struct file *, char *, size_t, loff_t *);\n\tssize_t (*splice_read)(struct trace_iterator *, struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);\n\tvoid (*print_header)(struct seq_file *);\n\tenum print_line_t (*print_line)(struct trace_iterator *);\n\tint (*set_flag)(struct trace_array *, u32, u32, int);\n\tint (*flag_changed)(struct trace_array *, u32, int);\n\tstruct tracer *next;\n\tstruct tracer_flags *flags;\n\tint enabled;\n\tbool print_max;\n\tbool allow_instances;\n\tbool use_max_tr;\n\tbool noboot;\n};\n\nstruct event_subsystem;\n\nstruct trace_subsystem_dir {\n\tstruct list_head list;\n\tstruct event_subsystem *subsystem;\n\tstruct trace_array *tr;\n\tstruct dentry *entry;\n\tint ref_count;\n\tint nr_events;\n};\n\nstruct trace_array_cpu {\n\tatomic_t disabled;\n\tvoid *buffer_page;\n\tlong unsigned int entries;\n\tlong unsigned int saved_latency;\n\tlong unsigned int critical_start;\n\tlong unsigned int critical_end;\n\tlong unsigned int critical_sequence;\n\tlong unsigned int nice;\n\tlong unsigned int policy;\n\tlong unsigned int rt_priority;\n\tlong unsigned int skipped_entries;\n\tu64 preempt_timestamp;\n\tpid_t pid;\n\tkuid_t uid;\n\tchar comm[16];\n\tint ftrace_ignore_pid;\n\tbool ignore_pid;\n};\n\nstruct trace_option_dentry;\n\nstruct trace_options {\n\tstruct tracer *tracer;\n\tstruct trace_option_dentry *topts;\n};\n\nstruct tracer_opt;\n\nstruct trace_option_dentry {\n\tstruct tracer_opt *opt;\n\tstruct tracer_flags *flags;\n\tstruct trace_array *tr;\n\tstruct dentry *entry;\n};\n\nstruct trace_pid_list {\n\tint pid_max;\n\tlong unsigned int *pids;\n};\n\nenum {\n\tTRACE_PIDS = 1,\n\tTRACE_NO_PIDS = 2,\n};\n\ntypedef bool (*cond_update_fn_t)(struct trace_array *, void *);\n\nstruct cond_snapshot {\n\tvoid *cond_data;\n\tcond_update_fn_t update;\n};\n\nstruct trace_func_repeats {\n\tlong unsigned int ip;\n\tlong unsigned int parent_ip;\n\tlong unsigned int count;\n\tu64 ts_last_call;\n};\n\nenum {\n\tTRACE_ARRAY_FL_GLOBAL = 1,\n};\n\nstruct tracer_opt {\n\tconst char *name;\n\tu32 bit;\n};\n\nstruct tracer_flags {\n\tu32 val;\n\tstruct tracer_opt *opts;\n\tstruct tracer *trace;\n};\n\nstruct ftrace_mod_load {\n\tstruct list_head list;\n\tchar *func;\n\tchar *module;\n\tint enable;\n};\n\nenum {\n\tFTRACE_HASH_FL_MOD = 1,\n};\n\nstruct ftrace_func_command {\n\tstruct list_head list;\n\tchar *name;\n\tint (*func)(struct trace_array *, struct ftrace_hash *, char *, char *, char *, int);\n};\n\nstruct ftrace_probe_ops {\n\tvoid (*func)(long unsigned int, long unsigned int, struct trace_array *, struct ftrace_probe_ops *, void *);\n\tint (*init)(struct ftrace_probe_ops *, struct trace_array *, long unsigned int, void *, void **);\n\tvoid (*free)(struct ftrace_probe_ops *, struct trace_array *, long unsigned int, void *);\n\tint (*print)(struct seq_file *, long unsigned int, struct ftrace_probe_ops *, void *);\n};\n\ntypedef int (*ftrace_mapper_func)(void *);\n\nstruct trace_parser {\n\tbool cont;\n\tchar *buffer;\n\tunsigned int idx;\n\tunsigned int size;\n};\n\nenum trace_iterator_bits {\n\tTRACE_ITER_PRINT_PARENT_BIT = 0,\n\tTRACE_ITER_SYM_OFFSET_BIT = 1,\n\tTRACE_ITER_SYM_ADDR_BIT = 2,\n\tTRACE_ITER_VERBOSE_BIT = 3,\n\tTRACE_ITER_RAW_BIT = 4,\n\tTRACE_ITER_HEX_BIT = 5,\n\tTRACE_ITER_BIN_BIT = 6,\n\tTRACE_ITER_BLOCK_BIT = 7,\n\tTRACE_ITER_PRINTK_BIT = 8,\n\tTRACE_ITER_ANNOTATE_BIT = 9,\n\tTRACE_ITER_USERSTACKTRACE_BIT = 10,\n\tTRACE_ITER_SYM_USEROBJ_BIT = 11,\n\tTRACE_ITER_PRINTK_MSGONLY_BIT = 12,\n\tTRACE_ITER_CONTEXT_INFO_BIT = 13,\n\tTRACE_ITER_LATENCY_FMT_BIT = 14,\n\tTRACE_ITER_RECORD_CMD_BIT = 15,\n\tTRACE_ITER_RECORD_TGID_BIT = 16,\n\tTRACE_ITER_OVERWRITE_BIT = 17,\n\tTRACE_ITER_STOP_ON_FREE_BIT = 18,\n\tTRACE_ITER_IRQ_INFO_BIT = 19,\n\tTRACE_ITER_MARKERS_BIT = 20,\n\tTRACE_ITER_EVENT_FORK_BIT = 21,\n\tTRACE_ITER_PAUSE_ON_TRACE_BIT = 22,\n\tTRACE_ITER_HASH_PTR_BIT = 23,\n\tTRACE_ITER_FUNCTION_BIT = 24,\n\tTRACE_ITER_FUNC_FORK_BIT = 25,\n\tTRACE_ITER_DISPLAY_GRAPH_BIT = 26,\n\tTRACE_ITER_STACKTRACE_BIT = 27,\n\tTRACE_ITER_LAST_BIT = 28,\n};\n\nstruct event_subsystem {\n\tstruct list_head list;\n\tconst char *name;\n\tstruct event_filter *filter;\n\tint ref_count;\n};\n\nenum regex_type {\n\tMATCH_FULL = 0,\n\tMATCH_FRONT_ONLY = 1,\n\tMATCH_MIDDLE_ONLY = 2,\n\tMATCH_END_ONLY = 3,\n\tMATCH_GLOB = 4,\n\tMATCH_INDEX = 5,\n};\n\nstruct tracer_stat {\n\tconst char *name;\n\tvoid * (*stat_start)(struct tracer_stat *);\n\tvoid * (*stat_next)(void *, int);\n\tcmp_func_t stat_cmp;\n\tint (*stat_show)(struct seq_file *, void *);\n\tvoid (*stat_release)(void *);\n\tint (*stat_headers)(struct seq_file *);\n};\n\nenum {\n\tFTRACE_MODIFY_ENABLE_FL = 1,\n\tFTRACE_MODIFY_MAY_SLEEP_FL = 2,\n};\n\nstruct ftrace_profile {\n\tstruct hlist_node node;\n\tlong unsigned int ip;\n\tlong unsigned int counter;\n\tlong long unsigned int time;\n\tlong long unsigned int time_squared;\n};\n\nstruct ftrace_profile_page {\n\tstruct ftrace_profile_page *next;\n\tlong unsigned int index;\n\tstruct ftrace_profile records[0];\n};\n\nstruct ftrace_profile_stat {\n\tatomic_t disabled;\n\tstruct hlist_head *hash;\n\tstruct ftrace_profile_page *pages;\n\tstruct ftrace_profile_page *start;\n\tstruct tracer_stat stat;\n};\n\nstruct ftrace_func_probe {\n\tstruct ftrace_probe_ops *probe_ops;\n\tstruct ftrace_ops ops;\n\tstruct trace_array *tr;\n\tstruct list_head list;\n\tvoid *data;\n\tint ref;\n};\n\nstruct ftrace_page {\n\tstruct ftrace_page *next;\n\tstruct dyn_ftrace *records;\n\tint index;\n\tint order;\n};\n\nstruct ftrace_rec_iter___2 {\n\tstruct ftrace_page *pg;\n\tint index;\n};\n\nstruct ftrace_iterator {\n\tloff_t pos;\n\tloff_t func_pos;\n\tloff_t mod_pos;\n\tstruct ftrace_page *pg;\n\tstruct dyn_ftrace *func;\n\tstruct ftrace_func_probe *probe;\n\tstruct ftrace_func_entry *probe_entry;\n\tstruct trace_parser parser;\n\tstruct ftrace_hash *hash;\n\tstruct ftrace_ops *ops;\n\tstruct trace_array *tr;\n\tstruct list_head *mod_list;\n\tint pidx;\n\tint idx;\n\tunsigned int flags;\n};\n\nstruct ftrace_glob {\n\tchar *search;\n\tunsigned int len;\n\tint type;\n};\n\nstruct ftrace_func_map {\n\tstruct ftrace_func_entry entry;\n\tvoid *data;\n};\n\nstruct ftrace_func_mapper {\n\tstruct ftrace_hash hash;\n};\n\nstruct ftrace_direct_func {\n\tstruct list_head next;\n\tlong unsigned int addr;\n\tint count;\n};\n\nenum graph_filter_type {\n\tGRAPH_FILTER_NOTRACE = 0,\n\tGRAPH_FILTER_FUNCTION = 1,\n};\n\nstruct ftrace_graph_data {\n\tstruct ftrace_hash *hash;\n\tstruct ftrace_func_entry *entry;\n\tint idx;\n\tenum graph_filter_type type;\n\tstruct ftrace_hash *new_hash;\n\tconst struct seq_operations *seq_ops;\n\tstruct trace_parser parser;\n};\n\nstruct ftrace_mod_func {\n\tstruct list_head list;\n\tchar *name;\n\tlong unsigned int ip;\n\tunsigned int size;\n};\n\nstruct ftrace_mod_map {\n\tstruct callback_head rcu;\n\tstruct list_head list;\n\tstruct module *mod;\n\tlong unsigned int start_addr;\n\tlong unsigned int end_addr;\n\tstruct list_head funcs;\n\tunsigned int num_funcs;\n};\n\nstruct ftrace_init_func {\n\tstruct list_head list;\n\tlong unsigned int ip;\n};\n\nenum ring_buffer_type {\n\tRINGBUF_TYPE_DATA_TYPE_LEN_MAX = 28,\n\tRINGBUF_TYPE_PADDING = 29,\n\tRINGBUF_TYPE_TIME_EXTEND = 30,\n\tRINGBUF_TYPE_TIME_STAMP = 31,\n};\n\nenum ring_buffer_flags {\n\tRB_FL_OVERWRITE = 1,\n};\n\nstruct ring_buffer_per_cpu;\n\nstruct buffer_page;\n\nstruct ring_buffer_iter {\n\tstruct ring_buffer_per_cpu *cpu_buffer;\n\tlong unsigned int head;\n\tlong unsigned int next_event;\n\tstruct buffer_page *head_page;\n\tstruct buffer_page *cache_reader_page;\n\tlong unsigned int cache_read;\n\tu64 read_stamp;\n\tu64 page_stamp;\n\tstruct ring_buffer_event *event;\n\tint missed_events;\n};\n\nstruct rb_irq_work {\n\tstruct irq_work work;\n\twait_queue_head_t waiters;\n\twait_queue_head_t full_waiters;\n\tbool waiters_pending;\n\tbool full_waiters_pending;\n\tbool wakeup_full;\n};\n\nstruct trace_buffer___2 {\n\tunsigned int flags;\n\tint cpus;\n\tatomic_t record_disabled;\n\tcpumask_var_t cpumask;\n\tstruct lock_class_key *reader_lock_key;\n\tstruct mutex mutex;\n\tstruct ring_buffer_per_cpu **buffers;\n\tstruct hlist_node node;\n\tu64 (*clock)();\n\tstruct rb_irq_work irq_work;\n\tbool time_stamp_abs;\n};\n\nenum {\n\tRB_LEN_TIME_EXTEND = 8,\n\tRB_LEN_TIME_STAMP = 8,\n};\n\nstruct buffer_data_page {\n\tu64 time_stamp;\n\tlocal_t commit;\n\tunsigned char data[0];\n};\n\nstruct buffer_page {\n\tstruct list_head list;\n\tlocal_t write;\n\tunsigned int read;\n\tlocal_t entries;\n\tlong unsigned int real_end;\n\tstruct buffer_data_page *page;\n};\n\nstruct rb_event_info {\n\tu64 ts;\n\tu64 delta;\n\tu64 before;\n\tu64 after;\n\tlong unsigned int length;\n\tstruct buffer_page *tail_page;\n\tint add_timestamp;\n};\n\nenum {\n\tRB_ADD_STAMP_NONE = 0,\n\tRB_ADD_STAMP_EXTEND = 2,\n\tRB_ADD_STAMP_ABSOLUTE = 4,\n\tRB_ADD_STAMP_FORCE = 8,\n};\n\nenum {\n\tRB_CTX_TRANSITION = 0,\n\tRB_CTX_NMI = 1,\n\tRB_CTX_IRQ = 2,\n\tRB_CTX_SOFTIRQ = 3,\n\tRB_CTX_NORMAL = 4,\n\tRB_CTX_MAX = 5,\n};\n\nstruct rb_time_struct {\n\tlocal64_t time;\n};\n\ntypedef struct rb_time_struct rb_time_t;\n\nstruct ring_buffer_per_cpu {\n\tint cpu;\n\tatomic_t record_disabled;\n\tatomic_t resize_disabled;\n\tstruct trace_buffer___2 *buffer;\n\traw_spinlock_t reader_lock;\n\tarch_spinlock_t lock;\n\tstruct lock_class_key lock_key;\n\tstruct buffer_data_page *free_page;\n\tlong unsigned int nr_pages;\n\tunsigned int current_context;\n\tstruct list_head *pages;\n\tstruct buffer_page *head_page;\n\tstruct buffer_page *tail_page;\n\tstruct buffer_page *commit_page;\n\tstruct buffer_page *reader_page;\n\tlong unsigned int lost_events;\n\tlong unsigned int last_overrun;\n\tlong unsigned int nest;\n\tlocal_t entries_bytes;\n\tlocal_t entries;\n\tlocal_t overrun;\n\tlocal_t commit_overrun;\n\tlocal_t dropped_events;\n\tlocal_t committing;\n\tlocal_t commits;\n\tlocal_t pages_touched;\n\tlocal_t pages_read;\n\tlong int last_pages_touch;\n\tsize_t shortest_full;\n\tlong unsigned int read;\n\tlong unsigned int read_bytes;\n\trb_time_t write_stamp;\n\trb_time_t before_stamp;\n\tu64 event_stamp[5];\n\tu64 read_stamp;\n\tlong int nr_pages_to_update;\n\tstruct list_head new_pages;\n\tstruct work_struct update_pages_work;\n\tstruct completion update_done;\n\tstruct rb_irq_work irq_work;\n};\n\ntypedef struct vfsmount * (*debugfs_automount_t)(struct dentry *, void *);\n\nstruct trace_export {\n\tstruct trace_export *next;\n\tvoid (*write)(struct trace_export *, const void *, unsigned int);\n\tint flags;\n};\n\nenum fsnotify_data_type {\n\tFSNOTIFY_EVENT_NONE = 0,\n\tFSNOTIFY_EVENT_PATH = 1,\n\tFSNOTIFY_EVENT_INODE = 2,\n};\n\nenum trace_iter_flags {\n\tTRACE_FILE_LAT_FMT = 1,\n\tTRACE_FILE_ANNOTATE = 2,\n\tTRACE_FILE_TIME_IN_NS = 4,\n};\n\nenum trace_flag_type {\n\tTRACE_FLAG_IRQS_OFF = 1,\n\tTRACE_FLAG_IRQS_NOSUPPORT = 2,\n\tTRACE_FLAG_NEED_RESCHED = 4,\n\tTRACE_FLAG_HARDIRQ = 8,\n\tTRACE_FLAG_SOFTIRQ = 16,\n\tTRACE_FLAG_PREEMPT_RESCHED = 32,\n\tTRACE_FLAG_NMI = 64,\n};\n\nenum trace_type {\n\t__TRACE_FIRST_TYPE = 0,\n\tTRACE_FN = 1,\n\tTRACE_CTX = 2,\n\tTRACE_WAKE = 3,\n\tTRACE_STACK = 4,\n\tTRACE_PRINT = 5,\n\tTRACE_BPRINT = 6,\n\tTRACE_MMIO_RW = 7,\n\tTRACE_MMIO_MAP = 8,\n\tTRACE_BRANCH = 9,\n\tTRACE_GRAPH_RET = 10,\n\tTRACE_GRAPH_ENT = 11,\n\tTRACE_USER_STACK = 12,\n\tTRACE_BLK = 13,\n\tTRACE_BPUTS = 14,\n\tTRACE_HWLAT = 15,\n\tTRACE_OSNOISE = 16,\n\tTRACE_TIMERLAT = 17,\n\tTRACE_RAW_DATA = 18,\n\tTRACE_FUNC_REPEATS = 19,\n\t__TRACE_LAST_TYPE = 20,\n};\n\nstruct ftrace_entry {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n\tlong unsigned int parent_ip;\n};\n\nstruct stack_entry {\n\tstruct trace_entry ent;\n\tint size;\n\tlong unsigned int caller[8];\n};\n\nstruct userstack_entry {\n\tstruct trace_entry ent;\n\tunsigned int tgid;\n\tlong unsigned int caller[8];\n};\n\nstruct bprint_entry {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n\tconst char *fmt;\n\tu32 buf[0];\n};\n\nstruct print_entry {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n\tchar buf[0];\n};\n\nstruct raw_data_entry {\n\tstruct trace_entry ent;\n\tunsigned int id;\n\tchar buf[0];\n};\n\nstruct bputs_entry {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n\tconst char *str;\n};\n\nstruct func_repeats_entry {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n\tlong unsigned int parent_ip;\n\tu16 count;\n\tu16 top_delta_ts;\n\tu32 bottom_delta_ts;\n};\n\nenum trace_iterator_flags {\n\tTRACE_ITER_PRINT_PARENT = 1,\n\tTRACE_ITER_SYM_OFFSET = 2,\n\tTRACE_ITER_SYM_ADDR = 4,\n\tTRACE_ITER_VERBOSE = 8,\n\tTRACE_ITER_RAW = 16,\n\tTRACE_ITER_HEX = 32,\n\tTRACE_ITER_BIN = 64,\n\tTRACE_ITER_BLOCK = 128,\n\tTRACE_ITER_PRINTK = 256,\n\tTRACE_ITER_ANNOTATE = 512,\n\tTRACE_ITER_USERSTACKTRACE = 1024,\n\tTRACE_ITER_SYM_USEROBJ = 2048,\n\tTRACE_ITER_PRINTK_MSGONLY = 4096,\n\tTRACE_ITER_CONTEXT_INFO = 8192,\n\tTRACE_ITER_LATENCY_FMT = 16384,\n\tTRACE_ITER_RECORD_CMD = 32768,\n\tTRACE_ITER_RECORD_TGID = 65536,\n\tTRACE_ITER_OVERWRITE = 131072,\n\tTRACE_ITER_STOP_ON_FREE = 262144,\n\tTRACE_ITER_IRQ_INFO = 524288,\n\tTRACE_ITER_MARKERS = 1048576,\n\tTRACE_ITER_EVENT_FORK = 2097152,\n\tTRACE_ITER_PAUSE_ON_TRACE = 4194304,\n\tTRACE_ITER_HASH_PTR = 8388608,\n\tTRACE_ITER_FUNCTION = 16777216,\n\tTRACE_ITER_FUNC_FORK = 33554432,\n\tTRACE_ITER_DISPLAY_GRAPH = 67108864,\n\tTRACE_ITER_STACKTRACE = 134217728,\n};\n\nstruct trace_min_max_param {\n\tstruct mutex *lock;\n\tu64 *val;\n\tu64 *min;\n\tu64 *max;\n};\n\nstruct saved_cmdlines_buffer {\n\tunsigned int map_pid_to_cmdline[32769];\n\tunsigned int *map_cmdline_to_pid;\n\tunsigned int cmdline_num;\n\tint cmdline_idx;\n\tchar *saved_cmdlines;\n};\n\nstruct ftrace_stack {\n\tlong unsigned int calls[1024];\n};\n\nstruct ftrace_stacks {\n\tstruct ftrace_stack stacks[4];\n};\n\nstruct trace_buffer_struct {\n\tint nesting;\n\tchar buffer[4096];\n};\n\nstruct ftrace_buffer_info {\n\tstruct trace_iterator iter;\n\tvoid *spare;\n\tunsigned int spare_cpu;\n\tunsigned int read;\n};\n\nstruct err_info {\n\tconst char **errs;\n\tu8 type;\n\tu8 pos;\n\tu64 ts;\n};\n\nstruct tracing_log_err {\n\tstruct list_head list;\n\tstruct err_info info;\n\tchar loc[128];\n\tchar cmd[256];\n};\n\nstruct buffer_ref {\n\tstruct trace_buffer *buffer;\n\tvoid *page;\n\tint cpu;\n\trefcount_t refcount;\n};\n\nstruct ftrace_func_mapper___2;\n\nstruct ctx_switch_entry {\n\tstruct trace_entry ent;\n\tunsigned int prev_pid;\n\tunsigned int next_pid;\n\tunsigned int next_cpu;\n\tunsigned char prev_prio;\n\tunsigned char prev_state;\n\tunsigned char next_prio;\n\tunsigned char next_state;\n};\n\nstruct hwlat_entry {\n\tstruct trace_entry ent;\n\tu64 duration;\n\tu64 outer_duration;\n\tu64 nmi_total_ts;\n\tstruct timespec64 timestamp;\n\tunsigned int nmi_count;\n\tunsigned int seqnum;\n\tunsigned int count;\n};\n\nstruct osnoise_entry {\n\tstruct trace_entry ent;\n\tu64 noise;\n\tu64 runtime;\n\tu64 max_sample;\n\tunsigned int hw_count;\n\tunsigned int nmi_count;\n\tunsigned int irq_count;\n\tunsigned int softirq_count;\n\tunsigned int thread_count;\n};\n\nstruct timerlat_entry {\n\tstruct trace_entry ent;\n\tunsigned int seqnum;\n\tint context;\n\tu64 timer_latency;\n};\n\nstruct trace_mark {\n\tlong long unsigned int val;\n\tchar sym;\n};\n\nstruct stat_node {\n\tstruct rb_node node;\n\tvoid *stat;\n};\n\nstruct stat_session {\n\tstruct list_head session_list;\n\tstruct tracer_stat *ts;\n\tstruct rb_root stat_root;\n\tstruct mutex stat_mutex;\n\tstruct dentry *file;\n};\n\nstruct trace_bprintk_fmt {\n\tstruct list_head list;\n\tconst char *fmt;\n};\n\ntypedef int (*tracing_map_cmp_fn_t)(void *, void *);\n\nstruct tracing_map_field {\n\ttracing_map_cmp_fn_t cmp_fn;\n\tunion {\n\t\tatomic64_t sum;\n\t\tunsigned int offset;\n\t};\n};\n\nstruct tracing_map;\n\nstruct tracing_map_elt {\n\tstruct tracing_map *map;\n\tstruct tracing_map_field *fields;\n\tatomic64_t *vars;\n\tbool *var_set;\n\tvoid *key;\n\tvoid *private_data;\n};\n\nstruct tracing_map_sort_key {\n\tunsigned int field_idx;\n\tbool descending;\n};\n\nstruct tracing_map_array;\n\nstruct tracing_map_ops;\n\nstruct tracing_map {\n\tunsigned int key_size;\n\tunsigned int map_bits;\n\tunsigned int map_size;\n\tunsigned int max_elts;\n\tatomic_t next_elt;\n\tstruct tracing_map_array *elts;\n\tstruct tracing_map_array *map;\n\tconst struct tracing_map_ops *ops;\n\tvoid *private_data;\n\tstruct tracing_map_field fields[6];\n\tunsigned int n_fields;\n\tint key_idx[3];\n\tunsigned int n_keys;\n\tstruct tracing_map_sort_key sort_key;\n\tunsigned int n_vars;\n\tatomic64_t hits;\n\tatomic64_t drops;\n};\n\nstruct tracing_map_entry {\n\tu32 key;\n\tstruct tracing_map_elt *val;\n};\n\nstruct tracing_map_sort_entry {\n\tvoid *key;\n\tstruct tracing_map_elt *elt;\n\tbool elt_copied;\n\tbool dup;\n};\n\nstruct tracing_map_array {\n\tunsigned int entries_per_page;\n\tunsigned int entry_size_shift;\n\tunsigned int entry_shift;\n\tunsigned int entry_mask;\n\tunsigned int n_pages;\n\tvoid **pages;\n};\n\nstruct tracing_map_ops {\n\tint (*elt_alloc)(struct tracing_map_elt *);\n\tvoid (*elt_free)(struct tracing_map_elt *);\n\tvoid (*elt_clear)(struct tracing_map_elt *);\n\tvoid (*elt_init)(struct tracing_map_elt *);\n};\n\nenum {\n\tTRACE_FUNC_NO_OPTS = 0,\n\tTRACE_FUNC_OPT_STACK = 1,\n\tTRACE_FUNC_OPT_NO_REPEATS = 2,\n\tTRACE_FUNC_OPT_HIGHEST_BIT = 4,\n};\n\nenum {\n\tMODE_NONE = 0,\n\tMODE_ROUND_ROBIN = 1,\n\tMODE_PER_CPU = 2,\n\tMODE_MAX = 3,\n};\n\nstruct hwlat_kthread_data {\n\tstruct task_struct *kthread;\n\tu64 nmi_ts_start;\n\tu64 nmi_total_ts;\n\tint nmi_count;\n\tint nmi_cpu;\n};\n\nstruct hwlat_sample {\n\tu64 seqnum;\n\tu64 duration;\n\tu64 outer_duration;\n\tu64 nmi_total_ts;\n\tstruct timespec64 timestamp;\n\tint nmi_count;\n\tint count;\n};\n\nstruct hwlat_data {\n\tstruct mutex lock;\n\tu64 count;\n\tu64 sample_window;\n\tu64 sample_width;\n\tint thread_mode;\n};\n\nstruct trace_event_raw_thread_noise {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tu64 start;\n\tu64 duration;\n\tpid_t pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_softirq_noise {\n\tstruct trace_entry ent;\n\tu64 start;\n\tu64 duration;\n\tint vector;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_irq_noise {\n\tstruct trace_entry ent;\n\tu64 start;\n\tu64 duration;\n\tu32 __data_loc_desc;\n\tint vector;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_nmi_noise {\n\tstruct trace_entry ent;\n\tu64 start;\n\tu64 duration;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sample_threshold {\n\tstruct trace_entry ent;\n\tu64 start;\n\tu64 duration;\n\tu64 interference;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_thread_noise {};\n\nstruct trace_event_data_offsets_softirq_noise {};\n\nstruct trace_event_data_offsets_irq_noise {\n\tu32 desc;\n};\n\nstruct trace_event_data_offsets_nmi_noise {};\n\nstruct trace_event_data_offsets_sample_threshold {};\n\ntypedef void (*btf_trace_thread_noise)(void *, struct task_struct *, u64, u64);\n\ntypedef void (*btf_trace_softirq_noise)(void *, int, u64, u64);\n\ntypedef void (*btf_trace_irq_noise)(void *, int, const char *, u64, u64);\n\ntypedef void (*btf_trace_nmi_noise)(void *, u64, u64);\n\ntypedef void (*btf_trace_sample_threshold)(void *, u64, u64, u64);\n\nstruct osn_nmi {\n\tu64 count;\n\tu64 delta_start;\n};\n\nstruct osn_irq {\n\tu64 count;\n\tu64 arrival_time;\n\tu64 delta_start;\n};\n\nstruct osn_softirq {\n\tu64 count;\n\tu64 arrival_time;\n\tu64 delta_start;\n};\n\nstruct osn_thread {\n\tu64 count;\n\tu64 arrival_time;\n\tu64 delta_start;\n};\n\nstruct osnoise_variables {\n\tstruct task_struct *kthread;\n\tbool sampling;\n\tpid_t pid;\n\tstruct osn_nmi nmi;\n\tstruct osn_irq irq;\n\tstruct osn_softirq softirq;\n\tstruct osn_thread thread;\n\tlocal_t int_counter;\n};\n\nstruct timerlat_variables {\n\tstruct task_struct *kthread;\n\tstruct hrtimer timer;\n\tu64 rel_period;\n\tu64 abs_period;\n\tbool tracing_thread;\n\tu64 count;\n};\n\nstruct osnoise_sample {\n\tu64 runtime;\n\tu64 noise;\n\tu64 max_sample;\n\tint hw_count;\n\tint nmi_count;\n\tint irq_count;\n\tint softirq_count;\n\tint thread_count;\n};\n\nstruct timerlat_sample {\n\tu64 timer_latency;\n\tunsigned int seqnum;\n\tint context;\n};\n\nstruct osnoise_data {\n\tu64 sample_period;\n\tu64 sample_runtime;\n\tu64 stop_tracing;\n\tu64 stop_tracing_total;\n\tu64 timerlat_period;\n\tu64 print_stack;\n\tint timerlat_tracer;\n\tbool tainted;\n};\n\nstruct trace_stack {\n\tint stack_size;\n\tint nr_entries;\n\tlong unsigned int calls[256];\n};\n\nenum {\n\tTRACE_NOP_OPT_ACCEPT = 1,\n\tTRACE_NOP_OPT_REFUSE = 2,\n};\n\nstruct trace_mmiotrace_rw {\n\tstruct trace_entry ent;\n\tstruct mmiotrace_rw rw;\n};\n\nstruct trace_mmiotrace_map {\n\tstruct trace_entry ent;\n\tstruct mmiotrace_map map;\n};\n\nstruct header_iter {\n\tstruct pci_dev *dev;\n};\n\nstruct ftrace_graph_ent_entry {\n\tstruct trace_entry ent;\n\tstruct ftrace_graph_ent graph_ent;\n} __attribute__((packed));\n\nstruct ftrace_graph_ret_entry {\n\tstruct trace_entry ent;\n\tstruct ftrace_graph_ret ret;\n};\n\nstruct fgraph_cpu_data {\n\tpid_t last_pid;\n\tint depth;\n\tint depth_irq;\n\tint ignore;\n\tlong unsigned int enter_funcs[50];\n};\n\nstruct fgraph_data {\n\tstruct fgraph_cpu_data *cpu_data;\n\tstruct ftrace_graph_ent_entry ent;\n\tstruct ftrace_graph_ret_entry ret;\n\tint failed;\n\tint cpu;\n\tint: 32;\n} __attribute__((packed));\n\nenum {\n\tFLAGS_FILL_FULL = 268435456,\n\tFLAGS_FILL_START = 536870912,\n\tFLAGS_FILL_END = 805306368,\n};\n\nstruct disk_stats {\n\tu64 nsecs[4];\n\tlong unsigned int sectors[4];\n\tlong unsigned int ios[4];\n\tlong unsigned int merges[4];\n\tlong unsigned int io_ticks;\n\tlocal_t in_flight[2];\n};\n\nstruct blk_crypto_key;\n\nstruct bio_crypt_ctx {\n\tconst struct blk_crypto_key *bc_key;\n\tu64 bc_dun[4];\n};\n\ntypedef __u32 blk_mq_req_flags_t;\n\nstruct blk_mq_ctxs;\n\nstruct blk_mq_ctx {\n\tstruct {\n\t\tspinlock_t lock;\n\t\tstruct list_head rq_lists[3];\n\t\tlong: 64;\n\t};\n\tunsigned int cpu;\n\tshort unsigned int index_hw[3];\n\tstruct blk_mq_hw_ctx *hctxs[3];\n\tlong unsigned int rq_dispatched[2];\n\tlong unsigned int rq_merged;\n\tlong unsigned int rq_completed[2];\n\tstruct request_queue *queue;\n\tstruct blk_mq_ctxs *ctxs;\n\tstruct kobject kobj;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct blk_mq_tags;\n\nstruct blk_mq_hw_ctx {\n\tstruct {\n\t\tspinlock_t lock;\n\t\tstruct list_head dispatch;\n\t\tlong unsigned int state;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct delayed_work run_work;\n\tcpumask_var_t cpumask;\n\tint next_cpu;\n\tint next_cpu_batch;\n\tlong unsigned int flags;\n\tvoid *sched_data;\n\tstruct request_queue *queue;\n\tstruct blk_flush_queue *fq;\n\tvoid *driver_data;\n\tstruct sbitmap ctx_map;\n\tstruct blk_mq_ctx *dispatch_from;\n\tunsigned int dispatch_busy;\n\tshort unsigned int type;\n\tshort unsigned int nr_ctx;\n\tstruct blk_mq_ctx **ctxs;\n\tspinlock_t dispatch_wait_lock;\n\twait_queue_entry_t dispatch_wait;\n\tatomic_t wait_index;\n\tstruct blk_mq_tags *tags;\n\tstruct blk_mq_tags *sched_tags;\n\tlong unsigned int queued;\n\tlong unsigned int run;\n\tlong unsigned int dispatched[7];\n\tunsigned int numa_node;\n\tunsigned int queue_num;\n\tatomic_t nr_active;\n\tstruct hlist_node cpuhp_online;\n\tstruct hlist_node cpuhp_dead;\n\tstruct kobject kobj;\n\tlong unsigned int poll_considered;\n\tlong unsigned int poll_invoked;\n\tlong unsigned int poll_success;\n\tstruct dentry *debugfs_dir;\n\tstruct dentry *sched_debugfs_dir;\n\tstruct list_head hctx_list;\n\tstruct srcu_struct srcu[0];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct blk_mq_alloc_data {\n\tstruct request_queue *q;\n\tblk_mq_req_flags_t flags;\n\tunsigned int shallow_depth;\n\tunsigned int cmd_flags;\n\tstruct blk_mq_ctx *ctx;\n\tstruct blk_mq_hw_ctx *hctx;\n};\n\nstruct blk_stat_callback {\n\tstruct list_head list;\n\tstruct timer_list timer;\n\tstruct blk_rq_stat *cpu_stat;\n\tint (*bucket_fn)(const struct request *);\n\tunsigned int buckets;\n\tstruct blk_rq_stat *stat;\n\tvoid (*timer_fn)(struct blk_stat_callback *);\n\tvoid *data;\n\tstruct callback_head rcu;\n};\n\nstruct blk_trace {\n\tint trace_state;\n\tstruct rchan *rchan;\n\tlong unsigned int *sequence;\n\tunsigned char *msg_data;\n\tu16 act_mask;\n\tu64 start_lba;\n\tu64 end_lba;\n\tu32 pid;\n\tu32 dev;\n\tstruct dentry *dir;\n\tstruct list_head running_list;\n\tatomic_t dropped;\n};\n\nstruct blk_flush_queue {\n\tunsigned int flush_pending_idx: 1;\n\tunsigned int flush_running_idx: 1;\n\tblk_status_t rq_status;\n\tlong unsigned int flush_pending_since;\n\tstruct list_head flush_queue[2];\n\tstruct list_head flush_data_in_flight;\n\tstruct request *flush_rq;\n\tspinlock_t mq_flush_lock;\n};\n\nstruct blk_mq_queue_map {\n\tunsigned int *mq_map;\n\tunsigned int nr_queues;\n\tunsigned int queue_offset;\n};\n\nstruct blk_mq_tag_set {\n\tstruct blk_mq_queue_map map[3];\n\tunsigned int nr_maps;\n\tconst struct blk_mq_ops *ops;\n\tunsigned int nr_hw_queues;\n\tunsigned int queue_depth;\n\tunsigned int reserved_tags;\n\tunsigned int cmd_size;\n\tint numa_node;\n\tunsigned int timeout;\n\tunsigned int flags;\n\tvoid *driver_data;\n\tatomic_t active_queues_shared_sbitmap;\n\tstruct sbitmap_queue __bitmap_tags;\n\tstruct sbitmap_queue __breserved_tags;\n\tstruct blk_mq_tags **tags;\n\tstruct mutex tag_list_lock;\n\tstruct list_head tag_list;\n};\n\ntypedef u64 compat_u64;\n\nenum blktrace_cat {\n\tBLK_TC_READ = 1,\n\tBLK_TC_WRITE = 2,\n\tBLK_TC_FLUSH = 4,\n\tBLK_TC_SYNC = 8,\n\tBLK_TC_SYNCIO = 8,\n\tBLK_TC_QUEUE = 16,\n\tBLK_TC_REQUEUE = 32,\n\tBLK_TC_ISSUE = 64,\n\tBLK_TC_COMPLETE = 128,\n\tBLK_TC_FS = 256,\n\tBLK_TC_PC = 512,\n\tBLK_TC_NOTIFY = 1024,\n\tBLK_TC_AHEAD = 2048,\n\tBLK_TC_META = 4096,\n\tBLK_TC_DISCARD = 8192,\n\tBLK_TC_DRV_DATA = 16384,\n\tBLK_TC_FUA = 32768,\n\tBLK_TC_END = 32768,\n};\n\nenum blktrace_act {\n\t__BLK_TA_QUEUE = 1,\n\t__BLK_TA_BACKMERGE = 2,\n\t__BLK_TA_FRONTMERGE = 3,\n\t__BLK_TA_GETRQ = 4,\n\t__BLK_TA_SLEEPRQ = 5,\n\t__BLK_TA_REQUEUE = 6,\n\t__BLK_TA_ISSUE = 7,\n\t__BLK_TA_COMPLETE = 8,\n\t__BLK_TA_PLUG = 9,\n\t__BLK_TA_UNPLUG_IO = 10,\n\t__BLK_TA_UNPLUG_TIMER = 11,\n\t__BLK_TA_INSERT = 12,\n\t__BLK_TA_SPLIT = 13,\n\t__BLK_TA_BOUNCE = 14,\n\t__BLK_TA_REMAP = 15,\n\t__BLK_TA_ABORT = 16,\n\t__BLK_TA_DRV_DATA = 17,\n\t__BLK_TA_CGROUP = 256,\n};\n\nenum blktrace_notify {\n\t__BLK_TN_PROCESS = 0,\n\t__BLK_TN_TIMESTAMP = 1,\n\t__BLK_TN_MESSAGE = 2,\n\t__BLK_TN_CGROUP = 256,\n};\n\nstruct blk_io_trace {\n\t__u32 magic;\n\t__u32 sequence;\n\t__u64 time;\n\t__u64 sector;\n\t__u32 bytes;\n\t__u32 action;\n\t__u32 pid;\n\t__u32 device;\n\t__u32 cpu;\n\t__u16 error;\n\t__u16 pdu_len;\n};\n\nstruct blk_io_trace_remap {\n\t__be32 device_from;\n\t__be32 device_to;\n\t__be64 sector_from;\n};\n\nenum {\n\tBlktrace_setup = 1,\n\tBlktrace_running = 2,\n\tBlktrace_stopped = 3,\n};\n\nstruct blk_user_trace_setup {\n\tchar name[32];\n\t__u16 act_mask;\n\t__u32 buf_size;\n\t__u32 buf_nr;\n\t__u64 start_lba;\n\t__u64 end_lba;\n\t__u32 pid;\n};\n\nstruct compat_blk_user_trace_setup {\n\tchar name[32];\n\tu16 act_mask;\n\tshort: 16;\n\tu32 buf_size;\n\tu32 buf_nr;\n\tcompat_u64 start_lba;\n\tcompat_u64 end_lba;\n\tu32 pid;\n} __attribute__((packed));\n\nstruct blk_mq_tags {\n\tunsigned int nr_tags;\n\tunsigned int nr_reserved_tags;\n\tatomic_t active_queues;\n\tstruct sbitmap_queue *bitmap_tags;\n\tstruct sbitmap_queue *breserved_tags;\n\tstruct sbitmap_queue __bitmap_tags;\n\tstruct sbitmap_queue __breserved_tags;\n\tstruct request **rqs;\n\tstruct request **static_rqs;\n\tstruct list_head page_list;\n\tspinlock_t lock;\n};\n\nstruct blk_mq_queue_data {\n\tstruct request *rq;\n\tbool last;\n};\n\nenum blk_crypto_mode_num {\n\tBLK_ENCRYPTION_MODE_INVALID = 0,\n\tBLK_ENCRYPTION_MODE_AES_256_XTS = 1,\n\tBLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV = 2,\n\tBLK_ENCRYPTION_MODE_ADIANTUM = 3,\n\tBLK_ENCRYPTION_MODE_MAX = 4,\n};\n\nstruct blk_crypto_config {\n\tenum blk_crypto_mode_num crypto_mode;\n\tunsigned int data_unit_size;\n\tunsigned int dun_bytes;\n};\n\nstruct blk_crypto_key {\n\tstruct blk_crypto_config crypto_cfg;\n\tunsigned int data_unit_size_bits;\n\tunsigned int size;\n\tu8 raw[64];\n};\n\nstruct blk_mq_ctxs {\n\tstruct kobject kobj;\n\tstruct blk_mq_ctx *queue_ctx;\n};\n\ntypedef void blk_log_action_t(struct trace_iterator *, const char *, bool);\n\nstruct ftrace_event_field {\n\tstruct list_head link;\n\tconst char *name;\n\tconst char *type;\n\tint filter_type;\n\tint offset;\n\tint size;\n\tint is_signed;\n};\n\nenum {\n\tFORMAT_HEADER = 1,\n\tFORMAT_FIELD_SEPERATOR = 2,\n\tFORMAT_PRINTFMT = 3,\n};\n\nstruct event_probe_data {\n\tstruct trace_event_file *file;\n\tlong unsigned int count;\n\tint ref;\n\tbool enable;\n};\n\nstruct syscall_trace_enter {\n\tstruct trace_entry ent;\n\tint nr;\n\tlong unsigned int args[0];\n};\n\nstruct syscall_trace_exit {\n\tstruct trace_entry ent;\n\tint nr;\n\tlong int ret;\n};\n\nstruct syscall_tp_t {\n\tlong long unsigned int regs;\n\tlong unsigned int syscall_nr;\n\tlong unsigned int ret;\n};\n\nstruct syscall_tp_t___2 {\n\tlong long unsigned int regs;\n\tlong unsigned int syscall_nr;\n\tlong unsigned int args[6];\n};\n\ntypedef long unsigned int perf_trace_t[256];\n\nstruct filter_pred;\n\nstruct prog_entry {\n\tint target;\n\tint when_to_branch;\n\tstruct filter_pred *pred;\n};\n\ntypedef int (*filter_pred_fn_t)(struct filter_pred *, void *);\n\nstruct regex;\n\ntypedef int (*regex_match_func)(char *, struct regex *, int);\n\nstruct regex {\n\tchar pattern[256];\n\tint len;\n\tint field_len;\n\tregex_match_func match;\n};\n\nstruct filter_pred {\n\tfilter_pred_fn_t fn;\n\tu64 val;\n\tstruct regex regex;\n\tshort unsigned int *ops;\n\tstruct ftrace_event_field *field;\n\tint offset;\n\tint not;\n\tint op;\n};\n\nenum filter_op_ids {\n\tOP_GLOB = 0,\n\tOP_NE = 1,\n\tOP_EQ = 2,\n\tOP_LE = 3,\n\tOP_LT = 4,\n\tOP_GE = 5,\n\tOP_GT = 6,\n\tOP_BAND = 7,\n\tOP_MAX = 8,\n};\n\nenum {\n\tFILT_ERR_NONE = 0,\n\tFILT_ERR_INVALID_OP = 1,\n\tFILT_ERR_TOO_MANY_OPEN = 2,\n\tFILT_ERR_TOO_MANY_CLOSE = 3,\n\tFILT_ERR_MISSING_QUOTE = 4,\n\tFILT_ERR_OPERAND_TOO_LONG = 5,\n\tFILT_ERR_EXPECT_STRING = 6,\n\tFILT_ERR_EXPECT_DIGIT = 7,\n\tFILT_ERR_ILLEGAL_FIELD_OP = 8,\n\tFILT_ERR_FIELD_NOT_FOUND = 9,\n\tFILT_ERR_ILLEGAL_INTVAL = 10,\n\tFILT_ERR_BAD_SUBSYS_FILTER = 11,\n\tFILT_ERR_TOO_MANY_PREDS = 12,\n\tFILT_ERR_INVALID_FILTER = 13,\n\tFILT_ERR_IP_FIELD_ONLY = 14,\n\tFILT_ERR_INVALID_VALUE = 15,\n\tFILT_ERR_ERRNO = 16,\n\tFILT_ERR_NO_FILTER = 17,\n};\n\nstruct filter_parse_error {\n\tint lasterr;\n\tint lasterr_pos;\n};\n\ntypedef int (*parse_pred_fn)(const char *, void *, int, struct filter_parse_error *, struct filter_pred **);\n\nenum {\n\tINVERT = 1,\n\tPROCESS_AND = 2,\n\tPROCESS_OR = 4,\n};\n\nenum {\n\tTOO_MANY_CLOSE = 4294967295,\n\tTOO_MANY_OPEN = 4294967294,\n\tMISSING_QUOTE = 4294967293,\n};\n\nstruct filter_list {\n\tstruct list_head list;\n\tstruct event_filter *filter;\n};\n\nstruct function_filter_data {\n\tstruct ftrace_ops *ops;\n\tint first_filter;\n\tint first_notrace;\n};\n\nstruct event_trigger_ops;\n\nstruct event_command;\n\nstruct event_trigger_data {\n\tlong unsigned int count;\n\tint ref;\n\tstruct event_trigger_ops *ops;\n\tstruct event_command *cmd_ops;\n\tstruct event_filter *filter;\n\tchar *filter_str;\n\tvoid *private_data;\n\tbool paused;\n\tbool paused_tmp;\n\tstruct list_head list;\n\tchar *name;\n\tstruct list_head named_list;\n\tstruct event_trigger_data *named_data;\n};\n\nstruct event_trigger_ops {\n\tvoid (*func)(struct event_trigger_data *, struct trace_buffer *, void *, struct ring_buffer_event *);\n\tint (*init)(struct event_trigger_ops *, struct event_trigger_data *);\n\tvoid (*free)(struct event_trigger_ops *, struct event_trigger_data *);\n\tint (*print)(struct seq_file *, struct event_trigger_ops *, struct event_trigger_data *);\n};\n\nstruct event_command {\n\tstruct list_head list;\n\tchar *name;\n\tenum event_trigger_type trigger_type;\n\tint flags;\n\tint (*func)(struct event_command *, struct trace_event_file *, char *, char *, char *);\n\tint (*reg)(char *, struct event_trigger_ops *, struct event_trigger_data *, struct trace_event_file *);\n\tvoid (*unreg)(char *, struct event_trigger_ops *, struct event_trigger_data *, struct trace_event_file *);\n\tvoid (*unreg_all)(struct trace_event_file *);\n\tint (*set_filter)(char *, struct event_trigger_data *, struct trace_event_file *);\n\tstruct event_trigger_ops * (*get_trigger_ops)(char *, char *);\n};\n\nstruct enable_trigger_data {\n\tstruct trace_event_file *file;\n\tbool enable;\n\tbool hist;\n};\n\nenum event_command_flags {\n\tEVENT_CMD_FL_POST_TRIGGER = 1,\n\tEVENT_CMD_FL_NEEDS_REC = 2,\n};\n\nenum dynevent_type {\n\tDYNEVENT_TYPE_SYNTH = 1,\n\tDYNEVENT_TYPE_KPROBE = 2,\n\tDYNEVENT_TYPE_NONE = 3,\n};\n\nstruct dynevent_cmd;\n\ntypedef int (*dynevent_create_fn_t)(struct dynevent_cmd *);\n\nstruct dynevent_cmd {\n\tstruct seq_buf seq;\n\tconst char *event_name;\n\tunsigned int n_fields;\n\tenum dynevent_type type;\n\tdynevent_create_fn_t run_command;\n\tvoid *private_data;\n};\n\nstruct synth_field_desc {\n\tconst char *type;\n\tconst char *name;\n};\n\nstruct synth_trace_event;\n\nstruct synth_event;\n\nstruct synth_event_trace_state {\n\tstruct trace_event_buffer fbuffer;\n\tstruct synth_trace_event *entry;\n\tstruct trace_buffer *buffer;\n\tstruct synth_event *event;\n\tunsigned int cur_field;\n\tunsigned int n_u64;\n\tbool disabled;\n\tbool add_next;\n\tbool add_name;\n};\n\nstruct synth_trace_event {\n\tstruct trace_entry ent;\n\tu64 fields[0];\n};\n\nstruct dyn_event_operations;\n\nstruct dyn_event {\n\tstruct list_head list;\n\tstruct dyn_event_operations *ops;\n};\n\nstruct synth_field;\n\nstruct synth_event {\n\tstruct dyn_event devent;\n\tint ref;\n\tchar *name;\n\tstruct synth_field **fields;\n\tunsigned int n_fields;\n\tstruct synth_field **dynamic_fields;\n\tunsigned int n_dynamic_fields;\n\tunsigned int n_u64;\n\tstruct trace_event_class class;\n\tstruct trace_event_call call;\n\tstruct tracepoint *tp;\n\tstruct module *mod;\n};\n\nstruct dyn_event_operations {\n\tstruct list_head list;\n\tint (*create)(const char *);\n\tint (*show)(struct seq_file *, struct dyn_event *);\n\tbool (*is_busy)(struct dyn_event *);\n\tint (*free)(struct dyn_event *);\n\tbool (*match)(const char *, const char *, int, const char **, struct dyn_event *);\n};\n\ntypedef int (*dynevent_check_arg_fn_t)(void *);\n\nstruct dynevent_arg {\n\tconst char *str;\n\tchar separator;\n};\n\nstruct dynevent_arg_pair {\n\tconst char *lhs;\n\tconst char *rhs;\n\tchar operator;\n\tchar separator;\n};\n\nstruct synth_field {\n\tchar *type;\n\tchar *name;\n\tsize_t size;\n\tunsigned int offset;\n\tunsigned int field_pos;\n\tbool is_signed;\n\tbool is_string;\n\tbool is_dynamic;\n};\n\nenum {\n\tSYNTH_ERR_BAD_NAME = 0,\n\tSYNTH_ERR_INVALID_CMD = 1,\n\tSYNTH_ERR_INVALID_DYN_CMD = 2,\n\tSYNTH_ERR_EVENT_EXISTS = 3,\n\tSYNTH_ERR_TOO_MANY_FIELDS = 4,\n\tSYNTH_ERR_INCOMPLETE_TYPE = 5,\n\tSYNTH_ERR_INVALID_TYPE = 6,\n\tSYNTH_ERR_INVALID_FIELD = 7,\n\tSYNTH_ERR_INVALID_ARRAY_SPEC = 8,\n};\n\nenum {\n\tHIST_ERR_NONE = 0,\n\tHIST_ERR_DUPLICATE_VAR = 1,\n\tHIST_ERR_VAR_NOT_UNIQUE = 2,\n\tHIST_ERR_TOO_MANY_VARS = 3,\n\tHIST_ERR_MALFORMED_ASSIGNMENT = 4,\n\tHIST_ERR_NAMED_MISMATCH = 5,\n\tHIST_ERR_TRIGGER_EEXIST = 6,\n\tHIST_ERR_TRIGGER_ENOENT_CLEAR = 7,\n\tHIST_ERR_SET_CLOCK_FAIL = 8,\n\tHIST_ERR_BAD_FIELD_MODIFIER = 9,\n\tHIST_ERR_TOO_MANY_SUBEXPR = 10,\n\tHIST_ERR_TIMESTAMP_MISMATCH = 11,\n\tHIST_ERR_TOO_MANY_FIELD_VARS = 12,\n\tHIST_ERR_EVENT_FILE_NOT_FOUND = 13,\n\tHIST_ERR_HIST_NOT_FOUND = 14,\n\tHIST_ERR_HIST_CREATE_FAIL = 15,\n\tHIST_ERR_SYNTH_VAR_NOT_FOUND = 16,\n\tHIST_ERR_SYNTH_EVENT_NOT_FOUND = 17,\n\tHIST_ERR_SYNTH_TYPE_MISMATCH = 18,\n\tHIST_ERR_SYNTH_COUNT_MISMATCH = 19,\n\tHIST_ERR_FIELD_VAR_PARSE_FAIL = 20,\n\tHIST_ERR_VAR_CREATE_FIND_FAIL = 21,\n\tHIST_ERR_ONX_NOT_VAR = 22,\n\tHIST_ERR_ONX_VAR_NOT_FOUND = 23,\n\tHIST_ERR_ONX_VAR_CREATE_FAIL = 24,\n\tHIST_ERR_FIELD_VAR_CREATE_FAIL = 25,\n\tHIST_ERR_TOO_MANY_PARAMS = 26,\n\tHIST_ERR_PARAM_NOT_FOUND = 27,\n\tHIST_ERR_INVALID_PARAM = 28,\n\tHIST_ERR_ACTION_NOT_FOUND = 29,\n\tHIST_ERR_NO_SAVE_PARAMS = 30,\n\tHIST_ERR_TOO_MANY_SAVE_ACTIONS = 31,\n\tHIST_ERR_ACTION_MISMATCH = 32,\n\tHIST_ERR_NO_CLOSING_PAREN = 33,\n\tHIST_ERR_SUBSYS_NOT_FOUND = 34,\n\tHIST_ERR_INVALID_SUBSYS_EVENT = 35,\n\tHIST_ERR_INVALID_REF_KEY = 36,\n\tHIST_ERR_VAR_NOT_FOUND = 37,\n\tHIST_ERR_FIELD_NOT_FOUND = 38,\n\tHIST_ERR_EMPTY_ASSIGNMENT = 39,\n\tHIST_ERR_INVALID_SORT_MODIFIER = 40,\n\tHIST_ERR_EMPTY_SORT_FIELD = 41,\n\tHIST_ERR_TOO_MANY_SORT_FIELDS = 42,\n\tHIST_ERR_INVALID_SORT_FIELD = 43,\n\tHIST_ERR_INVALID_STR_OPERAND = 44,\n};\n\nstruct hist_field;\n\ntypedef u64 (*hist_field_fn_t)(struct hist_field *, struct tracing_map_elt *, struct trace_buffer *, struct ring_buffer_event *, void *);\n\nstruct hist_trigger_data;\n\nstruct hist_var {\n\tchar *name;\n\tstruct hist_trigger_data *hist_data;\n\tunsigned int idx;\n};\n\nenum field_op_id {\n\tFIELD_OP_NONE = 0,\n\tFIELD_OP_PLUS = 1,\n\tFIELD_OP_MINUS = 2,\n\tFIELD_OP_UNARY_MINUS = 3,\n};\n\nstruct hist_field {\n\tstruct ftrace_event_field *field;\n\tlong unsigned int flags;\n\thist_field_fn_t fn;\n\tunsigned int ref;\n\tunsigned int size;\n\tunsigned int offset;\n\tunsigned int is_signed;\n\tconst char *type;\n\tstruct hist_field *operands[2];\n\tstruct hist_trigger_data *hist_data;\n\tstruct hist_var var;\n\tenum field_op_id operator;\n\tchar *system;\n\tchar *event_name;\n\tchar *name;\n\tunsigned int var_ref_idx;\n\tbool read_once;\n\tunsigned int var_str_idx;\n};\n\nstruct hist_trigger_attrs;\n\nstruct action_data;\n\nstruct field_var;\n\nstruct field_var_hist;\n\nstruct hist_trigger_data {\n\tstruct hist_field *fields[22];\n\tunsigned int n_vals;\n\tunsigned int n_keys;\n\tunsigned int n_fields;\n\tunsigned int n_vars;\n\tunsigned int n_var_str;\n\tunsigned int key_size;\n\tstruct tracing_map_sort_key sort_keys[2];\n\tunsigned int n_sort_keys;\n\tstruct trace_event_file *event_file;\n\tstruct hist_trigger_attrs *attrs;\n\tstruct tracing_map *map;\n\tbool enable_timestamps;\n\tbool remove;\n\tstruct hist_field *var_refs[16];\n\tunsigned int n_var_refs;\n\tstruct action_data *actions[8];\n\tunsigned int n_actions;\n\tstruct field_var *field_vars[32];\n\tunsigned int n_field_vars;\n\tunsigned int n_field_var_str;\n\tstruct field_var_hist *field_var_hists[32];\n\tunsigned int n_field_var_hists;\n\tstruct field_var *save_vars[32];\n\tunsigned int n_save_vars;\n\tunsigned int n_save_var_str;\n};\n\nenum hist_field_flags {\n\tHIST_FIELD_FL_HITCOUNT = 1,\n\tHIST_FIELD_FL_KEY = 2,\n\tHIST_FIELD_FL_STRING = 4,\n\tHIST_FIELD_FL_HEX = 8,\n\tHIST_FIELD_FL_SYM = 16,\n\tHIST_FIELD_FL_SYM_OFFSET = 32,\n\tHIST_FIELD_FL_EXECNAME = 64,\n\tHIST_FIELD_FL_SYSCALL = 128,\n\tHIST_FIELD_FL_STACKTRACE = 256,\n\tHIST_FIELD_FL_LOG2 = 512,\n\tHIST_FIELD_FL_TIMESTAMP = 1024,\n\tHIST_FIELD_FL_TIMESTAMP_USECS = 2048,\n\tHIST_FIELD_FL_VAR = 4096,\n\tHIST_FIELD_FL_EXPR = 8192,\n\tHIST_FIELD_FL_VAR_REF = 16384,\n\tHIST_FIELD_FL_CPU = 32768,\n\tHIST_FIELD_FL_ALIAS = 65536,\n};\n\nstruct var_defs {\n\tunsigned int n_vars;\n\tchar *name[16];\n\tchar *expr[16];\n};\n\nstruct hist_trigger_attrs {\n\tchar *keys_str;\n\tchar *vals_str;\n\tchar *sort_key_str;\n\tchar *name;\n\tchar *clock;\n\tbool pause;\n\tbool cont;\n\tbool clear;\n\tbool ts_in_usecs;\n\tunsigned int map_bits;\n\tchar *assignment_str[16];\n\tunsigned int n_assignments;\n\tchar *action_str[8];\n\tunsigned int n_actions;\n\tstruct var_defs var_defs;\n};\n\nstruct field_var {\n\tstruct hist_field *var;\n\tstruct hist_field *val;\n};\n\nstruct field_var_hist {\n\tstruct hist_trigger_data *hist_data;\n\tchar *cmd;\n};\n\nenum handler_id {\n\tHANDLER_ONMATCH = 1,\n\tHANDLER_ONMAX = 2,\n\tHANDLER_ONCHANGE = 3,\n};\n\nenum action_id {\n\tACTION_SAVE = 1,\n\tACTION_TRACE = 2,\n\tACTION_SNAPSHOT = 3,\n};\n\ntypedef void (*action_fn_t)(struct hist_trigger_data *, struct tracing_map_elt *, struct trace_buffer *, void *, struct ring_buffer_event *, void *, struct action_data *, u64 *);\n\ntypedef bool (*check_track_val_fn_t)(u64, u64);\n\nstruct action_data {\n\tenum handler_id handler;\n\tenum action_id action;\n\tchar *action_name;\n\taction_fn_t fn;\n\tunsigned int n_params;\n\tchar *params[32];\n\tunsigned int var_ref_idx[16];\n\tstruct synth_event *synth_event;\n\tbool use_trace_keyword;\n\tchar *synth_event_name;\n\tunion {\n\t\tstruct {\n\t\t\tchar *event;\n\t\t\tchar *event_system;\n\t\t} match_data;\n\t\tstruct {\n\t\t\tchar *var_str;\n\t\t\tstruct hist_field *var_ref;\n\t\t\tstruct hist_field *track_var;\n\t\t\tcheck_track_val_fn_t check_val;\n\t\t\taction_fn_t save_data;\n\t\t} track_data;\n\t};\n};\n\nstruct track_data {\n\tu64 track_val;\n\tbool updated;\n\tunsigned int key_len;\n\tvoid *key;\n\tstruct tracing_map_elt elt;\n\tstruct action_data *action_data;\n\tstruct hist_trigger_data *hist_data;\n};\n\nstruct hist_elt_data {\n\tchar *comm;\n\tu64 *var_ref_vals;\n\tchar *field_var_str[32];\n};\n\nstruct snapshot_context {\n\tstruct tracing_map_elt *elt;\n\tvoid *key;\n};\n\ntypedef void (*synth_probe_func_t)(void *, u64 *, unsigned int *);\n\nstruct hist_var_data {\n\tstruct list_head list;\n\tstruct hist_trigger_data *hist_data;\n};\n\nenum bpf_func_id {\n\tBPF_FUNC_unspec = 0,\n\tBPF_FUNC_map_lookup_elem = 1,\n\tBPF_FUNC_map_update_elem = 2,\n\tBPF_FUNC_map_delete_elem = 3,\n\tBPF_FUNC_probe_read = 4,\n\tBPF_FUNC_ktime_get_ns = 5,\n\tBPF_FUNC_trace_printk = 6,\n\tBPF_FUNC_get_prandom_u32 = 7,\n\tBPF_FUNC_get_smp_processor_id = 8,\n\tBPF_FUNC_skb_store_bytes = 9,\n\tBPF_FUNC_l3_csum_replace = 10,\n\tBPF_FUNC_l4_csum_replace = 11,\n\tBPF_FUNC_tail_call = 12,\n\tBPF_FUNC_clone_redirect = 13,\n\tBPF_FUNC_get_current_pid_tgid = 14,\n\tBPF_FUNC_get_current_uid_gid = 15,\n\tBPF_FUNC_get_current_comm = 16,\n\tBPF_FUNC_get_cgroup_classid = 17,\n\tBPF_FUNC_skb_vlan_push = 18,\n\tBPF_FUNC_skb_vlan_pop = 19,\n\tBPF_FUNC_skb_get_tunnel_key = 20,\n\tBPF_FUNC_skb_set_tunnel_key = 21,\n\tBPF_FUNC_perf_event_read = 22,\n\tBPF_FUNC_redirect = 23,\n\tBPF_FUNC_get_route_realm = 24,\n\tBPF_FUNC_perf_event_output = 25,\n\tBPF_FUNC_skb_load_bytes = 26,\n\tBPF_FUNC_get_stackid = 27,\n\tBPF_FUNC_csum_diff = 28,\n\tBPF_FUNC_skb_get_tunnel_opt = 29,\n\tBPF_FUNC_skb_set_tunnel_opt = 30,\n\tBPF_FUNC_skb_change_proto = 31,\n\tBPF_FUNC_skb_change_type = 32,\n\tBPF_FUNC_skb_under_cgroup = 33,\n\tBPF_FUNC_get_hash_recalc = 34,\n\tBPF_FUNC_get_current_task = 35,\n\tBPF_FUNC_probe_write_user = 36,\n\tBPF_FUNC_current_task_under_cgroup = 37,\n\tBPF_FUNC_skb_change_tail = 38,\n\tBPF_FUNC_skb_pull_data = 39,\n\tBPF_FUNC_csum_update = 40,\n\tBPF_FUNC_set_hash_invalid = 41,\n\tBPF_FUNC_get_numa_node_id = 42,\n\tBPF_FUNC_skb_change_head = 43,\n\tBPF_FUNC_xdp_adjust_head = 44,\n\tBPF_FUNC_probe_read_str = 45,\n\tBPF_FUNC_get_socket_cookie = 46,\n\tBPF_FUNC_get_socket_uid = 47,\n\tBPF_FUNC_set_hash = 48,\n\tBPF_FUNC_setsockopt = 49,\n\tBPF_FUNC_skb_adjust_room = 50,\n\tBPF_FUNC_redirect_map = 51,\n\tBPF_FUNC_sk_redirect_map = 52,\n\tBPF_FUNC_sock_map_update = 53,\n\tBPF_FUNC_xdp_adjust_meta = 54,\n\tBPF_FUNC_perf_event_read_value = 55,\n\tBPF_FUNC_perf_prog_read_value = 56,\n\tBPF_FUNC_getsockopt = 57,\n\tBPF_FUNC_override_return = 58,\n\tBPF_FUNC_sock_ops_cb_flags_set = 59,\n\tBPF_FUNC_msg_redirect_map = 60,\n\tBPF_FUNC_msg_apply_bytes = 61,\n\tBPF_FUNC_msg_cork_bytes = 62,\n\tBPF_FUNC_msg_pull_data = 63,\n\tBPF_FUNC_bind = 64,\n\tBPF_FUNC_xdp_adjust_tail = 65,\n\tBPF_FUNC_skb_get_xfrm_state = 66,\n\tBPF_FUNC_get_stack = 67,\n\tBPF_FUNC_skb_load_bytes_relative = 68,\n\tBPF_FUNC_fib_lookup = 69,\n\tBPF_FUNC_sock_hash_update = 70,\n\tBPF_FUNC_msg_redirect_hash = 71,\n\tBPF_FUNC_sk_redirect_hash = 72,\n\tBPF_FUNC_lwt_push_encap = 73,\n\tBPF_FUNC_lwt_seg6_store_bytes = 74,\n\tBPF_FUNC_lwt_seg6_adjust_srh = 75,\n\tBPF_FUNC_lwt_seg6_action = 76,\n\tBPF_FUNC_rc_repeat = 77,\n\tBPF_FUNC_rc_keydown = 78,\n\tBPF_FUNC_skb_cgroup_id = 79,\n\tBPF_FUNC_get_current_cgroup_id = 80,\n\tBPF_FUNC_get_local_storage = 81,\n\tBPF_FUNC_sk_select_reuseport = 82,\n\tBPF_FUNC_skb_ancestor_cgroup_id = 83,\n\tBPF_FUNC_sk_lookup_tcp = 84,\n\tBPF_FUNC_sk_lookup_udp = 85,\n\tBPF_FUNC_sk_release = 86,\n\tBPF_FUNC_map_push_elem = 87,\n\tBPF_FUNC_map_pop_elem = 88,\n\tBPF_FUNC_map_peek_elem = 89,\n\tBPF_FUNC_msg_push_data = 90,\n\tBPF_FUNC_msg_pop_data = 91,\n\tBPF_FUNC_rc_pointer_rel = 92,\n\tBPF_FUNC_spin_lock = 93,\n\tBPF_FUNC_spin_unlock = 94,\n\tBPF_FUNC_sk_fullsock = 95,\n\tBPF_FUNC_tcp_sock = 96,\n\tBPF_FUNC_skb_ecn_set_ce = 97,\n\tBPF_FUNC_get_listener_sock = 98,\n\tBPF_FUNC_skc_lookup_tcp = 99,\n\tBPF_FUNC_tcp_check_syncookie = 100,\n\tBPF_FUNC_sysctl_get_name = 101,\n\tBPF_FUNC_sysctl_get_current_value = 102,\n\tBPF_FUNC_sysctl_get_new_value = 103,\n\tBPF_FUNC_sysctl_set_new_value = 104,\n\tBPF_FUNC_strtol = 105,\n\tBPF_FUNC_strtoul = 106,\n\tBPF_FUNC_sk_storage_get = 107,\n\tBPF_FUNC_sk_storage_delete = 108,\n\tBPF_FUNC_send_signal = 109,\n\tBPF_FUNC_tcp_gen_syncookie = 110,\n\tBPF_FUNC_skb_output = 111,\n\tBPF_FUNC_probe_read_user = 112,\n\tBPF_FUNC_probe_read_kernel = 113,\n\tBPF_FUNC_probe_read_user_str = 114,\n\tBPF_FUNC_probe_read_kernel_str = 115,\n\tBPF_FUNC_tcp_send_ack = 116,\n\tBPF_FUNC_send_signal_thread = 117,\n\tBPF_FUNC_jiffies64 = 118,\n\tBPF_FUNC_read_branch_records = 119,\n\tBPF_FUNC_get_ns_current_pid_tgid = 120,\n\tBPF_FUNC_xdp_output = 121,\n\tBPF_FUNC_get_netns_cookie = 122,\n\tBPF_FUNC_get_current_ancestor_cgroup_id = 123,\n\tBPF_FUNC_sk_assign = 124,\n\tBPF_FUNC_ktime_get_boot_ns = 125,\n\tBPF_FUNC_seq_printf = 126,\n\tBPF_FUNC_seq_write = 127,\n\tBPF_FUNC_sk_cgroup_id = 128,\n\tBPF_FUNC_sk_ancestor_cgroup_id = 129,\n\tBPF_FUNC_ringbuf_output = 130,\n\tBPF_FUNC_ringbuf_reserve = 131,\n\tBPF_FUNC_ringbuf_submit = 132,\n\tBPF_FUNC_ringbuf_discard = 133,\n\tBPF_FUNC_ringbuf_query = 134,\n\tBPF_FUNC_csum_level = 135,\n\tBPF_FUNC_skc_to_tcp6_sock = 136,\n\tBPF_FUNC_skc_to_tcp_sock = 137,\n\tBPF_FUNC_skc_to_tcp_timewait_sock = 138,\n\tBPF_FUNC_skc_to_tcp_request_sock = 139,\n\tBPF_FUNC_skc_to_udp6_sock = 140,\n\tBPF_FUNC_get_task_stack = 141,\n\tBPF_FUNC_load_hdr_opt = 142,\n\tBPF_FUNC_store_hdr_opt = 143,\n\tBPF_FUNC_reserve_hdr_opt = 144,\n\tBPF_FUNC_inode_storage_get = 145,\n\tBPF_FUNC_inode_storage_delete = 146,\n\tBPF_FUNC_d_path = 147,\n\tBPF_FUNC_copy_from_user = 148,\n\tBPF_FUNC_snprintf_btf = 149,\n\tBPF_FUNC_seq_printf_btf = 150,\n\tBPF_FUNC_skb_cgroup_classid = 151,\n\tBPF_FUNC_redirect_neigh = 152,\n\tBPF_FUNC_per_cpu_ptr = 153,\n\tBPF_FUNC_this_cpu_ptr = 154,\n\tBPF_FUNC_redirect_peer = 155,\n\tBPF_FUNC_task_storage_get = 156,\n\tBPF_FUNC_task_storage_delete = 157,\n\tBPF_FUNC_get_current_task_btf = 158,\n\tBPF_FUNC_bprm_opts_set = 159,\n\tBPF_FUNC_ktime_get_coarse_ns = 160,\n\tBPF_FUNC_ima_inode_hash = 161,\n\tBPF_FUNC_sock_from_file = 162,\n\tBPF_FUNC_check_mtu = 163,\n\tBPF_FUNC_for_each_map_elem = 164,\n\tBPF_FUNC_snprintf = 165,\n\tBPF_FUNC_sys_bpf = 166,\n\tBPF_FUNC_btf_find_by_name_kind = 167,\n\tBPF_FUNC_sys_close = 168,\n\t__BPF_FUNC_MAX_ID = 169,\n};\n\nenum {\n\tBPF_F_INDEX_MASK = 4294967295,\n\tBPF_F_CURRENT_CPU = 4294967295,\n\tBPF_F_CTXLEN_MASK = 0,\n};\n\nenum {\n\tBPF_F_GET_BRANCH_RECORDS_SIZE = 1,\n};\n\nstruct bpf_perf_event_value {\n\t__u64 counter;\n\t__u64 enabled;\n\t__u64 running;\n};\n\nstruct bpf_raw_tracepoint_args {\n\t__u64 args[0];\n};\n\nenum bpf_task_fd_type {\n\tBPF_FD_TYPE_RAW_TRACEPOINT = 0,\n\tBPF_FD_TYPE_TRACEPOINT = 1,\n\tBPF_FD_TYPE_KPROBE = 2,\n\tBPF_FD_TYPE_KRETPROBE = 3,\n\tBPF_FD_TYPE_UPROBE = 4,\n\tBPF_FD_TYPE_URETPROBE = 5,\n};\n\nstruct btf_ptr {\n\tvoid *ptr;\n\t__u32 type_id;\n\t__u32 flags;\n};\n\nenum {\n\tBTF_F_COMPACT = 1,\n\tBTF_F_NONAME = 2,\n\tBTF_F_PTR_RAW = 4,\n\tBTF_F_ZERO = 8,\n};\n\nstruct bpf_local_storage_data;\n\nstruct bpf_local_storage {\n\tstruct bpf_local_storage_data *cache[16];\n\tstruct hlist_head list;\n\tvoid *owner;\n\tstruct callback_head rcu;\n\traw_spinlock_t lock;\n};\n\nstruct bpf_local_storage_map_bucket;\n\nstruct bpf_local_storage_map {\n\tstruct bpf_map map;\n\tstruct bpf_local_storage_map_bucket *buckets;\n\tu32 bucket_log;\n\tu16 elem_size;\n\tu16 cache_idx;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum bpf_arg_type {\n\tARG_DONTCARE = 0,\n\tARG_CONST_MAP_PTR = 1,\n\tARG_PTR_TO_MAP_KEY = 2,\n\tARG_PTR_TO_MAP_VALUE = 3,\n\tARG_PTR_TO_UNINIT_MAP_VALUE = 4,\n\tARG_PTR_TO_MAP_VALUE_OR_NULL = 5,\n\tARG_PTR_TO_MEM = 6,\n\tARG_PTR_TO_MEM_OR_NULL = 7,\n\tARG_PTR_TO_UNINIT_MEM = 8,\n\tARG_CONST_SIZE = 9,\n\tARG_CONST_SIZE_OR_ZERO = 10,\n\tARG_PTR_TO_CTX = 11,\n\tARG_PTR_TO_CTX_OR_NULL = 12,\n\tARG_ANYTHING = 13,\n\tARG_PTR_TO_SPIN_LOCK = 14,\n\tARG_PTR_TO_SOCK_COMMON = 15,\n\tARG_PTR_TO_INT = 16,\n\tARG_PTR_TO_LONG = 17,\n\tARG_PTR_TO_SOCKET = 18,\n\tARG_PTR_TO_SOCKET_OR_NULL = 19,\n\tARG_PTR_TO_BTF_ID = 20,\n\tARG_PTR_TO_ALLOC_MEM = 21,\n\tARG_PTR_TO_ALLOC_MEM_OR_NULL = 22,\n\tARG_CONST_ALLOC_SIZE_OR_ZERO = 23,\n\tARG_PTR_TO_BTF_ID_SOCK_COMMON = 24,\n\tARG_PTR_TO_PERCPU_BTF_ID = 25,\n\tARG_PTR_TO_FUNC = 26,\n\tARG_PTR_TO_STACK_OR_NULL = 27,\n\tARG_PTR_TO_CONST_STR = 28,\n\t__BPF_ARG_TYPE_MAX = 29,\n};\n\nenum bpf_return_type {\n\tRET_INTEGER = 0,\n\tRET_VOID = 1,\n\tRET_PTR_TO_MAP_VALUE = 2,\n\tRET_PTR_TO_MAP_VALUE_OR_NULL = 3,\n\tRET_PTR_TO_SOCKET_OR_NULL = 4,\n\tRET_PTR_TO_TCP_SOCK_OR_NULL = 5,\n\tRET_PTR_TO_SOCK_COMMON_OR_NULL = 6,\n\tRET_PTR_TO_ALLOC_MEM_OR_NULL = 7,\n\tRET_PTR_TO_BTF_ID_OR_NULL = 8,\n\tRET_PTR_TO_MEM_OR_BTF_ID_OR_NULL = 9,\n\tRET_PTR_TO_MEM_OR_BTF_ID = 10,\n\tRET_PTR_TO_BTF_ID = 11,\n};\n\nstruct bpf_func_proto {\n\tu64 (*func)(u64, u64, u64, u64, u64);\n\tbool gpl_only;\n\tbool pkt_access;\n\tenum bpf_return_type ret_type;\n\tunion {\n\t\tstruct {\n\t\t\tenum bpf_arg_type arg1_type;\n\t\t\tenum bpf_arg_type arg2_type;\n\t\t\tenum bpf_arg_type arg3_type;\n\t\t\tenum bpf_arg_type arg4_type;\n\t\t\tenum bpf_arg_type arg5_type;\n\t\t};\n\t\tenum bpf_arg_type arg_type[5];\n\t};\n\tunion {\n\t\tstruct {\n\t\t\tu32 *arg1_btf_id;\n\t\t\tu32 *arg2_btf_id;\n\t\t\tu32 *arg3_btf_id;\n\t\t\tu32 *arg4_btf_id;\n\t\t\tu32 *arg5_btf_id;\n\t\t};\n\t\tu32 *arg_btf_id[5];\n\t};\n\tint *ret_btf_id;\n\tbool (*allowed)(const struct bpf_prog *);\n};\n\nenum bpf_access_type {\n\tBPF_READ = 1,\n\tBPF_WRITE = 2,\n};\n\nstruct bpf_verifier_log;\n\nstruct bpf_insn_access_aux {\n\tenum bpf_reg_type reg_type;\n\tunion {\n\t\tint ctx_field_size;\n\t\tstruct {\n\t\t\tstruct btf *btf;\n\t\t\tu32 btf_id;\n\t\t};\n\t};\n\tstruct bpf_verifier_log *log;\n};\n\nstruct bpf_verifier_ops {\n\tconst struct bpf_func_proto * (*get_func_proto)(enum bpf_func_id, const struct bpf_prog *);\n\tbool (*is_valid_access)(int, int, enum bpf_access_type, const struct bpf_prog *, struct bpf_insn_access_aux *);\n\tint (*gen_prologue)(struct bpf_insn *, bool, const struct bpf_prog *);\n\tint (*gen_ld_abs)(const struct bpf_insn *, struct bpf_insn *);\n\tu32 (*convert_ctx_access)(enum bpf_access_type, const struct bpf_insn *, struct bpf_insn *, struct bpf_prog *, u32 *);\n\tint (*btf_struct_access)(struct bpf_verifier_log *, const struct btf *, const struct btf_type *, int, int, enum bpf_access_type, u32 *);\n\tbool (*check_kfunc_call)(u32);\n};\n\nstruct bpf_event_entry {\n\tstruct perf_event *event;\n\tstruct file *perf_file;\n\tstruct file *map_file;\n\tstruct callback_head rcu;\n};\n\ntypedef long unsigned int (*bpf_ctx_copy_t)(void *, const void *, long unsigned int, long unsigned int);\n\ntypedef struct pt_regs bpf_user_pt_regs_t;\n\nstruct bpf_perf_event_data {\n\tbpf_user_pt_regs_t regs;\n\t__u64 sample_period;\n\t__u64 addr;\n};\n\nstruct perf_event_query_bpf {\n\t__u32 ids_len;\n\t__u32 prog_cnt;\n\t__u32 ids[0];\n};\n\nstruct bpf_perf_event_data_kern {\n\tbpf_user_pt_regs_t *regs;\n\tstruct perf_sample_data *data;\n\tstruct perf_event *event;\n};\n\nstruct btf_id_set {\n\tu32 cnt;\n\tu32 ids[0];\n};\n\nstruct bpf_local_storage_map_bucket {\n\tstruct hlist_head list;\n\traw_spinlock_t lock;\n};\n\nstruct bpf_local_storage_data {\n\tstruct bpf_local_storage_map *smap;\n\tu8 data[0];\n};\n\nstruct trace_event_raw_bpf_trace_printk {\n\tstruct trace_entry ent;\n\tu32 __data_loc_bpf_string;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_bpf_trace_printk {\n\tu32 bpf_string;\n};\n\ntypedef void (*btf_trace_bpf_trace_printk)(void *, const char *);\n\nstruct bpf_trace_module {\n\tstruct module *module;\n\tstruct list_head list;\n};\n\ntypedef u64 (*btf_bpf_override_return)(struct pt_regs *, long unsigned int);\n\ntypedef u64 (*btf_bpf_probe_read_user)(void *, u32, const void *);\n\ntypedef u64 (*btf_bpf_probe_read_user_str)(void *, u32, const void *);\n\ntypedef u64 (*btf_bpf_probe_read_kernel)(void *, u32, const void *);\n\ntypedef u64 (*btf_bpf_probe_read_kernel_str)(void *, u32, const void *);\n\ntypedef u64 (*btf_bpf_probe_read_compat)(void *, u32, const void *);\n\ntypedef u64 (*btf_bpf_probe_read_compat_str)(void *, u32, const void *);\n\ntypedef u64 (*btf_bpf_probe_write_user)(void *, const void *, u32);\n\ntypedef u64 (*btf_bpf_trace_printk)(char *, u32, u64, u64, u64);\n\ntypedef u64 (*btf_bpf_seq_printf)(struct seq_file *, char *, u32, const void *, u32);\n\ntypedef u64 (*btf_bpf_seq_write)(struct seq_file *, const void *, u32);\n\ntypedef u64 (*btf_bpf_seq_printf_btf)(struct seq_file *, struct btf_ptr *, u32, u64);\n\ntypedef u64 (*btf_bpf_perf_event_read)(struct bpf_map *, u64);\n\ntypedef u64 (*btf_bpf_perf_event_read_value)(struct bpf_map *, u64, struct bpf_perf_event_value *, u32);\n\nstruct bpf_trace_sample_data {\n\tstruct perf_sample_data sds[3];\n};\n\ntypedef u64 (*btf_bpf_perf_event_output)(struct pt_regs *, struct bpf_map *, u64, void *, u64);\n\nstruct bpf_nested_pt_regs {\n\tstruct pt_regs regs[3];\n};\n\ntypedef u64 (*btf_bpf_get_current_task)();\n\ntypedef u64 (*btf_bpf_get_current_task_btf)();\n\ntypedef u64 (*btf_bpf_current_task_under_cgroup)(struct bpf_map *, u32);\n\nstruct send_signal_irq_work {\n\tstruct irq_work irq_work;\n\tstruct task_struct *task;\n\tu32 sig;\n\tenum pid_type type;\n};\n\ntypedef u64 (*btf_bpf_send_signal)(u32);\n\ntypedef u64 (*btf_bpf_send_signal_thread)(u32);\n\ntypedef u64 (*btf_bpf_d_path)(struct path *, char *, u32);\n\ntypedef u64 (*btf_bpf_snprintf_btf)(char *, u32, struct btf_ptr *, u32, u64);\n\ntypedef u64 (*btf_bpf_perf_event_output_tp)(void *, struct bpf_map *, u64, void *, u64);\n\ntypedef u64 (*btf_bpf_get_stackid_tp)(void *, struct bpf_map *, u64);\n\ntypedef u64 (*btf_bpf_get_stack_tp)(void *, void *, u32, u64);\n\ntypedef u64 (*btf_bpf_perf_prog_read_value)(struct bpf_perf_event_data_kern *, struct bpf_perf_event_value *, u32);\n\ntypedef u64 (*btf_bpf_read_branch_records)(struct bpf_perf_event_data_kern *, void *, u32, u64);\n\nstruct bpf_raw_tp_regs {\n\tstruct pt_regs regs[3];\n};\n\ntypedef u64 (*btf_bpf_perf_event_output_raw_tp)(struct bpf_raw_tracepoint_args *, struct bpf_map *, u64, void *, u64);\n\ntypedef u64 (*btf_bpf_get_stackid_raw_tp)(struct bpf_raw_tracepoint_args *, struct bpf_map *, u64);\n\ntypedef u64 (*btf_bpf_get_stack_raw_tp)(struct bpf_raw_tracepoint_args *, void *, u32, u64);\n\nstruct kprobe_trace_entry_head {\n\tstruct trace_entry ent;\n\tlong unsigned int ip;\n};\n\nstruct kretprobe_trace_entry_head {\n\tstruct trace_entry ent;\n\tlong unsigned int func;\n\tlong unsigned int ret_ip;\n};\n\ntypedef int (*print_type_func_t)(struct trace_seq *, void *, void *);\n\nenum fetch_op {\n\tFETCH_OP_NOP = 0,\n\tFETCH_OP_REG = 1,\n\tFETCH_OP_STACK = 2,\n\tFETCH_OP_STACKP = 3,\n\tFETCH_OP_RETVAL = 4,\n\tFETCH_OP_IMM = 5,\n\tFETCH_OP_COMM = 6,\n\tFETCH_OP_ARG = 7,\n\tFETCH_OP_FOFFS = 8,\n\tFETCH_OP_DATA = 9,\n\tFETCH_OP_DEREF = 10,\n\tFETCH_OP_UDEREF = 11,\n\tFETCH_OP_ST_RAW = 12,\n\tFETCH_OP_ST_MEM = 13,\n\tFETCH_OP_ST_UMEM = 14,\n\tFETCH_OP_ST_STRING = 15,\n\tFETCH_OP_ST_USTRING = 16,\n\tFETCH_OP_MOD_BF = 17,\n\tFETCH_OP_LP_ARRAY = 18,\n\tFETCH_OP_END = 19,\n\tFETCH_NOP_SYMBOL = 20,\n};\n\nstruct fetch_insn {\n\tenum fetch_op op;\n\tunion {\n\t\tunsigned int param;\n\t\tstruct {\n\t\t\tunsigned int size;\n\t\t\tint offset;\n\t\t};\n\t\tstruct {\n\t\t\tunsigned char basesize;\n\t\t\tunsigned char lshift;\n\t\t\tunsigned char rshift;\n\t\t};\n\t\tlong unsigned int immediate;\n\t\tvoid *data;\n\t};\n};\n\nstruct fetch_type {\n\tconst char *name;\n\tsize_t size;\n\tint is_signed;\n\tprint_type_func_t print;\n\tconst char *fmt;\n\tconst char *fmttype;\n};\n\nstruct probe_arg {\n\tstruct fetch_insn *code;\n\tbool dynamic;\n\tunsigned int offset;\n\tunsigned int count;\n\tconst char *name;\n\tconst char *comm;\n\tchar *fmt;\n\tconst struct fetch_type *type;\n};\n\nstruct trace_uprobe_filter {\n\trwlock_t rwlock;\n\tint nr_systemwide;\n\tstruct list_head perf_events;\n};\n\nstruct trace_probe_event {\n\tunsigned int flags;\n\tstruct trace_event_class class;\n\tstruct trace_event_call call;\n\tstruct list_head files;\n\tstruct list_head probes;\n\tstruct trace_uprobe_filter filter[0];\n};\n\nstruct trace_probe {\n\tstruct list_head list;\n\tstruct trace_probe_event *event;\n\tssize_t size;\n\tunsigned int nr_args;\n\tstruct probe_arg args[0];\n};\n\nstruct event_file_link {\n\tstruct trace_event_file *file;\n\tstruct list_head list;\n};\n\nenum {\n\tTP_ERR_FILE_NOT_FOUND = 0,\n\tTP_ERR_NO_REGULAR_FILE = 1,\n\tTP_ERR_BAD_REFCNT = 2,\n\tTP_ERR_REFCNT_OPEN_BRACE = 3,\n\tTP_ERR_BAD_REFCNT_SUFFIX = 4,\n\tTP_ERR_BAD_UPROBE_OFFS = 5,\n\tTP_ERR_MAXACT_NO_KPROBE = 6,\n\tTP_ERR_BAD_MAXACT = 7,\n\tTP_ERR_MAXACT_TOO_BIG = 8,\n\tTP_ERR_BAD_PROBE_ADDR = 9,\n\tTP_ERR_BAD_RETPROBE = 10,\n\tTP_ERR_BAD_ADDR_SUFFIX = 11,\n\tTP_ERR_NO_GROUP_NAME = 12,\n\tTP_ERR_GROUP_TOO_LONG = 13,\n\tTP_ERR_BAD_GROUP_NAME = 14,\n\tTP_ERR_NO_EVENT_NAME = 15,\n\tTP_ERR_EVENT_TOO_LONG = 16,\n\tTP_ERR_BAD_EVENT_NAME = 17,\n\tTP_ERR_RETVAL_ON_PROBE = 18,\n\tTP_ERR_BAD_STACK_NUM = 19,\n\tTP_ERR_BAD_ARG_NUM = 20,\n\tTP_ERR_BAD_VAR = 21,\n\tTP_ERR_BAD_REG_NAME = 22,\n\tTP_ERR_BAD_MEM_ADDR = 23,\n\tTP_ERR_BAD_IMM = 24,\n\tTP_ERR_IMMSTR_NO_CLOSE = 25,\n\tTP_ERR_FILE_ON_KPROBE = 26,\n\tTP_ERR_BAD_FILE_OFFS = 27,\n\tTP_ERR_SYM_ON_UPROBE = 28,\n\tTP_ERR_TOO_MANY_OPS = 29,\n\tTP_ERR_DEREF_NEED_BRACE = 30,\n\tTP_ERR_BAD_DEREF_OFFS = 31,\n\tTP_ERR_DEREF_OPEN_BRACE = 32,\n\tTP_ERR_COMM_CANT_DEREF = 33,\n\tTP_ERR_BAD_FETCH_ARG = 34,\n\tTP_ERR_ARRAY_NO_CLOSE = 35,\n\tTP_ERR_BAD_ARRAY_SUFFIX = 36,\n\tTP_ERR_BAD_ARRAY_NUM = 37,\n\tTP_ERR_ARRAY_TOO_BIG = 38,\n\tTP_ERR_BAD_TYPE = 39,\n\tTP_ERR_BAD_STRING = 40,\n\tTP_ERR_BAD_BITFIELD = 41,\n\tTP_ERR_ARG_NAME_TOO_LONG = 42,\n\tTP_ERR_NO_ARG_NAME = 43,\n\tTP_ERR_BAD_ARG_NAME = 44,\n\tTP_ERR_USED_ARG_NAME = 45,\n\tTP_ERR_ARG_TOO_LONG = 46,\n\tTP_ERR_NO_ARG_BODY = 47,\n\tTP_ERR_BAD_INSN_BNDRY = 48,\n\tTP_ERR_FAIL_REG_PROBE = 49,\n\tTP_ERR_DIFF_PROBE_TYPE = 50,\n\tTP_ERR_DIFF_ARG_TYPE = 51,\n\tTP_ERR_SAME_PROBE = 52,\n};\n\nstruct trace_kprobe {\n\tstruct dyn_event devent;\n\tstruct kretprobe rp;\n\tlong unsigned int *nhit;\n\tconst char *symbol;\n\tstruct trace_probe tp;\n};\n\nenum error_detector {\n\tERROR_DETECTOR_KFENCE = 0,\n\tERROR_DETECTOR_KASAN = 1,\n};\n\nstruct trace_event_raw_error_report_template {\n\tstruct trace_entry ent;\n\tenum error_detector error_detector;\n\tlong unsigned int id;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_error_report_template {};\n\ntypedef void (*btf_trace_error_report_end)(void *, enum error_detector, long unsigned int);\n\nstruct trace_event_raw_cpu {\n\tstruct trace_entry ent;\n\tu32 state;\n\tu32 cpu_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_powernv_throttle {\n\tstruct trace_entry ent;\n\tint chip_id;\n\tu32 __data_loc_reason;\n\tint pmax;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_pstate_sample {\n\tstruct trace_entry ent;\n\tu32 core_busy;\n\tu32 scaled_busy;\n\tu32 from;\n\tu32 to;\n\tu64 mperf;\n\tu64 aperf;\n\tu64 tsc;\n\tu32 freq;\n\tu32 io_boost;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cpu_frequency_limits {\n\tstruct trace_entry ent;\n\tu32 min_freq;\n\tu32 max_freq;\n\tu32 cpu_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_device_pm_callback_start {\n\tstruct trace_entry ent;\n\tu32 __data_loc_device;\n\tu32 __data_loc_driver;\n\tu32 __data_loc_parent;\n\tu32 __data_loc_pm_ops;\n\tint event;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_device_pm_callback_end {\n\tstruct trace_entry ent;\n\tu32 __data_loc_device;\n\tu32 __data_loc_driver;\n\tint error;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_suspend_resume {\n\tstruct trace_entry ent;\n\tconst char *action;\n\tint val;\n\tbool start;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_wakeup_source {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tu64 state;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_clock {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tu64 state;\n\tu64 cpu_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_power_domain {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tu64 state;\n\tu64 cpu_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cpu_latency_qos_request {\n\tstruct trace_entry ent;\n\ts32 value;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_pm_qos_update {\n\tstruct trace_entry ent;\n\tenum pm_qos_req_action action;\n\tint prev_value;\n\tint curr_value;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_dev_pm_qos_request {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tenum dev_pm_qos_req_type type;\n\ts32 new_value;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_cpu {};\n\nstruct trace_event_data_offsets_powernv_throttle {\n\tu32 reason;\n};\n\nstruct trace_event_data_offsets_pstate_sample {};\n\nstruct trace_event_data_offsets_cpu_frequency_limits {};\n\nstruct trace_event_data_offsets_device_pm_callback_start {\n\tu32 device;\n\tu32 driver;\n\tu32 parent;\n\tu32 pm_ops;\n};\n\nstruct trace_event_data_offsets_device_pm_callback_end {\n\tu32 device;\n\tu32 driver;\n};\n\nstruct trace_event_data_offsets_suspend_resume {};\n\nstruct trace_event_data_offsets_wakeup_source {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_clock {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_power_domain {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_cpu_latency_qos_request {};\n\nstruct trace_event_data_offsets_pm_qos_update {};\n\nstruct trace_event_data_offsets_dev_pm_qos_request {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_cpu_idle)(void *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_powernv_throttle)(void *, int, const char *, int);\n\ntypedef void (*btf_trace_pstate_sample)(void *, u32, u32, u32, u32, u64, u64, u64, u32, u32);\n\ntypedef void (*btf_trace_cpu_frequency)(void *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_cpu_frequency_limits)(void *, struct cpufreq_policy *);\n\ntypedef void (*btf_trace_device_pm_callback_start)(void *, struct device *, const char *, int);\n\ntypedef void (*btf_trace_device_pm_callback_end)(void *, struct device *, int);\n\ntypedef void (*btf_trace_suspend_resume)(void *, const char *, int, bool);\n\ntypedef void (*btf_trace_wakeup_source_activate)(void *, const char *, unsigned int);\n\ntypedef void (*btf_trace_wakeup_source_deactivate)(void *, const char *, unsigned int);\n\ntypedef void (*btf_trace_clock_enable)(void *, const char *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_clock_disable)(void *, const char *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_clock_set_rate)(void *, const char *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_power_domain_target)(void *, const char *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_pm_qos_add_request)(void *, s32);\n\ntypedef void (*btf_trace_pm_qos_update_request)(void *, s32);\n\ntypedef void (*btf_trace_pm_qos_remove_request)(void *, s32);\n\ntypedef void (*btf_trace_pm_qos_update_target)(void *, enum pm_qos_req_action, int, int);\n\ntypedef void (*btf_trace_pm_qos_update_flags)(void *, enum pm_qos_req_action, int, int);\n\ntypedef void (*btf_trace_dev_pm_qos_add_request)(void *, const char *, enum dev_pm_qos_req_type, s32);\n\ntypedef void (*btf_trace_dev_pm_qos_update_request)(void *, const char *, enum dev_pm_qos_req_type, s32);\n\ntypedef void (*btf_trace_dev_pm_qos_remove_request)(void *, const char *, enum dev_pm_qos_req_type, s32);\n\nstruct trace_event_raw_rpm_internal {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tint flags;\n\tint usage_count;\n\tint disable_depth;\n\tint runtime_auto;\n\tint request_pending;\n\tint irq_safe;\n\tint child_count;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rpm_return_int {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tlong unsigned int ip;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_rpm_internal {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_rpm_return_int {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_rpm_suspend)(void *, struct device *, int);\n\ntypedef void (*btf_trace_rpm_resume)(void *, struct device *, int);\n\ntypedef void (*btf_trace_rpm_idle)(void *, struct device *, int);\n\ntypedef void (*btf_trace_rpm_usage)(void *, struct device *, int);\n\ntypedef void (*btf_trace_rpm_return_int)(void *, struct device *, long unsigned int, int);\n\nstruct trace_probe_log {\n\tconst char *subsystem;\n\tconst char **argv;\n\tint argc;\n\tint index;\n};\n\nenum uprobe_filter_ctx {\n\tUPROBE_FILTER_REGISTER = 0,\n\tUPROBE_FILTER_UNREGISTER = 1,\n\tUPROBE_FILTER_MMAP = 2,\n};\n\nstruct uprobe_consumer {\n\tint (*handler)(struct uprobe_consumer *, struct pt_regs *);\n\tint (*ret_handler)(struct uprobe_consumer *, long unsigned int, struct pt_regs *);\n\tbool (*filter)(struct uprobe_consumer *, enum uprobe_filter_ctx, struct mm_struct *);\n\tstruct uprobe_consumer *next;\n};\n\nstruct uprobe_trace_entry_head {\n\tstruct trace_entry ent;\n\tlong unsigned int vaddr[0];\n};\n\nstruct trace_uprobe {\n\tstruct dyn_event devent;\n\tstruct uprobe_consumer consumer;\n\tstruct path path;\n\tstruct inode *inode;\n\tchar *filename;\n\tlong unsigned int offset;\n\tlong unsigned int ref_ctr_offset;\n\tlong unsigned int nhit;\n\tstruct trace_probe tp;\n};\n\nstruct uprobe_dispatch_data {\n\tstruct trace_uprobe *tu;\n\tlong unsigned int bp_addr;\n};\n\nstruct uprobe_cpu_buffer {\n\tstruct mutex mutex;\n\tvoid *buf;\n};\n\ntypedef bool (*filter_func_t)(struct uprobe_consumer *, enum uprobe_filter_ctx, struct mm_struct *);\n\nstruct rhash_lock_head;\n\nstruct bucket_table {\n\tunsigned int size;\n\tunsigned int nest;\n\tu32 hash_rnd;\n\tstruct list_head walkers;\n\tstruct callback_head rcu;\n\tstruct bucket_table *future_tbl;\n\tstruct lockdep_map dep_map;\n\tlong: 64;\n\tstruct rhash_lock_head *buckets[0];\n};\n\nenum xdp_action {\n\tXDP_ABORTED = 0,\n\tXDP_DROP = 1,\n\tXDP_PASS = 2,\n\tXDP_TX = 3,\n\tXDP_REDIRECT = 4,\n};\n\nenum xdp_mem_type {\n\tMEM_TYPE_PAGE_SHARED = 0,\n\tMEM_TYPE_PAGE_ORDER0 = 1,\n\tMEM_TYPE_PAGE_POOL = 2,\n\tMEM_TYPE_XSK_BUFF_POOL = 3,\n\tMEM_TYPE_MAX = 4,\n};\n\nstruct xdp_cpumap_stats {\n\tunsigned int redirect;\n\tunsigned int pass;\n\tunsigned int drop;\n};\n\nstruct bpf_prog_dummy {\n\tstruct bpf_prog prog;\n};\n\ntypedef u64 (*btf_bpf_user_rnd_u32)();\n\ntypedef u64 (*btf_bpf_get_raw_cpu_id)();\n\nstruct _bpf_dtab_netdev {\n\tstruct net_device *dev;\n};\n\nstruct rhash_lock_head {};\n\nstruct zero_copy_allocator;\n\nstruct xdp_mem_allocator {\n\tstruct xdp_mem_info mem;\n\tunion {\n\t\tvoid *allocator;\n\t\tstruct page_pool *page_pool;\n\t\tstruct zero_copy_allocator *zc_alloc;\n\t};\n\tstruct rhash_head node;\n\tstruct callback_head rcu;\n};\n\nstruct trace_event_raw_xdp_exception {\n\tstruct trace_entry ent;\n\tint prog_id;\n\tu32 act;\n\tint ifindex;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xdp_bulk_tx {\n\tstruct trace_entry ent;\n\tint ifindex;\n\tu32 act;\n\tint drops;\n\tint sent;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xdp_redirect_template {\n\tstruct trace_entry ent;\n\tint prog_id;\n\tu32 act;\n\tint ifindex;\n\tint err;\n\tint to_ifindex;\n\tu32 map_id;\n\tint map_index;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xdp_cpumap_kthread {\n\tstruct trace_entry ent;\n\tint map_id;\n\tu32 act;\n\tint cpu;\n\tunsigned int drops;\n\tunsigned int processed;\n\tint sched;\n\tunsigned int xdp_pass;\n\tunsigned int xdp_drop;\n\tunsigned int xdp_redirect;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xdp_cpumap_enqueue {\n\tstruct trace_entry ent;\n\tint map_id;\n\tu32 act;\n\tint cpu;\n\tunsigned int drops;\n\tunsigned int processed;\n\tint to_cpu;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xdp_devmap_xmit {\n\tstruct trace_entry ent;\n\tint from_ifindex;\n\tu32 act;\n\tint to_ifindex;\n\tint drops;\n\tint sent;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mem_disconnect {\n\tstruct trace_entry ent;\n\tconst struct xdp_mem_allocator *xa;\n\tu32 mem_id;\n\tu32 mem_type;\n\tconst void *allocator;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mem_connect {\n\tstruct trace_entry ent;\n\tconst struct xdp_mem_allocator *xa;\n\tu32 mem_id;\n\tu32 mem_type;\n\tconst void *allocator;\n\tconst struct xdp_rxq_info *rxq;\n\tint ifindex;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mem_return_failed {\n\tstruct trace_entry ent;\n\tconst struct page *page;\n\tu32 mem_id;\n\tu32 mem_type;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_xdp_exception {};\n\nstruct trace_event_data_offsets_xdp_bulk_tx {};\n\nstruct trace_event_data_offsets_xdp_redirect_template {};\n\nstruct trace_event_data_offsets_xdp_cpumap_kthread {};\n\nstruct trace_event_data_offsets_xdp_cpumap_enqueue {};\n\nstruct trace_event_data_offsets_xdp_devmap_xmit {};\n\nstruct trace_event_data_offsets_mem_disconnect {};\n\nstruct trace_event_data_offsets_mem_connect {};\n\nstruct trace_event_data_offsets_mem_return_failed {};\n\ntypedef void (*btf_trace_xdp_exception)(void *, const struct net_device *, const struct bpf_prog *, u32);\n\ntypedef void (*btf_trace_xdp_bulk_tx)(void *, const struct net_device *, int, int, int);\n\ntypedef void (*btf_trace_xdp_redirect)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32);\n\ntypedef void (*btf_trace_xdp_redirect_err)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32);\n\ntypedef void (*btf_trace_xdp_redirect_map)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32);\n\ntypedef void (*btf_trace_xdp_redirect_map_err)(void *, const struct net_device *, const struct bpf_prog *, const void *, int, enum bpf_map_type, u32, u32);\n\ntypedef void (*btf_trace_xdp_cpumap_kthread)(void *, int, unsigned int, unsigned int, int, struct xdp_cpumap_stats *);\n\ntypedef void (*btf_trace_xdp_cpumap_enqueue)(void *, int, unsigned int, unsigned int, int);\n\ntypedef void (*btf_trace_xdp_devmap_xmit)(void *, const struct net_device *, const struct net_device *, int, int, int);\n\ntypedef void (*btf_trace_mem_disconnect)(void *, const struct xdp_mem_allocator *);\n\ntypedef void (*btf_trace_mem_connect)(void *, const struct xdp_mem_allocator *, const struct xdp_rxq_info *);\n\ntypedef void (*btf_trace_mem_return_failed)(void *, const struct xdp_mem_info *, const struct page *);\n\nenum bpf_cmd {\n\tBPF_MAP_CREATE = 0,\n\tBPF_MAP_LOOKUP_ELEM = 1,\n\tBPF_MAP_UPDATE_ELEM = 2,\n\tBPF_MAP_DELETE_ELEM = 3,\n\tBPF_MAP_GET_NEXT_KEY = 4,\n\tBPF_PROG_LOAD = 5,\n\tBPF_OBJ_PIN = 6,\n\tBPF_OBJ_GET = 7,\n\tBPF_PROG_ATTACH = 8,\n\tBPF_PROG_DETACH = 9,\n\tBPF_PROG_TEST_RUN = 10,\n\tBPF_PROG_RUN = 10,\n\tBPF_PROG_GET_NEXT_ID = 11,\n\tBPF_MAP_GET_NEXT_ID = 12,\n\tBPF_PROG_GET_FD_BY_ID = 13,\n\tBPF_MAP_GET_FD_BY_ID = 14,\n\tBPF_OBJ_GET_INFO_BY_FD = 15,\n\tBPF_PROG_QUERY = 16,\n\tBPF_RAW_TRACEPOINT_OPEN = 17,\n\tBPF_BTF_LOAD = 18,\n\tBPF_BTF_GET_FD_BY_ID = 19,\n\tBPF_TASK_FD_QUERY = 20,\n\tBPF_MAP_LOOKUP_AND_DELETE_ELEM = 21,\n\tBPF_MAP_FREEZE = 22,\n\tBPF_BTF_GET_NEXT_ID = 23,\n\tBPF_MAP_LOOKUP_BATCH = 24,\n\tBPF_MAP_LOOKUP_AND_DELETE_BATCH = 25,\n\tBPF_MAP_UPDATE_BATCH = 26,\n\tBPF_MAP_DELETE_BATCH = 27,\n\tBPF_LINK_CREATE = 28,\n\tBPF_LINK_UPDATE = 29,\n\tBPF_LINK_GET_FD_BY_ID = 30,\n\tBPF_LINK_GET_NEXT_ID = 31,\n\tBPF_ENABLE_STATS = 32,\n\tBPF_ITER_CREATE = 33,\n\tBPF_LINK_DETACH = 34,\n\tBPF_PROG_BIND_MAP = 35,\n};\n\nenum {\n\tBPF_ANY = 0,\n\tBPF_NOEXIST = 1,\n\tBPF_EXIST = 2,\n\tBPF_F_LOCK = 4,\n};\n\nenum {\n\tBPF_F_NO_PREALLOC = 1,\n\tBPF_F_NO_COMMON_LRU = 2,\n\tBPF_F_NUMA_NODE = 4,\n\tBPF_F_RDONLY = 8,\n\tBPF_F_WRONLY = 16,\n\tBPF_F_STACK_BUILD_ID = 32,\n\tBPF_F_ZERO_SEED = 64,\n\tBPF_F_RDONLY_PROG = 128,\n\tBPF_F_WRONLY_PROG = 256,\n\tBPF_F_CLONE = 512,\n\tBPF_F_MMAPABLE = 1024,\n\tBPF_F_PRESERVE_ELEMS = 2048,\n\tBPF_F_INNER_MAP = 4096,\n};\n\nenum bpf_stats_type {\n\tBPF_STATS_RUN_TIME = 0,\n};\n\nstruct bpf_prog_info {\n\t__u32 type;\n\t__u32 id;\n\t__u8 tag[8];\n\t__u32 jited_prog_len;\n\t__u32 xlated_prog_len;\n\t__u64 jited_prog_insns;\n\t__u64 xlated_prog_insns;\n\t__u64 load_time;\n\t__u32 created_by_uid;\n\t__u32 nr_map_ids;\n\t__u64 map_ids;\n\tchar name[16];\n\t__u32 ifindex;\n\t__u32 gpl_compatible: 1;\n\t__u64 netns_dev;\n\t__u64 netns_ino;\n\t__u32 nr_jited_ksyms;\n\t__u32 nr_jited_func_lens;\n\t__u64 jited_ksyms;\n\t__u64 jited_func_lens;\n\t__u32 btf_id;\n\t__u32 func_info_rec_size;\n\t__u64 func_info;\n\t__u32 nr_func_info;\n\t__u32 nr_line_info;\n\t__u64 line_info;\n\t__u64 jited_line_info;\n\t__u32 nr_jited_line_info;\n\t__u32 line_info_rec_size;\n\t__u32 jited_line_info_rec_size;\n\t__u32 nr_prog_tags;\n\t__u64 prog_tags;\n\t__u64 run_time_ns;\n\t__u64 run_cnt;\n\t__u64 recursion_misses;\n};\n\nstruct bpf_map_info {\n\t__u32 type;\n\t__u32 id;\n\t__u32 key_size;\n\t__u32 value_size;\n\t__u32 max_entries;\n\t__u32 map_flags;\n\tchar name[16];\n\t__u32 ifindex;\n\t__u32 btf_vmlinux_value_type_id;\n\t__u64 netns_dev;\n\t__u64 netns_ino;\n\t__u32 btf_id;\n\t__u32 btf_key_type_id;\n\t__u32 btf_value_type_id;\n};\n\nstruct bpf_btf_info {\n\t__u64 btf;\n\t__u32 btf_size;\n\t__u32 id;\n\t__u64 name;\n\t__u32 name_len;\n\t__u32 kernel_btf;\n};\n\nstruct bpf_spin_lock {\n\t__u32 val;\n};\n\ntypedef sockptr_t bpfptr_t;\n\nstruct bpf_verifier_log {\n\tu32 level;\n\tchar kbuf[1024];\n\tchar *ubuf;\n\tu32 len_used;\n\tu32 len_total;\n};\n\nstruct bpf_subprog_info {\n\tu32 start;\n\tu32 linfo_idx;\n\tu16 stack_depth;\n\tbool has_tail_call;\n\tbool tail_call_reachable;\n\tbool has_ld_abs;\n};\n\nstruct bpf_id_pair {\n\tu32 old;\n\tu32 cur;\n};\n\nstruct bpf_verifier_stack_elem;\n\nstruct bpf_verifier_state;\n\nstruct bpf_verifier_state_list;\n\nstruct bpf_insn_aux_data;\n\nstruct bpf_verifier_env {\n\tu32 insn_idx;\n\tu32 prev_insn_idx;\n\tstruct bpf_prog *prog;\n\tconst struct bpf_verifier_ops *ops;\n\tstruct bpf_verifier_stack_elem *head;\n\tint stack_size;\n\tbool strict_alignment;\n\tbool test_state_freq;\n\tstruct bpf_verifier_state *cur_state;\n\tstruct bpf_verifier_state_list **explored_states;\n\tstruct bpf_verifier_state_list *free_list;\n\tstruct bpf_map *used_maps[64];\n\tstruct btf_mod_pair used_btfs[64];\n\tu32 used_map_cnt;\n\tu32 used_btf_cnt;\n\tu32 id_gen;\n\tbool explore_alu_limits;\n\tbool allow_ptr_leaks;\n\tbool allow_uninit_stack;\n\tbool allow_ptr_to_map_access;\n\tbool bpf_capable;\n\tbool bypass_spec_v1;\n\tbool bypass_spec_v4;\n\tbool seen_direct_write;\n\tstruct bpf_insn_aux_data *insn_aux_data;\n\tconst struct bpf_line_info *prev_linfo;\n\tstruct bpf_verifier_log log;\n\tstruct bpf_subprog_info subprog_info[257];\n\tstruct bpf_id_pair idmap_scratch[75];\n\tstruct {\n\t\tint *insn_state;\n\t\tint *insn_stack;\n\t\tint cur_stack;\n\t} cfg;\n\tu32 pass_cnt;\n\tu32 subprog_cnt;\n\tu32 prev_insn_processed;\n\tu32 insn_processed;\n\tu32 prev_jmps_processed;\n\tu32 jmps_processed;\n\tu64 verification_time;\n\tu32 max_states_per_insn;\n\tu32 total_states;\n\tu32 peak_states;\n\tu32 longest_mark_read_walk;\n\tbpfptr_t fd_array;\n};\n\nstruct tnum {\n\tu64 value;\n\tu64 mask;\n};\n\nenum bpf_reg_liveness {\n\tREG_LIVE_NONE = 0,\n\tREG_LIVE_READ32 = 1,\n\tREG_LIVE_READ64 = 2,\n\tREG_LIVE_READ = 3,\n\tREG_LIVE_WRITTEN = 4,\n\tREG_LIVE_DONE = 8,\n};\n\nstruct bpf_reg_state {\n\tenum bpf_reg_type type;\n\ts32 off;\n\tunion {\n\t\tint range;\n\t\tstruct bpf_map *map_ptr;\n\t\tstruct {\n\t\t\tstruct btf *btf;\n\t\t\tu32 btf_id;\n\t\t};\n\t\tu32 mem_size;\n\t\tstruct {\n\t\t\tlong unsigned int raw1;\n\t\t\tlong unsigned int raw2;\n\t\t} raw;\n\t\tu32 subprogno;\n\t};\n\tu32 id;\n\tu32 ref_obj_id;\n\tstruct tnum var_off;\n\ts64 smin_value;\n\ts64 smax_value;\n\tu64 umin_value;\n\tu64 umax_value;\n\ts32 s32_min_value;\n\ts32 s32_max_value;\n\tu32 u32_min_value;\n\tu32 u32_max_value;\n\tstruct bpf_reg_state *parent;\n\tu32 frameno;\n\ts32 subreg_def;\n\tenum bpf_reg_liveness live;\n\tbool precise;\n};\n\nstruct bpf_reference_state;\n\nstruct bpf_stack_state;\n\nstruct bpf_func_state {\n\tstruct bpf_reg_state regs[11];\n\tint callsite;\n\tu32 frameno;\n\tu32 subprogno;\n\tint acquired_refs;\n\tstruct bpf_reference_state *refs;\n\tint allocated_stack;\n\tbool in_callback_fn;\n\tstruct bpf_stack_state *stack;\n};\n\nstruct bpf_attach_target_info {\n\tstruct btf_func_model fmodel;\n\tlong int tgt_addr;\n\tconst char *tgt_name;\n\tconst struct btf_type *tgt_type;\n};\n\nstruct bpf_link_primer {\n\tstruct bpf_link *link;\n\tstruct file *file;\n\tint fd;\n\tu32 id;\n};\n\nstruct bpf_stack_state {\n\tstruct bpf_reg_state spilled_ptr;\n\tu8 slot_type[8];\n};\n\nstruct bpf_reference_state {\n\tint id;\n\tint insn_idx;\n};\n\nstruct bpf_idx_pair {\n\tu32 prev_idx;\n\tu32 idx;\n};\n\nstruct bpf_verifier_state {\n\tstruct bpf_func_state *frame[8];\n\tstruct bpf_verifier_state *parent;\n\tu32 branches;\n\tu32 insn_idx;\n\tu32 curframe;\n\tu32 active_spin_lock;\n\tbool speculative;\n\tu32 first_insn_idx;\n\tu32 last_insn_idx;\n\tstruct bpf_idx_pair *jmp_history;\n\tu32 jmp_history_cnt;\n};\n\nstruct bpf_verifier_state_list {\n\tstruct bpf_verifier_state state;\n\tstruct bpf_verifier_state_list *next;\n\tint miss_cnt;\n\tint hit_cnt;\n};\n\nstruct bpf_insn_aux_data {\n\tunion {\n\t\tenum bpf_reg_type ptr_type;\n\t\tlong unsigned int map_ptr_state;\n\t\ts32 call_imm;\n\t\tu32 alu_limit;\n\t\tstruct {\n\t\t\tu32 map_index;\n\t\t\tu32 map_off;\n\t\t};\n\t\tstruct {\n\t\t\tenum bpf_reg_type reg_type;\n\t\t\tunion {\n\t\t\t\tstruct {\n\t\t\t\t\tstruct btf *btf;\n\t\t\t\t\tu32 btf_id;\n\t\t\t\t};\n\t\t\t\tu32 mem_size;\n\t\t\t};\n\t\t} btf_var;\n\t};\n\tu64 map_key_state;\n\tint ctx_field_size;\n\tu32 seen;\n\tbool sanitize_stack_spill;\n\tbool zext_dst;\n\tu8 alu_state;\n\tunsigned int orig_idx;\n\tbool prune_point;\n};\n\nenum perf_bpf_event_type {\n\tPERF_BPF_EVENT_UNKNOWN = 0,\n\tPERF_BPF_EVENT_PROG_LOAD = 1,\n\tPERF_BPF_EVENT_PROG_UNLOAD = 2,\n\tPERF_BPF_EVENT_MAX = 3,\n};\n\nenum bpf_audit {\n\tBPF_AUDIT_LOAD = 0,\n\tBPF_AUDIT_UNLOAD = 1,\n\tBPF_AUDIT_MAX = 2,\n};\n\nstruct bpf_tracing_link {\n\tstruct bpf_link link;\n\tenum bpf_attach_type attach_type;\n\tstruct bpf_trampoline *trampoline;\n\tstruct bpf_prog *tgt_prog;\n};\n\nstruct bpf_raw_tp_link {\n\tstruct bpf_link link;\n\tstruct bpf_raw_event_map *btp;\n};\n\ntypedef u64 (*btf_bpf_sys_bpf)(int, void *, u32);\n\ntypedef u64 (*btf_bpf_sys_close)(u32);\n\nstruct btf_member {\n\t__u32 name_off;\n\t__u32 type;\n\t__u32 offset;\n};\n\nstruct btf_param {\n\t__u32 name_off;\n\t__u32 type;\n};\n\nenum btf_func_linkage {\n\tBTF_FUNC_STATIC = 0,\n\tBTF_FUNC_GLOBAL = 1,\n\tBTF_FUNC_EXTERN = 2,\n};\n\nstruct btf_var_secinfo {\n\t__u32 type;\n\t__u32 offset;\n\t__u32 size;\n};\n\nenum sk_action {\n\tSK_DROP = 0,\n\tSK_PASS = 1,\n};\n\nstruct bpf_kfunc_desc {\n\tstruct btf_func_model func_model;\n\tu32 func_id;\n\ts32 imm;\n};\n\nstruct bpf_kfunc_desc_tab {\n\tstruct bpf_kfunc_desc descs[256];\n\tu32 nr_descs;\n};\n\nstruct bpf_struct_ops {\n\tconst struct bpf_verifier_ops *verifier_ops;\n\tint (*init)(struct btf *);\n\tint (*check_member)(const struct btf_type *, const struct btf_member *);\n\tint (*init_member)(const struct btf_type *, const struct btf_member *, void *, const void *);\n\tint (*reg)(void *);\n\tvoid (*unreg)(void *);\n\tconst struct btf_type *type;\n\tconst struct btf_type *value_type;\n\tconst char *name;\n\tstruct btf_func_model func_models[64];\n\tu32 type_id;\n\tu32 value_id;\n};\n\ntypedef u32 (*bpf_convert_ctx_access_t)(enum bpf_access_type, const struct bpf_insn *, struct bpf_insn *, struct bpf_prog *, u32 *);\n\nenum bpf_stack_slot_type {\n\tSTACK_INVALID = 0,\n\tSTACK_SPILL = 1,\n\tSTACK_MISC = 2,\n\tSTACK_ZERO = 3,\n};\n\nstruct bpf_verifier_stack_elem {\n\tstruct bpf_verifier_state st;\n\tint insn_idx;\n\tint prev_insn_idx;\n\tstruct bpf_verifier_stack_elem *next;\n\tu32 log_pos;\n};\n\nenum {\n\tBTF_SOCK_TYPE_INET = 0,\n\tBTF_SOCK_TYPE_INET_CONN = 1,\n\tBTF_SOCK_TYPE_INET_REQ = 2,\n\tBTF_SOCK_TYPE_INET_TW = 3,\n\tBTF_SOCK_TYPE_REQ = 4,\n\tBTF_SOCK_TYPE_SOCK = 5,\n\tBTF_SOCK_TYPE_SOCK_COMMON = 6,\n\tBTF_SOCK_TYPE_TCP = 7,\n\tBTF_SOCK_TYPE_TCP_REQ = 8,\n\tBTF_SOCK_TYPE_TCP_TW = 9,\n\tBTF_SOCK_TYPE_TCP6 = 10,\n\tBTF_SOCK_TYPE_UDP = 11,\n\tBTF_SOCK_TYPE_UDP6 = 12,\n\tMAX_BTF_SOCK_TYPE = 13,\n};\n\ntypedef void (*bpf_insn_print_t)(void *, const char *, ...);\n\ntypedef const char * (*bpf_insn_revmap_call_t)(void *, const struct bpf_insn *);\n\ntypedef const char * (*bpf_insn_print_imm_t)(void *, const struct bpf_insn *, __u64);\n\nstruct bpf_insn_cbs {\n\tbpf_insn_print_t cb_print;\n\tbpf_insn_revmap_call_t cb_call;\n\tbpf_insn_print_imm_t cb_imm;\n\tvoid *private_data;\n};\n\nstruct bpf_call_arg_meta {\n\tstruct bpf_map *map_ptr;\n\tbool raw_mode;\n\tbool pkt_access;\n\tint regno;\n\tint access_size;\n\tint mem_size;\n\tu64 msize_max_value;\n\tint ref_obj_id;\n\tint func_id;\n\tstruct btf *btf;\n\tu32 btf_id;\n\tstruct btf *ret_btf;\n\tu32 ret_btf_id;\n\tu32 subprogno;\n};\n\nenum reg_arg_type {\n\tSRC_OP = 0,\n\tDST_OP = 1,\n\tDST_OP_NO_MARK = 2,\n};\n\nenum stack_access_src {\n\tACCESS_DIRECT = 1,\n\tACCESS_HELPER = 2,\n};\n\nstruct bpf_reg_types {\n\tconst enum bpf_reg_type types[10];\n\tu32 *btf_id;\n};\n\nenum {\n\tAT_PKT_END = 4294967295,\n\tBEYOND_PKT_END = 4294967294,\n};\n\ntypedef int (*set_callee_state_fn)(struct bpf_verifier_env *, struct bpf_func_state *, struct bpf_func_state *, int);\n\nenum {\n\tREASON_BOUNDS = 4294967295,\n\tREASON_TYPE = 4294967294,\n\tREASON_PATHS = 4294967293,\n\tREASON_LIMIT = 4294967292,\n\tREASON_STACK = 4294967291,\n};\n\nstruct bpf_sanitize_info {\n\tstruct bpf_insn_aux_data aux;\n\tbool mask_to_left;\n};\n\nenum {\n\tDISCOVERED = 16,\n\tEXPLORED = 32,\n\tFALLTHROUGH = 1,\n\tBRANCH = 2,\n};\n\nenum {\n\tDONE_EXPLORING = 0,\n\tKEEP_EXPLORING = 1,\n};\n\nstruct tree_descr {\n\tconst char *name;\n\tconst struct file_operations *ops;\n\tint mode;\n};\n\nstruct bpf_preload_info {\n\tchar link_name[16];\n\tint link_id;\n};\n\nstruct bpf_preload_ops {\n\tstruct umd_info info;\n\tint (*preload)(struct bpf_preload_info *);\n\tint (*finish)();\n\tstruct module *owner;\n};\n\nenum bpf_type {\n\tBPF_TYPE_UNSPEC = 0,\n\tBPF_TYPE_PROG = 1,\n\tBPF_TYPE_MAP = 2,\n\tBPF_TYPE_LINK = 3,\n};\n\nstruct map_iter {\n\tvoid *key;\n\tbool done;\n};\n\nenum {\n\tOPT_MODE = 0,\n};\n\nstruct bpf_mount_opts {\n\tumode_t mode;\n};\n\nstruct bpf_pidns_info {\n\t__u32 pid;\n\t__u32 tgid;\n};\n\nstruct bpf_cgroup_storage_info {\n\tstruct task_struct *task;\n\tstruct bpf_cgroup_storage *storage[2];\n};\n\ntypedef u64 (*btf_bpf_map_lookup_elem)(struct bpf_map *, void *);\n\ntypedef u64 (*btf_bpf_map_update_elem)(struct bpf_map *, void *, void *, u64);\n\ntypedef u64 (*btf_bpf_map_delete_elem)(struct bpf_map *, void *);\n\ntypedef u64 (*btf_bpf_map_push_elem)(struct bpf_map *, void *, u64);\n\ntypedef u64 (*btf_bpf_map_pop_elem)(struct bpf_map *, void *);\n\ntypedef u64 (*btf_bpf_map_peek_elem)(struct bpf_map *, void *);\n\ntypedef u64 (*btf_bpf_get_smp_processor_id)();\n\ntypedef u64 (*btf_bpf_get_numa_node_id)();\n\ntypedef u64 (*btf_bpf_ktime_get_ns)();\n\ntypedef u64 (*btf_bpf_ktime_get_boot_ns)();\n\ntypedef u64 (*btf_bpf_ktime_get_coarse_ns)();\n\ntypedef u64 (*btf_bpf_get_current_pid_tgid)();\n\ntypedef u64 (*btf_bpf_get_current_uid_gid)();\n\ntypedef u64 (*btf_bpf_get_current_comm)(char *, u32);\n\ntypedef u64 (*btf_bpf_spin_lock)(struct bpf_spin_lock *);\n\ntypedef u64 (*btf_bpf_spin_unlock)(struct bpf_spin_lock *);\n\ntypedef u64 (*btf_bpf_jiffies64)();\n\ntypedef u64 (*btf_bpf_get_current_cgroup_id)();\n\ntypedef u64 (*btf_bpf_get_current_ancestor_cgroup_id)(int);\n\ntypedef u64 (*btf_bpf_get_local_storage)(struct bpf_map *, u64);\n\ntypedef u64 (*btf_bpf_strtol)(const char *, size_t, u64, long int *);\n\ntypedef u64 (*btf_bpf_strtoul)(const char *, size_t, u64, long unsigned int *);\n\ntypedef u64 (*btf_bpf_get_ns_current_pid_tgid)(u64, u64, struct bpf_pidns_info *, u32);\n\ntypedef u64 (*btf_bpf_event_output_data)(void *, struct bpf_map *, u64, void *, u64);\n\ntypedef u64 (*btf_bpf_copy_from_user)(void *, u32, const void *);\n\ntypedef u64 (*btf_bpf_per_cpu_ptr)(const void *, u32);\n\ntypedef u64 (*btf_bpf_this_cpu_ptr)(const void *);\n\nstruct bpf_bprintf_buffers {\n\tchar tmp_bufs[1536];\n};\n\ntypedef u64 (*btf_bpf_snprintf)(char *, u32, char *, const void *, u32);\n\nunion bpf_iter_link_info {\n\tstruct {\n\t\t__u32 map_fd;\n\t} map;\n};\n\ntypedef int (*bpf_iter_attach_target_t)(struct bpf_prog *, union bpf_iter_link_info *, struct bpf_iter_aux_info *);\n\ntypedef void (*bpf_iter_detach_target_t)(struct bpf_iter_aux_info *);\n\ntypedef void (*bpf_iter_show_fdinfo_t)(const struct bpf_iter_aux_info *, struct seq_file *);\n\ntypedef int (*bpf_iter_fill_link_info_t)(const struct bpf_iter_aux_info *, struct bpf_link_info *);\n\nenum bpf_iter_feature {\n\tBPF_ITER_RESCHED = 1,\n};\n\nstruct bpf_iter_reg {\n\tconst char *target;\n\tbpf_iter_attach_target_t attach_target;\n\tbpf_iter_detach_target_t detach_target;\n\tbpf_iter_show_fdinfo_t show_fdinfo;\n\tbpf_iter_fill_link_info_t fill_link_info;\n\tu32 ctx_arg_info_size;\n\tu32 feature;\n\tstruct bpf_ctx_arg_aux ctx_arg_info[2];\n\tconst struct bpf_iter_seq_info *seq_info;\n};\n\nstruct bpf_iter_meta {\n\tunion {\n\t\tstruct seq_file *seq;\n\t};\n\tu64 session_id;\n\tu64 seq_num;\n};\n\nstruct bpf_iter_target_info {\n\tstruct list_head list;\n\tconst struct bpf_iter_reg *reg_info;\n\tu32 btf_id;\n};\n\nstruct bpf_iter_link {\n\tstruct bpf_link link;\n\tstruct bpf_iter_aux_info aux;\n\tstruct bpf_iter_target_info *tinfo;\n};\n\nstruct bpf_iter_priv_data {\n\tstruct bpf_iter_target_info *tinfo;\n\tconst struct bpf_iter_seq_info *seq_info;\n\tstruct bpf_prog *prog;\n\tu64 session_id;\n\tu64 seq_num;\n\tbool done_stop;\n\tlong: 56;\n\tu8 target_private[0];\n};\n\ntypedef u64 (*btf_bpf_for_each_map_elem)(struct bpf_map *, void *, void *, u64);\n\nstruct bpf_iter_seq_map_info {\n\tu32 map_id;\n};\n\nstruct bpf_iter__bpf_map {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct bpf_map *map;\n\t};\n};\n\nstruct bpf_iter_seq_task_common {\n\tstruct pid_namespace *ns;\n};\n\nstruct bpf_iter_seq_task_info {\n\tstruct bpf_iter_seq_task_common common;\n\tu32 tid;\n};\n\nstruct bpf_iter__task {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct task_struct *task;\n\t};\n};\n\nstruct bpf_iter_seq_task_file_info {\n\tstruct bpf_iter_seq_task_common common;\n\tstruct task_struct *task;\n\tu32 tid;\n\tu32 fd;\n};\n\nstruct bpf_iter__task_file {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct task_struct *task;\n\t};\n\tu32 fd;\n\tunion {\n\t\tstruct file *file;\n\t};\n};\n\nstruct bpf_iter_seq_task_vma_info {\n\tstruct bpf_iter_seq_task_common common;\n\tstruct task_struct *task;\n\tstruct vm_area_struct *vma;\n\tu32 tid;\n\tlong unsigned int prev_vm_start;\n\tlong unsigned int prev_vm_end;\n};\n\nenum bpf_task_vma_iter_find_op {\n\ttask_vma_iter_first_vma = 0,\n\ttask_vma_iter_next_vma = 1,\n\ttask_vma_iter_find_vma = 2,\n};\n\nstruct bpf_iter__task_vma {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct task_struct *task;\n\t};\n\tunion {\n\t\tstruct vm_area_struct *vma;\n\t};\n};\n\nstruct bpf_iter_seq_prog_info {\n\tu32 prog_id;\n};\n\nstruct bpf_iter__bpf_prog {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct bpf_prog *prog;\n\t};\n};\n\nstruct bpf_iter__bpf_map_elem {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct bpf_map *map;\n\t};\n\tunion {\n\t\tvoid *key;\n\t};\n\tunion {\n\t\tvoid *value;\n\t};\n};\n\nstruct pcpu_freelist_node;\n\nstruct pcpu_freelist_head {\n\tstruct pcpu_freelist_node *first;\n\traw_spinlock_t lock;\n};\n\nstruct pcpu_freelist_node {\n\tstruct pcpu_freelist_node *next;\n};\n\nstruct pcpu_freelist {\n\tstruct pcpu_freelist_head *freelist;\n\tstruct pcpu_freelist_head extralist;\n};\n\nstruct bpf_lru_node {\n\tstruct list_head list;\n\tu16 cpu;\n\tu8 type;\n\tu8 ref;\n};\n\nstruct bpf_lru_list {\n\tstruct list_head lists[3];\n\tunsigned int counts[2];\n\tstruct list_head *next_inactive_rotation;\n\traw_spinlock_t lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct bpf_lru_locallist {\n\tstruct list_head lists[2];\n\tu16 next_steal;\n\traw_spinlock_t lock;\n};\n\nstruct bpf_common_lru {\n\tstruct bpf_lru_list lru_list;\n\tstruct bpf_lru_locallist *local_list;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\ntypedef bool (*del_from_htab_func)(void *, struct bpf_lru_node *);\n\nstruct bpf_lru {\n\tunion {\n\t\tstruct bpf_common_lru common_lru;\n\t\tstruct bpf_lru_list *percpu_lru;\n\t};\n\tdel_from_htab_func del_from_htab;\n\tvoid *del_arg;\n\tunsigned int hash_offset;\n\tunsigned int nr_scans;\n\tbool percpu;\n\tlong: 56;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct bucket {\n\tstruct hlist_nulls_head head;\n\tunion {\n\t\traw_spinlock_t raw_lock;\n\t\tspinlock_t lock;\n\t};\n};\n\nstruct htab_elem;\n\nstruct bpf_htab {\n\tstruct bpf_map map;\n\tstruct bucket *buckets;\n\tvoid *elems;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tunion {\n\t\tstruct pcpu_freelist freelist;\n\t\tstruct bpf_lru lru;\n\t};\n\tstruct htab_elem **extra_elems;\n\tatomic_t count;\n\tu32 n_buckets;\n\tu32 elem_size;\n\tu32 hashrnd;\n\tstruct lock_class_key lockdep_key;\n\tint *map_locked[8];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct htab_elem {\n\tunion {\n\t\tstruct hlist_nulls_node hash_node;\n\t\tstruct {\n\t\t\tvoid *padding;\n\t\t\tunion {\n\t\t\t\tstruct bpf_htab *htab;\n\t\t\t\tstruct pcpu_freelist_node fnode;\n\t\t\t\tstruct htab_elem *batch_flink;\n\t\t\t};\n\t\t};\n\t};\n\tunion {\n\t\tstruct callback_head rcu;\n\t\tstruct bpf_lru_node lru_node;\n\t};\n\tu32 hash;\n\tint: 32;\n\tchar key[0];\n};\n\nstruct bpf_iter_seq_hash_map_info {\n\tstruct bpf_map *map;\n\tstruct bpf_htab *htab;\n\tvoid *percpu_value_buf;\n\tu32 bucket_id;\n\tu32 skip_elems;\n};\n\nstruct bpf_iter_seq_array_map_info {\n\tstruct bpf_map *map;\n\tvoid *percpu_value_buf;\n\tu32 index;\n};\n\nstruct prog_poke_elem {\n\tstruct list_head list;\n\tstruct bpf_prog_aux *aux;\n};\n\nenum bpf_lru_list_type {\n\tBPF_LRU_LIST_T_ACTIVE = 0,\n\tBPF_LRU_LIST_T_INACTIVE = 1,\n\tBPF_LRU_LIST_T_FREE = 2,\n\tBPF_LRU_LOCAL_LIST_T_FREE = 3,\n\tBPF_LRU_LOCAL_LIST_T_PENDING = 4,\n};\n\nstruct bpf_lpm_trie_key {\n\t__u32 prefixlen;\n\t__u8 data[0];\n};\n\nstruct lpm_trie_node {\n\tstruct callback_head rcu;\n\tstruct lpm_trie_node *child[2];\n\tu32 prefixlen;\n\tu32 flags;\n\tu8 data[0];\n};\n\nstruct lpm_trie {\n\tstruct bpf_map map;\n\tstruct lpm_trie_node *root;\n\tsize_t n_entries;\n\tsize_t max_prefixlen;\n\tsize_t data_size;\n\tspinlock_t lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct bpf_cgroup_storage_map {\n\tstruct bpf_map map;\n\tspinlock_t lock;\n\tstruct rb_root root;\n\tstruct list_head list;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct bpf_queue_stack {\n\tstruct bpf_map map;\n\traw_spinlock_t lock;\n\tu32 head;\n\tu32 tail;\n\tu32 size;\n\tchar elements[0];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum {\n\tBPF_RB_NO_WAKEUP = 1,\n\tBPF_RB_FORCE_WAKEUP = 2,\n};\n\nenum {\n\tBPF_RB_AVAIL_DATA = 0,\n\tBPF_RB_RING_SIZE = 1,\n\tBPF_RB_CONS_POS = 2,\n\tBPF_RB_PROD_POS = 3,\n};\n\nenum {\n\tBPF_RINGBUF_BUSY_BIT = 2147483648,\n\tBPF_RINGBUF_DISCARD_BIT = 1073741824,\n\tBPF_RINGBUF_HDR_SZ = 8,\n};\n\nstruct bpf_ringbuf {\n\twait_queue_head_t waitq;\n\tstruct irq_work work;\n\tu64 mask;\n\tstruct page **pages;\n\tint nr_pages;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tspinlock_t spinlock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong unsigned int consumer_pos;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong unsigned int producer_pos;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tchar data[0];\n};\n\nstruct bpf_ringbuf_map {\n\tstruct bpf_map map;\n\tstruct bpf_ringbuf *rb;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct bpf_ringbuf_hdr {\n\tu32 len;\n\tu32 pg_off;\n};\n\ntypedef u64 (*btf_bpf_ringbuf_reserve)(struct bpf_map *, u64, u64);\n\ntypedef u64 (*btf_bpf_ringbuf_submit)(void *, u64);\n\ntypedef u64 (*btf_bpf_ringbuf_discard)(void *, u64);\n\ntypedef u64 (*btf_bpf_ringbuf_output)(struct bpf_map *, void *, u64, u64);\n\ntypedef u64 (*btf_bpf_ringbuf_query)(struct bpf_map *, u64);\n\nstruct bpf_local_storage_elem {\n\tstruct hlist_node map_node;\n\tstruct hlist_node snode;\n\tstruct bpf_local_storage *local_storage;\n\tstruct callback_head rcu;\n\tlong: 64;\n\tstruct bpf_local_storage_data sdata;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct bpf_local_storage_cache {\n\tspinlock_t idx_lock;\n\tu64 idx_usage_counts[16];\n};\n\nenum {\n\tBPF_LOCAL_STORAGE_GET_F_CREATE = 1,\n\tBPF_SK_STORAGE_GET_F_CREATE = 1,\n};\n\ntypedef u64 (*btf_bpf_task_storage_get)(struct bpf_map *, struct task_struct *, void *, u64);\n\ntypedef u64 (*btf_bpf_task_storage_delete)(struct bpf_map *, struct task_struct *);\n\nstruct lsm_blob_sizes {\n\tint lbs_cred;\n\tint lbs_file;\n\tint lbs_inode;\n\tint lbs_superblock;\n\tint lbs_ipc;\n\tint lbs_msg_msg;\n\tint lbs_task;\n};\n\nstruct bpf_storage_blob {\n\tstruct bpf_local_storage *storage;\n};\n\ntypedef u64 (*btf_bpf_inode_storage_get)(struct bpf_map *, struct inode *, void *, u64);\n\ntypedef u64 (*btf_bpf_inode_storage_delete)(struct bpf_map *, struct inode *);\n\nstruct btf_enum {\n\t__u32 name_off;\n\t__s32 val;\n};\n\nstruct btf_array {\n\t__u32 type;\n\t__u32 index_type;\n\t__u32 nelems;\n};\n\nenum {\n\tBTF_VAR_STATIC = 0,\n\tBTF_VAR_GLOBAL_ALLOCATED = 1,\n\tBTF_VAR_GLOBAL_EXTERN = 2,\n};\n\nstruct btf_var {\n\t__u32 linkage;\n};\n\nstruct bpf_flow_keys {\n\t__u16 nhoff;\n\t__u16 thoff;\n\t__u16 addr_proto;\n\t__u8 is_frag;\n\t__u8 is_first_frag;\n\t__u8 is_encap;\n\t__u8 ip_proto;\n\t__be16 n_proto;\n\t__be16 sport;\n\t__be16 dport;\n\tunion {\n\t\tstruct {\n\t\t\t__be32 ipv4_src;\n\t\t\t__be32 ipv4_dst;\n\t\t};\n\t\tstruct {\n\t\t\t__u32 ipv6_src[4];\n\t\t\t__u32 ipv6_dst[4];\n\t\t};\n\t};\n\t__u32 flags;\n\t__be32 flow_label;\n};\n\nstruct bpf_sock {\n\t__u32 bound_dev_if;\n\t__u32 family;\n\t__u32 type;\n\t__u32 protocol;\n\t__u32 mark;\n\t__u32 priority;\n\t__u32 src_ip4;\n\t__u32 src_ip6[4];\n\t__u32 src_port;\n\t__u32 dst_port;\n\t__u32 dst_ip4;\n\t__u32 dst_ip6[4];\n\t__u32 state;\n\t__s32 rx_queue_mapping;\n};\n\nstruct __sk_buff {\n\t__u32 len;\n\t__u32 pkt_type;\n\t__u32 mark;\n\t__u32 queue_mapping;\n\t__u32 protocol;\n\t__u32 vlan_present;\n\t__u32 vlan_tci;\n\t__u32 vlan_proto;\n\t__u32 priority;\n\t__u32 ingress_ifindex;\n\t__u32 ifindex;\n\t__u32 tc_index;\n\t__u32 cb[5];\n\t__u32 hash;\n\t__u32 tc_classid;\n\t__u32 data;\n\t__u32 data_end;\n\t__u32 napi_id;\n\t__u32 family;\n\t__u32 remote_ip4;\n\t__u32 local_ip4;\n\t__u32 remote_ip6[4];\n\t__u32 local_ip6[4];\n\t__u32 remote_port;\n\t__u32 local_port;\n\t__u32 data_meta;\n\tunion {\n\t\tstruct bpf_flow_keys *flow_keys;\n\t};\n\t__u64 tstamp;\n\t__u32 wire_len;\n\t__u32 gso_segs;\n\tunion {\n\t\tstruct bpf_sock *sk;\n\t};\n\t__u32 gso_size;\n};\n\nstruct xdp_md {\n\t__u32 data;\n\t__u32 data_end;\n\t__u32 data_meta;\n\t__u32 ingress_ifindex;\n\t__u32 rx_queue_index;\n\t__u32 egress_ifindex;\n};\n\nstruct sk_msg_md {\n\tunion {\n\t\tvoid *data;\n\t};\n\tunion {\n\t\tvoid *data_end;\n\t};\n\t__u32 family;\n\t__u32 remote_ip4;\n\t__u32 local_ip4;\n\t__u32 remote_ip6[4];\n\t__u32 local_ip6[4];\n\t__u32 remote_port;\n\t__u32 local_port;\n\t__u32 size;\n\tunion {\n\t\tstruct bpf_sock *sk;\n\t};\n};\n\nstruct sk_reuseport_md {\n\tunion {\n\t\tvoid *data;\n\t};\n\tunion {\n\t\tvoid *data_end;\n\t};\n\t__u32 len;\n\t__u32 eth_protocol;\n\t__u32 ip_protocol;\n\t__u32 bind_inany;\n\t__u32 hash;\n\tunion {\n\t\tstruct bpf_sock *sk;\n\t};\n\tunion {\n\t\tstruct bpf_sock *migrating_sk;\n\t};\n};\n\nstruct bpf_sock_addr {\n\t__u32 user_family;\n\t__u32 user_ip4;\n\t__u32 user_ip6[4];\n\t__u32 user_port;\n\t__u32 family;\n\t__u32 type;\n\t__u32 protocol;\n\t__u32 msg_src_ip4;\n\t__u32 msg_src_ip6[4];\n\tunion {\n\t\tstruct bpf_sock *sk;\n\t};\n};\n\nstruct bpf_sock_ops {\n\t__u32 op;\n\tunion {\n\t\t__u32 args[4];\n\t\t__u32 reply;\n\t\t__u32 replylong[4];\n\t};\n\t__u32 family;\n\t__u32 remote_ip4;\n\t__u32 local_ip4;\n\t__u32 remote_ip6[4];\n\t__u32 local_ip6[4];\n\t__u32 remote_port;\n\t__u32 local_port;\n\t__u32 is_fullsock;\n\t__u32 snd_cwnd;\n\t__u32 srtt_us;\n\t__u32 bpf_sock_ops_cb_flags;\n\t__u32 state;\n\t__u32 rtt_min;\n\t__u32 snd_ssthresh;\n\t__u32 rcv_nxt;\n\t__u32 snd_nxt;\n\t__u32 snd_una;\n\t__u32 mss_cache;\n\t__u32 ecn_flags;\n\t__u32 rate_delivered;\n\t__u32 rate_interval_us;\n\t__u32 packets_out;\n\t__u32 retrans_out;\n\t__u32 total_retrans;\n\t__u32 segs_in;\n\t__u32 data_segs_in;\n\t__u32 segs_out;\n\t__u32 data_segs_out;\n\t__u32 lost_out;\n\t__u32 sacked_out;\n\t__u32 sk_txhash;\n\t__u64 bytes_received;\n\t__u64 bytes_acked;\n\tunion {\n\t\tstruct bpf_sock *sk;\n\t};\n\tunion {\n\t\tvoid *skb_data;\n\t};\n\tunion {\n\t\tvoid *skb_data_end;\n\t};\n\t__u32 skb_len;\n\t__u32 skb_tcp_flags;\n};\n\nstruct bpf_cgroup_dev_ctx {\n\t__u32 access_type;\n\t__u32 major;\n\t__u32 minor;\n};\n\nstruct bpf_sysctl {\n\t__u32 write;\n\t__u32 file_pos;\n};\n\nstruct bpf_sockopt {\n\tunion {\n\t\tstruct bpf_sock *sk;\n\t};\n\tunion {\n\t\tvoid *optval;\n\t};\n\tunion {\n\t\tvoid *optval_end;\n\t};\n\t__s32 level;\n\t__s32 optname;\n\t__s32 optlen;\n\t__s32 retval;\n};\n\nstruct bpf_sk_lookup {\n\tunion {\n\t\tunion {\n\t\t\tstruct bpf_sock *sk;\n\t\t};\n\t\t__u64 cookie;\n\t};\n\t__u32 family;\n\t__u32 protocol;\n\t__u32 remote_ip4;\n\t__u32 remote_ip6[4];\n\t__u32 remote_port;\n\t__u32 local_ip4;\n\t__u32 local_ip6[4];\n\t__u32 local_port;\n};\n\nstruct sk_reuseport_kern {\n\tstruct sk_buff *skb;\n\tstruct sock *sk;\n\tstruct sock *selected_sk;\n\tstruct sock *migrating_sk;\n\tvoid *data_end;\n\tu32 hash;\n\tu32 reuseport_id;\n\tbool bind_inany;\n};\n\nstruct bpf_flow_dissector {\n\tstruct bpf_flow_keys *flow_keys;\n\tconst struct sk_buff *skb;\n\tconst void *data;\n\tconst void *data_end;\n};\n\nstruct inet_listen_hashbucket {\n\tspinlock_t lock;\n\tunsigned int count;\n\tunion {\n\t\tstruct hlist_head head;\n\t\tstruct hlist_nulls_head nulls_head;\n\t};\n};\n\nstruct inet_ehash_bucket;\n\nstruct inet_bind_hashbucket;\n\nstruct inet_hashinfo {\n\tstruct inet_ehash_bucket *ehash;\n\tspinlock_t *ehash_locks;\n\tunsigned int ehash_mask;\n\tunsigned int ehash_locks_mask;\n\tstruct kmem_cache *bind_bucket_cachep;\n\tstruct inet_bind_hashbucket *bhash;\n\tunsigned int bhash_size;\n\tunsigned int lhash2_mask;\n\tstruct inet_listen_hashbucket *lhash2;\n\tlong: 64;\n\tstruct inet_listen_hashbucket listening_hash[32];\n};\n\nstruct ip_ra_chain {\n\tstruct ip_ra_chain *next;\n\tstruct sock *sk;\n\tunion {\n\t\tvoid (*destructor)(struct sock *);\n\t\tstruct sock *saved_sk;\n\t};\n\tstruct callback_head rcu;\n};\n\nstruct fib_table {\n\tstruct hlist_node tb_hlist;\n\tu32 tb_id;\n\tint tb_num_default;\n\tstruct callback_head rcu;\n\tlong unsigned int *tb_data;\n\tlong unsigned int __data[0];\n};\n\nstruct inet_peer_base {\n\tstruct rb_root rb_root;\n\tseqlock_t lock;\n\tint total;\n};\n\nstruct tcp_fastopen_context {\n\tsiphash_key_t key[2];\n\tint num;\n\tstruct callback_head rcu;\n};\n\nstruct xdp_txq_info {\n\tstruct net_device *dev;\n};\n\nstruct xdp_buff {\n\tvoid *data;\n\tvoid *data_end;\n\tvoid *data_meta;\n\tvoid *data_hard_start;\n\tstruct xdp_rxq_info *rxq;\n\tstruct xdp_txq_info *txq;\n\tu32 frame_sz;\n};\n\nstruct bpf_sock_addr_kern {\n\tstruct sock *sk;\n\tstruct sockaddr *uaddr;\n\tu64 tmp_reg;\n\tvoid *t_ctx;\n};\n\nstruct bpf_sock_ops_kern {\n\tstruct sock *sk;\n\tunion {\n\t\tu32 args[4];\n\t\tu32 reply;\n\t\tu32 replylong[4];\n\t};\n\tstruct sk_buff *syn_skb;\n\tstruct sk_buff *skb;\n\tvoid *skb_data_end;\n\tu8 op;\n\tu8 is_fullsock;\n\tu8 remaining_opt_len;\n\tu64 temp;\n};\n\nstruct bpf_sysctl_kern {\n\tstruct ctl_table_header *head;\n\tstruct ctl_table *table;\n\tvoid *cur_val;\n\tsize_t cur_len;\n\tvoid *new_val;\n\tsize_t new_len;\n\tint new_updated;\n\tint write;\n\tloff_t *ppos;\n\tu64 tmp_reg;\n};\n\nstruct bpf_sockopt_kern {\n\tstruct sock *sk;\n\tu8 *optval;\n\tu8 *optval_end;\n\ts32 level;\n\ts32 optname;\n\ts32 optlen;\n\ts32 retval;\n};\n\nstruct bpf_sk_lookup_kern {\n\tu16 family;\n\tu16 protocol;\n\t__be16 sport;\n\tu16 dport;\n\tstruct {\n\t\t__be32 saddr;\n\t\t__be32 daddr;\n\t} v4;\n\tstruct {\n\t\tconst struct in6_addr *saddr;\n\t\tconst struct in6_addr *daddr;\n\t} v6;\n\tstruct sock *selected_sk;\n\tbool no_reuseport;\n};\n\nstruct lwtunnel_state {\n\t__u16 type;\n\t__u16 flags;\n\t__u16 headroom;\n\tatomic_t refcnt;\n\tint (*orig_output)(struct net *, struct sock *, struct sk_buff *);\n\tint (*orig_input)(struct sk_buff *);\n\tstruct callback_head rcu;\n\t__u8 data[0];\n};\n\nstruct sock_reuseport {\n\tstruct callback_head rcu;\n\tu16 max_socks;\n\tu16 num_socks;\n\tu16 num_closed_socks;\n\tunsigned int synq_overflow_ts;\n\tunsigned int reuseport_id;\n\tunsigned int bind_inany: 1;\n\tunsigned int has_conns: 1;\n\tstruct bpf_prog *prog;\n\tstruct sock *socks[0];\n};\n\nstruct sk_psock_progs {\n\tstruct bpf_prog *msg_parser;\n\tstruct bpf_prog *stream_parser;\n\tstruct bpf_prog *stream_verdict;\n\tstruct bpf_prog *skb_verdict;\n};\n\nstruct strp_stats {\n\tlong long unsigned int msgs;\n\tlong long unsigned int bytes;\n\tunsigned int mem_fail;\n\tunsigned int need_more_hdr;\n\tunsigned int msg_too_big;\n\tunsigned int msg_timeouts;\n\tunsigned int bad_hdr_len;\n};\n\nstruct strparser;\n\nstruct strp_callbacks {\n\tint (*parse_msg)(struct strparser *, struct sk_buff *);\n\tvoid (*rcv_msg)(struct strparser *, struct sk_buff *);\n\tint (*read_sock_done)(struct strparser *, int);\n\tvoid (*abort_parser)(struct strparser *, int);\n\tvoid (*lock)(struct strparser *);\n\tvoid (*unlock)(struct strparser *);\n};\n\nstruct strparser {\n\tstruct sock *sk;\n\tu32 stopped: 1;\n\tu32 paused: 1;\n\tu32 aborted: 1;\n\tu32 interrupted: 1;\n\tu32 unrecov_intr: 1;\n\tstruct sk_buff **skb_nextp;\n\tstruct sk_buff *skb_head;\n\tunsigned int need_bytes;\n\tstruct delayed_work msg_timer_work;\n\tstruct work_struct work;\n\tstruct strp_stats stats;\n\tstruct strp_callbacks cb;\n};\n\nstruct sk_psock_work_state {\n\tstruct sk_buff *skb;\n\tu32 len;\n\tu32 off;\n};\n\nstruct sk_msg;\n\nstruct sk_psock {\n\tstruct sock *sk;\n\tstruct sock *sk_redir;\n\tu32 apply_bytes;\n\tu32 cork_bytes;\n\tu32 eval;\n\tstruct sk_msg *cork;\n\tstruct sk_psock_progs progs;\n\tstruct strparser strp;\n\tstruct sk_buff_head ingress_skb;\n\tstruct list_head ingress_msg;\n\tspinlock_t ingress_lock;\n\tlong unsigned int state;\n\tstruct list_head link;\n\tspinlock_t link_lock;\n\trefcount_t refcnt;\n\tvoid (*saved_unhash)(struct sock *);\n\tvoid (*saved_close)(struct sock *, long int);\n\tvoid (*saved_write_space)(struct sock *);\n\tvoid (*saved_data_ready)(struct sock *);\n\tint (*psock_update_sk_prot)(struct sock *, struct sk_psock *, bool);\n\tstruct proto *sk_proto;\n\tstruct mutex work_mutex;\n\tstruct sk_psock_work_state work_state;\n\tstruct work_struct work;\n\tstruct rcu_work rwork;\n};\n\nstruct inet_ehash_bucket {\n\tstruct hlist_nulls_head chain;\n};\n\nstruct inet_bind_hashbucket {\n\tspinlock_t lock;\n\tstruct hlist_head chain;\n};\n\nstruct ack_sample {\n\tu32 pkts_acked;\n\ts32 rtt_us;\n\tu32 in_flight;\n};\n\nstruct rate_sample {\n\tu64 prior_mstamp;\n\tu32 prior_delivered;\n\ts32 delivered;\n\tlong int interval_us;\n\tu32 snd_interval_us;\n\tu32 rcv_interval_us;\n\tlong int rtt_us;\n\tint losses;\n\tu32 acked_sacked;\n\tu32 prior_in_flight;\n\tbool is_app_limited;\n\tbool is_retrans;\n\tbool is_ack_delayed;\n};\n\nstruct sk_msg_sg {\n\tu32 start;\n\tu32 curr;\n\tu32 end;\n\tu32 size;\n\tu32 copybreak;\n\tlong unsigned int copy;\n\tstruct scatterlist data[19];\n};\n\nstruct sk_msg {\n\tstruct sk_msg_sg sg;\n\tvoid *data;\n\tvoid *data_end;\n\tu32 apply_bytes;\n\tu32 cork_bytes;\n\tu32 flags;\n\tstruct sk_buff *skb;\n\tstruct sock *sk_redir;\n\tstruct sock *sk;\n\tstruct list_head list;\n};\n\nenum verifier_phase {\n\tCHECK_META = 0,\n\tCHECK_TYPE = 1,\n};\n\nstruct resolve_vertex {\n\tconst struct btf_type *t;\n\tu32 type_id;\n\tu16 next_member;\n};\n\nenum visit_state {\n\tNOT_VISITED = 0,\n\tVISITED = 1,\n\tRESOLVED = 2,\n};\n\nenum resolve_mode {\n\tRESOLVE_TBD = 0,\n\tRESOLVE_PTR = 1,\n\tRESOLVE_STRUCT_OR_ARRAY = 2,\n};\n\nstruct btf_sec_info {\n\tu32 off;\n\tu32 len;\n};\n\nstruct btf_verifier_env {\n\tstruct btf *btf;\n\tu8 *visit_states;\n\tstruct resolve_vertex stack[32];\n\tstruct bpf_verifier_log log;\n\tu32 log_type_id;\n\tu32 top_stack;\n\tenum verifier_phase phase;\n\tenum resolve_mode resolve_mode;\n};\n\nstruct btf_show {\n\tu64 flags;\n\tvoid *target;\n\tvoid (*showfn)(struct btf_show *, const char *, struct __va_list_tag *);\n\tconst struct btf *btf;\n\tstruct {\n\t\tu8 depth;\n\t\tu8 depth_to_show;\n\t\tu8 depth_check;\n\t\tu8 array_member: 1;\n\t\tu8 array_terminated: 1;\n\t\tu16 array_encoding;\n\t\tu32 type_id;\n\t\tint status;\n\t\tconst struct btf_type *type;\n\t\tconst struct btf_member *member;\n\t\tchar name[80];\n\t} state;\n\tstruct {\n\t\tu32 size;\n\t\tvoid *head;\n\t\tvoid *data;\n\t\tu8 safe[32];\n\t} obj;\n};\n\nstruct btf_kind_operations {\n\ts32 (*check_meta)(struct btf_verifier_env *, const struct btf_type *, u32);\n\tint (*resolve)(struct btf_verifier_env *, const struct resolve_vertex *);\n\tint (*check_member)(struct btf_verifier_env *, const struct btf_type *, const struct btf_member *, const struct btf_type *);\n\tint (*check_kflag_member)(struct btf_verifier_env *, const struct btf_type *, const struct btf_member *, const struct btf_type *);\n\tvoid (*log_details)(struct btf_verifier_env *, const struct btf_type *);\n\tvoid (*show)(const struct btf *, const struct btf_type *, u32, void *, u8, struct btf_show *);\n};\n\nstruct bpf_ctx_convert {\n\tstruct __sk_buff BPF_PROG_TYPE_SOCKET_FILTER_prog;\n\tstruct sk_buff BPF_PROG_TYPE_SOCKET_FILTER_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_SCHED_CLS_prog;\n\tstruct sk_buff BPF_PROG_TYPE_SCHED_CLS_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_SCHED_ACT_prog;\n\tstruct sk_buff BPF_PROG_TYPE_SCHED_ACT_kern;\n\tstruct xdp_md BPF_PROG_TYPE_XDP_prog;\n\tstruct xdp_buff BPF_PROG_TYPE_XDP_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_CGROUP_SKB_prog;\n\tstruct sk_buff BPF_PROG_TYPE_CGROUP_SKB_kern;\n\tstruct bpf_sock BPF_PROG_TYPE_CGROUP_SOCK_prog;\n\tstruct sock BPF_PROG_TYPE_CGROUP_SOCK_kern;\n\tstruct bpf_sock_addr BPF_PROG_TYPE_CGROUP_SOCK_ADDR_prog;\n\tstruct bpf_sock_addr_kern BPF_PROG_TYPE_CGROUP_SOCK_ADDR_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_LWT_IN_prog;\n\tstruct sk_buff BPF_PROG_TYPE_LWT_IN_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_LWT_OUT_prog;\n\tstruct sk_buff BPF_PROG_TYPE_LWT_OUT_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_LWT_XMIT_prog;\n\tstruct sk_buff BPF_PROG_TYPE_LWT_XMIT_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_LWT_SEG6LOCAL_prog;\n\tstruct sk_buff BPF_PROG_TYPE_LWT_SEG6LOCAL_kern;\n\tstruct bpf_sock_ops BPF_PROG_TYPE_SOCK_OPS_prog;\n\tstruct bpf_sock_ops_kern BPF_PROG_TYPE_SOCK_OPS_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_SK_SKB_prog;\n\tstruct sk_buff BPF_PROG_TYPE_SK_SKB_kern;\n\tstruct sk_msg_md BPF_PROG_TYPE_SK_MSG_prog;\n\tstruct sk_msg BPF_PROG_TYPE_SK_MSG_kern;\n\tstruct __sk_buff BPF_PROG_TYPE_FLOW_DISSECTOR_prog;\n\tstruct bpf_flow_dissector BPF_PROG_TYPE_FLOW_DISSECTOR_kern;\n\tbpf_user_pt_regs_t BPF_PROG_TYPE_KPROBE_prog;\n\tstruct pt_regs BPF_PROG_TYPE_KPROBE_kern;\n\t__u64 BPF_PROG_TYPE_TRACEPOINT_prog;\n\tu64 BPF_PROG_TYPE_TRACEPOINT_kern;\n\tstruct bpf_perf_event_data BPF_PROG_TYPE_PERF_EVENT_prog;\n\tstruct bpf_perf_event_data_kern BPF_PROG_TYPE_PERF_EVENT_kern;\n\tstruct bpf_raw_tracepoint_args BPF_PROG_TYPE_RAW_TRACEPOINT_prog;\n\tu64 BPF_PROG_TYPE_RAW_TRACEPOINT_kern;\n\tstruct bpf_raw_tracepoint_args BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE_prog;\n\tu64 BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE_kern;\n\tvoid *BPF_PROG_TYPE_TRACING_prog;\n\tvoid *BPF_PROG_TYPE_TRACING_kern;\n\tstruct bpf_cgroup_dev_ctx BPF_PROG_TYPE_CGROUP_DEVICE_prog;\n\tstruct bpf_cgroup_dev_ctx BPF_PROG_TYPE_CGROUP_DEVICE_kern;\n\tstruct bpf_sysctl BPF_PROG_TYPE_CGROUP_SYSCTL_prog;\n\tstruct bpf_sysctl_kern BPF_PROG_TYPE_CGROUP_SYSCTL_kern;\n\tstruct bpf_sockopt BPF_PROG_TYPE_CGROUP_SOCKOPT_prog;\n\tstruct bpf_sockopt_kern BPF_PROG_TYPE_CGROUP_SOCKOPT_kern;\n\t__u32 BPF_PROG_TYPE_LIRC_MODE2_prog;\n\tu32 BPF_PROG_TYPE_LIRC_MODE2_kern;\n\tstruct sk_reuseport_md BPF_PROG_TYPE_SK_REUSEPORT_prog;\n\tstruct sk_reuseport_kern BPF_PROG_TYPE_SK_REUSEPORT_kern;\n\tstruct bpf_sk_lookup BPF_PROG_TYPE_SK_LOOKUP_prog;\n\tstruct bpf_sk_lookup_kern BPF_PROG_TYPE_SK_LOOKUP_kern;\n\tvoid *BPF_PROG_TYPE_STRUCT_OPS_prog;\n\tvoid *BPF_PROG_TYPE_STRUCT_OPS_kern;\n\tvoid *BPF_PROG_TYPE_EXT_prog;\n\tvoid *BPF_PROG_TYPE_EXT_kern;\n\tvoid *BPF_PROG_TYPE_LSM_prog;\n\tvoid *BPF_PROG_TYPE_LSM_kern;\n\tvoid *BPF_PROG_TYPE_SYSCALL_prog;\n\tvoid *BPF_PROG_TYPE_SYSCALL_kern;\n};\n\nenum {\n\t__ctx_convertBPF_PROG_TYPE_SOCKET_FILTER = 0,\n\t__ctx_convertBPF_PROG_TYPE_SCHED_CLS = 1,\n\t__ctx_convertBPF_PROG_TYPE_SCHED_ACT = 2,\n\t__ctx_convertBPF_PROG_TYPE_XDP = 3,\n\t__ctx_convertBPF_PROG_TYPE_CGROUP_SKB = 4,\n\t__ctx_convertBPF_PROG_TYPE_CGROUP_SOCK = 5,\n\t__ctx_convertBPF_PROG_TYPE_CGROUP_SOCK_ADDR = 6,\n\t__ctx_convertBPF_PROG_TYPE_LWT_IN = 7,\n\t__ctx_convertBPF_PROG_TYPE_LWT_OUT = 8,\n\t__ctx_convertBPF_PROG_TYPE_LWT_XMIT = 9,\n\t__ctx_convertBPF_PROG_TYPE_LWT_SEG6LOCAL = 10,\n\t__ctx_convertBPF_PROG_TYPE_SOCK_OPS = 11,\n\t__ctx_convertBPF_PROG_TYPE_SK_SKB = 12,\n\t__ctx_convertBPF_PROG_TYPE_SK_MSG = 13,\n\t__ctx_convertBPF_PROG_TYPE_FLOW_DISSECTOR = 14,\n\t__ctx_convertBPF_PROG_TYPE_KPROBE = 15,\n\t__ctx_convertBPF_PROG_TYPE_TRACEPOINT = 16,\n\t__ctx_convertBPF_PROG_TYPE_PERF_EVENT = 17,\n\t__ctx_convertBPF_PROG_TYPE_RAW_TRACEPOINT = 18,\n\t__ctx_convertBPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 19,\n\t__ctx_convertBPF_PROG_TYPE_TRACING = 20,\n\t__ctx_convertBPF_PROG_TYPE_CGROUP_DEVICE = 21,\n\t__ctx_convertBPF_PROG_TYPE_CGROUP_SYSCTL = 22,\n\t__ctx_convertBPF_PROG_TYPE_CGROUP_SOCKOPT = 23,\n\t__ctx_convertBPF_PROG_TYPE_LIRC_MODE2 = 24,\n\t__ctx_convertBPF_PROG_TYPE_SK_REUSEPORT = 25,\n\t__ctx_convertBPF_PROG_TYPE_SK_LOOKUP = 26,\n\t__ctx_convertBPF_PROG_TYPE_STRUCT_OPS = 27,\n\t__ctx_convertBPF_PROG_TYPE_EXT = 28,\n\t__ctx_convertBPF_PROG_TYPE_LSM = 29,\n\t__ctx_convertBPF_PROG_TYPE_SYSCALL = 30,\n\t__ctx_convert_unused = 31,\n};\n\nenum bpf_struct_walk_result {\n\tWALK_SCALAR = 0,\n\tWALK_PTR = 1,\n\tWALK_STRUCT = 2,\n};\n\nstruct btf_show_snprintf {\n\tstruct btf_show show;\n\tint len_left;\n\tint len;\n};\n\nstruct btf_module {\n\tstruct list_head list;\n\tstruct module *module;\n\tstruct btf *btf;\n\tstruct bin_attribute *sysfs_attr;\n};\n\ntypedef u64 (*btf_bpf_btf_find_by_name_kind)(char *, int, u32, int);\n\nstruct bpf_dispatcher_prog {\n\tstruct bpf_prog *prog;\n\trefcount_t users;\n};\n\nstruct bpf_dispatcher {\n\tstruct mutex mutex;\n\tvoid *func;\n\tstruct bpf_dispatcher_prog progs[48];\n\tint num_progs;\n\tvoid *image;\n\tu32 image_off;\n\tstruct bpf_ksym ksym;\n};\n\nenum {\n\tBPF_F_BROADCAST = 8,\n\tBPF_F_EXCLUDE_INGRESS = 16,\n};\n\nstruct bpf_devmap_val {\n\t__u32 ifindex;\n\tunion {\n\t\tint fd;\n\t\t__u32 id;\n\t} bpf_prog;\n};\n\nenum net_device_flags {\n\tIFF_UP = 1,\n\tIFF_BROADCAST = 2,\n\tIFF_DEBUG = 4,\n\tIFF_LOOPBACK = 8,\n\tIFF_POINTOPOINT = 16,\n\tIFF_NOTRAILERS = 32,\n\tIFF_RUNNING = 64,\n\tIFF_NOARP = 128,\n\tIFF_PROMISC = 256,\n\tIFF_ALLMULTI = 512,\n\tIFF_MASTER = 1024,\n\tIFF_SLAVE = 2048,\n\tIFF_MULTICAST = 4096,\n\tIFF_PORTSEL = 8192,\n\tIFF_AUTOMEDIA = 16384,\n\tIFF_DYNAMIC = 32768,\n\tIFF_LOWER_UP = 65536,\n\tIFF_DORMANT = 131072,\n\tIFF_ECHO = 262144,\n};\n\nstruct xdp_dev_bulk_queue {\n\tstruct xdp_frame *q[16];\n\tstruct list_head flush_node;\n\tstruct net_device *dev;\n\tstruct net_device *dev_rx;\n\tstruct bpf_prog *xdp_prog;\n\tunsigned int count;\n};\n\nenum netdev_cmd {\n\tNETDEV_UP = 1,\n\tNETDEV_DOWN = 2,\n\tNETDEV_REBOOT = 3,\n\tNETDEV_CHANGE = 4,\n\tNETDEV_REGISTER = 5,\n\tNETDEV_UNREGISTER = 6,\n\tNETDEV_CHANGEMTU = 7,\n\tNETDEV_CHANGEADDR = 8,\n\tNETDEV_PRE_CHANGEADDR = 9,\n\tNETDEV_GOING_DOWN = 10,\n\tNETDEV_CHANGENAME = 11,\n\tNETDEV_FEAT_CHANGE = 12,\n\tNETDEV_BONDING_FAILOVER = 13,\n\tNETDEV_PRE_UP = 14,\n\tNETDEV_PRE_TYPE_CHANGE = 15,\n\tNETDEV_POST_TYPE_CHANGE = 16,\n\tNETDEV_POST_INIT = 17,\n\tNETDEV_RELEASE = 18,\n\tNETDEV_NOTIFY_PEERS = 19,\n\tNETDEV_JOIN = 20,\n\tNETDEV_CHANGEUPPER = 21,\n\tNETDEV_RESEND_IGMP = 22,\n\tNETDEV_PRECHANGEMTU = 23,\n\tNETDEV_CHANGEINFODATA = 24,\n\tNETDEV_BONDING_INFO = 25,\n\tNETDEV_PRECHANGEUPPER = 26,\n\tNETDEV_CHANGELOWERSTATE = 27,\n\tNETDEV_UDP_TUNNEL_PUSH_INFO = 28,\n\tNETDEV_UDP_TUNNEL_DROP_INFO = 29,\n\tNETDEV_CHANGE_TX_QUEUE_LEN = 30,\n\tNETDEV_CVLAN_FILTER_PUSH_INFO = 31,\n\tNETDEV_CVLAN_FILTER_DROP_INFO = 32,\n\tNETDEV_SVLAN_FILTER_PUSH_INFO = 33,\n\tNETDEV_SVLAN_FILTER_DROP_INFO = 34,\n};\n\nstruct netdev_notifier_info {\n\tstruct net_device *dev;\n\tstruct netlink_ext_ack *extack;\n};\n\nstruct bpf_nh_params {\n\tu32 nh_family;\n\tunion {\n\t\tu32 ipv4_nh;\n\t\tstruct in6_addr ipv6_nh;\n\t};\n};\n\nstruct bpf_redirect_info {\n\tu32 flags;\n\tu32 tgt_index;\n\tvoid *tgt_value;\n\tstruct bpf_map *map;\n\tu32 map_id;\n\tenum bpf_map_type map_type;\n\tu32 kern_flags;\n\tstruct bpf_nh_params nh;\n};\n\nstruct bpf_dtab;\n\nstruct bpf_dtab_netdev {\n\tstruct net_device *dev;\n\tstruct hlist_node index_hlist;\n\tstruct bpf_dtab *dtab;\n\tstruct bpf_prog *xdp_prog;\n\tstruct callback_head rcu;\n\tunsigned int idx;\n\tstruct bpf_devmap_val val;\n};\n\nstruct bpf_dtab {\n\tstruct bpf_map map;\n\tstruct bpf_dtab_netdev **netdev_map;\n\tstruct list_head list;\n\tstruct hlist_head *dev_index_head;\n\tspinlock_t index_lock;\n\tunsigned int items;\n\tu32 n_buckets;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct bpf_cpumap_val {\n\t__u32 qsize;\n\tunion {\n\t\tint fd;\n\t\t__u32 id;\n\t} bpf_prog;\n};\n\nstruct bpf_cpu_map_entry;\n\nstruct xdp_bulk_queue {\n\tvoid *q[8];\n\tstruct list_head flush_node;\n\tstruct bpf_cpu_map_entry *obj;\n\tunsigned int count;\n};\n\nstruct bpf_cpu_map;\n\nstruct bpf_cpu_map_entry {\n\tu32 cpu;\n\tint map_id;\n\tstruct xdp_bulk_queue *bulkq;\n\tstruct bpf_cpu_map *cmap;\n\tstruct ptr_ring *queue;\n\tstruct task_struct *kthread;\n\tstruct bpf_cpumap_val value;\n\tstruct bpf_prog *prog;\n\tatomic_t refcnt;\n\tstruct callback_head rcu;\n\tstruct work_struct kthread_stop_wq;\n};\n\nstruct bpf_cpu_map {\n\tstruct bpf_map map;\n\tstruct bpf_cpu_map_entry **cpu_map;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct rhlist_head {\n\tstruct rhash_head rhead;\n\tstruct rhlist_head *next;\n};\n\nstruct bpf_prog_offload_ops {\n\tint (*insn_hook)(struct bpf_verifier_env *, int, int);\n\tint (*finalize)(struct bpf_verifier_env *);\n\tint (*replace_insn)(struct bpf_verifier_env *, u32, struct bpf_insn *);\n\tint (*remove_insns)(struct bpf_verifier_env *, u32, u32);\n\tint (*prepare)(struct bpf_prog *);\n\tint (*translate)(struct bpf_prog *);\n\tvoid (*destroy)(struct bpf_prog *);\n};\n\nstruct bpf_offload_dev {\n\tconst struct bpf_prog_offload_ops *ops;\n\tstruct list_head netdevs;\n\tvoid *priv;\n};\n\ntypedef struct ns_common *ns_get_path_helper_t(void *);\n\nstruct bpf_offload_netdev {\n\tstruct rhash_head l;\n\tstruct net_device *netdev;\n\tstruct bpf_offload_dev *offdev;\n\tstruct list_head progs;\n\tstruct list_head maps;\n\tstruct list_head offdev_netdevs;\n};\n\nstruct ns_get_path_bpf_prog_args {\n\tstruct bpf_prog *prog;\n\tstruct bpf_prog_info *info;\n};\n\nstruct ns_get_path_bpf_map_args {\n\tstruct bpf_offloaded_map *offmap;\n\tstruct bpf_map_info *info;\n};\n\nstruct bpf_netns_link {\n\tstruct bpf_link link;\n\tenum bpf_attach_type type;\n\tenum netns_bpf_attach_type netns_type;\n\tstruct net *net;\n\tstruct list_head node;\n};\n\nenum bpf_stack_build_id_status {\n\tBPF_STACK_BUILD_ID_EMPTY = 0,\n\tBPF_STACK_BUILD_ID_VALID = 1,\n\tBPF_STACK_BUILD_ID_IP = 2,\n};\n\nstruct bpf_stack_build_id {\n\t__s32 status;\n\tunsigned char build_id[20];\n\tunion {\n\t\t__u64 offset;\n\t\t__u64 ip;\n\t};\n};\n\nenum {\n\tBPF_F_SKIP_FIELD_MASK = 255,\n\tBPF_F_USER_STACK = 256,\n\tBPF_F_FAST_STACK_CMP = 512,\n\tBPF_F_REUSE_STACKID = 1024,\n\tBPF_F_USER_BUILD_ID = 2048,\n};\n\nenum perf_callchain_context {\n\tPERF_CONTEXT_HV = 4294967264,\n\tPERF_CONTEXT_KERNEL = 4294967168,\n\tPERF_CONTEXT_USER = 4294966784,\n\tPERF_CONTEXT_GUEST = 4294965248,\n\tPERF_CONTEXT_GUEST_KERNEL = 4294965120,\n\tPERF_CONTEXT_GUEST_USER = 4294964736,\n\tPERF_CONTEXT_MAX = 4294963201,\n};\n\nstruct stack_map_bucket {\n\tstruct pcpu_freelist_node fnode;\n\tu32 hash;\n\tu32 nr;\n\tu64 data[0];\n};\n\nstruct bpf_stack_map {\n\tstruct bpf_map map;\n\tvoid *elems;\n\tstruct pcpu_freelist freelist;\n\tu32 n_buckets;\n\tstruct stack_map_bucket *buckets[0];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct stack_map_irq_work {\n\tstruct irq_work irq_work;\n\tstruct mm_struct *mm;\n};\n\ntypedef u64 (*btf_bpf_get_stackid)(struct pt_regs *, struct bpf_map *, u64);\n\ntypedef u64 (*btf_bpf_get_stackid_pe)(struct bpf_perf_event_data_kern *, struct bpf_map *, u64);\n\ntypedef u64 (*btf_bpf_get_stack)(struct pt_regs *, void *, u32, u64);\n\ntypedef u64 (*btf_bpf_get_task_stack)(struct task_struct *, void *, u32, u64);\n\ntypedef u64 (*btf_bpf_get_stack_pe)(struct bpf_perf_event_data_kern *, void *, u32, u64);\n\nenum {\n\tBPF_F_SYSCTL_BASE_NAME = 1,\n};\n\nstruct bpf_prog_list {\n\tstruct list_head node;\n\tstruct bpf_prog *prog;\n\tstruct bpf_cgroup_link *link;\n\tstruct bpf_cgroup_storage *storage[2];\n};\n\nstruct qdisc_skb_cb {\n\tstruct {\n\t\tunsigned int pkt_len;\n\t\tu16 slave_dev_queue_mapping;\n\t\tu16 tc_classid;\n\t};\n\tunsigned char data[20];\n\tu16 mru;\n\tbool post_ct;\n};\n\nstruct bpf_skb_data_end {\n\tstruct qdisc_skb_cb qdisc_cb;\n\tvoid *data_meta;\n\tvoid *data_end;\n};\n\nstruct bpf_sockopt_buf {\n\tu8 data[32];\n};\n\nenum {\n\tTCPF_ESTABLISHED = 2,\n\tTCPF_SYN_SENT = 4,\n\tTCPF_SYN_RECV = 8,\n\tTCPF_FIN_WAIT1 = 16,\n\tTCPF_FIN_WAIT2 = 32,\n\tTCPF_TIME_WAIT = 64,\n\tTCPF_CLOSE = 128,\n\tTCPF_CLOSE_WAIT = 256,\n\tTCPF_LAST_ACK = 512,\n\tTCPF_LISTEN = 1024,\n\tTCPF_CLOSING = 2048,\n\tTCPF_NEW_SYN_RECV = 4096,\n};\n\ntypedef u64 (*btf_bpf_sysctl_get_name)(struct bpf_sysctl_kern *, char *, size_t, u64);\n\ntypedef u64 (*btf_bpf_sysctl_get_current_value)(struct bpf_sysctl_kern *, char *, size_t);\n\ntypedef u64 (*btf_bpf_sysctl_get_new_value)(struct bpf_sysctl_kern *, char *, size_t);\n\ntypedef u64 (*btf_bpf_sysctl_set_new_value)(struct bpf_sysctl_kern *, const char *, size_t);\n\nenum sock_type {\n\tSOCK_STREAM = 1,\n\tSOCK_DGRAM = 2,\n\tSOCK_RAW = 3,\n\tSOCK_RDM = 4,\n\tSOCK_SEQPACKET = 5,\n\tSOCK_DCCP = 6,\n\tSOCK_PACKET = 10,\n};\n\nenum {\n\tIPPROTO_IP = 0,\n\tIPPROTO_ICMP = 1,\n\tIPPROTO_IGMP = 2,\n\tIPPROTO_IPIP = 4,\n\tIPPROTO_TCP = 6,\n\tIPPROTO_EGP = 8,\n\tIPPROTO_PUP = 12,\n\tIPPROTO_UDP = 17,\n\tIPPROTO_IDP = 22,\n\tIPPROTO_TP = 29,\n\tIPPROTO_DCCP = 33,\n\tIPPROTO_IPV6 = 41,\n\tIPPROTO_RSVP = 46,\n\tIPPROTO_GRE = 47,\n\tIPPROTO_ESP = 50,\n\tIPPROTO_AH = 51,\n\tIPPROTO_MTP = 92,\n\tIPPROTO_BEETPH = 94,\n\tIPPROTO_ENCAP = 98,\n\tIPPROTO_PIM = 103,\n\tIPPROTO_COMP = 108,\n\tIPPROTO_SCTP = 132,\n\tIPPROTO_UDPLITE = 136,\n\tIPPROTO_MPLS = 137,\n\tIPPROTO_ETHERNET = 143,\n\tIPPROTO_RAW = 255,\n\tIPPROTO_MPTCP = 262,\n\tIPPROTO_MAX = 263,\n};\n\nenum sock_flags {\n\tSOCK_DEAD = 0,\n\tSOCK_DONE = 1,\n\tSOCK_URGINLINE = 2,\n\tSOCK_KEEPOPEN = 3,\n\tSOCK_LINGER = 4,\n\tSOCK_DESTROY = 5,\n\tSOCK_BROADCAST = 6,\n\tSOCK_TIMESTAMP = 7,\n\tSOCK_ZAPPED = 8,\n\tSOCK_USE_WRITE_QUEUE = 9,\n\tSOCK_DBG = 10,\n\tSOCK_RCVTSTAMP = 11,\n\tSOCK_RCVTSTAMPNS = 12,\n\tSOCK_LOCALROUTE = 13,\n\tSOCK_MEMALLOC = 14,\n\tSOCK_TIMESTAMPING_RX_SOFTWARE = 15,\n\tSOCK_FASYNC = 16,\n\tSOCK_RXQ_OVFL = 17,\n\tSOCK_ZEROCOPY = 18,\n\tSOCK_WIFI_STATUS = 19,\n\tSOCK_NOFCS = 20,\n\tSOCK_FILTER_LOCKED = 21,\n\tSOCK_SELECT_ERR_QUEUE = 22,\n\tSOCK_RCU_FREE = 23,\n\tSOCK_TXTIME = 24,\n\tSOCK_XDP = 25,\n\tSOCK_TSTAMP_NEW = 26,\n};\n\nstruct reuseport_array {\n\tstruct bpf_map map;\n\tstruct sock *ptrs[0];\n};\n\nenum bpf_struct_ops_state {\n\tBPF_STRUCT_OPS_STATE_INIT = 0,\n\tBPF_STRUCT_OPS_STATE_INUSE = 1,\n\tBPF_STRUCT_OPS_STATE_TOBEFREE = 2,\n};\n\nstruct bpf_struct_ops_value {\n\trefcount_t refcnt;\n\tenum bpf_struct_ops_state state;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tchar data[0];\n};\n\nstruct bpf_struct_ops_map {\n\tstruct bpf_map map;\n\tconst struct bpf_struct_ops *st_ops;\n\tstruct mutex lock;\n\tstruct bpf_prog **progs;\n\tvoid *image;\n\tstruct bpf_struct_ops_value *uvalue;\n\tstruct bpf_struct_ops_value kvalue;\n};\n\nstruct bpf_struct_ops_tcp_congestion_ops {\n\trefcount_t refcnt;\n\tenum bpf_struct_ops_state state;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct tcp_congestion_ops data;\n};\n\nstruct sembuf {\n\tshort unsigned int sem_num;\n\tshort int sem_op;\n\tshort int sem_flg;\n};\n\nenum key_need_perm {\n\tKEY_NEED_UNSPECIFIED = 0,\n\tKEY_NEED_VIEW = 1,\n\tKEY_NEED_READ = 2,\n\tKEY_NEED_WRITE = 3,\n\tKEY_NEED_SEARCH = 4,\n\tKEY_NEED_LINK = 5,\n\tKEY_NEED_SETATTR = 6,\n\tKEY_NEED_UNLINK = 7,\n\tKEY_SYSADMIN_OVERRIDE = 8,\n\tKEY_AUTHTOKEN_OVERRIDE = 9,\n\tKEY_DEFER_PERM_CHECK = 10,\n};\n\nstruct __key_reference_with_attributes;\n\ntypedef struct __key_reference_with_attributes *key_ref_t;\n\nstruct xfrm_sec_ctx {\n\t__u8 ctx_doi;\n\t__u8 ctx_alg;\n\t__u16 ctx_len;\n\t__u32 ctx_sid;\n\tchar ctx_str[0];\n};\n\nstruct xfrm_user_sec_ctx {\n\t__u16 len;\n\t__u16 exttype;\n\t__u8 ctx_alg;\n\t__u8 ctx_doi;\n\t__u16 ctx_len;\n};\n\nenum {\n\tBPF_F_BPRM_SECUREEXEC = 1,\n};\n\ntypedef u64 (*btf_bpf_bprm_opts_set)(struct linux_binprm *, u64);\n\ntypedef u64 (*btf_bpf_ima_inode_hash)(struct inode *, void *, u32);\n\nstruct static_call_tramp_key {\n\ts32 tramp;\n\ts32 key;\n};\n\nenum perf_event_read_format {\n\tPERF_FORMAT_TOTAL_TIME_ENABLED = 1,\n\tPERF_FORMAT_TOTAL_TIME_RUNNING = 2,\n\tPERF_FORMAT_ID = 4,\n\tPERF_FORMAT_GROUP = 8,\n\tPERF_FORMAT_MAX = 16,\n};\n\nenum perf_event_ioc_flags {\n\tPERF_IOC_FLAG_GROUP = 1,\n};\n\nstruct perf_ns_link_info {\n\t__u64 dev;\n\t__u64 ino;\n};\n\nenum {\n\tNET_NS_INDEX = 0,\n\tUTS_NS_INDEX = 1,\n\tIPC_NS_INDEX = 2,\n\tPID_NS_INDEX = 3,\n\tUSER_NS_INDEX = 4,\n\tMNT_NS_INDEX = 5,\n\tCGROUP_NS_INDEX = 6,\n\tNR_NAMESPACES = 7,\n};\n\nenum perf_event_type {\n\tPERF_RECORD_MMAP = 1,\n\tPERF_RECORD_LOST = 2,\n\tPERF_RECORD_COMM = 3,\n\tPERF_RECORD_EXIT = 4,\n\tPERF_RECORD_THROTTLE = 5,\n\tPERF_RECORD_UNTHROTTLE = 6,\n\tPERF_RECORD_FORK = 7,\n\tPERF_RECORD_READ = 8,\n\tPERF_RECORD_SAMPLE = 9,\n\tPERF_RECORD_MMAP2 = 10,\n\tPERF_RECORD_AUX = 11,\n\tPERF_RECORD_ITRACE_START = 12,\n\tPERF_RECORD_LOST_SAMPLES = 13,\n\tPERF_RECORD_SWITCH = 14,\n\tPERF_RECORD_SWITCH_CPU_WIDE = 15,\n\tPERF_RECORD_NAMESPACES = 16,\n\tPERF_RECORD_KSYMBOL = 17,\n\tPERF_RECORD_BPF_EVENT = 18,\n\tPERF_RECORD_CGROUP = 19,\n\tPERF_RECORD_TEXT_POKE = 20,\n\tPERF_RECORD_MAX = 21,\n};\n\nstruct swevent_hlist {\n\tstruct hlist_head heads[256];\n\tstruct callback_head callback_head;\n};\n\nstruct pmu_event_list {\n\traw_spinlock_t lock;\n\tstruct list_head list;\n};\n\nstruct perf_buffer {\n\trefcount_t refcount;\n\tstruct callback_head callback_head;\n\tint nr_pages;\n\tint overwrite;\n\tint paused;\n\tatomic_t poll;\n\tlocal_t head;\n\tunsigned int nest;\n\tlocal_t events;\n\tlocal_t wakeup;\n\tlocal_t lost;\n\tlong int watermark;\n\tlong int aux_watermark;\n\tspinlock_t event_lock;\n\tstruct list_head event_list;\n\tatomic_t mmap_count;\n\tlong unsigned int mmap_locked;\n\tstruct user_struct *mmap_user;\n\tlong int aux_head;\n\tunsigned int aux_nest;\n\tlong int aux_wakeup;\n\tlong unsigned int aux_pgoff;\n\tint aux_nr_pages;\n\tint aux_overwrite;\n\tatomic_t aux_mmap_count;\n\tlong unsigned int aux_mmap_locked;\n\tvoid (*free_aux)(void *);\n\trefcount_t aux_refcount;\n\tint aux_in_sampling;\n\tvoid **aux_pages;\n\tvoid *aux_priv;\n\tstruct perf_event_mmap_page *user_page;\n\tvoid *data_pages[0];\n};\n\nstruct match_token {\n\tint token;\n\tconst char *pattern;\n};\n\nenum {\n\tMAX_OPT_ARGS = 3,\n};\n\nstruct min_heap {\n\tvoid *data;\n\tint nr;\n\tint size;\n};\n\nstruct min_heap_callbacks {\n\tint elem_size;\n\tbool (*less)(const void *, const void *);\n\tvoid (*swp)(void *, void *);\n};\n\ntypedef int (*remote_function_f)(void *);\n\nstruct remote_function_call {\n\tstruct task_struct *p;\n\tremote_function_f func;\n\tvoid *info;\n\tint ret;\n};\n\ntypedef void (*event_f)(struct perf_event *, struct perf_cpu_context *, struct perf_event_context *, void *);\n\nstruct event_function_struct {\n\tstruct perf_event *event;\n\tevent_f func;\n\tvoid *data;\n};\n\nenum event_type_t {\n\tEVENT_FLEXIBLE = 1,\n\tEVENT_PINNED = 2,\n\tEVENT_TIME = 4,\n\tEVENT_CPU = 8,\n\tEVENT_ALL = 3,\n};\n\nstruct __group_key {\n\tint cpu;\n\tstruct cgroup *cgroup;\n};\n\nstruct stop_event_data {\n\tstruct perf_event *event;\n\tunsigned int restart;\n};\n\nstruct perf_read_data {\n\tstruct perf_event *event;\n\tbool group;\n\tint ret;\n};\n\nstruct perf_read_event {\n\tstruct perf_event_header header;\n\tu32 pid;\n\tu32 tid;\n};\n\ntypedef void perf_iterate_f(struct perf_event *, void *);\n\nstruct remote_output {\n\tstruct perf_buffer *rb;\n\tint err;\n};\n\nstruct perf_task_event {\n\tstruct task_struct *task;\n\tstruct perf_event_context *task_ctx;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu32 pid;\n\t\tu32 ppid;\n\t\tu32 tid;\n\t\tu32 ptid;\n\t\tu64 time;\n\t} event_id;\n};\n\nstruct perf_comm_event {\n\tstruct task_struct *task;\n\tchar *comm;\n\tint comm_size;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu32 pid;\n\t\tu32 tid;\n\t} event_id;\n};\n\nstruct perf_namespaces_event {\n\tstruct task_struct *task;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu32 pid;\n\t\tu32 tid;\n\t\tu64 nr_namespaces;\n\t\tstruct perf_ns_link_info link_info[7];\n\t} event_id;\n};\n\nstruct perf_cgroup_event {\n\tchar *path;\n\tint path_size;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu64 id;\n\t\tchar path[0];\n\t} event_id;\n};\n\nstruct perf_mmap_event {\n\tstruct vm_area_struct *vma;\n\tconst char *file_name;\n\tint file_size;\n\tint maj;\n\tint min;\n\tu64 ino;\n\tu64 ino_generation;\n\tu32 prot;\n\tu32 flags;\n\tu8 build_id[20];\n\tu32 build_id_size;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu32 pid;\n\t\tu32 tid;\n\t\tu64 start;\n\t\tu64 len;\n\t\tu64 pgoff;\n\t} event_id;\n};\n\nstruct perf_switch_event {\n\tstruct task_struct *task;\n\tstruct task_struct *next_prev;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu32 next_prev_pid;\n\t\tu32 next_prev_tid;\n\t} event_id;\n};\n\nstruct perf_ksymbol_event {\n\tconst char *name;\n\tint name_len;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu64 addr;\n\t\tu32 len;\n\t\tu16 ksym_type;\n\t\tu16 flags;\n\t} event_id;\n};\n\nstruct perf_bpf_event {\n\tstruct bpf_prog *prog;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu16 type;\n\t\tu16 flags;\n\t\tu32 id;\n\t\tu8 tag[8];\n\t} event_id;\n};\n\nstruct perf_text_poke_event {\n\tconst void *old_bytes;\n\tconst void *new_bytes;\n\tsize_t pad;\n\tu16 old_len;\n\tu16 new_len;\n\tstruct {\n\t\tstruct perf_event_header header;\n\t\tu64 addr;\n\t} event_id;\n};\n\nstruct swevent_htable {\n\tstruct swevent_hlist *swevent_hlist;\n\tstruct mutex hlist_mutex;\n\tint hlist_refcount;\n\tint recursion[4];\n};\n\nenum perf_probe_config {\n\tPERF_PROBE_CONFIG_IS_RETPROBE = 1,\n\tPERF_UPROBE_REF_CTR_OFFSET_BITS = 32,\n\tPERF_UPROBE_REF_CTR_OFFSET_SHIFT = 32,\n};\n\nenum {\n\tIF_ACT_NONE = 4294967295,\n\tIF_ACT_FILTER = 0,\n\tIF_ACT_START = 1,\n\tIF_ACT_STOP = 2,\n\tIF_SRC_FILE = 3,\n\tIF_SRC_KERNEL = 4,\n\tIF_SRC_FILEADDR = 5,\n\tIF_SRC_KERNELADDR = 6,\n};\n\nenum {\n\tIF_STATE_ACTION = 0,\n\tIF_STATE_SOURCE = 1,\n\tIF_STATE_END = 2,\n};\n\nstruct perf_aux_event {\n\tstruct perf_event_header header;\n\tu32 pid;\n\tu32 tid;\n};\n\nstruct perf_aux_event___2 {\n\tstruct perf_event_header header;\n\tu64 offset;\n\tu64 size;\n\tu64 flags;\n};\n\nstruct callchain_cpus_entries {\n\tstruct callback_head callback_head;\n\tstruct perf_callchain_entry *cpu_entries[0];\n};\n\nenum bp_type_idx {\n\tTYPE_INST = 0,\n\tTYPE_DATA = 0,\n\tTYPE_MAX = 1,\n};\n\nstruct bp_cpuinfo {\n\tunsigned int cpu_pinned;\n\tunsigned int *tsk_pinned;\n\tunsigned int flexible;\n};\n\nstruct bp_busy_slots {\n\tunsigned int pinned;\n\tunsigned int flexible;\n};\n\ntypedef u8 uprobe_opcode_t;\n\nstruct uprobe {\n\tstruct rb_node rb_node;\n\trefcount_t ref;\n\tstruct rw_semaphore register_rwsem;\n\tstruct rw_semaphore consumer_rwsem;\n\tstruct list_head pending_list;\n\tstruct uprobe_consumer *consumers;\n\tstruct inode *inode;\n\tloff_t offset;\n\tloff_t ref_ctr_offset;\n\tlong unsigned int flags;\n\tstruct arch_uprobe arch;\n};\n\nstruct xol_area {\n\twait_queue_head_t wq;\n\tatomic_t slot_count;\n\tlong unsigned int *bitmap;\n\tstruct vm_special_mapping xol_mapping;\n\tstruct page *pages[2];\n\tlong unsigned int vaddr;\n};\n\nstruct compact_control;\n\nstruct capture_control {\n\tstruct compact_control *cc;\n\tstruct page *page;\n};\n\ntypedef int filler_t(void *, struct page *);\n\nstruct page_vma_mapped_walk {\n\tstruct page *page;\n\tstruct vm_area_struct *vma;\n\tlong unsigned int address;\n\tpmd_t *pmd;\n\tpte_t *pte;\n\tspinlock_t *ptl;\n\tunsigned int flags;\n};\n\nstruct compact_control {\n\tstruct list_head freepages;\n\tstruct list_head migratepages;\n\tunsigned int nr_freepages;\n\tunsigned int nr_migratepages;\n\tlong unsigned int free_pfn;\n\tlong unsigned int migrate_pfn;\n\tlong unsigned int fast_start_pfn;\n\tstruct zone *zone;\n\tlong unsigned int total_migrate_scanned;\n\tlong unsigned int total_free_scanned;\n\tshort unsigned int fast_search_fail;\n\tshort int search_order;\n\tconst gfp_t gfp_mask;\n\tint order;\n\tint migratetype;\n\tconst unsigned int alloc_flags;\n\tconst int highest_zoneidx;\n\tenum migrate_mode mode;\n\tbool ignore_skip_hint;\n\tbool no_set_skip_hint;\n\tbool ignore_block_suitable;\n\tbool direct_compaction;\n\tbool proactive_compaction;\n\tbool whole_zone;\n\tbool contended;\n\tbool rescan;\n\tbool alloc_contig;\n};\n\nstruct delayed_uprobe {\n\tstruct list_head list;\n\tstruct uprobe *uprobe;\n\tstruct mm_struct *mm;\n};\n\nstruct __uprobe_key {\n\tstruct inode *inode;\n\tloff_t offset;\n};\n\nstruct map_info {\n\tstruct map_info *next;\n\tstruct mm_struct *mm;\n\tlong unsigned int vaddr;\n};\n\nstruct user_return_notifier {\n\tvoid (*on_user_return)(struct user_return_notifier *);\n\tstruct hlist_node link;\n};\n\nstruct parallel_data;\n\nstruct padata_priv {\n\tstruct list_head list;\n\tstruct parallel_data *pd;\n\tint cb_cpu;\n\tunsigned int seq_nr;\n\tint info;\n\tvoid (*parallel)(struct padata_priv *);\n\tvoid (*serial)(struct padata_priv *);\n};\n\nstruct padata_cpumask {\n\tcpumask_var_t pcpu;\n\tcpumask_var_t cbcpu;\n};\n\nstruct padata_shell;\n\nstruct padata_list;\n\nstruct padata_serial_queue;\n\nstruct parallel_data {\n\tstruct padata_shell *ps;\n\tstruct padata_list *reorder_list;\n\tstruct padata_serial_queue *squeue;\n\tatomic_t refcnt;\n\tunsigned int seq_nr;\n\tunsigned int processed;\n\tint cpu;\n\tstruct padata_cpumask cpumask;\n\tstruct work_struct reorder_work;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tspinlock_t lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct padata_list {\n\tstruct list_head list;\n\tspinlock_t lock;\n};\n\nstruct padata_serial_queue {\n\tstruct padata_list serial;\n\tstruct work_struct work;\n\tstruct parallel_data *pd;\n};\n\nstruct padata_instance;\n\nstruct padata_shell {\n\tstruct padata_instance *pinst;\n\tstruct parallel_data *pd;\n\tstruct parallel_data *opd;\n\tstruct list_head list;\n};\n\nstruct padata_instance {\n\tstruct hlist_node cpu_online_node;\n\tstruct hlist_node cpu_dead_node;\n\tstruct workqueue_struct *parallel_wq;\n\tstruct workqueue_struct *serial_wq;\n\tstruct list_head pslist;\n\tstruct padata_cpumask cpumask;\n\tstruct kobject kobj;\n\tstruct mutex lock;\n\tu8 flags;\n};\n\nstruct padata_mt_job {\n\tvoid (*thread_fn)(long unsigned int, long unsigned int, void *);\n\tvoid *fn_arg;\n\tlong unsigned int start;\n\tlong unsigned int size;\n\tlong unsigned int align;\n\tlong unsigned int min_chunk;\n\tint max_threads;\n};\n\nstruct padata_work {\n\tstruct work_struct pw_work;\n\tstruct list_head pw_list;\n\tvoid *pw_data;\n};\n\nstruct padata_mt_job_state {\n\tspinlock_t lock;\n\tstruct completion completion;\n\tstruct padata_mt_job *job;\n\tint nworks;\n\tint nworks_fini;\n\tlong unsigned int chunk_size;\n};\n\nstruct padata_sysfs_entry {\n\tstruct attribute attr;\n\tssize_t (*show)(struct padata_instance *, struct attribute *, char *);\n\tssize_t (*store)(struct padata_instance *, struct attribute *, const char *, size_t);\n};\n\nstruct static_key_mod {\n\tstruct static_key_mod *next;\n\tstruct jump_entry *entries;\n\tstruct module *mod;\n};\n\nstruct static_key_deferred {\n\tstruct static_key key;\n\tlong unsigned int timeout;\n\tstruct delayed_work work;\n};\n\nenum rseq_cpu_id_state {\n\tRSEQ_CPU_ID_UNINITIALIZED = 4294967295,\n\tRSEQ_CPU_ID_REGISTRATION_FAILED = 4294967294,\n};\n\nenum rseq_flags {\n\tRSEQ_FLAG_UNREGISTER = 1,\n};\n\nenum rseq_cs_flags {\n\tRSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = 1,\n\tRSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = 2,\n\tRSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = 4,\n};\n\nstruct rseq_cs {\n\t__u32 version;\n\t__u32 flags;\n\t__u64 start_ip;\n\t__u64 post_commit_offset;\n\t__u64 abort_ip;\n};\n\nstruct trace_event_raw_rseq_update {\n\tstruct trace_entry ent;\n\ts32 cpu_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rseq_ip_fixup {\n\tstruct trace_entry ent;\n\tlong unsigned int regs_ip;\n\tlong unsigned int start_ip;\n\tlong unsigned int post_commit_offset;\n\tlong unsigned int abort_ip;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_rseq_update {};\n\nstruct trace_event_data_offsets_rseq_ip_fixup {};\n\ntypedef void (*btf_trace_rseq_update)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_rseq_ip_fixup)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int);\n\nstruct watch;\n\nstruct watch_list {\n\tstruct callback_head rcu;\n\tstruct hlist_head watchers;\n\tvoid (*release_watch)(struct watch *);\n\tspinlock_t lock;\n};\n\nenum watch_notification_type {\n\tWATCH_TYPE_META = 0,\n\tWATCH_TYPE_KEY_NOTIFY = 1,\n\tWATCH_TYPE__NR = 2,\n};\n\nenum watch_meta_notification_subtype {\n\tWATCH_META_REMOVAL_NOTIFICATION = 0,\n\tWATCH_META_LOSS_NOTIFICATION = 1,\n};\n\nstruct watch_notification {\n\t__u32 type: 24;\n\t__u32 subtype: 8;\n\t__u32 info;\n};\n\nstruct watch_notification_type_filter {\n\t__u32 type;\n\t__u32 info_filter;\n\t__u32 info_mask;\n\t__u32 subtype_filter[8];\n};\n\nstruct watch_notification_filter {\n\t__u32 nr_filters;\n\t__u32 __reserved;\n\tstruct watch_notification_type_filter filters[0];\n};\n\nstruct watch_notification_removal {\n\tstruct watch_notification watch;\n\t__u64 id;\n};\n\nstruct watch_type_filter {\n\tenum watch_notification_type type;\n\t__u32 subtype_filter[1];\n\t__u32 info_filter;\n\t__u32 info_mask;\n};\n\nstruct watch_filter {\n\tunion {\n\t\tstruct callback_head rcu;\n\t\tlong unsigned int type_filter[2];\n\t};\n\tu32 nr_filters;\n\tstruct watch_type_filter filters[0];\n};\n\nstruct watch_queue {\n\tstruct callback_head rcu;\n\tstruct watch_filter *filter;\n\tstruct pipe_inode_info *pipe;\n\tstruct hlist_head watches;\n\tstruct page **notes;\n\tlong unsigned int *notes_bitmap;\n\tstruct kref usage;\n\tspinlock_t lock;\n\tunsigned int nr_notes;\n\tunsigned int nr_pages;\n\tbool defunct;\n};\n\nstruct watch {\n\tunion {\n\t\tstruct callback_head rcu;\n\t\tu32 info_id;\n\t};\n\tstruct watch_queue *queue;\n\tstruct hlist_node queue_node;\n\tstruct watch_list *watch_list;\n\tstruct hlist_node list_node;\n\tconst struct cred *cred;\n\tvoid *private;\n\tu64 id;\n\tstruct kref usage;\n};\n\nstruct pkcs7_message;\n\ntypedef int __kernel_rwf_t;\n\nenum positive_aop_returns {\n\tAOP_WRITEPAGE_ACTIVATE = 524288,\n\tAOP_TRUNCATED_PAGE = 524289,\n};\n\nenum iter_type {\n\tITER_IOVEC = 0,\n\tITER_KVEC = 1,\n\tITER_BVEC = 2,\n\tITER_PIPE = 3,\n\tITER_XARRAY = 4,\n\tITER_DISCARD = 5,\n};\n\nenum mapping_flags {\n\tAS_EIO = 0,\n\tAS_ENOSPC = 1,\n\tAS_MM_ALL_LOCKS = 2,\n\tAS_UNEVICTABLE = 3,\n\tAS_EXITING = 4,\n\tAS_NO_WRITEBACK_TAGS = 5,\n\tAS_THP_SUPPORT = 6,\n};\n\nstruct wait_page_key {\n\tstruct page *page;\n\tint bit_nr;\n\tint page_match;\n};\n\nstruct pagevec {\n\tunsigned char nr;\n\tbool percpu_pvec_drained;\n\tstruct page *pages[15];\n};\n\nstruct fid {\n\tunion {\n\t\tstruct {\n\t\t\tu32 ino;\n\t\t\tu32 gen;\n\t\t\tu32 parent_ino;\n\t\t\tu32 parent_gen;\n\t\t} i32;\n\t\tstruct {\n\t\t\tu32 block;\n\t\t\tu16 partref;\n\t\t\tu16 parent_partref;\n\t\t\tu32 generation;\n\t\t\tu32 parent_block;\n\t\t\tu32 parent_generation;\n\t\t} udf;\n\t\t__u32 raw[0];\n\t};\n};\n\nstruct trace_event_raw_mm_filemap_op_page_cache {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tlong unsigned int i_ino;\n\tlong unsigned int index;\n\tdev_t s_dev;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_filemap_set_wb_err {\n\tstruct trace_entry ent;\n\tlong unsigned int i_ino;\n\tdev_t s_dev;\n\terrseq_t errseq;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_file_check_and_advance_wb_err {\n\tstruct trace_entry ent;\n\tstruct file *file;\n\tlong unsigned int i_ino;\n\tdev_t s_dev;\n\terrseq_t old;\n\terrseq_t new;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mm_filemap_op_page_cache {};\n\nstruct trace_event_data_offsets_filemap_set_wb_err {};\n\nstruct trace_event_data_offsets_file_check_and_advance_wb_err {};\n\ntypedef void (*btf_trace_mm_filemap_delete_from_page_cache)(void *, struct page *);\n\ntypedef void (*btf_trace_mm_filemap_add_to_page_cache)(void *, struct page *);\n\ntypedef void (*btf_trace_filemap_set_wb_err)(void *, struct address_space *, errseq_t);\n\ntypedef void (*btf_trace_file_check_and_advance_wb_err)(void *, struct file *, errseq_t);\n\nenum behavior {\n\tEXCLUSIVE = 0,\n\tSHARED = 1,\n\tDROP = 2,\n};\n\nstruct reciprocal_value {\n\tu32 m;\n\tu8 sh1;\n\tu8 sh2;\n};\n\nstruct kmem_cache_order_objects {\n\tunsigned int x;\n};\n\nstruct kmem_cache_cpu;\n\nstruct kmem_cache_node;\n\nstruct kmem_cache {\n\tstruct kmem_cache_cpu *cpu_slab;\n\tslab_flags_t flags;\n\tlong unsigned int min_partial;\n\tunsigned int size;\n\tunsigned int object_size;\n\tstruct reciprocal_value reciprocal_size;\n\tunsigned int offset;\n\tunsigned int cpu_partial;\n\tstruct kmem_cache_order_objects oo;\n\tstruct kmem_cache_order_objects max;\n\tstruct kmem_cache_order_objects min;\n\tgfp_t allocflags;\n\tint refcount;\n\tvoid (*ctor)(void *);\n\tunsigned int inuse;\n\tunsigned int align;\n\tunsigned int red_left_pad;\n\tconst char *name;\n\tstruct list_head list;\n\tstruct kobject kobj;\n\tlong unsigned int random;\n\tunsigned int remote_node_defrag_ratio;\n\tunsigned int *random_seq;\n\tunsigned int useroffset;\n\tunsigned int usersize;\n\tstruct kmem_cache_node *node[32];\n};\n\nstruct kmem_cache_cpu {\n\tvoid **freelist;\n\tlong unsigned int tid;\n\tstruct page *page;\n\tstruct page *partial;\n};\n\nstruct kmem_cache_node {\n\tspinlock_t list_lock;\n\tlong unsigned int nr_partial;\n\tstruct list_head partial;\n\tatomic_long_t nr_slabs;\n\tatomic_long_t total_objects;\n\tstruct list_head full;\n};\n\nstruct zap_details {\n\tstruct address_space *check_mapping;\n\tlong unsigned int first_index;\n\tlong unsigned int last_index;\n\tstruct page *single_page;\n};\n\nenum oom_constraint {\n\tCONSTRAINT_NONE = 0,\n\tCONSTRAINT_CPUSET = 1,\n\tCONSTRAINT_MEMORY_POLICY = 2,\n\tCONSTRAINT_MEMCG = 3,\n};\n\nstruct oom_control {\n\tstruct zonelist *zonelist;\n\tnodemask_t *nodemask;\n\tstruct mem_cgroup *memcg;\n\tconst gfp_t gfp_mask;\n\tconst int order;\n\tlong unsigned int totalpages;\n\tstruct task_struct *chosen;\n\tlong int chosen_points;\n\tenum oom_constraint constraint;\n};\n\nenum compact_priority {\n\tCOMPACT_PRIO_SYNC_FULL = 0,\n\tMIN_COMPACT_PRIORITY = 0,\n\tCOMPACT_PRIO_SYNC_LIGHT = 1,\n\tMIN_COMPACT_COSTLY_PRIORITY = 1,\n\tDEF_COMPACT_PRIORITY = 1,\n\tCOMPACT_PRIO_ASYNC = 2,\n\tINIT_COMPACT_PRIORITY = 2,\n};\n\nenum compact_result {\n\tCOMPACT_NOT_SUITABLE_ZONE = 0,\n\tCOMPACT_SKIPPED = 1,\n\tCOMPACT_DEFERRED = 2,\n\tCOMPACT_NO_SUITABLE_PAGE = 3,\n\tCOMPACT_CONTINUE = 4,\n\tCOMPACT_COMPLETE = 5,\n\tCOMPACT_PARTIAL_SKIPPED = 6,\n\tCOMPACT_CONTENDED = 7,\n\tCOMPACT_SUCCESS = 8,\n};\n\nstruct trace_event_raw_oom_score_adj_update {\n\tstruct trace_entry ent;\n\tpid_t pid;\n\tchar comm[16];\n\tshort int oom_score_adj;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_reclaim_retry_zone {\n\tstruct trace_entry ent;\n\tint node;\n\tint zone_idx;\n\tint order;\n\tlong unsigned int reclaimable;\n\tlong unsigned int available;\n\tlong unsigned int min_wmark;\n\tint no_progress_loops;\n\tbool wmark_check;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mark_victim {\n\tstruct trace_entry ent;\n\tint pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_wake_reaper {\n\tstruct trace_entry ent;\n\tint pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_start_task_reaping {\n\tstruct trace_entry ent;\n\tint pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_finish_task_reaping {\n\tstruct trace_entry ent;\n\tint pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_skip_task_reaping {\n\tstruct trace_entry ent;\n\tint pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_compact_retry {\n\tstruct trace_entry ent;\n\tint order;\n\tint priority;\n\tint result;\n\tint retries;\n\tint max_retries;\n\tbool ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_oom_score_adj_update {};\n\nstruct trace_event_data_offsets_reclaim_retry_zone {};\n\nstruct trace_event_data_offsets_mark_victim {};\n\nstruct trace_event_data_offsets_wake_reaper {};\n\nstruct trace_event_data_offsets_start_task_reaping {};\n\nstruct trace_event_data_offsets_finish_task_reaping {};\n\nstruct trace_event_data_offsets_skip_task_reaping {};\n\nstruct trace_event_data_offsets_compact_retry {};\n\ntypedef void (*btf_trace_oom_score_adj_update)(void *, struct task_struct *);\n\ntypedef void (*btf_trace_reclaim_retry_zone)(void *, struct zoneref *, int, long unsigned int, long unsigned int, long unsigned int, int, bool);\n\ntypedef void (*btf_trace_mark_victim)(void *, int);\n\ntypedef void (*btf_trace_wake_reaper)(void *, int);\n\ntypedef void (*btf_trace_start_task_reaping)(void *, int);\n\ntypedef void (*btf_trace_finish_task_reaping)(void *, int);\n\ntypedef void (*btf_trace_skip_task_reaping)(void *, int);\n\ntypedef void (*btf_trace_compact_retry)(void *, int, enum compact_priority, enum compact_result, int, int, bool);\n\nenum wb_congested_state {\n\tWB_async_congested = 0,\n\tWB_sync_congested = 1,\n};\n\nenum wb_state {\n\tWB_registered = 0,\n\tWB_writeback_running = 1,\n\tWB_has_dirty_io = 2,\n\tWB_start_all = 3,\n};\n\nenum {\n\tBLK_RW_ASYNC = 0,\n\tBLK_RW_SYNC = 1,\n};\n\nstruct wb_lock_cookie {\n\tbool locked;\n\tlong unsigned int flags;\n};\n\ntypedef int (*writepage_t)(struct page *, struct writeback_control *, void *);\n\nenum page_memcg_data_flags {\n\tMEMCG_DATA_OBJCGS = 1,\n\tMEMCG_DATA_KMEM = 2,\n\t__NR_MEMCG_DATA_FLAGS = 4,\n};\n\nstruct dirty_throttle_control {\n\tstruct wb_domain *dom;\n\tstruct dirty_throttle_control *gdtc;\n\tstruct bdi_writeback *wb;\n\tstruct fprop_local_percpu *wb_completions;\n\tlong unsigned int avail;\n\tlong unsigned int dirty;\n\tlong unsigned int thresh;\n\tlong unsigned int bg_thresh;\n\tlong unsigned int wb_dirty;\n\tlong unsigned int wb_thresh;\n\tlong unsigned int wb_bg_thresh;\n\tlong unsigned int pos_ratio;\n};\n\ntypedef void compound_page_dtor(struct page *);\n\nstruct trace_event_raw_mm_lru_insertion {\n\tstruct trace_entry ent;\n\tstruct page *page;\n\tlong unsigned int pfn;\n\tenum lru_list lru;\n\tlong unsigned int flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_lru_activate {\n\tstruct trace_entry ent;\n\tstruct page *page;\n\tlong unsigned int pfn;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mm_lru_insertion {};\n\nstruct trace_event_data_offsets_mm_lru_activate {};\n\ntypedef void (*btf_trace_mm_lru_insertion)(void *, struct page *);\n\ntypedef void (*btf_trace_mm_lru_activate)(void *, struct page *);\n\nstruct lru_rotate {\n\tlocal_lock_t lock;\n\tstruct pagevec pvec;\n};\n\nstruct lru_pvecs {\n\tlocal_lock_t lock;\n\tstruct pagevec lru_add;\n\tstruct pagevec lru_deactivate_file;\n\tstruct pagevec lru_deactivate;\n\tstruct pagevec lru_lazyfree;\n\tstruct pagevec activate_page;\n};\n\nenum lruvec_flags {\n\tLRUVEC_CONGESTED = 0,\n};\n\nenum pgdat_flags {\n\tPGDAT_DIRTY = 0,\n\tPGDAT_WRITEBACK = 1,\n\tPGDAT_RECLAIM_LOCKED = 2,\n};\n\nenum zone_flags {\n\tZONE_BOOSTED_WATERMARK = 0,\n\tZONE_RECLAIM_ACTIVE = 1,\n};\n\nstruct reclaim_stat {\n\tunsigned int nr_dirty;\n\tunsigned int nr_unqueued_dirty;\n\tunsigned int nr_congested;\n\tunsigned int nr_writeback;\n\tunsigned int nr_immediate;\n\tunsigned int nr_pageout;\n\tunsigned int nr_activate[2];\n\tunsigned int nr_ref_keep;\n\tunsigned int nr_unmap_fail;\n\tunsigned int nr_lazyfree_fail;\n};\n\nstruct mem_cgroup_reclaim_cookie {\n\tpg_data_t *pgdat;\n\tunsigned int generation;\n};\n\nenum ttu_flags {\n\tTTU_SPLIT_HUGE_PMD = 4,\n\tTTU_IGNORE_MLOCK = 8,\n\tTTU_SYNC = 16,\n\tTTU_IGNORE_HWPOISON = 32,\n\tTTU_BATCH_FLUSH = 64,\n\tTTU_RMAP_LOCKED = 128,\n};\n\nstruct trace_event_raw_mm_vmscan_kswapd_sleep {\n\tstruct trace_entry ent;\n\tint nid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_kswapd_wake {\n\tstruct trace_entry ent;\n\tint nid;\n\tint zid;\n\tint order;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_wakeup_kswapd {\n\tstruct trace_entry ent;\n\tint nid;\n\tint zid;\n\tint order;\n\tgfp_t gfp_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_direct_reclaim_begin_template {\n\tstruct trace_entry ent;\n\tint order;\n\tgfp_t gfp_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_direct_reclaim_end_template {\n\tstruct trace_entry ent;\n\tlong unsigned int nr_reclaimed;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_shrink_slab_start {\n\tstruct trace_entry ent;\n\tstruct shrinker *shr;\n\tvoid *shrink;\n\tint nid;\n\tlong int nr_objects_to_shrink;\n\tgfp_t gfp_flags;\n\tlong unsigned int cache_items;\n\tlong long unsigned int delta;\n\tlong unsigned int total_scan;\n\tint priority;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_shrink_slab_end {\n\tstruct trace_entry ent;\n\tstruct shrinker *shr;\n\tint nid;\n\tvoid *shrink;\n\tlong int unused_scan;\n\tlong int new_scan;\n\tint retval;\n\tlong int total_scan;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_lru_isolate {\n\tstruct trace_entry ent;\n\tint highest_zoneidx;\n\tint order;\n\tlong unsigned int nr_requested;\n\tlong unsigned int nr_scanned;\n\tlong unsigned int nr_skipped;\n\tlong unsigned int nr_taken;\n\tisolate_mode_t isolate_mode;\n\tint lru;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_writepage {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tint reclaim_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_lru_shrink_inactive {\n\tstruct trace_entry ent;\n\tint nid;\n\tlong unsigned int nr_scanned;\n\tlong unsigned int nr_reclaimed;\n\tlong unsigned int nr_dirty;\n\tlong unsigned int nr_writeback;\n\tlong unsigned int nr_congested;\n\tlong unsigned int nr_immediate;\n\tunsigned int nr_activate0;\n\tunsigned int nr_activate1;\n\tlong unsigned int nr_ref_keep;\n\tlong unsigned int nr_unmap_fail;\n\tint priority;\n\tint reclaim_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_lru_shrink_active {\n\tstruct trace_entry ent;\n\tint nid;\n\tlong unsigned int nr_taken;\n\tlong unsigned int nr_active;\n\tlong unsigned int nr_deactivated;\n\tlong unsigned int nr_referenced;\n\tint priority;\n\tint reclaim_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_vmscan_node_reclaim_begin {\n\tstruct trace_entry ent;\n\tint nid;\n\tint order;\n\tgfp_t gfp_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mm_vmscan_kswapd_sleep {};\n\nstruct trace_event_data_offsets_mm_vmscan_kswapd_wake {};\n\nstruct trace_event_data_offsets_mm_vmscan_wakeup_kswapd {};\n\nstruct trace_event_data_offsets_mm_vmscan_direct_reclaim_begin_template {};\n\nstruct trace_event_data_offsets_mm_vmscan_direct_reclaim_end_template {};\n\nstruct trace_event_data_offsets_mm_shrink_slab_start {};\n\nstruct trace_event_data_offsets_mm_shrink_slab_end {};\n\nstruct trace_event_data_offsets_mm_vmscan_lru_isolate {};\n\nstruct trace_event_data_offsets_mm_vmscan_writepage {};\n\nstruct trace_event_data_offsets_mm_vmscan_lru_shrink_inactive {};\n\nstruct trace_event_data_offsets_mm_vmscan_lru_shrink_active {};\n\nstruct trace_event_data_offsets_mm_vmscan_node_reclaim_begin {};\n\ntypedef void (*btf_trace_mm_vmscan_kswapd_sleep)(void *, int);\n\ntypedef void (*btf_trace_mm_vmscan_kswapd_wake)(void *, int, int, int);\n\ntypedef void (*btf_trace_mm_vmscan_wakeup_kswapd)(void *, int, int, int, gfp_t);\n\ntypedef void (*btf_trace_mm_vmscan_direct_reclaim_begin)(void *, int, gfp_t);\n\ntypedef void (*btf_trace_mm_vmscan_memcg_reclaim_begin)(void *, int, gfp_t);\n\ntypedef void (*btf_trace_mm_vmscan_memcg_softlimit_reclaim_begin)(void *, int, gfp_t);\n\ntypedef void (*btf_trace_mm_vmscan_direct_reclaim_end)(void *, long unsigned int);\n\ntypedef void (*btf_trace_mm_vmscan_memcg_reclaim_end)(void *, long unsigned int);\n\ntypedef void (*btf_trace_mm_vmscan_memcg_softlimit_reclaim_end)(void *, long unsigned int);\n\ntypedef void (*btf_trace_mm_shrink_slab_start)(void *, struct shrinker *, struct shrink_control *, long int, long unsigned int, long long unsigned int, long unsigned int, int);\n\ntypedef void (*btf_trace_mm_shrink_slab_end)(void *, struct shrinker *, int, int, long int, long int, long int);\n\ntypedef void (*btf_trace_mm_vmscan_lru_isolate)(void *, int, int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, isolate_mode_t, int);\n\ntypedef void (*btf_trace_mm_vmscan_writepage)(void *, struct page *);\n\ntypedef void (*btf_trace_mm_vmscan_lru_shrink_inactive)(void *, int, long unsigned int, long unsigned int, struct reclaim_stat *, int, int);\n\ntypedef void (*btf_trace_mm_vmscan_lru_shrink_active)(void *, int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, int, int);\n\ntypedef void (*btf_trace_mm_vmscan_node_reclaim_begin)(void *, int, int, gfp_t);\n\ntypedef void (*btf_trace_mm_vmscan_node_reclaim_end)(void *, long unsigned int);\n\nstruct scan_control {\n\tlong unsigned int nr_to_reclaim;\n\tnodemask_t *nodemask;\n\tstruct mem_cgroup *target_mem_cgroup;\n\tlong unsigned int anon_cost;\n\tlong unsigned int file_cost;\n\tunsigned int may_deactivate: 2;\n\tunsigned int force_deactivate: 1;\n\tunsigned int skipped_deactivate: 1;\n\tunsigned int may_writepage: 1;\n\tunsigned int may_unmap: 1;\n\tunsigned int may_swap: 1;\n\tunsigned int memcg_low_reclaim: 1;\n\tunsigned int memcg_low_skipped: 1;\n\tunsigned int hibernation_mode: 1;\n\tunsigned int compaction_ready: 1;\n\tunsigned int cache_trim_mode: 1;\n\tunsigned int file_is_tiny: 1;\n\ts8 order;\n\ts8 priority;\n\ts8 reclaim_idx;\n\tgfp_t gfp_mask;\n\tlong unsigned int nr_scanned;\n\tlong unsigned int nr_reclaimed;\n\tstruct {\n\t\tunsigned int dirty;\n\t\tunsigned int unqueued_dirty;\n\t\tunsigned int congested;\n\t\tunsigned int writeback;\n\t\tunsigned int immediate;\n\t\tunsigned int file_taken;\n\t\tunsigned int taken;\n\t} nr;\n\tstruct reclaim_state reclaim_state;\n};\n\ntypedef enum {\n\tPAGE_KEEP = 0,\n\tPAGE_ACTIVATE = 1,\n\tPAGE_SUCCESS = 2,\n\tPAGE_CLEAN = 3,\n} pageout_t;\n\nenum page_references {\n\tPAGEREF_RECLAIM = 0,\n\tPAGEREF_RECLAIM_CLEAN = 1,\n\tPAGEREF_KEEP = 2,\n\tPAGEREF_ACTIVATE = 3,\n};\n\nenum scan_balance {\n\tSCAN_EQUAL = 0,\n\tSCAN_FRACT = 1,\n\tSCAN_ANON = 2,\n\tSCAN_FILE = 3,\n};\n\ntypedef __u64 __le64;\n\nenum transparent_hugepage_flag {\n\tTRANSPARENT_HUGEPAGE_NEVER_DAX = 0,\n\tTRANSPARENT_HUGEPAGE_FLAG = 1,\n\tTRANSPARENT_HUGEPAGE_REQ_MADV_FLAG = 2,\n\tTRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG = 3,\n\tTRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG = 4,\n\tTRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG = 5,\n\tTRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG = 6,\n\tTRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG = 7,\n\tTRANSPARENT_HUGEPAGE_USE_ZERO_PAGE_FLAG = 8,\n};\n\nstruct xattr;\n\ntypedef int (*initxattrs)(struct inode *, const struct xattr *, void *);\n\nstruct xattr {\n\tconst char *name;\n\tvoid *value;\n\tsize_t value_len;\n};\n\nstruct constant_table {\n\tconst char *name;\n\tint value;\n};\n\nenum {\n\tMPOL_DEFAULT = 0,\n\tMPOL_PREFERRED = 1,\n\tMPOL_BIND = 2,\n\tMPOL_INTERLEAVE = 3,\n\tMPOL_LOCAL = 4,\n\tMPOL_MAX = 5,\n};\n\nstruct shared_policy {\n\tstruct rb_root root;\n\trwlock_t lock;\n};\n\nstruct simple_xattrs {\n\tstruct list_head head;\n\tspinlock_t lock;\n};\n\nstruct simple_xattr {\n\tstruct list_head list;\n\tchar *name;\n\tsize_t size;\n\tchar value[0];\n};\n\nstruct shmem_inode_info {\n\tspinlock_t lock;\n\tunsigned int seals;\n\tlong unsigned int flags;\n\tlong unsigned int alloced;\n\tlong unsigned int swapped;\n\tstruct list_head shrinklist;\n\tstruct list_head swaplist;\n\tstruct shared_policy policy;\n\tstruct simple_xattrs xattrs;\n\tatomic_t stop_eviction;\n\tstruct inode vfs_inode;\n};\n\nstruct shmem_sb_info {\n\tlong unsigned int max_blocks;\n\tstruct percpu_counter used_blocks;\n\tlong unsigned int max_inodes;\n\tlong unsigned int free_inodes;\n\tspinlock_t stat_lock;\n\tumode_t mode;\n\tunsigned char huge;\n\tkuid_t uid;\n\tkgid_t gid;\n\tbool full_inums;\n\tino_t next_ino;\n\tino_t *ino_batch;\n\tstruct mempolicy *mpol;\n\tspinlock_t shrinklist_lock;\n\tstruct list_head shrinklist;\n\tlong unsigned int shrinklist_len;\n};\n\nenum sgp_type {\n\tSGP_READ = 0,\n\tSGP_CACHE = 1,\n\tSGP_NOHUGE = 2,\n\tSGP_HUGE = 3,\n\tSGP_WRITE = 4,\n\tSGP_FALLOC = 5,\n};\n\nenum fid_type {\n\tFILEID_ROOT = 0,\n\tFILEID_INO32_GEN = 1,\n\tFILEID_INO32_GEN_PARENT = 2,\n\tFILEID_BTRFS_WITHOUT_PARENT = 77,\n\tFILEID_BTRFS_WITH_PARENT = 78,\n\tFILEID_BTRFS_WITH_PARENT_ROOT = 79,\n\tFILEID_UDF_WITHOUT_PARENT = 81,\n\tFILEID_UDF_WITH_PARENT = 82,\n\tFILEID_NILFS_WITHOUT_PARENT = 97,\n\tFILEID_NILFS_WITH_PARENT = 98,\n\tFILEID_FAT_WITHOUT_PARENT = 113,\n\tFILEID_FAT_WITH_PARENT = 114,\n\tFILEID_LUSTRE = 151,\n\tFILEID_KERNFS = 254,\n\tFILEID_INVALID = 255,\n};\n\nstruct shmem_falloc {\n\twait_queue_head_t *waitq;\n\tlong unsigned int start;\n\tlong unsigned int next;\n\tlong unsigned int nr_falloced;\n\tlong unsigned int nr_unswapped;\n};\n\nstruct shmem_options {\n\tlong long unsigned int blocks;\n\tlong long unsigned int inodes;\n\tstruct mempolicy *mpol;\n\tkuid_t uid;\n\tkgid_t gid;\n\tumode_t mode;\n\tbool full_inums;\n\tint huge;\n\tint seen;\n};\n\nenum shmem_param {\n\tOpt_gid = 0,\n\tOpt_huge = 1,\n\tOpt_mode = 2,\n\tOpt_mpol = 3,\n\tOpt_nr_blocks = 4,\n\tOpt_nr_inodes = 5,\n\tOpt_size = 6,\n\tOpt_uid = 7,\n\tOpt_inode32 = 8,\n\tOpt_inode64 = 9,\n};\n\nenum writeback_stat_item {\n\tNR_DIRTY_THRESHOLD = 0,\n\tNR_DIRTY_BG_THRESHOLD = 1,\n\tNR_VM_WRITEBACK_STAT_ITEMS = 2,\n};\n\nstruct contig_page_info {\n\tlong unsigned int free_pages;\n\tlong unsigned int free_blocks_total;\n\tlong unsigned int free_blocks_suitable;\n};\n\nstruct radix_tree_iter {\n\tlong unsigned int index;\n\tlong unsigned int next_index;\n\tlong unsigned int tags;\n\tstruct xa_node *node;\n};\n\nenum {\n\tRADIX_TREE_ITER_TAG_MASK = 15,\n\tRADIX_TREE_ITER_TAGGED = 16,\n\tRADIX_TREE_ITER_CONTIG = 32,\n};\n\nenum mminit_level {\n\tMMINIT_WARNING = 0,\n\tMMINIT_VERIFY = 1,\n\tMMINIT_TRACE = 2,\n};\n\nstruct pcpu_group_info {\n\tint nr_units;\n\tlong unsigned int base_offset;\n\tunsigned int *cpu_map;\n};\n\nstruct pcpu_alloc_info {\n\tsize_t static_size;\n\tsize_t reserved_size;\n\tsize_t dyn_size;\n\tsize_t unit_size;\n\tsize_t atom_size;\n\tsize_t alloc_size;\n\tsize_t __ai_size;\n\tint nr_groups;\n\tstruct pcpu_group_info groups[0];\n};\n\nstruct trace_event_raw_percpu_alloc_percpu {\n\tstruct trace_entry ent;\n\tbool reserved;\n\tbool is_atomic;\n\tsize_t size;\n\tsize_t align;\n\tvoid *base_addr;\n\tint off;\n\tvoid *ptr;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_percpu_free_percpu {\n\tstruct trace_entry ent;\n\tvoid *base_addr;\n\tint off;\n\tvoid *ptr;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_percpu_alloc_percpu_fail {\n\tstruct trace_entry ent;\n\tbool reserved;\n\tbool is_atomic;\n\tsize_t size;\n\tsize_t align;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_percpu_create_chunk {\n\tstruct trace_entry ent;\n\tvoid *base_addr;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_percpu_destroy_chunk {\n\tstruct trace_entry ent;\n\tvoid *base_addr;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_percpu_alloc_percpu {};\n\nstruct trace_event_data_offsets_percpu_free_percpu {};\n\nstruct trace_event_data_offsets_percpu_alloc_percpu_fail {};\n\nstruct trace_event_data_offsets_percpu_create_chunk {};\n\nstruct trace_event_data_offsets_percpu_destroy_chunk {};\n\ntypedef void (*btf_trace_percpu_alloc_percpu)(void *, bool, bool, size_t, size_t, void *, int, void *);\n\ntypedef void (*btf_trace_percpu_free_percpu)(void *, void *, int, void *);\n\ntypedef void (*btf_trace_percpu_alloc_percpu_fail)(void *, bool, bool, size_t, size_t);\n\ntypedef void (*btf_trace_percpu_create_chunk)(void *, void *);\n\ntypedef void (*btf_trace_percpu_destroy_chunk)(void *, void *);\n\nstruct pcpu_block_md {\n\tint scan_hint;\n\tint scan_hint_start;\n\tint contig_hint;\n\tint contig_hint_start;\n\tint left_free;\n\tint right_free;\n\tint first_free;\n\tint nr_bits;\n};\n\nstruct pcpu_chunk {\n\tstruct list_head list;\n\tint free_bytes;\n\tstruct pcpu_block_md chunk_md;\n\tvoid *base_addr;\n\tlong unsigned int *alloc_map;\n\tlong unsigned int *bound_map;\n\tstruct pcpu_block_md *md_blocks;\n\tvoid *data;\n\tbool immutable;\n\tbool isolated;\n\tint start_offset;\n\tint end_offset;\n\tstruct obj_cgroup **obj_cgroups;\n\tint nr_pages;\n\tint nr_populated;\n\tint nr_empty_pop_pages;\n\tlong unsigned int populated[0];\n};\n\nstruct trace_event_raw_kmem_alloc {\n\tstruct trace_entry ent;\n\tlong unsigned int call_site;\n\tconst void *ptr;\n\tsize_t bytes_req;\n\tsize_t bytes_alloc;\n\tgfp_t gfp_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_kmem_alloc_node {\n\tstruct trace_entry ent;\n\tlong unsigned int call_site;\n\tconst void *ptr;\n\tsize_t bytes_req;\n\tsize_t bytes_alloc;\n\tgfp_t gfp_flags;\n\tint node;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_kfree {\n\tstruct trace_entry ent;\n\tlong unsigned int call_site;\n\tconst void *ptr;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_kmem_cache_free {\n\tstruct trace_entry ent;\n\tlong unsigned int call_site;\n\tconst void *ptr;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_page_free {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tunsigned int order;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_page_free_batched {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_page_alloc {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tunsigned int order;\n\tgfp_t gfp_flags;\n\tint migratetype;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_page {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tunsigned int order;\n\tint migratetype;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_page_pcpu_drain {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tunsigned int order;\n\tint migratetype;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_page_alloc_extfrag {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tint alloc_order;\n\tint fallback_order;\n\tint alloc_migratetype;\n\tint fallback_migratetype;\n\tint change_ownership;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rss_stat {\n\tstruct trace_entry ent;\n\tunsigned int mm_id;\n\tunsigned int curr;\n\tint member;\n\tlong int size;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_kmem_alloc {};\n\nstruct trace_event_data_offsets_kmem_alloc_node {};\n\nstruct trace_event_data_offsets_kfree {};\n\nstruct trace_event_data_offsets_kmem_cache_free {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_mm_page_free {};\n\nstruct trace_event_data_offsets_mm_page_free_batched {};\n\nstruct trace_event_data_offsets_mm_page_alloc {};\n\nstruct trace_event_data_offsets_mm_page {};\n\nstruct trace_event_data_offsets_mm_page_pcpu_drain {};\n\nstruct trace_event_data_offsets_mm_page_alloc_extfrag {};\n\nstruct trace_event_data_offsets_rss_stat {};\n\ntypedef void (*btf_trace_kmalloc)(void *, long unsigned int, const void *, size_t, size_t, gfp_t);\n\ntypedef void (*btf_trace_kmem_cache_alloc)(void *, long unsigned int, const void *, size_t, size_t, gfp_t);\n\ntypedef void (*btf_trace_kmalloc_node)(void *, long unsigned int, const void *, size_t, size_t, gfp_t, int);\n\ntypedef void (*btf_trace_kmem_cache_alloc_node)(void *, long unsigned int, const void *, size_t, size_t, gfp_t, int);\n\ntypedef void (*btf_trace_kfree)(void *, long unsigned int, const void *);\n\ntypedef void (*btf_trace_kmem_cache_free)(void *, long unsigned int, const void *, const char *);\n\ntypedef void (*btf_trace_mm_page_free)(void *, struct page *, unsigned int);\n\ntypedef void (*btf_trace_mm_page_free_batched)(void *, struct page *);\n\ntypedef void (*btf_trace_mm_page_alloc)(void *, struct page *, unsigned int, gfp_t, int);\n\ntypedef void (*btf_trace_mm_page_alloc_zone_locked)(void *, struct page *, unsigned int, int);\n\ntypedef void (*btf_trace_mm_page_pcpu_drain)(void *, struct page *, unsigned int, int);\n\ntypedef void (*btf_trace_mm_page_alloc_extfrag)(void *, struct page *, int, int, int, int);\n\ntypedef void (*btf_trace_rss_stat)(void *, struct mm_struct *, int, long int);\n\nenum slab_state {\n\tDOWN = 0,\n\tPARTIAL = 1,\n\tPARTIAL_NODE = 2,\n\tUP = 3,\n\tFULL = 4,\n};\n\nstruct kmalloc_info_struct {\n\tconst char *name[4];\n\tunsigned int size;\n};\n\nstruct slabinfo {\n\tlong unsigned int active_objs;\n\tlong unsigned int num_objs;\n\tlong unsigned int active_slabs;\n\tlong unsigned int num_slabs;\n\tlong unsigned int shared_avail;\n\tunsigned int limit;\n\tunsigned int batchcount;\n\tunsigned int shared;\n\tunsigned int objects_per_slab;\n\tunsigned int cache_order;\n};\n\nstruct kmem_obj_info {\n\tvoid *kp_ptr;\n\tstruct page *kp_page;\n\tvoid *kp_objp;\n\tlong unsigned int kp_data_offset;\n\tstruct kmem_cache *kp_slab_cache;\n\tvoid *kp_ret;\n\tvoid *kp_stack[16];\n\tvoid *kp_free_stack[16];\n};\n\nenum pageblock_bits {\n\tPB_migrate = 0,\n\tPB_migrate_end = 2,\n\tPB_migrate_skip = 3,\n\tNR_PAGEBLOCK_BITS = 4,\n};\n\nstruct node___2 {\n\tstruct device dev;\n\tstruct list_head access_list;\n\tstruct work_struct node_work;\n\tstruct list_head cache_attrs;\n\tstruct device *cache_dev;\n};\n\ntypedef struct page *new_page_t(struct page *, long unsigned int);\n\ntypedef void free_page_t(struct page *, long unsigned int);\n\nstruct alloc_context {\n\tstruct zonelist *zonelist;\n\tnodemask_t *nodemask;\n\tstruct zoneref *preferred_zoneref;\n\tint migratetype;\n\tenum zone_type highest_zoneidx;\n\tbool spread_dirty_pages;\n};\n\nstruct trace_event_raw_mm_compaction_isolate_template {\n\tstruct trace_entry ent;\n\tlong unsigned int start_pfn;\n\tlong unsigned int end_pfn;\n\tlong unsigned int nr_scanned;\n\tlong unsigned int nr_taken;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_compaction_migratepages {\n\tstruct trace_entry ent;\n\tlong unsigned int nr_migrated;\n\tlong unsigned int nr_failed;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_compaction_begin {\n\tstruct trace_entry ent;\n\tlong unsigned int zone_start;\n\tlong unsigned int migrate_pfn;\n\tlong unsigned int free_pfn;\n\tlong unsigned int zone_end;\n\tbool sync;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_compaction_end {\n\tstruct trace_entry ent;\n\tlong unsigned int zone_start;\n\tlong unsigned int migrate_pfn;\n\tlong unsigned int free_pfn;\n\tlong unsigned int zone_end;\n\tbool sync;\n\tint status;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_compaction_try_to_compact_pages {\n\tstruct trace_entry ent;\n\tint order;\n\tgfp_t gfp_mask;\n\tint prio;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_compaction_suitable_template {\n\tstruct trace_entry ent;\n\tint nid;\n\tenum zone_type idx;\n\tint order;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_compaction_defer_template {\n\tstruct trace_entry ent;\n\tint nid;\n\tenum zone_type idx;\n\tint order;\n\tunsigned int considered;\n\tunsigned int defer_shift;\n\tint order_failed;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_compaction_kcompactd_sleep {\n\tstruct trace_entry ent;\n\tint nid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_kcompactd_wake_template {\n\tstruct trace_entry ent;\n\tint nid;\n\tint order;\n\tenum zone_type highest_zoneidx;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mm_compaction_isolate_template {};\n\nstruct trace_event_data_offsets_mm_compaction_migratepages {};\n\nstruct trace_event_data_offsets_mm_compaction_begin {};\n\nstruct trace_event_data_offsets_mm_compaction_end {};\n\nstruct trace_event_data_offsets_mm_compaction_try_to_compact_pages {};\n\nstruct trace_event_data_offsets_mm_compaction_suitable_template {};\n\nstruct trace_event_data_offsets_mm_compaction_defer_template {};\n\nstruct trace_event_data_offsets_mm_compaction_kcompactd_sleep {};\n\nstruct trace_event_data_offsets_kcompactd_wake_template {};\n\ntypedef void (*btf_trace_mm_compaction_isolate_migratepages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_mm_compaction_isolate_freepages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_mm_compaction_migratepages)(void *, long unsigned int, int, struct list_head *);\n\ntypedef void (*btf_trace_mm_compaction_begin)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, bool);\n\ntypedef void (*btf_trace_mm_compaction_end)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, bool, int);\n\ntypedef void (*btf_trace_mm_compaction_try_to_compact_pages)(void *, int, gfp_t, int);\n\ntypedef void (*btf_trace_mm_compaction_finished)(void *, struct zone *, int, int);\n\ntypedef void (*btf_trace_mm_compaction_suitable)(void *, struct zone *, int, int);\n\ntypedef void (*btf_trace_mm_compaction_deferred)(void *, struct zone *, int);\n\ntypedef void (*btf_trace_mm_compaction_defer_compaction)(void *, struct zone *, int);\n\ntypedef void (*btf_trace_mm_compaction_defer_reset)(void *, struct zone *, int);\n\ntypedef void (*btf_trace_mm_compaction_kcompactd_sleep)(void *, int);\n\ntypedef void (*btf_trace_mm_compaction_wakeup_kcompactd)(void *, int, int, enum zone_type);\n\ntypedef void (*btf_trace_mm_compaction_kcompactd_wake)(void *, int, int, enum zone_type);\n\ntypedef enum {\n\tISOLATE_ABORT = 0,\n\tISOLATE_NONE = 1,\n\tISOLATE_SUCCESS = 2,\n} isolate_migrate_t;\n\nstruct anon_vma_chain {\n\tstruct vm_area_struct *vma;\n\tstruct anon_vma *anon_vma;\n\tstruct list_head same_vma;\n\tstruct rb_node rb;\n\tlong unsigned int rb_subtree_last;\n};\n\nenum lru_status {\n\tLRU_REMOVED = 0,\n\tLRU_REMOVED_RETRY = 1,\n\tLRU_ROTATE = 2,\n\tLRU_SKIP = 3,\n\tLRU_RETRY = 4,\n};\n\ntypedef enum lru_status (*list_lru_walk_cb)(struct list_head *, struct list_lru_one *, spinlock_t *, void *);\n\ntypedef struct {\n\tlong unsigned int pd;\n} hugepd_t;\n\nstruct migration_target_control {\n\tint nid;\n\tnodemask_t *nmask;\n\tgfp_t gfp_mask;\n};\n\nstruct follow_page_context {\n\tstruct dev_pagemap *pgmap;\n\tunsigned int page_mask;\n};\n\nstruct trace_event_raw_mmap_lock_start_locking {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tu32 __data_loc_memcg_path;\n\tbool write;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mmap_lock_acquire_returned {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tu32 __data_loc_memcg_path;\n\tbool write;\n\tbool success;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mmap_lock_released {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tu32 __data_loc_memcg_path;\n\tbool write;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mmap_lock_start_locking {\n\tu32 memcg_path;\n};\n\nstruct trace_event_data_offsets_mmap_lock_acquire_returned {\n\tu32 memcg_path;\n};\n\nstruct trace_event_data_offsets_mmap_lock_released {\n\tu32 memcg_path;\n};\n\ntypedef void (*btf_trace_mmap_lock_start_locking)(void *, struct mm_struct *, const char *, bool);\n\ntypedef void (*btf_trace_mmap_lock_acquire_returned)(void *, struct mm_struct *, const char *, bool, bool);\n\ntypedef void (*btf_trace_mmap_lock_released)(void *, struct mm_struct *, const char *, bool);\n\nstruct memcg_path {\n\tlocal_lock_t lock;\n\tchar *buf;\n\tlocal_t buf_idx;\n};\n\ntypedef unsigned int pgtbl_mod_mask;\n\nenum {\n\tSWP_USED = 1,\n\tSWP_WRITEOK = 2,\n\tSWP_DISCARDABLE = 4,\n\tSWP_DISCARDING = 8,\n\tSWP_SOLIDSTATE = 16,\n\tSWP_CONTINUED = 32,\n\tSWP_BLKDEV = 64,\n\tSWP_ACTIVATED = 128,\n\tSWP_FS_OPS = 256,\n\tSWP_AREA_DISCARD = 512,\n\tSWP_PAGE_DISCARD = 1024,\n\tSWP_STABLE_WRITES = 2048,\n\tSWP_SYNCHRONOUS_IO = 4096,\n\tSWP_SCANNING = 16384,\n};\n\nstruct copy_subpage_arg {\n\tstruct page *dst;\n\tstruct page *src;\n\tstruct vm_area_struct *vma;\n};\n\nstruct mm_walk;\n\nstruct mm_walk_ops {\n\tint (*pgd_entry)(pgd_t *, long unsigned int, long unsigned int, struct mm_walk *);\n\tint (*p4d_entry)(p4d_t *, long unsigned int, long unsigned int, struct mm_walk *);\n\tint (*pud_entry)(pud_t *, long unsigned int, long unsigned int, struct mm_walk *);\n\tint (*pmd_entry)(pmd_t *, long unsigned int, long unsigned int, struct mm_walk *);\n\tint (*pte_entry)(pte_t *, long unsigned int, long unsigned int, struct mm_walk *);\n\tint (*pte_hole)(long unsigned int, long unsigned int, int, struct mm_walk *);\n\tint (*hugetlb_entry)(pte_t *, long unsigned int, long unsigned int, long unsigned int, struct mm_walk *);\n\tint (*test_walk)(long unsigned int, long unsigned int, struct mm_walk *);\n\tint (*pre_vma)(long unsigned int, long unsigned int, struct mm_walk *);\n\tvoid (*post_vma)(struct mm_walk *);\n};\n\nenum page_walk_action {\n\tACTION_SUBTREE = 0,\n\tACTION_CONTINUE = 1,\n\tACTION_AGAIN = 2,\n};\n\nstruct mm_walk {\n\tconst struct mm_walk_ops *ops;\n\tstruct mm_struct *mm;\n\tpgd_t *pgd;\n\tstruct vm_area_struct *vma;\n\tenum page_walk_action action;\n\tbool no_vma;\n\tvoid *private;\n};\n\nenum {\n\tHUGETLB_SHMFS_INODE = 1,\n\tHUGETLB_ANONHUGE_INODE = 2,\n};\n\nstruct trace_event_raw_vm_unmapped_area {\n\tstruct trace_entry ent;\n\tlong unsigned int addr;\n\tlong unsigned int total_vm;\n\tlong unsigned int flags;\n\tlong unsigned int length;\n\tlong unsigned int low_limit;\n\tlong unsigned int high_limit;\n\tlong unsigned int align_mask;\n\tlong unsigned int align_offset;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_vm_unmapped_area {};\n\ntypedef void (*btf_trace_vm_unmapped_area)(void *, long unsigned int, struct vm_unmapped_area_info *);\n\nenum pgt_entry {\n\tNORMAL_PMD = 0,\n\tHPAGE_PMD = 1,\n\tNORMAL_PUD = 2,\n\tHPAGE_PUD = 3,\n};\n\nstruct rmap_walk_control {\n\tvoid *arg;\n\tbool (*rmap_one)(struct page *, struct vm_area_struct *, long unsigned int, void *);\n\tint (*done)(struct page *);\n\tstruct anon_vma * (*anon_lock)(struct page *);\n\tbool (*invalid_vma)(struct vm_area_struct *, void *);\n};\n\nstruct page_referenced_arg {\n\tint mapcount;\n\tint referenced;\n\tlong unsigned int vm_flags;\n\tstruct mem_cgroup *memcg;\n};\n\nstruct make_exclusive_args {\n\tstruct mm_struct *mm;\n\tlong unsigned int address;\n\tvoid *owner;\n\tbool valid;\n};\n\nstruct vmap_area {\n\tlong unsigned int va_start;\n\tlong unsigned int va_end;\n\tstruct rb_node rb_node;\n\tstruct list_head list;\n\tunion {\n\t\tlong unsigned int subtree_max_size;\n\t\tstruct vm_struct *vm;\n\t};\n};\n\nstruct vfree_deferred {\n\tstruct llist_head list;\n\tstruct work_struct wq;\n};\n\nenum fit_type {\n\tNOTHING_FIT = 0,\n\tFL_FIT_TYPE = 1,\n\tLE_FIT_TYPE = 2,\n\tRE_FIT_TYPE = 3,\n\tNE_FIT_TYPE = 4,\n};\n\nstruct vmap_block_queue {\n\tspinlock_t lock;\n\tstruct list_head free;\n};\n\nstruct vmap_block {\n\tspinlock_t lock;\n\tstruct vmap_area *va;\n\tlong unsigned int free;\n\tlong unsigned int dirty;\n\tlong unsigned int dirty_min;\n\tlong unsigned int dirty_max;\n\tstruct list_head free_list;\n\tstruct callback_head callback_head;\n\tstruct list_head purge;\n};\n\nstruct vmap_pfn_data {\n\tlong unsigned int *pfns;\n\tpgprot_t prot;\n\tunsigned int idx;\n};\n\nstruct page_frag_cache {\n\tvoid *va;\n\t__u16 offset;\n\t__u16 size;\n\tunsigned int pagecnt_bias;\n\tbool pfmemalloc;\n};\n\ntypedef int fpi_t;\n\nstruct pagesets {\n\tlocal_lock_t lock;\n};\n\nstruct pcpu_drain {\n\tstruct zone *zone;\n\tstruct work_struct work;\n};\n\nstruct mminit_pfnnid_cache {\n\tlong unsigned int last_start;\n\tlong unsigned int last_end;\n\tint last_nid;\n};\n\nenum {\n\tMMOP_OFFLINE = 0,\n\tMMOP_ONLINE = 1,\n\tMMOP_ONLINE_KERNEL = 2,\n\tMMOP_ONLINE_MOVABLE = 3,\n};\n\ntypedef int mhp_t;\n\ntypedef void (*online_page_callback_t)(struct page *, unsigned int);\n\nstruct memory_block {\n\tlong unsigned int start_section_nr;\n\tlong unsigned int state;\n\tint online_type;\n\tint nid;\n\tstruct device dev;\n\tlong unsigned int nr_vmemmap_pages;\n};\n\nstruct memory_notify {\n\tlong unsigned int start_pfn;\n\tlong unsigned int nr_pages;\n\tint status_change_nid_normal;\n\tint status_change_nid_high;\n\tint status_change_nid;\n};\n\ntypedef int (*walk_memory_blocks_func_t)(struct memory_block *, void *);\n\nenum hugetlb_page_flags {\n\tHPG_restore_reserve = 0,\n\tHPG_migratable = 1,\n\tHPG_temporary = 2,\n\tHPG_freed = 3,\n\tHPG_vmemmap_optimized = 4,\n\t__NR_HPAGEFLAGS = 5,\n};\n\nstruct madvise_walk_private {\n\tstruct mmu_gather *tlb;\n\tbool pageout;\n};\n\nstruct vma_swap_readahead {\n\tshort unsigned int win;\n\tshort unsigned int offset;\n\tshort unsigned int nr_pte;\n\tpte_t *ptes;\n};\n\nenum {\n\tPERCPU_REF_INIT_ATOMIC = 1,\n\tPERCPU_REF_INIT_DEAD = 2,\n\tPERCPU_REF_ALLOW_REINIT = 4,\n};\n\nunion swap_header {\n\tstruct {\n\t\tchar reserved[4086];\n\t\tchar magic[10];\n\t} magic;\n\tstruct {\n\t\tchar bootbits[1024];\n\t\t__u32 version;\n\t\t__u32 last_page;\n\t\t__u32 nr_badpages;\n\t\tunsigned char sws_uuid[16];\n\t\tunsigned char sws_volume[16];\n\t\t__u32 padding[117];\n\t\t__u32 badpages[1];\n\t} info;\n};\n\nstruct swap_extent {\n\tstruct rb_node rb_node;\n\tlong unsigned int start_page;\n\tlong unsigned int nr_pages;\n\tsector_t start_block;\n};\n\nstruct swap_slots_cache {\n\tbool lock_initialized;\n\tstruct mutex alloc_lock;\n\tswp_entry_t *slots;\n\tint nr;\n\tint cur;\n\tspinlock_t free_lock;\n\tswp_entry_t *slots_ret;\n\tint n_ret;\n};\n\nstruct frontswap_ops {\n\tvoid (*init)(unsigned int);\n\tint (*store)(unsigned int, long unsigned int, struct page *);\n\tint (*load)(unsigned int, long unsigned int, struct page *);\n\tvoid (*invalidate_page)(unsigned int, long unsigned int);\n\tvoid (*invalidate_area)(unsigned int);\n\tstruct frontswap_ops *next;\n};\n\nstruct crypto_async_request;\n\ntypedef void (*crypto_completion_t)(struct crypto_async_request *, int);\n\nstruct crypto_async_request {\n\tstruct list_head list;\n\tcrypto_completion_t complete;\n\tvoid *data;\n\tstruct crypto_tfm *tfm;\n\tu32 flags;\n};\n\nstruct crypto_wait {\n\tstruct completion completion;\n\tint err;\n};\n\nstruct zpool;\n\nstruct zpool_ops {\n\tint (*evict)(struct zpool *, long unsigned int);\n};\n\nenum zpool_mapmode {\n\tZPOOL_MM_RW = 0,\n\tZPOOL_MM_RO = 1,\n\tZPOOL_MM_WO = 2,\n\tZPOOL_MM_DEFAULT = 0,\n};\n\nstruct acomp_req {\n\tstruct crypto_async_request base;\n\tstruct scatterlist *src;\n\tstruct scatterlist *dst;\n\tunsigned int slen;\n\tunsigned int dlen;\n\tu32 flags;\n\tvoid *__ctx[0];\n};\n\nstruct crypto_acomp {\n\tint (*compress)(struct acomp_req *);\n\tint (*decompress)(struct acomp_req *);\n\tvoid (*dst_free)(struct scatterlist *);\n\tunsigned int reqsize;\n\tstruct crypto_tfm base;\n};\n\nstruct crypto_acomp_ctx {\n\tstruct crypto_acomp *acomp;\n\tstruct acomp_req *req;\n\tstruct crypto_wait wait;\n\tu8 *dstmem;\n\tstruct mutex *mutex;\n};\n\nstruct zswap_pool {\n\tstruct zpool *zpool;\n\tstruct crypto_acomp_ctx *acomp_ctx;\n\tstruct kref kref;\n\tstruct list_head list;\n\tstruct work_struct release_work;\n\tstruct work_struct shrink_work;\n\tstruct hlist_node node;\n\tchar tfm_name[128];\n};\n\nstruct zswap_entry {\n\tstruct rb_node rbnode;\n\tlong unsigned int offset;\n\tint refcount;\n\tunsigned int length;\n\tstruct zswap_pool *pool;\n\tunion {\n\t\tlong unsigned int handle;\n\t\tlong unsigned int value;\n\t};\n};\n\nstruct zswap_header {\n\tswp_entry_t swpentry;\n};\n\nstruct zswap_tree {\n\tstruct rb_root rbroot;\n\tspinlock_t lock;\n};\n\nenum zswap_get_swap_ret {\n\tZSWAP_SWAPCACHE_NEW = 0,\n\tZSWAP_SWAPCACHE_EXIST = 1,\n\tZSWAP_SWAPCACHE_FAIL = 2,\n};\n\nstruct dma_pool {\n\tstruct list_head page_list;\n\tspinlock_t lock;\n\tsize_t size;\n\tstruct device *dev;\n\tsize_t allocation;\n\tsize_t boundary;\n\tchar name[32];\n\tstruct list_head pools;\n};\n\nstruct dma_page {\n\tstruct list_head page_list;\n\tvoid *vaddr;\n\tdma_addr_t dma;\n\tunsigned int in_use;\n\tunsigned int offset;\n};\n\nenum string_size_units {\n\tSTRING_UNITS_10 = 0,\n\tSTRING_UNITS_2 = 1,\n};\n\ntypedef void (*node_registration_func_t)(struct node___2 *);\n\nenum mcopy_atomic_mode {\n\tMCOPY_ATOMIC_NORMAL = 0,\n\tMCOPY_ATOMIC_ZEROPAGE = 1,\n\tMCOPY_ATOMIC_CONTINUE = 2,\n};\n\nenum {\n\tSUBPAGE_INDEX_SUBPOOL = 1,\n\tSUBPAGE_INDEX_CGROUP = 2,\n\tSUBPAGE_INDEX_CGROUP_RSVD = 3,\n\t__MAX_CGROUP_SUBPAGE_INDEX = 3,\n\t__NR_USED_SUBPAGE = 4,\n};\n\nstruct resv_map {\n\tstruct kref refs;\n\tspinlock_t lock;\n\tstruct list_head regions;\n\tlong int adds_in_progress;\n\tstruct list_head region_cache;\n\tlong int region_cache_count;\n\tstruct page_counter *reservation_counter;\n\tlong unsigned int pages_per_hpage;\n\tstruct cgroup_subsys_state *css;\n};\n\nstruct file_region {\n\tstruct list_head link;\n\tlong int from;\n\tlong int to;\n\tstruct page_counter *reservation_counter;\n\tstruct cgroup_subsys_state *css;\n};\n\nstruct huge_bootmem_page {\n\tstruct list_head list;\n\tstruct hstate *hstate;\n};\n\nenum hugetlb_memory_event {\n\tHUGETLB_MAX = 0,\n\tHUGETLB_NR_MEMORY_EVENTS = 1,\n};\n\nstruct hugetlb_cgroup {\n\tstruct cgroup_subsys_state css;\n\tstruct page_counter hugepage[2];\n\tstruct page_counter rsvd_hugepage[2];\n\tatomic_long_t events[2];\n\tatomic_long_t events_local[2];\n\tstruct cgroup_file events_file[2];\n\tstruct cgroup_file events_local_file[2];\n};\n\nenum vma_resv_mode {\n\tVMA_NEEDS_RESV = 0,\n\tVMA_COMMIT_RESV = 1,\n\tVMA_END_RESV = 2,\n\tVMA_ADD_RESV = 3,\n\tVMA_DEL_RESV = 4,\n};\n\nstruct node_hstate {\n\tstruct kobject *hugepages_kobj;\n\tstruct kobject *hstate_kobjs[2];\n};\n\nstruct nodemask_scratch {\n\tnodemask_t mask1;\n\tnodemask_t mask2;\n};\n\nstruct sp_node {\n\tstruct rb_node nd;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tstruct mempolicy *policy;\n};\n\nstruct mempolicy_operations {\n\tint (*create)(struct mempolicy *, const nodemask_t *);\n\tvoid (*rebind)(struct mempolicy *, const nodemask_t *);\n};\n\nstruct queue_pages {\n\tstruct list_head *pagelist;\n\tlong unsigned int flags;\n\tnodemask_t *nmask;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tstruct vm_area_struct *first;\n};\n\nstruct vmemmap_remap_walk {\n\tvoid (*remap_pte)(pte_t *, long unsigned int, struct vmemmap_remap_walk *);\n\tlong unsigned int nr_walked;\n\tstruct page *reuse_page;\n\tlong unsigned int reuse_addr;\n\tstruct list_head *vmemmap_pages;\n};\n\nstruct mmu_notifier_subscriptions {\n\tstruct hlist_head list;\n\tbool has_itree;\n\tspinlock_t lock;\n\tlong unsigned int invalidate_seq;\n\tlong unsigned int active_invalidate_ranges;\n\tstruct rb_root_cached itree;\n\twait_queue_head_t wq;\n\tstruct hlist_head deferred_list;\n};\n\nstruct interval_tree_node {\n\tstruct rb_node rb;\n\tlong unsigned int start;\n\tlong unsigned int last;\n\tlong unsigned int __subtree_last;\n};\n\nstruct mmu_interval_notifier;\n\nstruct mmu_interval_notifier_ops {\n\tbool (*invalidate)(struct mmu_interval_notifier *, const struct mmu_notifier_range *, long unsigned int);\n};\n\nstruct mmu_interval_notifier {\n\tstruct interval_tree_node interval_tree;\n\tconst struct mmu_interval_notifier_ops *ops;\n\tstruct mm_struct *mm;\n\tstruct hlist_node deferred_item;\n\tlong unsigned int invalidate_seq;\n};\n\nstruct rmap_item;\n\nstruct mm_slot {\n\tstruct hlist_node link;\n\tstruct list_head mm_list;\n\tstruct rmap_item *rmap_list;\n\tstruct mm_struct *mm;\n};\n\nstruct stable_node;\n\nstruct rmap_item {\n\tstruct rmap_item *rmap_list;\n\tunion {\n\t\tstruct anon_vma *anon_vma;\n\t\tint nid;\n\t};\n\tstruct mm_struct *mm;\n\tlong unsigned int address;\n\tunsigned int oldchecksum;\n\tunion {\n\t\tstruct rb_node node;\n\t\tstruct {\n\t\t\tstruct stable_node *head;\n\t\t\tstruct hlist_node hlist;\n\t\t};\n\t};\n};\n\nstruct ksm_scan {\n\tstruct mm_slot *mm_slot;\n\tlong unsigned int address;\n\tstruct rmap_item **rmap_list;\n\tlong unsigned int seqnr;\n};\n\nstruct stable_node {\n\tunion {\n\t\tstruct rb_node node;\n\t\tstruct {\n\t\t\tstruct list_head *head;\n\t\t\tstruct {\n\t\t\t\tstruct hlist_node hlist_dup;\n\t\t\t\tstruct list_head list;\n\t\t\t};\n\t\t};\n\t};\n\tstruct hlist_head hlist;\n\tunion {\n\t\tlong unsigned int kpfn;\n\t\tlong unsigned int chain_prune_time;\n\t};\n\tint rmap_hlist_len;\n\tint nid;\n};\n\nenum get_ksm_page_flags {\n\tGET_KSM_PAGE_NOLOCK = 0,\n\tGET_KSM_PAGE_LOCK = 1,\n\tGET_KSM_PAGE_TRYLOCK = 2,\n};\n\nenum stat_item {\n\tALLOC_FASTPATH = 0,\n\tALLOC_SLOWPATH = 1,\n\tFREE_FASTPATH = 2,\n\tFREE_SLOWPATH = 3,\n\tFREE_FROZEN = 4,\n\tFREE_ADD_PARTIAL = 5,\n\tFREE_REMOVE_PARTIAL = 6,\n\tALLOC_FROM_PARTIAL = 7,\n\tALLOC_SLAB = 8,\n\tALLOC_REFILL = 9,\n\tALLOC_NODE_MISMATCH = 10,\n\tFREE_SLAB = 11,\n\tCPUSLAB_FLUSH = 12,\n\tDEACTIVATE_FULL = 13,\n\tDEACTIVATE_EMPTY = 14,\n\tDEACTIVATE_TO_HEAD = 15,\n\tDEACTIVATE_TO_TAIL = 16,\n\tDEACTIVATE_REMOTE_FREES = 17,\n\tDEACTIVATE_BYPASS = 18,\n\tORDER_FALLBACK = 19,\n\tCMPXCHG_DOUBLE_CPU_FAIL = 20,\n\tCMPXCHG_DOUBLE_FAIL = 21,\n\tCPU_PARTIAL_ALLOC = 22,\n\tCPU_PARTIAL_FREE = 23,\n\tCPU_PARTIAL_NODE = 24,\n\tCPU_PARTIAL_DRAIN = 25,\n\tNR_SLUB_STAT_ITEMS = 26,\n};\n\nstruct track {\n\tlong unsigned int addr;\n\tlong unsigned int addrs[16];\n\tint cpu;\n\tint pid;\n\tlong unsigned int when;\n};\n\nenum track_item {\n\tTRACK_ALLOC = 0,\n\tTRACK_FREE = 1,\n};\n\nstruct detached_freelist {\n\tstruct page *page;\n\tvoid *tail;\n\tvoid *freelist;\n\tint cnt;\n\tstruct kmem_cache *s;\n};\n\nstruct location {\n\tlong unsigned int count;\n\tlong unsigned int addr;\n\tlong long int sum_time;\n\tlong int min_time;\n\tlong int max_time;\n\tlong int min_pid;\n\tlong int max_pid;\n\tlong unsigned int cpus[5];\n\tnodemask_t nodes;\n};\n\nstruct loc_track {\n\tlong unsigned int max;\n\tlong unsigned int count;\n\tstruct location *loc;\n};\n\nenum slab_stat_type {\n\tSL_ALL = 0,\n\tSL_PARTIAL = 1,\n\tSL_CPU = 2,\n\tSL_OBJECTS = 3,\n\tSL_TOTAL = 4,\n};\n\nstruct slab_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct kmem_cache *, char *);\n\tssize_t (*store)(struct kmem_cache *, const char *, size_t);\n};\n\nstruct saved_alias {\n\tstruct kmem_cache *s;\n\tconst char *name;\n\tstruct saved_alias *next;\n};\n\nenum slab_modes {\n\tM_NONE = 0,\n\tM_PARTIAL = 1,\n\tM_FULL = 2,\n\tM_FREE = 3,\n};\n\nstruct kcsan_scoped_access {};\n\nenum kfence_object_state {\n\tKFENCE_OBJECT_UNUSED = 0,\n\tKFENCE_OBJECT_ALLOCATED = 1,\n\tKFENCE_OBJECT_FREED = 2,\n};\n\nstruct kfence_track {\n\tpid_t pid;\n\tint num_stack_entries;\n\tlong unsigned int stack_entries[64];\n};\n\nstruct kfence_metadata {\n\tstruct list_head list;\n\tstruct callback_head callback_head;\n\traw_spinlock_t lock;\n\tenum kfence_object_state state;\n\tlong unsigned int addr;\n\tsize_t size;\n\tstruct kmem_cache *cache;\n\tlong unsigned int unprotected_page;\n\tstruct kfence_track alloc_track;\n\tstruct kfence_track free_track;\n};\n\nenum kfence_error_type {\n\tKFENCE_ERROR_OOB = 0,\n\tKFENCE_ERROR_UAF = 1,\n\tKFENCE_ERROR_CORRUPTION = 2,\n\tKFENCE_ERROR_INVALID = 3,\n\tKFENCE_ERROR_INVALID_FREE = 4,\n};\n\nenum kfence_counter_id {\n\tKFENCE_COUNTER_ALLOCATED = 0,\n\tKFENCE_COUNTER_ALLOCS = 1,\n\tKFENCE_COUNTER_FREES = 2,\n\tKFENCE_COUNTER_ZOMBIES = 3,\n\tKFENCE_COUNTER_BUGS = 4,\n\tKFENCE_COUNTER_COUNT = 5,\n};\n\ntypedef __kernel_long_t __kernel_ptrdiff_t;\n\ntypedef __kernel_ptrdiff_t ptrdiff_t;\n\nstruct buffer_head;\n\ntypedef void bh_end_io_t(struct buffer_head *, int);\n\nstruct buffer_head {\n\tlong unsigned int b_state;\n\tstruct buffer_head *b_this_page;\n\tstruct page *b_page;\n\tsector_t b_blocknr;\n\tsize_t b_size;\n\tchar *b_data;\n\tstruct block_device *b_bdev;\n\tbh_end_io_t *b_end_io;\n\tvoid *b_private;\n\tstruct list_head b_assoc_buffers;\n\tstruct address_space *b_assoc_map;\n\tatomic_t b_count;\n\tspinlock_t b_uptodate_lock;\n};\n\nenum migrate_vma_direction {\n\tMIGRATE_VMA_SELECT_SYSTEM = 1,\n\tMIGRATE_VMA_SELECT_DEVICE_PRIVATE = 2,\n};\n\nstruct migrate_vma {\n\tstruct vm_area_struct *vma;\n\tlong unsigned int *dst;\n\tlong unsigned int *src;\n\tlong unsigned int cpages;\n\tlong unsigned int npages;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tvoid *pgmap_owner;\n\tlong unsigned int flags;\n};\n\nenum bh_state_bits {\n\tBH_Uptodate = 0,\n\tBH_Dirty = 1,\n\tBH_Lock = 2,\n\tBH_Req = 3,\n\tBH_Mapped = 4,\n\tBH_New = 5,\n\tBH_Async_Read = 6,\n\tBH_Async_Write = 7,\n\tBH_Delay = 8,\n\tBH_Boundary = 9,\n\tBH_Write_EIO = 10,\n\tBH_Unwritten = 11,\n\tBH_Quiet = 12,\n\tBH_Meta = 13,\n\tBH_Prio = 14,\n\tBH_Defer_Completion = 15,\n\tBH_PrivateStart = 16,\n};\n\nstruct trace_event_raw_mm_migrate_pages {\n\tstruct trace_entry ent;\n\tlong unsigned int succeeded;\n\tlong unsigned int failed;\n\tlong unsigned int thp_succeeded;\n\tlong unsigned int thp_failed;\n\tlong unsigned int thp_split;\n\tenum migrate_mode mode;\n\tint reason;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_migrate_pages_start {\n\tstruct trace_entry ent;\n\tenum migrate_mode mode;\n\tint reason;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mm_migrate_pages {};\n\nstruct trace_event_data_offsets_mm_migrate_pages_start {};\n\ntypedef void (*btf_trace_mm_migrate_pages)(void *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, enum migrate_mode, int);\n\ntypedef void (*btf_trace_mm_migrate_pages_start)(void *, enum migrate_mode, int);\n\nenum scan_result {\n\tSCAN_FAIL = 0,\n\tSCAN_SUCCEED = 1,\n\tSCAN_PMD_NULL = 2,\n\tSCAN_EXCEED_NONE_PTE = 3,\n\tSCAN_EXCEED_SWAP_PTE = 4,\n\tSCAN_EXCEED_SHARED_PTE = 5,\n\tSCAN_PTE_NON_PRESENT = 6,\n\tSCAN_PTE_UFFD_WP = 7,\n\tSCAN_PAGE_RO = 8,\n\tSCAN_LACK_REFERENCED_PAGE = 9,\n\tSCAN_PAGE_NULL = 10,\n\tSCAN_SCAN_ABORT = 11,\n\tSCAN_PAGE_COUNT = 12,\n\tSCAN_PAGE_LRU = 13,\n\tSCAN_PAGE_LOCK = 14,\n\tSCAN_PAGE_ANON = 15,\n\tSCAN_PAGE_COMPOUND = 16,\n\tSCAN_ANY_PROCESS = 17,\n\tSCAN_VMA_NULL = 18,\n\tSCAN_VMA_CHECK = 19,\n\tSCAN_ADDRESS_RANGE = 20,\n\tSCAN_SWAP_CACHE_PAGE = 21,\n\tSCAN_DEL_PAGE_LRU = 22,\n\tSCAN_ALLOC_HUGE_PAGE_FAIL = 23,\n\tSCAN_CGROUP_CHARGE_FAIL = 24,\n\tSCAN_TRUNCATED = 25,\n\tSCAN_PAGE_HAS_PRIVATE = 26,\n};\n\nstruct trace_event_raw_mm_khugepaged_scan_pmd {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tlong unsigned int pfn;\n\tbool writable;\n\tint referenced;\n\tint none_or_zero;\n\tint status;\n\tint unmapped;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_collapse_huge_page {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tint isolated;\n\tint status;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_collapse_huge_page_isolate {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tint none_or_zero;\n\tint referenced;\n\tbool writable;\n\tint status;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mm_collapse_huge_page_swapin {\n\tstruct trace_entry ent;\n\tstruct mm_struct *mm;\n\tint swapped_in;\n\tint referenced;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mm_khugepaged_scan_pmd {};\n\nstruct trace_event_data_offsets_mm_collapse_huge_page {};\n\nstruct trace_event_data_offsets_mm_collapse_huge_page_isolate {};\n\nstruct trace_event_data_offsets_mm_collapse_huge_page_swapin {};\n\ntypedef void (*btf_trace_mm_khugepaged_scan_pmd)(void *, struct mm_struct *, struct page *, bool, int, int, int, int);\n\ntypedef void (*btf_trace_mm_collapse_huge_page)(void *, struct mm_struct *, int, int);\n\ntypedef void (*btf_trace_mm_collapse_huge_page_isolate)(void *, struct page *, int, int, bool, int);\n\ntypedef void (*btf_trace_mm_collapse_huge_page_swapin)(void *, struct mm_struct *, int, int, int);\n\nstruct mm_slot___2 {\n\tstruct hlist_node hash;\n\tstruct list_head mm_node;\n\tstruct mm_struct *mm;\n\tint nr_pte_mapped_thp;\n\tlong unsigned int pte_mapped_thp[8];\n};\n\nstruct khugepaged_scan {\n\tstruct list_head mm_head;\n\tstruct mm_slot___2 *mm_slot;\n\tlong unsigned int address;\n};\n\nstruct mem_cgroup_tree_per_node {\n\tstruct rb_root rb_root;\n\tstruct rb_node *rb_rightmost;\n\tspinlock_t lock;\n};\n\nstruct mem_cgroup_tree {\n\tstruct mem_cgroup_tree_per_node *rb_tree_per_node[32];\n};\n\nstruct mem_cgroup_eventfd_list {\n\tstruct list_head list;\n\tstruct eventfd_ctx *eventfd;\n};\n\nstruct mem_cgroup_event {\n\tstruct mem_cgroup *memcg;\n\tstruct eventfd_ctx *eventfd;\n\tstruct list_head list;\n\tint (*register_event)(struct mem_cgroup *, struct eventfd_ctx *, const char *);\n\tvoid (*unregister_event)(struct mem_cgroup *, struct eventfd_ctx *);\n\tpoll_table pt;\n\twait_queue_head_t *wqh;\n\twait_queue_entry_t wait;\n\tstruct work_struct remove;\n};\n\nstruct move_charge_struct {\n\tspinlock_t lock;\n\tstruct mm_struct *mm;\n\tstruct mem_cgroup *from;\n\tstruct mem_cgroup *to;\n\tlong unsigned int flags;\n\tlong unsigned int precharge;\n\tlong unsigned int moved_charge;\n\tlong unsigned int moved_swap;\n\tstruct task_struct *moving_task;\n\twait_queue_head_t waitq;\n};\n\nenum res_type {\n\t_MEM = 0,\n\t_MEMSWAP = 1,\n\t_OOM_TYPE = 2,\n\t_KMEM = 3,\n\t_TCP = 4,\n};\n\nstruct memory_stat {\n\tconst char *name;\n\tunsigned int idx;\n};\n\nstruct oom_wait_info {\n\tstruct mem_cgroup *memcg;\n\twait_queue_entry_t wait;\n};\n\nenum oom_status {\n\tOOM_SUCCESS = 0,\n\tOOM_FAILED = 1,\n\tOOM_ASYNC = 2,\n\tOOM_SKIPPED = 3,\n};\n\nstruct obj_stock {\n\tstruct obj_cgroup *cached_objcg;\n\tstruct pglist_data *cached_pgdat;\n\tunsigned int nr_bytes;\n\tint nr_slab_reclaimable_b;\n\tint nr_slab_unreclaimable_b;\n};\n\nstruct memcg_stock_pcp {\n\tstruct mem_cgroup *cached;\n\tunsigned int nr_pages;\n\tstruct obj_stock task_obj;\n\tstruct obj_stock irq_obj;\n\tstruct work_struct work;\n\tlong unsigned int flags;\n};\n\nenum {\n\tRES_USAGE = 0,\n\tRES_LIMIT = 1,\n\tRES_MAX_USAGE = 2,\n\tRES_FAILCNT = 3,\n\tRES_SOFT_LIMIT = 4,\n};\n\nunion mc_target {\n\tstruct page *page;\n\tswp_entry_t ent;\n};\n\nenum mc_target_type {\n\tMC_TARGET_NONE = 0,\n\tMC_TARGET_PAGE = 1,\n\tMC_TARGET_SWAP = 2,\n\tMC_TARGET_DEVICE = 3,\n};\n\nstruct uncharge_gather {\n\tstruct mem_cgroup *memcg;\n\tlong unsigned int nr_memory;\n\tlong unsigned int pgpgout;\n\tlong unsigned int nr_kmem;\n\tstruct page *dummy_page;\n};\n\nstruct numa_stat {\n\tconst char *name;\n\tunsigned int lru_mask;\n};\n\nenum vmpressure_levels {\n\tVMPRESSURE_LOW = 0,\n\tVMPRESSURE_MEDIUM = 1,\n\tVMPRESSURE_CRITICAL = 2,\n\tVMPRESSURE_NUM_LEVELS = 3,\n};\n\nenum vmpressure_modes {\n\tVMPRESSURE_NO_PASSTHROUGH = 0,\n\tVMPRESSURE_HIERARCHY = 1,\n\tVMPRESSURE_LOCAL = 2,\n\tVMPRESSURE_NUM_MODES = 3,\n};\n\nstruct vmpressure_event {\n\tstruct eventfd_ctx *efd;\n\tenum vmpressure_levels level;\n\tenum vmpressure_modes mode;\n\tstruct list_head node;\n};\n\nstruct swap_cgroup_ctrl {\n\tstruct page **map;\n\tlong unsigned int length;\n\tspinlock_t lock;\n};\n\nstruct swap_cgroup {\n\tshort unsigned int id;\n};\n\nenum {\n\tRES_USAGE___2 = 0,\n\tRES_RSVD_USAGE = 1,\n\tRES_LIMIT___2 = 2,\n\tRES_RSVD_LIMIT = 3,\n\tRES_MAX_USAGE___2 = 4,\n\tRES_RSVD_MAX_USAGE = 5,\n\tRES_FAILCNT___2 = 6,\n\tRES_RSVD_FAILCNT = 7,\n};\n\nenum mf_result {\n\tMF_IGNORED = 0,\n\tMF_FAILED = 1,\n\tMF_DELAYED = 2,\n\tMF_RECOVERED = 3,\n};\n\nenum mf_action_page_type {\n\tMF_MSG_KERNEL = 0,\n\tMF_MSG_KERNEL_HIGH_ORDER = 1,\n\tMF_MSG_SLAB = 2,\n\tMF_MSG_DIFFERENT_COMPOUND = 3,\n\tMF_MSG_POISONED_HUGE = 4,\n\tMF_MSG_HUGE = 5,\n\tMF_MSG_FREE_HUGE = 6,\n\tMF_MSG_NON_PMD_HUGE = 7,\n\tMF_MSG_UNMAP_FAILED = 8,\n\tMF_MSG_DIRTY_SWAPCACHE = 9,\n\tMF_MSG_CLEAN_SWAPCACHE = 10,\n\tMF_MSG_DIRTY_MLOCKED_LRU = 11,\n\tMF_MSG_CLEAN_MLOCKED_LRU = 12,\n\tMF_MSG_DIRTY_UNEVICTABLE_LRU = 13,\n\tMF_MSG_CLEAN_UNEVICTABLE_LRU = 14,\n\tMF_MSG_DIRTY_LRU = 15,\n\tMF_MSG_CLEAN_LRU = 16,\n\tMF_MSG_TRUNCATED_LRU = 17,\n\tMF_MSG_BUDDY = 18,\n\tMF_MSG_BUDDY_2ND = 19,\n\tMF_MSG_DAX = 20,\n\tMF_MSG_UNSPLIT_THP = 21,\n\tMF_MSG_UNKNOWN = 22,\n};\n\ntypedef long unsigned int dax_entry_t;\n\nstruct __kfifo {\n\tunsigned int in;\n\tunsigned int out;\n\tunsigned int mask;\n\tunsigned int esize;\n\tvoid *data;\n};\n\nstruct to_kill {\n\tstruct list_head nd;\n\tstruct task_struct *tsk;\n\tlong unsigned int addr;\n\tshort int size_shift;\n};\n\nstruct hwp_walk {\n\tstruct to_kill tk;\n\tlong unsigned int pfn;\n\tint flags;\n};\n\nstruct page_state {\n\tlong unsigned int mask;\n\tlong unsigned int res;\n\tenum mf_action_page_type type;\n\tint (*action)(struct page *, long unsigned int);\n};\n\nstruct memory_failure_entry {\n\tlong unsigned int pfn;\n\tint flags;\n};\n\nstruct memory_failure_cpu {\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tstruct memory_failure_entry *type;\n\t\t\tconst struct memory_failure_entry *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tstruct memory_failure_entry *ptr;\n\t\t\tconst struct memory_failure_entry *ptr_const;\n\t\t};\n\t\tstruct memory_failure_entry buf[16];\n\t} fifo;\n\tspinlock_t lock;\n\tstruct work_struct work;\n};\n\nstruct cleancache_filekey {\n\tunion {\n\t\tino_t ino;\n\t\t__u32 fh[6];\n\t\tu32 key[6];\n\t} u;\n};\n\nstruct cleancache_ops {\n\tint (*init_fs)(size_t);\n\tint (*init_shared_fs)(uuid_t *, size_t);\n\tint (*get_page)(int, struct cleancache_filekey, long unsigned int, struct page *);\n\tvoid (*put_page)(int, struct cleancache_filekey, long unsigned int, struct page *);\n\tvoid (*invalidate_page)(int, struct cleancache_filekey, long unsigned int);\n\tvoid (*invalidate_inode)(int, struct cleancache_filekey);\n\tvoid (*invalidate_fs)(int);\n};\n\nstruct trace_event_raw_test_pages_isolated {\n\tstruct trace_entry ent;\n\tlong unsigned int start_pfn;\n\tlong unsigned int end_pfn;\n\tlong unsigned int fin_pfn;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_test_pages_isolated {};\n\ntypedef void (*btf_trace_test_pages_isolated)(void *, long unsigned int, long unsigned int, long unsigned int);\n\nstruct zpool_driver;\n\nstruct zpool {\n\tstruct zpool_driver *driver;\n\tvoid *pool;\n\tconst struct zpool_ops *ops;\n\tbool evictable;\n\tbool can_sleep_mapped;\n\tstruct list_head list;\n};\n\nstruct zpool_driver {\n\tchar *type;\n\tstruct module *owner;\n\tatomic_t refcount;\n\tstruct list_head list;\n\tvoid * (*create)(const char *, gfp_t, const struct zpool_ops *, struct zpool *);\n\tvoid (*destroy)(void *);\n\tbool malloc_support_movable;\n\tint (*malloc)(void *, size_t, gfp_t, long unsigned int *);\n\tvoid (*free)(void *, long unsigned int);\n\tint (*shrink)(void *, unsigned int, unsigned int *);\n\tbool sleep_mapped;\n\tvoid * (*map)(void *, long unsigned int, enum zpool_mapmode);\n\tvoid (*unmap)(void *, long unsigned int);\n\tu64 (*total_size)(void *);\n};\n\nstruct zbud_pool;\n\nstruct zbud_ops {\n\tint (*evict)(struct zbud_pool *, long unsigned int);\n};\n\nstruct zbud_pool {\n\tspinlock_t lock;\n\tunion {\n\t\tstruct list_head buddied;\n\t\tstruct list_head unbuddied[63];\n\t};\n\tstruct list_head lru;\n\tu64 pages_nr;\n\tconst struct zbud_ops *ops;\n\tstruct zpool *zpool;\n\tconst struct zpool_ops *zpool_ops;\n};\n\nstruct zbud_header {\n\tstruct list_head buddy;\n\tstruct list_head lru;\n\tunsigned int first_chunks;\n\tunsigned int last_chunks;\n\tbool under_reclaim;\n};\n\nenum buddy {\n\tFIRST = 0,\n\tLAST = 1,\n};\n\nenum zs_mapmode {\n\tZS_MM_RW = 0,\n\tZS_MM_RO = 1,\n\tZS_MM_WO = 2,\n};\n\nstruct zs_pool_stats {\n\tatomic_long_t pages_compacted;\n};\n\nenum fullness_group {\n\tZS_EMPTY = 0,\n\tZS_ALMOST_EMPTY = 1,\n\tZS_ALMOST_FULL = 2,\n\tZS_FULL = 3,\n\tNR_ZS_FULLNESS = 4,\n};\n\nenum zs_stat_type {\n\tCLASS_EMPTY = 0,\n\tCLASS_ALMOST_EMPTY = 1,\n\tCLASS_ALMOST_FULL = 2,\n\tCLASS_FULL = 3,\n\tOBJ_ALLOCATED = 4,\n\tOBJ_USED = 5,\n\tNR_ZS_STAT_TYPE = 6,\n};\n\nstruct zs_size_stat {\n\tlong unsigned int objs[6];\n};\n\nstruct size_class {\n\tspinlock_t lock;\n\tstruct list_head fullness_list[4];\n\tint size;\n\tint objs_per_zspage;\n\tint pages_per_zspage;\n\tunsigned int index;\n\tstruct zs_size_stat stats;\n};\n\nstruct link_free {\n\tunion {\n\t\tlong unsigned int next;\n\t\tlong unsigned int handle;\n\t};\n};\n\nstruct zs_pool {\n\tconst char *name;\n\tstruct size_class *size_class[255];\n\tstruct kmem_cache *handle_cachep;\n\tstruct kmem_cache *zspage_cachep;\n\tatomic_long_t pages_allocated;\n\tstruct zs_pool_stats stats;\n\tstruct shrinker shrinker;\n\tstruct inode *inode;\n\tstruct work_struct free_work;\n\tstruct wait_queue_head migration_wait;\n\tatomic_long_t isolated_pages;\n\tbool destroying;\n};\n\nstruct zspage {\n\tstruct {\n\t\tunsigned int fullness: 2;\n\t\tunsigned int class: 9;\n\t\tunsigned int isolated: 3;\n\t\tunsigned int magic: 8;\n\t};\n\tunsigned int inuse;\n\tunsigned int freeobj;\n\tstruct page *first_page;\n\tstruct list_head list;\n\trwlock_t lock;\n};\n\nstruct mapping_area {\n\tchar *vm_buf;\n\tchar *vm_addr;\n\tenum zs_mapmode vm_mm;\n};\n\nstruct zs_compact_control {\n\tstruct page *s_page;\n\tstruct page *d_page;\n\tint obj_idx;\n};\n\nstruct z3fold_pool;\n\nstruct z3fold_ops {\n\tint (*evict)(struct z3fold_pool *, long unsigned int);\n};\n\nstruct z3fold_pool {\n\tconst char *name;\n\tspinlock_t lock;\n\tspinlock_t stale_lock;\n\tstruct list_head *unbuddied;\n\tstruct list_head lru;\n\tstruct list_head stale;\n\tatomic64_t pages_nr;\n\tstruct kmem_cache *c_handle;\n\tconst struct z3fold_ops *ops;\n\tstruct zpool *zpool;\n\tconst struct zpool_ops *zpool_ops;\n\tstruct workqueue_struct *compact_wq;\n\tstruct workqueue_struct *release_wq;\n\tstruct work_struct work;\n\tstruct inode *inode;\n};\n\nenum buddy___2 {\n\tHEADLESS = 0,\n\tFIRST___2 = 1,\n\tMIDDLE = 2,\n\tLAST___2 = 3,\n\tBUDDIES_MAX = 3,\n};\n\nstruct z3fold_buddy_slots {\n\tlong unsigned int slot[4];\n\tlong unsigned int pool;\n\trwlock_t lock;\n};\n\nstruct z3fold_header {\n\tstruct list_head buddy;\n\tspinlock_t page_lock;\n\tstruct kref refcount;\n\tstruct work_struct work;\n\tstruct z3fold_buddy_slots *slots;\n\tstruct z3fold_pool *pool;\n\tshort int cpu;\n\tshort unsigned int first_chunks;\n\tshort unsigned int middle_chunks;\n\tshort unsigned int last_chunks;\n\tshort unsigned int start_middle;\n\tshort unsigned int first_num: 2;\n\tshort unsigned int mapped_count: 2;\n\tshort unsigned int foreign_handles: 2;\n};\n\nenum z3fold_page_flags {\n\tPAGE_HEADLESS = 0,\n\tMIDDLE_CHUNK_MAPPED = 1,\n\tNEEDS_COMPACTING = 2,\n\tPAGE_STALE = 3,\n\tPAGE_CLAIMED = 4,\n};\n\nenum z3fold_handle_flags {\n\tHANDLES_NOFREE = 0,\n};\n\nstruct trace_event_raw_cma_alloc_class {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tlong unsigned int pfn;\n\tconst struct page *page;\n\tlong unsigned int count;\n\tunsigned int align;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cma_release {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tlong unsigned int pfn;\n\tconst struct page *page;\n\tlong unsigned int count;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cma_alloc_start {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tlong unsigned int count;\n\tunsigned int align;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_cma_alloc_class {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_cma_release {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_cma_alloc_start {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_cma_release)(void *, const char *, long unsigned int, const struct page *, long unsigned int);\n\ntypedef void (*btf_trace_cma_alloc_start)(void *, const char *, long unsigned int, unsigned int);\n\ntypedef void (*btf_trace_cma_alloc_finish)(void *, const char *, long unsigned int, const struct page *, long unsigned int, unsigned int);\n\ntypedef void (*btf_trace_cma_alloc_busy_retry)(void *, const char *, long unsigned int, const struct page *, long unsigned int, unsigned int);\n\nstruct cma_kobject {\n\tstruct kobject kobj;\n\tstruct cma *cma;\n};\n\nstruct balloon_dev_info {\n\tlong unsigned int isolated_pages;\n\tspinlock_t pages_lock;\n\tstruct list_head pages;\n\tint (*migratepage)(struct balloon_dev_info *, struct page *, struct page *, enum migrate_mode);\n\tstruct inode *inode;\n};\n\nstruct cma_mem {\n\tstruct hlist_node node;\n\tstruct page *p;\n\tlong unsigned int n;\n};\n\nenum {\n\tBAD_STACK = 4294967295,\n\tNOT_STACK = 0,\n\tGOOD_FRAME = 1,\n\tGOOD_STACK = 2,\n};\n\nenum hmm_pfn_flags {\n\tHMM_PFN_VALID = 0,\n\tHMM_PFN_WRITE = 0,\n\tHMM_PFN_ERROR = 0,\n\tHMM_PFN_ORDER_SHIFT = 56,\n\tHMM_PFN_REQ_FAULT = 0,\n\tHMM_PFN_REQ_WRITE = 0,\n\tHMM_PFN_FLAGS = 0,\n};\n\nstruct hmm_range {\n\tstruct mmu_interval_notifier *notifier;\n\tlong unsigned int notifier_seq;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tlong unsigned int *hmm_pfns;\n\tlong unsigned int default_flags;\n\tlong unsigned int pfn_flags_mask;\n\tvoid *dev_private_owner;\n};\n\nstruct hmm_vma_walk {\n\tstruct hmm_range *range;\n\tlong unsigned int last;\n};\n\nenum {\n\tHMM_NEED_FAULT = 1,\n\tHMM_NEED_WRITE_FAULT = 2,\n\tHMM_NEED_ALL_BITS = 3,\n};\n\nstruct hugetlbfs_inode_info {\n\tstruct shared_policy policy;\n\tstruct inode vfs_inode;\n\tunsigned int seals;\n};\n\nstruct wp_walk {\n\tstruct mmu_notifier_range range;\n\tlong unsigned int tlbflush_start;\n\tlong unsigned int tlbflush_end;\n\tlong unsigned int total;\n};\n\nstruct clean_walk {\n\tstruct wp_walk base;\n\tlong unsigned int bitmap_pgoff;\n\tlong unsigned int *bitmap;\n\tlong unsigned int start;\n\tlong unsigned int end;\n};\n\nstruct page_reporting_dev_info {\n\tint (*report)(struct page_reporting_dev_info *, struct scatterlist *, unsigned int);\n\tstruct delayed_work work;\n\tatomic_t state;\n\tunsigned int order;\n};\n\nenum {\n\tPAGE_REPORTING_IDLE = 0,\n\tPAGE_REPORTING_REQUESTED = 1,\n\tPAGE_REPORTING_ACTIVE = 2,\n};\n\nstruct open_how {\n\t__u64 flags;\n\t__u64 mode;\n\t__u64 resolve;\n};\n\ntypedef s32 compat_off_t;\n\nstruct open_flags {\n\tint open_flag;\n\tumode_t mode;\n\tint acc_mode;\n\tint intent;\n\tint lookup_flags;\n};\n\ntypedef __kernel_long_t __kernel_off_t;\n\ntypedef __kernel_off_t off_t;\n\ntypedef __kernel_rwf_t rwf_t;\n\nstruct fscrypt_policy_v1 {\n\t__u8 version;\n\t__u8 contents_encryption_mode;\n\t__u8 filenames_encryption_mode;\n\t__u8 flags;\n\t__u8 master_key_descriptor[8];\n};\n\nstruct fscrypt_policy_v2 {\n\t__u8 version;\n\t__u8 contents_encryption_mode;\n\t__u8 filenames_encryption_mode;\n\t__u8 flags;\n\t__u8 __reserved[4];\n\t__u8 master_key_identifier[16];\n};\n\nunion fscrypt_policy {\n\tu8 version;\n\tstruct fscrypt_policy_v1 v1;\n\tstruct fscrypt_policy_v2 v2;\n};\n\nenum vfs_get_super_keying {\n\tvfs_get_single_super = 0,\n\tvfs_get_single_reconf_super = 1,\n\tvfs_get_keyed_super = 2,\n\tvfs_get_independent_super = 3,\n};\n\ntypedef struct kobject *kobj_probe_t(dev_t, int *, void *);\n\nstruct kobj_map;\n\nstruct char_device_struct {\n\tstruct char_device_struct *next;\n\tunsigned int major;\n\tunsigned int baseminor;\n\tint minorct;\n\tchar name[64];\n\tstruct cdev *cdev;\n};\n\nstruct stat {\n\t__kernel_ulong_t st_dev;\n\t__kernel_ulong_t st_ino;\n\t__kernel_ulong_t st_nlink;\n\tunsigned int st_mode;\n\tunsigned int st_uid;\n\tunsigned int st_gid;\n\tunsigned int __pad0;\n\t__kernel_ulong_t st_rdev;\n\t__kernel_long_t st_size;\n\t__kernel_long_t st_blksize;\n\t__kernel_long_t st_blocks;\n\t__kernel_ulong_t st_atime;\n\t__kernel_ulong_t st_atime_nsec;\n\t__kernel_ulong_t st_mtime;\n\t__kernel_ulong_t st_mtime_nsec;\n\t__kernel_ulong_t st_ctime;\n\t__kernel_ulong_t st_ctime_nsec;\n\t__kernel_long_t __unused[3];\n};\n\nstruct __old_kernel_stat {\n\tshort unsigned int st_dev;\n\tshort unsigned int st_ino;\n\tshort unsigned int st_mode;\n\tshort unsigned int st_nlink;\n\tshort unsigned int st_uid;\n\tshort unsigned int st_gid;\n\tshort unsigned int st_rdev;\n\tunsigned int st_size;\n\tunsigned int st_atime;\n\tunsigned int st_mtime;\n\tunsigned int st_ctime;\n};\n\nstruct statx_timestamp {\n\t__s64 tv_sec;\n\t__u32 tv_nsec;\n\t__s32 __reserved;\n};\n\nstruct statx {\n\t__u32 stx_mask;\n\t__u32 stx_blksize;\n\t__u64 stx_attributes;\n\t__u32 stx_nlink;\n\t__u32 stx_uid;\n\t__u32 stx_gid;\n\t__u16 stx_mode;\n\t__u16 __spare0[1];\n\t__u64 stx_ino;\n\t__u64 stx_size;\n\t__u64 stx_blocks;\n\t__u64 stx_attributes_mask;\n\tstruct statx_timestamp stx_atime;\n\tstruct statx_timestamp stx_btime;\n\tstruct statx_timestamp stx_ctime;\n\tstruct statx_timestamp stx_mtime;\n\t__u32 stx_rdev_major;\n\t__u32 stx_rdev_minor;\n\t__u32 stx_dev_major;\n\t__u32 stx_dev_minor;\n\t__u64 stx_mnt_id;\n\t__u64 __spare2;\n\t__u64 __spare3[12];\n};\n\nstruct mount;\n\nstruct mnt_namespace {\n\tstruct ns_common ns;\n\tstruct mount *root;\n\tstruct list_head list;\n\tspinlock_t ns_lock;\n\tstruct user_namespace *user_ns;\n\tstruct ucounts *ucounts;\n\tu64 seq;\n\twait_queue_head_t poll;\n\tu64 event;\n\tunsigned int mounts;\n\tunsigned int pending_mounts;\n};\n\ntypedef u32 compat_ino_t;\n\ntypedef u16 __compat_uid_t;\n\ntypedef u16 __compat_gid_t;\n\ntypedef u16 compat_mode_t;\n\ntypedef u16 compat_dev_t;\n\ntypedef u16 compat_nlink_t;\n\nstruct compat_stat {\n\tcompat_dev_t st_dev;\n\tu16 __pad1;\n\tcompat_ino_t st_ino;\n\tcompat_mode_t st_mode;\n\tcompat_nlink_t st_nlink;\n\t__compat_uid_t st_uid;\n\t__compat_gid_t st_gid;\n\tcompat_dev_t st_rdev;\n\tu16 __pad2;\n\tu32 st_size;\n\tu32 st_blksize;\n\tu32 st_blocks;\n\tu32 st_atime;\n\tu32 st_atime_nsec;\n\tu32 st_mtime;\n\tu32 st_mtime_nsec;\n\tu32 st_ctime;\n\tu32 st_ctime_nsec;\n\tu32 __unused4;\n\tu32 __unused5;\n};\n\nstruct mnt_pcp;\n\nstruct mountpoint;\n\nstruct mount {\n\tstruct hlist_node mnt_hash;\n\tstruct mount *mnt_parent;\n\tstruct dentry *mnt_mountpoint;\n\tstruct vfsmount mnt;\n\tunion {\n\t\tstruct callback_head mnt_rcu;\n\t\tstruct llist_node mnt_llist;\n\t};\n\tstruct mnt_pcp *mnt_pcp;\n\tstruct list_head mnt_mounts;\n\tstruct list_head mnt_child;\n\tstruct list_head mnt_instance;\n\tconst char *mnt_devname;\n\tstruct list_head mnt_list;\n\tstruct list_head mnt_expire;\n\tstruct list_head mnt_share;\n\tstruct list_head mnt_slave_list;\n\tstruct list_head mnt_slave;\n\tstruct mount *mnt_master;\n\tstruct mnt_namespace *mnt_ns;\n\tstruct mountpoint *mnt_mp;\n\tunion {\n\t\tstruct hlist_node mnt_mp_list;\n\t\tstruct hlist_node mnt_umount;\n\t};\n\tstruct list_head mnt_umounting;\n\tstruct fsnotify_mark_connector *mnt_fsnotify_marks;\n\t__u32 mnt_fsnotify_mask;\n\tint mnt_id;\n\tint mnt_group_id;\n\tint mnt_expiry_mark;\n\tstruct hlist_head mnt_pins;\n\tstruct hlist_head mnt_stuck_children;\n};\n\nstruct mnt_pcp {\n\tint mnt_count;\n\tint mnt_writers;\n};\n\nstruct mountpoint {\n\tstruct hlist_node m_hash;\n\tstruct dentry *m_dentry;\n\tstruct hlist_head m_list;\n\tint m_count;\n};\n\ntypedef short unsigned int ushort;\n\nstruct user_arg_ptr {\n\tbool is_compat;\n\tunion {\n\t\tconst char * const *native;\n\t\tconst compat_uptr_t *compat;\n\t} ptr;\n};\n\nenum inode_i_mutex_lock_class {\n\tI_MUTEX_NORMAL = 0,\n\tI_MUTEX_PARENT = 1,\n\tI_MUTEX_CHILD = 2,\n\tI_MUTEX_XATTR = 3,\n\tI_MUTEX_NONDIR2 = 4,\n\tI_MUTEX_PARENT2 = 5,\n};\n\nstruct name_snapshot {\n\tstruct qstr name;\n\tunsigned char inline_name[32];\n};\n\nstruct saved {\n\tstruct path link;\n\tstruct delayed_call done;\n\tconst char *name;\n\tunsigned int seq;\n};\n\nstruct nameidata {\n\tstruct path path;\n\tstruct qstr last;\n\tstruct path root;\n\tstruct inode *inode;\n\tunsigned int flags;\n\tunsigned int state;\n\tunsigned int seq;\n\tunsigned int m_seq;\n\tunsigned int r_seq;\n\tint last_type;\n\tunsigned int depth;\n\tint total_link_count;\n\tstruct saved *stack;\n\tstruct saved internal[2];\n\tstruct filename *name;\n\tstruct nameidata *saved;\n\tunsigned int root_seq;\n\tint dfd;\n\tkuid_t dir_uid;\n\tumode_t dir_mode;\n};\n\nstruct renamedata {\n\tstruct user_namespace *old_mnt_userns;\n\tstruct inode *old_dir;\n\tstruct dentry *old_dentry;\n\tstruct user_namespace *new_mnt_userns;\n\tstruct inode *new_dir;\n\tstruct dentry *new_dentry;\n\tstruct inode **delegated_inode;\n\tunsigned int flags;\n};\n\nenum {\n\tLAST_NORM = 0,\n\tLAST_ROOT = 1,\n\tLAST_DOT = 2,\n\tLAST_DOTDOT = 3,\n};\n\nenum {\n\tWALK_TRAILING = 1,\n\tWALK_MORE = 2,\n\tWALK_NOFOLLOW = 4,\n};\n\nstruct word_at_a_time {\n\tconst long unsigned int one_bits;\n\tconst long unsigned int high_bits;\n};\n\nstruct f_owner_ex {\n\tint type;\n\t__kernel_pid_t pid;\n};\n\nstruct flock {\n\tshort int l_type;\n\tshort int l_whence;\n\t__kernel_off_t l_start;\n\t__kernel_off_t l_len;\n\t__kernel_pid_t l_pid;\n};\n\nstruct compat_flock {\n\tshort int l_type;\n\tshort int l_whence;\n\tcompat_off_t l_start;\n\tcompat_off_t l_len;\n\tcompat_pid_t l_pid;\n};\n\nstruct compat_flock64 {\n\tshort int l_type;\n\tshort int l_whence;\n\tcompat_loff_t l_start;\n\tcompat_loff_t l_len;\n\tcompat_pid_t l_pid;\n} __attribute__((packed));\n\nstruct file_clone_range {\n\t__s64 src_fd;\n\t__u64 src_offset;\n\t__u64 src_length;\n\t__u64 dest_offset;\n};\n\nstruct file_dedupe_range_info {\n\t__s64 dest_fd;\n\t__u64 dest_offset;\n\t__u64 bytes_deduped;\n\t__s32 status;\n\t__u32 reserved;\n};\n\nstruct file_dedupe_range {\n\t__u64 src_offset;\n\t__u64 src_length;\n\t__u16 dest_count;\n\t__u16 reserved1;\n\t__u32 reserved2;\n\tstruct file_dedupe_range_info info[0];\n};\n\nstruct fsxattr {\n\t__u32 fsx_xflags;\n\t__u32 fsx_extsize;\n\t__u32 fsx_nextents;\n\t__u32 fsx_projid;\n\t__u32 fsx_cowextsize;\n\tunsigned char fsx_pad[8];\n};\n\ntypedef int get_block_t(struct inode *, sector_t, struct buffer_head *, int);\n\nstruct fiemap_extent;\n\nstruct fiemap_extent_info {\n\tunsigned int fi_flags;\n\tunsigned int fi_extents_mapped;\n\tunsigned int fi_extents_max;\n\tstruct fiemap_extent *fi_extents_start;\n};\n\nstruct fileattr {\n\tu32 flags;\n\tu32 fsx_xflags;\n\tu32 fsx_extsize;\n\tu32 fsx_nextents;\n\tu32 fsx_projid;\n\tu32 fsx_cowextsize;\n\tbool flags_valid: 1;\n\tbool fsx_valid: 1;\n};\n\nstruct space_resv {\n\t__s16 l_type;\n\t__s16 l_whence;\n\t__s64 l_start;\n\t__s64 l_len;\n\t__s32 l_sysid;\n\t__u32 l_pid;\n\t__s32 l_pad[4];\n};\n\nstruct space_resv_32 {\n\t__s16 l_type;\n\t__s16 l_whence;\n\t__s64 l_start;\n\t__s64 l_len;\n\t__s32 l_sysid;\n\t__u32 l_pid;\n\t__s32 l_pad[4];\n} __attribute__((packed));\n\nstruct fiemap_extent {\n\t__u64 fe_logical;\n\t__u64 fe_physical;\n\t__u64 fe_length;\n\t__u64 fe_reserved64[2];\n\t__u32 fe_flags;\n\t__u32 fe_reserved[3];\n};\n\nstruct fiemap {\n\t__u64 fm_start;\n\t__u64 fm_length;\n\t__u32 fm_flags;\n\t__u32 fm_mapped_extents;\n\t__u32 fm_extent_count;\n\t__u32 fm_reserved;\n\tstruct fiemap_extent fm_extents[0];\n};\n\nstruct linux_dirent64 {\n\tu64 d_ino;\n\ts64 d_off;\n\tshort unsigned int d_reclen;\n\tunsigned char d_type;\n\tchar d_name[0];\n};\n\nstruct old_linux_dirent {\n\tlong unsigned int d_ino;\n\tlong unsigned int d_offset;\n\tshort unsigned int d_namlen;\n\tchar d_name[1];\n};\n\nstruct readdir_callback {\n\tstruct dir_context ctx;\n\tstruct old_linux_dirent *dirent;\n\tint result;\n};\n\nstruct linux_dirent {\n\tlong unsigned int d_ino;\n\tlong unsigned int d_off;\n\tshort unsigned int d_reclen;\n\tchar d_name[1];\n};\n\nstruct getdents_callback {\n\tstruct dir_context ctx;\n\tstruct linux_dirent *current_dir;\n\tint prev_reclen;\n\tint count;\n\tint error;\n};\n\nstruct getdents_callback64 {\n\tstruct dir_context ctx;\n\tstruct linux_dirent64 *current_dir;\n\tint prev_reclen;\n\tint count;\n\tint error;\n};\n\nstruct compat_old_linux_dirent {\n\tcompat_ulong_t d_ino;\n\tcompat_ulong_t d_offset;\n\tshort unsigned int d_namlen;\n\tchar d_name[1];\n};\n\nstruct compat_readdir_callback {\n\tstruct dir_context ctx;\n\tstruct compat_old_linux_dirent *dirent;\n\tint result;\n};\n\nstruct compat_linux_dirent {\n\tcompat_ulong_t d_ino;\n\tcompat_ulong_t d_off;\n\tshort unsigned int d_reclen;\n\tchar d_name[1];\n};\n\nstruct compat_getdents_callback {\n\tstruct dir_context ctx;\n\tstruct compat_linux_dirent *current_dir;\n\tint prev_reclen;\n\tint count;\n\tint error;\n};\n\ntypedef struct {\n\tlong unsigned int fds_bits[16];\n} __kernel_fd_set;\n\ntypedef __kernel_fd_set fd_set;\n\nstruct poll_table_entry {\n\tstruct file *filp;\n\t__poll_t key;\n\twait_queue_entry_t wait;\n\twait_queue_head_t *wait_address;\n};\n\nstruct poll_table_page;\n\nstruct poll_wqueues {\n\tpoll_table pt;\n\tstruct poll_table_page *table;\n\tstruct task_struct *polling_task;\n\tint triggered;\n\tint error;\n\tint inline_index;\n\tstruct poll_table_entry inline_entries[9];\n};\n\nstruct poll_table_page {\n\tstruct poll_table_page *next;\n\tstruct poll_table_entry *entry;\n\tstruct poll_table_entry entries[0];\n};\n\nenum poll_time_type {\n\tPT_TIMEVAL = 0,\n\tPT_OLD_TIMEVAL = 1,\n\tPT_TIMESPEC = 2,\n\tPT_OLD_TIMESPEC = 3,\n};\n\ntypedef struct {\n\tlong unsigned int *in;\n\tlong unsigned int *out;\n\tlong unsigned int *ex;\n\tlong unsigned int *res_in;\n\tlong unsigned int *res_out;\n\tlong unsigned int *res_ex;\n} fd_set_bits;\n\nstruct sigset_argpack {\n\tsigset_t *p;\n\tsize_t size;\n};\n\nstruct poll_list {\n\tstruct poll_list *next;\n\tint len;\n\tstruct pollfd entries[0];\n};\n\nstruct compat_sel_arg_struct {\n\tcompat_ulong_t n;\n\tcompat_uptr_t inp;\n\tcompat_uptr_t outp;\n\tcompat_uptr_t exp;\n\tcompat_uptr_t tvp;\n};\n\nstruct compat_sigset_argpack {\n\tcompat_uptr_t p;\n\tcompat_size_t size;\n};\n\nenum dentry_d_lock_class {\n\tDENTRY_D_LOCK_NORMAL = 0,\n\tDENTRY_D_LOCK_NESTED = 1,\n};\n\nstruct external_name {\n\tunion {\n\t\tatomic_t count;\n\t\tstruct callback_head head;\n\t} u;\n\tunsigned char name[0];\n};\n\nenum d_walk_ret {\n\tD_WALK_CONTINUE = 0,\n\tD_WALK_QUIT = 1,\n\tD_WALK_NORETRY = 2,\n\tD_WALK_SKIP = 3,\n};\n\nstruct check_mount {\n\tstruct vfsmount *mnt;\n\tunsigned int mounted;\n};\n\nstruct select_data {\n\tstruct dentry *start;\n\tunion {\n\t\tlong int found;\n\t\tstruct dentry *victim;\n\t};\n\tstruct list_head dispose;\n};\n\nenum file_time_flags {\n\tS_ATIME = 1,\n\tS_MTIME = 2,\n\tS_CTIME = 4,\n\tS_VERSION = 8,\n};\n\nstruct mount_attr {\n\t__u64 attr_set;\n\t__u64 attr_clr;\n\t__u64 propagation;\n\t__u64 userns_fd;\n};\n\nstruct proc_mounts {\n\tstruct mnt_namespace *ns;\n\tstruct path root;\n\tint (*show)(struct seq_file *, struct vfsmount *);\n\tstruct mount cursor;\n};\n\nstruct mount_kattr {\n\tunsigned int attr_set;\n\tunsigned int attr_clr;\n\tunsigned int propagation;\n\tunsigned int lookup_flags;\n\tbool recurse;\n\tstruct user_namespace *mnt_userns;\n};\n\nenum umount_tree_flags {\n\tUMOUNT_SYNC = 1,\n\tUMOUNT_PROPAGATE = 2,\n\tUMOUNT_CONNECTED = 4,\n};\n\nstruct unicode_map {\n\tconst char *charset;\n\tint version;\n};\n\nstruct simple_transaction_argresp {\n\tssize_t size;\n\tchar data[0];\n};\n\nstruct simple_attr {\n\tint (*get)(void *, u64 *);\n\tint (*set)(void *, u64);\n\tchar get_buf[24];\n\tchar set_buf[24];\n\tvoid *data;\n\tconst char *fmt;\n\tstruct mutex mutex;\n};\n\nstruct wb_writeback_work {\n\tlong int nr_pages;\n\tstruct super_block *sb;\n\tenum writeback_sync_modes sync_mode;\n\tunsigned int tagged_writepages: 1;\n\tunsigned int for_kupdate: 1;\n\tunsigned int range_cyclic: 1;\n\tunsigned int for_background: 1;\n\tunsigned int for_sync: 1;\n\tunsigned int auto_free: 1;\n\tenum wb_reason reason;\n\tstruct list_head list;\n\tstruct wb_completion *done;\n};\n\nstruct trace_event_raw_writeback_page_template {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t ino;\n\tlong unsigned int index;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_dirty_inode_template {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t ino;\n\tlong unsigned int state;\n\tlong unsigned int flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_inode_foreign_history {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t ino;\n\tino_t cgroup_ino;\n\tunsigned int history;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_inode_switch_wbs {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t ino;\n\tino_t old_cgroup_ino;\n\tino_t new_cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_track_foreign_dirty {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tu64 bdi_id;\n\tino_t ino;\n\tunsigned int memcg_id;\n\tino_t cgroup_ino;\n\tino_t page_cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_flush_foreign {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t cgroup_ino;\n\tunsigned int frn_bdi_id;\n\tunsigned int frn_memcg_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_write_inode_template {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t ino;\n\tint sync_mode;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_work_class {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tlong int nr_pages;\n\tdev_t sb_dev;\n\tint sync_mode;\n\tint for_kupdate;\n\tint range_cyclic;\n\tint for_background;\n\tint reason;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_pages_written {\n\tstruct trace_entry ent;\n\tlong int pages;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_class {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_bdi_register {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_wbc_class {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tlong int nr_to_write;\n\tlong int pages_skipped;\n\tint sync_mode;\n\tint for_kupdate;\n\tint for_background;\n\tint for_reclaim;\n\tint range_cyclic;\n\tlong int range_start;\n\tlong int range_end;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_queue_io {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tlong unsigned int older;\n\tlong int age;\n\tint moved;\n\tint reason;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_global_dirty_state {\n\tstruct trace_entry ent;\n\tlong unsigned int nr_dirty;\n\tlong unsigned int nr_writeback;\n\tlong unsigned int background_thresh;\n\tlong unsigned int dirty_thresh;\n\tlong unsigned int dirty_limit;\n\tlong unsigned int nr_dirtied;\n\tlong unsigned int nr_written;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_bdi_dirty_ratelimit {\n\tstruct trace_entry ent;\n\tchar bdi[32];\n\tlong unsigned int write_bw;\n\tlong unsigned int avg_write_bw;\n\tlong unsigned int dirty_rate;\n\tlong unsigned int dirty_ratelimit;\n\tlong unsigned int task_ratelimit;\n\tlong unsigned int balanced_dirty_ratelimit;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_balance_dirty_pages {\n\tstruct trace_entry ent;\n\tchar bdi[32];\n\tlong unsigned int limit;\n\tlong unsigned int setpoint;\n\tlong unsigned int dirty;\n\tlong unsigned int bdi_setpoint;\n\tlong unsigned int bdi_dirty;\n\tlong unsigned int dirty_ratelimit;\n\tlong unsigned int task_ratelimit;\n\tunsigned int dirtied;\n\tunsigned int dirtied_pause;\n\tlong unsigned int paused;\n\tlong int pause;\n\tlong unsigned int period;\n\tlong int think;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_sb_inodes_requeue {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t ino;\n\tlong unsigned int state;\n\tlong unsigned int dirtied_when;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_congest_waited_template {\n\tstruct trace_entry ent;\n\tunsigned int usec_timeout;\n\tunsigned int usec_delayed;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_single_inode_template {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tino_t ino;\n\tlong unsigned int state;\n\tlong unsigned int dirtied_when;\n\tlong unsigned int writeback_index;\n\tlong int nr_to_write;\n\tlong unsigned int wrote;\n\tino_t cgroup_ino;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_writeback_inode_template {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tino_t ino;\n\tlong unsigned int state;\n\t__u16 mode;\n\tlong unsigned int dirtied_when;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_writeback_page_template {};\n\nstruct trace_event_data_offsets_writeback_dirty_inode_template {};\n\nstruct trace_event_data_offsets_inode_foreign_history {};\n\nstruct trace_event_data_offsets_inode_switch_wbs {};\n\nstruct trace_event_data_offsets_track_foreign_dirty {};\n\nstruct trace_event_data_offsets_flush_foreign {};\n\nstruct trace_event_data_offsets_writeback_write_inode_template {};\n\nstruct trace_event_data_offsets_writeback_work_class {};\n\nstruct trace_event_data_offsets_writeback_pages_written {};\n\nstruct trace_event_data_offsets_writeback_class {};\n\nstruct trace_event_data_offsets_writeback_bdi_register {};\n\nstruct trace_event_data_offsets_wbc_class {};\n\nstruct trace_event_data_offsets_writeback_queue_io {};\n\nstruct trace_event_data_offsets_global_dirty_state {};\n\nstruct trace_event_data_offsets_bdi_dirty_ratelimit {};\n\nstruct trace_event_data_offsets_balance_dirty_pages {};\n\nstruct trace_event_data_offsets_writeback_sb_inodes_requeue {};\n\nstruct trace_event_data_offsets_writeback_congest_waited_template {};\n\nstruct trace_event_data_offsets_writeback_single_inode_template {};\n\nstruct trace_event_data_offsets_writeback_inode_template {};\n\ntypedef void (*btf_trace_writeback_dirty_page)(void *, struct page *, struct address_space *);\n\ntypedef void (*btf_trace_wait_on_page_writeback)(void *, struct page *, struct address_space *);\n\ntypedef void (*btf_trace_writeback_mark_inode_dirty)(void *, struct inode *, int);\n\ntypedef void (*btf_trace_writeback_dirty_inode_start)(void *, struct inode *, int);\n\ntypedef void (*btf_trace_writeback_dirty_inode)(void *, struct inode *, int);\n\ntypedef void (*btf_trace_inode_foreign_history)(void *, struct inode *, struct writeback_control *, unsigned int);\n\ntypedef void (*btf_trace_inode_switch_wbs)(void *, struct inode *, struct bdi_writeback *, struct bdi_writeback *);\n\ntypedef void (*btf_trace_track_foreign_dirty)(void *, struct page *, struct bdi_writeback *);\n\ntypedef void (*btf_trace_flush_foreign)(void *, struct bdi_writeback *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_writeback_write_inode_start)(void *, struct inode *, struct writeback_control *);\n\ntypedef void (*btf_trace_writeback_write_inode)(void *, struct inode *, struct writeback_control *);\n\ntypedef void (*btf_trace_writeback_queue)(void *, struct bdi_writeback *, struct wb_writeback_work *);\n\ntypedef void (*btf_trace_writeback_exec)(void *, struct bdi_writeback *, struct wb_writeback_work *);\n\ntypedef void (*btf_trace_writeback_start)(void *, struct bdi_writeback *, struct wb_writeback_work *);\n\ntypedef void (*btf_trace_writeback_written)(void *, struct bdi_writeback *, struct wb_writeback_work *);\n\ntypedef void (*btf_trace_writeback_wait)(void *, struct bdi_writeback *, struct wb_writeback_work *);\n\ntypedef void (*btf_trace_writeback_pages_written)(void *, long int);\n\ntypedef void (*btf_trace_writeback_wake_background)(void *, struct bdi_writeback *);\n\ntypedef void (*btf_trace_writeback_bdi_register)(void *, struct backing_dev_info *);\n\ntypedef void (*btf_trace_wbc_writepage)(void *, struct writeback_control *, struct backing_dev_info *);\n\ntypedef void (*btf_trace_writeback_queue_io)(void *, struct bdi_writeback *, struct wb_writeback_work *, long unsigned int, int);\n\ntypedef void (*btf_trace_global_dirty_state)(void *, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_bdi_dirty_ratelimit)(void *, struct bdi_writeback *, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_balance_dirty_pages)(void *, struct bdi_writeback *, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long unsigned int, long int, long unsigned int);\n\ntypedef void (*btf_trace_writeback_sb_inodes_requeue)(void *, struct inode *);\n\ntypedef void (*btf_trace_writeback_congestion_wait)(void *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_writeback_wait_iff_congested)(void *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_writeback_single_inode_start)(void *, struct inode *, struct writeback_control *, long unsigned int);\n\ntypedef void (*btf_trace_writeback_single_inode)(void *, struct inode *, struct writeback_control *, long unsigned int);\n\ntypedef void (*btf_trace_writeback_lazytime)(void *, struct inode *);\n\ntypedef void (*btf_trace_writeback_lazytime_iput)(void *, struct inode *);\n\ntypedef void (*btf_trace_writeback_dirty_inode_enqueue)(void *, struct inode *);\n\ntypedef void (*btf_trace_sb_mark_inode_writeback)(void *, struct inode *);\n\ntypedef void (*btf_trace_sb_clear_inode_writeback)(void *, struct inode *);\n\nstruct inode_switch_wbs_context {\n\tstruct rcu_work work;\n\tstruct bdi_writeback *new_wb;\n\tstruct inode *inodes[0];\n};\n\nstruct splice_desc {\n\tsize_t total_len;\n\tunsigned int len;\n\tunsigned int flags;\n\tunion {\n\t\tvoid *userptr;\n\t\tstruct file *file;\n\t\tvoid *data;\n\t} u;\n\tloff_t pos;\n\tloff_t *opos;\n\tsize_t num_spliced;\n\tbool need_wakeup;\n};\n\ntypedef int splice_actor(struct pipe_inode_info *, struct pipe_buffer *, struct splice_desc *);\n\ntypedef int splice_direct_actor(struct pipe_inode_info *, struct splice_desc *);\n\nstruct old_utimbuf32 {\n\told_time32_t actime;\n\told_time32_t modtime;\n};\n\nstruct utimbuf {\n\t__kernel_old_time_t actime;\n\t__kernel_old_time_t modtime;\n};\n\nstruct prepend_buffer {\n\tchar *buf;\n\tint len;\n};\n\ntypedef int __kernel_daddr_t;\n\nstruct ustat {\n\t__kernel_daddr_t f_tfree;\n\tlong unsigned int f_tinode;\n\tchar f_fname[6];\n\tchar f_fpack[6];\n};\n\ntypedef s32 compat_daddr_t;\n\ntypedef __kernel_fsid_t compat_fsid_t;\n\nstruct compat_statfs {\n\tint f_type;\n\tint f_bsize;\n\tint f_blocks;\n\tint f_bfree;\n\tint f_bavail;\n\tint f_files;\n\tint f_ffree;\n\tcompat_fsid_t f_fsid;\n\tint f_namelen;\n\tint f_frsize;\n\tint f_flags;\n\tint f_spare[4];\n};\n\nstruct compat_ustat {\n\tcompat_daddr_t f_tfree;\n\tcompat_ino_t f_tinode;\n\tchar f_fname[6];\n\tchar f_fpack[6];\n};\n\nstruct statfs {\n\t__kernel_long_t f_type;\n\t__kernel_long_t f_bsize;\n\t__kernel_long_t f_blocks;\n\t__kernel_long_t f_bfree;\n\t__kernel_long_t f_bavail;\n\t__kernel_long_t f_files;\n\t__kernel_long_t f_ffree;\n\t__kernel_fsid_t f_fsid;\n\t__kernel_long_t f_namelen;\n\t__kernel_long_t f_frsize;\n\t__kernel_long_t f_flags;\n\t__kernel_long_t f_spare[4];\n};\n\nstruct statfs64 {\n\t__kernel_long_t f_type;\n\t__kernel_long_t f_bsize;\n\t__u64 f_blocks;\n\t__u64 f_bfree;\n\t__u64 f_bavail;\n\t__u64 f_files;\n\t__u64 f_ffree;\n\t__kernel_fsid_t f_fsid;\n\t__kernel_long_t f_namelen;\n\t__kernel_long_t f_frsize;\n\t__kernel_long_t f_flags;\n\t__kernel_long_t f_spare[4];\n};\n\nstruct compat_statfs64 {\n\t__u32 f_type;\n\t__u32 f_bsize;\n\t__u64 f_blocks;\n\t__u64 f_bfree;\n\t__u64 f_bavail;\n\t__u64 f_files;\n\t__u64 f_ffree;\n\t__kernel_fsid_t f_fsid;\n\t__u32 f_namelen;\n\t__u32 f_frsize;\n\t__u32 f_flags;\n\t__u32 f_spare[4];\n} __attribute__((packed));\n\nstruct ns_get_path_task_args {\n\tconst struct proc_ns_operations *ns_ops;\n\tstruct task_struct *task;\n};\n\nenum legacy_fs_param {\n\tLEGACY_FS_UNSET_PARAMS = 0,\n\tLEGACY_FS_MONOLITHIC_PARAMS = 1,\n\tLEGACY_FS_INDIVIDUAL_PARAMS = 2,\n};\n\nstruct legacy_fs_context {\n\tchar *legacy_data;\n\tsize_t data_size;\n\tenum legacy_fs_param param_type;\n};\n\nenum fsconfig_command {\n\tFSCONFIG_SET_FLAG = 0,\n\tFSCONFIG_SET_STRING = 1,\n\tFSCONFIG_SET_BINARY = 2,\n\tFSCONFIG_SET_PATH = 3,\n\tFSCONFIG_SET_PATH_EMPTY = 4,\n\tFSCONFIG_SET_FD = 5,\n\tFSCONFIG_CMD_CREATE = 6,\n\tFSCONFIG_CMD_RECONFIGURE = 7,\n};\n\nstruct dax_device;\n\nstruct iomap_page_ops;\n\nstruct iomap___2 {\n\tu64 addr;\n\tloff_t offset;\n\tu64 length;\n\tu16 type;\n\tu16 flags;\n\tstruct block_device *bdev;\n\tstruct dax_device *dax_dev;\n\tvoid *inline_data;\n\tvoid *private;\n\tconst struct iomap_page_ops *page_ops;\n};\n\nstruct iomap_page_ops {\n\tint (*page_prepare)(struct inode *, loff_t, unsigned int, struct iomap___2 *);\n\tvoid (*page_done)(struct inode *, loff_t, unsigned int, struct page *, struct iomap___2 *);\n};\n\nstruct decrypt_bh_ctx {\n\tstruct work_struct work;\n\tstruct buffer_head *bh;\n};\n\nstruct bh_lru {\n\tstruct buffer_head *bhs[16];\n};\n\nstruct bh_accounting {\n\tint nr;\n\tint ratelimit;\n};\n\nenum stat_group {\n\tSTAT_READ = 0,\n\tSTAT_WRITE = 1,\n\tSTAT_DISCARD = 2,\n\tSTAT_FLUSH = 3,\n\tNR_STAT_GROUPS = 4,\n};\n\nenum {\n\tDISK_EVENT_MEDIA_CHANGE = 1,\n\tDISK_EVENT_EJECT_REQUEST = 2,\n};\n\nenum {\n\tBIOSET_NEED_BVECS = 1,\n\tBIOSET_NEED_RESCUER = 2,\n};\n\nstruct bdev_inode {\n\tstruct block_device bdev;\n\tstruct inode vfs_inode;\n};\n\nstruct blkdev_dio {\n\tunion {\n\t\tstruct kiocb *iocb;\n\t\tstruct task_struct *waiter;\n\t};\n\tsize_t size;\n\tatomic_t ref;\n\tbool multi_bio: 1;\n\tbool should_dirty: 1;\n\tbool is_sync: 1;\n\tstruct bio bio;\n};\n\nstruct bd_holder_disk {\n\tstruct list_head list;\n\tstruct gendisk *disk;\n\tint refcnt;\n};\n\ntypedef int dio_iodone_t(struct kiocb *, loff_t, ssize_t, void *);\n\ntypedef void dio_submit_t(struct bio *, struct inode *, loff_t);\n\nenum {\n\tDIO_LOCKING = 1,\n\tDIO_SKIP_HOLES = 2,\n};\n\nstruct dio_submit {\n\tstruct bio *bio;\n\tunsigned int blkbits;\n\tunsigned int blkfactor;\n\tunsigned int start_zero_done;\n\tint pages_in_io;\n\tsector_t block_in_file;\n\tunsigned int blocks_available;\n\tint reap_counter;\n\tsector_t final_block_in_request;\n\tint boundary;\n\tget_block_t *get_block;\n\tdio_submit_t *submit_io;\n\tloff_t logical_offset_in_bio;\n\tsector_t final_block_in_bio;\n\tsector_t next_block_for_io;\n\tstruct page *cur_page;\n\tunsigned int cur_page_offset;\n\tunsigned int cur_page_len;\n\tsector_t cur_page_block;\n\tloff_t cur_page_fs_offset;\n\tstruct iov_iter *iter;\n\tunsigned int head;\n\tunsigned int tail;\n\tsize_t from;\n\tsize_t to;\n};\n\nstruct dio {\n\tint flags;\n\tint op;\n\tint op_flags;\n\tblk_qc_t bio_cookie;\n\tstruct gendisk *bio_disk;\n\tstruct inode *inode;\n\tloff_t i_size;\n\tdio_iodone_t *end_io;\n\tvoid *private;\n\tspinlock_t bio_lock;\n\tint page_errors;\n\tint is_async;\n\tbool defer_completion;\n\tbool should_dirty;\n\tint io_error;\n\tlong unsigned int refcount;\n\tstruct bio *bio_list;\n\tstruct task_struct *waiter;\n\tstruct kiocb *iocb;\n\tssize_t result;\n\tunion {\n\t\tstruct page *pages[64];\n\t\tstruct work_struct complete_work;\n\t};\n\tlong: 64;\n};\n\nstruct bvec_iter_all {\n\tstruct bio_vec bv;\n\tint idx;\n\tunsigned int done;\n};\n\nstruct mpage_readpage_args {\n\tstruct bio *bio;\n\tstruct page *page;\n\tunsigned int nr_pages;\n\tbool is_readahead;\n\tsector_t last_block_in_bio;\n\tstruct buffer_head map_bh;\n\tlong unsigned int first_logical_block;\n\tget_block_t *get_block;\n};\n\nstruct mpage_data {\n\tstruct bio *bio;\n\tsector_t last_block_in_bio;\n\tget_block_t *get_block;\n\tunsigned int use_writepage;\n};\n\ntypedef u32 nlink_t;\n\ntypedef int (*proc_write_t)(struct file *, char *, size_t);\n\nstruct proc_dir_entry {\n\tatomic_t in_use;\n\trefcount_t refcnt;\n\tstruct list_head pde_openers;\n\tspinlock_t pde_unload_lock;\n\tstruct completion *pde_unload_completion;\n\tconst struct inode_operations *proc_iops;\n\tunion {\n\t\tconst struct proc_ops *proc_ops;\n\t\tconst struct file_operations *proc_dir_ops;\n\t};\n\tconst struct dentry_operations *proc_dops;\n\tunion {\n\t\tconst struct seq_operations *seq_ops;\n\t\tint (*single_show)(struct seq_file *, void *);\n\t};\n\tproc_write_t write;\n\tvoid *data;\n\tunsigned int state_size;\n\tunsigned int low_ino;\n\tnlink_t nlink;\n\tkuid_t uid;\n\tkgid_t gid;\n\tloff_t size;\n\tstruct proc_dir_entry *parent;\n\tstruct rb_root subdir;\n\tstruct rb_node subdir_node;\n\tchar *name;\n\tumode_t mode;\n\tu8 flags;\n\tu8 namelen;\n\tchar inline_name[0];\n};\n\nunion proc_op {\n\tint (*proc_get_link)(struct dentry *, struct path *);\n\tint (*proc_show)(struct seq_file *, struct pid_namespace *, struct pid *, struct task_struct *);\n\tconst char *lsm;\n};\n\nstruct proc_inode {\n\tstruct pid *pid;\n\tunsigned int fd;\n\tunion proc_op op;\n\tstruct proc_dir_entry *pde;\n\tstruct ctl_table_header *sysctl;\n\tstruct ctl_table *sysctl_entry;\n\tstruct hlist_node sibling_inodes;\n\tconst struct proc_ns_operations *ns_ops;\n\tstruct inode vfs_inode;\n};\n\nstruct proc_fs_opts {\n\tint flag;\n\tconst char *str;\n};\n\nstruct file_handle {\n\t__u32 handle_bytes;\n\tint handle_type;\n\tunsigned char f_handle[0];\n};\n\nstruct inotify_inode_mark {\n\tstruct fsnotify_mark fsn_mark;\n\tint wd;\n};\n\nstruct dnotify_struct {\n\tstruct dnotify_struct *dn_next;\n\t__u32 dn_mask;\n\tint dn_fd;\n\tstruct file *dn_filp;\n\tfl_owner_t dn_owner;\n};\n\nstruct dnotify_mark {\n\tstruct fsnotify_mark fsn_mark;\n\tstruct dnotify_struct *dn;\n};\n\nstruct inotify_event_info {\n\tstruct fsnotify_event fse;\n\tu32 mask;\n\tint wd;\n\tu32 sync_cookie;\n\tint name_len;\n\tchar name[0];\n};\n\nstruct inotify_event {\n\t__s32 wd;\n\t__u32 mask;\n\t__u32 cookie;\n\t__u32 len;\n\tchar name[0];\n};\n\nenum {\n\tFAN_EVENT_INIT = 0,\n\tFAN_EVENT_REPORTED = 1,\n\tFAN_EVENT_ANSWERED = 2,\n\tFAN_EVENT_CANCELED = 3,\n};\n\nstruct fanotify_fh {\n\tu8 type;\n\tu8 len;\n\tu8 flags;\n\tu8 pad;\n\tunsigned char buf[0];\n};\n\nstruct fanotify_info {\n\tu8 dir_fh_totlen;\n\tu8 file_fh_totlen;\n\tu8 name_len;\n\tu8 pad;\n\tunsigned char buf[0];\n};\n\nenum fanotify_event_type {\n\tFANOTIFY_EVENT_TYPE_FID = 0,\n\tFANOTIFY_EVENT_TYPE_FID_NAME = 1,\n\tFANOTIFY_EVENT_TYPE_PATH = 2,\n\tFANOTIFY_EVENT_TYPE_PATH_PERM = 3,\n\tFANOTIFY_EVENT_TYPE_OVERFLOW = 4,\n\t__FANOTIFY_EVENT_TYPE_NUM = 5,\n};\n\nstruct fanotify_event {\n\tstruct fsnotify_event fse;\n\tstruct hlist_node merge_list;\n\tu32 mask;\n\tstruct {\n\t\tunsigned int type: 3;\n\t\tunsigned int hash: 29;\n\t};\n\tstruct pid *pid;\n};\n\nstruct fanotify_fid_event {\n\tstruct fanotify_event fae;\n\t__kernel_fsid_t fsid;\n\tstruct fanotify_fh object_fh;\n\tunsigned char _inline_fh_buf[12];\n};\n\nstruct fanotify_name_event {\n\tstruct fanotify_event fae;\n\t__kernel_fsid_t fsid;\n\tstruct fanotify_info info;\n};\n\nstruct fanotify_path_event {\n\tstruct fanotify_event fae;\n\tstruct path path;\n};\n\nstruct fanotify_perm_event {\n\tstruct fanotify_event fae;\n\tstruct path path;\n\tshort unsigned int response;\n\tshort unsigned int state;\n\tint fd;\n};\n\nstruct fanotify_event_metadata {\n\t__u32 event_len;\n\t__u8 vers;\n\t__u8 reserved;\n\t__u16 metadata_len;\n\t__u64 mask;\n\t__s32 fd;\n\t__s32 pid;\n};\n\nstruct fanotify_event_info_header {\n\t__u8 info_type;\n\t__u8 pad;\n\t__u16 len;\n};\n\nstruct fanotify_event_info_fid {\n\tstruct fanotify_event_info_header hdr;\n\t__kernel_fsid_t fsid;\n\tunsigned char handle[0];\n};\n\nstruct fanotify_response {\n\t__s32 fd;\n\t__u32 response;\n};\n\nstruct epoll_event {\n\t__poll_t events;\n\t__u64 data;\n} __attribute__((packed));\n\nstruct epoll_filefd {\n\tstruct file *file;\n\tint fd;\n} __attribute__((packed));\n\nstruct epitem;\n\nstruct eppoll_entry {\n\tstruct eppoll_entry *next;\n\tstruct epitem *base;\n\twait_queue_entry_t wait;\n\twait_queue_head_t *whead;\n};\n\nstruct eventpoll;\n\nstruct epitem {\n\tunion {\n\t\tstruct rb_node rbn;\n\t\tstruct callback_head rcu;\n\t};\n\tstruct list_head rdllink;\n\tstruct epitem *next;\n\tstruct epoll_filefd ffd;\n\tstruct eppoll_entry *pwqlist;\n\tstruct eventpoll *ep;\n\tstruct hlist_node fllink;\n\tstruct wakeup_source *ws;\n\tstruct epoll_event event;\n};\n\nstruct eventpoll {\n\tstruct mutex mtx;\n\twait_queue_head_t wq;\n\twait_queue_head_t poll_wait;\n\tstruct list_head rdllist;\n\trwlock_t lock;\n\tstruct rb_root_cached rbr;\n\tstruct epitem *ovflist;\n\tstruct wakeup_source *ws;\n\tstruct user_struct *user;\n\tstruct file *file;\n\tu64 gen;\n\tstruct hlist_head refs;\n\tunsigned int napi_id;\n};\n\nstruct ep_pqueue {\n\tpoll_table pt;\n\tstruct epitem *epi;\n};\n\nstruct epitems_head {\n\tstruct hlist_head epitems;\n\tstruct epitems_head *next;\n};\n\nstruct signalfd_siginfo {\n\t__u32 ssi_signo;\n\t__s32 ssi_errno;\n\t__s32 ssi_code;\n\t__u32 ssi_pid;\n\t__u32 ssi_uid;\n\t__s32 ssi_fd;\n\t__u32 ssi_tid;\n\t__u32 ssi_band;\n\t__u32 ssi_overrun;\n\t__u32 ssi_trapno;\n\t__s32 ssi_status;\n\t__s32 ssi_int;\n\t__u64 ssi_ptr;\n\t__u64 ssi_utime;\n\t__u64 ssi_stime;\n\t__u64 ssi_addr;\n\t__u16 ssi_addr_lsb;\n\t__u16 __pad2;\n\t__s32 ssi_syscall;\n\t__u64 ssi_call_addr;\n\t__u32 ssi_arch;\n\t__u8 __pad[28];\n};\n\nstruct signalfd_ctx {\n\tsigset_t sigmask;\n};\n\nstruct timerfd_ctx {\n\tunion {\n\t\tstruct hrtimer tmr;\n\t\tstruct alarm alarm;\n\t} t;\n\tktime_t tintv;\n\tktime_t moffs;\n\twait_queue_head_t wqh;\n\tu64 ticks;\n\tint clockid;\n\tshort unsigned int expired;\n\tshort unsigned int settime_flags;\n\tstruct callback_head rcu;\n\tstruct list_head clist;\n\tspinlock_t cancel_lock;\n\tbool might_cancel;\n};\n\nstruct eventfd_ctx___2 {\n\tstruct kref kref;\n\twait_queue_head_t wqh;\n\t__u64 count;\n\tunsigned int flags;\n\tint id;\n};\n\nenum userfaultfd_state {\n\tUFFD_STATE_WAIT_API = 0,\n\tUFFD_STATE_RUNNING = 1,\n};\n\nstruct userfaultfd_ctx {\n\twait_queue_head_t fault_pending_wqh;\n\twait_queue_head_t fault_wqh;\n\twait_queue_head_t fd_wqh;\n\twait_queue_head_t event_wqh;\n\tseqcount_spinlock_t refile_seq;\n\trefcount_t refcount;\n\tunsigned int flags;\n\tunsigned int features;\n\tenum userfaultfd_state state;\n\tbool released;\n\tbool mmap_changing;\n\tstruct mm_struct *mm;\n};\n\nstruct uffd_msg {\n\t__u8 event;\n\t__u8 reserved1;\n\t__u16 reserved2;\n\t__u32 reserved3;\n\tunion {\n\t\tstruct {\n\t\t\t__u64 flags;\n\t\t\t__u64 address;\n\t\t\tunion {\n\t\t\t\t__u32 ptid;\n\t\t\t} feat;\n\t\t} pagefault;\n\t\tstruct {\n\t\t\t__u32 ufd;\n\t\t} fork;\n\t\tstruct {\n\t\t\t__u64 from;\n\t\t\t__u64 to;\n\t\t\t__u64 len;\n\t\t} remap;\n\t\tstruct {\n\t\t\t__u64 start;\n\t\t\t__u64 end;\n\t\t} remove;\n\t\tstruct {\n\t\t\t__u64 reserved1;\n\t\t\t__u64 reserved2;\n\t\t\t__u64 reserved3;\n\t\t} reserved;\n\t} arg;\n};\n\nstruct uffdio_api {\n\t__u64 api;\n\t__u64 features;\n\t__u64 ioctls;\n};\n\nstruct uffdio_range {\n\t__u64 start;\n\t__u64 len;\n};\n\nstruct uffdio_register {\n\tstruct uffdio_range range;\n\t__u64 mode;\n\t__u64 ioctls;\n};\n\nstruct uffdio_copy {\n\t__u64 dst;\n\t__u64 src;\n\t__u64 len;\n\t__u64 mode;\n\t__s64 copy;\n};\n\nstruct uffdio_zeropage {\n\tstruct uffdio_range range;\n\t__u64 mode;\n\t__s64 zeropage;\n};\n\nstruct uffdio_writeprotect {\n\tstruct uffdio_range range;\n\t__u64 mode;\n};\n\nstruct uffdio_continue {\n\tstruct uffdio_range range;\n\t__u64 mode;\n\t__s64 mapped;\n};\n\nstruct userfaultfd_fork_ctx {\n\tstruct userfaultfd_ctx *orig;\n\tstruct userfaultfd_ctx *new;\n\tstruct list_head list;\n};\n\nstruct userfaultfd_unmap_ctx {\n\tstruct userfaultfd_ctx *ctx;\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tstruct list_head list;\n};\n\nstruct userfaultfd_wait_queue {\n\tstruct uffd_msg msg;\n\twait_queue_entry_t wq;\n\tstruct userfaultfd_ctx *ctx;\n\tbool waken;\n};\n\nstruct userfaultfd_wake_range {\n\tlong unsigned int start;\n\tlong unsigned int len;\n};\n\nstruct kioctx;\n\nstruct kioctx_table {\n\tstruct callback_head rcu;\n\tunsigned int nr;\n\tstruct kioctx *table[0];\n};\n\ntypedef __kernel_ulong_t aio_context_t;\n\nenum {\n\tIOCB_CMD_PREAD = 0,\n\tIOCB_CMD_PWRITE = 1,\n\tIOCB_CMD_FSYNC = 2,\n\tIOCB_CMD_FDSYNC = 3,\n\tIOCB_CMD_POLL = 5,\n\tIOCB_CMD_NOOP = 6,\n\tIOCB_CMD_PREADV = 7,\n\tIOCB_CMD_PWRITEV = 8,\n};\n\nstruct io_event {\n\t__u64 data;\n\t__u64 obj;\n\t__s64 res;\n\t__s64 res2;\n};\n\nstruct iocb {\n\t__u64 aio_data;\n\t__u32 aio_key;\n\t__kernel_rwf_t aio_rw_flags;\n\t__u16 aio_lio_opcode;\n\t__s16 aio_reqprio;\n\t__u32 aio_fildes;\n\t__u64 aio_buf;\n\t__u64 aio_nbytes;\n\t__s64 aio_offset;\n\t__u64 aio_reserved2;\n\t__u32 aio_flags;\n\t__u32 aio_resfd;\n};\n\ntypedef u32 compat_aio_context_t;\n\ntypedef int kiocb_cancel_fn(struct kiocb *);\n\nstruct aio_ring {\n\tunsigned int id;\n\tunsigned int nr;\n\tunsigned int head;\n\tunsigned int tail;\n\tunsigned int magic;\n\tunsigned int compat_features;\n\tunsigned int incompat_features;\n\tunsigned int header_length;\n\tstruct io_event io_events[0];\n};\n\nstruct kioctx_cpu;\n\nstruct ctx_rq_wait;\n\nstruct kioctx {\n\tstruct percpu_ref users;\n\tatomic_t dead;\n\tstruct percpu_ref reqs;\n\tlong unsigned int user_id;\n\tstruct kioctx_cpu *cpu;\n\tunsigned int req_batch;\n\tunsigned int max_reqs;\n\tunsigned int nr_events;\n\tlong unsigned int mmap_base;\n\tlong unsigned int mmap_size;\n\tstruct page **ring_pages;\n\tlong int nr_pages;\n\tstruct rcu_work free_rwork;\n\tstruct ctx_rq_wait *rq_wait;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct {\n\t\tatomic_t reqs_available;\n\t\tlong: 32;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct {\n\t\tspinlock_t ctx_lock;\n\t\tstruct list_head active_reqs;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct {\n\t\tstruct mutex ring_lock;\n\t\twait_queue_head_t wait;\n\t\tlong: 64;\n\t};\n\tstruct {\n\t\tunsigned int tail;\n\t\tunsigned int completed_events;\n\t\tspinlock_t completion_lock;\n\t\tlong: 32;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct page *internal_pages[8];\n\tstruct file *aio_ring_file;\n\tunsigned int id;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct kioctx_cpu {\n\tunsigned int reqs_available;\n};\n\nstruct ctx_rq_wait {\n\tstruct completion comp;\n\tatomic_t count;\n};\n\nstruct fsync_iocb {\n\tstruct file *file;\n\tstruct work_struct work;\n\tbool datasync;\n\tstruct cred *creds;\n};\n\nstruct poll_iocb {\n\tstruct file *file;\n\tstruct wait_queue_head *head;\n\t__poll_t events;\n\tbool done;\n\tbool cancelled;\n\tstruct wait_queue_entry wait;\n\tstruct work_struct work;\n};\n\nstruct aio_kiocb {\n\tunion {\n\t\tstruct file *ki_filp;\n\t\tstruct kiocb rw;\n\t\tstruct fsync_iocb fsync;\n\t\tstruct poll_iocb poll;\n\t};\n\tstruct kioctx *ki_ctx;\n\tkiocb_cancel_fn *ki_cancel;\n\tstruct io_event ki_res;\n\tstruct list_head ki_list;\n\trefcount_t ki_refcnt;\n\tstruct eventfd_ctx *ki_eventfd;\n};\n\nstruct aio_poll_table {\n\tstruct poll_table_struct pt;\n\tstruct aio_kiocb *iocb;\n\tint error;\n};\n\nstruct __aio_sigset {\n\tconst sigset_t *sigmask;\n\tsize_t sigsetsize;\n};\n\nstruct __compat_aio_sigset {\n\tcompat_uptr_t sigmask;\n\tcompat_size_t sigsetsize;\n};\n\nstruct xa_limit {\n\tu32 max;\n\tu32 min;\n};\n\nstruct io_wq;\n\nstruct io_wq_work_node;\n\nstruct io_wq_work_list {\n\tstruct io_wq_work_node *first;\n\tstruct io_wq_work_node *last;\n};\n\nstruct io_ring_ctx;\n\nstruct io_uring_task {\n\tint cached_refs;\n\tstruct xarray xa;\n\tstruct wait_queue_head wait;\n\tconst struct io_ring_ctx *last;\n\tstruct io_wq *io_wq;\n\tstruct percpu_counter inflight;\n\tatomic_t inflight_tracked;\n\tatomic_t in_idle;\n\tspinlock_t task_lock;\n\tstruct io_wq_work_list task_list;\n\tlong unsigned int task_state;\n\tstruct callback_head task_work;\n};\n\nstruct user_msghdr {\n\tvoid *msg_name;\n\tint msg_namelen;\n\tstruct iovec *msg_iov;\n\t__kernel_size_t msg_iovlen;\n\tvoid *msg_control;\n\t__kernel_size_t msg_controllen;\n\tunsigned int msg_flags;\n};\n\ntypedef s32 compat_ssize_t;\n\nstruct compat_msghdr {\n\tcompat_uptr_t msg_name;\n\tcompat_int_t msg_namelen;\n\tcompat_uptr_t msg_iov;\n\tcompat_size_t msg_iovlen;\n\tcompat_uptr_t msg_control;\n\tcompat_size_t msg_controllen;\n\tcompat_uint_t msg_flags;\n};\n\nstruct scm_fp_list {\n\tshort int count;\n\tshort int max;\n\tstruct user_struct *user;\n\tstruct file *fp[253];\n};\n\nstruct unix_skb_parms {\n\tstruct pid *pid;\n\tkuid_t uid;\n\tkgid_t gid;\n\tstruct scm_fp_list *fp;\n\tu32 secid;\n\tu32 consumed;\n};\n\nstruct trace_event_raw_io_uring_create {\n\tstruct trace_entry ent;\n\tint fd;\n\tvoid *ctx;\n\tu32 sq_entries;\n\tu32 cq_entries;\n\tu32 flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_register {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tunsigned int opcode;\n\tunsigned int nr_files;\n\tunsigned int nr_bufs;\n\tbool eventfd;\n\tlong int ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_file_get {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tint fd;\n\tchar __data[0];\n};\n\nstruct io_wq_work;\n\nstruct trace_event_raw_io_uring_queue_async_work {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tint rw;\n\tvoid *req;\n\tstruct io_wq_work *work;\n\tunsigned int flags;\n\tchar __data[0];\n};\n\nstruct io_wq_work_node {\n\tstruct io_wq_work_node *next;\n};\n\nstruct io_wq_work {\n\tstruct io_wq_work_node list;\n\tunsigned int flags;\n};\n\nstruct trace_event_raw_io_uring_defer {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tvoid *req;\n\tlong long unsigned int data;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_link {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tvoid *req;\n\tvoid *target_req;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_cqring_wait {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tint min_events;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_fail_link {\n\tstruct trace_entry ent;\n\tvoid *req;\n\tvoid *link;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_complete {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tu64 user_data;\n\tlong int res;\n\tunsigned int cflags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_submit_sqe {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tvoid *req;\n\tu8 opcode;\n\tu64 user_data;\n\tu32 flags;\n\tbool force_nonblock;\n\tbool sq_thread;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_poll_arm {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tvoid *req;\n\tu8 opcode;\n\tu64 user_data;\n\tint mask;\n\tint events;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_poll_wake {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tu8 opcode;\n\tu64 user_data;\n\tint mask;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_task_add {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tu8 opcode;\n\tu64 user_data;\n\tint mask;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_io_uring_task_run {\n\tstruct trace_entry ent;\n\tvoid *ctx;\n\tvoid *req;\n\tu8 opcode;\n\tu64 user_data;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_io_uring_create {};\n\nstruct trace_event_data_offsets_io_uring_register {};\n\nstruct trace_event_data_offsets_io_uring_file_get {};\n\nstruct trace_event_data_offsets_io_uring_queue_async_work {};\n\nstruct trace_event_data_offsets_io_uring_defer {};\n\nstruct trace_event_data_offsets_io_uring_link {};\n\nstruct trace_event_data_offsets_io_uring_cqring_wait {};\n\nstruct trace_event_data_offsets_io_uring_fail_link {};\n\nstruct trace_event_data_offsets_io_uring_complete {};\n\nstruct trace_event_data_offsets_io_uring_submit_sqe {};\n\nstruct trace_event_data_offsets_io_uring_poll_arm {};\n\nstruct trace_event_data_offsets_io_uring_poll_wake {};\n\nstruct trace_event_data_offsets_io_uring_task_add {};\n\nstruct trace_event_data_offsets_io_uring_task_run {};\n\ntypedef void (*btf_trace_io_uring_create)(void *, int, void *, u32, u32, u32);\n\ntypedef void (*btf_trace_io_uring_register)(void *, void *, unsigned int, unsigned int, unsigned int, bool, long int);\n\ntypedef void (*btf_trace_io_uring_file_get)(void *, void *, int);\n\ntypedef void (*btf_trace_io_uring_queue_async_work)(void *, void *, int, void *, struct io_wq_work *, unsigned int);\n\ntypedef void (*btf_trace_io_uring_defer)(void *, void *, void *, long long unsigned int);\n\ntypedef void (*btf_trace_io_uring_link)(void *, void *, void *, void *);\n\ntypedef void (*btf_trace_io_uring_cqring_wait)(void *, void *, int);\n\ntypedef void (*btf_trace_io_uring_fail_link)(void *, void *, void *);\n\ntypedef void (*btf_trace_io_uring_complete)(void *, void *, u64, long int, unsigned int);\n\ntypedef void (*btf_trace_io_uring_submit_sqe)(void *, void *, void *, u8, u64, u32, bool, bool);\n\ntypedef void (*btf_trace_io_uring_poll_arm)(void *, void *, void *, u8, u64, int, int);\n\ntypedef void (*btf_trace_io_uring_poll_wake)(void *, void *, u8, u64, int);\n\ntypedef void (*btf_trace_io_uring_task_add)(void *, void *, u8, u64, int);\n\ntypedef void (*btf_trace_io_uring_task_run)(void *, void *, void *, u8, u64);\n\nstruct io_uring_sqe {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 ioprio;\n\t__s32 fd;\n\tunion {\n\t\t__u64 off;\n\t\t__u64 addr2;\n\t};\n\tunion {\n\t\t__u64 addr;\n\t\t__u64 splice_off_in;\n\t};\n\t__u32 len;\n\tunion {\n\t\t__kernel_rwf_t rw_flags;\n\t\t__u32 fsync_flags;\n\t\t__u16 poll_events;\n\t\t__u32 poll32_events;\n\t\t__u32 sync_range_flags;\n\t\t__u32 msg_flags;\n\t\t__u32 timeout_flags;\n\t\t__u32 accept_flags;\n\t\t__u32 cancel_flags;\n\t\t__u32 open_flags;\n\t\t__u32 statx_flags;\n\t\t__u32 fadvise_advice;\n\t\t__u32 splice_flags;\n\t\t__u32 rename_flags;\n\t\t__u32 unlink_flags;\n\t};\n\t__u64 user_data;\n\tunion {\n\t\t__u16 buf_index;\n\t\t__u16 buf_group;\n\t};\n\t__u16 personality;\n\t__s32 splice_fd_in;\n\t__u64 __pad2[2];\n};\n\nenum {\n\tIOSQE_FIXED_FILE_BIT = 0,\n\tIOSQE_IO_DRAIN_BIT = 1,\n\tIOSQE_IO_LINK_BIT = 2,\n\tIOSQE_IO_HARDLINK_BIT = 3,\n\tIOSQE_ASYNC_BIT = 4,\n\tIOSQE_BUFFER_SELECT_BIT = 5,\n};\n\nenum {\n\tIORING_OP_NOP = 0,\n\tIORING_OP_READV = 1,\n\tIORING_OP_WRITEV = 2,\n\tIORING_OP_FSYNC = 3,\n\tIORING_OP_READ_FIXED = 4,\n\tIORING_OP_WRITE_FIXED = 5,\n\tIORING_OP_POLL_ADD = 6,\n\tIORING_OP_POLL_REMOVE = 7,\n\tIORING_OP_SYNC_FILE_RANGE = 8,\n\tIORING_OP_SENDMSG = 9,\n\tIORING_OP_RECVMSG = 10,\n\tIORING_OP_TIMEOUT = 11,\n\tIORING_OP_TIMEOUT_REMOVE = 12,\n\tIORING_OP_ACCEPT = 13,\n\tIORING_OP_ASYNC_CANCEL = 14,\n\tIORING_OP_LINK_TIMEOUT = 15,\n\tIORING_OP_CONNECT = 16,\n\tIORING_OP_FALLOCATE = 17,\n\tIORING_OP_OPENAT = 18,\n\tIORING_OP_CLOSE = 19,\n\tIORING_OP_FILES_UPDATE = 20,\n\tIORING_OP_STATX = 21,\n\tIORING_OP_READ = 22,\n\tIORING_OP_WRITE = 23,\n\tIORING_OP_FADVISE = 24,\n\tIORING_OP_MADVISE = 25,\n\tIORING_OP_SEND = 26,\n\tIORING_OP_RECV = 27,\n\tIORING_OP_OPENAT2 = 28,\n\tIORING_OP_EPOLL_CTL = 29,\n\tIORING_OP_SPLICE = 30,\n\tIORING_OP_PROVIDE_BUFFERS = 31,\n\tIORING_OP_REMOVE_BUFFERS = 32,\n\tIORING_OP_TEE = 33,\n\tIORING_OP_SHUTDOWN = 34,\n\tIORING_OP_RENAMEAT = 35,\n\tIORING_OP_UNLINKAT = 36,\n\tIORING_OP_LAST = 37,\n};\n\nstruct io_uring_cqe {\n\t__u64 user_data;\n\t__s32 res;\n\t__u32 flags;\n};\n\nenum {\n\tIORING_CQE_BUFFER_SHIFT = 16,\n};\n\nstruct io_sqring_offsets {\n\t__u32 head;\n\t__u32 tail;\n\t__u32 ring_mask;\n\t__u32 ring_entries;\n\t__u32 flags;\n\t__u32 dropped;\n\t__u32 array;\n\t__u32 resv1;\n\t__u64 resv2;\n};\n\nstruct io_cqring_offsets {\n\t__u32 head;\n\t__u32 tail;\n\t__u32 ring_mask;\n\t__u32 ring_entries;\n\t__u32 overflow;\n\t__u32 cqes;\n\t__u32 flags;\n\t__u32 resv1;\n\t__u64 resv2;\n};\n\nstruct io_uring_params {\n\t__u32 sq_entries;\n\t__u32 cq_entries;\n\t__u32 flags;\n\t__u32 sq_thread_cpu;\n\t__u32 sq_thread_idle;\n\t__u32 features;\n\t__u32 wq_fd;\n\t__u32 resv[3];\n\tstruct io_sqring_offsets sq_off;\n\tstruct io_cqring_offsets cq_off;\n};\n\nenum {\n\tIORING_REGISTER_BUFFERS = 0,\n\tIORING_UNREGISTER_BUFFERS = 1,\n\tIORING_REGISTER_FILES = 2,\n\tIORING_UNREGISTER_FILES = 3,\n\tIORING_REGISTER_EVENTFD = 4,\n\tIORING_UNREGISTER_EVENTFD = 5,\n\tIORING_REGISTER_FILES_UPDATE = 6,\n\tIORING_REGISTER_EVENTFD_ASYNC = 7,\n\tIORING_REGISTER_PROBE = 8,\n\tIORING_REGISTER_PERSONALITY = 9,\n\tIORING_UNREGISTER_PERSONALITY = 10,\n\tIORING_REGISTER_RESTRICTIONS = 11,\n\tIORING_REGISTER_ENABLE_RINGS = 12,\n\tIORING_REGISTER_FILES2 = 13,\n\tIORING_REGISTER_FILES_UPDATE2 = 14,\n\tIORING_REGISTER_BUFFERS2 = 15,\n\tIORING_REGISTER_BUFFERS_UPDATE = 16,\n\tIORING_REGISTER_IOWQ_AFF = 17,\n\tIORING_UNREGISTER_IOWQ_AFF = 18,\n\tIORING_REGISTER_LAST = 19,\n};\n\nstruct io_uring_rsrc_register {\n\t__u32 nr;\n\t__u32 resv;\n\t__u64 resv2;\n\t__u64 data;\n\t__u64 tags;\n};\n\nstruct io_uring_rsrc_update2 {\n\t__u32 offset;\n\t__u32 resv;\n\t__u64 data;\n\t__u64 tags;\n\t__u32 nr;\n\t__u32 resv2;\n};\n\nstruct io_uring_probe_op {\n\t__u8 op;\n\t__u8 resv;\n\t__u16 flags;\n\t__u32 resv2;\n};\n\nstruct io_uring_probe {\n\t__u8 last_op;\n\t__u8 ops_len;\n\t__u16 resv;\n\t__u32 resv2[3];\n\tstruct io_uring_probe_op ops[0];\n};\n\nstruct io_uring_restriction {\n\t__u16 opcode;\n\tunion {\n\t\t__u8 register_op;\n\t\t__u8 sqe_op;\n\t\t__u8 sqe_flags;\n\t};\n\t__u8 resv;\n\t__u32 resv2[3];\n};\n\nenum {\n\tIORING_RESTRICTION_REGISTER_OP = 0,\n\tIORING_RESTRICTION_SQE_OP = 1,\n\tIORING_RESTRICTION_SQE_FLAGS_ALLOWED = 2,\n\tIORING_RESTRICTION_SQE_FLAGS_REQUIRED = 3,\n\tIORING_RESTRICTION_LAST = 4,\n};\n\nstruct io_uring_getevents_arg {\n\t__u64 sigmask;\n\t__u32 sigmask_sz;\n\t__u32 pad;\n\t__u64 ts;\n};\n\nenum {\n\tIO_WQ_WORK_CANCEL = 1,\n\tIO_WQ_WORK_HASHED = 2,\n\tIO_WQ_WORK_UNBOUND = 4,\n\tIO_WQ_WORK_CONCURRENT = 16,\n\tIO_WQ_HASH_SHIFT = 24,\n};\n\nenum io_wq_cancel {\n\tIO_WQ_CANCEL_OK = 0,\n\tIO_WQ_CANCEL_RUNNING = 1,\n\tIO_WQ_CANCEL_NOTFOUND = 2,\n};\n\ntypedef struct io_wq_work *free_work_fn(struct io_wq_work *);\n\ntypedef void io_wq_work_fn(struct io_wq_work *);\n\nstruct io_wq_hash {\n\trefcount_t refs;\n\tlong unsigned int map;\n\tstruct wait_queue_head wait;\n};\n\nstruct io_wq_data {\n\tstruct io_wq_hash *hash;\n\tstruct task_struct *task;\n\tio_wq_work_fn *do_work;\n\tfree_work_fn *free_work;\n};\n\ntypedef bool work_cancel_fn(struct io_wq_work *, void *);\n\nstruct io_uring {\n\tu32 head;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu32 tail;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct io_rings {\n\tstruct io_uring sq;\n\tstruct io_uring cq;\n\tu32 sq_ring_mask;\n\tu32 cq_ring_mask;\n\tu32 sq_ring_entries;\n\tu32 cq_ring_entries;\n\tu32 sq_dropped;\n\tu32 sq_flags;\n\tu32 cq_flags;\n\tu32 cq_overflow;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct io_uring_cqe cqes[0];\n};\n\nenum io_uring_cmd_flags {\n\tIO_URING_F_NONBLOCK = 1,\n\tIO_URING_F_COMPLETE_DEFER = 2,\n};\n\nstruct io_mapped_ubuf {\n\tu64 ubuf;\n\tu64 ubuf_end;\n\tunsigned int nr_bvecs;\n\tlong unsigned int acct_pages;\n\tstruct bio_vec bvec[0];\n};\n\nstruct io_overflow_cqe {\n\tstruct io_uring_cqe cqe;\n\tstruct list_head list;\n};\n\nstruct io_fixed_file {\n\tlong unsigned int file_ptr;\n};\n\nstruct io_rsrc_put {\n\tstruct list_head list;\n\tu64 tag;\n\tunion {\n\t\tvoid *rsrc;\n\t\tstruct file *file;\n\t\tstruct io_mapped_ubuf *buf;\n\t};\n};\n\nstruct io_file_table {\n\tstruct io_fixed_file **files;\n};\n\nstruct io_rsrc_data;\n\nstruct io_rsrc_node {\n\tstruct percpu_ref refs;\n\tstruct list_head node;\n\tstruct list_head rsrc_list;\n\tstruct io_rsrc_data *rsrc_data;\n\tstruct llist_node llist;\n\tbool done;\n};\n\ntypedef void rsrc_put_fn(struct io_ring_ctx *, struct io_rsrc_put *);\n\nstruct io_rsrc_data {\n\tstruct io_ring_ctx *ctx;\n\tu64 **tags;\n\tunsigned int nr;\n\trsrc_put_fn *do_put;\n\tatomic_t refs;\n\tstruct completion done;\n\tbool quiesce;\n};\n\nstruct io_kiocb;\n\nstruct io_submit_link {\n\tstruct io_kiocb *head;\n\tstruct io_kiocb *last;\n};\n\nstruct io_comp_state {\n\tstruct io_kiocb *reqs[32];\n\tunsigned int nr;\n\tstruct list_head free_list;\n};\n\nstruct io_submit_state {\n\tstruct blk_plug plug;\n\tstruct io_submit_link link;\n\tvoid *reqs[32];\n\tunsigned int free_reqs;\n\tbool plug_started;\n\tstruct io_comp_state comp;\n\tstruct file *file;\n\tunsigned int fd;\n\tunsigned int file_refs;\n\tunsigned int ios_left;\n};\n\nstruct io_restriction {\n\tlong unsigned int register_op[1];\n\tlong unsigned int sqe_op[1];\n\tu8 sqe_flags_allowed;\n\tu8 sqe_flags_required;\n\tbool registered;\n};\n\nstruct io_sq_data;\n\nstruct io_ring_ctx {\n\tstruct {\n\t\tstruct percpu_ref refs;\n\t\tstruct io_rings *rings;\n\t\tunsigned int flags;\n\t\tunsigned int compat: 1;\n\t\tunsigned int drain_next: 1;\n\t\tunsigned int eventfd_async: 1;\n\t\tunsigned int restricted: 1;\n\t\tunsigned int off_timeout_used: 1;\n\t\tunsigned int drain_active: 1;\n\t\tlong: 26;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct {\n\t\tstruct mutex uring_lock;\n\t\tu32 *sq_array;\n\t\tstruct io_uring_sqe *sq_sqes;\n\t\tunsigned int cached_sq_head;\n\t\tunsigned int sq_entries;\n\t\tstruct list_head defer_list;\n\t\tstruct io_rsrc_node *rsrc_node;\n\t\tstruct io_file_table file_table;\n\t\tunsigned int nr_user_files;\n\t\tunsigned int nr_user_bufs;\n\t\tstruct io_mapped_ubuf **user_bufs;\n\t\tstruct io_submit_state submit_state;\n\t\tstruct list_head timeout_list;\n\t\tstruct list_head cq_overflow_list;\n\t\tstruct xarray io_buffers;\n\t\tstruct xarray personalities;\n\t\tu32 pers_next;\n\t\tunsigned int sq_thread_idle;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct list_head locked_free_list;\n\tunsigned int locked_free_nr;\n\tconst struct cred *sq_creds;\n\tstruct io_sq_data *sq_data;\n\tstruct wait_queue_head sqo_sq_wait;\n\tstruct list_head sqd_list;\n\tlong unsigned int check_cq_overflow;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct {\n\t\tunsigned int cached_cq_tail;\n\t\tunsigned int cq_entries;\n\t\tstruct eventfd_ctx *cq_ev_fd;\n\t\tstruct wait_queue_head poll_wait;\n\t\tstruct wait_queue_head cq_wait;\n\t\tunsigned int cq_extra;\n\t\tatomic_t cq_timeouts;\n\t\tstruct fasync_struct *cq_fasync;\n\t\tunsigned int cq_last_tm_flush;\n\t\tlong: 32;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct {\n\t\tspinlock_t completion_lock;\n\t\tstruct list_head iopoll_list;\n\t\tstruct hlist_head *cancel_hash;\n\t\tunsigned int cancel_hash_bits;\n\t\tbool poll_multi_queue;\n\t\tlong: 24;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tstruct io_restriction restrictions;\n\tstruct {\n\t\tstruct io_rsrc_node *rsrc_backup_node;\n\t\tstruct io_mapped_ubuf *dummy_ubuf;\n\t\tstruct io_rsrc_data *file_data;\n\t\tstruct io_rsrc_data *buf_data;\n\t\tstruct delayed_work rsrc_put_work;\n\t\tstruct llist_head rsrc_put_llist;\n\t\tstruct list_head rsrc_ref_list;\n\t\tspinlock_t rsrc_ref_lock;\n\t};\n\tstruct {\n\t\tstruct socket *ring_sock;\n\t\tstruct io_wq_hash *hash_map;\n\t\tstruct user_struct *user;\n\t\tstruct mm_struct *mm_account;\n\t\tstruct llist_head fallback_llist;\n\t\tstruct delayed_work fallback_work;\n\t\tstruct work_struct exit_work;\n\t\tstruct list_head tctx_list;\n\t\tstruct completion ref_comp;\n\t};\n};\n\nstruct io_buffer {\n\tstruct list_head list;\n\t__u64 addr;\n\t__u32 len;\n\t__u16 bid;\n};\n\nenum {\n\tIO_SQ_THREAD_SHOULD_STOP = 0,\n\tIO_SQ_THREAD_SHOULD_PARK = 1,\n};\n\nstruct io_sq_data {\n\trefcount_t refs;\n\tatomic_t park_pending;\n\tstruct mutex lock;\n\tstruct list_head ctx_list;\n\tstruct task_struct *thread;\n\tstruct wait_queue_head wait;\n\tunsigned int sq_thread_idle;\n\tint sq_cpu;\n\tpid_t task_pid;\n\tpid_t task_tgid;\n\tlong unsigned int state;\n\tstruct completion exited;\n};\n\nstruct io_rw {\n\tstruct kiocb kiocb;\n\tu64 addr;\n\tu64 len;\n};\n\nstruct io_poll_iocb {\n\tstruct file *file;\n\tstruct wait_queue_head *head;\n\t__poll_t events;\n\tbool done;\n\tbool canceled;\n\tstruct wait_queue_entry wait;\n};\n\nstruct io_poll_update {\n\tstruct file *file;\n\tu64 old_user_data;\n\tu64 new_user_data;\n\t__poll_t events;\n\tbool update_events;\n\tbool update_user_data;\n};\n\nstruct io_accept {\n\tstruct file *file;\n\tstruct sockaddr *addr;\n\tint *addr_len;\n\tint flags;\n\tlong unsigned int nofile;\n};\n\nstruct io_sync {\n\tstruct file *file;\n\tloff_t len;\n\tloff_t off;\n\tint flags;\n\tint mode;\n};\n\nstruct io_cancel {\n\tstruct file *file;\n\tu64 addr;\n};\n\nstruct io_timeout {\n\tstruct file *file;\n\tu32 off;\n\tu32 target_seq;\n\tstruct list_head list;\n\tstruct io_kiocb *head;\n};\n\nstruct io_timeout_rem {\n\tstruct file *file;\n\tu64 addr;\n\tstruct timespec64 ts;\n\tu32 flags;\n};\n\nstruct io_connect {\n\tstruct file *file;\n\tstruct sockaddr *addr;\n\tint addr_len;\n};\n\nstruct io_sr_msg {\n\tstruct file *file;\n\tunion {\n\t\tstruct compat_msghdr *umsg_compat;\n\t\tstruct user_msghdr *umsg;\n\t\tvoid *buf;\n\t};\n\tint msg_flags;\n\tint bgid;\n\tsize_t len;\n\tstruct io_buffer *kbuf;\n};\n\nstruct io_open {\n\tstruct file *file;\n\tint dfd;\n\tstruct filename *filename;\n\tstruct open_how how;\n\tlong unsigned int nofile;\n};\n\nstruct io_close {\n\tstruct file *file;\n\tint fd;\n};\n\nstruct io_rsrc_update {\n\tstruct file *file;\n\tu64 arg;\n\tu32 nr_args;\n\tu32 offset;\n};\n\nstruct io_fadvise {\n\tstruct file *file;\n\tu64 offset;\n\tu32 len;\n\tu32 advice;\n};\n\nstruct io_madvise {\n\tstruct file *file;\n\tu64 addr;\n\tu32 len;\n\tu32 advice;\n};\n\nstruct io_epoll {\n\tstruct file *file;\n\tint epfd;\n\tint op;\n\tint fd;\n\tstruct epoll_event event;\n} __attribute__((packed));\n\nstruct io_splice {\n\tstruct file *file_out;\n\tstruct file *file_in;\n\tloff_t off_out;\n\tloff_t off_in;\n\tu64 len;\n\tunsigned int flags;\n};\n\nstruct io_provide_buf {\n\tstruct file *file;\n\t__u64 addr;\n\t__u32 len;\n\t__u32 bgid;\n\t__u16 nbufs;\n\t__u16 bid;\n};\n\nstruct io_statx {\n\tstruct file *file;\n\tint dfd;\n\tunsigned int mask;\n\tunsigned int flags;\n\tconst char *filename;\n\tstruct statx *buffer;\n};\n\nstruct io_shutdown {\n\tstruct file *file;\n\tint how;\n};\n\nstruct io_rename {\n\tstruct file *file;\n\tint old_dfd;\n\tint new_dfd;\n\tstruct filename *oldpath;\n\tstruct filename *newpath;\n\tint flags;\n};\n\nstruct io_unlink {\n\tstruct file *file;\n\tint dfd;\n\tint flags;\n\tstruct filename *filename;\n};\n\nstruct io_completion {\n\tstruct file *file;\n\tstruct list_head list;\n\tu32 cflags;\n};\n\ntypedef void (*io_req_tw_func_t)(struct io_kiocb *);\n\nstruct io_task_work {\n\tunion {\n\t\tstruct io_wq_work_node node;\n\t\tstruct llist_node fallback_node;\n\t};\n\tio_req_tw_func_t func;\n};\n\nstruct async_poll;\n\nstruct io_kiocb {\n\tunion {\n\t\tstruct file *file;\n\t\tstruct io_rw rw;\n\t\tstruct io_poll_iocb poll;\n\t\tstruct io_poll_update poll_update;\n\t\tstruct io_accept accept;\n\t\tstruct io_sync sync;\n\t\tstruct io_cancel cancel;\n\t\tstruct io_timeout timeout;\n\t\tstruct io_timeout_rem timeout_rem;\n\t\tstruct io_connect connect;\n\t\tstruct io_sr_msg sr_msg;\n\t\tstruct io_open open;\n\t\tstruct io_close close;\n\t\tstruct io_rsrc_update rsrc_update;\n\t\tstruct io_fadvise fadvise;\n\t\tstruct io_madvise madvise;\n\t\tstruct io_epoll epoll;\n\t\tstruct io_splice splice;\n\t\tstruct io_provide_buf pbuf;\n\t\tstruct io_statx statx;\n\t\tstruct io_shutdown shutdown;\n\t\tstruct io_rename rename;\n\t\tstruct io_unlink unlink;\n\t\tstruct io_completion compl;\n\t};\n\tvoid *async_data;\n\tu8 opcode;\n\tu8 iopoll_completed;\n\tu16 buf_index;\n\tu32 result;\n\tstruct io_ring_ctx *ctx;\n\tunsigned int flags;\n\tatomic_t refs;\n\tstruct task_struct *task;\n\tu64 user_data;\n\tstruct io_kiocb *link;\n\tstruct percpu_ref *fixed_rsrc_refs;\n\tstruct list_head inflight_entry;\n\tstruct io_task_work io_task_work;\n\tstruct hlist_node hash_node;\n\tstruct async_poll *apoll;\n\tstruct io_wq_work work;\n\tconst struct cred *creds;\n\tstruct io_mapped_ubuf *imu;\n};\n\nstruct io_timeout_data {\n\tstruct io_kiocb *req;\n\tstruct hrtimer timer;\n\tstruct timespec64 ts;\n\tenum hrtimer_mode mode;\n};\n\nstruct io_async_connect {\n\tstruct __kernel_sockaddr_storage address;\n};\n\nstruct io_async_msghdr {\n\tstruct iovec fast_iov[8];\n\tstruct iovec *free_iov;\n\tstruct sockaddr *uaddr;\n\tstruct msghdr msg;\n\tstruct __kernel_sockaddr_storage addr;\n};\n\nstruct io_async_rw {\n\tstruct iovec fast_iov[8];\n\tconst struct iovec *free_iovec;\n\tstruct iov_iter iter;\n\tsize_t bytes_done;\n\tstruct wait_page_queue wpq;\n};\n\nenum {\n\tREQ_F_FIXED_FILE_BIT = 0,\n\tREQ_F_IO_DRAIN_BIT = 1,\n\tREQ_F_LINK_BIT = 2,\n\tREQ_F_HARDLINK_BIT = 3,\n\tREQ_F_FORCE_ASYNC_BIT = 4,\n\tREQ_F_BUFFER_SELECT_BIT = 5,\n\tREQ_F_FAIL_BIT = 8,\n\tREQ_F_INFLIGHT_BIT = 9,\n\tREQ_F_CUR_POS_BIT = 10,\n\tREQ_F_NOWAIT_BIT = 11,\n\tREQ_F_LINK_TIMEOUT_BIT = 12,\n\tREQ_F_NEED_CLEANUP_BIT = 13,\n\tREQ_F_POLLED_BIT = 14,\n\tREQ_F_BUFFER_SELECTED_BIT = 15,\n\tREQ_F_LTIMEOUT_ACTIVE_BIT = 16,\n\tREQ_F_COMPLETE_INLINE_BIT = 17,\n\tREQ_F_REISSUE_BIT = 18,\n\tREQ_F_DONT_REISSUE_BIT = 19,\n\tREQ_F_CREDS_BIT = 20,\n\tREQ_F_ASYNC_READ_BIT = 21,\n\tREQ_F_ASYNC_WRITE_BIT = 22,\n\tREQ_F_ISREG_BIT = 23,\n\t__REQ_F_LAST_BIT = 24,\n};\n\nenum {\n\tREQ_F_FIXED_FILE = 1,\n\tREQ_F_IO_DRAIN = 2,\n\tREQ_F_LINK = 4,\n\tREQ_F_HARDLINK = 8,\n\tREQ_F_FORCE_ASYNC = 16,\n\tREQ_F_BUFFER_SELECT = 32,\n\tREQ_F_FAIL = 256,\n\tREQ_F_INFLIGHT = 512,\n\tREQ_F_CUR_POS = 1024,\n\tREQ_F_NOWAIT = 2048,\n\tREQ_F_LINK_TIMEOUT = 4096,\n\tREQ_F_NEED_CLEANUP = 8192,\n\tREQ_F_POLLED = 16384,\n\tREQ_F_BUFFER_SELECTED = 32768,\n\tREQ_F_LTIMEOUT_ACTIVE = 65536,\n\tREQ_F_COMPLETE_INLINE = 131072,\n\tREQ_F_REISSUE = 262144,\n\tREQ_F_DONT_REISSUE = 524288,\n\tREQ_F_ASYNC_READ = 2097152,\n\tREQ_F_ASYNC_WRITE = 4194304,\n\tREQ_F_ISREG = 8388608,\n\tREQ_F_CREDS = 1048576,\n};\n\nstruct async_poll {\n\tstruct io_poll_iocb poll;\n\tstruct io_poll_iocb *double_poll;\n};\n\nenum {\n\tIORING_RSRC_FILE = 0,\n\tIORING_RSRC_BUFFER = 1,\n};\n\nstruct io_tctx_node {\n\tstruct list_head ctx_node;\n\tstruct task_struct *task;\n\tstruct io_ring_ctx *ctx;\n};\n\nstruct io_defer_entry {\n\tstruct list_head list;\n\tstruct io_kiocb *req;\n\tu32 seq;\n};\n\nstruct io_op_def {\n\tunsigned int needs_file: 1;\n\tunsigned int hash_reg_file: 1;\n\tunsigned int unbound_nonreg_file: 1;\n\tunsigned int not_supported: 1;\n\tunsigned int pollin: 1;\n\tunsigned int pollout: 1;\n\tunsigned int buffer_select: 1;\n\tunsigned int needs_async_setup: 1;\n\tunsigned int plug: 1;\n\tshort unsigned int async_size;\n};\n\nstruct req_batch {\n\tstruct task_struct *task;\n\tint task_refs;\n\tint ctx_refs;\n};\n\nstruct io_poll_table {\n\tstruct poll_table_struct pt;\n\tstruct io_kiocb *req;\n\tint nr_entries;\n\tint error;\n};\n\nenum {\n\tIO_APOLL_OK = 0,\n\tIO_APOLL_ABORTED = 1,\n\tIO_APOLL_READY = 2,\n};\n\nstruct io_cancel_data {\n\tstruct io_ring_ctx *ctx;\n\tu64 user_data;\n};\n\nstruct io_wait_queue {\n\tstruct wait_queue_entry wq;\n\tstruct io_ring_ctx *ctx;\n\tunsigned int to_wait;\n\tunsigned int nr_timeouts;\n};\n\nstruct io_tctx_exit {\n\tstruct callback_head task_work;\n\tstruct completion completion;\n\tstruct io_ring_ctx *ctx;\n};\n\nstruct io_task_cancel {\n\tstruct task_struct *task;\n\tbool all;\n};\n\nstruct creds;\n\nenum {\n\tIO_WORKER_F_UP = 1,\n\tIO_WORKER_F_RUNNING = 2,\n\tIO_WORKER_F_FREE = 4,\n\tIO_WORKER_F_FIXED = 8,\n\tIO_WORKER_F_BOUND = 16,\n};\n\nenum {\n\tIO_WQ_BIT_EXIT = 0,\n};\n\nenum {\n\tIO_WQE_FLAG_STALLED = 1,\n};\n\nstruct io_wqe;\n\nstruct io_worker {\n\trefcount_t ref;\n\tunsigned int flags;\n\tstruct hlist_nulls_node nulls_node;\n\tstruct list_head all_list;\n\tstruct task_struct *task;\n\tstruct io_wqe *wqe;\n\tstruct io_wq_work *cur_work;\n\tspinlock_t lock;\n\tstruct completion ref_done;\n\tstruct callback_head rcu;\n};\n\nstruct io_wqe_acct {\n\tunsigned int nr_workers;\n\tunsigned int max_workers;\n\tint index;\n\tatomic_t nr_running;\n};\n\nstruct io_wq___2;\n\nstruct io_wqe {\n\tstruct {\n\t\traw_spinlock_t lock;\n\t\tstruct io_wq_work_list work_list;\n\t\tunsigned int flags;\n\t\tlong: 32;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t\tlong: 64;\n\t};\n\tint node;\n\tstruct io_wqe_acct acct[2];\n\tstruct hlist_nulls_head free_list;\n\tstruct list_head all_list;\n\tstruct wait_queue_entry wait;\n\tstruct io_wq___2 *wq;\n\tstruct io_wq_work *hash_tail[64];\n\tcpumask_var_t cpu_mask;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum {\n\tIO_WQ_ACCT_BOUND = 0,\n\tIO_WQ_ACCT_UNBOUND = 1,\n};\n\nstruct io_wq___2 {\n\tlong unsigned int state;\n\tfree_work_fn *free_work;\n\tio_wq_work_fn *do_work;\n\tstruct io_wq_hash *hash;\n\tatomic_t worker_refs;\n\tstruct completion worker_done;\n\tstruct hlist_node cpuhp_node;\n\tstruct task_struct *task;\n\tstruct io_wqe *wqes[0];\n};\n\nstruct io_cb_cancel_data {\n\twork_cancel_fn *fn;\n\tvoid *data;\n\tint nr_running;\n\tint nr_pending;\n\tbool cancel_all;\n};\n\nstruct create_worker_data {\n\tstruct callback_head work;\n\tstruct io_wqe *wqe;\n\tint index;\n};\n\nstruct online_data {\n\tunsigned int cpu;\n\tbool online;\n};\n\nstruct iomap_ops {\n\tint (*iomap_begin)(struct inode *, loff_t, loff_t, unsigned int, struct iomap___2 *, struct iomap___2 *);\n\tint (*iomap_end)(struct inode *, loff_t, loff_t, ssize_t, unsigned int, struct iomap___2 *);\n};\n\ntypedef loff_t (*iomap_actor_t)(struct inode *, loff_t, loff_t, void *, struct iomap___2 *, struct iomap___2 *);\n\nstruct trace_event_raw_dax_pmd_fault_class {\n\tstruct trace_entry ent;\n\tlong unsigned int ino;\n\tlong unsigned int vm_start;\n\tlong unsigned int vm_end;\n\tlong unsigned int vm_flags;\n\tlong unsigned int address;\n\tlong unsigned int pgoff;\n\tlong unsigned int max_pgoff;\n\tdev_t dev;\n\tunsigned int flags;\n\tint result;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_dax_pmd_load_hole_class {\n\tstruct trace_entry ent;\n\tlong unsigned int ino;\n\tlong unsigned int vm_flags;\n\tlong unsigned int address;\n\tstruct page *zero_page;\n\tvoid *radix_entry;\n\tdev_t dev;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_dax_pmd_insert_mapping_class {\n\tstruct trace_entry ent;\n\tlong unsigned int ino;\n\tlong unsigned int vm_flags;\n\tlong unsigned int address;\n\tlong int length;\n\tu64 pfn_val;\n\tvoid *radix_entry;\n\tdev_t dev;\n\tint write;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_dax_pte_fault_class {\n\tstruct trace_entry ent;\n\tlong unsigned int ino;\n\tlong unsigned int vm_flags;\n\tlong unsigned int address;\n\tlong unsigned int pgoff;\n\tdev_t dev;\n\tunsigned int flags;\n\tint result;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_dax_insert_mapping {\n\tstruct trace_entry ent;\n\tlong unsigned int ino;\n\tlong unsigned int vm_flags;\n\tlong unsigned int address;\n\tvoid *radix_entry;\n\tdev_t dev;\n\tint write;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_dax_writeback_range_class {\n\tstruct trace_entry ent;\n\tlong unsigned int ino;\n\tlong unsigned int start_index;\n\tlong unsigned int end_index;\n\tdev_t dev;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_dax_writeback_one {\n\tstruct trace_entry ent;\n\tlong unsigned int ino;\n\tlong unsigned int pgoff;\n\tlong unsigned int pglen;\n\tdev_t dev;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_dax_pmd_fault_class {};\n\nstruct trace_event_data_offsets_dax_pmd_load_hole_class {};\n\nstruct trace_event_data_offsets_dax_pmd_insert_mapping_class {};\n\nstruct trace_event_data_offsets_dax_pte_fault_class {};\n\nstruct trace_event_data_offsets_dax_insert_mapping {};\n\nstruct trace_event_data_offsets_dax_writeback_range_class {};\n\nstruct trace_event_data_offsets_dax_writeback_one {};\n\ntypedef void (*btf_trace_dax_pmd_fault)(void *, struct inode *, struct vm_fault *, long unsigned int, int);\n\ntypedef void (*btf_trace_dax_pmd_fault_done)(void *, struct inode *, struct vm_fault *, long unsigned int, int);\n\ntypedef void (*btf_trace_dax_pmd_load_hole)(void *, struct inode *, struct vm_fault *, struct page *, void *);\n\ntypedef void (*btf_trace_dax_pmd_load_hole_fallback)(void *, struct inode *, struct vm_fault *, struct page *, void *);\n\ntypedef void (*btf_trace_dax_pmd_insert_mapping)(void *, struct inode *, struct vm_fault *, long int, pfn_t, void *);\n\ntypedef void (*btf_trace_dax_pte_fault)(void *, struct inode *, struct vm_fault *, int);\n\ntypedef void (*btf_trace_dax_pte_fault_done)(void *, struct inode *, struct vm_fault *, int);\n\ntypedef void (*btf_trace_dax_load_hole)(void *, struct inode *, struct vm_fault *, int);\n\ntypedef void (*btf_trace_dax_insert_pfn_mkwrite_no_entry)(void *, struct inode *, struct vm_fault *, int);\n\ntypedef void (*btf_trace_dax_insert_pfn_mkwrite)(void *, struct inode *, struct vm_fault *, int);\n\ntypedef void (*btf_trace_dax_insert_mapping)(void *, struct inode *, struct vm_fault *, void *);\n\ntypedef void (*btf_trace_dax_writeback_range)(void *, struct inode *, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_dax_writeback_range_done)(void *, struct inode *, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_dax_writeback_one)(void *, struct inode *, long unsigned int, long unsigned int);\n\nstruct exceptional_entry_key {\n\tstruct xarray *xa;\n\tlong unsigned int entry_start;\n};\n\nstruct wait_exceptional_entry_queue {\n\twait_queue_entry_t wait;\n\tstruct exceptional_entry_key key;\n};\n\nenum dax_wake_mode {\n\tWAKE_ALL = 0,\n\tWAKE_NEXT = 1,\n};\n\nstruct crypto_skcipher;\n\nstruct fscrypt_blk_crypto_key;\n\nstruct fscrypt_prepared_key {\n\tstruct crypto_skcipher *tfm;\n\tstruct fscrypt_blk_crypto_key *blk_key;\n};\n\nstruct fscrypt_mode;\n\nstruct fscrypt_direct_key;\n\nstruct fscrypt_info {\n\tstruct fscrypt_prepared_key ci_enc_key;\n\tbool ci_owns_key;\n\tbool ci_inlinecrypt;\n\tstruct fscrypt_mode *ci_mode;\n\tstruct inode *ci_inode;\n\tstruct key *ci_master_key;\n\tstruct list_head ci_master_key_link;\n\tstruct fscrypt_direct_key *ci_direct_key;\n\tsiphash_key_t ci_dirhash_key;\n\tbool ci_dirhash_key_initialized;\n\tunion fscrypt_policy ci_policy;\n\tu8 ci_nonce[16];\n\tu32 ci_hashed_ino;\n};\n\nstruct skcipher_request {\n\tunsigned int cryptlen;\n\tu8 *iv;\n\tstruct scatterlist *src;\n\tstruct scatterlist *dst;\n\tstruct crypto_async_request base;\n\tvoid *__ctx[0];\n};\n\nstruct crypto_skcipher {\n\tunsigned int reqsize;\n\tstruct crypto_tfm base;\n};\n\nstruct fscrypt_mode {\n\tconst char *friendly_name;\n\tconst char *cipher_str;\n\tint keysize;\n\tint ivsize;\n\tint logged_impl_name;\n\tenum blk_crypto_mode_num blk_crypto_mode;\n};\n\ntypedef enum {\n\tFS_DECRYPT = 0,\n\tFS_ENCRYPT = 1,\n} fscrypt_direction_t;\n\nunion fscrypt_iv {\n\tstruct {\n\t\t__le64 lblk_num;\n\t\tu8 nonce[16];\n\t};\n\tu8 raw[32];\n\t__le64 dun[4];\n};\n\nstruct fscrypt_str {\n\tunsigned char *name;\n\tu32 len;\n};\n\nstruct fscrypt_name {\n\tconst struct qstr *usr_fname;\n\tstruct fscrypt_str disk_name;\n\tu32 hash;\n\tu32 minor_hash;\n\tstruct fscrypt_str crypto_buf;\n\tbool is_nokey_name;\n};\n\nstruct fscrypt_nokey_name {\n\tu32 dirhash[2];\n\tu8 bytes[149];\n\tu8 sha256[32];\n};\n\nstruct fscrypt_hkdf {\n\tstruct crypto_shash *hmac_tfm;\n};\n\nstruct fscrypt_key_specifier {\n\t__u32 type;\n\t__u32 __reserved;\n\tunion {\n\t\t__u8 __reserved[32];\n\t\t__u8 descriptor[8];\n\t\t__u8 identifier[16];\n\t} u;\n};\n\nstruct fscrypt_symlink_data {\n\t__le16 len;\n\tchar encrypted_path[1];\n} __attribute__((packed));\n\nstruct fscrypt_master_key_secret {\n\tstruct fscrypt_hkdf hkdf;\n\tu32 size;\n\tu8 raw[64];\n};\n\nstruct fscrypt_master_key {\n\tstruct fscrypt_master_key_secret mk_secret;\n\tstruct fscrypt_key_specifier mk_spec;\n\tstruct key *mk_users;\n\trefcount_t mk_refcount;\n\tstruct list_head mk_decrypted_inodes;\n\tspinlock_t mk_decrypted_inodes_lock;\n\tstruct fscrypt_prepared_key mk_direct_keys[10];\n\tstruct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[10];\n\tstruct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[10];\n\tsiphash_key_t mk_ino_hash_key;\n\tbool mk_ino_hash_key_initialized;\n};\n\nenum key_state {\n\tKEY_IS_UNINSTANTIATED = 0,\n\tKEY_IS_POSITIVE = 1,\n};\n\nstruct fscrypt_provisioning_key_payload {\n\t__u32 type;\n\t__u32 __reserved;\n\t__u8 raw[0];\n};\n\nstruct fscrypt_add_key_arg {\n\tstruct fscrypt_key_specifier key_spec;\n\t__u32 raw_size;\n\t__u32 key_id;\n\t__u32 __reserved[8];\n\t__u8 raw[0];\n};\n\nstruct fscrypt_remove_key_arg {\n\tstruct fscrypt_key_specifier key_spec;\n\t__u32 removal_status_flags;\n\t__u32 __reserved[5];\n};\n\nstruct fscrypt_get_key_status_arg {\n\tstruct fscrypt_key_specifier key_spec;\n\t__u32 __reserved[6];\n\t__u32 status;\n\t__u32 status_flags;\n\t__u32 user_count;\n\t__u32 __out_reserved[13];\n};\n\nstruct skcipher_alg {\n\tint (*setkey)(struct crypto_skcipher *, const u8 *, unsigned int);\n\tint (*encrypt)(struct skcipher_request *);\n\tint (*decrypt)(struct skcipher_request *);\n\tint (*init)(struct crypto_skcipher *);\n\tvoid (*exit)(struct crypto_skcipher *);\n\tunsigned int min_keysize;\n\tunsigned int max_keysize;\n\tunsigned int ivsize;\n\tunsigned int chunksize;\n\tunsigned int walksize;\n\tstruct crypto_alg base;\n};\n\nstruct fscrypt_context_v1 {\n\tu8 version;\n\tu8 contents_encryption_mode;\n\tu8 filenames_encryption_mode;\n\tu8 flags;\n\tu8 master_key_descriptor[8];\n\tu8 nonce[16];\n};\n\nstruct fscrypt_context_v2 {\n\tu8 version;\n\tu8 contents_encryption_mode;\n\tu8 filenames_encryption_mode;\n\tu8 flags;\n\tu8 __reserved[4];\n\tu8 master_key_identifier[16];\n\tu8 nonce[16];\n};\n\nunion fscrypt_context {\n\tu8 version;\n\tstruct fscrypt_context_v1 v1;\n\tstruct fscrypt_context_v2 v2;\n};\n\nstruct crypto_template;\n\nstruct crypto_spawn;\n\nstruct crypto_instance {\n\tstruct crypto_alg alg;\n\tstruct crypto_template *tmpl;\n\tunion {\n\t\tstruct hlist_node list;\n\t\tstruct crypto_spawn *spawns;\n\t};\n\tvoid *__ctx[0];\n};\n\nstruct crypto_spawn {\n\tstruct list_head list;\n\tstruct crypto_alg *alg;\n\tunion {\n\t\tstruct crypto_instance *inst;\n\t\tstruct crypto_spawn *next;\n\t};\n\tconst struct crypto_type *frontend;\n\tu32 mask;\n\tbool dead;\n\tbool registered;\n};\n\nstruct rtattr;\n\nstruct crypto_template {\n\tstruct list_head list;\n\tstruct hlist_head instances;\n\tstruct module *module;\n\tint (*create)(struct crypto_template *, struct rtattr **);\n\tchar name[128];\n};\n\nstruct user_key_payload {\n\tstruct callback_head rcu;\n\tshort unsigned int datalen;\n\tlong: 48;\n\tchar data[0];\n};\n\nstruct fscrypt_key {\n\t__u32 mode;\n\t__u8 raw[64];\n\t__u32 size;\n};\n\nstruct fscrypt_direct_key {\n\tstruct hlist_node dk_node;\n\trefcount_t dk_refcount;\n\tconst struct fscrypt_mode *dk_mode;\n\tstruct fscrypt_prepared_key dk_key;\n\tu8 dk_descriptor[8];\n\tu8 dk_raw[64];\n};\n\nstruct fscrypt_get_policy_ex_arg {\n\t__u64 policy_size;\n\tunion {\n\t\t__u8 version;\n\t\tstruct fscrypt_policy_v1 v1;\n\t\tstruct fscrypt_policy_v2 v2;\n\t} policy;\n};\n\nstruct fscrypt_dummy_policy {\n\tconst union fscrypt_policy *policy;\n};\n\nstruct fscrypt_blk_crypto_key {\n\tstruct blk_crypto_key base;\n\tint num_devs;\n\tstruct request_queue *devs[0];\n};\n\nstruct fsverity_hash_alg;\n\nstruct merkle_tree_params {\n\tstruct fsverity_hash_alg *hash_alg;\n\tconst u8 *hashstate;\n\tunsigned int digest_size;\n\tunsigned int block_size;\n\tunsigned int hashes_per_block;\n\tunsigned int log_blocksize;\n\tunsigned int log_arity;\n\tunsigned int num_levels;\n\tu64 tree_size;\n\tlong unsigned int level0_blocks;\n\tu64 level_start[8];\n};\n\nstruct fsverity_info {\n\tstruct merkle_tree_params tree_params;\n\tu8 root_hash[64];\n\tu8 file_digest[64];\n\tconst struct inode *inode;\n};\n\nstruct fsverity_enable_arg {\n\t__u32 version;\n\t__u32 hash_algorithm;\n\t__u32 block_size;\n\t__u32 salt_size;\n\t__u64 salt_ptr;\n\t__u32 sig_size;\n\t__u32 __reserved1;\n\t__u64 sig_ptr;\n\t__u64 __reserved2[11];\n};\n\nstruct fsverity_descriptor {\n\t__u8 version;\n\t__u8 hash_algorithm;\n\t__u8 log_blocksize;\n\t__u8 salt_size;\n\t__le32 sig_size;\n\t__le64 data_size;\n\t__u8 root_hash[64];\n\t__u8 salt[32];\n\t__u8 __reserved[144];\n\t__u8 signature[0];\n};\n\nstruct crypto_ahash;\n\nstruct fsverity_hash_alg {\n\tstruct crypto_ahash *tfm;\n\tconst char *name;\n\tunsigned int digest_size;\n\tunsigned int block_size;\n\tmempool_t req_pool;\n};\n\nstruct ahash_request;\n\nstruct crypto_ahash {\n\tint (*init)(struct ahash_request *);\n\tint (*update)(struct ahash_request *);\n\tint (*final)(struct ahash_request *);\n\tint (*finup)(struct ahash_request *);\n\tint (*digest)(struct ahash_request *);\n\tint (*export)(struct ahash_request *, void *);\n\tint (*import)(struct ahash_request *, const void *);\n\tint (*setkey)(struct crypto_ahash *, const u8 *, unsigned int);\n\tunsigned int reqsize;\n\tstruct crypto_tfm base;\n};\n\nstruct ahash_request {\n\tstruct crypto_async_request base;\n\tunsigned int nbytes;\n\tstruct scatterlist *src;\n\tu8 *result;\n\tvoid *priv;\n\tvoid *__ctx[0];\n};\n\nstruct hash_alg_common {\n\tunsigned int digestsize;\n\tunsigned int statesize;\n\tstruct crypto_alg base;\n};\n\nstruct fsverity_digest {\n\t__u16 digest_algorithm;\n\t__u16 digest_size;\n\t__u8 digest[0];\n};\n\nstruct fsverity_read_metadata_arg {\n\t__u64 metadata_type;\n\t__u64 offset;\n\t__u64 length;\n\t__u64 buf_ptr;\n\t__u64 __reserved;\n};\n\nstruct fsverity_formatted_digest {\n\tchar magic[8];\n\t__le16 digest_algorithm;\n\t__le16 digest_size;\n\t__u8 digest[0];\n};\n\nstruct flock64 {\n\tshort int l_type;\n\tshort int l_whence;\n\t__kernel_loff_t l_start;\n\t__kernel_loff_t l_len;\n\t__kernel_pid_t l_pid;\n};\n\nstruct trace_event_raw_locks_get_lock_context {\n\tstruct trace_entry ent;\n\tlong unsigned int i_ino;\n\tdev_t s_dev;\n\tunsigned char type;\n\tstruct file_lock_context *ctx;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_filelock_lock {\n\tstruct trace_entry ent;\n\tstruct file_lock *fl;\n\tlong unsigned int i_ino;\n\tdev_t s_dev;\n\tstruct file_lock *fl_blocker;\n\tfl_owner_t fl_owner;\n\tunsigned int fl_pid;\n\tunsigned int fl_flags;\n\tunsigned char fl_type;\n\tloff_t fl_start;\n\tloff_t fl_end;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_filelock_lease {\n\tstruct trace_entry ent;\n\tstruct file_lock *fl;\n\tlong unsigned int i_ino;\n\tdev_t s_dev;\n\tstruct file_lock *fl_blocker;\n\tfl_owner_t fl_owner;\n\tunsigned int fl_flags;\n\tunsigned char fl_type;\n\tlong unsigned int fl_break_time;\n\tlong unsigned int fl_downgrade_time;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_generic_add_lease {\n\tstruct trace_entry ent;\n\tlong unsigned int i_ino;\n\tint wcount;\n\tint rcount;\n\tint icount;\n\tdev_t s_dev;\n\tfl_owner_t fl_owner;\n\tunsigned int fl_flags;\n\tunsigned char fl_type;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_leases_conflict {\n\tstruct trace_entry ent;\n\tvoid *lease;\n\tvoid *breaker;\n\tunsigned int l_fl_flags;\n\tunsigned int b_fl_flags;\n\tunsigned char l_fl_type;\n\tunsigned char b_fl_type;\n\tbool conflict;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_locks_get_lock_context {};\n\nstruct trace_event_data_offsets_filelock_lock {};\n\nstruct trace_event_data_offsets_filelock_lease {};\n\nstruct trace_event_data_offsets_generic_add_lease {};\n\nstruct trace_event_data_offsets_leases_conflict {};\n\ntypedef void (*btf_trace_locks_get_lock_context)(void *, struct inode *, int, struct file_lock_context *);\n\ntypedef void (*btf_trace_posix_lock_inode)(void *, struct inode *, struct file_lock *, int);\n\ntypedef void (*btf_trace_fcntl_setlk)(void *, struct inode *, struct file_lock *, int);\n\ntypedef void (*btf_trace_locks_remove_posix)(void *, struct inode *, struct file_lock *, int);\n\ntypedef void (*btf_trace_flock_lock_inode)(void *, struct inode *, struct file_lock *, int);\n\ntypedef void (*btf_trace_break_lease_noblock)(void *, struct inode *, struct file_lock *);\n\ntypedef void (*btf_trace_break_lease_block)(void *, struct inode *, struct file_lock *);\n\ntypedef void (*btf_trace_break_lease_unblock)(void *, struct inode *, struct file_lock *);\n\ntypedef void (*btf_trace_generic_delete_lease)(void *, struct inode *, struct file_lock *);\n\ntypedef void (*btf_trace_time_out_leases)(void *, struct inode *, struct file_lock *);\n\ntypedef void (*btf_trace_generic_add_lease)(void *, struct inode *, struct file_lock *);\n\ntypedef void (*btf_trace_leases_conflict)(void *, bool, struct file_lock *, struct file_lock *);\n\nstruct file_lock_list_struct {\n\tspinlock_t lock;\n\tstruct hlist_head hlist;\n};\n\nstruct locks_iterator {\n\tint li_cpu;\n\tloff_t li_pos;\n};\n\nenum {\n\tVERBOSE_STATUS = 1,\n};\n\nenum {\n\tEnabled = 0,\n\tMagic = 1,\n};\n\ntypedef struct {\n\tstruct list_head list;\n\tlong unsigned int flags;\n\tint offset;\n\tint size;\n\tchar *magic;\n\tchar *mask;\n\tconst char *interpreter;\n\tchar *name;\n\tstruct dentry *dentry;\n\tstruct file *interp_file;\n} Node;\n\ntypedef unsigned int __kernel_uid_t;\n\ntypedef unsigned int __kernel_gid_t;\n\nstruct elf_prpsinfo {\n\tchar pr_state;\n\tchar pr_sname;\n\tchar pr_zomb;\n\tchar pr_nice;\n\tlong unsigned int pr_flag;\n\t__kernel_uid_t pr_uid;\n\t__kernel_gid_t pr_gid;\n\tpid_t pr_pid;\n\tpid_t pr_ppid;\n\tpid_t pr_pgrp;\n\tpid_t pr_sid;\n\tchar pr_fname[16];\n\tchar pr_psargs[80];\n};\n\nstruct core_vma_metadata {\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tlong unsigned int flags;\n\tlong unsigned int dump_size;\n};\n\nstruct arch_elf_state {};\n\nstruct memelfnote {\n\tconst char *name;\n\tint type;\n\tunsigned int datasz;\n\tvoid *data;\n};\n\nstruct elf_thread_core_info {\n\tstruct elf_thread_core_info *next;\n\tstruct task_struct *task;\n\tstruct elf_prstatus prstatus;\n\tstruct memelfnote notes[0];\n};\n\nstruct elf_note_info {\n\tstruct elf_thread_core_info *thread;\n\tstruct memelfnote psinfo;\n\tstruct memelfnote signote;\n\tstruct memelfnote auxv;\n\tstruct memelfnote files;\n\tsiginfo_t csigdata;\n\tsize_t size;\n\tint thread_notes;\n};\n\nstruct user_regs_struct {\n\tlong unsigned int r15;\n\tlong unsigned int r14;\n\tlong unsigned int r13;\n\tlong unsigned int r12;\n\tlong unsigned int bp;\n\tlong unsigned int bx;\n\tlong unsigned int r11;\n\tlong unsigned int r10;\n\tlong unsigned int r9;\n\tlong unsigned int r8;\n\tlong unsigned int ax;\n\tlong unsigned int cx;\n\tlong unsigned int dx;\n\tlong unsigned int si;\n\tlong unsigned int di;\n\tlong unsigned int orig_ax;\n\tlong unsigned int ip;\n\tlong unsigned int cs;\n\tlong unsigned int flags;\n\tlong unsigned int sp;\n\tlong unsigned int ss;\n\tlong unsigned int fs_base;\n\tlong unsigned int gs_base;\n\tlong unsigned int ds;\n\tlong unsigned int es;\n\tlong unsigned int fs;\n\tlong unsigned int gs;\n};\n\ntypedef __u32 Elf32_Addr;\n\ntypedef __u16 Elf32_Half;\n\ntypedef __u32 Elf32_Off;\n\nstruct elf32_hdr {\n\tunsigned char e_ident[16];\n\tElf32_Half e_type;\n\tElf32_Half e_machine;\n\tElf32_Word e_version;\n\tElf32_Addr e_entry;\n\tElf32_Off e_phoff;\n\tElf32_Off e_shoff;\n\tElf32_Word e_flags;\n\tElf32_Half e_ehsize;\n\tElf32_Half e_phentsize;\n\tElf32_Half e_phnum;\n\tElf32_Half e_shentsize;\n\tElf32_Half e_shnum;\n\tElf32_Half e_shstrndx;\n};\n\nstruct elf32_phdr {\n\tElf32_Word p_type;\n\tElf32_Off p_offset;\n\tElf32_Addr p_vaddr;\n\tElf32_Addr p_paddr;\n\tElf32_Word p_filesz;\n\tElf32_Word p_memsz;\n\tElf32_Word p_flags;\n\tElf32_Word p_align;\n};\n\nstruct elf32_shdr {\n\tElf32_Word sh_name;\n\tElf32_Word sh_type;\n\tElf32_Word sh_flags;\n\tElf32_Addr sh_addr;\n\tElf32_Off sh_offset;\n\tElf32_Word sh_size;\n\tElf32_Word sh_link;\n\tElf32_Word sh_info;\n\tElf32_Word sh_addralign;\n\tElf32_Word sh_entsize;\n};\n\nstruct user_regs_struct32 {\n\t__u32 ebx;\n\t__u32 ecx;\n\t__u32 edx;\n\t__u32 esi;\n\t__u32 edi;\n\t__u32 ebp;\n\t__u32 eax;\n\tshort unsigned int ds;\n\tshort unsigned int __ds;\n\tshort unsigned int es;\n\tshort unsigned int __es;\n\tshort unsigned int fs;\n\tshort unsigned int __fs;\n\tshort unsigned int gs;\n\tshort unsigned int __gs;\n\t__u32 orig_eax;\n\t__u32 eip;\n\tshort unsigned int cs;\n\tshort unsigned int __cs;\n\t__u32 eflags;\n\t__u32 esp;\n\tshort unsigned int ss;\n\tshort unsigned int __ss;\n};\n\nstruct compat_elf_siginfo {\n\tcompat_int_t si_signo;\n\tcompat_int_t si_code;\n\tcompat_int_t si_errno;\n};\n\nstruct compat_elf_prstatus_common {\n\tstruct compat_elf_siginfo pr_info;\n\tshort int pr_cursig;\n\tcompat_ulong_t pr_sigpend;\n\tcompat_ulong_t pr_sighold;\n\tcompat_pid_t pr_pid;\n\tcompat_pid_t pr_ppid;\n\tcompat_pid_t pr_pgrp;\n\tcompat_pid_t pr_sid;\n\tstruct old_timeval32 pr_utime;\n\tstruct old_timeval32 pr_stime;\n\tstruct old_timeval32 pr_cutime;\n\tstruct old_timeval32 pr_cstime;\n};\n\nstruct compat_elf_prpsinfo {\n\tchar pr_state;\n\tchar pr_sname;\n\tchar pr_zomb;\n\tchar pr_nice;\n\tcompat_ulong_t pr_flag;\n\t__compat_uid_t pr_uid;\n\t__compat_gid_t pr_gid;\n\tcompat_pid_t pr_pid;\n\tcompat_pid_t pr_ppid;\n\tcompat_pid_t pr_pgrp;\n\tcompat_pid_t pr_sid;\n\tchar pr_fname[16];\n\tchar pr_psargs[80];\n};\n\ntypedef struct user_regs_struct compat_elf_gregset_t;\n\nstruct i386_elf_prstatus {\n\tstruct compat_elf_prstatus_common common;\n\tstruct user_regs_struct32 pr_reg;\n\tcompat_int_t pr_fpvalid;\n};\n\nstruct compat_elf_prstatus {\n\tstruct compat_elf_prstatus_common common;\n\tcompat_elf_gregset_t pr_reg;\n\tcompat_int_t pr_fpvalid;\n};\n\nstruct elf_thread_core_info___2 {\n\tstruct elf_thread_core_info___2 *next;\n\tstruct task_struct *task;\n\tstruct compat_elf_prstatus prstatus;\n\tstruct memelfnote notes[0];\n};\n\nstruct elf_note_info___2 {\n\tstruct elf_thread_core_info___2 *thread;\n\tstruct memelfnote psinfo;\n\tstruct memelfnote signote;\n\tstruct memelfnote auxv;\n\tstruct memelfnote files;\n\tcompat_siginfo_t csigdata;\n\tsize_t size;\n\tint thread_notes;\n};\n\nstruct posix_acl_xattr_entry {\n\t__le16 e_tag;\n\t__le16 e_perm;\n\t__le32 e_id;\n};\n\nstruct posix_acl_xattr_header {\n\t__le32 a_version;\n};\n\nstruct rpc_timer {\n\tstruct list_head list;\n\tlong unsigned int expires;\n\tstruct delayed_work dwork;\n};\n\nstruct rpc_wait_queue {\n\tspinlock_t lock;\n\tstruct list_head tasks[4];\n\tunsigned char maxpriority;\n\tunsigned char priority;\n\tunsigned char nr;\n\tshort unsigned int qlen;\n\tstruct rpc_timer timer_list;\n\tconst char *name;\n};\n\nstruct nfs_seqid_counter {\n\tktime_t create_time;\n\tint owner_id;\n\tint flags;\n\tu32 counter;\n\tspinlock_t lock;\n\tstruct list_head list;\n\tstruct rpc_wait_queue wait;\n};\n\nstruct nfs4_stateid_struct {\n\tunion {\n\t\tchar data[16];\n\t\tstruct {\n\t\t\t__be32 seqid;\n\t\t\tchar other[12];\n\t\t};\n\t};\n\tenum {\n\t\tNFS4_INVALID_STATEID_TYPE = 0,\n\t\tNFS4_SPECIAL_STATEID_TYPE = 1,\n\t\tNFS4_OPEN_STATEID_TYPE = 2,\n\t\tNFS4_LOCK_STATEID_TYPE = 3,\n\t\tNFS4_DELEGATION_STATEID_TYPE = 4,\n\t\tNFS4_LAYOUT_STATEID_TYPE = 5,\n\t\tNFS4_PNFS_DS_STATEID_TYPE = 6,\n\t\tNFS4_REVOKED_STATEID_TYPE = 7,\n\t} type;\n};\n\ntypedef struct nfs4_stateid_struct nfs4_stateid;\n\nstruct nfs4_state;\n\nstruct nfs4_lock_state {\n\tstruct list_head ls_locks;\n\tstruct nfs4_state *ls_state;\n\tlong unsigned int ls_flags;\n\tstruct nfs_seqid_counter ls_seqid;\n\tnfs4_stateid ls_stateid;\n\trefcount_t ls_count;\n\tfl_owner_t ls_owner;\n};\n\nstruct xdr_netobj {\n\tunsigned int len;\n\tu8 *data;\n};\n\nstruct xdr_buf {\n\tstruct kvec head[1];\n\tstruct kvec tail[1];\n\tstruct bio_vec *bvec;\n\tstruct page **pages;\n\tunsigned int page_base;\n\tunsigned int page_len;\n\tunsigned int flags;\n\tunsigned int buflen;\n\tunsigned int len;\n};\n\nstruct rpc_rqst;\n\nstruct xdr_stream {\n\t__be32 *p;\n\tstruct xdr_buf *buf;\n\t__be32 *end;\n\tstruct kvec *iov;\n\tstruct kvec scratch;\n\tstruct page **page_ptr;\n\tunsigned int nwords;\n\tstruct rpc_rqst *rqst;\n};\n\nstruct rpc_xprt;\n\nstruct rpc_task;\n\nstruct rpc_cred;\n\nstruct rpc_rqst {\n\tstruct rpc_xprt *rq_xprt;\n\tstruct xdr_buf rq_snd_buf;\n\tstruct xdr_buf rq_rcv_buf;\n\tstruct rpc_task *rq_task;\n\tstruct rpc_cred *rq_cred;\n\t__be32 rq_xid;\n\tint rq_cong;\n\tu32 rq_seqno;\n\tint rq_enc_pages_num;\n\tstruct page **rq_enc_pages;\n\tvoid (*rq_release_snd_buf)(struct rpc_rqst *);\n\tunion {\n\t\tstruct list_head rq_list;\n\t\tstruct rb_node rq_recv;\n\t};\n\tstruct list_head rq_xmit;\n\tstruct list_head rq_xmit2;\n\tvoid *rq_buffer;\n\tsize_t rq_callsize;\n\tvoid *rq_rbuffer;\n\tsize_t rq_rcvsize;\n\tsize_t rq_xmit_bytes_sent;\n\tsize_t rq_reply_bytes_recvd;\n\tstruct xdr_buf rq_private_buf;\n\tlong unsigned int rq_majortimeo;\n\tlong unsigned int rq_minortimeo;\n\tlong unsigned int rq_timeout;\n\tktime_t rq_rtt;\n\tunsigned int rq_retries;\n\tunsigned int rq_connect_cookie;\n\tatomic_t rq_pin;\n\tu32 rq_bytes_sent;\n\tktime_t rq_xtime;\n\tint rq_ntrans;\n\tstruct list_head rq_bc_list;\n\tlong unsigned int rq_bc_pa_state;\n\tstruct list_head rq_bc_pa_list;\n};\n\ntypedef void (*kxdreproc_t)(struct rpc_rqst *, struct xdr_stream *, const void *);\n\ntypedef int (*kxdrdproc_t)(struct rpc_rqst *, struct xdr_stream *, void *);\n\nstruct rpc_procinfo;\n\nstruct rpc_message {\n\tconst struct rpc_procinfo *rpc_proc;\n\tvoid *rpc_argp;\n\tvoid *rpc_resp;\n\tconst struct cred *rpc_cred;\n};\n\nstruct rpc_procinfo {\n\tu32 p_proc;\n\tkxdreproc_t p_encode;\n\tkxdrdproc_t p_decode;\n\tunsigned int p_arglen;\n\tunsigned int p_replen;\n\tunsigned int p_timer;\n\tu32 p_statidx;\n\tconst char *p_name;\n};\n\nstruct rpc_wait {\n\tstruct list_head list;\n\tstruct list_head links;\n\tstruct list_head timer_list;\n};\n\nstruct rpc_call_ops;\n\nstruct rpc_clnt;\n\nstruct rpc_task {\n\tatomic_t tk_count;\n\tint tk_status;\n\tstruct list_head tk_task;\n\tvoid (*tk_callback)(struct rpc_task *);\n\tvoid (*tk_action)(struct rpc_task *);\n\tlong unsigned int tk_timeout;\n\tlong unsigned int tk_runstate;\n\tstruct rpc_wait_queue *tk_waitqueue;\n\tunion {\n\t\tstruct work_struct tk_work;\n\t\tstruct rpc_wait tk_wait;\n\t} u;\n\tint tk_rpc_status;\n\tstruct rpc_message tk_msg;\n\tvoid *tk_calldata;\n\tconst struct rpc_call_ops *tk_ops;\n\tstruct rpc_clnt *tk_client;\n\tstruct rpc_xprt *tk_xprt;\n\tstruct rpc_cred *tk_op_cred;\n\tstruct rpc_rqst *tk_rqstp;\n\tstruct workqueue_struct *tk_workqueue;\n\tktime_t tk_start;\n\tpid_t tk_owner;\n\tshort unsigned int tk_flags;\n\tshort unsigned int tk_timeouts;\n\tshort unsigned int tk_pid;\n\tunsigned char tk_priority: 2;\n\tunsigned char tk_garb_retry: 2;\n\tunsigned char tk_cred_retry: 2;\n\tunsigned char tk_rebind_retry: 2;\n};\n\nstruct rpc_call_ops {\n\tvoid (*rpc_call_prepare)(struct rpc_task *, void *);\n\tvoid (*rpc_call_done)(struct rpc_task *, void *);\n\tvoid (*rpc_count_stats)(struct rpc_task *, void *);\n\tvoid (*rpc_release)(void *);\n};\n\nstruct rpc_iostats;\n\nstruct rpc_pipe_dir_head {\n\tstruct list_head pdh_entries;\n\tstruct dentry *pdh_dentry;\n};\n\nstruct rpc_rtt {\n\tlong unsigned int timeo;\n\tlong unsigned int srtt[5];\n\tlong unsigned int sdrtt[5];\n\tint ntimeouts[5];\n};\n\nstruct rpc_timeout {\n\tlong unsigned int to_initval;\n\tlong unsigned int to_maxval;\n\tlong unsigned int to_increment;\n\tunsigned int to_retries;\n\tunsigned char to_exponential;\n};\n\nstruct rpc_sysfs_client;\n\nstruct rpc_xprt_switch;\n\nstruct rpc_xprt_iter_ops;\n\nstruct rpc_xprt_iter {\n\tstruct rpc_xprt_switch *xpi_xpswitch;\n\tstruct rpc_xprt *xpi_cursor;\n\tconst struct rpc_xprt_iter_ops *xpi_ops;\n};\n\nstruct rpc_auth;\n\nstruct rpc_stat;\n\nstruct rpc_program;\n\nstruct rpc_clnt {\n\tatomic_t cl_count;\n\tunsigned int cl_clid;\n\tstruct list_head cl_clients;\n\tstruct list_head cl_tasks;\n\tspinlock_t cl_lock;\n\tstruct rpc_xprt *cl_xprt;\n\tconst struct rpc_procinfo *cl_procinfo;\n\tu32 cl_prog;\n\tu32 cl_vers;\n\tu32 cl_maxproc;\n\tstruct rpc_auth *cl_auth;\n\tstruct rpc_stat *cl_stats;\n\tstruct rpc_iostats *cl_metrics;\n\tunsigned int cl_softrtry: 1;\n\tunsigned int cl_softerr: 1;\n\tunsigned int cl_discrtry: 1;\n\tunsigned int cl_noretranstimeo: 1;\n\tunsigned int cl_autobind: 1;\n\tunsigned int cl_chatty: 1;\n\tstruct rpc_rtt *cl_rtt;\n\tconst struct rpc_timeout *cl_timeout;\n\tatomic_t cl_swapper;\n\tint cl_nodelen;\n\tchar cl_nodename[65];\n\tstruct rpc_pipe_dir_head cl_pipedir_objects;\n\tstruct rpc_clnt *cl_parent;\n\tstruct rpc_rtt cl_rtt_default;\n\tstruct rpc_timeout cl_timeout_default;\n\tconst struct rpc_program *cl_program;\n\tconst char *cl_principal;\n\tstruct dentry *cl_debugfs;\n\tstruct rpc_sysfs_client *cl_sysfs;\n\tunion {\n\t\tstruct rpc_xprt_iter cl_xpi;\n\t\tstruct work_struct cl_work;\n\t};\n\tconst struct cred *cl_cred;\n};\n\nstruct svc_xprt;\n\nstruct rpc_sysfs_xprt;\n\nstruct rpc_xprt_ops;\n\nstruct svc_serv;\n\nstruct xprt_class;\n\nstruct rpc_xprt {\n\tstruct kref kref;\n\tconst struct rpc_xprt_ops *ops;\n\tunsigned int id;\n\tconst struct rpc_timeout *timeout;\n\tstruct __kernel_sockaddr_storage addr;\n\tsize_t addrlen;\n\tint prot;\n\tlong unsigned int cong;\n\tlong unsigned int cwnd;\n\tsize_t max_payload;\n\tstruct rpc_wait_queue binding;\n\tstruct rpc_wait_queue sending;\n\tstruct rpc_wait_queue pending;\n\tstruct rpc_wait_queue backlog;\n\tstruct list_head free;\n\tunsigned int max_reqs;\n\tunsigned int min_reqs;\n\tunsigned int num_reqs;\n\tlong unsigned int state;\n\tunsigned char resvport: 1;\n\tunsigned char reuseport: 1;\n\tatomic_t swapper;\n\tunsigned int bind_index;\n\tstruct list_head xprt_switch;\n\tlong unsigned int bind_timeout;\n\tlong unsigned int reestablish_timeout;\n\tunsigned int connect_cookie;\n\tstruct work_struct task_cleanup;\n\tstruct timer_list timer;\n\tlong unsigned int last_used;\n\tlong unsigned int idle_timeout;\n\tlong unsigned int connect_timeout;\n\tlong unsigned int max_reconnect_timeout;\n\tatomic_long_t queuelen;\n\tspinlock_t transport_lock;\n\tspinlock_t reserve_lock;\n\tspinlock_t queue_lock;\n\tu32 xid;\n\tstruct rpc_task *snd_task;\n\tstruct list_head xmit_queue;\n\tatomic_long_t xmit_queuelen;\n\tstruct svc_xprt *bc_xprt;\n\tstruct svc_serv *bc_serv;\n\tunsigned int bc_alloc_max;\n\tunsigned int bc_alloc_count;\n\tatomic_t bc_slot_count;\n\tspinlock_t bc_pa_lock;\n\tstruct list_head bc_pa_list;\n\tstruct rb_root recv_queue;\n\tstruct {\n\t\tlong unsigned int bind_count;\n\t\tlong unsigned int connect_count;\n\t\tlong unsigned int connect_start;\n\t\tlong unsigned int connect_time;\n\t\tlong unsigned int sends;\n\t\tlong unsigned int recvs;\n\t\tlong unsigned int bad_xids;\n\t\tlong unsigned int max_slots;\n\t\tlong long unsigned int req_u;\n\t\tlong long unsigned int bklog_u;\n\t\tlong long unsigned int sending_u;\n\t\tlong long unsigned int pending_u;\n\t} stat;\n\tstruct net *xprt_net;\n\tconst char *servername;\n\tconst char *address_strings[6];\n\tstruct dentry *debugfs;\n\tatomic_t inject_disconnect;\n\tstruct callback_head rcu;\n\tconst struct xprt_class *xprt_class;\n\tstruct rpc_sysfs_xprt *xprt_sysfs;\n\tbool main;\n};\n\nstruct rpc_credops;\n\nstruct rpc_cred {\n\tstruct hlist_node cr_hash;\n\tstruct list_head cr_lru;\n\tstruct callback_head cr_rcu;\n\tstruct rpc_auth *cr_auth;\n\tconst struct rpc_credops *cr_ops;\n\tlong unsigned int cr_expire;\n\tlong unsigned int cr_flags;\n\trefcount_t cr_count;\n\tconst struct cred *cr_cred;\n};\n\ntypedef u32 rpc_authflavor_t;\n\nstruct auth_cred {\n\tconst struct cred *cred;\n\tconst char *principal;\n};\n\nstruct rpc_cred_cache;\n\nstruct rpc_authops;\n\nstruct rpc_auth {\n\tunsigned int au_cslack;\n\tunsigned int au_rslack;\n\tunsigned int au_verfsize;\n\tunsigned int au_ralign;\n\tlong unsigned int au_flags;\n\tconst struct rpc_authops *au_ops;\n\trpc_authflavor_t au_flavor;\n\trefcount_t au_count;\n\tstruct rpc_cred_cache *au_credcache;\n};\n\nstruct rpc_credops {\n\tconst char *cr_name;\n\tint (*cr_init)(struct rpc_auth *, struct rpc_cred *);\n\tvoid (*crdestroy)(struct rpc_cred *);\n\tint (*crmatch)(struct auth_cred *, struct rpc_cred *, int);\n\tint (*crmarshal)(struct rpc_task *, struct xdr_stream *);\n\tint (*crrefresh)(struct rpc_task *);\n\tint (*crvalidate)(struct rpc_task *, struct xdr_stream *);\n\tint (*crwrap_req)(struct rpc_task *, struct xdr_stream *);\n\tint (*crunwrap_resp)(struct rpc_task *, struct xdr_stream *);\n\tint (*crkey_timeout)(struct rpc_cred *);\n\tchar * (*crstringify_acceptor)(struct rpc_cred *);\n\tbool (*crneed_reencode)(struct rpc_task *);\n};\n\nstruct rpc_auth_create_args;\n\nstruct rpcsec_gss_info;\n\nstruct rpc_authops {\n\tstruct module *owner;\n\trpc_authflavor_t au_flavor;\n\tchar *au_name;\n\tstruct rpc_auth * (*create)(const struct rpc_auth_create_args *, struct rpc_clnt *);\n\tvoid (*destroy)(struct rpc_auth *);\n\tint (*hash_cred)(struct auth_cred *, unsigned int);\n\tstruct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);\n\tstruct rpc_cred * (*crcreate)(struct rpc_auth *, struct auth_cred *, int, gfp_t);\n\trpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);\n\tint (*flavor2info)(rpc_authflavor_t, struct rpcsec_gss_info *);\n\tint (*key_timeout)(struct rpc_auth *, struct rpc_cred *);\n};\n\nstruct rpc_auth_create_args {\n\trpc_authflavor_t pseudoflavor;\n\tconst char *target_name;\n};\n\nstruct rpcsec_gss_oid {\n\tunsigned int len;\n\tu8 data[32];\n};\n\nstruct rpcsec_gss_info {\n\tstruct rpcsec_gss_oid oid;\n\tu32 qop;\n\tu32 service;\n};\n\nstruct rpc_xprt_ops {\n\tvoid (*set_buffer_size)(struct rpc_xprt *, size_t, size_t);\n\tint (*reserve_xprt)(struct rpc_xprt *, struct rpc_task *);\n\tvoid (*release_xprt)(struct rpc_xprt *, struct rpc_task *);\n\tvoid (*alloc_slot)(struct rpc_xprt *, struct rpc_task *);\n\tvoid (*free_slot)(struct rpc_xprt *, struct rpc_rqst *);\n\tvoid (*rpcbind)(struct rpc_task *);\n\tvoid (*set_port)(struct rpc_xprt *, short unsigned int);\n\tvoid (*connect)(struct rpc_xprt *, struct rpc_task *);\n\tint (*buf_alloc)(struct rpc_task *);\n\tvoid (*buf_free)(struct rpc_task *);\n\tvoid (*prepare_request)(struct rpc_rqst *);\n\tint (*send_request)(struct rpc_rqst *);\n\tvoid (*wait_for_reply_request)(struct rpc_task *);\n\tvoid (*timer)(struct rpc_xprt *, struct rpc_task *);\n\tvoid (*release_request)(struct rpc_task *);\n\tvoid (*close)(struct rpc_xprt *);\n\tvoid (*destroy)(struct rpc_xprt *);\n\tvoid (*set_connect_timeout)(struct rpc_xprt *, long unsigned int, long unsigned int);\n\tvoid (*print_stats)(struct rpc_xprt *, struct seq_file *);\n\tint (*enable_swap)(struct rpc_xprt *);\n\tvoid (*disable_swap)(struct rpc_xprt *);\n\tvoid (*inject_disconnect)(struct rpc_xprt *);\n\tint (*bc_setup)(struct rpc_xprt *, unsigned int);\n\tsize_t (*bc_maxpayload)(struct rpc_xprt *);\n\tunsigned int (*bc_num_slots)(struct rpc_xprt *);\n\tvoid (*bc_free_rqst)(struct rpc_rqst *);\n\tvoid (*bc_destroy)(struct rpc_xprt *, unsigned int);\n};\n\nstruct svc_program;\n\nstruct svc_stat;\n\nstruct svc_pool;\n\nstruct svc_serv_ops;\n\nstruct svc_serv {\n\tstruct svc_program *sv_program;\n\tstruct svc_stat *sv_stats;\n\tspinlock_t sv_lock;\n\tunsigned int sv_nrthreads;\n\tunsigned int sv_maxconn;\n\tunsigned int sv_max_payload;\n\tunsigned int sv_max_mesg;\n\tunsigned int sv_xdrsize;\n\tstruct list_head sv_permsocks;\n\tstruct list_head sv_tempsocks;\n\tint sv_tmpcnt;\n\tstruct timer_list sv_temptimer;\n\tchar *sv_name;\n\tunsigned int sv_nrpools;\n\tstruct svc_pool *sv_pools;\n\tconst struct svc_serv_ops *sv_ops;\n\tstruct list_head sv_cb_list;\n\tspinlock_t sv_cb_lock;\n\twait_queue_head_t sv_cb_waitq;\n\tbool sv_bc_enabled;\n};\n\nstruct xprt_create;\n\nstruct xprt_class {\n\tstruct list_head list;\n\tint ident;\n\tstruct rpc_xprt * (*setup)(struct xprt_create *);\n\tstruct module *owner;\n\tchar name[32];\n\tconst char *netid[0];\n};\n\nstruct xprt_create {\n\tint ident;\n\tstruct net *net;\n\tstruct sockaddr *srcaddr;\n\tstruct sockaddr *dstaddr;\n\tsize_t addrlen;\n\tconst char *servername;\n\tstruct svc_xprt *bc_xprt;\n\tstruct rpc_xprt_switch *bc_xps;\n\tunsigned int flags;\n};\n\nstruct rpc_sysfs_xprt_switch;\n\nstruct rpc_xprt_switch {\n\tspinlock_t xps_lock;\n\tstruct kref xps_kref;\n\tunsigned int xps_id;\n\tunsigned int xps_nxprts;\n\tunsigned int xps_nactive;\n\tatomic_long_t xps_queuelen;\n\tstruct list_head xps_xprt_list;\n\tstruct net *xps_net;\n\tconst struct rpc_xprt_iter_ops *xps_iter_ops;\n\tstruct rpc_sysfs_xprt_switch *xps_sysfs;\n\tstruct callback_head xps_rcu;\n};\n\nstruct rpc_stat {\n\tconst struct rpc_program *program;\n\tunsigned int netcnt;\n\tunsigned int netudpcnt;\n\tunsigned int nettcpcnt;\n\tunsigned int nettcpconn;\n\tunsigned int netreconn;\n\tunsigned int rpccnt;\n\tunsigned int rpcretrans;\n\tunsigned int rpcauthrefresh;\n\tunsigned int rpcgarbage;\n};\n\nstruct rpc_version;\n\nstruct rpc_program {\n\tconst char *name;\n\tu32 number;\n\tunsigned int nrvers;\n\tconst struct rpc_version **version;\n\tstruct rpc_stat *stats;\n\tconst char *pipe_dir_name;\n};\n\nstruct svc_stat {\n\tstruct svc_program *program;\n\tunsigned int netcnt;\n\tunsigned int netudpcnt;\n\tunsigned int nettcpcnt;\n\tunsigned int nettcpconn;\n\tunsigned int rpccnt;\n\tunsigned int rpcbadfmt;\n\tunsigned int rpcbadauth;\n\tunsigned int rpcbadclnt;\n};\n\nstruct svc_version;\n\nstruct svc_rqst;\n\nstruct svc_process_info;\n\nstruct svc_program {\n\tstruct svc_program *pg_next;\n\tu32 pg_prog;\n\tunsigned int pg_lovers;\n\tunsigned int pg_hivers;\n\tunsigned int pg_nvers;\n\tconst struct svc_version **pg_vers;\n\tchar *pg_name;\n\tchar *pg_class;\n\tstruct svc_stat *pg_stats;\n\tint (*pg_authenticate)(struct svc_rqst *);\n\t__be32 (*pg_init_request)(struct svc_rqst *, const struct svc_program *, struct svc_process_info *);\n\tint (*pg_rpcbind_set)(struct net *, const struct svc_program *, u32, int, short unsigned int, short unsigned int);\n};\n\nstruct rpc_xprt_iter_ops {\n\tvoid (*xpi_rewind)(struct rpc_xprt_iter *);\n\tstruct rpc_xprt * (*xpi_xprt)(struct rpc_xprt_iter *);\n\tstruct rpc_xprt * (*xpi_next)(struct rpc_xprt_iter *);\n};\n\nstruct rpc_version {\n\tu32 number;\n\tunsigned int nrprocs;\n\tconst struct rpc_procinfo *procs;\n\tunsigned int *counts;\n};\n\nstruct nfs_fh {\n\tshort unsigned int size;\n\tunsigned char data[128];\n};\n\nenum nfs3_stable_how {\n\tNFS_UNSTABLE = 0,\n\tNFS_DATA_SYNC = 1,\n\tNFS_FILE_SYNC = 2,\n\tNFS_INVALID_STABLE_HOW = 4294967295,\n};\n\nstruct nfs4_label {\n\tuint32_t lfs;\n\tuint32_t pi;\n\tu32 len;\n\tchar *label;\n};\n\ntypedef struct {\n\tchar data[8];\n} nfs4_verifier;\n\nenum nfs4_change_attr_type {\n\tNFS4_CHANGE_TYPE_IS_MONOTONIC_INCR = 0,\n\tNFS4_CHANGE_TYPE_IS_VERSION_COUNTER = 1,\n\tNFS4_CHANGE_TYPE_IS_VERSION_COUNTER_NOPNFS = 2,\n\tNFS4_CHANGE_TYPE_IS_TIME_METADATA = 3,\n\tNFS4_CHANGE_TYPE_IS_UNDEFINED = 4,\n};\n\nstruct gss_api_mech;\n\nstruct gss_ctx {\n\tstruct gss_api_mech *mech_type;\n\tvoid *internal_ctx_id;\n\tunsigned int slack;\n\tunsigned int align;\n};\n\nstruct gss_api_ops;\n\nstruct pf_desc;\n\nstruct gss_api_mech {\n\tstruct list_head gm_list;\n\tstruct module *gm_owner;\n\tstruct rpcsec_gss_oid gm_oid;\n\tchar *gm_name;\n\tconst struct gss_api_ops *gm_ops;\n\tint gm_pf_num;\n\tstruct pf_desc *gm_pfs;\n\tconst char *gm_upcall_enctypes;\n};\n\nstruct auth_domain;\n\nstruct pf_desc {\n\tu32 pseudoflavor;\n\tu32 qop;\n\tu32 service;\n\tchar *name;\n\tchar *auth_domain_name;\n\tstruct auth_domain *domain;\n\tbool datatouch;\n};\n\nstruct auth_ops;\n\nstruct auth_domain {\n\tstruct kref ref;\n\tstruct hlist_node hash;\n\tchar *name;\n\tstruct auth_ops *flavour;\n\tstruct callback_head callback_head;\n};\n\nstruct gss_api_ops {\n\tint (*gss_import_sec_context)(const void *, size_t, struct gss_ctx *, time64_t *, gfp_t);\n\tu32 (*gss_get_mic)(struct gss_ctx *, struct xdr_buf *, struct xdr_netobj *);\n\tu32 (*gss_verify_mic)(struct gss_ctx *, struct xdr_buf *, struct xdr_netobj *);\n\tu32 (*gss_wrap)(struct gss_ctx *, int, struct xdr_buf *, struct page **);\n\tu32 (*gss_unwrap)(struct gss_ctx *, int, int, struct xdr_buf *);\n\tvoid (*gss_delete_sec_context)(void *);\n};\n\nstruct nfs4_string {\n\tunsigned int len;\n\tchar *data;\n};\n\nstruct nfs_fsid {\n\tuint64_t major;\n\tuint64_t minor;\n};\n\nstruct nfs4_threshold {\n\t__u32 bm;\n\t__u32 l_type;\n\t__u64 rd_sz;\n\t__u64 wr_sz;\n\t__u64 rd_io_sz;\n\t__u64 wr_io_sz;\n};\n\nstruct nfs_fattr {\n\tunsigned int valid;\n\tumode_t mode;\n\t__u32 nlink;\n\tkuid_t uid;\n\tkgid_t gid;\n\tdev_t rdev;\n\t__u64 size;\n\tunion {\n\t\tstruct {\n\t\t\t__u32 blocksize;\n\t\t\t__u32 blocks;\n\t\t} nfs2;\n\t\tstruct {\n\t\t\t__u64 used;\n\t\t} nfs3;\n\t} du;\n\tstruct nfs_fsid fsid;\n\t__u64 fileid;\n\t__u64 mounted_on_fileid;\n\tstruct timespec64 atime;\n\tstruct timespec64 mtime;\n\tstruct timespec64 ctime;\n\t__u64 change_attr;\n\t__u64 pre_change_attr;\n\t__u64 pre_size;\n\tstruct timespec64 pre_mtime;\n\tstruct timespec64 pre_ctime;\n\tlong unsigned int time_start;\n\tlong unsigned int gencount;\n\tstruct nfs4_string *owner_name;\n\tstruct nfs4_string *group_name;\n\tstruct nfs4_threshold *mdsthreshold;\n\tstruct nfs4_label *label;\n};\n\nstruct nfs_fsinfo {\n\tstruct nfs_fattr *fattr;\n\t__u32 rtmax;\n\t__u32 rtpref;\n\t__u32 rtmult;\n\t__u32 wtmax;\n\t__u32 wtpref;\n\t__u32 wtmult;\n\t__u32 dtpref;\n\t__u64 maxfilesize;\n\tstruct timespec64 time_delta;\n\t__u32 lease_time;\n\t__u32 nlayouttypes;\n\t__u32 layouttype[8];\n\t__u32 blksize;\n\t__u32 clone_blksize;\n\tenum nfs4_change_attr_type change_attr_type;\n\t__u32 xattr_support;\n};\n\nstruct nfs_fsstat {\n\tstruct nfs_fattr *fattr;\n\t__u64 tbytes;\n\t__u64 fbytes;\n\t__u64 abytes;\n\t__u64 tfiles;\n\t__u64 ffiles;\n\t__u64 afiles;\n};\n\nstruct nfs_pathconf {\n\tstruct nfs_fattr *fattr;\n\t__u32 max_link;\n\t__u32 max_namelen;\n};\n\nstruct nfs4_change_info {\n\tu32 atomic;\n\tu64 before;\n\tu64 after;\n};\n\nstruct nfs4_slot;\n\nstruct nfs4_sequence_args {\n\tstruct nfs4_slot *sa_slot;\n\tu8 sa_cache_this: 1;\n\tu8 sa_privileged: 1;\n};\n\nstruct nfs4_sequence_res {\n\tstruct nfs4_slot *sr_slot;\n\tlong unsigned int sr_timestamp;\n\tint sr_status;\n\tu32 sr_status_flags;\n\tu32 sr_highest_slotid;\n\tu32 sr_target_highest_slotid;\n};\n\nstruct nfs_open_context;\n\nstruct nfs_lock_context {\n\trefcount_t count;\n\tstruct list_head list;\n\tstruct nfs_open_context *open_context;\n\tfl_owner_t lockowner;\n\tatomic_t io_count;\n\tstruct callback_head callback_head;\n};\n\nstruct nfs_open_context {\n\tstruct nfs_lock_context lock_context;\n\tfl_owner_t flock_owner;\n\tstruct dentry *dentry;\n\tconst struct cred *cred;\n\tstruct rpc_cred *ll_cred;\n\tstruct nfs4_state *state;\n\tfmode_t mode;\n\tlong unsigned int flags;\n\tint error;\n\tstruct list_head list;\n\tstruct nfs4_threshold *mdsthreshold;\n\tstruct callback_head callback_head;\n};\n\nstruct nlm_host;\n\nstruct nfs_iostats;\n\nstruct nfs_auth_info {\n\tunsigned int flavor_len;\n\trpc_authflavor_t flavors[12];\n};\n\nstruct nfs_fscache_key;\n\nstruct fscache_cookie;\n\nstruct pnfs_layoutdriver_type;\n\nstruct nfs_client;\n\nstruct nfs_server {\n\tstruct nfs_client *nfs_client;\n\tstruct list_head client_link;\n\tstruct list_head master_link;\n\tstruct rpc_clnt *client;\n\tstruct rpc_clnt *client_acl;\n\tstruct nlm_host *nlm_host;\n\tstruct nfs_iostats *io_stats;\n\tatomic_long_t writeback;\n\tunsigned int flags;\n\tunsigned int fattr_valid;\n\tunsigned int caps;\n\tunsigned int rsize;\n\tunsigned int rpages;\n\tunsigned int wsize;\n\tunsigned int wpages;\n\tunsigned int wtmult;\n\tunsigned int dtsize;\n\tshort unsigned int port;\n\tunsigned int bsize;\n\tunsigned int gxasize;\n\tunsigned int sxasize;\n\tunsigned int lxasize;\n\tunsigned int acregmin;\n\tunsigned int acregmax;\n\tunsigned int acdirmin;\n\tunsigned int acdirmax;\n\tunsigned int namelen;\n\tunsigned int options;\n\tunsigned int clone_blksize;\n\tenum nfs4_change_attr_type change_attr_type;\n\tstruct nfs_fsid fsid;\n\t__u64 maxfilesize;\n\tstruct timespec64 time_delta;\n\tlong unsigned int mount_time;\n\tstruct super_block *super;\n\tdev_t s_dev;\n\tstruct nfs_auth_info auth_info;\n\tstruct nfs_fscache_key *fscache_key;\n\tstruct fscache_cookie *fscache;\n\tu32 pnfs_blksize;\n\tu32 attr_bitmask[3];\n\tu32 attr_bitmask_nl[3];\n\tu32 exclcreat_bitmask[3];\n\tu32 cache_consistency_bitmask[3];\n\tu32 acl_bitmask;\n\tu32 fh_expire_type;\n\tstruct pnfs_layoutdriver_type *pnfs_curr_ld;\n\tstruct rpc_wait_queue roc_rpcwaitq;\n\tvoid *pnfs_ld_data;\n\tstruct rb_root state_owners;\n\tstruct ida openowner_id;\n\tstruct ida lockowner_id;\n\tstruct list_head state_owners_lru;\n\tstruct list_head layouts;\n\tstruct list_head delegations;\n\tstruct list_head ss_copies;\n\tlong unsigned int mig_gen;\n\tlong unsigned int mig_status;\n\tvoid (*destroy)(struct nfs_server *);\n\tatomic_t active;\n\tstruct __kernel_sockaddr_storage mountd_address;\n\tsize_t mountd_addrlen;\n\tu32 mountd_version;\n\tshort unsigned int mountd_port;\n\tshort unsigned int mountd_protocol;\n\tstruct rpc_wait_queue uoc_rpcwaitq;\n\tunsigned int read_hdrsize;\n\tconst struct cred *cred;\n\tbool has_sec_mnt_opts;\n};\n\nstruct nfs_subversion;\n\nstruct idmap;\n\nstruct nfs4_slot_table;\n\nstruct nfs4_session;\n\nstruct nfs_rpc_ops;\n\nstruct nfs4_minor_version_ops;\n\nstruct nfs41_server_owner;\n\nstruct nfs41_server_scope;\n\nstruct nfs41_impl_id;\n\nstruct nfs_client {\n\trefcount_t cl_count;\n\tatomic_t cl_mds_count;\n\tint cl_cons_state;\n\tlong unsigned int cl_res_state;\n\tlong unsigned int cl_flags;\n\tstruct __kernel_sockaddr_storage cl_addr;\n\tsize_t cl_addrlen;\n\tchar *cl_hostname;\n\tchar *cl_acceptor;\n\tstruct list_head cl_share_link;\n\tstruct list_head cl_superblocks;\n\tstruct rpc_clnt *cl_rpcclient;\n\tconst struct nfs_rpc_ops *rpc_ops;\n\tint cl_proto;\n\tstruct nfs_subversion *cl_nfs_mod;\n\tu32 cl_minorversion;\n\tunsigned int cl_nconnect;\n\tconst char *cl_principal;\n\tstruct list_head cl_ds_clients;\n\tu64 cl_clientid;\n\tnfs4_verifier cl_confirm;\n\tlong unsigned int cl_state;\n\tspinlock_t cl_lock;\n\tlong unsigned int cl_lease_time;\n\tlong unsigned int cl_last_renewal;\n\tstruct delayed_work cl_renewd;\n\tstruct rpc_wait_queue cl_rpcwaitq;\n\tstruct idmap *cl_idmap;\n\tconst char *cl_owner_id;\n\tu32 cl_cb_ident;\n\tconst struct nfs4_minor_version_ops *cl_mvops;\n\tlong unsigned int cl_mig_gen;\n\tstruct nfs4_slot_table *cl_slot_tbl;\n\tu32 cl_seqid;\n\tu32 cl_exchange_flags;\n\tstruct nfs4_session *cl_session;\n\tbool cl_preserve_clid;\n\tstruct nfs41_server_owner *cl_serverowner;\n\tstruct nfs41_server_scope *cl_serverscope;\n\tstruct nfs41_impl_id *cl_implid;\n\tlong unsigned int cl_sp4_flags;\n\twait_queue_head_t cl_lock_waitq;\n\tchar cl_ipaddr[48];\n\tstruct fscache_cookie *fscache;\n\tstruct net *cl_net;\n\tstruct list_head pending_cb_stateids;\n};\n\nstruct pnfs_layout_segment;\n\nstruct nfs_seqid {\n\tstruct nfs_seqid_counter *sequence;\n\tstruct list_head list;\n\tstruct rpc_task *task;\n};\n\nstruct nfs_write_verifier {\n\tchar data[8];\n};\n\nstruct nfs_writeverf {\n\tstruct nfs_write_verifier verifier;\n\tenum nfs3_stable_how committed;\n};\n\nstruct nfs_pgio_args {\n\tstruct nfs4_sequence_args seq_args;\n\tstruct nfs_fh *fh;\n\tstruct nfs_open_context *context;\n\tstruct nfs_lock_context *lock_context;\n\tnfs4_stateid stateid;\n\t__u64 offset;\n\t__u32 count;\n\tunsigned int pgbase;\n\tstruct page **pages;\n\tunion {\n\t\tunsigned int replen;\n\t\tstruct {\n\t\t\tconst u32 *bitmask;\n\t\t\tu32 bitmask_store[3];\n\t\t\tenum nfs3_stable_how stable;\n\t\t};\n\t};\n};\n\nstruct nfs_pgio_res {\n\tstruct nfs4_sequence_res seq_res;\n\tstruct nfs_fattr *fattr;\n\t__u64 count;\n\t__u32 op_status;\n\tunion {\n\t\tstruct {\n\t\t\tunsigned int replen;\n\t\t\tint eof;\n\t\t};\n\t\tstruct {\n\t\t\tstruct nfs_writeverf *verf;\n\t\t\tconst struct nfs_server *server;\n\t\t};\n\t};\n};\n\nstruct nfs_commitargs {\n\tstruct nfs4_sequence_args seq_args;\n\tstruct nfs_fh *fh;\n\t__u64 offset;\n\t__u32 count;\n\tconst u32 *bitmask;\n};\n\nstruct nfs_commitres {\n\tstruct nfs4_sequence_res seq_res;\n\t__u32 op_status;\n\tstruct nfs_fattr *fattr;\n\tstruct nfs_writeverf *verf;\n\tconst struct nfs_server *server;\n};\n\nstruct nfs_removeargs {\n\tstruct nfs4_sequence_args seq_args;\n\tconst struct nfs_fh *fh;\n\tstruct qstr name;\n};\n\nstruct nfs_removeres {\n\tstruct nfs4_sequence_res seq_res;\n\tstruct nfs_server *server;\n\tstruct nfs_fattr *dir_attr;\n\tstruct nfs4_change_info cinfo;\n};\n\nstruct nfs_renameargs {\n\tstruct nfs4_sequence_args seq_args;\n\tconst struct nfs_fh *old_dir;\n\tconst struct nfs_fh *new_dir;\n\tconst struct qstr *old_name;\n\tconst struct qstr *new_name;\n};\n\nstruct nfs_renameres {\n\tstruct nfs4_sequence_res seq_res;\n\tstruct nfs_server *server;\n\tstruct nfs4_change_info old_cinfo;\n\tstruct nfs_fattr *old_fattr;\n\tstruct nfs4_change_info new_cinfo;\n\tstruct nfs_fattr *new_fattr;\n};\n\nstruct nfs_entry {\n\t__u64 ino;\n\t__u64 cookie;\n\t__u64 prev_cookie;\n\tconst char *name;\n\tunsigned int len;\n\tint eof;\n\tstruct nfs_fh *fh;\n\tstruct nfs_fattr *fattr;\n\tstruct nfs4_label *label;\n\tunsigned char d_type;\n\tstruct nfs_server *server;\n};\n\nstruct nfs_readdir_arg {\n\tstruct dentry *dentry;\n\tconst struct cred *cred;\n\t__be32 *verf;\n\tu64 cookie;\n\tstruct page **pages;\n\tunsigned int page_len;\n\tbool plus;\n};\n\nstruct nfs_readdir_res {\n\t__be32 *verf;\n};\n\nstruct nfs4_pathname {\n\tunsigned int ncomponents;\n\tstruct nfs4_string components[512];\n};\n\nstruct nfs4_fs_location {\n\tunsigned int nservers;\n\tstruct nfs4_string servers[10];\n\tstruct nfs4_pathname rootpath;\n};\n\nstruct nfs4_fs_locations {\n\tstruct nfs_fattr fattr;\n\tconst struct nfs_server *server;\n\tstruct nfs4_pathname fs_path;\n\tint nlocations;\n\tstruct nfs4_fs_location locations[10];\n};\n\nstruct nfstime4 {\n\tu64 seconds;\n\tu32 nseconds;\n};\n\nstruct pnfs_commit_ops;\n\nstruct pnfs_ds_commit_info {\n\tstruct list_head commits;\n\tunsigned int nwritten;\n\tunsigned int ncommitting;\n\tconst struct pnfs_commit_ops *ops;\n};\n\nstruct nfs41_server_owner {\n\tuint64_t minor_id;\n\tuint32_t major_id_sz;\n\tchar major_id[1024];\n};\n\nstruct nfs41_server_scope {\n\tuint32_t server_scope_sz;\n\tchar server_scope[1024];\n};\n\nstruct nfs41_impl_id {\n\tchar domain[1025];\n\tchar name[1025];\n\tstruct nfstime4 date;\n};\n\nstruct nfs_page_array {\n\tstruct page **pagevec;\n\tunsigned int npages;\n\tstruct page *page_array[8];\n};\n\nstruct nfs_page;\n\nstruct nfs_rw_ops;\n\nstruct nfs_io_completion;\n\nstruct nfs_direct_req;\n\nstruct nfs_pgio_completion_ops;\n\nstruct nfs_pgio_header {\n\tstruct inode *inode;\n\tconst struct cred *cred;\n\tstruct list_head pages;\n\tstruct nfs_page *req;\n\tstruct nfs_writeverf verf;\n\tfmode_t rw_mode;\n\tstruct pnfs_layout_segment *lseg;\n\tloff_t io_start;\n\tconst struct rpc_call_ops *mds_ops;\n\tvoid (*release)(struct nfs_pgio_header *);\n\tconst struct nfs_pgio_completion_ops *completion_ops;\n\tconst struct nfs_rw_ops *rw_ops;\n\tstruct nfs_io_completion *io_completion;\n\tstruct nfs_direct_req *dreq;\n\tint pnfs_error;\n\tint error;\n\tunsigned int good_bytes;\n\tlong unsigned int flags;\n\tstruct rpc_task task;\n\tstruct nfs_fattr fattr;\n\tstruct nfs_pgio_args args;\n\tstruct nfs_pgio_res res;\n\tlong unsigned int timestamp;\n\tint (*pgio_done_cb)(struct rpc_task *, struct nfs_pgio_header *);\n\t__u64 mds_offset;\n\tstruct nfs_page_array page_array;\n\tstruct nfs_client *ds_clp;\n\tu32 ds_commit_idx;\n\tu32 pgio_mirror_idx;\n};\n\nstruct nfs_pgio_completion_ops {\n\tvoid (*error_cleanup)(struct list_head *, int);\n\tvoid (*init_hdr)(struct nfs_pgio_header *);\n\tvoid (*completion)(struct nfs_pgio_header *);\n\tvoid (*reschedule_io)(struct nfs_pgio_header *);\n};\n\nstruct nfs_mds_commit_info {\n\tatomic_t rpcs_out;\n\tatomic_long_t ncommit;\n\tstruct list_head list;\n};\n\nstruct nfs_commit_data;\n\nstruct nfs_commit_info;\n\nstruct nfs_commit_completion_ops {\n\tvoid (*completion)(struct nfs_commit_data *);\n\tvoid (*resched_write)(struct nfs_commit_info *, struct nfs_page *);\n};\n\nstruct nfs_commit_data {\n\tstruct rpc_task task;\n\tstruct inode *inode;\n\tconst struct cred *cred;\n\tstruct nfs_fattr fattr;\n\tstruct nfs_writeverf verf;\n\tstruct list_head pages;\n\tstruct list_head list;\n\tstruct nfs_direct_req *dreq;\n\tstruct nfs_commitargs args;\n\tstruct nfs_commitres res;\n\tstruct nfs_open_context *context;\n\tstruct pnfs_layout_segment *lseg;\n\tstruct nfs_client *ds_clp;\n\tint ds_commit_index;\n\tloff_t lwb;\n\tconst struct rpc_call_ops *mds_ops;\n\tconst struct nfs_commit_completion_ops *completion_ops;\n\tint (*commit_done_cb)(struct rpc_task *, struct nfs_commit_data *);\n\tlong unsigned int flags;\n};\n\nstruct nfs_commit_info {\n\tstruct inode *inode;\n\tstruct nfs_mds_commit_info *mds;\n\tstruct pnfs_ds_commit_info *ds;\n\tstruct nfs_direct_req *dreq;\n\tconst struct nfs_commit_completion_ops *completion_ops;\n};\n\nstruct nfs_unlinkdata {\n\tstruct nfs_removeargs args;\n\tstruct nfs_removeres res;\n\tstruct dentry *dentry;\n\twait_queue_head_t wq;\n\tconst struct cred *cred;\n\tstruct nfs_fattr dir_attr;\n\tlong int timeout;\n};\n\nstruct nfs_renamedata {\n\tstruct nfs_renameargs args;\n\tstruct nfs_renameres res;\n\tconst struct cred *cred;\n\tstruct inode *old_dir;\n\tstruct dentry *old_dentry;\n\tstruct nfs_fattr old_fattr;\n\tstruct inode *new_dir;\n\tstruct dentry *new_dentry;\n\tstruct nfs_fattr new_fattr;\n\tvoid (*complete)(struct rpc_task *, struct nfs_renamedata *);\n\tlong int timeout;\n\tbool cancelled;\n};\n\nstruct nlmclnt_operations;\n\nstruct nfs_client_initdata;\n\nstruct nfs_access_entry;\n\nstruct nfs_rpc_ops {\n\tu32 version;\n\tconst struct dentry_operations *dentry_ops;\n\tconst struct inode_operations *dir_inode_ops;\n\tconst struct inode_operations *file_inode_ops;\n\tconst struct file_operations *file_ops;\n\tconst struct nlmclnt_operations *nlmclnt_ops;\n\tint (*getroot)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);\n\tint (*submount)(struct fs_context *, struct nfs_server *);\n\tint (*try_get_tree)(struct fs_context *);\n\tint (*getattr)(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *, struct inode *);\n\tint (*setattr)(struct dentry *, struct nfs_fattr *, struct iattr *);\n\tint (*lookup)(struct inode *, struct dentry *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *);\n\tint (*lookupp)(struct inode *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *);\n\tint (*access)(struct inode *, struct nfs_access_entry *);\n\tint (*readlink)(struct inode *, struct page *, unsigned int, unsigned int);\n\tint (*create)(struct inode *, struct dentry *, struct iattr *, int);\n\tint (*remove)(struct inode *, struct dentry *);\n\tvoid (*unlink_setup)(struct rpc_message *, struct dentry *, struct inode *);\n\tvoid (*unlink_rpc_prepare)(struct rpc_task *, struct nfs_unlinkdata *);\n\tint (*unlink_done)(struct rpc_task *, struct inode *);\n\tvoid (*rename_setup)(struct rpc_message *, struct dentry *, struct dentry *);\n\tvoid (*rename_rpc_prepare)(struct rpc_task *, struct nfs_renamedata *);\n\tint (*rename_done)(struct rpc_task *, struct inode *, struct inode *);\n\tint (*link)(struct inode *, struct inode *, const struct qstr *);\n\tint (*symlink)(struct inode *, struct dentry *, struct page *, unsigned int, struct iattr *);\n\tint (*mkdir)(struct inode *, struct dentry *, struct iattr *);\n\tint (*rmdir)(struct inode *, const struct qstr *);\n\tint (*readdir)(struct nfs_readdir_arg *, struct nfs_readdir_res *);\n\tint (*mknod)(struct inode *, struct dentry *, struct iattr *, dev_t);\n\tint (*statfs)(struct nfs_server *, struct nfs_fh *, struct nfs_fsstat *);\n\tint (*fsinfo)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);\n\tint (*pathconf)(struct nfs_server *, struct nfs_fh *, struct nfs_pathconf *);\n\tint (*set_capabilities)(struct nfs_server *, struct nfs_fh *);\n\tint (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, bool);\n\tint (*pgio_rpc_prepare)(struct rpc_task *, struct nfs_pgio_header *);\n\tvoid (*read_setup)(struct nfs_pgio_header *, struct rpc_message *);\n\tint (*read_done)(struct rpc_task *, struct nfs_pgio_header *);\n\tvoid (*write_setup)(struct nfs_pgio_header *, struct rpc_message *, struct rpc_clnt **);\n\tint (*write_done)(struct rpc_task *, struct nfs_pgio_header *);\n\tvoid (*commit_setup)(struct nfs_commit_data *, struct rpc_message *, struct rpc_clnt **);\n\tvoid (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *);\n\tint (*commit_done)(struct rpc_task *, struct nfs_commit_data *);\n\tint (*lock)(struct file *, int, struct file_lock *);\n\tint (*lock_check_bounds)(const struct file_lock *);\n\tvoid (*clear_acl_cache)(struct inode *);\n\tvoid (*close_context)(struct nfs_open_context *, int);\n\tstruct inode * (*open_context)(struct inode *, struct nfs_open_context *, int, struct iattr *, int *);\n\tint (*have_delegation)(struct inode *, fmode_t);\n\tstruct nfs_client * (*alloc_client)(const struct nfs_client_initdata *);\n\tstruct nfs_client * (*init_client)(struct nfs_client *, const struct nfs_client_initdata *);\n\tvoid (*free_client)(struct nfs_client *);\n\tstruct nfs_server * (*create_server)(struct fs_context *);\n\tstruct nfs_server * (*clone_server)(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, rpc_authflavor_t);\n};\n\nstruct nfs_access_entry {\n\tstruct rb_node rb_node;\n\tstruct list_head lru;\n\tconst struct cred *cred;\n\t__u32 mask;\n\tstruct callback_head callback_head;\n};\n\nstruct nfs4_state_recovery_ops;\n\nstruct nfs4_state_maintenance_ops;\n\nstruct nfs4_mig_recovery_ops;\n\nstruct nfs4_minor_version_ops {\n\tu32 minor_version;\n\tunsigned int init_caps;\n\tint (*init_client)(struct nfs_client *);\n\tvoid (*shutdown_client)(struct nfs_client *);\n\tbool (*match_stateid)(const nfs4_stateid *, const nfs4_stateid *);\n\tint (*find_root_sec)(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);\n\tvoid (*free_lock_state)(struct nfs_server *, struct nfs4_lock_state *);\n\tint (*test_and_free_expired)(struct nfs_server *, nfs4_stateid *, const struct cred *);\n\tstruct nfs_seqid * (*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);\n\tvoid (*session_trunk)(struct rpc_clnt *, struct rpc_xprt *, void *);\n\tconst struct rpc_call_ops *call_sync_ops;\n\tconst struct nfs4_state_recovery_ops *reboot_recovery_ops;\n\tconst struct nfs4_state_recovery_ops *nograce_recovery_ops;\n\tconst struct nfs4_state_maintenance_ops *state_renewal_ops;\n\tconst struct nfs4_mig_recovery_ops *mig_recovery_ops;\n};\n\nstruct nfs4_state_owner;\n\nstruct nfs4_state {\n\tstruct list_head open_states;\n\tstruct list_head inode_states;\n\tstruct list_head lock_states;\n\tstruct nfs4_state_owner *owner;\n\tstruct inode *inode;\n\tlong unsigned int flags;\n\tspinlock_t state_lock;\n\tseqlock_t seqlock;\n\tnfs4_stateid stateid;\n\tnfs4_stateid open_stateid;\n\tunsigned int n_rdonly;\n\tunsigned int n_wronly;\n\tunsigned int n_rdwr;\n\tfmode_t state;\n\trefcount_t count;\n\twait_queue_head_t waitq;\n\tstruct callback_head callback_head;\n};\n\nstruct cache_head {\n\tstruct hlist_node cache_list;\n\ttime64_t expiry_time;\n\ttime64_t last_refresh;\n\tstruct kref ref;\n\tlong unsigned int flags;\n};\n\nstruct cache_deferred_req;\n\nstruct cache_req {\n\tstruct cache_deferred_req * (*defer)(struct cache_req *);\n\tint thread_wait;\n};\n\nstruct cache_deferred_req {\n\tstruct hlist_node hash;\n\tstruct list_head recent;\n\tstruct cache_head *item;\n\tvoid *owner;\n\tvoid (*revisit)(struct cache_deferred_req *, int);\n};\n\nstruct svc_cred {\n\tkuid_t cr_uid;\n\tkgid_t cr_gid;\n\tstruct group_info *cr_group_info;\n\tu32 cr_flavor;\n\tchar *cr_raw_principal;\n\tchar *cr_principal;\n\tchar *cr_targ_princ;\n\tstruct gss_api_mech *cr_gss_mech;\n};\n\nstruct auth_ops {\n\tchar *name;\n\tstruct module *owner;\n\tint flavour;\n\tint (*accept)(struct svc_rqst *, __be32 *);\n\tint (*release)(struct svc_rqst *);\n\tvoid (*domain_release)(struct auth_domain *);\n\tint (*set_client)(struct svc_rqst *);\n};\n\nstruct svc_cacherep;\n\nstruct svc_procedure;\n\nstruct svc_deferred_req;\n\nstruct svc_rqst {\n\tstruct list_head rq_all;\n\tstruct callback_head rq_rcu_head;\n\tstruct svc_xprt *rq_xprt;\n\tstruct __kernel_sockaddr_storage rq_addr;\n\tsize_t rq_addrlen;\n\tstruct __kernel_sockaddr_storage rq_daddr;\n\tsize_t rq_daddrlen;\n\tstruct svc_serv *rq_server;\n\tstruct svc_pool *rq_pool;\n\tconst struct svc_procedure *rq_procinfo;\n\tstruct auth_ops *rq_authop;\n\tstruct svc_cred rq_cred;\n\tvoid *rq_xprt_ctxt;\n\tstruct svc_deferred_req *rq_deferred;\n\tsize_t rq_xprt_hlen;\n\tstruct xdr_buf rq_arg;\n\tstruct xdr_stream rq_arg_stream;\n\tstruct xdr_stream rq_res_stream;\n\tstruct page *rq_scratch_page;\n\tstruct xdr_buf rq_res;\n\tstruct page *rq_pages[260];\n\tstruct page **rq_respages;\n\tstruct page **rq_next_page;\n\tstruct page **rq_page_end;\n\tstruct kvec rq_vec[259];\n\tstruct bio_vec rq_bvec[259];\n\t__be32 rq_xid;\n\tu32 rq_prog;\n\tu32 rq_vers;\n\tu32 rq_proc;\n\tu32 rq_prot;\n\tint rq_cachetype;\n\tlong unsigned int rq_flags;\n\tktime_t rq_qtime;\n\tvoid *rq_argp;\n\tvoid *rq_resp;\n\tvoid *rq_auth_data;\n\tint rq_auth_slack;\n\tint rq_reserved;\n\tktime_t rq_stime;\n\tstruct cache_req rq_chandle;\n\tstruct auth_domain *rq_client;\n\tstruct auth_domain *rq_gssclient;\n\tstruct svc_cacherep *rq_cacherep;\n\tstruct task_struct *rq_task;\n\tspinlock_t rq_lock;\n\tstruct net *rq_bc_net;\n\tvoid **rq_lease_breaker;\n};\n\nstruct svc_pool_stats {\n\tatomic_long_t packets;\n\tlong unsigned int sockets_queued;\n\tatomic_long_t threads_woken;\n\tatomic_long_t threads_timedout;\n};\n\nstruct svc_pool {\n\tunsigned int sp_id;\n\tspinlock_t sp_lock;\n\tstruct list_head sp_sockets;\n\tunsigned int sp_nrthreads;\n\tstruct list_head sp_all_threads;\n\tstruct svc_pool_stats sp_stats;\n\tlong unsigned int sp_flags;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct svc_serv_ops {\n\tvoid (*svo_shutdown)(struct svc_serv *, struct net *);\n\tint (*svo_function)(void *);\n\tvoid (*svo_enqueue_xprt)(struct svc_xprt *);\n\tint (*svo_setup)(struct svc_serv *, struct svc_pool *, int);\n\tstruct module *svo_module;\n};\n\nstruct svc_procedure {\n\t__be32 (*pc_func)(struct svc_rqst *);\n\tint (*pc_decode)(struct svc_rqst *, __be32 *);\n\tint (*pc_encode)(struct svc_rqst *, __be32 *);\n\tvoid (*pc_release)(struct svc_rqst *);\n\tunsigned int pc_argsize;\n\tunsigned int pc_ressize;\n\tunsigned int pc_cachetype;\n\tunsigned int pc_xdrressize;\n\tconst char *pc_name;\n};\n\nstruct svc_deferred_req {\n\tu32 prot;\n\tstruct svc_xprt *xprt;\n\tstruct __kernel_sockaddr_storage addr;\n\tsize_t addrlen;\n\tstruct __kernel_sockaddr_storage daddr;\n\tsize_t daddrlen;\n\tstruct cache_deferred_req handle;\n\tsize_t xprt_hlen;\n\tint argslen;\n\t__be32 args[0];\n};\n\nstruct svc_process_info {\n\tunion {\n\t\tint (*dispatch)(struct svc_rqst *, __be32 *);\n\t\tstruct {\n\t\t\tunsigned int lovers;\n\t\t\tunsigned int hivers;\n\t\t} mismatch;\n\t};\n};\n\nstruct svc_version {\n\tu32 vs_vers;\n\tu32 vs_nproc;\n\tconst struct svc_procedure *vs_proc;\n\tunsigned int *vs_count;\n\tu32 vs_xdrsize;\n\tbool vs_hidden;\n\tbool vs_rpcb_optnl;\n\tbool vs_need_cong_ctrl;\n\tint (*vs_dispatch)(struct svc_rqst *, __be32 *);\n};\n\nstruct nfs4_ssc_client_ops;\n\nstruct nfs_ssc_client_ops;\n\nstruct nfs_ssc_client_ops_tbl {\n\tconst struct nfs4_ssc_client_ops *ssc_nfs4_ops;\n\tconst struct nfs_ssc_client_ops *ssc_nfs_ops;\n};\n\nstruct nfs4_ssc_client_ops {\n\tstruct file * (*sco_open)(struct vfsmount *, struct nfs_fh *, nfs4_stateid *);\n\tvoid (*sco_close)(struct file *);\n};\n\nstruct nfs_ssc_client_ops {\n\tvoid (*sco_sb_deactive)(struct super_block *);\n};\n\nstruct nfs4_state_recovery_ops {\n\tint owner_flag_bit;\n\tint state_flag_bit;\n\tint (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *);\n\tint (*recover_lock)(struct nfs4_state *, struct file_lock *);\n\tint (*establish_clid)(struct nfs_client *, const struct cred *);\n\tint (*reclaim_complete)(struct nfs_client *, const struct cred *);\n\tint (*detect_trunking)(struct nfs_client *, struct nfs_client **, const struct cred *);\n};\n\nstruct nfs4_state_maintenance_ops {\n\tint (*sched_state_renewal)(struct nfs_client *, const struct cred *, unsigned int);\n\tconst struct cred * (*get_state_renewal_cred)(struct nfs_client *);\n\tint (*renew_lease)(struct nfs_client *, const struct cred *);\n};\n\nstruct nfs4_mig_recovery_ops {\n\tint (*get_locations)(struct inode *, struct nfs4_fs_locations *, struct page *, const struct cred *);\n\tint (*fsid_present)(struct inode *, const struct cred *);\n};\n\nstruct nfs4_state_owner {\n\tstruct nfs_server *so_server;\n\tstruct list_head so_lru;\n\tlong unsigned int so_expires;\n\tstruct rb_node so_server_node;\n\tconst struct cred *so_cred;\n\tspinlock_t so_lock;\n\tatomic_t so_count;\n\tlong unsigned int so_flags;\n\tstruct list_head so_states;\n\tstruct nfs_seqid_counter so_seqid;\n\tseqcount_spinlock_t so_reclaim_seqcount;\n\tstruct mutex so_delegreturn_mutex;\n};\n\nstruct core_name {\n\tchar *corename;\n\tint used;\n\tint size;\n};\n\nstruct trace_event_raw_iomap_readpage_class {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tu64 ino;\n\tint nr_pages;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iomap_range_class {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tu64 ino;\n\tloff_t size;\n\tlong unsigned int offset;\n\tunsigned int length;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iomap_class {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tu64 ino;\n\tu64 addr;\n\tloff_t offset;\n\tu64 length;\n\tu16 type;\n\tu16 flags;\n\tdev_t bdev;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iomap_apply {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tu64 ino;\n\tloff_t pos;\n\tloff_t length;\n\tunsigned int flags;\n\tconst void *ops;\n\tvoid *actor;\n\tlong unsigned int caller;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_iomap_readpage_class {};\n\nstruct trace_event_data_offsets_iomap_range_class {};\n\nstruct trace_event_data_offsets_iomap_class {};\n\nstruct trace_event_data_offsets_iomap_apply {};\n\ntypedef void (*btf_trace_iomap_readpage)(void *, struct inode *, int);\n\ntypedef void (*btf_trace_iomap_readahead)(void *, struct inode *, int);\n\ntypedef void (*btf_trace_iomap_writepage)(void *, struct inode *, long unsigned int, unsigned int);\n\ntypedef void (*btf_trace_iomap_releasepage)(void *, struct inode *, long unsigned int, unsigned int);\n\ntypedef void (*btf_trace_iomap_invalidatepage)(void *, struct inode *, long unsigned int, unsigned int);\n\ntypedef void (*btf_trace_iomap_dio_invalidate_fail)(void *, struct inode *, long unsigned int, unsigned int);\n\ntypedef void (*btf_trace_iomap_apply_dstmap)(void *, struct inode *, struct iomap___2 *);\n\ntypedef void (*btf_trace_iomap_apply_srcmap)(void *, struct inode *, struct iomap___2 *);\n\ntypedef void (*btf_trace_iomap_apply)(void *, struct inode *, loff_t, loff_t, unsigned int, const void *, void *, long unsigned int);\n\nstruct iomap_ioend {\n\tstruct list_head io_list;\n\tu16 io_type;\n\tu16 io_flags;\n\tstruct inode *io_inode;\n\tsize_t io_size;\n\tloff_t io_offset;\n\tstruct bio *io_bio;\n\tstruct bio io_inline_bio;\n};\n\nstruct iomap_writepage_ctx;\n\nstruct iomap_writeback_ops {\n\tint (*map_blocks)(struct iomap_writepage_ctx *, struct inode *, loff_t);\n\tint (*prepare_ioend)(struct iomap_ioend *, int);\n\tvoid (*discard_page)(struct page *, loff_t);\n};\n\nstruct iomap_writepage_ctx {\n\tstruct iomap___2 iomap;\n\tstruct iomap_ioend *ioend;\n\tconst struct iomap_writeback_ops *ops;\n};\n\ntypedef int (*list_cmp_func_t)(void *, const struct list_head *, const struct list_head *);\n\nstruct iomap_page {\n\tatomic_t read_bytes_pending;\n\tatomic_t write_bytes_pending;\n\tspinlock_t uptodate_lock;\n\tlong unsigned int uptodate[0];\n};\n\nstruct iomap_readpage_ctx {\n\tstruct page *cur_page;\n\tbool cur_page_in_bio;\n\tstruct bio *bio;\n\tstruct readahead_control *rac;\n};\n\nenum {\n\tIOMAP_WRITE_F_UNSHARE = 1,\n};\n\nstruct iomap_dio_ops {\n\tint (*end_io)(struct kiocb *, ssize_t, int, unsigned int);\n\tblk_qc_t (*submit_io)(struct inode *, struct iomap___2 *, struct bio *, loff_t);\n};\n\nstruct iomap_dio {\n\tstruct kiocb *iocb;\n\tconst struct iomap_dio_ops *dops;\n\tloff_t i_size;\n\tloff_t size;\n\tatomic_t ref;\n\tunsigned int flags;\n\tint error;\n\tbool wait_for_completion;\n\tunion {\n\t\tstruct {\n\t\t\tstruct iov_iter *iter;\n\t\t\tstruct task_struct *waiter;\n\t\t\tstruct request_queue *last_queue;\n\t\t\tblk_qc_t cookie;\n\t\t} submit;\n\t\tstruct {\n\t\t\tstruct work_struct work;\n\t\t} aio;\n\t};\n};\n\nstruct fiemap_ctx {\n\tstruct fiemap_extent_info *fi;\n\tstruct iomap___2 prev;\n};\n\nstruct iomap_swapfile_info {\n\tstruct iomap___2 iomap;\n\tstruct swap_info_struct *sis;\n\tuint64_t lowest_ppage;\n\tuint64_t highest_ppage;\n\tlong unsigned int nr_pages;\n\tint nr_extents;\n\tstruct file *file;\n};\n\nenum {\n\tQIF_BLIMITS_B = 0,\n\tQIF_SPACE_B = 1,\n\tQIF_ILIMITS_B = 2,\n\tQIF_INODES_B = 3,\n\tQIF_BTIME_B = 4,\n\tQIF_ITIME_B = 5,\n};\n\ntypedef __kernel_uid32_t qid_t;\n\nenum {\n\tDQF_INFO_DIRTY_B = 17,\n};\n\nstruct dqstats {\n\tlong unsigned int stat[8];\n\tstruct percpu_counter counter[8];\n};\n\nenum {\n\t_DQUOT_USAGE_ENABLED = 0,\n\t_DQUOT_LIMITS_ENABLED = 1,\n\t_DQUOT_SUSPENDED = 2,\n\t_DQUOT_STATE_FLAGS = 3,\n};\n\nstruct quota_module_name {\n\tint qm_fmt_id;\n\tchar *qm_mod_name;\n};\n\nstruct dquot_warn {\n\tstruct super_block *w_sb;\n\tstruct kqid w_dq_id;\n\tshort int w_type;\n};\n\nstruct fs_disk_quota {\n\t__s8 d_version;\n\t__s8 d_flags;\n\t__u16 d_fieldmask;\n\t__u32 d_id;\n\t__u64 d_blk_hardlimit;\n\t__u64 d_blk_softlimit;\n\t__u64 d_ino_hardlimit;\n\t__u64 d_ino_softlimit;\n\t__u64 d_bcount;\n\t__u64 d_icount;\n\t__s32 d_itimer;\n\t__s32 d_btimer;\n\t__u16 d_iwarns;\n\t__u16 d_bwarns;\n\t__s8 d_itimer_hi;\n\t__s8 d_btimer_hi;\n\t__s8 d_rtbtimer_hi;\n\t__s8 d_padding2;\n\t__u64 d_rtb_hardlimit;\n\t__u64 d_rtb_softlimit;\n\t__u64 d_rtbcount;\n\t__s32 d_rtbtimer;\n\t__u16 d_rtbwarns;\n\t__s16 d_padding3;\n\tchar d_padding4[8];\n};\n\nstruct fs_qfilestat {\n\t__u64 qfs_ino;\n\t__u64 qfs_nblks;\n\t__u32 qfs_nextents;\n};\n\ntypedef struct fs_qfilestat fs_qfilestat_t;\n\nstruct fs_quota_stat {\n\t__s8 qs_version;\n\t__u16 qs_flags;\n\t__s8 qs_pad;\n\tfs_qfilestat_t qs_uquota;\n\tfs_qfilestat_t qs_gquota;\n\t__u32 qs_incoredqs;\n\t__s32 qs_btimelimit;\n\t__s32 qs_itimelimit;\n\t__s32 qs_rtbtimelimit;\n\t__u16 qs_bwarnlimit;\n\t__u16 qs_iwarnlimit;\n};\n\nstruct fs_qfilestatv {\n\t__u64 qfs_ino;\n\t__u64 qfs_nblks;\n\t__u32 qfs_nextents;\n\t__u32 qfs_pad;\n};\n\nstruct fs_quota_statv {\n\t__s8 qs_version;\n\t__u8 qs_pad1;\n\t__u16 qs_flags;\n\t__u32 qs_incoredqs;\n\tstruct fs_qfilestatv qs_uquota;\n\tstruct fs_qfilestatv qs_gquota;\n\tstruct fs_qfilestatv qs_pquota;\n\t__s32 qs_btimelimit;\n\t__s32 qs_itimelimit;\n\t__s32 qs_rtbtimelimit;\n\t__u16 qs_bwarnlimit;\n\t__u16 qs_iwarnlimit;\n\t__u16 qs_rtbwarnlimit;\n\t__u16 qs_pad3;\n\t__u32 qs_pad4;\n\t__u64 qs_pad2[7];\n};\n\nstruct if_dqblk {\n\t__u64 dqb_bhardlimit;\n\t__u64 dqb_bsoftlimit;\n\t__u64 dqb_curspace;\n\t__u64 dqb_ihardlimit;\n\t__u64 dqb_isoftlimit;\n\t__u64 dqb_curinodes;\n\t__u64 dqb_btime;\n\t__u64 dqb_itime;\n\t__u32 dqb_valid;\n};\n\nstruct if_nextdqblk {\n\t__u64 dqb_bhardlimit;\n\t__u64 dqb_bsoftlimit;\n\t__u64 dqb_curspace;\n\t__u64 dqb_ihardlimit;\n\t__u64 dqb_isoftlimit;\n\t__u64 dqb_curinodes;\n\t__u64 dqb_btime;\n\t__u64 dqb_itime;\n\t__u32 dqb_valid;\n\t__u32 dqb_id;\n};\n\nstruct if_dqinfo {\n\t__u64 dqi_bgrace;\n\t__u64 dqi_igrace;\n\t__u32 dqi_flags;\n\t__u32 dqi_valid;\n};\n\nstruct compat_if_dqblk {\n\tcompat_u64 dqb_bhardlimit;\n\tcompat_u64 dqb_bsoftlimit;\n\tcompat_u64 dqb_curspace;\n\tcompat_u64 dqb_ihardlimit;\n\tcompat_u64 dqb_isoftlimit;\n\tcompat_u64 dqb_curinodes;\n\tcompat_u64 dqb_btime;\n\tcompat_u64 dqb_itime;\n\tcompat_uint_t dqb_valid;\n} __attribute__((packed));\n\nstruct compat_fs_qfilestat {\n\tcompat_u64 dqb_bhardlimit;\n\tcompat_u64 qfs_nblks;\n\tcompat_uint_t qfs_nextents;\n} __attribute__((packed));\n\nstruct compat_fs_quota_stat {\n\t__s8 qs_version;\n\tchar: 8;\n\t__u16 qs_flags;\n\t__s8 qs_pad;\n\tint: 24;\n\tstruct compat_fs_qfilestat qs_uquota;\n\tstruct compat_fs_qfilestat qs_gquota;\n\tcompat_uint_t qs_incoredqs;\n\tcompat_int_t qs_btimelimit;\n\tcompat_int_t qs_itimelimit;\n\tcompat_int_t qs_rtbtimelimit;\n\t__u16 qs_bwarnlimit;\n\t__u16 qs_iwarnlimit;\n} __attribute__((packed));\n\nenum {\n\tQUOTA_NL_C_UNSPEC = 0,\n\tQUOTA_NL_C_WARNING = 1,\n\t__QUOTA_NL_C_MAX = 2,\n};\n\nenum {\n\tQUOTA_NL_A_UNSPEC = 0,\n\tQUOTA_NL_A_QTYPE = 1,\n\tQUOTA_NL_A_EXCESS_ID = 2,\n\tQUOTA_NL_A_WARNING = 3,\n\tQUOTA_NL_A_DEV_MAJOR = 4,\n\tQUOTA_NL_A_DEV_MINOR = 5,\n\tQUOTA_NL_A_CAUSED_ID = 6,\n\tQUOTA_NL_A_PAD = 7,\n\t__QUOTA_NL_A_MAX = 8,\n};\n\nstruct proc_maps_private {\n\tstruct inode *inode;\n\tstruct task_struct *task;\n\tstruct mm_struct *mm;\n\tstruct vm_area_struct *tail_vma;\n\tstruct mempolicy *task_mempolicy;\n};\n\nstruct mem_size_stats {\n\tlong unsigned int resident;\n\tlong unsigned int shared_clean;\n\tlong unsigned int shared_dirty;\n\tlong unsigned int private_clean;\n\tlong unsigned int private_dirty;\n\tlong unsigned int referenced;\n\tlong unsigned int anonymous;\n\tlong unsigned int lazyfree;\n\tlong unsigned int anonymous_thp;\n\tlong unsigned int shmem_thp;\n\tlong unsigned int file_thp;\n\tlong unsigned int swap;\n\tlong unsigned int shared_hugetlb;\n\tlong unsigned int private_hugetlb;\n\tu64 pss;\n\tu64 pss_anon;\n\tu64 pss_file;\n\tu64 pss_shmem;\n\tu64 pss_locked;\n\tu64 swap_pss;\n\tbool check_shmem_swap;\n};\n\nenum clear_refs_types {\n\tCLEAR_REFS_ALL = 1,\n\tCLEAR_REFS_ANON = 2,\n\tCLEAR_REFS_MAPPED = 3,\n\tCLEAR_REFS_SOFT_DIRTY = 4,\n\tCLEAR_REFS_MM_HIWATER_RSS = 5,\n\tCLEAR_REFS_LAST = 6,\n};\n\nstruct clear_refs_private {\n\tenum clear_refs_types type;\n};\n\ntypedef struct {\n\tu64 pme;\n} pagemap_entry_t;\n\nstruct pagemapread {\n\tint pos;\n\tint len;\n\tpagemap_entry_t *buffer;\n\tbool show_pfn;\n};\n\nstruct numa_maps {\n\tlong unsigned int pages;\n\tlong unsigned int anon;\n\tlong unsigned int active;\n\tlong unsigned int writeback;\n\tlong unsigned int mapcount_max;\n\tlong unsigned int dirty;\n\tlong unsigned int swapcache;\n\tlong unsigned int node[32];\n};\n\nstruct numa_maps_private {\n\tstruct proc_maps_private proc_maps;\n\tstruct numa_maps md;\n};\n\nstruct pde_opener {\n\tstruct list_head lh;\n\tstruct file *file;\n\tbool closing;\n\tstruct completion *c;\n};\n\nenum {\n\tBIAS = 2147483648,\n};\n\nstruct proc_fs_context {\n\tstruct pid_namespace *pid_ns;\n\tunsigned int mask;\n\tenum proc_hidepid hidepid;\n\tint gid;\n\tenum proc_pidonly pidonly;\n};\n\nenum proc_param {\n\tOpt_gid___2 = 0,\n\tOpt_hidepid = 1,\n\tOpt_subset = 2,\n};\n\nstruct genradix_root;\n\nstruct __genradix {\n\tstruct genradix_root *root;\n};\n\nstruct syscall_info {\n\t__u64 sp;\n\tstruct seccomp_data data;\n};\n\ntypedef struct dentry *instantiate_t(struct dentry *, struct task_struct *, const void *);\n\nstruct pid_entry {\n\tconst char *name;\n\tunsigned int len;\n\tumode_t mode;\n\tconst struct inode_operations *iop;\n\tconst struct file_operations *fop;\n\tunion proc_op op;\n};\n\nstruct limit_names {\n\tconst char *name;\n\tconst char *unit;\n};\n\nstruct map_files_info {\n\tlong unsigned int start;\n\tlong unsigned int end;\n\tfmode_t mode;\n};\n\nstruct timers_private {\n\tstruct pid *pid;\n\tstruct task_struct *task;\n\tstruct sighand_struct *sighand;\n\tstruct pid_namespace *ns;\n\tlong unsigned int flags;\n};\n\nstruct tgid_iter {\n\tunsigned int tgid;\n\tstruct task_struct *task;\n};\n\nstruct fd_data {\n\tfmode_t mode;\n\tunsigned int fd;\n};\n\nstruct sysctl_alias {\n\tconst char *kernel_param;\n\tconst char *sysctl_param;\n};\n\nstruct seq_net_private {\n\tstruct net *net;\n};\n\nstruct bpf_iter_aux_info___2;\n\nstruct vmcore {\n\tstruct list_head list;\n\tlong long unsigned int paddr;\n\tlong long unsigned int size;\n\tloff_t offset;\n};\n\nstruct vmcoredd_node {\n\tstruct list_head list;\n\tvoid *buf;\n\tunsigned int size;\n};\n\ntypedef struct elf32_hdr Elf32_Ehdr;\n\ntypedef struct elf32_phdr Elf32_Phdr;\n\ntypedef struct elf32_note Elf32_Nhdr;\n\ntypedef struct elf64_note Elf64_Nhdr;\n\nstruct vmcoredd_header {\n\t__u32 n_namesz;\n\t__u32 n_descsz;\n\t__u32 n_type;\n\t__u8 name[8];\n\t__u8 dump_name[44];\n};\n\nstruct vmcoredd_data {\n\tchar dump_name[44];\n\tunsigned int size;\n\tint (*vmcoredd_callback)(struct vmcoredd_data *, void *);\n};\n\nstruct kernfs_iattrs {\n\tkuid_t ia_uid;\n\tkgid_t ia_gid;\n\tstruct timespec64 ia_atime;\n\tstruct timespec64 ia_mtime;\n\tstruct timespec64 ia_ctime;\n\tstruct simple_xattrs xattrs;\n\tatomic_t nr_user_xattrs;\n\tatomic_t user_xattr_size;\n};\n\nstruct kernfs_super_info {\n\tstruct super_block *sb;\n\tstruct kernfs_root *root;\n\tconst void *ns;\n\tstruct list_head node;\n};\n\nenum kernfs_node_flag {\n\tKERNFS_ACTIVATED = 16,\n\tKERNFS_NS = 32,\n\tKERNFS_HAS_SEQ_SHOW = 64,\n\tKERNFS_HAS_MMAP = 128,\n\tKERNFS_LOCKDEP = 256,\n\tKERNFS_SUICIDAL = 1024,\n\tKERNFS_SUICIDED = 2048,\n\tKERNFS_EMPTY_DIR = 4096,\n\tKERNFS_HAS_RELEASE = 8192,\n};\n\nstruct kernfs_open_node {\n\tatomic_t refcnt;\n\tatomic_t event;\n\twait_queue_head_t poll;\n\tstruct list_head files;\n};\n\nstruct config_group;\n\nstruct config_item_type;\n\nstruct config_item {\n\tchar *ci_name;\n\tchar ci_namebuf[20];\n\tstruct kref ci_kref;\n\tstruct list_head ci_entry;\n\tstruct config_item *ci_parent;\n\tstruct config_group *ci_group;\n\tconst struct config_item_type *ci_type;\n\tstruct dentry *ci_dentry;\n};\n\nstruct configfs_subsystem;\n\nstruct config_group {\n\tstruct config_item cg_item;\n\tstruct list_head cg_children;\n\tstruct configfs_subsystem *cg_subsys;\n\tstruct list_head default_groups;\n\tstruct list_head group_entry;\n};\n\nstruct configfs_item_operations;\n\nstruct configfs_group_operations;\n\nstruct configfs_attribute;\n\nstruct configfs_bin_attribute;\n\nstruct config_item_type {\n\tstruct module *ct_owner;\n\tstruct configfs_item_operations *ct_item_ops;\n\tstruct configfs_group_operations *ct_group_ops;\n\tstruct configfs_attribute **ct_attrs;\n\tstruct configfs_bin_attribute **ct_bin_attrs;\n};\n\nstruct configfs_item_operations {\n\tvoid (*release)(struct config_item *);\n\tint (*allow_link)(struct config_item *, struct config_item *);\n\tvoid (*drop_link)(struct config_item *, struct config_item *);\n};\n\nstruct configfs_group_operations {\n\tstruct config_item * (*make_item)(struct config_group *, const char *);\n\tstruct config_group * (*make_group)(struct config_group *, const char *);\n\tint (*commit_item)(struct config_item *);\n\tvoid (*disconnect_notify)(struct config_group *, struct config_item *);\n\tvoid (*drop_item)(struct config_group *, struct config_item *);\n};\n\nstruct configfs_attribute {\n\tconst char *ca_name;\n\tstruct module *ca_owner;\n\tumode_t ca_mode;\n\tssize_t (*show)(struct config_item *, char *);\n\tssize_t (*store)(struct config_item *, const char *, size_t);\n};\n\nstruct configfs_bin_attribute {\n\tstruct configfs_attribute cb_attr;\n\tvoid *cb_private;\n\tsize_t cb_max_size;\n\tssize_t (*read)(struct config_item *, void *, size_t);\n\tssize_t (*write)(struct config_item *, const void *, size_t);\n};\n\nstruct configfs_subsystem {\n\tstruct config_group su_group;\n\tstruct mutex su_mutex;\n};\n\nstruct configfs_fragment {\n\tatomic_t frag_count;\n\tstruct rw_semaphore frag_sem;\n\tbool frag_dead;\n};\n\nstruct configfs_dirent {\n\tatomic_t s_count;\n\tint s_dependent_count;\n\tstruct list_head s_sibling;\n\tstruct list_head s_children;\n\tint s_links;\n\tvoid *s_element;\n\tint s_type;\n\tumode_t s_mode;\n\tstruct dentry *s_dentry;\n\tstruct iattr *s_iattr;\n\tstruct configfs_fragment *s_frag;\n};\n\nstruct configfs_buffer {\n\tsize_t count;\n\tloff_t pos;\n\tchar *page;\n\tstruct configfs_item_operations *ops;\n\tstruct mutex mutex;\n\tint needs_read_fill;\n\tbool read_in_progress;\n\tbool write_in_progress;\n\tchar *bin_buffer;\n\tint bin_buffer_size;\n\tint cb_max_size;\n\tstruct config_item *item;\n\tstruct module *owner;\n\tunion {\n\t\tstruct configfs_attribute *attr;\n\t\tstruct configfs_bin_attribute *bin_attr;\n\t};\n};\n\nstruct pts_mount_opts {\n\tint setuid;\n\tint setgid;\n\tkuid_t uid;\n\tkgid_t gid;\n\tumode_t mode;\n\tumode_t ptmxmode;\n\tint reserve;\n\tint max;\n};\n\nenum {\n\tOpt_uid___2 = 0,\n\tOpt_gid___3 = 1,\n\tOpt_mode___2 = 2,\n\tOpt_ptmxmode = 3,\n\tOpt_newinstance = 4,\n\tOpt_max = 5,\n\tOpt_err = 6,\n};\n\nstruct pts_fs_info {\n\tstruct ida allocated_ptys;\n\tstruct pts_mount_opts mount_opts;\n\tstruct super_block *sb;\n\tstruct dentry *ptmx_dentry;\n};\n\nstruct ramfs_mount_opts {\n\tumode_t mode;\n};\n\nstruct ramfs_fs_info {\n\tstruct ramfs_mount_opts mount_opts;\n};\n\nenum ramfs_param {\n\tOpt_mode___3 = 0,\n};\n\nenum hugetlbfs_size_type {\n\tNO_SIZE = 0,\n\tSIZE_STD = 1,\n\tSIZE_PERCENT = 2,\n};\n\nstruct hugetlbfs_fs_context {\n\tstruct hstate *hstate;\n\tlong long unsigned int max_size_opt;\n\tlong long unsigned int min_size_opt;\n\tlong int max_hpages;\n\tlong int nr_inodes;\n\tlong int min_hpages;\n\tenum hugetlbfs_size_type max_val_type;\n\tenum hugetlbfs_size_type min_val_type;\n\tkuid_t uid;\n\tkgid_t gid;\n\tumode_t mode;\n};\n\nenum hugetlb_param {\n\tOpt_gid___4 = 0,\n\tOpt_min_size = 1,\n\tOpt_mode___4 = 2,\n\tOpt_nr_inodes___2 = 3,\n\tOpt_pagesize = 4,\n\tOpt_size___2 = 5,\n\tOpt_uid___3 = 6,\n};\n\nstruct getdents_callback___2 {\n\tstruct dir_context ctx;\n\tchar *name;\n\tu64 ino;\n\tint found;\n\tint sequence;\n};\n\ntypedef u16 wchar_t;\n\ntypedef u32 unicode_t;\n\nstruct nls_table {\n\tconst char *charset;\n\tconst char *alias;\n\tint (*uni2char)(wchar_t, unsigned char *, int);\n\tint (*char2uni)(const unsigned char *, int, wchar_t *);\n\tconst unsigned char *charset2lower;\n\tconst unsigned char *charset2upper;\n\tstruct module *owner;\n\tstruct nls_table *next;\n};\n\nenum utf16_endian {\n\tUTF16_HOST_ENDIAN = 0,\n\tUTF16_LITTLE_ENDIAN = 1,\n\tUTF16_BIG_ENDIAN = 2,\n};\n\nstruct utf8_table {\n\tint cmask;\n\tint cval;\n\tint shift;\n\tlong int lmask;\n\tlong int lval;\n};\n\nstruct utf8data;\n\nstruct utf8cursor {\n\tconst struct utf8data *data;\n\tconst char *s;\n\tconst char *p;\n\tconst char *ss;\n\tconst char *sp;\n\tunsigned int len;\n\tunsigned int slen;\n\tshort int ccc;\n\tshort int nccc;\n\tunsigned char hangul[12];\n};\n\nstruct utf8data {\n\tunsigned int maxage;\n\tunsigned int offset;\n};\n\ntypedef const unsigned char utf8trie_t;\n\ntypedef const unsigned char utf8leaf_t;\n\ntypedef unsigned int autofs_wqt_t;\n\nstruct autofs_sb_info;\n\nstruct autofs_info {\n\tstruct dentry *dentry;\n\tstruct inode *inode;\n\tint flags;\n\tstruct completion expire_complete;\n\tstruct list_head active;\n\tstruct list_head expiring;\n\tstruct autofs_sb_info *sbi;\n\tlong unsigned int last_used;\n\tint count;\n\tkuid_t uid;\n\tkgid_t gid;\n\tstruct callback_head rcu;\n};\n\nstruct autofs_wait_queue;\n\nstruct autofs_sb_info {\n\tu32 magic;\n\tint pipefd;\n\tstruct file *pipe;\n\tstruct pid *oz_pgrp;\n\tint version;\n\tint sub_version;\n\tint min_proto;\n\tint max_proto;\n\tunsigned int flags;\n\tlong unsigned int exp_timeout;\n\tunsigned int type;\n\tstruct super_block *sb;\n\tstruct mutex wq_mutex;\n\tstruct mutex pipe_mutex;\n\tspinlock_t fs_lock;\n\tstruct autofs_wait_queue *queues;\n\tspinlock_t lookup_lock;\n\tstruct list_head active_list;\n\tstruct list_head expiring_list;\n\tstruct callback_head rcu;\n};\n\nstruct autofs_wait_queue {\n\twait_queue_head_t queue;\n\tstruct autofs_wait_queue *next;\n\tautofs_wqt_t wait_queue_token;\n\tstruct qstr name;\n\tu32 offset;\n\tu32 dev;\n\tu64 ino;\n\tkuid_t uid;\n\tkgid_t gid;\n\tpid_t pid;\n\tpid_t tgid;\n\tint status;\n\tunsigned int wait_ctr;\n};\n\nenum {\n\tOpt_err___2 = 0,\n\tOpt_fd = 1,\n\tOpt_uid___4 = 2,\n\tOpt_gid___5 = 3,\n\tOpt_pgrp = 4,\n\tOpt_minproto = 5,\n\tOpt_maxproto = 6,\n\tOpt_indirect = 7,\n\tOpt_direct = 8,\n\tOpt_offset = 9,\n\tOpt_strictexpire = 10,\n\tOpt_ignore = 11,\n};\n\nstruct autofs_packet_hdr {\n\tint proto_version;\n\tint type;\n};\n\nstruct autofs_packet_expire {\n\tstruct autofs_packet_hdr hdr;\n\tint len;\n\tchar name[256];\n};\n\nenum {\n\tAUTOFS_IOC_READY_CMD = 96,\n\tAUTOFS_IOC_FAIL_CMD = 97,\n\tAUTOFS_IOC_CATATONIC_CMD = 98,\n\tAUTOFS_IOC_PROTOVER_CMD = 99,\n\tAUTOFS_IOC_SETTIMEOUT_CMD = 100,\n\tAUTOFS_IOC_EXPIRE_CMD = 101,\n};\n\nenum autofs_notify {\n\tNFY_NONE = 0,\n\tNFY_MOUNT = 1,\n\tNFY_EXPIRE = 2,\n};\n\nenum {\n\tAUTOFS_IOC_EXPIRE_MULTI_CMD = 102,\n\tAUTOFS_IOC_PROTOSUBVER_CMD = 103,\n\tAUTOFS_IOC_ASKUMOUNT_CMD = 112,\n};\n\nstruct autofs_packet_missing {\n\tstruct autofs_packet_hdr hdr;\n\tautofs_wqt_t wait_queue_token;\n\tint len;\n\tchar name[256];\n};\n\nstruct autofs_packet_expire_multi {\n\tstruct autofs_packet_hdr hdr;\n\tautofs_wqt_t wait_queue_token;\n\tint len;\n\tchar name[256];\n};\n\nunion autofs_packet_union {\n\tstruct autofs_packet_hdr hdr;\n\tstruct autofs_packet_missing missing;\n\tstruct autofs_packet_expire expire;\n\tstruct autofs_packet_expire_multi expire_multi;\n};\n\nstruct autofs_v5_packet {\n\tstruct autofs_packet_hdr hdr;\n\tautofs_wqt_t wait_queue_token;\n\t__u32 dev;\n\t__u64 ino;\n\t__u32 uid;\n\t__u32 gid;\n\t__u32 pid;\n\t__u32 tgid;\n\t__u32 len;\n\tchar name[256];\n};\n\ntypedef struct autofs_v5_packet autofs_packet_missing_indirect_t;\n\ntypedef struct autofs_v5_packet autofs_packet_expire_indirect_t;\n\ntypedef struct autofs_v5_packet autofs_packet_missing_direct_t;\n\ntypedef struct autofs_v5_packet autofs_packet_expire_direct_t;\n\nunion autofs_v5_packet_union {\n\tstruct autofs_packet_hdr hdr;\n\tstruct autofs_v5_packet v5_packet;\n\tautofs_packet_missing_indirect_t missing_indirect;\n\tautofs_packet_expire_indirect_t expire_indirect;\n\tautofs_packet_missing_direct_t missing_direct;\n\tautofs_packet_expire_direct_t expire_direct;\n};\n\nstruct args_protover {\n\t__u32 version;\n};\n\nstruct args_protosubver {\n\t__u32 sub_version;\n};\n\nstruct args_openmount {\n\t__u32 devid;\n};\n\nstruct args_ready {\n\t__u32 token;\n};\n\nstruct args_fail {\n\t__u32 token;\n\t__s32 status;\n};\n\nstruct args_setpipefd {\n\t__s32 pipefd;\n};\n\nstruct args_timeout {\n\t__u64 timeout;\n};\n\nstruct args_requester {\n\t__u32 uid;\n\t__u32 gid;\n};\n\nstruct args_expire {\n\t__u32 how;\n};\n\nstruct args_askumount {\n\t__u32 may_umount;\n};\n\nstruct args_in {\n\t__u32 type;\n};\n\nstruct args_out {\n\t__u32 devid;\n\t__u32 magic;\n};\n\nstruct args_ismountpoint {\n\tunion {\n\t\tstruct args_in in;\n\t\tstruct args_out out;\n\t};\n};\n\nstruct autofs_dev_ioctl {\n\t__u32 ver_major;\n\t__u32 ver_minor;\n\t__u32 size;\n\t__s32 ioctlfd;\n\tunion {\n\t\tstruct args_protover protover;\n\t\tstruct args_protosubver protosubver;\n\t\tstruct args_openmount openmount;\n\t\tstruct args_ready ready;\n\t\tstruct args_fail fail;\n\t\tstruct args_setpipefd setpipefd;\n\t\tstruct args_timeout timeout;\n\t\tstruct args_requester requester;\n\t\tstruct args_expire expire;\n\t\tstruct args_askumount askumount;\n\t\tstruct args_ismountpoint ismountpoint;\n\t};\n\tchar path[0];\n};\n\nenum {\n\tAUTOFS_DEV_IOCTL_VERSION_CMD = 113,\n\tAUTOFS_DEV_IOCTL_PROTOVER_CMD = 114,\n\tAUTOFS_DEV_IOCTL_PROTOSUBVER_CMD = 115,\n\tAUTOFS_DEV_IOCTL_OPENMOUNT_CMD = 116,\n\tAUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD = 117,\n\tAUTOFS_DEV_IOCTL_READY_CMD = 118,\n\tAUTOFS_DEV_IOCTL_FAIL_CMD = 119,\n\tAUTOFS_DEV_IOCTL_SETPIPEFD_CMD = 120,\n\tAUTOFS_DEV_IOCTL_CATATONIC_CMD = 121,\n\tAUTOFS_DEV_IOCTL_TIMEOUT_CMD = 122,\n\tAUTOFS_DEV_IOCTL_REQUESTER_CMD = 123,\n\tAUTOFS_DEV_IOCTL_EXPIRE_CMD = 124,\n\tAUTOFS_DEV_IOCTL_ASKUMOUNT_CMD = 125,\n\tAUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD = 126,\n};\n\ntypedef int (*ioctl_fn)(struct file *, struct autofs_sb_info *, struct autofs_dev_ioctl *);\n\nstruct debugfs_fsdata {\n\tconst struct file_operations *real_fops;\n\trefcount_t active_users;\n\tstruct completion active_users_drained;\n};\n\nstruct debugfs_mount_opts {\n\tkuid_t uid;\n\tkgid_t gid;\n\tumode_t mode;\n};\n\nenum {\n\tOpt_uid___5 = 0,\n\tOpt_gid___6 = 1,\n\tOpt_mode___5 = 2,\n\tOpt_err___3 = 3,\n};\n\nstruct debugfs_fs_info {\n\tstruct debugfs_mount_opts mount_opts;\n};\n\nstruct debugfs_reg32 {\n\tchar *name;\n\tlong unsigned int offset;\n};\n\nstruct debugfs_regset32 {\n\tconst struct debugfs_reg32 *regs;\n\tint nregs;\n\tvoid *base;\n\tstruct device *dev;\n};\n\nstruct debugfs_devm_entry {\n\tint (*read)(struct seq_file *, void *);\n\tstruct device *dev;\n};\n\nstruct tracefs_dir_ops {\n\tint (*mkdir)(const char *);\n\tint (*rmdir)(const char *);\n};\n\nstruct tracefs_mount_opts {\n\tkuid_t uid;\n\tkgid_t gid;\n\tumode_t mode;\n};\n\nstruct tracefs_fs_info {\n\tstruct tracefs_mount_opts mount_opts;\n};\n\nenum pstore_type_id {\n\tPSTORE_TYPE_DMESG = 0,\n\tPSTORE_TYPE_MCE = 1,\n\tPSTORE_TYPE_CONSOLE = 2,\n\tPSTORE_TYPE_FTRACE = 3,\n\tPSTORE_TYPE_PPC_RTAS = 4,\n\tPSTORE_TYPE_PPC_OF = 5,\n\tPSTORE_TYPE_PPC_COMMON = 6,\n\tPSTORE_TYPE_PMSG = 7,\n\tPSTORE_TYPE_PPC_OPAL = 8,\n\tPSTORE_TYPE_MAX = 9,\n};\n\nstruct pstore_info;\n\nstruct pstore_record {\n\tstruct pstore_info *psi;\n\tenum pstore_type_id type;\n\tu64 id;\n\tstruct timespec64 time;\n\tchar *buf;\n\tssize_t size;\n\tssize_t ecc_notice_size;\n\tint count;\n\tenum kmsg_dump_reason reason;\n\tunsigned int part;\n\tbool compressed;\n};\n\nstruct pstore_info {\n\tstruct module *owner;\n\tconst char *name;\n\tstruct semaphore buf_lock;\n\tchar *buf;\n\tsize_t bufsize;\n\tstruct mutex read_mutex;\n\tint flags;\n\tint max_reason;\n\tvoid *data;\n\tint (*open)(struct pstore_info *);\n\tint (*close)(struct pstore_info *);\n\tssize_t (*read)(struct pstore_record *);\n\tint (*write)(struct pstore_record *);\n\tint (*write_user)(struct pstore_record *, const char *);\n\tint (*erase)(struct pstore_record *);\n};\n\nstruct pstore_ftrace_record {\n\tlong unsigned int ip;\n\tlong unsigned int parent_ip;\n\tu64 ts;\n};\n\nstruct pstore_private {\n\tstruct list_head list;\n\tstruct dentry *dentry;\n\tstruct pstore_record *record;\n\tsize_t total_size;\n};\n\nstruct pstore_ftrace_seq_data {\n\tconst void *ptr;\n\tsize_t off;\n\tsize_t size;\n};\n\nenum {\n\tOpt_kmsg_bytes = 0,\n\tOpt_err___4 = 1,\n};\n\nstruct crypto_comp {\n\tstruct crypto_tfm base;\n};\n\nstruct pstore_zbackend {\n\tint (*zbufsize)(size_t);\n\tconst char *name;\n};\n\nstruct efi_variable {\n\tefi_char16_t VariableName[512];\n\tefi_guid_t VendorGuid;\n\tlong unsigned int DataSize;\n\t__u8 Data[1024];\n\tefi_status_t Status;\n\t__u32 Attributes;\n} __attribute__((packed));\n\nstruct efivar_entry {\n\tstruct efi_variable var;\n\tstruct list_head list;\n\tstruct kobject kobj;\n\tbool scanning;\n\tbool deleting;\n};\n\ntypedef unsigned int __kernel_mode_t;\n\nstruct ipc64_perm {\n\t__kernel_key_t key;\n\t__kernel_uid32_t uid;\n\t__kernel_gid32_t gid;\n\t__kernel_uid32_t cuid;\n\t__kernel_gid32_t cgid;\n\t__kernel_mode_t mode;\n\tunsigned char __pad1[0];\n\tshort unsigned int seq;\n\tshort unsigned int __pad2;\n\t__kernel_ulong_t __unused1;\n\t__kernel_ulong_t __unused2;\n};\n\ntypedef s32 compat_key_t;\n\ntypedef u32 __compat_gid32_t;\n\nstruct compat_ipc64_perm {\n\tcompat_key_t key;\n\t__compat_uid32_t uid;\n\t__compat_gid32_t gid;\n\t__compat_uid32_t cuid;\n\t__compat_gid32_t cgid;\n\tshort unsigned int mode;\n\tshort unsigned int __pad1;\n\tshort unsigned int seq;\n\tshort unsigned int __pad2;\n\tcompat_ulong_t unused1;\n\tcompat_ulong_t unused2;\n};\n\nstruct compat_ipc_perm {\n\tkey_t key;\n\t__compat_uid_t uid;\n\t__compat_gid_t gid;\n\t__compat_uid_t cuid;\n\t__compat_gid_t cgid;\n\tcompat_mode_t mode;\n\tshort unsigned int seq;\n};\n\nstruct ipc_perm {\n\t__kernel_key_t key;\n\t__kernel_uid_t uid;\n\t__kernel_gid_t gid;\n\t__kernel_uid_t cuid;\n\t__kernel_gid_t cgid;\n\t__kernel_mode_t mode;\n\tshort unsigned int seq;\n};\n\nstruct ipc_params {\n\tkey_t key;\n\tint flg;\n\tunion {\n\t\tsize_t size;\n\t\tint nsems;\n\t} u;\n};\n\nstruct ipc_ops {\n\tint (*getnew)(struct ipc_namespace *, struct ipc_params *);\n\tint (*associate)(struct kern_ipc_perm *, int);\n\tint (*more_checks)(struct kern_ipc_perm *, struct ipc_params *);\n};\n\nstruct ipc_proc_iface {\n\tconst char *path;\n\tconst char *header;\n\tint ids;\n\tint (*show)(struct seq_file *, void *);\n};\n\nstruct ipc_proc_iter {\n\tstruct ipc_namespace *ns;\n\tstruct pid_namespace *pid_ns;\n\tstruct ipc_proc_iface *iface;\n};\n\nstruct msg_msgseg;\n\nstruct msg_msg {\n\tstruct list_head m_list;\n\tlong int m_type;\n\tsize_t m_ts;\n\tstruct msg_msgseg *next;\n\tvoid *security;\n};\n\nstruct msg_msgseg {\n\tstruct msg_msgseg *next;\n};\n\ntypedef int __kernel_ipc_pid_t;\n\nstruct msgbuf {\n\t__kernel_long_t mtype;\n\tchar mtext[1];\n};\n\nstruct msg;\n\nstruct msqid_ds {\n\tstruct ipc_perm msg_perm;\n\tstruct msg *msg_first;\n\tstruct msg *msg_last;\n\t__kernel_old_time_t msg_stime;\n\t__kernel_old_time_t msg_rtime;\n\t__kernel_old_time_t msg_ctime;\n\tlong unsigned int msg_lcbytes;\n\tlong unsigned int msg_lqbytes;\n\tshort unsigned int msg_cbytes;\n\tshort unsigned int msg_qnum;\n\tshort unsigned int msg_qbytes;\n\t__kernel_ipc_pid_t msg_lspid;\n\t__kernel_ipc_pid_t msg_lrpid;\n};\n\nstruct msqid64_ds {\n\tstruct ipc64_perm msg_perm;\n\tlong int msg_stime;\n\tlong int msg_rtime;\n\tlong int msg_ctime;\n\tlong unsigned int msg_cbytes;\n\tlong unsigned int msg_qnum;\n\tlong unsigned int msg_qbytes;\n\t__kernel_pid_t msg_lspid;\n\t__kernel_pid_t msg_lrpid;\n\tlong unsigned int __unused4;\n\tlong unsigned int __unused5;\n};\n\nstruct msginfo {\n\tint msgpool;\n\tint msgmap;\n\tint msgmax;\n\tint msgmnb;\n\tint msgmni;\n\tint msgssz;\n\tint msgtql;\n\tshort unsigned int msgseg;\n};\n\ntypedef u16 compat_ipc_pid_t;\n\nstruct compat_msqid64_ds {\n\tstruct compat_ipc64_perm msg_perm;\n\tcompat_ulong_t msg_stime;\n\tcompat_ulong_t msg_stime_high;\n\tcompat_ulong_t msg_rtime;\n\tcompat_ulong_t msg_rtime_high;\n\tcompat_ulong_t msg_ctime;\n\tcompat_ulong_t msg_ctime_high;\n\tcompat_ulong_t msg_cbytes;\n\tcompat_ulong_t msg_qnum;\n\tcompat_ulong_t msg_qbytes;\n\tcompat_pid_t msg_lspid;\n\tcompat_pid_t msg_lrpid;\n\tcompat_ulong_t __unused4;\n\tcompat_ulong_t __unused5;\n};\n\nstruct msg_queue {\n\tstruct kern_ipc_perm q_perm;\n\ttime64_t q_stime;\n\ttime64_t q_rtime;\n\ttime64_t q_ctime;\n\tlong unsigned int q_cbytes;\n\tlong unsigned int q_qnum;\n\tlong unsigned int q_qbytes;\n\tstruct pid *q_lspid;\n\tstruct pid *q_lrpid;\n\tstruct list_head q_messages;\n\tstruct list_head q_receivers;\n\tstruct list_head q_senders;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct msg_receiver {\n\tstruct list_head r_list;\n\tstruct task_struct *r_tsk;\n\tint r_mode;\n\tlong int r_msgtype;\n\tlong int r_maxsize;\n\tstruct msg_msg *r_msg;\n};\n\nstruct msg_sender {\n\tstruct list_head list;\n\tstruct task_struct *tsk;\n\tsize_t msgsz;\n};\n\nstruct compat_msqid_ds {\n\tstruct compat_ipc_perm msg_perm;\n\tcompat_uptr_t msg_first;\n\tcompat_uptr_t msg_last;\n\told_time32_t msg_stime;\n\told_time32_t msg_rtime;\n\told_time32_t msg_ctime;\n\tcompat_ulong_t msg_lcbytes;\n\tcompat_ulong_t msg_lqbytes;\n\tshort unsigned int msg_cbytes;\n\tshort unsigned int msg_qnum;\n\tshort unsigned int msg_qbytes;\n\tcompat_ipc_pid_t msg_lspid;\n\tcompat_ipc_pid_t msg_lrpid;\n};\n\nstruct compat_msgbuf {\n\tcompat_long_t mtype;\n\tchar mtext[1];\n};\n\nstruct sem;\n\nstruct sem_queue;\n\nstruct sem_undo;\n\nstruct semid_ds {\n\tstruct ipc_perm sem_perm;\n\t__kernel_old_time_t sem_otime;\n\t__kernel_old_time_t sem_ctime;\n\tstruct sem *sem_base;\n\tstruct sem_queue *sem_pending;\n\tstruct sem_queue **sem_pending_last;\n\tstruct sem_undo *undo;\n\tshort unsigned int sem_nsems;\n};\n\nstruct sem {\n\tint semval;\n\tstruct pid *sempid;\n\tspinlock_t lock;\n\tstruct list_head pending_alter;\n\tstruct list_head pending_const;\n\ttime64_t sem_otime;\n};\n\nstruct sem_queue {\n\tstruct list_head list;\n\tstruct task_struct *sleeper;\n\tstruct sem_undo *undo;\n\tstruct pid *pid;\n\tint status;\n\tstruct sembuf *sops;\n\tstruct sembuf *blocking;\n\tint nsops;\n\tbool alter;\n\tbool dupsop;\n};\n\nstruct sem_undo {\n\tstruct list_head list_proc;\n\tstruct callback_head rcu;\n\tstruct sem_undo_list *ulp;\n\tstruct list_head list_id;\n\tint semid;\n\tshort int *semadj;\n};\n\nstruct semid64_ds {\n\tstruct ipc64_perm sem_perm;\n\t__kernel_long_t sem_otime;\n\t__kernel_ulong_t __unused1;\n\t__kernel_long_t sem_ctime;\n\t__kernel_ulong_t __unused2;\n\t__kernel_ulong_t sem_nsems;\n\t__kernel_ulong_t __unused3;\n\t__kernel_ulong_t __unused4;\n};\n\nstruct seminfo {\n\tint semmap;\n\tint semmni;\n\tint semmns;\n\tint semmnu;\n\tint semmsl;\n\tint semopm;\n\tint semume;\n\tint semusz;\n\tint semvmx;\n\tint semaem;\n};\n\nstruct sem_undo_list {\n\trefcount_t refcnt;\n\tspinlock_t lock;\n\tstruct list_head list_proc;\n};\n\nstruct compat_semid64_ds {\n\tstruct compat_ipc64_perm sem_perm;\n\tcompat_ulong_t sem_otime;\n\tcompat_ulong_t sem_otime_high;\n\tcompat_ulong_t sem_ctime;\n\tcompat_ulong_t sem_ctime_high;\n\tcompat_ulong_t sem_nsems;\n\tcompat_ulong_t __unused3;\n\tcompat_ulong_t __unused4;\n};\n\nstruct sem_array {\n\tstruct kern_ipc_perm sem_perm;\n\ttime64_t sem_ctime;\n\tstruct list_head pending_alter;\n\tstruct list_head pending_const;\n\tstruct list_head list_id;\n\tint sem_nsems;\n\tint complex_count;\n\tunsigned int use_global_lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct sem sems[0];\n};\n\nstruct compat_semid_ds {\n\tstruct compat_ipc_perm sem_perm;\n\told_time32_t sem_otime;\n\told_time32_t sem_ctime;\n\tcompat_uptr_t sem_base;\n\tcompat_uptr_t sem_pending;\n\tcompat_uptr_t sem_pending_last;\n\tcompat_uptr_t undo;\n\tshort unsigned int sem_nsems;\n};\n\nstruct shmid_ds {\n\tstruct ipc_perm shm_perm;\n\tint shm_segsz;\n\t__kernel_old_time_t shm_atime;\n\t__kernel_old_time_t shm_dtime;\n\t__kernel_old_time_t shm_ctime;\n\t__kernel_ipc_pid_t shm_cpid;\n\t__kernel_ipc_pid_t shm_lpid;\n\tshort unsigned int shm_nattch;\n\tshort unsigned int shm_unused;\n\tvoid *shm_unused2;\n\tvoid *shm_unused3;\n};\n\nstruct shmid64_ds {\n\tstruct ipc64_perm shm_perm;\n\tsize_t shm_segsz;\n\tlong int shm_atime;\n\tlong int shm_dtime;\n\tlong int shm_ctime;\n\t__kernel_pid_t shm_cpid;\n\t__kernel_pid_t shm_lpid;\n\tlong unsigned int shm_nattch;\n\tlong unsigned int __unused4;\n\tlong unsigned int __unused5;\n};\n\nstruct shminfo64 {\n\tlong unsigned int shmmax;\n\tlong unsigned int shmmin;\n\tlong unsigned int shmmni;\n\tlong unsigned int shmseg;\n\tlong unsigned int shmall;\n\tlong unsigned int __unused1;\n\tlong unsigned int __unused2;\n\tlong unsigned int __unused3;\n\tlong unsigned int __unused4;\n};\n\nstruct shminfo {\n\tint shmmax;\n\tint shmmin;\n\tint shmmni;\n\tint shmseg;\n\tint shmall;\n};\n\nstruct shm_info {\n\tint used_ids;\n\t__kernel_ulong_t shm_tot;\n\t__kernel_ulong_t shm_rss;\n\t__kernel_ulong_t shm_swp;\n\t__kernel_ulong_t swap_attempts;\n\t__kernel_ulong_t swap_successes;\n};\n\nstruct compat_shmid64_ds {\n\tstruct compat_ipc64_perm shm_perm;\n\tcompat_size_t shm_segsz;\n\tcompat_ulong_t shm_atime;\n\tcompat_ulong_t shm_atime_high;\n\tcompat_ulong_t shm_dtime;\n\tcompat_ulong_t shm_dtime_high;\n\tcompat_ulong_t shm_ctime;\n\tcompat_ulong_t shm_ctime_high;\n\tcompat_pid_t shm_cpid;\n\tcompat_pid_t shm_lpid;\n\tcompat_ulong_t shm_nattch;\n\tcompat_ulong_t __unused4;\n\tcompat_ulong_t __unused5;\n};\n\nstruct shmid_kernel {\n\tstruct kern_ipc_perm shm_perm;\n\tstruct file *shm_file;\n\tlong unsigned int shm_nattch;\n\tlong unsigned int shm_segsz;\n\ttime64_t shm_atim;\n\ttime64_t shm_dtim;\n\ttime64_t shm_ctim;\n\tstruct pid *shm_cprid;\n\tstruct pid *shm_lprid;\n\tstruct ucounts *mlock_ucounts;\n\tstruct task_struct *shm_creator;\n\tstruct list_head shm_clist;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct shm_file_data {\n\tint id;\n\tstruct ipc_namespace *ns;\n\tstruct file *file;\n\tconst struct vm_operations_struct *vm_ops;\n};\n\nstruct compat_shmid_ds {\n\tstruct compat_ipc_perm shm_perm;\n\tint shm_segsz;\n\told_time32_t shm_atime;\n\told_time32_t shm_dtime;\n\told_time32_t shm_ctime;\n\tcompat_ipc_pid_t shm_cpid;\n\tcompat_ipc_pid_t shm_lpid;\n\tshort unsigned int shm_nattch;\n\tshort unsigned int shm_unused;\n\tcompat_uptr_t shm_unused2;\n\tcompat_uptr_t shm_unused3;\n};\n\nstruct compat_shminfo64 {\n\tcompat_ulong_t shmmax;\n\tcompat_ulong_t shmmin;\n\tcompat_ulong_t shmmni;\n\tcompat_ulong_t shmseg;\n\tcompat_ulong_t shmall;\n\tcompat_ulong_t __unused1;\n\tcompat_ulong_t __unused2;\n\tcompat_ulong_t __unused3;\n\tcompat_ulong_t __unused4;\n};\n\nstruct compat_shm_info {\n\tcompat_int_t used_ids;\n\tcompat_ulong_t shm_tot;\n\tcompat_ulong_t shm_rss;\n\tcompat_ulong_t shm_swp;\n\tcompat_ulong_t swap_attempts;\n\tcompat_ulong_t swap_successes;\n};\n\nstruct compat_ipc_kludge {\n\tcompat_uptr_t msgp;\n\tcompat_long_t msgtyp;\n};\n\nstruct mqueue_fs_context {\n\tstruct ipc_namespace *ipc_ns;\n};\n\nstruct posix_msg_tree_node {\n\tstruct rb_node rb_node;\n\tstruct list_head msg_list;\n\tint priority;\n};\n\nstruct ext_wait_queue {\n\tstruct task_struct *task;\n\tstruct list_head list;\n\tstruct msg_msg *msg;\n\tint state;\n};\n\nstruct mqueue_inode_info {\n\tspinlock_t lock;\n\tstruct inode vfs_inode;\n\twait_queue_head_t wait_q;\n\tstruct rb_root msg_tree;\n\tstruct rb_node *msg_tree_rightmost;\n\tstruct posix_msg_tree_node *node_cache;\n\tstruct mq_attr attr;\n\tstruct sigevent notify;\n\tstruct pid *notify_owner;\n\tu32 notify_self_exec_id;\n\tstruct user_namespace *notify_user_ns;\n\tstruct ucounts *ucounts;\n\tstruct sock *notify_sock;\n\tstruct sk_buff *notify_cookie;\n\tstruct ext_wait_queue e_wait_q[2];\n\tlong unsigned int qsize;\n};\n\nstruct compat_mq_attr {\n\tcompat_long_t mq_flags;\n\tcompat_long_t mq_maxmsg;\n\tcompat_long_t mq_msgsize;\n\tcompat_long_t mq_curmsgs;\n\tcompat_long_t __reserved[4];\n};\n\nstruct key_user {\n\tstruct rb_node node;\n\tstruct mutex cons_lock;\n\tspinlock_t lock;\n\trefcount_t usage;\n\tatomic_t nkeys;\n\tatomic_t nikeys;\n\tkuid_t uid;\n\tint qnkeys;\n\tint qnbytes;\n};\n\nenum key_notification_subtype {\n\tNOTIFY_KEY_INSTANTIATED = 0,\n\tNOTIFY_KEY_UPDATED = 1,\n\tNOTIFY_KEY_LINKED = 2,\n\tNOTIFY_KEY_UNLINKED = 3,\n\tNOTIFY_KEY_CLEARED = 4,\n\tNOTIFY_KEY_REVOKED = 5,\n\tNOTIFY_KEY_INVALIDATED = 6,\n\tNOTIFY_KEY_SETATTR = 7,\n};\n\nstruct key_notification {\n\tstruct watch_notification watch;\n\t__u32 key_id;\n\t__u32 aux;\n};\n\nstruct assoc_array_edit;\n\nstruct assoc_array_ops {\n\tlong unsigned int (*get_key_chunk)(const void *, int);\n\tlong unsigned int (*get_object_key_chunk)(const void *, int);\n\tbool (*compare_object)(const void *, const void *);\n\tint (*diff_objects)(const void *, const void *);\n\tvoid (*free_object)(void *);\n};\n\nstruct assoc_array_node {\n\tstruct assoc_array_ptr *back_pointer;\n\tu8 parent_slot;\n\tstruct assoc_array_ptr *slots[16];\n\tlong unsigned int nr_leaves_on_branch;\n};\n\nstruct assoc_array_shortcut {\n\tstruct assoc_array_ptr *back_pointer;\n\tint parent_slot;\n\tint skip_to_level;\n\tstruct assoc_array_ptr *next_node;\n\tlong unsigned int index_key[0];\n};\n\nstruct assoc_array_edit___2 {\n\tstruct callback_head rcu;\n\tstruct assoc_array *array;\n\tconst struct assoc_array_ops *ops;\n\tconst struct assoc_array_ops *ops_for_excised_subtree;\n\tstruct assoc_array_ptr *leaf;\n\tstruct assoc_array_ptr **leaf_p;\n\tstruct assoc_array_ptr *dead_leaf;\n\tstruct assoc_array_ptr *new_meta[3];\n\tstruct assoc_array_ptr *excised_meta[1];\n\tstruct assoc_array_ptr *excised_subtree;\n\tstruct assoc_array_ptr **set_backpointers[16];\n\tstruct assoc_array_ptr *set_backpointers_to;\n\tstruct assoc_array_node *adjust_count_on;\n\tlong int adjust_count_by;\n\tstruct {\n\t\tstruct assoc_array_ptr **ptr;\n\t\tstruct assoc_array_ptr *to;\n\t} set[2];\n\tstruct {\n\t\tu8 *p;\n\t\tu8 to;\n\t} set_parent_slot[1];\n\tu8 segment_cache[17];\n};\n\nstruct keyring_search_context {\n\tstruct keyring_index_key index_key;\n\tconst struct cred *cred;\n\tstruct key_match_data match_data;\n\tunsigned int flags;\n\tint (*iterator)(const void *, void *);\n\tint skipped_ret;\n\tbool possessed;\n\tkey_ref_t result;\n\ttime64_t now;\n};\n\nstruct keyring_read_iterator_context {\n\tsize_t buflen;\n\tsize_t count;\n\tkey_serial_t *buffer;\n};\n\nstruct keyctl_dh_params {\n\tunion {\n\t\t__s32 private;\n\t\t__s32 priv;\n\t};\n\t__s32 prime;\n\t__s32 base;\n};\n\nstruct keyctl_kdf_params {\n\tchar *hashname;\n\tchar *otherinfo;\n\t__u32 otherinfolen;\n\t__u32 __spare[8];\n};\n\nstruct keyctl_pkey_query {\n\t__u32 supported_ops;\n\t__u32 key_size;\n\t__u16 max_data_size;\n\t__u16 max_sig_size;\n\t__u16 max_enc_size;\n\t__u16 max_dec_size;\n\t__u32 __spare[10];\n};\n\nstruct keyctl_pkey_params {\n\t__s32 key_id;\n\t__u32 in_len;\n\tunion {\n\t\t__u32 out_len;\n\t\t__u32 in2_len;\n\t};\n\t__u32 __spare[7];\n};\n\nstruct request_key_auth {\n\tstruct callback_head rcu;\n\tstruct key *target_key;\n\tstruct key *dest_keyring;\n\tconst struct cred *cred;\n\tvoid *callout_info;\n\tsize_t callout_len;\n\tpid_t pid;\n\tchar op[8];\n};\n\nstruct compat_keyctl_kdf_params {\n\tcompat_uptr_t hashname;\n\tcompat_uptr_t otherinfo;\n\t__u32 otherinfolen;\n\t__u32 __spare[8];\n};\n\nstruct kpp_request {\n\tstruct crypto_async_request base;\n\tstruct scatterlist *src;\n\tstruct scatterlist *dst;\n\tunsigned int src_len;\n\tunsigned int dst_len;\n\tvoid *__ctx[0];\n};\n\nstruct crypto_kpp {\n\tstruct crypto_tfm base;\n};\n\nstruct kpp_alg {\n\tint (*set_secret)(struct crypto_kpp *, const void *, unsigned int);\n\tint (*generate_public_key)(struct kpp_request *);\n\tint (*compute_shared_secret)(struct kpp_request *);\n\tunsigned int (*max_size)(struct crypto_kpp *);\n\tint (*init)(struct crypto_kpp *);\n\tvoid (*exit)(struct crypto_kpp *);\n\tunsigned int reqsize;\n\tstruct crypto_alg base;\n};\n\nstruct dh {\n\tvoid *key;\n\tvoid *p;\n\tvoid *q;\n\tvoid *g;\n\tunsigned int key_size;\n\tunsigned int p_size;\n\tunsigned int q_size;\n\tunsigned int g_size;\n};\n\nstruct dh_completion {\n\tstruct completion completion;\n\tint err;\n};\n\nstruct kdf_sdesc {\n\tstruct shash_desc shash;\n\tchar ctx[0];\n};\n\nenum {\n\tOpt_err___5 = 0,\n\tOpt_enc = 1,\n\tOpt_hash = 2,\n};\n\nstruct vfs_cap_data {\n\t__le32 magic_etc;\n\tstruct {\n\t\t__le32 permitted;\n\t\t__le32 inheritable;\n\t} data[2];\n};\n\nstruct vfs_ns_cap_data {\n\t__le32 magic_etc;\n\tstruct {\n\t\t__le32 permitted;\n\t\t__le32 inheritable;\n\t} data[2];\n\t__le32 rootid;\n};\n\nstruct sctp_endpoint;\n\nunion security_list_options {\n\tint (*binder_set_context_mgr)(struct task_struct *);\n\tint (*binder_transaction)(struct task_struct *, struct task_struct *);\n\tint (*binder_transfer_binder)(struct task_struct *, struct task_struct *);\n\tint (*binder_transfer_file)(struct task_struct *, struct task_struct *, struct file *);\n\tint (*ptrace_access_check)(struct task_struct *, unsigned int);\n\tint (*ptrace_traceme)(struct task_struct *);\n\tint (*capget)(struct task_struct *, kernel_cap_t *, kernel_cap_t *, kernel_cap_t *);\n\tint (*capset)(struct cred *, const struct cred *, const kernel_cap_t *, const kernel_cap_t *, const kernel_cap_t *);\n\tint (*capable)(const struct cred *, struct user_namespace *, int, unsigned int);\n\tint (*quotactl)(int, int, int, struct super_block *);\n\tint (*quota_on)(struct dentry *);\n\tint (*syslog)(int);\n\tint (*settime)(const struct timespec64 *, const struct timezone *);\n\tint (*vm_enough_memory)(struct mm_struct *, long int);\n\tint (*bprm_creds_for_exec)(struct linux_binprm *);\n\tint (*bprm_creds_from_file)(struct linux_binprm *, struct file *);\n\tint (*bprm_check_security)(struct linux_binprm *);\n\tvoid (*bprm_committing_creds)(struct linux_binprm *);\n\tvoid (*bprm_committed_creds)(struct linux_binprm *);\n\tint (*fs_context_dup)(struct fs_context *, struct fs_context *);\n\tint (*fs_context_parse_param)(struct fs_context *, struct fs_parameter *);\n\tint (*sb_alloc_security)(struct super_block *);\n\tvoid (*sb_delete)(struct super_block *);\n\tvoid (*sb_free_security)(struct super_block *);\n\tvoid (*sb_free_mnt_opts)(void *);\n\tint (*sb_eat_lsm_opts)(char *, void **);\n\tint (*sb_mnt_opts_compat)(struct super_block *, void *);\n\tint (*sb_remount)(struct super_block *, void *);\n\tint (*sb_kern_mount)(struct super_block *);\n\tint (*sb_show_options)(struct seq_file *, struct super_block *);\n\tint (*sb_statfs)(struct dentry *);\n\tint (*sb_mount)(const char *, const struct path *, const char *, long unsigned int, void *);\n\tint (*sb_umount)(struct vfsmount *, int);\n\tint (*sb_pivotroot)(const struct path *, const struct path *);\n\tint (*sb_set_mnt_opts)(struct super_block *, void *, long unsigned int, long unsigned int *);\n\tint (*sb_clone_mnt_opts)(const struct super_block *, struct super_block *, long unsigned int, long unsigned int *);\n\tint (*sb_add_mnt_opt)(const char *, const char *, int, void **);\n\tint (*move_mount)(const struct path *, const struct path *);\n\tint (*dentry_init_security)(struct dentry *, int, const struct qstr *, void **, u32 *);\n\tint (*dentry_create_files_as)(struct dentry *, int, struct qstr *, const struct cred *, struct cred *);\n\tint (*path_unlink)(const struct path *, struct dentry *);\n\tint (*path_mkdir)(const struct path *, struct dentry *, umode_t);\n\tint (*path_rmdir)(const struct path *, struct dentry *);\n\tint (*path_mknod)(const struct path *, struct dentry *, umode_t, unsigned int);\n\tint (*path_truncate)(const struct path *);\n\tint (*path_symlink)(const struct path *, struct dentry *, const char *);\n\tint (*path_link)(struct dentry *, const struct path *, struct dentry *);\n\tint (*path_rename)(const struct path *, struct dentry *, const struct path *, struct dentry *);\n\tint (*path_chmod)(const struct path *, umode_t);\n\tint (*path_chown)(const struct path *, kuid_t, kgid_t);\n\tint (*path_chroot)(const struct path *);\n\tint (*path_notify)(const struct path *, u64, unsigned int);\n\tint (*inode_alloc_security)(struct inode *);\n\tvoid (*inode_free_security)(struct inode *);\n\tint (*inode_init_security)(struct inode *, struct inode *, const struct qstr *, const char **, void **, size_t *);\n\tint (*inode_init_security_anon)(struct inode *, const struct qstr *, const struct inode *);\n\tint (*inode_create)(struct inode *, struct dentry *, umode_t);\n\tint (*inode_link)(struct dentry *, struct inode *, struct dentry *);\n\tint (*inode_unlink)(struct inode *, struct dentry *);\n\tint (*inode_symlink)(struct inode *, struct dentry *, const char *);\n\tint (*inode_mkdir)(struct inode *, struct dentry *, umode_t);\n\tint (*inode_rmdir)(struct inode *, struct dentry *);\n\tint (*inode_mknod)(struct inode *, struct dentry *, umode_t, dev_t);\n\tint (*inode_rename)(struct inode *, struct dentry *, struct inode *, struct dentry *);\n\tint (*inode_readlink)(struct dentry *);\n\tint (*inode_follow_link)(struct dentry *, struct inode *, bool);\n\tint (*inode_permission)(struct inode *, int);\n\tint (*inode_setattr)(struct dentry *, struct iattr *);\n\tint (*inode_getattr)(const struct path *);\n\tint (*inode_setxattr)(struct user_namespace *, struct dentry *, const char *, const void *, size_t, int);\n\tvoid (*inode_post_setxattr)(struct dentry *, const char *, const void *, size_t, int);\n\tint (*inode_getxattr)(struct dentry *, const char *);\n\tint (*inode_listxattr)(struct dentry *);\n\tint (*inode_removexattr)(struct user_namespace *, struct dentry *, const char *);\n\tint (*inode_need_killpriv)(struct dentry *);\n\tint (*inode_killpriv)(struct user_namespace *, struct dentry *);\n\tint (*inode_getsecurity)(struct user_namespace *, struct inode *, const char *, void **, bool);\n\tint (*inode_setsecurity)(struct inode *, const char *, const void *, size_t, int);\n\tint (*inode_listsecurity)(struct inode *, char *, size_t);\n\tvoid (*inode_getsecid)(struct inode *, u32 *);\n\tint (*inode_copy_up)(struct dentry *, struct cred **);\n\tint (*inode_copy_up_xattr)(const char *);\n\tint (*kernfs_init_security)(struct kernfs_node *, struct kernfs_node *);\n\tint (*file_permission)(struct file *, int);\n\tint (*file_alloc_security)(struct file *);\n\tvoid (*file_free_security)(struct file *);\n\tint (*file_ioctl)(struct file *, unsigned int, long unsigned int);\n\tint (*mmap_addr)(long unsigned int);\n\tint (*mmap_file)(struct file *, long unsigned int, long unsigned int, long unsigned int);\n\tint (*file_mprotect)(struct vm_area_struct *, long unsigned int, long unsigned int);\n\tint (*file_lock)(struct file *, unsigned int);\n\tint (*file_fcntl)(struct file *, unsigned int, long unsigned int);\n\tvoid (*file_set_fowner)(struct file *);\n\tint (*file_send_sigiotask)(struct task_struct *, struct fown_struct *, int);\n\tint (*file_receive)(struct file *);\n\tint (*file_open)(struct file *);\n\tint (*task_alloc)(struct task_struct *, long unsigned int);\n\tvoid (*task_free)(struct task_struct *);\n\tint (*cred_alloc_blank)(struct cred *, gfp_t);\n\tvoid (*cred_free)(struct cred *);\n\tint (*cred_prepare)(struct cred *, const struct cred *, gfp_t);\n\tvoid (*cred_transfer)(struct cred *, const struct cred *);\n\tvoid (*cred_getsecid)(const struct cred *, u32 *);\n\tint (*kernel_act_as)(struct cred *, u32);\n\tint (*kernel_create_files_as)(struct cred *, struct inode *);\n\tint (*kernel_module_request)(char *);\n\tint (*kernel_load_data)(enum kernel_load_data_id, bool);\n\tint (*kernel_post_load_data)(char *, loff_t, enum kernel_load_data_id, char *);\n\tint (*kernel_read_file)(struct file *, enum kernel_read_file_id, bool);\n\tint (*kernel_post_read_file)(struct file *, char *, loff_t, enum kernel_read_file_id);\n\tint (*task_fix_setuid)(struct cred *, const struct cred *, int);\n\tint (*task_fix_setgid)(struct cred *, const struct cred *, int);\n\tint (*task_setpgid)(struct task_struct *, pid_t);\n\tint (*task_getpgid)(struct task_struct *);\n\tint (*task_getsid)(struct task_struct *);\n\tvoid (*task_getsecid_subj)(struct task_struct *, u32 *);\n\tvoid (*task_getsecid_obj)(struct task_struct *, u32 *);\n\tint (*task_setnice)(struct task_struct *, int);\n\tint (*task_setioprio)(struct task_struct *, int);\n\tint (*task_getioprio)(struct task_struct *);\n\tint (*task_prlimit)(const struct cred *, const struct cred *, unsigned int);\n\tint (*task_setrlimit)(struct task_struct *, unsigned int, struct rlimit *);\n\tint (*task_setscheduler)(struct task_struct *);\n\tint (*task_getscheduler)(struct task_struct *);\n\tint (*task_movememory)(struct task_struct *);\n\tint (*task_kill)(struct task_struct *, struct kernel_siginfo *, int, const struct cred *);\n\tint (*task_prctl)(int, long unsigned int, long unsigned int, long unsigned int, long unsigned int);\n\tvoid (*task_to_inode)(struct task_struct *, struct inode *);\n\tint (*ipc_permission)(struct kern_ipc_perm *, short int);\n\tvoid (*ipc_getsecid)(struct kern_ipc_perm *, u32 *);\n\tint (*msg_msg_alloc_security)(struct msg_msg *);\n\tvoid (*msg_msg_free_security)(struct msg_msg *);\n\tint (*msg_queue_alloc_security)(struct kern_ipc_perm *);\n\tvoid (*msg_queue_free_security)(struct kern_ipc_perm *);\n\tint (*msg_queue_associate)(struct kern_ipc_perm *, int);\n\tint (*msg_queue_msgctl)(struct kern_ipc_perm *, int);\n\tint (*msg_queue_msgsnd)(struct kern_ipc_perm *, struct msg_msg *, int);\n\tint (*msg_queue_msgrcv)(struct kern_ipc_perm *, struct msg_msg *, struct task_struct *, long int, int);\n\tint (*shm_alloc_security)(struct kern_ipc_perm *);\n\tvoid (*shm_free_security)(struct kern_ipc_perm *);\n\tint (*shm_associate)(struct kern_ipc_perm *, int);\n\tint (*shm_shmctl)(struct kern_ipc_perm *, int);\n\tint (*shm_shmat)(struct kern_ipc_perm *, char *, int);\n\tint (*sem_alloc_security)(struct kern_ipc_perm *);\n\tvoid (*sem_free_security)(struct kern_ipc_perm *);\n\tint (*sem_associate)(struct kern_ipc_perm *, int);\n\tint (*sem_semctl)(struct kern_ipc_perm *, int);\n\tint (*sem_semop)(struct kern_ipc_perm *, struct sembuf *, unsigned int, int);\n\tint (*netlink_send)(struct sock *, struct sk_buff *);\n\tvoid (*d_instantiate)(struct dentry *, struct inode *);\n\tint (*getprocattr)(struct task_struct *, char *, char **);\n\tint (*setprocattr)(const char *, void *, size_t);\n\tint (*ismaclabel)(const char *);\n\tint (*secid_to_secctx)(u32, char **, u32 *);\n\tint (*secctx_to_secid)(const char *, u32, u32 *);\n\tvoid (*release_secctx)(char *, u32);\n\tvoid (*inode_invalidate_secctx)(struct inode *);\n\tint (*inode_notifysecctx)(struct inode *, void *, u32);\n\tint (*inode_setsecctx)(struct dentry *, void *, u32);\n\tint (*inode_getsecctx)(struct inode *, void **, u32 *);\n\tint (*post_notification)(const struct cred *, const struct cred *, struct watch_notification *);\n\tint (*watch_key)(struct key *);\n\tint (*unix_stream_connect)(struct sock *, struct sock *, struct sock *);\n\tint (*unix_may_send)(struct socket *, struct socket *);\n\tint (*socket_create)(int, int, int, int);\n\tint (*socket_post_create)(struct socket *, int, int, int, int);\n\tint (*socket_socketpair)(struct socket *, struct socket *);\n\tint (*socket_bind)(struct socket *, struct sockaddr *, int);\n\tint (*socket_connect)(struct socket *, struct sockaddr *, int);\n\tint (*socket_listen)(struct socket *, int);\n\tint (*socket_accept)(struct socket *, struct socket *);\n\tint (*socket_sendmsg)(struct socket *, struct msghdr *, int);\n\tint (*socket_recvmsg)(struct socket *, struct msghdr *, int, int);\n\tint (*socket_getsockname)(struct socket *);\n\tint (*socket_getpeername)(struct socket *);\n\tint (*socket_getsockopt)(struct socket *, int, int);\n\tint (*socket_setsockopt)(struct socket *, int, int);\n\tint (*socket_shutdown)(struct socket *, int);\n\tint (*socket_sock_rcv_skb)(struct sock *, struct sk_buff *);\n\tint (*socket_getpeersec_stream)(struct socket *, char *, int *, unsigned int);\n\tint (*socket_getpeersec_dgram)(struct socket *, struct sk_buff *, u32 *);\n\tint (*sk_alloc_security)(struct sock *, int, gfp_t);\n\tvoid (*sk_free_security)(struct sock *);\n\tvoid (*sk_clone_security)(const struct sock *, struct sock *);\n\tvoid (*sk_getsecid)(struct sock *, u32 *);\n\tvoid (*sock_graft)(struct sock *, struct socket *);\n\tint (*inet_conn_request)(const struct sock *, struct sk_buff *, struct request_sock *);\n\tvoid (*inet_csk_clone)(struct sock *, const struct request_sock *);\n\tvoid (*inet_conn_established)(struct sock *, struct sk_buff *);\n\tint (*secmark_relabel_packet)(u32);\n\tvoid (*secmark_refcount_inc)();\n\tvoid (*secmark_refcount_dec)();\n\tvoid (*req_classify_flow)(const struct request_sock *, struct flowi_common *);\n\tint (*tun_dev_alloc_security)(void **);\n\tvoid (*tun_dev_free_security)(void *);\n\tint (*tun_dev_create)();\n\tint (*tun_dev_attach_queue)(void *);\n\tint (*tun_dev_attach)(struct sock *, void *);\n\tint (*tun_dev_open)(void *);\n\tint (*sctp_assoc_request)(struct sctp_endpoint *, struct sk_buff *);\n\tint (*sctp_bind_connect)(struct sock *, int, struct sockaddr *, int);\n\tvoid (*sctp_sk_clone)(struct sctp_endpoint *, struct sock *, struct sock *);\n\tint (*ib_pkey_access)(void *, u64, u16);\n\tint (*ib_endport_manage_subnet)(void *, const char *, u8);\n\tint (*ib_alloc_security)(void **);\n\tvoid (*ib_free_security)(void *);\n\tint (*xfrm_policy_alloc_security)(struct xfrm_sec_ctx **, struct xfrm_user_sec_ctx *, gfp_t);\n\tint (*xfrm_policy_clone_security)(struct xfrm_sec_ctx *, struct xfrm_sec_ctx **);\n\tvoid (*xfrm_policy_free_security)(struct xfrm_sec_ctx *);\n\tint (*xfrm_policy_delete_security)(struct xfrm_sec_ctx *);\n\tint (*xfrm_state_alloc)(struct xfrm_state *, struct xfrm_user_sec_ctx *);\n\tint (*xfrm_state_alloc_acquire)(struct xfrm_state *, struct xfrm_sec_ctx *, u32);\n\tvoid (*xfrm_state_free_security)(struct xfrm_state *);\n\tint (*xfrm_state_delete_security)(struct xfrm_state *);\n\tint (*xfrm_policy_lookup)(struct xfrm_sec_ctx *, u32);\n\tint (*xfrm_state_pol_flow_match)(struct xfrm_state *, struct xfrm_policy *, const struct flowi_common *);\n\tint (*xfrm_decode_session)(struct sk_buff *, u32 *, int);\n\tint (*key_alloc)(struct key *, const struct cred *, long unsigned int);\n\tvoid (*key_free)(struct key *);\n\tint (*key_permission)(key_ref_t, const struct cred *, enum key_need_perm);\n\tint (*key_getsecurity)(struct key *, char **);\n\tint (*audit_rule_init)(u32, u32, char *, void **);\n\tint (*audit_rule_known)(struct audit_krule *);\n\tint (*audit_rule_match)(u32, u32, u32, void *);\n\tvoid (*audit_rule_free)(void *);\n\tint (*bpf)(int, union bpf_attr *, unsigned int);\n\tint (*bpf_map)(struct bpf_map *, fmode_t);\n\tint (*bpf_prog)(struct bpf_prog *);\n\tint (*bpf_map_alloc_security)(struct bpf_map *);\n\tvoid (*bpf_map_free_security)(struct bpf_map *);\n\tint (*bpf_prog_alloc_security)(struct bpf_prog_aux *);\n\tvoid (*bpf_prog_free_security)(struct bpf_prog_aux *);\n\tint (*locked_down)(enum lockdown_reason);\n\tint (*perf_event_open)(struct perf_event_attr *, int);\n\tint (*perf_event_alloc)(struct perf_event *);\n\tvoid (*perf_event_free)(struct perf_event *);\n\tint (*perf_event_read)(struct perf_event *);\n\tint (*perf_event_write)(struct perf_event *);\n};\n\nstruct security_hook_heads {\n\tstruct hlist_head binder_set_context_mgr;\n\tstruct hlist_head binder_transaction;\n\tstruct hlist_head binder_transfer_binder;\n\tstruct hlist_head binder_transfer_file;\n\tstruct hlist_head ptrace_access_check;\n\tstruct hlist_head ptrace_traceme;\n\tstruct hlist_head capget;\n\tstruct hlist_head capset;\n\tstruct hlist_head capable;\n\tstruct hlist_head quotactl;\n\tstruct hlist_head quota_on;\n\tstruct hlist_head syslog;\n\tstruct hlist_head settime;\n\tstruct hlist_head vm_enough_memory;\n\tstruct hlist_head bprm_creds_for_exec;\n\tstruct hlist_head bprm_creds_from_file;\n\tstruct hlist_head bprm_check_security;\n\tstruct hlist_head bprm_committing_creds;\n\tstruct hlist_head bprm_committed_creds;\n\tstruct hlist_head fs_context_dup;\n\tstruct hlist_head fs_context_parse_param;\n\tstruct hlist_head sb_alloc_security;\n\tstruct hlist_head sb_delete;\n\tstruct hlist_head sb_free_security;\n\tstruct hlist_head sb_free_mnt_opts;\n\tstruct hlist_head sb_eat_lsm_opts;\n\tstruct hlist_head sb_mnt_opts_compat;\n\tstruct hlist_head sb_remount;\n\tstruct hlist_head sb_kern_mount;\n\tstruct hlist_head sb_show_options;\n\tstruct hlist_head sb_statfs;\n\tstruct hlist_head sb_mount;\n\tstruct hlist_head sb_umount;\n\tstruct hlist_head sb_pivotroot;\n\tstruct hlist_head sb_set_mnt_opts;\n\tstruct hlist_head sb_clone_mnt_opts;\n\tstruct hlist_head sb_add_mnt_opt;\n\tstruct hlist_head move_mount;\n\tstruct hlist_head dentry_init_security;\n\tstruct hlist_head dentry_create_files_as;\n\tstruct hlist_head path_unlink;\n\tstruct hlist_head path_mkdir;\n\tstruct hlist_head path_rmdir;\n\tstruct hlist_head path_mknod;\n\tstruct hlist_head path_truncate;\n\tstruct hlist_head path_symlink;\n\tstruct hlist_head path_link;\n\tstruct hlist_head path_rename;\n\tstruct hlist_head path_chmod;\n\tstruct hlist_head path_chown;\n\tstruct hlist_head path_chroot;\n\tstruct hlist_head path_notify;\n\tstruct hlist_head inode_alloc_security;\n\tstruct hlist_head inode_free_security;\n\tstruct hlist_head inode_init_security;\n\tstruct hlist_head inode_init_security_anon;\n\tstruct hlist_head inode_create;\n\tstruct hlist_head inode_link;\n\tstruct hlist_head inode_unlink;\n\tstruct hlist_head inode_symlink;\n\tstruct hlist_head inode_mkdir;\n\tstruct hlist_head inode_rmdir;\n\tstruct hlist_head inode_mknod;\n\tstruct hlist_head inode_rename;\n\tstruct hlist_head inode_readlink;\n\tstruct hlist_head inode_follow_link;\n\tstruct hlist_head inode_permission;\n\tstruct hlist_head inode_setattr;\n\tstruct hlist_head inode_getattr;\n\tstruct hlist_head inode_setxattr;\n\tstruct hlist_head inode_post_setxattr;\n\tstruct hlist_head inode_getxattr;\n\tstruct hlist_head inode_listxattr;\n\tstruct hlist_head inode_removexattr;\n\tstruct hlist_head inode_need_killpriv;\n\tstruct hlist_head inode_killpriv;\n\tstruct hlist_head inode_getsecurity;\n\tstruct hlist_head inode_setsecurity;\n\tstruct hlist_head inode_listsecurity;\n\tstruct hlist_head inode_getsecid;\n\tstruct hlist_head inode_copy_up;\n\tstruct hlist_head inode_copy_up_xattr;\n\tstruct hlist_head kernfs_init_security;\n\tstruct hlist_head file_permission;\n\tstruct hlist_head file_alloc_security;\n\tstruct hlist_head file_free_security;\n\tstruct hlist_head file_ioctl;\n\tstruct hlist_head mmap_addr;\n\tstruct hlist_head mmap_file;\n\tstruct hlist_head file_mprotect;\n\tstruct hlist_head file_lock;\n\tstruct hlist_head file_fcntl;\n\tstruct hlist_head file_set_fowner;\n\tstruct hlist_head file_send_sigiotask;\n\tstruct hlist_head file_receive;\n\tstruct hlist_head file_open;\n\tstruct hlist_head task_alloc;\n\tstruct hlist_head task_free;\n\tstruct hlist_head cred_alloc_blank;\n\tstruct hlist_head cred_free;\n\tstruct hlist_head cred_prepare;\n\tstruct hlist_head cred_transfer;\n\tstruct hlist_head cred_getsecid;\n\tstruct hlist_head kernel_act_as;\n\tstruct hlist_head kernel_create_files_as;\n\tstruct hlist_head kernel_module_request;\n\tstruct hlist_head kernel_load_data;\n\tstruct hlist_head kernel_post_load_data;\n\tstruct hlist_head kernel_read_file;\n\tstruct hlist_head kernel_post_read_file;\n\tstruct hlist_head task_fix_setuid;\n\tstruct hlist_head task_fix_setgid;\n\tstruct hlist_head task_setpgid;\n\tstruct hlist_head task_getpgid;\n\tstruct hlist_head task_getsid;\n\tstruct hlist_head task_getsecid_subj;\n\tstruct hlist_head task_getsecid_obj;\n\tstruct hlist_head task_setnice;\n\tstruct hlist_head task_setioprio;\n\tstruct hlist_head task_getioprio;\n\tstruct hlist_head task_prlimit;\n\tstruct hlist_head task_setrlimit;\n\tstruct hlist_head task_setscheduler;\n\tstruct hlist_head task_getscheduler;\n\tstruct hlist_head task_movememory;\n\tstruct hlist_head task_kill;\n\tstruct hlist_head task_prctl;\n\tstruct hlist_head task_to_inode;\n\tstruct hlist_head ipc_permission;\n\tstruct hlist_head ipc_getsecid;\n\tstruct hlist_head msg_msg_alloc_security;\n\tstruct hlist_head msg_msg_free_security;\n\tstruct hlist_head msg_queue_alloc_security;\n\tstruct hlist_head msg_queue_free_security;\n\tstruct hlist_head msg_queue_associate;\n\tstruct hlist_head msg_queue_msgctl;\n\tstruct hlist_head msg_queue_msgsnd;\n\tstruct hlist_head msg_queue_msgrcv;\n\tstruct hlist_head shm_alloc_security;\n\tstruct hlist_head shm_free_security;\n\tstruct hlist_head shm_associate;\n\tstruct hlist_head shm_shmctl;\n\tstruct hlist_head shm_shmat;\n\tstruct hlist_head sem_alloc_security;\n\tstruct hlist_head sem_free_security;\n\tstruct hlist_head sem_associate;\n\tstruct hlist_head sem_semctl;\n\tstruct hlist_head sem_semop;\n\tstruct hlist_head netlink_send;\n\tstruct hlist_head d_instantiate;\n\tstruct hlist_head getprocattr;\n\tstruct hlist_head setprocattr;\n\tstruct hlist_head ismaclabel;\n\tstruct hlist_head secid_to_secctx;\n\tstruct hlist_head secctx_to_secid;\n\tstruct hlist_head release_secctx;\n\tstruct hlist_head inode_invalidate_secctx;\n\tstruct hlist_head inode_notifysecctx;\n\tstruct hlist_head inode_setsecctx;\n\tstruct hlist_head inode_getsecctx;\n\tstruct hlist_head post_notification;\n\tstruct hlist_head watch_key;\n\tstruct hlist_head unix_stream_connect;\n\tstruct hlist_head unix_may_send;\n\tstruct hlist_head socket_create;\n\tstruct hlist_head socket_post_create;\n\tstruct hlist_head socket_socketpair;\n\tstruct hlist_head socket_bind;\n\tstruct hlist_head socket_connect;\n\tstruct hlist_head socket_listen;\n\tstruct hlist_head socket_accept;\n\tstruct hlist_head socket_sendmsg;\n\tstruct hlist_head socket_recvmsg;\n\tstruct hlist_head socket_getsockname;\n\tstruct hlist_head socket_getpeername;\n\tstruct hlist_head socket_getsockopt;\n\tstruct hlist_head socket_setsockopt;\n\tstruct hlist_head socket_shutdown;\n\tstruct hlist_head socket_sock_rcv_skb;\n\tstruct hlist_head socket_getpeersec_stream;\n\tstruct hlist_head socket_getpeersec_dgram;\n\tstruct hlist_head sk_alloc_security;\n\tstruct hlist_head sk_free_security;\n\tstruct hlist_head sk_clone_security;\n\tstruct hlist_head sk_getsecid;\n\tstruct hlist_head sock_graft;\n\tstruct hlist_head inet_conn_request;\n\tstruct hlist_head inet_csk_clone;\n\tstruct hlist_head inet_conn_established;\n\tstruct hlist_head secmark_relabel_packet;\n\tstruct hlist_head secmark_refcount_inc;\n\tstruct hlist_head secmark_refcount_dec;\n\tstruct hlist_head req_classify_flow;\n\tstruct hlist_head tun_dev_alloc_security;\n\tstruct hlist_head tun_dev_free_security;\n\tstruct hlist_head tun_dev_create;\n\tstruct hlist_head tun_dev_attach_queue;\n\tstruct hlist_head tun_dev_attach;\n\tstruct hlist_head tun_dev_open;\n\tstruct hlist_head sctp_assoc_request;\n\tstruct hlist_head sctp_bind_connect;\n\tstruct hlist_head sctp_sk_clone;\n\tstruct hlist_head ib_pkey_access;\n\tstruct hlist_head ib_endport_manage_subnet;\n\tstruct hlist_head ib_alloc_security;\n\tstruct hlist_head ib_free_security;\n\tstruct hlist_head xfrm_policy_alloc_security;\n\tstruct hlist_head xfrm_policy_clone_security;\n\tstruct hlist_head xfrm_policy_free_security;\n\tstruct hlist_head xfrm_policy_delete_security;\n\tstruct hlist_head xfrm_state_alloc;\n\tstruct hlist_head xfrm_state_alloc_acquire;\n\tstruct hlist_head xfrm_state_free_security;\n\tstruct hlist_head xfrm_state_delete_security;\n\tstruct hlist_head xfrm_policy_lookup;\n\tstruct hlist_head xfrm_state_pol_flow_match;\n\tstruct hlist_head xfrm_decode_session;\n\tstruct hlist_head key_alloc;\n\tstruct hlist_head key_free;\n\tstruct hlist_head key_permission;\n\tstruct hlist_head key_getsecurity;\n\tstruct hlist_head audit_rule_init;\n\tstruct hlist_head audit_rule_known;\n\tstruct hlist_head audit_rule_match;\n\tstruct hlist_head audit_rule_free;\n\tstruct hlist_head bpf;\n\tstruct hlist_head bpf_map;\n\tstruct hlist_head bpf_prog;\n\tstruct hlist_head bpf_map_alloc_security;\n\tstruct hlist_head bpf_map_free_security;\n\tstruct hlist_head bpf_prog_alloc_security;\n\tstruct hlist_head bpf_prog_free_security;\n\tstruct hlist_head locked_down;\n\tstruct hlist_head perf_event_open;\n\tstruct hlist_head perf_event_alloc;\n\tstruct hlist_head perf_event_free;\n\tstruct hlist_head perf_event_read;\n\tstruct hlist_head perf_event_write;\n};\n\nstruct security_hook_list {\n\tstruct hlist_node list;\n\tstruct hlist_head *head;\n\tunion security_list_options hook;\n\tchar *lsm;\n};\n\nenum lsm_order {\n\tLSM_ORDER_FIRST = 4294967295,\n\tLSM_ORDER_MUTABLE = 0,\n};\n\nstruct lsm_info {\n\tconst char *name;\n\tenum lsm_order order;\n\tlong unsigned int flags;\n\tint *enabled;\n\tint (*init)();\n\tstruct lsm_blob_sizes *blobs;\n};\n\nenum lsm_event {\n\tLSM_POLICY_CHANGE = 0,\n};\n\nstruct ethhdr {\n\tunsigned char h_dest[6];\n\tunsigned char h_source[6];\n\t__be16 h_proto;\n};\n\nstruct ethtool_drvinfo {\n\t__u32 cmd;\n\tchar driver[32];\n\tchar version[32];\n\tchar fw_version[32];\n\tchar bus_info[32];\n\tchar erom_version[32];\n\tchar reserved2[12];\n\t__u32 n_priv_flags;\n\t__u32 n_stats;\n\t__u32 testinfo_len;\n\t__u32 eedump_len;\n\t__u32 regdump_len;\n};\n\nstruct ethtool_wolinfo {\n\t__u32 cmd;\n\t__u32 supported;\n\t__u32 wolopts;\n\t__u8 sopass[6];\n};\n\nstruct ethtool_tunable {\n\t__u32 cmd;\n\t__u32 id;\n\t__u32 type_id;\n\t__u32 len;\n\tvoid *data[0];\n};\n\nstruct ethtool_regs {\n\t__u32 cmd;\n\t__u32 version;\n\t__u32 len;\n\t__u8 data[0];\n};\n\nstruct ethtool_eeprom {\n\t__u32 cmd;\n\t__u32 magic;\n\t__u32 offset;\n\t__u32 len;\n\t__u8 data[0];\n};\n\nstruct ethtool_eee {\n\t__u32 cmd;\n\t__u32 supported;\n\t__u32 advertised;\n\t__u32 lp_advertised;\n\t__u32 eee_active;\n\t__u32 eee_enabled;\n\t__u32 tx_lpi_enabled;\n\t__u32 tx_lpi_timer;\n\t__u32 reserved[2];\n};\n\nstruct ethtool_modinfo {\n\t__u32 cmd;\n\t__u32 type;\n\t__u32 eeprom_len;\n\t__u32 reserved[8];\n};\n\nstruct ethtool_coalesce {\n\t__u32 cmd;\n\t__u32 rx_coalesce_usecs;\n\t__u32 rx_max_coalesced_frames;\n\t__u32 rx_coalesce_usecs_irq;\n\t__u32 rx_max_coalesced_frames_irq;\n\t__u32 tx_coalesce_usecs;\n\t__u32 tx_max_coalesced_frames;\n\t__u32 tx_coalesce_usecs_irq;\n\t__u32 tx_max_coalesced_frames_irq;\n\t__u32 stats_block_coalesce_usecs;\n\t__u32 use_adaptive_rx_coalesce;\n\t__u32 use_adaptive_tx_coalesce;\n\t__u32 pkt_rate_low;\n\t__u32 rx_coalesce_usecs_low;\n\t__u32 rx_max_coalesced_frames_low;\n\t__u32 tx_coalesce_usecs_low;\n\t__u32 tx_max_coalesced_frames_low;\n\t__u32 pkt_rate_high;\n\t__u32 rx_coalesce_usecs_high;\n\t__u32 rx_max_coalesced_frames_high;\n\t__u32 tx_coalesce_usecs_high;\n\t__u32 tx_max_coalesced_frames_high;\n\t__u32 rate_sample_interval;\n};\n\nstruct ethtool_ringparam {\n\t__u32 cmd;\n\t__u32 rx_max_pending;\n\t__u32 rx_mini_max_pending;\n\t__u32 rx_jumbo_max_pending;\n\t__u32 tx_max_pending;\n\t__u32 rx_pending;\n\t__u32 rx_mini_pending;\n\t__u32 rx_jumbo_pending;\n\t__u32 tx_pending;\n};\n\nstruct ethtool_channels {\n\t__u32 cmd;\n\t__u32 max_rx;\n\t__u32 max_tx;\n\t__u32 max_other;\n\t__u32 max_combined;\n\t__u32 rx_count;\n\t__u32 tx_count;\n\t__u32 other_count;\n\t__u32 combined_count;\n};\n\nstruct ethtool_pauseparam {\n\t__u32 cmd;\n\t__u32 autoneg;\n\t__u32 rx_pause;\n\t__u32 tx_pause;\n};\n\nenum ethtool_link_ext_state {\n\tETHTOOL_LINK_EXT_STATE_AUTONEG = 0,\n\tETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE = 1,\n\tETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH = 2,\n\tETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY = 3,\n\tETHTOOL_LINK_EXT_STATE_NO_CABLE = 4,\n\tETHTOOL_LINK_EXT_STATE_CABLE_ISSUE = 5,\n\tETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE = 6,\n\tETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE = 7,\n\tETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED = 8,\n\tETHTOOL_LINK_EXT_STATE_OVERHEAT = 9,\n};\n\nenum ethtool_link_ext_substate_autoneg {\n\tETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED = 1,\n\tETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED = 2,\n\tETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED = 3,\n\tETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE = 4,\n\tETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE = 5,\n\tETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD = 6,\n};\n\nenum ethtool_link_ext_substate_link_training {\n\tETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED = 1,\n\tETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT = 2,\n\tETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY = 3,\n\tETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT = 4,\n};\n\nenum ethtool_link_ext_substate_link_logical_mismatch {\n\tETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK = 1,\n\tETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK = 2,\n\tETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS = 3,\n\tETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED = 4,\n\tETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED = 5,\n};\n\nenum ethtool_link_ext_substate_bad_signal_integrity {\n\tETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS = 1,\n\tETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE = 2,\n};\n\nenum ethtool_link_ext_substate_cable_issue {\n\tETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE = 1,\n\tETHTOOL_LINK_EXT_SUBSTATE_CI_CABLE_TEST_FAILURE = 2,\n};\n\nstruct ethtool_test {\n\t__u32 cmd;\n\t__u32 flags;\n\t__u32 reserved;\n\t__u32 len;\n\t__u64 data[0];\n};\n\nstruct ethtool_stats {\n\t__u32 cmd;\n\t__u32 n_stats;\n\t__u64 data[0];\n};\n\nstruct ethtool_tcpip4_spec {\n\t__be32 ip4src;\n\t__be32 ip4dst;\n\t__be16 psrc;\n\t__be16 pdst;\n\t__u8 tos;\n};\n\nstruct ethtool_ah_espip4_spec {\n\t__be32 ip4src;\n\t__be32 ip4dst;\n\t__be32 spi;\n\t__u8 tos;\n};\n\nstruct ethtool_usrip4_spec {\n\t__be32 ip4src;\n\t__be32 ip4dst;\n\t__be32 l4_4_bytes;\n\t__u8 tos;\n\t__u8 ip_ver;\n\t__u8 proto;\n};\n\nstruct ethtool_tcpip6_spec {\n\t__be32 ip6src[4];\n\t__be32 ip6dst[4];\n\t__be16 psrc;\n\t__be16 pdst;\n\t__u8 tclass;\n};\n\nstruct ethtool_ah_espip6_spec {\n\t__be32 ip6src[4];\n\t__be32 ip6dst[4];\n\t__be32 spi;\n\t__u8 tclass;\n};\n\nstruct ethtool_usrip6_spec {\n\t__be32 ip6src[4];\n\t__be32 ip6dst[4];\n\t__be32 l4_4_bytes;\n\t__u8 tclass;\n\t__u8 l4_proto;\n};\n\nunion ethtool_flow_union {\n\tstruct ethtool_tcpip4_spec tcp_ip4_spec;\n\tstruct ethtool_tcpip4_spec udp_ip4_spec;\n\tstruct ethtool_tcpip4_spec sctp_ip4_spec;\n\tstruct ethtool_ah_espip4_spec ah_ip4_spec;\n\tstruct ethtool_ah_espip4_spec esp_ip4_spec;\n\tstruct ethtool_usrip4_spec usr_ip4_spec;\n\tstruct ethtool_tcpip6_spec tcp_ip6_spec;\n\tstruct ethtool_tcpip6_spec udp_ip6_spec;\n\tstruct ethtool_tcpip6_spec sctp_ip6_spec;\n\tstruct ethtool_ah_espip6_spec ah_ip6_spec;\n\tstruct ethtool_ah_espip6_spec esp_ip6_spec;\n\tstruct ethtool_usrip6_spec usr_ip6_spec;\n\tstruct ethhdr ether_spec;\n\t__u8 hdata[52];\n};\n\nstruct ethtool_flow_ext {\n\t__u8 padding[2];\n\tunsigned char h_dest[6];\n\t__be16 vlan_etype;\n\t__be16 vlan_tci;\n\t__be32 data[2];\n};\n\nstruct ethtool_rx_flow_spec {\n\t__u32 flow_type;\n\tunion ethtool_flow_union h_u;\n\tstruct ethtool_flow_ext h_ext;\n\tunion ethtool_flow_union m_u;\n\tstruct ethtool_flow_ext m_ext;\n\t__u64 ring_cookie;\n\t__u32 location;\n};\n\nstruct ethtool_rxnfc {\n\t__u32 cmd;\n\t__u32 flow_type;\n\t__u64 data;\n\tstruct ethtool_rx_flow_spec fs;\n\tunion {\n\t\t__u32 rule_cnt;\n\t\t__u32 rss_context;\n\t};\n\t__u32 rule_locs[0];\n};\n\nstruct ethtool_flash {\n\t__u32 cmd;\n\t__u32 region;\n\tchar data[128];\n};\n\nstruct ethtool_dump {\n\t__u32 cmd;\n\t__u32 version;\n\t__u32 flag;\n\t__u32 len;\n\t__u8 data[0];\n};\n\nstruct ethtool_ts_info {\n\t__u32 cmd;\n\t__u32 so_timestamping;\n\t__s32 phc_index;\n\t__u32 tx_types;\n\t__u32 tx_reserved[3];\n\t__u32 rx_filters;\n\t__u32 rx_reserved[3];\n};\n\nstruct ethtool_fecparam {\n\t__u32 cmd;\n\t__u32 active_fec;\n\t__u32 fec;\n\t__u32 reserved;\n};\n\nenum ethtool_link_mode_bit_indices {\n\tETHTOOL_LINK_MODE_10baseT_Half_BIT = 0,\n\tETHTOOL_LINK_MODE_10baseT_Full_BIT = 1,\n\tETHTOOL_LINK_MODE_100baseT_Half_BIT = 2,\n\tETHTOOL_LINK_MODE_100baseT_Full_BIT = 3,\n\tETHTOOL_LINK_MODE_1000baseT_Half_BIT = 4,\n\tETHTOOL_LINK_MODE_1000baseT_Full_BIT = 5,\n\tETHTOOL_LINK_MODE_Autoneg_BIT = 6,\n\tETHTOOL_LINK_MODE_TP_BIT = 7,\n\tETHTOOL_LINK_MODE_AUI_BIT = 8,\n\tETHTOOL_LINK_MODE_MII_BIT = 9,\n\tETHTOOL_LINK_MODE_FIBRE_BIT = 10,\n\tETHTOOL_LINK_MODE_BNC_BIT = 11,\n\tETHTOOL_LINK_MODE_10000baseT_Full_BIT = 12,\n\tETHTOOL_LINK_MODE_Pause_BIT = 13,\n\tETHTOOL_LINK_MODE_Asym_Pause_BIT = 14,\n\tETHTOOL_LINK_MODE_2500baseX_Full_BIT = 15,\n\tETHTOOL_LINK_MODE_Backplane_BIT = 16,\n\tETHTOOL_LINK_MODE_1000baseKX_Full_BIT = 17,\n\tETHTOOL_LINK_MODE_10000baseKX4_Full_BIT = 18,\n\tETHTOOL_LINK_MODE_10000baseKR_Full_BIT = 19,\n\tETHTOOL_LINK_MODE_10000baseR_FEC_BIT = 20,\n\tETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT = 21,\n\tETHTOOL_LINK_MODE_20000baseKR2_Full_BIT = 22,\n\tETHTOOL_LINK_MODE_40000baseKR4_Full_BIT = 23,\n\tETHTOOL_LINK_MODE_40000baseCR4_Full_BIT = 24,\n\tETHTOOL_LINK_MODE_40000baseSR4_Full_BIT = 25,\n\tETHTOOL_LINK_MODE_40000baseLR4_Full_BIT = 26,\n\tETHTOOL_LINK_MODE_56000baseKR4_Full_BIT = 27,\n\tETHTOOL_LINK_MODE_56000baseCR4_Full_BIT = 28,\n\tETHTOOL_LINK_MODE_56000baseSR4_Full_BIT = 29,\n\tETHTOOL_LINK_MODE_56000baseLR4_Full_BIT = 30,\n\tETHTOOL_LINK_MODE_25000baseCR_Full_BIT = 31,\n\tETHTOOL_LINK_MODE_25000baseKR_Full_BIT = 32,\n\tETHTOOL_LINK_MODE_25000baseSR_Full_BIT = 33,\n\tETHTOOL_LINK_MODE_50000baseCR2_Full_BIT = 34,\n\tETHTOOL_LINK_MODE_50000baseKR2_Full_BIT = 35,\n\tETHTOOL_LINK_MODE_100000baseKR4_Full_BIT = 36,\n\tETHTOOL_LINK_MODE_100000baseSR4_Full_BIT = 37,\n\tETHTOOL_LINK_MODE_100000baseCR4_Full_BIT = 38,\n\tETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT = 39,\n\tETHTOOL_LINK_MODE_50000baseSR2_Full_BIT = 40,\n\tETHTOOL_LINK_MODE_1000baseX_Full_BIT = 41,\n\tETHTOOL_LINK_MODE_10000baseCR_Full_BIT = 42,\n\tETHTOOL_LINK_MODE_10000baseSR_Full_BIT = 43,\n\tETHTOOL_LINK_MODE_10000baseLR_Full_BIT = 44,\n\tETHTOOL_LINK_MODE_10000baseLRM_Full_BIT = 45,\n\tETHTOOL_LINK_MODE_10000baseER_Full_BIT = 46,\n\tETHTOOL_LINK_MODE_2500baseT_Full_BIT = 47,\n\tETHTOOL_LINK_MODE_5000baseT_Full_BIT = 48,\n\tETHTOOL_LINK_MODE_FEC_NONE_BIT = 49,\n\tETHTOOL_LINK_MODE_FEC_RS_BIT = 50,\n\tETHTOOL_LINK_MODE_FEC_BASER_BIT = 51,\n\tETHTOOL_LINK_MODE_50000baseKR_Full_BIT = 52,\n\tETHTOOL_LINK_MODE_50000baseSR_Full_BIT = 53,\n\tETHTOOL_LINK_MODE_50000baseCR_Full_BIT = 54,\n\tETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT = 55,\n\tETHTOOL_LINK_MODE_50000baseDR_Full_BIT = 56,\n\tETHTOOL_LINK_MODE_100000baseKR2_Full_BIT = 57,\n\tETHTOOL_LINK_MODE_100000baseSR2_Full_BIT = 58,\n\tETHTOOL_LINK_MODE_100000baseCR2_Full_BIT = 59,\n\tETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT = 60,\n\tETHTOOL_LINK_MODE_100000baseDR2_Full_BIT = 61,\n\tETHTOOL_LINK_MODE_200000baseKR4_Full_BIT = 62,\n\tETHTOOL_LINK_MODE_200000baseSR4_Full_BIT = 63,\n\tETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64,\n\tETHTOOL_LINK_MODE_200000baseDR4_Full_BIT = 65,\n\tETHTOOL_LINK_MODE_200000baseCR4_Full_BIT = 66,\n\tETHTOOL_LINK_MODE_100baseT1_Full_BIT = 67,\n\tETHTOOL_LINK_MODE_1000baseT1_Full_BIT = 68,\n\tETHTOOL_LINK_MODE_400000baseKR8_Full_BIT = 69,\n\tETHTOOL_LINK_MODE_400000baseSR8_Full_BIT = 70,\n\tETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71,\n\tETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72,\n\tETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73,\n\tETHTOOL_LINK_MODE_FEC_LLRS_BIT = 74,\n\tETHTOOL_LINK_MODE_100000baseKR_Full_BIT = 75,\n\tETHTOOL_LINK_MODE_100000baseSR_Full_BIT = 76,\n\tETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT = 77,\n\tETHTOOL_LINK_MODE_100000baseCR_Full_BIT = 78,\n\tETHTOOL_LINK_MODE_100000baseDR_Full_BIT = 79,\n\tETHTOOL_LINK_MODE_200000baseKR2_Full_BIT = 80,\n\tETHTOOL_LINK_MODE_200000baseSR2_Full_BIT = 81,\n\tETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT = 82,\n\tETHTOOL_LINK_MODE_200000baseDR2_Full_BIT = 83,\n\tETHTOOL_LINK_MODE_200000baseCR2_Full_BIT = 84,\n\tETHTOOL_LINK_MODE_400000baseKR4_Full_BIT = 85,\n\tETHTOOL_LINK_MODE_400000baseSR4_Full_BIT = 86,\n\tETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87,\n\tETHTOOL_LINK_MODE_400000baseDR4_Full_BIT = 88,\n\tETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89,\n\tETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90,\n\tETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91,\n\t__ETHTOOL_LINK_MODE_MASK_NBITS = 92,\n};\n\nstruct ethtool_link_settings {\n\t__u32 cmd;\n\t__u32 speed;\n\t__u8 duplex;\n\t__u8 port;\n\t__u8 phy_address;\n\t__u8 autoneg;\n\t__u8 mdio_support;\n\t__u8 eth_tp_mdix;\n\t__u8 eth_tp_mdix_ctrl;\n\t__s8 link_mode_masks_nwords;\n\t__u8 transceiver;\n\t__u8 master_slave_cfg;\n\t__u8 master_slave_state;\n\t__u8 reserved1[1];\n\t__u32 reserved[7];\n\t__u32 link_mode_masks[0];\n};\n\nstruct ethtool_link_ext_state_info {\n\tenum ethtool_link_ext_state link_ext_state;\n\tunion {\n\t\tenum ethtool_link_ext_substate_autoneg autoneg;\n\t\tenum ethtool_link_ext_substate_link_training link_training;\n\t\tenum ethtool_link_ext_substate_link_logical_mismatch link_logical_mismatch;\n\t\tenum ethtool_link_ext_substate_bad_signal_integrity bad_signal_integrity;\n\t\tenum ethtool_link_ext_substate_cable_issue cable_issue;\n\t\tu8 __link_ext_substate;\n\t};\n};\n\nstruct ethtool_link_ksettings {\n\tstruct ethtool_link_settings base;\n\tstruct {\n\t\tlong unsigned int supported[2];\n\t\tlong unsigned int advertising[2];\n\t\tlong unsigned int lp_advertising[2];\n\t} link_modes;\n\tu32 lanes;\n};\n\nstruct ethtool_eth_mac_stats {\n\tu64 FramesTransmittedOK;\n\tu64 SingleCollisionFrames;\n\tu64 MultipleCollisionFrames;\n\tu64 FramesReceivedOK;\n\tu64 FrameCheckSequenceErrors;\n\tu64 AlignmentErrors;\n\tu64 OctetsTransmittedOK;\n\tu64 FramesWithDeferredXmissions;\n\tu64 LateCollisions;\n\tu64 FramesAbortedDueToXSColls;\n\tu64 FramesLostDueToIntMACXmitError;\n\tu64 CarrierSenseErrors;\n\tu64 OctetsReceivedOK;\n\tu64 FramesLostDueToIntMACRcvError;\n\tu64 MulticastFramesXmittedOK;\n\tu64 BroadcastFramesXmittedOK;\n\tu64 FramesWithExcessiveDeferral;\n\tu64 MulticastFramesReceivedOK;\n\tu64 BroadcastFramesReceivedOK;\n\tu64 InRangeLengthErrors;\n\tu64 OutOfRangeLengthField;\n\tu64 FrameTooLongErrors;\n};\n\nstruct ethtool_eth_phy_stats {\n\tu64 SymbolErrorDuringCarrier;\n};\n\nstruct ethtool_eth_ctrl_stats {\n\tu64 MACControlFramesTransmitted;\n\tu64 MACControlFramesReceived;\n\tu64 UnsupportedOpcodesReceived;\n};\n\nstruct ethtool_pause_stats {\n\tu64 tx_pause_frames;\n\tu64 rx_pause_frames;\n};\n\nstruct ethtool_fec_stat {\n\tu64 total;\n\tu64 lanes[8];\n};\n\nstruct ethtool_fec_stats {\n\tstruct ethtool_fec_stat corrected_blocks;\n\tstruct ethtool_fec_stat uncorrectable_blocks;\n\tstruct ethtool_fec_stat corrected_bits;\n};\n\nstruct ethtool_rmon_hist_range {\n\tu16 low;\n\tu16 high;\n};\n\nstruct ethtool_rmon_stats {\n\tu64 undersize_pkts;\n\tu64 oversize_pkts;\n\tu64 fragments;\n\tu64 jabbers;\n\tu64 hist[10];\n\tu64 hist_tx[10];\n};\n\nstruct ethtool_module_eeprom {\n\tu32 offset;\n\tu32 length;\n\tu8 page;\n\tu8 bank;\n\tu8 i2c_address;\n\tu8 *data;\n};\n\nenum ib_uverbs_write_cmds {\n\tIB_USER_VERBS_CMD_GET_CONTEXT = 0,\n\tIB_USER_VERBS_CMD_QUERY_DEVICE = 1,\n\tIB_USER_VERBS_CMD_QUERY_PORT = 2,\n\tIB_USER_VERBS_CMD_ALLOC_PD = 3,\n\tIB_USER_VERBS_CMD_DEALLOC_PD = 4,\n\tIB_USER_VERBS_CMD_CREATE_AH = 5,\n\tIB_USER_VERBS_CMD_MODIFY_AH = 6,\n\tIB_USER_VERBS_CMD_QUERY_AH = 7,\n\tIB_USER_VERBS_CMD_DESTROY_AH = 8,\n\tIB_USER_VERBS_CMD_REG_MR = 9,\n\tIB_USER_VERBS_CMD_REG_SMR = 10,\n\tIB_USER_VERBS_CMD_REREG_MR = 11,\n\tIB_USER_VERBS_CMD_QUERY_MR = 12,\n\tIB_USER_VERBS_CMD_DEREG_MR = 13,\n\tIB_USER_VERBS_CMD_ALLOC_MW = 14,\n\tIB_USER_VERBS_CMD_BIND_MW = 15,\n\tIB_USER_VERBS_CMD_DEALLOC_MW = 16,\n\tIB_USER_VERBS_CMD_CREATE_COMP_CHANNEL = 17,\n\tIB_USER_VERBS_CMD_CREATE_CQ = 18,\n\tIB_USER_VERBS_CMD_RESIZE_CQ = 19,\n\tIB_USER_VERBS_CMD_DESTROY_CQ = 20,\n\tIB_USER_VERBS_CMD_POLL_CQ = 21,\n\tIB_USER_VERBS_CMD_PEEK_CQ = 22,\n\tIB_USER_VERBS_CMD_REQ_NOTIFY_CQ = 23,\n\tIB_USER_VERBS_CMD_CREATE_QP = 24,\n\tIB_USER_VERBS_CMD_QUERY_QP = 25,\n\tIB_USER_VERBS_CMD_MODIFY_QP = 26,\n\tIB_USER_VERBS_CMD_DESTROY_QP = 27,\n\tIB_USER_VERBS_CMD_POST_SEND = 28,\n\tIB_USER_VERBS_CMD_POST_RECV = 29,\n\tIB_USER_VERBS_CMD_ATTACH_MCAST = 30,\n\tIB_USER_VERBS_CMD_DETACH_MCAST = 31,\n\tIB_USER_VERBS_CMD_CREATE_SRQ = 32,\n\tIB_USER_VERBS_CMD_MODIFY_SRQ = 33,\n\tIB_USER_VERBS_CMD_QUERY_SRQ = 34,\n\tIB_USER_VERBS_CMD_DESTROY_SRQ = 35,\n\tIB_USER_VERBS_CMD_POST_SRQ_RECV = 36,\n\tIB_USER_VERBS_CMD_OPEN_XRCD = 37,\n\tIB_USER_VERBS_CMD_CLOSE_XRCD = 38,\n\tIB_USER_VERBS_CMD_CREATE_XSRQ = 39,\n\tIB_USER_VERBS_CMD_OPEN_QP = 40,\n};\n\nenum ib_uverbs_wc_opcode {\n\tIB_UVERBS_WC_SEND = 0,\n\tIB_UVERBS_WC_RDMA_WRITE = 1,\n\tIB_UVERBS_WC_RDMA_READ = 2,\n\tIB_UVERBS_WC_COMP_SWAP = 3,\n\tIB_UVERBS_WC_FETCH_ADD = 4,\n\tIB_UVERBS_WC_BIND_MW = 5,\n\tIB_UVERBS_WC_LOCAL_INV = 6,\n\tIB_UVERBS_WC_TSO = 7,\n};\n\nenum ib_uverbs_create_qp_mask {\n\tIB_UVERBS_CREATE_QP_MASK_IND_TABLE = 1,\n};\n\nenum ib_uverbs_wr_opcode {\n\tIB_UVERBS_WR_RDMA_WRITE = 0,\n\tIB_UVERBS_WR_RDMA_WRITE_WITH_IMM = 1,\n\tIB_UVERBS_WR_SEND = 2,\n\tIB_UVERBS_WR_SEND_WITH_IMM = 3,\n\tIB_UVERBS_WR_RDMA_READ = 4,\n\tIB_UVERBS_WR_ATOMIC_CMP_AND_SWP = 5,\n\tIB_UVERBS_WR_ATOMIC_FETCH_AND_ADD = 6,\n\tIB_UVERBS_WR_LOCAL_INV = 7,\n\tIB_UVERBS_WR_BIND_MW = 8,\n\tIB_UVERBS_WR_SEND_WITH_INV = 9,\n\tIB_UVERBS_WR_TSO = 10,\n\tIB_UVERBS_WR_RDMA_READ_WITH_INV = 11,\n\tIB_UVERBS_WR_MASKED_ATOMIC_CMP_AND_SWP = 12,\n\tIB_UVERBS_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13,\n};\n\nenum ib_uverbs_access_flags {\n\tIB_UVERBS_ACCESS_LOCAL_WRITE = 1,\n\tIB_UVERBS_ACCESS_REMOTE_WRITE = 2,\n\tIB_UVERBS_ACCESS_REMOTE_READ = 4,\n\tIB_UVERBS_ACCESS_REMOTE_ATOMIC = 8,\n\tIB_UVERBS_ACCESS_MW_BIND = 16,\n\tIB_UVERBS_ACCESS_ZERO_BASED = 32,\n\tIB_UVERBS_ACCESS_ON_DEMAND = 64,\n\tIB_UVERBS_ACCESS_HUGETLB = 128,\n\tIB_UVERBS_ACCESS_RELAXED_ORDERING = 1048576,\n\tIB_UVERBS_ACCESS_OPTIONAL_RANGE = 1072693248,\n};\n\nenum ib_uverbs_srq_type {\n\tIB_UVERBS_SRQT_BASIC = 0,\n\tIB_UVERBS_SRQT_XRC = 1,\n\tIB_UVERBS_SRQT_TM = 2,\n};\n\nenum ib_uverbs_wq_type {\n\tIB_UVERBS_WQT_RQ = 0,\n};\n\nenum ib_uverbs_wq_flags {\n\tIB_UVERBS_WQ_FLAGS_CVLAN_STRIPPING = 1,\n\tIB_UVERBS_WQ_FLAGS_SCATTER_FCS = 2,\n\tIB_UVERBS_WQ_FLAGS_DELAY_DROP = 4,\n\tIB_UVERBS_WQ_FLAGS_PCI_WRITE_END_PADDING = 8,\n};\n\nenum ib_uverbs_qp_type {\n\tIB_UVERBS_QPT_RC = 2,\n\tIB_UVERBS_QPT_UC = 3,\n\tIB_UVERBS_QPT_UD = 4,\n\tIB_UVERBS_QPT_RAW_PACKET = 8,\n\tIB_UVERBS_QPT_XRC_INI = 9,\n\tIB_UVERBS_QPT_XRC_TGT = 10,\n\tIB_UVERBS_QPT_DRIVER = 255,\n};\n\nenum ib_uverbs_qp_create_flags {\n\tIB_UVERBS_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 2,\n\tIB_UVERBS_QP_CREATE_SCATTER_FCS = 256,\n\tIB_UVERBS_QP_CREATE_CVLAN_STRIPPING = 512,\n\tIB_UVERBS_QP_CREATE_PCI_WRITE_END_PADDING = 2048,\n\tIB_UVERBS_QP_CREATE_SQ_SIG_ALL = 4096,\n};\n\nenum ib_uverbs_gid_type {\n\tIB_UVERBS_GID_TYPE_IB = 0,\n\tIB_UVERBS_GID_TYPE_ROCE_V1 = 1,\n\tIB_UVERBS_GID_TYPE_ROCE_V2 = 2,\n};\n\nenum ib_poll_context {\n\tIB_POLL_SOFTIRQ = 0,\n\tIB_POLL_WORKQUEUE = 1,\n\tIB_POLL_UNBOUND_WORKQUEUE = 2,\n\tIB_POLL_LAST_POOL_TYPE = 2,\n\tIB_POLL_DIRECT = 3,\n};\n\nstruct lsm_network_audit {\n\tint netif;\n\tconst struct sock *sk;\n\tu16 family;\n\t__be16 dport;\n\t__be16 sport;\n\tunion {\n\t\tstruct {\n\t\t\t__be32 daddr;\n\t\t\t__be32 saddr;\n\t\t} v4;\n\t\tstruct {\n\t\t\tstruct in6_addr daddr;\n\t\t\tstruct in6_addr saddr;\n\t\t} v6;\n\t} fam;\n};\n\nstruct lsm_ioctlop_audit {\n\tstruct path path;\n\tu16 cmd;\n};\n\nstruct lsm_ibpkey_audit {\n\tu64 subnet_prefix;\n\tu16 pkey;\n};\n\nstruct lsm_ibendport_audit {\n\tconst char *dev_name;\n\tu8 port;\n};\n\nstruct selinux_state;\n\nstruct selinux_audit_data {\n\tu32 ssid;\n\tu32 tsid;\n\tu16 tclass;\n\tu32 requested;\n\tu32 audited;\n\tu32 denied;\n\tint result;\n\tstruct selinux_state *state;\n};\n\nstruct smack_audit_data;\n\nstruct apparmor_audit_data;\n\nstruct common_audit_data {\n\tchar type;\n\tunion {\n\t\tstruct path path;\n\t\tstruct dentry *dentry;\n\t\tstruct inode *inode;\n\t\tstruct lsm_network_audit *net;\n\t\tint cap;\n\t\tint ipc_id;\n\t\tstruct task_struct *tsk;\n\t\tstruct {\n\t\t\tkey_serial_t key;\n\t\t\tchar *key_desc;\n\t\t} key_struct;\n\t\tchar *kmod_name;\n\t\tstruct lsm_ioctlop_audit *op;\n\t\tstruct file *file;\n\t\tstruct lsm_ibpkey_audit *ibpkey;\n\t\tstruct lsm_ibendport_audit *ibendport;\n\t\tint reason;\n\t} u;\n\tunion {\n\t\tstruct smack_audit_data *smack_audit_data;\n\t\tstruct selinux_audit_data *selinux_audit_data;\n\t\tstruct apparmor_audit_data *apparmor_audit_data;\n\t};\n};\n\nenum {\n\tPOLICYDB_CAPABILITY_NETPEER = 0,\n\tPOLICYDB_CAPABILITY_OPENPERM = 1,\n\tPOLICYDB_CAPABILITY_EXTSOCKCLASS = 2,\n\tPOLICYDB_CAPABILITY_ALWAYSNETWORK = 3,\n\tPOLICYDB_CAPABILITY_CGROUPSECLABEL = 4,\n\tPOLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION = 5,\n\tPOLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS = 6,\n\t__POLICYDB_CAPABILITY_MAX = 7,\n};\n\nstruct selinux_avc;\n\nstruct selinux_policy;\n\nstruct selinux_state {\n\tbool enforcing;\n\tbool checkreqprot;\n\tbool initialized;\n\tbool policycap[7];\n\tstruct page *status_page;\n\tstruct mutex status_lock;\n\tstruct selinux_avc *avc;\n\tstruct selinux_policy *policy;\n\tstruct mutex policy_mutex;\n};\n\nstruct avc_cache {\n\tstruct hlist_head slots[512];\n\tspinlock_t slots_lock[512];\n\tatomic_t lru_hint;\n\tatomic_t active_nodes;\n\tu32 latest_notif;\n};\n\nstruct selinux_avc {\n\tunsigned int avc_cache_threshold;\n\tstruct avc_cache avc_cache;\n};\n\nstruct av_decision {\n\tu32 allowed;\n\tu32 auditallow;\n\tu32 auditdeny;\n\tu32 seqno;\n\tu32 flags;\n};\n\nstruct extended_perms_data {\n\tu32 p[8];\n};\n\nstruct extended_perms_decision {\n\tu8 used;\n\tu8 driver;\n\tstruct extended_perms_data *allowed;\n\tstruct extended_perms_data *auditallow;\n\tstruct extended_perms_data *dontaudit;\n};\n\nstruct extended_perms {\n\tu16 len;\n\tstruct extended_perms_data drivers;\n};\n\nstruct avc_cache_stats {\n\tunsigned int lookups;\n\tunsigned int misses;\n\tunsigned int allocations;\n\tunsigned int reclaims;\n\tunsigned int frees;\n};\n\nstruct security_class_mapping {\n\tconst char *name;\n\tconst char *perms[33];\n};\n\nstruct trace_event_raw_selinux_audited {\n\tstruct trace_entry ent;\n\tu32 requested;\n\tu32 denied;\n\tu32 audited;\n\tint result;\n\tu32 __data_loc_scontext;\n\tu32 __data_loc_tcontext;\n\tu32 __data_loc_tclass;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_selinux_audited {\n\tu32 scontext;\n\tu32 tcontext;\n\tu32 tclass;\n};\n\ntypedef void (*btf_trace_selinux_audited)(void *, struct selinux_audit_data *, char *, char *, const char *);\n\nstruct avc_xperms_node;\n\nstruct avc_entry {\n\tu32 ssid;\n\tu32 tsid;\n\tu16 tclass;\n\tstruct av_decision avd;\n\tstruct avc_xperms_node *xp_node;\n};\n\nstruct avc_xperms_node {\n\tstruct extended_perms xp;\n\tstruct list_head xpd_head;\n};\n\nstruct avc_node {\n\tstruct avc_entry ae;\n\tstruct hlist_node list;\n\tstruct callback_head rhead;\n};\n\nstruct avc_xperms_decision_node {\n\tstruct extended_perms_decision xpd;\n\tstruct list_head xpd_list;\n};\n\nstruct avc_callback_node {\n\tint (*callback)(u32);\n\tu32 events;\n\tstruct avc_callback_node *next;\n};\n\ntypedef __u16 __sum16;\n\nenum sctp_endpoint_type {\n\tSCTP_EP_TYPE_SOCKET = 0,\n\tSCTP_EP_TYPE_ASSOCIATION = 1,\n};\n\nstruct sctp_chunk;\n\nstruct sctp_inq {\n\tstruct list_head in_chunk_list;\n\tstruct sctp_chunk *in_progress;\n\tstruct work_struct immediate;\n};\n\nstruct sctp_bind_addr {\n\t__u16 port;\n\tstruct list_head address_list;\n};\n\nstruct sctp_ep_common {\n\tstruct hlist_node node;\n\tint hashent;\n\tenum sctp_endpoint_type type;\n\trefcount_t refcnt;\n\tbool dead;\n\tstruct sock *sk;\n\tstruct net *net;\n\tstruct sctp_inq inqueue;\n\tstruct sctp_bind_addr bind_addr;\n};\n\nstruct crypto_shash___2;\n\nstruct sctp_hmac_algo_param;\n\nstruct sctp_chunks_param;\n\nstruct sctp_endpoint {\n\tstruct sctp_ep_common base;\n\tstruct list_head asocs;\n\t__u8 secret_key[32];\n\t__u8 *digest;\n\t__u32 sndbuf_policy;\n\t__u32 rcvbuf_policy;\n\tstruct crypto_shash___2 **auth_hmacs;\n\tstruct sctp_hmac_algo_param *auth_hmacs_list;\n\tstruct sctp_chunks_param *auth_chunk_list;\n\tstruct list_head endpoint_shared_keys;\n\t__u16 active_key_id;\n\t__u8 ecn_enable: 1;\n\t__u8 auth_enable: 1;\n\t__u8 intl_enable: 1;\n\t__u8 prsctp_enable: 1;\n\t__u8 asconf_enable: 1;\n\t__u8 reconf_enable: 1;\n\t__u8 strreset_enable;\n\tu32 secid;\n\tu32 peer_secid;\n};\n\nstruct sockaddr_in6 {\n\tshort unsigned int sin6_family;\n\t__be16 sin6_port;\n\t__be32 sin6_flowinfo;\n\tstruct in6_addr sin6_addr;\n\t__u32 sin6_scope_id;\n};\n\nstruct in_addr {\n\t__be32 s_addr;\n};\n\nstruct sockaddr_in {\n\t__kernel_sa_family_t sin_family;\n\t__be16 sin_port;\n\tstruct in_addr sin_addr;\n\tunsigned char __pad[8];\n};\n\nstruct nf_hook_state;\n\ntypedef unsigned int nf_hookfn(void *, struct sk_buff *, const struct nf_hook_state *);\n\nstruct nf_hook_entry {\n\tnf_hookfn *hook;\n\tvoid *priv;\n};\n\nstruct nf_hook_entries {\n\tu16 num_hook_entries;\n\tstruct nf_hook_entry hooks[0];\n};\n\nstruct nf_hook_state {\n\tu8 hook;\n\tu8 pf;\n\tstruct net_device *in;\n\tstruct net_device *out;\n\tstruct sock *sk;\n\tstruct net *net;\n\tint (*okfn)(struct net *, struct sock *, struct sk_buff *);\n};\n\nenum nf_hook_ops_type {\n\tNF_HOOK_OP_UNDEFINED = 0,\n\tNF_HOOK_OP_NF_TABLES = 1,\n};\n\nstruct nf_hook_ops {\n\tnf_hookfn *hook;\n\tstruct net_device *dev;\n\tvoid *priv;\n\tu8 pf;\n\tenum nf_hook_ops_type hook_ops_type: 8;\n\tunsigned int hooknum;\n\tint priority;\n};\n\nenum nf_ip_hook_priorities {\n\tNF_IP_PRI_FIRST = 2147483648,\n\tNF_IP_PRI_RAW_BEFORE_DEFRAG = 4294966846,\n\tNF_IP_PRI_CONNTRACK_DEFRAG = 4294966896,\n\tNF_IP_PRI_RAW = 4294966996,\n\tNF_IP_PRI_SELINUX_FIRST = 4294967071,\n\tNF_IP_PRI_CONNTRACK = 4294967096,\n\tNF_IP_PRI_MANGLE = 4294967146,\n\tNF_IP_PRI_NAT_DST = 4294967196,\n\tNF_IP_PRI_FILTER = 0,\n\tNF_IP_PRI_SECURITY = 50,\n\tNF_IP_PRI_NAT_SRC = 100,\n\tNF_IP_PRI_SELINUX_LAST = 225,\n\tNF_IP_PRI_CONNTRACK_HELPER = 300,\n\tNF_IP_PRI_CONNTRACK_CONFIRM = 2147483647,\n\tNF_IP_PRI_LAST = 2147483647,\n};\n\nenum nf_ip6_hook_priorities {\n\tNF_IP6_PRI_FIRST = 2147483648,\n\tNF_IP6_PRI_RAW_BEFORE_DEFRAG = 4294966846,\n\tNF_IP6_PRI_CONNTRACK_DEFRAG = 4294966896,\n\tNF_IP6_PRI_RAW = 4294966996,\n\tNF_IP6_PRI_SELINUX_FIRST = 4294967071,\n\tNF_IP6_PRI_CONNTRACK = 4294967096,\n\tNF_IP6_PRI_MANGLE = 4294967146,\n\tNF_IP6_PRI_NAT_DST = 4294967196,\n\tNF_IP6_PRI_FILTER = 0,\n\tNF_IP6_PRI_SECURITY = 50,\n\tNF_IP6_PRI_NAT_SRC = 100,\n\tNF_IP6_PRI_SELINUX_LAST = 225,\n\tNF_IP6_PRI_CONNTRACK_HELPER = 300,\n\tNF_IP6_PRI_LAST = 2147483647,\n};\n\nstruct socket_alloc {\n\tstruct socket socket;\n\tstruct inode vfs_inode;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct ip_options {\n\t__be32 faddr;\n\t__be32 nexthop;\n\tunsigned char optlen;\n\tunsigned char srr;\n\tunsigned char rr;\n\tunsigned char ts;\n\tunsigned char is_strictroute: 1;\n\tunsigned char srr_is_hit: 1;\n\tunsigned char is_changed: 1;\n\tunsigned char rr_needaddr: 1;\n\tunsigned char ts_needtime: 1;\n\tunsigned char ts_needaddr: 1;\n\tunsigned char router_alert;\n\tunsigned char cipso;\n\tunsigned char __pad2;\n\tunsigned char __data[0];\n};\n\nstruct ip_options_rcu {\n\tstruct callback_head rcu;\n\tstruct ip_options opt;\n};\n\nstruct ipv6_opt_hdr;\n\nstruct ipv6_rt_hdr;\n\nstruct ipv6_txoptions {\n\trefcount_t refcnt;\n\tint tot_len;\n\t__u16 opt_flen;\n\t__u16 opt_nflen;\n\tstruct ipv6_opt_hdr *hopopt;\n\tstruct ipv6_opt_hdr *dst0opt;\n\tstruct ipv6_rt_hdr *srcrt;\n\tstruct ipv6_opt_hdr *dst1opt;\n\tstruct callback_head rcu;\n};\n\nstruct inet_cork {\n\tunsigned int flags;\n\t__be32 addr;\n\tstruct ip_options *opt;\n\tunsigned int fragsize;\n\tint length;\n\tstruct dst_entry *dst;\n\tu8 tx_flags;\n\t__u8 ttl;\n\t__s16 tos;\n\tchar priority;\n\t__u16 gso_size;\n\tu64 transmit_time;\n\tu32 mark;\n};\n\nstruct inet_cork_full {\n\tstruct inet_cork base;\n\tstruct flowi fl;\n};\n\nstruct ipv6_pinfo;\n\nstruct ip_mc_socklist;\n\nstruct inet_sock {\n\tstruct sock sk;\n\tstruct ipv6_pinfo *pinet6;\n\t__be32 inet_saddr;\n\t__s16 uc_ttl;\n\t__u16 cmsg_flags;\n\t__be16 inet_sport;\n\t__u16 inet_id;\n\tstruct ip_options_rcu *inet_opt;\n\tint rx_dst_ifindex;\n\t__u8 tos;\n\t__u8 min_ttl;\n\t__u8 mc_ttl;\n\t__u8 pmtudisc;\n\t__u8 recverr: 1;\n\t__u8 is_icsk: 1;\n\t__u8 freebind: 1;\n\t__u8 hdrincl: 1;\n\t__u8 mc_loop: 1;\n\t__u8 transparent: 1;\n\t__u8 mc_all: 1;\n\t__u8 nodefrag: 1;\n\t__u8 bind_address_no_port: 1;\n\t__u8 recverr_rfc4884: 1;\n\t__u8 defer_connect: 1;\n\t__u8 rcv_tos;\n\t__u8 convert_csum;\n\tint uc_index;\n\tint mc_index;\n\t__be32 mc_addr;\n\tstruct ip_mc_socklist *mc_list;\n\tstruct inet_cork_full cork;\n};\n\nstruct in6_pktinfo {\n\tstruct in6_addr ipi6_addr;\n\tint ipi6_ifindex;\n};\n\nstruct inet6_cork {\n\tstruct ipv6_txoptions *opt;\n\tu8 hop_limit;\n\tu8 tclass;\n};\n\nstruct ipv6_mc_socklist;\n\nstruct ipv6_ac_socklist;\n\nstruct ipv6_fl_socklist;\n\nstruct ipv6_pinfo {\n\tstruct in6_addr saddr;\n\tstruct in6_pktinfo sticky_pktinfo;\n\tconst struct in6_addr *daddr_cache;\n\tconst struct in6_addr *saddr_cache;\n\t__be32 flow_label;\n\t__u32 frag_size;\n\t__u16 __unused_1: 7;\n\t__s16 hop_limit: 9;\n\t__u16 mc_loop: 1;\n\t__u16 __unused_2: 6;\n\t__s16 mcast_hops: 9;\n\tint ucast_oif;\n\tint mcast_oif;\n\tunion {\n\t\tstruct {\n\t\t\t__u16 srcrt: 1;\n\t\t\t__u16 osrcrt: 1;\n\t\t\t__u16 rxinfo: 1;\n\t\t\t__u16 rxoinfo: 1;\n\t\t\t__u16 rxhlim: 1;\n\t\t\t__u16 rxohlim: 1;\n\t\t\t__u16 hopopts: 1;\n\t\t\t__u16 ohopopts: 1;\n\t\t\t__u16 dstopts: 1;\n\t\t\t__u16 odstopts: 1;\n\t\t\t__u16 rxflow: 1;\n\t\t\t__u16 rxtclass: 1;\n\t\t\t__u16 rxpmtu: 1;\n\t\t\t__u16 rxorigdstaddr: 1;\n\t\t\t__u16 recvfragsize: 1;\n\t\t} bits;\n\t\t__u16 all;\n\t} rxopt;\n\t__u16 recverr: 1;\n\t__u16 sndflow: 1;\n\t__u16 repflow: 1;\n\t__u16 pmtudisc: 3;\n\t__u16 padding: 1;\n\t__u16 srcprefs: 3;\n\t__u16 dontfrag: 1;\n\t__u16 autoflowlabel: 1;\n\t__u16 autoflowlabel_set: 1;\n\t__u16 mc_all: 1;\n\t__u16 recverr_rfc4884: 1;\n\t__u16 rtalert_isolate: 1;\n\t__u8 min_hopcount;\n\t__u8 tclass;\n\t__be32 rcv_flowinfo;\n\t__u32 dst_cookie;\n\t__u32 rx_dst_cookie;\n\tstruct ipv6_mc_socklist *ipv6_mc_list;\n\tstruct ipv6_ac_socklist *ipv6_ac_list;\n\tstruct ipv6_fl_socklist *ipv6_fl_list;\n\tstruct ipv6_txoptions *opt;\n\tstruct sk_buff *pktoptions;\n\tstruct sk_buff *rxpmtu;\n\tstruct inet6_cork cork;\n};\n\nstruct tcphdr {\n\t__be16 source;\n\t__be16 dest;\n\t__be32 seq;\n\t__be32 ack_seq;\n\t__u16 res1: 4;\n\t__u16 doff: 4;\n\t__u16 fin: 1;\n\t__u16 syn: 1;\n\t__u16 rst: 1;\n\t__u16 psh: 1;\n\t__u16 ack: 1;\n\t__u16 urg: 1;\n\t__u16 ece: 1;\n\t__u16 cwr: 1;\n\t__be16 window;\n\t__sum16 check;\n\t__be16 urg_ptr;\n};\n\nstruct iphdr {\n\t__u8 ihl: 4;\n\t__u8 version: 4;\n\t__u8 tos;\n\t__be16 tot_len;\n\t__be16 id;\n\t__be16 frag_off;\n\t__u8 ttl;\n\t__u8 protocol;\n\t__sum16 check;\n\t__be32 saddr;\n\t__be32 daddr;\n};\n\nstruct ipv6_rt_hdr {\n\t__u8 nexthdr;\n\t__u8 hdrlen;\n\t__u8 type;\n\t__u8 segments_left;\n};\n\nstruct ipv6_opt_hdr {\n\t__u8 nexthdr;\n\t__u8 hdrlen;\n};\n\nstruct ipv6hdr {\n\t__u8 priority: 4;\n\t__u8 version: 4;\n\t__u8 flow_lbl[3];\n\t__be16 payload_len;\n\t__u8 nexthdr;\n\t__u8 hop_limit;\n\tstruct in6_addr saddr;\n\tstruct in6_addr daddr;\n};\n\nstruct udphdr {\n\t__be16 source;\n\t__be16 dest;\n\t__be16 len;\n\t__sum16 check;\n};\n\nstruct inet6_skb_parm {\n\tint iif;\n\t__be16 ra;\n\t__u16 dst0;\n\t__u16 srcrt;\n\t__u16 dst1;\n\t__u16 lastopt;\n\t__u16 nhoff;\n\t__u16 flags;\n\t__u16 dsthao;\n\t__u16 frag_max_size;\n};\n\nstruct ip6_sf_socklist;\n\nstruct ipv6_mc_socklist {\n\tstruct in6_addr addr;\n\tint ifindex;\n\tunsigned int sfmode;\n\tstruct ipv6_mc_socklist *next;\n\tstruct ip6_sf_socklist *sflist;\n\tstruct callback_head rcu;\n};\n\nstruct ipv6_ac_socklist {\n\tstruct in6_addr acl_addr;\n\tint acl_ifindex;\n\tstruct ipv6_ac_socklist *acl_next;\n};\n\nstruct ip6_flowlabel;\n\nstruct ipv6_fl_socklist {\n\tstruct ipv6_fl_socklist *next;\n\tstruct ip6_flowlabel *fl;\n\tstruct callback_head rcu;\n};\n\nstruct ip6_sf_socklist {\n\tunsigned int sl_max;\n\tunsigned int sl_count;\n\tstruct callback_head rcu;\n\tstruct in6_addr sl_addr[0];\n};\n\nstruct ip6_flowlabel {\n\tstruct ip6_flowlabel *next;\n\t__be32 label;\n\tatomic_t users;\n\tstruct in6_addr dst;\n\tstruct ipv6_txoptions *opt;\n\tlong unsigned int linger;\n\tstruct callback_head rcu;\n\tu8 share;\n\tunion {\n\t\tstruct pid *pid;\n\t\tkuid_t uid;\n\t} owner;\n\tlong unsigned int lastuse;\n\tlong unsigned int expires;\n\tstruct net *fl_net;\n};\n\nstruct inet_skb_parm {\n\tint iif;\n\tstruct ip_options opt;\n\tu16 flags;\n\tu16 frag_max_size;\n};\n\nstruct tty_file_private {\n\tstruct tty_struct *tty;\n\tstruct file *file;\n\tstruct list_head list;\n};\n\nstruct netlbl_lsm_cache {\n\trefcount_t refcount;\n\tvoid (*free)(const void *);\n\tvoid *data;\n};\n\nstruct netlbl_lsm_catmap {\n\tu32 startbit;\n\tu64 bitmap[4];\n\tstruct netlbl_lsm_catmap *next;\n};\n\nstruct netlbl_lsm_secattr {\n\tu32 flags;\n\tu32 type;\n\tchar *domain;\n\tstruct netlbl_lsm_cache *cache;\n\tstruct {\n\t\tstruct {\n\t\t\tstruct netlbl_lsm_catmap *cat;\n\t\t\tu32 lvl;\n\t\t} mls;\n\t\tu32 secid;\n\t} attr;\n};\n\nstruct dccp_hdr {\n\t__be16 dccph_sport;\n\t__be16 dccph_dport;\n\t__u8 dccph_doff;\n\t__u8 dccph_cscov: 4;\n\t__u8 dccph_ccval: 4;\n\t__sum16 dccph_checksum;\n\t__u8 dccph_x: 1;\n\t__u8 dccph_type: 4;\n\t__u8 dccph_reserved: 3;\n\t__u8 dccph_seq2;\n\t__be16 dccph_seq;\n};\n\nenum dccp_state {\n\tDCCP_OPEN = 1,\n\tDCCP_REQUESTING = 2,\n\tDCCP_LISTEN = 10,\n\tDCCP_RESPOND = 3,\n\tDCCP_ACTIVE_CLOSEREQ = 4,\n\tDCCP_PASSIVE_CLOSE = 8,\n\tDCCP_CLOSING = 11,\n\tDCCP_TIME_WAIT = 6,\n\tDCCP_CLOSED = 7,\n\tDCCP_NEW_SYN_RECV = 12,\n\tDCCP_PARTOPEN = 13,\n\tDCCP_PASSIVE_CLOSEREQ = 14,\n\tDCCP_MAX_STATES = 15,\n};\n\ntypedef __s32 sctp_assoc_t;\n\nenum sctp_msg_flags {\n\tMSG_NOTIFICATION = 32768,\n};\n\nstruct sctp_initmsg {\n\t__u16 sinit_num_ostreams;\n\t__u16 sinit_max_instreams;\n\t__u16 sinit_max_attempts;\n\t__u16 sinit_max_init_timeo;\n};\n\nstruct sctp_sndrcvinfo {\n\t__u16 sinfo_stream;\n\t__u16 sinfo_ssn;\n\t__u16 sinfo_flags;\n\t__u32 sinfo_ppid;\n\t__u32 sinfo_context;\n\t__u32 sinfo_timetolive;\n\t__u32 sinfo_tsn;\n\t__u32 sinfo_cumtsn;\n\tsctp_assoc_t sinfo_assoc_id;\n};\n\nstruct sctp_rtoinfo {\n\tsctp_assoc_t srto_assoc_id;\n\t__u32 srto_initial;\n\t__u32 srto_max;\n\t__u32 srto_min;\n};\n\nstruct sctp_assocparams {\n\tsctp_assoc_t sasoc_assoc_id;\n\t__u16 sasoc_asocmaxrxt;\n\t__u16 sasoc_number_peer_destinations;\n\t__u32 sasoc_peer_rwnd;\n\t__u32 sasoc_local_rwnd;\n\t__u32 sasoc_cookie_life;\n};\n\nstruct sctp_paddrparams {\n\tsctp_assoc_t spp_assoc_id;\n\tstruct __kernel_sockaddr_storage spp_address;\n\t__u32 spp_hbinterval;\n\t__u16 spp_pathmaxrxt;\n\t__u32 spp_pathmtu;\n\t__u32 spp_sackdelay;\n\t__u32 spp_flags;\n\t__u32 spp_ipv6_flowlabel;\n\t__u8 spp_dscp;\n\tchar: 8;\n} __attribute__((packed));\n\nstruct sctphdr {\n\t__be16 source;\n\t__be16 dest;\n\t__be32 vtag;\n\t__le32 checksum;\n};\n\nstruct sctp_chunkhdr {\n\t__u8 type;\n\t__u8 flags;\n\t__be16 length;\n};\n\nenum sctp_cid {\n\tSCTP_CID_DATA = 0,\n\tSCTP_CID_INIT = 1,\n\tSCTP_CID_INIT_ACK = 2,\n\tSCTP_CID_SACK = 3,\n\tSCTP_CID_HEARTBEAT = 4,\n\tSCTP_CID_HEARTBEAT_ACK = 5,\n\tSCTP_CID_ABORT = 6,\n\tSCTP_CID_SHUTDOWN = 7,\n\tSCTP_CID_SHUTDOWN_ACK = 8,\n\tSCTP_CID_ERROR = 9,\n\tSCTP_CID_COOKIE_ECHO = 10,\n\tSCTP_CID_COOKIE_ACK = 11,\n\tSCTP_CID_ECN_ECNE = 12,\n\tSCTP_CID_ECN_CWR = 13,\n\tSCTP_CID_SHUTDOWN_COMPLETE = 14,\n\tSCTP_CID_AUTH = 15,\n\tSCTP_CID_I_DATA = 64,\n\tSCTP_CID_FWD_TSN = 192,\n\tSCTP_CID_ASCONF = 193,\n\tSCTP_CID_I_FWD_TSN = 194,\n\tSCTP_CID_ASCONF_ACK = 128,\n\tSCTP_CID_RECONF = 130,\n\tSCTP_CID_PAD = 132,\n};\n\nstruct sctp_paramhdr {\n\t__be16 type;\n\t__be16 length;\n};\n\nenum sctp_param {\n\tSCTP_PARAM_HEARTBEAT_INFO = 256,\n\tSCTP_PARAM_IPV4_ADDRESS = 1280,\n\tSCTP_PARAM_IPV6_ADDRESS = 1536,\n\tSCTP_PARAM_STATE_COOKIE = 1792,\n\tSCTP_PARAM_UNRECOGNIZED_PARAMETERS = 2048,\n\tSCTP_PARAM_COOKIE_PRESERVATIVE = 2304,\n\tSCTP_PARAM_HOST_NAME_ADDRESS = 2816,\n\tSCTP_PARAM_SUPPORTED_ADDRESS_TYPES = 3072,\n\tSCTP_PARAM_ECN_CAPABLE = 128,\n\tSCTP_PARAM_RANDOM = 640,\n\tSCTP_PARAM_CHUNKS = 896,\n\tSCTP_PARAM_HMAC_ALGO = 1152,\n\tSCTP_PARAM_SUPPORTED_EXT = 2176,\n\tSCTP_PARAM_FWD_TSN_SUPPORT = 192,\n\tSCTP_PARAM_ADD_IP = 448,\n\tSCTP_PARAM_DEL_IP = 704,\n\tSCTP_PARAM_ERR_CAUSE = 960,\n\tSCTP_PARAM_SET_PRIMARY = 1216,\n\tSCTP_PARAM_SUCCESS_REPORT = 1472,\n\tSCTP_PARAM_ADAPTATION_LAYER_IND = 1728,\n\tSCTP_PARAM_RESET_OUT_REQUEST = 3328,\n\tSCTP_PARAM_RESET_IN_REQUEST = 3584,\n\tSCTP_PARAM_RESET_TSN_REQUEST = 3840,\n\tSCTP_PARAM_RESET_RESPONSE = 4096,\n\tSCTP_PARAM_RESET_ADD_OUT_STREAMS = 4352,\n\tSCTP_PARAM_RESET_ADD_IN_STREAMS = 4608,\n};\n\nstruct sctp_datahdr {\n\t__be32 tsn;\n\t__be16 stream;\n\t__be16 ssn;\n\t__u32 ppid;\n\t__u8 payload[0];\n};\n\nstruct sctp_idatahdr {\n\t__be32 tsn;\n\t__be16 stream;\n\t__be16 reserved;\n\t__be32 mid;\n\tunion {\n\t\t__u32 ppid;\n\t\t__be32 fsn;\n\t};\n\t__u8 payload[0];\n};\n\nstruct sctp_inithdr {\n\t__be32 init_tag;\n\t__be32 a_rwnd;\n\t__be16 num_outbound_streams;\n\t__be16 num_inbound_streams;\n\t__be32 initial_tsn;\n\t__u8 params[0];\n};\n\nstruct sctp_init_chunk {\n\tstruct sctp_chunkhdr chunk_hdr;\n\tstruct sctp_inithdr init_hdr;\n};\n\nstruct sctp_ipv4addr_param {\n\tstruct sctp_paramhdr param_hdr;\n\tstruct in_addr addr;\n};\n\nstruct sctp_ipv6addr_param {\n\tstruct sctp_paramhdr param_hdr;\n\tstruct in6_addr addr;\n};\n\nstruct sctp_cookie_preserve_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__be32 lifespan_increment;\n};\n\nstruct sctp_hostname_param {\n\tstruct sctp_paramhdr param_hdr;\n\tuint8_t hostname[0];\n};\n\nstruct sctp_supported_addrs_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__be16 types[0];\n};\n\nstruct sctp_adaptation_ind_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__be32 adaptation_ind;\n};\n\nstruct sctp_supported_ext_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__u8 chunks[0];\n};\n\nstruct sctp_random_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__u8 random_val[0];\n};\n\nstruct sctp_chunks_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__u8 chunks[0];\n};\n\nstruct sctp_hmac_algo_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__be16 hmac_ids[0];\n};\n\nstruct sctp_cookie_param {\n\tstruct sctp_paramhdr p;\n\t__u8 body[0];\n};\n\nstruct sctp_gap_ack_block {\n\t__be16 start;\n\t__be16 end;\n};\n\nunion sctp_sack_variable {\n\tstruct sctp_gap_ack_block gab;\n\t__be32 dup;\n};\n\nstruct sctp_sackhdr {\n\t__be32 cum_tsn_ack;\n\t__be32 a_rwnd;\n\t__be16 num_gap_ack_blocks;\n\t__be16 num_dup_tsns;\n\tunion sctp_sack_variable variable[0];\n};\n\nstruct sctp_heartbeathdr {\n\tstruct sctp_paramhdr info;\n};\n\nstruct sctp_shutdownhdr {\n\t__be32 cum_tsn_ack;\n};\n\nstruct sctp_errhdr {\n\t__be16 cause;\n\t__be16 length;\n\t__u8 variable[0];\n};\n\nstruct sctp_ecnehdr {\n\t__be32 lowest_tsn;\n};\n\nstruct sctp_cwrhdr {\n\t__be32 lowest_tsn;\n};\n\nstruct sctp_fwdtsn_skip {\n\t__be16 stream;\n\t__be16 ssn;\n};\n\nstruct sctp_fwdtsn_hdr {\n\t__be32 new_cum_tsn;\n\tstruct sctp_fwdtsn_skip skip[0];\n};\n\nstruct sctp_ifwdtsn_skip {\n\t__be16 stream;\n\t__u8 reserved;\n\t__u8 flags;\n\t__be32 mid;\n};\n\nstruct sctp_ifwdtsn_hdr {\n\t__be32 new_cum_tsn;\n\tstruct sctp_ifwdtsn_skip skip[0];\n};\n\nstruct sctp_addip_param {\n\tstruct sctp_paramhdr param_hdr;\n\t__be32 crr_id;\n};\n\nstruct sctp_addiphdr {\n\t__be32 serial;\n\t__u8 params[0];\n};\n\nstruct sctp_authhdr {\n\t__be16 shkey_id;\n\t__be16 hmac_id;\n\t__u8 hmac[0];\n};\n\nunion sctp_addr {\n\tstruct sockaddr_in v4;\n\tstruct sockaddr_in6 v6;\n\tstruct sockaddr sa;\n};\n\nstruct sctp_cookie {\n\t__u32 my_vtag;\n\t__u32 peer_vtag;\n\t__u32 my_ttag;\n\t__u32 peer_ttag;\n\tktime_t expiration;\n\t__u16 sinit_num_ostreams;\n\t__u16 sinit_max_instreams;\n\t__u32 initial_tsn;\n\tunion sctp_addr peer_addr;\n\t__u16 my_port;\n\t__u8 prsctp_capable;\n\t__u8 padding;\n\t__u32 adaptation_ind;\n\t__u8 auth_random[36];\n\t__u8 auth_hmacs[10];\n\t__u8 auth_chunks[20];\n\t__u32 raw_addr_list_len;\n\tstruct sctp_init_chunk peer_init[0];\n};\n\nstruct sctp_tsnmap {\n\tlong unsigned int *tsn_map;\n\t__u32 base_tsn;\n\t__u32 cumulative_tsn_ack_point;\n\t__u32 max_tsn_seen;\n\t__u16 len;\n\t__u16 pending_data;\n\t__u16 num_dup_tsns;\n\t__be32 dup_tsns[16];\n};\n\nstruct sctp_inithdr_host {\n\t__u32 init_tag;\n\t__u32 a_rwnd;\n\t__u16 num_outbound_streams;\n\t__u16 num_inbound_streams;\n\t__u32 initial_tsn;\n};\n\nenum sctp_state {\n\tSCTP_STATE_CLOSED = 0,\n\tSCTP_STATE_COOKIE_WAIT = 1,\n\tSCTP_STATE_COOKIE_ECHOED = 2,\n\tSCTP_STATE_ESTABLISHED = 3,\n\tSCTP_STATE_SHUTDOWN_PENDING = 4,\n\tSCTP_STATE_SHUTDOWN_SENT = 5,\n\tSCTP_STATE_SHUTDOWN_RECEIVED = 6,\n\tSCTP_STATE_SHUTDOWN_ACK_SENT = 7,\n};\n\nstruct sctp_stream_out_ext;\n\nstruct sctp_stream_out {\n\tunion {\n\t\t__u32 mid;\n\t\t__u16 ssn;\n\t};\n\t__u32 mid_uo;\n\tstruct sctp_stream_out_ext *ext;\n\t__u8 state;\n};\n\nstruct sctp_stream_in {\n\tunion {\n\t\t__u32 mid;\n\t\t__u16 ssn;\n\t};\n\t__u32 mid_uo;\n\t__u32 fsn;\n\t__u32 fsn_uo;\n\tchar pd_mode;\n\tchar pd_mode_uo;\n};\n\nstruct sctp_stream_interleave;\n\nstruct sctp_stream {\n\tstruct {\n\t\tstruct __genradix tree;\n\t\tstruct sctp_stream_out type[0];\n\t} out;\n\tstruct {\n\t\tstruct __genradix tree;\n\t\tstruct sctp_stream_in type[0];\n\t} in;\n\t__u16 outcnt;\n\t__u16 incnt;\n\tstruct sctp_stream_out *out_curr;\n\tunion {\n\t\tstruct {\n\t\t\tstruct list_head prio_list;\n\t\t};\n\t\tstruct {\n\t\t\tstruct list_head rr_list;\n\t\t\tstruct sctp_stream_out_ext *rr_next;\n\t\t};\n\t};\n\tstruct sctp_stream_interleave *si;\n};\n\nstruct sctp_sched_ops;\n\nstruct sctp_association;\n\nstruct sctp_outq {\n\tstruct sctp_association *asoc;\n\tstruct list_head out_chunk_list;\n\tstruct sctp_sched_ops *sched;\n\tunsigned int out_qlen;\n\tunsigned int error;\n\tstruct list_head control_chunk_list;\n\tstruct list_head sacked;\n\tstruct list_head retransmit;\n\tstruct list_head abandoned;\n\t__u32 outstanding_bytes;\n\tchar fast_rtx;\n\tchar cork;\n};\n\nstruct sctp_ulpq {\n\tchar pd_mode;\n\tstruct sctp_association *asoc;\n\tstruct sk_buff_head reasm;\n\tstruct sk_buff_head reasm_uo;\n\tstruct sk_buff_head lobby;\n};\n\nstruct sctp_priv_assoc_stats {\n\tstruct __kernel_sockaddr_storage obs_rto_ipaddr;\n\t__u64 max_obs_rto;\n\t__u64 isacks;\n\t__u64 osacks;\n\t__u64 opackets;\n\t__u64 ipackets;\n\t__u64 rtxchunks;\n\t__u64 outofseqtsns;\n\t__u64 idupchunks;\n\t__u64 gapcnt;\n\t__u64 ouodchunks;\n\t__u64 iuodchunks;\n\t__u64 oodchunks;\n\t__u64 iodchunks;\n\t__u64 octrlchunks;\n\t__u64 ictrlchunks;\n};\n\nstruct sctp_transport;\n\nstruct sctp_auth_bytes;\n\nstruct sctp_shared_key;\n\nstruct sctp_association {\n\tstruct sctp_ep_common base;\n\tstruct list_head asocs;\n\tsctp_assoc_t assoc_id;\n\tstruct sctp_endpoint *ep;\n\tstruct sctp_cookie c;\n\tstruct {\n\t\tstruct list_head transport_addr_list;\n\t\t__u32 rwnd;\n\t\t__u16 transport_count;\n\t\t__u16 port;\n\t\tstruct sctp_transport *primary_path;\n\t\tunion sctp_addr primary_addr;\n\t\tstruct sctp_transport *active_path;\n\t\tstruct sctp_transport *retran_path;\n\t\tstruct sctp_transport *last_sent_to;\n\t\tstruct sctp_transport *last_data_from;\n\t\tstruct sctp_tsnmap tsn_map;\n\t\t__be16 addip_disabled_mask;\n\t\t__u16 ecn_capable: 1;\n\t\t__u16 ipv4_address: 1;\n\t\t__u16 ipv6_address: 1;\n\t\t__u16 hostname_address: 1;\n\t\t__u16 asconf_capable: 1;\n\t\t__u16 prsctp_capable: 1;\n\t\t__u16 reconf_capable: 1;\n\t\t__u16 intl_capable: 1;\n\t\t__u16 auth_capable: 1;\n\t\t__u16 sack_needed: 1;\n\t\t__u16 sack_generation: 1;\n\t\t__u16 zero_window_announced: 1;\n\t\t__u32 sack_cnt;\n\t\t__u32 adaptation_ind;\n\t\tstruct sctp_inithdr_host i;\n\t\tvoid *cookie;\n\t\tint cookie_len;\n\t\t__u32 addip_serial;\n\t\tstruct sctp_random_param *peer_random;\n\t\tstruct sctp_chunks_param *peer_chunks;\n\t\tstruct sctp_hmac_algo_param *peer_hmacs;\n\t} peer;\n\tenum sctp_state state;\n\tint overall_error_count;\n\tktime_t cookie_life;\n\tlong unsigned int rto_initial;\n\tlong unsigned int rto_max;\n\tlong unsigned int rto_min;\n\tint max_burst;\n\tint max_retrans;\n\t__u16 pf_retrans;\n\t__u16 ps_retrans;\n\t__u16 max_init_attempts;\n\t__u16 init_retries;\n\tlong unsigned int max_init_timeo;\n\tlong unsigned int hbinterval;\n\tlong unsigned int probe_interval;\n\t__be16 encap_port;\n\t__u16 pathmaxrxt;\n\t__u32 flowlabel;\n\t__u8 dscp;\n\t__u8 pmtu_pending;\n\t__u32 pathmtu;\n\t__u32 param_flags;\n\t__u32 sackfreq;\n\tlong unsigned int sackdelay;\n\tlong unsigned int timeouts[12];\n\tstruct timer_list timers[12];\n\tstruct sctp_transport *shutdown_last_sent_to;\n\tstruct sctp_transport *init_last_sent_to;\n\tint shutdown_retries;\n\t__u32 next_tsn;\n\t__u32 ctsn_ack_point;\n\t__u32 adv_peer_ack_point;\n\t__u32 highest_sacked;\n\t__u32 fast_recovery_exit;\n\t__u8 fast_recovery;\n\t__u16 unack_data;\n\t__u32 rtx_data_chunks;\n\t__u32 rwnd;\n\t__u32 a_rwnd;\n\t__u32 rwnd_over;\n\t__u32 rwnd_press;\n\tint sndbuf_used;\n\tatomic_t rmem_alloc;\n\twait_queue_head_t wait;\n\t__u32 frag_point;\n\t__u32 user_frag;\n\tint init_err_counter;\n\tint init_cycle;\n\t__u16 default_stream;\n\t__u16 default_flags;\n\t__u32 default_ppid;\n\t__u32 default_context;\n\t__u32 default_timetolive;\n\t__u32 default_rcv_context;\n\tstruct sctp_stream stream;\n\tstruct sctp_outq outqueue;\n\tstruct sctp_ulpq ulpq;\n\t__u32 last_ecne_tsn;\n\t__u32 last_cwr_tsn;\n\tint numduptsns;\n\tstruct sctp_chunk *addip_last_asconf;\n\tstruct list_head asconf_ack_list;\n\tstruct list_head addip_chunk_list;\n\t__u32 addip_serial;\n\tint src_out_of_asoc_ok;\n\tunion sctp_addr *asconf_addr_del_pending;\n\tstruct sctp_transport *new_transport;\n\tstruct list_head endpoint_shared_keys;\n\tstruct sctp_auth_bytes *asoc_shared_key;\n\tstruct sctp_shared_key *shkey;\n\t__u16 default_hmac_id;\n\t__u16 active_key_id;\n\t__u8 need_ecne: 1;\n\t__u8 temp: 1;\n\t__u8 pf_expose: 2;\n\t__u8 force_delay: 1;\n\t__u8 strreset_enable;\n\t__u8 strreset_outstanding;\n\t__u32 strreset_outseq;\n\t__u32 strreset_inseq;\n\t__u32 strreset_result[2];\n\tstruct sctp_chunk *strreset_chunk;\n\tstruct sctp_priv_assoc_stats stats;\n\tint sent_cnt_removable;\n\t__u16 subscribe;\n\t__u64 abandoned_unsent[3];\n\t__u64 abandoned_sent[3];\n\tstruct callback_head rcu;\n};\n\nstruct sctp_auth_bytes {\n\trefcount_t refcnt;\n\t__u32 len;\n\t__u8 data[0];\n};\n\nstruct sctp_shared_key {\n\tstruct list_head key_list;\n\tstruct sctp_auth_bytes *key;\n\trefcount_t refcnt;\n\t__u16 key_id;\n\t__u8 deactivated;\n};\n\nenum {\n\tSCTP_MAX_STREAM = 65535,\n};\n\nenum sctp_event_timeout {\n\tSCTP_EVENT_TIMEOUT_NONE = 0,\n\tSCTP_EVENT_TIMEOUT_T1_COOKIE = 1,\n\tSCTP_EVENT_TIMEOUT_T1_INIT = 2,\n\tSCTP_EVENT_TIMEOUT_T2_SHUTDOWN = 3,\n\tSCTP_EVENT_TIMEOUT_T3_RTX = 4,\n\tSCTP_EVENT_TIMEOUT_T4_RTO = 5,\n\tSCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD = 6,\n\tSCTP_EVENT_TIMEOUT_HEARTBEAT = 7,\n\tSCTP_EVENT_TIMEOUT_RECONF = 8,\n\tSCTP_EVENT_TIMEOUT_PROBE = 9,\n\tSCTP_EVENT_TIMEOUT_SACK = 10,\n\tSCTP_EVENT_TIMEOUT_AUTOCLOSE = 11,\n};\n\nenum {\n\tSCTP_MAX_DUP_TSNS = 16,\n};\n\nenum sctp_scope {\n\tSCTP_SCOPE_GLOBAL = 0,\n\tSCTP_SCOPE_PRIVATE = 1,\n\tSCTP_SCOPE_LINK = 2,\n\tSCTP_SCOPE_LOOPBACK = 3,\n\tSCTP_SCOPE_UNUSABLE = 4,\n};\n\nenum {\n\tSCTP_AUTH_HMAC_ID_RESERVED_0 = 0,\n\tSCTP_AUTH_HMAC_ID_SHA1 = 1,\n\tSCTP_AUTH_HMAC_ID_RESERVED_2 = 2,\n\tSCTP_AUTH_HMAC_ID_SHA256 = 3,\n\t__SCTP_AUTH_HMAC_MAX = 4,\n};\n\nstruct sctp_ulpevent {\n\tstruct sctp_association *asoc;\n\tstruct sctp_chunk *chunk;\n\tunsigned int rmem_len;\n\tunion {\n\t\t__u32 mid;\n\t\t__u16 ssn;\n\t};\n\tunion {\n\t\t__u32 ppid;\n\t\t__u32 fsn;\n\t};\n\t__u32 tsn;\n\t__u32 cumtsn;\n\t__u16 stream;\n\t__u16 flags;\n\t__u16 msg_flags;\n} __attribute__((packed));\n\nunion sctp_addr_param;\n\nunion sctp_params {\n\tvoid *v;\n\tstruct sctp_paramhdr *p;\n\tstruct sctp_cookie_preserve_param *life;\n\tstruct sctp_hostname_param *dns;\n\tstruct sctp_cookie_param *cookie;\n\tstruct sctp_supported_addrs_param *sat;\n\tstruct sctp_ipv4addr_param *v4;\n\tstruct sctp_ipv6addr_param *v6;\n\tunion sctp_addr_param *addr;\n\tstruct sctp_adaptation_ind_param *aind;\n\tstruct sctp_supported_ext_param *ext;\n\tstruct sctp_random_param *random;\n\tstruct sctp_chunks_param *chunks;\n\tstruct sctp_hmac_algo_param *hmac_algo;\n\tstruct sctp_addip_param *addip;\n};\n\nstruct sctp_sender_hb_info;\n\nstruct sctp_signed_cookie;\n\nstruct sctp_datamsg;\n\nstruct sctp_chunk {\n\tstruct list_head list;\n\trefcount_t refcnt;\n\tint sent_count;\n\tunion {\n\t\tstruct list_head transmitted_list;\n\t\tstruct list_head stream_list;\n\t};\n\tstruct list_head frag_list;\n\tstruct sk_buff *skb;\n\tunion {\n\t\tstruct sk_buff *head_skb;\n\t\tstruct sctp_shared_key *shkey;\n\t};\n\tunion sctp_params param_hdr;\n\tunion {\n\t\t__u8 *v;\n\t\tstruct sctp_datahdr *data_hdr;\n\t\tstruct sctp_inithdr *init_hdr;\n\t\tstruct sctp_sackhdr *sack_hdr;\n\t\tstruct sctp_heartbeathdr *hb_hdr;\n\t\tstruct sctp_sender_hb_info *hbs_hdr;\n\t\tstruct sctp_shutdownhdr *shutdown_hdr;\n\t\tstruct sctp_signed_cookie *cookie_hdr;\n\t\tstruct sctp_ecnehdr *ecne_hdr;\n\t\tstruct sctp_cwrhdr *ecn_cwr_hdr;\n\t\tstruct sctp_errhdr *err_hdr;\n\t\tstruct sctp_addiphdr *addip_hdr;\n\t\tstruct sctp_fwdtsn_hdr *fwdtsn_hdr;\n\t\tstruct sctp_authhdr *auth_hdr;\n\t\tstruct sctp_idatahdr *idata_hdr;\n\t\tstruct sctp_ifwdtsn_hdr *ifwdtsn_hdr;\n\t} subh;\n\t__u8 *chunk_end;\n\tstruct sctp_chunkhdr *chunk_hdr;\n\tstruct sctphdr *sctp_hdr;\n\tstruct sctp_sndrcvinfo sinfo;\n\tstruct sctp_association *asoc;\n\tstruct sctp_ep_common *rcvr;\n\tlong unsigned int sent_at;\n\tunion sctp_addr source;\n\tunion sctp_addr dest;\n\tstruct sctp_datamsg *msg;\n\tstruct sctp_transport *transport;\n\tstruct sk_buff *auth_chunk;\n\t__u16 rtt_in_progress: 1;\n\t__u16 has_tsn: 1;\n\t__u16 has_ssn: 1;\n\t__u16 singleton: 1;\n\t__u16 end_of_packet: 1;\n\t__u16 ecn_ce_done: 1;\n\t__u16 pdiscard: 1;\n\t__u16 tsn_gap_acked: 1;\n\t__u16 data_accepted: 1;\n\t__u16 auth: 1;\n\t__u16 has_asconf: 1;\n\t__u16 pmtu_probe: 1;\n\t__u16 tsn_missing_report: 2;\n\t__u16 fast_retransmit: 2;\n};\n\nstruct sctp_stream_interleave {\n\t__u16 data_chunk_len;\n\t__u16 ftsn_chunk_len;\n\tstruct sctp_chunk * (*make_datafrag)(const struct sctp_association *, const struct sctp_sndrcvinfo *, int, __u8, gfp_t);\n\tvoid (*assign_number)(struct sctp_chunk *);\n\tbool (*validate_data)(struct sctp_chunk *);\n\tint (*ulpevent_data)(struct sctp_ulpq *, struct sctp_chunk *, gfp_t);\n\tint (*enqueue_event)(struct sctp_ulpq *, struct sctp_ulpevent *);\n\tvoid (*renege_events)(struct sctp_ulpq *, struct sctp_chunk *, gfp_t);\n\tvoid (*start_pd)(struct sctp_ulpq *, gfp_t);\n\tvoid (*abort_pd)(struct sctp_ulpq *, gfp_t);\n\tvoid (*generate_ftsn)(struct sctp_outq *, __u32);\n\tbool (*validate_ftsn)(struct sctp_chunk *);\n\tvoid (*report_ftsn)(struct sctp_ulpq *, __u32);\n\tvoid (*handle_ftsn)(struct sctp_ulpq *, struct sctp_chunk *);\n};\n\nstruct sctp_bind_bucket {\n\tshort unsigned int port;\n\tsigned char fastreuse;\n\tsigned char fastreuseport;\n\tkuid_t fastuid;\n\tstruct hlist_node node;\n\tstruct hlist_head owner;\n\tstruct net *net;\n};\n\nenum sctp_socket_type {\n\tSCTP_SOCKET_UDP = 0,\n\tSCTP_SOCKET_UDP_HIGH_BANDWIDTH = 1,\n\tSCTP_SOCKET_TCP = 2,\n};\n\nstruct sctp_pf;\n\nstruct sctp_sock {\n\tstruct inet_sock inet;\n\tenum sctp_socket_type type;\n\tint: 32;\n\tstruct sctp_pf *pf;\n\tstruct crypto_shash___2 *hmac;\n\tchar *sctp_hmac_alg;\n\tstruct sctp_endpoint *ep;\n\tstruct sctp_bind_bucket *bind_hash;\n\t__u16 default_stream;\n\tshort: 16;\n\t__u32 default_ppid;\n\t__u16 default_flags;\n\tshort: 16;\n\t__u32 default_context;\n\t__u32 default_timetolive;\n\t__u32 default_rcv_context;\n\tint max_burst;\n\t__u32 hbinterval;\n\t__u32 probe_interval;\n\t__be16 udp_port;\n\t__be16 encap_port;\n\t__u16 pathmaxrxt;\n\tshort: 16;\n\t__u32 flowlabel;\n\t__u8 dscp;\n\tchar: 8;\n\t__u16 pf_retrans;\n\t__u16 ps_retrans;\n\tshort: 16;\n\t__u32 pathmtu;\n\t__u32 sackdelay;\n\t__u32 sackfreq;\n\t__u32 param_flags;\n\t__u32 default_ss;\n\tstruct sctp_rtoinfo rtoinfo;\n\tstruct sctp_paddrparams paddrparam;\n\tstruct sctp_assocparams assocparams;\n\t__u16 subscribe;\n\tstruct sctp_initmsg initmsg;\n\tshort: 16;\n\tint user_frag;\n\t__u32 autoclose;\n\t__u32 adaptation_ind;\n\t__u32 pd_point;\n\t__u16 nodelay: 1;\n\t__u16 pf_expose: 2;\n\t__u16 reuse: 1;\n\t__u16 disable_fragments: 1;\n\t__u16 v4mapped: 1;\n\t__u16 frag_interleave: 1;\n\t__u16 recvrcvinfo: 1;\n\t__u16 recvnxtinfo: 1;\n\t__u16 data_ready_signalled: 1;\n\tint: 22;\n\tatomic_t pd_mode;\n\tstruct sk_buff_head pd_lobby;\n\tstruct list_head auto_asconf_list;\n\tint do_auto_asconf;\n\tint: 32;\n} __attribute__((packed));\n\nstruct sctp_af;\n\nstruct sctp_pf {\n\tvoid (*event_msgname)(struct sctp_ulpevent *, char *, int *);\n\tvoid (*skb_msgname)(struct sk_buff *, char *, int *);\n\tint (*af_supported)(sa_family_t, struct sctp_sock *);\n\tint (*cmp_addr)(const union sctp_addr *, const union sctp_addr *, struct sctp_sock *);\n\tint (*bind_verify)(struct sctp_sock *, union sctp_addr *);\n\tint (*send_verify)(struct sctp_sock *, union sctp_addr *);\n\tint (*supported_addrs)(const struct sctp_sock *, __be16 *);\n\tstruct sock * (*create_accept_sk)(struct sock *, struct sctp_association *, bool);\n\tint (*addr_to_user)(struct sctp_sock *, union sctp_addr *);\n\tvoid (*to_sk_saddr)(union sctp_addr *, struct sock *);\n\tvoid (*to_sk_daddr)(union sctp_addr *, struct sock *);\n\tvoid (*copy_ip_options)(struct sock *, struct sock *);\n\tstruct sctp_af *af;\n};\n\nstruct sctp_signed_cookie {\n\t__u8 signature[32];\n\t__u32 __pad;\n\tstruct sctp_cookie c;\n} __attribute__((packed));\n\nunion sctp_addr_param {\n\tstruct sctp_paramhdr p;\n\tstruct sctp_ipv4addr_param v4;\n\tstruct sctp_ipv6addr_param v6;\n};\n\nstruct sctp_sender_hb_info {\n\tstruct sctp_paramhdr param_hdr;\n\tunion sctp_addr daddr;\n\tlong unsigned int sent_at;\n\t__u64 hb_nonce;\n\t__u32 probe_size;\n};\n\nstruct sctp_af {\n\tint (*sctp_xmit)(struct sk_buff *, struct sctp_transport *);\n\tint (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int);\n\tint (*getsockopt)(struct sock *, int, int, char *, int *);\n\tvoid (*get_dst)(struct sctp_transport *, union sctp_addr *, struct flowi *, struct sock *);\n\tvoid (*get_saddr)(struct sctp_sock *, struct sctp_transport *, struct flowi *);\n\tvoid (*copy_addrlist)(struct list_head *, struct net_device *);\n\tint (*cmp_addr)(const union sctp_addr *, const union sctp_addr *);\n\tvoid (*addr_copy)(union sctp_addr *, union sctp_addr *);\n\tvoid (*from_skb)(union sctp_addr *, struct sk_buff *, int);\n\tvoid (*from_sk)(union sctp_addr *, struct sock *);\n\tbool (*from_addr_param)(union sctp_addr *, union sctp_addr_param *, __be16, int);\n\tint (*to_addr_param)(const union sctp_addr *, union sctp_addr_param *);\n\tint (*addr_valid)(union sctp_addr *, struct sctp_sock *, const struct sk_buff *);\n\tenum sctp_scope (*scope)(union sctp_addr *);\n\tvoid (*inaddr_any)(union sctp_addr *, __be16);\n\tint (*is_any)(const union sctp_addr *);\n\tint (*available)(union sctp_addr *, struct sctp_sock *);\n\tint (*skb_iif)(const struct sk_buff *);\n\tint (*is_ce)(const struct sk_buff *);\n\tvoid (*seq_dump_addr)(struct seq_file *, union sctp_addr *);\n\tvoid (*ecn_capable)(struct sock *);\n\t__u16 net_header_len;\n\tint sockaddr_len;\n\tint (*ip_options_len)(struct sock *);\n\tsa_family_t sa_family;\n\tstruct list_head list;\n};\n\nstruct sctp_packet {\n\t__u16 source_port;\n\t__u16 destination_port;\n\t__u32 vtag;\n\tstruct list_head chunk_list;\n\tsize_t overhead;\n\tsize_t size;\n\tsize_t max_size;\n\tstruct sctp_transport *transport;\n\tstruct sctp_chunk *auth;\n\tu8 has_cookie_echo: 1;\n\tu8 has_sack: 1;\n\tu8 has_auth: 1;\n\tu8 has_data: 1;\n\tu8 ipfragok: 1;\n};\n\nstruct sctp_transport {\n\tstruct list_head transports;\n\tstruct rhlist_head node;\n\trefcount_t refcnt;\n\t__u32 rto_pending: 1;\n\t__u32 hb_sent: 1;\n\t__u32 pmtu_pending: 1;\n\t__u32 dst_pending_confirm: 1;\n\t__u32 sack_generation: 1;\n\tu32 dst_cookie;\n\tstruct flowi fl;\n\tunion sctp_addr ipaddr;\n\tstruct sctp_af *af_specific;\n\tstruct sctp_association *asoc;\n\tlong unsigned int rto;\n\t__u32 rtt;\n\t__u32 rttvar;\n\t__u32 srtt;\n\t__u32 cwnd;\n\t__u32 ssthresh;\n\t__u32 partial_bytes_acked;\n\t__u32 flight_size;\n\t__u32 burst_limited;\n\tstruct dst_entry *dst;\n\tunion sctp_addr saddr;\n\tlong unsigned int hbinterval;\n\tlong unsigned int probe_interval;\n\tlong unsigned int sackdelay;\n\t__u32 sackfreq;\n\tatomic_t mtu_info;\n\tktime_t last_time_heard;\n\tlong unsigned int last_time_sent;\n\tlong unsigned int last_time_ecne_reduced;\n\t__be16 encap_port;\n\t__u16 pathmaxrxt;\n\t__u32 flowlabel;\n\t__u8 dscp;\n\t__u16 pf_retrans;\n\t__u16 ps_retrans;\n\t__u32 pathmtu;\n\t__u32 param_flags;\n\tint init_sent_count;\n\tint state;\n\tshort unsigned int error_count;\n\tstruct timer_list T3_rtx_timer;\n\tstruct timer_list hb_timer;\n\tstruct timer_list proto_unreach_timer;\n\tstruct timer_list reconf_timer;\n\tstruct timer_list probe_timer;\n\tstruct list_head transmitted;\n\tstruct sctp_packet packet;\n\tstruct list_head send_ready;\n\tstruct {\n\t\t__u32 next_tsn_at_change;\n\t\tchar changeover_active;\n\t\tchar cycling_changeover;\n\t\tchar cacc_saw_newack;\n\t} cacc;\n\tstruct {\n\t\t__u32 last_rtx_chunks;\n\t\t__u16 pmtu;\n\t\t__u16 probe_size;\n\t\t__u16 probe_high;\n\t\t__u8 probe_count: 3;\n\t\t__u8 raise_count: 5;\n\t\t__u8 state;\n\t} pl;\n\t__u64 hb_nonce;\n\tstruct callback_head rcu;\n};\n\nstruct sctp_datamsg {\n\tstruct list_head chunks;\n\trefcount_t refcnt;\n\tlong unsigned int expires_at;\n\tint send_error;\n\tu8 send_failed: 1;\n\tu8 can_delay: 1;\n\tu8 abandoned: 1;\n};\n\nstruct sctp_stream_priorities {\n\tstruct list_head prio_sched;\n\tstruct list_head active;\n\tstruct sctp_stream_out_ext *next;\n\t__u16 prio;\n};\n\nstruct sctp_stream_out_ext {\n\t__u64 abandoned_unsent[3];\n\t__u64 abandoned_sent[3];\n\tstruct list_head outq;\n\tunion {\n\t\tstruct {\n\t\t\tstruct list_head prio_list;\n\t\t\tstruct sctp_stream_priorities *prio_head;\n\t\t};\n\t\tstruct {\n\t\t\tstruct list_head rr_list;\n\t\t};\n\t};\n};\n\nstruct task_security_struct {\n\tu32 osid;\n\tu32 sid;\n\tu32 exec_sid;\n\tu32 create_sid;\n\tu32 keycreate_sid;\n\tu32 sockcreate_sid;\n};\n\nenum label_initialized {\n\tLABEL_INVALID = 0,\n\tLABEL_INITIALIZED = 1,\n\tLABEL_PENDING = 2,\n};\n\nstruct inode_security_struct {\n\tstruct inode *inode;\n\tstruct list_head list;\n\tu32 task_sid;\n\tu32 sid;\n\tu16 sclass;\n\tunsigned char initialized;\n\tspinlock_t lock;\n};\n\nstruct file_security_struct {\n\tu32 sid;\n\tu32 fown_sid;\n\tu32 isid;\n\tu32 pseqno;\n};\n\nstruct superblock_security_struct {\n\tu32 sid;\n\tu32 def_sid;\n\tu32 mntpoint_sid;\n\tshort unsigned int behavior;\n\tshort unsigned int flags;\n\tstruct mutex lock;\n\tstruct list_head isec_head;\n\tspinlock_t isec_lock;\n};\n\nstruct msg_security_struct {\n\tu32 sid;\n};\n\nstruct ipc_security_struct {\n\tu16 sclass;\n\tu32 sid;\n};\n\nstruct sk_security_struct {\n\tenum {\n\t\tNLBL_UNSET = 0,\n\t\tNLBL_REQUIRE = 1,\n\t\tNLBL_LABELED = 2,\n\t\tNLBL_REQSKB = 3,\n\t\tNLBL_CONNLABELED = 4,\n\t} nlbl_state;\n\tstruct netlbl_lsm_secattr *nlbl_secattr;\n\tu32 sid;\n\tu32 peer_sid;\n\tu16 sclass;\n\tenum {\n\t\tSCTP_ASSOC_UNSET = 0,\n\t\tSCTP_ASSOC_SET = 1,\n\t} sctp_assoc_state;\n};\n\nstruct tun_security_struct {\n\tu32 sid;\n};\n\nstruct key_security_struct {\n\tu32 sid;\n};\n\nstruct ib_security_struct {\n\tu32 sid;\n};\n\nstruct bpf_security_struct {\n\tu32 sid;\n};\n\nstruct perf_event_security_struct {\n\tu32 sid;\n};\n\nstruct selinux_mnt_opts {\n\tconst char *fscontext;\n\tconst char *context;\n\tconst char *rootcontext;\n\tconst char *defcontext;\n};\n\nenum {\n\tOpt_error = 4294967295,\n\tOpt_context = 0,\n\tOpt_defcontext = 1,\n\tOpt_fscontext = 2,\n\tOpt_rootcontext = 3,\n\tOpt_seclabel = 4,\n};\n\nstruct selinux_policy_convert_data;\n\nstruct selinux_load_state {\n\tstruct selinux_policy *policy;\n\tstruct selinux_policy_convert_data *convert_data;\n};\n\nenum sel_inos {\n\tSEL_ROOT_INO = 2,\n\tSEL_LOAD = 3,\n\tSEL_ENFORCE = 4,\n\tSEL_CONTEXT = 5,\n\tSEL_ACCESS = 6,\n\tSEL_CREATE = 7,\n\tSEL_RELABEL = 8,\n\tSEL_USER = 9,\n\tSEL_POLICYVERS = 10,\n\tSEL_COMMIT_BOOLS = 11,\n\tSEL_MLS = 12,\n\tSEL_DISABLE = 13,\n\tSEL_MEMBER = 14,\n\tSEL_CHECKREQPROT = 15,\n\tSEL_COMPAT_NET = 16,\n\tSEL_REJECT_UNKNOWN = 17,\n\tSEL_DENY_UNKNOWN = 18,\n\tSEL_STATUS = 19,\n\tSEL_POLICY = 20,\n\tSEL_VALIDATE_TRANS = 21,\n\tSEL_INO_NEXT = 22,\n};\n\nstruct selinux_fs_info {\n\tstruct dentry *bool_dir;\n\tunsigned int bool_num;\n\tchar **bool_pending_names;\n\tunsigned int *bool_pending_values;\n\tstruct dentry *class_dir;\n\tlong unsigned int last_class_ino;\n\tbool policy_opened;\n\tstruct dentry *policycap_dir;\n\tlong unsigned int last_ino;\n\tstruct selinux_state *state;\n\tstruct super_block *sb;\n};\n\nstruct policy_load_memory {\n\tsize_t len;\n\tvoid *data;\n};\n\nenum {\n\tSELNL_MSG_SETENFORCE = 16,\n\tSELNL_MSG_POLICYLOAD = 17,\n\tSELNL_MSG_MAX = 18,\n};\n\nenum selinux_nlgroups {\n\tSELNLGRP_NONE = 0,\n\tSELNLGRP_AVC = 1,\n\t__SELNLGRP_MAX = 2,\n};\n\nstruct selnl_msg_setenforce {\n\t__s32 val;\n};\n\nstruct selnl_msg_policyload {\n\t__u32 seqno;\n};\n\nenum {\n\tXFRM_MSG_BASE = 16,\n\tXFRM_MSG_NEWSA = 16,\n\tXFRM_MSG_DELSA = 17,\n\tXFRM_MSG_GETSA = 18,\n\tXFRM_MSG_NEWPOLICY = 19,\n\tXFRM_MSG_DELPOLICY = 20,\n\tXFRM_MSG_GETPOLICY = 21,\n\tXFRM_MSG_ALLOCSPI = 22,\n\tXFRM_MSG_ACQUIRE = 23,\n\tXFRM_MSG_EXPIRE = 24,\n\tXFRM_MSG_UPDPOLICY = 25,\n\tXFRM_MSG_UPDSA = 26,\n\tXFRM_MSG_POLEXPIRE = 27,\n\tXFRM_MSG_FLUSHSA = 28,\n\tXFRM_MSG_FLUSHPOLICY = 29,\n\tXFRM_MSG_NEWAE = 30,\n\tXFRM_MSG_GETAE = 31,\n\tXFRM_MSG_REPORT = 32,\n\tXFRM_MSG_MIGRATE = 33,\n\tXFRM_MSG_NEWSADINFO = 34,\n\tXFRM_MSG_GETSADINFO = 35,\n\tXFRM_MSG_NEWSPDINFO = 36,\n\tXFRM_MSG_GETSPDINFO = 37,\n\tXFRM_MSG_MAPPING = 38,\n\t__XFRM_MSG_MAX = 39,\n};\n\nenum {\n\tRTM_BASE = 16,\n\tRTM_NEWLINK = 16,\n\tRTM_DELLINK = 17,\n\tRTM_GETLINK = 18,\n\tRTM_SETLINK = 19,\n\tRTM_NEWADDR = 20,\n\tRTM_DELADDR = 21,\n\tRTM_GETADDR = 22,\n\tRTM_NEWROUTE = 24,\n\tRTM_DELROUTE = 25,\n\tRTM_GETROUTE = 26,\n\tRTM_NEWNEIGH = 28,\n\tRTM_DELNEIGH = 29,\n\tRTM_GETNEIGH = 30,\n\tRTM_NEWRULE = 32,\n\tRTM_DELRULE = 33,\n\tRTM_GETRULE = 34,\n\tRTM_NEWQDISC = 36,\n\tRTM_DELQDISC = 37,\n\tRTM_GETQDISC = 38,\n\tRTM_NEWTCLASS = 40,\n\tRTM_DELTCLASS = 41,\n\tRTM_GETTCLASS = 42,\n\tRTM_NEWTFILTER = 44,\n\tRTM_DELTFILTER = 45,\n\tRTM_GETTFILTER = 46,\n\tRTM_NEWACTION = 48,\n\tRTM_DELACTION = 49,\n\tRTM_GETACTION = 50,\n\tRTM_NEWPREFIX = 52,\n\tRTM_GETMULTICAST = 58,\n\tRTM_GETANYCAST = 62,\n\tRTM_NEWNEIGHTBL = 64,\n\tRTM_GETNEIGHTBL = 66,\n\tRTM_SETNEIGHTBL = 67,\n\tRTM_NEWNDUSEROPT = 68,\n\tRTM_NEWADDRLABEL = 72,\n\tRTM_DELADDRLABEL = 73,\n\tRTM_GETADDRLABEL = 74,\n\tRTM_GETDCB = 78,\n\tRTM_SETDCB = 79,\n\tRTM_NEWNETCONF = 80,\n\tRTM_DELNETCONF = 81,\n\tRTM_GETNETCONF = 82,\n\tRTM_NEWMDB = 84,\n\tRTM_DELMDB = 85,\n\tRTM_GETMDB = 86,\n\tRTM_NEWNSID = 88,\n\tRTM_DELNSID = 89,\n\tRTM_GETNSID = 90,\n\tRTM_NEWSTATS = 92,\n\tRTM_GETSTATS = 94,\n\tRTM_NEWCACHEREPORT = 96,\n\tRTM_NEWCHAIN = 100,\n\tRTM_DELCHAIN = 101,\n\tRTM_GETCHAIN = 102,\n\tRTM_NEWNEXTHOP = 104,\n\tRTM_DELNEXTHOP = 105,\n\tRTM_GETNEXTHOP = 106,\n\tRTM_NEWLINKPROP = 108,\n\tRTM_DELLINKPROP = 109,\n\tRTM_GETLINKPROP = 110,\n\tRTM_NEWVLAN = 112,\n\tRTM_DELVLAN = 113,\n\tRTM_GETVLAN = 114,\n\tRTM_NEWNEXTHOPBUCKET = 116,\n\tRTM_DELNEXTHOPBUCKET = 117,\n\tRTM_GETNEXTHOPBUCKET = 118,\n\t__RTM_MAX = 119,\n};\n\nstruct nlmsg_perm {\n\tu16 nlmsg_type;\n\tu32 perm;\n};\n\nstruct netif_security_struct {\n\tstruct net *ns;\n\tint ifindex;\n\tu32 sid;\n};\n\nstruct sel_netif {\n\tstruct list_head list;\n\tstruct netif_security_struct nsec;\n\tstruct callback_head callback_head;\n};\n\nstruct netnode_security_struct {\n\tunion {\n\t\t__be32 ipv4;\n\t\tstruct in6_addr ipv6;\n\t} addr;\n\tu32 sid;\n\tu16 family;\n};\n\nstruct sel_netnode_bkt {\n\tunsigned int size;\n\tstruct list_head list;\n};\n\nstruct sel_netnode {\n\tstruct netnode_security_struct nsec;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct netport_security_struct {\n\tu32 sid;\n\tu16 port;\n\tu8 protocol;\n};\n\nstruct sel_netport_bkt {\n\tint size;\n\tstruct list_head list;\n};\n\nstruct sel_netport {\n\tstruct netport_security_struct psec;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct selinux_kernel_status {\n\tu32 version;\n\tu32 sequence;\n\tu32 enforcing;\n\tu32 policyload;\n\tu32 deny_unknown;\n};\n\nstruct ebitmap_node {\n\tstruct ebitmap_node *next;\n\tlong unsigned int maps[6];\n\tu32 startbit;\n};\n\nstruct ebitmap {\n\tstruct ebitmap_node *node;\n\tu32 highbit;\n};\n\nstruct policy_file {\n\tchar *data;\n\tsize_t len;\n};\n\nstruct hashtab_node {\n\tvoid *key;\n\tvoid *datum;\n\tstruct hashtab_node *next;\n};\n\nstruct hashtab {\n\tstruct hashtab_node **htable;\n\tu32 size;\n\tu32 nel;\n};\n\nstruct hashtab_info {\n\tu32 slots_used;\n\tu32 max_chain_len;\n};\n\nstruct hashtab_key_params {\n\tu32 (*hash)(const void *);\n\tint (*cmp)(const void *, const void *);\n};\n\nstruct symtab {\n\tstruct hashtab table;\n\tu32 nprim;\n};\n\nstruct mls_level {\n\tu32 sens;\n\tstruct ebitmap cat;\n};\n\nstruct mls_range {\n\tstruct mls_level level[2];\n};\n\nstruct context___2 {\n\tu32 user;\n\tu32 role;\n\tu32 type;\n\tu32 len;\n\tstruct mls_range range;\n\tchar *str;\n};\n\nstruct sidtab_str_cache;\n\nstruct sidtab_entry {\n\tu32 sid;\n\tu32 hash;\n\tstruct context___2 context;\n\tstruct sidtab_str_cache *cache;\n\tstruct hlist_node list;\n};\n\nstruct sidtab_str_cache {\n\tstruct callback_head rcu_member;\n\tstruct list_head lru_member;\n\tstruct sidtab_entry *parent;\n\tu32 len;\n\tchar str[0];\n};\n\nstruct sidtab_node_inner;\n\nstruct sidtab_node_leaf;\n\nunion sidtab_entry_inner {\n\tstruct sidtab_node_inner *ptr_inner;\n\tstruct sidtab_node_leaf *ptr_leaf;\n};\n\nstruct sidtab_node_inner {\n\tunion sidtab_entry_inner entries[512];\n};\n\nstruct sidtab_node_leaf {\n\tstruct sidtab_entry entries[39];\n};\n\nstruct sidtab_isid_entry {\n\tint set;\n\tstruct sidtab_entry entry;\n};\n\nstruct sidtab;\n\nstruct sidtab_convert_params {\n\tint (*func)(struct context___2 *, struct context___2 *, void *);\n\tvoid *args;\n\tstruct sidtab *target;\n};\n\nstruct sidtab {\n\tunion sidtab_entry_inner roots[4];\n\tu32 count;\n\tstruct sidtab_convert_params *convert;\n\tbool frozen;\n\tspinlock_t lock;\n\tu32 cache_free_slots;\n\tstruct list_head cache_lru_list;\n\tspinlock_t cache_lock;\n\tstruct sidtab_isid_entry isids[27];\n\tstruct hlist_head context_to_sid[512];\n};\n\nstruct avtab_key {\n\tu16 source_type;\n\tu16 target_type;\n\tu16 target_class;\n\tu16 specified;\n};\n\nstruct avtab_extended_perms {\n\tu8 specified;\n\tu8 driver;\n\tstruct extended_perms_data perms;\n};\n\nstruct avtab_datum {\n\tunion {\n\t\tu32 data;\n\t\tstruct avtab_extended_perms *xperms;\n\t} u;\n};\n\nstruct avtab_node {\n\tstruct avtab_key key;\n\tstruct avtab_datum datum;\n\tstruct avtab_node *next;\n};\n\nstruct avtab {\n\tstruct avtab_node **htable;\n\tu32 nel;\n\tu32 nslot;\n\tu32 mask;\n};\n\nstruct type_set;\n\nstruct constraint_expr {\n\tu32 expr_type;\n\tu32 attr;\n\tu32 op;\n\tstruct ebitmap names;\n\tstruct type_set *type_names;\n\tstruct constraint_expr *next;\n};\n\nstruct type_set {\n\tstruct ebitmap types;\n\tstruct ebitmap negset;\n\tu32 flags;\n};\n\nstruct constraint_node {\n\tu32 permissions;\n\tstruct constraint_expr *expr;\n\tstruct constraint_node *next;\n};\n\nstruct common_datum {\n\tu32 value;\n\tstruct symtab permissions;\n};\n\nstruct class_datum {\n\tu32 value;\n\tchar *comkey;\n\tstruct common_datum *comdatum;\n\tstruct symtab permissions;\n\tstruct constraint_node *constraints;\n\tstruct constraint_node *validatetrans;\n\tchar default_user;\n\tchar default_role;\n\tchar default_type;\n\tchar default_range;\n};\n\nstruct role_datum {\n\tu32 value;\n\tu32 bounds;\n\tstruct ebitmap dominates;\n\tstruct ebitmap types;\n};\n\nstruct role_allow {\n\tu32 role;\n\tu32 new_role;\n\tstruct role_allow *next;\n};\n\nstruct type_datum {\n\tu32 value;\n\tu32 bounds;\n\tunsigned char primary;\n\tunsigned char attribute;\n};\n\nstruct user_datum {\n\tu32 value;\n\tu32 bounds;\n\tstruct ebitmap roles;\n\tstruct mls_range range;\n\tstruct mls_level dfltlevel;\n};\n\nstruct cond_bool_datum {\n\t__u32 value;\n\tint state;\n};\n\nstruct ocontext {\n\tunion {\n\t\tchar *name;\n\t\tstruct {\n\t\t\tu8 protocol;\n\t\t\tu16 low_port;\n\t\t\tu16 high_port;\n\t\t} port;\n\t\tstruct {\n\t\t\tu32 addr;\n\t\t\tu32 mask;\n\t\t} node;\n\t\tstruct {\n\t\t\tu32 addr[4];\n\t\t\tu32 mask[4];\n\t\t} node6;\n\t\tstruct {\n\t\t\tu64 subnet_prefix;\n\t\t\tu16 low_pkey;\n\t\t\tu16 high_pkey;\n\t\t} ibpkey;\n\t\tstruct {\n\t\t\tchar *dev_name;\n\t\t\tu8 port;\n\t\t} ibendport;\n\t} u;\n\tunion {\n\t\tu32 sclass;\n\t\tu32 behavior;\n\t} v;\n\tstruct context___2 context[2];\n\tu32 sid[2];\n\tstruct ocontext *next;\n};\n\nstruct genfs {\n\tchar *fstype;\n\tstruct ocontext *head;\n\tstruct genfs *next;\n};\n\nstruct cond_node;\n\nstruct policydb {\n\tint mls_enabled;\n\tstruct symtab symtab[8];\n\tchar **sym_val_to_name[8];\n\tstruct class_datum **class_val_to_struct;\n\tstruct role_datum **role_val_to_struct;\n\tstruct user_datum **user_val_to_struct;\n\tstruct type_datum **type_val_to_struct;\n\tstruct avtab te_avtab;\n\tstruct hashtab role_tr;\n\tstruct ebitmap filename_trans_ttypes;\n\tstruct hashtab filename_trans;\n\tu32 compat_filename_trans_count;\n\tstruct cond_bool_datum **bool_val_to_struct;\n\tstruct avtab te_cond_avtab;\n\tstruct cond_node *cond_list;\n\tu32 cond_list_len;\n\tstruct role_allow *role_allow;\n\tstruct ocontext *ocontexts[9];\n\tstruct genfs *genfs;\n\tstruct hashtab range_tr;\n\tstruct ebitmap *type_attr_map_array;\n\tstruct ebitmap policycaps;\n\tstruct ebitmap permissive_map;\n\tsize_t len;\n\tunsigned int policyvers;\n\tunsigned int reject_unknown: 1;\n\tunsigned int allow_unknown: 1;\n\tu16 process_class;\n\tu32 process_trans_perms;\n};\n\nstruct perm_datum {\n\tu32 value;\n};\n\nstruct role_trans_key {\n\tu32 role;\n\tu32 type;\n\tu32 tclass;\n};\n\nstruct role_trans_datum {\n\tu32 new_role;\n};\n\nstruct filename_trans_key {\n\tu32 ttype;\n\tu16 tclass;\n\tconst char *name;\n};\n\nstruct filename_trans_datum {\n\tstruct ebitmap stypes;\n\tu32 otype;\n\tstruct filename_trans_datum *next;\n};\n\nstruct level_datum {\n\tstruct mls_level *level;\n\tunsigned char isalias;\n};\n\nstruct cat_datum {\n\tu32 value;\n\tunsigned char isalias;\n};\n\nstruct range_trans {\n\tu32 source_type;\n\tu32 target_type;\n\tu32 target_class;\n};\n\nstruct cond_expr_node;\n\nstruct cond_expr {\n\tstruct cond_expr_node *nodes;\n\tu32 len;\n};\n\nstruct cond_av_list {\n\tstruct avtab_node **nodes;\n\tu32 len;\n};\n\nstruct cond_node {\n\tint cur_state;\n\tstruct cond_expr expr;\n\tstruct cond_av_list true_list;\n\tstruct cond_av_list false_list;\n};\n\nstruct policy_data {\n\tstruct policydb *p;\n\tvoid *fp;\n};\n\nstruct cond_expr_node {\n\tu32 expr_type;\n\tu32 bool;\n};\n\nstruct policydb_compat_info {\n\tint version;\n\tint sym_num;\n\tint ocon_num;\n};\n\nstruct selinux_mapping;\n\nstruct selinux_map {\n\tstruct selinux_mapping *mapping;\n\tu16 size;\n};\n\nstruct selinux_policy {\n\tstruct sidtab *sidtab;\n\tstruct policydb policydb;\n\tstruct selinux_map map;\n\tu32 latest_granting;\n};\n\nstruct convert_context_args {\n\tstruct selinux_state *state;\n\tstruct policydb *oldp;\n\tstruct policydb *newp;\n};\n\nstruct selinux_policy_convert_data {\n\tstruct convert_context_args args;\n\tstruct sidtab_convert_params sidtab_params;\n};\n\nstruct selinux_mapping {\n\tu16 value;\n\tunsigned int num_perms;\n\tu32 perms[32];\n};\n\nstruct selinux_audit_rule {\n\tu32 au_seqno;\n\tstruct context___2 au_ctxt;\n};\n\nstruct cond_insertf_data {\n\tstruct policydb *p;\n\tstruct avtab_node **dst;\n\tstruct cond_av_list *other;\n};\n\nstruct rt6key {\n\tstruct in6_addr addr;\n\tint plen;\n};\n\nstruct rtable;\n\nstruct fnhe_hash_bucket;\n\nstruct fib_nh_common {\n\tstruct net_device *nhc_dev;\n\tint nhc_oif;\n\tunsigned char nhc_scope;\n\tu8 nhc_family;\n\tu8 nhc_gw_family;\n\tunsigned char nhc_flags;\n\tstruct lwtunnel_state *nhc_lwtstate;\n\tunion {\n\t\t__be32 ipv4;\n\t\tstruct in6_addr ipv6;\n\t} nhc_gw;\n\tint nhc_weight;\n\tatomic_t nhc_upper_bound;\n\tstruct rtable **nhc_pcpu_rth_output;\n\tstruct rtable *nhc_rth_input;\n\tstruct fnhe_hash_bucket *nhc_exceptions;\n};\n\nstruct rt6_exception_bucket;\n\nstruct fib6_nh {\n\tstruct fib_nh_common nh_common;\n\tlong unsigned int last_probe;\n\tstruct rt6_info **rt6i_pcpu;\n\tstruct rt6_exception_bucket *rt6i_exception_bucket;\n};\n\nstruct fib6_node;\n\nstruct dst_metrics;\n\nstruct nexthop;\n\nstruct fib6_info {\n\tstruct fib6_table *fib6_table;\n\tstruct fib6_info *fib6_next;\n\tstruct fib6_node *fib6_node;\n\tunion {\n\t\tstruct list_head fib6_siblings;\n\t\tstruct list_head nh_list;\n\t};\n\tunsigned int fib6_nsiblings;\n\trefcount_t fib6_ref;\n\tlong unsigned int expires;\n\tstruct dst_metrics *fib6_metrics;\n\tstruct rt6key fib6_dst;\n\tu32 fib6_flags;\n\tstruct rt6key fib6_src;\n\tstruct rt6key fib6_prefsrc;\n\tu32 fib6_metric;\n\tu8 fib6_protocol;\n\tu8 fib6_type;\n\tu8 should_flush: 1;\n\tu8 dst_nocount: 1;\n\tu8 dst_nopolicy: 1;\n\tu8 fib6_destroying: 1;\n\tu8 offload: 1;\n\tu8 trap: 1;\n\tu8 offload_failed: 1;\n\tu8 unused: 1;\n\tstruct callback_head rcu;\n\tstruct nexthop *nh;\n\tstruct fib6_nh fib6_nh[0];\n};\n\nstruct uncached_list;\n\nstruct rt6_info {\n\tstruct dst_entry dst;\n\tstruct fib6_info *from;\n\tint sernum;\n\tstruct rt6key rt6i_dst;\n\tstruct rt6key rt6i_src;\n\tstruct in6_addr rt6i_gateway;\n\tstruct inet6_dev *rt6i_idev;\n\tu32 rt6i_flags;\n\tstruct list_head rt6i_uncached;\n\tstruct uncached_list *rt6i_uncached_list;\n\tshort unsigned int rt6i_nfheader_len;\n};\n\nstruct rt6_statistics {\n\t__u32 fib_nodes;\n\t__u32 fib_route_nodes;\n\t__u32 fib_rt_entries;\n\t__u32 fib_rt_cache;\n\t__u32 fib_discarded_routes;\n\tatomic_t fib_rt_alloc;\n\tatomic_t fib_rt_uncache;\n};\n\nstruct fib6_node {\n\tstruct fib6_node *parent;\n\tstruct fib6_node *left;\n\tstruct fib6_node *right;\n\tstruct fib6_node *subtree;\n\tstruct fib6_info *leaf;\n\t__u16 fn_bit;\n\t__u16 fn_flags;\n\tint fn_sernum;\n\tstruct fib6_info *rr_ptr;\n\tstruct callback_head rcu;\n};\n\nstruct fib6_table {\n\tstruct hlist_node tb6_hlist;\n\tu32 tb6_id;\n\tspinlock_t tb6_lock;\n\tstruct fib6_node tb6_root;\n\tstruct inet_peer_base tb6_peers;\n\tunsigned int flags;\n\tunsigned int fib_seq;\n};\n\ntypedef union {\n\t__be32 a4;\n\t__be32 a6[4];\n\tstruct in6_addr in6;\n} xfrm_address_t;\n\nstruct xfrm_id {\n\txfrm_address_t daddr;\n\t__be32 spi;\n\t__u8 proto;\n};\n\nstruct xfrm_selector {\n\txfrm_address_t daddr;\n\txfrm_address_t saddr;\n\t__be16 dport;\n\t__be16 dport_mask;\n\t__be16 sport;\n\t__be16 sport_mask;\n\t__u16 family;\n\t__u8 prefixlen_d;\n\t__u8 prefixlen_s;\n\t__u8 proto;\n\tint ifindex;\n\t__kernel_uid32_t user;\n};\n\nstruct xfrm_lifetime_cfg {\n\t__u64 soft_byte_limit;\n\t__u64 hard_byte_limit;\n\t__u64 soft_packet_limit;\n\t__u64 hard_packet_limit;\n\t__u64 soft_add_expires_seconds;\n\t__u64 hard_add_expires_seconds;\n\t__u64 soft_use_expires_seconds;\n\t__u64 hard_use_expires_seconds;\n};\n\nstruct xfrm_lifetime_cur {\n\t__u64 bytes;\n\t__u64 packets;\n\t__u64 add_time;\n\t__u64 use_time;\n};\n\nstruct xfrm_replay_state {\n\t__u32 oseq;\n\t__u32 seq;\n\t__u32 bitmap;\n};\n\nstruct xfrm_replay_state_esn {\n\tunsigned int bmp_len;\n\t__u32 oseq;\n\t__u32 seq;\n\t__u32 oseq_hi;\n\t__u32 seq_hi;\n\t__u32 replay_window;\n\t__u32 bmp[0];\n};\n\nstruct xfrm_algo {\n\tchar alg_name[64];\n\tunsigned int alg_key_len;\n\tchar alg_key[0];\n};\n\nstruct xfrm_algo_auth {\n\tchar alg_name[64];\n\tunsigned int alg_key_len;\n\tunsigned int alg_trunc_len;\n\tchar alg_key[0];\n};\n\nstruct xfrm_algo_aead {\n\tchar alg_name[64];\n\tunsigned int alg_key_len;\n\tunsigned int alg_icv_len;\n\tchar alg_key[0];\n};\n\nstruct xfrm_stats {\n\t__u32 replay_window;\n\t__u32 replay;\n\t__u32 integrity_failed;\n};\n\nenum {\n\tXFRM_POLICY_TYPE_MAIN = 0,\n\tXFRM_POLICY_TYPE_SUB = 1,\n\tXFRM_POLICY_TYPE_MAX = 2,\n\tXFRM_POLICY_TYPE_ANY = 255,\n};\n\nstruct xfrm_encap_tmpl {\n\t__u16 encap_type;\n\t__be16 encap_sport;\n\t__be16 encap_dport;\n\txfrm_address_t encap_oa;\n};\n\nenum xfrm_attr_type_t {\n\tXFRMA_UNSPEC = 0,\n\tXFRMA_ALG_AUTH = 1,\n\tXFRMA_ALG_CRYPT = 2,\n\tXFRMA_ALG_COMP = 3,\n\tXFRMA_ENCAP = 4,\n\tXFRMA_TMPL = 5,\n\tXFRMA_SA = 6,\n\tXFRMA_POLICY = 7,\n\tXFRMA_SEC_CTX = 8,\n\tXFRMA_LTIME_VAL = 9,\n\tXFRMA_REPLAY_VAL = 10,\n\tXFRMA_REPLAY_THRESH = 11,\n\tXFRMA_ETIMER_THRESH = 12,\n\tXFRMA_SRCADDR = 13,\n\tXFRMA_COADDR = 14,\n\tXFRMA_LASTUSED = 15,\n\tXFRMA_POLICY_TYPE = 16,\n\tXFRMA_MIGRATE = 17,\n\tXFRMA_ALG_AEAD = 18,\n\tXFRMA_KMADDRESS = 19,\n\tXFRMA_ALG_AUTH_TRUNC = 20,\n\tXFRMA_MARK = 21,\n\tXFRMA_TFCPAD = 22,\n\tXFRMA_REPLAY_ESN_VAL = 23,\n\tXFRMA_SA_EXTRA_FLAGS = 24,\n\tXFRMA_PROTO = 25,\n\tXFRMA_ADDRESS_FILTER = 26,\n\tXFRMA_PAD = 27,\n\tXFRMA_OFFLOAD_DEV = 28,\n\tXFRMA_SET_MARK = 29,\n\tXFRMA_SET_MARK_MASK = 30,\n\tXFRMA_IF_ID = 31,\n\t__XFRMA_MAX = 32,\n};\n\nstruct xfrm_mark {\n\t__u32 v;\n\t__u32 m;\n};\n\nstruct xfrm_address_filter {\n\txfrm_address_t saddr;\n\txfrm_address_t daddr;\n\t__u16 family;\n\t__u8 splen;\n\t__u8 dplen;\n};\n\nstruct xfrm_state_walk {\n\tstruct list_head all;\n\tu8 state;\n\tu8 dying;\n\tu8 proto;\n\tu32 seq;\n\tstruct xfrm_address_filter *filter;\n};\n\nenum xfrm_replay_mode {\n\tXFRM_REPLAY_MODE_LEGACY = 0,\n\tXFRM_REPLAY_MODE_BMP = 1,\n\tXFRM_REPLAY_MODE_ESN = 2,\n};\n\nstruct xfrm_state_offload {\n\tstruct net_device *dev;\n\tstruct net_device *real_dev;\n\tlong unsigned int offload_handle;\n\tunsigned int num_exthdrs;\n\tu8 flags;\n};\n\nstruct xfrm_mode {\n\tu8 encap;\n\tu8 family;\n\tu8 flags;\n};\n\nstruct xfrm_type;\n\nstruct xfrm_type_offload;\n\nstruct xfrm_state {\n\tpossible_net_t xs_net;\n\tunion {\n\t\tstruct hlist_node gclist;\n\t\tstruct hlist_node bydst;\n\t};\n\tstruct hlist_node bysrc;\n\tstruct hlist_node byspi;\n\tstruct hlist_node byseq;\n\trefcount_t refcnt;\n\tspinlock_t lock;\n\tstruct xfrm_id id;\n\tstruct xfrm_selector sel;\n\tstruct xfrm_mark mark;\n\tu32 if_id;\n\tu32 tfcpad;\n\tu32 genid;\n\tstruct xfrm_state_walk km;\n\tstruct {\n\t\tu32 reqid;\n\t\tu8 mode;\n\t\tu8 replay_window;\n\t\tu8 aalgo;\n\t\tu8 ealgo;\n\t\tu8 calgo;\n\t\tu8 flags;\n\t\tu16 family;\n\t\txfrm_address_t saddr;\n\t\tint header_len;\n\t\tint trailer_len;\n\t\tu32 extra_flags;\n\t\tstruct xfrm_mark smark;\n\t} props;\n\tstruct xfrm_lifetime_cfg lft;\n\tstruct xfrm_algo_auth *aalg;\n\tstruct xfrm_algo *ealg;\n\tstruct xfrm_algo *calg;\n\tstruct xfrm_algo_aead *aead;\n\tconst char *geniv;\n\tstruct xfrm_encap_tmpl *encap;\n\tstruct sock *encap_sk;\n\txfrm_address_t *coaddr;\n\tstruct xfrm_state *tunnel;\n\tatomic_t tunnel_users;\n\tstruct xfrm_replay_state replay;\n\tstruct xfrm_replay_state_esn *replay_esn;\n\tstruct xfrm_replay_state preplay;\n\tstruct xfrm_replay_state_esn *preplay_esn;\n\tenum xfrm_replay_mode repl_mode;\n\tu32 xflags;\n\tu32 replay_maxage;\n\tu32 replay_maxdiff;\n\tstruct timer_list rtimer;\n\tstruct xfrm_stats stats;\n\tstruct xfrm_lifetime_cur curlft;\n\tstruct hrtimer mtimer;\n\tstruct xfrm_state_offload xso;\n\tlong int saved_tmo;\n\ttime64_t lastused;\n\tstruct page_frag xfrag;\n\tconst struct xfrm_type *type;\n\tstruct xfrm_mode inner_mode;\n\tstruct xfrm_mode inner_mode_iaf;\n\tstruct xfrm_mode outer_mode;\n\tconst struct xfrm_type_offload *type_offload;\n\tstruct xfrm_sec_ctx *security;\n\tvoid *data;\n};\n\nstruct dst_metrics {\n\tu32 metrics[17];\n\trefcount_t refcnt;\n};\n\nstruct xfrm_policy_walk_entry {\n\tstruct list_head all;\n\tu8 dead;\n};\n\nstruct xfrm_policy_queue {\n\tstruct sk_buff_head hold_queue;\n\tstruct timer_list hold_timer;\n\tlong unsigned int timeout;\n};\n\nstruct xfrm_tmpl {\n\tstruct xfrm_id id;\n\txfrm_address_t saddr;\n\tshort unsigned int encap_family;\n\tu32 reqid;\n\tu8 mode;\n\tu8 share;\n\tu8 optional;\n\tu8 allalgs;\n\tu32 aalgos;\n\tu32 ealgos;\n\tu32 calgos;\n};\n\nstruct xfrm_policy {\n\tpossible_net_t xp_net;\n\tstruct hlist_node bydst;\n\tstruct hlist_node byidx;\n\trwlock_t lock;\n\trefcount_t refcnt;\n\tu32 pos;\n\tstruct timer_list timer;\n\tatomic_t genid;\n\tu32 priority;\n\tu32 index;\n\tu32 if_id;\n\tstruct xfrm_mark mark;\n\tstruct xfrm_selector selector;\n\tstruct xfrm_lifetime_cfg lft;\n\tstruct xfrm_lifetime_cur curlft;\n\tstruct xfrm_policy_walk_entry walk;\n\tstruct xfrm_policy_queue polq;\n\tbool bydst_reinsert;\n\tu8 type;\n\tu8 action;\n\tu8 flags;\n\tu8 xfrm_nr;\n\tu16 family;\n\tstruct xfrm_sec_ctx *security;\n\tstruct xfrm_tmpl xfrm_vec[6];\n\tstruct hlist_node bydst_inexact_list;\n\tstruct callback_head rcu;\n};\n\nstruct udp_hslot;\n\nstruct udp_table {\n\tstruct udp_hslot *hash;\n\tstruct udp_hslot *hash2;\n\tunsigned int mask;\n\tunsigned int log;\n};\n\nstruct fib_nh_exception {\n\tstruct fib_nh_exception *fnhe_next;\n\tint fnhe_genid;\n\t__be32 fnhe_daddr;\n\tu32 fnhe_pmtu;\n\tbool fnhe_mtu_locked;\n\t__be32 fnhe_gw;\n\tlong unsigned int fnhe_expires;\n\tstruct rtable *fnhe_rth_input;\n\tstruct rtable *fnhe_rth_output;\n\tlong unsigned int fnhe_stamp;\n\tstruct callback_head rcu;\n};\n\nstruct rtable {\n\tstruct dst_entry dst;\n\tint rt_genid;\n\tunsigned int rt_flags;\n\t__u16 rt_type;\n\t__u8 rt_is_input;\n\t__u8 rt_uses_gateway;\n\tint rt_iif;\n\tu8 rt_gw_family;\n\tunion {\n\t\t__be32 rt_gw4;\n\t\tstruct in6_addr rt_gw6;\n\t};\n\tu32 rt_mtu_locked: 1;\n\tu32 rt_pmtu: 31;\n\tstruct list_head rt_uncached;\n\tstruct uncached_list *rt_uncached_list;\n};\n\nstruct fnhe_hash_bucket {\n\tstruct fib_nh_exception *chain;\n};\n\nstruct rt6_exception_bucket {\n\tstruct hlist_head chain;\n\tint depth;\n};\n\nstruct xfrm_type {\n\tstruct module *owner;\n\tu8 proto;\n\tu8 flags;\n\tint (*init_state)(struct xfrm_state *);\n\tvoid (*destructor)(struct xfrm_state *);\n\tint (*input)(struct xfrm_state *, struct sk_buff *);\n\tint (*output)(struct xfrm_state *, struct sk_buff *);\n\tint (*reject)(struct xfrm_state *, struct sk_buff *, const struct flowi *);\n};\n\nstruct xfrm_type_offload {\n\tstruct module *owner;\n\tu8 proto;\n\tvoid (*encap)(struct xfrm_state *, struct sk_buff *);\n\tint (*input_tail)(struct xfrm_state *, struct sk_buff *);\n\tint (*xmit)(struct xfrm_state *, struct sk_buff *, netdev_features_t);\n};\n\nstruct xfrm_dst {\n\tunion {\n\t\tstruct dst_entry dst;\n\t\tstruct rtable rt;\n\t\tstruct rt6_info rt6;\n\t} u;\n\tstruct dst_entry *route;\n\tstruct dst_entry *child;\n\tstruct dst_entry *path;\n\tstruct xfrm_policy *pols[2];\n\tint num_pols;\n\tint num_xfrms;\n\tu32 xfrm_genid;\n\tu32 policy_genid;\n\tu32 route_mtu_cached;\n\tu32 child_mtu_cached;\n\tu32 route_cookie;\n\tu32 path_cookie;\n};\n\nstruct xfrm_offload {\n\tstruct {\n\t\t__u32 low;\n\t\t__u32 hi;\n\t} seq;\n\t__u32 flags;\n\t__u32 status;\n\t__u8 proto;\n\t__u8 inner_ipproto;\n};\n\nstruct sec_path {\n\tint len;\n\tint olen;\n\tstruct xfrm_state *xvec[6];\n\tstruct xfrm_offload ovec[1];\n};\n\nstruct udp_hslot {\n\tstruct hlist_head head;\n\tint count;\n\tspinlock_t lock;\n};\n\nstruct pkey_security_struct {\n\tu64 subnet_prefix;\n\tu16 pkey;\n\tu32 sid;\n};\n\nstruct sel_ib_pkey_bkt {\n\tint size;\n\tstruct list_head list;\n};\n\nstruct sel_ib_pkey {\n\tstruct pkey_security_struct psec;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct smack_audit_data {\n\tconst char *function;\n\tchar *subject;\n\tchar *object;\n\tchar *request;\n\tint result;\n};\n\nstruct smack_known {\n\tstruct list_head list;\n\tstruct hlist_node smk_hashed;\n\tchar *smk_known;\n\tu32 smk_secid;\n\tstruct netlbl_lsm_secattr smk_netlabel;\n\tstruct list_head smk_rules;\n\tstruct mutex smk_rules_lock;\n};\n\nstruct superblock_smack {\n\tstruct smack_known *smk_root;\n\tstruct smack_known *smk_floor;\n\tstruct smack_known *smk_hat;\n\tstruct smack_known *smk_default;\n\tint smk_flags;\n};\n\nstruct socket_smack {\n\tstruct smack_known *smk_out;\n\tstruct smack_known *smk_in;\n\tstruct smack_known *smk_packet;\n\tint smk_state;\n};\n\nstruct inode_smack {\n\tstruct smack_known *smk_inode;\n\tstruct smack_known *smk_task;\n\tstruct smack_known *smk_mmap;\n\tint smk_flags;\n};\n\nstruct task_smack {\n\tstruct smack_known *smk_task;\n\tstruct smack_known *smk_forked;\n\tstruct list_head smk_rules;\n\tstruct mutex smk_rules_lock;\n\tstruct list_head smk_relabel;\n};\n\nstruct smack_rule {\n\tstruct list_head list;\n\tstruct smack_known *smk_subject;\n\tstruct smack_known *smk_object;\n\tint smk_access;\n};\n\nstruct smk_net4addr {\n\tstruct list_head list;\n\tstruct in_addr smk_host;\n\tstruct in_addr smk_mask;\n\tint smk_masks;\n\tstruct smack_known *smk_label;\n};\n\nstruct smk_net6addr {\n\tstruct list_head list;\n\tstruct in6_addr smk_host;\n\tstruct in6_addr smk_mask;\n\tint smk_masks;\n\tstruct smack_known *smk_label;\n};\n\nstruct smack_known_list_elem {\n\tstruct list_head list;\n\tstruct smack_known *smk_label;\n};\n\nenum {\n\tOpt_error___2 = 4294967295,\n\tOpt_fsdefault = 0,\n\tOpt_fsfloor = 1,\n\tOpt_fshat = 2,\n\tOpt_fsroot = 3,\n\tOpt_fstransmute = 4,\n};\n\nstruct smk_audit_info {\n\tstruct common_audit_data a;\n\tstruct smack_audit_data sad;\n};\n\nstruct smack_mnt_opts {\n\tconst char *fsdefault;\n\tconst char *fsfloor;\n\tconst char *fshat;\n\tconst char *fsroot;\n\tconst char *fstransmute;\n};\n\nstruct netlbl_audit {\n\tu32 secid;\n\tkuid_t loginuid;\n\tunsigned int sessionid;\n};\n\nstruct cipso_v4_std_map_tbl {\n\tstruct {\n\t\tu32 *cipso;\n\t\tu32 *local;\n\t\tu32 cipso_size;\n\t\tu32 local_size;\n\t} lvl;\n\tstruct {\n\t\tu32 *cipso;\n\t\tu32 *local;\n\t\tu32 cipso_size;\n\t\tu32 local_size;\n\t} cat;\n};\n\nstruct cipso_v4_doi {\n\tu32 doi;\n\tu32 type;\n\tunion {\n\t\tstruct cipso_v4_std_map_tbl *std;\n\t} map;\n\tu8 tags[5];\n\trefcount_t refcount;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nenum smk_inos {\n\tSMK_ROOT_INO = 2,\n\tSMK_LOAD = 3,\n\tSMK_CIPSO = 4,\n\tSMK_DOI = 5,\n\tSMK_DIRECT = 6,\n\tSMK_AMBIENT = 7,\n\tSMK_NET4ADDR = 8,\n\tSMK_ONLYCAP = 9,\n\tSMK_LOGGING = 10,\n\tSMK_LOAD_SELF = 11,\n\tSMK_ACCESSES = 12,\n\tSMK_MAPPED = 13,\n\tSMK_LOAD2 = 14,\n\tSMK_LOAD_SELF2 = 15,\n\tSMK_ACCESS2 = 16,\n\tSMK_CIPSO2 = 17,\n\tSMK_REVOKE_SUBJ = 18,\n\tSMK_CHANGE_RULE = 19,\n\tSMK_SYSLOG = 20,\n\tSMK_PTRACE = 21,\n\tSMK_UNCONFINED = 22,\n\tSMK_NET6ADDR = 23,\n\tSMK_RELABEL_SELF = 24,\n};\n\nstruct smack_parsed_rule {\n\tstruct smack_known *smk_subject;\n\tstruct smack_known *smk_object;\n\tint smk_access1;\n\tint smk_access2;\n};\n\nstruct sockaddr_un {\n\t__kernel_sa_family_t sun_family;\n\tchar sun_path[108];\n};\n\nstruct unix_address {\n\trefcount_t refcnt;\n\tint len;\n\tunsigned int hash;\n\tstruct sockaddr_un name[0];\n};\n\nstruct scm_stat {\n\tatomic_t nr_fds;\n};\n\nstruct unix_sock {\n\tstruct sock sk;\n\tstruct unix_address *addr;\n\tstruct path path;\n\tstruct mutex iolock;\n\tstruct mutex bindlock;\n\tstruct sock *peer;\n\tstruct list_head link;\n\tatomic_long_t inflight;\n\tspinlock_t lock;\n\tlong unsigned int gc_flags;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct socket_wq peer_wq;\n\twait_queue_entry_t peer_wake;\n\tstruct scm_stat scm_stat;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n};\n\nenum tomoyo_conditions_index {\n\tTOMOYO_TASK_UID = 0,\n\tTOMOYO_TASK_EUID = 1,\n\tTOMOYO_TASK_SUID = 2,\n\tTOMOYO_TASK_FSUID = 3,\n\tTOMOYO_TASK_GID = 4,\n\tTOMOYO_TASK_EGID = 5,\n\tTOMOYO_TASK_SGID = 6,\n\tTOMOYO_TASK_FSGID = 7,\n\tTOMOYO_TASK_PID = 8,\n\tTOMOYO_TASK_PPID = 9,\n\tTOMOYO_EXEC_ARGC = 10,\n\tTOMOYO_EXEC_ENVC = 11,\n\tTOMOYO_TYPE_IS_SOCKET = 12,\n\tTOMOYO_TYPE_IS_SYMLINK = 13,\n\tTOMOYO_TYPE_IS_FILE = 14,\n\tTOMOYO_TYPE_IS_BLOCK_DEV = 15,\n\tTOMOYO_TYPE_IS_DIRECTORY = 16,\n\tTOMOYO_TYPE_IS_CHAR_DEV = 17,\n\tTOMOYO_TYPE_IS_FIFO = 18,\n\tTOMOYO_MODE_SETUID = 19,\n\tTOMOYO_MODE_SETGID = 20,\n\tTOMOYO_MODE_STICKY = 21,\n\tTOMOYO_MODE_OWNER_READ = 22,\n\tTOMOYO_MODE_OWNER_WRITE = 23,\n\tTOMOYO_MODE_OWNER_EXECUTE = 24,\n\tTOMOYO_MODE_GROUP_READ = 25,\n\tTOMOYO_MODE_GROUP_WRITE = 26,\n\tTOMOYO_MODE_GROUP_EXECUTE = 27,\n\tTOMOYO_MODE_OTHERS_READ = 28,\n\tTOMOYO_MODE_OTHERS_WRITE = 29,\n\tTOMOYO_MODE_OTHERS_EXECUTE = 30,\n\tTOMOYO_EXEC_REALPATH = 31,\n\tTOMOYO_SYMLINK_TARGET = 32,\n\tTOMOYO_PATH1_UID = 33,\n\tTOMOYO_PATH1_GID = 34,\n\tTOMOYO_PATH1_INO = 35,\n\tTOMOYO_PATH1_MAJOR = 36,\n\tTOMOYO_PATH1_MINOR = 37,\n\tTOMOYO_PATH1_PERM = 38,\n\tTOMOYO_PATH1_TYPE = 39,\n\tTOMOYO_PATH1_DEV_MAJOR = 40,\n\tTOMOYO_PATH1_DEV_MINOR = 41,\n\tTOMOYO_PATH2_UID = 42,\n\tTOMOYO_PATH2_GID = 43,\n\tTOMOYO_PATH2_INO = 44,\n\tTOMOYO_PATH2_MAJOR = 45,\n\tTOMOYO_PATH2_MINOR = 46,\n\tTOMOYO_PATH2_PERM = 47,\n\tTOMOYO_PATH2_TYPE = 48,\n\tTOMOYO_PATH2_DEV_MAJOR = 49,\n\tTOMOYO_PATH2_DEV_MINOR = 50,\n\tTOMOYO_PATH1_PARENT_UID = 51,\n\tTOMOYO_PATH1_PARENT_GID = 52,\n\tTOMOYO_PATH1_PARENT_INO = 53,\n\tTOMOYO_PATH1_PARENT_PERM = 54,\n\tTOMOYO_PATH2_PARENT_UID = 55,\n\tTOMOYO_PATH2_PARENT_GID = 56,\n\tTOMOYO_PATH2_PARENT_INO = 57,\n\tTOMOYO_PATH2_PARENT_PERM = 58,\n\tTOMOYO_MAX_CONDITION_KEYWORD = 59,\n\tTOMOYO_NUMBER_UNION = 60,\n\tTOMOYO_NAME_UNION = 61,\n\tTOMOYO_ARGV_ENTRY = 62,\n\tTOMOYO_ENVP_ENTRY = 63,\n};\n\nenum tomoyo_path_stat_index {\n\tTOMOYO_PATH1 = 0,\n\tTOMOYO_PATH1_PARENT = 1,\n\tTOMOYO_PATH2 = 2,\n\tTOMOYO_PATH2_PARENT = 3,\n\tTOMOYO_MAX_PATH_STAT = 4,\n};\n\nenum tomoyo_mode_index {\n\tTOMOYO_CONFIG_DISABLED = 0,\n\tTOMOYO_CONFIG_LEARNING = 1,\n\tTOMOYO_CONFIG_PERMISSIVE = 2,\n\tTOMOYO_CONFIG_ENFORCING = 3,\n\tTOMOYO_CONFIG_MAX_MODE = 4,\n\tTOMOYO_CONFIG_WANT_REJECT_LOG = 64,\n\tTOMOYO_CONFIG_WANT_GRANT_LOG = 128,\n\tTOMOYO_CONFIG_USE_DEFAULT = 255,\n};\n\nenum tomoyo_policy_id {\n\tTOMOYO_ID_GROUP = 0,\n\tTOMOYO_ID_ADDRESS_GROUP = 1,\n\tTOMOYO_ID_PATH_GROUP = 2,\n\tTOMOYO_ID_NUMBER_GROUP = 3,\n\tTOMOYO_ID_TRANSITION_CONTROL = 4,\n\tTOMOYO_ID_AGGREGATOR = 5,\n\tTOMOYO_ID_MANAGER = 6,\n\tTOMOYO_ID_CONDITION = 7,\n\tTOMOYO_ID_NAME = 8,\n\tTOMOYO_ID_ACL = 9,\n\tTOMOYO_ID_DOMAIN = 10,\n\tTOMOYO_MAX_POLICY = 11,\n};\n\nenum tomoyo_domain_info_flags_index {\n\tTOMOYO_DIF_QUOTA_WARNED = 0,\n\tTOMOYO_DIF_TRANSITION_FAILED = 1,\n\tTOMOYO_MAX_DOMAIN_INFO_FLAGS = 2,\n};\n\nenum tomoyo_grant_log {\n\tTOMOYO_GRANTLOG_AUTO = 0,\n\tTOMOYO_GRANTLOG_NO = 1,\n\tTOMOYO_GRANTLOG_YES = 2,\n};\n\nenum tomoyo_group_id {\n\tTOMOYO_PATH_GROUP = 0,\n\tTOMOYO_NUMBER_GROUP = 1,\n\tTOMOYO_ADDRESS_GROUP = 2,\n\tTOMOYO_MAX_GROUP = 3,\n};\n\nenum tomoyo_path_acl_index {\n\tTOMOYO_TYPE_EXECUTE = 0,\n\tTOMOYO_TYPE_READ = 1,\n\tTOMOYO_TYPE_WRITE = 2,\n\tTOMOYO_TYPE_APPEND = 3,\n\tTOMOYO_TYPE_UNLINK = 4,\n\tTOMOYO_TYPE_GETATTR = 5,\n\tTOMOYO_TYPE_RMDIR = 6,\n\tTOMOYO_TYPE_TRUNCATE = 7,\n\tTOMOYO_TYPE_SYMLINK = 8,\n\tTOMOYO_TYPE_CHROOT = 9,\n\tTOMOYO_TYPE_UMOUNT = 10,\n\tTOMOYO_MAX_PATH_OPERATION = 11,\n};\n\nenum tomoyo_memory_stat_type {\n\tTOMOYO_MEMORY_POLICY = 0,\n\tTOMOYO_MEMORY_AUDIT = 1,\n\tTOMOYO_MEMORY_QUERY = 2,\n\tTOMOYO_MAX_MEMORY_STAT = 3,\n};\n\nenum tomoyo_mkdev_acl_index {\n\tTOMOYO_TYPE_MKBLOCK = 0,\n\tTOMOYO_TYPE_MKCHAR = 1,\n\tTOMOYO_MAX_MKDEV_OPERATION = 2,\n};\n\nenum tomoyo_network_acl_index {\n\tTOMOYO_NETWORK_BIND = 0,\n\tTOMOYO_NETWORK_LISTEN = 1,\n\tTOMOYO_NETWORK_CONNECT = 2,\n\tTOMOYO_NETWORK_SEND = 3,\n\tTOMOYO_MAX_NETWORK_OPERATION = 4,\n};\n\nenum tomoyo_path2_acl_index {\n\tTOMOYO_TYPE_LINK = 0,\n\tTOMOYO_TYPE_RENAME = 1,\n\tTOMOYO_TYPE_PIVOT_ROOT = 2,\n\tTOMOYO_MAX_PATH2_OPERATION = 3,\n};\n\nenum tomoyo_path_number_acl_index {\n\tTOMOYO_TYPE_CREATE = 0,\n\tTOMOYO_TYPE_MKDIR = 1,\n\tTOMOYO_TYPE_MKFIFO = 2,\n\tTOMOYO_TYPE_MKSOCK = 3,\n\tTOMOYO_TYPE_IOCTL = 4,\n\tTOMOYO_TYPE_CHMOD = 5,\n\tTOMOYO_TYPE_CHOWN = 6,\n\tTOMOYO_TYPE_CHGRP = 7,\n\tTOMOYO_MAX_PATH_NUMBER_OPERATION = 8,\n};\n\nenum tomoyo_securityfs_interface_index {\n\tTOMOYO_DOMAINPOLICY = 0,\n\tTOMOYO_EXCEPTIONPOLICY = 1,\n\tTOMOYO_PROCESS_STATUS = 2,\n\tTOMOYO_STAT = 3,\n\tTOMOYO_AUDIT = 4,\n\tTOMOYO_VERSION = 5,\n\tTOMOYO_PROFILE = 6,\n\tTOMOYO_QUERY = 7,\n\tTOMOYO_MANAGER = 8,\n};\n\nenum tomoyo_mac_index {\n\tTOMOYO_MAC_FILE_EXECUTE = 0,\n\tTOMOYO_MAC_FILE_OPEN = 1,\n\tTOMOYO_MAC_FILE_CREATE = 2,\n\tTOMOYO_MAC_FILE_UNLINK = 3,\n\tTOMOYO_MAC_FILE_GETATTR = 4,\n\tTOMOYO_MAC_FILE_MKDIR = 5,\n\tTOMOYO_MAC_FILE_RMDIR = 6,\n\tTOMOYO_MAC_FILE_MKFIFO = 7,\n\tTOMOYO_MAC_FILE_MKSOCK = 8,\n\tTOMOYO_MAC_FILE_TRUNCATE = 9,\n\tTOMOYO_MAC_FILE_SYMLINK = 10,\n\tTOMOYO_MAC_FILE_MKBLOCK = 11,\n\tTOMOYO_MAC_FILE_MKCHAR = 12,\n\tTOMOYO_MAC_FILE_LINK = 13,\n\tTOMOYO_MAC_FILE_RENAME = 14,\n\tTOMOYO_MAC_FILE_CHMOD = 15,\n\tTOMOYO_MAC_FILE_CHOWN = 16,\n\tTOMOYO_MAC_FILE_CHGRP = 17,\n\tTOMOYO_MAC_FILE_IOCTL = 18,\n\tTOMOYO_MAC_FILE_CHROOT = 19,\n\tTOMOYO_MAC_FILE_MOUNT = 20,\n\tTOMOYO_MAC_FILE_UMOUNT = 21,\n\tTOMOYO_MAC_FILE_PIVOT_ROOT = 22,\n\tTOMOYO_MAC_NETWORK_INET_STREAM_BIND = 23,\n\tTOMOYO_MAC_NETWORK_INET_STREAM_LISTEN = 24,\n\tTOMOYO_MAC_NETWORK_INET_STREAM_CONNECT = 25,\n\tTOMOYO_MAC_NETWORK_INET_DGRAM_BIND = 26,\n\tTOMOYO_MAC_NETWORK_INET_DGRAM_SEND = 27,\n\tTOMOYO_MAC_NETWORK_INET_RAW_BIND = 28,\n\tTOMOYO_MAC_NETWORK_INET_RAW_SEND = 29,\n\tTOMOYO_MAC_NETWORK_UNIX_STREAM_BIND = 30,\n\tTOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN = 31,\n\tTOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT = 32,\n\tTOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND = 33,\n\tTOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND = 34,\n\tTOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND = 35,\n\tTOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN = 36,\n\tTOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT = 37,\n\tTOMOYO_MAC_ENVIRON = 38,\n\tTOMOYO_MAX_MAC_INDEX = 39,\n};\n\nenum tomoyo_mac_category_index {\n\tTOMOYO_MAC_CATEGORY_FILE = 0,\n\tTOMOYO_MAC_CATEGORY_NETWORK = 1,\n\tTOMOYO_MAC_CATEGORY_MISC = 2,\n\tTOMOYO_MAX_MAC_CATEGORY_INDEX = 3,\n};\n\nenum tomoyo_pref_index {\n\tTOMOYO_PREF_MAX_AUDIT_LOG = 0,\n\tTOMOYO_PREF_MAX_LEARNING_ENTRY = 1,\n\tTOMOYO_MAX_PREF = 2,\n};\n\nstruct tomoyo_shared_acl_head {\n\tstruct list_head list;\n\tatomic_t users;\n} __attribute__((packed));\n\nstruct tomoyo_path_info {\n\tconst char *name;\n\tu32 hash;\n\tu16 const_len;\n\tbool is_dir;\n\tbool is_patterned;\n};\n\nstruct tomoyo_obj_info;\n\nstruct tomoyo_execve;\n\nstruct tomoyo_domain_info;\n\nstruct tomoyo_acl_info;\n\nstruct tomoyo_request_info {\n\tstruct tomoyo_obj_info *obj;\n\tstruct tomoyo_execve *ee;\n\tstruct tomoyo_domain_info *domain;\n\tunion {\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *filename;\n\t\t\tconst struct tomoyo_path_info *matched_path;\n\t\t\tu8 operation;\n\t\t} path;\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *filename1;\n\t\t\tconst struct tomoyo_path_info *filename2;\n\t\t\tu8 operation;\n\t\t} path2;\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *filename;\n\t\t\tunsigned int mode;\n\t\t\tunsigned int major;\n\t\t\tunsigned int minor;\n\t\t\tu8 operation;\n\t\t} mkdev;\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *filename;\n\t\t\tlong unsigned int number;\n\t\t\tu8 operation;\n\t\t} path_number;\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *name;\n\t\t} environ;\n\t\tstruct {\n\t\t\tconst __be32 *address;\n\t\t\tu16 port;\n\t\t\tu8 protocol;\n\t\t\tu8 operation;\n\t\t\tbool is_ipv6;\n\t\t} inet_network;\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *address;\n\t\t\tu8 protocol;\n\t\t\tu8 operation;\n\t\t} unix_network;\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *type;\n\t\t\tconst struct tomoyo_path_info *dir;\n\t\t\tconst struct tomoyo_path_info *dev;\n\t\t\tlong unsigned int flags;\n\t\t\tint need_dev;\n\t\t} mount;\n\t\tstruct {\n\t\t\tconst struct tomoyo_path_info *domainname;\n\t\t} task;\n\t} param;\n\tstruct tomoyo_acl_info *matched_acl;\n\tu8 param_type;\n\tbool granted;\n\tu8 retry;\n\tu8 profile;\n\tu8 mode;\n\tu8 type;\n};\n\nstruct tomoyo_mini_stat {\n\tkuid_t uid;\n\tkgid_t gid;\n\tino_t ino;\n\tumode_t mode;\n\tdev_t dev;\n\tdev_t rdev;\n};\n\nstruct tomoyo_obj_info {\n\tbool validate_done;\n\tbool stat_valid[4];\n\tstruct path path1;\n\tstruct path path2;\n\tstruct tomoyo_mini_stat stat[4];\n\tstruct tomoyo_path_info *symlink_target;\n};\n\nstruct tomoyo_page_dump {\n\tstruct page *page;\n\tchar *data;\n};\n\nstruct tomoyo_execve {\n\tstruct tomoyo_request_info r;\n\tstruct tomoyo_obj_info obj;\n\tstruct linux_binprm *bprm;\n\tconst struct tomoyo_path_info *transition;\n\tstruct tomoyo_page_dump dump;\n\tchar *tmp;\n};\n\nstruct tomoyo_policy_namespace;\n\nstruct tomoyo_domain_info {\n\tstruct list_head list;\n\tstruct list_head acl_info_list;\n\tconst struct tomoyo_path_info *domainname;\n\tstruct tomoyo_policy_namespace *ns;\n\tlong unsigned int group[4];\n\tu8 profile;\n\tbool is_deleted;\n\tbool flags[2];\n\tatomic_t users;\n};\n\nstruct tomoyo_condition;\n\nstruct tomoyo_acl_info {\n\tstruct list_head list;\n\tstruct tomoyo_condition *cond;\n\ts8 is_deleted;\n\tu8 type;\n} __attribute__((packed));\n\nstruct tomoyo_condition {\n\tstruct tomoyo_shared_acl_head head;\n\tu32 size;\n\tu16 condc;\n\tu16 numbers_count;\n\tu16 names_count;\n\tu16 argc;\n\tu16 envc;\n\tu8 grant_log;\n\tconst struct tomoyo_path_info *transit;\n};\n\nstruct tomoyo_profile;\n\nstruct tomoyo_policy_namespace {\n\tstruct tomoyo_profile *profile_ptr[256];\n\tstruct list_head group_list[3];\n\tstruct list_head policy_list[11];\n\tstruct list_head acl_group[256];\n\tstruct list_head namespace_list;\n\tunsigned int profile_version;\n\tconst char *name;\n};\n\nstruct tomoyo_io_buffer {\n\tvoid (*read)(struct tomoyo_io_buffer *);\n\tint (*write)(struct tomoyo_io_buffer *);\n\t__poll_t (*poll)(struct file *, poll_table *);\n\tstruct mutex io_sem;\n\tchar *read_user_buf;\n\tsize_t read_user_buf_avail;\n\tstruct {\n\t\tstruct list_head *ns;\n\t\tstruct list_head *domain;\n\t\tstruct list_head *group;\n\t\tstruct list_head *acl;\n\t\tsize_t avail;\n\t\tunsigned int step;\n\t\tunsigned int query_index;\n\t\tu16 index;\n\t\tu16 cond_index;\n\t\tu8 acl_group_index;\n\t\tu8 cond_step;\n\t\tu8 bit;\n\t\tu8 w_pos;\n\t\tbool eof;\n\t\tbool print_this_domain_only;\n\t\tbool print_transition_related_only;\n\t\tbool print_cond_part;\n\t\tconst char *w[64];\n\t} r;\n\tstruct {\n\t\tstruct tomoyo_policy_namespace *ns;\n\t\tstruct tomoyo_domain_info *domain;\n\t\tsize_t avail;\n\t\tbool is_delete;\n\t} w;\n\tchar *read_buf;\n\tsize_t readbuf_size;\n\tchar *write_buf;\n\tsize_t writebuf_size;\n\tenum tomoyo_securityfs_interface_index type;\n\tu8 users;\n\tstruct list_head list;\n};\n\nstruct tomoyo_preference {\n\tunsigned int learning_max_entry;\n\tbool enforcing_verbose;\n\tbool learning_verbose;\n\tbool permissive_verbose;\n};\n\nstruct tomoyo_profile {\n\tconst struct tomoyo_path_info *comment;\n\tstruct tomoyo_preference *learning;\n\tstruct tomoyo_preference *permissive;\n\tstruct tomoyo_preference *enforcing;\n\tstruct tomoyo_preference preference;\n\tu8 default_config;\n\tu8 config[42];\n\tunsigned int pref[2];\n};\n\nstruct tomoyo_time {\n\tu16 year;\n\tu8 month;\n\tu8 day;\n\tu8 hour;\n\tu8 min;\n\tu8 sec;\n};\n\nstruct tomoyo_log {\n\tstruct list_head list;\n\tchar *log;\n\tint size;\n};\n\nenum tomoyo_value_type {\n\tTOMOYO_VALUE_TYPE_INVALID = 0,\n\tTOMOYO_VALUE_TYPE_DECIMAL = 1,\n\tTOMOYO_VALUE_TYPE_OCTAL = 2,\n\tTOMOYO_VALUE_TYPE_HEXADECIMAL = 3,\n};\n\nenum tomoyo_transition_type {\n\tTOMOYO_TRANSITION_CONTROL_NO_RESET = 0,\n\tTOMOYO_TRANSITION_CONTROL_RESET = 1,\n\tTOMOYO_TRANSITION_CONTROL_NO_INITIALIZE = 2,\n\tTOMOYO_TRANSITION_CONTROL_INITIALIZE = 3,\n\tTOMOYO_TRANSITION_CONTROL_NO_KEEP = 4,\n\tTOMOYO_TRANSITION_CONTROL_KEEP = 5,\n\tTOMOYO_MAX_TRANSITION_TYPE = 6,\n};\n\nenum tomoyo_acl_entry_type_index {\n\tTOMOYO_TYPE_PATH_ACL = 0,\n\tTOMOYO_TYPE_PATH2_ACL = 1,\n\tTOMOYO_TYPE_PATH_NUMBER_ACL = 2,\n\tTOMOYO_TYPE_MKDEV_ACL = 3,\n\tTOMOYO_TYPE_MOUNT_ACL = 4,\n\tTOMOYO_TYPE_INET_ACL = 5,\n\tTOMOYO_TYPE_UNIX_ACL = 6,\n\tTOMOYO_TYPE_ENV_ACL = 7,\n\tTOMOYO_TYPE_MANUAL_TASK_ACL = 8,\n};\n\nenum tomoyo_policy_stat_type {\n\tTOMOYO_STAT_POLICY_UPDATES = 0,\n\tTOMOYO_STAT_POLICY_LEARNING = 1,\n\tTOMOYO_STAT_POLICY_PERMISSIVE = 2,\n\tTOMOYO_STAT_POLICY_ENFORCING = 3,\n\tTOMOYO_MAX_POLICY_STAT = 4,\n};\n\nstruct tomoyo_acl_head {\n\tstruct list_head list;\n\ts8 is_deleted;\n} __attribute__((packed));\n\nstruct tomoyo_name {\n\tstruct tomoyo_shared_acl_head head;\n\tstruct tomoyo_path_info entry;\n};\n\nstruct tomoyo_group;\n\nstruct tomoyo_name_union {\n\tconst struct tomoyo_path_info *filename;\n\tstruct tomoyo_group *group;\n};\n\nstruct tomoyo_group {\n\tstruct tomoyo_shared_acl_head head;\n\tconst struct tomoyo_path_info *group_name;\n\tstruct list_head member_list;\n};\n\nstruct tomoyo_number_union {\n\tlong unsigned int values[2];\n\tstruct tomoyo_group *group;\n\tu8 value_type[2];\n};\n\nstruct tomoyo_ipaddr_union {\n\tstruct in6_addr ip[2];\n\tstruct tomoyo_group *group;\n\tbool is_ipv6;\n};\n\nstruct tomoyo_path_group {\n\tstruct tomoyo_acl_head head;\n\tconst struct tomoyo_path_info *member_name;\n};\n\nstruct tomoyo_number_group {\n\tstruct tomoyo_acl_head head;\n\tstruct tomoyo_number_union number;\n};\n\nstruct tomoyo_address_group {\n\tstruct tomoyo_acl_head head;\n\tstruct tomoyo_ipaddr_union address;\n};\n\nstruct tomoyo_argv {\n\tlong unsigned int index;\n\tconst struct tomoyo_path_info *value;\n\tbool is_not;\n};\n\nstruct tomoyo_envp {\n\tconst struct tomoyo_path_info *name;\n\tconst struct tomoyo_path_info *value;\n\tbool is_not;\n};\n\nstruct tomoyo_condition_element {\n\tu8 left;\n\tu8 right;\n\tbool equals;\n};\n\nstruct tomoyo_task_acl {\n\tstruct tomoyo_acl_info head;\n\tconst struct tomoyo_path_info *domainname;\n};\n\nstruct tomoyo_path_acl {\n\tstruct tomoyo_acl_info head;\n\tu16 perm;\n\tstruct tomoyo_name_union name;\n};\n\nstruct tomoyo_path_number_acl {\n\tstruct tomoyo_acl_info head;\n\tu8 perm;\n\tstruct tomoyo_name_union name;\n\tstruct tomoyo_number_union number;\n};\n\nstruct tomoyo_mkdev_acl {\n\tstruct tomoyo_acl_info head;\n\tu8 perm;\n\tstruct tomoyo_name_union name;\n\tstruct tomoyo_number_union mode;\n\tstruct tomoyo_number_union major;\n\tstruct tomoyo_number_union minor;\n};\n\nstruct tomoyo_path2_acl {\n\tstruct tomoyo_acl_info head;\n\tu8 perm;\n\tstruct tomoyo_name_union name1;\n\tstruct tomoyo_name_union name2;\n};\n\nstruct tomoyo_mount_acl {\n\tstruct tomoyo_acl_info head;\n\tstruct tomoyo_name_union dev_name;\n\tstruct tomoyo_name_union dir_name;\n\tstruct tomoyo_name_union fs_type;\n\tstruct tomoyo_number_union flags;\n};\n\nstruct tomoyo_env_acl {\n\tstruct tomoyo_acl_info head;\n\tconst struct tomoyo_path_info *env;\n};\n\nstruct tomoyo_inet_acl {\n\tstruct tomoyo_acl_info head;\n\tu8 protocol;\n\tu8 perm;\n\tstruct tomoyo_ipaddr_union address;\n\tstruct tomoyo_number_union port;\n};\n\nstruct tomoyo_unix_acl {\n\tstruct tomoyo_acl_info head;\n\tu8 protocol;\n\tu8 perm;\n\tstruct tomoyo_name_union name;\n};\n\nstruct tomoyo_acl_param {\n\tchar *data;\n\tstruct list_head *list;\n\tstruct tomoyo_policy_namespace *ns;\n\tbool is_delete;\n};\n\nstruct tomoyo_transition_control {\n\tstruct tomoyo_acl_head head;\n\tu8 type;\n\tbool is_last_name;\n\tconst struct tomoyo_path_info *domainname;\n\tconst struct tomoyo_path_info *program;\n};\n\nstruct tomoyo_aggregator {\n\tstruct tomoyo_acl_head head;\n\tconst struct tomoyo_path_info *original_name;\n\tconst struct tomoyo_path_info *aggregated_name;\n};\n\nstruct tomoyo_manager {\n\tstruct tomoyo_acl_head head;\n\tconst struct tomoyo_path_info *manager;\n};\n\nstruct tomoyo_task {\n\tstruct tomoyo_domain_info *domain_info;\n\tstruct tomoyo_domain_info *old_domain_info;\n};\n\nstruct tomoyo_query {\n\tstruct list_head list;\n\tstruct tomoyo_domain_info *domain;\n\tchar *query;\n\tsize_t query_len;\n\tunsigned int serial;\n\tu8 timer;\n\tu8 answer;\n\tu8 retry;\n};\n\nenum tomoyo_special_mount {\n\tTOMOYO_MOUNT_BIND = 0,\n\tTOMOYO_MOUNT_MOVE = 1,\n\tTOMOYO_MOUNT_REMOUNT = 2,\n\tTOMOYO_MOUNT_MAKE_UNBINDABLE = 3,\n\tTOMOYO_MOUNT_MAKE_PRIVATE = 4,\n\tTOMOYO_MOUNT_MAKE_SLAVE = 5,\n\tTOMOYO_MOUNT_MAKE_SHARED = 6,\n\tTOMOYO_MAX_SPECIAL_MOUNT = 7,\n};\n\nstruct tomoyo_inet_addr_info {\n\t__be16 port;\n\tconst __be32 *address;\n\tbool is_ipv6;\n};\n\nstruct tomoyo_unix_addr_info {\n\tu8 *addr;\n\tunsigned int addr_len;\n};\n\nstruct tomoyo_addr_info {\n\tu8 protocol;\n\tu8 operation;\n\tstruct tomoyo_inet_addr_info inet;\n\tstruct tomoyo_unix_addr_info unix0;\n};\n\ntypedef unsigned char Byte;\n\ntypedef long unsigned int uLong;\n\nstruct internal_state;\n\nstruct z_stream_s {\n\tconst Byte *next_in;\n\tuLong avail_in;\n\tuLong total_in;\n\tByte *next_out;\n\tuLong avail_out;\n\tuLong total_out;\n\tchar *msg;\n\tstruct internal_state *state;\n\tvoid *workspace;\n\tint data_type;\n\tuLong adler;\n\tuLong reserved;\n};\n\nstruct internal_state {\n\tint dummy;\n};\n\ntypedef struct z_stream_s z_stream;\n\ntypedef z_stream *z_streamp;\n\nenum audit_mode {\n\tAUDIT_NORMAL = 0,\n\tAUDIT_QUIET_DENIED = 1,\n\tAUDIT_QUIET = 2,\n\tAUDIT_NOQUIET = 3,\n\tAUDIT_ALL = 4,\n};\n\nenum aa_sfs_type {\n\tAA_SFS_TYPE_BOOLEAN = 0,\n\tAA_SFS_TYPE_STRING = 1,\n\tAA_SFS_TYPE_U64 = 2,\n\tAA_SFS_TYPE_FOPS = 3,\n\tAA_SFS_TYPE_DIR = 4,\n};\n\nstruct aa_sfs_entry {\n\tconst char *name;\n\tstruct dentry *dentry;\n\tumode_t mode;\n\tenum aa_sfs_type v_type;\n\tunion {\n\t\tbool boolean;\n\t\tchar *string;\n\t\tlong unsigned int u64;\n\t\tstruct aa_sfs_entry *files;\n\t} v;\n\tconst struct file_operations *file_ops;\n};\n\nenum aafs_ns_type {\n\tAAFS_NS_DIR = 0,\n\tAAFS_NS_PROFS = 1,\n\tAAFS_NS_NS = 2,\n\tAAFS_NS_RAW_DATA = 3,\n\tAAFS_NS_LOAD = 4,\n\tAAFS_NS_REPLACE = 5,\n\tAAFS_NS_REMOVE = 6,\n\tAAFS_NS_REVISION = 7,\n\tAAFS_NS_COUNT = 8,\n\tAAFS_NS_MAX_COUNT = 9,\n\tAAFS_NS_SIZE = 10,\n\tAAFS_NS_MAX_SIZE = 11,\n\tAAFS_NS_OWNER = 12,\n\tAAFS_NS_SIZEOF = 13,\n};\n\nenum aafs_prof_type {\n\tAAFS_PROF_DIR = 0,\n\tAAFS_PROF_PROFS = 1,\n\tAAFS_PROF_NAME = 2,\n\tAAFS_PROF_MODE = 3,\n\tAAFS_PROF_ATTACH = 4,\n\tAAFS_PROF_HASH = 5,\n\tAAFS_PROF_RAW_DATA = 6,\n\tAAFS_PROF_RAW_HASH = 7,\n\tAAFS_PROF_RAW_ABI = 8,\n\tAAFS_PROF_SIZEOF = 9,\n};\n\nstruct table_header {\n\tu16 td_id;\n\tu16 td_flags;\n\tu32 td_hilen;\n\tu32 td_lolen;\n\tchar td_data[0];\n};\n\nstruct aa_dfa {\n\tstruct kref count;\n\tu16 flags;\n\tu32 max_oob;\n\tstruct table_header *tables[8];\n};\n\nstruct aa_policy {\n\tconst char *name;\n\tchar *hname;\n\tstruct list_head list;\n\tstruct list_head profiles;\n};\n\nstruct aa_labelset {\n\trwlock_t lock;\n\tstruct rb_root root;\n};\n\nenum label_flags {\n\tFLAG_HAT = 1,\n\tFLAG_UNCONFINED = 2,\n\tFLAG_NULL = 4,\n\tFLAG_IX_ON_NAME_ERROR = 8,\n\tFLAG_IMMUTIBLE = 16,\n\tFLAG_USER_DEFINED = 32,\n\tFLAG_NO_LIST_REF = 64,\n\tFLAG_NS_COUNT = 128,\n\tFLAG_IN_TREE = 256,\n\tFLAG_PROFILE = 512,\n\tFLAG_EXPLICIT = 1024,\n\tFLAG_STALE = 2048,\n\tFLAG_RENAMED = 4096,\n\tFLAG_REVOKED = 8192,\n};\n\nstruct aa_label;\n\nstruct aa_proxy {\n\tstruct kref count;\n\tstruct aa_label *label;\n};\n\nstruct aa_profile;\n\nstruct aa_label {\n\tstruct kref count;\n\tstruct rb_node node;\n\tstruct callback_head rcu;\n\tstruct aa_proxy *proxy;\n\tchar *hname;\n\tlong int flags;\n\tu32 secid;\n\tint size;\n\tstruct aa_profile *vec[0];\n};\n\nstruct label_it {\n\tint i;\n\tint j;\n};\n\nstruct aa_policydb {\n\tstruct aa_dfa *dfa;\n\tunsigned int start[17];\n};\n\nstruct aa_domain {\n\tint size;\n\tchar **table;\n};\n\nstruct aa_file_rules {\n\tunsigned int start;\n\tstruct aa_dfa *dfa;\n\tstruct aa_domain trans;\n};\n\nstruct aa_caps {\n\tkernel_cap_t allow;\n\tkernel_cap_t audit;\n\tkernel_cap_t denied;\n\tkernel_cap_t quiet;\n\tkernel_cap_t kill;\n\tkernel_cap_t extended;\n};\n\nstruct aa_rlimit {\n\tunsigned int mask;\n\tstruct rlimit limits[16];\n};\n\nstruct aa_ns;\n\nstruct aa_secmark;\n\nstruct aa_loaddata;\n\nstruct aa_profile {\n\tstruct aa_policy base;\n\tstruct aa_profile *parent;\n\tstruct aa_ns *ns;\n\tconst char *rename;\n\tconst char *attach;\n\tstruct aa_dfa *xmatch;\n\tint xmatch_len;\n\tenum audit_mode audit;\n\tlong int mode;\n\tu32 path_flags;\n\tconst char *disconnected;\n\tint size;\n\tstruct aa_policydb policy;\n\tstruct aa_file_rules file;\n\tstruct aa_caps caps;\n\tint xattr_count;\n\tchar **xattrs;\n\tstruct aa_rlimit rlimits;\n\tint secmark_count;\n\tstruct aa_secmark *secmark;\n\tstruct aa_loaddata *rawdata;\n\tunsigned char *hash;\n\tchar *dirname;\n\tstruct dentry *dents[9];\n\tstruct rhashtable *data;\n\tstruct aa_label label;\n};\n\nstruct aa_perms {\n\tu32 allow;\n\tu32 audit;\n\tu32 deny;\n\tu32 quiet;\n\tu32 kill;\n\tu32 stop;\n\tu32 complain;\n\tu32 cond;\n\tu32 hide;\n\tu32 prompt;\n\tu16 xindex;\n};\n\nstruct path_cond {\n\tkuid_t uid;\n\tumode_t mode;\n};\n\nstruct aa_secmark {\n\tu8 audit;\n\tu8 deny;\n\tu32 secid;\n\tchar *label;\n};\n\nenum profile_mode {\n\tAPPARMOR_ENFORCE = 0,\n\tAPPARMOR_COMPLAIN = 1,\n\tAPPARMOR_KILL = 2,\n\tAPPARMOR_UNCONFINED = 3,\n};\n\nstruct aa_data {\n\tchar *key;\n\tu32 size;\n\tchar *data;\n\tstruct rhash_head head;\n};\n\nstruct aa_ns_acct {\n\tint max_size;\n\tint max_count;\n\tint size;\n\tint count;\n};\n\nstruct aa_ns {\n\tstruct aa_policy base;\n\tstruct aa_ns *parent;\n\tstruct mutex lock;\n\tstruct aa_ns_acct acct;\n\tstruct aa_profile *unconfined;\n\tstruct list_head sub_ns;\n\tatomic_t uniq_null;\n\tlong int uniq_id;\n\tint level;\n\tlong int revision;\n\twait_queue_head_t wait;\n\tstruct aa_labelset labels;\n\tstruct list_head rawdata_list;\n\tstruct dentry *dents[13];\n};\n\nstruct aa_loaddata {\n\tstruct kref count;\n\tstruct list_head list;\n\tstruct work_struct work;\n\tstruct dentry *dents[6];\n\tstruct aa_ns *ns;\n\tchar *name;\n\tsize_t size;\n\tsize_t compressed_size;\n\tlong int revision;\n\tint abi;\n\tunsigned char *hash;\n\tchar *data;\n};\n\nenum {\n\tAAFS_LOADDATA_ABI = 0,\n\tAAFS_LOADDATA_REVISION = 1,\n\tAAFS_LOADDATA_HASH = 2,\n\tAAFS_LOADDATA_DATA = 3,\n\tAAFS_LOADDATA_COMPRESSED_SIZE = 4,\n\tAAFS_LOADDATA_DIR = 5,\n\tAAFS_LOADDATA_NDENTS = 6,\n};\n\nstruct rawdata_f_data {\n\tstruct aa_loaddata *loaddata;\n};\n\nstruct aa_revision {\n\tstruct aa_ns *ns;\n\tlong int last_read;\n};\n\nstruct multi_transaction {\n\tstruct kref count;\n\tssize_t size;\n\tchar data[0];\n};\n\nstruct apparmor_audit_data {\n\tint error;\n\tint type;\n\tconst char *op;\n\tstruct aa_label *label;\n\tconst char *name;\n\tconst char *info;\n\tu32 request;\n\tu32 denied;\n\tunion {\n\t\tstruct {\n\t\t\tstruct aa_label *peer;\n\t\t\tunion {\n\t\t\t\tstruct {\n\t\t\t\t\tconst char *target;\n\t\t\t\t\tkuid_t ouid;\n\t\t\t\t} fs;\n\t\t\t\tstruct {\n\t\t\t\t\tint rlim;\n\t\t\t\t\tlong unsigned int max;\n\t\t\t\t} rlim;\n\t\t\t\tstruct {\n\t\t\t\t\tint signal;\n\t\t\t\t\tint unmappedsig;\n\t\t\t\t};\n\t\t\t\tstruct {\n\t\t\t\t\tint type;\n\t\t\t\t\tint protocol;\n\t\t\t\t\tstruct sock *peer_sk;\n\t\t\t\t\tvoid *addr;\n\t\t\t\t\tint addrlen;\n\t\t\t\t} net;\n\t\t\t};\n\t\t};\n\t\tstruct {\n\t\t\tstruct aa_profile *profile;\n\t\t\tconst char *ns;\n\t\t\tlong int pos;\n\t\t} iface;\n\t\tstruct {\n\t\t\tconst char *src_name;\n\t\t\tconst char *type;\n\t\t\tconst char *trans;\n\t\t\tconst char *data;\n\t\t\tlong unsigned int flags;\n\t\t} mnt;\n\t};\n};\n\nenum audit_type {\n\tAUDIT_APPARMOR_AUDIT = 0,\n\tAUDIT_APPARMOR_ALLOWED = 1,\n\tAUDIT_APPARMOR_DENIED = 2,\n\tAUDIT_APPARMOR_HINT = 3,\n\tAUDIT_APPARMOR_STATUS = 4,\n\tAUDIT_APPARMOR_ERROR = 5,\n\tAUDIT_APPARMOR_KILL = 6,\n\tAUDIT_APPARMOR_AUTO = 7,\n};\n\nstruct aa_audit_rule {\n\tstruct aa_label *label;\n};\n\nstruct audit_cache {\n\tstruct aa_profile *profile;\n\tkernel_cap_t caps;\n};\n\nstruct aa_task_ctx {\n\tstruct aa_label *nnp;\n\tstruct aa_label *onexec;\n\tstruct aa_label *previous;\n\tu64 token;\n};\n\nstruct counted_str {\n\tstruct kref count;\n\tchar name[0];\n};\n\nstruct match_workbuf {\n\tunsigned int count;\n\tunsigned int pos;\n\tunsigned int len;\n\tunsigned int size;\n\tunsigned int history[24];\n};\n\nenum path_flags {\n\tPATH_IS_DIR = 1,\n\tPATH_CONNECT_PATH = 4,\n\tPATH_CHROOT_REL = 8,\n\tPATH_CHROOT_NSCONNECT = 16,\n\tPATH_DELEGATE_DELETED = 32768,\n\tPATH_MEDIATE_DELETED = 65536,\n};\n\nstruct aa_load_ent {\n\tstruct list_head list;\n\tstruct aa_profile *new;\n\tstruct aa_profile *old;\n\tstruct aa_profile *rename;\n\tconst char *ns_name;\n};\n\nenum aa_code {\n\tAA_U8 = 0,\n\tAA_U16 = 1,\n\tAA_U32 = 2,\n\tAA_U64 = 3,\n\tAA_NAME = 4,\n\tAA_STRING = 5,\n\tAA_BLOB = 6,\n\tAA_STRUCT = 7,\n\tAA_STRUCTEND = 8,\n\tAA_LIST = 9,\n\tAA_LISTEND = 10,\n\tAA_ARRAY = 11,\n\tAA_ARRAYEND = 12,\n};\n\nstruct aa_ext {\n\tvoid *start;\n\tvoid *end;\n\tvoid *pos;\n\tu32 version;\n};\n\nstruct aa_file_ctx {\n\tspinlock_t lock;\n\tstruct aa_label *label;\n\tu32 allow;\n};\n\nstruct aa_sk_ctx {\n\tstruct aa_label *label;\n\tstruct aa_label *peer;\n};\n\nunion aa_buffer {\n\tstruct list_head list;\n\tchar buffer[1];\n};\n\nstruct ptrace_relation {\n\tstruct task_struct *tracer;\n\tstruct task_struct *tracee;\n\tbool invalid;\n\tstruct list_head node;\n\tstruct callback_head rcu;\n};\n\nstruct access_report_info {\n\tstruct callback_head work;\n\tconst char *access;\n\tstruct task_struct *target;\n\tstruct task_struct *agent;\n};\n\nenum sid_policy_type {\n\tSIDPOL_DEFAULT = 0,\n\tSIDPOL_CONSTRAINED = 1,\n\tSIDPOL_ALLOWED = 2,\n};\n\ntypedef union {\n\tkuid_t uid;\n\tkgid_t gid;\n} kid_t;\n\nenum setid_type {\n\tUID = 0,\n\tGID = 1,\n};\n\nstruct setid_rule {\n\tstruct hlist_node next;\n\tkid_t src_id;\n\tkid_t dst_id;\n\tenum setid_type type;\n};\n\nstruct setid_ruleset {\n\tstruct hlist_head rules[256];\n\tchar *policy_str;\n\tstruct callback_head rcu;\n\tenum setid_type type;\n};\n\nenum devcg_behavior {\n\tDEVCG_DEFAULT_NONE = 0,\n\tDEVCG_DEFAULT_ALLOW = 1,\n\tDEVCG_DEFAULT_DENY = 2,\n};\n\nstruct dev_exception_item {\n\tu32 major;\n\tu32 minor;\n\tshort int type;\n\tshort int access;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct dev_cgroup {\n\tstruct cgroup_subsys_state css;\n\tstruct list_head exceptions;\n\tenum devcg_behavior behavior;\n};\n\nstruct landlock_ruleset_attr {\n\t__u64 handled_access_fs;\n};\n\nenum landlock_rule_type {\n\tLANDLOCK_RULE_PATH_BENEATH = 1,\n};\n\nstruct landlock_path_beneath_attr {\n\t__u64 allowed_access;\n\t__s32 parent_fd;\n} __attribute__((packed));\n\nstruct landlock_hierarchy {\n\tstruct landlock_hierarchy *parent;\n\trefcount_t usage;\n};\n\nstruct landlock_ruleset {\n\tstruct rb_root root;\n\tstruct landlock_hierarchy *hierarchy;\n\tunion {\n\t\tstruct work_struct work_free;\n\t\tstruct {\n\t\t\tstruct mutex lock;\n\t\t\trefcount_t usage;\n\t\t\tu32 num_rules;\n\t\t\tu32 num_layers;\n\t\t\tu16 fs_access_masks[0];\n\t\t};\n\t};\n};\n\nstruct landlock_cred_security {\n\tstruct landlock_ruleset *domain;\n};\n\nstruct landlock_object;\n\nstruct landlock_object_underops {\n\tvoid (*release)(struct landlock_object * const);\n};\n\nstruct landlock_object {\n\trefcount_t usage;\n\tspinlock_t lock;\n\tvoid *underobj;\n\tunion {\n\t\tstruct callback_head rcu_free;\n\t\tconst struct landlock_object_underops *underops;\n\t};\n};\n\nstruct landlock_layer {\n\tu16 level;\n\tu16 access;\n};\n\nstruct landlock_rule {\n\tstruct rb_node node;\n\tstruct landlock_object *object;\n\tu32 num_layers;\n\tstruct landlock_layer layers[0];\n};\n\nstruct landlock_inode_security {\n\tstruct landlock_object *object;\n};\n\nstruct landlock_superblock_security {\n\tatomic_long_t inode_refs;\n};\n\nenum {\n\tCRYPTO_MSG_ALG_REQUEST = 0,\n\tCRYPTO_MSG_ALG_REGISTER = 1,\n\tCRYPTO_MSG_ALG_LOADED = 2,\n};\n\nstruct crypto_larval {\n\tstruct crypto_alg alg;\n\tstruct crypto_alg *adult;\n\tstruct completion completion;\n\tu32 mask;\n};\n\nstruct crypto_cipher {\n\tstruct crypto_tfm base;\n};\n\nstruct rtattr {\n\tshort unsigned int rta_len;\n\tshort unsigned int rta_type;\n};\n\nstruct crypto_queue {\n\tstruct list_head list;\n\tstruct list_head *backlog;\n\tunsigned int qlen;\n\tunsigned int max_qlen;\n};\n\nstruct crypto_attr_alg {\n\tchar name[128];\n};\n\nstruct crypto_attr_type {\n\tu32 type;\n\tu32 mask;\n};\n\nenum {\n\tNAPI_STATE_SCHED = 0,\n\tNAPI_STATE_MISSED = 1,\n\tNAPI_STATE_DISABLE = 2,\n\tNAPI_STATE_NPSVC = 3,\n\tNAPI_STATE_LISTED = 4,\n\tNAPI_STATE_NO_BUSY_POLL = 5,\n\tNAPI_STATE_IN_BUSY_POLL = 6,\n\tNAPI_STATE_PREFER_BUSY_POLL = 7,\n\tNAPI_STATE_THREADED = 8,\n\tNAPI_STATE_SCHED_THREADED = 9,\n};\n\nenum xps_map_type {\n\tXPS_CPUS = 0,\n\tXPS_RXQS = 1,\n\tXPS_MAPS_MAX = 2,\n};\n\nenum bpf_xdp_mode {\n\tXDP_MODE_SKB = 0,\n\tXDP_MODE_DRV = 1,\n\tXDP_MODE_HW = 2,\n\t__MAX_XDP_MODE = 3,\n};\n\nenum {\n\tNETIF_MSG_DRV_BIT = 0,\n\tNETIF_MSG_PROBE_BIT = 1,\n\tNETIF_MSG_LINK_BIT = 2,\n\tNETIF_MSG_TIMER_BIT = 3,\n\tNETIF_MSG_IFDOWN_BIT = 4,\n\tNETIF_MSG_IFUP_BIT = 5,\n\tNETIF_MSG_RX_ERR_BIT = 6,\n\tNETIF_MSG_TX_ERR_BIT = 7,\n\tNETIF_MSG_TX_QUEUED_BIT = 8,\n\tNETIF_MSG_INTR_BIT = 9,\n\tNETIF_MSG_TX_DONE_BIT = 10,\n\tNETIF_MSG_RX_STATUS_BIT = 11,\n\tNETIF_MSG_PKTDATA_BIT = 12,\n\tNETIF_MSG_HW_BIT = 13,\n\tNETIF_MSG_WOL_BIT = 14,\n\tNETIF_MSG_CLASS_COUNT = 15,\n};\n\nenum {\n\tCRYPTOA_UNSPEC = 0,\n\tCRYPTOA_ALG = 1,\n\tCRYPTOA_TYPE = 2,\n\t__CRYPTOA_MAX = 3,\n};\n\nstruct scatter_walk {\n\tstruct scatterlist *sg;\n\tunsigned int offset;\n};\n\nstruct aead_request {\n\tstruct crypto_async_request base;\n\tunsigned int assoclen;\n\tunsigned int cryptlen;\n\tu8 *iv;\n\tstruct scatterlist *src;\n\tstruct scatterlist *dst;\n\tvoid *__ctx[0];\n};\n\nstruct crypto_aead;\n\nstruct aead_alg {\n\tint (*setkey)(struct crypto_aead *, const u8 *, unsigned int);\n\tint (*setauthsize)(struct crypto_aead *, unsigned int);\n\tint (*encrypt)(struct aead_request *);\n\tint (*decrypt)(struct aead_request *);\n\tint (*init)(struct crypto_aead *);\n\tvoid (*exit)(struct crypto_aead *);\n\tunsigned int ivsize;\n\tunsigned int maxauthsize;\n\tunsigned int chunksize;\n\tstruct crypto_alg base;\n};\n\nstruct crypto_aead {\n\tunsigned int authsize;\n\tunsigned int reqsize;\n\tstruct crypto_tfm base;\n};\n\nstruct aead_instance {\n\tvoid (*free)(struct aead_instance *);\n\tunion {\n\t\tstruct {\n\t\t\tchar head[64];\n\t\t\tstruct crypto_instance base;\n\t\t} s;\n\t\tstruct aead_alg alg;\n\t};\n};\n\nstruct crypto_aead_spawn {\n\tstruct crypto_spawn base;\n};\n\nenum crypto_attr_type_t {\n\tCRYPTOCFGA_UNSPEC = 0,\n\tCRYPTOCFGA_PRIORITY_VAL = 1,\n\tCRYPTOCFGA_REPORT_LARVAL = 2,\n\tCRYPTOCFGA_REPORT_HASH = 3,\n\tCRYPTOCFGA_REPORT_BLKCIPHER = 4,\n\tCRYPTOCFGA_REPORT_AEAD = 5,\n\tCRYPTOCFGA_REPORT_COMPRESS = 6,\n\tCRYPTOCFGA_REPORT_RNG = 7,\n\tCRYPTOCFGA_REPORT_CIPHER = 8,\n\tCRYPTOCFGA_REPORT_AKCIPHER = 9,\n\tCRYPTOCFGA_REPORT_KPP = 10,\n\tCRYPTOCFGA_REPORT_ACOMP = 11,\n\tCRYPTOCFGA_STAT_LARVAL = 12,\n\tCRYPTOCFGA_STAT_HASH = 13,\n\tCRYPTOCFGA_STAT_BLKCIPHER = 14,\n\tCRYPTOCFGA_STAT_AEAD = 15,\n\tCRYPTOCFGA_STAT_COMPRESS = 16,\n\tCRYPTOCFGA_STAT_RNG = 17,\n\tCRYPTOCFGA_STAT_CIPHER = 18,\n\tCRYPTOCFGA_STAT_AKCIPHER = 19,\n\tCRYPTOCFGA_STAT_KPP = 20,\n\tCRYPTOCFGA_STAT_ACOMP = 21,\n\t__CRYPTOCFGA_MAX = 22,\n};\n\nstruct crypto_report_aead {\n\tchar type[64];\n\tchar geniv[64];\n\tunsigned int blocksize;\n\tunsigned int maxauthsize;\n\tunsigned int ivsize;\n};\n\nstruct crypto_sync_skcipher;\n\nstruct aead_geniv_ctx {\n\tspinlock_t lock;\n\tstruct crypto_aead *child;\n\tstruct crypto_sync_skcipher *sknull;\n\tu8 salt[0];\n};\n\nstruct crypto_rng;\n\nstruct rng_alg {\n\tint (*generate)(struct crypto_rng *, const u8 *, unsigned int, u8 *, unsigned int);\n\tint (*seed)(struct crypto_rng *, const u8 *, unsigned int);\n\tvoid (*set_ent)(struct crypto_rng *, const u8 *, unsigned int);\n\tunsigned int seedsize;\n\tstruct crypto_alg base;\n};\n\nstruct crypto_rng {\n\tstruct crypto_tfm base;\n};\n\nstruct crypto_cipher_spawn {\n\tstruct crypto_spawn base;\n};\n\nstruct crypto_sync_skcipher___2 {\n\tstruct crypto_skcipher base;\n};\n\nstruct skcipher_instance {\n\tvoid (*free)(struct skcipher_instance *);\n\tunion {\n\t\tstruct {\n\t\t\tchar head[64];\n\t\t\tstruct crypto_instance base;\n\t\t} s;\n\t\tstruct skcipher_alg alg;\n\t};\n};\n\nstruct crypto_skcipher_spawn {\n\tstruct crypto_spawn base;\n};\n\nstruct skcipher_walk {\n\tunion {\n\t\tstruct {\n\t\t\tstruct page *page;\n\t\t\tlong unsigned int offset;\n\t\t} phys;\n\t\tstruct {\n\t\t\tu8 *page;\n\t\t\tvoid *addr;\n\t\t} virt;\n\t} src;\n\tunion {\n\t\tstruct {\n\t\t\tstruct page *page;\n\t\t\tlong unsigned int offset;\n\t\t} phys;\n\t\tstruct {\n\t\t\tu8 *page;\n\t\t\tvoid *addr;\n\t\t} virt;\n\t} dst;\n\tstruct scatter_walk in;\n\tunsigned int nbytes;\n\tstruct scatter_walk out;\n\tunsigned int total;\n\tstruct list_head buffers;\n\tu8 *page;\n\tu8 *buffer;\n\tu8 *oiv;\n\tvoid *iv;\n\tunsigned int ivsize;\n\tint flags;\n\tunsigned int blocksize;\n\tunsigned int stride;\n\tunsigned int alignmask;\n};\n\nstruct skcipher_ctx_simple {\n\tstruct crypto_cipher *cipher;\n};\n\nstruct crypto_report_blkcipher {\n\tchar type[64];\n\tchar geniv[64];\n\tunsigned int blocksize;\n\tunsigned int min_keysize;\n\tunsigned int max_keysize;\n\tunsigned int ivsize;\n};\n\nenum {\n\tSKCIPHER_WALK_PHYS = 1,\n\tSKCIPHER_WALK_SLOW = 2,\n\tSKCIPHER_WALK_COPY = 4,\n\tSKCIPHER_WALK_DIFF = 8,\n\tSKCIPHER_WALK_SLEEP = 16,\n};\n\nstruct skcipher_walk_buffer {\n\tstruct list_head entry;\n\tstruct scatter_walk dst;\n\tunsigned int len;\n\tu8 *data;\n\tu8 buffer[0];\n};\n\nstruct ahash_alg {\n\tint (*init)(struct ahash_request *);\n\tint (*update)(struct ahash_request *);\n\tint (*final)(struct ahash_request *);\n\tint (*finup)(struct ahash_request *);\n\tint (*digest)(struct ahash_request *);\n\tint (*export)(struct ahash_request *, void *);\n\tint (*import)(struct ahash_request *, const void *);\n\tint (*setkey)(struct crypto_ahash *, const u8 *, unsigned int);\n\tint (*init_tfm)(struct crypto_ahash *);\n\tvoid (*exit_tfm)(struct crypto_ahash *);\n\tstruct hash_alg_common halg;\n};\n\nstruct crypto_hash_walk {\n\tchar *data;\n\tunsigned int offset;\n\tunsigned int alignmask;\n\tstruct page *pg;\n\tunsigned int entrylen;\n\tunsigned int total;\n\tstruct scatterlist *sg;\n\tunsigned int flags;\n};\n\nstruct ahash_instance {\n\tvoid (*free)(struct ahash_instance *);\n\tunion {\n\t\tstruct {\n\t\t\tchar head[88];\n\t\t\tstruct crypto_instance base;\n\t\t} s;\n\t\tstruct ahash_alg alg;\n\t};\n};\n\nstruct crypto_ahash_spawn {\n\tstruct crypto_spawn base;\n};\n\nstruct crypto_report_hash {\n\tchar type[64];\n\tunsigned int blocksize;\n\tunsigned int digestsize;\n};\n\nstruct ahash_request_priv {\n\tcrypto_completion_t complete;\n\tvoid *data;\n\tu8 *result;\n\tu32 flags;\n\tvoid *ubuf[0];\n};\n\nstruct shash_instance {\n\tvoid (*free)(struct shash_instance *);\n\tunion {\n\t\tstruct {\n\t\t\tchar head[96];\n\t\t\tstruct crypto_instance base;\n\t\t} s;\n\t\tstruct shash_alg alg;\n\t};\n};\n\nstruct crypto_shash_spawn {\n\tstruct crypto_spawn base;\n};\n\nstruct crypto_report_akcipher {\n\tchar type[64];\n};\n\nstruct akcipher_request {\n\tstruct crypto_async_request base;\n\tstruct scatterlist *src;\n\tstruct scatterlist *dst;\n\tunsigned int src_len;\n\tunsigned int dst_len;\n\tvoid *__ctx[0];\n};\n\nstruct crypto_akcipher {\n\tstruct crypto_tfm base;\n};\n\nstruct akcipher_alg {\n\tint (*sign)(struct akcipher_request *);\n\tint (*verify)(struct akcipher_request *);\n\tint (*encrypt)(struct akcipher_request *);\n\tint (*decrypt)(struct akcipher_request *);\n\tint (*set_pub_key)(struct crypto_akcipher *, const void *, unsigned int);\n\tint (*set_priv_key)(struct crypto_akcipher *, const void *, unsigned int);\n\tunsigned int (*max_size)(struct crypto_akcipher *);\n\tint (*init)(struct crypto_akcipher *);\n\tvoid (*exit)(struct crypto_akcipher *);\n\tunsigned int reqsize;\n\tstruct crypto_alg base;\n};\n\nstruct akcipher_instance {\n\tvoid (*free)(struct akcipher_instance *);\n\tunion {\n\t\tstruct {\n\t\t\tchar head[80];\n\t\t\tstruct crypto_instance base;\n\t\t} s;\n\t\tstruct akcipher_alg alg;\n\t};\n};\n\nstruct crypto_akcipher_spawn {\n\tstruct crypto_spawn base;\n};\n\nstruct crypto_report_kpp {\n\tchar type[64];\n};\n\ntypedef long unsigned int mpi_limb_t;\n\nstruct gcry_mpi {\n\tint alloced;\n\tint nlimbs;\n\tint nbits;\n\tint sign;\n\tunsigned int flags;\n\tmpi_limb_t *d;\n};\n\ntypedef struct gcry_mpi *MPI;\n\nstruct dh_ctx {\n\tMPI p;\n\tMPI q;\n\tMPI g;\n\tMPI xa;\n};\n\nenum {\n\tCRYPTO_KPP_SECRET_TYPE_UNKNOWN = 0,\n\tCRYPTO_KPP_SECRET_TYPE_DH = 1,\n\tCRYPTO_KPP_SECRET_TYPE_ECDH = 2,\n};\n\nstruct kpp_secret {\n\tshort unsigned int type;\n\tshort unsigned int len;\n};\n\nenum asn1_class {\n\tASN1_UNIV = 0,\n\tASN1_APPL = 1,\n\tASN1_CONT = 2,\n\tASN1_PRIV = 3,\n};\n\nenum asn1_method {\n\tASN1_PRIM = 0,\n\tASN1_CONS = 1,\n};\n\nenum asn1_tag {\n\tASN1_EOC = 0,\n\tASN1_BOOL = 1,\n\tASN1_INT = 2,\n\tASN1_BTS = 3,\n\tASN1_OTS = 4,\n\tASN1_NULL = 5,\n\tASN1_OID = 6,\n\tASN1_ODE = 7,\n\tASN1_EXT = 8,\n\tASN1_REAL = 9,\n\tASN1_ENUM = 10,\n\tASN1_EPDV = 11,\n\tASN1_UTF8STR = 12,\n\tASN1_RELOID = 13,\n\tASN1_SEQ = 16,\n\tASN1_SET = 17,\n\tASN1_NUMSTR = 18,\n\tASN1_PRNSTR = 19,\n\tASN1_TEXSTR = 20,\n\tASN1_VIDSTR = 21,\n\tASN1_IA5STR = 22,\n\tASN1_UNITIM = 23,\n\tASN1_GENTIM = 24,\n\tASN1_GRASTR = 25,\n\tASN1_VISSTR = 26,\n\tASN1_GENSTR = 27,\n\tASN1_UNISTR = 28,\n\tASN1_CHRSTR = 29,\n\tASN1_BMPSTR = 30,\n\tASN1_LONG_TAG = 31,\n};\n\ntypedef int (*asn1_action_t)(void *, size_t, unsigned char, const void *, size_t);\n\nstruct asn1_decoder {\n\tconst unsigned char *machine;\n\tsize_t machlen;\n\tconst asn1_action_t *actions;\n};\n\nenum asn1_opcode {\n\tASN1_OP_MATCH = 0,\n\tASN1_OP_MATCH_OR_SKIP = 1,\n\tASN1_OP_MATCH_ACT = 2,\n\tASN1_OP_MATCH_ACT_OR_SKIP = 3,\n\tASN1_OP_MATCH_JUMP = 4,\n\tASN1_OP_MATCH_JUMP_OR_SKIP = 5,\n\tASN1_OP_MATCH_ANY = 8,\n\tASN1_OP_MATCH_ANY_OR_SKIP = 9,\n\tASN1_OP_MATCH_ANY_ACT = 10,\n\tASN1_OP_MATCH_ANY_ACT_OR_SKIP = 11,\n\tASN1_OP_COND_MATCH_OR_SKIP = 17,\n\tASN1_OP_COND_MATCH_ACT_OR_SKIP = 19,\n\tASN1_OP_COND_MATCH_JUMP_OR_SKIP = 21,\n\tASN1_OP_COND_MATCH_ANY = 24,\n\tASN1_OP_COND_MATCH_ANY_OR_SKIP = 25,\n\tASN1_OP_COND_MATCH_ANY_ACT = 26,\n\tASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 27,\n\tASN1_OP_COND_FAIL = 28,\n\tASN1_OP_COMPLETE = 29,\n\tASN1_OP_ACT = 30,\n\tASN1_OP_MAYBE_ACT = 31,\n\tASN1_OP_END_SEQ = 32,\n\tASN1_OP_END_SET = 33,\n\tASN1_OP_END_SEQ_OF = 34,\n\tASN1_OP_END_SET_OF = 35,\n\tASN1_OP_END_SEQ_ACT = 36,\n\tASN1_OP_END_SET_ACT = 37,\n\tASN1_OP_END_SEQ_OF_ACT = 38,\n\tASN1_OP_END_SET_OF_ACT = 39,\n\tASN1_OP_RETURN = 40,\n\tASN1_OP__NR = 41,\n};\n\nenum rsapubkey_actions {\n\tACT_rsa_get_e = 0,\n\tACT_rsa_get_n = 1,\n\tNR__rsapubkey_actions = 2,\n};\n\nenum rsaprivkey_actions {\n\tACT_rsa_get_d = 0,\n\tACT_rsa_get_dp = 1,\n\tACT_rsa_get_dq = 2,\n\tACT_rsa_get_e___2 = 3,\n\tACT_rsa_get_n___2 = 4,\n\tACT_rsa_get_p = 5,\n\tACT_rsa_get_q = 6,\n\tACT_rsa_get_qinv = 7,\n\tNR__rsaprivkey_actions = 8,\n};\n\nstruct rsa_key {\n\tconst u8 *n;\n\tconst u8 *e;\n\tconst u8 *d;\n\tconst u8 *p;\n\tconst u8 *q;\n\tconst u8 *dp;\n\tconst u8 *dq;\n\tconst u8 *qinv;\n\tsize_t n_sz;\n\tsize_t e_sz;\n\tsize_t d_sz;\n\tsize_t p_sz;\n\tsize_t q_sz;\n\tsize_t dp_sz;\n\tsize_t dq_sz;\n\tsize_t qinv_sz;\n};\n\nstruct rsa_mpi_key {\n\tMPI n;\n\tMPI e;\n\tMPI d;\n};\n\nstruct asn1_decoder___2;\n\nstruct rsa_asn1_template {\n\tconst char *name;\n\tconst u8 *data;\n\tsize_t size;\n};\n\nstruct pkcs1pad_ctx {\n\tstruct crypto_akcipher *child;\n\tunsigned int key_size;\n};\n\nstruct pkcs1pad_inst_ctx {\n\tstruct crypto_akcipher_spawn spawn;\n\tconst struct rsa_asn1_template *digest_info;\n};\n\nstruct pkcs1pad_request {\n\tstruct scatterlist in_sg[2];\n\tstruct scatterlist out_sg[1];\n\tuint8_t *in_buf;\n\tuint8_t *out_buf;\n\tstruct akcipher_request child_req;\n};\n\nstruct crypto_report_acomp {\n\tchar type[64];\n};\n\nstruct acomp_alg {\n\tint (*compress)(struct acomp_req *);\n\tint (*decompress)(struct acomp_req *);\n\tvoid (*dst_free)(struct scatterlist *);\n\tint (*init)(struct crypto_acomp *);\n\tvoid (*exit)(struct crypto_acomp *);\n\tunsigned int reqsize;\n\tstruct crypto_alg base;\n};\n\nstruct crypto_report_comp {\n\tchar type[64];\n};\n\nstruct crypto_scomp {\n\tstruct crypto_tfm base;\n};\n\nstruct scomp_alg {\n\tvoid * (*alloc_ctx)(struct crypto_scomp *);\n\tvoid (*free_ctx)(struct crypto_scomp *, void *);\n\tint (*compress)(struct crypto_scomp *, const u8 *, unsigned int, u8 *, unsigned int *, void *);\n\tint (*decompress)(struct crypto_scomp *, const u8 *, unsigned int, u8 *, unsigned int *, void *);\n\tstruct crypto_alg base;\n};\n\nstruct scomp_scratch {\n\tspinlock_t lock;\n\tvoid *src;\n\tvoid *dst;\n};\n\nstruct cryptomgr_param {\n\tstruct rtattr *tb[34];\n\tstruct {\n\t\tstruct rtattr attr;\n\t\tstruct crypto_attr_type data;\n\t} type;\n\tstruct {\n\t\tstruct rtattr attr;\n\t\tstruct crypto_attr_alg data;\n\t} attrs[32];\n\tchar template[128];\n\tstruct crypto_larval *larval;\n\tu32 otype;\n\tu32 omask;\n};\n\nstruct crypto_test_param {\n\tchar driver[128];\n\tchar alg[128];\n\tu32 type;\n};\n\nstruct hmac_ctx {\n\tstruct crypto_shash *hash;\n};\n\nstruct md5_state {\n\tu32 hash[4];\n\tu32 block[16];\n\tu64 byte_count;\n};\n\nstruct sha1_state {\n\tu32 state[5];\n\tu64 count;\n\tu8 buffer[64];\n};\n\ntypedef void sha1_block_fn(struct sha1_state *, const u8 *, int);\n\nstruct sha256_state {\n\tu32 state[8];\n\tu64 count;\n\tu8 buf[64];\n};\n\nstruct sha512_state {\n\tu64 state[8];\n\tu64 count[2];\n\tu8 buf[128];\n};\n\ntypedef void sha512_block_fn(struct sha512_state *, const u8 *, int);\n\nstruct crypto_rfc3686_ctx {\n\tstruct crypto_skcipher *child;\n\tu8 nonce[4];\n};\n\nstruct crypto_rfc3686_req_ctx {\n\tu8 iv[16];\n\tstruct skcipher_request subreq;\n};\n\nstruct crypto_aes_ctx {\n\tu32 key_enc[60];\n\tu32 key_dec[60];\n\tu32 key_length;\n};\n\nstruct chksum_desc_ctx {\n\t__u16 crc;\n};\n\nstruct lz4_ctx {\n\tvoid *lz4_comp_mem;\n};\n\nstruct crypto_report_rng {\n\tchar type[64];\n\tunsigned int seedsize;\n};\n\nstruct rand_data {\n\t__u64 data;\n\t__u64 old_data;\n\t__u64 prev_time;\n\t__u64 last_delta;\n\t__s64 last_delta2;\n\tunsigned int osr;\n\tunsigned char *mem;\n\tunsigned int memlocation;\n\tunsigned int memblocks;\n\tunsigned int memblocksize;\n\tunsigned int memaccessloops;\n\tint rct_count;\n\tunsigned int apt_observations;\n\tunsigned int apt_count;\n\tunsigned int apt_base;\n\tunsigned int apt_base_set: 1;\n\tunsigned int health_failure: 1;\n};\n\nstruct rand_data___2;\n\nstruct jitterentropy {\n\tspinlock_t jent_lock;\n\tstruct rand_data___2 *entropy_collector;\n\tunsigned int reset_cnt;\n};\n\ntypedef enum {\n\tZSTD_fast = 0,\n\tZSTD_dfast = 1,\n\tZSTD_greedy = 2,\n\tZSTD_lazy = 3,\n\tZSTD_lazy2 = 4,\n\tZSTD_btlazy2 = 5,\n\tZSTD_btopt = 6,\n\tZSTD_btopt2 = 7,\n} ZSTD_strategy;\n\ntypedef struct {\n\tunsigned int windowLog;\n\tunsigned int chainLog;\n\tunsigned int hashLog;\n\tunsigned int searchLog;\n\tunsigned int searchLength;\n\tunsigned int targetLength;\n\tZSTD_strategy strategy;\n} ZSTD_compressionParameters;\n\ntypedef struct {\n\tunsigned int contentSizeFlag;\n\tunsigned int checksumFlag;\n\tunsigned int noDictIDFlag;\n} ZSTD_frameParameters;\n\ntypedef struct {\n\tZSTD_compressionParameters cParams;\n\tZSTD_frameParameters fParams;\n} ZSTD_parameters;\n\nstruct ZSTD_CCtx_s;\n\ntypedef struct ZSTD_CCtx_s ZSTD_CCtx;\n\nstruct ZSTD_DCtx_s;\n\ntypedef struct ZSTD_DCtx_s ZSTD_DCtx;\n\nstruct zstd_ctx {\n\tZSTD_CCtx *cctx;\n\tZSTD_DCtx *dctx;\n\tvoid *cwksp;\n\tvoid *dwksp;\n};\n\nenum asymmetric_payload_bits {\n\tasym_crypto = 0,\n\tasym_subtype = 1,\n\tasym_key_ids = 2,\n\tasym_auth = 3,\n};\n\nstruct asymmetric_key_id {\n\tshort unsigned int len;\n\tunsigned char data[0];\n};\n\nstruct asymmetric_key_ids {\n\tvoid *id[2];\n};\n\nstruct public_key_signature;\n\nstruct asymmetric_key_subtype {\n\tstruct module *owner;\n\tconst char *name;\n\tshort unsigned int name_len;\n\tvoid (*describe)(const struct key *, struct seq_file *);\n\tvoid (*destroy)(void *, void *);\n\tint (*query)(const struct kernel_pkey_params *, struct kernel_pkey_query *);\n\tint (*eds_op)(struct kernel_pkey_params *, const void *, void *);\n\tint (*verify_signature)(const struct key *, const struct public_key_signature *);\n};\n\nstruct public_key_signature {\n\tstruct asymmetric_key_id *auth_ids[2];\n\tu8 *s;\n\tu32 s_size;\n\tu8 *digest;\n\tu8 digest_size;\n\tconst char *pkey_algo;\n\tconst char *hash_algo;\n\tconst char *encoding;\n\tconst void *data;\n\tunsigned int data_size;\n};\n\nstruct asymmetric_key_parser {\n\tstruct list_head link;\n\tstruct module *owner;\n\tconst char *name;\n\tint (*parse)(struct key_preparsed_payload *);\n};\n\nenum OID {\n\tOID_id_dsa_with_sha1 = 0,\n\tOID_id_dsa = 1,\n\tOID_id_ecPublicKey = 2,\n\tOID_id_prime192v1 = 3,\n\tOID_id_prime256v1 = 4,\n\tOID_id_ecdsa_with_sha1 = 5,\n\tOID_id_ecdsa_with_sha224 = 6,\n\tOID_id_ecdsa_with_sha256 = 7,\n\tOID_id_ecdsa_with_sha384 = 8,\n\tOID_id_ecdsa_with_sha512 = 9,\n\tOID_rsaEncryption = 10,\n\tOID_md2WithRSAEncryption = 11,\n\tOID_md3WithRSAEncryption = 12,\n\tOID_md4WithRSAEncryption = 13,\n\tOID_sha1WithRSAEncryption = 14,\n\tOID_sha256WithRSAEncryption = 15,\n\tOID_sha384WithRSAEncryption = 16,\n\tOID_sha512WithRSAEncryption = 17,\n\tOID_sha224WithRSAEncryption = 18,\n\tOID_data = 19,\n\tOID_signed_data = 20,\n\tOID_email_address = 21,\n\tOID_contentType = 22,\n\tOID_messageDigest = 23,\n\tOID_signingTime = 24,\n\tOID_smimeCapabilites = 25,\n\tOID_smimeAuthenticatedAttrs = 26,\n\tOID_md2 = 27,\n\tOID_md4 = 28,\n\tOID_md5 = 29,\n\tOID_mskrb5 = 30,\n\tOID_krb5 = 31,\n\tOID_krb5u2u = 32,\n\tOID_msIndirectData = 33,\n\tOID_msStatementType = 34,\n\tOID_msSpOpusInfo = 35,\n\tOID_msPeImageDataObjId = 36,\n\tOID_msIndividualSPKeyPurpose = 37,\n\tOID_msOutlookExpress = 38,\n\tOID_ntlmssp = 39,\n\tOID_spnego = 40,\n\tOID_certAuthInfoAccess = 41,\n\tOID_sha1 = 42,\n\tOID_id_ansip384r1 = 43,\n\tOID_sha256 = 44,\n\tOID_sha384 = 45,\n\tOID_sha512 = 46,\n\tOID_sha224 = 47,\n\tOID_commonName = 48,\n\tOID_surname = 49,\n\tOID_countryName = 50,\n\tOID_locality = 51,\n\tOID_stateOrProvinceName = 52,\n\tOID_organizationName = 53,\n\tOID_organizationUnitName = 54,\n\tOID_title = 55,\n\tOID_description = 56,\n\tOID_name = 57,\n\tOID_givenName = 58,\n\tOID_initials = 59,\n\tOID_generationalQualifier = 60,\n\tOID_subjectKeyIdentifier = 61,\n\tOID_keyUsage = 62,\n\tOID_subjectAltName = 63,\n\tOID_issuerAltName = 64,\n\tOID_basicConstraints = 65,\n\tOID_crlDistributionPoints = 66,\n\tOID_certPolicies = 67,\n\tOID_authorityKeyIdentifier = 68,\n\tOID_extKeyUsage = 69,\n\tOID_gostCPSignA = 70,\n\tOID_gostCPSignB = 71,\n\tOID_gostCPSignC = 72,\n\tOID_gost2012PKey256 = 73,\n\tOID_gost2012PKey512 = 74,\n\tOID_gost2012Digest256 = 75,\n\tOID_gost2012Digest512 = 76,\n\tOID_gost2012Signature256 = 77,\n\tOID_gost2012Signature512 = 78,\n\tOID_gostTC26Sign256A = 79,\n\tOID_gostTC26Sign256B = 80,\n\tOID_gostTC26Sign256C = 81,\n\tOID_gostTC26Sign256D = 82,\n\tOID_gostTC26Sign512A = 83,\n\tOID_gostTC26Sign512B = 84,\n\tOID_gostTC26Sign512C = 85,\n\tOID_sm2 = 86,\n\tOID_sm3 = 87,\n\tOID_SM2_with_SM3 = 88,\n\tOID_sm3WithRSAEncryption = 89,\n\tOID_TPMLoadableKey = 90,\n\tOID_TPMImportableKey = 91,\n\tOID_TPMSealedData = 92,\n\tOID__NR = 93,\n};\n\nstruct public_key {\n\tvoid *key;\n\tu32 keylen;\n\tenum OID algo;\n\tvoid *params;\n\tu32 paramlen;\n\tbool key_is_private;\n\tconst char *id_type;\n\tconst char *pkey_algo;\n};\n\nenum x509_actions {\n\tACT_x509_extract_key_data = 0,\n\tACT_x509_extract_name_segment = 1,\n\tACT_x509_note_OID = 2,\n\tACT_x509_note_issuer = 3,\n\tACT_x509_note_not_after = 4,\n\tACT_x509_note_not_before = 5,\n\tACT_x509_note_params = 6,\n\tACT_x509_note_pkey_algo = 7,\n\tACT_x509_note_serial = 8,\n\tACT_x509_note_signature = 9,\n\tACT_x509_note_subject = 10,\n\tACT_x509_note_tbs_certificate = 11,\n\tACT_x509_process_extension = 12,\n\tNR__x509_actions = 13,\n};\n\nenum x509_akid_actions {\n\tACT_x509_akid_note_kid = 0,\n\tACT_x509_akid_note_name = 1,\n\tACT_x509_akid_note_serial = 2,\n\tACT_x509_extract_name_segment___2 = 3,\n\tACT_x509_note_OID___2 = 4,\n\tNR__x509_akid_actions = 5,\n};\n\nstruct x509_certificate {\n\tstruct x509_certificate *next;\n\tstruct x509_certificate *signer;\n\tstruct public_key *pub;\n\tstruct public_key_signature *sig;\n\tchar *issuer;\n\tchar *subject;\n\tstruct asymmetric_key_id *id;\n\tstruct asymmetric_key_id *skid;\n\ttime64_t valid_from;\n\ttime64_t valid_to;\n\tconst void *tbs;\n\tunsigned int tbs_size;\n\tunsigned int raw_sig_size;\n\tconst void *raw_sig;\n\tconst void *raw_serial;\n\tunsigned int raw_serial_size;\n\tunsigned int raw_issuer_size;\n\tconst void *raw_issuer;\n\tconst void *raw_subject;\n\tunsigned int raw_subject_size;\n\tunsigned int raw_skid_size;\n\tconst void *raw_skid;\n\tunsigned int index;\n\tbool seen;\n\tbool verified;\n\tbool self_signed;\n\tbool unsupported_key;\n\tbool unsupported_sig;\n\tbool blacklisted;\n};\n\nstruct x509_parse_context {\n\tstruct x509_certificate *cert;\n\tlong unsigned int data;\n\tconst void *cert_start;\n\tconst void *key;\n\tsize_t key_size;\n\tconst void *params;\n\tsize_t params_size;\n\tenum OID key_algo;\n\tenum OID last_oid;\n\tenum OID algo_oid;\n\tunsigned char nr_mpi;\n\tu8 o_size;\n\tu8 cn_size;\n\tu8 email_size;\n\tu16 o_offset;\n\tu16 cn_offset;\n\tu16 email_offset;\n\tunsigned int raw_akid_size;\n\tconst void *raw_akid;\n\tconst void *akid_raw_issuer;\n\tunsigned int akid_raw_issuer_size;\n};\n\nenum pkcs7_actions {\n\tACT_pkcs7_check_content_type = 0,\n\tACT_pkcs7_extract_cert = 1,\n\tACT_pkcs7_note_OID = 2,\n\tACT_pkcs7_note_certificate_list = 3,\n\tACT_pkcs7_note_content = 4,\n\tACT_pkcs7_note_data = 5,\n\tACT_pkcs7_note_signed_info = 6,\n\tACT_pkcs7_note_signeddata_version = 7,\n\tACT_pkcs7_note_signerinfo_version = 8,\n\tACT_pkcs7_sig_note_authenticated_attr = 9,\n\tACT_pkcs7_sig_note_digest_algo = 10,\n\tACT_pkcs7_sig_note_issuer = 11,\n\tACT_pkcs7_sig_note_pkey_algo = 12,\n\tACT_pkcs7_sig_note_serial = 13,\n\tACT_pkcs7_sig_note_set_of_authattrs = 14,\n\tACT_pkcs7_sig_note_signature = 15,\n\tACT_pkcs7_sig_note_skid = 16,\n\tNR__pkcs7_actions = 17,\n};\n\nstruct pkcs7_signed_info {\n\tstruct pkcs7_signed_info *next;\n\tstruct x509_certificate *signer;\n\tunsigned int index;\n\tbool unsupported_crypto;\n\tbool blacklisted;\n\tconst void *msgdigest;\n\tunsigned int msgdigest_len;\n\tunsigned int authattrs_len;\n\tconst void *authattrs;\n\tlong unsigned int aa_set;\n\ttime64_t signing_time;\n\tstruct public_key_signature *sig;\n};\n\nstruct pkcs7_message___2 {\n\tstruct x509_certificate *certs;\n\tstruct x509_certificate *crl;\n\tstruct pkcs7_signed_info *signed_infos;\n\tu8 version;\n\tbool have_authattrs;\n\tenum OID data_type;\n\tsize_t data_len;\n\tsize_t data_hdrlen;\n\tconst void *data;\n};\n\nstruct pkcs7_parse_context {\n\tstruct pkcs7_message___2 *msg;\n\tstruct pkcs7_signed_info *sinfo;\n\tstruct pkcs7_signed_info **ppsinfo;\n\tstruct x509_certificate *certs;\n\tstruct x509_certificate **ppcerts;\n\tlong unsigned int data;\n\tenum OID last_oid;\n\tunsigned int x509_index;\n\tunsigned int sinfo_index;\n\tconst void *raw_serial;\n\tunsigned int raw_serial_size;\n\tunsigned int raw_issuer_size;\n\tconst void *raw_issuer;\n\tconst void *raw_skid;\n\tunsigned int raw_skid_size;\n\tbool expect_skid;\n};\n\nenum hash_algo {\n\tHASH_ALGO_MD4 = 0,\n\tHASH_ALGO_MD5 = 1,\n\tHASH_ALGO_SHA1 = 2,\n\tHASH_ALGO_RIPE_MD_160 = 3,\n\tHASH_ALGO_SHA256 = 4,\n\tHASH_ALGO_SHA384 = 5,\n\tHASH_ALGO_SHA512 = 6,\n\tHASH_ALGO_SHA224 = 7,\n\tHASH_ALGO_RIPE_MD_128 = 8,\n\tHASH_ALGO_RIPE_MD_256 = 9,\n\tHASH_ALGO_RIPE_MD_320 = 10,\n\tHASH_ALGO_WP_256 = 11,\n\tHASH_ALGO_WP_384 = 12,\n\tHASH_ALGO_WP_512 = 13,\n\tHASH_ALGO_TGR_128 = 14,\n\tHASH_ALGO_TGR_160 = 15,\n\tHASH_ALGO_TGR_192 = 16,\n\tHASH_ALGO_SM3_256 = 17,\n\tHASH_ALGO_STREEBOG_256 = 18,\n\tHASH_ALGO_STREEBOG_512 = 19,\n\tHASH_ALGO__LAST = 20,\n};\n\nstruct mz_hdr {\n\tuint16_t magic;\n\tuint16_t lbsize;\n\tuint16_t blocks;\n\tuint16_t relocs;\n\tuint16_t hdrsize;\n\tuint16_t min_extra_pps;\n\tuint16_t max_extra_pps;\n\tuint16_t ss;\n\tuint16_t sp;\n\tuint16_t checksum;\n\tuint16_t ip;\n\tuint16_t cs;\n\tuint16_t reloc_table_offset;\n\tuint16_t overlay_num;\n\tuint16_t reserved0[4];\n\tuint16_t oem_id;\n\tuint16_t oem_info;\n\tuint16_t reserved1[10];\n\tuint32_t peaddr;\n\tchar message[0];\n};\n\nstruct pe_hdr {\n\tuint32_t magic;\n\tuint16_t machine;\n\tuint16_t sections;\n\tuint32_t timestamp;\n\tuint32_t symbol_table;\n\tuint32_t symbols;\n\tuint16_t opt_hdr_size;\n\tuint16_t flags;\n};\n\nstruct pe32_opt_hdr {\n\tuint16_t magic;\n\tuint8_t ld_major;\n\tuint8_t ld_minor;\n\tuint32_t text_size;\n\tuint32_t data_size;\n\tuint32_t bss_size;\n\tuint32_t entry_point;\n\tuint32_t code_base;\n\tuint32_t data_base;\n\tuint32_t image_base;\n\tuint32_t section_align;\n\tuint32_t file_align;\n\tuint16_t os_major;\n\tuint16_t os_minor;\n\tuint16_t image_major;\n\tuint16_t image_minor;\n\tuint16_t subsys_major;\n\tuint16_t subsys_minor;\n\tuint32_t win32_version;\n\tuint32_t image_size;\n\tuint32_t header_size;\n\tuint32_t csum;\n\tuint16_t subsys;\n\tuint16_t dll_flags;\n\tuint32_t stack_size_req;\n\tuint32_t stack_size;\n\tuint32_t heap_size_req;\n\tuint32_t heap_size;\n\tuint32_t loader_flags;\n\tuint32_t data_dirs;\n};\n\nstruct pe32plus_opt_hdr {\n\tuint16_t magic;\n\tuint8_t ld_major;\n\tuint8_t ld_minor;\n\tuint32_t text_size;\n\tuint32_t data_size;\n\tuint32_t bss_size;\n\tuint32_t entry_point;\n\tuint32_t code_base;\n\tuint64_t image_base;\n\tuint32_t section_align;\n\tuint32_t file_align;\n\tuint16_t os_major;\n\tuint16_t os_minor;\n\tuint16_t image_major;\n\tuint16_t image_minor;\n\tuint16_t subsys_major;\n\tuint16_t subsys_minor;\n\tuint32_t win32_version;\n\tuint32_t image_size;\n\tuint32_t header_size;\n\tuint32_t csum;\n\tuint16_t subsys;\n\tuint16_t dll_flags;\n\tuint64_t stack_size_req;\n\tuint64_t stack_size;\n\tuint64_t heap_size_req;\n\tuint64_t heap_size;\n\tuint32_t loader_flags;\n\tuint32_t data_dirs;\n};\n\nstruct data_dirent {\n\tuint32_t virtual_address;\n\tuint32_t size;\n};\n\nstruct data_directory {\n\tstruct data_dirent exports;\n\tstruct data_dirent imports;\n\tstruct data_dirent resources;\n\tstruct data_dirent exceptions;\n\tstruct data_dirent certs;\n\tstruct data_dirent base_relocations;\n\tstruct data_dirent debug;\n\tstruct data_dirent arch;\n\tstruct data_dirent global_ptr;\n\tstruct data_dirent tls;\n\tstruct data_dirent load_config;\n\tstruct data_dirent bound_imports;\n\tstruct data_dirent import_addrs;\n\tstruct data_dirent delay_imports;\n\tstruct data_dirent clr_runtime_hdr;\n\tstruct data_dirent reserved;\n};\n\nstruct section_header {\n\tchar name[8];\n\tuint32_t virtual_size;\n\tuint32_t virtual_address;\n\tuint32_t raw_data_size;\n\tuint32_t data_addr;\n\tuint32_t relocs;\n\tuint32_t line_numbers;\n\tuint16_t num_relocs;\n\tuint16_t num_lin_numbers;\n\tuint32_t flags;\n};\n\nstruct win_certificate {\n\tuint32_t length;\n\tuint16_t revision;\n\tuint16_t cert_type;\n};\n\nstruct pefile_context {\n\tunsigned int header_size;\n\tunsigned int image_checksum_offset;\n\tunsigned int cert_dirent_offset;\n\tunsigned int n_data_dirents;\n\tunsigned int n_sections;\n\tunsigned int certs_size;\n\tunsigned int sig_offset;\n\tunsigned int sig_len;\n\tconst struct section_header *secs;\n\tconst void *digest;\n\tunsigned int digest_len;\n\tconst char *digest_algo;\n};\n\nenum mscode_actions {\n\tACT_mscode_note_content_type = 0,\n\tACT_mscode_note_digest = 1,\n\tACT_mscode_note_digest_algo = 2,\n\tNR__mscode_actions = 3,\n};\n\nenum rq_qos_id {\n\tRQ_QOS_WBT = 0,\n\tRQ_QOS_LATENCY = 1,\n\tRQ_QOS_COST = 2,\n\tRQ_QOS_IOPRIO = 3,\n};\n\nstruct rq_qos_ops;\n\nstruct rq_qos {\n\tstruct rq_qos_ops *ops;\n\tstruct request_queue *q;\n\tenum rq_qos_id id;\n\tstruct rq_qos *next;\n\tstruct dentry *debugfs_dir;\n};\n\nenum hctx_type {\n\tHCTX_TYPE_DEFAULT = 0,\n\tHCTX_TYPE_READ = 1,\n\tHCTX_TYPE_POLL = 2,\n\tHCTX_MAX_TYPES = 3,\n};\n\nstruct rq_qos_ops {\n\tvoid (*throttle)(struct rq_qos *, struct bio *);\n\tvoid (*track)(struct rq_qos *, struct request *, struct bio *);\n\tvoid (*merge)(struct rq_qos *, struct request *, struct bio *);\n\tvoid (*issue)(struct rq_qos *, struct request *);\n\tvoid (*requeue)(struct rq_qos *, struct request *);\n\tvoid (*done)(struct rq_qos *, struct request *);\n\tvoid (*done_bio)(struct rq_qos *, struct bio *);\n\tvoid (*cleanup)(struct rq_qos *, struct bio *);\n\tvoid (*queue_depth_changed)(struct rq_qos *);\n\tvoid (*exit)(struct rq_qos *);\n\tconst struct blk_mq_debugfs_attr *debugfs_attrs;\n};\n\nstruct biovec_slab {\n\tint nr_vecs;\n\tchar *name;\n\tstruct kmem_cache *slab;\n};\n\nstruct bio_slab {\n\tstruct kmem_cache *slab;\n\tunsigned int slab_ref;\n\tunsigned int slab_size;\n\tchar name[8];\n};\n\nenum {\n\tBLK_MQ_F_SHOULD_MERGE = 1,\n\tBLK_MQ_F_TAG_QUEUE_SHARED = 2,\n\tBLK_MQ_F_STACKING = 4,\n\tBLK_MQ_F_TAG_HCTX_SHARED = 8,\n\tBLK_MQ_F_BLOCKING = 32,\n\tBLK_MQ_F_NO_SCHED = 64,\n\tBLK_MQ_F_ALLOC_POLICY_START_BIT = 8,\n\tBLK_MQ_F_ALLOC_POLICY_BITS = 1,\n\tBLK_MQ_S_STOPPED = 0,\n\tBLK_MQ_S_TAG_ACTIVE = 1,\n\tBLK_MQ_S_SCHED_RESTART = 2,\n\tBLK_MQ_S_INACTIVE = 3,\n\tBLK_MQ_MAX_DEPTH = 10240,\n\tBLK_MQ_CPU_WORK_BATCH = 8,\n};\n\nenum {\n\tWBT_RWQ_BG = 0,\n\tWBT_RWQ_KSWAPD = 1,\n\tWBT_RWQ_DISCARD = 2,\n\tWBT_NUM_RWQ = 3,\n};\n\nstruct blk_plug_cb;\n\ntypedef void (*blk_plug_cb_fn)(struct blk_plug_cb *, bool);\n\nstruct blk_plug_cb {\n\tstruct list_head list;\n\tblk_plug_cb_fn callback;\n\tvoid *data;\n};\n\nenum {\n\tBLK_MQ_REQ_NOWAIT = 1,\n\tBLK_MQ_REQ_RESERVED = 2,\n\tBLK_MQ_REQ_PM = 4,\n};\n\nstruct trace_event_raw_block_buffer {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tsize_t size;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_rq_requeue {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tunsigned int nr_sector;\n\tchar rwbs[8];\n\tu32 __data_loc_cmd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_rq_complete {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tunsigned int nr_sector;\n\tint error;\n\tchar rwbs[8];\n\tu32 __data_loc_cmd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_rq {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tunsigned int nr_sector;\n\tunsigned int bytes;\n\tchar rwbs[8];\n\tchar comm[16];\n\tu32 __data_loc_cmd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_bio_complete {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tunsigned int nr_sector;\n\tint error;\n\tchar rwbs[8];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_bio {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tunsigned int nr_sector;\n\tchar rwbs[8];\n\tchar comm[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_plug {\n\tstruct trace_entry ent;\n\tchar comm[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_unplug {\n\tstruct trace_entry ent;\n\tint nr_rq;\n\tchar comm[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_split {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tsector_t new_sector;\n\tchar rwbs[8];\n\tchar comm[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_bio_remap {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tunsigned int nr_sector;\n\tdev_t old_dev;\n\tsector_t old_sector;\n\tchar rwbs[8];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_block_rq_remap {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tsector_t sector;\n\tunsigned int nr_sector;\n\tdev_t old_dev;\n\tsector_t old_sector;\n\tunsigned int nr_bios;\n\tchar rwbs[8];\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_block_buffer {};\n\nstruct trace_event_data_offsets_block_rq_requeue {\n\tu32 cmd;\n};\n\nstruct trace_event_data_offsets_block_rq_complete {\n\tu32 cmd;\n};\n\nstruct trace_event_data_offsets_block_rq {\n\tu32 cmd;\n};\n\nstruct trace_event_data_offsets_block_bio_complete {};\n\nstruct trace_event_data_offsets_block_bio {};\n\nstruct trace_event_data_offsets_block_plug {};\n\nstruct trace_event_data_offsets_block_unplug {};\n\nstruct trace_event_data_offsets_block_split {};\n\nstruct trace_event_data_offsets_block_bio_remap {};\n\nstruct trace_event_data_offsets_block_rq_remap {};\n\ntypedef void (*btf_trace_block_touch_buffer)(void *, struct buffer_head *);\n\ntypedef void (*btf_trace_block_dirty_buffer)(void *, struct buffer_head *);\n\ntypedef void (*btf_trace_block_rq_requeue)(void *, struct request *);\n\ntypedef void (*btf_trace_block_rq_complete)(void *, struct request *, int, unsigned int);\n\ntypedef void (*btf_trace_block_rq_insert)(void *, struct request *);\n\ntypedef void (*btf_trace_block_rq_issue)(void *, struct request *);\n\ntypedef void (*btf_trace_block_rq_merge)(void *, struct request *);\n\ntypedef void (*btf_trace_block_bio_complete)(void *, struct request_queue *, struct bio *);\n\ntypedef void (*btf_trace_block_bio_bounce)(void *, struct bio *);\n\ntypedef void (*btf_trace_block_bio_backmerge)(void *, struct bio *);\n\ntypedef void (*btf_trace_block_bio_frontmerge)(void *, struct bio *);\n\ntypedef void (*btf_trace_block_bio_queue)(void *, struct bio *);\n\ntypedef void (*btf_trace_block_getrq)(void *, struct bio *);\n\ntypedef void (*btf_trace_block_plug)(void *, struct request_queue *);\n\ntypedef void (*btf_trace_block_unplug)(void *, struct request_queue *, unsigned int, bool);\n\ntypedef void (*btf_trace_block_split)(void *, struct bio *, unsigned int);\n\ntypedef void (*btf_trace_block_bio_remap)(void *, struct bio *, dev_t, sector_t);\n\ntypedef void (*btf_trace_block_rq_remap)(void *, struct request *, dev_t, sector_t);\n\nenum {\n\tBLK_MQ_NO_TAG = 4294967295,\n\tBLK_MQ_TAG_MIN = 1,\n\tBLK_MQ_TAG_MAX = 4294967294,\n};\n\nstruct queue_sysfs_entry {\n\tstruct attribute attr;\n\tssize_t (*show)(struct request_queue *, char *);\n\tssize_t (*store)(struct request_queue *, const char *, size_t);\n};\n\nenum {\n\tREQ_FSEQ_PREFLUSH = 1,\n\tREQ_FSEQ_DATA = 2,\n\tREQ_FSEQ_POSTFLUSH = 4,\n\tREQ_FSEQ_DONE = 8,\n\tREQ_FSEQ_ACTIONS = 7,\n\tFLUSH_PENDING_TIMEOUT = 1500,\n};\n\nenum blk_default_limits {\n\tBLK_MAX_SEGMENTS = 128,\n\tBLK_SAFE_MAX_SECTORS = 255,\n\tBLK_DEF_MAX_SECTORS = 2560,\n\tBLK_MAX_SEGMENT_SIZE = 65536,\n\tBLK_SEG_BOUNDARY_MASK = 4294967295,\n};\n\nenum {\n\tICQ_EXITED = 4,\n\tICQ_DESTROYED = 8,\n};\n\nstruct rq_map_data {\n\tstruct page **pages;\n\tint page_order;\n\tint nr_entries;\n\tlong unsigned int offset;\n\tint null_mapped;\n\tint from_user;\n};\n\nstruct bio_map_data {\n\tbool is_our_pages: 1;\n\tbool is_null_mapped: 1;\n\tstruct iov_iter iter;\n\tstruct iovec iov[0];\n};\n\nstruct req_iterator {\n\tstruct bvec_iter iter;\n\tstruct bio *bio;\n};\n\nenum bio_merge_status {\n\tBIO_MERGE_OK = 0,\n\tBIO_MERGE_NONE = 1,\n\tBIO_MERGE_FAILED = 2,\n};\n\ntypedef bool (*sb_for_each_fn)(struct sbitmap *, unsigned int, void *);\n\ntypedef bool busy_iter_fn(struct blk_mq_hw_ctx *, struct request *, void *, bool);\n\ntypedef bool busy_tag_iter_fn(struct request *, void *, bool);\n\nenum {\n\tBLK_MQ_UNIQUE_TAG_BITS = 16,\n\tBLK_MQ_UNIQUE_TAG_MASK = 65535,\n};\n\nstruct mq_inflight {\n\tstruct block_device *part;\n\tunsigned int inflight[2];\n};\n\nstruct flush_busy_ctx_data {\n\tstruct blk_mq_hw_ctx *hctx;\n\tstruct list_head *list;\n};\n\nstruct dispatch_rq_data {\n\tstruct blk_mq_hw_ctx *hctx;\n\tstruct request *rq;\n};\n\nenum prep_dispatch {\n\tPREP_DISPATCH_OK = 0,\n\tPREP_DISPATCH_NO_TAG = 1,\n\tPREP_DISPATCH_NO_BUDGET = 2,\n};\n\nstruct rq_iter_data {\n\tstruct blk_mq_hw_ctx *hctx;\n\tbool has_rq;\n};\n\nstruct blk_mq_qe_pair {\n\tstruct list_head node;\n\tstruct request_queue *q;\n\tstruct elevator_type *type;\n};\n\nstruct sbq_wait {\n\tstruct sbitmap_queue *sbq;\n\tstruct wait_queue_entry wait;\n};\n\nstruct bt_iter_data {\n\tstruct blk_mq_hw_ctx *hctx;\n\tbusy_iter_fn *fn;\n\tvoid *data;\n\tbool reserved;\n};\n\nstruct bt_tags_iter_data {\n\tstruct blk_mq_tags *tags;\n\tbusy_tag_iter_fn *fn;\n\tvoid *data;\n\tunsigned int flags;\n};\n\nstruct blk_queue_stats {\n\tstruct list_head callbacks;\n\tspinlock_t lock;\n\tbool enable_accounting;\n};\n\nstruct blk_mq_ctx_sysfs_entry {\n\tstruct attribute attr;\n\tssize_t (*show)(struct blk_mq_ctx *, char *);\n\tssize_t (*store)(struct blk_mq_ctx *, const char *, size_t);\n};\n\nstruct blk_mq_hw_ctx_sysfs_entry {\n\tstruct attribute attr;\n\tssize_t (*show)(struct blk_mq_hw_ctx *, char *);\n\tssize_t (*store)(struct blk_mq_hw_ctx *, const char *, size_t);\n};\n\ntypedef u32 compat_caddr_t;\n\nstruct hd_geometry {\n\tunsigned char heads;\n\tunsigned char sectors;\n\tshort unsigned int cylinders;\n\tlong unsigned int start;\n};\n\nstruct blkpg_ioctl_arg {\n\tint op;\n\tint flags;\n\tint datalen;\n\tvoid *data;\n};\n\nstruct blkpg_partition {\n\tlong long int start;\n\tlong long int length;\n\tint pno;\n\tchar devname[64];\n\tchar volname[64];\n};\n\nstruct pr_reservation {\n\t__u64 key;\n\t__u32 type;\n\t__u32 flags;\n};\n\nstruct pr_registration {\n\t__u64 old_key;\n\t__u64 new_key;\n\t__u32 flags;\n\t__u32 __pad;\n};\n\nstruct pr_preempt {\n\t__u64 old_key;\n\t__u64 new_key;\n\t__u32 type;\n\t__u32 flags;\n};\n\nstruct pr_clear {\n\t__u64 key;\n\t__u32 flags;\n\t__u32 __pad;\n};\n\nstruct compat_blkpg_ioctl_arg {\n\tcompat_int_t op;\n\tcompat_int_t flags;\n\tcompat_int_t datalen;\n\tcompat_caddr_t data;\n};\n\nstruct compat_hd_geometry {\n\tunsigned char heads;\n\tunsigned char sectors;\n\tshort unsigned int cylinders;\n\tu32 start;\n};\n\nstruct klist_node;\n\nstruct klist {\n\tspinlock_t k_lock;\n\tstruct list_head k_list;\n\tvoid (*get)(struct klist_node *);\n\tvoid (*put)(struct klist_node *);\n};\n\nstruct klist_node {\n\tvoid *n_klist;\n\tstruct list_head n_node;\n\tstruct kref n_ref;\n};\n\nstruct klist_iter {\n\tstruct klist *i_klist;\n\tstruct klist_node *i_cur;\n};\n\nstruct class_dev_iter {\n\tstruct klist_iter ki;\n\tconst struct device_type *type;\n};\n\nstruct badblocks {\n\tstruct device *dev;\n\tint count;\n\tint unacked_exist;\n\tint shift;\n\tu64 *page;\n\tint changed;\n\tseqlock_t lock;\n\tsector_t sector;\n\tsector_t size;\n};\n\nstruct blk_major_name {\n\tstruct blk_major_name *next;\n\tint major;\n\tchar name[16];\n\tvoid (*probe)(dev_t);\n};\n\nenum {\n\tIOPRIO_WHO_PROCESS = 1,\n\tIOPRIO_WHO_PGRP = 2,\n\tIOPRIO_WHO_USER = 3,\n};\n\nstruct parsed_partitions {\n\tstruct block_device *bdev;\n\tchar name[32];\n\tstruct {\n\t\tsector_t from;\n\t\tsector_t size;\n\t\tint flags;\n\t\tbool has_info;\n\t\tstruct partition_meta_info info;\n\t} *parts;\n\tint next;\n\tint limit;\n\tbool access_beyond_eod;\n\tchar *pp_buf;\n};\n\ntypedef struct {\n\tstruct page *v;\n} Sector;\n\nstruct lvm_rec {\n\tchar lvm_id[4];\n\tchar reserved4[16];\n\t__be32 lvmarea_len;\n\t__be32 vgda_len;\n\t__be32 vgda_psn[2];\n\tchar reserved36[10];\n\t__be16 pp_size;\n\tchar reserved46[12];\n\t__be16 version;\n};\n\nstruct vgda {\n\t__be32 secs;\n\t__be32 usec;\n\tchar reserved8[16];\n\t__be16 numlvs;\n\t__be16 maxlvs;\n\t__be16 pp_size;\n\t__be16 numpvs;\n\t__be16 total_vgdas;\n\t__be16 vgda_size;\n};\n\nstruct lvd {\n\t__be16 lv_ix;\n\t__be16 res2;\n\t__be16 res4;\n\t__be16 maxsize;\n\t__be16 lv_state;\n\t__be16 mirror;\n\t__be16 mirror_policy;\n\t__be16 num_lps;\n\t__be16 res10[8];\n};\n\nstruct lvname {\n\tchar name[64];\n};\n\nstruct ppe {\n\t__be16 lv_ix;\n\tshort unsigned int res2;\n\tshort unsigned int res4;\n\t__be16 lp_ix;\n\tshort unsigned int res8[12];\n};\n\nstruct pvd {\n\tchar reserved0[16];\n\t__be16 pp_count;\n\tchar reserved18[2];\n\t__be32 psn_part1;\n\tchar reserved24[8];\n\tstruct ppe ppe[1016];\n};\n\nstruct lv_info {\n\tshort unsigned int pps_per_lv;\n\tshort unsigned int pps_found;\n\tunsigned char lv_is_contiguous;\n};\n\nstruct mac_partition {\n\t__be16 signature;\n\t__be16 res1;\n\t__be32 map_count;\n\t__be32 start_block;\n\t__be32 block_count;\n\tchar name[32];\n\tchar type[32];\n\t__be32 data_start;\n\t__be32 data_count;\n\t__be32 status;\n\t__be32 boot_start;\n\t__be32 boot_size;\n\t__be32 boot_load;\n\t__be32 boot_load2;\n\t__be32 boot_entry;\n\t__be32 boot_entry2;\n\t__be32 boot_cksum;\n\tchar processor[16];\n};\n\nstruct mac_driver_desc {\n\t__be16 signature;\n\t__be16 block_size;\n\t__be32 block_count;\n};\n\nstruct msdos_partition {\n\tu8 boot_ind;\n\tu8 head;\n\tu8 sector;\n\tu8 cyl;\n\tu8 sys_ind;\n\tu8 end_head;\n\tu8 end_sector;\n\tu8 end_cyl;\n\t__le32 start_sect;\n\t__le32 nr_sects;\n};\n\nstruct frag {\n\tstruct list_head list;\n\tu32 group;\n\tu8 num;\n\tu8 rec;\n\tu8 map;\n\tu8 data[0];\n};\n\nstruct privhead {\n\tu16 ver_major;\n\tu16 ver_minor;\n\tu64 logical_disk_start;\n\tu64 logical_disk_size;\n\tu64 config_start;\n\tu64 config_size;\n\tuuid_t disk_id;\n};\n\nstruct tocblock {\n\tu8 bitmap1_name[16];\n\tu64 bitmap1_start;\n\tu64 bitmap1_size;\n\tu8 bitmap2_name[16];\n\tu64 bitmap2_start;\n\tu64 bitmap2_size;\n};\n\nstruct vmdb {\n\tu16 ver_major;\n\tu16 ver_minor;\n\tu32 vblk_size;\n\tu32 vblk_offset;\n\tu32 last_vblk_seq;\n};\n\nstruct vblk_comp {\n\tu8 state[16];\n\tu64 parent_id;\n\tu8 type;\n\tu8 children;\n\tu16 chunksize;\n};\n\nstruct vblk_dgrp {\n\tu8 disk_id[64];\n};\n\nstruct vblk_disk {\n\tuuid_t disk_id;\n\tu8 alt_name[128];\n};\n\nstruct vblk_part {\n\tu64 start;\n\tu64 size;\n\tu64 volume_offset;\n\tu64 parent_id;\n\tu64 disk_id;\n\tu8 partnum;\n};\n\nstruct vblk_volu {\n\tu8 volume_type[16];\n\tu8 volume_state[16];\n\tu8 guid[16];\n\tu8 drive_hint[4];\n\tu64 size;\n\tu8 partition_type;\n};\n\nstruct vblk {\n\tu8 name[64];\n\tu64 obj_id;\n\tu32 sequence;\n\tu8 flags;\n\tu8 type;\n\tunion {\n\t\tstruct vblk_comp comp;\n\t\tstruct vblk_dgrp dgrp;\n\t\tstruct vblk_disk disk;\n\t\tstruct vblk_part part;\n\t\tstruct vblk_volu volu;\n\t} vblk;\n\tstruct list_head list;\n};\n\nstruct ldmdb {\n\tstruct privhead ph;\n\tstruct tocblock toc;\n\tstruct vmdb vm;\n\tstruct list_head v_dgrp;\n\tstruct list_head v_disk;\n\tstruct list_head v_volu;\n\tstruct list_head v_comp;\n\tstruct list_head v_part;\n};\n\nstruct fat_boot_sector {\n\t__u8 ignored[3];\n\t__u8 system_id[8];\n\t__u8 sector_size[2];\n\t__u8 sec_per_clus;\n\t__le16 reserved;\n\t__u8 fats;\n\t__u8 dir_entries[2];\n\t__u8 sectors[2];\n\t__u8 media;\n\t__le16 fat_length;\n\t__le16 secs_track;\n\t__le16 heads;\n\t__le32 hidden;\n\t__le32 total_sect;\n\tunion {\n\t\tstruct {\n\t\t\t__u8 drive_number;\n\t\t\t__u8 state;\n\t\t\t__u8 signature;\n\t\t\t__u8 vol_id[4];\n\t\t\t__u8 vol_label[11];\n\t\t\t__u8 fs_type[8];\n\t\t} fat16;\n\t\tstruct {\n\t\t\t__le32 length;\n\t\t\t__le16 flags;\n\t\t\t__u8 version[2];\n\t\t\t__le32 root_cluster;\n\t\t\t__le16 info_sector;\n\t\t\t__le16 backup_boot;\n\t\t\t__le16 reserved2[6];\n\t\t\t__u8 drive_number;\n\t\t\t__u8 state;\n\t\t\t__u8 signature;\n\t\t\t__u8 vol_id[4];\n\t\t\t__u8 vol_label[11];\n\t\t\t__u8 fs_type[8];\n\t\t} fat32;\n\t};\n};\n\nenum msdos_sys_ind {\n\tDOS_EXTENDED_PARTITION = 5,\n\tLINUX_EXTENDED_PARTITION = 133,\n\tWIN98_EXTENDED_PARTITION = 15,\n\tLINUX_DATA_PARTITION = 131,\n\tLINUX_LVM_PARTITION = 142,\n\tLINUX_RAID_PARTITION = 253,\n\tSOLARIS_X86_PARTITION = 130,\n\tNEW_SOLARIS_X86_PARTITION = 191,\n\tDM6_AUX1PARTITION = 81,\n\tDM6_AUX3PARTITION = 83,\n\tDM6_PARTITION = 84,\n\tEZD_PARTITION = 85,\n\tFREEBSD_PARTITION = 165,\n\tOPENBSD_PARTITION = 166,\n\tNETBSD_PARTITION = 169,\n\tBSDI_PARTITION = 183,\n\tMINIX_PARTITION = 129,\n\tUNIXWARE_PARTITION = 99,\n};\n\nstruct solaris_x86_slice {\n\t__le16 s_tag;\n\t__le16 s_flag;\n\t__le32 s_start;\n\t__le32 s_size;\n};\n\nstruct solaris_x86_vtoc {\n\tunsigned int v_bootinfo[3];\n\t__le32 v_sanity;\n\t__le32 v_version;\n\tchar v_volume[8];\n\t__le16 v_sectorsz;\n\t__le16 v_nparts;\n\tunsigned int v_reserved[10];\n\tstruct solaris_x86_slice v_slice[16];\n\tunsigned int timestamp[16];\n\tchar v_asciilabel[128];\n};\n\nstruct bsd_partition {\n\t__le32 p_size;\n\t__le32 p_offset;\n\t__le32 p_fsize;\n\t__u8 p_fstype;\n\t__u8 p_frag;\n\t__le16 p_cpg;\n};\n\nstruct bsd_disklabel {\n\t__le32 d_magic;\n\t__s16 d_type;\n\t__s16 d_subtype;\n\tchar d_typename[16];\n\tchar d_packname[16];\n\t__u32 d_secsize;\n\t__u32 d_nsectors;\n\t__u32 d_ntracks;\n\t__u32 d_ncylinders;\n\t__u32 d_secpercyl;\n\t__u32 d_secperunit;\n\t__u16 d_sparespertrack;\n\t__u16 d_sparespercyl;\n\t__u32 d_acylinders;\n\t__u16 d_rpm;\n\t__u16 d_interleave;\n\t__u16 d_trackskew;\n\t__u16 d_cylskew;\n\t__u32 d_headswitch;\n\t__u32 d_trkseek;\n\t__u32 d_flags;\n\t__u32 d_drivedata[5];\n\t__u32 d_spare[5];\n\t__le32 d_magic2;\n\t__le16 d_checksum;\n\t__le16 d_npartitions;\n\t__le32 d_bbsize;\n\t__le32 d_sbsize;\n\tstruct bsd_partition d_partitions[16];\n};\n\nstruct _gpt_header {\n\t__le64 signature;\n\t__le32 revision;\n\t__le32 header_size;\n\t__le32 header_crc32;\n\t__le32 reserved1;\n\t__le64 my_lba;\n\t__le64 alternate_lba;\n\t__le64 first_usable_lba;\n\t__le64 last_usable_lba;\n\tefi_guid_t disk_guid;\n\t__le64 partition_entry_lba;\n\t__le32 num_partition_entries;\n\t__le32 sizeof_partition_entry;\n\t__le32 partition_entry_array_crc32;\n} __attribute__((packed));\n\ntypedef struct _gpt_header gpt_header;\n\nstruct _gpt_entry_attributes {\n\tu64 required_to_function: 1;\n\tu64 reserved: 47;\n\tu64 type_guid_specific: 16;\n};\n\ntypedef struct _gpt_entry_attributes gpt_entry_attributes;\n\nstruct _gpt_entry {\n\tefi_guid_t partition_type_guid;\n\tefi_guid_t unique_partition_guid;\n\t__le64 starting_lba;\n\t__le64 ending_lba;\n\tgpt_entry_attributes attributes;\n\t__le16 partition_name[36];\n};\n\ntypedef struct _gpt_entry gpt_entry;\n\nstruct _gpt_mbr_record {\n\tu8 boot_indicator;\n\tu8 start_head;\n\tu8 start_sector;\n\tu8 start_track;\n\tu8 os_type;\n\tu8 end_head;\n\tu8 end_sector;\n\tu8 end_track;\n\t__le32 starting_lba;\n\t__le32 size_in_lba;\n};\n\ntypedef struct _gpt_mbr_record gpt_mbr_record;\n\nstruct _legacy_mbr {\n\tu8 boot_code[440];\n\t__le32 unique_mbr_signature;\n\t__le16 unknown;\n\tgpt_mbr_record partition_record[4];\n\t__le16 signature;\n} __attribute__((packed));\n\ntypedef struct _legacy_mbr legacy_mbr;\n\nstruct d_partition {\n\t__le32 p_res;\n\tu8 p_fstype;\n\tu8 p_res2[3];\n\t__le32 p_offset;\n\t__le32 p_size;\n};\n\nstruct disklabel {\n\tu8 d_reserved[270];\n\tstruct d_partition d_partitions[2];\n\tu8 d_blank[208];\n\t__le16 d_magic;\n} __attribute__((packed));\n\nstruct rq_wait {\n\twait_queue_head_t wait;\n\tatomic_t inflight;\n};\n\nstruct rq_depth {\n\tunsigned int max_depth;\n\tint scale_step;\n\tbool scaled_max;\n\tunsigned int queue_depth;\n\tunsigned int default_depth;\n};\n\ntypedef bool acquire_inflight_cb_t(struct rq_wait *, void *);\n\ntypedef void cleanup_cb_t(struct rq_wait *, void *);\n\nstruct rq_qos_wait_data {\n\tstruct wait_queue_entry wq;\n\tstruct task_struct *task;\n\tstruct rq_wait *rqw;\n\tacquire_inflight_cb_t *cb;\n\tvoid *private_data;\n\tbool got_token;\n};\n\nenum {\n\tDISK_EVENT_FLAG_POLL = 1,\n\tDISK_EVENT_FLAG_UEVENT = 2,\n};\n\nstruct disk_events {\n\tstruct list_head node;\n\tstruct gendisk *disk;\n\tspinlock_t lock;\n\tstruct mutex block_mutex;\n\tint block;\n\tunsigned int pending;\n\tunsigned int clearing;\n\tlong int poll_msecs;\n\tstruct delayed_work dwork;\n};\n\nstruct cdrom_device_ops;\n\nstruct cdrom_device_info {\n\tconst struct cdrom_device_ops *ops;\n\tstruct list_head list;\n\tstruct gendisk *disk;\n\tvoid *handle;\n\tint mask;\n\tint speed;\n\tint capacity;\n\tunsigned int options: 30;\n\tunsigned int mc_flags: 2;\n\tunsigned int vfs_events;\n\tunsigned int ioctl_events;\n\tint use_count;\n\tchar name[20];\n\t__u8 sanyo_slot: 2;\n\t__u8 keeplocked: 1;\n\t__u8 reserved: 5;\n\tint cdda_method;\n\t__u8 last_sense;\n\t__u8 media_written;\n\tshort unsigned int mmc3_profile;\n\tint for_data;\n\tint (*exit)(struct cdrom_device_info *);\n\tint mrw_mode_page;\n};\n\nenum sam_status {\n\tSAM_STAT_GOOD = 0,\n\tSAM_STAT_CHECK_CONDITION = 2,\n\tSAM_STAT_CONDITION_MET = 4,\n\tSAM_STAT_BUSY = 8,\n\tSAM_STAT_INTERMEDIATE = 16,\n\tSAM_STAT_INTERMEDIATE_CONDITION_MET = 20,\n\tSAM_STAT_RESERVATION_CONFLICT = 24,\n\tSAM_STAT_COMMAND_TERMINATED = 34,\n\tSAM_STAT_TASK_SET_FULL = 40,\n\tSAM_STAT_ACA_ACTIVE = 48,\n\tSAM_STAT_TASK_ABORTED = 64,\n};\n\nstruct scsi_sense_hdr {\n\tu8 response_code;\n\tu8 sense_key;\n\tu8 asc;\n\tu8 ascq;\n\tu8 byte4;\n\tu8 byte5;\n\tu8 byte6;\n\tu8 additional_length;\n};\n\nstruct cdrom_msf0 {\n\t__u8 minute;\n\t__u8 second;\n\t__u8 frame;\n};\n\nunion cdrom_addr {\n\tstruct cdrom_msf0 msf;\n\tint lba;\n};\n\nstruct cdrom_multisession {\n\tunion cdrom_addr addr;\n\t__u8 xa_flag;\n\t__u8 addr_format;\n};\n\nstruct cdrom_mcn {\n\t__u8 medium_catalog_number[14];\n};\n\nstruct request_sense;\n\nstruct cdrom_generic_command {\n\tunsigned char cmd[12];\n\tunsigned char *buffer;\n\tunsigned int buflen;\n\tint stat;\n\tstruct request_sense *sense;\n\tunsigned char data_direction;\n\tint quiet;\n\tint timeout;\n\tunion {\n\t\tvoid *reserved[1];\n\t\tvoid *unused;\n\t};\n};\n\nstruct request_sense {\n\t__u8 error_code: 7;\n\t__u8 valid: 1;\n\t__u8 segment_number;\n\t__u8 sense_key: 4;\n\t__u8 reserved2: 1;\n\t__u8 ili: 1;\n\t__u8 reserved1: 2;\n\t__u8 information[4];\n\t__u8 add_sense_len;\n\t__u8 command_info[4];\n\t__u8 asc;\n\t__u8 ascq;\n\t__u8 fruc;\n\t__u8 sks[3];\n\t__u8 asb[46];\n};\n\nstruct packet_command {\n\tunsigned char cmd[12];\n\tunsigned char *buffer;\n\tunsigned int buflen;\n\tint stat;\n\tstruct scsi_sense_hdr *sshdr;\n\tunsigned char data_direction;\n\tint quiet;\n\tint timeout;\n\tvoid *reserved[1];\n};\n\nstruct cdrom_device_ops {\n\tint (*open)(struct cdrom_device_info *, int);\n\tvoid (*release)(struct cdrom_device_info *);\n\tint (*drive_status)(struct cdrom_device_info *, int);\n\tunsigned int (*check_events)(struct cdrom_device_info *, unsigned int, int);\n\tint (*tray_move)(struct cdrom_device_info *, int);\n\tint (*lock_door)(struct cdrom_device_info *, int);\n\tint (*select_speed)(struct cdrom_device_info *, int);\n\tint (*select_disc)(struct cdrom_device_info *, int);\n\tint (*get_last_session)(struct cdrom_device_info *, struct cdrom_multisession *);\n\tint (*get_mcn)(struct cdrom_device_info *, struct cdrom_mcn *);\n\tint (*reset)(struct cdrom_device_info *);\n\tint (*audio_ioctl)(struct cdrom_device_info *, unsigned int, void *);\n\tconst int capability;\n\tint (*generic_packet)(struct cdrom_device_info *, struct packet_command *);\n};\n\nenum scsi_msg_byte {\n\tCOMMAND_COMPLETE = 0,\n\tEXTENDED_MESSAGE = 1,\n\tSAVE_POINTERS = 2,\n\tRESTORE_POINTERS = 3,\n\tDISCONNECT = 4,\n\tINITIATOR_ERROR = 5,\n\tABORT_TASK_SET = 6,\n\tMESSAGE_REJECT = 7,\n\tNOP___2 = 8,\n\tMSG_PARITY_ERROR = 9,\n\tLINKED_CMD_COMPLETE = 10,\n\tLINKED_FLG_CMD_COMPLETE = 11,\n\tTARGET_RESET = 12,\n\tABORT_TASK = 13,\n\tCLEAR_TASK_SET = 14,\n\tINITIATE_RECOVERY = 15,\n\tRELEASE_RECOVERY = 16,\n\tTERMINATE_IO_PROC = 17,\n\tCLEAR_ACA = 22,\n\tLOGICAL_UNIT_RESET = 23,\n\tSIMPLE_QUEUE_TAG = 32,\n\tHEAD_OF_QUEUE_TAG = 33,\n\tORDERED_QUEUE_TAG = 34,\n\tIGNORE_WIDE_RESIDUE = 35,\n\tACA = 36,\n\tQAS_REQUEST = 85,\n\tBUS_DEVICE_RESET = 12,\n\tABORT = 6,\n};\n\nstruct scsi_ioctl_command {\n\tunsigned int inlen;\n\tunsigned int outlen;\n\tunsigned char data[0];\n};\n\nenum scsi_device_event {\n\tSDEV_EVT_MEDIA_CHANGE = 1,\n\tSDEV_EVT_INQUIRY_CHANGE_REPORTED = 2,\n\tSDEV_EVT_CAPACITY_CHANGE_REPORTED = 3,\n\tSDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED = 4,\n\tSDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED = 5,\n\tSDEV_EVT_LUN_CHANGE_REPORTED = 6,\n\tSDEV_EVT_ALUA_STATE_CHANGE_REPORTED = 7,\n\tSDEV_EVT_POWER_ON_RESET_OCCURRED = 8,\n\tSDEV_EVT_FIRST = 1,\n\tSDEV_EVT_LAST = 8,\n\tSDEV_EVT_MAXBITS = 9,\n};\n\nstruct scsi_request {\n\tunsigned char __cmd[16];\n\tunsigned char *cmd;\n\tshort unsigned int cmd_len;\n\tint result;\n\tunsigned int sense_len;\n\tunsigned int resid_len;\n\tint retries;\n\tvoid *sense;\n};\n\nstruct sg_io_hdr {\n\tint interface_id;\n\tint dxfer_direction;\n\tunsigned char cmd_len;\n\tunsigned char mx_sb_len;\n\tshort unsigned int iovec_count;\n\tunsigned int dxfer_len;\n\tvoid *dxferp;\n\tunsigned char *cmdp;\n\tvoid *sbp;\n\tunsigned int timeout;\n\tunsigned int flags;\n\tint pack_id;\n\tvoid *usr_ptr;\n\tunsigned char status;\n\tunsigned char masked_status;\n\tunsigned char msg_status;\n\tunsigned char sb_len_wr;\n\tshort unsigned int host_status;\n\tshort unsigned int driver_status;\n\tint resid;\n\tunsigned int duration;\n\tunsigned int info;\n};\n\nstruct compat_sg_io_hdr {\n\tcompat_int_t interface_id;\n\tcompat_int_t dxfer_direction;\n\tunsigned char cmd_len;\n\tunsigned char mx_sb_len;\n\tshort unsigned int iovec_count;\n\tcompat_uint_t dxfer_len;\n\tcompat_uint_t dxferp;\n\tcompat_uptr_t cmdp;\n\tcompat_uptr_t sbp;\n\tcompat_uint_t timeout;\n\tcompat_uint_t flags;\n\tcompat_int_t pack_id;\n\tcompat_uptr_t usr_ptr;\n\tunsigned char status;\n\tunsigned char masked_status;\n\tunsigned char msg_status;\n\tunsigned char sb_len_wr;\n\tshort unsigned int host_status;\n\tshort unsigned int driver_status;\n\tcompat_int_t resid;\n\tcompat_uint_t duration;\n\tcompat_uint_t info;\n};\n\nstruct blk_cmd_filter {\n\tlong unsigned int read_ok[4];\n\tlong unsigned int write_ok[4];\n};\n\nstruct compat_cdrom_generic_command {\n\tunsigned char cmd[12];\n\tcompat_caddr_t buffer;\n\tcompat_uint_t buflen;\n\tcompat_int_t stat;\n\tcompat_caddr_t sense;\n\tunsigned char data_direction;\n\tunsigned char pad[3];\n\tcompat_int_t quiet;\n\tcompat_int_t timeout;\n\tcompat_caddr_t unused;\n};\n\nenum {\n\tOMAX_SB_LEN = 16,\n};\n\nstruct bsg_device {\n\tstruct request_queue *queue;\n\tspinlock_t lock;\n\tstruct hlist_node dev_list;\n\trefcount_t ref_count;\n\tchar name[20];\n\tint max_queue;\n};\n\nstruct bsg_job;\n\ntypedef int bsg_job_fn(struct bsg_job *);\n\nstruct bsg_buffer {\n\tunsigned int payload_len;\n\tint sg_cnt;\n\tstruct scatterlist *sg_list;\n};\n\nstruct bsg_job {\n\tstruct device *dev;\n\tstruct kref kref;\n\tunsigned int timeout;\n\tvoid *request;\n\tvoid *reply;\n\tunsigned int request_len;\n\tunsigned int reply_len;\n\tstruct bsg_buffer request_payload;\n\tstruct bsg_buffer reply_payload;\n\tint result;\n\tunsigned int reply_payload_rcv_len;\n\tstruct request *bidi_rq;\n\tstruct bio *bidi_bio;\n\tvoid *dd_data;\n};\n\ntypedef enum blk_eh_timer_return bsg_timeout_fn(struct request *);\n\nstruct bsg_set {\n\tstruct blk_mq_tag_set tag_set;\n\tbsg_job_fn *job_fn;\n\tbsg_timeout_fn *timeout_fn;\n};\n\ntypedef struct blkcg_policy_data *blkcg_pol_alloc_cpd_fn(gfp_t);\n\ntypedef void blkcg_pol_init_cpd_fn(struct blkcg_policy_data *);\n\ntypedef void blkcg_pol_free_cpd_fn(struct blkcg_policy_data *);\n\ntypedef void blkcg_pol_bind_cpd_fn(struct blkcg_policy_data *);\n\ntypedef struct blkg_policy_data *blkcg_pol_alloc_pd_fn(gfp_t, struct request_queue *, struct blkcg *);\n\ntypedef void blkcg_pol_init_pd_fn(struct blkg_policy_data *);\n\ntypedef void blkcg_pol_online_pd_fn(struct blkg_policy_data *);\n\ntypedef void blkcg_pol_offline_pd_fn(struct blkg_policy_data *);\n\ntypedef void blkcg_pol_free_pd_fn(struct blkg_policy_data *);\n\ntypedef void blkcg_pol_reset_pd_stats_fn(struct blkg_policy_data *);\n\ntypedef size_t blkcg_pol_stat_pd_fn(struct blkg_policy_data *, char *, size_t);\n\nstruct blkcg_policy {\n\tint plid;\n\tstruct cftype *dfl_cftypes;\n\tstruct cftype *legacy_cftypes;\n\tblkcg_pol_alloc_cpd_fn *cpd_alloc_fn;\n\tblkcg_pol_init_cpd_fn *cpd_init_fn;\n\tblkcg_pol_free_cpd_fn *cpd_free_fn;\n\tblkcg_pol_bind_cpd_fn *cpd_bind_fn;\n\tblkcg_pol_alloc_pd_fn *pd_alloc_fn;\n\tblkcg_pol_init_pd_fn *pd_init_fn;\n\tblkcg_pol_online_pd_fn *pd_online_fn;\n\tblkcg_pol_offline_pd_fn *pd_offline_fn;\n\tblkcg_pol_free_pd_fn *pd_free_fn;\n\tblkcg_pol_reset_pd_stats_fn *pd_reset_stats_fn;\n\tblkcg_pol_stat_pd_fn *pd_stat_fn;\n};\n\nstruct blkg_conf_ctx {\n\tstruct block_device *bdev;\n\tstruct blkcg_gq *blkg;\n\tchar *body;\n};\n\nenum blkg_rwstat_type {\n\tBLKG_RWSTAT_READ = 0,\n\tBLKG_RWSTAT_WRITE = 1,\n\tBLKG_RWSTAT_SYNC = 2,\n\tBLKG_RWSTAT_ASYNC = 3,\n\tBLKG_RWSTAT_DISCARD = 4,\n\tBLKG_RWSTAT_NR = 5,\n\tBLKG_RWSTAT_TOTAL = 5,\n};\n\nstruct blkg_rwstat {\n\tstruct percpu_counter cpu_cnt[5];\n\tatomic64_t aux_cnt[5];\n};\n\nstruct blkg_rwstat_sample {\n\tu64 cnt[5];\n};\n\nstruct throtl_service_queue {\n\tstruct throtl_service_queue *parent_sq;\n\tstruct list_head queued[2];\n\tunsigned int nr_queued[2];\n\tstruct rb_root_cached pending_tree;\n\tunsigned int nr_pending;\n\tlong unsigned int first_pending_disptime;\n\tstruct timer_list pending_timer;\n};\n\nstruct latency_bucket {\n\tlong unsigned int total_latency;\n\tint samples;\n};\n\nstruct avg_latency_bucket {\n\tlong unsigned int latency;\n\tbool valid;\n};\n\nstruct throtl_data {\n\tstruct throtl_service_queue service_queue;\n\tstruct request_queue *queue;\n\tunsigned int nr_queued[2];\n\tunsigned int throtl_slice;\n\tstruct work_struct dispatch_work;\n\tunsigned int limit_index;\n\tbool limit_valid[2];\n\tlong unsigned int low_upgrade_time;\n\tlong unsigned int low_downgrade_time;\n\tunsigned int scale;\n\tstruct latency_bucket tmp_buckets[18];\n\tstruct avg_latency_bucket avg_buckets[18];\n\tstruct latency_bucket *latency_buckets[2];\n\tlong unsigned int last_calculate_time;\n\tlong unsigned int filtered_latency;\n\tbool track_bio_latency;\n};\n\nstruct throtl_grp;\n\nstruct throtl_qnode {\n\tstruct list_head node;\n\tstruct bio_list bios;\n\tstruct throtl_grp *tg;\n};\n\nstruct throtl_grp {\n\tstruct blkg_policy_data pd;\n\tstruct rb_node rb_node;\n\tstruct throtl_data *td;\n\tstruct throtl_service_queue service_queue;\n\tstruct throtl_qnode qnode_on_self[2];\n\tstruct throtl_qnode qnode_on_parent[2];\n\tlong unsigned int disptime;\n\tunsigned int flags;\n\tbool has_rules[2];\n\tuint64_t bps[4];\n\tuint64_t bps_conf[4];\n\tunsigned int iops[4];\n\tunsigned int iops_conf[4];\n\tuint64_t bytes_disp[2];\n\tunsigned int io_disp[2];\n\tlong unsigned int last_low_overflow_time[2];\n\tuint64_t last_bytes_disp[2];\n\tunsigned int last_io_disp[2];\n\tlong unsigned int last_check_time;\n\tlong unsigned int latency_target;\n\tlong unsigned int latency_target_conf;\n\tlong unsigned int slice_start[2];\n\tlong unsigned int slice_end[2];\n\tlong unsigned int last_finish_time;\n\tlong unsigned int checked_last_finish_time;\n\tlong unsigned int avg_idletime;\n\tlong unsigned int idletime_threshold;\n\tlong unsigned int idletime_threshold_conf;\n\tunsigned int bio_cnt;\n\tunsigned int bad_bio_cnt;\n\tlong unsigned int bio_cnt_reset_time;\n\tstruct blkg_rwstat stat_bytes;\n\tstruct blkg_rwstat stat_ios;\n};\n\nenum tg_state_flags {\n\tTHROTL_TG_PENDING = 1,\n\tTHROTL_TG_WAS_EMPTY = 2,\n};\n\nenum {\n\tLIMIT_LOW = 0,\n\tLIMIT_MAX = 1,\n\tLIMIT_CNT = 2,\n};\n\nenum prio_policy {\n\tPOLICY_NO_CHANGE = 0,\n\tPOLICY_NONE_TO_RT = 1,\n\tPOLICY_RESTRICT_TO_BE = 2,\n\tPOLICY_ALL_TO_IDLE = 3,\n};\n\nstruct ioprio_blkg {\n\tstruct blkg_policy_data pd;\n};\n\nstruct ioprio_blkcg {\n\tstruct blkcg_policy_data cpd;\n\tenum prio_policy prio_policy;\n};\n\nstruct blk_ioprio {\n\tstruct rq_qos rqos;\n};\n\nstruct blk_iolatency {\n\tstruct rq_qos rqos;\n\tstruct timer_list timer;\n\tatomic_t enabled;\n};\n\nstruct iolatency_grp;\n\nstruct child_latency_info {\n\tspinlock_t lock;\n\tu64 last_scale_event;\n\tu64 scale_lat;\n\tu64 nr_samples;\n\tstruct iolatency_grp *scale_grp;\n\tatomic_t scale_cookie;\n};\n\nstruct percentile_stats {\n\tu64 total;\n\tu64 missed;\n};\n\nstruct latency_stat {\n\tunion {\n\t\tstruct percentile_stats ps;\n\t\tstruct blk_rq_stat rqs;\n\t};\n};\n\nstruct iolatency_grp {\n\tstruct blkg_policy_data pd;\n\tstruct latency_stat *stats;\n\tstruct latency_stat cur_stat;\n\tstruct blk_iolatency *blkiolat;\n\tstruct rq_depth rq_depth;\n\tstruct rq_wait rq_wait;\n\tatomic64_t window_start;\n\tatomic_t scale_cookie;\n\tu64 min_lat_nsec;\n\tu64 cur_win_nsec;\n\tu64 lat_avg;\n\tu64 nr_samples;\n\tbool ssd;\n\tstruct child_latency_info child_lat;\n};\n\nenum {\n\tMILLION = 1000000,\n\tMIN_PERIOD = 1000,\n\tMAX_PERIOD = 1000000,\n\tMARGIN_MIN_PCT = 10,\n\tMARGIN_LOW_PCT = 20,\n\tMARGIN_TARGET_PCT = 50,\n\tINUSE_ADJ_STEP_PCT = 25,\n\tTIMER_SLACK_PCT = 1,\n\tWEIGHT_ONE = 65536,\n\tVTIME_PER_SEC_SHIFT = 37,\n\tVTIME_PER_SEC = 0,\n\tVTIME_PER_USEC = 137438,\n\tVTIME_PER_NSEC = 137,\n\tVRATE_MIN_PPM = 10000,\n\tVRATE_MAX_PPM = 100000000,\n\tVRATE_MIN = 1374,\n\tVRATE_CLAMP_ADJ_PCT = 4,\n\tRQ_WAIT_BUSY_PCT = 5,\n\tUNBUSY_THR_PCT = 75,\n\tMIN_DELAY_THR_PCT = 500,\n\tMAX_DELAY_THR_PCT = 25000,\n\tMIN_DELAY = 250,\n\tMAX_DELAY = 250000,\n\tDFGV_USAGE_PCT = 50,\n\tDFGV_PERIOD = 100000,\n\tMAX_LAGGING_PERIODS = 10,\n\tAUTOP_CYCLE_NSEC = 1410065408,\n\tIOC_PAGE_SHIFT = 12,\n\tIOC_PAGE_SIZE = 4096,\n\tIOC_SECT_TO_PAGE_SHIFT = 3,\n\tLCOEF_RANDIO_PAGES = 4096,\n};\n\nenum ioc_running {\n\tIOC_IDLE = 0,\n\tIOC_RUNNING = 1,\n\tIOC_STOP = 2,\n};\n\nenum {\n\tQOS_ENABLE = 0,\n\tQOS_CTRL = 1,\n\tNR_QOS_CTRL_PARAMS = 2,\n};\n\nenum {\n\tQOS_RPPM = 0,\n\tQOS_RLAT = 1,\n\tQOS_WPPM = 2,\n\tQOS_WLAT = 3,\n\tQOS_MIN = 4,\n\tQOS_MAX = 5,\n\tNR_QOS_PARAMS = 6,\n};\n\nenum {\n\tCOST_CTRL = 0,\n\tCOST_MODEL = 1,\n\tNR_COST_CTRL_PARAMS = 2,\n};\n\nenum {\n\tI_LCOEF_RBPS = 0,\n\tI_LCOEF_RSEQIOPS = 1,\n\tI_LCOEF_RRANDIOPS = 2,\n\tI_LCOEF_WBPS = 3,\n\tI_LCOEF_WSEQIOPS = 4,\n\tI_LCOEF_WRANDIOPS = 5,\n\tNR_I_LCOEFS = 6,\n};\n\nenum {\n\tLCOEF_RPAGE = 0,\n\tLCOEF_RSEQIO = 1,\n\tLCOEF_RRANDIO = 2,\n\tLCOEF_WPAGE = 3,\n\tLCOEF_WSEQIO = 4,\n\tLCOEF_WRANDIO = 5,\n\tNR_LCOEFS = 6,\n};\n\nenum {\n\tAUTOP_INVALID = 0,\n\tAUTOP_HDD = 1,\n\tAUTOP_SSD_QD1 = 2,\n\tAUTOP_SSD_DFL = 3,\n\tAUTOP_SSD_FAST = 4,\n};\n\nstruct ioc_params {\n\tu32 qos[6];\n\tu64 i_lcoefs[6];\n\tu64 lcoefs[6];\n\tu32 too_fast_vrate_pct;\n\tu32 too_slow_vrate_pct;\n};\n\nstruct ioc_margins {\n\ts64 min;\n\ts64 low;\n\ts64 target;\n};\n\nstruct ioc_missed {\n\tlocal_t nr_met;\n\tlocal_t nr_missed;\n\tu32 last_met;\n\tu32 last_missed;\n};\n\nstruct ioc_pcpu_stat {\n\tstruct ioc_missed missed[2];\n\tlocal64_t rq_wait_ns;\n\tu64 last_rq_wait_ns;\n};\n\nstruct ioc {\n\tstruct rq_qos rqos;\n\tbool enabled;\n\tstruct ioc_params params;\n\tstruct ioc_margins margins;\n\tu32 period_us;\n\tu32 timer_slack_ns;\n\tu64 vrate_min;\n\tu64 vrate_max;\n\tspinlock_t lock;\n\tstruct timer_list timer;\n\tstruct list_head active_iocgs;\n\tstruct ioc_pcpu_stat *pcpu_stat;\n\tenum ioc_running running;\n\tatomic64_t vtime_rate;\n\tu64 vtime_base_rate;\n\ts64 vtime_err;\n\tseqcount_spinlock_t period_seqcount;\n\tu64 period_at;\n\tu64 period_at_vtime;\n\tatomic64_t cur_period;\n\tint busy_level;\n\tbool weights_updated;\n\tatomic_t hweight_gen;\n\tu64 dfgv_period_at;\n\tu64 dfgv_period_rem;\n\tu64 dfgv_usage_us_sum;\n\tu64 autop_too_fast_at;\n\tu64 autop_too_slow_at;\n\tint autop_idx;\n\tbool user_qos_params: 1;\n\tbool user_cost_model: 1;\n};\n\nstruct iocg_pcpu_stat {\n\tlocal64_t abs_vusage;\n};\n\nstruct iocg_stat {\n\tu64 usage_us;\n\tu64 wait_us;\n\tu64 indebt_us;\n\tu64 indelay_us;\n};\n\nstruct ioc_gq {\n\tstruct blkg_policy_data pd;\n\tstruct ioc *ioc;\n\tu32 cfg_weight;\n\tu32 weight;\n\tu32 active;\n\tu32 inuse;\n\tu32 last_inuse;\n\ts64 saved_margin;\n\tsector_t cursor;\n\tatomic64_t vtime;\n\tatomic64_t done_vtime;\n\tu64 abs_vdebt;\n\tu64 delay;\n\tu64 delay_at;\n\tatomic64_t active_period;\n\tstruct list_head active_list;\n\tu64 child_active_sum;\n\tu64 child_inuse_sum;\n\tu64 child_adjusted_sum;\n\tint hweight_gen;\n\tu32 hweight_active;\n\tu32 hweight_inuse;\n\tu32 hweight_donating;\n\tu32 hweight_after_donation;\n\tstruct list_head walk_list;\n\tstruct list_head surplus_list;\n\tstruct wait_queue_head waitq;\n\tstruct hrtimer waitq_timer;\n\tu64 activated_at;\n\tstruct iocg_pcpu_stat *pcpu_stat;\n\tstruct iocg_stat local_stat;\n\tstruct iocg_stat desc_stat;\n\tstruct iocg_stat last_stat;\n\tu64 last_stat_abs_vusage;\n\tu64 usage_delta_us;\n\tu64 wait_since;\n\tu64 indebt_since;\n\tu64 indelay_since;\n\tint level;\n\tstruct ioc_gq *ancestors[0];\n};\n\nstruct ioc_cgrp {\n\tstruct blkcg_policy_data cpd;\n\tunsigned int dfl_weight;\n};\n\nstruct ioc_now {\n\tu64 now_ns;\n\tu64 now;\n\tu64 vnow;\n\tu64 vrate;\n};\n\nstruct iocg_wait {\n\tstruct wait_queue_entry wait;\n\tstruct bio *bio;\n\tu64 abs_cost;\n\tbool committed;\n};\n\nstruct iocg_wake_ctx {\n\tstruct ioc_gq *iocg;\n\tu32 hw_inuse;\n\ts64 vbudget;\n};\n\nstruct trace_event_raw_iocost_iocg_state {\n\tstruct trace_entry ent;\n\tu32 __data_loc_devname;\n\tu32 __data_loc_cgroup;\n\tu64 now;\n\tu64 vnow;\n\tu64 vrate;\n\tu64 last_period;\n\tu64 cur_period;\n\tu64 vtime;\n\tu32 weight;\n\tu32 inuse;\n\tu64 hweight_active;\n\tu64 hweight_inuse;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iocg_inuse_update {\n\tstruct trace_entry ent;\n\tu32 __data_loc_devname;\n\tu32 __data_loc_cgroup;\n\tu64 now;\n\tu32 old_inuse;\n\tu32 new_inuse;\n\tu64 old_hweight_inuse;\n\tu64 new_hweight_inuse;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iocost_ioc_vrate_adj {\n\tstruct trace_entry ent;\n\tu32 __data_loc_devname;\n\tu64 old_vrate;\n\tu64 new_vrate;\n\tint busy_level;\n\tu32 read_missed_ppm;\n\tu32 write_missed_ppm;\n\tu32 rq_wait_pct;\n\tint nr_lagging;\n\tint nr_shortages;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iocost_iocg_forgive_debt {\n\tstruct trace_entry ent;\n\tu32 __data_loc_devname;\n\tu32 __data_loc_cgroup;\n\tu64 now;\n\tu64 vnow;\n\tu32 usage_pct;\n\tu64 old_debt;\n\tu64 new_debt;\n\tu64 old_delay;\n\tu64 new_delay;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_iocost_iocg_state {\n\tu32 devname;\n\tu32 cgroup;\n};\n\nstruct trace_event_data_offsets_iocg_inuse_update {\n\tu32 devname;\n\tu32 cgroup;\n};\n\nstruct trace_event_data_offsets_iocost_ioc_vrate_adj {\n\tu32 devname;\n};\n\nstruct trace_event_data_offsets_iocost_iocg_forgive_debt {\n\tu32 devname;\n\tu32 cgroup;\n};\n\ntypedef void (*btf_trace_iocost_iocg_activate)(void *, struct ioc_gq *, const char *, struct ioc_now *, u64, u64, u64);\n\ntypedef void (*btf_trace_iocost_iocg_idle)(void *, struct ioc_gq *, const char *, struct ioc_now *, u64, u64, u64);\n\ntypedef void (*btf_trace_iocost_inuse_shortage)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u32, u64, u64);\n\ntypedef void (*btf_trace_iocost_inuse_transfer)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u32, u64, u64);\n\ntypedef void (*btf_trace_iocost_inuse_adjust)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u32, u64, u64);\n\ntypedef void (*btf_trace_iocost_ioc_vrate_adj)(void *, struct ioc *, u64, u32 *, u32, int, int);\n\ntypedef void (*btf_trace_iocost_iocg_forgive_debt)(void *, struct ioc_gq *, const char *, struct ioc_now *, u32, u64, u64, u64, u64);\n\nenum dd_data_dir {\n\tDD_READ = 0,\n\tDD_WRITE = 1,\n};\n\nenum {\n\tDD_DIR_COUNT = 2,\n};\n\nenum dd_prio {\n\tDD_RT_PRIO = 0,\n\tDD_BE_PRIO = 1,\n\tDD_IDLE_PRIO = 2,\n\tDD_PRIO_MAX = 2,\n};\n\nenum {\n\tDD_PRIO_COUNT = 3,\n};\n\nstruct io_stats_per_prio {\n\tlocal_t inserted;\n\tlocal_t merged;\n\tlocal_t dispatched;\n\tlocal_t completed;\n};\n\nstruct io_stats {\n\tstruct io_stats_per_prio stats[3];\n};\n\nstruct dd_per_prio {\n\tstruct list_head dispatch;\n\tstruct rb_root sort_list[2];\n\tstruct list_head fifo_list[2];\n\tstruct request *next_rq[2];\n};\n\nstruct deadline_data {\n\tstruct dd_per_prio per_prio[3];\n\tenum dd_data_dir last_dir;\n\tunsigned int batching;\n\tunsigned int starved;\n\tstruct io_stats *stats;\n\tint fifo_expire[2];\n\tint fifo_batch;\n\tint writes_starved;\n\tint front_merges;\n\tu32 async_depth;\n\tspinlock_t lock;\n\tspinlock_t zone_lock;\n};\n\nstruct trace_event_raw_kyber_latency {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tchar domain[16];\n\tchar type[8];\n\tu8 percentile;\n\tu8 numerator;\n\tu8 denominator;\n\tunsigned int samples;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_kyber_adjust {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tchar domain[16];\n\tunsigned int depth;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_kyber_throttled {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tchar domain[16];\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_kyber_latency {};\n\nstruct trace_event_data_offsets_kyber_adjust {};\n\nstruct trace_event_data_offsets_kyber_throttled {};\n\ntypedef void (*btf_trace_kyber_latency)(void *, struct request_queue *, const char *, const char *, unsigned int, unsigned int, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_kyber_adjust)(void *, struct request_queue *, const char *, unsigned int);\n\ntypedef void (*btf_trace_kyber_throttled)(void *, struct request_queue *, const char *);\n\nenum {\n\tKYBER_READ = 0,\n\tKYBER_WRITE = 1,\n\tKYBER_DISCARD = 2,\n\tKYBER_OTHER = 3,\n\tKYBER_NUM_DOMAINS = 4,\n};\n\nenum {\n\tKYBER_ASYNC_PERCENT = 75,\n};\n\nenum {\n\tKYBER_LATENCY_SHIFT = 2,\n\tKYBER_GOOD_BUCKETS = 4,\n\tKYBER_LATENCY_BUCKETS = 8,\n};\n\nenum {\n\tKYBER_TOTAL_LATENCY = 0,\n\tKYBER_IO_LATENCY = 1,\n};\n\nstruct kyber_cpu_latency {\n\tatomic_t buckets[48];\n};\n\nstruct kyber_ctx_queue {\n\tspinlock_t lock;\n\tstruct list_head rq_list[4];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct kyber_queue_data {\n\tstruct request_queue *q;\n\tstruct sbitmap_queue domain_tokens[4];\n\tunsigned int async_depth;\n\tstruct kyber_cpu_latency *cpu_latency;\n\tstruct timer_list timer;\n\tunsigned int latency_buckets[48];\n\tlong unsigned int latency_timeout[3];\n\tint domain_p99[3];\n\tu64 latency_targets[3];\n};\n\nstruct kyber_hctx_data {\n\tspinlock_t lock;\n\tstruct list_head rqs[4];\n\tunsigned int cur_domain;\n\tunsigned int batching;\n\tstruct kyber_ctx_queue *kcqs;\n\tstruct sbitmap kcq_map[4];\n\tstruct sbq_wait domain_wait[4];\n\tstruct sbq_wait_state *domain_ws[4];\n\tatomic_t wait_index[4];\n};\n\nstruct flush_kcq_data {\n\tstruct kyber_hctx_data *khd;\n\tunsigned int sched_domain;\n\tstruct list_head *list;\n};\n\nstruct bfq_entity;\n\nstruct bfq_service_tree {\n\tstruct rb_root active;\n\tstruct rb_root idle;\n\tstruct bfq_entity *first_idle;\n\tstruct bfq_entity *last_idle;\n\tu64 vtime;\n\tlong unsigned int wsum;\n};\n\nstruct bfq_sched_data;\n\nstruct bfq_queue;\n\nstruct bfq_entity {\n\tstruct rb_node rb_node;\n\tbool on_st_or_in_serv;\n\tu64 start;\n\tu64 finish;\n\tstruct rb_root *tree;\n\tu64 min_start;\n\tint service;\n\tint budget;\n\tint dev_weight;\n\tint weight;\n\tint new_weight;\n\tint orig_weight;\n\tstruct bfq_entity *parent;\n\tstruct bfq_sched_data *my_sched_data;\n\tstruct bfq_sched_data *sched_data;\n\tint prio_changed;\n\tbool in_groups_with_pending_reqs;\n\tstruct bfq_queue *last_bfqq_created;\n};\n\nstruct bfq_sched_data {\n\tstruct bfq_entity *in_service_entity;\n\tstruct bfq_entity *next_in_service;\n\tstruct bfq_service_tree service_tree[3];\n\tlong unsigned int bfq_class_idle_last_service;\n};\n\nstruct bfq_weight_counter {\n\tunsigned int weight;\n\tunsigned int num_active;\n\tstruct rb_node weights_node;\n};\n\nstruct bfq_ttime {\n\tu64 last_end_request;\n\tu64 ttime_total;\n\tlong unsigned int ttime_samples;\n\tu64 ttime_mean;\n};\n\nstruct bfq_data;\n\nstruct bfq_io_cq;\n\nstruct bfq_queue {\n\tint ref;\n\tint stable_ref;\n\tstruct bfq_data *bfqd;\n\tshort unsigned int ioprio;\n\tshort unsigned int ioprio_class;\n\tshort unsigned int new_ioprio;\n\tshort unsigned int new_ioprio_class;\n\tu64 last_serv_time_ns;\n\tunsigned int inject_limit;\n\tlong unsigned int decrease_time_jif;\n\tstruct bfq_queue *new_bfqq;\n\tstruct rb_node pos_node;\n\tstruct rb_root *pos_root;\n\tstruct rb_root sort_list;\n\tstruct request *next_rq;\n\tint queued[2];\n\tint allocated;\n\tint meta_pending;\n\tstruct list_head fifo;\n\tstruct bfq_entity entity;\n\tstruct bfq_weight_counter *weight_counter;\n\tint max_budget;\n\tlong unsigned int budget_timeout;\n\tint dispatched;\n\tlong unsigned int flags;\n\tstruct list_head bfqq_list;\n\tstruct bfq_ttime ttime;\n\tu64 io_start_time;\n\tu64 tot_idle_time;\n\tu32 seek_history;\n\tstruct hlist_node burst_list_node;\n\tsector_t last_request_pos;\n\tunsigned int requests_within_timer;\n\tpid_t pid;\n\tstruct bfq_io_cq *bic;\n\tlong unsigned int wr_cur_max_time;\n\tlong unsigned int soft_rt_next_start;\n\tlong unsigned int last_wr_start_finish;\n\tunsigned int wr_coeff;\n\tlong unsigned int last_idle_bklogged;\n\tlong unsigned int service_from_backlogged;\n\tlong unsigned int service_from_wr;\n\tlong unsigned int wr_start_at_switch_to_srt;\n\tlong unsigned int split_time;\n\tlong unsigned int first_IO_time;\n\tlong unsigned int creation_time;\n\tu32 max_service_rate;\n\tstruct bfq_queue *waker_bfqq;\n\tstruct bfq_queue *tentative_waker_bfqq;\n\tunsigned int num_waker_detections;\n\tstruct hlist_node woken_list_node;\n\tstruct hlist_head woken_list;\n};\n\nstruct bfq_group;\n\nstruct bfq_data {\n\tstruct request_queue *queue;\n\tstruct list_head dispatch;\n\tstruct bfq_group *root_group;\n\tstruct rb_root_cached queue_weights_tree;\n\tunsigned int num_groups_with_pending_reqs;\n\tunsigned int busy_queues[3];\n\tint wr_busy_queues;\n\tint queued;\n\tint rq_in_driver;\n\tbool nonrot_with_queueing;\n\tint max_rq_in_driver;\n\tint hw_tag_samples;\n\tint hw_tag;\n\tint budgets_assigned;\n\tstruct hrtimer idle_slice_timer;\n\tstruct bfq_queue *in_service_queue;\n\tsector_t last_position;\n\tsector_t in_serv_last_pos;\n\tu64 last_completion;\n\tstruct bfq_queue *last_completed_rq_bfqq;\n\tstruct bfq_queue *last_bfqq_created;\n\tu64 last_empty_occupied_ns;\n\tbool wait_dispatch;\n\tstruct request *waited_rq;\n\tbool rqs_injected;\n\tu64 first_dispatch;\n\tu64 last_dispatch;\n\tktime_t last_budget_start;\n\tktime_t last_idling_start;\n\tlong unsigned int last_idling_start_jiffies;\n\tint peak_rate_samples;\n\tu32 sequential_samples;\n\tu64 tot_sectors_dispatched;\n\tu32 last_rq_max_size;\n\tu64 delta_from_first;\n\tu32 peak_rate;\n\tint bfq_max_budget;\n\tstruct list_head active_list;\n\tstruct list_head idle_list;\n\tu64 bfq_fifo_expire[2];\n\tunsigned int bfq_back_penalty;\n\tunsigned int bfq_back_max;\n\tu32 bfq_slice_idle;\n\tint bfq_user_max_budget;\n\tunsigned int bfq_timeout;\n\tbool strict_guarantees;\n\tlong unsigned int last_ins_in_burst;\n\tlong unsigned int bfq_burst_interval;\n\tint burst_size;\n\tstruct bfq_entity *burst_parent_entity;\n\tlong unsigned int bfq_large_burst_thresh;\n\tbool large_burst;\n\tstruct hlist_head burst_list;\n\tbool low_latency;\n\tunsigned int bfq_wr_coeff;\n\tunsigned int bfq_wr_max_time;\n\tunsigned int bfq_wr_rt_max_time;\n\tunsigned int bfq_wr_min_idle_time;\n\tlong unsigned int bfq_wr_min_inter_arr_async;\n\tunsigned int bfq_wr_max_softrt_rate;\n\tu64 rate_dur_prod;\n\tstruct bfq_queue oom_bfqq;\n\tspinlock_t lock;\n\tstruct bfq_io_cq *bio_bic;\n\tstruct bfq_queue *bio_bfqq;\n\tunsigned int word_depths[4];\n};\n\nstruct bfq_io_cq {\n\tstruct io_cq icq;\n\tstruct bfq_queue *bfqq[2];\n\tint ioprio;\n\tuint64_t blkcg_serial_nr;\n\tbool saved_has_short_ttime;\n\tbool saved_IO_bound;\n\tu64 saved_io_start_time;\n\tu64 saved_tot_idle_time;\n\tbool saved_in_large_burst;\n\tbool was_in_burst_list;\n\tunsigned int saved_weight;\n\tlong unsigned int saved_wr_coeff;\n\tlong unsigned int saved_last_wr_start_finish;\n\tlong unsigned int saved_service_from_wr;\n\tlong unsigned int saved_wr_start_at_switch_to_srt;\n\tunsigned int saved_wr_cur_max_time;\n\tstruct bfq_ttime saved_ttime;\n\tu64 saved_last_serv_time_ns;\n\tunsigned int saved_inject_limit;\n\tlong unsigned int saved_decrease_time_jif;\n\tstruct bfq_queue *stable_merge_bfqq;\n\tbool stably_merged;\n};\n\nstruct bfqg_stats {\n\tstruct blkg_rwstat bytes;\n\tstruct blkg_rwstat ios;\n};\n\nstruct bfq_group {\n\tstruct blkg_policy_data pd;\n\tchar blkg_path[128];\n\tint ref;\n\tstruct bfq_entity entity;\n\tstruct bfq_sched_data sched_data;\n\tvoid *bfqd;\n\tstruct bfq_queue *async_bfqq[16];\n\tstruct bfq_queue *async_idle_bfqq;\n\tstruct bfq_entity *my_entity;\n\tint active_entities;\n\tstruct rb_root rq_pos_tree;\n\tstruct bfqg_stats stats;\n};\n\nenum bfqq_state_flags {\n\tBFQQF_just_created = 0,\n\tBFQQF_busy = 1,\n\tBFQQF_wait_request = 2,\n\tBFQQF_non_blocking_wait_rq = 3,\n\tBFQQF_fifo_expire = 4,\n\tBFQQF_has_short_ttime = 5,\n\tBFQQF_sync = 6,\n\tBFQQF_IO_bound = 7,\n\tBFQQF_in_large_burst = 8,\n\tBFQQF_softrt_update = 9,\n\tBFQQF_coop = 10,\n\tBFQQF_split_coop = 11,\n};\n\nenum bfqq_expiration {\n\tBFQQE_TOO_IDLE = 0,\n\tBFQQE_BUDGET_TIMEOUT = 1,\n\tBFQQE_BUDGET_EXHAUSTED = 2,\n\tBFQQE_NO_MORE_REQUESTS = 3,\n\tBFQQE_PREEMPTED = 4,\n};\n\nstruct bfq_group_data {\n\tstruct blkcg_policy_data pd;\n\tunsigned int weight;\n};\n\nenum bip_flags {\n\tBIP_BLOCK_INTEGRITY = 1,\n\tBIP_MAPPED_INTEGRITY = 2,\n\tBIP_CTRL_NOCHECK = 4,\n\tBIP_DISK_NOCHECK = 8,\n\tBIP_IP_CHECKSUM = 16,\n};\n\nenum blk_integrity_flags {\n\tBLK_INTEGRITY_VERIFY = 1,\n\tBLK_INTEGRITY_GENERATE = 2,\n\tBLK_INTEGRITY_DEVICE_CAPABLE = 4,\n\tBLK_INTEGRITY_IP_CHECKSUM = 8,\n};\n\nstruct integrity_sysfs_entry {\n\tstruct attribute attr;\n\tssize_t (*show)(struct blk_integrity *, char *);\n\tssize_t (*store)(struct blk_integrity *, const char *, size_t);\n};\n\nenum t10_dif_type {\n\tT10_PI_TYPE0_PROTECTION = 0,\n\tT10_PI_TYPE1_PROTECTION = 1,\n\tT10_PI_TYPE2_PROTECTION = 2,\n\tT10_PI_TYPE3_PROTECTION = 3,\n};\n\nstruct t10_pi_tuple {\n\t__be16 guard_tag;\n\t__be16 app_tag;\n\t__be32 ref_tag;\n};\n\ntypedef __be16 csum_fn(void *, unsigned int);\n\nstruct virtio_device_id {\n\t__u32 device;\n\t__u32 vendor;\n};\n\nstruct virtio_device;\n\nstruct virtqueue {\n\tstruct list_head list;\n\tvoid (*callback)(struct virtqueue *);\n\tconst char *name;\n\tstruct virtio_device *vdev;\n\tunsigned int index;\n\tunsigned int num_free;\n\tvoid *priv;\n};\n\nstruct vringh_config_ops;\n\nstruct virtio_config_ops;\n\nstruct virtio_device {\n\tint index;\n\tbool failed;\n\tbool config_enabled;\n\tbool config_change_pending;\n\tspinlock_t config_lock;\n\tspinlock_t vqs_list_lock;\n\tstruct device dev;\n\tstruct virtio_device_id id;\n\tconst struct virtio_config_ops *config;\n\tconst struct vringh_config_ops *vringh_config;\n\tstruct list_head vqs;\n\tu64 features;\n\tvoid *priv;\n};\n\ntypedef void vq_callback_t(struct virtqueue *);\n\nstruct irq_affinity___2;\n\nstruct virtio_shm_region;\n\nstruct virtio_config_ops {\n\tvoid (*get)(struct virtio_device *, unsigned int, void *, unsigned int);\n\tvoid (*set)(struct virtio_device *, unsigned int, const void *, unsigned int);\n\tu32 (*generation)(struct virtio_device *);\n\tu8 (*get_status)(struct virtio_device *);\n\tvoid (*set_status)(struct virtio_device *, u8);\n\tvoid (*reset)(struct virtio_device *);\n\tint (*find_vqs)(struct virtio_device *, unsigned int, struct virtqueue **, vq_callback_t **, const char * const *, const bool *, struct irq_affinity___2 *);\n\tvoid (*del_vqs)(struct virtio_device *);\n\tu64 (*get_features)(struct virtio_device *);\n\tint (*finalize_features)(struct virtio_device *);\n\tconst char * (*bus_name)(struct virtio_device *);\n\tint (*set_vq_affinity)(struct virtqueue *, const struct cpumask *);\n\tconst struct cpumask * (*get_vq_affinity)(struct virtio_device *, int);\n\tbool (*get_shm_region)(struct virtio_device *, struct virtio_shm_region *, u8);\n};\n\nstruct virtio_shm_region {\n\tu64 addr;\n\tu64 len;\n};\n\nstruct irq_poll;\n\ntypedef int irq_poll_fn(struct irq_poll *, int);\n\nstruct irq_poll {\n\tstruct list_head list;\n\tlong unsigned int state;\n\tint weight;\n\tirq_poll_fn *poll;\n};\n\nstruct dim_sample {\n\tktime_t time;\n\tu32 pkt_ctr;\n\tu32 byte_ctr;\n\tu16 event_ctr;\n\tu32 comp_ctr;\n};\n\nstruct dim_stats {\n\tint ppms;\n\tint bpms;\n\tint epms;\n\tint cpms;\n\tint cpe_ratio;\n};\n\nstruct dim {\n\tu8 state;\n\tstruct dim_stats prev_stats;\n\tstruct dim_sample start_sample;\n\tstruct dim_sample measuring_sample;\n\tstruct work_struct work;\n\tvoid *priv;\n\tu8 profile_ix;\n\tu8 mode;\n\tu8 tune_state;\n\tu8 steps_right;\n\tu8 steps_left;\n\tu8 tired;\n};\n\nenum rdma_nl_counter_mode {\n\tRDMA_COUNTER_MODE_NONE = 0,\n\tRDMA_COUNTER_MODE_AUTO = 1,\n\tRDMA_COUNTER_MODE_MANUAL = 2,\n\tRDMA_COUNTER_MODE_MAX = 3,\n};\n\nenum rdma_nl_counter_mask {\n\tRDMA_COUNTER_MASK_QP_TYPE = 1,\n\tRDMA_COUNTER_MASK_PID = 2,\n};\n\nenum rdma_restrack_type {\n\tRDMA_RESTRACK_PD = 0,\n\tRDMA_RESTRACK_CQ = 1,\n\tRDMA_RESTRACK_QP = 2,\n\tRDMA_RESTRACK_CM_ID = 3,\n\tRDMA_RESTRACK_MR = 4,\n\tRDMA_RESTRACK_CTX = 5,\n\tRDMA_RESTRACK_COUNTER = 6,\n\tRDMA_RESTRACK_SRQ = 7,\n\tRDMA_RESTRACK_MAX = 8,\n};\n\nstruct rdma_restrack_entry {\n\tbool valid;\n\tu8 no_track: 1;\n\tstruct kref kref;\n\tstruct completion comp;\n\tstruct task_struct *task;\n\tconst char *kern_name;\n\tenum rdma_restrack_type type;\n\tbool user;\n\tu32 id;\n};\n\nstruct rdma_link_ops {\n\tstruct list_head list;\n\tconst char *type;\n\tint (*newlink)(const char *, struct net_device *);\n};\n\nstruct auto_mode_param {\n\tint qp_type;\n};\n\nstruct rdma_counter_mode {\n\tenum rdma_nl_counter_mode mode;\n\tenum rdma_nl_counter_mask mask;\n\tstruct auto_mode_param param;\n};\n\nstruct rdma_hw_stats;\n\nstruct rdma_port_counter {\n\tstruct rdma_counter_mode mode;\n\tstruct rdma_hw_stats *hstats;\n\tunsigned int num_counters;\n\tstruct mutex lock;\n};\n\nstruct rdma_hw_stats {\n\tstruct mutex lock;\n\tlong unsigned int timestamp;\n\tlong unsigned int lifespan;\n\tconst char * const *names;\n\tint num_counters;\n\tu64 value[0];\n};\n\nstruct ib_device;\n\nstruct rdma_counter {\n\tstruct rdma_restrack_entry res;\n\tstruct ib_device *device;\n\tuint32_t id;\n\tstruct kref kref;\n\tstruct rdma_counter_mode mode;\n\tstruct mutex lock;\n\tstruct rdma_hw_stats *stats;\n\tu32 port;\n};\n\nenum rdma_driver_id {\n\tRDMA_DRIVER_UNKNOWN = 0,\n\tRDMA_DRIVER_MLX5 = 1,\n\tRDMA_DRIVER_MLX4 = 2,\n\tRDMA_DRIVER_CXGB3 = 3,\n\tRDMA_DRIVER_CXGB4 = 4,\n\tRDMA_DRIVER_MTHCA = 5,\n\tRDMA_DRIVER_BNXT_RE = 6,\n\tRDMA_DRIVER_OCRDMA = 7,\n\tRDMA_DRIVER_NES = 8,\n\tRDMA_DRIVER_I40IW = 9,\n\tRDMA_DRIVER_IRDMA = 9,\n\tRDMA_DRIVER_VMW_PVRDMA = 10,\n\tRDMA_DRIVER_QEDR = 11,\n\tRDMA_DRIVER_HNS = 12,\n\tRDMA_DRIVER_USNIC = 13,\n\tRDMA_DRIVER_RXE = 14,\n\tRDMA_DRIVER_HFI1 = 15,\n\tRDMA_DRIVER_QIB = 16,\n\tRDMA_DRIVER_EFA = 17,\n\tRDMA_DRIVER_SIW = 18,\n};\n\nenum ib_cq_notify_flags {\n\tIB_CQ_SOLICITED = 1,\n\tIB_CQ_NEXT_COMP = 2,\n\tIB_CQ_SOLICITED_MASK = 3,\n\tIB_CQ_REPORT_MISSED_EVENTS = 4,\n};\n\nstruct ib_mad;\n\nenum rdma_link_layer {\n\tIB_LINK_LAYER_UNSPECIFIED = 0,\n\tIB_LINK_LAYER_INFINIBAND = 1,\n\tIB_LINK_LAYER_ETHERNET = 2,\n};\n\nenum rdma_netdev_t {\n\tRDMA_NETDEV_OPA_VNIC = 0,\n\tRDMA_NETDEV_IPOIB = 1,\n};\n\nenum ib_srq_attr_mask {\n\tIB_SRQ_MAX_WR = 1,\n\tIB_SRQ_LIMIT = 2,\n};\n\nenum ib_mr_type {\n\tIB_MR_TYPE_MEM_REG = 0,\n\tIB_MR_TYPE_SG_GAPS = 1,\n\tIB_MR_TYPE_DM = 2,\n\tIB_MR_TYPE_USER = 3,\n\tIB_MR_TYPE_DMA = 4,\n\tIB_MR_TYPE_INTEGRITY = 5,\n};\n\nenum ib_uverbs_advise_mr_advice {\n\tIB_UVERBS_ADVISE_MR_ADVICE_PREFETCH = 0,\n\tIB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_WRITE = 1,\n\tIB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_NO_FAULT = 2,\n};\n\nstruct uverbs_attr_bundle;\n\nstruct rdma_cm_id;\n\nstruct iw_cm_id;\n\nstruct iw_cm_conn_param;\n\nstruct ib_qp;\n\nstruct ib_send_wr;\n\nstruct ib_recv_wr;\n\nstruct ib_cq;\n\nstruct ib_wc;\n\nstruct ib_srq;\n\nstruct ib_grh;\n\nstruct ib_device_attr;\n\nstruct ib_udata;\n\nstruct ib_device_modify;\n\nstruct ib_port_attr;\n\nstruct ib_port_modify;\n\nstruct ib_port_immutable;\n\nstruct rdma_netdev_alloc_params;\n\nunion ib_gid;\n\nstruct ib_gid_attr;\n\nstruct ib_ucontext;\n\nstruct rdma_user_mmap_entry;\n\nstruct ib_pd;\n\nstruct ib_ah;\n\nstruct rdma_ah_init_attr;\n\nstruct rdma_ah_attr;\n\nstruct ib_srq_init_attr;\n\nstruct ib_srq_attr;\n\nstruct ib_qp_init_attr;\n\nstruct ib_qp_attr;\n\nstruct ib_cq_init_attr;\n\nstruct ib_mr;\n\nstruct ib_sge;\n\nstruct ib_mr_status;\n\nstruct ib_mw;\n\nstruct ib_xrcd;\n\nstruct ib_flow;\n\nstruct ib_flow_attr;\n\nstruct ib_flow_action;\n\nstruct ib_flow_action_attrs_esp;\n\nstruct ib_wq;\n\nstruct ib_wq_init_attr;\n\nstruct ib_wq_attr;\n\nstruct ib_rwq_ind_table;\n\nstruct ib_rwq_ind_table_init_attr;\n\nstruct ib_dm;\n\nstruct ib_dm_alloc_attr;\n\nstruct ib_dm_mr_attr;\n\nstruct ib_counters;\n\nstruct ib_counters_read_attr;\n\nstruct ib_device_ops {\n\tstruct module *owner;\n\tenum rdma_driver_id driver_id;\n\tu32 uverbs_abi_ver;\n\tunsigned int uverbs_no_driver_id_binding: 1;\n\tconst struct attribute_group *device_group;\n\tconst struct attribute_group **port_groups;\n\tint (*post_send)(struct ib_qp *, const struct ib_send_wr *, const struct ib_send_wr **);\n\tint (*post_recv)(struct ib_qp *, const struct ib_recv_wr *, const struct ib_recv_wr **);\n\tvoid (*drain_rq)(struct ib_qp *);\n\tvoid (*drain_sq)(struct ib_qp *);\n\tint (*poll_cq)(struct ib_cq *, int, struct ib_wc *);\n\tint (*peek_cq)(struct ib_cq *, int);\n\tint (*req_notify_cq)(struct ib_cq *, enum ib_cq_notify_flags);\n\tint (*post_srq_recv)(struct ib_srq *, const struct ib_recv_wr *, const struct ib_recv_wr **);\n\tint (*process_mad)(struct ib_device *, int, u32, const struct ib_wc *, const struct ib_grh *, const struct ib_mad *, struct ib_mad *, size_t *, u16 *);\n\tint (*query_device)(struct ib_device *, struct ib_device_attr *, struct ib_udata *);\n\tint (*modify_device)(struct ib_device *, int, struct ib_device_modify *);\n\tvoid (*get_dev_fw_str)(struct ib_device *, char *);\n\tconst struct cpumask * (*get_vector_affinity)(struct ib_device *, int);\n\tint (*query_port)(struct ib_device *, u32, struct ib_port_attr *);\n\tint (*modify_port)(struct ib_device *, u32, int, struct ib_port_modify *);\n\tint (*get_port_immutable)(struct ib_device *, u32, struct ib_port_immutable *);\n\tenum rdma_link_layer (*get_link_layer)(struct ib_device *, u32);\n\tstruct net_device * (*get_netdev)(struct ib_device *, u32);\n\tstruct net_device * (*alloc_rdma_netdev)(struct ib_device *, u32, enum rdma_netdev_t, const char *, unsigned char, void (*)(struct net_device *));\n\tint (*rdma_netdev_get_params)(struct ib_device *, u32, enum rdma_netdev_t, struct rdma_netdev_alloc_params *);\n\tint (*query_gid)(struct ib_device *, u32, int, union ib_gid *);\n\tint (*add_gid)(const struct ib_gid_attr *, void **);\n\tint (*del_gid)(const struct ib_gid_attr *, void **);\n\tint (*query_pkey)(struct ib_device *, u32, u16, u16 *);\n\tint (*alloc_ucontext)(struct ib_ucontext *, struct ib_udata *);\n\tvoid (*dealloc_ucontext)(struct ib_ucontext *);\n\tint (*mmap)(struct ib_ucontext *, struct vm_area_struct *);\n\tvoid (*mmap_free)(struct rdma_user_mmap_entry *);\n\tvoid (*disassociate_ucontext)(struct ib_ucontext *);\n\tint (*alloc_pd)(struct ib_pd *, struct ib_udata *);\n\tint (*dealloc_pd)(struct ib_pd *, struct ib_udata *);\n\tint (*create_ah)(struct ib_ah *, struct rdma_ah_init_attr *, struct ib_udata *);\n\tint (*create_user_ah)(struct ib_ah *, struct rdma_ah_init_attr *, struct ib_udata *);\n\tint (*modify_ah)(struct ib_ah *, struct rdma_ah_attr *);\n\tint (*query_ah)(struct ib_ah *, struct rdma_ah_attr *);\n\tint (*destroy_ah)(struct ib_ah *, u32);\n\tint (*create_srq)(struct ib_srq *, struct ib_srq_init_attr *, struct ib_udata *);\n\tint (*modify_srq)(struct ib_srq *, struct ib_srq_attr *, enum ib_srq_attr_mask, struct ib_udata *);\n\tint (*query_srq)(struct ib_srq *, struct ib_srq_attr *);\n\tint (*destroy_srq)(struct ib_srq *, struct ib_udata *);\n\tstruct ib_qp * (*create_qp)(struct ib_pd *, struct ib_qp_init_attr *, struct ib_udata *);\n\tint (*modify_qp)(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);\n\tint (*query_qp)(struct ib_qp *, struct ib_qp_attr *, int, struct ib_qp_init_attr *);\n\tint (*destroy_qp)(struct ib_qp *, struct ib_udata *);\n\tint (*create_cq)(struct ib_cq *, const struct ib_cq_init_attr *, struct ib_udata *);\n\tint (*modify_cq)(struct ib_cq *, u16, u16);\n\tint (*destroy_cq)(struct ib_cq *, struct ib_udata *);\n\tint (*resize_cq)(struct ib_cq *, int, struct ib_udata *);\n\tstruct ib_mr * (*get_dma_mr)(struct ib_pd *, int);\n\tstruct ib_mr * (*reg_user_mr)(struct ib_pd *, u64, u64, u64, int, struct ib_udata *);\n\tstruct ib_mr * (*reg_user_mr_dmabuf)(struct ib_pd *, u64, u64, u64, int, int, struct ib_udata *);\n\tstruct ib_mr * (*rereg_user_mr)(struct ib_mr *, int, u64, u64, u64, int, struct ib_pd *, struct ib_udata *);\n\tint (*dereg_mr)(struct ib_mr *, struct ib_udata *);\n\tstruct ib_mr * (*alloc_mr)(struct ib_pd *, enum ib_mr_type, u32);\n\tstruct ib_mr * (*alloc_mr_integrity)(struct ib_pd *, u32, u32);\n\tint (*advise_mr)(struct ib_pd *, enum ib_uverbs_advise_mr_advice, u32, struct ib_sge *, u32, struct uverbs_attr_bundle *);\n\tint (*map_mr_sg)(struct ib_mr *, struct scatterlist *, int, unsigned int *);\n\tint (*check_mr_status)(struct ib_mr *, u32, struct ib_mr_status *);\n\tint (*alloc_mw)(struct ib_mw *, struct ib_udata *);\n\tint (*dealloc_mw)(struct ib_mw *);\n\tint (*attach_mcast)(struct ib_qp *, union ib_gid *, u16);\n\tint (*detach_mcast)(struct ib_qp *, union ib_gid *, u16);\n\tint (*alloc_xrcd)(struct ib_xrcd *, struct ib_udata *);\n\tint (*dealloc_xrcd)(struct ib_xrcd *, struct ib_udata *);\n\tstruct ib_flow * (*create_flow)(struct ib_qp *, struct ib_flow_attr *, struct ib_udata *);\n\tint (*destroy_flow)(struct ib_flow *);\n\tstruct ib_flow_action * (*create_flow_action_esp)(struct ib_device *, const struct ib_flow_action_attrs_esp *, struct uverbs_attr_bundle *);\n\tint (*destroy_flow_action)(struct ib_flow_action *);\n\tint (*modify_flow_action_esp)(struct ib_flow_action *, const struct ib_flow_action_attrs_esp *, struct uverbs_attr_bundle *);\n\tint (*set_vf_link_state)(struct ib_device *, int, u32, int);\n\tint (*get_vf_config)(struct ib_device *, int, u32, struct ifla_vf_info *);\n\tint (*get_vf_stats)(struct ib_device *, int, u32, struct ifla_vf_stats *);\n\tint (*get_vf_guid)(struct ib_device *, int, u32, struct ifla_vf_guid *, struct ifla_vf_guid *);\n\tint (*set_vf_guid)(struct ib_device *, int, u32, u64, int);\n\tstruct ib_wq * (*create_wq)(struct ib_pd *, struct ib_wq_init_attr *, struct ib_udata *);\n\tint (*destroy_wq)(struct ib_wq *, struct ib_udata *);\n\tint (*modify_wq)(struct ib_wq *, struct ib_wq_attr *, u32, struct ib_udata *);\n\tint (*create_rwq_ind_table)(struct ib_rwq_ind_table *, struct ib_rwq_ind_table_init_attr *, struct ib_udata *);\n\tint (*destroy_rwq_ind_table)(struct ib_rwq_ind_table *);\n\tstruct ib_dm * (*alloc_dm)(struct ib_device *, struct ib_ucontext *, struct ib_dm_alloc_attr *, struct uverbs_attr_bundle *);\n\tint (*dealloc_dm)(struct ib_dm *, struct uverbs_attr_bundle *);\n\tstruct ib_mr * (*reg_dm_mr)(struct ib_pd *, struct ib_dm *, struct ib_dm_mr_attr *, struct uverbs_attr_bundle *);\n\tint (*create_counters)(struct ib_counters *, struct uverbs_attr_bundle *);\n\tint (*destroy_counters)(struct ib_counters *);\n\tint (*read_counters)(struct ib_counters *, struct ib_counters_read_attr *, struct uverbs_attr_bundle *);\n\tint (*map_mr_sg_pi)(struct ib_mr *, struct scatterlist *, int, unsigned int *, struct scatterlist *, int, unsigned int *);\n\tstruct rdma_hw_stats * (*alloc_hw_device_stats)(struct ib_device *);\n\tstruct rdma_hw_stats * (*alloc_hw_port_stats)(struct ib_device *, u32);\n\tint (*get_hw_stats)(struct ib_device *, struct rdma_hw_stats *, u32, int);\n\tint (*fill_res_mr_entry)(struct sk_buff *, struct ib_mr *);\n\tint (*fill_res_mr_entry_raw)(struct sk_buff *, struct ib_mr *);\n\tint (*fill_res_cq_entry)(struct sk_buff *, struct ib_cq *);\n\tint (*fill_res_cq_entry_raw)(struct sk_buff *, struct ib_cq *);\n\tint (*fill_res_qp_entry)(struct sk_buff *, struct ib_qp *);\n\tint (*fill_res_qp_entry_raw)(struct sk_buff *, struct ib_qp *);\n\tint (*fill_res_cm_id_entry)(struct sk_buff *, struct rdma_cm_id *);\n\tint (*enable_driver)(struct ib_device *);\n\tvoid (*dealloc_driver)(struct ib_device *);\n\tvoid (*iw_add_ref)(struct ib_qp *);\n\tvoid (*iw_rem_ref)(struct ib_qp *);\n\tstruct ib_qp * (*iw_get_qp)(struct ib_device *, int);\n\tint (*iw_connect)(struct iw_cm_id *, struct iw_cm_conn_param *);\n\tint (*iw_accept)(struct iw_cm_id *, struct iw_cm_conn_param *);\n\tint (*iw_reject)(struct iw_cm_id *, const void *, u8);\n\tint (*iw_create_listen)(struct iw_cm_id *, int);\n\tint (*iw_destroy_listen)(struct iw_cm_id *);\n\tint (*counter_bind_qp)(struct rdma_counter *, struct ib_qp *);\n\tint (*counter_unbind_qp)(struct ib_qp *);\n\tint (*counter_dealloc)(struct rdma_counter *);\n\tstruct rdma_hw_stats * (*counter_alloc_stats)(struct rdma_counter *);\n\tint (*counter_update_stats)(struct rdma_counter *);\n\tint (*fill_stat_mr_entry)(struct sk_buff *, struct ib_mr *);\n\tint (*query_ucontext)(struct ib_ucontext *, struct uverbs_attr_bundle *);\n\tsize_t size_ib_ah;\n\tsize_t size_ib_counters;\n\tsize_t size_ib_cq;\n\tsize_t size_ib_mw;\n\tsize_t size_ib_pd;\n\tsize_t size_ib_rwq_ind_table;\n\tsize_t size_ib_srq;\n\tsize_t size_ib_ucontext;\n\tsize_t size_ib_xrcd;\n};\n\nstruct ib_core_device {\n\tstruct device dev;\n\tpossible_net_t rdma_net;\n\tstruct kobject *ports_kobj;\n\tstruct list_head port_list;\n\tstruct ib_device *owner;\n};\n\nenum ib_atomic_cap {\n\tIB_ATOMIC_NONE = 0,\n\tIB_ATOMIC_HCA = 1,\n\tIB_ATOMIC_GLOB = 2,\n};\n\nstruct ib_odp_caps {\n\tuint64_t general_caps;\n\tstruct {\n\t\tuint32_t rc_odp_caps;\n\t\tuint32_t uc_odp_caps;\n\t\tuint32_t ud_odp_caps;\n\t\tuint32_t xrc_odp_caps;\n\t} per_transport_caps;\n};\n\nstruct ib_rss_caps {\n\tu32 supported_qpts;\n\tu32 max_rwq_indirection_tables;\n\tu32 max_rwq_indirection_table_size;\n};\n\nstruct ib_tm_caps {\n\tu32 max_rndv_hdr_size;\n\tu32 max_num_tags;\n\tu32 flags;\n\tu32 max_ops;\n\tu32 max_sge;\n};\n\nstruct ib_cq_caps {\n\tu16 max_cq_moderation_count;\n\tu16 max_cq_moderation_period;\n};\n\nstruct ib_device_attr {\n\tu64 fw_ver;\n\t__be64 sys_image_guid;\n\tu64 max_mr_size;\n\tu64 page_size_cap;\n\tu32 vendor_id;\n\tu32 vendor_part_id;\n\tu32 hw_ver;\n\tint max_qp;\n\tint max_qp_wr;\n\tu64 device_cap_flags;\n\tint max_send_sge;\n\tint max_recv_sge;\n\tint max_sge_rd;\n\tint max_cq;\n\tint max_cqe;\n\tint max_mr;\n\tint max_pd;\n\tint max_qp_rd_atom;\n\tint max_ee_rd_atom;\n\tint max_res_rd_atom;\n\tint max_qp_init_rd_atom;\n\tint max_ee_init_rd_atom;\n\tenum ib_atomic_cap atomic_cap;\n\tenum ib_atomic_cap masked_atomic_cap;\n\tint max_ee;\n\tint max_rdd;\n\tint max_mw;\n\tint max_raw_ipv6_qp;\n\tint max_raw_ethy_qp;\n\tint max_mcast_grp;\n\tint max_mcast_qp_attach;\n\tint max_total_mcast_qp_attach;\n\tint max_ah;\n\tint max_srq;\n\tint max_srq_wr;\n\tint max_srq_sge;\n\tunsigned int max_fast_reg_page_list_len;\n\tunsigned int max_pi_fast_reg_page_list_len;\n\tu16 max_pkeys;\n\tu8 local_ca_ack_delay;\n\tint sig_prot_cap;\n\tint sig_guard_cap;\n\tstruct ib_odp_caps odp_caps;\n\tuint64_t timestamp_mask;\n\tuint64_t hca_core_clock;\n\tstruct ib_rss_caps rss_caps;\n\tu32 max_wq_type_rq;\n\tu32 raw_packet_caps;\n\tstruct ib_tm_caps tm_caps;\n\tstruct ib_cq_caps cq_caps;\n\tu64 max_dm_size;\n\tu32 max_sgl_rd;\n};\n\nstruct hw_stats_device_data;\n\nstruct rdma_restrack_root;\n\nstruct uapi_definition;\n\nstruct ib_port_data;\n\nstruct ib_device {\n\tstruct device *dma_device;\n\tstruct ib_device_ops ops;\n\tchar name[64];\n\tstruct callback_head callback_head;\n\tstruct list_head event_handler_list;\n\tstruct rw_semaphore event_handler_rwsem;\n\tspinlock_t qp_open_list_lock;\n\tstruct rw_semaphore client_data_rwsem;\n\tstruct xarray client_data;\n\tstruct mutex unregistration_lock;\n\trwlock_t cache_lock;\n\tstruct ib_port_data *port_data;\n\tint num_comp_vectors;\n\tunion {\n\t\tstruct device dev;\n\t\tstruct ib_core_device coredev;\n\t};\n\tconst struct attribute_group *groups[4];\n\tu64 uverbs_cmd_mask;\n\tchar node_desc[64];\n\t__be64 node_guid;\n\tu32 local_dma_lkey;\n\tu16 is_switch: 1;\n\tu16 kverbs_provider: 1;\n\tu16 use_cq_dim: 1;\n\tu8 node_type;\n\tu32 phys_port_cnt;\n\tstruct ib_device_attr attrs;\n\tstruct hw_stats_device_data *hw_stats_data;\n\tstruct rdmacg_device cg_device;\n\tu32 index;\n\tspinlock_t cq_pools_lock;\n\tstruct list_head cq_pools[3];\n\tstruct rdma_restrack_root *res;\n\tconst struct uapi_definition *driver_def;\n\trefcount_t refcount;\n\tstruct completion unreg_completion;\n\tstruct work_struct unregistration_work;\n\tconst struct rdma_link_ops *link_ops;\n\tstruct mutex compat_devs_mutex;\n\tstruct xarray compat_devs;\n\tchar iw_ifname[16];\n\tu32 iw_driver_flags;\n\tu32 lag_flags;\n};\n\nenum ib_signature_type {\n\tIB_SIG_TYPE_NONE = 0,\n\tIB_SIG_TYPE_T10_DIF = 1,\n};\n\nenum ib_t10_dif_bg_type {\n\tIB_T10DIF_CRC = 0,\n\tIB_T10DIF_CSUM = 1,\n};\n\nstruct ib_t10_dif_domain {\n\tenum ib_t10_dif_bg_type bg_type;\n\tu16 pi_interval;\n\tu16 bg;\n\tu16 app_tag;\n\tu32 ref_tag;\n\tbool ref_remap;\n\tbool app_escape;\n\tbool ref_escape;\n\tu16 apptag_check_mask;\n};\n\nstruct ib_sig_domain {\n\tenum ib_signature_type sig_type;\n\tunion {\n\t\tstruct ib_t10_dif_domain dif;\n\t} sig;\n};\n\nstruct ib_sig_attrs {\n\tu8 check_mask;\n\tstruct ib_sig_domain mem;\n\tstruct ib_sig_domain wire;\n\tint meta_length;\n};\n\nenum ib_sig_err_type {\n\tIB_SIG_BAD_GUARD = 0,\n\tIB_SIG_BAD_REFTAG = 1,\n\tIB_SIG_BAD_APPTAG = 2,\n};\n\nstruct ib_sig_err {\n\tenum ib_sig_err_type err_type;\n\tu32 expected;\n\tu32 actual;\n\tu64 sig_err_offset;\n\tu32 key;\n};\n\nenum ib_uverbs_flow_action_esp_keymat {\n\tIB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM = 0,\n};\n\nstruct ib_uverbs_flow_action_esp_keymat_aes_gcm {\n\t__u64 iv;\n\t__u32 iv_algo;\n\t__u32 salt;\n\t__u32 icv_len;\n\t__u32 key_len;\n\t__u32 aes_key[8];\n};\n\nenum ib_uverbs_flow_action_esp_replay {\n\tIB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE = 0,\n\tIB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP = 1,\n};\n\nstruct ib_uverbs_flow_action_esp_replay_bmp {\n\t__u32 size;\n};\n\nunion ib_gid {\n\tu8 raw[16];\n\tstruct {\n\t\t__be64 subnet_prefix;\n\t\t__be64 interface_id;\n\t} global;\n};\n\nenum ib_gid_type {\n\tIB_GID_TYPE_IB = 0,\n\tIB_GID_TYPE_ROCE = 1,\n\tIB_GID_TYPE_ROCE_UDP_ENCAP = 2,\n\tIB_GID_TYPE_SIZE = 3,\n};\n\nstruct ib_gid_attr {\n\tstruct net_device *ndev;\n\tstruct ib_device *device;\n\tunion ib_gid gid;\n\tenum ib_gid_type gid_type;\n\tu16 index;\n\tu32 port_num;\n};\n\nstruct ib_cq_init_attr {\n\tunsigned int cqe;\n\tu32 comp_vector;\n\tu32 flags;\n};\n\nstruct ib_dm_mr_attr {\n\tu64 length;\n\tu64 offset;\n\tu32 access_flags;\n};\n\nstruct ib_dm_alloc_attr {\n\tu64 length;\n\tu32 alignment;\n\tu32 flags;\n};\n\nenum ib_mtu {\n\tIB_MTU_256 = 1,\n\tIB_MTU_512 = 2,\n\tIB_MTU_1024 = 3,\n\tIB_MTU_2048 = 4,\n\tIB_MTU_4096 = 5,\n};\n\nenum ib_port_state {\n\tIB_PORT_NOP = 0,\n\tIB_PORT_DOWN = 1,\n\tIB_PORT_INIT = 2,\n\tIB_PORT_ARMED = 3,\n\tIB_PORT_ACTIVE = 4,\n\tIB_PORT_ACTIVE_DEFER = 5,\n};\n\nstruct ib_port_attr {\n\tu64 subnet_prefix;\n\tenum ib_port_state state;\n\tenum ib_mtu max_mtu;\n\tenum ib_mtu active_mtu;\n\tu32 phys_mtu;\n\tint gid_tbl_len;\n\tunsigned int ip_gids: 1;\n\tu32 port_cap_flags;\n\tu32 max_msg_sz;\n\tu32 bad_pkey_cntr;\n\tu32 qkey_viol_cntr;\n\tu16 pkey_tbl_len;\n\tu32 sm_lid;\n\tu32 lid;\n\tu8 lmc;\n\tu8 max_vl_num;\n\tu8 sm_sl;\n\tu8 subnet_timeout;\n\tu8 init_type_reply;\n\tu8 active_width;\n\tu16 active_speed;\n\tu8 phys_state;\n\tu16 port_cap_flags2;\n};\n\nstruct ib_device_modify {\n\tu64 sys_image_guid;\n\tchar node_desc[64];\n};\n\nstruct ib_port_modify {\n\tu32 set_port_cap_mask;\n\tu32 clr_port_cap_mask;\n\tu8 init_type;\n};\n\nenum ib_event_type {\n\tIB_EVENT_CQ_ERR = 0,\n\tIB_EVENT_QP_FATAL = 1,\n\tIB_EVENT_QP_REQ_ERR = 2,\n\tIB_EVENT_QP_ACCESS_ERR = 3,\n\tIB_EVENT_COMM_EST = 4,\n\tIB_EVENT_SQ_DRAINED = 5,\n\tIB_EVENT_PATH_MIG = 6,\n\tIB_EVENT_PATH_MIG_ERR = 7,\n\tIB_EVENT_DEVICE_FATAL = 8,\n\tIB_EVENT_PORT_ACTIVE = 9,\n\tIB_EVENT_PORT_ERR = 10,\n\tIB_EVENT_LID_CHANGE = 11,\n\tIB_EVENT_PKEY_CHANGE = 12,\n\tIB_EVENT_SM_CHANGE = 13,\n\tIB_EVENT_SRQ_ERR = 14,\n\tIB_EVENT_SRQ_LIMIT_REACHED = 15,\n\tIB_EVENT_QP_LAST_WQE_REACHED = 16,\n\tIB_EVENT_CLIENT_REREGISTER = 17,\n\tIB_EVENT_GID_CHANGE = 18,\n\tIB_EVENT_WQ_FATAL = 19,\n};\n\nstruct ib_ucq_object;\n\ntypedef void (*ib_comp_handler)(struct ib_cq *, void *);\n\nstruct ib_event;\n\nstruct ib_cq {\n\tstruct ib_device *device;\n\tstruct ib_ucq_object *uobject;\n\tib_comp_handler comp_handler;\n\tvoid (*event_handler)(struct ib_event *, void *);\n\tvoid *cq_context;\n\tint cqe;\n\tunsigned int cqe_used;\n\tatomic_t usecnt;\n\tenum ib_poll_context poll_ctx;\n\tstruct ib_wc *wc;\n\tstruct list_head pool_entry;\n\tunion {\n\t\tstruct irq_poll iop;\n\t\tstruct work_struct work;\n\t};\n\tstruct workqueue_struct *comp_wq;\n\tstruct dim *dim;\n\tktime_t timestamp;\n\tu8 interrupt: 1;\n\tu8 shared: 1;\n\tunsigned int comp_vector;\n\tstruct rdma_restrack_entry res;\n};\n\nstruct ib_uqp_object;\n\nenum ib_qp_type {\n\tIB_QPT_SMI = 0,\n\tIB_QPT_GSI = 1,\n\tIB_QPT_RC = 2,\n\tIB_QPT_UC = 3,\n\tIB_QPT_UD = 4,\n\tIB_QPT_RAW_IPV6 = 5,\n\tIB_QPT_RAW_ETHERTYPE = 6,\n\tIB_QPT_RAW_PACKET = 8,\n\tIB_QPT_XRC_INI = 9,\n\tIB_QPT_XRC_TGT = 10,\n\tIB_QPT_MAX = 11,\n\tIB_QPT_DRIVER = 255,\n\tIB_QPT_RESERVED1 = 4096,\n\tIB_QPT_RESERVED2 = 4097,\n\tIB_QPT_RESERVED3 = 4098,\n\tIB_QPT_RESERVED4 = 4099,\n\tIB_QPT_RESERVED5 = 4100,\n\tIB_QPT_RESERVED6 = 4101,\n\tIB_QPT_RESERVED7 = 4102,\n\tIB_QPT_RESERVED8 = 4103,\n\tIB_QPT_RESERVED9 = 4104,\n\tIB_QPT_RESERVED10 = 4105,\n};\n\nstruct ib_qp_security;\n\nstruct ib_qp {\n\tstruct ib_device *device;\n\tstruct ib_pd *pd;\n\tstruct ib_cq *send_cq;\n\tstruct ib_cq *recv_cq;\n\tspinlock_t mr_lock;\n\tint mrs_used;\n\tstruct list_head rdma_mrs;\n\tstruct list_head sig_mrs;\n\tstruct ib_srq *srq;\n\tstruct ib_xrcd *xrcd;\n\tstruct list_head xrcd_list;\n\tatomic_t usecnt;\n\tstruct list_head open_list;\n\tstruct ib_qp *real_qp;\n\tstruct ib_uqp_object *uobject;\n\tvoid (*event_handler)(struct ib_event *, void *);\n\tvoid *qp_context;\n\tconst struct ib_gid_attr *av_sgid_attr;\n\tconst struct ib_gid_attr *alt_path_sgid_attr;\n\tu32 qp_num;\n\tu32 max_write_sge;\n\tu32 max_read_sge;\n\tenum ib_qp_type qp_type;\n\tstruct ib_rwq_ind_table *rwq_ind_tbl;\n\tstruct ib_qp_security *qp_sec;\n\tu32 port;\n\tbool integrity_en;\n\tstruct rdma_restrack_entry res;\n\tstruct rdma_counter *counter;\n};\n\nstruct ib_usrq_object;\n\nenum ib_srq_type {\n\tIB_SRQT_BASIC = 0,\n\tIB_SRQT_XRC = 1,\n\tIB_SRQT_TM = 2,\n};\n\nstruct ib_srq {\n\tstruct ib_device *device;\n\tstruct ib_pd *pd;\n\tstruct ib_usrq_object *uobject;\n\tvoid (*event_handler)(struct ib_event *, void *);\n\tvoid *srq_context;\n\tenum ib_srq_type srq_type;\n\tatomic_t usecnt;\n\tstruct {\n\t\tstruct ib_cq *cq;\n\t\tunion {\n\t\t\tstruct {\n\t\t\t\tstruct ib_xrcd *xrcd;\n\t\t\t\tu32 srq_num;\n\t\t\t} xrc;\n\t\t};\n\t} ext;\n\tstruct rdma_restrack_entry res;\n};\n\nstruct ib_uwq_object;\n\nenum ib_wq_state {\n\tIB_WQS_RESET = 0,\n\tIB_WQS_RDY = 1,\n\tIB_WQS_ERR = 2,\n};\n\nenum ib_wq_type {\n\tIB_WQT_RQ = 0,\n};\n\nstruct ib_wq {\n\tstruct ib_device *device;\n\tstruct ib_uwq_object *uobject;\n\tvoid *wq_context;\n\tvoid (*event_handler)(struct ib_event *, void *);\n\tstruct ib_pd *pd;\n\tstruct ib_cq *cq;\n\tu32 wq_num;\n\tenum ib_wq_state state;\n\tenum ib_wq_type wq_type;\n\tatomic_t usecnt;\n};\n\nstruct ib_event {\n\tstruct ib_device *device;\n\tunion {\n\t\tstruct ib_cq *cq;\n\t\tstruct ib_qp *qp;\n\t\tstruct ib_srq *srq;\n\t\tstruct ib_wq *wq;\n\t\tu32 port_num;\n\t} element;\n\tenum ib_event_type event;\n};\n\nstruct ib_global_route {\n\tconst struct ib_gid_attr *sgid_attr;\n\tunion ib_gid dgid;\n\tu32 flow_label;\n\tu8 sgid_index;\n\tu8 hop_limit;\n\tu8 traffic_class;\n};\n\nstruct ib_grh {\n\t__be32 version_tclass_flow;\n\t__be16 paylen;\n\tu8 next_hdr;\n\tu8 hop_limit;\n\tunion ib_gid sgid;\n\tunion ib_gid dgid;\n};\n\nstruct ib_mr_status {\n\tu32 fail_status;\n\tstruct ib_sig_err sig_err;\n};\n\nstruct rdma_ah_init_attr {\n\tstruct rdma_ah_attr *ah_attr;\n\tu32 flags;\n\tstruct net_device *xmit_slave;\n};\n\nenum rdma_ah_attr_type {\n\tRDMA_AH_ATTR_TYPE_UNDEFINED = 0,\n\tRDMA_AH_ATTR_TYPE_IB = 1,\n\tRDMA_AH_ATTR_TYPE_ROCE = 2,\n\tRDMA_AH_ATTR_TYPE_OPA = 3,\n};\n\nstruct ib_ah_attr {\n\tu16 dlid;\n\tu8 src_path_bits;\n};\n\nstruct roce_ah_attr {\n\tu8 dmac[6];\n};\n\nstruct opa_ah_attr {\n\tu32 dlid;\n\tu8 src_path_bits;\n\tbool make_grd;\n};\n\nstruct rdma_ah_attr {\n\tstruct ib_global_route grh;\n\tu8 sl;\n\tu8 static_rate;\n\tu32 port_num;\n\tu8 ah_flags;\n\tenum rdma_ah_attr_type type;\n\tunion {\n\t\tstruct ib_ah_attr ib;\n\t\tstruct roce_ah_attr roce;\n\t\tstruct opa_ah_attr opa;\n\t};\n};\n\nenum ib_wc_status {\n\tIB_WC_SUCCESS = 0,\n\tIB_WC_LOC_LEN_ERR = 1,\n\tIB_WC_LOC_QP_OP_ERR = 2,\n\tIB_WC_LOC_EEC_OP_ERR = 3,\n\tIB_WC_LOC_PROT_ERR = 4,\n\tIB_WC_WR_FLUSH_ERR = 5,\n\tIB_WC_MW_BIND_ERR = 6,\n\tIB_WC_BAD_RESP_ERR = 7,\n\tIB_WC_LOC_ACCESS_ERR = 8,\n\tIB_WC_REM_INV_REQ_ERR = 9,\n\tIB_WC_REM_ACCESS_ERR = 10,\n\tIB_WC_REM_OP_ERR = 11,\n\tIB_WC_RETRY_EXC_ERR = 12,\n\tIB_WC_RNR_RETRY_EXC_ERR = 13,\n\tIB_WC_LOC_RDD_VIOL_ERR = 14,\n\tIB_WC_REM_INV_RD_REQ_ERR = 15,\n\tIB_WC_REM_ABORT_ERR = 16,\n\tIB_WC_INV_EECN_ERR = 17,\n\tIB_WC_INV_EEC_STATE_ERR = 18,\n\tIB_WC_FATAL_ERR = 19,\n\tIB_WC_RESP_TIMEOUT_ERR = 20,\n\tIB_WC_GENERAL_ERR = 21,\n};\n\nenum ib_wc_opcode {\n\tIB_WC_SEND = 0,\n\tIB_WC_RDMA_WRITE = 1,\n\tIB_WC_RDMA_READ = 2,\n\tIB_WC_COMP_SWAP = 3,\n\tIB_WC_FETCH_ADD = 4,\n\tIB_WC_BIND_MW = 5,\n\tIB_WC_LOCAL_INV = 6,\n\tIB_WC_LSO = 7,\n\tIB_WC_REG_MR = 8,\n\tIB_WC_MASKED_COMP_SWAP = 9,\n\tIB_WC_MASKED_FETCH_ADD = 10,\n\tIB_WC_RECV = 128,\n\tIB_WC_RECV_RDMA_WITH_IMM = 129,\n};\n\nstruct ib_cqe {\n\tvoid (*done)(struct ib_cq *, struct ib_wc *);\n};\n\nstruct ib_wc {\n\tunion {\n\t\tu64 wr_id;\n\t\tstruct ib_cqe *wr_cqe;\n\t};\n\tenum ib_wc_status status;\n\tenum ib_wc_opcode opcode;\n\tu32 vendor_err;\n\tu32 byte_len;\n\tstruct ib_qp *qp;\n\tunion {\n\t\t__be32 imm_data;\n\t\tu32 invalidate_rkey;\n\t} ex;\n\tu32 src_qp;\n\tu32 slid;\n\tint wc_flags;\n\tu16 pkey_index;\n\tu8 sl;\n\tu8 dlid_path_bits;\n\tu32 port_num;\n\tu8 smac[6];\n\tu16 vlan_id;\n\tu8 network_hdr_type;\n};\n\nstruct ib_srq_attr {\n\tu32 max_wr;\n\tu32 max_sge;\n\tu32 srq_limit;\n};\n\nstruct ib_xrcd {\n\tstruct ib_device *device;\n\tatomic_t usecnt;\n\tstruct inode *inode;\n\tstruct rw_semaphore tgt_qps_rwsem;\n\tstruct xarray tgt_qps;\n};\n\nstruct ib_srq_init_attr {\n\tvoid (*event_handler)(struct ib_event *, void *);\n\tvoid *srq_context;\n\tstruct ib_srq_attr attr;\n\tenum ib_srq_type srq_type;\n\tstruct {\n\t\tstruct ib_cq *cq;\n\t\tunion {\n\t\t\tstruct {\n\t\t\t\tstruct ib_xrcd *xrcd;\n\t\t\t} xrc;\n\t\t\tstruct {\n\t\t\t\tu32 max_num_tags;\n\t\t\t} tag_matching;\n\t\t};\n\t} ext;\n};\n\nstruct ib_qp_cap {\n\tu32 max_send_wr;\n\tu32 max_recv_wr;\n\tu32 max_send_sge;\n\tu32 max_recv_sge;\n\tu32 max_inline_data;\n\tu32 max_rdma_ctxs;\n};\n\nenum ib_sig_type {\n\tIB_SIGNAL_ALL_WR = 0,\n\tIB_SIGNAL_REQ_WR = 1,\n};\n\nstruct ib_qp_init_attr {\n\tvoid (*event_handler)(struct ib_event *, void *);\n\tvoid *qp_context;\n\tstruct ib_cq *send_cq;\n\tstruct ib_cq *recv_cq;\n\tstruct ib_srq *srq;\n\tstruct ib_xrcd *xrcd;\n\tstruct ib_qp_cap cap;\n\tenum ib_sig_type sq_sig_type;\n\tenum ib_qp_type qp_type;\n\tu32 create_flags;\n\tu32 port_num;\n\tstruct ib_rwq_ind_table *rwq_ind_tbl;\n\tu32 source_qpn;\n};\n\nstruct ib_uobject;\n\nstruct ib_rwq_ind_table {\n\tstruct ib_device *device;\n\tstruct ib_uobject *uobject;\n\tatomic_t usecnt;\n\tu32 ind_tbl_num;\n\tu32 log_ind_tbl_size;\n\tstruct ib_wq **ind_tbl;\n};\n\nenum ib_qp_state {\n\tIB_QPS_RESET = 0,\n\tIB_QPS_INIT = 1,\n\tIB_QPS_RTR = 2,\n\tIB_QPS_RTS = 3,\n\tIB_QPS_SQD = 4,\n\tIB_QPS_SQE = 5,\n\tIB_QPS_ERR = 6,\n};\n\nenum ib_mig_state {\n\tIB_MIG_MIGRATED = 0,\n\tIB_MIG_REARM = 1,\n\tIB_MIG_ARMED = 2,\n};\n\nenum ib_mw_type {\n\tIB_MW_TYPE_1 = 1,\n\tIB_MW_TYPE_2 = 2,\n};\n\nstruct ib_qp_attr {\n\tenum ib_qp_state qp_state;\n\tenum ib_qp_state cur_qp_state;\n\tenum ib_mtu path_mtu;\n\tenum ib_mig_state path_mig_state;\n\tu32 qkey;\n\tu32 rq_psn;\n\tu32 sq_psn;\n\tu32 dest_qp_num;\n\tint qp_access_flags;\n\tstruct ib_qp_cap cap;\n\tstruct rdma_ah_attr ah_attr;\n\tstruct rdma_ah_attr alt_ah_attr;\n\tu16 pkey_index;\n\tu16 alt_pkey_index;\n\tu8 en_sqd_async_notify;\n\tu8 sq_draining;\n\tu8 max_rd_atomic;\n\tu8 max_dest_rd_atomic;\n\tu8 min_rnr_timer;\n\tu32 port_num;\n\tu8 timeout;\n\tu8 retry_cnt;\n\tu8 rnr_retry;\n\tu32 alt_port_num;\n\tu8 alt_timeout;\n\tu32 rate_limit;\n\tstruct net_device *xmit_slave;\n};\n\nenum ib_wr_opcode {\n\tIB_WR_RDMA_WRITE = 0,\n\tIB_WR_RDMA_WRITE_WITH_IMM = 1,\n\tIB_WR_SEND = 2,\n\tIB_WR_SEND_WITH_IMM = 3,\n\tIB_WR_RDMA_READ = 4,\n\tIB_WR_ATOMIC_CMP_AND_SWP = 5,\n\tIB_WR_ATOMIC_FETCH_AND_ADD = 6,\n\tIB_WR_BIND_MW = 8,\n\tIB_WR_LSO = 10,\n\tIB_WR_SEND_WITH_INV = 9,\n\tIB_WR_RDMA_READ_WITH_INV = 11,\n\tIB_WR_LOCAL_INV = 7,\n\tIB_WR_MASKED_ATOMIC_CMP_AND_SWP = 12,\n\tIB_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13,\n\tIB_WR_REG_MR = 32,\n\tIB_WR_REG_MR_INTEGRITY = 33,\n\tIB_WR_RESERVED1 = 240,\n\tIB_WR_RESERVED2 = 241,\n\tIB_WR_RESERVED3 = 242,\n\tIB_WR_RESERVED4 = 243,\n\tIB_WR_RESERVED5 = 244,\n\tIB_WR_RESERVED6 = 245,\n\tIB_WR_RESERVED7 = 246,\n\tIB_WR_RESERVED8 = 247,\n\tIB_WR_RESERVED9 = 248,\n\tIB_WR_RESERVED10 = 249,\n};\n\nstruct ib_sge {\n\tu64 addr;\n\tu32 length;\n\tu32 lkey;\n};\n\nstruct ib_send_wr {\n\tstruct ib_send_wr *next;\n\tunion {\n\t\tu64 wr_id;\n\t\tstruct ib_cqe *wr_cqe;\n\t};\n\tstruct ib_sge *sg_list;\n\tint num_sge;\n\tenum ib_wr_opcode opcode;\n\tint send_flags;\n\tunion {\n\t\t__be32 imm_data;\n\t\tu32 invalidate_rkey;\n\t} ex;\n};\n\nstruct ib_ah {\n\tstruct ib_device *device;\n\tstruct ib_pd *pd;\n\tstruct ib_uobject *uobject;\n\tconst struct ib_gid_attr *sgid_attr;\n\tenum rdma_ah_attr_type type;\n};\n\nstruct ib_mr {\n\tstruct ib_device *device;\n\tstruct ib_pd *pd;\n\tu32 lkey;\n\tu32 rkey;\n\tu64 iova;\n\tu64 length;\n\tunsigned int page_size;\n\tenum ib_mr_type type;\n\tbool need_inval;\n\tunion {\n\t\tstruct ib_uobject *uobject;\n\t\tstruct list_head qp_entry;\n\t};\n\tstruct ib_dm *dm;\n\tstruct ib_sig_attrs *sig_attrs;\n\tstruct rdma_restrack_entry res;\n};\n\nstruct ib_recv_wr {\n\tstruct ib_recv_wr *next;\n\tunion {\n\t\tu64 wr_id;\n\t\tstruct ib_cqe *wr_cqe;\n\t};\n\tstruct ib_sge *sg_list;\n\tint num_sge;\n};\n\nstruct ib_rdmacg_object {\n\tstruct rdma_cgroup *cg;\n};\n\nstruct ib_uverbs_file;\n\nstruct ib_ucontext {\n\tstruct ib_device *device;\n\tstruct ib_uverbs_file *ufile;\n\tstruct ib_rdmacg_object cg_obj;\n\tstruct rdma_restrack_entry res;\n\tstruct xarray mmap_xa;\n};\n\nstruct uverbs_api_object;\n\nstruct ib_uobject {\n\tu64 user_handle;\n\tstruct ib_uverbs_file *ufile;\n\tstruct ib_ucontext *context;\n\tvoid *object;\n\tstruct list_head list;\n\tstruct ib_rdmacg_object cg_obj;\n\tint id;\n\tstruct kref ref;\n\tatomic_t usecnt;\n\tstruct callback_head rcu;\n\tconst struct uverbs_api_object *uapi_object;\n};\n\nstruct ib_udata {\n\tconst void *inbuf;\n\tvoid *outbuf;\n\tsize_t inlen;\n\tsize_t outlen;\n};\n\nstruct ib_pd {\n\tu32 local_dma_lkey;\n\tu32 flags;\n\tstruct ib_device *device;\n\tstruct ib_uobject *uobject;\n\tatomic_t usecnt;\n\tu32 unsafe_global_rkey;\n\tstruct ib_mr *__internal_mr;\n\tstruct rdma_restrack_entry res;\n};\n\nstruct ib_wq_init_attr {\n\tvoid *wq_context;\n\tenum ib_wq_type wq_type;\n\tu32 max_wr;\n\tu32 max_sge;\n\tstruct ib_cq *cq;\n\tvoid (*event_handler)(struct ib_event *, void *);\n\tu32 create_flags;\n};\n\nstruct ib_wq_attr {\n\tenum ib_wq_state wq_state;\n\tenum ib_wq_state curr_wq_state;\n\tu32 flags;\n\tu32 flags_mask;\n};\n\nstruct ib_rwq_ind_table_init_attr {\n\tu32 log_ind_tbl_size;\n\tstruct ib_wq **ind_tbl;\n};\n\nenum port_pkey_state {\n\tIB_PORT_PKEY_NOT_VALID = 0,\n\tIB_PORT_PKEY_VALID = 1,\n\tIB_PORT_PKEY_LISTED = 2,\n};\n\nstruct ib_port_pkey {\n\tenum port_pkey_state state;\n\tu16 pkey_index;\n\tu32 port_num;\n\tstruct list_head qp_list;\n\tstruct list_head to_error_list;\n\tstruct ib_qp_security *sec;\n};\n\nstruct ib_ports_pkeys;\n\nstruct ib_qp_security {\n\tstruct ib_qp *qp;\n\tstruct ib_device *dev;\n\tstruct mutex mutex;\n\tstruct ib_ports_pkeys *ports_pkeys;\n\tstruct list_head shared_qp_list;\n\tvoid *security;\n\tbool destroying;\n\tatomic_t error_list_count;\n\tstruct completion error_complete;\n\tint error_comps_pending;\n};\n\nstruct ib_ports_pkeys {\n\tstruct ib_port_pkey main;\n\tstruct ib_port_pkey alt;\n};\n\nstruct ib_dm {\n\tstruct ib_device *device;\n\tu32 length;\n\tu32 flags;\n\tstruct ib_uobject *uobject;\n\tatomic_t usecnt;\n};\n\nstruct ib_mw {\n\tstruct ib_device *device;\n\tstruct ib_pd *pd;\n\tstruct ib_uobject *uobject;\n\tu32 rkey;\n\tenum ib_mw_type type;\n};\n\nenum ib_flow_attr_type {\n\tIB_FLOW_ATTR_NORMAL = 0,\n\tIB_FLOW_ATTR_ALL_DEFAULT = 1,\n\tIB_FLOW_ATTR_MC_DEFAULT = 2,\n\tIB_FLOW_ATTR_SNIFFER = 3,\n};\n\nenum ib_flow_spec_type {\n\tIB_FLOW_SPEC_ETH = 32,\n\tIB_FLOW_SPEC_IB = 34,\n\tIB_FLOW_SPEC_IPV4 = 48,\n\tIB_FLOW_SPEC_IPV6 = 49,\n\tIB_FLOW_SPEC_ESP = 52,\n\tIB_FLOW_SPEC_TCP = 64,\n\tIB_FLOW_SPEC_UDP = 65,\n\tIB_FLOW_SPEC_VXLAN_TUNNEL = 80,\n\tIB_FLOW_SPEC_GRE = 81,\n\tIB_FLOW_SPEC_MPLS = 96,\n\tIB_FLOW_SPEC_INNER = 256,\n\tIB_FLOW_SPEC_ACTION_TAG = 4096,\n\tIB_FLOW_SPEC_ACTION_DROP = 4097,\n\tIB_FLOW_SPEC_ACTION_HANDLE = 4098,\n\tIB_FLOW_SPEC_ACTION_COUNT = 4099,\n};\n\nstruct ib_flow_eth_filter {\n\tu8 dst_mac[6];\n\tu8 src_mac[6];\n\t__be16 ether_type;\n\t__be16 vlan_tag;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_eth {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_eth_filter val;\n\tstruct ib_flow_eth_filter mask;\n};\n\nstruct ib_flow_ib_filter {\n\t__be16 dlid;\n\t__u8 sl;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_ib {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_ib_filter val;\n\tstruct ib_flow_ib_filter mask;\n};\n\nstruct ib_flow_ipv4_filter {\n\t__be32 src_ip;\n\t__be32 dst_ip;\n\tu8 proto;\n\tu8 tos;\n\tu8 ttl;\n\tu8 flags;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_ipv4 {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_ipv4_filter val;\n\tstruct ib_flow_ipv4_filter mask;\n};\n\nstruct ib_flow_ipv6_filter {\n\tu8 src_ip[16];\n\tu8 dst_ip[16];\n\t__be32 flow_label;\n\tu8 next_hdr;\n\tu8 traffic_class;\n\tu8 hop_limit;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_ipv6 {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_ipv6_filter val;\n\tstruct ib_flow_ipv6_filter mask;\n};\n\nstruct ib_flow_tcp_udp_filter {\n\t__be16 dst_port;\n\t__be16 src_port;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_tcp_udp {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_tcp_udp_filter val;\n\tstruct ib_flow_tcp_udp_filter mask;\n};\n\nstruct ib_flow_tunnel_filter {\n\t__be32 tunnel_id;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_tunnel {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_tunnel_filter val;\n\tstruct ib_flow_tunnel_filter mask;\n};\n\nstruct ib_flow_esp_filter {\n\t__be32 spi;\n\t__be32 seq;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_esp {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_esp_filter val;\n\tstruct ib_flow_esp_filter mask;\n};\n\nstruct ib_flow_gre_filter {\n\t__be16 c_ks_res0_ver;\n\t__be16 protocol;\n\t__be32 key;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_gre {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_gre_filter val;\n\tstruct ib_flow_gre_filter mask;\n};\n\nstruct ib_flow_mpls_filter {\n\t__be32 tag;\n\tu8 real_sz[0];\n};\n\nstruct ib_flow_spec_mpls {\n\tu32 type;\n\tu16 size;\n\tstruct ib_flow_mpls_filter val;\n\tstruct ib_flow_mpls_filter mask;\n};\n\nstruct ib_flow_spec_action_tag {\n\tenum ib_flow_spec_type type;\n\tu16 size;\n\tu32 tag_id;\n};\n\nstruct ib_flow_spec_action_drop {\n\tenum ib_flow_spec_type type;\n\tu16 size;\n};\n\nstruct ib_flow_spec_action_handle {\n\tenum ib_flow_spec_type type;\n\tu16 size;\n\tstruct ib_flow_action *act;\n};\n\nenum ib_flow_action_type {\n\tIB_FLOW_ACTION_UNSPECIFIED = 0,\n\tIB_FLOW_ACTION_ESP = 1,\n};\n\nstruct ib_flow_action {\n\tstruct ib_device *device;\n\tstruct ib_uobject *uobject;\n\tenum ib_flow_action_type type;\n\tatomic_t usecnt;\n};\n\nstruct ib_flow_spec_action_count {\n\tenum ib_flow_spec_type type;\n\tu16 size;\n\tstruct ib_counters *counters;\n};\n\nstruct ib_counters {\n\tstruct ib_device *device;\n\tstruct ib_uobject *uobject;\n\tatomic_t usecnt;\n};\n\nunion ib_flow_spec {\n\tstruct {\n\t\tu32 type;\n\t\tu16 size;\n\t};\n\tstruct ib_flow_spec_eth eth;\n\tstruct ib_flow_spec_ib ib;\n\tstruct ib_flow_spec_ipv4 ipv4;\n\tstruct ib_flow_spec_tcp_udp tcp_udp;\n\tstruct ib_flow_spec_ipv6 ipv6;\n\tstruct ib_flow_spec_tunnel tunnel;\n\tstruct ib_flow_spec_esp esp;\n\tstruct ib_flow_spec_gre gre;\n\tstruct ib_flow_spec_mpls mpls;\n\tstruct ib_flow_spec_action_tag flow_tag;\n\tstruct ib_flow_spec_action_drop drop;\n\tstruct ib_flow_spec_action_handle action;\n\tstruct ib_flow_spec_action_count flow_count;\n};\n\nstruct ib_flow_attr {\n\tenum ib_flow_attr_type type;\n\tu16 size;\n\tu16 priority;\n\tu32 flags;\n\tu8 num_of_specs;\n\tu32 port;\n\tunion ib_flow_spec flows[0];\n};\n\nstruct ib_flow {\n\tstruct ib_qp *qp;\n\tstruct ib_device *device;\n\tstruct ib_uobject *uobject;\n};\n\nstruct ib_flow_action_attrs_esp_keymats {\n\tenum ib_uverbs_flow_action_esp_keymat protocol;\n\tunion {\n\t\tstruct ib_uverbs_flow_action_esp_keymat_aes_gcm aes_gcm;\n\t} keymat;\n};\n\nstruct ib_flow_action_attrs_esp_replays {\n\tenum ib_uverbs_flow_action_esp_replay protocol;\n\tunion {\n\t\tstruct ib_uverbs_flow_action_esp_replay_bmp bmp;\n\t} replay;\n};\n\nstruct ib_flow_spec_list {\n\tstruct ib_flow_spec_list *next;\n\tunion ib_flow_spec spec;\n};\n\nstruct ib_flow_action_attrs_esp {\n\tstruct ib_flow_action_attrs_esp_keymats *keymat;\n\tstruct ib_flow_action_attrs_esp_replays *replay;\n\tstruct ib_flow_spec_list *encap;\n\tu32 esn;\n\tu32 spi;\n\tu32 seq;\n\tu32 tfc_pad;\n\tu64 flags;\n\tu64 hard_limit_pkts;\n};\n\nstruct ib_pkey_cache;\n\nstruct ib_gid_table;\n\nstruct ib_port_cache {\n\tu64 subnet_prefix;\n\tstruct ib_pkey_cache *pkey;\n\tstruct ib_gid_table *gid;\n\tu8 lmc;\n\tenum ib_port_state port_state;\n};\n\nstruct ib_port_immutable {\n\tint pkey_tbl_len;\n\tint gid_tbl_len;\n\tu32 core_cap_flags;\n\tu32 max_mad_size;\n};\n\nstruct ib_port;\n\nstruct ib_port_data {\n\tstruct ib_device *ib_dev;\n\tstruct ib_port_immutable immutable;\n\tspinlock_t pkey_list_lock;\n\tspinlock_t netdev_lock;\n\tstruct list_head pkey_list;\n\tstruct ib_port_cache cache;\n\tstruct net_device *netdev;\n\tstruct hlist_node ndev_hash_link;\n\tstruct rdma_port_counter port_counter;\n\tstruct ib_port *sysfs;\n};\n\nstruct rdma_netdev_alloc_params {\n\tsize_t sizeof_priv;\n\tunsigned int txqs;\n\tunsigned int rxqs;\n\tvoid *param;\n\tint (*initialize_rdma_netdev)(struct ib_device *, u32, struct net_device *, void *);\n};\n\nstruct ib_counters_read_attr {\n\tu64 *counters_buff;\n\tu32 ncounters;\n\tu32 flags;\n};\n\nstruct rdma_user_mmap_entry {\n\tstruct kref ref;\n\tstruct ib_ucontext *ucontext;\n\tlong unsigned int start_pgoff;\n\tsize_t npages;\n\tbool driver_removed;\n};\n\nenum blk_zone_type {\n\tBLK_ZONE_TYPE_CONVENTIONAL = 1,\n\tBLK_ZONE_TYPE_SEQWRITE_REQ = 2,\n\tBLK_ZONE_TYPE_SEQWRITE_PREF = 3,\n};\n\nenum blk_zone_cond {\n\tBLK_ZONE_COND_NOT_WP = 0,\n\tBLK_ZONE_COND_EMPTY = 1,\n\tBLK_ZONE_COND_IMP_OPEN = 2,\n\tBLK_ZONE_COND_EXP_OPEN = 3,\n\tBLK_ZONE_COND_CLOSED = 4,\n\tBLK_ZONE_COND_READONLY = 13,\n\tBLK_ZONE_COND_FULL = 14,\n\tBLK_ZONE_COND_OFFLINE = 15,\n};\n\nenum blk_zone_report_flags {\n\tBLK_ZONE_REP_CAPACITY = 1,\n};\n\nstruct blk_zone_report {\n\t__u64 sector;\n\t__u32 nr_zones;\n\t__u32 flags;\n\tstruct blk_zone zones[0];\n};\n\nstruct blk_zone_range {\n\t__u64 sector;\n\t__u64 nr_sectors;\n};\n\nstruct zone_report_args {\n\tstruct blk_zone *zones;\n};\n\nstruct blk_revalidate_zone_args {\n\tstruct gendisk *disk;\n\tlong unsigned int *conv_zones_bitmap;\n\tlong unsigned int *seq_zones_wlock;\n\tunsigned int nr_zones;\n\tsector_t zone_sectors;\n\tsector_t sector;\n};\n\nenum wbt_flags {\n\tWBT_TRACKED = 1,\n\tWBT_READ = 2,\n\tWBT_KSWAPD = 4,\n\tWBT_DISCARD = 8,\n\tWBT_NR_BITS = 4,\n};\n\nenum {\n\tWBT_STATE_ON_DEFAULT = 1,\n\tWBT_STATE_ON_MANUAL = 2,\n\tWBT_STATE_OFF_DEFAULT = 3,\n};\n\nstruct rq_wb {\n\tunsigned int wb_background;\n\tunsigned int wb_normal;\n\tshort int enable_state;\n\tunsigned int unknown_cnt;\n\tu64 win_nsec;\n\tu64 cur_win_nsec;\n\tstruct blk_stat_callback *cb;\n\tu64 sync_issue;\n\tvoid *sync_cookie;\n\tunsigned int wc;\n\tlong unsigned int last_issue;\n\tlong unsigned int last_comp;\n\tlong unsigned int min_lat_nsec;\n\tstruct rq_qos rqos;\n\tstruct rq_wait rq_wait[3];\n\tstruct rq_depth rq_depth;\n};\n\nstruct trace_event_raw_wbt_stat {\n\tstruct trace_entry ent;\n\tchar name[32];\n\ts64 rmean;\n\tu64 rmin;\n\tu64 rmax;\n\ts64 rnr_samples;\n\ts64 rtime;\n\ts64 wmean;\n\tu64 wmin;\n\tu64 wmax;\n\ts64 wnr_samples;\n\ts64 wtime;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_wbt_lat {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tlong unsigned int lat;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_wbt_step {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tconst char *msg;\n\tint step;\n\tlong unsigned int window;\n\tunsigned int bg;\n\tunsigned int normal;\n\tunsigned int max;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_wbt_timer {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tunsigned int status;\n\tint step;\n\tunsigned int inflight;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_wbt_stat {};\n\nstruct trace_event_data_offsets_wbt_lat {};\n\nstruct trace_event_data_offsets_wbt_step {};\n\nstruct trace_event_data_offsets_wbt_timer {};\n\ntypedef void (*btf_trace_wbt_stat)(void *, struct backing_dev_info *, struct blk_rq_stat *);\n\ntypedef void (*btf_trace_wbt_lat)(void *, struct backing_dev_info *, long unsigned int);\n\ntypedef void (*btf_trace_wbt_step)(void *, struct backing_dev_info *, const char *, int, long unsigned int, unsigned int, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_wbt_timer)(void *, struct backing_dev_info *, unsigned int, int, unsigned int);\n\nenum {\n\tRWB_DEF_DEPTH = 16,\n\tRWB_WINDOW_NSEC = 100000000,\n\tRWB_MIN_WRITE_SAMPLES = 3,\n\tRWB_UNKNOWN_BUMP = 5,\n};\n\nenum {\n\tLAT_OK = 1,\n\tLAT_UNKNOWN = 2,\n\tLAT_UNKNOWN_WRITES = 3,\n\tLAT_EXCEEDED = 4,\n};\n\nstruct wbt_wait_data {\n\tstruct rq_wb *rwb;\n\tenum wbt_flags wb_acct;\n\tlong unsigned int rw;\n};\n\nstruct show_busy_params {\n\tstruct seq_file *m;\n\tstruct blk_mq_hw_ctx *hctx;\n};\n\nenum opal_mbr {\n\tOPAL_MBR_ENABLE = 0,\n\tOPAL_MBR_DISABLE = 1,\n};\n\nenum opal_mbr_done_flag {\n\tOPAL_MBR_NOT_DONE = 0,\n\tOPAL_MBR_DONE = 1,\n};\n\nenum opal_user {\n\tOPAL_ADMIN1 = 0,\n\tOPAL_USER1 = 1,\n\tOPAL_USER2 = 2,\n\tOPAL_USER3 = 3,\n\tOPAL_USER4 = 4,\n\tOPAL_USER5 = 5,\n\tOPAL_USER6 = 6,\n\tOPAL_USER7 = 7,\n\tOPAL_USER8 = 8,\n\tOPAL_USER9 = 9,\n};\n\nenum opal_lock_state {\n\tOPAL_RO = 1,\n\tOPAL_RW = 2,\n\tOPAL_LK = 4,\n};\n\nstruct opal_key {\n\t__u8 lr;\n\t__u8 key_len;\n\t__u8 __align[6];\n\t__u8 key[256];\n};\n\nstruct opal_lr_act {\n\tstruct opal_key key;\n\t__u32 sum;\n\t__u8 num_lrs;\n\t__u8 lr[9];\n\t__u8 align[2];\n};\n\nstruct opal_session_info {\n\t__u32 sum;\n\t__u32 who;\n\tstruct opal_key opal_key;\n};\n\nstruct opal_user_lr_setup {\n\t__u64 range_start;\n\t__u64 range_length;\n\t__u32 RLE;\n\t__u32 WLE;\n\tstruct opal_session_info session;\n};\n\nstruct opal_lock_unlock {\n\tstruct opal_session_info session;\n\t__u32 l_state;\n\t__u8 __align[4];\n};\n\nstruct opal_new_pw {\n\tstruct opal_session_info session;\n\tstruct opal_session_info new_user_pw;\n};\n\nstruct opal_mbr_data {\n\tstruct opal_key key;\n\t__u8 enable_disable;\n\t__u8 __align[7];\n};\n\nstruct opal_mbr_done {\n\tstruct opal_key key;\n\t__u8 done_flag;\n\t__u8 __align[7];\n};\n\nstruct opal_shadow_mbr {\n\tstruct opal_key key;\n\tconst __u64 data;\n\t__u64 offset;\n\t__u64 size;\n};\n\nenum opal_table_ops {\n\tOPAL_READ_TABLE = 0,\n\tOPAL_WRITE_TABLE = 1,\n};\n\nstruct opal_read_write_table {\n\tstruct opal_key key;\n\tconst __u64 data;\n\tconst __u8 table_uid[8];\n\t__u64 offset;\n\t__u64 size;\n\t__u64 flags;\n\t__u64 priv;\n};\n\ntypedef int sec_send_recv(void *, u16, u8, void *, size_t, bool);\n\nenum {\n\tTCG_SECP_00 = 0,\n\tTCG_SECP_01 = 1,\n};\n\nenum opal_response_token {\n\tOPAL_DTA_TOKENID_BYTESTRING = 224,\n\tOPAL_DTA_TOKENID_SINT = 225,\n\tOPAL_DTA_TOKENID_UINT = 226,\n\tOPAL_DTA_TOKENID_TOKEN = 227,\n\tOPAL_DTA_TOKENID_INVALID = 0,\n};\n\nenum opal_uid {\n\tOPAL_SMUID_UID = 0,\n\tOPAL_THISSP_UID = 1,\n\tOPAL_ADMINSP_UID = 2,\n\tOPAL_LOCKINGSP_UID = 3,\n\tOPAL_ENTERPRISE_LOCKINGSP_UID = 4,\n\tOPAL_ANYBODY_UID = 5,\n\tOPAL_SID_UID = 6,\n\tOPAL_ADMIN1_UID = 7,\n\tOPAL_USER1_UID = 8,\n\tOPAL_USER2_UID = 9,\n\tOPAL_PSID_UID = 10,\n\tOPAL_ENTERPRISE_BANDMASTER0_UID = 11,\n\tOPAL_ENTERPRISE_ERASEMASTER_UID = 12,\n\tOPAL_TABLE_TABLE = 13,\n\tOPAL_LOCKINGRANGE_GLOBAL = 14,\n\tOPAL_LOCKINGRANGE_ACE_RDLOCKED = 15,\n\tOPAL_LOCKINGRANGE_ACE_WRLOCKED = 16,\n\tOPAL_MBRCONTROL = 17,\n\tOPAL_MBR = 18,\n\tOPAL_AUTHORITY_TABLE = 19,\n\tOPAL_C_PIN_TABLE = 20,\n\tOPAL_LOCKING_INFO_TABLE = 21,\n\tOPAL_ENTERPRISE_LOCKING_INFO_TABLE = 22,\n\tOPAL_DATASTORE = 23,\n\tOPAL_C_PIN_MSID = 24,\n\tOPAL_C_PIN_SID = 25,\n\tOPAL_C_PIN_ADMIN1 = 26,\n\tOPAL_HALF_UID_AUTHORITY_OBJ_REF = 27,\n\tOPAL_HALF_UID_BOOLEAN_ACE = 28,\n\tOPAL_UID_HEXFF = 29,\n};\n\nenum opal_method {\n\tOPAL_PROPERTIES = 0,\n\tOPAL_STARTSESSION = 1,\n\tOPAL_REVERT = 2,\n\tOPAL_ACTIVATE = 3,\n\tOPAL_EGET = 4,\n\tOPAL_ESET = 5,\n\tOPAL_NEXT = 6,\n\tOPAL_EAUTHENTICATE = 7,\n\tOPAL_GETACL = 8,\n\tOPAL_GENKEY = 9,\n\tOPAL_REVERTSP = 10,\n\tOPAL_GET = 11,\n\tOPAL_SET = 12,\n\tOPAL_AUTHENTICATE = 13,\n\tOPAL_RANDOM = 14,\n\tOPAL_ERASE = 15,\n};\n\nenum opal_token {\n\tOPAL_TRUE = 1,\n\tOPAL_FALSE = 0,\n\tOPAL_BOOLEAN_EXPR = 3,\n\tOPAL_TABLE = 0,\n\tOPAL_STARTROW = 1,\n\tOPAL_ENDROW = 2,\n\tOPAL_STARTCOLUMN = 3,\n\tOPAL_ENDCOLUMN = 4,\n\tOPAL_VALUES = 1,\n\tOPAL_TABLE_UID = 0,\n\tOPAL_TABLE_NAME = 1,\n\tOPAL_TABLE_COMMON = 2,\n\tOPAL_TABLE_TEMPLATE = 3,\n\tOPAL_TABLE_KIND = 4,\n\tOPAL_TABLE_COLUMN = 5,\n\tOPAL_TABLE_COLUMNS = 6,\n\tOPAL_TABLE_ROWS = 7,\n\tOPAL_TABLE_ROWS_FREE = 8,\n\tOPAL_TABLE_ROW_BYTES = 9,\n\tOPAL_TABLE_LASTID = 10,\n\tOPAL_TABLE_MIN = 11,\n\tOPAL_TABLE_MAX = 12,\n\tOPAL_PIN = 3,\n\tOPAL_RANGESTART = 3,\n\tOPAL_RANGELENGTH = 4,\n\tOPAL_READLOCKENABLED = 5,\n\tOPAL_WRITELOCKENABLED = 6,\n\tOPAL_READLOCKED = 7,\n\tOPAL_WRITELOCKED = 8,\n\tOPAL_ACTIVEKEY = 10,\n\tOPAL_LIFECYCLE = 6,\n\tOPAL_MAXRANGES = 4,\n\tOPAL_MBRENABLE = 1,\n\tOPAL_MBRDONE = 2,\n\tOPAL_HOSTPROPERTIES = 0,\n\tOPAL_STARTLIST = 240,\n\tOPAL_ENDLIST = 241,\n\tOPAL_STARTNAME = 242,\n\tOPAL_ENDNAME = 243,\n\tOPAL_CALL = 248,\n\tOPAL_ENDOFDATA = 249,\n\tOPAL_ENDOFSESSION = 250,\n\tOPAL_STARTTRANSACTON = 251,\n\tOPAL_ENDTRANSACTON = 252,\n\tOPAL_EMPTYATOM = 255,\n\tOPAL_WHERE = 0,\n};\n\nenum opal_parameter {\n\tOPAL_SUM_SET_LIST = 393216,\n};\n\nstruct opal_compacket {\n\t__be32 reserved0;\n\tu8 extendedComID[4];\n\t__be32 outstandingData;\n\t__be32 minTransfer;\n\t__be32 length;\n};\n\nstruct opal_packet {\n\t__be32 tsn;\n\t__be32 hsn;\n\t__be32 seq_number;\n\t__be16 reserved0;\n\t__be16 ack_type;\n\t__be32 acknowledgment;\n\t__be32 length;\n};\n\nstruct opal_data_subpacket {\n\tu8 reserved0[6];\n\t__be16 kind;\n\t__be32 length;\n};\n\nstruct opal_header {\n\tstruct opal_compacket cp;\n\tstruct opal_packet pkt;\n\tstruct opal_data_subpacket subpkt;\n};\n\nstruct d0_header {\n\t__be32 length;\n\t__be32 revision;\n\t__be32 reserved01;\n\t__be32 reserved02;\n\tu8 ignored[32];\n};\n\nstruct d0_tper_features {\n\tu8 supported_features;\n\tu8 reserved01[3];\n\t__be32 reserved02;\n\t__be32 reserved03;\n};\n\nstruct d0_locking_features {\n\tu8 supported_features;\n\tu8 reserved01[3];\n\t__be32 reserved02;\n\t__be32 reserved03;\n};\n\nstruct d0_geometry_features {\n\tu8 header[4];\n\tu8 reserved01;\n\tu8 reserved02[7];\n\t__be32 logical_block_size;\n\t__be64 alignment_granularity;\n\t__be64 lowest_aligned_lba;\n};\n\nstruct d0_opal_v100 {\n\t__be16 baseComID;\n\t__be16 numComIDs;\n};\n\nstruct d0_single_user_mode {\n\t__be32 num_locking_objects;\n\tu8 reserved01;\n\tu8 reserved02;\n\t__be16 reserved03;\n\t__be32 reserved04;\n};\n\nstruct d0_opal_v200 {\n\t__be16 baseComID;\n\t__be16 numComIDs;\n\tu8 range_crossing;\n\tu8 num_locking_admin_auth[2];\n\tu8 num_locking_user_auth[2];\n\tu8 initialPIN;\n\tu8 revertedPIN;\n\tu8 reserved01;\n\t__be32 reserved02;\n};\n\nstruct d0_features {\n\t__be16 code;\n\tu8 r_version;\n\tu8 length;\n\tu8 features[0];\n};\n\nstruct opal_dev;\n\nstruct opal_step {\n\tint (*fn)(struct opal_dev *, void *);\n\tvoid *data;\n};\n\nenum opal_atom_width {\n\tOPAL_WIDTH_TINY = 0,\n\tOPAL_WIDTH_SHORT = 1,\n\tOPAL_WIDTH_MEDIUM = 2,\n\tOPAL_WIDTH_LONG = 3,\n\tOPAL_WIDTH_TOKEN = 4,\n};\n\nstruct opal_resp_tok {\n\tconst u8 *pos;\n\tsize_t len;\n\tenum opal_response_token type;\n\tenum opal_atom_width width;\n\tunion {\n\t\tu64 u;\n\t\ts64 s;\n\t} stored;\n};\n\nstruct parsed_resp {\n\tint num;\n\tstruct opal_resp_tok toks[64];\n};\n\nstruct opal_dev {\n\tbool supported;\n\tbool mbr_enabled;\n\tvoid *data;\n\tsec_send_recv *send_recv;\n\tstruct mutex dev_lock;\n\tu16 comid;\n\tu32 hsn;\n\tu32 tsn;\n\tu64 align;\n\tu64 lowest_lba;\n\tsize_t pos;\n\tu8 cmd[2048];\n\tu8 resp[2048];\n\tstruct parsed_resp parsed;\n\tsize_t prev_d_len;\n\tvoid *prev_data;\n\tstruct list_head unlk_lst;\n};\n\ntypedef int cont_fn(struct opal_dev *);\n\nstruct opal_suspend_data {\n\tstruct opal_lock_unlock unlk;\n\tu8 lr;\n\tstruct list_head node;\n};\n\nstruct blk_ksm_keyslot {\n\tatomic_t slot_refs;\n\tstruct list_head idle_slot_node;\n\tstruct hlist_node hash_node;\n\tconst struct blk_crypto_key *key;\n\tstruct blk_keyslot_manager *ksm;\n};\n\nstruct blk_ksm_ll_ops {\n\tint (*keyslot_program)(struct blk_keyslot_manager *, const struct blk_crypto_key *, unsigned int);\n\tint (*keyslot_evict)(struct blk_keyslot_manager *, const struct blk_crypto_key *, unsigned int);\n};\n\nstruct blk_keyslot_manager {\n\tstruct blk_ksm_ll_ops ksm_ll_ops;\n\tunsigned int max_dun_bytes_supported;\n\tunsigned int crypto_modes_supported[4];\n\tstruct device *dev;\n\tunsigned int num_slots;\n\tstruct rw_semaphore lock;\n\twait_queue_head_t idle_slots_wait_queue;\n\tstruct list_head idle_slots;\n\tspinlock_t idle_slots_lock;\n\tstruct hlist_head *slot_hashtable;\n\tunsigned int log_slot_ht_size;\n\tstruct blk_ksm_keyslot *slots;\n};\n\nstruct blk_crypto_mode {\n\tconst char *cipher_str;\n\tunsigned int keysize;\n\tunsigned int ivsize;\n};\n\nstruct bio_fallback_crypt_ctx {\n\tstruct bio_crypt_ctx crypt_ctx;\n\tstruct bvec_iter crypt_iter;\n\tunion {\n\t\tstruct {\n\t\t\tstruct work_struct work;\n\t\t\tstruct bio *bio;\n\t\t};\n\t\tstruct {\n\t\t\tvoid *bi_private_orig;\n\t\t\tbio_end_io_t *bi_end_io_orig;\n\t\t};\n\t};\n};\n\nstruct blk_crypto_keyslot {\n\tenum blk_crypto_mode_num crypto_mode;\n\tstruct crypto_skcipher *tfms[4];\n};\n\nunion blk_crypto_iv {\n\t__le64 dun[4];\n\tu8 bytes[32];\n};\n\ntypedef int (*cmp_r_func_t)(const void *, const void *, const void *);\n\nstruct random_ready_callback {\n\tstruct list_head list;\n\tvoid (*func)(struct random_ready_callback *);\n\tstruct module *owner;\n};\n\nstruct siprand_state {\n\tlong unsigned int v0;\n\tlong unsigned int v1;\n\tlong unsigned int v2;\n\tlong unsigned int v3;\n};\n\nstruct region {\n\tunsigned int start;\n\tunsigned int off;\n\tunsigned int group_len;\n\tunsigned int end;\n\tunsigned int nbits;\n};\n\nenum {\n\tREG_OP_ISFREE = 0,\n\tREG_OP_ALLOC = 1,\n\tREG_OP_RELEASE = 2,\n};\n\ntypedef struct scatterlist *sg_alloc_fn(unsigned int, gfp_t);\n\ntypedef void sg_free_fn(struct scatterlist *, unsigned int);\n\nstruct sg_page_iter {\n\tstruct scatterlist *sg;\n\tunsigned int sg_pgoffset;\n\tunsigned int __nents;\n\tint __pg_advance;\n};\n\nstruct sg_dma_page_iter {\n\tstruct sg_page_iter base;\n};\n\nstruct sg_mapping_iter {\n\tstruct page *page;\n\tvoid *addr;\n\tsize_t length;\n\tsize_t consumed;\n\tstruct sg_page_iter piter;\n\tunsigned int __offset;\n\tunsigned int __remaining;\n\tunsigned int __flags;\n};\n\nstruct csum_state {\n\t__wsum csum;\n\tsize_t off;\n};\n\nstruct rhltable {\n\tstruct rhashtable ht;\n};\n\nstruct rhashtable_walker {\n\tstruct list_head list;\n\tstruct bucket_table *tbl;\n};\n\nstruct rhashtable_iter {\n\tstruct rhashtable *ht;\n\tstruct rhash_head *p;\n\tstruct rhlist_head *list;\n\tstruct rhashtable_walker walker;\n\tunsigned int slot;\n\tunsigned int skip;\n\tbool end_of_table;\n};\n\nunion nested_table {\n\tunion nested_table *table;\n\tstruct rhash_lock_head *bucket;\n};\n\nstruct once_work {\n\tstruct work_struct work;\n\tstruct static_key_true *key;\n\tstruct module *module;\n};\n\nstruct genradix_iter {\n\tsize_t offset;\n\tsize_t pos;\n};\n\nstruct genradix_node {\n\tunion {\n\t\tstruct genradix_node *children[512];\n\t\tu8 data[4096];\n\t};\n};\n\nstruct reciprocal_value_adv {\n\tu32 m;\n\tu8 sh;\n\tu8 exp;\n\tbool is_wide_m;\n};\n\nenum devm_ioremap_type {\n\tDEVM_IOREMAP = 0,\n\tDEVM_IOREMAP_UC = 1,\n\tDEVM_IOREMAP_WC = 2,\n\tDEVM_IOREMAP_NP = 3,\n};\n\nstruct pcim_iomap_devres {\n\tvoid *table[6];\n};\n\nstruct btree_head {\n\tlong unsigned int *node;\n\tmempool_t *mempool;\n\tint height;\n};\n\nstruct btree_geo {\n\tint keylen;\n\tint no_pairs;\n\tint no_longs;\n};\n\ntypedef void (*visitor128_t)(void *, long unsigned int, u64, u64, size_t);\n\ntypedef void (*visitorl_t)(void *, long unsigned int, long unsigned int, size_t);\n\ntypedef void (*visitor32_t)(void *, long unsigned int, u32, size_t);\n\ntypedef void (*visitor64_t)(void *, long unsigned int, u64, size_t);\n\nenum assoc_array_walk_status {\n\tassoc_array_walk_tree_empty = 0,\n\tassoc_array_walk_found_terminal_node = 1,\n\tassoc_array_walk_found_wrong_shortcut = 2,\n};\n\nstruct assoc_array_walk_result {\n\tstruct {\n\t\tstruct assoc_array_node *node;\n\t\tint level;\n\t\tint slot;\n\t} terminal_node;\n\tstruct {\n\t\tstruct assoc_array_shortcut *shortcut;\n\t\tint level;\n\t\tint sc_level;\n\t\tlong unsigned int sc_segments;\n\t\tlong unsigned int dissimilarity;\n\t} wrong_shortcut;\n};\n\nstruct assoc_array_delete_collapse_context {\n\tstruct assoc_array_node *node;\n\tconst void *skip_leaf;\n\tint slot;\n};\n\nstruct linear_range {\n\tunsigned int min;\n\tunsigned int min_sel;\n\tunsigned int max_sel;\n\tunsigned int step;\n};\n\nenum packing_op {\n\tPACK = 0,\n\tUNPACK = 1,\n};\n\nstruct xxh32_state {\n\tuint32_t total_len_32;\n\tuint32_t large_len;\n\tuint32_t v1;\n\tuint32_t v2;\n\tuint32_t v3;\n\tuint32_t v4;\n\tuint32_t mem32[4];\n\tuint32_t memsize;\n};\n\nstruct xxh64_state {\n\tuint64_t total_len;\n\tuint64_t v1;\n\tuint64_t v2;\n\tuint64_t v3;\n\tuint64_t v4;\n\tuint64_t mem64[4];\n\tuint32_t memsize;\n};\n\nstruct gen_pool_chunk {\n\tstruct list_head next_chunk;\n\tatomic_long_t avail;\n\tphys_addr_t phys_addr;\n\tvoid *owner;\n\tlong unsigned int start_addr;\n\tlong unsigned int end_addr;\n\tlong unsigned int bits[0];\n};\n\nstruct genpool_data_align {\n\tint align;\n};\n\nstruct genpool_data_fixed {\n\tlong unsigned int offset;\n};\n\ntypedef struct {\n\tunsigned char op;\n\tunsigned char bits;\n\tshort unsigned int val;\n} code;\n\ntypedef enum {\n\tHEAD = 0,\n\tFLAGS = 1,\n\tTIME = 2,\n\tOS = 3,\n\tEXLEN = 4,\n\tEXTRA = 5,\n\tNAME = 6,\n\tCOMMENT = 7,\n\tHCRC = 8,\n\tDICTID = 9,\n\tDICT = 10,\n\tTYPE = 11,\n\tTYPEDO = 12,\n\tSTORED = 13,\n\tCOPY = 14,\n\tTABLE = 15,\n\tLENLENS = 16,\n\tCODELENS = 17,\n\tLEN = 18,\n\tLENEXT = 19,\n\tDIST = 20,\n\tDISTEXT = 21,\n\tMATCH = 22,\n\tLIT = 23,\n\tCHECK = 24,\n\tLENGTH = 25,\n\tDONE = 26,\n\tBAD = 27,\n\tMEM = 28,\n\tSYNC = 29,\n} inflate_mode;\n\nstruct inflate_state {\n\tinflate_mode mode;\n\tint last;\n\tint wrap;\n\tint havedict;\n\tint flags;\n\tunsigned int dmax;\n\tlong unsigned int check;\n\tlong unsigned int total;\n\tunsigned int wbits;\n\tunsigned int wsize;\n\tunsigned int whave;\n\tunsigned int write;\n\tunsigned char *window;\n\tlong unsigned int hold;\n\tunsigned int bits;\n\tunsigned int length;\n\tunsigned int offset;\n\tunsigned int extra;\n\tconst code *lencode;\n\tconst code *distcode;\n\tunsigned int lenbits;\n\tunsigned int distbits;\n\tunsigned int ncode;\n\tunsigned int nlen;\n\tunsigned int ndist;\n\tunsigned int have;\n\tcode *next;\n\tshort unsigned int lens[320];\n\tshort unsigned int work[288];\n\tcode codes[2048];\n};\n\nunion uu {\n\tshort unsigned int us;\n\tunsigned char b[2];\n};\n\ntypedef unsigned int uInt;\n\ntypedef enum {\n\tCODES = 0,\n\tLENS = 1,\n\tDISTS = 2,\n} codetype;\n\nstruct inflate_workspace {\n\tstruct inflate_state inflate_state;\n\tunsigned char working_window[32768];\n};\n\ntypedef unsigned char uch;\n\ntypedef short unsigned int ush;\n\ntypedef long unsigned int ulg;\n\nstruct ct_data_s {\n\tunion {\n\t\tush freq;\n\t\tush code;\n\t} fc;\n\tunion {\n\t\tush dad;\n\t\tush len;\n\t} dl;\n};\n\ntypedef struct ct_data_s ct_data;\n\nstruct static_tree_desc_s {\n\tconst ct_data *static_tree;\n\tconst int *extra_bits;\n\tint extra_base;\n\tint elems;\n\tint max_length;\n};\n\ntypedef struct static_tree_desc_s static_tree_desc;\n\nstruct tree_desc_s {\n\tct_data *dyn_tree;\n\tint max_code;\n\tstatic_tree_desc *stat_desc;\n};\n\ntypedef ush Pos;\n\ntypedef unsigned int IPos;\n\nstruct deflate_state {\n\tz_streamp strm;\n\tint status;\n\tByte *pending_buf;\n\tulg pending_buf_size;\n\tByte *pending_out;\n\tint pending;\n\tint noheader;\n\tByte data_type;\n\tByte method;\n\tint last_flush;\n\tuInt w_size;\n\tuInt w_bits;\n\tuInt w_mask;\n\tByte *window;\n\tulg window_size;\n\tPos *prev;\n\tPos *head;\n\tuInt ins_h;\n\tuInt hash_size;\n\tuInt hash_bits;\n\tuInt hash_mask;\n\tuInt hash_shift;\n\tlong int block_start;\n\tuInt match_length;\n\tIPos prev_match;\n\tint match_available;\n\tuInt strstart;\n\tuInt match_start;\n\tuInt lookahead;\n\tuInt prev_length;\n\tuInt max_chain_length;\n\tuInt max_lazy_match;\n\tint level;\n\tint strategy;\n\tuInt good_match;\n\tint nice_match;\n\tstruct ct_data_s dyn_ltree[573];\n\tstruct ct_data_s dyn_dtree[61];\n\tstruct ct_data_s bl_tree[39];\n\tstruct tree_desc_s l_desc;\n\tstruct tree_desc_s d_desc;\n\tstruct tree_desc_s bl_desc;\n\tush bl_count[16];\n\tint heap[573];\n\tint heap_len;\n\tint heap_max;\n\tuch depth[573];\n\tuch *l_buf;\n\tuInt lit_bufsize;\n\tuInt last_lit;\n\tush *d_buf;\n\tulg opt_len;\n\tulg static_len;\n\tulg compressed_len;\n\tuInt matches;\n\tint last_eob_len;\n\tush bi_buf;\n\tint bi_valid;\n};\n\ntypedef struct deflate_state deflate_state;\n\ntypedef enum {\n\tneed_more = 0,\n\tblock_done = 1,\n\tfinish_started = 2,\n\tfinish_done = 3,\n} block_state;\n\ntypedef block_state (*compress_func)(deflate_state *, int);\n\nstruct deflate_workspace {\n\tdeflate_state deflate_memory;\n\tByte *window_memory;\n\tPos *prev_memory;\n\tPos *head_memory;\n\tchar *overlay_memory;\n};\n\ntypedef struct deflate_workspace deflate_workspace;\n\nstruct config_s {\n\tush good_length;\n\tush max_lazy;\n\tush nice_length;\n\tush max_chain;\n\tcompress_func func;\n};\n\ntypedef struct config_s config;\n\ntypedef struct tree_desc_s tree_desc;\n\ntypedef struct {\n\tuint32_t hashTable[4096];\n\tuint32_t currentOffset;\n\tuint32_t initCheck;\n\tconst uint8_t *dictionary;\n\tuint8_t *bufferStart;\n\tuint32_t dictSize;\n} LZ4_stream_t_internal;\n\ntypedef union {\n\tlong long unsigned int table[2052];\n\tLZ4_stream_t_internal internal_donotuse;\n} LZ4_stream_t;\n\ntypedef uint8_t BYTE;\n\ntypedef uint16_t U16;\n\ntypedef uint32_t U32;\n\ntypedef uint64_t U64;\n\ntypedef uintptr_t uptrval;\n\ntypedef enum {\n\tnoLimit = 0,\n\tlimitedOutput = 1,\n} limitedOutput_directive;\n\ntypedef enum {\n\tbyPtr = 0,\n\tbyU32 = 1,\n\tbyU16 = 2,\n} tableType_t;\n\ntypedef enum {\n\tnoDict = 0,\n\twithPrefix64k = 1,\n\tusingExtDict = 2,\n} dict_directive;\n\ntypedef enum {\n\tnoDictIssue = 0,\n\tdictSmall = 1,\n} dictIssue_directive;\n\ntypedef struct {\n\tconst uint8_t *externalDict;\n\tsize_t extDictSize;\n\tconst uint8_t *prefixEnd;\n\tsize_t prefixSize;\n} LZ4_streamDecode_t_internal;\n\ntypedef union {\n\tlong long unsigned int table[4];\n\tLZ4_streamDecode_t_internal internal_donotuse;\n} LZ4_streamDecode_t;\n\ntypedef enum {\n\tendOnOutputSize = 0,\n\tendOnInputSize = 1,\n} endCondition_directive;\n\ntypedef enum {\n\tdecode_full_block = 0,\n\tpartial_decode = 1,\n} earlyEnd_directive;\n\ntypedef struct {\n\tsize_t bitContainer;\n\tint bitPos;\n\tchar *startPtr;\n\tchar *ptr;\n\tchar *endPtr;\n} BIT_CStream_t;\n\ntypedef unsigned int FSE_CTable;\n\ntypedef struct {\n\tptrdiff_t value;\n\tconst void *stateTable;\n\tconst void *symbolTT;\n\tunsigned int stateLog;\n} FSE_CState_t;\n\ntypedef struct {\n\tint deltaFindState;\n\tU32 deltaNbBits;\n} FSE_symbolCompressionTransform;\n\ntypedef int16_t S16;\n\nstruct HUF_CElt_s {\n\tU16 val;\n\tBYTE nbBits;\n};\n\ntypedef struct HUF_CElt_s HUF_CElt;\n\ntypedef enum {\n\tHUF_repeat_none = 0,\n\tHUF_repeat_check = 1,\n\tHUF_repeat_valid = 2,\n} HUF_repeat;\n\nstruct nodeElt_s {\n\tU32 count;\n\tU16 parent;\n\tBYTE byte;\n\tBYTE nbBits;\n};\n\ntypedef struct nodeElt_s nodeElt;\n\ntypedef struct {\n\tU32 base;\n\tU32 curr;\n} rankPos;\n\ntypedef enum {\n\tZSTDcs_created = 0,\n\tZSTDcs_init = 1,\n\tZSTDcs_ongoing = 2,\n\tZSTDcs_ending = 3,\n} ZSTD_compressionStage_e;\n\ntypedef void * (*ZSTD_allocFunction)(void *, size_t);\n\ntypedef void (*ZSTD_freeFunction)(void *, void *);\n\ntypedef struct {\n\tZSTD_allocFunction customAlloc;\n\tZSTD_freeFunction customFree;\n\tvoid *opaque;\n} ZSTD_customMem;\n\ntypedef struct {\n\tU32 price;\n\tU32 off;\n\tU32 mlen;\n\tU32 litlen;\n\tU32 rep[3];\n} ZSTD_optimal_t;\n\ntypedef struct {\n\tU32 off;\n\tU32 len;\n} ZSTD_match_t;\n\nstruct seqDef_s;\n\ntypedef struct seqDef_s seqDef;\n\ntypedef struct {\n\tseqDef *sequencesStart;\n\tseqDef *sequences;\n\tBYTE *litStart;\n\tBYTE *lit;\n\tBYTE *llCode;\n\tBYTE *mlCode;\n\tBYTE *ofCode;\n\tU32 longLengthID;\n\tU32 longLengthPos;\n\tZSTD_optimal_t *priceTable;\n\tZSTD_match_t *matchTable;\n\tU32 *matchLengthFreq;\n\tU32 *litLengthFreq;\n\tU32 *litFreq;\n\tU32 *offCodeFreq;\n\tU32 matchLengthSum;\n\tU32 matchSum;\n\tU32 litLengthSum;\n\tU32 litSum;\n\tU32 offCodeSum;\n\tU32 log2matchLengthSum;\n\tU32 log2matchSum;\n\tU32 log2litLengthSum;\n\tU32 log2litSum;\n\tU32 log2offCodeSum;\n\tU32 factor;\n\tU32 staticPrices;\n\tU32 cachedPrice;\n\tU32 cachedLitLength;\n\tconst BYTE *cachedLiterals;\n} seqStore_t;\n\nstruct HUF_CElt_s___2;\n\ntypedef struct HUF_CElt_s___2 HUF_CElt___2;\n\nstruct ZSTD_CCtx_s___2 {\n\tconst BYTE *nextSrc;\n\tconst BYTE *base;\n\tconst BYTE *dictBase;\n\tU32 dictLimit;\n\tU32 lowLimit;\n\tU32 nextToUpdate;\n\tU32 nextToUpdate3;\n\tU32 hashLog3;\n\tU32 loadedDictEnd;\n\tU32 forceWindow;\n\tU32 forceRawDict;\n\tZSTD_compressionStage_e stage;\n\tU32 rep[3];\n\tU32 repToConfirm[3];\n\tU32 dictID;\n\tZSTD_parameters params;\n\tvoid *workSpace;\n\tsize_t workSpaceSize;\n\tsize_t blockSize;\n\tU64 frameContentSize;\n\tstruct xxh64_state xxhState;\n\tZSTD_customMem customMem;\n\tseqStore_t seqStore;\n\tU32 *hashTable;\n\tU32 *hashTable3;\n\tU32 *chainTable;\n\tHUF_CElt___2 *hufTable;\n\tU32 flagStaticTables;\n\tHUF_repeat flagStaticHufTable;\n\tFSE_CTable offcodeCTable[187];\n\tFSE_CTable matchlengthCTable[363];\n\tFSE_CTable litlengthCTable[329];\n\tunsigned int tmpCounters[1536];\n};\n\ntypedef struct ZSTD_CCtx_s___2 ZSTD_CCtx___2;\n\nstruct ZSTD_CDict_s {\n\tvoid *dictBuffer;\n\tconst void *dictContent;\n\tsize_t dictContentSize;\n\tZSTD_CCtx___2 *refContext;\n};\n\ntypedef struct ZSTD_CDict_s ZSTD_CDict;\n\nstruct ZSTD_inBuffer_s {\n\tconst void *src;\n\tsize_t size;\n\tsize_t pos;\n};\n\ntypedef struct ZSTD_inBuffer_s ZSTD_inBuffer;\n\nstruct ZSTD_outBuffer_s {\n\tvoid *dst;\n\tsize_t size;\n\tsize_t pos;\n};\n\ntypedef struct ZSTD_outBuffer_s ZSTD_outBuffer;\n\ntypedef enum {\n\tzcss_init = 0,\n\tzcss_load = 1,\n\tzcss_flush = 2,\n\tzcss_final = 3,\n} ZSTD_cStreamStage;\n\nstruct ZSTD_CStream_s {\n\tZSTD_CCtx___2 *cctx;\n\tZSTD_CDict *cdictLocal;\n\tconst ZSTD_CDict *cdict;\n\tchar *inBuff;\n\tsize_t inBuffSize;\n\tsize_t inToCompress;\n\tsize_t inBuffPos;\n\tsize_t inBuffTarget;\n\tsize_t blockSize;\n\tchar *outBuff;\n\tsize_t outBuffSize;\n\tsize_t outBuffContentSize;\n\tsize_t outBuffFlushedSize;\n\tZSTD_cStreamStage stage;\n\tU32 checksum;\n\tU32 frameEnded;\n\tU64 pledgedSrcSize;\n\tU64 inputProcessed;\n\tZSTD_parameters params;\n\tZSTD_customMem customMem;\n};\n\ntypedef struct ZSTD_CStream_s ZSTD_CStream;\n\ntypedef int32_t S32;\n\ntypedef enum {\n\tset_basic = 0,\n\tset_rle = 1,\n\tset_compressed = 2,\n\tset_repeat = 3,\n} symbolEncodingType_e;\n\nstruct seqDef_s {\n\tU32 offset;\n\tU16 litLength;\n\tU16 matchLength;\n};\n\ntypedef enum {\n\tZSTDcrp_continue = 0,\n\tZSTDcrp_noMemset = 1,\n\tZSTDcrp_fullReset = 2,\n} ZSTD_compResetPolicy_e;\n\ntypedef void (*ZSTD_blockCompressor)(ZSTD_CCtx___2 *, const void *, size_t);\n\ntypedef enum {\n\tzsf_gather = 0,\n\tzsf_flush = 1,\n\tzsf_end = 2,\n} ZSTD_flush_e;\n\ntypedef size_t (*searchMax_f)(ZSTD_CCtx___2 *, const BYTE *, const BYTE *, size_t *, U32, U32);\n\ntypedef struct {\n\tsize_t bitContainer;\n\tunsigned int bitsConsumed;\n\tconst char *ptr;\n\tconst char *start;\n} BIT_DStream_t;\n\ntypedef enum {\n\tBIT_DStream_unfinished = 0,\n\tBIT_DStream_endOfBuffer = 1,\n\tBIT_DStream_completed = 2,\n\tBIT_DStream_overflow = 3,\n} BIT_DStream_status;\n\ntypedef unsigned int FSE_DTable;\n\ntypedef struct {\n\tsize_t state;\n\tconst void *table;\n} FSE_DState_t;\n\ntypedef struct {\n\tU16 tableLog;\n\tU16 fastMode;\n} FSE_DTableHeader;\n\ntypedef struct {\n\tshort unsigned int newState;\n\tunsigned char symbol;\n\tunsigned char nbBits;\n} FSE_decode_t;\n\ntypedef struct {\n\tvoid *ptr;\n\tconst void *end;\n} ZSTD_stack;\n\ntypedef U32 HUF_DTable;\n\ntypedef struct {\n\tBYTE maxTableLog;\n\tBYTE tableType;\n\tBYTE tableLog;\n\tBYTE reserved;\n} DTableDesc;\n\ntypedef struct {\n\tBYTE byte;\n\tBYTE nbBits;\n} HUF_DEltX2;\n\ntypedef struct {\n\tU16 sequence;\n\tBYTE nbBits;\n\tBYTE length;\n} HUF_DEltX4;\n\ntypedef struct {\n\tBYTE symbol;\n\tBYTE weight;\n} sortedSymbol_t;\n\ntypedef U32 rankValCol_t[13];\n\ntypedef struct {\n\tU32 tableTime;\n\tU32 decode256Time;\n} algo_time_t;\n\ntypedef struct {\n\tFSE_DTable LLTable[513];\n\tFSE_DTable OFTable[257];\n\tFSE_DTable MLTable[513];\n\tHUF_DTable hufTable[4097];\n\tU64 workspace[384];\n\tU32 rep[3];\n} ZSTD_entropyTables_t;\n\ntypedef struct {\n\tlong long unsigned int frameContentSize;\n\tunsigned int windowSize;\n\tunsigned int dictID;\n\tunsigned int checksumFlag;\n} ZSTD_frameParams;\n\ntypedef enum {\n\tbt_raw = 0,\n\tbt_rle = 1,\n\tbt_compressed = 2,\n\tbt_reserved = 3,\n} blockType_e;\n\ntypedef enum {\n\tZSTDds_getFrameHeaderSize = 0,\n\tZSTDds_decodeFrameHeader = 1,\n\tZSTDds_decodeBlockHeader = 2,\n\tZSTDds_decompressBlock = 3,\n\tZSTDds_decompressLastBlock = 4,\n\tZSTDds_checkChecksum = 5,\n\tZSTDds_decodeSkippableHeader = 6,\n\tZSTDds_skipFrame = 7,\n} ZSTD_dStage;\n\nstruct ZSTD_DCtx_s___2 {\n\tconst FSE_DTable *LLTptr;\n\tconst FSE_DTable *MLTptr;\n\tconst FSE_DTable *OFTptr;\n\tconst HUF_DTable *HUFptr;\n\tZSTD_entropyTables_t entropy;\n\tconst void *previousDstEnd;\n\tconst void *base;\n\tconst void *vBase;\n\tconst void *dictEnd;\n\tsize_t expected;\n\tZSTD_frameParams fParams;\n\tblockType_e bType;\n\tZSTD_dStage stage;\n\tU32 litEntropy;\n\tU32 fseEntropy;\n\tstruct xxh64_state xxhState;\n\tsize_t headerSize;\n\tU32 dictID;\n\tconst BYTE *litPtr;\n\tZSTD_customMem customMem;\n\tsize_t litSize;\n\tsize_t rleSize;\n\tBYTE litBuffer[131080];\n\tBYTE headerBuffer[18];\n};\n\ntypedef struct ZSTD_DCtx_s___2 ZSTD_DCtx___2;\n\nstruct ZSTD_DDict_s {\n\tvoid *dictBuffer;\n\tconst void *dictContent;\n\tsize_t dictSize;\n\tZSTD_entropyTables_t entropy;\n\tU32 dictID;\n\tU32 entropyPresent;\n\tZSTD_customMem cMem;\n};\n\ntypedef struct ZSTD_DDict_s ZSTD_DDict;\n\ntypedef enum {\n\tzdss_init = 0,\n\tzdss_loadHeader = 1,\n\tzdss_read = 2,\n\tzdss_load = 3,\n\tzdss_flush = 4,\n} ZSTD_dStreamStage;\n\nstruct ZSTD_DStream_s {\n\tZSTD_DCtx___2 *dctx;\n\tZSTD_DDict *ddictLocal;\n\tconst ZSTD_DDict *ddict;\n\tZSTD_frameParams fParams;\n\tZSTD_dStreamStage stage;\n\tchar *inBuff;\n\tsize_t inBuffSize;\n\tsize_t inPos;\n\tsize_t maxWindowSize;\n\tchar *outBuff;\n\tsize_t outBuffSize;\n\tsize_t outStart;\n\tsize_t outEnd;\n\tsize_t blockSize;\n\tBYTE headerBuffer[18];\n\tsize_t lhSize;\n\tZSTD_customMem customMem;\n\tvoid *legacyContext;\n\tU32 previousLegacyVersion;\n\tU32 legacyVersion;\n\tU32 hostageByte;\n};\n\ntypedef struct ZSTD_DStream_s ZSTD_DStream;\n\ntypedef enum {\n\tZSTDnit_frameHeader = 0,\n\tZSTDnit_blockHeader = 1,\n\tZSTDnit_block = 2,\n\tZSTDnit_lastBlock = 3,\n\tZSTDnit_checksum = 4,\n\tZSTDnit_skippableFrame = 5,\n} ZSTD_nextInputType_e;\n\ntypedef uintptr_t uPtrDiff;\n\ntypedef struct {\n\tblockType_e blockType;\n\tU32 lastBlock;\n\tU32 origSize;\n} blockProperties_t;\n\ntypedef union {\n\tFSE_decode_t realData;\n\tU32 alignedBy4;\n} FSE_decode_t4;\n\ntypedef struct {\n\tsize_t litLength;\n\tsize_t matchLength;\n\tsize_t offset;\n\tconst BYTE *match;\n} seq_t;\n\ntypedef struct {\n\tBIT_DStream_t DStream;\n\tFSE_DState_t stateLL;\n\tFSE_DState_t stateOffb;\n\tFSE_DState_t stateML;\n\tsize_t prevOffset[3];\n\tconst BYTE *base;\n\tsize_t pos;\n\tuPtrDiff gotoDict;\n} seqState_t;\n\nenum xz_mode {\n\tXZ_SINGLE = 0,\n\tXZ_PREALLOC = 1,\n\tXZ_DYNALLOC = 2,\n};\n\nenum xz_ret {\n\tXZ_OK = 0,\n\tXZ_STREAM_END = 1,\n\tXZ_UNSUPPORTED_CHECK = 2,\n\tXZ_MEM_ERROR = 3,\n\tXZ_MEMLIMIT_ERROR = 4,\n\tXZ_FORMAT_ERROR = 5,\n\tXZ_OPTIONS_ERROR = 6,\n\tXZ_DATA_ERROR = 7,\n\tXZ_BUF_ERROR = 8,\n};\n\nstruct xz_buf {\n\tconst uint8_t *in;\n\tsize_t in_pos;\n\tsize_t in_size;\n\tuint8_t *out;\n\tsize_t out_pos;\n\tsize_t out_size;\n};\n\nstruct xz_dec;\n\ntypedef uint64_t vli_type;\n\nenum xz_check {\n\tXZ_CHECK_NONE = 0,\n\tXZ_CHECK_CRC32 = 1,\n\tXZ_CHECK_CRC64 = 4,\n\tXZ_CHECK_SHA256 = 10,\n};\n\nstruct xz_dec_hash {\n\tvli_type unpadded;\n\tvli_type uncompressed;\n\tuint32_t crc32;\n};\n\nstruct xz_dec_lzma2;\n\nstruct xz_dec_bcj;\n\nstruct xz_dec___2 {\n\tenum {\n\t\tSEQ_STREAM_HEADER = 0,\n\t\tSEQ_BLOCK_START = 1,\n\t\tSEQ_BLOCK_HEADER = 2,\n\t\tSEQ_BLOCK_UNCOMPRESS = 3,\n\t\tSEQ_BLOCK_PADDING = 4,\n\t\tSEQ_BLOCK_CHECK = 5,\n\t\tSEQ_INDEX = 6,\n\t\tSEQ_INDEX_PADDING = 7,\n\t\tSEQ_INDEX_CRC32 = 8,\n\t\tSEQ_STREAM_FOOTER = 9,\n\t} sequence;\n\tuint32_t pos;\n\tvli_type vli;\n\tsize_t in_start;\n\tsize_t out_start;\n\tuint32_t crc32;\n\tenum xz_check check_type;\n\tenum xz_mode mode;\n\tbool allow_buf_error;\n\tstruct {\n\t\tvli_type compressed;\n\t\tvli_type uncompressed;\n\t\tuint32_t size;\n\t} block_header;\n\tstruct {\n\t\tvli_type compressed;\n\t\tvli_type uncompressed;\n\t\tvli_type count;\n\t\tstruct xz_dec_hash hash;\n\t} block;\n\tstruct {\n\t\tenum {\n\t\t\tSEQ_INDEX_COUNT = 0,\n\t\t\tSEQ_INDEX_UNPADDED = 1,\n\t\t\tSEQ_INDEX_UNCOMPRESSED = 2,\n\t\t} sequence;\n\t\tvli_type size;\n\t\tvli_type count;\n\t\tstruct xz_dec_hash hash;\n\t} index;\n\tstruct {\n\t\tsize_t pos;\n\t\tsize_t size;\n\t\tuint8_t buf[1024];\n\t} temp;\n\tstruct xz_dec_lzma2 *lzma2;\n\tstruct xz_dec_bcj *bcj;\n\tbool bcj_active;\n};\n\nenum lzma_state {\n\tSTATE_LIT_LIT = 0,\n\tSTATE_MATCH_LIT_LIT = 1,\n\tSTATE_REP_LIT_LIT = 2,\n\tSTATE_SHORTREP_LIT_LIT = 3,\n\tSTATE_MATCH_LIT = 4,\n\tSTATE_REP_LIT = 5,\n\tSTATE_SHORTREP_LIT = 6,\n\tSTATE_LIT_MATCH = 7,\n\tSTATE_LIT_LONGREP = 8,\n\tSTATE_LIT_SHORTREP = 9,\n\tSTATE_NONLIT_MATCH = 10,\n\tSTATE_NONLIT_REP = 11,\n};\n\nstruct dictionary {\n\tuint8_t *buf;\n\tsize_t start;\n\tsize_t pos;\n\tsize_t full;\n\tsize_t limit;\n\tsize_t end;\n\tuint32_t size;\n\tuint32_t size_max;\n\tuint32_t allocated;\n\tenum xz_mode mode;\n};\n\nstruct rc_dec {\n\tuint32_t range;\n\tuint32_t code;\n\tuint32_t init_bytes_left;\n\tconst uint8_t *in;\n\tsize_t in_pos;\n\tsize_t in_limit;\n};\n\nstruct lzma_len_dec {\n\tuint16_t choice;\n\tuint16_t choice2;\n\tuint16_t low[128];\n\tuint16_t mid[128];\n\tuint16_t high[256];\n};\n\nstruct lzma_dec {\n\tuint32_t rep0;\n\tuint32_t rep1;\n\tuint32_t rep2;\n\tuint32_t rep3;\n\tenum lzma_state state;\n\tuint32_t len;\n\tuint32_t lc;\n\tuint32_t literal_pos_mask;\n\tuint32_t pos_mask;\n\tuint16_t is_match[192];\n\tuint16_t is_rep[12];\n\tuint16_t is_rep0[12];\n\tuint16_t is_rep1[12];\n\tuint16_t is_rep2[12];\n\tuint16_t is_rep0_long[192];\n\tuint16_t dist_slot[256];\n\tuint16_t dist_special[114];\n\tuint16_t dist_align[16];\n\tstruct lzma_len_dec match_len_dec;\n\tstruct lzma_len_dec rep_len_dec;\n\tuint16_t literal[12288];\n};\n\nenum lzma2_seq {\n\tSEQ_CONTROL = 0,\n\tSEQ_UNCOMPRESSED_1 = 1,\n\tSEQ_UNCOMPRESSED_2 = 2,\n\tSEQ_COMPRESSED_0 = 3,\n\tSEQ_COMPRESSED_1 = 4,\n\tSEQ_PROPERTIES = 5,\n\tSEQ_LZMA_PREPARE = 6,\n\tSEQ_LZMA_RUN = 7,\n\tSEQ_COPY = 8,\n};\n\nstruct lzma2_dec {\n\tenum lzma2_seq sequence;\n\tenum lzma2_seq next_sequence;\n\tuint32_t uncompressed;\n\tuint32_t compressed;\n\tbool need_dict_reset;\n\tbool need_props;\n};\n\nstruct xz_dec_lzma2___2 {\n\tstruct rc_dec rc;\n\tstruct dictionary dict;\n\tstruct lzma2_dec lzma2;\n\tstruct lzma_dec lzma;\n\tstruct {\n\t\tuint32_t size;\n\t\tuint8_t buf[63];\n\t} temp;\n};\n\nstruct xz_dec_bcj___2 {\n\tenum {\n\t\tBCJ_X86 = 4,\n\t\tBCJ_POWERPC = 5,\n\t\tBCJ_IA64 = 6,\n\t\tBCJ_ARM = 7,\n\t\tBCJ_ARMTHUMB = 8,\n\t\tBCJ_SPARC = 9,\n\t} type;\n\tenum xz_ret ret;\n\tbool single_call;\n\tuint32_t pos;\n\tuint32_t x86_prev_mask;\n\tuint8_t *out;\n\tsize_t out_pos;\n\tsize_t out_size;\n\tstruct {\n\t\tsize_t filtered;\n\t\tsize_t size;\n\t\tuint8_t buf[16];\n\t} temp;\n};\n\nstruct ts_state {\n\tunsigned int offset;\n\tchar cb[48];\n};\n\nstruct ts_config;\n\nstruct ts_ops {\n\tconst char *name;\n\tstruct ts_config * (*init)(const void *, unsigned int, gfp_t, int);\n\tunsigned int (*find)(struct ts_config *, struct ts_state *);\n\tvoid (*destroy)(struct ts_config *);\n\tvoid * (*get_pattern)(struct ts_config *);\n\tunsigned int (*get_pattern_len)(struct ts_config *);\n\tstruct module *owner;\n\tstruct list_head list;\n};\n\nstruct ts_config {\n\tstruct ts_ops *ops;\n\tint flags;\n\tunsigned int (*get_next_block)(unsigned int, const u8 **, struct ts_config *, struct ts_state *);\n\tvoid (*finish)(struct ts_config *, struct ts_state *);\n};\n\nstruct ts_linear_state {\n\tunsigned int len;\n\tconst void *data;\n};\n\nstruct ei_entry {\n\tstruct list_head list;\n\tlong unsigned int start_addr;\n\tlong unsigned int end_addr;\n\tint etype;\n\tvoid *priv;\n};\n\nstruct ddebug_table {\n\tstruct list_head link;\n\tconst char *mod_name;\n\tunsigned int num_ddebugs;\n\tstruct _ddebug *ddebugs;\n};\n\nstruct ddebug_query {\n\tconst char *filename;\n\tconst char *module;\n\tconst char *function;\n\tconst char *format;\n\tunsigned int first_lineno;\n\tunsigned int last_lineno;\n};\n\nstruct ddebug_iter {\n\tstruct ddebug_table *table;\n\tunsigned int idx;\n};\n\nstruct flag_settings {\n\tunsigned int flags;\n\tunsigned int mask;\n};\n\nstruct flagsbuf {\n\tchar buf[7];\n};\n\nstruct nla_bitfield32 {\n\t__u32 value;\n\t__u32 selector;\n};\n\nenum nla_policy_validation {\n\tNLA_VALIDATE_NONE = 0,\n\tNLA_VALIDATE_RANGE = 1,\n\tNLA_VALIDATE_RANGE_WARN_TOO_LONG = 2,\n\tNLA_VALIDATE_MIN = 3,\n\tNLA_VALIDATE_MAX = 4,\n\tNLA_VALIDATE_MASK = 5,\n\tNLA_VALIDATE_RANGE_PTR = 6,\n\tNLA_VALIDATE_FUNCTION = 7,\n};\n\nenum netlink_validation {\n\tNL_VALIDATE_LIBERAL = 0,\n\tNL_VALIDATE_TRAILING = 1,\n\tNL_VALIDATE_MAXTYPE = 2,\n\tNL_VALIDATE_UNSPEC = 4,\n\tNL_VALIDATE_STRICT_ATTRS = 8,\n\tNL_VALIDATE_NESTED = 16,\n};\n\nstruct cpu_rmap {\n\tstruct kref refcount;\n\tu16 size;\n\tu16 used;\n\tvoid **obj;\n\tstruct {\n\t\tu16 index;\n\t\tu16 dist;\n\t} near[0];\n};\n\nstruct irq_glue {\n\tstruct irq_affinity_notify notify;\n\tstruct cpu_rmap *rmap;\n\tu16 index;\n};\n\ntypedef mpi_limb_t *mpi_ptr_t;\n\ntypedef int mpi_size_t;\n\ntypedef mpi_limb_t UWtype;\n\ntypedef unsigned int UHWtype;\n\nenum gcry_mpi_constants {\n\tMPI_C_ZERO = 0,\n\tMPI_C_ONE = 1,\n\tMPI_C_TWO = 2,\n\tMPI_C_THREE = 3,\n\tMPI_C_FOUR = 4,\n\tMPI_C_EIGHT = 5,\n};\n\nstruct barrett_ctx_s;\n\ntypedef struct barrett_ctx_s *mpi_barrett_t;\n\nstruct gcry_mpi_point {\n\tMPI x;\n\tMPI y;\n\tMPI z;\n};\n\ntypedef struct gcry_mpi_point *MPI_POINT;\n\nenum gcry_mpi_ec_models {\n\tMPI_EC_WEIERSTRASS = 0,\n\tMPI_EC_MONTGOMERY = 1,\n\tMPI_EC_EDWARDS = 2,\n};\n\nenum ecc_dialects {\n\tECC_DIALECT_STANDARD = 0,\n\tECC_DIALECT_ED25519 = 1,\n\tECC_DIALECT_SAFECURVE = 2,\n};\n\nstruct mpi_ec_ctx {\n\tenum gcry_mpi_ec_models model;\n\tenum ecc_dialects dialect;\n\tint flags;\n\tunsigned int nbits;\n\tMPI p;\n\tMPI a;\n\tMPI b;\n\tMPI_POINT G;\n\tMPI n;\n\tunsigned int h;\n\tMPI_POINT Q;\n\tMPI d;\n\tconst char *name;\n\tstruct {\n\t\tstruct {\n\t\t\tunsigned int a_is_pminus3: 1;\n\t\t\tunsigned int two_inv_p: 1;\n\t\t} valid;\n\t\tint a_is_pminus3;\n\t\tMPI two_inv_p;\n\t\tmpi_barrett_t p_barrett;\n\t\tMPI scratch[11];\n\t} t;\n\tvoid (*addm)(MPI, MPI, MPI, struct mpi_ec_ctx *);\n\tvoid (*subm)(MPI, MPI, MPI, struct mpi_ec_ctx *);\n\tvoid (*mulm)(MPI, MPI, MPI, struct mpi_ec_ctx *);\n\tvoid (*pow2)(MPI, const MPI, struct mpi_ec_ctx *);\n\tvoid (*mul2)(MPI, MPI, struct mpi_ec_ctx *);\n};\n\nstruct field_table {\n\tconst char *p;\n\tvoid (*addm)(MPI, MPI, MPI, struct mpi_ec_ctx *);\n\tvoid (*subm)(MPI, MPI, MPI, struct mpi_ec_ctx *);\n\tvoid (*mulm)(MPI, MPI, MPI, struct mpi_ec_ctx *);\n\tvoid (*mul2)(MPI, MPI, struct mpi_ec_ctx *);\n\tvoid (*pow2)(MPI, const MPI, struct mpi_ec_ctx *);\n};\n\nenum gcry_mpi_format {\n\tGCRYMPI_FMT_NONE = 0,\n\tGCRYMPI_FMT_STD = 1,\n\tGCRYMPI_FMT_PGP = 2,\n\tGCRYMPI_FMT_SSH = 3,\n\tGCRYMPI_FMT_HEX = 4,\n\tGCRYMPI_FMT_USG = 5,\n\tGCRYMPI_FMT_OPAQUE = 8,\n};\n\nstruct barrett_ctx_s___2;\n\ntypedef struct barrett_ctx_s___2 *mpi_barrett_t___2;\n\nstruct barrett_ctx_s___2 {\n\tMPI m;\n\tint m_copied;\n\tint k;\n\tMPI y;\n\tMPI r1;\n\tMPI r2;\n\tMPI r3;\n};\n\nstruct karatsuba_ctx {\n\tstruct karatsuba_ctx *next;\n\tmpi_ptr_t tspace;\n\tmpi_size_t tspace_size;\n\tmpi_ptr_t tp;\n\tmpi_size_t tp_size;\n};\n\ntypedef long int mpi_limb_signed_t;\n\nenum dim_tune_state {\n\tDIM_PARKING_ON_TOP = 0,\n\tDIM_PARKING_TIRED = 1,\n\tDIM_GOING_RIGHT = 2,\n\tDIM_GOING_LEFT = 3,\n};\n\nstruct dim_cq_moder {\n\tu16 usec;\n\tu16 pkts;\n\tu16 comps;\n\tu8 cq_period_mode;\n};\n\nenum dim_cq_period_mode {\n\tDIM_CQ_PERIOD_MODE_START_FROM_EQE = 0,\n\tDIM_CQ_PERIOD_MODE_START_FROM_CQE = 1,\n\tDIM_CQ_PERIOD_NUM_MODES = 2,\n};\n\nenum dim_state {\n\tDIM_START_MEASURE = 0,\n\tDIM_MEASURE_IN_PROGRESS = 1,\n\tDIM_APPLY_NEW_PROFILE = 2,\n};\n\nenum dim_stats_state {\n\tDIM_STATS_WORSE = 0,\n\tDIM_STATS_SAME = 1,\n\tDIM_STATS_BETTER = 2,\n};\n\nenum dim_step_result {\n\tDIM_STEPPED = 0,\n\tDIM_TOO_TIRED = 1,\n\tDIM_ON_EDGE = 2,\n};\n\nstruct sg_pool {\n\tsize_t size;\n\tchar *name;\n\tstruct kmem_cache *slab;\n\tmempool_t *pool;\n};\n\nenum {\n\tIRQ_POLL_F_SCHED = 0,\n\tIRQ_POLL_F_DISABLE = 1,\n};\n\nstruct font_desc {\n\tint idx;\n\tconst char *name;\n\tunsigned int width;\n\tunsigned int height;\n\tunsigned int charcount;\n\tconst void *data;\n\tint pref;\n};\n\nstruct font_data {\n\tunsigned int extra[4];\n\tconst unsigned char data[0];\n};\n\nstruct pldmfw_record {\n\tstruct list_head entry;\n\tstruct list_head descs;\n\tconst u8 *version_string;\n\tu8 version_type;\n\tu8 version_len;\n\tu16 package_data_len;\n\tu32 device_update_flags;\n\tconst u8 *package_data;\n\tlong unsigned int *component_bitmap;\n\tu16 component_bitmap_len;\n};\n\nstruct pldmfw_desc_tlv {\n\tstruct list_head entry;\n\tconst u8 *data;\n\tu16 type;\n\tu16 size;\n};\n\nstruct pldmfw_component {\n\tstruct list_head entry;\n\tu16 classification;\n\tu16 identifier;\n\tu16 options;\n\tu16 activation_method;\n\tu32 comparison_stamp;\n\tu32 component_size;\n\tconst u8 *component_data;\n\tconst u8 *version_string;\n\tu8 version_type;\n\tu8 version_len;\n\tu8 index;\n};\n\nstruct pldmfw_ops;\n\nstruct pldmfw {\n\tconst struct pldmfw_ops *ops;\n\tstruct device *dev;\n};\n\nstruct pldmfw_ops {\n\tbool (*match_record)(struct pldmfw *, struct pldmfw_record *);\n\tint (*send_package_data)(struct pldmfw *, const u8 *, u16);\n\tint (*send_component_table)(struct pldmfw *, struct pldmfw_component *, u8);\n\tint (*flash_component)(struct pldmfw *, struct pldmfw_component *);\n\tint (*finalize_update)(struct pldmfw *);\n};\n\nstruct __pldm_timestamp {\n\tu8 b[13];\n};\n\nstruct __pldm_header {\n\tuuid_t id;\n\tu8 revision;\n\t__le16 size;\n\tstruct __pldm_timestamp release_date;\n\t__le16 component_bitmap_len;\n\tu8 version_type;\n\tu8 version_len;\n\tu8 version_string[0];\n} __attribute__((packed));\n\nstruct __pldmfw_record_info {\n\t__le16 record_len;\n\tu8 descriptor_count;\n\t__le32 device_update_flags;\n\tu8 version_type;\n\tu8 version_len;\n\t__le16 package_data_len;\n\tu8 variable_record_data[0];\n} __attribute__((packed));\n\nstruct __pldmfw_desc_tlv {\n\t__le16 type;\n\t__le16 size;\n\tu8 data[0];\n};\n\nstruct __pldmfw_record_area {\n\tu8 record_count;\n\tu8 records[0];\n};\n\nstruct __pldmfw_component_info {\n\t__le16 classification;\n\t__le16 identifier;\n\t__le32 comparison_stamp;\n\t__le16 options;\n\t__le16 activation_method;\n\t__le32 location_offset;\n\t__le32 size;\n\tu8 version_type;\n\tu8 version_len;\n\tu8 version_string[0];\n} __attribute__((packed));\n\nstruct __pldmfw_component_area {\n\t__le16 component_image_count;\n\tu8 components[0];\n};\n\nstruct pldmfw_priv {\n\tstruct pldmfw *context;\n\tconst struct firmware *fw;\n\tsize_t offset;\n\tstruct list_head records;\n\tstruct list_head components;\n\tconst struct __pldm_header *header;\n\tu16 total_header_size;\n\tu16 component_bitmap_len;\n\tu16 bitmap_size;\n\tu16 component_count;\n\tconst u8 *component_start;\n\tconst u8 *record_start;\n\tu8 record_count;\n\tu32 header_crc;\n\tstruct pldmfw_record *matching_record;\n};\n\nstruct pldm_pci_record_id {\n\tint vendor;\n\tint device;\n\tint subsystem_vendor;\n\tint subsystem_device;\n};\n\nstruct msr {\n\tunion {\n\t\tstruct {\n\t\t\tu32 l;\n\t\t\tu32 h;\n\t\t};\n\t\tu64 q;\n\t};\n};\n\nstruct msr_info {\n\tu32 msr_no;\n\tstruct msr reg;\n\tstruct msr *msrs;\n\tint err;\n};\n\nstruct msr_regs_info {\n\tu32 *regs;\n\tint err;\n};\n\nstruct msr_info_completion {\n\tstruct msr_info msr;\n\tstruct completion done;\n};\n\nstruct trace_event_raw_msr_trace_class {\n\tstruct trace_entry ent;\n\tunsigned int msr;\n\tu64 val;\n\tint failed;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_msr_trace_class {};\n\ntypedef void (*btf_trace_read_msr)(void *, unsigned int, u64, int);\n\ntypedef void (*btf_trace_write_msr)(void *, unsigned int, u64, int);\n\ntypedef void (*btf_trace_rdpmc)(void *, unsigned int, u64, int);\n\nstruct warn_args___2;\n\nstruct compress_format {\n\tunsigned char magic[2];\n\tconst char *name;\n\tdecompress_fn decompressor;\n};\n\nstruct group_data {\n\tint limit[21];\n\tint base[20];\n\tint permute[258];\n\tint minLen;\n\tint maxLen;\n};\n\nstruct bunzip_data {\n\tint writeCopies;\n\tint writePos;\n\tint writeRunCountdown;\n\tint writeCount;\n\tint writeCurrent;\n\tlong int (*fill)(void *, long unsigned int);\n\tlong int inbufCount;\n\tlong int inbufPos;\n\tunsigned char *inbuf;\n\tunsigned int inbufBitCount;\n\tunsigned int inbufBits;\n\tunsigned int crc32Table[256];\n\tunsigned int headerCRC;\n\tunsigned int totalCRC;\n\tunsigned int writeCRC;\n\tunsigned int *dbuf;\n\tunsigned int dbufSize;\n\tunsigned char selectors[32768];\n\tstruct group_data groups[6];\n\tint io_error;\n\tint byteCount[256];\n\tunsigned char symToByte[256];\n\tunsigned char mtfSymbol[256];\n};\n\nstruct rc {\n\tlong int (*fill)(void *, long unsigned int);\n\tuint8_t *ptr;\n\tuint8_t *buffer;\n\tuint8_t *buffer_end;\n\tlong int buffer_size;\n\tuint32_t code;\n\tuint32_t range;\n\tuint32_t bound;\n\tvoid (*error)(char *);\n};\n\nstruct lzma_header {\n\tuint8_t pos;\n\tuint32_t dict_size;\n\tuint64_t dst_size;\n} __attribute__((packed));\n\nstruct writer {\n\tuint8_t *buffer;\n\tuint8_t previous_byte;\n\tsize_t buffer_pos;\n\tint bufsize;\n\tsize_t global_pos;\n\tlong int (*flush)(void *, long unsigned int);\n\tstruct lzma_header *header;\n};\n\nstruct cstate {\n\tint state;\n\tuint32_t rep0;\n\tuint32_t rep1;\n\tuint32_t rep2;\n\tuint32_t rep3;\n};\n\ntypedef enum {\n\tZSTD_error_no_error = 0,\n\tZSTD_error_GENERIC = 1,\n\tZSTD_error_prefix_unknown = 2,\n\tZSTD_error_version_unsupported = 3,\n\tZSTD_error_parameter_unknown = 4,\n\tZSTD_error_frameParameter_unsupported = 5,\n\tZSTD_error_frameParameter_unsupportedBy32bits = 6,\n\tZSTD_error_frameParameter_windowTooLarge = 7,\n\tZSTD_error_compressionParameter_unsupported = 8,\n\tZSTD_error_init_missing = 9,\n\tZSTD_error_memory_allocation = 10,\n\tZSTD_error_stage_wrong = 11,\n\tZSTD_error_dstSize_tooSmall = 12,\n\tZSTD_error_srcSize_wrong = 13,\n\tZSTD_error_corruption_detected = 14,\n\tZSTD_error_checksum_wrong = 15,\n\tZSTD_error_tableLog_tooLarge = 16,\n\tZSTD_error_maxSymbolValue_tooLarge = 17,\n\tZSTD_error_maxSymbolValue_tooSmall = 18,\n\tZSTD_error_dictionary_corrupted = 19,\n\tZSTD_error_dictionary_wrong = 20,\n\tZSTD_error_dictionaryCreation_failed = 21,\n\tZSTD_error_maxCode = 22,\n} ZSTD_ErrorCode;\n\nstruct ZSTD_DStream_s___2;\n\ntypedef struct ZSTD_DStream_s___2 ZSTD_DStream___2;\n\nenum cpio_fields {\n\tC_MAGIC = 0,\n\tC_INO = 1,\n\tC_MODE = 2,\n\tC_UID = 3,\n\tC_GID = 4,\n\tC_NLINK = 5,\n\tC_MTIME = 6,\n\tC_FILESIZE = 7,\n\tC_MAJ = 8,\n\tC_MIN = 9,\n\tC_RMAJ = 10,\n\tC_RMIN = 11,\n\tC_NAMESIZE = 12,\n\tC_CHKSUM = 13,\n\tC_NFIELDS = 14,\n};\n\nstruct fprop_local_single {\n\tlong unsigned int events;\n\tunsigned int period;\n\traw_spinlock_t lock;\n};\n\nstruct ida_bitmap {\n\tlong unsigned int bitmap[16];\n};\n\nstruct klist_waiter {\n\tstruct list_head list;\n\tstruct klist_node *node;\n\tstruct task_struct *process;\n\tint woken;\n};\n\nstruct uevent_sock {\n\tstruct list_head list;\n\tstruct sock *sk;\n};\n\nenum {\n\tLOGIC_PIO_INDIRECT = 0,\n\tLOGIC_PIO_CPU_MMIO = 1,\n};\n\nstruct logic_pio_host_ops;\n\nstruct logic_pio_hwaddr {\n\tstruct list_head list;\n\tstruct fwnode_handle *fwnode;\n\tresource_size_t hw_start;\n\tresource_size_t io_start;\n\tresource_size_t size;\n\tlong unsigned int flags;\n\tvoid *hostdata;\n\tconst struct logic_pio_host_ops *ops;\n};\n\nstruct logic_pio_host_ops {\n\tu32 (*in)(void *, long unsigned int, size_t);\n\tvoid (*out)(void *, long unsigned int, u32, size_t);\n\tu32 (*ins)(void *, long unsigned int, void *, size_t, unsigned int);\n\tvoid (*outs)(void *, long unsigned int, const void *, size_t, unsigned int);\n};\n\ntypedef struct {\n\tlong unsigned int key[2];\n} hsiphash_key_t;\n\nstruct clk_core;\n\nstruct clk {\n\tstruct clk_core *core;\n\tstruct device *dev;\n\tconst char *dev_id;\n\tconst char *con_id;\n\tlong unsigned int min_rate;\n\tlong unsigned int max_rate;\n\tunsigned int exclusive_count;\n\tstruct hlist_node clks_node;\n};\n\nenum format_type {\n\tFORMAT_TYPE_NONE = 0,\n\tFORMAT_TYPE_WIDTH = 1,\n\tFORMAT_TYPE_PRECISION = 2,\n\tFORMAT_TYPE_CHAR = 3,\n\tFORMAT_TYPE_STR = 4,\n\tFORMAT_TYPE_PTR = 5,\n\tFORMAT_TYPE_PERCENT_CHAR = 6,\n\tFORMAT_TYPE_INVALID = 7,\n\tFORMAT_TYPE_LONG_LONG = 8,\n\tFORMAT_TYPE_ULONG = 9,\n\tFORMAT_TYPE_LONG = 10,\n\tFORMAT_TYPE_UBYTE = 11,\n\tFORMAT_TYPE_BYTE = 12,\n\tFORMAT_TYPE_USHORT = 13,\n\tFORMAT_TYPE_SHORT = 14,\n\tFORMAT_TYPE_UINT = 15,\n\tFORMAT_TYPE_INT = 16,\n\tFORMAT_TYPE_SIZE_T = 17,\n\tFORMAT_TYPE_PTRDIFF = 18,\n};\n\nstruct printf_spec {\n\tunsigned int type: 8;\n\tint field_width: 24;\n\tunsigned int flags: 8;\n\tunsigned int base: 8;\n\tint precision: 16;\n};\n\nstruct page_flags_fields {\n\tint width;\n\tint shift;\n\tint mask;\n\tconst struct printf_spec *spec;\n\tconst char *name;\n};\n\nstruct minmax_sample {\n\tu32 t;\n\tu32 v;\n};\n\nstruct minmax {\n\tstruct minmax_sample s[3];\n};\n\nenum {\n\tst_wordstart = 0,\n\tst_wordcmp = 1,\n\tst_wordskip = 2,\n\tst_bufcpy = 3,\n};\n\nenum {\n\tst_wordstart___2 = 0,\n\tst_wordcmp___2 = 1,\n\tst_wordskip___2 = 2,\n};\n\nstruct in6_addr___2;\n\nenum reg_type {\n\tREG_TYPE_RM = 0,\n\tREG_TYPE_REG = 1,\n\tREG_TYPE_INDEX = 2,\n\tREG_TYPE_BASE = 3,\n};\n\nenum device_link_state {\n\tDL_STATE_NONE = 4294967295,\n\tDL_STATE_DORMANT = 0,\n\tDL_STATE_AVAILABLE = 1,\n\tDL_STATE_CONSUMER_PROBE = 2,\n\tDL_STATE_ACTIVE = 3,\n\tDL_STATE_SUPPLIER_UNBIND = 4,\n};\n\nstruct device_link {\n\tstruct device *supplier;\n\tstruct list_head s_node;\n\tstruct device *consumer;\n\tstruct list_head c_node;\n\tstruct device link_dev;\n\tenum device_link_state status;\n\tu32 flags;\n\trefcount_t rpm_active;\n\tstruct kref kref;\n\tstruct work_struct rm_work;\n\tbool supplier_preactivated;\n};\n\nstruct phy_configure_opts_dp {\n\tunsigned int link_rate;\n\tunsigned int lanes;\n\tunsigned int voltage[4];\n\tunsigned int pre[4];\n\tu8 ssc: 1;\n\tu8 set_rate: 1;\n\tu8 set_lanes: 1;\n\tu8 set_voltages: 1;\n};\n\nstruct phy_configure_opts_mipi_dphy {\n\tunsigned int clk_miss;\n\tunsigned int clk_post;\n\tunsigned int clk_pre;\n\tunsigned int clk_prepare;\n\tunsigned int clk_settle;\n\tunsigned int clk_term_en;\n\tunsigned int clk_trail;\n\tunsigned int clk_zero;\n\tunsigned int d_term_en;\n\tunsigned int eot;\n\tunsigned int hs_exit;\n\tunsigned int hs_prepare;\n\tunsigned int hs_settle;\n\tunsigned int hs_skip;\n\tunsigned int hs_trail;\n\tunsigned int hs_zero;\n\tunsigned int init;\n\tunsigned int lpx;\n\tunsigned int ta_get;\n\tunsigned int ta_go;\n\tunsigned int ta_sure;\n\tunsigned int wakeup;\n\tlong unsigned int hs_clk_rate;\n\tlong unsigned int lp_clk_rate;\n\tunsigned char lanes;\n};\n\nenum phy_mode {\n\tPHY_MODE_INVALID = 0,\n\tPHY_MODE_USB_HOST = 1,\n\tPHY_MODE_USB_HOST_LS = 2,\n\tPHY_MODE_USB_HOST_FS = 3,\n\tPHY_MODE_USB_HOST_HS = 4,\n\tPHY_MODE_USB_HOST_SS = 5,\n\tPHY_MODE_USB_DEVICE = 6,\n\tPHY_MODE_USB_DEVICE_LS = 7,\n\tPHY_MODE_USB_DEVICE_FS = 8,\n\tPHY_MODE_USB_DEVICE_HS = 9,\n\tPHY_MODE_USB_DEVICE_SS = 10,\n\tPHY_MODE_USB_OTG = 11,\n\tPHY_MODE_UFS_HS_A = 12,\n\tPHY_MODE_UFS_HS_B = 13,\n\tPHY_MODE_PCIE = 14,\n\tPHY_MODE_ETHERNET = 15,\n\tPHY_MODE_MIPI_DPHY = 16,\n\tPHY_MODE_SATA = 17,\n\tPHY_MODE_LVDS = 18,\n\tPHY_MODE_DP = 19,\n};\n\nenum phy_media {\n\tPHY_MEDIA_DEFAULT = 0,\n\tPHY_MEDIA_SR = 1,\n\tPHY_MEDIA_DAC = 2,\n};\n\nunion phy_configure_opts {\n\tstruct phy_configure_opts_mipi_dphy mipi_dphy;\n\tstruct phy_configure_opts_dp dp;\n};\n\nstruct phy;\n\nstruct phy_ops {\n\tint (*init)(struct phy *);\n\tint (*exit)(struct phy *);\n\tint (*power_on)(struct phy *);\n\tint (*power_off)(struct phy *);\n\tint (*set_mode)(struct phy *, enum phy_mode, int);\n\tint (*set_media)(struct phy *, enum phy_media);\n\tint (*set_speed)(struct phy *, int);\n\tint (*configure)(struct phy *, union phy_configure_opts *);\n\tint (*validate)(struct phy *, enum phy_mode, int, union phy_configure_opts *);\n\tint (*reset)(struct phy *);\n\tint (*calibrate)(struct phy *);\n\tvoid (*release)(struct phy *);\n\tstruct module *owner;\n};\n\nstruct phy_attrs {\n\tu32 bus_width;\n\tu32 max_link_rate;\n\tenum phy_mode mode;\n};\n\nstruct regulator;\n\nstruct phy {\n\tstruct device dev;\n\tint id;\n\tconst struct phy_ops *ops;\n\tstruct mutex mutex;\n\tint init_count;\n\tint power_count;\n\tstruct phy_attrs attrs;\n\tstruct regulator *pwr;\n};\n\nstruct phy_provider {\n\tstruct device *dev;\n\tstruct device_node *children;\n\tstruct module *owner;\n\tstruct list_head list;\n\tstruct phy * (*of_xlate)(struct device *, struct of_phandle_args *);\n};\n\nstruct phy_lookup {\n\tstruct list_head node;\n\tconst char *dev_id;\n\tconst char *con_id;\n\tstruct phy *phy;\n};\n\nstruct pinctrl;\n\nstruct pinctrl_state;\n\nstruct dev_pin_info {\n\tstruct pinctrl *p;\n\tstruct pinctrl_state *default_state;\n\tstruct pinctrl_state *init_state;\n\tstruct pinctrl_state *sleep_state;\n\tstruct pinctrl_state *idle_state;\n};\n\nstruct pinctrl {\n\tstruct list_head node;\n\tstruct device *dev;\n\tstruct list_head states;\n\tstruct pinctrl_state *state;\n\tstruct list_head dt_maps;\n\tstruct kref users;\n};\n\nstruct pinctrl_state {\n\tstruct list_head node;\n\tconst char *name;\n\tstruct list_head settings;\n};\n\nstruct pinctrl_pin_desc {\n\tunsigned int number;\n\tconst char *name;\n\tvoid *drv_data;\n};\n\nstruct gpio_chip;\n\nstruct pinctrl_gpio_range {\n\tstruct list_head node;\n\tconst char *name;\n\tunsigned int id;\n\tunsigned int base;\n\tunsigned int pin_base;\n\tunsigned int npins;\n\tconst unsigned int *pins;\n\tstruct gpio_chip *gc;\n};\n\nstruct gpio_irq_chip {\n\tstruct irq_chip *chip;\n\tstruct irq_domain *domain;\n\tconst struct irq_domain_ops *domain_ops;\n\tstruct fwnode_handle *fwnode;\n\tstruct irq_domain *parent_domain;\n\tint (*child_to_parent_hwirq)(struct gpio_chip *, unsigned int, unsigned int, unsigned int *, unsigned int *);\n\tvoid * (*populate_parent_alloc_arg)(struct gpio_chip *, unsigned int, unsigned int);\n\tunsigned int (*child_offset_to_irq)(struct gpio_chip *, unsigned int);\n\tstruct irq_domain_ops child_irq_domain_ops;\n\tirq_flow_handler_t handler;\n\tunsigned int default_type;\n\tstruct lock_class_key *lock_key;\n\tstruct lock_class_key *request_key;\n\tirq_flow_handler_t parent_handler;\n\tvoid *parent_handler_data;\n\tunsigned int num_parents;\n\tunsigned int *parents;\n\tunsigned int *map;\n\tbool threaded;\n\tint (*init_hw)(struct gpio_chip *);\n\tvoid (*init_valid_mask)(struct gpio_chip *, long unsigned int *, unsigned int);\n\tlong unsigned int *valid_mask;\n\tunsigned int first;\n\tvoid (*irq_enable)(struct irq_data *);\n\tvoid (*irq_disable)(struct irq_data *);\n\tvoid (*irq_unmask)(struct irq_data *);\n\tvoid (*irq_mask)(struct irq_data *);\n};\n\nstruct gpio_device;\n\nstruct gpio_chip {\n\tconst char *label;\n\tstruct gpio_device *gpiodev;\n\tstruct device *parent;\n\tstruct module *owner;\n\tint (*request)(struct gpio_chip *, unsigned int);\n\tvoid (*free)(struct gpio_chip *, unsigned int);\n\tint (*get_direction)(struct gpio_chip *, unsigned int);\n\tint (*direction_input)(struct gpio_chip *, unsigned int);\n\tint (*direction_output)(struct gpio_chip *, unsigned int, int);\n\tint (*get)(struct gpio_chip *, unsigned int);\n\tint (*get_multiple)(struct gpio_chip *, long unsigned int *, long unsigned int *);\n\tvoid (*set)(struct gpio_chip *, unsigned int, int);\n\tvoid (*set_multiple)(struct gpio_chip *, long unsigned int *, long unsigned int *);\n\tint (*set_config)(struct gpio_chip *, unsigned int, long unsigned int);\n\tint (*to_irq)(struct gpio_chip *, unsigned int);\n\tvoid (*dbg_show)(struct seq_file *, struct gpio_chip *);\n\tint (*init_valid_mask)(struct gpio_chip *, long unsigned int *, unsigned int);\n\tint (*add_pin_ranges)(struct gpio_chip *);\n\tint base;\n\tu16 ngpio;\n\tconst char * const *names;\n\tbool can_sleep;\n\tlong unsigned int (*read_reg)(void *);\n\tvoid (*write_reg)(void *, long unsigned int);\n\tbool be_bits;\n\tvoid *reg_dat;\n\tvoid *reg_set;\n\tvoid *reg_clr;\n\tvoid *reg_dir_out;\n\tvoid *reg_dir_in;\n\tbool bgpio_dir_unreadable;\n\tint bgpio_bits;\n\tspinlock_t bgpio_lock;\n\tlong unsigned int bgpio_data;\n\tlong unsigned int bgpio_dir;\n\tstruct gpio_irq_chip irq;\n\tlong unsigned int *valid_mask;\n};\n\nstruct pinctrl_dev;\n\nstruct pinctrl_map;\n\nstruct pinctrl_ops {\n\tint (*get_groups_count)(struct pinctrl_dev *);\n\tconst char * (*get_group_name)(struct pinctrl_dev *, unsigned int);\n\tint (*get_group_pins)(struct pinctrl_dev *, unsigned int, const unsigned int **, unsigned int *);\n\tvoid (*pin_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int);\n\tint (*dt_node_to_map)(struct pinctrl_dev *, struct device_node *, struct pinctrl_map **, unsigned int *);\n\tvoid (*dt_free_map)(struct pinctrl_dev *, struct pinctrl_map *, unsigned int);\n};\n\nstruct pinctrl_desc;\n\nstruct pinctrl_dev {\n\tstruct list_head node;\n\tstruct pinctrl_desc *desc;\n\tstruct xarray pin_desc_tree;\n\tstruct list_head gpio_ranges;\n\tstruct device *dev;\n\tstruct module *owner;\n\tvoid *driver_data;\n\tstruct pinctrl *p;\n\tstruct pinctrl_state *hog_default;\n\tstruct pinctrl_state *hog_sleep;\n\tstruct mutex mutex;\n\tstruct dentry *device_root;\n};\n\nenum pinctrl_map_type {\n\tPIN_MAP_TYPE_INVALID = 0,\n\tPIN_MAP_TYPE_DUMMY_STATE = 1,\n\tPIN_MAP_TYPE_MUX_GROUP = 2,\n\tPIN_MAP_TYPE_CONFIGS_PIN = 3,\n\tPIN_MAP_TYPE_CONFIGS_GROUP = 4,\n};\n\nstruct pinctrl_map_mux {\n\tconst char *group;\n\tconst char *function;\n};\n\nstruct pinctrl_map_configs {\n\tconst char *group_or_pin;\n\tlong unsigned int *configs;\n\tunsigned int num_configs;\n};\n\nstruct pinctrl_map {\n\tconst char *dev_name;\n\tconst char *name;\n\tenum pinctrl_map_type type;\n\tconst char *ctrl_dev_name;\n\tunion {\n\t\tstruct pinctrl_map_mux mux;\n\t\tstruct pinctrl_map_configs configs;\n\t} data;\n};\n\nstruct pinmux_ops;\n\nstruct pinconf_ops;\n\nstruct pinconf_generic_params;\n\nstruct pin_config_item;\n\nstruct pinctrl_desc {\n\tconst char *name;\n\tconst struct pinctrl_pin_desc *pins;\n\tunsigned int npins;\n\tconst struct pinctrl_ops *pctlops;\n\tconst struct pinmux_ops *pmxops;\n\tconst struct pinconf_ops *confops;\n\tstruct module *owner;\n\tunsigned int num_custom_params;\n\tconst struct pinconf_generic_params *custom_params;\n\tconst struct pin_config_item *custom_conf_items;\n\tbool link_consumers;\n};\n\nstruct pinmux_ops {\n\tint (*request)(struct pinctrl_dev *, unsigned int);\n\tint (*free)(struct pinctrl_dev *, unsigned int);\n\tint (*get_functions_count)(struct pinctrl_dev *);\n\tconst char * (*get_function_name)(struct pinctrl_dev *, unsigned int);\n\tint (*get_function_groups)(struct pinctrl_dev *, unsigned int, const char * const **, unsigned int *);\n\tint (*set_mux)(struct pinctrl_dev *, unsigned int, unsigned int);\n\tint (*gpio_request_enable)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int);\n\tvoid (*gpio_disable_free)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int);\n\tint (*gpio_set_direction)(struct pinctrl_dev *, struct pinctrl_gpio_range *, unsigned int, bool);\n\tbool strict;\n};\n\nstruct pinconf_ops {\n\tbool is_generic;\n\tint (*pin_config_get)(struct pinctrl_dev *, unsigned int, long unsigned int *);\n\tint (*pin_config_set)(struct pinctrl_dev *, unsigned int, long unsigned int *, unsigned int);\n\tint (*pin_config_group_get)(struct pinctrl_dev *, unsigned int, long unsigned int *);\n\tint (*pin_config_group_set)(struct pinctrl_dev *, unsigned int, long unsigned int *, unsigned int);\n\tvoid (*pin_config_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int);\n\tvoid (*pin_config_group_dbg_show)(struct pinctrl_dev *, struct seq_file *, unsigned int);\n\tvoid (*pin_config_config_dbg_show)(struct pinctrl_dev *, struct seq_file *, long unsigned int);\n};\n\nenum pin_config_param {\n\tPIN_CONFIG_BIAS_BUS_HOLD = 0,\n\tPIN_CONFIG_BIAS_DISABLE = 1,\n\tPIN_CONFIG_BIAS_HIGH_IMPEDANCE = 2,\n\tPIN_CONFIG_BIAS_PULL_DOWN = 3,\n\tPIN_CONFIG_BIAS_PULL_PIN_DEFAULT = 4,\n\tPIN_CONFIG_BIAS_PULL_UP = 5,\n\tPIN_CONFIG_DRIVE_OPEN_DRAIN = 6,\n\tPIN_CONFIG_DRIVE_OPEN_SOURCE = 7,\n\tPIN_CONFIG_DRIVE_PUSH_PULL = 8,\n\tPIN_CONFIG_DRIVE_STRENGTH = 9,\n\tPIN_CONFIG_DRIVE_STRENGTH_UA = 10,\n\tPIN_CONFIG_INPUT_DEBOUNCE = 11,\n\tPIN_CONFIG_INPUT_ENABLE = 12,\n\tPIN_CONFIG_INPUT_SCHMITT = 13,\n\tPIN_CONFIG_INPUT_SCHMITT_ENABLE = 14,\n\tPIN_CONFIG_MODE_LOW_POWER = 15,\n\tPIN_CONFIG_MODE_PWM = 16,\n\tPIN_CONFIG_OUTPUT = 17,\n\tPIN_CONFIG_OUTPUT_ENABLE = 18,\n\tPIN_CONFIG_PERSIST_STATE = 19,\n\tPIN_CONFIG_POWER_SOURCE = 20,\n\tPIN_CONFIG_SKEW_DELAY = 21,\n\tPIN_CONFIG_SLEEP_HARDWARE_STATE = 22,\n\tPIN_CONFIG_SLEW_RATE = 23,\n\tPIN_CONFIG_END = 127,\n\tPIN_CONFIG_MAX = 255,\n};\n\nstruct pinconf_generic_params {\n\tconst char * const property;\n\tenum pin_config_param param;\n\tu32 default_value;\n};\n\nstruct pin_config_item {\n\tconst enum pin_config_param param;\n\tconst char * const display;\n\tconst char * const format;\n\tbool has_arg;\n};\n\nstruct gpio_desc___2;\n\nstruct gpio_device {\n\tint id;\n\tstruct device dev;\n\tstruct cdev chrdev;\n\tstruct device *mockdev;\n\tstruct module *owner;\n\tstruct gpio_chip *chip;\n\tstruct gpio_desc___2 *descs;\n\tint base;\n\tu16 ngpio;\n\tconst char *label;\n\tvoid *data;\n\tstruct list_head list;\n\tstruct blocking_notifier_head notifier;\n\tstruct list_head pin_ranges;\n};\n\nstruct gpio_desc___2 {\n\tstruct gpio_device *gdev;\n\tlong unsigned int flags;\n\tconst char *label;\n\tconst char *name;\n\tunsigned int debounce_period_us;\n};\n\nstruct pinctrl_setting_mux {\n\tunsigned int group;\n\tunsigned int func;\n};\n\nstruct pinctrl_setting_configs {\n\tunsigned int group_or_pin;\n\tlong unsigned int *configs;\n\tunsigned int num_configs;\n};\n\nstruct pinctrl_setting {\n\tstruct list_head node;\n\tenum pinctrl_map_type type;\n\tstruct pinctrl_dev *pctldev;\n\tconst char *dev_name;\n\tunion {\n\t\tstruct pinctrl_setting_mux mux;\n\t\tstruct pinctrl_setting_configs configs;\n\t} data;\n};\n\nstruct pin_desc {\n\tstruct pinctrl_dev *pctldev;\n\tconst char *name;\n\tbool dynamic_name;\n\tvoid *drv_data;\n\tunsigned int mux_usecount;\n\tconst char *mux_owner;\n\tconst struct pinctrl_setting_mux *mux_setting;\n\tconst char *gpio_owner;\n};\n\nstruct pinctrl_maps {\n\tstruct list_head node;\n\tconst struct pinctrl_map *maps;\n\tunsigned int num_maps;\n};\n\nstruct pctldev;\n\nenum regcache_type {\n\tREGCACHE_NONE = 0,\n\tREGCACHE_RBTREE = 1,\n\tREGCACHE_COMPRESSED = 2,\n\tREGCACHE_FLAT = 3,\n};\n\nstruct reg_default {\n\tunsigned int reg;\n\tunsigned int def;\n};\n\nenum regmap_endian {\n\tREGMAP_ENDIAN_DEFAULT = 0,\n\tREGMAP_ENDIAN_BIG = 1,\n\tREGMAP_ENDIAN_LITTLE = 2,\n\tREGMAP_ENDIAN_NATIVE = 3,\n};\n\nstruct regmap_range {\n\tunsigned int range_min;\n\tunsigned int range_max;\n};\n\nstruct regmap_access_table {\n\tconst struct regmap_range *yes_ranges;\n\tunsigned int n_yes_ranges;\n\tconst struct regmap_range *no_ranges;\n\tunsigned int n_no_ranges;\n};\n\ntypedef void (*regmap_lock)(void *);\n\ntypedef void (*regmap_unlock)(void *);\n\nstruct regmap_range_cfg;\n\nstruct regmap_config {\n\tconst char *name;\n\tint reg_bits;\n\tint reg_stride;\n\tint pad_bits;\n\tint val_bits;\n\tbool (*writeable_reg)(struct device *, unsigned int);\n\tbool (*readable_reg)(struct device *, unsigned int);\n\tbool (*volatile_reg)(struct device *, unsigned int);\n\tbool (*precious_reg)(struct device *, unsigned int);\n\tbool (*writeable_noinc_reg)(struct device *, unsigned int);\n\tbool (*readable_noinc_reg)(struct device *, unsigned int);\n\tbool disable_locking;\n\tregmap_lock lock;\n\tregmap_unlock unlock;\n\tvoid *lock_arg;\n\tint (*reg_read)(void *, unsigned int, unsigned int *);\n\tint (*reg_write)(void *, unsigned int, unsigned int);\n\tbool fast_io;\n\tunsigned int max_register;\n\tconst struct regmap_access_table *wr_table;\n\tconst struct regmap_access_table *rd_table;\n\tconst struct regmap_access_table *volatile_table;\n\tconst struct regmap_access_table *precious_table;\n\tconst struct regmap_access_table *wr_noinc_table;\n\tconst struct regmap_access_table *rd_noinc_table;\n\tconst struct reg_default *reg_defaults;\n\tunsigned int num_reg_defaults;\n\tenum regcache_type cache_type;\n\tconst void *reg_defaults_raw;\n\tunsigned int num_reg_defaults_raw;\n\tlong unsigned int read_flag_mask;\n\tlong unsigned int write_flag_mask;\n\tbool zero_flag_mask;\n\tbool use_single_read;\n\tbool use_single_write;\n\tbool use_relaxed_mmio;\n\tbool can_multi_write;\n\tenum regmap_endian reg_format_endian;\n\tenum regmap_endian val_format_endian;\n\tconst struct regmap_range_cfg *ranges;\n\tunsigned int num_ranges;\n\tbool use_hwlock;\n\tunsigned int hwlock_id;\n\tunsigned int hwlock_mode;\n\tbool can_sleep;\n};\n\nstruct regmap_range_cfg {\n\tconst char *name;\n\tunsigned int range_min;\n\tunsigned int range_max;\n\tunsigned int selector_reg;\n\tunsigned int selector_mask;\n\tint selector_shift;\n\tunsigned int window_start;\n\tunsigned int window_len;\n};\n\ntypedef int (*regmap_hw_write)(void *, const void *, size_t);\n\ntypedef int (*regmap_hw_gather_write)(void *, const void *, size_t, const void *, size_t);\n\nstruct regmap_async;\n\ntypedef int (*regmap_hw_async_write)(void *, const void *, size_t, const void *, size_t, struct regmap_async *);\n\ntypedef int (*regmap_hw_read)(void *, const void *, size_t, void *, size_t);\n\ntypedef int (*regmap_hw_reg_read)(void *, unsigned int, unsigned int *);\n\ntypedef int (*regmap_hw_reg_write)(void *, unsigned int, unsigned int);\n\ntypedef int (*regmap_hw_reg_update_bits)(void *, unsigned int, unsigned int, unsigned int);\n\ntypedef struct regmap_async * (*regmap_hw_async_alloc)();\n\ntypedef void (*regmap_hw_free_context)(void *);\n\nstruct regmap_bus {\n\tbool fast_io;\n\tregmap_hw_write write;\n\tregmap_hw_gather_write gather_write;\n\tregmap_hw_async_write async_write;\n\tregmap_hw_reg_write reg_write;\n\tregmap_hw_reg_update_bits reg_update_bits;\n\tregmap_hw_read read;\n\tregmap_hw_reg_read reg_read;\n\tregmap_hw_free_context free_context;\n\tregmap_hw_async_alloc async_alloc;\n\tu8 read_flag_mask;\n\tenum regmap_endian reg_format_endian_default;\n\tenum regmap_endian val_format_endian_default;\n\tsize_t max_raw_read;\n\tsize_t max_raw_write;\n\tbool free_on_exit;\n};\n\nstruct i2c_device_id {\n\tchar name[20];\n\tkernel_ulong_t driver_data;\n};\n\nstruct software_node {\n\tconst char *name;\n\tconst struct software_node *parent;\n\tconst struct property_entry *properties;\n};\n\nstruct i2c_msg {\n\t__u16 addr;\n\t__u16 flags;\n\t__u16 len;\n\t__u8 *buf;\n};\n\nunion i2c_smbus_data {\n\t__u8 byte;\n\t__u16 word;\n\t__u8 block[34];\n};\n\nenum i2c_slave_event {\n\tI2C_SLAVE_READ_REQUESTED = 0,\n\tI2C_SLAVE_WRITE_REQUESTED = 1,\n\tI2C_SLAVE_READ_PROCESSED = 2,\n\tI2C_SLAVE_WRITE_RECEIVED = 3,\n\tI2C_SLAVE_STOP = 4,\n};\n\nstruct i2c_client;\n\ntypedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);\n\nstruct i2c_adapter;\n\nstruct i2c_client {\n\tshort unsigned int flags;\n\tshort unsigned int addr;\n\tchar name[20];\n\tstruct i2c_adapter *adapter;\n\tstruct device dev;\n\tint init_irq;\n\tint irq;\n\tstruct list_head detected;\n\ti2c_slave_cb_t slave_cb;\n\tvoid *devres_group_id;\n};\n\nenum i2c_alert_protocol {\n\tI2C_PROTOCOL_SMBUS_ALERT = 0,\n\tI2C_PROTOCOL_SMBUS_HOST_NOTIFY = 1,\n};\n\nstruct i2c_board_info;\n\nstruct i2c_driver {\n\tunsigned int class;\n\tint (*probe)(struct i2c_client *, const struct i2c_device_id *);\n\tint (*remove)(struct i2c_client *);\n\tint (*probe_new)(struct i2c_client *);\n\tvoid (*shutdown)(struct i2c_client *);\n\tvoid (*alert)(struct i2c_client *, enum i2c_alert_protocol, unsigned int);\n\tint (*command)(struct i2c_client *, unsigned int, void *);\n\tstruct device_driver driver;\n\tconst struct i2c_device_id *id_table;\n\tint (*detect)(struct i2c_client *, struct i2c_board_info *);\n\tconst short unsigned int *address_list;\n\tstruct list_head clients;\n};\n\nstruct i2c_board_info {\n\tchar type[20];\n\tshort unsigned int flags;\n\tshort unsigned int addr;\n\tconst char *dev_name;\n\tvoid *platform_data;\n\tstruct device_node *of_node;\n\tstruct fwnode_handle *fwnode;\n\tconst struct software_node *swnode;\n\tconst struct resource *resources;\n\tunsigned int num_resources;\n\tint irq;\n};\n\nstruct i2c_algorithm;\n\nstruct i2c_lock_operations;\n\nstruct i2c_bus_recovery_info;\n\nstruct i2c_adapter_quirks;\n\nstruct i2c_adapter {\n\tstruct module *owner;\n\tunsigned int class;\n\tconst struct i2c_algorithm *algo;\n\tvoid *algo_data;\n\tconst struct i2c_lock_operations *lock_ops;\n\tstruct rt_mutex bus_lock;\n\tstruct rt_mutex mux_lock;\n\tint timeout;\n\tint retries;\n\tstruct device dev;\n\tlong unsigned int locked_flags;\n\tint nr;\n\tchar name[48];\n\tstruct completion dev_released;\n\tstruct mutex userspace_clients_lock;\n\tstruct list_head userspace_clients;\n\tstruct i2c_bus_recovery_info *bus_recovery_info;\n\tconst struct i2c_adapter_quirks *quirks;\n\tstruct irq_domain *host_notify_domain;\n\tstruct regulator *bus_regulator;\n};\n\nstruct i2c_algorithm {\n\tint (*master_xfer)(struct i2c_adapter *, struct i2c_msg *, int);\n\tint (*master_xfer_atomic)(struct i2c_adapter *, struct i2c_msg *, int);\n\tint (*smbus_xfer)(struct i2c_adapter *, u16, short unsigned int, char, u8, int, union i2c_smbus_data *);\n\tint (*smbus_xfer_atomic)(struct i2c_adapter *, u16, short unsigned int, char, u8, int, union i2c_smbus_data *);\n\tu32 (*functionality)(struct i2c_adapter *);\n\tint (*reg_slave)(struct i2c_client *);\n\tint (*unreg_slave)(struct i2c_client *);\n};\n\nstruct i2c_lock_operations {\n\tvoid (*lock_bus)(struct i2c_adapter *, unsigned int);\n\tint (*trylock_bus)(struct i2c_adapter *, unsigned int);\n\tvoid (*unlock_bus)(struct i2c_adapter *, unsigned int);\n};\n\nstruct i2c_bus_recovery_info {\n\tint (*recover_bus)(struct i2c_adapter *);\n\tint (*get_scl)(struct i2c_adapter *);\n\tvoid (*set_scl)(struct i2c_adapter *, int);\n\tint (*get_sda)(struct i2c_adapter *);\n\tvoid (*set_sda)(struct i2c_adapter *, int);\n\tint (*get_bus_free)(struct i2c_adapter *);\n\tvoid (*prepare_recovery)(struct i2c_adapter *);\n\tvoid (*unprepare_recovery)(struct i2c_adapter *);\n\tstruct gpio_desc *scl_gpiod;\n\tstruct gpio_desc *sda_gpiod;\n\tstruct pinctrl *pinctrl;\n\tstruct pinctrl_state *pins_default;\n\tstruct pinctrl_state *pins_gpio;\n};\n\nstruct i2c_adapter_quirks {\n\tu64 flags;\n\tint max_num_msgs;\n\tu16 max_write_len;\n\tu16 max_read_len;\n\tu16 max_comb_1st_msg_len;\n\tu16 max_comb_2nd_msg_len;\n};\n\nenum {\n\tSX150X_123 = 0,\n\tSX150X_456 = 1,\n\tSX150X_789 = 2,\n};\n\nenum {\n\tSX150X_789_REG_MISC_AUTOCLEAR_OFF = 1,\n\tSX150X_MAX_REGISTER = 173,\n\tSX150X_IRQ_TYPE_EDGE_RISING = 1,\n\tSX150X_IRQ_TYPE_EDGE_FALLING = 2,\n\tSX150X_789_RESET_KEY1 = 18,\n\tSX150X_789_RESET_KEY2 = 52,\n};\n\nstruct sx150x_123_pri {\n\tu8 reg_pld_mode;\n\tu8 reg_pld_table0;\n\tu8 reg_pld_table1;\n\tu8 reg_pld_table2;\n\tu8 reg_pld_table3;\n\tu8 reg_pld_table4;\n\tu8 reg_advanced;\n};\n\nstruct sx150x_456_pri {\n\tu8 reg_pld_mode;\n\tu8 reg_pld_table0;\n\tu8 reg_pld_table1;\n\tu8 reg_pld_table2;\n\tu8 reg_pld_table3;\n\tu8 reg_pld_table4;\n\tu8 reg_advanced;\n};\n\nstruct sx150x_789_pri {\n\tu8 reg_drain;\n\tu8 reg_polarity;\n\tu8 reg_clock;\n\tu8 reg_misc;\n\tu8 reg_reset;\n\tu8 ngpios;\n};\n\nstruct sx150x_device_data {\n\tu8 model;\n\tu8 reg_pullup;\n\tu8 reg_pulldn;\n\tu8 reg_dir;\n\tu8 reg_data;\n\tu8 reg_irq_mask;\n\tu8 reg_irq_src;\n\tu8 reg_sense;\n\tu8 ngpios;\n\tunion {\n\t\tstruct sx150x_123_pri x123;\n\t\tstruct sx150x_456_pri x456;\n\t\tstruct sx150x_789_pri x789;\n\t} pri;\n\tconst struct pinctrl_pin_desc *pins;\n\tunsigned int npins;\n};\n\nstruct regmap;\n\nstruct sx150x_pinctrl {\n\tstruct device *dev;\n\tstruct i2c_client *client;\n\tstruct pinctrl_dev *pctldev;\n\tstruct pinctrl_desc pinctrl_desc;\n\tstruct gpio_chip gpio;\n\tstruct irq_chip irq_chip;\n\tstruct regmap *regmap;\n\tstruct {\n\t\tu32 sense;\n\t\tu32 masked;\n\t} irq;\n\tstruct mutex lock;\n\tconst struct sx150x_device_data *data;\n};\n\nstruct intel_pingroup {\n\tconst char *name;\n\tconst unsigned int *pins;\n\tsize_t npins;\n\tshort unsigned int mode;\n\tconst unsigned int *modes;\n};\n\nstruct intel_function {\n\tconst char *name;\n\tconst char * const *groups;\n\tsize_t ngroups;\n};\n\nstruct intel_padgroup {\n\tunsigned int reg_num;\n\tunsigned int base;\n\tunsigned int size;\n\tint gpio_base;\n\tunsigned int padown_num;\n};\n\nstruct intel_community {\n\tunsigned int barno;\n\tunsigned int padown_offset;\n\tunsigned int padcfglock_offset;\n\tunsigned int hostown_offset;\n\tunsigned int is_offset;\n\tunsigned int ie_offset;\n\tunsigned int features;\n\tunsigned int pin_base;\n\tsize_t npins;\n\tunsigned int gpp_size;\n\tunsigned int gpp_num_padown_regs;\n\tconst struct intel_padgroup *gpps;\n\tsize_t ngpps;\n\tconst unsigned int *pad_map;\n\tshort unsigned int nirqs;\n\tshort unsigned int acpi_space_id;\n\tvoid *regs;\n\tvoid *pad_regs;\n};\n\nstruct intel_pinctrl_soc_data {\n\tconst char *uid;\n\tconst struct pinctrl_pin_desc *pins;\n\tsize_t npins;\n\tconst struct intel_pingroup *groups;\n\tsize_t ngroups;\n\tconst struct intel_function *functions;\n\tsize_t nfunctions;\n\tconst struct intel_community *communities;\n\tsize_t ncommunities;\n};\n\nstruct intel_pad_context;\n\nstruct intel_community_context;\n\nstruct intel_pinctrl_context {\n\tstruct intel_pad_context *pads;\n\tstruct intel_community_context *communities;\n};\n\nstruct intel_pad_context {\n\tu32 conf0;\n\tu32 val;\n};\n\nstruct intel_pinctrl {\n\tstruct device *dev;\n\traw_spinlock_t lock;\n\tstruct pinctrl_desc pctldesc;\n\tstruct pinctrl_dev *pctldev;\n\tstruct gpio_chip chip;\n\tstruct irq_chip irqchip;\n\tconst struct intel_pinctrl_soc_data *soc;\n\tstruct intel_community *communities;\n\tsize_t ncommunities;\n\tstruct intel_pinctrl_context context;\n\tint irq;\n};\n\ntypedef acpi_status (*acpi_adr_space_handler)(u32, acpi_physical_address, u32, u64 *, void *, void *);\n\ntypedef acpi_status (*acpi_adr_space_setup)(acpi_handle, u32, void *, void **);\n\nstruct acpi_hotplug_profile {\n\tstruct kobject kobj;\n\tint (*scan_dependent)(struct acpi_device *);\n\tvoid (*notify_online)(struct acpi_device *);\n\tbool enabled: 1;\n\tbool demand_offline: 1;\n};\n\nstruct acpi_device_status {\n\tu32 present: 1;\n\tu32 enabled: 1;\n\tu32 show_in_ui: 1;\n\tu32 functional: 1;\n\tu32 battery_present: 1;\n\tu32 reserved: 27;\n};\n\nstruct acpi_device_flags {\n\tu32 dynamic_status: 1;\n\tu32 removable: 1;\n\tu32 ejectable: 1;\n\tu32 power_manageable: 1;\n\tu32 match_driver: 1;\n\tu32 initialized: 1;\n\tu32 visited: 1;\n\tu32 hotplug_notify: 1;\n\tu32 is_dock_station: 1;\n\tu32 of_compatible_ok: 1;\n\tu32 coherent_dma: 1;\n\tu32 cca_seen: 1;\n\tu32 enumeration_by_parent: 1;\n\tu32 reserved: 19;\n};\n\ntypedef char acpi_bus_id[8];\n\nstruct acpi_pnp_type {\n\tu32 hardware_id: 1;\n\tu32 bus_address: 1;\n\tu32 platform_id: 1;\n\tu32 reserved: 29;\n};\n\ntypedef u64 acpi_bus_address;\n\ntypedef char acpi_device_name[40];\n\ntypedef char acpi_device_class[20];\n\nstruct acpi_device_pnp {\n\tacpi_bus_id bus_id;\n\tint instance_no;\n\tstruct acpi_pnp_type type;\n\tacpi_bus_address bus_address;\n\tchar *unique_id;\n\tstruct list_head ids;\n\tacpi_device_name device_name;\n\tacpi_device_class device_class;\n\tunion acpi_object *str_obj;\n};\n\nstruct acpi_device_power_flags {\n\tu32 explicit_get: 1;\n\tu32 power_resources: 1;\n\tu32 inrush_current: 1;\n\tu32 power_removed: 1;\n\tu32 ignore_parent: 1;\n\tu32 dsw_present: 1;\n\tu32 reserved: 26;\n};\n\nstruct acpi_device_power_state {\n\tstruct {\n\t\tu8 valid: 1;\n\t\tu8 explicit_set: 1;\n\t\tu8 reserved: 6;\n\t} flags;\n\tint power;\n\tint latency;\n\tstruct list_head resources;\n};\n\nstruct acpi_device_power {\n\tint state;\n\tstruct acpi_device_power_flags flags;\n\tstruct acpi_device_power_state states[5];\n};\n\nstruct acpi_device_wakeup_flags {\n\tu8 valid: 1;\n\tu8 notifier_present: 1;\n};\n\nstruct acpi_device_wakeup_context {\n\tvoid (*func)(struct acpi_device_wakeup_context *);\n\tstruct device *dev;\n};\n\nstruct acpi_device_wakeup {\n\tacpi_handle gpe_device;\n\tu64 gpe_number;\n\tu64 sleep_state;\n\tstruct list_head resources;\n\tstruct acpi_device_wakeup_flags flags;\n\tstruct acpi_device_wakeup_context context;\n\tstruct wakeup_source *ws;\n\tint prepare_count;\n\tint enable_count;\n};\n\nstruct acpi_device_perf_flags {\n\tu8 reserved: 8;\n};\n\nstruct acpi_device_perf_state;\n\nstruct acpi_device_perf {\n\tint state;\n\tstruct acpi_device_perf_flags flags;\n\tint state_count;\n\tstruct acpi_device_perf_state *states;\n};\n\nstruct acpi_device_dir {\n\tstruct proc_dir_entry *entry;\n};\n\nstruct acpi_device_data {\n\tconst union acpi_object *pointer;\n\tstruct list_head properties;\n\tconst union acpi_object *of_compatible;\n\tstruct list_head subnodes;\n};\n\nstruct acpi_scan_handler;\n\nstruct acpi_hotplug_context;\n\nstruct acpi_driver;\n\nstruct acpi_gpio_mapping;\n\nstruct acpi_device {\n\tint device_type;\n\tacpi_handle handle;\n\tstruct fwnode_handle fwnode;\n\tstruct acpi_device *parent;\n\tstruct list_head children;\n\tstruct list_head node;\n\tstruct list_head wakeup_list;\n\tstruct list_head del_list;\n\tstruct acpi_device_status status;\n\tstruct acpi_device_flags flags;\n\tstruct acpi_device_pnp pnp;\n\tstruct acpi_device_power power;\n\tstruct acpi_device_wakeup wakeup;\n\tstruct acpi_device_perf performance;\n\tstruct acpi_device_dir dir;\n\tstruct acpi_device_data data;\n\tstruct acpi_scan_handler *handler;\n\tstruct acpi_hotplug_context *hp;\n\tstruct acpi_driver *driver;\n\tconst struct acpi_gpio_mapping *driver_gpios;\n\tvoid *driver_data;\n\tstruct device dev;\n\tunsigned int physical_node_count;\n\tunsigned int dep_unmet;\n\tstruct list_head physical_node_list;\n\tstruct mutex physical_node_lock;\n\tvoid (*remove)(struct acpi_device *);\n};\n\nstruct acpi_scan_handler {\n\tconst struct acpi_device_id *ids;\n\tstruct list_head list_node;\n\tbool (*match)(const char *, const struct acpi_device_id **);\n\tint (*attach)(struct acpi_device *, const struct acpi_device_id *);\n\tvoid (*detach)(struct acpi_device *);\n\tvoid (*bind)(struct device *);\n\tvoid (*unbind)(struct device *);\n\tstruct acpi_hotplug_profile hotplug;\n};\n\nstruct acpi_hotplug_context {\n\tstruct acpi_device *self;\n\tint (*notify)(struct acpi_device *, u32);\n\tvoid (*uevent)(struct acpi_device *, u32);\n\tvoid (*fixup)(struct acpi_device *);\n};\n\ntypedef int (*acpi_op_add)(struct acpi_device *);\n\ntypedef int (*acpi_op_remove)(struct acpi_device *);\n\ntypedef void (*acpi_op_notify)(struct acpi_device *, u32);\n\nstruct acpi_device_ops {\n\tacpi_op_add add;\n\tacpi_op_remove remove;\n\tacpi_op_notify notify;\n};\n\nstruct acpi_driver {\n\tchar name[80];\n\tchar class[80];\n\tconst struct acpi_device_id *ids;\n\tunsigned int flags;\n\tstruct acpi_device_ops ops;\n\tstruct device_driver drv;\n\tstruct module *owner;\n};\n\nstruct acpi_device_perf_state {\n\tstruct {\n\t\tu8 valid: 1;\n\t\tu8 reserved: 7;\n\t} flags;\n\tu8 power;\n\tu8 performance;\n\tint latency;\n};\n\nstruct acpi_gpio_params;\n\nstruct acpi_gpio_mapping {\n\tconst char *name;\n\tconst struct acpi_gpio_params *data;\n\tunsigned int size;\n\tunsigned int quirks;\n};\n\nstruct intel_pad_context___2;\n\nstruct intel_pinctrl_context___2 {\n\tstruct intel_pad_context___2 *pads;\n\tstruct intel_community_context *communities;\n};\n\nstruct intel_pad_context___2 {\n\tu32 padctrl0;\n\tu32 padctrl1;\n};\n\nstruct intel_community_context {\n\tunsigned int intr_lines[16];\n\tu32 saved_intmask;\n};\n\nstruct intel_pinctrl___2 {\n\tstruct device *dev;\n\traw_spinlock_t lock;\n\tstruct pinctrl_desc pctldesc;\n\tstruct pinctrl_dev *pctldev;\n\tstruct gpio_chip chip;\n\tstruct irq_chip irqchip;\n\tconst struct intel_pinctrl_soc_data *soc;\n\tstruct intel_community *communities;\n\tsize_t ncommunities;\n\tstruct intel_pinctrl_context___2 context;\n\tint irq;\n};\n\nenum {\n\tINTEL_GPIO_BASE_ZERO = 4294967294,\n\tINTEL_GPIO_BASE_NOMAP = 4294967295,\n\tINTEL_GPIO_BASE_MATCH = 0,\n};\n\nstruct intel_pad_context___3;\n\nstruct intel_community_context___2;\n\nstruct intel_pinctrl_context___3 {\n\tstruct intel_pad_context___3 *pads;\n\tstruct intel_community_context___2 *communities;\n};\n\nstruct intel_pad_context___3 {\n\tu32 padcfg0;\n\tu32 padcfg1;\n\tu32 padcfg2;\n};\n\nstruct intel_community_context___2 {\n\tu32 *intmask;\n\tu32 *hostown;\n};\n\nstruct intel_pinctrl___3 {\n\tstruct device *dev;\n\traw_spinlock_t lock;\n\tstruct pinctrl_desc pctldesc;\n\tstruct pinctrl_dev *pctldev;\n\tstruct gpio_chip chip;\n\tstruct irq_chip irqchip;\n\tconst struct intel_pinctrl_soc_data *soc;\n\tstruct intel_community *communities;\n\tsize_t ncommunities;\n\tstruct intel_pinctrl_context___3 context;\n\tint irq;\n};\n\nenum {\n\tPAD_UNLOCKED = 0,\n\tPAD_LOCKED = 1,\n\tPAD_LOCKED_TX = 2,\n\tPAD_LOCKED_FULL = 3,\n};\n\nstruct gpio_pin_range {\n\tstruct list_head node;\n\tstruct pinctrl_dev *pctldev;\n\tstruct pinctrl_gpio_range range;\n};\n\nstruct gpio_array;\n\nstruct gpio_descs {\n\tstruct gpio_array *info;\n\tunsigned int ndescs;\n\tstruct gpio_desc___2 *desc[0];\n};\n\nstruct gpio_array {\n\tstruct gpio_desc___2 **desc;\n\tunsigned int size;\n\tstruct gpio_chip *chip;\n\tlong unsigned int *get_mask;\n\tlong unsigned int *set_mask;\n\tlong unsigned int invert_mask[0];\n};\n\nenum gpiod_flags {\n\tGPIOD_ASIS = 0,\n\tGPIOD_IN = 1,\n\tGPIOD_OUT_LOW = 3,\n\tGPIOD_OUT_HIGH = 7,\n\tGPIOD_OUT_LOW_OPEN_DRAIN = 11,\n\tGPIOD_OUT_HIGH_OPEN_DRAIN = 15,\n};\n\nstruct acpi_gpio_params {\n\tunsigned int crs_entry_index;\n\tunsigned int line_index;\n\tbool active_low;\n};\n\nenum gpio_lookup_flags {\n\tGPIO_ACTIVE_HIGH = 0,\n\tGPIO_ACTIVE_LOW = 1,\n\tGPIO_OPEN_DRAIN = 2,\n\tGPIO_OPEN_SOURCE = 4,\n\tGPIO_PERSISTENT = 0,\n\tGPIO_TRANSITORY = 8,\n\tGPIO_PULL_UP = 16,\n\tGPIO_PULL_DOWN = 32,\n\tGPIO_LOOKUP_FLAGS_DEFAULT = 0,\n};\n\nstruct gpiod_lookup {\n\tconst char *key;\n\tu16 chip_hwnum;\n\tconst char *con_id;\n\tunsigned int idx;\n\tlong unsigned int flags;\n};\n\nstruct gpiod_lookup_table {\n\tstruct list_head list;\n\tconst char *dev_id;\n\tstruct gpiod_lookup table[0];\n};\n\nstruct gpiod_hog {\n\tstruct list_head list;\n\tconst char *chip_label;\n\tu16 chip_hwnum;\n\tconst char *line_name;\n\tlong unsigned int lflags;\n\tint dflags;\n};\n\nenum {\n\tGPIOLINE_CHANGED_REQUESTED = 1,\n\tGPIOLINE_CHANGED_RELEASED = 2,\n\tGPIOLINE_CHANGED_CONFIG = 3,\n};\n\nstruct acpi_gpio_info {\n\tstruct acpi_device *adev;\n\tenum gpiod_flags flags;\n\tbool gpioint;\n\tint pin_config;\n\tint polarity;\n\tint triggering;\n\tunsigned int debounce;\n\tunsigned int quirks;\n};\n\nstruct trace_event_raw_gpio_direction {\n\tstruct trace_entry ent;\n\tunsigned int gpio;\n\tint in;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_gpio_value {\n\tstruct trace_entry ent;\n\tunsigned int gpio;\n\tint get;\n\tint value;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_gpio_direction {};\n\nstruct trace_event_data_offsets_gpio_value {};\n\ntypedef void (*btf_trace_gpio_direction)(void *, unsigned int, int, int);\n\ntypedef void (*btf_trace_gpio_value)(void *, unsigned int, int, int);\n\nstruct devres;\n\nstruct gpio {\n\tunsigned int gpio;\n\tlong unsigned int flags;\n\tconst char *label;\n};\n\nstruct gpiochip_info {\n\tchar name[32];\n\tchar label[32];\n\t__u32 lines;\n};\n\nenum gpio_v2_line_flag {\n\tGPIO_V2_LINE_FLAG_USED = 1,\n\tGPIO_V2_LINE_FLAG_ACTIVE_LOW = 2,\n\tGPIO_V2_LINE_FLAG_INPUT = 4,\n\tGPIO_V2_LINE_FLAG_OUTPUT = 8,\n\tGPIO_V2_LINE_FLAG_EDGE_RISING = 16,\n\tGPIO_V2_LINE_FLAG_EDGE_FALLING = 32,\n\tGPIO_V2_LINE_FLAG_OPEN_DRAIN = 64,\n\tGPIO_V2_LINE_FLAG_OPEN_SOURCE = 128,\n\tGPIO_V2_LINE_FLAG_BIAS_PULL_UP = 256,\n\tGPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = 512,\n\tGPIO_V2_LINE_FLAG_BIAS_DISABLED = 1024,\n\tGPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME = 2048,\n};\n\nstruct gpio_v2_line_values {\n\t__u64 bits;\n\t__u64 mask;\n};\n\nenum gpio_v2_line_attr_id {\n\tGPIO_V2_LINE_ATTR_ID_FLAGS = 1,\n\tGPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES = 2,\n\tGPIO_V2_LINE_ATTR_ID_DEBOUNCE = 3,\n};\n\nstruct gpio_v2_line_attribute {\n\t__u32 id;\n\t__u32 padding;\n\tunion {\n\t\t__u64 flags;\n\t\t__u64 values;\n\t\t__u32 debounce_period_us;\n\t};\n};\n\nstruct gpio_v2_line_config_attribute {\n\tstruct gpio_v2_line_attribute attr;\n\t__u64 mask;\n};\n\nstruct gpio_v2_line_config {\n\t__u64 flags;\n\t__u32 num_attrs;\n\t__u32 padding[5];\n\tstruct gpio_v2_line_config_attribute attrs[10];\n};\n\nstruct gpio_v2_line_request {\n\t__u32 offsets[64];\n\tchar consumer[32];\n\tstruct gpio_v2_line_config config;\n\t__u32 num_lines;\n\t__u32 event_buffer_size;\n\t__u32 padding[5];\n\t__s32 fd;\n};\n\nstruct gpio_v2_line_info {\n\tchar name[32];\n\tchar consumer[32];\n\t__u32 offset;\n\t__u32 num_attrs;\n\t__u64 flags;\n\tstruct gpio_v2_line_attribute attrs[10];\n\t__u32 padding[4];\n};\n\nenum gpio_v2_line_changed_type {\n\tGPIO_V2_LINE_CHANGED_REQUESTED = 1,\n\tGPIO_V2_LINE_CHANGED_RELEASED = 2,\n\tGPIO_V2_LINE_CHANGED_CONFIG = 3,\n};\n\nstruct gpio_v2_line_info_changed {\n\tstruct gpio_v2_line_info info;\n\t__u64 timestamp_ns;\n\t__u32 event_type;\n\t__u32 padding[5];\n};\n\nenum gpio_v2_line_event_id {\n\tGPIO_V2_LINE_EVENT_RISING_EDGE = 1,\n\tGPIO_V2_LINE_EVENT_FALLING_EDGE = 2,\n};\n\nstruct gpio_v2_line_event {\n\t__u64 timestamp_ns;\n\t__u32 id;\n\t__u32 offset;\n\t__u32 seqno;\n\t__u32 line_seqno;\n\t__u32 padding[6];\n};\n\nstruct gpioline_info {\n\t__u32 line_offset;\n\t__u32 flags;\n\tchar name[32];\n\tchar consumer[32];\n};\n\nstruct gpioline_info_changed {\n\tstruct gpioline_info info;\n\t__u64 timestamp;\n\t__u32 event_type;\n\t__u32 padding[5];\n};\n\nstruct gpiohandle_request {\n\t__u32 lineoffsets[64];\n\t__u32 flags;\n\t__u8 default_values[64];\n\tchar consumer_label[32];\n\t__u32 lines;\n\tint fd;\n};\n\nstruct gpiohandle_config {\n\t__u32 flags;\n\t__u8 default_values[64];\n\t__u32 padding[4];\n};\n\nstruct gpiohandle_data {\n\t__u8 values[64];\n};\n\nstruct gpioevent_request {\n\t__u32 lineoffset;\n\t__u32 handleflags;\n\t__u32 eventflags;\n\tchar consumer_label[32];\n\tint fd;\n};\n\nstruct gpioevent_data {\n\t__u64 timestamp;\n\t__u32 id;\n};\n\nstruct linehandle_state {\n\tstruct gpio_device *gdev;\n\tconst char *label;\n\tstruct gpio_desc___2 *descs[64];\n\tu32 num_descs;\n};\n\nstruct linereq;\n\nstruct line {\n\tstruct gpio_desc___2 *desc;\n\tstruct linereq *req;\n\tunsigned int irq;\n\tu64 eflags;\n\tu64 timestamp_ns;\n\tu32 req_seqno;\n\tu32 line_seqno;\n\tstruct delayed_work work;\n\tunsigned int sw_debounced;\n\tunsigned int level;\n};\n\nstruct linereq {\n\tstruct gpio_device *gdev;\n\tconst char *label;\n\tu32 num_lines;\n\twait_queue_head_t wait;\n\tu32 event_buffer_size;\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tstruct gpio_v2_line_event *type;\n\t\t\tconst struct gpio_v2_line_event *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tstruct gpio_v2_line_event *ptr;\n\t\t\tconst struct gpio_v2_line_event *ptr_const;\n\t\t};\n\t\tstruct gpio_v2_line_event buf[0];\n\t} events;\n\tatomic_t seqno;\n\tstruct mutex config_mutex;\n\tstruct line lines[0];\n};\n\nstruct lineevent_state {\n\tstruct gpio_device *gdev;\n\tconst char *label;\n\tstruct gpio_desc___2 *desc;\n\tu32 eflags;\n\tint irq;\n\twait_queue_head_t wait;\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tstruct gpioevent_data *type;\n\t\t\tconst struct gpioevent_data *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tstruct gpioevent_data *ptr;\n\t\t\tconst struct gpioevent_data *ptr_const;\n\t\t};\n\t\tstruct gpioevent_data buf[16];\n\t} events;\n\tu64 timestamp;\n};\n\nstruct gpio_chardev_data {\n\tstruct gpio_device *gdev;\n\twait_queue_head_t wait;\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tstruct gpio_v2_line_info_changed *type;\n\t\t\tconst struct gpio_v2_line_info_changed *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tstruct gpio_v2_line_info_changed *ptr;\n\t\t\tconst struct gpio_v2_line_info_changed *ptr_const;\n\t\t};\n\t\tstruct gpio_v2_line_info_changed buf[32];\n\t} events;\n\tstruct notifier_block lineinfo_changed_nb;\n\tlong unsigned int *watched_lines;\n\tatomic_t watch_abi_version;\n};\n\ntypedef u64 acpi_size;\n\nstruct acpi_buffer {\n\tacpi_size length;\n\tvoid *pointer;\n};\n\ntypedef void (*acpi_object_handler)(acpi_handle, void *);\n\nstruct acpi_connection_info {\n\tu8 *connection;\n\tu16 length;\n\tu8 access_length;\n};\n\nstruct acpi_resource_irq {\n\tu8 descriptor_length;\n\tu8 triggering;\n\tu8 polarity;\n\tu8 shareable;\n\tu8 wake_capable;\n\tu8 interrupt_count;\n\tu8 interrupts[1];\n};\n\nstruct acpi_resource_dma {\n\tu8 type;\n\tu8 bus_master;\n\tu8 transfer;\n\tu8 channel_count;\n\tu8 channels[1];\n};\n\nstruct acpi_resource_start_dependent {\n\tu8 descriptor_length;\n\tu8 compatibility_priority;\n\tu8 performance_robustness;\n};\n\nstruct acpi_resource_io {\n\tu8 io_decode;\n\tu8 alignment;\n\tu8 address_length;\n\tu16 minimum;\n\tu16 maximum;\n} __attribute__((packed));\n\nstruct acpi_resource_fixed_io {\n\tu16 address;\n\tu8 address_length;\n} __attribute__((packed));\n\nstruct acpi_resource_fixed_dma {\n\tu16 request_lines;\n\tu16 channels;\n\tu8 width;\n} __attribute__((packed));\n\nstruct acpi_resource_vendor {\n\tu16 byte_length;\n\tu8 byte_data[1];\n} __attribute__((packed));\n\nstruct acpi_resource_vendor_typed {\n\tu16 byte_length;\n\tu8 uuid_subtype;\n\tu8 uuid[16];\n\tu8 byte_data[1];\n};\n\nstruct acpi_resource_end_tag {\n\tu8 checksum;\n};\n\nstruct acpi_resource_memory24 {\n\tu8 write_protect;\n\tu16 minimum;\n\tu16 maximum;\n\tu16 alignment;\n\tu16 address_length;\n} __attribute__((packed));\n\nstruct acpi_resource_memory32 {\n\tu8 write_protect;\n\tu32 minimum;\n\tu32 maximum;\n\tu32 alignment;\n\tu32 address_length;\n} __attribute__((packed));\n\nstruct acpi_resource_fixed_memory32 {\n\tu8 write_protect;\n\tu32 address;\n\tu32 address_length;\n} __attribute__((packed));\n\nstruct acpi_memory_attribute {\n\tu8 write_protect;\n\tu8 caching;\n\tu8 range_type;\n\tu8 translation;\n};\n\nstruct acpi_io_attribute {\n\tu8 range_type;\n\tu8 translation;\n\tu8 translation_type;\n\tu8 reserved1;\n};\n\nunion acpi_resource_attribute {\n\tstruct acpi_memory_attribute mem;\n\tstruct acpi_io_attribute io;\n\tu8 type_specific;\n};\n\nstruct acpi_resource_label {\n\tu16 string_length;\n\tchar *string_ptr;\n} __attribute__((packed));\n\nstruct acpi_resource_source {\n\tu8 index;\n\tu16 string_length;\n\tchar *string_ptr;\n} __attribute__((packed));\n\nstruct acpi_address16_attribute {\n\tu16 granularity;\n\tu16 minimum;\n\tu16 maximum;\n\tu16 translation_offset;\n\tu16 address_length;\n};\n\nstruct acpi_address32_attribute {\n\tu32 granularity;\n\tu32 minimum;\n\tu32 maximum;\n\tu32 translation_offset;\n\tu32 address_length;\n};\n\nstruct acpi_address64_attribute {\n\tu64 granularity;\n\tu64 minimum;\n\tu64 maximum;\n\tu64 translation_offset;\n\tu64 address_length;\n};\n\nstruct acpi_resource_address {\n\tu8 resource_type;\n\tu8 producer_consumer;\n\tu8 decode;\n\tu8 min_address_fixed;\n\tu8 max_address_fixed;\n\tunion acpi_resource_attribute info;\n};\n\nstruct acpi_resource_address16 {\n\tu8 resource_type;\n\tu8 producer_consumer;\n\tu8 decode;\n\tu8 min_address_fixed;\n\tu8 max_address_fixed;\n\tunion acpi_resource_attribute info;\n\tstruct acpi_address16_attribute address;\n\tstruct acpi_resource_source resource_source;\n} __attribute__((packed));\n\nstruct acpi_resource_address32 {\n\tu8 resource_type;\n\tu8 producer_consumer;\n\tu8 decode;\n\tu8 min_address_fixed;\n\tu8 max_address_fixed;\n\tunion acpi_resource_attribute info;\n\tstruct acpi_address32_attribute address;\n\tstruct acpi_resource_source resource_source;\n} __attribute__((packed));\n\nstruct acpi_resource_address64 {\n\tu8 resource_type;\n\tu8 producer_consumer;\n\tu8 decode;\n\tu8 min_address_fixed;\n\tu8 max_address_fixed;\n\tunion acpi_resource_attribute info;\n\tstruct acpi_address64_attribute address;\n\tstruct acpi_resource_source resource_source;\n} __attribute__((packed));\n\nstruct acpi_resource_extended_address64 {\n\tu8 resource_type;\n\tu8 producer_consumer;\n\tu8 decode;\n\tu8 min_address_fixed;\n\tu8 max_address_fixed;\n\tunion acpi_resource_attribute info;\n\tu8 revision_ID;\n\tstruct acpi_address64_attribute address;\n\tu64 type_specific;\n} __attribute__((packed));\n\nstruct acpi_resource_extended_irq {\n\tu8 producer_consumer;\n\tu8 triggering;\n\tu8 polarity;\n\tu8 shareable;\n\tu8 wake_capable;\n\tu8 interrupt_count;\n\tstruct acpi_resource_source resource_source;\n\tu32 interrupts[1];\n} __attribute__((packed));\n\nstruct acpi_resource_generic_register {\n\tu8 space_id;\n\tu8 bit_width;\n\tu8 bit_offset;\n\tu8 access_size;\n\tu64 address;\n} __attribute__((packed));\n\nstruct acpi_resource_gpio {\n\tu8 revision_id;\n\tu8 connection_type;\n\tu8 producer_consumer;\n\tu8 pin_config;\n\tu8 shareable;\n\tu8 wake_capable;\n\tu8 io_restriction;\n\tu8 triggering;\n\tu8 polarity;\n\tu16 drive_strength;\n\tu16 debounce_timeout;\n\tu16 pin_table_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu16 *pin_table;\n\tu8 *vendor_data;\n} __attribute__((packed));\n\nstruct acpi_resource_common_serialbus {\n\tu8 revision_id;\n\tu8 type;\n\tu8 producer_consumer;\n\tu8 slave_mode;\n\tu8 connection_sharing;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu8 *vendor_data;\n} __attribute__((packed));\n\nstruct acpi_resource_i2c_serialbus {\n\tu8 revision_id;\n\tu8 type;\n\tu8 producer_consumer;\n\tu8 slave_mode;\n\tu8 connection_sharing;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu8 *vendor_data;\n\tu8 access_mode;\n\tu16 slave_address;\n\tu32 connection_speed;\n} __attribute__((packed));\n\nstruct acpi_resource_spi_serialbus {\n\tu8 revision_id;\n\tu8 type;\n\tu8 producer_consumer;\n\tu8 slave_mode;\n\tu8 connection_sharing;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu8 *vendor_data;\n\tu8 wire_mode;\n\tu8 device_polarity;\n\tu8 data_bit_length;\n\tu8 clock_phase;\n\tu8 clock_polarity;\n\tu16 device_selection;\n\tu32 connection_speed;\n} __attribute__((packed));\n\nstruct acpi_resource_uart_serialbus {\n\tu8 revision_id;\n\tu8 type;\n\tu8 producer_consumer;\n\tu8 slave_mode;\n\tu8 connection_sharing;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu8 *vendor_data;\n\tu8 endian;\n\tu8 data_bits;\n\tu8 stop_bits;\n\tu8 flow_control;\n\tu8 parity;\n\tu8 lines_enabled;\n\tu16 rx_fifo_size;\n\tu16 tx_fifo_size;\n\tu32 default_baud_rate;\n} __attribute__((packed));\n\nstruct acpi_resource_csi2_serialbus {\n\tu8 revision_id;\n\tu8 type;\n\tu8 producer_consumer;\n\tu8 slave_mode;\n\tu8 connection_sharing;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu8 *vendor_data;\n\tu8 local_port_instance;\n\tu8 phy_type;\n} __attribute__((packed));\n\nstruct acpi_resource_pin_function {\n\tu8 revision_id;\n\tu8 pin_config;\n\tu8 shareable;\n\tu16 function_number;\n\tu16 pin_table_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu16 *pin_table;\n\tu8 *vendor_data;\n} __attribute__((packed));\n\nstruct acpi_resource_pin_config {\n\tu8 revision_id;\n\tu8 producer_consumer;\n\tu8 shareable;\n\tu8 pin_config_type;\n\tu32 pin_config_value;\n\tu16 pin_table_length;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tu16 *pin_table;\n\tu8 *vendor_data;\n} __attribute__((packed));\n\nstruct acpi_resource_pin_group {\n\tu8 revision_id;\n\tu8 producer_consumer;\n\tu16 pin_table_length;\n\tu16 vendor_length;\n\tu16 *pin_table;\n\tstruct acpi_resource_label resource_label;\n\tu8 *vendor_data;\n} __attribute__((packed));\n\nstruct acpi_resource_pin_group_function {\n\tu8 revision_id;\n\tu8 producer_consumer;\n\tu8 shareable;\n\tu16 function_number;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tstruct acpi_resource_label resource_source_label;\n\tu8 *vendor_data;\n} __attribute__((packed));\n\nstruct acpi_resource_pin_group_config {\n\tu8 revision_id;\n\tu8 producer_consumer;\n\tu8 shareable;\n\tu8 pin_config_type;\n\tu32 pin_config_value;\n\tu16 vendor_length;\n\tstruct acpi_resource_source resource_source;\n\tstruct acpi_resource_label resource_source_label;\n\tu8 *vendor_data;\n} __attribute__((packed));\n\nunion acpi_resource_data {\n\tstruct acpi_resource_irq irq;\n\tstruct acpi_resource_dma dma;\n\tstruct acpi_resource_start_dependent start_dpf;\n\tstruct acpi_resource_io io;\n\tstruct acpi_resource_fixed_io fixed_io;\n\tstruct acpi_resource_fixed_dma fixed_dma;\n\tstruct acpi_resource_vendor vendor;\n\tstruct acpi_resource_vendor_typed vendor_typed;\n\tstruct acpi_resource_end_tag end_tag;\n\tstruct acpi_resource_memory24 memory24;\n\tstruct acpi_resource_memory32 memory32;\n\tstruct acpi_resource_fixed_memory32 fixed_memory32;\n\tstruct acpi_resource_address16 address16;\n\tstruct acpi_resource_address32 address32;\n\tstruct acpi_resource_address64 address64;\n\tstruct acpi_resource_extended_address64 ext_address64;\n\tstruct acpi_resource_extended_irq extended_irq;\n\tstruct acpi_resource_generic_register generic_reg;\n\tstruct acpi_resource_gpio gpio;\n\tstruct acpi_resource_i2c_serialbus i2c_serial_bus;\n\tstruct acpi_resource_spi_serialbus spi_serial_bus;\n\tstruct acpi_resource_uart_serialbus uart_serial_bus;\n\tstruct acpi_resource_csi2_serialbus csi2_serial_bus;\n\tstruct acpi_resource_common_serialbus common_serial_bus;\n\tstruct acpi_resource_pin_function pin_function;\n\tstruct acpi_resource_pin_config pin_config;\n\tstruct acpi_resource_pin_group pin_group;\n\tstruct acpi_resource_pin_group_function pin_group_function;\n\tstruct acpi_resource_pin_group_config pin_group_config;\n\tstruct acpi_resource_address address;\n};\n\nstruct acpi_resource {\n\tu32 type;\n\tu32 length;\n\tunion acpi_resource_data data;\n} __attribute__((packed));\n\ntypedef acpi_status (*acpi_walk_resource_callback)(struct acpi_resource *, void *);\n\nstruct acpi_gpiolib_dmi_quirk {\n\tbool no_edge_events_on_boot;\n\tchar *ignore_wake;\n};\n\nstruct acpi_gpio_event {\n\tstruct list_head node;\n\tacpi_handle handle;\n\tirq_handler_t handler;\n\tunsigned int pin;\n\tunsigned int irq;\n\tlong unsigned int irqflags;\n\tbool irq_is_wake;\n\tbool irq_requested;\n\tstruct gpio_desc___2 *desc;\n};\n\nstruct acpi_gpio_connection {\n\tstruct list_head node;\n\tunsigned int pin;\n\tstruct gpio_desc___2 *desc;\n};\n\nstruct acpi_gpio_chip {\n\tstruct acpi_connection_info conn_info;\n\tstruct list_head conns;\n\tstruct mutex conn_lock;\n\tstruct gpio_chip *chip;\n\tstruct list_head events;\n\tstruct list_head deferred_req_irqs_list_entry;\n};\n\nstruct acpi_gpio_lookup {\n\tstruct acpi_gpio_info info;\n\tint index;\n\tu16 pin_index;\n\tbool active_low;\n\tstruct gpio_desc___2 *desc;\n\tint n;\n};\n\nstruct extcon_dev;\n\nstruct regulator_dev;\n\nstruct regulator_ops {\n\tint (*list_voltage)(struct regulator_dev *, unsigned int);\n\tint (*set_voltage)(struct regulator_dev *, int, int, unsigned int *);\n\tint (*map_voltage)(struct regulator_dev *, int, int);\n\tint (*set_voltage_sel)(struct regulator_dev *, unsigned int);\n\tint (*get_voltage)(struct regulator_dev *);\n\tint (*get_voltage_sel)(struct regulator_dev *);\n\tint (*set_current_limit)(struct regulator_dev *, int, int);\n\tint (*get_current_limit)(struct regulator_dev *);\n\tint (*set_input_current_limit)(struct regulator_dev *, int);\n\tint (*set_over_current_protection)(struct regulator_dev *, int, int, bool);\n\tint (*set_over_voltage_protection)(struct regulator_dev *, int, int, bool);\n\tint (*set_under_voltage_protection)(struct regulator_dev *, int, int, bool);\n\tint (*set_thermal_protection)(struct regulator_dev *, int, int, bool);\n\tint (*set_active_discharge)(struct regulator_dev *, bool);\n\tint (*enable)(struct regulator_dev *);\n\tint (*disable)(struct regulator_dev *);\n\tint (*is_enabled)(struct regulator_dev *);\n\tint (*set_mode)(struct regulator_dev *, unsigned int);\n\tunsigned int (*get_mode)(struct regulator_dev *);\n\tint (*get_error_flags)(struct regulator_dev *, unsigned int *);\n\tint (*enable_time)(struct regulator_dev *);\n\tint (*set_ramp_delay)(struct regulator_dev *, int);\n\tint (*set_voltage_time)(struct regulator_dev *, int, int);\n\tint (*set_voltage_time_sel)(struct regulator_dev *, unsigned int, unsigned int);\n\tint (*set_soft_start)(struct regulator_dev *);\n\tint (*get_status)(struct regulator_dev *);\n\tunsigned int (*get_optimum_mode)(struct regulator_dev *, int, int, int);\n\tint (*set_load)(struct regulator_dev *, int);\n\tint (*set_bypass)(struct regulator_dev *, bool);\n\tint (*get_bypass)(struct regulator_dev *, bool *);\n\tint (*set_suspend_voltage)(struct regulator_dev *, int);\n\tint (*set_suspend_enable)(struct regulator_dev *);\n\tint (*set_suspend_disable)(struct regulator_dev *);\n\tint (*set_suspend_mode)(struct regulator_dev *, unsigned int);\n\tint (*resume)(struct regulator_dev *);\n\tint (*set_pull_down)(struct regulator_dev *);\n};\n\nstruct regulator_coupler;\n\nstruct coupling_desc {\n\tstruct regulator_dev **coupled_rdevs;\n\tstruct regulator_coupler *coupler;\n\tint n_resolved;\n\tint n_coupled;\n};\n\nstruct regulator_desc;\n\nstruct regulation_constraints;\n\nstruct regulator_enable_gpio;\n\nstruct regulator_dev {\n\tconst struct regulator_desc *desc;\n\tint exclusive;\n\tu32 use_count;\n\tu32 open_count;\n\tu32 bypass_count;\n\tstruct list_head list;\n\tstruct list_head consumer_list;\n\tstruct coupling_desc coupling_desc;\n\tstruct blocking_notifier_head notifier;\n\tstruct ww_mutex mutex;\n\tstruct task_struct *mutex_owner;\n\tint ref_cnt;\n\tstruct module *owner;\n\tstruct device dev;\n\tstruct regulation_constraints *constraints;\n\tstruct regulator *supply;\n\tconst char *supply_name;\n\tstruct regmap *regmap;\n\tstruct delayed_work disable_work;\n\tvoid *reg_data;\n\tstruct dentry *debugfs;\n\tstruct regulator_enable_gpio *ena_pin;\n\tunsigned int ena_gpio_state: 1;\n\tunsigned int is_switch: 1;\n\tktime_t last_off;\n\tint cached_err;\n\tbool use_cached_err;\n\tspinlock_t err_lock;\n};\n\nenum regulator_type {\n\tREGULATOR_VOLTAGE = 0,\n\tREGULATOR_CURRENT = 1,\n};\n\nstruct regulator_config;\n\nstruct regulator_desc {\n\tconst char *name;\n\tconst char *supply_name;\n\tconst char *of_match;\n\tbool of_match_full_name;\n\tconst char *regulators_node;\n\tint (*of_parse_cb)(struct device_node *, const struct regulator_desc *, struct regulator_config *);\n\tint id;\n\tunsigned int continuous_voltage_range: 1;\n\tunsigned int n_voltages;\n\tunsigned int n_current_limits;\n\tconst struct regulator_ops *ops;\n\tint irq;\n\tenum regulator_type type;\n\tstruct module *owner;\n\tunsigned int min_uV;\n\tunsigned int uV_step;\n\tunsigned int linear_min_sel;\n\tint fixed_uV;\n\tunsigned int ramp_delay;\n\tint min_dropout_uV;\n\tconst struct linear_range *linear_ranges;\n\tconst unsigned int *linear_range_selectors;\n\tint n_linear_ranges;\n\tconst unsigned int *volt_table;\n\tconst unsigned int *curr_table;\n\tunsigned int vsel_range_reg;\n\tunsigned int vsel_range_mask;\n\tunsigned int vsel_reg;\n\tunsigned int vsel_mask;\n\tunsigned int vsel_step;\n\tunsigned int csel_reg;\n\tunsigned int csel_mask;\n\tunsigned int apply_reg;\n\tunsigned int apply_bit;\n\tunsigned int enable_reg;\n\tunsigned int enable_mask;\n\tunsigned int enable_val;\n\tunsigned int disable_val;\n\tbool enable_is_inverted;\n\tunsigned int bypass_reg;\n\tunsigned int bypass_mask;\n\tunsigned int bypass_val_on;\n\tunsigned int bypass_val_off;\n\tunsigned int active_discharge_on;\n\tunsigned int active_discharge_off;\n\tunsigned int active_discharge_mask;\n\tunsigned int active_discharge_reg;\n\tunsigned int soft_start_reg;\n\tunsigned int soft_start_mask;\n\tunsigned int soft_start_val_on;\n\tunsigned int pull_down_reg;\n\tunsigned int pull_down_mask;\n\tunsigned int pull_down_val_on;\n\tunsigned int ramp_reg;\n\tunsigned int ramp_mask;\n\tconst unsigned int *ramp_delay_table;\n\tunsigned int n_ramp_values;\n\tunsigned int enable_time;\n\tunsigned int off_on_delay;\n\tunsigned int poll_enabled_time;\n\tunsigned int (*of_map_mode)(unsigned int);\n};\n\nstruct regulator_init_data;\n\nstruct regulator_config {\n\tstruct device *dev;\n\tconst struct regulator_init_data *init_data;\n\tvoid *driver_data;\n\tstruct device_node *of_node;\n\tstruct regmap *regmap;\n\tstruct gpio_desc *ena_gpiod;\n};\n\nstruct regulator_state {\n\tint uV;\n\tint min_uV;\n\tint max_uV;\n\tunsigned int mode;\n\tint enabled;\n\tbool changeable;\n};\n\nstruct notification_limit {\n\tint prot;\n\tint err;\n\tint warn;\n};\n\nstruct regulation_constraints {\n\tconst char *name;\n\tint min_uV;\n\tint max_uV;\n\tint uV_offset;\n\tint min_uA;\n\tint max_uA;\n\tint ilim_uA;\n\tint system_load;\n\tu32 *max_spread;\n\tint max_uV_step;\n\tunsigned int valid_modes_mask;\n\tunsigned int valid_ops_mask;\n\tint input_uV;\n\tstruct regulator_state state_disk;\n\tstruct regulator_state state_mem;\n\tstruct regulator_state state_standby;\n\tstruct notification_limit over_curr_limits;\n\tstruct notification_limit over_voltage_limits;\n\tstruct notification_limit under_voltage_limits;\n\tstruct notification_limit temp_limits;\n\tsuspend_state_t initial_state;\n\tunsigned int initial_mode;\n\tunsigned int ramp_delay;\n\tunsigned int settling_time;\n\tunsigned int settling_time_up;\n\tunsigned int settling_time_down;\n\tunsigned int enable_time;\n\tunsigned int active_discharge;\n\tunsigned int always_on: 1;\n\tunsigned int boot_on: 1;\n\tunsigned int apply_uV: 1;\n\tunsigned int ramp_disable: 1;\n\tunsigned int soft_start: 1;\n\tunsigned int pull_down: 1;\n\tunsigned int over_current_protection: 1;\n\tunsigned int over_current_detection: 1;\n\tunsigned int over_voltage_detection: 1;\n\tunsigned int under_voltage_detection: 1;\n\tunsigned int over_temp_detection: 1;\n};\n\nstruct regulator_consumer_supply;\n\nstruct regulator_init_data {\n\tconst char *supply_regulator;\n\tstruct regulation_constraints constraints;\n\tint num_consumer_supplies;\n\tstruct regulator_consumer_supply *consumer_supplies;\n\tint (*regulator_init)(void *);\n\tvoid *driver_data;\n};\n\nenum palmas_usb_state {\n\tPALMAS_USB_STATE_DISCONNECT = 0,\n\tPALMAS_USB_STATE_VBUS = 1,\n\tPALMAS_USB_STATE_ID = 2,\n};\n\nstruct regmap_irq_chip_data;\n\nstruct palmas_gpadc;\n\nstruct palmas_pmic_driver_data;\n\nstruct palmas_pmic;\n\nstruct palmas_resource;\n\nstruct palmas_usb;\n\nstruct palmas {\n\tstruct device *dev;\n\tstruct i2c_client *i2c_clients[3];\n\tstruct regmap *regmap[3];\n\tint id;\n\tunsigned int features;\n\tint irq;\n\tu32 irq_mask;\n\tstruct mutex irq_lock;\n\tstruct regmap_irq_chip_data *irq_data;\n\tstruct palmas_pmic_driver_data *pmic_ddata;\n\tstruct palmas_pmic *pmic;\n\tstruct palmas_gpadc *gpadc;\n\tstruct palmas_resource *resource;\n\tstruct palmas_usb *usb;\n\tu8 gpio_muxed;\n\tu8 led_muxed;\n\tu8 pwm_muxed;\n};\n\nstruct of_regulator_match;\n\nstruct palmas_regs_info;\n\nstruct palmas_sleep_requestor_info;\n\nstruct palmas_pmic_platform_data;\n\nstruct palmas_pmic_driver_data {\n\tint smps_start;\n\tint smps_end;\n\tint ldo_begin;\n\tint ldo_end;\n\tint max_reg;\n\tbool has_regen3;\n\tstruct palmas_regs_info *palmas_regs_info;\n\tstruct of_regulator_match *palmas_matches;\n\tstruct palmas_sleep_requestor_info *sleep_req_info;\n\tint (*smps_register)(struct palmas_pmic *, struct palmas_pmic_driver_data *, struct palmas_pmic_platform_data *, const char *, struct regulator_config);\n\tint (*ldo_register)(struct palmas_pmic *, struct palmas_pmic_driver_data *, struct palmas_pmic_platform_data *, const char *, struct regulator_config);\n};\n\nstruct palmas_pmic {\n\tstruct palmas *palmas;\n\tstruct device *dev;\n\tstruct regulator_desc desc[27];\n\tstruct mutex mutex;\n\tint smps123;\n\tint smps457;\n\tint smps12;\n\tint range[10];\n\tunsigned int ramp_delay[10];\n\tunsigned int current_reg_mode[10];\n};\n\nstruct palmas_resource {\n\tstruct palmas *palmas;\n\tstruct device *dev;\n};\n\nstruct palmas_usb {\n\tstruct palmas *palmas;\n\tstruct device *dev;\n\tstruct extcon_dev *edev;\n\tint id_otg_irq;\n\tint id_irq;\n\tint vbus_otg_irq;\n\tint vbus_irq;\n\tint gpio_id_irq;\n\tint gpio_vbus_irq;\n\tstruct gpio_desc *id_gpiod;\n\tstruct gpio_desc *vbus_gpiod;\n\tlong unsigned int sw_debounce_jiffies;\n\tstruct delayed_work wq_detectid;\n\tenum palmas_usb_state linkstat;\n\tint wakeup;\n\tbool enable_vbus_detection;\n\tbool enable_id_detection;\n\tbool enable_gpio_id_detection;\n\tbool enable_gpio_vbus_detection;\n};\n\nstruct palmas_sleep_requestor_info {\n\tint id;\n\tint reg_offset;\n\tint bit_pos;\n};\n\nstruct palmas_regs_info {\n\tchar *name;\n\tchar *sname;\n\tu8 vsel_addr;\n\tu8 ctrl_addr;\n\tu8 tstep_addr;\n\tint sleep_id;\n};\n\nstruct palmas_reg_init;\n\nstruct palmas_pmic_platform_data {\n\tstruct regulator_init_data *reg_data[27];\n\tstruct palmas_reg_init *reg_init[27];\n\tint ldo6_vibrator;\n\tbool enable_ldo8_tracking;\n};\n\nstruct palmas_adc_wakeup_property {\n\tint adc_channel_number;\n\tint adc_high_threshold;\n\tint adc_low_threshold;\n};\n\nstruct palmas_gpadc_platform_data {\n\tint ch3_current;\n\tint ch0_current;\n\tbool extended_delay;\n\tint bat_removal;\n\tint start_polarity;\n\tint auto_conversion_period_ms;\n\tstruct palmas_adc_wakeup_property *adc_wakeup1_data;\n\tstruct palmas_adc_wakeup_property *adc_wakeup2_data;\n};\n\nstruct palmas_reg_init {\n\tint warm_reset;\n\tint roof_floor;\n\tint mode_sleep;\n\tu8 vsel;\n};\n\nenum palmas_regulators {\n\tPALMAS_REG_SMPS12 = 0,\n\tPALMAS_REG_SMPS123 = 1,\n\tPALMAS_REG_SMPS3 = 2,\n\tPALMAS_REG_SMPS45 = 3,\n\tPALMAS_REG_SMPS457 = 4,\n\tPALMAS_REG_SMPS6 = 5,\n\tPALMAS_REG_SMPS7 = 6,\n\tPALMAS_REG_SMPS8 = 7,\n\tPALMAS_REG_SMPS9 = 8,\n\tPALMAS_REG_SMPS10_OUT2 = 9,\n\tPALMAS_REG_SMPS10_OUT1 = 10,\n\tPALMAS_REG_LDO1 = 11,\n\tPALMAS_REG_LDO2 = 12,\n\tPALMAS_REG_LDO3 = 13,\n\tPALMAS_REG_LDO4 = 14,\n\tPALMAS_REG_LDO5 = 15,\n\tPALMAS_REG_LDO6 = 16,\n\tPALMAS_REG_LDO7 = 17,\n\tPALMAS_REG_LDO8 = 18,\n\tPALMAS_REG_LDO9 = 19,\n\tPALMAS_REG_LDOLN = 20,\n\tPALMAS_REG_LDOUSB = 21,\n\tPALMAS_REG_REGEN1 = 22,\n\tPALMAS_REG_REGEN2 = 23,\n\tPALMAS_REG_REGEN3 = 24,\n\tPALMAS_REG_SYSEN1 = 25,\n\tPALMAS_REG_SYSEN2 = 26,\n\tPALMAS_NUM_REGS = 27,\n};\n\nstruct palmas_usb_platform_data {\n\tint wakeup;\n};\n\nstruct palmas_resource_platform_data {\n\tint regen1_mode_sleep;\n\tint regen2_mode_sleep;\n\tint sysen1_mode_sleep;\n\tint sysen2_mode_sleep;\n\tu8 nsleep_res;\n\tu8 nsleep_smps;\n\tu8 nsleep_ldo1;\n\tu8 nsleep_ldo2;\n\tu8 enable1_res;\n\tu8 enable1_smps;\n\tu8 enable1_ldo1;\n\tu8 enable1_ldo2;\n\tu8 enable2_res;\n\tu8 enable2_smps;\n\tu8 enable2_ldo1;\n\tu8 enable2_ldo2;\n};\n\nstruct palmas_clk_platform_data {\n\tint clk32kg_mode_sleep;\n\tint clk32kgaudio_mode_sleep;\n};\n\nstruct palmas_platform_data {\n\tint irq_flags;\n\tint gpio_base;\n\tu8 power_ctrl;\n\tint mux_from_pdata;\n\tu8 pad1;\n\tu8 pad2;\n\tbool pm_off;\n\tstruct palmas_pmic_platform_data *pmic_pdata;\n\tstruct palmas_gpadc_platform_data *gpadc_pdata;\n\tstruct palmas_usb_platform_data *usb_pdata;\n\tstruct palmas_resource_platform_data *resource_pdata;\n\tstruct palmas_clk_platform_data *clk_pdata;\n};\n\nenum palmas_irqs {\n\tPALMAS_CHARG_DET_N_VBUS_OVV_IRQ = 0,\n\tPALMAS_PWRON_IRQ = 1,\n\tPALMAS_LONG_PRESS_KEY_IRQ = 2,\n\tPALMAS_RPWRON_IRQ = 3,\n\tPALMAS_PWRDOWN_IRQ = 4,\n\tPALMAS_HOTDIE_IRQ = 5,\n\tPALMAS_VSYS_MON_IRQ = 6,\n\tPALMAS_VBAT_MON_IRQ = 7,\n\tPALMAS_RTC_ALARM_IRQ = 8,\n\tPALMAS_RTC_TIMER_IRQ = 9,\n\tPALMAS_WDT_IRQ = 10,\n\tPALMAS_BATREMOVAL_IRQ = 11,\n\tPALMAS_RESET_IN_IRQ = 12,\n\tPALMAS_FBI_BB_IRQ = 13,\n\tPALMAS_SHORT_IRQ = 14,\n\tPALMAS_VAC_ACOK_IRQ = 15,\n\tPALMAS_GPADC_AUTO_0_IRQ = 16,\n\tPALMAS_GPADC_AUTO_1_IRQ = 17,\n\tPALMAS_GPADC_EOC_SW_IRQ = 18,\n\tPALMAS_GPADC_EOC_RT_IRQ = 19,\n\tPALMAS_ID_OTG_IRQ = 20,\n\tPALMAS_ID_IRQ = 21,\n\tPALMAS_VBUS_OTG_IRQ = 22,\n\tPALMAS_VBUS_IRQ = 23,\n\tPALMAS_GPIO_0_IRQ = 24,\n\tPALMAS_GPIO_1_IRQ = 25,\n\tPALMAS_GPIO_2_IRQ = 26,\n\tPALMAS_GPIO_3_IRQ = 27,\n\tPALMAS_GPIO_4_IRQ = 28,\n\tPALMAS_GPIO_5_IRQ = 29,\n\tPALMAS_GPIO_6_IRQ = 30,\n\tPALMAS_GPIO_7_IRQ = 31,\n\tPALMAS_NUM_IRQ = 32,\n};\n\nstruct palmas_gpio {\n\tstruct gpio_chip gpio_chip;\n\tstruct palmas *palmas;\n};\n\nstruct palmas_device_data {\n\tint ngpio;\n};\n\nenum {\n\tRC5T583_IRQ_ONKEY = 0,\n\tRC5T583_IRQ_ACOK = 1,\n\tRC5T583_IRQ_LIDOPEN = 2,\n\tRC5T583_IRQ_PREOT = 3,\n\tRC5T583_IRQ_CLKSTP = 4,\n\tRC5T583_IRQ_ONKEY_OFF = 5,\n\tRC5T583_IRQ_WD = 6,\n\tRC5T583_IRQ_EN_PWRREQ1 = 7,\n\tRC5T583_IRQ_EN_PWRREQ2 = 8,\n\tRC5T583_IRQ_PRE_VINDET = 9,\n\tRC5T583_IRQ_DC0LIM = 10,\n\tRC5T583_IRQ_DC1LIM = 11,\n\tRC5T583_IRQ_DC2LIM = 12,\n\tRC5T583_IRQ_DC3LIM = 13,\n\tRC5T583_IRQ_CTC = 14,\n\tRC5T583_IRQ_YALE = 15,\n\tRC5T583_IRQ_DALE = 16,\n\tRC5T583_IRQ_WALE = 17,\n\tRC5T583_IRQ_AIN1L = 18,\n\tRC5T583_IRQ_AIN2L = 19,\n\tRC5T583_IRQ_AIN3L = 20,\n\tRC5T583_IRQ_VBATL = 21,\n\tRC5T583_IRQ_VIN3L = 22,\n\tRC5T583_IRQ_VIN8L = 23,\n\tRC5T583_IRQ_AIN1H = 24,\n\tRC5T583_IRQ_AIN2H = 25,\n\tRC5T583_IRQ_AIN3H = 26,\n\tRC5T583_IRQ_VBATH = 27,\n\tRC5T583_IRQ_VIN3H = 28,\n\tRC5T583_IRQ_VIN8H = 29,\n\tRC5T583_IRQ_ADCEND = 30,\n\tRC5T583_IRQ_GPIO0 = 31,\n\tRC5T583_IRQ_GPIO1 = 32,\n\tRC5T583_IRQ_GPIO2 = 33,\n\tRC5T583_IRQ_GPIO3 = 34,\n\tRC5T583_IRQ_GPIO4 = 35,\n\tRC5T583_IRQ_GPIO5 = 36,\n\tRC5T583_IRQ_GPIO6 = 37,\n\tRC5T583_IRQ_GPIO7 = 38,\n\tRC5T583_MAX_IRQS = 39,\n};\n\nenum {\n\tRC5T583_GPIO0 = 0,\n\tRC5T583_GPIO1 = 1,\n\tRC5T583_GPIO2 = 2,\n\tRC5T583_GPIO3 = 3,\n\tRC5T583_GPIO4 = 4,\n\tRC5T583_GPIO5 = 5,\n\tRC5T583_GPIO6 = 6,\n\tRC5T583_GPIO7 = 7,\n\tRC5T583_MAX_GPIO = 8,\n};\n\nenum {\n\tRC5T583_REGULATOR_DC0 = 0,\n\tRC5T583_REGULATOR_DC1 = 1,\n\tRC5T583_REGULATOR_DC2 = 2,\n\tRC5T583_REGULATOR_DC3 = 3,\n\tRC5T583_REGULATOR_LDO0 = 4,\n\tRC5T583_REGULATOR_LDO1 = 5,\n\tRC5T583_REGULATOR_LDO2 = 6,\n\tRC5T583_REGULATOR_LDO3 = 7,\n\tRC5T583_REGULATOR_LDO4 = 8,\n\tRC5T583_REGULATOR_LDO5 = 9,\n\tRC5T583_REGULATOR_LDO6 = 10,\n\tRC5T583_REGULATOR_LDO7 = 11,\n\tRC5T583_REGULATOR_LDO8 = 12,\n\tRC5T583_REGULATOR_LDO9 = 13,\n\tRC5T583_REGULATOR_MAX = 14,\n};\n\nstruct rc5t583 {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tint chip_irq;\n\tint irq_base;\n\tstruct mutex irq_lock;\n\tlong unsigned int group_irq_en[5];\n\tuint8_t intc_inten_reg;\n\tuint8_t irq_en_reg[8];\n\tuint8_t gpedge_reg[2];\n};\n\nstruct rc5t583_platform_data {\n\tint irq_base;\n\tint gpio_base;\n\tbool enable_shutdown;\n\tint regulator_deepsleep_slot[14];\n\tlong unsigned int regulator_ext_pwr_control[14];\n\tstruct regulator_init_data *reg_init_data[14];\n};\n\nstruct rc5t583_gpio {\n\tstruct gpio_chip gpio_chip;\n\tstruct rc5t583 *rc5t583;\n};\n\nenum {\n\tTPS6586X_ID_SYS = 0,\n\tTPS6586X_ID_SM_0 = 1,\n\tTPS6586X_ID_SM_1 = 2,\n\tTPS6586X_ID_SM_2 = 3,\n\tTPS6586X_ID_LDO_0 = 4,\n\tTPS6586X_ID_LDO_1 = 5,\n\tTPS6586X_ID_LDO_2 = 6,\n\tTPS6586X_ID_LDO_3 = 7,\n\tTPS6586X_ID_LDO_4 = 8,\n\tTPS6586X_ID_LDO_5 = 9,\n\tTPS6586X_ID_LDO_6 = 10,\n\tTPS6586X_ID_LDO_7 = 11,\n\tTPS6586X_ID_LDO_8 = 12,\n\tTPS6586X_ID_LDO_9 = 13,\n\tTPS6586X_ID_LDO_RTC = 14,\n\tTPS6586X_ID_MAX_REGULATOR = 15,\n};\n\nenum {\n\tTPS6586X_INT_PLDO_0 = 0,\n\tTPS6586X_INT_PLDO_1 = 1,\n\tTPS6586X_INT_PLDO_2 = 2,\n\tTPS6586X_INT_PLDO_3 = 3,\n\tTPS6586X_INT_PLDO_4 = 4,\n\tTPS6586X_INT_PLDO_5 = 5,\n\tTPS6586X_INT_PLDO_6 = 6,\n\tTPS6586X_INT_PLDO_7 = 7,\n\tTPS6586X_INT_COMP_DET = 8,\n\tTPS6586X_INT_ADC = 9,\n\tTPS6586X_INT_PLDO_8 = 10,\n\tTPS6586X_INT_PLDO_9 = 11,\n\tTPS6586X_INT_PSM_0 = 12,\n\tTPS6586X_INT_PSM_1 = 13,\n\tTPS6586X_INT_PSM_2 = 14,\n\tTPS6586X_INT_PSM_3 = 15,\n\tTPS6586X_INT_RTC_ALM1 = 16,\n\tTPS6586X_INT_ACUSB_OVP = 17,\n\tTPS6586X_INT_USB_DET = 18,\n\tTPS6586X_INT_AC_DET = 19,\n\tTPS6586X_INT_BAT_DET = 20,\n\tTPS6586X_INT_CHG_STAT = 21,\n\tTPS6586X_INT_CHG_TEMP = 22,\n\tTPS6586X_INT_PP = 23,\n\tTPS6586X_INT_RESUME = 24,\n\tTPS6586X_INT_LOW_SYS = 25,\n\tTPS6586X_INT_RTC_ALM2 = 26,\n};\n\nstruct tps6586x_subdev_info {\n\tint id;\n\tconst char *name;\n\tvoid *platform_data;\n\tstruct device_node *of_node;\n};\n\nstruct tps6586x_platform_data {\n\tint num_subdevs;\n\tstruct tps6586x_subdev_info *subdevs;\n\tint gpio_base;\n\tint irq_base;\n\tbool pm_off;\n\tstruct regulator_init_data *reg_init_data[15];\n};\n\nstruct tps6586x_gpio {\n\tstruct gpio_chip gpio_chip;\n\tstruct device *parent;\n};\n\nstruct tps65910_sleep_keepon_data {\n\tunsigned int therm_keepon: 1;\n\tunsigned int clkout32k_keepon: 1;\n\tunsigned int i2chs_keepon: 1;\n};\n\nstruct tps65910_board {\n\tint gpio_base;\n\tint irq;\n\tint irq_base;\n\tint vmbch_threshold;\n\tint vmbch2_threshold;\n\tbool en_ck32k_xtal;\n\tbool en_dev_slp;\n\tbool pm_off;\n\tstruct tps65910_sleep_keepon_data slp_keepon;\n\tbool en_gpio_sleep[9];\n\tlong unsigned int regulator_ext_sleep_control[14];\n\tstruct regulator_init_data *tps65910_pmic_init_data[14];\n};\n\nstruct tps65910 {\n\tstruct device *dev;\n\tstruct i2c_client *i2c_client;\n\tstruct regmap *regmap;\n\tlong unsigned int id;\n\tstruct tps65910_board *of_plat_data;\n\tint chip_irq;\n\tstruct regmap_irq_chip_data *irq_data;\n};\n\nstruct tps65910_gpio {\n\tstruct gpio_chip gpio_chip;\n\tstruct tps65910 *tps65910;\n};\n\nstruct tps68470_gpio_data {\n\tstruct regmap *tps68470_regmap;\n\tstruct gpio_chip gc;\n};\n\nenum pwm_polarity {\n\tPWM_POLARITY_NORMAL = 0,\n\tPWM_POLARITY_INVERSED = 1,\n};\n\nstruct pwm_args {\n\tu64 period;\n\tenum pwm_polarity polarity;\n};\n\nenum {\n\tPWMF_REQUESTED = 1,\n\tPWMF_EXPORTED = 2,\n};\n\nstruct pwm_state {\n\tu64 period;\n\tu64 duty_cycle;\n\tenum pwm_polarity polarity;\n\tbool enabled;\n\tbool usage_power;\n};\n\nstruct pwm_chip;\n\nstruct pwm_device {\n\tconst char *label;\n\tlong unsigned int flags;\n\tunsigned int hwpwm;\n\tunsigned int pwm;\n\tstruct pwm_chip *chip;\n\tvoid *chip_data;\n\tstruct pwm_args args;\n\tstruct pwm_state state;\n\tstruct pwm_state last;\n};\n\nstruct pwm_ops;\n\nstruct pwm_chip {\n\tstruct device *dev;\n\tconst struct pwm_ops *ops;\n\tint base;\n\tunsigned int npwm;\n\tstruct pwm_device * (*of_xlate)(struct pwm_chip *, const struct of_phandle_args *);\n\tunsigned int of_pwm_n_cells;\n\tstruct list_head list;\n\tstruct pwm_device *pwms;\n};\n\nstruct pwm_capture;\n\nstruct pwm_ops {\n\tint (*request)(struct pwm_chip *, struct pwm_device *);\n\tvoid (*free)(struct pwm_chip *, struct pwm_device *);\n\tint (*capture)(struct pwm_chip *, struct pwm_device *, struct pwm_capture *, long unsigned int);\n\tint (*apply)(struct pwm_chip *, struct pwm_device *, const struct pwm_state *);\n\tvoid (*get_state)(struct pwm_chip *, struct pwm_device *, struct pwm_state *);\n\tstruct module *owner;\n\tint (*config)(struct pwm_chip *, struct pwm_device *, int, int);\n\tint (*set_polarity)(struct pwm_chip *, struct pwm_device *, enum pwm_polarity);\n\tint (*enable)(struct pwm_chip *, struct pwm_device *);\n\tvoid (*disable)(struct pwm_chip *, struct pwm_device *);\n};\n\nstruct pwm_capture {\n\tunsigned int period;\n\tunsigned int duty_cycle;\n};\n\nstruct pwm_lookup {\n\tstruct list_head list;\n\tconst char *provider;\n\tunsigned int index;\n\tconst char *dev_id;\n\tconst char *con_id;\n\tunsigned int period;\n\tenum pwm_polarity polarity;\n\tconst char *module;\n};\n\nstruct trace_event_raw_pwm {\n\tstruct trace_entry ent;\n\tstruct pwm_device *pwm;\n\tu64 period;\n\tu64 duty_cycle;\n\tenum pwm_polarity polarity;\n\tbool enabled;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_pwm {};\n\ntypedef void (*btf_trace_pwm_apply)(void *, struct pwm_device *, const struct pwm_state *);\n\ntypedef void (*btf_trace_pwm_get)(void *, struct pwm_device *, const struct pwm_state *);\n\nstruct pwm_export {\n\tstruct device child;\n\tstruct pwm_device *pwm;\n\tstruct mutex lock;\n\tstruct pwm_state suspend;\n};\n\nstruct intel_scu_ipc_dev;\n\nstruct intel_soc_pmic {\n\tint irq;\n\tstruct regmap *regmap;\n\tstruct regmap_irq_chip_data *irq_chip_data;\n\tstruct regmap_irq_chip_data *irq_chip_data_pwrbtn;\n\tstruct regmap_irq_chip_data *irq_chip_data_tmu;\n\tstruct regmap_irq_chip_data *irq_chip_data_bcu;\n\tstruct regmap_irq_chip_data *irq_chip_data_adc;\n\tstruct regmap_irq_chip_data *irq_chip_data_chgr;\n\tstruct regmap_irq_chip_data *irq_chip_data_crit;\n\tstruct device *dev;\n\tstruct intel_scu_ipc_dev *scu;\n};\n\nstruct crystalcove_pwm {\n\tstruct pwm_chip chip;\n\tstruct regmap *regmap;\n};\n\nenum {\n\tpci_channel_io_normal = 1,\n\tpci_channel_io_frozen = 2,\n\tpci_channel_io_perm_failure = 3,\n};\n\nstruct pci_sriov {\n\tint pos;\n\tint nres;\n\tu32 cap;\n\tu16 ctrl;\n\tu16 total_VFs;\n\tu16 initial_VFs;\n\tu16 num_VFs;\n\tu16 offset;\n\tu16 stride;\n\tu16 vf_device;\n\tu32 pgsz;\n\tu8 link;\n\tu8 max_VF_buses;\n\tu16 driver_max_VFs;\n\tstruct pci_dev *dev;\n\tstruct pci_dev *self;\n\tu32 class;\n\tu8 hdr_type;\n\tu16 subsystem_vendor;\n\tu16 subsystem_device;\n\tresource_size_t barsz[6];\n\tbool drivers_autoprobe;\n};\n\nstruct rcec_ea {\n\tu8 nextbusn;\n\tu8 lastbusn;\n\tu32 bitmap;\n};\n\nstruct pci_bus_resource {\n\tstruct list_head list;\n\tstruct resource *res;\n\tunsigned int flags;\n};\n\ntypedef u64 pci_bus_addr_t;\n\nstruct pci_bus_region {\n\tpci_bus_addr_t start;\n\tpci_bus_addr_t end;\n};\n\nenum pci_fixup_pass {\n\tpci_fixup_early = 0,\n\tpci_fixup_header = 1,\n\tpci_fixup_final = 2,\n\tpci_fixup_enable = 3,\n\tpci_fixup_resume = 4,\n\tpci_fixup_suspend = 5,\n\tpci_fixup_resume_early = 6,\n\tpci_fixup_suspend_late = 7,\n};\n\nstruct hotplug_slot_ops;\n\nstruct hotplug_slot {\n\tconst struct hotplug_slot_ops *ops;\n\tstruct list_head slot_list;\n\tstruct pci_slot *pci_slot;\n\tstruct module *owner;\n\tconst char *mod_name;\n};\n\nenum pci_dev_flags {\n\tPCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = 1,\n\tPCI_DEV_FLAGS_NO_D3 = 2,\n\tPCI_DEV_FLAGS_ASSIGNED = 4,\n\tPCI_DEV_FLAGS_ACS_ENABLED_QUIRK = 8,\n\tPCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = 32,\n\tPCI_DEV_FLAGS_NO_BUS_RESET = 64,\n\tPCI_DEV_FLAGS_NO_PM_RESET = 128,\n\tPCI_DEV_FLAGS_VPD_REF_F0 = 256,\n\tPCI_DEV_FLAGS_BRIDGE_XLATE_ROOT = 512,\n\tPCI_DEV_FLAGS_NO_FLR_RESET = 1024,\n\tPCI_DEV_FLAGS_NO_RELAXED_ORDERING = 2048,\n};\n\nenum pci_bus_flags {\n\tPCI_BUS_FLAGS_NO_MSI = 1,\n\tPCI_BUS_FLAGS_NO_MMRBC = 2,\n\tPCI_BUS_FLAGS_NO_AERSID = 4,\n\tPCI_BUS_FLAGS_NO_EXTCFG = 8,\n};\n\nenum pci_bus_speed {\n\tPCI_SPEED_33MHz = 0,\n\tPCI_SPEED_66MHz = 1,\n\tPCI_SPEED_66MHz_PCIX = 2,\n\tPCI_SPEED_100MHz_PCIX = 3,\n\tPCI_SPEED_133MHz_PCIX = 4,\n\tPCI_SPEED_66MHz_PCIX_ECC = 5,\n\tPCI_SPEED_100MHz_PCIX_ECC = 6,\n\tPCI_SPEED_133MHz_PCIX_ECC = 7,\n\tPCI_SPEED_66MHz_PCIX_266 = 9,\n\tPCI_SPEED_100MHz_PCIX_266 = 10,\n\tPCI_SPEED_133MHz_PCIX_266 = 11,\n\tAGP_UNKNOWN = 12,\n\tAGP_1X = 13,\n\tAGP_2X = 14,\n\tAGP_4X = 15,\n\tAGP_8X = 16,\n\tPCI_SPEED_66MHz_PCIX_533 = 17,\n\tPCI_SPEED_100MHz_PCIX_533 = 18,\n\tPCI_SPEED_133MHz_PCIX_533 = 19,\n\tPCIE_SPEED_2_5GT = 20,\n\tPCIE_SPEED_5_0GT = 21,\n\tPCIE_SPEED_8_0GT = 22,\n\tPCIE_SPEED_16_0GT = 23,\n\tPCIE_SPEED_32_0GT = 24,\n\tPCIE_SPEED_64_0GT = 25,\n\tPCI_SPEED_UNKNOWN = 255,\n};\n\nstruct pci_host_bridge {\n\tstruct device dev;\n\tstruct pci_bus *bus;\n\tstruct pci_ops *ops;\n\tstruct pci_ops *child_ops;\n\tvoid *sysdata;\n\tint busnr;\n\tstruct list_head windows;\n\tstruct list_head dma_ranges;\n\tu8 (*swizzle_irq)(struct pci_dev *, u8 *);\n\tint (*map_irq)(const struct pci_dev *, u8, u8);\n\tvoid (*release_fn)(struct pci_host_bridge *);\n\tvoid *release_data;\n\tunsigned int ignore_reset_delay: 1;\n\tunsigned int no_ext_tags: 1;\n\tunsigned int native_aer: 1;\n\tunsigned int native_pcie_hotplug: 1;\n\tunsigned int native_shpc_hotplug: 1;\n\tunsigned int native_pme: 1;\n\tunsigned int native_ltr: 1;\n\tunsigned int native_dpc: 1;\n\tunsigned int preserve_config: 1;\n\tunsigned int size_windows: 1;\n\tunsigned int msi_domain: 1;\n\tresource_size_t (*align_resource)(struct pci_dev *, const struct resource *, resource_size_t, resource_size_t, resource_size_t);\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong unsigned int private[0];\n};\n\nenum {\n\tPCI_REASSIGN_ALL_RSRC = 1,\n\tPCI_REASSIGN_ALL_BUS = 2,\n\tPCI_PROBE_ONLY = 4,\n\tPCI_CAN_SKIP_ISA_ALIGN = 8,\n\tPCI_ENABLE_PROC_DOMAINS = 16,\n\tPCI_COMPAT_DOMAIN_0 = 32,\n\tPCI_SCAN_ALL_PCIE_DEVS = 64,\n};\n\nenum pcie_bus_config_types {\n\tPCIE_BUS_TUNE_OFF = 0,\n\tPCIE_BUS_DEFAULT = 1,\n\tPCIE_BUS_SAFE = 2,\n\tPCIE_BUS_PERFORMANCE = 3,\n\tPCIE_BUS_PEER2PEER = 4,\n};\n\nstruct hotplug_slot_ops {\n\tint (*enable_slot)(struct hotplug_slot *);\n\tint (*disable_slot)(struct hotplug_slot *);\n\tint (*set_attention_status)(struct hotplug_slot *, u8);\n\tint (*hardware_test)(struct hotplug_slot *, u32);\n\tint (*get_power_status)(struct hotplug_slot *, u8 *);\n\tint (*get_attention_status)(struct hotplug_slot *, u8 *);\n\tint (*get_latch_status)(struct hotplug_slot *, u8 *);\n\tint (*get_adapter_status)(struct hotplug_slot *, u8 *);\n\tint (*reset_slot)(struct hotplug_slot *, int);\n};\n\nenum pci_bar_type {\n\tpci_bar_unknown = 0,\n\tpci_bar_io = 1,\n\tpci_bar_mem32 = 2,\n\tpci_bar_mem64 = 3,\n};\n\nstruct pci_domain_busn_res {\n\tstruct list_head list;\n\tstruct resource res;\n\tint domain_nr;\n};\n\nstruct bus_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct bus_type *, char *);\n\tssize_t (*store)(struct bus_type *, const char *, size_t);\n};\n\nenum pcie_reset_state {\n\tpcie_deassert_reset = 1,\n\tpcie_warm_reset = 2,\n\tpcie_hot_reset = 3,\n};\n\nenum pcie_link_width {\n\tPCIE_LNK_WIDTH_RESRV = 0,\n\tPCIE_LNK_X1 = 1,\n\tPCIE_LNK_X2 = 2,\n\tPCIE_LNK_X4 = 4,\n\tPCIE_LNK_X8 = 8,\n\tPCIE_LNK_X12 = 12,\n\tPCIE_LNK_X16 = 16,\n\tPCIE_LNK_X32 = 32,\n\tPCIE_LNK_WIDTH_UNKNOWN = 255,\n};\n\nstruct pci_cap_saved_data {\n\tu16 cap_nr;\n\tbool cap_extended;\n\tunsigned int size;\n\tu32 data[0];\n};\n\nstruct pci_cap_saved_state {\n\tstruct hlist_node next;\n\tstruct pci_cap_saved_data cap;\n};\n\ntypedef int (*arch_set_vga_state_t)(struct pci_dev *, bool, unsigned int, u32);\n\nstruct pci_platform_pm_ops {\n\tbool (*bridge_d3)(struct pci_dev *);\n\tbool (*is_manageable)(struct pci_dev *);\n\tint (*set_state)(struct pci_dev *, pci_power_t);\n\tpci_power_t (*get_state)(struct pci_dev *);\n\tvoid (*refresh_state)(struct pci_dev *);\n\tpci_power_t (*choose_state)(struct pci_dev *);\n\tint (*set_wakeup)(struct pci_dev *, bool);\n\tbool (*need_resume)(struct pci_dev *);\n};\n\nstruct pci_pme_device {\n\tstruct list_head list;\n\tstruct pci_dev *dev;\n};\n\nstruct pci_saved_state {\n\tu32 config_space[16];\n\tstruct pci_cap_saved_data cap[0];\n};\n\nstruct pci_devres {\n\tunsigned int enabled: 1;\n\tunsigned int pinned: 1;\n\tunsigned int orig_intx: 1;\n\tunsigned int restore_intx: 1;\n\tunsigned int mwi: 1;\n\tu32 region_mask;\n};\n\nstruct driver_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct device_driver *, char *);\n\tssize_t (*store)(struct device_driver *, const char *, size_t);\n};\n\nenum pci_ers_result {\n\tPCI_ERS_RESULT_NONE = 1,\n\tPCI_ERS_RESULT_CAN_RECOVER = 2,\n\tPCI_ERS_RESULT_NEED_RESET = 3,\n\tPCI_ERS_RESULT_DISCONNECT = 4,\n\tPCI_ERS_RESULT_RECOVERED = 5,\n\tPCI_ERS_RESULT_NO_AER_DRIVER = 6,\n};\n\nenum dev_dma_attr {\n\tDEV_DMA_NOT_SUPPORTED = 0,\n\tDEV_DMA_NON_COHERENT = 1,\n\tDEV_DMA_COHERENT = 2,\n};\n\nstruct pcie_device {\n\tint irq;\n\tstruct pci_dev *port;\n\tu32 service;\n\tvoid *priv_data;\n\tstruct device device;\n};\n\nstruct pcie_port_service_driver {\n\tconst char *name;\n\tint (*probe)(struct pcie_device *);\n\tvoid (*remove)(struct pcie_device *);\n\tint (*suspend)(struct pcie_device *);\n\tint (*resume_noirq)(struct pcie_device *);\n\tint (*resume)(struct pcie_device *);\n\tint (*runtime_suspend)(struct pcie_device *);\n\tint (*runtime_resume)(struct pcie_device *);\n\tvoid (*error_resume)(struct pci_dev *);\n\tint port_type;\n\tu32 service;\n\tstruct device_driver driver;\n};\n\nstruct pci_dynid {\n\tstruct list_head node;\n\tstruct pci_device_id id;\n};\n\nstruct drv_dev_and_id {\n\tstruct pci_driver *drv;\n\tstruct pci_dev *dev;\n\tconst struct pci_device_id *id;\n};\n\nenum pci_mmap_state {\n\tpci_mmap_io = 0,\n\tpci_mmap_mem = 1,\n};\n\nenum pci_mmap_api {\n\tPCI_MMAP_SYSFS = 0,\n\tPCI_MMAP_PROCFS = 1,\n};\n\nstruct pci_vpd_ops;\n\nstruct pci_vpd {\n\tconst struct pci_vpd_ops *ops;\n\tstruct mutex lock;\n\tunsigned int len;\n\tu16 flag;\n\tu8 cap;\n\tunsigned int busy: 1;\n\tunsigned int valid: 1;\n};\n\nstruct pci_vpd_ops {\n\tssize_t (*read)(struct pci_dev *, loff_t, size_t, void *);\n\tssize_t (*write)(struct pci_dev *, loff_t, size_t, const void *);\n};\n\nstruct pci_dev_resource {\n\tstruct list_head list;\n\tstruct resource *res;\n\tstruct pci_dev *dev;\n\tresource_size_t start;\n\tresource_size_t end;\n\tresource_size_t add_size;\n\tresource_size_t min_align;\n\tlong unsigned int flags;\n};\n\nenum release_type {\n\tleaf_only = 0,\n\twhole_subtree = 1,\n};\n\nenum enable_type {\n\tundefined = 4294967295,\n\tuser_disabled = 0,\n\tauto_disabled = 1,\n\tuser_enabled = 2,\n\tauto_enabled = 3,\n};\n\nstruct msix_entry {\n\tu32 vector;\n\tu16 entry;\n};\n\nstruct portdrv_service_data {\n\tstruct pcie_port_service_driver *drv;\n\tstruct device *dev;\n\tu32 service;\n};\n\ntypedef int (*pcie_pm_callback_t)(struct pcie_device *);\n\nstruct walk_rcec_data {\n\tstruct pci_dev *rcec;\n\tint (*user_callback)(struct pci_dev *, void *);\n\tvoid *user_data;\n};\n\nstruct aspm_latency {\n\tu32 l0s;\n\tu32 l1;\n};\n\nstruct pcie_link_state {\n\tstruct pci_dev *pdev;\n\tstruct pci_dev *downstream;\n\tstruct pcie_link_state *root;\n\tstruct pcie_link_state *parent;\n\tstruct list_head sibling;\n\tu32 aspm_support: 7;\n\tu32 aspm_enabled: 7;\n\tu32 aspm_capable: 7;\n\tu32 aspm_default: 7;\n\tchar: 4;\n\tu32 aspm_disable: 7;\n\tu32 clkpm_capable: 1;\n\tu32 clkpm_enabled: 1;\n\tu32 clkpm_default: 1;\n\tu32 clkpm_disable: 1;\n\tstruct aspm_latency latency_up;\n\tstruct aspm_latency latency_dw;\n\tstruct aspm_latency acceptable[8];\n};\n\nstruct aer_stats {\n\tu64 dev_cor_errs[16];\n\tu64 dev_fatal_errs[27];\n\tu64 dev_nonfatal_errs[27];\n\tu64 dev_total_cor_errs;\n\tu64 dev_total_fatal_errs;\n\tu64 dev_total_nonfatal_errs;\n\tu64 rootport_total_cor_errs;\n\tu64 rootport_total_fatal_errs;\n\tu64 rootport_total_nonfatal_errs;\n};\n\nstruct aer_header_log_regs {\n\tunsigned int dw0;\n\tunsigned int dw1;\n\tunsigned int dw2;\n\tunsigned int dw3;\n};\n\nstruct aer_capability_regs {\n\tu32 header;\n\tu32 uncor_status;\n\tu32 uncor_mask;\n\tu32 uncor_severity;\n\tu32 cor_status;\n\tu32 cor_mask;\n\tu32 cap_control;\n\tstruct aer_header_log_regs header_log;\n\tu32 root_command;\n\tu32 root_status;\n\tu16 cor_err_source;\n\tu16 uncor_err_source;\n};\n\nstruct aer_err_info {\n\tstruct pci_dev *dev[5];\n\tint error_dev_num;\n\tunsigned int id: 16;\n\tunsigned int severity: 2;\n\tunsigned int __pad1: 5;\n\tunsigned int multi_error_valid: 1;\n\tunsigned int first_error: 5;\n\tunsigned int __pad2: 2;\n\tunsigned int tlp_header_valid: 1;\n\tunsigned int status;\n\tunsigned int mask;\n\tstruct aer_header_log_regs tlp;\n};\n\nstruct aer_err_source {\n\tunsigned int status;\n\tunsigned int id;\n};\n\nstruct aer_rpc {\n\tstruct pci_dev *rpd;\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tstruct aer_err_source *type;\n\t\t\tconst struct aer_err_source *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tstruct aer_err_source *ptr;\n\t\t\tconst struct aer_err_source *ptr_const;\n\t\t};\n\t\tstruct aer_err_source buf[128];\n\t} aer_fifo;\n};\n\nstruct aer_recover_entry {\n\tu8 bus;\n\tu8 devfn;\n\tu16 domain;\n\tint severity;\n\tstruct aer_capability_regs *regs;\n};\n\nstruct pcie_pme_service_data {\n\tspinlock_t lock;\n\tstruct pcie_device *srv;\n\tstruct work_struct work;\n\tbool noirq;\n};\n\ntypedef void (*acpi_notify_handler)(acpi_handle, u32, void *);\n\nstruct pci_filp_private {\n\tenum pci_mmap_state mmap_state;\n\tint write_combine;\n};\n\nstruct pci_slot_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct pci_slot *, char *);\n\tssize_t (*store)(struct pci_slot *, const char *, size_t);\n};\n\nstruct acpi_bus_type {\n\tstruct list_head list;\n\tconst char *name;\n\tbool (*match)(struct device *);\n\tstruct acpi_device * (*find_companion)(struct device *);\n\tvoid (*setup)(struct device *);\n\tvoid (*cleanup)(struct device *);\n};\n\nstruct acpi_pci_root {\n\tstruct acpi_device *device;\n\tstruct pci_bus *bus;\n\tu16 segment;\n\tstruct resource secondary;\n\tu32 osc_support_set;\n\tu32 osc_control_set;\n\tphys_addr_t mcfg_addr;\n};\n\nenum pm_qos_flags_status {\n\tPM_QOS_FLAGS_UNDEFINED = 4294967295,\n\tPM_QOS_FLAGS_NONE = 0,\n\tPM_QOS_FLAGS_SOME = 1,\n\tPM_QOS_FLAGS_ALL = 2,\n};\n\nstruct hpx_type0 {\n\tu32 revision;\n\tu8 cache_line_size;\n\tu8 latency_timer;\n\tu8 enable_serr;\n\tu8 enable_perr;\n};\n\nstruct hpx_type1 {\n\tu32 revision;\n\tu8 max_mem_read;\n\tu8 avg_max_split;\n\tu16 tot_max_split;\n};\n\nstruct hpx_type2 {\n\tu32 revision;\n\tu32 unc_err_mask_and;\n\tu32 unc_err_mask_or;\n\tu32 unc_err_sever_and;\n\tu32 unc_err_sever_or;\n\tu32 cor_err_mask_and;\n\tu32 cor_err_mask_or;\n\tu32 adv_err_cap_and;\n\tu32 adv_err_cap_or;\n\tu16 pci_exp_devctl_and;\n\tu16 pci_exp_devctl_or;\n\tu16 pci_exp_lnkctl_and;\n\tu16 pci_exp_lnkctl_or;\n\tu32 sec_unc_err_sever_and;\n\tu32 sec_unc_err_sever_or;\n\tu32 sec_unc_err_mask_and;\n\tu32 sec_unc_err_mask_or;\n};\n\nstruct hpx_type3 {\n\tu16 device_type;\n\tu16 function_type;\n\tu16 config_space_location;\n\tu16 pci_exp_cap_id;\n\tu16 pci_exp_cap_ver;\n\tu16 pci_exp_vendor_id;\n\tu16 dvsec_id;\n\tu16 dvsec_rev;\n\tu16 match_offset;\n\tu32 match_mask_and;\n\tu32 match_value;\n\tu16 reg_offset;\n\tu32 reg_mask_and;\n\tu32 reg_mask_or;\n};\n\nenum hpx_type3_dev_type {\n\tHPX_TYPE_ENDPOINT = 1,\n\tHPX_TYPE_LEG_END = 2,\n\tHPX_TYPE_RC_END = 4,\n\tHPX_TYPE_RC_EC = 8,\n\tHPX_TYPE_ROOT_PORT = 16,\n\tHPX_TYPE_UPSTREAM = 32,\n\tHPX_TYPE_DOWNSTREAM = 64,\n\tHPX_TYPE_PCI_BRIDGE = 128,\n\tHPX_TYPE_PCIE_BRIDGE = 256,\n};\n\nenum hpx_type3_fn_type {\n\tHPX_FN_NORMAL = 1,\n\tHPX_FN_SRIOV_PHYS = 2,\n\tHPX_FN_SRIOV_VIRT = 4,\n};\n\nenum hpx_type3_cfg_loc {\n\tHPX_CFG_PCICFG = 0,\n\tHPX_CFG_PCIE_CAP = 1,\n\tHPX_CFG_PCIE_CAP_EXT = 2,\n\tHPX_CFG_VEND_CAP = 3,\n\tHPX_CFG_DVSEC = 4,\n\tHPX_CFG_MAX = 5,\n};\n\nenum pci_irq_reroute_variant {\n\tINTEL_IRQ_REROUTE_VARIANT = 1,\n\tMAX_IRQ_REROUTE_VARIANTS = 3,\n};\n\nstruct pci_fixup {\n\tu16 vendor;\n\tu16 device;\n\tu32 class;\n\tunsigned int class_shift;\n\tint hook_offset;\n};\n\nenum {\n\tNVME_REG_CAP = 0,\n\tNVME_REG_VS = 8,\n\tNVME_REG_INTMS = 12,\n\tNVME_REG_INTMC = 16,\n\tNVME_REG_CC = 20,\n\tNVME_REG_CSTS = 28,\n\tNVME_REG_NSSR = 32,\n\tNVME_REG_AQA = 36,\n\tNVME_REG_ASQ = 40,\n\tNVME_REG_ACQ = 48,\n\tNVME_REG_CMBLOC = 56,\n\tNVME_REG_CMBSZ = 60,\n\tNVME_REG_BPINFO = 64,\n\tNVME_REG_BPRSEL = 68,\n\tNVME_REG_BPMBL = 72,\n\tNVME_REG_CMBMSC = 80,\n\tNVME_REG_PMRCAP = 3584,\n\tNVME_REG_PMRCTL = 3588,\n\tNVME_REG_PMRSTS = 3592,\n\tNVME_REG_PMREBS = 3596,\n\tNVME_REG_PMRSWTP = 3600,\n\tNVME_REG_DBS = 4096,\n};\n\nenum {\n\tNVME_CC_ENABLE = 1,\n\tNVME_CC_EN_SHIFT = 0,\n\tNVME_CC_CSS_SHIFT = 4,\n\tNVME_CC_MPS_SHIFT = 7,\n\tNVME_CC_AMS_SHIFT = 11,\n\tNVME_CC_SHN_SHIFT = 14,\n\tNVME_CC_IOSQES_SHIFT = 16,\n\tNVME_CC_IOCQES_SHIFT = 20,\n\tNVME_CC_CSS_NVM = 0,\n\tNVME_CC_CSS_CSI = 96,\n\tNVME_CC_CSS_MASK = 112,\n\tNVME_CC_AMS_RR = 0,\n\tNVME_CC_AMS_WRRU = 2048,\n\tNVME_CC_AMS_VS = 14336,\n\tNVME_CC_SHN_NONE = 0,\n\tNVME_CC_SHN_NORMAL = 16384,\n\tNVME_CC_SHN_ABRUPT = 32768,\n\tNVME_CC_SHN_MASK = 49152,\n\tNVME_CC_IOSQES = 393216,\n\tNVME_CC_IOCQES = 4194304,\n\tNVME_CAP_CSS_NVM = 1,\n\tNVME_CAP_CSS_CSI = 64,\n\tNVME_CSTS_RDY = 1,\n\tNVME_CSTS_CFS = 2,\n\tNVME_CSTS_NSSRO = 16,\n\tNVME_CSTS_PP = 32,\n\tNVME_CSTS_SHST_NORMAL = 0,\n\tNVME_CSTS_SHST_OCCUR = 4,\n\tNVME_CSTS_SHST_CMPLT = 8,\n\tNVME_CSTS_SHST_MASK = 12,\n\tNVME_CMBMSC_CRE = 1,\n\tNVME_CMBMSC_CMSE = 2,\n};\n\nenum {\n\tNVME_AEN_BIT_NS_ATTR = 8,\n\tNVME_AEN_BIT_FW_ACT = 9,\n\tNVME_AEN_BIT_ANA_CHANGE = 11,\n\tNVME_AEN_BIT_DISC_CHANGE = 31,\n};\n\nenum {\n\tSWITCHTEC_GAS_MRPC_OFFSET = 0,\n\tSWITCHTEC_GAS_TOP_CFG_OFFSET = 4096,\n\tSWITCHTEC_GAS_SW_EVENT_OFFSET = 6144,\n\tSWITCHTEC_GAS_SYS_INFO_OFFSET = 8192,\n\tSWITCHTEC_GAS_FLASH_INFO_OFFSET = 8704,\n\tSWITCHTEC_GAS_PART_CFG_OFFSET = 16384,\n\tSWITCHTEC_GAS_NTB_OFFSET = 65536,\n\tSWITCHTEC_GAS_PFF_CSR_OFFSET = 1261568,\n};\n\nenum {\n\tSWITCHTEC_NTB_REG_INFO_OFFSET = 0,\n\tSWITCHTEC_NTB_REG_CTRL_OFFSET = 16384,\n\tSWITCHTEC_NTB_REG_DBMSG_OFFSET = 409600,\n};\n\nstruct nt_partition_info {\n\tu32 xlink_enabled;\n\tu32 target_part_low;\n\tu32 target_part_high;\n\tu32 reserved;\n};\n\nstruct ntb_info_regs {\n\tu8 partition_count;\n\tu8 partition_id;\n\tu16 reserved1;\n\tu64 ep_map;\n\tu16 requester_id;\n\tu16 reserved2;\n\tu32 reserved3[4];\n\tstruct nt_partition_info ntp_info[48];\n} __attribute__((packed));\n\nstruct ntb_ctrl_regs {\n\tu32 partition_status;\n\tu32 partition_op;\n\tu32 partition_ctrl;\n\tu32 bar_setup;\n\tu32 bar_error;\n\tu16 lut_table_entries;\n\tu16 lut_table_offset;\n\tu32 lut_error;\n\tu16 req_id_table_size;\n\tu16 req_id_table_offset;\n\tu32 req_id_error;\n\tu32 reserved1[7];\n\tstruct {\n\t\tu32 ctl;\n\t\tu32 win_size;\n\t\tu64 xlate_addr;\n\t} bar_entry[6];\n\tstruct {\n\t\tu32 win_size;\n\t\tu32 reserved[3];\n\t} bar_ext_entry[6];\n\tu32 reserved2[192];\n\tu32 req_id_table[512];\n\tu32 reserved3[256];\n\tu64 lut_entry[512];\n};\n\nstruct pci_dev_reset_methods {\n\tu16 vendor;\n\tu16 device;\n\tint (*reset)(struct pci_dev *, int);\n};\n\nstruct pci_dev_acs_enabled {\n\tu16 vendor;\n\tu16 device;\n\tint (*acs_enabled)(struct pci_dev *, u16);\n};\n\nstruct pci_dev_acs_ops {\n\tu16 vendor;\n\tu16 device;\n\tint (*enable_acs)(struct pci_dev *);\n\tint (*disable_acs_redir)(struct pci_dev *);\n};\n\nstruct slot {\n\tu8 number;\n\tunsigned int devfn;\n\tstruct pci_bus *bus;\n\tstruct pci_dev *dev;\n\tunsigned int latch_status: 1;\n\tunsigned int adapter_status: 1;\n\tunsigned int extracting;\n\tstruct hotplug_slot hotplug_slot;\n\tstruct list_head slot_list;\n};\n\nstruct cpci_hp_controller_ops {\n\tint (*query_enum)();\n\tint (*enable_irq)();\n\tint (*disable_irq)();\n\tint (*check_irq)(void *);\n\tint (*hardware_test)(struct slot *, u32);\n\tu8 (*get_power)(struct slot *);\n\tint (*set_power)(struct slot *, int);\n};\n\nstruct cpci_hp_controller {\n\tunsigned int irq;\n\tlong unsigned int irq_flags;\n\tchar *devname;\n\tvoid *dev_id;\n\tchar *name;\n\tstruct cpci_hp_controller_ops *ops;\n};\n\ntypedef acpi_status (*acpi_walk_callback)(acpi_handle, u32, void *, void **);\n\nstruct controller {\n\tstruct pcie_device *pcie;\n\tu32 slot_cap;\n\tunsigned int inband_presence_disabled: 1;\n\tu16 slot_ctrl;\n\tstruct mutex ctrl_lock;\n\tlong unsigned int cmd_started;\n\tunsigned int cmd_busy: 1;\n\twait_queue_head_t queue;\n\tatomic_t pending_events;\n\tunsigned int notification_enabled: 1;\n\tunsigned int power_fault_detected;\n\tstruct task_struct *poll_thread;\n\tu8 state;\n\tstruct mutex state_lock;\n\tstruct delayed_work button_work;\n\tstruct hotplug_slot hotplug_slot;\n\tstruct rw_semaphore reset_lock;\n\tunsigned int ist_running;\n\tint request_result;\n\twait_queue_head_t requester;\n};\n\nstruct controller___2;\n\nstruct hpc_ops;\n\nstruct slot___2 {\n\tu8 bus;\n\tu8 device;\n\tu16 status;\n\tu32 number;\n\tu8 is_a_board;\n\tu8 state;\n\tu8 attention_save;\n\tu8 presence_save;\n\tu8 latch_save;\n\tu8 pwr_save;\n\tstruct controller___2 *ctrl;\n\tconst struct hpc_ops *hpc_ops;\n\tstruct hotplug_slot hotplug_slot;\n\tstruct list_head slot_list;\n\tstruct delayed_work work;\n\tstruct mutex lock;\n\tstruct workqueue_struct *wq;\n\tu8 hp_slot;\n};\n\nstruct controller___2 {\n\tstruct mutex crit_sect;\n\tstruct mutex cmd_lock;\n\tint num_slots;\n\tint slot_num_inc;\n\tstruct pci_dev *pci_dev;\n\tstruct list_head slot_list;\n\tconst struct hpc_ops *hpc_ops;\n\twait_queue_head_t queue;\n\tu8 slot_device_offset;\n\tu32 pcix_misc2_reg;\n\tu32 first_slot;\n\tu32 cap_offset;\n\tlong unsigned int mmio_base;\n\tlong unsigned int mmio_size;\n\tvoid *creg;\n\tstruct timer_list poll_timer;\n};\n\nstruct hpc_ops {\n\tint (*power_on_slot)(struct slot___2 *);\n\tint (*slot_enable)(struct slot___2 *);\n\tint (*slot_disable)(struct slot___2 *);\n\tint (*set_bus_speed_mode)(struct slot___2 *, enum pci_bus_speed);\n\tint (*get_power_status)(struct slot___2 *, u8 *);\n\tint (*get_attention_status)(struct slot___2 *, u8 *);\n\tint (*set_attention_status)(struct slot___2 *, u8);\n\tint (*get_latch_status)(struct slot___2 *, u8 *);\n\tint (*get_adapter_status)(struct slot___2 *, u8 *);\n\tint (*get_adapter_speed)(struct slot___2 *, enum pci_bus_speed *);\n\tint (*get_mode1_ECC_cap)(struct slot___2 *, u8 *);\n\tint (*get_prog_int)(struct slot___2 *, u8 *);\n\tint (*query_power_fault)(struct slot___2 *);\n\tvoid (*green_led_on)(struct slot___2 *);\n\tvoid (*green_led_off)(struct slot___2 *);\n\tvoid (*green_led_blink)(struct slot___2 *);\n\tvoid (*release_ctlr)(struct controller___2 *);\n\tint (*check_cmd_status)(struct controller___2 *);\n};\n\nstruct event_info {\n\tu32 event_type;\n\tstruct slot___2 *p_slot;\n\tstruct work_struct work;\n};\n\nstruct pushbutton_work_info {\n\tstruct slot___2 *p_slot;\n\tstruct work_struct work;\n};\n\nenum ctrl_offsets {\n\tBASE_OFFSET = 0,\n\tSLOT_AVAIL1 = 4,\n\tSLOT_AVAIL2 = 8,\n\tSLOT_CONFIG = 12,\n\tSEC_BUS_CONFIG = 16,\n\tMSI_CTRL = 18,\n\tPROG_INTERFACE = 19,\n\tCMD = 20,\n\tCMD_STATUS = 22,\n\tINTR_LOC = 24,\n\tSERR_LOC = 28,\n\tSERR_INTR_ENABLE = 32,\n\tSLOT1 = 36,\n};\n\nstruct acpiphp_slot;\n\nstruct slot___3 {\n\tstruct hotplug_slot hotplug_slot;\n\tstruct acpiphp_slot *acpi_slot;\n\tunsigned int sun;\n};\n\nstruct acpiphp_slot {\n\tstruct list_head node;\n\tstruct pci_bus *bus;\n\tstruct list_head funcs;\n\tstruct slot___3 *slot;\n\tu8 device;\n\tu32 flags;\n};\n\nstruct acpiphp_attention_info {\n\tint (*set_attn)(struct hotplug_slot *, u8);\n\tint (*get_attn)(struct hotplug_slot *, u8 *);\n\tstruct module *owner;\n};\n\nstruct acpiphp_context;\n\nstruct acpiphp_bridge {\n\tstruct list_head list;\n\tstruct list_head slots;\n\tstruct kref ref;\n\tstruct acpiphp_context *context;\n\tint nr_slots;\n\tstruct pci_bus *pci_bus;\n\tstruct pci_dev *pci_dev;\n\tbool is_going_away;\n};\n\nstruct acpiphp_func {\n\tstruct acpiphp_bridge *parent;\n\tstruct acpiphp_slot *slot;\n\tstruct list_head sibling;\n\tu8 function;\n\tu32 flags;\n};\n\nstruct acpiphp_context {\n\tstruct acpi_hotplug_context hp;\n\tstruct acpiphp_func func;\n\tstruct acpiphp_bridge *bridge;\n\tunsigned int refcount;\n};\n\nstruct acpiphp_root_context {\n\tstruct acpi_hotplug_context hp;\n\tstruct acpiphp_bridge *root_bridge;\n};\n\nenum dmi_device_type {\n\tDMI_DEV_TYPE_ANY = 0,\n\tDMI_DEV_TYPE_OTHER = 1,\n\tDMI_DEV_TYPE_UNKNOWN = 2,\n\tDMI_DEV_TYPE_VIDEO = 3,\n\tDMI_DEV_TYPE_SCSI = 4,\n\tDMI_DEV_TYPE_ETHERNET = 5,\n\tDMI_DEV_TYPE_TOKENRING = 6,\n\tDMI_DEV_TYPE_SOUND = 7,\n\tDMI_DEV_TYPE_PATA = 8,\n\tDMI_DEV_TYPE_SATA = 9,\n\tDMI_DEV_TYPE_SAS = 10,\n\tDMI_DEV_TYPE_IPMI = 4294967295,\n\tDMI_DEV_TYPE_OEM_STRING = 4294967294,\n\tDMI_DEV_TYPE_DEV_ONBOARD = 4294967293,\n\tDMI_DEV_TYPE_DEV_SLOT = 4294967292,\n};\n\nstruct dmi_device {\n\tstruct list_head list;\n\tint type;\n\tconst char *name;\n\tvoid *device_data;\n};\n\nstruct dmi_dev_onboard {\n\tstruct dmi_device dev;\n\tint instance;\n\tint segment;\n\tint bus;\n\tint devfn;\n};\n\nenum smbios_attr_enum {\n\tSMBIOS_ATTR_NONE = 0,\n\tSMBIOS_ATTR_LABEL_SHOW = 1,\n\tSMBIOS_ATTR_INSTANCE_SHOW = 2,\n};\n\nenum acpi_attr_enum {\n\tACPI_ATTR_LABEL_SHOW = 0,\n\tACPI_ATTR_INDEX_SHOW = 1,\n};\n\nstruct pci_p2pdma {\n\tstruct gen_pool *pool;\n\tbool p2pmem_published;\n\tstruct xarray map_types;\n};\n\nenum pci_p2pdma_map_type {\n\tPCI_P2PDMA_MAP_UNKNOWN = 0,\n\tPCI_P2PDMA_MAP_NOT_SUPPORTED = 1,\n\tPCI_P2PDMA_MAP_BUS_ADDR = 2,\n\tPCI_P2PDMA_MAP_THRU_HOST_BRIDGE = 3,\n};\n\nstruct pci_p2pdma_pagemap {\n\tstruct dev_pagemap pgmap;\n\tstruct pci_dev *provider;\n\tu64 bus_offset;\n};\n\nstruct pci_p2pdma_whitelist_entry {\n\tshort unsigned int vendor;\n\tshort unsigned int device;\n\tenum {\n\t\tREQ_SAME_HOST_BRIDGE = 1,\n\t} flags;\n};\n\nenum pci_interrupt_pin {\n\tPCI_INTERRUPT_UNKNOWN = 0,\n\tPCI_INTERRUPT_INTA = 1,\n\tPCI_INTERRUPT_INTB = 2,\n\tPCI_INTERRUPT_INTC = 3,\n\tPCI_INTERRUPT_INTD = 4,\n};\n\nenum pci_barno {\n\tNO_BAR = 4294967295,\n\tBAR_0 = 0,\n\tBAR_1 = 1,\n\tBAR_2 = 2,\n\tBAR_3 = 3,\n\tBAR_4 = 4,\n\tBAR_5 = 5,\n};\n\nstruct pci_epf_header {\n\tu16 vendorid;\n\tu16 deviceid;\n\tu8 revid;\n\tu8 progif_code;\n\tu8 subclass_code;\n\tu8 baseclass_code;\n\tu8 cache_line_size;\n\tu16 subsys_vendor_id;\n\tu16 subsys_id;\n\tenum pci_interrupt_pin interrupt_pin;\n};\n\nstruct pci_epf_bar {\n\tdma_addr_t phys_addr;\n\tvoid *addr;\n\tsize_t size;\n\tenum pci_barno barno;\n\tint flags;\n};\n\nstruct pci_epc_ops;\n\nstruct pci_epc_mem;\n\nstruct pci_epc {\n\tstruct device dev;\n\tstruct list_head pci_epf;\n\tconst struct pci_epc_ops *ops;\n\tstruct pci_epc_mem **windows;\n\tstruct pci_epc_mem *mem;\n\tunsigned int num_windows;\n\tu8 max_functions;\n\tstruct config_group *group;\n\tstruct mutex lock;\n\tlong unsigned int function_num_map;\n\tstruct atomic_notifier_head notifier;\n};\n\nenum pci_epc_irq_type {\n\tPCI_EPC_IRQ_UNKNOWN = 0,\n\tPCI_EPC_IRQ_LEGACY = 1,\n\tPCI_EPC_IRQ_MSI = 2,\n\tPCI_EPC_IRQ_MSIX = 3,\n};\n\nstruct pci_epc_features;\n\nstruct pci_epc_ops {\n\tint (*write_header)(struct pci_epc *, u8, struct pci_epf_header *);\n\tint (*set_bar)(struct pci_epc *, u8, struct pci_epf_bar *);\n\tvoid (*clear_bar)(struct pci_epc *, u8, struct pci_epf_bar *);\n\tint (*map_addr)(struct pci_epc *, u8, phys_addr_t, u64, size_t);\n\tvoid (*unmap_addr)(struct pci_epc *, u8, phys_addr_t);\n\tint (*set_msi)(struct pci_epc *, u8, u8);\n\tint (*get_msi)(struct pci_epc *, u8);\n\tint (*set_msix)(struct pci_epc *, u8, u16, enum pci_barno, u32);\n\tint (*get_msix)(struct pci_epc *, u8);\n\tint (*raise_irq)(struct pci_epc *, u8, enum pci_epc_irq_type, u16);\n\tint (*map_msi_irq)(struct pci_epc *, u8, phys_addr_t, u8, u32, u32 *, u32 *);\n\tint (*start)(struct pci_epc *);\n\tvoid (*stop)(struct pci_epc *);\n\tconst struct pci_epc_features * (*get_features)(struct pci_epc *, u8);\n\tstruct module *owner;\n};\n\nstruct pci_epc_features {\n\tunsigned int linkup_notifier: 1;\n\tunsigned int core_init_notifier: 1;\n\tunsigned int msi_capable: 1;\n\tunsigned int msix_capable: 1;\n\tu8 reserved_bar;\n\tu8 bar_fixed_64bit;\n\tu64 bar_fixed_size[6];\n\tsize_t align;\n};\n\nstruct pci_epc_mem_window {\n\tphys_addr_t phys_base;\n\tsize_t size;\n\tsize_t page_size;\n};\n\nstruct pci_epc_mem {\n\tstruct pci_epc_mem_window window;\n\tlong unsigned int *bitmap;\n\tint pages;\n\tstruct mutex lock;\n};\n\nenum dw_pcie_region_type {\n\tDW_PCIE_REGION_UNKNOWN = 0,\n\tDW_PCIE_REGION_INBOUND = 1,\n\tDW_PCIE_REGION_OUTBOUND = 2,\n};\n\nstruct pcie_port;\n\nstruct dw_pcie_host_ops {\n\tint (*host_init)(struct pcie_port *);\n\tint (*msi_host_init)(struct pcie_port *);\n};\n\nstruct pcie_port {\n\tbool has_msi_ctrl: 1;\n\tu64 cfg0_base;\n\tvoid *va_cfg0_base;\n\tu32 cfg0_size;\n\tresource_size_t io_base;\n\tphys_addr_t io_bus_addr;\n\tu32 io_size;\n\tint irq;\n\tconst struct dw_pcie_host_ops *ops;\n\tint msi_irq;\n\tstruct irq_domain *irq_domain;\n\tstruct irq_domain *msi_domain;\n\tu16 msi_msg;\n\tdma_addr_t msi_data;\n\tstruct irq_chip *msi_irq_chip;\n\tu32 num_vectors;\n\tu32 irq_mask[8];\n\tstruct pci_host_bridge *bridge;\n\traw_spinlock_t lock;\n\tlong unsigned int msi_irq_in_use[4];\n};\n\nenum dw_pcie_as_type {\n\tDW_PCIE_AS_UNKNOWN = 0,\n\tDW_PCIE_AS_MEM = 1,\n\tDW_PCIE_AS_IO = 2,\n};\n\nstruct dw_pcie_ep;\n\nstruct dw_pcie_ep_ops {\n\tvoid (*ep_init)(struct dw_pcie_ep *);\n\tint (*raise_irq)(struct dw_pcie_ep *, u8, enum pci_epc_irq_type, u16);\n\tconst struct pci_epc_features * (*get_features)(struct dw_pcie_ep *);\n\tunsigned int (*func_conf_select)(struct dw_pcie_ep *, u8);\n};\n\nstruct dw_pcie_ep {\n\tstruct pci_epc *epc;\n\tstruct list_head func_list;\n\tconst struct dw_pcie_ep_ops *ops;\n\tphys_addr_t phys_base;\n\tsize_t addr_size;\n\tsize_t page_size;\n\tu8 bar_to_atu[6];\n\tphys_addr_t *outbound_addr;\n\tlong unsigned int *ib_window_map;\n\tlong unsigned int *ob_window_map;\n\tvoid *msi_mem;\n\tphys_addr_t msi_mem_phys;\n\tstruct pci_epf_bar *epf_bar[6];\n};\n\nstruct dw_pcie;\n\nstruct dw_pcie_ops {\n\tu64 (*cpu_addr_fixup)(struct dw_pcie *, u64);\n\tu32 (*read_dbi)(struct dw_pcie *, void *, u32, size_t);\n\tvoid (*write_dbi)(struct dw_pcie *, void *, u32, size_t, u32);\n\tvoid (*write_dbi2)(struct dw_pcie *, void *, u32, size_t, u32);\n\tint (*link_up)(struct dw_pcie *);\n\tint (*start_link)(struct dw_pcie *);\n\tvoid (*stop_link)(struct dw_pcie *);\n};\n\nstruct dw_pcie {\n\tstruct device *dev;\n\tvoid *dbi_base;\n\tvoid *dbi_base2;\n\tvoid *atu_base;\n\tsize_t atu_size;\n\tu32 num_ib_windows;\n\tu32 num_ob_windows;\n\tstruct pcie_port pp;\n\tstruct dw_pcie_ep ep;\n\tconst struct dw_pcie_ops *ops;\n\tunsigned int version;\n\tint num_lanes;\n\tint link_gen;\n\tu8 n_fts[2];\n\tbool iatu_unroll_enabled: 1;\n\tbool io_cfg_atu_shared: 1;\n};\n\nenum dw_pcie_device_mode {\n\tDW_PCIE_UNKNOWN_TYPE = 0,\n\tDW_PCIE_EP_TYPE = 1,\n\tDW_PCIE_LEG_EP_TYPE = 2,\n\tDW_PCIE_RC_TYPE = 3,\n};\n\nstruct dw_plat_pcie {\n\tstruct dw_pcie *pci;\n\tstruct regmap *regmap;\n\tenum dw_pcie_device_mode mode;\n};\n\nstruct dw_plat_pcie_of_data {\n\tenum dw_pcie_device_mode mode;\n};\n\nstruct reset_control;\n\nenum pcie_data_rate {\n\tPCIE_GEN1 = 0,\n\tPCIE_GEN2 = 1,\n\tPCIE_GEN3 = 2,\n\tPCIE_GEN4 = 3,\n};\n\nstruct meson_pcie_clk_res {\n\tstruct clk *clk;\n\tstruct clk *port_clk;\n\tstruct clk *general_clk;\n};\n\nstruct meson_pcie_rc_reset {\n\tstruct reset_control *port;\n\tstruct reset_control *apb;\n};\n\nstruct meson_pcie {\n\tstruct dw_pcie pci;\n\tvoid *cfg_base;\n\tstruct meson_pcie_clk_res clk_res;\n\tstruct meson_pcie_rc_reset mrst;\n\tstruct gpio_desc *reset_gpio;\n\tstruct phy *phy;\n};\n\nenum hdmi_infoframe_type {\n\tHDMI_INFOFRAME_TYPE_VENDOR = 129,\n\tHDMI_INFOFRAME_TYPE_AVI = 130,\n\tHDMI_INFOFRAME_TYPE_SPD = 131,\n\tHDMI_INFOFRAME_TYPE_AUDIO = 132,\n\tHDMI_INFOFRAME_TYPE_DRM = 135,\n};\n\nstruct hdmi_any_infoframe {\n\tenum hdmi_infoframe_type type;\n\tunsigned char version;\n\tunsigned char length;\n};\n\nenum hdmi_colorspace {\n\tHDMI_COLORSPACE_RGB = 0,\n\tHDMI_COLORSPACE_YUV422 = 1,\n\tHDMI_COLORSPACE_YUV444 = 2,\n\tHDMI_COLORSPACE_YUV420 = 3,\n\tHDMI_COLORSPACE_RESERVED4 = 4,\n\tHDMI_COLORSPACE_RESERVED5 = 5,\n\tHDMI_COLORSPACE_RESERVED6 = 6,\n\tHDMI_COLORSPACE_IDO_DEFINED = 7,\n};\n\nenum hdmi_scan_mode {\n\tHDMI_SCAN_MODE_NONE = 0,\n\tHDMI_SCAN_MODE_OVERSCAN = 1,\n\tHDMI_SCAN_MODE_UNDERSCAN = 2,\n\tHDMI_SCAN_MODE_RESERVED = 3,\n};\n\nenum hdmi_colorimetry {\n\tHDMI_COLORIMETRY_NONE = 0,\n\tHDMI_COLORIMETRY_ITU_601 = 1,\n\tHDMI_COLORIMETRY_ITU_709 = 2,\n\tHDMI_COLORIMETRY_EXTENDED = 3,\n};\n\nenum hdmi_picture_aspect {\n\tHDMI_PICTURE_ASPECT_NONE = 0,\n\tHDMI_PICTURE_ASPECT_4_3 = 1,\n\tHDMI_PICTURE_ASPECT_16_9 = 2,\n\tHDMI_PICTURE_ASPECT_64_27 = 3,\n\tHDMI_PICTURE_ASPECT_256_135 = 4,\n\tHDMI_PICTURE_ASPECT_RESERVED = 5,\n};\n\nenum hdmi_active_aspect {\n\tHDMI_ACTIVE_ASPECT_16_9_TOP = 2,\n\tHDMI_ACTIVE_ASPECT_14_9_TOP = 3,\n\tHDMI_ACTIVE_ASPECT_16_9_CENTER = 4,\n\tHDMI_ACTIVE_ASPECT_PICTURE = 8,\n\tHDMI_ACTIVE_ASPECT_4_3 = 9,\n\tHDMI_ACTIVE_ASPECT_16_9 = 10,\n\tHDMI_ACTIVE_ASPECT_14_9 = 11,\n\tHDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13,\n\tHDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14,\n\tHDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15,\n};\n\nenum hdmi_extended_colorimetry {\n\tHDMI_EXTENDED_COLORIMETRY_XV_YCC_601 = 0,\n\tHDMI_EXTENDED_COLORIMETRY_XV_YCC_709 = 1,\n\tHDMI_EXTENDED_COLORIMETRY_S_YCC_601 = 2,\n\tHDMI_EXTENDED_COLORIMETRY_OPYCC_601 = 3,\n\tHDMI_EXTENDED_COLORIMETRY_OPRGB = 4,\n\tHDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM = 5,\n\tHDMI_EXTENDED_COLORIMETRY_BT2020 = 6,\n\tHDMI_EXTENDED_COLORIMETRY_RESERVED = 7,\n};\n\nenum hdmi_quantization_range {\n\tHDMI_QUANTIZATION_RANGE_DEFAULT = 0,\n\tHDMI_QUANTIZATION_RANGE_LIMITED = 1,\n\tHDMI_QUANTIZATION_RANGE_FULL = 2,\n\tHDMI_QUANTIZATION_RANGE_RESERVED = 3,\n};\n\nenum hdmi_nups {\n\tHDMI_NUPS_UNKNOWN = 0,\n\tHDMI_NUPS_HORIZONTAL = 1,\n\tHDMI_NUPS_VERTICAL = 2,\n\tHDMI_NUPS_BOTH = 3,\n};\n\nenum hdmi_ycc_quantization_range {\n\tHDMI_YCC_QUANTIZATION_RANGE_LIMITED = 0,\n\tHDMI_YCC_QUANTIZATION_RANGE_FULL = 1,\n};\n\nenum hdmi_content_type {\n\tHDMI_CONTENT_TYPE_GRAPHICS = 0,\n\tHDMI_CONTENT_TYPE_PHOTO = 1,\n\tHDMI_CONTENT_TYPE_CINEMA = 2,\n\tHDMI_CONTENT_TYPE_GAME = 3,\n};\n\nenum hdmi_metadata_type {\n\tHDMI_STATIC_METADATA_TYPE1 = 0,\n};\n\nenum hdmi_eotf {\n\tHDMI_EOTF_TRADITIONAL_GAMMA_SDR = 0,\n\tHDMI_EOTF_TRADITIONAL_GAMMA_HDR = 1,\n\tHDMI_EOTF_SMPTE_ST2084 = 2,\n\tHDMI_EOTF_BT_2100_HLG = 3,\n};\n\nstruct hdmi_avi_infoframe {\n\tenum hdmi_infoframe_type type;\n\tunsigned char version;\n\tunsigned char length;\n\tenum hdmi_colorspace colorspace;\n\tenum hdmi_scan_mode scan_mode;\n\tenum hdmi_colorimetry colorimetry;\n\tenum hdmi_picture_aspect picture_aspect;\n\tenum hdmi_active_aspect active_aspect;\n\tbool itc;\n\tenum hdmi_extended_colorimetry extended_colorimetry;\n\tenum hdmi_quantization_range quantization_range;\n\tenum hdmi_nups nups;\n\tunsigned char video_code;\n\tenum hdmi_ycc_quantization_range ycc_quantization_range;\n\tenum hdmi_content_type content_type;\n\tunsigned char pixel_repeat;\n\tshort unsigned int top_bar;\n\tshort unsigned int bottom_bar;\n\tshort unsigned int left_bar;\n\tshort unsigned int right_bar;\n};\n\nstruct hdmi_drm_infoframe {\n\tenum hdmi_infoframe_type type;\n\tunsigned char version;\n\tunsigned char length;\n\tenum hdmi_eotf eotf;\n\tenum hdmi_metadata_type metadata_type;\n\tstruct {\n\t\tu16 x;\n\t\tu16 y;\n\t} display_primaries[3];\n\tstruct {\n\t\tu16 x;\n\t\tu16 y;\n\t} white_point;\n\tu16 max_display_mastering_luminance;\n\tu16 min_display_mastering_luminance;\n\tu16 max_cll;\n\tu16 max_fall;\n};\n\nenum hdmi_spd_sdi {\n\tHDMI_SPD_SDI_UNKNOWN = 0,\n\tHDMI_SPD_SDI_DSTB = 1,\n\tHDMI_SPD_SDI_DVDP = 2,\n\tHDMI_SPD_SDI_DVHS = 3,\n\tHDMI_SPD_SDI_HDDVR = 4,\n\tHDMI_SPD_SDI_DVC = 5,\n\tHDMI_SPD_SDI_DSC = 6,\n\tHDMI_SPD_SDI_VCD = 7,\n\tHDMI_SPD_SDI_GAME = 8,\n\tHDMI_SPD_SDI_PC = 9,\n\tHDMI_SPD_SDI_BD = 10,\n\tHDMI_SPD_SDI_SACD = 11,\n\tHDMI_SPD_SDI_HDDVD = 12,\n\tHDMI_SPD_SDI_PMP = 13,\n};\n\nstruct hdmi_spd_infoframe {\n\tenum hdmi_infoframe_type type;\n\tunsigned char version;\n\tunsigned char length;\n\tchar vendor[8];\n\tchar product[16];\n\tenum hdmi_spd_sdi sdi;\n};\n\nenum hdmi_audio_coding_type {\n\tHDMI_AUDIO_CODING_TYPE_STREAM = 0,\n\tHDMI_AUDIO_CODING_TYPE_PCM = 1,\n\tHDMI_AUDIO_CODING_TYPE_AC3 = 2,\n\tHDMI_AUDIO_CODING_TYPE_MPEG1 = 3,\n\tHDMI_AUDIO_CODING_TYPE_MP3 = 4,\n\tHDMI_AUDIO_CODING_TYPE_MPEG2 = 5,\n\tHDMI_AUDIO_CODING_TYPE_AAC_LC = 6,\n\tHDMI_AUDIO_CODING_TYPE_DTS = 7,\n\tHDMI_AUDIO_CODING_TYPE_ATRAC = 8,\n\tHDMI_AUDIO_CODING_TYPE_DSD = 9,\n\tHDMI_AUDIO_CODING_TYPE_EAC3 = 10,\n\tHDMI_AUDIO_CODING_TYPE_DTS_HD = 11,\n\tHDMI_AUDIO_CODING_TYPE_MLP = 12,\n\tHDMI_AUDIO_CODING_TYPE_DST = 13,\n\tHDMI_AUDIO_CODING_TYPE_WMA_PRO = 14,\n\tHDMI_AUDIO_CODING_TYPE_CXT = 15,\n};\n\nenum hdmi_audio_sample_size {\n\tHDMI_AUDIO_SAMPLE_SIZE_STREAM = 0,\n\tHDMI_AUDIO_SAMPLE_SIZE_16 = 1,\n\tHDMI_AUDIO_SAMPLE_SIZE_20 = 2,\n\tHDMI_AUDIO_SAMPLE_SIZE_24 = 3,\n};\n\nenum hdmi_audio_sample_frequency {\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_STREAM = 0,\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_32000 = 1,\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_44100 = 2,\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_48000 = 3,\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_88200 = 4,\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_96000 = 5,\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_176400 = 6,\n\tHDMI_AUDIO_SAMPLE_FREQUENCY_192000 = 7,\n};\n\nenum hdmi_audio_coding_type_ext {\n\tHDMI_AUDIO_CODING_TYPE_EXT_CT = 0,\n\tHDMI_AUDIO_CODING_TYPE_EXT_HE_AAC = 1,\n\tHDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2 = 2,\n\tHDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND = 3,\n\tHDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC = 4,\n\tHDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2 = 5,\n\tHDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC = 6,\n\tHDMI_AUDIO_CODING_TYPE_EXT_DRA = 7,\n\tHDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND = 8,\n\tHDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND = 10,\n};\n\nstruct hdmi_audio_infoframe {\n\tenum hdmi_infoframe_type type;\n\tunsigned char version;\n\tunsigned char length;\n\tunsigned char channels;\n\tenum hdmi_audio_coding_type coding_type;\n\tenum hdmi_audio_sample_size sample_size;\n\tenum hdmi_audio_sample_frequency sample_frequency;\n\tenum hdmi_audio_coding_type_ext coding_type_ext;\n\tunsigned char channel_allocation;\n\tunsigned char level_shift_value;\n\tbool downmix_inhibit;\n};\n\nenum hdmi_3d_structure {\n\tHDMI_3D_STRUCTURE_INVALID = 4294967295,\n\tHDMI_3D_STRUCTURE_FRAME_PACKING = 0,\n\tHDMI_3D_STRUCTURE_FIELD_ALTERNATIVE = 1,\n\tHDMI_3D_STRUCTURE_LINE_ALTERNATIVE = 2,\n\tHDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL = 3,\n\tHDMI_3D_STRUCTURE_L_DEPTH = 4,\n\tHDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH = 5,\n\tHDMI_3D_STRUCTURE_TOP_AND_BOTTOM = 6,\n\tHDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8,\n};\n\nstruct hdmi_vendor_infoframe {\n\tenum hdmi_infoframe_type type;\n\tunsigned char version;\n\tunsigned char length;\n\tunsigned int oui;\n\tu8 vic;\n\tenum hdmi_3d_structure s3d_struct;\n\tunsigned int s3d_ext_data;\n};\n\nunion hdmi_vendor_any_infoframe {\n\tstruct {\n\t\tenum hdmi_infoframe_type type;\n\t\tunsigned char version;\n\t\tunsigned char length;\n\t\tunsigned int oui;\n\t} any;\n\tstruct hdmi_vendor_infoframe hdmi;\n};\n\nunion hdmi_infoframe {\n\tstruct hdmi_any_infoframe any;\n\tstruct hdmi_avi_infoframe avi;\n\tstruct hdmi_spd_infoframe spd;\n\tunion hdmi_vendor_any_infoframe vendor;\n\tstruct hdmi_audio_infoframe audio;\n\tstruct hdmi_drm_infoframe drm;\n};\n\nstruct vc {\n\tstruct vc_data *d;\n\tstruct work_struct SAK_work;\n};\n\nstruct vgastate {\n\tvoid *vgabase;\n\tlong unsigned int membase;\n\t__u32 memsize;\n\t__u32 flags;\n\t__u32 depth;\n\t__u32 num_attr;\n\t__u32 num_crtc;\n\t__u32 num_gfx;\n\t__u32 num_seq;\n\tvoid *vidstate;\n};\n\nstruct fb_fix_screeninfo {\n\tchar id[16];\n\tlong unsigned int smem_start;\n\t__u32 smem_len;\n\t__u32 type;\n\t__u32 type_aux;\n\t__u32 visual;\n\t__u16 xpanstep;\n\t__u16 ypanstep;\n\t__u16 ywrapstep;\n\t__u32 line_length;\n\tlong unsigned int mmio_start;\n\t__u32 mmio_len;\n\t__u32 accel;\n\t__u16 capabilities;\n\t__u16 reserved[2];\n};\n\nstruct fb_bitfield {\n\t__u32 offset;\n\t__u32 length;\n\t__u32 msb_right;\n};\n\nstruct fb_var_screeninfo {\n\t__u32 xres;\n\t__u32 yres;\n\t__u32 xres_virtual;\n\t__u32 yres_virtual;\n\t__u32 xoffset;\n\t__u32 yoffset;\n\t__u32 bits_per_pixel;\n\t__u32 grayscale;\n\tstruct fb_bitfield red;\n\tstruct fb_bitfield green;\n\tstruct fb_bitfield blue;\n\tstruct fb_bitfield transp;\n\t__u32 nonstd;\n\t__u32 activate;\n\t__u32 height;\n\t__u32 width;\n\t__u32 accel_flags;\n\t__u32 pixclock;\n\t__u32 left_margin;\n\t__u32 right_margin;\n\t__u32 upper_margin;\n\t__u32 lower_margin;\n\t__u32 hsync_len;\n\t__u32 vsync_len;\n\t__u32 sync;\n\t__u32 vmode;\n\t__u32 rotate;\n\t__u32 colorspace;\n\t__u32 reserved[4];\n};\n\nstruct fb_cmap {\n\t__u32 start;\n\t__u32 len;\n\t__u16 *red;\n\t__u16 *green;\n\t__u16 *blue;\n\t__u16 *transp;\n};\n\nenum {\n\tFB_BLANK_UNBLANK = 0,\n\tFB_BLANK_NORMAL = 1,\n\tFB_BLANK_VSYNC_SUSPEND = 2,\n\tFB_BLANK_HSYNC_SUSPEND = 3,\n\tFB_BLANK_POWERDOWN = 4,\n};\n\nstruct fb_copyarea {\n\t__u32 dx;\n\t__u32 dy;\n\t__u32 width;\n\t__u32 height;\n\t__u32 sx;\n\t__u32 sy;\n};\n\nstruct fb_fillrect {\n\t__u32 dx;\n\t__u32 dy;\n\t__u32 width;\n\t__u32 height;\n\t__u32 color;\n\t__u32 rop;\n};\n\nstruct fb_image {\n\t__u32 dx;\n\t__u32 dy;\n\t__u32 width;\n\t__u32 height;\n\t__u32 fg_color;\n\t__u32 bg_color;\n\t__u8 depth;\n\tconst char *data;\n\tstruct fb_cmap cmap;\n};\n\nstruct fbcurpos {\n\t__u16 x;\n\t__u16 y;\n};\n\nstruct fb_cursor {\n\t__u16 set;\n\t__u16 enable;\n\t__u16 rop;\n\tconst char *mask;\n\tstruct fbcurpos hot;\n\tstruct fb_image image;\n};\n\nstruct fb_chroma {\n\t__u32 redx;\n\t__u32 greenx;\n\t__u32 bluex;\n\t__u32 whitex;\n\t__u32 redy;\n\t__u32 greeny;\n\t__u32 bluey;\n\t__u32 whitey;\n};\n\nstruct fb_videomode;\n\nstruct fb_monspecs {\n\tstruct fb_chroma chroma;\n\tstruct fb_videomode *modedb;\n\t__u8 manufacturer[4];\n\t__u8 monitor[14];\n\t__u8 serial_no[14];\n\t__u8 ascii[14];\n\t__u32 modedb_len;\n\t__u32 model;\n\t__u32 serial;\n\t__u32 year;\n\t__u32 week;\n\t__u32 hfmin;\n\t__u32 hfmax;\n\t__u32 dclkmin;\n\t__u32 dclkmax;\n\t__u16 input;\n\t__u16 dpms;\n\t__u16 signal;\n\t__u16 vfmin;\n\t__u16 vfmax;\n\t__u16 gamma;\n\t__u16 gtf: 1;\n\t__u16 misc;\n\t__u8 version;\n\t__u8 revision;\n\t__u8 max_x;\n\t__u8 max_y;\n};\n\nstruct fb_videomode {\n\tconst char *name;\n\tu32 refresh;\n\tu32 xres;\n\tu32 yres;\n\tu32 pixclock;\n\tu32 left_margin;\n\tu32 right_margin;\n\tu32 upper_margin;\n\tu32 lower_margin;\n\tu32 hsync_len;\n\tu32 vsync_len;\n\tu32 sync;\n\tu32 vmode;\n\tu32 flag;\n};\n\nstruct fb_info;\n\nstruct fb_event {\n\tstruct fb_info *info;\n\tvoid *data;\n};\n\nstruct fb_pixmap {\n\tu8 *addr;\n\tu32 size;\n\tu32 offset;\n\tu32 buf_align;\n\tu32 scan_align;\n\tu32 access_align;\n\tu32 flags;\n\tu32 blit_x;\n\tu32 blit_y;\n\tvoid (*writeio)(struct fb_info *, void *, void *, unsigned int);\n\tvoid (*readio)(struct fb_info *, void *, void *, unsigned int);\n};\n\nstruct fb_deferred_io;\n\nstruct fb_ops;\n\nstruct fb_tile_ops;\n\nstruct apertures_struct;\n\nstruct fb_info {\n\tatomic_t count;\n\tint node;\n\tint flags;\n\tint fbcon_rotate_hint;\n\tstruct mutex lock;\n\tstruct mutex mm_lock;\n\tstruct fb_var_screeninfo var;\n\tstruct fb_fix_screeninfo fix;\n\tstruct fb_monspecs monspecs;\n\tstruct work_struct queue;\n\tstruct fb_pixmap pixmap;\n\tstruct fb_pixmap sprite;\n\tstruct fb_cmap cmap;\n\tstruct list_head modelist;\n\tstruct fb_videomode *mode;\n\tstruct delayed_work deferred_work;\n\tstruct fb_deferred_io *fbdefio;\n\tconst struct fb_ops *fbops;\n\tstruct device *device;\n\tstruct device *dev;\n\tint class_flag;\n\tstruct fb_tile_ops *tileops;\n\tunion {\n\t\tchar *screen_base;\n\t\tchar *screen_buffer;\n\t};\n\tlong unsigned int screen_size;\n\tvoid *pseudo_palette;\n\tu32 state;\n\tvoid *fbcon_par;\n\tvoid *par;\n\tstruct apertures_struct *apertures;\n\tbool skip_vt_switch;\n};\n\nstruct fb_blit_caps {\n\tu32 x;\n\tu32 y;\n\tu32 len;\n\tu32 flags;\n};\n\nstruct fb_deferred_io {\n\tlong unsigned int delay;\n\tstruct mutex lock;\n\tstruct list_head pagelist;\n\tvoid (*first_io)(struct fb_info *);\n\tvoid (*deferred_io)(struct fb_info *, struct list_head *);\n};\n\nstruct fb_ops {\n\tstruct module *owner;\n\tint (*fb_open)(struct fb_info *, int);\n\tint (*fb_release)(struct fb_info *, int);\n\tssize_t (*fb_read)(struct fb_info *, char *, size_t, loff_t *);\n\tssize_t (*fb_write)(struct fb_info *, const char *, size_t, loff_t *);\n\tint (*fb_check_var)(struct fb_var_screeninfo *, struct fb_info *);\n\tint (*fb_set_par)(struct fb_info *);\n\tint (*fb_setcolreg)(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, struct fb_info *);\n\tint (*fb_setcmap)(struct fb_cmap *, struct fb_info *);\n\tint (*fb_blank)(int, struct fb_info *);\n\tint (*fb_pan_display)(struct fb_var_screeninfo *, struct fb_info *);\n\tvoid (*fb_fillrect)(struct fb_info *, const struct fb_fillrect *);\n\tvoid (*fb_copyarea)(struct fb_info *, const struct fb_copyarea *);\n\tvoid (*fb_imageblit)(struct fb_info *, const struct fb_image *);\n\tint (*fb_cursor)(struct fb_info *, struct fb_cursor *);\n\tint (*fb_sync)(struct fb_info *);\n\tint (*fb_ioctl)(struct fb_info *, unsigned int, long unsigned int);\n\tint (*fb_compat_ioctl)(struct fb_info *, unsigned int, long unsigned int);\n\tint (*fb_mmap)(struct fb_info *, struct vm_area_struct *);\n\tvoid (*fb_get_caps)(struct fb_info *, struct fb_blit_caps *, struct fb_var_screeninfo *);\n\tvoid (*fb_destroy)(struct fb_info *);\n\tint (*fb_debug_enter)(struct fb_info *);\n\tint (*fb_debug_leave)(struct fb_info *);\n};\n\nstruct fb_tilemap {\n\t__u32 width;\n\t__u32 height;\n\t__u32 depth;\n\t__u32 length;\n\tconst __u8 *data;\n};\n\nstruct fb_tilerect {\n\t__u32 sx;\n\t__u32 sy;\n\t__u32 width;\n\t__u32 height;\n\t__u32 index;\n\t__u32 fg;\n\t__u32 bg;\n\t__u32 rop;\n};\n\nstruct fb_tilearea {\n\t__u32 sx;\n\t__u32 sy;\n\t__u32 dx;\n\t__u32 dy;\n\t__u32 width;\n\t__u32 height;\n};\n\nstruct fb_tileblit {\n\t__u32 sx;\n\t__u32 sy;\n\t__u32 width;\n\t__u32 height;\n\t__u32 fg;\n\t__u32 bg;\n\t__u32 length;\n\t__u32 *indices;\n};\n\nstruct fb_tilecursor {\n\t__u32 sx;\n\t__u32 sy;\n\t__u32 mode;\n\t__u32 shape;\n\t__u32 fg;\n\t__u32 bg;\n};\n\nstruct fb_tile_ops {\n\tvoid (*fb_settile)(struct fb_info *, struct fb_tilemap *);\n\tvoid (*fb_tilecopy)(struct fb_info *, struct fb_tilearea *);\n\tvoid (*fb_tilefill)(struct fb_info *, struct fb_tilerect *);\n\tvoid (*fb_tileblit)(struct fb_info *, struct fb_tileblit *);\n\tvoid (*fb_tilecursor)(struct fb_info *, struct fb_tilecursor *);\n\tint (*fb_get_tilemax)(struct fb_info *);\n};\n\nstruct aperture {\n\tresource_size_t base;\n\tresource_size_t size;\n};\n\nstruct apertures_struct {\n\tunsigned int count;\n\tstruct aperture ranges[0];\n};\n\nenum backlight_update_reason {\n\tBACKLIGHT_UPDATE_HOTKEY = 0,\n\tBACKLIGHT_UPDATE_SYSFS = 1,\n};\n\nenum backlight_type {\n\tBACKLIGHT_RAW = 1,\n\tBACKLIGHT_PLATFORM = 2,\n\tBACKLIGHT_FIRMWARE = 3,\n\tBACKLIGHT_TYPE_MAX = 4,\n};\n\nenum backlight_notification {\n\tBACKLIGHT_REGISTERED = 0,\n\tBACKLIGHT_UNREGISTERED = 1,\n};\n\nenum backlight_scale {\n\tBACKLIGHT_SCALE_UNKNOWN = 0,\n\tBACKLIGHT_SCALE_LINEAR = 1,\n\tBACKLIGHT_SCALE_NON_LINEAR = 2,\n};\n\nstruct backlight_device;\n\nstruct backlight_ops {\n\tunsigned int options;\n\tint (*update_status)(struct backlight_device *);\n\tint (*get_brightness)(struct backlight_device *);\n\tint (*check_fb)(struct backlight_device *, struct fb_info *);\n};\n\nstruct backlight_properties {\n\tint brightness;\n\tint max_brightness;\n\tint power;\n\tint fb_blank;\n\tenum backlight_type type;\n\tunsigned int state;\n\tenum backlight_scale scale;\n};\n\nstruct backlight_device {\n\tstruct backlight_properties props;\n\tstruct mutex update_lock;\n\tstruct mutex ops_lock;\n\tconst struct backlight_ops *ops;\n\tstruct notifier_block fb_notif;\n\tstruct list_head entry;\n\tstruct device dev;\n\tbool fb_bl_on[32];\n\tint use_count;\n};\n\nstruct fb_cmap_user {\n\t__u32 start;\n\t__u32 len;\n\t__u16 *red;\n\t__u16 *green;\n\t__u16 *blue;\n\t__u16 *transp;\n};\n\nstruct fb_modelist {\n\tstruct list_head list;\n\tstruct fb_videomode mode;\n};\n\nstruct fb_fix_screeninfo32 {\n\tchar id[16];\n\tcompat_caddr_t smem_start;\n\tu32 smem_len;\n\tu32 type;\n\tu32 type_aux;\n\tu32 visual;\n\tu16 xpanstep;\n\tu16 ypanstep;\n\tu16 ywrapstep;\n\tu32 line_length;\n\tcompat_caddr_t mmio_start;\n\tu32 mmio_len;\n\tu32 accel;\n\tu16 reserved[3];\n};\n\nstruct fb_cmap32 {\n\tu32 start;\n\tu32 len;\n\tcompat_caddr_t red;\n\tcompat_caddr_t green;\n\tcompat_caddr_t blue;\n\tcompat_caddr_t transp;\n};\n\nstruct dmt_videomode {\n\tu32 dmt_id;\n\tu32 std_2byte_code;\n\tu32 cvt_3byte_code;\n\tconst struct fb_videomode *mode;\n};\n\nenum display_flags {\n\tDISPLAY_FLAGS_HSYNC_LOW = 1,\n\tDISPLAY_FLAGS_HSYNC_HIGH = 2,\n\tDISPLAY_FLAGS_VSYNC_LOW = 4,\n\tDISPLAY_FLAGS_VSYNC_HIGH = 8,\n\tDISPLAY_FLAGS_DE_LOW = 16,\n\tDISPLAY_FLAGS_DE_HIGH = 32,\n\tDISPLAY_FLAGS_PIXDATA_POSEDGE = 64,\n\tDISPLAY_FLAGS_PIXDATA_NEGEDGE = 128,\n\tDISPLAY_FLAGS_INTERLACED = 256,\n\tDISPLAY_FLAGS_DOUBLESCAN = 512,\n\tDISPLAY_FLAGS_DOUBLECLK = 1024,\n\tDISPLAY_FLAGS_SYNC_POSEDGE = 2048,\n\tDISPLAY_FLAGS_SYNC_NEGEDGE = 4096,\n};\n\nstruct videomode {\n\tlong unsigned int pixelclock;\n\tu32 hactive;\n\tu32 hfront_porch;\n\tu32 hback_porch;\n\tu32 hsync_len;\n\tu32 vactive;\n\tu32 vfront_porch;\n\tu32 vback_porch;\n\tu32 vsync_len;\n\tenum display_flags flags;\n};\n\nstruct broken_edid {\n\tu8 manufacturer[4];\n\tu32 model;\n\tu32 fix;\n};\n\nstruct __fb_timings {\n\tu32 dclk;\n\tu32 hfreq;\n\tu32 vfreq;\n\tu32 hactive;\n\tu32 vactive;\n\tu32 hblank;\n\tu32 vblank;\n\tu32 htotal;\n\tu32 vtotal;\n};\n\nstruct fb_cvt_data {\n\tu32 xres;\n\tu32 yres;\n\tu32 refresh;\n\tu32 f_refresh;\n\tu32 pixclock;\n\tu32 hperiod;\n\tu32 hblank;\n\tu32 hfreq;\n\tu32 htotal;\n\tu32 vtotal;\n\tu32 vsync;\n\tu32 hsync;\n\tu32 h_front_porch;\n\tu32 h_back_porch;\n\tu32 v_front_porch;\n\tu32 v_back_porch;\n\tu32 h_margin;\n\tu32 v_margin;\n\tu32 interlace;\n\tu32 aspect_ratio;\n\tu32 active_pixels;\n\tu32 flags;\n\tu32 status;\n};\n\ntypedef unsigned char u_char;\n\ntypedef short unsigned int u_short;\n\nstruct fb_con2fbmap {\n\t__u32 console;\n\t__u32 framebuffer;\n};\n\nstruct fbcon_display {\n\tconst u_char *fontdata;\n\tint userfont;\n\tu_short scrollmode;\n\tu_short inverse;\n\tshort int yscroll;\n\tint vrows;\n\tint cursor_shape;\n\tint con_rotate;\n\tu32 xres_virtual;\n\tu32 yres_virtual;\n\tu32 height;\n\tu32 width;\n\tu32 bits_per_pixel;\n\tu32 grayscale;\n\tu32 nonstd;\n\tu32 accel_flags;\n\tu32 rotate;\n\tstruct fb_bitfield red;\n\tstruct fb_bitfield green;\n\tstruct fb_bitfield blue;\n\tstruct fb_bitfield transp;\n\tconst struct fb_videomode *mode;\n};\n\nstruct fbcon_ops {\n\tvoid (*bmove)(struct vc_data *, struct fb_info *, int, int, int, int, int, int);\n\tvoid (*clear)(struct vc_data *, struct fb_info *, int, int, int, int);\n\tvoid (*putcs)(struct vc_data *, struct fb_info *, const short unsigned int *, int, int, int, int, int);\n\tvoid (*clear_margins)(struct vc_data *, struct fb_info *, int, int);\n\tvoid (*cursor)(struct vc_data *, struct fb_info *, int, int, int);\n\tint (*update_start)(struct fb_info *);\n\tint (*rotate_font)(struct fb_info *, struct vc_data *);\n\tstruct fb_var_screeninfo var;\n\tstruct timer_list cursor_timer;\n\tstruct fb_cursor cursor_state;\n\tstruct fbcon_display *p;\n\tstruct fb_info *info;\n\tint currcon;\n\tint cur_blink_jiffies;\n\tint cursor_flash;\n\tint cursor_reset;\n\tint blank_state;\n\tint graphics;\n\tint save_graphics;\n\tint flags;\n\tint rotate;\n\tint cur_rotate;\n\tchar *cursor_data;\n\tu8 *fontbuffer;\n\tu8 *fontdata;\n\tu8 *cursor_src;\n\tu32 cursor_size;\n\tu32 fd_size;\n};\n\nenum {\n\tFBCON_LOGO_CANSHOW = 4294967295,\n\tFBCON_LOGO_DRAW = 4294967294,\n\tFBCON_LOGO_DONTSHOW = 4294967293,\n};\n\nstruct vesafb_par {\n\tu32 pseudo_palette[256];\n\tint wc_cookie;\n\tstruct resource *region;\n};\n\nstruct acpi_table_bgrt {\n\tstruct acpi_table_header header;\n\tu16 version;\n\tu8 status;\n\tu8 image_type;\n\tu64 image_address;\n\tu32 image_offset_x;\n\tu32 image_offset_y;\n};\n\nenum drm_panel_orientation {\n\tDRM_MODE_PANEL_ORIENTATION_UNKNOWN = 4294967295,\n\tDRM_MODE_PANEL_ORIENTATION_NORMAL = 0,\n\tDRM_MODE_PANEL_ORIENTATION_BOTTOM_UP = 1,\n\tDRM_MODE_PANEL_ORIENTATION_LEFT_UP = 2,\n\tDRM_MODE_PANEL_ORIENTATION_RIGHT_UP = 3,\n};\n\nstruct bmp_file_header {\n\tu16 id;\n\tu32 file_size;\n\tu32 reserved;\n\tu32 bitmap_offset;\n} __attribute__((packed));\n\nstruct bmp_dib_header {\n\tu32 dib_header_size;\n\ts32 width;\n\ts32 height;\n\tu16 planes;\n\tu16 bpp;\n\tu32 compression;\n\tu32 bitmap_size;\n\tu32 horz_resolution;\n\tu32 vert_resolution;\n\tu32 colors_used;\n\tu32 colors_important;\n};\n\nstruct simplefb_format {\n\tconst char *name;\n\tu32 bits_per_pixel;\n\tstruct fb_bitfield red;\n\tstruct fb_bitfield green;\n\tstruct fb_bitfield blue;\n\tstruct fb_bitfield transp;\n\tu32 fourcc;\n};\n\nstruct simplefb_params {\n\tu32 width;\n\tu32 height;\n\tu32 stride;\n\tstruct simplefb_format *format;\n};\n\nstruct simplefb_par {\n\tu32 palette[16];\n};\n\nstruct timing_entry {\n\tu32 min;\n\tu32 typ;\n\tu32 max;\n};\n\nstruct display_timing {\n\tstruct timing_entry pixelclock;\n\tstruct timing_entry hactive;\n\tstruct timing_entry hfront_porch;\n\tstruct timing_entry hback_porch;\n\tstruct timing_entry hsync_len;\n\tstruct timing_entry vactive;\n\tstruct timing_entry vfront_porch;\n\tstruct timing_entry vback_porch;\n\tstruct timing_entry vsync_len;\n\tenum display_flags flags;\n};\n\nstruct display_timings {\n\tunsigned int num_timings;\n\tunsigned int native_mode;\n\tstruct display_timing **timings;\n};\n\nstruct thermal_cooling_device_ops;\n\nstruct thermal_cooling_device {\n\tint id;\n\tchar *type;\n\tstruct device device;\n\tstruct device_node *np;\n\tvoid *devdata;\n\tvoid *stats;\n\tconst struct thermal_cooling_device_ops *ops;\n\tbool updated;\n\tstruct mutex lock;\n\tstruct list_head thermal_instances;\n\tstruct list_head node;\n};\n\nstruct idle_cpu {\n\tstruct cpuidle_state *state_table;\n\tlong unsigned int auto_demotion_disable_flags;\n\tbool byt_auto_demotion_disable_flag;\n\tbool disable_promotion_to_c1e;\n\tbool use_acpi;\n};\n\nstruct thermal_cooling_device_ops {\n\tint (*get_max_state)(struct thermal_cooling_device *, long unsigned int *);\n\tint (*get_cur_state)(struct thermal_cooling_device *, long unsigned int *);\n\tint (*set_cur_state)(struct thermal_cooling_device *, long unsigned int);\n\tint (*get_requested_power)(struct thermal_cooling_device *, u32 *);\n\tint (*state2power)(struct thermal_cooling_device *, long unsigned int, u32 *);\n\tint (*power2state)(struct thermal_cooling_device *, u32, long unsigned int *);\n};\n\nstruct acpi_lpi_state {\n\tu32 min_residency;\n\tu32 wake_latency;\n\tu32 flags;\n\tu32 arch_flags;\n\tu32 res_cnt_freq;\n\tu32 enable_parent_state;\n\tu64 address;\n\tu8 index;\n\tu8 entry_method;\n\tchar desc[32];\n};\n\nstruct acpi_processor_power {\n\tint count;\n\tunion {\n\t\tstruct acpi_processor_cx states[8];\n\t\tstruct acpi_lpi_state lpi_states[8];\n\t};\n\tint timer_broadcast_on_state;\n};\n\nstruct acpi_psd_package {\n\tu64 num_entries;\n\tu64 revision;\n\tu64 domain;\n\tu64 coord_type;\n\tu64 num_processors;\n};\n\nstruct acpi_pct_register {\n\tu8 descriptor;\n\tu16 length;\n\tu8 space_id;\n\tu8 bit_width;\n\tu8 bit_offset;\n\tu8 reserved;\n\tu64 address;\n} __attribute__((packed));\n\nstruct acpi_processor_px {\n\tu64 core_frequency;\n\tu64 power;\n\tu64 transition_latency;\n\tu64 bus_master_latency;\n\tu64 control;\n\tu64 status;\n};\n\nstruct acpi_processor_performance {\n\tunsigned int state;\n\tunsigned int platform_limit;\n\tstruct acpi_pct_register control_register;\n\tstruct acpi_pct_register status_register;\n\tshort: 16;\n\tunsigned int state_count;\n\tint: 32;\n\tstruct acpi_processor_px *states;\n\tstruct acpi_psd_package domain_info;\n\tcpumask_var_t shared_cpu_map;\n\tunsigned int shared_type;\n\tint: 32;\n} __attribute__((packed));\n\nstruct acpi_tsd_package {\n\tu64 num_entries;\n\tu64 revision;\n\tu64 domain;\n\tu64 coord_type;\n\tu64 num_processors;\n};\n\nstruct acpi_processor_tx_tss {\n\tu64 freqpercentage;\n\tu64 power;\n\tu64 transition_latency;\n\tu64 control;\n\tu64 status;\n};\n\nstruct acpi_processor_tx {\n\tu16 power;\n\tu16 performance;\n};\n\nstruct acpi_processor;\n\nstruct acpi_processor_throttling {\n\tunsigned int state;\n\tunsigned int platform_limit;\n\tstruct acpi_pct_register control_register;\n\tstruct acpi_pct_register status_register;\n\tshort: 16;\n\tunsigned int state_count;\n\tint: 32;\n\tstruct acpi_processor_tx_tss *states_tss;\n\tstruct acpi_tsd_package domain_info;\n\tcpumask_var_t shared_cpu_map;\n\tint (*acpi_processor_get_throttling)(struct acpi_processor *);\n\tint (*acpi_processor_set_throttling)(struct acpi_processor *, int, bool);\n\tu32 address;\n\tu8 duty_offset;\n\tu8 duty_width;\n\tu8 tsd_valid_flag;\n\tchar: 8;\n\tunsigned int shared_type;\n\tstruct acpi_processor_tx states[16];\n\tint: 32;\n} __attribute__((packed));\n\nstruct acpi_processor_lx {\n\tint px;\n\tint tx;\n};\n\nstruct acpi_processor_limit {\n\tstruct acpi_processor_lx state;\n\tstruct acpi_processor_lx thermal;\n\tstruct acpi_processor_lx user;\n};\n\nstruct acpi_processor {\n\tacpi_handle handle;\n\tu32 acpi_id;\n\tphys_cpuid_t phys_id;\n\tu32 id;\n\tu32 pblk;\n\tint performance_platform_limit;\n\tint throttling_platform_limit;\n\tstruct acpi_processor_flags flags;\n\tstruct acpi_processor_power power;\n\tstruct acpi_processor_performance *performance;\n\tstruct acpi_processor_throttling throttling;\n\tstruct acpi_processor_limit limit;\n\tstruct thermal_cooling_device *cdev;\n\tstruct device *dev;\n\tstruct freq_qos_request perflib_req;\n\tstruct freq_qos_request thermal_req;\n};\n\nenum ipmi_addr_src {\n\tSI_INVALID = 0,\n\tSI_HOTMOD = 1,\n\tSI_HARDCODED = 2,\n\tSI_SPMI = 3,\n\tSI_ACPI = 4,\n\tSI_SMBIOS = 5,\n\tSI_PCI = 6,\n\tSI_DEVICETREE = 7,\n\tSI_PLATFORM = 8,\n\tSI_LAST = 9,\n};\n\nstruct dmi_header {\n\tu8 type;\n\tu8 length;\n\tu16 handle;\n};\n\nenum si_type {\n\tSI_TYPE_INVALID = 0,\n\tSI_KCS = 1,\n\tSI_SMIC = 2,\n\tSI_BT = 3,\n\tSI_TYPE_MAX = 4,\n};\n\nenum ipmi_addr_space {\n\tIPMI_IO_ADDR_SPACE = 0,\n\tIPMI_MEM_ADDR_SPACE = 1,\n};\n\nenum ipmi_plat_interface_type {\n\tIPMI_PLAT_IF_SI = 0,\n\tIPMI_PLAT_IF_SSIF = 1,\n};\n\nstruct ipmi_plat_data {\n\tenum ipmi_plat_interface_type iftype;\n\tunsigned int type;\n\tunsigned int space;\n\tlong unsigned int addr;\n\tunsigned int regspacing;\n\tunsigned int regsize;\n\tunsigned int regshift;\n\tunsigned int irq;\n\tunsigned int slave_addr;\n\tenum ipmi_addr_src addr_source;\n};\n\nstruct ipmi_dmi_info {\n\tenum si_type si_type;\n\tunsigned int space;\n\tlong unsigned int addr;\n\tu8 slave_addr;\n\tstruct ipmi_dmi_info *next;\n};\n\ntypedef u16 acpi_owner_id;\n\nunion acpi_name_union {\n\tu32 integer;\n\tchar ascii[4];\n};\n\nstruct acpi_table_desc {\n\tacpi_physical_address address;\n\tstruct acpi_table_header *pointer;\n\tu32 length;\n\tunion acpi_name_union signature;\n\tacpi_owner_id owner_id;\n\tu8 flags;\n\tu16 validation_count;\n};\n\nstruct acpi_madt_io_sapic {\n\tstruct acpi_subtable_header header;\n\tu8 id;\n\tu8 reserved;\n\tu32 global_irq_base;\n\tu64 address;\n};\n\nstruct acpi_madt_interrupt_source {\n\tstruct acpi_subtable_header header;\n\tu16 inti_flags;\n\tu8 type;\n\tu8 id;\n\tu8 eid;\n\tu8 io_sapic_vector;\n\tu32 global_irq;\n\tu32 flags;\n};\n\nstruct acpi_madt_generic_interrupt {\n\tstruct acpi_subtable_header header;\n\tu16 reserved;\n\tu32 cpu_interface_number;\n\tu32 uid;\n\tu32 flags;\n\tu32 parking_version;\n\tu32 performance_interrupt;\n\tu64 parked_address;\n\tu64 base_address;\n\tu64 gicv_base_address;\n\tu64 gich_base_address;\n\tu32 vgic_interrupt;\n\tu64 gicr_base_address;\n\tu64 arm_mpidr;\n\tu8 efficiency_class;\n\tu8 reserved2[1];\n\tu16 spe_interrupt;\n} __attribute__((packed));\n\nstruct acpi_madt_generic_distributor {\n\tstruct acpi_subtable_header header;\n\tu16 reserved;\n\tu32 gic_id;\n\tu64 base_address;\n\tu32 global_irq_base;\n\tu8 version;\n\tu8 reserved2[3];\n};\n\nenum acpi_subtable_type {\n\tACPI_SUBTABLE_COMMON = 0,\n\tACPI_SUBTABLE_HMAT = 1,\n\tACPI_SUBTABLE_PRMT = 2,\n};\n\nstruct acpi_subtable_entry {\n\tunion acpi_subtable_headers *hdr;\n\tenum acpi_subtable_type type;\n};\n\nenum acpi_predicate {\n\tall_versions = 0,\n\tless_than_or_equal = 1,\n\tequal = 2,\n\tgreater_than_or_equal = 3,\n};\n\nstruct acpi_platform_list {\n\tchar oem_id[7];\n\tchar oem_table_id[9];\n\tu32 oem_revision;\n\tchar *table;\n\tenum acpi_predicate pred;\n\tchar *reason;\n\tu32 data;\n};\n\ntypedef u32 (*acpi_interface_handler)(acpi_string, u32);\n\nstruct acpi_osi_entry {\n\tchar string[64];\n\tbool enable;\n};\n\nstruct acpi_osi_config {\n\tu8 default_disabling;\n\tunsigned int linux_enable: 1;\n\tunsigned int linux_dmi: 1;\n\tunsigned int linux_cmdline: 1;\n\tunsigned int darwin_enable: 1;\n\tunsigned int darwin_dmi: 1;\n\tunsigned int darwin_cmdline: 1;\n};\n\nstruct acpi_predefined_names {\n\tconst char *name;\n\tu8 type;\n\tchar *val;\n};\n\ntypedef u32 (*acpi_osd_handler)(void *);\n\ntypedef void (*acpi_osd_exec_callback)(void *);\n\ntypedef u32 (*acpi_gpe_handler)(acpi_handle, u32, void *);\n\nstruct acpi_pci_id {\n\tu16 segment;\n\tu16 bus;\n\tu16 device;\n\tu16 function;\n};\n\nstruct acpi_mem_mapping {\n\tacpi_physical_address physical_address;\n\tu8 *logical_address;\n\tacpi_size length;\n\tstruct acpi_mem_mapping *next_mm;\n};\n\nstruct acpi_mem_space_context {\n\tu32 length;\n\tacpi_physical_address address;\n\tstruct acpi_mem_mapping *cur_mm;\n\tstruct acpi_mem_mapping *first_mm;\n};\n\ntypedef enum {\n\tOSL_GLOBAL_LOCK_HANDLER = 0,\n\tOSL_NOTIFY_HANDLER = 1,\n\tOSL_GPE_HANDLER = 2,\n\tOSL_DEBUGGER_MAIN_THREAD = 3,\n\tOSL_DEBUGGER_EXEC_THREAD = 4,\n\tOSL_EC_POLL_HANDLER = 5,\n\tOSL_EC_BURST_HANDLER = 6,\n} acpi_execute_type;\n\nunion acpi_operand_object;\n\nstruct acpi_namespace_node {\n\tunion acpi_operand_object *object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 flags;\n\tunion acpi_name_union name;\n\tstruct acpi_namespace_node *parent;\n\tstruct acpi_namespace_node *child;\n\tstruct acpi_namespace_node *peer;\n\tacpi_owner_id owner_id;\n};\n\nstruct acpi_object_common {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n};\n\nstruct acpi_object_integer {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 fill[3];\n\tu64 value;\n};\n\nstruct acpi_object_string {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tchar *pointer;\n\tu32 length;\n};\n\nstruct acpi_object_buffer {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 *pointer;\n\tu32 length;\n\tu32 aml_length;\n\tu8 *aml_start;\n\tstruct acpi_namespace_node *node;\n};\n\nstruct acpi_object_package {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_operand_object **elements;\n\tu8 *aml_start;\n\tu32 aml_length;\n\tu32 count;\n};\n\nstruct acpi_object_event {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tvoid *os_semaphore;\n};\n\nstruct acpi_walk_state;\n\ntypedef acpi_status (*acpi_internal_method)(struct acpi_walk_state *);\n\nstruct acpi_object_method {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 info_flags;\n\tu8 param_count;\n\tu8 sync_level;\n\tunion acpi_operand_object *mutex;\n\tunion acpi_operand_object *node;\n\tu8 *aml_start;\n\tunion {\n\t\tacpi_internal_method implementation;\n\t\tunion acpi_operand_object *handler;\n\t} dispatch;\n\tu32 aml_length;\n\tacpi_owner_id owner_id;\n\tu8 thread_count;\n};\n\nstruct acpi_thread_state;\n\nstruct acpi_object_mutex {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 sync_level;\n\tu16 acquisition_depth;\n\tvoid *os_mutex;\n\tu64 thread_id;\n\tstruct acpi_thread_state *owner_thread;\n\tunion acpi_operand_object *prev;\n\tunion acpi_operand_object *next;\n\tstruct acpi_namespace_node *node;\n\tu8 original_sync_level;\n};\n\nstruct acpi_object_region {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 space_id;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_operand_object *handler;\n\tunion acpi_operand_object *next;\n\tacpi_physical_address address;\n\tu32 length;\n};\n\nstruct acpi_object_notify_common {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tunion acpi_operand_object *notify_list[2];\n\tunion acpi_operand_object *handler;\n};\n\nstruct acpi_gpe_block_info;\n\nstruct acpi_object_device {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tunion acpi_operand_object *notify_list[2];\n\tunion acpi_operand_object *handler;\n\tstruct acpi_gpe_block_info *gpe_block;\n};\n\nstruct acpi_object_power_resource {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tunion acpi_operand_object *notify_list[2];\n\tunion acpi_operand_object *handler;\n\tu32 system_level;\n\tu32 resource_order;\n};\n\nstruct acpi_object_processor {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 proc_id;\n\tu8 length;\n\tunion acpi_operand_object *notify_list[2];\n\tunion acpi_operand_object *handler;\n\tacpi_io_address address;\n};\n\nstruct acpi_object_thermal_zone {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tunion acpi_operand_object *notify_list[2];\n\tunion acpi_operand_object *handler;\n};\n\nstruct acpi_object_field_common {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 field_flags;\n\tu8 attribute;\n\tu8 access_byte_width;\n\tstruct acpi_namespace_node *node;\n\tu32 bit_length;\n\tu32 base_byte_offset;\n\tu32 value;\n\tu8 start_field_bit_offset;\n\tu8 access_length;\n\tunion acpi_operand_object *region_obj;\n};\n\nstruct acpi_object_region_field {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 field_flags;\n\tu8 attribute;\n\tu8 access_byte_width;\n\tstruct acpi_namespace_node *node;\n\tu32 bit_length;\n\tu32 base_byte_offset;\n\tu32 value;\n\tu8 start_field_bit_offset;\n\tu8 access_length;\n\tu16 resource_length;\n\tunion acpi_operand_object *region_obj;\n\tu8 *resource_buffer;\n\tu16 pin_number_index;\n\tu8 *internal_pcc_buffer;\n};\n\nstruct acpi_object_buffer_field {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 field_flags;\n\tu8 attribute;\n\tu8 access_byte_width;\n\tstruct acpi_namespace_node *node;\n\tu32 bit_length;\n\tu32 base_byte_offset;\n\tu32 value;\n\tu8 start_field_bit_offset;\n\tu8 access_length;\n\tu8 is_create_field;\n\tunion acpi_operand_object *buffer_obj;\n};\n\nstruct acpi_object_bank_field {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 field_flags;\n\tu8 attribute;\n\tu8 access_byte_width;\n\tstruct acpi_namespace_node *node;\n\tu32 bit_length;\n\tu32 base_byte_offset;\n\tu32 value;\n\tu8 start_field_bit_offset;\n\tu8 access_length;\n\tunion acpi_operand_object *region_obj;\n\tunion acpi_operand_object *bank_obj;\n};\n\nstruct acpi_object_index_field {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 field_flags;\n\tu8 attribute;\n\tu8 access_byte_width;\n\tstruct acpi_namespace_node *node;\n\tu32 bit_length;\n\tu32 base_byte_offset;\n\tu32 value;\n\tu8 start_field_bit_offset;\n\tu8 access_length;\n\tunion acpi_operand_object *index_obj;\n\tunion acpi_operand_object *data_obj;\n};\n\nstruct acpi_object_notify_handler {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tstruct acpi_namespace_node *node;\n\tu32 handler_type;\n\tacpi_notify_handler handler;\n\tvoid *context;\n\tunion acpi_operand_object *next[2];\n};\n\nstruct acpi_object_addr_handler {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 space_id;\n\tu8 handler_flags;\n\tacpi_adr_space_handler handler;\n\tstruct acpi_namespace_node *node;\n\tvoid *context;\n\tvoid *context_mutex;\n\tacpi_adr_space_setup setup;\n\tunion acpi_operand_object *region_list;\n\tunion acpi_operand_object *next;\n};\n\nstruct acpi_object_reference {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tu8 class;\n\tu8 target_type;\n\tu8 resolved;\n\tvoid *object;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_operand_object **where;\n\tu8 *index_pointer;\n\tu8 *aml;\n\tu32 value;\n};\n\nstruct acpi_object_extra {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tstruct acpi_namespace_node *method_REG;\n\tstruct acpi_namespace_node *scope_node;\n\tvoid *region_context;\n\tu8 *aml_start;\n\tu32 aml_length;\n};\n\nstruct acpi_object_data {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tacpi_object_handler handler;\n\tvoid *pointer;\n};\n\nstruct acpi_object_cache_list {\n\tunion acpi_operand_object *next_object;\n\tu8 descriptor_type;\n\tu8 type;\n\tu16 reference_count;\n\tu8 flags;\n\tunion acpi_operand_object *next;\n};\n\nunion acpi_operand_object {\n\tstruct acpi_object_common common;\n\tstruct acpi_object_integer integer;\n\tstruct acpi_object_string string;\n\tstruct acpi_object_buffer buffer;\n\tstruct acpi_object_package package;\n\tstruct acpi_object_event event;\n\tstruct acpi_object_method method;\n\tstruct acpi_object_mutex mutex;\n\tstruct acpi_object_region region;\n\tstruct acpi_object_notify_common common_notify;\n\tstruct acpi_object_device device;\n\tstruct acpi_object_power_resource power_resource;\n\tstruct acpi_object_processor processor;\n\tstruct acpi_object_thermal_zone thermal_zone;\n\tstruct acpi_object_field_common common_field;\n\tstruct acpi_object_region_field field;\n\tstruct acpi_object_buffer_field buffer_field;\n\tstruct acpi_object_bank_field bank_field;\n\tstruct acpi_object_index_field index_field;\n\tstruct acpi_object_notify_handler notify;\n\tstruct acpi_object_addr_handler address_space;\n\tstruct acpi_object_reference reference;\n\tstruct acpi_object_extra extra;\n\tstruct acpi_object_data data;\n\tstruct acpi_object_cache_list cache;\n\tstruct acpi_namespace_node node;\n};\n\nunion acpi_parse_object;\n\nunion acpi_generic_state;\n\nstruct acpi_parse_state {\n\tu8 *aml_start;\n\tu8 *aml;\n\tu8 *aml_end;\n\tu8 *pkg_start;\n\tu8 *pkg_end;\n\tunion acpi_parse_object *start_op;\n\tstruct acpi_namespace_node *start_node;\n\tunion acpi_generic_state *scope;\n\tunion acpi_parse_object *start_scope;\n\tu32 aml_size;\n};\n\ntypedef acpi_status (*acpi_parse_downwards)(struct acpi_walk_state *, union acpi_parse_object **);\n\ntypedef acpi_status (*acpi_parse_upwards)(struct acpi_walk_state *);\n\nstruct acpi_opcode_info;\n\nstruct acpi_walk_state {\n\tstruct acpi_walk_state *next;\n\tu8 descriptor_type;\n\tu8 walk_type;\n\tu16 opcode;\n\tu8 next_op_info;\n\tu8 num_operands;\n\tu8 operand_index;\n\tacpi_owner_id owner_id;\n\tu8 last_predicate;\n\tu8 current_result;\n\tu8 return_used;\n\tu8 scope_depth;\n\tu8 pass_number;\n\tu8 namespace_override;\n\tu8 result_size;\n\tu8 result_count;\n\tu8 *aml;\n\tu32 arg_types;\n\tu32 method_breakpoint;\n\tu32 user_breakpoint;\n\tu32 parse_flags;\n\tstruct acpi_parse_state parser_state;\n\tu32 prev_arg_types;\n\tu32 arg_count;\n\tu16 method_nesting_depth;\n\tu8 method_is_nested;\n\tstruct acpi_namespace_node arguments[7];\n\tstruct acpi_namespace_node local_variables[8];\n\tunion acpi_operand_object *operands[9];\n\tunion acpi_operand_object **params;\n\tu8 *aml_last_while;\n\tunion acpi_operand_object **caller_return_desc;\n\tunion acpi_generic_state *control_state;\n\tstruct acpi_namespace_node *deferred_node;\n\tunion acpi_operand_object *implicit_return_obj;\n\tstruct acpi_namespace_node *method_call_node;\n\tunion acpi_parse_object *method_call_op;\n\tunion acpi_operand_object *method_desc;\n\tstruct acpi_namespace_node *method_node;\n\tchar *method_pathname;\n\tunion acpi_parse_object *op;\n\tconst struct acpi_opcode_info *op_info;\n\tunion acpi_parse_object *origin;\n\tunion acpi_operand_object *result_obj;\n\tunion acpi_generic_state *results;\n\tunion acpi_operand_object *return_desc;\n\tunion acpi_generic_state *scope_info;\n\tunion acpi_parse_object *prev_op;\n\tunion acpi_parse_object *next_op;\n\tstruct acpi_thread_state *thread;\n\tacpi_parse_downwards descending_callback;\n\tacpi_parse_upwards ascending_callback;\n};\n\nstruct acpi_gpe_handler_info {\n\tacpi_gpe_handler address;\n\tvoid *context;\n\tstruct acpi_namespace_node *method_node;\n\tu8 original_flags;\n\tu8 originally_enabled;\n};\n\nstruct acpi_gpe_notify_info {\n\tstruct acpi_namespace_node *device_node;\n\tstruct acpi_gpe_notify_info *next;\n};\n\nunion acpi_gpe_dispatch_info {\n\tstruct acpi_namespace_node *method_node;\n\tstruct acpi_gpe_handler_info *handler;\n\tstruct acpi_gpe_notify_info *notify_list;\n};\n\nstruct acpi_gpe_register_info;\n\nstruct acpi_gpe_event_info {\n\tunion acpi_gpe_dispatch_info dispatch;\n\tstruct acpi_gpe_register_info *register_info;\n\tu8 flags;\n\tu8 gpe_number;\n\tu8 runtime_count;\n\tu8 disable_for_dispatch;\n};\n\nstruct acpi_gpe_address {\n\tu8 space_id;\n\tu64 address;\n};\n\nstruct acpi_gpe_register_info {\n\tstruct acpi_gpe_address status_address;\n\tstruct acpi_gpe_address enable_address;\n\tu16 base_gpe_number;\n\tu8 enable_for_wake;\n\tu8 enable_for_run;\n\tu8 mask_for_run;\n\tu8 enable_mask;\n};\n\nstruct acpi_gpe_xrupt_info;\n\nstruct acpi_gpe_block_info {\n\tstruct acpi_namespace_node *node;\n\tstruct acpi_gpe_block_info *previous;\n\tstruct acpi_gpe_block_info *next;\n\tstruct acpi_gpe_xrupt_info *xrupt_block;\n\tstruct acpi_gpe_register_info *register_info;\n\tstruct acpi_gpe_event_info *event_info;\n\tu64 address;\n\tu32 register_count;\n\tu16 gpe_count;\n\tu16 block_base_number;\n\tu8 space_id;\n\tu8 initialized;\n};\n\nstruct acpi_gpe_xrupt_info {\n\tstruct acpi_gpe_xrupt_info *previous;\n\tstruct acpi_gpe_xrupt_info *next;\n\tstruct acpi_gpe_block_info *gpe_block_list_head;\n\tu32 interrupt_number;\n};\n\nstruct acpi_common_state {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n};\n\nstruct acpi_update_state {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tunion acpi_operand_object *object;\n};\n\nstruct acpi_pkg_state {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tu32 index;\n\tunion acpi_operand_object *source_object;\n\tunion acpi_operand_object *dest_object;\n\tstruct acpi_walk_state *walk_state;\n\tvoid *this_target_obj;\n\tu32 num_packages;\n};\n\nstruct acpi_control_state {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tu16 opcode;\n\tunion acpi_parse_object *predicate_op;\n\tu8 *aml_predicate_start;\n\tu8 *package_end;\n\tu64 loop_timeout;\n};\n\nunion acpi_parse_value {\n\tu64 integer;\n\tu32 size;\n\tchar *string;\n\tu8 *buffer;\n\tchar *name;\n\tunion acpi_parse_object *arg;\n};\n\nstruct acpi_parse_obj_common {\n\tunion acpi_parse_object *parent;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 aml_opcode;\n\tu8 *aml;\n\tunion acpi_parse_object *next;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_parse_value value;\n\tu8 arg_list_length;\n\tu16 disasm_flags;\n\tu8 disasm_opcode;\n\tchar *operator_symbol;\n\tchar aml_op_name[16];\n};\n\nstruct acpi_parse_obj_named {\n\tunion acpi_parse_object *parent;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 aml_opcode;\n\tu8 *aml;\n\tunion acpi_parse_object *next;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_parse_value value;\n\tu8 arg_list_length;\n\tu16 disasm_flags;\n\tu8 disasm_opcode;\n\tchar *operator_symbol;\n\tchar aml_op_name[16];\n\tchar *path;\n\tu8 *data;\n\tu32 length;\n\tu32 name;\n};\n\nstruct acpi_parse_obj_asl {\n\tunion acpi_parse_object *parent;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 aml_opcode;\n\tu8 *aml;\n\tunion acpi_parse_object *next;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_parse_value value;\n\tu8 arg_list_length;\n\tu16 disasm_flags;\n\tu8 disasm_opcode;\n\tchar *operator_symbol;\n\tchar aml_op_name[16];\n\tunion acpi_parse_object *child;\n\tunion acpi_parse_object *parent_method;\n\tchar *filename;\n\tu8 file_changed;\n\tchar *parent_filename;\n\tchar *external_name;\n\tchar *namepath;\n\tchar name_seg[4];\n\tu32 extra_value;\n\tu32 column;\n\tu32 line_number;\n\tu32 logical_line_number;\n\tu32 logical_byte_offset;\n\tu32 end_line;\n\tu32 end_logical_line;\n\tu32 acpi_btype;\n\tu32 aml_length;\n\tu32 aml_subtree_length;\n\tu32 final_aml_length;\n\tu32 final_aml_offset;\n\tu32 compile_flags;\n\tu16 parse_opcode;\n\tu8 aml_opcode_length;\n\tu8 aml_pkg_len_bytes;\n\tu8 extra;\n\tchar parse_op_name[20];\n};\n\nunion acpi_parse_object {\n\tstruct acpi_parse_obj_common common;\n\tstruct acpi_parse_obj_named named;\n\tstruct acpi_parse_obj_asl asl;\n};\n\nstruct acpi_scope_state {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tstruct acpi_namespace_node *node;\n};\n\nstruct acpi_pscope_state {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tu32 arg_count;\n\tunion acpi_parse_object *op;\n\tu8 *arg_end;\n\tu8 *pkg_end;\n\tu32 arg_list;\n};\n\nstruct acpi_thread_state {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tu8 current_sync_level;\n\tstruct acpi_walk_state *walk_state_list;\n\tunion acpi_operand_object *acquired_mutex_list;\n\tu64 thread_id;\n};\n\nstruct acpi_result_values {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tunion acpi_operand_object *obj_desc[8];\n};\n\nstruct acpi_global_notify_handler {\n\tacpi_notify_handler handler;\n\tvoid *context;\n};\n\nstruct acpi_notify_info {\n\tvoid *next;\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 value;\n\tu16 state;\n\tu8 handler_list_id;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_operand_object *handler_list_head;\n\tstruct acpi_global_notify_handler *global;\n};\n\nunion acpi_generic_state {\n\tstruct acpi_common_state common;\n\tstruct acpi_control_state control;\n\tstruct acpi_update_state update;\n\tstruct acpi_scope_state scope;\n\tstruct acpi_pscope_state parse_scope;\n\tstruct acpi_pkg_state pkg;\n\tstruct acpi_thread_state thread;\n\tstruct acpi_result_values results;\n\tstruct acpi_notify_info notify;\n};\n\nstruct acpi_opcode_info {\n\tchar *name;\n\tu32 parse_args;\n\tu32 runtime_args;\n\tu16 flags;\n\tu8 object_type;\n\tu8 class;\n\tu8 type;\n};\n\nstruct acpi_os_dpc {\n\tacpi_osd_exec_callback function;\n\tvoid *context;\n\tstruct work_struct work;\n};\n\nstruct acpi_ioremap {\n\tstruct list_head list;\n\tvoid *virt;\n\tacpi_physical_address phys;\n\tacpi_size size;\n\tunion {\n\t\tlong unsigned int refcount;\n\t\tstruct rcu_work rwork;\n\t} track;\n};\n\nstruct acpi_hp_work {\n\tstruct work_struct work;\n\tstruct acpi_device *adev;\n\tu32 src;\n};\n\nstruct acpi_pld_info {\n\tu8 revision;\n\tu8 ignore_color;\n\tu8 red;\n\tu8 green;\n\tu8 blue;\n\tu16 width;\n\tu16 height;\n\tu8 user_visible;\n\tu8 dock;\n\tu8 lid;\n\tu8 panel;\n\tu8 vertical_position;\n\tu8 horizontal_position;\n\tu8 shape;\n\tu8 group_orientation;\n\tu8 group_token;\n\tu8 group_position;\n\tu8 bay;\n\tu8 ejectable;\n\tu8 ospm_eject_required;\n\tu8 cabinet_number;\n\tu8 card_cage_number;\n\tu8 reference;\n\tu8 rotation;\n\tu8 order;\n\tu8 reserved;\n\tu16 vertical_offset;\n\tu16 horizontal_offset;\n};\n\nstruct acpi_handle_list {\n\tu32 count;\n\tacpi_handle handles[10];\n};\n\nstruct acpi_device_bus_id {\n\tconst char *bus_id;\n\tstruct ida instance_ida;\n\tstruct list_head node;\n};\n\nstruct acpi_dev_match_info {\n\tstruct acpi_device_id hid[2];\n\tconst char *uid;\n\ts64 hrv;\n};\n\nstruct nvs_region {\n\t__u64 phys_start;\n\t__u64 size;\n\tstruct list_head node;\n};\n\nstruct nvs_page {\n\tlong unsigned int phys_start;\n\tunsigned int size;\n\tvoid *kaddr;\n\tvoid *data;\n\tbool unmap;\n\tstruct list_head node;\n};\n\nstruct acpi_wakeup_handler {\n\tstruct list_head list_node;\n\tbool (*wakeup)(void *);\n\tvoid *context;\n};\n\ntypedef u32 acpi_event_status;\n\nstruct acpi_table_facs {\n\tchar signature[4];\n\tu32 length;\n\tu32 hardware_signature;\n\tu32 firmware_waking_vector;\n\tu32 global_lock;\n\tu32 flags;\n\tu64 xfirmware_waking_vector;\n\tu8 version;\n\tu8 reserved[3];\n\tu32 ospm_flags;\n\tu8 reserved1[24];\n};\n\nstruct acpi_hardware_id {\n\tstruct list_head list;\n\tconst char *id;\n};\n\nstruct acpi_data_node {\n\tconst char *name;\n\tacpi_handle handle;\n\tstruct fwnode_handle fwnode;\n\tstruct fwnode_handle *parent;\n\tstruct acpi_device_data data;\n\tstruct list_head sibling;\n\tstruct kobject kobj;\n\tstruct completion kobj_done;\n};\n\nstruct acpi_data_node_attr {\n\tstruct attribute attr;\n\tssize_t (*show)(struct acpi_data_node *, char *);\n\tssize_t (*store)(struct acpi_data_node *, const char *, size_t);\n};\n\nstruct pm_domain_data {\n\tstruct list_head list_node;\n\tstruct device *dev;\n};\n\nstruct acpi_device_physical_node {\n\tunsigned int node_id;\n\tstruct list_head node;\n\tstruct device *dev;\n\tbool put_online: 1;\n};\n\ntypedef u32 (*acpi_event_handler)(void *);\n\ntypedef acpi_status (*acpi_table_handler)(u32, void *, void *);\n\nenum acpi_bus_device_type {\n\tACPI_BUS_TYPE_DEVICE = 0,\n\tACPI_BUS_TYPE_POWER = 1,\n\tACPI_BUS_TYPE_PROCESSOR = 2,\n\tACPI_BUS_TYPE_THERMAL = 3,\n\tACPI_BUS_TYPE_POWER_BUTTON = 4,\n\tACPI_BUS_TYPE_SLEEP_BUTTON = 5,\n\tACPI_BUS_TYPE_ECDT_EC = 6,\n\tACPI_BUS_DEVICE_TYPE_COUNT = 7,\n};\n\nstruct acpi_osc_context {\n\tchar *uuid_str;\n\tint rev;\n\tstruct acpi_buffer cap;\n\tstruct acpi_buffer ret;\n};\n\nstruct acpi_pnp_device_id {\n\tu32 length;\n\tchar *string;\n};\n\nstruct acpi_pnp_device_id_list {\n\tu32 count;\n\tu32 list_size;\n\tstruct acpi_pnp_device_id ids[0];\n};\n\nstruct acpi_device_info {\n\tu32 info_size;\n\tu32 name;\n\tacpi_object_type type;\n\tu8 param_count;\n\tu16 valid;\n\tu8 flags;\n\tu8 highest_dstates[4];\n\tu8 lowest_dstates[5];\n\tu64 address;\n\tstruct acpi_pnp_device_id hardware_id;\n\tstruct acpi_pnp_device_id unique_id;\n\tstruct acpi_pnp_device_id class_code;\n\tstruct acpi_pnp_device_id_list compatible_id_list;\n};\n\nstruct acpi_table_spcr {\n\tstruct acpi_table_header header;\n\tu8 interface_type;\n\tu8 reserved[3];\n\tstruct acpi_generic_address serial_port;\n\tu8 interrupt_type;\n\tu8 pc_interrupt;\n\tu32 interrupt;\n\tu8 baud_rate;\n\tu8 parity;\n\tu8 stop_bits;\n\tu8 flow_control;\n\tu8 terminal_type;\n\tu8 reserved1;\n\tu16 pci_device_id;\n\tu16 pci_vendor_id;\n\tu8 pci_bus;\n\tu8 pci_device;\n\tu8 pci_function;\n\tu32 pci_flags;\n\tu8 pci_segment;\n\tu32 reserved2;\n} __attribute__((packed));\n\nstruct acpi_table_stao {\n\tstruct acpi_table_header header;\n\tu8 ignore_uart;\n} __attribute__((packed));\n\nstruct acpi_dep_data {\n\tstruct list_head node;\n\tacpi_handle supplier;\n\tacpi_handle consumer;\n};\n\nenum acpi_reconfig_event {\n\tACPI_RECONFIG_DEVICE_ADD = 0,\n\tACPI_RECONFIG_DEVICE_REMOVE = 1,\n};\n\nstruct acpi_probe_entry;\n\ntypedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *, struct acpi_probe_entry *);\n\nstruct acpi_probe_entry {\n\t__u8 id[5];\n\t__u8 type;\n\tacpi_probe_entry_validate_subtbl subtable_valid;\n\tunion {\n\t\tacpi_tbl_table_handler probe_table;\n\t\tacpi_tbl_entry_handler probe_subtbl;\n\t};\n\tkernel_ulong_t driver_data;\n};\n\nstruct acpi_scan_clear_dep_work {\n\tstruct work_struct work;\n\tstruct acpi_device *adev;\n};\n\nstruct resource_win {\n\tstruct resource res;\n\tresource_size_t offset;\n};\n\nstruct res_proc_context {\n\tstruct list_head *list;\n\tint (*preproc)(struct acpi_resource *, void *);\n\tvoid *preproc_data;\n\tint count;\n\tint error;\n};\n\nstruct acpi_processor_errata {\n\tu8 smp;\n\tstruct {\n\t\tu8 throttle: 1;\n\t\tu8 fdma: 1;\n\t\tu8 reserved: 6;\n\t\tu32 bmisx;\n\t} piix4;\n};\n\nstruct acpi_table_ecdt {\n\tstruct acpi_table_header header;\n\tstruct acpi_generic_address control;\n\tstruct acpi_generic_address data;\n\tu32 uid;\n\tu8 gpe;\n\tu8 id[1];\n} __attribute__((packed));\n\nstruct transaction;\n\nstruct acpi_ec {\n\tacpi_handle handle;\n\tint gpe;\n\tint irq;\n\tlong unsigned int command_addr;\n\tlong unsigned int data_addr;\n\tbool global_lock;\n\tlong unsigned int flags;\n\tlong unsigned int reference_count;\n\tstruct mutex mutex;\n\twait_queue_head_t wait;\n\tstruct list_head list;\n\tstruct transaction *curr;\n\tspinlock_t lock;\n\tstruct work_struct work;\n\tlong unsigned int timestamp;\n\tlong unsigned int nr_pending_queries;\n\tbool busy_polling;\n\tunsigned int polling_guard;\n};\n\nstruct transaction {\n\tconst u8 *wdata;\n\tu8 *rdata;\n\tshort unsigned int irq_count;\n\tu8 command;\n\tu8 wi;\n\tu8 ri;\n\tu8 wlen;\n\tu8 rlen;\n\tu8 flags;\n};\n\ntypedef int (*acpi_ec_query_func)(void *);\n\nenum ec_command {\n\tACPI_EC_COMMAND_READ = 128,\n\tACPI_EC_COMMAND_WRITE = 129,\n\tACPI_EC_BURST_ENABLE = 130,\n\tACPI_EC_BURST_DISABLE = 131,\n\tACPI_EC_COMMAND_QUERY = 132,\n};\n\nenum {\n\tEC_FLAGS_QUERY_ENABLED = 0,\n\tEC_FLAGS_QUERY_PENDING = 1,\n\tEC_FLAGS_QUERY_GUARDING = 2,\n\tEC_FLAGS_EVENT_HANDLER_INSTALLED = 3,\n\tEC_FLAGS_EC_HANDLER_INSTALLED = 4,\n\tEC_FLAGS_QUERY_METHODS_INSTALLED = 5,\n\tEC_FLAGS_STARTED = 6,\n\tEC_FLAGS_STOPPED = 7,\n\tEC_FLAGS_EVENTS_MASKED = 8,\n};\n\nstruct acpi_ec_query_handler {\n\tstruct list_head node;\n\tacpi_ec_query_func func;\n\tacpi_handle handle;\n\tvoid *data;\n\tu8 query_bit;\n\tstruct kref kref;\n};\n\nstruct acpi_ec_query {\n\tstruct transaction transaction;\n\tstruct work_struct work;\n\tstruct acpi_ec_query_handler *handler;\n};\n\nstruct dock_station {\n\tacpi_handle handle;\n\tlong unsigned int last_dock_time;\n\tu32 flags;\n\tstruct list_head dependent_devices;\n\tstruct list_head sibling;\n\tstruct platform_device *dock_device;\n};\n\nstruct dock_dependent_device {\n\tstruct list_head list;\n\tstruct acpi_device *adev;\n};\n\nenum dock_callback_type {\n\tDOCK_CALL_HANDLER = 0,\n\tDOCK_CALL_FIXUP = 1,\n\tDOCK_CALL_UEVENT = 2,\n};\n\nstruct acpi_pci_root_ops;\n\nstruct acpi_pci_root_info {\n\tstruct acpi_pci_root *root;\n\tstruct acpi_device *bridge;\n\tstruct acpi_pci_root_ops *ops;\n\tstruct list_head resources;\n\tchar name[16];\n};\n\nstruct acpi_pci_root_ops {\n\tstruct pci_ops *pci_ops;\n\tint (*init_info)(struct acpi_pci_root_info *);\n\tvoid (*release_info)(struct acpi_pci_root_info *);\n\tint (*prepare_resources)(struct acpi_pci_root_info *);\n};\n\nstruct pci_osc_bit_struct {\n\tu32 bit;\n\tchar *desc;\n};\n\nstruct acpi_handle_node {\n\tstruct list_head node;\n\tacpi_handle handle;\n};\n\nstruct acpi_pci_link_irq {\n\tu32 active;\n\tu8 triggering;\n\tu8 polarity;\n\tu8 resource_type;\n\tu8 possible_count;\n\tu32 possible[16];\n\tu8 initialized: 1;\n\tu8 reserved: 7;\n};\n\nstruct acpi_pci_link {\n\tstruct list_head list;\n\tstruct acpi_device *device;\n\tstruct acpi_pci_link_irq irq;\n\tint refcnt;\n};\n\nstruct acpi_pci_routing_table {\n\tu32 length;\n\tu32 pin;\n\tu64 address;\n\tu32 source_index;\n\tchar source[4];\n};\n\nstruct acpi_prt_entry {\n\tstruct acpi_pci_id id;\n\tu8 pin;\n\tacpi_handle link;\n\tu32 index;\n};\n\nstruct prt_quirk {\n\tconst struct dmi_system_id *system;\n\tunsigned int segment;\n\tunsigned int bus;\n\tunsigned int device;\n\tunsigned char pin;\n\tconst char *source;\n\tconst char *actual_source;\n};\n\nstruct lpss_clk_data {\n\tconst char *name;\n\tstruct clk *clk;\n};\n\nstruct lpss_private_data;\n\nstruct lpss_device_desc {\n\tunsigned int flags;\n\tconst char *clk_con_id;\n\tunsigned int prv_offset;\n\tsize_t prv_size_override;\n\tstruct property_entry *properties;\n\tvoid (*setup)(struct lpss_private_data *);\n\tbool resume_from_noirq;\n};\n\nstruct lpss_private_data {\n\tstruct acpi_device *adev;\n\tvoid *mmio_base;\n\tresource_size_t mmio_size;\n\tunsigned int fixed_clk_rate;\n\tstruct clk *clk;\n\tconst struct lpss_device_desc *dev_desc;\n\tu32 prv_reg_ctx[9];\n};\n\nstruct lpss_device_links {\n\tconst char *supplier_hid;\n\tconst char *supplier_uid;\n\tconst char *consumer_hid;\n\tconst char *consumer_uid;\n\tu32 flags;\n\tconst struct dmi_system_id *dep_missing_ids;\n};\n\nstruct hid_uid {\n\tconst char *hid;\n\tconst char *uid;\n};\n\nstruct fch_clk_data {\n\tvoid *base;\n\tu32 is_rv;\n};\n\nstruct apd_private_data;\n\nstruct apd_device_desc {\n\tunsigned int fixed_clk_rate;\n\tstruct property_entry *properties;\n\tint (*setup)(struct apd_private_data *);\n};\n\nstruct apd_private_data {\n\tstruct clk *clk;\n\tstruct acpi_device *adev;\n\tconst struct apd_device_desc *dev_desc;\n};\n\nstruct acpi_power_dependent_device {\n\tstruct device *dev;\n\tstruct list_head node;\n};\n\nstruct acpi_power_resource {\n\tstruct acpi_device device;\n\tstruct list_head list_node;\n\tchar *name;\n\tu32 system_level;\n\tu32 order;\n\tunsigned int ref_count;\n\tu8 state;\n\tbool wakeup_enabled;\n\tstruct mutex resource_lock;\n\tstruct list_head dependents;\n};\n\nstruct acpi_power_resource_entry {\n\tstruct list_head node;\n\tstruct acpi_power_resource *resource;\n};\n\nstruct acpi_bus_event {\n\tstruct list_head node;\n\tacpi_device_class device_class;\n\tacpi_bus_id bus_id;\n\tu32 type;\n\tu32 data;\n};\n\nstruct acpi_genl_event {\n\tacpi_device_class device_class;\n\tchar bus_id[15];\n\tu32 type;\n\tu32 data;\n};\n\nenum {\n\tACPI_GENL_ATTR_UNSPEC = 0,\n\tACPI_GENL_ATTR_EVENT = 1,\n\t__ACPI_GENL_ATTR_MAX = 2,\n};\n\nenum {\n\tACPI_GENL_CMD_UNSPEC = 0,\n\tACPI_GENL_CMD_EVENT = 1,\n\t__ACPI_GENL_CMD_MAX = 2,\n};\n\nstruct acpi_ged_device {\n\tstruct device *dev;\n\tstruct list_head event_list;\n};\n\nstruct acpi_ged_event {\n\tstruct list_head node;\n\tstruct device *dev;\n\tunsigned int gsi;\n\tunsigned int irq;\n\tacpi_handle handle;\n};\n\ntypedef void (*acpi_gbl_event_handler)(u32, acpi_handle, u32, void *);\n\nstruct acpi_table_bert {\n\tstruct acpi_table_header header;\n\tu32 region_length;\n\tu64 address;\n};\n\nstruct acpi_dlayer {\n\tconst char *name;\n\tlong unsigned int value;\n};\n\nstruct acpi_dlevel {\n\tconst char *name;\n\tlong unsigned int value;\n};\n\nstruct acpi_table_attr {\n\tstruct bin_attribute attr;\n\tchar name[4];\n\tint instance;\n\tchar filename[8];\n\tstruct list_head node;\n};\n\nstruct acpi_data_attr {\n\tstruct bin_attribute attr;\n\tu64 addr;\n};\n\nstruct acpi_data_obj {\n\tchar *name;\n\tint (*fn)(void *, struct acpi_data_attr *);\n};\n\nstruct event_counter {\n\tu32 count;\n\tu32 flags;\n};\n\nstruct acpi_device_properties {\n\tconst guid_t *guid;\n\tconst union acpi_object *properties;\n\tstruct list_head list;\n};\n\nstruct always_present_id {\n\tstruct acpi_device_id hid[2];\n\tstruct x86_cpu_id cpu_ids[2];\n\tstruct dmi_system_id dmi_ids[2];\n\tconst char *uid;\n};\n\nstruct lpi_device_info {\n\tchar *name;\n\tint enabled;\n\tunion acpi_object *package;\n};\n\nstruct lpi_device_constraint {\n\tint uid;\n\tint min_dstate;\n\tint function_states;\n};\n\nstruct lpi_constraints {\n\tacpi_handle handle;\n\tint min_dstate;\n};\n\nstruct lpi_device_constraint_amd {\n\tchar *name;\n\tint enabled;\n\tint function_states;\n\tint min_dstate;\n};\n\nstruct acpi_lpat {\n\tint temp;\n\tint raw;\n};\n\nstruct acpi_lpat_conversion_table {\n\tstruct acpi_lpat *lpat;\n\tint lpat_count;\n};\n\nenum fpdt_subtable_type {\n\tSUBTABLE_FBPT = 0,\n\tSUBTABLE_S3PT = 1,\n};\n\nstruct fpdt_subtable_entry {\n\tu16 type;\n\tu8 length;\n\tu8 revision;\n\tu32 reserved;\n\tu64 address;\n};\n\nstruct fpdt_subtable_header {\n\tu32 signature;\n\tu32 length;\n};\n\nenum fpdt_record_type {\n\tRECORD_S3_RESUME = 0,\n\tRECORD_S3_SUSPEND = 1,\n\tRECORD_BOOT = 2,\n};\n\nstruct fpdt_record_header {\n\tu16 type;\n\tu8 length;\n\tu8 revision;\n};\n\nstruct resume_performance_record {\n\tstruct fpdt_record_header header;\n\tu32 resume_count;\n\tu64 resume_prev;\n\tu64 resume_avg;\n};\n\nstruct boot_performance_record {\n\tstruct fpdt_record_header header;\n\tu32 reserved;\n\tu64 firmware_start;\n\tu64 bootloader_load;\n\tu64 bootloader_launch;\n\tu64 exitbootservice_start;\n\tu64 exitbootservice_end;\n};\n\nstruct suspend_performance_record {\n\tstruct fpdt_record_header header;\n\tu64 suspend_start;\n\tu64 suspend_end;\n} __attribute__((packed));\n\nstruct acpi_table_lpit {\n\tstruct acpi_table_header header;\n};\n\nstruct acpi_lpit_header {\n\tu32 type;\n\tu32 length;\n\tu16 unique_id;\n\tu16 reserved;\n\tu32 flags;\n};\n\nstruct acpi_lpit_native {\n\tstruct acpi_lpit_header header;\n\tstruct acpi_generic_address entry_trigger;\n\tu32 residency;\n\tu32 latency;\n\tstruct acpi_generic_address residency_counter;\n\tu64 counter_frequency;\n} __attribute__((packed));\n\nstruct lpit_residency_info {\n\tstruct acpi_generic_address gaddr;\n\tu64 frequency;\n\tvoid *iomem_addr;\n};\n\nstruct acpi_table_wdat {\n\tstruct acpi_table_header header;\n\tu32 header_length;\n\tu16 pci_segment;\n\tu8 pci_bus;\n\tu8 pci_device;\n\tu8 pci_function;\n\tu8 reserved[3];\n\tu32 timer_period;\n\tu32 max_count;\n\tu32 min_count;\n\tu8 flags;\n\tu8 reserved2[3];\n\tu32 entries;\n};\n\nstruct acpi_wdat_entry {\n\tu8 action;\n\tu8 instruction;\n\tu16 reserved;\n\tstruct acpi_generic_address register_region;\n\tu32 value;\n\tu32 mask;\n} __attribute__((packed));\n\ntypedef u64 acpi_integer;\n\nstruct acpi_prmt_module_info {\n\tu16 revision;\n\tu16 length;\n\tu8 module_guid[16];\n\tu16 major_rev;\n\tu16 minor_rev;\n\tu16 handler_info_count;\n\tu32 handler_info_offset;\n\tu64 mmio_list_pointer;\n} __attribute__((packed));\n\nstruct acpi_prmt_handler_info {\n\tu16 revision;\n\tu16 length;\n\tu8 handler_guid[16];\n\tu64 handler_address;\n\tu64 static_data_buffer_address;\n\tu64 acpi_param_buffer_address;\n} __attribute__((packed));\n\nstruct prm_mmio_addr_range {\n\tu64 phys_addr;\n\tu64 virt_addr;\n\tu32 length;\n} __attribute__((packed));\n\nstruct prm_mmio_info {\n\tu64 mmio_count;\n\tstruct prm_mmio_addr_range addr_ranges[0];\n};\n\nstruct prm_buffer {\n\tu8 prm_status;\n\tu64 efi_status;\n\tu8 prm_cmd;\n\tguid_t handler_guid;\n} __attribute__((packed));\n\nstruct prm_context_buffer {\n\tchar signature[4];\n\tu16 revision;\n\tu16 reserved;\n\tguid_t identifier;\n\tu64 static_data_buffer;\n\tstruct prm_mmio_info *mmio_ranges;\n};\n\nstruct prm_handler_info {\n\tguid_t guid;\n\tu64 handler_addr;\n\tu64 static_data_buffer_addr;\n\tu64 acpi_param_buffer_addr;\n\tstruct list_head handler_list;\n};\n\nstruct prm_module_info {\n\tguid_t guid;\n\tu16 major_rev;\n\tu16 minor_rev;\n\tu16 handler_count;\n\tstruct prm_mmio_info *mmio_info;\n\tbool updatable;\n\tstruct list_head module_list;\n\tstruct prm_handler_info handlers[0];\n};\n\nstruct acpi_name_info {\n\tchar name[4];\n\tu16 argument_list;\n\tu8 expected_btypes;\n} __attribute__((packed));\n\nstruct acpi_package_info {\n\tu8 type;\n\tu8 object_type1;\n\tu8 count1;\n\tu8 object_type2;\n\tu8 count2;\n\tu16 reserved;\n} __attribute__((packed));\n\nstruct acpi_package_info2 {\n\tu8 type;\n\tu8 count;\n\tu8 object_type[4];\n\tu8 reserved;\n};\n\nstruct acpi_package_info3 {\n\tu8 type;\n\tu8 count;\n\tu8 object_type[2];\n\tu8 tail_object_type;\n\tu16 reserved;\n} __attribute__((packed));\n\nstruct acpi_package_info4 {\n\tu8 type;\n\tu8 object_type1;\n\tu8 count1;\n\tu8 sub_object_types;\n\tu8 pkg_count;\n\tu16 reserved;\n} __attribute__((packed));\n\nunion acpi_predefined_info {\n\tstruct acpi_name_info info;\n\tstruct acpi_package_info ret_info;\n\tstruct acpi_package_info2 ret_info2;\n\tstruct acpi_package_info3 ret_info3;\n\tstruct acpi_package_info4 ret_info4;\n};\n\nstruct acpi_evaluate_info {\n\tstruct acpi_namespace_node *prefix_node;\n\tconst char *relative_pathname;\n\tunion acpi_operand_object **parameters;\n\tstruct acpi_namespace_node *node;\n\tunion acpi_operand_object *obj_desc;\n\tchar *full_pathname;\n\tconst union acpi_predefined_info *predefined;\n\tunion acpi_operand_object *return_object;\n\tunion acpi_operand_object *parent_package;\n\tu32 return_flags;\n\tu32 return_btype;\n\tu16 param_count;\n\tu16 node_flags;\n\tu8 pass_number;\n\tu8 return_object_type;\n\tu8 flags;\n};\n\nenum {\n\tACPI_REFCLASS_LOCAL = 0,\n\tACPI_REFCLASS_ARG = 1,\n\tACPI_REFCLASS_REFOF = 2,\n\tACPI_REFCLASS_INDEX = 3,\n\tACPI_REFCLASS_TABLE = 4,\n\tACPI_REFCLASS_NAME = 5,\n\tACPI_REFCLASS_DEBUG = 6,\n\tACPI_REFCLASS_MAX = 6,\n};\n\nstruct acpi_common_descriptor {\n\tvoid *common_pointer;\n\tu8 descriptor_type;\n};\n\nunion acpi_descriptor {\n\tstruct acpi_common_descriptor common;\n\tunion acpi_operand_object object;\n\tstruct acpi_namespace_node node;\n\tunion acpi_parse_object op;\n};\n\ntypedef enum {\n\tACPI_IMODE_LOAD_PASS1 = 1,\n\tACPI_IMODE_LOAD_PASS2 = 2,\n\tACPI_IMODE_EXECUTE = 3,\n} acpi_interpreter_mode;\n\nstruct acpi_create_field_info {\n\tstruct acpi_namespace_node *region_node;\n\tstruct acpi_namespace_node *field_node;\n\tstruct acpi_namespace_node *register_node;\n\tstruct acpi_namespace_node *data_register_node;\n\tstruct acpi_namespace_node *connection_node;\n\tu8 *resource_buffer;\n\tu32 bank_value;\n\tu32 field_bit_position;\n\tu32 field_bit_length;\n\tu16 resource_length;\n\tu16 pin_number_index;\n\tu8 field_flags;\n\tu8 attribute;\n\tu8 field_type;\n\tu8 access_length;\n};\n\nstruct acpi_init_walk_info {\n\tu32 table_index;\n\tu32 object_count;\n\tu32 method_count;\n\tu32 serial_method_count;\n\tu32 non_serial_method_count;\n\tu32 serialized_method_count;\n\tu32 device_count;\n\tu32 op_region_count;\n\tu32 field_count;\n\tu32 buffer_count;\n\tu32 package_count;\n\tu32 op_region_init;\n\tu32 field_init;\n\tu32 buffer_init;\n\tu32 package_init;\n\tacpi_owner_id owner_id;\n};\n\ntypedef u32 acpi_name;\n\ntypedef acpi_status (*acpi_exception_handler)(acpi_status, acpi_name, u16, u32, void *);\n\nenum {\n\tAML_FIELD_ACCESS_ANY = 0,\n\tAML_FIELD_ACCESS_BYTE = 1,\n\tAML_FIELD_ACCESS_WORD = 2,\n\tAML_FIELD_ACCESS_DWORD = 3,\n\tAML_FIELD_ACCESS_QWORD = 4,\n\tAML_FIELD_ACCESS_BUFFER = 5,\n};\n\ntypedef acpi_status (*acpi_execute_op)(struct acpi_walk_state *);\n\nstruct acpi_fixed_event_handler {\n\tacpi_event_handler handler;\n\tvoid *context;\n};\n\nstruct acpi_fixed_event_info {\n\tu8 status_register_id;\n\tu8 enable_register_id;\n\tu16 status_bit_mask;\n\tu16 enable_bit_mask;\n};\n\ntypedef u32 acpi_mutex_handle;\n\nstruct acpi_gpe_walk_info {\n\tstruct acpi_namespace_node *gpe_device;\n\tstruct acpi_gpe_block_info *gpe_block;\n\tu16 count;\n\tacpi_owner_id owner_id;\n\tu8 execute_by_owner_id;\n};\n\nstruct acpi_gpe_device_info {\n\tu32 index;\n\tu32 next_block_base_index;\n\tacpi_status status;\n\tstruct acpi_namespace_node *gpe_device;\n};\n\ntypedef acpi_status (*acpi_gpe_callback)(struct acpi_gpe_xrupt_info *, struct acpi_gpe_block_info *, void *);\n\nstruct acpi_reg_walk_info {\n\tu32 function;\n\tu32 reg_run_count;\n\tacpi_adr_space_type space_id;\n};\n\ntypedef u32 (*acpi_sci_handler)(void *);\n\nstruct acpi_sci_handler_info {\n\tstruct acpi_sci_handler_info *next;\n\tacpi_sci_handler address;\n\tvoid *context;\n};\n\nstruct acpi_exdump_info {\n\tu8 opcode;\n\tu8 offset;\n\tconst char *name;\n} __attribute__((packed));\n\nenum {\n\tAML_FIELD_UPDATE_PRESERVE = 0,\n\tAML_FIELD_UPDATE_WRITE_AS_ONES = 32,\n\tAML_FIELD_UPDATE_WRITE_AS_ZEROS = 64,\n};\n\nstruct acpi_signal_fatal_info {\n\tu32 type;\n\tu32 code;\n\tu32 argument;\n};\n\nenum {\n\tMATCH_MTR = 0,\n\tMATCH_MEQ = 1,\n\tMATCH_MLE = 2,\n\tMATCH_MLT = 3,\n\tMATCH_MGE = 4,\n\tMATCH_MGT = 5,\n};\n\nenum {\n\tAML_FIELD_ATTRIB_QUICK = 2,\n\tAML_FIELD_ATTRIB_SEND_RECEIVE = 4,\n\tAML_FIELD_ATTRIB_BYTE = 6,\n\tAML_FIELD_ATTRIB_WORD = 8,\n\tAML_FIELD_ATTRIB_BLOCK = 10,\n\tAML_FIELD_ATTRIB_BYTES = 11,\n\tAML_FIELD_ATTRIB_PROCESS_CALL = 12,\n\tAML_FIELD_ATTRIB_BLOCK_PROCESS_CALL = 13,\n\tAML_FIELD_ATTRIB_RAW_BYTES = 14,\n\tAML_FIELD_ATTRIB_RAW_PROCESS_BYTES = 15,\n};\n\ntypedef enum {\n\tACPI_TRACE_AML_METHOD = 0,\n\tACPI_TRACE_AML_OPCODE = 1,\n\tACPI_TRACE_AML_REGION = 2,\n} acpi_trace_event_type;\n\nstruct acpi_gpe_block_status_context {\n\tstruct acpi_gpe_register_info *gpe_skip_register_info;\n\tu8 gpe_skip_mask;\n\tu8 retval;\n};\n\nstruct acpi_bit_register_info {\n\tu8 parent_register;\n\tu8 bit_position;\n\tu16 access_bit_mask;\n};\n\nstruct acpi_port_info {\n\tchar *name;\n\tu16 start;\n\tu16 end;\n\tu8 osi_dependency;\n};\n\nstruct acpi_pci_device {\n\tacpi_handle device;\n\tstruct acpi_pci_device *next;\n};\n\nstruct acpi_walk_info {\n\tu32 debug_level;\n\tu32 count;\n\tacpi_owner_id owner_id;\n\tu8 display_type;\n};\n\ntypedef acpi_status (*acpi_init_handler)(acpi_handle, u32);\n\nstruct acpi_device_walk_info {\n\tstruct acpi_table_desc *table_desc;\n\tstruct acpi_evaluate_info *evaluate_info;\n\tu32 device_count;\n\tu32 num_STA;\n\tu32 num_INI;\n};\n\ntypedef acpi_status (*acpi_pkg_callback)(u8, union acpi_operand_object *, union acpi_generic_state *, void *);\n\nstruct acpi_table_list {\n\tstruct acpi_table_desc *tables;\n\tu32 current_table_count;\n\tu32 max_table_count;\n\tu8 flags;\n};\n\nenum acpi_return_package_types {\n\tACPI_PTYPE1_FIXED = 1,\n\tACPI_PTYPE1_VAR = 2,\n\tACPI_PTYPE1_OPTION = 3,\n\tACPI_PTYPE2 = 4,\n\tACPI_PTYPE2_COUNT = 5,\n\tACPI_PTYPE2_PKG_COUNT = 6,\n\tACPI_PTYPE2_FIXED = 7,\n\tACPI_PTYPE2_MIN = 8,\n\tACPI_PTYPE2_REV_FIXED = 9,\n\tACPI_PTYPE2_FIX_VAR = 10,\n\tACPI_PTYPE2_VAR_VAR = 11,\n\tACPI_PTYPE2_UUID_PAIR = 12,\n\tACPI_PTYPE_CUSTOM = 13,\n};\n\ntypedef acpi_status (*acpi_object_converter)(struct acpi_namespace_node *, union acpi_operand_object *, union acpi_operand_object **);\n\nstruct acpi_simple_repair_info {\n\tchar name[4];\n\tu32 unexpected_btypes;\n\tu32 package_index;\n\tacpi_object_converter object_converter;\n};\n\ntypedef acpi_status (*acpi_repair_function)(struct acpi_evaluate_info *, union acpi_operand_object **);\n\nstruct acpi_repair_info {\n\tchar name[4];\n\tacpi_repair_function repair_function;\n};\n\nstruct acpi_namestring_info {\n\tconst char *external_name;\n\tconst char *next_external_char;\n\tchar *internal_name;\n\tu32 length;\n\tu32 num_segments;\n\tu32 num_carats;\n\tu8 fully_qualified;\n};\n\nstruct acpi_rw_lock {\n\tvoid *writer_mutex;\n\tvoid *reader_mutex;\n\tu32 num_readers;\n};\n\nstruct acpi_get_devices_info {\n\tacpi_walk_callback user_function;\n\tvoid *context;\n\tconst char *hid;\n};\n\nstruct aml_resource_small_header {\n\tu8 descriptor_type;\n};\n\nstruct aml_resource_irq {\n\tu8 descriptor_type;\n\tu16 irq_mask;\n\tu8 flags;\n} __attribute__((packed));\n\nstruct aml_resource_dma {\n\tu8 descriptor_type;\n\tu8 dma_channel_mask;\n\tu8 flags;\n};\n\nstruct aml_resource_start_dependent {\n\tu8 descriptor_type;\n\tu8 flags;\n};\n\nstruct aml_resource_end_dependent {\n\tu8 descriptor_type;\n};\n\nstruct aml_resource_io {\n\tu8 descriptor_type;\n\tu8 flags;\n\tu16 minimum;\n\tu16 maximum;\n\tu8 alignment;\n\tu8 address_length;\n};\n\nstruct aml_resource_fixed_io {\n\tu8 descriptor_type;\n\tu16 address;\n\tu8 address_length;\n} __attribute__((packed));\n\nstruct aml_resource_vendor_small {\n\tu8 descriptor_type;\n};\n\nstruct aml_resource_end_tag {\n\tu8 descriptor_type;\n\tu8 checksum;\n};\n\nstruct aml_resource_fixed_dma {\n\tu8 descriptor_type;\n\tu16 request_lines;\n\tu16 channels;\n\tu8 width;\n} __attribute__((packed));\n\nstruct aml_resource_large_header {\n\tu8 descriptor_type;\n\tu16 resource_length;\n} __attribute__((packed));\n\nstruct aml_resource_memory24 {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 flags;\n\tu16 minimum;\n\tu16 maximum;\n\tu16 alignment;\n\tu16 address_length;\n} __attribute__((packed));\n\nstruct aml_resource_vendor_large {\n\tu8 descriptor_type;\n\tu16 resource_length;\n} __attribute__((packed));\n\nstruct aml_resource_memory32 {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 flags;\n\tu32 minimum;\n\tu32 maximum;\n\tu32 alignment;\n\tu32 address_length;\n} __attribute__((packed));\n\nstruct aml_resource_fixed_memory32 {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 flags;\n\tu32 address;\n\tu32 address_length;\n} __attribute__((packed));\n\nstruct aml_resource_address {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 resource_type;\n\tu8 flags;\n\tu8 specific_flags;\n} __attribute__((packed));\n\nstruct aml_resource_extended_address64 {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 resource_type;\n\tu8 flags;\n\tu8 specific_flags;\n\tu8 revision_ID;\n\tu8 reserved;\n\tu64 granularity;\n\tu64 minimum;\n\tu64 maximum;\n\tu64 translation_offset;\n\tu64 address_length;\n\tu64 type_specific;\n} __attribute__((packed));\n\nstruct aml_resource_address64 {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 resource_type;\n\tu8 flags;\n\tu8 specific_flags;\n\tu64 granularity;\n\tu64 minimum;\n\tu64 maximum;\n\tu64 translation_offset;\n\tu64 address_length;\n} __attribute__((packed));\n\nstruct aml_resource_address32 {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 resource_type;\n\tu8 flags;\n\tu8 specific_flags;\n\tu32 granularity;\n\tu32 minimum;\n\tu32 maximum;\n\tu32 translation_offset;\n\tu32 address_length;\n} __attribute__((packed));\n\nstruct aml_resource_address16 {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 resource_type;\n\tu8 flags;\n\tu8 specific_flags;\n\tu16 granularity;\n\tu16 minimum;\n\tu16 maximum;\n\tu16 translation_offset;\n\tu16 address_length;\n} __attribute__((packed));\n\nstruct aml_resource_extended_irq {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 flags;\n\tu8 interrupt_count;\n\tu32 interrupts[1];\n} __attribute__((packed));\n\nstruct aml_resource_generic_register {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 address_space_id;\n\tu8 bit_width;\n\tu8 bit_offset;\n\tu8 access_size;\n\tu64 address;\n} __attribute__((packed));\n\nstruct aml_resource_gpio {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu8 connection_type;\n\tu16 flags;\n\tu16 int_flags;\n\tu8 pin_config;\n\tu16 drive_strength;\n\tu16 debounce_timeout;\n\tu16 pin_table_offset;\n\tu8 res_source_index;\n\tu16 res_source_offset;\n\tu16 vendor_offset;\n\tu16 vendor_length;\n} __attribute__((packed));\n\nstruct aml_resource_common_serialbus {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu8 res_source_index;\n\tu8 type;\n\tu8 flags;\n\tu16 type_specific_flags;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n} __attribute__((packed));\n\nstruct aml_resource_csi2_serialbus {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu8 res_source_index;\n\tu8 type;\n\tu8 flags;\n\tu16 type_specific_flags;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n} __attribute__((packed));\n\nstruct aml_resource_i2c_serialbus {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu8 res_source_index;\n\tu8 type;\n\tu8 flags;\n\tu16 type_specific_flags;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu32 connection_speed;\n\tu16 slave_address;\n} __attribute__((packed));\n\nstruct aml_resource_spi_serialbus {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu8 res_source_index;\n\tu8 type;\n\tu8 flags;\n\tu16 type_specific_flags;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu32 connection_speed;\n\tu8 data_bit_length;\n\tu8 clock_phase;\n\tu8 clock_polarity;\n\tu16 device_selection;\n} __attribute__((packed));\n\nstruct aml_resource_uart_serialbus {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu8 res_source_index;\n\tu8 type;\n\tu8 flags;\n\tu16 type_specific_flags;\n\tu8 type_revision_id;\n\tu16 type_data_length;\n\tu32 default_baud_rate;\n\tu16 rx_fifo_size;\n\tu16 tx_fifo_size;\n\tu8 parity;\n\tu8 lines_enabled;\n} __attribute__((packed));\n\nstruct aml_resource_pin_function {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu16 flags;\n\tu8 pin_config;\n\tu16 function_number;\n\tu16 pin_table_offset;\n\tu8 res_source_index;\n\tu16 res_source_offset;\n\tu16 vendor_offset;\n\tu16 vendor_length;\n} __attribute__((packed));\n\nstruct aml_resource_pin_config {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu16 flags;\n\tu8 pin_config_type;\n\tu32 pin_config_value;\n\tu16 pin_table_offset;\n\tu8 res_source_index;\n\tu16 res_source_offset;\n\tu16 vendor_offset;\n\tu16 vendor_length;\n} __attribute__((packed));\n\nstruct aml_resource_pin_group {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu16 flags;\n\tu16 pin_table_offset;\n\tu16 label_offset;\n\tu16 vendor_offset;\n\tu16 vendor_length;\n} __attribute__((packed));\n\nstruct aml_resource_pin_group_function {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu16 flags;\n\tu16 function_number;\n\tu8 res_source_index;\n\tu16 res_source_offset;\n\tu16 res_source_label_offset;\n\tu16 vendor_offset;\n\tu16 vendor_length;\n} __attribute__((packed));\n\nstruct aml_resource_pin_group_config {\n\tu8 descriptor_type;\n\tu16 resource_length;\n\tu8 revision_id;\n\tu16 flags;\n\tu8 pin_config_type;\n\tu32 pin_config_value;\n\tu8 res_source_index;\n\tu16 res_source_offset;\n\tu16 res_source_label_offset;\n\tu16 vendor_offset;\n\tu16 vendor_length;\n} __attribute__((packed));\n\nunion aml_resource {\n\tu8 descriptor_type;\n\tstruct aml_resource_small_header small_header;\n\tstruct aml_resource_large_header large_header;\n\tstruct aml_resource_irq irq;\n\tstruct aml_resource_dma dma;\n\tstruct aml_resource_start_dependent start_dpf;\n\tstruct aml_resource_end_dependent end_dpf;\n\tstruct aml_resource_io io;\n\tstruct aml_resource_fixed_io fixed_io;\n\tstruct aml_resource_fixed_dma fixed_dma;\n\tstruct aml_resource_vendor_small vendor_small;\n\tstruct aml_resource_end_tag end_tag;\n\tstruct aml_resource_memory24 memory24;\n\tstruct aml_resource_generic_register generic_reg;\n\tstruct aml_resource_vendor_large vendor_large;\n\tstruct aml_resource_memory32 memory32;\n\tstruct aml_resource_fixed_memory32 fixed_memory32;\n\tstruct aml_resource_address16 address16;\n\tstruct aml_resource_address32 address32;\n\tstruct aml_resource_address64 address64;\n\tstruct aml_resource_extended_address64 ext_address64;\n\tstruct aml_resource_extended_irq extended_irq;\n\tstruct aml_resource_gpio gpio;\n\tstruct aml_resource_i2c_serialbus i2c_serial_bus;\n\tstruct aml_resource_spi_serialbus spi_serial_bus;\n\tstruct aml_resource_uart_serialbus uart_serial_bus;\n\tstruct aml_resource_csi2_serialbus csi2_serial_bus;\n\tstruct aml_resource_common_serialbus common_serial_bus;\n\tstruct aml_resource_pin_function pin_function;\n\tstruct aml_resource_pin_config pin_config;\n\tstruct aml_resource_pin_group pin_group;\n\tstruct aml_resource_pin_group_function pin_group_function;\n\tstruct aml_resource_pin_group_config pin_group_config;\n\tstruct aml_resource_address address;\n\tu32 dword_item;\n\tu16 word_item;\n\tu8 byte_item;\n};\n\nstruct acpi_rsconvert_info {\n\tu8 opcode;\n\tu8 resource_offset;\n\tu8 aml_offset;\n\tu8 value;\n};\n\nenum {\n\tACPI_RSC_INITGET = 0,\n\tACPI_RSC_INITSET = 1,\n\tACPI_RSC_FLAGINIT = 2,\n\tACPI_RSC_1BITFLAG = 3,\n\tACPI_RSC_2BITFLAG = 4,\n\tACPI_RSC_3BITFLAG = 5,\n\tACPI_RSC_6BITFLAG = 6,\n\tACPI_RSC_ADDRESS = 7,\n\tACPI_RSC_BITMASK = 8,\n\tACPI_RSC_BITMASK16 = 9,\n\tACPI_RSC_COUNT = 10,\n\tACPI_RSC_COUNT16 = 11,\n\tACPI_RSC_COUNT_GPIO_PIN = 12,\n\tACPI_RSC_COUNT_GPIO_RES = 13,\n\tACPI_RSC_COUNT_GPIO_VEN = 14,\n\tACPI_RSC_COUNT_SERIAL_RES = 15,\n\tACPI_RSC_COUNT_SERIAL_VEN = 16,\n\tACPI_RSC_DATA8 = 17,\n\tACPI_RSC_EXIT_EQ = 18,\n\tACPI_RSC_EXIT_LE = 19,\n\tACPI_RSC_EXIT_NE = 20,\n\tACPI_RSC_LENGTH = 21,\n\tACPI_RSC_MOVE_GPIO_PIN = 22,\n\tACPI_RSC_MOVE_GPIO_RES = 23,\n\tACPI_RSC_MOVE_SERIAL_RES = 24,\n\tACPI_RSC_MOVE_SERIAL_VEN = 25,\n\tACPI_RSC_MOVE8 = 26,\n\tACPI_RSC_MOVE16 = 27,\n\tACPI_RSC_MOVE32 = 28,\n\tACPI_RSC_MOVE64 = 29,\n\tACPI_RSC_SET8 = 30,\n\tACPI_RSC_SOURCE = 31,\n\tACPI_RSC_SOURCEX = 32,\n};\n\ntypedef u16 acpi_rs_length;\n\ntypedef acpi_status (*acpi_walk_aml_callback)(u8 *, u32, u32, u8, void **);\n\nstruct acpi_rsdump_info {\n\tu8 opcode;\n\tu8 offset;\n\tconst char *name;\n\tconst char **pointer;\n} __attribute__((packed));\n\nenum {\n\tACPI_RSD_TITLE = 0,\n\tACPI_RSD_1BITFLAG = 1,\n\tACPI_RSD_2BITFLAG = 2,\n\tACPI_RSD_3BITFLAG = 3,\n\tACPI_RSD_6BITFLAG = 4,\n\tACPI_RSD_ADDRESS = 5,\n\tACPI_RSD_DWORDLIST = 6,\n\tACPI_RSD_LITERAL = 7,\n\tACPI_RSD_LONGLIST = 8,\n\tACPI_RSD_SHORTLIST = 9,\n\tACPI_RSD_SHORTLISTX = 10,\n\tACPI_RSD_SOURCE = 11,\n\tACPI_RSD_STRING = 12,\n\tACPI_RSD_UINT8 = 13,\n\tACPI_RSD_UINT16 = 14,\n\tACPI_RSD_UINT32 = 15,\n\tACPI_RSD_UINT64 = 16,\n\tACPI_RSD_WORDLIST = 17,\n\tACPI_RSD_LABEL = 18,\n\tACPI_RSD_SOURCE_LABEL = 19,\n};\n\ntypedef u32 acpi_rsdesc_size;\n\nstruct acpi_vendor_uuid {\n\tu8 subtype;\n\tu8 data[16];\n};\n\nstruct acpi_vendor_walk_info {\n\tstruct acpi_vendor_uuid *uuid;\n\tstruct acpi_buffer *buffer;\n\tacpi_status status;\n};\n\nstruct acpi_fadt_info {\n\tconst char *name;\n\tu16 address64;\n\tu16 address32;\n\tu16 length;\n\tu8 default_length;\n\tu8 flags;\n};\n\nstruct acpi_fadt_pm_info {\n\tstruct acpi_generic_address *target;\n\tu16 source;\n\tu8 register_num;\n};\n\nstruct acpi_table_rsdp {\n\tchar signature[8];\n\tu8 checksum;\n\tchar oem_id[6];\n\tu8 revision;\n\tu32 rsdt_physical_address;\n\tu32 length;\n\tu64 xsdt_physical_address;\n\tu8 extended_checksum;\n\tu8 reserved[3];\n} __attribute__((packed));\n\nstruct acpi_address_range {\n\tstruct acpi_address_range *next;\n\tstruct acpi_namespace_node *region_node;\n\tacpi_physical_address start_address;\n\tacpi_physical_address end_address;\n};\n\nstruct acpi_pkg_info {\n\tu8 *free_space;\n\tacpi_size length;\n\tu32 object_space;\n\tu32 num_packages;\n};\n\nstruct acpi_exception_info {\n\tchar *name;\n};\n\nstruct acpi_mutex_info {\n\tvoid *mutex;\n\tu32 use_count;\n\tu64 thread_id;\n};\n\nstruct acpi_comment_node {\n\tchar *comment;\n\tstruct acpi_comment_node *next;\n};\n\nstruct acpi_interface_info {\n\tchar *name;\n\tstruct acpi_interface_info *next;\n\tu8 flags;\n\tu8 value;\n};\n\nenum led_brightness {\n\tLED_OFF = 0,\n\tLED_ON = 1,\n\tLED_HALF = 127,\n\tLED_FULL = 255,\n};\n\nstruct led_hw_trigger_type {\n\tint dummy;\n};\n\nstruct led_pattern;\n\nstruct led_trigger;\n\nstruct led_classdev {\n\tconst char *name;\n\tunsigned int brightness;\n\tunsigned int max_brightness;\n\tint flags;\n\tlong unsigned int work_flags;\n\tvoid (*brightness_set)(struct led_classdev *, enum led_brightness);\n\tint (*brightness_set_blocking)(struct led_classdev *, enum led_brightness);\n\tenum led_brightness (*brightness_get)(struct led_classdev *);\n\tint (*blink_set)(struct led_classdev *, long unsigned int *, long unsigned int *);\n\tint (*pattern_set)(struct led_classdev *, struct led_pattern *, u32, int);\n\tint (*pattern_clear)(struct led_classdev *);\n\tstruct device *dev;\n\tconst struct attribute_group **groups;\n\tstruct list_head node;\n\tconst char *default_trigger;\n\tlong unsigned int blink_delay_on;\n\tlong unsigned int blink_delay_off;\n\tstruct timer_list blink_timer;\n\tint blink_brightness;\n\tint new_blink_brightness;\n\tvoid (*flash_resume)(struct led_classdev *);\n\tstruct work_struct set_brightness_work;\n\tint delayed_set_value;\n\tstruct rw_semaphore trigger_lock;\n\tstruct led_trigger *trigger;\n\tstruct list_head trig_list;\n\tvoid *trigger_data;\n\tbool activated;\n\tstruct led_hw_trigger_type *trigger_type;\n\tint brightness_hw_changed;\n\tstruct kernfs_node *brightness_hw_changed_kn;\n\tstruct mutex led_access;\n};\n\nstruct led_pattern {\n\tu32 delta_t;\n\tint brightness;\n};\n\nstruct led_trigger {\n\tconst char *name;\n\tint (*activate)(struct led_classdev *);\n\tvoid (*deactivate)(struct led_classdev *);\n\tstruct led_hw_trigger_type *trigger_type;\n\trwlock_t leddev_list_lock;\n\tstruct list_head led_cdevs;\n\tstruct list_head next_trig;\n\tconst struct attribute_group **groups;\n};\n\nenum power_supply_property {\n\tPOWER_SUPPLY_PROP_STATUS = 0,\n\tPOWER_SUPPLY_PROP_CHARGE_TYPE = 1,\n\tPOWER_SUPPLY_PROP_HEALTH = 2,\n\tPOWER_SUPPLY_PROP_PRESENT = 3,\n\tPOWER_SUPPLY_PROP_ONLINE = 4,\n\tPOWER_SUPPLY_PROP_AUTHENTIC = 5,\n\tPOWER_SUPPLY_PROP_TECHNOLOGY = 6,\n\tPOWER_SUPPLY_PROP_CYCLE_COUNT = 7,\n\tPOWER_SUPPLY_PROP_VOLTAGE_MAX = 8,\n\tPOWER_SUPPLY_PROP_VOLTAGE_MIN = 9,\n\tPOWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN = 10,\n\tPOWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN = 11,\n\tPOWER_SUPPLY_PROP_VOLTAGE_NOW = 12,\n\tPOWER_SUPPLY_PROP_VOLTAGE_AVG = 13,\n\tPOWER_SUPPLY_PROP_VOLTAGE_OCV = 14,\n\tPOWER_SUPPLY_PROP_VOLTAGE_BOOT = 15,\n\tPOWER_SUPPLY_PROP_CURRENT_MAX = 16,\n\tPOWER_SUPPLY_PROP_CURRENT_NOW = 17,\n\tPOWER_SUPPLY_PROP_CURRENT_AVG = 18,\n\tPOWER_SUPPLY_PROP_CURRENT_BOOT = 19,\n\tPOWER_SUPPLY_PROP_POWER_NOW = 20,\n\tPOWER_SUPPLY_PROP_POWER_AVG = 21,\n\tPOWER_SUPPLY_PROP_CHARGE_FULL_DESIGN = 22,\n\tPOWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN = 23,\n\tPOWER_SUPPLY_PROP_CHARGE_FULL = 24,\n\tPOWER_SUPPLY_PROP_CHARGE_EMPTY = 25,\n\tPOWER_SUPPLY_PROP_CHARGE_NOW = 26,\n\tPOWER_SUPPLY_PROP_CHARGE_AVG = 27,\n\tPOWER_SUPPLY_PROP_CHARGE_COUNTER = 28,\n\tPOWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT = 29,\n\tPOWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX = 30,\n\tPOWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE = 31,\n\tPOWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX = 32,\n\tPOWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT = 33,\n\tPOWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX = 34,\n\tPOWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD = 35,\n\tPOWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD = 36,\n\tPOWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT = 37,\n\tPOWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT = 38,\n\tPOWER_SUPPLY_PROP_INPUT_POWER_LIMIT = 39,\n\tPOWER_SUPPLY_PROP_ENERGY_FULL_DESIGN = 40,\n\tPOWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN = 41,\n\tPOWER_SUPPLY_PROP_ENERGY_FULL = 42,\n\tPOWER_SUPPLY_PROP_ENERGY_EMPTY = 43,\n\tPOWER_SUPPLY_PROP_ENERGY_NOW = 44,\n\tPOWER_SUPPLY_PROP_ENERGY_AVG = 45,\n\tPOWER_SUPPLY_PROP_CAPACITY = 46,\n\tPOWER_SUPPLY_PROP_CAPACITY_ALERT_MIN = 47,\n\tPOWER_SUPPLY_PROP_CAPACITY_ALERT_MAX = 48,\n\tPOWER_SUPPLY_PROP_CAPACITY_ERROR_MARGIN = 49,\n\tPOWER_SUPPLY_PROP_CAPACITY_LEVEL = 50,\n\tPOWER_SUPPLY_PROP_TEMP = 51,\n\tPOWER_SUPPLY_PROP_TEMP_MAX = 52,\n\tPOWER_SUPPLY_PROP_TEMP_MIN = 53,\n\tPOWER_SUPPLY_PROP_TEMP_ALERT_MIN = 54,\n\tPOWER_SUPPLY_PROP_TEMP_ALERT_MAX = 55,\n\tPOWER_SUPPLY_PROP_TEMP_AMBIENT = 56,\n\tPOWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN = 57,\n\tPOWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX = 58,\n\tPOWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW = 59,\n\tPOWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG = 60,\n\tPOWER_SUPPLY_PROP_TIME_TO_FULL_NOW = 61,\n\tPOWER_SUPPLY_PROP_TIME_TO_FULL_AVG = 62,\n\tPOWER_SUPPLY_PROP_TYPE = 63,\n\tPOWER_SUPPLY_PROP_USB_TYPE = 64,\n\tPOWER_SUPPLY_PROP_SCOPE = 65,\n\tPOWER_SUPPLY_PROP_PRECHARGE_CURRENT = 66,\n\tPOWER_SUPPLY_PROP_CHARGE_TERM_CURRENT = 67,\n\tPOWER_SUPPLY_PROP_CALIBRATE = 68,\n\tPOWER_SUPPLY_PROP_MANUFACTURE_YEAR = 69,\n\tPOWER_SUPPLY_PROP_MANUFACTURE_MONTH = 70,\n\tPOWER_SUPPLY_PROP_MANUFACTURE_DAY = 71,\n\tPOWER_SUPPLY_PROP_MODEL_NAME = 72,\n\tPOWER_SUPPLY_PROP_MANUFACTURER = 73,\n\tPOWER_SUPPLY_PROP_SERIAL_NUMBER = 74,\n};\n\nenum power_supply_type {\n\tPOWER_SUPPLY_TYPE_UNKNOWN = 0,\n\tPOWER_SUPPLY_TYPE_BATTERY = 1,\n\tPOWER_SUPPLY_TYPE_UPS = 2,\n\tPOWER_SUPPLY_TYPE_MAINS = 3,\n\tPOWER_SUPPLY_TYPE_USB = 4,\n\tPOWER_SUPPLY_TYPE_USB_DCP = 5,\n\tPOWER_SUPPLY_TYPE_USB_CDP = 6,\n\tPOWER_SUPPLY_TYPE_USB_ACA = 7,\n\tPOWER_SUPPLY_TYPE_USB_TYPE_C = 8,\n\tPOWER_SUPPLY_TYPE_USB_PD = 9,\n\tPOWER_SUPPLY_TYPE_USB_PD_DRP = 10,\n\tPOWER_SUPPLY_TYPE_APPLE_BRICK_ID = 11,\n\tPOWER_SUPPLY_TYPE_WIRELESS = 12,\n};\n\nenum power_supply_usb_type {\n\tPOWER_SUPPLY_USB_TYPE_UNKNOWN = 0,\n\tPOWER_SUPPLY_USB_TYPE_SDP = 1,\n\tPOWER_SUPPLY_USB_TYPE_DCP = 2,\n\tPOWER_SUPPLY_USB_TYPE_CDP = 3,\n\tPOWER_SUPPLY_USB_TYPE_ACA = 4,\n\tPOWER_SUPPLY_USB_TYPE_C = 5,\n\tPOWER_SUPPLY_USB_TYPE_PD = 6,\n\tPOWER_SUPPLY_USB_TYPE_PD_DRP = 7,\n\tPOWER_SUPPLY_USB_TYPE_PD_PPS = 8,\n\tPOWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID = 9,\n};\n\nunion power_supply_propval {\n\tint intval;\n\tconst char *strval;\n};\n\nstruct power_supply_config {\n\tstruct device_node *of_node;\n\tstruct fwnode_handle *fwnode;\n\tvoid *drv_data;\n\tconst struct attribute_group **attr_grp;\n\tchar **supplied_to;\n\tsize_t num_supplicants;\n};\n\nstruct power_supply;\n\nstruct power_supply_desc {\n\tconst char *name;\n\tenum power_supply_type type;\n\tconst enum power_supply_usb_type *usb_types;\n\tsize_t num_usb_types;\n\tconst enum power_supply_property *properties;\n\tsize_t num_properties;\n\tint (*get_property)(struct power_supply *, enum power_supply_property, union power_supply_propval *);\n\tint (*set_property)(struct power_supply *, enum power_supply_property, const union power_supply_propval *);\n\tint (*property_is_writeable)(struct power_supply *, enum power_supply_property);\n\tvoid (*external_power_changed)(struct power_supply *);\n\tvoid (*set_charged)(struct power_supply *);\n\tbool no_thermal;\n\tint use_for_apm;\n};\n\nstruct thermal_zone_device;\n\nstruct power_supply {\n\tconst struct power_supply_desc *desc;\n\tchar **supplied_to;\n\tsize_t num_supplicants;\n\tchar **supplied_from;\n\tsize_t num_supplies;\n\tstruct device_node *of_node;\n\tvoid *drv_data;\n\tstruct device dev;\n\tstruct work_struct changed_work;\n\tstruct delayed_work deferred_register_work;\n\tspinlock_t changed_lock;\n\tbool changed;\n\tbool initialized;\n\tbool removing;\n\tatomic_t use_cnt;\n\tstruct thermal_zone_device *tzd;\n\tstruct thermal_cooling_device *tcd;\n\tstruct led_trigger *charging_full_trig;\n\tchar *charging_full_trig_name;\n\tstruct led_trigger *charging_trig;\n\tchar *charging_trig_name;\n\tstruct led_trigger *full_trig;\n\tchar *full_trig_name;\n\tstruct led_trigger *online_trig;\n\tchar *online_trig_name;\n\tstruct led_trigger *charging_blink_full_solid_trig;\n\tchar *charging_blink_full_solid_trig_name;\n};\n\nstruct acpi_ac_bl {\n\tconst char *hid;\n\tint hrv;\n};\n\nstruct acpi_ac {\n\tstruct power_supply *charger;\n\tstruct power_supply_desc charger_desc;\n\tstruct acpi_device *device;\n\tlong long unsigned int state;\n\tstruct notifier_block battery_nb;\n};\n\nstruct input_id {\n\t__u16 bustype;\n\t__u16 vendor;\n\t__u16 product;\n\t__u16 version;\n};\n\nstruct input_absinfo {\n\t__s32 value;\n\t__s32 minimum;\n\t__s32 maximum;\n\t__s32 fuzz;\n\t__s32 flat;\n\t__s32 resolution;\n};\n\nstruct input_keymap_entry {\n\t__u8 flags;\n\t__u8 len;\n\t__u16 index;\n\t__u32 keycode;\n\t__u8 scancode[32];\n};\n\nstruct ff_replay {\n\t__u16 length;\n\t__u16 delay;\n};\n\nstruct ff_trigger {\n\t__u16 button;\n\t__u16 interval;\n};\n\nstruct ff_envelope {\n\t__u16 attack_length;\n\t__u16 attack_level;\n\t__u16 fade_length;\n\t__u16 fade_level;\n};\n\nstruct ff_constant_effect {\n\t__s16 level;\n\tstruct ff_envelope envelope;\n};\n\nstruct ff_ramp_effect {\n\t__s16 start_level;\n\t__s16 end_level;\n\tstruct ff_envelope envelope;\n};\n\nstruct ff_condition_effect {\n\t__u16 right_saturation;\n\t__u16 left_saturation;\n\t__s16 right_coeff;\n\t__s16 left_coeff;\n\t__u16 deadband;\n\t__s16 center;\n};\n\nstruct ff_periodic_effect {\n\t__u16 waveform;\n\t__u16 period;\n\t__s16 magnitude;\n\t__s16 offset;\n\t__u16 phase;\n\tstruct ff_envelope envelope;\n\t__u32 custom_len;\n\t__s16 *custom_data;\n};\n\nstruct ff_rumble_effect {\n\t__u16 strong_magnitude;\n\t__u16 weak_magnitude;\n};\n\nstruct ff_effect {\n\t__u16 type;\n\t__s16 id;\n\t__u16 direction;\n\tstruct ff_trigger trigger;\n\tstruct ff_replay replay;\n\tunion {\n\t\tstruct ff_constant_effect constant;\n\t\tstruct ff_ramp_effect ramp;\n\t\tstruct ff_periodic_effect periodic;\n\t\tstruct ff_condition_effect condition[2];\n\t\tstruct ff_rumble_effect rumble;\n\t} u;\n};\n\nstruct input_device_id {\n\tkernel_ulong_t flags;\n\t__u16 bustype;\n\t__u16 vendor;\n\t__u16 product;\n\t__u16 version;\n\tkernel_ulong_t evbit[1];\n\tkernel_ulong_t keybit[12];\n\tkernel_ulong_t relbit[1];\n\tkernel_ulong_t absbit[1];\n\tkernel_ulong_t mscbit[1];\n\tkernel_ulong_t ledbit[1];\n\tkernel_ulong_t sndbit[1];\n\tkernel_ulong_t ffbit[2];\n\tkernel_ulong_t swbit[1];\n\tkernel_ulong_t propbit[1];\n\tkernel_ulong_t driver_info;\n};\n\nstruct input_value {\n\t__u16 type;\n\t__u16 code;\n\t__s32 value;\n};\n\nenum input_clock_type {\n\tINPUT_CLK_REAL = 0,\n\tINPUT_CLK_MONO = 1,\n\tINPUT_CLK_BOOT = 2,\n\tINPUT_CLK_MAX = 3,\n};\n\nstruct ff_device;\n\nstruct input_dev_poller;\n\nstruct input_mt;\n\nstruct input_handle;\n\nstruct input_dev {\n\tconst char *name;\n\tconst char *phys;\n\tconst char *uniq;\n\tstruct input_id id;\n\tlong unsigned int propbit[1];\n\tlong unsigned int evbit[1];\n\tlong unsigned int keybit[12];\n\tlong unsigned int relbit[1];\n\tlong unsigned int absbit[1];\n\tlong unsigned int mscbit[1];\n\tlong unsigned int ledbit[1];\n\tlong unsigned int sndbit[1];\n\tlong unsigned int ffbit[2];\n\tlong unsigned int swbit[1];\n\tunsigned int hint_events_per_packet;\n\tunsigned int keycodemax;\n\tunsigned int keycodesize;\n\tvoid *keycode;\n\tint (*setkeycode)(struct input_dev *, const struct input_keymap_entry *, unsigned int *);\n\tint (*getkeycode)(struct input_dev *, struct input_keymap_entry *);\n\tstruct ff_device *ff;\n\tstruct input_dev_poller *poller;\n\tunsigned int repeat_key;\n\tstruct timer_list timer;\n\tint rep[2];\n\tstruct input_mt *mt;\n\tstruct input_absinfo *absinfo;\n\tlong unsigned int key[12];\n\tlong unsigned int led[1];\n\tlong unsigned int snd[1];\n\tlong unsigned int sw[1];\n\tint (*open)(struct input_dev *);\n\tvoid (*close)(struct input_dev *);\n\tint (*flush)(struct input_dev *, struct file *);\n\tint (*event)(struct input_dev *, unsigned int, unsigned int, int);\n\tstruct input_handle *grab;\n\tspinlock_t event_lock;\n\tstruct mutex mutex;\n\tunsigned int users;\n\tbool going_away;\n\tstruct device dev;\n\tstruct list_head h_list;\n\tstruct list_head node;\n\tunsigned int num_vals;\n\tunsigned int max_vals;\n\tstruct input_value *vals;\n\tbool devres_managed;\n\tktime_t timestamp[3];\n\tbool inhibited;\n};\n\nstruct ff_device {\n\tint (*upload)(struct input_dev *, struct ff_effect *, struct ff_effect *);\n\tint (*erase)(struct input_dev *, int);\n\tint (*playback)(struct input_dev *, int, int);\n\tvoid (*set_gain)(struct input_dev *, u16);\n\tvoid (*set_autocenter)(struct input_dev *, u16);\n\tvoid (*destroy)(struct ff_device *);\n\tvoid *private;\n\tlong unsigned int ffbit[2];\n\tstruct mutex mutex;\n\tint max_effects;\n\tstruct ff_effect *effects;\n\tstruct file *effect_owners[0];\n};\n\nstruct input_handler;\n\nstruct input_handle {\n\tvoid *private;\n\tint open;\n\tconst char *name;\n\tstruct input_dev *dev;\n\tstruct input_handler *handler;\n\tstruct list_head d_node;\n\tstruct list_head h_node;\n};\n\nstruct input_handler {\n\tvoid *private;\n\tvoid (*event)(struct input_handle *, unsigned int, unsigned int, int);\n\tvoid (*events)(struct input_handle *, const struct input_value *, unsigned int);\n\tbool (*filter)(struct input_handle *, unsigned int, unsigned int, int);\n\tbool (*match)(struct input_handler *, struct input_dev *);\n\tint (*connect)(struct input_handler *, struct input_dev *, const struct input_device_id *);\n\tvoid (*disconnect)(struct input_handle *);\n\tvoid (*start)(struct input_handle *);\n\tbool legacy_minors;\n\tint minor;\n\tconst char *name;\n\tconst struct input_device_id *id_table;\n\tstruct list_head h_list;\n\tstruct list_head node;\n};\n\nenum {\n\tACPI_BUTTON_LID_INIT_IGNORE = 0,\n\tACPI_BUTTON_LID_INIT_OPEN = 1,\n\tACPI_BUTTON_LID_INIT_METHOD = 2,\n\tACPI_BUTTON_LID_INIT_DISABLED = 3,\n};\n\nstruct acpi_button {\n\tunsigned int type;\n\tstruct input_dev *input;\n\tchar phys[32];\n\tlong unsigned int pushed;\n\tint last_state;\n\tktime_t last_time;\n\tbool suspended;\n\tbool lid_state_initialized;\n};\n\nstruct acpi_fan_fps {\n\tu64 control;\n\tu64 trip_point;\n\tu64 speed;\n\tu64 noise_level;\n\tu64 power;\n\tchar name[20];\n\tstruct device_attribute dev_attr;\n};\n\nstruct acpi_fan_fif {\n\tu64 revision;\n\tu64 fine_grain_ctrl;\n\tu64 step_size;\n\tu64 low_speed_notification;\n};\n\nstruct acpi_fan {\n\tbool acpi4;\n\tstruct acpi_fan_fif fif;\n\tstruct acpi_fan_fps *fps;\n\tint fps_count;\n\tstruct thermal_cooling_device *cdev;\n};\n\nstruct acpi_pci_slot {\n\tstruct pci_slot *pci_slot;\n\tstruct list_head list;\n};\n\nstruct acpi_lpi_states_array {\n\tunsigned int size;\n\tunsigned int composite_states_size;\n\tstruct acpi_lpi_state *entries;\n\tstruct acpi_lpi_state *composite_states[8];\n};\n\nstruct throttling_tstate {\n\tunsigned int cpu;\n\tint target_state;\n};\n\nstruct acpi_processor_throttling_arg {\n\tstruct acpi_processor *pr;\n\tint target_state;\n\tbool force;\n};\n\nstruct container_dev {\n\tstruct device dev;\n\tint (*offline)(struct container_dev *);\n};\n\nenum thermal_device_mode {\n\tTHERMAL_DEVICE_DISABLED = 0,\n\tTHERMAL_DEVICE_ENABLED = 1,\n};\n\nenum thermal_trip_type {\n\tTHERMAL_TRIP_ACTIVE = 0,\n\tTHERMAL_TRIP_PASSIVE = 1,\n\tTHERMAL_TRIP_HOT = 2,\n\tTHERMAL_TRIP_CRITICAL = 3,\n};\n\nenum thermal_trend {\n\tTHERMAL_TREND_STABLE = 0,\n\tTHERMAL_TREND_RAISING = 1,\n\tTHERMAL_TREND_DROPPING = 2,\n\tTHERMAL_TREND_RAISE_FULL = 3,\n\tTHERMAL_TREND_DROP_FULL = 4,\n};\n\nenum thermal_notify_event {\n\tTHERMAL_EVENT_UNSPECIFIED = 0,\n\tTHERMAL_EVENT_TEMP_SAMPLE = 1,\n\tTHERMAL_TRIP_VIOLATED = 2,\n\tTHERMAL_TRIP_CHANGED = 3,\n\tTHERMAL_DEVICE_DOWN = 4,\n\tTHERMAL_DEVICE_UP = 5,\n\tTHERMAL_DEVICE_POWER_CAPABILITY_CHANGED = 6,\n\tTHERMAL_TABLE_CHANGED = 7,\n\tTHERMAL_EVENT_KEEP_ALIVE = 8,\n};\n\nstruct thermal_zone_device_ops {\n\tint (*bind)(struct thermal_zone_device *, struct thermal_cooling_device *);\n\tint (*unbind)(struct thermal_zone_device *, struct thermal_cooling_device *);\n\tint (*get_temp)(struct thermal_zone_device *, int *);\n\tint (*set_trips)(struct thermal_zone_device *, int, int);\n\tint (*change_mode)(struct thermal_zone_device *, enum thermal_device_mode);\n\tint (*get_trip_type)(struct thermal_zone_device *, int, enum thermal_trip_type *);\n\tint (*get_trip_temp)(struct thermal_zone_device *, int, int *);\n\tint (*set_trip_temp)(struct thermal_zone_device *, int, int);\n\tint (*get_trip_hyst)(struct thermal_zone_device *, int, int *);\n\tint (*set_trip_hyst)(struct thermal_zone_device *, int, int);\n\tint (*get_crit_temp)(struct thermal_zone_device *, int *);\n\tint (*set_emul_temp)(struct thermal_zone_device *, int);\n\tint (*get_trend)(struct thermal_zone_device *, int, enum thermal_trend *);\n\tvoid (*hot)(struct thermal_zone_device *);\n\tvoid (*critical)(struct thermal_zone_device *);\n};\n\nstruct thermal_attr;\n\nstruct thermal_zone_params;\n\nstruct thermal_governor;\n\nstruct thermal_zone_device {\n\tint id;\n\tchar type[20];\n\tstruct device device;\n\tstruct attribute_group trips_attribute_group;\n\tstruct thermal_attr *trip_temp_attrs;\n\tstruct thermal_attr *trip_type_attrs;\n\tstruct thermal_attr *trip_hyst_attrs;\n\tenum thermal_device_mode mode;\n\tvoid *devdata;\n\tint trips;\n\tlong unsigned int trips_disabled;\n\tlong unsigned int passive_delay_jiffies;\n\tlong unsigned int polling_delay_jiffies;\n\tint temperature;\n\tint last_temperature;\n\tint emul_temperature;\n\tint passive;\n\tint prev_low_trip;\n\tint prev_high_trip;\n\tatomic_t need_update;\n\tstruct thermal_zone_device_ops *ops;\n\tstruct thermal_zone_params *tzp;\n\tstruct thermal_governor *governor;\n\tvoid *governor_data;\n\tstruct list_head thermal_instances;\n\tstruct ida ida;\n\tstruct mutex lock;\n\tstruct list_head node;\n\tstruct delayed_work poll_queue;\n\tenum thermal_notify_event notify_event;\n};\n\nstruct thermal_bind_params;\n\nstruct thermal_zone_params {\n\tchar governor_name[20];\n\tbool no_hwmon;\n\tint num_tbps;\n\tstruct thermal_bind_params *tbp;\n\tu32 sustainable_power;\n\ts32 k_po;\n\ts32 k_pu;\n\ts32 k_i;\n\ts32 k_d;\n\ts32 integral_cutoff;\n\tint slope;\n\tint offset;\n};\n\nstruct thermal_governor {\n\tchar name[20];\n\tint (*bind_to_tz)(struct thermal_zone_device *);\n\tvoid (*unbind_from_tz)(struct thermal_zone_device *);\n\tint (*throttle)(struct thermal_zone_device *, int);\n\tstruct list_head governor_list;\n};\n\nstruct thermal_bind_params {\n\tstruct thermal_cooling_device *cdev;\n\tint weight;\n\tint trip_mask;\n\tlong unsigned int *binding_limits;\n\tint (*match)(struct thermal_zone_device *, struct thermal_cooling_device *);\n};\n\nstruct acpi_thermal_state {\n\tu8 critical: 1;\n\tu8 hot: 1;\n\tu8 passive: 1;\n\tu8 active: 1;\n\tu8 reserved: 4;\n\tint active_index;\n};\n\nstruct acpi_thermal_state_flags {\n\tu8 valid: 1;\n\tu8 enabled: 1;\n\tu8 reserved: 6;\n};\n\nstruct acpi_thermal_critical {\n\tstruct acpi_thermal_state_flags flags;\n\tlong unsigned int temperature;\n};\n\nstruct acpi_thermal_hot {\n\tstruct acpi_thermal_state_flags flags;\n\tlong unsigned int temperature;\n};\n\nstruct acpi_thermal_passive {\n\tstruct acpi_thermal_state_flags flags;\n\tlong unsigned int temperature;\n\tlong unsigned int tc1;\n\tlong unsigned int tc2;\n\tlong unsigned int tsp;\n\tstruct acpi_handle_list devices;\n};\n\nstruct acpi_thermal_active {\n\tstruct acpi_thermal_state_flags flags;\n\tlong unsigned int temperature;\n\tstruct acpi_handle_list devices;\n};\n\nstruct acpi_thermal_trips {\n\tstruct acpi_thermal_critical critical;\n\tstruct acpi_thermal_hot hot;\n\tstruct acpi_thermal_passive passive;\n\tstruct acpi_thermal_active active[10];\n};\n\nstruct acpi_thermal_flags {\n\tu8 cooling_mode: 1;\n\tu8 devices: 1;\n\tu8 reserved: 6;\n};\n\nstruct acpi_thermal {\n\tstruct acpi_device *device;\n\tacpi_bus_id name;\n\tlong unsigned int temperature;\n\tlong unsigned int last_temperature;\n\tlong unsigned int polling_frequency;\n\tvolatile u8 zombie;\n\tstruct acpi_thermal_flags flags;\n\tstruct acpi_thermal_state state;\n\tstruct acpi_thermal_trips trips;\n\tstruct acpi_handle_list devices;\n\tstruct thermal_zone_device *thermal_zone;\n\tint kelvin_offset;\n\tstruct work_struct thermal_check_work;\n\tstruct mutex thermal_check_lock;\n\trefcount_t thermal_check_count;\n};\n\nstruct acpi_table_slit {\n\tstruct acpi_table_header header;\n\tu64 locality_count;\n\tu8 entry[1];\n} __attribute__((packed));\n\nstruct acpi_table_srat {\n\tstruct acpi_table_header header;\n\tu32 table_revision;\n\tu64 reserved;\n};\n\nenum acpi_srat_type {\n\tACPI_SRAT_TYPE_CPU_AFFINITY = 0,\n\tACPI_SRAT_TYPE_MEMORY_AFFINITY = 1,\n\tACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2,\n\tACPI_SRAT_TYPE_GICC_AFFINITY = 3,\n\tACPI_SRAT_TYPE_GIC_ITS_AFFINITY = 4,\n\tACPI_SRAT_TYPE_GENERIC_AFFINITY = 5,\n\tACPI_SRAT_TYPE_RESERVED = 6,\n};\n\nstruct acpi_srat_mem_affinity {\n\tstruct acpi_subtable_header header;\n\tu32 proximity_domain;\n\tu16 reserved;\n\tu64 base_address;\n\tu64 length;\n\tu32 reserved1;\n\tu32 flags;\n\tu64 reserved2;\n} __attribute__((packed));\n\nstruct acpi_srat_gicc_affinity {\n\tstruct acpi_subtable_header header;\n\tu32 proximity_domain;\n\tu32 acpi_processor_uid;\n\tu32 flags;\n\tu32 clock_domain;\n} __attribute__((packed));\n\nstruct acpi_srat_generic_affinity {\n\tstruct acpi_subtable_header header;\n\tu8 reserved;\n\tu8 device_handle_type;\n\tu32 proximity_domain;\n\tu8 device_handle[16];\n\tu32 flags;\n\tu32 reserved1;\n};\n\nenum acpi_hmat_type {\n\tACPI_HMAT_TYPE_PROXIMITY = 0,\n\tACPI_HMAT_TYPE_LOCALITY = 1,\n\tACPI_HMAT_TYPE_CACHE = 2,\n\tACPI_HMAT_TYPE_RESERVED = 3,\n};\n\nstruct acpi_hmat_proximity_domain {\n\tstruct acpi_hmat_structure header;\n\tu16 flags;\n\tu16 reserved1;\n\tu32 processor_PD;\n\tu32 memory_PD;\n\tu32 reserved2;\n\tu64 reserved3;\n\tu64 reserved4;\n};\n\nstruct acpi_hmat_locality {\n\tstruct acpi_hmat_structure header;\n\tu8 flags;\n\tu8 data_type;\n\tu8 min_transfer_size;\n\tu8 reserved1;\n\tu32 number_of_initiator_Pds;\n\tu32 number_of_target_Pds;\n\tu32 reserved2;\n\tu64 entry_base_unit;\n};\n\nstruct acpi_hmat_cache {\n\tstruct acpi_hmat_structure header;\n\tu32 memory_PD;\n\tu32 reserved1;\n\tu64 cache_size;\n\tu32 cache_attributes;\n\tu16 reserved2;\n\tu16 number_of_SMBIOShandles;\n};\n\nstruct node_hmem_attrs {\n\tunsigned int read_bandwidth;\n\tunsigned int write_bandwidth;\n\tunsigned int read_latency;\n\tunsigned int write_latency;\n};\n\nenum cache_indexing {\n\tNODE_CACHE_DIRECT_MAP = 0,\n\tNODE_CACHE_INDEXED = 1,\n\tNODE_CACHE_OTHER = 2,\n};\n\nenum cache_write_policy {\n\tNODE_CACHE_WRITE_BACK = 0,\n\tNODE_CACHE_WRITE_THROUGH = 1,\n\tNODE_CACHE_WRITE_OTHER = 2,\n};\n\nstruct node_cache_attrs {\n\tenum cache_indexing indexing;\n\tenum cache_write_policy write_policy;\n\tu64 size;\n\tu16 line_size;\n\tu8 level;\n};\n\nenum locality_types {\n\tWRITE_LATENCY = 0,\n\tREAD_LATENCY = 1,\n\tWRITE_BANDWIDTH = 2,\n\tREAD_BANDWIDTH = 3,\n};\n\nstruct memory_locality {\n\tstruct list_head node;\n\tstruct acpi_hmat_locality *hmat_loc;\n};\n\nstruct target_cache {\n\tstruct list_head node;\n\tstruct node_cache_attrs cache_attrs;\n};\n\nstruct memory_target {\n\tstruct list_head node;\n\tunsigned int memory_pxm;\n\tunsigned int processor_pxm;\n\tstruct resource memregions;\n\tstruct node_hmem_attrs hmem_attrs[2];\n\tstruct list_head caches;\n\tstruct node_cache_attrs cache_attrs;\n\tbool registered;\n};\n\nstruct memory_initiator {\n\tstruct list_head node;\n\tunsigned int processor_pxm;\n\tbool has_cpu;\n};\n\nstruct acpi_memory_info {\n\tstruct list_head list;\n\tu64 start_addr;\n\tu64 length;\n\tshort unsigned int caching;\n\tshort unsigned int write_protect;\n\tunsigned int enabled: 1;\n};\n\nstruct acpi_memory_device {\n\tstruct acpi_device *device;\n\tstruct list_head res_list;\n};\n\nstruct acpi_pci_ioapic {\n\tacpi_handle root_handle;\n\tacpi_handle handle;\n\tu32 gsi_base;\n\tstruct resource res;\n\tstruct pci_dev *pdev;\n\tstruct list_head list;\n};\n\nenum dmi_entry_type {\n\tDMI_ENTRY_BIOS = 0,\n\tDMI_ENTRY_SYSTEM = 1,\n\tDMI_ENTRY_BASEBOARD = 2,\n\tDMI_ENTRY_CHASSIS = 3,\n\tDMI_ENTRY_PROCESSOR = 4,\n\tDMI_ENTRY_MEM_CONTROLLER = 5,\n\tDMI_ENTRY_MEM_MODULE = 6,\n\tDMI_ENTRY_CACHE = 7,\n\tDMI_ENTRY_PORT_CONNECTOR = 8,\n\tDMI_ENTRY_SYSTEM_SLOT = 9,\n\tDMI_ENTRY_ONBOARD_DEVICE = 10,\n\tDMI_ENTRY_OEMSTRINGS = 11,\n\tDMI_ENTRY_SYSCONF = 12,\n\tDMI_ENTRY_BIOS_LANG = 13,\n\tDMI_ENTRY_GROUP_ASSOC = 14,\n\tDMI_ENTRY_SYSTEM_EVENT_LOG = 15,\n\tDMI_ENTRY_PHYS_MEM_ARRAY = 16,\n\tDMI_ENTRY_MEM_DEVICE = 17,\n\tDMI_ENTRY_32_MEM_ERROR = 18,\n\tDMI_ENTRY_MEM_ARRAY_MAPPED_ADDR = 19,\n\tDMI_ENTRY_MEM_DEV_MAPPED_ADDR = 20,\n\tDMI_ENTRY_BUILTIN_POINTING_DEV = 21,\n\tDMI_ENTRY_PORTABLE_BATTERY = 22,\n\tDMI_ENTRY_SYSTEM_RESET = 23,\n\tDMI_ENTRY_HW_SECURITY = 24,\n\tDMI_ENTRY_SYSTEM_POWER_CONTROLS = 25,\n\tDMI_ENTRY_VOLTAGE_PROBE = 26,\n\tDMI_ENTRY_COOLING_DEV = 27,\n\tDMI_ENTRY_TEMP_PROBE = 28,\n\tDMI_ENTRY_ELECTRICAL_CURRENT_PROBE = 29,\n\tDMI_ENTRY_OOB_REMOTE_ACCESS = 30,\n\tDMI_ENTRY_BIS_ENTRY = 31,\n\tDMI_ENTRY_SYSTEM_BOOT = 32,\n\tDMI_ENTRY_MGMT_DEV = 33,\n\tDMI_ENTRY_MGMT_DEV_COMPONENT = 34,\n\tDMI_ENTRY_MGMT_DEV_THRES = 35,\n\tDMI_ENTRY_MEM_CHANNEL = 36,\n\tDMI_ENTRY_IPMI_DEV = 37,\n\tDMI_ENTRY_SYS_POWER_SUPPLY = 38,\n\tDMI_ENTRY_ADDITIONAL = 39,\n\tDMI_ENTRY_ONBOARD_DEV_EXT = 40,\n\tDMI_ENTRY_MGMT_CONTROLLER_HOST = 41,\n\tDMI_ENTRY_INACTIVE = 126,\n\tDMI_ENTRY_END_OF_TABLE = 127,\n};\n\nenum {\n\tPOWER_SUPPLY_STATUS_UNKNOWN = 0,\n\tPOWER_SUPPLY_STATUS_CHARGING = 1,\n\tPOWER_SUPPLY_STATUS_DISCHARGING = 2,\n\tPOWER_SUPPLY_STATUS_NOT_CHARGING = 3,\n\tPOWER_SUPPLY_STATUS_FULL = 4,\n};\n\nenum {\n\tPOWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,\n\tPOWER_SUPPLY_TECHNOLOGY_NiMH = 1,\n\tPOWER_SUPPLY_TECHNOLOGY_LION = 2,\n\tPOWER_SUPPLY_TECHNOLOGY_LIPO = 3,\n\tPOWER_SUPPLY_TECHNOLOGY_LiFe = 4,\n\tPOWER_SUPPLY_TECHNOLOGY_NiCd = 5,\n\tPOWER_SUPPLY_TECHNOLOGY_LiMn = 6,\n};\n\nenum {\n\tPOWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,\n\tPOWER_SUPPLY_CAPACITY_LEVEL_CRITICAL = 1,\n\tPOWER_SUPPLY_CAPACITY_LEVEL_LOW = 2,\n\tPOWER_SUPPLY_CAPACITY_LEVEL_NORMAL = 3,\n\tPOWER_SUPPLY_CAPACITY_LEVEL_HIGH = 4,\n\tPOWER_SUPPLY_CAPACITY_LEVEL_FULL = 5,\n};\n\nstruct acpi_battery_hook {\n\tconst char *name;\n\tint (*add_battery)(struct power_supply *);\n\tint (*remove_battery)(struct power_supply *);\n\tstruct list_head list;\n};\n\nenum {\n\tACPI_BATTERY_ALARM_PRESENT = 0,\n\tACPI_BATTERY_XINFO_PRESENT = 1,\n\tACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY = 2,\n\tACPI_BATTERY_QUIRK_THINKPAD_MAH = 3,\n\tACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE = 4,\n};\n\nstruct acpi_battery {\n\tstruct mutex lock;\n\tstruct mutex sysfs_lock;\n\tstruct power_supply *bat;\n\tstruct power_supply_desc bat_desc;\n\tstruct acpi_device *device;\n\tstruct notifier_block pm_nb;\n\tstruct list_head list;\n\tlong unsigned int update_time;\n\tint revision;\n\tint rate_now;\n\tint capacity_now;\n\tint voltage_now;\n\tint design_capacity;\n\tint full_charge_capacity;\n\tint technology;\n\tint design_voltage;\n\tint design_capacity_warning;\n\tint design_capacity_low;\n\tint cycle_count;\n\tint measurement_accuracy;\n\tint max_sampling_time;\n\tint min_sampling_time;\n\tint max_averaging_interval;\n\tint min_averaging_interval;\n\tint capacity_granularity_1;\n\tint capacity_granularity_2;\n\tint alarm;\n\tchar model_number[32];\n\tchar serial_number[32];\n\tchar type[32];\n\tchar oem_info[32];\n\tint state;\n\tint power_unit;\n\tlong unsigned int flags;\n};\n\nstruct acpi_offsets {\n\tsize_t offset;\n\tu8 mode;\n};\n\nstruct acpi_pcct_hw_reduced {\n\tstruct acpi_subtable_header header;\n\tu32 platform_interrupt;\n\tu8 flags;\n\tu8 reserved;\n\tu64 base_address;\n\tu64 length;\n\tstruct acpi_generic_address doorbell_register;\n\tu64 preserve_mask;\n\tu64 write_mask;\n\tu32 latency;\n\tu32 max_access_rate;\n\tu16 min_turnaround_time;\n} __attribute__((packed));\n\nstruct acpi_pcct_shared_memory {\n\tu32 signature;\n\tu16 command;\n\tu16 status;\n};\n\nstruct mbox_chan;\n\nstruct mbox_chan_ops {\n\tint (*send_data)(struct mbox_chan *, void *);\n\tint (*flush)(struct mbox_chan *, long unsigned int);\n\tint (*startup)(struct mbox_chan *);\n\tvoid (*shutdown)(struct mbox_chan *);\n\tbool (*last_tx_done)(struct mbox_chan *);\n\tbool (*peek_data)(struct mbox_chan *);\n};\n\nstruct mbox_controller;\n\nstruct mbox_client;\n\nstruct mbox_chan {\n\tstruct mbox_controller *mbox;\n\tunsigned int txdone_method;\n\tstruct mbox_client *cl;\n\tstruct completion tx_complete;\n\tvoid *active_req;\n\tunsigned int msg_count;\n\tunsigned int msg_free;\n\tvoid *msg_data[20];\n\tspinlock_t lock;\n\tvoid *con_priv;\n};\n\nstruct mbox_controller {\n\tstruct device *dev;\n\tconst struct mbox_chan_ops *ops;\n\tstruct mbox_chan *chans;\n\tint num_chans;\n\tbool txdone_irq;\n\tbool txdone_poll;\n\tunsigned int txpoll_period;\n\tstruct mbox_chan * (*of_xlate)(struct mbox_controller *, const struct of_phandle_args *);\n\tstruct hrtimer poll_hrt;\n\tstruct list_head node;\n};\n\nstruct mbox_client {\n\tstruct device *dev;\n\tbool tx_block;\n\tlong unsigned int tx_tout;\n\tbool knows_txdone;\n\tvoid (*rx_callback)(struct mbox_client *, void *);\n\tvoid (*tx_prepare)(struct mbox_client *, void *);\n\tvoid (*tx_done)(struct mbox_client *, void *, int);\n};\n\nstruct cpc_register_resource {\n\tacpi_object_type type;\n\tu64 *sys_mem_vaddr;\n\tunion {\n\t\tstruct cpc_reg reg;\n\t\tu64 int_value;\n\t} cpc_entry;\n};\n\nstruct cpc_desc {\n\tint num_entries;\n\tint version;\n\tint cpu_id;\n\tint write_cmd_status;\n\tint write_cmd_id;\n\tstruct cpc_register_resource cpc_regs[21];\n\tstruct acpi_psd_package domain_info;\n\tstruct kobject kobj;\n};\n\nenum cppc_regs {\n\tHIGHEST_PERF = 0,\n\tNOMINAL_PERF = 1,\n\tLOW_NON_LINEAR_PERF = 2,\n\tLOWEST_PERF = 3,\n\tGUARANTEED_PERF = 4,\n\tDESIRED_PERF = 5,\n\tMIN_PERF = 6,\n\tMAX_PERF = 7,\n\tPERF_REDUC_TOLERANCE = 8,\n\tTIME_WINDOW = 9,\n\tCTR_WRAP_TIME = 10,\n\tREFERENCE_CTR = 11,\n\tDELIVERED_CTR = 12,\n\tPERF_LIMITED = 13,\n\tENABLE = 14,\n\tAUTO_SEL_ENABLE = 15,\n\tAUTO_ACT_WINDOW = 16,\n\tENERGY_PERF = 17,\n\tREFERENCE_PERF = 18,\n\tLOWEST_FREQ = 19,\n\tNOMINAL_FREQ = 20,\n};\n\nstruct cppc_perf_ctrls {\n\tu32 max_perf;\n\tu32 min_perf;\n\tu32 desired_perf;\n};\n\nstruct cppc_perf_fb_ctrs {\n\tu64 reference;\n\tu64 delivered;\n\tu64 reference_perf;\n\tu64 wraparound_time;\n};\n\nstruct cppc_cpudata {\n\tstruct list_head node;\n\tstruct cppc_perf_caps perf_caps;\n\tstruct cppc_perf_ctrls perf_ctrls;\n\tstruct cppc_perf_fb_ctrs perf_fb_ctrs;\n\tunsigned int shared_type;\n\tcpumask_var_t shared_cpu_map;\n};\n\nstruct cppc_pcc_data {\n\tstruct mbox_chan *pcc_channel;\n\tvoid *pcc_comm_addr;\n\tbool pcc_channel_acquired;\n\tunsigned int deadline_us;\n\tunsigned int pcc_mpar;\n\tunsigned int pcc_mrtt;\n\tunsigned int pcc_nominal;\n\tbool pending_pcc_write_cmd;\n\tbool platform_owns_pcc;\n\tunsigned int pcc_write_cnt;\n\tstruct rw_semaphore pcc_lock;\n\twait_queue_head_t pcc_write_wait_q;\n\tktime_t last_cmd_cmpl_time;\n\tktime_t last_mpar_reset;\n\tint mpar_count;\n\tint refcount;\n};\n\nstruct acpi_whea_header {\n\tu8 action;\n\tu8 instruction;\n\tu8 flags;\n\tu8 reserved;\n\tstruct acpi_generic_address register_region;\n\tu64 value;\n\tu64 mask;\n} __attribute__((packed));\n\nstruct apei_exec_context;\n\ntypedef int (*apei_exec_ins_func_t)(struct apei_exec_context *, struct acpi_whea_header *);\n\nstruct apei_exec_ins_type;\n\nstruct apei_exec_context {\n\tu32 ip;\n\tu64 value;\n\tu64 var1;\n\tu64 var2;\n\tu64 src_base;\n\tu64 dst_base;\n\tstruct apei_exec_ins_type *ins_table;\n\tu32 instructions;\n\tstruct acpi_whea_header *action_table;\n\tu32 entries;\n};\n\nstruct apei_exec_ins_type {\n\tu32 flags;\n\tapei_exec_ins_func_t run;\n};\n\nstruct apei_resources {\n\tstruct list_head iomem;\n\tstruct list_head ioport;\n};\n\ntypedef int (*apei_exec_entry_func_t)(struct apei_exec_context *, struct acpi_whea_header *, void *);\n\nstruct apei_res {\n\tstruct list_head list;\n\tlong unsigned int start;\n\tlong unsigned int end;\n};\n\nstruct acpi_table_hest {\n\tstruct acpi_table_header header;\n\tu32 error_source_count;\n};\n\nenum acpi_hest_types {\n\tACPI_HEST_TYPE_IA32_CHECK = 0,\n\tACPI_HEST_TYPE_IA32_CORRECTED_CHECK = 1,\n\tACPI_HEST_TYPE_IA32_NMI = 2,\n\tACPI_HEST_TYPE_NOT_USED3 = 3,\n\tACPI_HEST_TYPE_NOT_USED4 = 4,\n\tACPI_HEST_TYPE_NOT_USED5 = 5,\n\tACPI_HEST_TYPE_AER_ROOT_PORT = 6,\n\tACPI_HEST_TYPE_AER_ENDPOINT = 7,\n\tACPI_HEST_TYPE_AER_BRIDGE = 8,\n\tACPI_HEST_TYPE_GENERIC_ERROR = 9,\n\tACPI_HEST_TYPE_GENERIC_ERROR_V2 = 10,\n\tACPI_HEST_TYPE_IA32_DEFERRED_CHECK = 11,\n\tACPI_HEST_TYPE_RESERVED = 12,\n};\n\nstruct acpi_hest_ia_machine_check {\n\tstruct acpi_hest_header header;\n\tu16 reserved1;\n\tu8 flags;\n\tu8 enabled;\n\tu32 records_to_preallocate;\n\tu32 max_sections_per_record;\n\tu64 global_capability_data;\n\tu64 global_control_data;\n\tu8 num_hardware_banks;\n\tu8 reserved3[7];\n};\n\nstruct acpi_hest_generic {\n\tstruct acpi_hest_header header;\n\tu16 related_source_id;\n\tu8 reserved;\n\tu8 enabled;\n\tu32 records_to_preallocate;\n\tu32 max_sections_per_record;\n\tu32 max_raw_data_length;\n\tstruct acpi_generic_address error_status_address;\n\tstruct acpi_hest_notify notify;\n\tu32 error_block_length;\n} __attribute__((packed));\n\nstruct acpi_hest_ia_deferred_check {\n\tstruct acpi_hest_header header;\n\tu16 reserved1;\n\tu8 flags;\n\tu8 enabled;\n\tu32 records_to_preallocate;\n\tu32 max_sections_per_record;\n\tstruct acpi_hest_notify notify;\n\tu8 num_hardware_banks;\n\tu8 reserved2[3];\n};\n\nenum hest_status {\n\tHEST_ENABLED = 0,\n\tHEST_DISABLED = 1,\n\tHEST_NOT_FOUND = 2,\n};\n\ntypedef int (*apei_hest_func_t)(struct acpi_hest_header *, void *);\n\nstruct ghes_arr {\n\tstruct platform_device **ghes_devs;\n\tunsigned int count;\n};\n\nstruct acpi_table_erst {\n\tstruct acpi_table_header header;\n\tu32 header_length;\n\tu32 reserved;\n\tu32 entries;\n};\n\nenum acpi_erst_actions {\n\tACPI_ERST_BEGIN_WRITE = 0,\n\tACPI_ERST_BEGIN_READ = 1,\n\tACPI_ERST_BEGIN_CLEAR = 2,\n\tACPI_ERST_END = 3,\n\tACPI_ERST_SET_RECORD_OFFSET = 4,\n\tACPI_ERST_EXECUTE_OPERATION = 5,\n\tACPI_ERST_CHECK_BUSY_STATUS = 6,\n\tACPI_ERST_GET_COMMAND_STATUS = 7,\n\tACPI_ERST_GET_RECORD_ID = 8,\n\tACPI_ERST_SET_RECORD_ID = 9,\n\tACPI_ERST_GET_RECORD_COUNT = 10,\n\tACPI_ERST_BEGIN_DUMMY_WRIITE = 11,\n\tACPI_ERST_NOT_USED = 12,\n\tACPI_ERST_GET_ERROR_RANGE = 13,\n\tACPI_ERST_GET_ERROR_LENGTH = 14,\n\tACPI_ERST_GET_ERROR_ATTRIBUTES = 15,\n\tACPI_ERST_EXECUTE_TIMINGS = 16,\n\tACPI_ERST_ACTION_RESERVED = 17,\n};\n\nenum acpi_erst_instructions {\n\tACPI_ERST_READ_REGISTER = 0,\n\tACPI_ERST_READ_REGISTER_VALUE = 1,\n\tACPI_ERST_WRITE_REGISTER = 2,\n\tACPI_ERST_WRITE_REGISTER_VALUE = 3,\n\tACPI_ERST_NOOP = 4,\n\tACPI_ERST_LOAD_VAR1 = 5,\n\tACPI_ERST_LOAD_VAR2 = 6,\n\tACPI_ERST_STORE_VAR1 = 7,\n\tACPI_ERST_ADD = 8,\n\tACPI_ERST_SUBTRACT = 9,\n\tACPI_ERST_ADD_VALUE = 10,\n\tACPI_ERST_SUBTRACT_VALUE = 11,\n\tACPI_ERST_STALL = 12,\n\tACPI_ERST_STALL_WHILE_TRUE = 13,\n\tACPI_ERST_SKIP_NEXT_IF_TRUE = 14,\n\tACPI_ERST_GOTO = 15,\n\tACPI_ERST_SET_SRC_ADDRESS_BASE = 16,\n\tACPI_ERST_SET_DST_ADDRESS_BASE = 17,\n\tACPI_ERST_MOVE_DATA = 18,\n\tACPI_ERST_INSTRUCTION_RESERVED = 19,\n};\n\nstruct erst_erange {\n\tu64 base;\n\tu64 size;\n\tvoid *vaddr;\n\tu32 attr;\n};\n\nstruct erst_record_id_cache {\n\tstruct mutex lock;\n\tu64 *entries;\n\tint len;\n\tint size;\n\tint refcount;\n};\n\nstruct cper_pstore_record {\n\tstruct cper_record_header hdr;\n\tstruct cper_section_descriptor sec_hdr;\n\tchar data[0];\n};\n\nstruct acpi_bert_region {\n\tu32 block_status;\n\tu32 raw_data_offset;\n\tu32 raw_data_length;\n\tu32 data_length;\n\tu32 error_severity;\n};\n\nstruct acpi_hest_generic_status {\n\tu32 block_status;\n\tu32 raw_data_offset;\n\tu32 raw_data_length;\n\tu32 data_length;\n\tu32 error_severity;\n};\n\nenum acpi_hest_notify_types {\n\tACPI_HEST_NOTIFY_POLLED = 0,\n\tACPI_HEST_NOTIFY_EXTERNAL = 1,\n\tACPI_HEST_NOTIFY_LOCAL = 2,\n\tACPI_HEST_NOTIFY_SCI = 3,\n\tACPI_HEST_NOTIFY_NMI = 4,\n\tACPI_HEST_NOTIFY_CMCI = 5,\n\tACPI_HEST_NOTIFY_MCE = 6,\n\tACPI_HEST_NOTIFY_GPIO = 7,\n\tACPI_HEST_NOTIFY_SEA = 8,\n\tACPI_HEST_NOTIFY_SEI = 9,\n\tACPI_HEST_NOTIFY_GSIV = 10,\n\tACPI_HEST_NOTIFY_SOFTWARE_DELEGATED = 11,\n\tACPI_HEST_NOTIFY_RESERVED = 12,\n};\n\nstruct acpi_hest_generic_v2 {\n\tstruct acpi_hest_header header;\n\tu16 related_source_id;\n\tu8 reserved;\n\tu8 enabled;\n\tu32 records_to_preallocate;\n\tu32 max_sections_per_record;\n\tu32 max_raw_data_length;\n\tstruct acpi_generic_address error_status_address;\n\tstruct acpi_hest_notify notify;\n\tu32 error_block_length;\n\tstruct acpi_generic_address read_ack_register;\n\tu64 read_ack_preserve;\n\tu64 read_ack_write;\n} __attribute__((packed));\n\nstruct acpi_hest_generic_data {\n\tu8 section_type[16];\n\tu32 error_severity;\n\tu16 revision;\n\tu8 validation_bits;\n\tu8 flags;\n\tu32 error_data_length;\n\tu8 fru_id[16];\n\tu8 fru_text[20];\n};\n\nstruct acpi_hest_generic_data_v300 {\n\tu8 section_type[16];\n\tu32 error_severity;\n\tu16 revision;\n\tu8 validation_bits;\n\tu8 flags;\n\tu32 error_data_length;\n\tu8 fru_id[16];\n\tu8 fru_text[20];\n\tu64 time_stamp;\n};\n\nstruct cper_sec_proc_arm {\n\tu32 validation_bits;\n\tu16 err_info_num;\n\tu16 context_info_num;\n\tu32 section_length;\n\tu8 affinity_level;\n\tu8 reserved[3];\n\tu64 mpidr;\n\tu64 midr;\n\tu32 running_state;\n\tu32 psci_state;\n};\n\nstruct cper_arm_err_info {\n\tu8 version;\n\tu8 length;\n\tu16 validation_bits;\n\tu8 type;\n\tu16 multiple_error;\n\tu8 flags;\n\tu64 error_info;\n\tu64 virt_fault_addr;\n\tu64 physical_fault_addr;\n} __attribute__((packed));\n\nstruct cper_sec_pcie {\n\tu64 validation_bits;\n\tu32 port_type;\n\tstruct {\n\t\tu8 minor;\n\t\tu8 major;\n\t\tu8 reserved[2];\n\t} version;\n\tu16 command;\n\tu16 status;\n\tu32 reserved;\n\tstruct {\n\t\tu16 vendor_id;\n\t\tu16 device_id;\n\t\tu8 class_code[3];\n\t\tu8 function;\n\t\tu8 device;\n\t\tu16 segment;\n\t\tu8 bus;\n\t\tu8 secondary_bus;\n\t\tu16 slot;\n\t\tu8 reserved;\n\t} __attribute__((packed)) device_id;\n\tstruct {\n\t\tu32 lower;\n\t\tu32 upper;\n\t} serial_number;\n\tstruct {\n\t\tu16 secondary_status;\n\t\tu16 control;\n\t} bridge;\n\tu8 capability[60];\n\tu8 aer_info[96];\n};\n\nstruct ghes {\n\tunion {\n\t\tstruct acpi_hest_generic *generic;\n\t\tstruct acpi_hest_generic_v2 *generic_v2;\n\t};\n\tstruct acpi_hest_generic_status *estatus;\n\tlong unsigned int flags;\n\tunion {\n\t\tstruct list_head list;\n\t\tstruct timer_list timer;\n\t\tunsigned int irq;\n\t};\n};\n\nstruct ghes_estatus_node {\n\tstruct llist_node llnode;\n\tstruct acpi_hest_generic *generic;\n\tstruct ghes *ghes;\n\tint task_work_cpu;\n\tstruct callback_head task_work;\n};\n\nstruct ghes_estatus_cache {\n\tu32 estatus_len;\n\tatomic_t count;\n\tstruct acpi_hest_generic *generic;\n\tlong long unsigned int time_in;\n\tstruct callback_head rcu;\n};\n\nstruct ghes_vendor_record_entry {\n\tstruct work_struct work;\n\tint error_severity;\n\tchar vendor_record[0];\n};\n\nstruct pmic_table {\n\tint address;\n\tint reg;\n\tint bit;\n};\n\nstruct intel_pmic_opregion_data {\n\tint (*get_power)(struct regmap *, int, int, u64 *);\n\tint (*update_power)(struct regmap *, int, int, bool);\n\tint (*get_raw_temp)(struct regmap *, int);\n\tint (*update_aux)(struct regmap *, int, int);\n\tint (*get_policy)(struct regmap *, int, int, u64 *);\n\tint (*update_policy)(struct regmap *, int, int, int);\n\tint (*exec_mipi_pmic_seq_element)(struct regmap *, u16, u32, u32, u32);\n\tstruct pmic_table *power_table;\n\tint power_table_count;\n\tstruct pmic_table *thermal_table;\n\tint thermal_table_count;\n\tint pmic_i2c_address;\n};\n\nstruct intel_pmic_regs_handler_ctx {\n\tunsigned int val;\n\tu16 addr;\n};\n\nstruct intel_pmic_opregion {\n\tstruct mutex lock;\n\tstruct acpi_lpat_conversion_table *lpat_table;\n\tstruct regmap *regmap;\n\tstruct intel_pmic_opregion_data *data;\n\tstruct intel_pmic_regs_handler_ctx ctx;\n};\n\nstruct regmap_irq_type {\n\tunsigned int type_reg_offset;\n\tunsigned int type_reg_mask;\n\tunsigned int type_rising_val;\n\tunsigned int type_falling_val;\n\tunsigned int type_level_low_val;\n\tunsigned int type_level_high_val;\n\tunsigned int types_supported;\n};\n\nstruct regmap_irq {\n\tunsigned int reg_offset;\n\tunsigned int mask;\n\tstruct regmap_irq_type type;\n};\n\nstruct regmap_irq_sub_irq_map {\n\tunsigned int num_regs;\n\tunsigned int *offset;\n};\n\nstruct regmap_irq_chip {\n\tconst char *name;\n\tunsigned int main_status;\n\tunsigned int num_main_status_bits;\n\tstruct regmap_irq_sub_irq_map *sub_reg_offsets;\n\tint num_main_regs;\n\tunsigned int status_base;\n\tunsigned int mask_base;\n\tunsigned int unmask_base;\n\tunsigned int ack_base;\n\tunsigned int wake_base;\n\tunsigned int type_base;\n\tunsigned int *virt_reg_base;\n\tunsigned int irq_reg_stride;\n\tbool mask_writeonly: 1;\n\tbool init_ack_masked: 1;\n\tbool mask_invert: 1;\n\tbool use_ack: 1;\n\tbool ack_invert: 1;\n\tbool clear_ack: 1;\n\tbool wake_invert: 1;\n\tbool runtime_pm: 1;\n\tbool type_invert: 1;\n\tbool type_in_mask: 1;\n\tbool clear_on_unmask: 1;\n\tbool not_fixed_stride: 1;\n\tbool status_invert: 1;\n\tint num_regs;\n\tconst struct regmap_irq *irqs;\n\tint num_irqs;\n\tint num_type_reg;\n\tint num_virt_regs;\n\tunsigned int type_reg_stride;\n\tint (*handle_pre_irq)(void *);\n\tint (*handle_post_irq)(void *);\n\tint (*set_type_virt)(unsigned int **, unsigned int, long unsigned int, int);\n\tvoid *irq_drv_data;\n};\n\nstruct axp20x_dev {\n\tstruct device *dev;\n\tint irq;\n\tlong unsigned int irq_flags;\n\tstruct regmap *regmap;\n\tstruct regmap_irq_chip_data *regmap_irqc;\n\tlong int variant;\n\tint nr_cells;\n\tconst struct mfd_cell *cells;\n\tconst struct regmap_config *regmap_cfg;\n\tconst struct regmap_irq_chip *regmap_irq_chip;\n};\n\nstruct mfd_cell_acpi_match;\n\nstruct mfd_cell {\n\tconst char *name;\n\tint id;\n\tint level;\n\tint (*enable)(struct platform_device *);\n\tint (*disable)(struct platform_device *);\n\tint (*suspend)(struct platform_device *);\n\tint (*resume)(struct platform_device *);\n\tvoid *platform_data;\n\tsize_t pdata_size;\n\tconst struct software_node *swnode;\n\tconst char *of_compatible;\n\tconst u64 of_reg;\n\tbool use_of_reg;\n\tconst struct mfd_cell_acpi_match *acpi_match;\n\tint num_resources;\n\tconst struct resource *resources;\n\tbool ignore_resource_conflicts;\n\tbool pm_runtime_no_callbacks;\n\tconst char * const *parent_supplies;\n\tint num_parent_supplies;\n};\n\nstruct tps68470_pmic_table {\n\tu32 address;\n\tu32 reg;\n\tu32 bitmask;\n};\n\nstruct tps68470_pmic_opregion {\n\tstruct mutex lock;\n\tstruct regmap *regmap;\n};\n\nstruct acpi_table_viot {\n\tstruct acpi_table_header header;\n\tu16 node_count;\n\tu16 node_offset;\n\tu8 reserved[8];\n};\n\nstruct acpi_viot_header {\n\tu8 type;\n\tu8 reserved;\n\tu16 length;\n};\n\nenum acpi_viot_node_type {\n\tACPI_VIOT_NODE_PCI_RANGE = 1,\n\tACPI_VIOT_NODE_MMIO = 2,\n\tACPI_VIOT_NODE_VIRTIO_IOMMU_PCI = 3,\n\tACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO = 4,\n\tACPI_VIOT_RESERVED = 5,\n};\n\nstruct acpi_viot_pci_range {\n\tstruct acpi_viot_header header;\n\tu32 endpoint_start;\n\tu16 segment_start;\n\tu16 segment_end;\n\tu16 bdf_start;\n\tu16 bdf_end;\n\tu16 output_node;\n\tu8 reserved[6];\n};\n\nstruct acpi_viot_mmio {\n\tstruct acpi_viot_header header;\n\tu32 endpoint;\n\tu64 base_address;\n\tu16 output_node;\n\tu8 reserved[6];\n};\n\nstruct acpi_viot_virtio_iommu_pci {\n\tstruct acpi_viot_header header;\n\tu16 segment;\n\tu16 bdf;\n\tu8 reserved[8];\n};\n\nstruct acpi_viot_virtio_iommu_mmio {\n\tstruct acpi_viot_header header;\n\tu8 reserved[4];\n\tu64 base_address;\n};\n\nstruct viot_iommu {\n\tunsigned int offset;\n\tstruct fwnode_handle *fwnode;\n\tstruct list_head list;\n};\n\nstruct viot_endpoint {\n\tunion {\n\t\tstruct {\n\t\t\tu16 segment_start;\n\t\t\tu16 segment_end;\n\t\t\tu16 bdf_start;\n\t\t\tu16 bdf_end;\n\t\t};\n\t\tu64 address;\n\t};\n\tu32 endpoint_id;\n\tstruct viot_iommu *viommu;\n\tstruct list_head list;\n};\n\nstruct pnp_resource {\n\tstruct list_head list;\n\tstruct resource res;\n};\n\nstruct pnp_port {\n\tresource_size_t min;\n\tresource_size_t max;\n\tresource_size_t align;\n\tresource_size_t size;\n\tunsigned char flags;\n};\n\ntypedef struct {\n\tlong unsigned int bits[4];\n} pnp_irq_mask_t;\n\nstruct pnp_irq {\n\tpnp_irq_mask_t map;\n\tunsigned char flags;\n};\n\nstruct pnp_dma {\n\tunsigned char map;\n\tunsigned char flags;\n};\n\nstruct pnp_mem {\n\tresource_size_t min;\n\tresource_size_t max;\n\tresource_size_t align;\n\tresource_size_t size;\n\tunsigned char flags;\n};\n\nstruct pnp_option {\n\tstruct list_head list;\n\tunsigned int flags;\n\tlong unsigned int type;\n\tunion {\n\t\tstruct pnp_port port;\n\t\tstruct pnp_irq irq;\n\t\tstruct pnp_dma dma;\n\t\tstruct pnp_mem mem;\n\t} u;\n};\n\nstruct pnp_info_buffer {\n\tchar *buffer;\n\tchar *curr;\n\tlong unsigned int size;\n\tlong unsigned int len;\n\tint stop;\n\tint error;\n};\n\ntypedef struct pnp_info_buffer pnp_info_buffer_t;\n\nstruct pnp_fixup {\n\tchar id[7];\n\tvoid (*quirk_function)(struct pnp_dev *);\n};\n\nstruct acpipnp_parse_option_s {\n\tstruct pnp_dev *dev;\n\tunsigned int option_flags;\n};\n\nstruct clk_bulk_data {\n\tconst char *id;\n\tstruct clk *clk;\n};\n\nstruct clk_bulk_devres {\n\tstruct clk_bulk_data *clks;\n\tint num_clks;\n};\n\nstruct clk_hw;\n\nstruct clk_lookup {\n\tstruct list_head node;\n\tconst char *dev_id;\n\tconst char *con_id;\n\tstruct clk *clk;\n\tstruct clk_hw *clk_hw;\n};\n\nstruct clk_init_data;\n\nstruct clk_hw {\n\tstruct clk_core *core;\n\tstruct clk *clk;\n\tconst struct clk_init_data *init;\n};\n\nstruct clk_rate_request {\n\tlong unsigned int rate;\n\tlong unsigned int min_rate;\n\tlong unsigned int max_rate;\n\tlong unsigned int best_parent_rate;\n\tstruct clk_hw *best_parent_hw;\n};\n\nstruct clk_duty {\n\tunsigned int num;\n\tunsigned int den;\n};\n\nstruct clk_ops {\n\tint (*prepare)(struct clk_hw *);\n\tvoid (*unprepare)(struct clk_hw *);\n\tint (*is_prepared)(struct clk_hw *);\n\tvoid (*unprepare_unused)(struct clk_hw *);\n\tint (*enable)(struct clk_hw *);\n\tvoid (*disable)(struct clk_hw *);\n\tint (*is_enabled)(struct clk_hw *);\n\tvoid (*disable_unused)(struct clk_hw *);\n\tint (*save_context)(struct clk_hw *);\n\tvoid (*restore_context)(struct clk_hw *);\n\tlong unsigned int (*recalc_rate)(struct clk_hw *, long unsigned int);\n\tlong int (*round_rate)(struct clk_hw *, long unsigned int, long unsigned int *);\n\tint (*determine_rate)(struct clk_hw *, struct clk_rate_request *);\n\tint (*set_parent)(struct clk_hw *, u8);\n\tu8 (*get_parent)(struct clk_hw *);\n\tint (*set_rate)(struct clk_hw *, long unsigned int, long unsigned int);\n\tint (*set_rate_and_parent)(struct clk_hw *, long unsigned int, long unsigned int, u8);\n\tlong unsigned int (*recalc_accuracy)(struct clk_hw *, long unsigned int);\n\tint (*get_phase)(struct clk_hw *);\n\tint (*set_phase)(struct clk_hw *, int);\n\tint (*get_duty_cycle)(struct clk_hw *, struct clk_duty *);\n\tint (*set_duty_cycle)(struct clk_hw *, struct clk_duty *);\n\tint (*init)(struct clk_hw *);\n\tvoid (*terminate)(struct clk_hw *);\n\tvoid (*debug_init)(struct clk_hw *, struct dentry *);\n};\n\nstruct clk_parent_data {\n\tconst struct clk_hw *hw;\n\tconst char *fw_name;\n\tconst char *name;\n\tint index;\n};\n\nstruct clk_init_data {\n\tconst char *name;\n\tconst struct clk_ops *ops;\n\tconst char * const *parent_names;\n\tconst struct clk_parent_data *parent_data;\n\tconst struct clk_hw **parent_hws;\n\tu8 num_parents;\n\tlong unsigned int flags;\n};\n\nstruct clk_lookup_alloc {\n\tstruct clk_lookup cl;\n\tchar dev_id[20];\n\tchar con_id[16];\n};\n\nstruct clk_notifier {\n\tstruct clk *clk;\n\tstruct srcu_notifier_head notifier_head;\n\tstruct list_head node;\n};\n\nstruct clk_notifier_data {\n\tstruct clk *clk;\n\tlong unsigned int old_rate;\n\tlong unsigned int new_rate;\n};\n\nstruct clk_parent_map;\n\nstruct clk_core {\n\tconst char *name;\n\tconst struct clk_ops *ops;\n\tstruct clk_hw *hw;\n\tstruct module *owner;\n\tstruct device *dev;\n\tstruct device_node *of_node;\n\tstruct clk_core *parent;\n\tstruct clk_parent_map *parents;\n\tu8 num_parents;\n\tu8 new_parent_index;\n\tlong unsigned int rate;\n\tlong unsigned int req_rate;\n\tlong unsigned int new_rate;\n\tstruct clk_core *new_parent;\n\tstruct clk_core *new_child;\n\tlong unsigned int flags;\n\tbool orphan;\n\tbool rpm_enabled;\n\tunsigned int enable_count;\n\tunsigned int prepare_count;\n\tunsigned int protect_count;\n\tlong unsigned int min_rate;\n\tlong unsigned int max_rate;\n\tlong unsigned int accuracy;\n\tint phase;\n\tstruct clk_duty duty;\n\tstruct hlist_head children;\n\tstruct hlist_node child_node;\n\tstruct hlist_head clks;\n\tunsigned int notifier_count;\n\tstruct dentry *dentry;\n\tstruct hlist_node debug_node;\n\tstruct kref ref;\n};\n\nstruct clk_parent_map {\n\tconst struct clk_hw *hw;\n\tstruct clk_core *core;\n\tconst char *fw_name;\n\tconst char *name;\n\tint index;\n};\n\nstruct trace_event_raw_clk {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_clk_rate {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tlong unsigned int rate;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_clk_rate_range {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tlong unsigned int min;\n\tlong unsigned int max;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_clk_parent {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tu32 __data_loc_pname;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_clk_phase {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tint phase;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_clk_duty_cycle {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tunsigned int num;\n\tunsigned int den;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_clk {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_clk_rate {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_clk_rate_range {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_clk_parent {\n\tu32 name;\n\tu32 pname;\n};\n\nstruct trace_event_data_offsets_clk_phase {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_clk_duty_cycle {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_clk_enable)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_enable_complete)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_disable)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_disable_complete)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_prepare)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_prepare_complete)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_unprepare)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_unprepare_complete)(void *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_set_rate)(void *, struct clk_core *, long unsigned int);\n\ntypedef void (*btf_trace_clk_set_rate_complete)(void *, struct clk_core *, long unsigned int);\n\ntypedef void (*btf_trace_clk_set_min_rate)(void *, struct clk_core *, long unsigned int);\n\ntypedef void (*btf_trace_clk_set_max_rate)(void *, struct clk_core *, long unsigned int);\n\ntypedef void (*btf_trace_clk_set_rate_range)(void *, struct clk_core *, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_clk_set_parent)(void *, struct clk_core *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_set_parent_complete)(void *, struct clk_core *, struct clk_core *);\n\ntypedef void (*btf_trace_clk_set_phase)(void *, struct clk_core *, int);\n\ntypedef void (*btf_trace_clk_set_phase_complete)(void *, struct clk_core *, int);\n\ntypedef void (*btf_trace_clk_set_duty_cycle)(void *, struct clk_core *, struct clk_duty *);\n\ntypedef void (*btf_trace_clk_set_duty_cycle_complete)(void *, struct clk_core *, struct clk_duty *);\n\nstruct clk_notifier_devres {\n\tstruct clk *clk;\n\tstruct notifier_block *nb;\n};\n\nstruct clk_div_table {\n\tunsigned int val;\n\tunsigned int div;\n};\n\nstruct clk_divider {\n\tstruct clk_hw hw;\n\tvoid *reg;\n\tu8 shift;\n\tu8 width;\n\tu8 flags;\n\tconst struct clk_div_table *table;\n\tspinlock_t *lock;\n};\n\nstruct clk_fixed_factor {\n\tstruct clk_hw hw;\n\tunsigned int mult;\n\tunsigned int div;\n};\n\nstruct clk_fixed_rate {\n\tstruct clk_hw hw;\n\tlong unsigned int fixed_rate;\n\tlong unsigned int fixed_accuracy;\n\tlong unsigned int flags;\n};\n\nstruct clk_gate {\n\tstruct clk_hw hw;\n\tvoid *reg;\n\tu8 bit_idx;\n\tu8 flags;\n\tspinlock_t *lock;\n};\n\nstruct clk_multiplier {\n\tstruct clk_hw hw;\n\tvoid *reg;\n\tu8 shift;\n\tu8 width;\n\tu8 flags;\n\tspinlock_t *lock;\n};\n\nstruct clk_mux {\n\tstruct clk_hw hw;\n\tvoid *reg;\n\tu32 *table;\n\tu32 mask;\n\tu8 shift;\n\tu8 flags;\n\tspinlock_t *lock;\n};\n\nstruct clk_composite {\n\tstruct clk_hw hw;\n\tstruct clk_ops ops;\n\tstruct clk_hw *mux_hw;\n\tstruct clk_hw *rate_hw;\n\tstruct clk_hw *gate_hw;\n\tconst struct clk_ops *mux_ops;\n\tconst struct clk_ops *rate_ops;\n\tconst struct clk_ops *gate_ops;\n};\n\nstruct clk_fractional_divider {\n\tstruct clk_hw hw;\n\tvoid *reg;\n\tu8 mshift;\n\tu8 mwidth;\n\tu32 mmask;\n\tu8 nshift;\n\tu8 nwidth;\n\tu32 nmask;\n\tu8 flags;\n\tvoid (*approximation)(struct clk_hw *, long unsigned int, long unsigned int *, long unsigned int *, long unsigned int *);\n\tspinlock_t *lock;\n};\n\nstruct clk_gpio {\n\tstruct clk_hw hw;\n\tstruct gpio_desc *gpiod;\n};\n\nstruct pmc_clk {\n\tconst char *name;\n\tlong unsigned int freq;\n\tconst char *parent_name;\n};\n\nstruct pmc_clk_data {\n\tvoid *base;\n\tconst struct pmc_clk *clks;\n\tbool critical;\n};\n\nstruct clk_plt_fixed {\n\tstruct clk_hw *clk;\n\tstruct clk_lookup *lookup;\n};\n\nstruct clk_plt {\n\tstruct clk_hw hw;\n\tvoid *reg;\n\tstruct clk_lookup *lookup;\n\tspinlock_t lock;\n};\n\nstruct clk_plt_data {\n\tstruct clk_plt_fixed **parents;\n\tu8 nparents;\n\tstruct clk_plt *clks[6];\n\tstruct clk_lookup *mclk_lookup;\n\tstruct clk_lookup *ether_clk_lookup;\n};\n\ntypedef s32 dma_cookie_t;\n\nenum dma_status {\n\tDMA_COMPLETE = 0,\n\tDMA_IN_PROGRESS = 1,\n\tDMA_PAUSED = 2,\n\tDMA_ERROR = 3,\n\tDMA_OUT_OF_ORDER = 4,\n};\n\nenum dma_transaction_type {\n\tDMA_MEMCPY = 0,\n\tDMA_XOR = 1,\n\tDMA_PQ = 2,\n\tDMA_XOR_VAL = 3,\n\tDMA_PQ_VAL = 4,\n\tDMA_MEMSET = 5,\n\tDMA_MEMSET_SG = 6,\n\tDMA_INTERRUPT = 7,\n\tDMA_PRIVATE = 8,\n\tDMA_ASYNC_TX = 9,\n\tDMA_SLAVE = 10,\n\tDMA_CYCLIC = 11,\n\tDMA_INTERLEAVE = 12,\n\tDMA_COMPLETION_NO_ORDER = 13,\n\tDMA_REPEAT = 14,\n\tDMA_LOAD_EOT = 15,\n\tDMA_TX_TYPE_END = 16,\n};\n\nenum dma_transfer_direction {\n\tDMA_MEM_TO_MEM = 0,\n\tDMA_MEM_TO_DEV = 1,\n\tDMA_DEV_TO_MEM = 2,\n\tDMA_DEV_TO_DEV = 3,\n\tDMA_TRANS_NONE = 4,\n};\n\nstruct data_chunk {\n\tsize_t size;\n\tsize_t icg;\n\tsize_t dst_icg;\n\tsize_t src_icg;\n};\n\nstruct dma_interleaved_template {\n\tdma_addr_t src_start;\n\tdma_addr_t dst_start;\n\tenum dma_transfer_direction dir;\n\tbool src_inc;\n\tbool dst_inc;\n\tbool src_sgl;\n\tbool dst_sgl;\n\tsize_t numf;\n\tsize_t frame_size;\n\tstruct data_chunk sgl[0];\n};\n\nenum dma_ctrl_flags {\n\tDMA_PREP_INTERRUPT = 1,\n\tDMA_CTRL_ACK = 2,\n\tDMA_PREP_PQ_DISABLE_P = 4,\n\tDMA_PREP_PQ_DISABLE_Q = 8,\n\tDMA_PREP_CONTINUE = 16,\n\tDMA_PREP_FENCE = 32,\n\tDMA_CTRL_REUSE = 64,\n\tDMA_PREP_CMD = 128,\n\tDMA_PREP_REPEAT = 256,\n\tDMA_PREP_LOAD_EOT = 512,\n};\n\nenum sum_check_bits {\n\tSUM_CHECK_P = 0,\n\tSUM_CHECK_Q = 1,\n};\n\nenum sum_check_flags {\n\tSUM_CHECK_P_RESULT = 1,\n\tSUM_CHECK_Q_RESULT = 2,\n};\n\ntypedef struct {\n\tlong unsigned int bits[1];\n} dma_cap_mask_t;\n\nenum dma_desc_metadata_mode {\n\tDESC_METADATA_NONE = 0,\n\tDESC_METADATA_CLIENT = 1,\n\tDESC_METADATA_ENGINE = 2,\n};\n\nstruct dma_chan_percpu {\n\tlong unsigned int memcpy_count;\n\tlong unsigned int bytes_transferred;\n};\n\nstruct dma_router {\n\tstruct device *dev;\n\tvoid (*route_free)(struct device *, void *);\n};\n\nstruct dma_device;\n\nstruct dma_chan_dev;\n\nstruct dma_chan___2 {\n\tstruct dma_device *device;\n\tstruct device *slave;\n\tdma_cookie_t cookie;\n\tdma_cookie_t completed_cookie;\n\tint chan_id;\n\tstruct dma_chan_dev *dev;\n\tconst char *name;\n\tchar *dbg_client_name;\n\tstruct list_head device_node;\n\tstruct dma_chan_percpu *local;\n\tint client_count;\n\tint table_count;\n\tstruct dma_router *router;\n\tvoid *route_data;\n\tvoid *private;\n};\n\ntypedef bool (*dma_filter_fn)(struct dma_chan___2 *, void *);\n\nstruct dma_slave_map;\n\nstruct dma_filter {\n\tdma_filter_fn fn;\n\tint mapcnt;\n\tconst struct dma_slave_map *map;\n};\n\nenum dmaengine_alignment {\n\tDMAENGINE_ALIGN_1_BYTE = 0,\n\tDMAENGINE_ALIGN_2_BYTES = 1,\n\tDMAENGINE_ALIGN_4_BYTES = 2,\n\tDMAENGINE_ALIGN_8_BYTES = 3,\n\tDMAENGINE_ALIGN_16_BYTES = 4,\n\tDMAENGINE_ALIGN_32_BYTES = 5,\n\tDMAENGINE_ALIGN_64_BYTES = 6,\n\tDMAENGINE_ALIGN_128_BYTES = 7,\n\tDMAENGINE_ALIGN_256_BYTES = 8,\n};\n\nenum dma_residue_granularity {\n\tDMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0,\n\tDMA_RESIDUE_GRANULARITY_SEGMENT = 1,\n\tDMA_RESIDUE_GRANULARITY_BURST = 2,\n};\n\nstruct dma_async_tx_descriptor;\n\nstruct dma_slave_caps;\n\nstruct dma_slave_config;\n\nstruct dma_tx_state;\n\nstruct dma_device {\n\tstruct kref ref;\n\tunsigned int chancnt;\n\tunsigned int privatecnt;\n\tstruct list_head channels;\n\tstruct list_head global_node;\n\tstruct dma_filter filter;\n\tdma_cap_mask_t cap_mask;\n\tenum dma_desc_metadata_mode desc_metadata_modes;\n\tshort unsigned int max_xor;\n\tshort unsigned int max_pq;\n\tenum dmaengine_alignment copy_align;\n\tenum dmaengine_alignment xor_align;\n\tenum dmaengine_alignment pq_align;\n\tenum dmaengine_alignment fill_align;\n\tint dev_id;\n\tstruct device *dev;\n\tstruct module *owner;\n\tstruct ida chan_ida;\n\tstruct mutex chan_mutex;\n\tu32 src_addr_widths;\n\tu32 dst_addr_widths;\n\tu32 directions;\n\tu32 min_burst;\n\tu32 max_burst;\n\tu32 max_sg_burst;\n\tbool descriptor_reuse;\n\tenum dma_residue_granularity residue_granularity;\n\tint (*device_alloc_chan_resources)(struct dma_chan___2 *);\n\tint (*device_router_config)(struct dma_chan___2 *);\n\tvoid (*device_free_chan_resources)(struct dma_chan___2 *);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_memcpy)(struct dma_chan___2 *, dma_addr_t, dma_addr_t, size_t, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_xor)(struct dma_chan___2 *, dma_addr_t, dma_addr_t *, unsigned int, size_t, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_xor_val)(struct dma_chan___2 *, dma_addr_t *, unsigned int, size_t, enum sum_check_flags *, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_pq)(struct dma_chan___2 *, dma_addr_t *, dma_addr_t *, unsigned int, const unsigned char *, size_t, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_pq_val)(struct dma_chan___2 *, dma_addr_t *, dma_addr_t *, unsigned int, const unsigned char *, size_t, enum sum_check_flags *, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_memset)(struct dma_chan___2 *, dma_addr_t, int, size_t, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_memset_sg)(struct dma_chan___2 *, struct scatterlist *, unsigned int, int, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_interrupt)(struct dma_chan___2 *, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_slave_sg)(struct dma_chan___2 *, struct scatterlist *, unsigned int, enum dma_transfer_direction, long unsigned int, void *);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_cyclic)(struct dma_chan___2 *, dma_addr_t, size_t, size_t, enum dma_transfer_direction, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_interleaved_dma)(struct dma_chan___2 *, struct dma_interleaved_template *, long unsigned int);\n\tstruct dma_async_tx_descriptor * (*device_prep_dma_imm_data)(struct dma_chan___2 *, dma_addr_t, u64, long unsigned int);\n\tvoid (*device_caps)(struct dma_chan___2 *, struct dma_slave_caps *);\n\tint (*device_config)(struct dma_chan___2 *, struct dma_slave_config *);\n\tint (*device_pause)(struct dma_chan___2 *);\n\tint (*device_resume)(struct dma_chan___2 *);\n\tint (*device_terminate_all)(struct dma_chan___2 *);\n\tvoid (*device_synchronize)(struct dma_chan___2 *);\n\tenum dma_status (*device_tx_status)(struct dma_chan___2 *, dma_cookie_t, struct dma_tx_state *);\n\tvoid (*device_issue_pending)(struct dma_chan___2 *);\n\tvoid (*device_release)(struct dma_device *);\n\tvoid (*dbg_summary_show)(struct seq_file *, struct dma_device *);\n\tstruct dentry *dbg_dev_root;\n};\n\nstruct dma_chan_dev {\n\tstruct dma_chan___2 *chan;\n\tstruct device device;\n\tint dev_id;\n\tbool chan_dma_dev;\n};\n\nenum dma_slave_buswidth {\n\tDMA_SLAVE_BUSWIDTH_UNDEFINED = 0,\n\tDMA_SLAVE_BUSWIDTH_1_BYTE = 1,\n\tDMA_SLAVE_BUSWIDTH_2_BYTES = 2,\n\tDMA_SLAVE_BUSWIDTH_3_BYTES = 3,\n\tDMA_SLAVE_BUSWIDTH_4_BYTES = 4,\n\tDMA_SLAVE_BUSWIDTH_8_BYTES = 8,\n\tDMA_SLAVE_BUSWIDTH_16_BYTES = 16,\n\tDMA_SLAVE_BUSWIDTH_32_BYTES = 32,\n\tDMA_SLAVE_BUSWIDTH_64_BYTES = 64,\n};\n\nstruct dma_slave_config {\n\tenum dma_transfer_direction direction;\n\tphys_addr_t src_addr;\n\tphys_addr_t dst_addr;\n\tenum dma_slave_buswidth src_addr_width;\n\tenum dma_slave_buswidth dst_addr_width;\n\tu32 src_maxburst;\n\tu32 dst_maxburst;\n\tu32 src_port_window_size;\n\tu32 dst_port_window_size;\n\tbool device_fc;\n\tunsigned int slave_id;\n\tvoid *peripheral_config;\n\tsize_t peripheral_size;\n};\n\nstruct dma_slave_caps {\n\tu32 src_addr_widths;\n\tu32 dst_addr_widths;\n\tu32 directions;\n\tu32 min_burst;\n\tu32 max_burst;\n\tu32 max_sg_burst;\n\tbool cmd_pause;\n\tbool cmd_resume;\n\tbool cmd_terminate;\n\tenum dma_residue_granularity residue_granularity;\n\tbool descriptor_reuse;\n};\n\ntypedef void (*dma_async_tx_callback)(void *);\n\nenum dmaengine_tx_result {\n\tDMA_TRANS_NOERROR = 0,\n\tDMA_TRANS_READ_FAILED = 1,\n\tDMA_TRANS_WRITE_FAILED = 2,\n\tDMA_TRANS_ABORTED = 3,\n};\n\nstruct dmaengine_result {\n\tenum dmaengine_tx_result result;\n\tu32 residue;\n};\n\ntypedef void (*dma_async_tx_callback_result)(void *, const struct dmaengine_result *);\n\nstruct dmaengine_unmap_data {\n\tu16 map_cnt;\n\tu8 to_cnt;\n\tu8 from_cnt;\n\tu8 bidi_cnt;\n\tstruct device *dev;\n\tstruct kref kref;\n\tsize_t len;\n\tdma_addr_t addr[0];\n};\n\nstruct dma_descriptor_metadata_ops {\n\tint (*attach)(struct dma_async_tx_descriptor *, void *, size_t);\n\tvoid * (*get_ptr)(struct dma_async_tx_descriptor *, size_t *, size_t *);\n\tint (*set_len)(struct dma_async_tx_descriptor *, size_t);\n};\n\nstruct dma_async_tx_descriptor {\n\tdma_cookie_t cookie;\n\tenum dma_ctrl_flags flags;\n\tdma_addr_t phys;\n\tstruct dma_chan___2 *chan;\n\tdma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *);\n\tint (*desc_free)(struct dma_async_tx_descriptor *);\n\tdma_async_tx_callback callback;\n\tdma_async_tx_callback_result callback_result;\n\tvoid *callback_param;\n\tstruct dmaengine_unmap_data *unmap;\n\tenum dma_desc_metadata_mode desc_metadata_mode;\n\tstruct dma_descriptor_metadata_ops *metadata_ops;\n};\n\nstruct dma_tx_state {\n\tdma_cookie_t last;\n\tdma_cookie_t used;\n\tu32 residue;\n\tu32 in_flight_bytes;\n};\n\nstruct dma_slave_map {\n\tconst char *devname;\n\tconst char *slave;\n\tvoid *param;\n};\n\nstruct dma_chan_tbl_ent {\n\tstruct dma_chan___2 *chan;\n};\n\nstruct dmaengine_unmap_pool {\n\tstruct kmem_cache *cache;\n\tconst char *name;\n\tmempool_t *pool;\n\tsize_t size;\n};\n\nstruct dmaengine_desc_callback {\n\tdma_async_tx_callback callback;\n\tdma_async_tx_callback_result callback_result;\n\tvoid *callback_param;\n};\n\nstruct virt_dma_desc {\n\tstruct dma_async_tx_descriptor tx;\n\tstruct dmaengine_result tx_result;\n\tstruct list_head node;\n};\n\nstruct virt_dma_chan {\n\tstruct dma_chan___2 chan;\n\tstruct tasklet_struct task;\n\tvoid (*desc_free)(struct virt_dma_desc *);\n\tspinlock_t lock;\n\tstruct list_head desc_allocated;\n\tstruct list_head desc_submitted;\n\tstruct list_head desc_issued;\n\tstruct list_head desc_completed;\n\tstruct list_head desc_terminated;\n\tstruct virt_dma_desc *cyclic;\n};\n\nstruct acpi_table_csrt {\n\tstruct acpi_table_header header;\n};\n\nstruct acpi_csrt_group {\n\tu32 length;\n\tu32 vendor_id;\n\tu32 subvendor_id;\n\tu16 device_id;\n\tu16 subdevice_id;\n\tu16 revision;\n\tu16 reserved;\n\tu32 shared_info_length;\n};\n\nstruct acpi_csrt_shared_info {\n\tu16 major_version;\n\tu16 minor_version;\n\tu32 mmio_base_low;\n\tu32 mmio_base_high;\n\tu32 gsi_interrupt;\n\tu8 interrupt_polarity;\n\tu8 interrupt_mode;\n\tu8 num_channels;\n\tu8 dma_address_width;\n\tu16 base_request_line;\n\tu16 num_handshake_signals;\n\tu32 max_block_size;\n};\n\nstruct acpi_dma_spec {\n\tint chan_id;\n\tint slave_id;\n\tstruct device *dev;\n};\n\nstruct acpi_dma {\n\tstruct list_head dma_controllers;\n\tstruct device *dev;\n\tstruct dma_chan___2 * (*acpi_dma_xlate)(struct acpi_dma_spec *, struct acpi_dma *);\n\tvoid *data;\n\tshort unsigned int base_request_line;\n\tshort unsigned int end_request_line;\n};\n\nstruct acpi_dma_filter_info {\n\tdma_cap_mask_t dma_cap;\n\tdma_filter_fn filter_fn;\n};\n\nstruct acpi_dma_parser_data {\n\tstruct acpi_dma_spec dma_spec;\n\tsize_t index;\n\tsize_t n;\n};\n\nstruct dw_dma_slave {\n\tstruct device *dma_dev;\n\tu8 src_id;\n\tu8 dst_id;\n\tu8 m_master;\n\tu8 p_master;\n\tu8 channels;\n\tbool hs_polarity;\n};\n\nstruct dw_dma_platform_data {\n\tunsigned int nr_channels;\n\tunsigned char chan_allocation_order;\n\tunsigned char chan_priority;\n\tunsigned int block_size;\n\tunsigned char nr_masters;\n\tunsigned char data_width[4];\n\tunsigned char multi_block[8];\n\tu32 max_burst[8];\n\tunsigned char protctl;\n};\n\nstruct dw_dma;\n\nstruct dw_dma_chip {\n\tstruct device *dev;\n\tint id;\n\tint irq;\n\tvoid *regs;\n\tstruct clk *clk;\n\tstruct dw_dma *dw;\n\tconst struct dw_dma_platform_data *pdata;\n};\n\nstruct dma_pool___2;\n\nstruct dw_dma_chan;\n\nstruct dw_dma {\n\tstruct dma_device dma;\n\tchar name[20];\n\tvoid *regs;\n\tstruct dma_pool___2 *desc_pool;\n\tstruct tasklet_struct tasklet;\n\tstruct dw_dma_chan *chan;\n\tu8 all_chan_mask;\n\tu8 in_use;\n\tvoid (*initialize_chan)(struct dw_dma_chan *);\n\tvoid (*suspend_chan)(struct dw_dma_chan *, bool);\n\tvoid (*resume_chan)(struct dw_dma_chan *, bool);\n\tu32 (*prepare_ctllo)(struct dw_dma_chan *);\n\tvoid (*encode_maxburst)(struct dw_dma_chan *, u32 *);\n\tu32 (*bytes2block)(struct dw_dma_chan *, size_t, unsigned int, size_t *);\n\tsize_t (*block2bytes)(struct dw_dma_chan *, u32, u32);\n\tvoid (*set_device_name)(struct dw_dma *, int);\n\tvoid (*disable)(struct dw_dma *);\n\tvoid (*enable)(struct dw_dma *);\n\tstruct dw_dma_platform_data *pdata;\n};\n\nenum dw_dma_fc {\n\tDW_DMA_FC_D_M2M = 0,\n\tDW_DMA_FC_D_M2P = 1,\n\tDW_DMA_FC_D_P2M = 2,\n\tDW_DMA_FC_D_P2P = 3,\n\tDW_DMA_FC_P_P2M = 4,\n\tDW_DMA_FC_SP_P2P = 5,\n\tDW_DMA_FC_P_M2P = 6,\n\tDW_DMA_FC_DP_P2P = 7,\n};\n\nstruct dw_dma_chan_regs {\n\tu32 SAR;\n\tu32 __pad_SAR;\n\tu32 DAR;\n\tu32 __pad_DAR;\n\tu32 LLP;\n\tu32 __pad_LLP;\n\tu32 CTL_LO;\n\tu32 CTL_HI;\n\tu32 SSTAT;\n\tu32 __pad_SSTAT;\n\tu32 DSTAT;\n\tu32 __pad_DSTAT;\n\tu32 SSTATAR;\n\tu32 __pad_SSTATAR;\n\tu32 DSTATAR;\n\tu32 __pad_DSTATAR;\n\tu32 CFG_LO;\n\tu32 CFG_HI;\n\tu32 SGR;\n\tu32 __pad_SGR;\n\tu32 DSR;\n\tu32 __pad_DSR;\n};\n\nstruct dw_dma_irq_regs {\n\tu32 XFER;\n\tu32 __pad_XFER;\n\tu32 BLOCK;\n\tu32 __pad_BLOCK;\n\tu32 SRC_TRAN;\n\tu32 __pad_SRC_TRAN;\n\tu32 DST_TRAN;\n\tu32 __pad_DST_TRAN;\n\tu32 ERROR;\n\tu32 __pad_ERROR;\n};\n\nstruct dw_dma_regs {\n\tstruct dw_dma_chan_regs CHAN[8];\n\tstruct dw_dma_irq_regs RAW;\n\tstruct dw_dma_irq_regs STATUS;\n\tstruct dw_dma_irq_regs MASK;\n\tstruct dw_dma_irq_regs CLEAR;\n\tu32 STATUS_INT;\n\tu32 __pad_STATUS_INT;\n\tu32 REQ_SRC;\n\tu32 __pad_REQ_SRC;\n\tu32 REQ_DST;\n\tu32 __pad_REQ_DST;\n\tu32 SGL_REQ_SRC;\n\tu32 __pad_SGL_REQ_SRC;\n\tu32 SGL_REQ_DST;\n\tu32 __pad_SGL_REQ_DST;\n\tu32 LAST_SRC;\n\tu32 __pad_LAST_SRC;\n\tu32 LAST_DST;\n\tu32 __pad_LAST_DST;\n\tu32 CFG;\n\tu32 __pad_CFG;\n\tu32 CH_EN;\n\tu32 __pad_CH_EN;\n\tu32 ID;\n\tu32 __pad_ID;\n\tu32 TEST;\n\tu32 __pad_TEST;\n\tu32 CLASS_PRIORITY0;\n\tu32 __pad_CLASS_PRIORITY0;\n\tu32 CLASS_PRIORITY1;\n\tu32 __pad_CLASS_PRIORITY1;\n\tu32 __reserved;\n\tu32 DWC_PARAMS[8];\n\tu32 MULTI_BLK_TYPE;\n\tu32 MAX_BLK_SIZE;\n\tu32 DW_PARAMS;\n\tu32 COMP_TYPE;\n\tu32 COMP_VERSION;\n\tu32 FIFO_PARTITION0;\n\tu32 __pad_FIFO_PARTITION0;\n\tu32 FIFO_PARTITION1;\n\tu32 __pad_FIFO_PARTITION1;\n\tu32 SAI_ERR;\n\tu32 __pad_SAI_ERR;\n\tu32 GLOBAL_CFG;\n\tu32 __pad_GLOBAL_CFG;\n};\n\nenum dw_dmac_flags {\n\tDW_DMA_IS_CYCLIC = 0,\n\tDW_DMA_IS_SOFT_LLP = 1,\n\tDW_DMA_IS_PAUSED = 2,\n\tDW_DMA_IS_INITIALIZED = 3,\n};\n\nstruct dw_dma_chan {\n\tstruct dma_chan___2 chan;\n\tvoid *ch_regs;\n\tu8 mask;\n\tu8 priority;\n\tenum dma_transfer_direction direction;\n\tstruct list_head *tx_node_active;\n\tspinlock_t lock;\n\tlong unsigned int flags;\n\tstruct list_head active_list;\n\tstruct list_head queue;\n\tunsigned int descs_allocated;\n\tunsigned int block_size;\n\tbool nollp;\n\tu32 max_burst;\n\tstruct dw_dma_slave dws;\n\tstruct dma_slave_config dma_sconfig;\n};\n\nstruct dw_lli {\n\t__le32 sar;\n\t__le32 dar;\n\t__le32 llp;\n\t__le32 ctllo;\n\t__le32 ctlhi;\n\t__le32 sstat;\n\t__le32 dstat;\n};\n\nstruct dw_desc {\n\tstruct dw_lli lli;\n\tstruct list_head desc_node;\n\tstruct list_head tx_list;\n\tstruct dma_async_tx_descriptor txd;\n\tsize_t len;\n\tsize_t total_len;\n\tu32 residue;\n};\n\nstruct dw_dma_chip_pdata {\n\tconst struct dw_dma_platform_data *pdata;\n\tint (*probe)(struct dw_dma_chip *);\n\tint (*remove)(struct dw_dma_chip *);\n\tstruct dw_dma_chip *chip;\n};\n\nstruct hsu_dma;\n\nstruct hsu_dma_chip {\n\tstruct device *dev;\n\tint irq;\n\tvoid *regs;\n\tunsigned int length;\n\tunsigned int offset;\n\tstruct hsu_dma *hsu;\n};\n\nstruct hsu_dma_chan;\n\nstruct hsu_dma {\n\tstruct dma_device dma;\n\tstruct hsu_dma_chan *chan;\n\tshort unsigned int nr_channels;\n};\n\nstruct hsu_dma_sg {\n\tdma_addr_t addr;\n\tunsigned int len;\n};\n\nstruct hsu_dma_desc {\n\tstruct virt_dma_desc vdesc;\n\tenum dma_transfer_direction direction;\n\tstruct hsu_dma_sg *sg;\n\tunsigned int nents;\n\tsize_t length;\n\tunsigned int active;\n\tenum dma_status status;\n};\n\nstruct hsu_dma_chan {\n\tstruct virt_dma_chan vchan;\n\tvoid *reg;\n\tenum dma_transfer_direction direction;\n\tstruct dma_slave_config config;\n\tstruct hsu_dma_desc *desc;\n};\n\nstruct of_dma {\n\tstruct list_head of_dma_controllers;\n\tstruct device_node *of_node;\n\tstruct dma_chan___2 * (*of_dma_xlate)(struct of_phandle_args *, struct of_dma *);\n\tvoid * (*of_dma_route_allocate)(struct of_phandle_args *, struct of_dma *);\n\tstruct dma_router *dma_router;\n\tvoid *of_dma_data;\n};\n\nenum ldma_chan_on_off {\n\tDMA_CH_OFF = 0,\n\tDMA_CH_ON = 1,\n};\n\nenum {\n\tDMA_TYPE_TX = 0,\n\tDMA_TYPE_RX = 1,\n\tDMA_TYPE_MCPY = 2,\n};\n\nstruct ldma_port;\n\nstruct dw2_desc_sw;\n\nstruct ldma_chan {\n\tstruct virt_dma_chan vchan;\n\tstruct ldma_port *port;\n\tchar name[8];\n\tint nr;\n\tu32 flags;\n\tenum ldma_chan_on_off onoff;\n\tdma_addr_t desc_phys;\n\tvoid *desc_base;\n\tu32 desc_cnt;\n\tint rst;\n\tu32 hdrm_len;\n\tbool hdrm_csum;\n\tu32 boff_len;\n\tu32 data_endian;\n\tu32 desc_endian;\n\tbool pden;\n\tbool desc_rx_np;\n\tbool data_endian_en;\n\tbool desc_endian_en;\n\tbool abc_en;\n\tbool desc_init;\n\tstruct dma_pool___2 *desc_pool;\n\tu32 desc_num;\n\tstruct dw2_desc_sw *ds;\n\tstruct work_struct work;\n\tstruct dma_slave_config config;\n};\n\nstruct ldma_dev;\n\nstruct ldma_port {\n\tstruct ldma_dev *ldev;\n\tu32 portid;\n\tu32 rxbl;\n\tu32 txbl;\n\tu32 rxendi;\n\tu32 txendi;\n\tu32 pkt_drop;\n};\n\nstruct dw2_desc;\n\nstruct dw2_desc_sw {\n\tstruct virt_dma_desc vdesc;\n\tstruct ldma_chan *chan;\n\tdma_addr_t desc_phys;\n\tsize_t desc_cnt;\n\tsize_t size;\n\tstruct dw2_desc *desc_hw;\n};\n\nstruct ldma_inst_data;\n\nstruct ldma_dev {\n\tstruct device *dev;\n\tvoid *base;\n\tstruct reset_control *rst;\n\tstruct clk *core_clk;\n\tstruct dma_device dma_dev;\n\tu32 ver;\n\tint irq;\n\tstruct ldma_port *ports;\n\tstruct ldma_chan *chans;\n\tspinlock_t dev_lock;\n\tu32 chan_nrs;\n\tu32 port_nrs;\n\tu32 channels_mask;\n\tu32 flags;\n\tu32 pollcnt;\n\tconst struct ldma_inst_data *inst;\n\tstruct workqueue_struct *wq;\n};\n\nstruct ldma_inst_data {\n\tbool desc_in_sram;\n\tbool chan_fc;\n\tbool desc_fod;\n\tbool valid_desc_fetch_ack;\n\tu32 orrc;\n\tconst char *name;\n\tu32 type;\n};\n\nstruct dw2_desc {\n\tu32 field;\n\tu32 addr;\n};\n\nstruct virtio_driver {\n\tstruct device_driver driver;\n\tconst struct virtio_device_id *id_table;\n\tconst unsigned int *feature_table;\n\tunsigned int feature_table_size;\n\tconst unsigned int *feature_table_legacy;\n\tunsigned int feature_table_size_legacy;\n\tint (*validate)(struct virtio_device *);\n\tint (*probe)(struct virtio_device *);\n\tvoid (*scan)(struct virtio_device *);\n\tvoid (*remove)(struct virtio_device *);\n\tvoid (*config_changed)(struct virtio_device *);\n\tint (*freeze)(struct virtio_device *);\n\tint (*restore)(struct virtio_device *);\n};\n\ntypedef __u16 __virtio16;\n\ntypedef __u32 __virtio32;\n\ntypedef __u64 __virtio64;\n\nstruct vring_desc {\n\t__virtio64 addr;\n\t__virtio32 len;\n\t__virtio16 flags;\n\t__virtio16 next;\n};\n\nstruct vring_avail {\n\t__virtio16 flags;\n\t__virtio16 idx;\n\t__virtio16 ring[0];\n};\n\nstruct vring_used_elem {\n\t__virtio32 id;\n\t__virtio32 len;\n};\n\ntypedef struct vring_used_elem vring_used_elem_t;\n\nstruct vring_used {\n\t__virtio16 flags;\n\t__virtio16 idx;\n\tvring_used_elem_t ring[0];\n};\n\ntypedef struct vring_desc vring_desc_t;\n\ntypedef struct vring_avail vring_avail_t;\n\ntypedef struct vring_used vring_used_t;\n\nstruct vring {\n\tunsigned int num;\n\tvring_desc_t *desc;\n\tvring_avail_t *avail;\n\tvring_used_t *used;\n};\n\nstruct vring_packed_desc_event {\n\t__le16 off_wrap;\n\t__le16 flags;\n};\n\nstruct vring_packed_desc {\n\t__le64 addr;\n\t__le32 len;\n\t__le16 id;\n\t__le16 flags;\n};\n\nstruct vring_desc_state_split {\n\tvoid *data;\n\tstruct vring_desc *indir_desc;\n};\n\nstruct vring_desc_state_packed {\n\tvoid *data;\n\tstruct vring_packed_desc *indir_desc;\n\tu16 num;\n\tu16 last;\n};\n\nstruct vring_desc_extra {\n\tdma_addr_t addr;\n\tu32 len;\n\tu16 flags;\n\tu16 next;\n};\n\nstruct vring_virtqueue {\n\tstruct virtqueue vq;\n\tbool packed_ring;\n\tbool use_dma_api;\n\tbool weak_barriers;\n\tbool broken;\n\tbool indirect;\n\tbool event;\n\tunsigned int free_head;\n\tunsigned int num_added;\n\tu16 last_used_idx;\n\tbool event_triggered;\n\tunion {\n\t\tstruct {\n\t\t\tstruct vring vring;\n\t\t\tu16 avail_flags_shadow;\n\t\t\tu16 avail_idx_shadow;\n\t\t\tstruct vring_desc_state_split *desc_state;\n\t\t\tstruct vring_desc_extra *desc_extra;\n\t\t\tdma_addr_t queue_dma_addr;\n\t\t\tsize_t queue_size_in_bytes;\n\t\t} split;\n\t\tstruct {\n\t\t\tstruct {\n\t\t\t\tunsigned int num;\n\t\t\t\tstruct vring_packed_desc *desc;\n\t\t\t\tstruct vring_packed_desc_event *driver;\n\t\t\t\tstruct vring_packed_desc_event *device;\n\t\t\t} vring;\n\t\t\tbool avail_wrap_counter;\n\t\t\tbool used_wrap_counter;\n\t\t\tu16 avail_used_flags;\n\t\t\tu16 next_avail_idx;\n\t\t\tu16 event_flags_shadow;\n\t\t\tstruct vring_desc_state_packed *desc_state;\n\t\t\tstruct vring_desc_extra *desc_extra;\n\t\t\tdma_addr_t ring_dma_addr;\n\t\t\tdma_addr_t driver_event_dma_addr;\n\t\t\tdma_addr_t device_event_dma_addr;\n\t\t\tsize_t ring_size_in_bytes;\n\t\t\tsize_t event_size_in_bytes;\n\t\t} packed;\n\t};\n\tbool (*notify)(struct virtqueue *);\n\tbool we_own_ring;\n};\n\nstruct xsd_errors {\n\tint errnum;\n\tconst char *errstring;\n};\n\nstruct xenbus_watch {\n\tstruct list_head list;\n\tconst char *node;\n\tunsigned int nr_pending;\n\tbool (*will_handle)(struct xenbus_watch *, const char *, const char *);\n\tvoid (*callback)(struct xenbus_watch *, const char *, const char *);\n};\n\nstruct xenbus_transaction {\n\tu32 id;\n};\n\nstruct grant_entry_v1 {\n\tuint16_t flags;\n\tdomid_t domid;\n\tuint32_t frame;\n};\n\nstruct grant_entry_header {\n\tuint16_t flags;\n\tdomid_t domid;\n};\n\nunion grant_entry_v2 {\n\tstruct grant_entry_header hdr;\n\tstruct {\n\t\tstruct grant_entry_header hdr;\n\t\tuint32_t pad0;\n\t\tuint64_t frame;\n\t} full_page;\n\tstruct {\n\t\tstruct grant_entry_header hdr;\n\t\tuint16_t page_off;\n\t\tuint16_t length;\n\t\tuint64_t frame;\n\t} sub_page;\n\tstruct {\n\t\tstruct grant_entry_header hdr;\n\t\tdomid_t trans_domid;\n\t\tuint16_t pad0;\n\t\tgrant_ref_t gref;\n\t} transitive;\n\tuint32_t __spacer[4];\n};\n\nstruct gnttab_setup_table {\n\tdomid_t dom;\n\tuint32_t nr_frames;\n\tint16_t status;\n\t__guest_handle_xen_pfn_t frame_list;\n};\n\nstruct gnttab_copy {\n\tstruct {\n\t\tunion {\n\t\t\tgrant_ref_t ref;\n\t\t\txen_pfn_t gmfn;\n\t\t} u;\n\t\tdomid_t domid;\n\t\tuint16_t offset;\n\t} source;\n\tstruct {\n\t\tunion {\n\t\t\tgrant_ref_t ref;\n\t\t\txen_pfn_t gmfn;\n\t\t} u;\n\t\tdomid_t domid;\n\t\tuint16_t offset;\n\t} dest;\n\tuint16_t len;\n\tuint16_t flags;\n\tint16_t status;\n};\n\nstruct gnttab_query_size {\n\tdomid_t dom;\n\tuint32_t nr_frames;\n\tuint32_t max_nr_frames;\n\tint16_t status;\n};\n\nstruct gnttab_set_version {\n\tuint32_t version;\n};\n\nstruct gnttab_get_status_frames {\n\tuint32_t nr_frames;\n\tdomid_t dom;\n\tint16_t status;\n\t__guest_handle_uint64_t frame_list;\n};\n\nstruct gnttab_free_callback {\n\tstruct gnttab_free_callback *next;\n\tvoid (*fn)(void *);\n\tvoid *arg;\n\tu16 count;\n};\n\nstruct gntab_unmap_queue_data;\n\ntypedef void (*gnttab_unmap_refs_done)(int, struct gntab_unmap_queue_data *);\n\nstruct gntab_unmap_queue_data {\n\tstruct delayed_work gnttab_work;\n\tvoid *data;\n\tgnttab_unmap_refs_done done;\n\tstruct gnttab_unmap_grant_ref *unmap_ops;\n\tstruct gnttab_unmap_grant_ref *kunmap_ops;\n\tstruct page **pages;\n\tunsigned int count;\n\tunsigned int age;\n};\n\nstruct gnttab_page_cache {\n\tspinlock_t lock;\n\tstruct page *pages;\n\tunsigned int num_pages;\n};\n\nstruct gnttab_dma_alloc_args {\n\tstruct device *dev;\n\tbool coherent;\n\tint nr_pages;\n\tstruct page **pages;\n\txen_pfn_t *frames;\n\tvoid *vaddr;\n\tdma_addr_t dev_bus_addr;\n};\n\nstruct xen_page_foreign {\n\tdomid_t domid;\n\tgrant_ref_t gref;\n};\n\ntypedef void (*xen_grant_fn_t)(long unsigned int, unsigned int, unsigned int, void *);\n\nstruct gnttab_ops {\n\tunsigned int version;\n\tunsigned int grefs_per_grant_frame;\n\tint (*map_frames)(xen_pfn_t *, unsigned int);\n\tvoid (*unmap_frames)();\n\tvoid (*update_entry)(grant_ref_t, domid_t, long unsigned int, unsigned int);\n\tint (*end_foreign_access_ref)(grant_ref_t, int);\n\tlong unsigned int (*end_foreign_transfer_ref)(grant_ref_t);\n\tint (*query_foreign_access)(grant_ref_t);\n};\n\nstruct unmap_refs_callback_data {\n\tstruct completion completion;\n\tint result;\n};\n\nstruct deferred_entry {\n\tstruct list_head list;\n\tgrant_ref_t ref;\n\tbool ro;\n\tuint16_t warn_delay;\n\tstruct page *page;\n};\n\nstruct xen_feature_info {\n\tunsigned int submap_idx;\n\tuint32_t submap;\n};\n\nstruct balloon_stats {\n\tlong unsigned int current_pages;\n\tlong unsigned int target_pages;\n\tlong unsigned int target_unpopulated;\n\tlong unsigned int balloon_low;\n\tlong unsigned int balloon_high;\n\tlong unsigned int total_pages;\n\tlong unsigned int schedule_delay;\n\tlong unsigned int max_schedule_delay;\n\tlong unsigned int retry_count;\n\tlong unsigned int max_retry_count;\n};\n\nenum bp_state {\n\tBP_DONE = 0,\n\tBP_WAIT = 1,\n\tBP_EAGAIN = 2,\n\tBP_ECANCELED = 3,\n};\n\nenum shutdown_state {\n\tSHUTDOWN_INVALID = 4294967295,\n\tSHUTDOWN_POWEROFF = 0,\n\tSHUTDOWN_SUSPEND = 2,\n\tSHUTDOWN_HALT = 4,\n};\n\nstruct suspend_info {\n\tint cancelled;\n};\n\nstruct shutdown_handler {\n\tconst char command[11];\n\tbool flag;\n\tvoid (*cb)();\n};\n\nstruct vcpu_runstate_info {\n\tint state;\n\tuint64_t state_entry_time;\n\tuint64_t time[4];\n};\n\ntypedef struct vcpu_runstate_info *__guest_handle_vcpu_runstate_info;\n\nstruct vcpu_register_runstate_memory_area {\n\tunion {\n\t\t__guest_handle_vcpu_runstate_info h;\n\t\tstruct vcpu_runstate_info *v;\n\t\tuint64_t p;\n\t} addr;\n};\n\ntypedef uint32_t evtchn_port_t;\n\ntypedef evtchn_port_t *__guest_handle_evtchn_port_t;\n\nstruct evtchn_bind_interdomain {\n\tdomid_t remote_dom;\n\tevtchn_port_t remote_port;\n\tevtchn_port_t local_port;\n};\n\nstruct evtchn_bind_virq {\n\tuint32_t virq;\n\tuint32_t vcpu;\n\tevtchn_port_t port;\n};\n\nstruct evtchn_bind_pirq {\n\tuint32_t pirq;\n\tuint32_t flags;\n\tevtchn_port_t port;\n};\n\nstruct evtchn_bind_ipi {\n\tuint32_t vcpu;\n\tevtchn_port_t port;\n};\n\nstruct evtchn_close {\n\tevtchn_port_t port;\n};\n\nstruct evtchn_send {\n\tevtchn_port_t port;\n};\n\nstruct evtchn_status {\n\tdomid_t dom;\n\tevtchn_port_t port;\n\tuint32_t status;\n\tuint32_t vcpu;\n\tunion {\n\t\tstruct {\n\t\t\tdomid_t dom;\n\t\t} unbound;\n\t\tstruct {\n\t\t\tdomid_t dom;\n\t\t\tevtchn_port_t port;\n\t\t} interdomain;\n\t\tuint32_t pirq;\n\t\tuint32_t virq;\n\t} u;\n};\n\nstruct evtchn_bind_vcpu {\n\tevtchn_port_t port;\n\tuint32_t vcpu;\n};\n\nstruct evtchn_set_priority {\n\tevtchn_port_t port;\n\tuint32_t priority;\n};\n\nstruct sched_poll {\n\t__guest_handle_evtchn_port_t ports;\n\tunsigned int nr_ports;\n\tuint64_t timeout;\n};\n\nstruct physdev_eoi {\n\tuint32_t irq;\n};\n\nstruct physdev_pirq_eoi_gmfn {\n\txen_ulong_t gmfn;\n};\n\nstruct physdev_irq_status_query {\n\tuint32_t irq;\n\tuint32_t flags;\n};\n\nstruct physdev_irq {\n\tuint32_t irq;\n\tuint32_t vector;\n};\n\nstruct physdev_map_pirq {\n\tdomid_t domid;\n\tint type;\n\tint index;\n\tint pirq;\n\tint bus;\n\tint devfn;\n\tint entry_nr;\n\tuint64_t table_base;\n};\n\nstruct physdev_unmap_pirq {\n\tdomid_t domid;\n\tint pirq;\n};\n\nstruct physdev_get_free_pirq {\n\tint type;\n\tuint32_t pirq;\n};\n\nenum xenbus_state {\n\tXenbusStateUnknown = 0,\n\tXenbusStateInitialising = 1,\n\tXenbusStateInitWait = 2,\n\tXenbusStateInitialised = 3,\n\tXenbusStateConnected = 4,\n\tXenbusStateClosing = 5,\n\tXenbusStateClosed = 6,\n\tXenbusStateReconfiguring = 7,\n\tXenbusStateReconfigured = 8,\n};\n\nstruct xenbus_device {\n\tconst char *devicetype;\n\tconst char *nodename;\n\tconst char *otherend;\n\tint otherend_id;\n\tstruct xenbus_watch otherend_watch;\n\tstruct device dev;\n\tenum xenbus_state state;\n\tstruct completion down;\n\tstruct work_struct work;\n\tstruct semaphore reclaim_sem;\n\tatomic_t event_channels;\n\tatomic_t events;\n\tatomic_t spurious_events;\n\tatomic_t jiffies_eoi_delayed;\n\tunsigned int spurious_threshold;\n};\n\nstruct evtchn_loop_ctrl;\n\nstruct evtchn_ops {\n\tunsigned int (*max_channels)();\n\tunsigned int (*nr_channels)();\n\tint (*setup)(evtchn_port_t);\n\tvoid (*remove)(evtchn_port_t, unsigned int);\n\tvoid (*bind_to_cpu)(evtchn_port_t, unsigned int, unsigned int);\n\tvoid (*clear_pending)(evtchn_port_t);\n\tvoid (*set_pending)(evtchn_port_t);\n\tbool (*is_pending)(evtchn_port_t);\n\tvoid (*mask)(evtchn_port_t);\n\tvoid (*unmask)(evtchn_port_t);\n\tvoid (*handle_events)(unsigned int, struct evtchn_loop_ctrl *);\n\tvoid (*resume)();\n\tint (*percpu_init)(unsigned int);\n\tint (*percpu_deinit)(unsigned int);\n};\n\nstruct evtchn_loop_ctrl {\n\tktime_t timeout;\n\tunsigned int count;\n\tbool defer_eoi;\n};\n\nenum xen_irq_type {\n\tIRQT_UNBOUND = 0,\n\tIRQT_PIRQ = 1,\n\tIRQT_VIRQ = 2,\n\tIRQT_IPI = 3,\n\tIRQT_EVTCHN = 4,\n};\n\nstruct irq_info {\n\tstruct list_head list;\n\tstruct list_head eoi_list;\n\tshort int refcnt;\n\tu8 spurious_cnt;\n\tu8 is_accounted;\n\tshort int type;\n\tu8 mask_reason;\n\tu8 is_active;\n\tunsigned int irq;\n\tevtchn_port_t evtchn;\n\tshort unsigned int cpu;\n\tshort unsigned int eoi_cpu;\n\tunsigned int irq_epoch;\n\tu64 eoi_time;\n\traw_spinlock_t lock;\n\tunion {\n\t\tshort unsigned int virq;\n\t\tenum ipi_vector ipi;\n\t\tstruct {\n\t\t\tshort unsigned int pirq;\n\t\t\tshort unsigned int gsi;\n\t\t\tunsigned char vector;\n\t\t\tunsigned char flags;\n\t\t\tuint16_t domid;\n\t\t} pirq;\n\t\tstruct xenbus_device *interdomain;\n\t} u;\n};\n\nstruct lateeoi_work {\n\tstruct delayed_work delayed;\n\tspinlock_t eoi_list_lock;\n\tstruct list_head eoi_list;\n};\n\nstruct evtchn_unmask {\n\tevtchn_port_t port;\n};\n\nstruct evtchn_init_control {\n\tuint64_t control_gfn;\n\tuint32_t offset;\n\tuint32_t vcpu;\n\tuint8_t link_bits;\n\tuint8_t _pad[7];\n};\n\nstruct evtchn_expand_array {\n\tuint64_t array_gfn;\n};\n\ntypedef uint32_t event_word_t;\n\nstruct evtchn_fifo_control_block {\n\tuint32_t ready;\n\tuint32_t _rsvd;\n\tevent_word_t head[16];\n};\n\nstruct evtchn_fifo_queue {\n\tuint32_t head[16];\n};\n\nstruct evtchn_alloc_unbound {\n\tdomid_t dom;\n\tdomid_t remote_dom;\n\tevtchn_port_t port;\n};\n\nstruct xenbus_map_node {\n\tstruct list_head next;\n\tunion {\n\t\tstruct {\n\t\t\tstruct vm_struct *area;\n\t\t} pv;\n\t\tstruct {\n\t\t\tstruct page *pages[16];\n\t\t\tlong unsigned int addrs[16];\n\t\t\tvoid *addr;\n\t\t} hvm;\n\t};\n\tgrant_handle_t handles[16];\n\tunsigned int nr_handles;\n};\n\nstruct map_ring_valloc {\n\tstruct xenbus_map_node *node;\n\tlong unsigned int addrs[16];\n\tphys_addr_t phys_addrs[16];\n\tstruct gnttab_map_grant_ref map[16];\n\tstruct gnttab_unmap_grant_ref unmap[16];\n\tunsigned int idx;\n};\n\nstruct xenbus_ring_ops {\n\tint (*map)(struct xenbus_device *, struct map_ring_valloc *, grant_ref_t *, unsigned int, void **);\n\tint (*unmap)(struct xenbus_device *, void *);\n};\n\nstruct unmap_ring_hvm {\n\tunsigned int idx;\n\tlong unsigned int addrs[16];\n};\n\nenum xsd_sockmsg_type {\n\tXS_DEBUG = 0,\n\tXS_DIRECTORY = 1,\n\tXS_READ = 2,\n\tXS_GET_PERMS = 3,\n\tXS_WATCH = 4,\n\tXS_UNWATCH = 5,\n\tXS_TRANSACTION_START = 6,\n\tXS_TRANSACTION_END = 7,\n\tXS_INTRODUCE = 8,\n\tXS_RELEASE = 9,\n\tXS_GET_DOMAIN_PATH = 10,\n\tXS_WRITE = 11,\n\tXS_MKDIR = 12,\n\tXS_RM = 13,\n\tXS_SET_PERMS = 14,\n\tXS_WATCH_EVENT = 15,\n\tXS_ERROR = 16,\n\tXS_IS_DOMAIN_INTRODUCED = 17,\n\tXS_RESUME = 18,\n\tXS_SET_TARGET = 19,\n\tXS_RESTRICT = 20,\n\tXS_RESET_WATCHES = 21,\n};\n\nstruct xsd_sockmsg {\n\tuint32_t type;\n\tuint32_t req_id;\n\tuint32_t tx_id;\n\tuint32_t len;\n};\n\ntypedef uint32_t XENSTORE_RING_IDX;\n\nstruct xenstore_domain_interface {\n\tchar req[1024];\n\tchar rsp[1024];\n\tXENSTORE_RING_IDX req_cons;\n\tXENSTORE_RING_IDX req_prod;\n\tXENSTORE_RING_IDX rsp_cons;\n\tXENSTORE_RING_IDX rsp_prod;\n};\n\nstruct xs_watch_event {\n\tstruct list_head list;\n\tunsigned int len;\n\tstruct xenbus_watch *handle;\n\tconst char *path;\n\tconst char *token;\n\tchar body[0];\n};\n\nenum xb_req_state {\n\txb_req_state_queued = 0,\n\txb_req_state_wait_reply = 1,\n\txb_req_state_got_reply = 2,\n\txb_req_state_aborted = 3,\n};\n\nstruct xb_req_data {\n\tstruct list_head list;\n\twait_queue_head_t wq;\n\tstruct xsd_sockmsg msg;\n\tuint32_t caller_req_id;\n\tenum xsd_sockmsg_type type;\n\tchar *body;\n\tconst struct kvec *vec;\n\tint num_vecs;\n\tint err;\n\tenum xb_req_state state;\n\tbool user_req;\n\tvoid (*cb)(struct xb_req_data *);\n\tvoid *par;\n};\n\nenum xenstore_init {\n\tXS_UNKNOWN = 0,\n\tXS_PV = 1,\n\tXS_HVM = 2,\n\tXS_LOCAL = 3,\n};\n\nstruct xenbus_device_id {\n\tchar devicetype[32];\n};\n\nstruct xenbus_driver {\n\tconst char *name;\n\tconst struct xenbus_device_id *ids;\n\tbool allow_rebind;\n\tint (*probe)(struct xenbus_device *, const struct xenbus_device_id *);\n\tvoid (*otherend_changed)(struct xenbus_device *, enum xenbus_state);\n\tint (*remove)(struct xenbus_device *);\n\tint (*suspend)(struct xenbus_device *);\n\tint (*resume)(struct xenbus_device *);\n\tint (*uevent)(struct xenbus_device *, struct kobj_uevent_env *);\n\tstruct device_driver driver;\n\tint (*read_otherend_details)(struct xenbus_device *);\n\tint (*is_ready)(struct xenbus_device *);\n\tvoid (*reclaim_memory)(struct xenbus_device *);\n};\n\nstruct xen_hvm_param {\n\tdomid_t domid;\n\tuint32_t index;\n\tuint64_t value;\n};\n\nstruct xen_bus_type {\n\tchar *root;\n\tunsigned int levels;\n\tint (*get_bus_id)(char *, const char *);\n\tint (*probe)(struct xen_bus_type *, const char *, const char *);\n\tbool (*otherend_will_handle)(struct xenbus_watch *, const char *, const char *);\n\tvoid (*otherend_changed)(struct xenbus_watch *, const char *, const char *);\n\tstruct bus_type bus;\n};\n\nstruct xb_find_info {\n\tstruct xenbus_device *dev;\n\tconst char *nodename;\n};\n\nstruct xenbus_transaction_holder {\n\tstruct list_head list;\n\tstruct xenbus_transaction handle;\n\tunsigned int generation_id;\n};\n\nstruct read_buffer {\n\tstruct list_head list;\n\tunsigned int cons;\n\tunsigned int len;\n\tchar msg[0];\n};\n\nstruct xenbus_file_priv {\n\tstruct mutex msgbuffer_mutex;\n\tstruct list_head transactions;\n\tstruct list_head watches;\n\tunsigned int len;\n\tunion {\n\t\tstruct xsd_sockmsg msg;\n\t\tchar buffer[4096];\n\t} u;\n\tstruct mutex reply_mutex;\n\tstruct list_head read_buffers;\n\twait_queue_head_t read_waitq;\n\tstruct kref kref;\n\tstruct work_struct wq;\n};\n\nstruct watch_adapter {\n\tstruct list_head list;\n\tstruct xenbus_watch watch;\n\tstruct xenbus_file_priv *dev_data;\n\tchar *token;\n};\n\nstruct physdev_manage_pci {\n\tuint8_t bus;\n\tuint8_t devfn;\n};\n\nstruct physdev_manage_pci_ext {\n\tuint8_t bus;\n\tuint8_t devfn;\n\tunsigned int is_extfn;\n\tunsigned int is_virtfn;\n\tstruct {\n\t\tuint8_t bus;\n\t\tuint8_t devfn;\n\t} physfn;\n};\n\nstruct physdev_pci_mmcfg_reserved {\n\tuint64_t address;\n\tuint16_t segment;\n\tuint8_t start_bus;\n\tuint8_t end_bus;\n\tuint32_t flags;\n};\n\nstruct physdev_pci_device_add {\n\tuint16_t seg;\n\tuint8_t bus;\n\tuint8_t devfn;\n\tuint32_t flags;\n\tstruct {\n\t\tuint8_t bus;\n\t\tuint8_t devfn;\n\t} physfn;\n\tuint32_t optarr[0];\n};\n\nstruct physdev_pci_device {\n\tuint16_t seg;\n\tuint8_t bus;\n\tuint8_t devfn;\n};\n\nstruct usb_device_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__le16 bcdUSB;\n\t__u8 bDeviceClass;\n\t__u8 bDeviceSubClass;\n\t__u8 bDeviceProtocol;\n\t__u8 bMaxPacketSize0;\n\t__le16 idVendor;\n\t__le16 idProduct;\n\t__le16 bcdDevice;\n\t__u8 iManufacturer;\n\t__u8 iProduct;\n\t__u8 iSerialNumber;\n\t__u8 bNumConfigurations;\n};\n\nstruct usb_config_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__le16 wTotalLength;\n\t__u8 bNumInterfaces;\n\t__u8 bConfigurationValue;\n\t__u8 iConfiguration;\n\t__u8 bmAttributes;\n\t__u8 bMaxPower;\n} __attribute__((packed));\n\nstruct usb_interface_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bInterfaceNumber;\n\t__u8 bAlternateSetting;\n\t__u8 bNumEndpoints;\n\t__u8 bInterfaceClass;\n\t__u8 bInterfaceSubClass;\n\t__u8 bInterfaceProtocol;\n\t__u8 iInterface;\n};\n\nstruct usb_endpoint_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bEndpointAddress;\n\t__u8 bmAttributes;\n\t__le16 wMaxPacketSize;\n\t__u8 bInterval;\n\t__u8 bRefresh;\n\t__u8 bSynchAddress;\n} __attribute__((packed));\n\nstruct usb_ssp_isoc_ep_comp_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__le16 wReseved;\n\t__le32 dwBytesPerInterval;\n};\n\nstruct usb_ss_ep_comp_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bMaxBurst;\n\t__u8 bmAttributes;\n\t__le16 wBytesPerInterval;\n};\n\nstruct usb_interface_assoc_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bFirstInterface;\n\t__u8 bInterfaceCount;\n\t__u8 bFunctionClass;\n\t__u8 bFunctionSubClass;\n\t__u8 bFunctionProtocol;\n\t__u8 iFunction;\n};\n\nstruct usb_bos_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__le16 wTotalLength;\n\t__u8 bNumDeviceCaps;\n} __attribute__((packed));\n\nstruct usb_ext_cap_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDevCapabilityType;\n\t__le32 bmAttributes;\n} __attribute__((packed));\n\nstruct usb_ss_cap_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDevCapabilityType;\n\t__u8 bmAttributes;\n\t__le16 wSpeedSupported;\n\t__u8 bFunctionalitySupport;\n\t__u8 bU1devExitLat;\n\t__le16 bU2DevExitLat;\n};\n\nstruct usb_ss_container_id_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDevCapabilityType;\n\t__u8 bReserved;\n\t__u8 ContainerID[16];\n};\n\nstruct usb_ssp_cap_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDevCapabilityType;\n\t__u8 bReserved;\n\t__le32 bmAttributes;\n\t__le16 wFunctionalitySupport;\n\t__le16 wReserved;\n\t__le32 bmSublinkSpeedAttr[1];\n};\n\nstruct usb_ptm_cap_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDevCapabilityType;\n};\n\nenum usb_device_speed {\n\tUSB_SPEED_UNKNOWN = 0,\n\tUSB_SPEED_LOW = 1,\n\tUSB_SPEED_FULL = 2,\n\tUSB_SPEED_HIGH = 3,\n\tUSB_SPEED_WIRELESS = 4,\n\tUSB_SPEED_SUPER = 5,\n\tUSB_SPEED_SUPER_PLUS = 6,\n};\n\nenum usb_device_state {\n\tUSB_STATE_NOTATTACHED = 0,\n\tUSB_STATE_ATTACHED = 1,\n\tUSB_STATE_POWERED = 2,\n\tUSB_STATE_RECONNECTING = 3,\n\tUSB_STATE_UNAUTHENTICATED = 4,\n\tUSB_STATE_DEFAULT = 5,\n\tUSB_STATE_ADDRESS = 6,\n\tUSB_STATE_CONFIGURED = 7,\n\tUSB_STATE_SUSPENDED = 8,\n};\n\nenum usb3_link_state {\n\tUSB3_LPM_U0 = 0,\n\tUSB3_LPM_U1 = 1,\n\tUSB3_LPM_U2 = 2,\n\tUSB3_LPM_U3 = 3,\n};\n\nenum usb_ssp_rate {\n\tUSB_SSP_GEN_UNKNOWN = 0,\n\tUSB_SSP_GEN_2x1 = 1,\n\tUSB_SSP_GEN_1x2 = 2,\n\tUSB_SSP_GEN_2x2 = 3,\n};\n\nstruct ep_device;\n\nstruct usb_host_endpoint {\n\tstruct usb_endpoint_descriptor desc;\n\tstruct usb_ss_ep_comp_descriptor ss_ep_comp;\n\tstruct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp;\n\tchar: 8;\n\tstruct list_head urb_list;\n\tvoid *hcpriv;\n\tstruct ep_device *ep_dev;\n\tunsigned char *extra;\n\tint extralen;\n\tint enabled;\n\tint streams;\n\tint: 32;\n} __attribute__((packed));\n\nstruct usb_host_interface {\n\tstruct usb_interface_descriptor desc;\n\tint extralen;\n\tunsigned char *extra;\n\tstruct usb_host_endpoint *endpoint;\n\tchar *string;\n};\n\nenum usb_interface_condition {\n\tUSB_INTERFACE_UNBOUND = 0,\n\tUSB_INTERFACE_BINDING = 1,\n\tUSB_INTERFACE_BOUND = 2,\n\tUSB_INTERFACE_UNBINDING = 3,\n};\n\nstruct usb_interface {\n\tstruct usb_host_interface *altsetting;\n\tstruct usb_host_interface *cur_altsetting;\n\tunsigned int num_altsetting;\n\tstruct usb_interface_assoc_descriptor *intf_assoc;\n\tint minor;\n\tenum usb_interface_condition condition;\n\tunsigned int sysfs_files_created: 1;\n\tunsigned int ep_devs_created: 1;\n\tunsigned int unregistering: 1;\n\tunsigned int needs_remote_wakeup: 1;\n\tunsigned int needs_altsetting0: 1;\n\tunsigned int needs_binding: 1;\n\tunsigned int resetting_device: 1;\n\tunsigned int authorized: 1;\n\tstruct device dev;\n\tstruct device *usb_dev;\n\tstruct work_struct reset_ws;\n};\n\nstruct usb_interface_cache {\n\tunsigned int num_altsetting;\n\tstruct kref ref;\n\tstruct usb_host_interface altsetting[0];\n};\n\nstruct usb_host_config {\n\tstruct usb_config_descriptor desc;\n\tchar *string;\n\tstruct usb_interface_assoc_descriptor *intf_assoc[16];\n\tstruct usb_interface *interface[32];\n\tstruct usb_interface_cache *intf_cache[32];\n\tunsigned char *extra;\n\tint extralen;\n};\n\nstruct usb_host_bos {\n\tstruct usb_bos_descriptor *desc;\n\tstruct usb_ext_cap_descriptor *ext_cap;\n\tstruct usb_ss_cap_descriptor *ss_cap;\n\tstruct usb_ssp_cap_descriptor *ssp_cap;\n\tstruct usb_ss_container_id_descriptor *ss_id;\n\tstruct usb_ptm_cap_descriptor *ptm_cap;\n};\n\nstruct usb_devmap {\n\tlong unsigned int devicemap[2];\n};\n\nstruct mon_bus;\n\nstruct usb_device;\n\nstruct usb_bus {\n\tstruct device *controller;\n\tstruct device *sysdev;\n\tint busnum;\n\tconst char *bus_name;\n\tu8 uses_pio_for_control;\n\tu8 otg_port;\n\tunsigned int is_b_host: 1;\n\tunsigned int b_hnp_enable: 1;\n\tunsigned int no_stop_on_short: 1;\n\tunsigned int no_sg_constraint: 1;\n\tunsigned int sg_tablesize;\n\tint devnum_next;\n\tstruct mutex devnum_next_mutex;\n\tstruct usb_devmap devmap;\n\tstruct usb_device *root_hub;\n\tstruct usb_bus *hs_companion;\n\tint bandwidth_allocated;\n\tint bandwidth_int_reqs;\n\tint bandwidth_isoc_reqs;\n\tunsigned int resuming_ports;\n\tstruct mon_bus *mon_bus;\n\tint monitored;\n};\n\nstruct wusb_dev;\n\nstruct usb2_lpm_parameters {\n\tunsigned int besl;\n\tint timeout;\n};\n\nstruct usb3_lpm_parameters {\n\tunsigned int mel;\n\tunsigned int pel;\n\tunsigned int sel;\n\tint timeout;\n};\n\nstruct usb_tt;\n\nstruct usb_device {\n\tint devnum;\n\tchar devpath[16];\n\tu32 route;\n\tenum usb_device_state state;\n\tenum usb_device_speed speed;\n\tunsigned int rx_lanes;\n\tunsigned int tx_lanes;\n\tenum usb_ssp_rate ssp_rate;\n\tstruct usb_tt *tt;\n\tint ttport;\n\tunsigned int toggle[2];\n\tstruct usb_device *parent;\n\tstruct usb_bus *bus;\n\tstruct usb_host_endpoint ep0;\n\tstruct device dev;\n\tstruct usb_device_descriptor descriptor;\n\tstruct usb_host_bos *bos;\n\tstruct usb_host_config *config;\n\tstruct usb_host_config *actconfig;\n\tstruct usb_host_endpoint *ep_in[16];\n\tstruct usb_host_endpoint *ep_out[16];\n\tchar **rawdescriptors;\n\tshort unsigned int bus_mA;\n\tu8 portnum;\n\tu8 level;\n\tu8 devaddr;\n\tunsigned int can_submit: 1;\n\tunsigned int persist_enabled: 1;\n\tunsigned int have_langid: 1;\n\tunsigned int authorized: 1;\n\tunsigned int authenticated: 1;\n\tunsigned int wusb: 1;\n\tunsigned int lpm_capable: 1;\n\tunsigned int usb2_hw_lpm_capable: 1;\n\tunsigned int usb2_hw_lpm_besl_capable: 1;\n\tunsigned int usb2_hw_lpm_enabled: 1;\n\tunsigned int usb2_hw_lpm_allowed: 1;\n\tunsigned int usb3_lpm_u1_enabled: 1;\n\tunsigned int usb3_lpm_u2_enabled: 1;\n\tint string_langid;\n\tchar *product;\n\tchar *manufacturer;\n\tchar *serial;\n\tstruct list_head filelist;\n\tint maxchild;\n\tu32 quirks;\n\tatomic_t urbnum;\n\tlong unsigned int active_duration;\n\tlong unsigned int connect_time;\n\tunsigned int do_remote_wakeup: 1;\n\tunsigned int reset_resume: 1;\n\tunsigned int port_is_suspended: 1;\n\tstruct wusb_dev *wusb_dev;\n\tint slot_id;\n\tstruct usb2_lpm_parameters l1_params;\n\tstruct usb3_lpm_parameters u1_params;\n\tstruct usb3_lpm_parameters u2_params;\n\tunsigned int lpm_disable_count;\n\tu16 hub_delay;\n\tunsigned int use_generic_driver: 1;\n};\n\nstruct usb_tt {\n\tstruct usb_device *hub;\n\tint multi;\n\tunsigned int think_time;\n\tvoid *hcpriv;\n\tspinlock_t lock;\n\tstruct list_head clear_list;\n\tstruct work_struct clear_work;\n};\n\nstruct usb_iso_packet_descriptor {\n\tunsigned int offset;\n\tunsigned int length;\n\tunsigned int actual_length;\n\tint status;\n};\n\nstruct usb_anchor {\n\tstruct list_head urb_list;\n\twait_queue_head_t wait;\n\tspinlock_t lock;\n\tatomic_t suspend_wakeups;\n\tunsigned int poisoned: 1;\n};\n\nstruct urb;\n\ntypedef void (*usb_complete_t)(struct urb *);\n\nstruct urb {\n\tstruct kref kref;\n\tint unlinked;\n\tvoid *hcpriv;\n\tatomic_t use_count;\n\tatomic_t reject;\n\tstruct list_head urb_list;\n\tstruct list_head anchor_list;\n\tstruct usb_anchor *anchor;\n\tstruct usb_device *dev;\n\tstruct usb_host_endpoint *ep;\n\tunsigned int pipe;\n\tunsigned int stream_id;\n\tint status;\n\tunsigned int transfer_flags;\n\tvoid *transfer_buffer;\n\tdma_addr_t transfer_dma;\n\tstruct scatterlist *sg;\n\tint num_mapped_sgs;\n\tint num_sgs;\n\tu32 transfer_buffer_length;\n\tu32 actual_length;\n\tunsigned char *setup_packet;\n\tdma_addr_t setup_dma;\n\tint start_frame;\n\tint number_of_packets;\n\tint interval;\n\tint error_count;\n\tvoid *context;\n\tusb_complete_t complete;\n\tstruct usb_iso_packet_descriptor iso_frame_desc[0];\n};\n\nstruct giveback_urb_bh {\n\tbool running;\n\tspinlock_t lock;\n\tstruct list_head head;\n\tstruct tasklet_struct bh;\n\tstruct usb_host_endpoint *completing_ep;\n};\n\nenum usb_dev_authorize_policy {\n\tUSB_DEVICE_AUTHORIZE_NONE = 0,\n\tUSB_DEVICE_AUTHORIZE_ALL = 1,\n\tUSB_DEVICE_AUTHORIZE_INTERNAL = 2,\n};\n\nstruct usb_phy_roothub;\n\nstruct hc_driver;\n\nstruct usb_phy;\n\nstruct usb_hcd {\n\tstruct usb_bus self;\n\tstruct kref kref;\n\tconst char *product_desc;\n\tint speed;\n\tchar irq_descr[24];\n\tstruct timer_list rh_timer;\n\tstruct urb *status_urb;\n\tstruct work_struct wakeup_work;\n\tstruct work_struct died_work;\n\tconst struct hc_driver *driver;\n\tstruct usb_phy *usb_phy;\n\tstruct usb_phy_roothub *phy_roothub;\n\tlong unsigned int flags;\n\tenum usb_dev_authorize_policy dev_policy;\n\tunsigned int rh_registered: 1;\n\tunsigned int rh_pollable: 1;\n\tunsigned int msix_enabled: 1;\n\tunsigned int msi_enabled: 1;\n\tunsigned int skip_phy_initialization: 1;\n\tunsigned int uses_new_polling: 1;\n\tunsigned int wireless: 1;\n\tunsigned int has_tt: 1;\n\tunsigned int amd_resume_bug: 1;\n\tunsigned int can_do_streams: 1;\n\tunsigned int tpl_support: 1;\n\tunsigned int cant_recv_wakeups: 1;\n\tunsigned int irq;\n\tvoid *regs;\n\tresource_size_t rsrc_start;\n\tresource_size_t rsrc_len;\n\tunsigned int power_budget;\n\tstruct giveback_urb_bh high_prio_bh;\n\tstruct giveback_urb_bh low_prio_bh;\n\tstruct mutex *address0_mutex;\n\tstruct mutex *bandwidth_mutex;\n\tstruct usb_hcd *shared_hcd;\n\tstruct usb_hcd *primary_hcd;\n\tstruct dma_pool___2 *pool[4];\n\tint state;\n\tstruct gen_pool *localmem_pool;\n\tlong unsigned int hcd_priv[0];\n};\n\nstruct hc_driver {\n\tconst char *description;\n\tconst char *product_desc;\n\tsize_t hcd_priv_size;\n\tirqreturn_t (*irq)(struct usb_hcd *);\n\tint flags;\n\tint (*reset)(struct usb_hcd *);\n\tint (*start)(struct usb_hcd *);\n\tint (*pci_suspend)(struct usb_hcd *, bool);\n\tint (*pci_resume)(struct usb_hcd *, bool);\n\tvoid (*stop)(struct usb_hcd *);\n\tvoid (*shutdown)(struct usb_hcd *);\n\tint (*get_frame_number)(struct usb_hcd *);\n\tint (*urb_enqueue)(struct usb_hcd *, struct urb *, gfp_t);\n\tint (*urb_dequeue)(struct usb_hcd *, struct urb *, int);\n\tint (*map_urb_for_dma)(struct usb_hcd *, struct urb *, gfp_t);\n\tvoid (*unmap_urb_for_dma)(struct usb_hcd *, struct urb *);\n\tvoid (*endpoint_disable)(struct usb_hcd *, struct usb_host_endpoint *);\n\tvoid (*endpoint_reset)(struct usb_hcd *, struct usb_host_endpoint *);\n\tint (*hub_status_data)(struct usb_hcd *, char *);\n\tint (*hub_control)(struct usb_hcd *, u16, u16, u16, char *, u16);\n\tint (*bus_suspend)(struct usb_hcd *);\n\tint (*bus_resume)(struct usb_hcd *);\n\tint (*start_port_reset)(struct usb_hcd *, unsigned int);\n\tlong unsigned int (*get_resuming_ports)(struct usb_hcd *);\n\tvoid (*relinquish_port)(struct usb_hcd *, int);\n\tint (*port_handed_over)(struct usb_hcd *, int);\n\tvoid (*clear_tt_buffer_complete)(struct usb_hcd *, struct usb_host_endpoint *);\n\tint (*alloc_dev)(struct usb_hcd *, struct usb_device *);\n\tvoid (*free_dev)(struct usb_hcd *, struct usb_device *);\n\tint (*alloc_streams)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint **, unsigned int, unsigned int, gfp_t);\n\tint (*free_streams)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint **, unsigned int, gfp_t);\n\tint (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);\n\tint (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);\n\tint (*check_bandwidth)(struct usb_hcd *, struct usb_device *);\n\tvoid (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);\n\tint (*address_device)(struct usb_hcd *, struct usb_device *);\n\tint (*enable_device)(struct usb_hcd *, struct usb_device *);\n\tint (*update_hub_device)(struct usb_hcd *, struct usb_device *, struct usb_tt *, gfp_t);\n\tint (*reset_device)(struct usb_hcd *, struct usb_device *);\n\tint (*update_device)(struct usb_hcd *, struct usb_device *);\n\tint (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);\n\tint (*enable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state);\n\tint (*disable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state);\n\tint (*find_raw_port_number)(struct usb_hcd *, int);\n\tint (*port_power)(struct usb_hcd *, int, bool);\n\tint (*submit_single_step_set_feature)(struct usb_hcd *, struct urb *, int);\n};\n\nstruct physdev_dbgp_op {\n\tuint8_t op;\n\tuint8_t bus;\n\tunion {\n\t\tstruct physdev_pci_device pci;\n\t} u;\n};\n\nstruct pcpu {\n\tstruct list_head list;\n\tstruct device dev;\n\tuint32_t cpu_id;\n\tuint32_t flags;\n};\n\ntypedef uint8_t xen_domain_handle_t[16];\n\nstruct xen_compile_info {\n\tchar compiler[64];\n\tchar compile_by[16];\n\tchar compile_domain[32];\n\tchar compile_date[32];\n};\n\nstruct xen_platform_parameters {\n\txen_ulong_t virt_start;\n};\n\nstruct xen_build_id {\n\tuint32_t len;\n\tunsigned char buf[0];\n};\n\nstruct hyp_sysfs_attr {\n\tstruct attribute attr;\n\tssize_t (*show)(struct hyp_sysfs_attr *, char *);\n\tssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t);\n\tvoid *hyp_attr_data;\n};\n\nstruct pmu_mode {\n\tconst char *name;\n\tuint32_t mode;\n};\n\nenum xen_swiotlb_err {\n\tXEN_SWIOTLB_UNKNOWN = 0,\n\tXEN_SWIOTLB_ENOMEM = 1,\n\tXEN_SWIOTLB_EFIXUP = 2,\n};\n\nstruct mcinfo_common {\n\tuint16_t type;\n\tuint16_t size;\n};\n\nstruct mcinfo_global {\n\tstruct mcinfo_common common;\n\tuint16_t mc_domid;\n\tuint16_t mc_vcpuid;\n\tuint32_t mc_socketid;\n\tuint16_t mc_coreid;\n\tuint16_t mc_core_threadid;\n\tuint32_t mc_apicid;\n\tuint32_t mc_flags;\n\tuint64_t mc_gstatus;\n};\n\nstruct mcinfo_bank {\n\tstruct mcinfo_common common;\n\tuint16_t mc_bank;\n\tuint16_t mc_domid;\n\tuint64_t mc_status;\n\tuint64_t mc_addr;\n\tuint64_t mc_misc;\n\tuint64_t mc_ctrl2;\n\tuint64_t mc_tsc;\n};\n\nstruct mcinfo_msr {\n\tuint64_t reg;\n\tuint64_t value;\n};\n\nstruct mc_info {\n\tuint32_t mi_nentries;\n\tuint32_t flags;\n\tuint64_t mi_data[95];\n};\n\ntypedef struct mc_info *__guest_handle_mc_info;\n\nstruct mcinfo_logical_cpu {\n\tuint32_t mc_cpunr;\n\tuint32_t mc_chipid;\n\tuint16_t mc_coreid;\n\tuint16_t mc_threadid;\n\tuint32_t mc_apicid;\n\tuint32_t mc_clusterid;\n\tuint32_t mc_ncores;\n\tuint32_t mc_ncores_active;\n\tuint32_t mc_nthreads;\n\tuint32_t mc_cpuid_level;\n\tuint32_t mc_family;\n\tuint32_t mc_vendor;\n\tuint32_t mc_model;\n\tuint32_t mc_step;\n\tchar mc_vendorid[16];\n\tchar mc_brandid[64];\n\tuint32_t mc_cpu_caps[7];\n\tuint32_t mc_cache_size;\n\tuint32_t mc_cache_alignment;\n\tuint32_t mc_nmsrvals;\n\tstruct mcinfo_msr mc_msrvalues[8];\n};\n\ntypedef struct mcinfo_logical_cpu *__guest_handle_mcinfo_logical_cpu;\n\nstruct xen_mc_fetch {\n\tuint32_t flags;\n\tuint32_t _pad0;\n\tuint64_t fetch_id;\n\t__guest_handle_mc_info data;\n};\n\nstruct xen_mc_notifydomain {\n\tuint16_t mc_domid;\n\tuint16_t mc_vcpuid;\n\tuint32_t flags;\n};\n\nstruct xen_mc_physcpuinfo {\n\tuint32_t ncpus;\n\tuint32_t _pad0;\n\t__guest_handle_mcinfo_logical_cpu info;\n};\n\nstruct xen_mc_msrinject {\n\tuint32_t mcinj_cpunr;\n\tuint32_t mcinj_flags;\n\tuint32_t mcinj_count;\n\tuint32_t _pad0;\n\tstruct mcinfo_msr mcinj_msr[8];\n};\n\nstruct xen_mc_mceinject {\n\tunsigned int mceinj_cpunr;\n};\n\nstruct xen_mc {\n\tuint32_t cmd;\n\tuint32_t interface_version;\n\tunion {\n\t\tstruct xen_mc_fetch mc_fetch;\n\t\tstruct xen_mc_notifydomain mc_notifydomain;\n\t\tstruct xen_mc_physcpuinfo mc_physcpuinfo;\n\t\tstruct xen_mc_msrinject mc_msrinject;\n\t\tstruct xen_mc_mceinject mc_mceinject;\n\t} u;\n};\n\nstruct xen_mce {\n\t__u64 status;\n\t__u64 misc;\n\t__u64 addr;\n\t__u64 mcgstatus;\n\t__u64 ip;\n\t__u64 tsc;\n\t__u64 time;\n\t__u8 cpuvendor;\n\t__u8 inject_flags;\n\t__u16 pad;\n\t__u32 cpuid;\n\t__u8 cs;\n\t__u8 bank;\n\t__u8 cpu;\n\t__u8 finished;\n\t__u32 extcpu;\n\t__u32 socketid;\n\t__u32 apicid;\n\t__u64 mcgcap;\n\t__u64 synd;\n\t__u64 ipid;\n\t__u64 ppin;\n};\n\nstruct xen_mce_log {\n\tchar signature[12];\n\tunsigned int len;\n\tunsigned int next;\n\tunsigned int flags;\n\tunsigned int recordlen;\n\tstruct xen_mce entry[32];\n};\n\ntypedef int *__guest_handle_int;\n\ntypedef xen_ulong_t *__guest_handle_xen_ulong_t;\n\nstruct xen_add_to_physmap_range {\n\tdomid_t domid;\n\tuint16_t space;\n\tuint16_t size;\n\tdomid_t foreign_domid;\n\t__guest_handle_xen_ulong_t idxs;\n\t__guest_handle_xen_pfn_t gpfns;\n\t__guest_handle_int errs;\n};\n\nstruct xen_remove_from_physmap {\n\tdomid_t domid;\n\txen_pfn_t gpfn;\n};\n\ntypedef void (*xen_gfn_fn_t)(long unsigned int, void *);\n\nstruct xen_remap_gfn_info;\n\nstruct remap_data___2 {\n\txen_pfn_t *fgfn;\n\tint nr_fgfn;\n\tpgprot_t prot;\n\tdomid_t domid;\n\tstruct vm_area_struct *vma;\n\tint index;\n\tstruct page **pages;\n\tstruct xen_remap_gfn_info *info;\n\tint *err_ptr;\n\tint mapped;\n\tint h_errs[1];\n\txen_ulong_t h_idxs[1];\n\txen_pfn_t h_gpfns[1];\n\tint h_iter;\n};\n\nstruct map_balloon_pages {\n\txen_pfn_t *pfns;\n\tunsigned int idx;\n};\n\nstruct remap_pfn {\n\tstruct mm_struct *mm;\n\tstruct page **pages;\n\tpgprot_t prot;\n\tlong unsigned int i;\n};\n\nstruct fastopen_queue {\n\tstruct request_sock *rskq_rst_head;\n\tstruct request_sock *rskq_rst_tail;\n\tspinlock_t lock;\n\tint qlen;\n\tint max_qlen;\n\tstruct tcp_fastopen_context *ctx;\n};\n\nstruct request_sock_queue {\n\tspinlock_t rskq_lock;\n\tu8 rskq_defer_accept;\n\tu32 synflood_warned;\n\tatomic_t qlen;\n\tatomic_t young;\n\tstruct request_sock *rskq_accept_head;\n\tstruct request_sock *rskq_accept_tail;\n\tstruct fastopen_queue fastopenq;\n};\n\nstruct inet_connection_sock_af_ops {\n\tint (*queue_xmit)(struct sock *, struct sk_buff *, struct flowi *);\n\tvoid (*send_check)(struct sock *, struct sk_buff *);\n\tint (*rebuild_header)(struct sock *);\n\tvoid (*sk_rx_dst_set)(struct sock *, const struct sk_buff *);\n\tint (*conn_request)(struct sock *, struct sk_buff *);\n\tstruct sock * (*syn_recv_sock)(const struct sock *, struct sk_buff *, struct request_sock *, struct dst_entry *, struct request_sock *, bool *);\n\tu16 net_header_len;\n\tu16 net_frag_header_len;\n\tu16 sockaddr_len;\n\tint (*setsockopt)(struct sock *, int, int, sockptr_t, unsigned int);\n\tint (*getsockopt)(struct sock *, int, int, char *, int *);\n\tvoid (*addr2sockaddr)(struct sock *, struct sockaddr *);\n\tvoid (*mtu_reduced)(struct sock *);\n};\n\nstruct inet_bind_bucket;\n\nstruct tcp_ulp_ops;\n\nstruct inet_connection_sock {\n\tstruct inet_sock icsk_inet;\n\tstruct request_sock_queue icsk_accept_queue;\n\tstruct inet_bind_bucket *icsk_bind_hash;\n\tlong unsigned int icsk_timeout;\n\tstruct timer_list icsk_retransmit_timer;\n\tstruct timer_list icsk_delack_timer;\n\t__u32 icsk_rto;\n\t__u32 icsk_rto_min;\n\t__u32 icsk_delack_max;\n\t__u32 icsk_pmtu_cookie;\n\tconst struct tcp_congestion_ops *icsk_ca_ops;\n\tconst struct inet_connection_sock_af_ops *icsk_af_ops;\n\tconst struct tcp_ulp_ops *icsk_ulp_ops;\n\tvoid *icsk_ulp_data;\n\tvoid (*icsk_clean_acked)(struct sock *, u32);\n\tstruct hlist_node icsk_listen_portaddr_node;\n\tunsigned int (*icsk_sync_mss)(struct sock *, u32);\n\t__u8 icsk_ca_state: 5;\n\t__u8 icsk_ca_initialized: 1;\n\t__u8 icsk_ca_setsockopt: 1;\n\t__u8 icsk_ca_dst_locked: 1;\n\t__u8 icsk_retransmits;\n\t__u8 icsk_pending;\n\t__u8 icsk_backoff;\n\t__u8 icsk_syn_retries;\n\t__u8 icsk_probes_out;\n\t__u16 icsk_ext_hdr_len;\n\tstruct {\n\t\t__u8 pending;\n\t\t__u8 quick;\n\t\t__u8 pingpong;\n\t\t__u8 retry;\n\t\t__u32 ato;\n\t\tlong unsigned int timeout;\n\t\t__u32 lrcvtime;\n\t\t__u16 last_seg_size;\n\t\t__u16 rcv_mss;\n\t} icsk_ack;\n\tstruct {\n\t\tint search_high;\n\t\tint search_low;\n\t\tu32 probe_size: 31;\n\t\tu32 enabled: 1;\n\t\tu32 probe_timestamp;\n\t} icsk_mtup;\n\tu32 icsk_probes_tstamp;\n\tu32 icsk_user_timeout;\n\tu64 icsk_ca_priv[13];\n};\n\nstruct tcp_ulp_ops {\n\tstruct list_head list;\n\tint (*init)(struct sock *);\n\tvoid (*update)(struct sock *, struct proto *, void (*)(struct sock *));\n\tvoid (*release)(struct sock *);\n\tint (*get_info)(const struct sock *, struct sk_buff *);\n\tsize_t (*get_info_size)(const struct sock *);\n\tvoid (*clone)(const struct request_sock *, struct sock *, const gfp_t);\n\tchar name[16];\n\tstruct module *owner;\n};\n\ntypedef unsigned int RING_IDX;\n\nstruct pvcalls_data_intf {\n\tRING_IDX in_cons;\n\tRING_IDX in_prod;\n\tRING_IDX in_error;\n\tuint8_t pad1[52];\n\tRING_IDX out_cons;\n\tRING_IDX out_prod;\n\tRING_IDX out_error;\n\tuint8_t pad2[52];\n\tRING_IDX ring_order;\n\tgrant_ref_t ref[0];\n};\n\nstruct pvcalls_data {\n\tunsigned char *in;\n\tunsigned char *out;\n};\n\nstruct xen_pvcalls_socket {\n\tuint64_t id;\n\tuint32_t domain;\n\tuint32_t type;\n\tuint32_t protocol;\n};\n\nstruct xen_pvcalls_connect {\n\tuint64_t id;\n\tuint8_t addr[28];\n\tuint32_t len;\n\tuint32_t flags;\n\tgrant_ref_t ref;\n\tuint32_t evtchn;\n};\n\nstruct xen_pvcalls_release {\n\tuint64_t id;\n\tuint8_t reuse;\n};\n\nstruct xen_pvcalls_bind {\n\tuint64_t id;\n\tuint8_t addr[28];\n\tuint32_t len;\n};\n\nstruct xen_pvcalls_listen {\n\tuint64_t id;\n\tuint32_t backlog;\n};\n\nstruct xen_pvcalls_accept {\n\tuint64_t id;\n\tuint64_t id_new;\n\tgrant_ref_t ref;\n\tuint32_t evtchn;\n};\n\nstruct xen_pvcalls_poll {\n\tuint64_t id;\n};\n\nstruct xen_pvcalls_dummy {\n\tuint8_t dummy[56];\n};\n\nstruct xen_pvcalls_request {\n\tuint32_t req_id;\n\tuint32_t cmd;\n\tunion {\n\t\tstruct xen_pvcalls_socket socket;\n\t\tstruct xen_pvcalls_connect connect;\n\t\tstruct xen_pvcalls_release release;\n\t\tstruct xen_pvcalls_bind bind;\n\t\tstruct xen_pvcalls_listen listen;\n\t\tstruct xen_pvcalls_accept accept;\n\t\tstruct xen_pvcalls_poll poll;\n\t\tstruct xen_pvcalls_dummy dummy;\n\t} u;\n};\n\nstruct _xen_pvcalls_socket {\n\tuint64_t id;\n};\n\nstruct _xen_pvcalls_connect {\n\tuint64_t id;\n};\n\nstruct _xen_pvcalls_release {\n\tuint64_t id;\n};\n\nstruct _xen_pvcalls_bind {\n\tuint64_t id;\n};\n\nstruct _xen_pvcalls_listen {\n\tuint64_t id;\n};\n\nstruct _xen_pvcalls_accept {\n\tuint64_t id;\n};\n\nstruct _xen_pvcalls_poll {\n\tuint64_t id;\n};\n\nstruct _xen_pvcalls_dummy {\n\tuint8_t dummy[8];\n};\n\nstruct xen_pvcalls_response {\n\tuint32_t req_id;\n\tuint32_t cmd;\n\tint32_t ret;\n\tuint32_t pad;\n\tunion {\n\t\tstruct _xen_pvcalls_socket socket;\n\t\tstruct _xen_pvcalls_connect connect;\n\t\tstruct _xen_pvcalls_release release;\n\t\tstruct _xen_pvcalls_bind bind;\n\t\tstruct _xen_pvcalls_listen listen;\n\t\tstruct _xen_pvcalls_accept accept;\n\t\tstruct _xen_pvcalls_poll poll;\n\t\tstruct _xen_pvcalls_dummy dummy;\n\t} u;\n};\n\nunion xen_pvcalls_sring_entry {\n\tstruct xen_pvcalls_request req;\n\tstruct xen_pvcalls_response rsp;\n};\n\nstruct xen_pvcalls_sring {\n\tRING_IDX req_prod;\n\tRING_IDX req_event;\n\tRING_IDX rsp_prod;\n\tRING_IDX rsp_event;\n\tuint8_t __pad[48];\n\tunion xen_pvcalls_sring_entry ring[1];\n};\n\nstruct xen_pvcalls_back_ring {\n\tRING_IDX rsp_prod_pvt;\n\tRING_IDX req_cons;\n\tunsigned int nr_ents;\n\tstruct xen_pvcalls_sring *sring;\n};\n\nstruct pvcalls_back_global {\n\tstruct list_head frontends;\n\tstruct semaphore frontends_lock;\n};\n\nstruct pvcalls_fedata {\n\tstruct list_head list;\n\tstruct xenbus_device *dev;\n\tstruct xen_pvcalls_sring *sring;\n\tstruct xen_pvcalls_back_ring ring;\n\tint irq;\n\tstruct list_head socket_mappings;\n\tstruct xarray socketpass_mappings;\n\tstruct semaphore socket_lock;\n};\n\nstruct pvcalls_ioworker {\n\tstruct work_struct register_work;\n\tstruct workqueue_struct *wq;\n};\n\nstruct sockpass_mapping;\n\nstruct sock_mapping {\n\tstruct list_head list;\n\tstruct pvcalls_fedata *fedata;\n\tstruct sockpass_mapping *sockpass;\n\tstruct socket *sock;\n\tuint64_t id;\n\tgrant_ref_t ref;\n\tstruct pvcalls_data_intf *ring;\n\tvoid *bytes;\n\tstruct pvcalls_data data;\n\tuint32_t ring_order;\n\tint irq;\n\tatomic_t read;\n\tatomic_t write;\n\tatomic_t io;\n\tatomic_t release;\n\tatomic_t eoi;\n\tvoid (*saved_data_ready)(struct sock *);\n\tstruct pvcalls_ioworker ioworker;\n};\n\nstruct sockpass_mapping {\n\tstruct list_head list;\n\tstruct pvcalls_fedata *fedata;\n\tstruct socket *sock;\n\tuint64_t id;\n\tstruct xen_pvcalls_request reqcopy;\n\tspinlock_t copy_lock;\n\tstruct workqueue_struct *wq;\n\tstruct work_struct register_work;\n\tvoid (*saved_data_ready)(struct sock *);\n};\n\nstruct ww_class {\n\tatomic_long_t stamp;\n\tstruct lock_class_key acquire_key;\n\tstruct lock_class_key mutex_key;\n\tconst char *acquire_name;\n\tconst char *mutex_name;\n\tunsigned int is_wait_die;\n};\n\nstruct pre_voltage_change_data {\n\tlong unsigned int old_uV;\n\tlong unsigned int min_uV;\n\tlong unsigned int max_uV;\n};\n\nstruct regulator_bulk_data {\n\tconst char *supply;\n\tstruct regulator *consumer;\n\tint ret;\n};\n\nstruct regulator_voltage {\n\tint min_uV;\n\tint max_uV;\n};\n\nstruct regulator {\n\tstruct device *dev;\n\tstruct list_head list;\n\tunsigned int always_on: 1;\n\tunsigned int bypass: 1;\n\tunsigned int device_link: 1;\n\tint uA_load;\n\tunsigned int enable_count;\n\tunsigned int deferred_disables;\n\tstruct regulator_voltage voltage[5];\n\tconst char *supply_name;\n\tstruct device_attribute dev_attr;\n\tstruct regulator_dev *rdev;\n\tstruct dentry *debugfs;\n};\n\nstruct regulator_coupler {\n\tstruct list_head list;\n\tint (*attach_regulator)(struct regulator_coupler *, struct regulator_dev *);\n\tint (*detach_regulator)(struct regulator_coupler *, struct regulator_dev *);\n\tint (*balance_voltage)(struct regulator_coupler *, struct regulator_dev *, suspend_state_t);\n};\n\nenum regulator_status {\n\tREGULATOR_STATUS_OFF = 0,\n\tREGULATOR_STATUS_ON = 1,\n\tREGULATOR_STATUS_ERROR = 2,\n\tREGULATOR_STATUS_FAST = 3,\n\tREGULATOR_STATUS_NORMAL = 4,\n\tREGULATOR_STATUS_IDLE = 5,\n\tREGULATOR_STATUS_STANDBY = 6,\n\tREGULATOR_STATUS_BYPASS = 7,\n\tREGULATOR_STATUS_UNDEFINED = 8,\n};\n\nenum regulator_detection_severity {\n\tREGULATOR_SEVERITY_PROT = 0,\n\tREGULATOR_SEVERITY_ERR = 1,\n\tREGULATOR_SEVERITY_WARN = 2,\n};\n\nstruct regulator_enable_gpio {\n\tstruct list_head list;\n\tstruct gpio_desc *gpiod;\n\tu32 enable_count;\n\tu32 request_count;\n};\n\nenum regulator_active_discharge {\n\tREGULATOR_ACTIVE_DISCHARGE_DEFAULT = 0,\n\tREGULATOR_ACTIVE_DISCHARGE_DISABLE = 1,\n\tREGULATOR_ACTIVE_DISCHARGE_ENABLE = 2,\n};\n\nstruct regulator_consumer_supply {\n\tconst char *dev_name;\n\tconst char *supply;\n};\n\nstruct trace_event_raw_regulator_basic {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_regulator_range {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tint min;\n\tint max;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_regulator_value {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tunsigned int val;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_regulator_basic {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_regulator_range {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_regulator_value {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_regulator_enable)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_enable_delay)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_enable_complete)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_disable)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_disable_complete)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_bypass_enable)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_bypass_enable_complete)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_bypass_disable)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_bypass_disable_complete)(void *, const char *);\n\ntypedef void (*btf_trace_regulator_set_voltage)(void *, const char *, int, int);\n\ntypedef void (*btf_trace_regulator_set_voltage_complete)(void *, const char *, unsigned int);\n\nenum regulator_get_type {\n\tNORMAL_GET = 0,\n\tEXCLUSIVE_GET = 1,\n\tOPTIONAL_GET = 2,\n\tMAX_GET_TYPE = 3,\n};\n\nstruct regulator_map {\n\tstruct list_head list;\n\tconst char *dev_name;\n\tconst char *supply;\n\tstruct regulator_dev *regulator;\n};\n\nstruct regulator_supply_alias {\n\tstruct list_head list;\n\tstruct device *src_dev;\n\tconst char *src_supply;\n\tstruct device *alias_dev;\n\tconst char *alias_supply;\n};\n\nstruct summary_data {\n\tstruct seq_file *s;\n\tstruct regulator_dev *parent;\n\tint level;\n};\n\nstruct summary_lock_data {\n\tstruct ww_acquire_ctx *ww_ctx;\n\tstruct regulator_dev **new_contended_rdev;\n\tstruct regulator_dev **old_contended_rdev;\n};\n\nstruct fixed_voltage_config {\n\tconst char *supply_name;\n\tconst char *input_supply;\n\tint microvolts;\n\tunsigned int startup_delay;\n\tunsigned int off_on_delay;\n\tunsigned int enabled_at_boot: 1;\n\tstruct regulator_init_data *init_data;\n};\n\nstruct fixed_regulator_data {\n\tstruct fixed_voltage_config cfg;\n\tstruct regulator_init_data init_data;\n\tstruct platform_device pdev;\n};\n\nstruct regulator_err_state {\n\tstruct regulator_dev *rdev;\n\tlong unsigned int notifs;\n\tlong unsigned int errors;\n\tint possible_errs;\n};\n\nstruct regulator_irq_data {\n\tstruct regulator_err_state *states;\n\tint num_states;\n\tvoid *data;\n\tlong int opaque;\n};\n\nstruct regulator_irq_desc {\n\tconst char *name;\n\tint irq_flags;\n\tint fatal_cnt;\n\tint reread_ms;\n\tint irq_off_ms;\n\tbool skip_off;\n\tbool high_prio;\n\tvoid *data;\n\tint (*die)(struct regulator_irq_data *);\n\tint (*map_event)(int, struct regulator_irq_data *, long unsigned int *);\n\tint (*renable)(struct regulator_irq_data *);\n};\n\nstruct regulator_bulk_devres {\n\tstruct regulator_bulk_data *consumers;\n\tint num_consumers;\n};\n\nstruct regulator_supply_alias_match {\n\tstruct device *dev;\n\tconst char *id;\n};\n\nstruct regulator_notifier_match {\n\tstruct regulator *regulator;\n\tstruct notifier_block *nb;\n};\n\nenum {\n\tREGULATOR_ERROR_CLEARED = 0,\n\tREGULATOR_FAILED_RETRY = 1,\n\tREGULATOR_ERROR_ON = 2,\n};\n\nstruct regulator_irq {\n\tstruct regulator_irq_data rdata;\n\tstruct regulator_irq_desc desc;\n\tint irq;\n\tint retry_cnt;\n\tstruct delayed_work isr_work;\n};\n\nstruct reset_control___2;\n\nstruct reset_control_bulk_data {\n\tconst char *id;\n\tstruct reset_control___2 *rstc;\n};\n\nstruct reset_controller_dev;\n\nstruct reset_control___2 {\n\tstruct reset_controller_dev *rcdev;\n\tstruct list_head list;\n\tunsigned int id;\n\tstruct kref refcnt;\n\tbool acquired;\n\tbool shared;\n\tbool array;\n\tatomic_t deassert_count;\n\tatomic_t triggered_count;\n};\n\nstruct reset_control_ops {\n\tint (*reset)(struct reset_controller_dev *, long unsigned int);\n\tint (*assert)(struct reset_controller_dev *, long unsigned int);\n\tint (*deassert)(struct reset_controller_dev *, long unsigned int);\n\tint (*status)(struct reset_controller_dev *, long unsigned int);\n};\n\nstruct reset_controller_dev {\n\tconst struct reset_control_ops *ops;\n\tstruct module *owner;\n\tstruct list_head list;\n\tstruct list_head reset_control_head;\n\tstruct device *dev;\n\tstruct device_node *of_node;\n\tint of_reset_n_cells;\n\tint (*of_xlate)(struct reset_controller_dev *, const struct of_phandle_args *);\n\tunsigned int nr_resets;\n};\n\nstruct reset_control_lookup {\n\tstruct list_head list;\n\tconst char *provider;\n\tunsigned int index;\n\tconst char *dev_id;\n\tconst char *con_id;\n};\n\nstruct reset_control_array {\n\tstruct reset_control___2 base;\n\tunsigned int num_rstcs;\n\tstruct reset_control___2 *rstc[0];\n};\n\nstruct reset_control_bulk_devres {\n\tint num_rstcs;\n\tstruct reset_control_bulk_data *rstcs;\n};\n\nstruct serial_struct32 {\n\tcompat_int_t type;\n\tcompat_int_t line;\n\tcompat_uint_t port;\n\tcompat_int_t irq;\n\tcompat_int_t flags;\n\tcompat_int_t xmit_fifo_size;\n\tcompat_int_t custom_divisor;\n\tcompat_int_t baud_base;\n\tshort unsigned int close_delay;\n\tchar io_type;\n\tchar reserved_char;\n\tcompat_int_t hub6;\n\tshort unsigned int closing_wait;\n\tshort unsigned int closing_wait2;\n\tcompat_uint_t iomem_base;\n\tshort unsigned int iomem_reg_shift;\n\tunsigned int port_high;\n\tcompat_int_t reserved;\n};\n\nstruct n_tty_data {\n\tsize_t read_head;\n\tsize_t commit_head;\n\tsize_t canon_head;\n\tsize_t echo_head;\n\tsize_t echo_commit;\n\tsize_t echo_mark;\n\tlong unsigned int char_map[4];\n\tlong unsigned int overrun_time;\n\tint num_overrun;\n\tbool no_room;\n\tunsigned char lnext: 1;\n\tunsigned char erasing: 1;\n\tunsigned char raw: 1;\n\tunsigned char real_raw: 1;\n\tunsigned char icanon: 1;\n\tunsigned char push: 1;\n\tchar read_buf[4096];\n\tlong unsigned int read_flags[64];\n\tunsigned char echo_buf[4096];\n\tsize_t read_tail;\n\tsize_t line_start;\n\tunsigned int column;\n\tunsigned int canon_column;\n\tsize_t echo_tail;\n\tstruct mutex atomic_read_lock;\n\tstruct mutex output_lock;\n};\n\nenum {\n\tERASE = 0,\n\tWERASE = 1,\n\tKILL = 2,\n};\n\nstruct termios {\n\ttcflag_t c_iflag;\n\ttcflag_t c_oflag;\n\ttcflag_t c_cflag;\n\ttcflag_t c_lflag;\n\tcc_t c_line;\n\tcc_t c_cc[19];\n};\n\nstruct termios2 {\n\ttcflag_t c_iflag;\n\ttcflag_t c_oflag;\n\ttcflag_t c_cflag;\n\ttcflag_t c_lflag;\n\tcc_t c_line;\n\tcc_t c_cc[19];\n\tspeed_t c_ispeed;\n\tspeed_t c_ospeed;\n};\n\nstruct termio {\n\tshort unsigned int c_iflag;\n\tshort unsigned int c_oflag;\n\tshort unsigned int c_cflag;\n\tshort unsigned int c_lflag;\n\tunsigned char c_line;\n\tunsigned char c_cc[8];\n};\n\nstruct ldsem_waiter {\n\tstruct list_head list;\n\tstruct task_struct *task;\n};\n\nstruct pts_fs_info___2;\n\nstruct tty_audit_buf {\n\tstruct mutex mutex;\n\tdev_t dev;\n\tunsigned int icanon: 1;\n\tsize_t valid;\n\tunsigned char *data;\n};\n\nstruct sysrq_state {\n\tstruct input_handle handle;\n\tstruct work_struct reinject_work;\n\tlong unsigned int key_down[12];\n\tunsigned int alt;\n\tunsigned int alt_use;\n\tunsigned int shift;\n\tunsigned int shift_use;\n\tbool active;\n\tbool need_reinject;\n\tbool reinjecting;\n\tbool reset_canceled;\n\tbool reset_requested;\n\tlong unsigned int reset_keybit[12];\n\tint reset_seq_len;\n\tint reset_seq_cnt;\n\tint reset_seq_version;\n\tstruct timer_list keyreset_timer;\n};\n\nstruct unipair {\n\tshort unsigned int unicode;\n\tshort unsigned int fontpos;\n};\n\nstruct unimapdesc {\n\tshort unsigned int entry_ct;\n\tstruct unipair *entries;\n};\n\nstruct kbentry {\n\tunsigned char kb_table;\n\tunsigned char kb_index;\n\tshort unsigned int kb_value;\n};\n\nstruct kbsentry {\n\tunsigned char kb_func;\n\tunsigned char kb_string[512];\n};\n\nstruct kbkeycode {\n\tunsigned int scancode;\n\tunsigned int keycode;\n};\n\nstruct kbd_repeat {\n\tint delay;\n\tint period;\n};\n\nstruct console_font_op {\n\tunsigned int op;\n\tunsigned int flags;\n\tunsigned int width;\n\tunsigned int height;\n\tunsigned int charcount;\n\tunsigned char *data;\n};\n\nstruct vt_stat {\n\tshort unsigned int v_active;\n\tshort unsigned int v_signal;\n\tshort unsigned int v_state;\n};\n\nstruct vt_sizes {\n\tshort unsigned int v_rows;\n\tshort unsigned int v_cols;\n\tshort unsigned int v_scrollsize;\n};\n\nstruct vt_consize {\n\tshort unsigned int v_rows;\n\tshort unsigned int v_cols;\n\tshort unsigned int v_vlin;\n\tshort unsigned int v_clin;\n\tshort unsigned int v_vcol;\n\tshort unsigned int v_ccol;\n};\n\nstruct vt_event {\n\tunsigned int event;\n\tunsigned int oldev;\n\tunsigned int newev;\n\tunsigned int pad[4];\n};\n\nstruct vt_setactivate {\n\tunsigned int console;\n\tstruct vt_mode mode;\n};\n\nstruct vt_spawn_console {\n\tspinlock_t lock;\n\tstruct pid *pid;\n\tint sig;\n};\n\nstruct vt_event_wait {\n\tstruct list_head list;\n\tstruct vt_event event;\n\tint done;\n};\n\nstruct compat_console_font_op {\n\tcompat_uint_t op;\n\tcompat_uint_t flags;\n\tcompat_uint_t width;\n\tcompat_uint_t height;\n\tcompat_uint_t charcount;\n\tcompat_caddr_t data;\n};\n\nstruct compat_unimapdesc {\n\tshort unsigned int entry_ct;\n\tcompat_caddr_t entries;\n};\n\nstruct vt_notifier_param {\n\tstruct vc_data *vc;\n\tunsigned int c;\n};\n\nstruct vcs_poll_data {\n\tstruct notifier_block notifier;\n\tunsigned int cons_num;\n\tint event;\n\twait_queue_head_t waitq;\n\tstruct fasync_struct *fasync;\n};\n\nstruct tiocl_selection {\n\tshort unsigned int xs;\n\tshort unsigned int ys;\n\tshort unsigned int xe;\n\tshort unsigned int ye;\n\tshort unsigned int sel_mode;\n};\n\nstruct vc_selection {\n\tstruct mutex lock;\n\tstruct vc_data *cons;\n\tchar *buffer;\n\tunsigned int buf_len;\n\tvolatile int start;\n\tint end;\n};\n\nstruct kbdiacr {\n\tunsigned char diacr;\n\tunsigned char base;\n\tunsigned char result;\n};\n\nstruct kbdiacrs {\n\tunsigned int kb_cnt;\n\tstruct kbdiacr kbdiacr[256];\n};\n\nstruct kbdiacruc {\n\tunsigned int diacr;\n\tunsigned int base;\n\tunsigned int result;\n};\n\nstruct kbdiacrsuc {\n\tunsigned int kb_cnt;\n\tstruct kbdiacruc kbdiacruc[256];\n};\n\nstruct keyboard_notifier_param {\n\tstruct vc_data *vc;\n\tint down;\n\tint shift;\n\tint ledstate;\n\tunsigned int value;\n};\n\nstruct kbd_struct {\n\tunsigned char lockstate;\n\tunsigned char slockstate;\n\tunsigned char ledmode: 1;\n\tunsigned char ledflagstate: 4;\n\tchar: 3;\n\tunsigned char default_ledflagstate: 4;\n\tunsigned char kbdmode: 3;\n\tchar: 1;\n\tunsigned char modeflags: 5;\n};\n\ntypedef void k_handler_fn(struct vc_data *, unsigned char, char);\n\ntypedef void fn_handler_fn(struct vc_data *);\n\nstruct getset_keycode_data {\n\tstruct input_keymap_entry ke;\n\tint error;\n};\n\nstruct kbd_led_trigger {\n\tstruct led_trigger trigger;\n\tunsigned int mask;\n};\n\nstruct uni_pagedir {\n\tu16 **uni_pgdir[32];\n\tlong unsigned int refcount;\n\tlong unsigned int sum;\n\tunsigned char *inverse_translations[4];\n\tu16 *inverse_trans_unicode;\n};\n\ntypedef uint32_t char32_t;\n\nstruct uni_screen {\n\tchar32_t *lines[0];\n};\n\nstruct con_driver {\n\tconst struct consw *con;\n\tconst char *desc;\n\tstruct device *dev;\n\tint node;\n\tint first;\n\tint last;\n\tint flag;\n};\n\nenum {\n\tblank_off = 0,\n\tblank_normal_wait = 1,\n\tblank_vesa_wait = 2,\n};\n\nenum {\n\tEPecma = 0,\n\tEPdec = 1,\n\tEPeq = 2,\n\tEPgt = 3,\n\tEPlt = 4,\n};\n\nstruct rgb {\n\tu8 r;\n\tu8 g;\n\tu8 b;\n};\n\nenum {\n\tESnormal = 0,\n\tESesc = 1,\n\tESsquare = 2,\n\tESgetpars = 3,\n\tESfunckey = 4,\n\tEShash = 5,\n\tESsetG0 = 6,\n\tESsetG1 = 7,\n\tESpercent = 8,\n\tEScsiignore = 9,\n\tESnonstd = 10,\n\tESpalette = 11,\n\tESosc = 12,\n};\n\nstruct interval {\n\tuint32_t first;\n\tuint32_t last;\n};\n\nstruct vc_draw_region {\n\tlong unsigned int from;\n\tlong unsigned int to;\n\tint x;\n};\n\nstruct hv_ops;\n\nstruct hvc_struct {\n\tstruct tty_port port;\n\tspinlock_t lock;\n\tint index;\n\tint do_wakeup;\n\tchar *outbuf;\n\tint outbuf_size;\n\tint n_outbuf;\n\tuint32_t vtermno;\n\tconst struct hv_ops *ops;\n\tint irq_requested;\n\tint data;\n\tstruct winsize ws;\n\tstruct work_struct tty_resize;\n\tstruct list_head next;\n\tlong unsigned int flags;\n};\n\nstruct hv_ops {\n\tint (*get_chars)(uint32_t, char *, int);\n\tint (*put_chars)(uint32_t, const char *, int);\n\tint (*flush)(uint32_t, bool);\n\tint (*notifier_add)(struct hvc_struct *, int);\n\tvoid (*notifier_del)(struct hvc_struct *, int);\n\tvoid (*notifier_hangup)(struct hvc_struct *, int);\n\tint (*tiocmget)(struct hvc_struct *);\n\tint (*tiocmset)(struct hvc_struct *, unsigned int, unsigned int);\n\tvoid (*dtr_rts)(struct hvc_struct *, int);\n};\n\nstruct earlycon_device {\n\tstruct console *con;\n\tstruct uart_port port;\n\tchar options[16];\n\tunsigned int baud;\n};\n\nstruct earlycon_id {\n\tchar name[15];\n\tchar name_term;\n\tchar compatible[128];\n\tint (*setup)(struct earlycon_device *, const char *);\n};\n\ntypedef uint32_t XENCONS_RING_IDX;\n\nstruct xencons_interface {\n\tchar in[1024];\n\tchar out[2048];\n\tXENCONS_RING_IDX in_cons;\n\tXENCONS_RING_IDX in_prod;\n\tXENCONS_RING_IDX out_cons;\n\tXENCONS_RING_IDX out_prod;\n};\n\nstruct xencons_info {\n\tstruct list_head list;\n\tstruct xenbus_device *xbdev;\n\tstruct xencons_interface *intf;\n\tunsigned int evtchn;\n\tstruct hvc_struct *hvc;\n\tint irq;\n\tint vtermno;\n\tgrant_ref_t gntref;\n};\n\nstruct uart_driver {\n\tstruct module *owner;\n\tconst char *driver_name;\n\tconst char *dev_name;\n\tint major;\n\tint minor;\n\tint nr;\n\tstruct console *cons;\n\tstruct uart_state *state;\n\tstruct tty_driver *tty_driver;\n};\n\nstruct uart_match {\n\tstruct uart_port *port;\n\tstruct uart_driver *driver;\n};\n\nenum hwparam_type {\n\thwparam_ioport = 0,\n\thwparam_iomem = 1,\n\thwparam_ioport_or_iomem = 2,\n\thwparam_irq = 3,\n\thwparam_dma = 4,\n\thwparam_dma_addr = 5,\n\thwparam_other = 6,\n};\n\nstruct plat_serial8250_port {\n\tlong unsigned int iobase;\n\tvoid *membase;\n\tresource_size_t mapbase;\n\tunsigned int irq;\n\tlong unsigned int irqflags;\n\tunsigned int uartclk;\n\tvoid *private_data;\n\tunsigned char regshift;\n\tunsigned char iotype;\n\tunsigned char hub6;\n\tunsigned char has_sysrq;\n\tupf_t flags;\n\tunsigned int type;\n\tunsigned int (*serial_in)(struct uart_port *, int);\n\tvoid (*serial_out)(struct uart_port *, int, int);\n\tvoid (*set_termios)(struct uart_port *, struct ktermios *, struct ktermios *);\n\tvoid (*set_ldisc)(struct uart_port *, struct ktermios *);\n\tunsigned int (*get_mctrl)(struct uart_port *);\n\tint (*handle_irq)(struct uart_port *);\n\tvoid (*pm)(struct uart_port *, unsigned int, unsigned int);\n\tvoid (*handle_break)(struct uart_port *);\n};\n\nenum {\n\tPLAT8250_DEV_LEGACY = 4294967295,\n\tPLAT8250_DEV_PLATFORM = 0,\n\tPLAT8250_DEV_PLATFORM1 = 1,\n\tPLAT8250_DEV_PLATFORM2 = 2,\n\tPLAT8250_DEV_FOURPORT = 3,\n\tPLAT8250_DEV_ACCENT = 4,\n\tPLAT8250_DEV_BOCA = 5,\n\tPLAT8250_DEV_EXAR_ST16C554 = 6,\n\tPLAT8250_DEV_HUB6 = 7,\n\tPLAT8250_DEV_AU1X00 = 8,\n\tPLAT8250_DEV_SM501 = 9,\n};\n\nstruct uart_8250_port;\n\nstruct uart_8250_ops {\n\tint (*setup_irq)(struct uart_8250_port *);\n\tvoid (*release_irq)(struct uart_8250_port *);\n};\n\nstruct mctrl_gpios;\n\nstruct uart_8250_dma;\n\nstruct uart_8250_em485;\n\nstruct uart_8250_port {\n\tstruct uart_port port;\n\tstruct timer_list timer;\n\tstruct list_head list;\n\tu32 capabilities;\n\tshort unsigned int bugs;\n\tbool fifo_bug;\n\tunsigned int tx_loadsz;\n\tunsigned char acr;\n\tunsigned char fcr;\n\tunsigned char ier;\n\tunsigned char lcr;\n\tunsigned char mcr;\n\tunsigned char mcr_mask;\n\tunsigned char mcr_force;\n\tunsigned char cur_iotype;\n\tunsigned int rpm_tx_active;\n\tunsigned char canary;\n\tunsigned char probe;\n\tstruct mctrl_gpios *gpios;\n\tunsigned char lsr_saved_flags;\n\tunsigned char msr_saved_flags;\n\tstruct uart_8250_dma *dma;\n\tconst struct uart_8250_ops *ops;\n\tint (*dl_read)(struct uart_8250_port *);\n\tvoid (*dl_write)(struct uart_8250_port *, int);\n\tstruct uart_8250_em485 *em485;\n\tvoid (*rs485_start_tx)(struct uart_8250_port *);\n\tvoid (*rs485_stop_tx)(struct uart_8250_port *);\n\tstruct delayed_work overrun_backoff;\n\tu32 overrun_backoff_time_ms;\n};\n\nstruct uart_8250_em485 {\n\tstruct hrtimer start_tx_timer;\n\tstruct hrtimer stop_tx_timer;\n\tstruct hrtimer *active_timer;\n\tstruct uart_8250_port *port;\n\tunsigned int tx_stopped: 1;\n};\n\nstruct uart_8250_dma {\n\tint (*tx_dma)(struct uart_8250_port *);\n\tint (*rx_dma)(struct uart_8250_port *);\n\tdma_filter_fn fn;\n\tvoid *rx_param;\n\tvoid *tx_param;\n\tstruct dma_slave_config rxconf;\n\tstruct dma_slave_config txconf;\n\tstruct dma_chan___2 *rxchan;\n\tstruct dma_chan___2 *txchan;\n\tphys_addr_t rx_dma_addr;\n\tphys_addr_t tx_dma_addr;\n\tdma_addr_t rx_addr;\n\tdma_addr_t tx_addr;\n\tdma_cookie_t rx_cookie;\n\tdma_cookie_t tx_cookie;\n\tvoid *rx_buf;\n\tsize_t rx_size;\n\tsize_t tx_size;\n\tunsigned char tx_running;\n\tunsigned char tx_err;\n\tunsigned char rx_running;\n};\n\nstruct old_serial_port {\n\tunsigned int uart;\n\tunsigned int baud_base;\n\tunsigned int port;\n\tunsigned int irq;\n\tupf_t flags;\n\tunsigned char io_type;\n\tunsigned char *iomem_base;\n\tshort unsigned int iomem_reg_shift;\n};\n\nstruct irq_info___2 {\n\tstruct hlist_node node;\n\tint irq;\n\tspinlock_t lock;\n\tstruct list_head *head;\n};\n\nstruct serial8250_config {\n\tconst char *name;\n\tshort unsigned int fifo_size;\n\tshort unsigned int tx_loadsz;\n\tunsigned char fcr;\n\tunsigned char rxtrig_bytes[4];\n\tunsigned int flags;\n};\n\nstruct dw8250_port_data {\n\tint line;\n\tstruct uart_8250_dma dma;\n\tu8 dlf_size;\n};\n\nstruct fintek_8250 {\n\tu16 pid;\n\tu16 base_port;\n\tu8 index;\n\tu8 key;\n};\n\nstruct pciserial_board {\n\tunsigned int flags;\n\tunsigned int num_ports;\n\tunsigned int base_baud;\n\tunsigned int uart_offset;\n\tunsigned int reg_shift;\n\tunsigned int first_offset;\n};\n\nstruct serial_private;\n\nstruct pci_serial_quirk {\n\tu32 vendor;\n\tu32 device;\n\tu32 subvendor;\n\tu32 subdevice;\n\tint (*probe)(struct pci_dev *);\n\tint (*init)(struct pci_dev *);\n\tint (*setup)(struct serial_private *, const struct pciserial_board *, struct uart_8250_port *, int);\n\tvoid (*exit)(struct pci_dev *);\n};\n\nstruct serial_private {\n\tstruct pci_dev *dev;\n\tunsigned int nr;\n\tstruct pci_serial_quirk *quirk;\n\tconst struct pciserial_board *board;\n\tint line[0];\n};\n\nstruct f815xxa_data {\n\tspinlock_t lock;\n\tint idx;\n};\n\nstruct timedia_struct {\n\tint num;\n\tconst short unsigned int *ids;\n};\n\nstruct quatech_feature {\n\tu16 devid;\n\tbool amcc;\n};\n\nenum pci_board_num_t {\n\tpbn_default = 0,\n\tpbn_b0_1_115200 = 1,\n\tpbn_b0_2_115200 = 2,\n\tpbn_b0_4_115200 = 3,\n\tpbn_b0_5_115200 = 4,\n\tpbn_b0_8_115200 = 5,\n\tpbn_b0_1_921600 = 6,\n\tpbn_b0_2_921600 = 7,\n\tpbn_b0_4_921600 = 8,\n\tpbn_b0_2_1130000 = 9,\n\tpbn_b0_4_1152000 = 10,\n\tpbn_b0_4_1250000 = 11,\n\tpbn_b0_2_1843200 = 12,\n\tpbn_b0_4_1843200 = 13,\n\tpbn_b0_1_3906250 = 14,\n\tpbn_b0_bt_1_115200 = 15,\n\tpbn_b0_bt_2_115200 = 16,\n\tpbn_b0_bt_4_115200 = 17,\n\tpbn_b0_bt_8_115200 = 18,\n\tpbn_b0_bt_1_460800 = 19,\n\tpbn_b0_bt_2_460800 = 20,\n\tpbn_b0_bt_4_460800 = 21,\n\tpbn_b0_bt_1_921600 = 22,\n\tpbn_b0_bt_2_921600 = 23,\n\tpbn_b0_bt_4_921600 = 24,\n\tpbn_b0_bt_8_921600 = 25,\n\tpbn_b1_1_115200 = 26,\n\tpbn_b1_2_115200 = 27,\n\tpbn_b1_4_115200 = 28,\n\tpbn_b1_8_115200 = 29,\n\tpbn_b1_16_115200 = 30,\n\tpbn_b1_1_921600 = 31,\n\tpbn_b1_2_921600 = 32,\n\tpbn_b1_4_921600 = 33,\n\tpbn_b1_8_921600 = 34,\n\tpbn_b1_2_1250000 = 35,\n\tpbn_b1_bt_1_115200 = 36,\n\tpbn_b1_bt_2_115200 = 37,\n\tpbn_b1_bt_4_115200 = 38,\n\tpbn_b1_bt_2_921600 = 39,\n\tpbn_b1_1_1382400 = 40,\n\tpbn_b1_2_1382400 = 41,\n\tpbn_b1_4_1382400 = 42,\n\tpbn_b1_8_1382400 = 43,\n\tpbn_b2_1_115200 = 44,\n\tpbn_b2_2_115200 = 45,\n\tpbn_b2_4_115200 = 46,\n\tpbn_b2_8_115200 = 47,\n\tpbn_b2_1_460800 = 48,\n\tpbn_b2_4_460800 = 49,\n\tpbn_b2_8_460800 = 50,\n\tpbn_b2_16_460800 = 51,\n\tpbn_b2_1_921600 = 52,\n\tpbn_b2_4_921600 = 53,\n\tpbn_b2_8_921600 = 54,\n\tpbn_b2_8_1152000 = 55,\n\tpbn_b2_bt_1_115200 = 56,\n\tpbn_b2_bt_2_115200 = 57,\n\tpbn_b2_bt_4_115200 = 58,\n\tpbn_b2_bt_2_921600 = 59,\n\tpbn_b2_bt_4_921600 = 60,\n\tpbn_b3_2_115200 = 61,\n\tpbn_b3_4_115200 = 62,\n\tpbn_b3_8_115200 = 63,\n\tpbn_b4_bt_2_921600 = 64,\n\tpbn_b4_bt_4_921600 = 65,\n\tpbn_b4_bt_8_921600 = 66,\n\tpbn_panacom = 67,\n\tpbn_panacom2 = 68,\n\tpbn_panacom4 = 69,\n\tpbn_plx_romulus = 70,\n\tpbn_endrun_2_4000000 = 71,\n\tpbn_oxsemi = 72,\n\tpbn_oxsemi_1_3906250 = 73,\n\tpbn_oxsemi_2_3906250 = 74,\n\tpbn_oxsemi_4_3906250 = 75,\n\tpbn_oxsemi_8_3906250 = 76,\n\tpbn_intel_i960 = 77,\n\tpbn_sgi_ioc3 = 78,\n\tpbn_computone_4 = 79,\n\tpbn_computone_6 = 80,\n\tpbn_computone_8 = 81,\n\tpbn_sbsxrsio = 82,\n\tpbn_pasemi_1682M = 83,\n\tpbn_ni8430_2 = 84,\n\tpbn_ni8430_4 = 85,\n\tpbn_ni8430_8 = 86,\n\tpbn_ni8430_16 = 87,\n\tpbn_ADDIDATA_PCIe_1_3906250 = 88,\n\tpbn_ADDIDATA_PCIe_2_3906250 = 89,\n\tpbn_ADDIDATA_PCIe_4_3906250 = 90,\n\tpbn_ADDIDATA_PCIe_8_3906250 = 91,\n\tpbn_ce4100_1_115200 = 92,\n\tpbn_omegapci = 93,\n\tpbn_NETMOS9900_2s_115200 = 94,\n\tpbn_brcm_trumanage = 95,\n\tpbn_fintek_4 = 96,\n\tpbn_fintek_8 = 97,\n\tpbn_fintek_12 = 98,\n\tpbn_fintek_F81504A = 99,\n\tpbn_fintek_F81508A = 100,\n\tpbn_fintek_F81512A = 101,\n\tpbn_wch382_2 = 102,\n\tpbn_wch384_4 = 103,\n\tpbn_wch384_8 = 104,\n\tpbn_pericom_PI7C9X7951 = 105,\n\tpbn_pericom_PI7C9X7952 = 106,\n\tpbn_pericom_PI7C9X7954 = 107,\n\tpbn_pericom_PI7C9X7958 = 108,\n\tpbn_sunix_pci_1s = 109,\n\tpbn_sunix_pci_2s = 110,\n\tpbn_sunix_pci_4s = 111,\n\tpbn_sunix_pci_8s = 112,\n\tpbn_sunix_pci_16s = 113,\n\tpbn_titan_1_4000000 = 114,\n\tpbn_titan_2_4000000 = 115,\n\tpbn_titan_4_4000000 = 116,\n\tpbn_titan_8_4000000 = 117,\n\tpbn_moxa8250_2p = 118,\n\tpbn_moxa8250_4p = 119,\n\tpbn_moxa8250_8p = 120,\n};\n\nstruct lpss8250;\n\nstruct lpss8250_board {\n\tlong unsigned int freq;\n\tunsigned int base_baud;\n\tint (*setup)(struct lpss8250 *, struct uart_port *);\n\tvoid (*exit)(struct lpss8250 *);\n};\n\nstruct lpss8250 {\n\tstruct dw8250_port_data data;\n\tstruct lpss8250_board *board;\n\tstruct dw_dma_chip dma_chip;\n\tstruct dw_dma_slave dma_param;\n\tu8 dma_maxburst;\n};\n\nstruct hsu_dma_slave {\n\tstruct device *dma_dev;\n\tint chan_id;\n};\n\nstruct mid8250;\n\nstruct mid8250_board {\n\tunsigned int flags;\n\tlong unsigned int freq;\n\tunsigned int base_baud;\n\tint (*setup)(struct mid8250 *, struct uart_port *);\n\tvoid (*exit)(struct mid8250 *);\n};\n\nstruct mid8250 {\n\tint line;\n\tint dma_index;\n\tstruct pci_dev *dma_dev;\n\tstruct uart_8250_dma dma;\n\tstruct mid8250_board *board;\n\tstruct hsu_dma_chip dma_chip;\n};\n\nstruct gpio_array___2;\n\nenum mctrl_gpio_idx {\n\tUART_GPIO_CTS = 0,\n\tUART_GPIO_DSR = 1,\n\tUART_GPIO_DCD = 2,\n\tUART_GPIO_RNG = 3,\n\tUART_GPIO_RI = 3,\n\tUART_GPIO_RTS = 4,\n\tUART_GPIO_DTR = 5,\n\tUART_GPIO_MAX = 6,\n};\n\nstruct mctrl_gpios___2 {\n\tstruct uart_port *port;\n\tstruct gpio_desc *gpio[6];\n\tint irq[6];\n\tunsigned int mctrl_prev;\n\tbool mctrl_on;\n};\n\nstruct serdev_device;\n\nstruct serdev_device_ops {\n\tint (*receive_buf)(struct serdev_device *, const unsigned char *, size_t);\n\tvoid (*write_wakeup)(struct serdev_device *);\n};\n\nstruct serdev_controller;\n\nstruct serdev_device {\n\tstruct device dev;\n\tint nr;\n\tstruct serdev_controller *ctrl;\n\tconst struct serdev_device_ops *ops;\n\tstruct completion write_comp;\n\tstruct mutex write_lock;\n};\n\nstruct serdev_controller_ops;\n\nstruct serdev_controller {\n\tstruct device dev;\n\tunsigned int nr;\n\tstruct serdev_device *serdev;\n\tconst struct serdev_controller_ops *ops;\n};\n\nstruct serdev_device_driver {\n\tstruct device_driver driver;\n\tint (*probe)(struct serdev_device *);\n\tvoid (*remove)(struct serdev_device *);\n};\n\nenum serdev_parity {\n\tSERDEV_PARITY_NONE = 0,\n\tSERDEV_PARITY_EVEN = 1,\n\tSERDEV_PARITY_ODD = 2,\n};\n\nstruct serdev_controller_ops {\n\tint (*write_buf)(struct serdev_controller *, const unsigned char *, size_t);\n\tvoid (*write_flush)(struct serdev_controller *);\n\tint (*write_room)(struct serdev_controller *);\n\tint (*open)(struct serdev_controller *);\n\tvoid (*close)(struct serdev_controller *);\n\tvoid (*set_flow_control)(struct serdev_controller *, bool);\n\tint (*set_parity)(struct serdev_controller *, enum serdev_parity);\n\tunsigned int (*set_baudrate)(struct serdev_controller *, unsigned int);\n\tvoid (*wait_until_sent)(struct serdev_controller *, long int);\n\tint (*get_tiocm)(struct serdev_controller *);\n\tint (*set_tiocm)(struct serdev_controller *, unsigned int, unsigned int);\n};\n\nstruct acpi_serdev_lookup {\n\tacpi_handle device_handle;\n\tacpi_handle controller_handle;\n\tint n;\n\tint index;\n};\n\nstruct serport {\n\tstruct tty_port *port;\n\tstruct tty_struct *tty;\n\tstruct tty_driver *tty_drv;\n\tint tty_idx;\n\tlong unsigned int flags;\n};\n\nstruct memdev {\n\tconst char *name;\n\tumode_t mode;\n\tconst struct file_operations *fops;\n\tfmode_t fmode;\n};\n\nstruct timer_rand_state {\n\tcycles_t last_time;\n\tlong int last_delta;\n\tlong int last_delta2;\n};\n\nstruct trace_event_raw_add_device_randomness {\n\tstruct trace_entry ent;\n\tint bytes;\n\tlong unsigned int IP;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_random__mix_pool_bytes {\n\tstruct trace_entry ent;\n\tconst char *pool_name;\n\tint bytes;\n\tlong unsigned int IP;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_credit_entropy_bits {\n\tstruct trace_entry ent;\n\tconst char *pool_name;\n\tint bits;\n\tint entropy_count;\n\tlong unsigned int IP;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_debit_entropy {\n\tstruct trace_entry ent;\n\tconst char *pool_name;\n\tint debit_bits;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_add_input_randomness {\n\tstruct trace_entry ent;\n\tint input_bits;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_add_disk_randomness {\n\tstruct trace_entry ent;\n\tdev_t dev;\n\tint input_bits;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_random__get_random_bytes {\n\tstruct trace_entry ent;\n\tint nbytes;\n\tlong unsigned int IP;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_random__extract_entropy {\n\tstruct trace_entry ent;\n\tconst char *pool_name;\n\tint nbytes;\n\tint entropy_count;\n\tlong unsigned int IP;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_urandom_read {\n\tstruct trace_entry ent;\n\tint got_bits;\n\tint pool_left;\n\tint input_left;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_prandom_u32 {\n\tstruct trace_entry ent;\n\tunsigned int ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_add_device_randomness {};\n\nstruct trace_event_data_offsets_random__mix_pool_bytes {};\n\nstruct trace_event_data_offsets_credit_entropy_bits {};\n\nstruct trace_event_data_offsets_debit_entropy {};\n\nstruct trace_event_data_offsets_add_input_randomness {};\n\nstruct trace_event_data_offsets_add_disk_randomness {};\n\nstruct trace_event_data_offsets_random__get_random_bytes {};\n\nstruct trace_event_data_offsets_random__extract_entropy {};\n\nstruct trace_event_data_offsets_urandom_read {};\n\nstruct trace_event_data_offsets_prandom_u32 {};\n\ntypedef void (*btf_trace_add_device_randomness)(void *, int, long unsigned int);\n\ntypedef void (*btf_trace_mix_pool_bytes)(void *, const char *, int, long unsigned int);\n\ntypedef void (*btf_trace_mix_pool_bytes_nolock)(void *, const char *, int, long unsigned int);\n\ntypedef void (*btf_trace_credit_entropy_bits)(void *, const char *, int, int, long unsigned int);\n\ntypedef void (*btf_trace_debit_entropy)(void *, const char *, int);\n\ntypedef void (*btf_trace_add_input_randomness)(void *, int);\n\ntypedef void (*btf_trace_add_disk_randomness)(void *, dev_t, int);\n\ntypedef void (*btf_trace_get_random_bytes)(void *, int, long unsigned int);\n\ntypedef void (*btf_trace_get_random_bytes_arch)(void *, int, long unsigned int);\n\ntypedef void (*btf_trace_extract_entropy)(void *, const char *, int, int, long unsigned int);\n\ntypedef void (*btf_trace_urandom_read)(void *, int, int, int);\n\ntypedef void (*btf_trace_prandom_u32)(void *, unsigned int);\n\nstruct poolinfo {\n\tint poolbitshift;\n\tint poolwords;\n\tint poolbytes;\n\tint poolfracbits;\n\tint tap1;\n\tint tap2;\n\tint tap3;\n\tint tap4;\n\tint tap5;\n};\n\nstruct crng_state {\n\t__u32 state[16];\n\tlong unsigned int init_time;\n\tspinlock_t lock;\n};\n\nstruct entropy_store {\n\tconst struct poolinfo *poolinfo;\n\t__u32 *pool;\n\tconst char *name;\n\tspinlock_t lock;\n\tshort unsigned int add_ptr;\n\tshort unsigned int input_rotate;\n\tint entropy_count;\n\tunsigned int last_data_init: 1;\n\t__u8 last_data[10];\n};\n\nstruct fast_pool {\n\t__u32 pool[4];\n\tlong unsigned int last;\n\tshort unsigned int reg_idx;\n\tunsigned char count;\n};\n\nstruct batched_entropy {\n\tunion {\n\t\tu64 entropy_u64[8];\n\t\tu32 entropy_u32[16];\n\t};\n\tunsigned int position;\n\tspinlock_t batch_lock;\n};\n\nstruct hpet_info {\n\tlong unsigned int hi_ireqfreq;\n\tlong unsigned int hi_flags;\n\tshort unsigned int hi_hpet;\n\tshort unsigned int hi_timer;\n};\n\nstruct hpet_timer {\n\tu64 hpet_config;\n\tunion {\n\t\tu64 _hpet_hc64;\n\t\tu32 _hpet_hc32;\n\t\tlong unsigned int _hpet_compare;\n\t} _u1;\n\tu64 hpet_fsb[2];\n};\n\nstruct hpet {\n\tu64 hpet_cap;\n\tu64 res0;\n\tu64 hpet_config;\n\tu64 res1;\n\tu64 hpet_isr;\n\tu64 res2[25];\n\tunion {\n\t\tu64 _hpet_mc64;\n\t\tu32 _hpet_mc32;\n\t\tlong unsigned int _hpet_mc;\n\t} _u0;\n\tu64 res3;\n\tstruct hpet_timer hpet_timers[1];\n};\n\nstruct hpets;\n\nstruct hpet_dev {\n\tstruct hpets *hd_hpets;\n\tstruct hpet *hd_hpet;\n\tstruct hpet_timer *hd_timer;\n\tlong unsigned int hd_ireqfreq;\n\tlong unsigned int hd_irqdata;\n\twait_queue_head_t hd_waitqueue;\n\tstruct fasync_struct *hd_async_queue;\n\tunsigned int hd_flags;\n\tunsigned int hd_irq;\n\tunsigned int hd_hdwirq;\n\tchar hd_name[7];\n};\n\nstruct hpets {\n\tstruct hpets *hp_next;\n\tstruct hpet *hp_hpet;\n\tlong unsigned int hp_hpet_phys;\n\tstruct clocksource *hp_clocksource;\n\tlong long unsigned int hp_tick_freq;\n\tlong unsigned int hp_delta;\n\tunsigned int hp_ntimer;\n\tunsigned int hp_which;\n\tstruct hpet_dev hp_dev[0];\n};\n\nstruct compat_hpet_info {\n\tcompat_ulong_t hi_ireqfreq;\n\tcompat_ulong_t hi_flags;\n\tshort unsigned int hi_hpet;\n\tshort unsigned int hi_timer;\n};\n\nstruct nvram_ops {\n\tssize_t (*get_size)();\n\tunsigned char (*read_byte)(int);\n\tvoid (*write_byte)(unsigned char, int);\n\tssize_t (*read)(char *, size_t, loff_t *);\n\tssize_t (*write)(char *, size_t, loff_t *);\n\tlong int (*initialize)();\n\tlong int (*set_checksum)();\n};\n\nstruct vcpu_data;\n\nstruct amd_iommu_pi_data {\n\tu32 ga_tag;\n\tu32 prev_ga_tag;\n\tu64 base;\n\tbool is_guest_mode;\n\tstruct vcpu_data *vcpu_data;\n\tvoid *ir_data;\n};\n\nstruct vcpu_data {\n\tu64 pi_desc_addr;\n\tu32 vector;\n};\n\nstruct amd_iommu_device_info {\n\tint max_pasids;\n\tu32 flags;\n};\n\nenum io_pgtable_fmt {\n\tARM_32_LPAE_S1 = 0,\n\tARM_32_LPAE_S2 = 1,\n\tARM_64_LPAE_S1 = 2,\n\tARM_64_LPAE_S2 = 3,\n\tARM_V7S = 4,\n\tARM_MALI_LPAE = 5,\n\tAMD_IOMMU_V1 = 6,\n\tIO_PGTABLE_NUM_FMTS = 7,\n};\n\nstruct iommu_flush_ops {\n\tvoid (*tlb_flush_all)(void *);\n\tvoid (*tlb_flush_walk)(long unsigned int, size_t, size_t, void *);\n\tvoid (*tlb_add_page)(struct iommu_iotlb_gather *, long unsigned int, size_t, void *);\n};\n\nstruct io_pgtable_cfg {\n\tlong unsigned int quirks;\n\tlong unsigned int pgsize_bitmap;\n\tunsigned int ias;\n\tunsigned int oas;\n\tbool coherent_walk;\n\tconst struct iommu_flush_ops *tlb;\n\tstruct device *iommu_dev;\n\tunion {\n\t\tstruct {\n\t\t\tu64 ttbr;\n\t\t\tstruct {\n\t\t\t\tu32 ips: 3;\n\t\t\t\tu32 tg: 2;\n\t\t\t\tu32 sh: 2;\n\t\t\t\tu32 orgn: 2;\n\t\t\t\tu32 irgn: 2;\n\t\t\t\tu32 tsz: 6;\n\t\t\t} tcr;\n\t\t\tu64 mair;\n\t\t} arm_lpae_s1_cfg;\n\t\tstruct {\n\t\t\tu64 vttbr;\n\t\t\tstruct {\n\t\t\t\tu32 ps: 3;\n\t\t\t\tu32 tg: 2;\n\t\t\t\tu32 sh: 2;\n\t\t\t\tu32 orgn: 2;\n\t\t\t\tu32 irgn: 2;\n\t\t\t\tu32 sl: 2;\n\t\t\t\tu32 tsz: 6;\n\t\t\t} vtcr;\n\t\t} arm_lpae_s2_cfg;\n\t\tstruct {\n\t\t\tu32 ttbr;\n\t\t\tu32 tcr;\n\t\t\tu32 nmrr;\n\t\t\tu32 prrr;\n\t\t} arm_v7s_cfg;\n\t\tstruct {\n\t\t\tu64 transtab;\n\t\t\tu64 memattr;\n\t\t} arm_mali_lpae_cfg;\n\t};\n};\n\nstruct io_pgtable_ops {\n\tint (*map)(struct io_pgtable_ops *, long unsigned int, phys_addr_t, size_t, int, gfp_t);\n\tsize_t (*unmap)(struct io_pgtable_ops *, long unsigned int, size_t, struct iommu_iotlb_gather *);\n\tphys_addr_t (*iova_to_phys)(struct io_pgtable_ops *, long unsigned int);\n};\n\nstruct io_pgtable {\n\tenum io_pgtable_fmt fmt;\n\tvoid *cookie;\n\tstruct io_pgtable_cfg cfg;\n\tstruct io_pgtable_ops ops;\n};\n\nstruct irq_remap_table {\n\traw_spinlock_t lock;\n\tunsigned int min_index;\n\tu32 *table;\n};\n\nstruct amd_iommu_fault {\n\tu64 address;\n\tu32 pasid;\n\tu16 device_id;\n\tu16 tag;\n\tu16 flags;\n};\n\nstruct amd_io_pgtable {\n\tstruct io_pgtable_cfg pgtbl_cfg;\n\tstruct io_pgtable iop;\n\tint mode;\n\tu64 *root;\n\tatomic64_t pt_root;\n};\n\nstruct protection_domain {\n\tstruct list_head dev_list;\n\tstruct iommu_domain domain;\n\tstruct amd_io_pgtable iop;\n\tspinlock_t lock;\n\tu16 id;\n\tint glx;\n\tu64 *gcr3_tbl;\n\tlong unsigned int flags;\n\tunsigned int dev_cnt;\n\tunsigned int dev_iommu[32];\n};\n\nstruct amd_irte_ops;\n\nstruct amd_iommu___2 {\n\tstruct list_head list;\n\tint index;\n\traw_spinlock_t lock;\n\tstruct pci_dev *dev;\n\tstruct pci_dev *root_pdev;\n\tu64 mmio_phys;\n\tu64 mmio_phys_end;\n\tu8 *mmio_base;\n\tu32 cap;\n\tu8 acpi_flags;\n\tu64 features;\n\tbool is_iommu_v2;\n\tu16 devid;\n\tu16 cap_ptr;\n\tu16 pci_seg;\n\tu64 exclusion_start;\n\tu64 exclusion_length;\n\tu8 *cmd_buf;\n\tu32 cmd_buf_head;\n\tu32 cmd_buf_tail;\n\tu8 *evt_buf;\n\tu8 *ppr_log;\n\tu8 *ga_log;\n\tu8 *ga_log_tail;\n\tbool int_enabled;\n\tbool need_sync;\n\tstruct iommu_device iommu;\n\tu32 stored_addr_lo;\n\tu32 stored_addr_hi;\n\tu32 stored_l1[108];\n\tu32 stored_l2[131];\n\tu8 max_banks;\n\tu8 max_counters;\n\tstruct irq_domain *ir_domain;\n\tstruct irq_domain *msi_domain;\n\tstruct amd_irte_ops *irte_ops;\n\tu32 flags;\n\tvolatile u64 *cmd_sem;\n\tu64 cmd_sem_val;\n\tstruct irq_affinity_notify intcapxt_notify;\n};\n\nstruct amd_irte_ops {\n\tvoid (*prepare)(void *, u32, bool, u8, u32, int);\n\tvoid (*activate)(void *, u16, u16);\n\tvoid (*deactivate)(void *, u16, u16);\n\tvoid (*set_affinity)(void *, u16, u16, u8, u32);\n\tvoid * (*get)(struct irq_remap_table *, int);\n\tvoid (*set_allocated)(struct irq_remap_table *, int);\n\tbool (*is_allocated)(struct irq_remap_table *, int);\n\tvoid (*clear_allocated)(struct irq_remap_table *, int);\n};\n\nstruct acpihid_map_entry {\n\tstruct list_head list;\n\tu8 uid[256];\n\tu8 hid[9];\n\tu16 devid;\n\tu16 root_devid;\n\tbool cmd_line;\n\tstruct iommu_group *group;\n};\n\nstruct devid_map {\n\tstruct list_head list;\n\tu8 id;\n\tu16 devid;\n\tbool cmd_line;\n};\n\nstruct iommu_dev_data {\n\tspinlock_t lock;\n\tstruct list_head list;\n\tstruct llist_node dev_data_list;\n\tstruct protection_domain *domain;\n\tstruct pci_dev *pdev;\n\tu16 devid;\n\tbool iommu_v2;\n\tstruct {\n\t\tbool enabled;\n\t\tint qdep;\n\t} ats;\n\tbool pri_tlp;\n\tbool use_vapic;\n\tbool defer_attach;\n\tstruct ratelimit_state rs;\n};\n\nstruct dev_table_entry {\n\tu64 data[4];\n};\n\nstruct unity_map_entry {\n\tstruct list_head list;\n\tu16 devid_start;\n\tu16 devid_end;\n\tu64 address_start;\n\tu64 address_end;\n\tint prot;\n};\n\nenum amd_iommu_intr_mode_type {\n\tAMD_IOMMU_GUEST_IR_LEGACY = 0,\n\tAMD_IOMMU_GUEST_IR_LEGACY_GA = 1,\n\tAMD_IOMMU_GUEST_IR_VAPIC = 2,\n};\n\nunion irte {\n\tu32 val;\n\tstruct {\n\t\tu32 valid: 1;\n\t\tu32 no_fault: 1;\n\t\tu32 int_type: 3;\n\t\tu32 rq_eoi: 1;\n\t\tu32 dm: 1;\n\t\tu32 rsvd_1: 1;\n\t\tu32 destination: 8;\n\t\tu32 vector: 8;\n\t\tu32 rsvd_2: 8;\n\t} fields;\n};\n\nunion irte_ga_lo {\n\tu64 val;\n\tstruct {\n\t\tu64 valid: 1;\n\t\tu64 no_fault: 1;\n\t\tu64 int_type: 3;\n\t\tu64 rq_eoi: 1;\n\t\tu64 dm: 1;\n\t\tu64 guest_mode: 1;\n\t\tu64 destination: 24;\n\t\tu64 ga_tag: 32;\n\t} fields_remap;\n\tstruct {\n\t\tu64 valid: 1;\n\t\tu64 no_fault: 1;\n\t\tu64 ga_log_intr: 1;\n\t\tu64 rsvd1: 3;\n\t\tu64 is_run: 1;\n\t\tu64 guest_mode: 1;\n\t\tu64 destination: 24;\n\t\tu64 ga_tag: 32;\n\t} fields_vapic;\n};\n\nunion irte_ga_hi {\n\tu64 val;\n\tstruct {\n\t\tu64 vector: 8;\n\t\tu64 rsvd_1: 4;\n\t\tu64 ga_root_ptr: 40;\n\t\tu64 rsvd_2: 4;\n\t\tu64 destination: 8;\n\t} fields;\n};\n\nstruct irte_ga {\n\tunion irte_ga_lo lo;\n\tunion irte_ga_hi hi;\n};\n\nstruct irq_2_irte {\n\tu16 devid;\n\tu16 index;\n};\n\nstruct amd_ir_data {\n\tu32 cached_ga_tag;\n\tstruct irq_2_irte irq_2_irte;\n\tstruct msi_msg msi_entry;\n\tvoid *entry;\n\tvoid *ref;\n\tstruct irq_cfg *cfg;\n\tint ga_vector;\n\tint ga_root_ptr;\n\tint ga_tag;\n};\n\nstruct irq_remap_ops {\n\tint capability;\n\tint (*prepare)();\n\tint (*enable)();\n\tvoid (*disable)();\n\tint (*reenable)(int);\n\tint (*enable_faulting)();\n};\n\nstruct iommu_cmd {\n\tu32 data[4];\n};\n\nenum irq_remap_cap {\n\tIRQ_POSTING_CAP = 0,\n};\n\nstruct ivhd_header {\n\tu8 type;\n\tu8 flags;\n\tu16 length;\n\tu16 devid;\n\tu16 cap_ptr;\n\tu64 mmio_phys;\n\tu16 pci_seg;\n\tu16 info;\n\tu32 efr_attr;\n\tu64 efr_reg;\n\tu64 res;\n};\n\nstruct ivhd_entry {\n\tu8 type;\n\tu16 devid;\n\tu8 flags;\n\tu32 ext;\n\tu32 hidh;\n\tu64 cid;\n\tu8 uidf;\n\tu8 uidl;\n\tu8 uid;\n} __attribute__((packed));\n\nstruct ivmd_header {\n\tu8 type;\n\tu8 flags;\n\tu16 length;\n\tu16 devid;\n\tu16 aux;\n\tu64 resv;\n\tu64 range_start;\n\tu64 range_length;\n};\n\nenum iommu_init_state {\n\tIOMMU_START_STATE = 0,\n\tIOMMU_IVRS_DETECTED = 1,\n\tIOMMU_ACPI_FINISHED = 2,\n\tIOMMU_ENABLED = 3,\n\tIOMMU_PCI_INIT = 4,\n\tIOMMU_INTERRUPTS_EN = 5,\n\tIOMMU_INITIALIZED = 6,\n\tIOMMU_NOT_FOUND = 7,\n\tIOMMU_INIT_ERROR = 8,\n\tIOMMU_CMDLINE_DISABLED = 9,\n};\n\nunion intcapxt {\n\tu64 capxt;\n\tstruct {\n\t\tu64 reserved_0: 2;\n\t\tu64 dest_mode_logical: 1;\n\t\tu64 reserved_1: 5;\n\t\tu64 destid_0_23: 24;\n\t\tu64 vector: 8;\n\t\tu64 reserved_2: 16;\n\t\tu64 destid_24_31: 8;\n\t};\n};\n\nstruct ivrs_quirk_entry {\n\tu8 id;\n\tu16 devid;\n};\n\nenum {\n\tDELL_INSPIRON_7375 = 0,\n\tDELL_LATITUDE_5495 = 1,\n\tLENOVO_IDEAPAD_330S_15ARR = 2,\n};\n\nstruct io_pgtable_init_fns {\n\tstruct io_pgtable * (*alloc)(struct io_pgtable_cfg *, void *);\n\tvoid (*free)(struct io_pgtable *);\n};\n\ntypedef int (*amd_iommu_invalid_ppr_cb)(struct pci_dev *, u32, long unsigned int, u16);\n\ntypedef void (*amd_iommu_invalidate_ctx)(struct pci_dev *, u32);\n\nstruct pri_queue {\n\tatomic_t inflight;\n\tbool finish;\n\tint status;\n};\n\nstruct device_state;\n\nstruct pasid_state {\n\tstruct list_head list;\n\tatomic_t count;\n\tunsigned int mmu_notifier_count;\n\tstruct mm_struct *mm;\n\tstruct mmu_notifier mn;\n\tstruct pri_queue pri[512];\n\tstruct device_state *device_state;\n\tu32 pasid;\n\tbool invalid;\n\tspinlock_t lock;\n\twait_queue_head_t wq;\n};\n\nstruct device_state {\n\tstruct list_head list;\n\tu16 devid;\n\tatomic_t count;\n\tstruct pci_dev *pdev;\n\tstruct pasid_state **states;\n\tstruct iommu_domain *domain;\n\tint pasid_levels;\n\tint max_pasids;\n\tamd_iommu_invalid_ppr_cb inv_ppr_cb;\n\tamd_iommu_invalidate_ctx inv_ctx_cb;\n\tspinlock_t lock;\n\twait_queue_head_t wq;\n};\n\nstruct fault {\n\tstruct work_struct work;\n\tstruct device_state *dev_state;\n\tstruct pasid_state *state;\n\tstruct mm_struct *mm;\n\tu64 address;\n\tu16 devid;\n\tu32 pasid;\n\tu16 tag;\n\tu16 finish;\n\tu16 flags;\n};\n\nstruct acpi_table_dmar {\n\tstruct acpi_table_header header;\n\tu8 width;\n\tu8 flags;\n\tu8 reserved[10];\n};\n\nstruct acpi_dmar_header {\n\tu16 type;\n\tu16 length;\n};\n\nenum acpi_dmar_type {\n\tACPI_DMAR_TYPE_HARDWARE_UNIT = 0,\n\tACPI_DMAR_TYPE_RESERVED_MEMORY = 1,\n\tACPI_DMAR_TYPE_ROOT_ATS = 2,\n\tACPI_DMAR_TYPE_HARDWARE_AFFINITY = 3,\n\tACPI_DMAR_TYPE_NAMESPACE = 4,\n\tACPI_DMAR_TYPE_SATC = 5,\n\tACPI_DMAR_TYPE_RESERVED = 6,\n};\n\nstruct acpi_dmar_device_scope {\n\tu8 entry_type;\n\tu8 length;\n\tu16 reserved;\n\tu8 enumeration_id;\n\tu8 bus;\n};\n\nenum acpi_dmar_scope_type {\n\tACPI_DMAR_SCOPE_TYPE_NOT_USED = 0,\n\tACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1,\n\tACPI_DMAR_SCOPE_TYPE_BRIDGE = 2,\n\tACPI_DMAR_SCOPE_TYPE_IOAPIC = 3,\n\tACPI_DMAR_SCOPE_TYPE_HPET = 4,\n\tACPI_DMAR_SCOPE_TYPE_NAMESPACE = 5,\n\tACPI_DMAR_SCOPE_TYPE_RESERVED = 6,\n};\n\nstruct acpi_dmar_pci_path {\n\tu8 device;\n\tu8 function;\n};\n\nstruct acpi_dmar_hardware_unit {\n\tstruct acpi_dmar_header header;\n\tu8 flags;\n\tu8 reserved;\n\tu16 segment;\n\tu64 address;\n};\n\nstruct acpi_dmar_reserved_memory {\n\tstruct acpi_dmar_header header;\n\tu16 reserved;\n\tu16 segment;\n\tu64 base_address;\n\tu64 end_address;\n};\n\nstruct acpi_dmar_atsr {\n\tstruct acpi_dmar_header header;\n\tu8 flags;\n\tu8 reserved;\n\tu16 segment;\n};\n\nstruct acpi_dmar_rhsa {\n\tstruct acpi_dmar_header header;\n\tu32 reserved;\n\tu64 base_address;\n\tu32 proximity_domain;\n} __attribute__((packed));\n\nstruct acpi_dmar_andd {\n\tstruct acpi_dmar_header header;\n\tu8 reserved[3];\n\tu8 device_number;\n\tchar device_name[1];\n} __attribute__((packed));\n\nstruct acpi_dmar_satc {\n\tstruct acpi_dmar_header header;\n\tu8 flags;\n\tu8 reserved;\n\tu16 segment;\n};\n\nstruct dmar_dev_scope {\n\tstruct device *dev;\n\tu8 bus;\n\tu8 devfn;\n};\n\nstruct intel_iommu;\n\nstruct dmar_drhd_unit {\n\tstruct list_head list;\n\tstruct acpi_dmar_header *hdr;\n\tu64 reg_base_addr;\n\tstruct dmar_dev_scope *devices;\n\tint devices_cnt;\n\tu16 segment;\n\tu8 ignored: 1;\n\tu8 include_all: 1;\n\tu8 gfx_dedicated: 1;\n\tstruct intel_iommu *iommu;\n};\n\nstruct iommu_flush {\n\tvoid (*flush_context)(struct intel_iommu *, u16, u16, u8, u64);\n\tvoid (*flush_iotlb)(struct intel_iommu *, u16, u64, unsigned int, u64);\n};\n\ntypedef unsigned int ioasid_t;\n\ntypedef ioasid_t (*ioasid_alloc_fn_t)(ioasid_t, ioasid_t, void *);\n\ntypedef void (*ioasid_free_fn_t)(ioasid_t, void *);\n\nstruct ioasid_allocator_ops {\n\tioasid_alloc_fn_t alloc;\n\tioasid_free_fn_t free;\n\tstruct list_head list;\n\tvoid *pdata;\n};\n\nstruct iopf_queue;\n\nstruct dmar_domain;\n\nstruct root_entry;\n\nstruct page_req_dsc;\n\nstruct q_inval;\n\nstruct ir_table;\n\nstruct intel_iommu {\n\tvoid *reg;\n\tu64 reg_phys;\n\tu64 reg_size;\n\tu64 cap;\n\tu64 ecap;\n\tu64 vccap;\n\tu32 gcmd;\n\traw_spinlock_t register_lock;\n\tint seq_id;\n\tint agaw;\n\tint msagaw;\n\tunsigned int irq;\n\tunsigned int pr_irq;\n\tu16 segment;\n\tunsigned char name[13];\n\tlong unsigned int *domain_ids;\n\tstruct dmar_domain ***domains;\n\tspinlock_t lock;\n\tstruct root_entry *root_entry;\n\tstruct iommu_flush flush;\n\tstruct page_req_dsc *prq;\n\tunsigned char prq_name[16];\n\tstruct completion prq_complete;\n\tstruct ioasid_allocator_ops pasid_allocator;\n\tstruct iopf_queue *iopf_queue;\n\tunsigned char iopfq_name[16];\n\tstruct q_inval *qi;\n\tu32 *iommu_state;\n\tstruct ir_table *ir_table;\n\tstruct irq_domain *ir_domain;\n\tstruct irq_domain *ir_msi_domain;\n\tstruct iommu_device iommu;\n\tint node;\n\tu32 flags;\n\tstruct dmar_drhd_unit *drhd;\n\tvoid *perf_statistic;\n};\n\nstruct dmar_pci_path {\n\tu8 bus;\n\tu8 device;\n\tu8 function;\n};\n\nstruct dmar_pci_notify_info {\n\tstruct pci_dev *dev;\n\tlong unsigned int event;\n\tint bus;\n\tu16 seg;\n\tu16 level;\n\tstruct dmar_pci_path path[0];\n};\n\nstruct irte___2 {\n\tunion {\n\t\tstruct {\n\t\t\t__u64 present: 1;\n\t\t\t__u64 fpd: 1;\n\t\t\t__u64 __res0: 6;\n\t\t\t__u64 avail: 4;\n\t\t\t__u64 __res1: 3;\n\t\t\t__u64 pst: 1;\n\t\t\t__u64 vector: 8;\n\t\t\t__u64 __res2: 40;\n\t\t};\n\t\tstruct {\n\t\t\t__u64 r_present: 1;\n\t\t\t__u64 r_fpd: 1;\n\t\t\t__u64 dst_mode: 1;\n\t\t\t__u64 redir_hint: 1;\n\t\t\t__u64 trigger_mode: 1;\n\t\t\t__u64 dlvry_mode: 3;\n\t\t\t__u64 r_avail: 4;\n\t\t\t__u64 r_res0: 4;\n\t\t\t__u64 r_vector: 8;\n\t\t\t__u64 r_res1: 8;\n\t\t\t__u64 dest_id: 32;\n\t\t};\n\t\tstruct {\n\t\t\t__u64 p_present: 1;\n\t\t\t__u64 p_fpd: 1;\n\t\t\t__u64 p_res0: 6;\n\t\t\t__u64 p_avail: 4;\n\t\t\t__u64 p_res1: 2;\n\t\t\t__u64 p_urgent: 1;\n\t\t\t__u64 p_pst: 1;\n\t\t\t__u64 p_vector: 8;\n\t\t\t__u64 p_res2: 14;\n\t\t\t__u64 pda_l: 26;\n\t\t};\n\t\t__u64 low;\n\t};\n\tunion {\n\t\tstruct {\n\t\t\t__u64 sid: 16;\n\t\t\t__u64 sq: 2;\n\t\t\t__u64 svt: 2;\n\t\t\t__u64 __res3: 44;\n\t\t};\n\t\tstruct {\n\t\t\t__u64 p_sid: 16;\n\t\t\t__u64 p_sq: 2;\n\t\t\t__u64 p_svt: 2;\n\t\t\t__u64 p_res3: 12;\n\t\t\t__u64 pda_h: 32;\n\t\t};\n\t\t__u64 high;\n\t};\n};\n\nstruct iova {\n\tstruct rb_node node;\n\tlong unsigned int pfn_hi;\n\tlong unsigned int pfn_lo;\n};\n\nstruct iova_magazine;\n\nstruct iova_cpu_rcache;\n\nstruct iova_rcache {\n\tspinlock_t lock;\n\tlong unsigned int depot_size;\n\tstruct iova_magazine *depot[32];\n\tstruct iova_cpu_rcache *cpu_rcaches;\n};\n\nstruct iova_domain;\n\ntypedef void (*iova_flush_cb)(struct iova_domain *);\n\ntypedef void (*iova_entry_dtor)(long unsigned int);\n\nstruct iova_fq;\n\nstruct iova_domain {\n\tspinlock_t iova_rbtree_lock;\n\tstruct rb_root rbroot;\n\tstruct rb_node *cached_node;\n\tstruct rb_node *cached32_node;\n\tlong unsigned int granule;\n\tlong unsigned int start_pfn;\n\tlong unsigned int dma_32bit_pfn;\n\tlong unsigned int max32_alloc_size;\n\tstruct iova_fq *fq;\n\tatomic64_t fq_flush_start_cnt;\n\tatomic64_t fq_flush_finish_cnt;\n\tstruct iova anchor;\n\tstruct iova_rcache rcaches[6];\n\tiova_flush_cb flush_cb;\n\tiova_entry_dtor entry_dtor;\n\tstruct timer_list fq_timer;\n\tatomic_t fq_timer_on;\n\tstruct hlist_node cpuhp_dead;\n};\n\nstruct iova_fq_entry {\n\tlong unsigned int iova_pfn;\n\tlong unsigned int pages;\n\tlong unsigned int data;\n\tu64 counter;\n};\n\nstruct iova_fq {\n\tstruct iova_fq_entry entries[256];\n\tunsigned int head;\n\tunsigned int tail;\n\tspinlock_t lock;\n};\n\nenum {\n\tQI_FREE = 0,\n\tQI_IN_USE = 1,\n\tQI_DONE = 2,\n\tQI_ABORT = 3,\n};\n\nstruct qi_desc {\n\tu64 qw0;\n\tu64 qw1;\n\tu64 qw2;\n\tu64 qw3;\n};\n\nstruct q_inval {\n\traw_spinlock_t q_lock;\n\tvoid *desc;\n\tint *desc_status;\n\tint free_head;\n\tint free_tail;\n\tint free_cnt;\n};\n\nstruct ir_table {\n\tstruct irte___2 *base;\n\tlong unsigned int *bitmap;\n};\n\nstruct root_entry {\n\tu64 lo;\n\tu64 hi;\n};\n\nstruct dma_pte;\n\nstruct dmar_domain {\n\tint nid;\n\tunsigned int iommu_refcnt[128];\n\tu16 iommu_did[128];\n\tu8 has_iotlb_device: 1;\n\tu8 iommu_coherency: 1;\n\tu8 iommu_snooping: 1;\n\tstruct list_head devices;\n\tstruct list_head subdevices;\n\tstruct iova_domain iovad;\n\tstruct dma_pte *pgd;\n\tint gaw;\n\tint agaw;\n\tint flags;\n\tint iommu_superpage;\n\tu64 max_addr;\n\tu32 default_pasid;\n\tstruct iommu_domain domain;\n};\n\nstruct dma_pte {\n\tu64 val;\n};\n\nenum latency_type {\n\tDMAR_LATENCY_INV_IOTLB = 0,\n\tDMAR_LATENCY_INV_DEVTLB = 1,\n\tDMAR_LATENCY_INV_IEC = 2,\n\tDMAR_LATENCY_PRQ = 3,\n\tDMAR_LATENCY_NUM = 4,\n};\n\nenum latency_count {\n\tCOUNTS_10e2 = 0,\n\tCOUNTS_10e3 = 1,\n\tCOUNTS_10e4 = 2,\n\tCOUNTS_10e5 = 3,\n\tCOUNTS_10e6 = 4,\n\tCOUNTS_10e7 = 5,\n\tCOUNTS_10e8_plus = 6,\n\tCOUNTS_MIN = 7,\n\tCOUNTS_MAX = 8,\n\tCOUNTS_SUM = 9,\n\tCOUNTS_NUM = 10,\n};\n\ntypedef int (*dmar_res_handler_t)(struct acpi_dmar_header *, void *);\n\nstruct dmar_res_callback {\n\tdmar_res_handler_t cb[6];\n\tvoid *arg[6];\n\tbool ignore_unhandled;\n\tbool print_entry;\n};\n\nenum faulttype {\n\tDMA_REMAP = 0,\n\tINTR_REMAP = 1,\n\tUNKNOWN = 2,\n};\n\nstruct ioasid_set {\n\tint dummy;\n};\n\nenum iommu_inv_granularity {\n\tIOMMU_INV_GRANU_DOMAIN = 0,\n\tIOMMU_INV_GRANU_PASID = 1,\n\tIOMMU_INV_GRANU_ADDR = 2,\n\tIOMMU_INV_GRANU_NR = 3,\n};\n\nenum {\n\tSR_DMAR_FECTL_REG = 0,\n\tSR_DMAR_FEDATA_REG = 1,\n\tSR_DMAR_FEADDR_REG = 2,\n\tSR_DMAR_FEUADDR_REG = 3,\n\tMAX_SR_DMAR_REGS = 4,\n};\n\nstruct context_entry {\n\tu64 lo;\n\tu64 hi;\n};\n\nstruct subdev_domain_info {\n\tstruct list_head link_phys;\n\tstruct list_head link_domain;\n\tstruct device *pdev;\n\tstruct dmar_domain *domain;\n\tint users;\n};\n\nstruct pasid_table;\n\nstruct device_domain_info {\n\tstruct list_head link;\n\tstruct list_head global;\n\tstruct list_head table;\n\tstruct list_head subdevices;\n\tu32 segment;\n\tu8 bus;\n\tu8 devfn;\n\tu16 pfsid;\n\tu8 pasid_supported: 3;\n\tu8 pasid_enabled: 1;\n\tu8 pri_supported: 1;\n\tu8 pri_enabled: 1;\n\tu8 ats_supported: 1;\n\tu8 ats_enabled: 1;\n\tu8 auxd_enabled: 1;\n\tu8 ats_qdep;\n\tstruct device *dev;\n\tstruct intel_iommu *iommu;\n\tstruct dmar_domain *domain;\n\tstruct pasid_table *pasid_table;\n};\n\nstruct pasid_table {\n\tvoid *table;\n\tint order;\n\tu32 max_pasid;\n\tstruct list_head dev;\n};\n\nenum cap_audit_type {\n\tCAP_AUDIT_STATIC_DMAR = 0,\n\tCAP_AUDIT_STATIC_IRQR = 1,\n\tCAP_AUDIT_HOTPLUG_DMAR = 2,\n\tCAP_AUDIT_HOTPLUG_IRQR = 3,\n};\n\nstruct dmar_rmrr_unit {\n\tstruct list_head list;\n\tstruct acpi_dmar_header *hdr;\n\tu64 base_address;\n\tu64 end_address;\n\tstruct dmar_dev_scope *devices;\n\tint devices_cnt;\n};\n\nstruct dmar_atsr_unit {\n\tstruct list_head list;\n\tstruct acpi_dmar_header *hdr;\n\tstruct dmar_dev_scope *devices;\n\tint devices_cnt;\n\tu8 include_all: 1;\n};\n\nstruct dmar_satc_unit {\n\tstruct list_head list;\n\tstruct acpi_dmar_header *hdr;\n\tstruct dmar_dev_scope *devices;\n\tstruct intel_iommu *iommu;\n\tint devices_cnt;\n\tu8 atc_required: 1;\n};\n\nstruct domain_context_mapping_data {\n\tstruct dmar_domain *domain;\n\tstruct intel_iommu *iommu;\n\tstruct pasid_table *table;\n};\n\nstruct pasid_dir_entry {\n\tu64 val;\n};\n\nstruct pasid_entry {\n\tu64 val[8];\n};\n\nstruct pasid_table_opaque {\n\tstruct pasid_table **pasid_table;\n\tint segment;\n\tint bus;\n\tint devfn;\n};\n\nstruct trace_event_raw_qi_submit {\n\tstruct trace_entry ent;\n\tu64 qw0;\n\tu64 qw1;\n\tu64 qw2;\n\tu64 qw3;\n\tu32 __data_loc_iommu;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_prq_report {\n\tstruct trace_entry ent;\n\tu64 dw0;\n\tu64 dw1;\n\tu64 dw2;\n\tu64 dw3;\n\tlong unsigned int seq;\n\tu32 __data_loc_iommu;\n\tu32 __data_loc_dev;\n\tu32 __data_loc_buff;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_qi_submit {\n\tu32 iommu;\n};\n\nstruct trace_event_data_offsets_prq_report {\n\tu32 iommu;\n\tu32 dev;\n\tu32 buff;\n};\n\ntypedef void (*btf_trace_qi_submit)(void *, struct intel_iommu *, u64, u64, u64, u64);\n\ntypedef void (*btf_trace_prq_report)(void *, struct intel_iommu *, struct device *, u64, u64, u64, u64, long unsigned int);\n\nenum iommu_fault_type {\n\tIOMMU_FAULT_DMA_UNRECOV = 1,\n\tIOMMU_FAULT_PAGE_REQ = 2,\n};\n\nstruct page_req_dsc {\n\tunion {\n\t\tstruct {\n\t\t\tu64 type: 8;\n\t\t\tu64 pasid_present: 1;\n\t\t\tu64 priv_data_present: 1;\n\t\t\tu64 rsvd: 6;\n\t\t\tu64 rid: 16;\n\t\t\tu64 pasid: 20;\n\t\t\tu64 exe_req: 1;\n\t\t\tu64 pm_req: 1;\n\t\t\tu64 rsvd2: 10;\n\t\t};\n\t\tu64 qw_0;\n\t};\n\tunion {\n\t\tstruct {\n\t\t\tu64 rd_req: 1;\n\t\t\tu64 wr_req: 1;\n\t\t\tu64 lpig: 1;\n\t\t\tu64 prg_index: 9;\n\t\t\tu64 addr: 52;\n\t\t};\n\t\tu64 qw_1;\n\t};\n\tu64 priv_data[2];\n};\n\nstruct intel_svm_dev {\n\tstruct list_head list;\n\tstruct callback_head rcu;\n\tstruct device *dev;\n\tstruct intel_iommu *iommu;\n\tstruct iommu_sva sva;\n\tlong unsigned int prq_seq_number;\n\tu32 pasid;\n\tint users;\n\tu16 did;\n\tu16 dev_iotlb: 1;\n\tu16 sid;\n\tu16 qdep;\n};\n\nstruct intel_svm {\n\tstruct mmu_notifier notifier;\n\tstruct mm_struct *mm;\n\tunsigned int flags;\n\tu32 pasid;\n\tint gpasid;\n\tstruct list_head devs;\n};\n\nenum irq_mode {\n\tIRQ_REMAPPING = 0,\n\tIRQ_POSTING = 1,\n};\n\nstruct ioapic_scope {\n\tstruct intel_iommu *iommu;\n\tunsigned int id;\n\tunsigned int bus;\n\tunsigned int devfn;\n};\n\nstruct hpet_scope {\n\tstruct intel_iommu *iommu;\n\tu8 id;\n\tunsigned int bus;\n\tunsigned int devfn;\n};\n\nstruct irq_2_iommu {\n\tstruct intel_iommu *iommu;\n\tu16 irte_index;\n\tu16 sub_handle;\n\tu8 irte_mask;\n\tenum irq_mode mode;\n};\n\nstruct intel_ir_data {\n\tstruct irq_2_iommu irq_2_iommu;\n\tstruct irte___2 irte_entry;\n\tunion {\n\t\tstruct msi_msg msi_entry;\n\t};\n};\n\nstruct set_msi_sid_data {\n\tstruct pci_dev *pdev;\n\tu16 alias;\n\tint count;\n\tint busmatch_count;\n};\n\nstruct iommu_group {\n\tstruct kobject kobj;\n\tstruct kobject *devices_kobj;\n\tstruct list_head devices;\n\tstruct mutex mutex;\n\tstruct blocking_notifier_head notifier;\n\tvoid *iommu_data;\n\tvoid (*iommu_data_release)(void *);\n\tchar *name;\n\tint id;\n\tstruct iommu_domain *default_domain;\n\tstruct iommu_domain *domain;\n\tstruct list_head entry;\n};\n\nstruct fsl_mc_obj_desc {\n\tchar type[16];\n\tint id;\n\tu16 vendor;\n\tu16 ver_major;\n\tu16 ver_minor;\n\tu8 irq_count;\n\tu8 region_count;\n\tu32 state;\n\tchar label[16];\n\tu16 flags;\n};\n\nstruct fsl_mc_io;\n\nstruct fsl_mc_device_irq;\n\nstruct fsl_mc_resource;\n\nstruct fsl_mc_device {\n\tstruct device dev;\n\tu64 dma_mask;\n\tu16 flags;\n\tu32 icid;\n\tu16 mc_handle;\n\tstruct fsl_mc_io *mc_io;\n\tstruct fsl_mc_obj_desc obj_desc;\n\tstruct resource *regions;\n\tstruct fsl_mc_device_irq **irqs;\n\tstruct fsl_mc_resource *resource;\n\tstruct device_link *consumer_link;\n\tchar *driver_override;\n};\n\nenum fsl_mc_pool_type {\n\tFSL_MC_POOL_DPMCP = 0,\n\tFSL_MC_POOL_DPBP = 1,\n\tFSL_MC_POOL_DPCON = 2,\n\tFSL_MC_POOL_IRQ = 3,\n\tFSL_MC_NUM_POOL_TYPES = 4,\n};\n\nstruct fsl_mc_resource_pool;\n\nstruct fsl_mc_resource {\n\tenum fsl_mc_pool_type type;\n\ts32 id;\n\tvoid *data;\n\tstruct fsl_mc_resource_pool *parent_pool;\n\tstruct list_head node;\n};\n\nstruct fsl_mc_device_irq {\n\tstruct msi_desc *msi_desc;\n\tstruct fsl_mc_device *mc_dev;\n\tu8 dev_irq_index;\n\tstruct fsl_mc_resource resource;\n};\n\nstruct fsl_mc_io {\n\tstruct device *dev;\n\tu16 flags;\n\tu32 portal_size;\n\tphys_addr_t portal_phys_addr;\n\tvoid *portal_virt_addr;\n\tstruct fsl_mc_device *dpmcp_dev;\n\tunion {\n\t\tstruct mutex mutex;\n\t\traw_spinlock_t spinlock;\n\t};\n};\n\nstruct group_device {\n\tstruct list_head list;\n\tstruct device *dev;\n\tchar *name;\n};\n\nstruct iommu_group_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct iommu_group *, char *);\n\tssize_t (*store)(struct iommu_group *, const char *, size_t);\n};\n\nstruct group_for_pci_data {\n\tstruct pci_dev *pdev;\n\tstruct iommu_group *group;\n};\n\nstruct __group_domain_type {\n\tstruct device *dev;\n\tunsigned int type;\n};\n\nstruct trace_event_raw_iommu_group_event {\n\tstruct trace_entry ent;\n\tint gid;\n\tu32 __data_loc_device;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iommu_device_event {\n\tstruct trace_entry ent;\n\tu32 __data_loc_device;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_map {\n\tstruct trace_entry ent;\n\tu64 iova;\n\tu64 paddr;\n\tsize_t size;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_unmap {\n\tstruct trace_entry ent;\n\tu64 iova;\n\tsize_t size;\n\tsize_t unmapped_size;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_iommu_error {\n\tstruct trace_entry ent;\n\tu32 __data_loc_device;\n\tu32 __data_loc_driver;\n\tu64 iova;\n\tint flags;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_iommu_group_event {\n\tu32 device;\n};\n\nstruct trace_event_data_offsets_iommu_device_event {\n\tu32 device;\n};\n\nstruct trace_event_data_offsets_map {};\n\nstruct trace_event_data_offsets_unmap {};\n\nstruct trace_event_data_offsets_iommu_error {\n\tu32 device;\n\tu32 driver;\n};\n\ntypedef void (*btf_trace_add_device_to_group)(void *, int, struct device *);\n\ntypedef void (*btf_trace_remove_device_from_group)(void *, int, struct device *);\n\ntypedef void (*btf_trace_attach_device_to_domain)(void *, struct device *);\n\ntypedef void (*btf_trace_detach_device_from_domain)(void *, struct device *);\n\ntypedef void (*btf_trace_map)(void *, long unsigned int, phys_addr_t, size_t);\n\ntypedef void (*btf_trace_unmap)(void *, long unsigned int, size_t, size_t);\n\ntypedef void (*btf_trace_io_page_fault)(void *, struct device *, long unsigned int, int);\n\nstruct iommu_dma_msi_page {\n\tstruct list_head list;\n\tdma_addr_t iova;\n\tphys_addr_t phys;\n};\n\nenum iommu_dma_cookie_type {\n\tIOMMU_DMA_IOVA_COOKIE = 0,\n\tIOMMU_DMA_MSI_COOKIE = 1,\n};\n\nstruct iommu_dma_cookie {\n\tenum iommu_dma_cookie_type type;\n\tunion {\n\t\tstruct iova_domain iovad;\n\t\tdma_addr_t msi_iova;\n\t};\n\tstruct list_head msi_page_list;\n\tstruct iommu_domain *fq_domain;\n};\n\nstruct ioasid_data {\n\tioasid_t id;\n\tstruct ioasid_set *set;\n\tvoid *private;\n\tstruct callback_head rcu;\n\trefcount_t refs;\n};\n\nstruct ioasid_allocator_data {\n\tstruct ioasid_allocator_ops *ops;\n\tstruct list_head list;\n\tstruct list_head slist;\n\tlong unsigned int flags;\n\tstruct xarray xa;\n\tstruct callback_head rcu;\n};\n\nstruct iova_magazine {\n\tlong unsigned int size;\n\tlong unsigned int pfns[128];\n};\n\nstruct iova_cpu_rcache {\n\tspinlock_t lock;\n\tstruct iova_magazine *loaded;\n\tstruct iova_magazine *prev;\n};\n\nstruct hyperv_root_ir_data {\n\tu8 ioapic_id;\n\tbool is_level;\n\tstruct hv_interrupt_entry entry;\n} __attribute__((packed));\n\nenum iommu_page_response_code {\n\tIOMMU_PAGE_RESP_SUCCESS = 0,\n\tIOMMU_PAGE_RESP_INVALID = 1,\n\tIOMMU_PAGE_RESP_FAILURE = 2,\n};\n\nstruct iopf_queue___2;\n\nstruct iopf_device_param {\n\tstruct device *dev;\n\tstruct iopf_queue___2 *queue;\n\tstruct list_head queue_list;\n\tstruct list_head partial;\n};\n\nstruct iopf_queue___2 {\n\tstruct workqueue_struct *wq;\n\tstruct list_head devices;\n\tstruct mutex lock;\n};\n\nstruct iopf_fault {\n\tstruct iommu_fault fault;\n\tstruct list_head list;\n};\n\nstruct iopf_group {\n\tstruct iopf_fault last_fault;\n\tstruct list_head faults;\n\tstruct work_struct work;\n\tstruct device *dev;\n};\n\nstruct mipi_dsi_msg {\n\tu8 channel;\n\tu8 type;\n\tu16 flags;\n\tsize_t tx_len;\n\tconst void *tx_buf;\n\tsize_t rx_len;\n\tvoid *rx_buf;\n};\n\nstruct mipi_dsi_packet {\n\tsize_t size;\n\tu8 header[4];\n\tsize_t payload_length;\n\tconst u8 *payload;\n};\n\nstruct mipi_dsi_host;\n\nstruct mipi_dsi_device;\n\nstruct mipi_dsi_host_ops {\n\tint (*attach)(struct mipi_dsi_host *, struct mipi_dsi_device *);\n\tint (*detach)(struct mipi_dsi_host *, struct mipi_dsi_device *);\n\tssize_t (*transfer)(struct mipi_dsi_host *, const struct mipi_dsi_msg *);\n};\n\nstruct mipi_dsi_host {\n\tstruct device *dev;\n\tconst struct mipi_dsi_host_ops *ops;\n\tstruct list_head list;\n};\n\nenum mipi_dsi_pixel_format {\n\tMIPI_DSI_FMT_RGB888 = 0,\n\tMIPI_DSI_FMT_RGB666 = 1,\n\tMIPI_DSI_FMT_RGB666_PACKED = 2,\n\tMIPI_DSI_FMT_RGB565 = 3,\n};\n\nstruct mipi_dsi_device {\n\tstruct mipi_dsi_host *host;\n\tstruct device dev;\n\tchar name[20];\n\tunsigned int channel;\n\tunsigned int lanes;\n\tenum mipi_dsi_pixel_format format;\n\tlong unsigned int mode_flags;\n\tlong unsigned int hs_rate;\n\tlong unsigned int lp_rate;\n};\n\nstruct mipi_dsi_device_info {\n\tchar type[20];\n\tu32 channel;\n\tstruct device_node *node;\n};\n\nenum mipi_dsi_dcs_tear_mode {\n\tMIPI_DSI_DCS_TEAR_MODE_VBLANK = 0,\n\tMIPI_DSI_DCS_TEAR_MODE_VHBLANK = 1,\n};\n\nstruct mipi_dsi_driver {\n\tstruct device_driver driver;\n\tint (*probe)(struct mipi_dsi_device *);\n\tint (*remove)(struct mipi_dsi_device *);\n\tvoid (*shutdown)(struct mipi_dsi_device *);\n};\n\nstruct drm_dsc_picture_parameter_set {\n\tu8 dsc_version;\n\tu8 pps_identifier;\n\tu8 pps_reserved;\n\tu8 pps_3;\n\tu8 pps_4;\n\tu8 bits_per_pixel_low;\n\t__be16 pic_height;\n\t__be16 pic_width;\n\t__be16 slice_height;\n\t__be16 slice_width;\n\t__be16 chunk_size;\n\tu8 initial_xmit_delay_high;\n\tu8 initial_xmit_delay_low;\n\t__be16 initial_dec_delay;\n\tu8 pps20_reserved;\n\tu8 initial_scale_value;\n\t__be16 scale_increment_interval;\n\tu8 scale_decrement_interval_high;\n\tu8 scale_decrement_interval_low;\n\tu8 pps26_reserved;\n\tu8 first_line_bpg_offset;\n\t__be16 nfl_bpg_offset;\n\t__be16 slice_bpg_offset;\n\t__be16 initial_offset;\n\t__be16 final_offset;\n\tu8 flatness_min_qp;\n\tu8 flatness_max_qp;\n\t__be16 rc_model_size;\n\tu8 rc_edge_factor;\n\tu8 rc_quant_incr_limit0;\n\tu8 rc_quant_incr_limit1;\n\tu8 rc_tgt_offset;\n\tu8 rc_buf_thresh[14];\n\t__be16 rc_range_parameters[15];\n\tu8 native_422_420;\n\tu8 second_line_bpg_offset;\n\t__be16 nsl_bpg_offset;\n\t__be16 second_line_offset_adj;\n\tu32 pps_long_94_reserved;\n\tu32 pps_long_98_reserved;\n\tu32 pps_long_102_reserved;\n\tu32 pps_long_106_reserved;\n\tu32 pps_long_110_reserved;\n\tu32 pps_long_114_reserved;\n\tu32 pps_long_118_reserved;\n\tu32 pps_long_122_reserved;\n\t__be16 pps_short_126_reserved;\n} __attribute__((packed));\n\nenum {\n\tMIPI_DSI_V_SYNC_START = 1,\n\tMIPI_DSI_V_SYNC_END = 17,\n\tMIPI_DSI_H_SYNC_START = 33,\n\tMIPI_DSI_H_SYNC_END = 49,\n\tMIPI_DSI_COMPRESSION_MODE = 7,\n\tMIPI_DSI_END_OF_TRANSMISSION = 8,\n\tMIPI_DSI_COLOR_MODE_OFF = 2,\n\tMIPI_DSI_COLOR_MODE_ON = 18,\n\tMIPI_DSI_SHUTDOWN_PERIPHERAL = 34,\n\tMIPI_DSI_TURN_ON_PERIPHERAL = 50,\n\tMIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 3,\n\tMIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 19,\n\tMIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 35,\n\tMIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 4,\n\tMIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 20,\n\tMIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 36,\n\tMIPI_DSI_DCS_SHORT_WRITE = 5,\n\tMIPI_DSI_DCS_SHORT_WRITE_PARAM = 21,\n\tMIPI_DSI_DCS_READ = 6,\n\tMIPI_DSI_EXECUTE_QUEUE = 22,\n\tMIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 55,\n\tMIPI_DSI_NULL_PACKET = 9,\n\tMIPI_DSI_BLANKING_PACKET = 25,\n\tMIPI_DSI_GENERIC_LONG_WRITE = 41,\n\tMIPI_DSI_DCS_LONG_WRITE = 57,\n\tMIPI_DSI_PICTURE_PARAMETER_SET = 10,\n\tMIPI_DSI_COMPRESSED_PIXEL_STREAM = 11,\n\tMIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 12,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 28,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 44,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_30 = 13,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_36 = 29,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 61,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_16 = 14,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_18 = 30,\n\tMIPI_DSI_PIXEL_STREAM_3BYTE_18 = 46,\n\tMIPI_DSI_PACKED_PIXEL_STREAM_24 = 62,\n};\n\nenum {\n\tMIPI_DCS_NOP = 0,\n\tMIPI_DCS_SOFT_RESET = 1,\n\tMIPI_DCS_GET_COMPRESSION_MODE = 3,\n\tMIPI_DCS_GET_DISPLAY_ID = 4,\n\tMIPI_DCS_GET_ERROR_COUNT_ON_DSI = 5,\n\tMIPI_DCS_GET_RED_CHANNEL = 6,\n\tMIPI_DCS_GET_GREEN_CHANNEL = 7,\n\tMIPI_DCS_GET_BLUE_CHANNEL = 8,\n\tMIPI_DCS_GET_DISPLAY_STATUS = 9,\n\tMIPI_DCS_GET_POWER_MODE = 10,\n\tMIPI_DCS_GET_ADDRESS_MODE = 11,\n\tMIPI_DCS_GET_PIXEL_FORMAT = 12,\n\tMIPI_DCS_GET_DISPLAY_MODE = 13,\n\tMIPI_DCS_GET_SIGNAL_MODE = 14,\n\tMIPI_DCS_GET_DIAGNOSTIC_RESULT = 15,\n\tMIPI_DCS_ENTER_SLEEP_MODE = 16,\n\tMIPI_DCS_EXIT_SLEEP_MODE = 17,\n\tMIPI_DCS_ENTER_PARTIAL_MODE = 18,\n\tMIPI_DCS_ENTER_NORMAL_MODE = 19,\n\tMIPI_DCS_GET_IMAGE_CHECKSUM_RGB = 20,\n\tMIPI_DCS_GET_IMAGE_CHECKSUM_CT = 21,\n\tMIPI_DCS_EXIT_INVERT_MODE = 32,\n\tMIPI_DCS_ENTER_INVERT_MODE = 33,\n\tMIPI_DCS_SET_GAMMA_CURVE = 38,\n\tMIPI_DCS_SET_DISPLAY_OFF = 40,\n\tMIPI_DCS_SET_DISPLAY_ON = 41,\n\tMIPI_DCS_SET_COLUMN_ADDRESS = 42,\n\tMIPI_DCS_SET_PAGE_ADDRESS = 43,\n\tMIPI_DCS_WRITE_MEMORY_START = 44,\n\tMIPI_DCS_WRITE_LUT = 45,\n\tMIPI_DCS_READ_MEMORY_START = 46,\n\tMIPI_DCS_SET_PARTIAL_ROWS = 48,\n\tMIPI_DCS_SET_PARTIAL_COLUMNS = 49,\n\tMIPI_DCS_SET_SCROLL_AREA = 51,\n\tMIPI_DCS_SET_TEAR_OFF = 52,\n\tMIPI_DCS_SET_TEAR_ON = 53,\n\tMIPI_DCS_SET_ADDRESS_MODE = 54,\n\tMIPI_DCS_SET_SCROLL_START = 55,\n\tMIPI_DCS_EXIT_IDLE_MODE = 56,\n\tMIPI_DCS_ENTER_IDLE_MODE = 57,\n\tMIPI_DCS_SET_PIXEL_FORMAT = 58,\n\tMIPI_DCS_WRITE_MEMORY_CONTINUE = 60,\n\tMIPI_DCS_SET_3D_CONTROL = 61,\n\tMIPI_DCS_READ_MEMORY_CONTINUE = 62,\n\tMIPI_DCS_GET_3D_CONTROL = 63,\n\tMIPI_DCS_SET_VSYNC_TIMING = 64,\n\tMIPI_DCS_SET_TEAR_SCANLINE = 68,\n\tMIPI_DCS_GET_SCANLINE = 69,\n\tMIPI_DCS_SET_DISPLAY_BRIGHTNESS = 81,\n\tMIPI_DCS_GET_DISPLAY_BRIGHTNESS = 82,\n\tMIPI_DCS_WRITE_CONTROL_DISPLAY = 83,\n\tMIPI_DCS_GET_CONTROL_DISPLAY = 84,\n\tMIPI_DCS_WRITE_POWER_SAVE = 85,\n\tMIPI_DCS_GET_POWER_SAVE = 86,\n\tMIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 94,\n\tMIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 95,\n\tMIPI_DCS_READ_DDB_START = 161,\n\tMIPI_DCS_READ_PPS_START = 162,\n\tMIPI_DCS_READ_DDB_CONTINUE = 168,\n\tMIPI_DCS_READ_PPS_CONTINUE = 169,\n};\n\nstruct drm_dmi_panel_orientation_data {\n\tint width;\n\tint height;\n\tconst char * const *bios_dates;\n\tint orientation;\n};\n\nstruct vga_device {\n\tstruct list_head list;\n\tstruct pci_dev *pdev;\n\tunsigned int decodes;\n\tunsigned int owns;\n\tunsigned int locks;\n\tunsigned int io_lock_cnt;\n\tunsigned int mem_lock_cnt;\n\tunsigned int io_norm_cnt;\n\tunsigned int mem_norm_cnt;\n\tbool bridge_has_one_vga;\n\tvoid *cookie;\n\tvoid (*irq_set_state)(void *, bool);\n\tunsigned int (*set_vga_decode)(void *, bool);\n};\n\nstruct vga_arb_user_card {\n\tstruct pci_dev *pdev;\n\tunsigned int mem_cnt;\n\tunsigned int io_cnt;\n};\n\nstruct vga_arb_private {\n\tstruct list_head list;\n\tstruct pci_dev *target;\n\tstruct vga_arb_user_card cards[10];\n\tspinlock_t lock;\n};\n\nenum vga_switcheroo_handler_flags_t {\n\tVGA_SWITCHEROO_CAN_SWITCH_DDC = 1,\n\tVGA_SWITCHEROO_NEEDS_EDP_CONFIG = 2,\n};\n\nenum vga_switcheroo_state {\n\tVGA_SWITCHEROO_OFF = 0,\n\tVGA_SWITCHEROO_ON = 1,\n\tVGA_SWITCHEROO_NOT_FOUND = 2,\n};\n\nenum vga_switcheroo_client_id {\n\tVGA_SWITCHEROO_UNKNOWN_ID = 4096,\n\tVGA_SWITCHEROO_IGD = 0,\n\tVGA_SWITCHEROO_DIS = 1,\n\tVGA_SWITCHEROO_MAX_CLIENTS = 2,\n};\n\nstruct vga_switcheroo_handler {\n\tint (*init)();\n\tint (*switchto)(enum vga_switcheroo_client_id);\n\tint (*switch_ddc)(enum vga_switcheroo_client_id);\n\tint (*power_state)(enum vga_switcheroo_client_id, enum vga_switcheroo_state);\n\tenum vga_switcheroo_client_id (*get_client_id)(struct pci_dev *);\n};\n\nstruct vga_switcheroo_client_ops {\n\tvoid (*set_gpu_state)(struct pci_dev *, enum vga_switcheroo_state);\n\tvoid (*reprobe)(struct pci_dev *);\n\tbool (*can_switch)(struct pci_dev *);\n\tvoid (*gpu_bound)(struct pci_dev *, enum vga_switcheroo_client_id);\n};\n\nstruct vga_switcheroo_client {\n\tstruct pci_dev *pdev;\n\tstruct fb_info *fb_info;\n\tenum vga_switcheroo_state pwr_state;\n\tconst struct vga_switcheroo_client_ops *ops;\n\tenum vga_switcheroo_client_id id;\n\tbool active;\n\tbool driver_power_control;\n\tstruct list_head list;\n\tstruct pci_dev *vga_dev;\n};\n\nstruct vgasr_priv {\n\tbool active;\n\tbool delayed_switch_active;\n\tenum vga_switcheroo_client_id delayed_client_id;\n\tstruct dentry *debugfs_root;\n\tint registered_clients;\n\tstruct list_head clients;\n\tconst struct vga_switcheroo_handler *handler;\n\tenum vga_switcheroo_handler_flags_t handler_flags;\n\tstruct mutex mux_hw_lock;\n\tint old_ddc_owner;\n};\n\nstruct cb_id {\n\t__u32 idx;\n\t__u32 val;\n};\n\nstruct cn_msg {\n\tstruct cb_id id;\n\t__u32 seq;\n\t__u32 ack;\n\t__u16 len;\n\t__u16 flags;\n\t__u8 data[0];\n};\n\nstruct cn_queue_dev {\n\tatomic_t refcnt;\n\tunsigned char name[32];\n\tstruct list_head queue_list;\n\tspinlock_t queue_lock;\n\tstruct sock *nls;\n};\n\nstruct cn_callback_id {\n\tunsigned char name[32];\n\tstruct cb_id id;\n};\n\nstruct cn_callback_entry {\n\tstruct list_head callback_entry;\n\trefcount_t refcnt;\n\tstruct cn_queue_dev *pdev;\n\tstruct cn_callback_id id;\n\tvoid (*callback)(struct cn_msg *, struct netlink_skb_parms *);\n\tu32 seq;\n\tu32 group;\n};\n\nstruct cn_dev {\n\tstruct cb_id id;\n\tu32 seq;\n\tu32 groups;\n\tstruct sock *nls;\n\tstruct cn_queue_dev *cbdev;\n};\n\nenum proc_cn_mcast_op {\n\tPROC_CN_MCAST_LISTEN = 1,\n\tPROC_CN_MCAST_IGNORE = 2,\n};\n\nstruct fork_proc_event {\n\t__kernel_pid_t parent_pid;\n\t__kernel_pid_t parent_tgid;\n\t__kernel_pid_t child_pid;\n\t__kernel_pid_t child_tgid;\n};\n\nstruct exec_proc_event {\n\t__kernel_pid_t process_pid;\n\t__kernel_pid_t process_tgid;\n};\n\nstruct id_proc_event {\n\t__kernel_pid_t process_pid;\n\t__kernel_pid_t process_tgid;\n\tunion {\n\t\t__u32 ruid;\n\t\t__u32 rgid;\n\t} r;\n\tunion {\n\t\t__u32 euid;\n\t\t__u32 egid;\n\t} e;\n};\n\nstruct sid_proc_event {\n\t__kernel_pid_t process_pid;\n\t__kernel_pid_t process_tgid;\n};\n\nstruct ptrace_proc_event {\n\t__kernel_pid_t process_pid;\n\t__kernel_pid_t process_tgid;\n\t__kernel_pid_t tracer_pid;\n\t__kernel_pid_t tracer_tgid;\n};\n\nstruct comm_proc_event {\n\t__kernel_pid_t process_pid;\n\t__kernel_pid_t process_tgid;\n\tchar comm[16];\n};\n\nstruct coredump_proc_event {\n\t__kernel_pid_t process_pid;\n\t__kernel_pid_t process_tgid;\n\t__kernel_pid_t parent_pid;\n\t__kernel_pid_t parent_tgid;\n};\n\nstruct exit_proc_event {\n\t__kernel_pid_t process_pid;\n\t__kernel_pid_t process_tgid;\n\t__u32 exit_code;\n\t__u32 exit_signal;\n\t__kernel_pid_t parent_pid;\n\t__kernel_pid_t parent_tgid;\n};\n\nstruct proc_event {\n\tenum what what;\n\t__u32 cpu;\n\t__u64 timestamp_ns;\n\tunion {\n\t\tstruct {\n\t\t\t__u32 err;\n\t\t} ack;\n\t\tstruct fork_proc_event fork;\n\t\tstruct exec_proc_event exec;\n\t\tstruct id_proc_event id;\n\t\tstruct sid_proc_event sid;\n\t\tstruct ptrace_proc_event ptrace;\n\t\tstruct comm_proc_event comm;\n\t\tstruct coredump_proc_event coredump;\n\t\tstruct exit_proc_event exit;\n\t} event_data;\n};\n\nstruct local_event {\n\tlocal_lock_t lock;\n\t__u32 count;\n};\n\nstruct nvm_ioctl_info_tgt {\n\t__u32 version[3];\n\t__u32 reserved;\n\tchar tgtname[48];\n};\n\nstruct nvm_ioctl_info {\n\t__u32 version[3];\n\t__u16 tgtsize;\n\t__u16 reserved16;\n\t__u32 reserved[12];\n\tstruct nvm_ioctl_info_tgt tgts[63];\n};\n\nstruct nvm_ioctl_device_info {\n\tchar devname[32];\n\tchar bmname[48];\n\t__u32 bmversion[3];\n\t__u32 flags;\n\t__u32 reserved[8];\n};\n\nstruct nvm_ioctl_get_devices {\n\t__u32 nr_devices;\n\t__u32 reserved[31];\n\tstruct nvm_ioctl_device_info info[31];\n};\n\nstruct nvm_ioctl_create_simple {\n\t__u32 lun_begin;\n\t__u32 lun_end;\n};\n\nstruct nvm_ioctl_create_extended {\n\t__u16 lun_begin;\n\t__u16 lun_end;\n\t__u16 op;\n\t__u16 rsv;\n};\n\nenum {\n\tNVM_CONFIG_TYPE_SIMPLE = 0,\n\tNVM_CONFIG_TYPE_EXTENDED = 1,\n};\n\nstruct nvm_ioctl_create_conf {\n\t__u32 type;\n\tunion {\n\t\tstruct nvm_ioctl_create_simple s;\n\t\tstruct nvm_ioctl_create_extended e;\n\t};\n};\n\nenum {\n\tNVM_TARGET_FACTORY = 1,\n};\n\nstruct nvm_ioctl_create {\n\tchar dev[32];\n\tchar tgttype[48];\n\tchar tgtname[32];\n\t__u32 flags;\n\tstruct nvm_ioctl_create_conf conf;\n};\n\nstruct nvm_ioctl_remove {\n\tchar tgtname[32];\n\t__u32 flags;\n};\n\nstruct nvm_ioctl_dev_init {\n\tchar dev[32];\n\tchar mmtype[8];\n\t__u32 flags;\n};\n\nenum {\n\tNVM_FACTORY_ERASE_ONLY_USER = 1,\n\tNVM_FACTORY_RESET_HOST_BLKS = 2,\n\tNVM_FACTORY_RESET_GRWN_BBLKS = 4,\n\tNVM_FACTORY_NR_BITS = 8,\n};\n\nstruct nvm_ioctl_dev_factory {\n\tchar dev[32];\n\t__u32 flags;\n};\n\nenum {\n\tNVM_INFO_CMD = 32,\n\tNVM_GET_DEVICES_CMD = 33,\n\tNVM_DEV_CREATE_CMD = 34,\n\tNVM_DEV_REMOVE_CMD = 35,\n\tNVM_DEV_INIT_CMD = 36,\n\tNVM_DEV_FACTORY_CMD = 37,\n\tNVM_DEV_VIO_ADMIN_CMD = 65,\n\tNVM_DEV_VIO_CMD = 66,\n\tNVM_DEV_VIO_USER_CMD = 67,\n};\n\nenum {\n\tNVM_OCSSD_SPEC_12 = 12,\n\tNVM_OCSSD_SPEC_20 = 20,\n};\n\nstruct ppa_addr {\n\tunion {\n\t\tstruct {\n\t\t\tu64 ch: 8;\n\t\t\tu64 lun: 8;\n\t\t\tu64 blk: 16;\n\t\t\tu64 reserved: 32;\n\t\t} a;\n\t\tstruct {\n\t\t\tu64 ch: 8;\n\t\t\tu64 lun: 8;\n\t\t\tu64 blk: 16;\n\t\t\tu64 pg: 16;\n\t\t\tu64 pl: 4;\n\t\t\tu64 sec: 4;\n\t\t\tu64 reserved: 8;\n\t\t} g;\n\t\tstruct {\n\t\t\tu64 grp: 8;\n\t\t\tu64 pu: 8;\n\t\t\tu64 chk: 16;\n\t\t\tu64 sec: 24;\n\t\t\tu64 reserved: 8;\n\t\t} m;\n\t\tstruct {\n\t\t\tu64 line: 63;\n\t\t\tu64 is_cached: 1;\n\t\t} c;\n\t\tu64 ppa;\n\t};\n};\n\nstruct nvm_dev;\n\ntypedef int nvm_id_fn(struct nvm_dev *);\n\nstruct nvm_addrf {\n\tu8 ch_len;\n\tu8 lun_len;\n\tu8 chk_len;\n\tu8 sec_len;\n\tu8 rsv_len[2];\n\tu8 ch_offset;\n\tu8 lun_offset;\n\tu8 chk_offset;\n\tu8 sec_offset;\n\tu8 rsv_off[2];\n\tu64 ch_mask;\n\tu64 lun_mask;\n\tu64 chk_mask;\n\tu64 sec_mask;\n\tu64 rsv_mask[2];\n};\n\nstruct nvm_geo {\n\tu8 major_ver_id;\n\tu8 minor_ver_id;\n\tu8 version;\n\tint num_ch;\n\tint num_lun;\n\tint all_luns;\n\tint all_chunks;\n\tint op;\n\tsector_t total_secs;\n\tu32 num_chk;\n\tu32 clba;\n\tu16 csecs;\n\tu16 sos;\n\tbool ext;\n\tu32 mdts;\n\tu32 ws_min;\n\tu32 ws_opt;\n\tu32 mw_cunits;\n\tu32 maxoc;\n\tu32 maxocpu;\n\tu32 mccap;\n\tu32 trdt;\n\tu32 trdm;\n\tu32 tprt;\n\tu32 tprm;\n\tu32 tbet;\n\tu32 tbem;\n\tstruct nvm_addrf addrf;\n\tu8 vmnt;\n\tu32 cap;\n\tu32 dom;\n\tu8 mtype;\n\tu8 fmtype;\n\tu16 cpar;\n\tu32 mpos;\n\tu8 num_pln;\n\tu8 pln_mode;\n\tu16 num_pg;\n\tu16 fpg_sz;\n};\n\nstruct nvm_dev_ops;\n\nstruct nvm_dev {\n\tstruct nvm_dev_ops *ops;\n\tstruct list_head devices;\n\tstruct nvm_geo geo;\n\tlong unsigned int *lun_map;\n\tvoid *dma_pool;\n\tstruct request_queue *q;\n\tchar name[32];\n\tvoid *private_data;\n\tstruct kref ref;\n\tvoid *rmap;\n\tstruct mutex mlock;\n\tspinlock_t lock;\n\tstruct list_head area_list;\n\tstruct list_head targets;\n};\n\ntypedef int nvm_op_bb_tbl_fn(struct nvm_dev *, struct ppa_addr, u8 *);\n\ntypedef int nvm_op_set_bb_fn(struct nvm_dev *, struct ppa_addr *, int, int);\n\nstruct nvm_chk_meta;\n\ntypedef int nvm_get_chk_meta_fn(struct nvm_dev *, sector_t, int, struct nvm_chk_meta *);\n\nstruct nvm_chk_meta {\n\tu8 state;\n\tu8 type;\n\tu8 wi;\n\tu8 rsvd[5];\n\tu64 slba;\n\tu64 cnlb;\n\tu64 wp;\n};\n\nstruct nvm_rq;\n\ntypedef int nvm_submit_io_fn(struct nvm_dev *, struct nvm_rq *, void *);\n\ntypedef void nvm_end_io_fn(struct nvm_rq *);\n\nstruct nvm_tgt_dev;\n\nstruct nvm_rq {\n\tstruct nvm_tgt_dev *dev;\n\tstruct bio *bio;\n\tunion {\n\t\tstruct ppa_addr ppa_addr;\n\t\tdma_addr_t dma_ppa_list;\n\t};\n\tstruct ppa_addr *ppa_list;\n\tvoid *meta_list;\n\tdma_addr_t dma_meta_list;\n\tnvm_end_io_fn *end_io;\n\tuint8_t opcode;\n\tuint16_t nr_ppas;\n\tuint16_t flags;\n\tu64 ppa_status;\n\tint error;\n\tint is_seq;\n\tvoid *private;\n};\n\ntypedef void *nvm_create_dma_pool_fn(struct nvm_dev *, char *, int);\n\ntypedef void nvm_destroy_dma_pool_fn(void *);\n\ntypedef void *nvm_dev_dma_alloc_fn(struct nvm_dev *, void *, gfp_t, dma_addr_t *);\n\ntypedef void nvm_dev_dma_free_fn(void *, void *, dma_addr_t);\n\nstruct nvm_dev_ops {\n\tnvm_id_fn *identity;\n\tnvm_op_bb_tbl_fn *get_bb_tbl;\n\tnvm_op_set_bb_fn *set_bb_tbl;\n\tnvm_get_chk_meta_fn *get_chk_meta;\n\tnvm_submit_io_fn *submit_io;\n\tnvm_create_dma_pool_fn *create_dma_pool;\n\tnvm_destroy_dma_pool_fn *destroy_dma_pool;\n\tnvm_dev_dma_alloc_fn *dev_dma_alloc;\n\tnvm_dev_dma_free_fn *dev_dma_free;\n};\n\nenum {\n\tNVM_RSP_L2P = 1,\n\tNVM_RSP_ECC = 2,\n\tNVM_ADDRMODE_LINEAR = 0,\n\tNVM_ADDRMODE_CHANNEL = 1,\n\tNVM_PLANE_SINGLE = 1,\n\tNVM_PLANE_DOUBLE = 2,\n\tNVM_PLANE_QUAD = 4,\n\tNVM_RSP_SUCCESS = 0,\n\tNVM_RSP_NOT_CHANGEABLE = 1,\n\tNVM_RSP_ERR_FAILWRITE = 16639,\n\tNVM_RSP_ERR_EMPTYPAGE = 17151,\n\tNVM_RSP_ERR_FAILECC = 17025,\n\tNVM_RSP_ERR_FAILCRC = 16388,\n\tNVM_RSP_WARN_HIGHECC = 18176,\n\tNVM_OP_PWRITE = 145,\n\tNVM_OP_PREAD = 146,\n\tNVM_OP_ERASE = 144,\n\tNVM_IO_SNGL_ACCESS = 0,\n\tNVM_IO_DUAL_ACCESS = 1,\n\tNVM_IO_QUAD_ACCESS = 2,\n\tNVM_IO_SUSPEND = 128,\n\tNVM_IO_SLC_MODE = 256,\n\tNVM_IO_SCRAMBLE_ENABLE = 512,\n\tNVM_BLK_T_FREE = 0,\n\tNVM_BLK_T_BAD = 1,\n\tNVM_BLK_T_GRWN_BAD = 2,\n\tNVM_BLK_T_DEV = 4,\n\tNVM_BLK_T_HOST = 8,\n\tNVM_ID_CAP_SLC = 1,\n\tNVM_ID_CAP_CMD_SUSPEND = 2,\n\tNVM_ID_CAP_SCRAMBLE = 4,\n\tNVM_ID_CAP_ENCRYPT = 8,\n\tNVM_ID_FMTYPE_SLC = 0,\n\tNVM_ID_FMTYPE_MLC = 1,\n\tNVM_ID_DCAP_BBLKMGMT = 1,\n\tNVM_UD_DCAP_ECC = 2,\n};\n\nstruct nvm_addrf_12 {\n\tu8 ch_len;\n\tu8 lun_len;\n\tu8 blk_len;\n\tu8 pg_len;\n\tu8 pln_len;\n\tu8 sec_len;\n\tu8 ch_offset;\n\tu8 lun_offset;\n\tu8 blk_offset;\n\tu8 pg_offset;\n\tu8 pln_offset;\n\tu8 sec_offset;\n\tu64 ch_mask;\n\tu64 lun_mask;\n\tu64 blk_mask;\n\tu64 pg_mask;\n\tu64 pln_mask;\n\tu64 sec_mask;\n};\n\nenum {\n\tNVM_CHK_ST_FREE = 1,\n\tNVM_CHK_ST_CLOSED = 2,\n\tNVM_CHK_ST_OPEN = 4,\n\tNVM_CHK_ST_OFFLINE = 8,\n\tNVM_CHK_TP_W_SEQ = 1,\n\tNVM_CHK_TP_W_RAN = 2,\n\tNVM_CHK_TP_SZ_SPEC = 16,\n};\n\nstruct nvm_tgt_type;\n\nstruct nvm_target {\n\tstruct list_head list;\n\tstruct nvm_tgt_dev *dev;\n\tstruct nvm_tgt_type *type;\n\tstruct gendisk *disk;\n};\n\nstruct nvm_tgt_dev {\n\tstruct nvm_geo geo;\n\tstruct ppa_addr *luns;\n\tstruct request_queue *q;\n\tstruct nvm_dev *parent;\n\tvoid *map;\n};\n\ntypedef sector_t nvm_tgt_capacity_fn(void *);\n\ntypedef void *nvm_tgt_init_fn(struct nvm_tgt_dev *, struct gendisk *, int);\n\ntypedef void nvm_tgt_exit_fn(void *, bool);\n\ntypedef int nvm_tgt_sysfs_init_fn(struct gendisk *);\n\ntypedef void nvm_tgt_sysfs_exit_fn(struct gendisk *);\n\nstruct nvm_tgt_type {\n\tconst char *name;\n\tunsigned int version[3];\n\tint flags;\n\tconst struct block_device_operations *bops;\n\tnvm_tgt_capacity_fn *capacity;\n\tnvm_tgt_init_fn *init;\n\tnvm_tgt_exit_fn *exit;\n\tnvm_tgt_sysfs_init_fn *sysfs_init;\n\tnvm_tgt_sysfs_exit_fn *sysfs_exit;\n\tstruct list_head list;\n\tstruct module *owner;\n};\n\nenum {\n\tNVM_TGT_F_DEV_L2P = 0,\n\tNVM_TGT_F_HOST_L2P = 1,\n};\n\nstruct nvm_ch_map {\n\tint ch_off;\n\tint num_lun;\n\tint *lun_offs;\n};\n\nstruct nvm_dev_map {\n\tstruct nvm_ch_map *chnls;\n\tint num_ch;\n};\n\nstruct component_ops {\n\tint (*bind)(struct device *, struct device *, void *);\n\tvoid (*unbind)(struct device *, struct device *, void *);\n};\n\nstruct component_master_ops {\n\tint (*bind)(struct device *);\n\tvoid (*unbind)(struct device *);\n};\n\nstruct component;\n\nstruct component_match_array {\n\tvoid *data;\n\tint (*compare)(struct device *, void *);\n\tint (*compare_typed)(struct device *, int, void *);\n\tvoid (*release)(struct device *, void *);\n\tstruct component *component;\n\tbool duplicate;\n};\n\nstruct master;\n\nstruct component {\n\tstruct list_head node;\n\tstruct master *master;\n\tbool bound;\n\tconst struct component_ops *ops;\n\tint subcomponent;\n\tstruct device *dev;\n};\n\nstruct component_match {\n\tsize_t alloc;\n\tsize_t num;\n\tstruct component_match_array *compare;\n};\n\nstruct master {\n\tstruct list_head node;\n\tbool bound;\n\tconst struct component_master_ops *ops;\n\tstruct device *parent;\n\tstruct component_match *match;\n};\n\nstruct fwnode_link {\n\tstruct fwnode_handle *supplier;\n\tstruct list_head s_hook;\n\tstruct fwnode_handle *consumer;\n\tstruct list_head c_hook;\n};\n\nstruct wake_irq {\n\tstruct device *dev;\n\tunsigned int status;\n\tint irq;\n\tconst char *name;\n};\n\nenum dpm_order {\n\tDPM_ORDER_NONE = 0,\n\tDPM_ORDER_DEV_AFTER_PARENT = 1,\n\tDPM_ORDER_PARENT_BEFORE_DEV = 2,\n\tDPM_ORDER_DEV_LAST = 3,\n};\n\nstruct subsys_private {\n\tstruct kset subsys;\n\tstruct kset *devices_kset;\n\tstruct list_head interfaces;\n\tstruct mutex mutex;\n\tstruct kset *drivers_kset;\n\tstruct klist klist_devices;\n\tstruct klist klist_drivers;\n\tstruct blocking_notifier_head bus_notifier;\n\tunsigned int drivers_autoprobe: 1;\n\tstruct bus_type *bus;\n\tstruct kset glue_dirs;\n\tstruct class *class;\n};\n\nstruct driver_private {\n\tstruct kobject kobj;\n\tstruct klist klist_devices;\n\tstruct klist_node knode_bus;\n\tstruct module_kobject *mkobj;\n\tstruct device_driver *driver;\n};\n\nstruct device_private {\n\tstruct klist klist_children;\n\tstruct klist_node knode_parent;\n\tstruct klist_node knode_driver;\n\tstruct klist_node knode_bus;\n\tstruct klist_node knode_class;\n\tstruct list_head deferred_probe;\n\tstruct device_driver *async_driver;\n\tchar *deferred_probe_reason;\n\tstruct device *device;\n\tu8 dead: 1;\n};\n\nunion device_attr_group_devres {\n\tconst struct attribute_group *group;\n\tconst struct attribute_group **groups;\n};\n\nstruct class_dir {\n\tstruct kobject kobj;\n\tstruct class *class;\n};\n\nstruct root_device {\n\tstruct device dev;\n\tstruct module *owner;\n};\n\nstruct subsys_dev_iter {\n\tstruct klist_iter ki;\n\tconst struct device_type *type;\n};\n\nstruct device_attach_data {\n\tstruct device *dev;\n\tbool check_async;\n\tbool want_async;\n\tbool have_async;\n};\n\nstruct class_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct class *, struct class_attribute *, char *);\n\tssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t);\n};\n\nstruct class_attribute_string {\n\tstruct class_attribute attr;\n\tchar *str;\n};\n\nstruct class_compat {\n\tstruct kobject *kobj;\n};\n\nstruct irq_affinity_devres {\n\tunsigned int count;\n\tunsigned int irq[0];\n};\n\nstruct platform_object {\n\tstruct platform_device pdev;\n\tchar name[0];\n};\n\nstruct cpu_attr {\n\tstruct device_attribute attr;\n\tconst struct cpumask * const map;\n};\n\nstruct probe {\n\tstruct probe *next;\n\tdev_t dev;\n\tlong unsigned int range;\n\tstruct module *owner;\n\tkobj_probe_t *get;\n\tint (*lock)(dev_t, void *);\n\tvoid *data;\n};\n\nstruct kobj_map___2 {\n\tstruct probe *probes[255];\n\tstruct mutex *lock;\n};\n\nstruct devres_node {\n\tstruct list_head entry;\n\tdr_release_t release;\n\tconst char *name;\n\tsize_t size;\n};\n\nstruct devres___2 {\n\tstruct devres_node node;\n\tu8 data[0];\n};\n\nstruct devres_group {\n\tstruct devres_node node[2];\n\tvoid *id;\n\tint color;\n};\n\nstruct action_devres {\n\tvoid *data;\n\tvoid (*action)(void *);\n};\n\nstruct pages_devres {\n\tlong unsigned int addr;\n\tunsigned int order;\n};\n\nstruct attribute_container {\n\tstruct list_head node;\n\tstruct klist containers;\n\tstruct class *class;\n\tconst struct attribute_group *grp;\n\tstruct device_attribute **attrs;\n\tint (*match)(struct attribute_container *, struct device *);\n\tlong unsigned int flags;\n};\n\nstruct internal_container {\n\tstruct klist_node node;\n\tstruct attribute_container *cont;\n\tstruct device classdev;\n};\n\nstruct transport_container;\n\nstruct transport_class {\n\tstruct class class;\n\tint (*setup)(struct transport_container *, struct device *, struct device *);\n\tint (*configure)(struct transport_container *, struct device *, struct device *);\n\tint (*remove)(struct transport_container *, struct device *, struct device *);\n};\n\nstruct transport_container {\n\tstruct attribute_container ac;\n\tconst struct attribute_group *statistics;\n};\n\nstruct anon_transport_class {\n\tstruct transport_class tclass;\n\tstruct attribute_container container;\n};\n\ntypedef void * (*devcon_match_fn_t)(struct fwnode_handle *, const char *, void *);\n\nstruct mii_bus;\n\nstruct mdio_device {\n\tstruct device dev;\n\tstruct mii_bus *bus;\n\tchar modalias[32];\n\tint (*bus_match)(struct device *, struct device_driver *);\n\tvoid (*device_free)(struct mdio_device *);\n\tvoid (*device_remove)(struct mdio_device *);\n\tint addr;\n\tint flags;\n\tstruct gpio_desc *reset_gpio;\n\tstruct reset_control *reset_ctrl;\n\tunsigned int reset_assert_delay;\n\tunsigned int reset_deassert_delay;\n};\n\nstruct phy_c45_device_ids {\n\tu32 devices_in_package;\n\tu32 mmds_present;\n\tu32 device_ids[32];\n};\n\nenum phy_state {\n\tPHY_DOWN = 0,\n\tPHY_READY = 1,\n\tPHY_HALTED = 2,\n\tPHY_UP = 3,\n\tPHY_RUNNING = 4,\n\tPHY_NOLINK = 5,\n\tPHY_CABLETEST = 6,\n};\n\ntypedef enum {\n\tPHY_INTERFACE_MODE_NA = 0,\n\tPHY_INTERFACE_MODE_INTERNAL = 1,\n\tPHY_INTERFACE_MODE_MII = 2,\n\tPHY_INTERFACE_MODE_GMII = 3,\n\tPHY_INTERFACE_MODE_SGMII = 4,\n\tPHY_INTERFACE_MODE_TBI = 5,\n\tPHY_INTERFACE_MODE_REVMII = 6,\n\tPHY_INTERFACE_MODE_RMII = 7,\n\tPHY_INTERFACE_MODE_REVRMII = 8,\n\tPHY_INTERFACE_MODE_RGMII = 9,\n\tPHY_INTERFACE_MODE_RGMII_ID = 10,\n\tPHY_INTERFACE_MODE_RGMII_RXID = 11,\n\tPHY_INTERFACE_MODE_RGMII_TXID = 12,\n\tPHY_INTERFACE_MODE_RTBI = 13,\n\tPHY_INTERFACE_MODE_SMII = 14,\n\tPHY_INTERFACE_MODE_XGMII = 15,\n\tPHY_INTERFACE_MODE_XLGMII = 16,\n\tPHY_INTERFACE_MODE_MOCA = 17,\n\tPHY_INTERFACE_MODE_QSGMII = 18,\n\tPHY_INTERFACE_MODE_TRGMII = 19,\n\tPHY_INTERFACE_MODE_100BASEX = 20,\n\tPHY_INTERFACE_MODE_1000BASEX = 21,\n\tPHY_INTERFACE_MODE_2500BASEX = 22,\n\tPHY_INTERFACE_MODE_5GBASER = 23,\n\tPHY_INTERFACE_MODE_RXAUI = 24,\n\tPHY_INTERFACE_MODE_XAUI = 25,\n\tPHY_INTERFACE_MODE_10GBASER = 26,\n\tPHY_INTERFACE_MODE_25GBASER = 27,\n\tPHY_INTERFACE_MODE_USXGMII = 28,\n\tPHY_INTERFACE_MODE_10GKR = 29,\n\tPHY_INTERFACE_MODE_MAX = 30,\n} phy_interface_t;\n\nstruct phy_led_trigger;\n\nstruct phylink;\n\nstruct phy_driver;\n\nstruct phy_package_shared;\n\nstruct mii_timestamper;\n\nstruct phy_device {\n\tstruct mdio_device mdio;\n\tstruct phy_driver *drv;\n\tu32 phy_id;\n\tstruct phy_c45_device_ids c45_ids;\n\tunsigned int is_c45: 1;\n\tunsigned int is_internal: 1;\n\tunsigned int is_pseudo_fixed_link: 1;\n\tunsigned int is_gigabit_capable: 1;\n\tunsigned int has_fixups: 1;\n\tunsigned int suspended: 1;\n\tunsigned int suspended_by_mdio_bus: 1;\n\tunsigned int sysfs_links: 1;\n\tunsigned int loopback_enabled: 1;\n\tunsigned int downshifted_rate: 1;\n\tunsigned int is_on_sfp_module: 1;\n\tunsigned int mac_managed_pm: 1;\n\tunsigned int autoneg: 1;\n\tunsigned int link: 1;\n\tunsigned int autoneg_complete: 1;\n\tunsigned int interrupts: 1;\n\tenum phy_state state;\n\tu32 dev_flags;\n\tphy_interface_t interface;\n\tint speed;\n\tint duplex;\n\tint port;\n\tint pause;\n\tint asym_pause;\n\tu8 master_slave_get;\n\tu8 master_slave_set;\n\tu8 master_slave_state;\n\tlong unsigned int supported[2];\n\tlong unsigned int advertising[2];\n\tlong unsigned int lp_advertising[2];\n\tlong unsigned int adv_old[2];\n\tu32 eee_broken_modes;\n\tstruct phy_led_trigger *phy_led_triggers;\n\tunsigned int phy_num_led_triggers;\n\tstruct phy_led_trigger *last_triggered;\n\tstruct phy_led_trigger *led_link_trigger;\n\tint irq;\n\tvoid *priv;\n\tstruct phy_package_shared *shared;\n\tstruct sk_buff *skb;\n\tvoid *ehdr;\n\tstruct nlattr *nest;\n\tstruct delayed_work state_queue;\n\tstruct mutex lock;\n\tbool sfp_bus_attached;\n\tstruct sfp_bus *sfp_bus;\n\tstruct phylink *phylink;\n\tstruct net_device *attached_dev;\n\tstruct mii_timestamper *mii_ts;\n\tu8 mdix;\n\tu8 mdix_ctrl;\n\tvoid (*phy_link_change)(struct phy_device *, bool);\n\tvoid (*adjust_link)(struct net_device *);\n\tconst struct macsec_ops *macsec_ops;\n};\n\nstruct phy_tdr_config {\n\tu32 first;\n\tu32 last;\n\tu32 step;\n\ts8 pair;\n};\n\nstruct mdio_bus_stats {\n\tu64_stats_t transfers;\n\tu64_stats_t errors;\n\tu64_stats_t writes;\n\tu64_stats_t reads;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct mii_bus {\n\tstruct module *owner;\n\tconst char *name;\n\tchar id[61];\n\tvoid *priv;\n\tint (*read)(struct mii_bus *, int, int);\n\tint (*write)(struct mii_bus *, int, int, u16);\n\tint (*reset)(struct mii_bus *);\n\tstruct mdio_bus_stats stats[32];\n\tstruct mutex mdio_lock;\n\tstruct device *parent;\n\tenum {\n\t\tMDIOBUS_ALLOCATED = 1,\n\t\tMDIOBUS_REGISTERED = 2,\n\t\tMDIOBUS_UNREGISTERED = 3,\n\t\tMDIOBUS_RELEASED = 4,\n\t} state;\n\tstruct device dev;\n\tstruct mdio_device *mdio_map[32];\n\tu32 phy_mask;\n\tu32 phy_ignore_ta_mask;\n\tint irq[32];\n\tint reset_delay_us;\n\tint reset_post_delay_us;\n\tstruct gpio_desc *reset_gpiod;\n\tenum {\n\t\tMDIOBUS_NO_CAP = 0,\n\t\tMDIOBUS_C22 = 1,\n\t\tMDIOBUS_C45 = 2,\n\t\tMDIOBUS_C22_C45 = 3,\n\t} probe_capabilities;\n\tstruct mutex shared_lock;\n\tstruct phy_package_shared *shared[32];\n};\n\nstruct mdio_driver_common {\n\tstruct device_driver driver;\n\tint flags;\n};\n\nstruct mii_timestamper {\n\tbool (*rxtstamp)(struct mii_timestamper *, struct sk_buff *, int);\n\tvoid (*txtstamp)(struct mii_timestamper *, struct sk_buff *, int);\n\tint (*hwtstamp)(struct mii_timestamper *, struct ifreq *);\n\tvoid (*link_state)(struct mii_timestamper *, struct phy_device *);\n\tint (*ts_info)(struct mii_timestamper *, struct ethtool_ts_info *);\n\tstruct device *device;\n};\n\nstruct phy_package_shared {\n\tint addr;\n\trefcount_t refcnt;\n\tlong unsigned int flags;\n\tsize_t priv_size;\n\tvoid *priv;\n};\n\nstruct phy_driver {\n\tstruct mdio_driver_common mdiodrv;\n\tu32 phy_id;\n\tchar *name;\n\tu32 phy_id_mask;\n\tconst long unsigned int * const features;\n\tu32 flags;\n\tconst void *driver_data;\n\tint (*soft_reset)(struct phy_device *);\n\tint (*config_init)(struct phy_device *);\n\tint (*probe)(struct phy_device *);\n\tint (*get_features)(struct phy_device *);\n\tint (*suspend)(struct phy_device *);\n\tint (*resume)(struct phy_device *);\n\tint (*config_aneg)(struct phy_device *);\n\tint (*aneg_done)(struct phy_device *);\n\tint (*read_status)(struct phy_device *);\n\tint (*config_intr)(struct phy_device *);\n\tirqreturn_t (*handle_interrupt)(struct phy_device *);\n\tvoid (*remove)(struct phy_device *);\n\tint (*match_phy_device)(struct phy_device *);\n\tint (*set_wol)(struct phy_device *, struct ethtool_wolinfo *);\n\tvoid (*get_wol)(struct phy_device *, struct ethtool_wolinfo *);\n\tvoid (*link_change_notify)(struct phy_device *);\n\tint (*read_mmd)(struct phy_device *, int, u16);\n\tint (*write_mmd)(struct phy_device *, int, u16, u16);\n\tint (*read_page)(struct phy_device *);\n\tint (*write_page)(struct phy_device *, int);\n\tint (*module_info)(struct phy_device *, struct ethtool_modinfo *);\n\tint (*module_eeprom)(struct phy_device *, struct ethtool_eeprom *, u8 *);\n\tint (*cable_test_start)(struct phy_device *);\n\tint (*cable_test_tdr_start)(struct phy_device *, const struct phy_tdr_config *);\n\tint (*cable_test_get_status)(struct phy_device *, bool *);\n\tint (*get_sset_count)(struct phy_device *);\n\tvoid (*get_strings)(struct phy_device *, u8 *);\n\tvoid (*get_stats)(struct phy_device *, struct ethtool_stats *, u64 *);\n\tint (*get_tunable)(struct phy_device *, struct ethtool_tunable *, void *);\n\tint (*set_tunable)(struct phy_device *, struct ethtool_tunable *, const void *);\n\tint (*set_loopback)(struct phy_device *, bool);\n\tint (*get_sqi)(struct phy_device *);\n\tint (*get_sqi_max)(struct phy_device *);\n};\n\nstruct software_node_ref_args {\n\tconst struct software_node *node;\n\tunsigned int nargs;\n\tu64 args[8];\n};\n\nstruct swnode {\n\tstruct kobject kobj;\n\tstruct fwnode_handle fwnode;\n\tconst struct software_node *node;\n\tint id;\n\tstruct ida child_ids;\n\tstruct list_head entry;\n\tstruct list_head children;\n\tstruct swnode *parent;\n\tunsigned int allocated: 1;\n\tunsigned int managed: 1;\n};\n\nstruct auxiliary_device_id {\n\tchar name[32];\n\tkernel_ulong_t driver_data;\n};\n\nstruct auxiliary_device {\n\tstruct device dev;\n\tconst char *name;\n\tu32 id;\n};\n\nstruct auxiliary_driver {\n\tint (*probe)(struct auxiliary_device *, const struct auxiliary_device_id *);\n\tvoid (*remove)(struct auxiliary_device *);\n\tvoid (*shutdown)(struct auxiliary_device *);\n\tint (*suspend)(struct auxiliary_device *, pm_message_t);\n\tint (*resume)(struct auxiliary_device *);\n\tconst char *name;\n\tstruct device_driver driver;\n\tconst struct auxiliary_device_id *id_table;\n};\n\nstruct req {\n\tstruct req *next;\n\tstruct completion done;\n\tint err;\n\tconst char *name;\n\tumode_t mode;\n\tkuid_t uid;\n\tkgid_t gid;\n\tstruct device *dev;\n};\n\ntypedef int (*pm_callback_t)(struct device *);\n\nenum gpd_status {\n\tGENPD_STATE_ON = 0,\n\tGENPD_STATE_OFF = 1,\n};\n\nenum genpd_notication {\n\tGENPD_NOTIFY_PRE_OFF = 0,\n\tGENPD_NOTIFY_OFF = 1,\n\tGENPD_NOTIFY_PRE_ON = 2,\n\tGENPD_NOTIFY_ON = 3,\n};\n\nstruct dev_power_governor {\n\tbool (*power_down_ok)(struct dev_pm_domain *);\n\tbool (*suspend_ok)(struct device *);\n};\n\nstruct gpd_dev_ops {\n\tint (*start)(struct device *);\n\tint (*stop)(struct device *);\n};\n\nstruct genpd_power_state {\n\ts64 power_off_latency_ns;\n\ts64 power_on_latency_ns;\n\ts64 residency_ns;\n\tu64 usage;\n\tu64 rejected;\n\tstruct fwnode_handle *fwnode;\n\tktime_t idle_time;\n\tvoid *data;\n};\n\nstruct opp_table;\n\nstruct dev_pm_opp;\n\nstruct genpd_lock_ops;\n\nstruct generic_pm_domain {\n\tstruct device dev;\n\tstruct dev_pm_domain domain;\n\tstruct list_head gpd_list_node;\n\tstruct list_head parent_links;\n\tstruct list_head child_links;\n\tstruct list_head dev_list;\n\tstruct dev_power_governor *gov;\n\tstruct work_struct power_off_work;\n\tstruct fwnode_handle *provider;\n\tbool has_provider;\n\tconst char *name;\n\tatomic_t sd_count;\n\tenum gpd_status status;\n\tunsigned int device_count;\n\tunsigned int suspended_count;\n\tunsigned int prepared_count;\n\tunsigned int performance_state;\n\tcpumask_var_t cpus;\n\tint (*power_off)(struct generic_pm_domain *);\n\tint (*power_on)(struct generic_pm_domain *);\n\tstruct raw_notifier_head power_notifiers;\n\tstruct opp_table *opp_table;\n\tunsigned int (*opp_to_performance_state)(struct generic_pm_domain *, struct dev_pm_opp *);\n\tint (*set_performance_state)(struct generic_pm_domain *, unsigned int);\n\tstruct gpd_dev_ops dev_ops;\n\ts64 max_off_time_ns;\n\tktime_t next_wakeup;\n\tbool max_off_time_changed;\n\tbool cached_power_down_ok;\n\tbool cached_power_down_state_idx;\n\tint (*attach_dev)(struct generic_pm_domain *, struct device *);\n\tvoid (*detach_dev)(struct generic_pm_domain *, struct device *);\n\tunsigned int flags;\n\tstruct genpd_power_state *states;\n\tvoid (*free_states)(struct genpd_power_state *, unsigned int);\n\tunsigned int state_count;\n\tunsigned int state_idx;\n\tktime_t on_time;\n\tktime_t accounting_time;\n\tconst struct genpd_lock_ops *lock_ops;\n\tunion {\n\t\tstruct mutex mlock;\n\t\tstruct {\n\t\t\tspinlock_t slock;\n\t\t\tlong unsigned int lock_flags;\n\t\t};\n\t};\n};\n\nstruct genpd_lock_ops {\n\tvoid (*lock)(struct generic_pm_domain *);\n\tvoid (*lock_nested)(struct generic_pm_domain *, int);\n\tint (*lock_interruptible)(struct generic_pm_domain *);\n\tvoid (*unlock)(struct generic_pm_domain *);\n};\n\nstruct gpd_link {\n\tstruct generic_pm_domain *parent;\n\tstruct list_head parent_node;\n\tstruct generic_pm_domain *child;\n\tstruct list_head child_node;\n\tunsigned int performance_state;\n\tunsigned int prev_performance_state;\n};\n\nstruct gpd_timing_data {\n\ts64 suspend_latency_ns;\n\ts64 resume_latency_ns;\n\ts64 effective_constraint_ns;\n\tbool constraint_changed;\n\tbool cached_suspend_ok;\n};\n\nstruct generic_pm_domain_data {\n\tstruct pm_domain_data base;\n\tstruct gpd_timing_data td;\n\tstruct notifier_block nb;\n\tstruct notifier_block *power_nb;\n\tint cpu;\n\tunsigned int performance_state;\n\tunsigned int rpm_pstate;\n\tktime_t next_wakeup;\n\tvoid *data;\n};\n\nstruct pm_clk_notifier_block {\n\tstruct notifier_block nb;\n\tstruct dev_pm_domain *pm_domain;\n\tchar *con_ids[0];\n};\n\nenum pce_status {\n\tPCE_STATUS_NONE = 0,\n\tPCE_STATUS_ACQUIRED = 1,\n\tPCE_STATUS_PREPARED = 2,\n\tPCE_STATUS_ENABLED = 3,\n\tPCE_STATUS_ERROR = 4,\n};\n\nstruct pm_clock_entry {\n\tstruct list_head node;\n\tchar *con_id;\n\tstruct clk *clk;\n\tenum pce_status status;\n\tbool enabled_when_prepared;\n};\n\nstruct isa_driver {\n\tint (*match)(struct device *, unsigned int);\n\tint (*probe)(struct device *, unsigned int);\n\tvoid (*remove)(struct device *, unsigned int);\n\tvoid (*shutdown)(struct device *, unsigned int);\n\tint (*suspend)(struct device *, unsigned int, pm_message_t);\n\tint (*resume)(struct device *, unsigned int);\n\tstruct device_driver driver;\n\tstruct device *devices;\n};\n\nstruct isa_dev {\n\tstruct device dev;\n\tstruct device *next;\n\tunsigned int id;\n};\n\nenum fw_opt {\n\tFW_OPT_UEVENT = 1,\n\tFW_OPT_NOWAIT = 2,\n\tFW_OPT_USERHELPER = 4,\n\tFW_OPT_NO_WARN = 8,\n\tFW_OPT_NOCACHE = 16,\n\tFW_OPT_NOFALLBACK_SYSFS = 32,\n\tFW_OPT_FALLBACK_PLATFORM = 64,\n\tFW_OPT_PARTIAL = 128,\n};\n\nenum fw_status {\n\tFW_STATUS_UNKNOWN = 0,\n\tFW_STATUS_LOADING = 1,\n\tFW_STATUS_DONE = 2,\n\tFW_STATUS_ABORTED = 3,\n};\n\nstruct fw_state {\n\tstruct completion completion;\n\tenum fw_status status;\n};\n\nstruct firmware_cache;\n\nstruct fw_priv {\n\tstruct kref ref;\n\tstruct list_head list;\n\tstruct firmware_cache *fwc;\n\tstruct fw_state fw_st;\n\tvoid *data;\n\tsize_t size;\n\tsize_t allocated_size;\n\tsize_t offset;\n\tu32 opt_flags;\n\tbool is_paged_buf;\n\tstruct page **pages;\n\tint nr_pages;\n\tint page_array_size;\n\tconst char *fw_name;\n};\n\nstruct firmware_cache {\n\tspinlock_t lock;\n\tstruct list_head head;\n\tint state;\n\tspinlock_t name_lock;\n\tstruct list_head fw_names;\n\tstruct delayed_work work;\n\tstruct notifier_block pm_notify;\n};\n\nstruct fw_cache_entry {\n\tstruct list_head list;\n\tconst char *name;\n};\n\nstruct fw_name_devm {\n\tlong unsigned int magic;\n\tconst char *name;\n};\n\nstruct firmware_work {\n\tstruct work_struct work;\n\tstruct module *module;\n\tconst char *name;\n\tstruct device *device;\n\tvoid *context;\n\tvoid (*cont)(const struct firmware *, void *);\n\tu32 opt_flags;\n};\n\nstruct node_access_nodes {\n\tstruct device dev;\n\tstruct list_head list_node;\n\tunsigned int access;\n\tstruct node_hmem_attrs hmem_attrs;\n};\n\nstruct node_cache_info {\n\tstruct device dev;\n\tstruct list_head node;\n\tstruct node_cache_attrs cache_attrs;\n};\n\nstruct node_attr {\n\tstruct device_attribute attr;\n\tenum node_states state;\n};\n\nstruct for_each_memory_block_cb_data {\n\twalk_memory_blocks_func_t func;\n\tvoid *arg;\n};\n\nstruct reg_sequence {\n\tunsigned int reg;\n\tunsigned int def;\n\tunsigned int delay_us;\n};\n\nstruct regmap___2;\n\nstruct regmap_async {\n\tstruct list_head list;\n\tstruct regmap___2 *map;\n\tvoid *work_buf;\n};\n\nstruct reg_field {\n\tunsigned int reg;\n\tunsigned int lsb;\n\tunsigned int msb;\n\tunsigned int id_size;\n\tunsigned int id_offset;\n};\n\nstruct regmap_format {\n\tsize_t buf_size;\n\tsize_t reg_bytes;\n\tsize_t pad_bytes;\n\tsize_t val_bytes;\n\tvoid (*format_write)(struct regmap___2 *, unsigned int, unsigned int);\n\tvoid (*format_reg)(void *, unsigned int, unsigned int);\n\tvoid (*format_val)(void *, unsigned int, unsigned int);\n\tunsigned int (*parse_val)(const void *);\n\tvoid (*parse_inplace)(void *);\n};\n\nstruct hwspinlock;\n\nstruct regcache_ops;\n\nstruct regmap___2 {\n\tunion {\n\t\tstruct mutex mutex;\n\t\tstruct {\n\t\t\tspinlock_t spinlock;\n\t\t\tlong unsigned int spinlock_flags;\n\t\t};\n\t};\n\tregmap_lock lock;\n\tregmap_unlock unlock;\n\tvoid *lock_arg;\n\tgfp_t alloc_flags;\n\tstruct device *dev;\n\tvoid *work_buf;\n\tstruct regmap_format format;\n\tconst struct regmap_bus *bus;\n\tvoid *bus_context;\n\tconst char *name;\n\tbool async;\n\tspinlock_t async_lock;\n\twait_queue_head_t async_waitq;\n\tstruct list_head async_list;\n\tstruct list_head async_free;\n\tint async_ret;\n\tbool debugfs_disable;\n\tstruct dentry *debugfs;\n\tconst char *debugfs_name;\n\tunsigned int debugfs_reg_len;\n\tunsigned int debugfs_val_len;\n\tunsigned int debugfs_tot_len;\n\tstruct list_head debugfs_off_cache;\n\tstruct mutex cache_lock;\n\tunsigned int max_register;\n\tbool (*writeable_reg)(struct device *, unsigned int);\n\tbool (*readable_reg)(struct device *, unsigned int);\n\tbool (*volatile_reg)(struct device *, unsigned int);\n\tbool (*precious_reg)(struct device *, unsigned int);\n\tbool (*writeable_noinc_reg)(struct device *, unsigned int);\n\tbool (*readable_noinc_reg)(struct device *, unsigned int);\n\tconst struct regmap_access_table *wr_table;\n\tconst struct regmap_access_table *rd_table;\n\tconst struct regmap_access_table *volatile_table;\n\tconst struct regmap_access_table *precious_table;\n\tconst struct regmap_access_table *wr_noinc_table;\n\tconst struct regmap_access_table *rd_noinc_table;\n\tint (*reg_read)(void *, unsigned int, unsigned int *);\n\tint (*reg_write)(void *, unsigned int, unsigned int);\n\tint (*reg_update_bits)(void *, unsigned int, unsigned int, unsigned int);\n\tbool defer_caching;\n\tlong unsigned int read_flag_mask;\n\tlong unsigned int write_flag_mask;\n\tint reg_shift;\n\tint reg_stride;\n\tint reg_stride_order;\n\tconst struct regcache_ops *cache_ops;\n\tenum regcache_type cache_type;\n\tunsigned int cache_size_raw;\n\tunsigned int cache_word_size;\n\tunsigned int num_reg_defaults;\n\tunsigned int num_reg_defaults_raw;\n\tbool cache_only;\n\tbool cache_bypass;\n\tbool cache_free;\n\tstruct reg_default *reg_defaults;\n\tconst void *reg_defaults_raw;\n\tvoid *cache;\n\tbool cache_dirty;\n\tbool no_sync_defaults;\n\tstruct reg_sequence *patch;\n\tint patch_regs;\n\tbool use_single_read;\n\tbool use_single_write;\n\tbool can_multi_write;\n\tsize_t max_raw_read;\n\tsize_t max_raw_write;\n\tstruct rb_root range_tree;\n\tvoid *selector_work_buf;\n\tstruct hwspinlock *hwlock;\n\tbool can_sleep;\n};\n\nstruct regcache_ops {\n\tconst char *name;\n\tenum regcache_type type;\n\tint (*init)(struct regmap___2 *);\n\tint (*exit)(struct regmap___2 *);\n\tvoid (*debugfs_init)(struct regmap___2 *);\n\tint (*read)(struct regmap___2 *, unsigned int, unsigned int *);\n\tint (*write)(struct regmap___2 *, unsigned int, unsigned int);\n\tint (*sync)(struct regmap___2 *, unsigned int, unsigned int);\n\tint (*drop)(struct regmap___2 *, unsigned int, unsigned int);\n};\n\nstruct regmap_range_node {\n\tstruct rb_node node;\n\tconst char *name;\n\tstruct regmap___2 *map;\n\tunsigned int range_min;\n\tunsigned int range_max;\n\tunsigned int selector_reg;\n\tunsigned int selector_mask;\n\tint selector_shift;\n\tunsigned int window_start;\n\tunsigned int window_len;\n};\n\nstruct regmap_field {\n\tstruct regmap___2 *regmap;\n\tunsigned int mask;\n\tunsigned int shift;\n\tunsigned int reg;\n\tunsigned int id_size;\n\tunsigned int id_offset;\n};\n\nstruct trace_event_raw_regmap_reg {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tunsigned int reg;\n\tunsigned int val;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_regmap_block {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tunsigned int reg;\n\tint count;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_regcache_sync {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tu32 __data_loc_status;\n\tu32 __data_loc_type;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_regmap_bool {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tint flag;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_regmap_async {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_regcache_drop_region {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tunsigned int from;\n\tunsigned int to;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_regmap_reg {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_regmap_block {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_regcache_sync {\n\tu32 name;\n\tu32 status;\n\tu32 type;\n};\n\nstruct trace_event_data_offsets_regmap_bool {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_regmap_async {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_regcache_drop_region {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_regmap_reg_write)(void *, struct regmap___2 *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_regmap_reg_read)(void *, struct regmap___2 *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_regmap_reg_read_cache)(void *, struct regmap___2 *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_regmap_hw_read_start)(void *, struct regmap___2 *, unsigned int, int);\n\ntypedef void (*btf_trace_regmap_hw_read_done)(void *, struct regmap___2 *, unsigned int, int);\n\ntypedef void (*btf_trace_regmap_hw_write_start)(void *, struct regmap___2 *, unsigned int, int);\n\ntypedef void (*btf_trace_regmap_hw_write_done)(void *, struct regmap___2 *, unsigned int, int);\n\ntypedef void (*btf_trace_regcache_sync)(void *, struct regmap___2 *, const char *, const char *);\n\ntypedef void (*btf_trace_regmap_cache_only)(void *, struct regmap___2 *, bool);\n\ntypedef void (*btf_trace_regmap_cache_bypass)(void *, struct regmap___2 *, bool);\n\ntypedef void (*btf_trace_regmap_async_write_start)(void *, struct regmap___2 *, unsigned int, int);\n\ntypedef void (*btf_trace_regmap_async_io_complete)(void *, struct regmap___2 *);\n\ntypedef void (*btf_trace_regmap_async_complete_start)(void *, struct regmap___2 *);\n\ntypedef void (*btf_trace_regmap_async_complete_done)(void *, struct regmap___2 *);\n\ntypedef void (*btf_trace_regcache_drop_region)(void *, struct regmap___2 *, unsigned int, unsigned int);\n\nstruct regcache_rbtree_node {\n\tvoid *block;\n\tlong int *cache_present;\n\tunsigned int base_reg;\n\tunsigned int blklen;\n\tstruct rb_node node;\n};\n\nstruct regcache_rbtree_ctx {\n\tstruct rb_root root;\n\tstruct regcache_rbtree_node *cached_rbnode;\n};\n\nstruct regmap_debugfs_off_cache {\n\tstruct list_head list;\n\toff_t min;\n\toff_t max;\n\tunsigned int base_reg;\n\tunsigned int max_reg;\n};\n\nstruct regmap_debugfs_node {\n\tstruct regmap___2 *map;\n\tstruct list_head link;\n};\n\nstruct ptp_system_timestamp {\n\tstruct timespec64 pre_ts;\n\tstruct timespec64 post_ts;\n};\n\nstruct spi_statistics {\n\tspinlock_t lock;\n\tlong unsigned int messages;\n\tlong unsigned int transfers;\n\tlong unsigned int errors;\n\tlong unsigned int timedout;\n\tlong unsigned int spi_sync;\n\tlong unsigned int spi_sync_immediate;\n\tlong unsigned int spi_async;\n\tlong long unsigned int bytes;\n\tlong long unsigned int bytes_rx;\n\tlong long unsigned int bytes_tx;\n\tlong unsigned int transfer_bytes_histo[17];\n\tlong unsigned int transfers_split_maxsize;\n};\n\nstruct spi_delay {\n\tu16 value;\n\tu8 unit;\n};\n\nstruct spi_controller;\n\nstruct spi_device {\n\tstruct device dev;\n\tstruct spi_controller *controller;\n\tstruct spi_controller *master;\n\tu32 max_speed_hz;\n\tu8 chip_select;\n\tu8 bits_per_word;\n\tbool rt;\n\tu32 mode;\n\tint irq;\n\tvoid *controller_state;\n\tvoid *controller_data;\n\tchar modalias[32];\n\tconst char *driver_override;\n\tint cs_gpio;\n\tstruct gpio_desc *cs_gpiod;\n\tstruct spi_delay word_delay;\n\tstruct spi_statistics statistics;\n};\n\nstruct spi_message;\n\nstruct spi_transfer;\n\nstruct spi_controller_mem_ops;\n\nstruct spi_controller {\n\tstruct device dev;\n\tstruct list_head list;\n\ts16 bus_num;\n\tu16 num_chipselect;\n\tu16 dma_alignment;\n\tu32 mode_bits;\n\tu32 buswidth_override_bits;\n\tu32 bits_per_word_mask;\n\tu32 min_speed_hz;\n\tu32 max_speed_hz;\n\tu16 flags;\n\tbool devm_allocated;\n\tbool slave;\n\tsize_t (*max_transfer_size)(struct spi_device *);\n\tsize_t (*max_message_size)(struct spi_device *);\n\tstruct mutex io_mutex;\n\tspinlock_t bus_lock_spinlock;\n\tstruct mutex bus_lock_mutex;\n\tbool bus_lock_flag;\n\tint (*setup)(struct spi_device *);\n\tint (*set_cs_timing)(struct spi_device *, struct spi_delay *, struct spi_delay *, struct spi_delay *);\n\tint (*transfer)(struct spi_device *, struct spi_message *);\n\tvoid (*cleanup)(struct spi_device *);\n\tbool (*can_dma)(struct spi_controller *, struct spi_device *, struct spi_transfer *);\n\tstruct device *dma_map_dev;\n\tbool queued;\n\tstruct kthread_worker *kworker;\n\tstruct kthread_work pump_messages;\n\tspinlock_t queue_lock;\n\tstruct list_head queue;\n\tstruct spi_message *cur_msg;\n\tbool idling;\n\tbool busy;\n\tbool running;\n\tbool rt;\n\tbool auto_runtime_pm;\n\tbool cur_msg_prepared;\n\tbool cur_msg_mapped;\n\tbool last_cs_enable;\n\tbool last_cs_mode_high;\n\tbool fallback;\n\tstruct completion xfer_completion;\n\tsize_t max_dma_len;\n\tint (*prepare_transfer_hardware)(struct spi_controller *);\n\tint (*transfer_one_message)(struct spi_controller *, struct spi_message *);\n\tint (*unprepare_transfer_hardware)(struct spi_controller *);\n\tint (*prepare_message)(struct spi_controller *, struct spi_message *);\n\tint (*unprepare_message)(struct spi_controller *, struct spi_message *);\n\tint (*slave_abort)(struct spi_controller *);\n\tvoid (*set_cs)(struct spi_device *, bool);\n\tint (*transfer_one)(struct spi_controller *, struct spi_device *, struct spi_transfer *);\n\tvoid (*handle_err)(struct spi_controller *, struct spi_message *);\n\tconst struct spi_controller_mem_ops *mem_ops;\n\tstruct spi_delay cs_setup;\n\tstruct spi_delay cs_hold;\n\tstruct spi_delay cs_inactive;\n\tint *cs_gpios;\n\tstruct gpio_desc **cs_gpiods;\n\tbool use_gpio_descriptors;\n\ts8 unused_native_cs;\n\ts8 max_native_cs;\n\tstruct spi_statistics statistics;\n\tstruct dma_chan___2 *dma_tx;\n\tstruct dma_chan___2 *dma_rx;\n\tvoid *dummy_rx;\n\tvoid *dummy_tx;\n\tint (*fw_translate_cs)(struct spi_controller *, unsigned int);\n\tbool ptp_sts_supported;\n\tlong unsigned int irq_flags;\n};\n\nstruct spi_message {\n\tstruct list_head transfers;\n\tstruct spi_device *spi;\n\tunsigned int is_dma_mapped: 1;\n\tvoid (*complete)(void *);\n\tvoid *context;\n\tunsigned int frame_length;\n\tunsigned int actual_length;\n\tint status;\n\tstruct list_head queue;\n\tvoid *state;\n\tstruct list_head resources;\n};\n\nstruct spi_transfer {\n\tconst void *tx_buf;\n\tvoid *rx_buf;\n\tunsigned int len;\n\tdma_addr_t tx_dma;\n\tdma_addr_t rx_dma;\n\tstruct sg_table tx_sg;\n\tstruct sg_table rx_sg;\n\tunsigned int dummy_data: 1;\n\tunsigned int cs_change: 1;\n\tunsigned int tx_nbits: 3;\n\tunsigned int rx_nbits: 3;\n\tu8 bits_per_word;\n\tstruct spi_delay delay;\n\tstruct spi_delay cs_change_delay;\n\tstruct spi_delay word_delay;\n\tu32 speed_hz;\n\tu32 effective_speed_hz;\n\tunsigned int ptp_sts_word_pre;\n\tunsigned int ptp_sts_word_post;\n\tstruct ptp_system_timestamp *ptp_sts;\n\tbool timestamped;\n\tstruct list_head transfer_list;\n\tu16 error;\n};\n\nstruct spi_mem;\n\nstruct spi_mem_op;\n\nstruct spi_mem_dirmap_desc;\n\nstruct spi_controller_mem_ops {\n\tint (*adjust_op_size)(struct spi_mem *, struct spi_mem_op *);\n\tbool (*supports_op)(struct spi_mem *, const struct spi_mem_op *);\n\tint (*exec_op)(struct spi_mem *, const struct spi_mem_op *);\n\tconst char * (*get_name)(struct spi_mem *);\n\tint (*dirmap_create)(struct spi_mem_dirmap_desc *);\n\tvoid (*dirmap_destroy)(struct spi_mem_dirmap_desc *);\n\tssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *, u64, size_t, void *);\n\tssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *, u64, size_t, const void *);\n\tint (*poll_status)(struct spi_mem *, const struct spi_mem_op *, u16, u16, long unsigned int, long unsigned int, long unsigned int);\n};\n\nstruct regmap_async_spi {\n\tstruct regmap_async core;\n\tstruct spi_message m;\n\tstruct spi_transfer t[2];\n};\n\nstruct regmap_mmio_context {\n\tvoid *regs;\n\tunsigned int val_bytes;\n\tbool relaxed_mmio;\n\tbool attached_clk;\n\tstruct clk *clk;\n\tvoid (*reg_write)(struct regmap_mmio_context *, unsigned int, unsigned int);\n\tunsigned int (*reg_read)(struct regmap_mmio_context *, unsigned int);\n};\n\nstruct regmap_irq_chip_data___2 {\n\tstruct mutex lock;\n\tstruct irq_chip irq_chip;\n\tstruct regmap___2 *map;\n\tconst struct regmap_irq_chip *chip;\n\tint irq_base;\n\tstruct irq_domain *domain;\n\tint irq;\n\tint wake_count;\n\tvoid *status_reg_buf;\n\tunsigned int *main_status_buf;\n\tunsigned int *status_buf;\n\tunsigned int *mask_buf;\n\tunsigned int *mask_buf_def;\n\tunsigned int *wake_buf;\n\tunsigned int *type_buf;\n\tunsigned int *type_buf_def;\n\tunsigned int **virt_buf;\n\tunsigned int irq_reg_stride;\n\tunsigned int type_reg_stride;\n\tbool clear_status: 1;\n};\n\nstruct devcd_entry {\n\tstruct device devcd_dev;\n\tvoid *data;\n\tsize_t datalen;\n\tstruct module *owner;\n\tssize_t (*read)(char *, loff_t, size_t, void *, size_t);\n\tvoid (*free)(void *);\n\tstruct delayed_work del_wk;\n\tstruct device *failing_dev;\n};\n\ntypedef void (*irq_write_msi_msg_t)(struct msi_desc *, struct msi_msg *);\n\nstruct platform_msi_priv_data {\n\tstruct device *dev;\n\tvoid *host_data;\n\tmsi_alloc_info_t arg;\n\tirq_write_msi_msg_t write_msg;\n\tint devid;\n};\n\nstruct trace_event_raw_devres {\n\tstruct trace_entry ent;\n\tu32 __data_loc_devname;\n\tstruct device *dev;\n\tconst char *op;\n\tvoid *node;\n\tconst char *name;\n\tsize_t size;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_devres {\n\tu32 devname;\n};\n\ntypedef void (*btf_trace_devres_log)(void *, struct device *, const char *, void *, const char *, size_t);\n\nstruct mfd_cell_acpi_match {\n\tconst char *pnpid;\n\tconst long long unsigned int adr;\n};\n\nenum {\n\tCHIP_INVALID = 0,\n\tCHIP_PM8606 = 1,\n\tCHIP_PM8607 = 2,\n\tCHIP_MAX = 3,\n};\n\nenum pm8606_ref_gp_and_osc_clients {\n\tREF_GP_NO_CLIENTS = 0,\n\tWLED1_DUTY = 1,\n\tWLED2_DUTY = 2,\n\tWLED3_DUTY = 4,\n\tRGB1_ENABLE = 8,\n\tRGB2_ENABLE = 16,\n\tLDO_VBR_EN = 32,\n\tREF_GP_MAX_CLIENT = 65535,\n};\n\nenum {\n\tPM8607_IRQ_ONKEY = 0,\n\tPM8607_IRQ_EXTON = 1,\n\tPM8607_IRQ_CHG = 2,\n\tPM8607_IRQ_BAT = 3,\n\tPM8607_IRQ_RTC = 4,\n\tPM8607_IRQ_CC = 5,\n\tPM8607_IRQ_VBAT = 6,\n\tPM8607_IRQ_VCHG = 7,\n\tPM8607_IRQ_VSYS = 8,\n\tPM8607_IRQ_TINT = 9,\n\tPM8607_IRQ_GPADC0 = 10,\n\tPM8607_IRQ_GPADC1 = 11,\n\tPM8607_IRQ_GPADC2 = 12,\n\tPM8607_IRQ_GPADC3 = 13,\n\tPM8607_IRQ_AUDIO_SHORT = 14,\n\tPM8607_IRQ_PEN = 15,\n\tPM8607_IRQ_HEADSET = 16,\n\tPM8607_IRQ_HOOK = 17,\n\tPM8607_IRQ_MICIN = 18,\n\tPM8607_IRQ_CHG_FAIL = 19,\n\tPM8607_IRQ_CHG_DONE = 20,\n\tPM8607_IRQ_CHG_FAULT = 21,\n};\n\nstruct pm860x_chip {\n\tstruct device *dev;\n\tstruct mutex irq_lock;\n\tstruct mutex osc_lock;\n\tstruct i2c_client *client;\n\tstruct i2c_client *companion;\n\tstruct regmap *regmap;\n\tstruct regmap *regmap_companion;\n\tint buck3_double;\n\tint companion_addr;\n\tshort unsigned int osc_vote;\n\tint id;\n\tint irq_mode;\n\tint irq_base;\n\tint core_irq;\n\tunsigned char chip_version;\n\tunsigned char osc_status;\n\tunsigned int wakeup_flag;\n};\n\nenum {\n\tGI2C_PORT = 0,\n\tPI2C_PORT = 1,\n};\n\nstruct pm860x_backlight_pdata {\n\tint pwm;\n\tint iset;\n};\n\nstruct pm860x_led_pdata {\n\tint iset;\n};\n\nstruct pm860x_rtc_pdata {\n\tint (*sync)(unsigned int);\n\tint vrtc;\n};\n\nstruct pm860x_touch_pdata {\n\tint gpadc_prebias;\n\tint slot_cycle;\n\tint off_scale;\n\tint sw_cal;\n\tint tsi_prebias;\n\tint pen_prebias;\n\tint pen_prechg;\n\tint res_x;\n\tlong unsigned int flags;\n};\n\nstruct pm860x_power_pdata {\n\tint max_capacity;\n\tint resistor;\n};\n\nstruct charger_desc;\n\nstruct pm860x_platform_data {\n\tstruct pm860x_backlight_pdata *backlight;\n\tstruct pm860x_led_pdata *led;\n\tstruct pm860x_rtc_pdata *rtc;\n\tstruct pm860x_touch_pdata *touch;\n\tstruct pm860x_power_pdata *power;\n\tstruct regulator_init_data *buck1;\n\tstruct regulator_init_data *buck2;\n\tstruct regulator_init_data *buck3;\n\tstruct regulator_init_data *ldo1;\n\tstruct regulator_init_data *ldo2;\n\tstruct regulator_init_data *ldo3;\n\tstruct regulator_init_data *ldo4;\n\tstruct regulator_init_data *ldo5;\n\tstruct regulator_init_data *ldo6;\n\tstruct regulator_init_data *ldo7;\n\tstruct regulator_init_data *ldo8;\n\tstruct regulator_init_data *ldo9;\n\tstruct regulator_init_data *ldo10;\n\tstruct regulator_init_data *ldo12;\n\tstruct regulator_init_data *ldo_vibrator;\n\tstruct regulator_init_data *ldo14;\n\tstruct charger_desc *chg_desc;\n\tint companion_addr;\n\tint i2c_port;\n\tint irq_mode;\n\tint irq_base;\n\tint num_leds;\n\tint num_backlights;\n};\n\nenum polling_modes {\n\tCM_POLL_DISABLE = 0,\n\tCM_POLL_ALWAYS = 1,\n\tCM_POLL_EXTERNAL_POWER_ONLY = 2,\n\tCM_POLL_CHARGING_ONLY = 3,\n};\n\nenum data_source {\n\tCM_BATTERY_PRESENT = 0,\n\tCM_NO_BATTERY = 1,\n\tCM_FUEL_GAUGE = 2,\n\tCM_CHARGER_STAT = 3,\n};\n\nstruct charger_regulator;\n\nstruct charger_desc {\n\tconst char *psy_name;\n\tenum polling_modes polling_mode;\n\tunsigned int polling_interval_ms;\n\tunsigned int fullbatt_vchkdrop_uV;\n\tunsigned int fullbatt_uV;\n\tunsigned int fullbatt_soc;\n\tunsigned int fullbatt_full_capacity;\n\tenum data_source battery_present;\n\tconst char **psy_charger_stat;\n\tint num_charger_regulators;\n\tstruct charger_regulator *charger_regulators;\n\tconst struct attribute_group **sysfs_groups;\n\tconst char *psy_fuel_gauge;\n\tconst char *thermal_zone;\n\tint temp_min;\n\tint temp_max;\n\tint temp_diff;\n\tbool measure_battery_temp;\n\tu32 charging_max_duration_ms;\n\tu32 discharging_max_duration_ms;\n};\n\nstruct charger_manager;\n\nstruct charger_cable {\n\tconst char *extcon_name;\n\tconst char *name;\n\tstruct extcon_dev *extcon_dev;\n\tu64 extcon_type;\n\tstruct work_struct wq;\n\tstruct notifier_block nb;\n\tbool attached;\n\tstruct charger_regulator *charger;\n\tint min_uA;\n\tint max_uA;\n\tstruct charger_manager *cm;\n};\n\nstruct charger_regulator {\n\tconst char *regulator_name;\n\tstruct regulator *consumer;\n\tint externally_control;\n\tstruct charger_cable *cables;\n\tint num_cables;\n\tstruct attribute_group attr_grp;\n\tstruct device_attribute attr_name;\n\tstruct device_attribute attr_state;\n\tstruct device_attribute attr_externally_control;\n\tstruct attribute *attrs[4];\n\tstruct charger_manager *cm;\n};\n\nstruct charger_manager {\n\tstruct list_head entry;\n\tstruct device *dev;\n\tstruct charger_desc *desc;\n\tstruct thermal_zone_device *tzd_batt;\n\tbool charger_enabled;\n\tint emergency_stop;\n\tchar psy_name_buf[31];\n\tstruct power_supply_desc charger_psy_desc;\n\tstruct power_supply *charger_psy;\n\tu64 charging_start_time;\n\tu64 charging_end_time;\n\tint battery_status;\n};\n\nstruct pm860x_irq_data {\n\tint reg;\n\tint mask_reg;\n\tint enable;\n\tint offs;\n};\n\nstruct htcpld_chip_platform_data {\n\tunsigned int addr;\n\tunsigned int reset;\n\tunsigned int num_gpios;\n\tunsigned int gpio_out_base;\n\tunsigned int gpio_in_base;\n\tunsigned int irq_base;\n\tunsigned int num_irqs;\n};\n\nstruct htcpld_core_platform_data {\n\tunsigned int int_reset_gpio_hi;\n\tunsigned int int_reset_gpio_lo;\n\tunsigned int i2c_adapter_id;\n\tstruct htcpld_chip_platform_data *chip;\n\tunsigned int num_chip;\n};\n\nstruct htcpld_chip {\n\tspinlock_t lock;\n\tu8 reset;\n\tu8 addr;\n\tstruct device *dev;\n\tstruct i2c_client *client;\n\tu8 cache_out;\n\tstruct gpio_chip chip_out;\n\tu8 cache_in;\n\tstruct gpio_chip chip_in;\n\tu16 irqs_enabled;\n\tuint irq_start;\n\tint nirqs;\n\tunsigned int flow_type;\n\tstruct work_struct set_val_work;\n};\n\nstruct htcpld_data {\n\tu16 irqs_enabled;\n\tuint irq_start;\n\tint nirqs;\n\tuint chained_irq;\n\tunsigned int int_reset_gpio_hi;\n\tunsigned int int_reset_gpio_lo;\n\tstruct htcpld_chip *chip;\n\tunsigned int nchips;\n};\n\nstruct wm8400_platform_data {\n\tint (*platform_init)(struct device *);\n};\n\nstruct wm8400 {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tstruct platform_device regulators[6];\n};\n\nenum wm831x_auxadc {\n\tWM831X_AUX_CAL = 15,\n\tWM831X_AUX_BKUP_BATT = 10,\n\tWM831X_AUX_WALL = 9,\n\tWM831X_AUX_BATT = 8,\n\tWM831X_AUX_USB = 7,\n\tWM831X_AUX_SYSVDD = 6,\n\tWM831X_AUX_BATT_TEMP = 5,\n\tWM831X_AUX_CHIP_TEMP = 4,\n\tWM831X_AUX_AUX4 = 3,\n\tWM831X_AUX_AUX3 = 2,\n\tWM831X_AUX_AUX2 = 1,\n\tWM831X_AUX_AUX1 = 0,\n};\n\nstruct wm831x_backlight_pdata {\n\tint isink;\n\tint max_uA;\n};\n\nstruct wm831x_backup_pdata {\n\tint charger_enable;\n\tint no_constant_voltage;\n\tint vlim;\n\tint ilim;\n};\n\nstruct wm831x_battery_pdata {\n\tint enable;\n\tint fast_enable;\n\tint off_mask;\n\tint trickle_ilim;\n\tint vsel;\n\tint eoc_iterm;\n\tint fast_ilim;\n\tint timeout;\n};\n\nenum wm831x_status_src {\n\tWM831X_STATUS_PRESERVE = 0,\n\tWM831X_STATUS_OTP = 1,\n\tWM831X_STATUS_POWER = 2,\n\tWM831X_STATUS_CHARGER = 3,\n\tWM831X_STATUS_MANUAL = 4,\n};\n\nstruct wm831x_status_pdata {\n\tenum wm831x_status_src default_src;\n\tconst char *name;\n\tconst char *default_trigger;\n};\n\nstruct wm831x_touch_pdata {\n\tint fivewire;\n\tint isel;\n\tint rpu;\n\tint pressure;\n\tunsigned int data_irq;\n\tint data_irqf;\n\tunsigned int pd_irq;\n\tint pd_irqf;\n};\n\nenum wm831x_watchdog_action {\n\tWM831X_WDOG_NONE = 0,\n\tWM831X_WDOG_INTERRUPT = 1,\n\tWM831X_WDOG_RESET = 2,\n\tWM831X_WDOG_WAKE = 3,\n};\n\nstruct wm831x_watchdog_pdata {\n\tenum wm831x_watchdog_action primary;\n\tenum wm831x_watchdog_action secondary;\n\tunsigned int software: 1;\n};\n\nstruct wm831x;\n\nstruct wm831x_pdata {\n\tint wm831x_num;\n\tint (*pre_init)(struct wm831x *);\n\tint (*post_init)(struct wm831x *);\n\tbool irq_cmos;\n\tbool disable_touch;\n\tbool soft_shutdown;\n\tint irq_base;\n\tint gpio_base;\n\tint gpio_defaults[16];\n\tstruct wm831x_backlight_pdata *backlight;\n\tstruct wm831x_backup_pdata *backup;\n\tstruct wm831x_battery_pdata *battery;\n\tstruct wm831x_touch_pdata *touch;\n\tstruct wm831x_watchdog_pdata *watchdog;\n\tstruct wm831x_status_pdata *status[2];\n\tstruct regulator_init_data *dcdc[4];\n\tstruct regulator_init_data *epe[2];\n\tstruct regulator_init_data *ldo[11];\n\tstruct regulator_init_data *isink[2];\n};\n\nenum wm831x_parent {\n\tWM8310 = 33552,\n\tWM8311 = 33553,\n\tWM8312 = 33554,\n\tWM8320 = 33568,\n\tWM8321 = 33569,\n\tWM8325 = 33573,\n\tWM8326 = 33574,\n};\n\ntypedef int (*wm831x_auxadc_read_fn)(struct wm831x *, enum wm831x_auxadc);\n\nstruct wm831x {\n\tstruct mutex io_lock;\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tstruct wm831x_pdata pdata;\n\tenum wm831x_parent type;\n\tint irq;\n\tstruct mutex irq_lock;\n\tstruct irq_domain *irq_domain;\n\tint irq_masks_cur[5];\n\tint irq_masks_cache[5];\n\tbool soft_shutdown;\n\tunsigned int has_gpio_ena: 1;\n\tunsigned int has_cs_sts: 1;\n\tunsigned int charger_irq_wake: 1;\n\tint num_gpio;\n\tint gpio_update[16];\n\tbool gpio_level_high[16];\n\tbool gpio_level_low[16];\n\tstruct mutex auxadc_lock;\n\tstruct list_head auxadc_pending;\n\tu16 auxadc_active;\n\twm831x_auxadc_read_fn auxadc_read;\n\tstruct mutex key_lock;\n\tunsigned int locked: 1;\n};\n\nstruct wm831x_irq_data {\n\tint primary;\n\tint reg;\n\tint mask;\n};\n\nstruct wm831x_auxadc_req {\n\tstruct list_head list;\n\tenum wm831x_auxadc input;\n\tint val;\n\tstruct completion done;\n};\n\nstruct spi_device_id {\n\tchar name[32];\n\tkernel_ulong_t driver_data;\n};\n\nstruct spi_driver {\n\tconst struct spi_device_id *id_table;\n\tint (*probe)(struct spi_device *);\n\tint (*remove)(struct spi_device *);\n\tvoid (*shutdown)(struct spi_device *);\n\tstruct device_driver driver;\n};\n\nstruct wm8350_audio_platform_data {\n\tint vmid_discharge_msecs;\n\tint drain_msecs;\n\tint cap_discharge_msecs;\n\tint vmid_charge_msecs;\n\tu32 vmid_s_curve: 2;\n\tu32 dis_out4: 2;\n\tu32 dis_out3: 2;\n\tu32 dis_out2: 2;\n\tu32 dis_out1: 2;\n\tu32 vroi_out4: 1;\n\tu32 vroi_out3: 1;\n\tu32 vroi_out2: 1;\n\tu32 vroi_out1: 1;\n\tu32 vroi_enable: 1;\n\tu32 codec_current_on: 2;\n\tu32 codec_current_standby: 2;\n\tu32 codec_current_charge: 2;\n};\n\nstruct wm8350_codec {\n\tstruct platform_device *pdev;\n\tstruct wm8350_audio_platform_data *platform_data;\n};\n\nstruct wm8350_gpio {\n\tstruct platform_device *pdev;\n};\n\nstruct wm8350_led {\n\tstruct platform_device *pdev;\n\tstruct work_struct work;\n\tspinlock_t value_lock;\n\tenum led_brightness value;\n\tstruct led_classdev cdev;\n\tint max_uA_index;\n\tint enabled;\n\tstruct regulator *isink;\n\tstruct regulator_consumer_supply isink_consumer;\n\tstruct regulator_init_data isink_init;\n\tstruct regulator *dcdc;\n\tstruct regulator_consumer_supply dcdc_consumer;\n\tstruct regulator_init_data dcdc_init;\n};\n\nstruct wm8350_pmic {\n\tint max_dcdc;\n\tint max_isink;\n\tint isink_A_dcdc;\n\tint isink_B_dcdc;\n\tu16 dcdc1_hib_mode;\n\tu16 dcdc3_hib_mode;\n\tu16 dcdc4_hib_mode;\n\tu16 dcdc6_hib_mode;\n\tstruct platform_device *pdev[12];\n\tstruct wm8350_led led[2];\n};\n\nstruct rtc_device___2;\n\nstruct wm8350_rtc {\n\tstruct platform_device *pdev;\n\tstruct rtc_device___2 *rtc;\n\tint alarm_enabled;\n\tint update_enabled;\n};\n\nstruct wm8350_charger_policy {\n\tint eoc_mA;\n\tint charge_mV;\n\tint fast_limit_mA;\n\tint fast_limit_USB_mA;\n\tint charge_timeout;\n\tint trickle_start_mV;\n\tint trickle_charge_mA;\n\tint trickle_charge_USB_mA;\n};\n\nstruct wm8350_power {\n\tstruct platform_device *pdev;\n\tstruct power_supply *battery;\n\tstruct power_supply *usb;\n\tstruct power_supply *ac;\n\tstruct wm8350_charger_policy *policy;\n\tint rev_g_coeff;\n};\n\nstruct wm8350_wdt {\n\tstruct platform_device *pdev;\n};\n\nstruct wm8350_hwmon {\n\tstruct platform_device *pdev;\n\tstruct device *classdev;\n};\n\nstruct wm8350 {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tbool unlocked;\n\tstruct mutex auxadc_mutex;\n\tstruct completion auxadc_done;\n\tstruct mutex irq_lock;\n\tint chip_irq;\n\tint irq_base;\n\tu16 irq_masks[7];\n\tstruct wm8350_codec codec;\n\tstruct wm8350_gpio gpio;\n\tstruct wm8350_hwmon hwmon;\n\tstruct wm8350_pmic pmic;\n\tstruct wm8350_power power;\n\tstruct wm8350_rtc rtc;\n\tstruct wm8350_wdt wdt;\n};\n\nstruct wm8350_platform_data {\n\tint (*init)(struct wm8350 *);\n\tint irq_high;\n\tint irq_base;\n\tint gpio_base;\n};\n\nstruct wm8350_reg_access {\n\tu16 readable;\n\tu16 writable;\n\tu16 vol;\n};\n\nstruct wm8350_irq_data {\n\tint primary;\n\tint reg;\n\tint mask;\n\tint primary_only;\n};\n\nstruct tps65910_platform_data {\n\tint irq;\n\tint irq_base;\n};\n\nenum chips {\n\tTPS80031 = 1,\n\tTPS80032 = 2,\n};\n\nenum {\n\tTPS80031_INT_PWRON = 0,\n\tTPS80031_INT_RPWRON = 1,\n\tTPS80031_INT_SYS_VLOW = 2,\n\tTPS80031_INT_RTC_ALARM = 3,\n\tTPS80031_INT_RTC_PERIOD = 4,\n\tTPS80031_INT_HOT_DIE = 5,\n\tTPS80031_INT_VXX_SHORT = 6,\n\tTPS80031_INT_SPDURATION = 7,\n\tTPS80031_INT_WATCHDOG = 8,\n\tTPS80031_INT_BAT = 9,\n\tTPS80031_INT_SIM = 10,\n\tTPS80031_INT_MMC = 11,\n\tTPS80031_INT_RES = 12,\n\tTPS80031_INT_GPADC_RT = 13,\n\tTPS80031_INT_GPADC_SW2_EOC = 14,\n\tTPS80031_INT_CC_AUTOCAL = 15,\n\tTPS80031_INT_ID_WKUP = 16,\n\tTPS80031_INT_VBUSS_WKUP = 17,\n\tTPS80031_INT_ID = 18,\n\tTPS80031_INT_VBUS = 19,\n\tTPS80031_INT_CHRG_CTRL = 20,\n\tTPS80031_INT_EXT_CHRG = 21,\n\tTPS80031_INT_INT_CHRG = 22,\n\tTPS80031_INT_RES2 = 23,\n\tTPS80031_INT_BAT_TEMP_OVRANGE = 24,\n\tTPS80031_INT_BAT_REMOVED = 25,\n\tTPS80031_INT_VBUS_DET = 26,\n\tTPS80031_INT_VAC_DET = 27,\n\tTPS80031_INT_FAULT_WDG = 28,\n\tTPS80031_INT_LINCH_GATED = 29,\n\tTPS80031_INT_NR = 30,\n};\n\nenum {\n\tTPS80031_REGULATOR_VIO = 0,\n\tTPS80031_REGULATOR_SMPS1 = 1,\n\tTPS80031_REGULATOR_SMPS2 = 2,\n\tTPS80031_REGULATOR_SMPS3 = 3,\n\tTPS80031_REGULATOR_SMPS4 = 4,\n\tTPS80031_REGULATOR_VANA = 5,\n\tTPS80031_REGULATOR_LDO1 = 6,\n\tTPS80031_REGULATOR_LDO2 = 7,\n\tTPS80031_REGULATOR_LDO3 = 8,\n\tTPS80031_REGULATOR_LDO4 = 9,\n\tTPS80031_REGULATOR_LDO5 = 10,\n\tTPS80031_REGULATOR_LDO6 = 11,\n\tTPS80031_REGULATOR_LDO7 = 12,\n\tTPS80031_REGULATOR_LDOLN = 13,\n\tTPS80031_REGULATOR_LDOUSB = 14,\n\tTPS80031_REGULATOR_VBUS = 15,\n\tTPS80031_REGULATOR_REGEN1 = 16,\n\tTPS80031_REGULATOR_REGEN2 = 17,\n\tTPS80031_REGULATOR_SYSEN = 18,\n\tTPS80031_REGULATOR_MAX = 19,\n};\n\nenum tps80031_ext_control {\n\tTPS80031_PWR_REQ_INPUT_NONE = 0,\n\tTPS80031_PWR_REQ_INPUT_PREQ1 = 1,\n\tTPS80031_PWR_REQ_INPUT_PREQ2 = 2,\n\tTPS80031_PWR_REQ_INPUT_PREQ3 = 4,\n\tTPS80031_PWR_OFF_ON_SLEEP = 8,\n\tTPS80031_PWR_ON_ON_SLEEP = 16,\n};\n\nenum tps80031_pupd_pins {\n\tTPS80031_PREQ1 = 0,\n\tTPS80031_PREQ2A = 1,\n\tTPS80031_PREQ2B = 2,\n\tTPS80031_PREQ2C = 3,\n\tTPS80031_PREQ3 = 4,\n\tTPS80031_NRES_WARM = 5,\n\tTPS80031_PWM_FORCE = 6,\n\tTPS80031_CHRG_EXT_CHRG_STATZ = 7,\n\tTPS80031_SIM = 8,\n\tTPS80031_MMC = 9,\n\tTPS80031_GPADC_START = 10,\n\tTPS80031_DVSI2C_SCL = 11,\n\tTPS80031_DVSI2C_SDA = 12,\n\tTPS80031_CTLI2C_SCL = 13,\n\tTPS80031_CTLI2C_SDA = 14,\n};\n\nenum tps80031_pupd_settings {\n\tTPS80031_PUPD_NORMAL = 0,\n\tTPS80031_PUPD_PULLDOWN = 1,\n\tTPS80031_PUPD_PULLUP = 2,\n};\n\nstruct tps80031 {\n\tstruct device *dev;\n\tlong unsigned int chip_info;\n\tint es_version;\n\tstruct i2c_client *clients[4];\n\tstruct regmap *regmap[4];\n\tstruct regmap_irq_chip_data *irq_data;\n};\n\nstruct tps80031_pupd_init_data {\n\tint input_pin;\n\tint setting;\n};\n\nstruct tps80031_regulator_platform_data {\n\tstruct regulator_init_data *reg_init_data;\n\tunsigned int ext_ctrl_flag;\n\tunsigned int config_flags;\n};\n\nstruct tps80031_platform_data {\n\tint irq_base;\n\tbool use_power_off;\n\tstruct tps80031_pupd_init_data *pupd_init_data;\n\tint pupd_init_data_size;\n\tstruct tps80031_regulator_platform_data *regulator_pdata[19];\n};\n\nstruct tps80031_pupd_data {\n\tu8 reg;\n\tu8 pullup_bit;\n\tu8 pulldown_bit;\n};\n\nstruct of_dev_auxdata {\n\tchar *compatible;\n\tresource_size_t phys_addr;\n\tchar *name;\n\tvoid *platform_data;\n};\n\nstruct matrix_keymap_data {\n\tconst uint32_t *keymap;\n\tunsigned int keymap_size;\n};\n\nenum twl_module_ids {\n\tTWL_MODULE_USB = 0,\n\tTWL_MODULE_PIH = 1,\n\tTWL_MODULE_MAIN_CHARGE = 2,\n\tTWL_MODULE_PM_MASTER = 3,\n\tTWL_MODULE_PM_RECEIVER = 4,\n\tTWL_MODULE_RTC = 5,\n\tTWL_MODULE_PWM = 6,\n\tTWL_MODULE_LED = 7,\n\tTWL_MODULE_SECURED_REG = 8,\n\tTWL_MODULE_LAST = 9,\n};\n\nenum twl4030_module_ids {\n\tTWL4030_MODULE_AUDIO_VOICE = 9,\n\tTWL4030_MODULE_GPIO = 10,\n\tTWL4030_MODULE_INTBR = 11,\n\tTWL4030_MODULE_TEST = 12,\n\tTWL4030_MODULE_KEYPAD = 13,\n\tTWL4030_MODULE_MADC = 14,\n\tTWL4030_MODULE_INTERRUPTS = 15,\n\tTWL4030_MODULE_PRECHARGE = 16,\n\tTWL4030_MODULE_BACKUP = 17,\n\tTWL4030_MODULE_INT = 18,\n\tTWL5031_MODULE_ACCESSORY = 19,\n\tTWL5031_MODULE_INTERRUPTS = 20,\n\tTWL4030_MODULE_LAST = 21,\n};\n\nenum twl6030_module_ids {\n\tTWL6030_MODULE_ID0 = 9,\n\tTWL6030_MODULE_ID1 = 10,\n\tTWL6030_MODULE_ID2 = 11,\n\tTWL6030_MODULE_GPADC = 12,\n\tTWL6030_MODULE_GASGAUGE = 13,\n\tTWL6030_MODULE_LAST = 14,\n};\n\nstruct twl4030_clock_init_data {\n\tbool ck32k_lowpwr_enable;\n};\n\nstruct twl4030_bci_platform_data {\n\tint *battery_tmp_tbl;\n\tunsigned int tblsize;\n\tint bb_uvolt;\n\tint bb_uamp;\n};\n\nstruct twl4030_gpio_platform_data {\n\tbool use_leds;\n\tu8 mmc_cd;\n\tu32 debounce;\n\tu32 pullups;\n\tu32 pulldowns;\n\tint (*setup)(struct device *, unsigned int, unsigned int);\n\tint (*teardown)(struct device *, unsigned int, unsigned int);\n};\n\nstruct twl4030_madc_platform_data {\n\tint irq_line;\n};\n\nstruct twl4030_keypad_data {\n\tconst struct matrix_keymap_data *keymap_data;\n\tunsigned int rows;\n\tunsigned int cols;\n\tbool rep;\n};\n\nenum twl4030_usb_mode {\n\tT2_USB_MODE_ULPI = 1,\n\tT2_USB_MODE_CEA2011_3PIN = 2,\n};\n\nstruct twl4030_usb_data {\n\tenum twl4030_usb_mode usb_mode;\n\tlong unsigned int features;\n\tint (*phy_init)(struct device *);\n\tint (*phy_exit)(struct device *);\n\tint (*phy_power)(struct device *, int, int);\n\tint (*phy_set_clock)(struct device *, int);\n\tint (*phy_suspend)(struct device *, int);\n};\n\nstruct twl4030_ins {\n\tu16 pmb_message;\n\tu8 delay;\n};\n\nstruct twl4030_script {\n\tstruct twl4030_ins *script;\n\tunsigned int size;\n\tu8 flags;\n};\n\nstruct twl4030_resconfig {\n\tu8 resource;\n\tu8 devgroup;\n\tu8 type;\n\tu8 type2;\n\tu8 remap_off;\n\tu8 remap_sleep;\n};\n\nstruct twl4030_power_data {\n\tstruct twl4030_script **scripts;\n\tunsigned int num;\n\tstruct twl4030_resconfig *resource_config;\n\tstruct twl4030_resconfig *board_config;\n\tbool use_poweroff;\n\tbool ac_charger_quirk;\n};\n\nstruct twl4030_codec_data {\n\tunsigned int digimic_delay;\n\tunsigned int ramp_delay_value;\n\tunsigned int offset_cncl_path;\n\tunsigned int hs_extmute: 1;\n\tint hs_extmute_gpio;\n};\n\nstruct twl4030_vibra_data {\n\tunsigned int coexist;\n};\n\nstruct twl4030_audio_data {\n\tunsigned int audio_mclk;\n\tstruct twl4030_codec_data *codec;\n\tstruct twl4030_vibra_data *vibra;\n\tint audpwron_gpio;\n\tint naudint_irq;\n\tunsigned int irq_base;\n};\n\nstruct twl4030_platform_data {\n\tstruct twl4030_clock_init_data *clock;\n\tstruct twl4030_bci_platform_data *bci;\n\tstruct twl4030_gpio_platform_data *gpio;\n\tstruct twl4030_madc_platform_data *madc;\n\tstruct twl4030_keypad_data *keypad;\n\tstruct twl4030_usb_data *usb;\n\tstruct twl4030_power_data *power;\n\tstruct twl4030_audio_data *audio;\n\tstruct regulator_init_data *vdac;\n\tstruct regulator_init_data *vaux1;\n\tstruct regulator_init_data *vaux2;\n\tstruct regulator_init_data *vaux3;\n\tstruct regulator_init_data *vdd1;\n\tstruct regulator_init_data *vdd2;\n\tstruct regulator_init_data *vdd3;\n\tstruct regulator_init_data *vpll1;\n\tstruct regulator_init_data *vpll2;\n\tstruct regulator_init_data *vmmc1;\n\tstruct regulator_init_data *vmmc2;\n\tstruct regulator_init_data *vsim;\n\tstruct regulator_init_data *vaux4;\n\tstruct regulator_init_data *vio;\n\tstruct regulator_init_data *vintana1;\n\tstruct regulator_init_data *vintana2;\n\tstruct regulator_init_data *vintdig;\n\tstruct regulator_init_data *vmmc;\n\tstruct regulator_init_data *vpp;\n\tstruct regulator_init_data *vusim;\n\tstruct regulator_init_data *vana;\n\tstruct regulator_init_data *vcxio;\n\tstruct regulator_init_data *vusb;\n\tstruct regulator_init_data *clk32kg;\n\tstruct regulator_init_data *v1v8;\n\tstruct regulator_init_data *v2v1;\n\tstruct regulator_init_data *ldo1;\n\tstruct regulator_init_data *ldo2;\n\tstruct regulator_init_data *ldo3;\n\tstruct regulator_init_data *ldo4;\n\tstruct regulator_init_data *ldo5;\n\tstruct regulator_init_data *ldo6;\n\tstruct regulator_init_data *ldo7;\n\tstruct regulator_init_data *ldoln;\n\tstruct regulator_init_data *ldousb;\n\tstruct regulator_init_data *smps3;\n\tstruct regulator_init_data *smps4;\n\tstruct regulator_init_data *vio6025;\n};\n\nstruct twl_regulator_driver_data {\n\tint (*set_voltage)(void *, int);\n\tint (*get_voltage)(void *);\n\tvoid *data;\n\tlong unsigned int features;\n};\n\nstruct twl_client {\n\tstruct i2c_client *client;\n\tstruct regmap *regmap;\n};\n\nstruct twl_mapping {\n\tunsigned char sid;\n\tunsigned char base;\n};\n\nstruct twl_private {\n\tbool ready;\n\tu32 twl_idcode;\n\tunsigned int twl_id;\n\tstruct twl_mapping *twl_map;\n\tstruct twl_client *twl_modules;\n};\n\nstruct sih_irq_data {\n\tu8 isr_offset;\n\tu8 imr_offset;\n};\n\nstruct sih {\n\tchar name[8];\n\tu8 module;\n\tu8 control_offset;\n\tbool set_cor;\n\tu8 bits;\n\tu8 bytes_ixr;\n\tu8 edr_offset;\n\tu8 bytes_edr;\n\tu8 irq_lines;\n\tstruct sih_irq_data mask[2];\n};\n\nstruct sih_agent {\n\tint irq_base;\n\tconst struct sih *sih;\n\tu32 imr;\n\tbool imr_change_pending;\n\tu32 edge_change;\n\tstruct mutex irq_lock;\n\tchar *irq_name;\n};\n\nstruct twl6030_irq {\n\tunsigned int irq_base;\n\tint twl_irq;\n\tbool irq_wake_enabled;\n\tatomic_t wakeirqs;\n\tstruct notifier_block pm_nb;\n\tstruct irq_chip irq_chip;\n\tstruct irq_domain *irq_domain;\n\tconst int *irq_mapping_tbl;\n};\n\nenum twl4030_audio_res {\n\tTWL4030_AUDIO_RES_POWER = 0,\n\tTWL4030_AUDIO_RES_APLL = 1,\n\tTWL4030_AUDIO_RES_MAX = 2,\n};\n\nstruct twl4030_audio_resource {\n\tint request_count;\n\tu8 reg;\n\tu8 mask;\n};\n\nstruct twl4030_audio {\n\tunsigned int audio_mclk;\n\tstruct mutex mutex;\n\tstruct twl4030_audio_resource resource[2];\n\tstruct mfd_cell cells[2];\n};\n\nenum of_gpio_flags {\n\tOF_GPIO_ACTIVE_LOW = 1,\n\tOF_GPIO_SINGLE_ENDED = 2,\n\tOF_GPIO_OPEN_DRAIN = 4,\n\tOF_GPIO_TRANSITORY = 8,\n\tOF_GPIO_PULL_UP = 16,\n\tOF_GPIO_PULL_DOWN = 32,\n};\n\nstruct twl6040 {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tstruct regmap_irq_chip_data *irq_data;\n\tstruct regulator_bulk_data supplies[2];\n\tstruct clk *clk32k;\n\tstruct clk *mclk;\n\tstruct mutex mutex;\n\tstruct mutex irq_mutex;\n\tstruct mfd_cell cells[4];\n\tstruct completion ready;\n\tint audpwron;\n\tint power_count;\n\tint rev;\n\tint pll;\n\tunsigned int sysclk_rate;\n\tunsigned int mclk_rate;\n\tunsigned int irq;\n\tunsigned int irq_ready;\n\tunsigned int irq_th;\n};\n\nstruct mfd_of_node_entry {\n\tstruct list_head list;\n\tstruct device *dev;\n\tstruct device_node *np;\n};\n\nstruct pcap_subdev {\n\tint id;\n\tconst char *name;\n\tvoid *platform_data;\n};\n\nstruct pcap_platform_data {\n\tunsigned int irq_base;\n\tunsigned int config;\n\tint gpio;\n\tvoid (*init)(void *);\n\tint num_subdevs;\n\tstruct pcap_subdev *subdevs;\n};\n\nstruct pcap_adc_request {\n\tu8 bank;\n\tu8 ch[2];\n\tu32 flags;\n\tvoid (*callback)(void *, u16 *);\n\tvoid *data;\n};\n\nstruct pcap_adc_sync_request {\n\tu16 res[2];\n\tstruct completion completion;\n};\n\nstruct pcap_chip {\n\tstruct spi_device *spi;\n\tu32 buf;\n\tspinlock_t io_lock;\n\tunsigned int irq_base;\n\tu32 msr;\n\tstruct work_struct isr_work;\n\tstruct work_struct msr_work;\n\tstruct workqueue_struct *workqueue;\n\tstruct pcap_adc_request *adc_queue[8];\n\tu8 adc_head;\n\tu8 adc_tail;\n\tspinlock_t adc_lock;\n};\n\nstruct da903x_subdev_info {\n\tint id;\n\tconst char *name;\n\tvoid *platform_data;\n};\n\nstruct da903x_platform_data {\n\tint num_subdevs;\n\tstruct da903x_subdev_info *subdevs;\n};\n\nstruct da903x_chip;\n\nstruct da903x_chip_ops {\n\tint (*init_chip)(struct da903x_chip *);\n\tint (*unmask_events)(struct da903x_chip *, unsigned int);\n\tint (*mask_events)(struct da903x_chip *, unsigned int);\n\tint (*read_events)(struct da903x_chip *, unsigned int *);\n\tint (*read_status)(struct da903x_chip *, unsigned int *);\n};\n\nstruct da903x_chip {\n\tstruct i2c_client *client;\n\tstruct device *dev;\n\tconst struct da903x_chip_ops *ops;\n\tint type;\n\tuint32_t events_mask;\n\tstruct mutex lock;\n\tstruct work_struct irq_work;\n\tstruct blocking_notifier_head notifier_list;\n};\n\nstruct da9052 {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tstruct mutex auxadc_lock;\n\tstruct completion done;\n\tint irq_base;\n\tstruct regmap_irq_chip_data *irq_data;\n\tu8 chip_id;\n\tint chip_irq;\n\tint (*fix_io)(struct da9052 *, unsigned char);\n};\n\nstruct led_platform_data;\n\nstruct da9052_pdata {\n\tstruct led_platform_data *pled;\n\tint (*init)(struct da9052 *);\n\tint irq_base;\n\tint gpio_base;\n\tint use_for_apm;\n\tstruct regulator_init_data *regulators[14];\n};\n\nenum da9052_chip_id {\n\tDA9052 = 0,\n\tDA9053_AA = 1,\n\tDA9053_BA = 2,\n\tDA9053_BB = 3,\n\tDA9053_BC = 4,\n};\n\nenum lp8788_int_id {\n\tLP8788_INT_TSDL = 0,\n\tLP8788_INT_TSDH = 1,\n\tLP8788_INT_UVLO = 2,\n\tLP8788_INT_FLAGMON = 3,\n\tLP8788_INT_PWRON_TIME = 4,\n\tLP8788_INT_PWRON = 5,\n\tLP8788_INT_COMP1 = 6,\n\tLP8788_INT_COMP2 = 7,\n\tLP8788_INT_CHG_INPUT_STATE = 8,\n\tLP8788_INT_CHG_STATE = 9,\n\tLP8788_INT_EOC = 10,\n\tLP8788_INT_CHG_RESTART = 11,\n\tLP8788_INT_RESTART_TIMEOUT = 12,\n\tLP8788_INT_FULLCHG_TIMEOUT = 13,\n\tLP8788_INT_PRECHG_TIMEOUT = 14,\n\tLP8788_INT_RTC_ALARM1 = 17,\n\tLP8788_INT_RTC_ALARM2 = 18,\n\tLP8788_INT_ENTER_SYS_SUPPORT = 19,\n\tLP8788_INT_EXIT_SYS_SUPPORT = 20,\n\tLP8788_INT_BATT_LOW = 21,\n\tLP8788_INT_NO_BATT = 22,\n\tLP8788_INT_MAX = 24,\n};\n\nenum lp8788_dvs_sel {\n\tDVS_SEL_V0 = 0,\n\tDVS_SEL_V1 = 1,\n\tDVS_SEL_V2 = 2,\n\tDVS_SEL_V3 = 3,\n};\n\nenum lp8788_charger_event {\n\tNO_CHARGER = 0,\n\tCHARGER_DETECTED = 1,\n};\n\nenum lp8788_bl_ctrl_mode {\n\tLP8788_BL_REGISTER_ONLY = 0,\n\tLP8788_BL_COMB_PWM_BASED = 1,\n\tLP8788_BL_COMB_REGISTER_BASED = 2,\n};\n\nenum lp8788_bl_dim_mode {\n\tLP8788_DIM_EXPONENTIAL = 0,\n\tLP8788_DIM_LINEAR = 1,\n};\n\nenum lp8788_bl_full_scale_current {\n\tLP8788_FULLSCALE_5000uA = 0,\n\tLP8788_FULLSCALE_8500uA = 1,\n\tLP8788_FULLSCALE_1200uA = 2,\n\tLP8788_FULLSCALE_1550uA = 3,\n\tLP8788_FULLSCALE_1900uA = 4,\n\tLP8788_FULLSCALE_2250uA = 5,\n\tLP8788_FULLSCALE_2600uA = 6,\n\tLP8788_FULLSCALE_2950uA = 7,\n};\n\nenum lp8788_bl_ramp_step {\n\tLP8788_RAMP_8us = 0,\n\tLP8788_RAMP_1024us = 1,\n\tLP8788_RAMP_2048us = 2,\n\tLP8788_RAMP_4096us = 3,\n\tLP8788_RAMP_8192us = 4,\n\tLP8788_RAMP_16384us = 5,\n\tLP8788_RAMP_32768us = 6,\n\tLP8788_RAMP_65538us = 7,\n};\n\nenum lp8788_isink_scale {\n\tLP8788_ISINK_SCALE_100mA = 0,\n\tLP8788_ISINK_SCALE_120mA = 1,\n};\n\nenum lp8788_isink_number {\n\tLP8788_ISINK_1 = 0,\n\tLP8788_ISINK_2 = 1,\n\tLP8788_ISINK_3 = 2,\n};\n\nenum lp8788_alarm_sel {\n\tLP8788_ALARM_1 = 0,\n\tLP8788_ALARM_2 = 1,\n\tLP8788_ALARM_MAX = 2,\n};\n\nstruct lp8788_buck1_dvs {\n\tint gpio;\n\tenum lp8788_dvs_sel vsel;\n};\n\nstruct lp8788_buck2_dvs {\n\tint gpio[2];\n\tenum lp8788_dvs_sel vsel;\n};\n\nstruct lp8788_chg_param {\n\tu8 addr;\n\tu8 val;\n};\n\nstruct lp8788;\n\nstruct lp8788_charger_platform_data {\n\tconst char *adc_vbatt;\n\tconst char *adc_batt_temp;\n\tunsigned int max_vbatt_mv;\n\tstruct lp8788_chg_param *chg_params;\n\tint num_chg_params;\n\tvoid (*charger_event)(struct lp8788 *, enum lp8788_charger_event);\n};\n\nstruct lp8788_platform_data;\n\nstruct lp8788 {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tstruct irq_domain *irqdm;\n\tint irq;\n\tstruct lp8788_platform_data *pdata;\n};\n\nstruct lp8788_backlight_platform_data {\n\tchar *name;\n\tint initial_brightness;\n\tenum lp8788_bl_ctrl_mode bl_mode;\n\tenum lp8788_bl_dim_mode dim_mode;\n\tenum lp8788_bl_full_scale_current full_scale;\n\tenum lp8788_bl_ramp_step rise_time;\n\tenum lp8788_bl_ramp_step fall_time;\n\tenum pwm_polarity pwm_pol;\n\tunsigned int period_ns;\n};\n\nstruct lp8788_led_platform_data {\n\tchar *name;\n\tenum lp8788_isink_scale scale;\n\tenum lp8788_isink_number num;\n\tint iout_code;\n};\n\nstruct lp8788_vib_platform_data {\n\tchar *name;\n\tenum lp8788_isink_scale scale;\n\tenum lp8788_isink_number num;\n\tint iout_code;\n\tint pwm_code;\n};\n\nstruct iio_map;\n\nstruct lp8788_platform_data {\n\tint (*init_func)(struct lp8788 *);\n\tstruct regulator_init_data *buck_data[4];\n\tstruct regulator_init_data *dldo_data[12];\n\tstruct regulator_init_data *aldo_data[10];\n\tstruct lp8788_buck1_dvs *buck1_dvs;\n\tstruct lp8788_buck2_dvs *buck2_dvs;\n\tstruct lp8788_charger_platform_data *chg_pdata;\n\tenum lp8788_alarm_sel alarm_sel;\n\tstruct lp8788_backlight_platform_data *bl_pdata;\n\tstruct lp8788_led_platform_data *led_pdata;\n\tstruct lp8788_vib_platform_data *vib_pdata;\n\tstruct iio_map *adc_pdata;\n};\n\nstruct lp8788_irq_data {\n\tstruct lp8788 *lp;\n\tstruct mutex irq_lock;\n\tstruct irq_domain *domain;\n\tint enabled[24];\n};\n\nstruct da9055 {\n\tstruct regmap *regmap;\n\tstruct regmap_irq_chip_data *irq_data;\n\tstruct device *dev;\n\tstruct i2c_client *i2c_client;\n\tint irq_base;\n\tint chip_irq;\n};\n\nenum gpio_select {\n\tNO_GPIO = 0,\n\tGPIO_1 = 1,\n\tGPIO_2 = 2,\n};\n\nstruct da9055_pdata {\n\tint (*init)(struct da9055 *);\n\tint irq_base;\n\tint gpio_base;\n\tstruct regulator_init_data *regulators[8];\n\tbool reset_enable;\n\tint *gpio_ren;\n\tint *gpio_rsel;\n\tenum gpio_select *reg_ren;\n\tenum gpio_select *reg_rsel;\n\tstruct gpio_desc **ena_gpiods;\n};\n\nenum max77693_types {\n\tTYPE_MAX77693_UNKNOWN = 0,\n\tTYPE_MAX77693 = 1,\n\tTYPE_MAX77843 = 2,\n\tTYPE_MAX77693_NUM = 3,\n};\n\nstruct max77693_dev {\n\tstruct device *dev;\n\tstruct i2c_client *i2c;\n\tstruct i2c_client *i2c_muic;\n\tstruct i2c_client *i2c_haptic;\n\tstruct i2c_client *i2c_chg;\n\tenum max77693_types type;\n\tstruct regmap *regmap;\n\tstruct regmap *regmap_muic;\n\tstruct regmap *regmap_haptic;\n\tstruct regmap *regmap_chg;\n\tstruct regmap_irq_chip_data *irq_data_led;\n\tstruct regmap_irq_chip_data *irq_data_topsys;\n\tstruct regmap_irq_chip_data *irq_data_chg;\n\tstruct regmap_irq_chip_data *irq_data_muic;\n\tint irq;\n};\n\nenum max77843_sys_reg {\n\tMAX77843_SYS_REG_PMICID = 0,\n\tMAX77843_SYS_REG_PMICREV = 1,\n\tMAX77843_SYS_REG_MAINCTRL1 = 2,\n\tMAX77843_SYS_REG_INTSRC = 34,\n\tMAX77843_SYS_REG_INTSRCMASK = 35,\n\tMAX77843_SYS_REG_SYSINTSRC = 36,\n\tMAX77843_SYS_REG_SYSINTMASK = 38,\n\tMAX77843_SYS_REG_TOPSYS_STAT = 40,\n\tMAX77843_SYS_REG_SAFEOUTCTRL = 198,\n\tMAX77843_SYS_REG_END = 199,\n};\n\nenum max77843_charger_reg {\n\tMAX77843_CHG_REG_CHG_INT = 176,\n\tMAX77843_CHG_REG_CHG_INT_MASK = 177,\n\tMAX77843_CHG_REG_CHG_INT_OK = 178,\n\tMAX77843_CHG_REG_CHG_DTLS_00 = 179,\n\tMAX77843_CHG_REG_CHG_DTLS_01 = 180,\n\tMAX77843_CHG_REG_CHG_DTLS_02 = 181,\n\tMAX77843_CHG_REG_CHG_CNFG_00 = 183,\n\tMAX77843_CHG_REG_CHG_CNFG_01 = 184,\n\tMAX77843_CHG_REG_CHG_CNFG_02 = 185,\n\tMAX77843_CHG_REG_CHG_CNFG_03 = 186,\n\tMAX77843_CHG_REG_CHG_CNFG_04 = 187,\n\tMAX77843_CHG_REG_CHG_CNFG_06 = 189,\n\tMAX77843_CHG_REG_CHG_CNFG_07 = 190,\n\tMAX77843_CHG_REG_CHG_CNFG_09 = 192,\n\tMAX77843_CHG_REG_CHG_CNFG_10 = 193,\n\tMAX77843_CHG_REG_CHG_CNFG_11 = 194,\n\tMAX77843_CHG_REG_CHG_CNFG_12 = 195,\n\tMAX77843_CHG_REG_END = 196,\n};\n\nenum {\n\tMAX8925_IRQ_VCHG_DC_OVP = 0,\n\tMAX8925_IRQ_VCHG_DC_F = 1,\n\tMAX8925_IRQ_VCHG_DC_R = 2,\n\tMAX8925_IRQ_VCHG_THM_OK_R = 3,\n\tMAX8925_IRQ_VCHG_THM_OK_F = 4,\n\tMAX8925_IRQ_VCHG_SYSLOW_F = 5,\n\tMAX8925_IRQ_VCHG_SYSLOW_R = 6,\n\tMAX8925_IRQ_VCHG_RST = 7,\n\tMAX8925_IRQ_VCHG_DONE = 8,\n\tMAX8925_IRQ_VCHG_TOPOFF = 9,\n\tMAX8925_IRQ_VCHG_TMR_FAULT = 10,\n\tMAX8925_IRQ_GPM_RSTIN = 11,\n\tMAX8925_IRQ_GPM_MPL = 12,\n\tMAX8925_IRQ_GPM_SW_3SEC = 13,\n\tMAX8925_IRQ_GPM_EXTON_F = 14,\n\tMAX8925_IRQ_GPM_EXTON_R = 15,\n\tMAX8925_IRQ_GPM_SW_1SEC = 16,\n\tMAX8925_IRQ_GPM_SW_F = 17,\n\tMAX8925_IRQ_GPM_SW_R = 18,\n\tMAX8925_IRQ_GPM_SYSCKEN_F = 19,\n\tMAX8925_IRQ_GPM_SYSCKEN_R = 20,\n\tMAX8925_IRQ_RTC_ALARM1 = 21,\n\tMAX8925_IRQ_RTC_ALARM0 = 22,\n\tMAX8925_IRQ_TSC_STICK = 23,\n\tMAX8925_IRQ_TSC_NSTICK = 24,\n\tMAX8925_NR_IRQS = 25,\n};\n\nstruct max8925_chip {\n\tstruct device *dev;\n\tstruct i2c_client *i2c;\n\tstruct i2c_client *adc;\n\tstruct i2c_client *rtc;\n\tstruct mutex io_lock;\n\tstruct mutex irq_lock;\n\tint irq_base;\n\tint core_irq;\n\tint tsc_irq;\n\tunsigned int wakeup_flag;\n};\n\nstruct max8925_backlight_pdata {\n\tint lxw_scl;\n\tint lxw_freq;\n\tint dual_string;\n};\n\nstruct max8925_touch_pdata {\n\tunsigned int flags;\n};\n\nstruct max8925_power_pdata {\n\tint (*set_charger)(int);\n\tunsigned int batt_detect: 1;\n\tunsigned int topoff_threshold: 2;\n\tunsigned int fast_charge: 3;\n\tunsigned int no_temp_support: 1;\n\tunsigned int no_insert_detect: 1;\n\tchar **supplied_to;\n\tint num_supplicants;\n};\n\nstruct max8925_platform_data {\n\tstruct max8925_backlight_pdata *backlight;\n\tstruct max8925_touch_pdata *touch;\n\tstruct max8925_power_pdata *power;\n\tstruct regulator_init_data *sd1;\n\tstruct regulator_init_data *sd2;\n\tstruct regulator_init_data *sd3;\n\tstruct regulator_init_data *ldo1;\n\tstruct regulator_init_data *ldo2;\n\tstruct regulator_init_data *ldo3;\n\tstruct regulator_init_data *ldo4;\n\tstruct regulator_init_data *ldo5;\n\tstruct regulator_init_data *ldo6;\n\tstruct regulator_init_data *ldo7;\n\tstruct regulator_init_data *ldo8;\n\tstruct regulator_init_data *ldo9;\n\tstruct regulator_init_data *ldo10;\n\tstruct regulator_init_data *ldo11;\n\tstruct regulator_init_data *ldo12;\n\tstruct regulator_init_data *ldo13;\n\tstruct regulator_init_data *ldo14;\n\tstruct regulator_init_data *ldo15;\n\tstruct regulator_init_data *ldo16;\n\tstruct regulator_init_data *ldo17;\n\tstruct regulator_init_data *ldo18;\n\tstruct regulator_init_data *ldo19;\n\tstruct regulator_init_data *ldo20;\n\tint irq_base;\n\tint tsc_irq;\n};\n\nenum {\n\tFLAGS_ADC = 1,\n\tFLAGS_RTC = 2,\n};\n\nstruct max8925_irq_data {\n\tint reg;\n\tint mask_reg;\n\tint enable;\n\tint offs;\n\tint flags;\n\tint tsc_irq;\n};\n\nstruct max8997_regulator_data {\n\tint id;\n\tstruct regulator_init_data *initdata;\n\tstruct device_node *reg_node;\n};\n\nstruct max8997_muic_reg_data {\n\tu8 addr;\n\tu8 data;\n};\n\nstruct max8997_muic_platform_data {\n\tstruct max8997_muic_reg_data *init_data;\n\tint num_init_data;\n\tint detcable_delay_ms;\n\tint path_usb;\n\tint path_uart;\n};\n\nenum max8997_haptic_motor_type {\n\tMAX8997_HAPTIC_ERM = 0,\n\tMAX8997_HAPTIC_LRA = 1,\n};\n\nenum max8997_haptic_pulse_mode {\n\tMAX8997_EXTERNAL_MODE = 0,\n\tMAX8997_INTERNAL_MODE = 1,\n};\n\nenum max8997_haptic_pwm_divisor {\n\tMAX8997_PWM_DIVISOR_32 = 0,\n\tMAX8997_PWM_DIVISOR_64 = 1,\n\tMAX8997_PWM_DIVISOR_128 = 2,\n\tMAX8997_PWM_DIVISOR_256 = 3,\n};\n\nstruct max8997_haptic_platform_data {\n\tunsigned int pwm_channel_id;\n\tunsigned int pwm_period;\n\tenum max8997_haptic_motor_type type;\n\tenum max8997_haptic_pulse_mode mode;\n\tenum max8997_haptic_pwm_divisor pwm_divisor;\n\tunsigned int internal_mode_pattern;\n\tunsigned int pattern_cycle;\n\tunsigned int pattern_signal_period;\n};\n\nenum max8997_led_mode {\n\tMAX8997_NONE = 0,\n\tMAX8997_FLASH_MODE = 1,\n\tMAX8997_MOVIE_MODE = 2,\n\tMAX8997_FLASH_PIN_CONTROL_MODE = 3,\n\tMAX8997_MOVIE_PIN_CONTROL_MODE = 4,\n};\n\nstruct max8997_led_platform_data {\n\tenum max8997_led_mode mode[2];\n\tu8 brightness[2];\n};\n\nstruct max8997_platform_data {\n\tint ono;\n\tstruct max8997_regulator_data *regulators;\n\tint num_regulators;\n\tbool ignore_gpiodvs_side_effect;\n\tint buck125_gpios[3];\n\tint buck125_default_idx;\n\tunsigned int buck1_voltage[8];\n\tbool buck1_gpiodvs;\n\tunsigned int buck2_voltage[8];\n\tbool buck2_gpiodvs;\n\tunsigned int buck5_voltage[8];\n\tbool buck5_gpiodvs;\n\tint eoc_mA;\n\tint timeout;\n\tstruct max8997_muic_platform_data *muic_pdata;\n\tstruct max8997_haptic_platform_data *haptic_pdata;\n\tstruct max8997_led_platform_data *led_pdata;\n};\n\nenum max8997_pmic_reg {\n\tMAX8997_REG_PMIC_ID0 = 0,\n\tMAX8997_REG_PMIC_ID1 = 1,\n\tMAX8997_REG_INTSRC = 2,\n\tMAX8997_REG_INT1 = 3,\n\tMAX8997_REG_INT2 = 4,\n\tMAX8997_REG_INT3 = 5,\n\tMAX8997_REG_INT4 = 6,\n\tMAX8997_REG_INT1MSK = 8,\n\tMAX8997_REG_INT2MSK = 9,\n\tMAX8997_REG_INT3MSK = 10,\n\tMAX8997_REG_INT4MSK = 11,\n\tMAX8997_REG_STATUS1 = 13,\n\tMAX8997_REG_STATUS2 = 14,\n\tMAX8997_REG_STATUS3 = 15,\n\tMAX8997_REG_STATUS4 = 16,\n\tMAX8997_REG_MAINCON1 = 19,\n\tMAX8997_REG_MAINCON2 = 20,\n\tMAX8997_REG_BUCKRAMP = 21,\n\tMAX8997_REG_BUCK1CTRL = 24,\n\tMAX8997_REG_BUCK1DVS1 = 25,\n\tMAX8997_REG_BUCK1DVS2 = 26,\n\tMAX8997_REG_BUCK1DVS3 = 27,\n\tMAX8997_REG_BUCK1DVS4 = 28,\n\tMAX8997_REG_BUCK1DVS5 = 29,\n\tMAX8997_REG_BUCK1DVS6 = 30,\n\tMAX8997_REG_BUCK1DVS7 = 31,\n\tMAX8997_REG_BUCK1DVS8 = 32,\n\tMAX8997_REG_BUCK2CTRL = 33,\n\tMAX8997_REG_BUCK2DVS1 = 34,\n\tMAX8997_REG_BUCK2DVS2 = 35,\n\tMAX8997_REG_BUCK2DVS3 = 36,\n\tMAX8997_REG_BUCK2DVS4 = 37,\n\tMAX8997_REG_BUCK2DVS5 = 38,\n\tMAX8997_REG_BUCK2DVS6 = 39,\n\tMAX8997_REG_BUCK2DVS7 = 40,\n\tMAX8997_REG_BUCK2DVS8 = 41,\n\tMAX8997_REG_BUCK3CTRL = 42,\n\tMAX8997_REG_BUCK3DVS = 43,\n\tMAX8997_REG_BUCK4CTRL = 44,\n\tMAX8997_REG_BUCK4DVS = 45,\n\tMAX8997_REG_BUCK5CTRL = 46,\n\tMAX8997_REG_BUCK5DVS1 = 47,\n\tMAX8997_REG_BUCK5DVS2 = 48,\n\tMAX8997_REG_BUCK5DVS3 = 49,\n\tMAX8997_REG_BUCK5DVS4 = 50,\n\tMAX8997_REG_BUCK5DVS5 = 51,\n\tMAX8997_REG_BUCK5DVS6 = 52,\n\tMAX8997_REG_BUCK5DVS7 = 53,\n\tMAX8997_REG_BUCK5DVS8 = 54,\n\tMAX8997_REG_BUCK6CTRL = 55,\n\tMAX8997_REG_BUCK6BPSKIPCTRL = 56,\n\tMAX8997_REG_BUCK7CTRL = 57,\n\tMAX8997_REG_BUCK7DVS = 58,\n\tMAX8997_REG_LDO1CTRL = 59,\n\tMAX8997_REG_LDO2CTRL = 60,\n\tMAX8997_REG_LDO3CTRL = 61,\n\tMAX8997_REG_LDO4CTRL = 62,\n\tMAX8997_REG_LDO5CTRL = 63,\n\tMAX8997_REG_LDO6CTRL = 64,\n\tMAX8997_REG_LDO7CTRL = 65,\n\tMAX8997_REG_LDO8CTRL = 66,\n\tMAX8997_REG_LDO9CTRL = 67,\n\tMAX8997_REG_LDO10CTRL = 68,\n\tMAX8997_REG_LDO11CTRL = 69,\n\tMAX8997_REG_LDO12CTRL = 70,\n\tMAX8997_REG_LDO13CTRL = 71,\n\tMAX8997_REG_LDO14CTRL = 72,\n\tMAX8997_REG_LDO15CTRL = 73,\n\tMAX8997_REG_LDO16CTRL = 74,\n\tMAX8997_REG_LDO17CTRL = 75,\n\tMAX8997_REG_LDO18CTRL = 76,\n\tMAX8997_REG_LDO21CTRL = 77,\n\tMAX8997_REG_MBCCTRL1 = 80,\n\tMAX8997_REG_MBCCTRL2 = 81,\n\tMAX8997_REG_MBCCTRL3 = 82,\n\tMAX8997_REG_MBCCTRL4 = 83,\n\tMAX8997_REG_MBCCTRL5 = 84,\n\tMAX8997_REG_MBCCTRL6 = 85,\n\tMAX8997_REG_OTPCGHCVS = 86,\n\tMAX8997_REG_SAFEOUTCTRL = 90,\n\tMAX8997_REG_LBCNFG1 = 94,\n\tMAX8997_REG_LBCNFG2 = 95,\n\tMAX8997_REG_BBCCTRL = 96,\n\tMAX8997_REG_FLASH1_CUR = 99,\n\tMAX8997_REG_FLASH2_CUR = 100,\n\tMAX8997_REG_MOVIE_CUR = 101,\n\tMAX8997_REG_GSMB_CUR = 102,\n\tMAX8997_REG_BOOST_CNTL = 103,\n\tMAX8997_REG_LEN_CNTL = 104,\n\tMAX8997_REG_FLASH_CNTL = 105,\n\tMAX8997_REG_WDT_CNTL = 106,\n\tMAX8997_REG_MAXFLASH1 = 107,\n\tMAX8997_REG_MAXFLASH2 = 108,\n\tMAX8997_REG_FLASHSTATUS = 109,\n\tMAX8997_REG_FLASHSTATUSMASK = 110,\n\tMAX8997_REG_GPIOCNTL1 = 112,\n\tMAX8997_REG_GPIOCNTL2 = 113,\n\tMAX8997_REG_GPIOCNTL3 = 114,\n\tMAX8997_REG_GPIOCNTL4 = 115,\n\tMAX8997_REG_GPIOCNTL5 = 116,\n\tMAX8997_REG_GPIOCNTL6 = 117,\n\tMAX8997_REG_GPIOCNTL7 = 118,\n\tMAX8997_REG_GPIOCNTL8 = 119,\n\tMAX8997_REG_GPIOCNTL9 = 120,\n\tMAX8997_REG_GPIOCNTL10 = 121,\n\tMAX8997_REG_GPIOCNTL11 = 122,\n\tMAX8997_REG_GPIOCNTL12 = 123,\n\tMAX8997_REG_LDO1CONFIG = 128,\n\tMAX8997_REG_LDO2CONFIG = 129,\n\tMAX8997_REG_LDO3CONFIG = 130,\n\tMAX8997_REG_LDO4CONFIG = 131,\n\tMAX8997_REG_LDO5CONFIG = 132,\n\tMAX8997_REG_LDO6CONFIG = 133,\n\tMAX8997_REG_LDO7CONFIG = 134,\n\tMAX8997_REG_LDO8CONFIG = 135,\n\tMAX8997_REG_LDO9CONFIG = 136,\n\tMAX8997_REG_LDO10CONFIG = 137,\n\tMAX8997_REG_LDO11CONFIG = 138,\n\tMAX8997_REG_LDO12CONFIG = 139,\n\tMAX8997_REG_LDO13CONFIG = 140,\n\tMAX8997_REG_LDO14CONFIG = 141,\n\tMAX8997_REG_LDO15CONFIG = 142,\n\tMAX8997_REG_LDO16CONFIG = 143,\n\tMAX8997_REG_LDO17CONFIG = 144,\n\tMAX8997_REG_LDO18CONFIG = 145,\n\tMAX8997_REG_LDO21CONFIG = 146,\n\tMAX8997_REG_DVSOKTIMER1 = 151,\n\tMAX8997_REG_DVSOKTIMER2 = 152,\n\tMAX8997_REG_DVSOKTIMER4 = 153,\n\tMAX8997_REG_DVSOKTIMER5 = 154,\n\tMAX8997_REG_PMIC_END = 155,\n};\n\nenum max8997_muic_reg {\n\tMAX8997_MUIC_REG_ID = 0,\n\tMAX8997_MUIC_REG_INT1 = 1,\n\tMAX8997_MUIC_REG_INT2 = 2,\n\tMAX8997_MUIC_REG_INT3 = 3,\n\tMAX8997_MUIC_REG_STATUS1 = 4,\n\tMAX8997_MUIC_REG_STATUS2 = 5,\n\tMAX8997_MUIC_REG_STATUS3 = 6,\n\tMAX8997_MUIC_REG_INTMASK1 = 7,\n\tMAX8997_MUIC_REG_INTMASK2 = 8,\n\tMAX8997_MUIC_REG_INTMASK3 = 9,\n\tMAX8997_MUIC_REG_CDETCTRL = 10,\n\tMAX8997_MUIC_REG_CONTROL1 = 12,\n\tMAX8997_MUIC_REG_CONTROL2 = 13,\n\tMAX8997_MUIC_REG_CONTROL3 = 14,\n\tMAX8997_MUIC_REG_END = 15,\n};\n\nenum max8997_haptic_reg {\n\tMAX8997_HAPTIC_REG_GENERAL = 0,\n\tMAX8997_HAPTIC_REG_CONF1 = 1,\n\tMAX8997_HAPTIC_REG_CONF2 = 2,\n\tMAX8997_HAPTIC_REG_DRVCONF = 3,\n\tMAX8997_HAPTIC_REG_CYCLECONF1 = 4,\n\tMAX8997_HAPTIC_REG_CYCLECONF2 = 5,\n\tMAX8997_HAPTIC_REG_SIGCONF1 = 6,\n\tMAX8997_HAPTIC_REG_SIGCONF2 = 7,\n\tMAX8997_HAPTIC_REG_SIGCONF3 = 8,\n\tMAX8997_HAPTIC_REG_SIGCONF4 = 9,\n\tMAX8997_HAPTIC_REG_SIGDC1 = 10,\n\tMAX8997_HAPTIC_REG_SIGDC2 = 11,\n\tMAX8997_HAPTIC_REG_SIGPWMDC1 = 12,\n\tMAX8997_HAPTIC_REG_SIGPWMDC2 = 13,\n\tMAX8997_HAPTIC_REG_SIGPWMDC3 = 14,\n\tMAX8997_HAPTIC_REG_SIGPWMDC4 = 15,\n\tMAX8997_HAPTIC_REG_MTR_REV = 16,\n\tMAX8997_HAPTIC_REG_END = 17,\n};\n\nenum max8997_irq_source {\n\tPMIC_INT1 = 0,\n\tPMIC_INT2 = 1,\n\tPMIC_INT3 = 2,\n\tPMIC_INT4 = 3,\n\tFUEL_GAUGE = 4,\n\tMUIC_INT1 = 5,\n\tMUIC_INT2 = 6,\n\tMUIC_INT3 = 7,\n\tGPIO_LOW = 8,\n\tGPIO_HI = 9,\n\tFLASH_STATUS = 10,\n\tMAX8997_IRQ_GROUP_NR = 11,\n};\n\nstruct max8997_dev {\n\tstruct device *dev;\n\tstruct max8997_platform_data *pdata;\n\tstruct i2c_client *i2c;\n\tstruct i2c_client *rtc;\n\tstruct i2c_client *haptic;\n\tstruct i2c_client *muic;\n\tstruct mutex iolock;\n\tlong unsigned int type;\n\tstruct platform_device *battery;\n\tint irq;\n\tint ono;\n\tstruct irq_domain *irq_domain;\n\tstruct mutex irqlock;\n\tint irq_masks_cur[11];\n\tint irq_masks_cache[11];\n\tu8 reg_dump[187];\n\tbool gpio_status[12];\n};\n\nenum max8997_types {\n\tTYPE_MAX8997 = 0,\n\tTYPE_MAX8966 = 1,\n};\n\nenum max8997_irq {\n\tMAX8997_PMICIRQ_PWRONR = 0,\n\tMAX8997_PMICIRQ_PWRONF = 1,\n\tMAX8997_PMICIRQ_PWRON1SEC = 2,\n\tMAX8997_PMICIRQ_JIGONR = 3,\n\tMAX8997_PMICIRQ_JIGONF = 4,\n\tMAX8997_PMICIRQ_LOWBAT2 = 5,\n\tMAX8997_PMICIRQ_LOWBAT1 = 6,\n\tMAX8997_PMICIRQ_JIGR = 7,\n\tMAX8997_PMICIRQ_JIGF = 8,\n\tMAX8997_PMICIRQ_MR = 9,\n\tMAX8997_PMICIRQ_DVS1OK = 10,\n\tMAX8997_PMICIRQ_DVS2OK = 11,\n\tMAX8997_PMICIRQ_DVS3OK = 12,\n\tMAX8997_PMICIRQ_DVS4OK = 13,\n\tMAX8997_PMICIRQ_CHGINS = 14,\n\tMAX8997_PMICIRQ_CHGRM = 15,\n\tMAX8997_PMICIRQ_DCINOVP = 16,\n\tMAX8997_PMICIRQ_TOPOFFR = 17,\n\tMAX8997_PMICIRQ_CHGRSTF = 18,\n\tMAX8997_PMICIRQ_MBCHGTMEXPD = 19,\n\tMAX8997_PMICIRQ_RTC60S = 20,\n\tMAX8997_PMICIRQ_RTCA1 = 21,\n\tMAX8997_PMICIRQ_RTCA2 = 22,\n\tMAX8997_PMICIRQ_SMPL_INT = 23,\n\tMAX8997_PMICIRQ_RTC1S = 24,\n\tMAX8997_PMICIRQ_WTSR = 25,\n\tMAX8997_MUICIRQ_ADCError = 26,\n\tMAX8997_MUICIRQ_ADCLow = 27,\n\tMAX8997_MUICIRQ_ADC = 28,\n\tMAX8997_MUICIRQ_VBVolt = 29,\n\tMAX8997_MUICIRQ_DBChg = 30,\n\tMAX8997_MUICIRQ_DCDTmr = 31,\n\tMAX8997_MUICIRQ_ChgDetRun = 32,\n\tMAX8997_MUICIRQ_ChgTyp = 33,\n\tMAX8997_MUICIRQ_OVP = 34,\n\tMAX8997_IRQ_NR = 35,\n};\n\nstruct max8997_irq_data {\n\tint mask;\n\tenum max8997_irq_source group;\n};\n\nstruct max8998_regulator_data {\n\tint id;\n\tstruct regulator_init_data *initdata;\n\tstruct device_node *reg_node;\n};\n\nstruct max8998_platform_data {\n\tstruct max8998_regulator_data *regulators;\n\tint num_regulators;\n\tunsigned int irq_base;\n\tint ono;\n\tbool buck_voltage_lock;\n\tint buck1_voltage[4];\n\tint buck2_voltage[2];\n\tint buck1_set1;\n\tint buck1_set2;\n\tint buck1_default_idx;\n\tint buck2_set3;\n\tint buck2_default_idx;\n\tbool wakeup;\n\tbool rtc_delay;\n\tint eoc;\n\tint restart;\n\tint timeout;\n};\n\nenum {\n\tMAX8998_REG_IRQ1 = 0,\n\tMAX8998_REG_IRQ2 = 1,\n\tMAX8998_REG_IRQ3 = 2,\n\tMAX8998_REG_IRQ4 = 3,\n\tMAX8998_REG_IRQM1 = 4,\n\tMAX8998_REG_IRQM2 = 5,\n\tMAX8998_REG_IRQM3 = 6,\n\tMAX8998_REG_IRQM4 = 7,\n\tMAX8998_REG_STATUS1 = 8,\n\tMAX8998_REG_STATUS2 = 9,\n\tMAX8998_REG_STATUSM1 = 10,\n\tMAX8998_REG_STATUSM2 = 11,\n\tMAX8998_REG_CHGR1 = 12,\n\tMAX8998_REG_CHGR2 = 13,\n\tMAX8998_REG_LDO_ACTIVE_DISCHARGE1 = 14,\n\tMAX8998_REG_LDO_ACTIVE_DISCHARGE2 = 15,\n\tMAX8998_REG_BUCK_ACTIVE_DISCHARGE3 = 16,\n\tMAX8998_REG_ONOFF1 = 17,\n\tMAX8998_REG_ONOFF2 = 18,\n\tMAX8998_REG_ONOFF3 = 19,\n\tMAX8998_REG_ONOFF4 = 20,\n\tMAX8998_REG_BUCK1_VOLTAGE1 = 21,\n\tMAX8998_REG_BUCK1_VOLTAGE2 = 22,\n\tMAX8998_REG_BUCK1_VOLTAGE3 = 23,\n\tMAX8998_REG_BUCK1_VOLTAGE4 = 24,\n\tMAX8998_REG_BUCK2_VOLTAGE1 = 25,\n\tMAX8998_REG_BUCK2_VOLTAGE2 = 26,\n\tMAX8998_REG_BUCK3 = 27,\n\tMAX8998_REG_BUCK4 = 28,\n\tMAX8998_REG_LDO2_LDO3 = 29,\n\tMAX8998_REG_LDO4 = 30,\n\tMAX8998_REG_LDO5 = 31,\n\tMAX8998_REG_LDO6 = 32,\n\tMAX8998_REG_LDO7 = 33,\n\tMAX8998_REG_LDO8_LDO9 = 34,\n\tMAX8998_REG_LDO10_LDO11 = 35,\n\tMAX8998_REG_LDO12 = 36,\n\tMAX8998_REG_LDO13 = 37,\n\tMAX8998_REG_LDO14 = 38,\n\tMAX8998_REG_LDO15 = 39,\n\tMAX8998_REG_LDO16 = 40,\n\tMAX8998_REG_LDO17 = 41,\n\tMAX8998_REG_BKCHR = 42,\n\tMAX8998_REG_LBCNFG1 = 43,\n\tMAX8998_REG_LBCNFG2 = 44,\n};\n\nenum {\n\tTYPE_MAX8998 = 0,\n\tTYPE_LP3974 = 1,\n\tTYPE_LP3979 = 2,\n};\n\nstruct max8998_dev {\n\tstruct device *dev;\n\tstruct max8998_platform_data *pdata;\n\tstruct i2c_client *i2c;\n\tstruct i2c_client *rtc;\n\tstruct mutex iolock;\n\tstruct mutex irqlock;\n\tunsigned int irq_base;\n\tstruct irq_domain *irq_domain;\n\tint irq;\n\tint ono;\n\tu8 irq_masks_cur[4];\n\tu8 irq_masks_cache[4];\n\tlong unsigned int type;\n\tbool wakeup;\n};\n\nstruct max8998_reg_dump {\n\tu8 addr;\n\tu8 val;\n};\n\nenum {\n\tMAX8998_IRQ_DCINF = 0,\n\tMAX8998_IRQ_DCINR = 1,\n\tMAX8998_IRQ_JIGF = 2,\n\tMAX8998_IRQ_JIGR = 3,\n\tMAX8998_IRQ_PWRONF = 4,\n\tMAX8998_IRQ_PWRONR = 5,\n\tMAX8998_IRQ_WTSREVNT = 6,\n\tMAX8998_IRQ_SMPLEVNT = 7,\n\tMAX8998_IRQ_ALARM1 = 8,\n\tMAX8998_IRQ_ALARM0 = 9,\n\tMAX8998_IRQ_ONKEY1S = 10,\n\tMAX8998_IRQ_TOPOFFR = 11,\n\tMAX8998_IRQ_DCINOVPR = 12,\n\tMAX8998_IRQ_CHGRSTF = 13,\n\tMAX8998_IRQ_DONER = 14,\n\tMAX8998_IRQ_CHGFAULT = 15,\n\tMAX8998_IRQ_LOBAT1 = 16,\n\tMAX8998_IRQ_LOBAT2 = 17,\n\tMAX8998_IRQ_NR = 18,\n};\n\nstruct max8998_irq_data {\n\tint reg;\n\tint mask;\n};\n\nstruct max8997_dev___2;\n\nstruct adp5520_gpio_platform_data {\n\tunsigned int gpio_start;\n\tu8 gpio_en_mask;\n\tu8 gpio_pullup_mask;\n};\n\nstruct adp5520_keys_platform_data {\n\tint rows_en_mask;\n\tint cols_en_mask;\n\tconst short unsigned int *keymap;\n\tshort unsigned int keymapsize;\n\tunsigned int repeat: 1;\n};\n\nstruct led_info;\n\nstruct adp5520_leds_platform_data {\n\tint num_leds;\n\tstruct led_info *leds;\n\tu8 fade_in;\n\tu8 fade_out;\n\tu8 led_on_time;\n};\n\nstruct adp5520_backlight_platform_data {\n\tu8 fade_in;\n\tu8 fade_out;\n\tu8 fade_led_law;\n\tu8 en_ambl_sens;\n\tu8 abml_filt;\n\tu8 l1_daylight_max;\n\tu8 l1_daylight_dim;\n\tu8 l2_office_max;\n\tu8 l2_office_dim;\n\tu8 l3_dark_max;\n\tu8 l3_dark_dim;\n\tu8 l2_trip;\n\tu8 l2_hyst;\n\tu8 l3_trip;\n\tu8 l3_hyst;\n};\n\nstruct adp5520_platform_data {\n\tstruct adp5520_keys_platform_data *keys;\n\tstruct adp5520_gpio_platform_data *gpio;\n\tstruct adp5520_leds_platform_data *leds;\n\tstruct adp5520_backlight_platform_data *backlight;\n};\n\nstruct adp5520_chip {\n\tstruct i2c_client *client;\n\tstruct device *dev;\n\tstruct mutex lock;\n\tstruct blocking_notifier_head notifier_list;\n\tint irq;\n\tlong unsigned int id;\n\tuint8_t mode;\n};\n\nstruct tps6586x_irq_data {\n\tu8 mask_reg;\n\tu8 mask_mask;\n};\n\nstruct tps6586x {\n\tstruct device *dev;\n\tstruct i2c_client *client;\n\tstruct regmap *regmap;\n\tint version;\n\tint irq;\n\tstruct irq_chip irq_chip;\n\tstruct mutex irq_lock;\n\tint irq_base;\n\tu32 irq_en;\n\tu8 mask_reg[5];\n\tstruct irq_domain *irq_domain;\n};\n\nenum {\n\tTPS65090_IRQ_INTERRUPT = 0,\n\tTPS65090_IRQ_VAC_STATUS_CHANGE = 1,\n\tTPS65090_IRQ_VSYS_STATUS_CHANGE = 2,\n\tTPS65090_IRQ_BAT_STATUS_CHANGE = 3,\n\tTPS65090_IRQ_CHARGING_STATUS_CHANGE = 4,\n\tTPS65090_IRQ_CHARGING_COMPLETE = 5,\n\tTPS65090_IRQ_OVERLOAD_DCDC1 = 6,\n\tTPS65090_IRQ_OVERLOAD_DCDC2 = 7,\n\tTPS65090_IRQ_OVERLOAD_DCDC3 = 8,\n\tTPS65090_IRQ_OVERLOAD_FET1 = 9,\n\tTPS65090_IRQ_OVERLOAD_FET2 = 10,\n\tTPS65090_IRQ_OVERLOAD_FET3 = 11,\n\tTPS65090_IRQ_OVERLOAD_FET4 = 12,\n\tTPS65090_IRQ_OVERLOAD_FET5 = 13,\n\tTPS65090_IRQ_OVERLOAD_FET6 = 14,\n\tTPS65090_IRQ_OVERLOAD_FET7 = 15,\n};\n\nenum {\n\tTPS65090_REGULATOR_DCDC1 = 0,\n\tTPS65090_REGULATOR_DCDC2 = 1,\n\tTPS65090_REGULATOR_DCDC3 = 2,\n\tTPS65090_REGULATOR_FET1 = 3,\n\tTPS65090_REGULATOR_FET2 = 4,\n\tTPS65090_REGULATOR_FET3 = 5,\n\tTPS65090_REGULATOR_FET4 = 6,\n\tTPS65090_REGULATOR_FET5 = 7,\n\tTPS65090_REGULATOR_FET6 = 8,\n\tTPS65090_REGULATOR_FET7 = 9,\n\tTPS65090_REGULATOR_LDO1 = 10,\n\tTPS65090_REGULATOR_LDO2 = 11,\n\tTPS65090_REGULATOR_MAX = 12,\n};\n\nstruct tps65090 {\n\tstruct device *dev;\n\tstruct regmap *rmap;\n\tstruct regmap_irq_chip_data *irq_data;\n};\n\nstruct tps65090_regulator_plat_data {\n\tstruct regulator_init_data *reg_init_data;\n\tbool enable_ext_control;\n\tstruct gpio_desc *gpiod;\n\tbool overcurrent_wait_valid;\n\tint overcurrent_wait;\n};\n\nstruct tps65090_platform_data {\n\tint irq_base;\n\tchar **supplied_to;\n\tsize_t num_supplicants;\n\tint enable_low_current_chrg;\n\tstruct tps65090_regulator_plat_data *reg_pdata[12];\n};\n\nenum tps65090_cells {\n\tPMIC = 0,\n\tCHARGER = 1,\n};\n\nenum aat2870_id {\n\tAAT2870_ID_BL = 0,\n\tAAT2870_ID_LDOA = 1,\n\tAAT2870_ID_LDOB = 2,\n\tAAT2870_ID_LDOC = 3,\n\tAAT2870_ID_LDOD = 4,\n};\n\nstruct aat2870_register {\n\tbool readable;\n\tbool writeable;\n\tu8 value;\n};\n\nstruct aat2870_data {\n\tstruct device *dev;\n\tstruct i2c_client *client;\n\tstruct mutex io_lock;\n\tstruct aat2870_register *reg_cache;\n\tint en_pin;\n\tbool is_enable;\n\tint (*init)(struct aat2870_data *);\n\tvoid (*uninit)(struct aat2870_data *);\n\tint (*read)(struct aat2870_data *, u8, u8 *);\n\tint (*write)(struct aat2870_data *, u8, u8);\n\tint (*update)(struct aat2870_data *, u8, u8, u8);\n\tstruct dentry *dentry_root;\n};\n\nstruct aat2870_subdev_info {\n\tint id;\n\tconst char *name;\n\tvoid *platform_data;\n};\n\nstruct aat2870_platform_data {\n\tint en_pin;\n\tstruct aat2870_subdev_info *subdevs;\n\tint num_subdevs;\n\tint (*init)(struct aat2870_data *);\n\tvoid (*uninit)(struct aat2870_data *);\n};\n\nenum {\n\tPALMAS_EXT_CONTROL_ENABLE1 = 1,\n\tPALMAS_EXT_CONTROL_ENABLE2 = 2,\n\tPALMAS_EXT_CONTROL_NSLEEP = 4,\n};\n\nenum palmas_external_requestor_id {\n\tPALMAS_EXTERNAL_REQSTR_ID_REGEN1 = 0,\n\tPALMAS_EXTERNAL_REQSTR_ID_REGEN2 = 1,\n\tPALMAS_EXTERNAL_REQSTR_ID_SYSEN1 = 2,\n\tPALMAS_EXTERNAL_REQSTR_ID_SYSEN2 = 3,\n\tPALMAS_EXTERNAL_REQSTR_ID_CLK32KG = 4,\n\tPALMAS_EXTERNAL_REQSTR_ID_CLK32KGAUDIO = 5,\n\tPALMAS_EXTERNAL_REQSTR_ID_REGEN3 = 6,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS12 = 7,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS3 = 8,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS45 = 9,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS6 = 10,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS7 = 11,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS8 = 12,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS9 = 13,\n\tPALMAS_EXTERNAL_REQSTR_ID_SMPS10 = 14,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO1 = 15,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO2 = 16,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO3 = 17,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO4 = 18,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO5 = 19,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO6 = 20,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO7 = 21,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO8 = 22,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDO9 = 23,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDOLN = 24,\n\tPALMAS_EXTERNAL_REQSTR_ID_LDOUSB = 25,\n\tPALMAS_EXTERNAL_REQSTR_ID_MAX = 26,\n};\n\nenum tps65917_irqs {\n\tTPS65917_RESERVED1 = 0,\n\tTPS65917_PWRON_IRQ = 1,\n\tTPS65917_LONG_PRESS_KEY_IRQ = 2,\n\tTPS65917_RESERVED2 = 3,\n\tTPS65917_PWRDOWN_IRQ = 4,\n\tTPS65917_HOTDIE_IRQ = 5,\n\tTPS65917_VSYS_MON_IRQ = 6,\n\tTPS65917_RESERVED3 = 7,\n\tTPS65917_RESERVED4 = 8,\n\tTPS65917_OTP_ERROR_IRQ = 9,\n\tTPS65917_WDT_IRQ = 10,\n\tTPS65917_RESERVED5 = 11,\n\tTPS65917_RESET_IN_IRQ = 12,\n\tTPS65917_FSD_IRQ = 13,\n\tTPS65917_SHORT_IRQ = 14,\n\tTPS65917_RESERVED6 = 15,\n\tTPS65917_GPADC_AUTO_0_IRQ = 16,\n\tTPS65917_GPADC_AUTO_1_IRQ = 17,\n\tTPS65917_GPADC_EOC_SW_IRQ = 18,\n\tTPS65917_RESREVED6 = 19,\n\tTPS65917_RESERVED7 = 20,\n\tTPS65917_RESERVED8 = 21,\n\tTPS65917_RESERVED9 = 22,\n\tTPS65917_VBUS_IRQ = 23,\n\tTPS65917_GPIO_0_IRQ = 24,\n\tTPS65917_GPIO_1_IRQ = 25,\n\tTPS65917_GPIO_2_IRQ = 26,\n\tTPS65917_GPIO_3_IRQ = 27,\n\tTPS65917_GPIO_4_IRQ = 28,\n\tTPS65917_GPIO_5_IRQ = 29,\n\tTPS65917_GPIO_6_IRQ = 30,\n\tTPS65917_RESERVED10 = 31,\n\tTPS65917_NUM_IRQ = 32,\n};\n\nstruct palmas_driver_data {\n\tunsigned int *features;\n\tstruct regmap_irq_chip *irq_chip;\n};\n\nenum {\n\tRC5T583_DS_NONE = 0,\n\tRC5T583_DS_DC0 = 1,\n\tRC5T583_DS_DC1 = 2,\n\tRC5T583_DS_DC2 = 3,\n\tRC5T583_DS_DC3 = 4,\n\tRC5T583_DS_LDO0 = 5,\n\tRC5T583_DS_LDO1 = 6,\n\tRC5T583_DS_LDO2 = 7,\n\tRC5T583_DS_LDO3 = 8,\n\tRC5T583_DS_LDO4 = 9,\n\tRC5T583_DS_LDO5 = 10,\n\tRC5T583_DS_LDO6 = 11,\n\tRC5T583_DS_LDO7 = 12,\n\tRC5T583_DS_LDO8 = 13,\n\tRC5T583_DS_LDO9 = 14,\n\tRC5T583_DS_PSO0 = 15,\n\tRC5T583_DS_PSO1 = 16,\n\tRC5T583_DS_PSO2 = 17,\n\tRC5T583_DS_PSO3 = 18,\n\tRC5T583_DS_PSO4 = 19,\n\tRC5T583_DS_PSO5 = 20,\n\tRC5T583_DS_PSO6 = 21,\n\tRC5T583_DS_PSO7 = 22,\n\tRC5T583_DS_MAX = 23,\n};\n\nenum {\n\tRC5T583_EXT_PWRREQ1_CONTROL = 1,\n\tRC5T583_EXT_PWRREQ2_CONTROL = 2,\n};\n\nstruct deepsleep_control_data {\n\tu8 reg_add;\n\tu8 ds_pos_bit;\n};\n\nenum int_type {\n\tSYS_INT = 1,\n\tDCDC_INT = 2,\n\tRTC_INT = 4,\n\tADC_INT = 8,\n\tGPIO_INT = 16,\n};\n\nstruct rc5t583_irq_data {\n\tu8 int_type;\n\tu8 master_bit;\n\tu8 int_en_bit;\n\tu8 mask_reg_index;\n\tint grp_index;\n};\n\nstruct syscon_platform_data {\n\tconst char *label;\n};\n\nstruct syscon {\n\tstruct device_node *np;\n\tstruct regmap *regmap;\n\tstruct list_head list;\n};\n\nenum {\n\tAS3711_REGULATOR_SD_1 = 0,\n\tAS3711_REGULATOR_SD_2 = 1,\n\tAS3711_REGULATOR_SD_3 = 2,\n\tAS3711_REGULATOR_SD_4 = 3,\n\tAS3711_REGULATOR_LDO_1 = 4,\n\tAS3711_REGULATOR_LDO_2 = 5,\n\tAS3711_REGULATOR_LDO_3 = 6,\n\tAS3711_REGULATOR_LDO_4 = 7,\n\tAS3711_REGULATOR_LDO_5 = 8,\n\tAS3711_REGULATOR_LDO_6 = 9,\n\tAS3711_REGULATOR_LDO_7 = 10,\n\tAS3711_REGULATOR_LDO_8 = 11,\n\tAS3711_REGULATOR_MAX = 12,\n};\n\nstruct as3711 {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n};\n\nenum as3711_su2_feedback {\n\tAS3711_SU2_VOLTAGE = 0,\n\tAS3711_SU2_CURR1 = 1,\n\tAS3711_SU2_CURR2 = 2,\n\tAS3711_SU2_CURR3 = 3,\n\tAS3711_SU2_CURR_AUTO = 4,\n};\n\nenum as3711_su2_fbprot {\n\tAS3711_SU2_LX_SD4 = 0,\n\tAS3711_SU2_GPIO2 = 1,\n\tAS3711_SU2_GPIO3 = 2,\n\tAS3711_SU2_GPIO4 = 3,\n};\n\nstruct as3711_regulator_pdata {\n\tstruct regulator_init_data *init_data[12];\n};\n\nstruct as3711_bl_pdata {\n\tbool su1_fb;\n\tint su1_max_uA;\n\tbool su2_fb;\n\tint su2_max_uA;\n\tenum as3711_su2_feedback su2_feedback;\n\tenum as3711_su2_fbprot su2_fbprot;\n\tbool su2_auto_curr1;\n\tbool su2_auto_curr2;\n\tbool su2_auto_curr3;\n};\n\nstruct as3711_platform_data {\n\tstruct as3711_regulator_pdata regulator;\n\tstruct as3711_bl_pdata backlight;\n};\n\nenum {\n\tAS3711_REGULATOR = 0,\n\tAS3711_BACKLIGHT = 1,\n};\n\nstruct intel_soc_pmic_config {\n\tlong unsigned int irq_flags;\n\tstruct mfd_cell *cell_dev;\n\tint n_cell_devs;\n\tconst struct regmap_config *regmap_config;\n\tconst struct regmap_irq_chip *irq_chip;\n};\n\nenum {\n\tCHT_WC_PWRSRC_IRQ = 0,\n\tCHT_WC_THRM_IRQ = 1,\n\tCHT_WC_BCU_IRQ = 2,\n\tCHT_WC_ADC_IRQ = 3,\n\tCHT_WC_EXT_CHGR_IRQ = 4,\n\tCHT_WC_GPIO_IRQ = 5,\n\tCHT_WC_CRIT_IRQ = 7,\n};\n\nstruct badrange {\n\tstruct list_head list;\n\tspinlock_t lock;\n};\n\nenum {\n\tNDD_ALIASING = 0,\n\tNDD_UNARMED = 1,\n\tNDD_LOCKED = 2,\n\tNDD_SECURITY_OVERWRITE = 3,\n\tNDD_WORK_PENDING = 4,\n\tNDD_NOBLK = 5,\n\tNDD_LABELING = 6,\n\tND_IOCTL_MAX_BUFLEN = 4194304,\n\tND_CMD_MAX_ELEM = 5,\n\tND_CMD_MAX_ENVELOPE = 256,\n\tND_MAX_MAPPINGS = 32,\n\tND_REGION_PAGEMAP = 0,\n\tND_REGION_PERSIST_CACHE = 1,\n\tND_REGION_PERSIST_MEMCTRL = 2,\n\tND_REGION_ASYNC = 3,\n\tDPA_RESOURCE_ADJUSTED = 1,\n};\n\nstruct nvdimm_bus_descriptor;\n\nstruct nvdimm;\n\ntypedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *, struct nvdimm *, unsigned int, void *, unsigned int, int *);\n\nstruct nvdimm_bus_fw_ops;\n\nstruct nvdimm_bus_descriptor {\n\tconst struct attribute_group **attr_groups;\n\tlong unsigned int cmd_mask;\n\tlong unsigned int dimm_family_mask;\n\tlong unsigned int bus_family_mask;\n\tstruct module *module;\n\tchar *provider_name;\n\tstruct device_node *of_node;\n\tndctl_fn ndctl;\n\tint (*flush_probe)(struct nvdimm_bus_descriptor *);\n\tint (*clear_to_send)(struct nvdimm_bus_descriptor *, struct nvdimm *, unsigned int, void *);\n\tconst struct nvdimm_bus_fw_ops *fw_ops;\n};\n\nstruct nvdimm_security_ops;\n\nstruct nvdimm_fw_ops;\n\nstruct nvdimm {\n\tlong unsigned int flags;\n\tvoid *provider_data;\n\tlong unsigned int cmd_mask;\n\tstruct device dev;\n\tatomic_t busy;\n\tint id;\n\tint num_flush;\n\tstruct resource *flush_wpq;\n\tconst char *dimm_id;\n\tstruct {\n\t\tconst struct nvdimm_security_ops *ops;\n\t\tlong unsigned int flags;\n\t\tlong unsigned int ext_flags;\n\t\tunsigned int overwrite_tmo;\n\t\tstruct kernfs_node *overwrite_state;\n\t} sec;\n\tstruct delayed_work dwork;\n\tconst struct nvdimm_fw_ops *fw_ops;\n};\n\nenum nvdimm_fwa_state {\n\tNVDIMM_FWA_INVALID = 0,\n\tNVDIMM_FWA_IDLE = 1,\n\tNVDIMM_FWA_ARMED = 2,\n\tNVDIMM_FWA_BUSY = 3,\n\tNVDIMM_FWA_ARM_OVERFLOW = 4,\n};\n\nenum nvdimm_fwa_capability {\n\tNVDIMM_FWA_CAP_INVALID = 0,\n\tNVDIMM_FWA_CAP_NONE = 1,\n\tNVDIMM_FWA_CAP_QUIESCE = 2,\n\tNVDIMM_FWA_CAP_LIVE = 3,\n};\n\nstruct nvdimm_bus_fw_ops {\n\tenum nvdimm_fwa_state (*activate_state)(struct nvdimm_bus_descriptor *);\n\tenum nvdimm_fwa_capability (*capability)(struct nvdimm_bus_descriptor *);\n\tint (*activate)(struct nvdimm_bus_descriptor *);\n};\n\nstruct nvdimm_bus {\n\tstruct nvdimm_bus_descriptor *nd_desc;\n\twait_queue_head_t wait;\n\tstruct list_head list;\n\tstruct device dev;\n\tint id;\n\tint probe_active;\n\tatomic_t ioctl_active;\n\tstruct list_head mapping_list;\n\tstruct mutex reconfig_mutex;\n\tstruct badrange badrange;\n};\n\nstruct nvdimm_key_data {\n\tu8 data[32];\n};\n\nenum nvdimm_passphrase_type {\n\tNVDIMM_USER = 0,\n\tNVDIMM_MASTER = 1,\n};\n\nstruct nvdimm_security_ops {\n\tlong unsigned int (*get_flags)(struct nvdimm *, enum nvdimm_passphrase_type);\n\tint (*freeze)(struct nvdimm *);\n\tint (*change_key)(struct nvdimm *, const struct nvdimm_key_data *, const struct nvdimm_key_data *, enum nvdimm_passphrase_type);\n\tint (*unlock)(struct nvdimm *, const struct nvdimm_key_data *);\n\tint (*disable)(struct nvdimm *, const struct nvdimm_key_data *);\n\tint (*erase)(struct nvdimm *, const struct nvdimm_key_data *, enum nvdimm_passphrase_type);\n\tint (*overwrite)(struct nvdimm *, const struct nvdimm_key_data *);\n\tint (*query_overwrite)(struct nvdimm *);\n};\n\nenum nvdimm_fwa_trigger {\n\tNVDIMM_FWA_ARM = 0,\n\tNVDIMM_FWA_DISARM = 1,\n};\n\nenum nvdimm_fwa_result {\n\tNVDIMM_FWA_RESULT_INVALID = 0,\n\tNVDIMM_FWA_RESULT_NONE = 1,\n\tNVDIMM_FWA_RESULT_SUCCESS = 2,\n\tNVDIMM_FWA_RESULT_NOTSTAGED = 3,\n\tNVDIMM_FWA_RESULT_NEEDRESET = 4,\n\tNVDIMM_FWA_RESULT_FAIL = 5,\n};\n\nstruct nvdimm_fw_ops {\n\tenum nvdimm_fwa_state (*activate_state)(struct nvdimm *);\n\tenum nvdimm_fwa_result (*activate_result)(struct nvdimm *);\n\tint (*arm)(struct nvdimm *, enum nvdimm_fwa_trigger);\n};\n\nenum {\n\tND_CMD_IMPLEMENTED = 0,\n\tND_CMD_ARS_CAP = 1,\n\tND_CMD_ARS_START = 2,\n\tND_CMD_ARS_STATUS = 3,\n\tND_CMD_CLEAR_ERROR = 4,\n\tND_CMD_SMART = 1,\n\tND_CMD_SMART_THRESHOLD = 2,\n\tND_CMD_DIMM_FLAGS = 3,\n\tND_CMD_GET_CONFIG_SIZE = 4,\n\tND_CMD_GET_CONFIG_DATA = 5,\n\tND_CMD_SET_CONFIG_DATA = 6,\n\tND_CMD_VENDOR_EFFECT_LOG_SIZE = 7,\n\tND_CMD_VENDOR_EFFECT_LOG = 8,\n\tND_CMD_VENDOR = 9,\n\tND_CMD_CALL = 10,\n};\n\nenum {\n\tNSINDEX_SIG_LEN = 16,\n\tNSINDEX_ALIGN = 256,\n\tNSINDEX_SEQ_MASK = 3,\n\tNSLABEL_UUID_LEN = 16,\n\tNSLABEL_NAME_LEN = 64,\n\tNSLABEL_FLAG_ROLABEL = 1,\n\tNSLABEL_FLAG_LOCAL = 2,\n\tNSLABEL_FLAG_BTT = 4,\n\tNSLABEL_FLAG_UPDATING = 8,\n\tBTT_ALIGN = 4096,\n\tBTTINFO_SIG_LEN = 16,\n\tBTTINFO_UUID_LEN = 16,\n\tBTTINFO_FLAG_ERROR = 1,\n\tBTTINFO_MAJOR_VERSION = 1,\n\tND_LABEL_MIN_SIZE = 1024,\n\tND_LABEL_ID_SIZE = 50,\n\tND_NSINDEX_INIT = 1,\n};\n\nstruct nvdimm_map {\n\tstruct nvdimm_bus *nvdimm_bus;\n\tstruct list_head list;\n\tresource_size_t offset;\n\tlong unsigned int flags;\n\tsize_t size;\n\tunion {\n\t\tvoid *mem;\n\t\tvoid *iomem;\n\t};\n\tstruct kref kref;\n};\n\nstruct badrange_entry {\n\tu64 start;\n\tu64 length;\n\tstruct list_head list;\n};\n\nstruct nd_cmd_desc {\n\tint in_num;\n\tint out_num;\n\tu32 in_sizes[5];\n\tint out_sizes[5];\n};\n\nstruct nd_interleave_set {\n\tu64 cookie1;\n\tu64 cookie2;\n\tu64 altcookie;\n\tguid_t type_guid;\n};\n\nstruct nvdimm_drvdata;\n\nstruct nd_mapping {\n\tstruct nvdimm *nvdimm;\n\tu64 start;\n\tu64 size;\n\tint position;\n\tstruct list_head labels;\n\tstruct mutex lock;\n\tstruct nvdimm_drvdata *ndd;\n};\n\nstruct nd_percpu_lane;\n\nstruct nd_region {\n\tstruct device dev;\n\tstruct ida ns_ida;\n\tstruct ida btt_ida;\n\tstruct ida pfn_ida;\n\tstruct ida dax_ida;\n\tlong unsigned int flags;\n\tstruct device *ns_seed;\n\tstruct device *btt_seed;\n\tstruct device *pfn_seed;\n\tstruct device *dax_seed;\n\tlong unsigned int align;\n\tu16 ndr_mappings;\n\tu64 ndr_size;\n\tu64 ndr_start;\n\tint id;\n\tint num_lanes;\n\tint ro;\n\tint numa_node;\n\tint target_node;\n\tvoid *provider_data;\n\tstruct kernfs_node *bb_state;\n\tstruct badblocks bb;\n\tstruct nd_interleave_set *nd_set;\n\tstruct nd_percpu_lane *lane;\n\tint (*flush)(struct nd_region *, struct bio *);\n\tstruct nd_mapping mapping[0];\n};\n\nstruct nd_cmd_get_config_size {\n\t__u32 status;\n\t__u32 config_size;\n\t__u32 max_xfer;\n};\n\nstruct nd_cmd_set_config_hdr {\n\t__u32 in_offset;\n\t__u32 in_length;\n\t__u8 in_buf[0];\n};\n\nstruct nd_cmd_vendor_hdr {\n\t__u32 opcode;\n\t__u32 in_length;\n\t__u8 in_buf[0];\n};\n\nstruct nd_cmd_ars_cap {\n\t__u64 address;\n\t__u64 length;\n\t__u32 status;\n\t__u32 max_ars_out;\n\t__u32 clear_err_unit;\n\t__u16 flags;\n\t__u16 reserved;\n};\n\nstruct nd_cmd_clear_error {\n\t__u64 address;\n\t__u64 length;\n\t__u32 status;\n\t__u8 reserved[4];\n\t__u64 cleared;\n};\n\nstruct nd_cmd_pkg {\n\t__u64 nd_family;\n\t__u64 nd_command;\n\t__u32 nd_size_in;\n\t__u32 nd_size_out;\n\t__u32 nd_reserved2[9];\n\t__u32 nd_fw_size;\n\tunsigned char nd_payload[0];\n};\n\nenum nvdimm_event {\n\tNVDIMM_REVALIDATE_POISON = 0,\n\tNVDIMM_REVALIDATE_REGION = 1,\n};\n\nenum nvdimm_claim_class {\n\tNVDIMM_CCLASS_NONE = 0,\n\tNVDIMM_CCLASS_BTT = 1,\n\tNVDIMM_CCLASS_BTT2 = 2,\n\tNVDIMM_CCLASS_PFN = 3,\n\tNVDIMM_CCLASS_DAX = 4,\n\tNVDIMM_CCLASS_UNKNOWN = 5,\n};\n\nstruct nd_device_driver {\n\tstruct device_driver drv;\n\tlong unsigned int type;\n\tint (*probe)(struct device *);\n\tvoid (*remove)(struct device *);\n\tvoid (*shutdown)(struct device *);\n\tvoid (*notify)(struct device *, enum nvdimm_event);\n};\n\nstruct nd_namespace_common {\n\tint force_raw;\n\tstruct device dev;\n\tstruct device *claim;\n\tenum nvdimm_claim_class claim_class;\n\tint (*rw_bytes)(struct nd_namespace_common *, resource_size_t, void *, size_t, int, long unsigned int);\n};\n\nstruct nd_namespace_io {\n\tstruct nd_namespace_common common;\n\tstruct resource res;\n\tresource_size_t size;\n\tvoid *addr;\n\tstruct badblocks bb;\n};\n\nstruct nvdimm_drvdata {\n\tstruct device *dev;\n\tint nslabel_size;\n\tstruct nd_cmd_get_config_size nsarea;\n\tvoid *data;\n\tint ns_current;\n\tint ns_next;\n\tstruct resource dpa;\n\tstruct kref kref;\n};\n\nstruct nd_percpu_lane {\n\tint count;\n\tspinlock_t lock;\n};\n\nstruct btt;\n\nstruct nd_btt {\n\tstruct device dev;\n\tstruct nd_namespace_common *ndns;\n\tstruct btt *btt;\n\tlong unsigned int lbasize;\n\tu64 size;\n\tu8 *uuid;\n\tint id;\n\tint initial_offset;\n\tu16 version_major;\n\tu16 version_minor;\n};\n\nenum nd_pfn_mode {\n\tPFN_MODE_NONE = 0,\n\tPFN_MODE_RAM = 1,\n\tPFN_MODE_PMEM = 2,\n};\n\nstruct nd_pfn_sb;\n\nstruct nd_pfn {\n\tint id;\n\tu8 *uuid;\n\tstruct device dev;\n\tlong unsigned int align;\n\tlong unsigned int npfns;\n\tenum nd_pfn_mode mode;\n\tstruct nd_pfn_sb *pfn_sb;\n\tstruct nd_namespace_common *ndns;\n};\n\nstruct nd_pfn_sb {\n\tu8 signature[16];\n\tu8 uuid[16];\n\tu8 parent_uuid[16];\n\t__le32 flags;\n\t__le16 version_major;\n\t__le16 version_minor;\n\t__le64 dataoff;\n\t__le64 npfns;\n\t__le32 mode;\n\t__le32 start_pad;\n\t__le32 end_trunc;\n\t__le32 align;\n\t__le32 page_size;\n\t__le16 page_struct_size;\n\tu8 padding[3994];\n\t__le64 checksum;\n};\n\nstruct nd_dax {\n\tstruct nd_pfn nd_pfn;\n};\n\nenum nd_async_mode {\n\tND_SYNC = 0,\n\tND_ASYNC = 1,\n};\n\nstruct clear_badblocks_context {\n\tresource_size_t phys;\n\tresource_size_t cleared;\n};\n\nenum nd_ioctl_mode {\n\tBUS_IOCTL = 0,\n\tDIMM_IOCTL = 1,\n};\n\nstruct nd_cmd_get_config_data_hdr {\n\t__u32 in_offset;\n\t__u32 in_length;\n\t__u32 status;\n\t__u8 out_buf[0];\n};\n\nstruct nd_blk_region {\n\tint (*enable)(struct nvdimm_bus *, struct device *);\n\tint (*do_io)(struct nd_blk_region *, resource_size_t, void *, u64, int);\n\tvoid *blk_provider_data;\n\tstruct nd_region nd_region;\n};\n\nenum nvdimm_security_bits {\n\tNVDIMM_SECURITY_DISABLED = 0,\n\tNVDIMM_SECURITY_UNLOCKED = 1,\n\tNVDIMM_SECURITY_LOCKED = 2,\n\tNVDIMM_SECURITY_FROZEN = 3,\n\tNVDIMM_SECURITY_OVERWRITE = 4,\n};\n\nstruct nd_label_id {\n\tchar id[50];\n};\n\nstruct blk_alloc_info {\n\tstruct nd_mapping *nd_mapping;\n\tresource_size_t available;\n\tresource_size_t busy;\n\tstruct resource *res;\n};\n\nenum nd_driver_flags {\n\tND_DRIVER_DIMM = 2,\n\tND_DRIVER_REGION_PMEM = 4,\n\tND_DRIVER_REGION_BLK = 8,\n\tND_DRIVER_NAMESPACE_IO = 16,\n\tND_DRIVER_NAMESPACE_PMEM = 32,\n\tND_DRIVER_NAMESPACE_BLK = 64,\n\tND_DRIVER_DAX_PMEM = 128,\n};\n\nstruct nd_mapping_desc {\n\tstruct nvdimm *nvdimm;\n\tu64 start;\n\tu64 size;\n\tint position;\n};\n\nstruct nd_region_desc {\n\tstruct resource *res;\n\tstruct nd_mapping_desc *mapping;\n\tu16 num_mappings;\n\tconst struct attribute_group **attr_groups;\n\tstruct nd_interleave_set *nd_set;\n\tvoid *provider_data;\n\tint num_lanes;\n\tint numa_node;\n\tint target_node;\n\tlong unsigned int flags;\n\tstruct device_node *of_node;\n\tint (*flush)(struct nd_region *, struct bio *);\n};\n\nstruct nd_blk_region_desc {\n\tint (*enable)(struct nvdimm_bus *, struct device *);\n\tint (*do_io)(struct nd_blk_region *, resource_size_t, void *, u64, int);\n\tstruct nd_region_desc ndr_desc;\n};\n\nstruct nd_namespace_index {\n\tu8 sig[16];\n\tu8 flags[3];\n\tu8 labelsize;\n\t__le32 seq;\n\t__le64 myoff;\n\t__le64 mysize;\n\t__le64 otheroff;\n\t__le64 labeloff;\n\t__le32 nslot;\n\t__le16 major;\n\t__le16 minor;\n\t__le64 checksum;\n\tu8 free[0];\n};\n\nstruct nd_namespace_label {\n\tu8 uuid[16];\n\tu8 name[64];\n\t__le32 flags;\n\t__le16 nlabel;\n\t__le16 position;\n\t__le64 isetcookie;\n\t__le64 lbasize;\n\t__le64 dpa;\n\t__le64 rawsize;\n\t__le32 slot;\n\tu8 align;\n\tu8 reserved[3];\n\tguid_t type_guid;\n\tguid_t abstraction_guid;\n\tu8 reserved2[88];\n\t__le64 checksum;\n};\n\nenum {\n\tND_MAX_LANES = 256,\n\tINT_LBASIZE_ALIGNMENT = 64,\n\tNVDIMM_IO_ATOMIC = 1,\n};\n\nstruct nd_region_data {\n\tint ns_count;\n\tint ns_active;\n\tunsigned int hints_shift;\n\tvoid *flush_wpq[0];\n};\n\nstruct nd_label_ent {\n\tstruct list_head list;\n\tlong unsigned int flags;\n\tstruct nd_namespace_label *label;\n};\n\nstruct conflict_context {\n\tstruct nd_region *nd_region;\n\tresource_size_t start;\n\tresource_size_t size;\n};\n\nenum {\n\tND_MIN_NAMESPACE_SIZE = 4096,\n};\n\nstruct nd_namespace_pmem {\n\tstruct nd_namespace_io nsio;\n\tlong unsigned int lbasize;\n\tchar *alt_name;\n\tu8 *uuid;\n\tint id;\n};\n\nstruct nd_namespace_blk {\n\tstruct nd_namespace_common common;\n\tchar *alt_name;\n\tu8 *uuid;\n\tint id;\n\tlong unsigned int lbasize;\n\tresource_size_t size;\n\tint num_resources;\n\tstruct resource **res;\n};\n\nenum nd_label_flags {\n\tND_LABEL_REAP = 0,\n};\n\nenum alloc_loc {\n\tALLOC_ERR = 0,\n\tALLOC_BEFORE = 1,\n\tALLOC_MID = 2,\n\tALLOC_AFTER = 3,\n};\n\nstruct btt {\n\tstruct gendisk *btt_disk;\n\tstruct list_head arena_list;\n\tstruct dentry *debugfs_dir;\n\tstruct nd_btt *nd_btt;\n\tu64 nlba;\n\tlong long unsigned int rawsize;\n\tu32 lbasize;\n\tu32 sector_size;\n\tstruct nd_region *nd_region;\n\tstruct mutex init_lock;\n\tint init_state;\n\tint num_arenas;\n\tstruct badblocks *phys_bb;\n};\n\nstruct nd_gen_sb {\n\tchar reserved[4088];\n\t__le64 checksum;\n};\n\nstruct btt_sb {\n\tu8 signature[16];\n\tu8 uuid[16];\n\tu8 parent_uuid[16];\n\t__le32 flags;\n\t__le16 version_major;\n\t__le16 version_minor;\n\t__le32 external_lbasize;\n\t__le32 external_nlba;\n\t__le32 internal_lbasize;\n\t__le32 internal_nlba;\n\t__le32 nfree;\n\t__le32 infosize;\n\t__le64 nextoff;\n\t__le64 dataoff;\n\t__le64 mapoff;\n\t__le64 logoff;\n\t__le64 info2off;\n\tu8 padding[3968];\n\t__le64 checksum;\n};\n\nstruct dax_operations {\n\tlong int (*direct_access)(struct dax_device *, long unsigned int, long int, void **, pfn_t *);\n\tbool (*dax_supported)(struct dax_device *, struct block_device *, int, sector_t, sector_t);\n\tsize_t (*copy_from_iter)(struct dax_device *, long unsigned int, void *, size_t, struct iov_iter *);\n\tsize_t (*copy_to_iter)(struct dax_device *, long unsigned int, void *, size_t, struct iov_iter *);\n\tint (*zero_page_range)(struct dax_device *, long unsigned int, size_t);\n};\n\nstruct dax_device {\n\tstruct hlist_node list;\n\tstruct inode inode;\n\tstruct cdev cdev;\n\tconst char *host;\n\tvoid *private;\n\tlong unsigned int flags;\n\tconst struct dax_operations *ops;\n};\n\nenum dax_device_flags {\n\tDAXDEV_ALIVE = 0,\n\tDAXDEV_WRITE_CACHE = 1,\n\tDAXDEV_SYNC = 2,\n};\n\nstruct dax_region {\n\tint id;\n\tint target_node;\n\tstruct kref kref;\n\tstruct device *dev;\n\tunsigned int align;\n\tstruct ida ida;\n\tstruct resource res;\n\tstruct device *seed;\n\tstruct device *youngest;\n};\n\nstruct dax_mapping {\n\tstruct device dev;\n\tint range_id;\n\tint id;\n};\n\nstruct dev_dax_range {\n\tlong unsigned int pgoff;\n\tstruct range range;\n\tstruct dax_mapping *mapping;\n};\n\nstruct dev_dax {\n\tstruct dax_region *region;\n\tstruct dax_device *dax_dev;\n\tunsigned int align;\n\tint target_node;\n\tint id;\n\tstruct ida ida;\n\tstruct device dev;\n\tstruct dev_pagemap *pgmap;\n\tint nr_range;\n\tstruct dev_dax_range *ranges;\n};\n\nenum dev_dax_subsys {\n\tDEV_DAX_BUS = 0,\n\tDEV_DAX_CLASS = 1,\n};\n\nstruct dev_dax_data {\n\tstruct dax_region *dax_region;\n\tstruct dev_pagemap *pgmap;\n\tenum dev_dax_subsys subsys;\n\tresource_size_t size;\n\tint id;\n};\n\nstruct dax_device_driver {\n\tstruct device_driver drv;\n\tstruct list_head ids;\n\tint match_always;\n\tint (*probe)(struct dev_dax *);\n\tvoid (*remove)(struct dev_dax *);\n};\n\nstruct dax_id {\n\tstruct list_head list;\n\tchar dev_name[30];\n};\n\nenum id_action {\n\tID_REMOVE = 0,\n\tID_ADD = 1,\n};\n\nstruct memregion_info {\n\tint target_node;\n};\n\nstruct seqcount_ww_mutex {\n\tseqcount_t seqcount;\n};\n\ntypedef struct seqcount_ww_mutex seqcount_ww_mutex_t;\n\nstruct dma_buf_map {\n\tunion {\n\t\tvoid *vaddr_iomem;\n\t\tvoid *vaddr;\n\t};\n\tbool is_iomem;\n};\n\nstruct dma_fence_ops;\n\nstruct dma_fence {\n\tspinlock_t *lock;\n\tconst struct dma_fence_ops *ops;\n\tunion {\n\t\tstruct list_head cb_list;\n\t\tktime_t timestamp;\n\t\tstruct callback_head rcu;\n\t};\n\tu64 context;\n\tu64 seqno;\n\tlong unsigned int flags;\n\tstruct kref refcount;\n\tint error;\n};\n\nstruct dma_fence_ops {\n\tbool use_64bit_seqno;\n\tconst char * (*get_driver_name)(struct dma_fence *);\n\tconst char * (*get_timeline_name)(struct dma_fence *);\n\tbool (*enable_signaling)(struct dma_fence *);\n\tbool (*signaled)(struct dma_fence *);\n\tlong int (*wait)(struct dma_fence *, bool, long int);\n\tvoid (*release)(struct dma_fence *);\n\tvoid (*fence_value_str)(struct dma_fence *, char *, int);\n\tvoid (*timeline_value_str)(struct dma_fence *, char *, int);\n};\n\nenum dma_fence_flag_bits {\n\tDMA_FENCE_FLAG_SIGNALED_BIT = 0,\n\tDMA_FENCE_FLAG_TIMESTAMP_BIT = 1,\n\tDMA_FENCE_FLAG_ENABLE_SIGNAL_BIT = 2,\n\tDMA_FENCE_FLAG_USER_BITS = 3,\n};\n\nstruct dma_fence_cb;\n\ntypedef void (*dma_fence_func_t)(struct dma_fence *, struct dma_fence_cb *);\n\nstruct dma_fence_cb {\n\tstruct list_head node;\n\tdma_fence_func_t func;\n};\n\nstruct dma_buf;\n\nstruct dma_buf_attachment;\n\nstruct dma_buf_ops {\n\tbool cache_sgt_mapping;\n\tint (*attach)(struct dma_buf *, struct dma_buf_attachment *);\n\tvoid (*detach)(struct dma_buf *, struct dma_buf_attachment *);\n\tint (*pin)(struct dma_buf_attachment *);\n\tvoid (*unpin)(struct dma_buf_attachment *);\n\tstruct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction);\n\tvoid (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *, enum dma_data_direction);\n\tvoid (*release)(struct dma_buf *);\n\tint (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);\n\tint (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);\n\tint (*mmap)(struct dma_buf *, struct vm_area_struct *);\n\tint (*vmap)(struct dma_buf *, struct dma_buf_map *);\n\tvoid (*vunmap)(struct dma_buf *, struct dma_buf_map *);\n};\n\nstruct dma_buf_poll_cb_t {\n\tstruct dma_fence_cb cb;\n\twait_queue_head_t *poll;\n\t__poll_t active;\n};\n\nstruct dma_resv;\n\nstruct dma_buf {\n\tsize_t size;\n\tstruct file *file;\n\tstruct list_head attachments;\n\tconst struct dma_buf_ops *ops;\n\tstruct mutex lock;\n\tunsigned int vmapping_counter;\n\tstruct dma_buf_map vmap_ptr;\n\tconst char *exp_name;\n\tconst char *name;\n\tspinlock_t name_lock;\n\tstruct module *owner;\n\tstruct list_head list_node;\n\tvoid *priv;\n\tstruct dma_resv *resv;\n\twait_queue_head_t poll;\n\tstruct dma_buf_poll_cb_t cb_excl;\n\tstruct dma_buf_poll_cb_t cb_shared;\n};\n\nstruct dma_buf_attach_ops;\n\nstruct dma_buf_attachment {\n\tstruct dma_buf *dmabuf;\n\tstruct device *dev;\n\tstruct list_head node;\n\tstruct sg_table *sgt;\n\tenum dma_data_direction dir;\n\tbool peer2peer;\n\tconst struct dma_buf_attach_ops *importer_ops;\n\tvoid *importer_priv;\n\tvoid *priv;\n};\n\nstruct dma_resv_list;\n\nstruct dma_resv {\n\tstruct ww_mutex lock;\n\tseqcount_ww_mutex_t seq;\n\tstruct dma_fence *fence_excl;\n\tstruct dma_resv_list *fence;\n};\n\nstruct dma_buf_attach_ops {\n\tbool allow_peer2peer;\n\tvoid (*move_notify)(struct dma_buf_attachment *);\n};\n\nstruct dma_buf_export_info {\n\tconst char *exp_name;\n\tstruct module *owner;\n\tconst struct dma_buf_ops *ops;\n\tsize_t size;\n\tint flags;\n\tstruct dma_resv *resv;\n\tvoid *priv;\n};\n\nstruct dma_resv_list {\n\tstruct callback_head rcu;\n\tu32 shared_count;\n\tu32 shared_max;\n\tstruct dma_fence *shared[0];\n};\n\nstruct dma_buf_sync {\n\t__u64 flags;\n};\n\nstruct dma_buf_list {\n\tstruct list_head head;\n\tstruct mutex lock;\n};\n\nstruct trace_event_raw_dma_fence {\n\tstruct trace_entry ent;\n\tu32 __data_loc_driver;\n\tu32 __data_loc_timeline;\n\tunsigned int context;\n\tunsigned int seqno;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_dma_fence {\n\tu32 driver;\n\tu32 timeline;\n};\n\ntypedef void (*btf_trace_dma_fence_emit)(void *, struct dma_fence *);\n\ntypedef void (*btf_trace_dma_fence_init)(void *, struct dma_fence *);\n\ntypedef void (*btf_trace_dma_fence_destroy)(void *, struct dma_fence *);\n\ntypedef void (*btf_trace_dma_fence_enable_signal)(void *, struct dma_fence *);\n\ntypedef void (*btf_trace_dma_fence_signaled)(void *, struct dma_fence *);\n\ntypedef void (*btf_trace_dma_fence_wait_start)(void *, struct dma_fence *);\n\ntypedef void (*btf_trace_dma_fence_wait_end)(void *, struct dma_fence *);\n\nstruct default_wait_cb {\n\tstruct dma_fence_cb base;\n\tstruct task_struct *task;\n};\n\nstruct dma_fence_array;\n\nstruct dma_fence_array_cb {\n\tstruct dma_fence_cb cb;\n\tstruct dma_fence_array *array;\n};\n\nstruct dma_fence_array {\n\tstruct dma_fence base;\n\tspinlock_t lock;\n\tunsigned int num_fences;\n\tatomic_t num_pending;\n\tstruct dma_fence **fences;\n\tstruct irq_work work;\n};\n\nstruct dma_fence_chain {\n\tstruct dma_fence base;\n\tspinlock_t lock;\n\tstruct dma_fence *prev;\n\tu64 prev_seqno;\n\tstruct dma_fence *fence;\n\tstruct dma_fence_cb cb;\n\tstruct irq_work work;\n};\n\nenum seqno_fence_condition {\n\tSEQNO_FENCE_WAIT_GEQUAL = 0,\n\tSEQNO_FENCE_WAIT_NONZERO = 1,\n};\n\nstruct seqno_fence {\n\tstruct dma_fence base;\n\tconst struct dma_fence_ops *ops;\n\tstruct dma_buf *sync_buf;\n\tuint32_t seqno_ofs;\n\tenum seqno_fence_condition condition;\n};\n\nstruct dma_heap;\n\nstruct dma_heap_ops {\n\tstruct dma_buf * (*allocate)(struct dma_heap *, long unsigned int, long unsigned int, long unsigned int);\n};\n\nstruct dma_heap {\n\tconst char *name;\n\tconst struct dma_heap_ops *ops;\n\tvoid *priv;\n\tdev_t heap_devt;\n\tstruct list_head list;\n\tstruct cdev heap_cdev;\n};\n\nstruct dma_heap_export_info {\n\tconst char *name;\n\tconst struct dma_heap_ops *ops;\n\tvoid *priv;\n};\n\nstruct dma_heap_allocation_data {\n\t__u64 len;\n\t__u32 fd;\n\t__u32 fd_flags;\n\t__u64 heap_flags;\n};\n\nstruct system_heap_buffer {\n\tstruct dma_heap *heap;\n\tstruct list_head attachments;\n\tstruct mutex lock;\n\tlong unsigned int len;\n\tstruct sg_table sg_table;\n\tint vmap_cnt;\n\tvoid *vaddr;\n};\n\nstruct dma_heap_attachment {\n\tstruct device *dev;\n\tstruct sg_table *table;\n\tstruct list_head list;\n\tbool mapped;\n};\n\nstruct cma_heap {\n\tstruct dma_heap *heap;\n\tstruct cma *cma;\n};\n\nstruct cma_heap_buffer {\n\tstruct cma_heap *heap;\n\tstruct list_head attachments;\n\tstruct mutex lock;\n\tlong unsigned int len;\n\tstruct page *cma_pages;\n\tstruct page **pages;\n\tlong unsigned int pagecount;\n\tint vmap_cnt;\n\tvoid *vaddr;\n};\n\nstruct dma_heap_attachment___2 {\n\tstruct device *dev;\n\tstruct sg_table table;\n\tstruct list_head list;\n\tbool mapped;\n};\n\nstruct sync_file {\n\tstruct file *file;\n\tchar user_name[32];\n\tstruct list_head sync_file_list;\n\twait_queue_head_t wq;\n\tlong unsigned int flags;\n\tstruct dma_fence *fence;\n\tstruct dma_fence_cb cb;\n};\n\nstruct sync_merge_data {\n\tchar name[32];\n\t__s32 fd2;\n\t__s32 fence;\n\t__u32 flags;\n\t__u32 pad;\n};\n\nstruct sync_fence_info {\n\tchar obj_name[32];\n\tchar driver_name[32];\n\t__s32 status;\n\t__u32 flags;\n\t__u64 timestamp_ns;\n};\n\nstruct sync_file_info {\n\tchar name[32];\n\t__s32 status;\n\t__u32 flags;\n\t__u32 num_fences;\n\t__u32 pad;\n\t__u64 sync_fence_info;\n};\n\nstruct udmabuf_create {\n\t__u32 memfd;\n\t__u32 flags;\n\t__u64 offset;\n\t__u64 size;\n};\n\nstruct udmabuf_create_item {\n\t__u32 memfd;\n\t__u32 __pad;\n\t__u64 offset;\n\t__u64 size;\n};\n\nstruct udmabuf_create_list {\n\t__u32 flags;\n\t__u32 count;\n\tstruct udmabuf_create_item list[0];\n};\n\nstruct udmabuf {\n\tlong unsigned int pagecount;\n\tstruct page **pages;\n\tstruct sg_table *sg;\n\tstruct miscdevice *device;\n};\n\nenum scsi_host_status {\n\tDID_OK = 0,\n\tDID_NO_CONNECT = 1,\n\tDID_BUS_BUSY = 2,\n\tDID_TIME_OUT = 3,\n\tDID_BAD_TARGET = 4,\n\tDID_ABORT = 5,\n\tDID_PARITY = 6,\n\tDID_ERROR = 7,\n\tDID_RESET = 8,\n\tDID_BAD_INTR = 9,\n\tDID_PASSTHROUGH = 10,\n\tDID_SOFT_ERROR = 11,\n\tDID_IMM_RETRY = 12,\n\tDID_REQUEUE = 13,\n\tDID_TRANSPORT_DISRUPTED = 14,\n\tDID_TRANSPORT_FAILFAST = 15,\n\tDID_TARGET_FAILURE = 16,\n\tDID_NEXUS_FAILURE = 17,\n\tDID_ALLOC_FAILURE = 18,\n\tDID_MEDIUM_ERROR = 19,\n\tDID_TRANSPORT_MARGINAL = 20,\n};\n\nenum scsi_disposition {\n\tNEEDS_RETRY = 8193,\n\tSUCCESS = 8194,\n\tFAILED = 8195,\n\tQUEUED = 8196,\n\tSOFT_ERROR = 8197,\n\tADD_TO_MLQUEUE = 8198,\n\tTIMEOUT_ERROR = 8199,\n\tSCSI_RETURN_NOT_HANDLED = 8200,\n\tFAST_IO_FAIL = 8201,\n};\n\ntypedef __u64 blist_flags_t;\n\nenum scsi_device_state {\n\tSDEV_CREATED = 1,\n\tSDEV_RUNNING = 2,\n\tSDEV_CANCEL = 3,\n\tSDEV_DEL = 4,\n\tSDEV_QUIESCE = 5,\n\tSDEV_OFFLINE = 6,\n\tSDEV_TRANSPORT_OFFLINE = 7,\n\tSDEV_BLOCK = 8,\n\tSDEV_CREATED_BLOCK = 9,\n};\n\nstruct scsi_vpd {\n\tstruct callback_head rcu;\n\tint len;\n\tunsigned char data[0];\n};\n\nstruct Scsi_Host;\n\nstruct scsi_target;\n\nstruct scsi_device_handler;\n\nstruct scsi_device {\n\tstruct Scsi_Host *host;\n\tstruct request_queue *request_queue;\n\tstruct list_head siblings;\n\tstruct list_head same_target_siblings;\n\tstruct sbitmap budget_map;\n\tatomic_t device_blocked;\n\tatomic_t restarts;\n\tspinlock_t list_lock;\n\tstruct list_head starved_entry;\n\tshort unsigned int queue_depth;\n\tshort unsigned int max_queue_depth;\n\tshort unsigned int last_queue_full_depth;\n\tshort unsigned int last_queue_full_count;\n\tlong unsigned int last_queue_full_time;\n\tlong unsigned int queue_ramp_up_period;\n\tlong unsigned int last_queue_ramp_up;\n\tunsigned int id;\n\tunsigned int channel;\n\tu64 lun;\n\tunsigned int manufacturer;\n\tunsigned int sector_size;\n\tvoid *hostdata;\n\tunsigned char type;\n\tchar scsi_level;\n\tchar inq_periph_qual;\n\tstruct mutex inquiry_mutex;\n\tunsigned char inquiry_len;\n\tunsigned char *inquiry;\n\tconst char *vendor;\n\tconst char *model;\n\tconst char *rev;\n\tstruct scsi_vpd *vpd_pg0;\n\tstruct scsi_vpd *vpd_pg83;\n\tstruct scsi_vpd *vpd_pg80;\n\tstruct scsi_vpd *vpd_pg89;\n\tunsigned char current_tag;\n\tstruct scsi_target *sdev_target;\n\tblist_flags_t sdev_bflags;\n\tunsigned int eh_timeout;\n\tunsigned int removable: 1;\n\tunsigned int changed: 1;\n\tunsigned int busy: 1;\n\tunsigned int lockable: 1;\n\tunsigned int locked: 1;\n\tunsigned int borken: 1;\n\tunsigned int disconnect: 1;\n\tunsigned int soft_reset: 1;\n\tunsigned int sdtr: 1;\n\tunsigned int wdtr: 1;\n\tunsigned int ppr: 1;\n\tunsigned int tagged_supported: 1;\n\tunsigned int simple_tags: 1;\n\tunsigned int was_reset: 1;\n\tunsigned int expecting_cc_ua: 1;\n\tunsigned int use_10_for_rw: 1;\n\tunsigned int use_10_for_ms: 1;\n\tunsigned int set_dbd_for_ms: 1;\n\tunsigned int no_report_opcodes: 1;\n\tunsigned int no_write_same: 1;\n\tunsigned int use_16_for_rw: 1;\n\tunsigned int skip_ms_page_8: 1;\n\tunsigned int skip_ms_page_3f: 1;\n\tunsigned int skip_vpd_pages: 1;\n\tunsigned int try_vpd_pages: 1;\n\tunsigned int use_192_bytes_for_3f: 1;\n\tunsigned int no_start_on_add: 1;\n\tunsigned int allow_restart: 1;\n\tunsigned int manage_start_stop: 1;\n\tunsigned int start_stop_pwr_cond: 1;\n\tunsigned int no_uld_attach: 1;\n\tunsigned int select_no_atn: 1;\n\tunsigned int fix_capacity: 1;\n\tunsigned int guess_capacity: 1;\n\tunsigned int retry_hwerror: 1;\n\tunsigned int last_sector_bug: 1;\n\tunsigned int no_read_disc_info: 1;\n\tunsigned int no_read_capacity_16: 1;\n\tunsigned int try_rc_10_first: 1;\n\tunsigned int security_supported: 1;\n\tunsigned int is_visible: 1;\n\tunsigned int wce_default_on: 1;\n\tunsigned int no_dif: 1;\n\tunsigned int broken_fua: 1;\n\tunsigned int lun_in_cdb: 1;\n\tunsigned int unmap_limit_for_ws: 1;\n\tunsigned int rpm_autosuspend: 1;\n\tbool offline_already;\n\tatomic_t disk_events_disable_depth;\n\tlong unsigned int supported_events[1];\n\tlong unsigned int pending_events[1];\n\tstruct list_head event_list;\n\tstruct work_struct event_work;\n\tunsigned int max_device_blocked;\n\tatomic_t iorequest_cnt;\n\tatomic_t iodone_cnt;\n\tatomic_t ioerr_cnt;\n\tstruct device sdev_gendev;\n\tstruct device sdev_dev;\n\tstruct execute_work ew;\n\tstruct work_struct requeue_work;\n\tstruct scsi_device_handler *handler;\n\tvoid *handler_data;\n\tsize_t dma_drain_len;\n\tvoid *dma_drain_buf;\n\tunsigned char access_state;\n\tstruct mutex state_mutex;\n\tenum scsi_device_state sdev_state;\n\tstruct task_struct *quiesced_by;\n\tlong unsigned int sdev_data[0];\n};\n\nenum scsi_host_state {\n\tSHOST_CREATED = 1,\n\tSHOST_RUNNING = 2,\n\tSHOST_CANCEL = 3,\n\tSHOST_DEL = 4,\n\tSHOST_RECOVERY = 5,\n\tSHOST_CANCEL_RECOVERY = 6,\n\tSHOST_DEL_RECOVERY = 7,\n};\n\nstruct scsi_host_template;\n\nstruct scsi_transport_template;\n\nstruct Scsi_Host {\n\tstruct list_head __devices;\n\tstruct list_head __targets;\n\tstruct list_head starved_list;\n\tspinlock_t default_lock;\n\tspinlock_t *host_lock;\n\tstruct mutex scan_mutex;\n\tstruct list_head eh_cmd_q;\n\tstruct task_struct *ehandler;\n\tstruct completion *eh_action;\n\twait_queue_head_t host_wait;\n\tstruct scsi_host_template *hostt;\n\tstruct scsi_transport_template *transportt;\n\tstruct blk_mq_tag_set tag_set;\n\tatomic_t host_blocked;\n\tunsigned int host_failed;\n\tunsigned int host_eh_scheduled;\n\tunsigned int host_no;\n\tint eh_deadline;\n\tlong unsigned int last_reset;\n\tunsigned int max_channel;\n\tunsigned int max_id;\n\tu64 max_lun;\n\tunsigned int unique_id;\n\tshort unsigned int max_cmd_len;\n\tint this_id;\n\tint can_queue;\n\tshort int cmd_per_lun;\n\tshort unsigned int sg_tablesize;\n\tshort unsigned int sg_prot_tablesize;\n\tunsigned int max_sectors;\n\tunsigned int max_segment_size;\n\tlong unsigned int dma_boundary;\n\tlong unsigned int virt_boundary_mask;\n\tunsigned int nr_hw_queues;\n\tunsigned int nr_maps;\n\tunsigned int active_mode: 2;\n\tunsigned int host_self_blocked: 1;\n\tunsigned int reverse_ordering: 1;\n\tunsigned int tmf_in_progress: 1;\n\tunsigned int async_scan: 1;\n\tunsigned int eh_noresume: 1;\n\tunsigned int no_write_same: 1;\n\tunsigned int host_tagset: 1;\n\tunsigned int short_inquiry: 1;\n\tunsigned int no_scsi2_lun_in_cdb: 1;\n\tchar work_q_name[20];\n\tstruct workqueue_struct *work_q;\n\tstruct workqueue_struct *tmf_work_q;\n\tunsigned int max_host_blocked;\n\tunsigned int prot_capabilities;\n\tunsigned char prot_guard_type;\n\tlong unsigned int base;\n\tlong unsigned int io_port;\n\tunsigned char n_io_port;\n\tunsigned char dma_channel;\n\tunsigned int irq;\n\tenum scsi_host_state shost_state;\n\tstruct device shost_gendev;\n\tstruct device shost_dev;\n\tvoid *shost_data;\n\tstruct device *dma_dev;\n\tlong unsigned int hostdata[0];\n};\n\nenum scsi_target_state {\n\tSTARGET_CREATED = 1,\n\tSTARGET_RUNNING = 2,\n\tSTARGET_REMOVE = 3,\n\tSTARGET_CREATED_REMOVE = 4,\n\tSTARGET_DEL = 5,\n};\n\nstruct scsi_target {\n\tstruct scsi_device *starget_sdev_user;\n\tstruct list_head siblings;\n\tstruct list_head devices;\n\tstruct device dev;\n\tstruct kref reap_ref;\n\tunsigned int channel;\n\tunsigned int id;\n\tunsigned int create: 1;\n\tunsigned int single_lun: 1;\n\tunsigned int pdt_1f_for_no_lun: 1;\n\tunsigned int no_report_luns: 1;\n\tunsigned int expecting_lun_change: 1;\n\tatomic_t target_busy;\n\tatomic_t target_blocked;\n\tunsigned int can_queue;\n\tunsigned int max_target_blocked;\n\tchar scsi_level;\n\tenum scsi_target_state state;\n\tvoid *hostdata;\n\tlong unsigned int starget_data[0];\n};\n\nstruct scsi_host_cmd_pool;\n\nstruct scsi_cmnd;\n\nstruct scsi_host_template {\n\tunsigned int cmd_size;\n\tint (*queuecommand)(struct Scsi_Host *, struct scsi_cmnd *);\n\tvoid (*commit_rqs)(struct Scsi_Host *, u16);\n\tstruct module *module;\n\tconst char *name;\n\tconst char * (*info)(struct Scsi_Host *);\n\tint (*ioctl)(struct scsi_device *, unsigned int, void *);\n\tint (*compat_ioctl)(struct scsi_device *, unsigned int, void *);\n\tint (*init_cmd_priv)(struct Scsi_Host *, struct scsi_cmnd *);\n\tint (*exit_cmd_priv)(struct Scsi_Host *, struct scsi_cmnd *);\n\tint (*eh_abort_handler)(struct scsi_cmnd *);\n\tint (*eh_device_reset_handler)(struct scsi_cmnd *);\n\tint (*eh_target_reset_handler)(struct scsi_cmnd *);\n\tint (*eh_bus_reset_handler)(struct scsi_cmnd *);\n\tint (*eh_host_reset_handler)(struct scsi_cmnd *);\n\tint (*slave_alloc)(struct scsi_device *);\n\tint (*slave_configure)(struct scsi_device *);\n\tvoid (*slave_destroy)(struct scsi_device *);\n\tint (*target_alloc)(struct scsi_target *);\n\tvoid (*target_destroy)(struct scsi_target *);\n\tint (*scan_finished)(struct Scsi_Host *, long unsigned int);\n\tvoid (*scan_start)(struct Scsi_Host *);\n\tint (*change_queue_depth)(struct scsi_device *, int);\n\tint (*map_queues)(struct Scsi_Host *);\n\tint (*mq_poll)(struct Scsi_Host *, unsigned int);\n\tbool (*dma_need_drain)(struct request *);\n\tint (*bios_param)(struct scsi_device *, struct block_device *, sector_t, int *);\n\tvoid (*unlock_native_capacity)(struct scsi_device *);\n\tint (*show_info)(struct seq_file *, struct Scsi_Host *);\n\tint (*write_info)(struct Scsi_Host *, char *, int);\n\tenum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);\n\tbool (*eh_should_retry_cmd)(struct scsi_cmnd *);\n\tint (*host_reset)(struct Scsi_Host *, int);\n\tconst char *proc_name;\n\tstruct proc_dir_entry *proc_dir;\n\tint can_queue;\n\tint this_id;\n\tshort unsigned int sg_tablesize;\n\tshort unsigned int sg_prot_tablesize;\n\tunsigned int max_sectors;\n\tunsigned int max_segment_size;\n\tlong unsigned int dma_boundary;\n\tlong unsigned int virt_boundary_mask;\n\tshort int cmd_per_lun;\n\tunsigned char present;\n\tint tag_alloc_policy;\n\tunsigned int track_queue_depth: 1;\n\tunsigned int supported_mode: 2;\n\tunsigned int emulated: 1;\n\tunsigned int skip_settle_delay: 1;\n\tunsigned int no_write_same: 1;\n\tunsigned int host_tagset: 1;\n\tunsigned int max_host_blocked;\n\tstruct device_attribute **shost_attrs;\n\tstruct device_attribute **sdev_attrs;\n\tconst struct attribute_group **sdev_groups;\n\tu64 vendor_id;\n\tstruct scsi_host_cmd_pool *cmd_pool;\n\tint rpm_autosuspend_delay;\n};\n\nstruct scsi_data_buffer {\n\tstruct sg_table table;\n\tunsigned int length;\n};\n\nstruct scsi_pointer {\n\tchar *ptr;\n\tint this_residual;\n\tstruct scatterlist *buffer;\n\tint buffers_residual;\n\tdma_addr_t dma_handle;\n\tvolatile int Status;\n\tvolatile int Message;\n\tvolatile int have_data_in;\n\tvolatile int sent_command;\n\tvolatile int phase;\n};\n\nstruct scsi_cmnd {\n\tstruct scsi_request req;\n\tstruct scsi_device *device;\n\tstruct list_head eh_entry;\n\tstruct delayed_work abort_work;\n\tstruct callback_head rcu;\n\tint eh_eflags;\n\tint budget_token;\n\tlong unsigned int jiffies_at_alloc;\n\tint retries;\n\tint allowed;\n\tunsigned char prot_op;\n\tunsigned char prot_type;\n\tunsigned char prot_flags;\n\tshort unsigned int cmd_len;\n\tenum dma_data_direction sc_data_direction;\n\tunsigned char *cmnd;\n\tstruct scsi_data_buffer sdb;\n\tstruct scsi_data_buffer *prot_sdb;\n\tunsigned int underflow;\n\tunsigned int transfersize;\n\tstruct request *request;\n\tunsigned char *sense_buffer;\n\tvoid (*scsi_done)(struct scsi_cmnd *);\n\tstruct scsi_pointer SCp;\n\tunsigned char *host_scribble;\n\tint result;\n\tint flags;\n\tlong unsigned int state;\n\tunsigned char tag;\n\tunsigned int extra_len;\n};\n\nenum scsi_prot_operations {\n\tSCSI_PROT_NORMAL = 0,\n\tSCSI_PROT_READ_INSERT = 1,\n\tSCSI_PROT_WRITE_STRIP = 2,\n\tSCSI_PROT_READ_STRIP = 3,\n\tSCSI_PROT_WRITE_INSERT = 4,\n\tSCSI_PROT_READ_PASS = 5,\n\tSCSI_PROT_WRITE_PASS = 6,\n};\n\nstruct scsi_driver {\n\tstruct device_driver gendrv;\n\tvoid (*rescan)(struct device *);\n\tblk_status_t (*init_command)(struct scsi_cmnd *);\n\tvoid (*uninit_command)(struct scsi_cmnd *);\n\tint (*done)(struct scsi_cmnd *);\n\tint (*eh_action)(struct scsi_cmnd *, int);\n\tvoid (*eh_reset)(struct scsi_cmnd *);\n};\n\nstruct trace_event_raw_scsi_dispatch_cmd_start {\n\tstruct trace_entry ent;\n\tunsigned int host_no;\n\tunsigned int channel;\n\tunsigned int id;\n\tunsigned int lun;\n\tunsigned int opcode;\n\tunsigned int cmd_len;\n\tunsigned int data_sglen;\n\tunsigned int prot_sglen;\n\tunsigned char prot_op;\n\tu32 __data_loc_cmnd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_scsi_dispatch_cmd_error {\n\tstruct trace_entry ent;\n\tunsigned int host_no;\n\tunsigned int channel;\n\tunsigned int id;\n\tunsigned int lun;\n\tint rtn;\n\tunsigned int opcode;\n\tunsigned int cmd_len;\n\tunsigned int data_sglen;\n\tunsigned int prot_sglen;\n\tunsigned char prot_op;\n\tu32 __data_loc_cmnd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_scsi_cmd_done_timeout_template {\n\tstruct trace_entry ent;\n\tunsigned int host_no;\n\tunsigned int channel;\n\tunsigned int id;\n\tunsigned int lun;\n\tint result;\n\tunsigned int opcode;\n\tunsigned int cmd_len;\n\tunsigned int data_sglen;\n\tunsigned int prot_sglen;\n\tunsigned char prot_op;\n\tu32 __data_loc_cmnd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_scsi_eh_wakeup {\n\tstruct trace_entry ent;\n\tunsigned int host_no;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_scsi_dispatch_cmd_start {\n\tu32 cmnd;\n};\n\nstruct trace_event_data_offsets_scsi_dispatch_cmd_error {\n\tu32 cmnd;\n};\n\nstruct trace_event_data_offsets_scsi_cmd_done_timeout_template {\n\tu32 cmnd;\n};\n\nstruct trace_event_data_offsets_scsi_eh_wakeup {};\n\ntypedef void (*btf_trace_scsi_dispatch_cmd_start)(void *, struct scsi_cmnd *);\n\ntypedef void (*btf_trace_scsi_dispatch_cmd_error)(void *, struct scsi_cmnd *, int);\n\ntypedef void (*btf_trace_scsi_dispatch_cmd_done)(void *, struct scsi_cmnd *);\n\ntypedef void (*btf_trace_scsi_dispatch_cmd_timeout)(void *, struct scsi_cmnd *);\n\ntypedef void (*btf_trace_scsi_eh_wakeup)(void *, struct Scsi_Host *);\n\nstruct scsi_transport_template {\n\tstruct transport_container host_attrs;\n\tstruct transport_container target_attrs;\n\tstruct transport_container device_attrs;\n\tint (*user_scan)(struct Scsi_Host *, uint, uint, u64);\n\tint device_size;\n\tint device_private_offset;\n\tint target_size;\n\tint target_private_offset;\n\tint host_size;\n\tunsigned int create_work_queue: 1;\n\tvoid (*eh_strategy_handler)(struct Scsi_Host *);\n};\n\nstruct scsi_host_busy_iter_data {\n\tbool (*fn)(struct scsi_cmnd *, void *, bool);\n\tvoid *priv;\n};\n\nstruct scsi_idlun {\n\t__u32 dev_id;\n\t__u32 host_unique_id;\n};\n\ntypedef void (*activate_complete)(void *, int);\n\nstruct scsi_device_handler {\n\tstruct list_head list;\n\tstruct module *module;\n\tconst char *name;\n\tenum scsi_disposition (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);\n\tint (*attach)(struct scsi_device *);\n\tvoid (*detach)(struct scsi_device *);\n\tint (*activate)(struct scsi_device *, activate_complete, void *);\n\tblk_status_t (*prep_fn)(struct scsi_device *, struct request *);\n\tint (*set_params)(struct scsi_device *, const char *);\n\tvoid (*rescan)(struct scsi_device *);\n};\n\nstruct scsi_eh_save {\n\tint result;\n\tunsigned int resid_len;\n\tint eh_eflags;\n\tenum dma_data_direction data_direction;\n\tunsigned int underflow;\n\tunsigned char cmd_len;\n\tunsigned char prot_op;\n\tunsigned char *cmnd;\n\tstruct scsi_data_buffer sdb;\n\tunsigned char eh_cmnd[16];\n\tstruct scatterlist sense_sgl;\n};\n\nstruct scsi_varlen_cdb_hdr {\n\t__u8 opcode;\n\t__u8 control;\n\t__u8 misc[5];\n\t__u8 additional_cdb_length;\n\t__be16 service_action;\n};\n\nstruct scsi_mode_data {\n\t__u32 length;\n\t__u16 block_descriptor_length;\n\t__u8 medium_type;\n\t__u8 device_specific;\n\t__u8 header_length;\n\t__u8 longlba: 1;\n};\n\nstruct scsi_event {\n\tenum scsi_device_event evt_type;\n\tstruct list_head node;\n};\n\nenum scsi_host_prot_capabilities {\n\tSHOST_DIF_TYPE1_PROTECTION = 1,\n\tSHOST_DIF_TYPE2_PROTECTION = 2,\n\tSHOST_DIF_TYPE3_PROTECTION = 4,\n\tSHOST_DIX_TYPE0_PROTECTION = 8,\n\tSHOST_DIX_TYPE1_PROTECTION = 16,\n\tSHOST_DIX_TYPE2_PROTECTION = 32,\n\tSHOST_DIX_TYPE3_PROTECTION = 64,\n};\n\nenum {\n\tACTION_FAIL = 0,\n\tACTION_REPREP = 1,\n\tACTION_RETRY = 2,\n\tACTION_DELAYED_RETRY = 3,\n};\n\nstruct value_name_pair;\n\nstruct sa_name_list {\n\tint opcode;\n\tconst struct value_name_pair *arr;\n\tint arr_sz;\n};\n\nstruct value_name_pair {\n\tint value;\n\tconst char *name;\n};\n\nstruct error_info {\n\tshort unsigned int code12;\n\tshort unsigned int size;\n};\n\nstruct error_info2 {\n\tunsigned char code1;\n\tunsigned char code2_min;\n\tunsigned char code2_max;\n\tconst char *str;\n\tconst char *fmt;\n};\n\nstruct scsi_lun {\n\t__u8 scsi_lun[8];\n};\n\nenum scsi_timeouts {\n\tSCSI_DEFAULT_EH_TIMEOUT = 3000,\n};\n\nenum scsi_scan_mode {\n\tSCSI_SCAN_INITIAL = 0,\n\tSCSI_SCAN_RESCAN = 1,\n\tSCSI_SCAN_MANUAL = 2,\n};\n\nstruct async_scan_data {\n\tstruct list_head list;\n\tstruct Scsi_Host *shost;\n\tstruct completion prev_finished;\n};\n\nenum scsi_devinfo_key {\n\tSCSI_DEVINFO_GLOBAL = 0,\n\tSCSI_DEVINFO_SPI = 1,\n};\n\nstruct scsi_dev_info_list {\n\tstruct list_head dev_info_list;\n\tchar vendor[8];\n\tchar model[16];\n\tblist_flags_t flags;\n\tunsigned int compatible;\n};\n\nstruct scsi_dev_info_list_table {\n\tstruct list_head node;\n\tstruct list_head scsi_dev_info_list;\n\tconst char *name;\n\tint key;\n};\n\nstruct double_list {\n\tstruct list_head *top;\n\tstruct list_head *bottom;\n};\n\nstruct scsi_nl_hdr {\n\t__u8 version;\n\t__u8 transport;\n\t__u16 magic;\n\t__u16 msgtype;\n\t__u16 msglen;\n};\n\nenum {\n\tSCSI_DH_OK = 0,\n\tSCSI_DH_DEV_FAILED = 1,\n\tSCSI_DH_DEV_TEMP_BUSY = 2,\n\tSCSI_DH_DEV_UNSUPP = 3,\n\tSCSI_DH_DEVICE_MAX = 4,\n\tSCSI_DH_NOTCONN = 5,\n\tSCSI_DH_CONN_FAILURE = 6,\n\tSCSI_DH_TRANSPORT_MAX = 7,\n\tSCSI_DH_IO = 8,\n\tSCSI_DH_INVALID_IO = 9,\n\tSCSI_DH_RETRY = 10,\n\tSCSI_DH_IMM_RETRY = 11,\n\tSCSI_DH_TIMED_OUT = 12,\n\tSCSI_DH_RES_TEMP_UNAVAIL = 13,\n\tSCSI_DH_DEV_OFFLINED = 14,\n\tSCSI_DH_NOMEM = 15,\n\tSCSI_DH_NOSYS = 16,\n\tSCSI_DH_DRIVER_MAX = 17,\n};\n\nstruct scsi_dh_blist {\n\tconst char *vendor;\n\tconst char *model;\n\tconst char *driver;\n};\n\nenum scsi_prot_flags {\n\tSCSI_PROT_TRANSFER_PI = 1,\n\tSCSI_PROT_GUARD_CHECK = 2,\n\tSCSI_PROT_REF_CHECK = 4,\n\tSCSI_PROT_REF_INCREMENT = 8,\n\tSCSI_PROT_IP_CHECKSUM = 16,\n};\n\nenum {\n\tSD_EXT_CDB_SIZE = 32,\n\tSD_MEMPOOL_SIZE = 2,\n};\n\nenum {\n\tSD_DEF_XFER_BLOCKS = 65535,\n\tSD_MAX_XFER_BLOCKS = 4294967295,\n\tSD_MAX_WS10_BLOCKS = 65535,\n\tSD_MAX_WS16_BLOCKS = 8388607,\n};\n\nenum {\n\tSD_LBP_FULL = 0,\n\tSD_LBP_UNMAP = 1,\n\tSD_LBP_WS16 = 2,\n\tSD_LBP_WS10 = 3,\n\tSD_LBP_ZERO = 4,\n\tSD_LBP_DISABLE = 5,\n};\n\nenum {\n\tSD_ZERO_WRITE = 0,\n\tSD_ZERO_WS = 1,\n\tSD_ZERO_WS16_UNMAP = 2,\n\tSD_ZERO_WS10_UNMAP = 3,\n};\n\nstruct opal_dev___2;\n\nstruct scsi_disk {\n\tstruct scsi_driver *driver;\n\tstruct scsi_device *device;\n\tstruct device dev;\n\tstruct gendisk *disk;\n\tstruct opal_dev___2 *opal_dev;\n\tu32 nr_zones;\n\tu32 rev_nr_zones;\n\tu32 zone_blocks;\n\tu32 rev_zone_blocks;\n\tu32 zones_optimal_open;\n\tu32 zones_optimal_nonseq;\n\tu32 zones_max_open;\n\tu32 *zones_wp_offset;\n\tspinlock_t zones_wp_offset_lock;\n\tu32 *rev_wp_offset;\n\tstruct mutex rev_mutex;\n\tstruct work_struct zone_wp_offset_work;\n\tchar *zone_wp_update_buf;\n\tatomic_t openers;\n\tsector_t capacity;\n\tint max_retries;\n\tu32 max_xfer_blocks;\n\tu32 opt_xfer_blocks;\n\tu32 max_ws_blocks;\n\tu32 max_unmap_blocks;\n\tu32 unmap_granularity;\n\tu32 unmap_alignment;\n\tu32 index;\n\tunsigned int physical_block_size;\n\tunsigned int max_medium_access_timeouts;\n\tunsigned int medium_access_timed_out;\n\tu8 media_present;\n\tu8 write_prot;\n\tu8 protection_type;\n\tu8 provisioning_mode;\n\tu8 zeroing_mode;\n\tunsigned int ATO: 1;\n\tunsigned int cache_override: 1;\n\tunsigned int WCE: 1;\n\tunsigned int RCD: 1;\n\tunsigned int DPOFUA: 1;\n\tunsigned int first_scan: 1;\n\tunsigned int lbpme: 1;\n\tunsigned int lbprz: 1;\n\tunsigned int lbpu: 1;\n\tunsigned int lbpws: 1;\n\tunsigned int lbpws10: 1;\n\tunsigned int lbpvpd: 1;\n\tunsigned int ws10: 1;\n\tunsigned int ws16: 1;\n\tunsigned int rc_basis: 2;\n\tunsigned int zoned: 2;\n\tunsigned int urswrz: 1;\n\tunsigned int security: 1;\n\tunsigned int ignore_medium_access_errors: 1;\n};\n\nenum scsi_host_guard_type {\n\tSHOST_DIX_GUARD_CRC = 1,\n\tSHOST_DIX_GUARD_IP = 2,\n};\n\nenum zbc_zone_type {\n\tZBC_ZONE_TYPE_CONV = 1,\n\tZBC_ZONE_TYPE_SEQWRITE_REQ = 2,\n\tZBC_ZONE_TYPE_SEQWRITE_PREF = 3,\n};\n\nenum zbc_zone_cond {\n\tZBC_ZONE_COND_NO_WP = 0,\n\tZBC_ZONE_COND_EMPTY = 1,\n\tZBC_ZONE_COND_IMP_OPEN = 2,\n\tZBC_ZONE_COND_EXP_OPEN = 3,\n\tZBC_ZONE_COND_CLOSED = 4,\n\tZBC_ZONE_COND_READONLY = 13,\n\tZBC_ZONE_COND_FULL = 14,\n\tZBC_ZONE_COND_OFFLINE = 15,\n};\n\nstruct nvme_id_power_state {\n\t__le16 max_power;\n\t__u8 rsvd2;\n\t__u8 flags;\n\t__le32 entry_lat;\n\t__le32 exit_lat;\n\t__u8 read_tput;\n\t__u8 read_lat;\n\t__u8 write_tput;\n\t__u8 write_lat;\n\t__le16 idle_power;\n\t__u8 idle_scale;\n\t__u8 rsvd19;\n\t__le16 active_power;\n\t__u8 active_work_scale;\n\t__u8 rsvd23[9];\n};\n\nenum {\n\tNVME_PS_FLAGS_MAX_POWER_SCALE = 1,\n\tNVME_PS_FLAGS_NON_OP_STATE = 2,\n};\n\nenum nvme_ctrl_attr {\n\tNVME_CTRL_ATTR_HID_128_BIT = 1,\n\tNVME_CTRL_ATTR_TBKAS = 64,\n};\n\nstruct nvme_id_ctrl {\n\t__le16 vid;\n\t__le16 ssvid;\n\tchar sn[20];\n\tchar mn[40];\n\tchar fr[8];\n\t__u8 rab;\n\t__u8 ieee[3];\n\t__u8 cmic;\n\t__u8 mdts;\n\t__le16 cntlid;\n\t__le32 ver;\n\t__le32 rtd3r;\n\t__le32 rtd3e;\n\t__le32 oaes;\n\t__le32 ctratt;\n\t__u8 rsvd100[28];\n\t__le16 crdt1;\n\t__le16 crdt2;\n\t__le16 crdt3;\n\t__u8 rsvd134[122];\n\t__le16 oacs;\n\t__u8 acl;\n\t__u8 aerl;\n\t__u8 frmw;\n\t__u8 lpa;\n\t__u8 elpe;\n\t__u8 npss;\n\t__u8 avscc;\n\t__u8 apsta;\n\t__le16 wctemp;\n\t__le16 cctemp;\n\t__le16 mtfa;\n\t__le32 hmpre;\n\t__le32 hmmin;\n\t__u8 tnvmcap[16];\n\t__u8 unvmcap[16];\n\t__le32 rpmbs;\n\t__le16 edstt;\n\t__u8 dsto;\n\t__u8 fwug;\n\t__le16 kas;\n\t__le16 hctma;\n\t__le16 mntmt;\n\t__le16 mxtmt;\n\t__le32 sanicap;\n\t__le32 hmminds;\n\t__le16 hmmaxd;\n\t__u8 rsvd338[4];\n\t__u8 anatt;\n\t__u8 anacap;\n\t__le32 anagrpmax;\n\t__le32 nanagrpid;\n\t__u8 rsvd352[160];\n\t__u8 sqes;\n\t__u8 cqes;\n\t__le16 maxcmd;\n\t__le32 nn;\n\t__le16 oncs;\n\t__le16 fuses;\n\t__u8 fna;\n\t__u8 vwc;\n\t__le16 awun;\n\t__le16 awupf;\n\t__u8 nvscc;\n\t__u8 nwpc;\n\t__le16 acwu;\n\t__u8 rsvd534[2];\n\t__le32 sgls;\n\t__le32 mnan;\n\t__u8 rsvd544[224];\n\tchar subnqn[256];\n\t__u8 rsvd1024[768];\n\t__le32 ioccsz;\n\t__le32 iorcsz;\n\t__le16 icdoff;\n\t__u8 ctrattr;\n\t__u8 msdbd;\n\t__u8 rsvd1804[244];\n\tstruct nvme_id_power_state psd[32];\n\t__u8 vs[1024];\n};\n\nenum {\n\tNVME_CTRL_CMIC_MULTI_CTRL = 2,\n\tNVME_CTRL_CMIC_ANA = 8,\n\tNVME_CTRL_ONCS_COMPARE = 1,\n\tNVME_CTRL_ONCS_WRITE_UNCORRECTABLE = 2,\n\tNVME_CTRL_ONCS_DSM = 4,\n\tNVME_CTRL_ONCS_WRITE_ZEROES = 8,\n\tNVME_CTRL_ONCS_RESERVATIONS = 32,\n\tNVME_CTRL_ONCS_TIMESTAMP = 64,\n\tNVME_CTRL_VWC_PRESENT = 1,\n\tNVME_CTRL_OACS_SEC_SUPP = 1,\n\tNVME_CTRL_OACS_DIRECTIVES = 32,\n\tNVME_CTRL_OACS_DBBUF_SUPP = 256,\n\tNVME_CTRL_LPA_CMD_EFFECTS_LOG = 2,\n\tNVME_CTRL_CTRATT_128_ID = 1,\n\tNVME_CTRL_CTRATT_NON_OP_PSP = 2,\n\tNVME_CTRL_CTRATT_NVM_SETS = 4,\n\tNVME_CTRL_CTRATT_READ_RECV_LVLS = 8,\n\tNVME_CTRL_CTRATT_ENDURANCE_GROUPS = 16,\n\tNVME_CTRL_CTRATT_PREDICTABLE_LAT = 32,\n\tNVME_CTRL_CTRATT_NAMESPACE_GRANULARITY = 128,\n\tNVME_CTRL_CTRATT_UUID_LIST = 512,\n};\n\nstruct nvme_lbaf {\n\t__le16 ms;\n\t__u8 ds;\n\t__u8 rp;\n};\n\nstruct nvme_id_ns {\n\t__le64 nsze;\n\t__le64 ncap;\n\t__le64 nuse;\n\t__u8 nsfeat;\n\t__u8 nlbaf;\n\t__u8 flbas;\n\t__u8 mc;\n\t__u8 dpc;\n\t__u8 dps;\n\t__u8 nmic;\n\t__u8 rescap;\n\t__u8 fpi;\n\t__u8 dlfeat;\n\t__le16 nawun;\n\t__le16 nawupf;\n\t__le16 nacwu;\n\t__le16 nabsn;\n\t__le16 nabo;\n\t__le16 nabspf;\n\t__le16 noiob;\n\t__u8 nvmcap[16];\n\t__le16 npwg;\n\t__le16 npwa;\n\t__le16 npdg;\n\t__le16 npda;\n\t__le16 nows;\n\t__u8 rsvd74[18];\n\t__le32 anagrpid;\n\t__u8 rsvd96[3];\n\t__u8 nsattr;\n\t__le16 nvmsetid;\n\t__le16 endgid;\n\t__u8 nguid[16];\n\t__u8 eui64[8];\n\tstruct nvme_lbaf lbaf[16];\n\t__u8 rsvd192[192];\n\t__u8 vs[3712];\n};\n\nstruct nvme_id_ctrl_nvm {\n\t__u8 vsl;\n\t__u8 wzsl;\n\t__u8 wusl;\n\t__u8 dmrl;\n\t__le32 dmrsl;\n\t__le64 dmsl;\n\t__u8 rsvd16[4080];\n};\n\nenum {\n\tNVME_ID_CNS_NS = 0,\n\tNVME_ID_CNS_CTRL = 1,\n\tNVME_ID_CNS_NS_ACTIVE_LIST = 2,\n\tNVME_ID_CNS_NS_DESC_LIST = 3,\n\tNVME_ID_CNS_CS_NS = 5,\n\tNVME_ID_CNS_CS_CTRL = 6,\n\tNVME_ID_CNS_NS_PRESENT_LIST = 16,\n\tNVME_ID_CNS_NS_PRESENT = 17,\n\tNVME_ID_CNS_CTRL_NS_LIST = 18,\n\tNVME_ID_CNS_CTRL_LIST = 19,\n\tNVME_ID_CNS_SCNDRY_CTRL_LIST = 21,\n\tNVME_ID_CNS_NS_GRANULARITY = 22,\n\tNVME_ID_CNS_UUID_LIST = 23,\n};\n\nenum {\n\tNVME_CSI_NVM = 0,\n\tNVME_CSI_ZNS = 2,\n};\n\nenum {\n\tNVME_DIR_IDENTIFY = 0,\n\tNVME_DIR_STREAMS = 1,\n\tNVME_DIR_SND_ID_OP_ENABLE = 1,\n\tNVME_DIR_SND_ST_OP_REL_ID = 1,\n\tNVME_DIR_SND_ST_OP_REL_RSC = 2,\n\tNVME_DIR_RCV_ID_OP_PARAM = 1,\n\tNVME_DIR_RCV_ST_OP_PARAM = 1,\n\tNVME_DIR_RCV_ST_OP_STATUS = 2,\n\tNVME_DIR_RCV_ST_OP_RESOURCE = 3,\n\tNVME_DIR_ENDIR = 1,\n};\n\nenum {\n\tNVME_NS_FEAT_THIN = 1,\n\tNVME_NS_FEAT_ATOMICS = 2,\n\tNVME_NS_FEAT_IO_OPT = 16,\n\tNVME_NS_ATTR_RO = 1,\n\tNVME_NS_FLBAS_LBA_MASK = 15,\n\tNVME_NS_FLBAS_META_EXT = 16,\n\tNVME_NS_NMIC_SHARED = 1,\n\tNVME_LBAF_RP_BEST = 0,\n\tNVME_LBAF_RP_BETTER = 1,\n\tNVME_LBAF_RP_GOOD = 2,\n\tNVME_LBAF_RP_DEGRADED = 3,\n\tNVME_NS_DPC_PI_LAST = 16,\n\tNVME_NS_DPC_PI_FIRST = 8,\n\tNVME_NS_DPC_PI_TYPE3 = 4,\n\tNVME_NS_DPC_PI_TYPE2 = 2,\n\tNVME_NS_DPC_PI_TYPE1 = 1,\n\tNVME_NS_DPS_PI_FIRST = 8,\n\tNVME_NS_DPS_PI_MASK = 7,\n\tNVME_NS_DPS_PI_TYPE1 = 1,\n\tNVME_NS_DPS_PI_TYPE2 = 2,\n\tNVME_NS_DPS_PI_TYPE3 = 3,\n};\n\nstruct nvme_ns_id_desc {\n\t__u8 nidt;\n\t__u8 nidl;\n\t__le16 reserved;\n};\n\nenum {\n\tNVME_NIDT_EUI64 = 1,\n\tNVME_NIDT_NGUID = 2,\n\tNVME_NIDT_UUID = 3,\n\tNVME_NIDT_CSI = 4,\n};\n\nstruct nvme_fw_slot_info_log {\n\t__u8 afi;\n\t__u8 rsvd1[7];\n\t__le64 frs[7];\n\t__u8 rsvd64[448];\n};\n\nenum {\n\tNVME_CMD_EFFECTS_CSUPP = 1,\n\tNVME_CMD_EFFECTS_LBCC = 2,\n\tNVME_CMD_EFFECTS_NCC = 4,\n\tNVME_CMD_EFFECTS_NIC = 8,\n\tNVME_CMD_EFFECTS_CCC = 16,\n\tNVME_CMD_EFFECTS_CSE_MASK = 196608,\n\tNVME_CMD_EFFECTS_UUID_SEL = 524288,\n};\n\nstruct nvme_effects_log {\n\t__le32 acs[256];\n\t__le32 iocs[256];\n\t__u8 resv[2048];\n};\n\nenum nvme_ana_state {\n\tNVME_ANA_OPTIMIZED = 1,\n\tNVME_ANA_NONOPTIMIZED = 2,\n\tNVME_ANA_INACCESSIBLE = 3,\n\tNVME_ANA_PERSISTENT_LOSS = 4,\n\tNVME_ANA_CHANGE = 15,\n};\n\nstruct nvme_ana_rsp_hdr {\n\t__le64 chgcnt;\n\t__le16 ngrps;\n\t__le16 rsvd10[3];\n};\n\nenum {\n\tNVME_AER_ERROR = 0,\n\tNVME_AER_SMART = 1,\n\tNVME_AER_NOTICE = 2,\n\tNVME_AER_CSS = 6,\n\tNVME_AER_VS = 7,\n};\n\nenum {\n\tNVME_AER_NOTICE_NS_CHANGED = 0,\n\tNVME_AER_NOTICE_FW_ACT_STARTING = 1,\n\tNVME_AER_NOTICE_ANA = 3,\n\tNVME_AER_NOTICE_DISC_CHANGED = 240,\n};\n\nenum {\n\tNVME_AEN_CFG_NS_ATTR = 256,\n\tNVME_AEN_CFG_FW_ACT = 512,\n\tNVME_AEN_CFG_ANA_CHANGE = 2048,\n\tNVME_AEN_CFG_DISC_CHANGE = 2147483648,\n};\n\nenum nvme_opcode {\n\tnvme_cmd_flush = 0,\n\tnvme_cmd_write = 1,\n\tnvme_cmd_read = 2,\n\tnvme_cmd_write_uncor = 4,\n\tnvme_cmd_compare = 5,\n\tnvme_cmd_write_zeroes = 8,\n\tnvme_cmd_dsm = 9,\n\tnvme_cmd_verify = 12,\n\tnvme_cmd_resv_register = 13,\n\tnvme_cmd_resv_report = 14,\n\tnvme_cmd_resv_acquire = 17,\n\tnvme_cmd_resv_release = 21,\n\tnvme_cmd_zone_mgmt_send = 121,\n\tnvme_cmd_zone_mgmt_recv = 122,\n\tnvme_cmd_zone_append = 125,\n};\n\nstruct nvme_sgl_desc {\n\t__le64 addr;\n\t__le32 length;\n\t__u8 rsvd[3];\n\t__u8 type;\n};\n\nstruct nvme_keyed_sgl_desc {\n\t__le64 addr;\n\t__u8 length[3];\n\t__u8 key[4];\n\t__u8 type;\n};\n\nunion nvme_data_ptr {\n\tstruct {\n\t\t__le64 prp1;\n\t\t__le64 prp2;\n\t};\n\tstruct nvme_sgl_desc sgl;\n\tstruct nvme_keyed_sgl_desc ksgl;\n};\n\nenum {\n\tNVME_CMD_FUSE_FIRST = 1,\n\tNVME_CMD_FUSE_SECOND = 2,\n\tNVME_CMD_SGL_METABUF = 64,\n\tNVME_CMD_SGL_METASEG = 128,\n\tNVME_CMD_SGL_ALL = 192,\n};\n\nstruct nvme_common_command {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__le32 cdw2[2];\n\t__le64 metadata;\n\tunion nvme_data_ptr dptr;\n\t__le32 cdw10;\n\t__le32 cdw11;\n\t__le32 cdw12;\n\t__le32 cdw13;\n\t__le32 cdw14;\n\t__le32 cdw15;\n};\n\nstruct nvme_rw_command {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2;\n\t__le64 metadata;\n\tunion nvme_data_ptr dptr;\n\t__le64 slba;\n\t__le16 length;\n\t__le16 control;\n\t__le32 dsmgmt;\n\t__le32 reftag;\n\t__le16 apptag;\n\t__le16 appmask;\n};\n\nenum {\n\tNVME_RW_LR = 32768,\n\tNVME_RW_FUA = 16384,\n\tNVME_RW_APPEND_PIREMAP = 512,\n\tNVME_RW_DSM_FREQ_UNSPEC = 0,\n\tNVME_RW_DSM_FREQ_TYPICAL = 1,\n\tNVME_RW_DSM_FREQ_RARE = 2,\n\tNVME_RW_DSM_FREQ_READS = 3,\n\tNVME_RW_DSM_FREQ_WRITES = 4,\n\tNVME_RW_DSM_FREQ_RW = 5,\n\tNVME_RW_DSM_FREQ_ONCE = 6,\n\tNVME_RW_DSM_FREQ_PREFETCH = 7,\n\tNVME_RW_DSM_FREQ_TEMP = 8,\n\tNVME_RW_DSM_LATENCY_NONE = 0,\n\tNVME_RW_DSM_LATENCY_IDLE = 16,\n\tNVME_RW_DSM_LATENCY_NORM = 32,\n\tNVME_RW_DSM_LATENCY_LOW = 48,\n\tNVME_RW_DSM_SEQ_REQ = 64,\n\tNVME_RW_DSM_COMPRESSED = 128,\n\tNVME_RW_PRINFO_PRCHK_REF = 1024,\n\tNVME_RW_PRINFO_PRCHK_APP = 2048,\n\tNVME_RW_PRINFO_PRCHK_GUARD = 4096,\n\tNVME_RW_PRINFO_PRACT = 8192,\n\tNVME_RW_DTYPE_STREAMS = 16,\n};\n\nstruct nvme_dsm_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2[2];\n\tunion nvme_data_ptr dptr;\n\t__le32 nr;\n\t__le32 attributes;\n\t__u32 rsvd12[4];\n};\n\nenum {\n\tNVME_DSMGMT_IDR = 1,\n\tNVME_DSMGMT_IDW = 2,\n\tNVME_DSMGMT_AD = 4,\n};\n\nstruct nvme_dsm_range {\n\t__le32 cattr;\n\t__le32 nlb;\n\t__le64 slba;\n};\n\nstruct nvme_write_zeroes_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2;\n\t__le64 metadata;\n\tunion nvme_data_ptr dptr;\n\t__le64 slba;\n\t__le16 length;\n\t__le16 control;\n\t__le32 dsmgmt;\n\t__le32 reftag;\n\t__le16 apptag;\n\t__le16 appmask;\n};\n\nenum nvme_zone_mgmt_action {\n\tNVME_ZONE_CLOSE = 1,\n\tNVME_ZONE_FINISH = 2,\n\tNVME_ZONE_OPEN = 3,\n\tNVME_ZONE_RESET = 4,\n\tNVME_ZONE_OFFLINE = 5,\n\tNVME_ZONE_SET_DESC_EXT = 16,\n};\n\nstruct nvme_zone_mgmt_send_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__le32 cdw2[2];\n\t__le64 metadata;\n\tunion nvme_data_ptr dptr;\n\t__le64 slba;\n\t__le32 cdw12;\n\t__u8 zsa;\n\t__u8 select_all;\n\t__u8 rsvd13[2];\n\t__le32 cdw14[2];\n};\n\nstruct nvme_zone_mgmt_recv_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__le64 rsvd2[2];\n\tunion nvme_data_ptr dptr;\n\t__le64 slba;\n\t__le32 numd;\n\t__u8 zra;\n\t__u8 zrasf;\n\t__u8 pr;\n\t__u8 rsvd13;\n\t__le32 cdw14[2];\n};\n\nstruct nvme_feat_auto_pst {\n\t__le64 entries[32];\n};\n\nstruct nvme_feat_host_behavior {\n\t__u8 acre;\n\t__u8 resv1[511];\n};\n\nenum {\n\tNVME_ENABLE_ACRE = 1,\n};\n\nenum nvme_admin_opcode {\n\tnvme_admin_delete_sq = 0,\n\tnvme_admin_create_sq = 1,\n\tnvme_admin_get_log_page = 2,\n\tnvme_admin_delete_cq = 4,\n\tnvme_admin_create_cq = 5,\n\tnvme_admin_identify = 6,\n\tnvme_admin_abort_cmd = 8,\n\tnvme_admin_set_features = 9,\n\tnvme_admin_get_features = 10,\n\tnvme_admin_async_event = 12,\n\tnvme_admin_ns_mgmt = 13,\n\tnvme_admin_activate_fw = 16,\n\tnvme_admin_download_fw = 17,\n\tnvme_admin_dev_self_test = 20,\n\tnvme_admin_ns_attach = 21,\n\tnvme_admin_keep_alive = 24,\n\tnvme_admin_directive_send = 25,\n\tnvme_admin_directive_recv = 26,\n\tnvme_admin_virtual_mgmt = 28,\n\tnvme_admin_nvme_mi_send = 29,\n\tnvme_admin_nvme_mi_recv = 30,\n\tnvme_admin_dbbuf = 124,\n\tnvme_admin_format_nvm = 128,\n\tnvme_admin_security_send = 129,\n\tnvme_admin_security_recv = 130,\n\tnvme_admin_sanitize_nvm = 132,\n\tnvme_admin_get_lba_status = 134,\n\tnvme_admin_vendor_start = 192,\n};\n\nenum {\n\tNVME_QUEUE_PHYS_CONTIG = 1,\n\tNVME_CQ_IRQ_ENABLED = 2,\n\tNVME_SQ_PRIO_URGENT = 0,\n\tNVME_SQ_PRIO_HIGH = 2,\n\tNVME_SQ_PRIO_MEDIUM = 4,\n\tNVME_SQ_PRIO_LOW = 6,\n\tNVME_FEAT_ARBITRATION = 1,\n\tNVME_FEAT_POWER_MGMT = 2,\n\tNVME_FEAT_LBA_RANGE = 3,\n\tNVME_FEAT_TEMP_THRESH = 4,\n\tNVME_FEAT_ERR_RECOVERY = 5,\n\tNVME_FEAT_VOLATILE_WC = 6,\n\tNVME_FEAT_NUM_QUEUES = 7,\n\tNVME_FEAT_IRQ_COALESCE = 8,\n\tNVME_FEAT_IRQ_CONFIG = 9,\n\tNVME_FEAT_WRITE_ATOMIC = 10,\n\tNVME_FEAT_ASYNC_EVENT = 11,\n\tNVME_FEAT_AUTO_PST = 12,\n\tNVME_FEAT_HOST_MEM_BUF = 13,\n\tNVME_FEAT_TIMESTAMP = 14,\n\tNVME_FEAT_KATO = 15,\n\tNVME_FEAT_HCTM = 16,\n\tNVME_FEAT_NOPSC = 17,\n\tNVME_FEAT_RRL = 18,\n\tNVME_FEAT_PLM_CONFIG = 19,\n\tNVME_FEAT_PLM_WINDOW = 20,\n\tNVME_FEAT_HOST_BEHAVIOR = 22,\n\tNVME_FEAT_SANITIZE = 23,\n\tNVME_FEAT_SW_PROGRESS = 128,\n\tNVME_FEAT_HOST_ID = 129,\n\tNVME_FEAT_RESV_MASK = 130,\n\tNVME_FEAT_RESV_PERSIST = 131,\n\tNVME_FEAT_WRITE_PROTECT = 132,\n\tNVME_FEAT_VENDOR_START = 192,\n\tNVME_FEAT_VENDOR_END = 255,\n\tNVME_LOG_ERROR = 1,\n\tNVME_LOG_SMART = 2,\n\tNVME_LOG_FW_SLOT = 3,\n\tNVME_LOG_CHANGED_NS = 4,\n\tNVME_LOG_CMD_EFFECTS = 5,\n\tNVME_LOG_DEVICE_SELF_TEST = 6,\n\tNVME_LOG_TELEMETRY_HOST = 7,\n\tNVME_LOG_TELEMETRY_CTRL = 8,\n\tNVME_LOG_ENDURANCE_GROUP = 9,\n\tNVME_LOG_ANA = 12,\n\tNVME_LOG_DISC = 112,\n\tNVME_LOG_RESERVATION = 128,\n\tNVME_FWACT_REPL = 0,\n\tNVME_FWACT_REPL_ACTV = 8,\n\tNVME_FWACT_ACTV = 16,\n};\n\nstruct nvme_identify {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2[2];\n\tunion nvme_data_ptr dptr;\n\t__u8 cns;\n\t__u8 rsvd3;\n\t__le16 ctrlid;\n\t__u8 rsvd11[3];\n\t__u8 csi;\n\t__u32 rsvd12[4];\n};\n\nstruct nvme_features {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2[2];\n\tunion nvme_data_ptr dptr;\n\t__le32 fid;\n\t__le32 dword11;\n\t__le32 dword12;\n\t__le32 dword13;\n\t__le32 dword14;\n\t__le32 dword15;\n};\n\nstruct nvme_create_cq {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__u32 rsvd1[5];\n\t__le64 prp1;\n\t__u64 rsvd8;\n\t__le16 cqid;\n\t__le16 qsize;\n\t__le16 cq_flags;\n\t__le16 irq_vector;\n\t__u32 rsvd12[4];\n};\n\nstruct nvme_create_sq {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__u32 rsvd1[5];\n\t__le64 prp1;\n\t__u64 rsvd8;\n\t__le16 sqid;\n\t__le16 qsize;\n\t__le16 sq_flags;\n\t__le16 cqid;\n\t__u32 rsvd12[4];\n};\n\nstruct nvme_delete_queue {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__u32 rsvd1[9];\n\t__le16 qid;\n\t__u16 rsvd10;\n\t__u32 rsvd11[5];\n};\n\nstruct nvme_abort_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__u32 rsvd1[9];\n\t__le16 sqid;\n\t__u16 cid;\n\t__u32 rsvd11[5];\n};\n\nstruct nvme_download_firmware {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__u32 rsvd1[5];\n\tunion nvme_data_ptr dptr;\n\t__le32 numd;\n\t__le32 offset;\n\t__u32 rsvd12[4];\n};\n\nstruct nvme_format_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2[4];\n\t__le32 cdw10;\n\t__u32 rsvd11[5];\n};\n\nstruct nvme_get_log_page_command {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2[2];\n\tunion nvme_data_ptr dptr;\n\t__u8 lid;\n\t__u8 lsp;\n\t__le16 numdl;\n\t__le16 numdu;\n\t__u16 rsvd11;\n\tunion {\n\t\tstruct {\n\t\t\t__le32 lpol;\n\t\t\t__le32 lpou;\n\t\t};\n\t\t__le64 lpo;\n\t};\n\t__u8 rsvd14[3];\n\t__u8 csi;\n\t__u32 rsvd15;\n};\n\nstruct nvme_directive_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2[2];\n\tunion nvme_data_ptr dptr;\n\t__le32 numd;\n\t__u8 doper;\n\t__u8 dtype;\n\t__le16 dspec;\n\t__u8 endir;\n\t__u8 tdtype;\n\t__u16 rsvd15;\n\t__u32 rsvd16[3];\n};\n\nenum nvmf_fabrics_opcode {\n\tnvme_fabrics_command = 127,\n};\n\nenum nvmf_capsule_command {\n\tnvme_fabrics_type_property_set = 0,\n\tnvme_fabrics_type_connect = 1,\n\tnvme_fabrics_type_property_get = 4,\n};\n\nstruct nvmf_common_command {\n\t__u8 opcode;\n\t__u8 resv1;\n\t__u16 command_id;\n\t__u8 fctype;\n\t__u8 resv2[35];\n\t__u8 ts[24];\n};\n\nstruct nvmf_connect_command {\n\t__u8 opcode;\n\t__u8 resv1;\n\t__u16 command_id;\n\t__u8 fctype;\n\t__u8 resv2[19];\n\tunion nvme_data_ptr dptr;\n\t__le16 recfmt;\n\t__le16 qid;\n\t__le16 sqsize;\n\t__u8 cattr;\n\t__u8 resv3;\n\t__le32 kato;\n\t__u8 resv4[12];\n};\n\nstruct nvmf_property_set_command {\n\t__u8 opcode;\n\t__u8 resv1;\n\t__u16 command_id;\n\t__u8 fctype;\n\t__u8 resv2[35];\n\t__u8 attrib;\n\t__u8 resv3[3];\n\t__le32 offset;\n\t__le64 value;\n\t__u8 resv4[8];\n};\n\nstruct nvmf_property_get_command {\n\t__u8 opcode;\n\t__u8 resv1;\n\t__u16 command_id;\n\t__u8 fctype;\n\t__u8 resv2[35];\n\t__u8 attrib;\n\t__u8 resv3[3];\n\t__le32 offset;\n\t__u8 resv4[16];\n};\n\nstruct nvme_dbbuf {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__u32 rsvd1[5];\n\t__le64 prp1;\n\t__le64 prp2;\n\t__u32 rsvd12[6];\n};\n\nstruct streams_directive_params {\n\t__le16 msl;\n\t__le16 nssa;\n\t__le16 nsso;\n\t__u8 rsvd[10];\n\t__le32 sws;\n\t__le16 sgs;\n\t__le16 nsa;\n\t__le16 nso;\n\t__u8 rsvd2[6];\n};\n\nstruct nvme_command {\n\tunion {\n\t\tstruct nvme_common_command common;\n\t\tstruct nvme_rw_command rw;\n\t\tstruct nvme_identify identify;\n\t\tstruct nvme_features features;\n\t\tstruct nvme_create_cq create_cq;\n\t\tstruct nvme_create_sq create_sq;\n\t\tstruct nvme_delete_queue delete_queue;\n\t\tstruct nvme_download_firmware dlfw;\n\t\tstruct nvme_format_cmd format;\n\t\tstruct nvme_dsm_cmd dsm;\n\t\tstruct nvme_write_zeroes_cmd write_zeroes;\n\t\tstruct nvme_zone_mgmt_send_cmd zms;\n\t\tstruct nvme_zone_mgmt_recv_cmd zmr;\n\t\tstruct nvme_abort_cmd abort;\n\t\tstruct nvme_get_log_page_command get_log_page;\n\t\tstruct nvmf_common_command fabrics;\n\t\tstruct nvmf_connect_command connect;\n\t\tstruct nvmf_property_set_command prop_set;\n\t\tstruct nvmf_property_get_command prop_get;\n\t\tstruct nvme_dbbuf dbbuf;\n\t\tstruct nvme_directive_cmd directive;\n\t};\n};\n\nenum {\n\tNVME_SC_SUCCESS = 0,\n\tNVME_SC_INVALID_OPCODE = 1,\n\tNVME_SC_INVALID_FIELD = 2,\n\tNVME_SC_CMDID_CONFLICT = 3,\n\tNVME_SC_DATA_XFER_ERROR = 4,\n\tNVME_SC_POWER_LOSS = 5,\n\tNVME_SC_INTERNAL = 6,\n\tNVME_SC_ABORT_REQ = 7,\n\tNVME_SC_ABORT_QUEUE = 8,\n\tNVME_SC_FUSED_FAIL = 9,\n\tNVME_SC_FUSED_MISSING = 10,\n\tNVME_SC_INVALID_NS = 11,\n\tNVME_SC_CMD_SEQ_ERROR = 12,\n\tNVME_SC_SGL_INVALID_LAST = 13,\n\tNVME_SC_SGL_INVALID_COUNT = 14,\n\tNVME_SC_SGL_INVALID_DATA = 15,\n\tNVME_SC_SGL_INVALID_METADATA = 16,\n\tNVME_SC_SGL_INVALID_TYPE = 17,\n\tNVME_SC_CMB_INVALID_USE = 18,\n\tNVME_SC_PRP_INVALID_OFFSET = 19,\n\tNVME_SC_ATOMIC_WU_EXCEEDED = 20,\n\tNVME_SC_OP_DENIED = 21,\n\tNVME_SC_SGL_INVALID_OFFSET = 22,\n\tNVME_SC_RESERVED = 23,\n\tNVME_SC_HOST_ID_INCONSIST = 24,\n\tNVME_SC_KA_TIMEOUT_EXPIRED = 25,\n\tNVME_SC_KA_TIMEOUT_INVALID = 26,\n\tNVME_SC_ABORTED_PREEMPT_ABORT = 27,\n\tNVME_SC_SANITIZE_FAILED = 28,\n\tNVME_SC_SANITIZE_IN_PROGRESS = 29,\n\tNVME_SC_SGL_INVALID_GRANULARITY = 30,\n\tNVME_SC_CMD_NOT_SUP_CMB_QUEUE = 31,\n\tNVME_SC_NS_WRITE_PROTECTED = 32,\n\tNVME_SC_CMD_INTERRUPTED = 33,\n\tNVME_SC_TRANSIENT_TR_ERR = 34,\n\tNVME_SC_INVALID_IO_CMD_SET = 44,\n\tNVME_SC_LBA_RANGE = 128,\n\tNVME_SC_CAP_EXCEEDED = 129,\n\tNVME_SC_NS_NOT_READY = 130,\n\tNVME_SC_RESERVATION_CONFLICT = 131,\n\tNVME_SC_FORMAT_IN_PROGRESS = 132,\n\tNVME_SC_CQ_INVALID = 256,\n\tNVME_SC_QID_INVALID = 257,\n\tNVME_SC_QUEUE_SIZE = 258,\n\tNVME_SC_ABORT_LIMIT = 259,\n\tNVME_SC_ABORT_MISSING = 260,\n\tNVME_SC_ASYNC_LIMIT = 261,\n\tNVME_SC_FIRMWARE_SLOT = 262,\n\tNVME_SC_FIRMWARE_IMAGE = 263,\n\tNVME_SC_INVALID_VECTOR = 264,\n\tNVME_SC_INVALID_LOG_PAGE = 265,\n\tNVME_SC_INVALID_FORMAT = 266,\n\tNVME_SC_FW_NEEDS_CONV_RESET = 267,\n\tNVME_SC_INVALID_QUEUE = 268,\n\tNVME_SC_FEATURE_NOT_SAVEABLE = 269,\n\tNVME_SC_FEATURE_NOT_CHANGEABLE = 270,\n\tNVME_SC_FEATURE_NOT_PER_NS = 271,\n\tNVME_SC_FW_NEEDS_SUBSYS_RESET = 272,\n\tNVME_SC_FW_NEEDS_RESET = 273,\n\tNVME_SC_FW_NEEDS_MAX_TIME = 274,\n\tNVME_SC_FW_ACTIVATE_PROHIBITED = 275,\n\tNVME_SC_OVERLAPPING_RANGE = 276,\n\tNVME_SC_NS_INSUFFICIENT_CAP = 277,\n\tNVME_SC_NS_ID_UNAVAILABLE = 278,\n\tNVME_SC_NS_ALREADY_ATTACHED = 280,\n\tNVME_SC_NS_IS_PRIVATE = 281,\n\tNVME_SC_NS_NOT_ATTACHED = 282,\n\tNVME_SC_THIN_PROV_NOT_SUPP = 283,\n\tNVME_SC_CTRL_LIST_INVALID = 284,\n\tNVME_SC_SELT_TEST_IN_PROGRESS = 285,\n\tNVME_SC_BP_WRITE_PROHIBITED = 286,\n\tNVME_SC_CTRL_ID_INVALID = 287,\n\tNVME_SC_SEC_CTRL_STATE_INVALID = 288,\n\tNVME_SC_CTRL_RES_NUM_INVALID = 289,\n\tNVME_SC_RES_ID_INVALID = 290,\n\tNVME_SC_PMR_SAN_PROHIBITED = 291,\n\tNVME_SC_ANA_GROUP_ID_INVALID = 292,\n\tNVME_SC_ANA_ATTACH_FAILED = 293,\n\tNVME_SC_BAD_ATTRIBUTES = 384,\n\tNVME_SC_INVALID_PI = 385,\n\tNVME_SC_READ_ONLY = 386,\n\tNVME_SC_ONCS_NOT_SUPPORTED = 387,\n\tNVME_SC_CONNECT_FORMAT = 384,\n\tNVME_SC_CONNECT_CTRL_BUSY = 385,\n\tNVME_SC_CONNECT_INVALID_PARAM = 386,\n\tNVME_SC_CONNECT_RESTART_DISC = 387,\n\tNVME_SC_CONNECT_INVALID_HOST = 388,\n\tNVME_SC_DISCOVERY_RESTART = 400,\n\tNVME_SC_AUTH_REQUIRED = 401,\n\tNVME_SC_ZONE_BOUNDARY_ERROR = 440,\n\tNVME_SC_ZONE_FULL = 441,\n\tNVME_SC_ZONE_READ_ONLY = 442,\n\tNVME_SC_ZONE_OFFLINE = 443,\n\tNVME_SC_ZONE_INVALID_WRITE = 444,\n\tNVME_SC_ZONE_TOO_MANY_ACTIVE = 445,\n\tNVME_SC_ZONE_TOO_MANY_OPEN = 446,\n\tNVME_SC_ZONE_INVALID_TRANSITION = 447,\n\tNVME_SC_WRITE_FAULT = 640,\n\tNVME_SC_READ_ERROR = 641,\n\tNVME_SC_GUARD_CHECK = 642,\n\tNVME_SC_APPTAG_CHECK = 643,\n\tNVME_SC_REFTAG_CHECK = 644,\n\tNVME_SC_COMPARE_FAILED = 645,\n\tNVME_SC_ACCESS_DENIED = 646,\n\tNVME_SC_UNWRITTEN_BLOCK = 647,\n\tNVME_SC_ANA_PERSISTENT_LOSS = 769,\n\tNVME_SC_ANA_INACCESSIBLE = 770,\n\tNVME_SC_ANA_TRANSITION = 771,\n\tNVME_SC_HOST_PATH_ERROR = 880,\n\tNVME_SC_HOST_ABORTED_CMD = 881,\n\tNVME_SC_CRD = 6144,\n\tNVME_SC_DNR = 16384,\n};\n\nunion nvme_result {\n\t__le16 u16;\n\t__le32 u32;\n\t__le64 u64;\n};\n\nenum nvme_quirks {\n\tNVME_QUIRK_STRIPE_SIZE = 1,\n\tNVME_QUIRK_IDENTIFY_CNS = 2,\n\tNVME_QUIRK_DEALLOCATE_ZEROES = 4,\n\tNVME_QUIRK_DELAY_BEFORE_CHK_RDY = 8,\n\tNVME_QUIRK_NO_APST = 16,\n\tNVME_QUIRK_NO_DEEPEST_PS = 32,\n\tNVME_QUIRK_LIGHTNVM = 64,\n\tNVME_QUIRK_MEDIUM_PRIO_SQ = 128,\n\tNVME_QUIRK_IGNORE_DEV_SUBNQN = 256,\n\tNVME_QUIRK_DISABLE_WRITE_ZEROES = 512,\n\tNVME_QUIRK_SIMPLE_SUSPEND = 1024,\n\tNVME_QUIRK_SINGLE_VECTOR = 2048,\n\tNVME_QUIRK_128_BYTES_SQES = 4096,\n\tNVME_QUIRK_SHARED_TAGS = 8192,\n\tNVME_QUIRK_NO_TEMP_THRESH_CHANGE = 16384,\n\tNVME_QUIRK_NO_NS_DESC_LIST = 32768,\n\tNVME_QUIRK_DMA_ADDRESS_BITS_48 = 65536,\n};\n\nstruct nvme_ctrl;\n\nstruct nvme_request {\n\tstruct nvme_command *cmd;\n\tunion nvme_result result;\n\tu8 retries;\n\tu8 flags;\n\tu16 status;\n\tstruct nvme_ctrl *ctrl;\n};\n\nenum nvme_ctrl_state {\n\tNVME_CTRL_NEW = 0,\n\tNVME_CTRL_LIVE = 1,\n\tNVME_CTRL_RESETTING = 2,\n\tNVME_CTRL_CONNECTING = 3,\n\tNVME_CTRL_DELETING = 4,\n\tNVME_CTRL_DELETING_NOIO = 5,\n\tNVME_CTRL_DEAD = 6,\n};\n\nstruct nvme_fault_inject {};\n\nstruct nvme_ctrl_ops;\n\nstruct nvme_subsystem;\n\nstruct nvmf_ctrl_options;\n\nstruct nvme_ctrl {\n\tbool comp_seen;\n\tenum nvme_ctrl_state state;\n\tbool identified;\n\tspinlock_t lock;\n\tstruct mutex scan_lock;\n\tconst struct nvme_ctrl_ops *ops;\n\tstruct request_queue *admin_q;\n\tstruct request_queue *connect_q;\n\tstruct request_queue *fabrics_q;\n\tstruct device *dev;\n\tint instance;\n\tint numa_node;\n\tstruct blk_mq_tag_set *tagset;\n\tstruct blk_mq_tag_set *admin_tagset;\n\tstruct list_head namespaces;\n\tstruct rw_semaphore namespaces_rwsem;\n\tstruct device ctrl_device;\n\tstruct device *device;\n\tstruct device *hwmon_device;\n\tstruct cdev cdev;\n\tstruct work_struct reset_work;\n\tstruct work_struct delete_work;\n\twait_queue_head_t state_wq;\n\tstruct nvme_subsystem *subsys;\n\tstruct list_head subsys_entry;\n\tstruct opal_dev___2 *opal_dev;\n\tchar name[12];\n\tu16 cntlid;\n\tu32 ctrl_config;\n\tu16 mtfa;\n\tu32 queue_count;\n\tu64 cap;\n\tu32 max_hw_sectors;\n\tu32 max_segments;\n\tu32 max_integrity_segments;\n\tu32 max_discard_sectors;\n\tu32 max_discard_segments;\n\tu32 max_zeroes_sectors;\n\tu32 max_zone_append;\n\tu16 crdt[3];\n\tu16 oncs;\n\tu16 oacs;\n\tu16 nssa;\n\tu16 nr_streams;\n\tu16 sqsize;\n\tu32 max_namespaces;\n\tatomic_t abort_limit;\n\tu8 vwc;\n\tu32 vs;\n\tu32 sgls;\n\tu16 kas;\n\tu8 npss;\n\tu8 apsta;\n\tu16 wctemp;\n\tu16 cctemp;\n\tu32 oaes;\n\tu32 aen_result;\n\tu32 ctratt;\n\tunsigned int shutdown_timeout;\n\tunsigned int kato;\n\tbool subsystem;\n\tlong unsigned int quirks;\n\tstruct nvme_id_power_state psd[32];\n\tstruct nvme_effects_log *effects;\n\tstruct xarray cels;\n\tstruct work_struct scan_work;\n\tstruct work_struct async_event_work;\n\tstruct delayed_work ka_work;\n\tstruct delayed_work failfast_work;\n\tstruct nvme_command ka_cmd;\n\tstruct work_struct fw_act_work;\n\tlong unsigned int events;\n\tu8 anacap;\n\tu8 anatt;\n\tu32 anagrpmax;\n\tu32 nanagrpid;\n\tstruct mutex ana_lock;\n\tstruct nvme_ana_rsp_hdr *ana_log_buf;\n\tsize_t ana_log_size;\n\tstruct timer_list anatt_timer;\n\tstruct work_struct ana_work;\n\tu64 ps_max_latency_us;\n\tbool apst_enabled;\n\tu32 hmpre;\n\tu32 hmmin;\n\tu32 hmminds;\n\tu16 hmmaxd;\n\tu32 ioccsz;\n\tu32 iorcsz;\n\tu16 icdoff;\n\tu16 maxcmd;\n\tint nr_reconnects;\n\tlong unsigned int flags;\n\tstruct nvmf_ctrl_options *opts;\n\tstruct page *discard_page;\n\tlong unsigned int discard_page_busy;\n\tstruct nvme_fault_inject fault_inject;\n};\n\nenum {\n\tNVME_REQ_CANCELLED = 1,\n\tNVME_REQ_USERCMD = 2,\n};\n\nstruct nvme_ctrl_ops {\n\tconst char *name;\n\tstruct module *module;\n\tunsigned int flags;\n\tint (*reg_read32)(struct nvme_ctrl *, u32, u32 *);\n\tint (*reg_write32)(struct nvme_ctrl *, u32, u32);\n\tint (*reg_read64)(struct nvme_ctrl *, u32, u64 *);\n\tvoid (*free_ctrl)(struct nvme_ctrl *);\n\tvoid (*submit_async_event)(struct nvme_ctrl *);\n\tvoid (*delete_ctrl)(struct nvme_ctrl *);\n\tint (*get_address)(struct nvme_ctrl *, char *, int);\n};\n\nenum nvme_iopolicy {\n\tNVME_IOPOLICY_NUMA = 0,\n\tNVME_IOPOLICY_RR = 1,\n};\n\nstruct nvme_subsystem {\n\tint instance;\n\tstruct device dev;\n\tstruct kref ref;\n\tstruct list_head entry;\n\tstruct mutex lock;\n\tstruct list_head ctrls;\n\tstruct list_head nsheads;\n\tchar subnqn[223];\n\tchar serial[20];\n\tchar model[40];\n\tchar firmware_rev[8];\n\tu8 cmic;\n\tu16 vendor_id;\n\tu16 awupf;\n\tstruct ida ns_ida;\n\tenum nvme_iopolicy iopolicy;\n};\n\nstruct nvmf_host;\n\nstruct nvmf_ctrl_options {\n\tunsigned int mask;\n\tchar *transport;\n\tchar *subsysnqn;\n\tchar *traddr;\n\tchar *trsvcid;\n\tchar *host_traddr;\n\tchar *host_iface;\n\tsize_t queue_size;\n\tunsigned int nr_io_queues;\n\tunsigned int reconnect_delay;\n\tbool discovery_nqn;\n\tbool duplicate_connect;\n\tunsigned int kato;\n\tstruct nvmf_host *host;\n\tint max_reconnects;\n\tbool disable_sqflow;\n\tbool hdr_digest;\n\tbool data_digest;\n\tunsigned int nr_write_queues;\n\tunsigned int nr_poll_queues;\n\tint tos;\n\tint fast_io_fail_tmo;\n};\n\nstruct nvme_ns_ids {\n\tu8 eui64[8];\n\tu8 nguid[16];\n\tuuid_t uuid;\n\tu8 csi;\n};\n\nstruct nvme_ns;\n\nstruct nvme_ns_head {\n\tstruct list_head list;\n\tstruct srcu_struct srcu;\n\tstruct nvme_subsystem *subsys;\n\tunsigned int ns_id;\n\tstruct nvme_ns_ids ids;\n\tstruct list_head entry;\n\tstruct kref ref;\n\tbool shared;\n\tint instance;\n\tstruct nvme_effects_log *effects;\n\tstruct cdev cdev;\n\tstruct device cdev_device;\n\tstruct gendisk *disk;\n\tstruct bio_list requeue_list;\n\tspinlock_t requeue_lock;\n\tstruct work_struct requeue_work;\n\tstruct mutex lock;\n\tlong unsigned int flags;\n\tstruct nvme_ns *current_path[0];\n};\n\nstruct nvme_ns {\n\tstruct list_head list;\n\tstruct nvme_ctrl *ctrl;\n\tstruct request_queue *queue;\n\tstruct gendisk *disk;\n\tenum nvme_ana_state ana_state;\n\tu32 ana_grpid;\n\tstruct list_head siblings;\n\tstruct nvm_dev *ndev;\n\tstruct kref kref;\n\tstruct nvme_ns_head *head;\n\tint lba_shift;\n\tu16 ms;\n\tu16 sgs;\n\tu32 sws;\n\tu8 pi_type;\n\tu64 zsze;\n\tlong unsigned int features;\n\tlong unsigned int flags;\n\tstruct cdev cdev;\n\tstruct device cdev_device;\n\tstruct nvme_fault_inject fault_inject;\n};\n\nenum nvme_ns_features {\n\tNVME_NS_EXT_LBAS = 1,\n\tNVME_NS_METADATA_SUPPORTED = 2,\n};\n\nstruct nvmf_host {\n\tstruct kref ref;\n\tstruct list_head list;\n\tchar nqn[223];\n\tuuid_t id;\n};\n\nstruct trace_event_raw_nvme_setup_cmd {\n\tstruct trace_entry ent;\n\tchar disk[32];\n\tint ctrl_id;\n\tint qid;\n\tu8 opcode;\n\tu8 flags;\n\tu8 fctype;\n\tu16 cid;\n\tu32 nsid;\n\tbool metadata;\n\tu8 cdw10[24];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_nvme_complete_rq {\n\tstruct trace_entry ent;\n\tchar disk[32];\n\tint ctrl_id;\n\tint qid;\n\tint cid;\n\tu64 result;\n\tu8 retries;\n\tu8 flags;\n\tu16 status;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_nvme_async_event {\n\tstruct trace_entry ent;\n\tint ctrl_id;\n\tu32 result;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_nvme_sq {\n\tstruct trace_entry ent;\n\tint ctrl_id;\n\tchar disk[32];\n\tint qid;\n\tu16 sq_head;\n\tu16 sq_tail;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_nvme_setup_cmd {};\n\nstruct trace_event_data_offsets_nvme_complete_rq {};\n\nstruct trace_event_data_offsets_nvme_async_event {};\n\nstruct trace_event_data_offsets_nvme_sq {};\n\ntypedef void (*btf_trace_nvme_setup_cmd)(void *, struct request *, struct nvme_command *);\n\ntypedef void (*btf_trace_nvme_complete_rq)(void *, struct request *);\n\ntypedef void (*btf_trace_nvme_async_event)(void *, struct nvme_ctrl *, u32);\n\ntypedef void (*btf_trace_nvme_sq)(void *, struct request *, __le16, int);\n\nenum nvme_disposition {\n\tCOMPLETE = 0,\n\tRETRY = 1,\n\tFAILOVER = 2,\n};\n\nstruct nvme_core_quirk_entry {\n\tu16 vid;\n\tconst char *mn;\n\tconst char *fr;\n\tlong unsigned int quirks;\n};\n\nstruct nvme_user_io {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 control;\n\t__u16 nblocks;\n\t__u16 rsvd;\n\t__u64 metadata;\n\t__u64 addr;\n\t__u64 slba;\n\t__u32 dsmgmt;\n\t__u32 reftag;\n\t__u16 apptag;\n\t__u16 appmask;\n};\n\nstruct nvme_passthru_cmd {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 rsvd1;\n\t__u32 nsid;\n\t__u32 cdw2;\n\t__u32 cdw3;\n\t__u64 metadata;\n\t__u64 addr;\n\t__u32 metadata_len;\n\t__u32 data_len;\n\t__u32 cdw10;\n\t__u32 cdw11;\n\t__u32 cdw12;\n\t__u32 cdw13;\n\t__u32 cdw14;\n\t__u32 cdw15;\n\t__u32 timeout_ms;\n\t__u32 result;\n};\n\nstruct nvme_passthru_cmd64 {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 rsvd1;\n\t__u32 nsid;\n\t__u32 cdw2;\n\t__u32 cdw3;\n\t__u64 metadata;\n\t__u64 addr;\n\t__u32 metadata_len;\n\t__u32 data_len;\n\t__u32 cdw10;\n\t__u32 cdw11;\n\t__u32 cdw12;\n\t__u32 cdw13;\n\t__u32 cdw14;\n\t__u32 cdw15;\n\t__u32 timeout_ms;\n\t__u32 rsvd2;\n\t__u64 result;\n};\n\nstruct nvme_ana_group_desc {\n\t__le32 grpid;\n\t__le32 nnsids;\n\t__le64 chgcnt;\n\t__u8 state;\n\t__u8 rsvd17[15];\n\t__le32 nsids[0];\n};\n\nstruct nvm_user_vio {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 control;\n\t__u16 nppas;\n\t__u16 rsvd;\n\t__u64 metadata;\n\t__u64 addr;\n\t__u64 ppa_list;\n\t__u32 metadata_len;\n\t__u32 data_len;\n\t__u64 status;\n\t__u32 result;\n\t__u32 rsvd3[3];\n};\n\nstruct nvm_passthru_vio {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u8 rsvd[2];\n\t__u32 nsid;\n\t__u32 cdw2;\n\t__u32 cdw3;\n\t__u64 metadata;\n\t__u64 addr;\n\t__u32 metadata_len;\n\t__u32 data_len;\n\t__u64 ppa_list;\n\t__u16 nppas;\n\t__u16 control;\n\t__u32 cdw13;\n\t__u32 cdw14;\n\t__u32 cdw15;\n\t__u64 status;\n\t__u32 result;\n\t__u32 timeout_ms;\n};\n\nenum nvme_nvm_admin_opcode {\n\tnvme_nvm_admin_identity = 226,\n\tnvme_nvm_admin_get_bb_tbl = 242,\n\tnvme_nvm_admin_set_bb_tbl = 241,\n};\n\nenum nvme_nvm_log_page {\n\tNVME_NVM_LOG_REPORT_CHUNK = 202,\n};\n\nstruct nvme_nvm_ph_rw {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd2;\n\t__le64 metadata;\n\t__le64 prp1;\n\t__le64 prp2;\n\t__le64 spba;\n\t__le16 length;\n\t__le16 control;\n\t__le32 dsmgmt;\n\t__le64 resv;\n};\n\nstruct nvme_nvm_erase_blk {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd[2];\n\t__le64 prp1;\n\t__le64 prp2;\n\t__le64 spba;\n\t__le16 length;\n\t__le16 control;\n\t__le32 dsmgmt;\n\t__le64 resv;\n};\n\nstruct nvme_nvm_identity {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd[2];\n\t__le64 prp1;\n\t__le64 prp2;\n\t__u32 rsvd11[6];\n};\n\nstruct nvme_nvm_getbbtbl {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__u64 rsvd[2];\n\t__le64 prp1;\n\t__le64 prp2;\n\t__le64 spba;\n\t__u32 rsvd4[4];\n};\n\nstruct nvme_nvm_setbbtbl {\n\t__u8 opcode;\n\t__u8 flags;\n\t__u16 command_id;\n\t__le32 nsid;\n\t__le64 rsvd[2];\n\t__le64 prp1;\n\t__le64 prp2;\n\t__le64 spba;\n\t__le16 nlb;\n\t__u8 value;\n\t__u8 rsvd3;\n\t__u32 rsvd4[3];\n};\n\nstruct nvme_nvm_command {\n\tunion {\n\t\tstruct nvme_common_command common;\n\t\tstruct nvme_nvm_ph_rw ph_rw;\n\t\tstruct nvme_nvm_erase_blk erase;\n\t\tstruct nvme_nvm_identity identity;\n\t\tstruct nvme_nvm_getbbtbl get_bb;\n\t\tstruct nvme_nvm_setbbtbl set_bb;\n\t};\n};\n\nstruct nvme_nvm_id12_grp {\n\t__u8 mtype;\n\t__u8 fmtype;\n\t__le16 res16;\n\t__u8 num_ch;\n\t__u8 num_lun;\n\t__u8 num_pln;\n\t__u8 rsvd1;\n\t__le16 num_chk;\n\t__le16 num_pg;\n\t__le16 fpg_sz;\n\t__le16 csecs;\n\t__le16 sos;\n\t__le16 rsvd2;\n\t__le32 trdt;\n\t__le32 trdm;\n\t__le32 tprt;\n\t__le32 tprm;\n\t__le32 tbet;\n\t__le32 tbem;\n\t__le32 mpos;\n\t__le32 mccap;\n\t__le16 cpar;\n\t__u8 reserved[906];\n};\n\nstruct nvme_nvm_id12_addrf {\n\t__u8 ch_offset;\n\t__u8 ch_len;\n\t__u8 lun_offset;\n\t__u8 lun_len;\n\t__u8 pln_offset;\n\t__u8 pln_len;\n\t__u8 blk_offset;\n\t__u8 blk_len;\n\t__u8 pg_offset;\n\t__u8 pg_len;\n\t__u8 sec_offset;\n\t__u8 sec_len;\n\t__u8 res[4];\n};\n\nstruct nvme_nvm_id12 {\n\t__u8 ver_id;\n\t__u8 vmnt;\n\t__u8 cgrps;\n\t__u8 res;\n\t__le32 cap;\n\t__le32 dom;\n\tstruct nvme_nvm_id12_addrf ppaf;\n\t__u8 resv[228];\n\tstruct nvme_nvm_id12_grp grp;\n\t__u8 resv2[2880];\n};\n\nstruct nvme_nvm_bb_tbl {\n\t__u8 tblid[4];\n\t__le16 verid;\n\t__le16 revid;\n\t__le32 rvsd1;\n\t__le32 tblks;\n\t__le32 tfact;\n\t__le32 tgrown;\n\t__le32 tdresv;\n\t__le32 thresv;\n\t__le32 rsvd2[8];\n\t__u8 blk[0];\n};\n\nstruct nvme_nvm_id20_addrf {\n\t__u8 grp_len;\n\t__u8 pu_len;\n\t__u8 chk_len;\n\t__u8 lba_len;\n\t__u8 resv[4];\n};\n\nstruct nvme_nvm_id20 {\n\t__u8 mjr;\n\t__u8 mnr;\n\t__u8 resv[6];\n\tstruct nvme_nvm_id20_addrf lbaf;\n\t__le32 mccap;\n\t__u8 resv2[12];\n\t__u8 wit;\n\t__u8 resv3[31];\n\t__le16 num_grp;\n\t__le16 num_pu;\n\t__le32 num_chk;\n\t__le32 clba;\n\t__u8 resv4[52];\n\t__le32 ws_min;\n\t__le32 ws_opt;\n\t__le32 mw_cunits;\n\t__le32 maxoc;\n\t__le32 maxocpu;\n\t__u8 resv5[44];\n\t__le32 trdt;\n\t__le32 trdm;\n\t__le32 twrt;\n\t__le32 twrm;\n\t__le32 tcrst;\n\t__le32 tcrsm;\n\t__u8 resv6[40];\n\t__u8 resv7[2816];\n\t__u8 vs[1024];\n};\n\nstruct nvme_nvm_chk_meta {\n\t__u8 state;\n\t__u8 type;\n\t__u8 wi;\n\t__u8 rsvd[5];\n\t__le64 slba;\n\t__le64 cnlb;\n\t__le64 wp;\n};\n\nstruct nvme_zns_lbafe {\n\t__le64 zsze;\n\t__u8 zdes;\n\t__u8 rsvd9[7];\n};\n\nstruct nvme_id_ns_zns {\n\t__le16 zoc;\n\t__le16 ozcs;\n\t__le32 mar;\n\t__le32 mor;\n\t__le32 rrl;\n\t__le32 frl;\n\t__u8 rsvd20[2796];\n\tstruct nvme_zns_lbafe lbafe[16];\n\t__u8 rsvd3072[768];\n\t__u8 vs[256];\n};\n\nstruct nvme_id_ctrl_zns {\n\t__u8 zasl;\n\t__u8 rsvd1[4095];\n};\n\nstruct nvme_zone_descriptor {\n\t__u8 zt;\n\t__u8 zs;\n\t__u8 za;\n\t__u8 rsvd3[5];\n\t__le64 zcap;\n\t__le64 zslba;\n\t__le64 wp;\n\t__u8 rsvd32[32];\n};\n\nenum {\n\tNVME_ZONE_TYPE_SEQWRITE_REQ = 2,\n};\n\nstruct nvme_zone_report {\n\t__le64 nr_zones;\n\t__u8 resv8[56];\n\tstruct nvme_zone_descriptor entries[0];\n};\n\nenum {\n\tNVME_ZRA_ZONE_REPORT = 0,\n\tNVME_ZRASF_ZONE_REPORT_ALL = 0,\n\tNVME_ZRASF_ZONE_STATE_EMPTY = 1,\n\tNVME_ZRASF_ZONE_STATE_IMP_OPEN = 2,\n\tNVME_ZRASF_ZONE_STATE_EXP_OPEN = 3,\n\tNVME_ZRASF_ZONE_STATE_CLOSED = 4,\n\tNVME_ZRASF_ZONE_STATE_READONLY = 5,\n\tNVME_ZRASF_ZONE_STATE_FULL = 6,\n\tNVME_ZRASF_ZONE_STATE_OFFLINE = 7,\n\tNVME_REPORT_ZONE_PARTIAL = 1,\n};\n\nenum hwmon_sensor_types {\n\thwmon_chip = 0,\n\thwmon_temp = 1,\n\thwmon_in = 2,\n\thwmon_curr = 3,\n\thwmon_power = 4,\n\thwmon_energy = 5,\n\thwmon_humidity = 6,\n\thwmon_fan = 7,\n\thwmon_pwm = 8,\n\thwmon_intrusion = 9,\n\thwmon_max = 10,\n};\n\nenum hwmon_chip_attributes {\n\thwmon_chip_temp_reset_history = 0,\n\thwmon_chip_in_reset_history = 1,\n\thwmon_chip_curr_reset_history = 2,\n\thwmon_chip_power_reset_history = 3,\n\thwmon_chip_register_tz = 4,\n\thwmon_chip_update_interval = 5,\n\thwmon_chip_alarms = 6,\n\thwmon_chip_samples = 7,\n\thwmon_chip_curr_samples = 8,\n\thwmon_chip_in_samples = 9,\n\thwmon_chip_power_samples = 10,\n\thwmon_chip_temp_samples = 11,\n};\n\nenum hwmon_temp_attributes {\n\thwmon_temp_enable = 0,\n\thwmon_temp_input = 1,\n\thwmon_temp_type = 2,\n\thwmon_temp_lcrit = 3,\n\thwmon_temp_lcrit_hyst = 4,\n\thwmon_temp_min = 5,\n\thwmon_temp_min_hyst = 6,\n\thwmon_temp_max = 7,\n\thwmon_temp_max_hyst = 8,\n\thwmon_temp_crit = 9,\n\thwmon_temp_crit_hyst = 10,\n\thwmon_temp_emergency = 11,\n\thwmon_temp_emergency_hyst = 12,\n\thwmon_temp_alarm = 13,\n\thwmon_temp_lcrit_alarm = 14,\n\thwmon_temp_min_alarm = 15,\n\thwmon_temp_max_alarm = 16,\n\thwmon_temp_crit_alarm = 17,\n\thwmon_temp_emergency_alarm = 18,\n\thwmon_temp_fault = 19,\n\thwmon_temp_offset = 20,\n\thwmon_temp_label = 21,\n\thwmon_temp_lowest = 22,\n\thwmon_temp_highest = 23,\n\thwmon_temp_reset_history = 24,\n\thwmon_temp_rated_min = 25,\n\thwmon_temp_rated_max = 26,\n};\n\nstruct hwmon_ops {\n\tumode_t (*is_visible)(const void *, enum hwmon_sensor_types, u32, int);\n\tint (*read)(struct device *, enum hwmon_sensor_types, u32, int, long int *);\n\tint (*read_string)(struct device *, enum hwmon_sensor_types, u32, int, const char **);\n\tint (*write)(struct device *, enum hwmon_sensor_types, u32, int, long int);\n};\n\nstruct hwmon_channel_info {\n\tenum hwmon_sensor_types type;\n\tconst u32 *config;\n};\n\nstruct hwmon_chip_info {\n\tconst struct hwmon_ops *ops;\n\tconst struct hwmon_channel_info **info;\n};\n\nstruct nvme_smart_log {\n\t__u8 critical_warning;\n\t__u8 temperature[2];\n\t__u8 avail_spare;\n\t__u8 spare_thresh;\n\t__u8 percent_used;\n\t__u8 endu_grp_crit_warn_sumry;\n\t__u8 rsvd7[25];\n\t__u8 data_units_read[16];\n\t__u8 data_units_written[16];\n\t__u8 host_reads[16];\n\t__u8 host_writes[16];\n\t__u8 ctrl_busy_time[16];\n\t__u8 power_cycles[16];\n\t__u8 power_on_hours[16];\n\t__u8 unsafe_shutdowns[16];\n\t__u8 media_errors[16];\n\t__u8 num_err_log_entries[16];\n\t__le32 warning_temp_time;\n\t__le32 critical_comp_time;\n\t__le16 temp_sensor[8];\n\t__le32 thm_temp1_trans_count;\n\t__le32 thm_temp2_trans_count;\n\t__le32 thm_temp1_total_time;\n\t__le32 thm_temp2_total_time;\n\t__u8 rsvd232[280];\n};\n\nenum {\n\tNVME_SMART_CRIT_SPARE = 1,\n\tNVME_SMART_CRIT_TEMPERATURE = 2,\n\tNVME_SMART_CRIT_RELIABILITY = 4,\n\tNVME_SMART_CRIT_MEDIA = 8,\n\tNVME_SMART_CRIT_VOLATILE_MEMORY = 16,\n};\n\nenum {\n\tNVME_TEMP_THRESH_MASK = 65535,\n\tNVME_TEMP_THRESH_SELECT_SHIFT = 16,\n\tNVME_TEMP_THRESH_TYPE_UNDER = 1048576,\n};\n\nstruct nvme_hwmon_data {\n\tstruct nvme_ctrl *ctrl;\n\tstruct nvme_smart_log log;\n\tstruct mutex read_lock;\n};\n\nenum {\n\tNVME_CMBSZ_SQS = 1,\n\tNVME_CMBSZ_CQS = 2,\n\tNVME_CMBSZ_LISTS = 4,\n\tNVME_CMBSZ_RDS = 8,\n\tNVME_CMBSZ_WDS = 16,\n\tNVME_CMBSZ_SZ_SHIFT = 12,\n\tNVME_CMBSZ_SZ_MASK = 1048575,\n\tNVME_CMBSZ_SZU_SHIFT = 8,\n\tNVME_CMBSZ_SZU_MASK = 15,\n};\n\nenum {\n\tNVME_SGL_FMT_DATA_DESC = 0,\n\tNVME_SGL_FMT_SEG_DESC = 2,\n\tNVME_SGL_FMT_LAST_SEG_DESC = 3,\n\tNVME_KEY_SGL_FMT_DATA_DESC = 4,\n\tNVME_TRANSPORT_SGL_DATA_DESC = 5,\n};\n\nenum {\n\tNVME_HOST_MEM_ENABLE = 1,\n\tNVME_HOST_MEM_RETURN = 2,\n};\n\nstruct nvme_host_mem_buf_desc {\n\t__le64 addr;\n\t__le32 size;\n\t__u32 rsvd;\n};\n\nstruct nvme_completion {\n\tunion nvme_result result;\n\t__le16 sq_head;\n\t__le16 sq_id;\n\t__u16 command_id;\n\t__le16 status;\n};\n\nstruct nvme_queue;\n\nstruct nvme_dev {\n\tstruct nvme_queue *queues;\n\tstruct blk_mq_tag_set tagset;\n\tstruct blk_mq_tag_set admin_tagset;\n\tu32 *dbs;\n\tstruct device *dev;\n\tstruct dma_pool___2 *prp_page_pool;\n\tstruct dma_pool___2 *prp_small_pool;\n\tunsigned int online_queues;\n\tunsigned int max_qid;\n\tunsigned int io_queues[3];\n\tunsigned int num_vecs;\n\tu32 q_depth;\n\tint io_sqes;\n\tu32 db_stride;\n\tvoid *bar;\n\tlong unsigned int bar_mapped_size;\n\tstruct work_struct remove_work;\n\tstruct mutex shutdown_lock;\n\tbool subsystem;\n\tu64 cmb_size;\n\tbool cmb_use_sqes;\n\tu32 cmbsz;\n\tu32 cmbloc;\n\tstruct nvme_ctrl ctrl;\n\tu32 last_ps;\n\tmempool_t *iod_mempool;\n\tu32 *dbbuf_dbs;\n\tdma_addr_t dbbuf_dbs_dma_addr;\n\tu32 *dbbuf_eis;\n\tdma_addr_t dbbuf_eis_dma_addr;\n\tu64 host_mem_size;\n\tu32 nr_host_mem_descs;\n\tdma_addr_t host_mem_descs_dma;\n\tstruct nvme_host_mem_buf_desc *host_mem_descs;\n\tvoid **host_mem_desc_bufs;\n\tunsigned int nr_allocated_queues;\n\tunsigned int nr_write_queues;\n\tunsigned int nr_poll_queues;\n};\n\nstruct nvme_queue {\n\tstruct nvme_dev *dev;\n\tspinlock_t sq_lock;\n\tvoid *sq_cmds;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tspinlock_t cq_poll_lock;\n\tstruct nvme_completion *cqes;\n\tdma_addr_t sq_dma_addr;\n\tdma_addr_t cq_dma_addr;\n\tu32 *q_db;\n\tu32 q_depth;\n\tu16 cq_vector;\n\tu16 sq_tail;\n\tu16 last_sq_tail;\n\tu16 cq_head;\n\tu16 qid;\n\tu8 cq_phase;\n\tu8 sqes;\n\tlong unsigned int flags;\n\tu32 *dbbuf_sq_db;\n\tu32 *dbbuf_cq_db;\n\tu32 *dbbuf_sq_ei;\n\tu32 *dbbuf_cq_ei;\n\tstruct completion delete_done;\n};\n\nstruct nvme_iod {\n\tstruct nvme_request req;\n\tstruct nvme_command cmd;\n\tstruct nvme_queue *nvmeq;\n\tbool use_sgl;\n\tint aborted;\n\tint npages;\n\tint nents;\n\tdma_addr_t first_dma;\n\tunsigned int dma_len;\n\tdma_addr_t meta_dma;\n\tstruct scatterlist *sg;\n};\n\nstruct pci_saved_state___2;\n\nenum {\n\tATA_MAX_DEVICES = 2,\n\tATA_MAX_PRD = 256,\n\tATA_SECT_SIZE = 512,\n\tATA_MAX_SECTORS_128 = 128,\n\tATA_MAX_SECTORS = 256,\n\tATA_MAX_SECTORS_1024 = 1024,\n\tATA_MAX_SECTORS_LBA48 = 65535,\n\tATA_MAX_SECTORS_TAPE = 65535,\n\tATA_MAX_TRIM_RNUM = 64,\n\tATA_ID_WORDS = 256,\n\tATA_ID_CONFIG = 0,\n\tATA_ID_CYLS = 1,\n\tATA_ID_HEADS = 3,\n\tATA_ID_SECTORS = 6,\n\tATA_ID_SERNO = 10,\n\tATA_ID_BUF_SIZE = 21,\n\tATA_ID_FW_REV = 23,\n\tATA_ID_PROD = 27,\n\tATA_ID_MAX_MULTSECT = 47,\n\tATA_ID_DWORD_IO = 48,\n\tATA_ID_TRUSTED = 48,\n\tATA_ID_CAPABILITY = 49,\n\tATA_ID_OLD_PIO_MODES = 51,\n\tATA_ID_OLD_DMA_MODES = 52,\n\tATA_ID_FIELD_VALID = 53,\n\tATA_ID_CUR_CYLS = 54,\n\tATA_ID_CUR_HEADS = 55,\n\tATA_ID_CUR_SECTORS = 56,\n\tATA_ID_MULTSECT = 59,\n\tATA_ID_LBA_CAPACITY = 60,\n\tATA_ID_SWDMA_MODES = 62,\n\tATA_ID_MWDMA_MODES = 63,\n\tATA_ID_PIO_MODES = 64,\n\tATA_ID_EIDE_DMA_MIN = 65,\n\tATA_ID_EIDE_DMA_TIME = 66,\n\tATA_ID_EIDE_PIO = 67,\n\tATA_ID_EIDE_PIO_IORDY = 68,\n\tATA_ID_ADDITIONAL_SUPP = 69,\n\tATA_ID_QUEUE_DEPTH = 75,\n\tATA_ID_SATA_CAPABILITY = 76,\n\tATA_ID_SATA_CAPABILITY_2 = 77,\n\tATA_ID_FEATURE_SUPP = 78,\n\tATA_ID_MAJOR_VER = 80,\n\tATA_ID_COMMAND_SET_1 = 82,\n\tATA_ID_COMMAND_SET_2 = 83,\n\tATA_ID_CFSSE = 84,\n\tATA_ID_CFS_ENABLE_1 = 85,\n\tATA_ID_CFS_ENABLE_2 = 86,\n\tATA_ID_CSF_DEFAULT = 87,\n\tATA_ID_UDMA_MODES = 88,\n\tATA_ID_HW_CONFIG = 93,\n\tATA_ID_SPG = 98,\n\tATA_ID_LBA_CAPACITY_2 = 100,\n\tATA_ID_SECTOR_SIZE = 106,\n\tATA_ID_WWN = 108,\n\tATA_ID_LOGICAL_SECTOR_SIZE = 117,\n\tATA_ID_COMMAND_SET_3 = 119,\n\tATA_ID_COMMAND_SET_4 = 120,\n\tATA_ID_LAST_LUN = 126,\n\tATA_ID_DLF = 128,\n\tATA_ID_CSFO = 129,\n\tATA_ID_CFA_POWER = 160,\n\tATA_ID_CFA_KEY_MGMT = 162,\n\tATA_ID_CFA_MODES = 163,\n\tATA_ID_DATA_SET_MGMT = 169,\n\tATA_ID_SCT_CMD_XPORT = 206,\n\tATA_ID_ROT_SPEED = 217,\n\tATA_ID_PIO4 = 2,\n\tATA_ID_SERNO_LEN = 20,\n\tATA_ID_FW_REV_LEN = 8,\n\tATA_ID_PROD_LEN = 40,\n\tATA_ID_WWN_LEN = 8,\n\tATA_PCI_CTL_OFS = 2,\n\tATA_PIO0 = 1,\n\tATA_PIO1 = 3,\n\tATA_PIO2 = 7,\n\tATA_PIO3 = 15,\n\tATA_PIO4 = 31,\n\tATA_PIO5 = 63,\n\tATA_PIO6 = 127,\n\tATA_PIO4_ONLY = 16,\n\tATA_SWDMA0 = 1,\n\tATA_SWDMA1 = 3,\n\tATA_SWDMA2 = 7,\n\tATA_SWDMA2_ONLY = 4,\n\tATA_MWDMA0 = 1,\n\tATA_MWDMA1 = 3,\n\tATA_MWDMA2 = 7,\n\tATA_MWDMA3 = 15,\n\tATA_MWDMA4 = 31,\n\tATA_MWDMA12_ONLY = 6,\n\tATA_MWDMA2_ONLY = 4,\n\tATA_UDMA0 = 1,\n\tATA_UDMA1 = 3,\n\tATA_UDMA2 = 7,\n\tATA_UDMA3 = 15,\n\tATA_UDMA4 = 31,\n\tATA_UDMA5 = 63,\n\tATA_UDMA6 = 127,\n\tATA_UDMA7 = 255,\n\tATA_UDMA24_ONLY = 20,\n\tATA_UDMA_MASK_40C = 7,\n\tATA_PRD_SZ = 8,\n\tATA_PRD_TBL_SZ = 2048,\n\tATA_PRD_EOT = 2147483648,\n\tATA_DMA_TABLE_OFS = 4,\n\tATA_DMA_STATUS = 2,\n\tATA_DMA_CMD = 0,\n\tATA_DMA_WR = 8,\n\tATA_DMA_START = 1,\n\tATA_DMA_INTR = 4,\n\tATA_DMA_ERR = 2,\n\tATA_DMA_ACTIVE = 1,\n\tATA_HOB = 128,\n\tATA_NIEN = 2,\n\tATA_LBA = 64,\n\tATA_DEV1 = 16,\n\tATA_DEVICE_OBS = 160,\n\tATA_DEVCTL_OBS = 8,\n\tATA_BUSY = 128,\n\tATA_DRDY = 64,\n\tATA_DF = 32,\n\tATA_DSC = 16,\n\tATA_DRQ = 8,\n\tATA_CORR = 4,\n\tATA_SENSE = 2,\n\tATA_ERR = 1,\n\tATA_SRST = 4,\n\tATA_ICRC = 128,\n\tATA_BBK = 128,\n\tATA_UNC = 64,\n\tATA_MC = 32,\n\tATA_IDNF = 16,\n\tATA_MCR = 8,\n\tATA_ABORTED = 4,\n\tATA_TRK0NF = 2,\n\tATA_AMNF = 1,\n\tATAPI_LFS = 240,\n\tATAPI_EOM = 2,\n\tATAPI_ILI = 1,\n\tATAPI_IO = 2,\n\tATAPI_COD = 1,\n\tATA_REG_DATA = 0,\n\tATA_REG_ERR = 1,\n\tATA_REG_NSECT = 2,\n\tATA_REG_LBAL = 3,\n\tATA_REG_LBAM = 4,\n\tATA_REG_LBAH = 5,\n\tATA_REG_DEVICE = 6,\n\tATA_REG_STATUS = 7,\n\tATA_REG_FEATURE = 1,\n\tATA_REG_CMD = 7,\n\tATA_REG_BYTEL = 4,\n\tATA_REG_BYTEH = 5,\n\tATA_REG_DEVSEL = 6,\n\tATA_REG_IRQ = 2,\n\tATA_CMD_DEV_RESET = 8,\n\tATA_CMD_CHK_POWER = 229,\n\tATA_CMD_STANDBY = 226,\n\tATA_CMD_IDLE = 227,\n\tATA_CMD_EDD = 144,\n\tATA_CMD_DOWNLOAD_MICRO = 146,\n\tATA_CMD_DOWNLOAD_MICRO_DMA = 147,\n\tATA_CMD_NOP = 0,\n\tATA_CMD_FLUSH = 231,\n\tATA_CMD_FLUSH_EXT = 234,\n\tATA_CMD_ID_ATA = 236,\n\tATA_CMD_ID_ATAPI = 161,\n\tATA_CMD_SERVICE = 162,\n\tATA_CMD_READ = 200,\n\tATA_CMD_READ_EXT = 37,\n\tATA_CMD_READ_QUEUED = 38,\n\tATA_CMD_READ_STREAM_EXT = 43,\n\tATA_CMD_READ_STREAM_DMA_EXT = 42,\n\tATA_CMD_WRITE = 202,\n\tATA_CMD_WRITE_EXT = 53,\n\tATA_CMD_WRITE_QUEUED = 54,\n\tATA_CMD_WRITE_STREAM_EXT = 59,\n\tATA_CMD_WRITE_STREAM_DMA_EXT = 58,\n\tATA_CMD_WRITE_FUA_EXT = 61,\n\tATA_CMD_WRITE_QUEUED_FUA_EXT = 62,\n\tATA_CMD_FPDMA_READ = 96,\n\tATA_CMD_FPDMA_WRITE = 97,\n\tATA_CMD_NCQ_NON_DATA = 99,\n\tATA_CMD_FPDMA_SEND = 100,\n\tATA_CMD_FPDMA_RECV = 101,\n\tATA_CMD_PIO_READ = 32,\n\tATA_CMD_PIO_READ_EXT = 36,\n\tATA_CMD_PIO_WRITE = 48,\n\tATA_CMD_PIO_WRITE_EXT = 52,\n\tATA_CMD_READ_MULTI = 196,\n\tATA_CMD_READ_MULTI_EXT = 41,\n\tATA_CMD_WRITE_MULTI = 197,\n\tATA_CMD_WRITE_MULTI_EXT = 57,\n\tATA_CMD_WRITE_MULTI_FUA_EXT = 206,\n\tATA_CMD_SET_FEATURES = 239,\n\tATA_CMD_SET_MULTI = 198,\n\tATA_CMD_PACKET = 160,\n\tATA_CMD_VERIFY = 64,\n\tATA_CMD_VERIFY_EXT = 66,\n\tATA_CMD_WRITE_UNCORR_EXT = 69,\n\tATA_CMD_STANDBYNOW1 = 224,\n\tATA_CMD_IDLEIMMEDIATE = 225,\n\tATA_CMD_SLEEP = 230,\n\tATA_CMD_INIT_DEV_PARAMS = 145,\n\tATA_CMD_READ_NATIVE_MAX = 248,\n\tATA_CMD_READ_NATIVE_MAX_EXT = 39,\n\tATA_CMD_SET_MAX = 249,\n\tATA_CMD_SET_MAX_EXT = 55,\n\tATA_CMD_READ_LOG_EXT = 47,\n\tATA_CMD_WRITE_LOG_EXT = 63,\n\tATA_CMD_READ_LOG_DMA_EXT = 71,\n\tATA_CMD_WRITE_LOG_DMA_EXT = 87,\n\tATA_CMD_TRUSTED_NONDATA = 91,\n\tATA_CMD_TRUSTED_RCV = 92,\n\tATA_CMD_TRUSTED_RCV_DMA = 93,\n\tATA_CMD_TRUSTED_SND = 94,\n\tATA_CMD_TRUSTED_SND_DMA = 95,\n\tATA_CMD_PMP_READ = 228,\n\tATA_CMD_PMP_READ_DMA = 233,\n\tATA_CMD_PMP_WRITE = 232,\n\tATA_CMD_PMP_WRITE_DMA = 235,\n\tATA_CMD_CONF_OVERLAY = 177,\n\tATA_CMD_SEC_SET_PASS = 241,\n\tATA_CMD_SEC_UNLOCK = 242,\n\tATA_CMD_SEC_ERASE_PREP = 243,\n\tATA_CMD_SEC_ERASE_UNIT = 244,\n\tATA_CMD_SEC_FREEZE_LOCK = 245,\n\tATA_CMD_SEC_DISABLE_PASS = 246,\n\tATA_CMD_CONFIG_STREAM = 81,\n\tATA_CMD_SMART = 176,\n\tATA_CMD_MEDIA_LOCK = 222,\n\tATA_CMD_MEDIA_UNLOCK = 223,\n\tATA_CMD_DSM = 6,\n\tATA_CMD_CHK_MED_CRD_TYP = 209,\n\tATA_CMD_CFA_REQ_EXT_ERR = 3,\n\tATA_CMD_CFA_WRITE_NE = 56,\n\tATA_CMD_CFA_TRANS_SECT = 135,\n\tATA_CMD_CFA_ERASE = 192,\n\tATA_CMD_CFA_WRITE_MULT_NE = 205,\n\tATA_CMD_REQ_SENSE_DATA = 11,\n\tATA_CMD_SANITIZE_DEVICE = 180,\n\tATA_CMD_ZAC_MGMT_IN = 74,\n\tATA_CMD_ZAC_MGMT_OUT = 159,\n\tATA_CMD_RESTORE = 16,\n\tATA_SUBCMD_FPDMA_RECV_RD_LOG_DMA_EXT = 1,\n\tATA_SUBCMD_FPDMA_RECV_ZAC_MGMT_IN = 2,\n\tATA_SUBCMD_FPDMA_SEND_DSM = 0,\n\tATA_SUBCMD_FPDMA_SEND_WR_LOG_DMA_EXT = 2,\n\tATA_SUBCMD_NCQ_NON_DATA_ABORT_QUEUE = 0,\n\tATA_SUBCMD_NCQ_NON_DATA_SET_FEATURES = 5,\n\tATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT = 6,\n\tATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT = 7,\n\tATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES = 0,\n\tATA_SUBCMD_ZAC_MGMT_OUT_CLOSE_ZONE = 1,\n\tATA_SUBCMD_ZAC_MGMT_OUT_FINISH_ZONE = 2,\n\tATA_SUBCMD_ZAC_MGMT_OUT_OPEN_ZONE = 3,\n\tATA_SUBCMD_ZAC_MGMT_OUT_RESET_WRITE_POINTER = 4,\n\tATA_LOG_DIRECTORY = 0,\n\tATA_LOG_SATA_NCQ = 16,\n\tATA_LOG_NCQ_NON_DATA = 18,\n\tATA_LOG_NCQ_SEND_RECV = 19,\n\tATA_LOG_IDENTIFY_DEVICE = 48,\n\tATA_LOG_SECURITY = 6,\n\tATA_LOG_SATA_SETTINGS = 8,\n\tATA_LOG_ZONED_INFORMATION = 9,\n\tATA_LOG_DEVSLP_OFFSET = 48,\n\tATA_LOG_DEVSLP_SIZE = 8,\n\tATA_LOG_DEVSLP_MDAT = 0,\n\tATA_LOG_DEVSLP_MDAT_MASK = 31,\n\tATA_LOG_DEVSLP_DETO = 1,\n\tATA_LOG_DEVSLP_VALID = 7,\n\tATA_LOG_DEVSLP_VALID_MASK = 128,\n\tATA_LOG_NCQ_PRIO_OFFSET = 9,\n\tATA_LOG_NCQ_SEND_RECV_SUBCMDS_OFFSET = 0,\n\tATA_LOG_NCQ_SEND_RECV_SUBCMDS_DSM = 1,\n\tATA_LOG_NCQ_SEND_RECV_DSM_OFFSET = 4,\n\tATA_LOG_NCQ_SEND_RECV_DSM_TRIM = 1,\n\tATA_LOG_NCQ_SEND_RECV_RD_LOG_OFFSET = 8,\n\tATA_LOG_NCQ_SEND_RECV_RD_LOG_SUPPORTED = 1,\n\tATA_LOG_NCQ_SEND_RECV_WR_LOG_OFFSET = 12,\n\tATA_LOG_NCQ_SEND_RECV_WR_LOG_SUPPORTED = 1,\n\tATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_OFFSET = 16,\n\tATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_OUT_SUPPORTED = 1,\n\tATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_IN_SUPPORTED = 2,\n\tATA_LOG_NCQ_SEND_RECV_SIZE = 20,\n\tATA_LOG_NCQ_NON_DATA_SUBCMDS_OFFSET = 0,\n\tATA_LOG_NCQ_NON_DATA_ABORT_OFFSET = 0,\n\tATA_LOG_NCQ_NON_DATA_ABORT_NCQ = 1,\n\tATA_LOG_NCQ_NON_DATA_ABORT_ALL = 2,\n\tATA_LOG_NCQ_NON_DATA_ABORT_STREAMING = 4,\n\tATA_LOG_NCQ_NON_DATA_ABORT_NON_STREAMING = 8,\n\tATA_LOG_NCQ_NON_DATA_ABORT_SELECTED = 16,\n\tATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OFFSET = 28,\n\tATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OUT = 1,\n\tATA_LOG_NCQ_NON_DATA_SIZE = 64,\n\tATA_CMD_READ_LONG = 34,\n\tATA_CMD_READ_LONG_ONCE = 35,\n\tATA_CMD_WRITE_LONG = 50,\n\tATA_CMD_WRITE_LONG_ONCE = 51,\n\tSETFEATURES_XFER = 3,\n\tXFER_UDMA_7 = 71,\n\tXFER_UDMA_6 = 70,\n\tXFER_UDMA_5 = 69,\n\tXFER_UDMA_4 = 68,\n\tXFER_UDMA_3 = 67,\n\tXFER_UDMA_2 = 66,\n\tXFER_UDMA_1 = 65,\n\tXFER_UDMA_0 = 64,\n\tXFER_MW_DMA_4 = 36,\n\tXFER_MW_DMA_3 = 35,\n\tXFER_MW_DMA_2 = 34,\n\tXFER_MW_DMA_1 = 33,\n\tXFER_MW_DMA_0 = 32,\n\tXFER_SW_DMA_2 = 18,\n\tXFER_SW_DMA_1 = 17,\n\tXFER_SW_DMA_0 = 16,\n\tXFER_PIO_6 = 14,\n\tXFER_PIO_5 = 13,\n\tXFER_PIO_4 = 12,\n\tXFER_PIO_3 = 11,\n\tXFER_PIO_2 = 10,\n\tXFER_PIO_1 = 9,\n\tXFER_PIO_0 = 8,\n\tXFER_PIO_SLOW = 0,\n\tSETFEATURES_WC_ON = 2,\n\tSETFEATURES_WC_OFF = 130,\n\tSETFEATURES_RA_ON = 170,\n\tSETFEATURES_RA_OFF = 85,\n\tSETFEATURES_AAM_ON = 66,\n\tSETFEATURES_AAM_OFF = 194,\n\tSETFEATURES_SPINUP = 7,\n\tSETFEATURES_SPINUP_TIMEOUT = 30000,\n\tSETFEATURES_SATA_ENABLE = 16,\n\tSETFEATURES_SATA_DISABLE = 144,\n\tSATA_FPDMA_OFFSET = 1,\n\tSATA_FPDMA_AA = 2,\n\tSATA_DIPM = 3,\n\tSATA_FPDMA_IN_ORDER = 4,\n\tSATA_AN = 5,\n\tSATA_SSP = 6,\n\tSATA_DEVSLP = 9,\n\tSETFEATURE_SENSE_DATA = 195,\n\tATA_SET_MAX_ADDR = 0,\n\tATA_SET_MAX_PASSWD = 1,\n\tATA_SET_MAX_LOCK = 2,\n\tATA_SET_MAX_UNLOCK = 3,\n\tATA_SET_MAX_FREEZE_LOCK = 4,\n\tATA_SET_MAX_PASSWD_DMA = 5,\n\tATA_SET_MAX_UNLOCK_DMA = 6,\n\tATA_DCO_RESTORE = 192,\n\tATA_DCO_FREEZE_LOCK = 193,\n\tATA_DCO_IDENTIFY = 194,\n\tATA_DCO_SET = 195,\n\tATA_SMART_ENABLE = 216,\n\tATA_SMART_READ_VALUES = 208,\n\tATA_SMART_READ_THRESHOLDS = 209,\n\tATA_DSM_TRIM = 1,\n\tATA_SMART_LBAM_PASS = 79,\n\tATA_SMART_LBAH_PASS = 194,\n\tATAPI_PKT_DMA = 1,\n\tATAPI_DMADIR = 4,\n\tATAPI_CDB_LEN = 16,\n\tSATA_PMP_MAX_PORTS = 15,\n\tSATA_PMP_CTRL_PORT = 15,\n\tSATA_PMP_GSCR_DWORDS = 128,\n\tSATA_PMP_GSCR_PROD_ID = 0,\n\tSATA_PMP_GSCR_REV = 1,\n\tSATA_PMP_GSCR_PORT_INFO = 2,\n\tSATA_PMP_GSCR_ERROR = 32,\n\tSATA_PMP_GSCR_ERROR_EN = 33,\n\tSATA_PMP_GSCR_FEAT = 64,\n\tSATA_PMP_GSCR_FEAT_EN = 96,\n\tSATA_PMP_PSCR_STATUS = 0,\n\tSATA_PMP_PSCR_ERROR = 1,\n\tSATA_PMP_PSCR_CONTROL = 2,\n\tSATA_PMP_FEAT_BIST = 1,\n\tSATA_PMP_FEAT_PMREQ = 2,\n\tSATA_PMP_FEAT_DYNSSC = 4,\n\tSATA_PMP_FEAT_NOTIFY = 8,\n\tATA_CBL_NONE = 0,\n\tATA_CBL_PATA40 = 1,\n\tATA_CBL_PATA80 = 2,\n\tATA_CBL_PATA40_SHORT = 3,\n\tATA_CBL_PATA_UNK = 4,\n\tATA_CBL_PATA_IGN = 5,\n\tATA_CBL_SATA = 6,\n\tSCR_STATUS = 0,\n\tSCR_ERROR = 1,\n\tSCR_CONTROL = 2,\n\tSCR_ACTIVE = 3,\n\tSCR_NOTIFICATION = 4,\n\tSERR_DATA_RECOVERED = 1,\n\tSERR_COMM_RECOVERED = 2,\n\tSERR_DATA = 256,\n\tSERR_PERSISTENT = 512,\n\tSERR_PROTOCOL = 1024,\n\tSERR_INTERNAL = 2048,\n\tSERR_PHYRDY_CHG = 65536,\n\tSERR_PHY_INT_ERR = 131072,\n\tSERR_COMM_WAKE = 262144,\n\tSERR_10B_8B_ERR = 524288,\n\tSERR_DISPARITY = 1048576,\n\tSERR_CRC = 2097152,\n\tSERR_HANDSHAKE = 4194304,\n\tSERR_LINK_SEQ_ERR = 8388608,\n\tSERR_TRANS_ST_ERROR = 16777216,\n\tSERR_UNRECOG_FIS = 33554432,\n\tSERR_DEV_XCHG = 67108864,\n};\n\nenum ata_prot_flags {\n\tATA_PROT_FLAG_PIO = 1,\n\tATA_PROT_FLAG_DMA = 2,\n\tATA_PROT_FLAG_NCQ = 4,\n\tATA_PROT_FLAG_ATAPI = 8,\n\tATA_PROT_UNKNOWN = 255,\n\tATA_PROT_NODATA = 0,\n\tATA_PROT_PIO = 1,\n\tATA_PROT_DMA = 2,\n\tATA_PROT_NCQ_NODATA = 4,\n\tATA_PROT_NCQ = 6,\n\tATAPI_PROT_NODATA = 8,\n\tATAPI_PROT_PIO = 9,\n\tATAPI_PROT_DMA = 10,\n};\n\nstruct ata_bmdma_prd {\n\t__le32 addr;\n\t__le32 flags_len;\n};\n\nenum {\n\tATA_MSG_DRV = 1,\n\tATA_MSG_INFO = 2,\n\tATA_MSG_PROBE = 4,\n\tATA_MSG_WARN = 8,\n\tATA_MSG_MALLOC = 16,\n\tATA_MSG_CTL = 32,\n\tATA_MSG_INTR = 64,\n\tATA_MSG_ERR = 128,\n};\n\nenum {\n\tLIBATA_MAX_PRD = 128,\n\tLIBATA_DUMB_MAX_PRD = 64,\n\tATA_DEF_QUEUE = 1,\n\tATA_MAX_QUEUE = 32,\n\tATA_TAG_INTERNAL = 32,\n\tATA_SHORT_PAUSE = 16,\n\tATAPI_MAX_DRAIN = 16384,\n\tATA_ALL_DEVICES = 3,\n\tATA_SHT_EMULATED = 1,\n\tATA_SHT_THIS_ID = 4294967295,\n\tATA_TFLAG_LBA48 = 1,\n\tATA_TFLAG_ISADDR = 2,\n\tATA_TFLAG_DEVICE = 4,\n\tATA_TFLAG_WRITE = 8,\n\tATA_TFLAG_LBA = 16,\n\tATA_TFLAG_FUA = 32,\n\tATA_TFLAG_POLLING = 64,\n\tATA_DFLAG_LBA = 1,\n\tATA_DFLAG_LBA48 = 2,\n\tATA_DFLAG_CDB_INTR = 4,\n\tATA_DFLAG_NCQ = 8,\n\tATA_DFLAG_FLUSH_EXT = 16,\n\tATA_DFLAG_ACPI_PENDING = 32,\n\tATA_DFLAG_ACPI_FAILED = 64,\n\tATA_DFLAG_AN = 128,\n\tATA_DFLAG_TRUSTED = 256,\n\tATA_DFLAG_DMADIR = 1024,\n\tATA_DFLAG_CFG_MASK = 4095,\n\tATA_DFLAG_PIO = 4096,\n\tATA_DFLAG_NCQ_OFF = 8192,\n\tATA_DFLAG_SLEEPING = 32768,\n\tATA_DFLAG_DUBIOUS_XFER = 65536,\n\tATA_DFLAG_NO_UNLOAD = 131072,\n\tATA_DFLAG_UNLOCK_HPA = 262144,\n\tATA_DFLAG_NCQ_SEND_RECV = 524288,\n\tATA_DFLAG_NCQ_PRIO = 1048576,\n\tATA_DFLAG_NCQ_PRIO_ENABLE = 2097152,\n\tATA_DFLAG_INIT_MASK = 16777215,\n\tATA_DFLAG_DETACH = 16777216,\n\tATA_DFLAG_DETACHED = 33554432,\n\tATA_DFLAG_DA = 67108864,\n\tATA_DFLAG_DEVSLP = 134217728,\n\tATA_DFLAG_ACPI_DISABLED = 268435456,\n\tATA_DFLAG_D_SENSE = 536870912,\n\tATA_DFLAG_ZAC = 1073741824,\n\tATA_DEV_UNKNOWN = 0,\n\tATA_DEV_ATA = 1,\n\tATA_DEV_ATA_UNSUP = 2,\n\tATA_DEV_ATAPI = 3,\n\tATA_DEV_ATAPI_UNSUP = 4,\n\tATA_DEV_PMP = 5,\n\tATA_DEV_PMP_UNSUP = 6,\n\tATA_DEV_SEMB = 7,\n\tATA_DEV_SEMB_UNSUP = 8,\n\tATA_DEV_ZAC = 9,\n\tATA_DEV_ZAC_UNSUP = 10,\n\tATA_DEV_NONE = 11,\n\tATA_LFLAG_NO_HRST = 2,\n\tATA_LFLAG_NO_SRST = 4,\n\tATA_LFLAG_ASSUME_ATA = 8,\n\tATA_LFLAG_ASSUME_SEMB = 16,\n\tATA_LFLAG_ASSUME_CLASS = 24,\n\tATA_LFLAG_NO_RETRY = 32,\n\tATA_LFLAG_DISABLED = 64,\n\tATA_LFLAG_SW_ACTIVITY = 128,\n\tATA_LFLAG_NO_LPM = 256,\n\tATA_LFLAG_RST_ONCE = 512,\n\tATA_LFLAG_CHANGED = 1024,\n\tATA_LFLAG_NO_DB_DELAY = 2048,\n\tATA_FLAG_SLAVE_POSS = 1,\n\tATA_FLAG_SATA = 2,\n\tATA_FLAG_NO_LPM = 4,\n\tATA_FLAG_NO_LOG_PAGE = 32,\n\tATA_FLAG_NO_ATAPI = 64,\n\tATA_FLAG_PIO_DMA = 128,\n\tATA_FLAG_PIO_LBA48 = 256,\n\tATA_FLAG_PIO_POLLING = 512,\n\tATA_FLAG_NCQ = 1024,\n\tATA_FLAG_NO_POWEROFF_SPINDOWN = 2048,\n\tATA_FLAG_NO_HIBERNATE_SPINDOWN = 4096,\n\tATA_FLAG_DEBUGMSG = 8192,\n\tATA_FLAG_FPDMA_AA = 16384,\n\tATA_FLAG_IGN_SIMPLEX = 32768,\n\tATA_FLAG_NO_IORDY = 65536,\n\tATA_FLAG_ACPI_SATA = 131072,\n\tATA_FLAG_AN = 262144,\n\tATA_FLAG_PMP = 524288,\n\tATA_FLAG_FPDMA_AUX = 1048576,\n\tATA_FLAG_EM = 2097152,\n\tATA_FLAG_SW_ACTIVITY = 4194304,\n\tATA_FLAG_NO_DIPM = 8388608,\n\tATA_FLAG_SAS_HOST = 16777216,\n\tATA_PFLAG_EH_PENDING = 1,\n\tATA_PFLAG_EH_IN_PROGRESS = 2,\n\tATA_PFLAG_FROZEN = 4,\n\tATA_PFLAG_RECOVERED = 8,\n\tATA_PFLAG_LOADING = 16,\n\tATA_PFLAG_SCSI_HOTPLUG = 64,\n\tATA_PFLAG_INITIALIZING = 128,\n\tATA_PFLAG_RESETTING = 256,\n\tATA_PFLAG_UNLOADING = 512,\n\tATA_PFLAG_UNLOADED = 1024,\n\tATA_PFLAG_SUSPENDED = 131072,\n\tATA_PFLAG_PM_PENDING = 262144,\n\tATA_PFLAG_INIT_GTM_VALID = 524288,\n\tATA_PFLAG_PIO32 = 1048576,\n\tATA_PFLAG_PIO32CHANGE = 2097152,\n\tATA_PFLAG_EXTERNAL = 4194304,\n\tATA_QCFLAG_ACTIVE = 1,\n\tATA_QCFLAG_DMAMAP = 2,\n\tATA_QCFLAG_IO = 8,\n\tATA_QCFLAG_RESULT_TF = 16,\n\tATA_QCFLAG_CLEAR_EXCL = 32,\n\tATA_QCFLAG_QUIET = 64,\n\tATA_QCFLAG_RETRY = 128,\n\tATA_QCFLAG_FAILED = 65536,\n\tATA_QCFLAG_SENSE_VALID = 131072,\n\tATA_QCFLAG_EH_SCHEDULED = 262144,\n\tATA_HOST_SIMPLEX = 1,\n\tATA_HOST_STARTED = 2,\n\tATA_HOST_PARALLEL_SCAN = 4,\n\tATA_HOST_IGNORE_ATA = 8,\n\tATA_TMOUT_BOOT = 30000,\n\tATA_TMOUT_BOOT_QUICK = 7000,\n\tATA_TMOUT_INTERNAL_QUICK = 5000,\n\tATA_TMOUT_MAX_PARK = 30000,\n\tATA_TMOUT_FF_WAIT_LONG = 2000,\n\tATA_TMOUT_FF_WAIT = 800,\n\tATA_WAIT_AFTER_RESET = 150,\n\tATA_TMOUT_PMP_SRST_WAIT = 5000,\n\tATA_TMOUT_SPURIOUS_PHY = 10000,\n\tBUS_UNKNOWN = 0,\n\tBUS_DMA = 1,\n\tBUS_IDLE = 2,\n\tBUS_NOINTR = 3,\n\tBUS_NODATA = 4,\n\tBUS_TIMER = 5,\n\tBUS_PIO = 6,\n\tBUS_EDD = 7,\n\tBUS_IDENTIFY = 8,\n\tBUS_PACKET = 9,\n\tPORT_UNKNOWN = 0,\n\tPORT_ENABLED = 1,\n\tPORT_DISABLED = 2,\n\tATA_NR_PIO_MODES = 7,\n\tATA_NR_MWDMA_MODES = 5,\n\tATA_NR_UDMA_MODES = 8,\n\tATA_SHIFT_PIO = 0,\n\tATA_SHIFT_MWDMA = 7,\n\tATA_SHIFT_UDMA = 12,\n\tATA_SHIFT_PRIO = 6,\n\tATA_PRIO_HIGH = 2,\n\tATA_DMA_PAD_SZ = 4,\n\tATA_ERING_SIZE = 32,\n\tATA_DEFER_LINK = 1,\n\tATA_DEFER_PORT = 2,\n\tATA_EH_DESC_LEN = 80,\n\tATA_EH_REVALIDATE = 1,\n\tATA_EH_SOFTRESET = 2,\n\tATA_EH_HARDRESET = 4,\n\tATA_EH_RESET = 6,\n\tATA_EH_ENABLE_LINK = 8,\n\tATA_EH_PARK = 32,\n\tATA_EH_PERDEV_MASK = 33,\n\tATA_EH_ALL_ACTIONS = 15,\n\tATA_EHI_HOTPLUGGED = 1,\n\tATA_EHI_NO_AUTOPSY = 4,\n\tATA_EHI_QUIET = 8,\n\tATA_EHI_NO_RECOVERY = 16,\n\tATA_EHI_DID_SOFTRESET = 65536,\n\tATA_EHI_DID_HARDRESET = 131072,\n\tATA_EHI_PRINTINFO = 262144,\n\tATA_EHI_SETMODE = 524288,\n\tATA_EHI_POST_SETMODE = 1048576,\n\tATA_EHI_DID_RESET = 196608,\n\tATA_EHI_TO_SLAVE_MASK = 12,\n\tATA_EH_MAX_TRIES = 5,\n\tATA_LINK_RESUME_TRIES = 5,\n\tATA_PROBE_MAX_TRIES = 3,\n\tATA_EH_DEV_TRIES = 3,\n\tATA_EH_PMP_TRIES = 5,\n\tATA_EH_PMP_LINK_TRIES = 3,\n\tSATA_PMP_RW_TIMEOUT = 3000,\n\tATA_EH_CMD_TIMEOUT_TABLE_SIZE = 6,\n\tATA_HORKAGE_DIAGNOSTIC = 1,\n\tATA_HORKAGE_NODMA = 2,\n\tATA_HORKAGE_NONCQ = 4,\n\tATA_HORKAGE_MAX_SEC_128 = 8,\n\tATA_HORKAGE_BROKEN_HPA = 16,\n\tATA_HORKAGE_DISABLE = 32,\n\tATA_HORKAGE_HPA_SIZE = 64,\n\tATA_HORKAGE_IVB = 256,\n\tATA_HORKAGE_STUCK_ERR = 512,\n\tATA_HORKAGE_BRIDGE_OK = 1024,\n\tATA_HORKAGE_ATAPI_MOD16_DMA = 2048,\n\tATA_HORKAGE_FIRMWARE_WARN = 4096,\n\tATA_HORKAGE_1_5_GBPS = 8192,\n\tATA_HORKAGE_NOSETXFER = 16384,\n\tATA_HORKAGE_BROKEN_FPDMA_AA = 32768,\n\tATA_HORKAGE_DUMP_ID = 65536,\n\tATA_HORKAGE_MAX_SEC_LBA48 = 131072,\n\tATA_HORKAGE_ATAPI_DMADIR = 262144,\n\tATA_HORKAGE_NO_NCQ_TRIM = 524288,\n\tATA_HORKAGE_NOLPM = 1048576,\n\tATA_HORKAGE_WD_BROKEN_LPM = 2097152,\n\tATA_HORKAGE_ZERO_AFTER_TRIM = 4194304,\n\tATA_HORKAGE_NO_DMA_LOG = 8388608,\n\tATA_HORKAGE_NOTRIM = 16777216,\n\tATA_HORKAGE_MAX_SEC_1024 = 33554432,\n\tATA_HORKAGE_MAX_TRIM_128M = 67108864,\n\tATA_DMA_MASK_ATA = 1,\n\tATA_DMA_MASK_ATAPI = 2,\n\tATA_DMA_MASK_CFA = 4,\n\tATAPI_READ = 0,\n\tATAPI_WRITE = 1,\n\tATAPI_READ_CD = 2,\n\tATAPI_PASS_THRU = 3,\n\tATAPI_MISC = 4,\n\tATA_TIMING_SETUP = 1,\n\tATA_TIMING_ACT8B = 2,\n\tATA_TIMING_REC8B = 4,\n\tATA_TIMING_CYC8B = 8,\n\tATA_TIMING_8BIT = 14,\n\tATA_TIMING_ACTIVE = 16,\n\tATA_TIMING_RECOVER = 32,\n\tATA_TIMING_DMACK_HOLD = 64,\n\tATA_TIMING_CYCLE = 128,\n\tATA_TIMING_UDMA = 256,\n\tATA_TIMING_ALL = 511,\n\tATA_ACPI_FILTER_SETXFER = 1,\n\tATA_ACPI_FILTER_LOCK = 2,\n\tATA_ACPI_FILTER_DIPM = 4,\n\tATA_ACPI_FILTER_FPDMA_OFFSET = 8,\n\tATA_ACPI_FILTER_FPDMA_AA = 16,\n\tATA_ACPI_FILTER_DEFAULT = 7,\n};\n\nenum ata_xfer_mask {\n\tATA_MASK_PIO = 127,\n\tATA_MASK_MWDMA = 3968,\n\tATA_MASK_UDMA = 1044480,\n};\n\nenum ata_completion_errors {\n\tAC_ERR_OK = 0,\n\tAC_ERR_DEV = 1,\n\tAC_ERR_HSM = 2,\n\tAC_ERR_TIMEOUT = 4,\n\tAC_ERR_MEDIA = 8,\n\tAC_ERR_ATA_BUS = 16,\n\tAC_ERR_HOST_BUS = 32,\n\tAC_ERR_SYSTEM = 64,\n\tAC_ERR_INVALID = 128,\n\tAC_ERR_OTHER = 256,\n\tAC_ERR_NODEV_HINT = 512,\n\tAC_ERR_NCQ = 1024,\n};\n\nenum ata_lpm_policy {\n\tATA_LPM_UNKNOWN = 0,\n\tATA_LPM_MAX_POWER = 1,\n\tATA_LPM_MED_POWER = 2,\n\tATA_LPM_MED_POWER_WITH_DIPM = 3,\n\tATA_LPM_MIN_POWER_WITH_PARTIAL = 4,\n\tATA_LPM_MIN_POWER = 5,\n};\n\nstruct ata_queued_cmd;\n\ntypedef void (*ata_qc_cb_t)(struct ata_queued_cmd *);\n\nstruct ata_taskfile {\n\tlong unsigned int flags;\n\tu8 protocol;\n\tu8 ctl;\n\tu8 hob_feature;\n\tu8 hob_nsect;\n\tu8 hob_lbal;\n\tu8 hob_lbam;\n\tu8 hob_lbah;\n\tu8 feature;\n\tu8 nsect;\n\tu8 lbal;\n\tu8 lbam;\n\tu8 lbah;\n\tu8 device;\n\tu8 command;\n\tu32 auxiliary;\n};\n\nstruct ata_port;\n\nstruct ata_device;\n\nstruct ata_queued_cmd {\n\tstruct ata_port *ap;\n\tstruct ata_device *dev;\n\tstruct scsi_cmnd *scsicmd;\n\tvoid (*scsidone)(struct scsi_cmnd *);\n\tstruct ata_taskfile tf;\n\tu8 cdb[16];\n\tlong unsigned int flags;\n\tunsigned int tag;\n\tunsigned int hw_tag;\n\tunsigned int n_elem;\n\tunsigned int orig_n_elem;\n\tint dma_dir;\n\tunsigned int sect_size;\n\tunsigned int nbytes;\n\tunsigned int extrabytes;\n\tunsigned int curbytes;\n\tstruct scatterlist sgent;\n\tstruct scatterlist *sg;\n\tstruct scatterlist *cursg;\n\tunsigned int cursg_ofs;\n\tunsigned int err_mask;\n\tstruct ata_taskfile result_tf;\n\tata_qc_cb_t complete_fn;\n\tvoid *private_data;\n\tvoid *lldd_task;\n};\n\nstruct ata_link;\n\ntypedef int (*ata_prereset_fn_t)(struct ata_link *, long unsigned int);\n\nstruct ata_eh_info {\n\tstruct ata_device *dev;\n\tu32 serror;\n\tunsigned int err_mask;\n\tunsigned int action;\n\tunsigned int dev_action[2];\n\tunsigned int flags;\n\tunsigned int probe_mask;\n\tchar desc[80];\n\tint desc_len;\n};\n\nstruct ata_eh_context {\n\tstruct ata_eh_info i;\n\tint tries[2];\n\tint cmd_timeout_idx[12];\n\tunsigned int classes[2];\n\tunsigned int did_probe_mask;\n\tunsigned int unloaded_mask;\n\tunsigned int saved_ncq_enabled;\n\tu8 saved_xfer_mode[2];\n\tlong unsigned int last_reset;\n};\n\nstruct ata_ering_entry {\n\tunsigned int eflags;\n\tunsigned int err_mask;\n\tu64 timestamp;\n};\n\nstruct ata_ering {\n\tint cursor;\n\tstruct ata_ering_entry ring[32];\n};\n\nstruct ata_device {\n\tstruct ata_link *link;\n\tunsigned int devno;\n\tunsigned int horkage;\n\tlong unsigned int flags;\n\tstruct scsi_device *sdev;\n\tvoid *private_data;\n\tunion acpi_object *gtf_cache;\n\tunsigned int gtf_filter;\n\tvoid *zpodd;\n\tstruct device tdev;\n\tu64 n_sectors;\n\tu64 n_native_sectors;\n\tunsigned int class;\n\tlong unsigned int unpark_deadline;\n\tu8 pio_mode;\n\tu8 dma_mode;\n\tu8 xfer_mode;\n\tunsigned int xfer_shift;\n\tunsigned int multi_count;\n\tunsigned int max_sectors;\n\tunsigned int cdb_len;\n\tlong unsigned int pio_mask;\n\tlong unsigned int mwdma_mask;\n\tlong unsigned int udma_mask;\n\tu16 cylinders;\n\tu16 heads;\n\tu16 sectors;\n\tunion {\n\t\tu16 id[256];\n\t\tu32 gscr[128];\n\t};\n\tu8 devslp_timing[8];\n\tu8 ncq_send_recv_cmds[20];\n\tu8 ncq_non_data_cmds[64];\n\tu32 zac_zoned_cap;\n\tu32 zac_zones_optimal_open;\n\tu32 zac_zones_optimal_nonseq;\n\tu32 zac_zones_max_open;\n\tint spdn_cnt;\n\tstruct ata_ering ering;\n\tlong: 64;\n};\n\nstruct ata_link {\n\tstruct ata_port *ap;\n\tint pmp;\n\tstruct device tdev;\n\tunsigned int active_tag;\n\tu32 sactive;\n\tunsigned int flags;\n\tu32 saved_scontrol;\n\tunsigned int hw_sata_spd_limit;\n\tunsigned int sata_spd_limit;\n\tunsigned int sata_spd;\n\tenum ata_lpm_policy lpm_policy;\n\tstruct ata_eh_info eh_info;\n\tstruct ata_eh_context eh_context;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct ata_device device[2];\n\tlong unsigned int last_lpm_change;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\ntypedef int (*ata_reset_fn_t)(struct ata_link *, unsigned int *, long unsigned int);\n\ntypedef void (*ata_postreset_fn_t)(struct ata_link *, unsigned int *);\n\nenum sw_activity {\n\tOFF = 0,\n\tBLINK_ON = 1,\n\tBLINK_OFF = 2,\n};\n\nstruct ata_ioports {\n\tvoid *cmd_addr;\n\tvoid *data_addr;\n\tvoid *error_addr;\n\tvoid *feature_addr;\n\tvoid *nsect_addr;\n\tvoid *lbal_addr;\n\tvoid *lbam_addr;\n\tvoid *lbah_addr;\n\tvoid *device_addr;\n\tvoid *status_addr;\n\tvoid *command_addr;\n\tvoid *altstatus_addr;\n\tvoid *ctl_addr;\n\tvoid *bmdma_addr;\n\tvoid *scr_addr;\n};\n\nstruct ata_port_operations;\n\nstruct ata_host {\n\tspinlock_t lock;\n\tstruct device *dev;\n\tvoid * const *iomap;\n\tunsigned int n_ports;\n\tunsigned int n_tags;\n\tvoid *private_data;\n\tstruct ata_port_operations *ops;\n\tlong unsigned int flags;\n\tstruct kref kref;\n\tstruct mutex eh_mutex;\n\tstruct task_struct *eh_owner;\n\tstruct ata_port *simplex_claimed;\n\tstruct ata_port *ports[0];\n};\n\nstruct ata_port_operations {\n\tint (*qc_defer)(struct ata_queued_cmd *);\n\tint (*check_atapi_dma)(struct ata_queued_cmd *);\n\tenum ata_completion_errors (*qc_prep)(struct ata_queued_cmd *);\n\tunsigned int (*qc_issue)(struct ata_queued_cmd *);\n\tbool (*qc_fill_rtf)(struct ata_queued_cmd *);\n\tint (*cable_detect)(struct ata_port *);\n\tlong unsigned int (*mode_filter)(struct ata_device *, long unsigned int);\n\tvoid (*set_piomode)(struct ata_port *, struct ata_device *);\n\tvoid (*set_dmamode)(struct ata_port *, struct ata_device *);\n\tint (*set_mode)(struct ata_link *, struct ata_device **);\n\tunsigned int (*read_id)(struct ata_device *, struct ata_taskfile *, u16 *);\n\tvoid (*dev_config)(struct ata_device *);\n\tvoid (*freeze)(struct ata_port *);\n\tvoid (*thaw)(struct ata_port *);\n\tata_prereset_fn_t prereset;\n\tata_reset_fn_t softreset;\n\tata_reset_fn_t hardreset;\n\tata_postreset_fn_t postreset;\n\tata_prereset_fn_t pmp_prereset;\n\tata_reset_fn_t pmp_softreset;\n\tata_reset_fn_t pmp_hardreset;\n\tata_postreset_fn_t pmp_postreset;\n\tvoid (*error_handler)(struct ata_port *);\n\tvoid (*lost_interrupt)(struct ata_port *);\n\tvoid (*post_internal_cmd)(struct ata_queued_cmd *);\n\tvoid (*sched_eh)(struct ata_port *);\n\tvoid (*end_eh)(struct ata_port *);\n\tint (*scr_read)(struct ata_link *, unsigned int, u32 *);\n\tint (*scr_write)(struct ata_link *, unsigned int, u32);\n\tvoid (*pmp_attach)(struct ata_port *);\n\tvoid (*pmp_detach)(struct ata_port *);\n\tint (*set_lpm)(struct ata_link *, enum ata_lpm_policy, unsigned int);\n\tint (*port_suspend)(struct ata_port *, pm_message_t);\n\tint (*port_resume)(struct ata_port *);\n\tint (*port_start)(struct ata_port *);\n\tvoid (*port_stop)(struct ata_port *);\n\tvoid (*host_stop)(struct ata_host *);\n\tvoid (*sff_dev_select)(struct ata_port *, unsigned int);\n\tvoid (*sff_set_devctl)(struct ata_port *, u8);\n\tu8 (*sff_check_status)(struct ata_port *);\n\tu8 (*sff_check_altstatus)(struct ata_port *);\n\tvoid (*sff_tf_load)(struct ata_port *, const struct ata_taskfile *);\n\tvoid (*sff_tf_read)(struct ata_port *, struct ata_taskfile *);\n\tvoid (*sff_exec_command)(struct ata_port *, const struct ata_taskfile *);\n\tunsigned int (*sff_data_xfer)(struct ata_queued_cmd *, unsigned char *, unsigned int, int);\n\tvoid (*sff_irq_on)(struct ata_port *);\n\tbool (*sff_irq_check)(struct ata_port *);\n\tvoid (*sff_irq_clear)(struct ata_port *);\n\tvoid (*sff_drain_fifo)(struct ata_queued_cmd *);\n\tvoid (*bmdma_setup)(struct ata_queued_cmd *);\n\tvoid (*bmdma_start)(struct ata_queued_cmd *);\n\tvoid (*bmdma_stop)(struct ata_queued_cmd *);\n\tu8 (*bmdma_status)(struct ata_port *);\n\tssize_t (*em_show)(struct ata_port *, char *);\n\tssize_t (*em_store)(struct ata_port *, const char *, size_t);\n\tssize_t (*sw_activity_show)(struct ata_device *, char *);\n\tssize_t (*sw_activity_store)(struct ata_device *, enum sw_activity);\n\tssize_t (*transmit_led_message)(struct ata_port *, u32, ssize_t);\n\tvoid (*phy_reset)(struct ata_port *);\n\tvoid (*eng_timeout)(struct ata_port *);\n\tconst struct ata_port_operations *inherits;\n};\n\nstruct ata_port_stats {\n\tlong unsigned int unhandled_irq;\n\tlong unsigned int idle_irq;\n\tlong unsigned int rw_reqbuf;\n};\n\nstruct ata_acpi_drive {\n\tu32 pio;\n\tu32 dma;\n};\n\nstruct ata_acpi_gtm {\n\tstruct ata_acpi_drive drive[2];\n\tu32 flags;\n};\n\nstruct ata_port {\n\tstruct Scsi_Host *scsi_host;\n\tstruct ata_port_operations *ops;\n\tspinlock_t *lock;\n\tlong unsigned int flags;\n\tunsigned int pflags;\n\tunsigned int print_id;\n\tunsigned int local_port_no;\n\tunsigned int port_no;\n\tstruct ata_ioports ioaddr;\n\tu8 ctl;\n\tu8 last_ctl;\n\tstruct ata_link *sff_pio_task_link;\n\tstruct delayed_work sff_pio_task;\n\tstruct ata_bmdma_prd *bmdma_prd;\n\tdma_addr_t bmdma_prd_dma;\n\tunsigned int pio_mask;\n\tunsigned int mwdma_mask;\n\tunsigned int udma_mask;\n\tunsigned int cbl;\n\tstruct ata_queued_cmd qcmd[33];\n\tlong unsigned int sas_tag_allocated;\n\tu64 qc_active;\n\tint nr_active_links;\n\tunsigned int sas_last_tag;\n\tlong: 64;\n\tstruct ata_link link;\n\tstruct ata_link *slave_link;\n\tint nr_pmp_links;\n\tstruct ata_link *pmp_link;\n\tstruct ata_link *excl_link;\n\tstruct ata_port_stats stats;\n\tstruct ata_host *host;\n\tstruct device *dev;\n\tstruct device tdev;\n\tstruct mutex scsi_scan_mutex;\n\tstruct delayed_work hotplug_task;\n\tstruct work_struct scsi_rescan_task;\n\tunsigned int hsm_task_state;\n\tu32 msg_enable;\n\tstruct list_head eh_done_q;\n\twait_queue_head_t eh_wait_q;\n\tint eh_tries;\n\tstruct completion park_req_pending;\n\tpm_message_t pm_mesg;\n\tenum ata_lpm_policy target_lpm_policy;\n\tstruct timer_list fastdrain_timer;\n\tlong unsigned int fastdrain_cnt;\n\tasync_cookie_t cookie;\n\tint em_message_type;\n\tvoid *private_data;\n\tstruct ata_acpi_gtm __acpi_init_gtm;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu8 sector_buf[512];\n};\n\nstruct ata_port_info {\n\tlong unsigned int flags;\n\tlong unsigned int link_flags;\n\tlong unsigned int pio_mask;\n\tlong unsigned int mwdma_mask;\n\tlong unsigned int udma_mask;\n\tstruct ata_port_operations *port_ops;\n\tvoid *private_data;\n};\n\nstruct ata_timing {\n\tshort unsigned int mode;\n\tshort unsigned int setup;\n\tshort unsigned int act8b;\n\tshort unsigned int rec8b;\n\tshort unsigned int cyc8b;\n\tshort unsigned int active;\n\tshort unsigned int recover;\n\tshort unsigned int dmack_hold;\n\tshort unsigned int cycle;\n\tshort unsigned int udma;\n};\n\nstruct pci_bits {\n\tunsigned int reg;\n\tunsigned int width;\n\tlong unsigned int mask;\n\tlong unsigned int val;\n};\n\nenum ata_link_iter_mode {\n\tATA_LITER_EDGE = 0,\n\tATA_LITER_HOST_FIRST = 1,\n\tATA_LITER_PMP_FIRST = 2,\n};\n\nenum ata_dev_iter_mode {\n\tATA_DITER_ENABLED = 0,\n\tATA_DITER_ENABLED_REVERSE = 1,\n\tATA_DITER_ALL = 2,\n\tATA_DITER_ALL_REVERSE = 3,\n};\n\nstruct trace_event_raw_ata_qc_issue {\n\tstruct trace_entry ent;\n\tunsigned int ata_port;\n\tunsigned int ata_dev;\n\tunsigned int tag;\n\tunsigned char cmd;\n\tunsigned char dev;\n\tunsigned char lbal;\n\tunsigned char lbam;\n\tunsigned char lbah;\n\tunsigned char nsect;\n\tunsigned char feature;\n\tunsigned char hob_lbal;\n\tunsigned char hob_lbam;\n\tunsigned char hob_lbah;\n\tunsigned char hob_nsect;\n\tunsigned char hob_feature;\n\tunsigned char ctl;\n\tunsigned char proto;\n\tlong unsigned int flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_ata_qc_complete_template {\n\tstruct trace_entry ent;\n\tunsigned int ata_port;\n\tunsigned int ata_dev;\n\tunsigned int tag;\n\tunsigned char status;\n\tunsigned char dev;\n\tunsigned char lbal;\n\tunsigned char lbam;\n\tunsigned char lbah;\n\tunsigned char nsect;\n\tunsigned char error;\n\tunsigned char hob_lbal;\n\tunsigned char hob_lbam;\n\tunsigned char hob_lbah;\n\tunsigned char hob_nsect;\n\tunsigned char hob_feature;\n\tunsigned char ctl;\n\tlong unsigned int flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_ata_eh_link_autopsy {\n\tstruct trace_entry ent;\n\tunsigned int ata_port;\n\tunsigned int ata_dev;\n\tunsigned int eh_action;\n\tunsigned int eh_err_mask;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_ata_eh_link_autopsy_qc {\n\tstruct trace_entry ent;\n\tunsigned int ata_port;\n\tunsigned int ata_dev;\n\tunsigned int tag;\n\tunsigned int qc_flags;\n\tunsigned int eh_err_mask;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_ata_qc_issue {};\n\nstruct trace_event_data_offsets_ata_qc_complete_template {};\n\nstruct trace_event_data_offsets_ata_eh_link_autopsy {};\n\nstruct trace_event_data_offsets_ata_eh_link_autopsy_qc {};\n\ntypedef void (*btf_trace_ata_qc_issue)(void *, struct ata_queued_cmd *);\n\ntypedef void (*btf_trace_ata_qc_complete_internal)(void *, struct ata_queued_cmd *);\n\ntypedef void (*btf_trace_ata_qc_complete_failed)(void *, struct ata_queued_cmd *);\n\ntypedef void (*btf_trace_ata_qc_complete_done)(void *, struct ata_queued_cmd *);\n\ntypedef void (*btf_trace_ata_eh_link_autopsy)(void *, struct ata_device *, unsigned int, unsigned int);\n\ntypedef void (*btf_trace_ata_eh_link_autopsy_qc)(void *, struct ata_queued_cmd *);\n\nenum {\n\tATA_READID_POSTRESET = 1,\n\tATA_DNXFER_PIO = 0,\n\tATA_DNXFER_DMA = 1,\n\tATA_DNXFER_40C = 2,\n\tATA_DNXFER_FORCE_PIO = 3,\n\tATA_DNXFER_FORCE_PIO0 = 4,\n\tATA_DNXFER_QUIET = 2147483648,\n};\n\nstruct ata_force_param {\n\tconst char *name;\n\tu8 cbl;\n\tu8 spd_limit;\n\tlong unsigned int xfer_mask;\n\tunsigned int horkage_on;\n\tunsigned int horkage_off;\n\tu16 lflags;\n};\n\nstruct ata_force_ent {\n\tint port;\n\tint device;\n\tstruct ata_force_param param;\n};\n\nstruct ata_xfer_ent {\n\tint shift;\n\tint bits;\n\tu8 base;\n};\n\nstruct ata_blacklist_entry {\n\tconst char *model_num;\n\tconst char *model_rev;\n\tlong unsigned int horkage;\n};\n\ntypedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *);\n\nstruct ata_scsi_args {\n\tstruct ata_device *dev;\n\tu16 *id;\n\tstruct scsi_cmnd *cmd;\n};\n\nenum ata_lpm_hints {\n\tATA_LPM_EMPTY = 1,\n\tATA_LPM_HIPM = 2,\n\tATA_LPM_WAKE_ONLY = 4,\n};\n\nenum {\n\tATA_EH_SPDN_NCQ_OFF = 1,\n\tATA_EH_SPDN_SPEED_DOWN = 2,\n\tATA_EH_SPDN_FALLBACK_TO_PIO = 4,\n\tATA_EH_SPDN_KEEP_ERRORS = 8,\n\tATA_EFLAG_IS_IO = 1,\n\tATA_EFLAG_DUBIOUS_XFER = 2,\n\tATA_EFLAG_OLD_ER = 2147483648,\n\tATA_ECAT_NONE = 0,\n\tATA_ECAT_ATA_BUS = 1,\n\tATA_ECAT_TOUT_HSM = 2,\n\tATA_ECAT_UNK_DEV = 3,\n\tATA_ECAT_DUBIOUS_NONE = 4,\n\tATA_ECAT_DUBIOUS_ATA_BUS = 5,\n\tATA_ECAT_DUBIOUS_TOUT_HSM = 6,\n\tATA_ECAT_DUBIOUS_UNK_DEV = 7,\n\tATA_ECAT_NR = 8,\n\tATA_EH_CMD_DFL_TIMEOUT = 5000,\n\tATA_EH_RESET_COOL_DOWN = 5000,\n\tATA_EH_PRERESET_TIMEOUT = 10000,\n\tATA_EH_FASTDRAIN_INTERVAL = 3000,\n\tATA_EH_UA_TRIES = 5,\n\tATA_EH_PROBE_TRIAL_INTERVAL = 60000,\n\tATA_EH_PROBE_TRIALS = 2,\n};\n\nstruct ata_eh_cmd_timeout_ent {\n\tconst u8 *commands;\n\tconst long unsigned int *timeouts;\n};\n\nstruct speed_down_verdict_arg {\n\tu64 since;\n\tint xfer_ok;\n\tint nr_errors[8];\n};\n\nstruct ata_internal {\n\tstruct scsi_transport_template t;\n\tstruct device_attribute private_port_attrs[3];\n\tstruct device_attribute private_link_attrs[3];\n\tstruct device_attribute private_dev_attrs[9];\n\tstruct transport_container link_attr_cont;\n\tstruct transport_container dev_attr_cont;\n\tstruct device_attribute *link_attrs[4];\n\tstruct device_attribute *port_attrs[4];\n\tstruct device_attribute *dev_attrs[10];\n};\n\nstruct ata_show_ering_arg {\n\tchar *buf;\n\tint written;\n};\n\nenum hsm_task_states {\n\tHSM_ST_IDLE = 0,\n\tHSM_ST_FIRST = 1,\n\tHSM_ST = 2,\n\tHSM_ST_LAST = 3,\n\tHSM_ST_ERR = 4,\n};\n\nstruct ata_acpi_gtf {\n\tu8 tf[7];\n};\n\nstruct ata_acpi_hotplug_context {\n\tstruct acpi_hotplug_context hp;\n\tunion {\n\t\tstruct ata_port *ap;\n\t\tstruct ata_device *dev;\n\t} data;\n};\n\nstruct rm_feature_desc {\n\t__be16 feature_code;\n\t__u8 curr: 1;\n\t__u8 persistent: 1;\n\t__u8 feature_version: 4;\n\t__u8 reserved1: 2;\n\t__u8 add_len;\n\t__u8 lock: 1;\n\t__u8 dbml: 1;\n\t__u8 pvnt_jmpr: 1;\n\t__u8 eject: 1;\n\t__u8 load: 1;\n\t__u8 mech_type: 3;\n\t__u8 reserved2;\n\t__u8 reserved3;\n\t__u8 reserved4;\n};\n\nenum odd_mech_type {\n\tODD_MECH_TYPE_SLOT = 0,\n\tODD_MECH_TYPE_DRAWER = 1,\n\tODD_MECH_TYPE_UNSUPPORTED = 2,\n};\n\nstruct zpodd {\n\tenum odd_mech_type mech_type;\n\tstruct ata_device *dev;\n\tbool from_notify;\n\tbool zp_ready;\n\tlong unsigned int last_ready;\n\tbool zp_sampled;\n\tbool powered_off;\n};\n\nenum {\n\tAHCI_MAX_PORTS = 32,\n\tAHCI_MAX_CLKS = 5,\n\tAHCI_MAX_SG = 168,\n\tAHCI_DMA_BOUNDARY = 4294967295,\n\tAHCI_MAX_CMDS = 32,\n\tAHCI_CMD_SZ = 32,\n\tAHCI_CMD_SLOT_SZ = 1024,\n\tAHCI_RX_FIS_SZ = 256,\n\tAHCI_CMD_TBL_CDB = 64,\n\tAHCI_CMD_TBL_HDR_SZ = 128,\n\tAHCI_CMD_TBL_SZ = 2816,\n\tAHCI_CMD_TBL_AR_SZ = 90112,\n\tAHCI_PORT_PRIV_DMA_SZ = 91392,\n\tAHCI_PORT_PRIV_FBS_DMA_SZ = 95232,\n\tAHCI_IRQ_ON_SG = 2147483648,\n\tAHCI_CMD_ATAPI = 32,\n\tAHCI_CMD_WRITE = 64,\n\tAHCI_CMD_PREFETCH = 128,\n\tAHCI_CMD_RESET = 256,\n\tAHCI_CMD_CLR_BUSY = 1024,\n\tRX_FIS_PIO_SETUP = 32,\n\tRX_FIS_D2H_REG = 64,\n\tRX_FIS_SDB = 88,\n\tRX_FIS_UNK = 96,\n\tHOST_CAP = 0,\n\tHOST_CTL = 4,\n\tHOST_IRQ_STAT = 8,\n\tHOST_PORTS_IMPL = 12,\n\tHOST_VERSION = 16,\n\tHOST_EM_LOC = 28,\n\tHOST_EM_CTL = 32,\n\tHOST_CAP2 = 36,\n\tHOST_RESET = 1,\n\tHOST_IRQ_EN = 2,\n\tHOST_MRSM = 4,\n\tHOST_AHCI_EN = 2147483648,\n\tHOST_CAP_SXS = 32,\n\tHOST_CAP_EMS = 64,\n\tHOST_CAP_CCC = 128,\n\tHOST_CAP_PART = 8192,\n\tHOST_CAP_SSC = 16384,\n\tHOST_CAP_PIO_MULTI = 32768,\n\tHOST_CAP_FBS = 65536,\n\tHOST_CAP_PMP = 131072,\n\tHOST_CAP_ONLY = 262144,\n\tHOST_CAP_CLO = 16777216,\n\tHOST_CAP_LED = 33554432,\n\tHOST_CAP_ALPM = 67108864,\n\tHOST_CAP_SSS = 134217728,\n\tHOST_CAP_MPS = 268435456,\n\tHOST_CAP_SNTF = 536870912,\n\tHOST_CAP_NCQ = 1073741824,\n\tHOST_CAP_64 = 2147483648,\n\tHOST_CAP2_BOH = 1,\n\tHOST_CAP2_NVMHCI = 2,\n\tHOST_CAP2_APST = 4,\n\tHOST_CAP2_SDS = 8,\n\tHOST_CAP2_SADM = 16,\n\tHOST_CAP2_DESO = 32,\n\tPORT_LST_ADDR = 0,\n\tPORT_LST_ADDR_HI = 4,\n\tPORT_FIS_ADDR = 8,\n\tPORT_FIS_ADDR_HI = 12,\n\tPORT_IRQ_STAT = 16,\n\tPORT_IRQ_MASK = 20,\n\tPORT_CMD = 24,\n\tPORT_TFDATA = 32,\n\tPORT_SIG = 36,\n\tPORT_CMD_ISSUE = 56,\n\tPORT_SCR_STAT = 40,\n\tPORT_SCR_CTL = 44,\n\tPORT_SCR_ERR = 48,\n\tPORT_SCR_ACT = 52,\n\tPORT_SCR_NTF = 60,\n\tPORT_FBS = 64,\n\tPORT_DEVSLP = 68,\n\tPORT_IRQ_COLD_PRES = 2147483648,\n\tPORT_IRQ_TF_ERR = 1073741824,\n\tPORT_IRQ_HBUS_ERR = 536870912,\n\tPORT_IRQ_HBUS_DATA_ERR = 268435456,\n\tPORT_IRQ_IF_ERR = 134217728,\n\tPORT_IRQ_IF_NONFATAL = 67108864,\n\tPORT_IRQ_OVERFLOW = 16777216,\n\tPORT_IRQ_BAD_PMP = 8388608,\n\tPORT_IRQ_PHYRDY = 4194304,\n\tPORT_IRQ_DEV_ILCK = 128,\n\tPORT_IRQ_CONNECT = 64,\n\tPORT_IRQ_SG_DONE = 32,\n\tPORT_IRQ_UNK_FIS = 16,\n\tPORT_IRQ_SDB_FIS = 8,\n\tPORT_IRQ_DMAS_FIS = 4,\n\tPORT_IRQ_PIOS_FIS = 2,\n\tPORT_IRQ_D2H_REG_FIS = 1,\n\tPORT_IRQ_FREEZE = 683671632,\n\tPORT_IRQ_ERROR = 2025848912,\n\tDEF_PORT_IRQ = 2025848959,\n\tPORT_CMD_ASP = 134217728,\n\tPORT_CMD_ALPE = 67108864,\n\tPORT_CMD_ATAPI = 16777216,\n\tPORT_CMD_FBSCP = 4194304,\n\tPORT_CMD_ESP = 2097152,\n\tPORT_CMD_HPCP = 262144,\n\tPORT_CMD_PMP = 131072,\n\tPORT_CMD_LIST_ON = 32768,\n\tPORT_CMD_FIS_ON = 16384,\n\tPORT_CMD_FIS_RX = 16,\n\tPORT_CMD_CLO = 8,\n\tPORT_CMD_POWER_ON = 4,\n\tPORT_CMD_SPIN_UP = 2,\n\tPORT_CMD_START = 1,\n\tPORT_CMD_ICC_MASK = 4026531840,\n\tPORT_CMD_ICC_ACTIVE = 268435456,\n\tPORT_CMD_ICC_PARTIAL = 536870912,\n\tPORT_CMD_ICC_SLUMBER = 1610612736,\n\tPORT_FBS_DWE_OFFSET = 16,\n\tPORT_FBS_ADO_OFFSET = 12,\n\tPORT_FBS_DEV_OFFSET = 8,\n\tPORT_FBS_DEV_MASK = 3840,\n\tPORT_FBS_SDE = 4,\n\tPORT_FBS_DEC = 2,\n\tPORT_FBS_EN = 1,\n\tPORT_DEVSLP_DM_OFFSET = 25,\n\tPORT_DEVSLP_DM_MASK = 503316480,\n\tPORT_DEVSLP_DITO_OFFSET = 15,\n\tPORT_DEVSLP_MDAT_OFFSET = 10,\n\tPORT_DEVSLP_DETO_OFFSET = 2,\n\tPORT_DEVSLP_DSP = 2,\n\tPORT_DEVSLP_ADSE = 1,\n\tAHCI_HFLAG_NO_NCQ = 1,\n\tAHCI_HFLAG_IGN_IRQ_IF_ERR = 2,\n\tAHCI_HFLAG_IGN_SERR_INTERNAL = 4,\n\tAHCI_HFLAG_32BIT_ONLY = 8,\n\tAHCI_HFLAG_MV_PATA = 16,\n\tAHCI_HFLAG_NO_MSI = 32,\n\tAHCI_HFLAG_NO_PMP = 64,\n\tAHCI_HFLAG_SECT255 = 256,\n\tAHCI_HFLAG_YES_NCQ = 512,\n\tAHCI_HFLAG_NO_SUSPEND = 1024,\n\tAHCI_HFLAG_SRST_TOUT_IS_OFFLINE = 2048,\n\tAHCI_HFLAG_NO_SNTF = 4096,\n\tAHCI_HFLAG_NO_FPDMA_AA = 8192,\n\tAHCI_HFLAG_YES_FBS = 16384,\n\tAHCI_HFLAG_DELAY_ENGINE = 32768,\n\tAHCI_HFLAG_NO_DEVSLP = 131072,\n\tAHCI_HFLAG_NO_FBS = 262144,\n\tAHCI_HFLAG_MULTI_MSI = 1048576,\n\tAHCI_HFLAG_WAKE_BEFORE_STOP = 4194304,\n\tAHCI_HFLAG_YES_ALPM = 8388608,\n\tAHCI_HFLAG_NO_WRITE_TO_RO = 16777216,\n\tAHCI_HFLAG_IS_MOBILE = 33554432,\n\tAHCI_HFLAG_SUSPEND_PHYS = 67108864,\n\tAHCI_HFLAG_IGN_NOTSUPP_POWER_ON = 134217728,\n\tAHCI_HFLAG_NO_SXS = 268435456,\n\tAHCI_FLAG_COMMON = 393346,\n\tICH_MAP = 144,\n\tPCS_6 = 146,\n\tPCS_7 = 148,\n\tEM_MAX_SLOTS = 8,\n\tEM_MAX_RETRY = 5,\n\tEM_CTL_RST = 512,\n\tEM_CTL_TM = 256,\n\tEM_CTL_MR = 1,\n\tEM_CTL_ALHD = 67108864,\n\tEM_CTL_XMT = 33554432,\n\tEM_CTL_SMB = 16777216,\n\tEM_CTL_SGPIO = 524288,\n\tEM_CTL_SES = 262144,\n\tEM_CTL_SAFTE = 131072,\n\tEM_CTL_LED = 65536,\n\tEM_MSG_TYPE_LED = 1,\n\tEM_MSG_TYPE_SAFTE = 2,\n\tEM_MSG_TYPE_SES2 = 4,\n\tEM_MSG_TYPE_SGPIO = 8,\n};\n\nstruct ahci_cmd_hdr {\n\t__le32 opts;\n\t__le32 status;\n\t__le32 tbl_addr;\n\t__le32 tbl_addr_hi;\n\t__le32 reserved[4];\n};\n\nstruct ahci_em_priv {\n\tenum sw_activity blink_policy;\n\tstruct timer_list timer;\n\tlong unsigned int saved_activity;\n\tlong unsigned int activity;\n\tlong unsigned int led_state;\n\tstruct ata_link *link;\n};\n\nstruct ahci_port_priv {\n\tstruct ata_link *active_link;\n\tstruct ahci_cmd_hdr *cmd_slot;\n\tdma_addr_t cmd_slot_dma;\n\tvoid *cmd_tbl;\n\tdma_addr_t cmd_tbl_dma;\n\tvoid *rx_fis;\n\tdma_addr_t rx_fis_dma;\n\tunsigned int ncq_saw_d2h: 1;\n\tunsigned int ncq_saw_dmas: 1;\n\tunsigned int ncq_saw_sdb: 1;\n\tspinlock_t lock;\n\tu32 intr_mask;\n\tbool fbs_supported;\n\tbool fbs_enabled;\n\tint fbs_last_dev;\n\tstruct ahci_em_priv em_priv[8];\n\tchar *irq_desc;\n};\n\nstruct ahci_host_priv {\n\tunsigned int flags;\n\tu32 force_port_map;\n\tu32 mask_port_map;\n\tvoid *mmio;\n\tu32 cap;\n\tu32 cap2;\n\tu32 version;\n\tu32 port_map;\n\tu32 saved_cap;\n\tu32 saved_cap2;\n\tu32 saved_port_map;\n\tu32 em_loc;\n\tu32 em_buf_sz;\n\tu32 em_msg_type;\n\tu32 remapped_nvme;\n\tbool got_runtime_pm;\n\tstruct clk *clks[5];\n\tstruct reset_control *rsts;\n\tstruct regulator **target_pwrs;\n\tstruct regulator *ahci_regulator;\n\tstruct regulator *phy_regulator;\n\tstruct phy **phys;\n\tunsigned int nports;\n\tvoid *plat_data;\n\tunsigned int irq;\n\tvoid (*start_engine)(struct ata_port *);\n\tint (*stop_engine)(struct ata_port *);\n\tirqreturn_t (*irq_handler)(int, void *);\n\tint (*get_irq_vector)(struct ata_host *, int);\n};\n\nenum {\n\tAHCI_PCI_BAR_STA2X11 = 0,\n\tAHCI_PCI_BAR_CAVIUM = 0,\n\tAHCI_PCI_BAR_LOONGSON = 0,\n\tAHCI_PCI_BAR_ENMOTUS = 2,\n\tAHCI_PCI_BAR_CAVIUM_GEN5 = 4,\n\tAHCI_PCI_BAR_STANDARD = 5,\n};\n\nenum board_ids {\n\tboard_ahci = 0,\n\tboard_ahci_ign_iferr = 1,\n\tboard_ahci_mobile = 2,\n\tboard_ahci_nomsi = 3,\n\tboard_ahci_noncq = 4,\n\tboard_ahci_nosntf = 5,\n\tboard_ahci_yes_fbs = 6,\n\tboard_ahci_al = 7,\n\tboard_ahci_avn = 8,\n\tboard_ahci_mcp65 = 9,\n\tboard_ahci_mcp77 = 10,\n\tboard_ahci_mcp89 = 11,\n\tboard_ahci_mv = 12,\n\tboard_ahci_sb600 = 13,\n\tboard_ahci_sb700 = 14,\n\tboard_ahci_vt8251 = 15,\n\tboard_ahci_pcs7 = 16,\n\tboard_ahci_mcp_linux = 9,\n\tboard_ahci_mcp67 = 9,\n\tboard_ahci_mcp73 = 9,\n\tboard_ahci_mcp79 = 10,\n};\n\nstruct ahci_sg {\n\t__le32 addr;\n\t__le32 addr_hi;\n\t__le32 reserved;\n\t__le32 flags_size;\n};\n\ntypedef void (*spi_res_release_t)(struct spi_controller *, struct spi_message *, void *);\n\nstruct spi_res {\n\tstruct list_head entry;\n\tspi_res_release_t release;\n\tlong long unsigned int data[0];\n};\n\nstruct spi_replaced_transfers;\n\ntypedef void (*spi_replaced_release_t)(struct spi_controller *, struct spi_message *, struct spi_replaced_transfers *);\n\nstruct spi_replaced_transfers {\n\tspi_replaced_release_t release;\n\tvoid *extradata;\n\tstruct list_head replaced_transfers;\n\tstruct list_head *replaced_after;\n\tsize_t inserted;\n\tstruct spi_transfer inserted_transfers[0];\n};\n\nstruct spi_board_info {\n\tchar modalias[32];\n\tconst void *platform_data;\n\tconst struct software_node *swnode;\n\tvoid *controller_data;\n\tint irq;\n\tu32 max_speed_hz;\n\tu16 bus_num;\n\tu16 chip_select;\n\tu32 mode;\n};\n\nenum spi_mem_data_dir {\n\tSPI_MEM_NO_DATA = 0,\n\tSPI_MEM_DATA_IN = 1,\n\tSPI_MEM_DATA_OUT = 2,\n};\n\nstruct spi_mem_op {\n\tstruct {\n\t\tu8 nbytes;\n\t\tu8 buswidth;\n\t\tu8 dtr: 1;\n\t\tu16 opcode;\n\t} cmd;\n\tstruct {\n\t\tu8 nbytes;\n\t\tu8 buswidth;\n\t\tu8 dtr: 1;\n\t\tu64 val;\n\t} addr;\n\tstruct {\n\t\tu8 nbytes;\n\t\tu8 buswidth;\n\t\tu8 dtr: 1;\n\t} dummy;\n\tstruct {\n\t\tu8 buswidth;\n\t\tu8 dtr: 1;\n\t\tenum spi_mem_data_dir dir;\n\t\tunsigned int nbytes;\n\t\tunion {\n\t\t\tvoid *in;\n\t\t\tconst void *out;\n\t\t} buf;\n\t} data;\n};\n\nstruct spi_mem_dirmap_info {\n\tstruct spi_mem_op op_tmpl;\n\tu64 offset;\n\tu64 length;\n};\n\nstruct spi_mem_dirmap_desc {\n\tstruct spi_mem *mem;\n\tstruct spi_mem_dirmap_info info;\n\tunsigned int nodirmap;\n\tvoid *priv;\n};\n\nstruct spi_mem {\n\tstruct spi_device *spi;\n\tvoid *drvpriv;\n\tconst char *name;\n};\n\nstruct trace_event_raw_spi_controller {\n\tstruct trace_entry ent;\n\tint bus_num;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_spi_setup {\n\tstruct trace_entry ent;\n\tint bus_num;\n\tint chip_select;\n\tlong unsigned int mode;\n\tunsigned int bits_per_word;\n\tunsigned int max_speed_hz;\n\tint status;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_spi_set_cs {\n\tstruct trace_entry ent;\n\tint bus_num;\n\tint chip_select;\n\tlong unsigned int mode;\n\tbool enable;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_spi_message {\n\tstruct trace_entry ent;\n\tint bus_num;\n\tint chip_select;\n\tstruct spi_message *msg;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_spi_message_done {\n\tstruct trace_entry ent;\n\tint bus_num;\n\tint chip_select;\n\tstruct spi_message *msg;\n\tunsigned int frame;\n\tunsigned int actual;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_spi_transfer {\n\tstruct trace_entry ent;\n\tint bus_num;\n\tint chip_select;\n\tstruct spi_transfer *xfer;\n\tint len;\n\tu32 __data_loc_rx_buf;\n\tu32 __data_loc_tx_buf;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_spi_controller {};\n\nstruct trace_event_data_offsets_spi_setup {};\n\nstruct trace_event_data_offsets_spi_set_cs {};\n\nstruct trace_event_data_offsets_spi_message {};\n\nstruct trace_event_data_offsets_spi_message_done {};\n\nstruct trace_event_data_offsets_spi_transfer {\n\tu32 rx_buf;\n\tu32 tx_buf;\n};\n\ntypedef void (*btf_trace_spi_controller_idle)(void *, struct spi_controller *);\n\ntypedef void (*btf_trace_spi_controller_busy)(void *, struct spi_controller *);\n\ntypedef void (*btf_trace_spi_setup)(void *, struct spi_device *, int);\n\ntypedef void (*btf_trace_spi_set_cs)(void *, struct spi_device *, bool);\n\ntypedef void (*btf_trace_spi_message_submit)(void *, struct spi_message *);\n\ntypedef void (*btf_trace_spi_message_start)(void *, struct spi_message *);\n\ntypedef void (*btf_trace_spi_message_done)(void *, struct spi_message *);\n\ntypedef void (*btf_trace_spi_transfer_start)(void *, struct spi_message *, struct spi_transfer *);\n\ntypedef void (*btf_trace_spi_transfer_stop)(void *, struct spi_message *, struct spi_transfer *);\n\nstruct boardinfo {\n\tstruct list_head list;\n\tstruct spi_board_info board_info;\n};\n\nstruct acpi_spi_lookup {\n\tstruct spi_controller *ctlr;\n\tu32 max_speed_hz;\n\tu32 mode;\n\tint irq;\n\tu8 bits_per_word;\n\tu8 chip_select;\n};\n\nstruct spi_mem_driver {\n\tstruct spi_driver spidrv;\n\tint (*probe)(struct spi_mem *);\n\tint (*remove)(struct spi_mem *);\n\tvoid (*shutdown)(struct spi_mem *);\n};\n\nstruct devprobe2 {\n\tstruct net_device * (*probe)(int);\n\tint status;\n};\n\nenum {\n\tNETIF_F_SG_BIT = 0,\n\tNETIF_F_IP_CSUM_BIT = 1,\n\t__UNUSED_NETIF_F_1 = 2,\n\tNETIF_F_HW_CSUM_BIT = 3,\n\tNETIF_F_IPV6_CSUM_BIT = 4,\n\tNETIF_F_HIGHDMA_BIT = 5,\n\tNETIF_F_FRAGLIST_BIT = 6,\n\tNETIF_F_HW_VLAN_CTAG_TX_BIT = 7,\n\tNETIF_F_HW_VLAN_CTAG_RX_BIT = 8,\n\tNETIF_F_HW_VLAN_CTAG_FILTER_BIT = 9,\n\tNETIF_F_VLAN_CHALLENGED_BIT = 10,\n\tNETIF_F_GSO_BIT = 11,\n\tNETIF_F_LLTX_BIT = 12,\n\tNETIF_F_NETNS_LOCAL_BIT = 13,\n\tNETIF_F_GRO_BIT = 14,\n\tNETIF_F_LRO_BIT = 15,\n\tNETIF_F_GSO_SHIFT = 16,\n\tNETIF_F_TSO_BIT = 16,\n\tNETIF_F_GSO_ROBUST_BIT = 17,\n\tNETIF_F_TSO_ECN_BIT = 18,\n\tNETIF_F_TSO_MANGLEID_BIT = 19,\n\tNETIF_F_TSO6_BIT = 20,\n\tNETIF_F_FSO_BIT = 21,\n\tNETIF_F_GSO_GRE_BIT = 22,\n\tNETIF_F_GSO_GRE_CSUM_BIT = 23,\n\tNETIF_F_GSO_IPXIP4_BIT = 24,\n\tNETIF_F_GSO_IPXIP6_BIT = 25,\n\tNETIF_F_GSO_UDP_TUNNEL_BIT = 26,\n\tNETIF_F_GSO_UDP_TUNNEL_CSUM_BIT = 27,\n\tNETIF_F_GSO_PARTIAL_BIT = 28,\n\tNETIF_F_GSO_TUNNEL_REMCSUM_BIT = 29,\n\tNETIF_F_GSO_SCTP_BIT = 30,\n\tNETIF_F_GSO_ESP_BIT = 31,\n\tNETIF_F_GSO_UDP_BIT = 32,\n\tNETIF_F_GSO_UDP_L4_BIT = 33,\n\tNETIF_F_GSO_FRAGLIST_BIT = 34,\n\tNETIF_F_GSO_LAST = 34,\n\tNETIF_F_FCOE_CRC_BIT = 35,\n\tNETIF_F_SCTP_CRC_BIT = 36,\n\tNETIF_F_FCOE_MTU_BIT = 37,\n\tNETIF_F_NTUPLE_BIT = 38,\n\tNETIF_F_RXHASH_BIT = 39,\n\tNETIF_F_RXCSUM_BIT = 40,\n\tNETIF_F_NOCACHE_COPY_BIT = 41,\n\tNETIF_F_LOOPBACK_BIT = 42,\n\tNETIF_F_RXFCS_BIT = 43,\n\tNETIF_F_RXALL_BIT = 44,\n\tNETIF_F_HW_VLAN_STAG_TX_BIT = 45,\n\tNETIF_F_HW_VLAN_STAG_RX_BIT = 46,\n\tNETIF_F_HW_VLAN_STAG_FILTER_BIT = 47,\n\tNETIF_F_HW_L2FW_DOFFLOAD_BIT = 48,\n\tNETIF_F_HW_TC_BIT = 49,\n\tNETIF_F_HW_ESP_BIT = 50,\n\tNETIF_F_HW_ESP_TX_CSUM_BIT = 51,\n\tNETIF_F_RX_UDP_TUNNEL_PORT_BIT = 52,\n\tNETIF_F_HW_TLS_TX_BIT = 53,\n\tNETIF_F_HW_TLS_RX_BIT = 54,\n\tNETIF_F_GRO_HW_BIT = 55,\n\tNETIF_F_HW_TLS_RECORD_BIT = 56,\n\tNETIF_F_GRO_FRAGLIST_BIT = 57,\n\tNETIF_F_HW_MACSEC_BIT = 58,\n\tNETIF_F_GRO_UDP_FWD_BIT = 59,\n\tNETIF_F_HW_HSR_TAG_INS_BIT = 60,\n\tNETIF_F_HW_HSR_TAG_RM_BIT = 61,\n\tNETIF_F_HW_HSR_FWD_BIT = 62,\n\tNETIF_F_HW_HSR_DUP_BIT = 63,\n\tNETDEV_FEATURE_COUNT = 64,\n};\n\ntypedef struct bio_vec skb_frag_t;\n\nstruct skb_shared_hwtstamps {\n\tktime_t hwtstamp;\n};\n\nenum {\n\tSKBTX_HW_TSTAMP = 1,\n\tSKBTX_SW_TSTAMP = 2,\n\tSKBTX_IN_PROGRESS = 4,\n\tSKBTX_WIFI_STATUS = 16,\n\tSKBTX_SCHED_TSTAMP = 64,\n};\n\nstruct skb_shared_info {\n\t__u8 flags;\n\t__u8 meta_len;\n\t__u8 nr_frags;\n\t__u8 tx_flags;\n\tshort unsigned int gso_size;\n\tshort unsigned int gso_segs;\n\tstruct sk_buff *frag_list;\n\tstruct skb_shared_hwtstamps hwtstamps;\n\tunsigned int gso_type;\n\tu32 tskey;\n\tatomic_t dataref;\n\tvoid *destructor_arg;\n\tskb_frag_t frags[17];\n};\n\nenum netdev_priv_flags {\n\tIFF_802_1Q_VLAN = 1,\n\tIFF_EBRIDGE = 2,\n\tIFF_BONDING = 4,\n\tIFF_ISATAP = 8,\n\tIFF_WAN_HDLC = 16,\n\tIFF_XMIT_DST_RELEASE = 32,\n\tIFF_DONT_BRIDGE = 64,\n\tIFF_DISABLE_NETPOLL = 128,\n\tIFF_MACVLAN_PORT = 256,\n\tIFF_BRIDGE_PORT = 512,\n\tIFF_OVS_DATAPATH = 1024,\n\tIFF_TX_SKB_SHARING = 2048,\n\tIFF_UNICAST_FLT = 4096,\n\tIFF_TEAM_PORT = 8192,\n\tIFF_SUPP_NOFCS = 16384,\n\tIFF_LIVE_ADDR_CHANGE = 32768,\n\tIFF_MACVLAN = 65536,\n\tIFF_XMIT_DST_RELEASE_PERM = 131072,\n\tIFF_L3MDEV_MASTER = 262144,\n\tIFF_NO_QUEUE = 524288,\n\tIFF_OPENVSWITCH = 1048576,\n\tIFF_L3MDEV_SLAVE = 2097152,\n\tIFF_TEAM = 4194304,\n\tIFF_RXFH_CONFIGURED = 8388608,\n\tIFF_PHONY_HEADROOM = 16777216,\n\tIFF_MACSEC = 33554432,\n\tIFF_NO_RX_HANDLER = 67108864,\n\tIFF_FAILOVER = 134217728,\n\tIFF_FAILOVER_SLAVE = 268435456,\n\tIFF_L3MDEV_RX_HANDLER = 536870912,\n\tIFF_LIVE_RENAME_OK = 1073741824,\n\tIFF_TX_SKB_NO_LINEAR = 2147483648,\n};\n\nstruct mdio_board_info {\n\tconst char *bus_id;\n\tchar modalias[32];\n\tint mdio_addr;\n\tconst void *platform_data;\n};\n\nstruct mdio_board_entry {\n\tstruct list_head list;\n\tstruct mdio_board_info board_info;\n};\n\nstruct mii_timestamping_ctrl {\n\tstruct mii_timestamper * (*probe_channel)(struct device *, unsigned int);\n\tvoid (*release_channel)(struct device *, struct mii_timestamper *);\n};\n\nstruct mii_timestamping_desc {\n\tstruct list_head list;\n\tstruct mii_timestamping_ctrl *ctrl;\n\tstruct device *device;\n};\n\nstruct sfp;\n\nstruct sfp_socket_ops;\n\nstruct sfp_quirk;\n\nstruct sfp_upstream_ops;\n\nstruct sfp_bus {\n\tstruct kref kref;\n\tstruct list_head node;\n\tstruct fwnode_handle *fwnode;\n\tconst struct sfp_socket_ops *socket_ops;\n\tstruct device *sfp_dev;\n\tstruct sfp *sfp;\n\tconst struct sfp_quirk *sfp_quirk;\n\tconst struct sfp_upstream_ops *upstream_ops;\n\tvoid *upstream;\n\tstruct phy_device *phydev;\n\tbool registered;\n\tbool started;\n};\n\nstruct sfp_eeprom_base {\n\tu8 phys_id;\n\tu8 phys_ext_id;\n\tu8 connector;\n\tu8 if_1x_copper_passive: 1;\n\tu8 if_1x_copper_active: 1;\n\tu8 if_1x_lx: 1;\n\tu8 if_1x_sx: 1;\n\tu8 e10g_base_sr: 1;\n\tu8 e10g_base_lr: 1;\n\tu8 e10g_base_lrm: 1;\n\tu8 e10g_base_er: 1;\n\tu8 sonet_oc3_short_reach: 1;\n\tu8 sonet_oc3_smf_intermediate_reach: 1;\n\tu8 sonet_oc3_smf_long_reach: 1;\n\tu8 unallocated_5_3: 1;\n\tu8 sonet_oc12_short_reach: 1;\n\tu8 sonet_oc12_smf_intermediate_reach: 1;\n\tu8 sonet_oc12_smf_long_reach: 1;\n\tu8 unallocated_5_7: 1;\n\tu8 sonet_oc48_short_reach: 1;\n\tu8 sonet_oc48_intermediate_reach: 1;\n\tu8 sonet_oc48_long_reach: 1;\n\tu8 sonet_reach_bit2: 1;\n\tu8 sonet_reach_bit1: 1;\n\tu8 sonet_oc192_short_reach: 1;\n\tu8 escon_smf_1310_laser: 1;\n\tu8 escon_mmf_1310_led: 1;\n\tu8 e1000_base_sx: 1;\n\tu8 e1000_base_lx: 1;\n\tu8 e1000_base_cx: 1;\n\tu8 e1000_base_t: 1;\n\tu8 e100_base_lx: 1;\n\tu8 e100_base_fx: 1;\n\tu8 e_base_bx10: 1;\n\tu8 e_base_px: 1;\n\tu8 fc_tech_electrical_inter_enclosure: 1;\n\tu8 fc_tech_lc: 1;\n\tu8 fc_tech_sa: 1;\n\tu8 fc_ll_m: 1;\n\tu8 fc_ll_l: 1;\n\tu8 fc_ll_i: 1;\n\tu8 fc_ll_s: 1;\n\tu8 fc_ll_v: 1;\n\tu8 unallocated_8_0: 1;\n\tu8 unallocated_8_1: 1;\n\tu8 sfp_ct_passive: 1;\n\tu8 sfp_ct_active: 1;\n\tu8 fc_tech_ll: 1;\n\tu8 fc_tech_sl: 1;\n\tu8 fc_tech_sn: 1;\n\tu8 fc_tech_electrical_intra_enclosure: 1;\n\tu8 fc_media_sm: 1;\n\tu8 unallocated_9_1: 1;\n\tu8 fc_media_m5: 1;\n\tu8 fc_media_m6: 1;\n\tu8 fc_media_tv: 1;\n\tu8 fc_media_mi: 1;\n\tu8 fc_media_tp: 1;\n\tu8 fc_media_tw: 1;\n\tu8 fc_speed_100: 1;\n\tu8 unallocated_10_1: 1;\n\tu8 fc_speed_200: 1;\n\tu8 fc_speed_3200: 1;\n\tu8 fc_speed_400: 1;\n\tu8 fc_speed_1600: 1;\n\tu8 fc_speed_800: 1;\n\tu8 fc_speed_1200: 1;\n\tu8 encoding;\n\tu8 br_nominal;\n\tu8 rate_id;\n\tu8 link_len[6];\n\tchar vendor_name[16];\n\tu8 extended_cc;\n\tchar vendor_oui[3];\n\tchar vendor_pn[16];\n\tchar vendor_rev[4];\n\tunion {\n\t\t__be16 optical_wavelength;\n\t\t__be16 cable_compliance;\n\t\tstruct {\n\t\t\tu8 sff8431_app_e: 1;\n\t\t\tu8 fc_pi_4_app_h: 1;\n\t\t\tu8 reserved60_2: 6;\n\t\t\tu8 reserved61: 8;\n\t\t} passive;\n\t\tstruct {\n\t\t\tu8 sff8431_app_e: 1;\n\t\t\tu8 fc_pi_4_app_h: 1;\n\t\t\tu8 sff8431_lim: 1;\n\t\t\tu8 fc_pi_4_lim: 1;\n\t\t\tu8 reserved60_4: 4;\n\t\t\tu8 reserved61: 8;\n\t\t} active;\n\t};\n\tu8 reserved62;\n\tu8 cc_base;\n};\n\nstruct sfp_eeprom_ext {\n\t__be16 options;\n\tu8 br_max;\n\tu8 br_min;\n\tchar vendor_sn[16];\n\tchar datecode[8];\n\tu8 diagmon;\n\tu8 enhopts;\n\tu8 sff8472_compliance;\n\tu8 cc_ext;\n};\n\nstruct sfp_eeprom_id {\n\tstruct sfp_eeprom_base base;\n\tstruct sfp_eeprom_ext ext;\n};\n\nenum {\n\tSFF8024_ID_UNK = 0,\n\tSFF8024_ID_SFF_8472 = 2,\n\tSFF8024_ID_SFP = 3,\n\tSFF8024_ID_DWDM_SFP = 11,\n\tSFF8024_ID_QSFP_8438 = 12,\n\tSFF8024_ID_QSFP_8436_8636 = 13,\n\tSFF8024_ID_QSFP28_8636 = 17,\n\tSFF8024_ENCODING_UNSPEC = 0,\n\tSFF8024_ENCODING_8B10B = 1,\n\tSFF8024_ENCODING_4B5B = 2,\n\tSFF8024_ENCODING_NRZ = 3,\n\tSFF8024_ENCODING_8472_MANCHESTER = 4,\n\tSFF8024_ENCODING_8472_SONET = 5,\n\tSFF8024_ENCODING_8472_64B66B = 6,\n\tSFF8024_ENCODING_8436_MANCHESTER = 6,\n\tSFF8024_ENCODING_8436_SONET = 4,\n\tSFF8024_ENCODING_8436_64B66B = 5,\n\tSFF8024_ENCODING_256B257B = 7,\n\tSFF8024_ENCODING_PAM4 = 8,\n\tSFF8024_CONNECTOR_UNSPEC = 0,\n\tSFF8024_CONNECTOR_SC = 1,\n\tSFF8024_CONNECTOR_FIBERJACK = 6,\n\tSFF8024_CONNECTOR_LC = 7,\n\tSFF8024_CONNECTOR_MT_RJ = 8,\n\tSFF8024_CONNECTOR_MU = 9,\n\tSFF8024_CONNECTOR_SG = 10,\n\tSFF8024_CONNECTOR_OPTICAL_PIGTAIL = 11,\n\tSFF8024_CONNECTOR_MPO_1X12 = 12,\n\tSFF8024_CONNECTOR_MPO_2X16 = 13,\n\tSFF8024_CONNECTOR_HSSDC_II = 32,\n\tSFF8024_CONNECTOR_COPPER_PIGTAIL = 33,\n\tSFF8024_CONNECTOR_RJ45 = 34,\n\tSFF8024_CONNECTOR_NOSEPARATE = 35,\n\tSFF8024_CONNECTOR_MXC_2X16 = 36,\n\tSFF8024_ECC_UNSPEC = 0,\n\tSFF8024_ECC_100G_25GAUI_C2M_AOC = 1,\n\tSFF8024_ECC_100GBASE_SR4_25GBASE_SR = 2,\n\tSFF8024_ECC_100GBASE_LR4_25GBASE_LR = 3,\n\tSFF8024_ECC_100GBASE_ER4_25GBASE_ER = 4,\n\tSFF8024_ECC_100GBASE_SR10 = 5,\n\tSFF8024_ECC_100GBASE_CR4 = 11,\n\tSFF8024_ECC_25GBASE_CR_S = 12,\n\tSFF8024_ECC_25GBASE_CR_N = 13,\n\tSFF8024_ECC_10GBASE_T_SFI = 22,\n\tSFF8024_ECC_10GBASE_T_SR = 28,\n\tSFF8024_ECC_5GBASE_T = 29,\n\tSFF8024_ECC_2_5GBASE_T = 30,\n};\n\nstruct sfp_upstream_ops {\n\tvoid (*attach)(void *, struct sfp_bus *);\n\tvoid (*detach)(void *, struct sfp_bus *);\n\tint (*module_insert)(void *, const struct sfp_eeprom_id *);\n\tvoid (*module_remove)(void *);\n\tint (*module_start)(void *);\n\tvoid (*module_stop)(void *);\n\tvoid (*link_down)(void *);\n\tvoid (*link_up)(void *);\n\tint (*connect_phy)(void *, struct phy_device *);\n\tvoid (*disconnect_phy)(void *);\n};\n\nstruct sfp_socket_ops {\n\tvoid (*attach)(struct sfp *);\n\tvoid (*detach)(struct sfp *);\n\tvoid (*start)(struct sfp *);\n\tvoid (*stop)(struct sfp *);\n\tint (*module_info)(struct sfp *, struct ethtool_modinfo *);\n\tint (*module_eeprom)(struct sfp *, struct ethtool_eeprom *, u8 *);\n\tint (*module_eeprom_by_page)(struct sfp *, const struct ethtool_module_eeprom *, struct netlink_ext_ack *);\n};\n\nstruct sfp_quirk {\n\tconst char *vendor;\n\tconst char *part;\n\tvoid (*modes)(const struct sfp_eeprom_id *, long unsigned int *);\n};\n\nstruct wl1251_platform_data {\n\tint power_gpio;\n\tint irq;\n\tbool use_eeprom;\n};\n\nenum {\n\tIFLA_UNSPEC = 0,\n\tIFLA_ADDRESS = 1,\n\tIFLA_BROADCAST = 2,\n\tIFLA_IFNAME = 3,\n\tIFLA_MTU = 4,\n\tIFLA_LINK = 5,\n\tIFLA_QDISC = 6,\n\tIFLA_STATS = 7,\n\tIFLA_COST = 8,\n\tIFLA_PRIORITY = 9,\n\tIFLA_MASTER = 10,\n\tIFLA_WIRELESS = 11,\n\tIFLA_PROTINFO = 12,\n\tIFLA_TXQLEN = 13,\n\tIFLA_MAP = 14,\n\tIFLA_WEIGHT = 15,\n\tIFLA_OPERSTATE = 16,\n\tIFLA_LINKMODE = 17,\n\tIFLA_LINKINFO = 18,\n\tIFLA_NET_NS_PID = 19,\n\tIFLA_IFALIAS = 20,\n\tIFLA_NUM_VF = 21,\n\tIFLA_VFINFO_LIST = 22,\n\tIFLA_STATS64 = 23,\n\tIFLA_VF_PORTS = 24,\n\tIFLA_PORT_SELF = 25,\n\tIFLA_AF_SPEC = 26,\n\tIFLA_GROUP = 27,\n\tIFLA_NET_NS_FD = 28,\n\tIFLA_EXT_MASK = 29,\n\tIFLA_PROMISCUITY = 30,\n\tIFLA_NUM_TX_QUEUES = 31,\n\tIFLA_NUM_RX_QUEUES = 32,\n\tIFLA_CARRIER = 33,\n\tIFLA_PHYS_PORT_ID = 34,\n\tIFLA_CARRIER_CHANGES = 35,\n\tIFLA_PHYS_SWITCH_ID = 36,\n\tIFLA_LINK_NETNSID = 37,\n\tIFLA_PHYS_PORT_NAME = 38,\n\tIFLA_PROTO_DOWN = 39,\n\tIFLA_GSO_MAX_SEGS = 40,\n\tIFLA_GSO_MAX_SIZE = 41,\n\tIFLA_PAD = 42,\n\tIFLA_XDP = 43,\n\tIFLA_EVENT = 44,\n\tIFLA_NEW_NETNSID = 45,\n\tIFLA_IF_NETNSID = 46,\n\tIFLA_TARGET_NETNSID = 46,\n\tIFLA_CARRIER_UP_COUNT = 47,\n\tIFLA_CARRIER_DOWN_COUNT = 48,\n\tIFLA_NEW_IFINDEX = 49,\n\tIFLA_MIN_MTU = 50,\n\tIFLA_MAX_MTU = 51,\n\tIFLA_PROP_LIST = 52,\n\tIFLA_ALT_IFNAME = 53,\n\tIFLA_PERM_ADDRESS = 54,\n\tIFLA_PROTO_DOWN_REASON = 55,\n\tIFLA_PARENT_DEV_NAME = 56,\n\tIFLA_PARENT_DEV_BUS_NAME = 57,\n\t__IFLA_MAX = 58,\n};\n\nenum {\n\tIFLA_INFO_UNSPEC = 0,\n\tIFLA_INFO_KIND = 1,\n\tIFLA_INFO_DATA = 2,\n\tIFLA_INFO_XSTATS = 3,\n\tIFLA_INFO_SLAVE_KIND = 4,\n\tIFLA_INFO_SLAVE_DATA = 5,\n\t__IFLA_INFO_MAX = 6,\n};\n\nenum wwan_port_type {\n\tWWAN_PORT_AT = 0,\n\tWWAN_PORT_MBIM = 1,\n\tWWAN_PORT_QMI = 2,\n\tWWAN_PORT_QCDM = 3,\n\tWWAN_PORT_FIREHOSE = 4,\n\t__WWAN_PORT_MAX = 5,\n\tWWAN_PORT_MAX = 4,\n\tWWAN_PORT_UNKNOWN = 5,\n};\n\nstruct wwan_port;\n\nstruct wwan_port_ops {\n\tint (*start)(struct wwan_port *);\n\tvoid (*stop)(struct wwan_port *);\n\tint (*tx)(struct wwan_port *, struct sk_buff *);\n\tint (*tx_blocking)(struct wwan_port *, struct sk_buff *);\n\t__poll_t (*tx_poll)(struct wwan_port *, struct file *, poll_table *);\n};\n\nstruct wwan_port {\n\tenum wwan_port_type type;\n\tunsigned int start_count;\n\tlong unsigned int flags;\n\tconst struct wwan_port_ops *ops;\n\tstruct mutex ops_lock;\n\tstruct device dev;\n\tstruct sk_buff_head rxq;\n\twait_queue_head_t waitqueue;\n\tstruct mutex data_lock;\n\tunion {\n\t\tstruct {\n\t\t\tstruct ktermios termios;\n\t\t\tint mdmbits;\n\t\t} at_data;\n\t};\n};\n\nstruct wwan_netdev_priv {\n\tu32 link_id;\n\tint: 32;\n\tu8 drv_priv[0];\n};\n\nstruct wwan_ops {\n\tunsigned int priv_size;\n\tvoid (*setup)(struct net_device *);\n\tint (*newlink)(void *, struct net_device *, u32, struct netlink_ext_ack *);\n\tvoid (*dellink)(void *, struct net_device *, struct list_head *);\n};\n\nstruct ifinfomsg {\n\tunsigned char ifi_family;\n\tunsigned char __ifi_pad;\n\tshort unsigned int ifi_type;\n\tint ifi_index;\n\tunsigned int ifi_flags;\n\tunsigned int ifi_change;\n};\n\nenum {\n\tIFLA_WWAN_UNSPEC = 0,\n\tIFLA_WWAN_LINK_ID = 1,\n\t__IFLA_WWAN_MAX = 2,\n};\n\nstruct wwan_device {\n\tunsigned int id;\n\tstruct device dev;\n\tatomic_t port_id;\n\tconst struct wwan_ops *ops;\n\tvoid *ops_ctxt;\n};\n\nenum usb_otg_state {\n\tOTG_STATE_UNDEFINED = 0,\n\tOTG_STATE_B_IDLE = 1,\n\tOTG_STATE_B_SRP_INIT = 2,\n\tOTG_STATE_B_PERIPHERAL = 3,\n\tOTG_STATE_B_WAIT_ACON = 4,\n\tOTG_STATE_B_HOST = 5,\n\tOTG_STATE_A_IDLE = 6,\n\tOTG_STATE_A_WAIT_VRISE = 7,\n\tOTG_STATE_A_WAIT_BCON = 8,\n\tOTG_STATE_A_HOST = 9,\n\tOTG_STATE_A_SUSPEND = 10,\n\tOTG_STATE_A_PERIPHERAL = 11,\n\tOTG_STATE_A_WAIT_VFALL = 12,\n\tOTG_STATE_A_VBUS_ERR = 13,\n};\n\nenum usb_dr_mode {\n\tUSB_DR_MODE_UNKNOWN = 0,\n\tUSB_DR_MODE_HOST = 1,\n\tUSB_DR_MODE_PERIPHERAL = 2,\n\tUSB_DR_MODE_OTG = 3,\n};\n\nenum usb_led_event {\n\tUSB_LED_EVENT_HOST = 0,\n\tUSB_LED_EVENT_GADGET = 1,\n};\n\nstruct usb_device_id {\n\t__u16 match_flags;\n\t__u16 idVendor;\n\t__u16 idProduct;\n\t__u16 bcdDevice_lo;\n\t__u16 bcdDevice_hi;\n\t__u8 bDeviceClass;\n\t__u8 bDeviceSubClass;\n\t__u8 bDeviceProtocol;\n\t__u8 bInterfaceClass;\n\t__u8 bInterfaceSubClass;\n\t__u8 bInterfaceProtocol;\n\t__u8 bInterfaceNumber;\n\tkernel_ulong_t driver_info;\n};\n\nstruct usb_descriptor_header {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n};\n\nenum usb_port_connect_type {\n\tUSB_PORT_CONNECT_TYPE_UNKNOWN = 0,\n\tUSB_PORT_CONNECT_TYPE_HOT_PLUG = 1,\n\tUSB_PORT_CONNECT_TYPE_HARD_WIRED = 2,\n\tUSB_PORT_NOT_USED = 3,\n};\n\nstruct usb_dynids {\n\tspinlock_t lock;\n\tstruct list_head list;\n};\n\nstruct usbdrv_wrap {\n\tstruct device_driver driver;\n\tint for_devices;\n};\n\nstruct usb_driver {\n\tconst char *name;\n\tint (*probe)(struct usb_interface *, const struct usb_device_id *);\n\tvoid (*disconnect)(struct usb_interface *);\n\tint (*unlocked_ioctl)(struct usb_interface *, unsigned int, void *);\n\tint (*suspend)(struct usb_interface *, pm_message_t);\n\tint (*resume)(struct usb_interface *);\n\tint (*reset_resume)(struct usb_interface *);\n\tint (*pre_reset)(struct usb_interface *);\n\tint (*post_reset)(struct usb_interface *);\n\tconst struct usb_device_id *id_table;\n\tconst struct attribute_group **dev_groups;\n\tstruct usb_dynids dynids;\n\tstruct usbdrv_wrap drvwrap;\n\tunsigned int no_dynamic_id: 1;\n\tunsigned int supports_autosuspend: 1;\n\tunsigned int disable_hub_initiated_lpm: 1;\n\tunsigned int soft_unbind: 1;\n};\n\nstruct usb_device_driver {\n\tconst char *name;\n\tbool (*match)(struct usb_device *);\n\tint (*probe)(struct usb_device *);\n\tvoid (*disconnect)(struct usb_device *);\n\tint (*suspend)(struct usb_device *, pm_message_t);\n\tint (*resume)(struct usb_device *, pm_message_t);\n\tconst struct attribute_group **dev_groups;\n\tstruct usbdrv_wrap drvwrap;\n\tconst struct usb_device_id *id_table;\n\tunsigned int supports_autosuspend: 1;\n\tunsigned int generic_subclass: 1;\n};\n\nenum usb_phy_type {\n\tUSB_PHY_TYPE_UNDEFINED = 0,\n\tUSB_PHY_TYPE_USB2 = 1,\n\tUSB_PHY_TYPE_USB3 = 2,\n};\n\nenum usb_phy_events {\n\tUSB_EVENT_NONE = 0,\n\tUSB_EVENT_VBUS = 1,\n\tUSB_EVENT_ID = 2,\n\tUSB_EVENT_CHARGER = 3,\n\tUSB_EVENT_ENUMERATED = 4,\n};\n\nenum usb_charger_type {\n\tUNKNOWN_TYPE = 0,\n\tSDP_TYPE = 1,\n\tDCP_TYPE = 2,\n\tCDP_TYPE = 3,\n\tACA_TYPE = 4,\n};\n\nenum usb_charger_state {\n\tUSB_CHARGER_DEFAULT = 0,\n\tUSB_CHARGER_PRESENT = 1,\n\tUSB_CHARGER_ABSENT = 2,\n};\n\nstruct usb_charger_current {\n\tunsigned int sdp_min;\n\tunsigned int sdp_max;\n\tunsigned int dcp_min;\n\tunsigned int dcp_max;\n\tunsigned int cdp_min;\n\tunsigned int cdp_max;\n\tunsigned int aca_min;\n\tunsigned int aca_max;\n};\n\nstruct usb_otg;\n\nstruct usb_phy_io_ops;\n\nstruct usb_phy {\n\tstruct device *dev;\n\tconst char *label;\n\tunsigned int flags;\n\tenum usb_phy_type type;\n\tenum usb_phy_events last_event;\n\tstruct usb_otg *otg;\n\tstruct device *io_dev;\n\tstruct usb_phy_io_ops *io_ops;\n\tvoid *io_priv;\n\tstruct extcon_dev *edev;\n\tstruct extcon_dev *id_edev;\n\tstruct notifier_block vbus_nb;\n\tstruct notifier_block id_nb;\n\tstruct notifier_block type_nb;\n\tenum usb_charger_type chg_type;\n\tenum usb_charger_state chg_state;\n\tstruct usb_charger_current chg_cur;\n\tstruct work_struct chg_work;\n\tstruct atomic_notifier_head notifier;\n\tu16 port_status;\n\tu16 port_change;\n\tstruct list_head head;\n\tint (*init)(struct usb_phy *);\n\tvoid (*shutdown)(struct usb_phy *);\n\tint (*set_vbus)(struct usb_phy *, int);\n\tint (*set_power)(struct usb_phy *, unsigned int);\n\tint (*set_suspend)(struct usb_phy *, int);\n\tint (*set_wakeup)(struct usb_phy *, bool);\n\tint (*notify_connect)(struct usb_phy *, enum usb_device_speed);\n\tint (*notify_disconnect)(struct usb_phy *, enum usb_device_speed);\n\tenum usb_charger_type (*charger_detect)(struct usb_phy *);\n};\n\nstruct usb_port_status {\n\t__le16 wPortStatus;\n\t__le16 wPortChange;\n\t__le32 dwExtPortStatus;\n};\n\nstruct usb_hub_status {\n\t__le16 wHubStatus;\n\t__le16 wHubChange;\n};\n\nstruct usb_hub_descriptor {\n\t__u8 bDescLength;\n\t__u8 bDescriptorType;\n\t__u8 bNbrPorts;\n\t__le16 wHubCharacteristics;\n\t__u8 bPwrOn2PwrGood;\n\t__u8 bHubContrCurrent;\n\tunion {\n\t\tstruct {\n\t\t\t__u8 DeviceRemovable[4];\n\t\t\t__u8 PortPwrCtrlMask[4];\n\t\t} hs;\n\t\tstruct {\n\t\t\t__u8 bHubHdrDecLat;\n\t\t\t__le16 wHubDelay;\n\t\t\t__le16 DeviceRemovable;\n\t\t} __attribute__((packed)) ss;\n\t} u;\n} __attribute__((packed));\n\nstruct usb_phy_io_ops {\n\tint (*read)(struct usb_phy *, u32);\n\tint (*write)(struct usb_phy *, u32, u32);\n};\n\nstruct usb_gadget;\n\nstruct usb_otg {\n\tu8 default_a;\n\tstruct phy *phy;\n\tstruct usb_phy *usb_phy;\n\tstruct usb_bus *host;\n\tstruct usb_gadget *gadget;\n\tenum usb_otg_state state;\n\tint (*set_host)(struct usb_otg *, struct usb_bus *);\n\tint (*set_peripheral)(struct usb_otg *, struct usb_gadget *);\n\tint (*set_vbus)(struct usb_otg *, bool);\n\tint (*start_srp)(struct usb_otg *);\n\tint (*start_hnp)(struct usb_otg *);\n};\n\ntypedef u32 usb_port_location_t;\n\nstruct usb_port;\n\nstruct usb_hub {\n\tstruct device *intfdev;\n\tstruct usb_device *hdev;\n\tstruct kref kref;\n\tstruct urb *urb;\n\tu8 (*buffer)[8];\n\tunion {\n\t\tstruct usb_hub_status hub;\n\t\tstruct usb_port_status port;\n\t} *status;\n\tstruct mutex status_mutex;\n\tint error;\n\tint nerrors;\n\tlong unsigned int event_bits[1];\n\tlong unsigned int change_bits[1];\n\tlong unsigned int removed_bits[1];\n\tlong unsigned int wakeup_bits[1];\n\tlong unsigned int power_bits[1];\n\tlong unsigned int child_usage_bits[1];\n\tlong unsigned int warm_reset_bits[1];\n\tstruct usb_hub_descriptor *descriptor;\n\tstruct usb_tt tt;\n\tunsigned int mA_per_port;\n\tunsigned int wakeup_enabled_descendants;\n\tunsigned int limited_power: 1;\n\tunsigned int quiescing: 1;\n\tunsigned int disconnected: 1;\n\tunsigned int in_reset: 1;\n\tunsigned int quirk_disable_autosuspend: 1;\n\tunsigned int quirk_check_port_auto_suspend: 1;\n\tunsigned int has_indicators: 1;\n\tu8 indicator[31];\n\tstruct delayed_work leds;\n\tstruct delayed_work init_work;\n\tstruct work_struct events;\n\tspinlock_t irq_urb_lock;\n\tstruct timer_list irq_urb_retry;\n\tstruct usb_port **ports;\n};\n\nstruct usb_dev_state;\n\nstruct usb_port {\n\tstruct usb_device *child;\n\tstruct device dev;\n\tstruct usb_dev_state *port_owner;\n\tstruct usb_port *peer;\n\tstruct dev_pm_qos_request *req;\n\tenum usb_port_connect_type connect_type;\n\tusb_port_location_t location;\n\tstruct mutex status_lock;\n\tu32 over_current_count;\n\tu8 portnum;\n\tu32 quirks;\n\tunsigned int is_superspeed: 1;\n\tunsigned int usb3_lpm_u1_permit: 1;\n\tunsigned int usb3_lpm_u2_permit: 1;\n};\n\nstruct find_interface_arg {\n\tint minor;\n\tstruct device_driver *drv;\n};\n\nstruct each_dev_arg {\n\tvoid *data;\n\tint (*fn)(struct usb_device *, void *);\n};\n\nstruct each_hub_arg {\n\tvoid *data;\n\tint (*fn)(struct device *, void *);\n};\n\nstruct usb_qualifier_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__le16 bcdUSB;\n\t__u8 bDeviceClass;\n\t__u8 bDeviceSubClass;\n\t__u8 bDeviceProtocol;\n\t__u8 bMaxPacketSize0;\n\t__u8 bNumConfigurations;\n\t__u8 bRESERVED;\n};\n\nstruct usb_set_sel_req {\n\t__u8 u1_sel;\n\t__u8 u1_pel;\n\t__le16 u2_sel;\n\t__le16 u2_pel;\n};\n\nstruct usbdevfs_hub_portinfo {\n\tchar nports;\n\tchar port[127];\n};\n\nenum hub_led_mode {\n\tINDICATOR_AUTO = 0,\n\tINDICATOR_CYCLE = 1,\n\tINDICATOR_GREEN_BLINK = 2,\n\tINDICATOR_GREEN_BLINK_OFF = 3,\n\tINDICATOR_AMBER_BLINK = 4,\n\tINDICATOR_AMBER_BLINK_OFF = 5,\n\tINDICATOR_ALT_BLINK = 6,\n\tINDICATOR_ALT_BLINK_OFF = 7,\n};\n\nstruct usb_tt_clear {\n\tstruct list_head clear_list;\n\tunsigned int tt;\n\tu16 devinfo;\n\tstruct usb_hcd *hcd;\n\tstruct usb_host_endpoint *ep;\n};\n\nenum hub_activation_type {\n\tHUB_INIT = 0,\n\tHUB_INIT2 = 1,\n\tHUB_INIT3 = 2,\n\tHUB_POST_RESET = 3,\n\tHUB_RESUME = 4,\n\tHUB_RESET_RESUME = 5,\n};\n\nenum hub_quiescing_type {\n\tHUB_DISCONNECT = 0,\n\tHUB_PRE_RESET = 1,\n\tHUB_SUSPEND = 2,\n};\n\nstruct usb_ctrlrequest {\n\t__u8 bRequestType;\n\t__u8 bRequest;\n\t__le16 wValue;\n\t__le16 wIndex;\n\t__le16 wLength;\n};\n\nstruct usb_mon_operations {\n\tvoid (*urb_submit)(struct usb_bus *, struct urb *);\n\tvoid (*urb_submit_error)(struct usb_bus *, struct urb *, int);\n\tvoid (*urb_complete)(struct usb_bus *, struct urb *, int);\n};\n\nstruct usb_sg_request {\n\tint status;\n\tsize_t bytes;\n\tspinlock_t lock;\n\tstruct usb_device *dev;\n\tint pipe;\n\tint entries;\n\tstruct urb **urbs;\n\tint count;\n\tstruct completion complete;\n};\n\nstruct usb_cdc_header_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__le16 bcdCDC;\n} __attribute__((packed));\n\nstruct usb_cdc_call_mgmt_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__u8 bmCapabilities;\n\t__u8 bDataInterface;\n};\n\nstruct usb_cdc_acm_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__u8 bmCapabilities;\n};\n\nstruct usb_cdc_union_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__u8 bMasterInterface0;\n\t__u8 bSlaveInterface0;\n};\n\nstruct usb_cdc_country_functional_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__u8 iCountryCodeRelDate;\n\t__le16 wCountyCode0;\n};\n\nstruct usb_cdc_network_terminal_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__u8 bEntityId;\n\t__u8 iName;\n\t__u8 bChannelIndex;\n\t__u8 bPhysicalInterface;\n};\n\nstruct usb_cdc_ether_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__u8 iMACAddress;\n\t__le32 bmEthernetStatistics;\n\t__le16 wMaxSegmentSize;\n\t__le16 wNumberMCFilters;\n\t__u8 bNumberPowerFilters;\n} __attribute__((packed));\n\nstruct usb_cdc_dmm_desc {\n\t__u8 bFunctionLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubtype;\n\t__u16 bcdVersion;\n\t__le16 wMaxCommand;\n} __attribute__((packed));\n\nstruct usb_cdc_mdlm_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__le16 bcdVersion;\n\t__u8 bGUID[16];\n} __attribute__((packed));\n\nstruct usb_cdc_mdlm_detail_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__u8 bGuidDescriptorType;\n\t__u8 bDetailData[0];\n};\n\nstruct usb_cdc_obex_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__le16 bcdVersion;\n} __attribute__((packed));\n\nstruct usb_cdc_ncm_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__le16 bcdNcmVersion;\n\t__u8 bmNetworkCapabilities;\n} __attribute__((packed));\n\nstruct usb_cdc_mbim_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__le16 bcdMBIMVersion;\n\t__le16 wMaxControlMessage;\n\t__u8 bNumberFilters;\n\t__u8 bMaxFilterSize;\n\t__le16 wMaxSegmentSize;\n\t__u8 bmNetworkCapabilities;\n} __attribute__((packed));\n\nstruct usb_cdc_mbim_extended_desc {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDescriptorSubType;\n\t__le16 bcdMBIMExtendedVersion;\n\t__u8 bMaxOutstandingCommandMessages;\n\t__le16 wMTU;\n} __attribute__((packed));\n\nstruct usb_cdc_parsed_header {\n\tstruct usb_cdc_union_desc *usb_cdc_union_desc;\n\tstruct usb_cdc_header_desc *usb_cdc_header_desc;\n\tstruct usb_cdc_call_mgmt_descriptor *usb_cdc_call_mgmt_descriptor;\n\tstruct usb_cdc_acm_descriptor *usb_cdc_acm_descriptor;\n\tstruct usb_cdc_country_functional_desc *usb_cdc_country_functional_desc;\n\tstruct usb_cdc_network_terminal_desc *usb_cdc_network_terminal_desc;\n\tstruct usb_cdc_ether_desc *usb_cdc_ether_desc;\n\tstruct usb_cdc_dmm_desc *usb_cdc_dmm_desc;\n\tstruct usb_cdc_mdlm_desc *usb_cdc_mdlm_desc;\n\tstruct usb_cdc_mdlm_detail_desc *usb_cdc_mdlm_detail_desc;\n\tstruct usb_cdc_obex_desc *usb_cdc_obex_desc;\n\tstruct usb_cdc_ncm_desc *usb_cdc_ncm_desc;\n\tstruct usb_cdc_mbim_desc *usb_cdc_mbim_desc;\n\tstruct usb_cdc_mbim_extended_desc *usb_cdc_mbim_extended_desc;\n\tbool phonet_magic_present;\n};\n\nstruct api_context {\n\tstruct completion done;\n\tint status;\n};\n\nstruct set_config_request {\n\tstruct usb_device *udev;\n\tint config;\n\tstruct work_struct work;\n\tstruct list_head node;\n};\n\nstruct usb_dynid {\n\tstruct list_head node;\n\tstruct usb_device_id id;\n};\n\nstruct usb_dev_cap_header {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDevCapabilityType;\n};\n\nstruct usb_class_driver {\n\tchar *name;\n\tchar * (*devnode)(struct device *, umode_t *);\n\tconst struct file_operations *fops;\n\tint minor_base;\n};\n\nstruct usb_class {\n\tstruct kref kref;\n\tstruct class *class;\n};\n\nstruct ep_device {\n\tstruct usb_endpoint_descriptor *desc;\n\tstruct usb_device *udev;\n\tstruct device dev;\n};\n\nstruct usbdevfs_ctrltransfer {\n\t__u8 bRequestType;\n\t__u8 bRequest;\n\t__u16 wValue;\n\t__u16 wIndex;\n\t__u16 wLength;\n\t__u32 timeout;\n\tvoid *data;\n};\n\nstruct usbdevfs_bulktransfer {\n\tunsigned int ep;\n\tunsigned int len;\n\tunsigned int timeout;\n\tvoid *data;\n};\n\nstruct usbdevfs_setinterface {\n\tunsigned int interface;\n\tunsigned int altsetting;\n};\n\nstruct usbdevfs_disconnectsignal {\n\tunsigned int signr;\n\tvoid *context;\n};\n\nstruct usbdevfs_getdriver {\n\tunsigned int interface;\n\tchar driver[256];\n};\n\nstruct usbdevfs_connectinfo {\n\tunsigned int devnum;\n\tunsigned char slow;\n};\n\nstruct usbdevfs_conninfo_ex {\n\t__u32 size;\n\t__u32 busnum;\n\t__u32 devnum;\n\t__u32 speed;\n\t__u8 num_ports;\n\t__u8 ports[7];\n};\n\nstruct usbdevfs_iso_packet_desc {\n\tunsigned int length;\n\tunsigned int actual_length;\n\tunsigned int status;\n};\n\nstruct usbdevfs_urb {\n\tunsigned char type;\n\tunsigned char endpoint;\n\tint status;\n\tunsigned int flags;\n\tvoid *buffer;\n\tint buffer_length;\n\tint actual_length;\n\tint start_frame;\n\tunion {\n\t\tint number_of_packets;\n\t\tunsigned int stream_id;\n\t};\n\tint error_count;\n\tunsigned int signr;\n\tvoid *usercontext;\n\tstruct usbdevfs_iso_packet_desc iso_frame_desc[0];\n};\n\nstruct usbdevfs_ioctl {\n\tint ifno;\n\tint ioctl_code;\n\tvoid *data;\n};\n\nstruct usbdevfs_disconnect_claim {\n\tunsigned int interface;\n\tunsigned int flags;\n\tchar driver[256];\n};\n\nstruct usbdevfs_streams {\n\tunsigned int num_streams;\n\tunsigned int num_eps;\n\tunsigned char eps[0];\n};\n\nstruct usbdevfs_ctrltransfer32 {\n\tu8 bRequestType;\n\tu8 bRequest;\n\tu16 wValue;\n\tu16 wIndex;\n\tu16 wLength;\n\tu32 timeout;\n\tcompat_caddr_t data;\n};\n\nstruct usbdevfs_bulktransfer32 {\n\tcompat_uint_t ep;\n\tcompat_uint_t len;\n\tcompat_uint_t timeout;\n\tcompat_caddr_t data;\n};\n\nstruct usbdevfs_disconnectsignal32 {\n\tcompat_int_t signr;\n\tcompat_caddr_t context;\n};\n\nstruct usbdevfs_urb32 {\n\tunsigned char type;\n\tunsigned char endpoint;\n\tcompat_int_t status;\n\tcompat_uint_t flags;\n\tcompat_caddr_t buffer;\n\tcompat_int_t buffer_length;\n\tcompat_int_t actual_length;\n\tcompat_int_t start_frame;\n\tcompat_int_t number_of_packets;\n\tcompat_int_t error_count;\n\tcompat_uint_t signr;\n\tcompat_caddr_t usercontext;\n\tstruct usbdevfs_iso_packet_desc iso_frame_desc[0];\n};\n\nstruct usbdevfs_ioctl32 {\n\ts32 ifno;\n\ts32 ioctl_code;\n\tcompat_caddr_t data;\n};\n\nstruct usb_dev_state___2 {\n\tstruct list_head list;\n\tstruct usb_device *dev;\n\tstruct file *file;\n\tspinlock_t lock;\n\tstruct list_head async_pending;\n\tstruct list_head async_completed;\n\tstruct list_head memory_list;\n\twait_queue_head_t wait;\n\twait_queue_head_t wait_for_resume;\n\tunsigned int discsignr;\n\tstruct pid *disc_pid;\n\tconst struct cred *cred;\n\tsigval_t disccontext;\n\tlong unsigned int ifclaimed;\n\tu32 disabled_bulk_eps;\n\tlong unsigned int interface_allowed_mask;\n\tint not_yet_resumed;\n\tbool suspend_allowed;\n\tbool privileges_dropped;\n};\n\nstruct usb_memory {\n\tstruct list_head memlist;\n\tint vma_use_count;\n\tint urb_use_count;\n\tu32 size;\n\tvoid *mem;\n\tdma_addr_t dma_handle;\n\tlong unsigned int vm_start;\n\tstruct usb_dev_state___2 *ps;\n};\n\nstruct async {\n\tstruct list_head asynclist;\n\tstruct usb_dev_state___2 *ps;\n\tstruct pid *pid;\n\tconst struct cred *cred;\n\tunsigned int signr;\n\tunsigned int ifnum;\n\tvoid *userbuffer;\n\tvoid *userurb;\n\tsigval_t userurb_sigval;\n\tstruct urb *urb;\n\tstruct usb_memory *usbm;\n\tunsigned int mem_usage;\n\tint status;\n\tu8 bulk_addr;\n\tu8 bulk_status;\n};\n\nenum snoop_when {\n\tSUBMIT = 0,\n\tCOMPLETE___2 = 1,\n};\n\nstruct quirk_entry {\n\tu16 vid;\n\tu16 pid;\n\tu32 flags;\n};\n\nstruct class_info {\n\tint class;\n\tchar *class_name;\n};\n\nstruct usb_phy_roothub___2 {\n\tstruct phy *phy;\n\tstruct list_head list;\n};\n\ntypedef void (*companion_fn)(struct pci_dev *, struct usb_hcd *, struct pci_dev *, struct usb_hcd *);\n\nstruct phy_devm {\n\tstruct usb_phy *phy;\n\tstruct notifier_block *nb;\n};\n\nenum amd_chipset_gen {\n\tNOT_AMD_CHIPSET = 0,\n\tAMD_CHIPSET_SB600 = 1,\n\tAMD_CHIPSET_SB700 = 2,\n\tAMD_CHIPSET_SB800 = 3,\n\tAMD_CHIPSET_HUDSON2 = 4,\n\tAMD_CHIPSET_BOLTON = 5,\n\tAMD_CHIPSET_YANGTZE = 6,\n\tAMD_CHIPSET_TAISHAN = 7,\n\tAMD_CHIPSET_UNKNOWN = 8,\n};\n\nstruct amd_chipset_type {\n\tenum amd_chipset_gen gen;\n\tu8 rev;\n};\n\nstruct amd_chipset_info {\n\tstruct pci_dev *nb_dev;\n\tstruct pci_dev *smbus_dev;\n\tint nb_type;\n\tstruct amd_chipset_type sb_type;\n\tint isoc_reqs;\n\tint probe_count;\n\tbool need_pll_quirk;\n};\n\nstruct ehci_stats {\n\tlong unsigned int normal;\n\tlong unsigned int error;\n\tlong unsigned int iaa;\n\tlong unsigned int lost_iaa;\n\tlong unsigned int complete;\n\tlong unsigned int unlink;\n};\n\nstruct ehci_per_sched {\n\tstruct usb_device *udev;\n\tstruct usb_host_endpoint *ep;\n\tstruct list_head ps_list;\n\tu16 tt_usecs;\n\tu16 cs_mask;\n\tu16 period;\n\tu16 phase;\n\tu8 bw_phase;\n\tu8 phase_uf;\n\tu8 usecs;\n\tu8 c_usecs;\n\tu8 bw_uperiod;\n\tu8 bw_period;\n};\n\nenum ehci_rh_state {\n\tEHCI_RH_HALTED = 0,\n\tEHCI_RH_SUSPENDED = 1,\n\tEHCI_RH_RUNNING = 2,\n\tEHCI_RH_STOPPING = 3,\n};\n\nenum ehci_hrtimer_event {\n\tEHCI_HRTIMER_POLL_ASS = 0,\n\tEHCI_HRTIMER_POLL_PSS = 1,\n\tEHCI_HRTIMER_POLL_DEAD = 2,\n\tEHCI_HRTIMER_UNLINK_INTR = 3,\n\tEHCI_HRTIMER_FREE_ITDS = 4,\n\tEHCI_HRTIMER_ACTIVE_UNLINK = 5,\n\tEHCI_HRTIMER_START_UNLINK_INTR = 6,\n\tEHCI_HRTIMER_ASYNC_UNLINKS = 7,\n\tEHCI_HRTIMER_IAA_WATCHDOG = 8,\n\tEHCI_HRTIMER_DISABLE_PERIODIC = 9,\n\tEHCI_HRTIMER_DISABLE_ASYNC = 10,\n\tEHCI_HRTIMER_IO_WATCHDOG = 11,\n\tEHCI_HRTIMER_NUM_EVENTS = 12,\n};\n\nstruct ehci_caps;\n\nstruct ehci_regs;\n\nstruct ehci_dbg_port;\n\nstruct ehci_qh;\n\nunion ehci_shadow;\n\nstruct ehci_itd;\n\nstruct ehci_sitd;\n\nstruct ehci_hcd {\n\tenum ehci_hrtimer_event next_hrtimer_event;\n\tunsigned int enabled_hrtimer_events;\n\tktime_t hr_timeouts[12];\n\tstruct hrtimer hrtimer;\n\tint PSS_poll_count;\n\tint ASS_poll_count;\n\tint died_poll_count;\n\tstruct ehci_caps *caps;\n\tstruct ehci_regs *regs;\n\tstruct ehci_dbg_port *debug;\n\t__u32 hcs_params;\n\tspinlock_t lock;\n\tenum ehci_rh_state rh_state;\n\tbool scanning: 1;\n\tbool need_rescan: 1;\n\tbool intr_unlinking: 1;\n\tbool iaa_in_progress: 1;\n\tbool async_unlinking: 1;\n\tbool shutdown: 1;\n\tstruct ehci_qh *qh_scan_next;\n\tstruct ehci_qh *async;\n\tstruct ehci_qh *dummy;\n\tstruct list_head async_unlink;\n\tstruct list_head async_idle;\n\tunsigned int async_unlink_cycle;\n\tunsigned int async_count;\n\t__le32 old_current;\n\t__le32 old_token;\n\tunsigned int periodic_size;\n\t__le32 *periodic;\n\tdma_addr_t periodic_dma;\n\tstruct list_head intr_qh_list;\n\tunsigned int i_thresh;\n\tunion ehci_shadow *pshadow;\n\tstruct list_head intr_unlink_wait;\n\tstruct list_head intr_unlink;\n\tunsigned int intr_unlink_wait_cycle;\n\tunsigned int intr_unlink_cycle;\n\tunsigned int now_frame;\n\tunsigned int last_iso_frame;\n\tunsigned int intr_count;\n\tunsigned int isoc_count;\n\tunsigned int periodic_count;\n\tunsigned int uframe_periodic_max;\n\tstruct list_head cached_itd_list;\n\tstruct ehci_itd *last_itd_to_free;\n\tstruct list_head cached_sitd_list;\n\tstruct ehci_sitd *last_sitd_to_free;\n\tlong unsigned int reset_done[15];\n\tlong unsigned int bus_suspended;\n\tlong unsigned int companion_ports;\n\tlong unsigned int owned_ports;\n\tlong unsigned int port_c_suspend;\n\tlong unsigned int suspended_ports;\n\tlong unsigned int resuming_ports;\n\tstruct dma_pool___2 *qh_pool;\n\tstruct dma_pool___2 *qtd_pool;\n\tstruct dma_pool___2 *itd_pool;\n\tstruct dma_pool___2 *sitd_pool;\n\tunsigned int random_frame;\n\tlong unsigned int next_statechange;\n\tktime_t last_periodic_enable;\n\tu32 command;\n\tunsigned int no_selective_suspend: 1;\n\tunsigned int has_fsl_port_bug: 1;\n\tunsigned int has_fsl_hs_errata: 1;\n\tunsigned int has_fsl_susp_errata: 1;\n\tunsigned int big_endian_mmio: 1;\n\tunsigned int big_endian_desc: 1;\n\tunsigned int big_endian_capbase: 1;\n\tunsigned int has_amcc_usb23: 1;\n\tunsigned int need_io_watchdog: 1;\n\tunsigned int amd_pll_fix: 1;\n\tunsigned int use_dummy_qh: 1;\n\tunsigned int has_synopsys_hc_bug: 1;\n\tunsigned int frame_index_bug: 1;\n\tunsigned int need_oc_pp_cycle: 1;\n\tunsigned int imx28_write_fix: 1;\n\tunsigned int spurious_oc: 1;\n\t__le32 *ohci_hcctrl_reg;\n\tunsigned int has_hostpc: 1;\n\tunsigned int has_tdi_phy_lpm: 1;\n\tunsigned int has_ppcd: 1;\n\tu8 sbrn;\n\tstruct ehci_stats stats;\n\tstruct dentry *debug_dir;\n\tu8 bandwidth[64];\n\tu8 tt_budget[64];\n\tstruct list_head tt_list;\n\tlong unsigned int priv[0];\n};\n\nstruct ehci_caps {\n\tu32 hc_capbase;\n\tu32 hcs_params;\n\tu32 hcc_params;\n\tu8 portroute[8];\n};\n\nstruct ehci_regs {\n\tu32 command;\n\tu32 status;\n\tu32 intr_enable;\n\tu32 frame_index;\n\tu32 segment;\n\tu32 frame_list;\n\tu32 async_next;\n\tu32 reserved1[2];\n\tu32 txfill_tuning;\n\tu32 reserved2[6];\n\tu32 configured_flag;\n\tu32 port_status[0];\n\tu32 reserved3[9];\n\tu32 usbmode;\n\tu32 reserved4[6];\n\tu32 hostpc[0];\n\tu32 reserved5[17];\n\tu32 usbmode_ex;\n};\n\nstruct ehci_dbg_port {\n\tu32 control;\n\tu32 pids;\n\tu32 data03;\n\tu32 data47;\n\tu32 address;\n};\n\nstruct ehci_fstn;\n\nunion ehci_shadow {\n\tstruct ehci_qh *qh;\n\tstruct ehci_itd *itd;\n\tstruct ehci_sitd *sitd;\n\tstruct ehci_fstn *fstn;\n\t__le32 *hw_next;\n\tvoid *ptr;\n};\n\nstruct ehci_qh_hw;\n\nstruct ehci_qtd;\n\nstruct ehci_qh {\n\tstruct ehci_qh_hw *hw;\n\tdma_addr_t qh_dma;\n\tunion ehci_shadow qh_next;\n\tstruct list_head qtd_list;\n\tstruct list_head intr_node;\n\tstruct ehci_qtd *dummy;\n\tstruct list_head unlink_node;\n\tstruct ehci_per_sched ps;\n\tunsigned int unlink_cycle;\n\tu8 qh_state;\n\tu8 xacterrs;\n\tu8 unlink_reason;\n\tu8 gap_uf;\n\tunsigned int is_out: 1;\n\tunsigned int clearing_tt: 1;\n\tunsigned int dequeue_during_giveback: 1;\n\tunsigned int should_be_inactive: 1;\n};\n\nstruct ehci_iso_stream;\n\nstruct ehci_itd {\n\t__le32 hw_next;\n\t__le32 hw_transaction[8];\n\t__le32 hw_bufp[7];\n\t__le32 hw_bufp_hi[7];\n\tdma_addr_t itd_dma;\n\tunion ehci_shadow itd_next;\n\tstruct urb *urb;\n\tstruct ehci_iso_stream *stream;\n\tstruct list_head itd_list;\n\tunsigned int frame;\n\tunsigned int pg;\n\tunsigned int index[8];\n\tlong: 64;\n};\n\nstruct ehci_sitd {\n\t__le32 hw_next;\n\t__le32 hw_fullspeed_ep;\n\t__le32 hw_uframe;\n\t__le32 hw_results;\n\t__le32 hw_buf[2];\n\t__le32 hw_backpointer;\n\t__le32 hw_buf_hi[2];\n\tdma_addr_t sitd_dma;\n\tunion ehci_shadow sitd_next;\n\tstruct urb *urb;\n\tstruct ehci_iso_stream *stream;\n\tstruct list_head sitd_list;\n\tunsigned int frame;\n\tunsigned int index;\n};\n\nstruct ehci_qtd {\n\t__le32 hw_next;\n\t__le32 hw_alt_next;\n\t__le32 hw_token;\n\t__le32 hw_buf[5];\n\t__le32 hw_buf_hi[5];\n\tdma_addr_t qtd_dma;\n\tstruct list_head qtd_list;\n\tstruct urb *urb;\n\tsize_t length;\n};\n\nstruct ehci_fstn {\n\t__le32 hw_next;\n\t__le32 hw_prev;\n\tdma_addr_t fstn_dma;\n\tunion ehci_shadow fstn_next;\n\tlong: 64;\n};\n\nstruct ehci_qh_hw {\n\t__le32 hw_next;\n\t__le32 hw_info1;\n\t__le32 hw_info2;\n\t__le32 hw_current;\n\t__le32 hw_qtd_next;\n\t__le32 hw_alt_next;\n\t__le32 hw_token;\n\t__le32 hw_buf[5];\n\t__le32 hw_buf_hi[5];\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct ehci_iso_packet {\n\tu64 bufp;\n\t__le32 transaction;\n\tu8 cross;\n\tu32 buf1;\n};\n\nstruct ehci_iso_sched {\n\tstruct list_head td_list;\n\tunsigned int span;\n\tunsigned int first_packet;\n\tstruct ehci_iso_packet packet[0];\n};\n\nstruct ehci_iso_stream {\n\tstruct ehci_qh_hw *hw;\n\tu8 bEndpointAddress;\n\tu8 highspeed;\n\tstruct list_head td_list;\n\tstruct list_head free_list;\n\tstruct ehci_per_sched ps;\n\tunsigned int next_uframe;\n\t__le32 splits;\n\tu16 uperiod;\n\tu16 maxp;\n\tunsigned int bandwidth;\n\t__le32 buf0;\n\t__le32 buf1;\n\t__le32 buf2;\n\t__le32 address;\n};\n\nstruct ehci_tt {\n\tu16 bandwidth[8];\n\tstruct list_head tt_list;\n\tstruct list_head ps_list;\n\tstruct usb_tt *usb_tt;\n\tint tt_port;\n};\n\nstruct ehci_driver_overrides {\n\tsize_t extra_priv_size;\n\tint (*reset)(struct usb_hcd *);\n\tint (*port_power)(struct usb_hcd *, int, bool);\n};\n\nstruct debug_buffer {\n\tssize_t (*fill_func)(struct debug_buffer *);\n\tstruct usb_bus *bus;\n\tstruct mutex mutex;\n\tsize_t count;\n\tchar *output_buf;\n\tsize_t alloc_size;\n};\n\ntypedef __u32 __hc32;\n\ntypedef __u16 __hc16;\n\nstruct td;\n\nstruct ed {\n\t__hc32 hwINFO;\n\t__hc32 hwTailP;\n\t__hc32 hwHeadP;\n\t__hc32 hwNextED;\n\tdma_addr_t dma;\n\tstruct td *dummy;\n\tstruct ed *ed_next;\n\tstruct ed *ed_prev;\n\tstruct list_head td_list;\n\tstruct list_head in_use_list;\n\tu8 state;\n\tu8 type;\n\tu8 branch;\n\tu16 interval;\n\tu16 load;\n\tu16 last_iso;\n\tu16 tick;\n\tunsigned int takeback_wdh_cnt;\n\tstruct td *pending_td;\n\tlong: 64;\n};\n\nstruct td {\n\t__hc32 hwINFO;\n\t__hc32 hwCBP;\n\t__hc32 hwNextTD;\n\t__hc32 hwBE;\n\t__hc16 hwPSW[2];\n\t__u8 index;\n\tstruct ed *ed;\n\tstruct td *td_hash;\n\tstruct td *next_dl_td;\n\tstruct urb *urb;\n\tdma_addr_t td_dma;\n\tdma_addr_t data_dma;\n\tstruct list_head td_list;\n\tlong: 64;\n};\n\nstruct ohci_hcca {\n\t__hc32 int_table[32];\n\t__hc32 frame_no;\n\t__hc32 done_head;\n\tu8 reserved_for_hc[116];\n\tu8 what[4];\n};\n\nstruct ohci_roothub_regs {\n\t__hc32 a;\n\t__hc32 b;\n\t__hc32 status;\n\t__hc32 portstatus[15];\n};\n\nstruct ohci_regs {\n\t__hc32 revision;\n\t__hc32 control;\n\t__hc32 cmdstatus;\n\t__hc32 intrstatus;\n\t__hc32 intrenable;\n\t__hc32 intrdisable;\n\t__hc32 hcca;\n\t__hc32 ed_periodcurrent;\n\t__hc32 ed_controlhead;\n\t__hc32 ed_controlcurrent;\n\t__hc32 ed_bulkhead;\n\t__hc32 ed_bulkcurrent;\n\t__hc32 donehead;\n\t__hc32 fminterval;\n\t__hc32 fmremaining;\n\t__hc32 fmnumber;\n\t__hc32 periodicstart;\n\t__hc32 lsthresh;\n\tstruct ohci_roothub_regs roothub;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct urb_priv {\n\tstruct ed *ed;\n\tu16 length;\n\tu16 td_cnt;\n\tstruct list_head pending;\n\tstruct td *td[0];\n};\n\ntypedef struct urb_priv urb_priv_t;\n\nenum ohci_rh_state {\n\tOHCI_RH_HALTED = 0,\n\tOHCI_RH_SUSPENDED = 1,\n\tOHCI_RH_RUNNING = 2,\n};\n\nstruct ohci_hcd {\n\tspinlock_t lock;\n\tstruct ohci_regs *regs;\n\tstruct ohci_hcca *hcca;\n\tdma_addr_t hcca_dma;\n\tstruct ed *ed_rm_list;\n\tstruct ed *ed_bulktail;\n\tstruct ed *ed_controltail;\n\tstruct ed *periodic[32];\n\tvoid (*start_hnp)(struct ohci_hcd *);\n\tstruct dma_pool___2 *td_cache;\n\tstruct dma_pool___2 *ed_cache;\n\tstruct td *td_hash[64];\n\tstruct td *dl_start;\n\tstruct td *dl_end;\n\tstruct list_head pending;\n\tstruct list_head eds_in_use;\n\tenum ohci_rh_state rh_state;\n\tint num_ports;\n\tint load[32];\n\tu32 hc_control;\n\tlong unsigned int next_statechange;\n\tu32 fminterval;\n\tunsigned int autostop: 1;\n\tunsigned int working: 1;\n\tunsigned int restart_work: 1;\n\tlong unsigned int flags;\n\tunsigned int prev_frame_no;\n\tunsigned int wdh_cnt;\n\tunsigned int prev_wdh_cnt;\n\tu32 prev_donehead;\n\tstruct timer_list io_watchdog;\n\tstruct work_struct nec_work;\n\tstruct dentry *debug_dir;\n\tlong unsigned int priv[0];\n};\n\nstruct ohci_driver_overrides {\n\tconst char *product_desc;\n\tsize_t extra_priv_size;\n\tint (*reset)(struct usb_hcd *);\n};\n\nstruct debug_buffer___2 {\n\tssize_t (*fill_func)(struct debug_buffer___2 *);\n\tstruct ohci_hcd *ohci;\n\tstruct mutex mutex;\n\tsize_t count;\n\tchar *page;\n};\n\nstruct uhci_td;\n\nstruct uhci_qh {\n\t__le32 link;\n\t__le32 element;\n\tdma_addr_t dma_handle;\n\tstruct list_head node;\n\tstruct usb_host_endpoint *hep;\n\tstruct usb_device *udev;\n\tstruct list_head queue;\n\tstruct uhci_td *dummy_td;\n\tstruct uhci_td *post_td;\n\tstruct usb_iso_packet_descriptor *iso_packet_desc;\n\tlong unsigned int advance_jiffies;\n\tunsigned int unlink_frame;\n\tunsigned int period;\n\tshort int phase;\n\tshort int load;\n\tunsigned int iso_frame;\n\tint state;\n\tint type;\n\tint skel;\n\tunsigned int initial_toggle: 1;\n\tunsigned int needs_fixup: 1;\n\tunsigned int is_stopped: 1;\n\tunsigned int wait_expired: 1;\n\tunsigned int bandwidth_reserved: 1;\n};\n\nstruct uhci_td {\n\t__le32 link;\n\t__le32 status;\n\t__le32 token;\n\t__le32 buffer;\n\tdma_addr_t dma_handle;\n\tstruct list_head list;\n\tint frame;\n\tstruct list_head fl_list;\n};\n\nenum uhci_rh_state {\n\tUHCI_RH_RESET = 0,\n\tUHCI_RH_SUSPENDED = 1,\n\tUHCI_RH_AUTO_STOPPED = 2,\n\tUHCI_RH_RESUMING = 3,\n\tUHCI_RH_SUSPENDING = 4,\n\tUHCI_RH_RUNNING = 5,\n\tUHCI_RH_RUNNING_NODEVS = 6,\n};\n\nstruct uhci_hcd {\n\tlong unsigned int io_addr;\n\tvoid *regs;\n\tstruct dma_pool___2 *qh_pool;\n\tstruct dma_pool___2 *td_pool;\n\tstruct uhci_td *term_td;\n\tstruct uhci_qh *skelqh[11];\n\tstruct uhci_qh *next_qh;\n\tspinlock_t lock;\n\tdma_addr_t frame_dma_handle;\n\t__le32 *frame;\n\tvoid **frame_cpu;\n\tenum uhci_rh_state rh_state;\n\tlong unsigned int auto_stop_time;\n\tunsigned int frame_number;\n\tunsigned int is_stopped;\n\tunsigned int last_iso_frame;\n\tunsigned int cur_iso_frame;\n\tunsigned int scan_in_progress: 1;\n\tunsigned int need_rescan: 1;\n\tunsigned int dead: 1;\n\tunsigned int RD_enable: 1;\n\tunsigned int is_initialized: 1;\n\tunsigned int fsbr_is_on: 1;\n\tunsigned int fsbr_is_wanted: 1;\n\tunsigned int fsbr_expiring: 1;\n\tstruct timer_list fsbr_timer;\n\tunsigned int oc_low: 1;\n\tunsigned int wait_for_hp: 1;\n\tunsigned int big_endian_mmio: 1;\n\tunsigned int big_endian_desc: 1;\n\tunsigned int is_aspeed: 1;\n\tlong unsigned int port_c_suspend;\n\tlong unsigned int resuming_ports;\n\tlong unsigned int ports_timeout;\n\tstruct list_head idle_qh_list;\n\tint rh_numports;\n\twait_queue_head_t waitqh;\n\tint num_waiting;\n\tint total_load;\n\tshort int load[32];\n\tstruct clk *clk;\n\tvoid (*reset_hc)(struct uhci_hcd *);\n\tint (*check_and_reset_hc)(struct uhci_hcd *);\n\tvoid (*configure_hc)(struct uhci_hcd *);\n\tint (*resume_detect_interrupts_are_broken)(struct uhci_hcd *);\n\tint (*global_suspend_mode_is_broken)(struct uhci_hcd *);\n};\n\nstruct urb_priv___2 {\n\tstruct list_head node;\n\tstruct urb *urb;\n\tstruct uhci_qh *qh;\n\tstruct list_head td_list;\n\tunsigned int fsbr: 1;\n};\n\nstruct uhci_debug {\n\tint size;\n\tchar *data;\n};\n\nstruct xhci_cap_regs {\n\t__le32 hc_capbase;\n\t__le32 hcs_params1;\n\t__le32 hcs_params2;\n\t__le32 hcs_params3;\n\t__le32 hcc_params;\n\t__le32 db_off;\n\t__le32 run_regs_off;\n\t__le32 hcc_params2;\n};\n\nstruct xhci_op_regs {\n\t__le32 command;\n\t__le32 status;\n\t__le32 page_size;\n\t__le32 reserved1;\n\t__le32 reserved2;\n\t__le32 dev_notification;\n\t__le64 cmd_ring;\n\t__le32 reserved3[4];\n\t__le64 dcbaa_ptr;\n\t__le32 config_reg;\n\t__le32 reserved4[241];\n\t__le32 port_status_base;\n\t__le32 port_power_base;\n\t__le32 port_link_base;\n\t__le32 reserved5;\n\t__le32 reserved6[1016];\n};\n\nstruct xhci_intr_reg {\n\t__le32 irq_pending;\n\t__le32 irq_control;\n\t__le32 erst_size;\n\t__le32 rsvd;\n\t__le64 erst_base;\n\t__le64 erst_dequeue;\n};\n\nstruct xhci_run_regs {\n\t__le32 microframe_index;\n\t__le32 rsvd[7];\n\tstruct xhci_intr_reg ir_set[128];\n};\n\nstruct xhci_doorbell_array {\n\t__le32 doorbell[256];\n};\n\nstruct xhci_container_ctx {\n\tunsigned int type;\n\tint size;\n\tu8 *bytes;\n\tdma_addr_t dma;\n};\n\nstruct xhci_slot_ctx {\n\t__le32 dev_info;\n\t__le32 dev_info2;\n\t__le32 tt_info;\n\t__le32 dev_state;\n\t__le32 reserved[4];\n};\n\nstruct xhci_ep_ctx {\n\t__le32 ep_info;\n\t__le32 ep_info2;\n\t__le64 deq;\n\t__le32 tx_info;\n\t__le32 reserved[3];\n};\n\nstruct xhci_input_control_ctx {\n\t__le32 drop_flags;\n\t__le32 add_flags;\n\t__le32 rsvd2[6];\n};\n\nunion xhci_trb;\n\nstruct xhci_command {\n\tstruct xhci_container_ctx *in_ctx;\n\tu32 status;\n\tint slot_id;\n\tstruct completion *completion;\n\tunion xhci_trb *command_trb;\n\tstruct list_head cmd_list;\n};\n\nstruct xhci_link_trb {\n\t__le64 segment_ptr;\n\t__le32 intr_target;\n\t__le32 control;\n};\n\nstruct xhci_transfer_event {\n\t__le64 buffer;\n\t__le32 transfer_len;\n\t__le32 flags;\n};\n\nstruct xhci_event_cmd {\n\t__le64 cmd_trb;\n\t__le32 status;\n\t__le32 flags;\n};\n\nstruct xhci_generic_trb {\n\t__le32 field[4];\n};\n\nunion xhci_trb {\n\tstruct xhci_link_trb link;\n\tstruct xhci_transfer_event trans_event;\n\tstruct xhci_event_cmd event_cmd;\n\tstruct xhci_generic_trb generic;\n};\n\nstruct xhci_stream_ctx {\n\t__le64 stream_ring;\n\t__le32 reserved[2];\n};\n\nstruct xhci_ring;\n\nstruct xhci_stream_info {\n\tstruct xhci_ring **stream_rings;\n\tunsigned int num_streams;\n\tstruct xhci_stream_ctx *stream_ctx_array;\n\tunsigned int num_stream_ctxs;\n\tdma_addr_t ctx_array_dma;\n\tstruct xarray trb_address_map;\n\tstruct xhci_command *free_streams_command;\n};\n\nenum xhci_ring_type {\n\tTYPE_CTRL = 0,\n\tTYPE_ISOC = 1,\n\tTYPE_BULK = 2,\n\tTYPE_INTR = 3,\n\tTYPE_STREAM = 4,\n\tTYPE_COMMAND = 5,\n\tTYPE_EVENT = 6,\n};\n\nstruct xhci_segment;\n\nstruct xhci_ring {\n\tstruct xhci_segment *first_seg;\n\tstruct xhci_segment *last_seg;\n\tunion xhci_trb *enqueue;\n\tstruct xhci_segment *enq_seg;\n\tunion xhci_trb *dequeue;\n\tstruct xhci_segment *deq_seg;\n\tstruct list_head td_list;\n\tu32 cycle_state;\n\tunsigned int err_count;\n\tunsigned int stream_id;\n\tunsigned int num_segs;\n\tunsigned int num_trbs_free;\n\tunsigned int num_trbs_free_temp;\n\tunsigned int bounce_buf_len;\n\tenum xhci_ring_type type;\n\tbool last_td_was_short;\n\tstruct xarray *trb_address_map;\n};\n\nstruct xhci_bw_info {\n\tunsigned int ep_interval;\n\tunsigned int mult;\n\tunsigned int num_packets;\n\tunsigned int max_packet_size;\n\tunsigned int max_esit_payload;\n\tunsigned int type;\n};\n\nstruct xhci_virt_device;\n\nstruct xhci_hcd;\n\nstruct xhci_virt_ep {\n\tstruct xhci_virt_device *vdev;\n\tunsigned int ep_index;\n\tstruct xhci_ring *ring;\n\tstruct xhci_stream_info *stream_info;\n\tstruct xhci_ring *new_ring;\n\tunsigned int ep_state;\n\tstruct list_head cancelled_td_list;\n\tstruct timer_list stop_cmd_timer;\n\tstruct xhci_hcd *xhci;\n\tstruct xhci_segment *queued_deq_seg;\n\tunion xhci_trb *queued_deq_ptr;\n\tbool skip;\n\tstruct xhci_bw_info bw_info;\n\tstruct list_head bw_endpoint_list;\n\tint next_frame_id;\n\tbool use_extended_tbc;\n};\n\nstruct xhci_interval_bw_table;\n\nstruct xhci_tt_bw_info;\n\nstruct xhci_virt_device {\n\tint slot_id;\n\tstruct usb_device *udev;\n\tstruct xhci_container_ctx *out_ctx;\n\tstruct xhci_container_ctx *in_ctx;\n\tstruct xhci_virt_ep eps[31];\n\tu8 fake_port;\n\tu8 real_port;\n\tstruct xhci_interval_bw_table *bw_table;\n\tstruct xhci_tt_bw_info *tt_info;\n\tlong unsigned int flags;\n\tu16 current_mel;\n\tvoid *debugfs_private;\n};\n\nstruct xhci_erst_entry;\n\nstruct xhci_erst {\n\tstruct xhci_erst_entry *entries;\n\tunsigned int num_entries;\n\tdma_addr_t erst_dma_addr;\n\tunsigned int erst_size;\n};\n\nstruct s3_save {\n\tu32 command;\n\tu32 dev_nt;\n\tu64 dcbaa_ptr;\n\tu32 config_reg;\n\tu32 irq_pending;\n\tu32 irq_control;\n\tu32 erst_size;\n\tu64 erst_base;\n\tu64 erst_dequeue;\n};\n\nstruct xhci_bus_state {\n\tlong unsigned int bus_suspended;\n\tlong unsigned int next_statechange;\n\tu32 port_c_suspend;\n\tu32 suspended_ports;\n\tu32 port_remote_wakeup;\n\tlong unsigned int resume_done[31];\n\tlong unsigned int resuming_ports;\n\tlong unsigned int rexit_ports;\n\tstruct completion rexit_done[31];\n\tstruct completion u3exit_done[31];\n};\n\nstruct xhci_port;\n\nstruct xhci_hub {\n\tstruct xhci_port **ports;\n\tunsigned int num_ports;\n\tstruct usb_hcd *hcd;\n\tstruct xhci_bus_state bus_state;\n\tu8 maj_rev;\n\tu8 min_rev;\n};\n\nstruct xhci_device_context_array;\n\nstruct xhci_scratchpad;\n\nstruct xhci_root_port_bw_info;\n\nstruct xhci_port_cap;\n\nstruct xhci_hcd {\n\tstruct usb_hcd *main_hcd;\n\tstruct usb_hcd *shared_hcd;\n\tstruct xhci_cap_regs *cap_regs;\n\tstruct xhci_op_regs *op_regs;\n\tstruct xhci_run_regs *run_regs;\n\tstruct xhci_doorbell_array *dba;\n\tstruct xhci_intr_reg *ir_set;\n\t__u32 hcs_params1;\n\t__u32 hcs_params2;\n\t__u32 hcs_params3;\n\t__u32 hcc_params;\n\t__u32 hcc_params2;\n\tspinlock_t lock;\n\tu8 sbrn;\n\tu16 hci_version;\n\tu8 max_slots;\n\tu8 max_interrupters;\n\tu8 max_ports;\n\tu8 isoc_threshold;\n\tu32 imod_interval;\n\tu32 isoc_bei_interval;\n\tint event_ring_max;\n\tint page_size;\n\tint page_shift;\n\tint msix_count;\n\tstruct clk *clk;\n\tstruct clk *reg_clk;\n\tstruct reset_control *reset;\n\tstruct xhci_device_context_array *dcbaa;\n\tstruct xhci_ring *cmd_ring;\n\tunsigned int cmd_ring_state;\n\tstruct list_head cmd_list;\n\tunsigned int cmd_ring_reserved_trbs;\n\tstruct delayed_work cmd_timer;\n\tstruct completion cmd_ring_stop_completion;\n\tstruct xhci_command *current_cmd;\n\tstruct xhci_ring *event_ring;\n\tstruct xhci_erst erst;\n\tstruct xhci_scratchpad *scratchpad;\n\tstruct list_head lpm_failed_devs;\n\tstruct mutex mutex;\n\tstruct xhci_command *lpm_command;\n\tstruct xhci_virt_device *devs[256];\n\tstruct xhci_root_port_bw_info *rh_bw;\n\tstruct dma_pool___2 *device_pool;\n\tstruct dma_pool___2 *segment_pool;\n\tstruct dma_pool___2 *small_streams_pool;\n\tstruct dma_pool___2 *medium_streams_pool;\n\tunsigned int xhc_state;\n\tu32 command;\n\tstruct s3_save s3;\n\tlong long unsigned int quirks;\n\tunsigned int num_active_eps;\n\tunsigned int limit_active_eps;\n\tstruct xhci_port *hw_ports;\n\tstruct xhci_hub usb2_rhub;\n\tstruct xhci_hub usb3_rhub;\n\tunsigned int hw_lpm_support: 1;\n\tunsigned int broken_suspend: 1;\n\tu32 *ext_caps;\n\tunsigned int num_ext_caps;\n\tstruct xhci_port_cap *port_caps;\n\tunsigned int num_port_caps;\n\tstruct timer_list comp_mode_recovery_timer;\n\tu32 port_status_u0;\n\tu16 test_mode;\n\tstruct dentry *debugfs_root;\n\tstruct dentry *debugfs_slots;\n\tstruct list_head regset_list;\n\tvoid *dbc;\n\tlong unsigned int priv[0];\n};\n\nstruct xhci_segment {\n\tunion xhci_trb *trbs;\n\tstruct xhci_segment *next;\n\tdma_addr_t dma;\n\tdma_addr_t bounce_dma;\n\tvoid *bounce_buf;\n\tunsigned int bounce_offs;\n\tunsigned int bounce_len;\n};\n\nenum xhci_overhead_type {\n\tLS_OVERHEAD_TYPE = 0,\n\tFS_OVERHEAD_TYPE = 1,\n\tHS_OVERHEAD_TYPE = 2,\n};\n\nstruct xhci_interval_bw {\n\tunsigned int num_packets;\n\tstruct list_head endpoints;\n\tunsigned int overhead[3];\n};\n\nstruct xhci_interval_bw_table {\n\tunsigned int interval0_esit_payload;\n\tstruct xhci_interval_bw interval_bw[16];\n\tunsigned int bw_used;\n\tunsigned int ss_bw_in;\n\tunsigned int ss_bw_out;\n};\n\nstruct xhci_tt_bw_info {\n\tstruct list_head tt_list;\n\tint slot_id;\n\tint ttport;\n\tstruct xhci_interval_bw_table bw_table;\n\tint active_eps;\n};\n\nstruct xhci_root_port_bw_info {\n\tstruct list_head tts;\n\tunsigned int num_active_tts;\n\tstruct xhci_interval_bw_table bw_table;\n};\n\nstruct xhci_device_context_array {\n\t__le64 dev_context_ptrs[256];\n\tdma_addr_t dma;\n};\n\nenum xhci_setup_dev {\n\tSETUP_CONTEXT_ONLY = 0,\n\tSETUP_CONTEXT_ADDRESS = 1,\n};\n\nenum xhci_cancelled_td_status {\n\tTD_DIRTY = 0,\n\tTD_HALTED = 1,\n\tTD_CLEARING_CACHE = 2,\n\tTD_CLEARED = 3,\n};\n\nstruct xhci_td {\n\tstruct list_head td_list;\n\tstruct list_head cancelled_td_list;\n\tint status;\n\tenum xhci_cancelled_td_status cancel_status;\n\tstruct urb *urb;\n\tstruct xhci_segment *start_seg;\n\tunion xhci_trb *first_trb;\n\tunion xhci_trb *last_trb;\n\tstruct xhci_segment *last_trb_seg;\n\tstruct xhci_segment *bounce_seg;\n\tbool urb_length_set;\n\tunsigned int num_trbs;\n};\n\nstruct xhci_erst_entry {\n\t__le64 seg_addr;\n\t__le32 seg_size;\n\t__le32 rsvd;\n};\n\nstruct xhci_scratchpad {\n\tu64 *sp_array;\n\tdma_addr_t sp_dma;\n\tvoid **sp_buffers;\n};\n\nstruct urb_priv___3 {\n\tint num_tds;\n\tint num_tds_done;\n\tstruct xhci_td td[0];\n};\n\nstruct xhci_port_cap {\n\tu32 *psi;\n\tu8 psi_count;\n\tu8 psi_uid_count;\n\tu8 maj_rev;\n\tu8 min_rev;\n};\n\nstruct xhci_port {\n\t__le32 *addr;\n\tint hw_portnum;\n\tint hcd_portnum;\n\tstruct xhci_hub *rhub;\n\tstruct xhci_port_cap *port_cap;\n};\n\nstruct xhci_driver_overrides {\n\tsize_t extra_priv_size;\n\tint (*reset)(struct usb_hcd *);\n\tint (*start)(struct usb_hcd *);\n\tint (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);\n\tint (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);\n\tint (*check_bandwidth)(struct usb_hcd *, struct usb_device *);\n\tvoid (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);\n};\n\ntypedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);\n\nenum xhci_ep_reset_type {\n\tEP_HARD_RESET = 0,\n\tEP_SOFT_RESET = 1,\n};\n\nstruct dbc_regs {\n\t__le32 capability;\n\t__le32 doorbell;\n\t__le32 ersts;\n\t__le32 __reserved_0;\n\t__le64 erstba;\n\t__le64 erdp;\n\t__le32 control;\n\t__le32 status;\n\t__le32 portsc;\n\t__le32 __reserved_1;\n\t__le64 dccp;\n\t__le32 devinfo1;\n\t__le32 devinfo2;\n};\n\nstruct dbc_str_descs {\n\tchar string0[64];\n\tchar manufacturer[64];\n\tchar product[64];\n\tchar serial[64];\n};\n\nenum dbc_state {\n\tDS_DISABLED = 0,\n\tDS_INITIALIZED = 1,\n\tDS_ENABLED = 2,\n\tDS_CONNECTED = 3,\n\tDS_CONFIGURED = 4,\n\tDS_STALLED = 5,\n};\n\nstruct xhci_dbc;\n\nstruct dbc_ep {\n\tstruct xhci_dbc *dbc;\n\tstruct list_head list_pending;\n\tstruct xhci_ring *ring;\n\tunsigned int direction: 1;\n};\n\nstruct dbc_driver;\n\nstruct xhci_dbc {\n\tspinlock_t lock;\n\tstruct device *dev;\n\tstruct xhci_hcd *xhci;\n\tstruct dbc_regs *regs;\n\tstruct xhci_ring *ring_evt;\n\tstruct xhci_ring *ring_in;\n\tstruct xhci_ring *ring_out;\n\tstruct xhci_erst erst;\n\tstruct xhci_container_ctx *ctx;\n\tstruct dbc_str_descs *string;\n\tdma_addr_t string_dma;\n\tsize_t string_size;\n\tenum dbc_state state;\n\tstruct delayed_work event_work;\n\tunsigned int resume_required: 1;\n\tstruct dbc_ep eps[2];\n\tconst struct dbc_driver *driver;\n\tvoid *priv;\n};\n\nstruct dbc_driver {\n\tint (*configure)(struct xhci_dbc *);\n\tvoid (*disconnect)(struct xhci_dbc *);\n};\n\nstruct dbc_request {\n\tvoid *buf;\n\tunsigned int length;\n\tdma_addr_t dma;\n\tvoid (*complete)(struct xhci_dbc *, struct dbc_request *);\n\tstruct list_head list_pool;\n\tint status;\n\tunsigned int actual;\n\tstruct xhci_dbc *dbc;\n\tstruct list_head list_pending;\n\tdma_addr_t trb_dma;\n\tunion xhci_trb *trb;\n\tunsigned int direction: 1;\n};\n\nstruct trace_event_raw_xhci_log_msg {\n\tstruct trace_entry ent;\n\tu32 __data_loc_msg;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_ctx {\n\tstruct trace_entry ent;\n\tint ctx_64;\n\tunsigned int ctx_type;\n\tdma_addr_t ctx_dma;\n\tu8 *ctx_va;\n\tunsigned int ctx_ep_num;\n\tint slot_id;\n\tu32 __data_loc_ctx_data;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_trb {\n\tstruct trace_entry ent;\n\tu32 type;\n\tu32 field0;\n\tu32 field1;\n\tu32 field2;\n\tu32 field3;\n\tu32 __data_loc_str;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_free_virt_dev {\n\tstruct trace_entry ent;\n\tvoid *vdev;\n\tlong long unsigned int out_ctx;\n\tlong long unsigned int in_ctx;\n\tu8 fake_port;\n\tu8 real_port;\n\tu16 current_mel;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_virt_dev {\n\tstruct trace_entry ent;\n\tvoid *vdev;\n\tlong long unsigned int out_ctx;\n\tlong long unsigned int in_ctx;\n\tint devnum;\n\tint state;\n\tint speed;\n\tu8 portnum;\n\tu8 level;\n\tint slot_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_urb {\n\tstruct trace_entry ent;\n\tvoid *urb;\n\tunsigned int pipe;\n\tunsigned int stream;\n\tint status;\n\tunsigned int flags;\n\tint num_mapped_sgs;\n\tint num_sgs;\n\tint length;\n\tint actual;\n\tint epnum;\n\tint dir_in;\n\tint type;\n\tint slot_id;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_ep_ctx {\n\tstruct trace_entry ent;\n\tu32 info;\n\tu32 info2;\n\tu64 deq;\n\tu32 tx_info;\n\tu32 __data_loc_str;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_slot_ctx {\n\tstruct trace_entry ent;\n\tu32 info;\n\tu32 info2;\n\tu32 tt_info;\n\tu32 state;\n\tu32 __data_loc_str;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_ctrl_ctx {\n\tstruct trace_entry ent;\n\tu32 drop;\n\tu32 add;\n\tu32 __data_loc_str;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_ring {\n\tstruct trace_entry ent;\n\tu32 type;\n\tvoid *ring;\n\tdma_addr_t enq;\n\tdma_addr_t deq;\n\tdma_addr_t enq_seg;\n\tdma_addr_t deq_seg;\n\tunsigned int num_segs;\n\tunsigned int stream_id;\n\tunsigned int cycle_state;\n\tunsigned int num_trbs_free;\n\tunsigned int bounce_buf_len;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_portsc {\n\tstruct trace_entry ent;\n\tu32 portnum;\n\tu32 portsc;\n\tu32 __data_loc_str;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_log_doorbell {\n\tstruct trace_entry ent;\n\tu32 slot;\n\tu32 doorbell;\n\tu32 __data_loc_str;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_xhci_dbc_log_request {\n\tstruct trace_entry ent;\n\tstruct dbc_request *req;\n\tbool dir;\n\tunsigned int actual;\n\tunsigned int length;\n\tint status;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_xhci_log_msg {\n\tu32 msg;\n};\n\nstruct trace_event_data_offsets_xhci_log_ctx {\n\tu32 ctx_data;\n};\n\nstruct trace_event_data_offsets_xhci_log_trb {\n\tu32 str;\n};\n\nstruct trace_event_data_offsets_xhci_log_free_virt_dev {};\n\nstruct trace_event_data_offsets_xhci_log_virt_dev {};\n\nstruct trace_event_data_offsets_xhci_log_urb {};\n\nstruct trace_event_data_offsets_xhci_log_ep_ctx {\n\tu32 str;\n};\n\nstruct trace_event_data_offsets_xhci_log_slot_ctx {\n\tu32 str;\n};\n\nstruct trace_event_data_offsets_xhci_log_ctrl_ctx {\n\tu32 str;\n};\n\nstruct trace_event_data_offsets_xhci_log_ring {};\n\nstruct trace_event_data_offsets_xhci_log_portsc {\n\tu32 str;\n};\n\nstruct trace_event_data_offsets_xhci_log_doorbell {\n\tu32 str;\n};\n\nstruct trace_event_data_offsets_xhci_dbc_log_request {};\n\ntypedef void (*btf_trace_xhci_dbg_address)(void *, struct va_format *);\n\ntypedef void (*btf_trace_xhci_dbg_context_change)(void *, struct va_format *);\n\ntypedef void (*btf_trace_xhci_dbg_quirks)(void *, struct va_format *);\n\ntypedef void (*btf_trace_xhci_dbg_reset_ep)(void *, struct va_format *);\n\ntypedef void (*btf_trace_xhci_dbg_cancel_urb)(void *, struct va_format *);\n\ntypedef void (*btf_trace_xhci_dbg_init)(void *, struct va_format *);\n\ntypedef void (*btf_trace_xhci_dbg_ring_expansion)(void *, struct va_format *);\n\ntypedef void (*btf_trace_xhci_address_ctx)(void *, struct xhci_hcd *, struct xhci_container_ctx *, unsigned int);\n\ntypedef void (*btf_trace_xhci_handle_event)(void *, struct xhci_ring *, struct xhci_generic_trb *);\n\ntypedef void (*btf_trace_xhci_handle_command)(void *, struct xhci_ring *, struct xhci_generic_trb *);\n\ntypedef void (*btf_trace_xhci_handle_transfer)(void *, struct xhci_ring *, struct xhci_generic_trb *);\n\ntypedef void (*btf_trace_xhci_queue_trb)(void *, struct xhci_ring *, struct xhci_generic_trb *);\n\ntypedef void (*btf_trace_xhci_dbc_handle_event)(void *, struct xhci_ring *, struct xhci_generic_trb *);\n\ntypedef void (*btf_trace_xhci_dbc_handle_transfer)(void *, struct xhci_ring *, struct xhci_generic_trb *);\n\ntypedef void (*btf_trace_xhci_dbc_gadget_ep_queue)(void *, struct xhci_ring *, struct xhci_generic_trb *);\n\ntypedef void (*btf_trace_xhci_free_virt_device)(void *, struct xhci_virt_device *);\n\ntypedef void (*btf_trace_xhci_alloc_virt_device)(void *, struct xhci_virt_device *);\n\ntypedef void (*btf_trace_xhci_setup_device)(void *, struct xhci_virt_device *);\n\ntypedef void (*btf_trace_xhci_setup_addressable_virt_device)(void *, struct xhci_virt_device *);\n\ntypedef void (*btf_trace_xhci_stop_device)(void *, struct xhci_virt_device *);\n\ntypedef void (*btf_trace_xhci_urb_enqueue)(void *, struct urb *);\n\ntypedef void (*btf_trace_xhci_urb_giveback)(void *, struct urb *);\n\ntypedef void (*btf_trace_xhci_urb_dequeue)(void *, struct urb *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_stop_ep)(void *, struct xhci_ep_ctx *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_set_deq_ep)(void *, struct xhci_ep_ctx *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_reset_ep)(void *, struct xhci_ep_ctx *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_config_ep)(void *, struct xhci_ep_ctx *);\n\ntypedef void (*btf_trace_xhci_add_endpoint)(void *, struct xhci_ep_ctx *);\n\ntypedef void (*btf_trace_xhci_alloc_dev)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_free_dev)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_disable_slot)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_discover_or_reset_device)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_setup_device_slot)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_addr_dev)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_reset_dev)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_handle_cmd_set_deq)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_configure_endpoint)(void *, struct xhci_slot_ctx *);\n\ntypedef void (*btf_trace_xhci_address_ctrl_ctx)(void *, struct xhci_input_control_ctx *);\n\ntypedef void (*btf_trace_xhci_configure_endpoint_ctrl_ctx)(void *, struct xhci_input_control_ctx *);\n\ntypedef void (*btf_trace_xhci_ring_alloc)(void *, struct xhci_ring *);\n\ntypedef void (*btf_trace_xhci_ring_free)(void *, struct xhci_ring *);\n\ntypedef void (*btf_trace_xhci_ring_expansion)(void *, struct xhci_ring *);\n\ntypedef void (*btf_trace_xhci_inc_enq)(void *, struct xhci_ring *);\n\ntypedef void (*btf_trace_xhci_inc_deq)(void *, struct xhci_ring *);\n\ntypedef void (*btf_trace_xhci_handle_port_status)(void *, u32, u32);\n\ntypedef void (*btf_trace_xhci_get_port_status)(void *, u32, u32);\n\ntypedef void (*btf_trace_xhci_hub_status_data)(void *, u32, u32);\n\ntypedef void (*btf_trace_xhci_ring_ep_doorbell)(void *, u32, u32);\n\ntypedef void (*btf_trace_xhci_ring_host_doorbell)(void *, u32, u32);\n\ntypedef void (*btf_trace_xhci_dbc_alloc_request)(void *, struct dbc_request *);\n\ntypedef void (*btf_trace_xhci_dbc_free_request)(void *, struct dbc_request *);\n\ntypedef void (*btf_trace_xhci_dbc_queue_request)(void *, struct dbc_request *);\n\ntypedef void (*btf_trace_xhci_dbc_giveback_request)(void *, struct dbc_request *);\n\nstruct xhci_regset {\n\tchar name[32];\n\tstruct debugfs_regset32 regset;\n\tsize_t nregs;\n\tstruct list_head list;\n};\n\nstruct xhci_file_map {\n\tconst char *name;\n\tint (*show)(struct seq_file *, void *);\n};\n\nstruct xhci_ep_priv {\n\tchar name[32];\n\tstruct dentry *root;\n\tstruct xhci_stream_info *stream_info;\n\tstruct xhci_ring *show_ring;\n\tunsigned int stream_id;\n};\n\nstruct xhci_slot_priv {\n\tchar name[32];\n\tstruct dentry *root;\n\tstruct xhci_ep_priv *eps[31];\n\tstruct xhci_virt_device *dev;\n};\n\nstruct async_icount {\n\t__u32 cts;\n\t__u32 dsr;\n\t__u32 rng;\n\t__u32 dcd;\n\t__u32 tx;\n\t__u32 rx;\n\t__u32 frame;\n\t__u32 parity;\n\t__u32 overrun;\n\t__u32 brk;\n\t__u32 buf_overrun;\n};\n\nstruct kfifo {\n\tunion {\n\t\tstruct __kfifo kfifo;\n\t\tunsigned char *type;\n\t\tconst unsigned char *const_type;\n\t\tchar (*rectype)[0];\n\t\tvoid *ptr;\n\t\tconst void *ptr_const;\n\t};\n\tunsigned char buf[0];\n};\n\nstruct usb_serial;\n\nstruct usb_serial_port {\n\tstruct usb_serial *serial;\n\tstruct tty_port port;\n\tspinlock_t lock;\n\tu32 minor;\n\tu8 port_number;\n\tunsigned char *interrupt_in_buffer;\n\tstruct urb *interrupt_in_urb;\n\t__u8 interrupt_in_endpointAddress;\n\tunsigned char *interrupt_out_buffer;\n\tint interrupt_out_size;\n\tstruct urb *interrupt_out_urb;\n\t__u8 interrupt_out_endpointAddress;\n\tunsigned char *bulk_in_buffer;\n\tint bulk_in_size;\n\tstruct urb *read_urb;\n\t__u8 bulk_in_endpointAddress;\n\tunsigned char *bulk_in_buffers[2];\n\tstruct urb *read_urbs[2];\n\tlong unsigned int read_urbs_free;\n\tunsigned char *bulk_out_buffer;\n\tint bulk_out_size;\n\tstruct urb *write_urb;\n\tstruct kfifo write_fifo;\n\tunsigned char *bulk_out_buffers[2];\n\tstruct urb *write_urbs[2];\n\tlong unsigned int write_urbs_free;\n\t__u8 bulk_out_endpointAddress;\n\tstruct async_icount icount;\n\tint tx_bytes;\n\tlong unsigned int flags;\n\tstruct work_struct work;\n\tlong unsigned int sysrq;\n\tstruct device dev;\n};\n\nstruct usb_serial_driver;\n\nstruct usb_serial {\n\tstruct usb_device *dev;\n\tstruct usb_serial_driver *type;\n\tstruct usb_interface *interface;\n\tstruct usb_interface *sibling;\n\tunsigned int suspend_count;\n\tunsigned char disconnected: 1;\n\tunsigned char attached: 1;\n\tunsigned char minors_reserved: 1;\n\tunsigned char num_ports;\n\tunsigned char num_port_pointers;\n\tunsigned char num_interrupt_in;\n\tunsigned char num_interrupt_out;\n\tunsigned char num_bulk_in;\n\tunsigned char num_bulk_out;\n\tstruct usb_serial_port *port[16];\n\tstruct kref kref;\n\tstruct mutex disc_mutex;\n\tvoid *private;\n};\n\nstruct usb_serial_endpoints;\n\nstruct usb_serial_driver {\n\tconst char *description;\n\tconst struct usb_device_id *id_table;\n\tstruct list_head driver_list;\n\tstruct device_driver driver;\n\tstruct usb_driver *usb_driver;\n\tstruct usb_dynids dynids;\n\tunsigned char num_ports;\n\tunsigned char num_bulk_in;\n\tunsigned char num_bulk_out;\n\tunsigned char num_interrupt_in;\n\tunsigned char num_interrupt_out;\n\tsize_t bulk_in_size;\n\tsize_t bulk_out_size;\n\tint (*probe)(struct usb_serial *, const struct usb_device_id *);\n\tint (*attach)(struct usb_serial *);\n\tint (*calc_num_ports)(struct usb_serial *, struct usb_serial_endpoints *);\n\tvoid (*disconnect)(struct usb_serial *);\n\tvoid (*release)(struct usb_serial *);\n\tint (*port_probe)(struct usb_serial_port *);\n\tvoid (*port_remove)(struct usb_serial_port *);\n\tint (*suspend)(struct usb_serial *, pm_message_t);\n\tint (*resume)(struct usb_serial *);\n\tint (*reset_resume)(struct usb_serial *);\n\tint (*open)(struct tty_struct *, struct usb_serial_port *);\n\tvoid (*close)(struct usb_serial_port *);\n\tint (*write)(struct tty_struct *, struct usb_serial_port *, const unsigned char *, int);\n\tunsigned int (*write_room)(struct tty_struct *);\n\tint (*ioctl)(struct tty_struct *, unsigned int, long unsigned int);\n\tvoid (*get_serial)(struct tty_struct *, struct serial_struct *);\n\tint (*set_serial)(struct tty_struct *, struct serial_struct *);\n\tvoid (*set_termios)(struct tty_struct *, struct usb_serial_port *, struct ktermios *);\n\tvoid (*break_ctl)(struct tty_struct *, int);\n\tunsigned int (*chars_in_buffer)(struct tty_struct *);\n\tvoid (*wait_until_sent)(struct tty_struct *, long int);\n\tbool (*tx_empty)(struct usb_serial_port *);\n\tvoid (*throttle)(struct tty_struct *);\n\tvoid (*unthrottle)(struct tty_struct *);\n\tint (*tiocmget)(struct tty_struct *);\n\tint (*tiocmset)(struct tty_struct *, unsigned int, unsigned int);\n\tint (*tiocmiwait)(struct tty_struct *, long unsigned int);\n\tint (*get_icount)(struct tty_struct *, struct serial_icounter_struct *);\n\tvoid (*dtr_rts)(struct usb_serial_port *, int);\n\tint (*carrier_raised)(struct usb_serial_port *);\n\tvoid (*init_termios)(struct tty_struct *);\n\tvoid (*read_int_callback)(struct urb *);\n\tvoid (*write_int_callback)(struct urb *);\n\tvoid (*read_bulk_callback)(struct urb *);\n\tvoid (*write_bulk_callback)(struct urb *);\n\tvoid (*process_read_urb)(struct urb *);\n\tint (*prepare_write_buffer)(struct usb_serial_port *, void *, size_t);\n};\n\nstruct usb_serial_endpoints {\n\tunsigned char num_bulk_in;\n\tunsigned char num_bulk_out;\n\tunsigned char num_interrupt_in;\n\tunsigned char num_interrupt_out;\n\tstruct usb_endpoint_descriptor *bulk_in[16];\n\tstruct usb_endpoint_descriptor *bulk_out[16];\n\tstruct usb_endpoint_descriptor *interrupt_in[16];\n\tstruct usb_endpoint_descriptor *interrupt_out[16];\n};\n\nstruct usbcons_info {\n\tint magic;\n\tint break_flag;\n\tstruct usb_serial_port *port;\n};\n\nstruct usb_debug_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__u8 bDebugInEndpoint;\n\t__u8 bDebugOutEndpoint;\n};\n\nstruct ehci_dev {\n\tu32 bus;\n\tu32 slot;\n\tu32 func;\n};\n\ntypedef void (*set_debug_port_t)(int);\n\nstruct usb_hcd___2;\n\nstruct usb_string_descriptor {\n\t__u8 bLength;\n\t__u8 bDescriptorType;\n\t__le16 wData[1];\n};\n\nstruct xdbc_regs {\n\t__le32 capability;\n\t__le32 doorbell;\n\t__le32 ersts;\n\t__le32 __reserved_0;\n\t__le64 erstba;\n\t__le64 erdp;\n\t__le32 control;\n\t__le32 status;\n\t__le32 portsc;\n\t__le32 __reserved_1;\n\t__le64 dccp;\n\t__le32 devinfo1;\n\t__le32 devinfo2;\n};\n\nstruct xdbc_trb {\n\t__le32 field[4];\n};\n\nstruct xdbc_erst_entry {\n\t__le64 seg_addr;\n\t__le32 seg_size;\n\t__le32 __reserved_0;\n};\n\nstruct xdbc_info_context {\n\t__le64 string0;\n\t__le64 manufacturer;\n\t__le64 product;\n\t__le64 serial;\n\t__le32 length;\n\t__le32 __reserved_0[7];\n};\n\nstruct xdbc_ep_context {\n\t__le32 ep_info1;\n\t__le32 ep_info2;\n\t__le64 deq;\n\t__le32 tx_info;\n\t__le32 __reserved_0[11];\n};\n\nstruct xdbc_context {\n\tstruct xdbc_info_context info;\n\tstruct xdbc_ep_context out;\n\tstruct xdbc_ep_context in;\n};\n\nstruct xdbc_strings {\n\tchar string0[64];\n\tchar manufacturer[64];\n\tchar product[64];\n\tchar serial[64];\n};\n\nstruct xdbc_segment {\n\tstruct xdbc_trb *trbs;\n\tdma_addr_t dma;\n};\n\nstruct xdbc_ring {\n\tstruct xdbc_segment *segment;\n\tstruct xdbc_trb *enqueue;\n\tstruct xdbc_trb *dequeue;\n\tu32 cycle_state;\n};\n\nstruct xdbc_state {\n\tu16 vendor;\n\tu16 device;\n\tu32 bus;\n\tu32 dev;\n\tu32 func;\n\tvoid *xhci_base;\n\tu64 xhci_start;\n\tsize_t xhci_length;\n\tint port_number;\n\tstruct xdbc_regs *xdbc_reg;\n\tdma_addr_t table_dma;\n\tvoid *table_base;\n\tdma_addr_t erst_dma;\n\tsize_t erst_size;\n\tvoid *erst_base;\n\tstruct xdbc_ring evt_ring;\n\tstruct xdbc_segment evt_seg;\n\tdma_addr_t dbcc_dma;\n\tsize_t dbcc_size;\n\tvoid *dbcc_base;\n\tdma_addr_t string_dma;\n\tsize_t string_size;\n\tvoid *string_base;\n\tstruct xdbc_ring out_ring;\n\tstruct xdbc_segment out_seg;\n\tvoid *out_buf;\n\tdma_addr_t out_dma;\n\tstruct xdbc_ring in_ring;\n\tstruct xdbc_segment in_seg;\n\tvoid *in_buf;\n\tdma_addr_t in_dma;\n\tu32 flags;\n\traw_spinlock_t lock;\n};\n\nstruct input_mt_slot {\n\tint abs[14];\n\tunsigned int frame;\n\tunsigned int key;\n};\n\nstruct input_mt {\n\tint trkid;\n\tint num_slots;\n\tint slot;\n\tunsigned int flags;\n\tunsigned int frame;\n\tint *red;\n\tstruct input_mt_slot slots[0];\n};\n\nunion input_seq_state {\n\tstruct {\n\t\tshort unsigned int pos;\n\t\tbool mutex_acquired;\n\t};\n\tvoid *p;\n};\n\nstruct input_devres {\n\tstruct input_dev *input;\n};\n\nstruct input_event {\n\t__kernel_ulong_t __sec;\n\t__kernel_ulong_t __usec;\n\t__u16 type;\n\t__u16 code;\n\t__s32 value;\n};\n\nstruct input_event_compat {\n\tcompat_ulong_t sec;\n\tcompat_ulong_t usec;\n\t__u16 type;\n\t__u16 code;\n\t__s32 value;\n};\n\nstruct ff_periodic_effect_compat {\n\t__u16 waveform;\n\t__u16 period;\n\t__s16 magnitude;\n\t__s16 offset;\n\t__u16 phase;\n\tstruct ff_envelope envelope;\n\t__u32 custom_len;\n\tcompat_uptr_t custom_data;\n};\n\nstruct ff_effect_compat {\n\t__u16 type;\n\t__s16 id;\n\t__u16 direction;\n\tstruct ff_trigger trigger;\n\tstruct ff_replay replay;\n\tunion {\n\t\tstruct ff_constant_effect constant;\n\t\tstruct ff_ramp_effect ramp;\n\t\tstruct ff_periodic_effect_compat periodic;\n\t\tstruct ff_condition_effect condition[2];\n\t\tstruct ff_rumble_effect rumble;\n\t} u;\n};\n\nstruct input_mt_pos {\n\ts16 x;\n\ts16 y;\n};\n\nstruct input_dev_poller {\n\tvoid (*poll)(struct input_dev *);\n\tunsigned int poll_interval;\n\tunsigned int poll_interval_max;\n\tunsigned int poll_interval_min;\n\tstruct input_dev *input;\n\tstruct delayed_work work;\n};\n\nstruct touchscreen_properties {\n\tunsigned int max_x;\n\tunsigned int max_y;\n\tbool invert_x;\n\tbool invert_y;\n\tbool swap_x_y;\n};\n\nstruct led_init_data {\n\tstruct fwnode_handle *fwnode;\n\tconst char *default_label;\n\tconst char *devicename;\n\tbool devname_mandatory;\n};\n\nstruct input_led {\n\tstruct led_classdev cdev;\n\tstruct input_handle *handle;\n\tunsigned int code;\n};\n\nstruct input_leds {\n\tstruct input_handle handle;\n\tunsigned int num_leds;\n\tstruct input_led leds[0];\n};\n\nstruct input_mask {\n\t__u32 type;\n\t__u32 codes_size;\n\t__u64 codes_ptr;\n};\n\nstruct evdev_client;\n\nstruct evdev {\n\tint open;\n\tstruct input_handle handle;\n\tstruct evdev_client *grab;\n\tstruct list_head client_list;\n\tspinlock_t client_lock;\n\tstruct mutex mutex;\n\tstruct device dev;\n\tstruct cdev cdev;\n\tbool exist;\n};\n\nstruct evdev_client {\n\tunsigned int head;\n\tunsigned int tail;\n\tunsigned int packet_head;\n\tspinlock_t buffer_lock;\n\twait_queue_head_t wait;\n\tstruct fasync_struct *fasync;\n\tstruct evdev *evdev;\n\tstruct list_head node;\n\tenum input_clock_type clk_type;\n\tbool revoked;\n\tlong unsigned int *evmasks[32];\n\tunsigned int bufsize;\n\tstruct input_event buffer[0];\n};\n\nstruct trace_event_raw_rtc_time_alarm_class {\n\tstruct trace_entry ent;\n\ttime64_t secs;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rtc_irq_set_freq {\n\tstruct trace_entry ent;\n\tint freq;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rtc_irq_set_state {\n\tstruct trace_entry ent;\n\tint enabled;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rtc_alarm_irq_enable {\n\tstruct trace_entry ent;\n\tunsigned int enabled;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rtc_offset_class {\n\tstruct trace_entry ent;\n\tlong int offset;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_rtc_timer_class {\n\tstruct trace_entry ent;\n\tstruct rtc_timer *timer;\n\tktime_t expires;\n\tktime_t period;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_rtc_time_alarm_class {};\n\nstruct trace_event_data_offsets_rtc_irq_set_freq {};\n\nstruct trace_event_data_offsets_rtc_irq_set_state {};\n\nstruct trace_event_data_offsets_rtc_alarm_irq_enable {};\n\nstruct trace_event_data_offsets_rtc_offset_class {};\n\nstruct trace_event_data_offsets_rtc_timer_class {};\n\ntypedef void (*btf_trace_rtc_set_time)(void *, time64_t, int);\n\ntypedef void (*btf_trace_rtc_read_time)(void *, time64_t, int);\n\ntypedef void (*btf_trace_rtc_set_alarm)(void *, time64_t, int);\n\ntypedef void (*btf_trace_rtc_read_alarm)(void *, time64_t, int);\n\ntypedef void (*btf_trace_rtc_irq_set_freq)(void *, int, int);\n\ntypedef void (*btf_trace_rtc_irq_set_state)(void *, int, int);\n\ntypedef void (*btf_trace_rtc_alarm_irq_enable)(void *, unsigned int, int);\n\ntypedef void (*btf_trace_rtc_set_offset)(void *, long int, int);\n\ntypedef void (*btf_trace_rtc_read_offset)(void *, long int, int);\n\ntypedef void (*btf_trace_rtc_timer_enqueue)(void *, struct rtc_timer *);\n\ntypedef void (*btf_trace_rtc_timer_dequeue)(void *, struct rtc_timer *);\n\ntypedef void (*btf_trace_rtc_timer_fired)(void *, struct rtc_timer *);\n\nenum {\n\tnone = 0,\n\tday = 1,\n\tmonth = 2,\n\tyear = 3,\n};\n\nstruct nvmem_cell_info {\n\tconst char *name;\n\tunsigned int offset;\n\tunsigned int bytes;\n\tunsigned int bit_offset;\n\tunsigned int nbits;\n};\n\ntypedef int (*nvmem_reg_read_t)(void *, unsigned int, void *, size_t);\n\ntypedef int (*nvmem_reg_write_t)(void *, unsigned int, void *, size_t);\n\nenum nvmem_type {\n\tNVMEM_TYPE_UNKNOWN = 0,\n\tNVMEM_TYPE_EEPROM = 1,\n\tNVMEM_TYPE_OTP = 2,\n\tNVMEM_TYPE_BATTERY_BACKED = 3,\n\tNVMEM_TYPE_FRAM = 4,\n};\n\nstruct nvmem_keepout {\n\tunsigned int start;\n\tunsigned int end;\n\tunsigned char value;\n};\n\nstruct nvmem_config {\n\tstruct device *dev;\n\tconst char *name;\n\tint id;\n\tstruct module *owner;\n\tstruct gpio_desc *wp_gpio;\n\tconst struct nvmem_cell_info *cells;\n\tint ncells;\n\tconst struct nvmem_keepout *keepout;\n\tunsigned int nkeepout;\n\tenum nvmem_type type;\n\tbool read_only;\n\tbool root_only;\n\tstruct device_node *of_node;\n\tbool no_of_node;\n\tnvmem_reg_read_t reg_read;\n\tnvmem_reg_write_t reg_write;\n\tint size;\n\tint word_size;\n\tint stride;\n\tvoid *priv;\n\tbool compat;\n\tstruct device *base_dev;\n};\n\nstruct nvmem_device;\n\nstruct cmos_rtc_board_info {\n\tvoid (*wake_on)(struct device *);\n\tvoid (*wake_off)(struct device *);\n\tu32 flags;\n\tint address_space;\n\tu8 rtc_day_alarm;\n\tu8 rtc_mon_alarm;\n\tu8 rtc_century;\n};\n\nstruct cmos_rtc {\n\tstruct rtc_device *rtc;\n\tstruct device *dev;\n\tint irq;\n\tstruct resource *iomem;\n\ttime64_t alarm_expires;\n\tvoid (*wake_on)(struct device *);\n\tvoid (*wake_off)(struct device *);\n\tu8 enabled_wake;\n\tu8 suspend_ctrl;\n\tu8 day_alrm;\n\tu8 mon_alrm;\n\tu8 century;\n\tstruct rtc_wkalrm saved_wkalrm;\n};\n\nstruct i2c_devinfo {\n\tstruct list_head list;\n\tint busnum;\n\tstruct i2c_board_info board_info;\n};\n\nstruct i2c_device_identity {\n\tu16 manufacturer_id;\n\tu16 part_id;\n\tu8 die_revision;\n};\n\nstruct i2c_timings {\n\tu32 bus_freq_hz;\n\tu32 scl_rise_ns;\n\tu32 scl_fall_ns;\n\tu32 scl_int_delay_ns;\n\tu32 sda_fall_ns;\n\tu32 sda_hold_ns;\n\tu32 digital_filter_width_ns;\n\tu32 analog_filter_cutoff_freq_hz;\n};\n\nstruct trace_event_raw_i2c_write {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 msg_nr;\n\t__u16 addr;\n\t__u16 flags;\n\t__u16 len;\n\tu32 __data_loc_buf;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_i2c_read {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 msg_nr;\n\t__u16 addr;\n\t__u16 flags;\n\t__u16 len;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_i2c_reply {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 msg_nr;\n\t__u16 addr;\n\t__u16 flags;\n\t__u16 len;\n\tu32 __data_loc_buf;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_i2c_result {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 nr_msgs;\n\t__s16 ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_i2c_write {\n\tu32 buf;\n};\n\nstruct trace_event_data_offsets_i2c_read {};\n\nstruct trace_event_data_offsets_i2c_reply {\n\tu32 buf;\n};\n\nstruct trace_event_data_offsets_i2c_result {};\n\ntypedef void (*btf_trace_i2c_write)(void *, const struct i2c_adapter *, const struct i2c_msg *, int);\n\ntypedef void (*btf_trace_i2c_read)(void *, const struct i2c_adapter *, const struct i2c_msg *, int);\n\ntypedef void (*btf_trace_i2c_reply)(void *, const struct i2c_adapter *, const struct i2c_msg *, int);\n\ntypedef void (*btf_trace_i2c_result)(void *, const struct i2c_adapter *, int, int);\n\nstruct class_compat___2;\n\nstruct i2c_cmd_arg {\n\tunsigned int cmd;\n\tvoid *arg;\n};\n\nstruct i2c_smbus_alert_setup {\n\tint irq;\n};\n\nstruct trace_event_raw_smbus_write {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 addr;\n\t__u16 flags;\n\t__u8 command;\n\t__u8 len;\n\t__u32 protocol;\n\t__u8 buf[34];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_smbus_read {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 flags;\n\t__u16 addr;\n\t__u8 command;\n\t__u32 protocol;\n\t__u8 buf[34];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_smbus_reply {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 addr;\n\t__u16 flags;\n\t__u8 command;\n\t__u8 len;\n\t__u32 protocol;\n\t__u8 buf[34];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_smbus_result {\n\tstruct trace_entry ent;\n\tint adapter_nr;\n\t__u16 addr;\n\t__u16 flags;\n\t__u8 read_write;\n\t__u8 command;\n\t__s16 res;\n\t__u32 protocol;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_smbus_write {};\n\nstruct trace_event_data_offsets_smbus_read {};\n\nstruct trace_event_data_offsets_smbus_reply {};\n\nstruct trace_event_data_offsets_smbus_result {};\n\ntypedef void (*btf_trace_smbus_write)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, const union i2c_smbus_data *);\n\ntypedef void (*btf_trace_smbus_read)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int);\n\ntypedef void (*btf_trace_smbus_reply)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, const union i2c_smbus_data *, int);\n\ntypedef void (*btf_trace_smbus_result)(void *, const struct i2c_adapter *, u16, short unsigned int, char, u8, int, int);\n\nstruct i2c_acpi_handler_data {\n\tstruct acpi_connection_info info;\n\tstruct i2c_adapter *adapter;\n};\n\nstruct gsb_buffer {\n\tu8 status;\n\tu8 len;\n\tunion {\n\t\tu16 wdata;\n\t\tu8 bdata;\n\t\tu8 data[0];\n\t};\n};\n\nstruct i2c_acpi_lookup {\n\tstruct i2c_board_info *info;\n\tacpi_handle adapter_handle;\n\tacpi_handle device_handle;\n\tacpi_handle search_handle;\n\tint n;\n\tint index;\n\tu32 speed;\n\tu32 min_speed;\n\tu32 force_speed;\n};\n\nstruct dw_i2c_dev {\n\tstruct device *dev;\n\tstruct regmap *map;\n\tstruct regmap *sysmap;\n\tvoid *base;\n\tvoid *ext;\n\tstruct completion cmd_complete;\n\tstruct clk *clk;\n\tstruct clk *pclk;\n\tstruct reset_control *rst;\n\tstruct i2c_client *slave;\n\tu32 (*get_clk_rate_khz)(struct dw_i2c_dev *);\n\tint cmd_err;\n\tstruct i2c_msg *msgs;\n\tint msgs_num;\n\tint msg_write_idx;\n\tu32 tx_buf_len;\n\tu8 *tx_buf;\n\tint msg_read_idx;\n\tu32 rx_buf_len;\n\tu8 *rx_buf;\n\tint msg_err;\n\tunsigned int status;\n\tu32 abort_source;\n\tint irq;\n\tu32 flags;\n\tstruct i2c_adapter adapter;\n\tu32 functionality;\n\tu32 master_cfg;\n\tu32 slave_cfg;\n\tunsigned int tx_fifo_depth;\n\tunsigned int rx_fifo_depth;\n\tint rx_outstanding;\n\tstruct i2c_timings timings;\n\tu32 sda_hold_time;\n\tu16 ss_hcnt;\n\tu16 ss_lcnt;\n\tu16 fs_hcnt;\n\tu16 fs_lcnt;\n\tu16 fp_hcnt;\n\tu16 fp_lcnt;\n\tu16 hs_hcnt;\n\tu16 hs_lcnt;\n\tint (*acquire_lock)();\n\tvoid (*release_lock)();\n\tbool shared_with_punit;\n\tvoid (*disable)(struct dw_i2c_dev *);\n\tvoid (*disable_int)(struct dw_i2c_dev *);\n\tint (*init)(struct dw_i2c_dev *);\n\tint (*set_sda_hold_time)(struct dw_i2c_dev *);\n\tint mode;\n\tstruct i2c_bus_recovery_info rinfo;\n\tbool suspended;\n};\n\nenum dw_pci_ctl_id_t {\n\tmedfield = 0,\n\tmerrifield = 1,\n\tbaytrail = 2,\n\tcherrytrail = 3,\n\thaswell = 4,\n\telkhartlake = 5,\n\tnavi_amd = 6,\n};\n\nstruct dw_scl_sda_cfg {\n\tu32 ss_hcnt;\n\tu32 fs_hcnt;\n\tu32 ss_lcnt;\n\tu32 fs_lcnt;\n\tu32 sda_hold;\n};\n\nstruct dw_pci_controller {\n\tu32 bus_num;\n\tu32 flags;\n\tstruct dw_scl_sda_cfg *scl_sda_cfg;\n\tint (*setup)(struct pci_dev *, struct dw_pci_controller *);\n\tu32 (*get_clk_rate_khz)(struct dw_i2c_dev *);\n};\n\nstruct lirc_scancode {\n\t__u64 timestamp;\n\t__u16 flags;\n\t__u16 rc_proto;\n\t__u32 keycode;\n\t__u64 scancode;\n};\n\nenum rc_proto {\n\tRC_PROTO_UNKNOWN = 0,\n\tRC_PROTO_OTHER = 1,\n\tRC_PROTO_RC5 = 2,\n\tRC_PROTO_RC5X_20 = 3,\n\tRC_PROTO_RC5_SZ = 4,\n\tRC_PROTO_JVC = 5,\n\tRC_PROTO_SONY12 = 6,\n\tRC_PROTO_SONY15 = 7,\n\tRC_PROTO_SONY20 = 8,\n\tRC_PROTO_NEC = 9,\n\tRC_PROTO_NECX = 10,\n\tRC_PROTO_NEC32 = 11,\n\tRC_PROTO_SANYO = 12,\n\tRC_PROTO_MCIR2_KBD = 13,\n\tRC_PROTO_MCIR2_MSE = 14,\n\tRC_PROTO_RC6_0 = 15,\n\tRC_PROTO_RC6_6A_20 = 16,\n\tRC_PROTO_RC6_6A_24 = 17,\n\tRC_PROTO_RC6_6A_32 = 18,\n\tRC_PROTO_RC6_MCE = 19,\n\tRC_PROTO_SHARP = 20,\n\tRC_PROTO_XMP = 21,\n\tRC_PROTO_CEC = 22,\n\tRC_PROTO_IMON = 23,\n\tRC_PROTO_RCMM12 = 24,\n\tRC_PROTO_RCMM24 = 25,\n\tRC_PROTO_RCMM32 = 26,\n\tRC_PROTO_XBOX_DVD = 27,\n\tRC_PROTO_MAX = 27,\n};\n\nstruct rc_map_table {\n\tu64 scancode;\n\tu32 keycode;\n};\n\nstruct rc_map {\n\tstruct rc_map_table *scan;\n\tunsigned int size;\n\tunsigned int len;\n\tunsigned int alloc;\n\tenum rc_proto rc_proto;\n\tconst char *name;\n\tspinlock_t lock;\n};\n\nstruct rc_map_list {\n\tstruct list_head list;\n\tstruct rc_map map;\n};\n\nenum rc_driver_type {\n\tRC_DRIVER_SCANCODE = 0,\n\tRC_DRIVER_IR_RAW = 1,\n\tRC_DRIVER_IR_RAW_TX = 2,\n};\n\nstruct rc_scancode_filter {\n\tu32 data;\n\tu32 mask;\n};\n\nenum rc_filter_type {\n\tRC_FILTER_NORMAL = 0,\n\tRC_FILTER_WAKEUP = 1,\n\tRC_FILTER_MAX = 2,\n};\n\nstruct ir_raw_event_ctrl;\n\nstruct rc_dev {\n\tstruct device dev;\n\tbool managed_alloc;\n\tconst struct attribute_group *sysfs_groups[5];\n\tconst char *device_name;\n\tconst char *input_phys;\n\tstruct input_id input_id;\n\tconst char *driver_name;\n\tconst char *map_name;\n\tstruct rc_map rc_map;\n\tstruct mutex lock;\n\tunsigned int minor;\n\tstruct ir_raw_event_ctrl *raw;\n\tstruct input_dev *input_dev;\n\tenum rc_driver_type driver_type;\n\tbool idle;\n\tbool encode_wakeup;\n\tu64 allowed_protocols;\n\tu64 enabled_protocols;\n\tu64 allowed_wakeup_protocols;\n\tenum rc_proto wakeup_protocol;\n\tstruct rc_scancode_filter scancode_filter;\n\tstruct rc_scancode_filter scancode_wakeup_filter;\n\tu32 scancode_mask;\n\tu32 users;\n\tvoid *priv;\n\tspinlock_t keylock;\n\tbool keypressed;\n\tlong unsigned int keyup_jiffies;\n\tstruct timer_list timer_keyup;\n\tstruct timer_list timer_repeat;\n\tu32 last_keycode;\n\tenum rc_proto last_protocol;\n\tu64 last_scancode;\n\tu8 last_toggle;\n\tu32 timeout;\n\tu32 min_timeout;\n\tu32 max_timeout;\n\tu32 rx_resolution;\n\tu32 tx_resolution;\n\tstruct device lirc_dev;\n\tstruct cdev lirc_cdev;\n\tktime_t gap_start;\n\tu64 gap_duration;\n\tbool gap;\n\tspinlock_t lirc_fh_lock;\n\tstruct list_head lirc_fh;\n\tbool registered;\n\tint (*change_protocol)(struct rc_dev *, u64 *);\n\tint (*open)(struct rc_dev *);\n\tvoid (*close)(struct rc_dev *);\n\tint (*s_tx_mask)(struct rc_dev *, u32);\n\tint (*s_tx_carrier)(struct rc_dev *, u32);\n\tint (*s_tx_duty_cycle)(struct rc_dev *, u32);\n\tint (*s_rx_carrier_range)(struct rc_dev *, u32, u32);\n\tint (*tx_ir)(struct rc_dev *, unsigned int *, unsigned int);\n\tvoid (*s_idle)(struct rc_dev *, bool);\n\tint (*s_learning_mode)(struct rc_dev *, int);\n\tint (*s_carrier_report)(struct rc_dev *, int);\n\tint (*s_filter)(struct rc_dev *, struct rc_scancode_filter *);\n\tint (*s_wakeup_filter)(struct rc_dev *, struct rc_scancode_filter *);\n\tint (*s_timeout)(struct rc_dev *, unsigned int);\n};\n\nstruct ir_raw_event {\n\tunion {\n\t\tu32 duration;\n\t\tu32 carrier;\n\t};\n\tu8 duty_cycle;\n\tunsigned int pulse: 1;\n\tunsigned int reset: 1;\n\tunsigned int timeout: 1;\n\tunsigned int carrier_report: 1;\n};\n\nstruct nec_dec {\n\tint state;\n\tunsigned int count;\n\tu32 bits;\n\tbool is_nec_x;\n\tbool necx_repeat;\n};\n\nstruct rc5_dec {\n\tint state;\n\tu32 bits;\n\tunsigned int count;\n\tbool is_rc5x;\n};\n\nstruct rc6_dec {\n\tint state;\n\tu8 header;\n\tu32 body;\n\tbool toggle;\n\tunsigned int count;\n\tunsigned int wanted_bits;\n};\n\nstruct sony_dec {\n\tint state;\n\tu32 bits;\n\tunsigned int count;\n};\n\nstruct jvc_dec {\n\tint state;\n\tu16 bits;\n\tu16 old_bits;\n\tunsigned int count;\n\tbool first;\n\tbool toggle;\n};\n\nstruct sanyo_dec {\n\tint state;\n\tunsigned int count;\n\tu64 bits;\n};\n\nstruct sharp_dec {\n\tint state;\n\tunsigned int count;\n\tu32 bits;\n\tunsigned int pulse_len;\n};\n\nstruct mce_kbd_dec {\n\tspinlock_t keylock;\n\tstruct timer_list rx_timeout;\n\tint state;\n\tu8 header;\n\tu32 body;\n\tunsigned int count;\n\tunsigned int wanted_bits;\n};\n\nstruct xmp_dec {\n\tint state;\n\tunsigned int count;\n\tu32 durations[16];\n};\n\nstruct imon_dec {\n\tint state;\n\tint count;\n\tint last_chk;\n\tunsigned int bits;\n\tbool stick_keyboard;\n};\n\nstruct rcmm_dec {\n\tint state;\n\tunsigned int count;\n\tu32 bits;\n};\n\nstruct ir_raw_event_ctrl {\n\tstruct list_head list;\n\tstruct task_struct *thread;\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tstruct ir_raw_event *type;\n\t\t\tconst struct ir_raw_event *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tstruct ir_raw_event *ptr;\n\t\t\tconst struct ir_raw_event *ptr_const;\n\t\t};\n\t\tstruct ir_raw_event buf[512];\n\t} kfifo;\n\tktime_t last_event;\n\tstruct rc_dev *dev;\n\tspinlock_t edge_spinlock;\n\tstruct timer_list edge_handle;\n\tstruct ir_raw_event prev_ev;\n\tstruct ir_raw_event this_ev;\n\tu32 bpf_sample;\n\tstruct bpf_prog_array *progs;\n\tstruct nec_dec nec;\n\tstruct rc5_dec rc5;\n\tstruct rc6_dec rc6;\n\tstruct sony_dec sony;\n\tstruct jvc_dec jvc;\n\tstruct sanyo_dec sanyo;\n\tstruct sharp_dec sharp;\n\tstruct mce_kbd_dec mce_kbd;\n\tstruct xmp_dec xmp;\n\tstruct imon_dec imon;\n\tstruct rcmm_dec rcmm;\n};\n\nstruct rc_filter_attribute {\n\tstruct device_attribute attr;\n\tenum rc_filter_type type;\n\tbool mask;\n};\n\nstruct ir_raw_handler {\n\tstruct list_head list;\n\tu64 protocols;\n\tint (*decode)(struct rc_dev *, struct ir_raw_event);\n\tint (*encode)(enum rc_proto, u32, struct ir_raw_event *, unsigned int);\n\tu32 carrier;\n\tu32 min_timeout;\n\tint (*raw_register)(struct rc_dev *);\n\tint (*raw_unregister)(struct rc_dev *);\n};\n\nstruct ir_raw_timings_manchester {\n\tunsigned int leader_pulse;\n\tunsigned int leader_space;\n\tunsigned int clock;\n\tunsigned int invert: 1;\n\tunsigned int trailer_space;\n};\n\nstruct ir_raw_timings_pd {\n\tunsigned int header_pulse;\n\tunsigned int header_space;\n\tunsigned int bit_pulse;\n\tunsigned int bit_space[2];\n\tunsigned int trailer_pulse;\n\tunsigned int trailer_space;\n\tunsigned int msb_first: 1;\n};\n\nstruct ir_raw_timings_pl {\n\tunsigned int header_pulse;\n\tunsigned int bit_space;\n\tunsigned int bit_pulse[2];\n\tunsigned int trailer_space;\n\tunsigned int msb_first: 1;\n};\n\nstruct lirc_fh {\n\tstruct list_head list;\n\tstruct rc_dev *rc;\n\tint carrier_low;\n\tbool send_timeout_reports;\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tunsigned int *type;\n\t\t\tconst unsigned int *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tunsigned int *ptr;\n\t\t\tconst unsigned int *ptr_const;\n\t\t};\n\t\tunsigned int buf[0];\n\t} rawir;\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tstruct lirc_scancode *type;\n\t\t\tconst struct lirc_scancode *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tstruct lirc_scancode *ptr;\n\t\t\tconst struct lirc_scancode *ptr_const;\n\t\t};\n\t\tstruct lirc_scancode buf[0];\n\t} scancodes;\n\twait_queue_head_t wait_poll;\n\tu8 send_mode;\n\tu8 rec_mode;\n};\n\ntypedef u64 (*btf_bpf_rc_repeat)(u32 *);\n\ntypedef u64 (*btf_bpf_rc_keydown)(u32 *, u32, u64, u32);\n\ntypedef u64 (*btf_bpf_rc_pointer_rel)(u32 *, s32, s32);\n\nstruct pps_ktime {\n\t__s64 sec;\n\t__s32 nsec;\n\t__u32 flags;\n};\n\nstruct pps_ktime_compat {\n\t__s64 sec;\n\t__s32 nsec;\n\t__u32 flags;\n};\n\nstruct pps_kinfo {\n\t__u32 assert_sequence;\n\t__u32 clear_sequence;\n\tstruct pps_ktime assert_tu;\n\tstruct pps_ktime clear_tu;\n\tint current_mode;\n};\n\nstruct pps_kinfo_compat {\n\t__u32 assert_sequence;\n\t__u32 clear_sequence;\n\tstruct pps_ktime_compat assert_tu;\n\tstruct pps_ktime_compat clear_tu;\n\tint current_mode;\n} __attribute__((packed));\n\nstruct pps_kparams {\n\tint api_version;\n\tint mode;\n\tstruct pps_ktime assert_off_tu;\n\tstruct pps_ktime clear_off_tu;\n};\n\nstruct pps_fdata {\n\tstruct pps_kinfo info;\n\tstruct pps_ktime timeout;\n};\n\nstruct pps_fdata_compat {\n\tstruct pps_kinfo_compat info;\n\tstruct pps_ktime_compat timeout;\n} __attribute__((packed));\n\nstruct pps_bind_args {\n\tint tsformat;\n\tint edge;\n\tint consumer;\n};\n\nstruct pps_device;\n\nstruct pps_source_info {\n\tchar name[32];\n\tchar path[32];\n\tint mode;\n\tvoid (*echo)(struct pps_device *, int, void *);\n\tstruct module *owner;\n\tstruct device *dev;\n};\n\nstruct pps_device {\n\tstruct pps_source_info info;\n\tstruct pps_kparams params;\n\t__u32 assert_sequence;\n\t__u32 clear_sequence;\n\tstruct pps_ktime assert_tu;\n\tstruct pps_ktime clear_tu;\n\tint current_mode;\n\tunsigned int last_ev;\n\twait_queue_head_t queue;\n\tunsigned int id;\n\tconst void *lookup_cookie;\n\tstruct cdev cdev;\n\tstruct device *dev;\n\tstruct fasync_struct *async_queue;\n\tspinlock_t lock;\n};\n\nstruct pps_event_time {\n\tstruct timespec64 ts_real;\n};\n\nstruct ptp_clock_time {\n\t__s64 sec;\n\t__u32 nsec;\n\t__u32 reserved;\n};\n\nstruct ptp_extts_request {\n\tunsigned int index;\n\tunsigned int flags;\n\tunsigned int rsv[2];\n};\n\nstruct ptp_perout_request {\n\tunion {\n\t\tstruct ptp_clock_time start;\n\t\tstruct ptp_clock_time phase;\n\t};\n\tstruct ptp_clock_time period;\n\tunsigned int index;\n\tunsigned int flags;\n\tunion {\n\t\tstruct ptp_clock_time on;\n\t\tunsigned int rsv[4];\n\t};\n};\n\nenum ptp_pin_function {\n\tPTP_PF_NONE = 0,\n\tPTP_PF_EXTTS = 1,\n\tPTP_PF_PEROUT = 2,\n\tPTP_PF_PHYSYNC = 3,\n};\n\nstruct ptp_pin_desc {\n\tchar name[64];\n\tunsigned int index;\n\tunsigned int func;\n\tunsigned int chan;\n\tunsigned int rsv[5];\n};\n\nstruct ptp_extts_event {\n\tstruct ptp_clock_time t;\n\tunsigned int index;\n\tunsigned int flags;\n\tunsigned int rsv[2];\n};\n\nstruct ptp_clock_request {\n\tenum {\n\t\tPTP_CLK_REQ_EXTTS = 0,\n\t\tPTP_CLK_REQ_PEROUT = 1,\n\t\tPTP_CLK_REQ_PPS = 2,\n\t} type;\n\tunion {\n\t\tstruct ptp_extts_request extts;\n\t\tstruct ptp_perout_request perout;\n\t};\n};\n\nstruct ptp_clock_info {\n\tstruct module *owner;\n\tchar name[32];\n\ts32 max_adj;\n\tint n_alarm;\n\tint n_ext_ts;\n\tint n_per_out;\n\tint n_pins;\n\tint pps;\n\tstruct ptp_pin_desc *pin_config;\n\tint (*adjfine)(struct ptp_clock_info *, long int);\n\tint (*adjfreq)(struct ptp_clock_info *, s32);\n\tint (*adjphase)(struct ptp_clock_info *, s32);\n\tint (*adjtime)(struct ptp_clock_info *, s64);\n\tint (*gettime64)(struct ptp_clock_info *, struct timespec64 *);\n\tint (*gettimex64)(struct ptp_clock_info *, struct timespec64 *, struct ptp_system_timestamp *);\n\tint (*getcrosststamp)(struct ptp_clock_info *, struct system_device_crosststamp *);\n\tint (*settime64)(struct ptp_clock_info *, const struct timespec64 *);\n\tint (*enable)(struct ptp_clock_info *, struct ptp_clock_request *, int);\n\tint (*verify)(struct ptp_clock_info *, unsigned int, enum ptp_pin_function, unsigned int);\n\tlong int (*do_aux_work)(struct ptp_clock_info *);\n};\n\nenum ptp_clock_events {\n\tPTP_CLOCK_ALARM = 0,\n\tPTP_CLOCK_EXTTS = 1,\n\tPTP_CLOCK_PPS = 2,\n\tPTP_CLOCK_PPSUSR = 3,\n};\n\nstruct ptp_clock_event {\n\tint type;\n\tint index;\n\tunion {\n\t\tu64 timestamp;\n\t\tstruct pps_event_time pps_times;\n\t};\n};\n\nstruct timestamp_event_queue {\n\tstruct ptp_extts_event buf[128];\n\tint head;\n\tint tail;\n\tspinlock_t lock;\n};\n\nstruct ptp_clock {\n\tstruct posix_clock clock;\n\tstruct device dev;\n\tstruct ptp_clock_info *info;\n\tdev_t devid;\n\tint index;\n\tstruct pps_device *pps_source;\n\tlong int dialed_frequency;\n\tstruct timestamp_event_queue tsevq;\n\tstruct mutex tsevq_mux;\n\tstruct mutex pincfg_mux;\n\twait_queue_head_t tsev_wq;\n\tint defunct;\n\tstruct device_attribute *pin_dev_attr;\n\tstruct attribute **pin_attr;\n\tstruct attribute_group pin_attr_group;\n\tconst struct attribute_group *pin_attr_groups[2];\n\tstruct kthread_worker *kworker;\n\tstruct kthread_delayed_work aux_work;\n\tunsigned int max_vclocks;\n\tunsigned int n_vclocks;\n\tint *vclock_index;\n\tstruct mutex n_vclocks_mux;\n\tbool is_virtual_clock;\n};\n\nstruct ptp_clock_caps {\n\tint max_adj;\n\tint n_alarm;\n\tint n_ext_ts;\n\tint n_per_out;\n\tint pps;\n\tint n_pins;\n\tint cross_timestamping;\n\tint adjust_phase;\n\tint rsv[12];\n};\n\nstruct ptp_sys_offset {\n\tunsigned int n_samples;\n\tunsigned int rsv[3];\n\tstruct ptp_clock_time ts[51];\n};\n\nstruct ptp_sys_offset_extended {\n\tunsigned int n_samples;\n\tunsigned int rsv[3];\n\tstruct ptp_clock_time ts[75];\n};\n\nstruct ptp_sys_offset_precise {\n\tstruct ptp_clock_time device;\n\tstruct ptp_clock_time sys_realtime;\n\tstruct ptp_clock_time sys_monoraw;\n\tunsigned int rsv[4];\n};\n\nstruct ptp_vclock {\n\tstruct ptp_clock *pclock;\n\tstruct ptp_clock_info info;\n\tstruct ptp_clock *clock;\n\tstruct cyclecounter cc;\n\tstruct timecounter tc;\n\tspinlock_t lock;\n};\n\nstruct mt6397_chip {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tstruct notifier_block pm_nb;\n\tint irq;\n\tstruct irq_domain *irq_domain;\n\tstruct mutex irqlock;\n\tu16 wake_mask[2];\n\tu16 irq_masks_cur[2];\n\tu16 irq_masks_cache[2];\n\tu16 int_con[2];\n\tu16 int_status[2];\n\tu16 chip_id;\n\tvoid *irq_data;\n};\n\nstruct mt6323_pwrc {\n\tstruct device *dev;\n\tstruct regmap *regmap;\n\tu32 base;\n};\n\nenum power_supply_notifier_events {\n\tPSY_EVENT_PROP_CHANGED = 0,\n};\n\nstruct power_supply_battery_ocv_table {\n\tint ocv;\n\tint capacity;\n};\n\nstruct power_supply_resistance_temp_table {\n\tint temp;\n\tint resistance;\n};\n\nstruct power_supply_battery_info {\n\tint energy_full_design_uwh;\n\tint charge_full_design_uah;\n\tint voltage_min_design_uv;\n\tint voltage_max_design_uv;\n\tint tricklecharge_current_ua;\n\tint precharge_current_ua;\n\tint precharge_voltage_max_uv;\n\tint charge_term_current_ua;\n\tint charge_restart_voltage_uv;\n\tint overvoltage_limit_uv;\n\tint constant_charge_current_max_ua;\n\tint constant_charge_voltage_max_uv;\n\tint factory_internal_resistance_uohm;\n\tint ocv_temp[20];\n\tint temp_ambient_alert_min;\n\tint temp_ambient_alert_max;\n\tint temp_alert_min;\n\tint temp_alert_max;\n\tint temp_min;\n\tint temp_max;\n\tstruct power_supply_battery_ocv_table *ocv_table[20];\n\tint ocv_table_size[20];\n\tstruct power_supply_resistance_temp_table *resist_table;\n\tint resist_table_size;\n};\n\nstruct psy_am_i_supplied_data {\n\tstruct power_supply *psy;\n\tunsigned int count;\n};\n\nenum {\n\tPOWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0,\n\tPOWER_SUPPLY_CHARGE_TYPE_NONE = 1,\n\tPOWER_SUPPLY_CHARGE_TYPE_TRICKLE = 2,\n\tPOWER_SUPPLY_CHARGE_TYPE_FAST = 3,\n\tPOWER_SUPPLY_CHARGE_TYPE_STANDARD = 4,\n\tPOWER_SUPPLY_CHARGE_TYPE_ADAPTIVE = 5,\n\tPOWER_SUPPLY_CHARGE_TYPE_CUSTOM = 6,\n\tPOWER_SUPPLY_CHARGE_TYPE_LONGLIFE = 7,\n};\n\nenum {\n\tPOWER_SUPPLY_HEALTH_UNKNOWN = 0,\n\tPOWER_SUPPLY_HEALTH_GOOD = 1,\n\tPOWER_SUPPLY_HEALTH_OVERHEAT = 2,\n\tPOWER_SUPPLY_HEALTH_DEAD = 3,\n\tPOWER_SUPPLY_HEALTH_OVERVOLTAGE = 4,\n\tPOWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5,\n\tPOWER_SUPPLY_HEALTH_COLD = 6,\n\tPOWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7,\n\tPOWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8,\n\tPOWER_SUPPLY_HEALTH_OVERCURRENT = 9,\n\tPOWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED = 10,\n\tPOWER_SUPPLY_HEALTH_WARM = 11,\n\tPOWER_SUPPLY_HEALTH_COOL = 12,\n\tPOWER_SUPPLY_HEALTH_HOT = 13,\n};\n\nenum {\n\tPOWER_SUPPLY_SCOPE_UNKNOWN = 0,\n\tPOWER_SUPPLY_SCOPE_SYSTEM = 1,\n\tPOWER_SUPPLY_SCOPE_DEVICE = 2,\n};\n\nstruct power_supply_attr {\n\tconst char *prop_name;\n\tchar attr_name[31];\n\tstruct device_attribute dev_attr;\n\tconst char * const *text_values;\n\tint text_values_len;\n};\n\nenum hwmon_in_attributes {\n\thwmon_in_enable = 0,\n\thwmon_in_input = 1,\n\thwmon_in_min = 2,\n\thwmon_in_max = 3,\n\thwmon_in_lcrit = 4,\n\thwmon_in_crit = 5,\n\thwmon_in_average = 6,\n\thwmon_in_lowest = 7,\n\thwmon_in_highest = 8,\n\thwmon_in_reset_history = 9,\n\thwmon_in_label = 10,\n\thwmon_in_alarm = 11,\n\thwmon_in_min_alarm = 12,\n\thwmon_in_max_alarm = 13,\n\thwmon_in_lcrit_alarm = 14,\n\thwmon_in_crit_alarm = 15,\n\thwmon_in_rated_min = 16,\n\thwmon_in_rated_max = 17,\n};\n\nenum hwmon_curr_attributes {\n\thwmon_curr_enable = 0,\n\thwmon_curr_input = 1,\n\thwmon_curr_min = 2,\n\thwmon_curr_max = 3,\n\thwmon_curr_lcrit = 4,\n\thwmon_curr_crit = 5,\n\thwmon_curr_average = 6,\n\thwmon_curr_lowest = 7,\n\thwmon_curr_highest = 8,\n\thwmon_curr_reset_history = 9,\n\thwmon_curr_label = 10,\n\thwmon_curr_alarm = 11,\n\thwmon_curr_min_alarm = 12,\n\thwmon_curr_max_alarm = 13,\n\thwmon_curr_lcrit_alarm = 14,\n\thwmon_curr_crit_alarm = 15,\n\thwmon_curr_rated_min = 16,\n\thwmon_curr_rated_max = 17,\n};\n\nstruct power_supply_hwmon {\n\tstruct power_supply *psy;\n\tlong unsigned int *props;\n};\n\nstruct hwmon_type_attr_list {\n\tconst u32 *attrs;\n\tsize_t n_attrs;\n};\n\nenum cm_batt_temp {\n\tCM_BATT_OK = 0,\n\tCM_BATT_OVERHEAT = 1,\n\tCM_BATT_COLD = 2,\n};\n\nenum hwmon_power_attributes {\n\thwmon_power_enable = 0,\n\thwmon_power_average = 1,\n\thwmon_power_average_interval = 2,\n\thwmon_power_average_interval_max = 3,\n\thwmon_power_average_interval_min = 4,\n\thwmon_power_average_highest = 5,\n\thwmon_power_average_lowest = 6,\n\thwmon_power_average_max = 7,\n\thwmon_power_average_min = 8,\n\thwmon_power_input = 9,\n\thwmon_power_input_highest = 10,\n\thwmon_power_input_lowest = 11,\n\thwmon_power_reset_history = 12,\n\thwmon_power_accuracy = 13,\n\thwmon_power_cap = 14,\n\thwmon_power_cap_hyst = 15,\n\thwmon_power_cap_max = 16,\n\thwmon_power_cap_min = 17,\n\thwmon_power_min = 18,\n\thwmon_power_max = 19,\n\thwmon_power_crit = 20,\n\thwmon_power_lcrit = 21,\n\thwmon_power_label = 22,\n\thwmon_power_alarm = 23,\n\thwmon_power_cap_alarm = 24,\n\thwmon_power_min_alarm = 25,\n\thwmon_power_max_alarm = 26,\n\thwmon_power_lcrit_alarm = 27,\n\thwmon_power_crit_alarm = 28,\n\thwmon_power_rated_min = 29,\n\thwmon_power_rated_max = 30,\n};\n\nenum hwmon_energy_attributes {\n\thwmon_energy_enable = 0,\n\thwmon_energy_input = 1,\n\thwmon_energy_label = 2,\n};\n\nenum hwmon_humidity_attributes {\n\thwmon_humidity_enable = 0,\n\thwmon_humidity_input = 1,\n\thwmon_humidity_label = 2,\n\thwmon_humidity_min = 3,\n\thwmon_humidity_min_hyst = 4,\n\thwmon_humidity_max = 5,\n\thwmon_humidity_max_hyst = 6,\n\thwmon_humidity_alarm = 7,\n\thwmon_humidity_fault = 8,\n\thwmon_humidity_rated_min = 9,\n\thwmon_humidity_rated_max = 10,\n};\n\nenum hwmon_fan_attributes {\n\thwmon_fan_enable = 0,\n\thwmon_fan_input = 1,\n\thwmon_fan_label = 2,\n\thwmon_fan_min = 3,\n\thwmon_fan_max = 4,\n\thwmon_fan_div = 5,\n\thwmon_fan_pulses = 6,\n\thwmon_fan_target = 7,\n\thwmon_fan_alarm = 8,\n\thwmon_fan_min_alarm = 9,\n\thwmon_fan_max_alarm = 10,\n\thwmon_fan_fault = 11,\n};\n\nenum hwmon_pwm_attributes {\n\thwmon_pwm_input = 0,\n\thwmon_pwm_enable = 1,\n\thwmon_pwm_mode = 2,\n\thwmon_pwm_freq = 3,\n};\n\nenum hwmon_intrusion_attributes {\n\thwmon_intrusion_alarm = 0,\n\thwmon_intrusion_beep = 1,\n};\n\nstruct trace_event_raw_hwmon_attr_class {\n\tstruct trace_entry ent;\n\tint index;\n\tu32 __data_loc_attr_name;\n\tlong int val;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_hwmon_attr_show_string {\n\tstruct trace_entry ent;\n\tint index;\n\tu32 __data_loc_attr_name;\n\tu32 __data_loc_label;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_hwmon_attr_class {\n\tu32 attr_name;\n};\n\nstruct trace_event_data_offsets_hwmon_attr_show_string {\n\tu32 attr_name;\n\tu32 label;\n};\n\ntypedef void (*btf_trace_hwmon_attr_show)(void *, int, const char *, long int);\n\ntypedef void (*btf_trace_hwmon_attr_store)(void *, int, const char *, long int);\n\ntypedef void (*btf_trace_hwmon_attr_show_string)(void *, int, const char *, const char *);\n\nstruct hwmon_device {\n\tconst char *name;\n\tstruct device dev;\n\tconst struct hwmon_chip_info *chip;\n\tstruct list_head tzdata;\n\tstruct attribute_group group;\n\tconst struct attribute_group **groups;\n};\n\nstruct hwmon_device_attribute {\n\tstruct device_attribute dev_attr;\n\tconst struct hwmon_ops *ops;\n\tenum hwmon_sensor_types type;\n\tu32 attr;\n\tint index;\n\tchar name[32];\n};\n\nstruct thermal_attr {\n\tstruct device_attribute attr;\n\tchar name[20];\n};\n\nstruct devfreq_dev_status {\n\tlong unsigned int total_time;\n\tlong unsigned int busy_time;\n\tlong unsigned int current_frequency;\n\tvoid *private_data;\n};\n\nstruct trace_event_raw_thermal_temperature {\n\tstruct trace_entry ent;\n\tu32 __data_loc_thermal_zone;\n\tint id;\n\tint temp_prev;\n\tint temp;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cdev_update {\n\tstruct trace_entry ent;\n\tu32 __data_loc_type;\n\tlong unsigned int target;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_thermal_zone_trip {\n\tstruct trace_entry ent;\n\tu32 __data_loc_thermal_zone;\n\tint id;\n\tint trip;\n\tenum thermal_trip_type trip_type;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_thermal_power_devfreq_get_power {\n\tstruct trace_entry ent;\n\tu32 __data_loc_type;\n\tlong unsigned int freq;\n\tu32 busy_time;\n\tu32 total_time;\n\tu32 power;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_thermal_power_devfreq_limit {\n\tstruct trace_entry ent;\n\tu32 __data_loc_type;\n\tunsigned int freq;\n\tlong unsigned int cdev_state;\n\tu32 power;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_thermal_temperature {\n\tu32 thermal_zone;\n};\n\nstruct trace_event_data_offsets_cdev_update {\n\tu32 type;\n};\n\nstruct trace_event_data_offsets_thermal_zone_trip {\n\tu32 thermal_zone;\n};\n\nstruct trace_event_data_offsets_thermal_power_devfreq_get_power {\n\tu32 type;\n};\n\nstruct trace_event_data_offsets_thermal_power_devfreq_limit {\n\tu32 type;\n};\n\ntypedef void (*btf_trace_thermal_temperature)(void *, struct thermal_zone_device *);\n\ntypedef void (*btf_trace_cdev_update)(void *, struct thermal_cooling_device *, long unsigned int);\n\ntypedef void (*btf_trace_thermal_zone_trip)(void *, struct thermal_zone_device *, int, enum thermal_trip_type);\n\ntypedef void (*btf_trace_thermal_power_devfreq_get_power)(void *, struct thermal_cooling_device *, struct devfreq_dev_status *, long unsigned int, u32);\n\ntypedef void (*btf_trace_thermal_power_devfreq_limit)(void *, struct thermal_cooling_device *, long unsigned int, long unsigned int, u32);\n\nstruct thermal_instance {\n\tint id;\n\tchar name[20];\n\tstruct thermal_zone_device *tz;\n\tstruct thermal_cooling_device *cdev;\n\tint trip;\n\tbool initialized;\n\tlong unsigned int upper;\n\tlong unsigned int lower;\n\tlong unsigned int target;\n\tchar attr_name[20];\n\tstruct device_attribute attr;\n\tchar weight_attr_name[20];\n\tstruct device_attribute weight_attr;\n\tstruct list_head tz_node;\n\tstruct list_head cdev_node;\n\tunsigned int weight;\n};\n\nstruct genl_dumpit_info {\n\tconst struct genl_family *family;\n\tstruct genl_ops op;\n\tstruct nlattr **attrs;\n};\n\nenum thermal_genl_attr {\n\tTHERMAL_GENL_ATTR_UNSPEC = 0,\n\tTHERMAL_GENL_ATTR_TZ = 1,\n\tTHERMAL_GENL_ATTR_TZ_ID = 2,\n\tTHERMAL_GENL_ATTR_TZ_TEMP = 3,\n\tTHERMAL_GENL_ATTR_TZ_TRIP = 4,\n\tTHERMAL_GENL_ATTR_TZ_TRIP_ID = 5,\n\tTHERMAL_GENL_ATTR_TZ_TRIP_TYPE = 6,\n\tTHERMAL_GENL_ATTR_TZ_TRIP_TEMP = 7,\n\tTHERMAL_GENL_ATTR_TZ_TRIP_HYST = 8,\n\tTHERMAL_GENL_ATTR_TZ_MODE = 9,\n\tTHERMAL_GENL_ATTR_TZ_NAME = 10,\n\tTHERMAL_GENL_ATTR_TZ_CDEV_WEIGHT = 11,\n\tTHERMAL_GENL_ATTR_TZ_GOV = 12,\n\tTHERMAL_GENL_ATTR_TZ_GOV_NAME = 13,\n\tTHERMAL_GENL_ATTR_CDEV = 14,\n\tTHERMAL_GENL_ATTR_CDEV_ID = 15,\n\tTHERMAL_GENL_ATTR_CDEV_CUR_STATE = 16,\n\tTHERMAL_GENL_ATTR_CDEV_MAX_STATE = 17,\n\tTHERMAL_GENL_ATTR_CDEV_NAME = 18,\n\tTHERMAL_GENL_ATTR_GOV_NAME = 19,\n\t__THERMAL_GENL_ATTR_MAX = 20,\n};\n\nenum thermal_genl_sampling {\n\tTHERMAL_GENL_SAMPLING_TEMP = 0,\n\t__THERMAL_GENL_SAMPLING_MAX = 1,\n};\n\nenum thermal_genl_event {\n\tTHERMAL_GENL_EVENT_UNSPEC = 0,\n\tTHERMAL_GENL_EVENT_TZ_CREATE = 1,\n\tTHERMAL_GENL_EVENT_TZ_DELETE = 2,\n\tTHERMAL_GENL_EVENT_TZ_DISABLE = 3,\n\tTHERMAL_GENL_EVENT_TZ_ENABLE = 4,\n\tTHERMAL_GENL_EVENT_TZ_TRIP_UP = 5,\n\tTHERMAL_GENL_EVENT_TZ_TRIP_DOWN = 6,\n\tTHERMAL_GENL_EVENT_TZ_TRIP_CHANGE = 7,\n\tTHERMAL_GENL_EVENT_TZ_TRIP_ADD = 8,\n\tTHERMAL_GENL_EVENT_TZ_TRIP_DELETE = 9,\n\tTHERMAL_GENL_EVENT_CDEV_ADD = 10,\n\tTHERMAL_GENL_EVENT_CDEV_DELETE = 11,\n\tTHERMAL_GENL_EVENT_CDEV_STATE_UPDATE = 12,\n\tTHERMAL_GENL_EVENT_TZ_GOV_CHANGE = 13,\n\t__THERMAL_GENL_EVENT_MAX = 14,\n};\n\nenum thermal_genl_cmd {\n\tTHERMAL_GENL_CMD_UNSPEC = 0,\n\tTHERMAL_GENL_CMD_TZ_GET_ID = 1,\n\tTHERMAL_GENL_CMD_TZ_GET_TRIP = 2,\n\tTHERMAL_GENL_CMD_TZ_GET_TEMP = 3,\n\tTHERMAL_GENL_CMD_TZ_GET_GOV = 4,\n\tTHERMAL_GENL_CMD_TZ_GET_MODE = 5,\n\tTHERMAL_GENL_CMD_CDEV_GET = 6,\n\t__THERMAL_GENL_CMD_MAX = 7,\n};\n\nstruct param {\n\tstruct nlattr **attrs;\n\tstruct sk_buff *msg;\n\tconst char *name;\n\tint tz_id;\n\tint cdev_id;\n\tint trip_id;\n\tint trip_temp;\n\tint trip_type;\n\tint trip_hyst;\n\tint temp;\n\tint cdev_state;\n\tint cdev_max_state;\n};\n\ntypedef int (*cb_t)(struct param *);\n\nstruct thermal_hwmon_device {\n\tchar type[20];\n\tstruct device *device;\n\tint count;\n\tstruct list_head tz_list;\n\tstruct list_head node;\n};\n\nstruct thermal_hwmon_attr {\n\tstruct device_attribute attr;\n\tchar name[16];\n};\n\nstruct thermal_hwmon_temp {\n\tstruct list_head hwmon_node;\n\tstruct thermal_zone_device *tz;\n\tstruct thermal_hwmon_attr temp_input;\n\tstruct thermal_hwmon_attr temp_crit;\n};\n\nstruct trace_event_raw_thermal_power_allocator {\n\tstruct trace_entry ent;\n\tint tz_id;\n\tu32 __data_loc_req_power;\n\tu32 total_req_power;\n\tu32 __data_loc_granted_power;\n\tu32 total_granted_power;\n\tsize_t num_actors;\n\tu32 power_range;\n\tu32 max_allocatable_power;\n\tint current_temp;\n\ts32 delta_temp;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_thermal_power_allocator_pid {\n\tstruct trace_entry ent;\n\tint tz_id;\n\ts32 err;\n\ts32 err_integral;\n\ts64 p;\n\ts64 i;\n\ts64 d;\n\ts32 output;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_thermal_power_allocator {\n\tu32 req_power;\n\tu32 granted_power;\n};\n\nstruct trace_event_data_offsets_thermal_power_allocator_pid {};\n\ntypedef void (*btf_trace_thermal_power_allocator)(void *, struct thermal_zone_device *, u32 *, u32, u32 *, u32, size_t, u32, u32, int, s32);\n\ntypedef void (*btf_trace_thermal_power_allocator_pid)(void *, struct thermal_zone_device *, s32, s32, s64, s64, s64, s32);\n\nstruct power_allocator_params {\n\tbool allocated_tzp;\n\ts64 err_integral;\n\ts32 prev_err;\n\tint trip_switch_on;\n\tint trip_max_desired_temperature;\n\tu32 sustainable_power;\n};\n\nenum devfreq_timer {\n\tDEVFREQ_TIMER_DEFERRABLE = 0,\n\tDEVFREQ_TIMER_DELAYED = 1,\n\tDEVFREQ_TIMER_NUM = 2,\n};\n\nstruct devfreq_dev_profile {\n\tlong unsigned int initial_freq;\n\tunsigned int polling_ms;\n\tenum devfreq_timer timer;\n\tbool is_cooling_device;\n\tint (*target)(struct device *, long unsigned int *, u32);\n\tint (*get_dev_status)(struct device *, struct devfreq_dev_status *);\n\tint (*get_cur_freq)(struct device *, long unsigned int *);\n\tvoid (*exit)(struct device *);\n\tlong unsigned int *freq_table;\n\tunsigned int max_state;\n};\n\nstruct devfreq_stats {\n\tunsigned int total_trans;\n\tunsigned int *trans_table;\n\tu64 *time_in_state;\n\tu64 last_update;\n};\n\nstruct devfreq_governor;\n\nstruct devfreq {\n\tstruct list_head node;\n\tstruct mutex lock;\n\tstruct device dev;\n\tstruct devfreq_dev_profile *profile;\n\tconst struct devfreq_governor *governor;\n\tstruct opp_table *opp_table;\n\tstruct notifier_block nb;\n\tstruct delayed_work work;\n\tlong unsigned int previous_freq;\n\tstruct devfreq_dev_status last_status;\n\tvoid *data;\n\tstruct dev_pm_qos_request user_min_freq_req;\n\tstruct dev_pm_qos_request user_max_freq_req;\n\tlong unsigned int scaling_min_freq;\n\tlong unsigned int scaling_max_freq;\n\tbool stop_polling;\n\tlong unsigned int suspend_freq;\n\tlong unsigned int resume_freq;\n\tatomic_t suspend_count;\n\tstruct devfreq_stats stats;\n\tstruct srcu_notifier_head transition_notifier_list;\n\tstruct thermal_cooling_device *cdev;\n\tstruct notifier_block nb_min;\n\tstruct notifier_block nb_max;\n};\n\nstruct devfreq_governor {\n\tstruct list_head node;\n\tconst char name[16];\n\tconst u64 attrs;\n\tconst u64 flags;\n\tint (*get_target_freq)(struct devfreq *, long unsigned int *);\n\tint (*event_handler)(struct devfreq *, unsigned int, void *);\n};\n\nstruct devfreq_cooling_power {\n\tint (*get_real_power)(struct devfreq *, u32 *, long unsigned int, long unsigned int);\n};\n\nstruct devfreq_cooling_device {\n\tstruct thermal_cooling_device *cdev;\n\tstruct devfreq *devfreq;\n\tlong unsigned int cooling_state;\n\tu32 *freq_table;\n\tsize_t max_state;\n\tstruct devfreq_cooling_power *power_ops;\n\tu32 res_util;\n\tint capped_state;\n\tstruct dev_pm_qos_request req_max_freq;\n\tstruct em_perf_domain *em_pd;\n};\n\nstruct _thermal_state {\n\tu64 next_check;\n\tu64 last_interrupt_time;\n\tstruct delayed_work therm_work;\n\tlong unsigned int count;\n\tlong unsigned int last_count;\n\tlong unsigned int max_time_ms;\n\tlong unsigned int total_time_ms;\n\tbool rate_control_active;\n\tbool new_event;\n\tu8 level;\n\tu8 sample_index;\n\tu8 sample_count;\n\tu8 average;\n\tu8 baseline_temp;\n\tu8 temp_samples[3];\n};\n\nstruct thermal_state {\n\tstruct _thermal_state core_throttle;\n\tstruct _thermal_state core_power_limit;\n\tstruct _thermal_state package_throttle;\n\tstruct _thermal_state package_power_limit;\n\tstruct _thermal_state core_thresh0;\n\tstruct _thermal_state core_thresh1;\n\tstruct _thermal_state pkg_thresh0;\n\tstruct _thermal_state pkg_thresh1;\n};\n\nstruct watchdog_info {\n\t__u32 options;\n\t__u32 firmware_version;\n\t__u8 identity[32];\n};\n\nstruct watchdog_device;\n\nstruct watchdog_ops {\n\tstruct module *owner;\n\tint (*start)(struct watchdog_device *);\n\tint (*stop)(struct watchdog_device *);\n\tint (*ping)(struct watchdog_device *);\n\tunsigned int (*status)(struct watchdog_device *);\n\tint (*set_timeout)(struct watchdog_device *, unsigned int);\n\tint (*set_pretimeout)(struct watchdog_device *, unsigned int);\n\tunsigned int (*get_timeleft)(struct watchdog_device *);\n\tint (*restart)(struct watchdog_device *, long unsigned int, void *);\n\tlong int (*ioctl)(struct watchdog_device *, unsigned int, long unsigned int);\n};\n\nstruct watchdog_governor;\n\nstruct watchdog_core_data;\n\nstruct watchdog_device {\n\tint id;\n\tstruct device *parent;\n\tconst struct attribute_group **groups;\n\tconst struct watchdog_info *info;\n\tconst struct watchdog_ops *ops;\n\tconst struct watchdog_governor *gov;\n\tunsigned int bootstatus;\n\tunsigned int timeout;\n\tunsigned int pretimeout;\n\tunsigned int min_timeout;\n\tunsigned int max_timeout;\n\tunsigned int min_hw_heartbeat_ms;\n\tunsigned int max_hw_heartbeat_ms;\n\tstruct notifier_block reboot_nb;\n\tstruct notifier_block restart_nb;\n\tvoid *driver_data;\n\tstruct watchdog_core_data *wd_data;\n\tlong unsigned int status;\n\tstruct list_head deferred;\n};\n\nstruct watchdog_governor {\n\tconst char name[20];\n\tvoid (*pretimeout)(struct watchdog_device *);\n};\n\nstruct watchdog_core_data {\n\tstruct device dev;\n\tstruct cdev cdev;\n\tstruct watchdog_device *wdd;\n\tstruct mutex lock;\n\tktime_t last_keepalive;\n\tktime_t last_hw_keepalive;\n\tktime_t open_deadline;\n\tstruct hrtimer timer;\n\tstruct kthread_work work;\n\tlong unsigned int status;\n};\n\nstruct watchdog_pretimeout {\n\tstruct watchdog_device *wdd;\n\tstruct list_head entry;\n};\n\nstruct governor_priv {\n\tstruct watchdog_governor *gov;\n\tstruct list_head entry;\n};\n\nstruct dm_kobject_holder {\n\tstruct kobject kobj;\n\tstruct completion completion;\n};\n\nenum dev_type {\n\tDEV_UNKNOWN = 0,\n\tDEV_X1 = 1,\n\tDEV_X2 = 2,\n\tDEV_X4 = 3,\n\tDEV_X8 = 4,\n\tDEV_X16 = 5,\n\tDEV_X32 = 6,\n\tDEV_X64 = 7,\n};\n\nenum hw_event_mc_err_type {\n\tHW_EVENT_ERR_CORRECTED = 0,\n\tHW_EVENT_ERR_UNCORRECTED = 1,\n\tHW_EVENT_ERR_DEFERRED = 2,\n\tHW_EVENT_ERR_FATAL = 3,\n\tHW_EVENT_ERR_INFO = 4,\n};\n\nenum mem_type {\n\tMEM_EMPTY = 0,\n\tMEM_RESERVED = 1,\n\tMEM_UNKNOWN = 2,\n\tMEM_FPM = 3,\n\tMEM_EDO = 4,\n\tMEM_BEDO = 5,\n\tMEM_SDR = 6,\n\tMEM_RDR = 7,\n\tMEM_DDR = 8,\n\tMEM_RDDR = 9,\n\tMEM_RMBS = 10,\n\tMEM_DDR2 = 11,\n\tMEM_FB_DDR2 = 12,\n\tMEM_RDDR2 = 13,\n\tMEM_XDR = 14,\n\tMEM_DDR3 = 15,\n\tMEM_RDDR3 = 16,\n\tMEM_LRDDR3 = 17,\n\tMEM_LPDDR3 = 18,\n\tMEM_DDR4 = 19,\n\tMEM_RDDR4 = 20,\n\tMEM_LRDDR4 = 21,\n\tMEM_LPDDR4 = 22,\n\tMEM_DDR5 = 23,\n\tMEM_NVDIMM = 24,\n\tMEM_WIO2 = 25,\n};\n\nenum edac_type {\n\tEDAC_UNKNOWN = 0,\n\tEDAC_NONE = 1,\n\tEDAC_RESERVED = 2,\n\tEDAC_PARITY = 3,\n\tEDAC_EC = 4,\n\tEDAC_SECDED = 5,\n\tEDAC_S2ECD2ED = 6,\n\tEDAC_S4ECD4ED = 7,\n\tEDAC_S8ECD8ED = 8,\n\tEDAC_S16ECD16ED = 9,\n};\n\nenum scrub_type {\n\tSCRUB_UNKNOWN = 0,\n\tSCRUB_NONE = 1,\n\tSCRUB_SW_PROG = 2,\n\tSCRUB_SW_SRC = 3,\n\tSCRUB_SW_PROG_SRC = 4,\n\tSCRUB_SW_TUNABLE = 5,\n\tSCRUB_HW_PROG = 6,\n\tSCRUB_HW_SRC = 7,\n\tSCRUB_HW_PROG_SRC = 8,\n\tSCRUB_HW_TUNABLE = 9,\n};\n\nenum edac_mc_layer_type {\n\tEDAC_MC_LAYER_BRANCH = 0,\n\tEDAC_MC_LAYER_CHANNEL = 1,\n\tEDAC_MC_LAYER_SLOT = 2,\n\tEDAC_MC_LAYER_CHIP_SELECT = 3,\n\tEDAC_MC_LAYER_ALL_MEM = 4,\n};\n\nstruct edac_mc_layer {\n\tenum edac_mc_layer_type type;\n\tunsigned int size;\n\tbool is_virt_csrow;\n};\n\nstruct mem_ctl_info;\n\nstruct dimm_info {\n\tstruct device dev;\n\tchar label[32];\n\tunsigned int location[3];\n\tstruct mem_ctl_info *mci;\n\tunsigned int idx;\n\tu32 grain;\n\tenum dev_type dtype;\n\tenum mem_type mtype;\n\tenum edac_type edac_mode;\n\tu32 nr_pages;\n\tunsigned int csrow;\n\tunsigned int cschannel;\n\tu16 smbios_handle;\n\tu32 ce_count;\n\tu32 ue_count;\n};\n\nstruct mcidev_sysfs_attribute;\n\nstruct edac_raw_error_desc {\n\tchar location[256];\n\tchar label[296];\n\tlong int grain;\n\tu16 error_count;\n\tenum hw_event_mc_err_type type;\n\tint top_layer;\n\tint mid_layer;\n\tint low_layer;\n\tlong unsigned int page_frame_number;\n\tlong unsigned int offset_in_page;\n\tlong unsigned int syndrome;\n\tconst char *msg;\n\tconst char *other_detail;\n};\n\nstruct csrow_info;\n\nstruct mem_ctl_info {\n\tstruct device dev;\n\tstruct bus_type *bus;\n\tstruct list_head link;\n\tstruct module *owner;\n\tlong unsigned int mtype_cap;\n\tlong unsigned int edac_ctl_cap;\n\tlong unsigned int edac_cap;\n\tlong unsigned int scrub_cap;\n\tenum scrub_type scrub_mode;\n\tint (*set_sdram_scrub_rate)(struct mem_ctl_info *, u32);\n\tint (*get_sdram_scrub_rate)(struct mem_ctl_info *);\n\tvoid (*edac_check)(struct mem_ctl_info *);\n\tlong unsigned int (*ctl_page_to_phys)(struct mem_ctl_info *, long unsigned int);\n\tint mc_idx;\n\tstruct csrow_info **csrows;\n\tunsigned int nr_csrows;\n\tunsigned int num_cschannel;\n\tunsigned int n_layers;\n\tstruct edac_mc_layer *layers;\n\tbool csbased;\n\tunsigned int tot_dimms;\n\tstruct dimm_info **dimms;\n\tstruct device *pdev;\n\tconst char *mod_name;\n\tconst char *ctl_name;\n\tconst char *dev_name;\n\tvoid *pvt_info;\n\tlong unsigned int start_time;\n\tu32 ce_noinfo_count;\n\tu32 ue_noinfo_count;\n\tu32 ue_mc;\n\tu32 ce_mc;\n\tstruct completion complete;\n\tconst struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;\n\tstruct delayed_work work;\n\tstruct edac_raw_error_desc error_desc;\n\tint op_state;\n\tstruct dentry *debugfs;\n\tu8 fake_inject_layer[3];\n\tbool fake_inject_ue;\n\tu16 fake_inject_count;\n};\n\nstruct rank_info {\n\tint chan_idx;\n\tstruct csrow_info *csrow;\n\tstruct dimm_info *dimm;\n\tu32 ce_count;\n};\n\nstruct csrow_info {\n\tstruct device dev;\n\tlong unsigned int first_page;\n\tlong unsigned int last_page;\n\tlong unsigned int page_mask;\n\tint csrow_idx;\n\tu32 ue_count;\n\tu32 ce_count;\n\tstruct mem_ctl_info *mci;\n\tu32 nr_channels;\n\tstruct rank_info **channels;\n};\n\nstruct edac_device_counter {\n\tu32 ue_count;\n\tu32 ce_count;\n};\n\nstruct edac_device_ctl_info;\n\nstruct edac_dev_sysfs_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct edac_device_ctl_info *, char *);\n\tssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t);\n};\n\nstruct edac_device_instance;\n\nstruct edac_device_ctl_info {\n\tstruct list_head link;\n\tstruct module *owner;\n\tint dev_idx;\n\tint log_ue;\n\tint log_ce;\n\tint panic_on_ue;\n\tunsigned int poll_msec;\n\tlong unsigned int delay;\n\tstruct edac_dev_sysfs_attribute *sysfs_attributes;\n\tstruct bus_type *edac_subsys;\n\tint op_state;\n\tstruct delayed_work work;\n\tvoid (*edac_check)(struct edac_device_ctl_info *);\n\tstruct device *dev;\n\tconst char *mod_name;\n\tconst char *ctl_name;\n\tconst char *dev_name;\n\tvoid *pvt_info;\n\tlong unsigned int start_time;\n\tstruct completion removal_complete;\n\tchar name[32];\n\tu32 nr_instances;\n\tstruct edac_device_instance *instances;\n\tstruct edac_device_counter counters;\n\tstruct kobject kobj;\n};\n\nstruct edac_device_block;\n\nstruct edac_dev_sysfs_block_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct kobject *, struct attribute *, char *);\n\tssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);\n\tstruct edac_device_block *block;\n\tunsigned int value;\n};\n\nstruct edac_device_block {\n\tstruct edac_device_instance *instance;\n\tchar name[32];\n\tstruct edac_device_counter counters;\n\tint nr_attribs;\n\tstruct edac_dev_sysfs_block_attribute *block_attributes;\n\tstruct kobject kobj;\n};\n\nstruct edac_device_instance {\n\tstruct edac_device_ctl_info *ctl;\n\tchar name[35];\n\tstruct edac_device_counter counters;\n\tu32 nr_blocks;\n\tstruct edac_device_block *blocks;\n\tstruct kobject kobj;\n};\n\nstruct dev_ch_attribute {\n\tstruct device_attribute attr;\n\tunsigned int channel;\n};\n\nstruct ctl_info_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct edac_device_ctl_info *, char *);\n\tssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t);\n};\n\nstruct instance_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct edac_device_instance *, char *);\n\tssize_t (*store)(struct edac_device_instance *, const char *, size_t);\n};\n\nstruct edac_pci_counter {\n\tatomic_t pe_count;\n\tatomic_t npe_count;\n};\n\nstruct edac_pci_ctl_info {\n\tstruct list_head link;\n\tint pci_idx;\n\tstruct bus_type *edac_subsys;\n\tint op_state;\n\tstruct delayed_work work;\n\tvoid (*edac_check)(struct edac_pci_ctl_info *);\n\tstruct device *dev;\n\tconst char *mod_name;\n\tconst char *ctl_name;\n\tconst char *dev_name;\n\tvoid *pvt_info;\n\tlong unsigned int start_time;\n\tstruct completion complete;\n\tchar name[32];\n\tstruct edac_pci_counter counters;\n\tstruct kobject kobj;\n};\n\nstruct edac_pci_gen_data {\n\tint edac_idx;\n};\n\nstruct instance_attribute___2 {\n\tstruct attribute attr;\n\tssize_t (*show)(struct edac_pci_ctl_info *, char *);\n\tssize_t (*store)(struct edac_pci_ctl_info *, const char *, size_t);\n};\n\nstruct edac_pci_dev_attribute {\n\tstruct attribute attr;\n\tvoid *value;\n\tssize_t (*show)(void *, char *);\n\tssize_t (*store)(void *, const char *, size_t);\n};\n\ntypedef void (*pci_parity_check_fn_t)(struct pci_dev *);\n\nstruct ghes_pvt {\n\tstruct mem_ctl_info *mci;\n\tchar other_detail[400];\n\tchar msg[80];\n};\n\nstruct ghes_hw_desc {\n\tint num_dimms;\n\tstruct dimm_info *dimms;\n};\n\nstruct memdev_dmi_entry {\n\tu8 type;\n\tu8 length;\n\tu16 handle;\n\tu16 phys_mem_array_handle;\n\tu16 mem_err_info_handle;\n\tu16 total_width;\n\tu16 data_width;\n\tu16 size;\n\tu8 form_factor;\n\tu8 device_set;\n\tu8 device_locator;\n\tu8 bank_locator;\n\tu8 memory_type;\n\tu16 type_detail;\n\tu16 speed;\n\tu8 manufacturer;\n\tu8 serial_number;\n\tu8 asset_tag;\n\tu8 part_number;\n\tu8 attributes;\n\tu32 extended_size;\n\tu16 conf_mem_clk_speed;\n} __attribute__((packed));\n\nenum opp_table_access {\n\tOPP_TABLE_ACCESS_UNKNOWN = 0,\n\tOPP_TABLE_ACCESS_EXCLUSIVE = 1,\n\tOPP_TABLE_ACCESS_SHARED = 2,\n};\n\nstruct icc_path;\n\nstruct dev_pm_opp___2;\n\nstruct dev_pm_set_opp_data;\n\nstruct dev_pm_opp_supply;\n\nstruct opp_table___2 {\n\tstruct list_head node;\n\tstruct list_head lazy;\n\tstruct blocking_notifier_head head;\n\tstruct list_head dev_list;\n\tstruct list_head opp_list;\n\tstruct kref kref;\n\tstruct mutex lock;\n\tstruct device_node *np;\n\tlong unsigned int clock_latency_ns_max;\n\tunsigned int voltage_tolerance_v1;\n\tunsigned int parsed_static_opps;\n\tenum opp_table_access shared_opp;\n\tlong unsigned int current_rate;\n\tstruct dev_pm_opp___2 *current_opp;\n\tstruct dev_pm_opp___2 *suspend_opp;\n\tstruct mutex genpd_virt_dev_lock;\n\tstruct device **genpd_virt_devs;\n\tstruct opp_table___2 **required_opp_tables;\n\tunsigned int required_opp_count;\n\tunsigned int *supported_hw;\n\tunsigned int supported_hw_count;\n\tconst char *prop_name;\n\tstruct clk *clk;\n\tstruct regulator **regulators;\n\tint regulator_count;\n\tstruct icc_path **paths;\n\tunsigned int path_count;\n\tbool enabled;\n\tbool genpd_performance_state;\n\tbool is_genpd;\n\tint (*set_opp)(struct dev_pm_set_opp_data *);\n\tstruct dev_pm_opp_supply *sod_supplies;\n\tstruct dev_pm_set_opp_data *set_opp_data;\n\tstruct dentry *dentry;\n\tchar dentry_name[255];\n};\n\nstruct dev_pm_opp_icc_bw;\n\nstruct dev_pm_opp___2 {\n\tstruct list_head node;\n\tstruct kref kref;\n\tbool available;\n\tbool dynamic;\n\tbool turbo;\n\tbool suspend;\n\tbool removed;\n\tunsigned int pstate;\n\tlong unsigned int rate;\n\tunsigned int level;\n\tstruct dev_pm_opp_supply *supplies;\n\tstruct dev_pm_opp_icc_bw *bandwidth;\n\tlong unsigned int clock_latency_ns;\n\tstruct dev_pm_opp___2 **required_opps;\n\tstruct opp_table___2 *opp_table;\n\tstruct device_node *np;\n\tstruct dentry *dentry;\n};\n\nenum dev_pm_opp_event {\n\tOPP_EVENT_ADD = 0,\n\tOPP_EVENT_REMOVE = 1,\n\tOPP_EVENT_ENABLE = 2,\n\tOPP_EVENT_DISABLE = 3,\n\tOPP_EVENT_ADJUST_VOLTAGE = 4,\n};\n\nstruct dev_pm_opp_supply {\n\tlong unsigned int u_volt;\n\tlong unsigned int u_volt_min;\n\tlong unsigned int u_volt_max;\n\tlong unsigned int u_amp;\n};\n\nstruct dev_pm_opp_icc_bw {\n\tu32 avg;\n\tu32 peak;\n};\n\nstruct dev_pm_opp_info {\n\tlong unsigned int rate;\n\tstruct dev_pm_opp_supply *supplies;\n};\n\nstruct dev_pm_set_opp_data {\n\tstruct dev_pm_opp_info old_opp;\n\tstruct dev_pm_opp_info new_opp;\n\tstruct regulator **regulators;\n\tunsigned int regulator_count;\n\tstruct clk *clk;\n\tstruct device *dev;\n};\n\nstruct opp_device {\n\tstruct list_head node;\n\tconst struct device *dev;\n\tstruct dentry *dentry;\n};\n\nstruct cpufreq_policy_data {\n\tstruct cpufreq_cpuinfo cpuinfo;\n\tstruct cpufreq_frequency_table *freq_table;\n\tunsigned int cpu;\n\tunsigned int min;\n\tunsigned int max;\n};\n\nstruct freq_attr {\n\tstruct attribute attr;\n\tssize_t (*show)(struct cpufreq_policy *, char *);\n\tssize_t (*store)(struct cpufreq_policy *, const char *, size_t);\n};\n\nstruct cpufreq_driver {\n\tchar name[16];\n\tu16 flags;\n\tvoid *driver_data;\n\tint (*init)(struct cpufreq_policy *);\n\tint (*verify)(struct cpufreq_policy_data *);\n\tint (*setpolicy)(struct cpufreq_policy *);\n\tint (*target)(struct cpufreq_policy *, unsigned int, unsigned int);\n\tint (*target_index)(struct cpufreq_policy *, unsigned int);\n\tunsigned int (*fast_switch)(struct cpufreq_policy *, unsigned int);\n\tvoid (*adjust_perf)(unsigned int, long unsigned int, long unsigned int, long unsigned int);\n\tunsigned int (*get_intermediate)(struct cpufreq_policy *, unsigned int);\n\tint (*target_intermediate)(struct cpufreq_policy *, unsigned int);\n\tunsigned int (*get)(unsigned int);\n\tvoid (*update_limits)(unsigned int);\n\tint (*bios_limit)(int, unsigned int *);\n\tint (*online)(struct cpufreq_policy *);\n\tint (*offline)(struct cpufreq_policy *);\n\tint (*exit)(struct cpufreq_policy *);\n\tint (*suspend)(struct cpufreq_policy *);\n\tint (*resume)(struct cpufreq_policy *);\n\tvoid (*ready)(struct cpufreq_policy *);\n\tstruct freq_attr **attr;\n\tbool boost_enabled;\n\tint (*set_boost)(struct cpufreq_policy *, int);\n};\n\nstruct cpufreq_stats {\n\tunsigned int total_trans;\n\tlong long unsigned int last_time;\n\tunsigned int max_state;\n\tunsigned int state_num;\n\tunsigned int last_index;\n\tu64 *time_in_state;\n\tunsigned int *freq_table;\n\tunsigned int *trans_table;\n\tunsigned int reset_pending;\n\tlong long unsigned int reset_time;\n};\n\nenum {\n\tOD_NORMAL_SAMPLE = 0,\n\tOD_SUB_SAMPLE = 1,\n};\n\nstruct dbs_data {\n\tstruct gov_attr_set attr_set;\n\tvoid *tuners;\n\tunsigned int ignore_nice_load;\n\tunsigned int sampling_rate;\n\tunsigned int sampling_down_factor;\n\tunsigned int up_threshold;\n\tunsigned int io_is_busy;\n};\n\nstruct policy_dbs_info {\n\tstruct cpufreq_policy *policy;\n\tstruct mutex update_mutex;\n\tu64 last_sample_time;\n\ts64 sample_delay_ns;\n\tatomic_t work_count;\n\tstruct irq_work irq_work;\n\tstruct work_struct work;\n\tstruct dbs_data *dbs_data;\n\tstruct list_head list;\n\tunsigned int rate_mult;\n\tunsigned int idle_periods;\n\tbool is_shared;\n\tbool work_in_progress;\n};\n\nstruct dbs_governor {\n\tstruct cpufreq_governor gov;\n\tstruct kobj_type kobj_type;\n\tstruct dbs_data *gdbs_data;\n\tunsigned int (*gov_dbs_update)(struct cpufreq_policy *);\n\tstruct policy_dbs_info * (*alloc)();\n\tvoid (*free)(struct policy_dbs_info *);\n\tint (*init)(struct dbs_data *);\n\tvoid (*exit)(struct dbs_data *);\n\tvoid (*start)(struct cpufreq_policy *);\n};\n\nstruct od_ops {\n\tunsigned int (*powersave_bias_target)(struct cpufreq_policy *, unsigned int, unsigned int);\n};\n\nstruct od_policy_dbs_info {\n\tstruct policy_dbs_info policy_dbs;\n\tunsigned int freq_lo;\n\tunsigned int freq_lo_delay_us;\n\tunsigned int freq_hi_delay_us;\n\tunsigned int sample_type: 1;\n};\n\nstruct od_dbs_tuners {\n\tunsigned int powersave_bias;\n};\n\nstruct cs_policy_dbs_info {\n\tstruct policy_dbs_info policy_dbs;\n\tunsigned int down_skip;\n\tunsigned int requested_freq;\n};\n\nstruct cs_dbs_tuners {\n\tunsigned int down_threshold;\n\tunsigned int freq_step;\n};\n\nstruct cpu_dbs_info {\n\tu64 prev_cpu_idle;\n\tu64 prev_update_time;\n\tu64 prev_cpu_nice;\n\tunsigned int prev_load;\n\tstruct update_util_data update_util;\n\tstruct policy_dbs_info *policy_dbs;\n};\n\nenum acpi_preferred_pm_profiles {\n\tPM_UNSPECIFIED = 0,\n\tPM_DESKTOP = 1,\n\tPM_MOBILE = 2,\n\tPM_WORKSTATION = 3,\n\tPM_ENTERPRISE_SERVER = 4,\n\tPM_SOHO_SERVER = 5,\n\tPM_APPLIANCE_PC = 6,\n\tPM_PERFORMANCE_SERVER = 7,\n\tPM_TABLET = 8,\n};\n\nstruct sample {\n\tint32_t core_avg_perf;\n\tint32_t busy_scaled;\n\tu64 aperf;\n\tu64 mperf;\n\tu64 tsc;\n\tu64 time;\n};\n\nstruct pstate_data {\n\tint current_pstate;\n\tint min_pstate;\n\tint max_pstate;\n\tint max_pstate_physical;\n\tint perf_ctl_scaling;\n\tint scaling;\n\tint turbo_pstate;\n\tunsigned int min_freq;\n\tunsigned int max_freq;\n\tunsigned int turbo_freq;\n};\n\nstruct vid_data {\n\tint min;\n\tint max;\n\tint turbo;\n\tint32_t ratio;\n};\n\nstruct global_params {\n\tbool no_turbo;\n\tbool turbo_disabled;\n\tbool turbo_disabled_mf;\n\tint max_perf_pct;\n\tint min_perf_pct;\n};\n\nstruct cpudata {\n\tint cpu;\n\tunsigned int policy;\n\tstruct update_util_data update_util;\n\tbool update_util_set;\n\tstruct pstate_data pstate;\n\tstruct vid_data vid;\n\tu64 last_update;\n\tu64 last_sample_time;\n\tu64 aperf_mperf_shift;\n\tu64 prev_aperf;\n\tu64 prev_mperf;\n\tu64 prev_tsc;\n\tu64 prev_cummulative_iowait;\n\tstruct sample sample;\n\tint32_t min_perf_ratio;\n\tint32_t max_perf_ratio;\n\tstruct acpi_processor_performance acpi_perf_data;\n\tbool valid_pss_table;\n\tunsigned int iowait_boost;\n\ts16 epp_powersave;\n\ts16 epp_policy;\n\ts16 epp_default;\n\ts16 epp_cached;\n\tu64 hwp_req_cached;\n\tu64 hwp_cap_cached;\n\tu64 last_io_update;\n\tunsigned int sched_flags;\n\tu32 hwp_boost_min;\n\tbool suspended;\n};\n\nstruct pstate_funcs {\n\tint (*get_max)();\n\tint (*get_max_physical)();\n\tint (*get_min)();\n\tint (*get_turbo)();\n\tint (*get_scaling)();\n\tint (*get_aperf_mperf_shift)();\n\tu64 (*get_val)(struct cpudata *, int);\n\tvoid (*get_vid)(struct cpudata *);\n};\n\nenum {\n\tPSS = 0,\n\tPPC = 1,\n};\n\nstruct cpuidle_governor {\n\tchar name[16];\n\tstruct list_head governor_list;\n\tunsigned int rating;\n\tint (*enable)(struct cpuidle_driver *, struct cpuidle_device *);\n\tvoid (*disable)(struct cpuidle_driver *, struct cpuidle_device *);\n\tint (*select)(struct cpuidle_driver *, struct cpuidle_device *, bool *);\n\tvoid (*reflect)(struct cpuidle_device *, int);\n};\n\nstruct cpuidle_state_kobj {\n\tstruct cpuidle_state *state;\n\tstruct cpuidle_state_usage *state_usage;\n\tstruct completion kobj_unregister;\n\tstruct kobject kobj;\n\tstruct cpuidle_device *device;\n};\n\nstruct cpuidle_device_kobj {\n\tstruct cpuidle_device *dev;\n\tstruct completion kobj_unregister;\n\tstruct kobject kobj;\n};\n\nstruct cpuidle_attr {\n\tstruct attribute attr;\n\tssize_t (*show)(struct cpuidle_device *, char *);\n\tssize_t (*store)(struct cpuidle_device *, const char *, size_t);\n};\n\nstruct cpuidle_state_attr {\n\tstruct attribute attr;\n\tssize_t (*show)(struct cpuidle_state *, struct cpuidle_state_usage *, char *);\n\tssize_t (*store)(struct cpuidle_state *, struct cpuidle_state_usage *, const char *, size_t);\n};\n\nstruct ladder_device_state {\n\tstruct {\n\t\tu32 promotion_count;\n\t\tu32 demotion_count;\n\t\tu64 promotion_time_ns;\n\t\tu64 demotion_time_ns;\n\t} threshold;\n\tstruct {\n\t\tint promotion_count;\n\t\tint demotion_count;\n\t} stats;\n};\n\nstruct ladder_device {\n\tstruct ladder_device_state states[10];\n};\n\nstruct menu_device {\n\tint needs_update;\n\tint tick_wakeup;\n\tu64 next_timer_ns;\n\tunsigned int bucket;\n\tunsigned int correction_factor[12];\n\tunsigned int intervals[8];\n\tint interval_ptr;\n};\n\nstruct teo_bin {\n\tunsigned int intercepts;\n\tunsigned int hits;\n\tunsigned int recent;\n};\n\nstruct teo_cpu {\n\ts64 time_span_ns;\n\ts64 sleep_length_ns;\n\tstruct teo_bin state_bins[10];\n\tunsigned int total;\n\tint next_recent_idx;\n\tint recent_idx[9];\n};\n\nstruct pci_dev___2;\n\nstruct sdhci_pci_data {\n\tstruct pci_dev___2 *pdev;\n\tint slotno;\n\tint rst_n_gpio;\n\tint cd_gpio;\n\tint (*setup)(struct sdhci_pci_data *);\n\tvoid (*cleanup)(struct sdhci_pci_data *);\n};\n\nstruct led_properties {\n\tu32 color;\n\tbool color_present;\n\tconst char *function;\n\tu32 func_enum;\n\tbool func_enum_present;\n\tconst char *label;\n};\n\nenum cpu_led_event {\n\tCPU_LED_IDLE_START = 0,\n\tCPU_LED_IDLE_END = 1,\n\tCPU_LED_START = 2,\n\tCPU_LED_STOP = 3,\n\tCPU_LED_HALTED = 4,\n};\n\nstruct led_trigger_cpu {\n\tbool is_active;\n\tchar name[8];\n\tstruct led_trigger *_trig;\n};\n\nstruct dmi_memdev_info {\n\tconst char *device;\n\tconst char *bank;\n\tu64 size;\n\tu16 handle;\n\tu8 type;\n};\n\nstruct dmi_sysfs_entry {\n\tstruct dmi_header dh;\n\tstruct kobject kobj;\n\tint instance;\n\tint position;\n\tstruct list_head list;\n\tstruct kobject *child;\n};\n\nstruct dmi_sysfs_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct dmi_sysfs_entry *, char *);\n};\n\nstruct dmi_sysfs_mapped_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct dmi_sysfs_entry *, const struct dmi_header *, char *);\n};\n\ntypedef ssize_t (*dmi_callback)(struct dmi_sysfs_entry *, const struct dmi_header *, void *);\n\nstruct find_dmi_data {\n\tstruct dmi_sysfs_entry *entry;\n\tdmi_callback callback;\n\tvoid *private;\n\tint instance_countdown;\n\tssize_t ret;\n};\n\nstruct dmi_read_state {\n\tchar *buf;\n\tloff_t pos;\n\tsize_t count;\n};\n\nstruct dmi_entry_attr_show_data {\n\tstruct attribute *attr;\n\tchar *buf;\n};\n\nstruct dmi_system_event_log {\n\tstruct dmi_header header;\n\tu16 area_length;\n\tu16 header_start_offset;\n\tu16 data_start_offset;\n\tu8 access_method;\n\tu8 status;\n\tu32 change_token;\n\tunion {\n\t\tstruct {\n\t\t\tu16 index_addr;\n\t\t\tu16 data_addr;\n\t\t} io;\n\t\tu32 phys_addr32;\n\t\tu16 gpnv_handle;\n\t\tu32 access_method_address;\n\t};\n\tu8 header_format;\n\tu8 type_descriptors_supported_count;\n\tu8 per_log_type_descriptor_length;\n\tu8 supported_log_type_descriptos[0];\n} __attribute__((packed));\n\ntypedef u8 (*sel_io_reader)(const struct dmi_system_event_log *, loff_t);\n\nstruct dmi_device_attribute {\n\tstruct device_attribute dev_attr;\n\tint field;\n};\n\nstruct mafield {\n\tconst char *prefix;\n\tint field;\n};\n\nstruct acpi_table_ibft {\n\tstruct acpi_table_header header;\n\tu8 reserved[12];\n};\n\nstruct firmware_map_entry {\n\tu64 start;\n\tu64 end;\n\tconst char *type;\n\tstruct list_head list;\n\tstruct kobject kobj;\n};\n\nstruct memmap_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct firmware_map_entry *, char *);\n};\n\nstruct bmp_header {\n\tu16 id;\n\tu32 size;\n} __attribute__((packed));\n\ntypedef efi_status_t efi_query_variable_store_t(u32, long unsigned int, bool);\n\ntypedef struct {\n\tu16 version;\n\tu16 length;\n\tu32 runtime_services_supported;\n} efi_rt_properties_table_t;\n\nstruct efivar_operations {\n\tefi_get_variable_t *get_variable;\n\tefi_get_next_variable_t *get_next_variable;\n\tefi_set_variable_t *set_variable;\n\tefi_set_variable_t *set_variable_nonblocking;\n\tefi_query_variable_store_t *query_variable_store;\n};\n\nstruct efivars {\n\tstruct kset *kset;\n\tstruct kobject *kobject;\n\tconst struct efivar_operations *ops;\n};\n\nstruct linux_efi_random_seed {\n\tu32 size;\n\tu8 bits[0];\n};\n\nstruct linux_efi_memreserve {\n\tint size;\n\tatomic_t count;\n\tphys_addr_t next;\n\tstruct {\n\t\tphys_addr_t base;\n\t\tphys_addr_t size;\n\t} entry[0];\n};\n\nstruct efi_generic_dev_path {\n\tu8 type;\n\tu8 sub_type;\n\tu16 length;\n};\n\nstruct variable_validate {\n\tefi_guid_t vendor;\n\tchar *name;\n\tbool (*validate)(efi_char16_t *, int, u8 *, long unsigned int);\n};\n\ntypedef struct {\n\tu32 version;\n\tu32 num_entries;\n\tu32 desc_size;\n\tu32 reserved;\n\tefi_memory_desc_t entry[0];\n} efi_memory_attributes_table_t;\n\nstruct linux_efi_tpm_eventlog {\n\tu32 size;\n\tu32 final_events_preboot_size;\n\tu8 version;\n\tu8 log[0];\n};\n\nstruct efi_tcg2_final_events_table {\n\tu64 version;\n\tu64 nr_events;\n\tu8 events[0];\n};\n\nstruct tpm_digest {\n\tu16 alg_id;\n\tu8 digest[64];\n};\n\nenum tpm_duration {\n\tTPM_SHORT = 0,\n\tTPM_MEDIUM = 1,\n\tTPM_LONG = 2,\n\tTPM_LONG_LONG = 3,\n\tTPM_UNDEFINED = 4,\n\tTPM_NUM_DURATIONS = 4,\n};\n\nenum tcpa_event_types {\n\tPREBOOT = 0,\n\tPOST_CODE = 1,\n\tUNUSED = 2,\n\tNO_ACTION = 3,\n\tSEPARATOR = 4,\n\tACTION = 5,\n\tEVENT_TAG = 6,\n\tSCRTM_CONTENTS = 7,\n\tSCRTM_VERSION = 8,\n\tCPU_MICROCODE = 9,\n\tPLATFORM_CONFIG_FLAGS = 10,\n\tTABLE_OF_DEVICES = 11,\n\tCOMPACT_HASH = 12,\n\tIPL = 13,\n\tIPL_PARTITION_DATA = 14,\n\tNONHOST_CODE = 15,\n\tNONHOST_CONFIG = 16,\n\tNONHOST_INFO = 17,\n};\n\nstruct tcg_efi_specid_event_algs {\n\tu16 alg_id;\n\tu16 digest_size;\n};\n\nstruct tcg_efi_specid_event_head {\n\tu8 signature[16];\n\tu32 platform_class;\n\tu8 spec_version_minor;\n\tu8 spec_version_major;\n\tu8 spec_errata;\n\tu8 uintnsize;\n\tu32 num_algs;\n\tstruct tcg_efi_specid_event_algs digest_sizes[0];\n};\n\nstruct tcg_pcr_event {\n\tu32 pcr_idx;\n\tu32 event_type;\n\tu8 digest[20];\n\tu32 event_size;\n\tu8 event[0];\n};\n\nstruct tcg_event_field {\n\tu32 event_size;\n\tu8 event[0];\n};\n\nstruct tcg_pcr_event2_head {\n\tu32 pcr_idx;\n\tu32 event_type;\n\tu32 count;\n\tstruct tpm_digest digests[0];\n};\n\ntypedef u64 efi_physical_addr_t;\n\ntypedef struct {\n\tu64 length;\n\tu64 data;\n} efi_capsule_block_desc_t;\n\nstruct efi_system_resource_entry_v1 {\n\tefi_guid_t fw_class;\n\tu32 fw_type;\n\tu32 fw_version;\n\tu32 lowest_supported_fw_version;\n\tu32 capsule_flags;\n\tu32 last_attempt_version;\n\tu32 last_attempt_status;\n};\n\nstruct efi_system_resource_table {\n\tu32 fw_resource_count;\n\tu32 fw_resource_count_max;\n\tu64 fw_resource_version;\n\tu8 entries[0];\n};\n\nstruct esre_entry {\n\tunion {\n\t\tstruct efi_system_resource_entry_v1 *esre1;\n\t} esre;\n\tstruct kobject kobj;\n\tstruct list_head list;\n};\n\nstruct esre_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct esre_entry *, char *);\n\tssize_t (*store)(struct esre_entry *, const char *, size_t);\n};\n\nstruct cper_sec_proc_generic {\n\tu64 validation_bits;\n\tu8 proc_type;\n\tu8 proc_isa;\n\tu8 proc_error_type;\n\tu8 operation;\n\tu8 flags;\n\tu8 level;\n\tu16 reserved;\n\tu64 cpu_version;\n\tchar cpu_brand[128];\n\tu64 proc_id;\n\tu64 target_addr;\n\tu64 requestor_id;\n\tu64 responder_id;\n\tu64 ip;\n};\n\nstruct cper_sec_proc_ia {\n\tu64 validation_bits;\n\tu64 lapic_id;\n\tu8 cpuid[48];\n};\n\nstruct cper_mem_err_compact {\n\tu64 validation_bits;\n\tu16 node;\n\tu16 card;\n\tu16 module;\n\tu16 bank;\n\tu16 device;\n\tu16 row;\n\tu16 column;\n\tu16 bit_pos;\n\tu64 requestor_id;\n\tu64 responder_id;\n\tu64 target_id;\n\tu16 rank;\n\tu16 mem_array_handle;\n\tu16 mem_dev_handle;\n\tu8 extended;\n} __attribute__((packed));\n\nstruct cper_sec_fw_err_rec_ref {\n\tu8 record_type;\n\tu8 revision;\n\tu8 reserved[6];\n\tu64 record_identifier;\n\tguid_t record_identifier_guid;\n};\n\nstruct efi_runtime_map_entry {\n\tefi_memory_desc_t md;\n\tstruct kobject kobj;\n};\n\nstruct map_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct efi_runtime_map_entry *, char *);\n};\n\nstruct efi_acpi_dev_path {\n\tstruct efi_generic_dev_path header;\n\tu32 hid;\n\tu32 uid;\n};\n\nstruct efi_pci_dev_path {\n\tstruct efi_generic_dev_path header;\n\tu8 fn;\n\tu8 dev;\n};\n\nstruct efi_vendor_dev_path {\n\tstruct efi_generic_dev_path header;\n\tefi_guid_t vendorguid;\n\tu8 vendordata[0];\n};\n\nstruct efi_dev_path {\n\tunion {\n\t\tstruct efi_generic_dev_path header;\n\t\tstruct efi_acpi_dev_path acpi;\n\t\tstruct efi_pci_dev_path pci;\n\t\tstruct efi_vendor_dev_path vendor;\n\t};\n};\n\nstruct dev_header {\n\tu32 len;\n\tu32 prop_count;\n\tstruct efi_dev_path path[0];\n};\n\nstruct properties_header {\n\tu32 len;\n\tu32 version;\n\tu32 dev_count;\n\tstruct dev_header dev_header[0];\n};\n\nstruct efi_embedded_fw {\n\tstruct list_head list;\n\tconst char *name;\n\tconst u8 *data;\n\tsize_t length;\n};\n\nstruct efi_embedded_fw_desc {\n\tconst char *name;\n\tu8 prefix[8];\n\tu32 length;\n\tu8 sha256[32];\n};\n\nstruct cper_ia_err_info {\n\tguid_t err_type;\n\tu64 validation_bits;\n\tu64 check_info;\n\tu64 target_id;\n\tu64 requestor_id;\n\tu64 responder_id;\n\tu64 ip;\n};\n\nenum err_types {\n\tERR_TYPE_CACHE = 0,\n\tERR_TYPE_TLB = 1,\n\tERR_TYPE_BUS = 2,\n\tERR_TYPE_MS = 3,\n\tN_ERR_TYPES = 4,\n};\n\nstruct hid_device_id {\n\t__u16 bus;\n\t__u16 group;\n\t__u32 vendor;\n\t__u32 product;\n\tkernel_ulong_t driver_data;\n};\n\nstruct hid_item {\n\tunsigned int format;\n\t__u8 size;\n\t__u8 type;\n\t__u8 tag;\n\tunion {\n\t\t__u8 u8;\n\t\t__s8 s8;\n\t\t__u16 u16;\n\t\t__s16 s16;\n\t\t__u32 u32;\n\t\t__s32 s32;\n\t\t__u8 *longdata;\n\t} data;\n};\n\nstruct hid_global {\n\tunsigned int usage_page;\n\t__s32 logical_minimum;\n\t__s32 logical_maximum;\n\t__s32 physical_minimum;\n\t__s32 physical_maximum;\n\t__s32 unit_exponent;\n\tunsigned int unit;\n\tunsigned int report_id;\n\tunsigned int report_size;\n\tunsigned int report_count;\n};\n\nstruct hid_local {\n\tunsigned int usage[12288];\n\tu8 usage_size[12288];\n\tunsigned int collection_index[12288];\n\tunsigned int usage_index;\n\tunsigned int usage_minimum;\n\tunsigned int delimiter_depth;\n\tunsigned int delimiter_branch;\n};\n\nstruct hid_collection {\n\tint parent_idx;\n\tunsigned int type;\n\tunsigned int usage;\n\tunsigned int level;\n};\n\nstruct hid_usage {\n\tunsigned int hid;\n\tunsigned int collection_index;\n\tunsigned int usage_index;\n\t__s8 resolution_multiplier;\n\t__s8 wheel_factor;\n\t__u16 code;\n\t__u8 type;\n\t__s8 hat_min;\n\t__s8 hat_max;\n\t__s8 hat_dir;\n\t__s16 wheel_accumulated;\n};\n\nstruct hid_report;\n\nstruct hid_input;\n\nstruct hid_field {\n\tunsigned int physical;\n\tunsigned int logical;\n\tunsigned int application;\n\tstruct hid_usage *usage;\n\tunsigned int maxusage;\n\tunsigned int flags;\n\tunsigned int report_offset;\n\tunsigned int report_size;\n\tunsigned int report_count;\n\tunsigned int report_type;\n\t__s32 *value;\n\t__s32 logical_minimum;\n\t__s32 logical_maximum;\n\t__s32 physical_minimum;\n\t__s32 physical_maximum;\n\t__s32 unit_exponent;\n\tunsigned int unit;\n\tstruct hid_report *report;\n\tunsigned int index;\n\tstruct hid_input *hidinput;\n\t__u16 dpad;\n};\n\nstruct hid_device;\n\nstruct hid_report {\n\tstruct list_head list;\n\tstruct list_head hidinput_list;\n\tunsigned int id;\n\tunsigned int type;\n\tunsigned int application;\n\tstruct hid_field *field[256];\n\tunsigned int maxfield;\n\tunsigned int size;\n\tstruct hid_device *device;\n};\n\nstruct hid_input {\n\tstruct list_head list;\n\tstruct hid_report *report;\n\tstruct input_dev *input;\n\tconst char *name;\n\tbool registered;\n\tstruct list_head reports;\n\tunsigned int application;\n};\n\nenum hid_type {\n\tHID_TYPE_OTHER = 0,\n\tHID_TYPE_USBMOUSE = 1,\n\tHID_TYPE_USBNONE = 2,\n};\n\nstruct hid_report_enum {\n\tunsigned int numbered;\n\tstruct list_head report_list;\n\tstruct hid_report *report_id_hash[256];\n};\n\nenum hid_battery_status {\n\tHID_BATTERY_UNKNOWN = 0,\n\tHID_BATTERY_QUERIED = 1,\n\tHID_BATTERY_REPORTED = 2,\n};\n\nstruct hid_driver;\n\nstruct hid_ll_driver;\n\nstruct hid_device {\n\t__u8 *dev_rdesc;\n\tunsigned int dev_rsize;\n\t__u8 *rdesc;\n\tunsigned int rsize;\n\tstruct hid_collection *collection;\n\tunsigned int collection_size;\n\tunsigned int maxcollection;\n\tunsigned int maxapplication;\n\t__u16 bus;\n\t__u16 group;\n\t__u32 vendor;\n\t__u32 product;\n\t__u32 version;\n\tenum hid_type type;\n\tunsigned int country;\n\tstruct hid_report_enum report_enum[3];\n\tstruct work_struct led_work;\n\tstruct semaphore driver_input_lock;\n\tstruct device dev;\n\tstruct hid_driver *driver;\n\tstruct hid_ll_driver *ll_driver;\n\tstruct mutex ll_open_lock;\n\tunsigned int ll_open_count;\n\tstruct power_supply *battery;\n\t__s32 battery_capacity;\n\t__s32 battery_min;\n\t__s32 battery_max;\n\t__s32 battery_report_type;\n\t__s32 battery_report_id;\n\tenum hid_battery_status battery_status;\n\tbool battery_avoid_query;\n\tktime_t battery_ratelimit_time;\n\tlong unsigned int status;\n\tunsigned int claimed;\n\tunsigned int quirks;\n\tbool io_started;\n\tstruct list_head inputs;\n\tvoid *hiddev;\n\tvoid *hidraw;\n\tchar name[128];\n\tchar phys[64];\n\tchar uniq[64];\n\tvoid *driver_data;\n\tint (*ff_init)(struct hid_device *);\n\tint (*hiddev_connect)(struct hid_device *, unsigned int);\n\tvoid (*hiddev_disconnect)(struct hid_device *);\n\tvoid (*hiddev_hid_event)(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);\n\tvoid (*hiddev_report_event)(struct hid_device *, struct hid_report *);\n\tshort unsigned int debug;\n\tstruct dentry *debug_dir;\n\tstruct dentry *debug_rdesc;\n\tstruct dentry *debug_events;\n\tstruct list_head debug_list;\n\tspinlock_t debug_list_lock;\n\twait_queue_head_t debug_wait;\n};\n\nstruct hid_report_id;\n\nstruct hid_usage_id;\n\nstruct hid_driver {\n\tchar *name;\n\tconst struct hid_device_id *id_table;\n\tstruct list_head dyn_list;\n\tspinlock_t dyn_lock;\n\tbool (*match)(struct hid_device *, bool);\n\tint (*probe)(struct hid_device *, const struct hid_device_id *);\n\tvoid (*remove)(struct hid_device *);\n\tconst struct hid_report_id *report_table;\n\tint (*raw_event)(struct hid_device *, struct hid_report *, u8 *, int);\n\tconst struct hid_usage_id *usage_table;\n\tint (*event)(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);\n\tvoid (*report)(struct hid_device *, struct hid_report *);\n\t__u8 * (*report_fixup)(struct hid_device *, __u8 *, unsigned int *);\n\tint (*input_mapping)(struct hid_device *, struct hid_input *, struct hid_field *, struct hid_usage *, long unsigned int **, int *);\n\tint (*input_mapped)(struct hid_device *, struct hid_input *, struct hid_field *, struct hid_usage *, long unsigned int **, int *);\n\tint (*input_configured)(struct hid_device *, struct hid_input *);\n\tvoid (*feature_mapping)(struct hid_device *, struct hid_field *, struct hid_usage *);\n\tint (*suspend)(struct hid_device *, pm_message_t);\n\tint (*resume)(struct hid_device *);\n\tint (*reset_resume)(struct hid_device *);\n\tstruct device_driver driver;\n};\n\nstruct hid_ll_driver {\n\tint (*start)(struct hid_device *);\n\tvoid (*stop)(struct hid_device *);\n\tint (*open)(struct hid_device *);\n\tvoid (*close)(struct hid_device *);\n\tint (*power)(struct hid_device *, int);\n\tint (*parse)(struct hid_device *);\n\tvoid (*request)(struct hid_device *, struct hid_report *, int);\n\tint (*wait)(struct hid_device *);\n\tint (*raw_request)(struct hid_device *, unsigned char, __u8 *, size_t, unsigned char, int);\n\tint (*output_report)(struct hid_device *, __u8 *, size_t);\n\tint (*idle)(struct hid_device *, int, int, int);\n\tbool (*may_wakeup)(struct hid_device *);\n};\n\nstruct hid_parser {\n\tstruct hid_global global;\n\tstruct hid_global global_stack[4];\n\tunsigned int global_stack_ptr;\n\tstruct hid_local local;\n\tunsigned int *collection_stack;\n\tunsigned int collection_stack_ptr;\n\tunsigned int collection_stack_size;\n\tstruct hid_device *device;\n\tunsigned int scan_flags;\n};\n\nstruct hid_report_id {\n\t__u32 report_type;\n};\n\nstruct hid_usage_id {\n\t__u32 usage_hid;\n\t__u32 usage_type;\n\t__u32 usage_code;\n};\n\nstruct hiddev {\n\tint minor;\n\tint exist;\n\tint open;\n\tstruct mutex existancelock;\n\twait_queue_head_t wait;\n\tstruct hid_device *hid;\n\tstruct list_head list;\n\tspinlock_t list_lock;\n\tbool initialized;\n};\n\nstruct hidraw {\n\tunsigned int minor;\n\tint exist;\n\tint open;\n\twait_queue_head_t wait;\n\tstruct hid_device *hid;\n\tstruct device *dev;\n\tspinlock_t list_lock;\n\tstruct list_head list;\n};\n\nstruct hid_dynid {\n\tstruct list_head list;\n\tstruct hid_device_id id;\n};\n\ntypedef bool (*hid_usage_cmp_t)(struct hid_usage *, unsigned int, unsigned int);\n\nstruct quirks_list_struct {\n\tstruct hid_device_id hid_bl_item;\n\tstruct list_head node;\n};\n\nstruct hid_debug_list {\n\tstruct {\n\t\tunion {\n\t\t\tstruct __kfifo kfifo;\n\t\t\tchar *type;\n\t\t\tconst char *const_type;\n\t\t\tchar (*rectype)[0];\n\t\t\tchar *ptr;\n\t\t\tconst char *ptr_const;\n\t\t};\n\t\tchar buf[0];\n\t} hid_debug_fifo;\n\tstruct fasync_struct *fasync;\n\tstruct hid_device *hdev;\n\tstruct list_head node;\n\tstruct mutex read_mutex;\n};\n\nstruct hid_usage_entry {\n\tunsigned int page;\n\tunsigned int usage;\n\tconst char *description;\n};\n\nstruct hidraw_devinfo {\n\t__u32 bustype;\n\t__s16 vendor;\n\t__s16 product;\n};\n\nstruct hidraw_report {\n\t__u8 *value;\n\tint len;\n};\n\nstruct hidraw_list {\n\tstruct hidraw_report buffer[64];\n\tint head;\n\tint tail;\n\tstruct fasync_struct *fasync;\n\tstruct hidraw *hidraw;\n\tstruct list_head node;\n\tstruct mutex read_mutex;\n};\n\nstruct ts_dmi_data {\n\tstruct efi_embedded_fw_desc embedded_fw;\n\tconst char *acpi_name;\n\tconst struct property_entry *properties;\n};\n\nenum ppfear_regs {\n\tSPT_PMC_XRAM_PPFEAR0A = 1424,\n\tSPT_PMC_XRAM_PPFEAR0B = 1425,\n\tSPT_PMC_XRAM_PPFEAR0C = 1426,\n\tSPT_PMC_XRAM_PPFEAR0D = 1427,\n\tSPT_PMC_XRAM_PPFEAR1A = 1428,\n};\n\nstruct pmc_bit_map {\n\tconst char *name;\n\tu32 bit_mask;\n};\n\nstruct pmc_reg_map {\n\tconst struct pmc_bit_map **pfear_sts;\n\tconst struct pmc_bit_map *mphy_sts;\n\tconst struct pmc_bit_map *pll_sts;\n\tconst struct pmc_bit_map **slps0_dbg_maps;\n\tconst struct pmc_bit_map *ltr_show_sts;\n\tconst struct pmc_bit_map *msr_sts;\n\tconst struct pmc_bit_map **lpm_sts;\n\tconst u32 slp_s0_offset;\n\tconst int slp_s0_res_counter_step;\n\tconst u32 ltr_ignore_offset;\n\tconst int regmap_length;\n\tconst u32 ppfear0_offset;\n\tconst int ppfear_buckets;\n\tconst u32 pm_cfg_offset;\n\tconst int pm_read_disable_bit;\n\tconst u32 slps0_dbg_offset;\n\tconst u32 ltr_ignore_max;\n\tconst u32 pm_vric1_offset;\n\tconst int lpm_num_maps;\n\tconst int lpm_res_counter_step_x2;\n\tconst u32 lpm_sts_latch_en_offset;\n\tconst u32 lpm_en_offset;\n\tconst u32 lpm_priority_offset;\n\tconst u32 lpm_residency_offset;\n\tconst u32 lpm_status_offset;\n\tconst u32 lpm_live_status_offset;\n\tconst u32 etr3_offset;\n};\n\nstruct pmc_dev {\n\tu32 base_addr;\n\tvoid *regbase;\n\tconst struct pmc_reg_map *map;\n\tstruct dentry *dbgfs_dir;\n\tint pmc_xram_read_bit;\n\tstruct mutex lock;\n\tbool check_counters;\n\tu64 pc10_counter;\n\tu64 s0ix_counter;\n\tint num_lpm_modes;\n\tint lpm_en_modes[8];\n\tu32 *lpm_req_regs;\n};\n\nstruct intel_scu_ipc_data {\n\tstruct resource mem;\n\tint irq;\n};\n\nstruct intel_scu_ipc_dev___2 {\n\tstruct device dev;\n\tstruct resource mem;\n\tstruct module *owner;\n\tint irq;\n\tvoid *ipc_base;\n\tstruct completion cmd_complete;\n};\n\nstruct intel_scu_ipc_devres {\n\tstruct intel_scu_ipc_dev___2 *scu;\n};\n\nstruct pmc_reg_map___2 {\n\tconst struct pmc_bit_map *d3_sts_0;\n\tconst struct pmc_bit_map *d3_sts_1;\n\tconst struct pmc_bit_map *func_dis;\n\tconst struct pmc_bit_map *func_dis_2;\n\tconst struct pmc_bit_map *pss;\n};\n\nstruct pmc_data {\n\tconst struct pmc_reg_map___2 *map;\n\tconst struct pmc_clk *clks;\n};\n\nstruct pmc_dev___2 {\n\tu32 base_addr;\n\tvoid *regmap;\n\tconst struct pmc_reg_map___2 *map;\n\tstruct dentry *dbgfs_dir;\n\tbool init;\n};\n\nenum ec_status {\n\tEC_RES_SUCCESS = 0,\n\tEC_RES_INVALID_COMMAND = 1,\n\tEC_RES_ERROR = 2,\n\tEC_RES_INVALID_PARAM = 3,\n\tEC_RES_ACCESS_DENIED = 4,\n\tEC_RES_INVALID_RESPONSE = 5,\n\tEC_RES_INVALID_VERSION = 6,\n\tEC_RES_INVALID_CHECKSUM = 7,\n\tEC_RES_IN_PROGRESS = 8,\n\tEC_RES_UNAVAILABLE = 9,\n\tEC_RES_TIMEOUT = 10,\n\tEC_RES_OVERFLOW = 11,\n\tEC_RES_INVALID_HEADER = 12,\n\tEC_RES_REQUEST_TRUNCATED = 13,\n\tEC_RES_RESPONSE_TOO_BIG = 14,\n\tEC_RES_BUS_ERROR = 15,\n\tEC_RES_BUSY = 16,\n\tEC_RES_INVALID_HEADER_VERSION = 17,\n\tEC_RES_INVALID_HEADER_CRC = 18,\n\tEC_RES_INVALID_DATA_CRC = 19,\n\tEC_RES_DUP_UNAVAILABLE = 20,\n};\n\nenum host_event_code {\n\tEC_HOST_EVENT_LID_CLOSED = 1,\n\tEC_HOST_EVENT_LID_OPEN = 2,\n\tEC_HOST_EVENT_POWER_BUTTON = 3,\n\tEC_HOST_EVENT_AC_CONNECTED = 4,\n\tEC_HOST_EVENT_AC_DISCONNECTED = 5,\n\tEC_HOST_EVENT_BATTERY_LOW = 6,\n\tEC_HOST_EVENT_BATTERY_CRITICAL = 7,\n\tEC_HOST_EVENT_BATTERY = 8,\n\tEC_HOST_EVENT_THERMAL_THRESHOLD = 9,\n\tEC_HOST_EVENT_DEVICE = 10,\n\tEC_HOST_EVENT_THERMAL = 11,\n\tEC_HOST_EVENT_USB_CHARGER = 12,\n\tEC_HOST_EVENT_KEY_PRESSED = 13,\n\tEC_HOST_EVENT_INTERFACE_READY = 14,\n\tEC_HOST_EVENT_KEYBOARD_RECOVERY = 15,\n\tEC_HOST_EVENT_THERMAL_SHUTDOWN = 16,\n\tEC_HOST_EVENT_BATTERY_SHUTDOWN = 17,\n\tEC_HOST_EVENT_THROTTLE_START = 18,\n\tEC_HOST_EVENT_THROTTLE_STOP = 19,\n\tEC_HOST_EVENT_HANG_DETECT = 20,\n\tEC_HOST_EVENT_HANG_REBOOT = 21,\n\tEC_HOST_EVENT_PD_MCU = 22,\n\tEC_HOST_EVENT_BATTERY_STATUS = 23,\n\tEC_HOST_EVENT_PANIC = 24,\n\tEC_HOST_EVENT_KEYBOARD_FASTBOOT = 25,\n\tEC_HOST_EVENT_RTC = 26,\n\tEC_HOST_EVENT_MKBP = 27,\n\tEC_HOST_EVENT_USB_MUX = 28,\n\tEC_HOST_EVENT_MODE_CHANGE = 29,\n\tEC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT = 30,\n\tEC_HOST_EVENT_WOV = 31,\n\tEC_HOST_EVENT_INVALID = 32,\n};\n\nstruct ec_host_request {\n\tuint8_t struct_version;\n\tuint8_t checksum;\n\tuint16_t command;\n\tuint8_t command_version;\n\tuint8_t reserved;\n\tuint16_t data_len;\n};\n\nstruct ec_params_hello {\n\tuint32_t in_data;\n};\n\nstruct ec_response_hello {\n\tuint32_t out_data;\n};\n\nstruct ec_params_get_cmd_versions {\n\tuint8_t cmd;\n};\n\nstruct ec_response_get_cmd_versions {\n\tuint32_t version_mask;\n};\n\nenum ec_comms_status {\n\tEC_COMMS_STATUS_PROCESSING = 1,\n};\n\nstruct ec_response_get_comms_status {\n\tuint32_t flags;\n};\n\nstruct ec_response_get_protocol_info {\n\tuint32_t protocol_versions;\n\tuint16_t max_request_packet_size;\n\tuint16_t max_response_packet_size;\n\tuint32_t flags;\n};\n\nenum ec_led_colors {\n\tEC_LED_COLOR_RED = 0,\n\tEC_LED_COLOR_GREEN = 1,\n\tEC_LED_COLOR_BLUE = 2,\n\tEC_LED_COLOR_YELLOW = 3,\n\tEC_LED_COLOR_WHITE = 4,\n\tEC_LED_COLOR_AMBER = 5,\n\tEC_LED_COLOR_COUNT = 6,\n};\n\nenum motionsense_command {\n\tMOTIONSENSE_CMD_DUMP = 0,\n\tMOTIONSENSE_CMD_INFO = 1,\n\tMOTIONSENSE_CMD_EC_RATE = 2,\n\tMOTIONSENSE_CMD_SENSOR_ODR = 3,\n\tMOTIONSENSE_CMD_SENSOR_RANGE = 4,\n\tMOTIONSENSE_CMD_KB_WAKE_ANGLE = 5,\n\tMOTIONSENSE_CMD_DATA = 6,\n\tMOTIONSENSE_CMD_FIFO_INFO = 7,\n\tMOTIONSENSE_CMD_FIFO_FLUSH = 8,\n\tMOTIONSENSE_CMD_FIFO_READ = 9,\n\tMOTIONSENSE_CMD_PERFORM_CALIB = 10,\n\tMOTIONSENSE_CMD_SENSOR_OFFSET = 11,\n\tMOTIONSENSE_CMD_LIST_ACTIVITIES = 12,\n\tMOTIONSENSE_CMD_SET_ACTIVITY = 13,\n\tMOTIONSENSE_CMD_LID_ANGLE = 14,\n\tMOTIONSENSE_CMD_FIFO_INT_ENABLE = 15,\n\tMOTIONSENSE_CMD_SPOOF = 16,\n\tMOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE = 17,\n\tMOTIONSENSE_CMD_SENSOR_SCALE = 18,\n\tMOTIONSENSE_NUM_CMDS = 19,\n};\n\nstruct ec_response_motion_sensor_data {\n\tuint8_t flags;\n\tuint8_t sensor_num;\n\tunion {\n\t\tint16_t data[3];\n\t\tstruct {\n\t\t\tuint16_t reserved;\n\t\t\tuint32_t timestamp;\n\t\t} __attribute__((packed));\n\t\tstruct {\n\t\t\tuint8_t activity;\n\t\t\tuint8_t state;\n\t\t\tint16_t add_info[2];\n\t\t};\n\t};\n} __attribute__((packed));\n\nstruct ec_response_motion_sense_fifo_info {\n\tuint16_t size;\n\tuint16_t count;\n\tuint32_t timestamp;\n\tuint16_t total_lost;\n\tuint16_t lost[0];\n} __attribute__((packed));\n\nstruct ec_response_motion_sense_fifo_data {\n\tuint32_t number_data;\n\tstruct ec_response_motion_sensor_data data[0];\n};\n\nstruct ec_motion_sense_activity {\n\tuint8_t sensor_num;\n\tuint8_t activity;\n\tuint8_t enable;\n\tuint8_t reserved;\n\tuint16_t parameters[3];\n};\n\nstruct ec_params_motion_sense {\n\tuint8_t cmd;\n\tunion {\n\t\tstruct {\n\t\t\tuint8_t max_sensor_count;\n\t\t} dump;\n\t\tstruct {\n\t\t\tint16_t data;\n\t\t} kb_wake_angle;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t} info;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t} info_3;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t} data;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t} fifo_flush;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t} perform_calib;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t} list_activities;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t\tuint8_t roundup;\n\t\t\tuint16_t reserved;\n\t\t\tint32_t data;\n\t\t} ec_rate;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t\tuint8_t roundup;\n\t\t\tuint16_t reserved;\n\t\t\tint32_t data;\n\t\t} sensor_odr;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t\tuint8_t roundup;\n\t\t\tuint16_t reserved;\n\t\t\tint32_t data;\n\t\t} sensor_range;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t\tuint16_t flags;\n\t\t\tint16_t temp;\n\t\t\tint16_t offset[3];\n\t\t} __attribute__((packed)) sensor_offset;\n\t\tstruct {\n\t\t\tuint8_t sensor_num;\n\t\t\tuint16_t flags;\n\t\t\tint16_t temp;\n\t\t\tuint16_t scale[3];\n\t\t} __attribute__((packed)) sensor_scale;\n\t\tstruct {\n\t\t\tuint32_t max_data_vector;\n\t\t} fifo_read;\n\t\tstruct ec_motion_sense_activity set_activity;\n\t\tstruct {\n\t\t\tint8_t enable;\n\t\t} fifo_int_enable;\n\t\tstruct {\n\t\t\tuint8_t sensor_id;\n\t\t\tuint8_t spoof_enable;\n\t\t\tuint8_t reserved;\n\t\t\tint16_t components[3];\n\t\t} __attribute__((packed)) spoof;\n\t\tstruct {\n\t\t\tint16_t lid_angle;\n\t\t\tint16_t hys_degree;\n\t\t} tablet_mode_threshold;\n\t};\n} __attribute__((packed));\n\nstruct ec_response_motion_sense {\n\tunion {\n\t\tstruct {\n\t\t\tuint8_t module_flags;\n\t\t\tuint8_t sensor_count;\n\t\t\tstruct ec_response_motion_sensor_data sensor[0];\n\t\t} __attribute__((packed)) dump;\n\t\tstruct {\n\t\t\tuint8_t type;\n\t\t\tuint8_t location;\n\t\t\tuint8_t chip;\n\t\t} info;\n\t\tstruct {\n\t\t\tuint8_t type;\n\t\t\tuint8_t location;\n\t\t\tuint8_t chip;\n\t\t\tuint32_t min_frequency;\n\t\t\tuint32_t max_frequency;\n\t\t\tuint32_t fifo_max_event_count;\n\t\t} info_3;\n\t\tstruct ec_response_motion_sensor_data data;\n\t\tstruct {\n\t\t\tint32_t ret;\n\t\t} ec_rate;\n\t\tstruct {\n\t\t\tint32_t ret;\n\t\t} sensor_odr;\n\t\tstruct {\n\t\t\tint32_t ret;\n\t\t} sensor_range;\n\t\tstruct {\n\t\t\tint32_t ret;\n\t\t} kb_wake_angle;\n\t\tstruct {\n\t\t\tint32_t ret;\n\t\t} fifo_int_enable;\n\t\tstruct {\n\t\t\tint32_t ret;\n\t\t} spoof;\n\t\tstruct {\n\t\t\tint16_t temp;\n\t\t\tint16_t offset[3];\n\t\t} sensor_offset;\n\t\tstruct {\n\t\t\tint16_t temp;\n\t\t\tint16_t offset[3];\n\t\t} perform_calib;\n\t\tstruct {\n\t\t\tint16_t temp;\n\t\t\tuint16_t scale[3];\n\t\t} sensor_scale;\n\t\tstruct ec_response_motion_sense_fifo_info fifo_info;\n\t\tstruct ec_response_motion_sense_fifo_info fifo_flush;\n\t\tstruct ec_response_motion_sense_fifo_data fifo_read;\n\t\tstruct {\n\t\t\tuint16_t reserved;\n\t\t\tuint32_t enabled;\n\t\t\tuint32_t disabled;\n\t\t} __attribute__((packed)) list_activities;\n\t\tstruct {\n\t\t\tuint16_t value;\n\t\t} lid_angle;\n\t\tstruct {\n\t\t\tuint16_t lid_angle;\n\t\t\tuint16_t hys_degree;\n\t\t} tablet_mode_threshold;\n\t};\n};\n\nenum ec_temp_thresholds {\n\tEC_TEMP_THRESH_WARN = 0,\n\tEC_TEMP_THRESH_HIGH = 1,\n\tEC_TEMP_THRESH_HALT = 2,\n\tEC_TEMP_THRESH_COUNT = 3,\n};\n\nenum ec_mkbp_event {\n\tEC_MKBP_EVENT_KEY_MATRIX = 0,\n\tEC_MKBP_EVENT_HOST_EVENT = 1,\n\tEC_MKBP_EVENT_SENSOR_FIFO = 2,\n\tEC_MKBP_EVENT_BUTTON = 3,\n\tEC_MKBP_EVENT_SWITCH = 4,\n\tEC_MKBP_EVENT_FINGERPRINT = 5,\n\tEC_MKBP_EVENT_SYSRQ = 6,\n\tEC_MKBP_EVENT_HOST_EVENT64 = 7,\n\tEC_MKBP_EVENT_CEC_EVENT = 8,\n\tEC_MKBP_EVENT_CEC_MESSAGE = 9,\n\tEC_MKBP_EVENT_COUNT = 10,\n};\n\nunion ec_response_get_next_data_v1 {\n\tuint8_t key_matrix[16];\n\tuint32_t host_event;\n\tuint64_t host_event64;\n\tstruct {\n\t\tuint8_t reserved[3];\n\t\tstruct ec_response_motion_sense_fifo_info info;\n\t} __attribute__((packed)) sensor_fifo;\n\tuint32_t buttons;\n\tuint32_t switches;\n\tuint32_t fp_events;\n\tuint32_t sysrq;\n\tuint32_t cec_events;\n\tuint8_t cec_message[16];\n};\n\nstruct ec_response_get_next_event_v1 {\n\tuint8_t event_type;\n\tunion ec_response_get_next_data_v1 data;\n} __attribute__((packed));\n\nstruct ec_response_host_event_mask {\n\tuint32_t mask;\n};\n\nenum {\n\tEC_MSG_TX_HEADER_BYTES = 3,\n\tEC_MSG_TX_TRAILER_BYTES = 1,\n\tEC_MSG_TX_PROTO_BYTES = 4,\n\tEC_MSG_RX_PROTO_BYTES = 3,\n\tEC_PROTO2_MSG_BYTES = 256,\n\tEC_MAX_MSG_BYTES = 65536,\n};\n\nstruct cros_ec_command {\n\tuint32_t version;\n\tuint32_t command;\n\tuint32_t outsize;\n\tuint32_t insize;\n\tuint32_t result;\n\tuint8_t data[0];\n};\n\nstruct cros_ec_device {\n\tconst char *phys_name;\n\tstruct device *dev;\n\tbool was_wake_device;\n\tstruct class *cros_class;\n\tint (*cmd_readmem)(struct cros_ec_device *, unsigned int, unsigned int, void *);\n\tu16 max_request;\n\tu16 max_response;\n\tu16 max_passthru;\n\tu16 proto_version;\n\tvoid *priv;\n\tint irq;\n\tu8 *din;\n\tu8 *dout;\n\tint din_size;\n\tint dout_size;\n\tbool wake_enabled;\n\tbool suspended;\n\tint (*cmd_xfer)(struct cros_ec_device *, struct cros_ec_command *);\n\tint (*pkt_xfer)(struct cros_ec_device *, struct cros_ec_command *);\n\tstruct mutex lock;\n\tu8 mkbp_event_supported;\n\tbool host_sleep_v1;\n\tstruct blocking_notifier_head event_notifier;\n\tstruct ec_response_get_next_event_v1 event_data;\n\tint event_size;\n\tu32 host_event_wake_mask;\n\tu32 last_resume_result;\n\tktime_t last_event_time;\n\tstruct notifier_block notifier_ready;\n\tstruct platform_device *ec;\n\tstruct platform_device *pd;\n};\n\nstruct cros_ec_debugfs;\n\nstruct cros_ec_dev {\n\tstruct device class_dev;\n\tstruct cros_ec_device *ec_dev;\n\tstruct device *dev;\n\tstruct cros_ec_debugfs *debug_info;\n\tbool has_kb_wake_angle;\n\tu16 cmd_offset;\n\tu32 features[2];\n};\n\nstruct trace_event_raw_cros_ec_request_start {\n\tstruct trace_entry ent;\n\tuint32_t version;\n\tuint32_t offset;\n\tuint32_t command;\n\tuint32_t outsize;\n\tuint32_t insize;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_cros_ec_request_done {\n\tstruct trace_entry ent;\n\tuint32_t version;\n\tuint32_t offset;\n\tuint32_t command;\n\tuint32_t outsize;\n\tuint32_t insize;\n\tuint32_t result;\n\tint retval;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_cros_ec_request_start {};\n\nstruct trace_event_data_offsets_cros_ec_request_done {};\n\ntypedef void (*btf_trace_cros_ec_request_start)(void *, struct cros_ec_command *);\n\ntypedef void (*btf_trace_cros_ec_request_done)(void *, struct cros_ec_command *, int);\n\nstruct acpi_table_pcct {\n\tstruct acpi_table_header header;\n\tu32 flags;\n\tu64 reserved;\n};\n\nenum acpi_pcct_type {\n\tACPI_PCCT_TYPE_GENERIC_SUBSPACE = 0,\n\tACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE = 1,\n\tACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2 = 2,\n\tACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE = 3,\n\tACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE = 4,\n\tACPI_PCCT_TYPE_HW_REG_COMM_SUBSPACE = 5,\n\tACPI_PCCT_TYPE_RESERVED = 6,\n};\n\nstruct acpi_pcct_subspace {\n\tstruct acpi_subtable_header header;\n\tu8 reserved[6];\n\tu64 base_address;\n\tu64 length;\n\tstruct acpi_generic_address doorbell_register;\n\tu64 preserve_mask;\n\tu64 write_mask;\n\tu32 latency;\n\tu32 max_access_rate;\n\tu16 min_turnaround_time;\n} __attribute__((packed));\n\nstruct acpi_pcct_hw_reduced_type2 {\n\tstruct acpi_subtable_header header;\n\tu32 platform_interrupt;\n\tu8 flags;\n\tu8 reserved;\n\tu64 base_address;\n\tu64 length;\n\tstruct acpi_generic_address doorbell_register;\n\tu64 preserve_mask;\n\tu64 write_mask;\n\tu32 latency;\n\tu32 max_access_rate;\n\tu16 min_turnaround_time;\n\tstruct acpi_generic_address platform_ack_register;\n\tu64 ack_preserve_mask;\n\tu64 ack_write_mask;\n} __attribute__((packed));\n\nstruct hwspinlock___2;\n\nstruct hwspinlock_ops {\n\tint (*trylock)(struct hwspinlock___2 *);\n\tvoid (*unlock)(struct hwspinlock___2 *);\n\tvoid (*relax)(struct hwspinlock___2 *);\n};\n\nstruct hwspinlock_device;\n\nstruct hwspinlock___2 {\n\tstruct hwspinlock_device *bank;\n\tspinlock_t lock;\n\tvoid *priv;\n};\n\nstruct hwspinlock_device {\n\tstruct device *dev;\n\tconst struct hwspinlock_ops *ops;\n\tint base_id;\n\tint num_locks;\n\tstruct hwspinlock___2 lock[0];\n};\n\nstruct resource_table {\n\tu32 ver;\n\tu32 num;\n\tu32 reserved[2];\n\tu32 offset[0];\n};\n\nstruct fw_rsc_hdr {\n\tu32 type;\n\tu8 data[0];\n};\n\nenum fw_resource_type {\n\tRSC_CARVEOUT = 0,\n\tRSC_DEVMEM = 1,\n\tRSC_TRACE = 2,\n\tRSC_VDEV = 3,\n\tRSC_LAST = 4,\n\tRSC_VENDOR_START = 128,\n\tRSC_VENDOR_END = 512,\n};\n\nstruct fw_rsc_carveout {\n\tu32 da;\n\tu32 pa;\n\tu32 len;\n\tu32 flags;\n\tu32 reserved;\n\tu8 name[32];\n};\n\nstruct fw_rsc_devmem {\n\tu32 da;\n\tu32 pa;\n\tu32 len;\n\tu32 flags;\n\tu32 reserved;\n\tu8 name[32];\n};\n\nstruct fw_rsc_trace {\n\tu32 da;\n\tu32 len;\n\tu32 reserved;\n\tu8 name[32];\n};\n\nstruct fw_rsc_vdev_vring {\n\tu32 da;\n\tu32 align;\n\tu32 num;\n\tu32 notifyid;\n\tu32 pa;\n};\n\nstruct fw_rsc_vdev {\n\tu32 id;\n\tu32 notifyid;\n\tu32 dfeatures;\n\tu32 gfeatures;\n\tu32 config_len;\n\tu8 status;\n\tu8 num_of_vrings;\n\tu8 reserved[2];\n\tstruct fw_rsc_vdev_vring vring[0];\n};\n\nstruct rproc;\n\nstruct rproc_mem_entry {\n\tvoid *va;\n\tbool is_iomem;\n\tdma_addr_t dma;\n\tsize_t len;\n\tu32 da;\n\tvoid *priv;\n\tchar name[32];\n\tstruct list_head node;\n\tu32 rsc_offset;\n\tu32 flags;\n\tu32 of_resm_idx;\n\tint (*alloc)(struct rproc *, struct rproc_mem_entry *);\n\tint (*release)(struct rproc *, struct rproc_mem_entry *);\n};\n\nenum rproc_dump_mechanism {\n\tRPROC_COREDUMP_DISABLED = 0,\n\tRPROC_COREDUMP_ENABLED = 1,\n\tRPROC_COREDUMP_INLINE = 2,\n};\n\nstruct rproc_ops;\n\nstruct rproc {\n\tstruct list_head node;\n\tstruct iommu_domain *domain;\n\tconst char *name;\n\tconst char *firmware;\n\tvoid *priv;\n\tstruct rproc_ops *ops;\n\tstruct device dev;\n\tatomic_t power;\n\tunsigned int state;\n\tenum rproc_dump_mechanism dump_conf;\n\tstruct mutex lock;\n\tstruct dentry *dbg_dir;\n\tstruct list_head traces;\n\tint num_traces;\n\tstruct list_head carveouts;\n\tstruct list_head mappings;\n\tu64 bootaddr;\n\tstruct list_head rvdevs;\n\tstruct list_head subdevs;\n\tstruct idr notifyids;\n\tint index;\n\tstruct work_struct crash_handler;\n\tunsigned int crash_cnt;\n\tbool recovery_disabled;\n\tint max_notifyid;\n\tstruct resource_table *table_ptr;\n\tstruct resource_table *clean_table;\n\tstruct resource_table *cached_table;\n\tsize_t table_sz;\n\tbool has_iommu;\n\tbool auto_boot;\n\tstruct list_head dump_segments;\n\tint nb_vdev;\n\tu8 elf_class;\n\tu16 elf_machine;\n\tstruct cdev cdev;\n\tbool cdev_put_on_release;\n};\n\nenum rsc_handling_status {\n\tRSC_HANDLED = 0,\n\tRSC_IGNORED = 1,\n};\n\nstruct rproc_ops {\n\tint (*prepare)(struct rproc *);\n\tint (*unprepare)(struct rproc *);\n\tint (*start)(struct rproc *);\n\tint (*stop)(struct rproc *);\n\tint (*attach)(struct rproc *);\n\tint (*detach)(struct rproc *);\n\tvoid (*kick)(struct rproc *, int);\n\tvoid * (*da_to_va)(struct rproc *, u64, size_t, bool *);\n\tint (*parse_fw)(struct rproc *, const struct firmware *);\n\tint (*handle_rsc)(struct rproc *, u32, void *, int, int);\n\tstruct resource_table * (*find_loaded_rsc_table)(struct rproc *, const struct firmware *);\n\tstruct resource_table * (*get_loaded_rsc_table)(struct rproc *, size_t *);\n\tint (*load)(struct rproc *, const struct firmware *);\n\tint (*sanity_check)(struct rproc *, const struct firmware *);\n\tu64 (*get_boot_addr)(struct rproc *, const struct firmware *);\n\tlong unsigned int (*panic)(struct rproc *);\n\tvoid (*coredump)(struct rproc *);\n};\n\nenum rproc_state {\n\tRPROC_OFFLINE = 0,\n\tRPROC_SUSPENDED = 1,\n\tRPROC_RUNNING = 2,\n\tRPROC_CRASHED = 3,\n\tRPROC_DELETED = 4,\n\tRPROC_ATTACHED = 5,\n\tRPROC_DETACHED = 6,\n\tRPROC_LAST = 7,\n};\n\nenum rproc_crash_type {\n\tRPROC_MMUFAULT = 0,\n\tRPROC_WATCHDOG = 1,\n\tRPROC_FATAL_ERROR = 2,\n};\n\nstruct rproc_subdev {\n\tstruct list_head node;\n\tint (*prepare)(struct rproc_subdev *);\n\tint (*start)(struct rproc_subdev *);\n\tvoid (*stop)(struct rproc_subdev *, bool);\n\tvoid (*unprepare)(struct rproc_subdev *);\n};\n\nstruct rproc_vdev;\n\nstruct rproc_vring {\n\tvoid *va;\n\tint len;\n\tu32 da;\n\tu32 align;\n\tint notifyid;\n\tstruct rproc_vdev *rvdev;\n\tstruct virtqueue *vq;\n};\n\nstruct rproc_vdev {\n\tstruct kref refcount;\n\tstruct rproc_subdev subdev;\n\tstruct device dev;\n\tunsigned int id;\n\tstruct list_head node;\n\tstruct rproc *rproc;\n\tstruct rproc_vring vring[2];\n\tu32 rsc_offset;\n\tu32 index;\n};\n\nstruct rproc_debug_trace {\n\tstruct rproc *rproc;\n\tstruct dentry *tfile;\n\tstruct list_head node;\n\tstruct rproc_mem_entry trace_mem;\n};\n\ntypedef int (*rproc_handle_resource_t)(struct rproc *, void *, int, int);\n\nstruct rproc_dump_segment {\n\tstruct list_head node;\n\tdma_addr_t da;\n\tsize_t size;\n\tvoid *priv;\n\tvoid (*dump)(struct rproc *, struct rproc_dump_segment *, void *, size_t, size_t);\n\tloff_t offset;\n};\n\nstruct rproc_coredump_state {\n\tstruct rproc *rproc;\n\tvoid *header;\n\tstruct completion dump_done;\n};\n\nstruct devfreq_freqs {\n\tlong unsigned int old;\n\tlong unsigned int new;\n};\n\nstruct devfreq_passive_data {\n\tstruct devfreq *parent;\n\tint (*get_target_freq)(struct devfreq *, long unsigned int *);\n\tstruct devfreq *this;\n\tstruct notifier_block nb;\n};\n\nstruct trace_event_raw_devfreq_frequency {\n\tstruct trace_entry ent;\n\tu32 __data_loc_dev_name;\n\tlong unsigned int freq;\n\tlong unsigned int prev_freq;\n\tlong unsigned int busy_time;\n\tlong unsigned int total_time;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_devfreq_monitor {\n\tstruct trace_entry ent;\n\tlong unsigned int freq;\n\tlong unsigned int busy_time;\n\tlong unsigned int total_time;\n\tunsigned int polling_ms;\n\tu32 __data_loc_dev_name;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_devfreq_frequency {\n\tu32 dev_name;\n};\n\nstruct trace_event_data_offsets_devfreq_monitor {\n\tu32 dev_name;\n};\n\ntypedef void (*btf_trace_devfreq_frequency)(void *, struct devfreq *, long unsigned int, long unsigned int);\n\ntypedef void (*btf_trace_devfreq_monitor)(void *, struct devfreq *);\n\nstruct devfreq_notifier_devres {\n\tstruct devfreq *devfreq;\n\tstruct notifier_block *nb;\n\tunsigned int list;\n};\n\nstruct devfreq_event_desc;\n\nstruct devfreq_event_dev {\n\tstruct list_head node;\n\tstruct device dev;\n\tstruct mutex lock;\n\tu32 enable_count;\n\tconst struct devfreq_event_desc *desc;\n};\n\nstruct devfreq_event_ops;\n\nstruct devfreq_event_desc {\n\tconst char *name;\n\tu32 event_type;\n\tvoid *driver_data;\n\tconst struct devfreq_event_ops *ops;\n};\n\nstruct devfreq_event_data {\n\tlong unsigned int load_count;\n\tlong unsigned int total_count;\n};\n\nstruct devfreq_event_ops {\n\tint (*enable)(struct devfreq_event_dev *);\n\tint (*disable)(struct devfreq_event_dev *);\n\tint (*reset)(struct devfreq_event_dev *);\n\tint (*set_event)(struct devfreq_event_dev *);\n\tint (*get_event)(struct devfreq_event_dev *, struct devfreq_event_data *);\n};\n\nunion extcon_property_value {\n\tint intval;\n};\n\nstruct extcon_cable;\n\nstruct extcon_dev___2 {\n\tconst char *name;\n\tconst unsigned int *supported_cable;\n\tconst u32 *mutually_exclusive;\n\tstruct device dev;\n\tstruct raw_notifier_head nh_all;\n\tstruct raw_notifier_head *nh;\n\tstruct list_head entry;\n\tint max_supported;\n\tspinlock_t lock;\n\tu32 state;\n\tstruct device_type extcon_dev_type;\n\tstruct extcon_cable *cables;\n\tstruct attribute_group attr_g_muex;\n\tstruct attribute **attrs_muex;\n\tstruct device_attribute *d_attrs_muex;\n};\n\nstruct extcon_cable {\n\tstruct extcon_dev___2 *edev;\n\tint cable_index;\n\tstruct attribute_group attr_g;\n\tstruct device_attribute attr_name;\n\tstruct device_attribute attr_state;\n\tstruct attribute *attrs[3];\n\tunion extcon_property_value usb_propval[3];\n\tunion extcon_property_value chg_propval[1];\n\tunion extcon_property_value jack_propval[1];\n\tunion extcon_property_value disp_propval[2];\n\tlong unsigned int usb_bits[1];\n\tlong unsigned int chg_bits[1];\n\tlong unsigned int jack_bits[1];\n\tlong unsigned int disp_bits[1];\n};\n\nstruct __extcon_info {\n\tunsigned int type;\n\tunsigned int id;\n\tconst char *name;\n};\n\nstruct extcon_dev_notifier_devres {\n\tstruct extcon_dev___2 *edev;\n\tunsigned int id;\n\tstruct notifier_block *nb;\n};\n\nstruct powercap_control_type;\n\nstruct powercap_control_type_ops {\n\tint (*set_enable)(struct powercap_control_type *, bool);\n\tint (*get_enable)(struct powercap_control_type *, bool *);\n\tint (*release)(struct powercap_control_type *);\n};\n\nstruct powercap_control_type {\n\tstruct device dev;\n\tstruct idr idr;\n\tint nr_zones;\n\tconst struct powercap_control_type_ops *ops;\n\tstruct mutex lock;\n\tbool allocated;\n\tstruct list_head node;\n};\n\nstruct powercap_zone;\n\nstruct powercap_zone_ops {\n\tint (*get_max_energy_range_uj)(struct powercap_zone *, u64 *);\n\tint (*get_energy_uj)(struct powercap_zone *, u64 *);\n\tint (*reset_energy_uj)(struct powercap_zone *);\n\tint (*get_max_power_range_uw)(struct powercap_zone *, u64 *);\n\tint (*get_power_uw)(struct powercap_zone *, u64 *);\n\tint (*set_enable)(struct powercap_zone *, bool);\n\tint (*get_enable)(struct powercap_zone *, bool *);\n\tint (*release)(struct powercap_zone *);\n};\n\nstruct powercap_zone_constraint;\n\nstruct powercap_zone {\n\tint id;\n\tchar *name;\n\tvoid *control_type_inst;\n\tconst struct powercap_zone_ops *ops;\n\tstruct device dev;\n\tint const_id_cnt;\n\tstruct idr idr;\n\tstruct idr *parent_idr;\n\tvoid *private_data;\n\tstruct attribute **zone_dev_attrs;\n\tint zone_attr_count;\n\tstruct attribute_group dev_zone_attr_group;\n\tconst struct attribute_group *dev_attr_groups[2];\n\tbool allocated;\n\tstruct powercap_zone_constraint *constraints;\n};\n\nstruct powercap_zone_constraint_ops;\n\nstruct powercap_zone_constraint {\n\tint id;\n\tstruct powercap_zone *power_zone;\n\tconst struct powercap_zone_constraint_ops *ops;\n};\n\nstruct powercap_zone_constraint_ops {\n\tint (*set_power_limit_uw)(struct powercap_zone *, int, u64);\n\tint (*get_power_limit_uw)(struct powercap_zone *, int, u64 *);\n\tint (*set_time_window_us)(struct powercap_zone *, int, u64);\n\tint (*get_time_window_us)(struct powercap_zone *, int, u64 *);\n\tint (*get_max_power_uw)(struct powercap_zone *, int, u64 *);\n\tint (*get_min_power_uw)(struct powercap_zone *, int, u64 *);\n\tint (*get_max_time_window_us)(struct powercap_zone *, int, u64 *);\n\tint (*get_min_time_window_us)(struct powercap_zone *, int, u64 *);\n\tconst char * (*get_name)(struct powercap_zone *, int);\n};\n\nstruct dtpm_ops;\n\nstruct dtpm {\n\tstruct powercap_zone zone;\n\tstruct dtpm *parent;\n\tstruct list_head sibling;\n\tstruct list_head children;\n\tstruct dtpm_ops *ops;\n\tlong unsigned int flags;\n\tu64 power_limit;\n\tu64 power_max;\n\tu64 power_min;\n\tint weight;\n\tvoid *private;\n};\n\nstruct dtpm_ops {\n\tu64 (*set_power_uw)(struct dtpm *, u64);\n\tu64 (*get_power_uw)(struct dtpm *);\n\tvoid (*release)(struct dtpm *);\n};\n\nstruct dtpm_descr;\n\ntypedef int (*dtpm_init_t)(struct dtpm_descr *);\n\nstruct dtpm_descr {\n\tstruct dtpm *parent;\n\tconst char *name;\n\tdtpm_init_t init;\n};\n\nstruct dtpm_cpu {\n\tstruct freq_qos_request qos_req;\n\tint cpu;\n};\n\nstruct powercap_constraint_attr {\n\tstruct device_attribute power_limit_attr;\n\tstruct device_attribute time_window_attr;\n\tstruct device_attribute max_power_attr;\n\tstruct device_attribute min_power_attr;\n\tstruct device_attribute max_time_window_attr;\n\tstruct device_attribute min_time_window_attr;\n\tstruct device_attribute name_attr;\n};\n\nstruct idle_inject_thread {\n\tstruct task_struct *tsk;\n\tint should_run;\n};\n\nstruct idle_inject_device {\n\tstruct hrtimer timer;\n\tunsigned int idle_duration_us;\n\tunsigned int run_duration_us;\n\tunsigned int latency_us;\n\tlong unsigned int cpumask[0];\n};\n\nstruct trace_event_raw_extlog_mem_event {\n\tstruct trace_entry ent;\n\tu32 err_seq;\n\tu8 etype;\n\tu8 sev;\n\tu64 pa;\n\tu8 pa_mask_lsb;\n\tguid_t fru_id;\n\tu32 __data_loc_fru_text;\n\tstruct cper_mem_err_compact data;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mc_event {\n\tstruct trace_entry ent;\n\tunsigned int error_type;\n\tu32 __data_loc_msg;\n\tu32 __data_loc_label;\n\tu16 error_count;\n\tu8 mc_index;\n\ts8 top_layer;\n\ts8 middle_layer;\n\ts8 lower_layer;\n\tlong int address;\n\tu8 grain_bits;\n\tlong int syndrome;\n\tu32 __data_loc_driver_detail;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_arm_event {\n\tstruct trace_entry ent;\n\tu64 mpidr;\n\tu64 midr;\n\tu32 running_state;\n\tu32 psci_state;\n\tu8 affinity;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_non_standard_event {\n\tstruct trace_entry ent;\n\tchar sec_type[16];\n\tchar fru_id[16];\n\tu32 __data_loc_fru_text;\n\tu8 sev;\n\tu32 len;\n\tu32 __data_loc_buf;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_aer_event {\n\tstruct trace_entry ent;\n\tu32 __data_loc_dev_name;\n\tu32 status;\n\tu8 severity;\n\tu8 tlp_header_valid;\n\tu32 tlp_header[4];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_memory_failure_event {\n\tstruct trace_entry ent;\n\tlong unsigned int pfn;\n\tint type;\n\tint result;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_extlog_mem_event {\n\tu32 fru_text;\n};\n\nstruct trace_event_data_offsets_mc_event {\n\tu32 msg;\n\tu32 label;\n\tu32 driver_detail;\n};\n\nstruct trace_event_data_offsets_arm_event {};\n\nstruct trace_event_data_offsets_non_standard_event {\n\tu32 fru_text;\n\tu32 buf;\n};\n\nstruct trace_event_data_offsets_aer_event {\n\tu32 dev_name;\n};\n\nstruct trace_event_data_offsets_memory_failure_event {};\n\ntypedef void (*btf_trace_extlog_mem_event)(void *, struct cper_sec_mem_err *, u32, const guid_t *, const char *, u8);\n\ntypedef void (*btf_trace_mc_event)(void *, const unsigned int, const char *, const char *, const int, const u8, const s8, const s8, const s8, long unsigned int, const u8, long unsigned int, const char *);\n\ntypedef void (*btf_trace_arm_event)(void *, const struct cper_sec_proc_arm *);\n\ntypedef void (*btf_trace_non_standard_event)(void *, const guid_t *, const guid_t *, const char *, const u8, const u8 *, const u32);\n\ntypedef void (*btf_trace_aer_event)(void *, const char *, const u32, const u8, const u8, struct aer_header_log_regs *);\n\ntypedef void (*btf_trace_memory_failure_event)(void *, long unsigned int, int, int);\n\nstruct ce_array {\n\tu64 *array;\n\tunsigned int n;\n\tunsigned int decay_count;\n\tu64 pfns_poisoned;\n\tu64 ces_entered;\n\tu64 decays_done;\n\tunion {\n\t\tstruct {\n\t\t\t__u32 disabled: 1;\n\t\t\t__u32 __resv: 31;\n\t\t};\n\t\t__u32 flags;\n\t};\n};\n\nstruct nvmem_cell_lookup {\n\tconst char *nvmem_name;\n\tconst char *cell_name;\n\tconst char *dev_id;\n\tconst char *con_id;\n\tstruct list_head node;\n};\n\nenum {\n\tNVMEM_ADD = 1,\n\tNVMEM_REMOVE = 2,\n\tNVMEM_CELL_ADD = 3,\n\tNVMEM_CELL_REMOVE = 4,\n};\n\nstruct nvmem_cell_table {\n\tconst char *nvmem_name;\n\tconst struct nvmem_cell_info *cells;\n\tsize_t ncells;\n\tstruct list_head node;\n};\n\nstruct nvmem_device___2 {\n\tstruct module *owner;\n\tstruct device dev;\n\tint stride;\n\tint word_size;\n\tint id;\n\tstruct kref refcnt;\n\tsize_t size;\n\tbool read_only;\n\tbool root_only;\n\tint flags;\n\tenum nvmem_type type;\n\tstruct bin_attribute eeprom;\n\tstruct device *base_dev;\n\tstruct list_head cells;\n\tconst struct nvmem_keepout *keepout;\n\tunsigned int nkeepout;\n\tnvmem_reg_read_t reg_read;\n\tnvmem_reg_write_t reg_write;\n\tstruct gpio_desc *wp_gpio;\n\tvoid *priv;\n};\n\nstruct nvmem_cell {\n\tconst char *name;\n\tint offset;\n\tint bytes;\n\tint bit_offset;\n\tint nbits;\n\tstruct device_node *np;\n\tstruct nvmem_device___2 *nvmem;\n\tstruct list_head node;\n};\n\nstruct icc_node;\n\nstruct icc_req {\n\tstruct hlist_node req_node;\n\tstruct icc_node *node;\n\tstruct device *dev;\n\tbool enabled;\n\tu32 tag;\n\tu32 avg_bw;\n\tu32 peak_bw;\n};\n\nstruct icc_path___2 {\n\tconst char *name;\n\tsize_t num_nodes;\n\tstruct icc_req reqs[0];\n};\n\nstruct icc_node_data {\n\tstruct icc_node *node;\n\tu32 tag;\n};\n\nstruct icc_provider;\n\nstruct icc_node {\n\tint id;\n\tconst char *name;\n\tstruct icc_node **links;\n\tsize_t num_links;\n\tstruct icc_provider *provider;\n\tstruct list_head node_list;\n\tstruct list_head search_list;\n\tstruct icc_node *reverse;\n\tu8 is_traversed: 1;\n\tstruct hlist_head req_list;\n\tu32 avg_bw;\n\tu32 peak_bw;\n\tu32 init_avg;\n\tu32 init_peak;\n\tvoid *data;\n};\n\nstruct icc_onecell_data {\n\tunsigned int num_nodes;\n\tstruct icc_node *nodes[0];\n};\n\nstruct icc_provider {\n\tstruct list_head provider_list;\n\tstruct list_head nodes;\n\tint (*set)(struct icc_node *, struct icc_node *);\n\tint (*aggregate)(struct icc_node *, u32, u32, u32, u32 *, u32 *);\n\tvoid (*pre_aggregate)(struct icc_node *);\n\tint (*get_bw)(struct icc_node *, u32 *, u32 *);\n\tstruct icc_node * (*xlate)(struct of_phandle_args *, void *);\n\tstruct icc_node_data * (*xlate_extended)(struct of_phandle_args *, void *);\n\tstruct device *dev;\n\tint users;\n\tbool inter_set;\n\tvoid *data;\n};\n\nstruct trace_event_raw_icc_set_bw {\n\tstruct trace_entry ent;\n\tu32 __data_loc_path_name;\n\tu32 __data_loc_dev;\n\tu32 __data_loc_node_name;\n\tu32 avg_bw;\n\tu32 peak_bw;\n\tu32 node_avg_bw;\n\tu32 node_peak_bw;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_icc_set_bw_end {\n\tstruct trace_entry ent;\n\tu32 __data_loc_path_name;\n\tu32 __data_loc_dev;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_icc_set_bw {\n\tu32 path_name;\n\tu32 dev;\n\tu32 node_name;\n};\n\nstruct trace_event_data_offsets_icc_set_bw_end {\n\tu32 path_name;\n\tu32 dev;\n};\n\ntypedef void (*btf_trace_icc_set_bw)(void *, struct icc_path___2 *, struct icc_node *, int, u32, u32);\n\ntypedef void (*btf_trace_icc_set_bw_end)(void *, struct icc_path___2 *, int);\n\nstruct icc_bulk_data {\n\tstruct icc_path *path;\n\tconst char *name;\n\tu32 avg_bw;\n\tu32 peak_bw;\n};\n\nstruct net_device_devres {\n\tstruct net_device *ndev;\n};\n\nstruct __kernel_old_timespec {\n\t__kernel_old_time_t tv_sec;\n\tlong int tv_nsec;\n};\n\nstruct __kernel_sock_timeval {\n\t__s64 tv_sec;\n\t__s64 tv_usec;\n};\n\nstruct mmsghdr {\n\tstruct user_msghdr msg_hdr;\n\tunsigned int msg_len;\n};\n\nstruct scm_timestamping_internal {\n\tstruct timespec64 ts[3];\n};\n\nstruct ifconf {\n\tint ifc_len;\n\tunion {\n\t\tchar *ifcu_buf;\n\t\tstruct ifreq *ifcu_req;\n\t} ifc_ifcu;\n};\n\nstruct compat_ifmap {\n\tcompat_ulong_t mem_start;\n\tcompat_ulong_t mem_end;\n\tshort unsigned int base_addr;\n\tunsigned char irq;\n\tunsigned char dma;\n\tunsigned char port;\n};\n\nstruct compat_if_settings {\n\tunsigned int type;\n\tunsigned int size;\n\tcompat_uptr_t ifs_ifsu;\n};\n\nstruct compat_ifreq {\n\tunion {\n\t\tchar ifrn_name[16];\n\t} ifr_ifrn;\n\tunion {\n\t\tstruct sockaddr ifru_addr;\n\t\tstruct sockaddr ifru_dstaddr;\n\t\tstruct sockaddr ifru_broadaddr;\n\t\tstruct sockaddr ifru_netmask;\n\t\tstruct sockaddr ifru_hwaddr;\n\t\tshort int ifru_flags;\n\t\tcompat_int_t ifru_ivalue;\n\t\tcompat_int_t ifru_mtu;\n\t\tstruct compat_ifmap ifru_map;\n\t\tchar ifru_slave[16];\n\t\tchar ifru_newname[16];\n\t\tcompat_caddr_t ifru_data;\n\t\tstruct compat_if_settings ifru_settings;\n\t} ifr_ifru;\n};\n\nstruct compat_ifconf {\n\tcompat_int_t ifc_len;\n\tcompat_caddr_t ifcbuf;\n};\n\nenum sock_shutdown_cmd {\n\tSHUT_RD = 0,\n\tSHUT_WR = 1,\n\tSHUT_RDWR = 2,\n};\n\nstruct net_proto_family {\n\tint family;\n\tint (*create)(struct net *, struct socket *, int, int);\n\tstruct module *owner;\n};\n\nenum {\n\tSOCK_WAKE_IO = 0,\n\tSOCK_WAKE_WAITD = 1,\n\tSOCK_WAKE_SPACE = 2,\n\tSOCK_WAKE_URG = 3,\n};\n\nstruct compat_ethtool_rx_flow_spec {\n\tu32 flow_type;\n\tunion ethtool_flow_union h_u;\n\tstruct ethtool_flow_ext h_ext;\n\tunion ethtool_flow_union m_u;\n\tstruct ethtool_flow_ext m_ext;\n\tcompat_u64 ring_cookie;\n\tu32 location;\n} __attribute__((packed));\n\nstruct compat_ethtool_rxnfc {\n\tu32 cmd;\n\tu32 flow_type;\n\tcompat_u64 data;\n\tstruct compat_ethtool_rx_flow_spec fs;\n\tu32 rule_cnt;\n\tu32 rule_locs[0];\n} __attribute__((packed));\n\nstruct libipw_device;\n\nstruct iw_spy_data;\n\nstruct iw_public_data {\n\tstruct iw_spy_data *spy_data;\n\tstruct libipw_device *libipw;\n};\n\nstruct iw_param {\n\t__s32 value;\n\t__u8 fixed;\n\t__u8 disabled;\n\t__u16 flags;\n};\n\nstruct iw_point {\n\tvoid *pointer;\n\t__u16 length;\n\t__u16 flags;\n};\n\nstruct iw_freq {\n\t__s32 m;\n\t__s16 e;\n\t__u8 i;\n\t__u8 flags;\n};\n\nstruct iw_quality {\n\t__u8 qual;\n\t__u8 level;\n\t__u8 noise;\n\t__u8 updated;\n};\n\nstruct iw_discarded {\n\t__u32 nwid;\n\t__u32 code;\n\t__u32 fragment;\n\t__u32 retries;\n\t__u32 misc;\n};\n\nstruct iw_missed {\n\t__u32 beacon;\n};\n\nstruct iw_statistics {\n\t__u16 status;\n\tstruct iw_quality qual;\n\tstruct iw_discarded discard;\n\tstruct iw_missed miss;\n};\n\nunion iwreq_data {\n\tchar name[16];\n\tstruct iw_point essid;\n\tstruct iw_param nwid;\n\tstruct iw_freq freq;\n\tstruct iw_param sens;\n\tstruct iw_param bitrate;\n\tstruct iw_param txpower;\n\tstruct iw_param rts;\n\tstruct iw_param frag;\n\t__u32 mode;\n\tstruct iw_param retry;\n\tstruct iw_point encoding;\n\tstruct iw_param power;\n\tstruct iw_quality qual;\n\tstruct sockaddr ap_addr;\n\tstruct sockaddr addr;\n\tstruct iw_param param;\n\tstruct iw_point data;\n};\n\nstruct iw_priv_args {\n\t__u32 cmd;\n\t__u16 set_args;\n\t__u16 get_args;\n\tchar name[16];\n};\n\nstruct compat_mmsghdr {\n\tstruct compat_msghdr msg_hdr;\n\tcompat_uint_t msg_len;\n};\n\nstruct iw_request_info {\n\t__u16 cmd;\n\t__u16 flags;\n};\n\nstruct iw_spy_data {\n\tint spy_number;\n\tu_char spy_address[48];\n\tstruct iw_quality spy_stat[8];\n\tstruct iw_quality spy_thr_low;\n\tstruct iw_quality spy_thr_high;\n\tu_char spy_thr_under[8];\n};\n\nenum {\n\tSOF_TIMESTAMPING_TX_HARDWARE = 1,\n\tSOF_TIMESTAMPING_TX_SOFTWARE = 2,\n\tSOF_TIMESTAMPING_RX_HARDWARE = 4,\n\tSOF_TIMESTAMPING_RX_SOFTWARE = 8,\n\tSOF_TIMESTAMPING_SOFTWARE = 16,\n\tSOF_TIMESTAMPING_SYS_HARDWARE = 32,\n\tSOF_TIMESTAMPING_RAW_HARDWARE = 64,\n\tSOF_TIMESTAMPING_OPT_ID = 128,\n\tSOF_TIMESTAMPING_TX_SCHED = 256,\n\tSOF_TIMESTAMPING_TX_ACK = 512,\n\tSOF_TIMESTAMPING_OPT_CMSG = 1024,\n\tSOF_TIMESTAMPING_OPT_TSONLY = 2048,\n\tSOF_TIMESTAMPING_OPT_STATS = 4096,\n\tSOF_TIMESTAMPING_OPT_PKTINFO = 8192,\n\tSOF_TIMESTAMPING_OPT_TX_SWHW = 16384,\n\tSOF_TIMESTAMPING_BIND_PHC = 32768,\n\tSOF_TIMESTAMPING_LAST = 32768,\n\tSOF_TIMESTAMPING_MASK = 65535,\n};\n\nstruct scm_ts_pktinfo {\n\t__u32 if_index;\n\t__u32 pkt_length;\n\t__u32 reserved[2];\n};\n\nstruct sock_skb_cb {\n\tu32 dropcount;\n};\n\nstruct sock_ee_data_rfc4884 {\n\t__u16 len;\n\t__u8 flags;\n\t__u8 reserved;\n};\n\nstruct sock_extended_err {\n\t__u32 ee_errno;\n\t__u8 ee_origin;\n\t__u8 ee_type;\n\t__u8 ee_code;\n\t__u8 ee_pad;\n\t__u32 ee_info;\n\tunion {\n\t\t__u32 ee_data;\n\t\tstruct sock_ee_data_rfc4884 ee_rfc4884;\n\t};\n};\n\nstruct sock_exterr_skb {\n\tunion {\n\t\tstruct inet_skb_parm h4;\n\t\tstruct inet6_skb_parm h6;\n\t} header;\n\tstruct sock_extended_err ee;\n\tu16 addr_offset;\n\t__be16 port;\n\tu8 opt_stats: 1;\n\tu8 unused: 7;\n};\n\nstruct used_address {\n\tstruct __kernel_sockaddr_storage name;\n\tunsigned int name_len;\n};\n\nstruct linger {\n\tint l_onoff;\n\tint l_linger;\n};\n\nstruct cmsghdr {\n\t__kernel_size_t cmsg_len;\n\tint cmsg_level;\n\tint cmsg_type;\n};\n\nstruct ucred {\n\t__u32 pid;\n\t__u32 uid;\n\t__u32 gid;\n};\n\nstruct mmpin {\n\tstruct user_struct *user;\n\tunsigned int num_pg;\n};\n\nstruct ubuf_info {\n\tvoid (*callback)(struct sk_buff *, struct ubuf_info *, bool);\n\tunion {\n\t\tstruct {\n\t\t\tlong unsigned int desc;\n\t\t\tvoid *ctx;\n\t\t};\n\t\tstruct {\n\t\t\tu32 id;\n\t\t\tu16 len;\n\t\t\tu16 zerocopy: 1;\n\t\t\tu32 bytelen;\n\t\t};\n\t};\n\trefcount_t refcnt;\n\tu8 flags;\n\tstruct mmpin mmp;\n};\n\nenum {\n\tSKB_GSO_TCPV4 = 1,\n\tSKB_GSO_DODGY = 2,\n\tSKB_GSO_TCP_ECN = 4,\n\tSKB_GSO_TCP_FIXEDID = 8,\n\tSKB_GSO_TCPV6 = 16,\n\tSKB_GSO_FCOE = 32,\n\tSKB_GSO_GRE = 64,\n\tSKB_GSO_GRE_CSUM = 128,\n\tSKB_GSO_IPXIP4 = 256,\n\tSKB_GSO_IPXIP6 = 512,\n\tSKB_GSO_UDP_TUNNEL = 1024,\n\tSKB_GSO_UDP_TUNNEL_CSUM = 2048,\n\tSKB_GSO_PARTIAL = 4096,\n\tSKB_GSO_TUNNEL_REMCSUM = 8192,\n\tSKB_GSO_SCTP = 16384,\n\tSKB_GSO_ESP = 32768,\n\tSKB_GSO_UDP = 65536,\n\tSKB_GSO_UDP_L4 = 131072,\n\tSKB_GSO_FRAGLIST = 262144,\n};\n\nstruct prot_inuse {\n\tint val[64];\n};\n\nstruct gro_list {\n\tstruct list_head list;\n\tint count;\n};\n\nstruct napi_struct {\n\tstruct list_head poll_list;\n\tlong unsigned int state;\n\tint weight;\n\tint defer_hard_irqs_count;\n\tlong unsigned int gro_bitmask;\n\tint (*poll)(struct napi_struct *, int);\n\tint poll_owner;\n\tstruct net_device *dev;\n\tstruct gro_list gro_hash[8];\n\tstruct sk_buff *skb;\n\tstruct list_head rx_list;\n\tint rx_count;\n\tstruct hrtimer timer;\n\tstruct list_head dev_list;\n\tstruct hlist_node napi_hash_node;\n\tunsigned int napi_id;\n\tstruct task_struct *thread;\n};\n\nstruct sd_flow_limit {\n\tu64 count;\n\tunsigned int num_buckets;\n\tunsigned int history_head;\n\tu16 history[128];\n\tu8 buckets[0];\n};\n\nstruct softnet_data {\n\tstruct list_head poll_list;\n\tstruct sk_buff_head process_queue;\n\tunsigned int processed;\n\tunsigned int time_squeeze;\n\tunsigned int received_rps;\n\tstruct softnet_data *rps_ipi_list;\n\tstruct sd_flow_limit *flow_limit;\n\tstruct Qdisc *output_queue;\n\tstruct Qdisc **output_queue_tailp;\n\tstruct sk_buff *completion_queue;\n\tstruct sk_buff_head xfrm_backlog;\n\tstruct {\n\t\tu16 recursion;\n\t\tu8 more;\n\t} xmit;\n\tint: 32;\n\tunsigned int input_queue_head;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tcall_single_data_t csd;\n\tstruct softnet_data *rps_ipi_next;\n\tunsigned int cpu;\n\tunsigned int input_queue_tail;\n\tunsigned int dropped;\n\tstruct sk_buff_head input_pkt_queue;\n\tstruct napi_struct backlog;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct so_timestamping {\n\tint flags;\n\tint bind_phc;\n};\n\nenum txtime_flags {\n\tSOF_TXTIME_DEADLINE_MODE = 1,\n\tSOF_TXTIME_REPORT_ERRORS = 2,\n\tSOF_TXTIME_FLAGS_LAST = 2,\n\tSOF_TXTIME_FLAGS_MASK = 3,\n};\n\nstruct sock_txtime {\n\t__kernel_clockid_t clockid;\n\t__u32 flags;\n};\n\nenum sk_pacing {\n\tSK_PACING_NONE = 0,\n\tSK_PACING_NEEDED = 1,\n\tSK_PACING_FQ = 2,\n};\n\nstruct sockcm_cookie {\n\tu64 transmit_time;\n\tu32 mark;\n\tu16 tsflags;\n};\n\nstruct inet_bind_bucket {\n\tpossible_net_t ib_net;\n\tint l3mdev;\n\tshort unsigned int port;\n\tsigned char fastreuse;\n\tsigned char fastreuseport;\n\tkuid_t fastuid;\n\tstruct in6_addr fast_v6_rcv_saddr;\n\t__be32 fast_rcv_saddr;\n\tshort unsigned int fast_sk_family;\n\tbool fast_ipv6_only;\n\tstruct hlist_node node;\n\tstruct hlist_head owners;\n};\n\nstruct tcp_fastopen_cookie {\n\t__le64 val[2];\n\ts8 len;\n\tbool exp;\n};\n\nstruct tcp_sack_block {\n\tu32 start_seq;\n\tu32 end_seq;\n};\n\nstruct tcp_options_received {\n\tint ts_recent_stamp;\n\tu32 ts_recent;\n\tu32 rcv_tsval;\n\tu32 rcv_tsecr;\n\tu16 saw_tstamp: 1;\n\tu16 tstamp_ok: 1;\n\tu16 dsack: 1;\n\tu16 wscale_ok: 1;\n\tu16 sack_ok: 3;\n\tu16 smc_ok: 1;\n\tu16 snd_wscale: 4;\n\tu16 rcv_wscale: 4;\n\tu8 saw_unknown: 1;\n\tu8 unused: 7;\n\tu8 num_sacks;\n\tu16 user_mss;\n\tu16 mss_clamp;\n};\n\nstruct tcp_rack {\n\tu64 mstamp;\n\tu32 rtt_us;\n\tu32 end_seq;\n\tu32 last_delivered;\n\tu8 reo_wnd_steps;\n\tu8 reo_wnd_persist: 5;\n\tu8 dsack_seen: 1;\n\tu8 advanced: 1;\n};\n\nstruct tcp_sock_af_ops;\n\nstruct tcp_md5sig_info;\n\nstruct tcp_fastopen_request;\n\nstruct tcp_sock {\n\tstruct inet_connection_sock inet_conn;\n\tu16 tcp_header_len;\n\tu16 gso_segs;\n\t__be32 pred_flags;\n\tu64 bytes_received;\n\tu32 segs_in;\n\tu32 data_segs_in;\n\tu32 rcv_nxt;\n\tu32 copied_seq;\n\tu32 rcv_wup;\n\tu32 snd_nxt;\n\tu32 segs_out;\n\tu32 data_segs_out;\n\tu64 bytes_sent;\n\tu64 bytes_acked;\n\tu32 dsack_dups;\n\tu32 snd_una;\n\tu32 snd_sml;\n\tu32 rcv_tstamp;\n\tu32 lsndtime;\n\tu32 last_oow_ack_time;\n\tu32 compressed_ack_rcv_nxt;\n\tu32 tsoffset;\n\tstruct list_head tsq_node;\n\tstruct list_head tsorted_sent_queue;\n\tu32 snd_wl1;\n\tu32 snd_wnd;\n\tu32 max_window;\n\tu32 mss_cache;\n\tu32 window_clamp;\n\tu32 rcv_ssthresh;\n\tstruct tcp_rack rack;\n\tu16 advmss;\n\tu8 compressed_ack;\n\tu8 dup_ack_counter: 2;\n\tu8 tlp_retrans: 1;\n\tu8 unused: 5;\n\tu32 chrono_start;\n\tu32 chrono_stat[3];\n\tu8 chrono_type: 2;\n\tu8 rate_app_limited: 1;\n\tu8 fastopen_connect: 1;\n\tu8 fastopen_no_cookie: 1;\n\tu8 is_sack_reneg: 1;\n\tu8 fastopen_client_fail: 2;\n\tu8 nonagle: 4;\n\tu8 thin_lto: 1;\n\tu8 recvmsg_inq: 1;\n\tu8 repair: 1;\n\tu8 frto: 1;\n\tu8 repair_queue;\n\tu8 save_syn: 2;\n\tu8 syn_data: 1;\n\tu8 syn_fastopen: 1;\n\tu8 syn_fastopen_exp: 1;\n\tu8 syn_fastopen_ch: 1;\n\tu8 syn_data_acked: 1;\n\tu8 is_cwnd_limited: 1;\n\tu32 tlp_high_seq;\n\tu32 tcp_tx_delay;\n\tu64 tcp_wstamp_ns;\n\tu64 tcp_clock_cache;\n\tu64 tcp_mstamp;\n\tu32 srtt_us;\n\tu32 mdev_us;\n\tu32 mdev_max_us;\n\tu32 rttvar_us;\n\tu32 rtt_seq;\n\tstruct minmax rtt_min;\n\tu32 packets_out;\n\tu32 retrans_out;\n\tu32 max_packets_out;\n\tu32 max_packets_seq;\n\tu16 urg_data;\n\tu8 ecn_flags;\n\tu8 keepalive_probes;\n\tu32 reordering;\n\tu32 reord_seen;\n\tu32 snd_up;\n\tstruct tcp_options_received rx_opt;\n\tu32 snd_ssthresh;\n\tu32 snd_cwnd;\n\tu32 snd_cwnd_cnt;\n\tu32 snd_cwnd_clamp;\n\tu32 snd_cwnd_used;\n\tu32 snd_cwnd_stamp;\n\tu32 prior_cwnd;\n\tu32 prr_delivered;\n\tu32 prr_out;\n\tu32 delivered;\n\tu32 delivered_ce;\n\tu32 lost;\n\tu32 app_limited;\n\tu64 first_tx_mstamp;\n\tu64 delivered_mstamp;\n\tu32 rate_delivered;\n\tu32 rate_interval_us;\n\tu32 rcv_wnd;\n\tu32 write_seq;\n\tu32 notsent_lowat;\n\tu32 pushed_seq;\n\tu32 lost_out;\n\tu32 sacked_out;\n\tstruct hrtimer pacing_timer;\n\tstruct hrtimer compressed_ack_timer;\n\tstruct sk_buff *lost_skb_hint;\n\tstruct sk_buff *retransmit_skb_hint;\n\tstruct rb_root out_of_order_queue;\n\tstruct sk_buff *ooo_last_skb;\n\tstruct tcp_sack_block duplicate_sack[1];\n\tstruct tcp_sack_block selective_acks[4];\n\tstruct tcp_sack_block recv_sack_cache[4];\n\tstruct sk_buff *highest_sack;\n\tint lost_cnt_hint;\n\tu32 prior_ssthresh;\n\tu32 high_seq;\n\tu32 retrans_stamp;\n\tu32 undo_marker;\n\tint undo_retrans;\n\tu64 bytes_retrans;\n\tu32 total_retrans;\n\tu32 urg_seq;\n\tunsigned int keepalive_time;\n\tunsigned int keepalive_intvl;\n\tint linger2;\n\tu8 bpf_sock_ops_cb_flags;\n\tu16 timeout_rehash;\n\tu32 rcv_ooopack;\n\tu32 rcv_rtt_last_tsecr;\n\tstruct {\n\t\tu32 rtt_us;\n\t\tu32 seq;\n\t\tu64 time;\n\t} rcv_rtt_est;\n\tstruct {\n\t\tu32 space;\n\t\tu32 seq;\n\t\tu64 time;\n\t} rcvq_space;\n\tstruct {\n\t\tu32 probe_seq_start;\n\t\tu32 probe_seq_end;\n\t} mtu_probe;\n\tu32 mtu_info;\n\tbool is_mptcp;\n\tbool syn_smc;\n\tconst struct tcp_sock_af_ops *af_specific;\n\tstruct tcp_md5sig_info *md5sig_info;\n\tstruct tcp_fastopen_request *fastopen_req;\n\tstruct request_sock *fastopen_rsk;\n\tstruct saved_syn *saved_syn;\n};\n\nstruct tcp_md5sig_key;\n\nstruct tcp_sock_af_ops {\n\tstruct tcp_md5sig_key * (*md5_lookup)(const struct sock *, const struct sock *);\n\tint (*calc_md5_hash)(char *, const struct tcp_md5sig_key *, const struct sock *, const struct sk_buff *);\n\tint (*md5_parse)(struct sock *, int, sockptr_t, int);\n};\n\nstruct tcp_md5sig_info {\n\tstruct hlist_head head;\n\tstruct callback_head rcu;\n};\n\nstruct tcp_fastopen_request {\n\tstruct tcp_fastopen_cookie cookie;\n\tstruct msghdr *data;\n\tsize_t size;\n\tint copied;\n\tstruct ubuf_info *uarg;\n};\n\nunion tcp_md5_addr {\n\tstruct in_addr a4;\n\tstruct in6_addr a6;\n};\n\nstruct tcp_md5sig_key {\n\tstruct hlist_node node;\n\tu8 keylen;\n\tu8 family;\n\tu8 prefixlen;\n\tunion tcp_md5_addr addr;\n\tint l3index;\n\tu8 key[80];\n\tstruct callback_head rcu;\n};\n\nstruct net_protocol {\n\tint (*early_demux)(struct sk_buff *);\n\tint (*early_demux_handler)(struct sk_buff *);\n\tint (*handler)(struct sk_buff *);\n\tint (*err_handler)(struct sk_buff *, u32);\n\tunsigned int no_policy: 1;\n\tunsigned int icmp_strict_tag_validation: 1;\n};\n\nstruct cgroup_cls_state {\n\tstruct cgroup_subsys_state css;\n\tu32 classid;\n};\n\nenum {\n\tSK_MEMINFO_RMEM_ALLOC = 0,\n\tSK_MEMINFO_RCVBUF = 1,\n\tSK_MEMINFO_WMEM_ALLOC = 2,\n\tSK_MEMINFO_SNDBUF = 3,\n\tSK_MEMINFO_FWD_ALLOC = 4,\n\tSK_MEMINFO_WMEM_QUEUED = 5,\n\tSK_MEMINFO_OPTMEM = 6,\n\tSK_MEMINFO_BACKLOG = 7,\n\tSK_MEMINFO_DROPS = 8,\n\tSK_MEMINFO_VARS = 9,\n};\n\nenum sknetlink_groups {\n\tSKNLGRP_NONE = 0,\n\tSKNLGRP_INET_TCP_DESTROY = 1,\n\tSKNLGRP_INET_UDP_DESTROY = 2,\n\tSKNLGRP_INET6_TCP_DESTROY = 3,\n\tSKNLGRP_INET6_UDP_DESTROY = 4,\n\t__SKNLGRP_MAX = 5,\n};\n\nstruct inet_request_sock {\n\tstruct request_sock req;\n\tu16 snd_wscale: 4;\n\tu16 rcv_wscale: 4;\n\tu16 tstamp_ok: 1;\n\tu16 sack_ok: 1;\n\tu16 wscale_ok: 1;\n\tu16 ecn_ok: 1;\n\tu16 acked: 1;\n\tu16 no_srccheck: 1;\n\tu16 smc_ok: 1;\n\tu32 ir_mark;\n\tunion {\n\t\tstruct ip_options_rcu *ireq_opt;\n\t\tstruct {\n\t\t\tstruct ipv6_txoptions *ipv6_opt;\n\t\t\tstruct sk_buff *pktopts;\n\t\t};\n\t};\n};\n\nstruct tcp_request_sock_ops;\n\nstruct tcp_request_sock {\n\tstruct inet_request_sock req;\n\tconst struct tcp_request_sock_ops *af_specific;\n\tu64 snt_synack;\n\tbool tfo_listener;\n\tbool is_mptcp;\n\tbool drop_req;\n\tu32 txhash;\n\tu32 rcv_isn;\n\tu32 snt_isn;\n\tu32 ts_off;\n\tu32 last_oow_ack_time;\n\tu32 rcv_nxt;\n\tu8 syn_tos;\n};\n\nenum tcp_synack_type {\n\tTCP_SYNACK_NORMAL = 0,\n\tTCP_SYNACK_FASTOPEN = 1,\n\tTCP_SYNACK_COOKIE = 2,\n};\n\nstruct tcp_request_sock_ops {\n\tu16 mss_clamp;\n\tstruct tcp_md5sig_key * (*req_md5_lookup)(const struct sock *, const struct sock *);\n\tint (*calc_md5_hash)(char *, const struct tcp_md5sig_key *, const struct sock *, const struct sk_buff *);\n\t__u32 (*cookie_init_seq)(const struct sk_buff *, __u16 *);\n\tstruct dst_entry * (*route_req)(const struct sock *, struct sk_buff *, struct flowi *, struct request_sock *);\n\tu32 (*init_seq)(const struct sk_buff *);\n\tu32 (*init_ts_off)(const struct net *, const struct sk_buff *);\n\tint (*send_synack)(const struct sock *, struct dst_entry *, struct flowi *, struct request_sock *, struct tcp_fastopen_cookie *, enum tcp_synack_type, struct sk_buff *);\n};\n\nstruct nf_conntrack {\n\tatomic_t use;\n};\n\nenum {\n\tSKBFL_ZEROCOPY_ENABLE = 1,\n\tSKBFL_SHARED_FRAG = 2,\n};\n\nenum {\n\tSKB_FCLONE_UNAVAILABLE = 0,\n\tSKB_FCLONE_ORIG = 1,\n\tSKB_FCLONE_CLONE = 2,\n};\n\nstruct sk_buff_fclones {\n\tstruct sk_buff skb1;\n\tstruct sk_buff skb2;\n\trefcount_t fclone_ref;\n};\n\nstruct skb_seq_state {\n\t__u32 lower_offset;\n\t__u32 upper_offset;\n\t__u32 frag_idx;\n\t__u32 stepped_offset;\n\tstruct sk_buff *root_skb;\n\tstruct sk_buff *cur_skb;\n\t__u8 *frag_data;\n\t__u32 frag_off;\n};\n\nstruct skb_checksum_ops {\n\t__wsum (*update)(const void *, int, __wsum);\n\t__wsum (*combine)(__wsum, __wsum, int, int);\n};\n\nstruct skb_gso_cb {\n\tunion {\n\t\tint mac_offset;\n\t\tint data_offset;\n\t};\n\tint encap_level;\n\t__wsum csum;\n\t__u16 csum_start;\n};\n\nstruct napi_gro_cb {\n\tvoid *frag0;\n\tunsigned int frag0_len;\n\tint data_offset;\n\tu16 flush;\n\tu16 flush_id;\n\tu16 count;\n\tu16 gro_remcsum_start;\n\tlong unsigned int age;\n\tu16 proto;\n\tu8 same_flow: 1;\n\tu8 encap_mark: 1;\n\tu8 csum_valid: 1;\n\tu8 csum_cnt: 3;\n\tu8 free: 2;\n\tu8 is_ipv6: 1;\n\tu8 is_fou: 1;\n\tu8 is_atomic: 1;\n\tu8 recursion_counter: 4;\n\tu8 is_flist: 1;\n\t__wsum csum;\n\tstruct sk_buff *last;\n};\n\nenum skb_free_reason {\n\tSKB_REASON_CONSUMED = 0,\n\tSKB_REASON_DROPPED = 1,\n};\n\nstruct vlan_hdr {\n\t__be16 h_vlan_TCI;\n\t__be16 h_vlan_encapsulated_proto;\n};\n\nstruct vlan_ethhdr {\n\tunsigned char h_dest[6];\n\tunsigned char h_source[6];\n\t__be16 h_vlan_proto;\n\t__be16 h_vlan_TCI;\n\t__be16 h_vlan_encapsulated_proto;\n};\n\nstruct qdisc_walker {\n\tint stop;\n\tint skip;\n\tint count;\n\tint (*fn)(struct Qdisc *, long unsigned int, struct qdisc_walker *);\n};\n\nstruct ip_auth_hdr {\n\t__u8 nexthdr;\n\t__u8 hdrlen;\n\t__be16 reserved;\n\t__be32 spi;\n\t__be32 seq_no;\n\t__u8 auth_data[0];\n};\n\nstruct frag_hdr {\n\t__u8 nexthdr;\n\t__u8 reserved;\n\t__be16 frag_off;\n\t__be32 identification;\n};\n\nenum {\n\tSCM_TSTAMP_SND = 0,\n\tSCM_TSTAMP_SCHED = 1,\n\tSCM_TSTAMP_ACK = 2,\n};\n\nstruct mpls_shim_hdr {\n\t__be32 label_stack_entry;\n};\n\nstruct napi_alloc_cache {\n\tstruct page_frag_cache page;\n\tunsigned int skb_count;\n\tvoid *skb_cache[64];\n};\n\ntypedef int (*sendmsg_func)(struct sock *, struct msghdr *, struct kvec *, size_t, size_t);\n\ntypedef int (*sendpage_func)(struct sock *, struct page *, int, size_t, int);\n\nstruct ahash_request___2;\n\nstruct scm_cookie {\n\tstruct pid *pid;\n\tstruct scm_fp_list *fp;\n\tstruct scm_creds creds;\n\tu32 secid;\n};\n\nstruct scm_timestamping {\n\tstruct __kernel_old_timespec ts[3];\n};\n\nstruct scm_timestamping64 {\n\tstruct __kernel_timespec ts[3];\n};\n\nenum {\n\tTCA_STATS_UNSPEC = 0,\n\tTCA_STATS_BASIC = 1,\n\tTCA_STATS_RATE_EST = 2,\n\tTCA_STATS_QUEUE = 3,\n\tTCA_STATS_APP = 4,\n\tTCA_STATS_RATE_EST64 = 5,\n\tTCA_STATS_PAD = 6,\n\tTCA_STATS_BASIC_HW = 7,\n\tTCA_STATS_PKT64 = 8,\n\t__TCA_STATS_MAX = 9,\n};\n\nstruct gnet_stats_basic {\n\t__u64 bytes;\n\t__u32 packets;\n};\n\nstruct gnet_stats_rate_est {\n\t__u32 bps;\n\t__u32 pps;\n};\n\nstruct gnet_stats_rate_est64 {\n\t__u64 bps;\n\t__u64 pps;\n};\n\nstruct gnet_estimator {\n\tsigned char interval;\n\tunsigned char ewma_log;\n};\n\nstruct net_rate_estimator___2 {\n\tstruct gnet_stats_basic_packed *bstats;\n\tspinlock_t *stats_lock;\n\tseqcount_t *running;\n\tstruct gnet_stats_basic_cpu *cpu_bstats;\n\tu8 ewma_log;\n\tu8 intvl_log;\n\tseqcount_t seq;\n\tu64 last_packets;\n\tu64 last_bytes;\n\tu64 avpps;\n\tu64 avbps;\n\tlong unsigned int next_jiffies;\n\tstruct timer_list timer;\n\tstruct callback_head rcu;\n};\n\nstruct rtgenmsg {\n\tunsigned char rtgen_family;\n};\n\nenum rtnetlink_groups {\n\tRTNLGRP_NONE = 0,\n\tRTNLGRP_LINK = 1,\n\tRTNLGRP_NOTIFY = 2,\n\tRTNLGRP_NEIGH = 3,\n\tRTNLGRP_TC = 4,\n\tRTNLGRP_IPV4_IFADDR = 5,\n\tRTNLGRP_IPV4_MROUTE = 6,\n\tRTNLGRP_IPV4_ROUTE = 7,\n\tRTNLGRP_IPV4_RULE = 8,\n\tRTNLGRP_IPV6_IFADDR = 9,\n\tRTNLGRP_IPV6_MROUTE = 10,\n\tRTNLGRP_IPV6_ROUTE = 11,\n\tRTNLGRP_IPV6_IFINFO = 12,\n\tRTNLGRP_DECnet_IFADDR = 13,\n\tRTNLGRP_NOP2 = 14,\n\tRTNLGRP_DECnet_ROUTE = 15,\n\tRTNLGRP_DECnet_RULE = 16,\n\tRTNLGRP_NOP4 = 17,\n\tRTNLGRP_IPV6_PREFIX = 18,\n\tRTNLGRP_IPV6_RULE = 19,\n\tRTNLGRP_ND_USEROPT = 20,\n\tRTNLGRP_PHONET_IFADDR = 21,\n\tRTNLGRP_PHONET_ROUTE = 22,\n\tRTNLGRP_DCB = 23,\n\tRTNLGRP_IPV4_NETCONF = 24,\n\tRTNLGRP_IPV6_NETCONF = 25,\n\tRTNLGRP_MDB = 26,\n\tRTNLGRP_MPLS_ROUTE = 27,\n\tRTNLGRP_NSID = 28,\n\tRTNLGRP_MPLS_NETCONF = 29,\n\tRTNLGRP_IPV4_MROUTE_R = 30,\n\tRTNLGRP_IPV6_MROUTE_R = 31,\n\tRTNLGRP_NEXTHOP = 32,\n\tRTNLGRP_BRVLAN = 33,\n\t__RTNLGRP_MAX = 34,\n};\n\nenum {\n\tNETNSA_NONE = 0,\n\tNETNSA_NSID = 1,\n\tNETNSA_PID = 2,\n\tNETNSA_FD = 3,\n\tNETNSA_TARGET_NSID = 4,\n\tNETNSA_CURRENT_NSID = 5,\n\t__NETNSA_MAX = 6,\n};\n\nstruct pcpu_gen_cookie {\n\tlocal_t nesting;\n\tu64 last;\n};\n\nstruct gen_cookie {\n\tstruct pcpu_gen_cookie *local;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tatomic64_t forward_last;\n\tatomic64_t reverse_last;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\ntypedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, struct netlink_ext_ack *);\n\ntypedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);\n\nenum rtnl_link_flags {\n\tRTNL_FLAG_DOIT_UNLOCKED = 1,\n};\n\nstruct net_fill_args {\n\tu32 portid;\n\tu32 seq;\n\tint flags;\n\tint cmd;\n\tint nsid;\n\tbool add_ref;\n\tint ref_nsid;\n};\n\nstruct rtnl_net_dump_cb {\n\tstruct net *tgt_net;\n\tstruct net *ref_net;\n\tstruct sk_buff *skb;\n\tstruct net_fill_args fillargs;\n\tint idx;\n\tint s_idx;\n};\n\ntypedef u16 u_int16_t;\n\ntypedef u32 u_int32_t;\n\ntypedef u64 u_int64_t;\n\nstruct flow_dissector_key_control {\n\tu16 thoff;\n\tu16 addr_type;\n\tu32 flags;\n};\n\nenum flow_dissect_ret {\n\tFLOW_DISSECT_RET_OUT_GOOD = 0,\n\tFLOW_DISSECT_RET_OUT_BAD = 1,\n\tFLOW_DISSECT_RET_PROTO_AGAIN = 2,\n\tFLOW_DISSECT_RET_IPPROTO_AGAIN = 3,\n\tFLOW_DISSECT_RET_CONTINUE = 4,\n};\n\nstruct flow_dissector_key_basic {\n\t__be16 n_proto;\n\tu8 ip_proto;\n\tu8 padding;\n};\n\nstruct flow_dissector_key_tags {\n\tu32 flow_label;\n};\n\nstruct flow_dissector_key_vlan {\n\tunion {\n\t\tstruct {\n\t\t\tu16 vlan_id: 12;\n\t\t\tu16 vlan_dei: 1;\n\t\t\tu16 vlan_priority: 3;\n\t\t};\n\t\t__be16 vlan_tci;\n\t};\n\t__be16 vlan_tpid;\n};\n\nstruct flow_dissector_mpls_lse {\n\tu32 mpls_ttl: 8;\n\tu32 mpls_bos: 1;\n\tu32 mpls_tc: 3;\n\tu32 mpls_label: 20;\n};\n\nstruct flow_dissector_key_mpls {\n\tstruct flow_dissector_mpls_lse ls[7];\n\tu8 used_lses;\n};\n\nstruct flow_dissector_key_enc_opts {\n\tu8 data[255];\n\tu8 len;\n\t__be16 dst_opt_type;\n};\n\nstruct flow_dissector_key_keyid {\n\t__be32 keyid;\n};\n\nstruct flow_dissector_key_ipv4_addrs {\n\t__be32 src;\n\t__be32 dst;\n};\n\nstruct flow_dissector_key_ipv6_addrs {\n\tstruct in6_addr src;\n\tstruct in6_addr dst;\n};\n\nstruct flow_dissector_key_tipc {\n\t__be32 key;\n};\n\nstruct flow_dissector_key_addrs {\n\tunion {\n\t\tstruct flow_dissector_key_ipv4_addrs v4addrs;\n\t\tstruct flow_dissector_key_ipv6_addrs v6addrs;\n\t\tstruct flow_dissector_key_tipc tipckey;\n\t};\n};\n\nstruct flow_dissector_key_arp {\n\t__u32 sip;\n\t__u32 tip;\n\t__u8 op;\n\tunsigned char sha[6];\n\tunsigned char tha[6];\n};\n\nstruct flow_dissector_key_ports {\n\tunion {\n\t\t__be32 ports;\n\t\tstruct {\n\t\t\t__be16 src;\n\t\t\t__be16 dst;\n\t\t};\n\t};\n};\n\nstruct flow_dissector_key_icmp {\n\tstruct {\n\t\tu8 type;\n\t\tu8 code;\n\t};\n\tu16 id;\n};\n\nstruct flow_dissector_key_eth_addrs {\n\tunsigned char dst[6];\n\tunsigned char src[6];\n};\n\nstruct flow_dissector_key_tcp {\n\t__be16 flags;\n};\n\nstruct flow_dissector_key_ip {\n\t__u8 tos;\n\t__u8 ttl;\n};\n\nstruct flow_dissector_key_meta {\n\tint ingress_ifindex;\n\tu16 ingress_iftype;\n};\n\nstruct flow_dissector_key_ct {\n\tu16 ct_state;\n\tu16 ct_zone;\n\tu32 ct_mark;\n\tu32 ct_labels[4];\n};\n\nstruct flow_dissector_key_hash {\n\tu32 hash;\n};\n\nstruct flow_dissector_key {\n\tenum flow_dissector_key_id key_id;\n\tsize_t offset;\n};\n\nstruct flow_dissector {\n\tunsigned int used_keys;\n\tshort unsigned int offset[28];\n};\n\nstruct flow_keys_basic {\n\tstruct flow_dissector_key_control control;\n\tstruct flow_dissector_key_basic basic;\n};\n\nstruct flow_keys {\n\tstruct flow_dissector_key_control control;\n\tstruct flow_dissector_key_basic basic;\n\tstruct flow_dissector_key_tags tags;\n\tstruct flow_dissector_key_vlan vlan;\n\tstruct flow_dissector_key_vlan cvlan;\n\tstruct flow_dissector_key_keyid keyid;\n\tstruct flow_dissector_key_ports ports;\n\tstruct flow_dissector_key_icmp icmp;\n\tstruct flow_dissector_key_addrs addrs;\n\tint: 32;\n};\n\nstruct flow_keys_digest {\n\tu8 data[16];\n};\n\nenum ip_conntrack_info {\n\tIP_CT_ESTABLISHED = 0,\n\tIP_CT_RELATED = 1,\n\tIP_CT_NEW = 2,\n\tIP_CT_IS_REPLY = 3,\n\tIP_CT_ESTABLISHED_REPLY = 3,\n\tIP_CT_RELATED_REPLY = 4,\n\tIP_CT_NUMBER = 5,\n\tIP_CT_UNTRACKED = 7,\n};\n\nunion nf_inet_addr {\n\t__u32 all[4];\n\t__be32 ip;\n\t__be32 ip6[4];\n\tstruct in_addr in;\n\tstruct in6_addr in6;\n};\n\nstruct ip_ct_tcp_state {\n\tu_int32_t td_end;\n\tu_int32_t td_maxend;\n\tu_int32_t td_maxwin;\n\tu_int32_t td_maxack;\n\tu_int8_t td_scale;\n\tu_int8_t flags;\n};\n\nstruct ip_ct_tcp {\n\tstruct ip_ct_tcp_state seen[2];\n\tu_int8_t state;\n\tu_int8_t last_dir;\n\tu_int8_t retrans;\n\tu_int8_t last_index;\n\tu_int32_t last_seq;\n\tu_int32_t last_ack;\n\tu_int32_t last_end;\n\tu_int16_t last_win;\n\tu_int8_t last_wscale;\n\tu_int8_t last_flags;\n};\n\nunion nf_conntrack_man_proto {\n\t__be16 all;\n\tstruct {\n\t\t__be16 port;\n\t} tcp;\n\tstruct {\n\t\t__be16 port;\n\t} udp;\n\tstruct {\n\t\t__be16 id;\n\t} icmp;\n\tstruct {\n\t\t__be16 port;\n\t} dccp;\n\tstruct {\n\t\t__be16 port;\n\t} sctp;\n\tstruct {\n\t\t__be16 key;\n\t} gre;\n};\n\nstruct nf_ct_dccp {\n\tu_int8_t role[2];\n\tu_int8_t state;\n\tu_int8_t last_pkt;\n\tu_int8_t last_dir;\n\tu_int64_t handshake_seq;\n};\n\nstruct ip_ct_sctp {\n\tenum sctp_conntrack state;\n\t__be32 vtag[2];\n\tu8 last_dir;\n\tu8 flags;\n};\n\nstruct nf_ct_event;\n\nstruct nf_ct_event_notifier {\n\tint (*fcn)(unsigned int, struct nf_ct_event *);\n};\n\nstruct nf_exp_event;\n\nstruct nf_exp_event_notifier {\n\tint (*fcn)(unsigned int, struct nf_exp_event *);\n};\n\nenum bpf_ret_code {\n\tBPF_OK = 0,\n\tBPF_DROP = 2,\n\tBPF_REDIRECT = 7,\n\tBPF_LWT_REROUTE = 128,\n};\n\nenum {\n\tBPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = 1,\n\tBPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = 2,\n\tBPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = 4,\n};\n\nenum {\n\tTCA_FLOWER_KEY_CT_FLAGS_NEW = 1,\n\tTCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED = 2,\n\tTCA_FLOWER_KEY_CT_FLAGS_RELATED = 4,\n\tTCA_FLOWER_KEY_CT_FLAGS_TRACKED = 8,\n\tTCA_FLOWER_KEY_CT_FLAGS_INVALID = 16,\n\tTCA_FLOWER_KEY_CT_FLAGS_REPLY = 32,\n\t__TCA_FLOWER_KEY_CT_FLAGS_MAX = 33,\n};\n\nenum devlink_port_type {\n\tDEVLINK_PORT_TYPE_NOTSET = 0,\n\tDEVLINK_PORT_TYPE_AUTO = 1,\n\tDEVLINK_PORT_TYPE_ETH = 2,\n\tDEVLINK_PORT_TYPE_IB = 3,\n};\n\nenum devlink_port_flavour {\n\tDEVLINK_PORT_FLAVOUR_PHYSICAL = 0,\n\tDEVLINK_PORT_FLAVOUR_CPU = 1,\n\tDEVLINK_PORT_FLAVOUR_DSA = 2,\n\tDEVLINK_PORT_FLAVOUR_PCI_PF = 3,\n\tDEVLINK_PORT_FLAVOUR_PCI_VF = 4,\n\tDEVLINK_PORT_FLAVOUR_VIRTUAL = 5,\n\tDEVLINK_PORT_FLAVOUR_UNUSED = 6,\n\tDEVLINK_PORT_FLAVOUR_PCI_SF = 7,\n};\n\nstruct devlink_port_phys_attrs {\n\tu32 port_number;\n\tu32 split_subport_number;\n};\n\nstruct devlink_port_pci_pf_attrs {\n\tu32 controller;\n\tu16 pf;\n\tu8 external: 1;\n};\n\nstruct devlink_port_pci_vf_attrs {\n\tu32 controller;\n\tu16 pf;\n\tu16 vf;\n\tu8 external: 1;\n};\n\nstruct devlink_port_pci_sf_attrs {\n\tu32 controller;\n\tu32 sf;\n\tu16 pf;\n\tu8 external: 1;\n};\n\nstruct devlink_port_attrs {\n\tu8 split: 1;\n\tu8 splittable: 1;\n\tu32 lanes;\n\tenum devlink_port_flavour flavour;\n\tstruct netdev_phys_item_id switch_id;\n\tunion {\n\t\tstruct devlink_port_phys_attrs phys;\n\t\tstruct devlink_port_pci_pf_attrs pci_pf;\n\t\tstruct devlink_port_pci_vf_attrs pci_vf;\n\t\tstruct devlink_port_pci_sf_attrs pci_sf;\n\t};\n};\n\nstruct devlink;\n\nstruct devlink_rate;\n\nstruct devlink_port {\n\tstruct list_head list;\n\tstruct list_head param_list;\n\tstruct list_head region_list;\n\tstruct devlink *devlink;\n\tunsigned int index;\n\tbool registered;\n\tspinlock_t type_lock;\n\tenum devlink_port_type type;\n\tenum devlink_port_type desired_type;\n\tvoid *type_dev;\n\tstruct devlink_port_attrs attrs;\n\tu8 attrs_set: 1;\n\tu8 switch_port: 1;\n\tstruct delayed_work type_warn_dw;\n\tstruct list_head reporter_list;\n\tstruct mutex reporters_lock;\n\tstruct devlink_rate *devlink_rate;\n};\n\nstruct ip_tunnel_parm {\n\tchar name[16];\n\tint link;\n\t__be16 i_flags;\n\t__be16 o_flags;\n\t__be32 i_key;\n\t__be32 o_key;\n\tstruct iphdr iph;\n};\n\nenum phylink_op_type {\n\tPHYLINK_NETDEV = 0,\n\tPHYLINK_DEV = 1,\n};\n\nstruct phylink_link_state;\n\nstruct phylink_config {\n\tstruct device *dev;\n\tenum phylink_op_type type;\n\tbool pcs_poll;\n\tbool poll_fixed_state;\n\tbool ovr_an_inband;\n\tvoid (*get_fixed_state)(struct phylink_config *, struct phylink_link_state *);\n};\n\nstruct dsa_device_ops;\n\nstruct dsa_switch_tree;\n\nstruct packet_type;\n\nstruct dsa_switch;\n\nstruct dsa_netdevice_ops;\n\nstruct dsa_port {\n\tunion {\n\t\tstruct net_device *master;\n\t\tstruct net_device *slave;\n\t};\n\tconst struct dsa_device_ops *tag_ops;\n\tstruct dsa_switch_tree *dst;\n\tstruct sk_buff * (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *);\n\tbool (*filter)(const struct sk_buff *, struct net_device *);\n\tenum {\n\t\tDSA_PORT_TYPE_UNUSED = 0,\n\t\tDSA_PORT_TYPE_CPU = 1,\n\t\tDSA_PORT_TYPE_DSA = 2,\n\t\tDSA_PORT_TYPE_USER = 3,\n\t} type;\n\tstruct dsa_switch *ds;\n\tunsigned int index;\n\tconst char *name;\n\tstruct dsa_port *cpu_dp;\n\tu8 mac[6];\n\tstruct device_node *dn;\n\tunsigned int ageing_time;\n\tbool vlan_filtering;\n\tu8 stp_state;\n\tstruct net_device *bridge_dev;\n\tstruct devlink_port devlink_port;\n\tbool devlink_port_setup;\n\tstruct phylink *pl;\n\tstruct phylink_config pl_config;\n\tstruct net_device *lag_dev;\n\tbool lag_tx_enabled;\n\tstruct net_device *hsr_dev;\n\tstruct list_head list;\n\tvoid *priv;\n\tconst struct ethtool_ops *orig_ethtool_ops;\n\tconst struct dsa_netdevice_ops *netdev_ops;\n\tstruct list_head fdbs;\n\tstruct list_head mdbs;\n\tbool setup;\n};\n\nstruct packet_type {\n\t__be16 type;\n\tbool ignore_outgoing;\n\tstruct net_device *dev;\n\tint (*func)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);\n\tvoid (*list_func)(struct list_head *, struct packet_type *, struct net_device *);\n\tbool (*id_match)(struct packet_type *, struct sock *);\n\tvoid *af_packet_priv;\n\tstruct list_head list;\n};\n\nenum netdev_lag_tx_type {\n\tNETDEV_LAG_TX_TYPE_UNKNOWN = 0,\n\tNETDEV_LAG_TX_TYPE_RANDOM = 1,\n\tNETDEV_LAG_TX_TYPE_BROADCAST = 2,\n\tNETDEV_LAG_TX_TYPE_ROUNDROBIN = 3,\n\tNETDEV_LAG_TX_TYPE_ACTIVEBACKUP = 4,\n\tNETDEV_LAG_TX_TYPE_HASH = 5,\n};\n\nenum netdev_lag_hash {\n\tNETDEV_LAG_HASH_NONE = 0,\n\tNETDEV_LAG_HASH_L2 = 1,\n\tNETDEV_LAG_HASH_L34 = 2,\n\tNETDEV_LAG_HASH_L23 = 3,\n\tNETDEV_LAG_HASH_E23 = 4,\n\tNETDEV_LAG_HASH_E34 = 5,\n\tNETDEV_LAG_HASH_VLAN_SRCMAC = 6,\n\tNETDEV_LAG_HASH_UNKNOWN = 7,\n};\n\nstruct netdev_lag_upper_info {\n\tenum netdev_lag_tx_type tx_type;\n\tenum netdev_lag_hash hash_type;\n};\n\nstruct netdev_notifier_changeupper_info {\n\tstruct netdev_notifier_info info;\n\tstruct net_device *upper_dev;\n\tbool master;\n\tbool linking;\n\tvoid *upper_info;\n};\n\nstruct flow_match {\n\tstruct flow_dissector *dissector;\n\tvoid *mask;\n\tvoid *key;\n};\n\nenum flow_action_id {\n\tFLOW_ACTION_ACCEPT = 0,\n\tFLOW_ACTION_DROP = 1,\n\tFLOW_ACTION_TRAP = 2,\n\tFLOW_ACTION_GOTO = 3,\n\tFLOW_ACTION_REDIRECT = 4,\n\tFLOW_ACTION_MIRRED = 5,\n\tFLOW_ACTION_REDIRECT_INGRESS = 6,\n\tFLOW_ACTION_MIRRED_INGRESS = 7,\n\tFLOW_ACTION_VLAN_PUSH = 8,\n\tFLOW_ACTION_VLAN_POP = 9,\n\tFLOW_ACTION_VLAN_MANGLE = 10,\n\tFLOW_ACTION_TUNNEL_ENCAP = 11,\n\tFLOW_ACTION_TUNNEL_DECAP = 12,\n\tFLOW_ACTION_MANGLE = 13,\n\tFLOW_ACTION_ADD = 14,\n\tFLOW_ACTION_CSUM = 15,\n\tFLOW_ACTION_MARK = 16,\n\tFLOW_ACTION_PTYPE = 17,\n\tFLOW_ACTION_PRIORITY = 18,\n\tFLOW_ACTION_WAKE = 19,\n\tFLOW_ACTION_QUEUE = 20,\n\tFLOW_ACTION_SAMPLE = 21,\n\tFLOW_ACTION_POLICE = 22,\n\tFLOW_ACTION_CT = 23,\n\tFLOW_ACTION_CT_METADATA = 24,\n\tFLOW_ACTION_MPLS_PUSH = 25,\n\tFLOW_ACTION_MPLS_POP = 26,\n\tFLOW_ACTION_MPLS_MANGLE = 27,\n\tFLOW_ACTION_GATE = 28,\n\tFLOW_ACTION_PPPOE_PUSH = 29,\n\tNUM_FLOW_ACTIONS = 30,\n};\n\nenum flow_action_mangle_base {\n\tFLOW_ACT_MANGLE_UNSPEC = 0,\n\tFLOW_ACT_MANGLE_HDR_TYPE_ETH = 1,\n\tFLOW_ACT_MANGLE_HDR_TYPE_IP4 = 2,\n\tFLOW_ACT_MANGLE_HDR_TYPE_IP6 = 3,\n\tFLOW_ACT_MANGLE_HDR_TYPE_TCP = 4,\n\tFLOW_ACT_MANGLE_HDR_TYPE_UDP = 5,\n};\n\nenum flow_action_hw_stats {\n\tFLOW_ACTION_HW_STATS_IMMEDIATE = 1,\n\tFLOW_ACTION_HW_STATS_DELAYED = 2,\n\tFLOW_ACTION_HW_STATS_ANY = 3,\n\tFLOW_ACTION_HW_STATS_DISABLED = 4,\n\tFLOW_ACTION_HW_STATS_DONT_CARE = 7,\n};\n\ntypedef void (*action_destr)(void *);\n\nstruct flow_action_cookie {\n\tu32 cookie_len;\n\tu8 cookie[0];\n};\n\nstruct nf_flowtable;\n\nstruct ip_tunnel_key {\n\t__be64 tun_id;\n\tunion {\n\t\tstruct {\n\t\t\t__be32 src;\n\t\t\t__be32 dst;\n\t\t} ipv4;\n\t\tstruct {\n\t\t\tstruct in6_addr src;\n\t\t\tstruct in6_addr dst;\n\t\t} ipv6;\n\t} u;\n\t__be16 tun_flags;\n\tu8 tos;\n\tu8 ttl;\n\t__be32 label;\n\t__be16 tp_src;\n\t__be16 tp_dst;\n};\n\nstruct dst_cache_pcpu;\n\nstruct dst_cache {\n\tstruct dst_cache_pcpu *cache;\n\tlong unsigned int reset_ts;\n};\n\nstruct ip_tunnel_info {\n\tstruct ip_tunnel_key key;\n\tstruct dst_cache dst_cache;\n\tu8 options_len;\n\tu8 mode;\n};\n\nstruct psample_group;\n\nstruct action_gate_entry;\n\nstruct flow_action_entry {\n\tenum flow_action_id id;\n\tenum flow_action_hw_stats hw_stats;\n\taction_destr destructor;\n\tvoid *destructor_priv;\n\tunion {\n\t\tu32 chain_index;\n\t\tstruct net_device *dev;\n\t\tstruct {\n\t\t\tu16 vid;\n\t\t\t__be16 proto;\n\t\t\tu8 prio;\n\t\t} vlan;\n\t\tstruct {\n\t\t\tenum flow_action_mangle_base htype;\n\t\t\tu32 offset;\n\t\t\tu32 mask;\n\t\t\tu32 val;\n\t\t} mangle;\n\t\tstruct ip_tunnel_info *tunnel;\n\t\tu32 csum_flags;\n\t\tu32 mark;\n\t\tu16 ptype;\n\t\tu32 priority;\n\t\tstruct {\n\t\t\tu32 ctx;\n\t\t\tu32 index;\n\t\t\tu8 vf;\n\t\t} queue;\n\t\tstruct {\n\t\t\tstruct psample_group *psample_group;\n\t\t\tu32 rate;\n\t\t\tu32 trunc_size;\n\t\t\tbool truncate;\n\t\t} sample;\n\t\tstruct {\n\t\t\tu32 index;\n\t\t\tu32 burst;\n\t\t\tu64 rate_bytes_ps;\n\t\t\tu64 burst_pkt;\n\t\t\tu64 rate_pkt_ps;\n\t\t\tu32 mtu;\n\t\t} police;\n\t\tstruct {\n\t\t\tint action;\n\t\t\tu16 zone;\n\t\t\tstruct nf_flowtable *flow_table;\n\t\t} ct;\n\t\tstruct {\n\t\t\tlong unsigned int cookie;\n\t\t\tu32 mark;\n\t\t\tu32 labels[4];\n\t\t\tbool orig_dir;\n\t\t} ct_metadata;\n\t\tstruct {\n\t\t\tu32 label;\n\t\t\t__be16 proto;\n\t\t\tu8 tc;\n\t\t\tu8 bos;\n\t\t\tu8 ttl;\n\t\t} mpls_push;\n\t\tstruct {\n\t\t\t__be16 proto;\n\t\t} mpls_pop;\n\t\tstruct {\n\t\t\tu32 label;\n\t\t\tu8 tc;\n\t\t\tu8 bos;\n\t\t\tu8 ttl;\n\t\t} mpls_mangle;\n\t\tstruct {\n\t\t\tu32 index;\n\t\t\ts32 prio;\n\t\t\tu64 basetime;\n\t\t\tu64 cycletime;\n\t\t\tu64 cycletimeext;\n\t\t\tu32 num_entries;\n\t\t\tstruct action_gate_entry *entries;\n\t\t} gate;\n\t\tstruct {\n\t\t\tu16 sid;\n\t\t} pppoe;\n\t};\n\tstruct flow_action_cookie *cookie;\n};\n\nstruct flow_action {\n\tunsigned int num_entries;\n\tstruct flow_action_entry entries[0];\n};\n\nstruct flow_rule {\n\tstruct flow_match match;\n\tstruct flow_action action;\n};\n\nstruct flow_stats {\n\tu64 pkts;\n\tu64 bytes;\n\tu64 drops;\n\tu64 lastused;\n\tenum flow_action_hw_stats used_hw_stats;\n\tbool used_hw_stats_valid;\n};\n\nenum flow_cls_command {\n\tFLOW_CLS_REPLACE = 0,\n\tFLOW_CLS_DESTROY = 1,\n\tFLOW_CLS_STATS = 2,\n\tFLOW_CLS_TMPLT_CREATE = 3,\n\tFLOW_CLS_TMPLT_DESTROY = 4,\n};\n\nstruct flow_cls_common_offload {\n\tu32 chain_index;\n\t__be16 protocol;\n\tu32 prio;\n\tstruct netlink_ext_ack *extack;\n};\n\nstruct flow_cls_offload {\n\tstruct flow_cls_common_offload common;\n\tenum flow_cls_command command;\n\tlong unsigned int cookie;\n\tstruct flow_rule *rule;\n\tstruct flow_stats stats;\n\tu32 classid;\n};\n\nunion tcp_word_hdr {\n\tstruct tcphdr hdr;\n\t__be32 words[5];\n};\n\nstruct dsa_chip_data {\n\tstruct device *host_dev;\n\tint sw_addr;\n\tstruct device *netdev[12];\n\tint eeprom_len;\n\tstruct device_node *of_node;\n\tchar *port_names[12];\n\tstruct device_node *port_dn[12];\n\ts8 rtable[4];\n};\n\nstruct dsa_platform_data {\n\tstruct device *netdev;\n\tstruct net_device *of_netdev;\n\tint nr_chips;\n\tstruct dsa_chip_data *chip;\n};\n\nstruct phylink_link_state {\n\tlong unsigned int advertising[2];\n\tlong unsigned int lp_advertising[2];\n\tphy_interface_t interface;\n\tint speed;\n\tint duplex;\n\tint pause;\n\tunsigned int link: 1;\n\tunsigned int an_enabled: 1;\n\tunsigned int an_complete: 1;\n};\n\nenum devlink_sb_pool_type {\n\tDEVLINK_SB_POOL_TYPE_INGRESS = 0,\n\tDEVLINK_SB_POOL_TYPE_EGRESS = 1,\n};\n\nenum devlink_sb_threshold_type {\n\tDEVLINK_SB_THRESHOLD_TYPE_STATIC = 0,\n\tDEVLINK_SB_THRESHOLD_TYPE_DYNAMIC = 1,\n};\n\nenum devlink_eswitch_encap_mode {\n\tDEVLINK_ESWITCH_ENCAP_MODE_NONE = 0,\n\tDEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1,\n};\n\nenum devlink_rate_type {\n\tDEVLINK_RATE_TYPE_LEAF = 0,\n\tDEVLINK_RATE_TYPE_NODE = 1,\n};\n\nenum devlink_param_cmode {\n\tDEVLINK_PARAM_CMODE_RUNTIME = 0,\n\tDEVLINK_PARAM_CMODE_DRIVERINIT = 1,\n\tDEVLINK_PARAM_CMODE_PERMANENT = 2,\n\t__DEVLINK_PARAM_CMODE_MAX = 3,\n\tDEVLINK_PARAM_CMODE_MAX = 2,\n};\n\nenum devlink_trap_action {\n\tDEVLINK_TRAP_ACTION_DROP = 0,\n\tDEVLINK_TRAP_ACTION_TRAP = 1,\n\tDEVLINK_TRAP_ACTION_MIRROR = 2,\n};\n\nenum devlink_trap_type {\n\tDEVLINK_TRAP_TYPE_DROP = 0,\n\tDEVLINK_TRAP_TYPE_EXCEPTION = 1,\n\tDEVLINK_TRAP_TYPE_CONTROL = 2,\n};\n\nenum devlink_reload_action {\n\tDEVLINK_RELOAD_ACTION_UNSPEC = 0,\n\tDEVLINK_RELOAD_ACTION_DRIVER_REINIT = 1,\n\tDEVLINK_RELOAD_ACTION_FW_ACTIVATE = 2,\n\t__DEVLINK_RELOAD_ACTION_MAX = 3,\n\tDEVLINK_RELOAD_ACTION_MAX = 2,\n};\n\nenum devlink_reload_limit {\n\tDEVLINK_RELOAD_LIMIT_UNSPEC = 0,\n\tDEVLINK_RELOAD_LIMIT_NO_RESET = 1,\n\t__DEVLINK_RELOAD_LIMIT_MAX = 2,\n\tDEVLINK_RELOAD_LIMIT_MAX = 1,\n};\n\nenum devlink_dpipe_field_mapping_type {\n\tDEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0,\n\tDEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 1,\n};\n\nenum devlink_port_fn_state {\n\tDEVLINK_PORT_FN_STATE_INACTIVE = 0,\n\tDEVLINK_PORT_FN_STATE_ACTIVE = 1,\n};\n\nenum devlink_port_fn_opstate {\n\tDEVLINK_PORT_FN_OPSTATE_DETACHED = 0,\n\tDEVLINK_PORT_FN_OPSTATE_ATTACHED = 1,\n};\n\nstruct devlink_dev_stats {\n\tu32 reload_stats[6];\n\tu32 remote_reload_stats[6];\n};\n\nstruct devlink_dpipe_headers;\n\nstruct devlink_ops;\n\nstruct devlink {\n\tstruct list_head list;\n\tstruct list_head port_list;\n\tstruct list_head rate_list;\n\tstruct list_head sb_list;\n\tstruct list_head dpipe_table_list;\n\tstruct list_head resource_list;\n\tstruct list_head param_list;\n\tstruct list_head region_list;\n\tstruct list_head reporter_list;\n\tstruct mutex reporters_lock;\n\tstruct devlink_dpipe_headers *dpipe_headers;\n\tstruct list_head trap_list;\n\tstruct list_head trap_group_list;\n\tstruct list_head trap_policer_list;\n\tconst struct devlink_ops *ops;\n\tstruct xarray snapshot_ids;\n\tstruct devlink_dev_stats stats;\n\tstruct device *dev;\n\tpossible_net_t _net;\n\tstruct mutex lock;\n\tu8 reload_failed: 1;\n\tu8 reload_enabled: 1;\n\tu8 registered: 1;\n\tlong: 61;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tchar priv[0];\n};\n\nstruct devlink_dpipe_header;\n\nstruct devlink_dpipe_headers {\n\tstruct devlink_dpipe_header **headers;\n\tunsigned int headers_count;\n};\n\nstruct devlink_sb_pool_info;\n\nstruct devlink_info_req;\n\nstruct devlink_flash_update_params;\n\nstruct devlink_trap;\n\nstruct devlink_trap_group;\n\nstruct devlink_trap_policer;\n\nstruct devlink_port_new_attrs;\n\nstruct devlink_ops {\n\tu32 supported_flash_update_params;\n\tlong unsigned int reload_actions;\n\tlong unsigned int reload_limits;\n\tint (*reload_down)(struct devlink *, bool, enum devlink_reload_action, enum devlink_reload_limit, struct netlink_ext_ack *);\n\tint (*reload_up)(struct devlink *, enum devlink_reload_action, enum devlink_reload_limit, u32 *, struct netlink_ext_ack *);\n\tint (*port_type_set)(struct devlink_port *, enum devlink_port_type);\n\tint (*port_split)(struct devlink *, unsigned int, unsigned int, struct netlink_ext_ack *);\n\tint (*port_unsplit)(struct devlink *, unsigned int, struct netlink_ext_ack *);\n\tint (*sb_pool_get)(struct devlink *, unsigned int, u16, struct devlink_sb_pool_info *);\n\tint (*sb_pool_set)(struct devlink *, unsigned int, u16, u32, enum devlink_sb_threshold_type, struct netlink_ext_ack *);\n\tint (*sb_port_pool_get)(struct devlink_port *, unsigned int, u16, u32 *);\n\tint (*sb_port_pool_set)(struct devlink_port *, unsigned int, u16, u32, struct netlink_ext_ack *);\n\tint (*sb_tc_pool_bind_get)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u16 *, u32 *);\n\tint (*sb_tc_pool_bind_set)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u16, u32, struct netlink_ext_ack *);\n\tint (*sb_occ_snapshot)(struct devlink *, unsigned int);\n\tint (*sb_occ_max_clear)(struct devlink *, unsigned int);\n\tint (*sb_occ_port_pool_get)(struct devlink_port *, unsigned int, u16, u32 *, u32 *);\n\tint (*sb_occ_tc_port_bind_get)(struct devlink_port *, unsigned int, u16, enum devlink_sb_pool_type, u32 *, u32 *);\n\tint (*eswitch_mode_get)(struct devlink *, u16 *);\n\tint (*eswitch_mode_set)(struct devlink *, u16, struct netlink_ext_ack *);\n\tint (*eswitch_inline_mode_get)(struct devlink *, u8 *);\n\tint (*eswitch_inline_mode_set)(struct devlink *, u8, struct netlink_ext_ack *);\n\tint (*eswitch_encap_mode_get)(struct devlink *, enum devlink_eswitch_encap_mode *);\n\tint (*eswitch_encap_mode_set)(struct devlink *, enum devlink_eswitch_encap_mode, struct netlink_ext_ack *);\n\tint (*info_get)(struct devlink *, struct devlink_info_req *, struct netlink_ext_ack *);\n\tint (*flash_update)(struct devlink *, struct devlink_flash_update_params *, struct netlink_ext_ack *);\n\tint (*trap_init)(struct devlink *, const struct devlink_trap *, void *);\n\tvoid (*trap_fini)(struct devlink *, const struct devlink_trap *, void *);\n\tint (*trap_action_set)(struct devlink *, const struct devlink_trap *, enum devlink_trap_action, struct netlink_ext_ack *);\n\tint (*trap_group_init)(struct devlink *, const struct devlink_trap_group *);\n\tint (*trap_group_set)(struct devlink *, const struct devlink_trap_group *, const struct devlink_trap_policer *, struct netlink_ext_ack *);\n\tint (*trap_group_action_set)(struct devlink *, const struct devlink_trap_group *, enum devlink_trap_action, struct netlink_ext_ack *);\n\tint (*trap_drop_counter_get)(struct devlink *, const struct devlink_trap *, u64 *);\n\tint (*trap_policer_init)(struct devlink *, const struct devlink_trap_policer *);\n\tvoid (*trap_policer_fini)(struct devlink *, const struct devlink_trap_policer *);\n\tint (*trap_policer_set)(struct devlink *, const struct devlink_trap_policer *, u64, u64, struct netlink_ext_ack *);\n\tint (*trap_policer_counter_get)(struct devlink *, const struct devlink_trap_policer *, u64 *);\n\tint (*port_function_hw_addr_get)(struct devlink *, struct devlink_port *, u8 *, int *, struct netlink_ext_ack *);\n\tint (*port_function_hw_addr_set)(struct devlink *, struct devlink_port *, const u8 *, int, struct netlink_ext_ack *);\n\tint (*port_new)(struct devlink *, const struct devlink_port_new_attrs *, struct netlink_ext_ack *, unsigned int *);\n\tint (*port_del)(struct devlink *, unsigned int, struct netlink_ext_ack *);\n\tint (*port_fn_state_get)(struct devlink *, struct devlink_port *, enum devlink_port_fn_state *, enum devlink_port_fn_opstate *, struct netlink_ext_ack *);\n\tint (*port_fn_state_set)(struct devlink *, struct devlink_port *, enum devlink_port_fn_state, struct netlink_ext_ack *);\n\tint (*rate_leaf_tx_share_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *);\n\tint (*rate_leaf_tx_max_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *);\n\tint (*rate_node_tx_share_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *);\n\tint (*rate_node_tx_max_set)(struct devlink_rate *, void *, u64, struct netlink_ext_ack *);\n\tint (*rate_node_new)(struct devlink_rate *, void **, struct netlink_ext_ack *);\n\tint (*rate_node_del)(struct devlink_rate *, void *, struct netlink_ext_ack *);\n\tint (*rate_leaf_parent_set)(struct devlink_rate *, struct devlink_rate *, void *, void *, struct netlink_ext_ack *);\n\tint (*rate_node_parent_set)(struct devlink_rate *, struct devlink_rate *, void *, void *, struct netlink_ext_ack *);\n};\n\nstruct devlink_rate {\n\tstruct list_head list;\n\tenum devlink_rate_type type;\n\tstruct devlink *devlink;\n\tvoid *priv;\n\tu64 tx_share;\n\tu64 tx_max;\n\tstruct devlink_rate *parent;\n\tunion {\n\t\tstruct devlink_port *devlink_port;\n\t\tstruct {\n\t\t\tchar *name;\n\t\t\trefcount_t refcnt;\n\t\t};\n\t};\n};\n\nstruct devlink_port_new_attrs {\n\tenum devlink_port_flavour flavour;\n\tunsigned int port_index;\n\tu32 controller;\n\tu32 sfnum;\n\tu16 pfnum;\n\tu8 port_index_valid: 1;\n\tu8 controller_valid: 1;\n\tu8 sfnum_valid: 1;\n};\n\nstruct devlink_sb_pool_info {\n\tenum devlink_sb_pool_type pool_type;\n\tu32 size;\n\tenum devlink_sb_threshold_type threshold_type;\n\tu32 cell_size;\n};\n\nstruct devlink_dpipe_field {\n\tconst char *name;\n\tunsigned int id;\n\tunsigned int bitwidth;\n\tenum devlink_dpipe_field_mapping_type mapping_type;\n};\n\nstruct devlink_dpipe_header {\n\tconst char *name;\n\tunsigned int id;\n\tstruct devlink_dpipe_field *fields;\n\tunsigned int fields_count;\n\tbool global;\n};\n\nunion devlink_param_value {\n\tu8 vu8;\n\tu16 vu16;\n\tu32 vu32;\n\tchar vstr[32];\n\tbool vbool;\n};\n\nstruct devlink_param_gset_ctx {\n\tunion devlink_param_value val;\n\tenum devlink_param_cmode cmode;\n};\n\nstruct devlink_flash_update_params {\n\tconst struct firmware *fw;\n\tconst char *component;\n\tu32 overwrite_mask;\n};\n\nstruct devlink_trap_policer {\n\tu32 id;\n\tu64 init_rate;\n\tu64 init_burst;\n\tu64 max_rate;\n\tu64 min_rate;\n\tu64 max_burst;\n\tu64 min_burst;\n};\n\nstruct devlink_trap_group {\n\tconst char *name;\n\tu16 id;\n\tbool generic;\n\tu32 init_policer_id;\n};\n\nstruct devlink_trap {\n\tenum devlink_trap_type type;\n\tenum devlink_trap_action init_action;\n\tbool generic;\n\tu16 id;\n\tconst char *name;\n\tu16 init_group_id;\n\tu32 metadata_cap;\n};\n\nstruct arphdr {\n\t__be16 ar_hrd;\n\t__be16 ar_pro;\n\tunsigned char ar_hln;\n\tunsigned char ar_pln;\n\t__be16 ar_op;\n};\n\nstruct fib_info;\n\nstruct fib_nh {\n\tstruct fib_nh_common nh_common;\n\tstruct hlist_node nh_hash;\n\tstruct fib_info *nh_parent;\n\t__u32 nh_tclassid;\n\t__be32 nh_saddr;\n\tint nh_saddr_genid;\n};\n\nstruct fib_info {\n\tstruct hlist_node fib_hash;\n\tstruct hlist_node fib_lhash;\n\tstruct list_head nh_list;\n\tstruct net *fib_net;\n\tint fib_treeref;\n\trefcount_t fib_clntref;\n\tunsigned int fib_flags;\n\tunsigned char fib_dead;\n\tunsigned char fib_protocol;\n\tunsigned char fib_scope;\n\tunsigned char fib_type;\n\t__be32 fib_prefsrc;\n\tu32 fib_tb_id;\n\tu32 fib_priority;\n\tstruct dst_metrics *fib_metrics;\n\tint fib_nhs;\n\tbool fib_nh_is_v6;\n\tbool nh_updated;\n\tstruct nexthop *nh;\n\tstruct callback_head rcu;\n\tstruct fib_nh fib_nh[0];\n};\n\nstruct nh_info;\n\nstruct nh_group;\n\nstruct nexthop {\n\tstruct rb_node rb_node;\n\tstruct list_head fi_list;\n\tstruct list_head f6i_list;\n\tstruct list_head fdb_list;\n\tstruct list_head grp_list;\n\tstruct net *net;\n\tu32 id;\n\tu8 protocol;\n\tu8 nh_flags;\n\tbool is_group;\n\trefcount_t refcnt;\n\tstruct callback_head rcu;\n\tunion {\n\t\tstruct nh_info *nh_info;\n\t\tstruct nh_group *nh_grp;\n\t};\n};\n\nstruct switchdev_brport_flags {\n\tlong unsigned int val;\n\tlong unsigned int mask;\n};\n\nenum switchdev_obj_id {\n\tSWITCHDEV_OBJ_ID_UNDEFINED = 0,\n\tSWITCHDEV_OBJ_ID_PORT_VLAN = 1,\n\tSWITCHDEV_OBJ_ID_PORT_MDB = 2,\n\tSWITCHDEV_OBJ_ID_HOST_MDB = 3,\n\tSWITCHDEV_OBJ_ID_MRP = 4,\n\tSWITCHDEV_OBJ_ID_RING_TEST_MRP = 5,\n\tSWITCHDEV_OBJ_ID_RING_ROLE_MRP = 6,\n\tSWITCHDEV_OBJ_ID_RING_STATE_MRP = 7,\n\tSWITCHDEV_OBJ_ID_IN_TEST_MRP = 8,\n\tSWITCHDEV_OBJ_ID_IN_ROLE_MRP = 9,\n\tSWITCHDEV_OBJ_ID_IN_STATE_MRP = 10,\n};\n\nstruct switchdev_obj {\n\tstruct list_head list;\n\tstruct net_device *orig_dev;\n\tenum switchdev_obj_id id;\n\tu32 flags;\n\tvoid *complete_priv;\n\tvoid (*complete)(struct net_device *, int, void *);\n};\n\nstruct switchdev_obj_port_vlan {\n\tstruct switchdev_obj obj;\n\tu16 flags;\n\tu16 vid;\n};\n\nstruct switchdev_obj_port_mdb {\n\tstruct switchdev_obj obj;\n\tunsigned char addr[6];\n\tu16 vid;\n};\n\nstruct switchdev_obj_mrp {\n\tstruct switchdev_obj obj;\n\tstruct net_device *p_port;\n\tstruct net_device *s_port;\n\tu32 ring_id;\n\tu16 prio;\n};\n\nstruct switchdev_obj_ring_role_mrp {\n\tstruct switchdev_obj obj;\n\tu8 ring_role;\n\tu32 ring_id;\n\tu8 sw_backup;\n};\n\nenum dsa_tag_protocol {\n\tDSA_TAG_PROTO_NONE = 0,\n\tDSA_TAG_PROTO_BRCM = 1,\n\tDSA_TAG_PROTO_BRCM_LEGACY = 22,\n\tDSA_TAG_PROTO_BRCM_PREPEND = 2,\n\tDSA_TAG_PROTO_DSA = 3,\n\tDSA_TAG_PROTO_EDSA = 4,\n\tDSA_TAG_PROTO_GSWIP = 5,\n\tDSA_TAG_PROTO_KSZ9477 = 6,\n\tDSA_TAG_PROTO_KSZ9893 = 7,\n\tDSA_TAG_PROTO_LAN9303 = 8,\n\tDSA_TAG_PROTO_MTK = 9,\n\tDSA_TAG_PROTO_QCA = 10,\n\tDSA_TAG_PROTO_TRAILER = 11,\n\tDSA_TAG_PROTO_8021Q = 12,\n\tDSA_TAG_PROTO_SJA1105 = 13,\n\tDSA_TAG_PROTO_KSZ8795 = 14,\n\tDSA_TAG_PROTO_OCELOT = 15,\n\tDSA_TAG_PROTO_AR9331 = 16,\n\tDSA_TAG_PROTO_RTL4_A = 17,\n\tDSA_TAG_PROTO_HELLCREEK = 18,\n\tDSA_TAG_PROTO_XRS700X = 19,\n\tDSA_TAG_PROTO_OCELOT_8021Q = 20,\n\tDSA_TAG_PROTO_SEVILLE = 21,\n\tDSA_TAG_PROTO_SJA1110 = 23,\n};\n\nstruct dsa_device_ops {\n\tstruct sk_buff * (*xmit)(struct sk_buff *, struct net_device *);\n\tstruct sk_buff * (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *);\n\tvoid (*flow_dissect)(const struct sk_buff *, __be16 *, int *);\n\tbool (*filter)(const struct sk_buff *, struct net_device *);\n\tunsigned int needed_headroom;\n\tunsigned int needed_tailroom;\n\tconst char *name;\n\tenum dsa_tag_protocol proto;\n\tbool promisc_on_master;\n};\n\nstruct dsa_netdevice_ops {\n\tint (*ndo_do_ioctl)(struct net_device *, struct ifreq *, int);\n};\n\nstruct dsa_switch_tree {\n\tstruct list_head list;\n\tstruct raw_notifier_head nh;\n\tunsigned int index;\n\tstruct kref refcount;\n\tbool setup;\n\tconst struct dsa_device_ops *tag_ops;\n\tenum dsa_tag_protocol default_proto;\n\tstruct dsa_platform_data *pd;\n\tstruct list_head ports;\n\tstruct list_head rtable;\n\tstruct net_device **lags;\n\tunsigned int lags_len;\n};\n\nstruct dsa_mall_mirror_tc_entry {\n\tu8 to_local_port;\n\tbool ingress;\n};\n\nstruct dsa_mall_policer_tc_entry {\n\tu32 burst;\n\tu64 rate_bytes_per_sec;\n};\n\nstruct dsa_switch_ops;\n\nstruct dsa_switch {\n\tbool setup;\n\tstruct device *dev;\n\tstruct dsa_switch_tree *dst;\n\tunsigned int index;\n\tstruct notifier_block nb;\n\tvoid *priv;\n\tstruct dsa_chip_data *cd;\n\tconst struct dsa_switch_ops *ops;\n\tu32 phys_mii_mask;\n\tstruct mii_bus *slave_mii_bus;\n\tunsigned int ageing_time_min;\n\tunsigned int ageing_time_max;\n\tstruct devlink *devlink;\n\tunsigned int num_tx_queues;\n\tbool vlan_filtering_is_global;\n\tbool configure_vlan_while_not_filtering;\n\tbool untag_bridge_pvid;\n\tbool assisted_learning_on_cpu_port;\n\tbool vlan_filtering;\n\tbool pcs_poll;\n\tbool mtu_enforcement_ingress;\n\tunsigned int num_lag_ids;\n\tsize_t num_ports;\n};\n\nstruct fixed_phy_status;\n\ntypedef int dsa_fdb_dump_cb_t(const unsigned char *, u16, bool, void *);\n\nstruct dsa_switch_ops {\n\tenum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *, int, enum dsa_tag_protocol);\n\tint (*change_tag_protocol)(struct dsa_switch *, int, enum dsa_tag_protocol);\n\tint (*setup)(struct dsa_switch *);\n\tvoid (*teardown)(struct dsa_switch *);\n\tu32 (*get_phy_flags)(struct dsa_switch *, int);\n\tint (*phy_read)(struct dsa_switch *, int, int);\n\tint (*phy_write)(struct dsa_switch *, int, int, u16);\n\tvoid (*adjust_link)(struct dsa_switch *, int, struct phy_device *);\n\tvoid (*fixed_link_update)(struct dsa_switch *, int, struct fixed_phy_status *);\n\tvoid (*phylink_validate)(struct dsa_switch *, int, long unsigned int *, struct phylink_link_state *);\n\tint (*phylink_mac_link_state)(struct dsa_switch *, int, struct phylink_link_state *);\n\tvoid (*phylink_mac_config)(struct dsa_switch *, int, unsigned int, const struct phylink_link_state *);\n\tvoid (*phylink_mac_an_restart)(struct dsa_switch *, int);\n\tvoid (*phylink_mac_link_down)(struct dsa_switch *, int, unsigned int, phy_interface_t);\n\tvoid (*phylink_mac_link_up)(struct dsa_switch *, int, unsigned int, phy_interface_t, struct phy_device *, int, int, bool, bool);\n\tvoid (*phylink_fixed_state)(struct dsa_switch *, int, struct phylink_link_state *);\n\tvoid (*get_strings)(struct dsa_switch *, int, u32, uint8_t *);\n\tvoid (*get_ethtool_stats)(struct dsa_switch *, int, uint64_t *);\n\tint (*get_sset_count)(struct dsa_switch *, int, int);\n\tvoid (*get_ethtool_phy_stats)(struct dsa_switch *, int, uint64_t *);\n\tvoid (*get_stats64)(struct dsa_switch *, int, struct rtnl_link_stats64 *);\n\tvoid (*self_test)(struct dsa_switch *, int, struct ethtool_test *, u64 *);\n\tvoid (*get_wol)(struct dsa_switch *, int, struct ethtool_wolinfo *);\n\tint (*set_wol)(struct dsa_switch *, int, struct ethtool_wolinfo *);\n\tint (*get_ts_info)(struct dsa_switch *, int, struct ethtool_ts_info *);\n\tint (*suspend)(struct dsa_switch *);\n\tint (*resume)(struct dsa_switch *);\n\tint (*port_enable)(struct dsa_switch *, int, struct phy_device *);\n\tvoid (*port_disable)(struct dsa_switch *, int);\n\tint (*set_mac_eee)(struct dsa_switch *, int, struct ethtool_eee *);\n\tint (*get_mac_eee)(struct dsa_switch *, int, struct ethtool_eee *);\n\tint (*get_eeprom_len)(struct dsa_switch *);\n\tint (*get_eeprom)(struct dsa_switch *, struct ethtool_eeprom *, u8 *);\n\tint (*set_eeprom)(struct dsa_switch *, struct ethtool_eeprom *, u8 *);\n\tint (*get_regs_len)(struct dsa_switch *, int);\n\tvoid (*get_regs)(struct dsa_switch *, int, struct ethtool_regs *, void *);\n\tint (*port_prechangeupper)(struct dsa_switch *, int, struct netdev_notifier_changeupper_info *);\n\tint (*set_ageing_time)(struct dsa_switch *, unsigned int);\n\tint (*port_bridge_join)(struct dsa_switch *, int, struct net_device *);\n\tvoid (*port_bridge_leave)(struct dsa_switch *, int, struct net_device *);\n\tvoid (*port_stp_state_set)(struct dsa_switch *, int, u8);\n\tvoid (*port_fast_age)(struct dsa_switch *, int);\n\tint (*port_pre_bridge_flags)(struct dsa_switch *, int, struct switchdev_brport_flags, struct netlink_ext_ack *);\n\tint (*port_bridge_flags)(struct dsa_switch *, int, struct switchdev_brport_flags, struct netlink_ext_ack *);\n\tint (*port_set_mrouter)(struct dsa_switch *, int, bool, struct netlink_ext_ack *);\n\tint (*port_vlan_filtering)(struct dsa_switch *, int, bool, struct netlink_ext_ack *);\n\tint (*port_vlan_add)(struct dsa_switch *, int, const struct switchdev_obj_port_vlan *, struct netlink_ext_ack *);\n\tint (*port_vlan_del)(struct dsa_switch *, int, const struct switchdev_obj_port_vlan *);\n\tint (*port_fdb_add)(struct dsa_switch *, int, const unsigned char *, u16);\n\tint (*port_fdb_del)(struct dsa_switch *, int, const unsigned char *, u16);\n\tint (*port_fdb_dump)(struct dsa_switch *, int, dsa_fdb_dump_cb_t *, void *);\n\tint (*port_mdb_add)(struct dsa_switch *, int, const struct switchdev_obj_port_mdb *);\n\tint (*port_mdb_del)(struct dsa_switch *, int, const struct switchdev_obj_port_mdb *);\n\tint (*get_rxnfc)(struct dsa_switch *, int, struct ethtool_rxnfc *, u32 *);\n\tint (*set_rxnfc)(struct dsa_switch *, int, struct ethtool_rxnfc *);\n\tint (*cls_flower_add)(struct dsa_switch *, int, struct flow_cls_offload *, bool);\n\tint (*cls_flower_del)(struct dsa_switch *, int, struct flow_cls_offload *, bool);\n\tint (*cls_flower_stats)(struct dsa_switch *, int, struct flow_cls_offload *, bool);\n\tint (*port_mirror_add)(struct dsa_switch *, int, struct dsa_mall_mirror_tc_entry *, bool);\n\tvoid (*port_mirror_del)(struct dsa_switch *, int, struct dsa_mall_mirror_tc_entry *);\n\tint (*port_policer_add)(struct dsa_switch *, int, struct dsa_mall_policer_tc_entry *);\n\tvoid (*port_policer_del)(struct dsa_switch *, int);\n\tint (*port_setup_tc)(struct dsa_switch *, int, enum tc_setup_type, void *);\n\tint (*crosschip_bridge_join)(struct dsa_switch *, int, int, int, struct net_device *);\n\tvoid (*crosschip_bridge_leave)(struct dsa_switch *, int, int, int, struct net_device *);\n\tint (*crosschip_lag_change)(struct dsa_switch *, int, int);\n\tint (*crosschip_lag_join)(struct dsa_switch *, int, int, struct net_device *, struct netdev_lag_upper_info *);\n\tint (*crosschip_lag_leave)(struct dsa_switch *, int, int, struct net_device *);\n\tint (*port_hwtstamp_get)(struct dsa_switch *, int, struct ifreq *);\n\tint (*port_hwtstamp_set)(struct dsa_switch *, int, struct ifreq *);\n\tvoid (*port_txtstamp)(struct dsa_switch *, int, struct sk_buff *);\n\tbool (*port_rxtstamp)(struct dsa_switch *, int, struct sk_buff *, unsigned int);\n\tint (*devlink_param_get)(struct dsa_switch *, u32, struct devlink_param_gset_ctx *);\n\tint (*devlink_param_set)(struct dsa_switch *, u32, struct devlink_param_gset_ctx *);\n\tint (*devlink_info_get)(struct dsa_switch *, struct devlink_info_req *, struct netlink_ext_ack *);\n\tint (*devlink_sb_pool_get)(struct dsa_switch *, unsigned int, u16, struct devlink_sb_pool_info *);\n\tint (*devlink_sb_pool_set)(struct dsa_switch *, unsigned int, u16, u32, enum devlink_sb_threshold_type, struct netlink_ext_ack *);\n\tint (*devlink_sb_port_pool_get)(struct dsa_switch *, int, unsigned int, u16, u32 *);\n\tint (*devlink_sb_port_pool_set)(struct dsa_switch *, int, unsigned int, u16, u32, struct netlink_ext_ack *);\n\tint (*devlink_sb_tc_pool_bind_get)(struct dsa_switch *, int, unsigned int, u16, enum devlink_sb_pool_type, u16 *, u32 *);\n\tint (*devlink_sb_tc_pool_bind_set)(struct dsa_switch *, int, unsigned int, u16, enum devlink_sb_pool_type, u16, u32, struct netlink_ext_ack *);\n\tint (*devlink_sb_occ_snapshot)(struct dsa_switch *, unsigned int);\n\tint (*devlink_sb_occ_max_clear)(struct dsa_switch *, unsigned int);\n\tint (*devlink_sb_occ_port_pool_get)(struct dsa_switch *, int, unsigned int, u16, u32 *, u32 *);\n\tint (*devlink_sb_occ_tc_port_bind_get)(struct dsa_switch *, int, unsigned int, u16, enum devlink_sb_pool_type, u32 *, u32 *);\n\tint (*port_change_mtu)(struct dsa_switch *, int, int);\n\tint (*port_max_mtu)(struct dsa_switch *, int);\n\tint (*port_lag_change)(struct dsa_switch *, int);\n\tint (*port_lag_join)(struct dsa_switch *, int, struct net_device *, struct netdev_lag_upper_info *);\n\tint (*port_lag_leave)(struct dsa_switch *, int, struct net_device *);\n\tint (*port_hsr_join)(struct dsa_switch *, int, struct net_device *);\n\tint (*port_hsr_leave)(struct dsa_switch *, int, struct net_device *);\n\tint (*port_mrp_add)(struct dsa_switch *, int, const struct switchdev_obj_mrp *);\n\tint (*port_mrp_del)(struct dsa_switch *, int, const struct switchdev_obj_mrp *);\n\tint (*port_mrp_add_ring_role)(struct dsa_switch *, int, const struct switchdev_obj_ring_role_mrp *);\n\tint (*port_mrp_del_ring_role)(struct dsa_switch *, int, const struct switchdev_obj_ring_role_mrp *);\n};\n\nenum lwtunnel_encap_types {\n\tLWTUNNEL_ENCAP_NONE = 0,\n\tLWTUNNEL_ENCAP_MPLS = 1,\n\tLWTUNNEL_ENCAP_IP = 2,\n\tLWTUNNEL_ENCAP_ILA = 3,\n\tLWTUNNEL_ENCAP_IP6 = 4,\n\tLWTUNNEL_ENCAP_SEG6 = 5,\n\tLWTUNNEL_ENCAP_BPF = 6,\n\tLWTUNNEL_ENCAP_SEG6_LOCAL = 7,\n\tLWTUNNEL_ENCAP_RPL = 8,\n\t__LWTUNNEL_ENCAP_MAX = 9,\n};\n\nstruct nh_info {\n\tstruct hlist_node dev_hash;\n\tstruct nexthop *nh_parent;\n\tu8 family;\n\tbool reject_nh;\n\tbool fdb_nh;\n\tunion {\n\t\tstruct fib_nh_common fib_nhc;\n\t\tstruct fib_nh fib_nh;\n\t\tstruct fib6_nh fib6_nh;\n\t};\n};\n\nstruct nh_grp_entry;\n\nstruct nh_res_bucket {\n\tstruct nh_grp_entry *nh_entry;\n\tatomic_long_t used_time;\n\tlong unsigned int migrated_time;\n\tbool occupied;\n\tu8 nh_flags;\n};\n\nstruct nh_grp_entry {\n\tstruct nexthop *nh;\n\tu8 weight;\n\tunion {\n\t\tstruct {\n\t\t\tatomic_t upper_bound;\n\t\t} hthr;\n\t\tstruct {\n\t\t\tstruct list_head uw_nh_entry;\n\t\t\tu16 count_buckets;\n\t\t\tu16 wants_buckets;\n\t\t} res;\n\t};\n\tstruct list_head nh_list;\n\tstruct nexthop *nh_parent;\n};\n\nstruct nh_res_table {\n\tstruct net *net;\n\tu32 nhg_id;\n\tstruct delayed_work upkeep_dw;\n\tstruct list_head uw_nh_entries;\n\tlong unsigned int unbalanced_since;\n\tu32 idle_timer;\n\tu32 unbalanced_timer;\n\tu16 num_nh_buckets;\n\tstruct nh_res_bucket nh_buckets[0];\n};\n\nstruct nh_group {\n\tstruct nh_group *spare;\n\tu16 num_nh;\n\tbool is_multipath;\n\tbool hash_threshold;\n\tbool resilient;\n\tbool fdb_nh;\n\tbool has_v4;\n\tstruct nh_res_table *res_table;\n\tstruct nh_grp_entry nh_entries[0];\n};\n\nenum metadata_type {\n\tMETADATA_IP_TUNNEL = 0,\n\tMETADATA_HW_PORT_MUX = 1,\n};\n\nstruct hw_port_info {\n\tstruct net_device *lower_dev;\n\tu32 port_id;\n};\n\nstruct metadata_dst {\n\tstruct dst_entry dst;\n\tenum metadata_type type;\n\tunion {\n\t\tstruct ip_tunnel_info tun_info;\n\t\tstruct hw_port_info port_info;\n\t} u;\n};\n\nstruct gre_base_hdr {\n\t__be16 flags;\n\t__be16 protocol;\n};\n\nstruct gre_full_hdr {\n\tstruct gre_base_hdr fixed_header;\n\t__be16 csum;\n\t__be16 reserved1;\n\t__be32 key;\n\t__be32 seq;\n};\n\nstruct pptp_gre_header {\n\tstruct gre_base_hdr gre_hd;\n\t__be16 payload_len;\n\t__be16 call_id;\n\t__be32 seq;\n\t__be32 ack;\n};\n\nstruct tipc_basic_hdr {\n\t__be32 w[4];\n};\n\nstruct icmphdr {\n\t__u8 type;\n\t__u8 code;\n\t__sum16 checksum;\n\tunion {\n\t\tstruct {\n\t\t\t__be16 id;\n\t\t\t__be16 sequence;\n\t\t} echo;\n\t\t__be32 gateway;\n\t\tstruct {\n\t\t\t__be16 __unused;\n\t\t\t__be16 mtu;\n\t\t} frag;\n\t\t__u8 reserved[4];\n\t} un;\n};\n\nenum l2tp_debug_flags {\n\tL2TP_MSG_DEBUG = 1,\n\tL2TP_MSG_CONTROL = 2,\n\tL2TP_MSG_SEQ = 4,\n\tL2TP_MSG_DATA = 8,\n};\n\nstruct pppoe_tag {\n\t__be16 tag_type;\n\t__be16 tag_len;\n\tchar tag_data[0];\n};\n\nstruct pppoe_hdr {\n\t__u8 type: 4;\n\t__u8 ver: 4;\n\t__u8 code;\n\t__be16 sid;\n\t__be16 length;\n\tstruct pppoe_tag tag[0];\n};\n\nstruct mpls_label {\n\t__be32 entry;\n};\n\nstruct clock_identity {\n\tu8 id[8];\n};\n\nstruct port_identity {\n\tstruct clock_identity clock_identity;\n\t__be16 port_number;\n};\n\nstruct ptp_header {\n\tu8 tsmt;\n\tu8 ver;\n\t__be16 message_length;\n\tu8 domain_number;\n\tu8 reserved1;\n\tu8 flag_field[2];\n\t__be64 correction;\n\t__be32 reserved2;\n\tstruct port_identity source_port_identity;\n\t__be16 sequence_id;\n\tu8 control;\n\tu8 log_message_interval;\n} __attribute__((packed));\n\nenum batadv_packettype {\n\tBATADV_IV_OGM = 0,\n\tBATADV_BCAST = 1,\n\tBATADV_CODED = 2,\n\tBATADV_ELP = 3,\n\tBATADV_OGM2 = 4,\n\tBATADV_UNICAST = 64,\n\tBATADV_UNICAST_FRAG = 65,\n\tBATADV_UNICAST_4ADDR = 66,\n\tBATADV_ICMP = 67,\n\tBATADV_UNICAST_TVLV = 68,\n};\n\nstruct batadv_unicast_packet {\n\t__u8 packet_type;\n\t__u8 version;\n\t__u8 ttl;\n\t__u8 ttvn;\n\t__u8 dest[6];\n};\n\nstruct nf_conntrack_zone {\n\tu16 id;\n\tu8 flags;\n\tu8 dir;\n};\n\nstruct nf_conntrack_man {\n\tunion nf_inet_addr u3;\n\tunion nf_conntrack_man_proto u;\n\tu_int16_t l3num;\n};\n\nstruct nf_conntrack_tuple {\n\tstruct nf_conntrack_man src;\n\tstruct {\n\t\tunion nf_inet_addr u3;\n\t\tunion {\n\t\t\t__be16 all;\n\t\t\tstruct {\n\t\t\t\t__be16 port;\n\t\t\t} tcp;\n\t\t\tstruct {\n\t\t\t\t__be16 port;\n\t\t\t} udp;\n\t\t\tstruct {\n\t\t\t\tu_int8_t type;\n\t\t\t\tu_int8_t code;\n\t\t\t} icmp;\n\t\t\tstruct {\n\t\t\t\t__be16 port;\n\t\t\t} dccp;\n\t\t\tstruct {\n\t\t\t\t__be16 port;\n\t\t\t} sctp;\n\t\t\tstruct {\n\t\t\t\t__be16 key;\n\t\t\t} gre;\n\t\t} u;\n\t\tu_int8_t protonum;\n\t\tu_int8_t dir;\n\t} dst;\n};\n\nstruct nf_conntrack_tuple_hash {\n\tstruct hlist_nulls_node hnnode;\n\tstruct nf_conntrack_tuple tuple;\n};\n\nstruct nf_ct_udp {\n\tlong unsigned int stream_ts;\n};\n\nstruct nf_ct_gre {\n\tunsigned int stream_timeout;\n\tunsigned int timeout;\n};\n\nunion nf_conntrack_proto {\n\tstruct nf_ct_dccp dccp;\n\tstruct ip_ct_sctp sctp;\n\tstruct ip_ct_tcp tcp;\n\tstruct nf_ct_udp udp;\n\tstruct nf_ct_gre gre;\n\tunsigned int tmpl_padto;\n};\n\nstruct nf_ct_ext;\n\nstruct nf_conn {\n\tstruct nf_conntrack ct_general;\n\tspinlock_t lock;\n\tu32 timeout;\n\tstruct nf_conntrack_zone zone;\n\tstruct nf_conntrack_tuple_hash tuplehash[2];\n\tlong unsigned int status;\n\tu16 cpu;\n\tpossible_net_t ct_net;\n\tstruct hlist_node nat_bysource;\n\tstruct {\t} __nfct_init_offset;\n\tstruct nf_conn *master;\n\tu_int32_t mark;\n\tu_int32_t secmark;\n\tstruct nf_ct_ext *ext;\n\tunion nf_conntrack_proto proto;\n};\n\nstruct nf_conntrack_tuple_mask {\n\tstruct {\n\t\tunion nf_inet_addr u3;\n\t\tunion nf_conntrack_man_proto u;\n\t} src;\n};\n\nstruct nf_ct_ext {\n\tu8 offset[9];\n\tu8 len;\n\tchar data[0];\n};\n\nstruct nf_conntrack_helper;\n\nstruct nf_conntrack_expect {\n\tstruct hlist_node lnode;\n\tstruct hlist_node hnode;\n\tstruct nf_conntrack_tuple tuple;\n\tstruct nf_conntrack_tuple_mask mask;\n\tvoid (*expectfn)(struct nf_conn *, struct nf_conntrack_expect *);\n\tstruct nf_conntrack_helper *helper;\n\tstruct nf_conn *master;\n\tstruct timer_list timeout;\n\trefcount_t use;\n\tunsigned int flags;\n\tunsigned int class;\n\tunion nf_inet_addr saved_addr;\n\tunion nf_conntrack_man_proto saved_proto;\n\tenum ip_conntrack_dir dir;\n\tstruct callback_head rcu;\n};\n\nenum nf_ct_ext_id {\n\tNF_CT_EXT_HELPER = 0,\n\tNF_CT_EXT_NAT = 1,\n\tNF_CT_EXT_SEQADJ = 2,\n\tNF_CT_EXT_ACCT = 3,\n\tNF_CT_EXT_ECACHE = 4,\n\tNF_CT_EXT_TSTAMP = 5,\n\tNF_CT_EXT_TIMEOUT = 6,\n\tNF_CT_EXT_LABELS = 7,\n\tNF_CT_EXT_SYNPROXY = 8,\n\tNF_CT_EXT_NUM = 9,\n};\n\nstruct nf_ct_event {\n\tstruct nf_conn *ct;\n\tu32 portid;\n\tint report;\n};\n\nstruct nf_exp_event {\n\tstruct nf_conntrack_expect *exp;\n\tu32 portid;\n\tint report;\n};\n\nstruct nf_conn_labels {\n\tlong unsigned int bits[2];\n};\n\nstruct _flow_keys_digest_data {\n\t__be16 n_proto;\n\tu8 ip_proto;\n\tu8 padding;\n\t__be32 ports;\n\t__be32 src;\n\t__be32 dst;\n};\n\nstruct rps_sock_flow_table {\n\tu32 mask;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu32 ents[0];\n};\n\nstruct tc_skb_ext {\n\t__u32 chain;\n\t__u16 mru;\n\tbool post_ct;\n};\n\nstruct ipv4_devconf {\n\tvoid *sysctl;\n\tint data[32];\n\tlong unsigned int state[1];\n};\n\nenum nf_dev_hooks {\n\tNF_NETDEV_INGRESS = 0,\n\tNF_NETDEV_NUMHOOKS = 1,\n};\n\nenum {\n\tIF_OPER_UNKNOWN = 0,\n\tIF_OPER_NOTPRESENT = 1,\n\tIF_OPER_DOWN = 2,\n\tIF_OPER_LOWERLAYERDOWN = 3,\n\tIF_OPER_TESTING = 4,\n\tIF_OPER_DORMANT = 5,\n\tIF_OPER_UP = 6,\n};\n\nstruct ifbond {\n\t__s32 bond_mode;\n\t__s32 num_slaves;\n\t__s32 miimon;\n};\n\ntypedef struct ifbond ifbond;\n\nstruct ifslave {\n\t__s32 slave_id;\n\tchar slave_name[16];\n\t__s8 link;\n\t__s8 state;\n\t__u32 link_failure_count;\n};\n\ntypedef struct ifslave ifslave;\n\nenum netdev_state_t {\n\t__LINK_STATE_START = 0,\n\t__LINK_STATE_PRESENT = 1,\n\t__LINK_STATE_NOCARRIER = 2,\n\t__LINK_STATE_LINKWATCH_PENDING = 3,\n\t__LINK_STATE_DORMANT = 4,\n\t__LINK_STATE_TESTING = 5,\n};\n\nstruct netdev_boot_setup {\n\tchar name[16];\n\tstruct ifmap map;\n};\n\nenum {\n\tNAPIF_STATE_SCHED = 1,\n\tNAPIF_STATE_MISSED = 2,\n\tNAPIF_STATE_DISABLE = 4,\n\tNAPIF_STATE_NPSVC = 8,\n\tNAPIF_STATE_LISTED = 16,\n\tNAPIF_STATE_NO_BUSY_POLL = 32,\n\tNAPIF_STATE_IN_BUSY_POLL = 64,\n\tNAPIF_STATE_PREFER_BUSY_POLL = 128,\n\tNAPIF_STATE_THREADED = 256,\n\tNAPIF_STATE_SCHED_THREADED = 512,\n};\n\nenum gro_result {\n\tGRO_MERGED = 0,\n\tGRO_MERGED_FREE = 1,\n\tGRO_HELD = 2,\n\tGRO_NORMAL = 3,\n\tGRO_CONSUMED = 4,\n};\n\ntypedef enum gro_result gro_result_t;\n\nenum netdev_queue_state_t {\n\t__QUEUE_STATE_DRV_XOFF = 0,\n\t__QUEUE_STATE_STACK_XOFF = 1,\n\t__QUEUE_STATE_FROZEN = 2,\n};\n\nstruct net_device_path_stack {\n\tint num_paths;\n\tstruct net_device_path path[5];\n};\n\nstruct bpf_xdp_link {\n\tstruct bpf_link link;\n\tstruct net_device *dev;\n\tint flags;\n};\n\nstruct netdev_net_notifier {\n\tstruct list_head list;\n\tstruct notifier_block *nb;\n};\n\nstruct netpoll;\n\nstruct netpoll_info {\n\trefcount_t refcnt;\n\tstruct semaphore dev_lock;\n\tstruct sk_buff_head txq;\n\tstruct delayed_work tx_work;\n\tstruct netpoll *netpoll;\n\tstruct callback_head rcu;\n};\n\nstruct in_ifaddr;\n\nstruct ip_mc_list;\n\nstruct in_device {\n\tstruct net_device *dev;\n\trefcount_t refcnt;\n\tint dead;\n\tstruct in_ifaddr *ifa_list;\n\tstruct ip_mc_list *mc_list;\n\tstruct ip_mc_list **mc_hash;\n\tint mc_count;\n\tspinlock_t mc_tomb_lock;\n\tstruct ip_mc_list *mc_tomb;\n\tlong unsigned int mr_v1_seen;\n\tlong unsigned int mr_v2_seen;\n\tlong unsigned int mr_maxdelay;\n\tlong unsigned int mr_qi;\n\tlong unsigned int mr_qri;\n\tunsigned char mr_qrv;\n\tunsigned char mr_gq_running;\n\tu32 mr_ifc_count;\n\tstruct timer_list mr_gq_timer;\n\tstruct timer_list mr_ifc_timer;\n\tstruct neigh_parms *arp_parms;\n\tstruct ipv4_devconf cnf;\n\tstruct callback_head callback_head;\n};\n\nstruct offload_callbacks {\n\tstruct sk_buff * (*gso_segment)(struct sk_buff *, netdev_features_t);\n\tstruct sk_buff * (*gro_receive)(struct list_head *, struct sk_buff *);\n\tint (*gro_complete)(struct sk_buff *, int);\n};\n\nstruct packet_offload {\n\t__be16 type;\n\tu16 priority;\n\tstruct offload_callbacks callbacks;\n\tstruct list_head list;\n};\n\nstruct netdev_notifier_info_ext {\n\tstruct netdev_notifier_info info;\n\tunion {\n\t\tu32 mtu;\n\t} ext;\n};\n\nstruct netdev_notifier_change_info {\n\tstruct netdev_notifier_info info;\n\tunsigned int flags_changed;\n};\n\nstruct netdev_notifier_changelowerstate_info {\n\tstruct netdev_notifier_info info;\n\tvoid *lower_state_info;\n};\n\nstruct netdev_notifier_pre_changeaddr_info {\n\tstruct netdev_notifier_info info;\n\tconst unsigned char *dev_addr;\n};\n\ntypedef int (*bpf_op_t)(struct net_device *, struct netdev_bpf *);\n\nenum {\n\tNESTED_SYNC_IMM_BIT = 0,\n\tNESTED_SYNC_TODO_BIT = 1,\n};\n\nstruct netdev_nested_priv {\n\tunsigned char flags;\n\tvoid *data;\n};\n\nstruct netdev_bonding_info {\n\tifslave slave;\n\tifbond master;\n};\n\nstruct netdev_notifier_bonding_info {\n\tstruct netdev_notifier_info info;\n\tstruct netdev_bonding_info bonding_info;\n};\n\nunion inet_addr {\n\t__u32 all[4];\n\t__be32 ip;\n\t__be32 ip6[4];\n\tstruct in_addr in;\n\tstruct in6_addr in6;\n};\n\nstruct netpoll {\n\tstruct net_device *dev;\n\tchar dev_name[16];\n\tconst char *name;\n\tunion inet_addr local_ip;\n\tunion inet_addr remote_ip;\n\tbool ipv6;\n\tu16 local_port;\n\tu16 remote_port;\n\tu8 remote_mac[6];\n};\n\nenum qdisc_state_t {\n\t__QDISC_STATE_SCHED = 0,\n\t__QDISC_STATE_DEACTIVATED = 1,\n\t__QDISC_STATE_MISSED = 2,\n\t__QDISC_STATE_DRAINING = 3,\n};\n\nstruct tcf_walker {\n\tint stop;\n\tint skip;\n\tint count;\n\tbool nonempty;\n\tlong unsigned int cookie;\n\tint (*fn)(struct tcf_proto *, void *, struct tcf_walker *);\n};\n\nenum {\n\tIPV4_DEVCONF_FORWARDING = 1,\n\tIPV4_DEVCONF_MC_FORWARDING = 2,\n\tIPV4_DEVCONF_PROXY_ARP = 3,\n\tIPV4_DEVCONF_ACCEPT_REDIRECTS = 4,\n\tIPV4_DEVCONF_SECURE_REDIRECTS = 5,\n\tIPV4_DEVCONF_SEND_REDIRECTS = 6,\n\tIPV4_DEVCONF_SHARED_MEDIA = 7,\n\tIPV4_DEVCONF_RP_FILTER = 8,\n\tIPV4_DEVCONF_ACCEPT_SOURCE_ROUTE = 9,\n\tIPV4_DEVCONF_BOOTP_RELAY = 10,\n\tIPV4_DEVCONF_LOG_MARTIANS = 11,\n\tIPV4_DEVCONF_TAG = 12,\n\tIPV4_DEVCONF_ARPFILTER = 13,\n\tIPV4_DEVCONF_MEDIUM_ID = 14,\n\tIPV4_DEVCONF_NOXFRM = 15,\n\tIPV4_DEVCONF_NOPOLICY = 16,\n\tIPV4_DEVCONF_FORCE_IGMP_VERSION = 17,\n\tIPV4_DEVCONF_ARP_ANNOUNCE = 18,\n\tIPV4_DEVCONF_ARP_IGNORE = 19,\n\tIPV4_DEVCONF_PROMOTE_SECONDARIES = 20,\n\tIPV4_DEVCONF_ARP_ACCEPT = 21,\n\tIPV4_DEVCONF_ARP_NOTIFY = 22,\n\tIPV4_DEVCONF_ACCEPT_LOCAL = 23,\n\tIPV4_DEVCONF_SRC_VMARK = 24,\n\tIPV4_DEVCONF_PROXY_ARP_PVLAN = 25,\n\tIPV4_DEVCONF_ROUTE_LOCALNET = 26,\n\tIPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL = 27,\n\tIPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL = 28,\n\tIPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN = 29,\n\tIPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST = 30,\n\tIPV4_DEVCONF_DROP_GRATUITOUS_ARP = 31,\n\tIPV4_DEVCONF_BC_FORWARDING = 32,\n\t__IPV4_DEVCONF_MAX = 33,\n};\n\nstruct in_ifaddr {\n\tstruct hlist_node hash;\n\tstruct in_ifaddr *ifa_next;\n\tstruct in_device *ifa_dev;\n\tstruct callback_head callback_head;\n\t__be32 ifa_local;\n\t__be32 ifa_address;\n\t__be32 ifa_mask;\n\t__u32 ifa_rt_priority;\n\t__be32 ifa_broadcast;\n\tunsigned char ifa_scope;\n\tunsigned char ifa_prefixlen;\n\t__u32 ifa_flags;\n\tchar ifa_label[16];\n\t__u32 ifa_valid_lft;\n\t__u32 ifa_preferred_lft;\n\tlong unsigned int ifa_cstamp;\n\tlong unsigned int ifa_tstamp;\n};\n\nstruct udp_tunnel_info {\n\tshort unsigned int type;\n\tsa_family_t sa_family;\n\t__be16 port;\n\tu8 hw_priv;\n};\n\nstruct udp_tunnel_nic_shared {\n\tstruct udp_tunnel_nic *udp_tunnel_nic_info;\n\tstruct list_head devices;\n};\n\nstruct dev_kfree_skb_cb {\n\tenum skb_free_reason reason;\n};\n\nstruct netdev_adjacent {\n\tstruct net_device *dev;\n\tbool master;\n\tbool ignore;\n\tu16 ref_nr;\n\tvoid *private;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct netdev_hw_addr {\n\tstruct list_head list;\n\tunsigned char addr[32];\n\tunsigned char type;\n\tbool global_use;\n\tint sync_cnt;\n\tint refcount;\n\tint synced;\n\tstruct callback_head callback_head;\n};\n\nenum {\n\tNDA_UNSPEC = 0,\n\tNDA_DST = 1,\n\tNDA_LLADDR = 2,\n\tNDA_CACHEINFO = 3,\n\tNDA_PROBES = 4,\n\tNDA_VLAN = 5,\n\tNDA_PORT = 6,\n\tNDA_VNI = 7,\n\tNDA_IFINDEX = 8,\n\tNDA_MASTER = 9,\n\tNDA_LINK_NETNSID = 10,\n\tNDA_SRC_VNI = 11,\n\tNDA_PROTOCOL = 12,\n\tNDA_NH_ID = 13,\n\tNDA_FDB_EXT_ATTRS = 14,\n\t__NDA_MAX = 15,\n};\n\nstruct nda_cacheinfo {\n\t__u32 ndm_confirmed;\n\t__u32 ndm_used;\n\t__u32 ndm_updated;\n\t__u32 ndm_refcnt;\n};\n\nstruct ndt_stats {\n\t__u64 ndts_allocs;\n\t__u64 ndts_destroys;\n\t__u64 ndts_hash_grows;\n\t__u64 ndts_res_failed;\n\t__u64 ndts_lookups;\n\t__u64 ndts_hits;\n\t__u64 ndts_rcv_probes_mcast;\n\t__u64 ndts_rcv_probes_ucast;\n\t__u64 ndts_periodic_gc_runs;\n\t__u64 ndts_forced_gc_runs;\n\t__u64 ndts_table_fulls;\n};\n\nenum {\n\tNDTPA_UNSPEC = 0,\n\tNDTPA_IFINDEX = 1,\n\tNDTPA_REFCNT = 2,\n\tNDTPA_REACHABLE_TIME = 3,\n\tNDTPA_BASE_REACHABLE_TIME = 4,\n\tNDTPA_RETRANS_TIME = 5,\n\tNDTPA_GC_STALETIME = 6,\n\tNDTPA_DELAY_PROBE_TIME = 7,\n\tNDTPA_QUEUE_LEN = 8,\n\tNDTPA_APP_PROBES = 9,\n\tNDTPA_UCAST_PROBES = 10,\n\tNDTPA_MCAST_PROBES = 11,\n\tNDTPA_ANYCAST_DELAY = 12,\n\tNDTPA_PROXY_DELAY = 13,\n\tNDTPA_PROXY_QLEN = 14,\n\tNDTPA_LOCKTIME = 15,\n\tNDTPA_QUEUE_LENBYTES = 16,\n\tNDTPA_MCAST_REPROBES = 17,\n\tNDTPA_PAD = 18,\n\t__NDTPA_MAX = 19,\n};\n\nstruct ndtmsg {\n\t__u8 ndtm_family;\n\t__u8 ndtm_pad1;\n\t__u16 ndtm_pad2;\n};\n\nstruct ndt_config {\n\t__u16 ndtc_key_len;\n\t__u16 ndtc_entry_size;\n\t__u32 ndtc_entries;\n\t__u32 ndtc_last_flush;\n\t__u32 ndtc_last_rand;\n\t__u32 ndtc_hash_rnd;\n\t__u32 ndtc_hash_mask;\n\t__u32 ndtc_hash_chain_gc;\n\t__u32 ndtc_proxy_qlen;\n};\n\nenum {\n\tNDTA_UNSPEC = 0,\n\tNDTA_NAME = 1,\n\tNDTA_THRESH1 = 2,\n\tNDTA_THRESH2 = 3,\n\tNDTA_THRESH3 = 4,\n\tNDTA_CONFIG = 5,\n\tNDTA_PARMS = 6,\n\tNDTA_STATS = 7,\n\tNDTA_GC_INTERVAL = 8,\n\tNDTA_PAD = 9,\n\t__NDTA_MAX = 10,\n};\n\nenum {\n\tRTN_UNSPEC = 0,\n\tRTN_UNICAST = 1,\n\tRTN_LOCAL = 2,\n\tRTN_BROADCAST = 3,\n\tRTN_ANYCAST = 4,\n\tRTN_MULTICAST = 5,\n\tRTN_BLACKHOLE = 6,\n\tRTN_UNREACHABLE = 7,\n\tRTN_PROHIBIT = 8,\n\tRTN_THROW = 9,\n\tRTN_NAT = 10,\n\tRTN_XRESOLVE = 11,\n\t__RTN_MAX = 12,\n};\n\nenum {\n\tNEIGH_ARP_TABLE = 0,\n\tNEIGH_ND_TABLE = 1,\n\tNEIGH_DN_TABLE = 2,\n\tNEIGH_NR_TABLES = 3,\n\tNEIGH_LINK_TABLE = 3,\n};\n\nstruct neigh_seq_state {\n\tstruct seq_net_private p;\n\tstruct neigh_table *tbl;\n\tstruct neigh_hash_table *nht;\n\tvoid * (*neigh_sub_iter)(struct neigh_seq_state *, struct neighbour *, loff_t *);\n\tunsigned int bucket;\n\tunsigned int flags;\n};\n\nstruct neighbour_cb {\n\tlong unsigned int sched_next;\n\tunsigned int flags;\n};\n\nenum netevent_notif_type {\n\tNETEVENT_NEIGH_UPDATE = 1,\n\tNETEVENT_REDIRECT = 2,\n\tNETEVENT_DELAY_PROBE_TIME_UPDATE = 3,\n\tNETEVENT_IPV4_MPATH_HASH_UPDATE = 4,\n\tNETEVENT_IPV6_MPATH_HASH_UPDATE = 5,\n\tNETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE = 6,\n};\n\nstruct neigh_dump_filter {\n\tint master_idx;\n\tint dev_idx;\n};\n\nstruct neigh_sysctl_table {\n\tstruct ctl_table_header *sysctl_header;\n\tstruct ctl_table neigh_vars[21];\n};\n\nstruct netlink_dump_control {\n\tint (*start)(struct netlink_callback *);\n\tint (*dump)(struct sk_buff *, struct netlink_callback *);\n\tint (*done)(struct netlink_callback *);\n\tvoid *data;\n\tstruct module *module;\n\tu32 min_dump_alloc;\n};\n\nstruct rtnl_link_stats {\n\t__u32 rx_packets;\n\t__u32 tx_packets;\n\t__u32 rx_bytes;\n\t__u32 tx_bytes;\n\t__u32 rx_errors;\n\t__u32 tx_errors;\n\t__u32 rx_dropped;\n\t__u32 tx_dropped;\n\t__u32 multicast;\n\t__u32 collisions;\n\t__u32 rx_length_errors;\n\t__u32 rx_over_errors;\n\t__u32 rx_crc_errors;\n\t__u32 rx_frame_errors;\n\t__u32 rx_fifo_errors;\n\t__u32 rx_missed_errors;\n\t__u32 tx_aborted_errors;\n\t__u32 tx_carrier_errors;\n\t__u32 tx_fifo_errors;\n\t__u32 tx_heartbeat_errors;\n\t__u32 tx_window_errors;\n\t__u32 rx_compressed;\n\t__u32 tx_compressed;\n\t__u32 rx_nohandler;\n};\n\nstruct rtnl_link_ifmap {\n\t__u64 mem_start;\n\t__u64 mem_end;\n\t__u64 base_addr;\n\t__u16 irq;\n\t__u8 dma;\n\t__u8 port;\n};\n\nenum {\n\tIFLA_PROTO_DOWN_REASON_UNSPEC = 0,\n\tIFLA_PROTO_DOWN_REASON_MASK = 1,\n\tIFLA_PROTO_DOWN_REASON_VALUE = 2,\n\t__IFLA_PROTO_DOWN_REASON_CNT = 3,\n\tIFLA_PROTO_DOWN_REASON_MAX = 2,\n};\n\nenum {\n\tIFLA_BRPORT_UNSPEC = 0,\n\tIFLA_BRPORT_STATE = 1,\n\tIFLA_BRPORT_PRIORITY = 2,\n\tIFLA_BRPORT_COST = 3,\n\tIFLA_BRPORT_MODE = 4,\n\tIFLA_BRPORT_GUARD = 5,\n\tIFLA_BRPORT_PROTECT = 6,\n\tIFLA_BRPORT_FAST_LEAVE = 7,\n\tIFLA_BRPORT_LEARNING = 8,\n\tIFLA_BRPORT_UNICAST_FLOOD = 9,\n\tIFLA_BRPORT_PROXYARP = 10,\n\tIFLA_BRPORT_LEARNING_SYNC = 11,\n\tIFLA_BRPORT_PROXYARP_WIFI = 12,\n\tIFLA_BRPORT_ROOT_ID = 13,\n\tIFLA_BRPORT_BRIDGE_ID = 14,\n\tIFLA_BRPORT_DESIGNATED_PORT = 15,\n\tIFLA_BRPORT_DESIGNATED_COST = 16,\n\tIFLA_BRPORT_ID = 17,\n\tIFLA_BRPORT_NO = 18,\n\tIFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19,\n\tIFLA_BRPORT_CONFIG_PENDING = 20,\n\tIFLA_BRPORT_MESSAGE_AGE_TIMER = 21,\n\tIFLA_BRPORT_FORWARD_DELAY_TIMER = 22,\n\tIFLA_BRPORT_HOLD_TIMER = 23,\n\tIFLA_BRPORT_FLUSH = 24,\n\tIFLA_BRPORT_MULTICAST_ROUTER = 25,\n\tIFLA_BRPORT_PAD = 26,\n\tIFLA_BRPORT_MCAST_FLOOD = 27,\n\tIFLA_BRPORT_MCAST_TO_UCAST = 28,\n\tIFLA_BRPORT_VLAN_TUNNEL = 29,\n\tIFLA_BRPORT_BCAST_FLOOD = 30,\n\tIFLA_BRPORT_GROUP_FWD_MASK = 31,\n\tIFLA_BRPORT_NEIGH_SUPPRESS = 32,\n\tIFLA_BRPORT_ISOLATED = 33,\n\tIFLA_BRPORT_BACKUP_PORT = 34,\n\tIFLA_BRPORT_MRP_RING_OPEN = 35,\n\tIFLA_BRPORT_MRP_IN_OPEN = 36,\n\tIFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT = 37,\n\tIFLA_BRPORT_MCAST_EHT_HOSTS_CNT = 38,\n\t__IFLA_BRPORT_MAX = 39,\n};\n\nenum {\n\tIFLA_VF_INFO_UNSPEC = 0,\n\tIFLA_VF_INFO = 1,\n\t__IFLA_VF_INFO_MAX = 2,\n};\n\nenum {\n\tIFLA_VF_UNSPEC = 0,\n\tIFLA_VF_MAC = 1,\n\tIFLA_VF_VLAN = 2,\n\tIFLA_VF_TX_RATE = 3,\n\tIFLA_VF_SPOOFCHK = 4,\n\tIFLA_VF_LINK_STATE = 5,\n\tIFLA_VF_RATE = 6,\n\tIFLA_VF_RSS_QUERY_EN = 7,\n\tIFLA_VF_STATS = 8,\n\tIFLA_VF_TRUST = 9,\n\tIFLA_VF_IB_NODE_GUID = 10,\n\tIFLA_VF_IB_PORT_GUID = 11,\n\tIFLA_VF_VLAN_LIST = 12,\n\tIFLA_VF_BROADCAST = 13,\n\t__IFLA_VF_MAX = 14,\n};\n\nstruct ifla_vf_mac {\n\t__u32 vf;\n\t__u8 mac[32];\n};\n\nstruct ifla_vf_broadcast {\n\t__u8 broadcast[32];\n};\n\nstruct ifla_vf_vlan {\n\t__u32 vf;\n\t__u32 vlan;\n\t__u32 qos;\n};\n\nenum {\n\tIFLA_VF_VLAN_INFO_UNSPEC = 0,\n\tIFLA_VF_VLAN_INFO = 1,\n\t__IFLA_VF_VLAN_INFO_MAX = 2,\n};\n\nstruct ifla_vf_vlan_info {\n\t__u32 vf;\n\t__u32 vlan;\n\t__u32 qos;\n\t__be16 vlan_proto;\n};\n\nstruct ifla_vf_tx_rate {\n\t__u32 vf;\n\t__u32 rate;\n};\n\nstruct ifla_vf_rate {\n\t__u32 vf;\n\t__u32 min_tx_rate;\n\t__u32 max_tx_rate;\n};\n\nstruct ifla_vf_spoofchk {\n\t__u32 vf;\n\t__u32 setting;\n};\n\nstruct ifla_vf_link_state {\n\t__u32 vf;\n\t__u32 link_state;\n};\n\nstruct ifla_vf_rss_query_en {\n\t__u32 vf;\n\t__u32 setting;\n};\n\nenum {\n\tIFLA_VF_STATS_RX_PACKETS = 0,\n\tIFLA_VF_STATS_TX_PACKETS = 1,\n\tIFLA_VF_STATS_RX_BYTES = 2,\n\tIFLA_VF_STATS_TX_BYTES = 3,\n\tIFLA_VF_STATS_BROADCAST = 4,\n\tIFLA_VF_STATS_MULTICAST = 5,\n\tIFLA_VF_STATS_PAD = 6,\n\tIFLA_VF_STATS_RX_DROPPED = 7,\n\tIFLA_VF_STATS_TX_DROPPED = 8,\n\t__IFLA_VF_STATS_MAX = 9,\n};\n\nstruct ifla_vf_trust {\n\t__u32 vf;\n\t__u32 setting;\n};\n\nenum {\n\tIFLA_VF_PORT_UNSPEC = 0,\n\tIFLA_VF_PORT = 1,\n\t__IFLA_VF_PORT_MAX = 2,\n};\n\nenum {\n\tIFLA_PORT_UNSPEC = 0,\n\tIFLA_PORT_VF = 1,\n\tIFLA_PORT_PROFILE = 2,\n\tIFLA_PORT_VSI_TYPE = 3,\n\tIFLA_PORT_INSTANCE_UUID = 4,\n\tIFLA_PORT_HOST_UUID = 5,\n\tIFLA_PORT_REQUEST = 6,\n\tIFLA_PORT_RESPONSE = 7,\n\t__IFLA_PORT_MAX = 8,\n};\n\nstruct if_stats_msg {\n\t__u8 family;\n\t__u8 pad1;\n\t__u16 pad2;\n\t__u32 ifindex;\n\t__u32 filter_mask;\n};\n\nenum {\n\tIFLA_STATS_UNSPEC = 0,\n\tIFLA_STATS_LINK_64 = 1,\n\tIFLA_STATS_LINK_XSTATS = 2,\n\tIFLA_STATS_LINK_XSTATS_SLAVE = 3,\n\tIFLA_STATS_LINK_OFFLOAD_XSTATS = 4,\n\tIFLA_STATS_AF_SPEC = 5,\n\t__IFLA_STATS_MAX = 6,\n};\n\nenum {\n\tIFLA_OFFLOAD_XSTATS_UNSPEC = 0,\n\tIFLA_OFFLOAD_XSTATS_CPU_HIT = 1,\n\t__IFLA_OFFLOAD_XSTATS_MAX = 2,\n};\n\nenum {\n\tXDP_ATTACHED_NONE = 0,\n\tXDP_ATTACHED_DRV = 1,\n\tXDP_ATTACHED_SKB = 2,\n\tXDP_ATTACHED_HW = 3,\n\tXDP_ATTACHED_MULTI = 4,\n};\n\nenum {\n\tIFLA_XDP_UNSPEC = 0,\n\tIFLA_XDP_FD = 1,\n\tIFLA_XDP_ATTACHED = 2,\n\tIFLA_XDP_FLAGS = 3,\n\tIFLA_XDP_PROG_ID = 4,\n\tIFLA_XDP_DRV_PROG_ID = 5,\n\tIFLA_XDP_SKB_PROG_ID = 6,\n\tIFLA_XDP_HW_PROG_ID = 7,\n\tIFLA_XDP_EXPECTED_FD = 8,\n\t__IFLA_XDP_MAX = 9,\n};\n\nenum {\n\tIFLA_EVENT_NONE = 0,\n\tIFLA_EVENT_REBOOT = 1,\n\tIFLA_EVENT_FEATURES = 2,\n\tIFLA_EVENT_BONDING_FAILOVER = 3,\n\tIFLA_EVENT_NOTIFY_PEERS = 4,\n\tIFLA_EVENT_IGMP_RESEND = 5,\n\tIFLA_EVENT_BONDING_OPTIONS = 6,\n};\n\nenum {\n\tIFLA_BRIDGE_FLAGS = 0,\n\tIFLA_BRIDGE_MODE = 1,\n\tIFLA_BRIDGE_VLAN_INFO = 2,\n\tIFLA_BRIDGE_VLAN_TUNNEL_INFO = 3,\n\tIFLA_BRIDGE_MRP = 4,\n\tIFLA_BRIDGE_CFM = 5,\n\t__IFLA_BRIDGE_MAX = 6,\n};\n\nenum {\n\tBR_MCAST_DIR_RX = 0,\n\tBR_MCAST_DIR_TX = 1,\n\tBR_MCAST_DIR_SIZE = 2,\n};\n\nenum rtattr_type_t {\n\tRTA_UNSPEC = 0,\n\tRTA_DST = 1,\n\tRTA_SRC = 2,\n\tRTA_IIF = 3,\n\tRTA_OIF = 4,\n\tRTA_GATEWAY = 5,\n\tRTA_PRIORITY = 6,\n\tRTA_PREFSRC = 7,\n\tRTA_METRICS = 8,\n\tRTA_MULTIPATH = 9,\n\tRTA_PROTOINFO = 10,\n\tRTA_FLOW = 11,\n\tRTA_CACHEINFO = 12,\n\tRTA_SESSION = 13,\n\tRTA_MP_ALGO = 14,\n\tRTA_TABLE = 15,\n\tRTA_MARK = 16,\n\tRTA_MFC_STATS = 17,\n\tRTA_VIA = 18,\n\tRTA_NEWDST = 19,\n\tRTA_PREF = 20,\n\tRTA_ENCAP_TYPE = 21,\n\tRTA_ENCAP = 22,\n\tRTA_EXPIRES = 23,\n\tRTA_PAD = 24,\n\tRTA_UID = 25,\n\tRTA_TTL_PROPAGATE = 26,\n\tRTA_IP_PROTO = 27,\n\tRTA_SPORT = 28,\n\tRTA_DPORT = 29,\n\tRTA_NH_ID = 30,\n\t__RTA_MAX = 31,\n};\n\nstruct rta_cacheinfo {\n\t__u32 rta_clntref;\n\t__u32 rta_lastuse;\n\t__s32 rta_expires;\n\t__u32 rta_error;\n\t__u32 rta_used;\n\t__u32 rta_id;\n\t__u32 rta_ts;\n\t__u32 rta_tsage;\n};\n\nstruct rtnl_af_ops {\n\tstruct list_head list;\n\tint family;\n\tint (*fill_link_af)(struct sk_buff *, const struct net_device *, u32);\n\tsize_t (*get_link_af_size)(const struct net_device *, u32);\n\tint (*validate_link_af)(const struct net_device *, const struct nlattr *);\n\tint (*set_link_af)(struct net_device *, const struct nlattr *, struct netlink_ext_ack *);\n\tint (*fill_stats_af)(struct sk_buff *, const struct net_device *);\n\tsize_t (*get_stats_af_size)(const struct net_device *);\n};\n\nstruct rtnl_link {\n\trtnl_doit_func doit;\n\trtnl_dumpit_func dumpit;\n\tstruct module *owner;\n\tunsigned int flags;\n\tstruct callback_head rcu;\n};\n\nenum {\n\tIF_LINK_MODE_DEFAULT = 0,\n\tIF_LINK_MODE_DORMANT = 1,\n\tIF_LINK_MODE_TESTING = 2,\n};\n\nenum lw_bits {\n\tLW_URGENT = 0,\n};\n\nstruct seg6_pernet_data {\n\tstruct mutex lock;\n\tstruct in6_addr *tun_src;\n\tstruct rhashtable hmac_infos;\n};\n\nenum {\n\tBPF_F_RECOMPUTE_CSUM = 1,\n\tBPF_F_INVALIDATE_HASH = 2,\n};\n\nenum {\n\tBPF_F_HDR_FIELD_MASK = 15,\n};\n\nenum {\n\tBPF_F_PSEUDO_HDR = 16,\n\tBPF_F_MARK_MANGLED_0 = 32,\n\tBPF_F_MARK_ENFORCE = 64,\n};\n\nenum {\n\tBPF_F_INGRESS = 1,\n};\n\nenum {\n\tBPF_F_TUNINFO_IPV6 = 1,\n};\n\nenum {\n\tBPF_F_ZERO_CSUM_TX = 2,\n\tBPF_F_DONT_FRAGMENT = 4,\n\tBPF_F_SEQ_NUMBER = 8,\n};\n\nenum {\n\tBPF_CSUM_LEVEL_QUERY = 0,\n\tBPF_CSUM_LEVEL_INC = 1,\n\tBPF_CSUM_LEVEL_DEC = 2,\n\tBPF_CSUM_LEVEL_RESET = 3,\n};\n\nenum {\n\tBPF_F_ADJ_ROOM_FIXED_GSO = 1,\n\tBPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = 2,\n\tBPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = 4,\n\tBPF_F_ADJ_ROOM_ENCAP_L4_GRE = 8,\n\tBPF_F_ADJ_ROOM_ENCAP_L4_UDP = 16,\n\tBPF_F_ADJ_ROOM_NO_CSUM_RESET = 32,\n\tBPF_F_ADJ_ROOM_ENCAP_L2_ETH = 64,\n};\n\nenum {\n\tBPF_ADJ_ROOM_ENCAP_L2_MASK = 255,\n\tBPF_ADJ_ROOM_ENCAP_L2_SHIFT = 56,\n};\n\nenum {\n\tBPF_SK_LOOKUP_F_REPLACE = 1,\n\tBPF_SK_LOOKUP_F_NO_REUSEPORT = 2,\n};\n\nenum bpf_adj_room_mode {\n\tBPF_ADJ_ROOM_NET = 0,\n\tBPF_ADJ_ROOM_MAC = 1,\n};\n\nenum bpf_hdr_start_off {\n\tBPF_HDR_START_MAC = 0,\n\tBPF_HDR_START_NET = 1,\n};\n\nenum bpf_lwt_encap_mode {\n\tBPF_LWT_ENCAP_SEG6 = 0,\n\tBPF_LWT_ENCAP_SEG6_INLINE = 1,\n\tBPF_LWT_ENCAP_IP = 2,\n};\n\nstruct bpf_tunnel_key {\n\t__u32 tunnel_id;\n\tunion {\n\t\t__u32 remote_ipv4;\n\t\t__u32 remote_ipv6[4];\n\t};\n\t__u8 tunnel_tos;\n\t__u8 tunnel_ttl;\n\t__u16 tunnel_ext;\n\t__u32 tunnel_label;\n};\n\nstruct bpf_xfrm_state {\n\t__u32 reqid;\n\t__u32 spi;\n\t__u16 family;\n\t__u16 ext;\n\tunion {\n\t\t__u32 remote_ipv4;\n\t\t__u32 remote_ipv6[4];\n\t};\n};\n\nstruct bpf_tcp_sock {\n\t__u32 snd_cwnd;\n\t__u32 srtt_us;\n\t__u32 rtt_min;\n\t__u32 snd_ssthresh;\n\t__u32 rcv_nxt;\n\t__u32 snd_nxt;\n\t__u32 snd_una;\n\t__u32 mss_cache;\n\t__u32 ecn_flags;\n\t__u32 rate_delivered;\n\t__u32 rate_interval_us;\n\t__u32 packets_out;\n\t__u32 retrans_out;\n\t__u32 total_retrans;\n\t__u32 segs_in;\n\t__u32 data_segs_in;\n\t__u32 segs_out;\n\t__u32 data_segs_out;\n\t__u32 lost_out;\n\t__u32 sacked_out;\n\t__u64 bytes_received;\n\t__u64 bytes_acked;\n\t__u32 dsack_dups;\n\t__u32 delivered;\n\t__u32 delivered_ce;\n\t__u32 icsk_retransmits;\n};\n\nstruct bpf_sock_tuple {\n\tunion {\n\t\tstruct {\n\t\t\t__be32 saddr;\n\t\t\t__be32 daddr;\n\t\t\t__be16 sport;\n\t\t\t__be16 dport;\n\t\t} ipv4;\n\t\tstruct {\n\t\t\t__be32 saddr[4];\n\t\t\t__be32 daddr[4];\n\t\t\t__be16 sport;\n\t\t\t__be16 dport;\n\t\t} ipv6;\n\t};\n};\n\nstruct bpf_xdp_sock {\n\t__u32 queue_id;\n};\n\nenum {\n\tBPF_SOCK_OPS_RTO_CB_FLAG = 1,\n\tBPF_SOCK_OPS_RETRANS_CB_FLAG = 2,\n\tBPF_SOCK_OPS_STATE_CB_FLAG = 4,\n\tBPF_SOCK_OPS_RTT_CB_FLAG = 8,\n\tBPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = 16,\n\tBPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = 32,\n\tBPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = 64,\n\tBPF_SOCK_OPS_ALL_CB_FLAGS = 127,\n};\n\nenum {\n\tBPF_SOCK_OPS_VOID = 0,\n\tBPF_SOCK_OPS_TIMEOUT_INIT = 1,\n\tBPF_SOCK_OPS_RWND_INIT = 2,\n\tBPF_SOCK_OPS_TCP_CONNECT_CB = 3,\n\tBPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB = 4,\n\tBPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB = 5,\n\tBPF_SOCK_OPS_NEEDS_ECN = 6,\n\tBPF_SOCK_OPS_BASE_RTT = 7,\n\tBPF_SOCK_OPS_RTO_CB = 8,\n\tBPF_SOCK_OPS_RETRANS_CB = 9,\n\tBPF_SOCK_OPS_STATE_CB = 10,\n\tBPF_SOCK_OPS_TCP_LISTEN_CB = 11,\n\tBPF_SOCK_OPS_RTT_CB = 12,\n\tBPF_SOCK_OPS_PARSE_HDR_OPT_CB = 13,\n\tBPF_SOCK_OPS_HDR_OPT_LEN_CB = 14,\n\tBPF_SOCK_OPS_WRITE_HDR_OPT_CB = 15,\n};\n\nenum {\n\tTCP_BPF_IW = 1001,\n\tTCP_BPF_SNDCWND_CLAMP = 1002,\n\tTCP_BPF_DELACK_MAX = 1003,\n\tTCP_BPF_RTO_MIN = 1004,\n\tTCP_BPF_SYN = 1005,\n\tTCP_BPF_SYN_IP = 1006,\n\tTCP_BPF_SYN_MAC = 1007,\n};\n\nenum {\n\tBPF_LOAD_HDR_OPT_TCP_SYN = 1,\n};\n\nenum {\n\tBPF_FIB_LOOKUP_DIRECT = 1,\n\tBPF_FIB_LOOKUP_OUTPUT = 2,\n};\n\nenum {\n\tBPF_FIB_LKUP_RET_SUCCESS = 0,\n\tBPF_FIB_LKUP_RET_BLACKHOLE = 1,\n\tBPF_FIB_LKUP_RET_UNREACHABLE = 2,\n\tBPF_FIB_LKUP_RET_PROHIBIT = 3,\n\tBPF_FIB_LKUP_RET_NOT_FWDED = 4,\n\tBPF_FIB_LKUP_RET_FWD_DISABLED = 5,\n\tBPF_FIB_LKUP_RET_UNSUPP_LWT = 6,\n\tBPF_FIB_LKUP_RET_NO_NEIGH = 7,\n\tBPF_FIB_LKUP_RET_FRAG_NEEDED = 8,\n};\n\nstruct bpf_fib_lookup {\n\t__u8 family;\n\t__u8 l4_protocol;\n\t__be16 sport;\n\t__be16 dport;\n\tunion {\n\t\t__u16 tot_len;\n\t\t__u16 mtu_result;\n\t};\n\t__u32 ifindex;\n\tunion {\n\t\t__u8 tos;\n\t\t__be32 flowinfo;\n\t\t__u32 rt_metric;\n\t};\n\tunion {\n\t\t__be32 ipv4_src;\n\t\t__u32 ipv6_src[4];\n\t};\n\tunion {\n\t\t__be32 ipv4_dst;\n\t\t__u32 ipv6_dst[4];\n\t};\n\t__be16 h_vlan_proto;\n\t__be16 h_vlan_TCI;\n\t__u8 smac[6];\n\t__u8 dmac[6];\n};\n\nstruct bpf_redir_neigh {\n\t__u32 nh_family;\n\tunion {\n\t\t__be32 ipv4_nh;\n\t\t__u32 ipv6_nh[4];\n\t};\n};\n\nenum bpf_check_mtu_flags {\n\tBPF_MTU_CHK_SEGS = 1,\n};\n\nenum bpf_check_mtu_ret {\n\tBPF_MTU_CHK_RET_SUCCESS = 0,\n\tBPF_MTU_CHK_RET_FRAG_NEEDED = 1,\n\tBPF_MTU_CHK_RET_SEGS_TOOBIG = 2,\n};\n\nenum rt_scope_t {\n\tRT_SCOPE_UNIVERSE = 0,\n\tRT_SCOPE_SITE = 200,\n\tRT_SCOPE_LINK = 253,\n\tRT_SCOPE_HOST = 254,\n\tRT_SCOPE_NOWHERE = 255,\n};\n\nenum rt_class_t {\n\tRT_TABLE_UNSPEC = 0,\n\tRT_TABLE_COMPAT = 252,\n\tRT_TABLE_DEFAULT = 253,\n\tRT_TABLE_MAIN = 254,\n\tRT_TABLE_LOCAL = 255,\n\tRT_TABLE_MAX = 4294967295,\n};\n\nstruct nl_info {\n\tstruct nlmsghdr *nlh;\n\tstruct net *nl_net;\n\tu32 portid;\n\tu8 skip_notify: 1;\n\tu8 skip_notify_kernel: 1;\n};\n\nstruct inet_timewait_sock {\n\tstruct sock_common __tw_common;\n\t__u32 tw_mark;\n\tvolatile unsigned char tw_substate;\n\tunsigned char tw_rcv_wscale;\n\t__be16 tw_sport;\n\tunsigned int tw_kill: 1;\n\tunsigned int tw_transparent: 1;\n\tunsigned int tw_flowlabel: 20;\n\tunsigned int tw_pad: 2;\n\tunsigned int tw_tos: 8;\n\tu32 tw_txhash;\n\tu32 tw_priority;\n\tstruct timer_list tw_timer;\n\tstruct inet_bind_bucket *tw_tb;\n};\n\nstruct tcp_timewait_sock {\n\tstruct inet_timewait_sock tw_sk;\n\tu32 tw_rcv_wnd;\n\tu32 tw_ts_offset;\n\tu32 tw_ts_recent;\n\tu32 tw_last_oow_ack_time;\n\tint tw_ts_recent_stamp;\n\tu32 tw_tx_delay;\n\tstruct tcp_md5sig_key *tw_md5_key;\n};\n\nstruct udp_sock {\n\tstruct inet_sock inet;\n\tint pending;\n\tunsigned int corkflag;\n\t__u8 encap_type;\n\tunsigned char no_check6_tx: 1;\n\tunsigned char no_check6_rx: 1;\n\tunsigned char encap_enabled: 1;\n\tunsigned char gro_enabled: 1;\n\tunsigned char accept_udp_l4: 1;\n\tunsigned char accept_udp_fraglist: 1;\n\t__u16 len;\n\t__u16 gso_size;\n\t__u16 pcslen;\n\t__u16 pcrlen;\n\t__u8 pcflag;\n\t__u8 unused[3];\n\tint (*encap_rcv)(struct sock *, struct sk_buff *);\n\tint (*encap_err_lookup)(struct sock *, struct sk_buff *);\n\tvoid (*encap_destroy)(struct sock *);\n\tstruct sk_buff * (*gro_receive)(struct sock *, struct list_head *, struct sk_buff *);\n\tint (*gro_complete)(struct sock *, struct sk_buff *, int);\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct sk_buff_head reader_queue;\n\tint forward_deficit;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct udp6_sock {\n\tstruct udp_sock udp;\n\tstruct ipv6_pinfo inet6;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct tcp6_sock {\n\tstruct tcp_sock tcp;\n\tstruct ipv6_pinfo inet6;\n};\n\nstruct fib6_result;\n\nstruct fib6_config;\n\nstruct ipv6_stub {\n\tint (*ipv6_sock_mc_join)(struct sock *, int, const struct in6_addr *);\n\tint (*ipv6_sock_mc_drop)(struct sock *, int, const struct in6_addr *);\n\tstruct dst_entry * (*ipv6_dst_lookup_flow)(struct net *, const struct sock *, struct flowi6 *, const struct in6_addr *);\n\tint (*ipv6_route_input)(struct sk_buff *);\n\tstruct fib6_table * (*fib6_get_table)(struct net *, u32);\n\tint (*fib6_lookup)(struct net *, int, struct flowi6 *, struct fib6_result *, int);\n\tint (*fib6_table_lookup)(struct net *, struct fib6_table *, int, struct flowi6 *, struct fib6_result *, int);\n\tvoid (*fib6_select_path)(const struct net *, struct fib6_result *, struct flowi6 *, int, bool, const struct sk_buff *, int);\n\tu32 (*ip6_mtu_from_fib6)(const struct fib6_result *, const struct in6_addr *, const struct in6_addr *);\n\tint (*fib6_nh_init)(struct net *, struct fib6_nh *, struct fib6_config *, gfp_t, struct netlink_ext_ack *);\n\tvoid (*fib6_nh_release)(struct fib6_nh *);\n\tvoid (*fib6_update_sernum)(struct net *, struct fib6_info *);\n\tint (*ip6_del_rt)(struct net *, struct fib6_info *, bool);\n\tvoid (*fib6_rt_update)(struct net *, struct fib6_info *, struct nl_info *);\n\tvoid (*udpv6_encap_enable)();\n\tvoid (*ndisc_send_na)(struct net_device *, const struct in6_addr *, const struct in6_addr *, bool, bool, bool, bool);\n\tvoid (*xfrm6_local_rxpmtu)(struct sk_buff *, u32);\n\tint (*xfrm6_udp_encap_rcv)(struct sock *, struct sk_buff *);\n\tint (*xfrm6_rcv_encap)(struct sk_buff *, int, __be32, int);\n\tstruct neigh_table *nd_tbl;\n\tint (*ipv6_fragment)(struct net *, struct sock *, struct sk_buff *, int (*)(struct net *, struct sock *, struct sk_buff *));\n\tstruct net_device * (*ipv6_dev_find)(struct net *, const struct in6_addr *, struct net_device *);\n};\n\nstruct fib6_result {\n\tstruct fib6_nh *nh;\n\tstruct fib6_info *f6i;\n\tu32 fib6_flags;\n\tu8 fib6_type;\n\tstruct rt6_info *rt6;\n};\n\nstruct fib6_config {\n\tu32 fc_table;\n\tu32 fc_metric;\n\tint fc_dst_len;\n\tint fc_src_len;\n\tint fc_ifindex;\n\tu32 fc_flags;\n\tu32 fc_protocol;\n\tu16 fc_type;\n\tu16 fc_delete_all_nh: 1;\n\tu16 fc_ignore_dev_down: 1;\n\tu16 __unused: 14;\n\tu32 fc_nh_id;\n\tstruct in6_addr fc_dst;\n\tstruct in6_addr fc_src;\n\tstruct in6_addr fc_prefsrc;\n\tstruct in6_addr fc_gateway;\n\tlong unsigned int fc_expires;\n\tstruct nlattr *fc_mx;\n\tint fc_mx_len;\n\tint fc_mp_len;\n\tstruct nlattr *fc_mp;\n\tstruct nl_info fc_nlinfo;\n\tstruct nlattr *fc_encap;\n\tu16 fc_encap_type;\n\tbool fc_is_fdb;\n};\n\nstruct ipv6_bpf_stub {\n\tint (*inet6_bind)(struct sock *, struct sockaddr *, int, u32);\n\tstruct sock * (*udp6_lib_lookup)(struct net *, const struct in6_addr *, __be16, const struct in6_addr *, __be16, int, int, struct udp_table *, struct sk_buff *);\n};\n\nstruct fib_result {\n\t__be32 prefix;\n\tunsigned char prefixlen;\n\tunsigned char nh_sel;\n\tunsigned char type;\n\tunsigned char scope;\n\tu32 tclassid;\n\tstruct fib_nh_common *nhc;\n\tstruct fib_info *fi;\n\tstruct fib_table *table;\n\tstruct hlist_head *fa_head;\n};\n\nenum {\n\tINET_ECN_NOT_ECT = 0,\n\tINET_ECN_ECT_1 = 1,\n\tINET_ECN_ECT_0 = 2,\n\tINET_ECN_CE = 3,\n\tINET_ECN_MASK = 3,\n};\n\nstruct tcp_skb_cb {\n\t__u32 seq;\n\t__u32 end_seq;\n\tunion {\n\t\t__u32 tcp_tw_isn;\n\t\tstruct {\n\t\t\tu16 tcp_gso_segs;\n\t\t\tu16 tcp_gso_size;\n\t\t};\n\t};\n\t__u8 tcp_flags;\n\t__u8 sacked;\n\t__u8 ip_dsfield;\n\t__u8 txstamp_ack: 1;\n\t__u8 eor: 1;\n\t__u8 has_rxtstamp: 1;\n\t__u8 unused: 5;\n\t__u32 ack_seq;\n\tunion {\n\t\tstruct {\n\t\t\t__u32 in_flight: 30;\n\t\t\t__u32 is_app_limited: 1;\n\t\t\t__u32 unused: 1;\n\t\t\t__u32 delivered;\n\t\t\tu64 first_tx_mstamp;\n\t\t\tu64 delivered_mstamp;\n\t\t} tx;\n\t\tunion {\n\t\t\tstruct inet_skb_parm h4;\n\t\t\tstruct inet6_skb_parm h6;\n\t\t} header;\n\t};\n};\n\nstruct strp_msg {\n\tint full_len;\n\tint offset;\n};\n\nstruct xdp_umem {\n\tvoid *addrs;\n\tu64 size;\n\tu32 headroom;\n\tu32 chunk_size;\n\tu32 chunks;\n\tu32 npgs;\n\tstruct user_struct *user;\n\trefcount_t users;\n\tu8 flags;\n\tbool zc;\n\tstruct page **pgs;\n\tint id;\n\tstruct list_head xsk_dma_list;\n\tstruct work_struct work;\n};\n\nstruct xsk_queue;\n\nstruct xdp_sock {\n\tstruct sock sk;\n\tstruct xsk_queue *rx;\n\tstruct net_device *dev;\n\tstruct xdp_umem *umem;\n\tstruct list_head flush_node;\n\tstruct xsk_buff_pool *pool;\n\tu16 queue_id;\n\tbool zc;\n\tenum {\n\t\tXSK_READY = 0,\n\t\tXSK_BOUND = 1,\n\t\tXSK_UNBOUND = 2,\n\t} state;\n\tlong: 64;\n\tstruct xsk_queue *tx;\n\tstruct list_head tx_list;\n\tspinlock_t rx_lock;\n\tu64 rx_dropped;\n\tu64 rx_queue_full;\n\tstruct list_head map_list;\n\tspinlock_t map_list_lock;\n\tstruct mutex mutex;\n\tstruct xsk_queue *fq_tmp;\n\tstruct xsk_queue *cq_tmp;\n\tlong: 64;\n};\n\nstruct ipv6_sr_hdr {\n\t__u8 nexthdr;\n\t__u8 hdrlen;\n\t__u8 type;\n\t__u8 segments_left;\n\t__u8 first_segment;\n\t__u8 flags;\n\t__u16 tag;\n\tstruct in6_addr segments[0];\n};\n\nenum {\n\tSEG6_LOCAL_ACTION_UNSPEC = 0,\n\tSEG6_LOCAL_ACTION_END = 1,\n\tSEG6_LOCAL_ACTION_END_X = 2,\n\tSEG6_LOCAL_ACTION_END_T = 3,\n\tSEG6_LOCAL_ACTION_END_DX2 = 4,\n\tSEG6_LOCAL_ACTION_END_DX6 = 5,\n\tSEG6_LOCAL_ACTION_END_DX4 = 6,\n\tSEG6_LOCAL_ACTION_END_DT6 = 7,\n\tSEG6_LOCAL_ACTION_END_DT4 = 8,\n\tSEG6_LOCAL_ACTION_END_B6 = 9,\n\tSEG6_LOCAL_ACTION_END_B6_ENCAP = 10,\n\tSEG6_LOCAL_ACTION_END_BM = 11,\n\tSEG6_LOCAL_ACTION_END_S = 12,\n\tSEG6_LOCAL_ACTION_END_AS = 13,\n\tSEG6_LOCAL_ACTION_END_AM = 14,\n\tSEG6_LOCAL_ACTION_END_BPF = 15,\n\tSEG6_LOCAL_ACTION_END_DT46 = 16,\n\t__SEG6_LOCAL_ACTION_MAX = 17,\n};\n\nstruct seg6_bpf_srh_state {\n\tstruct ipv6_sr_hdr *srh;\n\tu16 hdrlen;\n\tbool valid;\n};\n\nstruct tls_crypto_info {\n\t__u16 version;\n\t__u16 cipher_type;\n};\n\nstruct tls12_crypto_info_aes_gcm_128 {\n\tstruct tls_crypto_info info;\n\tunsigned char iv[8];\n\tunsigned char key[16];\n\tunsigned char salt[4];\n\tunsigned char rec_seq[8];\n};\n\nstruct tls12_crypto_info_aes_gcm_256 {\n\tstruct tls_crypto_info info;\n\tunsigned char iv[8];\n\tunsigned char key[32];\n\tunsigned char salt[4];\n\tunsigned char rec_seq[8];\n};\n\nstruct tls12_crypto_info_chacha20_poly1305 {\n\tstruct tls_crypto_info info;\n\tunsigned char iv[12];\n\tunsigned char key[32];\n\tunsigned char salt[0];\n\tunsigned char rec_seq[8];\n};\n\nstruct tls_sw_context_rx {\n\tstruct crypto_aead *aead_recv;\n\tstruct crypto_wait async_wait;\n\tstruct strparser strp;\n\tstruct sk_buff_head rx_list;\n\tvoid (*saved_data_ready)(struct sock *);\n\tstruct sk_buff *recv_pkt;\n\tu8 control;\n\tu8 async_capable: 1;\n\tu8 decrypted: 1;\n\tatomic_t decrypt_pending;\n\tspinlock_t decrypt_compl_lock;\n\tbool async_notify;\n};\n\nstruct cipher_context {\n\tchar *iv;\n\tchar *rec_seq;\n};\n\nunion tls_crypto_context {\n\tstruct tls_crypto_info info;\n\tunion {\n\t\tstruct tls12_crypto_info_aes_gcm_128 aes_gcm_128;\n\t\tstruct tls12_crypto_info_aes_gcm_256 aes_gcm_256;\n\t\tstruct tls12_crypto_info_chacha20_poly1305 chacha20_poly1305;\n\t};\n};\n\nstruct tls_prot_info {\n\tu16 version;\n\tu16 cipher_type;\n\tu16 prepend_size;\n\tu16 tag_size;\n\tu16 overhead_size;\n\tu16 iv_size;\n\tu16 salt_size;\n\tu16 rec_seq_size;\n\tu16 aad_size;\n\tu16 tail_size;\n};\n\nstruct tls_context {\n\tstruct tls_prot_info prot_info;\n\tu8 tx_conf: 3;\n\tu8 rx_conf: 3;\n\tint (*push_pending_record)(struct sock *, int);\n\tvoid (*sk_write_space)(struct sock *);\n\tvoid *priv_ctx_tx;\n\tvoid *priv_ctx_rx;\n\tstruct net_device *netdev;\n\tstruct cipher_context tx;\n\tstruct cipher_context rx;\n\tstruct scatterlist *partially_sent_record;\n\tu16 partially_sent_offset;\n\tbool in_tcp_sendpages;\n\tbool pending_open_record_frags;\n\tstruct mutex tx_lock;\n\tlong unsigned int flags;\n\tstruct proto *sk_proto;\n\tstruct sock *sk;\n\tvoid (*sk_destruct)(struct sock *);\n\tunion tls_crypto_context crypto_send;\n\tunion tls_crypto_context crypto_recv;\n\tstruct list_head list;\n\trefcount_t refcount;\n\tstruct callback_head rcu;\n};\n\ntypedef u64 (*btf_bpf_skb_get_pay_offset)(struct sk_buff *);\n\ntypedef u64 (*btf_bpf_skb_get_nlattr)(struct sk_buff *, u32, u32);\n\ntypedef u64 (*btf_bpf_skb_get_nlattr_nest)(struct sk_buff *, u32, u32);\n\ntypedef u64 (*btf_bpf_skb_load_helper_8)(const struct sk_buff *, const void *, int, int);\n\ntypedef u64 (*btf_bpf_skb_load_helper_8_no_cache)(const struct sk_buff *, int);\n\ntypedef u64 (*btf_bpf_skb_load_helper_16)(const struct sk_buff *, const void *, int, int);\n\ntypedef u64 (*btf_bpf_skb_load_helper_16_no_cache)(const struct sk_buff *, int);\n\ntypedef u64 (*btf_bpf_skb_load_helper_32)(const struct sk_buff *, const void *, int, int);\n\ntypedef u64 (*btf_bpf_skb_load_helper_32_no_cache)(const struct sk_buff *, int);\n\nstruct bpf_scratchpad {\n\tunion {\n\t\t__be32 diff[128];\n\t\tu8 buff[512];\n\t};\n};\n\ntypedef u64 (*btf_bpf_skb_store_bytes)(struct sk_buff *, u32, const void *, u32, u64);\n\ntypedef u64 (*btf_bpf_skb_load_bytes)(const struct sk_buff *, u32, void *, u32);\n\ntypedef u64 (*btf_bpf_flow_dissector_load_bytes)(const struct bpf_flow_dissector *, u32, void *, u32);\n\ntypedef u64 (*btf_bpf_skb_load_bytes_relative)(const struct sk_buff *, u32, void *, u32, u32);\n\ntypedef u64 (*btf_bpf_skb_pull_data)(struct sk_buff *, u32);\n\ntypedef u64 (*btf_bpf_sk_fullsock)(struct sock *);\n\ntypedef u64 (*btf_sk_skb_pull_data)(struct sk_buff *, u32);\n\ntypedef u64 (*btf_bpf_l3_csum_replace)(struct sk_buff *, u32, u64, u64, u64);\n\ntypedef u64 (*btf_bpf_l4_csum_replace)(struct sk_buff *, u32, u64, u64, u64);\n\ntypedef u64 (*btf_bpf_csum_diff)(__be32 *, u32, __be32 *, u32, __wsum);\n\ntypedef u64 (*btf_bpf_csum_update)(struct sk_buff *, __wsum);\n\ntypedef u64 (*btf_bpf_csum_level)(struct sk_buff *, u64);\n\nenum {\n\tBPF_F_NEIGH = 2,\n\tBPF_F_PEER = 4,\n\tBPF_F_NEXTHOP = 8,\n};\n\ntypedef u64 (*btf_bpf_clone_redirect)(struct sk_buff *, u32, u64);\n\ntypedef u64 (*btf_bpf_redirect)(u32, u64);\n\ntypedef u64 (*btf_bpf_redirect_peer)(u32, u64);\n\ntypedef u64 (*btf_bpf_redirect_neigh)(u32, struct bpf_redir_neigh *, int, u64);\n\ntypedef u64 (*btf_bpf_msg_apply_bytes)(struct sk_msg *, u32);\n\ntypedef u64 (*btf_bpf_msg_cork_bytes)(struct sk_msg *, u32);\n\ntypedef u64 (*btf_bpf_msg_pull_data)(struct sk_msg *, u32, u32, u64);\n\ntypedef u64 (*btf_bpf_msg_push_data)(struct sk_msg *, u32, u32, u64);\n\ntypedef u64 (*btf_bpf_msg_pop_data)(struct sk_msg *, u32, u32, u64);\n\ntypedef u64 (*btf_bpf_get_cgroup_classid_curr)();\n\ntypedef u64 (*btf_bpf_skb_cgroup_classid)(const struct sk_buff *);\n\ntypedef u64 (*btf_bpf_get_cgroup_classid)(const struct sk_buff *);\n\ntypedef u64 (*btf_bpf_get_route_realm)(const struct sk_buff *);\n\ntypedef u64 (*btf_bpf_get_hash_recalc)(struct sk_buff *);\n\ntypedef u64 (*btf_bpf_set_hash_invalid)(struct sk_buff *);\n\ntypedef u64 (*btf_bpf_set_hash)(struct sk_buff *, u32);\n\ntypedef u64 (*btf_bpf_skb_vlan_push)(struct sk_buff *, __be16, u16);\n\ntypedef u64 (*btf_bpf_skb_vlan_pop)(struct sk_buff *);\n\ntypedef u64 (*btf_bpf_skb_change_proto)(struct sk_buff *, __be16, u64);\n\ntypedef u64 (*btf_bpf_skb_change_type)(struct sk_buff *, u32);\n\ntypedef u64 (*btf_sk_skb_adjust_room)(struct sk_buff *, s32, u32, u64);\n\ntypedef u64 (*btf_bpf_skb_adjust_room)(struct sk_buff *, s32, u32, u64);\n\ntypedef u64 (*btf_bpf_skb_change_tail)(struct sk_buff *, u32, u64);\n\ntypedef u64 (*btf_sk_skb_change_tail)(struct sk_buff *, u32, u64);\n\ntypedef u64 (*btf_bpf_skb_change_head)(struct sk_buff *, u32, u64);\n\ntypedef u64 (*btf_sk_skb_change_head)(struct sk_buff *, u32, u64);\n\ntypedef u64 (*btf_bpf_xdp_adjust_head)(struct xdp_buff *, int);\n\ntypedef u64 (*btf_bpf_xdp_adjust_tail)(struct xdp_buff *, int);\n\ntypedef u64 (*btf_bpf_xdp_adjust_meta)(struct xdp_buff *, int);\n\ntypedef u64 (*btf_bpf_xdp_redirect)(u32, u64);\n\ntypedef u64 (*btf_bpf_xdp_redirect_map)(struct bpf_map *, u32, u64);\n\ntypedef u64 (*btf_bpf_skb_event_output)(struct sk_buff *, struct bpf_map *, u64, void *, u64);\n\ntypedef u64 (*btf_bpf_skb_get_tunnel_key)(struct sk_buff *, struct bpf_tunnel_key *, u32, u64);\n\ntypedef u64 (*btf_bpf_skb_get_tunnel_opt)(struct sk_buff *, u8 *, u32);\n\ntypedef u64 (*btf_bpf_skb_set_tunnel_key)(struct sk_buff *, const struct bpf_tunnel_key *, u32, u64);\n\ntypedef u64 (*btf_bpf_skb_set_tunnel_opt)(struct sk_buff *, const u8 *, u32);\n\ntypedef u64 (*btf_bpf_skb_under_cgroup)(struct sk_buff *, struct bpf_map *, u32);\n\ntypedef u64 (*btf_bpf_skb_cgroup_id)(const struct sk_buff *);\n\ntypedef u64 (*btf_bpf_skb_ancestor_cgroup_id)(const struct sk_buff *, int);\n\ntypedef u64 (*btf_bpf_sk_cgroup_id)(struct sock *);\n\ntypedef u64 (*btf_bpf_sk_ancestor_cgroup_id)(struct sock *, int);\n\ntypedef u64 (*btf_bpf_xdp_event_output)(struct xdp_buff *, struct bpf_map *, u64, void *, u64);\n\ntypedef u64 (*btf_bpf_get_socket_cookie)(struct sk_buff *);\n\ntypedef u64 (*btf_bpf_get_socket_cookie_sock_addr)(struct bpf_sock_addr_kern *);\n\ntypedef u64 (*btf_bpf_get_socket_cookie_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_get_socket_ptr_cookie)(struct sock *);\n\ntypedef u64 (*btf_bpf_get_socket_cookie_sock_ops)(struct bpf_sock_ops_kern *);\n\ntypedef u64 (*btf_bpf_get_netns_cookie_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_get_netns_cookie_sock_addr)(struct bpf_sock_addr_kern *);\n\ntypedef u64 (*btf_bpf_get_socket_uid)(struct sk_buff *);\n\ntypedef u64 (*btf_bpf_sock_addr_setsockopt)(struct bpf_sock_addr_kern *, int, int, char *, int);\n\ntypedef u64 (*btf_bpf_sock_addr_getsockopt)(struct bpf_sock_addr_kern *, int, int, char *, int);\n\ntypedef u64 (*btf_bpf_sock_ops_setsockopt)(struct bpf_sock_ops_kern *, int, int, char *, int);\n\ntypedef u64 (*btf_bpf_sock_ops_getsockopt)(struct bpf_sock_ops_kern *, int, int, char *, int);\n\ntypedef u64 (*btf_bpf_sock_ops_cb_flags_set)(struct bpf_sock_ops_kern *, int);\n\ntypedef u64 (*btf_bpf_bind)(struct bpf_sock_addr_kern *, struct sockaddr *, int);\n\ntypedef u64 (*btf_bpf_skb_get_xfrm_state)(struct sk_buff *, u32, struct bpf_xfrm_state *, u32, u64);\n\ntypedef u64 (*btf_bpf_xdp_fib_lookup)(struct xdp_buff *, struct bpf_fib_lookup *, int, u32);\n\ntypedef u64 (*btf_bpf_skb_fib_lookup)(struct sk_buff *, struct bpf_fib_lookup *, int, u32);\n\ntypedef u64 (*btf_bpf_skb_check_mtu)(struct sk_buff *, u32, u32 *, s32, u64);\n\ntypedef u64 (*btf_bpf_xdp_check_mtu)(struct xdp_buff *, u32, u32 *, s32, u64);\n\ntypedef u64 (*btf_bpf_lwt_in_push_encap)(struct sk_buff *, u32, void *, u32);\n\ntypedef u64 (*btf_bpf_lwt_xmit_push_encap)(struct sk_buff *, u32, void *, u32);\n\ntypedef u64 (*btf_bpf_lwt_seg6_store_bytes)(struct sk_buff *, u32, const void *, u32);\n\ntypedef u64 (*btf_bpf_lwt_seg6_action)(struct sk_buff *, u32, void *, u32);\n\ntypedef u64 (*btf_bpf_lwt_seg6_adjust_srh)(struct sk_buff *, u32, s32);\n\ntypedef u64 (*btf_bpf_skc_lookup_tcp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64);\n\ntypedef u64 (*btf_bpf_sk_lookup_tcp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64);\n\ntypedef u64 (*btf_bpf_sk_lookup_udp)(struct sk_buff *, struct bpf_sock_tuple *, u32, u64, u64);\n\ntypedef u64 (*btf_bpf_sk_release)(struct sock *);\n\ntypedef u64 (*btf_bpf_xdp_sk_lookup_udp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64);\n\ntypedef u64 (*btf_bpf_xdp_skc_lookup_tcp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64);\n\ntypedef u64 (*btf_bpf_xdp_sk_lookup_tcp)(struct xdp_buff *, struct bpf_sock_tuple *, u32, u32, u64);\n\ntypedef u64 (*btf_bpf_sock_addr_skc_lookup_tcp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64);\n\ntypedef u64 (*btf_bpf_sock_addr_sk_lookup_tcp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64);\n\ntypedef u64 (*btf_bpf_sock_addr_sk_lookup_udp)(struct bpf_sock_addr_kern *, struct bpf_sock_tuple *, u32, u64, u64);\n\ntypedef u64 (*btf_bpf_tcp_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_get_listener_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_skb_ecn_set_ce)(struct sk_buff *);\n\ntypedef u64 (*btf_bpf_tcp_check_syncookie)(struct sock *, void *, u32, struct tcphdr *, u32);\n\ntypedef u64 (*btf_bpf_tcp_gen_syncookie)(struct sock *, void *, u32, struct tcphdr *, u32);\n\ntypedef u64 (*btf_bpf_sk_assign)(struct sk_buff *, struct sock *, u64);\n\ntypedef u64 (*btf_bpf_sock_ops_load_hdr_opt)(struct bpf_sock_ops_kern *, void *, u32, u64);\n\ntypedef u64 (*btf_bpf_sock_ops_store_hdr_opt)(struct bpf_sock_ops_kern *, const void *, u32, u64);\n\ntypedef u64 (*btf_bpf_sock_ops_reserve_hdr_opt)(struct bpf_sock_ops_kern *, u32, u64);\n\ntypedef u64 (*btf_sk_select_reuseport)(struct sk_reuseport_kern *, struct bpf_map *, void *, u32);\n\ntypedef u64 (*btf_sk_reuseport_load_bytes)(const struct sk_reuseport_kern *, u32, void *, u32);\n\ntypedef u64 (*btf_sk_reuseport_load_bytes_relative)(const struct sk_reuseport_kern *, u32, void *, u32, u32);\n\ntypedef u64 (*btf_bpf_sk_lookup_assign)(struct bpf_sk_lookup_kern *, struct sock *, u64);\n\ntypedef u64 (*btf_bpf_skc_to_tcp6_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_skc_to_tcp_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_skc_to_tcp_timewait_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_skc_to_tcp_request_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_skc_to_udp6_sock)(struct sock *);\n\ntypedef u64 (*btf_bpf_sock_from_file)(struct file *);\n\nstruct bpf_dtab_netdev___2;\n\nstruct bpf_cpu_map_entry___2;\n\nenum {\n\tINET_DIAG_REQ_NONE = 0,\n\tINET_DIAG_REQ_BYTECODE = 1,\n\tINET_DIAG_REQ_SK_BPF_STORAGES = 2,\n\tINET_DIAG_REQ_PROTOCOL = 3,\n\t__INET_DIAG_REQ_MAX = 4,\n};\n\nstruct sock_diag_req {\n\t__u8 sdiag_family;\n\t__u8 sdiag_protocol;\n};\n\nstruct sock_diag_handler {\n\t__u8 family;\n\tint (*dump)(struct sk_buff *, struct nlmsghdr *);\n\tint (*get_info)(struct sk_buff *, struct sock *);\n\tint (*destroy)(struct sk_buff *, struct nlmsghdr *);\n};\n\nstruct broadcast_sk {\n\tstruct sock *sk;\n\tstruct work_struct work;\n};\n\ntypedef int gifconf_func_t(struct net_device *, char *, int, int);\n\nstruct hwtstamp_config {\n\tint flags;\n\tint tx_type;\n\tint rx_filter;\n};\n\nenum hwtstamp_tx_types {\n\tHWTSTAMP_TX_OFF = 0,\n\tHWTSTAMP_TX_ON = 1,\n\tHWTSTAMP_TX_ONESTEP_SYNC = 2,\n\tHWTSTAMP_TX_ONESTEP_P2P = 3,\n\t__HWTSTAMP_TX_CNT = 4,\n};\n\nenum hwtstamp_rx_filters {\n\tHWTSTAMP_FILTER_NONE = 0,\n\tHWTSTAMP_FILTER_ALL = 1,\n\tHWTSTAMP_FILTER_SOME = 2,\n\tHWTSTAMP_FILTER_PTP_V1_L4_EVENT = 3,\n\tHWTSTAMP_FILTER_PTP_V1_L4_SYNC = 4,\n\tHWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ = 5,\n\tHWTSTAMP_FILTER_PTP_V2_L4_EVENT = 6,\n\tHWTSTAMP_FILTER_PTP_V2_L4_SYNC = 7,\n\tHWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ = 8,\n\tHWTSTAMP_FILTER_PTP_V2_L2_EVENT = 9,\n\tHWTSTAMP_FILTER_PTP_V2_L2_SYNC = 10,\n\tHWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ = 11,\n\tHWTSTAMP_FILTER_PTP_V2_EVENT = 12,\n\tHWTSTAMP_FILTER_PTP_V2_SYNC = 13,\n\tHWTSTAMP_FILTER_PTP_V2_DELAY_REQ = 14,\n\tHWTSTAMP_FILTER_NTP_ALL = 15,\n\t__HWTSTAMP_FILTER_CNT = 16,\n};\n\nstruct tso_t {\n\tint next_frag_idx;\n\tint size;\n\tvoid *data;\n\tu16 ip_id;\n\tu8 tlen;\n\tbool ipv6;\n\tu32 tcp_seq;\n};\n\nstruct fib_notifier_info {\n\tint family;\n\tstruct netlink_ext_ack *extack;\n};\n\nenum fib_event_type {\n\tFIB_EVENT_ENTRY_REPLACE = 0,\n\tFIB_EVENT_ENTRY_APPEND = 1,\n\tFIB_EVENT_ENTRY_ADD = 2,\n\tFIB_EVENT_ENTRY_DEL = 3,\n\tFIB_EVENT_RULE_ADD = 4,\n\tFIB_EVENT_RULE_DEL = 5,\n\tFIB_EVENT_NH_ADD = 6,\n\tFIB_EVENT_NH_DEL = 7,\n\tFIB_EVENT_VIF_ADD = 8,\n\tFIB_EVENT_VIF_DEL = 9,\n};\n\nstruct fib_notifier_net {\n\tstruct list_head fib_notifier_ops;\n\tstruct atomic_notifier_head fib_chain;\n};\n\nstruct xdp_frame_bulk {\n\tint count;\n\tvoid *xa;\n\tvoid *q[16];\n};\n\nstruct xdp_attachment_info {\n\tstruct bpf_prog *prog;\n\tu32 flags;\n};\n\nstruct xdp_buff_xsk;\n\nstruct xsk_buff_pool {\n\tstruct device *dev;\n\tstruct net_device *netdev;\n\tstruct list_head xsk_tx_list;\n\tspinlock_t xsk_tx_list_lock;\n\trefcount_t users;\n\tstruct xdp_umem *umem;\n\tstruct work_struct work;\n\tstruct list_head free_list;\n\tu32 heads_cnt;\n\tu16 queue_id;\n\tlong: 16;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tstruct xsk_queue *fq;\n\tstruct xsk_queue *cq;\n\tdma_addr_t *dma_pages;\n\tstruct xdp_buff_xsk *heads;\n\tu64 chunk_mask;\n\tu64 addrs_cnt;\n\tu32 free_list_cnt;\n\tu32 dma_pages_cnt;\n\tu32 free_heads_cnt;\n\tu32 headroom;\n\tu32 chunk_size;\n\tu32 frame_len;\n\tu8 cached_need_wakeup;\n\tbool uses_need_wakeup;\n\tbool dma_need_sync;\n\tbool unaligned;\n\tvoid *addrs;\n\tspinlock_t cq_lock;\n\tstruct xdp_buff_xsk *free_heads[0];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct xdp_buff_xsk {\n\tstruct xdp_buff xdp;\n\tdma_addr_t dma;\n\tdma_addr_t frame_dma;\n\tstruct xsk_buff_pool *pool;\n\tbool unaligned;\n\tu64 orig_addr;\n\tstruct list_head free_list_node;\n};\n\nstruct flow_match_meta {\n\tstruct flow_dissector_key_meta *key;\n\tstruct flow_dissector_key_meta *mask;\n};\n\nstruct flow_match_basic {\n\tstruct flow_dissector_key_basic *key;\n\tstruct flow_dissector_key_basic *mask;\n};\n\nstruct flow_match_control {\n\tstruct flow_dissector_key_control *key;\n\tstruct flow_dissector_key_control *mask;\n};\n\nstruct flow_match_eth_addrs {\n\tstruct flow_dissector_key_eth_addrs *key;\n\tstruct flow_dissector_key_eth_addrs *mask;\n};\n\nstruct flow_match_vlan {\n\tstruct flow_dissector_key_vlan *key;\n\tstruct flow_dissector_key_vlan *mask;\n};\n\nstruct flow_match_ipv4_addrs {\n\tstruct flow_dissector_key_ipv4_addrs *key;\n\tstruct flow_dissector_key_ipv4_addrs *mask;\n};\n\nstruct flow_match_ipv6_addrs {\n\tstruct flow_dissector_key_ipv6_addrs *key;\n\tstruct flow_dissector_key_ipv6_addrs *mask;\n};\n\nstruct flow_match_ip {\n\tstruct flow_dissector_key_ip *key;\n\tstruct flow_dissector_key_ip *mask;\n};\n\nstruct flow_match_ports {\n\tstruct flow_dissector_key_ports *key;\n\tstruct flow_dissector_key_ports *mask;\n};\n\nstruct flow_match_icmp {\n\tstruct flow_dissector_key_icmp *key;\n\tstruct flow_dissector_key_icmp *mask;\n};\n\nstruct flow_match_tcp {\n\tstruct flow_dissector_key_tcp *key;\n\tstruct flow_dissector_key_tcp *mask;\n};\n\nstruct flow_match_mpls {\n\tstruct flow_dissector_key_mpls *key;\n\tstruct flow_dissector_key_mpls *mask;\n};\n\nstruct flow_match_enc_keyid {\n\tstruct flow_dissector_key_keyid *key;\n\tstruct flow_dissector_key_keyid *mask;\n};\n\nstruct flow_match_enc_opts {\n\tstruct flow_dissector_key_enc_opts *key;\n\tstruct flow_dissector_key_enc_opts *mask;\n};\n\nstruct flow_match_ct {\n\tstruct flow_dissector_key_ct *key;\n\tstruct flow_dissector_key_ct *mask;\n};\n\nenum flow_block_command {\n\tFLOW_BLOCK_BIND = 0,\n\tFLOW_BLOCK_UNBIND = 1,\n};\n\nenum flow_block_binder_type {\n\tFLOW_BLOCK_BINDER_TYPE_UNSPEC = 0,\n\tFLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS = 1,\n\tFLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS = 2,\n\tFLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP = 3,\n\tFLOW_BLOCK_BINDER_TYPE_RED_MARK = 4,\n};\n\nstruct flow_block_offload {\n\tenum flow_block_command command;\n\tenum flow_block_binder_type binder_type;\n\tbool block_shared;\n\tbool unlocked_driver_cb;\n\tstruct net *net;\n\tstruct flow_block *block;\n\tstruct list_head cb_list;\n\tstruct list_head *driver_block_list;\n\tstruct netlink_ext_ack *extack;\n\tstruct Qdisc *sch;\n};\n\nstruct flow_block_cb;\n\nstruct flow_block_indr {\n\tstruct list_head list;\n\tstruct net_device *dev;\n\tstruct Qdisc *sch;\n\tenum flow_block_binder_type binder_type;\n\tvoid *data;\n\tvoid *cb_priv;\n\tvoid (*cleanup)(struct flow_block_cb *);\n};\n\nstruct flow_block_cb {\n\tstruct list_head driver_list;\n\tstruct list_head list;\n\tflow_setup_cb_t *cb;\n\tvoid *cb_ident;\n\tvoid *cb_priv;\n\tvoid (*release)(void *);\n\tstruct flow_block_indr indr;\n\tunsigned int refcnt;\n};\n\ntypedef int flow_indr_block_bind_cb_t(struct net_device *, struct Qdisc *, void *, enum tc_setup_type, void *, void *, void (*)(struct flow_block_cb *));\n\nstruct flow_indr_dev {\n\tstruct list_head list;\n\tflow_indr_block_bind_cb_t *cb;\n\tvoid *cb_priv;\n\trefcount_t refcnt;\n\tstruct callback_head rcu;\n};\n\nstruct rx_queue_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct netdev_rx_queue *, char *);\n\tssize_t (*store)(struct netdev_rx_queue *, const char *, size_t);\n};\n\nstruct netdev_queue_attribute {\n\tstruct attribute attr;\n\tssize_t (*show)(struct netdev_queue *, char *);\n\tssize_t (*store)(struct netdev_queue *, const char *, size_t);\n};\n\nstruct inet6_ifaddr {\n\tstruct in6_addr addr;\n\t__u32 prefix_len;\n\t__u32 rt_priority;\n\t__u32 valid_lft;\n\t__u32 prefered_lft;\n\trefcount_t refcnt;\n\tspinlock_t lock;\n\tint state;\n\t__u32 flags;\n\t__u8 dad_probes;\n\t__u8 stable_privacy_retry;\n\t__u16 scope;\n\t__u64 dad_nonce;\n\tlong unsigned int cstamp;\n\tlong unsigned int tstamp;\n\tstruct delayed_work dad_work;\n\tstruct inet6_dev *idev;\n\tstruct fib6_info *rt;\n\tstruct hlist_node addr_lst;\n\tstruct list_head if_list;\n\tstruct list_head tmp_list;\n\tstruct inet6_ifaddr *ifpub;\n\tint regen_count;\n\tbool tokenized;\n\tstruct callback_head rcu;\n\tstruct in6_addr peer_addr;\n};\n\nstruct fib_rule_uid_range {\n\t__u32 start;\n\t__u32 end;\n};\n\nenum {\n\tFRA_UNSPEC = 0,\n\tFRA_DST = 1,\n\tFRA_SRC = 2,\n\tFRA_IIFNAME = 3,\n\tFRA_GOTO = 4,\n\tFRA_UNUSED2 = 5,\n\tFRA_PRIORITY = 6,\n\tFRA_UNUSED3 = 7,\n\tFRA_UNUSED4 = 8,\n\tFRA_UNUSED5 = 9,\n\tFRA_FWMARK = 10,\n\tFRA_FLOW = 11,\n\tFRA_TUN_ID = 12,\n\tFRA_SUPPRESS_IFGROUP = 13,\n\tFRA_SUPPRESS_PREFIXLEN = 14,\n\tFRA_TABLE = 15,\n\tFRA_FWMASK = 16,\n\tFRA_OIFNAME = 17,\n\tFRA_PAD = 18,\n\tFRA_L3MDEV = 19,\n\tFRA_UID_RANGE = 20,\n\tFRA_PROTOCOL = 21,\n\tFRA_IP_PROTO = 22,\n\tFRA_SPORT_RANGE = 23,\n\tFRA_DPORT_RANGE = 24,\n\t__FRA_MAX = 25,\n};\n\nenum {\n\tFR_ACT_UNSPEC = 0,\n\tFR_ACT_TO_TBL = 1,\n\tFR_ACT_GOTO = 2,\n\tFR_ACT_NOP = 3,\n\tFR_ACT_RES3 = 4,\n\tFR_ACT_RES4 = 5,\n\tFR_ACT_BLACKHOLE = 6,\n\tFR_ACT_UNREACHABLE = 7,\n\tFR_ACT_PROHIBIT = 8,\n\t__FR_ACT_MAX = 9,\n};\n\nstruct fib_rule_notifier_info {\n\tstruct fib_notifier_info info;\n\tstruct fib_rule *rule;\n};\n\nstruct trace_event_raw_kfree_skb {\n\tstruct trace_entry ent;\n\tvoid *skbaddr;\n\tvoid *location;\n\tshort unsigned int protocol;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_consume_skb {\n\tstruct trace_entry ent;\n\tvoid *skbaddr;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_skb_copy_datagram_iovec {\n\tstruct trace_entry ent;\n\tconst void *skbaddr;\n\tint len;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_kfree_skb {};\n\nstruct trace_event_data_offsets_consume_skb {};\n\nstruct trace_event_data_offsets_skb_copy_datagram_iovec {};\n\ntypedef void (*btf_trace_kfree_skb)(void *, struct sk_buff *, void *);\n\ntypedef void (*btf_trace_consume_skb)(void *, struct sk_buff *);\n\ntypedef void (*btf_trace_skb_copy_datagram_iovec)(void *, const struct sk_buff *, int);\n\nstruct trace_event_raw_net_dev_start_xmit {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tu16 queue_mapping;\n\tconst void *skbaddr;\n\tbool vlan_tagged;\n\tu16 vlan_proto;\n\tu16 vlan_tci;\n\tu16 protocol;\n\tu8 ip_summed;\n\tunsigned int len;\n\tunsigned int data_len;\n\tint network_offset;\n\tbool transport_offset_valid;\n\tint transport_offset;\n\tu8 tx_flags;\n\tu16 gso_size;\n\tu16 gso_segs;\n\tu16 gso_type;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_net_dev_xmit {\n\tstruct trace_entry ent;\n\tvoid *skbaddr;\n\tunsigned int len;\n\tint rc;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_net_dev_xmit_timeout {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tu32 __data_loc_driver;\n\tint queue_index;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_net_dev_template {\n\tstruct trace_entry ent;\n\tvoid *skbaddr;\n\tunsigned int len;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_net_dev_rx_verbose_template {\n\tstruct trace_entry ent;\n\tu32 __data_loc_name;\n\tunsigned int napi_id;\n\tu16 queue_mapping;\n\tconst void *skbaddr;\n\tbool vlan_tagged;\n\tu16 vlan_proto;\n\tu16 vlan_tci;\n\tu16 protocol;\n\tu8 ip_summed;\n\tu32 hash;\n\tbool l4_hash;\n\tunsigned int len;\n\tunsigned int data_len;\n\tunsigned int truesize;\n\tbool mac_header_valid;\n\tint mac_header;\n\tunsigned char nr_frags;\n\tu16 gso_size;\n\tu16 gso_type;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_net_dev_rx_exit_template {\n\tstruct trace_entry ent;\n\tint ret;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_net_dev_start_xmit {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_net_dev_xmit {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_net_dev_xmit_timeout {\n\tu32 name;\n\tu32 driver;\n};\n\nstruct trace_event_data_offsets_net_dev_template {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_net_dev_rx_verbose_template {\n\tu32 name;\n};\n\nstruct trace_event_data_offsets_net_dev_rx_exit_template {};\n\ntypedef void (*btf_trace_net_dev_start_xmit)(void *, const struct sk_buff *, const struct net_device *);\n\ntypedef void (*btf_trace_net_dev_xmit)(void *, struct sk_buff *, int, struct net_device *, unsigned int);\n\ntypedef void (*btf_trace_net_dev_xmit_timeout)(void *, struct net_device *, int);\n\ntypedef void (*btf_trace_net_dev_queue)(void *, struct sk_buff *);\n\ntypedef void (*btf_trace_netif_receive_skb)(void *, struct sk_buff *);\n\ntypedef void (*btf_trace_netif_rx)(void *, struct sk_buff *);\n\ntypedef void (*btf_trace_napi_gro_frags_entry)(void *, const struct sk_buff *);\n\ntypedef void (*btf_trace_napi_gro_receive_entry)(void *, const struct sk_buff *);\n\ntypedef void (*btf_trace_netif_receive_skb_entry)(void *, const struct sk_buff *);\n\ntypedef void (*btf_trace_netif_receive_skb_list_entry)(void *, const struct sk_buff *);\n\ntypedef void (*btf_trace_netif_rx_entry)(void *, const struct sk_buff *);\n\ntypedef void (*btf_trace_netif_rx_ni_entry)(void *, const struct sk_buff *);\n\ntypedef void (*btf_trace_napi_gro_frags_exit)(void *, int);\n\ntypedef void (*btf_trace_napi_gro_receive_exit)(void *, int);\n\ntypedef void (*btf_trace_netif_receive_skb_exit)(void *, int);\n\ntypedef void (*btf_trace_netif_rx_exit)(void *, int);\n\ntypedef void (*btf_trace_netif_rx_ni_exit)(void *, int);\n\ntypedef void (*btf_trace_netif_receive_skb_list_exit)(void *, int);\n\nstruct trace_event_raw_napi_poll {\n\tstruct trace_entry ent;\n\tstruct napi_struct *napi;\n\tu32 __data_loc_dev_name;\n\tint work;\n\tint budget;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_napi_poll {\n\tu32 dev_name;\n};\n\ntypedef void (*btf_trace_napi_poll)(void *, struct napi_struct *, int, int);\n\nenum tcp_ca_state {\n\tTCP_CA_Open = 0,\n\tTCP_CA_Disorder = 1,\n\tTCP_CA_CWR = 2,\n\tTCP_CA_Recovery = 3,\n\tTCP_CA_Loss = 4,\n};\n\nstruct trace_event_raw_sock_rcvqueue_full {\n\tstruct trace_entry ent;\n\tint rmem_alloc;\n\tunsigned int truesize;\n\tint sk_rcvbuf;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_sock_exceed_buf_limit {\n\tstruct trace_entry ent;\n\tchar name[32];\n\tlong int *sysctl_mem;\n\tlong int allocated;\n\tint sysctl_rmem;\n\tint rmem_alloc;\n\tint sysctl_wmem;\n\tint wmem_alloc;\n\tint wmem_queued;\n\tint kind;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_inet_sock_set_state {\n\tstruct trace_entry ent;\n\tconst void *skaddr;\n\tint oldstate;\n\tint newstate;\n\t__u16 sport;\n\t__u16 dport;\n\t__u16 family;\n\t__u16 protocol;\n\t__u8 saddr[4];\n\t__u8 daddr[4];\n\t__u8 saddr_v6[16];\n\t__u8 daddr_v6[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_inet_sk_error_report {\n\tstruct trace_entry ent;\n\tint error;\n\t__u16 sport;\n\t__u16 dport;\n\t__u16 family;\n\t__u16 protocol;\n\t__u8 saddr[4];\n\t__u8 daddr[4];\n\t__u8 saddr_v6[16];\n\t__u8 daddr_v6[16];\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_sock_rcvqueue_full {};\n\nstruct trace_event_data_offsets_sock_exceed_buf_limit {};\n\nstruct trace_event_data_offsets_inet_sock_set_state {};\n\nstruct trace_event_data_offsets_inet_sk_error_report {};\n\ntypedef void (*btf_trace_sock_rcvqueue_full)(void *, struct sock *, struct sk_buff *);\n\ntypedef void (*btf_trace_sock_exceed_buf_limit)(void *, struct sock *, struct proto *, long int, int);\n\ntypedef void (*btf_trace_inet_sock_set_state)(void *, const struct sock *, const int, const int);\n\ntypedef void (*btf_trace_inet_sk_error_report)(void *, const struct sock *);\n\nstruct trace_event_raw_udp_fail_queue_rcv_skb {\n\tstruct trace_entry ent;\n\tint rc;\n\t__u16 lport;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_udp_fail_queue_rcv_skb {};\n\ntypedef void (*btf_trace_udp_fail_queue_rcv_skb)(void *, int, struct sock *);\n\nstruct trace_event_raw_tcp_event_sk_skb {\n\tstruct trace_entry ent;\n\tconst void *skbaddr;\n\tconst void *skaddr;\n\tint state;\n\t__u16 sport;\n\t__u16 dport;\n\t__u16 family;\n\t__u8 saddr[4];\n\t__u8 daddr[4];\n\t__u8 saddr_v6[16];\n\t__u8 daddr_v6[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_tcp_event_sk {\n\tstruct trace_entry ent;\n\tconst void *skaddr;\n\t__u16 sport;\n\t__u16 dport;\n\t__u16 family;\n\t__u8 saddr[4];\n\t__u8 daddr[4];\n\t__u8 saddr_v6[16];\n\t__u8 daddr_v6[16];\n\t__u64 sock_cookie;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_tcp_retransmit_synack {\n\tstruct trace_entry ent;\n\tconst void *skaddr;\n\tconst void *req;\n\t__u16 sport;\n\t__u16 dport;\n\t__u16 family;\n\t__u8 saddr[4];\n\t__u8 daddr[4];\n\t__u8 saddr_v6[16];\n\t__u8 daddr_v6[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_tcp_probe {\n\tstruct trace_entry ent;\n\t__u8 saddr[28];\n\t__u8 daddr[28];\n\t__u16 sport;\n\t__u16 dport;\n\t__u16 family;\n\t__u32 mark;\n\t__u16 data_len;\n\t__u32 snd_nxt;\n\t__u32 snd_una;\n\t__u32 snd_cwnd;\n\t__u32 ssthresh;\n\t__u32 snd_wnd;\n\t__u32 srtt;\n\t__u32 rcv_wnd;\n\t__u64 sock_cookie;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_tcp_event_skb {\n\tstruct trace_entry ent;\n\tconst void *skbaddr;\n\t__u8 saddr[28];\n\t__u8 daddr[28];\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_tcp_event_sk_skb {};\n\nstruct trace_event_data_offsets_tcp_event_sk {};\n\nstruct trace_event_data_offsets_tcp_retransmit_synack {};\n\nstruct trace_event_data_offsets_tcp_probe {};\n\nstruct trace_event_data_offsets_tcp_event_skb {};\n\ntypedef void (*btf_trace_tcp_retransmit_skb)(void *, const struct sock *, const struct sk_buff *);\n\ntypedef void (*btf_trace_tcp_send_reset)(void *, const struct sock *, const struct sk_buff *);\n\ntypedef void (*btf_trace_tcp_receive_reset)(void *, struct sock *);\n\ntypedef void (*btf_trace_tcp_destroy_sock)(void *, struct sock *);\n\ntypedef void (*btf_trace_tcp_rcv_space_adjust)(void *, struct sock *);\n\ntypedef void (*btf_trace_tcp_retransmit_synack)(void *, const struct sock *, const struct request_sock *);\n\ntypedef void (*btf_trace_tcp_probe)(void *, struct sock *, struct sk_buff *);\n\ntypedef void (*btf_trace_tcp_bad_csum)(void *, const struct sk_buff *);\n\nstruct trace_event_raw_fib_table_lookup {\n\tstruct trace_entry ent;\n\tu32 tb_id;\n\tint err;\n\tint oif;\n\tint iif;\n\tu8 proto;\n\t__u8 tos;\n\t__u8 scope;\n\t__u8 flags;\n\t__u8 src[4];\n\t__u8 dst[4];\n\t__u8 gw4[4];\n\t__u8 gw6[16];\n\tu16 sport;\n\tu16 dport;\n\tu32 __data_loc_name;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_fib_table_lookup {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_fib_table_lookup)(void *, u32, const struct flowi4 *, const struct fib_nh_common *, int);\n\nstruct trace_event_raw_qdisc_dequeue {\n\tstruct trace_entry ent;\n\tstruct Qdisc *qdisc;\n\tconst struct netdev_queue *txq;\n\tint packets;\n\tvoid *skbaddr;\n\tint ifindex;\n\tu32 handle;\n\tu32 parent;\n\tlong unsigned int txq_state;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_qdisc_enqueue {\n\tstruct trace_entry ent;\n\tstruct Qdisc *qdisc;\n\tvoid *skbaddr;\n\tint ifindex;\n\tu32 handle;\n\tu32 parent;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_qdisc_reset {\n\tstruct trace_entry ent;\n\tu32 __data_loc_dev;\n\tu32 __data_loc_kind;\n\tu32 parent;\n\tu32 handle;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_qdisc_destroy {\n\tstruct trace_entry ent;\n\tu32 __data_loc_dev;\n\tu32 __data_loc_kind;\n\tu32 parent;\n\tu32 handle;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_qdisc_create {\n\tstruct trace_entry ent;\n\tu32 __data_loc_dev;\n\tu32 __data_loc_kind;\n\tu32 parent;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_qdisc_dequeue {};\n\nstruct trace_event_data_offsets_qdisc_enqueue {};\n\nstruct trace_event_data_offsets_qdisc_reset {\n\tu32 dev;\n\tu32 kind;\n};\n\nstruct trace_event_data_offsets_qdisc_destroy {\n\tu32 dev;\n\tu32 kind;\n};\n\nstruct trace_event_data_offsets_qdisc_create {\n\tu32 dev;\n\tu32 kind;\n};\n\ntypedef void (*btf_trace_qdisc_dequeue)(void *, struct Qdisc *, const struct netdev_queue *, int, struct sk_buff *);\n\ntypedef void (*btf_trace_qdisc_enqueue)(void *, struct Qdisc *, const struct netdev_queue *, struct sk_buff *);\n\ntypedef void (*btf_trace_qdisc_reset)(void *, struct Qdisc *);\n\ntypedef void (*btf_trace_qdisc_destroy)(void *, struct Qdisc *);\n\ntypedef void (*btf_trace_qdisc_create)(void *, const struct Qdisc_ops *, struct net_device *, u32);\n\nstruct bridge_stp_xstats {\n\t__u64 transition_blk;\n\t__u64 transition_fwd;\n\t__u64 rx_bpdu;\n\t__u64 tx_bpdu;\n\t__u64 rx_tcn;\n\t__u64 tx_tcn;\n};\n\nstruct br_mcast_stats {\n\t__u64 igmp_v1queries[2];\n\t__u64 igmp_v2queries[2];\n\t__u64 igmp_v3queries[2];\n\t__u64 igmp_leaves[2];\n\t__u64 igmp_v1reports[2];\n\t__u64 igmp_v2reports[2];\n\t__u64 igmp_v3reports[2];\n\t__u64 igmp_parse_errors;\n\t__u64 mld_v1queries[2];\n\t__u64 mld_v2queries[2];\n\t__u64 mld_leaves[2];\n\t__u64 mld_v1reports[2];\n\t__u64 mld_v2reports[2];\n\t__u64 mld_parse_errors;\n\t__u64 mcast_bytes[2];\n\t__u64 mcast_packets[2];\n};\n\nstruct br_ip {\n\tunion {\n\t\t__be32 ip4;\n\t\tstruct in6_addr ip6;\n\t} src;\n\tunion {\n\t\t__be32 ip4;\n\t\tstruct in6_addr ip6;\n\t\tunsigned char mac_addr[6];\n\t} dst;\n\t__be16 proto;\n\t__u16 vid;\n};\n\nstruct bridge_id {\n\tunsigned char prio[2];\n\tunsigned char addr[6];\n};\n\ntypedef struct bridge_id bridge_id;\n\nstruct mac_addr {\n\tunsigned char addr[6];\n};\n\ntypedef struct mac_addr mac_addr;\n\ntypedef __u16 port_id;\n\nstruct bridge_mcast_own_query {\n\tstruct timer_list timer;\n\tu32 startup_sent;\n};\n\nstruct bridge_mcast_other_query {\n\tstruct timer_list timer;\n\tlong unsigned int delay_time;\n};\n\nstruct net_bridge_port;\n\nstruct bridge_mcast_querier {\n\tstruct br_ip addr;\n\tstruct net_bridge_port *port;\n};\n\nstruct net_bridge;\n\nstruct net_bridge_vlan_group;\n\nstruct bridge_mcast_stats;\n\nstruct net_bridge_port {\n\tstruct net_bridge *br;\n\tstruct net_device *dev;\n\tstruct list_head list;\n\tlong unsigned int flags;\n\tstruct net_bridge_vlan_group *vlgrp;\n\tstruct net_bridge_port *backup_port;\n\tu8 priority;\n\tu8 state;\n\tu16 port_no;\n\tunsigned char topology_change_ack;\n\tunsigned char config_pending;\n\tport_id port_id;\n\tport_id designated_port;\n\tbridge_id designated_root;\n\tbridge_id designated_bridge;\n\tu32 path_cost;\n\tu32 designated_cost;\n\tlong unsigned int designated_age;\n\tstruct timer_list forward_delay_timer;\n\tstruct timer_list hold_timer;\n\tstruct timer_list message_age_timer;\n\tstruct kobject kobj;\n\tstruct callback_head rcu;\n\tstruct bridge_mcast_own_query ip4_own_query;\n\tstruct timer_list ip4_mc_router_timer;\n\tstruct hlist_node ip4_rlist;\n\tstruct bridge_mcast_own_query ip6_own_query;\n\tstruct timer_list ip6_mc_router_timer;\n\tstruct hlist_node ip6_rlist;\n\tu32 multicast_eht_hosts_limit;\n\tu32 multicast_eht_hosts_cnt;\n\tunsigned char multicast_router;\n\tstruct bridge_mcast_stats *mcast_stats;\n\tstruct hlist_head mglist;\n\tchar sysfs_name[16];\n\tstruct netpoll *np;\n\tint offload_fwd_mark;\n\tu16 group_fwd_mask;\n\tu16 backup_redirected_cnt;\n\tstruct bridge_stp_xstats stp_xstats;\n};\n\nstruct bridge_mcast_stats {\n\tstruct br_mcast_stats mstats;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct net_bridge {\n\tspinlock_t lock;\n\tspinlock_t hash_lock;\n\tstruct hlist_head frame_type_list;\n\tstruct net_device *dev;\n\tlong unsigned int options;\n\t__be16 vlan_proto;\n\tu16 default_pvid;\n\tstruct net_bridge_vlan_group *vlgrp;\n\tstruct rhashtable fdb_hash_tbl;\n\tstruct list_head port_list;\n\tunion {\n\t\tstruct rtable fake_rtable;\n\t\tstruct rt6_info fake_rt6_info;\n\t};\n\tu16 group_fwd_mask;\n\tu16 group_fwd_mask_required;\n\tbridge_id designated_root;\n\tbridge_id bridge_id;\n\tunsigned char topology_change;\n\tunsigned char topology_change_detected;\n\tu16 root_port;\n\tlong unsigned int max_age;\n\tlong unsigned int hello_time;\n\tlong unsigned int forward_delay;\n\tlong unsigned int ageing_time;\n\tlong unsigned int bridge_max_age;\n\tlong unsigned int bridge_hello_time;\n\tlong unsigned int bridge_forward_delay;\n\tlong unsigned int bridge_ageing_time;\n\tu32 root_path_cost;\n\tu8 group_addr[6];\n\tenum {\n\t\tBR_NO_STP = 0,\n\t\tBR_KERNEL_STP = 1,\n\t\tBR_USER_STP = 2,\n\t} stp_enabled;\n\tu32 hash_max;\n\tu32 multicast_last_member_count;\n\tu32 multicast_startup_query_count;\n\tu8 multicast_igmp_version;\n\tu8 multicast_router;\n\tu8 multicast_mld_version;\n\tspinlock_t multicast_lock;\n\tlong unsigned int multicast_last_member_interval;\n\tlong unsigned int multicast_membership_interval;\n\tlong unsigned int multicast_querier_interval;\n\tlong unsigned int multicast_query_interval;\n\tlong unsigned int multicast_query_response_interval;\n\tlong unsigned int multicast_startup_query_interval;\n\tstruct rhashtable mdb_hash_tbl;\n\tstruct rhashtable sg_port_tbl;\n\tstruct hlist_head mcast_gc_list;\n\tstruct hlist_head mdb_list;\n\tstruct hlist_head ip4_mc_router_list;\n\tstruct timer_list ip4_mc_router_timer;\n\tstruct bridge_mcast_other_query ip4_other_query;\n\tstruct bridge_mcast_own_query ip4_own_query;\n\tstruct bridge_mcast_querier ip4_querier;\n\tstruct bridge_mcast_stats *mcast_stats;\n\tstruct hlist_head ip6_mc_router_list;\n\tstruct timer_list ip6_mc_router_timer;\n\tstruct bridge_mcast_other_query ip6_other_query;\n\tstruct bridge_mcast_own_query ip6_own_query;\n\tstruct bridge_mcast_querier ip6_querier;\n\tstruct work_struct mcast_gc_work;\n\tstruct timer_list hello_timer;\n\tstruct timer_list tcn_timer;\n\tstruct timer_list topology_change_timer;\n\tstruct delayed_work gc_work;\n\tstruct kobject *ifobj;\n\tu32 auto_cnt;\n\tint offload_fwd_mark;\n\tstruct hlist_head fdb_list;\n\tstruct hlist_head mrp_list;\n\tstruct hlist_head mep_list;\n};\n\nstruct net_bridge_vlan_group {\n\tstruct rhashtable vlan_hash;\n\tstruct rhashtable tunnel_hash;\n\tstruct list_head vlan_list;\n\tu16 num_vlans;\n\tu16 pvid;\n\tu8 pvid_state;\n};\n\nstruct net_bridge_fdb_key {\n\tmac_addr addr;\n\tu16 vlan_id;\n};\n\nstruct net_bridge_fdb_entry {\n\tstruct rhash_head rhnode;\n\tstruct net_bridge_port *dst;\n\tstruct net_bridge_fdb_key key;\n\tstruct hlist_node fdb_node;\n\tlong unsigned int flags;\n\tlong: 64;\n\tlong: 64;\n\tlong unsigned int updated;\n\tlong unsigned int used;\n\tstruct callback_head rcu;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct trace_event_raw_br_fdb_add {\n\tstruct trace_entry ent;\n\tu8 ndm_flags;\n\tu32 __data_loc_dev;\n\tunsigned char addr[6];\n\tu16 vid;\n\tu16 nlh_flags;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_br_fdb_external_learn_add {\n\tstruct trace_entry ent;\n\tu32 __data_loc_br_dev;\n\tu32 __data_loc_dev;\n\tunsigned char addr[6];\n\tu16 vid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_fdb_delete {\n\tstruct trace_entry ent;\n\tu32 __data_loc_br_dev;\n\tu32 __data_loc_dev;\n\tunsigned char addr[6];\n\tu16 vid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_br_fdb_update {\n\tstruct trace_entry ent;\n\tu32 __data_loc_br_dev;\n\tu32 __data_loc_dev;\n\tunsigned char addr[6];\n\tu16 vid;\n\tlong unsigned int flags;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_br_fdb_add {\n\tu32 dev;\n};\n\nstruct trace_event_data_offsets_br_fdb_external_learn_add {\n\tu32 br_dev;\n\tu32 dev;\n};\n\nstruct trace_event_data_offsets_fdb_delete {\n\tu32 br_dev;\n\tu32 dev;\n};\n\nstruct trace_event_data_offsets_br_fdb_update {\n\tu32 br_dev;\n\tu32 dev;\n};\n\ntypedef void (*btf_trace_br_fdb_add)(void *, struct ndmsg *, struct net_device *, const unsigned char *, u16, u16);\n\ntypedef void (*btf_trace_br_fdb_external_learn_add)(void *, struct net_bridge *, struct net_bridge_port *, const unsigned char *, u16);\n\ntypedef void (*btf_trace_fdb_delete)(void *, struct net_bridge *, struct net_bridge_fdb_entry *);\n\ntypedef void (*btf_trace_br_fdb_update)(void *, struct net_bridge *, struct net_bridge_port *, const unsigned char *, u16, long unsigned int);\n\nstruct trace_event_raw_page_pool_release {\n\tstruct trace_entry ent;\n\tconst struct page_pool *pool;\n\ts32 inflight;\n\tu32 hold;\n\tu32 release;\n\tu64 cnt;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_page_pool_state_release {\n\tstruct trace_entry ent;\n\tconst struct page_pool *pool;\n\tconst struct page *page;\n\tu32 release;\n\tlong unsigned int pfn;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_page_pool_state_hold {\n\tstruct trace_entry ent;\n\tconst struct page_pool *pool;\n\tconst struct page *page;\n\tu32 hold;\n\tlong unsigned int pfn;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_page_pool_update_nid {\n\tstruct trace_entry ent;\n\tconst struct page_pool *pool;\n\tint pool_nid;\n\tint new_nid;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_page_pool_release {};\n\nstruct trace_event_data_offsets_page_pool_state_release {};\n\nstruct trace_event_data_offsets_page_pool_state_hold {};\n\nstruct trace_event_data_offsets_page_pool_update_nid {};\n\ntypedef void (*btf_trace_page_pool_release)(void *, const struct page_pool *, s32, u32, u32);\n\ntypedef void (*btf_trace_page_pool_state_release)(void *, const struct page_pool *, const struct page *, u32);\n\ntypedef void (*btf_trace_page_pool_state_hold)(void *, const struct page_pool *, const struct page *, u32);\n\ntypedef void (*btf_trace_page_pool_update_nid)(void *, const struct page_pool *, int);\n\nstruct trace_event_raw_neigh_create {\n\tstruct trace_entry ent;\n\tu32 family;\n\tu32 __data_loc_dev;\n\tint entries;\n\tu8 created;\n\tu8 gc_exempt;\n\tu8 primary_key4[4];\n\tu8 primary_key6[16];\n\tchar __data[0];\n};\n\nstruct trace_event_raw_neigh_update {\n\tstruct trace_entry ent;\n\tu32 family;\n\tu32 __data_loc_dev;\n\tu8 lladdr[32];\n\tu8 lladdr_len;\n\tu8 flags;\n\tu8 nud_state;\n\tu8 type;\n\tu8 dead;\n\tint refcnt;\n\t__u8 primary_key4[4];\n\t__u8 primary_key6[16];\n\tlong unsigned int confirmed;\n\tlong unsigned int updated;\n\tlong unsigned int used;\n\tu8 new_lladdr[32];\n\tu8 new_state;\n\tu32 update_flags;\n\tu32 pid;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_neigh__update {\n\tstruct trace_entry ent;\n\tu32 family;\n\tu32 __data_loc_dev;\n\tu8 lladdr[32];\n\tu8 lladdr_len;\n\tu8 flags;\n\tu8 nud_state;\n\tu8 type;\n\tu8 dead;\n\tint refcnt;\n\t__u8 primary_key4[4];\n\t__u8 primary_key6[16];\n\tlong unsigned int confirmed;\n\tlong unsigned int updated;\n\tlong unsigned int used;\n\tu32 err;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_neigh_create {\n\tu32 dev;\n};\n\nstruct trace_event_data_offsets_neigh_update {\n\tu32 dev;\n};\n\nstruct trace_event_data_offsets_neigh__update {\n\tu32 dev;\n};\n\ntypedef void (*btf_trace_neigh_create)(void *, struct neigh_table *, struct net_device *, const void *, const struct neighbour *, bool);\n\ntypedef void (*btf_trace_neigh_update)(void *, struct neighbour *, const u8 *, u8, u32, u32);\n\ntypedef void (*btf_trace_neigh_update_done)(void *, struct neighbour *, int);\n\ntypedef void (*btf_trace_neigh_timer_handler)(void *, struct neighbour *, int);\n\ntypedef void (*btf_trace_neigh_event_send_done)(void *, struct neighbour *, int);\n\ntypedef void (*btf_trace_neigh_event_send_dead)(void *, struct neighbour *, int);\n\ntypedef void (*btf_trace_neigh_cleanup_and_release)(void *, struct neighbour *, int);\n\nstruct net_dm_drop_point {\n\t__u8 pc[8];\n\t__u32 count;\n};\n\nstruct net_dm_alert_msg {\n\t__u32 entries;\n\tstruct net_dm_drop_point points[0];\n};\n\nenum {\n\tNET_DM_CMD_UNSPEC = 0,\n\tNET_DM_CMD_ALERT = 1,\n\tNET_DM_CMD_CONFIG = 2,\n\tNET_DM_CMD_START = 3,\n\tNET_DM_CMD_STOP = 4,\n\tNET_DM_CMD_PACKET_ALERT = 5,\n\tNET_DM_CMD_CONFIG_GET = 6,\n\tNET_DM_CMD_CONFIG_NEW = 7,\n\tNET_DM_CMD_STATS_GET = 8,\n\tNET_DM_CMD_STATS_NEW = 9,\n\t_NET_DM_CMD_MAX = 10,\n};\n\nenum net_dm_attr {\n\tNET_DM_ATTR_UNSPEC = 0,\n\tNET_DM_ATTR_ALERT_MODE = 1,\n\tNET_DM_ATTR_PC = 2,\n\tNET_DM_ATTR_SYMBOL = 3,\n\tNET_DM_ATTR_IN_PORT = 4,\n\tNET_DM_ATTR_TIMESTAMP = 5,\n\tNET_DM_ATTR_PROTO = 6,\n\tNET_DM_ATTR_PAYLOAD = 7,\n\tNET_DM_ATTR_PAD = 8,\n\tNET_DM_ATTR_TRUNC_LEN = 9,\n\tNET_DM_ATTR_ORIG_LEN = 10,\n\tNET_DM_ATTR_QUEUE_LEN = 11,\n\tNET_DM_ATTR_STATS = 12,\n\tNET_DM_ATTR_HW_STATS = 13,\n\tNET_DM_ATTR_ORIGIN = 14,\n\tNET_DM_ATTR_HW_TRAP_GROUP_NAME = 15,\n\tNET_DM_ATTR_HW_TRAP_NAME = 16,\n\tNET_DM_ATTR_HW_ENTRIES = 17,\n\tNET_DM_ATTR_HW_ENTRY = 18,\n\tNET_DM_ATTR_HW_TRAP_COUNT = 19,\n\tNET_DM_ATTR_SW_DROPS = 20,\n\tNET_DM_ATTR_HW_DROPS = 21,\n\tNET_DM_ATTR_FLOW_ACTION_COOKIE = 22,\n\t__NET_DM_ATTR_MAX = 23,\n\tNET_DM_ATTR_MAX = 22,\n};\n\nenum net_dm_alert_mode {\n\tNET_DM_ALERT_MODE_SUMMARY = 0,\n\tNET_DM_ALERT_MODE_PACKET = 1,\n};\n\nenum {\n\tNET_DM_ATTR_PORT_NETDEV_IFINDEX = 0,\n\tNET_DM_ATTR_PORT_NETDEV_NAME = 1,\n\t__NET_DM_ATTR_PORT_MAX = 2,\n\tNET_DM_ATTR_PORT_MAX = 1,\n};\n\nenum {\n\tNET_DM_ATTR_STATS_DROPPED = 0,\n\t__NET_DM_ATTR_STATS_MAX = 1,\n\tNET_DM_ATTR_STATS_MAX = 0,\n};\n\nenum net_dm_origin {\n\tNET_DM_ORIGIN_SW = 0,\n\tNET_DM_ORIGIN_HW = 1,\n};\n\nstruct devlink_trap_metadata {\n\tconst char *trap_name;\n\tconst char *trap_group_name;\n\tstruct net_device *input_dev;\n\tconst struct flow_action_cookie *fa_cookie;\n\tenum devlink_trap_type trap_type;\n};\n\nstruct net_dm_stats {\n\tu64 dropped;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct net_dm_hw_entry {\n\tchar trap_name[40];\n\tu32 count;\n};\n\nstruct net_dm_hw_entries {\n\tu32 num_entries;\n\tstruct net_dm_hw_entry entries[0];\n};\n\nstruct per_cpu_dm_data {\n\tspinlock_t lock;\n\tunion {\n\t\tstruct sk_buff *skb;\n\t\tstruct net_dm_hw_entries *hw_entries;\n\t};\n\tstruct sk_buff_head drop_queue;\n\tstruct work_struct dm_alert_work;\n\tstruct timer_list send_timer;\n\tstruct net_dm_stats stats;\n};\n\nstruct dm_hw_stat_delta {\n\tstruct net_device *dev;\n\tlong unsigned int last_rx;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n\tlong unsigned int last_drop_val;\n};\n\nstruct net_dm_alert_ops {\n\tvoid (*kfree_skb_probe)(void *, struct sk_buff *, void *);\n\tvoid (*napi_poll_probe)(void *, struct napi_struct *, int, int);\n\tvoid (*work_item_func)(struct work_struct *);\n\tvoid (*hw_work_item_func)(struct work_struct *);\n\tvoid (*hw_trap_probe)(void *, const struct devlink *, struct sk_buff *, const struct devlink_trap_metadata *);\n};\n\nstruct net_dm_skb_cb {\n\tunion {\n\t\tstruct devlink_trap_metadata *hw_metadata;\n\t\tvoid *pc;\n\t};\n};\n\nstruct update_classid_context {\n\tu32 classid;\n\tunsigned int batch;\n};\n\nstruct rtnexthop {\n\tshort unsigned int rtnh_len;\n\tunsigned char rtnh_flags;\n\tunsigned char rtnh_hops;\n\tint rtnh_ifindex;\n};\n\nstruct lwtunnel_encap_ops {\n\tint (*build_state)(struct net *, struct nlattr *, unsigned int, const void *, struct lwtunnel_state **, struct netlink_ext_ack *);\n\tvoid (*destroy_state)(struct lwtunnel_state *);\n\tint (*output)(struct net *, struct sock *, struct sk_buff *);\n\tint (*input)(struct sk_buff *);\n\tint (*fill_encap)(struct sk_buff *, struct lwtunnel_state *);\n\tint (*get_encap_size)(struct lwtunnel_state *);\n\tint (*cmp_encap)(struct lwtunnel_state *, struct lwtunnel_state *);\n\tint (*xmit)(struct sk_buff *);\n\tstruct module *owner;\n};\n\nenum {\n\tLWT_BPF_PROG_UNSPEC = 0,\n\tLWT_BPF_PROG_FD = 1,\n\tLWT_BPF_PROG_NAME = 2,\n\t__LWT_BPF_PROG_MAX = 3,\n};\n\nenum {\n\tLWT_BPF_UNSPEC = 0,\n\tLWT_BPF_IN = 1,\n\tLWT_BPF_OUT = 2,\n\tLWT_BPF_XMIT = 3,\n\tLWT_BPF_XMIT_HEADROOM = 4,\n\t__LWT_BPF_MAX = 5,\n};\n\nenum {\n\tLWTUNNEL_XMIT_DONE = 0,\n\tLWTUNNEL_XMIT_CONTINUE = 1,\n};\n\nstruct bpf_lwt_prog {\n\tstruct bpf_prog *prog;\n\tchar *name;\n};\n\nstruct bpf_lwt {\n\tstruct bpf_lwt_prog in;\n\tstruct bpf_lwt_prog out;\n\tstruct bpf_lwt_prog xmit;\n\tint family;\n};\n\nstruct dst_cache_pcpu {\n\tlong unsigned int refresh_ts;\n\tstruct dst_entry *dst;\n\tu32 cookie;\n\tunion {\n\t\tstruct in_addr in_saddr;\n\t\tstruct in6_addr in6_saddr;\n\t};\n};\n\nenum devlink_command {\n\tDEVLINK_CMD_UNSPEC = 0,\n\tDEVLINK_CMD_GET = 1,\n\tDEVLINK_CMD_SET = 2,\n\tDEVLINK_CMD_NEW = 3,\n\tDEVLINK_CMD_DEL = 4,\n\tDEVLINK_CMD_PORT_GET = 5,\n\tDEVLINK_CMD_PORT_SET = 6,\n\tDEVLINK_CMD_PORT_NEW = 7,\n\tDEVLINK_CMD_PORT_DEL = 8,\n\tDEVLINK_CMD_PORT_SPLIT = 9,\n\tDEVLINK_CMD_PORT_UNSPLIT = 10,\n\tDEVLINK_CMD_SB_GET = 11,\n\tDEVLINK_CMD_SB_SET = 12,\n\tDEVLINK_CMD_SB_NEW = 13,\n\tDEVLINK_CMD_SB_DEL = 14,\n\tDEVLINK_CMD_SB_POOL_GET = 15,\n\tDEVLINK_CMD_SB_POOL_SET = 16,\n\tDEVLINK_CMD_SB_POOL_NEW = 17,\n\tDEVLINK_CMD_SB_POOL_DEL = 18,\n\tDEVLINK_CMD_SB_PORT_POOL_GET = 19,\n\tDEVLINK_CMD_SB_PORT_POOL_SET = 20,\n\tDEVLINK_CMD_SB_PORT_POOL_NEW = 21,\n\tDEVLINK_CMD_SB_PORT_POOL_DEL = 22,\n\tDEVLINK_CMD_SB_TC_POOL_BIND_GET = 23,\n\tDEVLINK_CMD_SB_TC_POOL_BIND_SET = 24,\n\tDEVLINK_CMD_SB_TC_POOL_BIND_NEW = 25,\n\tDEVLINK_CMD_SB_TC_POOL_BIND_DEL = 26,\n\tDEVLINK_CMD_SB_OCC_SNAPSHOT = 27,\n\tDEVLINK_CMD_SB_OCC_MAX_CLEAR = 28,\n\tDEVLINK_CMD_ESWITCH_GET = 29,\n\tDEVLINK_CMD_ESWITCH_SET = 30,\n\tDEVLINK_CMD_DPIPE_TABLE_GET = 31,\n\tDEVLINK_CMD_DPIPE_ENTRIES_GET = 32,\n\tDEVLINK_CMD_DPIPE_HEADERS_GET = 33,\n\tDEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET = 34,\n\tDEVLINK_CMD_RESOURCE_SET = 35,\n\tDEVLINK_CMD_RESOURCE_DUMP = 36,\n\tDEVLINK_CMD_RELOAD = 37,\n\tDEVLINK_CMD_PARAM_GET = 38,\n\tDEVLINK_CMD_PARAM_SET = 39,\n\tDEVLINK_CMD_PARAM_NEW = 40,\n\tDEVLINK_CMD_PARAM_DEL = 41,\n\tDEVLINK_CMD_REGION_GET = 42,\n\tDEVLINK_CMD_REGION_SET = 43,\n\tDEVLINK_CMD_REGION_NEW = 44,\n\tDEVLINK_CMD_REGION_DEL = 45,\n\tDEVLINK_CMD_REGION_READ = 46,\n\tDEVLINK_CMD_PORT_PARAM_GET = 47,\n\tDEVLINK_CMD_PORT_PARAM_SET = 48,\n\tDEVLINK_CMD_PORT_PARAM_NEW = 49,\n\tDEVLINK_CMD_PORT_PARAM_DEL = 50,\n\tDEVLINK_CMD_INFO_GET = 51,\n\tDEVLINK_CMD_HEALTH_REPORTER_GET = 52,\n\tDEVLINK_CMD_HEALTH_REPORTER_SET = 53,\n\tDEVLINK_CMD_HEALTH_REPORTER_RECOVER = 54,\n\tDEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE = 55,\n\tDEVLINK_CMD_HEALTH_REPORTER_DUMP_GET = 56,\n\tDEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR = 57,\n\tDEVLINK_CMD_FLASH_UPDATE = 58,\n\tDEVLINK_CMD_FLASH_UPDATE_END = 59,\n\tDEVLINK_CMD_FLASH_UPDATE_STATUS = 60,\n\tDEVLINK_CMD_TRAP_GET = 61,\n\tDEVLINK_CMD_TRAP_SET = 62,\n\tDEVLINK_CMD_TRAP_NEW = 63,\n\tDEVLINK_CMD_TRAP_DEL = 64,\n\tDEVLINK_CMD_TRAP_GROUP_GET = 65,\n\tDEVLINK_CMD_TRAP_GROUP_SET = 66,\n\tDEVLINK_CMD_TRAP_GROUP_NEW = 67,\n\tDEVLINK_CMD_TRAP_GROUP_DEL = 68,\n\tDEVLINK_CMD_TRAP_POLICER_GET = 69,\n\tDEVLINK_CMD_TRAP_POLICER_SET = 70,\n\tDEVLINK_CMD_TRAP_POLICER_NEW = 71,\n\tDEVLINK_CMD_TRAP_POLICER_DEL = 72,\n\tDEVLINK_CMD_HEALTH_REPORTER_TEST = 73,\n\tDEVLINK_CMD_RATE_GET = 74,\n\tDEVLINK_CMD_RATE_SET = 75,\n\tDEVLINK_CMD_RATE_NEW = 76,\n\tDEVLINK_CMD_RATE_DEL = 77,\n\t__DEVLINK_CMD_MAX = 78,\n\tDEVLINK_CMD_MAX = 77,\n};\n\nenum devlink_eswitch_mode {\n\tDEVLINK_ESWITCH_MODE_LEGACY = 0,\n\tDEVLINK_ESWITCH_MODE_SWITCHDEV = 1,\n};\n\nenum {\n\tDEVLINK_ATTR_STATS_RX_PACKETS = 0,\n\tDEVLINK_ATTR_STATS_RX_BYTES = 1,\n\tDEVLINK_ATTR_STATS_RX_DROPPED = 2,\n\t__DEVLINK_ATTR_STATS_MAX = 3,\n\tDEVLINK_ATTR_STATS_MAX = 2,\n};\n\nenum {\n\tDEVLINK_FLASH_OVERWRITE_SETTINGS_BIT = 0,\n\tDEVLINK_FLASH_OVERWRITE_IDENTIFIERS_BIT = 1,\n\t__DEVLINK_FLASH_OVERWRITE_MAX_BIT = 2,\n\tDEVLINK_FLASH_OVERWRITE_MAX_BIT = 1,\n};\n\nenum {\n\tDEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT = 0,\n\tDEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE = 1,\n};\n\nenum devlink_attr {\n\tDEVLINK_ATTR_UNSPEC = 0,\n\tDEVLINK_ATTR_BUS_NAME = 1,\n\tDEVLINK_ATTR_DEV_NAME = 2,\n\tDEVLINK_ATTR_PORT_INDEX = 3,\n\tDEVLINK_ATTR_PORT_TYPE = 4,\n\tDEVLINK_ATTR_PORT_DESIRED_TYPE = 5,\n\tDEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6,\n\tDEVLINK_ATTR_PORT_NETDEV_NAME = 7,\n\tDEVLINK_ATTR_PORT_IBDEV_NAME = 8,\n\tDEVLINK_ATTR_PORT_SPLIT_COUNT = 9,\n\tDEVLINK_ATTR_PORT_SPLIT_GROUP = 10,\n\tDEVLINK_ATTR_SB_INDEX = 11,\n\tDEVLINK_ATTR_SB_SIZE = 12,\n\tDEVLINK_ATTR_SB_INGRESS_POOL_COUNT = 13,\n\tDEVLINK_ATTR_SB_EGRESS_POOL_COUNT = 14,\n\tDEVLINK_ATTR_SB_INGRESS_TC_COUNT = 15,\n\tDEVLINK_ATTR_SB_EGRESS_TC_COUNT = 16,\n\tDEVLINK_ATTR_SB_POOL_INDEX = 17,\n\tDEVLINK_ATTR_SB_POOL_TYPE = 18,\n\tDEVLINK_ATTR_SB_POOL_SIZE = 19,\n\tDEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE = 20,\n\tDEVLINK_ATTR_SB_THRESHOLD = 21,\n\tDEVLINK_ATTR_SB_TC_INDEX = 22,\n\tDEVLINK_ATTR_SB_OCC_CUR = 23,\n\tDEVLINK_ATTR_SB_OCC_MAX = 24,\n\tDEVLINK_ATTR_ESWITCH_MODE = 25,\n\tDEVLINK_ATTR_ESWITCH_INLINE_MODE = 26,\n\tDEVLINK_ATTR_DPIPE_TABLES = 27,\n\tDEVLINK_ATTR_DPIPE_TABLE = 28,\n\tDEVLINK_ATTR_DPIPE_TABLE_NAME = 29,\n\tDEVLINK_ATTR_DPIPE_TABLE_SIZE = 30,\n\tDEVLINK_ATTR_DPIPE_TABLE_MATCHES = 31,\n\tDEVLINK_ATTR_DPIPE_TABLE_ACTIONS = 32,\n\tDEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED = 33,\n\tDEVLINK_ATTR_DPIPE_ENTRIES = 34,\n\tDEVLINK_ATTR_DPIPE_ENTRY = 35,\n\tDEVLINK_ATTR_DPIPE_ENTRY_INDEX = 36,\n\tDEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES = 37,\n\tDEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES = 38,\n\tDEVLINK_ATTR_DPIPE_ENTRY_COUNTER = 39,\n\tDEVLINK_ATTR_DPIPE_MATCH = 40,\n\tDEVLINK_ATTR_DPIPE_MATCH_VALUE = 41,\n\tDEVLINK_ATTR_DPIPE_MATCH_TYPE = 42,\n\tDEVLINK_ATTR_DPIPE_ACTION = 43,\n\tDEVLINK_ATTR_DPIPE_ACTION_VALUE = 44,\n\tDEVLINK_ATTR_DPIPE_ACTION_TYPE = 45,\n\tDEVLINK_ATTR_DPIPE_VALUE = 46,\n\tDEVLINK_ATTR_DPIPE_VALUE_MASK = 47,\n\tDEVLINK_ATTR_DPIPE_VALUE_MAPPING = 48,\n\tDEVLINK_ATTR_DPIPE_HEADERS = 49,\n\tDEVLINK_ATTR_DPIPE_HEADER = 50,\n\tDEVLINK_ATTR_DPIPE_HEADER_NAME = 51,\n\tDEVLINK_ATTR_DPIPE_HEADER_ID = 52,\n\tDEVLINK_ATTR_DPIPE_HEADER_FIELDS = 53,\n\tDEVLINK_ATTR_DPIPE_HEADER_GLOBAL = 54,\n\tDEVLINK_ATTR_DPIPE_HEADER_INDEX = 55,\n\tDEVLINK_ATTR_DPIPE_FIELD = 56,\n\tDEVLINK_ATTR_DPIPE_FIELD_NAME = 57,\n\tDEVLINK_ATTR_DPIPE_FIELD_ID = 58,\n\tDEVLINK_ATTR_DPIPE_FIELD_BITWIDTH = 59,\n\tDEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE = 60,\n\tDEVLINK_ATTR_PAD = 61,\n\tDEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62,\n\tDEVLINK_ATTR_RESOURCE_LIST = 63,\n\tDEVLINK_ATTR_RESOURCE = 64,\n\tDEVLINK_ATTR_RESOURCE_NAME = 65,\n\tDEVLINK_ATTR_RESOURCE_ID = 66,\n\tDEVLINK_ATTR_RESOURCE_SIZE = 67,\n\tDEVLINK_ATTR_RESOURCE_SIZE_NEW = 68,\n\tDEVLINK_ATTR_RESOURCE_SIZE_VALID = 69,\n\tDEVLINK_ATTR_RESOURCE_SIZE_MIN = 70,\n\tDEVLINK_ATTR_RESOURCE_SIZE_MAX = 71,\n\tDEVLINK_ATTR_RESOURCE_SIZE_GRAN = 72,\n\tDEVLINK_ATTR_RESOURCE_UNIT = 73,\n\tDEVLINK_ATTR_RESOURCE_OCC = 74,\n\tDEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID = 75,\n\tDEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS = 76,\n\tDEVLINK_ATTR_PORT_FLAVOUR = 77,\n\tDEVLINK_ATTR_PORT_NUMBER = 78,\n\tDEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER = 79,\n\tDEVLINK_ATTR_PARAM = 80,\n\tDEVLINK_ATTR_PARAM_NAME = 81,\n\tDEVLINK_ATTR_PARAM_GENERIC = 82,\n\tDEVLINK_ATTR_PARAM_TYPE = 83,\n\tDEVLINK_ATTR_PARAM_VALUES_LIST = 84,\n\tDEVLINK_ATTR_PARAM_VALUE = 85,\n\tDEVLINK_ATTR_PARAM_VALUE_DATA = 86,\n\tDEVLINK_ATTR_PARAM_VALUE_CMODE = 87,\n\tDEVLINK_ATTR_REGION_NAME = 88,\n\tDEVLINK_ATTR_REGION_SIZE = 89,\n\tDEVLINK_ATTR_REGION_SNAPSHOTS = 90,\n\tDEVLINK_ATTR_REGION_SNAPSHOT = 91,\n\tDEVLINK_ATTR_REGION_SNAPSHOT_ID = 92,\n\tDEVLINK_ATTR_REGION_CHUNKS = 93,\n\tDEVLINK_ATTR_REGION_CHUNK = 94,\n\tDEVLINK_ATTR_REGION_CHUNK_DATA = 95,\n\tDEVLINK_ATTR_REGION_CHUNK_ADDR = 96,\n\tDEVLINK_ATTR_REGION_CHUNK_LEN = 97,\n\tDEVLINK_ATTR_INFO_DRIVER_NAME = 98,\n\tDEVLINK_ATTR_INFO_SERIAL_NUMBER = 99,\n\tDEVLINK_ATTR_INFO_VERSION_FIXED = 100,\n\tDEVLINK_ATTR_INFO_VERSION_RUNNING = 101,\n\tDEVLINK_ATTR_INFO_VERSION_STORED = 102,\n\tDEVLINK_ATTR_INFO_VERSION_NAME = 103,\n\tDEVLINK_ATTR_INFO_VERSION_VALUE = 104,\n\tDEVLINK_ATTR_SB_POOL_CELL_SIZE = 105,\n\tDEVLINK_ATTR_FMSG = 106,\n\tDEVLINK_ATTR_FMSG_OBJ_NEST_START = 107,\n\tDEVLINK_ATTR_FMSG_PAIR_NEST_START = 108,\n\tDEVLINK_ATTR_FMSG_ARR_NEST_START = 109,\n\tDEVLINK_ATTR_FMSG_NEST_END = 110,\n\tDEVLINK_ATTR_FMSG_OBJ_NAME = 111,\n\tDEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE = 112,\n\tDEVLINK_ATTR_FMSG_OBJ_VALUE_DATA = 113,\n\tDEVLINK_ATTR_HEALTH_REPORTER = 114,\n\tDEVLINK_ATTR_HEALTH_REPORTER_NAME = 115,\n\tDEVLINK_ATTR_HEALTH_REPORTER_STATE = 116,\n\tDEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT = 117,\n\tDEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT = 118,\n\tDEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS = 119,\n\tDEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD = 120,\n\tDEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER = 121,\n\tDEVLINK_ATTR_FLASH_UPDATE_FILE_NAME = 122,\n\tDEVLINK_ATTR_FLASH_UPDATE_COMPONENT = 123,\n\tDEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG = 124,\n\tDEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE = 125,\n\tDEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL = 126,\n\tDEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127,\n\tDEVLINK_ATTR_PORT_PCI_VF_NUMBER = 128,\n\tDEVLINK_ATTR_STATS = 129,\n\tDEVLINK_ATTR_TRAP_NAME = 130,\n\tDEVLINK_ATTR_TRAP_ACTION = 131,\n\tDEVLINK_ATTR_TRAP_TYPE = 132,\n\tDEVLINK_ATTR_TRAP_GENERIC = 133,\n\tDEVLINK_ATTR_TRAP_METADATA = 134,\n\tDEVLINK_ATTR_TRAP_GROUP_NAME = 135,\n\tDEVLINK_ATTR_RELOAD_FAILED = 136,\n\tDEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS = 137,\n\tDEVLINK_ATTR_NETNS_FD = 138,\n\tDEVLINK_ATTR_NETNS_PID = 139,\n\tDEVLINK_ATTR_NETNS_ID = 140,\n\tDEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP = 141,\n\tDEVLINK_ATTR_TRAP_POLICER_ID = 142,\n\tDEVLINK_ATTR_TRAP_POLICER_RATE = 143,\n\tDEVLINK_ATTR_TRAP_POLICER_BURST = 144,\n\tDEVLINK_ATTR_PORT_FUNCTION = 145,\n\tDEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER = 146,\n\tDEVLINK_ATTR_PORT_LANES = 147,\n\tDEVLINK_ATTR_PORT_SPLITTABLE = 148,\n\tDEVLINK_ATTR_PORT_EXTERNAL = 149,\n\tDEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150,\n\tDEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT = 151,\n\tDEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK = 152,\n\tDEVLINK_ATTR_RELOAD_ACTION = 153,\n\tDEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED = 154,\n\tDEVLINK_ATTR_RELOAD_LIMITS = 155,\n\tDEVLINK_ATTR_DEV_STATS = 156,\n\tDEVLINK_ATTR_RELOAD_STATS = 157,\n\tDEVLINK_ATTR_RELOAD_STATS_ENTRY = 158,\n\tDEVLINK_ATTR_RELOAD_STATS_LIMIT = 159,\n\tDEVLINK_ATTR_RELOAD_STATS_VALUE = 160,\n\tDEVLINK_ATTR_REMOTE_RELOAD_STATS = 161,\n\tDEVLINK_ATTR_RELOAD_ACTION_INFO = 162,\n\tDEVLINK_ATTR_RELOAD_ACTION_STATS = 163,\n\tDEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164,\n\tDEVLINK_ATTR_RATE_TYPE = 165,\n\tDEVLINK_ATTR_RATE_TX_SHARE = 166,\n\tDEVLINK_ATTR_RATE_TX_MAX = 167,\n\tDEVLINK_ATTR_RATE_NODE_NAME = 168,\n\tDEVLINK_ATTR_RATE_PARENT_NODE_NAME = 169,\n\t__DEVLINK_ATTR_MAX = 170,\n\tDEVLINK_ATTR_MAX = 169,\n};\n\nenum devlink_dpipe_match_type {\n\tDEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT = 0,\n};\n\nenum devlink_dpipe_action_type {\n\tDEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY = 0,\n};\n\nenum devlink_dpipe_field_ethernet_id {\n\tDEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC = 0,\n};\n\nenum devlink_dpipe_field_ipv4_id {\n\tDEVLINK_DPIPE_FIELD_IPV4_DST_IP = 0,\n};\n\nenum devlink_dpipe_field_ipv6_id {\n\tDEVLINK_DPIPE_FIELD_IPV6_DST_IP = 0,\n};\n\nenum devlink_dpipe_header_id {\n\tDEVLINK_DPIPE_HEADER_ETHERNET = 0,\n\tDEVLINK_DPIPE_HEADER_IPV4 = 1,\n\tDEVLINK_DPIPE_HEADER_IPV6 = 2,\n};\n\nenum devlink_resource_unit {\n\tDEVLINK_RESOURCE_UNIT_ENTRY = 0,\n};\n\nenum devlink_port_function_attr {\n\tDEVLINK_PORT_FUNCTION_ATTR_UNSPEC = 0,\n\tDEVLINK_PORT_FUNCTION_ATTR_HW_ADDR = 1,\n\tDEVLINK_PORT_FN_ATTR_STATE = 2,\n\tDEVLINK_PORT_FN_ATTR_OPSTATE = 3,\n\t__DEVLINK_PORT_FUNCTION_ATTR_MAX = 4,\n\tDEVLINK_PORT_FUNCTION_ATTR_MAX = 3,\n};\n\nstruct devlink_dpipe_match {\n\tenum devlink_dpipe_match_type type;\n\tunsigned int header_index;\n\tstruct devlink_dpipe_header *header;\n\tunsigned int field_id;\n};\n\nstruct devlink_dpipe_action {\n\tenum devlink_dpipe_action_type type;\n\tunsigned int header_index;\n\tstruct devlink_dpipe_header *header;\n\tunsigned int field_id;\n};\n\nstruct devlink_dpipe_value {\n\tunion {\n\t\tstruct devlink_dpipe_action *action;\n\t\tstruct devlink_dpipe_match *match;\n\t};\n\tunsigned int mapping_value;\n\tbool mapping_valid;\n\tunsigned int value_size;\n\tvoid *value;\n\tvoid *mask;\n};\n\nstruct devlink_dpipe_entry {\n\tu64 index;\n\tstruct devlink_dpipe_value *match_values;\n\tunsigned int match_values_count;\n\tstruct devlink_dpipe_value *action_values;\n\tunsigned int action_values_count;\n\tu64 counter;\n\tbool counter_valid;\n};\n\nstruct devlink_dpipe_dump_ctx {\n\tstruct genl_info *info;\n\tenum devlink_command cmd;\n\tstruct sk_buff *skb;\n\tstruct nlattr *nest;\n\tvoid *hdr;\n};\n\nstruct devlink_dpipe_table_ops;\n\nstruct devlink_dpipe_table {\n\tvoid *priv;\n\tstruct list_head list;\n\tconst char *name;\n\tbool counters_enabled;\n\tbool counter_control_extern;\n\tbool resource_valid;\n\tu64 resource_id;\n\tu64 resource_units;\n\tstruct devlink_dpipe_table_ops *table_ops;\n\tstruct callback_head rcu;\n};\n\nstruct devlink_dpipe_table_ops {\n\tint (*actions_dump)(void *, struct sk_buff *);\n\tint (*matches_dump)(void *, struct sk_buff *);\n\tint (*entries_dump)(void *, bool, struct devlink_dpipe_dump_ctx *);\n\tint (*counters_set_update)(void *, bool);\n\tu64 (*size_get)(void *);\n};\n\nstruct devlink_resource_size_params {\n\tu64 size_min;\n\tu64 size_max;\n\tu64 size_granularity;\n\tenum devlink_resource_unit unit;\n};\n\ntypedef u64 devlink_resource_occ_get_t(void *);\n\nstruct devlink_resource {\n\tconst char *name;\n\tu64 id;\n\tu64 size;\n\tu64 size_new;\n\tbool size_valid;\n\tstruct devlink_resource *parent;\n\tstruct devlink_resource_size_params size_params;\n\tstruct list_head list;\n\tstruct list_head resource_list;\n\tdevlink_resource_occ_get_t *occ_get;\n\tvoid *occ_get_priv;\n};\n\nenum devlink_param_type {\n\tDEVLINK_PARAM_TYPE_U8 = 0,\n\tDEVLINK_PARAM_TYPE_U16 = 1,\n\tDEVLINK_PARAM_TYPE_U32 = 2,\n\tDEVLINK_PARAM_TYPE_STRING = 3,\n\tDEVLINK_PARAM_TYPE_BOOL = 4,\n};\n\nstruct devlink_flash_notify {\n\tconst char *status_msg;\n\tconst char *component;\n\tlong unsigned int done;\n\tlong unsigned int total;\n\tlong unsigned int timeout;\n};\n\nstruct devlink_param {\n\tu32 id;\n\tconst char *name;\n\tbool generic;\n\tenum devlink_param_type type;\n\tlong unsigned int supported_cmodes;\n\tint (*get)(struct devlink *, u32, struct devlink_param_gset_ctx *);\n\tint (*set)(struct devlink *, u32, struct devlink_param_gset_ctx *);\n\tint (*validate)(struct devlink *, u32, union devlink_param_value, struct netlink_ext_ack *);\n};\n\nstruct devlink_param_item {\n\tstruct list_head list;\n\tconst struct devlink_param *param;\n\tunion devlink_param_value driverinit_value;\n\tbool driverinit_value_valid;\n\tbool published;\n};\n\nenum devlink_param_generic_id {\n\tDEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET = 0,\n\tDEVLINK_PARAM_GENERIC_ID_MAX_MACS = 1,\n\tDEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV = 2,\n\tDEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT = 3,\n\tDEVLINK_PARAM_GENERIC_ID_IGNORE_ARI = 4,\n\tDEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX = 5,\n\tDEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN = 6,\n\tDEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY = 7,\n\tDEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE = 8,\n\tDEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE = 9,\n\tDEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET = 10,\n\t__DEVLINK_PARAM_GENERIC_ID_MAX = 11,\n\tDEVLINK_PARAM_GENERIC_ID_MAX = 10,\n};\n\nstruct devlink_region_ops {\n\tconst char *name;\n\tvoid (*destructor)(const void *);\n\tint (*snapshot)(struct devlink *, const struct devlink_region_ops *, struct netlink_ext_ack *, u8 **);\n\tvoid *priv;\n};\n\nstruct devlink_port_region_ops {\n\tconst char *name;\n\tvoid (*destructor)(const void *);\n\tint (*snapshot)(struct devlink_port *, const struct devlink_port_region_ops *, struct netlink_ext_ack *, u8 **);\n\tvoid *priv;\n};\n\nenum devlink_health_reporter_state {\n\tDEVLINK_HEALTH_REPORTER_STATE_HEALTHY = 0,\n\tDEVLINK_HEALTH_REPORTER_STATE_ERROR = 1,\n};\n\nstruct devlink_health_reporter;\n\nstruct devlink_fmsg;\n\nstruct devlink_health_reporter_ops {\n\tchar *name;\n\tint (*recover)(struct devlink_health_reporter *, void *, struct netlink_ext_ack *);\n\tint (*dump)(struct devlink_health_reporter *, struct devlink_fmsg *, void *, struct netlink_ext_ack *);\n\tint (*diagnose)(struct devlink_health_reporter *, struct devlink_fmsg *, struct netlink_ext_ack *);\n\tint (*test)(struct devlink_health_reporter *, struct netlink_ext_ack *);\n};\n\nstruct devlink_health_reporter {\n\tstruct list_head list;\n\tvoid *priv;\n\tconst struct devlink_health_reporter_ops *ops;\n\tstruct devlink *devlink;\n\tstruct devlink_port *devlink_port;\n\tstruct devlink_fmsg *dump_fmsg;\n\tstruct mutex dump_lock;\n\tu64 graceful_period;\n\tbool auto_recover;\n\tbool auto_dump;\n\tu8 health_state;\n\tu64 dump_ts;\n\tu64 dump_real_ts;\n\tu64 error_count;\n\tu64 recovery_count;\n\tu64 last_recovery_ts;\n\trefcount_t refcount;\n};\n\nstruct devlink_fmsg {\n\tstruct list_head item_list;\n\tbool putting_binary;\n};\n\nenum devlink_trap_generic_id {\n\tDEVLINK_TRAP_GENERIC_ID_SMAC_MC = 0,\n\tDEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH = 1,\n\tDEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER = 2,\n\tDEVLINK_TRAP_GENERIC_ID_INGRESS_STP_FILTER = 3,\n\tDEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST = 4,\n\tDEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER = 5,\n\tDEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE = 6,\n\tDEVLINK_TRAP_GENERIC_ID_TTL_ERROR = 7,\n\tDEVLINK_TRAP_GENERIC_ID_TAIL_DROP = 8,\n\tDEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET = 9,\n\tDEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC = 10,\n\tDEVLINK_TRAP_GENERIC_ID_DIP_LB = 11,\n\tDEVLINK_TRAP_GENERIC_ID_SIP_MC = 12,\n\tDEVLINK_TRAP_GENERIC_ID_SIP_LB = 13,\n\tDEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR = 14,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC = 15,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE = 16,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE = 17,\n\tDEVLINK_TRAP_GENERIC_ID_MTU_ERROR = 18,\n\tDEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH = 19,\n\tDEVLINK_TRAP_GENERIC_ID_RPF = 20,\n\tDEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE = 21,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS = 22,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS = 23,\n\tDEVLINK_TRAP_GENERIC_ID_NON_ROUTABLE = 24,\n\tDEVLINK_TRAP_GENERIC_ID_DECAP_ERROR = 25,\n\tDEVLINK_TRAP_GENERIC_ID_OVERLAY_SMAC_MC = 26,\n\tDEVLINK_TRAP_GENERIC_ID_INGRESS_FLOW_ACTION_DROP = 27,\n\tDEVLINK_TRAP_GENERIC_ID_EGRESS_FLOW_ACTION_DROP = 28,\n\tDEVLINK_TRAP_GENERIC_ID_STP = 29,\n\tDEVLINK_TRAP_GENERIC_ID_LACP = 30,\n\tDEVLINK_TRAP_GENERIC_ID_LLDP = 31,\n\tDEVLINK_TRAP_GENERIC_ID_IGMP_QUERY = 32,\n\tDEVLINK_TRAP_GENERIC_ID_IGMP_V1_REPORT = 33,\n\tDEVLINK_TRAP_GENERIC_ID_IGMP_V2_REPORT = 34,\n\tDEVLINK_TRAP_GENERIC_ID_IGMP_V3_REPORT = 35,\n\tDEVLINK_TRAP_GENERIC_ID_IGMP_V2_LEAVE = 36,\n\tDEVLINK_TRAP_GENERIC_ID_MLD_QUERY = 37,\n\tDEVLINK_TRAP_GENERIC_ID_MLD_V1_REPORT = 38,\n\tDEVLINK_TRAP_GENERIC_ID_MLD_V2_REPORT = 39,\n\tDEVLINK_TRAP_GENERIC_ID_MLD_V1_DONE = 40,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_DHCP = 41,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_DHCP = 42,\n\tDEVLINK_TRAP_GENERIC_ID_ARP_REQUEST = 43,\n\tDEVLINK_TRAP_GENERIC_ID_ARP_RESPONSE = 44,\n\tDEVLINK_TRAP_GENERIC_ID_ARP_OVERLAY = 45,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_NEIGH_SOLICIT = 46,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_NEIGH_ADVERT = 47,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_BFD = 48,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_BFD = 49,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_OSPF = 50,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_OSPF = 51,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_BGP = 52,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_BGP = 53,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_VRRP = 54,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_VRRP = 55,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_PIM = 56,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_PIM = 57,\n\tDEVLINK_TRAP_GENERIC_ID_UC_LB = 58,\n\tDEVLINK_TRAP_GENERIC_ID_LOCAL_ROUTE = 59,\n\tDEVLINK_TRAP_GENERIC_ID_EXTERNAL_ROUTE = 60,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_UC_DIP_LINK_LOCAL_SCOPE = 61,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_DIP_ALL_NODES = 62,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_DIP_ALL_ROUTERS = 63,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_ROUTER_SOLICIT = 64,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_ROUTER_ADVERT = 65,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_REDIRECT = 66,\n\tDEVLINK_TRAP_GENERIC_ID_IPV4_ROUTER_ALERT = 67,\n\tDEVLINK_TRAP_GENERIC_ID_IPV6_ROUTER_ALERT = 68,\n\tDEVLINK_TRAP_GENERIC_ID_PTP_EVENT = 69,\n\tDEVLINK_TRAP_GENERIC_ID_PTP_GENERAL = 70,\n\tDEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_SAMPLE = 71,\n\tDEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_TRAP = 72,\n\tDEVLINK_TRAP_GENERIC_ID_EARLY_DROP = 73,\n\tDEVLINK_TRAP_GENERIC_ID_VXLAN_PARSING = 74,\n\tDEVLINK_TRAP_GENERIC_ID_LLC_SNAP_PARSING = 75,\n\tDEVLINK_TRAP_GENERIC_ID_VLAN_PARSING = 76,\n\tDEVLINK_TRAP_GENERIC_ID_PPPOE_PPP_PARSING = 77,\n\tDEVLINK_TRAP_GENERIC_ID_MPLS_PARSING = 78,\n\tDEVLINK_TRAP_GENERIC_ID_ARP_PARSING = 79,\n\tDEVLINK_TRAP_GENERIC_ID_IP_1_PARSING = 80,\n\tDEVLINK_TRAP_GENERIC_ID_IP_N_PARSING = 81,\n\tDEVLINK_TRAP_GENERIC_ID_GRE_PARSING = 82,\n\tDEVLINK_TRAP_GENERIC_ID_UDP_PARSING = 83,\n\tDEVLINK_TRAP_GENERIC_ID_TCP_PARSING = 84,\n\tDEVLINK_TRAP_GENERIC_ID_IPSEC_PARSING = 85,\n\tDEVLINK_TRAP_GENERIC_ID_SCTP_PARSING = 86,\n\tDEVLINK_TRAP_GENERIC_ID_DCCP_PARSING = 87,\n\tDEVLINK_TRAP_GENERIC_ID_GTP_PARSING = 88,\n\tDEVLINK_TRAP_GENERIC_ID_ESP_PARSING = 89,\n\tDEVLINK_TRAP_GENERIC_ID_BLACKHOLE_NEXTHOP = 90,\n\tDEVLINK_TRAP_GENERIC_ID_DMAC_FILTER = 91,\n\t__DEVLINK_TRAP_GENERIC_ID_MAX = 92,\n\tDEVLINK_TRAP_GENERIC_ID_MAX = 91,\n};\n\nenum devlink_trap_group_generic_id {\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS = 0,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS = 1,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_L3_EXCEPTIONS = 2,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS = 3,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_TUNNEL_DROPS = 4,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_ACL_DROPS = 5,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_STP = 6,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_LACP = 7,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_LLDP = 8,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_MC_SNOOPING = 9,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_DHCP = 10,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_NEIGH_DISCOVERY = 11,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_BFD = 12,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_OSPF = 13,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_BGP = 14,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_VRRP = 15,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_PIM = 16,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_UC_LB = 17,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_LOCAL_DELIVERY = 18,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_EXTERNAL_DELIVERY = 19,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_IPV6 = 20,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_PTP_EVENT = 21,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_PTP_GENERAL = 22,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_ACL_SAMPLE = 23,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_ACL_TRAP = 24,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_PARSER_ERROR_DROPS = 25,\n\t__DEVLINK_TRAP_GROUP_GENERIC_ID_MAX = 26,\n\tDEVLINK_TRAP_GROUP_GENERIC_ID_MAX = 25,\n};\n\nstruct devlink_info_req {\n\tstruct sk_buff *msg;\n};\n\nstruct trace_event_raw_devlink_hwmsg {\n\tstruct trace_entry ent;\n\tu32 __data_loc_bus_name;\n\tu32 __data_loc_dev_name;\n\tu32 __data_loc_driver_name;\n\tbool incoming;\n\tlong unsigned int type;\n\tu32 __data_loc_buf;\n\tsize_t len;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_devlink_hwerr {\n\tstruct trace_entry ent;\n\tu32 __data_loc_bus_name;\n\tu32 __data_loc_dev_name;\n\tu32 __data_loc_driver_name;\n\tint err;\n\tu32 __data_loc_msg;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_devlink_health_report {\n\tstruct trace_entry ent;\n\tu32 __data_loc_bus_name;\n\tu32 __data_loc_dev_name;\n\tu32 __data_loc_driver_name;\n\tu32 __data_loc_reporter_name;\n\tu32 __data_loc_msg;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_devlink_health_recover_aborted {\n\tstruct trace_entry ent;\n\tu32 __data_loc_bus_name;\n\tu32 __data_loc_dev_name;\n\tu32 __data_loc_driver_name;\n\tu32 __data_loc_reporter_name;\n\tbool health_state;\n\tu64 time_since_last_recover;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_devlink_health_reporter_state_update {\n\tstruct trace_entry ent;\n\tu32 __data_loc_bus_name;\n\tu32 __data_loc_dev_name;\n\tu32 __data_loc_driver_name;\n\tu32 __data_loc_reporter_name;\n\tu8 new_state;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_devlink_trap_report {\n\tstruct trace_entry ent;\n\tu32 __data_loc_bus_name;\n\tu32 __data_loc_dev_name;\n\tu32 __data_loc_driver_name;\n\tu32 __data_loc_trap_name;\n\tu32 __data_loc_trap_group_name;\n\tu32 __data_loc_input_dev_name;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_devlink_hwmsg {\n\tu32 bus_name;\n\tu32 dev_name;\n\tu32 driver_name;\n\tu32 buf;\n};\n\nstruct trace_event_data_offsets_devlink_hwerr {\n\tu32 bus_name;\n\tu32 dev_name;\n\tu32 driver_name;\n\tu32 msg;\n};\n\nstruct trace_event_data_offsets_devlink_health_report {\n\tu32 bus_name;\n\tu32 dev_name;\n\tu32 driver_name;\n\tu32 reporter_name;\n\tu32 msg;\n};\n\nstruct trace_event_data_offsets_devlink_health_recover_aborted {\n\tu32 bus_name;\n\tu32 dev_name;\n\tu32 driver_name;\n\tu32 reporter_name;\n};\n\nstruct trace_event_data_offsets_devlink_health_reporter_state_update {\n\tu32 bus_name;\n\tu32 dev_name;\n\tu32 driver_name;\n\tu32 reporter_name;\n};\n\nstruct trace_event_data_offsets_devlink_trap_report {\n\tu32 bus_name;\n\tu32 dev_name;\n\tu32 driver_name;\n\tu32 trap_name;\n\tu32 trap_group_name;\n\tu32 input_dev_name;\n};\n\ntypedef void (*btf_trace_devlink_hwmsg)(void *, const struct devlink *, bool, long unsigned int, const u8 *, size_t);\n\ntypedef void (*btf_trace_devlink_hwerr)(void *, const struct devlink *, int, const char *);\n\ntypedef void (*btf_trace_devlink_health_report)(void *, const struct devlink *, const char *, const char *);\n\ntypedef void (*btf_trace_devlink_health_recover_aborted)(void *, const struct devlink *, const char *, bool, u64);\n\ntypedef void (*btf_trace_devlink_health_reporter_state_update)(void *, const struct devlink *, const char *, bool);\n\ntypedef void (*btf_trace_devlink_trap_report)(void *, const struct devlink *, struct sk_buff *, const struct devlink_trap_metadata *);\n\nstruct devlink_sb {\n\tstruct list_head list;\n\tunsigned int index;\n\tu32 size;\n\tu16 ingress_pools_count;\n\tu16 egress_pools_count;\n\tu16 ingress_tc_count;\n\tu16 egress_tc_count;\n};\n\nstruct devlink_region {\n\tstruct devlink *devlink;\n\tstruct devlink_port *port;\n\tstruct list_head list;\n\tunion {\n\t\tconst struct devlink_region_ops *ops;\n\t\tconst struct devlink_port_region_ops *port_ops;\n\t};\n\tstruct list_head snapshot_list;\n\tu32 max_snapshots;\n\tu32 cur_snapshots;\n\tu64 size;\n};\n\nstruct devlink_snapshot {\n\tstruct list_head list;\n\tstruct devlink_region *region;\n\tu8 *data;\n\tu32 id;\n};\n\nenum devlink_multicast_groups {\n\tDEVLINK_MCGRP_CONFIG = 0,\n};\n\nstruct devlink_reload_combination {\n\tenum devlink_reload_action action;\n\tenum devlink_reload_limit limit;\n};\n\nstruct devlink_fmsg_item {\n\tstruct list_head list;\n\tint attrtype;\n\tu8 nla_type;\n\tu16 len;\n\tint value[0];\n};\n\nstruct devlink_stats {\n\tu64 rx_bytes;\n\tu64 rx_packets;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct devlink_trap_policer_item {\n\tconst struct devlink_trap_policer *policer;\n\tu64 rate;\n\tu64 burst;\n\tstruct list_head list;\n};\n\nstruct devlink_trap_group_item {\n\tconst struct devlink_trap_group *group;\n\tstruct devlink_trap_policer_item *policer_item;\n\tstruct list_head list;\n\tstruct devlink_stats *stats;\n};\n\nstruct devlink_trap_item {\n\tconst struct devlink_trap *trap;\n\tstruct devlink_trap_group_item *group_item;\n\tstruct list_head list;\n\tenum devlink_trap_action action;\n\tstruct devlink_stats *stats;\n\tvoid *priv;\n};\n\nstruct gro_cell;\n\nstruct gro_cells {\n\tstruct gro_cell *cells;\n};\n\nstruct gro_cell {\n\tstruct sk_buff_head napi_skbs;\n\tstruct napi_struct napi;\n};\n\nenum __sk_action {\n\t__SK_DROP = 0,\n\t__SK_PASS = 1,\n\t__SK_REDIRECT = 2,\n\t__SK_NONE = 3,\n};\n\nenum sk_psock_state_bits {\n\tSK_PSOCK_TX_ENABLED = 0,\n};\n\nstruct sk_psock_link {\n\tstruct list_head list;\n\tstruct bpf_map *map;\n\tvoid *link_raw;\n};\n\nstruct bpf_stab {\n\tstruct bpf_map map;\n\tstruct sock **sks;\n\tstruct sk_psock_progs progs;\n\traw_spinlock_t lock;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n};\n\ntypedef u64 (*btf_bpf_sock_map_update)(struct bpf_sock_ops_kern *, struct bpf_map *, void *, u64);\n\ntypedef u64 (*btf_bpf_sk_redirect_map)(struct sk_buff *, struct bpf_map *, u32, u64);\n\ntypedef u64 (*btf_bpf_msg_redirect_map)(struct sk_msg *, struct bpf_map *, u32, u64);\n\nstruct sock_map_seq_info {\n\tstruct bpf_map *map;\n\tstruct sock *sk;\n\tu32 index;\n};\n\nstruct bpf_iter__sockmap {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct bpf_map *map;\n\t};\n\tunion {\n\t\tvoid *key;\n\t};\n\tunion {\n\t\tstruct sock *sk;\n\t};\n};\n\nstruct bpf_shtab_elem {\n\tstruct callback_head rcu;\n\tu32 hash;\n\tstruct sock *sk;\n\tstruct hlist_node node;\n\tu8 key[0];\n};\n\nstruct bpf_shtab_bucket {\n\tstruct hlist_head head;\n\traw_spinlock_t lock;\n};\n\nstruct bpf_shtab {\n\tstruct bpf_map map;\n\tstruct bpf_shtab_bucket *buckets;\n\tu32 buckets_num;\n\tu32 elem_size;\n\tstruct sk_psock_progs progs;\n\tatomic_t count;\n\tlong: 32;\n\tlong: 64;\n};\n\ntypedef u64 (*btf_bpf_sock_hash_update)(struct bpf_sock_ops_kern *, struct bpf_map *, void *, u64);\n\ntypedef u64 (*btf_bpf_sk_redirect_hash)(struct sk_buff *, struct bpf_map *, void *, u64);\n\ntypedef u64 (*btf_bpf_msg_redirect_hash)(struct sk_msg *, struct bpf_map *, void *, u64);\n\nstruct sock_hash_seq_info {\n\tstruct bpf_map *map;\n\tstruct bpf_shtab *htab;\n\tu32 bucket_id;\n};\n\nenum {\n\tSK_DIAG_BPF_STORAGE_REQ_NONE = 0,\n\tSK_DIAG_BPF_STORAGE_REQ_MAP_FD = 1,\n\t__SK_DIAG_BPF_STORAGE_REQ_MAX = 2,\n};\n\nenum {\n\tSK_DIAG_BPF_STORAGE_REP_NONE = 0,\n\tSK_DIAG_BPF_STORAGE = 1,\n\t__SK_DIAG_BPF_STORAGE_REP_MAX = 2,\n};\n\nenum {\n\tSK_DIAG_BPF_STORAGE_NONE = 0,\n\tSK_DIAG_BPF_STORAGE_PAD = 1,\n\tSK_DIAG_BPF_STORAGE_MAP_ID = 2,\n\tSK_DIAG_BPF_STORAGE_MAP_VALUE = 3,\n\t__SK_DIAG_BPF_STORAGE_MAX = 4,\n};\n\ntypedef u64 (*btf_bpf_sk_storage_get)(struct bpf_map *, struct sock *, void *, u64);\n\ntypedef u64 (*btf_bpf_sk_storage_delete)(struct bpf_map *, struct sock *);\n\ntypedef u64 (*btf_bpf_sk_storage_get_tracing)(struct bpf_map *, struct sock *, void *, u64);\n\ntypedef u64 (*btf_bpf_sk_storage_delete_tracing)(struct bpf_map *, struct sock *);\n\nstruct bpf_sk_storage_diag {\n\tu32 nr_maps;\n\tstruct bpf_map *maps[0];\n};\n\nstruct bpf_iter_seq_sk_storage_map_info {\n\tstruct bpf_map *map;\n\tunsigned int bucket_id;\n\tunsigned int skip_elems;\n};\n\nstruct bpf_iter__bpf_sk_storage_map {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct bpf_map *map;\n\t};\n\tunion {\n\t\tstruct sock *sk;\n\t};\n\tunion {\n\t\tvoid *value;\n\t};\n};\n\nstruct compat_cmsghdr {\n\tcompat_size_t cmsg_len;\n\tcompat_int_t cmsg_level;\n\tcompat_int_t cmsg_type;\n};\n\nstruct nvmem_cell___2;\n\nstruct fch_hdr {\n\t__u8 daddr[6];\n\t__u8 saddr[6];\n};\n\nstruct fcllc {\n\t__u8 dsap;\n\t__u8 ssap;\n\t__u8 llc;\n\t__u8 protid[3];\n\t__be16 ethertype;\n};\n\nenum macvlan_mode {\n\tMACVLAN_MODE_PRIVATE = 1,\n\tMACVLAN_MODE_VEPA = 2,\n\tMACVLAN_MODE_BRIDGE = 4,\n\tMACVLAN_MODE_PASSTHRU = 8,\n\tMACVLAN_MODE_SOURCE = 16,\n};\n\nstruct tc_ratespec {\n\tunsigned char cell_log;\n\t__u8 linklayer;\n\tshort unsigned int overhead;\n\tshort int cell_align;\n\tshort unsigned int mpu;\n\t__u32 rate;\n};\n\nstruct tc_prio_qopt {\n\tint bands;\n\t__u8 priomap[16];\n};\n\nenum {\n\tTCA_UNSPEC = 0,\n\tTCA_KIND = 1,\n\tTCA_OPTIONS = 2,\n\tTCA_STATS = 3,\n\tTCA_XSTATS = 4,\n\tTCA_RATE = 5,\n\tTCA_FCNT = 6,\n\tTCA_STATS2 = 7,\n\tTCA_STAB = 8,\n\tTCA_PAD = 9,\n\tTCA_DUMP_INVISIBLE = 10,\n\tTCA_CHAIN = 11,\n\tTCA_HW_OFFLOAD = 12,\n\tTCA_INGRESS_BLOCK = 13,\n\tTCA_EGRESS_BLOCK = 14,\n\tTCA_DUMP_FLAGS = 15,\n\t__TCA_MAX = 16,\n};\n\nstruct vlan_pcpu_stats {\n\tu64 rx_packets;\n\tu64 rx_bytes;\n\tu64 rx_multicast;\n\tu64 tx_packets;\n\tu64 tx_bytes;\n\tstruct u64_stats_sync syncp;\n\tu32 rx_errors;\n\tu32 tx_dropped;\n};\n\nstruct netpoll___2;\n\nstruct skb_array {\n\tstruct ptr_ring ring;\n};\n\nstruct macvlan_port;\n\nstruct macvlan_dev {\n\tstruct net_device *dev;\n\tstruct list_head list;\n\tstruct hlist_node hlist;\n\tstruct macvlan_port *port;\n\tstruct net_device *lowerdev;\n\tvoid *accel_priv;\n\tstruct vlan_pcpu_stats *pcpu_stats;\n\tlong unsigned int mc_filter[4];\n\tnetdev_features_t set_features;\n\tenum macvlan_mode mode;\n\tu16 flags;\n\tunsigned int macaddr_count;\n\tu32 bc_queue_len_req;\n\tstruct netpoll___2 *netpoll;\n};\n\nstruct psched_ratecfg {\n\tu64 rate_bytes_ps;\n\tu32 mult;\n\tu16 overhead;\n\tu8 linklayer;\n\tu8 shift;\n};\n\nstruct psched_pktrate {\n\tu64 rate_pkts_ps;\n\tu32 mult;\n\tu8 shift;\n};\n\nstruct mini_Qdisc_pair {\n\tstruct mini_Qdisc miniq1;\n\tstruct mini_Qdisc miniq2;\n\tstruct mini_Qdisc **p_miniq;\n};\n\nstruct pfifo_fast_priv {\n\tstruct skb_array q[3];\n};\n\nstruct tc_qopt_offload_stats {\n\tstruct gnet_stats_basic_packed *bstats;\n\tstruct gnet_stats_queue *qstats;\n};\n\nenum tc_mq_command {\n\tTC_MQ_CREATE = 0,\n\tTC_MQ_DESTROY = 1,\n\tTC_MQ_STATS = 2,\n\tTC_MQ_GRAFT = 3,\n};\n\nstruct tc_mq_opt_offload_graft_params {\n\tlong unsigned int queue;\n\tu32 child_handle;\n};\n\nstruct tc_mq_qopt_offload {\n\tenum tc_mq_command command;\n\tu32 handle;\n\tunion {\n\t\tstruct tc_qopt_offload_stats stats;\n\t\tstruct tc_mq_opt_offload_graft_params graft_params;\n\t};\n};\n\nstruct mq_sched {\n\tstruct Qdisc **qdiscs;\n};\n\nstruct sch_frag_data {\n\tlong unsigned int dst;\n\tstruct qdisc_skb_cb cb;\n\t__be16 inner_protocol;\n\tu16 vlan_tci;\n\t__be16 vlan_proto;\n\tunsigned int l2_len;\n\tu8 l2_data[18];\n\tint (*xmit)(struct sk_buff *);\n};\n\nenum tc_link_layer {\n\tTC_LINKLAYER_UNAWARE = 0,\n\tTC_LINKLAYER_ETHERNET = 1,\n\tTC_LINKLAYER_ATM = 2,\n};\n\nenum {\n\tTCA_STAB_UNSPEC = 0,\n\tTCA_STAB_BASE = 1,\n\tTCA_STAB_DATA = 2,\n\t__TCA_STAB_MAX = 3,\n};\n\nstruct qdisc_rate_table {\n\tstruct tc_ratespec rate;\n\tu32 data[256];\n\tstruct qdisc_rate_table *next;\n\tint refcnt;\n};\n\nstruct Qdisc_class_common {\n\tu32 classid;\n\tstruct hlist_node hnode;\n};\n\nstruct Qdisc_class_hash {\n\tstruct hlist_head *hash;\n\tunsigned int hashsize;\n\tunsigned int hashmask;\n\tunsigned int hashelems;\n};\n\nstruct qdisc_watchdog {\n\tu64 last_expires;\n\tstruct hrtimer timer;\n\tstruct Qdisc *qdisc;\n};\n\nenum tc_root_command {\n\tTC_ROOT_GRAFT = 0,\n};\n\nstruct tc_root_qopt_offload {\n\tenum tc_root_command command;\n\tu32 handle;\n\tbool ingress;\n};\n\nstruct check_loop_arg {\n\tstruct qdisc_walker w;\n\tstruct Qdisc *p;\n\tint depth;\n};\n\nstruct tcf_bind_args {\n\tstruct tcf_walker w;\n\tlong unsigned int base;\n\tlong unsigned int cl;\n\tu32 classid;\n};\n\nstruct tc_bind_class_args {\n\tstruct qdisc_walker w;\n\tlong unsigned int new_cl;\n\tu32 portid;\n\tu32 clid;\n};\n\nstruct qdisc_dump_args {\n\tstruct qdisc_walker w;\n\tstruct sk_buff *skb;\n\tstruct netlink_callback *cb;\n};\n\nenum net_xmit_qdisc_t {\n\t__NET_XMIT_STOLEN = 65536,\n\t__NET_XMIT_BYPASS = 131072,\n};\n\nenum {\n\tTCA_ACT_UNSPEC = 0,\n\tTCA_ACT_KIND = 1,\n\tTCA_ACT_OPTIONS = 2,\n\tTCA_ACT_INDEX = 3,\n\tTCA_ACT_STATS = 4,\n\tTCA_ACT_PAD = 5,\n\tTCA_ACT_COOKIE = 6,\n\tTCA_ACT_FLAGS = 7,\n\tTCA_ACT_HW_STATS = 8,\n\tTCA_ACT_USED_HW_STATS = 9,\n\t__TCA_ACT_MAX = 10,\n};\n\nenum tca_id {\n\tTCA_ID_UNSPEC = 0,\n\tTCA_ID_POLICE = 1,\n\tTCA_ID_GACT = 5,\n\tTCA_ID_IPT = 6,\n\tTCA_ID_PEDIT = 7,\n\tTCA_ID_MIRRED = 8,\n\tTCA_ID_NAT = 9,\n\tTCA_ID_XT = 10,\n\tTCA_ID_SKBEDIT = 11,\n\tTCA_ID_VLAN = 12,\n\tTCA_ID_BPF = 13,\n\tTCA_ID_CONNMARK = 14,\n\tTCA_ID_SKBMOD = 15,\n\tTCA_ID_CSUM = 16,\n\tTCA_ID_TUNNEL_KEY = 17,\n\tTCA_ID_SIMP = 22,\n\tTCA_ID_IFE = 25,\n\tTCA_ID_SAMPLE = 26,\n\tTCA_ID_CTINFO = 27,\n\tTCA_ID_MPLS = 28,\n\tTCA_ID_CT = 29,\n\tTCA_ID_GATE = 30,\n\t__TCA_ID_MAX = 255,\n};\n\nstruct tcf_t {\n\t__u64 install;\n\t__u64 lastuse;\n\t__u64 expires;\n\t__u64 firstuse;\n};\n\nstruct psample_group {\n\tstruct list_head list;\n\tstruct net *net;\n\tu32 group_num;\n\tu32 refcount;\n\tu32 seq;\n\tstruct callback_head rcu;\n};\n\nstruct action_gate_entry {\n\tu8 gate_state;\n\tu32 interval;\n\ts32 ipv;\n\ts32 maxoctets;\n};\n\nenum qdisc_class_ops_flags {\n\tQDISC_CLASS_OPS_DOIT_UNLOCKED = 1,\n};\n\nenum tcf_proto_ops_flags {\n\tTCF_PROTO_OPS_DOIT_UNLOCKED = 1,\n};\n\ntypedef void tcf_chain_head_change_t(struct tcf_proto *, void *);\n\nstruct tcf_idrinfo {\n\tstruct mutex lock;\n\tstruct idr action_idr;\n\tstruct net *net;\n};\n\nstruct tc_action_ops;\n\nstruct tc_cookie;\n\nstruct tc_action {\n\tconst struct tc_action_ops *ops;\n\t__u32 type;\n\tstruct tcf_idrinfo *idrinfo;\n\tu32 tcfa_index;\n\trefcount_t tcfa_refcnt;\n\tatomic_t tcfa_bindcnt;\n\tint tcfa_action;\n\tstruct tcf_t tcfa_tm;\n\tstruct gnet_stats_basic_packed tcfa_bstats;\n\tstruct gnet_stats_basic_packed tcfa_bstats_hw;\n\tstruct gnet_stats_queue tcfa_qstats;\n\tstruct net_rate_estimator *tcfa_rate_est;\n\tspinlock_t tcfa_lock;\n\tstruct gnet_stats_basic_cpu *cpu_bstats;\n\tstruct gnet_stats_basic_cpu *cpu_bstats_hw;\n\tstruct gnet_stats_queue *cpu_qstats;\n\tstruct tc_cookie *act_cookie;\n\tstruct tcf_chain *goto_chain;\n\tu32 tcfa_flags;\n\tu8 hw_stats;\n\tu8 used_hw_stats;\n\tbool used_hw_stats_valid;\n};\n\ntypedef void (*tc_action_priv_destructor)(void *);\n\nstruct tc_action_ops {\n\tstruct list_head head;\n\tchar kind[16];\n\tenum tca_id id;\n\tsize_t size;\n\tstruct module *owner;\n\tint (*act)(struct sk_buff *, const struct tc_action *, struct tcf_result *);\n\tint (*dump)(struct sk_buff *, struct tc_action *, int, int);\n\tvoid (*cleanup)(struct tc_action *);\n\tint (*lookup)(struct net *, struct tc_action **, u32);\n\tint (*init)(struct net *, struct nlattr *, struct nlattr *, struct tc_action **, int, int, bool, struct tcf_proto *, u32, struct netlink_ext_ack *);\n\tint (*walk)(struct net *, struct sk_buff *, struct netlink_callback *, int, const struct tc_action_ops *, struct netlink_ext_ack *);\n\tvoid (*stats_update)(struct tc_action *, u64, u64, u64, u64, bool);\n\tsize_t (*get_fill_size)(const struct tc_action *);\n\tstruct net_device * (*get_dev)(const struct tc_action *, tc_action_priv_destructor *);\n\tstruct psample_group * (*get_psample_group)(const struct tc_action *, tc_action_priv_destructor *);\n};\n\nstruct tc_cookie {\n\tu8 *data;\n\tu32 len;\n\tstruct callback_head rcu;\n};\n\nstruct tcf_block_ext_info {\n\tenum flow_block_binder_type binder_type;\n\ttcf_chain_head_change_t *chain_head_change;\n\tvoid *chain_head_change_priv;\n\tu32 block_index;\n};\n\nstruct tcf_qevent {\n\tstruct tcf_block *block;\n\tstruct tcf_block_ext_info info;\n\tstruct tcf_proto *filter_chain;\n};\n\nstruct tcf_exts {\n\t__u32 type;\n\tint nr_actions;\n\tstruct tc_action **actions;\n\tstruct net *net;\n\tint action;\n\tint police;\n};\n\nenum pedit_header_type {\n\tTCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK = 0,\n\tTCA_PEDIT_KEY_EX_HDR_TYPE_ETH = 1,\n\tTCA_PEDIT_KEY_EX_HDR_TYPE_IP4 = 2,\n\tTCA_PEDIT_KEY_EX_HDR_TYPE_IP6 = 3,\n\tTCA_PEDIT_KEY_EX_HDR_TYPE_TCP = 4,\n\tTCA_PEDIT_KEY_EX_HDR_TYPE_UDP = 5,\n\t__PEDIT_HDR_TYPE_MAX = 6,\n};\n\nenum pedit_cmd {\n\tTCA_PEDIT_KEY_EX_CMD_SET = 0,\n\tTCA_PEDIT_KEY_EX_CMD_ADD = 1,\n\t__PEDIT_CMD_MAX = 2,\n};\n\nstruct tc_pedit_key {\n\t__u32 mask;\n\t__u32 val;\n\t__u32 off;\n\t__u32 at;\n\t__u32 offmask;\n\t__u32 shift;\n};\n\nstruct tcf_pedit_key_ex {\n\tenum pedit_header_type htype;\n\tenum pedit_cmd cmd;\n};\n\nstruct tcf_pedit {\n\tstruct tc_action common;\n\tunsigned char tcfp_nkeys;\n\tunsigned char tcfp_flags;\n\tstruct tc_pedit_key *tcfp_keys;\n\tstruct tcf_pedit_key_ex *tcfp_keys_ex;\n};\n\nstruct tcf_mirred {\n\tstruct tc_action common;\n\tint tcfm_eaction;\n\tbool tcfm_mac_header_xmit;\n\tstruct net_device *tcfm_dev;\n\tstruct list_head tcfm_list;\n};\n\nstruct tcf_vlan_params {\n\tint tcfv_action;\n\tunsigned char tcfv_push_dst[6];\n\tunsigned char tcfv_push_src[6];\n\tu16 tcfv_push_vid;\n\t__be16 tcfv_push_proto;\n\tu8 tcfv_push_prio;\n\tbool tcfv_push_prio_exists;\n\tstruct callback_head rcu;\n};\n\nstruct tcf_vlan {\n\tstruct tc_action common;\n\tstruct tcf_vlan_params *vlan_p;\n};\n\nstruct tcf_tunnel_key_params {\n\tstruct callback_head rcu;\n\tint tcft_action;\n\tstruct metadata_dst *tcft_enc_metadata;\n};\n\nstruct tcf_tunnel_key {\n\tstruct tc_action common;\n\tstruct tcf_tunnel_key_params *params;\n};\n\nstruct tcf_csum_params {\n\tu32 update_flags;\n\tstruct callback_head rcu;\n};\n\nstruct tcf_csum {\n\tstruct tc_action common;\n\tstruct tcf_csum_params *params;\n};\n\nstruct tcf_gact {\n\tstruct tc_action common;\n\tu16 tcfg_ptype;\n\tu16 tcfg_pval;\n\tint tcfg_paction;\n\tatomic_t packets;\n};\n\nstruct tcf_police_params {\n\tint tcfp_result;\n\tu32 tcfp_ewma_rate;\n\ts64 tcfp_burst;\n\tu32 tcfp_mtu;\n\ts64 tcfp_mtu_ptoks;\n\ts64 tcfp_pkt_burst;\n\tstruct psched_ratecfg rate;\n\tbool rate_present;\n\tstruct psched_ratecfg peak;\n\tbool peak_present;\n\tstruct psched_pktrate ppsrate;\n\tbool pps_present;\n\tstruct callback_head rcu;\n};\n\nstruct tcf_police {\n\tstruct tc_action common;\n\tstruct tcf_police_params *params;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tspinlock_t tcfp_lock;\n\ts64 tcfp_toks;\n\ts64 tcfp_ptoks;\n\ts64 tcfp_pkttoks;\n\ts64 tcfp_t_c;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct tcf_sample {\n\tstruct tc_action common;\n\tu32 rate;\n\tbool truncate;\n\tu32 trunc_size;\n\tstruct psample_group *psample_group;\n\tu32 psample_group_num;\n\tstruct list_head tcfm_list;\n};\n\nstruct tcf_skbedit_params {\n\tu32 flags;\n\tu32 priority;\n\tu32 mark;\n\tu32 mask;\n\tu16 queue_mapping;\n\tu16 ptype;\n\tstruct callback_head rcu;\n};\n\nstruct tcf_skbedit {\n\tstruct tc_action common;\n\tstruct tcf_skbedit_params *params;\n};\n\nstruct nf_nat_range2 {\n\tunsigned int flags;\n\tunion nf_inet_addr min_addr;\n\tunion nf_inet_addr max_addr;\n\tunion nf_conntrack_man_proto min_proto;\n\tunion nf_conntrack_man_proto max_proto;\n\tunion nf_conntrack_man_proto base_proto;\n};\n\nstruct tcf_ct_flow_table;\n\nstruct tcf_ct_params {\n\tstruct nf_conn *tmpl;\n\tu16 zone;\n\tu32 mark;\n\tu32 mark_mask;\n\tu32 labels[4];\n\tu32 labels_mask[4];\n\tstruct nf_nat_range2 range;\n\tbool ipv4_range;\n\tu16 ct_action;\n\tstruct callback_head rcu;\n\tstruct tcf_ct_flow_table *ct_ft;\n\tstruct nf_flowtable *nf_ft;\n};\n\nstruct tcf_ct {\n\tstruct tc_action common;\n\tstruct tcf_ct_params *params;\n};\n\nstruct tcf_mpls_params {\n\tint tcfm_action;\n\tu32 tcfm_label;\n\tu8 tcfm_tc;\n\tu8 tcfm_ttl;\n\tu8 tcfm_bos;\n\t__be16 tcfm_proto;\n\tstruct callback_head rcu;\n};\n\nstruct tcf_mpls {\n\tstruct tc_action common;\n\tstruct tcf_mpls_params *mpls_p;\n};\n\nstruct tcfg_gate_entry {\n\tint index;\n\tu8 gate_state;\n\tu32 interval;\n\ts32 ipv;\n\ts32 maxoctets;\n\tstruct list_head list;\n};\n\nstruct tcf_gate_params {\n\ts32 tcfg_priority;\n\tu64 tcfg_basetime;\n\tu64 tcfg_cycletime;\n\tu64 tcfg_cycletime_ext;\n\tu32 tcfg_flags;\n\ts32 tcfg_clockid;\n\tsize_t num_entries;\n\tstruct list_head entries;\n};\n\nstruct tcf_gate {\n\tstruct tc_action common;\n\tstruct tcf_gate_params param;\n\tu8 current_gate_status;\n\tktime_t current_close_time;\n\tu32 current_entry_octets;\n\ts32 current_max_octets;\n\tstruct tcfg_gate_entry *next_entry;\n\tstruct hrtimer hitimer;\n\tenum tk_offsets tk_offset;\n};\n\nstruct tcf_filter_chain_list_item {\n\tstruct list_head list;\n\ttcf_chain_head_change_t *chain_head_change;\n\tvoid *chain_head_change_priv;\n};\n\nstruct tcf_net {\n\tspinlock_t idr_lock;\n\tstruct idr idr;\n};\n\nstruct tcf_block_owner_item {\n\tstruct list_head list;\n\tstruct Qdisc *q;\n\tenum flow_block_binder_type binder_type;\n};\n\nstruct tcf_chain_info {\n\tstruct tcf_proto **pprev;\n\tstruct tcf_proto *next;\n};\n\nstruct tcf_dump_args {\n\tstruct tcf_walker w;\n\tstruct sk_buff *skb;\n\tstruct netlink_callback *cb;\n\tstruct tcf_block *block;\n\tstruct Qdisc *q;\n\tu32 parent;\n\tbool terse_dump;\n};\n\nstruct tcamsg {\n\tunsigned char tca_family;\n\tunsigned char tca__pad1;\n\tshort unsigned int tca__pad2;\n};\n\nenum {\n\tTCA_ROOT_UNSPEC = 0,\n\tTCA_ROOT_TAB = 1,\n\tTCA_ROOT_FLAGS = 2,\n\tTCA_ROOT_COUNT = 3,\n\tTCA_ROOT_TIME_DELTA = 4,\n\t__TCA_ROOT_MAX = 5,\n};\n\nstruct tc_action_net {\n\tstruct tcf_idrinfo *idrinfo;\n\tconst struct tc_action_ops *ops;\n};\n\nstruct tc_fifo_qopt {\n\t__u32 limit;\n};\n\nenum tc_fifo_command {\n\tTC_FIFO_REPLACE = 0,\n\tTC_FIFO_DESTROY = 1,\n\tTC_FIFO_STATS = 2,\n};\n\nstruct tc_fifo_qopt_offload {\n\tenum tc_fifo_command command;\n\tu32 handle;\n\tu32 parent;\n\tunion {\n\t\tstruct tc_qopt_offload_stats stats;\n\t};\n};\n\nenum {\n\tTCA_FQ_CODEL_UNSPEC = 0,\n\tTCA_FQ_CODEL_TARGET = 1,\n\tTCA_FQ_CODEL_LIMIT = 2,\n\tTCA_FQ_CODEL_INTERVAL = 3,\n\tTCA_FQ_CODEL_ECN = 4,\n\tTCA_FQ_CODEL_FLOWS = 5,\n\tTCA_FQ_CODEL_QUANTUM = 6,\n\tTCA_FQ_CODEL_CE_THRESHOLD = 7,\n\tTCA_FQ_CODEL_DROP_BATCH_SIZE = 8,\n\tTCA_FQ_CODEL_MEMORY_LIMIT = 9,\n\t__TCA_FQ_CODEL_MAX = 10,\n};\n\nenum {\n\tTCA_FQ_CODEL_XSTATS_QDISC = 0,\n\tTCA_FQ_CODEL_XSTATS_CLASS = 1,\n};\n\nstruct tc_fq_codel_qd_stats {\n\t__u32 maxpacket;\n\t__u32 drop_overlimit;\n\t__u32 ecn_mark;\n\t__u32 new_flow_count;\n\t__u32 new_flows_len;\n\t__u32 old_flows_len;\n\t__u32 ce_mark;\n\t__u32 memory_usage;\n\t__u32 drop_overmemory;\n};\n\nstruct tc_fq_codel_cl_stats {\n\t__s32 deficit;\n\t__u32 ldelay;\n\t__u32 count;\n\t__u32 lastcount;\n\t__u32 dropping;\n\t__s32 drop_next;\n};\n\nstruct tc_fq_codel_xstats {\n\t__u32 type;\n\tunion {\n\t\tstruct tc_fq_codel_qd_stats qdisc_stats;\n\t\tstruct tc_fq_codel_cl_stats class_stats;\n\t};\n};\n\ntypedef u32 codel_time_t;\n\ntypedef s32 codel_tdiff_t;\n\nstruct codel_params {\n\tcodel_time_t target;\n\tcodel_time_t ce_threshold;\n\tcodel_time_t interval;\n\tu32 mtu;\n\tbool ecn;\n};\n\nstruct codel_vars {\n\tu32 count;\n\tu32 lastcount;\n\tbool dropping;\n\tu16 rec_inv_sqrt;\n\tcodel_time_t first_above_time;\n\tcodel_time_t drop_next;\n\tcodel_time_t ldelay;\n};\n\nstruct codel_stats {\n\tu32 maxpacket;\n\tu32 drop_count;\n\tu32 drop_len;\n\tu32 ecn_mark;\n\tu32 ce_mark;\n};\n\ntypedef u32 (*codel_skb_len_t)(const struct sk_buff *);\n\ntypedef codel_time_t (*codel_skb_time_t)(const struct sk_buff *);\n\ntypedef void (*codel_skb_drop_t)(struct sk_buff *, void *);\n\ntypedef struct sk_buff * (*codel_skb_dequeue_t)(struct codel_vars *, void *);\n\nstruct codel_skb_cb {\n\tcodel_time_t enqueue_time;\n\tunsigned int mem_usage;\n};\n\nstruct fq_codel_flow {\n\tstruct sk_buff *head;\n\tstruct sk_buff *tail;\n\tstruct list_head flowchain;\n\tint deficit;\n\tstruct codel_vars cvars;\n};\n\nstruct fq_codel_sched_data {\n\tstruct tcf_proto *filter_list;\n\tstruct tcf_block *block;\n\tstruct fq_codel_flow *flows;\n\tu32 *backlogs;\n\tu32 flows_cnt;\n\tu32 quantum;\n\tu32 drop_batch_size;\n\tu32 memory_limit;\n\tstruct codel_params cparams;\n\tstruct codel_stats cstats;\n\tu32 memory_usage;\n\tu32 drop_overmemory;\n\tu32 drop_overlimit;\n\tu32 new_flow_count;\n\tstruct list_head new_flows;\n\tstruct list_head old_flows;\n};\n\nstruct tcf_ematch_tree_hdr {\n\t__u16 nmatches;\n\t__u16 progid;\n};\n\nenum {\n\tTCA_EMATCH_TREE_UNSPEC = 0,\n\tTCA_EMATCH_TREE_HDR = 1,\n\tTCA_EMATCH_TREE_LIST = 2,\n\t__TCA_EMATCH_TREE_MAX = 3,\n};\n\nstruct tcf_ematch_hdr {\n\t__u16 matchid;\n\t__u16 kind;\n\t__u16 flags;\n\t__u16 pad;\n};\n\nstruct tcf_pkt_info {\n\tunsigned char *ptr;\n\tint nexthdr;\n};\n\nstruct tcf_ematch_ops;\n\nstruct tcf_ematch {\n\tstruct tcf_ematch_ops *ops;\n\tlong unsigned int data;\n\tunsigned int datalen;\n\tu16 matchid;\n\tu16 flags;\n\tstruct net *net;\n};\n\nstruct tcf_ematch_ops {\n\tint kind;\n\tint datalen;\n\tint (*change)(struct net *, void *, int, struct tcf_ematch *);\n\tint (*match)(struct sk_buff *, struct tcf_ematch *, struct tcf_pkt_info *);\n\tvoid (*destroy)(struct tcf_ematch *);\n\tint (*dump)(struct sk_buff *, struct tcf_ematch *);\n\tstruct module *owner;\n\tstruct list_head link;\n};\n\nstruct tcf_ematch_tree {\n\tstruct tcf_ematch_tree_hdr hdr;\n\tstruct tcf_ematch *matches;\n};\n\nstruct sockaddr_nl {\n\t__kernel_sa_family_t nl_family;\n\tshort unsigned int nl_pad;\n\t__u32 nl_pid;\n\t__u32 nl_groups;\n};\n\nstruct nlmsgerr {\n\tint error;\n\tstruct nlmsghdr msg;\n};\n\nenum nlmsgerr_attrs {\n\tNLMSGERR_ATTR_UNUSED = 0,\n\tNLMSGERR_ATTR_MSG = 1,\n\tNLMSGERR_ATTR_OFFS = 2,\n\tNLMSGERR_ATTR_COOKIE = 3,\n\tNLMSGERR_ATTR_POLICY = 4,\n\t__NLMSGERR_ATTR_MAX = 5,\n\tNLMSGERR_ATTR_MAX = 4,\n};\n\nstruct nl_pktinfo {\n\t__u32 group;\n};\n\nenum {\n\tNETLINK_UNCONNECTED = 0,\n\tNETLINK_CONNECTED = 1,\n};\n\nenum netlink_skb_flags {\n\tNETLINK_SKB_DST = 8,\n};\n\nstruct netlink_notify {\n\tstruct net *net;\n\tu32 portid;\n\tint protocol;\n};\n\nstruct netlink_tap {\n\tstruct net_device *dev;\n\tstruct module *module;\n\tstruct list_head list;\n};\n\nstruct trace_event_raw_netlink_extack {\n\tstruct trace_entry ent;\n\tu32 __data_loc_msg;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_netlink_extack {\n\tu32 msg;\n};\n\ntypedef void (*btf_trace_netlink_extack)(void *, const char *);\n\nstruct netlink_sock {\n\tstruct sock sk;\n\tu32 portid;\n\tu32 dst_portid;\n\tu32 dst_group;\n\tu32 flags;\n\tu32 subscriptions;\n\tu32 ngroups;\n\tlong unsigned int *groups;\n\tlong unsigned int state;\n\tsize_t max_recvmsg_len;\n\twait_queue_head_t wait;\n\tbool bound;\n\tbool cb_running;\n\tint dump_done_errno;\n\tstruct netlink_callback cb;\n\tstruct mutex *cb_mutex;\n\tstruct mutex cb_def_mutex;\n\tvoid (*netlink_rcv)(struct sk_buff *);\n\tint (*netlink_bind)(struct net *, int);\n\tvoid (*netlink_unbind)(struct net *, int);\n\tstruct module *module;\n\tstruct rhash_head node;\n\tstruct callback_head rcu;\n\tstruct work_struct work;\n};\n\nstruct listeners;\n\nstruct netlink_table {\n\tstruct rhashtable hash;\n\tstruct hlist_head mc_list;\n\tstruct listeners *listeners;\n\tunsigned int flags;\n\tunsigned int groups;\n\tstruct mutex *cb_mutex;\n\tstruct module *module;\n\tint (*bind)(struct net *, int);\n\tvoid (*unbind)(struct net *, int);\n\tbool (*compare)(struct net *, struct sock *);\n\tint registered;\n};\n\nstruct listeners {\n\tstruct callback_head rcu;\n\tlong unsigned int masks[0];\n};\n\nstruct netlink_tap_net {\n\tstruct list_head netlink_tap_all;\n\tstruct mutex netlink_tap_lock;\n};\n\nstruct netlink_compare_arg {\n\tpossible_net_t pnet;\n\tu32 portid;\n};\n\nstruct netlink_broadcast_data {\n\tstruct sock *exclude_sk;\n\tstruct net *net;\n\tu32 portid;\n\tu32 group;\n\tint failure;\n\tint delivery_failure;\n\tint congested;\n\tint delivered;\n\tgfp_t allocation;\n\tstruct sk_buff *skb;\n\tstruct sk_buff *skb2;\n\tint (*tx_filter)(struct sock *, struct sk_buff *, void *);\n\tvoid *tx_data;\n};\n\nstruct netlink_set_err_data {\n\tstruct sock *exclude_sk;\n\tu32 portid;\n\tu32 group;\n\tint code;\n};\n\nstruct nl_seq_iter {\n\tstruct seq_net_private p;\n\tstruct rhashtable_iter hti;\n\tint link;\n};\n\nstruct bpf_iter__netlink {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct netlink_sock *sk;\n\t};\n};\n\nenum {\n\tCTRL_CMD_UNSPEC = 0,\n\tCTRL_CMD_NEWFAMILY = 1,\n\tCTRL_CMD_DELFAMILY = 2,\n\tCTRL_CMD_GETFAMILY = 3,\n\tCTRL_CMD_NEWOPS = 4,\n\tCTRL_CMD_DELOPS = 5,\n\tCTRL_CMD_GETOPS = 6,\n\tCTRL_CMD_NEWMCAST_GRP = 7,\n\tCTRL_CMD_DELMCAST_GRP = 8,\n\tCTRL_CMD_GETMCAST_GRP = 9,\n\tCTRL_CMD_GETPOLICY = 10,\n\t__CTRL_CMD_MAX = 11,\n};\n\nenum {\n\tCTRL_ATTR_UNSPEC = 0,\n\tCTRL_ATTR_FAMILY_ID = 1,\n\tCTRL_ATTR_FAMILY_NAME = 2,\n\tCTRL_ATTR_VERSION = 3,\n\tCTRL_ATTR_HDRSIZE = 4,\n\tCTRL_ATTR_MAXATTR = 5,\n\tCTRL_ATTR_OPS = 6,\n\tCTRL_ATTR_MCAST_GROUPS = 7,\n\tCTRL_ATTR_POLICY = 8,\n\tCTRL_ATTR_OP_POLICY = 9,\n\tCTRL_ATTR_OP = 10,\n\t__CTRL_ATTR_MAX = 11,\n};\n\nenum {\n\tCTRL_ATTR_OP_UNSPEC = 0,\n\tCTRL_ATTR_OP_ID = 1,\n\tCTRL_ATTR_OP_FLAGS = 2,\n\t__CTRL_ATTR_OP_MAX = 3,\n};\n\nenum {\n\tCTRL_ATTR_MCAST_GRP_UNSPEC = 0,\n\tCTRL_ATTR_MCAST_GRP_NAME = 1,\n\tCTRL_ATTR_MCAST_GRP_ID = 2,\n\t__CTRL_ATTR_MCAST_GRP_MAX = 3,\n};\n\nenum {\n\tCTRL_ATTR_POLICY_UNSPEC = 0,\n\tCTRL_ATTR_POLICY_DO = 1,\n\tCTRL_ATTR_POLICY_DUMP = 2,\n\t__CTRL_ATTR_POLICY_DUMP_MAX = 3,\n\tCTRL_ATTR_POLICY_DUMP_MAX = 2,\n};\n\nstruct genl_start_context {\n\tconst struct genl_family *family;\n\tstruct nlmsghdr *nlh;\n\tstruct netlink_ext_ack *extack;\n\tconst struct genl_ops *ops;\n\tint hdrlen;\n};\n\nstruct netlink_policy_dump_state;\n\nstruct ctrl_dump_policy_ctx {\n\tstruct netlink_policy_dump_state *state;\n\tconst struct genl_family *rt;\n\tunsigned int opidx;\n\tu32 op;\n\tu16 fam_id;\n\tu8 policies: 1;\n\tu8 single_op: 1;\n};\n\nenum netlink_attribute_type {\n\tNL_ATTR_TYPE_INVALID = 0,\n\tNL_ATTR_TYPE_FLAG = 1,\n\tNL_ATTR_TYPE_U8 = 2,\n\tNL_ATTR_TYPE_U16 = 3,\n\tNL_ATTR_TYPE_U32 = 4,\n\tNL_ATTR_TYPE_U64 = 5,\n\tNL_ATTR_TYPE_S8 = 6,\n\tNL_ATTR_TYPE_S16 = 7,\n\tNL_ATTR_TYPE_S32 = 8,\n\tNL_ATTR_TYPE_S64 = 9,\n\tNL_ATTR_TYPE_BINARY = 10,\n\tNL_ATTR_TYPE_STRING = 11,\n\tNL_ATTR_TYPE_NUL_STRING = 12,\n\tNL_ATTR_TYPE_NESTED = 13,\n\tNL_ATTR_TYPE_NESTED_ARRAY = 14,\n\tNL_ATTR_TYPE_BITFIELD32 = 15,\n};\n\nenum netlink_policy_type_attr {\n\tNL_POLICY_TYPE_ATTR_UNSPEC = 0,\n\tNL_POLICY_TYPE_ATTR_TYPE = 1,\n\tNL_POLICY_TYPE_ATTR_MIN_VALUE_S = 2,\n\tNL_POLICY_TYPE_ATTR_MAX_VALUE_S = 3,\n\tNL_POLICY_TYPE_ATTR_MIN_VALUE_U = 4,\n\tNL_POLICY_TYPE_ATTR_MAX_VALUE_U = 5,\n\tNL_POLICY_TYPE_ATTR_MIN_LENGTH = 6,\n\tNL_POLICY_TYPE_ATTR_MAX_LENGTH = 7,\n\tNL_POLICY_TYPE_ATTR_POLICY_IDX = 8,\n\tNL_POLICY_TYPE_ATTR_POLICY_MAXTYPE = 9,\n\tNL_POLICY_TYPE_ATTR_BITFIELD32_MASK = 10,\n\tNL_POLICY_TYPE_ATTR_PAD = 11,\n\tNL_POLICY_TYPE_ATTR_MASK = 12,\n\t__NL_POLICY_TYPE_ATTR_MAX = 13,\n\tNL_POLICY_TYPE_ATTR_MAX = 12,\n};\n\nstruct netlink_policy_dump_state___2 {\n\tunsigned int policy_idx;\n\tunsigned int attr_idx;\n\tunsigned int n_alloc;\n\tstruct {\n\t\tconst struct nla_policy *policy;\n\t\tunsigned int maxtype;\n\t} policies[0];\n};\n\nstruct trace_event_raw_bpf_test_finish {\n\tstruct trace_entry ent;\n\tint err;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_bpf_test_finish {};\n\ntypedef void (*btf_trace_bpf_test_finish)(void *, int *);\n\nstruct bpf_test_timer {\n\tenum {\n\t\tNO_PREEMPT = 0,\n\t\tNO_MIGRATE = 1,\n\t} mode;\n\tu32 i;\n\tu64 time_start;\n\tu64 time_spent;\n};\n\nstruct bpf_fentry_test_t {\n\tstruct bpf_fentry_test_t *a;\n};\n\nstruct bpf_raw_tp_test_run_info {\n\tstruct bpf_prog *prog;\n\tvoid *ctx;\n\tu32 retval;\n};\n\nstruct ethtool_cmd {\n\t__u32 cmd;\n\t__u32 supported;\n\t__u32 advertising;\n\t__u16 speed;\n\t__u8 duplex;\n\t__u8 port;\n\t__u8 phy_address;\n\t__u8 transceiver;\n\t__u8 autoneg;\n\t__u8 mdio_support;\n\t__u32 maxtxpkt;\n\t__u32 maxrxpkt;\n\t__u16 speed_hi;\n\t__u8 eth_tp_mdix;\n\t__u8 eth_tp_mdix_ctrl;\n\t__u32 lp_advertising;\n\t__u32 reserved[2];\n};\n\nstruct ethtool_value {\n\t__u32 cmd;\n\t__u32 data;\n};\n\nenum tunable_id {\n\tETHTOOL_ID_UNSPEC = 0,\n\tETHTOOL_RX_COPYBREAK = 1,\n\tETHTOOL_TX_COPYBREAK = 2,\n\tETHTOOL_PFC_PREVENTION_TOUT = 3,\n\t__ETHTOOL_TUNABLE_COUNT = 4,\n};\n\nenum tunable_type_id {\n\tETHTOOL_TUNABLE_UNSPEC = 0,\n\tETHTOOL_TUNABLE_U8 = 1,\n\tETHTOOL_TUNABLE_U16 = 2,\n\tETHTOOL_TUNABLE_U32 = 3,\n\tETHTOOL_TUNABLE_U64 = 4,\n\tETHTOOL_TUNABLE_STRING = 5,\n\tETHTOOL_TUNABLE_S8 = 6,\n\tETHTOOL_TUNABLE_S16 = 7,\n\tETHTOOL_TUNABLE_S32 = 8,\n\tETHTOOL_TUNABLE_S64 = 9,\n};\n\nenum phy_tunable_id {\n\tETHTOOL_PHY_ID_UNSPEC = 0,\n\tETHTOOL_PHY_DOWNSHIFT = 1,\n\tETHTOOL_PHY_FAST_LINK_DOWN = 2,\n\tETHTOOL_PHY_EDPD = 3,\n\t__ETHTOOL_PHY_TUNABLE_COUNT = 4,\n};\n\nenum ethtool_stringset {\n\tETH_SS_TEST = 0,\n\tETH_SS_STATS = 1,\n\tETH_SS_PRIV_FLAGS = 2,\n\tETH_SS_NTUPLE_FILTERS = 3,\n\tETH_SS_FEATURES = 4,\n\tETH_SS_RSS_HASH_FUNCS = 5,\n\tETH_SS_TUNABLES = 6,\n\tETH_SS_PHY_STATS = 7,\n\tETH_SS_PHY_TUNABLES = 8,\n\tETH_SS_LINK_MODES = 9,\n\tETH_SS_MSG_CLASSES = 10,\n\tETH_SS_WOL_MODES = 11,\n\tETH_SS_SOF_TIMESTAMPING = 12,\n\tETH_SS_TS_TX_TYPES = 13,\n\tETH_SS_TS_RX_FILTERS = 14,\n\tETH_SS_UDP_TUNNEL_TYPES = 15,\n\tETH_SS_STATS_STD = 16,\n\tETH_SS_STATS_ETH_PHY = 17,\n\tETH_SS_STATS_ETH_MAC = 18,\n\tETH_SS_STATS_ETH_CTRL = 19,\n\tETH_SS_STATS_RMON = 20,\n\tETH_SS_COUNT = 21,\n};\n\nstruct ethtool_gstrings {\n\t__u32 cmd;\n\t__u32 string_set;\n\t__u32 len;\n\t__u8 data[0];\n};\n\nstruct ethtool_sset_info {\n\t__u32 cmd;\n\t__u32 reserved;\n\t__u64 sset_mask;\n\t__u32 data[0];\n};\n\nstruct ethtool_perm_addr {\n\t__u32 cmd;\n\t__u32 size;\n\t__u8 data[0];\n};\n\nenum ethtool_flags {\n\tETH_FLAG_TXVLAN = 128,\n\tETH_FLAG_RXVLAN = 256,\n\tETH_FLAG_LRO = 32768,\n\tETH_FLAG_NTUPLE = 134217728,\n\tETH_FLAG_RXHASH = 268435456,\n};\n\nstruct ethtool_rxfh {\n\t__u32 cmd;\n\t__u32 rss_context;\n\t__u32 indir_size;\n\t__u32 key_size;\n\t__u8 hfunc;\n\t__u8 rsvd8[3];\n\t__u32 rsvd32;\n\t__u32 rss_config[0];\n};\n\nstruct ethtool_get_features_block {\n\t__u32 available;\n\t__u32 requested;\n\t__u32 active;\n\t__u32 never_changed;\n};\n\nstruct ethtool_gfeatures {\n\t__u32 cmd;\n\t__u32 size;\n\tstruct ethtool_get_features_block features[0];\n};\n\nstruct ethtool_set_features_block {\n\t__u32 valid;\n\t__u32 requested;\n};\n\nstruct ethtool_sfeatures {\n\t__u32 cmd;\n\t__u32 size;\n\tstruct ethtool_set_features_block features[0];\n};\n\nenum ethtool_sfeatures_retval_bits {\n\tETHTOOL_F_UNSUPPORTED__BIT = 0,\n\tETHTOOL_F_WISH__BIT = 1,\n\tETHTOOL_F_COMPAT__BIT = 2,\n};\n\nstruct ethtool_per_queue_op {\n\t__u32 cmd;\n\t__u32 sub_command;\n\t__u32 queue_mask[128];\n\tchar data[0];\n};\n\nenum ethtool_fec_config_bits {\n\tETHTOOL_FEC_NONE_BIT = 0,\n\tETHTOOL_FEC_AUTO_BIT = 1,\n\tETHTOOL_FEC_OFF_BIT = 2,\n\tETHTOOL_FEC_RS_BIT = 3,\n\tETHTOOL_FEC_BASER_BIT = 4,\n\tETHTOOL_FEC_LLRS_BIT = 5,\n};\n\nenum {\n\tETH_RSS_HASH_TOP_BIT = 0,\n\tETH_RSS_HASH_XOR_BIT = 1,\n\tETH_RSS_HASH_CRC32_BIT = 2,\n\tETH_RSS_HASH_FUNCS_COUNT = 3,\n};\n\nstruct ethtool_rx_flow_rule {\n\tstruct flow_rule *rule;\n\tlong unsigned int priv[0];\n};\n\nstruct ethtool_rx_flow_spec_input {\n\tconst struct ethtool_rx_flow_spec *fs;\n\tu32 rss_ctx;\n};\n\nstruct ethtool_phy_ops {\n\tint (*get_sset_count)(struct phy_device *);\n\tint (*get_strings)(struct phy_device *, u8 *);\n\tint (*get_stats)(struct phy_device *, struct ethtool_stats *, u64 *);\n\tint (*start_cable_test)(struct phy_device *, struct netlink_ext_ack *);\n\tint (*start_cable_test_tdr)(struct phy_device *, struct netlink_ext_ack *, const struct phy_tdr_config *);\n};\n\nenum {\n\tETHTOOL_MSG_KERNEL_NONE = 0,\n\tETHTOOL_MSG_STRSET_GET_REPLY = 1,\n\tETHTOOL_MSG_LINKINFO_GET_REPLY = 2,\n\tETHTOOL_MSG_LINKINFO_NTF = 3,\n\tETHTOOL_MSG_LINKMODES_GET_REPLY = 4,\n\tETHTOOL_MSG_LINKMODES_NTF = 5,\n\tETHTOOL_MSG_LINKSTATE_GET_REPLY = 6,\n\tETHTOOL_MSG_DEBUG_GET_REPLY = 7,\n\tETHTOOL_MSG_DEBUG_NTF = 8,\n\tETHTOOL_MSG_WOL_GET_REPLY = 9,\n\tETHTOOL_MSG_WOL_NTF = 10,\n\tETHTOOL_MSG_FEATURES_GET_REPLY = 11,\n\tETHTOOL_MSG_FEATURES_SET_REPLY = 12,\n\tETHTOOL_MSG_FEATURES_NTF = 13,\n\tETHTOOL_MSG_PRIVFLAGS_GET_REPLY = 14,\n\tETHTOOL_MSG_PRIVFLAGS_NTF = 15,\n\tETHTOOL_MSG_RINGS_GET_REPLY = 16,\n\tETHTOOL_MSG_RINGS_NTF = 17,\n\tETHTOOL_MSG_CHANNELS_GET_REPLY = 18,\n\tETHTOOL_MSG_CHANNELS_NTF = 19,\n\tETHTOOL_MSG_COALESCE_GET_REPLY = 20,\n\tETHTOOL_MSG_COALESCE_NTF = 21,\n\tETHTOOL_MSG_PAUSE_GET_REPLY = 22,\n\tETHTOOL_MSG_PAUSE_NTF = 23,\n\tETHTOOL_MSG_EEE_GET_REPLY = 24,\n\tETHTOOL_MSG_EEE_NTF = 25,\n\tETHTOOL_MSG_TSINFO_GET_REPLY = 26,\n\tETHTOOL_MSG_CABLE_TEST_NTF = 27,\n\tETHTOOL_MSG_CABLE_TEST_TDR_NTF = 28,\n\tETHTOOL_MSG_TUNNEL_INFO_GET_REPLY = 29,\n\tETHTOOL_MSG_FEC_GET_REPLY = 30,\n\tETHTOOL_MSG_FEC_NTF = 31,\n\tETHTOOL_MSG_MODULE_EEPROM_GET_REPLY = 32,\n\tETHTOOL_MSG_STATS_GET_REPLY = 33,\n\tETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY = 34,\n\t__ETHTOOL_MSG_KERNEL_CNT = 35,\n\tETHTOOL_MSG_KERNEL_MAX = 34,\n};\n\nenum {\n\tETHTOOL_A_STATS_UNSPEC = 0,\n\tETHTOOL_A_STATS_PAD = 1,\n\tETHTOOL_A_STATS_HEADER = 2,\n\tETHTOOL_A_STATS_GROUPS = 3,\n\tETHTOOL_A_STATS_GRP = 4,\n\t__ETHTOOL_A_STATS_CNT = 5,\n\tETHTOOL_A_STATS_MAX = 4,\n};\n\nstruct ethtool_link_usettings {\n\tstruct ethtool_link_settings base;\n\tstruct {\n\t\t__u32 supported[3];\n\t\t__u32 advertising[3];\n\t\t__u32 lp_advertising[3];\n\t} link_modes;\n};\n\nstruct ethtool_rx_flow_key {\n\tstruct flow_dissector_key_basic basic;\n\tunion {\n\t\tstruct flow_dissector_key_ipv4_addrs ipv4;\n\t\tstruct flow_dissector_key_ipv6_addrs ipv6;\n\t};\n\tstruct flow_dissector_key_ports tp;\n\tstruct flow_dissector_key_ip ip;\n\tstruct flow_dissector_key_vlan vlan;\n\tstruct flow_dissector_key_eth_addrs eth_addrs;\n\tlong: 48;\n};\n\nstruct ethtool_rx_flow_match {\n\tstruct flow_dissector dissector;\n\tint: 32;\n\tstruct ethtool_rx_flow_key key;\n\tstruct ethtool_rx_flow_key mask;\n};\n\nenum {\n\tETHTOOL_UDP_TUNNEL_TYPE_VXLAN = 0,\n\tETHTOOL_UDP_TUNNEL_TYPE_GENEVE = 1,\n\tETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE = 2,\n\t__ETHTOOL_UDP_TUNNEL_TYPE_CNT = 3,\n};\n\nstruct link_mode_info {\n\tint speed;\n\tu8 lanes;\n\tu8 duplex;\n};\n\nenum {\n\tETHTOOL_MSG_USER_NONE = 0,\n\tETHTOOL_MSG_STRSET_GET = 1,\n\tETHTOOL_MSG_LINKINFO_GET = 2,\n\tETHTOOL_MSG_LINKINFO_SET = 3,\n\tETHTOOL_MSG_LINKMODES_GET = 4,\n\tETHTOOL_MSG_LINKMODES_SET = 5,\n\tETHTOOL_MSG_LINKSTATE_GET = 6,\n\tETHTOOL_MSG_DEBUG_GET = 7,\n\tETHTOOL_MSG_DEBUG_SET = 8,\n\tETHTOOL_MSG_WOL_GET = 9,\n\tETHTOOL_MSG_WOL_SET = 10,\n\tETHTOOL_MSG_FEATURES_GET = 11,\n\tETHTOOL_MSG_FEATURES_SET = 12,\n\tETHTOOL_MSG_PRIVFLAGS_GET = 13,\n\tETHTOOL_MSG_PRIVFLAGS_SET = 14,\n\tETHTOOL_MSG_RINGS_GET = 15,\n\tETHTOOL_MSG_RINGS_SET = 16,\n\tETHTOOL_MSG_CHANNELS_GET = 17,\n\tETHTOOL_MSG_CHANNELS_SET = 18,\n\tETHTOOL_MSG_COALESCE_GET = 19,\n\tETHTOOL_MSG_COALESCE_SET = 20,\n\tETHTOOL_MSG_PAUSE_GET = 21,\n\tETHTOOL_MSG_PAUSE_SET = 22,\n\tETHTOOL_MSG_EEE_GET = 23,\n\tETHTOOL_MSG_EEE_SET = 24,\n\tETHTOOL_MSG_TSINFO_GET = 25,\n\tETHTOOL_MSG_CABLE_TEST_ACT = 26,\n\tETHTOOL_MSG_CABLE_TEST_TDR_ACT = 27,\n\tETHTOOL_MSG_TUNNEL_INFO_GET = 28,\n\tETHTOOL_MSG_FEC_GET = 29,\n\tETHTOOL_MSG_FEC_SET = 30,\n\tETHTOOL_MSG_MODULE_EEPROM_GET = 31,\n\tETHTOOL_MSG_STATS_GET = 32,\n\tETHTOOL_MSG_PHC_VCLOCKS_GET = 33,\n\t__ETHTOOL_MSG_USER_CNT = 34,\n\tETHTOOL_MSG_USER_MAX = 33,\n};\n\nenum {\n\tETHTOOL_A_HEADER_UNSPEC = 0,\n\tETHTOOL_A_HEADER_DEV_INDEX = 1,\n\tETHTOOL_A_HEADER_DEV_NAME = 2,\n\tETHTOOL_A_HEADER_FLAGS = 3,\n\t__ETHTOOL_A_HEADER_CNT = 4,\n\tETHTOOL_A_HEADER_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_STRSET_UNSPEC = 0,\n\tETHTOOL_A_STRSET_HEADER = 1,\n\tETHTOOL_A_STRSET_STRINGSETS = 2,\n\tETHTOOL_A_STRSET_COUNTS_ONLY = 3,\n\t__ETHTOOL_A_STRSET_CNT = 4,\n\tETHTOOL_A_STRSET_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_LINKINFO_UNSPEC = 0,\n\tETHTOOL_A_LINKINFO_HEADER = 1,\n\tETHTOOL_A_LINKINFO_PORT = 2,\n\tETHTOOL_A_LINKINFO_PHYADDR = 3,\n\tETHTOOL_A_LINKINFO_TP_MDIX = 4,\n\tETHTOOL_A_LINKINFO_TP_MDIX_CTRL = 5,\n\tETHTOOL_A_LINKINFO_TRANSCEIVER = 6,\n\t__ETHTOOL_A_LINKINFO_CNT = 7,\n\tETHTOOL_A_LINKINFO_MAX = 6,\n};\n\nenum {\n\tETHTOOL_A_LINKMODES_UNSPEC = 0,\n\tETHTOOL_A_LINKMODES_HEADER = 1,\n\tETHTOOL_A_LINKMODES_AUTONEG = 2,\n\tETHTOOL_A_LINKMODES_OURS = 3,\n\tETHTOOL_A_LINKMODES_PEER = 4,\n\tETHTOOL_A_LINKMODES_SPEED = 5,\n\tETHTOOL_A_LINKMODES_DUPLEX = 6,\n\tETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG = 7,\n\tETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE = 8,\n\tETHTOOL_A_LINKMODES_LANES = 9,\n\t__ETHTOOL_A_LINKMODES_CNT = 10,\n\tETHTOOL_A_LINKMODES_MAX = 9,\n};\n\nenum {\n\tETHTOOL_A_LINKSTATE_UNSPEC = 0,\n\tETHTOOL_A_LINKSTATE_HEADER = 1,\n\tETHTOOL_A_LINKSTATE_LINK = 2,\n\tETHTOOL_A_LINKSTATE_SQI = 3,\n\tETHTOOL_A_LINKSTATE_SQI_MAX = 4,\n\tETHTOOL_A_LINKSTATE_EXT_STATE = 5,\n\tETHTOOL_A_LINKSTATE_EXT_SUBSTATE = 6,\n\t__ETHTOOL_A_LINKSTATE_CNT = 7,\n\tETHTOOL_A_LINKSTATE_MAX = 6,\n};\n\nenum {\n\tETHTOOL_A_DEBUG_UNSPEC = 0,\n\tETHTOOL_A_DEBUG_HEADER = 1,\n\tETHTOOL_A_DEBUG_MSGMASK = 2,\n\t__ETHTOOL_A_DEBUG_CNT = 3,\n\tETHTOOL_A_DEBUG_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_WOL_UNSPEC = 0,\n\tETHTOOL_A_WOL_HEADER = 1,\n\tETHTOOL_A_WOL_MODES = 2,\n\tETHTOOL_A_WOL_SOPASS = 3,\n\t__ETHTOOL_A_WOL_CNT = 4,\n\tETHTOOL_A_WOL_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_FEATURES_UNSPEC = 0,\n\tETHTOOL_A_FEATURES_HEADER = 1,\n\tETHTOOL_A_FEATURES_HW = 2,\n\tETHTOOL_A_FEATURES_WANTED = 3,\n\tETHTOOL_A_FEATURES_ACTIVE = 4,\n\tETHTOOL_A_FEATURES_NOCHANGE = 5,\n\t__ETHTOOL_A_FEATURES_CNT = 6,\n\tETHTOOL_A_FEATURES_MAX = 5,\n};\n\nenum {\n\tETHTOOL_A_PRIVFLAGS_UNSPEC = 0,\n\tETHTOOL_A_PRIVFLAGS_HEADER = 1,\n\tETHTOOL_A_PRIVFLAGS_FLAGS = 2,\n\t__ETHTOOL_A_PRIVFLAGS_CNT = 3,\n\tETHTOOL_A_PRIVFLAGS_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_RINGS_UNSPEC = 0,\n\tETHTOOL_A_RINGS_HEADER = 1,\n\tETHTOOL_A_RINGS_RX_MAX = 2,\n\tETHTOOL_A_RINGS_RX_MINI_MAX = 3,\n\tETHTOOL_A_RINGS_RX_JUMBO_MAX = 4,\n\tETHTOOL_A_RINGS_TX_MAX = 5,\n\tETHTOOL_A_RINGS_RX = 6,\n\tETHTOOL_A_RINGS_RX_MINI = 7,\n\tETHTOOL_A_RINGS_RX_JUMBO = 8,\n\tETHTOOL_A_RINGS_TX = 9,\n\t__ETHTOOL_A_RINGS_CNT = 10,\n\tETHTOOL_A_RINGS_MAX = 9,\n};\n\nenum {\n\tETHTOOL_A_CHANNELS_UNSPEC = 0,\n\tETHTOOL_A_CHANNELS_HEADER = 1,\n\tETHTOOL_A_CHANNELS_RX_MAX = 2,\n\tETHTOOL_A_CHANNELS_TX_MAX = 3,\n\tETHTOOL_A_CHANNELS_OTHER_MAX = 4,\n\tETHTOOL_A_CHANNELS_COMBINED_MAX = 5,\n\tETHTOOL_A_CHANNELS_RX_COUNT = 6,\n\tETHTOOL_A_CHANNELS_TX_COUNT = 7,\n\tETHTOOL_A_CHANNELS_OTHER_COUNT = 8,\n\tETHTOOL_A_CHANNELS_COMBINED_COUNT = 9,\n\t__ETHTOOL_A_CHANNELS_CNT = 10,\n\tETHTOOL_A_CHANNELS_MAX = 9,\n};\n\nenum {\n\tETHTOOL_A_COALESCE_UNSPEC = 0,\n\tETHTOOL_A_COALESCE_HEADER = 1,\n\tETHTOOL_A_COALESCE_RX_USECS = 2,\n\tETHTOOL_A_COALESCE_RX_MAX_FRAMES = 3,\n\tETHTOOL_A_COALESCE_RX_USECS_IRQ = 4,\n\tETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ = 5,\n\tETHTOOL_A_COALESCE_TX_USECS = 6,\n\tETHTOOL_A_COALESCE_TX_MAX_FRAMES = 7,\n\tETHTOOL_A_COALESCE_TX_USECS_IRQ = 8,\n\tETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ = 9,\n\tETHTOOL_A_COALESCE_STATS_BLOCK_USECS = 10,\n\tETHTOOL_A_COALESCE_USE_ADAPTIVE_RX = 11,\n\tETHTOOL_A_COALESCE_USE_ADAPTIVE_TX = 12,\n\tETHTOOL_A_COALESCE_PKT_RATE_LOW = 13,\n\tETHTOOL_A_COALESCE_RX_USECS_LOW = 14,\n\tETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW = 15,\n\tETHTOOL_A_COALESCE_TX_USECS_LOW = 16,\n\tETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW = 17,\n\tETHTOOL_A_COALESCE_PKT_RATE_HIGH = 18,\n\tETHTOOL_A_COALESCE_RX_USECS_HIGH = 19,\n\tETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH = 20,\n\tETHTOOL_A_COALESCE_TX_USECS_HIGH = 21,\n\tETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH = 22,\n\tETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 23,\n\t__ETHTOOL_A_COALESCE_CNT = 24,\n\tETHTOOL_A_COALESCE_MAX = 23,\n};\n\nenum {\n\tETHTOOL_A_PAUSE_UNSPEC = 0,\n\tETHTOOL_A_PAUSE_HEADER = 1,\n\tETHTOOL_A_PAUSE_AUTONEG = 2,\n\tETHTOOL_A_PAUSE_RX = 3,\n\tETHTOOL_A_PAUSE_TX = 4,\n\tETHTOOL_A_PAUSE_STATS = 5,\n\t__ETHTOOL_A_PAUSE_CNT = 6,\n\tETHTOOL_A_PAUSE_MAX = 5,\n};\n\nenum {\n\tETHTOOL_A_EEE_UNSPEC = 0,\n\tETHTOOL_A_EEE_HEADER = 1,\n\tETHTOOL_A_EEE_MODES_OURS = 2,\n\tETHTOOL_A_EEE_MODES_PEER = 3,\n\tETHTOOL_A_EEE_ACTIVE = 4,\n\tETHTOOL_A_EEE_ENABLED = 5,\n\tETHTOOL_A_EEE_TX_LPI_ENABLED = 6,\n\tETHTOOL_A_EEE_TX_LPI_TIMER = 7,\n\t__ETHTOOL_A_EEE_CNT = 8,\n\tETHTOOL_A_EEE_MAX = 7,\n};\n\nenum {\n\tETHTOOL_A_TSINFO_UNSPEC = 0,\n\tETHTOOL_A_TSINFO_HEADER = 1,\n\tETHTOOL_A_TSINFO_TIMESTAMPING = 2,\n\tETHTOOL_A_TSINFO_TX_TYPES = 3,\n\tETHTOOL_A_TSINFO_RX_FILTERS = 4,\n\tETHTOOL_A_TSINFO_PHC_INDEX = 5,\n\t__ETHTOOL_A_TSINFO_CNT = 6,\n\tETHTOOL_A_TSINFO_MAX = 5,\n};\n\nenum {\n\tETHTOOL_A_PHC_VCLOCKS_UNSPEC = 0,\n\tETHTOOL_A_PHC_VCLOCKS_HEADER = 1,\n\tETHTOOL_A_PHC_VCLOCKS_NUM = 2,\n\tETHTOOL_A_PHC_VCLOCKS_INDEX = 3,\n\t__ETHTOOL_A_PHC_VCLOCKS_CNT = 4,\n\tETHTOOL_A_PHC_VCLOCKS_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_CABLE_TEST_UNSPEC = 0,\n\tETHTOOL_A_CABLE_TEST_HEADER = 1,\n\t__ETHTOOL_A_CABLE_TEST_CNT = 2,\n\tETHTOOL_A_CABLE_TEST_MAX = 1,\n};\n\nenum {\n\tETHTOOL_A_CABLE_TEST_TDR_UNSPEC = 0,\n\tETHTOOL_A_CABLE_TEST_TDR_HEADER = 1,\n\tETHTOOL_A_CABLE_TEST_TDR_CFG = 2,\n\t__ETHTOOL_A_CABLE_TEST_TDR_CNT = 3,\n\tETHTOOL_A_CABLE_TEST_TDR_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_TUNNEL_INFO_UNSPEC = 0,\n\tETHTOOL_A_TUNNEL_INFO_HEADER = 1,\n\tETHTOOL_A_TUNNEL_INFO_UDP_PORTS = 2,\n\t__ETHTOOL_A_TUNNEL_INFO_CNT = 3,\n\tETHTOOL_A_TUNNEL_INFO_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_FEC_UNSPEC = 0,\n\tETHTOOL_A_FEC_HEADER = 1,\n\tETHTOOL_A_FEC_MODES = 2,\n\tETHTOOL_A_FEC_AUTO = 3,\n\tETHTOOL_A_FEC_ACTIVE = 4,\n\tETHTOOL_A_FEC_STATS = 5,\n\t__ETHTOOL_A_FEC_CNT = 6,\n\tETHTOOL_A_FEC_MAX = 5,\n};\n\nenum {\n\tETHTOOL_A_MODULE_EEPROM_UNSPEC = 0,\n\tETHTOOL_A_MODULE_EEPROM_HEADER = 1,\n\tETHTOOL_A_MODULE_EEPROM_OFFSET = 2,\n\tETHTOOL_A_MODULE_EEPROM_LENGTH = 3,\n\tETHTOOL_A_MODULE_EEPROM_PAGE = 4,\n\tETHTOOL_A_MODULE_EEPROM_BANK = 5,\n\tETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS = 6,\n\tETHTOOL_A_MODULE_EEPROM_DATA = 7,\n\t__ETHTOOL_A_MODULE_EEPROM_CNT = 8,\n\tETHTOOL_A_MODULE_EEPROM_MAX = 7,\n};\n\nenum {\n\tETHTOOL_STATS_ETH_PHY = 0,\n\tETHTOOL_STATS_ETH_MAC = 1,\n\tETHTOOL_STATS_ETH_CTRL = 2,\n\tETHTOOL_STATS_RMON = 3,\n\t__ETHTOOL_STATS_CNT = 4,\n};\n\nenum {\n\tETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR = 0,\n\t__ETHTOOL_A_STATS_ETH_PHY_CNT = 1,\n\tETHTOOL_A_STATS_ETH_PHY_MAX = 0,\n};\n\nenum {\n\tETHTOOL_A_STATS_ETH_MAC_2_TX_PKT = 0,\n\tETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL = 1,\n\tETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL = 2,\n\tETHTOOL_A_STATS_ETH_MAC_5_RX_PKT = 3,\n\tETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR = 4,\n\tETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR = 5,\n\tETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES = 6,\n\tETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER = 7,\n\tETHTOOL_A_STATS_ETH_MAC_10_LATE_COL = 8,\n\tETHTOOL_A_STATS_ETH_MAC_11_XS_COL = 9,\n\tETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR = 10,\n\tETHTOOL_A_STATS_ETH_MAC_13_CS_ERR = 11,\n\tETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES = 12,\n\tETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR = 13,\n\tETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST = 14,\n\tETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST = 15,\n\tETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER = 16,\n\tETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST = 17,\n\tETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST = 18,\n\tETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR = 19,\n\tETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN = 20,\n\tETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR = 21,\n\t__ETHTOOL_A_STATS_ETH_MAC_CNT = 22,\n\tETHTOOL_A_STATS_ETH_MAC_MAX = 21,\n};\n\nenum {\n\tETHTOOL_A_STATS_ETH_CTRL_3_TX = 0,\n\tETHTOOL_A_STATS_ETH_CTRL_4_RX = 1,\n\tETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP = 2,\n\t__ETHTOOL_A_STATS_ETH_CTRL_CNT = 3,\n\tETHTOOL_A_STATS_ETH_CTRL_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_STATS_RMON_UNDERSIZE = 0,\n\tETHTOOL_A_STATS_RMON_OVERSIZE = 1,\n\tETHTOOL_A_STATS_RMON_FRAG = 2,\n\tETHTOOL_A_STATS_RMON_JABBER = 3,\n\t__ETHTOOL_A_STATS_RMON_CNT = 4,\n\tETHTOOL_A_STATS_RMON_MAX = 3,\n};\n\nenum ethtool_multicast_groups {\n\tETHNL_MCGRP_MONITOR = 0,\n};\n\nstruct ethnl_req_info {\n\tstruct net_device *dev;\n\tu32 flags;\n};\n\nstruct ethnl_reply_data {\n\tstruct net_device *dev;\n};\n\nstruct ethnl_request_ops {\n\tu8 request_cmd;\n\tu8 reply_cmd;\n\tu16 hdr_attr;\n\tunsigned int req_info_size;\n\tunsigned int reply_data_size;\n\tbool allow_nodev_do;\n\tint (*parse_request)(struct ethnl_req_info *, struct nlattr **, struct netlink_ext_ack *);\n\tint (*prepare_data)(const struct ethnl_req_info *, struct ethnl_reply_data *, struct genl_info *);\n\tint (*reply_size)(const struct ethnl_req_info *, const struct ethnl_reply_data *);\n\tint (*fill_reply)(struct sk_buff *, const struct ethnl_req_info *, const struct ethnl_reply_data *);\n\tvoid (*cleanup_data)(struct ethnl_reply_data *);\n};\n\nstruct ethnl_dump_ctx {\n\tconst struct ethnl_request_ops *ops;\n\tstruct ethnl_req_info *req_info;\n\tstruct ethnl_reply_data *reply_data;\n\tint pos_hash;\n\tint pos_idx;\n};\n\ntypedef void (*ethnl_notify_handler_t)(struct net_device *, unsigned int, const void *);\n\nenum {\n\tETHTOOL_A_BITSET_BIT_UNSPEC = 0,\n\tETHTOOL_A_BITSET_BIT_INDEX = 1,\n\tETHTOOL_A_BITSET_BIT_NAME = 2,\n\tETHTOOL_A_BITSET_BIT_VALUE = 3,\n\t__ETHTOOL_A_BITSET_BIT_CNT = 4,\n\tETHTOOL_A_BITSET_BIT_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_BITSET_BITS_UNSPEC = 0,\n\tETHTOOL_A_BITSET_BITS_BIT = 1,\n\t__ETHTOOL_A_BITSET_BITS_CNT = 2,\n\tETHTOOL_A_BITSET_BITS_MAX = 1,\n};\n\nenum {\n\tETHTOOL_A_BITSET_UNSPEC = 0,\n\tETHTOOL_A_BITSET_NOMASK = 1,\n\tETHTOOL_A_BITSET_SIZE = 2,\n\tETHTOOL_A_BITSET_BITS = 3,\n\tETHTOOL_A_BITSET_VALUE = 4,\n\tETHTOOL_A_BITSET_MASK = 5,\n\t__ETHTOOL_A_BITSET_CNT = 6,\n\tETHTOOL_A_BITSET_MAX = 5,\n};\n\ntypedef const char (* const ethnl_string_array_t)[32];\n\nenum {\n\tETHTOOL_A_STRING_UNSPEC = 0,\n\tETHTOOL_A_STRING_INDEX = 1,\n\tETHTOOL_A_STRING_VALUE = 2,\n\t__ETHTOOL_A_STRING_CNT = 3,\n\tETHTOOL_A_STRING_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_STRINGS_UNSPEC = 0,\n\tETHTOOL_A_STRINGS_STRING = 1,\n\t__ETHTOOL_A_STRINGS_CNT = 2,\n\tETHTOOL_A_STRINGS_MAX = 1,\n};\n\nenum {\n\tETHTOOL_A_STRINGSET_UNSPEC = 0,\n\tETHTOOL_A_STRINGSET_ID = 1,\n\tETHTOOL_A_STRINGSET_COUNT = 2,\n\tETHTOOL_A_STRINGSET_STRINGS = 3,\n\t__ETHTOOL_A_STRINGSET_CNT = 4,\n\tETHTOOL_A_STRINGSET_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_STRINGSETS_UNSPEC = 0,\n\tETHTOOL_A_STRINGSETS_STRINGSET = 1,\n\t__ETHTOOL_A_STRINGSETS_CNT = 2,\n\tETHTOOL_A_STRINGSETS_MAX = 1,\n};\n\nstruct strset_info {\n\tbool per_dev;\n\tbool free_strings;\n\tunsigned int count;\n\tconst char (*strings)[32];\n};\n\nstruct strset_req_info {\n\tstruct ethnl_req_info base;\n\tu32 req_ids;\n\tbool counts_only;\n};\n\nstruct strset_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct strset_info sets[21];\n};\n\nstruct linkinfo_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_link_ksettings ksettings;\n\tstruct ethtool_link_settings *lsettings;\n};\n\nstruct linkmodes_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_link_ksettings ksettings;\n\tstruct ethtool_link_settings *lsettings;\n\tbool peer_empty;\n};\n\nstruct linkstate_reply_data {\n\tstruct ethnl_reply_data base;\n\tint link;\n\tint sqi;\n\tint sqi_max;\n\tbool link_ext_state_provided;\n\tstruct ethtool_link_ext_state_info ethtool_link_ext_state_info;\n};\n\nstruct debug_reply_data {\n\tstruct ethnl_reply_data base;\n\tu32 msg_mask;\n};\n\nstruct wol_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_wolinfo wol;\n\tbool show_sopass;\n};\n\nstruct features_reply_data {\n\tstruct ethnl_reply_data base;\n\tu32 hw[2];\n\tu32 wanted[2];\n\tu32 active[2];\n\tu32 nochange[2];\n\tu32 all[2];\n};\n\nstruct privflags_reply_data {\n\tstruct ethnl_reply_data base;\n\tconst char (*priv_flag_names)[32];\n\tunsigned int n_priv_flags;\n\tu32 priv_flags;\n};\n\nstruct rings_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_ringparam ringparam;\n};\n\nstruct channels_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_channels channels;\n};\n\nstruct coalesce_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_coalesce coalesce;\n\tu32 supported_params;\n};\n\nenum {\n\tETHTOOL_A_PAUSE_STAT_UNSPEC = 0,\n\tETHTOOL_A_PAUSE_STAT_PAD = 1,\n\tETHTOOL_A_PAUSE_STAT_TX_FRAMES = 2,\n\tETHTOOL_A_PAUSE_STAT_RX_FRAMES = 3,\n\t__ETHTOOL_A_PAUSE_STAT_CNT = 4,\n\tETHTOOL_A_PAUSE_STAT_MAX = 3,\n};\n\nstruct pause_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_pauseparam pauseparam;\n\tstruct ethtool_pause_stats pausestat;\n};\n\nstruct eee_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_eee eee;\n};\n\nstruct tsinfo_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_ts_info ts_info;\n};\n\nenum {\n\tETHTOOL_A_CABLE_PAIR_A = 0,\n\tETHTOOL_A_CABLE_PAIR_B = 1,\n\tETHTOOL_A_CABLE_PAIR_C = 2,\n\tETHTOOL_A_CABLE_PAIR_D = 3,\n};\n\nenum {\n\tETHTOOL_A_CABLE_RESULT_UNSPEC = 0,\n\tETHTOOL_A_CABLE_RESULT_PAIR = 1,\n\tETHTOOL_A_CABLE_RESULT_CODE = 2,\n\t__ETHTOOL_A_CABLE_RESULT_CNT = 3,\n\tETHTOOL_A_CABLE_RESULT_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC = 0,\n\tETHTOOL_A_CABLE_FAULT_LENGTH_PAIR = 1,\n\tETHTOOL_A_CABLE_FAULT_LENGTH_CM = 2,\n\t__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT = 3,\n\tETHTOOL_A_CABLE_FAULT_LENGTH_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_CABLE_TEST_NTF_STATUS_UNSPEC = 0,\n\tETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED = 1,\n\tETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED = 2,\n};\n\nenum {\n\tETHTOOL_A_CABLE_NEST_UNSPEC = 0,\n\tETHTOOL_A_CABLE_NEST_RESULT = 1,\n\tETHTOOL_A_CABLE_NEST_FAULT_LENGTH = 2,\n\t__ETHTOOL_A_CABLE_NEST_CNT = 3,\n\tETHTOOL_A_CABLE_NEST_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_CABLE_TEST_NTF_UNSPEC = 0,\n\tETHTOOL_A_CABLE_TEST_NTF_HEADER = 1,\n\tETHTOOL_A_CABLE_TEST_NTF_STATUS = 2,\n\tETHTOOL_A_CABLE_TEST_NTF_NEST = 3,\n\t__ETHTOOL_A_CABLE_TEST_NTF_CNT = 4,\n\tETHTOOL_A_CABLE_TEST_NTF_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_CABLE_TEST_TDR_CFG_UNSPEC = 0,\n\tETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST = 1,\n\tETHTOOL_A_CABLE_TEST_TDR_CFG_LAST = 2,\n\tETHTOOL_A_CABLE_TEST_TDR_CFG_STEP = 3,\n\tETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR = 4,\n\t__ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT = 5,\n\tETHTOOL_A_CABLE_TEST_TDR_CFG_MAX = 4,\n};\n\nenum {\n\tETHTOOL_A_CABLE_AMPLITUDE_UNSPEC = 0,\n\tETHTOOL_A_CABLE_AMPLITUDE_PAIR = 1,\n\tETHTOOL_A_CABLE_AMPLITUDE_mV = 2,\n\t__ETHTOOL_A_CABLE_AMPLITUDE_CNT = 3,\n\tETHTOOL_A_CABLE_AMPLITUDE_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_CABLE_PULSE_UNSPEC = 0,\n\tETHTOOL_A_CABLE_PULSE_mV = 1,\n\t__ETHTOOL_A_CABLE_PULSE_CNT = 2,\n\tETHTOOL_A_CABLE_PULSE_MAX = 1,\n};\n\nenum {\n\tETHTOOL_A_CABLE_STEP_UNSPEC = 0,\n\tETHTOOL_A_CABLE_STEP_FIRST_DISTANCE = 1,\n\tETHTOOL_A_CABLE_STEP_LAST_DISTANCE = 2,\n\tETHTOOL_A_CABLE_STEP_STEP_DISTANCE = 3,\n\t__ETHTOOL_A_CABLE_STEP_CNT = 4,\n\tETHTOOL_A_CABLE_STEP_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_CABLE_TDR_NEST_UNSPEC = 0,\n\tETHTOOL_A_CABLE_TDR_NEST_STEP = 1,\n\tETHTOOL_A_CABLE_TDR_NEST_AMPLITUDE = 2,\n\tETHTOOL_A_CABLE_TDR_NEST_PULSE = 3,\n\t__ETHTOOL_A_CABLE_TDR_NEST_CNT = 4,\n\tETHTOOL_A_CABLE_TDR_NEST_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_TUNNEL_UDP_ENTRY_UNSPEC = 0,\n\tETHTOOL_A_TUNNEL_UDP_ENTRY_PORT = 1,\n\tETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE = 2,\n\t__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT = 3,\n\tETHTOOL_A_TUNNEL_UDP_ENTRY_MAX = 2,\n};\n\nenum {\n\tETHTOOL_A_TUNNEL_UDP_TABLE_UNSPEC = 0,\n\tETHTOOL_A_TUNNEL_UDP_TABLE_SIZE = 1,\n\tETHTOOL_A_TUNNEL_UDP_TABLE_TYPES = 2,\n\tETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY = 3,\n\t__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT = 4,\n\tETHTOOL_A_TUNNEL_UDP_TABLE_MAX = 3,\n};\n\nenum {\n\tETHTOOL_A_TUNNEL_UDP_UNSPEC = 0,\n\tETHTOOL_A_TUNNEL_UDP_TABLE = 1,\n\t__ETHTOOL_A_TUNNEL_UDP_CNT = 2,\n\tETHTOOL_A_TUNNEL_UDP_MAX = 1,\n};\n\nenum udp_parsable_tunnel_type {\n\tUDP_TUNNEL_TYPE_VXLAN = 1,\n\tUDP_TUNNEL_TYPE_GENEVE = 2,\n\tUDP_TUNNEL_TYPE_VXLAN_GPE = 4,\n};\n\nenum udp_tunnel_nic_info_flags {\n\tUDP_TUNNEL_NIC_INFO_MAY_SLEEP = 1,\n\tUDP_TUNNEL_NIC_INFO_OPEN_ONLY = 2,\n\tUDP_TUNNEL_NIC_INFO_IPV4_ONLY = 4,\n\tUDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN = 8,\n};\n\nstruct udp_tunnel_nic_ops {\n\tvoid (*get_port)(struct net_device *, unsigned int, unsigned int, struct udp_tunnel_info *);\n\tvoid (*set_port_priv)(struct net_device *, unsigned int, unsigned int, u8);\n\tvoid (*add_port)(struct net_device *, struct udp_tunnel_info *);\n\tvoid (*del_port)(struct net_device *, struct udp_tunnel_info *);\n\tvoid (*reset_ntf)(struct net_device *);\n\tsize_t (*dump_size)(struct net_device *, unsigned int);\n\tint (*dump_write)(struct net_device *, unsigned int, struct sk_buff *);\n};\n\nstruct ethnl_tunnel_info_dump_ctx {\n\tstruct ethnl_req_info req_info;\n\tint pos_hash;\n\tint pos_idx;\n};\n\nenum {\n\tETHTOOL_A_FEC_STAT_UNSPEC = 0,\n\tETHTOOL_A_FEC_STAT_PAD = 1,\n\tETHTOOL_A_FEC_STAT_CORRECTED = 2,\n\tETHTOOL_A_FEC_STAT_UNCORR = 3,\n\tETHTOOL_A_FEC_STAT_CORR_BITS = 4,\n\t__ETHTOOL_A_FEC_STAT_CNT = 5,\n\tETHTOOL_A_FEC_STAT_MAX = 4,\n};\n\nstruct fec_stat_grp {\n\tu64 stats[9];\n\tu8 cnt;\n};\n\nstruct fec_reply_data {\n\tstruct ethnl_reply_data base;\n\tlong unsigned int fec_link_modes[2];\n\tu32 active_fec;\n\tu8 fec_auto;\n\tstruct fec_stat_grp corr;\n\tstruct fec_stat_grp uncorr;\n\tstruct fec_stat_grp corr_bits;\n};\n\nstruct eeprom_req_info {\n\tstruct ethnl_req_info base;\n\tu32 offset;\n\tu32 length;\n\tu8 page;\n\tu8 bank;\n\tu8 i2c_address;\n};\n\nstruct eeprom_reply_data {\n\tstruct ethnl_reply_data base;\n\tu32 length;\n\tu8 *data;\n};\n\nenum {\n\tETHTOOL_A_STATS_GRP_UNSPEC = 0,\n\tETHTOOL_A_STATS_GRP_PAD = 1,\n\tETHTOOL_A_STATS_GRP_ID = 2,\n\tETHTOOL_A_STATS_GRP_SS_ID = 3,\n\tETHTOOL_A_STATS_GRP_STAT = 4,\n\tETHTOOL_A_STATS_GRP_HIST_RX = 5,\n\tETHTOOL_A_STATS_GRP_HIST_TX = 6,\n\tETHTOOL_A_STATS_GRP_HIST_BKT_LOW = 7,\n\tETHTOOL_A_STATS_GRP_HIST_BKT_HI = 8,\n\tETHTOOL_A_STATS_GRP_HIST_VAL = 9,\n\t__ETHTOOL_A_STATS_GRP_CNT = 10,\n\tETHTOOL_A_STATS_GRP_MAX = 4,\n};\n\nstruct stats_req_info {\n\tstruct ethnl_req_info base;\n\tlong unsigned int stat_mask[1];\n};\n\nstruct stats_reply_data {\n\tstruct ethnl_reply_data base;\n\tstruct ethtool_eth_phy_stats phy_stats;\n\tstruct ethtool_eth_mac_stats mac_stats;\n\tstruct ethtool_eth_ctrl_stats ctrl_stats;\n\tstruct ethtool_rmon_stats rmon_stats;\n\tconst struct ethtool_rmon_hist_range *rmon_ranges;\n};\n\nstruct phc_vclocks_reply_data {\n\tstruct ethnl_reply_data base;\n\tint num;\n\tint *index;\n};\n\nstruct nf_hook_entries_rcu_head {\n\tstruct callback_head head;\n\tvoid *allocation;\n};\n\nstruct nf_conn___2;\n\nenum nf_nat_manip_type;\n\nstruct nf_nat_hook {\n\tint (*parse_nat_setup)(struct nf_conn___2 *, enum nf_nat_manip_type, const struct nlattr *);\n\tvoid (*decode_session)(struct sk_buff *, struct flowi *);\n\tunsigned int (*manip_pkt)(struct sk_buff *, struct nf_conn___2 *, enum nf_nat_manip_type, enum ip_conntrack_dir);\n};\n\nstruct nf_conntrack_tuple___2;\n\nstruct nf_ct_hook {\n\tint (*update)(struct net *, struct sk_buff *);\n\tvoid (*destroy)(struct nf_conntrack *);\n\tbool (*get_tuple_skb)(struct nf_conntrack_tuple___2 *, const struct sk_buff *);\n};\n\nstruct nfnl_ct_hook {\n\tsize_t (*build_size)(const struct nf_conn___2 *);\n\tint (*build)(struct sk_buff *, struct nf_conn___2 *, enum ip_conntrack_info, u_int16_t, u_int16_t);\n\tint (*parse)(const struct nlattr *, struct nf_conn___2 *);\n\tint (*attach_expect)(const struct nlattr *, struct nf_conn___2 *, u32, u32);\n\tvoid (*seq_adjust)(struct sk_buff *, struct nf_conn___2 *, enum ip_conntrack_info, s32);\n};\n\nstruct nf_ipv6_ops {\n\tvoid (*route_input)(struct sk_buff *);\n\tint (*fragment)(struct net *, struct sock *, struct sk_buff *, int (*)(struct net *, struct sock *, struct sk_buff *));\n\tint (*reroute)(struct sk_buff *, const struct nf_queue_entry *);\n};\n\nstruct nf_queue_entry {\n\tstruct list_head list;\n\tstruct sk_buff *skb;\n\tunsigned int id;\n\tunsigned int hook_index;\n\tstruct net_device *physin;\n\tstruct net_device *physout;\n\tstruct nf_hook_state state;\n\tu16 size;\n};\n\nstruct nf_loginfo {\n\tu_int8_t type;\n\tunion {\n\t\tstruct {\n\t\t\tu_int32_t copy_len;\n\t\t\tu_int16_t group;\n\t\t\tu_int16_t qthreshold;\n\t\t\tu_int16_t flags;\n\t\t} ulog;\n\t\tstruct {\n\t\t\tu_int8_t level;\n\t\t\tu_int8_t logflags;\n\t\t} log;\n\t} u;\n};\n\nstruct nf_log_buf {\n\tunsigned int count;\n\tchar buf[1020];\n};\n\nstruct nf_bridge_info {\n\tenum {\n\t\tBRNF_PROTO_UNCHANGED = 0,\n\t\tBRNF_PROTO_8021Q = 1,\n\t\tBRNF_PROTO_PPPOE = 2,\n\t} orig_proto: 8;\n\tu8 pkt_otherhost: 1;\n\tu8 in_prerouting: 1;\n\tu8 bridged_dnat: 1;\n\t__u16 frag_max_size;\n\tstruct net_device *physindev;\n\tstruct net_device *physoutdev;\n\tunion {\n\t\t__be32 ipv4_daddr;\n\t\tstruct in6_addr ipv6_daddr;\n\t\tchar neigh_header[8];\n\t};\n};\n\nstruct ip_rt_info {\n\t__be32 daddr;\n\t__be32 saddr;\n\tu_int8_t tos;\n\tu_int32_t mark;\n};\n\nstruct ip6_rt_info {\n\tstruct in6_addr daddr;\n\tstruct in6_addr saddr;\n\tu_int32_t mark;\n};\n\nstruct nf_sockopt_ops {\n\tstruct list_head list;\n\tu_int8_t pf;\n\tint set_optmin;\n\tint set_optmax;\n\tint (*set)(struct sock *, int, sockptr_t, unsigned int);\n\tint get_optmin;\n\tint get_optmax;\n\tint (*get)(struct sock *, int, void *, int *);\n\tstruct module *owner;\n};\n\nstruct ip_mreqn {\n\tstruct in_addr imr_multiaddr;\n\tstruct in_addr imr_address;\n\tint imr_ifindex;\n};\n\nstruct rtmsg {\n\tunsigned char rtm_family;\n\tunsigned char rtm_dst_len;\n\tunsigned char rtm_src_len;\n\tunsigned char rtm_tos;\n\tunsigned char rtm_table;\n\tunsigned char rtm_protocol;\n\tunsigned char rtm_scope;\n\tunsigned char rtm_type;\n\tunsigned int rtm_flags;\n};\n\nstruct rtvia {\n\t__kernel_sa_family_t rtvia_family;\n\t__u8 rtvia_addr[0];\n};\n\nstruct ip_sf_list;\n\nstruct ip_mc_list {\n\tstruct in_device *interface;\n\t__be32 multiaddr;\n\tunsigned int sfmode;\n\tstruct ip_sf_list *sources;\n\tstruct ip_sf_list *tomb;\n\tlong unsigned int sfcount[2];\n\tunion {\n\t\tstruct ip_mc_list *next;\n\t\tstruct ip_mc_list *next_rcu;\n\t};\n\tstruct ip_mc_list *next_hash;\n\tstruct timer_list timer;\n\tint users;\n\trefcount_t refcnt;\n\tspinlock_t lock;\n\tchar tm_running;\n\tchar reporter;\n\tchar unsolicit_count;\n\tchar loaded;\n\tunsigned char gsquery;\n\tunsigned char crcount;\n\tstruct callback_head rcu;\n};\n\nstruct ip_sf_socklist {\n\tunsigned int sl_max;\n\tunsigned int sl_count;\n\tstruct callback_head rcu;\n\t__be32 sl_addr[0];\n};\n\nstruct ip_mc_socklist {\n\tstruct ip_mc_socklist *next_rcu;\n\tstruct ip_mreqn multi;\n\tunsigned int sfmode;\n\tstruct ip_sf_socklist *sflist;\n\tstruct callback_head rcu;\n};\n\nstruct ip_sf_list {\n\tstruct ip_sf_list *sf_next;\n\tlong unsigned int sf_count[2];\n\t__be32 sf_inaddr;\n\tunsigned char sf_gsresp;\n\tunsigned char sf_oldin;\n\tunsigned char sf_crcount;\n};\n\nstruct ipv4_addr_key {\n\t__be32 addr;\n\tint vif;\n};\n\nstruct inetpeer_addr {\n\tunion {\n\t\tstruct ipv4_addr_key a4;\n\t\tstruct in6_addr a6;\n\t\tu32 key[4];\n\t};\n\t__u16 family;\n};\n\nstruct inet_peer {\n\tstruct rb_node rb_node;\n\tstruct inetpeer_addr daddr;\n\tu32 metrics[17];\n\tu32 rate_tokens;\n\tu32 n_redirects;\n\tlong unsigned int rate_last;\n\tunion {\n\t\tstruct {\n\t\t\tatomic_t rid;\n\t\t};\n\t\tstruct callback_head rcu;\n\t};\n\t__u32 dtime;\n\trefcount_t refcnt;\n};\n\nstruct fib_rt_info {\n\tstruct fib_info *fi;\n\tu32 tb_id;\n\t__be32 dst;\n\tint dst_len;\n\tu8 tos;\n\tu8 type;\n\tu8 offload: 1;\n\tu8 trap: 1;\n\tu8 offload_failed: 1;\n\tu8 unused: 5;\n};\n\nstruct uncached_list {\n\tspinlock_t lock;\n\tstruct list_head head;\n};\n\nstruct ip_rt_acct {\n\t__u32 o_bytes;\n\t__u32 o_packets;\n\t__u32 i_bytes;\n\t__u32 i_packets;\n};\n\nstruct rt_cache_stat {\n\tunsigned int in_slow_tot;\n\tunsigned int in_slow_mc;\n\tunsigned int in_no_route;\n\tunsigned int in_brd;\n\tunsigned int in_martian_dst;\n\tunsigned int in_martian_src;\n\tunsigned int out_slow_tot;\n\tunsigned int out_slow_mc;\n};\n\nstruct fib_alias {\n\tstruct hlist_node fa_list;\n\tstruct fib_info *fa_info;\n\tu8 fa_tos;\n\tu8 fa_type;\n\tu8 fa_state;\n\tu8 fa_slen;\n\tu32 tb_id;\n\ts16 fa_default;\n\tu8 offload: 1;\n\tu8 trap: 1;\n\tu8 offload_failed: 1;\n\tu8 unused: 5;\n\tstruct callback_head rcu;\n};\n\nstruct fib_prop {\n\tint error;\n\tu8 scope;\n};\n\nstruct net_offload {\n\tstruct offload_callbacks callbacks;\n\tunsigned int flags;\n};\n\nstruct raw_hashinfo {\n\trwlock_t lock;\n\tstruct hlist_head ht[256];\n};\n\nenum ip_defrag_users {\n\tIP_DEFRAG_LOCAL_DELIVER = 0,\n\tIP_DEFRAG_CALL_RA_CHAIN = 1,\n\tIP_DEFRAG_CONNTRACK_IN = 2,\n\t__IP_DEFRAG_CONNTRACK_IN_END = 65537,\n\tIP_DEFRAG_CONNTRACK_OUT = 65538,\n\t__IP_DEFRAG_CONNTRACK_OUT_END = 131073,\n\tIP_DEFRAG_CONNTRACK_BRIDGE_IN = 131074,\n\t__IP_DEFRAG_CONNTRACK_BRIDGE_IN = 196609,\n\tIP_DEFRAG_VS_IN = 196610,\n\tIP_DEFRAG_VS_OUT = 196611,\n\tIP_DEFRAG_VS_FWD = 196612,\n\tIP_DEFRAG_AF_PACKET = 196613,\n\tIP_DEFRAG_MACVLAN = 196614,\n};\n\nenum {\n\tINET_FRAG_FIRST_IN = 1,\n\tINET_FRAG_LAST_IN = 2,\n\tINET_FRAG_COMPLETE = 4,\n\tINET_FRAG_HASH_DEAD = 8,\n};\n\nstruct ipq {\n\tstruct inet_frag_queue q;\n\tu8 ecn;\n\tu16 max_df_size;\n\tint iif;\n\tunsigned int rid;\n\tstruct inet_peer *peer;\n};\n\nstruct ip_options_data {\n\tstruct ip_options_rcu opt;\n\tchar data[40];\n};\n\nstruct ipcm_cookie {\n\tstruct sockcm_cookie sockc;\n\t__be32 addr;\n\tint oif;\n\tstruct ip_options_rcu *opt;\n\t__u8 ttl;\n\t__s16 tos;\n\tchar priority;\n\t__u16 gso_size;\n};\n\nstruct ip_fraglist_iter {\n\tstruct sk_buff *frag;\n\tstruct iphdr *iph;\n\tint offset;\n\tunsigned int hlen;\n};\n\nstruct ip_frag_state {\n\tbool DF;\n\tunsigned int hlen;\n\tunsigned int ll_rs;\n\tunsigned int mtu;\n\tunsigned int left;\n\tint offset;\n\tint ptr;\n\t__be16 not_last_frag;\n};\n\nstruct ip_reply_arg {\n\tstruct kvec iov[1];\n\tint flags;\n\t__wsum csum;\n\tint csumoffset;\n\tint bound_dev_if;\n\tu8 tos;\n\tkuid_t uid;\n};\n\nstruct ip_mreq_source {\n\t__be32 imr_multiaddr;\n\t__be32 imr_interface;\n\t__be32 imr_sourceaddr;\n};\n\nstruct ip_msfilter {\n\t__be32 imsf_multiaddr;\n\t__be32 imsf_interface;\n\t__u32 imsf_fmode;\n\t__u32 imsf_numsrc;\n\t__be32 imsf_slist[1];\n};\n\nstruct group_req {\n\t__u32 gr_interface;\n\tstruct __kernel_sockaddr_storage gr_group;\n};\n\nstruct group_source_req {\n\t__u32 gsr_interface;\n\tstruct __kernel_sockaddr_storage gsr_group;\n\tstruct __kernel_sockaddr_storage gsr_source;\n};\n\nstruct group_filter {\n\t__u32 gf_interface;\n\tstruct __kernel_sockaddr_storage gf_group;\n\t__u32 gf_fmode;\n\t__u32 gf_numsrc;\n\tstruct __kernel_sockaddr_storage gf_slist[1];\n};\n\nstruct in_pktinfo {\n\tint ipi_ifindex;\n\tstruct in_addr ipi_spec_dst;\n\tstruct in_addr ipi_addr;\n};\n\nstruct compat_group_req {\n\t__u32 gr_interface;\n\tstruct __kernel_sockaddr_storage gr_group;\n} __attribute__((packed));\n\nstruct compat_group_source_req {\n\t__u32 gsr_interface;\n\tstruct __kernel_sockaddr_storage gsr_group;\n\tstruct __kernel_sockaddr_storage gsr_source;\n} __attribute__((packed));\n\nstruct compat_group_filter {\n\t__u32 gf_interface;\n\tstruct __kernel_sockaddr_storage gf_group;\n\t__u32 gf_fmode;\n\t__u32 gf_numsrc;\n\tstruct __kernel_sockaddr_storage gf_slist[1];\n} __attribute__((packed));\n\nstruct tcpvegas_info {\n\t__u32 tcpv_enabled;\n\t__u32 tcpv_rttcnt;\n\t__u32 tcpv_rtt;\n\t__u32 tcpv_minrtt;\n};\n\nstruct tcp_dctcp_info {\n\t__u16 dctcp_enabled;\n\t__u16 dctcp_ce_state;\n\t__u32 dctcp_alpha;\n\t__u32 dctcp_ab_ecn;\n\t__u32 dctcp_ab_tot;\n};\n\nstruct tcp_bbr_info {\n\t__u32 bbr_bw_lo;\n\t__u32 bbr_bw_hi;\n\t__u32 bbr_min_rtt;\n\t__u32 bbr_pacing_gain;\n\t__u32 bbr_cwnd_gain;\n};\n\nunion tcp_cc_info {\n\tstruct tcpvegas_info vegas;\n\tstruct tcp_dctcp_info dctcp;\n\tstruct tcp_bbr_info bbr;\n};\n\nenum {\n\tBPF_TCP_ESTABLISHED = 1,\n\tBPF_TCP_SYN_SENT = 2,\n\tBPF_TCP_SYN_RECV = 3,\n\tBPF_TCP_FIN_WAIT1 = 4,\n\tBPF_TCP_FIN_WAIT2 = 5,\n\tBPF_TCP_TIME_WAIT = 6,\n\tBPF_TCP_CLOSE = 7,\n\tBPF_TCP_CLOSE_WAIT = 8,\n\tBPF_TCP_LAST_ACK = 9,\n\tBPF_TCP_LISTEN = 10,\n\tBPF_TCP_CLOSING = 11,\n\tBPF_TCP_NEW_SYN_RECV = 12,\n\tBPF_TCP_MAX_STATES = 13,\n};\n\nenum inet_csk_ack_state_t {\n\tICSK_ACK_SCHED = 1,\n\tICSK_ACK_TIMER = 2,\n\tICSK_ACK_PUSHED = 4,\n\tICSK_ACK_PUSHED2 = 8,\n\tICSK_ACK_NOW = 16,\n};\n\nenum {\n\tTCP_FLAG_CWR = 32768,\n\tTCP_FLAG_ECE = 16384,\n\tTCP_FLAG_URG = 8192,\n\tTCP_FLAG_ACK = 4096,\n\tTCP_FLAG_PSH = 2048,\n\tTCP_FLAG_RST = 1024,\n\tTCP_FLAG_SYN = 512,\n\tTCP_FLAG_FIN = 256,\n\tTCP_RESERVED_BITS = 15,\n\tTCP_DATA_OFFSET = 240,\n};\n\nstruct tcp_repair_opt {\n\t__u32 opt_code;\n\t__u32 opt_val;\n};\n\nstruct tcp_repair_window {\n\t__u32 snd_wl1;\n\t__u32 snd_wnd;\n\t__u32 max_window;\n\t__u32 rcv_wnd;\n\t__u32 rcv_wup;\n};\n\nenum {\n\tTCP_NO_QUEUE = 0,\n\tTCP_RECV_QUEUE = 1,\n\tTCP_SEND_QUEUE = 2,\n\tTCP_QUEUES_NR = 3,\n};\n\nstruct tcp_info {\n\t__u8 tcpi_state;\n\t__u8 tcpi_ca_state;\n\t__u8 tcpi_retransmits;\n\t__u8 tcpi_probes;\n\t__u8 tcpi_backoff;\n\t__u8 tcpi_options;\n\t__u8 tcpi_snd_wscale: 4;\n\t__u8 tcpi_rcv_wscale: 4;\n\t__u8 tcpi_delivery_rate_app_limited: 1;\n\t__u8 tcpi_fastopen_client_fail: 2;\n\t__u32 tcpi_rto;\n\t__u32 tcpi_ato;\n\t__u32 tcpi_snd_mss;\n\t__u32 tcpi_rcv_mss;\n\t__u32 tcpi_unacked;\n\t__u32 tcpi_sacked;\n\t__u32 tcpi_lost;\n\t__u32 tcpi_retrans;\n\t__u32 tcpi_fackets;\n\t__u32 tcpi_last_data_sent;\n\t__u32 tcpi_last_ack_sent;\n\t__u32 tcpi_last_data_recv;\n\t__u32 tcpi_last_ack_recv;\n\t__u32 tcpi_pmtu;\n\t__u32 tcpi_rcv_ssthresh;\n\t__u32 tcpi_rtt;\n\t__u32 tcpi_rttvar;\n\t__u32 tcpi_snd_ssthresh;\n\t__u32 tcpi_snd_cwnd;\n\t__u32 tcpi_advmss;\n\t__u32 tcpi_reordering;\n\t__u32 tcpi_rcv_rtt;\n\t__u32 tcpi_rcv_space;\n\t__u32 tcpi_total_retrans;\n\t__u64 tcpi_pacing_rate;\n\t__u64 tcpi_max_pacing_rate;\n\t__u64 tcpi_bytes_acked;\n\t__u64 tcpi_bytes_received;\n\t__u32 tcpi_segs_out;\n\t__u32 tcpi_segs_in;\n\t__u32 tcpi_notsent_bytes;\n\t__u32 tcpi_min_rtt;\n\t__u32 tcpi_data_segs_in;\n\t__u32 tcpi_data_segs_out;\n\t__u64 tcpi_delivery_rate;\n\t__u64 tcpi_busy_time;\n\t__u64 tcpi_rwnd_limited;\n\t__u64 tcpi_sndbuf_limited;\n\t__u32 tcpi_delivered;\n\t__u32 tcpi_delivered_ce;\n\t__u64 tcpi_bytes_sent;\n\t__u64 tcpi_bytes_retrans;\n\t__u32 tcpi_dsack_dups;\n\t__u32 tcpi_reord_seen;\n\t__u32 tcpi_rcv_ooopack;\n\t__u32 tcpi_snd_wnd;\n};\n\nenum {\n\tTCP_NLA_PAD = 0,\n\tTCP_NLA_BUSY = 1,\n\tTCP_NLA_RWND_LIMITED = 2,\n\tTCP_NLA_SNDBUF_LIMITED = 3,\n\tTCP_NLA_DATA_SEGS_OUT = 4,\n\tTCP_NLA_TOTAL_RETRANS = 5,\n\tTCP_NLA_PACING_RATE = 6,\n\tTCP_NLA_DELIVERY_RATE = 7,\n\tTCP_NLA_SND_CWND = 8,\n\tTCP_NLA_REORDERING = 9,\n\tTCP_NLA_MIN_RTT = 10,\n\tTCP_NLA_RECUR_RETRANS = 11,\n\tTCP_NLA_DELIVERY_RATE_APP_LMT = 12,\n\tTCP_NLA_SNDQ_SIZE = 13,\n\tTCP_NLA_CA_STATE = 14,\n\tTCP_NLA_SND_SSTHRESH = 15,\n\tTCP_NLA_DELIVERED = 16,\n\tTCP_NLA_DELIVERED_CE = 17,\n\tTCP_NLA_BYTES_SENT = 18,\n\tTCP_NLA_BYTES_RETRANS = 19,\n\tTCP_NLA_DSACK_DUPS = 20,\n\tTCP_NLA_REORD_SEEN = 21,\n\tTCP_NLA_SRTT = 22,\n\tTCP_NLA_TIMEOUT_REHASH = 23,\n\tTCP_NLA_BYTES_NOTSENT = 24,\n\tTCP_NLA_EDT = 25,\n\tTCP_NLA_TTL = 26,\n};\n\nstruct tcp_zerocopy_receive {\n\t__u64 address;\n\t__u32 length;\n\t__u32 recv_skip_hint;\n\t__u32 inq;\n\t__s32 err;\n\t__u64 copybuf_address;\n\t__s32 copybuf_len;\n\t__u32 flags;\n\t__u64 msg_control;\n\t__u64 msg_controllen;\n\t__u32 msg_flags;\n\t__u32 reserved;\n};\n\nstruct tcp_md5sig_pool {\n\tstruct ahash_request *md5_req;\n\tvoid *scratch;\n};\n\nenum tcp_chrono {\n\tTCP_CHRONO_UNSPEC = 0,\n\tTCP_CHRONO_BUSY = 1,\n\tTCP_CHRONO_RWND_LIMITED = 2,\n\tTCP_CHRONO_SNDBUF_LIMITED = 3,\n\t__TCP_CHRONO_MAX = 4,\n};\n\nenum {\n\tTCP_CMSG_INQ = 1,\n\tTCP_CMSG_TS = 2,\n};\n\nstruct tcp_splice_state {\n\tstruct pipe_inode_info *pipe;\n\tsize_t len;\n\tunsigned int flags;\n};\n\nenum tcp_fastopen_client_fail {\n\tTFO_STATUS_UNSPEC = 0,\n\tTFO_COOKIE_UNAVAILABLE = 1,\n\tTFO_DATA_NOT_ACKED = 2,\n\tTFO_SYN_RETRANSMITTED = 3,\n};\n\nstruct tcp_sack_block_wire {\n\t__be32 start_seq;\n\t__be32 end_seq;\n};\n\nstruct static_key_false_deferred {\n\tstruct static_key_false key;\n\tlong unsigned int timeout;\n\tstruct delayed_work work;\n};\n\nstruct mptcp_ext {\n\tunion {\n\t\tu64 data_ack;\n\t\tu32 data_ack32;\n\t};\n\tu64 data_seq;\n\tu32 subflow_seq;\n\tu16 data_len;\n\t__sum16 csum;\n\tu8 use_map: 1;\n\tu8 dsn64: 1;\n\tu8 data_fin: 1;\n\tu8 use_ack: 1;\n\tu8 ack64: 1;\n\tu8 mpc_map: 1;\n\tu8 frozen: 1;\n\tu8 reset_transient: 1;\n\tu8 reset_reason: 4;\n\tu8 csum_reqd: 1;\n};\n\nenum tcp_queue {\n\tTCP_FRAG_IN_WRITE_QUEUE = 0,\n\tTCP_FRAG_IN_RTX_QUEUE = 1,\n};\n\nenum tcp_ca_ack_event_flags {\n\tCA_ACK_SLOWPATH = 1,\n\tCA_ACK_WIN_UPDATE = 2,\n\tCA_ACK_ECE = 4,\n};\n\nstruct tcp_sacktag_state {\n\tu64 first_sackt;\n\tu64 last_sackt;\n\tu32 reord;\n\tu32 sack_delivered;\n\tint flag;\n\tunsigned int mss_now;\n\tstruct rate_sample *rate;\n};\n\nenum pkt_hash_types {\n\tPKT_HASH_TYPE_NONE = 0,\n\tPKT_HASH_TYPE_L2 = 1,\n\tPKT_HASH_TYPE_L3 = 2,\n\tPKT_HASH_TYPE_L4 = 3,\n};\n\nenum {\n\tBPF_WRITE_HDR_TCP_CURRENT_MSS = 1,\n\tBPF_WRITE_HDR_TCP_SYNACK_COOKIE = 2,\n};\n\nenum tsq_flags {\n\tTSQF_THROTTLED = 1,\n\tTSQF_QUEUED = 2,\n\tTCPF_TSQ_DEFERRED = 4,\n\tTCPF_WRITE_TIMER_DEFERRED = 8,\n\tTCPF_DELACK_TIMER_DEFERRED = 16,\n\tTCPF_MTU_REDUCED_DEFERRED = 32,\n};\n\nstruct mptcp_rm_list {\n\tu8 ids[8];\n\tu8 nr;\n};\n\nstruct mptcp_addr_info {\n\tu8 id;\n\tsa_family_t family;\n\t__be16 port;\n\tunion {\n\t\tstruct in_addr addr;\n\t\tstruct in6_addr addr6;\n\t};\n};\n\nstruct mptcp_out_options {\n\tu16 suboptions;\n\tu64 sndr_key;\n\tu64 rcvr_key;\n\tu64 ahmac;\n\tstruct mptcp_addr_info addr;\n\tstruct mptcp_rm_list rm_list;\n\tu8 join_id;\n\tu8 backup;\n\tu8 reset_reason: 4;\n\tu8 reset_transient: 1;\n\tu8 csum_reqd: 1;\n\tu8 allow_join_id0: 1;\n\tu32 nonce;\n\tu64 thmac;\n\tu32 token;\n\tu8 hmac[20];\n\tstruct mptcp_ext ext_copy;\n};\n\nstruct tcp_out_options {\n\tu16 options;\n\tu16 mss;\n\tu8 ws;\n\tu8 num_sack_blocks;\n\tu8 hash_size;\n\tu8 bpf_opt_len;\n\t__u8 *hash_location;\n\t__u32 tsval;\n\t__u32 tsecr;\n\tstruct tcp_fastopen_cookie *fastopen_cookie;\n\tstruct mptcp_out_options mptcp;\n};\n\nstruct tsq_tasklet {\n\tstruct tasklet_struct tasklet;\n\tstruct list_head head;\n};\n\nstruct tcp_md5sig {\n\tstruct __kernel_sockaddr_storage tcpm_addr;\n\t__u8 tcpm_flags;\n\t__u8 tcpm_prefixlen;\n\t__u16 tcpm_keylen;\n\tint tcpm_ifindex;\n\t__u8 tcpm_key[80];\n};\n\nstruct icmp_err {\n\tint errno;\n\tunsigned int fatal: 1;\n};\n\nenum tcp_tw_status {\n\tTCP_TW_SUCCESS = 0,\n\tTCP_TW_RST = 1,\n\tTCP_TW_ACK = 2,\n\tTCP_TW_SYN = 3,\n};\n\nstruct tcp4_pseudohdr {\n\t__be32 saddr;\n\t__be32 daddr;\n\t__u8 pad;\n\t__u8 protocol;\n\t__be16 len;\n};\n\nenum tcp_seq_states {\n\tTCP_SEQ_STATE_LISTENING = 0,\n\tTCP_SEQ_STATE_ESTABLISHED = 1,\n};\n\nstruct tcp_seq_afinfo {\n\tsa_family_t family;\n};\n\nstruct tcp_iter_state {\n\tstruct seq_net_private p;\n\tenum tcp_seq_states state;\n\tstruct sock *syn_wait_sk;\n\tstruct tcp_seq_afinfo *bpf_seq_afinfo;\n\tint bucket;\n\tint offset;\n\tint sbucket;\n\tint num;\n\tloff_t last_pos;\n};\n\nstruct bpf_iter__tcp {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct sock_common *sk_common;\n\t};\n\tuid_t uid;\n};\n\nenum tcp_metric_index {\n\tTCP_METRIC_RTT = 0,\n\tTCP_METRIC_RTTVAR = 1,\n\tTCP_METRIC_SSTHRESH = 2,\n\tTCP_METRIC_CWND = 3,\n\tTCP_METRIC_REORDERING = 4,\n\tTCP_METRIC_RTT_US = 5,\n\tTCP_METRIC_RTTVAR_US = 6,\n\t__TCP_METRIC_MAX = 7,\n};\n\nenum {\n\tTCP_METRICS_ATTR_UNSPEC = 0,\n\tTCP_METRICS_ATTR_ADDR_IPV4 = 1,\n\tTCP_METRICS_ATTR_ADDR_IPV6 = 2,\n\tTCP_METRICS_ATTR_AGE = 3,\n\tTCP_METRICS_ATTR_TW_TSVAL = 4,\n\tTCP_METRICS_ATTR_TW_TS_STAMP = 5,\n\tTCP_METRICS_ATTR_VALS = 6,\n\tTCP_METRICS_ATTR_FOPEN_MSS = 7,\n\tTCP_METRICS_ATTR_FOPEN_SYN_DROPS = 8,\n\tTCP_METRICS_ATTR_FOPEN_SYN_DROP_TS = 9,\n\tTCP_METRICS_ATTR_FOPEN_COOKIE = 10,\n\tTCP_METRICS_ATTR_SADDR_IPV4 = 11,\n\tTCP_METRICS_ATTR_SADDR_IPV6 = 12,\n\tTCP_METRICS_ATTR_PAD = 13,\n\t__TCP_METRICS_ATTR_MAX = 14,\n};\n\nenum {\n\tTCP_METRICS_CMD_UNSPEC = 0,\n\tTCP_METRICS_CMD_GET = 1,\n\tTCP_METRICS_CMD_DEL = 2,\n\t__TCP_METRICS_CMD_MAX = 3,\n};\n\nstruct tcp_fastopen_metrics {\n\tu16 mss;\n\tu16 syn_loss: 10;\n\tu16 try_exp: 2;\n\tlong unsigned int last_syn_loss;\n\tstruct tcp_fastopen_cookie cookie;\n};\n\nstruct tcp_metrics_block {\n\tstruct tcp_metrics_block *tcpm_next;\n\tpossible_net_t tcpm_net;\n\tstruct inetpeer_addr tcpm_saddr;\n\tstruct inetpeer_addr tcpm_daddr;\n\tlong unsigned int tcpm_stamp;\n\tu32 tcpm_lock;\n\tu32 tcpm_vals[5];\n\tstruct tcp_fastopen_metrics tcpm_fastopen;\n\tstruct callback_head callback_head;\n};\n\nstruct tcpm_hash_bucket {\n\tstruct tcp_metrics_block *chain;\n};\n\nstruct icmp_filter {\n\t__u32 data;\n};\n\nstruct raw_iter_state {\n\tstruct seq_net_private p;\n\tint bucket;\n};\n\nstruct raw_sock {\n\tstruct inet_sock inet;\n\tstruct icmp_filter filter;\n\tu32 ipmr_table;\n};\n\nstruct raw_frag_vec {\n\tstruct msghdr *msg;\n\tunion {\n\t\tstruct icmphdr icmph;\n\t\tchar c[1];\n\t} hdr;\n\tint hlen;\n};\n\nstruct ip_tunnel_encap {\n\tu16 type;\n\tu16 flags;\n\t__be16 sport;\n\t__be16 dport;\n};\n\nstruct ip_tunnel_encap_ops {\n\tsize_t (*encap_hlen)(struct ip_tunnel_encap *);\n\tint (*build_header)(struct sk_buff *, struct ip_tunnel_encap *, u8 *, struct flowi4 *);\n\tint (*err_handler)(struct sk_buff *, u32);\n};\n\nstruct udp_skb_cb {\n\tunion {\n\t\tstruct inet_skb_parm h4;\n\t\tstruct inet6_skb_parm h6;\n\t} header;\n\t__u16 cscov;\n\t__u8 partial_cov;\n};\n\nstruct udp_dev_scratch {\n\tu32 _tsize_state;\n\tu16 len;\n\tbool is_linear;\n\tbool csum_unnecessary;\n};\n\nstruct udp_seq_afinfo {\n\tsa_family_t family;\n\tstruct udp_table *udp_table;\n};\n\nstruct udp_iter_state {\n\tstruct seq_net_private p;\n\tint bucket;\n\tstruct udp_seq_afinfo *bpf_seq_afinfo;\n};\n\nstruct bpf_iter__udp {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct udp_sock *udp_sk;\n\t};\n\tuid_t uid;\n\tint: 32;\n\tint bucket;\n};\n\nstruct inet_protosw {\n\tstruct list_head list;\n\tshort unsigned int type;\n\tshort unsigned int protocol;\n\tstruct proto *prot;\n\tconst struct proto_ops *ops;\n\tunsigned char flags;\n};\n\ntypedef struct sk_buff * (*gro_receive_t)(struct list_head *, struct sk_buff *);\n\ntypedef struct sk_buff * (*gro_receive_sk_t)(struct sock *, struct list_head *, struct sk_buff *);\n\ntypedef struct sock * (*udp_lookup_t)(const struct sk_buff *, __be16, __be16);\n\nstruct arpreq {\n\tstruct sockaddr arp_pa;\n\tstruct sockaddr arp_ha;\n\tint arp_flags;\n\tstruct sockaddr arp_netmask;\n\tchar arp_dev[16];\n};\n\ntypedef struct {\n\tchar ax25_call[7];\n} ax25_address;\n\nenum {\n\tAX25_VALUES_IPDEFMODE = 0,\n\tAX25_VALUES_AXDEFMODE = 1,\n\tAX25_VALUES_BACKOFF = 2,\n\tAX25_VALUES_CONMODE = 3,\n\tAX25_VALUES_WINDOW = 4,\n\tAX25_VALUES_EWINDOW = 5,\n\tAX25_VALUES_T1 = 6,\n\tAX25_VALUES_T2 = 7,\n\tAX25_VALUES_T3 = 8,\n\tAX25_VALUES_IDLE = 9,\n\tAX25_VALUES_N2 = 10,\n\tAX25_VALUES_PACLEN = 11,\n\tAX25_VALUES_PROTOCOL = 12,\n\tAX25_VALUES_DS_TIMEOUT = 13,\n\tAX25_MAX_VALUES = 14,\n};\n\nenum ip_conntrack_status {\n\tIPS_EXPECTED_BIT = 0,\n\tIPS_EXPECTED = 1,\n\tIPS_SEEN_REPLY_BIT = 1,\n\tIPS_SEEN_REPLY = 2,\n\tIPS_ASSURED_BIT = 2,\n\tIPS_ASSURED = 4,\n\tIPS_CONFIRMED_BIT = 3,\n\tIPS_CONFIRMED = 8,\n\tIPS_SRC_NAT_BIT = 4,\n\tIPS_SRC_NAT = 16,\n\tIPS_DST_NAT_BIT = 5,\n\tIPS_DST_NAT = 32,\n\tIPS_NAT_MASK = 48,\n\tIPS_SEQ_ADJUST_BIT = 6,\n\tIPS_SEQ_ADJUST = 64,\n\tIPS_SRC_NAT_DONE_BIT = 7,\n\tIPS_SRC_NAT_DONE = 128,\n\tIPS_DST_NAT_DONE_BIT = 8,\n\tIPS_DST_NAT_DONE = 256,\n\tIPS_NAT_DONE_MASK = 384,\n\tIPS_DYING_BIT = 9,\n\tIPS_DYING = 512,\n\tIPS_FIXED_TIMEOUT_BIT = 10,\n\tIPS_FIXED_TIMEOUT = 1024,\n\tIPS_TEMPLATE_BIT = 11,\n\tIPS_TEMPLATE = 2048,\n\tIPS_UNTRACKED_BIT = 12,\n\tIPS_UNTRACKED = 4096,\n\tIPS_NAT_CLASH_BIT = 12,\n\tIPS_NAT_CLASH = 4096,\n\tIPS_HELPER_BIT = 13,\n\tIPS_HELPER = 8192,\n\tIPS_OFFLOAD_BIT = 14,\n\tIPS_OFFLOAD = 16384,\n\tIPS_HW_OFFLOAD_BIT = 15,\n\tIPS_HW_OFFLOAD = 32768,\n\tIPS_UNCHANGEABLE_MASK = 56313,\n\t__IPS_MAX_BIT = 16,\n};\n\nenum {\n\tXFRM_LOOKUP_ICMP = 1,\n\tXFRM_LOOKUP_QUEUE = 2,\n\tXFRM_LOOKUP_KEEP_DST_REF = 4,\n};\n\nstruct icmp_ext_hdr {\n\t__u8 reserved1: 4;\n\t__u8 version: 4;\n\t__u8 reserved2;\n\t__sum16 checksum;\n};\n\nstruct icmp_extobj_hdr {\n\t__be16 length;\n\t__u8 class_num;\n\t__u8 class_type;\n};\n\nstruct icmp_ext_echo_ctype3_hdr {\n\t__be16 afi;\n\t__u8 addrlen;\n\t__u8 reserved;\n};\n\nstruct icmp_ext_echo_iio {\n\tstruct icmp_extobj_hdr extobj_hdr;\n\tunion {\n\t\tchar name[16];\n\t\t__be32 ifindex;\n\t\tstruct {\n\t\t\tstruct icmp_ext_echo_ctype3_hdr ctype3_hdr;\n\t\t\tunion {\n\t\t\t\t__be32 ipv4_addr;\n\t\t\t\tstruct in6_addr ipv6_addr;\n\t\t\t} ip_addr;\n\t\t} addr;\n\t} ident;\n};\n\nstruct icmp_bxm {\n\tstruct sk_buff *skb;\n\tint offset;\n\tint data_len;\n\tstruct {\n\t\tstruct icmphdr icmph;\n\t\t__be32 times[3];\n\t} data;\n\tint head_len;\n\tstruct ip_options_data replyopts;\n};\n\nstruct icmp_control {\n\tbool (*handler)(struct sk_buff *);\n\tshort int error;\n};\n\nstruct ifaddrmsg {\n\t__u8 ifa_family;\n\t__u8 ifa_prefixlen;\n\t__u8 ifa_flags;\n\t__u8 ifa_scope;\n\t__u32 ifa_index;\n};\n\nenum {\n\tIFA_UNSPEC = 0,\n\tIFA_ADDRESS = 1,\n\tIFA_LOCAL = 2,\n\tIFA_LABEL = 3,\n\tIFA_BROADCAST = 4,\n\tIFA_ANYCAST = 5,\n\tIFA_CACHEINFO = 6,\n\tIFA_MULTICAST = 7,\n\tIFA_FLAGS = 8,\n\tIFA_RT_PRIORITY = 9,\n\tIFA_TARGET_NETNSID = 10,\n\t__IFA_MAX = 11,\n};\n\nstruct ifa_cacheinfo {\n\t__u32 ifa_prefered;\n\t__u32 ifa_valid;\n\t__u32 cstamp;\n\t__u32 tstamp;\n};\n\nenum {\n\tIFLA_INET_UNSPEC = 0,\n\tIFLA_INET_CONF = 1,\n\t__IFLA_INET_MAX = 2,\n};\n\nstruct in_validator_info {\n\t__be32 ivi_addr;\n\tstruct in_device *ivi_dev;\n\tstruct netlink_ext_ack *extack;\n};\n\nstruct netconfmsg {\n\t__u8 ncm_family;\n};\n\nenum {\n\tNETCONFA_UNSPEC = 0,\n\tNETCONFA_IFINDEX = 1,\n\tNETCONFA_FORWARDING = 2,\n\tNETCONFA_RP_FILTER = 3,\n\tNETCONFA_MC_FORWARDING = 4,\n\tNETCONFA_PROXY_NEIGH = 5,\n\tNETCONFA_IGNORE_ROUTES_WITH_LINKDOWN = 6,\n\tNETCONFA_INPUT = 7,\n\tNETCONFA_BC_FORWARDING = 8,\n\t__NETCONFA_MAX = 9,\n};\n\nstruct inet_fill_args {\n\tu32 portid;\n\tu32 seq;\n\tint event;\n\tunsigned int flags;\n\tint netnsid;\n\tint ifindex;\n};\n\nstruct devinet_sysctl_table {\n\tstruct ctl_table_header *sysctl_header;\n\tstruct ctl_table devinet_vars[33];\n};\n\nstruct rtentry {\n\tlong unsigned int rt_pad1;\n\tstruct sockaddr rt_dst;\n\tstruct sockaddr rt_gateway;\n\tstruct sockaddr rt_genmask;\n\tshort unsigned int rt_flags;\n\tshort int rt_pad2;\n\tlong unsigned int rt_pad3;\n\tvoid *rt_pad4;\n\tshort int rt_metric;\n\tchar *rt_dev;\n\tlong unsigned int rt_mtu;\n\tlong unsigned int rt_window;\n\tshort unsigned int rt_irtt;\n};\n\nstruct pingv6_ops {\n\tint (*ipv6_recv_error)(struct sock *, struct msghdr *, int, int *);\n\tvoid (*ip6_datagram_recv_common_ctl)(struct sock *, struct msghdr *, struct sk_buff *);\n\tvoid (*ip6_datagram_recv_specific_ctl)(struct sock *, struct msghdr *, struct sk_buff *);\n\tint (*icmpv6_err_convert)(u8, u8, int *);\n\tvoid (*ipv6_icmp_error)(struct sock *, struct sk_buff *, int, __be16, u32, u8 *);\n\tint (*ipv6_chk_addr)(struct net *, const struct in6_addr *, const struct net_device *, int);\n};\n\nstruct compat_rtentry {\n\tu32 rt_pad1;\n\tstruct sockaddr rt_dst;\n\tstruct sockaddr rt_gateway;\n\tstruct sockaddr rt_genmask;\n\tshort unsigned int rt_flags;\n\tshort int rt_pad2;\n\tu32 rt_pad3;\n\tunsigned char rt_tos;\n\tunsigned char rt_class;\n\tshort int rt_pad4;\n\tshort int rt_metric;\n\tcompat_uptr_t rt_dev;\n\tu32 rt_mtu;\n\tu32 rt_window;\n\tshort unsigned int rt_irtt;\n};\n\nstruct igmphdr {\n\t__u8 type;\n\t__u8 code;\n\t__sum16 csum;\n\t__be32 group;\n};\n\nstruct igmpv3_grec {\n\t__u8 grec_type;\n\t__u8 grec_auxwords;\n\t__be16 grec_nsrcs;\n\t__be32 grec_mca;\n\t__be32 grec_src[0];\n};\n\nstruct igmpv3_report {\n\t__u8 type;\n\t__u8 resv1;\n\t__sum16 csum;\n\t__be16 resv2;\n\t__be16 ngrec;\n\tstruct igmpv3_grec grec[0];\n};\n\nstruct igmpv3_query {\n\t__u8 type;\n\t__u8 code;\n\t__sum16 csum;\n\t__be32 group;\n\t__u8 qrv: 3;\n\t__u8 suppress: 1;\n\t__u8 resv: 4;\n\t__u8 qqic;\n\t__be16 nsrcs;\n\t__be32 srcs[0];\n};\n\nstruct igmp_mc_iter_state {\n\tstruct seq_net_private p;\n\tstruct net_device *dev;\n\tstruct in_device *in_dev;\n};\n\nstruct igmp_mcf_iter_state {\n\tstruct seq_net_private p;\n\tstruct net_device *dev;\n\tstruct in_device *idev;\n\tstruct ip_mc_list *im;\n};\n\nstruct fib_config {\n\tu8 fc_dst_len;\n\tu8 fc_tos;\n\tu8 fc_protocol;\n\tu8 fc_scope;\n\tu8 fc_type;\n\tu8 fc_gw_family;\n\tu32 fc_table;\n\t__be32 fc_dst;\n\tunion {\n\t\t__be32 fc_gw4;\n\t\tstruct in6_addr fc_gw6;\n\t};\n\tint fc_oif;\n\tu32 fc_flags;\n\tu32 fc_priority;\n\t__be32 fc_prefsrc;\n\tu32 fc_nh_id;\n\tstruct nlattr *fc_mx;\n\tstruct rtnexthop *fc_mp;\n\tint fc_mx_len;\n\tint fc_mp_len;\n\tu32 fc_flow;\n\tu32 fc_nlflags;\n\tstruct nl_info fc_nlinfo;\n\tstruct nlattr *fc_encap;\n\tu16 fc_encap_type;\n};\n\nstruct fib_result_nl {\n\t__be32 fl_addr;\n\tu32 fl_mark;\n\tunsigned char fl_tos;\n\tunsigned char fl_scope;\n\tunsigned char tb_id_in;\n\tunsigned char tb_id;\n\tunsigned char prefixlen;\n\tunsigned char nh_sel;\n\tunsigned char type;\n\tunsigned char scope;\n\tint err;\n};\n\nstruct fib_dump_filter {\n\tu32 table_id;\n\tbool filter_set;\n\tbool dump_routes;\n\tbool dump_exceptions;\n\tunsigned char protocol;\n\tunsigned char rt_type;\n\tunsigned int flags;\n\tstruct net_device *dev;\n};\n\nstruct fib_nh_notifier_info {\n\tstruct fib_notifier_info info;\n\tstruct fib_nh *fib_nh;\n};\n\nstruct fib_entry_notifier_info {\n\tstruct fib_notifier_info info;\n\tu32 dst;\n\tint dst_len;\n\tstruct fib_info *fi;\n\tu8 tos;\n\tu8 type;\n\tu32 tb_id;\n};\n\ntypedef unsigned int t_key;\n\nstruct key_vector {\n\tt_key key;\n\tunsigned char pos;\n\tunsigned char bits;\n\tunsigned char slen;\n\tunion {\n\t\tstruct hlist_head leaf;\n\t\tstruct key_vector *tnode[0];\n\t};\n};\n\nstruct tnode {\n\tstruct callback_head rcu;\n\tt_key empty_children;\n\tt_key full_children;\n\tstruct key_vector *parent;\n\tstruct key_vector kv[1];\n};\n\nstruct trie_use_stats {\n\tunsigned int gets;\n\tunsigned int backtrack;\n\tunsigned int semantic_match_passed;\n\tunsigned int semantic_match_miss;\n\tunsigned int null_node_hit;\n\tunsigned int resize_node_skipped;\n};\n\nstruct trie_stat {\n\tunsigned int totdepth;\n\tunsigned int maxdepth;\n\tunsigned int tnodes;\n\tunsigned int leaves;\n\tunsigned int nullpointers;\n\tunsigned int prefixes;\n\tunsigned int nodesizes[32];\n};\n\nstruct trie {\n\tstruct key_vector kv[1];\n\tstruct trie_use_stats *stats;\n};\n\nstruct fib_trie_iter {\n\tstruct seq_net_private p;\n\tstruct fib_table *tb;\n\tstruct key_vector *tnode;\n\tunsigned int index;\n\tunsigned int depth;\n};\n\nstruct fib_route_iter {\n\tstruct seq_net_private p;\n\tstruct fib_table *main_tb;\n\tstruct key_vector *tnode;\n\tloff_t pos;\n\tt_key key;\n};\n\nstruct ipfrag_skb_cb {\n\tunion {\n\t\tstruct inet_skb_parm h4;\n\t\tstruct inet6_skb_parm h6;\n\t};\n\tstruct sk_buff *next_frag;\n\tint frag_run_len;\n};\n\nstruct icmpv6_echo {\n\t__be16 identifier;\n\t__be16 sequence;\n};\n\nstruct icmpv6_nd_advt {\n\t__u32 reserved: 5;\n\t__u32 override: 1;\n\t__u32 solicited: 1;\n\t__u32 router: 1;\n\t__u32 reserved2: 24;\n};\n\nstruct icmpv6_nd_ra {\n\t__u8 hop_limit;\n\t__u8 reserved: 3;\n\t__u8 router_pref: 2;\n\t__u8 home_agent: 1;\n\t__u8 other: 1;\n\t__u8 managed: 1;\n\t__be16 rt_lifetime;\n};\n\nstruct icmp6hdr {\n\t__u8 icmp6_type;\n\t__u8 icmp6_code;\n\t__sum16 icmp6_cksum;\n\tunion {\n\t\t__be32 un_data32[1];\n\t\t__be16 un_data16[2];\n\t\t__u8 un_data8[4];\n\t\tstruct icmpv6_echo u_echo;\n\t\tstruct icmpv6_nd_advt u_nd_advt;\n\t\tstruct icmpv6_nd_ra u_nd_ra;\n\t} icmp6_dataun;\n};\n\nstruct ping_iter_state {\n\tstruct seq_net_private p;\n\tint bucket;\n\tsa_family_t family;\n};\n\nstruct pingfakehdr {\n\tstruct icmphdr icmph;\n\tstruct msghdr *msg;\n\tsa_family_t family;\n\t__wsum wcheck;\n};\n\nstruct ping_table {\n\tstruct hlist_nulls_head hash[64];\n\trwlock_t lock;\n};\n\nenum lwtunnel_ip_t {\n\tLWTUNNEL_IP_UNSPEC = 0,\n\tLWTUNNEL_IP_ID = 1,\n\tLWTUNNEL_IP_DST = 2,\n\tLWTUNNEL_IP_SRC = 3,\n\tLWTUNNEL_IP_TTL = 4,\n\tLWTUNNEL_IP_TOS = 5,\n\tLWTUNNEL_IP_FLAGS = 6,\n\tLWTUNNEL_IP_PAD = 7,\n\tLWTUNNEL_IP_OPTS = 8,\n\t__LWTUNNEL_IP_MAX = 9,\n};\n\nenum lwtunnel_ip6_t {\n\tLWTUNNEL_IP6_UNSPEC = 0,\n\tLWTUNNEL_IP6_ID = 1,\n\tLWTUNNEL_IP6_DST = 2,\n\tLWTUNNEL_IP6_SRC = 3,\n\tLWTUNNEL_IP6_HOPLIMIT = 4,\n\tLWTUNNEL_IP6_TC = 5,\n\tLWTUNNEL_IP6_FLAGS = 6,\n\tLWTUNNEL_IP6_PAD = 7,\n\tLWTUNNEL_IP6_OPTS = 8,\n\t__LWTUNNEL_IP6_MAX = 9,\n};\n\nenum {\n\tLWTUNNEL_IP_OPTS_UNSPEC = 0,\n\tLWTUNNEL_IP_OPTS_GENEVE = 1,\n\tLWTUNNEL_IP_OPTS_VXLAN = 2,\n\tLWTUNNEL_IP_OPTS_ERSPAN = 3,\n\t__LWTUNNEL_IP_OPTS_MAX = 4,\n};\n\nenum {\n\tLWTUNNEL_IP_OPT_GENEVE_UNSPEC = 0,\n\tLWTUNNEL_IP_OPT_GENEVE_CLASS = 1,\n\tLWTUNNEL_IP_OPT_GENEVE_TYPE = 2,\n\tLWTUNNEL_IP_OPT_GENEVE_DATA = 3,\n\t__LWTUNNEL_IP_OPT_GENEVE_MAX = 4,\n};\n\nenum {\n\tLWTUNNEL_IP_OPT_VXLAN_UNSPEC = 0,\n\tLWTUNNEL_IP_OPT_VXLAN_GBP = 1,\n\t__LWTUNNEL_IP_OPT_VXLAN_MAX = 2,\n};\n\nenum {\n\tLWTUNNEL_IP_OPT_ERSPAN_UNSPEC = 0,\n\tLWTUNNEL_IP_OPT_ERSPAN_VER = 1,\n\tLWTUNNEL_IP_OPT_ERSPAN_INDEX = 2,\n\tLWTUNNEL_IP_OPT_ERSPAN_DIR = 3,\n\tLWTUNNEL_IP_OPT_ERSPAN_HWID = 4,\n\t__LWTUNNEL_IP_OPT_ERSPAN_MAX = 5,\n};\n\nstruct ip6_tnl_encap_ops {\n\tsize_t (*encap_hlen)(struct ip_tunnel_encap *);\n\tint (*build_header)(struct sk_buff *, struct ip_tunnel_encap *, u8 *, struct flowi6 *);\n\tint (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32);\n};\n\nstruct geneve_opt {\n\t__be16 opt_class;\n\tu8 type;\n\tu8 length: 5;\n\tu8 r3: 1;\n\tu8 r2: 1;\n\tu8 r1: 1;\n\tu8 opt_data[0];\n};\n\nstruct vxlan_metadata {\n\tu32 gbp;\n};\n\nstruct erspan_md2 {\n\t__be32 timestamp;\n\t__be16 sgt;\n\t__u8 hwid_upper: 2;\n\t__u8 ft: 5;\n\t__u8 p: 1;\n\t__u8 o: 1;\n\t__u8 gra: 2;\n\t__u8 dir: 1;\n\t__u8 hwid: 4;\n};\n\nstruct erspan_metadata {\n\tint version;\n\tunion {\n\t\t__be32 index;\n\t\tstruct erspan_md2 md2;\n\t} u;\n};\n\nstruct nhmsg {\n\tunsigned char nh_family;\n\tunsigned char nh_scope;\n\tunsigned char nh_protocol;\n\tunsigned char resvd;\n\tunsigned int nh_flags;\n};\n\nstruct nexthop_grp {\n\t__u32 id;\n\t__u8 weight;\n\t__u8 resvd1;\n\t__u16 resvd2;\n};\n\nenum {\n\tNEXTHOP_GRP_TYPE_MPATH = 0,\n\tNEXTHOP_GRP_TYPE_RES = 1,\n\t__NEXTHOP_GRP_TYPE_MAX = 2,\n};\n\nenum {\n\tNHA_UNSPEC = 0,\n\tNHA_ID = 1,\n\tNHA_GROUP = 2,\n\tNHA_GROUP_TYPE = 3,\n\tNHA_BLACKHOLE = 4,\n\tNHA_OIF = 5,\n\tNHA_GATEWAY = 6,\n\tNHA_ENCAP_TYPE = 7,\n\tNHA_ENCAP = 8,\n\tNHA_GROUPS = 9,\n\tNHA_MASTER = 10,\n\tNHA_FDB = 11,\n\tNHA_RES_GROUP = 12,\n\tNHA_RES_BUCKET = 13,\n\t__NHA_MAX = 14,\n};\n\nenum {\n\tNHA_RES_GROUP_UNSPEC = 0,\n\tNHA_RES_GROUP_PAD = 0,\n\tNHA_RES_GROUP_BUCKETS = 1,\n\tNHA_RES_GROUP_IDLE_TIMER = 2,\n\tNHA_RES_GROUP_UNBALANCED_TIMER = 3,\n\tNHA_RES_GROUP_UNBALANCED_TIME = 4,\n\t__NHA_RES_GROUP_MAX = 5,\n};\n\nenum {\n\tNHA_RES_BUCKET_UNSPEC = 0,\n\tNHA_RES_BUCKET_PAD = 0,\n\tNHA_RES_BUCKET_INDEX = 1,\n\tNHA_RES_BUCKET_IDLE_TIME = 2,\n\tNHA_RES_BUCKET_NH_ID = 3,\n\t__NHA_RES_BUCKET_MAX = 4,\n};\n\nstruct nh_config {\n\tu32 nh_id;\n\tu8 nh_family;\n\tu8 nh_protocol;\n\tu8 nh_blackhole;\n\tu8 nh_fdb;\n\tu32 nh_flags;\n\tint nh_ifindex;\n\tstruct net_device *dev;\n\tunion {\n\t\t__be32 ipv4;\n\t\tstruct in6_addr ipv6;\n\t} gw;\n\tstruct nlattr *nh_grp;\n\tu16 nh_grp_type;\n\tu16 nh_grp_res_num_buckets;\n\tlong unsigned int nh_grp_res_idle_timer;\n\tlong unsigned int nh_grp_res_unbalanced_timer;\n\tbool nh_grp_res_has_num_buckets;\n\tbool nh_grp_res_has_idle_timer;\n\tbool nh_grp_res_has_unbalanced_timer;\n\tstruct nlattr *nh_encap;\n\tu16 nh_encap_type;\n\tu32 nlflags;\n\tstruct nl_info nlinfo;\n};\n\nenum nexthop_event_type {\n\tNEXTHOP_EVENT_DEL = 0,\n\tNEXTHOP_EVENT_REPLACE = 1,\n\tNEXTHOP_EVENT_RES_TABLE_PRE_REPLACE = 2,\n\tNEXTHOP_EVENT_BUCKET_REPLACE = 3,\n};\n\nenum nh_notifier_info_type {\n\tNH_NOTIFIER_INFO_TYPE_SINGLE = 0,\n\tNH_NOTIFIER_INFO_TYPE_GRP = 1,\n\tNH_NOTIFIER_INFO_TYPE_RES_TABLE = 2,\n\tNH_NOTIFIER_INFO_TYPE_RES_BUCKET = 3,\n};\n\nstruct nh_notifier_single_info {\n\tstruct net_device *dev;\n\tu8 gw_family;\n\tunion {\n\t\t__be32 ipv4;\n\t\tstruct in6_addr ipv6;\n\t};\n\tu8 is_reject: 1;\n\tu8 is_fdb: 1;\n\tu8 has_encap: 1;\n};\n\nstruct nh_notifier_grp_entry_info {\n\tu8 weight;\n\tu32 id;\n\tstruct nh_notifier_single_info nh;\n};\n\nstruct nh_notifier_grp_info {\n\tu16 num_nh;\n\tbool is_fdb;\n\tstruct nh_notifier_grp_entry_info nh_entries[0];\n};\n\nstruct nh_notifier_res_bucket_info {\n\tu16 bucket_index;\n\tunsigned int idle_timer_ms;\n\tbool force;\n\tstruct nh_notifier_single_info old_nh;\n\tstruct nh_notifier_single_info new_nh;\n};\n\nstruct nh_notifier_res_table_info {\n\tu16 num_nh_buckets;\n\tstruct nh_notifier_single_info nhs[0];\n};\n\nstruct nh_notifier_info {\n\tstruct net *net;\n\tstruct netlink_ext_ack *extack;\n\tu32 id;\n\tenum nh_notifier_info_type type;\n\tunion {\n\t\tstruct nh_notifier_single_info *nh;\n\t\tstruct nh_notifier_grp_info *nh_grp;\n\t\tstruct nh_notifier_res_table_info *nh_res_table;\n\t\tstruct nh_notifier_res_bucket_info *nh_res_bucket;\n\t};\n};\n\nstruct nh_dump_filter {\n\tu32 nh_id;\n\tint dev_idx;\n\tint master_idx;\n\tbool group_filter;\n\tbool fdb_filter;\n\tu32 res_bucket_nh_id;\n};\n\nstruct rtm_dump_nh_ctx {\n\tu32 idx;\n};\n\nstruct rtm_dump_res_bucket_ctx {\n\tstruct rtm_dump_nh_ctx nh;\n\tu16 bucket_index;\n\tu32 done_nh_idx;\n};\n\nstruct rtm_dump_nexthop_bucket_data {\n\tstruct rtm_dump_res_bucket_ctx *ctx;\n\tstruct nh_dump_filter filter;\n};\n\nstruct inet6_protocol {\n\tvoid (*early_demux)(struct sk_buff *);\n\tvoid (*early_demux_handler)(struct sk_buff *);\n\tint (*handler)(struct sk_buff *);\n\tint (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32);\n\tunsigned int flags;\n};\n\nstruct snmp_mib {\n\tconst char *name;\n\tint entry;\n};\n\nstruct fib4_rule {\n\tstruct fib_rule common;\n\tu8 dst_len;\n\tu8 src_len;\n\tu8 tos;\n\t__be32 src;\n\t__be32 srcmask;\n\t__be32 dst;\n\t__be32 dstmask;\n\tu32 tclassid;\n};\n\nenum {\n\tPIM_TYPE_HELLO = 0,\n\tPIM_TYPE_REGISTER = 1,\n\tPIM_TYPE_REGISTER_STOP = 2,\n\tPIM_TYPE_JOIN_PRUNE = 3,\n\tPIM_TYPE_BOOTSTRAP = 4,\n\tPIM_TYPE_ASSERT = 5,\n\tPIM_TYPE_GRAFT = 6,\n\tPIM_TYPE_GRAFT_ACK = 7,\n\tPIM_TYPE_CANDIDATE_RP_ADV = 8,\n};\n\nstruct pimreghdr {\n\t__u8 type;\n\t__u8 reserved;\n\t__be16 csum;\n\t__be32 flags;\n};\n\ntypedef short unsigned int vifi_t;\n\nstruct vifctl {\n\tvifi_t vifc_vifi;\n\tunsigned char vifc_flags;\n\tunsigned char vifc_threshold;\n\tunsigned int vifc_rate_limit;\n\tunion {\n\t\tstruct in_addr vifc_lcl_addr;\n\t\tint vifc_lcl_ifindex;\n\t};\n\tstruct in_addr vifc_rmt_addr;\n};\n\nstruct mfcctl {\n\tstruct in_addr mfcc_origin;\n\tstruct in_addr mfcc_mcastgrp;\n\tvifi_t mfcc_parent;\n\tunsigned char mfcc_ttls[32];\n\tunsigned int mfcc_pkt_cnt;\n\tunsigned int mfcc_byte_cnt;\n\tunsigned int mfcc_wrong_if;\n\tint mfcc_expire;\n};\n\nstruct sioc_sg_req {\n\tstruct in_addr src;\n\tstruct in_addr grp;\n\tlong unsigned int pktcnt;\n\tlong unsigned int bytecnt;\n\tlong unsigned int wrong_if;\n};\n\nstruct sioc_vif_req {\n\tvifi_t vifi;\n\tlong unsigned int icount;\n\tlong unsigned int ocount;\n\tlong unsigned int ibytes;\n\tlong unsigned int obytes;\n};\n\nstruct igmpmsg {\n\t__u32 unused1;\n\t__u32 unused2;\n\tunsigned char im_msgtype;\n\tunsigned char im_mbz;\n\tunsigned char im_vif;\n\tunsigned char im_vif_hi;\n\tstruct in_addr im_src;\n\tstruct in_addr im_dst;\n};\n\nenum {\n\tIPMRA_TABLE_UNSPEC = 0,\n\tIPMRA_TABLE_ID = 1,\n\tIPMRA_TABLE_CACHE_RES_QUEUE_LEN = 2,\n\tIPMRA_TABLE_MROUTE_REG_VIF_NUM = 3,\n\tIPMRA_TABLE_MROUTE_DO_ASSERT = 4,\n\tIPMRA_TABLE_MROUTE_DO_PIM = 5,\n\tIPMRA_TABLE_VIFS = 6,\n\tIPMRA_TABLE_MROUTE_DO_WRVIFWHOLE = 7,\n\t__IPMRA_TABLE_MAX = 8,\n};\n\nenum {\n\tIPMRA_VIF_UNSPEC = 0,\n\tIPMRA_VIF = 1,\n\t__IPMRA_VIF_MAX = 2,\n};\n\nenum {\n\tIPMRA_VIFA_UNSPEC = 0,\n\tIPMRA_VIFA_IFINDEX = 1,\n\tIPMRA_VIFA_VIF_ID = 2,\n\tIPMRA_VIFA_FLAGS = 3,\n\tIPMRA_VIFA_BYTES_IN = 4,\n\tIPMRA_VIFA_BYTES_OUT = 5,\n\tIPMRA_VIFA_PACKETS_IN = 6,\n\tIPMRA_VIFA_PACKETS_OUT = 7,\n\tIPMRA_VIFA_LOCAL_ADDR = 8,\n\tIPMRA_VIFA_REMOTE_ADDR = 9,\n\tIPMRA_VIFA_PAD = 10,\n\t__IPMRA_VIFA_MAX = 11,\n};\n\nenum {\n\tIPMRA_CREPORT_UNSPEC = 0,\n\tIPMRA_CREPORT_MSGTYPE = 1,\n\tIPMRA_CREPORT_VIF_ID = 2,\n\tIPMRA_CREPORT_SRC_ADDR = 3,\n\tIPMRA_CREPORT_DST_ADDR = 4,\n\tIPMRA_CREPORT_PKT = 5,\n\tIPMRA_CREPORT_TABLE = 6,\n\t__IPMRA_CREPORT_MAX = 7,\n};\n\nstruct vif_device {\n\tstruct net_device *dev;\n\tlong unsigned int bytes_in;\n\tlong unsigned int bytes_out;\n\tlong unsigned int pkt_in;\n\tlong unsigned int pkt_out;\n\tlong unsigned int rate_limit;\n\tunsigned char threshold;\n\tshort unsigned int flags;\n\tint link;\n\tstruct netdev_phys_item_id dev_parent_id;\n\t__be32 local;\n\t__be32 remote;\n};\n\nstruct vif_entry_notifier_info {\n\tstruct fib_notifier_info info;\n\tstruct net_device *dev;\n\tshort unsigned int vif_index;\n\tshort unsigned int vif_flags;\n\tu32 tb_id;\n};\n\nenum {\n\tMFC_STATIC = 1,\n\tMFC_OFFLOAD = 2,\n};\n\nstruct mr_mfc {\n\tstruct rhlist_head mnode;\n\tshort unsigned int mfc_parent;\n\tint mfc_flags;\n\tunion {\n\t\tstruct {\n\t\t\tlong unsigned int expires;\n\t\t\tstruct sk_buff_head unresolved;\n\t\t} unres;\n\t\tstruct {\n\t\t\tlong unsigned int last_assert;\n\t\t\tint minvif;\n\t\t\tint maxvif;\n\t\t\tlong unsigned int bytes;\n\t\t\tlong unsigned int pkt;\n\t\t\tlong unsigned int wrong_if;\n\t\t\tlong unsigned int lastuse;\n\t\t\tunsigned char ttls[32];\n\t\t\trefcount_t refcount;\n\t\t} res;\n\t} mfc_un;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n\tvoid (*free)(struct callback_head *);\n};\n\nstruct mfc_entry_notifier_info {\n\tstruct fib_notifier_info info;\n\tstruct mr_mfc *mfc;\n\tu32 tb_id;\n};\n\nstruct mr_table_ops {\n\tconst struct rhashtable_params *rht_params;\n\tvoid *cmparg_any;\n};\n\nstruct mr_table {\n\tstruct list_head list;\n\tpossible_net_t net;\n\tstruct mr_table_ops ops;\n\tu32 id;\n\tstruct sock *mroute_sk;\n\tstruct timer_list ipmr_expire_timer;\n\tstruct list_head mfc_unres_queue;\n\tstruct vif_device vif_table[32];\n\tstruct rhltable mfc_hash;\n\tstruct list_head mfc_cache_list;\n\tint maxvif;\n\tatomic_t cache_resolve_queue_len;\n\tbool mroute_do_assert;\n\tbool mroute_do_pim;\n\tbool mroute_do_wrvifwhole;\n\tint mroute_reg_vif_num;\n};\n\nstruct mr_vif_iter {\n\tstruct seq_net_private p;\n\tstruct mr_table *mrt;\n\tint ct;\n};\n\nstruct mr_mfc_iter {\n\tstruct seq_net_private p;\n\tstruct mr_table *mrt;\n\tstruct list_head *cache;\n\tspinlock_t *lock;\n};\n\nstruct mfc_cache_cmp_arg {\n\t__be32 mfc_mcastgrp;\n\t__be32 mfc_origin;\n};\n\nstruct mfc_cache {\n\tstruct mr_mfc _c;\n\tunion {\n\t\tstruct {\n\t\t\t__be32 mfc_mcastgrp;\n\t\t\t__be32 mfc_origin;\n\t\t};\n\t\tstruct mfc_cache_cmp_arg cmparg;\n\t};\n};\n\nstruct ipmr_result {\n\tstruct mr_table *mrt;\n};\n\nstruct compat_sioc_sg_req {\n\tstruct in_addr src;\n\tstruct in_addr grp;\n\tcompat_ulong_t pktcnt;\n\tcompat_ulong_t bytecnt;\n\tcompat_ulong_t wrong_if;\n};\n\nstruct compat_sioc_vif_req {\n\tvifi_t vifi;\n\tcompat_ulong_t icount;\n\tcompat_ulong_t ocount;\n\tcompat_ulong_t ibytes;\n\tcompat_ulong_t obytes;\n};\n\nstruct rta_mfc_stats {\n\t__u64 mfcs_packets;\n\t__u64 mfcs_bytes;\n\t__u64 mfcs_wrong_if;\n};\n\nstruct bictcp {\n\tu32 cnt;\n\tu32 last_max_cwnd;\n\tu32 last_cwnd;\n\tu32 last_time;\n\tu32 bic_origin_point;\n\tu32 bic_K;\n\tu32 delay_min;\n\tu32 epoch_start;\n\tu32 ack_cnt;\n\tu32 tcp_cwnd;\n\tu16 unused;\n\tu8 sample_cnt;\n\tu8 found;\n\tu32 round_start;\n\tu32 end_seq;\n\tu32 last_ack;\n\tu32 curr_rtt;\n};\n\nstruct tls_rec {\n\tstruct list_head list;\n\tint tx_ready;\n\tint tx_flags;\n\tstruct sk_msg msg_plaintext;\n\tstruct sk_msg msg_encrypted;\n\tstruct scatterlist sg_aead_in[2];\n\tstruct scatterlist sg_aead_out[2];\n\tchar content_type;\n\tstruct scatterlist sg_content_type;\n\tchar aad_space[13];\n\tu8 iv_data[16];\n\tstruct aead_request aead_req;\n\tu8 aead_req_ctx[0];\n};\n\nstruct tx_work {\n\tstruct delayed_work work;\n\tstruct sock *sk;\n};\n\nstruct tls_sw_context_tx {\n\tstruct crypto_aead *aead_send;\n\tstruct crypto_wait async_wait;\n\tstruct tx_work tx_work;\n\tstruct tls_rec *open_rec;\n\tstruct list_head tx_list;\n\tatomic_t encrypt_pending;\n\tspinlock_t encrypt_compl_lock;\n\tint async_notify;\n\tu8 async_capable: 1;\n\tlong unsigned int tx_bitmask;\n};\n\nenum {\n\tTCP_BPF_IPV4 = 0,\n\tTCP_BPF_IPV6 = 1,\n\tTCP_BPF_NUM_PROTS = 2,\n};\n\nenum {\n\tTCP_BPF_BASE = 0,\n\tTCP_BPF_TX = 1,\n\tTCP_BPF_NUM_CFGS = 2,\n};\n\nenum {\n\tUDP_BPF_IPV4 = 0,\n\tUDP_BPF_IPV6 = 1,\n\tUDP_BPF_NUM_PROTS = 2,\n};\n\nstruct cipso_v4_map_cache_bkt {\n\tspinlock_t lock;\n\tu32 size;\n\tstruct list_head list;\n};\n\nstruct cipso_v4_map_cache_entry {\n\tu32 hash;\n\tunsigned char *key;\n\tsize_t key_len;\n\tstruct netlbl_lsm_cache *lsm_data;\n\tu32 activity;\n\tstruct list_head list;\n};\n\nstruct xfrm_policy_afinfo {\n\tstruct dst_ops *dst_ops;\n\tstruct dst_entry * (*dst_lookup)(struct net *, int, int, const xfrm_address_t *, const xfrm_address_t *, u32);\n\tint (*get_saddr)(struct net *, int, xfrm_address_t *, xfrm_address_t *, u32);\n\tint (*fill_dst)(struct xfrm_dst *, struct net_device *, const struct flowi *);\n\tstruct dst_entry * (*blackhole_route)(struct net *, struct dst_entry *);\n};\n\nstruct xfrm_state_afinfo {\n\tu8 family;\n\tu8 proto;\n\tconst struct xfrm_type_offload *type_offload_esp;\n\tconst struct xfrm_type *type_esp;\n\tconst struct xfrm_type *type_ipip;\n\tconst struct xfrm_type *type_ipip6;\n\tconst struct xfrm_type *type_comp;\n\tconst struct xfrm_type *type_ah;\n\tconst struct xfrm_type *type_routing;\n\tconst struct xfrm_type *type_dstopts;\n\tint (*output)(struct net *, struct sock *, struct sk_buff *);\n\tint (*transport_finish)(struct sk_buff *, int);\n\tvoid (*local_error)(struct sk_buff *, u32);\n};\n\nstruct ip_tunnel;\n\nstruct ip6_tnl;\n\nstruct xfrm_tunnel_skb_cb {\n\tunion {\n\t\tstruct inet_skb_parm h4;\n\t\tstruct inet6_skb_parm h6;\n\t} header;\n\tunion {\n\t\tstruct ip_tunnel *ip4;\n\t\tstruct ip6_tnl *ip6;\n\t} tunnel;\n};\n\nstruct xfrm_mode_skb_cb {\n\tstruct xfrm_tunnel_skb_cb header;\n\t__be16 id;\n\t__be16 frag_off;\n\tu8 ihl;\n\tu8 tos;\n\tu8 ttl;\n\tu8 protocol;\n\tu8 optlen;\n\tu8 flow_lbl[3];\n};\n\nstruct xfrm_spi_skb_cb {\n\tstruct xfrm_tunnel_skb_cb header;\n\tunsigned int daddroff;\n\tunsigned int family;\n\t__be32 seq;\n};\n\nstruct xfrm_input_afinfo {\n\tu8 family;\n\tbool is_ipip;\n\tint (*callback)(struct sk_buff *, u8, int);\n};\n\nstruct xfrm4_protocol {\n\tint (*handler)(struct sk_buff *);\n\tint (*input_handler)(struct sk_buff *, int, __be32, int);\n\tint (*cb_handler)(struct sk_buff *, int);\n\tint (*err_handler)(struct sk_buff *, u32);\n\tstruct xfrm4_protocol *next;\n\tint priority;\n};\n\ntypedef u64 (*btf_bpf_tcp_send_ack)(struct tcp_sock *, u32);\n\nenum {\n\tXFRM_STATE_VOID = 0,\n\tXFRM_STATE_ACQ = 1,\n\tXFRM_STATE_VALID = 2,\n\tXFRM_STATE_ERROR = 3,\n\tXFRM_STATE_EXPIRED = 4,\n\tXFRM_STATE_DEAD = 5,\n};\n\nstruct xfrm_if;\n\nstruct xfrm_if_cb {\n\tstruct xfrm_if * (*decode_session)(struct sk_buff *, short unsigned int);\n};\n\nstruct xfrm_if_parms {\n\tint link;\n\tu32 if_id;\n};\n\nstruct xfrm_if {\n\tstruct xfrm_if *next;\n\tstruct net_device *dev;\n\tstruct net *net;\n\tstruct xfrm_if_parms p;\n\tstruct gro_cells gro_cells;\n};\n\nstruct xfrm_policy_walk {\n\tstruct xfrm_policy_walk_entry walk;\n\tu8 type;\n\tu32 seq;\n};\n\nstruct xfrm_kmaddress {\n\txfrm_address_t local;\n\txfrm_address_t remote;\n\tu32 reserved;\n\tu16 family;\n};\n\nstruct xfrm_migrate {\n\txfrm_address_t old_daddr;\n\txfrm_address_t old_saddr;\n\txfrm_address_t new_daddr;\n\txfrm_address_t new_saddr;\n\tu8 proto;\n\tu8 mode;\n\tu16 reserved;\n\tu32 reqid;\n\tu16 old_family;\n\tu16 new_family;\n};\n\nstruct xfrmk_spdinfo {\n\tu32 incnt;\n\tu32 outcnt;\n\tu32 fwdcnt;\n\tu32 inscnt;\n\tu32 outscnt;\n\tu32 fwdscnt;\n\tu32 spdhcnt;\n\tu32 spdhmcnt;\n};\n\nstruct ip6_mh {\n\t__u8 ip6mh_proto;\n\t__u8 ip6mh_hdrlen;\n\t__u8 ip6mh_type;\n\t__u8 ip6mh_reserved;\n\t__u16 ip6mh_cksum;\n\t__u8 data[0];\n};\n\nstruct xfrm_flo {\n\tstruct dst_entry *dst_orig;\n\tu8 flags;\n};\n\nstruct xfrm_pol_inexact_node {\n\tstruct rb_node node;\n\tunion {\n\t\txfrm_address_t addr;\n\t\tstruct callback_head rcu;\n\t};\n\tu8 prefixlen;\n\tstruct rb_root root;\n\tstruct hlist_head hhead;\n};\n\nstruct xfrm_pol_inexact_key {\n\tpossible_net_t net;\n\tu32 if_id;\n\tu16 family;\n\tu8 dir;\n\tu8 type;\n};\n\nstruct xfrm_pol_inexact_bin {\n\tstruct xfrm_pol_inexact_key k;\n\tstruct rhash_head head;\n\tstruct hlist_head hhead;\n\tseqcount_spinlock_t count;\n\tstruct rb_root root_d;\n\tstruct rb_root root_s;\n\tstruct list_head inexact_bins;\n\tstruct callback_head rcu;\n};\n\nenum xfrm_pol_inexact_candidate_type {\n\tXFRM_POL_CAND_BOTH = 0,\n\tXFRM_POL_CAND_SADDR = 1,\n\tXFRM_POL_CAND_DADDR = 2,\n\tXFRM_POL_CAND_ANY = 3,\n\tXFRM_POL_CAND_MAX = 4,\n};\n\nstruct xfrm_pol_inexact_candidates {\n\tstruct hlist_head *res[4];\n};\n\nenum xfrm_ae_ftype_t {\n\tXFRM_AE_UNSPEC = 0,\n\tXFRM_AE_RTHR = 1,\n\tXFRM_AE_RVAL = 2,\n\tXFRM_AE_LVAL = 4,\n\tXFRM_AE_ETHR = 8,\n\tXFRM_AE_CR = 16,\n\tXFRM_AE_CE = 32,\n\tXFRM_AE_CU = 64,\n\t__XFRM_AE_MAX = 65,\n};\n\nenum xfrm_nlgroups {\n\tXFRMNLGRP_NONE = 0,\n\tXFRMNLGRP_ACQUIRE = 1,\n\tXFRMNLGRP_EXPIRE = 2,\n\tXFRMNLGRP_SA = 3,\n\tXFRMNLGRP_POLICY = 4,\n\tXFRMNLGRP_AEVENTS = 5,\n\tXFRMNLGRP_REPORT = 6,\n\tXFRMNLGRP_MIGRATE = 7,\n\tXFRMNLGRP_MAPPING = 8,\n\t__XFRMNLGRP_MAX = 9,\n};\n\nenum {\n\tXFRM_MODE_FLAG_TUNNEL = 1,\n};\n\nstruct km_event {\n\tunion {\n\t\tu32 hard;\n\t\tu32 proto;\n\t\tu32 byid;\n\t\tu32 aevent;\n\t\tu32 type;\n\t} data;\n\tu32 seq;\n\tu32 portid;\n\tu32 event;\n\tstruct net *net;\n};\n\nstruct xfrm_mgr {\n\tstruct list_head list;\n\tint (*notify)(struct xfrm_state *, const struct km_event *);\n\tint (*acquire)(struct xfrm_state *, struct xfrm_tmpl *, struct xfrm_policy *);\n\tstruct xfrm_policy * (*compile_policy)(struct sock *, int, u8 *, int, int *);\n\tint (*new_mapping)(struct xfrm_state *, xfrm_address_t *, __be16);\n\tint (*notify_policy)(struct xfrm_policy *, int, const struct km_event *);\n\tint (*report)(struct net *, u8, struct xfrm_selector *, xfrm_address_t *);\n\tint (*migrate)(const struct xfrm_selector *, u8, u8, const struct xfrm_migrate *, int, const struct xfrm_kmaddress *, const struct xfrm_encap_tmpl *);\n\tbool (*is_alive)(const struct km_event *);\n};\n\nstruct xfrmk_sadinfo {\n\tu32 sadhcnt;\n\tu32 sadhmcnt;\n\tu32 sadcnt;\n};\n\nstruct xfrm_translator {\n\tint (*alloc_compat)(struct sk_buff *, const struct nlmsghdr *);\n\tstruct nlmsghdr * (*rcv_msg_compat)(const struct nlmsghdr *, int, const struct nla_policy *, struct netlink_ext_ack *);\n\tint (*xlate_user_policy_sockptr)(u8 **, int);\n\tstruct module *owner;\n};\n\nstruct ip_beet_phdr {\n\t__u8 nexthdr;\n\t__u8 hdrlen;\n\t__u8 padlen;\n\t__u8 reserved;\n};\n\nstruct ip_tunnel_6rd_parm {\n\tstruct in6_addr prefix;\n\t__be32 relay_prefix;\n\tu16 prefixlen;\n\tu16 relay_prefixlen;\n};\n\nstruct ip_tunnel_prl_entry;\n\nstruct ip_tunnel {\n\tstruct ip_tunnel *next;\n\tstruct hlist_node hash_node;\n\tstruct net_device *dev;\n\tstruct net *net;\n\tlong unsigned int err_time;\n\tint err_count;\n\tu32 i_seqno;\n\tu32 o_seqno;\n\tint tun_hlen;\n\tu32 index;\n\tu8 erspan_ver;\n\tu8 dir;\n\tu16 hwid;\n\tstruct dst_cache dst_cache;\n\tstruct ip_tunnel_parm parms;\n\tint mlink;\n\tint encap_hlen;\n\tint hlen;\n\tstruct ip_tunnel_encap encap;\n\tstruct ip_tunnel_6rd_parm ip6rd;\n\tstruct ip_tunnel_prl_entry *prl;\n\tunsigned int prl_count;\n\tunsigned int ip_tnl_net_id;\n\tstruct gro_cells gro_cells;\n\t__u32 fwmark;\n\tbool collect_md;\n\tbool ignore_df;\n};\n\nstruct __ip6_tnl_parm {\n\tchar name[16];\n\tint link;\n\t__u8 proto;\n\t__u8 encap_limit;\n\t__u8 hop_limit;\n\tbool collect_md;\n\t__be32 flowinfo;\n\t__u32 flags;\n\tstruct in6_addr laddr;\n\tstruct in6_addr raddr;\n\t__be16 i_flags;\n\t__be16 o_flags;\n\t__be32 i_key;\n\t__be32 o_key;\n\t__u32 fwmark;\n\t__u32 index;\n\t__u8 erspan_ver;\n\t__u8 dir;\n\t__u16 hwid;\n};\n\nstruct ip6_tnl {\n\tstruct ip6_tnl *next;\n\tstruct net_device *dev;\n\tstruct net *net;\n\tstruct __ip6_tnl_parm parms;\n\tstruct flowi fl;\n\tstruct dst_cache dst_cache;\n\tstruct gro_cells gro_cells;\n\tint err_count;\n\tlong unsigned int err_time;\n\t__u32 i_seqno;\n\t__u32 o_seqno;\n\tint hlen;\n\tint tun_hlen;\n\tint encap_hlen;\n\tstruct ip_tunnel_encap encap;\n\tint mlink;\n};\n\nstruct xfrm_skb_cb {\n\tstruct xfrm_tunnel_skb_cb header;\n\tunion {\n\t\tstruct {\n\t\t\t__u32 low;\n\t\t\t__u32 hi;\n\t\t} output;\n\t\tstruct {\n\t\t\t__be32 low;\n\t\t\t__be32 hi;\n\t\t} input;\n\t} seq;\n};\n\nstruct ip_tunnel_prl_entry {\n\tstruct ip_tunnel_prl_entry *next;\n\t__be32 addr;\n\tu16 flags;\n\tstruct callback_head callback_head;\n};\n\nstruct xfrm_trans_tasklet {\n\tstruct tasklet_struct tasklet;\n\tstruct sk_buff_head queue;\n};\n\nstruct xfrm_trans_cb {\n\tunion {\n\t\tstruct inet_skb_parm h4;\n\t\tstruct inet6_skb_parm h6;\n\t} header;\n\tint (*finish)(struct net *, struct sock *, struct sk_buff *);\n\tstruct net *net;\n};\n\nstruct xfrm_user_offload {\n\tint ifindex;\n\t__u8 flags;\n};\n\nstruct sadb_alg {\n\t__u8 sadb_alg_id;\n\t__u8 sadb_alg_ivlen;\n\t__u16 sadb_alg_minbits;\n\t__u16 sadb_alg_maxbits;\n\t__u16 sadb_alg_reserved;\n};\n\nstruct xfrm_algo_aead_info {\n\tchar *geniv;\n\tu16 icv_truncbits;\n};\n\nstruct xfrm_algo_auth_info {\n\tu16 icv_truncbits;\n\tu16 icv_fullbits;\n};\n\nstruct xfrm_algo_encr_info {\n\tchar *geniv;\n\tu16 blockbits;\n\tu16 defkeybits;\n};\n\nstruct xfrm_algo_comp_info {\n\tu16 threshold;\n};\n\nstruct xfrm_algo_desc {\n\tchar *name;\n\tchar *compat;\n\tu8 available: 1;\n\tu8 pfkey_supported: 1;\n\tunion {\n\t\tstruct xfrm_algo_aead_info aead;\n\t\tstruct xfrm_algo_auth_info auth;\n\t\tstruct xfrm_algo_encr_info encr;\n\t\tstruct xfrm_algo_comp_info comp;\n\t} uinfo;\n\tstruct sadb_alg desc;\n};\n\nstruct xfrm_algo_list {\n\tstruct xfrm_algo_desc *algs;\n\tint entries;\n\tu32 type;\n\tu32 mask;\n};\n\nstruct xfrm_aead_name {\n\tconst char *name;\n\tint icvbits;\n};\n\nenum {\n\tXFRM_SHARE_ANY = 0,\n\tXFRM_SHARE_SESSION = 1,\n\tXFRM_SHARE_USER = 2,\n\tXFRM_SHARE_UNIQUE = 3,\n};\n\nstruct xfrm_user_tmpl {\n\tstruct xfrm_id id;\n\t__u16 family;\n\txfrm_address_t saddr;\n\t__u32 reqid;\n\t__u8 mode;\n\t__u8 share;\n\t__u8 optional;\n\t__u32 aalgos;\n\t__u32 ealgos;\n\t__u32 calgos;\n};\n\nstruct xfrm_userpolicy_type {\n\t__u8 type;\n\t__u16 reserved1;\n\t__u8 reserved2;\n};\n\nenum xfrm_sadattr_type_t {\n\tXFRMA_SAD_UNSPEC = 0,\n\tXFRMA_SAD_CNT = 1,\n\tXFRMA_SAD_HINFO = 2,\n\t__XFRMA_SAD_MAX = 3,\n};\n\nstruct xfrmu_sadhinfo {\n\t__u32 sadhcnt;\n\t__u32 sadhmcnt;\n};\n\nenum xfrm_spdattr_type_t {\n\tXFRMA_SPD_UNSPEC = 0,\n\tXFRMA_SPD_INFO = 1,\n\tXFRMA_SPD_HINFO = 2,\n\tXFRMA_SPD_IPV4_HTHRESH = 3,\n\tXFRMA_SPD_IPV6_HTHRESH = 4,\n\t__XFRMA_SPD_MAX = 5,\n};\n\nstruct xfrmu_spdinfo {\n\t__u32 incnt;\n\t__u32 outcnt;\n\t__u32 fwdcnt;\n\t__u32 inscnt;\n\t__u32 outscnt;\n\t__u32 fwdscnt;\n};\n\nstruct xfrmu_spdhinfo {\n\t__u32 spdhcnt;\n\t__u32 spdhmcnt;\n};\n\nstruct xfrmu_spdhthresh {\n\t__u8 lbits;\n\t__u8 rbits;\n};\n\nstruct xfrm_usersa_info {\n\tstruct xfrm_selector sel;\n\tstruct xfrm_id id;\n\txfrm_address_t saddr;\n\tstruct xfrm_lifetime_cfg lft;\n\tstruct xfrm_lifetime_cur curlft;\n\tstruct xfrm_stats stats;\n\t__u32 seq;\n\t__u32 reqid;\n\t__u16 family;\n\t__u8 mode;\n\t__u8 replay_window;\n\t__u8 flags;\n};\n\nstruct xfrm_usersa_id {\n\txfrm_address_t daddr;\n\t__be32 spi;\n\t__u16 family;\n\t__u8 proto;\n};\n\nstruct xfrm_aevent_id {\n\tstruct xfrm_usersa_id sa_id;\n\txfrm_address_t saddr;\n\t__u32 flags;\n\t__u32 reqid;\n};\n\nstruct xfrm_userspi_info {\n\tstruct xfrm_usersa_info info;\n\t__u32 min;\n\t__u32 max;\n};\n\nstruct xfrm_userpolicy_info {\n\tstruct xfrm_selector sel;\n\tstruct xfrm_lifetime_cfg lft;\n\tstruct xfrm_lifetime_cur curlft;\n\t__u32 priority;\n\t__u32 index;\n\t__u8 dir;\n\t__u8 action;\n\t__u8 flags;\n\t__u8 share;\n};\n\nstruct xfrm_userpolicy_id {\n\tstruct xfrm_selector sel;\n\t__u32 index;\n\t__u8 dir;\n};\n\nstruct xfrm_user_acquire {\n\tstruct xfrm_id id;\n\txfrm_address_t saddr;\n\tstruct xfrm_selector sel;\n\tstruct xfrm_userpolicy_info policy;\n\t__u32 aalgos;\n\t__u32 ealgos;\n\t__u32 calgos;\n\t__u32 seq;\n};\n\nstruct xfrm_user_expire {\n\tstruct xfrm_usersa_info state;\n\t__u8 hard;\n};\n\nstruct xfrm_user_polexpire {\n\tstruct xfrm_userpolicy_info pol;\n\t__u8 hard;\n};\n\nstruct xfrm_usersa_flush {\n\t__u8 proto;\n};\n\nstruct xfrm_user_report {\n\t__u8 proto;\n\tstruct xfrm_selector sel;\n};\n\nstruct xfrm_user_kmaddress {\n\txfrm_address_t local;\n\txfrm_address_t remote;\n\t__u32 reserved;\n\t__u16 family;\n};\n\nstruct xfrm_user_migrate {\n\txfrm_address_t old_daddr;\n\txfrm_address_t old_saddr;\n\txfrm_address_t new_daddr;\n\txfrm_address_t new_saddr;\n\t__u8 proto;\n\t__u8 mode;\n\t__u16 reserved;\n\t__u32 reqid;\n\t__u16 old_family;\n\t__u16 new_family;\n};\n\nstruct xfrm_user_mapping {\n\tstruct xfrm_usersa_id id;\n\t__u32 reqid;\n\txfrm_address_t old_saddr;\n\txfrm_address_t new_saddr;\n\t__be16 old_sport;\n\t__be16 new_sport;\n};\n\nstruct xfrm_dump_info {\n\tstruct sk_buff *in_skb;\n\tstruct sk_buff *out_skb;\n\tu32 nlmsg_seq;\n\tu16 nlmsg_flags;\n};\n\nstruct xfrm_link {\n\tint (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);\n\tint (*start)(struct netlink_callback *);\n\tint (*dump)(struct sk_buff *, struct netlink_callback *);\n\tint (*done)(struct netlink_callback *);\n\tconst struct nla_policy *nla_pol;\n\tint nla_max;\n};\n\nstruct espintcp_msg {\n\tstruct sk_buff *skb;\n\tstruct sk_msg skmsg;\n\tint offset;\n\tint len;\n};\n\nstruct espintcp_ctx {\n\tstruct strparser strp;\n\tstruct sk_buff_head ike_queue;\n\tstruct sk_buff_head out_queue;\n\tstruct espintcp_msg partial;\n\tvoid (*saved_data_ready)(struct sock *);\n\tvoid (*saved_write_space)(struct sock *);\n\tvoid (*saved_destruct)(struct sock *);\n\tstruct work_struct work;\n\tbool tx_running;\n};\n\nstruct unix_stream_read_state {\n\tint (*recv_actor)(struct sk_buff *, int, int, struct unix_stream_read_state *);\n\tstruct socket *socket;\n\tstruct msghdr *msg;\n\tstruct pipe_inode_info *pipe;\n\tsize_t size;\n\tint flags;\n\tunsigned int splice_flags;\n};\n\nstruct ipv6_params {\n\t__s32 disable_ipv6;\n\t__s32 autoconf;\n};\n\nenum flowlabel_reflect {\n\tFLOWLABEL_REFLECT_ESTABLISHED = 1,\n\tFLOWLABEL_REFLECT_TCP_RESET = 2,\n\tFLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES = 4,\n};\n\nstruct in6_rtmsg {\n\tstruct in6_addr rtmsg_dst;\n\tstruct in6_addr rtmsg_src;\n\tstruct in6_addr rtmsg_gateway;\n\t__u32 rtmsg_type;\n\t__u16 rtmsg_dst_len;\n\t__u16 rtmsg_src_len;\n\t__u32 rtmsg_metric;\n\tlong unsigned int rtmsg_info;\n\t__u32 rtmsg_flags;\n\tint rtmsg_ifindex;\n};\n\nstruct compat_in6_rtmsg {\n\tstruct in6_addr rtmsg_dst;\n\tstruct in6_addr rtmsg_src;\n\tstruct in6_addr rtmsg_gateway;\n\tu32 rtmsg_type;\n\tu16 rtmsg_dst_len;\n\tu16 rtmsg_src_len;\n\tu32 rtmsg_metric;\n\tu32 rtmsg_info;\n\tu32 rtmsg_flags;\n\ts32 rtmsg_ifindex;\n};\n\nstruct ac6_iter_state {\n\tstruct seq_net_private p;\n\tstruct net_device *dev;\n\tstruct inet6_dev *idev;\n};\n\nstruct ip6_fraglist_iter {\n\tstruct ipv6hdr *tmp_hdr;\n\tstruct sk_buff *frag;\n\tint offset;\n\tunsigned int hlen;\n\t__be32 frag_id;\n\tu8 nexthdr;\n};\n\nstruct ip6_frag_state {\n\tu8 *prevhdr;\n\tunsigned int hlen;\n\tunsigned int mtu;\n\tunsigned int left;\n\tint offset;\n\tint ptr;\n\tint hroom;\n\tint troom;\n\t__be32 frag_id;\n\tu8 nexthdr;\n};\n\nstruct ip6_ra_chain {\n\tstruct ip6_ra_chain *next;\n\tstruct sock *sk;\n\tint sel;\n\tvoid (*destructor)(struct sock *);\n};\n\nstruct ipcm6_cookie {\n\tstruct sockcm_cookie sockc;\n\t__s16 hlimit;\n\t__s16 tclass;\n\t__s8 dontfrag;\n\tstruct ipv6_txoptions *opt;\n\t__u16 gso_size;\n};\n\nenum {\n\tIFLA_INET6_UNSPEC = 0,\n\tIFLA_INET6_FLAGS = 1,\n\tIFLA_INET6_CONF = 2,\n\tIFLA_INET6_STATS = 3,\n\tIFLA_INET6_MCAST = 4,\n\tIFLA_INET6_CACHEINFO = 5,\n\tIFLA_INET6_ICMP6STATS = 6,\n\tIFLA_INET6_TOKEN = 7,\n\tIFLA_INET6_ADDR_GEN_MODE = 8,\n\t__IFLA_INET6_MAX = 9,\n};\n\nenum in6_addr_gen_mode {\n\tIN6_ADDR_GEN_MODE_EUI64 = 0,\n\tIN6_ADDR_GEN_MODE_NONE = 1,\n\tIN6_ADDR_GEN_MODE_STABLE_PRIVACY = 2,\n\tIN6_ADDR_GEN_MODE_RANDOM = 3,\n};\n\nstruct ifla_cacheinfo {\n\t__u32 max_reasm_len;\n\t__u32 tstamp;\n\t__u32 reachable_time;\n\t__u32 retrans_time;\n};\n\nstruct wpan_phy;\n\nstruct wpan_dev_header_ops;\n\nstruct wpan_dev {\n\tstruct wpan_phy *wpan_phy;\n\tint iftype;\n\tstruct list_head list;\n\tstruct net_device *netdev;\n\tconst struct wpan_dev_header_ops *header_ops;\n\tstruct net_device *lowpan_dev;\n\tu32 identifier;\n\t__le16 pan_id;\n\t__le16 short_addr;\n\t__le64 extended_addr;\n\tatomic_t bsn;\n\tatomic_t dsn;\n\tu8 min_be;\n\tu8 max_be;\n\tu8 csma_retries;\n\ts8 frame_retries;\n\tbool lbt;\n\tbool promiscuous_mode;\n\tbool ackreq;\n};\n\nstruct prefixmsg {\n\tunsigned char prefix_family;\n\tunsigned char prefix_pad1;\n\tshort unsigned int prefix_pad2;\n\tint prefix_ifindex;\n\tunsigned char prefix_type;\n\tunsigned char prefix_len;\n\tunsigned char prefix_flags;\n\tunsigned char prefix_pad3;\n};\n\nenum {\n\tPREFIX_UNSPEC = 0,\n\tPREFIX_ADDRESS = 1,\n\tPREFIX_CACHEINFO = 2,\n\t__PREFIX_MAX = 3,\n};\n\nstruct prefix_cacheinfo {\n\t__u32 preferred_time;\n\t__u32 valid_time;\n};\n\nstruct in6_ifreq {\n\tstruct in6_addr ifr6_addr;\n\t__u32 ifr6_prefixlen;\n\tint ifr6_ifindex;\n};\n\nenum {\n\tDEVCONF_FORWARDING = 0,\n\tDEVCONF_HOPLIMIT = 1,\n\tDEVCONF_MTU6 = 2,\n\tDEVCONF_ACCEPT_RA = 3,\n\tDEVCONF_ACCEPT_REDIRECTS = 4,\n\tDEVCONF_AUTOCONF = 5,\n\tDEVCONF_DAD_TRANSMITS = 6,\n\tDEVCONF_RTR_SOLICITS = 7,\n\tDEVCONF_RTR_SOLICIT_INTERVAL = 8,\n\tDEVCONF_RTR_SOLICIT_DELAY = 9,\n\tDEVCONF_USE_TEMPADDR = 10,\n\tDEVCONF_TEMP_VALID_LFT = 11,\n\tDEVCONF_TEMP_PREFERED_LFT = 12,\n\tDEVCONF_REGEN_MAX_RETRY = 13,\n\tDEVCONF_MAX_DESYNC_FACTOR = 14,\n\tDEVCONF_MAX_ADDRESSES = 15,\n\tDEVCONF_FORCE_MLD_VERSION = 16,\n\tDEVCONF_ACCEPT_RA_DEFRTR = 17,\n\tDEVCONF_ACCEPT_RA_PINFO = 18,\n\tDEVCONF_ACCEPT_RA_RTR_PREF = 19,\n\tDEVCONF_RTR_PROBE_INTERVAL = 20,\n\tDEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN = 21,\n\tDEVCONF_PROXY_NDP = 22,\n\tDEVCONF_OPTIMISTIC_DAD = 23,\n\tDEVCONF_ACCEPT_SOURCE_ROUTE = 24,\n\tDEVCONF_MC_FORWARDING = 25,\n\tDEVCONF_DISABLE_IPV6 = 26,\n\tDEVCONF_ACCEPT_DAD = 27,\n\tDEVCONF_FORCE_TLLAO = 28,\n\tDEVCONF_NDISC_NOTIFY = 29,\n\tDEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL = 30,\n\tDEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL = 31,\n\tDEVCONF_SUPPRESS_FRAG_NDISC = 32,\n\tDEVCONF_ACCEPT_RA_FROM_LOCAL = 33,\n\tDEVCONF_USE_OPTIMISTIC = 34,\n\tDEVCONF_ACCEPT_RA_MTU = 35,\n\tDEVCONF_STABLE_SECRET = 36,\n\tDEVCONF_USE_OIF_ADDRS_ONLY = 37,\n\tDEVCONF_ACCEPT_RA_MIN_HOP_LIMIT = 38,\n\tDEVCONF_IGNORE_ROUTES_WITH_LINKDOWN = 39,\n\tDEVCONF_DROP_UNICAST_IN_L2_MULTICAST = 40,\n\tDEVCONF_DROP_UNSOLICITED_NA = 41,\n\tDEVCONF_KEEP_ADDR_ON_DOWN = 42,\n\tDEVCONF_RTR_SOLICIT_MAX_INTERVAL = 43,\n\tDEVCONF_SEG6_ENABLED = 44,\n\tDEVCONF_SEG6_REQUIRE_HMAC = 45,\n\tDEVCONF_ENHANCED_DAD = 46,\n\tDEVCONF_ADDR_GEN_MODE = 47,\n\tDEVCONF_DISABLE_POLICY = 48,\n\tDEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN = 49,\n\tDEVCONF_NDISC_TCLASS = 50,\n\tDEVCONF_RPL_SEG_ENABLED = 51,\n\tDEVCONF_RA_DEFRTR_METRIC = 52,\n\tDEVCONF_MAX = 53,\n};\n\nenum {\n\tINET6_IFADDR_STATE_PREDAD = 0,\n\tINET6_IFADDR_STATE_DAD = 1,\n\tINET6_IFADDR_STATE_POSTDAD = 2,\n\tINET6_IFADDR_STATE_ERRDAD = 3,\n\tINET6_IFADDR_STATE_DEAD = 4,\n};\n\nenum nl802154_cca_modes {\n\t__NL802154_CCA_INVALID = 0,\n\tNL802154_CCA_ENERGY = 1,\n\tNL802154_CCA_CARRIER = 2,\n\tNL802154_CCA_ENERGY_CARRIER = 3,\n\tNL802154_CCA_ALOHA = 4,\n\tNL802154_CCA_UWB_SHR = 5,\n\tNL802154_CCA_UWB_MULTIPLEXED = 6,\n\t__NL802154_CCA_ATTR_AFTER_LAST = 7,\n\tNL802154_CCA_ATTR_MAX = 6,\n};\n\nenum nl802154_cca_opts {\n\tNL802154_CCA_OPT_ENERGY_CARRIER_AND = 0,\n\tNL802154_CCA_OPT_ENERGY_CARRIER_OR = 1,\n\t__NL802154_CCA_OPT_ATTR_AFTER_LAST = 2,\n\tNL802154_CCA_OPT_ATTR_MAX = 1,\n};\n\nenum nl802154_supported_bool_states {\n\tNL802154_SUPPORTED_BOOL_FALSE = 0,\n\tNL802154_SUPPORTED_BOOL_TRUE = 1,\n\t__NL802154_SUPPORTED_BOOL_INVALD = 2,\n\tNL802154_SUPPORTED_BOOL_BOTH = 3,\n\t__NL802154_SUPPORTED_BOOL_AFTER_LAST = 4,\n\tNL802154_SUPPORTED_BOOL_MAX = 3,\n};\n\nstruct wpan_phy_supported {\n\tu32 channels[32];\n\tu32 cca_modes;\n\tu32 cca_opts;\n\tu32 iftypes;\n\tenum nl802154_supported_bool_states lbt;\n\tu8 min_minbe;\n\tu8 max_minbe;\n\tu8 min_maxbe;\n\tu8 max_maxbe;\n\tu8 min_csma_backoffs;\n\tu8 max_csma_backoffs;\n\ts8 min_frame_retries;\n\ts8 max_frame_retries;\n\tsize_t tx_powers_size;\n\tsize_t cca_ed_levels_size;\n\tconst s32 *tx_powers;\n\tconst s32 *cca_ed_levels;\n};\n\nstruct wpan_phy_cca {\n\tenum nl802154_cca_modes mode;\n\tenum nl802154_cca_opts opt;\n};\n\nstruct wpan_phy {\n\tconst void *privid;\n\tu32 flags;\n\tu8 current_channel;\n\tu8 current_page;\n\tstruct wpan_phy_supported supported;\n\ts32 transmit_power;\n\tstruct wpan_phy_cca cca;\n\t__le64 perm_extended_addr;\n\ts32 cca_ed_level;\n\tu8 symbol_duration;\n\tu16 lifs_period;\n\tu16 sifs_period;\n\tstruct device dev;\n\tpossible_net_t _net;\n\tchar priv[0];\n};\n\nstruct ieee802154_addr {\n\tu8 mode;\n\t__le16 pan_id;\n\tunion {\n\t\t__le16 short_addr;\n\t\t__le64 extended_addr;\n\t};\n};\n\nstruct wpan_dev_header_ops {\n\tint (*create)(struct sk_buff *, struct net_device *, const struct ieee802154_addr *, const struct ieee802154_addr *, unsigned int);\n};\n\nunion fwnet_hwaddr {\n\tu8 u[16];\n\tstruct {\n\t\t__be64 uniq_id;\n\t\tu8 max_rec;\n\t\tu8 sspd;\n\t\t__be16 fifo_hi;\n\t\t__be32 fifo_lo;\n\t} uc;\n};\n\nstruct in6_validator_info {\n\tstruct in6_addr i6vi_addr;\n\tstruct inet6_dev *i6vi_dev;\n\tstruct netlink_ext_ack *extack;\n};\n\nstruct ifa6_config {\n\tconst struct in6_addr *pfx;\n\tunsigned int plen;\n\tconst struct in6_addr *peer_pfx;\n\tu32 rt_priority;\n\tu32 ifa_flags;\n\tu32 preferred_lft;\n\tu32 valid_lft;\n\tu16 scope;\n};\n\nenum cleanup_prefix_rt_t {\n\tCLEANUP_PREFIX_RT_NOP = 0,\n\tCLEANUP_PREFIX_RT_DEL = 1,\n\tCLEANUP_PREFIX_RT_EXPIRE = 2,\n};\n\nenum {\n\tIPV6_SADDR_RULE_INIT = 0,\n\tIPV6_SADDR_RULE_LOCAL = 1,\n\tIPV6_SADDR_RULE_SCOPE = 2,\n\tIPV6_SADDR_RULE_PREFERRED = 3,\n\tIPV6_SADDR_RULE_OIF = 4,\n\tIPV6_SADDR_RULE_LABEL = 5,\n\tIPV6_SADDR_RULE_PRIVACY = 6,\n\tIPV6_SADDR_RULE_ORCHID = 7,\n\tIPV6_SADDR_RULE_PREFIX = 8,\n\tIPV6_SADDR_RULE_NOT_OPTIMISTIC = 9,\n\tIPV6_SADDR_RULE_MAX = 10,\n};\n\nstruct ipv6_saddr_score {\n\tint rule;\n\tint addr_type;\n\tstruct inet6_ifaddr *ifa;\n\tlong unsigned int scorebits[1];\n\tint scopedist;\n\tint matchlen;\n};\n\nstruct ipv6_saddr_dst {\n\tconst struct in6_addr *addr;\n\tint ifindex;\n\tint scope;\n\tint label;\n\tunsigned int prefs;\n};\n\nstruct if6_iter_state {\n\tstruct seq_net_private p;\n\tint bucket;\n\tint offset;\n};\n\nenum addr_type_t {\n\tUNICAST_ADDR = 0,\n\tMULTICAST_ADDR = 1,\n\tANYCAST_ADDR = 2,\n};\n\nstruct inet6_fill_args {\n\tu32 portid;\n\tu32 seq;\n\tint event;\n\tunsigned int flags;\n\tint netnsid;\n\tint ifindex;\n\tenum addr_type_t type;\n};\n\nenum {\n\tDAD_PROCESS = 0,\n\tDAD_BEGIN = 1,\n\tDAD_ABORT = 2,\n};\n\nstruct ifaddrlblmsg {\n\t__u8 ifal_family;\n\t__u8 __ifal_reserved;\n\t__u8 ifal_prefixlen;\n\t__u8 ifal_flags;\n\t__u32 ifal_index;\n\t__u32 ifal_seq;\n};\n\nenum {\n\tIFAL_ADDRESS = 1,\n\tIFAL_LABEL = 2,\n\t__IFAL_MAX = 3,\n};\n\nstruct ip6addrlbl_entry {\n\tstruct in6_addr prefix;\n\tint prefixlen;\n\tint ifindex;\n\tint addrtype;\n\tu32 label;\n\tstruct hlist_node list;\n\tstruct callback_head rcu;\n};\n\nstruct ip6addrlbl_init_table {\n\tconst struct in6_addr *prefix;\n\tint prefixlen;\n\tu32 label;\n};\n\nstruct rd_msg {\n\tstruct icmp6hdr icmph;\n\tstruct in6_addr target;\n\tstruct in6_addr dest;\n\t__u8 opt[0];\n};\n\nstruct fib6_gc_args {\n\tint timeout;\n\tint more;\n};\n\nstruct rt6_exception {\n\tstruct hlist_node hlist;\n\tstruct rt6_info *rt6i;\n\tlong unsigned int stamp;\n\tstruct callback_head rcu;\n};\n\ntypedef struct rt6_info * (*pol_lookup_t)(struct net *, struct fib6_table *, struct flowi6 *, const struct sk_buff *, int);\n\nstruct route_info {\n\t__u8 type;\n\t__u8 length;\n\t__u8 prefix_len;\n\t__u8 reserved_l: 3;\n\t__u8 route_pref: 2;\n\t__u8 reserved_h: 3;\n\t__be32 lifetime;\n\t__u8 prefix[0];\n};\n\nstruct rt6_rtnl_dump_arg {\n\tstruct sk_buff *skb;\n\tstruct netlink_callback *cb;\n\tstruct net *net;\n\tstruct fib_dump_filter filter;\n};\n\nstruct netevent_redirect {\n\tstruct dst_entry *old;\n\tstruct dst_entry *new;\n\tstruct neighbour *neigh;\n\tconst void *daddr;\n};\n\nstruct trace_event_raw_fib6_table_lookup {\n\tstruct trace_entry ent;\n\tu32 tb_id;\n\tint err;\n\tint oif;\n\tint iif;\n\t__u8 tos;\n\t__u8 scope;\n\t__u8 flags;\n\t__u8 src[16];\n\t__u8 dst[16];\n\tu16 sport;\n\tu16 dport;\n\tu8 proto;\n\tu8 rt_type;\n\tu32 __data_loc_name;\n\t__u8 gw[16];\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_fib6_table_lookup {\n\tu32 name;\n};\n\ntypedef void (*btf_trace_fib6_table_lookup)(void *, const struct net *, const struct fib6_result *, struct fib6_table *, const struct flowi6 *);\n\nenum rt6_nud_state {\n\tRT6_NUD_FAIL_HARD = 4294967293,\n\tRT6_NUD_FAIL_PROBE = 4294967294,\n\tRT6_NUD_FAIL_DO_RR = 4294967295,\n\tRT6_NUD_SUCCEED = 1,\n};\n\nstruct fib6_nh_dm_arg {\n\tstruct net *net;\n\tconst struct in6_addr *saddr;\n\tint oif;\n\tint flags;\n\tstruct fib6_nh *nh;\n};\n\nstruct __rt6_probe_work {\n\tstruct work_struct work;\n\tstruct in6_addr target;\n\tstruct net_device *dev;\n};\n\nstruct fib6_nh_frl_arg {\n\tu32 flags;\n\tint oif;\n\tint strict;\n\tint *mpri;\n\tbool *do_rr;\n\tstruct fib6_nh *nh;\n};\n\nstruct fib6_nh_excptn_arg {\n\tstruct rt6_info *rt;\n\tint plen;\n};\n\nstruct fib6_nh_match_arg {\n\tconst struct net_device *dev;\n\tconst struct in6_addr *gw;\n\tstruct fib6_nh *match;\n};\n\nstruct fib6_nh_age_excptn_arg {\n\tstruct fib6_gc_args *gc_args;\n\tlong unsigned int now;\n};\n\nstruct fib6_nh_rd_arg {\n\tstruct fib6_result *res;\n\tstruct flowi6 *fl6;\n\tconst struct in6_addr *gw;\n\tstruct rt6_info **ret;\n};\n\nstruct ip6rd_flowi {\n\tstruct flowi6 fl6;\n\tstruct in6_addr gateway;\n};\n\nstruct fib6_nh_del_cached_rt_arg {\n\tstruct fib6_config *cfg;\n\tstruct fib6_info *f6i;\n};\n\nstruct arg_dev_net_ip {\n\tstruct net_device *dev;\n\tstruct net *net;\n\tstruct in6_addr *addr;\n};\n\nstruct arg_netdev_event {\n\tconst struct net_device *dev;\n\tunion {\n\t\tunsigned char nh_flags;\n\t\tlong unsigned int event;\n\t};\n};\n\nstruct rt6_mtu_change_arg {\n\tstruct net_device *dev;\n\tunsigned int mtu;\n\tstruct fib6_info *f6i;\n};\n\nstruct rt6_nh {\n\tstruct fib6_info *fib6_info;\n\tstruct fib6_config r_cfg;\n\tstruct list_head next;\n};\n\nstruct fib6_nh_exception_dump_walker {\n\tstruct rt6_rtnl_dump_arg *dump;\n\tstruct fib6_info *rt;\n\tunsigned int flags;\n\tunsigned int skip;\n\tunsigned int count;\n};\n\nenum fib6_walk_state {\n\tFWS_S = 0,\n\tFWS_L = 1,\n\tFWS_R = 2,\n\tFWS_C = 3,\n\tFWS_U = 4,\n};\n\nstruct fib6_walker {\n\tstruct list_head lh;\n\tstruct fib6_node *root;\n\tstruct fib6_node *node;\n\tstruct fib6_info *leaf;\n\tenum fib6_walk_state state;\n\tunsigned int skip;\n\tunsigned int count;\n\tunsigned int skip_in_node;\n\tint (*func)(struct fib6_walker *);\n\tvoid *args;\n};\n\nstruct fib6_entry_notifier_info {\n\tstruct fib_notifier_info info;\n\tstruct fib6_info *rt;\n\tunsigned int nsiblings;\n};\n\nstruct ipv6_route_iter {\n\tstruct seq_net_private p;\n\tstruct fib6_walker w;\n\tloff_t skip;\n\tstruct fib6_table *tbl;\n\tint sernum;\n};\n\nstruct bpf_iter__ipv6_route {\n\tunion {\n\t\tstruct bpf_iter_meta *meta;\n\t};\n\tunion {\n\t\tstruct fib6_info *rt;\n\t};\n};\n\nstruct fib6_cleaner {\n\tstruct fib6_walker w;\n\tstruct net *net;\n\tint (*func)(struct fib6_info *, void *);\n\tint sernum;\n\tvoid *arg;\n\tbool skip_notify;\n};\n\nenum {\n\tFIB6_NO_SERNUM_CHANGE = 0,\n};\n\nstruct fib6_dump_arg {\n\tstruct net *net;\n\tstruct notifier_block *nb;\n\tstruct netlink_ext_ack *extack;\n};\n\nstruct fib6_nh_pcpu_arg {\n\tstruct fib6_info *from;\n\tconst struct fib6_table *table;\n};\n\nstruct lookup_args {\n\tint offset;\n\tconst struct in6_addr *addr;\n};\n\nstruct ipv6_mreq {\n\tstruct in6_addr ipv6mr_multiaddr;\n\tint ipv6mr_ifindex;\n};\n\nstruct in6_flowlabel_req {\n\tstruct in6_addr flr_dst;\n\t__be32 flr_label;\n\t__u8 flr_action;\n\t__u8 flr_share;\n\t__u16 flr_flags;\n\t__u16 flr_expires;\n\t__u16 flr_linger;\n\t__u32 __flr_pad;\n};\n\nstruct ip6_mtuinfo {\n\tstruct sockaddr_in6 ip6m_addr;\n\t__u32 ip6m_mtu;\n};\n\nstruct nduseroptmsg {\n\tunsigned char nduseropt_family;\n\tunsigned char nduseropt_pad1;\n\tshort unsigned int nduseropt_opts_len;\n\tint nduseropt_ifindex;\n\t__u8 nduseropt_icmp_type;\n\t__u8 nduseropt_icmp_code;\n\tshort unsigned int nduseropt_pad2;\n\tunsigned int nduseropt_pad3;\n};\n\nenum {\n\tNDUSEROPT_UNSPEC = 0,\n\tNDUSEROPT_SRCADDR = 1,\n\t__NDUSEROPT_MAX = 2,\n};\n\nstruct nd_msg {\n\tstruct icmp6hdr icmph;\n\tstruct in6_addr target;\n\t__u8 opt[0];\n};\n\nstruct rs_msg {\n\tstruct icmp6hdr icmph;\n\t__u8 opt[0];\n};\n\nstruct ra_msg {\n\tstruct icmp6hdr icmph;\n\t__be32 reachable_time;\n\t__be32 retrans_timer;\n};\n\nstruct icmp6_filter {\n\t__u32 data[8];\n};\n\nstruct raw6_sock {\n\tstruct inet_sock inet;\n\t__u32 checksum;\n\t__u32 offset;\n\tstruct icmp6_filter filter;\n\t__u32 ip6mr_table;\n\tstruct ipv6_pinfo inet6;\n};\n\ntypedef int mh_filter_t(struct sock *, struct sk_buff *);\n\nstruct raw6_frag_vec {\n\tstruct msghdr *msg;\n\tint hlen;\n\tchar c[4];\n};\n\nstruct ipv6_destopt_hao {\n\t__u8 type;\n\t__u8 length;\n\tstruct in6_addr addr;\n} __attribute__((packed));\n\ntypedef void ip6_icmp_send_t(struct sk_buff *, u8, u8, __u32, const struct in6_addr *, const struct inet6_skb_parm *);\n\nstruct icmpv6_msg {\n\tstruct sk_buff *skb;\n\tint offset;\n\tuint8_t type;\n};\n\nstruct icmp6_err {\n\tint err;\n\tint fatal;\n};\n\nstruct mld_msg {\n\tstruct icmp6hdr mld_hdr;\n\tstruct in6_addr mld_mca;\n};\n\nstruct mld2_grec {\n\t__u8 grec_type;\n\t__u8 grec_auxwords;\n\t__be16 grec_nsrcs;\n\tstruct in6_addr grec_mca;\n\tstruct in6_addr grec_src[0];\n};\n\nstruct mld2_report {\n\tstruct icmp6hdr mld2r_hdr;\n\tstruct mld2_grec mld2r_grec[0];\n};\n\nstruct mld2_query {\n\tstruct icmp6hdr mld2q_hdr;\n\tstruct in6_addr mld2q_mca;\n\t__u8 mld2q_qrv: 3;\n\t__u8 mld2q_suppress: 1;\n\t__u8 mld2q_resv2: 4;\n\t__u8 mld2q_qqic;\n\t__be16 mld2q_nsrcs;\n\tstruct in6_addr mld2q_srcs[0];\n};\n\nstruct igmp6_mc_iter_state {\n\tstruct seq_net_private p;\n\tstruct net_device *dev;\n\tstruct inet6_dev *idev;\n};\n\nstruct igmp6_mcf_iter_state {\n\tstruct seq_net_private p;\n\tstruct net_device *dev;\n\tstruct inet6_dev *idev;\n\tstruct ifmcaddr6 *im;\n};\n\nenum ip6_defrag_users {\n\tIP6_DEFRAG_LOCAL_DELIVER = 0,\n\tIP6_DEFRAG_CONNTRACK_IN = 1,\n\t__IP6_DEFRAG_CONNTRACK_IN = 65536,\n\tIP6_DEFRAG_CONNTRACK_OUT = 65537,\n\t__IP6_DEFRAG_CONNTRACK_OUT = 131072,\n\tIP6_DEFRAG_CONNTRACK_BRIDGE_IN = 131073,\n\t__IP6_DEFRAG_CONNTRACK_BRIDGE_IN = 196608,\n};\n\nstruct frag_queue {\n\tstruct inet_frag_queue q;\n\tint iif;\n\t__u16 nhoffset;\n\tu8 ecn;\n};\n\nstruct tcp6_pseudohdr {\n\tstruct in6_addr saddr;\n\tstruct in6_addr daddr;\n\t__be32 len;\n\t__be32 protocol;\n};\n\nstruct rt0_hdr {\n\tstruct ipv6_rt_hdr rt_hdr;\n\t__u32 reserved;\n\tstruct in6_addr addr[0];\n};\n\nstruct ipv6_rpl_sr_hdr {\n\t__u8 nexthdr;\n\t__u8 hdrlen;\n\t__u8 type;\n\t__u8 segments_left;\n\t__u32 cmpre: 4;\n\t__u32 cmpri: 4;\n\t__u32 reserved: 4;\n\t__u32 pad: 4;\n\t__u32 reserved1: 16;\n\tunion {\n\t\tstruct in6_addr addr[0];\n\t\t__u8 data[0];\n\t} segments;\n};\n\nstruct tlvtype_proc {\n\tint type;\n\tbool (*func)(struct sk_buff *, int);\n};\n\nstruct ip6fl_iter_state {\n\tstruct seq_net_private p;\n\tstruct pid_namespace *pid_ns;\n\tint bucket;\n};\n\nstruct sr6_tlv {\n\t__u8 type;\n\t__u8 len;\n\t__u8 data[0];\n};\n\nenum {\n\tSEG6_ATTR_UNSPEC = 0,\n\tSEG6_ATTR_DST = 1,\n\tSEG6_ATTR_DSTLEN = 2,\n\tSEG6_ATTR_HMACKEYID = 3,\n\tSEG6_ATTR_SECRET = 4,\n\tSEG6_ATTR_SECRETLEN = 5,\n\tSEG6_ATTR_ALGID = 6,\n\tSEG6_ATTR_HMACINFO = 7,\n\t__SEG6_ATTR_MAX = 8,\n};\n\nenum {\n\tSEG6_CMD_UNSPEC = 0,\n\tSEG6_CMD_SETHMAC = 1,\n\tSEG6_CMD_DUMPHMAC = 2,\n\tSEG6_CMD_SET_TUNSRC = 3,\n\tSEG6_CMD_GET_TUNSRC = 4,\n\t__SEG6_CMD_MAX = 5,\n};\n\nstruct seg6_hmac_info {\n\tstruct rhash_head node;\n\tstruct callback_head rcu;\n\tu32 hmackeyid;\n\tchar secret[64];\n\tu8 slen;\n\tu8 alg_id;\n};\n\ntypedef short unsigned int mifi_t;\n\ntypedef __u32 if_mask;\n\nstruct if_set {\n\tif_mask ifs_bits[8];\n};\n\nstruct mif6ctl {\n\tmifi_t mif6c_mifi;\n\tunsigned char mif6c_flags;\n\tunsigned char vifc_threshold;\n\t__u16 mif6c_pifi;\n\tunsigned int vifc_rate_limit;\n};\n\nstruct mf6cctl {\n\tstruct sockaddr_in6 mf6cc_origin;\n\tstruct sockaddr_in6 mf6cc_mcastgrp;\n\tmifi_t mf6cc_parent;\n\tstruct if_set mf6cc_ifset;\n};\n\nstruct sioc_sg_req6 {\n\tstruct sockaddr_in6 src;\n\tstruct sockaddr_in6 grp;\n\tlong unsigned int pktcnt;\n\tlong unsigned int bytecnt;\n\tlong unsigned int wrong_if;\n};\n\nstruct sioc_mif_req6 {\n\tmifi_t mifi;\n\tlong unsigned int icount;\n\tlong unsigned int ocount;\n\tlong unsigned int ibytes;\n\tlong unsigned int obytes;\n};\n\nstruct mrt6msg {\n\t__u8 im6_mbz;\n\t__u8 im6_msgtype;\n\t__u16 im6_mif;\n\t__u32 im6_pad;\n\tstruct in6_addr im6_src;\n\tstruct in6_addr im6_dst;\n};\n\nenum {\n\tIP6MRA_CREPORT_UNSPEC = 0,\n\tIP6MRA_CREPORT_MSGTYPE = 1,\n\tIP6MRA_CREPORT_MIF_ID = 2,\n\tIP6MRA_CREPORT_SRC_ADDR = 3,\n\tIP6MRA_CREPORT_DST_ADDR = 4,\n\tIP6MRA_CREPORT_PKT = 5,\n\t__IP6MRA_CREPORT_MAX = 6,\n};\n\nstruct mfc6_cache_cmp_arg {\n\tstruct in6_addr mf6c_mcastgrp;\n\tstruct in6_addr mf6c_origin;\n};\n\nstruct mfc6_cache {\n\tstruct mr_mfc _c;\n\tunion {\n\t\tstruct {\n\t\t\tstruct in6_addr mf6c_mcastgrp;\n\t\t\tstruct in6_addr mf6c_origin;\n\t\t};\n\t\tstruct mfc6_cache_cmp_arg cmparg;\n\t};\n};\n\nstruct ip6mr_result {\n\tstruct mr_table *mrt;\n};\n\nstruct compat_sioc_sg_req6 {\n\tstruct sockaddr_in6 src;\n\tstruct sockaddr_in6 grp;\n\tcompat_ulong_t pktcnt;\n\tcompat_ulong_t bytecnt;\n\tcompat_ulong_t wrong_if;\n};\n\nstruct compat_sioc_mif_req6 {\n\tmifi_t mifi;\n\tcompat_ulong_t icount;\n\tcompat_ulong_t ocount;\n\tcompat_ulong_t ibytes;\n\tcompat_ulong_t obytes;\n};\n\nstruct xfrm6_protocol {\n\tint (*handler)(struct sk_buff *);\n\tint (*input_handler)(struct sk_buff *, int, __be32, int);\n\tint (*cb_handler)(struct sk_buff *, int);\n\tint (*err_handler)(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32);\n\tstruct xfrm6_protocol *next;\n\tint priority;\n};\n\nstruct br_input_skb_cb {\n\tstruct net_device *brdev;\n\tu16 frag_max_size;\n\tu8 igmp;\n\tu8 mrouters_only: 1;\n\tu8 proxyarp_replied: 1;\n\tu8 src_port_isolated: 1;\n\tu8 vlan_filtered: 1;\n\tu8 br_netfilter_broute: 1;\n\tint offload_fwd_mark;\n};\n\nstruct nf_bridge_frag_data;\n\nstruct fib6_rule {\n\tstruct fib_rule common;\n\tstruct rt6key src;\n\tstruct rt6key dst;\n\tu8 tclass;\n};\n\nstruct calipso_doi;\n\nstruct netlbl_calipso_ops {\n\tint (*doi_add)(struct calipso_doi *, struct netlbl_audit *);\n\tvoid (*doi_free)(struct calipso_doi *);\n\tint (*doi_remove)(u32, struct netlbl_audit *);\n\tstruct calipso_doi * (*doi_getdef)(u32);\n\tvoid (*doi_putdef)(struct calipso_doi *);\n\tint (*doi_walk)(u32 *, int (*)(struct calipso_doi *, void *), void *);\n\tint (*sock_getattr)(struct sock *, struct netlbl_lsm_secattr *);\n\tint (*sock_setattr)(struct sock *, const struct calipso_doi *, const struct netlbl_lsm_secattr *);\n\tvoid (*sock_delattr)(struct sock *);\n\tint (*req_setattr)(struct request_sock *, const struct calipso_doi *, const struct netlbl_lsm_secattr *);\n\tvoid (*req_delattr)(struct request_sock *);\n\tint (*opt_getattr)(const unsigned char *, struct netlbl_lsm_secattr *);\n\tunsigned char * (*skbuff_optptr)(const struct sk_buff *);\n\tint (*skbuff_setattr)(struct sk_buff *, const struct calipso_doi *, const struct netlbl_lsm_secattr *);\n\tint (*skbuff_delattr)(struct sk_buff *);\n\tvoid (*cache_invalidate)();\n\tint (*cache_add)(const unsigned char *, const struct netlbl_lsm_secattr *);\n};\n\nstruct calipso_doi {\n\tu32 doi;\n\tu32 type;\n\trefcount_t refcount;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct calipso_map_cache_bkt {\n\tspinlock_t lock;\n\tu32 size;\n\tstruct list_head list;\n};\n\nstruct calipso_map_cache_entry {\n\tu32 hash;\n\tunsigned char *key;\n\tsize_t key_len;\n\tstruct netlbl_lsm_cache *lsm_data;\n\tu32 activity;\n\tstruct list_head list;\n};\n\nenum {\n\tSEG6_IPTUNNEL_UNSPEC = 0,\n\tSEG6_IPTUNNEL_SRH = 1,\n\t__SEG6_IPTUNNEL_MAX = 2,\n};\n\nstruct seg6_iptunnel_encap {\n\tint mode;\n\tstruct ipv6_sr_hdr srh[0];\n};\n\nenum {\n\tSEG6_IPTUN_MODE_INLINE = 0,\n\tSEG6_IPTUN_MODE_ENCAP = 1,\n\tSEG6_IPTUN_MODE_L2ENCAP = 2,\n};\n\nstruct seg6_lwt {\n\tstruct dst_cache cache;\n\tstruct seg6_iptunnel_encap tuninfo[0];\n};\n\nenum l3mdev_type {\n\tL3MDEV_TYPE_UNSPEC = 0,\n\tL3MDEV_TYPE_VRF = 1,\n\t__L3MDEV_TYPE_MAX = 2,\n};\n\nenum {\n\tIP6_FH_F_FRAG = 1,\n\tIP6_FH_F_AUTH = 2,\n\tIP6_FH_F_SKIP_RH = 4,\n};\n\nenum {\n\tSEG6_LOCAL_UNSPEC = 0,\n\tSEG6_LOCAL_ACTION = 1,\n\tSEG6_LOCAL_SRH = 2,\n\tSEG6_LOCAL_TABLE = 3,\n\tSEG6_LOCAL_NH4 = 4,\n\tSEG6_LOCAL_NH6 = 5,\n\tSEG6_LOCAL_IIF = 6,\n\tSEG6_LOCAL_OIF = 7,\n\tSEG6_LOCAL_BPF = 8,\n\tSEG6_LOCAL_VRFTABLE = 9,\n\tSEG6_LOCAL_COUNTERS = 10,\n\t__SEG6_LOCAL_MAX = 11,\n};\n\nenum {\n\tSEG6_LOCAL_BPF_PROG_UNSPEC = 0,\n\tSEG6_LOCAL_BPF_PROG = 1,\n\tSEG6_LOCAL_BPF_PROG_NAME = 2,\n\t__SEG6_LOCAL_BPF_PROG_MAX = 3,\n};\n\nenum {\n\tSEG6_LOCAL_CNT_UNSPEC = 0,\n\tSEG6_LOCAL_CNT_PAD = 1,\n\tSEG6_LOCAL_CNT_PACKETS = 2,\n\tSEG6_LOCAL_CNT_BYTES = 3,\n\tSEG6_LOCAL_CNT_ERRORS = 4,\n\t__SEG6_LOCAL_CNT_MAX = 5,\n};\n\nstruct seg6_local_lwt;\n\nstruct seg6_local_lwtunnel_ops {\n\tint (*build_state)(struct seg6_local_lwt *, const void *, struct netlink_ext_ack *);\n\tvoid (*destroy_state)(struct seg6_local_lwt *);\n};\n\nenum seg6_end_dt_mode {\n\tDT_INVALID_MODE = 4294967274,\n\tDT_LEGACY_MODE = 0,\n\tDT_VRF_MODE = 1,\n};\n\nstruct seg6_end_dt_info {\n\tenum seg6_end_dt_mode mode;\n\tstruct net *net;\n\tint vrf_ifindex;\n\tint vrf_table;\n\tu16 family;\n};\n\nstruct pcpu_seg6_local_counters;\n\nstruct seg6_action_desc;\n\nstruct seg6_local_lwt {\n\tint action;\n\tstruct ipv6_sr_hdr *srh;\n\tint table;\n\tstruct in_addr nh4;\n\tstruct in6_addr nh6;\n\tint iif;\n\tint oif;\n\tstruct bpf_lwt_prog bpf;\n\tstruct seg6_end_dt_info dt_info;\n\tstruct pcpu_seg6_local_counters *pcpu_counters;\n\tint headroom;\n\tstruct seg6_action_desc *desc;\n\tlong unsigned int parsed_optattrs;\n};\n\nstruct seg6_action_desc {\n\tint action;\n\tlong unsigned int attrs;\n\tlong unsigned int optattrs;\n\tint (*input)(struct sk_buff *, struct seg6_local_lwt *);\n\tint static_headroom;\n\tstruct seg6_local_lwtunnel_ops slwt_ops;\n};\n\nstruct pcpu_seg6_local_counters {\n\tu64_stats_t packets;\n\tu64_stats_t bytes;\n\tu64_stats_t errors;\n\tstruct u64_stats_sync syncp;\n};\n\nstruct seg6_local_counters {\n\t__u64 packets;\n\t__u64 bytes;\n\t__u64 errors;\n};\n\nstruct seg6_action_param {\n\tint (*parse)(struct nlattr **, struct seg6_local_lwt *);\n\tint (*put)(struct sk_buff *, struct seg6_local_lwt *);\n\tint (*cmp)(struct seg6_local_lwt *, struct seg6_local_lwt *);\n\tvoid (*destroy)(struct seg6_local_lwt *);\n};\n\nstruct sr6_tlv_hmac {\n\tstruct sr6_tlv tlvhdr;\n\t__u16 reserved;\n\t__be32 hmackeyid;\n\t__u8 hmac[32];\n};\n\nenum {\n\tSEG6_HMAC_ALGO_SHA1 = 1,\n\tSEG6_HMAC_ALGO_SHA256 = 2,\n};\n\nstruct seg6_hmac_algo {\n\tu8 alg_id;\n\tchar name[64];\n\tstruct crypto_shash **tfms;\n\tstruct shash_desc **shashs;\n};\n\nenum {\n\tRPL_IPTUNNEL_UNSPEC = 0,\n\tRPL_IPTUNNEL_SRH = 1,\n\t__RPL_IPTUNNEL_MAX = 2,\n};\n\nstruct rpl_iptunnel_encap {\n\tstruct ipv6_rpl_sr_hdr srh[0];\n};\n\nstruct rpl_lwt {\n\tstruct dst_cache cache;\n\tstruct rpl_iptunnel_encap tuninfo;\n};\n\nstruct sockaddr_pkt {\n\tshort unsigned int spkt_family;\n\tunsigned char spkt_device[14];\n\t__be16 spkt_protocol;\n};\n\nstruct sockaddr_ll {\n\tshort unsigned int sll_family;\n\t__be16 sll_protocol;\n\tint sll_ifindex;\n\tshort unsigned int sll_hatype;\n\tunsigned char sll_pkttype;\n\tunsigned char sll_halen;\n\tunsigned char sll_addr[8];\n};\n\nstruct tpacket_stats {\n\tunsigned int tp_packets;\n\tunsigned int tp_drops;\n};\n\nstruct tpacket_stats_v3 {\n\tunsigned int tp_packets;\n\tunsigned int tp_drops;\n\tunsigned int tp_freeze_q_cnt;\n};\n\nstruct tpacket_rollover_stats {\n\t__u64 tp_all;\n\t__u64 tp_huge;\n\t__u64 tp_failed;\n};\n\nunion tpacket_stats_u {\n\tstruct tpacket_stats stats1;\n\tstruct tpacket_stats_v3 stats3;\n};\n\nstruct tpacket_auxdata {\n\t__u32 tp_status;\n\t__u32 tp_len;\n\t__u32 tp_snaplen;\n\t__u16 tp_mac;\n\t__u16 tp_net;\n\t__u16 tp_vlan_tci;\n\t__u16 tp_vlan_tpid;\n};\n\nstruct tpacket_hdr {\n\tlong unsigned int tp_status;\n\tunsigned int tp_len;\n\tunsigned int tp_snaplen;\n\tshort unsigned int tp_mac;\n\tshort unsigned int tp_net;\n\tunsigned int tp_sec;\n\tunsigned int tp_usec;\n};\n\nstruct tpacket2_hdr {\n\t__u32 tp_status;\n\t__u32 tp_len;\n\t__u32 tp_snaplen;\n\t__u16 tp_mac;\n\t__u16 tp_net;\n\t__u32 tp_sec;\n\t__u32 tp_nsec;\n\t__u16 tp_vlan_tci;\n\t__u16 tp_vlan_tpid;\n\t__u8 tp_padding[4];\n};\n\nstruct tpacket_hdr_variant1 {\n\t__u32 tp_rxhash;\n\t__u32 tp_vlan_tci;\n\t__u16 tp_vlan_tpid;\n\t__u16 tp_padding;\n};\n\nstruct tpacket3_hdr {\n\t__u32 tp_next_offset;\n\t__u32 tp_sec;\n\t__u32 tp_nsec;\n\t__u32 tp_snaplen;\n\t__u32 tp_len;\n\t__u32 tp_status;\n\t__u16 tp_mac;\n\t__u16 tp_net;\n\tunion {\n\t\tstruct tpacket_hdr_variant1 hv1;\n\t};\n\t__u8 tp_padding[8];\n};\n\nstruct tpacket_bd_ts {\n\tunsigned int ts_sec;\n\tunion {\n\t\tunsigned int ts_usec;\n\t\tunsigned int ts_nsec;\n\t};\n};\n\nstruct tpacket_hdr_v1 {\n\t__u32 block_status;\n\t__u32 num_pkts;\n\t__u32 offset_to_first_pkt;\n\t__u32 blk_len;\n\t__u64 seq_num;\n\tstruct tpacket_bd_ts ts_first_pkt;\n\tstruct tpacket_bd_ts ts_last_pkt;\n};\n\nunion tpacket_bd_header_u {\n\tstruct tpacket_hdr_v1 bh1;\n};\n\nstruct tpacket_block_desc {\n\t__u32 version;\n\t__u32 offset_to_priv;\n\tunion tpacket_bd_header_u hdr;\n};\n\nenum tpacket_versions {\n\tTPACKET_V1 = 0,\n\tTPACKET_V2 = 1,\n\tTPACKET_V3 = 2,\n};\n\nstruct tpacket_req {\n\tunsigned int tp_block_size;\n\tunsigned int tp_block_nr;\n\tunsigned int tp_frame_size;\n\tunsigned int tp_frame_nr;\n};\n\nstruct tpacket_req3 {\n\tunsigned int tp_block_size;\n\tunsigned int tp_block_nr;\n\tunsigned int tp_frame_size;\n\tunsigned int tp_frame_nr;\n\tunsigned int tp_retire_blk_tov;\n\tunsigned int tp_sizeof_priv;\n\tunsigned int tp_feature_req_word;\n};\n\nunion tpacket_req_u {\n\tstruct tpacket_req req;\n\tstruct tpacket_req3 req3;\n};\n\nstruct fanout_args {\n\t__u16 id;\n\t__u16 type_flags;\n\t__u32 max_num_members;\n};\n\nstruct virtio_net_hdr {\n\t__u8 flags;\n\t__u8 gso_type;\n\t__virtio16 hdr_len;\n\t__virtio16 gso_size;\n\t__virtio16 csum_start;\n\t__virtio16 csum_offset;\n};\n\nstruct packet_mclist {\n\tstruct packet_mclist *next;\n\tint ifindex;\n\tint count;\n\tshort unsigned int type;\n\tshort unsigned int alen;\n\tunsigned char addr[32];\n};\n\nstruct pgv;\n\nstruct tpacket_kbdq_core {\n\tstruct pgv *pkbdq;\n\tunsigned int feature_req_word;\n\tunsigned int hdrlen;\n\tunsigned char reset_pending_on_curr_blk;\n\tunsigned char delete_blk_timer;\n\tshort unsigned int kactive_blk_num;\n\tshort unsigned int blk_sizeof_priv;\n\tshort unsigned int last_kactive_blk_num;\n\tchar *pkblk_start;\n\tchar *pkblk_end;\n\tint kblk_size;\n\tunsigned int max_frame_len;\n\tunsigned int knum_blocks;\n\tuint64_t knxt_seq_num;\n\tchar *prev;\n\tchar *nxt_offset;\n\tstruct sk_buff *skb;\n\trwlock_t blk_fill_in_prog_lock;\n\tshort unsigned int retire_blk_tov;\n\tshort unsigned int version;\n\tlong unsigned int tov_in_jiffies;\n\tstruct timer_list retire_blk_timer;\n};\n\nstruct pgv {\n\tchar *buffer;\n};\n\nstruct packet_ring_buffer {\n\tstruct pgv *pg_vec;\n\tunsigned int head;\n\tunsigned int frames_per_block;\n\tunsigned int frame_size;\n\tunsigned int frame_max;\n\tunsigned int pg_vec_order;\n\tunsigned int pg_vec_pages;\n\tunsigned int pg_vec_len;\n\tunsigned int *pending_refcnt;\n\tunion {\n\t\tlong unsigned int *rx_owner_map;\n\t\tstruct tpacket_kbdq_core prb_bdqc;\n\t};\n};\n\nstruct packet_fanout {\n\tpossible_net_t net;\n\tunsigned int num_members;\n\tu32 max_num_members;\n\tu16 id;\n\tu8 type;\n\tu8 flags;\n\tunion {\n\t\tatomic_t rr_cur;\n\t\tstruct bpf_prog *bpf_prog;\n\t};\n\tstruct list_head list;\n\tspinlock_t lock;\n\trefcount_t sk_ref;\n\tlong: 64;\n\tstruct packet_type prot_hook;\n\tstruct sock *arr[0];\n};\n\nstruct packet_rollover {\n\tint sock;\n\tatomic_long_t num;\n\tatomic_long_t num_huge;\n\tatomic_long_t num_failed;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu32 history[16];\n};\n\nstruct packet_sock {\n\tstruct sock sk;\n\tstruct packet_fanout *fanout;\n\tunion tpacket_stats_u stats;\n\tstruct packet_ring_buffer rx_ring;\n\tstruct packet_ring_buffer tx_ring;\n\tint copy_thresh;\n\tspinlock_t bind_lock;\n\tstruct mutex pg_vec_lock;\n\tunsigned int running;\n\tunsigned int auxdata: 1;\n\tunsigned int origdev: 1;\n\tunsigned int has_vnet_hdr: 1;\n\tunsigned int tp_loss: 1;\n\tunsigned int tp_tx_has_off: 1;\n\tint pressure;\n\tint ifindex;\n\t__be16 num;\n\tstruct packet_rollover *rollover;\n\tstruct packet_mclist *mclist;\n\tatomic_t mapped;\n\tenum tpacket_versions tp_version;\n\tunsigned int tp_hdrlen;\n\tunsigned int tp_reserve;\n\tunsigned int tp_tstamp;\n\tstruct completion skb_completion;\n\tstruct net_device *cached_dev;\n\tint (*xmit)(struct sk_buff *);\n\tstruct packet_type prot_hook;\n\tatomic_t tp_drops;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct packet_mreq_max {\n\tint mr_ifindex;\n\tshort unsigned int mr_type;\n\tshort unsigned int mr_alen;\n\tunsigned char mr_address[32];\n};\n\nunion tpacket_uhdr {\n\tstruct tpacket_hdr *h1;\n\tstruct tpacket2_hdr *h2;\n\tstruct tpacket3_hdr *h3;\n\tvoid *raw;\n};\n\nstruct packet_skb_cb {\n\tunion {\n\t\tstruct sockaddr_pkt pkt;\n\t\tunion {\n\t\t\tunsigned int origlen;\n\t\t\tstruct sockaddr_ll ll;\n\t\t};\n\t} sa;\n};\n\nstruct _strp_msg {\n\tstruct strp_msg strp;\n\tint accum_len;\n};\n\nstruct vlan_group {\n\tunsigned int nr_vlan_devs;\n\tstruct hlist_node hlist;\n\tstruct net_device **vlan_devices_arrays[16];\n};\n\nstruct vlan_info {\n\tstruct net_device *real_dev;\n\tstruct vlan_group grp;\n\tstruct list_head vid_list;\n\tunsigned int nr_vids;\n\tstruct callback_head rcu;\n};\n\nenum vlan_flags {\n\tVLAN_FLAG_REORDER_HDR = 1,\n\tVLAN_FLAG_GVRP = 2,\n\tVLAN_FLAG_LOOSE_BINDING = 4,\n\tVLAN_FLAG_MVRP = 8,\n\tVLAN_FLAG_BRIDGE_BINDING = 16,\n};\n\nstruct vlan_priority_tci_mapping {\n\tu32 priority;\n\tu16 vlan_qos;\n\tstruct vlan_priority_tci_mapping *next;\n};\n\nstruct vlan_dev_priv {\n\tunsigned int nr_ingress_mappings;\n\tu32 ingress_priority_map[8];\n\tunsigned int nr_egress_mappings;\n\tstruct vlan_priority_tci_mapping *egress_priority_map[16];\n\t__be16 vlan_proto;\n\tu16 vlan_id;\n\tu16 flags;\n\tstruct net_device *real_dev;\n\tunsigned char real_dev_addr[6];\n\tstruct proc_dir_entry *dent;\n\tstruct vlan_pcpu_stats *vlan_pcpu_stats;\n\tstruct netpoll *netpoll;\n};\n\nenum vlan_protos {\n\tVLAN_PROTO_8021Q = 0,\n\tVLAN_PROTO_8021AD = 1,\n\tVLAN_PROTO_NUM = 2,\n};\n\nstruct vlan_vid_info {\n\tstruct list_head list;\n\t__be16 proto;\n\tu16 vid;\n\tint refcount;\n};\n\nenum nl80211_iftype {\n\tNL80211_IFTYPE_UNSPECIFIED = 0,\n\tNL80211_IFTYPE_ADHOC = 1,\n\tNL80211_IFTYPE_STATION = 2,\n\tNL80211_IFTYPE_AP = 3,\n\tNL80211_IFTYPE_AP_VLAN = 4,\n\tNL80211_IFTYPE_WDS = 5,\n\tNL80211_IFTYPE_MONITOR = 6,\n\tNL80211_IFTYPE_MESH_POINT = 7,\n\tNL80211_IFTYPE_P2P_CLIENT = 8,\n\tNL80211_IFTYPE_P2P_GO = 9,\n\tNL80211_IFTYPE_P2P_DEVICE = 10,\n\tNL80211_IFTYPE_OCB = 11,\n\tNL80211_IFTYPE_NAN = 12,\n\tNUM_NL80211_IFTYPES = 13,\n\tNL80211_IFTYPE_MAX = 12,\n};\n\nstruct cfg80211_conn;\n\nstruct cfg80211_cached_keys;\n\nenum ieee80211_bss_type {\n\tIEEE80211_BSS_TYPE_ESS = 0,\n\tIEEE80211_BSS_TYPE_PBSS = 1,\n\tIEEE80211_BSS_TYPE_IBSS = 2,\n\tIEEE80211_BSS_TYPE_MBSS = 3,\n\tIEEE80211_BSS_TYPE_ANY = 4,\n};\n\nstruct cfg80211_internal_bss;\n\nenum nl80211_chan_width {\n\tNL80211_CHAN_WIDTH_20_NOHT = 0,\n\tNL80211_CHAN_WIDTH_20 = 1,\n\tNL80211_CHAN_WIDTH_40 = 2,\n\tNL80211_CHAN_WIDTH_80 = 3,\n\tNL80211_CHAN_WIDTH_80P80 = 4,\n\tNL80211_CHAN_WIDTH_160 = 5,\n\tNL80211_CHAN_WIDTH_5 = 6,\n\tNL80211_CHAN_WIDTH_10 = 7,\n\tNL80211_CHAN_WIDTH_1 = 8,\n\tNL80211_CHAN_WIDTH_2 = 9,\n\tNL80211_CHAN_WIDTH_4 = 10,\n\tNL80211_CHAN_WIDTH_8 = 11,\n\tNL80211_CHAN_WIDTH_16 = 12,\n};\n\nenum ieee80211_edmg_bw_config {\n\tIEEE80211_EDMG_BW_CONFIG_4 = 4,\n\tIEEE80211_EDMG_BW_CONFIG_5 = 5,\n\tIEEE80211_EDMG_BW_CONFIG_6 = 6,\n\tIEEE80211_EDMG_BW_CONFIG_7 = 7,\n\tIEEE80211_EDMG_BW_CONFIG_8 = 8,\n\tIEEE80211_EDMG_BW_CONFIG_9 = 9,\n\tIEEE80211_EDMG_BW_CONFIG_10 = 10,\n\tIEEE80211_EDMG_BW_CONFIG_11 = 11,\n\tIEEE80211_EDMG_BW_CONFIG_12 = 12,\n\tIEEE80211_EDMG_BW_CONFIG_13 = 13,\n\tIEEE80211_EDMG_BW_CONFIG_14 = 14,\n\tIEEE80211_EDMG_BW_CONFIG_15 = 15,\n};\n\nstruct ieee80211_edmg {\n\tu8 channels;\n\tenum ieee80211_edmg_bw_config bw_config;\n};\n\nstruct ieee80211_channel;\n\nstruct cfg80211_chan_def {\n\tstruct ieee80211_channel *chan;\n\tenum nl80211_chan_width width;\n\tu32 center_freq1;\n\tu32 center_freq2;\n\tstruct ieee80211_edmg edmg;\n\tu16 freq1_offset;\n};\n\nstruct ieee80211_mcs_info {\n\tu8 rx_mask[10];\n\t__le16 rx_highest;\n\tu8 tx_params;\n\tu8 reserved[3];\n};\n\nstruct ieee80211_ht_cap {\n\t__le16 cap_info;\n\tu8 ampdu_params_info;\n\tstruct ieee80211_mcs_info mcs;\n\t__le16 extended_ht_cap_info;\n\t__le32 tx_BF_cap_info;\n\tu8 antenna_selection_info;\n} __attribute__((packed));\n\nstruct key_params;\n\nstruct cfg80211_ibss_params {\n\tconst u8 *ssid;\n\tconst u8 *bssid;\n\tstruct cfg80211_chan_def chandef;\n\tconst u8 *ie;\n\tu8 ssid_len;\n\tu8 ie_len;\n\tu16 beacon_interval;\n\tu32 basic_rates;\n\tbool channel_fixed;\n\tbool privacy;\n\tbool control_port;\n\tbool control_port_over_nl80211;\n\tbool userspace_handles_dfs;\n\tint: 24;\n\tint mcast_rate[5];\n\tstruct ieee80211_ht_cap ht_capa;\n\tstruct ieee80211_ht_cap ht_capa_mask;\n\tstruct key_params *wep_keys;\n\tint wep_tx_key;\n\tint: 32;\n} __attribute__((packed));\n\nenum nl80211_auth_type {\n\tNL80211_AUTHTYPE_OPEN_SYSTEM = 0,\n\tNL80211_AUTHTYPE_SHARED_KEY = 1,\n\tNL80211_AUTHTYPE_FT = 2,\n\tNL80211_AUTHTYPE_NETWORK_EAP = 3,\n\tNL80211_AUTHTYPE_SAE = 4,\n\tNL80211_AUTHTYPE_FILS_SK = 5,\n\tNL80211_AUTHTYPE_FILS_SK_PFS = 6,\n\tNL80211_AUTHTYPE_FILS_PK = 7,\n\t__NL80211_AUTHTYPE_NUM = 8,\n\tNL80211_AUTHTYPE_MAX = 7,\n\tNL80211_AUTHTYPE_AUTOMATIC = 8,\n};\n\nenum nl80211_mfp {\n\tNL80211_MFP_NO = 0,\n\tNL80211_MFP_REQUIRED = 1,\n\tNL80211_MFP_OPTIONAL = 2,\n};\n\nenum nl80211_sae_pwe_mechanism {\n\tNL80211_SAE_PWE_UNSPECIFIED = 0,\n\tNL80211_SAE_PWE_HUNT_AND_PECK = 1,\n\tNL80211_SAE_PWE_HASH_TO_ELEMENT = 2,\n\tNL80211_SAE_PWE_BOTH = 3,\n};\n\nstruct cfg80211_crypto_settings {\n\tu32 wpa_versions;\n\tu32 cipher_group;\n\tint n_ciphers_pairwise;\n\tu32 ciphers_pairwise[5];\n\tint n_akm_suites;\n\tu32 akm_suites[2];\n\tbool control_port;\n\t__be16 control_port_ethertype;\n\tbool control_port_no_encrypt;\n\tbool control_port_over_nl80211;\n\tbool control_port_no_preauth;\n\tstruct key_params *wep_keys;\n\tint wep_tx_key;\n\tconst u8 *psk;\n\tconst u8 *sae_pwd;\n\tu8 sae_pwd_len;\n\tenum nl80211_sae_pwe_mechanism sae_pwe;\n};\n\nstruct ieee80211_vht_mcs_info {\n\t__le16 rx_mcs_map;\n\t__le16 rx_highest;\n\t__le16 tx_mcs_map;\n\t__le16 tx_highest;\n};\n\nstruct ieee80211_vht_cap {\n\t__le32 vht_cap_info;\n\tstruct ieee80211_vht_mcs_info supp_mcs;\n};\n\nenum nl80211_bss_select_attr {\n\t__NL80211_BSS_SELECT_ATTR_INVALID = 0,\n\tNL80211_BSS_SELECT_ATTR_RSSI = 1,\n\tNL80211_BSS_SELECT_ATTR_BAND_PREF = 2,\n\tNL80211_BSS_SELECT_ATTR_RSSI_ADJUST = 3,\n\t__NL80211_BSS_SELECT_ATTR_AFTER_LAST = 4,\n\tNL80211_BSS_SELECT_ATTR_MAX = 3,\n};\n\nenum nl80211_band {\n\tNL80211_BAND_2GHZ = 0,\n\tNL80211_BAND_5GHZ = 1,\n\tNL80211_BAND_60GHZ = 2,\n\tNL80211_BAND_6GHZ = 3,\n\tNL80211_BAND_S1GHZ = 4,\n\tNUM_NL80211_BANDS = 5,\n};\n\nstruct cfg80211_bss_select_adjust {\n\tenum nl80211_band band;\n\ts8 delta;\n};\n\nstruct cfg80211_bss_selection {\n\tenum nl80211_bss_select_attr behaviour;\n\tunion {\n\t\tenum nl80211_band band_pref;\n\t\tstruct cfg80211_bss_select_adjust adjust;\n\t} param;\n};\n\nstruct cfg80211_connect_params {\n\tstruct ieee80211_channel *channel;\n\tstruct ieee80211_channel *channel_hint;\n\tconst u8 *bssid;\n\tconst u8 *bssid_hint;\n\tconst u8 *ssid;\n\tsize_t ssid_len;\n\tenum nl80211_auth_type auth_type;\n\tint: 32;\n\tconst u8 *ie;\n\tsize_t ie_len;\n\tbool privacy;\n\tint: 24;\n\tenum nl80211_mfp mfp;\n\tstruct cfg80211_crypto_settings crypto;\n\tconst u8 *key;\n\tu8 key_len;\n\tu8 key_idx;\n\tshort: 16;\n\tu32 flags;\n\tint bg_scan_period;\n\tstruct ieee80211_ht_cap ht_capa;\n\tstruct ieee80211_ht_cap ht_capa_mask;\n\tstruct ieee80211_vht_cap vht_capa;\n\tstruct ieee80211_vht_cap vht_capa_mask;\n\tbool pbss;\n\tint: 24;\n\tstruct cfg80211_bss_selection bss_select;\n\tconst u8 *prev_bssid;\n\tconst u8 *fils_erp_username;\n\tsize_t fils_erp_username_len;\n\tconst u8 *fils_erp_realm;\n\tsize_t fils_erp_realm_len;\n\tu16 fils_erp_next_seq_num;\n\tlong: 48;\n\tconst u8 *fils_erp_rrk;\n\tsize_t fils_erp_rrk_len;\n\tbool want_1x;\n\tint: 24;\n\tstruct ieee80211_edmg edmg;\n\tint: 32;\n} __attribute__((packed));\n\nstruct cfg80211_cqm_config;\n\nstruct wiphy;\n\nstruct wireless_dev {\n\tstruct wiphy *wiphy;\n\tenum nl80211_iftype iftype;\n\tstruct list_head list;\n\tstruct net_device *netdev;\n\tu32 identifier;\n\tstruct list_head mgmt_registrations;\n\tspinlock_t mgmt_registrations_lock;\n\tu8 mgmt_registrations_need_update: 1;\n\tstruct mutex mtx;\n\tbool use_4addr;\n\tbool is_running;\n\tbool registered;\n\tbool registering;\n\tu8 address[6];\n\tu8 ssid[32];\n\tu8 ssid_len;\n\tu8 mesh_id_len;\n\tu8 mesh_id_up_len;\n\tstruct cfg80211_conn *conn;\n\tstruct cfg80211_cached_keys *connect_keys;\n\tenum ieee80211_bss_type conn_bss_type;\n\tu32 conn_owner_nlportid;\n\tstruct work_struct disconnect_wk;\n\tu8 disconnect_bssid[6];\n\tstruct list_head event_list;\n\tspinlock_t event_lock;\n\tstruct cfg80211_internal_bss *current_bss;\n\tstruct cfg80211_chan_def preset_chandef;\n\tstruct cfg80211_chan_def chandef;\n\tbool ibss_fixed;\n\tbool ibss_dfs_possible;\n\tbool ps;\n\tint ps_timeout;\n\tint beacon_interval;\n\tu32 ap_unexpected_nlportid;\n\tu32 owner_nlportid;\n\tbool nl_owner_dead;\n\tbool cac_started;\n\tlong unsigned int cac_start_time;\n\tunsigned int cac_time_ms;\n\tstruct {\n\t\tstruct cfg80211_ibss_params ibss;\n\t\tstruct cfg80211_connect_params connect;\n\t\tstruct cfg80211_cached_keys *keys;\n\t\tconst u8 *ie;\n\t\tsize_t ie_len;\n\t\tu8 bssid[6];\n\t\tu8 prev_bssid[6];\n\t\tu8 ssid[32];\n\t\ts8 default_key;\n\t\ts8 default_mgmt_key;\n\t\tbool prev_bssid_valid;\n\t} wext;\n\tstruct cfg80211_cqm_config *cqm_config;\n\tstruct list_head pmsr_list;\n\tspinlock_t pmsr_lock;\n\tstruct work_struct pmsr_free_wk;\n\tlong unsigned int unprot_beacon_reported;\n};\n\nstruct iw_encode_ext {\n\t__u32 ext_flags;\n\t__u8 tx_seq[8];\n\t__u8 rx_seq[8];\n\tstruct sockaddr addr;\n\t__u16 alg;\n\t__u16 key_len;\n\t__u8 key[0];\n};\n\nstruct iwreq {\n\tunion {\n\t\tchar ifrn_name[16];\n\t} ifr_ifrn;\n\tunion iwreq_data u;\n};\n\nstruct iw_event {\n\t__u16 len;\n\t__u16 cmd;\n\tunion iwreq_data u;\n};\n\nstruct compat_iw_point {\n\tcompat_caddr_t pointer;\n\t__u16 length;\n\t__u16 flags;\n};\n\nstruct __compat_iw_event {\n\t__u16 len;\n\t__u16 cmd;\n\tcompat_caddr_t pointer;\n};\n\nenum nl80211_reg_initiator {\n\tNL80211_REGDOM_SET_BY_CORE = 0,\n\tNL80211_REGDOM_SET_BY_USER = 1,\n\tNL80211_REGDOM_SET_BY_DRIVER = 2,\n\tNL80211_REGDOM_SET_BY_COUNTRY_IE = 3,\n};\n\nenum nl80211_dfs_regions {\n\tNL80211_DFS_UNSET = 0,\n\tNL80211_DFS_FCC = 1,\n\tNL80211_DFS_ETSI = 2,\n\tNL80211_DFS_JP = 3,\n};\n\nenum nl80211_user_reg_hint_type {\n\tNL80211_USER_REG_HINT_USER = 0,\n\tNL80211_USER_REG_HINT_CELL_BASE = 1,\n\tNL80211_USER_REG_HINT_INDOOR = 2,\n};\n\nenum nl80211_mntr_flags {\n\t__NL80211_MNTR_FLAG_INVALID = 0,\n\tNL80211_MNTR_FLAG_FCSFAIL = 1,\n\tNL80211_MNTR_FLAG_PLCPFAIL = 2,\n\tNL80211_MNTR_FLAG_CONTROL = 3,\n\tNL80211_MNTR_FLAG_OTHER_BSS = 4,\n\tNL80211_MNTR_FLAG_COOK_FRAMES = 5,\n\tNL80211_MNTR_FLAG_ACTIVE = 6,\n\t__NL80211_MNTR_FLAG_AFTER_LAST = 7,\n\tNL80211_MNTR_FLAG_MAX = 6,\n};\n\nenum nl80211_key_mode {\n\tNL80211_KEY_RX_TX = 0,\n\tNL80211_KEY_NO_TX = 1,\n\tNL80211_KEY_SET_TX = 2,\n};\n\nenum nl80211_bss_scan_width {\n\tNL80211_BSS_CHAN_WIDTH_20 = 0,\n\tNL80211_BSS_CHAN_WIDTH_10 = 1,\n\tNL80211_BSS_CHAN_WIDTH_5 = 2,\n\tNL80211_BSS_CHAN_WIDTH_1 = 3,\n\tNL80211_BSS_CHAN_WIDTH_2 = 4,\n};\n\nstruct nl80211_wowlan_tcp_data_seq {\n\t__u32 start;\n\t__u32 offset;\n\t__u32 len;\n};\n\nstruct nl80211_wowlan_tcp_data_token {\n\t__u32 offset;\n\t__u32 len;\n\t__u8 token_stream[0];\n};\n\nstruct nl80211_wowlan_tcp_data_token_feature {\n\t__u32 min_len;\n\t__u32 max_len;\n\t__u32 bufsize;\n};\n\nenum nl80211_ext_feature_index {\n\tNL80211_EXT_FEATURE_VHT_IBSS = 0,\n\tNL80211_EXT_FEATURE_RRM = 1,\n\tNL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER = 2,\n\tNL80211_EXT_FEATURE_SCAN_START_TIME = 3,\n\tNL80211_EXT_FEATURE_BSS_PARENT_TSF = 4,\n\tNL80211_EXT_FEATURE_SET_SCAN_DWELL = 5,\n\tNL80211_EXT_FEATURE_BEACON_RATE_LEGACY = 6,\n\tNL80211_EXT_FEATURE_BEACON_RATE_HT = 7,\n\tNL80211_EXT_FEATURE_BEACON_RATE_VHT = 8,\n\tNL80211_EXT_FEATURE_FILS_STA = 9,\n\tNL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA = 10,\n\tNL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED = 11,\n\tNL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI = 12,\n\tNL80211_EXT_FEATURE_CQM_RSSI_LIST = 13,\n\tNL80211_EXT_FEATURE_FILS_SK_OFFLOAD = 14,\n\tNL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK = 15,\n\tNL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X = 16,\n\tNL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME = 17,\n\tNL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP = 18,\n\tNL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE = 19,\n\tNL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 20,\n\tNL80211_EXT_FEATURE_MFP_OPTIONAL = 21,\n\tNL80211_EXT_FEATURE_LOW_SPAN_SCAN = 22,\n\tNL80211_EXT_FEATURE_LOW_POWER_SCAN = 23,\n\tNL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN = 24,\n\tNL80211_EXT_FEATURE_DFS_OFFLOAD = 25,\n\tNL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211 = 26,\n\tNL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT = 27,\n\tNL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = 27,\n\tNL80211_EXT_FEATURE_TXQS = 28,\n\tNL80211_EXT_FEATURE_SCAN_RANDOM_SN = 29,\n\tNL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT = 30,\n\tNL80211_EXT_FEATURE_CAN_REPLACE_PTK0 = 31,\n\tNL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER = 32,\n\tNL80211_EXT_FEATURE_AIRTIME_FAIRNESS = 33,\n\tNL80211_EXT_FEATURE_AP_PMKSA_CACHING = 34,\n\tNL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD = 35,\n\tNL80211_EXT_FEATURE_EXT_KEY_ID = 36,\n\tNL80211_EXT_FEATURE_STA_TX_PWR = 37,\n\tNL80211_EXT_FEATURE_SAE_OFFLOAD = 38,\n\tNL80211_EXT_FEATURE_VLAN_OFFLOAD = 39,\n\tNL80211_EXT_FEATURE_AQL = 40,\n\tNL80211_EXT_FEATURE_BEACON_PROTECTION = 41,\n\tNL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH = 42,\n\tNL80211_EXT_FEATURE_PROTECTED_TWT = 43,\n\tNL80211_EXT_FEATURE_DEL_IBSS_STA = 44,\n\tNL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS = 45,\n\tNL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT = 46,\n\tNL80211_EXT_FEATURE_SCAN_FREQ_KHZ = 47,\n\tNL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS = 48,\n\tNL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION = 49,\n\tNL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK = 50,\n\tNL80211_EXT_FEATURE_SAE_OFFLOAD_AP = 51,\n\tNL80211_EXT_FEATURE_FILS_DISCOVERY = 52,\n\tNL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP = 53,\n\tNL80211_EXT_FEATURE_BEACON_RATE_HE = 54,\n\tNL80211_EXT_FEATURE_SECURE_LTF = 55,\n\tNL80211_EXT_FEATURE_SECURE_RTT = 56,\n\tNL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE = 57,\n\tNUM_NL80211_EXT_FEATURES = 58,\n\tMAX_NL80211_EXT_FEATURES = 57,\n};\n\nenum nl80211_dfs_state {\n\tNL80211_DFS_USABLE = 0,\n\tNL80211_DFS_UNAVAILABLE = 1,\n\tNL80211_DFS_AVAILABLE = 2,\n};\n\nstruct nl80211_vendor_cmd_info {\n\t__u32 vendor_id;\n\t__u32 subcmd;\n};\n\nenum nl80211_sar_type {\n\tNL80211_SAR_TYPE_POWER = 0,\n\tNUM_NL80211_SAR_TYPE = 1,\n};\n\nstruct ieee80211_he_cap_elem {\n\tu8 mac_cap_info[6];\n\tu8 phy_cap_info[11];\n};\n\nstruct ieee80211_he_mcs_nss_supp {\n\t__le16 rx_mcs_80;\n\t__le16 tx_mcs_80;\n\t__le16 rx_mcs_160;\n\t__le16 tx_mcs_160;\n\t__le16 rx_mcs_80p80;\n\t__le16 tx_mcs_80p80;\n};\n\nstruct ieee80211_he_6ghz_capa {\n\t__le16 capa;\n};\n\nstruct rfkill;\n\nenum environment_cap {\n\tENVIRON_ANY = 0,\n\tENVIRON_INDOOR = 1,\n\tENVIRON_OUTDOOR = 2,\n};\n\nstruct regulatory_request {\n\tstruct callback_head callback_head;\n\tint wiphy_idx;\n\tenum nl80211_reg_initiator initiator;\n\tenum nl80211_user_reg_hint_type user_reg_hint_type;\n\tchar alpha2[3];\n\tenum nl80211_dfs_regions dfs_region;\n\tbool intersect;\n\tbool processed;\n\tenum environment_cap country_ie_env;\n\tstruct list_head list;\n};\n\nstruct ieee80211_freq_range {\n\tu32 start_freq_khz;\n\tu32 end_freq_khz;\n\tu32 max_bandwidth_khz;\n};\n\nstruct ieee80211_power_rule {\n\tu32 max_antenna_gain;\n\tu32 max_eirp;\n};\n\nstruct ieee80211_wmm_ac {\n\tu16 cw_min;\n\tu16 cw_max;\n\tu16 cot;\n\tu8 aifsn;\n};\n\nstruct ieee80211_wmm_rule {\n\tstruct ieee80211_wmm_ac client[4];\n\tstruct ieee80211_wmm_ac ap[4];\n};\n\nstruct ieee80211_reg_rule {\n\tstruct ieee80211_freq_range freq_range;\n\tstruct ieee80211_power_rule power_rule;\n\tstruct ieee80211_wmm_rule wmm_rule;\n\tu32 flags;\n\tu32 dfs_cac_ms;\n\tbool has_wmm;\n};\n\nstruct ieee80211_regdomain {\n\tstruct callback_head callback_head;\n\tu32 n_reg_rules;\n\tchar alpha2[3];\n\tenum nl80211_dfs_regions dfs_region;\n\tstruct ieee80211_reg_rule reg_rules[0];\n};\n\nstruct ieee80211_channel {\n\tenum nl80211_band band;\n\tu32 center_freq;\n\tu16 freq_offset;\n\tu16 hw_value;\n\tu32 flags;\n\tint max_antenna_gain;\n\tint max_power;\n\tint max_reg_power;\n\tbool beacon_found;\n\tu32 orig_flags;\n\tint orig_mag;\n\tint orig_mpwr;\n\tenum nl80211_dfs_state dfs_state;\n\tlong unsigned int dfs_state_entered;\n\tunsigned int dfs_cac_ms;\n};\n\nstruct ieee80211_rate {\n\tu32 flags;\n\tu16 bitrate;\n\tu16 hw_value;\n\tu16 hw_value_short;\n};\n\nstruct ieee80211_sta_ht_cap {\n\tu16 cap;\n\tbool ht_supported;\n\tu8 ampdu_factor;\n\tu8 ampdu_density;\n\tstruct ieee80211_mcs_info mcs;\n\tchar: 8;\n} __attribute__((packed));\n\nstruct ieee80211_sta_vht_cap {\n\tbool vht_supported;\n\tu32 cap;\n\tstruct ieee80211_vht_mcs_info vht_mcs;\n};\n\nstruct ieee80211_sta_he_cap {\n\tbool has_he;\n\tstruct ieee80211_he_cap_elem he_cap_elem;\n\tstruct ieee80211_he_mcs_nss_supp he_mcs_nss_supp;\n\tu8 ppe_thres[25];\n} __attribute__((packed));\n\nstruct ieee80211_sband_iftype_data {\n\tu16 types_mask;\n\tstruct ieee80211_sta_he_cap he_cap;\n\tstruct ieee80211_he_6ghz_capa he_6ghz_capa;\n\tlong: 40;\n\tstruct {\n\t\tconst u8 *data;\n\t\tunsigned int len;\n\t} vendor_elems;\n} __attribute__((packed));\n\nstruct ieee80211_sta_s1g_cap {\n\tbool s1g;\n\tu8 cap[10];\n\tu8 nss_mcs[5];\n};\n\nstruct ieee80211_supported_band {\n\tstruct ieee80211_channel *channels;\n\tstruct ieee80211_rate *bitrates;\n\tenum nl80211_band band;\n\tint n_channels;\n\tint n_bitrates;\n\tstruct ieee80211_sta_ht_cap ht_cap;\n\tstruct ieee80211_sta_vht_cap vht_cap;\n\tstruct ieee80211_sta_s1g_cap s1g_cap;\n\tstruct ieee80211_edmg edmg_cap;\n\tu16 n_iftype_data;\n\tconst struct ieee80211_sband_iftype_data *iftype_data;\n};\n\nstruct key_params {\n\tconst u8 *key;\n\tconst u8 *seq;\n\tint key_len;\n\tint seq_len;\n\tu16 vlan_id;\n\tu32 cipher;\n\tenum nl80211_key_mode mode;\n};\n\nstruct mac_address {\n\tu8 addr[6];\n};\n\nstruct cfg80211_sar_freq_ranges {\n\tu32 start_freq;\n\tu32 end_freq;\n};\n\nstruct cfg80211_sar_capa {\n\tenum nl80211_sar_type type;\n\tu32 num_freq_ranges;\n\tconst struct cfg80211_sar_freq_ranges *freq_ranges;\n};\n\nstruct cfg80211_ssid {\n\tu8 ssid[32];\n\tu8 ssid_len;\n};\n\nenum cfg80211_signal_type {\n\tCFG80211_SIGNAL_TYPE_NONE = 0,\n\tCFG80211_SIGNAL_TYPE_MBM = 1,\n\tCFG80211_SIGNAL_TYPE_UNSPEC = 2,\n};\n\nstruct ieee80211_txrx_stypes;\n\nstruct ieee80211_iface_combination;\n\nstruct wiphy_iftype_akm_suites;\n\nstruct wiphy_wowlan_support;\n\nstruct cfg80211_wowlan;\n\nstruct wiphy_iftype_ext_capab;\n\nstruct wiphy_coalesce_support;\n\nstruct wiphy_vendor_command;\n\nstruct cfg80211_pmsr_capabilities;\n\nstruct wiphy {\n\tstruct mutex mtx;\n\tu8 perm_addr[6];\n\tu8 addr_mask[6];\n\tstruct mac_address *addresses;\n\tconst struct ieee80211_txrx_stypes *mgmt_stypes;\n\tconst struct ieee80211_iface_combination *iface_combinations;\n\tint n_iface_combinations;\n\tu16 software_iftypes;\n\tu16 n_addresses;\n\tu16 interface_modes;\n\tu16 max_acl_mac_addrs;\n\tu32 flags;\n\tu32 regulatory_flags;\n\tu32 features;\n\tu8 ext_features[8];\n\tu32 ap_sme_capa;\n\tenum cfg80211_signal_type signal_type;\n\tint bss_priv_size;\n\tu8 max_scan_ssids;\n\tu8 max_sched_scan_reqs;\n\tu8 max_sched_scan_ssids;\n\tu8 max_match_sets;\n\tu16 max_scan_ie_len;\n\tu16 max_sched_scan_ie_len;\n\tu32 max_sched_scan_plans;\n\tu32 max_sched_scan_plan_interval;\n\tu32 max_sched_scan_plan_iterations;\n\tint n_cipher_suites;\n\tconst u32 *cipher_suites;\n\tint n_akm_suites;\n\tconst u32 *akm_suites;\n\tconst struct wiphy_iftype_akm_suites *iftype_akm_suites;\n\tunsigned int num_iftype_akm_suites;\n\tu8 retry_short;\n\tu8 retry_long;\n\tu32 frag_threshold;\n\tu32 rts_threshold;\n\tu8 coverage_class;\n\tchar fw_version[32];\n\tu32 hw_version;\n\tconst struct wiphy_wowlan_support *wowlan;\n\tstruct cfg80211_wowlan *wowlan_config;\n\tu16 max_remain_on_channel_duration;\n\tu8 max_num_pmkids;\n\tu32 available_antennas_tx;\n\tu32 available_antennas_rx;\n\tu32 probe_resp_offload;\n\tconst u8 *extended_capabilities;\n\tconst u8 *extended_capabilities_mask;\n\tu8 extended_capabilities_len;\n\tconst struct wiphy_iftype_ext_capab *iftype_ext_capab;\n\tunsigned int num_iftype_ext_capab;\n\tconst void *privid;\n\tstruct ieee80211_supported_band *bands[5];\n\tvoid (*reg_notifier)(struct wiphy *, struct regulatory_request *);\n\tconst struct ieee80211_regdomain *regd;\n\tstruct device dev;\n\tbool registered;\n\tstruct dentry *debugfsdir;\n\tconst struct ieee80211_ht_cap *ht_capa_mod_mask;\n\tconst struct ieee80211_vht_cap *vht_capa_mod_mask;\n\tstruct list_head wdev_list;\n\tpossible_net_t _net;\n\tconst struct iw_handler_def *wext;\n\tconst struct wiphy_coalesce_support *coalesce;\n\tconst struct wiphy_vendor_command *vendor_commands;\n\tconst struct nl80211_vendor_cmd_info *vendor_events;\n\tint n_vendor_commands;\n\tint n_vendor_events;\n\tu16 max_ap_assoc_sta;\n\tu8 max_num_csa_counters;\n\tu32 bss_select_support;\n\tu8 nan_supported_bands;\n\tu32 txq_limit;\n\tu32 txq_memory_limit;\n\tu32 txq_quantum;\n\tlong unsigned int tx_queue_len;\n\tu8 support_mbssid: 1;\n\tu8 support_only_he_mbssid: 1;\n\tconst struct cfg80211_pmsr_capabilities *pmsr_capa;\n\tstruct {\n\t\tu64 peer;\n\t\tu64 vif;\n\t\tu8 max_retry;\n\t} tid_config_support;\n\tu8 max_data_retry_count;\n\tconst struct cfg80211_sar_capa *sar_capa;\n\tstruct rfkill *rfkill;\n\tlong: 64;\n\tchar priv[0];\n};\n\nstruct cfg80211_match_set {\n\tstruct cfg80211_ssid ssid;\n\tu8 bssid[6];\n\ts32 rssi_thold;\n\ts32 per_band_rssi_thold[5];\n};\n\nstruct cfg80211_sched_scan_plan {\n\tu32 interval;\n\tu32 iterations;\n};\n\nstruct cfg80211_sched_scan_request {\n\tu64 reqid;\n\tstruct cfg80211_ssid *ssids;\n\tint n_ssids;\n\tu32 n_channels;\n\tenum nl80211_bss_scan_width scan_width;\n\tconst u8 *ie;\n\tsize_t ie_len;\n\tu32 flags;\n\tstruct cfg80211_match_set *match_sets;\n\tint n_match_sets;\n\ts32 min_rssi_thold;\n\tu32 delay;\n\tstruct cfg80211_sched_scan_plan *scan_plans;\n\tint n_scan_plans;\n\tu8 mac_addr[6];\n\tu8 mac_addr_mask[6];\n\tbool relative_rssi_set;\n\ts8 relative_rssi;\n\tstruct cfg80211_bss_select_adjust rssi_adjust;\n\tstruct wiphy *wiphy;\n\tstruct net_device *dev;\n\tlong unsigned int scan_start;\n\tbool report_results;\n\tstruct callback_head callback_head;\n\tu32 owner_nlportid;\n\tbool nl_owner_dead;\n\tstruct list_head list;\n\tstruct ieee80211_channel *channels[0];\n};\n\nstruct cfg80211_pkt_pattern {\n\tconst u8 *mask;\n\tconst u8 *pattern;\n\tint pattern_len;\n\tint pkt_offset;\n};\n\nstruct cfg80211_wowlan_tcp {\n\tstruct socket *sock;\n\t__be32 src;\n\t__be32 dst;\n\tu16 src_port;\n\tu16 dst_port;\n\tu8 dst_mac[6];\n\tint payload_len;\n\tconst u8 *payload;\n\tstruct nl80211_wowlan_tcp_data_seq payload_seq;\n\tu32 data_interval;\n\tu32 wake_len;\n\tconst u8 *wake_data;\n\tconst u8 *wake_mask;\n\tu32 tokens_size;\n\tstruct nl80211_wowlan_tcp_data_token payload_tok;\n};\n\nstruct cfg80211_wowlan {\n\tbool any;\n\tbool disconnect;\n\tbool magic_pkt;\n\tbool gtk_rekey_failure;\n\tbool eap_identity_req;\n\tbool four_way_handshake;\n\tbool rfkill_release;\n\tstruct cfg80211_pkt_pattern *patterns;\n\tstruct cfg80211_wowlan_tcp *tcp;\n\tint n_patterns;\n\tstruct cfg80211_sched_scan_request *nd_config;\n};\n\nstruct ieee80211_iface_limit {\n\tu16 max;\n\tu16 types;\n};\n\nstruct ieee80211_iface_combination {\n\tconst struct ieee80211_iface_limit *limits;\n\tu32 num_different_channels;\n\tu16 max_interfaces;\n\tu8 n_limits;\n\tbool beacon_int_infra_match;\n\tu8 radar_detect_widths;\n\tu8 radar_detect_regions;\n\tu32 beacon_int_min_gcd;\n};\n\nstruct ieee80211_txrx_stypes {\n\tu16 tx;\n\tu16 rx;\n};\n\nstruct wiphy_wowlan_tcp_support {\n\tconst struct nl80211_wowlan_tcp_data_token_feature *tok;\n\tu32 data_payload_max;\n\tu32 data_interval_max;\n\tu32 wake_payload_max;\n\tbool seq;\n};\n\nstruct wiphy_wowlan_support {\n\tu32 flags;\n\tint n_patterns;\n\tint pattern_max_len;\n\tint pattern_min_len;\n\tint max_pkt_offset;\n\tint max_nd_match_sets;\n\tconst struct wiphy_wowlan_tcp_support *tcp;\n};\n\nstruct wiphy_coalesce_support {\n\tint n_rules;\n\tint max_delay;\n\tint n_patterns;\n\tint pattern_max_len;\n\tint pattern_min_len;\n\tint max_pkt_offset;\n};\n\nstruct wiphy_vendor_command {\n\tstruct nl80211_vendor_cmd_info info;\n\tu32 flags;\n\tint (*doit)(struct wiphy *, struct wireless_dev *, const void *, int);\n\tint (*dumpit)(struct wiphy *, struct wireless_dev *, struct sk_buff *, const void *, int, long unsigned int *);\n\tconst struct nla_policy *policy;\n\tunsigned int maxattr;\n};\n\nstruct wiphy_iftype_ext_capab {\n\tenum nl80211_iftype iftype;\n\tconst u8 *extended_capabilities;\n\tconst u8 *extended_capabilities_mask;\n\tu8 extended_capabilities_len;\n};\n\nstruct cfg80211_pmsr_capabilities {\n\tunsigned int max_peers;\n\tu8 report_ap_tsf: 1;\n\tu8 randomize_mac_addr: 1;\n\tstruct {\n\t\tu32 preambles;\n\t\tu32 bandwidths;\n\t\ts8 max_bursts_exponent;\n\t\tu8 max_ftms_per_burst;\n\t\tu8 supported: 1;\n\t\tu8 asap: 1;\n\t\tu8 non_asap: 1;\n\t\tu8 request_lci: 1;\n\t\tu8 request_civicloc: 1;\n\t\tu8 trigger_based: 1;\n\t\tu8 non_trigger_based: 1;\n\t} ftm;\n};\n\nstruct wiphy_iftype_akm_suites {\n\tu16 iftypes_mask;\n\tconst u32 *akm_suites;\n\tint n_akm_suites;\n};\n\nstruct iw_ioctl_description {\n\t__u8 header_type;\n\t__u8 token_type;\n\t__u16 token_size;\n\t__u16 min_tokens;\n\t__u16 max_tokens;\n\t__u32 flags;\n};\n\ntypedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, unsigned int, struct iw_request_info *, iw_handler);\n\nstruct iw_thrspy {\n\tstruct sockaddr addr;\n\tstruct iw_quality qual;\n\tstruct iw_quality low;\n\tstruct iw_quality high;\n};\n\nstruct netlbl_af4list {\n\t__be32 addr;\n\t__be32 mask;\n\tu32 valid;\n\tstruct list_head list;\n};\n\nstruct netlbl_af6list {\n\tstruct in6_addr addr;\n\tstruct in6_addr mask;\n\tu32 valid;\n\tstruct list_head list;\n};\n\nstruct netlbl_domaddr_map {\n\tstruct list_head list4;\n\tstruct list_head list6;\n};\n\nstruct netlbl_dommap_def {\n\tu32 type;\n\tunion {\n\t\tstruct netlbl_domaddr_map *addrsel;\n\t\tstruct cipso_v4_doi *cipso;\n\t\tstruct calipso_doi *calipso;\n\t};\n};\n\nstruct netlbl_domaddr4_map {\n\tstruct netlbl_dommap_def def;\n\tstruct netlbl_af4list list;\n};\n\nstruct netlbl_domaddr6_map {\n\tstruct netlbl_dommap_def def;\n\tstruct netlbl_af6list list;\n};\n\nstruct netlbl_dom_map {\n\tchar *domain;\n\tu16 family;\n\tstruct netlbl_dommap_def def;\n\tu32 valid;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct netlbl_domhsh_tbl {\n\tstruct list_head *tbl;\n\tu32 size;\n};\n\nenum {\n\tNLBL_MGMT_C_UNSPEC = 0,\n\tNLBL_MGMT_C_ADD = 1,\n\tNLBL_MGMT_C_REMOVE = 2,\n\tNLBL_MGMT_C_LISTALL = 3,\n\tNLBL_MGMT_C_ADDDEF = 4,\n\tNLBL_MGMT_C_REMOVEDEF = 5,\n\tNLBL_MGMT_C_LISTDEF = 6,\n\tNLBL_MGMT_C_PROTOCOLS = 7,\n\tNLBL_MGMT_C_VERSION = 8,\n\t__NLBL_MGMT_C_MAX = 9,\n};\n\nenum {\n\tNLBL_MGMT_A_UNSPEC = 0,\n\tNLBL_MGMT_A_DOMAIN = 1,\n\tNLBL_MGMT_A_PROTOCOL = 2,\n\tNLBL_MGMT_A_VERSION = 3,\n\tNLBL_MGMT_A_CV4DOI = 4,\n\tNLBL_MGMT_A_IPV6ADDR = 5,\n\tNLBL_MGMT_A_IPV6MASK = 6,\n\tNLBL_MGMT_A_IPV4ADDR = 7,\n\tNLBL_MGMT_A_IPV4MASK = 8,\n\tNLBL_MGMT_A_ADDRSELECTOR = 9,\n\tNLBL_MGMT_A_SELECTORLIST = 10,\n\tNLBL_MGMT_A_FAMILY = 11,\n\tNLBL_MGMT_A_CLPDOI = 12,\n\t__NLBL_MGMT_A_MAX = 13,\n};\n\nstruct netlbl_domhsh_walk_arg {\n\tstruct netlink_callback *nl_cb;\n\tstruct sk_buff *skb;\n\tu32 seq;\n};\n\nenum {\n\tNLBL_UNLABEL_C_UNSPEC = 0,\n\tNLBL_UNLABEL_C_ACCEPT = 1,\n\tNLBL_UNLABEL_C_LIST = 2,\n\tNLBL_UNLABEL_C_STATICADD = 3,\n\tNLBL_UNLABEL_C_STATICREMOVE = 4,\n\tNLBL_UNLABEL_C_STATICLIST = 5,\n\tNLBL_UNLABEL_C_STATICADDDEF = 6,\n\tNLBL_UNLABEL_C_STATICREMOVEDEF = 7,\n\tNLBL_UNLABEL_C_STATICLISTDEF = 8,\n\t__NLBL_UNLABEL_C_MAX = 9,\n};\n\nenum {\n\tNLBL_UNLABEL_A_UNSPEC = 0,\n\tNLBL_UNLABEL_A_ACPTFLG = 1,\n\tNLBL_UNLABEL_A_IPV6ADDR = 2,\n\tNLBL_UNLABEL_A_IPV6MASK = 3,\n\tNLBL_UNLABEL_A_IPV4ADDR = 4,\n\tNLBL_UNLABEL_A_IPV4MASK = 5,\n\tNLBL_UNLABEL_A_IFACE = 6,\n\tNLBL_UNLABEL_A_SECCTX = 7,\n\t__NLBL_UNLABEL_A_MAX = 8,\n};\n\nstruct netlbl_unlhsh_tbl {\n\tstruct list_head *tbl;\n\tu32 size;\n};\n\nstruct netlbl_unlhsh_addr4 {\n\tu32 secid;\n\tstruct netlbl_af4list list;\n\tstruct callback_head rcu;\n};\n\nstruct netlbl_unlhsh_addr6 {\n\tu32 secid;\n\tstruct netlbl_af6list list;\n\tstruct callback_head rcu;\n};\n\nstruct netlbl_unlhsh_iface {\n\tint ifindex;\n\tstruct list_head addr4_list;\n\tstruct list_head addr6_list;\n\tu32 valid;\n\tstruct list_head list;\n\tstruct callback_head rcu;\n};\n\nstruct netlbl_unlhsh_walk_arg {\n\tstruct netlink_callback *nl_cb;\n\tstruct sk_buff *skb;\n\tu32 seq;\n};\n\nenum {\n\tNLBL_CIPSOV4_C_UNSPEC = 0,\n\tNLBL_CIPSOV4_C_ADD = 1,\n\tNLBL_CIPSOV4_C_REMOVE = 2,\n\tNLBL_CIPSOV4_C_LIST = 3,\n\tNLBL_CIPSOV4_C_LISTALL = 4,\n\t__NLBL_CIPSOV4_C_MAX = 5,\n};\n\nenum {\n\tNLBL_CIPSOV4_A_UNSPEC = 0,\n\tNLBL_CIPSOV4_A_DOI = 1,\n\tNLBL_CIPSOV4_A_MTYPE = 2,\n\tNLBL_CIPSOV4_A_TAG = 3,\n\tNLBL_CIPSOV4_A_TAGLST = 4,\n\tNLBL_CIPSOV4_A_MLSLVLLOC = 5,\n\tNLBL_CIPSOV4_A_MLSLVLREM = 6,\n\tNLBL_CIPSOV4_A_MLSLVL = 7,\n\tNLBL_CIPSOV4_A_MLSLVLLST = 8,\n\tNLBL_CIPSOV4_A_MLSCATLOC = 9,\n\tNLBL_CIPSOV4_A_MLSCATREM = 10,\n\tNLBL_CIPSOV4_A_MLSCAT = 11,\n\tNLBL_CIPSOV4_A_MLSCATLST = 12,\n\t__NLBL_CIPSOV4_A_MAX = 13,\n};\n\nstruct netlbl_cipsov4_doiwalk_arg {\n\tstruct netlink_callback *nl_cb;\n\tstruct sk_buff *skb;\n\tu32 seq;\n};\n\nstruct netlbl_domhsh_walk_arg___2 {\n\tstruct netlbl_audit *audit_info;\n\tu32 doi;\n};\n\nenum {\n\tNLBL_CALIPSO_C_UNSPEC = 0,\n\tNLBL_CALIPSO_C_ADD = 1,\n\tNLBL_CALIPSO_C_REMOVE = 2,\n\tNLBL_CALIPSO_C_LIST = 3,\n\tNLBL_CALIPSO_C_LISTALL = 4,\n\t__NLBL_CALIPSO_C_MAX = 5,\n};\n\nenum {\n\tNLBL_CALIPSO_A_UNSPEC = 0,\n\tNLBL_CALIPSO_A_DOI = 1,\n\tNLBL_CALIPSO_A_MTYPE = 2,\n\t__NLBL_CALIPSO_A_MAX = 3,\n};\n\nstruct netlbl_calipso_doiwalk_arg {\n\tstruct netlink_callback *nl_cb;\n\tstruct sk_buff *skb;\n\tu32 seq;\n};\n\nstruct dcbmsg {\n\t__u8 dcb_family;\n\t__u8 cmd;\n\t__u16 dcb_pad;\n};\n\nenum dcbnl_commands {\n\tDCB_CMD_UNDEFINED = 0,\n\tDCB_CMD_GSTATE = 1,\n\tDCB_CMD_SSTATE = 2,\n\tDCB_CMD_PGTX_GCFG = 3,\n\tDCB_CMD_PGTX_SCFG = 4,\n\tDCB_CMD_PGRX_GCFG = 5,\n\tDCB_CMD_PGRX_SCFG = 6,\n\tDCB_CMD_PFC_GCFG = 7,\n\tDCB_CMD_PFC_SCFG = 8,\n\tDCB_CMD_SET_ALL = 9,\n\tDCB_CMD_GPERM_HWADDR = 10,\n\tDCB_CMD_GCAP = 11,\n\tDCB_CMD_GNUMTCS = 12,\n\tDCB_CMD_SNUMTCS = 13,\n\tDCB_CMD_PFC_GSTATE = 14,\n\tDCB_CMD_PFC_SSTATE = 15,\n\tDCB_CMD_BCN_GCFG = 16,\n\tDCB_CMD_BCN_SCFG = 17,\n\tDCB_CMD_GAPP = 18,\n\tDCB_CMD_SAPP = 19,\n\tDCB_CMD_IEEE_SET = 20,\n\tDCB_CMD_IEEE_GET = 21,\n\tDCB_CMD_GDCBX = 22,\n\tDCB_CMD_SDCBX = 23,\n\tDCB_CMD_GFEATCFG = 24,\n\tDCB_CMD_SFEATCFG = 25,\n\tDCB_CMD_CEE_GET = 26,\n\tDCB_CMD_IEEE_DEL = 27,\n\t__DCB_CMD_ENUM_MAX = 28,\n\tDCB_CMD_MAX = 27,\n};\n\nenum dcbnl_attrs {\n\tDCB_ATTR_UNDEFINED = 0,\n\tDCB_ATTR_IFNAME = 1,\n\tDCB_ATTR_STATE = 2,\n\tDCB_ATTR_PFC_STATE = 3,\n\tDCB_ATTR_PFC_CFG = 4,\n\tDCB_ATTR_NUM_TC = 5,\n\tDCB_ATTR_PG_CFG = 6,\n\tDCB_ATTR_SET_ALL = 7,\n\tDCB_ATTR_PERM_HWADDR = 8,\n\tDCB_ATTR_CAP = 9,\n\tDCB_ATTR_NUMTCS = 10,\n\tDCB_ATTR_BCN = 11,\n\tDCB_ATTR_APP = 12,\n\tDCB_ATTR_IEEE = 13,\n\tDCB_ATTR_DCBX = 14,\n\tDCB_ATTR_FEATCFG = 15,\n\tDCB_ATTR_CEE = 16,\n\t__DCB_ATTR_ENUM_MAX = 17,\n\tDCB_ATTR_MAX = 16,\n};\n\nenum ieee_attrs {\n\tDCB_ATTR_IEEE_UNSPEC = 0,\n\tDCB_ATTR_IEEE_ETS = 1,\n\tDCB_ATTR_IEEE_PFC = 2,\n\tDCB_ATTR_IEEE_APP_TABLE = 3,\n\tDCB_ATTR_IEEE_PEER_ETS = 4,\n\tDCB_ATTR_IEEE_PEER_PFC = 5,\n\tDCB_ATTR_IEEE_PEER_APP = 6,\n\tDCB_ATTR_IEEE_MAXRATE = 7,\n\tDCB_ATTR_IEEE_QCN = 8,\n\tDCB_ATTR_IEEE_QCN_STATS = 9,\n\tDCB_ATTR_DCB_BUFFER = 10,\n\t__DCB_ATTR_IEEE_MAX = 11,\n};\n\nenum ieee_attrs_app {\n\tDCB_ATTR_IEEE_APP_UNSPEC = 0,\n\tDCB_ATTR_IEEE_APP = 1,\n\t__DCB_ATTR_IEEE_APP_MAX = 2,\n};\n\nenum cee_attrs {\n\tDCB_ATTR_CEE_UNSPEC = 0,\n\tDCB_ATTR_CEE_PEER_PG = 1,\n\tDCB_ATTR_CEE_PEER_PFC = 2,\n\tDCB_ATTR_CEE_PEER_APP_TABLE = 3,\n\tDCB_ATTR_CEE_TX_PG = 4,\n\tDCB_ATTR_CEE_RX_PG = 5,\n\tDCB_ATTR_CEE_PFC = 6,\n\tDCB_ATTR_CEE_APP_TABLE = 7,\n\tDCB_ATTR_CEE_FEAT = 8,\n\t__DCB_ATTR_CEE_MAX = 9,\n};\n\nenum peer_app_attr {\n\tDCB_ATTR_CEE_PEER_APP_UNSPEC = 0,\n\tDCB_ATTR_CEE_PEER_APP_INFO = 1,\n\tDCB_ATTR_CEE_PEER_APP = 2,\n\t__DCB_ATTR_CEE_PEER_APP_MAX = 3,\n};\n\nenum dcbnl_pfc_up_attrs {\n\tDCB_PFC_UP_ATTR_UNDEFINED = 0,\n\tDCB_PFC_UP_ATTR_0 = 1,\n\tDCB_PFC_UP_ATTR_1 = 2,\n\tDCB_PFC_UP_ATTR_2 = 3,\n\tDCB_PFC_UP_ATTR_3 = 4,\n\tDCB_PFC_UP_ATTR_4 = 5,\n\tDCB_PFC_UP_ATTR_5 = 6,\n\tDCB_PFC_UP_ATTR_6 = 7,\n\tDCB_PFC_UP_ATTR_7 = 8,\n\tDCB_PFC_UP_ATTR_ALL = 9,\n\t__DCB_PFC_UP_ATTR_ENUM_MAX = 10,\n\tDCB_PFC_UP_ATTR_MAX = 9,\n};\n\nenum dcbnl_pg_attrs {\n\tDCB_PG_ATTR_UNDEFINED = 0,\n\tDCB_PG_ATTR_TC_0 = 1,\n\tDCB_PG_ATTR_TC_1 = 2,\n\tDCB_PG_ATTR_TC_2 = 3,\n\tDCB_PG_ATTR_TC_3 = 4,\n\tDCB_PG_ATTR_TC_4 = 5,\n\tDCB_PG_ATTR_TC_5 = 6,\n\tDCB_PG_ATTR_TC_6 = 7,\n\tDCB_PG_ATTR_TC_7 = 8,\n\tDCB_PG_ATTR_TC_MAX = 9,\n\tDCB_PG_ATTR_TC_ALL = 10,\n\tDCB_PG_ATTR_BW_ID_0 = 11,\n\tDCB_PG_ATTR_BW_ID_1 = 12,\n\tDCB_PG_ATTR_BW_ID_2 = 13,\n\tDCB_PG_ATTR_BW_ID_3 = 14,\n\tDCB_PG_ATTR_BW_ID_4 = 15,\n\tDCB_PG_ATTR_BW_ID_5 = 16,\n\tDCB_PG_ATTR_BW_ID_6 = 17,\n\tDCB_PG_ATTR_BW_ID_7 = 18,\n\tDCB_PG_ATTR_BW_ID_MAX = 19,\n\tDCB_PG_ATTR_BW_ID_ALL = 20,\n\t__DCB_PG_ATTR_ENUM_MAX = 21,\n\tDCB_PG_ATTR_MAX = 20,\n};\n\nenum dcbnl_tc_attrs {\n\tDCB_TC_ATTR_PARAM_UNDEFINED = 0,\n\tDCB_TC_ATTR_PARAM_PGID = 1,\n\tDCB_TC_ATTR_PARAM_UP_MAPPING = 2,\n\tDCB_TC_ATTR_PARAM_STRICT_PRIO = 3,\n\tDCB_TC_ATTR_PARAM_BW_PCT = 4,\n\tDCB_TC_ATTR_PARAM_ALL = 5,\n\t__DCB_TC_ATTR_PARAM_ENUM_MAX = 6,\n\tDCB_TC_ATTR_PARAM_MAX = 5,\n};\n\nenum dcbnl_cap_attrs {\n\tDCB_CAP_ATTR_UNDEFINED = 0,\n\tDCB_CAP_ATTR_ALL = 1,\n\tDCB_CAP_ATTR_PG = 2,\n\tDCB_CAP_ATTR_PFC = 3,\n\tDCB_CAP_ATTR_UP2TC = 4,\n\tDCB_CAP_ATTR_PG_TCS = 5,\n\tDCB_CAP_ATTR_PFC_TCS = 6,\n\tDCB_CAP_ATTR_GSP = 7,\n\tDCB_CAP_ATTR_BCN = 8,\n\tDCB_CAP_ATTR_DCBX = 9,\n\t__DCB_CAP_ATTR_ENUM_MAX = 10,\n\tDCB_CAP_ATTR_MAX = 9,\n};\n\nenum dcbnl_numtcs_attrs {\n\tDCB_NUMTCS_ATTR_UNDEFINED = 0,\n\tDCB_NUMTCS_ATTR_ALL = 1,\n\tDCB_NUMTCS_ATTR_PG = 2,\n\tDCB_NUMTCS_ATTR_PFC = 3,\n\t__DCB_NUMTCS_ATTR_ENUM_MAX = 4,\n\tDCB_NUMTCS_ATTR_MAX = 3,\n};\n\nenum dcbnl_bcn_attrs {\n\tDCB_BCN_ATTR_UNDEFINED = 0,\n\tDCB_BCN_ATTR_RP_0 = 1,\n\tDCB_BCN_ATTR_RP_1 = 2,\n\tDCB_BCN_ATTR_RP_2 = 3,\n\tDCB_BCN_ATTR_RP_3 = 4,\n\tDCB_BCN_ATTR_RP_4 = 5,\n\tDCB_BCN_ATTR_RP_5 = 6,\n\tDCB_BCN_ATTR_RP_6 = 7,\n\tDCB_BCN_ATTR_RP_7 = 8,\n\tDCB_BCN_ATTR_RP_ALL = 9,\n\tDCB_BCN_ATTR_BCNA_0 = 10,\n\tDCB_BCN_ATTR_BCNA_1 = 11,\n\tDCB_BCN_ATTR_ALPHA = 12,\n\tDCB_BCN_ATTR_BETA = 13,\n\tDCB_BCN_ATTR_GD = 14,\n\tDCB_BCN_ATTR_GI = 15,\n\tDCB_BCN_ATTR_TMAX = 16,\n\tDCB_BCN_ATTR_TD = 17,\n\tDCB_BCN_ATTR_RMIN = 18,\n\tDCB_BCN_ATTR_W = 19,\n\tDCB_BCN_ATTR_RD = 20,\n\tDCB_BCN_ATTR_RU = 21,\n\tDCB_BCN_ATTR_WRTT = 22,\n\tDCB_BCN_ATTR_RI = 23,\n\tDCB_BCN_ATTR_C = 24,\n\tDCB_BCN_ATTR_ALL = 25,\n\t__DCB_BCN_ATTR_ENUM_MAX = 26,\n\tDCB_BCN_ATTR_MAX = 25,\n};\n\nenum dcb_general_attr_values {\n\tDCB_ATTR_VALUE_UNDEFINED = 255,\n};\n\nenum dcbnl_app_attrs {\n\tDCB_APP_ATTR_UNDEFINED = 0,\n\tDCB_APP_ATTR_IDTYPE = 1,\n\tDCB_APP_ATTR_ID = 2,\n\tDCB_APP_ATTR_PRIORITY = 3,\n\t__DCB_APP_ATTR_ENUM_MAX = 4,\n\tDCB_APP_ATTR_MAX = 3,\n};\n\nenum dcbnl_featcfg_attrs {\n\tDCB_FEATCFG_ATTR_UNDEFINED = 0,\n\tDCB_FEATCFG_ATTR_ALL = 1,\n\tDCB_FEATCFG_ATTR_PG = 2,\n\tDCB_FEATCFG_ATTR_PFC = 3,\n\tDCB_FEATCFG_ATTR_APP = 4,\n\t__DCB_FEATCFG_ATTR_ENUM_MAX = 5,\n\tDCB_FEATCFG_ATTR_MAX = 4,\n};\n\nstruct dcb_app_type {\n\tint ifindex;\n\tstruct dcb_app app;\n\tstruct list_head list;\n\tu8 dcbx;\n};\n\nstruct dcb_ieee_app_prio_map {\n\tu64 map[8];\n};\n\nstruct dcb_ieee_app_dscp_map {\n\tu8 map[64];\n};\n\nenum dcbevent_notif_type {\n\tDCB_APP_EVENT = 1,\n};\n\nstruct reply_func {\n\tint type;\n\tint (*cb)(struct net_device *, struct nlmsghdr *, u32, struct nlattr **, struct sk_buff *);\n};\n\nenum switchdev_attr_id {\n\tSWITCHDEV_ATTR_ID_UNDEFINED = 0,\n\tSWITCHDEV_ATTR_ID_PORT_STP_STATE = 1,\n\tSWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS = 2,\n\tSWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS = 3,\n\tSWITCHDEV_ATTR_ID_PORT_MROUTER = 4,\n\tSWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME = 5,\n\tSWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING = 6,\n\tSWITCHDEV_ATTR_ID_BRIDGE_VLAN_PROTOCOL = 7,\n\tSWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED = 8,\n\tSWITCHDEV_ATTR_ID_BRIDGE_MROUTER = 9,\n\tSWITCHDEV_ATTR_ID_MRP_PORT_ROLE = 10,\n};\n\nstruct switchdev_attr {\n\tstruct net_device *orig_dev;\n\tenum switchdev_attr_id id;\n\tu32 flags;\n\tvoid *complete_priv;\n\tvoid (*complete)(struct net_device *, int, void *);\n\tunion {\n\t\tu8 stp_state;\n\t\tstruct switchdev_brport_flags brport_flags;\n\t\tbool mrouter;\n\t\tclock_t ageing_time;\n\t\tbool vlan_filtering;\n\t\tu16 vlan_protocol;\n\t\tbool mc_disabled;\n\t\tu8 mrp_port_role;\n\t} u;\n};\n\nenum switchdev_notifier_type {\n\tSWITCHDEV_FDB_ADD_TO_BRIDGE = 1,\n\tSWITCHDEV_FDB_DEL_TO_BRIDGE = 2,\n\tSWITCHDEV_FDB_ADD_TO_DEVICE = 3,\n\tSWITCHDEV_FDB_DEL_TO_DEVICE = 4,\n\tSWITCHDEV_FDB_OFFLOADED = 5,\n\tSWITCHDEV_FDB_FLUSH_TO_BRIDGE = 6,\n\tSWITCHDEV_PORT_OBJ_ADD = 7,\n\tSWITCHDEV_PORT_OBJ_DEL = 8,\n\tSWITCHDEV_PORT_ATTR_SET = 9,\n\tSWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE = 10,\n\tSWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE = 11,\n\tSWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE = 12,\n\tSWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE = 13,\n\tSWITCHDEV_VXLAN_FDB_OFFLOADED = 14,\n};\n\nstruct switchdev_notifier_info {\n\tstruct net_device *dev;\n\tstruct netlink_ext_ack *extack;\n\tconst void *ctx;\n};\n\nstruct switchdev_notifier_port_obj_info {\n\tstruct switchdev_notifier_info info;\n\tconst struct switchdev_obj *obj;\n\tbool handled;\n};\n\nstruct switchdev_notifier_port_attr_info {\n\tstruct switchdev_notifier_info info;\n\tconst struct switchdev_attr *attr;\n\tbool handled;\n};\n\ntypedef void switchdev_deferred_func_t(struct net_device *, const void *);\n\nstruct switchdev_deferred_item {\n\tstruct list_head list;\n\tstruct net_device *dev;\n\tswitchdev_deferred_func_t *func;\n\tlong unsigned int data[0];\n};\n\ntypedef int (*lookup_by_table_id_t)(struct net *, u32);\n\nstruct l3mdev_handler {\n\tlookup_by_table_id_t dev_lookup;\n};\n\nstruct ncsi_dev {\n\tint state;\n\tint link_up;\n\tstruct net_device *dev;\n\tvoid (*handler)(struct ncsi_dev *);\n};\n\nenum {\n\tNCSI_CAP_BASE = 0,\n\tNCSI_CAP_GENERIC = 0,\n\tNCSI_CAP_BC = 1,\n\tNCSI_CAP_MC = 2,\n\tNCSI_CAP_BUFFER = 3,\n\tNCSI_CAP_AEN = 4,\n\tNCSI_CAP_VLAN = 5,\n\tNCSI_CAP_MAX = 6,\n};\n\nenum {\n\tNCSI_MODE_BASE = 0,\n\tNCSI_MODE_ENABLE = 0,\n\tNCSI_MODE_TX_ENABLE = 1,\n\tNCSI_MODE_LINK = 2,\n\tNCSI_MODE_VLAN = 3,\n\tNCSI_MODE_BC = 4,\n\tNCSI_MODE_MC = 5,\n\tNCSI_MODE_AEN = 6,\n\tNCSI_MODE_FC = 7,\n\tNCSI_MODE_MAX = 8,\n};\n\nstruct ncsi_channel_version {\n\tu32 version;\n\tu32 alpha2;\n\tu8 fw_name[12];\n\tu32 fw_version;\n\tu16 pci_ids[4];\n\tu32 mf_id;\n};\n\nstruct ncsi_channel_cap {\n\tu32 index;\n\tu32 cap;\n};\n\nstruct ncsi_channel_mode {\n\tu32 index;\n\tu32 enable;\n\tu32 size;\n\tu32 data[8];\n};\n\nstruct ncsi_channel_mac_filter {\n\tu8 n_uc;\n\tu8 n_mc;\n\tu8 n_mixed;\n\tu64 bitmap;\n\tunsigned char *addrs;\n};\n\nstruct ncsi_channel_vlan_filter {\n\tu8 n_vids;\n\tu64 bitmap;\n\tu16 *vids;\n};\n\nstruct ncsi_channel_stats {\n\tu32 hnc_cnt_hi;\n\tu32 hnc_cnt_lo;\n\tu32 hnc_rx_bytes;\n\tu32 hnc_tx_bytes;\n\tu32 hnc_rx_uc_pkts;\n\tu32 hnc_rx_mc_pkts;\n\tu32 hnc_rx_bc_pkts;\n\tu32 hnc_tx_uc_pkts;\n\tu32 hnc_tx_mc_pkts;\n\tu32 hnc_tx_bc_pkts;\n\tu32 hnc_fcs_err;\n\tu32 hnc_align_err;\n\tu32 hnc_false_carrier;\n\tu32 hnc_runt_pkts;\n\tu32 hnc_jabber_pkts;\n\tu32 hnc_rx_pause_xon;\n\tu32 hnc_rx_pause_xoff;\n\tu32 hnc_tx_pause_xon;\n\tu32 hnc_tx_pause_xoff;\n\tu32 hnc_tx_s_collision;\n\tu32 hnc_tx_m_collision;\n\tu32 hnc_l_collision;\n\tu32 hnc_e_collision;\n\tu32 hnc_rx_ctl_frames;\n\tu32 hnc_rx_64_frames;\n\tu32 hnc_rx_127_frames;\n\tu32 hnc_rx_255_frames;\n\tu32 hnc_rx_511_frames;\n\tu32 hnc_rx_1023_frames;\n\tu32 hnc_rx_1522_frames;\n\tu32 hnc_rx_9022_frames;\n\tu32 hnc_tx_64_frames;\n\tu32 hnc_tx_127_frames;\n\tu32 hnc_tx_255_frames;\n\tu32 hnc_tx_511_frames;\n\tu32 hnc_tx_1023_frames;\n\tu32 hnc_tx_1522_frames;\n\tu32 hnc_tx_9022_frames;\n\tu32 hnc_rx_valid_bytes;\n\tu32 hnc_rx_runt_pkts;\n\tu32 hnc_rx_jabber_pkts;\n\tu32 ncsi_rx_cmds;\n\tu32 ncsi_dropped_cmds;\n\tu32 ncsi_cmd_type_errs;\n\tu32 ncsi_cmd_csum_errs;\n\tu32 ncsi_rx_pkts;\n\tu32 ncsi_tx_pkts;\n\tu32 ncsi_tx_aen_pkts;\n\tu32 pt_tx_pkts;\n\tu32 pt_tx_dropped;\n\tu32 pt_tx_channel_err;\n\tu32 pt_tx_us_err;\n\tu32 pt_rx_pkts;\n\tu32 pt_rx_dropped;\n\tu32 pt_rx_channel_err;\n\tu32 pt_rx_us_err;\n\tu32 pt_rx_os_err;\n};\n\nstruct ncsi_package;\n\nstruct ncsi_channel {\n\tunsigned char id;\n\tint state;\n\tbool reconfigure_needed;\n\tspinlock_t lock;\n\tstruct ncsi_package *package;\n\tstruct ncsi_channel_version version;\n\tstruct ncsi_channel_cap caps[6];\n\tstruct ncsi_channel_mode modes[8];\n\tstruct ncsi_channel_mac_filter mac_filter;\n\tstruct ncsi_channel_vlan_filter vlan_filter;\n\tstruct ncsi_channel_stats stats;\n\tstruct {\n\t\tstruct timer_list timer;\n\t\tbool enabled;\n\t\tunsigned int state;\n\t} monitor;\n\tstruct list_head node;\n\tstruct list_head link;\n};\n\nstruct ncsi_dev_priv;\n\nstruct ncsi_package {\n\tunsigned char id;\n\tunsigned char uuid[16];\n\tstruct ncsi_dev_priv *ndp;\n\tspinlock_t lock;\n\tunsigned int channel_num;\n\tstruct list_head channels;\n\tstruct list_head node;\n\tbool multi_channel;\n\tu32 channel_whitelist;\n\tstruct ncsi_channel *preferred_channel;\n};\n\nstruct ncsi_request {\n\tunsigned char id;\n\tbool used;\n\tunsigned int flags;\n\tstruct ncsi_dev_priv *ndp;\n\tstruct sk_buff *cmd;\n\tstruct sk_buff *rsp;\n\tstruct timer_list timer;\n\tbool enabled;\n\tu32 snd_seq;\n\tu32 snd_portid;\n\tstruct nlmsghdr nlhdr;\n};\n\nstruct ncsi_dev_priv {\n\tstruct ncsi_dev ndev;\n\tunsigned int flags;\n\tunsigned int gma_flag;\n\tspinlock_t lock;\n\tunsigned int package_probe_id;\n\tunsigned int package_num;\n\tstruct list_head packages;\n\tstruct ncsi_channel *hot_channel;\n\tstruct ncsi_request requests[256];\n\tunsigned int request_id;\n\tunsigned int pending_req_num;\n\tstruct ncsi_package *active_package;\n\tstruct ncsi_channel *active_channel;\n\tstruct list_head channel_queue;\n\tstruct work_struct work;\n\tstruct packet_type ptype;\n\tstruct list_head node;\n\tstruct list_head vlan_vids;\n\tbool multi_package;\n\tbool mlx_multi_host;\n\tu32 package_whitelist;\n};\n\nstruct ncsi_cmd_arg {\n\tstruct ncsi_dev_priv *ndp;\n\tunsigned char type;\n\tunsigned char id;\n\tunsigned char package;\n\tunsigned char channel;\n\tshort unsigned int payload;\n\tunsigned int req_flags;\n\tunion {\n\t\tunsigned char bytes[16];\n\t\tshort unsigned int words[8];\n\t\tunsigned int dwords[4];\n\t};\n\tunsigned char *data;\n\tstruct genl_info *info;\n};\n\nstruct ncsi_pkt_hdr {\n\tunsigned char mc_id;\n\tunsigned char revision;\n\tunsigned char reserved;\n\tunsigned char id;\n\tunsigned char type;\n\tunsigned char channel;\n\t__be16 length;\n\t__be32 reserved1[2];\n};\n\nstruct ncsi_cmd_pkt_hdr {\n\tstruct ncsi_pkt_hdr common;\n};\n\nstruct ncsi_cmd_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\t__be32 checksum;\n\tunsigned char pad[26];\n};\n\nstruct ncsi_cmd_sp_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\tunsigned char reserved[3];\n\tunsigned char hw_arbitration;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_cmd_dc_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\tunsigned char reserved[3];\n\tunsigned char ald;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_cmd_rc_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\t__be32 reserved;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_cmd_ae_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\tunsigned char reserved[3];\n\tunsigned char mc_id;\n\t__be32 mode;\n\t__be32 checksum;\n\tunsigned char pad[18];\n};\n\nstruct ncsi_cmd_sl_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\t__be32 mode;\n\t__be32 oem_mode;\n\t__be32 checksum;\n\tunsigned char pad[18];\n};\n\nstruct ncsi_cmd_svf_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\t__be16 reserved;\n\t__be16 vlan;\n\t__be16 reserved1;\n\tunsigned char index;\n\tunsigned char enable;\n\t__be32 checksum;\n\tunsigned char pad[18];\n};\n\nstruct ncsi_cmd_ev_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\tunsigned char reserved[3];\n\tunsigned char mode;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_cmd_sma_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\tunsigned char mac[6];\n\tunsigned char index;\n\tunsigned char at_e;\n\t__be32 checksum;\n\tunsigned char pad[18];\n};\n\nstruct ncsi_cmd_ebf_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\t__be32 mode;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_cmd_egmf_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\t__be32 mode;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_cmd_snfc_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\tunsigned char reserved[3];\n\tunsigned char mode;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_cmd_oem_pkt {\n\tstruct ncsi_cmd_pkt_hdr cmd;\n\t__be32 mfr_id;\n\tunsigned char data[0];\n};\n\nstruct ncsi_cmd_handler {\n\tunsigned char type;\n\tint payload;\n\tint (*handler)(struct sk_buff *, struct ncsi_cmd_arg *);\n};\n\nenum {\n\tNCSI_CAP_GENERIC_HWA = 1,\n\tNCSI_CAP_GENERIC_HDS = 2,\n\tNCSI_CAP_GENERIC_FC = 4,\n\tNCSI_CAP_GENERIC_FC1 = 8,\n\tNCSI_CAP_GENERIC_MC = 16,\n\tNCSI_CAP_GENERIC_HWA_UNKNOWN = 0,\n\tNCSI_CAP_GENERIC_HWA_SUPPORT = 32,\n\tNCSI_CAP_GENERIC_HWA_NOT_SUPPORT = 64,\n\tNCSI_CAP_GENERIC_HWA_RESERVED = 96,\n\tNCSI_CAP_GENERIC_HWA_MASK = 96,\n\tNCSI_CAP_GENERIC_MASK = 127,\n\tNCSI_CAP_BC_ARP = 1,\n\tNCSI_CAP_BC_DHCPC = 2,\n\tNCSI_CAP_BC_DHCPS = 4,\n\tNCSI_CAP_BC_NETBIOS = 8,\n\tNCSI_CAP_BC_MASK = 15,\n\tNCSI_CAP_MC_IPV6_NEIGHBOR = 1,\n\tNCSI_CAP_MC_IPV6_ROUTER = 2,\n\tNCSI_CAP_MC_DHCPV6_RELAY = 4,\n\tNCSI_CAP_MC_DHCPV6_WELL_KNOWN = 8,\n\tNCSI_CAP_MC_IPV6_MLD = 16,\n\tNCSI_CAP_MC_IPV6_NEIGHBOR_S = 32,\n\tNCSI_CAP_MC_MASK = 63,\n\tNCSI_CAP_AEN_LSC = 1,\n\tNCSI_CAP_AEN_CR = 2,\n\tNCSI_CAP_AEN_HDS = 4,\n\tNCSI_CAP_AEN_MASK = 7,\n\tNCSI_CAP_VLAN_ONLY = 1,\n\tNCSI_CAP_VLAN_NO = 2,\n\tNCSI_CAP_VLAN_ANY = 4,\n\tNCSI_CAP_VLAN_MASK = 7,\n};\n\nstruct ncsi_rsp_pkt_hdr {\n\tstruct ncsi_pkt_hdr common;\n\t__be16 code;\n\t__be16 reason;\n};\n\nstruct ncsi_rsp_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 checksum;\n\tunsigned char pad[22];\n};\n\nstruct ncsi_rsp_oem_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 mfr_id;\n\tunsigned char data[0];\n};\n\nstruct ncsi_rsp_oem_mlx_pkt {\n\tunsigned char cmd_rev;\n\tunsigned char cmd;\n\tunsigned char param;\n\tunsigned char optional;\n\tunsigned char data[0];\n};\n\nstruct ncsi_rsp_oem_bcm_pkt {\n\tunsigned char ver;\n\tunsigned char type;\n\t__be16 len;\n\tunsigned char data[0];\n};\n\nstruct ncsi_rsp_gls_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 status;\n\t__be32 other;\n\t__be32 oem_status;\n\t__be32 checksum;\n\tunsigned char pad[10];\n};\n\nstruct ncsi_rsp_gvi_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 ncsi_version;\n\tunsigned char reserved[3];\n\tunsigned char alpha2;\n\tunsigned char fw_name[12];\n\t__be32 fw_version;\n\t__be16 pci_ids[4];\n\t__be32 mf_id;\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_gc_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 cap;\n\t__be32 bc_cap;\n\t__be32 mc_cap;\n\t__be32 buf_cap;\n\t__be32 aen_cap;\n\tunsigned char vlan_cnt;\n\tunsigned char mixed_cnt;\n\tunsigned char mc_cnt;\n\tunsigned char uc_cnt;\n\tunsigned char reserved[2];\n\tunsigned char vlan_mode;\n\tunsigned char channel_cnt;\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_gp_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\tunsigned char mac_cnt;\n\tunsigned char reserved[2];\n\tunsigned char mac_enable;\n\tunsigned char vlan_cnt;\n\tunsigned char reserved1;\n\t__be16 vlan_enable;\n\t__be32 link_mode;\n\t__be32 bc_mode;\n\t__be32 valid_modes;\n\tunsigned char vlan_mode;\n\tunsigned char fc_mode;\n\tunsigned char reserved2[2];\n\t__be32 aen_mode;\n\tunsigned char mac[6];\n\t__be16 vlan;\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_gcps_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 cnt_hi;\n\t__be32 cnt_lo;\n\t__be32 rx_bytes;\n\t__be32 tx_bytes;\n\t__be32 rx_uc_pkts;\n\t__be32 rx_mc_pkts;\n\t__be32 rx_bc_pkts;\n\t__be32 tx_uc_pkts;\n\t__be32 tx_mc_pkts;\n\t__be32 tx_bc_pkts;\n\t__be32 fcs_err;\n\t__be32 align_err;\n\t__be32 false_carrier;\n\t__be32 runt_pkts;\n\t__be32 jabber_pkts;\n\t__be32 rx_pause_xon;\n\t__be32 rx_pause_xoff;\n\t__be32 tx_pause_xon;\n\t__be32 tx_pause_xoff;\n\t__be32 tx_s_collision;\n\t__be32 tx_m_collision;\n\t__be32 l_collision;\n\t__be32 e_collision;\n\t__be32 rx_ctl_frames;\n\t__be32 rx_64_frames;\n\t__be32 rx_127_frames;\n\t__be32 rx_255_frames;\n\t__be32 rx_511_frames;\n\t__be32 rx_1023_frames;\n\t__be32 rx_1522_frames;\n\t__be32 rx_9022_frames;\n\t__be32 tx_64_frames;\n\t__be32 tx_127_frames;\n\t__be32 tx_255_frames;\n\t__be32 tx_511_frames;\n\t__be32 tx_1023_frames;\n\t__be32 tx_1522_frames;\n\t__be32 tx_9022_frames;\n\t__be32 rx_valid_bytes;\n\t__be32 rx_runt_pkts;\n\t__be32 rx_jabber_pkts;\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_gns_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 rx_cmds;\n\t__be32 dropped_cmds;\n\t__be32 cmd_type_errs;\n\t__be32 cmd_csum_errs;\n\t__be32 rx_pkts;\n\t__be32 tx_pkts;\n\t__be32 tx_aen_pkts;\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_gnpts_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 tx_pkts;\n\t__be32 tx_dropped;\n\t__be32 tx_channel_err;\n\t__be32 tx_us_err;\n\t__be32 rx_pkts;\n\t__be32 rx_dropped;\n\t__be32 rx_channel_err;\n\t__be32 rx_us_err;\n\t__be32 rx_os_err;\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_gps_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\t__be32 status;\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_gpuuid_pkt {\n\tstruct ncsi_rsp_pkt_hdr rsp;\n\tunsigned char uuid[16];\n\t__be32 checksum;\n};\n\nstruct ncsi_rsp_oem_handler {\n\tunsigned int mfr_id;\n\tint (*handler)(struct ncsi_request *);\n};\n\nstruct ncsi_rsp_handler {\n\tunsigned char type;\n\tint payload;\n\tint (*handler)(struct ncsi_request *);\n};\n\nstruct ncsi_aen_pkt_hdr {\n\tstruct ncsi_pkt_hdr common;\n\tunsigned char reserved2[3];\n\tunsigned char type;\n};\n\nstruct ncsi_aen_lsc_pkt {\n\tstruct ncsi_aen_pkt_hdr aen;\n\t__be32 status;\n\t__be32 oem_status;\n\t__be32 checksum;\n\tunsigned char pad[14];\n};\n\nstruct ncsi_aen_hncdsc_pkt {\n\tstruct ncsi_aen_pkt_hdr aen;\n\t__be32 status;\n\t__be32 checksum;\n\tunsigned char pad[18];\n};\n\nstruct ncsi_aen_handler {\n\tunsigned char type;\n\tint payload;\n\tint (*handler)(struct ncsi_dev_priv *, struct ncsi_aen_pkt_hdr *);\n};\n\nenum {\n\tncsi_dev_state_registered = 0,\n\tncsi_dev_state_functional = 256,\n\tncsi_dev_state_probe = 512,\n\tncsi_dev_state_config = 768,\n\tncsi_dev_state_suspend = 1024,\n};\n\nenum {\n\tMLX_MC_RBT_SUPPORT = 1,\n\tMLX_MC_RBT_AVL = 8,\n};\n\nenum {\n\tncsi_dev_state_major = 65280,\n\tncsi_dev_state_minor = 255,\n\tncsi_dev_state_probe_deselect = 513,\n\tncsi_dev_state_probe_package = 514,\n\tncsi_dev_state_probe_channel = 515,\n\tncsi_dev_state_probe_mlx_gma = 516,\n\tncsi_dev_state_probe_mlx_smaf = 517,\n\tncsi_dev_state_probe_cis = 518,\n\tncsi_dev_state_probe_keep_phy = 519,\n\tncsi_dev_state_probe_gvi = 520,\n\tncsi_dev_state_probe_gc = 521,\n\tncsi_dev_state_probe_gls = 522,\n\tncsi_dev_state_probe_dp = 523,\n\tncsi_dev_state_config_sp = 769,\n\tncsi_dev_state_config_cis = 770,\n\tncsi_dev_state_config_oem_gma = 771,\n\tncsi_dev_state_config_clear_vids = 772,\n\tncsi_dev_state_config_svf = 773,\n\tncsi_dev_state_config_ev = 774,\n\tncsi_dev_state_config_sma = 775,\n\tncsi_dev_state_config_ebf = 776,\n\tncsi_dev_state_config_dgmf = 777,\n\tncsi_dev_state_config_ecnt = 778,\n\tncsi_dev_state_config_ec = 779,\n\tncsi_dev_state_config_ae = 780,\n\tncsi_dev_state_config_gls = 781,\n\tncsi_dev_state_config_done = 782,\n\tncsi_dev_state_suspend_select = 1025,\n\tncsi_dev_state_suspend_gls = 1026,\n\tncsi_dev_state_suspend_dcnt = 1027,\n\tncsi_dev_state_suspend_dc = 1028,\n\tncsi_dev_state_suspend_deselect = 1029,\n\tncsi_dev_state_suspend_done = 1030,\n};\n\nstruct vlan_vid {\n\tstruct list_head list;\n\t__be16 proto;\n\tu16 vid;\n};\n\nstruct ncsi_oem_gma_handler {\n\tunsigned int mfr_id;\n\tint (*handler)(struct ncsi_cmd_arg *);\n};\n\nenum ncsi_nl_commands {\n\tNCSI_CMD_UNSPEC = 0,\n\tNCSI_CMD_PKG_INFO = 1,\n\tNCSI_CMD_SET_INTERFACE = 2,\n\tNCSI_CMD_CLEAR_INTERFACE = 3,\n\tNCSI_CMD_SEND_CMD = 4,\n\tNCSI_CMD_SET_PACKAGE_MASK = 5,\n\tNCSI_CMD_SET_CHANNEL_MASK = 6,\n\t__NCSI_CMD_AFTER_LAST = 7,\n\tNCSI_CMD_MAX = 6,\n};\n\nenum ncsi_nl_attrs {\n\tNCSI_ATTR_UNSPEC = 0,\n\tNCSI_ATTR_IFINDEX = 1,\n\tNCSI_ATTR_PACKAGE_LIST = 2,\n\tNCSI_ATTR_PACKAGE_ID = 3,\n\tNCSI_ATTR_CHANNEL_ID = 4,\n\tNCSI_ATTR_DATA = 5,\n\tNCSI_ATTR_MULTI_FLAG = 6,\n\tNCSI_ATTR_PACKAGE_MASK = 7,\n\tNCSI_ATTR_CHANNEL_MASK = 8,\n\t__NCSI_ATTR_AFTER_LAST = 9,\n\tNCSI_ATTR_MAX = 8,\n};\n\nenum ncsi_nl_pkg_attrs {\n\tNCSI_PKG_ATTR_UNSPEC = 0,\n\tNCSI_PKG_ATTR = 1,\n\tNCSI_PKG_ATTR_ID = 2,\n\tNCSI_PKG_ATTR_FORCED = 3,\n\tNCSI_PKG_ATTR_CHANNEL_LIST = 4,\n\t__NCSI_PKG_ATTR_AFTER_LAST = 5,\n\tNCSI_PKG_ATTR_MAX = 4,\n};\n\nenum ncsi_nl_channel_attrs {\n\tNCSI_CHANNEL_ATTR_UNSPEC = 0,\n\tNCSI_CHANNEL_ATTR = 1,\n\tNCSI_CHANNEL_ATTR_ID = 2,\n\tNCSI_CHANNEL_ATTR_VERSION_MAJOR = 3,\n\tNCSI_CHANNEL_ATTR_VERSION_MINOR = 4,\n\tNCSI_CHANNEL_ATTR_VERSION_STR = 5,\n\tNCSI_CHANNEL_ATTR_LINK_STATE = 6,\n\tNCSI_CHANNEL_ATTR_ACTIVE = 7,\n\tNCSI_CHANNEL_ATTR_FORCED = 8,\n\tNCSI_CHANNEL_ATTR_VLAN_LIST = 9,\n\tNCSI_CHANNEL_ATTR_VLAN_ID = 10,\n\t__NCSI_CHANNEL_ATTR_AFTER_LAST = 11,\n\tNCSI_CHANNEL_ATTR_MAX = 10,\n};\n\nstruct sockaddr_xdp {\n\t__u16 sxdp_family;\n\t__u16 sxdp_flags;\n\t__u32 sxdp_ifindex;\n\t__u32 sxdp_queue_id;\n\t__u32 sxdp_shared_umem_fd;\n};\n\nstruct xdp_ring_offset {\n\t__u64 producer;\n\t__u64 consumer;\n\t__u64 desc;\n\t__u64 flags;\n};\n\nstruct xdp_mmap_offsets {\n\tstruct xdp_ring_offset rx;\n\tstruct xdp_ring_offset tx;\n\tstruct xdp_ring_offset fr;\n\tstruct xdp_ring_offset cr;\n};\n\nstruct xdp_umem_reg {\n\t__u64 addr;\n\t__u64 len;\n\t__u32 chunk_size;\n\t__u32 headroom;\n\t__u32 flags;\n};\n\nstruct xdp_statistics {\n\t__u64 rx_dropped;\n\t__u64 rx_invalid_descs;\n\t__u64 tx_invalid_descs;\n\t__u64 rx_ring_full;\n\t__u64 rx_fill_ring_empty_descs;\n\t__u64 tx_ring_empty_descs;\n};\n\nstruct xdp_options {\n\t__u32 flags;\n};\n\nstruct xdp_desc {\n\t__u64 addr;\n\t__u32 len;\n\t__u32 options;\n};\n\nstruct xsk_map {\n\tstruct bpf_map map;\n\tspinlock_t lock;\n\tstruct xdp_sock *xsk_map[0];\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct xdp_ring;\n\nstruct xsk_queue {\n\tu32 ring_mask;\n\tu32 nentries;\n\tu32 cached_prod;\n\tu32 cached_cons;\n\tstruct xdp_ring *ring;\n\tu64 invalid_descs;\n\tu64 queue_empty_descs;\n};\n\nstruct xdp_ring_offset_v1 {\n\t__u64 producer;\n\t__u64 consumer;\n\t__u64 desc;\n};\n\nstruct xdp_mmap_offsets_v1 {\n\tstruct xdp_ring_offset_v1 rx;\n\tstruct xdp_ring_offset_v1 tx;\n\tstruct xdp_ring_offset_v1 fr;\n\tstruct xdp_ring_offset_v1 cr;\n};\n\nstruct xsk_map_node {\n\tstruct list_head node;\n\tstruct xsk_map *map;\n\tstruct xdp_sock **map_entry;\n};\n\nstruct xdp_ring {\n\tu32 producer;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu32 pad1;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu32 consumer;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu32 pad2;\n\tu32 flags;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tu32 pad3;\n\tlong: 32;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n\tlong: 64;\n};\n\nstruct xdp_rxtx_ring {\n\tstruct xdp_ring ptrs;\n\tstruct xdp_desc desc[0];\n};\n\nstruct xdp_umem_ring {\n\tstruct xdp_ring ptrs;\n\tu64 desc[0];\n};\n\nstruct xsk_dma_map {\n\tdma_addr_t *dma_pages;\n\tstruct device *dev;\n\tstruct net_device *netdev;\n\trefcount_t users;\n\tstruct list_head list;\n\tu32 dma_pages_cnt;\n\tbool dma_need_sync;\n};\n\nstruct mptcp_mib {\n\tlong unsigned int mibs[37];\n};\n\nenum mptcp_event_type {\n\tMPTCP_EVENT_UNSPEC = 0,\n\tMPTCP_EVENT_CREATED = 1,\n\tMPTCP_EVENT_ESTABLISHED = 2,\n\tMPTCP_EVENT_CLOSED = 3,\n\tMPTCP_EVENT_ANNOUNCED = 6,\n\tMPTCP_EVENT_REMOVED = 7,\n\tMPTCP_EVENT_SUB_ESTABLISHED = 10,\n\tMPTCP_EVENT_SUB_CLOSED = 11,\n\tMPTCP_EVENT_SUB_PRIORITY = 13,\n};\n\nstruct mptcp_options_received {\n\tu64 sndr_key;\n\tu64 rcvr_key;\n\tu64 data_ack;\n\tu64 data_seq;\n\tu32 subflow_seq;\n\tu16 data_len;\n\t__sum16 csum;\n\tu16 mp_capable: 1;\n\tu16 mp_join: 1;\n\tu16 fastclose: 1;\n\tu16 reset: 1;\n\tu16 dss: 1;\n\tu16 add_addr: 1;\n\tu16 rm_addr: 1;\n\tu16 mp_prio: 1;\n\tu16 echo: 1;\n\tu16 csum_reqd: 1;\n\tu16 backup: 1;\n\tu16 deny_join_id0: 1;\n\tu32 token;\n\tu32 nonce;\n\tu64 thmac;\n\tu8 hmac[20];\n\tu8 join_id;\n\tu8 use_map: 1;\n\tu8 dsn64: 1;\n\tu8 data_fin: 1;\n\tu8 use_ack: 1;\n\tu8 ack64: 1;\n\tu8 mpc_map: 1;\n\tu8 __unused: 2;\n\tstruct mptcp_addr_info addr;\n\tstruct mptcp_rm_list rm_list;\n\tu64 ahmac;\n\tu8 reset_reason: 4;\n\tu8 reset_transient: 1;\n};\n\nstruct mptcp_pm_data {\n\tstruct mptcp_addr_info local;\n\tstruct mptcp_addr_info remote;\n\tstruct list_head anno_list;\n\tspinlock_t lock;\n\tu8 addr_signal;\n\tbool server_side;\n\tbool work_pending;\n\tbool accept_addr;\n\tbool accept_subflow;\n\tbool remote_deny_join_id0;\n\tu8 add_addr_signaled;\n\tu8 add_addr_accepted;\n\tu8 local_addr_used;\n\tu8 subflows;\n\tu8 status;\n\tstruct mptcp_rm_list rm_list_tx;\n\tstruct mptcp_rm_list rm_list_rx;\n};\n\nstruct mptcp_data_frag {\n\tstruct list_head list;\n\tu64 data_seq;\n\tu16 data_len;\n\tu16 offset;\n\tu16 overhead;\n\tu16 already_sent;\n\tstruct page *page;\n};\n\nstruct mptcp_sock {\n\tstruct inet_connection_sock sk;\n\tu64 local_key;\n\tu64 remote_key;\n\tu64 write_seq;\n\tu64 snd_nxt;\n\tu64 ack_seq;\n\tu64 rcv_wnd_sent;\n\tu64 rcv_data_fin_seq;\n\tint wmem_reserved;\n\tstruct sock *last_snd;\n\tint snd_burst;\n\tint old_wspace;\n\tu64 snd_una;\n\tu64 wnd_end;\n\tlong unsigned int timer_ival;\n\tu32 token;\n\tint rmem_released;\n\tlong unsigned int flags;\n\tbool can_ack;\n\tbool fully_established;\n\tbool rcv_data_fin;\n\tbool snd_data_fin_enable;\n\tbool rcv_fastclose;\n\tbool use_64bit_ack;\n\tbool csum_enabled;\n\tspinlock_t join_list_lock;\n\tstruct work_struct work;\n\tstruct sk_buff *ooo_last_skb;\n\tstruct rb_root out_of_order_queue;\n\tstruct sk_buff_head receive_queue;\n\tint tx_pending_data;\n\tstruct list_head conn_list;\n\tstruct list_head rtx_queue;\n\tstruct mptcp_data_frag *first_pending;\n\tstruct list_head join_list;\n\tstruct socket *subflow;\n\tstruct sock *first;\n\tstruct mptcp_pm_data pm;\n\tstruct {\n\t\tu32 space;\n\t\tu32 copied;\n\t\tu64 time;\n\t\tu64 rtt_us;\n\t} rcvq_space;\n\tu32 setsockopt_seq;\n\tchar ca_name[16];\n};\n\nstruct mptcp_subflow_request_sock {\n\tstruct tcp_request_sock sk;\n\tu16 mp_capable: 1;\n\tu16 mp_join: 1;\n\tu16 backup: 1;\n\tu16 csum_reqd: 1;\n\tu16 allow_join_id0: 1;\n\tu8 local_id;\n\tu8 remote_id;\n\tu64 local_key;\n\tu64 idsn;\n\tu32 token;\n\tu32 ssn_offset;\n\tu64 thmac;\n\tu32 local_nonce;\n\tu32 remote_nonce;\n\tstruct mptcp_sock *msk;\n\tstruct hlist_nulls_node token_node;\n};\n\nenum mptcp_data_avail {\n\tMPTCP_SUBFLOW_NODATA = 0,\n\tMPTCP_SUBFLOW_DATA_AVAIL = 1,\n};\n\nstruct mptcp_delegated_action {\n\tstruct napi_struct napi;\n\tstruct list_head head;\n};\n\nstruct mptcp_subflow_context {\n\tstruct list_head node;\n\tu64 local_key;\n\tu64 remote_key;\n\tu64 idsn;\n\tu64 map_seq;\n\tu32 snd_isn;\n\tu32 token;\n\tu32 rel_write_seq;\n\tu32 map_subflow_seq;\n\tu32 ssn_offset;\n\tu32 map_data_len;\n\t__wsum map_data_csum;\n\tu32 map_csum_len;\n\tu32 request_mptcp: 1;\n\tu32 request_join: 1;\n\tu32 request_bkup: 1;\n\tu32 mp_capable: 1;\n\tu32 mp_join: 1;\n\tu32 fully_established: 1;\n\tu32 pm_notified: 1;\n\tu32 conn_finished: 1;\n\tu32 map_valid: 1;\n\tu32 map_csum_reqd: 1;\n\tu32 map_data_fin: 1;\n\tu32 mpc_map: 1;\n\tu32 backup: 1;\n\tu32 send_mp_prio: 1;\n\tu32 rx_eof: 1;\n\tu32 can_ack: 1;\n\tu32 disposable: 1;\n\tenum mptcp_data_avail data_avail;\n\tu32 remote_nonce;\n\tu64 thmac;\n\tu32 local_nonce;\n\tu32 remote_token;\n\tu8 hmac[20];\n\tu8 local_id;\n\tu8 remote_id;\n\tu8 reset_seen: 1;\n\tu8 reset_transient: 1;\n\tu8 reset_reason: 4;\n\tlong int delegated_status;\n\tstruct list_head delegated_node;\n\tu32 setsockopt_seq;\n\tstruct sock *tcp_sock;\n\tstruct sock *conn;\n\tconst struct inet_connection_sock_af_ops *icsk_af_ops;\n\tvoid (*tcp_data_ready)(struct sock *);\n\tvoid (*tcp_state_change)(struct sock *);\n\tvoid (*tcp_write_space)(struct sock *);\n\tvoid (*tcp_error_report)(struct sock *);\n\tstruct callback_head rcu;\n};\n\nenum linux_mptcp_mib_field {\n\tMPTCP_MIB_NUM = 0,\n\tMPTCP_MIB_MPCAPABLEPASSIVE = 1,\n\tMPTCP_MIB_MPCAPABLEACTIVE = 2,\n\tMPTCP_MIB_MPCAPABLEACTIVEACK = 3,\n\tMPTCP_MIB_MPCAPABLEPASSIVEACK = 4,\n\tMPTCP_MIB_MPCAPABLEPASSIVEFALLBACK = 5,\n\tMPTCP_MIB_MPCAPABLEACTIVEFALLBACK = 6,\n\tMPTCP_MIB_TOKENFALLBACKINIT = 7,\n\tMPTCP_MIB_RETRANSSEGS = 8,\n\tMPTCP_MIB_JOINNOTOKEN = 9,\n\tMPTCP_MIB_JOINSYNRX = 10,\n\tMPTCP_MIB_JOINSYNACKRX = 11,\n\tMPTCP_MIB_JOINSYNACKMAC = 12,\n\tMPTCP_MIB_JOINACKRX = 13,\n\tMPTCP_MIB_JOINACKMAC = 14,\n\tMPTCP_MIB_DSSNOMATCH = 15,\n\tMPTCP_MIB_INFINITEMAPRX = 16,\n\tMPTCP_MIB_DSSTCPMISMATCH = 17,\n\tMPTCP_MIB_DATACSUMERR = 18,\n\tMPTCP_MIB_OFOQUEUETAIL = 19,\n\tMPTCP_MIB_OFOQUEUE = 20,\n\tMPTCP_MIB_OFOMERGE = 21,\n\tMPTCP_MIB_NODSSWINDOW = 22,\n\tMPTCP_MIB_DUPDATA = 23,\n\tMPTCP_MIB_ADDADDR = 24,\n\tMPTCP_MIB_ECHOADD = 25,\n\tMPTCP_MIB_PORTADD = 26,\n\tMPTCP_MIB_JOINPORTSYNRX = 27,\n\tMPTCP_MIB_JOINPORTSYNACKRX = 28,\n\tMPTCP_MIB_JOINPORTACKRX = 29,\n\tMPTCP_MIB_MISMATCHPORTSYNRX = 30,\n\tMPTCP_MIB_MISMATCHPORTACKRX = 31,\n\tMPTCP_MIB_RMADDR = 32,\n\tMPTCP_MIB_RMSUBFLOW = 33,\n\tMPTCP_MIB_MPPRIOTX = 34,\n\tMPTCP_MIB_MPPRIORX = 35,\n\tMPTCP_MIB_RCVPRUNED = 36,\n\t__MPTCP_MIB_MAX = 37,\n};\n\nstruct trace_event_raw_mptcp_subflow_get_send {\n\tstruct trace_entry ent;\n\tbool active;\n\tbool free;\n\tu32 snd_wnd;\n\tu32 pace;\n\tu8 backup;\n\tu64 ratio;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_mptcp_dump_mpext {\n\tstruct trace_entry ent;\n\tu64 data_ack;\n\tu64 data_seq;\n\tu32 subflow_seq;\n\tu16 data_len;\n\tu16 csum;\n\tu8 use_map;\n\tu8 dsn64;\n\tu8 data_fin;\n\tu8 use_ack;\n\tu8 ack64;\n\tu8 mpc_map;\n\tu8 frozen;\n\tu8 reset_transient;\n\tu8 reset_reason;\n\tu8 csum_reqd;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_ack_update_msk {\n\tstruct trace_entry ent;\n\tu64 data_ack;\n\tu64 old_snd_una;\n\tu64 new_snd_una;\n\tu64 new_wnd_end;\n\tu64 msk_wnd_end;\n\tchar __data[0];\n};\n\nstruct trace_event_raw_subflow_check_data_avail {\n\tstruct trace_entry ent;\n\tu8 status;\n\tconst void *skb;\n\tchar __data[0];\n};\n\nstruct trace_event_data_offsets_mptcp_subflow_get_send {};\n\nstruct trace_event_data_offsets_mptcp_dump_mpext {};\n\nstruct trace_event_data_offsets_ack_update_msk {};\n\nstruct trace_event_data_offsets_subflow_check_data_avail {};\n\ntypedef void (*btf_trace_mptcp_subflow_get_send)(void *, struct mptcp_subflow_context *);\n\ntypedef void (*btf_trace_get_mapping_status)(void *, struct mptcp_ext *);\n\ntypedef void (*btf_trace_ack_update_msk)(void *, u64, u64, u64, u64, u64);\n\ntypedef void (*btf_trace_subflow_check_data_avail)(void *, __u8, struct sk_buff *);\n\nstruct mptcp_skb_cb {\n\tu64 map_seq;\n\tu64 end_seq;\n\tu32 offset;\n\tu8 has_rxtstamp: 1;\n};\n\nenum {\n\tMPTCP_CMSG_TS = 1,\n};\n\nstruct mptcp_sendmsg_info {\n\tint mss_now;\n\tint size_goal;\n\tu16 limit;\n\tu16 sent;\n\tunsigned int flags;\n};\n\nstruct subflow_send_info {\n\tstruct sock *ssk;\n\tu64 ratio;\n};\n\nstruct csum_pseudo_header {\n\t__be64 data_seq;\n\t__be32 subflow_seq;\n\t__be16 data_len;\n\t__sum16 csum;\n};\n\nenum mapping_status {\n\tMAPPING_OK = 0,\n\tMAPPING_INVALID = 1,\n\tMAPPING_EMPTY = 2,\n\tMAPPING_DATA_FIN = 3,\n\tMAPPING_DUMMY = 4,\n};\n\nenum mptcp_addr_signal_status {\n\tMPTCP_ADD_ADDR_SIGNAL = 0,\n\tMPTCP_ADD_ADDR_ECHO = 1,\n\tMPTCP_ADD_ADDR_IPV6 = 2,\n\tMPTCP_ADD_ADDR_PORT = 3,\n\tMPTCP_RM_ADDR_SIGNAL = 4,\n};\n\nstruct mptcp_pm_add_entry;\n\nstruct token_bucket {\n\tspinlock_t lock;\n\tint chain_len;\n\tstruct hlist_nulls_head req_chain;\n\tstruct hlist_nulls_head msk_chain;\n};\n\nstruct mptcp_pernet {\n\tstruct ctl_table_header *ctl_table_hdr;\n\tu8 mptcp_enabled;\n\tunsigned int add_addr_timeout;\n\tu8 checksum_enabled;\n\tu8 allow_join_initial_addr_port;\n};\n\nenum mptcp_pm_status {\n\tMPTCP_PM_ADD_ADDR_RECEIVED = 0,\n\tMPTCP_PM_ADD_ADDR_SEND_ACK = 1,\n\tMPTCP_PM_RM_ADDR_RECEIVED = 2,\n\tMPTCP_PM_ESTABLISHED = 3,\n\tMPTCP_PM_ALREADY_ESTABLISHED = 4,\n\tMPTCP_PM_SUBFLOW_ESTABLISHED = 5,\n};\n\nenum {\n\tINET_ULP_INFO_UNSPEC = 0,\n\tINET_ULP_INFO_NAME = 1,\n\tINET_ULP_INFO_TLS = 2,\n\tINET_ULP_INFO_MPTCP = 3,\n\t__INET_ULP_INFO_MAX = 4,\n};\n\nenum {\n\tMPTCP_SUBFLOW_ATTR_UNSPEC = 0,\n\tMPTCP_SUBFLOW_ATTR_TOKEN_REM = 1,\n\tMPTCP_SUBFLOW_ATTR_TOKEN_LOC = 2,\n\tMPTCP_SUBFLOW_ATTR_RELWRITE_SEQ = 3,\n\tMPTCP_SUBFLOW_ATTR_MAP_SEQ = 4,\n\tMPTCP_SUBFLOW_ATTR_MAP_SFSEQ = 5,\n\tMPTCP_SUBFLOW_ATTR_SSN_OFFSET = 6,\n\tMPTCP_SUBFLOW_ATTR_MAP_DATALEN = 7,\n\tMPTCP_SUBFLOW_ATTR_FLAGS = 8,\n\tMPTCP_SUBFLOW_ATTR_ID_REM = 9,\n\tMPTCP_SUBFLOW_ATTR_ID_LOC = 10,\n\tMPTCP_SUBFLOW_ATTR_PAD = 11,\n\t__MPTCP_SUBFLOW_ATTR_MAX = 12,\n};\n\nenum {\n\tMPTCP_PM_ATTR_UNSPEC = 0,\n\tMPTCP_PM_ATTR_ADDR = 1,\n\tMPTCP_PM_ATTR_RCV_ADD_ADDRS = 2,\n\tMPTCP_PM_ATTR_SUBFLOWS = 3,\n\t__MPTCP_PM_ATTR_MAX = 4,\n};\n\nenum {\n\tMPTCP_PM_ADDR_ATTR_UNSPEC = 0,\n\tMPTCP_PM_ADDR_ATTR_FAMILY = 1,\n\tMPTCP_PM_ADDR_ATTR_ID = 2,\n\tMPTCP_PM_ADDR_ATTR_ADDR4 = 3,\n\tMPTCP_PM_ADDR_ATTR_ADDR6 = 4,\n\tMPTCP_PM_ADDR_ATTR_PORT = 5,\n\tMPTCP_PM_ADDR_ATTR_FLAGS = 6,\n\tMPTCP_PM_ADDR_ATTR_IF_IDX = 7,\n\t__MPTCP_PM_ADDR_ATTR_MAX = 8,\n};\n\nenum {\n\tMPTCP_PM_CMD_UNSPEC = 0,\n\tMPTCP_PM_CMD_ADD_ADDR = 1,\n\tMPTCP_PM_CMD_DEL_ADDR = 2,\n\tMPTCP_PM_CMD_GET_ADDR = 3,\n\tMPTCP_PM_CMD_FLUSH_ADDRS = 4,\n\tMPTCP_PM_CMD_SET_LIMITS = 5,\n\tMPTCP_PM_CMD_GET_LIMITS = 6,\n\tMPTCP_PM_CMD_SET_FLAGS = 7,\n\t__MPTCP_PM_CMD_AFTER_LAST = 8,\n};\n\nenum mptcp_event_attr {\n\tMPTCP_ATTR_UNSPEC = 0,\n\tMPTCP_ATTR_TOKEN = 1,\n\tMPTCP_ATTR_FAMILY = 2,\n\tMPTCP_ATTR_LOC_ID = 3,\n\tMPTCP_ATTR_REM_ID = 4,\n\tMPTCP_ATTR_SADDR4 = 5,\n\tMPTCP_ATTR_SADDR6 = 6,\n\tMPTCP_ATTR_DADDR4 = 7,\n\tMPTCP_ATTR_DADDR6 = 8,\n\tMPTCP_ATTR_SPORT = 9,\n\tMPTCP_ATTR_DPORT = 10,\n\tMPTCP_ATTR_BACKUP = 11,\n\tMPTCP_ATTR_ERROR = 12,\n\tMPTCP_ATTR_FLAGS = 13,\n\tMPTCP_ATTR_TIMEOUT = 14,\n\tMPTCP_ATTR_IF_IDX = 15,\n\tMPTCP_ATTR_RESET_REASON = 16,\n\tMPTCP_ATTR_RESET_FLAGS = 17,\n\t__MPTCP_ATTR_AFTER_LAST = 18,\n};\n\nstruct mptcp_pm_addr_entry {\n\tstruct list_head list;\n\tstruct mptcp_addr_info addr;\n\tu8 flags;\n\tint ifindex;\n\tstruct socket *lsk;\n};\n\nstruct mptcp_pm_add_entry___2 {\n\tstruct list_head list;\n\tstruct mptcp_addr_info addr;\n\tstruct timer_list add_timer;\n\tstruct mptcp_sock *sock;\n\tu8 retrans_times;\n};\n\nstruct pm_nl_pernet {\n\tspinlock_t lock;\n\tstruct list_head local_addr_list;\n\tunsigned int addrs;\n\tunsigned int add_addr_signal_max;\n\tunsigned int add_addr_accept_max;\n\tunsigned int local_addr_max;\n\tunsigned int subflows_max;\n\tunsigned int next_id;\n\tlong unsigned int id_bitmap[4];\n};\n\nstruct join_entry {\n\tu32 token;\n\tu32 remote_nonce;\n\tu32 local_nonce;\n\tu8 join_id;\n\tu8 local_id;\n\tu8 backup;\n\tu8 valid;\n};\n\nstruct pcibios_fwaddrmap {\n\tstruct list_head list;\n\tstruct pci_dev *dev;\n\tresource_size_t fw_addr[17];\n};\n\nstruct pci_check_idx_range {\n\tint start;\n\tint end;\n};\n\nstruct pci_raw_ops {\n\tint (*read)(unsigned int, unsigned int, unsigned int, int, int, u32 *);\n\tint (*write)(unsigned int, unsigned int, unsigned int, int, int, u32);\n};\n\nstruct acpi_table_mcfg {\n\tstruct acpi_table_header header;\n\tu8 reserved[8];\n};\n\nstruct acpi_mcfg_allocation {\n\tu64 address;\n\tu16 pci_segment;\n\tu8 start_bus_number;\n\tu8 end_bus_number;\n\tu32 reserved;\n};\n\nstruct pci_mmcfg_hostbridge_probe {\n\tu32 bus;\n\tu32 devfn;\n\tu32 vendor;\n\tu32 device;\n\tconst char * (*probe)();\n};\n\ntypedef bool (*check_reserved_t)(u64, u64, enum e820_type);\n\nstruct physdev_restore_msi {\n\tuint8_t bus;\n\tuint8_t devfn;\n};\n\nstruct physdev_setup_gsi {\n\tint gsi;\n\tuint8_t triggering;\n\tuint8_t polarity;\n};\n\nstruct xen_pci_frontend_ops {\n\tint (*enable_msi)(struct pci_dev *, int *);\n\tvoid (*disable_msi)(struct pci_dev *);\n\tint (*enable_msix)(struct pci_dev *, int *, int);\n\tvoid (*disable_msix)(struct pci_dev *);\n};\n\nstruct xen_msi_ops {\n\tint (*setup_msi_irqs)(struct pci_dev *, int, int);\n\tvoid (*teardown_msi_irqs)(struct pci_dev *);\n};\n\nstruct xen_device_domain_owner {\n\tdomid_t domain;\n\tstruct pci_dev *dev;\n\tstruct list_head list;\n};\n\nstruct pci_root_info {\n\tstruct acpi_pci_root_info common;\n\tstruct pci_sysdata sd;\n\tbool mcfg_added;\n\tu8 start_bus;\n\tu8 end_bus;\n};\n\nstruct irq_info___3 {\n\tu8 bus;\n\tu8 devfn;\n\tstruct {\n\t\tu8 link;\n\t\tu16 bitmap;\n\t} __attribute__((packed)) irq[4];\n\tu8 slot;\n\tu8 rfu;\n};\n\nstruct irq_routing_table {\n\tu32 signature;\n\tu16 version;\n\tu16 size;\n\tu8 rtr_bus;\n\tu8 rtr_devfn;\n\tu16 exclusive_irqs;\n\tu16 rtr_vendor;\n\tu16 rtr_device;\n\tu32 miniport_data;\n\tu8 rfu[11];\n\tu8 checksum;\n\tstruct irq_info___3 slots[0];\n};\n\nstruct irq_router {\n\tchar *name;\n\tu16 vendor;\n\tu16 device;\n\tint (*get)(struct pci_dev *, struct pci_dev *, int);\n\tint (*set)(struct pci_dev *, struct pci_dev *, int, int);\n};\n\nstruct irq_router_handler {\n\tu16 vendor;\n\tint (*probe)(struct irq_router *, struct pci_dev *, u16);\n};\n\nstruct pci_setup_rom {\n\tstruct setup_data data;\n\tuint16_t vendor;\n\tuint16_t devid;\n\tuint64_t pcilen;\n\tlong unsigned int segment;\n\tlong unsigned int bus;\n\tlong unsigned int device;\n\tlong unsigned int function;\n\tuint8_t romdata[0];\n};\n\nenum pci_bf_sort_state {\n\tpci_bf_sort_default = 0,\n\tpci_force_nobf = 1,\n\tpci_force_bf = 2,\n\tpci_dmi_bf = 3,\n};\n\nstruct pci_root_res {\n\tstruct list_head list;\n\tstruct resource res;\n};\n\nstruct pci_root_info___2 {\n\tstruct list_head list;\n\tchar name[12];\n\tstruct list_head resources;\n\tstruct resource busn;\n\tint node;\n\tint link;\n};\n\nstruct amd_hostbridge {\n\tu32 bus;\n\tu32 slot;\n\tu32 device;\n};\n\nstruct saved_msr {\n\tbool valid;\n\tstruct msr_info info;\n};\n\nstruct saved_msrs {\n\tunsigned int num;\n\tstruct saved_msr *array;\n};\n\nstruct saved_context {\n\tstruct pt_regs regs;\n\tu16 ds;\n\tu16 es;\n\tu16 fs;\n\tu16 gs;\n\tlong unsigned int kernelmode_gs_base;\n\tlong unsigned int usermode_gs_base;\n\tlong unsigned int fs_base;\n\tlong unsigned int cr0;\n\tlong unsigned int cr2;\n\tlong unsigned int cr3;\n\tlong unsigned int cr4;\n\tu64 misc_enable;\n\tbool misc_enable_saved;\n\tstruct saved_msrs saved_msrs;\n\tlong unsigned int efer;\n\tu16 gdt_pad;\n\tstruct desc_ptr gdt_desc;\n\tu16 idt_pad;\n\tstruct desc_ptr idt;\n\tu16 ldt;\n\tu16 tss;\n\tlong unsigned int tr;\n\tlong unsigned int safety;\n\tlong unsigned int return_address;\n} __attribute__((packed));\n\ntypedef int (*pm_cpu_match_t)(const struct x86_cpu_id *);\n\nstruct restore_data_record {\n\tlong unsigned int jump_address;\n\tlong unsigned int jump_address_phys;\n\tlong unsigned int cr3;\n\tlong unsigned int magic;\n\tlong unsigned int e820_checksum;\n};\n\n#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n#pragma clang attribute pop\n#endif\n\n#endif /* __VMLINUX_H__ */"
  },
  {
    "path": "service/firewall/interception/interception_default.go",
    "content": "//go:build !windows && !linux\n\npackage interception\n\nimport (\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n// start starts the interception.\nfunc startInterception(_ chan packet.Packet) error {\n\tlog.Critical(\"interception: this platform has no support for packet interception - a lot of functionality will be broken\")\n\treturn nil\n}\n\n// stop starts the interception.\nfunc stopInterception() error {\n\treturn nil\n}\n\n// ResetVerdictOfAllConnections resets all connections so they are forced to go thought the firewall again.\nfunc ResetVerdictOfAllConnections() error {\n\treturn nil\n}\n\n// UpdateVerdictOfConnection updates the verdict of the given connection in the OS integration.\nfunc UpdateVerdictOfConnection(conn *network.Connection) error {\n\treturn nil\n}\n"
  },
  {
    "path": "service/firewall/interception/interception_linux.go",
    "content": "package interception\n\nimport (\n\t\"time\"\n\n\tbandwidth \"github.com/safing/portmaster/service/firewall/interception/ebpf/bandwidth\"\n\tconn_listener \"github.com/safing/portmaster/service/firewall/interception/ebpf/connection_listener\"\n\t\"github.com/safing/portmaster/service/firewall/interception/nfq\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n// start starts the interception.\nfunc startInterception(packets chan packet.Packet) error {\n\t// Start packet interception via nfqueue.\n\terr := StartNfqueueInterception(packets)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Start ebpf new connection listener.\n\tmodule.mgr.Go(\"ebpf connection listener\", func(wc *mgr.WorkerCtx) error {\n\t\treturn conn_listener.ConnectionListenerWorker(wc.Ctx(), packets)\n\t})\n\n\t// Start ebpf bandwidth stats monitor.\n\tmodule.mgr.Go(\"ebpf bandwidth stats monitor\", func(wc *mgr.WorkerCtx) error {\n\t\treturn bandwidth.BandwidthStatsWorker(wc.Ctx(), 1*time.Second, BandwidthUpdates)\n\t})\n\n\treturn nil\n}\n\n// stop starts the interception.\nfunc stopInterception() error {\n\treturn StopNfqueueInterception()\n}\n\n// ResetVerdictOfAllConnections resets all connections so they are forced to go thought the firewall again.\nfunc ResetVerdictOfAllConnections() error {\n\treturn nfq.DeleteAllMarkedConnection()\n}\n\n// UpdateVerdictOfConnection deletes the verdict of the given connection so it can be initialized again with the next packet.\nfunc UpdateVerdictOfConnection(conn *network.Connection) error {\n\treturn nfq.DeleteMarkedConnection(conn)\n}\n"
  },
  {
    "path": "service/firewall/interception/interception_windows.go",
    "content": "package interception\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\tkext1 \"github.com/safing/portmaster/service/firewall/interception/windowskext\"\n\tkext2 \"github.com/safing/portmaster/service/firewall/interception/windowskext2\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\nvar useOldKext = false\n\n// start starts the interception.\nfunc startInterception(packets chan packet.Packet) error {\n\tkextFile, err := module.instance.BinaryUpdates().GetFile(\"portmaster-kext.sys\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interception: could not get kext sys: %s\", err)\n\t}\n\n\terr = kext2.Init(kextFile.Path())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interception: could not init windows kext: %s\", err)\n\t}\n\n\terr = kext2.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interception: could not start windows kext: %s\", err)\n\t}\n\n\tversion, err := kext2.GetVersion()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interception: failed to read version: %s\", err)\n\t}\n\tlog.Debugf(\"Kext version: %s\", version.String())\n\n\tif version.Major < 2 {\n\t\tuseOldKext = true\n\n\t\t// Transfer ownership.\n\t\tkext1.SetKextHandler(kext2.GetKextHandle())\n\t\tkext1.SetKextService(kext2.GetKextServiceHandle(), kextFile.Path())\n\n\t\t// Start packet handler.\n\t\tmodule.mgr.Go(\"kext packet handler\", func(w *mgr.WorkerCtx) error {\n\t\t\tkext1.Handler(w.Ctx(), packets)\n\t\t\treturn nil\n\t\t})\n\n\t\t// Start bandwidth stats monitor.\n\t\tmodule.mgr.Go(\"kext bandwidth stats monitor\", func(w *mgr.WorkerCtx) error {\n\t\t\treturn kext1.BandwidthStatsWorker(w.Ctx(), 1*time.Second, BandwidthUpdates)\n\t\t})\n\t} else {\n\n\t\t// Start packet handler.\n\t\tmodule.mgr.Go(\"kext packet handler\", func(w *mgr.WorkerCtx) error {\n\t\t\tkext2.Handler(w.Ctx(), packets, BandwidthUpdates)\n\t\t\treturn nil\n\t\t})\n\n\t\t// Start bandwidth stats monitor.\n\t\tmodule.mgr.Go(\"kext bandwidth request worker\", func(w *mgr.WorkerCtx) error {\n\t\t\ttimer := time.NewTicker(1 * time.Second)\n\t\t\tdefer timer.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-timer.C:\n\t\t\t\t\terr := kext2.SendBandwidthStatsRequest()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\tcase <-w.Done():\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\t// Start kext logging. The worker will periodically send request to the kext to send logs.\n\t\tmodule.mgr.Go(\"kext log request worker\", func(w *mgr.WorkerCtx) error {\n\t\t\ttimer := time.NewTicker(1 * time.Second)\n\t\t\tdefer timer.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-timer.C:\n\t\t\t\t\terr := kext2.SendLogRequest()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\tcase <-w.Done():\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\tmodule.mgr.Go(\"kext clean ended connection worker\", func(w *mgr.WorkerCtx) error {\n\t\t\ttimer := time.NewTicker(30 * time.Second)\n\t\t\tdefer timer.Stop()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-timer.C:\n\t\t\t\t\terr := kext2.SendCleanEndedConnection()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\tcase <-w.Done():\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\treturn nil\n}\n\n// stop starts the interception.\nfunc stopInterception() error {\n\tif useOldKext {\n\t\treturn kext1.Stop()\n\t}\n\treturn kext2.Stop()\n}\n\n// ResetVerdictOfAllConnections resets all connections so they are forced to go thought the firewall again.\nfunc ResetVerdictOfAllConnections() error {\n\tif useOldKext {\n\t\treturn kext1.ClearCache()\n\t}\n\treturn kext2.ClearCache()\n}\n\n// UpdateVerdictOfConnection updates the verdict of the given connection in the kernel extension.\nfunc UpdateVerdictOfConnection(conn *network.Connection) error {\n\tif useOldKext {\n\t\treturn kext1.UpdateVerdict(conn)\n\t}\n\treturn kext2.UpdateVerdict(conn)\n}\n\n// GetKextVersion returns the version of the kernel extension.\nfunc GetKextVersion() (string, error) {\n\tif useOldKext {\n\t\tversion, err := kext1.GetVersion()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn version.String(), nil\n\t} else {\n\t\tversion, err := kext2.GetVersion()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn version.String(), nil\n\t}\n}\n"
  },
  {
    "path": "service/firewall/interception/introspection.go",
    "content": "package interception\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\tpacketMetricsDestination string\n\tmetrics                  = &packetMetrics{}\n)\n\nfunc init() {\n\tflag.StringVar(&packetMetricsDestination, \"write-packet-metrics\", \"\", \"write packet metrics to the specified file\")\n}\n\ntype (\n\tperformanceRecord struct {\n\t\tstart    int64\n\t\tduration time.Duration\n\t\tverdict  string\n\t}\n\n\tpacketMetrics struct {\n\t\tdone    chan struct{}\n\t\tl       sync.Mutex\n\t\trecords []*performanceRecord\n\t}\n)\n\nfunc (pm *packetMetrics) record(tp *tracedPacket, verdict string) {\n\tgo func(start int64, duration time.Duration) {\n\t\tpm.l.Lock()\n\t\tdefer pm.l.Unlock()\n\n\t\tif pm.done == nil {\n\t\t\treturn\n\t\t}\n\n\t\tpm.records = append(pm.records, &performanceRecord{\n\t\t\tstart:    start,\n\t\t\tduration: duration,\n\t\t\tverdict:  verdict,\n\t\t})\n\t}(tp.start.UnixNano(), time.Since(tp.start))\n}\n\nfunc (pm *packetMetrics) stop() {\n\tpm.l.Lock()\n\tdefer pm.l.Unlock()\n\n\tif pm.done == nil {\n\t\treturn\n\t}\n\n\tclose(pm.done)\n\tpm.done = nil\n}\n\nfunc (pm *packetMetrics) writeMetrics() {\n\tif packetMetricsDestination == \"\" {\n\t\treturn\n\t}\n\n\tf, err := os.Create(packetMetricsDestination)\n\tif err != nil {\n\t\tlog.Errorf(\"Failed to create packet metrics file: %s\", err)\n\t\treturn\n\t}\n\tdefer func() {\n\t\t_ = f.Close()\n\t}()\n\n\tpm.l.Lock()\n\tpm.done = make(chan struct{})\n\tdone := pm.done\n\tpm.l.Unlock()\n\n\tfor {\n\t\tselect {\n\t\tcase <-done:\n\t\t\treturn\n\t\tcase <-time.After(time.Second * 5):\n\t\t}\n\t\tpm.l.Lock()\n\t\trecords := pm.records\n\t\tpm.records = nil\n\t\tpm.l.Unlock()\n\n\t\tfor _, r := range records {\n\t\t\tfmt.Fprintf(f, \"%d;%s;%s;%.2f\\n\", r.start, r.verdict, r.duration, float64(r.duration)/float64(time.Microsecond))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/firewall/interception/module.go",
    "content": "package interception\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\n// Interception is the packet interception module.\ntype Interception struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tEventStartStopState *mgr.EventMgr[bool] // true if started, false if stopped\n}\n\n// Manager returns the module manager.\nfunc (i *Interception) Manager() *mgr.Manager {\n\treturn i.mgr\n}\n\n// Start starts the module.\nfunc (i *Interception) Start() error {\n\tdefer func() { i.EventStartStopState.Submit(isStarted.Load()) }()\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (i *Interception) Stop() error {\n\tdefer func() { i.EventStartStopState.Submit(isStarted.Load()) }()\n\treturn stop()\n}\n\n// IsStarted returns whether the interception is currently started.\nfunc (i *Interception) IsStarted() bool {\n\treturn isStarted.Load()\n}\n\nvar (\n\t// Packets is a stream of interception network packets.\n\tPackets = make(chan packet.Packet, 1000)\n\n\t// BandwidthUpdates is a stream of bandwidth usage update for connections.\n\tBandwidthUpdates = make(chan *packet.BandwidthUpdate, 1000)\n\n\tdisableInterception bool\n\tisStarted           atomic.Bool\n)\n\nfunc init() {\n\tflag.BoolVar(&disableInterception, \"disable-interception\", false, \"disable packet interception; this breaks a lot of functionality\")\n}\n\n// Start starts the interception.\nfunc start() error {\n\tif disableInterception {\n\t\tlog.Warning(\"interception: packet interception is disabled via flag - this breaks a lot of functionality\")\n\t\treturn nil\n\t}\n\n\tif !isStarted.CompareAndSwap(false, true) {\n\t\treturn nil // already running\n\t}\n\n\tinputPackets := Packets\n\tif packetMetricsDestination != \"\" {\n\t\tgo metrics.writeMetrics()\n\t\tinputPackets = make(chan packet.Packet)\n\t\tgo func() {\n\t\t\tfor p := range inputPackets {\n\t\t\t\tPackets <- tracePacket(p)\n\t\t\t}\n\t\t}()\n\t}\n\n\terr := startInterception(inputPackets)\n\tif err != nil {\n\t\tlog.Errorf(\"interception: failed to start module: %q\", err)\n\t\tlog.Debug(\"interception: cleaning up after failed start...\")\n\t\tmetrics.stop()\n\t\tif e := stopInterception(); e != nil {\n\t\t\tlog.Debugf(\"interception: error cleaning up after failed start: %q\", e.Error())\n\t\t}\n\t\tisStarted.Store(false)\n\t}\n\treturn err\n}\n\n// Stop starts the interception.\nfunc stop() error {\n\tif disableInterception {\n\t\treturn nil\n\t}\n\n\tif !isStarted.CompareAndSwap(true, false) {\n\t\treturn nil // not running\n\t}\n\n\tmetrics.stop()\n\tif err := stopInterception(); err != nil {\n\t\tlog.Errorf(\"failed to stop interception module: %s\", err)\n\t}\n\treturn nil\n}\n\nvar (\n\tmodule     *Interception\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Interception module.\nfunc New(instance instance) (*Interception, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Interception\")\n\tmodule = &Interception{\n\t\tmgr:                 m,\n\t\tinstance:            instance,\n\t\tEventStartStopState: mgr.NewEventMgr[bool](\"IsStarted\", m),\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tBinaryUpdates() *updates.Updater\n}\n"
  },
  {
    "path": "service/firewall/interception/nfq/conntrack.go",
    "content": "//go:build linux\n\npackage nfq\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\n\tct \"github.com/florianl/go-conntrack\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network\"\n)\n\nvar nfct *ct.Nfct // Conntrack handler. NFCT: Network Filter Connection Tracking.\n\n// InitNFCT initializes the network filter conntrack library.\nfunc InitNFCT() error {\n\tvar err error\n\tnfct, err = ct.Open(&ct.Config{})\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// TeardownNFCT deinitializes the network filter conntrack library.\nfunc TeardownNFCT() {\n\tif nfct != nil {\n\t\t_ = nfct.Close()\n\t}\n}\n\n// DeleteAllMarkedConnection deletes all marked entries from the conntrack table.\nfunc DeleteAllMarkedConnection() error {\n\tif nfct == nil {\n\t\treturn errors.New(\"nfq: nfct not initialized\")\n\t}\n\n\t// Delete all ipv4 marked connections\n\tdeleted := deleteMarkedConnections(nfct, ct.IPv4)\n\n\tif netenv.IPv6Enabled() {\n\t\t// Delete all ipv6 marked connections\n\t\tdeleted += deleteMarkedConnections(nfct, ct.IPv6)\n\t}\n\n\tlog.Infof(\"nfq: deleted %d conntrack entries to reset permanent connection verdicts\", deleted)\n\treturn nil\n}\n\nfunc deleteMarkedConnections(nfct *ct.Nfct, f ct.Family) (deleted int) {\n\t// initialize variables\n\tpermanentFlags := []uint32{MarkAcceptAlways, MarkBlockAlways, MarkDropAlways, MarkRerouteNS, MarkRerouteSPN}\n\tfilter := ct.FilterAttr{}\n\tfilter.MarkMask = []byte{0xFF, 0xFF, 0xFF, 0xFF}\n\tfilter.Mark = []byte{0x00, 0x00, 0x00, 0x00} // 4 zeros starting value\n\n\tnumberOfErrors := 0\n\tvar deleteError error = nil\n\t// Get all connections from the specified family (ipv4 or ipv6)\n\tfor _, mark := range permanentFlags {\n\t\tbinary.BigEndian.PutUint32(filter.Mark, mark) // Little endian is in reverse not sure why. BigEndian makes it in correct order.\n\t\tcurrentConnections, err := nfct.Query(ct.Conntrack, f, filter)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"nfq: error on conntrack query: %s\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, connection := range currentConnections {\n\t\t\tdeleteError = nfct.Delete(ct.Conntrack, ct.IPv4, connection)\n\t\t\tif err != nil {\n\t\t\t\tnumberOfErrors++\n\t\t\t} else {\n\t\t\t\tdeleted++\n\t\t\t}\n\t\t}\n\t}\n\n\tif numberOfErrors > 0 {\n\t\tlog.Warningf(\"nfq: failed to delete %d conntrack entries last error is: %s\", numberOfErrors, deleteError)\n\t}\n\treturn deleted\n}\n\n// DeleteMarkedConnection removes a specific connection from the conntrack table.\nfunc DeleteMarkedConnection(conn *network.Connection) error {\n\tif nfct == nil {\n\t\treturn errors.New(\"nfq: nfct not initialized\")\n\t}\n\n\tcon := ct.Con{\n\t\tOrigin: &ct.IPTuple{\n\t\t\tSrc: &conn.LocalIP,\n\t\t\tDst: &conn.Entity.IP,\n\t\t\tProto: &ct.ProtoTuple{\n\t\t\t\tNumber:  &conn.Entity.Protocol,\n\t\t\t\tSrcPort: &conn.LocalPort,\n\t\t\t\tDstPort: &conn.Entity.Port,\n\t\t\t},\n\t\t},\n\t}\n\tconnections, err := nfct.Get(ct.Conntrack, ct.IPv4, con)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"nfq: failed to find entry for connection %s: %w\", conn.String(), err)\n\t}\n\n\tif len(connections) > 1 {\n\t\tlog.Warningf(\"nfq: multiple entries found for single connection: %s -> %d\", conn.String(), len(connections))\n\t}\n\n\tfor _, connection := range connections {\n\t\tdeleteErr := nfct.Delete(ct.Conntrack, ct.IPv4, connection)\n\t\tif err == nil {\n\t\t\terr = deleteErr\n\t\t}\n\t}\n\n\tif err != nil {\n\t\tlog.Warningf(\"nfq: error while deleting conntrack entries for connection %s: %s\", conn.String(), err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/firewall/interception/nfq/nfq.go",
    "content": "//go:build linux\n\n// Package nfq contains a nfqueue library experiment.\npackage nfq\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/florianl/go-nfqueue\"\n\t\"github.com/tevino/abool\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\tpmpacket \"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/process\"\n)\n\n// Queue wraps a nfqueue.\ntype Queue struct {\n\tid                   uint16\n\tafFamily             uint8\n\tnf                   atomic.Value\n\tpackets              chan pmpacket.Packet\n\tcancelSocketCallback context.CancelFunc\n\trestart              chan struct{}\n\n\tpendingVerdicts  uint64\n\tverdictCompleted chan struct{}\n}\n\nfunc (q *Queue) getNfq() *nfqueue.Nfqueue {\n\treturn q.nf.Load().(*nfqueue.Nfqueue) //nolint:forcetypeassert // TODO: Check.\n}\n\n// New opens a new nfQueue.\nfunc New(qid uint16, v6 bool) (*Queue, error) { //nolint:gocognit\n\tafFamily := unix.AF_INET\n\tif v6 {\n\t\tafFamily = unix.AF_INET6\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tq := &Queue{\n\t\tid:                   qid,\n\t\tafFamily:             uint8(afFamily),\n\t\tnf:                   atomic.Value{},\n\t\trestart:              make(chan struct{}, 1),\n\t\tpackets:              make(chan pmpacket.Packet, 1000),\n\t\tcancelSocketCallback: cancel,\n\t\tverdictCompleted:     make(chan struct{}, 1),\n\t}\n\n\t// Do not retry if the first one fails immediately as it\n\t// might point to a deeper integration error that's not fixable\n\t// with retrying ...\n\tif err := q.open(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tgo func() {\n\tWait:\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-q.restart:\n\t\t\t\truntime.Gosched()\n\t\t\t}\n\n\t\t\tfor {\n\t\t\t\terr := q.open(ctx)\n\t\t\t\tif err == nil {\n\t\t\t\t\tcontinue Wait\n\t\t\t\t}\n\n\t\t\t\t// Wait 100 ms and then try again ...\n\t\t\t\tlog.Errorf(\"Failed to open nfqueue: %s\", err)\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn q, nil\n}\n\n// open opens a new netlink socket and creates a new nfqueue.\n// Upon success, the new nfqueue is atomically stored in Queue.nf.\n// Users must use Queue.getNfq to access it. open does not care about\n// any other value or queue that might be stored in Queue.nf at\n// the time open is called.\nfunc (q *Queue) open(ctx context.Context) error {\n\tcfg := &nfqueue.Config{\n\t\tNfQueue:      q.id,\n\t\tMaxPacketLen: 1600, // mtu is normally around 1500, make sure to capture it.\n\t\tMaxQueueLen:  0xffff,\n\t\tAfFamily:     q.afFamily,\n\t\tCopymode:     nfqueue.NfQnlCopyPacket,\n\t\tReadTimeout:  1000 * time.Millisecond,\n\t\tWriteTimeout: 1000 * time.Millisecond,\n\t}\n\n\tnf, err := nfqueue.Open(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := nf.RegisterWithErrorFunc(ctx, q.packetHandler(ctx), q.handleError); err != nil {\n\t\t_ = nf.Close()\n\t\treturn err\n\t}\n\n\tq.nf.Store(nf)\n\n\treturn nil\n}\n\nfunc (q *Queue) handleError(e error) int {\n\t// embedded interface is required to work-around some\n\t// dep-vendoring weirdness\n\tif opError, ok := e.(interface { //nolint:errorlint // TODO: Check if we can remove workaround.\n\t\tTimeout() bool\n\t\tTemporary() bool\n\t}); ok {\n\t\tif opError.Timeout() || opError.Temporary() {\n\t\t\tc := atomic.LoadUint64(&q.pendingVerdicts)\n\t\t\tif c > 0 {\n\t\t\t\tlog.Tracef(\"nfqueue: waiting for %d pending verdicts\", c)\n\n\t\t\t\tfor atomic.LoadUint64(&q.pendingVerdicts) > 0 { // must NOT use c here\n\t\t\t\t\t<-q.verdictCompleted\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn 0\n\t\t}\n\t}\n\n\t// Check if the queue was already closed. Unfortunately, the exposed error\n\t// variable is in an internal stdlib package. Therefore, check for the error\n\t// string instead. :(\n\t// Official error variable is defined here:\n\t// https://github.com/golang/go/blob/0e85fd7561de869add933801c531bf25dee9561c/src/internal/poll/fd.go#L24\n\tif !strings.HasSuffix(e.Error(), \"use of closed file\") {\n\t\tlog.Errorf(\"nfqueue: encountered error while receiving packets: %s\\n\", e.Error())\n\t}\n\n\t// Close the existing socket\n\tif nf := q.getNfq(); nf != nil {\n\t\t// Call Close() on the Con directly, as nf.Close() calls waitgroup.Wait(), which then may deadlock.\n\t\t_ = nf.Con.Close()\n\t}\n\n\t// Trigger a restart of the queue\n\tq.restart <- struct{}{}\n\n\treturn 1\n}\n\nfunc (q *Queue) packetHandler(ctx context.Context) func(nfqueue.Attribute) int {\n\treturn func(attrs nfqueue.Attribute) int {\n\t\tif attrs.PacketID == nil {\n\t\t\t// we need a packet id to set a verdict,\n\t\t\t// if we don't get an ID there's hardly anything\n\t\t\t// we can do.\n\t\t\treturn 0\n\t\t}\n\n\t\tpkt := &packet{\n\t\t\tpktID:          *attrs.PacketID,\n\t\t\tqueue:          q,\n\t\t\tverdictSet:     make(chan struct{}),\n\t\t\tverdictPending: abool.New(),\n\t\t}\n\t\tpkt.Info().PID = process.UndefinedProcessID\n\t\tpkt.Info().SeenAt = time.Now()\n\n\t\tif attrs.Payload == nil {\n\t\t\t// There is not payload.\n\t\t\tlog.Warningf(\"nfqueue: packet #%d has no payload\", pkt.pktID)\n\t\t\treturn 0\n\t\t}\n\n\t\tif err := pmpacket.ParseLayer3(*attrs.Payload, &pkt.Base); err != nil {\n\t\t\tlog.Warningf(\"nfqueue: failed to parse payload: %s\", err)\n\t\t\t_ = pkt.Drop()\n\t\t\treturn 0\n\t\t}\n\n\t\tselect {\n\t\tcase q.packets <- pkt:\n\t\t\t// DEBUG:\n\t\t\t// log.Tracef(\"nfqueue: queued packet %s (%s -> %s) after %s\", pkt.ID(), pkt.Info().Src, pkt.Info().Dst, time.Since(pkt.Info().SeenAt))\n\t\tcase <-ctx.Done():\n\t\t\treturn 0\n\t\tcase <-time.After(time.Second):\n\t\t\tlog.Warningf(\"nfqueue: failed to queue packet (%s since it was handed over by the kernel)\", time.Since(pkt.Info().SeenAt))\n\t\t}\n\n\t\tgo func() {\n\t\t\tselect {\n\t\t\tcase <-pkt.verdictSet:\n\n\t\t\tcase <-time.After(20 * time.Second):\n\t\t\t\tlog.Warningf(\"nfqueue: no verdict set for packet %s (%s -> %s) after %s, dropping\", pkt.ID(), pkt.Info().Src, pkt.Info().Dst, time.Since(pkt.Info().SeenAt))\n\t\t\t\tif err := pkt.Drop(); err != nil {\n\t\t\t\t\tlog.Warningf(\"nfqueue: failed to apply default-drop to unveridcted packet %s (%s -> %s)\", pkt.ID(), pkt.Info().Src, pkt.Info().Dst)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\n\t\treturn 0 // continue calling this fn\n\t}\n}\n\n// Destroy destroys the queue. Any error encountered is logged.\nfunc (q *Queue) Destroy() {\n\tif q == nil {\n\t\treturn\n\t}\n\n\tq.cancelSocketCallback()\n\n\tif nf := q.getNfq(); nf != nil {\n\t\tif err := nf.Close(); err != nil {\n\t\t\tlog.Errorf(\"nfqueue: failed to close queue %d: %s\", q.id, err)\n\t\t}\n\t}\n}\n\n// PacketChannel returns the packet channel.\nfunc (q *Queue) PacketChannel() <-chan pmpacket.Packet {\n\treturn q.packets\n}\n"
  },
  {
    "path": "service/firewall/interception/nfq/packet.go",
    "content": "//go:build linux\n\npackage nfq\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\n\t\"github.com/florianl/go-nfqueue\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\tpmpacket \"github.com/safing/portmaster/service/network/packet\"\n)\n\n// Firewalling marks used by the Portmaster.\n// See TODO on packet.mark() on their relevance\n// and a possibility to remove most IPtables rules.\nconst (\n\tMarkAccept       = 1700\n\tMarkBlock        = 1701\n\tMarkDrop         = 1702\n\tMarkAcceptAlways = 1710\n\tMarkBlockAlways  = 1711\n\tMarkDropAlways   = 1712\n\tMarkRerouteNS    = 1799\n\tMarkRerouteSPN   = 1717\n)\n\nfunc markToString(mark int) string {\n\tswitch mark {\n\tcase MarkAccept:\n\t\treturn \"Accept\"\n\tcase MarkBlock:\n\t\treturn \"Block\"\n\tcase MarkDrop:\n\t\treturn \"Drop\"\n\tcase MarkAcceptAlways:\n\t\treturn \"AcceptAlways\"\n\tcase MarkBlockAlways:\n\t\treturn \"BlockAlways\"\n\tcase MarkDropAlways:\n\t\treturn \"DropAlways\"\n\tcase MarkRerouteNS:\n\t\treturn \"RerouteNS\"\n\tcase MarkRerouteSPN:\n\t\treturn \"RerouteSPN\"\n\t}\n\treturn \"unknown\"\n}\n\n// packet implements the packet.Packet interface.\ntype packet struct {\n\tpmpacket.Base\n\tpktID          uint32\n\tqueue          *Queue\n\tverdictSet     chan struct{}\n\tverdictPending *abool.AtomicBool\n}\n\nfunc (pkt *packet) ID() string {\n\treturn fmt.Sprintf(\"pkt:%d qid:%d\", pkt.pktID, pkt.queue.id)\n}\n\n// LoadPacketData does nothing on Linux, as data is always fully parsed.\nfunc (pkt *packet) LoadPacketData() error {\n\treturn nil\n}\n\n// TODO(ppacher): revisit the following behavior:\n//\n//\tThe legacy implementation of nfqueue (and the interception) module\n//\talways accept a packet but may mark it so that a subsequent rule in\n//\tthe C17 chain drops, rejects or modifies it.\n//\n//\tFor drop/return we could use the actual nfQueue verdicts Drop and Stop.\n//\tRe-routing to local NS or SPN can be done by modifying the packet here\n//\tand using SetVerdictModPacket and reject can be implemented using a simple\n//\traw-socket.\nfunc (pkt *packet) mark(mark int) (err error) {\n\tif pkt.verdictPending.SetToIf(false, true) {\n\t\tdefer close(pkt.verdictSet)\n\t\treturn pkt.setMark(mark)\n\t}\n\n\treturn errors.New(\"verdict already set\")\n}\n\nfunc (pkt *packet) setMark(mark int) error {\n\tatomic.AddUint64(&pkt.queue.pendingVerdicts, 1)\n\n\tdefer func() {\n\t\tatomic.AddUint64(&pkt.queue.pendingVerdicts, ^uint64(0))\n\t\tselect {\n\t\tcase pkt.queue.verdictCompleted <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}()\n\n\tfor {\n\t\tif err := pkt.queue.getNfq().SetVerdictWithMark(pkt.pktID, nfqueue.NfAccept, mark); err != nil {\n\t\t\t// embedded interface is required to work-around some\n\t\t\t// dep-vendoring weirdness\n\t\t\tif opErr, ok := err.(interface { //nolint:errorlint // TODO: Check if we can remove workaround.\n\t\t\t\tTimeout() bool\n\t\t\t\tTemporary() bool\n\t\t\t}); ok {\n\t\t\t\tif opErr.Timeout() || opErr.Temporary() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlog.Tracer(pkt.Ctx()).Errorf(\"nfqueue: failed to set verdict %s for %s (%s -> %s): %s\", markToString(mark), pkt.ID(), pkt.Info().Src, pkt.Info().Dst, err)\n\t\t\treturn err\n\t\t}\n\t\tbreak\n\t}\n\n\t// DEBUG:\n\t// log.Tracer(pkt.Ctx()).Tracef(\n\t// \t\"nfqueue: marking packet %s (%s -> %s) on queue %d with %s after %s\",\n\t// \tpkt.ID(), pkt.Info().Src, pkt.Info().Dst, pkt.queue.id,\n\t// \tmarkToString(mark), time.Since(pkt.Info().SeenAt),\n\t// )\n\treturn nil\n}\n\nfunc (pkt *packet) Accept() error {\n\treturn pkt.mark(MarkAccept)\n}\n\nfunc (pkt *packet) Block() error {\n\tif pkt.Info().Protocol == pmpacket.ICMP {\n\t\t// ICMP packets attributed to a blocked connection are always allowed, as\n\t\t// rejection ICMP packets will have the same mark as the blocked\n\t\t// connection. This is why we need to drop blocked ICMP packets instead.\n\t\treturn pkt.mark(MarkDrop)\n\t}\n\treturn pkt.mark(MarkBlock)\n}\n\nfunc (pkt *packet) Drop() error {\n\treturn pkt.mark(MarkDrop)\n}\n\nfunc (pkt *packet) PermanentAccept() error {\n\t// If the packet is localhost only, do not permanently accept the outgoing\n\t// packet, as the packet mark will be copied to the connection mark, which\n\t// will stick and it will bypass the incoming queue.\n\tif !pkt.Info().Inbound && pkt.Info().Dst.IsLoopback() {\n\t\treturn pkt.Accept()\n\t}\n\n\treturn pkt.mark(MarkAcceptAlways)\n}\n\nfunc (pkt *packet) PermanentBlock() error {\n\tif pkt.Info().Protocol == pmpacket.ICMP || pkt.Info().Protocol == pmpacket.ICMPv6 {\n\t\t// ICMP packets attributed to a blocked connection are always allowed, as\n\t\t// rejection ICMP packets will have the same mark as the blocked\n\t\t// connection. This is why we need to drop blocked ICMP packets instead.\n\t\treturn pkt.mark(MarkDropAlways)\n\t}\n\treturn pkt.mark(MarkBlockAlways)\n}\n\nfunc (pkt *packet) PermanentDrop() error {\n\treturn pkt.mark(MarkDropAlways)\n}\n\nfunc (pkt *packet) RerouteToNameserver() error {\n\treturn pkt.mark(MarkRerouteNS)\n}\n\nfunc (pkt *packet) RerouteToTunnel() error {\n\treturn pkt.mark(MarkRerouteSPN)\n}\n"
  },
  {
    "path": "service/firewall/interception/nfqueue_linux.go",
    "content": "package interception\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/coreos/go-iptables/iptables\"\n\t\"github.com/hashicorp/go-multierror\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/firewall/interception/nfq\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\nvar (\n\tv4chains []string\n\tv4rules  []string\n\tv4once   []string\n\n\tv6chains []string\n\tv6rules  []string\n\tv6once   []string\n\n\tout4Queue nfQueue\n\tin4Queue  nfQueue\n\tout6Queue nfQueue\n\tin6Queue  nfQueue\n\n\tisRunning      atomic.Bool\n\tshutdownSignal = make(chan struct{})\n)\n\n// nfQueue encapsulates nfQueue providers.\ntype nfQueue interface {\n\tPacketChannel() <-chan packet.Packet\n\tDestroy()\n}\n\nfunc init() {\n\tv4chains = []string{\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT\",\n\t\t\"mangle PORTMASTER-INGEST-INPUT\",\n\t\t\"filter PORTMASTER-FILTER\",\n\t\t\"nat PORTMASTER-REDIRECT\",\n\t}\n\n\tv4rules = []string{\n\t\t// stenya: Preserve original packet marks for permanently allowed connections (connmark 1710/AcceptAlways)\n\t\t// to ensure compatibility with other tools that also rely on packet marks.\n\t\t// This rule is placed before `CONNMARK --restore-mark` to prevent overwriting the original mark.\n\t\t// (Example: WireGuard/wg-quick relies on packet marks; changing them would break its routing).\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT -m mark ! --mark 0 -m connmark --mark 1710 -j RETURN\",\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT -j CONNMARK --restore-mark\",\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT -m mark --mark 0 -j NFQUEUE --queue-num 17040 --queue-bypass\",\n\n\t\t// stenya: Preserve original packet marks, similar to the OUTPUT chain (not sure if this is really needed for INPUT).\n\t\t\"mangle PORTMASTER-INGEST-INPUT -m mark ! --mark 0 -m connmark --mark 1710 -j RETURN\",\n\t\t\"mangle PORTMASTER-INGEST-INPUT -j CONNMARK --restore-mark\",\n\t\t\"mangle PORTMASTER-INGEST-INPUT -m mark --mark 0 -j NFQUEUE --queue-num 17140 --queue-bypass\",\n\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 0 -j DROP\",\n\t\t// stenya: Preserve original packet marks.\n\t\t\"filter PORTMASTER-FILTER -m connmark --mark 1710 -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1700 -j RETURN\",\n\t\t// Accepting ICMP packets with mark 1701 is required for rejecting to work,\n\t\t// as the rejection ICMP packet will have the same mark. Blocked ICMP\n\t\t// packets will always result in a drop within the Portmaster.\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1701 -p icmp -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1701 -j REJECT --reject-with icmp-admin-prohibited\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1702 -j DROP\",\n\t\t\"filter PORTMASTER-FILTER -j CONNMARK --save-mark\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1710 -j RETURN\",\n\t\t// Accepting ICMP packets with mark 1711 is required for rejecting to work,\n\t\t// as the rejection ICMP packet will have the same mark. Blocked ICMP\n\t\t// packets will always result in a drop within the Portmaster.\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1711 -p icmp -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1711 -j REJECT --reject-with icmp-admin-prohibited\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1712 -j DROP\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1717 -j RETURN\",\n\n\t\t\"nat PORTMASTER-REDIRECT -m mark --mark 1799 -p udp -j DNAT --to 127.0.0.17:53\",\n\t\t\"nat PORTMASTER-REDIRECT -m mark --mark 1717 -p tcp -j DNAT --to 127.0.0.17:717\",\n\t\t\"nat PORTMASTER-REDIRECT -m mark --mark 1717 -p udp -j DNAT --to 127.0.0.17:717\",\n\t\t// \"nat PORTMASTER-REDIRECT -m mark --mark 1717 ! -p tcp ! -p udp -j DNAT --to 127.0.0.17\",\n\t}\n\n\tv4once = []string{\n\t\t\"mangle OUTPUT -j PORTMASTER-INGEST-OUTPUT\",\n\t\t\"mangle INPUT -j PORTMASTER-INGEST-INPUT\",\n\t\t\"filter OUTPUT -j PORTMASTER-FILTER\",\n\t\t\"filter INPUT -j PORTMASTER-FILTER\",\n\t\t\"nat OUTPUT -j PORTMASTER-REDIRECT\",\n\t}\n\n\tv6chains = []string{\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT\",\n\t\t\"mangle PORTMASTER-INGEST-INPUT\",\n\t\t\"filter PORTMASTER-FILTER\",\n\t\t\"nat PORTMASTER-REDIRECT\",\n\t}\n\n\tv6rules = []string{\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT -m mark ! --mark 0 -m connmark --mark 1710 -j RETURN\",\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT -j CONNMARK --restore-mark\",\n\t\t\"mangle PORTMASTER-INGEST-OUTPUT -m mark --mark 0 -j NFQUEUE --queue-num 17060 --queue-bypass\",\n\n\t\t\"mangle PORTMASTER-INGEST-INPUT -m mark ! --mark 0 -m connmark --mark 1710 -j RETURN\",\n\t\t\"mangle PORTMASTER-INGEST-INPUT -j CONNMARK --restore-mark\",\n\t\t\"mangle PORTMASTER-INGEST-INPUT -m mark --mark 0 -j NFQUEUE --queue-num 17160 --queue-bypass\",\n\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 0 -j DROP\",\n\t\t\"filter PORTMASTER-FILTER -m connmark --mark 1710 -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1700 -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1701 -p icmpv6 -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1701 -j REJECT --reject-with icmp6-adm-prohibited\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1702 -j DROP\",\n\t\t\"filter PORTMASTER-FILTER -j CONNMARK --save-mark\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1710 -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1711 -p icmpv6 -j RETURN\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1711 -j REJECT --reject-with icmp6-adm-prohibited\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1712 -j DROP\",\n\t\t\"filter PORTMASTER-FILTER -m mark --mark 1717 -j RETURN\",\n\n\t\t\"nat PORTMASTER-REDIRECT -m mark --mark 1799 -p udp -j DNAT --to [::1]:53\",\n\t\t\"nat PORTMASTER-REDIRECT -m mark --mark 1717 -p tcp -j DNAT --to [::1]:717\",\n\t\t\"nat PORTMASTER-REDIRECT -m mark --mark 1717 -p udp -j DNAT --to [::1]:717\",\n\t\t// \"nat PORTMASTER-REDIRECT -m mark --mark 1717 ! -p tcp ! -p udp -j DNAT --to [::1]\",\n\t}\n\n\tv6once = []string{\n\t\t\"mangle OUTPUT -j PORTMASTER-INGEST-OUTPUT\",\n\t\t\"mangle INPUT -j PORTMASTER-INGEST-INPUT\",\n\t\t\"filter OUTPUT -j PORTMASTER-FILTER\",\n\t\t\"filter INPUT -j PORTMASTER-FILTER\",\n\t\t\"nat OUTPUT -j PORTMASTER-REDIRECT\",\n\t}\n\n\t// Reverse because we'd like to insert in a loop\n\t_ = sort.Reverse(sort.StringSlice(v4once)) // silence vet (sort is used just like in the docs)\n\t_ = sort.Reverse(sort.StringSlice(v6once)) // silence vet (sort is used just like in the docs)\n}\n\nfunc activateNfqueueFirewall() error {\n\tif err := activateIPTables(iptables.ProtocolIPv4, v4rules, v4once, v4chains); err != nil {\n\t\treturn err\n\t}\n\n\tif netenv.IPv6Enabled() {\n\t\tif err := activateIPTables(iptables.ProtocolIPv6, v6rules, v6once, v6chains); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := nfq.InitNFCT(); err != nil {\n\t\treturn err\n\t}\n\t_ = nfq.DeleteAllMarkedConnection()\n\n\treturn nil\n}\n\n// DeactivateNfqueueFirewall drops portmaster related IP tables rules.\n// Any errors encountered accumulated into a *multierror.Error.\nfunc DeactivateNfqueueFirewall() error {\n\t// IPv4\n\tvar result *multierror.Error\n\tif err := deactivateIPTables(iptables.ProtocolIPv4, v4once, v4chains); err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t// IPv6\n\tif netenv.IPv6Enabled() {\n\t\tif err := deactivateIPTables(iptables.ProtocolIPv6, v6once, v6chains); err != nil {\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\t}\n\n\t_ = nfq.DeleteAllMarkedConnection()\n\tnfq.TeardownNFCT()\n\n\treturn result.ErrorOrNil()\n}\n\nfunc activateIPTables(protocol iptables.Protocol, rules, once, chains []string) error {\n\ttbls, err := iptables.NewWithProtocol(protocol)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, chain := range chains {\n\t\tsplittedRule := strings.Split(chain, \" \")\n\t\tif err = tbls.ClearChain(splittedRule[0], splittedRule[1]); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, rule := range rules {\n\t\tsplittedRule := strings.Split(rule, \" \")\n\t\tif err = tbls.Append(splittedRule[0], splittedRule[1], splittedRule[2:]...); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, rule := range once {\n\t\tsplittedRule := strings.Split(rule, \" \")\n\n\t\terr := tbls.InsertUnique(splittedRule[0], splittedRule[1], 1, splittedRule[2:]...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ensureJumpRulesAtTop ensures that all \"once\" rules (the jump rules\n// into Portmaster chains) are at the first position in their respective chains\n// for both IPv4 and IPv6. It returns the list of rules that were out of position\n// and had to be reinserted.\nfunc ensureJumpRulesAtTop() (reinsertedRules []string, err error) {\n\treinsertedRules, err = reinsertDisplacedRules(iptables.ProtocolIPv4, v4once)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif netenv.IPv6Enabled() {\n\t\tv6ReinsertedRules, err := reinsertDisplacedRules(iptables.ProtocolIPv6, v6once)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treinsertedRules = append(reinsertedRules, v6ReinsertedRules...)\n\t}\n\n\treturn reinsertedRules, nil\n}\n\n// reinsertDisplacedRules checks each rule in once and, if it is not already\n// at position 1 of its chain, moves it there. To avoid a window where packets\n// can bypass the firewall, a temporary placeholder rule is inserted first,\n// then the original rule is deleted and reinserted at position 1, and finally\n// the placeholder is removed. Returns the subset of rules that required moving.\n// Required rules format example: \"filter OUTPUT -j PORTMASTER-FILTER\"\nfunc reinsertDisplacedRules(protocol iptables.Protocol, once []string) (reinsertedRules []string, err error) {\n\ttbls, err := iptables.NewWithProtocol(protocol)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar rulesToUpdate []string\n\tfor _, onceRule := range once {\n\t\tsplittedRule := strings.Split(onceRule, \" \")\n\t\ttable := splittedRule[0]\n\t\tchain := splittedRule[1]\n\t\t// get the first rule of the chain\n\t\tfirstRule, err := tbls.ListById(table, chain, 1)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// check if the first rule of the chain is the portmaster rule\n\t\tpmChainName := splittedRule[len(splittedRule)-1]\n\t\tif !strings.HasSuffix(firstRule, pmChainName) {\n\t\t\trulesToUpdate = append(rulesToUpdate, onceRule)\n\t\t}\n\t}\n\n\tcomment := []string{\"-m\", \"comment\", \"--comment\", `TEMPORARY_RULE`}\n\tfor _, rule := range rulesToUpdate {\n\t\tsplittedRule := strings.Split(rule, \" \")\n\t\ttable := splittedRule[0]     // \"filter\"\n\t\tchain := splittedRule[1]     // \"OUTPUT\"\n\t\truleSpec := splittedRule[2:] // \"-j PORTMASTER-FILTER\"\n\n\t\ttmpRuleSpec := append(append([]string{}, comment...), ruleSpec...) // \"-m comment --comment \"TEMPORARY_RULE\" -j PORTMASTER-FILTER\"\n\n\t\t// Insert the temporary rule on the first position\n\t\terr = tbls.Insert(table, chain, 1, tmpRuleSpec...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to insert temporary rule '%s' into chain '%s' in table '%s': %w\", tmpRuleSpec, chain, table, err)\n\t\t}\n\t\t// delete the original rule and re-insert it on the first position\n\t\terr = tbls.Delete(table, chain, ruleSpec...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to delete original rule '%s' from chain '%s' in table '%s': %w\", ruleSpec, chain, table, err)\n\t\t}\n\t\terr = tbls.Insert(table, chain, 1, ruleSpec...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to re-insert original rule '%s' into chain '%s' in table '%s': %w\", ruleSpec, chain, table, err)\n\t\t}\n\t\t// delete the temporary rule\n\t\terr = tbls.Delete(table, chain, tmpRuleSpec...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to delete temporary rule '%s' from chain '%s' in table '%s': %w\", tmpRuleSpec, chain, table, err)\n\t\t}\n\t}\n\n\treturn rulesToUpdate, nil\n}\n\nfunc deactivateIPTables(protocol iptables.Protocol, rules, chains []string) error {\n\ttbls, err := iptables.NewWithProtocol(protocol)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar multierr *multierror.Error\n\n\tfor _, rule := range rules {\n\t\tsplittedRule := strings.Split(rule, \" \")\n\t\tok, err := tbls.Exists(splittedRule[0], splittedRule[1], splittedRule[2:]...)\n\t\tif err != nil {\n\t\t\tmultierr = multierror.Append(multierr, err)\n\t\t}\n\t\tif ok {\n\t\t\tif err = tbls.Delete(splittedRule[0], splittedRule[1], splittedRule[2:]...); err != nil {\n\t\t\t\tmultierr = multierror.Append(multierr, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, chain := range chains {\n\t\tsplittedRule := strings.Split(chain, \" \")\n\t\tif err = tbls.ClearChain(splittedRule[0], splittedRule[1]); err != nil {\n\t\t\tmultierr = multierror.Append(multierr, err)\n\t\t}\n\t\tif err = tbls.DeleteChain(splittedRule[0], splittedRule[1]); err != nil {\n\t\t\tmultierr = multierror.Append(multierr, err)\n\t\t}\n\t}\n\n\treturn multierr.ErrorOrNil()\n}\n\n// StartNfqueueInterception starts the nfqueue interception.\nfunc StartNfqueueInterception(packets chan<- packet.Packet) (err error) {\n\tif !isRunning.CompareAndSwap(false, true) {\n\t\treturn nil // already running\n\t}\n\n\t// Reset shutdown signal\n\tshutdownSignal = make(chan struct{})\n\n\terr = activateNfqueueFirewall()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not initialize nfqueue: %w\", err)\n\t}\n\n\tout4Queue, err = nfq.New(17040, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"nfqueue(IPv4, out): %w\", err)\n\t}\n\tin4Queue, err = nfq.New(17140, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"nfqueue(IPv4, in): %w\", err)\n\t}\n\n\tif netenv.IPv6Enabled() {\n\t\tout6Queue, err = nfq.New(17060, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"nfqueue(IPv6, out): %w\", err)\n\t\t}\n\t\tin6Queue, err = nfq.New(17160, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"nfqueue(IPv6, in): %w\", err)\n\t\t}\n\t} else {\n\t\tlog.Warningf(\"interception: no IPv6 stack detected, disabling IPv6 network integration\")\n\t\tout6Queue = &disabledNfQueue{}\n\t\tin6Queue = &disabledNfQueue{}\n\t}\n\n\tmodule.mgr.Go(\"nfqueue packet handler\", func(_ *mgr.WorkerCtx) error {\n\t\treturn handleInterception(packets)\n\t})\n\n\t// Safety check: ensure Portmaster's iptables jump rules remain at the top of their chains.\n\t// During system boot, other services may insert their own iptables rules, potentially\n\t// displacing Portmaster's rules and causing traffic to bypass the firewall.\n\t// The check runs a few times after startup with increasing delays to cover this window.\n\t// A continuous periodic check is intentionally avoided - it would not react immediately\n\t// to rule changes anyway, and the overhead is not justified after the boot stage.\n\t// TODO: consider a more reactive approach using netlink to detect iptables changes in real time.\n\tmodule.mgr.Go(\"iptables rule order maintenance (startup)\", func(w *mgr.WorkerCtx) error {\n\t\tfor _, d := range []time.Duration{5 * time.Second, 10 * time.Second, 30 * time.Second} {\n\t\t\tselect {\n\t\t\tcase <-time.After(d):\n\t\t\tcase <-w.Done():\n\t\t\t\treturn nil\n\t\t\tcase <-shutdownSignal:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif updatedRules, err := ensureJumpRulesAtTop(); err != nil {\n\t\t\t\tlog.Errorf(\"interception: failed to ensure iptables jump rules at top: %v\", err)\n\t\t\t} else if len(updatedRules) > 0 {\n\t\t\t\tlog.Warningf(\"interception: the following iptables rules were found out of position and have been reinserted at the top of their chains: %v\", updatedRules)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n\n\treturn nil\n}\n\n// StopNfqueueInterception stops the nfqueue interception.\nfunc StopNfqueueInterception() error {\n\tif !isRunning.CompareAndSwap(true, false) {\n\t\treturn nil // not running\n\t}\n\n\t// Signal shutdown to packet handler\n\tdefer close(shutdownSignal)\n\n\tif out4Queue != nil {\n\t\tout4Queue.Destroy()\n\t}\n\tif in4Queue != nil {\n\t\tin4Queue.Destroy()\n\t}\n\tif out6Queue != nil {\n\t\tout6Queue.Destroy()\n\t}\n\tif in6Queue != nil {\n\t\tin6Queue.Destroy()\n\t}\n\n\terr := DeactivateNfqueueFirewall()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interception: error while deactivating nfqueue: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc handleInterception(packets chan<- packet.Packet) error {\n\tfor {\n\t\tvar pkt packet.Packet\n\t\tselect {\n\t\tcase <-shutdownSignal:\n\t\t\treturn nil\n\t\tcase pkt = <-out4Queue.PacketChannel():\n\t\t\tpkt.SetOutbound()\n\t\tcase pkt = <-in4Queue.PacketChannel():\n\t\t\tpkt.SetInbound()\n\t\tcase pkt = <-out6Queue.PacketChannel():\n\t\t\tpkt.SetOutbound()\n\t\tcase pkt = <-in6Queue.PacketChannel():\n\t\t\tpkt.SetInbound()\n\t\t}\n\n\t\tselect {\n\t\tcase packets <- pkt:\n\t\tcase <-shutdownSignal:\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\ntype disabledNfQueue struct{}\n\nfunc (dnfq *disabledNfQueue) PacketChannel() <-chan packet.Packet {\n\treturn nil\n}\n\nfunc (dnfq *disabledNfQueue) Destroy() {}\n"
  },
  {
    "path": "service/firewall/interception/packet_tracer.go",
    "content": "package interception\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\ntype tracedPacket struct {\n\tstart time.Time\n\tpacket.Packet\n}\n\nfunc tracePacket(p packet.Packet) packet.Packet {\n\treturn &tracedPacket{\n\t\tstart:  time.Now(),\n\t\tPacket: p,\n\t}\n}\n\nfunc (p *tracedPacket) markServed(v string) {\n\tif packetMetricsDestination == \"\" {\n\t\treturn\n\t}\n\n\tmetrics.record(p, v)\n}\n\nfunc (p *tracedPacket) Accept() error {\n\tdefer p.markServed(\"accept\")\n\treturn p.Packet.Accept()\n}\n\nfunc (p *tracedPacket) Block() error {\n\tdefer p.markServed(\"block\")\n\treturn p.Packet.Block()\n}\n\nfunc (p *tracedPacket) Drop() error {\n\tdefer p.markServed(\"drop\")\n\treturn p.Packet.Drop()\n}\n\nfunc (p *tracedPacket) PermanentAccept() error {\n\tdefer p.markServed(\"perm-accept\")\n\treturn p.Packet.PermanentAccept()\n}\n\nfunc (p *tracedPacket) PermanentBlock() error {\n\tdefer p.markServed(\"perm-block\")\n\treturn p.Packet.PermanentBlock()\n}\n\nfunc (p *tracedPacket) PermanentDrop() error {\n\tdefer p.markServed(\"perm-drop\")\n\treturn p.Packet.PermanentDrop()\n}\n\nfunc (p *tracedPacket) RerouteToNameserver() error {\n\tdefer p.markServed(\"reroute-ns\")\n\treturn p.Packet.RerouteToNameserver()\n}\n\nfunc (p *tracedPacket) RerouteToTunnel() error {\n\tdefer p.markServed(\"reroute-tunnel\")\n\treturn p.Packet.RerouteToTunnel()\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext/bandwidth_stats.go",
    "content": "//go:build windows\n// +build windows\n\npackage windowskext\n\n// This file contains example code how to read bandwidth stats from the kext. Its not ment to be used in production.\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\ntype Rxtxdata struct {\n\trx uint64\n\ttx uint64\n}\n\ntype Key struct {\n\tlocalIP    [4]uint32\n\tremoteIP   [4]uint32\n\tlocalPort  uint16\n\tremotePort uint16\n\tipv6       bool\n\tprotocol   uint8\n}\n\nvar m = make(map[Key]Rxtxdata)\n\nfunc BandwidthStatsWorker(ctx context.Context, collectInterval time.Duration, bandwidthUpdates chan *packet.BandwidthUpdate) error {\n\t// Setup ticker.\n\tticker := time.NewTicker(collectInterval)\n\tdefer ticker.Stop()\n\n\t// Collect bandwidth at every tick.\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\terr := reportBandwidth(ctx, bandwidthUpdates)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc reportBandwidth(ctx context.Context, bandwidthUpdates chan *packet.BandwidthUpdate) error {\n\tstats, err := GetConnectionsStats()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Report all statistics.\n\tfor i, stat := range stats {\n\t\tconnID := packet.CreateConnectionID(\n\t\t\tpacket.IPProtocol(stat.protocol),\n\t\t\tconvertArrayToIP(stat.localIP, stat.ipV6 == 1), stat.localPort,\n\t\t\tconvertArrayToIP(stat.remoteIP, stat.ipV6 == 1), stat.remotePort,\n\t\t\tfalse,\n\t\t)\n\t\tupdate := &packet.BandwidthUpdate{\n\t\t\tConnID:        connID,\n\t\t\tBytesReceived: stat.receivedBytes,\n\t\t\tBytesSent:     stat.transmittedBytes,\n\t\t\tMethod:        packet.Additive,\n\t\t}\n\t\tselect {\n\t\tcase bandwidthUpdates <- update:\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t\tlog.Warningf(\"kext: bandwidth update queue is full, skipping rest of batch (%d entries)\", len(stats)-i)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc StartBandwidthConsoleLogger() {\n\tgo func() {\n\t\tticker := time.NewTicker(2 * time.Second)\n\t\tdefer ticker.Stop()\n\t\tfor range ticker.C {\n\t\t\tconns, err := GetConnectionsStats()\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, conn := range conns {\n\t\t\t\tif conn.receivedBytes == 0 && conn.transmittedBytes == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tkey := Key{\n\t\t\t\t\tlocalIP:    conn.localIP,\n\t\t\t\t\tremoteIP:   conn.remoteIP,\n\t\t\t\t\tlocalPort:  conn.localPort,\n\t\t\t\t\tremotePort: conn.remotePort,\n\t\t\t\t\tipv6:       conn.ipV6 == 1,\n\t\t\t\t\tprotocol:   conn.protocol,\n\t\t\t\t}\n\n\t\t\t\t// First we get a \"copy\" of the entry\n\t\t\t\tif entry, ok := m[key]; ok {\n\t\t\t\t\t// Then we modify the copy\n\t\t\t\t\tentry.rx += conn.receivedBytes\n\t\t\t\t\tentry.tx += conn.transmittedBytes\n\n\t\t\t\t\t// Then we reassign map entry\n\t\t\t\t\tm[key] = entry\n\t\t\t\t} else {\n\t\t\t\t\tm[key] = Rxtxdata{\n\t\t\t\t\t\trx: conn.receivedBytes,\n\t\t\t\t\t\ttx: conn.transmittedBytes,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlog.Debug(\"----------------------------------\")\n\t\t\tfor key, value := range m {\n\t\t\t\tlog.Debugf(\n\t\t\t\t\t\"Conn: %d %s:%d %s:%d rx:%d tx:%d\", key.protocol,\n\t\t\t\t\tconvertArrayToIP(key.localIP, key.ipv6), key.localPort,\n\t\t\t\t\tconvertArrayToIP(key.remoteIP, key.ipv6), key.remotePort,\n\t\t\t\t\tvalue.rx, value.tx,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}()\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext/doc.go",
    "content": "// +build windows\n\n// Package windowskext provides network interception capabilities on windows via the Portmaster Kernel Extension.\npackage windowskext\n"
  },
  {
    "path": "service/firewall/interception/windowskext/handler.go",
    "content": "//go:build windows\n// +build windows\n\npackage windowskext\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/safing/portmaster/service/process\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\nconst (\n\t// VerdictRequestFlagFastTrackPermitted is set on packets that have been\n\t// already permitted by the kernel extension and the verdict request is only\n\t// informational.\n\tVerdictRequestFlagFastTrackPermitted = 1\n\n\t// VerdictRequestFlagSocketAuth indicates that the verdict request is for a\n\t// connection that was intercepted on an ALE layer instead of in the network\n\t// stack itself. Thus, no packet data is available.\n\tVerdictRequestFlagSocketAuth = 2\n\n\t// VerdictRequestFlagExpectSocketAuth indicates that the next verdict\n\t// requests is expected to be an informational socket auth request from\n\t// the ALE layer.\n\tVerdictRequestFlagExpectSocketAuth = 4\n)\n\n// Do not change the order of the members! The structure is used to communicate with the kernel extension.\n// VerdictRequest is the request structure from the Kext.\ntype VerdictRequest struct {\n\tid         uint32 // ID from RegisterPacket\n\tpid        uint64 // Process ID - info only packets\n\tdirection  uint8\n\tipV6       uint8     // True: IPv6, False: IPv4\n\tprotocol   uint8     // Protocol\n\tflags      uint8     // Flags\n\tlocalIP    [4]uint32 // Source Address\n\tremoteIP   [4]uint32 // Destination Address\n\tlocalPort  uint16    // Source Port\n\tremotePort uint16    // Destination port\n\t_          uint32    // compartmentID\n\t_          uint32    // interfaceIndex\n\t_          uint32    // subInterfaceIndex\n\tpacketSize uint32\n}\n\n// Do not change the order of the members! The structure is used to communicate with the kernel extension.\ntype VerdictInfo struct {\n\tid      uint32          // ID from RegisterPacket\n\tverdict network.Verdict // verdict for the connection\n}\n\n// Do not change the order of the members! The structure to communicate with the kernel extension.\ntype VerdictUpdateInfo struct {\n\tlocalIP    [4]uint32 // Source Address, only srcIP[0] if IPv4\n\tremoteIP   [4]uint32 // Destination Address\n\tlocalPort  uint16    // Source Port\n\tremotePort uint16    // Destination port\n\tipV6       uint8     // True: IPv6, False: IPv4\n\tprotocol   uint8     // Protocol (UDP, TCP, ...)\n\tverdict    uint8     // New verdict\n}\n\ntype ConnectionStat struct {\n\tlocalIP          [4]uint32 //Source Address, only srcIP[0] if IPv4\n\tremoteIP         [4]uint32 //Destination Address\n\tlocalPort        uint16    //Source Port\n\tremotePort       uint16    //Destination port\n\treceivedBytes    uint64    //Number of bytes recived on this connection\n\ttransmittedBytes uint64    //Number of bytes transsmited from this connection\n\tipV6             uint8     //True: IPv6, False: IPv4\n\tprotocol         uint8     //Protocol (UDP, TCP, ...)\n}\n\ntype VersionInfo struct {\n\tmajor    uint8\n\tminor    uint8\n\trevision uint8\n\tbuild    uint8\n}\n\nfunc (v *VersionInfo) String() string {\n\treturn fmt.Sprintf(\"%d.%d.%d.%d\", v.major, v.minor, v.revision, v.build)\n}\n\n// Handler transforms received packets to the Packet interface.\nfunc Handler(ctx context.Context, packets chan packet.Packet) {\n\tfor {\n\t\tpacketInfo, err := RecvVerdictRequest()\n\t\tif err != nil {\n\t\t\t// Check if we are done with processing.\n\t\t\tif errors.Is(err, ErrKextNotReady) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlog.Warningf(\"failed to get packet from windows kext: %s\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif packetInfo == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// log.Tracef(\"packet: %+v\", packetInfo)\n\n\t\t// New Packet\n\t\tnew := &Packet{\n\t\t\tverdictRequest: packetInfo,\n\t\t\tverdictSet:     abool.NewBool(false),\n\t\t}\n\t\tinfo := new.Info()\n\t\tinfo.Inbound = packetInfo.direction > 0\n\t\tinfo.InTunnel = false\n\t\tinfo.Protocol = packet.IPProtocol(packetInfo.protocol)\n\t\tinfo.PID = int(packetInfo.pid)\n\t\tinfo.SeenAt = time.Now()\n\n\t\t// Check PID\n\t\tif info.PID == 0 {\n\t\t\t// Windows does not have zero PIDs.\n\t\t\t// Set to UndefinedProcessID.\n\t\t\tinfo.PID = process.UndefinedProcessID\n\t\t}\n\n\t\t// Set IP version\n\t\tif packetInfo.ipV6 == 1 {\n\t\t\tinfo.Version = packet.IPv6\n\t\t} else {\n\t\t\tinfo.Version = packet.IPv4\n\t\t}\n\n\t\t// Set IPs\n\t\tif info.Inbound {\n\t\t\t// Inbound\n\t\t\tinfo.Src = convertArrayToIP(packetInfo.remoteIP, info.Version == packet.IPv6)\n\t\t\tinfo.Dst = convertArrayToIP(packetInfo.localIP, info.Version == packet.IPv6)\n\t\t} else {\n\t\t\t// Outbound\n\t\t\tinfo.Src = convertArrayToIP(packetInfo.localIP, info.Version == packet.IPv6)\n\t\t\tinfo.Dst = convertArrayToIP(packetInfo.remoteIP, info.Version == packet.IPv6)\n\t\t}\n\n\t\t// Set Ports\n\t\tif info.Inbound {\n\t\t\t// Inbound\n\t\t\tinfo.SrcPort = packetInfo.remotePort\n\t\t\tinfo.DstPort = packetInfo.localPort\n\t\t} else {\n\t\t\t// Outbound\n\t\t\tinfo.SrcPort = packetInfo.localPort\n\t\t\tinfo.DstPort = packetInfo.remotePort\n\t\t}\n\n\t\tpackets <- new\n\t}\n}\n\n// convertArrayToIP converts an array of uint32 values to a net.IP address.\nfunc convertArrayToIP(input [4]uint32, ipv6 bool) net.IP {\n\tif !ipv6 {\n\t\taddressBuf := make([]byte, 4)\n\t\tbinary.BigEndian.PutUint32(addressBuf, input[0])\n\t\treturn net.IP(addressBuf)\n\t}\n\n\taddressBuf := make([]byte, 16)\n\tfor i := 0; i < 4; i++ {\n\t\tbinary.BigEndian.PutUint32(addressBuf[i*4:i*4+4], input[i])\n\t}\n\treturn net.IP(addressBuf)\n}\n\nfunc ipAddressToArray(ip net.IP, isIPv6 bool) [4]uint32 {\n\tarray := [4]uint32{0}\n\tif isIPv6 {\n\t\tfor i := 0; i < 4; i++ {\n\t\t\tbinary.BigEndian.PutUint32(asByteArrayWithLength(&array[i], 4), getUInt32Value(&ip[i]))\n\t\t}\n\t} else {\n\t\tbinary.BigEndian.PutUint32(asByteArrayWithLength(&array[0], 4), getUInt32Value(&ip[0]))\n\t}\n\n\treturn array\n}\n\nfunc asByteArray[T any](obj *T) []byte {\n\treturn unsafe.Slice((*byte)(unsafe.Pointer(obj)), unsafe.Sizeof(*obj))\n}\n\nfunc asByteArrayWithLength[T any](obj *T, size uint32) []byte {\n\treturn unsafe.Slice((*byte)(unsafe.Pointer(obj)), size)\n}\n\nfunc getUInt32Value[T any](obj *T) uint32 {\n\treturn *(*uint32)(unsafe.Pointer(obj))\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext/kext.go",
    "content": "//go:build windows\n// +build windows\n\npackage windowskext\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"golang.org/x/sys/windows\"\n)\n\n// Package errors\nvar (\n\tErrKextNotReady = errors.New(\"the windows kernel extension (driver) is not ready to accept commands\")\n\tErrNoPacketID   = errors.New(\"the packet has no ID, possibly because it was fast-tracked by the kernel extension\")\n\n\tkextLock   sync.RWMutex\n\tdriverPath string\n\n\tkextHandle windows.Handle\n\tservice    *KextService\n)\n\nconst (\n\twinErrInvalidData     = uintptr(windows.ERROR_INVALID_DATA)\n\twinInvalidHandleValue = windows.Handle(^uintptr(0)) // Max value\n\tdriverName            = \"PortmasterKext\"\n)\n\n// Init initializes the DLL and the Kext (Kernel Driver).\nfunc Init(path string) error {\n\tkextHandle = winInvalidHandleValue\n\tdriverPath = path\n\treturn nil\n}\n\n// Start intercepting.\nfunc Start() error {\n\tkextLock.Lock()\n\tdefer kextLock.Unlock()\n\n\t// initialize and start driver service\n\tvar err error\n\tservice, err = createKextService(driverName, driverPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create service: %w\", err)\n\t}\n\n\trunning, err := service.isRunning()\n\tif err == nil && !running {\n\t\terr = service.start(true)\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to start service: %w\", err)\n\t\t}\n\t} else if err != nil {\n\t\treturn fmt.Errorf(\"service not initialized: %w\", err)\n\t}\n\n\t// Open the driver\n\tfilename := `\\\\.\\` + driverName\n\tkextHandle, err = openDriver(filename)\n\n\t// driver was not installed\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open driver: %q %w\", filename, err)\n\t}\n\n\treturn nil\n}\n\nfunc SetKextHandler(handle windows.Handle) {\n\tkextHandle = handle\n}\n\nfunc SetKextService(handle windows.Handle, path string) {\n\tservice = &KextService{handle: handle}\n\tdriverPath = path\n}\n\n// Stop intercepting.\nfunc Stop() error {\n\t// Prepare kernel for shutdown\n\terr := shutdownRequest()\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: shutdown request failed: %s\", err)\n\t}\n\n\tkextLock.Lock()\n\tdefer kextLock.Unlock()\n\n\terr = closeDriver(kextHandle)\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: failed to close the handle: %s\", err)\n\t}\n\n\terr = service.stop(true)\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: failed to stop service: %s\", err)\n\t}\n\t// Driver file may change on the next start so it's better to delete the service\n\terr = service.delete()\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: failed to delete service: %s\", err)\n\t}\n\n\tkextHandle = winInvalidHandleValue\n\treturn nil\n}\n\nfunc shutdownRequest() error {\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\tif kextHandle == winInvalidHandleValue {\n\t\treturn ErrKextNotReady\n\t}\n\t// Sent a shutdown request so the kernel extension can prepare.\n\t_, err := deviceIOControl(kextHandle, IOCTL_SHUTDOWN_REQUEST, nil, nil)\n\n\treturn err\n}\n\n// RecvVerdictRequest waits for the next verdict request from the kext. If a timeout is reached, both *VerdictRequest and error will be nil.\nfunc RecvVerdictRequest() (*VerdictRequest, error) {\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\tif kextHandle == winInvalidHandleValue {\n\t\treturn nil, ErrKextNotReady\n\t}\n\n\t// DEBUG:\n\t// timestamp := time.Now()\n\t// defer log.Tracef(\"winkext: getting verdict request took %s\", time.Since(timestamp))\n\n\t// Initialize struct for the output data\n\tvar new VerdictRequest\n\n\t// Make driver request\n\tdata := asByteArray(&new)\n\tbytesRead, err := deviceIOControl(kextHandle, IOCTL_RECV_VERDICT_REQ, nil, data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif bytesRead == 0 {\n\t\treturn nil, nil // no error, no new verdict request\n\t}\n\n\treturn &new, nil\n}\n\n// SetVerdict sets the verdict for a packet and/or connection.\nfunc SetVerdict(pkt *Packet, verdict network.Verdict) error {\n\tif pkt.verdictRequest.pid != 0 {\n\t\treturn nil // Ignore info only packets\n\t}\n\tif pkt.verdictRequest.id == 0 {\n\t\tlog.Tracer(pkt.Ctx()).Errorf(\"kext: failed to set verdict %s: no packet ID\", verdict)\n\t\treturn ErrNoPacketID\n\t}\n\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\tif kextHandle == winInvalidHandleValue {\n\t\tlog.Tracer(pkt.Ctx()).Errorf(\"kext: failed to set verdict %s: kext not ready\", verdict)\n\t\treturn ErrKextNotReady\n\t}\n\n\tverdictInfo := VerdictInfo{pkt.verdictRequest.id, verdict}\n\n\t// Make driver request\n\tdata := asByteArray(&verdictInfo)\n\t_, err := deviceIOControl(kextHandle, IOCTL_SET_VERDICT, data, nil)\n\tif err != nil {\n\t\tlog.Tracer(pkt.Ctx()).Errorf(\"kext: failed to set verdict %s on packet %d\", verdict, pkt.verdictRequest.id)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// GetPayload returns the payload of a packet.\nfunc GetPayload(packetID uint32, packetSize uint32) ([]byte, error) {\n\tif packetID == 0 {\n\t\treturn nil, ErrNoPacketID\n\t}\n\n\t// Check if driver is initialized\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\tif kextHandle == winInvalidHandleValue {\n\t\treturn nil, ErrKextNotReady\n\t}\n\n\tbuf := make([]byte, packetSize)\n\n\t// Combine id and length\n\tpayload := struct {\n\t\tid     uint32\n\t\tlength uint32\n\t}{packetID, packetSize}\n\n\t// Make driver request\n\tdata := asByteArray(&payload)\n\tbytesRead, err := deviceIOControl(kextHandle, IOCTL_GET_PAYLOAD, data, unsafe.Slice(&buf[0], packetSize))\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// check the result and return\n\tif bytesRead == 0 {\n\t\treturn nil, errors.New(\"windows kext did not return any data\")\n\t}\n\n\tif bytesRead < uint32(len(buf)) {\n\t\treturn buf[:bytesRead], nil\n\t}\n\n\treturn buf, nil\n}\n\nfunc ClearCache() error {\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\n\t// Check if driver is initialized\n\tif kextHandle == winInvalidHandleValue {\n\t\tlog.Error(\"kext: failed to clear the cache: kext not ready\")\n\t\treturn ErrKextNotReady\n\t}\n\n\t// Make driver request\n\t_, err := deviceIOControl(kextHandle, IOCTL_CLEAR_CACHE, nil, nil)\n\treturn err\n}\n\nfunc UpdateVerdict(conn *network.Connection) error {\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\n\t// Check if driver is initialized\n\tif kextHandle == winInvalidHandleValue {\n\t\tlog.Error(\"kext: failed to clear the cache: kext not ready\")\n\t\treturn ErrKextNotReady\n\t}\n\n\tvar isIpv6 uint8 = 0\n\tif conn.IPVersion == packet.IPv6 {\n\t\tisIpv6 = 1\n\t}\n\n\t// initialize variables\n\tinfo := VerdictUpdateInfo{\n\t\tipV6:       isIpv6,\n\t\tprotocol:   uint8(conn.IPProtocol),\n\t\tlocalIP:    ipAddressToArray(conn.LocalIP, isIpv6 == 1),\n\t\tlocalPort:  conn.LocalPort,\n\t\tremoteIP:   ipAddressToArray(conn.Entity.IP, isIpv6 == 1),\n\t\tremotePort: conn.Entity.Port,\n\t\tverdict:    uint8(conn.Verdict),\n\t}\n\n\t// Make driver request\n\tdata := asByteArray(&info)\n\t_, err := deviceIOControl(kextHandle, IOCTL_UPDATE_VERDICT, data, nil)\n\treturn err\n}\n\nfunc GetVersion() (*VersionInfo, error) {\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\n\t// Check if driver is initialized\n\tif kextHandle == winInvalidHandleValue {\n\t\tlog.Error(\"kext: failed to clear the cache: kext not ready\")\n\t\treturn nil, ErrKextNotReady\n\t}\n\n\tdata := make([]uint8, 4)\n\t_, err := deviceIOControl(kextHandle, IOCTL_VERSION, nil, data)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tversion := &VersionInfo{\n\t\tmajor:    data[0],\n\t\tminor:    data[1],\n\t\trevision: data[2],\n\t\tbuild:    data[3],\n\t}\n\treturn version, nil\n}\n\nvar sizeOfConnectionStat = uint32(unsafe.Sizeof(ConnectionStat{}))\n\nfunc GetConnectionsStats() ([]ConnectionStat, error) {\n\tkextLock.RLock()\n\tdefer kextLock.RUnlock()\n\n\t// Check if driver is initialized\n\tif kextHandle == winInvalidHandleValue {\n\t\tlog.Error(\"kext: failed to clear the cache: kext not ready\")\n\t\treturn nil, ErrKextNotReady\n\t}\n\n\tvar data [100]ConnectionStat\n\tsize := len(data)\n\tbytesReturned, err := deviceIOControl(kextHandle, IOCTL_GET_CONNECTIONS_STAT, asByteArray(&size), asByteArray(&data))\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn data[:bytesReturned/sizeOfConnectionStat], nil\n}\n\nfunc openDriver(filename string) (windows.Handle, error) {\n\tu16filename, err := syscall.UTF16FromString(filename)\n\tif err != nil {\n\t\treturn winInvalidHandleValue, fmt.Errorf(\"failed to convert driver filename to UTF16 string %w\", err)\n\t}\n\n\thandle, err := windows.CreateFile(&u16filename[0], windows.GENERIC_READ|windows.GENERIC_WRITE, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_OVERLAPPED, 0)\n\tif err != nil {\n\t\treturn winInvalidHandleValue, err\n\t}\n\n\treturn handle, nil\n}\n\nfunc closeDriver(handle windows.Handle) error {\n\tif kextHandle == winInvalidHandleValue {\n\t\treturn ErrKextNotReady\n\t}\n\n\treturn windows.CloseHandle(handle)\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext/packet.go",
    "content": "//go:build windows\n// +build windows\n\npackage windowskext\n\nimport (\n\t\"sync\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n// Packet represents an IP packet.\ntype Packet struct {\n\tpacket.Base\n\n\tverdictRequest *VerdictRequest\n\tverdictSet     *abool.AtomicBool\n\n\tpayloadLoaded bool\n\tlock          sync.Mutex\n}\n\n// FastTrackedByIntegration returns whether the packet has been fast-track\n// accepted by the OS integration.\nfunc (pkt *Packet) FastTrackedByIntegration() bool {\n\treturn pkt.verdictRequest.flags&VerdictRequestFlagFastTrackPermitted > 0\n}\n\n// InfoOnly returns whether the packet is informational only and does not\n// represent an actual packet.\nfunc (pkt *Packet) InfoOnly() bool {\n\treturn pkt.verdictRequest.flags&VerdictRequestFlagSocketAuth > 0\n}\n\n// ExpectInfo returns whether the next packet is expected to be informational only.\nfunc (pkt *Packet) ExpectInfo() bool {\n\treturn pkt.verdictRequest.flags&VerdictRequestFlagExpectSocketAuth > 0\n}\n\n// GetPayload returns the full raw packet.\nfunc (pkt *Packet) LoadPacketData() error {\n\tpkt.lock.Lock()\n\tdefer pkt.lock.Unlock()\n\n\tif pkt.verdictRequest.id == 0 {\n\t\treturn ErrNoPacketID\n\t}\n\n\tif !pkt.payloadLoaded {\n\t\tpkt.payloadLoaded = true\n\n\t\tpayload, err := GetPayload(pkt.verdictRequest.id, pkt.verdictRequest.packetSize)\n\t\tif err != nil {\n\t\t\tlog.Tracer(pkt.Ctx()).Warningf(\"windowskext: failed to load payload: %s\", err)\n\t\t\treturn packet.ErrFailedToLoadPayload\n\t\t}\n\n\t\terr = packet.ParseLayer3(payload, &pkt.Base)\n\t\tif err != nil {\n\t\t\tlog.Tracer(pkt.Ctx()).Warningf(\"windowskext: failed to parse payload: %s\", err)\n\t\t\treturn packet.ErrFailedToLoadPayload\n\t\t}\n\t}\n\n\tif len(pkt.Raw()) == 0 {\n\t\treturn packet.ErrFailedToLoadPayload\n\t}\n\treturn nil\n}\n\n// Accept accepts the packet.\nfunc (pkt *Packet) Accept() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, -network.VerdictAccept)\n\t}\n\treturn nil\n}\n\n// Block blocks the packet.\nfunc (pkt *Packet) Block() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, -network.VerdictBlock)\n\t}\n\treturn nil\n}\n\n// Drop drops the packet.\nfunc (pkt *Packet) Drop() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, -network.VerdictDrop)\n\t}\n\treturn nil\n}\n\n// PermanentAccept permanently accepts connection (and the current packet).\nfunc (pkt *Packet) PermanentAccept() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, network.VerdictAccept)\n\t}\n\treturn nil\n}\n\n// PermanentBlock permanently blocks connection (and the current packet).\nfunc (pkt *Packet) PermanentBlock() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, network.VerdictBlock)\n\t}\n\treturn nil\n}\n\n// PermanentDrop permanently drops connection (and the current packet).\nfunc (pkt *Packet) PermanentDrop() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, network.VerdictDrop)\n\t}\n\treturn nil\n}\n\n// RerouteToNameserver permanently reroutes the connection to the local nameserver (and the current packet).\nfunc (pkt *Packet) RerouteToNameserver() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, network.VerdictRerouteToNameserver)\n\t}\n\treturn nil\n}\n\n// RerouteToTunnel permanently reroutes the connection to the local tunnel entrypoint (and the current packet).\nfunc (pkt *Packet) RerouteToTunnel() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, network.VerdictRerouteToTunnel)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext/service.go",
    "content": "//go:build windows\r\n// +build windows\r\n\r\npackage windowskext\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"syscall\"\r\n\t\"time\"\r\n\r\n\t\"github.com/safing/portmaster/base/log\"\r\n\t\"golang.org/x/sys/windows\"\r\n)\r\n\r\ntype KextService struct {\r\n\thandle windows.Handle\r\n}\r\n\r\nfunc createKextService(driverName string, driverPath string) (*KextService, error) {\r\n\t// Open the service manager:\r\n\tmanager, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_ALL_ACCESS)\r\n\tif err != nil {\r\n\t\treturn nil, fmt.Errorf(\"failed to open service manager: %d\", err)\r\n\t}\r\n\tdefer windows.CloseServiceHandle(manager)\r\n\r\n\t// Convert the driver name to a UTF16 string\r\n\tdriverNameU16, err := syscall.UTF16FromString(driverName)\r\n\tif err != nil {\r\n\t\treturn nil, fmt.Errorf(\"failed to convert driver name to UTF16 string: %w\", err)\r\n\t}\r\n\r\n\t// Check if there is an old service.\r\n\tservice, err := windows.OpenService(manager, &driverNameU16[0], windows.SERVICE_ALL_ACCESS)\r\n\tif err == nil {\r\n\t\tlog.Warning(\"kext: old driver service was found\")\r\n\t\toldService := &KextService{handle: service}\r\n\t\terr := deleteService(manager, oldService, driverNameU16)\r\n\t\tif err != nil {\r\n\t\t\treturn nil, fmt.Errorf(\"failed to delete old driver service: %s\", err)\r\n\t\t}\r\n\r\n\t\tservice = winInvalidHandleValue\r\n\t\tlog.Info(\"kext: old driver service was deleted successfully\")\r\n\t}\r\n\r\n\tdriverPathU16, err := syscall.UTF16FromString(driverPath)\r\n\r\n\t// Create the service\r\n\tservice, err = windows.CreateService(manager, &driverNameU16[0], &driverNameU16[0], windows.SERVICE_ALL_ACCESS, windows.SERVICE_KERNEL_DRIVER, windows.SERVICE_DEMAND_START, windows.SERVICE_ERROR_NORMAL, &driverPathU16[0], nil, nil, nil, nil, nil)\r\n\tif err != nil {\r\n\t\treturn nil, err\r\n\t}\r\n\r\n\treturn &KextService{handle: service}, nil\r\n}\r\n\r\nfunc deleteService(manager windows.Handle, service *KextService, driverName []uint16) error {\r\n\t// Stop and wait before deleting\r\n\t_ = service.stop(true)\r\n\r\n\t// Try to delete even if stop failed\r\n\terr := service.delete()\r\n\tif err != nil {\r\n\t\treturn fmt.Errorf(\"failed to delete old service: %s\", err)\r\n\t}\r\n\r\n\t// Wait until we can no longer open the old service.\r\n\t// Not very efficient but NotifyServiceStatusChange cannot be used with driver service.\r\n\tstart := time.Now()\r\n\ttimeLimit := time.Duration(30 * time.Second)\r\n\tfor {\r\n\t\thandle, err := windows.OpenService(manager, &driverName[0], windows.SERVICE_ALL_ACCESS)\r\n\t\tif err != nil {\r\n\t\t\tbreak\r\n\t\t}\r\n\t\t_ = windows.CloseServiceHandle(handle)\r\n\r\n\t\tif time.Since(start) > timeLimit {\r\n\t\t\treturn fmt.Errorf(\"time limit reached\")\r\n\t\t}\r\n\r\n\t\ttime.Sleep(100 * time.Millisecond)\r\n\t}\r\n\treturn nil\r\n}\r\n\r\nfunc (s *KextService) isValid() bool {\r\n\treturn s != nil && s.handle != winInvalidHandleValue && s.handle != 0\r\n}\r\n\r\nfunc (s *KextService) isRunning() (bool, error) {\r\n\tif !s.isValid() {\r\n\t\treturn false, fmt.Errorf(\"kext service not initialized\")\r\n\t}\r\n\tvar status windows.SERVICE_STATUS\r\n\terr := windows.QueryServiceStatus(s.handle, &status)\r\n\tif err != nil {\r\n\t\treturn false, err\r\n\t}\r\n\treturn status.CurrentState == windows.SERVICE_RUNNING, nil\r\n}\r\n\r\nfunc waitForServiceStatus(handle windows.Handle, neededStatus uint32, timeLimit time.Duration) (bool, error) {\r\n\tvar status windows.SERVICE_STATUS\r\n\tstatus.CurrentState = windows.SERVICE_NO_CHANGE\r\n\tstart := time.Now()\r\n\tfor status.CurrentState != neededStatus {\r\n\t\terr := windows.QueryServiceStatus(handle, &status)\r\n\t\tif err != nil {\r\n\t\t\treturn false, fmt.Errorf(\"failed while waiting for service to start: %w\", err)\r\n\t\t}\r\n\r\n\t\tif time.Since(start) > timeLimit {\r\n\t\t\treturn false, fmt.Errorf(\"time limit reached\")\r\n\t\t}\r\n\r\n\t\t// Sleep for 1/10 of the wait hint, recommended time from microsoft\r\n\t\ttime.Sleep(time.Duration((status.WaitHint / 10)) * time.Millisecond)\r\n\t}\r\n\r\n\treturn true, nil\r\n}\r\n\r\nfunc (s *KextService) start(wait bool) error {\r\n\tif !s.isValid() {\r\n\t\treturn fmt.Errorf(\"kext service not initialized\")\r\n\t}\r\n\r\n\t// Start the service:\r\n\terr := windows.StartService(s.handle, 0, nil)\r\n\r\n\tif err != nil {\r\n\t\terr = windows.GetLastError()\r\n\t\tif err != windows.ERROR_SERVICE_ALREADY_RUNNING {\r\n\t\t\t// Failed to start service; clean-up:\r\n\t\t\tvar status windows.SERVICE_STATUS\r\n\t\t\t_ = windows.ControlService(s.handle, windows.SERVICE_CONTROL_STOP, &status)\r\n\t\t\t_ = windows.DeleteService(s.handle)\r\n\t\t\t_ = windows.CloseServiceHandle(s.handle)\r\n\t\t\ts.handle = winInvalidHandleValue\r\n\t\t\treturn err\r\n\t\t}\r\n\t}\r\n\r\n\t// Wait for service to start\r\n\tif wait {\r\n\t\tsuccess, err := waitForServiceStatus(s.handle, windows.SERVICE_RUNNING, time.Duration(10*time.Second))\r\n\t\tif err != nil || !success {\r\n\t\t\treturn fmt.Errorf(\"service did not start: %w\", err)\r\n\t\t}\r\n\t}\r\n\r\n\treturn nil\r\n}\r\n\r\nfunc (s *KextService) stop(wait bool) error {\r\n\tif !s.isValid() {\r\n\t\treturn fmt.Errorf(\"kext service not initialized\")\r\n\t}\r\n\r\n\t// Stop the service\r\n\tvar status windows.SERVICE_STATUS\r\n\terr := windows.ControlService(s.handle, windows.SERVICE_CONTROL_STOP, &status)\r\n\tif err != nil {\r\n\t\treturn fmt.Errorf(\"service failed to stop: %w\", err)\r\n\t}\r\n\r\n\t// Wait for service to stop\r\n\tif wait {\r\n\t\tsuccess, err := waitForServiceStatus(s.handle, windows.SERVICE_STOPPED, time.Duration(10*time.Second))\r\n\t\tif err != nil || !success {\r\n\t\t\treturn fmt.Errorf(\"service did not stop: %w\", err)\r\n\t\t}\r\n\t}\r\n\r\n\treturn nil\r\n}\r\n\r\nfunc (s *KextService) delete() error {\r\n\tif !s.isValid() {\r\n\t\treturn fmt.Errorf(\"kext service not initialized\")\r\n\t}\r\n\r\n\terr := windows.DeleteService(s.handle)\r\n\tif err != nil {\r\n\t\treturn fmt.Errorf(\"failed to delete service: %s\", err)\r\n\t}\r\n\r\n\t// Service wont be deleted until all handles are closed.\r\n\terr = windows.CloseServiceHandle(s.handle)\r\n\tif err != nil {\r\n\t\treturn fmt.Errorf(\"failed to close service handle: %s\", err)\r\n\t}\r\n\r\n\ts.handle = winInvalidHandleValue\r\n\treturn nil\r\n}\r\n"
  },
  {
    "path": "service/firewall/interception/windowskext/syscall.go",
    "content": "//go:build windows\r\n// +build windows\r\n\r\npackage windowskext\r\n\r\nimport \"golang.org/x/sys/windows\"\r\n\r\nconst (\r\n\tMETHOD_BUFFERED   = 0\r\n\tMETHOD_IN_DIRECT  = 1\r\n\tMETHOD_OUT_DIRECT = 2\r\n\tMETHOD_NEITHER    = 3\r\n\r\n\tSIOCTL_TYPE = 40000\r\n)\r\n\nvar (\n\tIOCTL_VERSION              = ctlCode(SIOCTL_TYPE, 0x800, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_SHUTDOWN_REQUEST     = ctlCode(SIOCTL_TYPE, 0x801, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_RECV_VERDICT_REQ     = ctlCode(SIOCTL_TYPE, 0x802, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_SET_VERDICT          = ctlCode(SIOCTL_TYPE, 0x803, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_GET_PAYLOAD          = ctlCode(SIOCTL_TYPE, 0x804, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_CLEAR_CACHE          = ctlCode(SIOCTL_TYPE, 0x805, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_UPDATE_VERDICT       = ctlCode(SIOCTL_TYPE, 0x806, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_GET_CONNECTIONS_STAT = ctlCode(SIOCTL_TYPE, 0x807, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n)\n\nfunc ctlCode(device_type, function, method, access uint32) uint32 {\n\treturn (device_type << 16) | (access << 14) | (function << 2) | method\n}\n\nfunc deviceIOControlAsync(handle windows.Handle, code uint32, inData []byte, outData []byte) (*windows.Overlapped, error) {\n\tvar inDataPtr *byte = nil\n\tvar inDataSize uint32 = 0\n\tif inData != nil {\n\t\tinDataPtr = &inData[0]\n\t\tinDataSize = uint32(len(inData))\n\t}\n\n\tvar outDataPtr *byte = nil\n\tvar outDataSize uint32 = 0\n\tif outData != nil {\n\t\toutDataPtr = &outData[0]\n\t\toutDataSize = uint32(len(outData))\n\t}\n\n\toverlapped := &windows.Overlapped{}\n\terr := windows.DeviceIoControl(handle,\n\t\tcode,\n\t\tinDataPtr, inDataSize,\n\t\toutDataPtr, outDataSize,\n\t\tnil, overlapped)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\r\n\treturn overlapped, nil\r\n\r\n}\r\n\r\nfunc deviceIOControl(handle windows.Handle, code uint32, inData []byte, outData []byte) (uint32, error) {\r\n\toverlapped, err := deviceIOControlAsync(handle, code, inData, outData)\r\n\tif err != nil {\r\n\t\treturn 0, err\r\n\t}\r\n\r\n\tvar bytesReturned uint32\r\n\terr = windows.GetOverlappedResult(handle, overlapped, &bytesReturned, true)\r\n\r\n\treturn bytesReturned, err\r\n}\r\n"
  },
  {
    "path": "service/firewall/interception/windowskext2/doc.go",
    "content": "// +build windows\n\n// Package windowskext provides network interception capabilities on windows via the Portmaster Kernel Extension.\npackage windowskext\n"
  },
  {
    "path": "service/firewall/interception/windowskext2/handler.go",
    "content": "//go:build windows\n// +build windows\n\npackage windowskext\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/windows_kext/kextinterface\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\ntype VersionInfo struct {\n\tMajor    uint8\n\tMinor    uint8\n\tRevision uint8\n\tBuild    uint8\n}\n\nfunc (v *VersionInfo) String() string {\n\treturn fmt.Sprintf(\"%d.%d.%d.%d\", v.Major, v.Minor, v.Revision, v.Build)\n}\n\n// Handler transforms received packets to the Packet interface.\nfunc Handler(ctx context.Context, packets chan packet.Packet, bandwidthUpdate chan *packet.BandwidthUpdate) {\n\tfor {\n\t\tpacketInfo, err := RecvVerdictRequest()\n\n\t\tif errors.Is(err, kextinterface.ErrUnexpectedInfoSize) || errors.Is(err, kextinterface.ErrUnexpectedReadError) {\n\t\t\tlog.Criticalf(\"unexpected kext info data: %s\", err)\n\t\t\tcontinue // Depending on the info type this may not affect the functionality. Try to continue reading the next commands.\n\t\t}\n\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"failed to get packet from windows kext: %s\", err)\n\t\t\t// Probably IO error, nothing else we can do.\n\t\t\treturn\n\t\t}\n\n\t\tswitch {\n\t\tcase packetInfo.ConnectionV4 != nil:\n\t\t\t{\n\t\t\t\t// log.Tracef(\"packet: %+v\", packetInfo.ConnectionV4)\n\t\t\t\tconn := packetInfo.ConnectionV4\n\t\t\t\t// New Packet\n\t\t\t\tnewPacket := &Packet{\n\t\t\t\t\tverdictRequest: conn.ID,\n\t\t\t\t\tpayload:        conn.Payload,\n\t\t\t\t\tpayloadLayer:   conn.PayloadLayer,\n\t\t\t\t\tverdictSet:     abool.NewBool(false),\n\t\t\t\t}\n\t\t\t\tinfo := newPacket.Info()\n\t\t\t\tinfo.Inbound = conn.Direction > 0\n\t\t\t\tinfo.InTunnel = false\n\t\t\t\tinfo.Protocol = packet.IPProtocol(conn.Protocol)\n\t\t\t\tinfo.PID = int(conn.ProcessID)\n\t\t\t\tinfo.SeenAt = time.Now()\n\n\t\t\t\t// Check PID\n\t\t\t\tif info.PID == 0 {\n\t\t\t\t\t// Windows does not have zero PIDs.\n\t\t\t\t\t// Set to UndefinedProcessID.\n\t\t\t\t\tinfo.PID = process.UndefinedProcessID\n\t\t\t\t}\n\n\t\t\t\t// Set IP version\n\t\t\t\tinfo.Version = packet.IPv4\n\n\t\t\t\t// Set IPs\n\t\t\t\tif info.Inbound {\n\t\t\t\t\t// Inbound\n\t\t\t\t\tinfo.Src = conn.RemoteIP[:]\n\t\t\t\t\tinfo.Dst = conn.LocalIP[:]\n\t\t\t\t} else {\n\t\t\t\t\t// Outbound\n\t\t\t\t\tinfo.Src = conn.LocalIP[:]\n\t\t\t\t\tinfo.Dst = conn.RemoteIP[:]\n\t\t\t\t}\n\n\t\t\t\t// Set Ports\n\t\t\t\tif info.Inbound {\n\t\t\t\t\t// Inbound\n\t\t\t\t\tinfo.SrcPort = conn.RemotePort\n\t\t\t\t\tinfo.DstPort = conn.LocalPort\n\t\t\t\t} else {\n\t\t\t\t\t// Outbound\n\t\t\t\t\tinfo.SrcPort = conn.LocalPort\n\t\t\t\t\tinfo.DstPort = conn.RemotePort\n\t\t\t\t}\n\n\t\t\t\tpackets <- newPacket\n\t\t\t}\n\t\tcase packetInfo.ConnectionV6 != nil:\n\t\t\t{\n\t\t\t\t// log.Tracef(\"packet: %+v\", packetInfo.ConnectionV6)\n\t\t\t\tconn := packetInfo.ConnectionV6\n\t\t\t\t// New Packet\n\t\t\t\tnewPacket := &Packet{\n\t\t\t\t\tverdictRequest: conn.ID,\n\t\t\t\t\tpayload:        conn.Payload,\n\t\t\t\t\tpayloadLayer:   conn.PayloadLayer,\n\t\t\t\t\tverdictSet:     abool.NewBool(false),\n\t\t\t\t}\n\t\t\t\tinfo := newPacket.Info()\n\t\t\t\tinfo.Inbound = conn.Direction > 0\n\t\t\t\tinfo.InTunnel = false\n\t\t\t\tinfo.Protocol = packet.IPProtocol(conn.Protocol)\n\t\t\t\tinfo.PID = int(conn.ProcessID)\n\t\t\t\tinfo.SeenAt = time.Now()\n\n\t\t\t\t// Check PID\n\t\t\t\tif info.PID == 0 {\n\t\t\t\t\t// Windows does not have zero PIDs.\n\t\t\t\t\t// Set to UndefinedProcessID.\n\t\t\t\t\tinfo.PID = process.UndefinedProcessID\n\t\t\t\t}\n\n\t\t\t\t// Set IP version\n\t\t\t\tinfo.Version = packet.IPv6\n\n\t\t\t\t// Set IPs\n\t\t\t\tif info.Inbound {\n\t\t\t\t\t// Inbound\n\t\t\t\t\tinfo.Src = conn.RemoteIP[:]\n\t\t\t\t\tinfo.Dst = conn.LocalIP[:]\n\t\t\t\t} else {\n\t\t\t\t\t// Outbound\n\t\t\t\t\tinfo.Src = conn.LocalIP[:]\n\t\t\t\t\tinfo.Dst = conn.RemoteIP[:]\n\t\t\t\t}\n\n\t\t\t\t// Set Ports\n\t\t\t\tif info.Inbound {\n\t\t\t\t\t// Inbound\n\t\t\t\t\tinfo.SrcPort = conn.RemotePort\n\t\t\t\t\tinfo.DstPort = conn.LocalPort\n\t\t\t\t} else {\n\t\t\t\t\t// Outbound\n\t\t\t\t\tinfo.SrcPort = conn.LocalPort\n\t\t\t\t\tinfo.DstPort = conn.RemotePort\n\t\t\t\t}\n\n\t\t\t\tpackets <- newPacket\n\t\t\t}\n\t\tcase packetInfo.LogLine != nil:\n\t\t\t{\n\t\t\t\tline := packetInfo.LogLine\n\t\t\t\tswitch line.Severity {\n\t\t\t\tcase byte(log.DebugLevel):\n\t\t\t\t\tlog.Debugf(\"kext: %s\", line.Line)\n\t\t\t\tcase byte(log.InfoLevel):\n\t\t\t\t\tlog.Infof(\"kext: %s\", line.Line)\n\t\t\t\tcase byte(log.WarningLevel):\n\t\t\t\t\tlog.Warningf(\"kext: %s\", line.Line)\n\t\t\t\tcase byte(log.ErrorLevel):\n\t\t\t\t\tlog.Errorf(\"kext: %s\", line.Line)\n\t\t\t\tcase byte(log.CriticalLevel):\n\t\t\t\t\tlog.Criticalf(\"kext: %s\", line.Line)\n\t\t\t\t}\n\t\t\t}\n\t\tcase packetInfo.BandwidthStats != nil:\n\t\t\t{\n\t\t\t\tbandwidthStats := packetInfo.BandwidthStats\n\t\t\t\tfor _, stat := range bandwidthStats.ValuesV4 {\n\t\t\t\t\tconnID := packet.CreateConnectionID(\n\t\t\t\t\t\tpacket.IPProtocol(bandwidthStats.Protocol),\n\t\t\t\t\t\tnet.IP(stat.LocalIP[:]), stat.LocalPort,\n\t\t\t\t\t\tnet.IP(stat.RemoteIP[:]), stat.RemotePort,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t)\n\t\t\t\t\tupdate := &packet.BandwidthUpdate{\n\t\t\t\t\t\tConnID:        connID,\n\t\t\t\t\t\tBytesReceived: stat.ReceivedBytes,\n\t\t\t\t\t\tBytesSent:     stat.TransmittedBytes,\n\t\t\t\t\t\tMethod:        packet.Additive,\n\t\t\t\t\t}\n\t\t\t\t\tbandwidthUpdate <- update\n\t\t\t\t}\n\t\t\t\tfor _, stat := range bandwidthStats.ValuesV6 {\n\t\t\t\t\tconnID := packet.CreateConnectionID(\n\t\t\t\t\t\tpacket.IPProtocol(bandwidthStats.Protocol),\n\t\t\t\t\t\tnet.IP(stat.LocalIP[:]), stat.LocalPort,\n\t\t\t\t\t\tnet.IP(stat.RemoteIP[:]), stat.RemotePort,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t)\n\t\t\t\t\tupdate := &packet.BandwidthUpdate{\n\t\t\t\t\t\tConnID:        connID,\n\t\t\t\t\t\tBytesReceived: stat.ReceivedBytes,\n\t\t\t\t\t\tBytesSent:     stat.TransmittedBytes,\n\t\t\t\t\t\tMethod:        packet.Additive,\n\t\t\t\t\t}\n\t\t\t\t\tbandwidthUpdate <- update\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext2/kext.go",
    "content": "//go:build windows\n// +build windows\n\npackage windowskext\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/windows_kext/kextinterface\"\n\t\"golang.org/x/sys/windows\"\n)\n\n// Package errors\nvar (\n\tdriverPath string\n\n\tservice  *kextinterface.KextService\n\tkextFile *kextinterface.KextFile\n)\n\nconst (\n\tdriverName = \"PortmasterKext\"\n)\n\nfunc Init(path string) error {\n\tdriverPath = path\n\treturn nil\n}\n\n// Start intercepting.\nfunc Start() error {\n\t// initialize and start driver service\n\tvar err error\n\tservice, err = kextinterface.CreateKextService(driverName, driverPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create service: %w\", err)\n\t}\n\n\t// Start service and open file\n\terr = service.Start(true)\n\tif err != nil {\n\t\tlog.Errorf(\"failed to start service: %s\", err)\n\t}\n\n\tkextFile, err = service.OpenFile(1024)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open driver: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc GetKextHandle() windows.Handle {\n\treturn kextFile.GetHandle()\n}\n\nfunc GetKextServiceHandle() windows.Handle {\n\treturn service.GetHandle()\n}\n\n// Stop intercepting.\nfunc Stop() error {\n\tif kextFile == nil {\n\t\treturn fmt.Errorf(\"kextfile is nil\")\n\t}\n\t// Prepare kernel for shutdown\n\terr := shutdownRequest()\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: shutdown request failed: %s\", err)\n\t}\n\t// Close the interface to the driver. Driver will continue to run.\n\terr = kextFile.Close()\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: failed to close kext file: %s\", err)\n\t}\n\n\t// Stop and delete the driver.\n\terr = service.Stop(true)\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: failed to stop kernel service: %s\", err)\n\t}\n\n\terr = service.Delete()\n\tif err != nil {\n\t\tlog.Warningf(\"winkext: failed to delete kernel service: %s\", err)\n\t}\n\treturn nil\n}\n\n// Sends a shutdown request.\nfunc shutdownRequest() error {\n\treturn kextinterface.SendShutdownCommand(kextFile)\n}\n\n// Send request for logs of the kext.\nfunc SendLogRequest() error {\n\treturn kextinterface.SendGetLogsCommand(kextFile)\n}\n\nfunc SendBandwidthStatsRequest() error {\n\treturn kextinterface.SendGetBandwidthStatsCommand(kextFile)\n}\n\nfunc SendPrintMemoryStatsCommand() error {\n\treturn kextinterface.SendPrintMemoryStatsCommand(kextFile)\n}\n\nfunc SendCleanEndedConnection() error {\n\treturn kextinterface.SendCleanEndedConnectionsCommand(kextFile)\n}\n\n// RecvVerdictRequest waits for the next verdict request from the kext. If a timeout is reached, both *VerdictRequest and error will be nil.\nfunc RecvVerdictRequest() (*kextinterface.Info, error) {\n\treturn kextinterface.RecvInfo(kextFile)\n}\n\n// SetVerdict sets the verdict for a packet and/or connection.\nfunc SetVerdict(pkt *Packet, verdict kextinterface.KextVerdict) error {\n\tverdictCommand := kextinterface.Verdict{ID: pkt.verdictRequest, Verdict: uint8(verdict)}\n\treturn kextinterface.SendVerdictCommand(kextFile, verdictCommand)\n}\n\n// Clears the internal connection cache.\nfunc ClearCache() error {\n\treturn kextinterface.SendClearCacheCommand(kextFile)\n}\n\n// Updates a specific connection verdict.\nfunc UpdateVerdict(conn *network.Connection) error {\n\tif conn.IPVersion == 4 {\n\t\tupdate := kextinterface.UpdateV4{\n\t\t\tProtocol:      conn.Entity.Protocol,\n\t\t\tLocalAddress:  [4]byte(conn.LocalIP),\n\t\t\tLocalPort:     conn.LocalPort,\n\t\t\tRemoteAddress: [4]byte(conn.Entity.IP),\n\t\t\tRemotePort:    conn.Entity.Port,\n\t\t\tVerdict:       uint8(getKextVerdictFromConnection(conn)),\n\t\t}\n\n\t\treturn kextinterface.SendUpdateV4Command(kextFile, update)\n\t} else if conn.IPVersion == 6 {\n\t\tupdate := kextinterface.UpdateV6{\n\t\t\tProtocol:      conn.Entity.Protocol,\n\t\t\tLocalAddress:  [16]byte(conn.LocalIP),\n\t\t\tLocalPort:     conn.LocalPort,\n\t\t\tRemoteAddress: [16]byte(conn.Entity.IP),\n\t\t\tRemotePort:    conn.Entity.Port,\n\t\t\tVerdict:       uint8(getKextVerdictFromConnection(conn)),\n\t\t}\n\n\t\treturn kextinterface.SendUpdateV6Command(kextFile, update)\n\t}\n\treturn nil\n}\n\nfunc getKextVerdictFromConnection(conn *network.Connection) kextinterface.KextVerdict {\n\tswitch conn.Verdict {\n\tcase network.VerdictUndecided:\n\t\treturn kextinterface.VerdictUndecided\n\tcase network.VerdictUndeterminable:\n\t\treturn kextinterface.VerdictUndeterminable\n\tcase network.VerdictAccept:\n\t\tif conn.VerdictPermanent {\n\t\t\treturn kextinterface.VerdictPermanentAccept\n\t\t} else {\n\t\t\treturn kextinterface.VerdictAccept\n\t\t}\n\tcase network.VerdictBlock:\n\t\tif conn.VerdictPermanent {\n\t\t\treturn kextinterface.VerdictPermanentBlock\n\t\t} else {\n\t\t\treturn kextinterface.VerdictBlock\n\t\t}\n\tcase network.VerdictDrop:\n\t\tif conn.VerdictPermanent {\n\t\t\treturn kextinterface.VerdictPermanentDrop\n\t\t} else {\n\t\t\treturn kextinterface.VerdictDrop\n\t\t}\n\tcase network.VerdictRerouteToNameserver:\n\t\treturn kextinterface.VerdictRerouteToNameserver\n\tcase network.VerdictRerouteToTunnel:\n\t\treturn kextinterface.VerdictRerouteToTunnel\n\tcase network.VerdictFailed:\n\t\treturn kextinterface.VerdictFailed\n\t}\n\treturn kextinterface.VerdictUndeterminable\n}\n\n// Returns the kext version.\nfunc GetVersion() (*VersionInfo, error) {\n\tdata, err := kextinterface.ReadVersion(kextFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tversion := &VersionInfo{\n\t\tMajor:    data[0],\n\t\tMinor:    data[1],\n\t\tRevision: data[2],\n\t\tBuild:    data[3],\n\t}\n\treturn version, nil\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext2/packet.go",
    "content": "//go:build windows\n// +build windows\n\npackage windowskext\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/windows_kext/kextinterface\"\n)\n\n// Packet represents an IP packet.\ntype Packet struct {\n\tpacket.Base\n\n\tverdictRequest uint64\n\tpayload        []byte\n\tpayloadLayer   uint8\n\tverdictSet     *abool.AtomicBool\n\n\tpayloadLoaded bool\n\tlock          sync.Mutex\n}\n\n// FastTrackedByIntegration returns whether the packet has been fast-track\n// accepted by the OS integration.\nfunc (pkt *Packet) FastTrackedByIntegration() bool {\n\treturn false\n}\n\n// InfoOnly returns whether the packet is informational only and does not\n// represent an actual packet.\nfunc (pkt *Packet) InfoOnly() bool {\n\treturn false\n}\n\n// ExpectInfo returns whether the next packet is expected to be informational only.\nfunc (pkt *Packet) ExpectInfo() bool {\n\treturn false\n}\n\n// GetPayload returns the full raw packet.\nfunc (pkt *Packet) LoadPacketData() error {\n\tpkt.lock.Lock()\n\tdefer pkt.lock.Unlock()\n\n\tif !pkt.payloadLoaded {\n\t\tpkt.payloadLoaded = true\n\n\t\tif len(pkt.payload) > 0 {\n\t\t\tvar err error\n\t\t\tswitch pkt.payloadLayer {\n\t\t\tcase 3:\n\t\t\t\terr = packet.ParseLayer3(pkt.payload, &pkt.Base)\n\t\t\tcase 4:\n\t\t\t\terr = packet.ParseLayer4(pkt.payload, &pkt.Base)\n\t\t\tdefault:\n\t\t\t\terr = fmt.Errorf(\"unsupported payload layer: %d\", pkt.payloadLayer)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tlog.Tracef(\"payload: %#v\", pkt.payload)\n\t\t\t\tlog.Tracer(pkt.Ctx()).Warningf(\"windowskext: failed to parse payload: %s\", err)\n\t\t\t\treturn packet.ErrFailedToLoadPayload\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(pkt.Raw()) == 0 {\n\t\treturn packet.ErrFailedToLoadPayload\n\t}\n\n\treturn nil\n}\n\n// Accept accepts the packet.\nfunc (pkt *Packet) Accept() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictAccept)\n\t}\n\treturn nil\n}\n\n// Block blocks the packet.\nfunc (pkt *Packet) Block() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictBlock)\n\t}\n\treturn nil\n}\n\n// Drop drops the packet.\nfunc (pkt *Packet) Drop() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictDrop)\n\t}\n\treturn nil\n}\n\n// PermanentAccept permanently accepts connection (and the current packet).\nfunc (pkt *Packet) PermanentAccept() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictPermanentAccept)\n\t}\n\treturn nil\n}\n\n// PermanentBlock permanently blocks connection (and the current packet).\nfunc (pkt *Packet) PermanentBlock() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictPermanentBlock)\n\t}\n\treturn nil\n}\n\n// PermanentDrop permanently drops connection (and the current packet).\nfunc (pkt *Packet) PermanentDrop() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictPermanentDrop)\n\t}\n\treturn nil\n}\n\n// RerouteToNameserver permanently reroutes the connection to the local nameserver (and the current packet).\nfunc (pkt *Packet) RerouteToNameserver() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictRerouteToNameserver)\n\t}\n\treturn nil\n}\n\n// RerouteToTunnel permanently reroutes the connection to the local tunnel entrypoint (and the current packet).\nfunc (pkt *Packet) RerouteToTunnel() error {\n\tif pkt.verdictSet.SetToIf(false, true) {\n\t\treturn SetVerdict(pkt, kextinterface.VerdictRerouteToTunnel)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/firewall/interception/windowskext2/service.go",
    "content": "//go:build windows\r\n// +build windows\r\n\r\npackage windowskext\r\n\nimport \"github.com/safing/portmaster/windows_kext/kextinterface\"\r\n\r\nfunc createKextService(driverName string, driverPath string) (*kextinterface.KextService, error) {\r\n\treturn kextinterface.CreateKextService(driverName, driverPath)\r\n}\n"
  },
  {
    "path": "service/firewall/master.go",
    "content": "package firewall\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/agext/levenshtein\"\n\t\"golang.org/x/net/publicsuffix\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/detection/dga\"\n\t\"github.com/safing/portmaster/service/intel/customlists\"\n\t\"github.com/safing/portmaster/service/intel/filterlists\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\nconst noReasonOptionKey = \"\"\n\ntype deciderFn func(context.Context, *network.Connection, *profile.LayeredProfile, packet.Packet) bool\n\nvar defaultDeciders = []deciderFn{\n\tcheckPortmasterConnection,\n\tcheckIfBroadcastReply,\n\tcheckConnectionType,\n\tcheckConnectionScope,\n\tcheckEndpointLists,\n\tcheckInvalidIP,\n\tcheckResolverScope,\n\tcheckConnectivityDomain,\n\tcheckBypassPrevention,\n\tcheckFilterLists,\n\tcheckCustomFilterList,\n\tcheckDomainHeuristics,\n\tcheckAutoPermitRelated,\n}\n\n// decideOnConnection makes a decision about a connection.\n// When called, the connection and profile is already locked.\nfunc decideOnConnection(ctx context.Context, conn *network.Connection, pkt packet.Packet) {\n\t// Check if we have a process and profile.\n\tlayeredProfile := conn.Process().Profile()\n\tif layeredProfile == nil {\n\t\tconn.Deny(\"unknown process or profile\", noReasonOptionKey)\n\t\treturn\n\t}\n\n\t// Check if the layered profile needs updating.\n\tif layeredProfile.NeedsUpdate() {\n\t\t// Update revision counter in connection.\n\t\tconn.ProfileRevisionCounter = layeredProfile.Update(\n\t\t\tconn.Process().MatchingData(),\n\t\t\tconn.Process().CreateProfileCallback,\n\t\t)\n\t\tconn.SaveWhenFinished()\n\n\t\t// Reset verdict for connection.\n\t\tlog.Tracer(ctx).Infof(\"filter: profile updated, re-evaluating verdict of %s\", conn)\n\n\t\t// Reset entity if it exists.\n\t\tif conn.Entity != nil {\n\t\t\tconn.Entity.ResetLists()\n\t\t}\n\t} else {\n\t\t// Check if the revision counter of the connection needs updating.\n\t\trevCnt := layeredProfile.RevisionCnt()\n\t\tif conn.ProfileRevisionCounter != revCnt {\n\t\t\tconn.ProfileRevisionCounter = revCnt\n\t\t\tconn.SaveWhenFinished()\n\t\t}\n\t}\n\n\t// prepare the entity and resolve all filterlist matches\n\tconn.Entity.ResolveSubDomainLists(ctx, layeredProfile.FilterSubDomains())\n\tconn.Entity.EnableCNAMECheck(ctx, layeredProfile.FilterCNAMEs())\n\tconn.Entity.LoadLists(ctx)\n\n\t// Run all deciders and return if they came to a conclusion.\n\tdone, defaultAction := runDeciders(ctx, defaultDeciders, conn, layeredProfile, pkt)\n\tif done {\n\t\treturn\n\t}\n\n\t// DNS Request are always default allowed, as the endpoint lists could not\n\t// be checked fully.\n\tif conn.Type == network.DNSRequest {\n\t\tconn.Accept(\"allowing dns request\", noReasonOptionKey)\n\t\treturn\n\t}\n\n\t// Deciders did not conclude, use default action.\n\tswitch defaultAction {\n\tcase profile.DefaultActionPermit:\n\t\tconn.Accept(\"allowed by default action\", profile.CfgOptionDefaultActionKey)\n\tcase profile.DefaultActionAsk:\n\t\t// Only prompt if there has not been a decision already.\n\t\t// This prevents prompts from being created when re-evaluating connections.\n\t\tif conn.Verdict == network.VerdictUndecided {\n\t\t\tprompt(ctx, conn)\n\t\t}\n\tdefault:\n\t\tconn.Deny(\"blocked by default action\", profile.CfgOptionDefaultActionKey)\n\t}\n}\n\nfunc runDeciders(ctx context.Context, selectedDeciders []deciderFn, conn *network.Connection, layeredProfile *profile.LayeredProfile, pkt packet.Packet) (done bool, defaultAction uint8) {\n\t// Read-lock all the profiles.\n\tlayeredProfile.LockForUsage()\n\tdefer layeredProfile.UnlockForUsage()\n\n\t// Go though all deciders, return if one sets an action.\n\tfor _, decider := range selectedDeciders {\n\t\tif decider(ctx, conn, layeredProfile, pkt) {\n\t\t\treturn true, profile.DefaultActionNotSet\n\t\t}\n\t}\n\n\t// Return the default action.\n\treturn false, layeredProfile.DefaultAction()\n}\n\n// checkPortmasterConnection allows all connection that originate from\n// portmaster itself.\nfunc checkPortmasterConnection(ctx context.Context, conn *network.Connection, _ *profile.LayeredProfile, _ packet.Packet) bool {\n\t// Grant own outgoing or local connections.\n\n\t// Blocking our own connections can lead to a very literal deadlock.\n\t// This can currently happen, as fast-tracked connections are also\n\t// reset in the OS integration and might show up in the connection\n\t// handling if a packet in the other direction hits the firewall first.\n\n\t// Ignore other processes.\n\tif conn.Process().Pid != ownPID {\n\t\treturn false\n\t}\n\n\t// Ignore inbound connection if non-local.\n\tif conn.Inbound {\n\t\tmyIP, err := netenv.IsMyIP(conn.Entity.IP)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Debugf(\"filter: failed to check if %s is own IP for granting own connection: %s\", conn.Entity.IP, err)\n\t\t\treturn false\n\t\t}\n\t\tif !myIP {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tlog.Tracer(ctx).Infof(\"filter: granting own connection %s\", conn)\n\tconn.Accept(\"connection by Portmaster\", noReasonOptionKey)\n\tconn.Internal = true\n\treturn true\n}\n\nfunc checkIfBroadcastReply(ctx context.Context, conn *network.Connection, _ *profile.LayeredProfile, _ packet.Packet) bool {\n\t// Only check inbound connections.\n\tif !conn.Inbound {\n\t\treturn false\n\t}\n\t// Only check if the process has been identified.\n\tif !conn.Process().IsIdentified() {\n\t\treturn false\n\t}\n\n\t// Check if the remote IP is part of a local network.\n\tlocalNet, err := netenv.GetLocalNetwork(conn.Entity.IP)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Warningf(\"filter: failed to get local network: %s\", err)\n\t\treturn false\n\t}\n\tif localNet == nil {\n\t\treturn false\n\t}\n\n\t// Search for a matching requesting connection.\n\trequestingConn := network.GetMulticastRequestConn(conn, localNet)\n\tif requestingConn == nil {\n\t\treturn false\n\t}\n\n\tconn.Accept(\n\t\tfmt.Sprintf(\n\t\t\t\"response to multi/broadcast query to %s/%s\",\n\t\t\tpacket.IPProtocol(requestingConn.Entity.Protocol),\n\t\t\tnet.JoinHostPort(\n\t\t\t\trequestingConn.Entity.IP.String(),\n\t\t\t\tstrconv.Itoa(int(requestingConn.Entity.Port)),\n\t\t\t),\n\t\t),\n\t\t\"\",\n\t)\n\treturn true\n}\n\nfunc checkEndpointLists(ctx context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// DNS request from the system resolver require a special decision process,\n\t// because the original requesting process is not known. Here, we only check\n\t// global-only and the most important per-app aspects. The resulting\n\t// connection is then blocked when the original requesting process is known.\n\tif conn.Type == network.DNSRequest && conn.Process().IsSystemResolver() {\n\t\treturn checkEndpointListsForSystemResolverDNSRequests(ctx, conn, p)\n\t}\n\n\tvar result endpoints.EPResult\n\tvar reason endpoints.Reason\n\n\t// check endpoints list\n\tvar optionKey string\n\tif conn.Inbound {\n\t\tresult, reason = p.MatchServiceEndpoint(ctx, conn.Entity)\n\t\toptionKey = profile.CfgOptionServiceEndpointsKey\n\t} else {\n\t\tresult, reason = p.MatchEndpoint(ctx, conn.Entity)\n\t\toptionKey = profile.CfgOptionEndpointsKey\n\t}\n\tswitch result {\n\tcase endpoints.Denied, endpoints.MatchError:\n\t\tconn.DenyWithContext(reason.String(), optionKey, reason.Context())\n\t\treturn true\n\tcase endpoints.Permitted:\n\t\tconn.AcceptWithContext(reason.String(), optionKey, reason.Context())\n\t\treturn true\n\tcase endpoints.NoMatch:\n\t\treturn false\n\t}\n\n\treturn false\n}\n\n// checkEndpointListsForSystemResolverDNSRequests is a special version of\n// checkEndpointLists that is only meant for DNS queries by the system\n// resolver. It only checks the endpoint filter list of the local profile and\n// does not include the global profile.\nfunc checkEndpointListsForSystemResolverDNSRequests(ctx context.Context, conn *network.Connection, p *profile.LayeredProfile) bool {\n\tvar profileEndpoints endpoints.Endpoints\n\tvar optionKey string\n\tif conn.Inbound {\n\t\tprofileEndpoints = p.LocalProfileWithoutLocking().GetServiceEndpoints()\n\t\toptionKey = profile.CfgOptionServiceEndpointsKey\n\t} else {\n\t\tprofileEndpoints = p.LocalProfileWithoutLocking().GetEndpoints()\n\t\toptionKey = profile.CfgOptionEndpointsKey\n\t}\n\n\tif profileEndpoints.IsSet() {\n\t\tresult, reason := profileEndpoints.Match(ctx, conn.Entity)\n\t\tif endpoints.IsDecision(result) {\n\t\t\tswitch result {\n\t\t\tcase endpoints.Denied, endpoints.MatchError:\n\t\t\t\tconn.DenyWithContext(reason.String(), optionKey, reason.Context())\n\t\t\t\treturn true\n\t\t\tcase endpoints.Permitted:\n\t\t\t\tconn.AcceptWithContext(reason.String(), optionKey, reason.Context())\n\t\t\t\treturn true\n\t\t\tcase endpoints.NoMatch:\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\nvar p2pFilterLists = []string{\"17-P2P\"}\n\nfunc checkConnectionType(ctx context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\tswitch {\n\t// Block incoming connection, if not from localhost.\n\tcase p.BlockInbound() && conn.Inbound &&\n\t\t!conn.Entity.IPScope.IsLocalhost():\n\t\tconn.Drop(\"inbound connections blocked\", profile.CfgOptionBlockInboundKey)\n\t\treturn true\n\n\t\t// Check for P2P and related connections.\n\tcase p.BlockP2P() && !conn.Inbound:\n\t\tswitch {\n\t\t// Block anything that is in the P2P filter list.\n\t\tcase conn.Entity.MatchLists(p2pFilterLists):\n\t\t\tconn.Block(\"P2P assistive infrastructure blocked based on filter list\", profile.CfgOptionBlockP2PKey)\n\t\t\treturn true\n\n\t\t\t// Remaining P2P deciders only apply to IP connections.\n\t\tcase conn.Type != network.IPConnection:\n\t\t\treturn false\n\n\t\t\t// Block well known ports of P2P assistive infrastructure.\n\t\tcase conn.Entity.DstPort() == 3478 || // STUN/TURN\n\t\t\tconn.Entity.DstPort() == 5349: // STUN/TURN over TLS/DTLS\n\t\t\tconn.Block(\"P2P assistive infrastructure blocked based on port\", profile.CfgOptionBlockP2PKey)\n\t\t\treturn true\n\n\t\t\t// Block direct connections with not previous DNS request.\n\t\tcase conn.Entity.IPScope.IsGlobal() &&\n\t\t\tconn.Entity.Domain == \"\":\n\t\t\tconn.Block(\"direct connections (P2P) blocked\", profile.CfgOptionBlockP2PKey)\n\t\t\treturn true\n\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc checkConnectivityDomain(_ context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\tswitch {\n\tcase conn.Entity.Domain == \"\":\n\t\t// Only applies if a domain is available.\n\t\treturn false\n\n\tcase netenv.GetOnlineStatus() > netenv.StatusPortal:\n\t\t// Special grant only applies if network status is Portal (or even more limited).\n\t\treturn false\n\n\tcase conn.Inbound:\n\t\t// Special grant only applies to outgoing connections.\n\t\treturn false\n\n\tcase p.BlockScopeInternet():\n\t\t// Special grant only applies if application is allowed to connect to the Internet.\n\t\treturn false\n\n\tcase netenv.IsConnectivityDomain(conn.Entity.Domain):\n\t\t// Special grant!\n\t\tconn.Accept(\"special grant for connectivity domain during network bootstrap\", noReasonOptionKey)\n\t\treturn true\n\n\tdefault:\n\t\t// Not a special grant domain\n\t\treturn false\n\t}\n}\n\nfunc checkConnectionScope(_ context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// If we are handling a DNS request, check if we can immediately block it.\n\tif conn.Type == network.DNSRequest {\n\t\t// DNS is expected to resolve to LAN or Internet addresses.\n\t\t// Localhost queries are immediately responded to by the nameserver.\n\t\tif p.BlockScopeInternet() && p.BlockScopeLAN() {\n\t\t\tconn.Block(\"Internet and LAN access blocked\", profile.CfgOptionBlockScopeInternetKey)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}\n\n\t// Check if the network scope is permitted.\n\tswitch conn.Entity.IPScope {\n\tcase netutils.Global, netutils.GlobalMulticast:\n\t\tif p.BlockScopeInternet() {\n\t\t\tconn.Deny(\"Internet access blocked\", profile.CfgOptionBlockScopeInternetKey) // Block Outbound / Drop Inbound\n\t\t\treturn true\n\t\t}\n\tcase netutils.SiteLocal, netutils.LinkLocal, netutils.LocalMulticast:\n\t\tif p.BlockScopeLAN() {\n\t\t\tconn.Block(\"LAN access blocked\", profile.CfgOptionBlockScopeLANKey) // Block Outbound / Drop Inbound\n\t\t\treturn true\n\t\t}\n\tcase netutils.HostLocal:\n\t\tif p.BlockScopeLocal() {\n\t\t\tconn.Block(\"Localhost access blocked\", profile.CfgOptionBlockScopeLocalKey) // Block Outbound / Drop Inbound\n\t\t\treturn true\n\t\t}\n\tcase netutils.Undefined, netutils.Invalid:\n\t\t// Block Invalid / Undefined IPs _after_ the rules.\n\t\treturn false\n\tdefault:\n\t\tconn.Deny(\"invalid IP\", noReasonOptionKey) // Block Outbound / Drop Inbound\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc checkInvalidIP(_ context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// Only applies to IP connections.\n\tif conn.Type != network.IPConnection {\n\t\treturn false\n\t}\n\n\t// Block Invalid / Undefined IPs.\n\tswitch conn.Entity.IPScope { //nolint:exhaustive // Only looking for specific values.\n\tcase netutils.Undefined, netutils.Invalid:\n\t\tconn.Deny(\"invalid IP\", noReasonOptionKey) // Block Outbound / Drop Inbound\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc checkBypassPrevention(ctx context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\tif p.PreventBypassing() {\n\t\t// check for bypass protection\n\t\tresult, reason, reasonCtx := PreventBypassing(ctx, conn)\n\t\tswitch result {\n\t\tcase endpoints.Denied, endpoints.MatchError:\n\t\t\t// Also block on MatchError to be on the safe side.\n\t\t\t// PreventBypassing does not use any data that needs to be loaded, so it should not fail anyway.\n\t\t\tconn.BlockWithContext(\"bypass prevention: \"+reason, profile.CfgOptionPreventBypassingKey, reasonCtx)\n\t\t\treturn true\n\t\tcase endpoints.Permitted:\n\t\t\tconn.AcceptWithContext(\"bypass prevention: \"+reason, profile.CfgOptionPreventBypassingKey, reasonCtx)\n\t\t\treturn true\n\t\tcase endpoints.NoMatch:\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc checkFilterLists(ctx context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// apply privacy filter lists\n\tresult, reason := p.MatchFilterLists(ctx, conn.Entity)\n\tswitch result {\n\tcase endpoints.Denied:\n\t\t// If the connection matches a filter list, check if the \"unbreak\" list matches too and abort blocking.\n\t\tresolvedUnbreakFilterListIDs := filterlists.GetUnbreakFilterListIDs()\n\t\tfor _, blockedListID := range conn.Entity.BlockedByLists {\n\t\t\tfor _, unbreakListID := range resolvedUnbreakFilterListIDs {\n\t\t\t\tif blockedListID == unbreakListID {\n\t\t\t\t\tlog.Tracer(ctx).Debugf(\"filter: unbreak filter %s matched, ignoring other filter list matches\", unbreakListID)\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Otherwise, continue with blocking.\n\t\tconn.DenyWithContext(reason.String(), profile.CfgOptionFilterListsKey, reason.Context())\n\t\treturn true\n\tcase endpoints.NoMatch:\n\t\t// nothing to do\n\tcase endpoints.Permitted, endpoints.MatchError:\n\t\tfallthrough\n\tdefault:\n\t\tlog.Tracer(ctx).Debugf(\"filter: filter lists returned unsupported verdict: %s\", result)\n\t}\n\treturn false\n}\n\nfunc checkResolverScope(_ context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// If the IP address was resolved, check the scope of the resolver.\n\tswitch {\n\tcase conn.Type != network.IPConnection:\n\t\t// Only applies to IP connections.\n\tcase !p.RemoveOutOfScopeDNS():\n\t\t// Out of scope checking is not active.\n\tcase conn.Resolver == nil:\n\t\t// IP address of connection was not resolved.\n\tcase conn.Resolver.IPScope.IsGlobal() &&\n\t\t(conn.Entity.IPScope.IsLAN() || conn.Entity.IPScope.IsLocalhost()):\n\t\t// Block global resolvers from returning LAN/Localhost IPs.\n\t\tconn.Block(\"DNS server horizon violation: global DNS server returned local IP address\", profile.CfgOptionRemoveOutOfScopeDNSKey)\n\t\treturn true\n\tcase conn.Resolver.IPScope.IsLAN() &&\n\t\tconn.Entity.IPScope.IsLocalhost():\n\t\t// Block LAN resolvers from returning Localhost IPs.\n\t\tconn.Block(\"DNS server horizon violation: LAN DNS server returned localhost IP address\", profile.CfgOptionRemoveOutOfScopeDNSKey)\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc checkDomainHeuristics(ctx context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// Don't check domain heuristics if no domain is available.\n\tif conn.Entity.Domain == \"\" {\n\t\treturn false\n\t}\n\n\t// Check if domain heuristics are enabled.\n\tif !p.DomainHeuristics() {\n\t\treturn false\n\t}\n\n\ttrimmedDomain := strings.TrimRight(conn.Entity.Domain, \".\")\n\tetld1, err := publicsuffix.EffectiveTLDPlusOne(trimmedDomain)\n\tif err != nil {\n\t\t// Don't run the check if the domain is a TLD.\n\t\treturn false\n\t}\n\n\tdomainToCheck := strings.Split(etld1, \".\")[0]\n\tscore := dga.LmsScore(domainToCheck)\n\tif score < 5 {\n\t\tlog.Tracer(ctx).Debugf(\n\t\t\t\"filter: possible data tunnel by %s in eTLD+1 %s: %s has an lms score of %.2f\",\n\t\t\tconn.Process(),\n\t\t\tetld1,\n\t\t\tdomainToCheck,\n\t\t\tscore,\n\t\t)\n\t\tconn.Block(\"possible DGA domain commonly used by malware\", profile.CfgOptionDomainHeuristicsKey)\n\t\treturn true\n\t}\n\tlog.Tracer(ctx).Tracef(\"filter: LMS score of eTLD+1 %s is %.2f\", etld1, score)\n\n\t// 100 is a somewhat arbitrary threshold to ensure we don't mess\n\t// around with CDN domain names to early. They use short second-level\n\t// domains that would trigger LMS checks but are to small to actually\n\t// exfiltrate data.\n\tif len(conn.Entity.Domain) > len(etld1)+100 {\n\t\tdomainToCheck = trimmedDomain[0:len(etld1)]\n\t\tscore := dga.LmsScoreOfDomain(domainToCheck)\n\t\tif score < 10 {\n\t\t\tlog.Tracer(ctx).Debugf(\n\t\t\t\t\"filter: possible data tunnel by %s in subdomain of %s: %s has an lms score of %.2f\",\n\t\t\t\tconn.Process(),\n\t\t\t\tconn.Entity.Domain,\n\t\t\t\tdomainToCheck,\n\t\t\t\tscore,\n\t\t\t)\n\t\t\tconn.Block(\"possible data tunnel for covert communication and protection bypassing\", profile.CfgOptionDomainHeuristicsKey)\n\t\t\treturn true\n\t\t}\n\t\tlog.Tracer(ctx).Tracef(\"filter: LMS score of entire domain is %.2f\", score)\n\t}\n\n\treturn false\n}\n\nfunc checkAutoPermitRelated(_ context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// Auto permit is disabled for default action permit.\n\tif p.DefaultAction() == profile.DefaultActionPermit {\n\t\treturn false\n\t}\n\n\t// Check if auto permit is disabled.\n\tif p.DisableAutoPermit() {\n\t\treturn false\n\t}\n\n\t// Check for relation to auto permit.\n\trelated, reason := checkRelation(conn)\n\tif related {\n\t\tconn.Accept(reason, profile.CfgOptionDisableAutoPermitKey)\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// checkRelation tries to find a relation between a process and a communication. This is for better out of the box experience and is _not_ meant to thwart intentional malware.\nfunc checkRelation(conn *network.Connection) (related bool, reason string) {\n\t// Don't check relation if no domain is available.\n\tif conn.Entity.Domain == \"\" {\n\t\treturn false, \"\"\n\t}\n\t// Don't check for unknown processes.\n\tif conn.Process().Pid < 0 {\n\t\treturn false, \"\"\n\t}\n\n\tpathElements := strings.Split(conn.Process().Path, string(filepath.Separator))\n\t// only look at the last two path segments\n\tif len(pathElements) > 2 {\n\t\tpathElements = pathElements[len(pathElements)-2:]\n\t}\n\tdomainElements := strings.Split(conn.Entity.Domain, \".\")\n\n\tvar domainElement string\n\tvar processElement string\n\nmatchLoop:\n\tfor _, domainElement = range domainElements {\n\t\tfor _, pathElement := range pathElements {\n\t\t\tif levenshtein.Match(domainElement, pathElement, nil) > 0.5 {\n\t\t\t\trelated = true\n\t\t\t\tprocessElement = pathElement\n\t\t\t\tbreak matchLoop\n\t\t\t}\n\t\t}\n\t\tif levenshtein.Match(domainElement, conn.Process().Name, nil) > 0.5 {\n\t\t\trelated = true\n\t\t\tprocessElement = conn.Process().Name\n\t\t\tbreak matchLoop\n\t\t}\n\t\tif levenshtein.Match(domainElement, conn.Process().ExecName, nil) > 0.5 {\n\t\t\trelated = true\n\t\t\tprocessElement = conn.Process().ExecName\n\t\t\tbreak matchLoop\n\t\t}\n\t}\n\n\tif related {\n\t\treason = fmt.Sprintf(\"auto allowed: domain is related to process: %s is related to %s\", domainElement, processElement)\n\t}\n\treturn related, reason\n}\n\nfunc checkCustomFilterList(_ context.Context, conn *network.Connection, p *profile.LayeredProfile, _ packet.Packet) bool {\n\t// Check if any custom list is loaded at all.\n\tif !customlists.IsLoaded() {\n\t\treturn false\n\t}\n\n\t// block if the domain name appears in the custom filter list (check for subdomains if enabled)\n\tif conn.Entity.Domain != \"\" {\n\t\tif ok, match := customlists.LookupDomain(conn.Entity.Domain, p.FilterSubDomains()); ok {\n\t\t\tconn.Deny(fmt.Sprintf(\"domain %s matches %s in custom filter list\", conn.Entity.Domain, match), customlists.CfgOptionCustomListFileKey)\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// block if any of the CNAME appears in the custom filter list (check for subdomains if enabled)\n\tif p.FilterCNAMEs() {\n\t\tfor _, cname := range conn.Entity.CNAME {\n\t\t\tif ok, match := customlists.LookupDomain(cname, p.FilterSubDomains()); ok {\n\t\t\t\tconn.Deny(fmt.Sprintf(\"domain alias (CNAME) %s matches %s in custom filter list\", cname, match), customlists.CfgOptionCustomListFileKey)\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\t// block if ip addresses appears in the custom filter list\n\tif conn.Entity.IP != nil {\n\t\tif customlists.LookupIP(conn.Entity.IP) {\n\t\t\tconn.Deny(\"IP address is in the custom filter list\", customlists.CfgOptionCustomListFileKey)\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// block autonomous system by its number if it appears in the custom filter list\n\tif conn.Entity.ASN != 0 {\n\t\tif customlists.LookupASN(conn.Entity.ASN) {\n\t\t\tconn.Deny(\"AS is in the custom filter list\", customlists.CfgOptionCustomListFileKey)\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// block if the country appears in the custom filter list\n\tif conn.Entity.Country != \"\" {\n\t\tif customlists.LookupCountry(conn.Entity.Country) {\n\t\t\tconn.Deny(\"country is in the custom filter list\", customlists.CfgOptionCustomListFileKey)\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "service/firewall/module.go",
    "content": "package firewall\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t_ \"github.com/safing/portmaster/service/core\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netquery\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/resolver\"\n\t\"github.com/safing/portmaster/service/updates\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/captain\"\n)\n\ntype stringSliceFlag []string\n\nfunc (ss *stringSliceFlag) String() string {\n\treturn strings.Join(*ss, \":\")\n}\n\nfunc (ss *stringSliceFlag) Set(value string) error {\n\t*ss = append(*ss, filepath.Clean(value))\n\treturn nil\n}\n\nvar allowedClients stringSliceFlag\n\ntype Firewall struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc init() {\n\tflag.Var(&allowedClients, \"allowed-clients\", \"A list of binaries that are allowed to connect to the Portmaster API\")\n}\n\nfunc (f *Firewall) Manager() *mgr.Manager {\n\treturn f.mgr\n}\n\nfunc (f *Firewall) Start() error {\n\tif err := prep(); err != nil {\n\t\tlog.Errorf(\"Failed to prepare firewall module %q\", err)\n\t\treturn err\n\t}\n\n\treturn start()\n}\n\nfunc (f *Firewall) Stop() error {\n\t// Cancel all workers and give them a little time.\n\t// The bandwidth updater can crash the sqlite DB for some reason.\n\t// TODO: Investigate.\n\tf.mgr.Cancel()\n\ttime.Sleep(100 * time.Millisecond)\n\n\treturn stop()\n}\n\nfunc prep() error {\n\tnetwork.SetDefaultFirewallHandler(defaultFirewallHandler)\n\n\t// Reset connections every time configuration changes\n\t// this will be triggered on spn enable/disable\n\tmodule.instance.Config().EventConfigChange.AddCallback(\"reset connection verdicts after global config change\", func(w *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\tresetAllConnectionVerdicts()\n\t\treturn false, nil\n\t})\n\n\tmodule.instance.Profile().EventConfigChange.AddCallback(\"reset connection verdicts after profile config change\",\n\t\tfunc(m *mgr.WorkerCtx, profileID string) (bool, error) {\n\t\t\t// Expected event data: scoped profile ID.\n\t\t\tprofileSource, profileID, ok := strings.Cut(profileID, \"/\")\n\t\t\tif !ok {\n\t\t\t\treturn false, fmt.Errorf(\"event data does not seem to be a scoped profile ID: %v\", profileID)\n\t\t\t}\n\n\t\t\tresetProfileConnectionVerdict(profileSource, profileID)\n\t\t\treturn false, nil\n\t\t},\n\t)\n\n\t// Reset connections when spn is connected\n\t// connect and disconnecting is triggered on config change event but connecting takеs more time\n\tmodule.instance.Captain().EventSPNConnected.AddCallback(\"reset connection verdicts on SPN connect\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\tresetAllConnectionVerdicts()\n\t\treturn false, err\n\t})\n\n\t// Reset connections when account is updated.\n\t// This will not change verdicts, but will update the feature flags on connections.\n\tmodule.instance.Access().EventAccountUpdate.AddCallback(\"update connection feature flags after account update\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\tresetAllConnectionVerdicts()\n\t\treturn false, err\n\t})\n\n\tmodule.instance.Network().EventConnectionReattributed.AddCallback(\"reset connection verdicts after connection re-attribution\", func(wc *mgr.WorkerCtx, connID string) (cancel bool, err error) {\n\t\t// Expected event data: connection ID.\n\t\tresetSingleConnectionVerdict(connID)\n\t\treturn false, err\n\t})\n\n\treturn nil\n}\n\nfunc start() error {\n\tgetConfig()\n\tstartAPIAuth()\n\n\tmodule.mgr.Go(\"packet handler\", packetHandler)\n\tmodule.mgr.Go(\"bandwidth update handler\", bandwidthUpdateHandler)\n\n\t// Start stat logger if logging is set to trace.\n\tif log.GetLogLevel() == log.TraceLevel {\n\t\tmodule.mgr.Go(\"stat logger\", statLogger)\n\t}\n\n\treturn nil\n}\n\nfunc stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *Firewall\n\tshimLoaded atomic.Bool\n)\n\nfunc New(instance instance) (*Firewall, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"Firewall\")\n\tmodule = &Firewall{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\tif err := prepAPIAuth(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := registerConfig(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tBinDir() string\n\tConfig() *config.Config\n\tBinaryUpdates() *updates.Updater\n\tProfile() *profile.ProfileModule\n\tCaptain() *captain.Captain\n\tAccess() *access.Access\n\tNetwork() *network.Network\n\tNetQuery() *netquery.NetQuery\n\tResolver() *resolver.ResolverModule\n}\n"
  },
  {
    "path": "service/firewall/packet_handler.go",
    "content": "package firewall\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/google/gopacket/layers\"\n\t\"github.com/miekg/dns\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/compat\"\n\t_ \"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/firewall/inspection\"\n\t\"github.com/safing/portmaster/service/firewall/interception\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/resolver\"\n\t\"github.com/safing/portmaster/spn/access\"\n)\n\ntype ExtVerdictHandlerFunc func(conn *network.Connection) (verdict network.Verdict, reason string, skipTunnel bool)\n\nvar (\n\tnameserverIPMatcher      func(ip net.IP) bool\n\tnameserverIPMatcherSet   = abool.New()\n\tnameserverIPMatcherReady = abool.New()\n\n\texternalVerdictHandler atomic.Pointer[ExtVerdictHandlerFunc]\n\n\tpacketsAccepted = new(uint64)\n\tpacketsBlocked  = new(uint64)\n\tpacketsDropped  = new(uint64)\n\tpacketsFailed   = new(uint64)\n\n\tblockedIPv4 = net.IPv4(0, 0, 0, 17)\n\tblockedIPv6 = net.ParseIP(\"::17\")\n\n\townPID = os.Getpid()\n)\n\nfunc resetSingleConnectionVerdict(connID string) {\n\t// Create tracing context.\n\tctx, tracer := log.AddTracer(context.Background())\n\tdefer tracer.Submit()\n\n\tconn, ok := network.GetConnection(connID)\n\tif !ok {\n\t\tconn, ok = network.GetDNSConnection(connID)\n\t\tif !ok {\n\t\t\ttracer.Debugf(\"filter: could not find re-attributed connection %s for re-evaluation\", connID)\n\t\t\treturn\n\t\t}\n\t}\n\n\tresetConnectionVerdict(ctx, conn)\n}\n\nfunc resetProfileConnectionVerdict(profileSource, profileID string) {\n\t// Create tracing context.\n\tctx, tracer := log.AddTracer(context.Background())\n\tdefer tracer.Submit()\n\n\t// Resetting will force all the connection to be evaluated by the firewall again\n\t// this will set new verdicts if configuration was update or spn has been disabled or enabled.\n\ttracer.Infof(\"filter: re-evaluating connections of %s/%s\", profileSource, profileID)\n\n\t// Re-evaluate all connections.\n\tvar changedVerdicts int\n\tfor _, conn := range network.GetAllConnections() {\n\t\t// Check if connection is complete and attributed to the deleted profile.\n\t\tif conn.DataIsComplete() &&\n\t\t\tconn.ProcessContext.Profile == profileID &&\n\t\t\tconn.ProcessContext.Source == profileSource {\n\t\t\tif resetConnectionVerdict(ctx, conn) {\n\t\t\t\tchangedVerdicts++\n\t\t\t}\n\t\t}\n\t}\n\ttracer.Infof(\"filter: changed verdict on %d connections\", changedVerdicts)\n}\n\nfunc resetAllConnectionVerdicts() {\n\t// Create tracing context.\n\tctx, tracer := log.AddTracer(context.Background())\n\tdefer tracer.Submit()\n\n\t// Resetting will force all the connection to be evaluated by the firewall again\n\t// this will set new verdicts if configuration was update or spn has been disabled or enabled.\n\ttracer.Info(\"filter: re-evaluating all connections\")\n\n\t// Re-evaluate all connections.\n\tvar changedVerdicts int\n\tfor _, conn := range network.GetAllConnections() {\n\t\t// Skip incomplete connections.\n\t\tif !conn.DataIsComplete() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif resetConnectionVerdict(ctx, conn) {\n\t\t\tchangedVerdicts++\n\t\t}\n\t}\n\ttracer.Infof(\"filter: changed verdict on %d connections\", changedVerdicts)\n}\n\nfunc resetConnectionVerdict(ctx context.Context, conn *network.Connection) (verdictChanged bool) {\n\ttracer := log.Tracer(ctx)\n\n\t// Remove any active prompt as the settings are being re-evaluated.\n\tconn.RemovePrompt()\n\n\tconn.Lock()\n\tdefer conn.Unlock()\n\n\t// Do not re-evaluate connection that have already ended.\n\tif conn.Ended > 0 {\n\t\treturn false\n\t}\n\n\t// Update feature flags.\n\tif err := conn.UpdateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {\n\t\ttracer.Warningf(\"filter: failed to update connection feature flags: %s\", err)\n\t}\n\n\t// Skip internal connections:\n\t// - Pre-authenticated connections from Portmaster\n\t// - Redirected DNS requests\n\t// - SPN Uplink to Home Hub\n\tif conn.Internal {\n\t\t// tracer.Tracef(\"filter: skipping internal connection %s\", conn)\n\t\treturn false\n\t}\n\n\ttracer.Debugf(\"filter: re-evaluating verdict of %s\", conn)\n\tpreviousVerdict := conn.Verdict\n\n\t// Apply privacy filter and check tunneling.\n\tFilterConnection(ctx, conn, nil, true, true)\n\n\t// Stop existing SPN tunnel if not needed anymore.\n\tif conn.Verdict != network.VerdictRerouteToTunnel && conn.TunnelContext != nil {\n\t\terr := conn.TunnelContext.StopTunnel()\n\t\tif err != nil {\n\t\t\ttracer.Debugf(\"filter: failed to stopped unneeded tunnel: %s\", err)\n\t\t}\n\t}\n\n\t// Save if verdict changed.\n\tif conn.Verdict != previousVerdict {\n\t\terr := interception.UpdateVerdictOfConnection(conn)\n\t\tif err != nil {\n\t\t\tlog.Debugf(\"filter: failed to update connection verdict: %s\", err)\n\t\t}\n\t\tconn.Save()\n\t\ttracer.Infof(\"filter: verdict of connection %s changed from %s to %s\", conn, previousVerdict.Verb(), conn.VerdictVerb())\n\n\t\t// Update verdict in OS integration, if an IP connection.\n\t\tif conn.Type == network.IPConnection {\n\t\t\terr := interception.UpdateVerdictOfConnection(conn)\n\t\t\tif err != nil {\n\t\t\t\tlog.Debugf(\"filter: failed to update connection verdict: %s\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn true\n\t}\n\n\ttracer.Tracef(\"filter: verdict to connection %s unchanged at %s\", conn, conn.VerdictVerb())\n\treturn false\n}\n\n// SetNameserverIPMatcher sets a function that is used to match the internal\n// nameserver IP(s). Can only bet set once.\nfunc SetNameserverIPMatcher(fn func(ip net.IP) bool) error {\n\tif !nameserverIPMatcherSet.SetToIf(false, true) {\n\t\treturn errors.New(\"nameserver IP matcher already set\")\n\t}\n\n\tnameserverIPMatcher = fn\n\tnameserverIPMatcherReady.Set()\n\treturn nil\n}\n\nfunc SetExternalVerdictHandler(fn ExtVerdictHandlerFunc) error {\n\tif !externalVerdictHandler.CompareAndSwap(nil, &fn) {\n\t\treturn errors.New(\"external verdict handler already set\")\n\t}\n\treturn nil\n}\n\nfunc handlePacket(pkt packet.Packet) {\n\t// First, check for an existing connection.\n\tconn, ok := network.GetConnection(pkt.GetConnectionID())\n\tif ok {\n\t\t// Add packet to connection handler queue or apply verdict directly.\n\t\tconn.HandlePacket(pkt)\n\t\treturn\n\t}\n\n\t// Else create new incomplete connection from the packet and start the new handler.\n\tconn = network.NewIncompleteConnection(pkt)\n\tconn.Lock()\n\tdefer conn.Unlock()\n\tconn.SetFirewallHandler(fastTrackHandler)\n\n\t// Let the new connection handler worker handle the packet.\n\tconn.HandlePacket(pkt)\n}\n\n// fastTrackedPermit quickly permits certain network critical or internal connections.\nfunc fastTrackedPermit(conn *network.Connection, pkt packet.Packet) (verdict network.Verdict, permanent bool) {\n\tmeta := pkt.Info()\n\n\t// Check if packed was already fast-tracked by the OS integration.\n\tif pkt.FastTrackedByIntegration() {\n\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-tracked by OS integration: %s\", pkt)\n\t\treturn network.VerdictAccept, true\n\t}\n\n\t// Check if connection was already blocked.\n\tif meta.Dst.Equal(blockedIPv4) || meta.Dst.Equal(blockedIPv6) {\n\t\treturn network.VerdictBlock, true\n\t}\n\n\t// Some programs do a network self-check where they connects to the same\n\t// IP/Port to test network capabilities.\n\t// Eg. dig: https://gitlab.isc.org/isc-projects/bind9/-/issues/1140\n\tif meta.SrcPort == meta.DstPort &&\n\t\tmeta.Src.Equal(meta.Dst) {\n\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-track network self-check: %s\", pkt)\n\t\treturn network.VerdictAccept, true\n\t}\n\n\tswitch meta.Protocol { //nolint:exhaustive // Checking for specific values only.\n\tcase packet.ICMP, packet.ICMPv6:\n\t\t// Load packet data.\n\t\terr := pkt.LoadPacketData()\n\t\tif err != nil {\n\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: failed to load ICMP packet data: %s\", err)\n\t\t\treturn network.VerdictAccept, true\n\t\t}\n\n\t\t// Submit to ICMP listener.\n\t\tsubmitted := netenv.SubmitPacketToICMPListener(pkt)\n\t\tif submitted {\n\t\t\t// If the packet was submitted to the listener, we must not do a\n\t\t\t// permanent accept, because then we won't see any future packets of that\n\t\t\t// connection and thus cannot continue to submit them.\n\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-track tracing ICMP/v6: %s\", pkt)\n\t\t\treturn network.VerdictAccept, false\n\t\t}\n\n\t\t// Handle echo request and replies regularly.\n\t\t// Other ICMP packets are considered system business.\n\t\ticmpLayers := pkt.Layers().LayerClass(layers.LayerClassIPControl)\n\t\tswitch icmpLayer := icmpLayers.(type) {\n\t\tcase *layers.ICMPv4:\n\t\t\tswitch icmpLayer.TypeCode.Type() {\n\t\t\tcase layers.ICMPv4TypeEchoRequest,\n\t\t\t\tlayers.ICMPv4TypeEchoReply:\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\t\tcase *layers.ICMPv6:\n\t\t\tswitch icmpLayer.TypeCode.Type() {\n\t\t\tcase layers.ICMPv6TypeEchoRequest,\n\t\t\t\tlayers.ICMPv6TypeEchoReply:\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\t\t}\n\n\t\t// Permit all ICMP/v6 packets that are not echo requests or replies.\n\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-track accepting ICMP/v6: %s\", pkt)\n\t\treturn network.VerdictAccept, true\n\n\tcase packet.UDP, packet.TCP:\n\t\tswitch meta.DstPort {\n\n\t\tcase 67, 68, 546, 547:\n\t\t\t// Always allow DHCP, DHCPv6.\n\n\t\t\t// DHCP and DHCPv6 must be UDP.\n\t\t\tif meta.Protocol != packet.UDP {\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// DHCP is only valid in local network scopes.\n\t\t\tswitch netutils.ClassifyIP(meta.Dst) { //nolint:exhaustive // Checking for specific values only.\n\t\t\tcase netutils.HostLocal, netutils.LinkLocal, netutils.SiteLocal, netutils.LocalMulticast:\n\t\t\tdefault:\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Log and permit.\n\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-track accepting DHCP: %s\", pkt)\n\t\t\treturn network.VerdictAccept, true\n\n\t\tcase apiPort:\n\t\t\t// Always allow direct access to the Portmaster API.\n\n\t\t\t// Portmaster API is TCP only.\n\t\t\tif meta.Protocol != packet.TCP {\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Check if the api port is even set.\n\t\t\tif !apiPortSet {\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Must be destined for the API IP.\n\t\t\tif !meta.Dst.Equal(apiIP) {\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Only fast-track local requests.\n\t\t\tisMe, err := netenv.IsMyIP(meta.Src)\n\t\t\tswitch {\n\t\t\tcase err != nil:\n\t\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: failed to check if %s is own IP for fast-track: %s\", meta.Src, err)\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\tcase !isMe:\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Log and permit.\n\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-track accepting api connection: %s\", pkt)\n\t\t\treturn network.VerdictAccept, true\n\n\t\tcase 53:\n\t\t\t// Always allow direct access to the Portmaster Nameserver.\n\t\t\t// DNS is both UDP and TCP.\n\n\t\t\t// Check if a nameserver IP matcher is set.\n\t\t\tif !nameserverIPMatcherReady.IsSet() {\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Check if packet is destined for a nameserver IP.\n\t\t\tif !nameserverIPMatcher(meta.Dst) {\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Only fast-track local requests.\n\t\t\tisMe, err := netenv.IsMyIP(meta.Src)\n\t\t\tswitch {\n\t\t\tcase err != nil:\n\t\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: failed to check if %s is own IP for fast-track: %s\", meta.Src, err)\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\tcase !isMe:\n\t\t\t\treturn network.VerdictUndecided, false\n\t\t\t}\n\n\t\t\t// Log and permit.\n\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-track accepting local dns: %s\", pkt)\n\n\t\t\t// Add to DNS request connections to attribute DNS request if outgoing.\n\t\t\tif pkt.IsOutbound() {\n\t\t\t\t// Assign PID from packet directly, as processing stops after fast-track.\n\t\t\t\tconn.PID = pkt.Info().PID\n\t\t\t\tnetwork.SaveDNSRequestConnection(conn, pkt)\n\t\t\t}\n\n\t\t\t// Accept local DNS, but only make permanent if we have the PID too.\n\t\t\treturn network.VerdictAccept, conn.PID != process.UndefinedProcessID\n\t\t}\n\n\t\t// Handle rare case where PM UI connection to WebSocket API lost it's verdict (e.g., cleared conntrack entries).\n\t\t// Fast-tracking keeps the UI connection seamless when resuming from paused state.\n\t\tif meta.SrcPort == apiPort && // connections made from API port\n\t\t\tmeta.Protocol == packet.TCP && // Portmaster API is TCP only\n\t\t\tapiPortSet && // API port is set\n\t\t\tmeta.Src.Equal(apiIP) { // initiated from API IP\n\n\t\t\t// Only fast-track local requests.\n\t\t\tisToMe, _ := netenv.IsMyIP(meta.Dst)\n\t\t\tif isToMe {\n\t\t\t\t// Log and permit.\n\t\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: fast-track accepting api-outbound packet: %s\", pkt)\n\t\t\t\treturn network.VerdictAccept, true\n\t\t\t}\n\t\t}\n\n\tcase compat.SystemIntegrationCheckProtocol:\n\t\tif pkt.Info().Dst.Equal(compat.SystemIntegrationCheckDstIP) {\n\t\t\tcompat.SubmitSystemIntegrationCheckPacket(pkt)\n\t\t\treturn network.VerdictDrop, false\n\t\t}\n\t}\n\n\treturn network.VerdictUndecided, false\n}\n\nfunc fastTrackHandler(conn *network.Connection, pkt packet.Packet) {\n\tconn.SaveWhenFinished()\n\n\tfastTrackedVerdict, permanent := fastTrackedPermit(conn, pkt)\n\tif fastTrackedVerdict != network.VerdictUndecided {\n\t\t// Set verdict on connection.\n\t\tconn.Verdict = fastTrackedVerdict\n\n\t\t// Apply verdict to (real) packet.\n\t\tif !pkt.InfoOnly() {\n\t\t\tissueVerdict(conn, pkt, fastTrackedVerdict, permanent)\n\t\t}\n\n\t\t// Stop handler if permanent.\n\t\tif permanent {\n\t\t\tconn.SetVerdict(fastTrackedVerdict, \"fast-tracked\", \"\", nil)\n\n\t\t\t// Do not finalize verdict, as we are missing necessary data.\n\t\t\tconn.StopFirewallHandler()\n\t\t}\n\n\t\t// Do not continue to next handler.\n\t\treturn\n\t}\n\n\t// If packet is not fast-tracked, continue with gathering more information.\n\tconn.UpdateFirewallHandler(gatherDataHandler)\n\tgatherDataHandler(conn, pkt)\n}\n\nfunc gatherDataHandler(conn *network.Connection, pkt packet.Packet) {\n\tconn.SaveWhenFinished()\n\n\t// Get process info\n\t_ = conn.GatherConnectionInfo(pkt)\n\t// Errors are informational and are logged to the context.\n\n\t// Run this handler again if data is not yet complete.\n\tif !conn.DataIsComplete() {\n\t\treturn\n\t}\n\n\t// Continue to filter handler, when connection data is complete.\n\tswitch conn.IPProtocol { //nolint:exhaustive\n\tcase packet.ICMP, packet.ICMPv6:\n\t\tconn.UpdateFirewallHandler(icmpFilterHandler)\n\t\ticmpFilterHandler(conn, pkt)\n\n\tdefault:\n\t\tconn.UpdateFirewallHandler(filterHandler)\n\t\tfilterHandler(conn, pkt)\n\t}\n}\n\nfunc filterHandler(conn *network.Connection, pkt packet.Packet) {\n\tconn.SaveWhenFinished()\n\n\t// Skip if data is not complete or packet is info-only.\n\tif !conn.DataIsComplete() || pkt.InfoOnly() {\n\t\treturn\n\t}\n\n\tfilterConnection := true\n\n\t// Check for special (internal) connection cases.\n\tswitch {\n\tcase !conn.Inbound && localPortIsPreAuthenticated(conn.Entity.Protocol, conn.LocalPort):\n\t\t// Approve connection.\n\t\tconn.Accept(\"connection by Portmaster\", noReasonOptionKey)\n\t\tconn.Internal = true\n\t\tfilterConnection = false\n\t\tlog.Tracer(pkt.Ctx()).Infof(\"filter: granting own pre-authenticated connection %s\", conn)\n\n\t// Redirect outbound DNS packets if enabled,\n\tcase dnsQueryInterception() &&\n\t\t!module.instance.Resolver().IsDisabled() &&\n\t\tpkt.IsOutbound() &&\n\t\tpkt.Info().DstPort == 53 &&\n\t\t// that don't match the address of our nameserver,\n\t\tnameserverIPMatcherReady.IsSet() &&\n\t\t!nameserverIPMatcher(pkt.Info().Dst) &&\n\t\t// and are not broadcast queries by us.\n\t\t// Context:\n\t\t// - Unicast queries by the resolver are pre-authenticated.\n\t\t// - Unicast queries by the compat self-check should be redirected.\n\t\t!(conn.Process().Pid == ownPID &&\n\t\t\tconn.Entity.IPScope == netutils.LocalMulticast):\n\n\t\t// Reroute rogue dns queries back to Portmaster.\n\t\tconn.SetVerdict(network.VerdictRerouteToNameserver, \"redirecting rogue dns query\", \"\", nil)\n\t\tconn.Internal = true\n\t\tlog.Tracer(pkt.Ctx()).Infof(\"filter: redirecting dns query %s to Portmaster\", conn)\n\n\t\t// Add to DNS request connections to attribute DNS request.\n\t\tnetwork.SaveDNSRequestConnection(conn, pkt)\n\n\t\t// End directly, as no other processing is necessary.\n\t\tconn.StopFirewallHandler()\n\n\t\tissueVerdict(conn, pkt, 0, true)\n\t\treturn\n\t}\n\n\t// Apply privacy filter and check tunneling.\n\tFilterConnection(pkt.Ctx(), conn, pkt, filterConnection, true)\n\n\t// Decide how to continue handling connection.\n\tswitch {\n\tcase conn.Inspecting && looksLikeOutgoingDNSRequest(conn):\n\t\tinspectDNSPacket(conn, pkt)\n\t\tconn.UpdateFirewallHandler(inspectDNSPacket)\n\tcase conn.Inspecting:\n\t\tlog.Tracer(pkt.Ctx()).Trace(\"filter: start inspecting\")\n\t\tconn.UpdateFirewallHandler(inspectAndVerdictHandler)\n\t\tinspectAndVerdictHandler(conn, pkt)\n\tdefault:\n\t\tconn.StopFirewallHandler()\n\t\tverdictHandler(conn, pkt)\n\t}\n}\n\n// FilterConnection runs all the filtering (and tunneling) procedures.\nfunc FilterConnection(ctx context.Context, conn *network.Connection, pkt packet.Packet, checkFilter, checkTunnel bool) {\n\t// Skip if data is not complete.\n\tif !conn.DataIsComplete() {\n\t\treturn\n\t}\n\n\t// Check if external verdict handler is set, and if so, run it.\n\t// Note! This block can override the filter and tunnel check flags!\n\tif extHandler := externalVerdictHandler.Load(); extHandler != nil {\n\t\tverdict, reason, skipTunnel := (*extHandler)(conn)\n\t\tswitch verdict {\n\t\t// Accept and Block - only these verdicts are supported to be returned by the external handler.\n\t\tcase network.VerdictAccept, network.VerdictBlock:\n\t\t\tconn.SetVerdict(verdict, reason, \"\", nil)\n\t\t\tcheckFilter = false\n\t\t\tcheckTunnel = !skipTunnel\n\t\t\tlog.Tracer(ctx).Infof(\"filter: special verdict %s %q %s for connection\", verdict, reason, conn)\n\t\t}\n\t}\n\n\tif checkFilter {\n\t\tif filterEnabled() {\n\t\t\tlog.Tracer(ctx).Trace(\"filter: starting decision process\")\n\t\t\tdecideOnConnection(ctx, conn, pkt)\n\t\t} else {\n\t\t\tconn.Accept(\"privacy filter disabled\", noReasonOptionKey)\n\t\t}\n\t}\n\n\t// TODO: Enable inspection framework again.\n\t// conn.Inspecting = false\n\n\t// TODO: Quick fix for the SPN.\n\t// Use inspection framework for proper encryption detection.\n\tswitch conn.Entity.DstPort() {\n\tcase\n\t\t22,  // SSH\n\t\t443, // HTTPS\n\t\t465, // SMTP-SSL\n\t\t853, // DoT\n\t\t993, // IMAP-SSL\n\t\t995: // POP3-SSL\n\t\tconn.Encrypted = true\n\t}\n\n\t// Check if connection should be tunneled.\n\tif checkTunnel {\n\t\tcheckTunneling(ctx, conn)\n\t}\n\n\t// Request tunneling if no tunnel is set and connection should be tunneled.\n\tif conn.Verdict == network.VerdictRerouteToTunnel &&\n\t\tconn.TunnelContext == nil {\n\t\terr := requestTunneling(ctx, conn)\n\t\tif err == nil {\n\t\t\tconn.ConnectionEstablished = true\n\t\t} else {\n\t\t\t// Set connection to failed, but keep tunneling data.\n\t\t\t// The tunneling data makes connection easy to recognize as a failed SPN\n\t\t\t// connection and the data will help with debugging and displaying in the UI.\n\t\t\tconn.Failed(fmt.Sprintf(\"failed to request tunneling: %s\", err), \"\")\n\t\t}\n\t}\n}\n\n// defaultFirewallHandler is used when no other firewall handler is set on a connection.\nfunc defaultFirewallHandler(conn *network.Connection, pkt packet.Packet) {\n\tswitch conn.IPProtocol { //nolint:exhaustive\n\tcase packet.ICMP, packet.ICMPv6:\n\t\t// Always use the ICMP handler for ICMP connections.\n\t\ticmpFilterHandler(conn, pkt)\n\n\tdefault:\n\t\tverdictHandler(conn, pkt)\n\t}\n}\n\nfunc verdictHandler(conn *network.Connection, pkt packet.Packet) {\n\t// Ignore info-only packets in this handler.\n\tif pkt.InfoOnly() {\n\t\treturn\n\t}\n\n\tissueVerdict(conn, pkt, 0, true)\n}\n\nfunc inspectAndVerdictHandler(conn *network.Connection, pkt packet.Packet) {\n\t// Ignore info-only packets in this handler.\n\tif pkt.InfoOnly() {\n\t\treturn\n\t}\n\n\t// Run inspectors.\n\tpktVerdict, continueInspection := inspection.RunInspectors(conn, pkt)\n\tif continueInspection {\n\t\tissueVerdict(conn, pkt, pktVerdict, false)\n\t\treturn\n\t}\n\n\t// we are done with inspecting\n\tconn.StopFirewallHandler()\n\tissueVerdict(conn, pkt, 0, true)\n}\n\nfunc inspectDNSPacket(conn *network.Connection, pkt packet.Packet) {\n\t// Ignore info-only packets in this handler.\n\tif pkt.InfoOnly() {\n\t\treturn\n\t}\n\n\tdnsPacket := new(dns.Msg)\n\terr := pkt.LoadPacketData()\n\tif err != nil {\n\t\t_ = pkt.Block()\n\t\tlog.Errorf(\"filter: failed to load packet payload: %s\", err)\n\t\treturn\n\t}\n\n\t// Parse and block invalid packets.\n\terr = dnsPacket.Unpack(pkt.Payload())\n\tif err != nil {\n\t\terr = pkt.PermanentBlock()\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"filter: failed to block packet: %s\", err)\n\t\t}\n\t\t_ = conn.SetVerdict(network.VerdictBlock, \"none DNS data on DNS port\", \"\", nil)\n\t\tconn.VerdictPermanent = true\n\t\tconn.Save()\n\t\treturn\n\t}\n\n\t// Packet was parsed.\n\t// Allow it but only after the answer was added to the cache.\n\tdefer func() {\n\t\terr = pkt.Accept()\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"filter: failed to accept dns packet: %s\", err)\n\t\t}\n\t}()\n\n\t// Check if packet has a question.\n\tif len(dnsPacket.Question) == 0 {\n\t\treturn\n\t}\n\n\t// Read create structs with the needed data.\n\tquestion := dnsPacket.Question[0]\n\tfqdn := dns.Fqdn(question.Name)\n\n\t// Check for compat check dns request.\n\tif strings.HasSuffix(fqdn, compat.DNSCheckInternalDomainScope) {\n\t\tsubdomain := strings.TrimSuffix(fqdn, compat.DNSCheckInternalDomainScope)\n\t\t_ = compat.SubmitDNSCheckDomain(subdomain)\n\t\tlog.Infof(\"packet_handler: self-check domain received\")\n\t\t// No need to parse the answer.\n\t\treturn\n\t}\n\n\t// Check if there is an answer.\n\tif len(dnsPacket.Answer) == 0 {\n\t\treturn\n\t}\n\n\tresolverInfo := &resolver.ResolverInfo{\n\t\tName:    \"DNSRequestObserver\",\n\t\tType:    resolver.ServerTypeFirewall,\n\t\tSource:  resolver.ServerSourceFirewall,\n\t\tIP:      conn.Entity.IP,\n\t\tDomain:  conn.Entity.Domain,\n\t\tIPScope: conn.Entity.IPScope,\n\t}\n\n\trrCache := &resolver.RRCache{\n\t\tDomain:   fqdn,\n\t\tQuestion: dns.Type(question.Qtype),\n\t\tRCode:    dnsPacket.Rcode,\n\t\tAnswer:   dnsPacket.Answer,\n\t\tNs:       dnsPacket.Ns,\n\t\tExtra:    dnsPacket.Extra,\n\t\tResolver: resolverInfo,\n\t}\n\n\tquery := &resolver.Query{\n\t\tFQDN:               fqdn,\n\t\tQType:              dns.Type(question.Qtype),\n\t\tNoCaching:          false,\n\t\tIgnoreFailing:      false,\n\t\tLocalResolversOnly: false,\n\t\tICANNSpace:         false,\n\t\tDomainRoot:         \"\",\n\t}\n\n\t// Save to cache\n\tUpdateIPsAndCNAMEs(query, rrCache, conn)\n}\n\nfunc icmpFilterHandler(conn *network.Connection, pkt packet.Packet) {\n\t// Load packet data.\n\terr := pkt.LoadPacketData()\n\tif err != nil {\n\t\tlog.Tracer(pkt.Ctx()).Debugf(\"filter: failed to load ICMP packet data: %s\", err)\n\t\tissueVerdict(conn, pkt, network.VerdictDrop, false)\n\t\treturn\n\t}\n\n\t// Submit to ICMP listener.\n\tsubmitted := netenv.SubmitPacketToICMPListener(pkt)\n\tif submitted {\n\t\tissueVerdict(conn, pkt, network.VerdictDrop, false)\n\t\treturn\n\t}\n\n\t// Handle echo request and replies regularly.\n\t// Other ICMP packets are considered system business.\n\ticmpLayers := pkt.Layers().LayerClass(layers.LayerClassIPControl)\n\tswitch icmpLayer := icmpLayers.(type) {\n\tcase *layers.ICMPv4:\n\t\tswitch icmpLayer.TypeCode.Type() {\n\t\tcase layers.ICMPv4TypeEchoRequest,\n\t\t\tlayers.ICMPv4TypeEchoReply:\n\t\t\t// Continue\n\t\tdefault:\n\t\t\tissueVerdict(conn, pkt, network.VerdictAccept, false)\n\t\t\treturn\n\t\t}\n\n\tcase *layers.ICMPv6:\n\t\tswitch icmpLayer.TypeCode.Type() {\n\t\tcase layers.ICMPv6TypeEchoRequest,\n\t\t\tlayers.ICMPv6TypeEchoReply:\n\t\t\t// Continue\n\n\t\tdefault:\n\t\t\tissueVerdict(conn, pkt, network.VerdictAccept, false)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Check if we already have a verdict.\n\tswitch conn.Verdict { //nolint:exhaustive\n\tcase network.VerdictUndecided, network.VerdictUndeterminable:\n\t\t// Apply privacy filter and check tunneling.\n\t\tFilterConnection(pkt.Ctx(), conn, pkt, true, false)\n\n\t\t// Save and propagate changes.\n\t\tconn.SaveWhenFinished()\n\t}\n\n\t// Outbound direction has priority.\n\tif conn.Inbound && conn.Ended == 0 && pkt.IsOutbound() {\n\t\t// Change direction from inbound to outbound on first outbound ICMP packet.\n\t\tconn.Inbound = false\n\n\t\t// Apply privacy filter and check tunneling.\n\t\tFilterConnection(pkt.Ctx(), conn, pkt, true, false)\n\n\t\t// Save and propagate changes.\n\t\tconn.SaveWhenFinished()\n\t}\n\n\tissueVerdict(conn, pkt, 0, false)\n}\n\nfunc issueVerdict(conn *network.Connection, pkt packet.Packet, verdict network.Verdict, allowPermanent bool) {\n\t// Check if packed was already fast-tracked by the OS integration.\n\tif pkt.FastTrackedByIntegration() {\n\t\treturn\n\t}\n\n\t// Enable permanent verdict.\n\tif allowPermanent && !conn.VerdictPermanent && permanentVerdicts() {\n\t\tconn.VerdictPermanent = true\n\t\tconn.SaveWhenFinished()\n\t}\n\n\t// do not allow to circumvent decision: e.g. to ACCEPT packets from a DROP-ed connection\n\tif verdict < conn.Verdict {\n\t\tverdict = conn.Verdict\n\t}\n\n\tvar err error\n\tswitch verdict {\n\tcase network.VerdictAccept:\n\t\tatomic.AddUint64(packetsAccepted, 1)\n\t\tif conn.VerdictPermanent {\n\t\t\terr = pkt.PermanentAccept()\n\t\t} else {\n\t\t\terr = pkt.Accept()\n\t\t}\n\tcase network.VerdictBlock:\n\t\tatomic.AddUint64(packetsBlocked, 1)\n\t\tif conn.VerdictPermanent {\n\t\t\terr = pkt.PermanentBlock()\n\t\t} else {\n\t\t\terr = pkt.Block()\n\t\t}\n\tcase network.VerdictDrop:\n\t\tatomic.AddUint64(packetsDropped, 1)\n\t\tif conn.VerdictPermanent {\n\t\t\terr = pkt.PermanentDrop()\n\t\t} else {\n\t\t\terr = pkt.Drop()\n\t\t}\n\tcase network.VerdictRerouteToNameserver:\n\t\terr = pkt.RerouteToNameserver()\n\tcase network.VerdictRerouteToTunnel:\n\t\terr = pkt.RerouteToTunnel()\n\tcase network.VerdictFailed:\n\t\tatomic.AddUint64(packetsFailed, 1)\n\t\terr = pkt.Drop()\n\tcase network.VerdictUndecided, network.VerdictUndeterminable:\n\t\tlog.Tracer(pkt.Ctx()).Warningf(\"filter: tried to apply verdict %s to pkt %s: dropping instead\", verdict, pkt)\n\t\tfallthrough\n\tdefault:\n\t\tatomic.AddUint64(packetsDropped, 1)\n\t\terr = pkt.Drop()\n\t}\n\n\tif err != nil {\n\t\tlog.Tracer(pkt.Ctx()).Warningf(\"filter: failed to apply verdict to pkt %s: %s\", pkt, err)\n\t}\n}\n\n// func tunnelHandler(pkt packet.Packet) {\n// \ttunnelInfo := GetTunnelInfo(pkt.Info().Dst)\n// \tif tunnelInfo == nil {\n// \t\tpkt.Block()\n// \t\treturn\n// \t}\n//\n// \tentry.CreateTunnel(pkt, tunnelInfo.Domain, tunnelInfo.RRCache.ExportAllARecords())\n// \tlog.Tracef(\"filter: rerouting %s to tunnel entry point\", pkt)\n// \tpkt.RerouteToTunnel()\n// \treturn\n// }\n\nfunc packetHandler(w *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-w.Done():\n\t\t\treturn nil\n\t\tcase pkt := <-interception.Packets:\n\t\t\tif pkt != nil {\n\t\t\t\thandlePacket(pkt)\n\t\t\t} else {\n\t\t\t\treturn errors.New(\"received nil packet from interception\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc bandwidthUpdateHandler(w *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-w.Done():\n\t\t\treturn nil\n\t\tcase bwUpdate := <-interception.BandwidthUpdates:\n\t\t\tif bwUpdate != nil {\n\t\t\t\t// DEBUG:\n\t\t\t\t// log.Debugf(\"filter: bandwidth update: %s\", bwUpdate)\n\t\t\t\tupdateBandwidth(w.Ctx(), bwUpdate)\n\t\t\t} else {\n\t\t\t\treturn errors.New(\"received nil bandwidth update from interception\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc updateBandwidth(ctx context.Context, bwUpdate *packet.BandwidthUpdate) {\n\t// Check if update makes sense.\n\tif bwUpdate.BytesReceived == 0 && bwUpdate.BytesSent == 0 {\n\t\treturn\n\t}\n\n\t// Get connection.\n\tconn, ok := network.GetConnection(bwUpdate.ConnID)\n\tif !ok {\n\t\treturn\n\t}\n\n\t// Do not wait for connections that are locked.\n\t// TODO: Use atomic operations for updating bandwidth stats.\n\tif !conn.TryLock() {\n\t\t// DEBUG:\n\t\t// log.Warningf(\"filter: failed to lock connection for bandwidth update: %s\", conn)\n\t\treturn\n\t}\n\tdefer conn.Unlock()\n\n\tbytesIn := bwUpdate.BytesReceived\n\tbytesOut := bwUpdate.BytesSent\n\n\t// Update stats according to method.\n\tswitch bwUpdate.Method {\n\tcase packet.Absolute:\n\t\tbytesIn = bwUpdate.BytesReceived - conn.BytesReceived\n\t\tbytesOut = bwUpdate.BytesSent - conn.BytesSent\n\n\t\tconn.BytesReceived = bwUpdate.BytesReceived\n\t\tconn.BytesSent = bwUpdate.BytesSent\n\tcase packet.Additive:\n\t\tconn.BytesReceived += bwUpdate.BytesReceived\n\t\tconn.BytesSent += bwUpdate.BytesSent\n\tdefault:\n\t\tlog.Warningf(\"filter: unsupported bandwidth update method: %d\", bwUpdate.Method)\n\t\treturn\n\t}\n\n\t// Update bandwidth in the netquery module.\n\tif module.instance.NetQuery() != nil && conn.BandwidthEnabled {\n\t\tif err := module.instance.NetQuery().Store.UpdateBandwidth(\n\t\t\tctx,\n\t\t\tconn.HistoryEnabled,\n\t\t\tfmt.Sprintf(\"%s/%s\", conn.ProcessContext.Source, conn.ProcessContext.Profile),\n\t\t\tconn.Process().GetKey(),\n\t\t\tconn.ID,\n\t\t\tbytesIn,\n\t\t\tbytesOut,\n\t\t); err != nil {\n\t\t\tlog.Errorf(\"filter: failed to persist bandwidth data: %s\", err)\n\t\t}\n\t}\n}\n\nfunc statLogger(w *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-w.Done():\n\t\t\treturn nil\n\t\tcase <-time.After(10 * time.Second):\n\t\t\tlog.Tracef(\n\t\t\t\t\"filter: packets accepted %d, blocked %d, dropped %d, failed %d\",\n\t\t\t\tatomic.LoadUint64(packetsAccepted),\n\t\t\t\tatomic.LoadUint64(packetsBlocked),\n\t\t\t\tatomic.LoadUint64(packetsDropped),\n\t\t\t\tatomic.LoadUint64(packetsFailed),\n\t\t\t)\n\t\t\tatomic.StoreUint64(packetsAccepted, 0)\n\t\t\tatomic.StoreUint64(packetsBlocked, 0)\n\t\t\tatomic.StoreUint64(packetsDropped, 0)\n\t\t\tatomic.StoreUint64(packetsFailed, 0)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/firewall/preauth.go",
    "content": "package firewall\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\nvar (\n\tpreAuthenticatedPorts     = make(map[string]struct{})\n\tpreAuthenticatedPortsLock sync.Mutex\n)\n\nfunc init() {\n\tresolver.SetLocalAddrFactory(PermittedAddr)\n\tnetenv.SetLocalAddrFactory(PermittedAddr)\n}\n\n// PermittedAddr returns an already permitted local address for the given network for reliable connectivity.\n// Returns nil in case of error.\nfunc PermittedAddr(network string) net.Addr {\n\tswitch network {\n\tcase \"udp\":\n\t\treturn PermittedUDPAddr()\n\tcase \"tcp\":\n\t\treturn PermittedTCPAddr()\n\t}\n\treturn nil\n}\n\n// PermittedUDPAddr returns an already permitted local udp address for reliable connectivity.\n// Returns nil in case of error.\nfunc PermittedUDPAddr() *net.UDPAddr {\n\tpreAuthdPort := GetPermittedPort(packet.UDP)\n\tif preAuthdPort == 0 {\n\t\treturn nil\n\t}\n\n\taddr, err := net.ResolveUDPAddr(\"udp\", fmt.Sprintf(\":%d\", preAuthdPort))\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\treturn addr\n}\n\n// PermittedTCPAddr returns an already permitted local tcp address for reliable connectivity.\n// Returns nil in case of error.\nfunc PermittedTCPAddr() *net.TCPAddr {\n\tpreAuthdPort := GetPermittedPort(packet.TCP)\n\tif preAuthdPort == 0 {\n\t\treturn nil\n\t}\n\n\taddr, err := net.ResolveTCPAddr(\"tcp\", fmt.Sprintf(\":%d\", preAuthdPort))\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\treturn addr\n}\n\n// GetPermittedPort returns a local port number that is already permitted for communication.\n// This bypasses the process attribution step to guarantee connectivity.\n// Communication on the returned port is attributed to the Portmaster.\n// Every pre-authenticated port is only valid once.\n// If no unused local port number can be found, it will return 0, which is\n// expected to trigger automatic port selection by the underlying OS.\nfunc GetPermittedPort(protocol packet.IPProtocol) uint16 {\n\tport, ok := network.GetUnusedLocalPort(uint8(protocol))\n\tif !ok {\n\t\treturn 0\n\t}\n\n\tpreAuthenticatedPortsLock.Lock()\n\tdefer preAuthenticatedPortsLock.Unlock()\n\n\t// Save generated port.\n\tkey := generateLocalPreAuthKey(uint8(protocol), port)\n\tpreAuthenticatedPorts[key] = struct{}{}\n\n\treturn port\n}\n\n// localPortIsPreAuthenticated checks if the given protocol and port are\n// pre-authenticated and should be attributed to the Portmaster itself.\nfunc localPortIsPreAuthenticated(protocol uint8, port uint16) bool {\n\tpreAuthenticatedPortsLock.Lock()\n\tdefer preAuthenticatedPortsLock.Unlock()\n\n\t// Check if the given protocol and port are pre-authenticated.\n\tkey := generateLocalPreAuthKey(protocol, port)\n\t_, ok := preAuthenticatedPorts[key]\n\tif ok {\n\t\t// Immediately remove pre authenticated port.\n\t\tdelete(preAuthenticatedPorts, key)\n\t}\n\n\treturn ok\n}\n\n// generateLocalPreAuthKey creates a map key for the pre-authenticated ports.\nfunc generateLocalPreAuthKey(protocol uint8, port uint16) string {\n\treturn strconv.Itoa(int(protocol)) + \":\" + strconv.Itoa(int(port))\n}\n"
  },
  {
    "path": "service/firewall/prompt.go",
    "content": "package firewall\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\nconst (\n\t// notification action IDs.\n\tallowDomainAll      = \"allow-domain-all\"\n\tallowDomainDistinct = \"allow-domain-distinct\"\n\tblockDomainAll      = \"block-domain-all\"\n\tblockDomainDistinct = \"block-domain-distinct\"\n\n\tallowIP        = \"allow-ip\"\n\tblockIP        = \"block-ip\"\n\tallowServingIP = \"allow-serving-ip\"\n\tblockServingIP = \"block-serving-ip\"\n\n\tcancelPrompt = \"cancel\"\n)\n\nvar (\n\tpromptNotificationCreation sync.Mutex\n\n\tdecisionTimeout int64 = 10 // in seconds\n)\n\ntype promptData struct {\n\tEntity  *intel.Entity\n\tProfile promptProfile\n}\n\ntype promptProfile struct {\n\tSource     string\n\tID         string\n\tLinkedPath string\n}\n\nfunc prompt(ctx context.Context, conn *network.Connection) {\n\t// Create notification.\n\tn := createPrompt(ctx, conn)\n\tif n == nil {\n\t\t// createPrompt returns nil when no further action should be taken.\n\t\treturn\n\t}\n\n\t// Add prompt to connection.\n\tconn.SetPrompt(n)\n\n\t// Get decision timeout and make sure it does not exceed the ask timeout.\n\ttimeout := decisionTimeout\n\tif timeout > askTimeout() {\n\t\ttimeout = askTimeout()\n\t}\n\n\t// wait for response/timeout\n\tselect {\n\tcase promptResponse := <-n.Response():\n\t\tswitch promptResponse {\n\t\tcase allowDomainAll, allowDomainDistinct, allowIP, allowServingIP:\n\t\t\t// Accept\n\t\t\tconn.Accept(\"allowed via prompt\", profile.CfgOptionEndpointsKey)\n\t\tcase \"\":\n\t\t\t// Dismissed\n\t\t\tconn.Deny(\"prompting canceled, waiting for new decision\", profile.CfgOptionDefaultActionKey)\n\t\tdefault:\n\t\t\t// Deny\n\t\t\tconn.Deny(\"blocked via prompt\", profile.CfgOptionEndpointsKey)\n\t\t}\n\n\tcase <-time.After(time.Duration(timeout) * time.Second):\n\t\tlog.Tracer(ctx).Debugf(\"filter: continuing prompting async\")\n\t\tconn.Deny(\"prompting in progress, please respond to prompt\", profile.CfgOptionDefaultActionKey)\n\n\tcase <-ctx.Done():\n\t\tlog.Tracer(ctx).Debugf(\"filter: aborting prompting because of shutdown\")\n\t\tconn.Drop(\"shutting down\", noReasonOptionKey)\n\t}\n}\n\n// promptIDPrefix is an identifier for privacy filter prompts. This is also used\n// in the UI, so don't change!\nconst promptIDPrefix = \"filter:prompt\"\n\nfunc createPrompt(ctx context.Context, conn *network.Connection) (n *notifications.Notification) {\n\texpires := time.Now().Add(time.Duration(askTimeout()) * time.Second).Unix()\n\n\t// Get local profile.\n\tlayeredProfile := conn.Process().Profile()\n\tif layeredProfile == nil {\n\t\tlog.Tracer(ctx).Warningf(\"filter: tried creating prompt for connection without profile\")\n\t\treturn nil\n\t}\n\tlocalProfile := layeredProfile.LocalProfile()\n\tif localProfile == nil {\n\t\tlog.Tracer(ctx).Warningf(\"filter: tried creating prompt for connection without local profile\")\n\t\treturn nil\n\t}\n\n\t// first check if there is an existing notification for this.\n\t// build notification ID\n\tvar nID string\n\tswitch {\n\tcase conn.Inbound, conn.Entity.Domain == \"\": // connection to/from IP\n\t\tnID = fmt.Sprintf(\n\t\t\t\"%s-%s-%v-%s\",\n\t\t\tpromptIDPrefix,\n\t\t\tlocalProfile.ID,\n\t\t\tconn.Inbound,\n\t\t\tconn.Entity.IP,\n\t\t)\n\tdefault: // connection to domain\n\t\tnID = fmt.Sprintf(\n\t\t\t\"%s-%s-%s\",\n\t\t\tpromptIDPrefix,\n\t\t\tlocalProfile.ID,\n\t\t\tconn.Entity.Domain,\n\t\t)\n\t}\n\n\t// Only handle one notification at a time.\n\tpromptNotificationCreation.Lock()\n\tdefer promptNotificationCreation.Unlock()\n\n\tn = notifications.Get(nID)\n\n\t// If there already is a notification, just update the expiry.\n\tif n != nil {\n\t\t// Get notification state and action.\n\t\tn.Lock()\n\t\tstate := n.State\n\t\taction := n.SelectedActionID\n\t\tn.Unlock()\n\n\t\t// If the notification is still active, extend and return.\n\t\t// This can happen because user input (prompts changing the endpoint\n\t\t// lists) can happen any time - also between checking the endpoint lists\n\t\t// and now.\n\t\tif state == notifications.Active {\n\t\t\tn.Update(expires)\n\t\t\tlog.Tracer(ctx).Debugf(\"filter: updated existing prompt notification\")\n\t\t\treturn n\n\t\t}\n\n\t\t// The notification is not active anymore, let's check if there is an\n\t\t// action we can perform.\n\t\t// If there already is an action defined, we won't be fast enough to\n\t\t// receive the action with n.Response(), so we take direct action here.\n\t\tif action != \"\" {\n\t\t\tswitch action {\n\t\t\tcase allowDomainAll, allowDomainDistinct, allowIP, allowServingIP:\n\t\t\t\tconn.Accept(\"allowed via prompt\", profile.CfgOptionEndpointsKey)\n\t\t\tdefault: // deny\n\t\t\t\tconn.Deny(\"blocked via prompt\", profile.CfgOptionEndpointsKey)\n\t\t\t}\n\t\t\treturn nil // Do not take further action.\n\t\t}\n\n\t\t// Continue to create a new notification because the previous one is not\n\t\t// active and not actionable.\n\t}\n\n\t// Reference relevant data for save function\n\tentity := conn.Entity\n\t// Also needed: localProfile\n\n\t// Create new notification.\n\tn = &notifications.Notification{\n\t\tEventID:      nID,\n\t\tType:         notifications.Prompt,\n\t\tTitle:        \"Connection Prompt\",\n\t\tCategory:     \"Privacy Filter\",\n\t\tShowOnSystem: askWithSystemNotifications(),\n\t\tEventData: &promptData{\n\t\t\tEntity: entity,\n\t\t\tProfile: promptProfile{\n\t\t\t\tSource: string(localProfile.Source),\n\t\t\t\tID:     localProfile.ID,\n\t\t\t\t// LinkedPath is used to enhance the display of the prompt in the UI.\n\t\t\t\t// TODO: Using the process path is a workaround. Find a cleaner solution.\n\t\t\t\tLinkedPath: conn.Process().Path,\n\t\t\t},\n\t\t},\n\t\tExpires: expires,\n\t}\n\n\t// Set action function.\n\tn.SetActionFunction(func(_ context.Context, n *notifications.Notification) error {\n\t\treturn saveResponse(\n\t\t\tlocalProfile,\n\t\t\tentity,\n\t\t\tn.SelectedActionID,\n\t\t)\n\t})\n\n\t// Get name of profile for notification. The profile is read-locked by the firewall handler.\n\tprofileName := localProfile.Name\n\n\t// add message and actions\n\tswitch {\n\tcase conn.Inbound:\n\t\tn.Message = fmt.Sprintf(\"%s wants to accept connections from %s (%d/%d)\", profileName, conn.Entity.IP.String(), conn.Entity.Protocol, conn.Entity.Port)\n\t\tn.AvailableActions = []*notifications.Action{\n\t\t\t{\n\t\t\t\tID:   allowServingIP,\n\t\t\t\tText: \"Allow\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:   blockServingIP,\n\t\t\t\tText: \"Block\",\n\t\t\t},\n\t\t}\n\tcase conn.Entity.Domain == \"\": // direct connection\n\t\tn.Message = fmt.Sprintf(\"%s wants to connect to %s (%d/%d)\", profileName, conn.Entity.IP.String(), conn.Entity.Protocol, conn.Entity.Port)\n\t\tn.AvailableActions = []*notifications.Action{\n\t\t\t{\n\t\t\t\tID:   allowIP,\n\t\t\t\tText: \"Allow\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:   blockIP,\n\t\t\t\tText: \"Block\",\n\t\t\t},\n\t\t}\n\tdefault: // connection to domain\n\t\tn.Message = fmt.Sprintf(\"%s wants to connect to %s\", profileName, conn.Entity.Domain)\n\t\tn.AvailableActions = []*notifications.Action{\n\t\t\t{\n\t\t\t\tID:   allowDomainAll,\n\t\t\t\tText: \"Allow\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:   blockDomainAll,\n\t\t\t\tText: \"Block\",\n\t\t\t},\n\t\t}\n\t}\n\n\tn.Save()\n\tlog.Tracer(ctx).Debugf(\"filter: sent prompt notification\")\n\n\treturn n\n}\n\n// promptSavingLock makes sure that only one prompt is saved at a time.\n// Should prompts be persisted in bulk, the next save process might load an\n// outdated profile and save it, losing config data.\nvar promptSavingLock sync.Mutex\n\nfunc saveResponse(p *profile.Profile, entity *intel.Entity, promptResponse string) error {\n\tif promptResponse == cancelPrompt {\n\t\treturn nil\n\t}\n\n\tpromptSavingLock.Lock()\n\tdefer promptSavingLock.Unlock()\n\n\t// Update the profile if necessary.\n\tif p.IsOutdated() {\n\t\tvar err error\n\t\tp, err = profile.GetLocalProfile(p.ID, nil, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tvar ep endpoints.Endpoint\n\tswitch promptResponse {\n\tcase allowDomainAll:\n\t\tep = &endpoints.EndpointDomain{\n\t\t\tEndpointBase:  endpoints.EndpointBase{Permitted: true},\n\t\t\tOriginalValue: \".\" + entity.Domain,\n\t\t}\n\tcase allowDomainDistinct:\n\t\tep = &endpoints.EndpointDomain{\n\t\t\tEndpointBase:  endpoints.EndpointBase{Permitted: true},\n\t\t\tOriginalValue: entity.Domain,\n\t\t}\n\tcase blockDomainAll:\n\t\tep = &endpoints.EndpointDomain{\n\t\t\tEndpointBase:  endpoints.EndpointBase{Permitted: false},\n\t\t\tOriginalValue: \".\" + entity.Domain,\n\t\t}\n\tcase blockDomainDistinct:\n\t\tep = &endpoints.EndpointDomain{\n\t\t\tEndpointBase:  endpoints.EndpointBase{Permitted: false},\n\t\t\tOriginalValue: entity.Domain,\n\t\t}\n\tcase allowIP, allowServingIP:\n\t\tep = &endpoints.EndpointIP{\n\t\t\tEndpointBase: endpoints.EndpointBase{Permitted: true},\n\t\t\tIP:           entity.IP,\n\t\t}\n\tcase blockIP, blockServingIP:\n\t\tep = &endpoints.EndpointIP{\n\t\t\tEndpointBase: endpoints.EndpointBase{Permitted: false},\n\t\t\tIP:           entity.IP,\n\t\t}\n\tcase cancelPrompt:\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown prompt response: %s\", promptResponse)\n\t}\n\n\tswitch promptResponse {\n\tcase allowServingIP, blockServingIP:\n\t\tp.AddServiceEndpoint(ep.String())\n\t\tlog.Infof(\"filter: added incoming rule to profile %s (LP Rev. %d): %q\",\n\t\t\tp, p.LayeredProfile().RevisionCnt(), ep.String())\n\tdefault:\n\t\tp.AddEndpoint(ep.String())\n\t\tlog.Infof(\"filter: added outgoing rule to profile %s (LP Rev. %d): %q\",\n\t\t\tp, p.LayeredProfile().RevisionCnt(), ep.String())\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/firewall/tunnel.go",
    "content": "package firewall\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/service/resolver\"\n\t\"github.com/safing/portmaster/spn/captain\"\n\t\"github.com/safing/portmaster/spn/crew\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/sluice\"\n)\n\nfunc checkTunneling(ctx context.Context, conn *network.Connection) {\n\t// Check if the connection should be tunneled at all.\n\tswitch {\n\tcase !tunnelEnabled():\n\t\t// Tunneling is disabled.\n\t\treturn\n\tcase !conn.Entity.IPScope.IsGlobal():\n\t\t// Can't tunnel Local/LAN connections.\n\t\treturn\n\tcase conn.Inbound:\n\t\t// Can't tunnel incoming connections.\n\t\treturn\n\tcase conn.Verdict != network.VerdictAccept:\n\t\t// Connection will be blocked.\n\t\treturn\n\tcase conn.IPProtocol != packet.TCP && conn.IPProtocol != packet.UDP:\n\t\t// Unsupported protocol.\n\t\treturn\n\tcase conn.Process().Pid == ownPID:\n\t\t// Bypass tunneling for certain own connections.\n\t\tswitch {\n\t\tcase !captain.ClientReady():\n\t\t\treturn\n\t\tcase captain.IsExcepted(conn.Entity.IP):\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Check more extensively for Local/LAN connections.\n\tlocalNet, err := netenv.GetLocalNetwork(conn.Entity.IP)\n\tif err != nil {\n\t\tlog.Warningf(\"firewall: failed to check if %s is in my net: %s\", conn.Entity.IP, err)\n\t} else if localNet != nil {\n\t\t// With IPv6, just checking the IP scope is not enough, as the host very\n\t\t// likely has a public IPv6 address.\n\t\t// Don't tunnel LAN connections.\n\n\t\t// TODO: We currently don't check the full LAN scope, but only the\n\t\t// broadcast domain of the host - ie. the networks that the host is\n\t\t// directly attached to.\n\t\treturn\n\t}\n\n\t// Get profile.\n\tlayeredProfile := conn.Process().Profile()\n\tif layeredProfile == nil {\n\t\tconn.Failed(\"no profile set\", \"\")\n\t\treturn\n\t}\n\n\t// Update profile.\n\tif layeredProfile.NeedsUpdate() {\n\t\t// Update revision counter in connection.\n\t\tconn.ProfileRevisionCounter = layeredProfile.Update(\n\t\t\tconn.Process().MatchingData(),\n\t\t\tconn.Process().CreateProfileCallback,\n\t\t)\n\t\tconn.SaveWhenFinished()\n\t} else {\n\t\t// Check if the revision counter of the connection needs updating.\n\t\trevCnt := layeredProfile.RevisionCnt()\n\t\tif conn.ProfileRevisionCounter != revCnt {\n\t\t\tconn.ProfileRevisionCounter = revCnt\n\t\t\tconn.SaveWhenFinished()\n\t\t}\n\t}\n\n\t// Check if tunneling is enabled for this app at all.\n\tif !layeredProfile.UseSPN() {\n\t\treturn\n\t}\n\n\t// Check if tunneling is enabled for entity.\n\tconn.Entity.FetchData(ctx)\n\tresult, _ := layeredProfile.MatchSPNUsagePolicy(ctx, conn.Entity)\n\tswitch result {\n\tcase endpoints.MatchError:\n\t\tconn.Failed(\"failed to check SPN rules\", profile.CfgOptionSPNUsagePolicyKey)\n\t\treturn\n\tcase endpoints.Denied:\n\t\treturn\n\tcase endpoints.Permitted, endpoints.NoMatch:\n\t\t// Continue\n\t}\n\n\t// Tunnel all the things!\n\tconn.SaveWhenFinished()\n\n\t// Check if ready.\n\tif !captain.ClientReady() {\n\t\t// Block connection as SPN is not ready yet.\n\t\tlog.Tracer(ctx).Trace(\"SPN not ready for tunneling\")\n\t\tconn.Failed(\"SPN not ready for tunneling\", \"\")\n\t\treturn\n\t}\n\n\tconn.SetVerdictDirectly(network.VerdictRerouteToTunnel)\n\tconn.Tunneled = true\n}\n\nfunc requestTunneling(ctx context.Context, conn *network.Connection) error {\n\t// Get profile.\n\tlayeredProfile := conn.Process().Profile()\n\tif layeredProfile == nil {\n\t\treturn errors.New(\"no profile set\")\n\t}\n\n\t// Get tunnel options.\n\tconn.TunnelOpts = DeriveTunnelOptions(layeredProfile, conn.Process(), conn.Entity, conn.Encrypted)\n\n\t// Queue request in sluice.\n\terr := sluice.AwaitRequest(conn, crew.HandleSluiceRequest)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Tracer(ctx).Trace(\"filter: tunneling requested\")\n\treturn nil\n}\n\nfunc init() {\n\tnavigator.DeriveTunnelOptions = func(lp *profile.LayeredProfile, destination *intel.Entity, connEncrypted bool) *navigator.Options {\n\t\treturn DeriveTunnelOptions(lp, nil, destination, connEncrypted)\n\t}\n}\n\n// DeriveTunnelOptions derives and returns the tunnel options from the connection and profile.\nfunc DeriveTunnelOptions(lp *profile.LayeredProfile, proc *process.Process, destination *intel.Entity, connEncrypted bool) *navigator.Options {\n\t// Set options.\n\ttunnelOpts := &navigator.Options{\n\t\tTransit: &navigator.TransitHubOptions{\n\t\t\tHubPolicies: lp.StackedTransitHubPolicies(),\n\t\t},\n\t\tDestination: &navigator.DestinationHubOptions{\n\t\t\tHubPolicies:        lp.StackedExitHubPolicies(),\n\t\t\tCheckHubPolicyWith: destination,\n\t\t},\n\t\tRoutingProfile: lp.SPNRoutingAlgorithm(),\n\t}\n\tif !connEncrypted {\n\t\ttunnelOpts.Destination.Regard = tunnelOpts.Destination.Regard.Add(navigator.StateTrusted)\n\t\t// TODO: Add this when all Hubs are on v0.6.21+\n\t\t// tunnelOpts.Destination.Regard = tunnelOpts.Destination.Regard.Add(navigator.StateAllowUnencrypted)\n\t}\n\n\t// Add required verified owners if community nodes should not be used.\n\tif !useCommunityNodes() {\n\t\ttunnelOpts.Transit.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners\n\t\ttunnelOpts.Destination.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners\n\t}\n\n\t// Get routing profile for checking for upgrades.\n\troutingProfile := navigator.GetRoutingProfile(tunnelOpts.RoutingProfile)\n\n\t// If we have any exit hub policies, we must be able to hop in order to follow the policy.\n\t// Switch to single-hop routing to allow for routing with hub selection.\n\tif routingProfile.MaxHops <= 1 && navigator.HubPoliciesAreSet(tunnelOpts.Destination.HubPolicies) {\n\t\ttunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID\n\t}\n\n\t// If the current home node is not trusted, then upgrade at least to two hops.\n\tif routingProfile.MinHops < 2 {\n\t\thomeNode, _ := navigator.Main.GetHome()\n\t\tif homeNode != nil && !homeNode.State.Has(navigator.StateTrusted) {\n\t\t\ttunnelOpts.RoutingProfile = navigator.RoutingProfileDoubleHopID\n\t\t}\n\t}\n\n\t// Special handling for the internal DNS resolver.\n\tif proc != nil && proc.Pid == ownPID && resolver.IsResolverAddress(destination.IP, destination.Port) {\n\t\tdnsExitHubPolicy, err := captain.GetDNSExitHubPolicy()\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"firewall: failed to get dns exit hub policy: %s\", err)\n\t\t}\n\n\t\tif err == nil && dnsExitHubPolicy.IsSet() {\n\t\t\t// Apply the dns exit hub policy, if set.\n\t\t\ttunnelOpts.Destination.HubPolicies = []endpoints.Endpoints{dnsExitHubPolicy}\n\t\t\t// Use the routing algorithm from the profile, as the home profile won't work with the policy.\n\t\t\ttunnelOpts.RoutingProfile = lp.SPNRoutingAlgorithm()\n\t\t\t// Raise the routing algorithm at least to single-hop.\n\t\t\tif tunnelOpts.RoutingProfile == navigator.RoutingProfileHomeID {\n\t\t\t\ttunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID\n\t\t\t}\n\t\t} else {\n\t\t\t// Disable any policies for the internal DNS resolver.\n\t\t\ttunnelOpts.Destination.HubPolicies = nil\n\t\t\t// Always use the home routing profile for the internal DNS resolver.\n\t\t\ttunnelOpts.RoutingProfile = navigator.RoutingProfileHomeID\n\t\t}\n\t}\n\n\treturn tunnelOpts\n}\n"
  },
  {
    "path": "service/instance.go",
    "content": "package service\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/broadcasts\"\n\t\"github.com/safing/portmaster/service/compat\"\n\t\"github.com/safing/portmaster/service/control\"\n\t\"github.com/safing/portmaster/service/core\"\n\t\"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/firewall\"\n\t\"github.com/safing/portmaster/service/firewall/interception\"\n\t\"github.com/safing/portmaster/service/firewall/interception/dnsmonitor\"\n\t\"github.com/safing/portmaster/service/integration\"\n\t\"github.com/safing/portmaster/service/intel/customlists\"\n\t\"github.com/safing/portmaster/service/intel/filterlists\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/interop\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/nameserver\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/netquery\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/resolver\"\n\t\"github.com/safing/portmaster/service/status\"\n\t\"github.com/safing/portmaster/service/sync\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/captain\"\n\t\"github.com/safing/portmaster/spn/crew\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/patrol\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/sluice\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\n// Instance is an instance of a Portmaster service.\ntype Instance struct {\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n\n\tshutdownCtx       context.Context\n\tcancelShutdownCtx context.CancelFunc\n\n\tserviceGroup             *mgr.Group\n\tserviceGroupInterception *mgr.GroupModule\n\n\tbinDir  string\n\tdataDir string\n\n\texitCode atomic.Int32\n\n\tdatabase      *dbmodule.DBModule\n\tconfig        *config.Config\n\tapi           *api.API\n\tmetrics       *metrics.Metrics\n\truntime       *runtime.Runtime\n\tnotifications *notifications.Notifications\n\trng           *rng.Rng\n\tbase          *base.Base\n\n\tcore          *core.Core\n\tbinaryUpdates *updates.Updater\n\tintelUpdates  *updates.Updater\n\tintegration   *integration.OSIntegration\n\tgeoip         *geoip.GeoIP\n\tnetenv        *netenv.NetEnv\n\tui            *ui.UI\n\tprofile       *profile.ProfileModule\n\tnetwork       *network.Network\n\tnetquery      *netquery.NetQuery\n\tfirewall      *firewall.Firewall\n\tfilterLists   *filterlists.FilterLists\n\tinterception  *interception.Interception\n\tdnsmonitor    *dnsmonitor.DNSMonitor\n\tcustomlist    *customlists.CustomList\n\tstatus        *status.Status\n\tbroadcasts    *broadcasts.Broadcasts\n\tcompat        *compat.Compat\n\tnameserver    *nameserver.NameServer\n\tprocess       *process.ProcessModule\n\tresolver      *resolver.ResolverModule\n\tsync          *sync.Sync\n\tcontrol       *control.Control\n\tinterop       *interop.Interoperability\n\n\taccess *access.Access\n\n\t// SPN modules\n\tSpnGroup  *mgr.ExtendedGroup\n\tcabin     *cabin.Cabin\n\tnavigator *navigator.Navigator\n\tcaptain   *captain.Captain\n\tcrew      *crew.Crew\n\tdocks     *docks.Docks\n\tpatrol    *patrol.Patrol\n\tships     *ships.Ships\n\tsluice    *sluice.SluiceModule\n\tterminal  *terminal.TerminalModule\n\n\tCommandLineOperation func() error\n\tShouldRestart        bool\n}\n\n// New returns a new Portmaster service instance.\nfunc New(svcCfg *ServiceConfig) (*Instance, error) { //nolint:maintidx\n\t// Initialize config.\n\terr := svcCfg.Init()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"internal service config error: %w\", err)\n\t}\n\n\t// Make sure data dir exists, so that child directories don't dictate the permissions.\n\terr = utils.EnsureDirectory(svcCfg.DataDir, utils.PublicReadExecPermission)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"data directory %s is not accessible: %w\", svcCfg.DataDir, err)\n\t}\n\n\t// Create instance to pass it to modules.\n\tinstance := &Instance{\n\t\tbinDir:  svcCfg.BinDir,\n\t\tdataDir: svcCfg.DataDir,\n\t}\n\tinstance.ctx, instance.cancelCtx = context.WithCancel(context.Background())\n\tinstance.shutdownCtx, instance.cancelShutdownCtx = context.WithCancel(context.Background())\n\n\t// Base modules\n\tinstance.base, err = base.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create base module: %w\", err)\n\t}\n\tinstance.database, err = dbmodule.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create database module: %w\", err)\n\t}\n\tinstance.config, err = config.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create config module: %w\", err)\n\t}\n\tinstance.api, err = api.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create api module: %w\", err)\n\t}\n\tinstance.metrics, err = metrics.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create metrics module: %w\", err)\n\t}\n\tinstance.runtime, err = runtime.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create runtime module: %w\", err)\n\t}\n\tinstance.notifications, err = notifications.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create runtime module: %w\", err)\n\t}\n\tinstance.rng, err = rng.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create rng module: %w\", err)\n\t}\n\n\t// Service modules\n\tbinaryUpdateConfig, intelUpdateConfig, err := MakeUpdateConfigs(svcCfg)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create updates config: %w\", err)\n\t}\n\tinstance.binaryUpdates, err = updates.New(instance, \"Binary Updater\", *binaryUpdateConfig)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create updates module: %w\", err)\n\t}\n\tinstance.intelUpdates, err = updates.New(instance, \"Intel Updater\", *intelUpdateConfig)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create updates module: %w\", err)\n\t}\n\tinstance.core, err = core.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create core module: %w\", err)\n\t}\n\tinstance.integration, err = integration.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create integration module: %w\", err)\n\t}\n\tinstance.geoip, err = geoip.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create customlist module: %w\", err)\n\t}\n\tinstance.netenv, err = netenv.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create netenv module: %w\", err)\n\t}\n\tinstance.ui, err = ui.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create ui module: %w\", err)\n\t}\n\tinstance.profile, err = profile.NewModule(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create profile module: %w\", err)\n\t}\n\tinstance.network, err = network.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create network module: %w\", err)\n\t}\n\tinstance.netquery, err = netquery.NewModule(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create netquery module: %w\", err)\n\t}\n\tinstance.firewall, err = firewall.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create firewall module: %w\", err)\n\t}\n\tinstance.filterLists, err = filterlists.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create filterLists module: %w\", err)\n\t}\n\tinstance.interception, err = interception.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create interception module: %w\", err)\n\t}\n\tinstance.dnsmonitor, err = dnsmonitor.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create dns-listener module: %w\", err)\n\t}\n\tinstance.customlist, err = customlists.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create customlist module: %w\", err)\n\t}\n\n\tinstance.status, err = status.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create status module: %w\", err)\n\t}\n\tinstance.broadcasts, err = broadcasts.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create broadcasts module: %w\", err)\n\t}\n\tinstance.compat, err = compat.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create compat module: %w\", err)\n\t}\n\tinstance.nameserver, err = nameserver.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create nameserver module: %w\", err)\n\t}\n\tinstance.process, err = process.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create process module: %w\", err)\n\t}\n\tinstance.resolver, err = resolver.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create resolver module: %w\", err)\n\t}\n\tinstance.sync, err = sync.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create sync module: %w\", err)\n\t}\n\tinstance.control, err = control.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create control module: %w\", err)\n\t}\n\tinstance.interop, err = interop.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create interop module: %w\", err)\n\t}\n\tinstance.access, err = access.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create access module: %w\", err)\n\t}\n\n\t// SPN modules\n\tinstance.cabin, err = cabin.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create cabin module: %w\", err)\n\t}\n\tinstance.navigator, err = navigator.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create navigator module: %w\", err)\n\t}\n\tinstance.captain, err = captain.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create captain module: %w\", err)\n\t}\n\tinstance.crew, err = crew.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create crew module: %w\", err)\n\t}\n\tinstance.docks, err = docks.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create docks module: %w\", err)\n\t}\n\tinstance.patrol, err = patrol.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create patrol module: %w\", err)\n\t}\n\tinstance.ships, err = ships.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create ships module: %w\", err)\n\t}\n\tinstance.sluice, err = sluice.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create sluice module: %w\", err)\n\t}\n\tinstance.terminal, err = terminal.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create terminal module: %w\", err)\n\t}\n\n\t// Grouped interception modules that can be paused/resumed together.\n\tinstance.serviceGroupInterception = mgr.NewGroupModule(\"Interception Group\",\n\t\tinstance.interception,\n\t\tinstance.dnsmonitor,\n\t\tinstance.compat)\n\n\t// Add all modules to instance group.\n\tinstance.serviceGroup = mgr.NewGroup(\n\t\tinstance.base,\n\t\tinstance.rng,\n\t\tinstance.database,\n\t\tinstance.config,\n\t\tinstance.api,\n\t\tinstance.metrics,\n\t\tinstance.runtime,\n\t\tinstance.notifications,\n\n\t\tinstance.core,\n\t\tinstance.binaryUpdates,\n\t\tinstance.intelUpdates,\n\t\tinstance.integration,\n\t\tinstance.geoip,\n\t\tinstance.netenv,\n\n\t\tinstance.process,\n\t\tinstance.profile,\n\t\tinstance.network,\n\t\tinstance.netquery,\n\t\tinstance.firewall,\n\t\tinstance.nameserver,\n\t\tinstance.resolver,\n\t\tinstance.filterLists,\n\t\tinstance.customlist,\n\n\t\tinstance.interop, // required to start before interception\n\n\t\t// Grouped pausable interception modules:\n\t\t// \t\tinstance.interception,\n\t\t// \t\tinstance.dnsmonitor,\n\t\t// \t\tinstance.compat\n\t\tinstance.serviceGroupInterception,\n\n\t\tinstance.status,\n\t\tinstance.broadcasts,\n\t\tinstance.sync,\n\t\tinstance.ui,\n\t\tinstance.control,\n\n\t\tinstance.access,\n\t)\n\n\t// SPN Group\n\tinstance.SpnGroup = mgr.NewExtendedGroup(\n\t\tinstance.cabin,\n\t\tinstance.navigator,\n\t\tinstance.captain,\n\t\tinstance.crew,\n\t\tinstance.docks,\n\t\tinstance.patrol,\n\t\tinstance.ships,\n\t\tinstance.sluice,\n\t\tinstance.terminal,\n\t)\n\n\treturn instance, nil\n}\n\n// SleepyModule is an interface for modules that can enter some sort of sleep mode.\ntype SleepyModule interface {\n\tSetSleep(enabled bool)\n}\n\n// SetSleep sets sleep mode on all modules that satisfy the SleepyModule interface.\nfunc (i *Instance) SetSleep(enabled bool) {\n\tfor _, module := range i.serviceGroup.Modules() {\n\t\tif sm, ok := module.(SleepyModule); ok {\n\t\t\tsm.SetSleep(enabled)\n\t\t}\n\t}\n\tfor _, module := range i.SpnGroup.Modules() {\n\t\tif sm, ok := module.(SleepyModule); ok {\n\t\t\tsm.SetSleep(enabled)\n\t\t}\n\t}\n}\n\n// BinDir returns the directory for binaries.\n// This directory may be read-only.\nfunc (i *Instance) BinDir() string {\n\treturn i.binDir\n}\n\n// DataDir returns the directory for variable data.\n// This directory is expected to be read/writeable.\nfunc (i *Instance) DataDir() string {\n\treturn i.dataDir\n}\n\n// Database returns the database module.\nfunc (i *Instance) Database() *dbmodule.DBModule {\n\treturn i.database\n}\n\n// Config returns the config module.\nfunc (i *Instance) Config() *config.Config {\n\treturn i.config\n}\n\n// API returns the api module.\nfunc (i *Instance) API() *api.API {\n\treturn i.api\n}\n\n// Metrics returns the metrics module.\nfunc (i *Instance) Metrics() *metrics.Metrics {\n\treturn i.metrics\n}\n\n// Runtime returns the runtime module.\nfunc (i *Instance) Runtime() *runtime.Runtime {\n\treturn i.runtime\n}\n\n// Notifications returns the notifications module.\nfunc (i *Instance) Notifications() *notifications.Notifications {\n\treturn i.notifications\n}\n\n// Rng returns the rng module.\nfunc (i *Instance) Rng() *rng.Rng {\n\treturn i.rng\n}\n\n// Base returns the base module.\nfunc (i *Instance) Base() *base.Base {\n\treturn i.base\n}\n\n// BinaryUpdates returns the updates module.\nfunc (i *Instance) BinaryUpdates() *updates.Updater {\n\treturn i.binaryUpdates\n}\n\n// GetBinaryUpdateFile returns the file path of a binary update file.\nfunc (i *Instance) GetBinaryUpdateFile(name string) (path string, err error) {\n\tfile, err := i.binaryUpdates.GetFile(name)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn file.Path(), nil\n}\n\n// IntelUpdates returns the updates module.\nfunc (i *Instance) IntelUpdates() *updates.Updater {\n\treturn i.intelUpdates\n}\n\n// OSIntegration returns the integration module.\nfunc (i *Instance) OSIntegration() *integration.OSIntegration {\n\treturn i.integration\n}\n\n// GeoIP returns the geoip module.\nfunc (i *Instance) GeoIP() *geoip.GeoIP {\n\treturn i.geoip\n}\n\n// NetEnv returns the netenv module.\nfunc (i *Instance) NetEnv() *netenv.NetEnv {\n\treturn i.netenv\n}\n\n// Access returns the access module.\nfunc (i *Instance) Access() *access.Access {\n\treturn i.access\n}\n\n// Cabin returns the cabin module.\nfunc (i *Instance) Cabin() *cabin.Cabin {\n\treturn i.cabin\n}\n\n// Captain returns the captain module.\nfunc (i *Instance) Captain() *captain.Captain {\n\treturn i.captain\n}\n\n// Crew returns the crew module.\nfunc (i *Instance) Crew() *crew.Crew {\n\treturn i.crew\n}\n\n// Docks returns the crew module.\nfunc (i *Instance) Docks() *docks.Docks {\n\treturn i.docks\n}\n\n// Navigator returns the navigator module.\nfunc (i *Instance) Navigator() *navigator.Navigator {\n\treturn i.navigator\n}\n\n// Patrol returns the patrol module.\nfunc (i *Instance) Patrol() *patrol.Patrol {\n\treturn i.patrol\n}\n\n// Ships returns the ships module.\nfunc (i *Instance) Ships() *ships.Ships {\n\treturn i.ships\n}\n\n// Sluice returns the ships module.\nfunc (i *Instance) Sluice() *sluice.SluiceModule {\n\treturn i.sluice\n}\n\n// Terminal returns the terminal module.\nfunc (i *Instance) Terminal() *terminal.TerminalModule {\n\treturn i.terminal\n}\n\n// UI returns the ui module.\nfunc (i *Instance) UI() *ui.UI {\n\treturn i.ui\n}\n\n// Profile returns the profile module.\nfunc (i *Instance) Profile() *profile.ProfileModule {\n\treturn i.profile\n}\n\n// Firewall returns the firewall module.\nfunc (i *Instance) Firewall() *firewall.Firewall {\n\treturn i.firewall\n}\n\n// FilterLists returns the filterLists module.\nfunc (i *Instance) FilterLists() *filterlists.FilterLists {\n\treturn i.filterLists\n}\n\n// Interception returns the interception module.\nfunc (i *Instance) Interception() *interception.Interception {\n\treturn i.interception\n}\n\n// InterceptionGroup returns the grouped interception modules that can be paused together.\nfunc (i *Instance) InterceptionGroup() *mgr.GroupModule {\n\treturn i.serviceGroupInterception\n}\n\n// DNSMonitor returns the dns-listener module.\nfunc (i *Instance) DNSMonitor() *dnsmonitor.DNSMonitor {\n\treturn i.dnsmonitor\n}\n\n// CustomList returns the customlist module.\nfunc (i *Instance) CustomList() *customlists.CustomList {\n\treturn i.customlist\n}\n\n// Status returns the status module.\nfunc (i *Instance) Status() *status.Status {\n\treturn i.status\n}\n\n// Broadcasts returns the broadcast module.\nfunc (i *Instance) Broadcasts() *broadcasts.Broadcasts {\n\treturn i.broadcasts\n}\n\n// Compat returns the compat module.\nfunc (i *Instance) Compat() *compat.Compat {\n\treturn i.compat\n}\n\n// NameServer returns the nameserver module.\nfunc (i *Instance) NameServer() *nameserver.NameServer {\n\treturn i.nameserver\n}\n\n// NetQuery returns the netquery module.\nfunc (i *Instance) NetQuery() *netquery.NetQuery {\n\treturn i.netquery\n}\n\n// Network returns the network module.\nfunc (i *Instance) Network() *network.Network {\n\treturn i.network\n}\n\n// Process returns the process module.\nfunc (i *Instance) Process() *process.ProcessModule {\n\treturn i.process\n}\n\n// Resolver returns the resolver module.\nfunc (i *Instance) Resolver() *resolver.ResolverModule {\n\treturn i.resolver\n}\n\n// Sync returns the sync module.\nfunc (i *Instance) Sync() *sync.Sync {\n\treturn i.sync\n}\n\n// Core returns the core module.\nfunc (i *Instance) Core() *core.Core {\n\treturn i.core\n}\n\n// SPNGroup returns the group of all SPN modules.\nfunc (i *Instance) SPNGroup() *mgr.ExtendedGroup {\n\treturn i.SpnGroup\n}\n\n// Events\n\n// GetEventSPNConnected return the event manager for the SPN connected event.\nfunc (i *Instance) GetEventSPNConnected() *mgr.EventMgr[struct{}] {\n\treturn i.captain.EventSPNConnected\n}\n\n// Special functions\n\n// SetCmdLineOperation sets a command line operation to be executed instead of starting the system. This is useful when functions need all modules to be prepared for a special operation.\nfunc (i *Instance) SetCmdLineOperation(f func() error) {\n\ti.CommandLineOperation = f\n}\n\n// GetStates returns the current states of all group modules.\nfunc (i *Instance) GetStates() []mgr.StateUpdate {\n\tmainStates := i.serviceGroup.GetStates()\n\tspnStates := i.SpnGroup.GetStates()\n\n\tupdates := make([]mgr.StateUpdate, 0, len(mainStates)+len(spnStates))\n\tupdates = append(updates, mainStates...)\n\tupdates = append(updates, spnStates...)\n\n\treturn updates\n}\n\n// AddStatesCallback adds the given callback function to all group modules that\n// expose a state manager at States().\nfunc (i *Instance) AddStatesCallback(callbackName string, callback mgr.EventCallbackFunc[mgr.StateUpdate]) {\n\ti.serviceGroup.AddStatesCallback(callbackName, callback)\n\ti.SpnGroup.AddStatesCallback(callbackName, callback)\n}\n\n// Ready returns whether all modules in the main service module group have been started and are still running.\nfunc (i *Instance) Ready() bool {\n\treturn i.serviceGroup.Ready()\n}\n\n// Start starts the instance modules.\nfunc (i *Instance) Start() error {\n\treturn i.serviceGroup.Start()\n}\n\n// Stop stops the instance modules.\nfunc (i *Instance) Stop() error {\n\treturn i.serviceGroup.Stop()\n}\n\n// RestartExitCode will instruct portmaster-start to restart the process immediately, potentially with a new version.\nconst RestartExitCode = 23\n\n// Restart asynchronously restarts the instance.\n// This only works if the underlying system/process supports this.\nfunc (i *Instance) Restart() {\n\t// Send a restart event, give it 10ms extra to propagate.\n\ti.core.EventRestart.Submit(struct{}{})\n\ttime.Sleep(10 * time.Millisecond)\n\n\t// Set the restart flag and shutdown.\n\ti.ShouldRestart = true\n\ti.shutdown(RestartExitCode)\n}\n\n// Shutdown asynchronously stops the instance.\nfunc (i *Instance) Shutdown() {\n\t// Send a shutdown event, give it 10ms extra to propagate.\n\ti.core.EventShutdown.Submit(struct{}{})\n\ttime.Sleep(10 * time.Millisecond)\n\n\ti.shutdown(0)\n}\n\nfunc (i *Instance) shutdown(exitCode int) {\n\t// Only shutdown once.\n\tif i.IsShuttingDown() {\n\t\treturn\n\t}\n\n\t// Cancel main  context.\n\ti.cancelCtx()\n\n\t// Set given exit code.\n\ti.exitCode.Store(int32(exitCode))\n\n\t// Start shutdown asynchronously in a separate manager.\n\tm := mgr.New(\"instance\")\n\tm.Go(\"shutdown\", func(w *mgr.WorkerCtx) error {\n\t\t// Stop all modules.\n\t\tif err := i.Stop(); err != nil {\n\t\t\tw.Error(\"failed to shutdown\", \"err\", err)\n\t\t}\n\n\t\t// Cancel shutdown process context.\n\t\ti.cancelShutdownCtx()\n\t\treturn nil\n\t})\n}\n\n// Ctx returns the instance context.\n// It is canceled when shutdown is started.\nfunc (i *Instance) Ctx() context.Context {\n\treturn i.ctx\n}\n\n// IsShuttingDown returns whether the instance is shutting down.\nfunc (i *Instance) IsShuttingDown() bool {\n\treturn i.ctx.Err() != nil\n}\n\n// ShuttingDown returns a channel that is triggered when the instance starts shutting down.\nfunc (i *Instance) ShuttingDown() <-chan struct{} {\n\treturn i.ctx.Done()\n}\n\n// ShutdownCtx returns the instance shutdown context.\n// It is canceled when shutdown is complete.\nfunc (i *Instance) ShutdownCtx() context.Context {\n\treturn i.shutdownCtx\n}\n\n// IsShutDown returns whether the instance has stopped.\nfunc (i *Instance) IsShutDown() bool {\n\treturn i.shutdownCtx.Err() != nil\n}\n\n// ShutDownComplete returns a channel that is triggered when the instance has shut down.\nfunc (i *Instance) ShutdownComplete() <-chan struct{} {\n\treturn i.shutdownCtx.Done()\n}\n\n// ExitCode returns the set exit code of the instance.\nfunc (i *Instance) ExitCode() int {\n\treturn int(i.exitCode.Load())\n}\n\n// ShouldRestartIsSet returns whether the service/instance should be restarted.\nfunc (i *Instance) ShouldRestartIsSet() bool {\n\treturn i.ShouldRestart\n}\n\n// CommandLineOperationIsSet returns whether the command line option is set.\nfunc (i *Instance) CommandLineOperationIsSet() bool {\n\treturn i.CommandLineOperation != nil\n}\n\n// CommandLineOperationExecute executes the set command line option.\nfunc (i *Instance) CommandLineOperationExecute() error {\n\treturn i.CommandLineOperation()\n}\n\n// AddModule adds a module to the service group.\nfunc (i *Instance) AddModule(m mgr.Module) {\n\ti.serviceGroup.Add(m)\n}\n"
  },
  {
    "path": "service/integration/etw_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage integration\n\nimport (\n\t\"fmt\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\ntype ETWFunctions struct {\n\tcreateState       *windows.Proc\n\tinitializeSession *windows.Proc\n\tstartTrace        *windows.Proc\n\tflushTrace        *windows.Proc\n\tstopTrace         *windows.Proc\n\tdestroySession    *windows.Proc\n\tstopOldSession    *windows.Proc\n}\n\nfunc initializeETW(dll *windows.DLL) (*ETWFunctions, error) {\n\tfunctions := &ETWFunctions{}\n\tvar err error\n\tfunctions.createState, err = dll.FindProc(\"PM_ETWCreateState\")\n\tif err != nil {\n\t\treturn functions, fmt.Errorf(\"failed to load function PM_ETWCreateState: %q\", err)\n\t}\n\tfunctions.initializeSession, err = dll.FindProc(\"PM_ETWInitializeSession\")\n\tif err != nil {\n\t\treturn functions, fmt.Errorf(\"failed to load function PM_ETWInitializeSession: %q\", err)\n\t}\n\tfunctions.startTrace, err = dll.FindProc(\"PM_ETWStartTrace\")\n\tif err != nil {\n\t\treturn functions, fmt.Errorf(\"failed to load function PM_ETWStartTrace: %q\", err)\n\t}\n\tfunctions.flushTrace, err = dll.FindProc(\"PM_ETWFlushTrace\")\n\tif err != nil {\n\t\treturn functions, fmt.Errorf(\"failed to load function PM_ETWFlushTrace: %q\", err)\n\t}\n\tfunctions.stopTrace, err = dll.FindProc(\"PM_ETWStopTrace\")\n\tif err != nil {\n\t\treturn functions, fmt.Errorf(\"failed to load function PM_ETWStopTrace: %q\", err)\n\t}\n\tfunctions.destroySession, err = dll.FindProc(\"PM_ETWDestroySession\")\n\tif err != nil {\n\t\treturn functions, fmt.Errorf(\"failed to load function PM_ETWDestroySession: %q\", err)\n\t}\n\tfunctions.stopOldSession, err = dll.FindProc(\"PM_ETWStopOldSession\")\n\tif err != nil {\n\t\treturn functions, fmt.Errorf(\"failed to load function PM_ETWDestroySession: %q\", err)\n\t}\n\treturn functions, nil\n}\n\n// CreateState calls the dll createState C function.\nfunc (etw ETWFunctions) CreateState(callback uintptr) uintptr {\n\tstate, _, _ := etw.createState.Call(callback)\n\treturn state\n}\n\n// InitializeSession calls the dll initializeSession C function.\nfunc (etw ETWFunctions) InitializeSession(state uintptr) error {\n\trc, _, _ := etw.initializeSession.Call(state)\n\tif rc != 0 {\n\t\treturn fmt.Errorf(\"failed with status code: %d\", rc)\n\t}\n\treturn nil\n}\n\n// StartTrace calls the dll startTrace C function.\nfunc (etw ETWFunctions) StartTrace(state uintptr) error {\n\trc, _, _ := etw.startTrace.Call(state)\n\tif rc != 0 {\n\t\treturn fmt.Errorf(\"failed with status code: %d\", rc)\n\t}\n\treturn nil\n}\n\n// FlushTrace calls the dll flushTrace C function.\nfunc (etw ETWFunctions) FlushTrace(state uintptr) error {\n\trc, _, _ := etw.flushTrace.Call(state)\n\tif rc != 0 {\n\t\treturn fmt.Errorf(\"failed with status code: %d\", rc)\n\t}\n\treturn nil\n}\n\n// StopTrace calls the dll stopTrace C function.\nfunc (etw ETWFunctions) StopTrace(state uintptr) error {\n\trc, _, _ := etw.stopTrace.Call(state)\n\tif rc != 0 {\n\t\treturn fmt.Errorf(\"failed with status code: %d\", rc)\n\t}\n\treturn nil\n}\n\n// DestroySession calls the dll destroySession C function.\nfunc (etw ETWFunctions) DestroySession(state uintptr) error {\n\trc, _, _ := etw.destroySession.Call(state)\n\tif rc != 0 {\n\t\treturn fmt.Errorf(\"failed with status code: %d\", rc)\n\t}\n\treturn nil\n}\n\n// StopOldSession calls the dll stopOldSession C function.\nfunc (etw ETWFunctions) StopOldSession() error {\n\trc, _, _ := etw.stopOldSession.Call()\n\tif rc != 0 {\n\t\treturn fmt.Errorf(\"failed with status code: %d\", rc)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/integration/integration.go",
    "content": "//go:build !windows\n// +build !windows\n\npackage integration\n\ntype OSSpecific struct{}\n\n// Initialize is empty on any OS different then Windows.\nfunc (i *OSIntegration) Initialize() error {\n\treturn nil\n}\n\n// CleanUp releases any resourses allocated during initializaion.\nfunc (i *OSIntegration) CleanUp() error {\n\treturn nil\n}\n"
  },
  {
    "path": "service/integration/integration_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage integration\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"golang.org/x/sys/windows\"\n)\n\ntype OSSpecific struct {\n\tdll          *windows.DLL\n\tetwFunctions *ETWFunctions\n}\n\n// Initialize loads the dll and finds all the needed functions from it.\nfunc (i *OSIntegration) Initialize() error {\n\t// Try to load dll\n\terr := i.loadDLL()\n\tif err != nil {\n\t\tlog.Errorf(\"integration: failed to load dll: %s\", err)\n\n\t\tcallbackLock := sync.Mutex{}\n\t\t// listen for event from the updater and try to load again if any.\n\t\ti.instance.BinaryUpdates().EventResourcesUpdated.AddCallback(\"core-dll-loader\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\t\t// Make sure no multiple callas are executed at the same time.\n\t\t\tcallbackLock.Lock()\n\t\t\tdefer callbackLock.Unlock()\n\n\t\t\t// Try to load again.\n\t\t\terr = i.loadDLL()\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(\"integration: failed to load dll: %s\", err)\n\t\t\t} else {\n\t\t\t\tlog.Info(\"integration: initialize successful after updater event\")\n\t\t\t}\n\t\t\treturn false, nil\n\t\t})\n\n\t} else {\n\t\tlog.Info(\"integration: initialize successful\")\n\t}\n\treturn nil\n}\n\nfunc (i *OSIntegration) loadDLL() error {\n\t// Find path to the dll.\n\tfile, err := i.instance.BinaryUpdates().GetFile(\"portmaster-core.dll\")\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Load the DLL.\n\ti.os.dll, err = windows.LoadDLL(file.Path())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to load dll: %q\", err)\n\t}\n\n\t// Enumerate all needed dll functions.\n\ti.os.etwFunctions, err = initializeETW(i.os.dll)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Notify listeners\n\ti.OnInitializedEvent.Submit(struct{}{})\n\n\treturn nil\n}\n\n// CleanUp releases any resources allocated during initialization.\nfunc (i *OSIntegration) CleanUp() error {\n\tif i.os.dll != nil {\n\t\treturn i.os.dll.Release()\n\t}\n\treturn nil\n}\n\n// GetETWInterface return struct containing all the ETW related functions, and nil if it was not loaded yet\nfunc (i *OSIntegration) GetETWInterface() *ETWFunctions {\n\treturn i.os.etwFunctions\n}\n"
  },
  {
    "path": "service/integration/module.go",
    "content": "package integration\n\nimport (\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\n// OSIntegration module provides special integration with the OS.\ntype OSIntegration struct {\n\tm *mgr.Manager\n\n\tOnInitializedEvent *mgr.EventMgr[struct{}]\n\n\t//nolint:unused\n\tos OSSpecific\n\n\tinstance instance\n}\n\n// New returns a new OSIntegration module.\nfunc New(instance instance) (*OSIntegration, error) {\n\tm := mgr.New(\"OSIntegration\")\n\tmodule := &OSIntegration{\n\t\tm:                  m,\n\t\tOnInitializedEvent: mgr.NewEventMgr[struct{}](\"on-initialized\", m),\n\t\tinstance:           instance,\n\t}\n\n\treturn module, nil\n}\n\n// Manager returns the module manager.\nfunc (i *OSIntegration) Manager() *mgr.Manager {\n\treturn i.m\n}\n\n// Start starts the module.\nfunc (i *OSIntegration) Start() error {\n\treturn i.Initialize()\n}\n\n// Stop stops the module.\nfunc (i *OSIntegration) Stop() error {\n\treturn i.CleanUp()\n}\n\ntype instance interface {\n\tBinaryUpdates() *updates.Updater\n}\n"
  },
  {
    "path": "service/intel/block_reason.go",
    "content": "package intel\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/nameserver/nsutil\"\n)\n\n// ListMatch represents an entity that has been\n// matched against filterlists.\ntype ListMatch struct {\n\tEntity        string\n\tActiveLists   []string\n\tInactiveLists []string\n}\n\nfunc (lm *ListMatch) String() string {\n\tinactive := \"\"\n\tif len(lm.InactiveLists) > 0 {\n\t\tinactive = \" and in deactivated lists \" + strings.Join(lm.InactiveLists, \", \")\n\t}\n\treturn fmt.Sprintf(\n\t\t\"%s in activated lists %s%s\",\n\t\tlm.Entity,\n\t\tstrings.Join(lm.ActiveLists, \",\"),\n\t\tinactive,\n\t)\n}\n\n// ListBlockReason is a list of list matches.\ntype ListBlockReason []ListMatch\n\nfunc (br ListBlockReason) String() string {\n\tif len(br) == 0 {\n\t\treturn \"\"\n\t}\n\n\tmatches := make([]string, len(br))\n\tfor idx, lm := range br {\n\t\tmatches[idx] = lm.String()\n\t}\n\n\treturn strings.Join(matches, \" and \")\n}\n\n// Context returns br wrapped into a map. It implements\n// the endpoints.Reason interface.\nfunc (br ListBlockReason) Context() interface{} {\n\treturn br\n}\n\n// MarshalJSON marshals the list block reason into a map\n// prefixed with filterlists.\nfunc (br ListBlockReason) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(map[string]interface{}{\n\t\t// we convert to []ListMatch to avoid recursing\n\t\t// here.\n\t\t\"filterlists\": []ListMatch(br),\n\t})\n}\n\n// GetExtraRRs implements the nsutil.RRProvider interface\n// and adds additional TXT records justifying the reason\n// the request was blocked.\nfunc (br ListBlockReason) GetExtraRRs(ctx context.Context, _ *dns.Msg) []dns.RR {\n\trrs := make([]dns.RR, 0, len(br))\n\n\tfor _, lm := range br {\n\t\tblockedBy, err := nsutil.MakeMessageRecord(log.InfoLevel, fmt.Sprintf(\n\t\t\t\"%s is blocked by filter lists %s\",\n\t\t\tlm.Entity,\n\t\t\tstrings.Join(lm.ActiveLists, \", \"),\n\t\t))\n\t\tif err == nil {\n\t\t\trrs = append(rrs, blockedBy)\n\t\t} else {\n\t\t\tlog.Tracer(ctx).Errorf(\"intel: failed to create TXT RR for block reason: %s\", err)\n\t\t}\n\n\t\tif len(lm.InactiveLists) > 0 {\n\t\t\twouldBeBlockedBy, err := nsutil.MakeMessageRecord(log.InfoLevel, fmt.Sprintf(\n\t\t\t\t\"%s would be blocked by filter lists %s\",\n\t\t\t\tlm.Entity,\n\t\t\t\tstrings.Join(lm.InactiveLists, \", \"),\n\t\t\t))\n\t\t\tif err == nil {\n\t\t\t\trrs = append(rrs, wouldBeBlockedBy)\n\t\t\t} else {\n\t\t\t\tlog.Tracer(ctx).Errorf(\"intel: failed to create TXT RR for block reason: %s\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn rrs\n}\n\nvar _ nsutil.RRProvider = ListBlockReason(nil)\n"
  },
  {
    "path": "service/intel/customlists/config.go",
    "content": "package customlists\n\nimport (\n\t\"github.com/safing/portmaster/base/config\"\n)\n\nvar (\n\t// CfgOptionCustomListFileKey is the config key for custom filter list file.\n\tCfgOptionCustomListFileKey            = \"filter/customListFile\"\n\tcfgOptionCustomListFileOrder          = 35\n\tcfgOptionCustomListCategoryAnnotation = \"Filter Lists\"\n)\n\nvar getFilePath config.StringOption\n\nfunc registerConfig() error {\n\thelp := `The file (.txt) is checked every couple minutes and will be automatically reloaded when it has changed.  \n\nEntries (one per line) may be one of:\n- Domain: \"example.com\"\n- IP Address: \"10.0.0.1\"\n- Country Code (based on IP): \"US\"\n- AS (Autonomous System): \"AS1234\"  \n\nEverything after the first element of a line, comments starting with a '#', and empty lines are ignored.  \nThe settings \"Block Subdomains of Filter List Entries\" and \"Block Domain Aliases\" also apply to the custom filter list.  \nLists in the \"Hosts\" format are not supported.  \n\nPlease note that the custom filter list is fully loaded into memory. This can have a negative impact on your device if big lists are loaded.`\n\n\t// Register a setting for the file path in the ui\n\terr := config.Register(&config.Option{\n\t\tName:            \"Custom Filter List\",\n\t\tKey:             CfgOptionCustomListFileKey,\n\t\tDescription:     \"Specify the file path to a custom filter list (.txt), which will be automatically refreshed. Any connections matching a domain, IP address, Country or ASN in the file will be blocked.\",\n\t\tHelp:            help,\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tDefaultValue:    \"\",\n\t\tRequiresRestart: false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionCustomListFileOrder,\n\t\t\tconfig.CategoryAnnotation:     cfgOptionCustomListCategoryAnnotation,\n\t\t\tconfig.DisplayHintAnnotation:  config.DisplayHintFilePicker,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgetFilePath = config.GetAsString(CfgOptionCustomListFileKey, \"\")\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/intel/customlists/lists.go",
    "content": "package customlists\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\nvar (\n\tcountryCodesFilterList      map[string]struct{}\n\tipAddressesFilterList       map[string]struct{}\n\tautonomousSystemsFilterList map[uint]struct{}\n\tdomainsFilterList           map[string]struct{}\n)\n\nconst (\n\trationForInvalidLinesUntilWarning = 0.1\n\tparseStatusNotificationID         = \"customlists:parse-status\"\n\tparseWarningNotificationID        = \"customlists:parse-warning\"\n\tzeroIPNotificationID              = \"customlists:too-many-zero-ips\"\n)\n\nfunc initFilterLists() {\n\tcountryCodesFilterList = make(map[string]struct{})\n\tipAddressesFilterList = make(map[string]struct{})\n\tautonomousSystemsFilterList = make(map[uint]struct{})\n\tdomainsFilterList = make(map[string]struct{})\n}\n\n// IsLoaded returns whether a custom filter list is loaded.\nfunc IsLoaded() bool {\n\tfilterListLock.RLock()\n\tdefer filterListLock.RUnlock()\n\n\tswitch {\n\tcase len(domainsFilterList) > 0:\n\t\treturn true\n\tcase len(ipAddressesFilterList) > 0:\n\t\treturn true\n\tcase len(countryCodesFilterList) > 0:\n\t\treturn true\n\tcase len(autonomousSystemsFilterList) > 0:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc parseFile(filePath string) error {\n\t// Reset all maps, previous (if any) settings will be lost.\n\tfor key := range countryCodesFilterList {\n\t\tdelete(countryCodesFilterList, key)\n\t}\n\tfor key := range ipAddressesFilterList {\n\t\tdelete(ipAddressesFilterList, key)\n\t}\n\tfor key := range autonomousSystemsFilterList {\n\t\tdelete(autonomousSystemsFilterList, key)\n\t}\n\tfor key := range domainsFilterList {\n\t\tdelete(domainsFilterList, key)\n\t}\n\n\t// Ignore empty file path.\n\tif filePath == \"\" {\n\t\treturn nil\n\t}\n\n\t// Open the file if possible\n\tfile, err := os.Open(filePath)\n\tif err != nil {\n\t\tlog.Warningf(\"intel/customlists: failed to parse file %s\", err)\n\t\tmodule.states.Add(mgr.State{\n\t\t\tID:      parseWarningNotificationID,\n\t\t\tName:    \"Failed to open custom filter list\",\n\t\t\tMessage: err.Error(),\n\t\t\tType:    mgr.StateTypeWarning,\n\t\t})\n\t\treturn err\n\t} else {\n\t\tmodule.states.Remove(parseWarningNotificationID)\n\t}\n\tdefer func() { _ = file.Close() }()\n\n\tvar allLinesCount uint64\n\tvar invalidLinesCount uint64\n\n\t// Read filter file line by line.\n\tscanner := bufio.NewScanner(file)\n\t// The scanner will error out if the line is greater than 64K, in this case it is enough.\n\tfor scanner.Scan() {\n\t\tallLinesCount++\n\t\t// Parse and count invalid lines (comment, empty lines, zero IPs...)\n\t\tif !parseLine(scanner.Text()) {\n\t\t\tinvalidLinesCount++\n\t\t}\n\t}\n\n\t// Check for scanner error.\n\tif err := scanner.Err(); err != nil {\n\t\treturn err\n\t}\n\n\tinvalidLinesRation := float32(invalidLinesCount) / float32(allLinesCount)\n\n\tif invalidLinesRation > rationForInvalidLinesUntilWarning {\n\t\tlog.Warning(\"intel/customlists: Too many invalid lines\")\n\t\tmodule.states.Add(mgr.State{\n\t\t\tID:   zeroIPNotificationID,\n\t\t\tName: \"Custom filter list has many invalid lines\",\n\t\t\tMessage: fmt.Sprintf(`%d out of %d lines are invalid.\n\t\t\t Check if you are using the correct file format and if the path to the custom filter list is correct.`, invalidLinesCount, allLinesCount),\n\t\t\tType: mgr.StateTypeWarning,\n\t\t})\n\t} else {\n\t\tmodule.states.Remove(zeroIPNotificationID)\n\t}\n\n\tallEntriesCount := len(domainsFilterList) + len(ipAddressesFilterList) + len(autonomousSystemsFilterList) + len(countryCodesFilterList)\n\tlog.Infof(\"intel/customlists: loaded %d entries from %s\", allEntriesCount, filePath)\n\n\tnotifications.NotifyInfo(parseStatusNotificationID,\n\t\t\"Custom filter list loaded successfully.\",\n\t\tfmt.Sprintf(`Custom filter list loaded from file %s:  \n%d Domains  \n%d IPs  \n%d Autonomous Systems  \n%d Countries`,\n\t\t\tfilePath,\n\t\t\tlen(domainsFilterList),\n\t\t\tlen(ipAddressesFilterList),\n\t\t\tlen(autonomousSystemsFilterList),\n\t\t\tlen(countryCodesFilterList)))\n\n\treturn nil\n}\n\nfunc parseLine(line string) (valid bool) {\n\t// Everything after the first field will be ignored.\n\tfields := strings.Fields(line)\n\n\t// Ignore empty lines.\n\tif len(fields) == 0 {\n\t\treturn true // Not an entry, but a valid line.\n\t}\n\n\tfield := fields[0]\n\n\t// Ignore comments\n\tif strings.HasPrefix(field, \"#\") {\n\t\treturn true // Not an entry, but a valid line.\n\t}\n\n\t// Go through all possible field types.\n\t// Parsing is ordered by\n\t// 1. Parsing options (ie. the domain has most variation and goes last.)\n\t// 2. Speed\n\n\t// Check if it'a a country code.\n\tif isCountryCode(field) {\n\t\tcountryCodesFilterList[field] = struct{}{}\n\t\treturn true\n\t}\n\n\t// Check if it's a Autonomous system (example AS123).\n\tif isAutonomousSystem(field) {\n\t\tasNumber, err := strconv.ParseUint(field[2:], 10, 32)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tautonomousSystemsFilterList[uint(asNumber)] = struct{}{}\n\t\treturn true\n\t}\n\n\t// Try to parse IP address.\n\tip := net.ParseIP(field)\n\tif ip != nil {\n\t\t// Check for zero ip.\n\t\tif net.IP.Equal(ip, net.IPv4zero) || net.IP.Equal(ip, net.IPv6zero) {\n\t\t\treturn false\n\t\t}\n\n\t\tipAddressesFilterList[ip.String()] = struct{}{}\n\t\treturn true\n\t}\n\n\t// Check if it's a domain.\n\tdomain := dns.Fqdn(field)\n\tif netutils.IsValidFqdn(domain) {\n\t\tdomainsFilterList[domain] = struct{}{}\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "service/intel/customlists/module.go",
    "content": "package customlists\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"golang.org/x/net/publicsuffix\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\ntype CustomList struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tupdateFilterListWorkerMgr *mgr.WorkerMgr\n\n\tstates *mgr.StateMgr\n}\n\nfunc (cl *CustomList) Manager() *mgr.Manager {\n\treturn cl.mgr\n}\n\nfunc (cl *CustomList) States() *mgr.StateMgr {\n\treturn cl.states\n}\n\nfunc (cl *CustomList) Start() error {\n\treturn start()\n}\n\nfunc (cl *CustomList) Stop() error {\n\treturn nil\n}\n\n// Helper variables for parsing the input file.\nvar (\n\tisCountryCode      = regexp.MustCompile(\"^[A-Z]{2}$\").MatchString\n\tisAutonomousSystem = regexp.MustCompile(`^AS[0-9]+$`).MatchString\n)\n\nvar (\n\tfilterListFilePath         string\n\tfilterListFileModifiedTime time.Time\n\n\tfilterListLock sync.RWMutex\n\n\t// ErrNotConfigured is returned when updating the custom filter list, but it\n\t// is not configured.\n\tErrNotConfigured = errors.New(\"custom filter list not configured\")\n)\n\nfunc prep() error {\n\tinitFilterLists()\n\n\t// Register the config in the ui.\n\terr := registerConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Register api endpoint for updating the filter list.\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:  \"customlists/update\",\n\t\tWrite: api.PermitUser,\n\t\tActionFunc: func(ar *api.Request) (msg string, err error) {\n\t\t\terrCheck := checkAndUpdateFilterList(nil)\n\t\t\tif errCheck != nil {\n\t\t\t\treturn \"\", errCheck\n\t\t\t}\n\t\t\treturn \"Custom filter list loaded successfully.\", nil\n\t\t},\n\t\tName:        \"Update custom filter list\",\n\t\tDescription: \"Reload the filter list from the configured file.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc start() error {\n\t// Register to hook to update after config change.\n\tmodule.instance.Config().EventConfigChange.AddCallback(\n\t\t\"update custom filter list\",\n\t\tfunc(wc *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\terr := checkAndUpdateFilterList(wc)\n\t\t\tif !errors.Is(err, ErrNotConfigured) {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\treturn false, nil\n\t\t},\n\t)\n\n\t// Create parser task and enqueue for execution. \"checkAndUpdateFilterList\" will schedule the next execution.\n\tmodule.updateFilterListWorkerMgr.Delay(20 * time.Second).Repeat(1 * time.Minute)\n\n\treturn nil\n}\n\nfunc checkAndUpdateFilterList(_ *mgr.WorkerCtx) error {\n\tfilterListLock.Lock()\n\tdefer filterListLock.Unlock()\n\n\t// Get path and return error if empty\n\tfilePath := getFilePath()\n\tif filePath == \"\" {\n\t\treturn ErrNotConfigured\n\t}\n\n\t// Try to get file info\n\tmodifiedTime := time.Now()\n\tif fileInfo, err := os.Stat(filePath); err == nil {\n\t\tmodifiedTime = fileInfo.ModTime()\n\t}\n\n\t// Check if file path has changed or if modified time has changed\n\tif filterListFilePath != filePath || !filterListFileModifiedTime.Equal(modifiedTime) {\n\t\terr := parseFile(filePath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfilterListFileModifiedTime = modifiedTime\n\t\tfilterListFilePath = filePath\n\t}\n\treturn nil\n}\n\n// LookupIP checks if the IP address is in a custom filter list.\nfunc LookupIP(ip net.IP) bool {\n\tfilterListLock.RLock()\n\tdefer filterListLock.RUnlock()\n\n\t_, ok := ipAddressesFilterList[ip.String()]\n\treturn ok\n}\n\n// LookupDomain checks if the Domain is in a custom filter list.\nfunc LookupDomain(fullDomain string, filterSubdomains bool) (bool, string) {\n\tfilterListLock.RLock()\n\tdefer filterListLock.RUnlock()\n\n\tif filterSubdomains {\n\t\t// Check if domain is in the list and all its subdomains.\n\t\tlistOfDomains := splitDomain(fullDomain)\n\t\tfor _, domain := range listOfDomains {\n\t\t\t_, ok := domainsFilterList[domain]\n\t\t\tif ok {\n\t\t\t\treturn true, domain\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Check only if the domain is in the list\n\t\t_, ok := domainsFilterList[fullDomain]\n\t\treturn ok, fullDomain\n\t}\n\treturn false, \"\"\n}\n\n// LookupASN checks if the Autonomous system number is in a custom filter list.\nfunc LookupASN(number uint) bool {\n\tfilterListLock.RLock()\n\tdefer filterListLock.RUnlock()\n\n\t_, ok := autonomousSystemsFilterList[number]\n\treturn ok\n}\n\n// LookupCountry checks if the country code is in a custom filter list.\nfunc LookupCountry(countryCode string) bool {\n\tfilterListLock.RLock()\n\tdefer filterListLock.RUnlock()\n\n\t_, ok := countryCodesFilterList[countryCode]\n\treturn ok\n}\n\nfunc splitDomain(domain string) []string {\n\tdomain = strings.Trim(domain, \".\")\n\tsuffix, _ := publicsuffix.PublicSuffix(domain)\n\tif suffix == domain {\n\t\treturn []string{domain}\n\t}\n\n\tdomainWithoutSuffix := domain[:len(domain)-len(suffix)]\n\tdomainWithoutSuffix = strings.Trim(domainWithoutSuffix, \".\")\n\n\tsplitted := strings.FieldsFunc(domainWithoutSuffix, func(r rune) bool {\n\t\treturn r == '.'\n\t})\n\n\tdomains := make([]string, 0, len(splitted))\n\tfor idx := range splitted {\n\n\t\td := strings.Join(splitted[idx:], \".\") + \".\" + suffix\n\t\tif d[len(d)-1] != '.' {\n\t\t\td += \".\"\n\t\t}\n\t\tdomains = append(domains, d)\n\t}\n\treturn domains\n}\n\nvar (\n\tmodule     *CustomList\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new CustomList module.\nfunc New(instance instance) (*CustomList, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"CustomList\")\n\tmodule = &CustomList{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tstates: mgr.NewStateMgr(m),\n\t\tupdateFilterListWorkerMgr: m.NewWorkerMgr(\n\t\t\t\"update custom filter list\",\n\t\t\tfunc(ctx *mgr.WorkerCtx) error {\n\t\t\t\terr := checkAndUpdateFilterList(ctx)\n\t\t\t\tif !errors.Is(err, ErrNotConfigured) {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\tnil,\n\t\t),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tConfig() *config.Config\n}\n"
  },
  {
    "path": "service/intel/entity.go",
    "content": "package intel\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"golang.org/x/net/publicsuffix\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel/filterlists\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\n// Entity describes a remote endpoint in many different ways.\n// It embeddes a sync.Mutex but none of the endpoints own\n// functions performs locking. The caller MUST ENSURE\n// proper locking and synchronization when accessing\n// any properties of Entity.\ntype Entity struct { //nolint:maligned\n\tsync.Mutex\n\n\t// lists exist for most entity information and\n\t// we need to know which one we loaded\n\tdomainListLoaded      bool\n\tipListLoaded          bool\n\tcountryListLoaded     bool\n\tasnListLoaded         bool\n\treverseResolveEnabled bool\n\tresolveSubDomainLists bool\n\tcheckCNAMEs           bool\n\n\t// IP is the IP address of the connection. If domain is\n\t// set, IP has been resolved by following all CNAMEs.\n\tIP net.IP\n\n\t// IPScope holds the network scope of the IP.\n\t// For DNS requests, this signifies in which scope the DNS request was resolved.\n\tIPScope netutils.IPScope\n\n\t// Protocol is the protcol number used by the connection.\n\tProtocol uint8\n\n\t// Port is the remote port of the connection\n\tPort uint16\n\n\t// dstPort is the destination port of the connection\n\tdstPort uint16\n\n\t// Domain is the target domain of the connection.\n\tDomain string\n\n\t// ReverseDomain is the domain the IP address points to. This is only\n\t// resolved and populated when needed.\n\tReverseDomain string\n\n\t// CNAME is a list of domain names that have been\n\t// resolved for Domain.\n\tCNAME []string\n\n\t// Country holds the country the IP address (ASN) is\n\t// located in.\n\tCountry string\n\n\t// Coordinates holds the approximate coordinates of the IP address.\n\tCoordinates *geoip.Coordinates\n\n\t// ASN holds the autonomous system number of the IP.\n\tASN uint\n\n\t// ASOrg holds the owner's name of the autonomous system.\n\tASOrg string\n\n\t// LocationError holds an error message if fetching the location failed.\n\tLocationError string\n\n\tlocation *geoip.Location\n\n\t// BlockedByLists holds list source IDs that\n\t// are used to block the entity.\n\tBlockedByLists []string\n\n\t// BlockedEntities holds a list of entities that\n\t// have been blocked. Values can be used as a key\n\t// for the ListOccurences map.\n\tBlockedEntities []string\n\n\t// ListOccurences is a map that matches an entity (Domain, IPs, ASN, Country, Sub-domain)\n\t// to a list of sources where the entity has been observed in.\n\tListOccurences map[string][]string\n\n\t// ListsError holds an error message if fetching the lists failed.\n\tListsError string\n\n\t// we only load each data above at most once\n\tfetchLocationOnce   sync.Once\n\treverseResolveOnce  sync.Once\n\tloadDomainListOnce  sync.Once\n\tloadIPListOnce      sync.Once\n\tloadCountryListOnce sync.Once\n\tloadAsnListOnce     sync.Once\n}\n\n// Init initializes internal metadata about the entity.\n// If the entity does not describe a destination, you can supply a different\n// destination port for endpoint matching.\n// It returns the entity itself for single line formatting.\nfunc (e *Entity) Init(dstPort uint16) *Entity {\n\t// Get IP scope.\n\tif e.IP != nil {\n\t\te.IPScope = netutils.GetIPScope(e.IP)\n\t} else {\n\t\te.IPScope = netutils.Undefined\n\t}\n\n\t// Set dst port to given value or fall back to entity.\n\tif dstPort > 0 {\n\t\te.dstPort = dstPort\n\t} else {\n\t\te.dstPort = e.Port\n\t}\n\n\treturn e\n}\n\n// DstPort returns the destination port.\nfunc (e *Entity) DstPort() uint16 {\n\treturn e.dstPort\n}\n\n// FetchData fetches additional information, meant to be called before persisting an entity record.\nfunc (e *Entity) FetchData(ctx context.Context) {\n\te.getLocation(ctx)\n\te.getLists(ctx)\n}\n\n// ResetLists resets the current list data and forces\n// all list sources to be re-acquired when calling GetLists().\nfunc (e *Entity) ResetLists() {\n\t// TODO(ppacher): our actual goal is to reset the domain\n\t// list right now so we could be more efficient by keeping\n\t// the other lists around.\n\n\te.BlockedByLists = nil\n\te.BlockedEntities = nil\n\te.ListOccurences = nil\n\n\te.domainListLoaded = false\n\te.ipListLoaded = false\n\te.countryListLoaded = false\n\te.asnListLoaded = false\n\te.resolveSubDomainLists = false\n\te.checkCNAMEs = false\n\te.loadDomainListOnce = sync.Once{}\n\te.loadIPListOnce = sync.Once{}\n\te.loadCountryListOnce = sync.Once{}\n\te.loadAsnListOnce = sync.Once{}\n}\n\n// ResolveSubDomainLists enables or disables list lookups for\n// sub-domains.\nfunc (e *Entity) ResolveSubDomainLists(ctx context.Context, enabled bool) {\n\tif e.domainListLoaded && enabled != e.resolveSubDomainLists {\n\t\tlog.Tracer(ctx).Warningf(\"intel/filterlists: tried to change sub-domain resolving for %s but lists are already fetched\", e.Domain)\n\t}\n\te.resolveSubDomainLists = enabled\n}\n\n// EnableCNAMECheck enalbes or disables list lookups for\n// entity CNAMEs.\nfunc (e *Entity) EnableCNAMECheck(ctx context.Context, enabled bool) {\n\tif e.domainListLoaded && enabled != e.checkCNAMEs {\n\t\tlog.Tracer(ctx).Warningf(\"intel/filterlists: tried to change CNAME resolving for %s but lists are already fetched\", e.Domain)\n\t}\n\te.checkCNAMEs = enabled\n}\n\n// CNAMECheckEnabled returns true if the entities CNAMEs should\n// also be checked.\nfunc (e *Entity) CNAMECheckEnabled() bool {\n\treturn e.checkCNAMEs\n}\n\n// Domain and IP\n\n// EnableReverseResolving enables reverse resolving the domain from the IP on demand.\nfunc (e *Entity) EnableReverseResolving() {\n\te.reverseResolveEnabled = true\n}\n\nfunc (e *Entity) reverseResolve(ctx context.Context) {\n\te.reverseResolveOnce.Do(func() {\n\t\t// need IP!\n\t\tif e.IP == nil {\n\t\t\treturn\n\t\t}\n\n\t\t// reverse resolve\n\t\tif reverseResolver == nil {\n\t\t\treturn\n\t\t}\n\t\t// TODO: security level\n\t\tdomain, err := reverseResolver(ctx, e.IP.String())\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Warningf(\"intel: failed to resolve IP %s: %s\", e.IP, err)\n\t\t\treturn\n\t\t}\n\t\te.ReverseDomain = domain\n\t})\n}\n\n// GetDomain returns the domain and whether it is set.\nfunc (e *Entity) GetDomain(ctx context.Context, mayUseReverseDomain bool) (string, bool) {\n\tif mayUseReverseDomain && e.reverseResolveEnabled {\n\t\te.reverseResolve(ctx)\n\n\t\tif e.ReverseDomain == \"\" {\n\t\t\treturn \"\", false\n\t\t}\n\t\treturn e.ReverseDomain, true\n\t}\n\n\tif e.Domain == \"\" {\n\t\treturn \"\", false\n\t}\n\treturn e.Domain, true\n}\n\n// GetIP returns the IP and whether it is set.\nfunc (e *Entity) GetIP() (net.IP, bool) {\n\tif e.IP == nil {\n\t\treturn nil, false\n\t}\n\treturn e.IP, true\n}\n\n// Location\n\nfunc (e *Entity) getLocation(ctx context.Context) {\n\te.fetchLocationOnce.Do(func() {\n\t\t// Only check if we have a global IP address.\n\t\tif e.IP == nil || !e.IPScope.IsGlobal() {\n\t\t\treturn\n\t\t}\n\n\t\t// get location data\n\t\tloc, err := geoip.GetLocation(e.IP)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Warningf(\"intel: failed to get location data for %s: %s\", e.IP, err)\n\t\t\te.LocationError = err.Error()\n\t\t\treturn\n\t\t}\n\t\te.location = loc\n\t\te.Country = loc.Country.Code\n\t\te.Coordinates = &loc.Coordinates\n\t\te.ASN = loc.AutonomousSystemNumber\n\t\te.ASOrg = loc.AutonomousSystemOrganization\n\n\t\t// Log result.\n\t\tif log.GetLogLevel() == log.TraceLevel {\n\t\t\t// Build flags\n\t\t\tvar flags string\n\t\t\tif loc.IsAnycast {\n\t\t\t\tflags += \" anycast\"\n\t\t\t}\n\t\t\tif loc.IsSatelliteProvider {\n\t\t\t\tflags += \" satellite\"\n\t\t\t}\n\t\t\tif loc.IsAnonymousProxy {\n\t\t\t\tflags += \" anonymous\"\n\t\t\t}\n\n\t\t\t// Log location\n\t\t\tlog.Tracer(ctx).Tracef(\n\t\t\t\t\"intel: located %s in %s (%s), as part of AS%d by %s%s\",\n\t\t\t\te.IP,\n\t\t\t\tloc.Country.Name,\n\t\t\t\tloc.Country.Code,\n\t\t\t\tloc.AutonomousSystemNumber,\n\t\t\t\tloc.AutonomousSystemOrganization,\n\t\t\t\tflags,\n\t\t\t)\n\t\t}\n\t})\n}\n\n// GetLocation returns the raw location data and whether it is set.\nfunc (e *Entity) GetLocation(ctx context.Context) (*geoip.Location, bool) {\n\te.getLocation(ctx)\n\n\tif e.location == nil {\n\t\treturn nil, false\n\t}\n\treturn e.location, true\n}\n\n// GetCountry returns the two letter ISO country code and whether it is set.\nfunc (e *Entity) GetCountry(ctx context.Context) (string, bool) {\n\te.getLocation(ctx)\n\n\tif e.LocationError != \"\" {\n\t\treturn \"\", false\n\t}\n\treturn e.Country, true\n}\n\n// GetCountryInfo returns the two letter ISO country code and whether it is set.\nfunc (e *Entity) GetCountryInfo(ctx context.Context) *geoip.CountryInfo {\n\te.getLocation(ctx)\n\n\tif e.LocationError != \"\" {\n\t\treturn nil\n\t}\n\treturn &e.location.Country\n}\n\n// GetASN returns the AS number and whether it is set.\nfunc (e *Entity) GetASN(ctx context.Context) (uint, bool) {\n\te.getLocation(ctx)\n\n\tif e.LocationError != \"\" {\n\t\treturn 0, false\n\t}\n\treturn e.ASN, true\n}\n\n// Lists\n\nfunc (e *Entity) getLists(ctx context.Context) {\n\te.getDomainLists(ctx)\n\te.getASNLists(ctx)\n\te.getIPLists(ctx)\n\te.getCountryLists(ctx)\n}\n\nfunc (e *Entity) mergeList(key string, list []string) {\n\tif len(list) == 0 {\n\t\treturn\n\t}\n\n\tif e.ListOccurences == nil {\n\t\te.ListOccurences = make(map[string][]string)\n\t}\n\n\te.ListOccurences[key] = mergeStringList(e.ListOccurences[key], list)\n}\n\nfunc (e *Entity) getDomainLists(ctx context.Context) {\n\tif e.domainListLoaded {\n\t\treturn\n\t}\n\n\tdomain, ok := e.GetDomain(ctx, false /* mayUseReverseDomain */)\n\tif !ok {\n\t\treturn\n\t}\n\n\te.loadDomainListOnce.Do(func() {\n\t\tdomainsToInspect := []string{domain}\n\n\t\tif e.checkCNAMEs && len(e.CNAME) > 0 {\n\t\t\tlog.Tracer(ctx).Tracef(\"intel: CNAME filtering enabled, checking %v too\", e.CNAME)\n\t\t\tdomainsToInspect = append(domainsToInspect, e.CNAME...)\n\t\t}\n\n\t\tvar domains []string\n\t\tif e.resolveSubDomainLists {\n\t\t\tfor _, domain := range domainsToInspect {\n\t\t\t\tsubdomains := splitDomain(domain)\n\t\t\t\tdomains = append(domains, subdomains...)\n\t\t\t}\n\t\t} else {\n\t\t\tdomains = domainsToInspect\n\t\t}\n\n\t\tdomains = makeDistinct(domains)\n\n\t\tfor _, d := range domains {\n\t\t\tlist, err := filterlists.LookupDomain(d)\n\t\t\tif err != nil {\n\t\t\t\tlog.Tracer(ctx).Errorf(\"intel: failed to get domain blocklists for %s: %s\", d, err)\n\t\t\t\te.ListsError = err.Error()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif len(list) > 0 {\n\t\t\t\tlog.Tracer(ctx).Tracef(\"intel: loaded domain lists for %s: %s\", d, strings.Join(list, \", \"))\n\t\t\t\te.mergeList(d, list)\n\t\t\t}\n\t\t}\n\t\te.domainListLoaded = true\n\t})\n}\n\nfunc splitDomain(domain string) []string {\n\t// Get suffix.\n\td := strings.TrimSuffix(domain, \".\")\n\tsuffix, icann := publicsuffix.PublicSuffix(d)\n\tif suffix == d {\n\t\treturn []string{domain}\n\t}\n\n\t// Split all subdomain into labels.\n\tlabels := strings.FieldsFunc(d[:len(d)-len(suffix)], func(r rune) bool {\n\t\treturn r == '.'\n\t})\n\n\t// Build list of all domains up to the public suffix.\n\tdomains := make([]string, 0, len(labels)+1)\n\tfor idx := range labels {\n\t\tdomains = append(\n\t\t\tdomains,\n\t\t\tstrings.Join(labels[idx:], \".\")+\".\"+suffix+\".\",\n\t\t)\n\t}\n\n\t// If the suffix is not a real TLD, but a public suffix, add it to the list.\n\tif !icann {\n\t\tdomains = append(domains, suffix+\".\")\n\t}\n\n\treturn domains\n}\n\nfunc (e *Entity) getASNLists(ctx context.Context) {\n\tif e.asnListLoaded {\n\t\treturn\n\t}\n\n\tasn, ok := e.GetASN(ctx)\n\tif !ok || asn == 0 {\n\t\treturn\n\t}\n\n\te.loadAsnListOnce.Do(func() {\n\t\tasnStr := strconv.FormatUint(uint64(asn), 10)\n\t\tlist, err := filterlists.LookupASNString(asnStr)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Errorf(\"intel: failed to get ASN blocklist for %d: %s\", asn, err)\n\t\t\te.ListsError = err.Error()\n\t\t\treturn\n\t\t}\n\n\t\tif len(list) > 0 {\n\t\t\tlog.Tracer(ctx).Tracef(\"intel: loaded ASN lists for %s: %s\", asnStr, strings.Join(list, \", \"))\n\t\t\te.mergeList(asnStr, list)\n\t\t}\n\n\t\te.asnListLoaded = true\n\t})\n}\n\nfunc (e *Entity) getCountryLists(ctx context.Context) {\n\tif e.countryListLoaded {\n\t\treturn\n\t}\n\n\tcountry, ok := e.GetCountry(ctx)\n\tif !ok || country == \"\" {\n\t\treturn\n\t}\n\n\te.loadCountryListOnce.Do(func() {\n\t\tlist, err := filterlists.LookupCountry(country)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Errorf(\"intel: failed to load country blocklist for %s: %s\", country, err)\n\t\t\te.ListsError = err.Error()\n\t\t\treturn\n\t\t}\n\n\t\tif len(list) > 0 {\n\t\t\tlog.Tracer(ctx).Tracef(\"intel: loaded country lists for %s: %s\", country, strings.Join(list, \", \"))\n\t\t\te.mergeList(country, list)\n\t\t}\n\n\t\te.countryListLoaded = true\n\t})\n}\n\nfunc (e *Entity) getIPLists(ctx context.Context) {\n\tif e.ipListLoaded {\n\t\treturn\n\t}\n\n\tip, ok := e.GetIP()\n\tif !ok || ip == nil {\n\t\treturn\n\t}\n\n\t// only load lists for IP addresses that are classified as global.\n\tif !e.IPScope.IsGlobal() {\n\t\treturn\n\t}\n\n\te.loadIPListOnce.Do(func() {\n\t\tlist, err := filterlists.LookupIP(ip)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Errorf(\"intel: failed to get IP blocklist for %s: %s\", ip.String(), err)\n\t\t\te.ListsError = err.Error()\n\t\t\treturn\n\t\t}\n\n\t\tif len(list) > 0 {\n\t\t\tlog.Tracer(ctx).Tracef(\"intel: loaded IP lists for %s: %s\", ip.String(), strings.Join(list, \", \"))\n\t\t\te.mergeList(ip.String(), list)\n\t\t}\n\n\t\te.ipListLoaded = true\n\t})\n}\n\n// LoadLists searches all filterlists for all occurrences of\n// this entity.\nfunc (e *Entity) LoadLists(ctx context.Context) {\n\te.getLists(ctx)\n}\n\n// MatchLists matches the entities lists against a slice\n// of source IDs and  updates various entity properties\n// like BlockedByLists, ListOccurences and BlockedEntitites.\nfunc (e *Entity) MatchLists(lists []string) bool {\n\tif len(lists) == 0 {\n\t\treturn false\n\t}\n\n\te.BlockedByLists = nil\n\te.BlockedEntities = nil\n\n\tlm := makeMap(lists)\n\tfor key, keyLists := range e.ListOccurences {\n\t\tfor _, keyListID := range keyLists {\n\t\t\tif _, ok := lm[keyListID]; ok {\n\t\t\t\te.BlockedByLists = append(e.BlockedByLists, keyListID)\n\t\t\t\te.BlockedEntities = append(e.BlockedEntities, key)\n\t\t\t}\n\t\t}\n\t}\n\n\te.BlockedByLists = makeDistinct(e.BlockedByLists)\n\te.BlockedEntities = makeDistinct(e.BlockedEntities)\n\n\treturn len(e.BlockedByLists) > 0\n}\n\n// ListBlockReason returns the block reason for this entity.\nfunc (e *Entity) ListBlockReason() ListBlockReason {\n\tblockedBy := make([]ListMatch, len(e.BlockedEntities))\n\n\tlm := makeMap(e.BlockedByLists)\n\n\tfor idx, blockedEntity := range e.BlockedEntities {\n\t\tif entityLists, ok := e.ListOccurences[blockedEntity]; ok {\n\t\t\tvar activeLists []string\n\t\t\tvar inactiveLists []string\n\n\t\t\tfor _, l := range entityLists {\n\t\t\t\tif _, ok := lm[l]; ok {\n\t\t\t\t\tactiveLists = append(activeLists, l)\n\t\t\t\t} else {\n\t\t\t\t\tinactiveLists = append(inactiveLists, l)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tblockedBy[idx] = ListMatch{\n\t\t\t\tEntity:        blockedEntity,\n\t\t\t\tActiveLists:   activeLists,\n\t\t\t\tInactiveLists: inactiveLists,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn blockedBy\n}\n\nfunc mergeStringList(a, b []string) []string {\n\tlistMap := make(map[string]struct{})\n\tfor _, s := range a {\n\t\tlistMap[s] = struct{}{}\n\t}\n\tfor _, s := range b {\n\t\tlistMap[s] = struct{}{}\n\t}\n\n\tres := make([]string, 0, len(listMap))\n\tfor s := range listMap {\n\t\tres = append(res, s)\n\t}\n\tsort.Strings(res)\n\treturn res\n}\n\nfunc makeDistinct(slice []string) []string {\n\tm := make(map[string]struct{}, len(slice))\n\tresult := make([]string, 0, len(slice))\n\n\tfor _, v := range slice {\n\t\tif _, ok := m[v]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tm[v] = struct{}{}\n\t\tresult = append(result, v)\n\t}\n\n\treturn result\n}\n\nfunc makeMap(slice []string) map[string]struct{} {\n\tlm := make(map[string]struct{})\n\tfor _, v := range slice {\n\t\tlm[v] = struct{}{}\n\t}\n\treturn lm\n}\n"
  },
  {
    "path": "service/intel/entity_test.go",
    "content": "package intel\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar splitDomainTestCases = [][]string{\n\t// Regular registered domains and subdomains.\n\t{\"example.com.\"},\n\t{\"www.example.com.\", \"example.com.\"},\n\t{\"sub.domain.example.com.\", \"domain.example.com.\", \"example.com.\"},\n\t{\"example.co.uk.\"},\n\t{\"www.example.co.uk.\", \"example.co.uk.\"},\n\n\t// TLD or public suffix: Return as is.\n\t{\"com.\"},\n\t{\"googleapis.com.\"},\n\n\t// Public suffix domains: Return including public suffix.\n\t{\"test.googleapis.com.\", \"googleapis.com.\"},\n\t{\"sub.domain.googleapis.com.\", \"domain.googleapis.com.\", \"googleapis.com.\"},\n}\n\nfunc TestSplitDomain(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, testCase := range splitDomainTestCases {\n\t\tsplitted := splitDomain(testCase[0])\n\t\tassert.Equal(t, testCase, splitted, \"result must match\")\n\t}\n}\n"
  },
  {
    "path": "service/intel/filterlists/bloom.go",
    "content": "package filterlists\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/tannerryan/ring\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar defaultFilter = newScopedBloom()\n\n// scopedBloom is a wrapper around a bloomfilter implementation\n// providing scoped filters for different entity types.\ntype scopedBloom struct {\n\trw      sync.RWMutex\n\tdomain  *ring.Ring\n\tasn     *ring.Ring\n\tcountry *ring.Ring\n\tipv4    *ring.Ring\n\tipv6    *ring.Ring\n}\n\nfunc newScopedBloom() *scopedBloom {\n\tmustInit := func(size int) *ring.Ring {\n\t\tf, err := ring.Init(size, bfFalsePositiveRate)\n\t\tif err != nil {\n\t\t\t// we panic here as those values cannot be controlled\n\t\t\t// by the user and invalid values shouldn't be\n\t\t\t// in a release anyway.\n\t\t\tpanic(\"Invalid bloom filter parameters!\")\n\t\t}\n\t\treturn f\n\t}\n\treturn &scopedBloom{\n\t\tdomain:  mustInit(domainBfSize),\n\t\tasn:     mustInit(asnBfSize),\n\t\tcountry: mustInit(countryBfSize),\n\t\tipv4:    mustInit(ipv4BfSize),\n\t\tipv6:    mustInit(ipv6BfSize),\n\t}\n}\n\nfunc (bf *scopedBloom) getBloomForType(entityType string) (*ring.Ring, error) {\n\tvar r *ring.Ring\n\n\tswitch strings.ToLower(entityType) {\n\tcase \"domain\":\n\t\tr = bf.domain\n\tcase \"asn\":\n\t\tr = bf.asn\n\tcase \"ipv4\":\n\t\tr = bf.ipv4\n\tcase \"ipv6\":\n\t\tr = bf.ipv6\n\tcase \"country\":\n\t\tr = bf.country\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported filterlists entity type %q\", entityType)\n\t}\n\n\treturn r, nil\n}\n\nfunc (bf *scopedBloom) add(scope, value string) {\n\tbf.rw.Lock()\n\tdefer bf.rw.Unlock()\n\n\tr, err := bf.getBloomForType(scope)\n\tif err != nil {\n\t\t// If we don't have a bloom filter for that scope\n\t\t// we are probably running an older version that does\n\t\t// not have support for it. We just drop the value\n\t\t// as a call to Test() for that scope will always\n\t\t// return \"true\"\n\t\tlog.Warningf(\"failed to add unknown entity type %q with value %q\", scope, value)\n\t\treturn\n\t}\n\n\tr.Add([]byte(value))\n}\n\nfunc (bf *scopedBloom) test(scope, value string) bool {\n\tbf.rw.RLock()\n\tdefer bf.rw.RUnlock()\n\n\tr, err := bf.getBloomForType(scope)\n\tif err != nil {\n\t\tlog.Warningf(\"testing for unknown entity type %q\", scope)\n\t\treturn true // simulate a match to the caller\n\t}\n\n\treturn r.Test([]byte(value))\n}\n\nfunc (bf *scopedBloom) loadFromCache() error {\n\tbf.rw.Lock()\n\tdefer bf.rw.Unlock()\n\n\tif err := loadBloomFromCache(bf.domain, \"domain\"); err != nil {\n\t\treturn err\n\t}\n\tif err := loadBloomFromCache(bf.asn, \"asn\"); err != nil {\n\t\treturn err\n\t}\n\tif err := loadBloomFromCache(bf.country, \"country\"); err != nil {\n\t\treturn err\n\t}\n\tif err := loadBloomFromCache(bf.ipv4, \"ipv4\"); err != nil {\n\t\treturn err\n\t}\n\tif err := loadBloomFromCache(bf.ipv6, \"ipv6\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (bf *scopedBloom) saveToCache() error {\n\tbf.rw.RLock()\n\tdefer bf.rw.RUnlock()\n\n\tif err := saveBloomToCache(bf.domain, \"domain\"); err != nil {\n\t\treturn err\n\t}\n\tif err := saveBloomToCache(bf.asn, \"asn\"); err != nil {\n\t\treturn err\n\t}\n\tif err := saveBloomToCache(bf.country, \"country\"); err != nil {\n\t\treturn err\n\t}\n\tif err := saveBloomToCache(bf.ipv4, \"ipv4\"); err != nil {\n\t\treturn err\n\t}\n\tif err := saveBloomToCache(bf.ipv6, \"ipv6\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (bf *scopedBloom) replaceWith(other *scopedBloom) {\n\tbf.rw.Lock()\n\tdefer bf.rw.Unlock()\n\n\tother.rw.RLock()\n\tdefer other.rw.RUnlock()\n\n\tbf.domain = other.domain\n\tbf.asn = other.asn\n\tbf.country = other.country\n\tbf.ipv4 = other.ipv4\n\tbf.ipv6 = other.ipv6\n}\n\ntype bloomFilterRecord struct {\n\trecord.Base\n\tsync.Mutex\n\n\tFilter string\n}\n\n// loadBloomFromCache loads the bloom filter stored under scope\n// into bf.\nfunc loadBloomFromCache(bf *ring.Ring, scope string) error {\n\tr, err := cache.Get(makeBloomCacheKey(scope))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar filterRecord *bloomFilterRecord\n\tif r.IsWrapped() {\n\t\tfilterRecord = new(bloomFilterRecord)\n\t\tif err := record.Unwrap(r, filterRecord); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tvar ok bool\n\t\tfilterRecord, ok = r.(*bloomFilterRecord)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"invalid type, expected bloomFilterRecord but got %T\", r)\n\t\t}\n\t}\n\n\tblob, err := hex.DecodeString(filterRecord.Filter)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := bf.UnmarshalBinary(blob); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// saveBloomToCache saves the bitset of the bloomfilter bf\n// in the cache db.\nfunc saveBloomToCache(bf *ring.Ring, scope string) error {\n\tblob, err := bf.MarshalBinary()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfilter := hex.EncodeToString(blob)\n\n\tr := &bloomFilterRecord{\n\t\tFilter: filter,\n\t}\n\n\tr.SetKey(makeBloomCacheKey(scope))\n\n\treturn cache.Put(r)\n}\n"
  },
  {
    "path": "service/intel/filterlists/cache_version.go",
    "content": "package filterlists\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/go-version\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nconst resetVersion = \"v0.6.0\"\n\ntype cacheVersionRecord struct {\n\trecord.Base\n\tsync.Mutex\n\n\tVersion string\n\tReset   string\n}\n\n// getCacheDatabaseVersion reads and returns the cache\n// database version record.\nfunc getCacheDatabaseVersion() (*version.Version, error) {\n\tr, err := cache.Get(filterListCacheVersionKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar verRecord *cacheVersionRecord\n\tif r.IsWrapped() {\n\t\tverRecord = new(cacheVersionRecord)\n\t\tif err := record.Unwrap(r, verRecord); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tvar ok bool\n\t\tverRecord, ok = r.(*cacheVersionRecord)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid type, expected cacheVersionRecord but got %T\", r)\n\t\t}\n\t}\n\n\tif verRecord.Reset != resetVersion {\n\t\treturn nil, database.ErrNotFound\n\t}\n\n\tver, err := version.NewSemver(verRecord.Version)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ver, nil\n}\n\n// setCacheDatabaseVersion updates the cache database\n// version record to ver.\nfunc setCacheDatabaseVersion(ver string) error {\n\tverRecord := &cacheVersionRecord{\n\t\tVersion: ver,\n\t\tReset:   resetVersion,\n\t}\n\n\tverRecord.SetKey(filterListCacheVersionKey)\n\treturn cache.Put(verRecord)\n}\n"
  },
  {
    "path": "service/intel/filterlists/database.go",
    "content": "package filterlists\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nconst (\n\tbaseListFilePath         = \"base.dsdl\"\n\tintermediateListFilePath = \"intermediate.dsdl\"\n\turgentListFilePath       = \"urgent.dsdl\"\n\tlistIndexFilePath        = \"index.dsd\"\n)\n\n// default bloomfilter element sizes (estimated).\nconst (\n\tdomainBfSize  = 1000000\n\tasnBfSize     = 1000\n\tcountryBfSize = 100\n\tipv4BfSize    = 100\n\tipv6BfSize    = 100\n)\n\nconst bfFalsePositiveRate = 0.001\n\nvar (\n\tfilterListLock sync.RWMutex\n\n\t// Updater files for tracking upgrades.\n\tbaseFile         *updates.Artifact\n\tintermediateFile *updates.Artifact\n\turgentFile       *updates.Artifact\n\n\tfilterListsLoaded chan struct{}\n)\n\nvar cache = database.NewInterface(&database.Options{\n\tLocal:     true,\n\tInternal:  true,\n\tCacheSize: 256,\n})\n\n// getFileFunc is the function used to get a file from\n// the updater. It's basically updates.GetFile and used\n// for unit testing.\n\n// getFile points to updates.GetFile but may be set to\n// something different during unit testing.\n// var getFile getFileFunc = registry.GetFile\n\nfunc init() {\n\tfilterListsLoaded = make(chan struct{})\n}\n\n// isLoaded returns true if the filterlists have been\n// loaded.\nfunc isLoaded() bool {\n\tselect {\n\tcase <-filterListsLoaded:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// processListFile opens the latest version of file and decodes it's DSDL\n// content. It calls processEntry for each decoded filterlists entry.\nfunc processListFile(ctx context.Context, filter *scopedBloom, file *updates.Artifact) error {\n\tf, err := os.Open(file.Path())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = f.Close()\n\t}()\n\n\tvalues := make(chan *listEntry, 100)\n\trecords := make(chan record.Record, 100)\n\n\tg, ctx := errgroup.WithContext(ctx)\n\n\t// startSafe runs fn inside the error group but wrapped\n\t// in recovered function.\n\tstartSafe := func(fn func() error) {\n\t\tg.Go(func() (err error) {\n\t\t\tdefer func() {\n\t\t\t\tif x := recover(); x != nil {\n\t\t\t\t\tif e, ok := x.(error); ok {\n\t\t\t\t\t\terr = e\n\t\t\t\t\t} else {\n\t\t\t\t\t\terr = fmt.Errorf(\"%v\", x)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\terr = fn()\n\t\t\treturn err\n\t\t})\n\t}\n\n\t// Decode file and send entries to values channel.\n\tstartSafe(func() (err error) {\n\t\tdefer close(values)\n\n\t\terr = decodeFile(ctx, f, values)\n\t\treturn\n\t})\n\n\t// Process each entry and send records to records channel.\n\tstartSafe(func() error {\n\t\tdefer close(records)\n\t\tfor entry := range values {\n\t\t\tif err := processEntry(ctx, filter, entry, records); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n\n\t// Persist records to the database.\n\tpersistRecords(startSafe, records)\n\n\treturn g.Wait()\n}\n\nfunc persistRecords(startJob func(func() error), records <-chan record.Record) {\n\tvar cnt int\n\tstart := time.Now()\n\tlogProgress := func() {\n\t\tif cnt == 0 {\n\t\t\t// protection against panic\n\t\t\treturn\n\t\t}\n\n\t\ttimePerEntity := time.Since(start) / time.Duration(cnt)\n\t\tspeed := float64(time.Second) / float64(timePerEntity)\n\t\tlog.Debugf(\"intel/filterlists: processed %d entities in %s with %s / entity (%.2f entities/second)\", cnt, time.Since(start), timePerEntity, speed)\n\t}\n\n\tbatch := database.NewInterface(&database.Options{Local: true, Internal: true})\n\n\tvar processBatch func() error\n\tprocessBatch = func() error {\n\t\tbatchPut := batch.PutMany(\"cache\")\n\t\tfor r := range records {\n\t\t\tif err := batchPut(r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcnt++\n\n\t\t\tif cnt%10000 == 0 {\n\t\t\t\tlogProgress()\n\t\t\t}\n\n\t\t\tif cnt%1000 == 0 {\n\t\t\t\tif err := batchPut(nil); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tstartJob(processBatch)\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\t// log final batch\n\t\tif cnt%10000 != 0 { // avoid duplicate logging\n\t\t\tlogProgress()\n\t\t}\n\t\treturn batchPut(nil)\n\t}\n\n\tstartJob(processBatch)\n}\n\nfunc normalizeEntry(entry *listEntry) {\n\tswitch strings.ToLower(entry.Type) { //\n\tcase \"domain\":\n\t\tentry.Entity = strings.ToLower(entry.Entity)\n\t\tif entry.Entity[len(entry.Entity)-1] != '.' {\n\t\t\t// ensure domains from the filter list are fully qualified and end in dot.\n\t\t\tentry.Entity += \".\"\n\t\t}\n\tdefault:\n\t}\n}\n\nfunc processEntry(ctx context.Context, filter *scopedBloom, entry *listEntry, records chan<- record.Record) error {\n\tnormalizeEntry(entry)\n\n\t// Only add the entry to the bloom filter if it has any sources.\n\tif len(entry.Resources) > 0 {\n\t\tfilter.add(entry.Type, entry.Entity)\n\t}\n\n\tr := &entityRecord{\n\t\tValue:     entry.Entity,\n\t\tType:      entry.Type,\n\t\tSources:   entry.getSources(),\n\t\tUpdatedAt: time.Now().Unix(),\n\t}\n\n\t// If the entry is a \"delete\" update, actually delete it to save space.\n\tif entry.Whitelist {\n\t\tr.CreateMeta()\n\t\tr.Meta().Delete()\n\t}\n\n\tkey := makeListCacheKey(strings.ToLower(r.Type), r.Value)\n\tr.SetKey(key)\n\n\tselect {\n\tcase records <- r:\n\t\treturn nil\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n}\n\nfunc mapKeys(m map[string]struct{}) []string {\n\tsl := make([]string, 0, len(m))\n\tfor s := range m {\n\t\tsl = append(sl, s)\n\t}\n\n\tsort.Strings(sl)\n\treturn sl\n}\n"
  },
  {
    "path": "service/intel/filterlists/decoder.go",
    "content": "package filterlists\n\nimport (\n\t\"compress/gzip\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/structures/dsd\"\n)\n\ntype listEntry struct {\n\tType      string          `json:\"type\"`\n\tEntity    string          `json:\"entity\"`\n\tWhitelist bool            `json:\"whitelist\"`\n\tResources []entryResource `json:\"resources\"`\n}\n\ntype entryResource struct {\n\tSourceID   string `json:\"sourceID\"`\n\tResourceID string `json:\"resourceID\"`\n}\n\nfunc (entry *listEntry) getSources() (sourceIDs []string) {\n\tsourceIDs = make([]string, 0, len(entry.Resources))\n\n\tfor _, resource := range entry.Resources {\n\t\tif !utils.StringInSlice(sourceIDs, resource.SourceID) {\n\t\t\tsourceIDs = append(sourceIDs, resource.SourceID)\n\t\t}\n\t}\n\n\treturn\n}\n\n// decodeFile decodes a DSDL filterlists file and sends decoded entities to\n// ch. It blocks until all list entries have been consumed or ctx is cancelled.\nfunc decodeFile(ctx context.Context, r io.Reader, ch chan<- *listEntry) error {\n\tcompressed, format, err := parseHeader(r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parser header: %w\", err)\n\t}\n\n\tif compressed {\n\t\tr, err = gzip.NewReader(r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open gzip reader: %w\", err)\n\t\t}\n\t}\n\n\t// we need a reader that supports io.ByteReader\n\treader := &byteReader{r}\n\tvar entryCount int\n\tfor {\n\t\tentryCount++\n\t\tlength, readErr := binary.ReadUvarint(reader)\n\t\tif readErr != nil {\n\t\t\tif errors.Is(readErr, io.EOF) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to load varint entity length: %w\", readErr)\n\t\t}\n\n\t\tblob := make([]byte, length)\n\t\t_, readErr = io.ReadFull(reader, blob)\n\t\tif readErr != nil {\n\t\t\tif errors.Is(readErr, io.EOF) {\n\t\t\t\t// there shouldn't be an EOF here because\n\t\t\t\t// we actually got a length above. Return\n\t\t\t\t// ErrUnexpectedEOF instead of just EOF.\n\t\t\t\t// io.ReadFull already returns ErrUnexpectedEOF\n\t\t\t\t// if it failed to read blob as a whole but my\n\t\t\t\t// return io.EOF if it read exactly 0 bytes.\n\t\t\t\treadErr = io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\treturn readErr\n\t\t}\n\n\t\t// we don't really care about the format here but it must be\n\t\t// something that can encode/decode complex structures like\n\t\t// JSON, BSON or GenCode. So LoadAsFormat MUST return the value\n\t\t// passed as the third parameter. String or RAW encoding IS AN\n\t\t// error here.\n\t\tentry := &listEntry{}\n\t\terr := dsd.LoadAsFormat(blob, format, entry)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decoded DSD encoded entity: %w\", err)\n\t\t}\n\n\t\tselect {\n\t\tcase ch <- entry:\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n}\n\nfunc parseHeader(r io.Reader) (compressed bool, format byte, err error) {\n\tvar listHeader [1]byte\n\tif _, err = r.Read(listHeader[:]); err != nil {\n\t\t// if we have an error here we can safely abort because\n\t\t// the file must be broken\n\t\treturn compressed, format, err\n\t}\n\n\tif listHeader[0] != dsd.LIST {\n\t\terr = fmt.Errorf(\"unexpected file type: %d (%c), expected dsd list\", listHeader[0], listHeader[0])\n\n\t\treturn compressed, format, err\n\t}\n\n\tvar compression [1]byte\n\tif _, err = r.Read(compression[:]); err != nil {\n\t\t// same here, a DSDL file must have at least 2 bytes header\n\t\treturn compressed, format, err\n\t}\n\n\tif compression[0] == dsd.GZIP {\n\t\tcompressed = true\n\n\t\tvar formatSlice [1]byte\n\t\tif _, err = r.Read(formatSlice[:]); err != nil {\n\t\t\treturn compressed, format, err\n\t\t}\n\n\t\tformat = formatSlice[0]\n\t\treturn compressed, format, err\n\t}\n\n\tformat = compression[0]\n\n\treturn compressed, format, err\n}\n\n// byteReader extends an io.Reader to implement the ByteReader interface.\ntype byteReader struct{ io.Reader }\n\nfunc (br *byteReader) ReadByte() (byte, error) {\n\tvar b [1]byte\n\t_, err := br.Read(b[:])\n\treturn b[0], err\n}\n"
  },
  {
    "path": "service/intel/filterlists/index.go",
    "content": "package filterlists\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/go-version\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/updates\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// the following definitions are copied from the intelhub repository\n// and stripped down to only include data required by portmaster.\n\n// Category is used to group different list sources by the type\n// of entity they are blocking. Categories may be nested using\n// the Parent field.\ntype Category struct {\n\t// ID is a unique ID for the category. For sub-categories\n\t// this ID must be used in the Parent field of any directly\n\t// nesteded categories.\n\tID string `json:\"id\"`\n\n\t// Parent may hold the ID of another category. If set, this\n\t// category is made a sub-category of it's parent.\n\tParent string `json:\"parent,omitempty\"`\n\n\t// Name is a human readable name for the category and can\n\t// be used in user interfaces.\n\tName string `json:\"name\"`\n\n\t// Description is a human readable description that may be\n\t// displayed in user interfaces.\n\tDescription string `json:\"description,omitempty\"`\n}\n\n// Source defines an external filterlists source.\ntype Source struct {\n\t// ID is a unique ID for the source. Entities always reference the\n\t// sources they have been observed in using this ID. Refer to the\n\t// Entry struct for more information.\n\tID string `json:\"id\"`\n\n\t// Name is a human readable name for the source and can be used\n\t// in user interfaces.\n\tName string `json:\"name\"`\n\n\t// Description may hold a human readable description for the source.\n\t// It may be used in user interfaces.\n\tDescription string `json:\"description\"`\n\n\t// Type describes the type of entities the source provides. Refer\n\t// to the Type definition for more information and well-known types.\n\tType string `json:\"type\"`\n\n\t// URL points to the filterlists file.\n\tURL string `json:\"url\"`\n\n\t// Category holds the unique ID of a category the source belongs to. Since\n\t// categories can be nested the source is automatically part of all categories\n\t// in the hierarchy. Refer to the Category struct for more information.\n\tCategory string `json:\"category\"`\n\n\t// Website may holds the URL of the source maintainers website.\n\tWebsite string `json:\"website,omitempty\"`\n\n\t// License holds the license that is used for the source.\n\tLicense string `json:\"license\"`\n\n\t// Contribute may hold an opaque string that informs a user on how to\n\t// contribute to the source. This may be a URL or mail address.\n\tContribute string `json:\"contribute\"`\n}\n\n// ListIndexFile describes the structure of the released list\n// index file.\ntype ListIndexFile struct {\n\trecord.Base\n\tsync.RWMutex\n\n\tVersion       string     `json:\"version\"`\n\tSchemaVersion string     `json:\"schemaVersion\"`\n\tCategories    []Category `json:\"categories\"`\n\tSources       []Source   `json:\"sources\"`\n}\n\nfunc (index *ListIndexFile) getCategorySources(id string) []string {\n\tids := make(map[string]struct{})\n\n\t// find all sources that match against cat\n\tfor _, s := range index.Sources {\n\t\tif s.Category == id {\n\t\t\tids[s.ID] = struct{}{}\n\t\t}\n\t}\n\n\t// find all child-categories recursing into getCategorySources.\n\tfor _, c := range index.Categories {\n\t\tif c.Parent == id {\n\t\t\tfor _, sid := range index.getCategorySources(c.ID) {\n\t\t\t\tids[sid] = struct{}{}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn mapKeys(ids)\n}\n\nfunc (index *ListIndexFile) getSourcesMatching(id string) []string {\n\t// if id is already a source ID we just return it\n\tfor _, s := range index.Sources {\n\t\tif s.ID == id {\n\t\t\treturn []string{s.ID}\n\t\t}\n\t}\n\n\t// otherwise we need to check the category tree\n\treturn index.getCategorySources(id)\n}\n\nfunc (index *ListIndexFile) getDistictSourceIDs(ids ...string) []string {\n\tindex.RLock()\n\tdefer index.RUnlock()\n\n\tdistinctIDs := make(map[string]struct{})\n\n\tfor _, id := range ids {\n\t\tfor _, sid := range index.getSourcesMatching(id) {\n\t\t\tdistinctIDs[sid] = struct{}{}\n\t\t}\n\t}\n\n\treturn mapKeys(distinctIDs)\n}\n\nfunc getListIndexFromCache() (*ListIndexFile, error) {\n\tr, err := cache.Get(filterListIndexKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar index *ListIndexFile\n\tif r.IsWrapped() {\n\t\tindex = new(ListIndexFile)\n\t\tif err := record.Unwrap(r, index); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tvar ok bool\n\t\tindex, ok = r.(*ListIndexFile)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid type, expected ListIndexFile but got %T\", r)\n\t\t}\n\t}\n\n\treturn index, nil\n}\n\nvar (\n\t// listIndexUpdate must only be used by updateListIndex.\n\tlistIndexUpdate     *updates.Artifact\n\tlistIndexUpdateLock sync.Mutex\n)\n\n// Compares two version strings and returns true only if both are successfully parsed and equal\nfunc areSemversEqual(v1, v2 string) bool {\n\tparsedV1, err1 := version.NewSemver(v1)\n\tparsedV2, err2 := version.NewSemver(v2)\n\tif err1 != nil || err2 != nil {\n\t\treturn false\n\t}\n\treturn parsedV1.Equal(parsedV2)\n}\n\nfunc updateListIndex() error {\n\tlistIndexUpdateLock.Lock()\n\tdefer listIndexUpdateLock.Unlock()\n\n\t// Check if an update is needed.\n\tswitch {\n\tcase listIndexUpdate == nil:\n\t\t// This is the first time this function is run, get updater file for index.\n\t\tvar err error\n\t\tlistIndexUpdate, err = module.instance.IntelUpdates().GetFile(listIndexFilePath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Check if the version in the cache is current.\n\t\tindex, err := getListIndexFromCache()\n\t\tswitch {\n\t\tcase errors.Is(err, database.ErrNotFound):\n\t\t\tlog.Info(\"filterlists: index not in cache, starting update\")\n\t\tcase err != nil:\n\t\t\tlog.Warningf(\"filterlists: failed to load index from cache, starting update: %s\", err)\n\t\tcase listIndexUpdate.Version != strings.TrimPrefix(index.Version, \"v\") &&\n\t\t\t// Avoid false positives by checking if the version is actually different (e.g. \"2025.04.14 == 2025.4.14\")\n\t\t\t!areSemversEqual(listIndexUpdate.Version, index.Version):\n\t\t\tlog.Infof(\n\t\t\t\t\"filterlists: index from cache is outdated, starting update (%s != %s)\",\n\t\t\t\tstrings.TrimPrefix(index.Version, \"v\"),\n\t\t\t\tlistIndexUpdate.Version,\n\t\t\t)\n\t\tdefault:\n\t\t\t// List is in cache and current, there is nothing to do.\n\t\t\tlog.Debugf(\"filterlists: index is up to date (%s == %s)\", index.Version, listIndexUpdate.Version)\n\n\t\t\t// Update the unbreak filter list IDs on initial load.\n\t\t\tupdateUnbreakFilterListIDs()\n\n\t\t\treturn nil\n\t\t}\n\tdefault:\n\t\t// Index is loaded and no update is available, there is nothing to do.\n\t\treturn nil\n\t}\n\n\t// Update list index from updates.\n\tblob, err := os.ReadFile(listIndexUpdate.Path())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tindex := &ListIndexFile{}\n\t_, err = dsd.Load(blob, index)\n\tif err != nil {\n\t\treturn err\n\t}\n\tindex.SetKey(filterListIndexKey)\n\n\tif err := cache.Put(index); err != nil {\n\t\treturn err\n\t}\n\tlog.Debugf(\"intel/filterlists: updated list index in cache to %s\", index.Version)\n\n\t// Update the unbreak filter list IDs after an update.\n\tupdateUnbreakFilterListIDs()\n\n\treturn nil\n}\n\n// ResolveListIDs resolves a slice of source or category IDs into\n// a slice of distinct source IDs.\nfunc ResolveListIDs(ids []string) ([]string, error) {\n\t// Try get the list\n\tindex, err := getListIndexFromCache()\n\tif err != nil {\n\t\tif errors.Is(err, database.ErrNotFound) {\n\t\t\t// Update the list index\n\t\t\tif err = updateListIndex(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// Retry getting the list.\n\t\t\tif index, err = getListIndexFromCache(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Errorf(\"failed to resolved ids %v: %s\", ids, err)\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tresolved := index.getDistictSourceIDs(ids...)\n\n\tlog.Debugf(\"intel/filterlists: resolved ids %v to %v\", ids, resolved)\n\n\treturn resolved, nil\n}\n\nvar (\n\tunbreakCategoryIDs = []string{\"UNBREAK\"}\n\n\tunbreakIDs     []string\n\tunbreakIDsLock sync.Mutex\n)\n\n// GetUnbreakFilterListIDs returns the resolved list of all unbreak filter lists.\nfunc GetUnbreakFilterListIDs() []string {\n\tunbreakIDsLock.Lock()\n\tdefer unbreakIDsLock.Unlock()\n\n\treturn unbreakIDs\n}\n\nfunc updateUnbreakFilterListIDs() {\n\tunbreakIDsLock.Lock()\n\tdefer unbreakIDsLock.Unlock()\n\n\tresolvedIDs, err := ResolveListIDs(unbreakCategoryIDs)\n\tif err != nil {\n\t\tlog.Warningf(\"filter: failed to resolve unbreak filter list IDs: %s\", err)\n\t} else {\n\t\tunbreakIDs = resolvedIDs\n\t}\n}\n"
  },
  {
    "path": "service/intel/filterlists/keys.go",
    "content": "package filterlists\n\nconst (\n\tcacheDBPrefix = \"cache:intel/filterlists\"\n\n\t// filterListCacheVersionKey is used to store the highest version\n\t// of a filterlists file (base, intermediate or urgent) in the\n\t// cache database. It's used to decide if the cache database and\n\t// bloomfilters need to be resetted and rebuilt.\n\tfilterListCacheVersionKey = cacheDBPrefix + \"/version\"\n\n\t// filterListIndexKey is used to store the filterlists index.\n\tfilterListIndexKey = cacheDBPrefix + \"/index\"\n\n\t// filterListKeyPrefix is the prefix inside that cache database\n\t// used for filter list entries.\n\tfilterListKeyPrefix = cacheDBPrefix + \"/lists/\"\n)\n\nfunc makeBloomCacheKey(scope string) string {\n\treturn cacheDBPrefix + \"/bloom/\" + scope\n}\n\nfunc makeListCacheKey(scope, key string) string {\n\treturn filterListKeyPrefix + scope + \"/\" + key\n}\n"
  },
  {
    "path": "service/intel/filterlists/lookup.go",
    "content": "package filterlists\n\nimport (\n\t\"errors\"\n\t\"net\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// lookupBlockLists loads the entity record for key from\n// cache and returns the list of blocklist sources the\n// key is part of. It is not considered an error if\n// key does not exist, instead, an empty slice is\n// returned.\nfunc lookupBlockLists(entity, value string) ([]string, error) {\n\tkey := makeListCacheKey(entity, value)\n\tif !isLoaded() {\n\t\tlog.Warningf(\"intel/filterlists: not searching for %s because filterlists not loaded\", key)\n\t\t// filterLists have not yet been loaded so\n\t\t// there's no point querying into the cache\n\t\t// database.\n\t\treturn nil, nil\n\t}\n\n\tfilterListLock.RLock()\n\tdefer filterListLock.RUnlock()\n\n\tif !defaultFilter.test(entity, value) {\n\t\treturn nil, nil\n\t}\n\n\t// log.Debugf(\"intel/filterlists: searching for entries with %s\", key)\n\tentry, err := getEntityRecordByKey(key)\n\tif err != nil {\n\t\tif errors.Is(err, database.ErrNotFound) {\n\t\t\treturn nil, nil\n\t\t}\n\t\tlog.Errorf(\"intel/filterlists: failed to get entries for key %s: %s\", key, err)\n\n\t\treturn nil, err\n\t}\n\n\treturn entry.Sources, nil\n}\n\n// LookupCountry returns a list of sources that mark the country\n// as blocked. If country is not stored in the cache database\n// a nil slice is returned.\nfunc LookupCountry(country string) ([]string, error) {\n\treturn lookupBlockLists(\"country\", country)\n}\n\n// LookupDomain returns a list of sources that mark the domain\n// as blocked. If domain is not stored in the cache database\n// a nil slice is returned. The caller is responsible for making\n// sure that the given domain is valid and canonical.\nfunc LookupDomain(domain string) ([]string, error) {\n\tswitch domain {\n\tcase \"\", \".\":\n\t\t// Return no lists for empty domains and the root zone.\n\t\treturn nil, nil\n\tdefault:\n\t\treturn lookupBlockLists(\"domain\", domain)\n\t}\n}\n\n// LookupASNString returns a list of sources that mark the ASN\n// as blocked. If ASN is not stored in the cache database\n// a nil slice is returned.\nfunc LookupASNString(asn string) ([]string, error) {\n\treturn lookupBlockLists(\"asn\", asn)\n}\n\n// LookupIP returns a list of block sources that contain\n// a reference to ip. LookupIP automatically checks the IPv4 or\n// IPv6 lists respectively.\nfunc LookupIP(ip net.IP) ([]string, error) {\n\tif ip.To4() == nil {\n\t\treturn LookupIPv6(ip)\n\t}\n\n\treturn LookupIPv4(ip)\n}\n\n// LookupIPString is like LookupIP but accepts an IPv4 or\n// IPv6 address in their string representations.\nfunc LookupIPString(ipStr string) ([]string, error) {\n\tip := net.ParseIP(ipStr)\n\tif ip == nil {\n\t\treturn nil, errors.New(\"invalid IP\")\n\t}\n\n\treturn LookupIP(ip)\n}\n\n// LookupIPv4String returns a list of block sources that\n// contain a reference to ip. If the IP is not stored in the\n// cache database a nil slice is returned.\nfunc LookupIPv4String(ipv4 string) ([]string, error) {\n\treturn lookupBlockLists(\"ipv4\", ipv4)\n}\n\n// LookupIPv4 is like LookupIPv4String but accepts a net.IP.\nfunc LookupIPv4(ipv4 net.IP) ([]string, error) {\n\tip := ipv4.To4()\n\tif ip == nil {\n\t\treturn nil, errors.New(\"invalid IPv4\")\n\t}\n\n\treturn LookupIPv4String(ip.String())\n}\n\n// LookupIPv6String returns a list of block sources that\n// contain a reference to ip. If the IP is not stored in the\n// cache database a nil slice is returned.\nfunc LookupIPv6String(ipv6 string) ([]string, error) {\n\treturn lookupBlockLists(\"ipv6\", ipv6)\n}\n\n// LookupIPv6 is like LookupIPv6String but accepts a net.IP.\nfunc LookupIPv6(ipv6 net.IP) ([]string, error) {\n\tip := ipv6.To16()\n\tif ip == nil {\n\t\treturn nil, errors.New(\"invalid IPv6\")\n\t}\n\n\treturn LookupIPv6String(ip.String())\n}\n"
  },
  {
    "path": "service/intel/filterlists/module.go",
    "content": "package filterlists\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nconst (\n\tfilterlistsDisabled          = \"filterlists:disabled\"\n\tfilterlistsUpdateFailed      = \"filterlists:update-failed\"\n\tfilterlistsStaleDataSurvived = \"filterlists:staledata\"\n)\n\ntype FilterLists struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tstates *mgr.StateMgr\n}\n\nfunc (fl *FilterLists) Manager() *mgr.Manager {\n\treturn fl.mgr\n}\n\nfunc (fl *FilterLists) States() *mgr.StateMgr {\n\treturn fl.states\n}\n\nfunc (fl *FilterLists) Start() error {\n\treturn start()\n}\n\nfunc (fl *FilterLists) Stop() error {\n\treturn stop()\n}\n\nvar (\n\t// booleans mainly used to decouple the module during testing.\n\tignoreUpdateEvents = abool.New()\n\tignoreNetEnvEvents = abool.New()\n)\n\nfunc init() {\n\tignoreNetEnvEvents.Set()\n}\n\nfunc registerEventCallbacks() {\n\tmodule.instance.IntelUpdates().EventResourcesUpdated.AddCallback(\"Check for blocklist updates\",\n\t\tfunc(wc *mgr.WorkerCtx, s struct{}) (bool, error) {\n\t\t\tif ignoreUpdateEvents.IsSet() {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn false, tryListUpdate(wc.Ctx())\n\t\t})\n\n\tmodule.instance.NetEnv().EventOnlineStatusChange.AddCallback(\"Check for blocklist updates\",\n\t\tfunc(wc *mgr.WorkerCtx, s netenv.OnlineStatus) (bool, error) {\n\t\t\tif ignoreNetEnvEvents.IsSet() {\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t\t// Nothing to do if we went offline.\n\t\t\tif s == netenv.StatusOffline {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn false, tryListUpdate(wc.Ctx())\n\t\t})\n}\n\nfunc start() error {\n\tfilterListLock.Lock()\n\tdefer filterListLock.Unlock()\n\n\t// Any call of tryListUpdate() must be only after module fully initialized\n\tdefer func() {\n\t\t// Register event callbacks\n\t\tregisterEventCallbacks()\n\n\t\t// Initial check filterlists updates\n\t\tmodule.Manager().Go(\"intel/filterlists initial check for update\", func(ctx *mgr.WorkerCtx) error {\n\t\t\tif err := tryListUpdate(ctx.Ctx()); err != nil {\n\t\t\t\tlog.Errorf(\"intel/filterlists: tryListUpdate() failed: %q\", err.Error())\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}()\n\n\tver, err := getCacheDatabaseVersion()\n\tif err == nil {\n\t\tlog.Debugf(\"intel/filterlists: cache database has version %s\", ver.String())\n\n\t\tif err = defaultFilter.loadFromCache(); err != nil {\n\t\t\terr = fmt.Errorf(\"failed to initialize bloom filters: %w\", err)\n\t\t}\n\t}\n\n\tif err != nil {\n\t\tlog.Debugf(\"intel/filterlists: blocklists disabled, waiting for update (%s)\", err)\n\t\twarnAboutDisabledFilterLists()\n\t} else {\n\t\tlog.Debugf(\"intel/filterlists: using cache database\")\n\t\tclose(filterListsLoaded)\n\t}\n\n\treturn nil\n}\n\nfunc stop() error {\n\tfilterListsLoaded = make(chan struct{})\n\treturn nil\n}\n\nfunc warnAboutDisabledFilterLists() {\n\tmodule.states.Add(mgr.State{\n\t\tID:      filterlistsDisabled,\n\t\tName:    \"Filter Lists Are Initializing\",\n\t\tMessage: \"Filter lists are being downloaded and set up in the background. They will be activated as configured when finished.\",\n\t\tType:    mgr.StateTypeWarning,\n\t})\n}\n\nvar (\n\tmodule     *FilterLists\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new FilterLists module.\nfunc New(instance instance) (*FilterLists, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"FilterLists\")\n\tmodule = &FilterLists{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tstates: mgr.NewStateMgr(m),\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tIntelUpdates() *updates.Updater\n\tNetEnv() *netenv.NetEnv\n}\n"
  },
  {
    "path": "service/intel/filterlists/module_test.go",
    "content": "package filterlists\n\n/*\nfunc TestMain(m *testing.M) {\n\t// we completely ignore netenv events during testing.\n\tignoreNetEnvEvents.Set()\n\n\tif err := updates.DisableUpdateSchedule(); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to disable update schedule: %s\", err)\n\t\tos.Exit(1)\n\t}\n\tpmtesting.TestMainWithHooks(m, module, loadOnStart, nil)\n}\n\nfunc loadOnStart() error {\n\tlog.SetLogLevel(log.TraceLevel)\n\n\tch := make(chan struct{})\n\tdefer close(ch)\n\n\tif err := updates.TriggerUpdate(); err != nil {\n\t\treturn fmt.Errorf(\"failed to trigger update: %w\", err)\n\t}\n\n\tvar err error\n\n\tgo func() {\n\t\tselect {\n\t\tcase <-ch:\n\t\t\treturn\n\n\t\tcase <-time.After(time.Minute):\n\t\t\terr = fmt.Errorf(\"timeout loading\")\n\t\t\tclose(filterListsLoaded) // let waitUntilLoaded() return\n\t\t}\n\t}()\n\n\twaitUntilLoaded()\n\ttime.Sleep(time.Second * 10)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfailureStatus, failureID, failureMsg := module.FailureStatus()\n\tif failureStatus == modules.FailureError || failureStatus == modules.FailureWarning {\n\t\treturn fmt.Errorf(\"module in failure state: %s %q\", failureID, failureMsg)\n\t}\n\n\t// ignore update events from now on during testing.\n\tignoreUpdateEvents.Set()\n\n\ttestSources := []string{\"TEST\"}\n\ttestEntries := []*listEntry{\n\t\t{\n\t\t\tEntity:  \"example.com\",\n\t\t\tSources: testSources,\n\t\t\tType:    \"Domain\",\n\t\t},\n\t\t{\n\t\t\tEntity:  \"1.1.1.1\",\n\t\t\tSources: testSources,\n\t\t\tType:    \"IPv4\",\n\t\t},\n\t\t{\n\t\t\tEntity:  \"AT\",\n\t\t\tSources: testSources,\n\t\t\tType:    \"Country\",\n\t\t},\n\t\t{\n\t\t\tEntity:  \"123\",\n\t\t\tSources: testSources,\n\t\t\tType:    \"ASN\",\n\t\t},\n\t}\n\n\tfor _, e := range testEntries {\n\t\t// add some test entries\n\t\tif err := processEntry(e); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t}\n\n\treturn nil\n}\n*/\n"
  },
  {
    "path": "service/intel/filterlists/record.go",
    "content": "package filterlists\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\ntype entityRecord struct {\n\trecord.Base `json:\"-\"`\n\tsync.Mutex  `json:\"-\"`\n\n\tValue     string\n\tSources   []string\n\tType      string\n\tUpdatedAt int64\n}\n\nfunc getEntityRecordByKey(key string) (*entityRecord, error) {\n\tr, err := cache.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif r.IsWrapped() {\n\t\tnewER := &entityRecord{}\n\t\tif err := record.Unwrap(r, newER); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn newER, nil\n\t}\n\n\tnewER, ok := r.(*entityRecord)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *entityRecord, but %T\", r)\n\t}\n\treturn newER, nil\n}\n"
  },
  {
    "path": "service/intel/filterlists/updater.go",
    "content": "package filterlists\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-version\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nvar updateInProgress = abool.New()\n\n// tryListUpdate wraps performUpdate but ensures the module's\n// error state is correctly set or resolved.\nfunc tryListUpdate(ctx context.Context) error {\n\terr := performUpdate(ctx)\n\tif err != nil {\n\t\t// Check if we are shutting down, as to not raise a false alarm.\n\t\tif module.mgr.IsDone() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Check if the module already has a failure status set. If not, set a\n\t\t// generic one with the returned error.\n\n\t\thasWarningState := false\n\t\tfor _, state := range module.states.Export().States {\n\t\t\tif state.Type == mgr.StateTypeWarning {\n\t\t\t\thasWarningState = true\n\t\t\t}\n\t\t}\n\t\tif !hasWarningState {\n\t\t\tmodule.states.Add(mgr.State{\n\t\t\t\tID:      filterlistsUpdateFailed,\n\t\t\t\tName:    \"Filter Lists Update Failed\",\n\t\t\t\tMessage: fmt.Sprintf(\"The Portmaster failed to process a filter lists update. Filtering capabilities are currently either impaired or not available at all. Error: %s\", err.Error()),\n\t\t\t\tType:    mgr.StateTypeWarning,\n\t\t\t})\n\t\t}\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc performUpdate(ctx context.Context) error {\n\tif !updateInProgress.SetToIf(false, true) {\n\t\tlog.Debugf(\"intel/filterlists: upgrade already in progress\")\n\t\treturn nil\n\t}\n\tdefer updateInProgress.UnSet()\n\n\t// First, update the list index.\n\terr := updateListIndex()\n\tif err != nil {\n\t\tlog.Warningf(\"intel/filterlists: failed update list index: %s\", err)\n\t}\n\n\tupgradables, err := getUpgradableFiles()\n\tif err != nil {\n\t\treturn err\n\t}\n\tlog.Debugf(\"intel/filterlists: resources to update: %v\", upgradables)\n\n\tif len(upgradables) == 0 {\n\t\tlog.Debugf(\"intel/filterlists: ignoring update, latest version is already used\")\n\t\treturn nil\n\t}\n\n\tcleanupRequired := false\n\tfilterToUpdate := defaultFilter\n\n\t// perform the actual upgrade by processing each file\n\t// in the returned order.\n\tfor idx, file := range upgradables {\n\t\tlog.Debugf(\"intel/filterlists: applying update (%d) %s version %s\", idx, file.Filename, file.Version)\n\n\t\tif file == baseFile {\n\t\t\tif idx != 0 {\n\t\t\t\tlog.Warningf(\"intel/filterlists: upgrade order is wrong, base file needs to be updated first not at idx %d\", idx)\n\t\t\t\t// we still continue because after processing the base\n\t\t\t\t// file everything is correct again, we just used some\n\t\t\t\t// CPU and IO resources for nothing when processing\n\t\t\t\t// the previous files.\n\t\t\t}\n\t\t\tcleanupRequired = true\n\n\t\t\t// since we are processing a base update we will create our\n\t\t\t// bloom filters from scratch.\n\t\t\tfilterToUpdate = newScopedBloom()\n\t\t}\n\n\t\tif err := processListFile(ctx, filterToUpdate, file); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to process upgrade %s version %s: %w\", file.Filename, file.Version, err)\n\t\t}\n\t}\n\n\tif filterToUpdate != defaultFilter {\n\t\t// replace the bloom filters in our default\n\t\t// filter.\n\t\tdefaultFilter.replaceWith(filterToUpdate)\n\t}\n\n\t// from now on, the database is ready and can be used if\n\t// it wasn't loaded yet.\n\tif !isLoaded() {\n\t\tclose(filterListsLoaded)\n\t}\n\n\tif err := defaultFilter.saveToCache(); err != nil {\n\t\t// just handle the error by logging as it's only consequence\n\t\t// is that we will need to reprocess all files during the next\n\t\t// start.\n\t\tlog.Errorf(\"intel/filterlists: failed to persist bloom filters in cache database: %s\", err)\n\t}\n\n\t// if we processed the base file we need to perform\n\t// some cleanup on filterlists entities that have not\n\t// been updated now. Once we are done, start a worker\n\t// for that purpose.\n\tif cleanupRequired {\n\t\tif err := module.mgr.Do(\"filterlists:cleanup\", removeAllObsoleteFilterEntries); err != nil {\n\t\t\t// if we failed to remove all stale cache entries\n\t\t\t// we abort now WITHOUT updating the database version. This means\n\t\t\t// we'll try again during the next update.\n\t\t\tmodule.states.Add(mgr.State{\n\t\t\t\tID:      filterlistsStaleDataSurvived,\n\t\t\t\tName:    \"Filter Lists May Overblock\",\n\t\t\t\tMessage: fmt.Sprintf(\"The Portmaster failed to delete outdated filter list data. Filtering capabilities are fully available, but overblocking may occur. Error: %s\", err.Error()), //nolint:misspell // overblocking != overclocking\n\t\t\t\tType:    mgr.StateTypeWarning,\n\t\t\t})\n\t\t\treturn fmt.Errorf(\"failed to cleanup stale cache records: %w\", err)\n\t\t}\n\t}\n\n\t// try to save the highest version of our files.\n\thighestVersion := upgradables[len(upgradables)-1]\n\tif err := setCacheDatabaseVersion(highestVersion.Version); err != nil {\n\t\tlog.Errorf(\"intel/filterlists: failed to save cache database version: %s\", err)\n\t} else {\n\t\tlog.Infof(\"intel/filterlists: successfully migrated cache database to %s\", highestVersion.Version)\n\t}\n\n\t// The list update succeeded, resolve any states.\n\tmodule.states.Clear()\n\treturn nil\n}\n\nfunc removeAllObsoleteFilterEntries(wc *mgr.WorkerCtx) error {\n\tlog.Debugf(\"intel/filterlists: cleanup task started, removing obsolete filter list entries ...\")\n\n\t// TODO: Remember the timestamp we started the last update and use that rather than \"one hour ago\".\n\n\t// First try to purge with PurgeOlderThan.\n\tn, err := cache.PurgeOlderThan(wc.Ctx(), filterListKeyPrefix, time.Now().Add(-time.Hour))\n\tswitch {\n\tcase err == nil:\n\t\t// Success!\n\t\tlog.Debugf(\"intel/filterlists: successfully removed %d obsolete entries\", n)\n\t\treturn nil\n\tcase errors.Is(err, database.ErrNotImplemented) || errors.Is(err, storage.ErrNotImplemented):\n\t\t// Try next method.\n\tdefault:\n\t\t// Return error.\n\t\treturn err\n\t}\n\n\t// Try with regular purge.\n\tn, err = cache.Purge(wc.Ctx(), query.New(filterListKeyPrefix).Where(\n\t\tquery.Where(\"UpdatedAt\", query.LessThan, time.Now().Add(-time.Hour).Unix()),\n\t))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Debugf(\"intel/filterlists: successfully removed %d obsolete entries\", n)\n\treturn nil\n}\n\n// getUpgradableFiles returns a slice of filterlists files\n// that should be updated. The files MUST be updated and\n// processed in the returned order!\nfunc getUpgradableFiles() ([]*updates.Artifact, error) {\n\tvar updateOrder []*updates.Artifact\n\n\tcacheDBInUse := isLoaded()\n\n\tnewBaseFile, err := module.instance.IntelUpdates().GetFile(baseListFilePath)\n\tif err != nil {\n\t\tlog.Warningf(\"intel/filterlists: failed to get base update: %s\", err)\n\t} else if newer, _ := newBaseFile.IsNewerThan(baseFile); newer || !cacheDBInUse {\n\t\tlog.Tracef(\"intel/filterlists: base file needs update to version %s\", newBaseFile.Version)\n\t\tif newBaseFile.SemVer() == nil {\n\t\t\tlog.Warningf(\"intel/filterlists: base file needs update to version %s, but semver is invalid\", newBaseFile.Version)\n\t\t} else {\n\t\t\tupdateOrder = append(updateOrder, newBaseFile)\n\t\t}\n\t}\n\n\tnewIntermediateFile, err := module.instance.IntelUpdates().GetFile(intermediateListFilePath)\n\tif err != nil {\n\t\tlog.Warningf(\"intel/filterlists: failed to get intermediate update: %s\", err)\n\t} else if newer, _ := newIntermediateFile.IsNewerThan(intermediateFile); newer || !cacheDBInUse {\n\t\tlog.Tracef(\"intel/filterlists: intermediate file needs update to version %s\", newIntermediateFile.Version)\n\t\tif newIntermediateFile.SemVer() == nil {\n\t\t\tlog.Warningf(\"intel/filterlists: intermediate file needs update to version %s, but semver is invalid\", newIntermediateFile.Version)\n\t\t} else {\n\t\t\tupdateOrder = append(updateOrder, newIntermediateFile)\n\t\t}\n\t}\n\n\tnewUrgentFile, err := module.instance.IntelUpdates().GetFile(urgentListFilePath)\n\tif err != nil {\n\t\tlog.Warningf(\"intel/filterlists: failed to get urgent update: %s\", err)\n\t} else if newer, _ := newUrgentFile.IsNewerThan(urgentFile); newer || !cacheDBInUse {\n\t\tlog.Tracef(\"intel/filterlists: urgent file needs update to version %s\", newUrgentFile.Version)\n\t\tif newUrgentFile.SemVer() == nil {\n\t\t\tlog.Warningf(\"intel/filterlists: urgent file needs update to version %s, but semver is invalid\", newUrgentFile.Version)\n\t\t} else {\n\t\t\tupdateOrder = append(updateOrder, newUrgentFile)\n\t\t}\n\t}\n\n\treturn resolveUpdateOrder(updateOrder)\n}\n\nfunc resolveUpdateOrder(updateOrder []*updates.Artifact) ([]*updates.Artifact, error) {\n\t// sort the update order by ascending version\n\tsort.Sort(byAscVersion(updateOrder))\n\tlog.Tracef(\"intel/filterlists: order of potential updates: %v\", updateOrder)\n\n\tvar cacheDBVersion *version.Version\n\tif !isLoaded() {\n\t\tcacheDBVersion, _ = version.NewSemver(\"v0.0.0\")\n\t} else {\n\t\tvar err error\n\t\tcacheDBVersion, err = getCacheDatabaseVersion()\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\t\tlog.Errorf(\"intel/filterlists: failed to get cache database version: %s\", err)\n\t\t\t}\n\t\t\tcacheDBVersion, _ = version.NewSemver(\"v0.0.0\")\n\t\t}\n\t}\n\n\tstartAtIdx := -1\n\tfor idx, file := range updateOrder {\n\t\tlog.Tracef(\"intel/filterlists: checking file with version %s against %s\", file.SemVer(), cacheDBVersion)\n\t\tif file.SemVer().GreaterThan(cacheDBVersion) && (startAtIdx == -1 || file == baseFile) {\n\t\t\tstartAtIdx = idx\n\t\t}\n\t}\n\n\t// if startAtIdx == -1 we don't have any upgradables to\n\t// process.\n\tif startAtIdx == -1 {\n\t\tlog.Tracef(\"intel/filterlists: nothing to process, latest version %s already in use\", cacheDBVersion)\n\t\treturn nil, nil\n\t}\n\n\t// skip any files that are lower then the current cache db version\n\t// or after which a base upgrade would be performed.\n\treturn updateOrder[startAtIdx:], nil\n}\n\ntype byAscVersion []*updates.Artifact\n\nfunc (fs byAscVersion) Len() int { return len(fs) }\n\nfunc (fs byAscVersion) Less(i, j int) bool {\n\treturn fs[i].SemVer().LessThan(fs[j].SemVer())\n}\n\nfunc (fs byAscVersion) Swap(i, j int) {\n\tfi := fs[i]\n\tfj := fs[j]\n\n\tfs[i] = fj\n\tfs[j] = fi\n}\n"
  },
  {
    "path": "service/intel/geoip/country_info.go",
    "content": "package geoip\n\nimport \"strings\"\n\nconst defaultCountryBasedAccuracy = 200\n\n// AddCountryInfo adds missing country information to the location.\nfunc (l *Location) AddCountryInfo() {\n\t// Check if we have the country code.\n\tif l.Country.Code == \"\" {\n\t\treturn\n\t}\n\n\t// Check for anycast.\n\tif l.IsAnycast {\n\t\t// Reset data for anycast.\n\t\tl.Country.Code = \"__\"\n\t\tl.Coordinates.Latitude = 0\n\t\tl.Coordinates.Longitude = 0\n\t}\n\n\t// Get country info.\n\tinfo, ok := countries[l.Country.Code]\n\tif !ok {\n\t\treturn\n\t}\n\t// Apply country info to location.\n\tl.Country = info\n\n\t// Use country center as location coordinates if unset.\n\tif l.Coordinates.Latitude == 0 && l.Coordinates.Longitude == 0 {\n\t\tl.Coordinates = info.Center\n\t}\n}\n\n// GetCountryInfo returns the country info of the given country code, or nil\n// in case the data does not exist.\nfunc GetCountryInfo(countryCode string) CountryInfo {\n\tinfo := countries[countryCode]\n\treturn info\n}\n\n// CountryInfo holds additional information about countries.\ntype CountryInfo struct {\n\tCode      string `maxminddb:\"iso_code\"`\n\tName      string\n\tCenter    Coordinates\n\tContinent ContinentInfo\n}\n\n// ContinentInfo holds additional information about continents.\ntype ContinentInfo struct {\n\tCode   string\n\tRegion string\n\tName   string\n}\n\n// Add data to countries.\nfunc init() {\n\tfor code, country := range countries {\n\t\t// Set country code.\n\t\tcountry.Code = code\n\n\t\t// Derive continent code from continental region.\n\t\tcountry.Continent.Code, _, _ = strings.Cut(country.Continent.Region, \"-\")\n\n\t\t// Add continent name.\n\t\tswitch country.Continent.Code {\n\t\tcase \"AF\":\n\t\t\tcountry.Continent.Name = \"Africa\"\n\t\tcase \"AN\":\n\t\t\tcountry.Continent.Name = \"Antarctica\"\n\t\tcase \"AS\":\n\t\t\tcountry.Continent.Name = \"Asia\"\n\t\tcase \"EU\":\n\t\t\tcountry.Continent.Name = \"Europe\"\n\t\tcase \"NA\":\n\t\t\tcountry.Continent.Name = \"North America\"\n\t\tcase \"OC\":\n\t\t\tcountry.Continent.Name = \"Oceania\"\n\t\tcase \"SA\":\n\t\t\tcountry.Continent.Name = \"South America\"\n\t\t}\n\n\t\t// Add default accuracy radius.\n\t\tcountry.Center.AccuracyRadius = defaultCountryBasedAccuracy\n\n\t\t// Apply back to map.\n\t\tcountries[code] = country\n\t}\n}\n\nvar countries = map[string]CountryInfo{\n\t\"__\": {\n\t\tName:   \"Anycast\",\n\t\tCenter: Coordinates{AccuracyRadius: earthCircumferenceInKm},\n\t},\n\t\"MN\": {\n\t\tName:      \"Mongolia\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 46.000000, Longitude: 103.000000},\n\t},\n\t\"BN\": {\n\t\tName:      \"Brunei Darussalam\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 4.000000, Longitude: 114.000000},\n\t},\n\t\"GI\": {\n\t\tName:      \"Gibraltar\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 36.000000, Longitude: -5.000000},\n\t},\n\t\"SO\": {\n\t\tName:      \"Somalia\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: 5.000000, Longitude: 46.000000},\n\t},\n\t\"GG\": {\n\t\tName:      \"Guernsey\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 49.000000, Longitude: -2.000000},\n\t},\n\t\"CL\": {\n\t\tName:      \"Chile\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -35.000000, Longitude: -71.000000},\n\t},\n\t\"LR\": {\n\t\tName:      \"Liberia\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 6.000000, Longitude: -9.000000},\n\t},\n\t\"TZ\": {\n\t\tName:      \"Tanzania\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -6.000000, Longitude: 34.000000},\n\t},\n\t\"MU\": {\n\t\tName:      \"Mauritius\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -20.000000, Longitude: 57.000000},\n\t},\n\t\"HM\": {\n\t\tName:      \"Heard Island and McDonald Islands\",\n\t\tContinent: ContinentInfo{Region: \"OC-S\"},\n\t\tCenter:    Coordinates{Latitude: -53.000000, Longitude: 73.000000},\n\t},\n\t\"AR\": {\n\t\tName:      \"Argentina\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -38.000000, Longitude: -63.000000},\n\t},\n\t\"BV\": {\n\t\tName:      \"Bouvet Island\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -54.000000, Longitude: 3.000000},\n\t},\n\t\"MS\": {\n\t\tName:      \"Montserrat\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 16.000000, Longitude: -62.000000},\n\t},\n\t\"PT\": {\n\t\tName:      \"Portugal\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 39.000000, Longitude: -8.000000},\n\t},\n\t\"BO\": {\n\t\tName:      \"Bolivia\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -16.000000, Longitude: -63.000000},\n\t},\n\t\"VC\": {\n\t\tName:      \"Saint Vincent and the Grenadines\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: -61.000000},\n\t},\n\t\"RO\": {\n\t\tName:      \"Romania\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 45.000000, Longitude: 24.000000},\n\t},\n\t\"MK\": {\n\t\tName:      \"North Macedonia\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 41.000000, Longitude: 21.000000},\n\t},\n\t\"UG\": {\n\t\tName:      \"Uganda\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: 1.000000, Longitude: 32.000000},\n\t},\n\t\"HN\": {\n\t\tName:      \"Honduras\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 15.000000, Longitude: -86.000000},\n\t},\n\t\"IS\": {\n\t\tName:      \"Iceland\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 64.000000, Longitude: -19.000000},\n\t},\n\t\"HR\": {\n\t\tName:      \"Croatia\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 45.000000, Longitude: 15.000000},\n\t},\n\t\"PL\": {\n\t\tName:      \"Poland\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 51.000000, Longitude: 19.000000},\n\t},\n\t\"TC\": {\n\t\tName:      \"Turks and Caicos Islands\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 21.000000, Longitude: -71.000000},\n\t},\n\t\"LC\": {\n\t\tName:      \"Saint Lucia\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 13.000000, Longitude: -60.000000},\n\t},\n\t\"JP\": {\n\t\tName:      \"Japan\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 36.000000, Longitude: 138.000000},\n\t},\n\t\"TN\": {\n\t\tName:      \"Tunisia\",\n\t\tContinent: ContinentInfo{Region: \"AF-N\"},\n\t\tCenter:    Coordinates{Latitude: 33.000000, Longitude: 9.000000},\n\t},\n\t\"GS\": {\n\t\tName:      \"South Georgia and the South Sandwich Islands\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -54.000000, Longitude: -36.000000},\n\t},\n\t\"MY\": {\n\t\tName:      \"Malaysia\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 4.000000, Longitude: 101.000000},\n\t},\n\t\"TT\": {\n\t\tName:      \"Trinidad and Tobago\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 10.000000, Longitude: -61.000000},\n\t},\n\t\"BE\": {\n\t\tName:      \"Belgium\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 50.000000, Longitude: 4.000000},\n\t},\n\t\"GU\": {\n\t\tName:      \"Guam\",\n\t\tContinent: ContinentInfo{Region: \"OC-N\"},\n\t\tCenter:    Coordinates{Latitude: 13.000000, Longitude: 144.000000},\n\t},\n\t\"NL\": {\n\t\tName:      \"Netherlands\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 52.000000, Longitude: 5.000000},\n\t},\n\t\"AF\": {\n\t\tName:      \"Afghanistan\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 33.000000, Longitude: 67.000000},\n\t},\n\t\"CK\": {\n\t\tName:      \"Cook Islands\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -21.000000, Longitude: -159.000000},\n\t},\n\t\"PM\": {\n\t\tName:      \"Saint Pierre and Miquelon\",\n\t\tContinent: ContinentInfo{Region: \"NA-N\"},\n\t\tCenter:    Coordinates{Latitude: 46.000000, Longitude: -56.000000},\n\t},\n\t\"OM\": {\n\t\tName:      \"Oman\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 21.000000, Longitude: 55.000000},\n\t},\n\t\"NP\": {\n\t\tName:      \"Nepal\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 28.000000, Longitude: 84.000000},\n\t},\n\t\"RS\": {\n\t\tName:      \"Serbia\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 44.000000, Longitude: 21.000000},\n\t},\n\t\"MW\": {\n\t\tName:      \"Malawi\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -13.000000, Longitude: 34.000000},\n\t},\n\t\"NE\": {\n\t\tName:      \"Niger\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 17.000000, Longitude: 8.000000},\n\t},\n\t\"BY\": {\n\t\tName:      \"Belarus\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 53.000000, Longitude: 27.000000},\n\t},\n\t\"TH\": {\n\t\tName:      \"Thailand\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 15.000000, Longitude: 100.000000},\n\t},\n\t\"CW\": {\n\t\tName:      \"Curaçao\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: -68.000000},\n\t},\n\t\"AS\": {\n\t\tName:      \"American Samoa\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -14.000000, Longitude: -170.000000},\n\t},\n\t\"BF\": {\n\t\tName:      \"Burkina Faso\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: -1.000000},\n\t},\n\t\"BR\": {\n\t\tName:      \"Brazil\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -14.000000, Longitude: -51.000000},\n\t},\n\t\"CX\": {\n\t\tName:      \"Christmas Island\",\n\t\tContinent: ContinentInfo{Region: \"OC-S\"},\n\t\tCenter:    Coordinates{Latitude: -10.000000, Longitude: 105.000000},\n\t},\n\t\"MG\": {\n\t\tName:      \"Madagascar\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -18.000000, Longitude: 46.000000},\n\t},\n\t\"CY\": {\n\t\tName:      \"Cyprus\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 35.000000, Longitude: 33.000000},\n\t},\n\t\"KW\": {\n\t\tName:      \"Kuwait\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 29.000000, Longitude: 47.000000},\n\t},\n\t\"IT\": {\n\t\tName:      \"Italy\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 41.000000, Longitude: 12.000000},\n\t},\n\t\"SJ\": {\n\t\tName:      \"Svalbard and Jan Mayen\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 77.000000, Longitude: 23.000000},\n\t},\n\t\"ZM\": {\n\t\tName:      \"Zambia\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -13.000000, Longitude: 27.000000},\n\t},\n\t\"TO\": {\n\t\tName:      \"Tonga\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -21.000000, Longitude: -175.000000},\n\t},\n\t\"EE\": {\n\t\tName:      \"Estonia\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 58.000000, Longitude: 25.000000},\n\t},\n\t\"LI\": {\n\t\tName:      \"Liechtenstein\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 47.000000, Longitude: 9.000000},\n\t},\n\t\"LB\": {\n\t\tName:      \"Lebanon\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 33.000000, Longitude: 35.000000},\n\t},\n\t\"DK\": {\n\t\tName:      \"Denmark\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 56.000000, Longitude: 9.000000},\n\t},\n\t\"LS\": {\n\t\tName:      \"Lesotho\",\n\t\tContinent: ContinentInfo{Region: \"AF-S\"},\n\t\tCenter:    Coordinates{Latitude: -29.000000, Longitude: 28.000000},\n\t},\n\t\"CM\": {\n\t\tName:      \"Cameroon\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: 7.000000, Longitude: 12.000000},\n\t},\n\t\"BH\": {\n\t\tName:      \"Bahrain\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 25.000000, Longitude: 50.000000},\n\t},\n\t\"NA\": {\n\t\tName:      \"Namibia\",\n\t\tContinent: ContinentInfo{Region: \"AF-S\"},\n\t\tCenter:    Coordinates{Latitude: -22.000000, Longitude: 18.000000},\n\t},\n\t\"ZA\": {\n\t\tName:      \"South Africa\",\n\t\tContinent: ContinentInfo{Region: \"AF-S\"},\n\t\tCenter:    Coordinates{Latitude: -30.000000, Longitude: 22.000000},\n\t},\n\t\"PH\": {\n\t\tName:      \"Philippines\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: 121.000000},\n\t},\n\t\"JM\": {\n\t\tName:      \"Jamaica\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -77.000000},\n\t},\n\t\"PS\": {\n\t\tName:      \"Palestine\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 31.000000, Longitude: 35.000000},\n\t},\n\t\"TM\": {\n\t\tName:      \"Turkmenistan\",\n\t\tContinent: ContinentInfo{Region: \"AS-C\"},\n\t\tCenter:    Coordinates{Latitude: 38.000000, Longitude: 59.000000},\n\t},\n\t\"SD\": {\n\t\tName:      \"Sudan\",\n\t\tContinent: ContinentInfo{Region: \"AF-N\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: 30.000000},\n\t},\n\t\"KN\": {\n\t\tName:      \"Saint Kitts and Nevis\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 17.000000, Longitude: -62.000000},\n\t},\n\t\"GF\": {\n\t\tName:      \"French Guiana\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: 3.000000, Longitude: -53.000000},\n\t},\n\t\"WS\": {\n\t\tName:      \"Samoa\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -13.000000, Longitude: -172.000000},\n\t},\n\t\"KE\": {\n\t\tName:      \"Kenya\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: 0.000000, Longitude: 37.000000},\n\t},\n\t\"CG\": {\n\t\tName:      \"Congo\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: 0.000000, Longitude: 15.000000},\n\t},\n\t\"FJ\": {\n\t\tName:      \"Fiji\",\n\t\tContinent: ContinentInfo{Region: \"OC-C\"},\n\t\tCenter:    Coordinates{Latitude: -16.000000, Longitude: 179.000000},\n\t},\n\t\"BL\": {\n\t\tName:      \"Saint Barthélemy\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 17.000000, Longitude: -62.000000},\n\t},\n\t\"TD\": {\n\t\tName:      \"Chad\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: 15.000000, Longitude: 18.000000},\n\t},\n\t\"TW\": {\n\t\tName:      \"Taiwan\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 23.000000, Longitude: 120.000000},\n\t},\n\t\"SA\": {\n\t\tName:      \"Saudi Arabia\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 23.000000, Longitude: 45.000000},\n\t},\n\t\"CO\": {\n\t\tName:      \"Colombia\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: 4.000000, Longitude: -74.000000},\n\t},\n\t\"FR\": {\n\t\tName:      \"France\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 46.000000, Longitude: 2.000000},\n\t},\n\t\"WF\": {\n\t\tName:      \"Wallis and Futuna\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -13.000000, Longitude: -177.000000},\n\t},\n\t\"QA\": {\n\t\tName:      \"Qatar\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 25.000000, Longitude: 51.000000},\n\t},\n\t\"IO\": {\n\t\tName:      \"British Indian Ocean Territory\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -6.000000, Longitude: 71.000000},\n\t},\n\t\"LT\": {\n\t\tName:      \"Lithuania\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 55.000000, Longitude: 23.000000},\n\t},\n\t\"IE\": {\n\t\tName:      \"Ireland\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 53.000000, Longitude: -8.000000},\n\t},\n\t\"GW\": {\n\t\tName:      \"Guinea-Bissau\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 11.000000, Longitude: -15.000000},\n\t},\n\t\"PE\": {\n\t\tName:      \"Peru\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -9.000000, Longitude: -75.000000},\n\t},\n\t\"MA\": {\n\t\tName:      \"Morocco\",\n\t\tContinent: ContinentInfo{Region: \"AF-N\"},\n\t\tCenter:    Coordinates{Latitude: 31.000000, Longitude: -7.000000},\n\t},\n\t\"CR\": {\n\t\tName:      \"Costa Rica\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 9.000000, Longitude: -83.000000},\n\t},\n\t\"FK\": {\n\t\tName:      \"Falkland Islands (Malvinas)\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -51.000000, Longitude: -59.000000},\n\t},\n\t\"PW\": {\n\t\tName:      \"Palau\",\n\t\tContinent: ContinentInfo{Region: \"OC-N\"},\n\t\tCenter:    Coordinates{Latitude: 7.000000, Longitude: 134.000000},\n\t},\n\t\"NC\": {\n\t\tName:      \"New Caledonia\",\n\t\tContinent: ContinentInfo{Region: \"OC-C\"},\n\t\tCenter:    Coordinates{Latitude: -20.000000, Longitude: 165.000000},\n\t},\n\t\"AM\": {\n\t\tName:      \"Armenia\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 40.000000, Longitude: 45.000000},\n\t},\n\t\"CU\": {\n\t\tName:      \"Cuba\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 21.000000, Longitude: -77.000000},\n\t},\n\t\"DE\": {\n\t\tName:      \"Germany\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 51.000000, Longitude: 10.000000},\n\t},\n\t\"MT\": {\n\t\tName:      \"Malta\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 35.000000, Longitude: 14.000000},\n\t},\n\t\"YE\": {\n\t\tName:      \"Yemen\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 15.000000, Longitude: 48.000000},\n\t},\n\t\"BA\": {\n\t\tName:      \"Bosnia and Herzegovina\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 43.000000, Longitude: 17.000000},\n\t},\n\t\"MP\": {\n\t\tName:      \"Northern Mariana Islands\",\n\t\tContinent: ContinentInfo{Region: \"OC-N\"},\n\t\tCenter:    Coordinates{Latitude: 17.000000, Longitude: 145.000000},\n\t},\n\t\"PY\": {\n\t\tName:      \"Paraguay\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -23.000000, Longitude: -58.000000},\n\t},\n\t\"MO\": {\n\t\tName:      \"Macao\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 22.000000, Longitude: 113.000000},\n\t},\n\t\"SH\": {\n\t\tName:      \"Saint Helena\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: -24.000000, Longitude: -10.000000},\n\t},\n\t\"PN\": {\n\t\tName:      \"Pitcairn\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -24.000000, Longitude: -127.000000},\n\t},\n\t\"GM\": {\n\t\tName:      \"Gambia\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 13.000000, Longitude: -15.000000},\n\t},\n\t\"TG\": {\n\t\tName:      \"Togo\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 8.000000, Longitude: 0.000000},\n\t},\n\t\"AT\": {\n\t\tName:      \"Austria\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 47.000000, Longitude: 14.000000},\n\t},\n\t\"GT\": {\n\t\tName:      \"Guatemala\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 15.000000, Longitude: -90.000000},\n\t},\n\t\"AE\": {\n\t\tName:      \"United Arab Emirates\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 23.000000, Longitude: 53.000000},\n\t},\n\t\"KR\": {\n\t\tName:      \"South Korea\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 35.000000, Longitude: 127.000000},\n\t},\n\t\"JE\": {\n\t\tName:      \"Jersey\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 49.000000, Longitude: -2.000000},\n\t},\n\t\"LV\": {\n\t\tName:      \"Latvia\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 56.000000, Longitude: 24.000000},\n\t},\n\t\"AW\": {\n\t\tName:      \"Aruba\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: -69.000000},\n\t},\n\t\"AO\": {\n\t\tName:      \"Angola\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: -11.000000, Longitude: 17.000000},\n\t},\n\t\"VE\": {\n\t\tName:      \"Venezuela\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: 6.000000, Longitude: -66.000000},\n\t},\n\t\"AG\": {\n\t\tName:      \"Antigua and Barbuda\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 17.000000, Longitude: -61.000000},\n\t},\n\t\"NU\": {\n\t\tName:      \"Niue\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -19.000000, Longitude: -169.000000},\n\t},\n\t\"KY\": {\n\t\tName:      \"Cayman Islands\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 19.000000, Longitude: -80.000000},\n\t},\n\t\"IM\": {\n\t\tName:      \"Isle of Man\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 54.000000, Longitude: -4.000000},\n\t},\n\t\"FM\": {\n\t\tName:      \"Micronesia\",\n\t\tContinent: ContinentInfo{Region: \"OC-N\"},\n\t\tCenter:    Coordinates{Latitude: 7.000000, Longitude: 150.000000},\n\t},\n\t\"SB\": {\n\t\tName:      \"Solomon Islands\",\n\t\tContinent: ContinentInfo{Region: \"OC-C\"},\n\t\tCenter:    Coordinates{Latitude: -9.000000, Longitude: 160.000000},\n\t},\n\t\"LU\": {\n\t\tName:      \"Luxembourg\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 49.000000, Longitude: 6.000000},\n\t},\n\t\"MF\": {\n\t\tName:      \"Saint Martin\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -63.000000},\n\t},\n\t\"AQ\": {\n\t\tName:      \"Antarctica\",\n\t\tContinent: ContinentInfo{Region: \"AN\"},\n\t\tCenter:    Coordinates{Latitude: -75.000000, Longitude: 0.000000},\n\t},\n\t\"SC\": {\n\t\tName:      \"Seychelles\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -4.000000, Longitude: 55.000000},\n\t},\n\t\"TL\": {\n\t\tName:      \"Timor-Leste\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: -8.000000, Longitude: 125.000000},\n\t},\n\t\"CC\": {\n\t\tName:      \"Cocos (Keeling) Islands\",\n\t\tContinent: ContinentInfo{Region: \"OC-S\"},\n\t\tCenter:    Coordinates{Latitude: -12.000000, Longitude: 96.000000},\n\t},\n\t\"ST\": {\n\t\tName:      \"Sao Tome and Principe\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: 0.000000, Longitude: 6.000000},\n\t},\n\t\"NO\": {\n\t\tName:      \"Norway\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 60.000000, Longitude: 8.000000},\n\t},\n\t\"CF\": {\n\t\tName:      \"Central African Republic\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: 6.000000, Longitude: 20.000000},\n\t},\n\t\"MR\": {\n\t\tName:      \"Mauritania\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 21.000000, Longitude: -10.000000},\n\t},\n\t\"NI\": {\n\t\tName:      \"Nicaragua\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: -85.000000},\n\t},\n\t\"AI\": {\n\t\tName:      \"Anguilla\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -63.000000},\n\t},\n\t\"AZ\": {\n\t\tName:      \"Azerbaijan\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 40.000000, Longitude: 47.000000},\n\t},\n\t\"US\": {\n\t\tName:      \"United States of America\",\n\t\tContinent: ContinentInfo{Region: \"NA-N\"},\n\t\tCenter:    Coordinates{Latitude: 37.000000, Longitude: -95.000000},\n\t},\n\t\"LA\": {\n\t\tName:      \"Lao\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 19.000000, Longitude: 102.000000},\n\t},\n\t\"BB\": {\n\t\tName:      \"Barbados\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 13.000000, Longitude: -59.000000},\n\t},\n\t\"CD\": {\n\t\tName:      \"DR Congo\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: -4.000000, Longitude: 21.000000},\n\t},\n\t\"TK\": {\n\t\tName:      \"Tokelau\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -8.000000, Longitude: -171.000000},\n\t},\n\t\"KZ\": {\n\t\tName:      \"Kazakhstan\",\n\t\tContinent: ContinentInfo{Region: \"AS-C\"},\n\t\tCenter:    Coordinates{Latitude: 48.000000, Longitude: 66.000000},\n\t},\n\t\"DM\": {\n\t\tName:      \"Dominica\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 15.000000, Longitude: -61.000000},\n\t},\n\t\"EG\": {\n\t\tName:      \"Egypt\",\n\t\tContinent: ContinentInfo{Region: \"AF-N\"},\n\t\tCenter:    Coordinates{Latitude: 26.000000, Longitude: 30.000000},\n\t},\n\t\"GH\": {\n\t\tName:      \"Ghana\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 7.000000, Longitude: -1.000000},\n\t},\n\t\"BI\": {\n\t\tName:      \"Burundi\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -3.000000, Longitude: 29.000000},\n\t},\n\t\"NZ\": {\n\t\tName:      \"New Zealand\",\n\t\tContinent: ContinentInfo{Region: \"OC-S\"},\n\t\tCenter:    Coordinates{Latitude: -40.000000, Longitude: 174.000000},\n\t},\n\t\"BJ\": {\n\t\tName:      \"Benin\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 9.000000, Longitude: 2.000000},\n\t},\n\t\"HU\": {\n\t\tName:      \"Hungary\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 47.000000, Longitude: 19.000000},\n\t},\n\t\"BD\": {\n\t\tName:      \"Bangladesh\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 23.000000, Longitude: 90.000000},\n\t},\n\t\"NF\": {\n\t\tName:      \"Norfolk Island\",\n\t\tContinent: ContinentInfo{Region: \"OC-S\"},\n\t\tCenter:    Coordinates{Latitude: -29.000000, Longitude: 167.000000},\n\t},\n\t\"LY\": {\n\t\tName:      \"Libya\",\n\t\tContinent: ContinentInfo{Region: \"AF-N\"},\n\t\tCenter:    Coordinates{Latitude: 26.000000, Longitude: 17.000000},\n\t},\n\t\"TV\": {\n\t\tName:      \"Tuvalu\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -7.000000, Longitude: 177.000000},\n\t},\n\t\"ZW\": {\n\t\tName:      \"Zimbabwe\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -19.000000, Longitude: 29.000000},\n\t},\n\t\"NG\": {\n\t\tName:      \"Nigeria\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 9.000000, Longitude: 8.000000},\n\t},\n\t\"GD\": {\n\t\tName:      \"Grenada\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: -61.000000},\n\t},\n\t\"SM\": {\n\t\tName:      \"San Marino\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 43.000000, Longitude: 12.000000},\n\t},\n\t\"RU\": {\n\t\tName:      \"Russian Federation\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 61.000000, Longitude: 105.000000},\n\t},\n\t\"DZ\": {\n\t\tName:      \"Algeria\",\n\t\tContinent: ContinentInfo{Region: \"AF-N\"},\n\t\tCenter:    Coordinates{Latitude: 28.000000, Longitude: 1.000000},\n\t},\n\t\"DO\": {\n\t\tName:      \"Dominican Republic\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -70.000000},\n\t},\n\t\"SI\": {\n\t\tName:      \"Slovenia\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 46.000000, Longitude: 14.000000},\n\t},\n\t\"BZ\": {\n\t\tName:      \"Belize\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 17.000000, Longitude: -88.000000},\n\t},\n\t\"DJ\": {\n\t\tName:      \"Djibouti\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: 11.000000, Longitude: 42.000000},\n\t},\n\t\"GN\": {\n\t\tName:      \"Guinea\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 9.000000, Longitude: -9.000000},\n\t},\n\t\"VN\": {\n\t\tName:      \"Viet Nam\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 14.000000, Longitude: 108.000000},\n\t},\n\t\"IR\": {\n\t\tName:      \"Iran\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 32.000000, Longitude: 53.000000},\n\t},\n\t\"KG\": {\n\t\tName:      \"Kyrgyzstan\",\n\t\tContinent: ContinentInfo{Region: \"AS-C\"},\n\t\tCenter:    Coordinates{Latitude: 41.000000, Longitude: 74.000000},\n\t},\n\t\"ML\": {\n\t\tName:      \"Mali\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 17.000000, Longitude: -3.000000},\n\t},\n\t\"GP\": {\n\t\tName:      \"Guadeloupe\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 16.000000, Longitude: -62.000000},\n\t},\n\t\"FI\": {\n\t\tName:      \"Finland\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 61.000000, Longitude: 25.000000},\n\t},\n\t\"UA\": {\n\t\tName:      \"Ukraine\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 48.000000, Longitude: 31.000000},\n\t},\n\t\"KP\": {\n\t\tName:      \"North Korea (DPRK)\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 40.000000, Longitude: 127.000000},\n\t},\n\t\"BT\": {\n\t\tName:      \"Bhutan\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 27.000000, Longitude: 90.000000},\n\t},\n\t\"BG\": {\n\t\tName:      \"Bulgaria\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 42.000000, Longitude: 25.000000},\n\t},\n\t\"MM\": {\n\t\tName:      \"Myanmar\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 21.000000, Longitude: 95.000000},\n\t},\n\t\"PK\": {\n\t\tName:      \"Pakistan\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 30.000000, Longitude: 69.000000},\n\t},\n\t\"KI\": {\n\t\tName:      \"Kiribati\",\n\t\tContinent: ContinentInfo{Region: \"OC-N\"},\n\t\tCenter:    Coordinates{Latitude: -3.000000, Longitude: -168.000000},\n\t},\n\t\"GL\": {\n\t\tName:      \"Greenland\",\n\t\tContinent: ContinentInfo{Region: \"NA-N\"},\n\t\tCenter:    Coordinates{Latitude: 71.000000, Longitude: -42.000000},\n\t},\n\t\"PG\": {\n\t\tName:      \"Papua New Guinea\",\n\t\tContinent: ContinentInfo{Region: \"OC-C\"},\n\t\tCenter:    Coordinates{Latitude: -6.000000, Longitude: 143.000000},\n\t},\n\t\"PF\": {\n\t\tName:      \"French Polynesia\",\n\t\tContinent: ContinentInfo{Region: \"OC-E\"},\n\t\tCenter:    Coordinates{Latitude: -17.000000, Longitude: -149.000000},\n\t},\n\t\"VU\": {\n\t\tName:      \"Vanuatu\",\n\t\tContinent: ContinentInfo{Region: \"OC-C\"},\n\t\tCenter:    Coordinates{Latitude: -15.000000, Longitude: 166.000000},\n\t},\n\t\"HT\": {\n\t\tName:      \"Haiti\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -72.000000},\n\t},\n\t\"SV\": {\n\t\tName:      \"El Salvador\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 13.000000, Longitude: -88.000000},\n\t},\n\t\"EC\": {\n\t\tName:      \"Ecuador\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -1.000000, Longitude: -78.000000},\n\t},\n\t\"KM\": {\n\t\tName:      \"Comoros\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -11.000000, Longitude: 43.000000},\n\t},\n\t\"VI\": {\n\t\tName:      \"Virgin Islands (U.S.)\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -64.000000},\n\t},\n\t\"YT\": {\n\t\tName:      \"Mayotte\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -12.000000, Longitude: 45.000000},\n\t},\n\t\"ET\": {\n\t\tName:      \"Ethiopia\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: 9.000000, Longitude: 40.000000},\n\t},\n\t\"JO\": {\n\t\tName:      \"Jordan\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 30.000000, Longitude: 36.000000},\n\t},\n\t\"RE\": {\n\t\tName:      \"Réunion\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -21.000000, Longitude: 55.000000},\n\t},\n\t\"NR\": {\n\t\tName:      \"Nauru\",\n\t\tContinent: ContinentInfo{Region: \"OC-N\"},\n\t\tCenter:    Coordinates{Latitude: 0.000000, Longitude: 166.000000},\n\t},\n\t\"HK\": {\n\t\tName:      \"Hong Kong\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 22.000000, Longitude: 114.000000},\n\t},\n\t\"AU\": {\n\t\tName:      \"Australia\",\n\t\tContinent: ContinentInfo{Region: \"OC-S\"},\n\t\tCenter:    Coordinates{Latitude: -25.000000, Longitude: 133.000000},\n\t},\n\t\"FO\": {\n\t\tName:      \"Faroe Islands\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 61.000000, Longitude: -6.000000},\n\t},\n\t\"IQ\": {\n\t\tName:      \"Iraq\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 33.000000, Longitude: 43.000000},\n\t},\n\t\"GE\": {\n\t\tName:      \"Georgia\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 42.000000, Longitude: 43.000000},\n\t},\n\t\"UZ\": {\n\t\tName:      \"Uzbekistan\",\n\t\tContinent: ContinentInfo{Region: \"AS-C\"},\n\t\tCenter:    Coordinates{Latitude: 41.000000, Longitude: 64.000000},\n\t},\n\t\"IN\": {\n\t\tName:      \"India\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 20.000000, Longitude: 78.000000},\n\t},\n\t\"MX\": {\n\t\tName:      \"Mexico\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 23.000000, Longitude: -102.000000},\n\t},\n\t\"ER\": {\n\t\tName:      \"Eritrea\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: 15.000000, Longitude: 39.000000},\n\t},\n\t\"AL\": {\n\t\tName:      \"Albania\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 41.000000, Longitude: 20.000000},\n\t},\n\t\"GY\": {\n\t\tName:      \"Guyana\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: 4.000000, Longitude: -58.000000},\n\t},\n\t\"CA\": {\n\t\tName:      \"Canada\",\n\t\tContinent: ContinentInfo{Region: \"NA-N\"},\n\t\tCenter:    Coordinates{Latitude: 56.000000, Longitude: -106.000000},\n\t},\n\t\"SY\": {\n\t\tName:      \"Syrian Arab Republic\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 34.000000, Longitude: 38.000000},\n\t},\n\t\"SG\": {\n\t\tName:      \"Singapore\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 1.000000, Longitude: 103.000000},\n\t},\n\t\"VG\": {\n\t\tName:      \"Virgin Islands (British)\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -64.000000},\n\t},\n\t\"MC\": {\n\t\tName:      \"Monaco\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 43.000000, Longitude: 7.000000},\n\t},\n\t\"BM\": {\n\t\tName:      \"Bermuda\",\n\t\tContinent: ContinentInfo{Region: \"NA-N\"},\n\t\tCenter:    Coordinates{Latitude: 32.000000, Longitude: -64.000000},\n\t},\n\t\"SX\": {\n\t\tName:      \"Sint Maarten\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -63.000000},\n\t},\n\t\"SR\": {\n\t\tName:      \"Suriname\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: 3.000000, Longitude: -56.000000},\n\t},\n\t\"MD\": {\n\t\tName:      \"Moldova\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 47.000000, Longitude: 28.000000},\n\t},\n\t\"CZ\": {\n\t\tName:      \"Czechia\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 49.000000, Longitude: 15.000000},\n\t},\n\t\"GQ\": {\n\t\tName:      \"Equatorial Guinea\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: 1.000000, Longitude: 10.000000},\n\t},\n\t\"TF\": {\n\t\tName:      \"French Southern Territories\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -49.000000, Longitude: 69.000000},\n\t},\n\t\"CI\": {\n\t\tName:      \"Côte d'Ivoire\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 7.000000, Longitude: -5.000000},\n\t},\n\t\"VA\": {\n\t\tName:      \"Holy See\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 41.000000, Longitude: 12.000000},\n\t},\n\t\"SN\": {\n\t\tName:      \"Senegal\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 14.000000, Longitude: -14.000000},\n\t},\n\t\"PR\": {\n\t\tName:      \"Puerto Rico\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 18.000000, Longitude: -66.000000},\n\t},\n\t\"ID\": {\n\t\tName:      \"Indonesia\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 0.000000, Longitude: 113.000000},\n\t},\n\t\"BS\": {\n\t\tName:      \"Bahamas\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 25.000000, Longitude: -77.000000},\n\t},\n\t\"CV\": {\n\t\tName:      \"Cabo Verde\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 16.000000, Longitude: -24.000000},\n\t},\n\t\"AD\": {\n\t\tName:      \"Andorra\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 42.000000, Longitude: 1.000000},\n\t},\n\t\"SK\": {\n\t\tName:      \"Slovakia\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 48.000000, Longitude: 19.000000},\n\t},\n\t\"MV\": {\n\t\tName:      \"Maldives\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 3.000000, Longitude: 73.000000},\n\t},\n\t\"ME\": {\n\t\tName:      \"Montenegro\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 42.000000, Longitude: 19.000000},\n\t},\n\t\"LK\": {\n\t\tName:      \"Sri Lanka\",\n\t\tContinent: ContinentInfo{Region: \"AS-S\"},\n\t\tCenter:    Coordinates{Latitude: 7.000000, Longitude: 80.000000},\n\t},\n\t\"KH\": {\n\t\tName:      \"Cambodia\",\n\t\tContinent: ContinentInfo{Region: \"AS-SE\"},\n\t\tCenter:    Coordinates{Latitude: 12.000000, Longitude: 104.000000},\n\t},\n\t\"GR\": {\n\t\tName:      \"Greece\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 39.000000, Longitude: 21.000000},\n\t},\n\t\"SL\": {\n\t\tName:      \"Sierra Leone\",\n\t\tContinent: ContinentInfo{Region: \"AF-W\"},\n\t\tCenter:    Coordinates{Latitude: 8.000000, Longitude: -11.000000},\n\t},\n\t\"XK\": {\n\t\tName:      \"Kosovo\",\n\t\tContinent: ContinentInfo{Region: \"EU-E\"},\n\t\tCenter:    Coordinates{Latitude: 42.000000, Longitude: 20.000000},\n\t},\n\t\"TJ\": {\n\t\tName:      \"Tajikistan\",\n\t\tContinent: ContinentInfo{Region: \"AS-C\"},\n\t\tCenter:    Coordinates{Latitude: 38.000000, Longitude: 71.000000},\n\t},\n\t\"SE\": {\n\t\tName:      \"Sweden\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 60.000000, Longitude: 18.000000},\n\t},\n\t\"GA\": {\n\t\tName:      \"Gabon\",\n\t\tContinent: ContinentInfo{Region: \"AF-C\"},\n\t\tCenter:    Coordinates{Latitude: 0.000000, Longitude: 11.000000},\n\t},\n\t\"UY\": {\n\t\tName:      \"Uruguay\",\n\t\tContinent: ContinentInfo{Region: \"SA\"},\n\t\tCenter:    Coordinates{Latitude: -32.000000, Longitude: -55.000000},\n\t},\n\t\"MZ\": {\n\t\tName:      \"Mozambique\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -18.000000, Longitude: 35.000000},\n\t},\n\t\"PA\": {\n\t\tName:      \"Panama\",\n\t\tContinent: ContinentInfo{Region: \"NA-S\"},\n\t\tCenter:    Coordinates{Latitude: 8.000000, Longitude: -80.000000},\n\t},\n\t\"SZ\": {\n\t\tName:      \"Eswatini\",\n\t\tContinent: ContinentInfo{Region: \"AF-S\"},\n\t\tCenter:    Coordinates{Latitude: -26.000000, Longitude: 31.000000},\n\t},\n\t\"IL\": {\n\t\tName:      \"Israel\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 31.000000, Longitude: 34.000000},\n\t},\n\t\"GB\": {\n\t\tName:      \"United Kingdom\",\n\t\tContinent: ContinentInfo{Region: \"EU-N\"},\n\t\tCenter:    Coordinates{Latitude: 55.000000, Longitude: -3.000000},\n\t},\n\t\"ES\": {\n\t\tName:      \"Spain\",\n\t\tContinent: ContinentInfo{Region: \"EU-S\"},\n\t\tCenter:    Coordinates{Latitude: 40.000000, Longitude: -3.000000},\n\t},\n\t\"RW\": {\n\t\tName:      \"Rwanda\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: -1.000000, Longitude: 29.000000},\n\t},\n\t\"EH\": {\n\t\tName:      \"Western Sahara\",\n\t\tContinent: ContinentInfo{Region: \"AF-N\"},\n\t\tCenter:    Coordinates{Latitude: 24.000000, Longitude: -12.000000},\n\t},\n\t\"MH\": {\n\t\tName:      \"Marshall Islands\",\n\t\tContinent: ContinentInfo{Region: \"OC-N\"},\n\t\tCenter:    Coordinates{Latitude: 7.000000, Longitude: 171.000000},\n\t},\n\t\"MQ\": {\n\t\tName:      \"Martinique\",\n\t\tContinent: ContinentInfo{Region: \"NA-E\"},\n\t\tCenter:    Coordinates{Latitude: 14.000000, Longitude: -61.000000},\n\t},\n\t\"CH\": {\n\t\tName:      \"Switzerland\",\n\t\tContinent: ContinentInfo{Region: \"EU-W\"},\n\t\tCenter:    Coordinates{Latitude: 46.000000, Longitude: 8.000000},\n\t},\n\t\"CN\": {\n\t\tName:      \"China\",\n\t\tContinent: ContinentInfo{Region: \"AS-E\"},\n\t\tCenter:    Coordinates{Latitude: 35.000000, Longitude: 104.000000},\n\t},\n\t\"TR\": {\n\t\tName:      \"Turkey\",\n\t\tContinent: ContinentInfo{Region: \"AS-W\"},\n\t\tCenter:    Coordinates{Latitude: 38.000000, Longitude: 35.000000},\n\t},\n\t\"BW\": {\n\t\tName:      \"Botswana\",\n\t\tContinent: ContinentInfo{Region: \"AF-S\"},\n\t\tCenter:    Coordinates{Latitude: -22.000000, Longitude: 24.000000},\n\t},\n\t\"SS\": {\n\t\tName:      \"South Sudan\",\n\t\tContinent: ContinentInfo{Region: \"AF-E\"},\n\t\tCenter:    Coordinates{Latitude: 4.000000, Longitude: 31.000000},\n\t},\n}\n"
  },
  {
    "path": "service/intel/geoip/country_info_test.go",
    "content": "package geoip\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestCountryInfo(t *testing.T) {\n\tt.Parallel()\n\n\tfor key, country := range countries {\n\t\t// Skip special anycast country.\n\t\tif key == \"__\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif key != country.Code {\n\t\t\tt.Errorf(\"%s has a wrong country code of %q\", key, country.Code)\n\t\t}\n\t\tif country.Name == \"\" {\n\t\t\tt.Errorf(\"%s is missing name\", key)\n\t\t}\n\t\tif country.Continent.Code == \"\" {\n\t\t\tt.Errorf(\"%s is missing continent\", key)\n\t\t}\n\t\tif country.Continent.Region == \"\" {\n\t\t\tt.Errorf(\"%s is missing continent region\", key)\n\t\t}\n\t\tif country.Continent.Name == \"\" {\n\t\t\tt.Errorf(\"%s is missing continent name\", key)\n\t\t}\n\t\tgeneratedContinentCode, _, _ := strings.Cut(country.Continent.Region, \"-\")\n\t\tif country.Continent.Code != generatedContinentCode {\n\t\t\tt.Errorf(\"%s is has wrong continent code or region\", key)\n\t\t}\n\t\tif country.Center.Latitude == 0 && country.Center.Longitude == 0 {\n\t\t\tt.Errorf(\"%s is missing coords\", key)\n\t\t}\n\t\tif country.Center.AccuracyRadius == 0 {\n\t\t\tt.Errorf(\"%s is missing accuracy radius\", key)\n\t\t}\n\n\t\t// Generate map source from data:\n\t\t// fmt.Printf(\n\t\t// \t`\"%s\": {Name:%q,Region:%q,ContinentCode:%q,Center:Coordinates{AccuracyRadius:%d,Latitude:%f,Longitude:%f},},`,\n\t\t// \tkey,\n\t\t// \tcountry.Name,\n\t\t// \tcountry.Region,\n\t\t// \tcountry.ContinentCode,\n\t\t// \tcountry.Center.AccuracyRadius,\n\t\t// \tcountry.Center.Latitude,\n\t\t// \tcountry.Center.Longitude,\n\t\t// )\n\t\t// fmt.Println()\n\t}\n\tif len(countries) < 247 {\n\t\tt.Errorf(\"dataset only includes %d countries\", len(countries))\n\t}\n}\n"
  },
  {
    "path": "service/intel/geoip/database.go",
    "content": "package geoip\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\tmaxminddb \"github.com/oschwald/maxminddb-golang\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nvar worker *updateWorker\n\nfunc init() {\n\tworker = &updateWorker{\n\t\ttrigger: make(chan struct{}),\n\t\tv4: updateBroadcaster{\n\t\t\tdbName: v4MMDBResource,\n\t\t},\n\t\tv6: updateBroadcaster{\n\t\t\tdbName: v6MMDBResource,\n\t\t},\n\t}\n}\n\nconst (\n\tv4MMDBResource = \"geoipv4.mmdb\"\n\tv6MMDBResource = \"geoipv6.mmdb\"\n)\n\ntype geoIPDB struct {\n\t*maxminddb.Reader\n\tupdate *updates.Artifact\n}\n\n// updateBroadcaster stores a geoIPDB and provides synchronized\n// access to the MMDB reader. It also supports broadcasting to\n// multiple waiters when a new database becomes available.\ntype updateBroadcaster struct {\n\trw     sync.RWMutex\n\tdb     *geoIPDB\n\tdbName string\n\n\twaiter chan struct{}\n}\n\n// AvailableUpdate returns a new update artifact if the current broadcaster\n// needs a database update.\nfunc (ub *updateBroadcaster) AvailableUpdate() *updates.Artifact {\n\tub.rw.RLock()\n\tdefer ub.rw.RUnlock()\n\n\t// Get artifact.\n\tartifact, err := module.instance.IntelUpdates().GetFile(ub.dbName)\n\tif err != nil {\n\t\tlog.Warningf(\"geoip: failed to get geoip update: %s\", err)\n\t\treturn nil\n\t}\n\n\t// Return artifact if not yet initialized.\n\tif ub.db == nil {\n\t\treturn artifact\n\t}\n\n\t// Compare and return artifact only when confirmed newer.\n\tif newer, _ := artifact.IsNewerThan(ub.db.update); newer {\n\t\treturn artifact\n\t}\n\treturn nil\n}\n\n// ReplaceDatabase replaces (or initially sets) the mmdb database.\n// It also notifies all waiters about the availability of the new\n// database.\nfunc (ub *updateBroadcaster) ReplaceDatabase(db *geoIPDB) {\n\tub.rw.Lock()\n\tdefer ub.rw.Unlock()\n\n\tif ub.db != nil {\n\t\t_ = ub.db.Close()\n\t}\n\tub.db = db\n\tub.notifyWaiters()\n}\n\n// notifyWaiters notifies and removes all waiters. Must be called\n// with ub.rw locked.\nfunc (ub *updateBroadcaster) notifyWaiters() {\n\tif ub.waiter == nil {\n\t\treturn\n\t}\n\twaiter := ub.waiter\n\tub.waiter = nil\n\tclose(waiter)\n}\n\n// getWaiter appends and returns a new waiter channel that gets closed\n// when a new database version is available. Must be called with\n// ub.rw locked.\nfunc (ub *updateBroadcaster) getWaiter() chan struct{} {\n\tif ub.waiter != nil {\n\t\treturn ub.waiter\n\t}\n\n\tub.waiter = make(chan struct{})\n\treturn ub.waiter\n}\n\ntype updateWorker struct {\n\ttrigger chan struct{}\n\tonce    sync.Once\n\n\tv4 updateBroadcaster\n\tv6 updateBroadcaster\n}\n\n// GetReader returns a MMDB reader for either the IPv4 or the IPv6 database.\n// If wait is true GetReader will wait at most 1 second for the database to\n// become available. If no database is available or GetReader times-out while\n// waiting nil is returned.\nfunc (upd *updateWorker) GetReader(v6 bool, wait bool) *maxminddb.Reader {\n\t// check which updateBroadcaster we need to use\n\tub := &upd.v4\n\tif v6 {\n\t\tub = &upd.v6\n\t}\n\n\t// lock the updateBroadcaster and - if we are allowed to wait -\n\t// create a new waiter channel, trigger an update and wait for at\n\t// least 1 second for the update to complete.\n\tub.rw.Lock()\n\tif ub.db == nil {\n\t\tif wait {\n\t\t\twaiter := ub.getWaiter()\n\t\t\tub.rw.Unlock()\n\n\t\t\tupd.triggerUpdate()\n\n\t\t\tselect {\n\t\t\tcase <-waiter:\n\t\t\t\t// call this method again but this time we don't allow\n\t\t\t\t// it to wait since there must be a open database anyway ...\n\t\t\t\treturn upd.GetReader(v6, false)\n\t\t\tcase <-time.After(time.Second):\n\t\t\t\t// we tried hard but failed so give up here\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tub.rw.Unlock()\n\t\treturn nil\n\t}\n\trd := ub.db.Reader\n\tub.rw.Unlock()\n\n\treturn rd\n}\n\n// triggerUpdate triggers a database update check.\nfunc (upd *updateWorker) triggerUpdate() {\n\tupd.start()\n\n\tselect {\n\tcase upd.trigger <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc (upd *updateWorker) start() {\n\tupd.once.Do(func() {\n\t\tmodule.mgr.Go(\"geoip-updater\", upd.run)\n\t})\n}\n\nfunc (upd *updateWorker) run(ctx *mgr.WorkerCtx) error {\n\tfor {\n\t\tupdate := upd.v4.AvailableUpdate()\n\t\tif update != nil {\n\t\t\tif v4, err := getGeoIPDB(update); err == nil {\n\t\t\t\tupd.v4.ReplaceDatabase(v4)\n\t\t\t} else {\n\t\t\t\tlog.Warningf(\"geoip: failed to get v4 database: %s\", err)\n\t\t\t}\n\t\t}\n\n\t\tupdate = upd.v6.AvailableUpdate()\n\t\tif update != nil {\n\t\t\tif v6, err := getGeoIPDB(update); err == nil {\n\t\t\t\tupd.v6.ReplaceDatabase(v6)\n\t\t\t} else {\n\t\t\t\tlog.Warningf(\"geoip: failed to get v6 database: %s\", err)\n\t\t\t}\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-upd.trigger:\n\t\t}\n\t}\n}\n\nfunc getGeoIPDB(update *updates.Artifact) (*geoIPDB, error) {\n\tlog.Debugf(\"geoip: opening database %s\", update.Path())\n\n\treader, err := maxminddb.Open(update.Path())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open: %w\", err)\n\t}\n\tlog.Debugf(\"geoip: successfully opened database %s\", update.Filename)\n\n\treturn &geoIPDB{\n\t\tReader: reader,\n\t\tupdate: update,\n\t}, nil\n}\n"
  },
  {
    "path": "service/intel/geoip/init_test.go",
    "content": "package geoip\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/configure\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype testInstance struct {\n\tdb           *dbmodule.DBModule\n\tapi          *api.API\n\tconfig       *config.Config\n\tintelUpdates *updates.Updater\n}\n\nvar _ instance = &testInstance{}\n\nfunc (stub *testInstance) IntelUpdates() *updates.Updater              { return stub.intelUpdates }\nfunc (stub *testInstance) Config() *config.Config                      { return stub.config }\nfunc (stub *testInstance) Notifications() *notifications.Notifications { return nil }\nfunc (stub *testInstance) Ready() bool                                 { return true }\nfunc (stub *testInstance) Restart()                                    {}\nfunc (stub *testInstance) Shutdown()                                   {}\nfunc (stub *testInstance) SetCmdLineOperation(f func() error)          {}\nfunc (stub *testInstance) BinaryUpdates() *updates.Updater             { return nil }\nfunc (stub *testInstance) UI() *ui.UI                                  { return nil }\nfunc (stub *testInstance) DataDir() string                             { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tvar err error\n\n\t// Create a temporary directory for testing\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temporary data directory: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Initialize the Intel update configuration\n\tintelUpdateConfig := updates.Config{\n\t\tName:              configure.DefaultIntelIndexName,\n\t\tDirectory:         filepath.Join(_dataDir, \"test_intel\"),\n\t\tDownloadDirectory: filepath.Join(_dataDir, \"test_download_intel\"),\n\t\tPurgeDirectory:    filepath.Join(_dataDir, \"test_upgrade_obsolete_intel\"),\n\t\tIndexURLs:         configure.DefaultIntelIndexURLs,\n\t\tIndexFile:         \"index.json\",\n\t\tAutoCheck:         true,\n\t\tAutoDownload:      true,\n\t\tAutoApply:         true,\n\t}\n\n\t// Set the default API listen address\n\tapi.SetDefaultAPIListenAddress(\"0.0.0.0:8080\")\n\n\t// Initialize the instance with the necessary components\n\tstub := &testInstance{}\n\tstub.db, err = dbmodule.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database: %w\", err)\n\t}\n\tstub.config, err = config.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config: %w\", err)\n\t}\n\tstub.api, err = api.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create api: %w\", err)\n\t}\n\tstub.intelUpdates, err = updates.New(stub, \"Intel Updater\", intelUpdateConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create updates: %w\", err)\n\t}\n\tmodule, err = New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to initialize module: %w\", err)\n\t}\n\terr = stub.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start database: %w\", err)\n\t}\n\terr = stub.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start config: %w\", err)\n\t}\n\terr = stub.api.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start api: %w\", err)\n\t}\n\terr = stub.intelUpdates.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start updates: %w\", err)\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start module: %w\", err)\n\t}\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "service/intel/geoip/location.go",
    "content": "package geoip\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/umahmood/haversine\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\nconst (\n\tearthCircumferenceInKm  = 40100 // earth circumference in km\n\tdefaultLocationAccuracy = 100\n)\n\n// Location holds information regarding the geographical and network location of an IP address.\n// TODO: We are currently re-using the Continent-Code for the region. Update this and all dependencies.\ntype Location struct {\n\tCountry                      CountryInfo `maxminddb:\"country\"`\n\tCoordinates                  Coordinates `maxminddb:\"location\"`\n\tAutonomousSystemNumber       uint        `maxminddb:\"autonomous_system_number\"`\n\tAutonomousSystemOrganization string      `maxminddb:\"autonomous_system_organization\"`\n\tIsAnycast                    bool        `maxminddb:\"is_anycast\"`\n\tIsSatelliteProvider          bool        `maxminddb:\"is_satellite_provider\"`\n\tIsAnonymousProxy             bool        `maxminddb:\"is_anonymous_proxy\"`\n}\n\n// Coordinates holds geographic coordinates and their estimated accuracy.\ntype Coordinates struct {\n\tAccuracyRadius uint16  `maxminddb:\"accuracy_radius\"`\n\tLatitude       float64 `maxminddb:\"latitude\"`\n\tLongitude      float64 `maxminddb:\"longitude\"`\n}\n\n/*\n\tLocation Estimation\n\n\tDistance Value\n\n\t- 0: Other side of the Internet.\n\t- 100: Very near, up to same network / datacenter.\n\n\tWeighting Goal\n\n\t- Exposure to different networks shall be limited as much as possible.\n\t- A single network should not see a connection over a large distance.\n\t- Latency should be low.\n\n\tWeighting Intentions\n\n\t- Being on the same continent is better than being in the same AS.\n\t- Being in the same country is better than having low coordinate distance.\n\t- Coordinate distance is only a tie breaker, as accuracy varies heavily.\n\t- Same AS with lower coordinate distance beats being on the same continent.\n\n\tWeighting Configuration\n*/\n\nconst (\n\tweightCountryMatch          = 10\n\tweightRegionMatch           = 10\n\tweightRegionalNeighborMatch = 10\n\n\tweightASNMatch   = 10\n\tweightASOrgMatch = 10\n\n\tweightCoordinateDistance = 50\n)\n\n/*\n\tAbout the Accuracy Radius\n\n\t- Range: 1-1000\n\t- Seen values (estimation): 1,5,10,20,50,100,200,500,1000\n\t- The default seems to be 100.\n\n\tCxamples\n\n\t- 1.1.1/24 has 1000: Anycast\n\t- 8.8.0/19 has 1000: Anycast\n\t- 8.8.52/22 has 1: City of Westfield\n\n\tConclusion\n\n\t- Ignore or penalize high accuracy radius.\n*/\n\n// EstimateNetworkProximity aims to calculate the distance between two network locations. Returns a proximity value between 0 (far away) and 100 (nearby).\nfunc (l *Location) EstimateNetworkProximity(to *Location) (proximity float32) {\n\tswitch {\n\tcase l.Country.Code != \"\" && l.Country.Code == to.Country.Code:\n\t\tproximity += weightCountryMatch + weightRegionMatch + weightRegionalNeighborMatch\n\tcase l.Country.Continent.Region != \"\" && l.Country.Continent.Region == to.Country.Continent.Region:\n\t\tproximity += weightRegionMatch + weightRegionalNeighborMatch\n\tcase l.IsRegionalNeighbor(to):\n\t\tproximity += weightRegionalNeighborMatch\n\t}\n\n\tswitch {\n\tcase l.AutonomousSystemNumber == to.AutonomousSystemNumber &&\n\t\tl.AutonomousSystemNumber != 0:\n\t\t// Rely more on the ASN data, as it is more accurate than the ASOrg data,\n\t\t// especially when combining location data from multiple sources.\n\t\tproximity += weightASNMatch + weightASOrgMatch\n\tcase l.AutonomousSystemOrganization == to.AutonomousSystemOrganization &&\n\t\tl.AutonomousSystemNumber != 0 && // Check if an ASN is set. If the ASOrg is known, the ASN must be too.\n\t\t!ASOrgUnknown(l.AutonomousSystemOrganization): // Check if the ASOrg name is valid.\n\t\tproximity += weightASOrgMatch\n\t}\n\n\t// Check coordinates and adjust accuracy value.\n\taccuracy := l.Coordinates.AccuracyRadius\n\tswitch {\n\tcase l.Coordinates.Latitude == 0 && l.Coordinates.Longitude == 0:\n\t\tfallthrough\n\tcase to.Coordinates.Latitude == 0 && to.Coordinates.Longitude == 0:\n\t\t// If we don't have any coordinates, return.\n\t\treturn proximity\n\tcase to.Coordinates.AccuracyRadius > accuracy:\n\t\t// If the destination accuracy is worse, use that one.\n\t\taccuracy = to.Coordinates.AccuracyRadius\n\t}\n\n\t// Apply the default location accuracy if there is none.\n\tif accuracy == 0 {\n\t\taccuracy = defaultLocationAccuracy\n\t}\n\n\t// Calculate coordinate distance in kilometers.\n\tfromCoords := haversine.Coord{Lat: l.Coordinates.Latitude, Lon: l.Coordinates.Longitude}\n\ttoCoords := haversine.Coord{Lat: to.Coordinates.Latitude, Lon: to.Coordinates.Longitude}\n\t_, km := haversine.Distance(fromCoords, toCoords)\n\n\tif km <= 100 && accuracy <= 100 {\n\t\t// Give the full value for highly accurate coordinates within 100km.\n\t\tproximity += weightCoordinateDistance\n\t} else {\n\t\t// Else, take a percentage.\n\t\tproximityInPercent := (earthCircumferenceInKm - km) / earthCircumferenceInKm\n\n\t\t// Apply penalty for locations with low accuracy (targeting accuracy radius >100).\n\t\t// Take away at most 50% of the weight through inaccuracy.\n\t\taccuracyModifier := 1 - float64(accuracy)/2000\n\n\t\t// Add proximiy weight.\n\t\tproximity += float32(\n\t\t\tweightCoordinateDistance * // Maxmimum weight for this data point.\n\t\t\t\tproximityInPercent * // Range: 0-1\n\t\t\t\taccuracyModifier, // Range: 0.5-1\n\t\t)\n\t}\n\n\treturn proximity\n}\n\n// PrimitiveNetworkProximity calculates the numerical distance between two IP addresses. Returns a proximity value between 0 (far away) and 100 (nearby).\nfunc PrimitiveNetworkProximity(from net.IP, to net.IP, ipVersion uint8) int {\n\tvar diff float64\n\n\tswitch ipVersion {\n\tcase 4:\n\t\t// TODO: use ip.To4() and :4\n\t\ta := binary.BigEndian.Uint32(from[12:])\n\t\tb := binary.BigEndian.Uint32(to[12:])\n\t\tif a > b {\n\t\t\tdiff = float64(a - b)\n\t\t} else {\n\t\t\tdiff = float64(b - a)\n\t\t}\n\tcase 6:\n\t\ta := binary.BigEndian.Uint64(from[:8])\n\t\tb := binary.BigEndian.Uint64(to[:8])\n\t\tif a > b {\n\t\t\tdiff = float64(a - b)\n\t\t} else {\n\t\t\tdiff = float64(b - a)\n\t\t}\n\tdefault:\n\t\treturn 0\n\t}\n\n\tswitch ipVersion {\n\tcase 4:\n\t\tdiff /= 256\n\t\treturn int((1 - diff/16777216) * 100)\n\tcase 6:\n\t\treturn int((1 - diff/18446744073709552000) * 100)\n\tdefault:\n\t\treturn 0\n\t}\n}\n\nvar unknownASOrgNames = []string{\n\t\"\",           // Expected default for unknown.\n\t\"not routed\", // Observed as \"Not routed\" in data set.\n\t\"unknown\",    // Observed as \"UNKNOWN\" in online data set.\n\t\"nil\",        // Programmatic unknown value.\n\t\"null\",       // Programmatic unknown value.\n\t\"undef\",      // Programmatic unknown value.\n\t\"undefined\",  // Programmatic unknown value.\n}\n\n// ASOrgUnknown return whether the given AS Org string actually is meant to\n// mean that the AS Org is unknown.\nfunc ASOrgUnknown(asOrg string) bool {\n\treturn utils.StringInSlice(\n\t\tunknownASOrgNames,\n\t\tstrings.ToLower(asOrg),\n\t)\n}\n"
  },
  {
    "path": "service/intel/geoip/location_test.go",
    "content": "package geoip\n\nimport (\n\t\"net\"\n\t\"testing\"\n)\n\nfunc TestPrimitiveNetworkProximity(t *testing.T) {\n\tt.Parallel()\n\n\tip4_1 := net.ParseIP(\"1.1.1.1\")\n\tip4_2 := net.ParseIP(\"1.1.1.2\")\n\tip4_3 := net.ParseIP(\"255.255.255.0\")\n\n\tdist := PrimitiveNetworkProximity(ip4_1, ip4_2, 4)\n\tt.Logf(\"primitive proximity %s <> %s: %d\", ip4_1, ip4_2, dist)\n\tif dist < 90 {\n\t\tt.Fatalf(\"unexpected distance between ip4_1 and ip4_2: %d\", dist)\n\t}\n\n\tdist = PrimitiveNetworkProximity(ip4_1, ip4_3, 4)\n\tt.Logf(\"primitive proximity %s <> %s: %d\", ip4_1, ip4_3, dist)\n\tif dist > 10 {\n\t\tt.Fatalf(\"unexpected distance between ip4_1 and ip4_3: %d\", dist)\n\t}\n\n\tip6_1 := net.ParseIP(\"2a02::1\")\n\tip6_2 := net.ParseIP(\"2a02::2\")\n\tip6_3 := net.ParseIP(\"ffff::1\")\n\n\tdist = PrimitiveNetworkProximity(ip6_1, ip6_2, 6)\n\tt.Logf(\"primitive proximity %s <> %s: %d\", ip6_1, ip6_2, dist)\n\tif dist < 90 {\n\t\tt.Fatalf(\"unexpected distance between ip6_1 and ip6_2: %d\", dist)\n\t}\n\n\tdist = PrimitiveNetworkProximity(ip6_1, ip6_3, 6)\n\tt.Logf(\"primitive proximity %s <> %s: %d\", ip6_1, ip6_3, dist)\n\tif dist > 20 {\n\t\tt.Fatalf(\"unexpected distance between ip6_1 and ip6_3: %d\", dist)\n\t}\n}\n"
  },
  {
    "path": "service/intel/geoip/lookup.go",
    "content": "package geoip\n\nimport (\n\t\"errors\"\n\t\"net\"\n\n\t\"github.com/oschwald/maxminddb-golang\"\n)\n\nfunc getReader(ip net.IP) *maxminddb.Reader {\n\tisV6 := ip.To4() == nil\n\treturn worker.GetReader(isV6, true)\n}\n\n// GetLocation returns Location data of an IP address.\nfunc GetLocation(ip net.IP) (*Location, error) {\n\tdb := getReader(ip)\n\tif db == nil {\n\t\treturn nil, errors.New(\"geoip database not available\")\n\t}\n\trecord := &Location{}\n\tif err := db.Lookup(ip, record); err != nil {\n\t\treturn nil, err\n\t}\n\n\trecord.AddCountryInfo()\n\treturn record, nil\n}\n\n// IsInitialized returns whether the geoip database has been initialized.\nfunc IsInitialized(v6, wait bool) bool {\n\treturn worker.GetReader(v6, wait) != nil\n}\n"
  },
  {
    "path": "service/intel/geoip/lookup_test.go",
    "content": "package geoip\n\nimport (\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestLocationLookup(t *testing.T) {\n\t// Skip in CI.\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\tt.Parallel()\n\n\t// Wait for db to be initialized\n\tworker.v4.rw.Lock()\n\twaiter := worker.v4.getWaiter()\n\tworker.v4.rw.Unlock()\n\n\tworker.triggerUpdate()\n\tselect {\n\tcase <-waiter:\n\tcase <-time.After(50 * time.Second):\n\t\tt.Error(\"timeout waiting for geoip database to be initialized (updated)\")\n\t}\n\n\tip1 := net.ParseIP(\"81.2.69.142\")\n\tloc1, err := GetLocation(ip1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"%v\", loc1)\n\n\tip2 := net.ParseIP(\"1.1.1.1\")\n\tloc2, err := GetLocation(ip2)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"%v\", loc2)\n\n\tip3 := net.ParseIP(\"8.8.8.8\")\n\tloc3, err := GetLocation(ip3)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"%v\", loc3)\n\n\tip4 := net.ParseIP(\"81.2.70.142\")\n\tloc4, err := GetLocation(ip4)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"%v\", loc4)\n\n\tip5 := net.ParseIP(\"194.232.1.1\")\n\tloc5, err := GetLocation(ip5)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"%v\", loc5)\n\n\tip6 := net.ParseIP(\"151.101.1.164\")\n\tloc6, err := GetLocation(ip6)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"%v\", loc6)\n\n\tdist1 := loc1.EstimateNetworkProximity(loc2)\n\tdist2 := loc2.EstimateNetworkProximity(loc3)\n\tdist3 := loc1.EstimateNetworkProximity(loc3)\n\tdist4 := loc1.EstimateNetworkProximity(loc4)\n\n\tt.Logf(\"proximity %s <> %s: %.2f\", ip1, ip2, dist1)\n\tt.Logf(\"proximity %s <> %s: %.2f\", ip2, ip3, dist2)\n\tt.Logf(\"proximity %s <> %s: %.2f\", ip1, ip3, dist3)\n\tt.Logf(\"proximity %s <> %s: %.2f\", ip1, ip4, dist4)\n}\n"
  },
  {
    "path": "service/intel/geoip/module.go",
    "content": "package geoip\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype GeoIP struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc (g *GeoIP) Manager() *mgr.Manager {\n\treturn g.mgr\n}\n\nfunc (g *GeoIP) Start() error {\n\tmodule.instance.IntelUpdates().EventResourcesUpdated.AddCallback(\n\t\t\"Check for GeoIP database updates\",\n\t\tfunc(_ *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\tworker.triggerUpdate()\n\t\t\treturn false, nil\n\t\t})\n\treturn nil\n}\n\nfunc (g *GeoIP) Stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *GeoIP\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new GeoIP module.\nfunc New(instance instance) (*GeoIP, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"geoip\")\n\tmodule = &GeoIP{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath: \"intel/geoip/countries\",\n\t\tRead: api.PermitUser,\n\t\t// Do not attach to module, as the data is always available anyway.\n\t\tStructFunc: func(ar *api.Request) (i interface{}, err error) {\n\t\t\treturn countries, nil\n\t\t},\n\t\tName:        \"Get Country Information\",\n\t\tDescription: \"Returns a map of country information centers indexed by ISO-A2 country code\",\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tBinaryUpdates() *updates.Updater\n\tIntelUpdates() *updates.Updater\n}\n"
  },
  {
    "path": "service/intel/geoip/regions.go",
    "content": "package geoip\n\nimport (\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\n// IsRegionalNeighbor returns whether the supplied location is a regional neighbor.\nfunc (l *Location) IsRegionalNeighbor(other *Location) bool {\n\tif l.Country.Continent.Region == \"\" || other.Country.Continent.Region == \"\" {\n\t\treturn false\n\t}\n\tif region, ok := regions[l.Country.Continent.Region]; ok {\n\t\treturn utils.StringInSlice(region.Neighbors, other.Country.Continent.Region)\n\t}\n\treturn false\n}\n\n// Region defines a geographic region and neighboring regions.\ntype Region struct {\n\tID        string\n\tName      string\n\tNeighbors []string\n}\n\nvar regions = map[string]*Region{\n\t\"AF-C\": {\n\t\tID:   \"AF-C\",\n\t\tName: \"Africa, Sub-Saharan Africa, Middle Africa\",\n\t\tNeighbors: []string{\n\t\t\t\"AF-E\",\n\t\t\t\"AF-N\",\n\t\t\t\"AF-S\",\n\t\t\t\"AF-W\",\n\t\t},\n\t},\n\t\"AF-E\": {\n\t\tID:   \"AF-E\",\n\t\tName: \"Africa, Sub-Saharan Africa, Eastern Africa\",\n\t\tNeighbors: []string{\n\t\t\t\"AF-C\",\n\t\t\t\"AF-N\",\n\t\t\t\"AF-S\",\n\t\t},\n\t},\n\t\"AF-N\": {\n\t\tID:   \"AF-N\",\n\t\tName: \"Africa, Northern Africa\",\n\t\tNeighbors: []string{\n\t\t\t\"AF-C\",\n\t\t\t\"AF-E\",\n\t\t\t\"AF-W\",\n\t\t\t\"AS-W\",\n\t\t\t\"EU-S\",\n\t\t},\n\t},\n\t\"AF-S\": {\n\t\tID:   \"AF-S\",\n\t\tName: \"Africa, Sub-Saharan Africa, Southern Africa\",\n\t\tNeighbors: []string{\n\t\t\t\"AF-C\",\n\t\t\t\"AF-E\",\n\t\t\t\"AF-W\",\n\t\t},\n\t},\n\t\"AF-W\": {\n\t\tID:   \"AF-W\",\n\t\tName: \"Africa, Sub-Saharan Africa, Western Africa\",\n\t\tNeighbors: []string{\n\t\t\t\"AF-C\",\n\t\t\t\"AF-N\",\n\t\t\t\"AF-S\",\n\t\t},\n\t},\n\t\"AN\": {\n\t\tID:        \"AN\",\n\t\tName:      \"Antarctica\",\n\t\tNeighbors: []string{},\n\t},\n\t\"AS-C\": {\n\t\tID:   \"AS-C\",\n\t\tName: \"Asia, Central Asia\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-E\",\n\t\t\t\"AS-S\",\n\t\t\t\"AS-SE\",\n\t\t\t\"AS-W\",\n\t\t},\n\t},\n\t\"AS-E\": {\n\t\tID:   \"AS-E\",\n\t\tName: \"Asia, Eastern Asia\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-C\",\n\t\t\t\"AS-S\",\n\t\t\t\"AS-SE\",\n\t\t},\n\t},\n\t\"AS-S\": {\n\t\tID:   \"AS-S\",\n\t\tName: \"Asia, Southern Asia\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-C\",\n\t\t\t\"AS-E\",\n\t\t\t\"AS-SE\",\n\t\t\t\"AS-W\",\n\t\t},\n\t},\n\t\"AS-SE\": {\n\t\tID:   \"AS-SE\",\n\t\tName: \"Asia, South-eastern Asia\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-C\",\n\t\t\t\"AS-E\",\n\t\t\t\"AS-S\",\n\t\t\t\"OC-C\",\n\t\t\t\"OC-E\",\n\t\t\t\"OC-N\",\n\t\t\t\"OC-S\",\n\t\t},\n\t},\n\t\"AS-W\": {\n\t\tID:   \"AS-W\",\n\t\tName: \"Asia, Western Asia\",\n\t\tNeighbors: []string{\n\t\t\t\"AF-N\",\n\t\t\t\"AS-C\",\n\t\t\t\"AS-S\",\n\t\t\t\"EU-E\",\n\t\t},\n\t},\n\t\"EU-E\": {\n\t\tID:   \"EU-E\",\n\t\tName: \"Europe, Eastern Europe\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-W\",\n\t\t\t\"EU-N\",\n\t\t\t\"EU-S\",\n\t\t\t\"EU-W\",\n\t\t},\n\t},\n\t\"EU-N\": {\n\t\tID:   \"EU-N\",\n\t\tName: \"Europe, Northern Europe\",\n\t\tNeighbors: []string{\n\t\t\t\"EU-E\",\n\t\t\t\"EU-S\",\n\t\t\t\"EU-W\",\n\t\t},\n\t},\n\t\"EU-S\": {\n\t\tID:   \"EU-S\",\n\t\tName: \"Europe, Southern Europe\",\n\t\tNeighbors: []string{\n\t\t\t\"AF-N\",\n\t\t\t\"EU-E\",\n\t\t\t\"EU-N\",\n\t\t\t\"EU-W\",\n\t\t},\n\t},\n\t\"EU-W\": {\n\t\tID:   \"EU-W\",\n\t\tName: \"Europe, Western Europe\",\n\t\tNeighbors: []string{\n\t\t\t\"EU-E\",\n\t\t\t\"EU-N\",\n\t\t\t\"EU-S\",\n\t\t},\n\t},\n\t\"NA-E\": {\n\t\tID:   \"NA-E\",\n\t\tName: \"North America, Caribbean\",\n\t\tNeighbors: []string{\n\t\t\t\"NA-N\",\n\t\t\t\"NA-S\",\n\t\t\t\"SA\",\n\t\t},\n\t},\n\t\"NA-N\": {\n\t\tID:   \"NA-N\",\n\t\tName: \"North America, Northern America\",\n\t\tNeighbors: []string{\n\t\t\t\"NA-E\",\n\t\t\t\"NA-N\",\n\t\t\t\"NA-S\",\n\t\t},\n\t},\n\t\"NA-S\": {\n\t\tID:   \"NA-S\",\n\t\tName: \"North America, Central America\",\n\t\tNeighbors: []string{\n\t\t\t\"NA-E\",\n\t\t\t\"NA-N\",\n\t\t\t\"NA-S\",\n\t\t\t\"SA\",\n\t\t},\n\t},\n\t\"OC-C\": {\n\t\tID:   \"OC-C\",\n\t\tName: \"Oceania, Melanesia\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-SE\",\n\t\t\t\"OC-E\",\n\t\t\t\"OC-N\",\n\t\t\t\"OC-S\",\n\t\t},\n\t},\n\t\"OC-E\": {\n\t\tID:   \"OC-E\",\n\t\tName: \"Oceania, Polynesia\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-SE\",\n\t\t\t\"OC-C\",\n\t\t\t\"OC-N\",\n\t\t\t\"OC-S\",\n\t\t},\n\t},\n\t\"OC-N\": {\n\t\tID:   \"OC-N\",\n\t\tName: \"Oceania, Micronesia\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-SE\",\n\t\t\t\"OC-C\",\n\t\t\t\"OC-E\",\n\t\t\t\"OC-S\",\n\t\t},\n\t},\n\t\"OC-S\": {\n\t\tID:   \"OC-S\",\n\t\tName: \"Oceania, Australia and New Zealand\",\n\t\tNeighbors: []string{\n\t\t\t\"AS-SE\",\n\t\t\t\"OC-C\",\n\t\t\t\"OC-E\",\n\t\t\t\"OC-N\",\n\t\t},\n\t},\n\t\"SA\": { // TODO: Split up\n\t\tID:   \"SA\",\n\t\tName: \"South America\",\n\t\tNeighbors: []string{\n\t\t\t\"NA-E\",\n\t\t\t\"NA-S\",\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "service/intel/geoip/regions_test.go",
    "content": "package geoip\n\nimport (\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\nfunc TestRegions(t *testing.T) {\n\tt.Parallel()\n\n\t// Check if all neighbors are also linked back.\n\tfor key, region := range regions {\n\t\tif key != region.ID {\n\t\t\tt.Errorf(\"region has different key than ID: %s != %s\", key, region.ID)\n\t\t}\n\t\tfor _, neighborID := range region.Neighbors {\n\t\t\tif otherRegion, ok := regions[neighborID]; ok {\n\t\t\t\tif !utils.StringInSlice(otherRegion.Neighbors, region.ID) {\n\t\t\t\t\tt.Errorf(\"region %s has neighbor %s, but is not linked back\", region.ID, neighborID)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tt.Errorf(\"region %s does not exist\", neighborID)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/intel/resolver.go",
    "content": "package intel\n\nimport (\n\t\"context\"\n)\n\nvar reverseResolver func(ctx context.Context, ip string) (domain string, err error)\n\n// SetReverseResolver allows the resolver module to register a function to allow reverse resolving IPs to domains.\nfunc SetReverseResolver(fn func(ctx context.Context, ip string) (domain string, err error)) {\n\tif reverseResolver == nil {\n\t\treverseResolver = fn\n\t}\n}\n"
  },
  {
    "path": "service/interop/api.go",
    "content": "package interop\r\n\r\nimport (\r\n\t\"github.com/safing/portmaster/base/api\"\r\n)\r\n\r\nconst (\r\n\tAPIEndpointPing = \"interop/ping\"\r\n)\r\n\r\ntype pingParams struct {\r\n\tMessage bool `json:\"message\"`\r\n}\r\n\r\nfunc (i *Interoperability) registerAPIEndpoints() error {\r\n\tif err := api.RegisterEndpoint(api.Endpoint{\r\n\t\tPath:        APIEndpointPing,\r\n\t\tRead:        api.PermitAnyone,\r\n\t\tWrite:       api.PermitAnyone,\r\n\t\tActionFunc:  i.handlePing,\r\n\t\tName:        \"Interoperability: Ping Portmaster\",\r\n\t\tDescription: \"Ping the Portmaster Core Service for interoperability checks.\",\r\n\t}); err != nil {\r\n\t\treturn err\r\n\t}\r\n\r\n\treturn nil\r\n}\r\n\r\nfunc (c *Interoperability) handlePing(r *api.Request) (msg string, err error) {\r\n\t// Received ping, possibly from IVPN client\r\n\t// Try to connect to IVPN client if not already connected\r\n\r\n\tfor _, im := range c.interopModules {\r\n\t\tif err := im.PingHandler(); err != nil {\r\n\t\t\tc.mgr.Warn(\"Failed to handle ping for interoperability module: \" + err.Error())\r\n\t\t}\r\n\t}\r\n\r\n\treturn \"\", nil\r\n}\r\n"
  },
  {
    "path": "service/interop/ivpn/ivpn.go",
    "content": "package ivpn\r\n\r\nimport (\r\n\t\"encoding/json\"\r\n\t\"fmt\"\r\n\t\"net\"\r\n\t\"sync/atomic\"\r\n\t\"time\"\r\n\r\n\t\"github.com/ivpn/desktop-app/daemon/protocol/ivpnclient\"\r\n\t\"github.com/safing/portmaster/base/info\"\r\n\t\"github.com/safing/portmaster/base/notifications\"\r\n\t\"github.com/safing/portmaster/service/firewall/interception\"\r\n\t\"github.com/safing/portmaster/service/mgr\"\r\n\t\"github.com/safing/portmaster/service/network\"\r\n\t\"github.com/safing/portmaster/service/network/packet\"\r\n)\r\n\r\nconst DNS_LOCKED_DESCRIPTION = \"Portmaster controls all DNS resolution on this system, which prevents conflicts with IVPN's DNS settings. To let IVPN manage DNS again, remove all DNS servers from Portmaster's DNS configuration.\"\r\n\r\n// interopBase defines the interface that the InteropIvpn module expects from its owner\r\n// (the main Interoperability module).\r\ntype interopBase interface {\r\n\tEnsureVerdictHandlerRegistered()\r\n\tDnsListenAddress() string\r\n\tDnsNameServers() []string\r\n\tEvtConfigChange() <-chan struct{}\r\n\tInterception() *interception.Interception\r\n\tManager() *mgr.Manager\r\n}\r\n\r\n// vpnConnectionInfo holds information about the active VPN connection of the IVPN client,\r\n// used for identifying VPN traffic in firewall verdicts.\r\ntype vpnConnectionInfo struct {\r\n\tdstPort    uint16\r\n\tdstAddress net.IP\r\n\tprotocol   uint8\r\n}\r\n\r\n// clientStatus holds information about the connected IVPN client\r\n// and its current VPN connection status, used for providing context in firewall verdicts.\r\ntype clientStatus struct {\r\n\tserviceBinary string\r\n\tvpnConnection vpnConnectionInfo\r\n}\r\n\r\n// InteropIvpn handles interoperability with the IVPN client application,\r\n// allowing Portmaster to receive information about IVPN VPN connections\r\n// and adjust firewall verdicts accordingly for better compatibility and user experience.\r\ntype InteropIvpn struct {\r\n\towner             interopBase\r\n\tconnHandler       *mgr.WorkerMgr\r\n\tstatus            atomic.Pointer[clientStatus]\r\n\tisCustomDnsActive atomic.Bool\r\n\tfirstTryDone      atomic.Pointer[chan struct{}]\r\n}\r\n\r\nfunc NewInteropIvpn(owner interopBase) *InteropIvpn {\r\n\treturn &InteropIvpn{\r\n\t\towner: owner,\r\n\t}\r\n}\r\n\r\nfunc (i *InteropIvpn) Start() error {\r\n\ti.connHandler = i.owner.Manager().NewWorkerMgr(\"ivpn client interoperability\", i.connectIvpnClient, nil)\r\n\r\n\tfirstTryChan := make(chan struct{})\r\n\ti.firstTryDone.Store(&firstTryChan)\r\n\r\n\ti.connHandler.Go()\r\n\r\n\t// Wait for the first connection attempt to complete.\r\n\t// The 'status' must be initialized before allowing firewall verdicts to proceed.\r\n\t// The wait is bounded by the connection timeouts inside connectIvpnClient.\r\n\t<-firstTryChan\r\n\r\n\treturn nil\r\n}\r\n\r\nfunc (i *InteropIvpn) PingHandler() error {\r\n\ti.connHandler.Go()\r\n\treturn nil\r\n}\r\n\r\nfunc (i *InteropIvpn) setFirstTryDone() {\r\n\tif chanPtr := i.firstTryDone.Load(); chanPtr != nil {\r\n\t\tclose(*chanPtr)\r\n\t\ti.firstTryDone.Store(nil)\r\n\t}\r\n}\r\n\r\nfunc (i *InteropIvpn) setServiceBinary(path string) {\r\n\tstatus := clientStatus{}\r\n\tif old := i.status.Load(); old != nil {\r\n\t\tstatus = *old\r\n\t}\r\n\tstatus.serviceBinary = path\r\n\ti.status.Store(&status)\r\n}\r\n\r\nvar notifWarnOldVersion atomic.Pointer[notifications.Notification]\r\n\r\n// Synchronously connects to the IVPN client, sets up message handlers\r\nfunc (i *InteropIvpn) connectIvpnClient(wc *mgr.WorkerCtx) error {\r\n\tdefer func() {\r\n\t\t// Clear client status on disconnect\r\n\t\ti.status.Store(nil)\r\n\t\t// Reset DNS tracking state\r\n\t\ti.isCustomDnsActive.Store(false)\r\n\t\t// Mark that the first connection attempt is done, even if it failed\r\n\t\ti.setFirstTryDone()\r\n\t}()\r\n\r\n\tnotifWarn := notifWarnOldVersion.Load()\r\n\tif notifWarn != nil {\r\n\t\tnotifWarn.Delete()\r\n\t\tnotifWarnOldVersion.Store(nil)\r\n\t}\r\n\r\n\tci := ivpnclient.ClientInfo{\r\n\t\tType:    ivpnclient.ClientPortmaster,\r\n\t\tName:    \"Portmaster\",\r\n\t\tVersion: info.Version()}\r\n\r\n\t// Create client.\r\n\t// Ignoring error here, since it is expected that the client may not be in running state\r\n\tclient, err := ivpnclient.NewClientAsRoot(nil, time.Second*10, ci)\r\n\tif err != nil {\r\n\t\treturn nil\r\n\t}\r\n\r\n\t// Register handler for VPN connection messages\r\n\tclient.SetMessageEventHandler(\"ConnectionStarting\", func(messageName string, messageData string) {\r\n\t\ti.onConnectionStarting(wc, messageName, messageData)\r\n\t})\r\n\tclient.SetMessageEventHandler(\"ConnectionStopped\", func(messageName string, messageData string) {\r\n\t\ti.onConnectionStopped(wc, messageName, messageData)\r\n\t})\r\n\r\n\t// Connect to client.\r\n\t// Ignoring error here, since it is expected that the client may not be in running state\r\n\terr = client.Connect(time.Second * 2)\r\n\tif err != nil {\r\n\t\treturn nil\r\n\t}\r\n\r\n\t// Send hello request, which is required to start receiving messages.\r\n\thello := client.InitHelloRequest()\r\n\thello.GetServiceBinaryPath = true\r\n\thello.GetActiveRemoteEndpoint = true\r\n\tvar helloResp ivpnclient.HelloResp\r\n\terr = client.SendRecv(&hello, &helloResp)\r\n\tif err != nil {\r\n\t\tclient.Disconnect()\r\n\t\treturn err\r\n\t}\r\n\r\n\tif helloResp.ServiceBinary == \"\" {\r\n\t\t// IVPN client version > v3.15.0 must provide the service binary path in the hello response.\r\n\t\twc.Warn(fmt.Sprintf(\"Detected IVPN Client version '%v' is incompatible. The hello response did not include all required fields.\", helloResp.Version))\r\n\t\tnotif := i.showNotificationWarnOldVersion()\r\n\t\tnotifWarnOldVersion.Store(notif)\r\n\t\treturn nil\r\n\t}\r\n\r\n\t// Save ServiceBinary.\r\n\ti.setServiceBinary(helloResp.ServiceBinary)\r\n\t// The status.vpnConnection must be already initialized (ConnectionStarting message already received).\r\n\ti.setFirstTryDone()\r\n\t// Notify owner that we can now provide verdicts for firewall module\r\n\ti.owner.EnsureVerdictHandlerRegistered()\r\n\r\n\twc.Debug(fmt.Sprintf(\"Connected to IVPN client %s\", helloResp.Version))\r\n\r\n\t// Show UI notification if not suppressed by user\r\n\tif !isNotificationSuppressed() {\r\n\t\tnotification := i.initAndShowNotification()\r\n\t\tdefer notification.Delete()\r\n\t}\r\n\r\n\t// Configure IVPN client DNS settings based on current Portmaster config at startup\r\n\ti.updateIvpnClientDnsSettings(wc, client)\r\n\r\n\t// Subscribe to interception start/stop events to update IVPN client DNS settings\r\n\tinterceptionStatus := i.owner.Interception().EventStartStopState.Subscribe(\"ivpn\", 10)\r\n\tdefer interceptionStatus.Cancel()\r\n\r\n\tdone := false\r\n\tfor !done {\r\n\t\tselect {\r\n\t\tcase <-interceptionStatus.Events():\r\n\t\t\ti.updateIvpnClientDnsSettings(wc, client)\r\n\t\tcase <-i.owner.EvtConfigChange():\r\n\t\t\ti.updateIvpnClientDnsSettings(wc, client)\r\n\t\tcase <-wc.Done():\r\n\t\t\tclient.Disconnect()\r\n\t\t\tdone = true\r\n\t\tcase <-client.Disconnected():\r\n\t\t\tdone = true\r\n\t\t}\r\n\t}\r\n\r\n\twc.Debug(\"IVPN client disconnected\")\r\n\treturn nil\r\n}\r\n\r\n// updateIvpnClientDnsSettings configures the IVPN client to use Portmaster's local DNS resolver\r\n// when custom DNS servers are configured in Portmaster and interception is active.\r\nfunc (i *InteropIvpn) updateIvpnClientDnsSettings(wc *mgr.WorkerCtx, client *ivpnclient.Client) {\r\n\t// Custom DNS should be applied only if there are any custom DNS servers configured in Portmaster,\r\n\t// and interception is active (PM not in Paused state).\r\n\twantCustomDns := len(i.owner.DnsNameServers()) > 0 && i.owner.Interception().IsStarted()\r\n\tif wantCustomDns == i.isCustomDnsActive.Load() {\r\n\t\treturn\r\n\t}\r\n\r\n\tif wantCustomDns {\r\n\t\t// Configure IVPN to use Portmaster's local DNS resolver.\r\n\t\t// This prevents IVPN from modifying system DNS, letting Portmaster handle all DNS requests.\r\n\t\tcustomDns := ivpnclient.DnsSettings{Servers: []ivpnclient.DnsServerConfig{{Address: i.owner.DnsListenAddress()}}}\r\n\t\tif err := client.SetTempPrioritizedDns(customDns, DNS_LOCKED_DESCRIPTION); err != nil {\r\n\t\t\twc.Warn(fmt.Sprintf(\"IVPN: Failed to set manual DNS: %v\", err))\r\n\t\t\treturn\r\n\t\t}\r\n\t\twc.Debug(fmt.Sprintf(\"IVPN: Manual DNS set successfully to %q\", i.owner.DnsListenAddress()))\r\n\t\ti.isCustomDnsActive.Store(true)\r\n\t\treturn\r\n\t}\r\n\r\n\t// Reset IVPN back to its default DNS handling.\r\n\tif err := client.SetTempPrioritizedDns(ivpnclient.DnsSettings{}, \"\"); err != nil {\r\n\t\twc.Warn(fmt.Sprintf(\"IVPN: Failed to restore manual DNS: %v\", err))\r\n\t\treturn\r\n\t}\r\n\r\n\ti.isCustomDnsActive.Store(false)\r\n\twc.Debug(\"IVPN: Manual DNS restored successfully\")\r\n}\r\n\r\n// notification handler: VPN connection is going to start\r\nfunc (i *InteropIvpn) onConnectionStarting(wc *mgr.WorkerCtx, _ string, messageData string) {\r\n\tconnInfo := ivpnclient.ConnectionStarting{}\r\n\terr := json.Unmarshal([]byte(messageData), &connInfo)\r\n\tif err != nil {\r\n\t\twc.Warn(fmt.Sprintf(\"IVPN: Failed to parse ConnectionStarting message: %v\", err))\r\n\t\treturn\r\n\t}\r\n\r\n\t// Update/Store VPN connection info for use in firewall verdicts\r\n\tstatus := clientStatus{}\r\n\tif old := i.status.Load(); old != nil {\r\n\t\tstatus = *old // Preserve existing status fields\r\n\t}\r\n\tconn := vpnConnectionInfo{\r\n\t\tdstPort:    connInfo.Port,\r\n\t\tdstAddress: net.ParseIP(connInfo.Address),\r\n\t\tprotocol:   connInfo.Protocol,\r\n\t}\r\n\tif conn.dstAddress == nil {\r\n\t\tconn.dstPort = 0 // Invalidate port if address is invalid, to avoid false matches in firewall verdicts.\r\n\t}\r\n\tstatus.vpnConnection = conn\r\n\ti.status.Store(&status)\r\n\r\n\twc.Debug(fmt.Sprintf(\"IVPN: VPN connection starting %s:%d %s\", connInfo.Address, connInfo.Port, packet.IPProtocol(connInfo.Protocol)))\r\n}\r\n\r\n// notification handler: VPN connection stopped\r\nfunc (i *InteropIvpn) onConnectionStopped(wc *mgr.WorkerCtx, _ string, messageData string) {\r\n\tstatus := clientStatus{}\r\n\tif old := i.status.Load(); old != nil {\r\n\t\tstatus = *old\r\n\t}\r\n\tstatus.vpnConnection = vpnConnectionInfo{}\r\n\ti.status.Store(&status)\r\n\twc.Debug(\"IVPN: VPN connection stopped\")\r\n}\r\n\r\n// VerdictHandler provides firewall verdicts for IVPN client connections\r\n// based on the current VPN connection status and client binary path.\r\n// It is registered with the firewall module to be called for firewall decisions,\r\n// allowing it to adjust verdicts for better compatibility and user experience with the IVPN client.\r\nfunc (i *InteropIvpn) VerdictHandler(conn *network.Connection) (verdict network.Verdict, reason string, skipTunnel bool) {\r\n\tstatus := i.status.Load()\r\n\tif status == nil {\r\n\t\treturn network.VerdictUndecided, \"\", false\r\n\t}\r\n\r\n\tif status.vpnConnection.dstPort != 0 {\r\n\t\tif conn.Entity.Port == status.vpnConnection.dstPort &&\r\n\t\t\tconn.Entity.Protocol == status.vpnConnection.protocol &&\r\n\t\t\tconn.Entity.IP.Equal(status.vpnConnection.dstAddress) {\r\n\t\t\t// By default, we accept outbound connections.\r\n\t\t\t// But UDP traffic is bidirectional, so we also accept inbound connections\r\n\t\t\t// to avoid breaking incoming UDP responses from the VPN server.\r\n\t\t\tif !conn.Inbound || status.vpnConnection.protocol == uint8(packet.UDP) {\r\n\t\t\t\treturn network.VerdictAccept, \"IVPN VPN connection\", true\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif status.serviceBinary != \"\" && conn.Process().Path == status.serviceBinary {\r\n\t\treturn network.VerdictAccept, \"IVPN Service connection\", true\r\n\t}\r\n\r\n\treturn network.VerdictUndecided, \"\", false\r\n}\r\n"
  },
  {
    "path": "service/interop/ivpn/notification.go",
    "content": "package ivpn\r\n\r\nimport (\r\n\t\"context\"\r\n\t\"sync\"\r\n\t\"time\"\r\n\r\n\t\"github.com/safing/portmaster/base/database\"\r\n\t\"github.com/safing/portmaster/base/database/record\"\r\n\t\"github.com/safing/portmaster/base/notifications\"\r\n)\r\n\r\nfunc (i *InteropIvpn) showNotificationWarnOldVersion() *notifications.Notification {\r\n\tnotification := &notifications.Notification{\r\n\t\tEventID:      \"interop:ivpn-old-version\",\r\n\t\tType:         notifications.Warning,\r\n\t\tTitle:        \"IVPN Client Compatibility Notice\",\r\n\t\tMessage:      `Portmaster has detected the IVPN Client, but the installed version may not be fully compatible when running alongside Portmaster. Some features may not work as expected. Please consider updating to the latest version of the IVPN Client.`,\r\n\t\tShowOnSystem: true,\r\n\t\tExpires:      time.Now().Add(5 * time.Minute).Unix(),\r\n\t\tAvailableActions: []*notifications.Action{\r\n\t\t\t{\r\n\t\t\t\tID:   \"ack\",\r\n\t\t\t\tText: \"OK\",\r\n\t\t\t},\r\n\t\t},\r\n\t}\r\n\tnotifications.Notify(notification)\r\n\treturn notification\r\n}\r\n\r\nfunc (i *InteropIvpn) initAndShowNotification() *notifications.Notification {\r\n\tconst actionSuppressID = \"suppress\"\r\n\r\n\tnotification := &notifications.Notification{\r\n\t\tEventID: \"interop:ivpn\",\r\n\t\tType:    notifications.Info,\r\n\t\tTitle:   \"IVPN Client detected\",\r\n\t\tMessage: `Portmaster has detected the IVPN Client and will allow its VPN and service connections.`,\r\n\t\tAvailableActions: []*notifications.Action{\r\n\t\t\t{\r\n\t\t\t\tID:   \"ack\",\r\n\t\t\t\tText: \"OK\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tID:         actionSuppressID,\r\n\t\t\t\tText:       \"Don't show again\",\r\n\t\t\t\tVisibility: notifications.ActionVisibilityDetailed,\r\n\t\t\t},\r\n\t\t},\r\n\t}\r\n\tnotification.SetActionFunction(func(_ context.Context, n *notifications.Notification) error {\r\n\t\tn.Lock()\r\n\t\tactionID := n.SelectedActionID\r\n\t\tn.Unlock()\r\n\t\tif actionID == actionSuppressID {\r\n\t\t\tif err := suppressNotification(); err != nil {\r\n\t\t\t\treturn err\r\n\t\t\t}\r\n\t\t}\r\n\t\tn.Delete()\r\n\t\treturn nil\r\n\t})\r\n\tnotifications.Notify(notification)\r\n\treturn notification\r\n}\r\n\r\n// === Notification state persistence ===\r\n\r\n// markerRecord is a minimal database record used as a presence-only marker.\r\ntype markerRecord struct {\r\n\trecord.Base\r\n\tsync.Mutex\r\n}\r\n\r\nvar db = database.NewInterface(&database.Options{Local: true, Internal: true})\r\n\r\n// Database key used to persist the user's choice to suppress the IVPN detected notification.\r\nconst Notification_DB_ID_IvpnDetectSuppressed = \"core:notifications/interop/ivpn/suppressed\"\r\n\r\n// isNotificationSuppressed returns true if the user has chosen to never see the IVPN compat notification.\r\nfunc isNotificationSuppressed() bool {\r\n\t_, err := db.Get(Notification_DB_ID_IvpnDetectSuppressed)\r\n\treturn err == nil\r\n}\r\n\r\n// suppressNotification persists the user's decision to never show the notification again.\r\nfunc suppressNotification() error {\r\n\tm := &markerRecord{}\r\n\tm.SetKey(Notification_DB_ID_IvpnDetectSuppressed)\r\n\treturn db.Put(m)\r\n}\r\n"
  },
  {
    "path": "service/interop/module.go",
    "content": "package interop\r\n\r\nimport (\r\n\t\"errors\"\r\n\t\"net\"\r\n\t\"sync/atomic\"\r\n\r\n\t\"github.com/safing/portmaster/base/config\"\r\n\t\"github.com/safing/portmaster/service/firewall\"\r\n\t\"github.com/safing/portmaster/service/firewall/interception\"\r\n\t\"github.com/safing/portmaster/service/interop/ivpn\"\r\n\t\"github.com/safing/portmaster/service/mgr\"\r\n\t\"github.com/safing/portmaster/service/network\"\r\n)\r\n\r\n// Interface for separate interoperability objects.\r\n// Each object can implement interoperability with a specific third-party application,\r\n// such as IVPN client, to exchange information and coordinate actions for better compatibility and user experience.\r\ntype interopModule interface {\r\n\tStart() error\r\n\tPingHandler() error\r\n\tVerdictHandler(conn *network.Connection) (network.Verdict, string, bool)\r\n}\r\n\r\ntype instance interface {\r\n\tConfig() *config.Config\r\n\tInterception() *interception.Interception\r\n}\r\n\r\n// Module for interoperability with third-party applications\r\ntype Interoperability struct {\r\n\tmgr                      *mgr.Manager\r\n\tinstance                 instance\r\n\tcfgDnsNameServers        config.StringArrayOption\r\n\tdnsListenAddress         string\r\n\tinteropModules           []interopModule\r\n\tverdictHandlerRegistered atomic.Bool\r\n}\r\n\r\n// Manager returns the module manager.\r\nfunc (u *Interoperability) Manager() *mgr.Manager {\r\n\treturn u.mgr\r\n}\r\n\r\n// Start starts the module.\r\nfunc (u *Interoperability) Start() error {\r\n\treturn start()\r\n}\r\n\r\n// Stop stops the module.\r\nfunc (u *Interoperability) Stop() error {\r\n\treturn stop()\r\n}\r\n\r\nfunc (u *Interoperability) DnsListenAddress() string {\r\n\treturn u.dnsListenAddress\r\n}\r\nfunc (u *Interoperability) DnsNameServers() []string {\r\n\treturn u.cfgDnsNameServers()\r\n}\r\nfunc (u *Interoperability) EvtConfigChange() <-chan struct{} {\r\n\treturn u.instance.Config().EventConfigChange.Subscribe(\"interoperability: config change detection\", 10).Events()\r\n}\r\nfunc (u *Interoperability) Interception() *interception.Interception {\r\n\treturn u.instance.Interception()\r\n}\r\n\r\nfunc start() error {\r\n\tfor _, im := range module.interopModules {\r\n\t\tif err := im.Start(); err != nil {\r\n\t\t\treturn errors.New(\"failed to start interoperability module: \" + err.Error())\r\n\t\t}\r\n\t}\r\n\treturn nil\r\n}\r\n\r\nfunc stop() error {\r\n\treturn nil\r\n}\r\n\r\nvar (\r\n\tmodule     *Interoperability\r\n\tshimLoaded atomic.Bool\r\n)\r\n\r\nfunc New(instance instance) (*Interoperability, error) {\r\n\tif !shimLoaded.CompareAndSwap(false, true) {\r\n\t\treturn nil, errors.New(\"only one instance allowed\")\r\n\t}\r\n\r\n\t// Determine Portmaster's local DNS resolver listen address for use in IVPN client configuration.\r\n\t// Ot is ok to check it once at startup, since it can only be changed by restarting Portmaster with a different config.\r\n\tvar err error\r\n\tdnsListenAddress := config.GetAsString(\"dns/listenAddress\", \"\")()\r\n\tdnsListenAddress, _, err = net.SplitHostPort(dnsListenAddress)\r\n\tif err != nil || net.ParseIP(dnsListenAddress) == nil || dnsListenAddress == \"\" || dnsListenAddress == \"0.0.0.0\" {\r\n\t\tdnsListenAddress = \"127.0.0.1\"\r\n\t}\r\n\r\n\t// Create module instance.\r\n\tm := mgr.New(\"Interop\")\r\n\tmodule = &Interoperability{\r\n\t\tmgr:               m,\r\n\t\tinstance:          instance,\r\n\t\tcfgDnsNameServers: config.GetAsStringArray(\"dns/nameservers\", []string{}),\r\n\t\tdnsListenAddress:  dnsListenAddress,\r\n\t\tinteropModules:    make([]interopModule, 0, 1),\r\n\t}\r\n\r\n\tif err := module.prep(); err != nil {\r\n\t\treturn nil, err\r\n\t}\r\n\r\n\treturn module, nil\r\n}\r\n\r\nfunc (i *Interoperability) prep() error {\r\n\ti.interopModules = append(i.interopModules, ivpn.NewInteropIvpn(i))\r\n\treturn i.registerAPIEndpoints()\r\n}\r\n\r\n// EnsureVerdictHandlerRegistered registers the interoperability module's verdict handler\r\n// with the firewall module if not already registered.\r\n// We do this lazily here only when we need it.\r\nfunc (i *Interoperability) EnsureVerdictHandlerRegistered() {\r\n\tif i.verdictHandlerRegistered.CompareAndSwap(false, true) {\r\n\t\tfirewall.SetExternalVerdictHandler(i.verdict_handler)\r\n\t}\r\n}\r\n"
  },
  {
    "path": "service/interop/verdict_handler.go",
    "content": "package interop\r\n\r\nimport (\r\n\t\"github.com/safing/portmaster/service/network\"\r\n)\r\n\r\nfunc (i *Interoperability) verdict_handler(conn *network.Connection) (verdict network.Verdict, reason string, skipTunnel bool) {\r\n\tfor _, im := range i.interopModules {\r\n\t\tverdict, reason, skipTunnel := im.VerdictHandler(conn)\r\n\t\tif verdict != network.VerdictUndecided {\r\n\t\t\treturn verdict, reason, skipTunnel\r\n\t\t}\r\n\t}\r\n\treturn network.VerdictUndecided, \"\", false\r\n}\r\n"
  },
  {
    "path": "service/mgr/doc.go",
    "content": "// Package mgr provides simple managing of flow control and logging.\npackage mgr\n"
  },
  {
    "path": "service/mgr/events.go",
    "content": "//nolint:structcheck,golint // TODO: Seems broken for generics.\npackage mgr\n\nimport (\n\t\"slices\"\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\n// EventMgr is a simple event manager.\ntype EventMgr[T any] struct {\n\tname string\n\tmgr  *Manager\n\tlock sync.Mutex\n\n\tsubs      []*EventSubscription[T]\n\tcallbacks []*EventCallback[T]\n}\n\n// EventSubscription is a subscription to an event.\ntype EventSubscription[T any] struct {\n\tname     string\n\tevents   chan T\n\tcanceled atomic.Bool\n}\n\n// EventCallback is a registered callback to an event.\ntype EventCallback[T any] struct {\n\tname     string\n\tcallback EventCallbackFunc[T]\n\tcanceled atomic.Bool\n}\n\n// EventCallbackFunc defines the event callback function.\ntype EventCallbackFunc[T any] func(*WorkerCtx, T) (cancel bool, err error)\n\n// NewEventMgr returns a new event manager.\n// It is easiest used as a public field on a struct,\n// so that others can simply Subscribe() oder AddCallback().\nfunc NewEventMgr[T any](eventName string, mgr *Manager) *EventMgr[T] {\n\treturn &EventMgr[T]{\n\t\tname: eventName,\n\t\tmgr:  mgr,\n\t}\n}\n\n// Subscribe subscribes to events.\n// The received events are shared among all subscribers and callbacks.\n// Be sure to apply proper concurrency safeguards, if applicable.\nfunc (em *EventMgr[T]) Subscribe(subscriberName string, chanSize int) *EventSubscription[T] {\n\tem.lock.Lock()\n\tdefer em.lock.Unlock()\n\n\tes := &EventSubscription[T]{\n\t\tname:   subscriberName,\n\t\tevents: make(chan T, chanSize),\n\t}\n\n\tem.subs = append(em.subs, es)\n\treturn es\n}\n\n// AddCallback adds a callback to executed on events.\n// The received events are shared among all subscribers and callbacks.\n// Be sure to apply proper concurrency safeguards, if applicable.\nfunc (em *EventMgr[T]) AddCallback(callbackName string, callback EventCallbackFunc[T]) {\n\tem.lock.Lock()\n\tdefer em.lock.Unlock()\n\n\tec := &EventCallback[T]{\n\t\tname:     callbackName,\n\t\tcallback: callback,\n\t}\n\n\tem.callbacks = append(em.callbacks, ec)\n}\n\n// Submit submits a new event.\nfunc (em *EventMgr[T]) Submit(event T) {\n\tem.lock.Lock()\n\tdefer em.lock.Unlock()\n\n\tvar anyCanceled bool\n\n\t// Send to subscriptions.\n\tfor _, sub := range em.subs {\n\t\t// Check if subscription was canceled.\n\t\tif sub.canceled.Load() {\n\t\t\tanyCanceled = true\n\t\t\tcontinue\n\t\t}\n\n\t\t// Submit via channel.\n\t\tselect {\n\t\tcase sub.events <- event:\n\t\tdefault:\n\t\t\tif em.mgr != nil {\n\t\t\t\tem.mgr.Warn(\n\t\t\t\t\t\"event subscription channel overflow\",\n\t\t\t\t\t\"event\", em.name,\n\t\t\t\t\t\"subscriber\", sub.name,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Run callbacks.\n\tfor _, ec := range em.callbacks {\n\t\t// Check if callback was canceled.\n\t\tif ec.canceled.Load() {\n\t\t\tanyCanceled = true\n\t\t\tcontinue\n\t\t}\n\n\t\t// Execute callback.\n\t\tvar (\n\t\t\tcancel bool\n\t\t\terr    error\n\t\t)\n\t\tif em.mgr != nil {\n\t\t\t// Prefer executing in worker.\n\t\t\tname := \"event \" + em.name + \" callback \" + ec.name\n\t\t\tem.mgr.Go(name, func(w *WorkerCtx) error {\n\t\t\t\tcancel, err = ec.callback(w, event)\n\t\t\t\t// Handle error and cancelation.\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.Warn(\n\t\t\t\t\t\t\"event callback failed\",\n\t\t\t\t\t\t\"event\", em.name,\n\t\t\t\t\t\t\"callback\", ec.name,\n\t\t\t\t\t\t\"err\", err,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tif cancel {\n\t\t\t\t\tec.canceled.Store(true)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t} else {\n\t\t\tcancel, err = ec.callback(nil, event)\n\t\t\t// Handle error and cancelation.\n\t\t\tif err != nil && em.mgr != nil {\n\t\t\t\tem.mgr.Warn(\n\t\t\t\t\t\"event callback failed\",\n\t\t\t\t\t\"event\", em.name,\n\t\t\t\t\t\"callback\", ec.name,\n\t\t\t\t\t\"err\", err,\n\t\t\t\t)\n\t\t\t}\n\t\t\tif cancel {\n\t\t\t\tec.canceled.Store(true)\n\t\t\t\tanyCanceled = true\n\t\t\t}\n\t\t}\n\t}\n\n\t// If any canceled subscription/callback was seen, clean the slices.\n\tif anyCanceled {\n\t\tem.clean()\n\t}\n}\n\n// clean removes all canceled subscriptions and callbacks.\nfunc (em *EventMgr[T]) clean() {\n\tem.subs = slices.DeleteFunc[[]*EventSubscription[T], *EventSubscription[T]](em.subs, func(es *EventSubscription[T]) bool {\n\t\treturn es.canceled.Load()\n\t})\n\tem.callbacks = slices.DeleteFunc[[]*EventCallback[T], *EventCallback[T]](em.callbacks, func(ec *EventCallback[T]) bool {\n\t\treturn ec.canceled.Load()\n\t})\n}\n\n// Events returns a read channel for the events.\n// The received events are shared among all subscribers and callbacks.\n// Be sure to apply proper concurrency safeguards, if applicable.\nfunc (es *EventSubscription[T]) Events() <-chan T {\n\treturn es.events\n}\n\n// Cancel cancels the subscription.\n// The events channel is not closed, but will not receive new events.\nfunc (es *EventSubscription[T]) Cancel() {\n\tes.canceled.Store(true)\n}\n\n// Done returns whether the event subscription has been canceled.\nfunc (es *EventSubscription[T]) Done() bool {\n\treturn es.canceled.Load()\n}\n"
  },
  {
    "path": "service/mgr/group.go",
    "content": "package mgr\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar (\n\t// ErrUnsuitableGroupState is returned when an operation cannot be executed due to an unsuitable state.\n\tErrUnsuitableGroupState = errors.New(\"unsuitable group state\")\n\n\t// ErrInvalidGroupState is returned when a group is in an invalid state and cannot be recovered.\n\tErrInvalidGroupState = errors.New(\"invalid group state\")\n\n\t// ErrExecuteCmdLineOp is returned when modules are created, but request\n\t// execution of a (somewhere else set) command line operation instead.\n\tErrExecuteCmdLineOp = errors.New(\"command line operation execution requested\")\n)\n\nconst (\n\tgroupStateOff int32 = iota\n\tgroupStateStarting\n\tgroupStateRunning\n\tgroupStateStopping\n\tgroupStateInvalid\n)\n\n//nolint:goconst\nfunc groupStateToString(state int32) string {\n\tswitch state {\n\tcase groupStateOff:\n\t\treturn \"off\"\n\tcase groupStateStarting:\n\t\treturn \"starting\"\n\tcase groupStateRunning:\n\t\treturn \"running\"\n\tcase groupStateStopping:\n\t\treturn \"stopping\"\n\tcase groupStateInvalid:\n\t\treturn \"invalid\"\n\t}\n\n\treturn \"unknown\"\n}\n\n// Group describes a group of modules.\ntype Group struct {\n\tmodules []*groupModule\n\n\tstate atomic.Int32\n}\n\ntype groupModule struct {\n\tmodule Module\n\tmgr    *Manager\n}\n\n// Module is an manage-able instance of some component.\ntype Module interface {\n\tManager() *Manager\n\tStart() error\n\tStop() error\n}\n\n// NewGroup returns a new group of modules.\nfunc NewGroup(modules ...Module) *Group {\n\t// Create group.\n\tg := &Group{\n\t\tmodules: make([]*groupModule, 0, len(modules)),\n\t}\n\n\t// Initialize groups modules.\n\tfor _, m := range modules {\n\t\tg.Add(m)\n\t}\n\n\treturn g\n}\n\n// Add validates the given module and adds it to the group, if all requirements are met.\n// Not safe for concurrent use with any other method.\n// All modules must be added before anything else is done with the group.\nfunc (g *Group) Add(m Module) {\n\tmgr := m.Manager()\n\n\t// Check module.\n\tswitch {\n\tcase m == nil:\n\t\t// Skip nil values to allow for cleaner code.\n\t\treturn\n\tcase reflect.ValueOf(m).IsNil():\n\t\t// If nil values are given via a struct, they are will be interfaces to a\n\t\t// nil type. Ignore these too.\n\t\treturn\n\tcase mgr == nil:\n\t\t// Ignore modules that do not return a manager.\n\t\treturn\n\tcase mgr.Name() == \"\":\n\t\t// Force name if none is set.\n\t\t// TODO: Unsafe if module is already logging, etc.\n\t\tmgr.setName(makeModuleName(m))\n\t}\n\n\t// Add module to group.\n\tg.modules = append(g.modules, &groupModule{\n\t\tmodule: m,\n\t\tmgr:    mgr,\n\t})\n}\n\n// Start starts all modules in the group in the defined order.\n// If a module fails to start, itself and all previous modules\n// will be stopped in the reverse order.\nfunc (g *Group) Start() error {\n\t// Check group state.\n\tswitch g.state.Load() {\n\tcase groupStateRunning:\n\t\t// Already running.\n\t\treturn nil\n\tcase groupStateInvalid:\n\t\t// Something went terribly wrong, cannot recover from here.\n\t\treturn fmt.Errorf(\"%w: cannot recover\", ErrInvalidGroupState)\n\tdefault:\n\t\tif !g.state.CompareAndSwap(groupStateOff, groupStateStarting) {\n\t\t\treturn fmt.Errorf(\"%w: group is not off, state: %s\", ErrUnsuitableGroupState, groupStateToString(g.state.Load()))\n\t\t}\n\t}\n\n\t// Start modules.\n\tfor i, m := range g.modules {\n\t\tm.mgr.Debug(\"starting\")\n\t\tstartTime := time.Now()\n\n\t\terr := m.mgr.Do(\"start module \"+m.mgr.name, func(_ *WorkerCtx) error {\n\t\t\treturn m.module.Start() //nolint:scopelint // Execution is synchronous.\n\t\t})\n\t\tif err != nil {\n\t\t\tm.mgr.Error(\n\t\t\t\t\"failed to start\",\n\t\t\t\t\"err\", err,\n\t\t\t\t\"time\", time.Since(startTime),\n\t\t\t)\n\t\t\tif !g.stopFrom(i) {\n\t\t\t\tg.state.Store(groupStateInvalid)\n\t\t\t} else {\n\t\t\t\tg.state.Store(groupStateOff)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to start %s: %w\", m.mgr.name, err)\n\t\t}\n\t\tm.mgr.Info(\"started\", \"time\", time.Since(startTime))\n\t}\n\n\tg.state.Store(groupStateRunning)\n\treturn nil\n}\n\n// IsStopped returns whether the group is stopped.\n// It returns an error if the group is in an invalid state.\nfunc (g *Group) IsStopped() (bool, error) {\n\tstate := g.state.Load()\n\tif state == groupStateInvalid {\n\t\treturn false, errors.New(\"invalid group state\")\n\t}\n\treturn state == groupStateOff, nil\n}\n\n// Stop stops all modules in the group in the reverse order.\nfunc (g *Group) Stop() error {\n\t// Check group state.\n\tswitch g.state.Load() {\n\tcase groupStateOff:\n\t\t// Already stopped.\n\t\treturn nil\n\tcase groupStateInvalid:\n\t\t// Something went terribly wrong, cannot recover from here.\n\t\treturn fmt.Errorf(\"%w: cannot recover\", ErrInvalidGroupState)\n\tdefault:\n\t\tif !g.state.CompareAndSwap(groupStateRunning, groupStateStopping) {\n\t\t\treturn fmt.Errorf(\"%w: group is not running, state: %s\", ErrUnsuitableGroupState, groupStateToString(g.state.Load()))\n\t\t}\n\t}\n\n\t// Stop modules.\n\tif !g.stopFrom(len(g.modules) - 1) {\n\t\tg.state.Store(groupStateInvalid)\n\t\treturn errors.New(\"failed to stop\")\n\t}\n\n\tg.state.Store(groupStateOff)\n\treturn nil\n}\n\nfunc (g *Group) stopFrom(index int) (ok bool) {\n\tok = true\n\n\t// Stop modules.\n\tfor i := index; i >= 0; i-- {\n\t\tm := g.modules[i]\n\t\tm.mgr.Debug(\"stopping\")\n\t\tstartTime := time.Now()\n\n\t\terr := m.mgr.Do(\"stop module \"+m.mgr.name, func(_ *WorkerCtx) error {\n\t\t\treturn m.module.Stop()\n\t\t})\n\t\tif err != nil {\n\t\t\tm.mgr.Error(\n\t\t\t\t\"failed to stop\",\n\t\t\t\t\"err\", err,\n\t\t\t\t\"time\", time.Since(startTime),\n\t\t\t)\n\t\t\tok = false\n\t\t}\n\t\tm.mgr.Cancel()\n\n\t\tvar waitSucceeded bool\n\t\tif m.mgr.hasStopWorker() {\n\t\t\twaitSucceeded = m.mgr.WaitForWorkersFromStop(0)\n\t\t} else {\n\t\t\twaitSucceeded = m.mgr.WaitForWorkers(0)\n\t\t}\n\n\t\tif waitSucceeded {\n\t\t\tm.mgr.Info(\"stopped\", \"time\", time.Since(startTime))\n\t\t} else {\n\t\t\tok = false\n\t\t\tm.mgr.Error(\n\t\t\t\t\"failed to stop\",\n\t\t\t\t\"err\", \"timed out\",\n\t\t\t\t\"workerCnt\", m.mgr.workerCnt.Load(),\n\t\t\t\t\"time\", time.Since(startTime),\n\t\t\t)\n\t\t}\n\t}\n\n\t// Reset modules.\n\tif !ok {\n\t\t// Stopping failed somewhere, reset anyway after a short wait.\n\t\t// This will be very uncommon and can help to mitigate race conditions in these events.\n\t\ttime.Sleep(time.Second)\n\t}\n\tfor _, m := range g.modules {\n\t\tm.mgr.Reset()\n\t}\n\n\treturn ok\n}\n\n// Ready returns whether all modules in the group have been started and are still running.\nfunc (g *Group) Ready() bool {\n\treturn g.state.Load() == groupStateRunning\n}\n\n// GetStates returns the current states of all group modules.\nfunc (g *Group) GetStates() []StateUpdate {\n\tupdates := make([]StateUpdate, 0, len(g.modules))\n\tfor _, gm := range g.modules {\n\t\tif stateful, ok := gm.module.(StatefulModule); ok {\n\t\t\tupdates = append(updates, stateful.States().Export())\n\t\t}\n\t}\n\treturn updates\n}\n\n// AddStatesCallback adds the given callback function to all group modules that\n// expose a state manager at States().\nfunc (g *Group) AddStatesCallback(callbackName string, callback EventCallbackFunc[StateUpdate]) {\n\tfor _, gm := range g.modules {\n\t\tif stateful, ok := gm.module.(StatefulModule); ok {\n\t\t\tstateful.States().AddCallback(callbackName, callback)\n\t\t}\n\t}\n}\n\n// Modules returns a copy of the modules.\nfunc (g *Group) Modules() []Module {\n\tcopied := make([]Module, 0, len(g.modules))\n\tfor _, gm := range g.modules {\n\t\tcopied = append(copied, gm.module)\n\t}\n\treturn copied\n}\n\n// RunModules is a simple wrapper function to start modules and stop them again\n// when the given context is canceled.\nfunc RunModules(ctx context.Context, modules ...Module) error {\n\tg := NewGroup(modules...)\n\n\t// Start module.\n\tif err := g.Start(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start: %w\", err)\n\t}\n\n\t// Stop module when context is canceled.\n\t<-ctx.Done()\n\treturn g.Stop()\n}\n\nfunc makeModuleName(m Module) string {\n\treturn strings.TrimPrefix(fmt.Sprintf(\"%T\", m), \"*\")\n}\n"
  },
  {
    "path": "service/mgr/group_ext.go",
    "content": "package mgr\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n)\n\n// ExtendedGroup extends the group with additional helpful functionality.\ntype ExtendedGroup struct {\n\t*Group\n\n\tensureCtx    context.Context\n\tensureCancel context.CancelFunc\n\tensureLock   sync.Mutex\n}\n\n// NewExtendedGroup returns a new extended group.\nfunc NewExtendedGroup(modules ...Module) *ExtendedGroup {\n\treturn UpgradeGroup(NewGroup(modules...))\n}\n\n// UpgradeGroup upgrades a regular group to an extended group.\nfunc UpgradeGroup(g *Group) *ExtendedGroup {\n\treturn &ExtendedGroup{\n\t\tGroup:        g,\n\t\tensureCancel: func() {},\n\t}\n}\n\n// EnsureStartedWorker tries to start the group until it succeeds or fails permanently.\nfunc (eg *ExtendedGroup) EnsureStartedWorker(wCtx *WorkerCtx) error {\n\t// Setup worker.\n\tvar ctx context.Context\n\tfunc() {\n\t\teg.ensureLock.Lock()\n\t\tdefer eg.ensureLock.Unlock()\n\t\teg.ensureCancel()\n\t\teg.ensureCtx, eg.ensureCancel = context.WithCancel(wCtx.Ctx())\n\t\tctx = eg.ensureCtx\n\t}()\n\n\tfor {\n\t\terr := eg.Group.Start()\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\treturn nil\n\t\tcase errors.Is(err, ErrInvalidGroupState):\n\t\t\twCtx.Debug(\"group start delayed\", \"err\", err)\n\t\tdefault:\n\t\t\treturn err\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-time.After(1 * time.Second):\n\t\t}\n\t}\n}\n\n// EnsureStoppedWorker tries to stop the group until it succeeds or fails permanently.\nfunc (eg *ExtendedGroup) EnsureStoppedWorker(wCtx *WorkerCtx) error {\n\t// Setup worker.\n\tvar ctx context.Context\n\tfunc() {\n\t\teg.ensureLock.Lock()\n\t\tdefer eg.ensureLock.Unlock()\n\t\teg.ensureCancel()\n\t\teg.ensureCtx, eg.ensureCancel = context.WithCancel(wCtx.Ctx())\n\t\tctx = eg.ensureCtx\n\t}()\n\n\tfor {\n\t\terr := eg.Group.Stop()\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\treturn nil\n\t\tcase errors.Is(err, ErrInvalidGroupState):\n\t\t\twCtx.Debug(\"group stop delayed\", \"err\", err)\n\t\tdefault:\n\t\t\treturn err\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-time.After(1 * time.Second):\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/mgr/group_module.go",
    "content": "package mgr\n\n// GroupModule is a module that wraps a group of modules,\n// to allow nesting groups of modules in parent group.\ntype GroupModule struct {\n\tmgr   *Manager\n\tgroup *Group\n}\n\nfunc NewGroupModule(name string, modules ...Module) *GroupModule {\n\treturn &GroupModule{\n\t\tmgr:   New(name),\n\t\tgroup: NewGroup(modules...),\n\t}\n}\n\nfunc (gm *GroupModule) Manager() *Manager {\n\treturn gm.mgr\n}\n\nfunc (gm *GroupModule) Start() error {\n\treturn gm.group.Start()\n}\n\nfunc (gm *GroupModule) Stop() error {\n\treturn gm.group.Stop()\n}\n\n// Modules returns the modules in the group wrapped by this group module.\n// (mimics Group.Modules())\nfunc (gm *GroupModule) Modules() []Module {\n\treturn gm.group.Modules()\n}\n"
  },
  {
    "path": "service/mgr/manager.go",
    "content": "package mgr\n\nimport (\n\t\"context\"\n\t\"log/slog\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// ManagerNameSLogKey is used as the logging key for the name of the manager.\nvar ManagerNameSLogKey = \"manager\"\n\n// Manager manages workers.\ntype Manager struct {\n\tname   string\n\tlogger *slog.Logger\n\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n\n\tworkerCnt   atomic.Int32\n\tworkersDone chan struct{}\n\n\tworkers      []*WorkerCtx\n\tworkersIndex int\n\tworkersLock  sync.Mutex\n}\n\n// New returns a new manager.\nfunc New(name string) *Manager {\n\treturn newManager(name)\n}\n\nfunc newManager(name string) *Manager {\n\tm := &Manager{\n\t\tname:        name,\n\t\tlogger:      slog.Default().With(ManagerNameSLogKey, name),\n\t\tworkersDone: make(chan struct{}),\n\t\tworkers:     make([]*WorkerCtx, 4),\n\t}\n\tm.ctx, m.cancelCtx = context.WithCancel(context.Background())\n\treturn m\n}\n\n// Name returns the manager name.\nfunc (m *Manager) Name() string {\n\treturn m.name\n}\n\n// setName sets the manager name and resets the logger to use that name.\n// Not safe for concurrent use with any other module methods.\nfunc (m *Manager) setName(newName string) {\n\tm.name = newName\n\tm.logger = slog.Default().With(ManagerNameSLogKey, m.name)\n}\n\n// Ctx returns the worker context.\nfunc (m *Manager) Ctx() context.Context {\n\treturn m.ctx\n}\n\n// Cancel cancels the worker context.\nfunc (m *Manager) Cancel() {\n\tm.cancelCtx()\n}\n\n// Done returns the context Done channel.\nfunc (m *Manager) Done() <-chan struct{} {\n\treturn m.ctx.Done()\n}\n\n// IsDone checks whether the manager context is done.\nfunc (m *Manager) IsDone() bool {\n\treturn m.ctx.Err() != nil\n}\n\n// LogEnabled reports whether the logger emits log records at the given level.\n// The manager context is automatically supplied.\nfunc (m *Manager) LogEnabled(level slog.Level) bool {\n\treturn m.logger.Enabled(m.ctx, level)\n}\n\n// Debug logs at LevelDebug.\n// The manager context is automatically supplied.\nfunc (m *Manager) Debug(msg string, args ...any) {\n\tif !m.logger.Enabled(m.ctx, slog.LevelDebug) {\n\t\treturn\n\t}\n\tm.writeLog(slog.LevelDebug, msg, args...)\n}\n\n// Info logs at LevelInfo.\n// The manager context is automatically supplied.\nfunc (m *Manager) Info(msg string, args ...any) {\n\tif !m.logger.Enabled(m.ctx, slog.LevelInfo) {\n\t\treturn\n\t}\n\tm.writeLog(slog.LevelInfo, msg, args...)\n}\n\n// Warn logs at LevelWarn.\n// The manager context is automatically supplied.\nfunc (m *Manager) Warn(msg string, args ...any) {\n\tif !m.logger.Enabled(m.ctx, slog.LevelWarn) {\n\t\treturn\n\t}\n\tm.writeLog(slog.LevelWarn, msg, args...)\n}\n\n// Error logs at LevelError.\n// The manager context is automatically supplied.\nfunc (m *Manager) Error(msg string, args ...any) {\n\tif !m.logger.Enabled(m.ctx, slog.LevelError) {\n\t\treturn\n\t}\n\tm.writeLog(slog.LevelError, msg, args...)\n}\n\n// Log emits a log record with the current time and the given level and message.\n// The manager context is automatically supplied.\nfunc (m *Manager) Log(level slog.Level, msg string, args ...any) {\n\tif !m.logger.Enabled(m.ctx, level) {\n\t\treturn\n\t}\n\tm.writeLog(level, msg, args...)\n}\n\n// LogAttrs is a more efficient version of Log() that accepts only Attrs.\n// The manager context is automatically supplied.\nfunc (m *Manager) LogAttrs(level slog.Level, msg string, attrs ...slog.Attr) {\n\tif !m.logger.Enabled(m.ctx, level) {\n\t\treturn\n\t}\n\n\tvar pcs [1]uintptr\n\truntime.Callers(2, pcs[:]) // skip \"Callers\" and \"LogAttrs\".\n\tr := slog.NewRecord(time.Now(), level, msg, pcs[0])\n\tr.AddAttrs(attrs...)\n\t_ = m.logger.Handler().Handle(m.ctx, r)\n}\n\nfunc (m *Manager) writeLog(level slog.Level, msg string, args ...any) {\n\tvar pcs [1]uintptr\n\truntime.Callers(3, pcs[:]) // skip \"Callers\", \"writeLog\" and the calling function.\n\tr := slog.NewRecord(time.Now(), level, msg, pcs[0])\n\tr.Add(args...)\n\t_ = m.logger.Handler().Handle(m.ctx, r)\n}\n\n// WaitForWorkers waits for all workers of this manager to be done.\n// The default maximum waiting time is one minute.\nfunc (m *Manager) WaitForWorkers(max time.Duration) (done bool) {\n\treturn m.waitForWorkers(max, 0)\n}\n\n// WaitForWorkersFromStop is a special version of WaitForWorkers, meant to be called from the stop routine.\n// It waits for all workers of this manager to be done, except for the Stop function.\n// The default maximum waiting time is one minute.\nfunc (m *Manager) WaitForWorkersFromStop(max time.Duration) (done bool) {\n\treturn m.waitForWorkers(max, 1)\n}\n\nfunc (m *Manager) waitForWorkers(max time.Duration, limit int32) (done bool) {\n\t// Return immediately if there are no workers.\n\tif m.workerCnt.Load() <= limit {\n\t\treturn true\n\t}\n\n\t// Setup timers.\n\treCheckDuration := 10 * time.Millisecond\n\tif max <= 0 {\n\t\tmax = time.Minute\n\t}\n\treCheck := time.NewTimer(reCheckDuration)\n\tmaxWait := time.NewTimer(max)\n\tdefer reCheck.Stop()\n\tdefer maxWait.Stop()\n\n\t// Wait for workers to finish, plus check the count in intervals.\n\tfor {\n\t\tif m.workerCnt.Load() <= limit {\n\t\t\treturn true\n\t\t}\n\n\t\tselect {\n\t\tcase <-m.workersDone:\n\t\t\tif m.workerCnt.Load() <= limit {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\tcase <-reCheck.C:\n\t\t\t// Check worker count again.\n\t\t\t// This is a dead simple and effective way to avoid all the channel race conditions.\n\t\t\treCheckDuration *= 2\n\t\t\treCheck.Reset(reCheckDuration)\n\n\t\tcase <-maxWait.C:\n\t\t\treturn m.workerCnt.Load() <= limit\n\t\t}\n\t}\n}\n\nfunc (m *Manager) workerStart(w *WorkerCtx) {\n\tm.registerWorker(w)\n\tm.workerCnt.Add(1)\n}\n\nfunc (m *Manager) workerDone(w *WorkerCtx) {\n\tm.unregisterWorker(w)\n\tif m.workerCnt.Add(-1) <= 1 {\n\t\t// Notify all waiters.\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase m.workersDone <- struct{}{}:\n\t\t\tdefault:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Reset resets the manager in order to be able to be used again.\n// In the process, the current context is canceled.\n// As part of a module (in a group), the module might be stopped and started again.\n// This method is not goroutine-safe. The caller must make sure the manager is\n// not being used in any way during execution.\nfunc (m *Manager) Reset() {\n\tm.cancelCtx()\n\tm.ctx, m.cancelCtx = context.WithCancel(context.Background())\n\tm.workerCnt.Store(0)\n\tm.workersDone = make(chan struct{})\n}\n"
  },
  {
    "path": "service/mgr/sleepyticker.go",
    "content": "package mgr\n\nimport \"time\"\n\n// SleepyTicker is wrapper over time.Ticker that respects the sleep mode of the module.\ntype SleepyTicker struct {\n\tticker         *time.Ticker\n\tnormalDuration time.Duration\n\tsleepDuration  time.Duration\n\tsleepMode      bool\n\n\tsleepChannel chan time.Time\n}\n\n// NewSleepyTicker returns a new SleepyTicker. This is a wrapper of the standard time.Ticker but it respects modules.Module sleep mode. Check https://pkg.go.dev/time#Ticker.\n// If sleepDuration is set to 0 ticker will not tick during sleep.\nfunc NewSleepyTicker(normalDuration time.Duration, sleepDuration time.Duration) *SleepyTicker {\n\tst := &SleepyTicker{\n\t\tticker:         time.NewTicker(normalDuration),\n\t\tnormalDuration: normalDuration,\n\t\tsleepDuration:  sleepDuration,\n\t\tsleepMode:      false,\n\t}\n\n\treturn st\n}\n\n// Wait waits until the module is not in sleep mode and returns time.Ticker.C channel.\nfunc (st *SleepyTicker) Wait() <-chan time.Time {\n\tif st.sleepMode && st.sleepDuration == 0 {\n\t\treturn st.sleepChannel\n\t}\n\treturn st.ticker.C\n}\n\n// Stop turns off a ticker. After Stop, no more ticks will be sent. Stop does not close the channel, to prevent a concurrent goroutine reading from the channel from seeing an erroneous \"tick\".\nfunc (st *SleepyTicker) Stop() {\n\tst.ticker.Stop()\n}\n\n// SetSleep sets the sleep mode of the ticker. If enabled is true, the ticker will tick with sleepDuration. If enabled is false, the ticker will tick with normalDuration.\nfunc (st *SleepyTicker) SetSleep(enabled bool) {\n\tst.sleepMode = enabled\n\tif enabled {\n\t\tif st.sleepDuration > 0 {\n\t\t\tst.ticker.Reset(st.sleepDuration)\n\t\t} else {\n\t\t\t// Next call to Wait will wait until SetSleep is called with enabled == false\n\t\t\tst.sleepChannel = make(chan time.Time)\n\t\t}\n\t} else {\n\t\tst.ticker.Reset(st.normalDuration)\n\t\tif st.sleepDuration > 0 {\n\t\t\t// Notify that  we are not sleeping anymore.\n\t\t\tclose(st.sleepChannel)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/mgr/sleepyticker_test.go",
    "content": "package mgr\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestSleepyTickerStop(t *testing.T) {\n\tnormalDuration := 100 * time.Millisecond\n\tsleepDuration := 200 * time.Millisecond\n\n\tst := NewSleepyTicker(normalDuration, sleepDuration)\n\tst.Stop() // no panic expected here\n}\n\nfunc TestSleepyTicker(t *testing.T) {\n\tnormalDuration := 100 * time.Millisecond\n\tsleepDuration := 200 * time.Millisecond\n\n\tst := NewSleepyTicker(normalDuration, sleepDuration)\n\n\t// Test normal mode\n\tselect {\n\tcase <-st.Wait():\n\t\t// Expected tick\n\tcase <-time.After(normalDuration + 50*time.Millisecond):\n\t\tt.Error(\"expected tick in normal mode\")\n\t}\n\n\t// Test sleep mode\n\tst.SetSleep(true)\n\tselect {\n\tcase <-st.Wait():\n\t\t// Expected tick\n\tcase <-time.After(sleepDuration + 50*time.Millisecond):\n\t\tt.Error(\"expected tick in sleep mode\")\n\t}\n\n\t// Test sleep mode with sleepDuration == 0\n\tst = NewSleepyTicker(normalDuration, 0)\n\tst.SetSleep(true)\n\tselect {\n\tcase <-st.Wait():\n\t\tt.Error(\"did not expect tick when sleepDuration is 0\")\n\tcase <-time.After(normalDuration):\n\t\t// Expected no tick\n\t}\n\n\t// Test stopping the ticker\n\tst.Stop()\n\tselect {\n\tcase <-st.Wait():\n\t\tt.Error(\"did not expect tick after stopping the ticker\")\n\tcase <-time.After(normalDuration):\n\t\t// Expected no tick\n\t}\n}\n"
  },
  {
    "path": "service/mgr/states.go",
    "content": "package mgr\n\nimport (\n\t\"slices\"\n\t\"sync\"\n\t\"time\"\n)\n\n// StateMgr is a simple state manager.\ntype StateMgr struct {\n\tstates     []State\n\tstatesLock sync.Mutex\n\n\tstatesEventMgr *EventMgr[StateUpdate]\n\n\tmgr *Manager\n}\n\n// State describes the state of a manager or module.\ntype State struct {\n\t// ID is a program-unique ID.\n\t// It must not only be unique within the StateMgr, but for the whole program,\n\t// as it may be re-used with related systems.\n\t// Required.\n\tID string\n\n\t// Name is the name of the state.\n\t// This may also serve as a notification title.\n\t// Required.\n\tName string\n\n\t// Message is a more detailed message about the state.\n\t// Optional.\n\tMessage string\n\n\t// Type defines the type of the state.\n\t// Optional.\n\tType StateType\n\n\t// Time is the time when the state was created or the originating incident occurred.\n\t// Optional, will be set to current time if not set.\n\tTime time.Time\n\n\t// Data can hold any additional data necessary for further processing of connected systems.\n\t// Optional.\n\tData any\n}\n\n// StateType defines commonly used states.\ntype StateType string\n\n// State Types.\nconst (\n\tStateTypeUndefined = \"\"\n\tStateTypeHint      = \"hint\"\n\tStateTypeWarning   = \"warning\"\n\tStateTypeError     = \"error\"\n)\n\n// Severity returns a number representing the gravity of the state for ordering.\nfunc (st StateType) Severity() int {\n\tswitch st {\n\tcase StateTypeUndefined:\n\t\treturn 0\n\tcase StateTypeHint:\n\t\treturn 1\n\tcase StateTypeWarning:\n\t\treturn 2\n\tcase StateTypeError:\n\t\treturn 3\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// StateUpdate is used to update others about a state change.\ntype StateUpdate struct {\n\tModule string\n\tStates []State\n}\n\n// StatefulModule is used for interface checks on modules.\ntype StatefulModule interface {\n\tStates() *StateMgr\n}\n\n// NewStateMgr returns a new state manager.\nfunc NewStateMgr(mgr *Manager) *StateMgr {\n\treturn &StateMgr{\n\t\tstatesEventMgr: NewEventMgr[StateUpdate](\"state update\", mgr),\n\t\tmgr:            mgr,\n\t}\n}\n\n// NewStateMgr returns a new state manager.\nfunc (m *Manager) NewStateMgr() *StateMgr {\n\treturn NewStateMgr(m)\n}\n\n// Add adds a state.\n// If a state with the same ID already exists, it is replaced.\nfunc (m *StateMgr) Add(s State) {\n\tm.statesLock.Lock()\n\tdefer m.statesLock.Unlock()\n\n\tif s.Time.IsZero() {\n\t\ts.Time = time.Now()\n\t}\n\n\t// Update or add state.\n\tindex := slices.IndexFunc(m.states, func(es State) bool {\n\t\treturn es.ID == s.ID\n\t})\n\tif index >= 0 {\n\t\tm.states[index] = s\n\t} else {\n\t\tm.states = append(m.states, s)\n\t}\n\n\tm.statesEventMgr.Submit(m.export())\n}\n\n// Remove removes the state with the given ID.\nfunc (m *StateMgr) Remove(id string) {\n\tm.statesLock.Lock()\n\tdefer m.statesLock.Unlock()\n\n\t// Quick check if slice is empty.\n\t// It is a common pattern to remove a state when no error was encountered at\n\t// a critical operation. This means that StateMgr.Remove will be called often.\n\tif len(m.states) == 0 {\n\t\treturn\n\t}\n\n\tvar entryRemoved bool\n\tm.states = slices.DeleteFunc(m.states, func(s State) bool {\n\t\tif s.ID == id {\n\t\t\tentryRemoved = true\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t})\n\n\tif entryRemoved {\n\t\tm.statesEventMgr.Submit(m.export())\n\t}\n}\n\n// Clear removes all states.\nfunc (m *StateMgr) Clear() {\n\tm.statesLock.Lock()\n\tm.states = nil\n\tm.statesLock.Unlock()\n\n\t// Submit event without lock, because callbacks might come back to change states.\n\tdefer m.statesEventMgr.Submit(m.Export())\n}\n\n// Export returns the current states.\nfunc (m *StateMgr) Export() StateUpdate {\n\tm.statesLock.Lock()\n\tdefer m.statesLock.Unlock()\n\n\treturn m.export()\n}\n\n// export returns the current states.\nfunc (m *StateMgr) export() StateUpdate {\n\tname := \"\"\n\tif m.mgr != nil {\n\t\tname = m.mgr.name\n\t}\n\n\treturn StateUpdate{\n\t\tModule: name,\n\t\tStates: slices.Clone(m.states),\n\t}\n}\n\n// Subscribe subscribes to state update events.\nfunc (m *StateMgr) Subscribe(subscriberName string, chanSize int) *EventSubscription[StateUpdate] {\n\treturn m.statesEventMgr.Subscribe(subscriberName, chanSize)\n}\n\n// AddCallback adds a callback to state update events.\nfunc (m *StateMgr) AddCallback(callbackName string, callback EventCallbackFunc[StateUpdate]) {\n\tm.statesEventMgr.AddCallback(callbackName, callback)\n}\n"
  },
  {
    "path": "service/mgr/worker.go",
    "content": "package mgr\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log/slog\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// workerContextKey is a key used for the context key/value storage.\ntype workerContextKey struct{}\n\n// WorkerCtxContextKey is the key used to add the WorkerCtx to a context.\nvar WorkerCtxContextKey = workerContextKey{}\n\n// WorkerCtx provides workers with the necessary environment for flow control\n// and logging.\ntype WorkerCtx struct {\n\tname     string\n\tworkFunc func(w *WorkerCtx) error\n\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n\n\tworkerMgr *WorkerMgr // TODO: Attach to context instead?\n\tlogger    *slog.Logger\n\n\t// isStopWorker indicates whether this worker is responsible for stopping\n\t// the manager. When true, the manager will not wait for this worker to\n\t// finish during stop, preventing deadlocks where the stop worker\n\t// would wait for itself to complete.\n\tisStopWorker bool\n}\n\n// AddToCtx adds the WorkerCtx to the given context.\nfunc (w *WorkerCtx) AddToCtx(ctx context.Context) context.Context {\n\treturn context.WithValue(ctx, WorkerCtxContextKey, w)\n}\n\n// WorkerFromCtx returns the WorkerCtx from the given context.\nfunc WorkerFromCtx(ctx context.Context) *WorkerCtx {\n\tv := ctx.Value(WorkerCtxContextKey)\n\tif w, ok := v.(*WorkerCtx); ok {\n\t\treturn w\n\t}\n\treturn nil\n}\n\n// Ctx returns the worker context.\n// Is automatically canceled after the worker stops/returns, regardless of error.\nfunc (w *WorkerCtx) Ctx() context.Context {\n\treturn w.ctx\n}\n\n// Cancel cancels the worker context.\n// Is automatically called after the worker stops/returns, regardless of error.\nfunc (w *WorkerCtx) Cancel() {\n\tw.cancelCtx()\n}\n\n// WorkerMgr returns the worker manager the worker was started from.\n// Returns nil if the worker is not associated with a scheduler.\nfunc (w *WorkerCtx) WorkerMgr() *WorkerMgr {\n\treturn w.workerMgr\n}\n\n// Done returns the context Done channel.\nfunc (w *WorkerCtx) Done() <-chan struct{} {\n\treturn w.ctx.Done()\n}\n\n// IsDone checks whether the worker context is done.\nfunc (w *WorkerCtx) IsDone() bool {\n\treturn w.ctx.Err() != nil\n}\n\n// Logger returns the logger used by the worker context.\nfunc (w *WorkerCtx) Logger() *slog.Logger {\n\treturn w.logger\n}\n\n// LogEnabled reports whether the logger emits log records at the given level.\n// The worker context is automatically supplied.\nfunc (w *WorkerCtx) LogEnabled(level slog.Level) bool {\n\treturn w.logger.Enabled(w.ctx, level)\n}\n\n// Debug logs at LevelDebug.\n// The worker context is automatically supplied.\nfunc (w *WorkerCtx) Debug(msg string, args ...any) {\n\tif !w.logger.Enabled(w.ctx, slog.LevelDebug) {\n\t\treturn\n\t}\n\tw.writeLog(slog.LevelDebug, msg, args...)\n}\n\n// Info logs at LevelInfo.\n// The worker context is automatically supplied.\nfunc (w *WorkerCtx) Info(msg string, args ...any) {\n\tif !w.logger.Enabled(w.ctx, slog.LevelInfo) {\n\t\treturn\n\t}\n\tw.writeLog(slog.LevelInfo, msg, args...)\n}\n\n// Warn logs at LevelWarn.\n// The worker context is automatically supplied.\nfunc (w *WorkerCtx) Warn(msg string, args ...any) {\n\tif !w.logger.Enabled(w.ctx, slog.LevelWarn) {\n\t\treturn\n\t}\n\tw.writeLog(slog.LevelWarn, msg, args...)\n}\n\n// Error logs at LevelError.\n// The worker context is automatically supplied.\nfunc (w *WorkerCtx) Error(msg string, args ...any) {\n\tif !w.logger.Enabled(w.ctx, slog.LevelError) {\n\t\treturn\n\t}\n\tw.writeLog(slog.LevelError, msg, args...)\n}\n\n// Log emits a log record with the current time and the given level and message.\n// The worker context is automatically supplied.\nfunc (w *WorkerCtx) Log(level slog.Level, msg string, args ...any) {\n\tif !w.logger.Enabled(w.ctx, level) {\n\t\treturn\n\t}\n\tw.writeLog(level, msg, args...)\n}\n\n// LogAttrs is a more efficient version of Log() that accepts only Attrs.\n// The worker context is automatically supplied.\nfunc (w *WorkerCtx) LogAttrs(level slog.Level, msg string, attrs ...slog.Attr) {\n\tif !w.logger.Enabled(w.ctx, level) {\n\t\treturn\n\t}\n\n\tvar pcs [1]uintptr\n\truntime.Callers(2, pcs[:]) // skip \"Callers\" and \"LogAttrs\".\n\tr := slog.NewRecord(time.Now(), level, msg, pcs[0])\n\tr.AddAttrs(attrs...)\n\t_ = w.logger.Handler().Handle(w.ctx, r)\n}\n\nfunc (w *WorkerCtx) writeLog(level slog.Level, msg string, args ...any) {\n\tvar pcs [1]uintptr\n\truntime.Callers(3, pcs[:]) // skip \"Callers\", \"writeLog\" and the calling function.\n\tr := slog.NewRecord(time.Now(), level, msg, pcs[0])\n\tr.Add(args...)\n\t_ = w.logger.Handler().Handle(w.ctx, r)\n}\n\n// Go starts the given function in a goroutine (as a \"worker\").\n// The worker context has\n// - A separate context which is canceled when the functions returns.\n// - Access to named structure logging.\n// - Given function is re-run after failure (with backoff).\n// - Panic catching.\n// - Flow control helpers.\nfunc (m *Manager) Go(name string, fn func(w *WorkerCtx) error) {\n\t// m.logger.Log(m.ctx, slog.LevelInfo, \"worker started\", \"name\", name)\n\tgo m.manageWorker(name, fn)\n}\n\nfunc (m *Manager) manageWorker(name string, fn func(w *WorkerCtx) error) {\n\tw := &WorkerCtx{\n\t\tname:     name,\n\t\tworkFunc: fn,\n\t\tlogger:   m.logger.With(\"worker\", name),\n\t}\n\tw.ctx = m.ctx\n\n\tm.workerStart(w)\n\tdefer m.workerDone(w)\n\n\tbackoff := time.Second\n\tfailCnt := 0\n\n\tfor {\n\t\tpanicInfo, err := m.runWorker(w, fn)\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\t// No error means that the worker is finished.\n\t\t\treturn\n\n\t\tcase errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):\n\t\t\t// A canceled context or exceeded deadline also means that the worker is finished.\n\t\t\treturn\n\n\t\tdefault:\n\t\t\t// Any other errors triggers a restart with backoff.\n\n\t\t\t// If manager is stopping, just log error and return.\n\t\t\tif m.IsDone() {\n\t\t\t\tif panicInfo != \"\" {\n\t\t\t\t\tw.Error(\n\t\t\t\t\t\t\"worker failed\",\n\t\t\t\t\t\t\"err\", err,\n\t\t\t\t\t\t\"file\", panicInfo,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tw.Error(\n\t\t\t\t\t\t\"worker failed\",\n\t\t\t\t\t\t\"err\", err,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Count failure and increase backoff (up to limit),\n\t\t\tfailCnt++\n\t\t\tbackoff *= 2\n\t\t\tif backoff > time.Minute {\n\t\t\t\tbackoff = time.Minute\n\t\t\t}\n\n\t\t\t// Log error and retry after backoff duration.\n\t\t\tif panicInfo != \"\" {\n\t\t\t\tw.Error(\n\t\t\t\t\t\"worker failed\",\n\t\t\t\t\t\"failCnt\", failCnt,\n\t\t\t\t\t\"backoff\", backoff,\n\t\t\t\t\t\"err\", err,\n\t\t\t\t\t\"file\", panicInfo,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tw.Error(\n\t\t\t\t\t\"worker failed\",\n\t\t\t\t\t\"failCnt\", failCnt,\n\t\t\t\t\t\"backoff\", backoff,\n\t\t\t\t\t\"err\", err,\n\t\t\t\t)\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase <-time.After(backoff):\n\t\t\tcase <-m.ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Do directly executes the given function (as a \"worker\").\n// The worker context has\n// - A separate context which is canceled when the functions returns.\n// - Access to named structure logging.\n// - Given function is re-run after failure (with backoff).\n// - Panic catching.\n// - Flow control helpers.\nfunc (m *Manager) Do(name string, fn func(w *WorkerCtx) error) error {\n\treturn m.do(name, false, fn)\n}\n\n// DoAsStopWorker is like Do(...), but marks the worker as a stop worker.\n// This means that the manager will not wait for this worker to finish when stopping.\n// Only one stop worker can be started at a time.\nfunc (m *Manager) DoAsStopWorker(name string, fn func(w *WorkerCtx) error) error {\n\tif m.hasStopWorker() {\n\t\treturn fmt.Errorf(\"cannot start stop worker %q: already has a stop worker\", name)\n\t}\n\treturn m.do(name, true, fn)\n}\n\nfunc (m *Manager) do(name string, isStopWorker bool, fn func(w *WorkerCtx) error) error {\n\t// Create context.\n\tw := &WorkerCtx{\n\t\tname:         name,\n\t\tworkFunc:     fn,\n\t\tctx:          m.Ctx(),\n\t\tlogger:       m.logger.With(\"worker\", name),\n\t\tisStopWorker: isStopWorker,\n\t}\n\n\tm.workerStart(w)\n\tdefer m.workerDone(w)\n\n\t// Run worker.\n\tpanicInfo, err := m.runWorker(w, fn)\n\tswitch {\n\tcase err == nil:\n\t\t// No error means that the worker is finished.\n\t\treturn nil\n\n\tcase errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):\n\t\t// A canceled context or exceeded deadline also means that the worker is finished.\n\t\treturn err\n\n\tdefault:\n\t\t// Log error and return.\n\t\tif panicInfo != \"\" {\n\t\t\tw.Error(\n\t\t\t\t\"worker failed\",\n\t\t\t\t\"err\", err,\n\t\t\t\t\"file\", panicInfo,\n\t\t\t)\n\t\t} else {\n\t\t\tw.Error(\n\t\t\t\t\"worker failed\",\n\t\t\t\t\"err\", err,\n\t\t\t)\n\t\t}\n\t\treturn err\n\t}\n}\n\nfunc (m *Manager) runWorker(w *WorkerCtx, fn func(w *WorkerCtx) error) (panicInfo string, err error) {\n\t// Create worker context that is canceled when worker finished or dies.\n\tw.ctx, w.cancelCtx = context.WithCancel(w.ctx)\n\tdefer w.Cancel()\n\n\t// Recover from panic.\n\tdefer func() {\n\t\tpanicVal := recover()\n\t\tif panicVal != nil {\n\t\t\terr = fmt.Errorf(\"panic: %s\", panicVal)\n\n\t\t\t// Print panic to stderr.\n\t\t\tstackTrace := string(debug.Stack())\n\t\t\tfmt.Fprintf(\n\t\t\t\tlog.GlobalWriter,\n\t\t\t\t\"===== PANIC =====\\n%s\\n\\n%s=====  END  =====\\n\",\n\t\t\t\tpanicVal,\n\t\t\t\tstackTrace,\n\t\t\t)\n\n\t\t\t// Find the line in the stack trace that refers to where the panic occurred.\n\t\t\tstackLines := strings.Split(stackTrace, \"\\n\")\n\t\t\tfoundPanic := false\n\t\t\tfor i, line := range stackLines {\n\t\t\t\tif !foundPanic {\n\t\t\t\t\tif strings.Contains(line, \"panic(\") {\n\t\t\t\t\t\tfoundPanic = true\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif strings.Contains(line, \"portmaster\") {\n\t\t\t\t\t\tif i+1 < len(stackLines) {\n\t\t\t\t\t\t\tpanicInfo = strings.SplitN(strings.TrimSpace(stackLines[i+1]), \" \", 2)[0]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\terr = fn(w)\n\treturn //nolint\n}\n\n// Repeat executes the given function periodically in a goroutine (as a \"worker\").\n// The worker context has\n// - A separate context which is canceled when the functions returns.\n// - Access to named structure logging.\n// - By default error/panic will be logged. For custom behavior supply errorFn, the argument is optional.\n// - Flow control helpers.\n// - Repeat is intended for long running tasks that are mostly idle.\nfunc (m *Manager) Repeat(name string, period time.Duration, fn func(w *WorkerCtx) error) *WorkerMgr {\n\tt := m.NewWorkerMgr(name, fn, nil)\n\treturn t.Repeat(period)\n}\n\n// Delay starts the given function delayed in a goroutine (as a \"worker\").\n// The worker context has\n// - A separate context which is canceled when the functions returns.\n// - Access to named structure logging.\n// - By default error/panic will be logged. For custom behavior supply errorFn, the argument is optional.\n// - Panic catching.\n// - Flow control helpers.\nfunc (m *Manager) Delay(name string, period time.Duration, fn func(w *WorkerCtx) error) *WorkerMgr {\n\tt := m.NewWorkerMgr(name, fn, nil)\n\treturn t.Delay(period)\n}\n"
  },
  {
    "path": "service/mgr/worker_info.go",
    "content": "package mgr\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/maruel/panicparse/v2/stack\"\n)\n\n// WorkerInfoModule is used for interface checks on modules.\ntype WorkerInfoModule interface {\n\tWorkerInfo(s *stack.Snapshot) (*WorkerInfo, error)\n}\n\nfunc (m *Manager) registerWorker(w *WorkerCtx) {\n\tm.workersLock.Lock()\n\tdefer m.workersLock.Unlock()\n\n\t// Iterate forwards over the ring buffer.\n\tend := (m.workersIndex - 1 + len(m.workers)) % len(m.workers)\n\tfor {\n\t\t// Check if entry is available.\n\t\tif m.workers[m.workersIndex] == nil {\n\t\t\tm.workers[m.workersIndex] = w\n\t\t\treturn\n\t\t}\n\t\t// Check if we checked the whole ring buffer.\n\t\tif m.workersIndex == end {\n\t\t\tbreak\n\t\t}\n\t\t// Go to next index.\n\t\tm.workersIndex = (m.workersIndex + 1) % len(m.workers)\n\t}\n\n\t// Increase ring buffer.\n\tnewRingBuf := make([]*WorkerCtx, len(m.workers)*4)\n\tcopy(newRingBuf, m.workers)\n\t// Add new entry.\n\tm.workersIndex = len(m.workers)\n\tnewRingBuf[m.workersIndex] = w\n\tm.workersIndex++\n\t// Switch to new ring buffer.\n\tm.workers = newRingBuf\n}\n\nfunc (m *Manager) unregisterWorker(w *WorkerCtx) {\n\tm.workersLock.Lock()\n\tdefer m.workersLock.Unlock()\n\n\t// Iterate backwards over the ring buffer.\n\ti := m.workersIndex\n\tend := (i + 1) % len(m.workers)\n\tfor {\n\t\t// Check if entry is the one we want to remove.\n\t\tif m.workers[i] == w {\n\t\t\tm.workers[i] = nil\n\t\t\treturn\n\t\t}\n\t\t// Check if we checked the whole ring buffer.\n\t\tif i == end {\n\t\t\tbreak\n\t\t}\n\t\t// Go to next index.\n\t\ti = (i - 1 + len(m.workers)) % len(m.workers)\n\t}\n}\n\nfunc (m *Manager) hasStopWorker() bool {\n\tm.workersLock.Lock()\n\tdefer m.workersLock.Unlock()\n\n\tfor _, w := range m.workers {\n\t\tif w == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif w.isStopWorker {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// WorkerInfo holds status information about a managers workers.\ntype WorkerInfo struct {\n\tRunning int\n\tWaiting int\n\n\tOther   int\n\tMissing int\n\n\tWorkers []*WorkerInfoDetail\n}\n\n// WorkerInfoDetail holds status information about a single worker.\ntype WorkerInfoDetail struct {\n\tCount       int\n\tState       string\n\tMgr         string\n\tName        string\n\tFunc        string\n\tCurrentLine string\n\tExtraInfo   string\n}\n\n// WorkerInfo returns status information for all running workers of this manager.\nfunc (m *Manager) WorkerInfo(s *stack.Snapshot) (*WorkerInfo, error) {\n\tm.workersLock.Lock()\n\tdefer m.workersLock.Unlock()\n\n\tvar err error\n\tif s == nil {\n\t\ts, _, err = stack.ScanSnapshot(bytes.NewReader(fullStack()), io.Discard, stack.DefaultOpts())\n\t\tif err != nil && !errors.Is(err, io.EOF) {\n\t\t\treturn nil, fmt.Errorf(\"get stack: %w\", err)\n\t\t}\n\t}\n\n\twi := &WorkerInfo{\n\t\tWorkers: make([]*WorkerInfoDetail, 0, len(m.workers)),\n\t}\n\n\t// Go through all registered workers of manager.\n\tfor _, w := range m.workers {\n\t\t// Ignore empty slots.\n\t\tif w == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Setup worker detail struct.\n\t\twd := &WorkerInfoDetail{\n\t\t\tCount: 1,\n\t\t\tMgr:   m.name,\n\t\t}\n\t\tif w.workerMgr != nil {\n\t\t\twd.Name = w.workerMgr.name\n\t\t\twd.Func = getFuncName(w.workerMgr.fn)\n\t\t} else {\n\t\t\twd.Name = w.name\n\t\t\twd.Func = getFuncName(w.workFunc)\n\t\t}\n\n\t\t// Search for stack of this worker.\n\tgoroutines:\n\t\tfor _, gr := range s.Goroutines {\n\t\t\tfor _, call := range gr.Stack.Calls {\n\t\t\t\t// Check if the can find the worker function in a call stack.\n\t\t\t\tfullFuncName := call.Func.ImportPath + \".\" + call.Func.Name\n\t\t\t\tif fullFuncName == wd.Func {\n\t\t\t\t\twd.State = gr.State\n\n\t\t\t\t\t// Find most useful line for where the goroutine currently is at.\n\t\t\t\t\t// Cut import path prefix to domain/user, eg. github.com/safing\n\t\t\t\t\timportPathPrefix := call.ImportPath\n\t\t\t\t\tsplitted := strings.SplitN(importPathPrefix, \"/\", 3)\n\t\t\t\t\tif len(splitted) == 3 {\n\t\t\t\t\t\timportPathPrefix = splitted[0] + \"/\" + splitted[1] + \"/\"\n\t\t\t\t\t}\n\t\t\t\t\t// Find \"last\" call within that import path prefix.\n\t\t\t\t\tfor _, call = range gr.Stack.Calls {\n\t\t\t\t\t\tif strings.HasPrefix(call.ImportPath, importPathPrefix) {\n\t\t\t\t\t\t\twd.CurrentLine = call.ImportPath + \"/\" + call.SrcName + \":\" + strconv.Itoa(call.Line)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// Fall back to last call if no better line was found.\n\t\t\t\t\tif wd.CurrentLine == \"\" {\n\t\t\t\t\t\twd.CurrentLine = gr.Stack.Calls[0].ImportPath + \"/\" + gr.Stack.Calls[0].SrcName + \":\" + strconv.Itoa(gr.Stack.Calls[0].Line)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Add some extra info in some cases.\n\t\t\t\t\tif wd.State == \"sleep\" { //nolint:goconst\n\t\t\t\t\t\twd.ExtraInfo = gr.SleepString()\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak goroutines\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Summarize and add to list.\n\t\tswitch wd.State {\n\t\tcase \"idle\", \"runnable\", \"running\", \"syscall\",\n\t\t\t\"waiting\", \"dead\", \"enqueue\", \"copystack\":\n\t\t\twi.Running++\n\t\tcase \"chan send\", \"chan receive\", \"select\", \"IO wait\",\n\t\t\t\"panicwait\", \"semacquire\", \"semarelease\", \"sleep\",\n\t\t\t\"sync.Mutex.Lock\":\n\t\t\twi.Waiting++\n\t\tcase \"\":\n\t\t\tif w.workerMgr != nil {\n\t\t\t\twi.Waiting++\n\t\t\t\twd.State = \"scheduled\"\n\t\t\t\twd.ExtraInfo = w.workerMgr.Status()\n\t\t\t} else {\n\t\t\t\twi.Missing++\n\t\t\t\twd.State = \"missing\"\n\t\t\t}\n\t\tdefault:\n\t\t\twi.Other++\n\t\t}\n\n\t\twi.Workers = append(wi.Workers, wd)\n\t}\n\n\t// Sort and return.\n\twi.clean()\n\treturn wi, nil\n}\n\n// Format formats the worker information as a readable table.\nfunc (wi *WorkerInfo) Format() string {\n\tbuf := bytes.NewBuffer(nil)\n\n\t// Add summary.\n\tbuf.WriteString(fmt.Sprintf(\n\t\t\"%d Workers: %d running, %d waiting\\n\\n\",\n\t\tlen(wi.Workers),\n\t\twi.Running,\n\t\twi.Waiting,\n\t))\n\n\t// Build table.\n\ttabWriter := tabwriter.NewWriter(buf, 4, 4, 3, ' ', 0)\n\t_, _ = fmt.Fprintf(tabWriter, \"#\\tState\\tModule\\tName\\tWorker Func\\tCurrent Line\\tExtra Info\\n\")\n\n\tfor _, wd := range wi.Workers {\n\t\t_, _ = fmt.Fprintf(tabWriter,\n\t\t\t\"%d\\t%s\\t%s\\t%s\\t%s\\t%s\\t%s\\n\",\n\t\t\twd.Count,\n\t\t\twd.State,\n\t\t\twd.Mgr,\n\t\t\twd.Name,\n\t\t\twd.Func,\n\t\t\twd.CurrentLine,\n\t\t\twd.ExtraInfo,\n\t\t)\n\t}\n\t_ = tabWriter.Flush()\n\n\treturn buf.String()\n}\n\nfunc getFuncName(fn func(w *WorkerCtx) error) string {\n\tname := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()\n\treturn strings.TrimSuffix(name, \"-fm\")\n}\n\nfunc fullStack() []byte {\n\tbuf := make([]byte, 8096)\n\tfor {\n\t\tn := runtime.Stack(buf, true)\n\t\tif n < len(buf) {\n\t\t\treturn buf[:n]\n\t\t}\n\t\tbuf = make([]byte, 2*len(buf))\n\t}\n}\n\n// MergeWorkerInfo merges multiple worker infos into one.\nfunc MergeWorkerInfo(infos ...*WorkerInfo) *WorkerInfo {\n\t// Calculate total registered workers.\n\tvar totalWorkers int\n\tfor _, status := range infos {\n\t\ttotalWorkers += len(status.Workers)\n\t}\n\n\t// Merge all worker infos.\n\twi := &WorkerInfo{\n\t\tWorkers: make([]*WorkerInfoDetail, 0, totalWorkers),\n\t}\n\tfor _, info := range infos {\n\t\twi.Running += info.Running\n\t\twi.Waiting += info.Waiting\n\t\twi.Other += info.Other\n\t\twi.Missing += info.Missing\n\t\twi.Workers = append(wi.Workers, info.Workers...)\n\t}\n\n\t// Sort and return.\n\twi.clean()\n\treturn wi\n}\n\nfunc (wi *WorkerInfo) clean() {\n\t// Check if there is anything to do.\n\tif len(wi.Workers) <= 1 {\n\t\treturn\n\t}\n\n\t// Sort for deduplication.\n\tslices.SortFunc(wi.Workers, sortWorkerInfoDetail)\n\n\t// Count duplicate worker details.\n\tcurrent := wi.Workers[0]\n\tfor i := 1; i < len(wi.Workers); i++ {\n\t\tif workerDetailsAreEqual(current, wi.Workers[i]) {\n\t\t\tcurrent.Count++\n\t\t} else {\n\t\t\tcurrent = wi.Workers[i]\n\t\t}\n\t}\n\t// Deduplicate worker details.\n\twi.Workers = slices.CompactFunc(wi.Workers, workerDetailsAreEqual)\n\n\t// Sort for presentation.\n\tslices.SortFunc(wi.Workers, sortWorkerInfoDetailByCount)\n}\n\n// sortWorkerInfoDetail is a sort function to sort worker info details by their content.\nfunc sortWorkerInfoDetail(a, b *WorkerInfoDetail) int {\n\tswitch {\n\tcase a.State != b.State:\n\t\treturn strings.Compare(a.State, b.State)\n\tcase a.Mgr != b.Mgr:\n\t\treturn strings.Compare(a.Mgr, b.Mgr)\n\tcase a.Name != b.Name:\n\t\treturn strings.Compare(a.Name, b.Name)\n\tcase a.Func != b.Func:\n\t\treturn strings.Compare(a.Func, b.Func)\n\tcase a.CurrentLine != b.CurrentLine:\n\t\treturn strings.Compare(a.CurrentLine, b.CurrentLine)\n\tcase a.ExtraInfo != b.ExtraInfo:\n\t\treturn strings.Compare(a.ExtraInfo, b.ExtraInfo)\n\tcase a.Count != b.Count:\n\t\treturn b.Count - a.Count\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// sortWorkerInfoDetailByCount is a sort function to sort worker info details by their count and then by content.\nfunc sortWorkerInfoDetailByCount(a, b *WorkerInfoDetail) int {\n\tstateA, stateB := goroutineStateOrder(a.State), goroutineStateOrder(b.State)\n\tswitch {\n\tcase stateA != stateB:\n\t\treturn stateA - stateB\n\tcase a.State != b.State:\n\t\treturn strings.Compare(a.State, b.State)\n\tcase a.Count != b.Count:\n\t\treturn b.Count - a.Count\n\tcase a.Mgr != b.Mgr:\n\t\treturn strings.Compare(a.Mgr, b.Mgr)\n\tcase a.Name != b.Name:\n\t\treturn strings.Compare(a.Name, b.Name)\n\tcase a.Func != b.Func:\n\t\treturn strings.Compare(a.Func, b.Func)\n\tcase a.CurrentLine != b.CurrentLine:\n\t\treturn strings.Compare(a.CurrentLine, b.CurrentLine)\n\tcase a.ExtraInfo != b.ExtraInfo:\n\t\treturn strings.Compare(a.ExtraInfo, b.ExtraInfo)\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// workerDetailsAreEqual is a deduplication function for worker details.\nfunc workerDetailsAreEqual(a, b *WorkerInfoDetail) bool {\n\tswitch {\n\tcase a.State != b.State:\n\t\treturn false\n\tcase a.Mgr != b.Mgr:\n\t\treturn false\n\tcase a.Name != b.Name:\n\t\treturn false\n\tcase a.Func != b.Func:\n\t\treturn false\n\tcase a.CurrentLine != b.CurrentLine:\n\t\treturn false\n\tcase a.ExtraInfo != b.ExtraInfo:\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\n//nolint:goconst\nfunc goroutineStateOrder(state string) int {\n\tswitch state {\n\tcase \"runnable\", \"running\", \"syscall\":\n\t\treturn 0 // Active.\n\tcase \"idle\", \"waiting\", \"dead\", \"enqueue\", \"copystack\":\n\t\treturn 1 // Active-ish.\n\tcase \"semacquire\", \"semarelease\", \"sleep\", \"panicwait\", \"sync.Mutex.Lock\":\n\t\treturn 2 // Bad (practice) blocking.\n\tcase \"chan send\", \"chan receive\", \"select\":\n\t\treturn 3 // Potentially bad (practice), but normal blocking.\n\tcase \"IO wait\":\n\t\treturn 4 // Normal blocking.\n\tcase \"scheduled\":\n\t\treturn 5 // Not running.\n\tcase \"missing\", \"\":\n\t\treturn 6 // Warning of undetected workers.\n\tdefault:\n\t\treturn 9\n\t}\n}\n"
  },
  {
    "path": "service/mgr/worker_test.go",
    "content": "package mgr\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestWorkerInfo(t *testing.T) { //nolint:paralleltest\n\tmgr := New(\"test\")\n\tmgr.Go(\"test func one\", testFunc1)\n\tmgr.Go(\"test func two\", testFunc2)\n\tmgr.Go(\"test func three\", testFunc3)\n\tdefer mgr.Cancel()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tinfo, err := mgr.WorkerInfo(nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif info.Waiting != 3 {\n\t\tt.Errorf(\"expected three waiting workers\")\n\t}\n\n\tfmt.Printf(\"%+v\\n\", info)\n}\n\nfunc testFunc1(ctx *WorkerCtx) error {\n\tselect {\n\tcase <-time.After(1 * time.Second):\n\tcase <-ctx.Done():\n\t}\n\treturn nil\n}\n\nfunc testFunc2(ctx *WorkerCtx) error {\n\tselect {\n\tcase <-time.After(1 * time.Second):\n\tcase <-ctx.Done():\n\t}\n\treturn nil\n}\n\nfunc testFunc3(ctx *WorkerCtx) error {\n\tselect {\n\tcase <-time.After(1 * time.Second):\n\tcase <-ctx.Done():\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/mgr/workermgr.go",
    "content": "package mgr\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n)\n\n// WorkerMgr schedules a worker.\ntype WorkerMgr struct {\n\tmgr *Manager\n\tctx *WorkerCtx\n\n\t// Definition.\n\tname    string\n\tfn      func(w *WorkerCtx) error\n\terrorFn func(c *WorkerCtx, err error, panicInfo string)\n\n\t// Manual trigger.\n\trun chan struct{}\n\n\t// Actions.\n\tactionLock   sync.Mutex\n\tselectAction chan struct{}\n\tdelay        *workerMgrDelay\n\trepeat       *workerMgrRepeat\n\tkeepAlive    *workerMgrNoop\n}\n\ntype taskAction interface {\n\tWait() <-chan time.Time\n\tAck()\n}\n\n// Delay.\ntype workerMgrDelay struct {\n\ts     *WorkerMgr\n\ttimer *time.Timer\n}\n\nfunc (s *WorkerMgr) newDelay(duration time.Duration) *workerMgrDelay {\n\treturn &workerMgrDelay{\n\t\ts:     s,\n\t\ttimer: time.NewTimer(duration),\n\t}\n}\nfunc (sd *workerMgrDelay) Wait() <-chan time.Time { return sd.timer.C }\n\nfunc (sd *workerMgrDelay) Ack() {\n\tsd.s.actionLock.Lock()\n\tdefer sd.s.actionLock.Unlock()\n\n\t// Remove delay, as it can only fire once.\n\tsd.s.delay = nil\n\n\t// Reset repeat.\n\tsd.s.repeat.Reset()\n\n\t// Stop timer.\n\tsd.timer.Stop()\n}\n\nfunc (sd *workerMgrDelay) Stop() {\n\tif sd == nil {\n\t\treturn\n\t}\n\tsd.timer.Stop()\n}\n\n// Repeat.\ntype workerMgrRepeat struct {\n\tticker   *time.Ticker\n\tinterval time.Duration\n}\n\nfunc (s *WorkerMgr) newRepeat(interval time.Duration) *workerMgrRepeat {\n\treturn &workerMgrRepeat{\n\t\tticker:   time.NewTicker(interval),\n\t\tinterval: interval,\n\t}\n}\n\nfunc (sr *workerMgrRepeat) Wait() <-chan time.Time { return sr.ticker.C }\nfunc (sr *workerMgrRepeat) Ack()                   {}\n\nfunc (sr *workerMgrRepeat) Reset() {\n\tif sr == nil {\n\t\treturn\n\t}\n\tsr.ticker.Reset(sr.interval)\n}\n\nfunc (sr *workerMgrRepeat) Stop() {\n\tif sr == nil {\n\t\treturn\n\t}\n\tsr.ticker.Stop()\n}\n\n// Noop.\ntype workerMgrNoop struct{}\n\nfunc (sn *workerMgrNoop) Wait() <-chan time.Time { return nil }\nfunc (sn *workerMgrNoop) Ack()                   {}\n\n// NewWorkerMgr creates a new scheduler for the given worker function.\n// Errors and panic will only be logged by default.\n// If custom behavior is required, supply an errorFn.\n// If all scheduling has ended, the scheduler will end itself,\n// including all related workers, except if keep-alive is enabled.\nfunc (m *Manager) NewWorkerMgr(name string, fn func(w *WorkerCtx) error, errorFn func(c *WorkerCtx, err error, panicInfo string)) *WorkerMgr {\n\t// Create task context.\n\twCtx := &WorkerCtx{\n\t\tlogger: m.logger.With(\"worker\", name),\n\t}\n\twCtx.ctx, wCtx.cancelCtx = context.WithCancel(m.Ctx())\n\n\ts := &WorkerMgr{\n\t\tmgr:          m,\n\t\tctx:          wCtx,\n\t\tname:         name,\n\t\tfn:           fn,\n\t\terrorFn:      errorFn,\n\t\trun:          make(chan struct{}, 1),\n\t\tselectAction: make(chan struct{}, 1),\n\t}\n\twCtx.workerMgr = s\n\n\tgo s.taskMgr()\n\treturn s\n}\n\nfunc (s *WorkerMgr) taskMgr() {\n\ts.mgr.workerStart(s.ctx)\n\tdefer s.mgr.workerDone(s.ctx)\n\n\t// If the task manager ends, end all descendants too.\n\tdefer s.ctx.cancelCtx()\n\n\t// Timers and tickers.\n\tvar (\n\t\taction taskAction\n\t)\n\tdefer func() {\n\t\ts.delay.Stop()\n\t\ts.repeat.Stop()\n\t}()\n\n\t// Wait for the first action.\n\tselect {\n\tcase <-s.selectAction:\n\tcase <-s.ctx.Done():\n\t\treturn\n\t}\n\nmanage:\n\tfor {\n\t\t// Select action.\n\t\tfunc() {\n\t\t\ts.actionLock.Lock()\n\t\t\tdefer s.actionLock.Unlock()\n\n\t\t\tswitch {\n\t\t\tcase s.delay != nil:\n\t\t\t\taction = s.delay\n\t\t\tcase s.repeat != nil:\n\t\t\t\taction = s.repeat\n\t\t\tcase s.keepAlive != nil:\n\t\t\t\taction = s.keepAlive\n\t\t\tdefault:\n\t\t\t\taction = nil\n\t\t\t}\n\t\t}()\n\t\tif action == nil {\n\t\t\treturn\n\t\t}\n\n\t\t// Wait for trigger or action.\n\t\tselect {\n\t\tcase <-action.Wait():\n\t\t\taction.Ack()\n\t\t\t// Time-triggered execution.\n\t\tcase <-s.run:\n\t\t\t// Manually triggered execution.\n\t\tcase <-s.selectAction:\n\t\t\t// Re-select action.\n\t\t\tcontinue manage\n\t\tcase <-s.ctx.Done():\n\t\t\t// Abort!\n\t\t\treturn\n\t\t}\n\n\t\t// Run worker.\n\t\twCtx := &WorkerCtx{\n\t\t\tworkerMgr: s,\n\t\t\tlogger:    s.ctx.logger,\n\t\t}\n\t\t//nolint:fatcontext // Every run gets a new context.\n\t\twCtx.ctx, wCtx.cancelCtx = context.WithCancel(s.ctx.ctx)\n\t\tpanicInfo, err := s.mgr.runWorker(wCtx, s.fn)\n\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\t// Continue with scheduling.\n\t\tcase errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):\n\t\t\t// Worker was canceled, continue with scheduling.\n\t\t\t// A canceled context or exceeded deadline also means that the worker is finished.\n\n\t\tdefault:\n\t\t\t// Log error and return.\n\t\t\tif panicInfo != \"\" {\n\t\t\t\twCtx.Error(\n\t\t\t\t\t\"worker failed\",\n\t\t\t\t\t\"err\", err,\n\t\t\t\t\t\"file\", panicInfo,\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\twCtx.Error(\n\t\t\t\t\t\"worker failed\",\n\t\t\t\t\t\"err\", err,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Delegate error handling to the error function, otherwise just continue the scheduler.\n\t\t\t// The error handler can stop the scheduler if it wants to.\n\t\t\tif s.errorFn != nil {\n\t\t\t\ts.errorFn(s.ctx, err, panicInfo)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Status returns the current status of the worker manager.\nfunc (s *WorkerMgr) Status() string {\n\ts.actionLock.Lock()\n\tdefer s.actionLock.Unlock()\n\n\tswitch {\n\tcase s.delay != nil:\n\t\treturn \"delayed\"\n\tcase s.repeat != nil:\n\t\treturn \"repeated every \" + s.repeat.interval.String()\n\tcase s.keepAlive != nil:\n\t\treturn \"on demand\"\n\tdefault:\n\t\treturn \"created\"\n\t}\n}\n\n// Go executes the worker immediately.\n// If the worker is currently being executed,\n// the next execution will commence afterwards.\n// Calling Go() implies KeepAlive() if nothing else was specified yet.\nfunc (s *WorkerMgr) Go() {\n\ts.actionLock.Lock()\n\tdefer s.actionLock.Unlock()\n\n\t// Check if any action is already defined.\n\tswitch {\n\tcase s.delay != nil:\n\tcase s.repeat != nil:\n\tcase s.keepAlive != nil:\n\tdefault:\n\t\ts.keepAlive = &workerMgrNoop{}\n\t\ts.check()\n\t}\n\n\t// Reset repeat if set.\n\ts.repeat.Reset()\n\n\t// Stop delay if set.\n\ts.delay.Stop()\n\ts.delay = nil\n\n\t// Send run command\n\tselect {\n\tcase s.run <- struct{}{}:\n\tdefault:\n\t}\n}\n\n// Stop immediately stops the scheduler and all related workers.\nfunc (s *WorkerMgr) Stop() {\n\ts.ctx.cancelCtx()\n}\n\n// Delay will schedule the worker to run after the given duration.\n// If set, the repeat schedule will continue afterwards.\n// Disable the delay by passing 0.\nfunc (s *WorkerMgr) Delay(duration time.Duration) *WorkerMgr {\n\ts.actionLock.Lock()\n\tdefer s.actionLock.Unlock()\n\n\ts.delay.Stop()\n\ts.delay = nil\n\tif duration > 0 {\n\t\ts.delay = s.newDelay(duration)\n\t}\n\n\ts.check()\n\treturn s\n}\n\n// Repeat will repeatedly execute the worker using the given interval.\n// Disable repeating by passing 0.\nfunc (s *WorkerMgr) Repeat(interval time.Duration) *WorkerMgr {\n\ts.actionLock.Lock()\n\tdefer s.actionLock.Unlock()\n\n\ts.repeat.Stop()\n\ts.repeat = nil\n\tif interval > 0 {\n\t\ts.repeat = s.newRepeat(interval)\n\t}\n\n\ts.check()\n\treturn s\n}\n\n// KeepAlive instructs the scheduler to not self-destruct,\n// even if all scheduled work is complete.\nfunc (s *WorkerMgr) KeepAlive() *WorkerMgr {\n\ts.actionLock.Lock()\n\tdefer s.actionLock.Unlock()\n\n\ts.keepAlive = &workerMgrNoop{}\n\n\ts.check()\n\treturn s\n}\n\nfunc (s *WorkerMgr) check() {\n\tselect {\n\tcase s.selectAction <- struct{}{}:\n\tdefault:\n\t}\n}\n"
  },
  {
    "path": "service/mgr/workermgr_test.go",
    "content": "package mgr\n\nimport (\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestWorkerMgrDelay(t *testing.T) {\n\tt.Parallel()\n\n\tm := New(\"DelayTest\")\n\n\tvalue := atomic.Bool{}\n\tvalue.Store(false)\n\n\t// Create a task that will after 1 second.\n\tm.NewWorkerMgr(\"test\", func(w *WorkerCtx) error {\n\t\tvalue.Store(true)\n\t\treturn nil\n\t}, nil).Delay(1 * time.Second)\n\n\t// Check if value is set after 1 second and not before or after.\n\titerations := 0\n\tfor !value.Load() {\n\t\titerations++\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n\n\t// 5% difference is acceptable since time.Sleep can't be perfect and it may very on different computers.\n\tif iterations < 95 || iterations > 105 {\n\t\tt.Errorf(\"WorkerMgr did not delay for a whole second it=%d\", iterations)\n\t}\n}\n\nfunc TestWorkerMgrRepeat(t *testing.T) {\n\tt.Parallel()\n\n\tm := New(\"RepeatTest\")\n\n\tvalue := atomic.Bool{}\n\tvalue.Store(false)\n\n\t// Create a task that should repeat every 100 milliseconds.\n\tm.NewWorkerMgr(\"test\", func(w *WorkerCtx) error {\n\t\tvalue.Store(true)\n\t\treturn nil\n\t}, nil).Repeat(100 * time.Millisecond)\n\n\t// Check 10 consecutive runs they should be delayed for around 100 milliseconds each.\n\tfor range 10 {\n\t\titerations := 0\n\t\tfor !value.Load() {\n\t\t\titerations++\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\n\t\t// 10% difference is acceptable at this scale since time.Sleep can't be perfect and it may very on different computers.\n\t\tif iterations < 9 || iterations > 11 {\n\t\t\tt.Errorf(\"Worker was not delayed for a 100 milliseconds it=%d\", iterations)\n\t\t\treturn\n\t\t}\n\t\t// Reset value\n\t\tvalue.Store(false)\n\t}\n}\n\nfunc TestWorkerMgrDelayAndRepeat(t *testing.T) { //nolint:dupl\n\tt.Parallel()\n\n\tm := New(\"DelayAndRepeatTest\")\n\n\tvalue := atomic.Bool{}\n\tvalue.Store(false)\n\n\t// Create a task that should delay for 1 second and then repeat every 100 milliseconds.\n\tm.NewWorkerMgr(\"test\", func(w *WorkerCtx) error {\n\t\tvalue.Store(true)\n\t\treturn nil\n\t}, nil).Delay(1 * time.Second).Repeat(100 * time.Millisecond)\n\n\titerations := 0\n\tfor !value.Load() {\n\t\titerations++\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n\n\t// 5% difference is acceptable since time.Sleep can't be perfect and it may very on different computers.\n\tif iterations < 95 || iterations > 105 {\n\t\tt.Errorf(\"WorkerMgr did not delay for a whole second it=%d\", iterations)\n\t}\n\n\t// Reset value\n\tvalue.Store(false)\n\n\t// Check 10 consecutive runs they should be delayed for around 100 milliseconds each.\n\tfor range 10 {\n\t\titerations = 0\n\t\tfor !value.Load() {\n\t\t\titerations++\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\n\t\t// 10% difference is acceptable at this scale since time.Sleep can't be perfect and it may very on different computers.\n\t\tif iterations < 9 || iterations > 11 {\n\t\t\tt.Errorf(\"Worker was not delayed for a 100 milliseconds it=%d\", iterations)\n\t\t\treturn\n\t\t}\n\t\t// Reset value\n\t\tvalue.Store(false)\n\t}\n}\n\nfunc TestWorkerMgrRepeatAndDelay(t *testing.T) { //nolint:dupl\n\tt.Parallel()\n\n\tm := New(\"RepeatAndDelayTest\")\n\n\tvalue := atomic.Bool{}\n\tvalue.Store(false)\n\n\t// Create a task that should delay for 1 second and then repeat every 100 milliseconds but with reverse command order.\n\tm.NewWorkerMgr(\"test\", func(w *WorkerCtx) error {\n\t\tvalue.Store(true)\n\t\treturn nil\n\t}, nil).Repeat(100 * time.Millisecond).Delay(1 * time.Second)\n\n\titerations := 0\n\tfor !value.Load() {\n\t\titerations++\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n\n\t// 5% difference is acceptable since time.Sleep can't be perfect and it may very on different computers.\n\tif iterations < 95 || iterations > 105 {\n\t\tt.Errorf(\"WorkerMgr did not delay for a whole second it=%d\", iterations)\n\t}\n\t// Reset value\n\tvalue.Store(false)\n\n\t// Check 10 consecutive runs they should be delayed for around 100 milliseconds each.\n\tfor range 10 {\n\t\titerations := 0\n\t\tfor !value.Load() {\n\t\t\titerations++\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\n\t\t// 10% difference is acceptable at this scale since time.Sleep can't be perfect and it may very on different computers.\n\t\tif iterations < 9 || iterations > 11 {\n\t\t\tt.Errorf(\"Worker was not delayed for a 100 milliseconds it=%d\", iterations)\n\t\t\treturn\n\t\t}\n\t\t// Reset value\n\t\tvalue.Store(false)\n\t}\n}\n"
  },
  {
    "path": "service/nameserver/config.go",
    "content": "package nameserver\n\nimport (\n\t\"flag\"\n\t\"runtime\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/core\"\n)\n\n// CfgDefaultNameserverAddressKey is the config key for the listen address..\nconst CfgDefaultNameserverAddressKey = \"dns/listenAddress\"\n\nvar (\n\tdefaultNameserverAddress = \"localhost:53\"\n\tnameserverAddress        string\n\tnameserverAddressConfig  config.StringOption\n\n\tnetworkServiceMode config.BoolOption\n)\n\nfunc init() {\n\t// On Windows, packets are redirected to the same interface.\n\tif runtime.GOOS == \"windows\" {\n\t\tdefaultNameserverAddress = \"0.0.0.0:53\"\n\t}\n\n\tflag.StringVar(\n\t\t&nameserverAddress,\n\t\t\"nameserver-address\",\n\t\tdefaultNameserverAddress,\n\t\t\"set default nameserver address; configuration is stronger\",\n\t)\n}\n\nfunc registerConfig() error {\n\terr := config.Register(&config.Option{\n\t\tName:            \"Internal DNS Server Listen Address\",\n\t\tKey:             CfgDefaultNameserverAddressKey,\n\t\tDescription:     \"Defines the IP address and port on which the internal DNS Server listens.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelDeveloper,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tDefaultValue:    nameserverAddress,\n\t\tValidationRegex: \"^(localhost|[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}|\\\\[[:0-9A-Fa-f]+\\\\]):[0-9]{1,5}$\",\n\t\tRequiresRestart: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: 514,\n\t\t\tconfig.CategoryAnnotation:     \"Development\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tnameserverAddressConfig = config.GetAsString(CfgDefaultNameserverAddressKey, nameserverAddress)\n\n\tnetworkServiceMode = config.Concurrent.GetAsBool(core.CfgNetworkServiceKey, false)\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/nameserver/conflict.go",
    "content": "package nameserver\n\nimport (\n\t\"net\"\n\t\"os\"\n\n\tprocessInfo \"github.com/shirou/gopsutil/process\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/state\"\n)\n\nvar commonResolverIPs = []net.IP{\n\tnet.IPv4zero,\n\tnet.IPv4(127, 0, 0, 1),  // default\n\tnet.IPv4(127, 0, 0, 53), // some resolvers on Linux\n\tnet.IPv6zero,\n\tnet.IPv6loopback,\n}\n\nfunc findConflictingProcess(ip net.IP, port uint16) (conflictingProcess *processInfo.Process) {\n\t// Evaluate which IPs to check.\n\tvar ipsToCheck []net.IP\n\tif ip.Equal(net.IPv4zero) || ip.Equal(net.IPv6zero) {\n\t\tipsToCheck = commonResolverIPs\n\t} else {\n\t\tipsToCheck = []net.IP{ip}\n\t}\n\n\t// Find the conflicting process.\n\tvar err error\n\tfor _, resolverIP := range ipsToCheck {\n\t\tconflictingProcess, err = getListeningProcess(resolverIP, port)\n\t\tswitch {\n\t\tcase err != nil:\n\t\t\t// Log the error and let the worker try again.\n\t\t\tlog.Warningf(\"nameserver: failed to find conflicting service: %s\", err)\n\t\tcase conflictingProcess != nil:\n\t\t\t// Conflicting service found.\n\t\t\treturn conflictingProcess\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc getListeningProcess(resolverIP net.IP, resolverPort uint16) (*processInfo.Process, error) {\n\tpid, _, err := state.Lookup(&packet.Info{\n\t\tInbound:  true,\n\t\tVersion:  0, // auto-detect\n\t\tProtocol: packet.UDP,\n\t\tSrc:      nil, // do not record direction\n\t\tSrcPort:  0,   // do not record direction\n\t\tDst:      resolverIP,\n\t\tDstPort:  resolverPort,\n\t}, true)\n\tif err != nil {\n\t\t// there may be nothing listening on :53\n\t\treturn nil, nil //nolint:nilerr // Treat lookup error as \"not found\".\n\t}\n\n\t// Ignore if it's us for some reason.\n\tif pid == os.Getpid() {\n\t\treturn nil, nil\n\t}\n\n\tproc, err := processInfo.NewProcess(int32(pid))\n\tif err != nil {\n\t\t// Process may have disappeared already.\n\t\treturn nil, err\n\t}\n\n\treturn proc, nil\n}\n"
  },
  {
    "path": "service/nameserver/failing.go",
    "content": "package nameserver\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\ntype failingQuery struct {\n\t// Until specifies until when the query should be regarded as failing.\n\tUntil time.Time\n\n\t// Keep specifies until when the failing status shall be kept.\n\tKeep time.Time\n\n\t// Times specifies how often this query failed.\n\tTimes int\n\n\t// Err holds the error the query failed with.\n\tErr error\n}\n\nconst (\n\tfailingDelay             = 900 * time.Millisecond\n\tfailingBaseDuration      = 900 * time.Millisecond\n\tfailingFactorDuration    = 500 * time.Millisecond\n\tfailingMaxDuration       = 30 * time.Second\n\tfailingKeepAddedDuration = 10 * time.Second\n)\n\nvar (\n\tfailingQueries                   = make(map[string]*failingQuery)\n\tfailingQueriesLock               sync.RWMutex\n\tfailingQueriesNetworkChangedFlag = netenv.GetNetworkChangedFlag()\n)\n\nfunc checkIfQueryIsFailing(q *resolver.Query) (failingUntil *time.Time, failingErr error) {\n\t// If the network changed, reset the failed queries.\n\tif failingQueriesNetworkChangedFlag.IsSet() {\n\t\tfailingQueriesNetworkChangedFlag.Refresh()\n\n\t\tfailingQueriesLock.Lock()\n\t\tdefer failingQueriesLock.Unlock()\n\n\t\t// Compiler optimized map reset.\n\t\tfor key := range failingQueries {\n\t\t\tdelete(failingQueries, key)\n\t\t}\n\n\t\treturn nil, nil\n\t}\n\n\tfailingQueriesLock.RLock()\n\tdefer failingQueriesLock.RUnlock()\n\n\t// Quickly return if map is empty.\n\tif len(failingQueries) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Check if query failed recently.\n\tfailing, ok := failingQueries[q.ID()]\n\tif !ok {\n\t\treturn nil, nil\n\t}\n\n\t// Check if failing query should still be regarded as failing.\n\tif time.Now().After(failing.Until) {\n\t\treturn nil, nil\n\t}\n\n\t// Return failing error and until when it's valid.\n\treturn &failing.Until, failing.Err\n}\n\nfunc addFailingQuery(q *resolver.Query, err error) {\n\t// Check if we were given an error.\n\tif err == nil {\n\t\treturn\n\t}\n\n\t// Exclude reverse and mDNS queries, as they fail _often_ and are usually not\n\t// retried quickly.\n\t// if strings.HasSuffix(q.FQDN, \".in-addr.arpa.\") ||\n\t// \tstrings.HasSuffix(q.FQDN, \".ip6.arpa.\") ||\n\t// \tstrings.HasSuffix(q.FQDN, \".local.\") {\n\t// \treturn\n\t// }\n\n\tfailingQueriesLock.Lock()\n\tdefer failingQueriesLock.Unlock()\n\n\tfailing, ok := failingQueries[q.ID()]\n\tif !ok {\n\t\tfailing = &failingQuery{Err: err}\n\t\tfailingQueries[q.ID()] = failing\n\t}\n\n\t// Calculate fail duration.\n\t// Initial fail duration will be at 900ms, perfect for a normal retry after 1s,\n\t// but not any earlier.\n\tfailDuration := failingBaseDuration + time.Duration(failing.Times)*failingFactorDuration\n\tif failDuration > failingMaxDuration {\n\t\tfailDuration = failingMaxDuration\n\t}\n\n\t// Update failing query.\n\tfailing.Times++\n\tfailing.Until = time.Now().Add(failDuration)\n\tfailing.Keep = failing.Until.Add(failingKeepAddedDuration)\n}\n\nfunc cleanFailingQueries(maxRemove, maxMiss int) {\n\tfailingQueriesLock.Lock()\n\tdefer failingQueriesLock.Unlock()\n\n\tnow := time.Now()\n\tfor key, failing := range failingQueries {\n\t\tif now.After(failing.Keep) {\n\t\t\tdelete(failingQueries, key)\n\n\t\t\tmaxRemove--\n\t\t\tif maxRemove == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tmaxMiss--\n\t\t\tif maxMiss == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/nameserver/metrics.go",
    "content": "package nameserver\n\nimport (\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/metrics\"\n)\n\nvar (\n\trequestsHistogram    *metrics.Histogram\n\ttotalHandledRequests *metrics.Counter\n)\n\nfunc registerMetrics() (err error) {\n\trequestsHistogram, err = metrics.NewHistogram(\n\t\t\"nameserver/request/duration/seconds\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tPermission:     api.PermitUser,\n\t\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttotalHandledRequests, err = metrics.NewCounter(\n\t\t\"nameserver/request/total\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tInternalID:     \"handled_dns_requests\",\n\t\t\tPermission:     api.PermitUser,\n\t\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\t\tPersist:        true,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/nameserver/module.go",
    "content": "package nameserver\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/compat\"\n\t\"github.com/safing/portmaster/service/firewall\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\ntype NameServer struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tstates *mgr.StateMgr\n}\n\nfunc (ns *NameServer) Manager() *mgr.Manager {\n\treturn ns.mgr\n}\n\nfunc (ns *NameServer) States() *mgr.StateMgr {\n\treturn ns.states\n}\n\nfunc (ns *NameServer) Start() error {\n\treturn start()\n}\n\nfunc (ns *NameServer) Stop() error {\n\treturn stop()\n}\n\nvar (\n\tstopListeners     bool\n\tstopListener1     func() error\n\tstopListener2     func() error\n\tstopListenersLock sync.Mutex\n\n\teventIDConflictingService = \"nameserver:conflicting-service\"\n\teventIDListenerFailed     = \"nameserver:listener-failed\"\n)\n\nfunc prep() error {\n\treturn registerConfig()\n}\n\nfunc start() error {\n\tif err := registerMetrics(); err != nil {\n\t\treturn err\n\t}\n\n\t// Get listen addresses.\n\tip1, ip2, port, err := getListenAddresses(nameserverAddressConfig())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse nameserver listen address: %w\", err)\n\t}\n\n\t// Tell the compat module where we are listening.\n\tcompat.SetNameserverListenIP(ip1)\n\n\t// Get own hostname.\n\thostname, err = os.Hostname()\n\tif err != nil {\n\t\tlog.Warningf(\"nameserver: failed to get hostname: %s\", err)\n\t}\n\thostname += \".\"\n\n\t// Start listener(s).\n\tif ip2 == nil {\n\t\t// Start a single listener.\n\t\tstartListener(ip1, port, true)\n\n\t\t// Set nameserver matcher in firewall to fast-track dns queries.\n\t\tif ip1.Equal(net.IPv4zero) || ip1.Equal(net.IPv6zero) {\n\t\t\t// Fast track dns queries destined for any of the local IPs.\n\t\t\treturn firewall.SetNameserverIPMatcher(func(ip net.IP) bool {\n\t\t\t\tdstIsMe, err := netenv.IsMyIP(ip)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warningf(\"nameserver: failed to check if IP %s is local: %s\", ip, err)\n\t\t\t\t}\n\t\t\t\treturn dstIsMe\n\t\t\t})\n\t\t}\n\t\treturn firewall.SetNameserverIPMatcher(func(ip net.IP) bool {\n\t\t\treturn ip.Equal(ip1)\n\t\t})\n\t}\n\n\t// Dual listener.\n\tstartListener(ip1, port, true)\n\tstartListener(ip2, port, false)\n\n\t// Fast track dns queries destined for one of the listener IPs.\n\treturn firewall.SetNameserverIPMatcher(func(ip net.IP) bool {\n\t\treturn ip.Equal(ip1) || ip.Equal(ip2)\n\t})\n}\n\nfunc startListener(ip net.IP, port uint16, first bool) {\n\t// Start DNS server as service worker.\n\tmodule.mgr.Go(\"dns resolver\", func(ctx *mgr.WorkerCtx) error {\n\t\t// Create DNS server.\n\t\tdnsServer := &dns.Server{\n\t\t\tAddr: net.JoinHostPort(\n\t\t\t\tip.String(),\n\t\t\t\tstrconv.Itoa(int(port)),\n\t\t\t),\n\t\t\tNet:     \"udp\",\n\t\t\tHandler: dns.HandlerFunc(handleRequestAsWorker),\n\t\t}\n\n\t\t// Register stop function.\n\t\tfunc() {\n\t\t\tstopListenersLock.Lock()\n\t\t\tdefer stopListenersLock.Unlock()\n\n\t\t\t// Check if we should stop\n\t\t\tif stopListeners {\n\t\t\t\t_ = dnsServer.Shutdown()\n\t\t\t\tdnsServer = nil\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Register stop function.\n\t\t\tif first {\n\t\t\t\tstopListener1 = dnsServer.Shutdown\n\t\t\t} else {\n\t\t\t\tstopListener2 = dnsServer.Shutdown\n\t\t\t}\n\t\t}()\n\n\t\t// Check if we should stop.\n\t\tif dnsServer == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Resolve generic listener error, if primary listener.\n\t\tif first {\n\t\t\tmodule.states.Remove(eventIDListenerFailed)\n\t\t}\n\n\t\t// Start listening.\n\t\tlog.Infof(\"nameserver: starting to listen on %s\", dnsServer.Addr)\n\t\terr := dnsServer.ListenAndServe()\n\t\tif err != nil {\n\t\t\t// Stop worker without error if we are shutting down.\n\t\t\tif module.mgr.IsDone() {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tlog.Warningf(\"nameserver: failed to listen on %s: %s\", dnsServer.Addr, err)\n\t\t\thandleListenError(err, ip, port, first)\n\t\t}\n\t\treturn err\n\t})\n}\n\nfunc handleListenError(err error, ip net.IP, port uint16, primaryListener bool) {\n\tvar n *notifications.Notification\n\n\t// Create suffix for secondary listener\n\tvar secondaryEventIDSuffix string\n\tif !primaryListener {\n\t\tsecondaryEventIDSuffix = \"-secondary\"\n\t}\n\n\t// Find a conflicting service.\n\tcfProcess := findConflictingProcess(ip, port)\n\tif cfProcess != nil {\n\t\t// Report the conflicting process.\n\n\t\t// Build conflicting process description.\n\t\tvar cfDescription string\n\t\tcfName, err := cfProcess.Name()\n\t\tif err == nil && cfName != \"\" {\n\t\t\tcfDescription = cfName\n\t\t}\n\t\tcfExe, err := cfProcess.Exe()\n\t\tif err == nil && cfDescription != \"\" {\n\t\t\tif cfDescription != \"\" {\n\t\t\t\tcfDescription += \" (\" + cfExe + \")\"\n\t\t\t} else {\n\t\t\t\tcfDescription = cfName\n\t\t\t}\n\t\t}\n\n\t\t// Notify user about conflicting service.\n\t\tn = notifications.Notify(&notifications.Notification{\n\t\t\tEventID: eventIDConflictingService + secondaryEventIDSuffix,\n\t\t\tType:    notifications.Error,\n\t\t\tTitle:   \"Conflicting DNS Software\",\n\t\t\tMessage: \"Restart Portmaster after you have deactivated or properly configured the conflicting software: \" +\n\t\t\t\tcfDescription,\n\t\t\tShowOnSystem: true,\n\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t{\n\t\t\t\t\tText:    \"Open Docs\",\n\t\t\t\t\tType:    notifications.ActionTypeOpenURL,\n\t\t\t\t\tPayload: \"https://docs.safing.io/portmaster/install/status/software-compatibility\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t} else {\n\t\t// If no conflict is found, report the error directly.\n\t\tn = notifications.Notify(&notifications.Notification{\n\t\t\tEventID: eventIDListenerFailed + secondaryEventIDSuffix,\n\t\t\tType:    notifications.Error,\n\t\t\tTitle:   \"Secure DNS Error\",\n\t\t\tMessage: fmt.Sprintf(\n\t\t\t\t\"The internal DNS server failed. Restart Portmaster to try again. Error: %s\",\n\t\t\t\terr,\n\t\t\t),\n\t\t\tShowOnSystem: true,\n\t\t})\n\t}\n\n\t// Attach error to module, if primary listener.\n\tif primaryListener {\n\t\tn.SyncWithState(module.states)\n\t}\n}\n\nfunc stop() error {\n\tstopListenersLock.Lock()\n\tdefer stopListenersLock.Unlock()\n\n\t// Stop listeners.\n\tstopListeners = true\n\tif stopListener1 != nil {\n\t\tif err := stopListener1(); err != nil {\n\t\t\tlog.Warningf(\"nameserver: failed to stop listener1: %s\", err)\n\t\t}\n\t}\n\tif stopListener2 != nil {\n\t\tif err := stopListener2(); err != nil {\n\t\t\tlog.Warningf(\"nameserver: failed to stop listener2: %s\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc getListenAddresses(listenAddress string) (ip1, ip2 net.IP, port uint16, err error) {\n\t// Split host and port.\n\tipString, portString, err := net.SplitHostPort(listenAddress)\n\tif err != nil {\n\t\treturn nil, nil, 0, fmt.Errorf(\n\t\t\t\"failed to parse address %s: %w\",\n\t\t\tlistenAddress,\n\t\t\terr,\n\t\t)\n\t}\n\n\t// Parse the IP address. If the want to listen on localhost, we need to\n\t// listen separately for IPv4 and IPv6.\n\tif ipString == \"localhost\" {\n\t\tip1 = net.IPv4(127, 0, 0, 17)\n\t\tif netenv.IPv6Enabled() {\n\t\t\tip2 = net.IPv6loopback\n\t\t} else {\n\t\t\tlog.Warningf(\"nameserver: no IPv6 stack detected, disabling IPv6 nameserver listener\")\n\t\t}\n\t} else {\n\t\tip1 = net.ParseIP(ipString)\n\t\tif ip1 == nil {\n\t\t\treturn nil, nil, 0, fmt.Errorf(\n\t\t\t\t\"failed to parse IP %s from %s\",\n\t\t\t\tipString,\n\t\t\t\tlistenAddress,\n\t\t\t)\n\t\t}\n\t}\n\n\t// Parse the port.\n\tport64, err := strconv.ParseUint(portString, 10, 16)\n\tif err != nil {\n\t\treturn nil, nil, 0, fmt.Errorf(\n\t\t\t\"failed to parse port %s from %s: %w\",\n\t\t\tportString,\n\t\t\tlistenAddress,\n\t\t\terr,\n\t\t)\n\t}\n\n\treturn ip1, ip2, uint16(port64), nil\n}\n\nvar (\n\tmodule     *NameServer\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new NameServer module.\nfunc New(instance instance) (*NameServer, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"NameServer\")\n\tmodule = &NameServer{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tstates: mgr.NewStateMgr(m),\n\t}\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "service/nameserver/nameserver.go",
    "content": "package nameserver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/firewall\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/nameserver/nsutil\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\nvar hostname string\n\nconst internalError = \"internal error: \"\n\nfunc handleRequestAsWorker(w dns.ResponseWriter, query *dns.Msg) {\n\terr := module.mgr.Do(\"handle dns request\", func(wc *mgr.WorkerCtx) error {\n\t\treturn handleRequest(wc.Ctx(), w, query)\n\t})\n\tif err != nil {\n\t\tlog.Warningf(\"nameserver: failed to handle dns request: %s\", err)\n\t}\n}\n\nfunc handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg) error { //nolint:maintidx // TODO\n\t// Record metrics.\n\tstartTime := time.Now()\n\tdefer requestsHistogram.UpdateDuration(startTime)\n\n\t// Check Question, only process the first, that's how everyone does it.\n\tvar originalQuestion dns.Question\n\tswitch len(request.Question) {\n\tcase 0:\n\t\tlog.Warning(\"nameserver: received query without question\")\n\t\treturn sendResponse(ctx, w, request, nsutil.Refused(\"no question provided\"))\n\tcase 1:\n\t\toriginalQuestion = request.Question[0]\n\tdefault:\n\t\tlog.Warningf(\n\t\t\t\"nameserver: received query with multiple questions, first is %s.%s\",\n\t\t\trequest.Question[0].Name,\n\t\t\tdns.Type(request.Question[0].Qtype),\n\t\t)\n\t\treturn sendResponse(ctx, w, request, nsutil.Refused(\"multiple question provided\"))\n\t}\n\n\t// Check the Query Class.\n\tif originalQuestion.Qclass != dns.ClassINET {\n\t\t// We only serve IN records.\n\t\tlog.Warningf(\"nameserver: received unsupported qclass %d question for %s\", originalQuestion.Qclass, originalQuestion.Name)\n\t\treturn sendResponse(ctx, w, request, nsutil.Refused(\"unsupported qclass\"))\n\t}\n\n\t// Check if we are handling a non-standard query name.\n\tvar nonStandardQuestionFormat bool\n\tlowerCaseQuestion := strings.ToLower(originalQuestion.Name)\n\tif lowerCaseQuestion != originalQuestion.Name {\n\t\tnonStandardQuestionFormat = true\n\t}\n\n\t// Create query for the resolver.\n\tq := &resolver.Query{\n\t\tFQDN:  lowerCaseQuestion,\n\t\tQType: dns.Type(originalQuestion.Qtype),\n\t}\n\n\t// Get remote address of request.\n\tremoteAddr, ok := w.RemoteAddr().(*net.UDPAddr)\n\tif !ok {\n\t\tlog.Warningf(\"nameserver: failed to get remote address of dns query: is type %+T\", w.RemoteAddr())\n\t\treturn sendResponse(ctx, w, request, nsutil.Refused(\"unsupported transport\"))\n\t}\n\n\t// Start context tracer for context-aware logging.\n\tctx, tracer := log.AddTracer(ctx)\n\tdefer tracer.Submit()\n\ttracer.Tracef(\"nameserver: handling new request for %s from %s:%d\", q.ID(), remoteAddr.IP, remoteAddr.Port)\n\n\t// Count request.\n\ttotalHandledRequests.Inc()\n\n\t// Setup quick reply function.\n\treply := func(responder nsutil.Responder, rrProviders ...nsutil.RRProvider) error {\n\t\terr := sendResponse(ctx, w, request, responder, rrProviders...)\n\t\t// Log error here instead of returning it in order to keep the context.\n\t\tif err != nil {\n\t\t\ttracer.Errorf(\"nameserver: %s\", err)\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Handle request for localhost and the hostname.\n\tif strings.HasSuffix(q.FQDN, \"localhost.\") || q.FQDN == hostname {\n\t\ttracer.Tracef(\"nameserver: returning localhost records\")\n\t\treturn reply(nsutil.Localhost())\n\t}\n\n\t// Validate domain name.\n\tif !netutils.IsValidFqdn(q.FQDN) {\n\t\ttracer.Debugf(\"nameserver: domain name %s is invalid, refusing\", q.FQDN)\n\t\treturn reply(nsutil.Refused(\"invalid domain\"))\n\t}\n\n\t// Get public suffix after validation.\n\tq.InitPublicSuffixData()\n\n\t// Check if query is failing.\n\t// Some software retries failing queries excessively. This might not be a\n\t// problem normally, but handling a request is pretty expensive for the\n\t// Portmaster, as it has to find out who sent the query. If we know the query\n\t// will fail with a very high probability, it is beneficial to just kill the\n\t// query for some time before doing any expensive work.\n\tdefer cleanFailingQueries(10, 3)\n\tfailingUntil, failingErr := checkIfQueryIsFailing(q)\n\tif failingErr != nil {\n\t\tremainingFailingDuration := time.Until(*failingUntil)\n\t\ttracer.Debugf(\"nameserver: returning previous error for %s: %s\", q.ID(), failingErr)\n\n\t\t// Delay the response a bit in order to mitigate request flooding.\n\t\tif remainingFailingDuration < failingDelay {\n\t\t\t// Delay for remainind fail duration.\n\t\t\ttracer.Tracef(\"nameserver: delaying failing lookup until end of fail duration for %s\", remainingFailingDuration.Round(time.Millisecond))\n\t\t\ttime.Sleep(remainingFailingDuration)\n\t\t\treturn reply(nsutil.ServerFailure(\n\t\t\t\tinternalError+failingErr.Error(),\n\t\t\t\t\"delayed failing query to mitigate request flooding\",\n\t\t\t))\n\t\t}\n\t\t// Delay for default duration.\n\t\ttracer.Tracef(\"nameserver: delaying failing lookup for %s\", failingDelay.Round(time.Millisecond))\n\t\ttime.Sleep(failingDelay)\n\t\treturn reply(nsutil.ServerFailure(\n\t\t\tinternalError+failingErr.Error(),\n\t\t\t\"delayed failing query to mitigate request flooding\",\n\t\t\tfmt.Sprintf(\"error is cached for another %s\", remainingFailingDuration.Round(time.Millisecond)),\n\t\t))\n\t}\n\n\t// Check if the request is local.\n\tlocal, err := netenv.IsMyIP(remoteAddr.IP)\n\tif err != nil {\n\t\ttracer.Warningf(\"nameserver: failed to check if request for %s is local: %s\", q.ID(), err)\n\t\treturn reply(nsutil.ServerFailure(internalError + \" failed to check if request is local\"))\n\t}\n\n\t// Create connection ID for dns request.\n\tconnID := fmt.Sprintf(\n\t\t\"%s-%d-#%d-%s\",\n\t\tremoteAddr.IP,\n\t\tremoteAddr.Port,\n\t\trequest.Id,\n\t\tq.ID(),\n\t)\n\n\t// Get connection for this request. This identifies the process behind the request.\n\tvar conn *network.Connection\n\tswitch {\n\tcase local:\n\t\tconn = network.NewConnectionFromDNSRequest(ctx, q.FQDN, nil, connID, remoteAddr.IP, uint16(remoteAddr.Port))\n\n\tcase networkServiceMode():\n\t\tconn, err = network.NewConnectionFromExternalDNSRequest(ctx, q.FQDN, nil, connID, remoteAddr.IP)\n\t\tif err != nil {\n\t\t\ttracer.Warningf(\"nameserver: failed to get host/profile for request for %s%s: %s\", q.FQDN, q.QType, err)\n\t\t\treturn reply(nsutil.ServerFailure(internalError + \"failed to get profile\"))\n\t\t}\n\n\tdefault:\n\t\ttracer.Warningf(\"nameserver: external request from %s for %s%s, ignoring\", remoteAddr, q.FQDN, q.QType)\n\t\treturn reply(nsutil.Refused(\"external queries are not permitted\"))\n\t}\n\tconn.Lock()\n\tdefer conn.Unlock()\n\n\t// Create reference for the rrCache.\n\tvar rrCache *resolver.RRCache\n\n\t// Once we decided on the connection we might need to save it to the database,\n\t// so we defer that check for now.\n\tdefer func() {\n\t\t// Add metadata to connection.\n\t\tif rrCache != nil {\n\t\t\tconn.DNSContext = rrCache.ToDNSRequestContext()\n\t\t\tconn.Resolver = rrCache.Resolver\n\t\t\tconn.Entity.IPScope = rrCache.Resolver.IPScope\n\t\t} else {\n\t\t\t// Get resolvers for this query to determine the resolving scope.\n\t\t\tresolvers, _, _ := resolver.GetResolversInScope(ctx, q)\n\t\t\tif len(resolvers) > 0 {\n\t\t\t\tconn.Entity.IPScope = resolvers[0].Info.IPScope\n\t\t\t}\n\t\t}\n\n\t\tswitch conn.Verdict {\n\t\t// We immediately save blocked, dropped or failed verdicts so\n\t\t// they pop up in the UI.\n\t\tcase network.VerdictBlock, network.VerdictDrop, network.VerdictFailed, network.VerdictRerouteToNameserver, network.VerdictRerouteToTunnel:\n\t\t\tconn.Save()\n\n\t\t// For undecided or accepted connections we don't save them yet, because\n\t\t// that will happen later anyway.\n\t\tcase network.VerdictUndecided, network.VerdictAccept:\n\t\t\t// Check if we have a response.\n\t\t\tif rrCache == nil {\n\t\t\t\tconn.Failed(internalError+\"no reply\", \"\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Mark successful queries as internal in order to hide them in the simple interface.\n\t\t\t// These requests were most probably made for another process and only add confusion if listed.\n\t\t\tif conn.Process().IsSystemResolver() {\n\t\t\t\tconn.Internal = true\n\t\t\t}\n\n\t\t\t// Save the request as open, as we don't know if there will be a connection or not.\n\t\t\tfirewall.UpdateIPsAndCNAMEs(q, rrCache, conn)\n\t\t\tnetwork.SaveOpenDNSRequest(q, rrCache, conn)\n\n\t\tcase network.VerdictUndeterminable:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\ttracer.Warningf(\"nameserver: unexpected verdict %s for connection %s, not saving\", conn.VerdictVerb(), conn)\n\t\t}\n\t}()\n\n\t// Check request with the privacy filter before resolving.\n\tfirewall.FilterConnection(ctx, conn, nil, true, false)\n\n\t// Check if there is a responder from the firewall.\n\t// In special cases, the firewall might want to respond the query itself.\n\t// A reason for this might be that the request is sink-holed to a forced\n\t// IP address in which case we \"accept\" it, but let the firewall handle\n\t// the resolving as it wishes.\n\tif responder, ok := conn.Reason.Context.(nsutil.Responder); ok {\n\t\ttracer.Infof(\"nameserver: handing over request for %s to special filter responder: %s\", q.ID(), conn.Reason.Msg)\n\t\treturn reply(responder, conn)\n\t}\n\n\t// Check if there is a Verdict to act upon.\n\tswitch conn.Verdict { //nolint:exhaustive // Only checking for specific values.\n\tcase network.VerdictBlock, network.VerdictDrop, network.VerdictFailed:\n\t\ttracer.Infof(\n\t\t\t\"nameserver: returning %s response for %s to %s\",\n\t\t\tconn.VerdictVerb(),\n\t\t\tq.ID(),\n\t\t\tconn.Process(),\n\t\t)\n\t\treturn reply(conn, conn)\n\t}\n\n\t// Resolve request.\n\trrCache, err = resolver.Resolve(ctx, q)\n\t// Handle error.\n\tif err != nil {\n\t\tswitch {\n\t\tcase errors.Is(err, resolver.ErrNotFound):\n\t\t\t// Try alternatives domain names for unofficial domain spaces.\n\t\t\trrCache = checkAlternativeCaches(ctx, q)\n\t\t\tif rrCache == nil {\n\t\t\t\ttracer.Tracef(\"nameserver: %s\", err)\n\t\t\t\tconn.Failed(\"domain does not exist\", \"\")\n\t\t\t\treturn reply(nsutil.NxDomain(\"nxdomain: \" + err.Error()))\n\t\t\t}\n\t\tcase errors.Is(err, resolver.ErrBlocked):\n\t\t\ttracer.Tracef(\"nameserver: %s\", err)\n\t\t\tconn.Block(err.Error(), \"\")\n\t\t\treturn reply(nsutil.BlockIP(\"blocked: \" + err.Error()))\n\n\t\tcase errors.Is(err, resolver.ErrLocalhost):\n\t\t\ttracer.Tracef(\"nameserver: returning localhost records\")\n\t\t\tconn.Accept(\"allowing query for localhost\", \"\")\n\t\t\treturn reply(nsutil.Localhost())\n\n\t\tcase errors.Is(err, resolver.ErrOffline):\n\t\t\tif rrCache == nil {\n\t\t\t\ttracer.Debugf(\"nameserver: not resolving %s, device is offline\", q.ID())\n\t\t\t\tconn.Failed(\"not resolving, device is offline\", \"\")\n\t\t\t\treturn reply(nsutil.ServerFailure(err.Error()))\n\t\t\t}\n\t\t\t// If an rrCache was returned, it's usable as a backup.\n\t\t\trrCache.IsBackup = true\n\t\t\tlog.Tracer(ctx).Debugf(\"nameserver: device is offline, using backup cache for %s\", q.ID())\n\n\t\tdefault:\n\t\t\ttracer.Warningf(\"nameserver: failed to resolve %s: %s\", q.ID(), err)\n\t\t\tconn.Failed(fmt.Sprintf(\"query failed: %s\", err), \"\")\n\t\t\taddFailingQuery(q, err)\n\t\t\treturn reply(nsutil.ServerFailure(internalError + err.Error()))\n\t\t}\n\t}\n\t// Handle special cases.\n\tswitch {\n\tcase rrCache == nil:\n\t\ttracer.Warning(\"nameserver: received successful, but empty reply from resolver\")\n\t\taddFailingQuery(q, errors.New(\"emptry reply from resolver\"))\n\t\treturn reply(nsutil.ServerFailure(internalError + \"empty reply\"))\n\tcase rrCache.RCode == dns.RcodeNameError:\n\t\t// Try alternatives domain names for unofficial domain spaces.\n\t\taltRRCache := checkAlternativeCaches(ctx, q)\n\t\tif altRRCache != nil {\n\t\t\trrCache = altRRCache\n\t\t} else {\n\t\t\t// Return now if NXDomain.\n\t\t\treturn reply(nsutil.NxDomain(\"no answer found (NXDomain)\"))\n\t\t}\n\n\t}\n\n\t// Check with firewall again after resolving.\n\ttracer.Trace(\"nameserver: deciding on resolved dns\")\n\trrCache = firewall.FilterResolvedDNS(ctx, conn, q, rrCache)\n\n\t// Check again if there is a responder from the firewall.\n\tif responder, ok := conn.Reason.Context.(nsutil.Responder); ok {\n\t\ttracer.Infof(\"nameserver: handing over request for %s to special filter responder: %s\", q.ID(), conn.Reason.Msg)\n\t\treturn reply(responder)\n\t}\n\n\t// Check if there is a Verdict to act upon.\n\tswitch conn.Verdict { //nolint:exhaustive // Only checking for specific values.\n\tcase network.VerdictBlock, network.VerdictDrop, network.VerdictFailed:\n\t\ttracer.Infof(\n\t\t\t\"nameserver: returning %s response for %s to %s\",\n\t\t\tconn.VerdictVerb(),\n\t\t\tq.ID(),\n\t\t\tconn.Process(),\n\t\t)\n\t\treturn reply(conn, conn, rrCache)\n\t}\n\n\t// Revert back to non-standard question format, if we had to convert.\n\tif nonStandardQuestionFormat {\n\t\trrCache.ReplaceAnswerNames(originalQuestion.Name)\n\t}\n\n\t// Reply with successful response.\n\tnoAnswerIndicator := \"\"\n\tif len(rrCache.Answer) == 0 {\n\t\tnoAnswerIndicator = \"/no answer\"\n\t}\n\ttracer.Infof(\n\t\t\"nameserver: returning %s response (%s%s) for %s to %s\",\n\t\tconn.VerdictVerb(),\n\t\tdns.RcodeToString[rrCache.RCode],\n\t\tnoAnswerIndicator,\n\t\tq.ID(),\n\t\tconn.Process(),\n\t)\n\treturn reply(rrCache, conn, rrCache)\n}\n\nfunc checkAlternativeCaches(ctx context.Context, q *resolver.Query) *resolver.RRCache {\n\t// Do not try alternatives when the query is in a public suffix.\n\t// This also includes arpa. and local.\n\tif q.ICANNSpace {\n\t\treturn nil\n\t}\n\n\t// Check if the env resolver has something.\n\tpmEnvQ := &resolver.Query{\n\t\tFQDN:  q.FQDN + \"local.\" + resolver.InternalSpecialUseDomain,\n\t\tQType: q.QType,\n\t}\n\trrCache, err := resolver.QueryPortmasterEnv(ctx, pmEnvQ)\n\tif err == nil && rrCache != nil && rrCache.RCode == dns.RcodeSuccess {\n\t\tmakeAlternativeRecord(ctx, q, rrCache, pmEnvQ.FQDN)\n\t\treturn rrCache\n\t}\n\n\t// Check if we have anything in cache\n\tlocalFQDN := q.FQDN + \"local.\"\n\trrCache, err = resolver.GetRRCache(localFQDN, q.QType)\n\tif err == nil && rrCache != nil && rrCache.RCode == dns.RcodeSuccess {\n\t\tmakeAlternativeRecord(ctx, q, rrCache, localFQDN)\n\t\treturn rrCache\n\t}\n\n\treturn nil\n}\n\nfunc makeAlternativeRecord(ctx context.Context, q *resolver.Query, rrCache *resolver.RRCache, altName string) {\n\tlog.Tracer(ctx).Debugf(\"using %s to answer query\", altName)\n\n\t// Duplicate answers so they match the query.\n\tcopied := make([]dns.RR, 0, len(rrCache.Answer))\n\tfor _, answer := range rrCache.Answer {\n\t\tif strings.ToLower(answer.Header().Name) == altName {\n\t\t\tcopiedAnswer := dns.Copy(answer)\n\t\t\tcopiedAnswer.Header().Name = q.FQDN\n\t\t\tcopied = append(copied, copiedAnswer)\n\t\t}\n\t}\n\tif len(copied) > 0 {\n\t\trrCache.Answer = append(rrCache.Answer, copied...)\n\t}\n\n\t// Update the question.\n\trrCache.Domain = q.FQDN\n}\n"
  },
  {
    "path": "service/nameserver/nsutil/nsutil.go",
    "content": "package nsutil\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// ErrNilRR is returned when a parsed RR is nil.\nvar ErrNilRR = errors.New(\"is nil\")\n\n// Responder defines the interface that any block/deny reason interface\n// may implement to support sending custom DNS responses for a given reason.\n// That is, if a reason context implements the Responder interface the\n// ReplyWithDNS method will be called instead of creating the default\n// zero-ip response.\ntype Responder interface {\n\t// ReplyWithDNS is called when a DNS response to a DNS message is\n\t// crafted because the request is either denied or blocked.\n\tReplyWithDNS(ctx context.Context, request *dns.Msg) *dns.Msg\n}\n\n// RRProvider defines the interface that any block/deny reason interface\n// may implement to support adding additional DNS resource records to\n// the DNS responses extra (additional) section.\ntype RRProvider interface {\n\t// GetExtraRRs is called when a DNS response to a DNS message is\n\t// crafted because the request is either denied or blocked.\n\tGetExtraRRs(ctx context.Context, request *dns.Msg) []dns.RR\n}\n\n// ResponderFunc is a convenience type to use a function\n// directly as a Responder.\ntype ResponderFunc func(ctx context.Context, request *dns.Msg) *dns.Msg\n\n// ReplyWithDNS implements the Responder interface and calls rf.\nfunc (rf ResponderFunc) ReplyWithDNS(ctx context.Context, request *dns.Msg) *dns.Msg {\n\treturn rf(ctx, request)\n}\n\n// MarshalJSON disables JSON marshaling for ResponderFunc.\nfunc (rf ResponderFunc) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(nil)\n}\n\n// BlockIP is a ResponderFunc than replies with either 0.0.0.17 or ::17 for\n// each A or AAAA question respectively. If there is no A or AAAA question, it\n// defaults to replying with NXDomain.\nfunc BlockIP(msgs ...string) ResponderFunc {\n\treturn createResponderFunc(\n\t\t\"blocking\",\n\t\t\"0.0.0.17\",\n\t\t\"::17\",\n\t\tmsgs...,\n\t)\n}\n\n// ZeroIP is a ResponderFunc than replies with either 0.0.0.0 or :: for each A\n// or AAAA question respectively. If there is no A or AAAA question, it\n// defaults to replying with NXDomain.\nfunc ZeroIP(msgs ...string) ResponderFunc {\n\treturn createResponderFunc(\n\t\t\"zero ip\",\n\t\t\"0.0.0.0\",\n\t\t\"::\",\n\t\tmsgs...,\n\t)\n}\n\n// Localhost is a ResponderFunc than replies with localhost IP addresses.\n// If there is no A or AAAA question, it defaults to replying with NXDomain.\nfunc Localhost(msgs ...string) ResponderFunc {\n\treturn createResponderFunc(\n\t\t\"localhost\",\n\t\t\"127.0.0.1\",\n\t\t\"::1\",\n\t\tmsgs...,\n\t)\n}\n\nfunc createResponderFunc(responderName, aAnswer, aaaaAnswer string, msgs ...string) ResponderFunc {\n\treturn func(ctx context.Context, request *dns.Msg) *dns.Msg {\n\t\treply := new(dns.Msg)\n\t\thasErr := false\n\n\t\tfor _, question := range request.Question {\n\t\t\tvar rr dns.RR\n\t\t\tvar err error\n\n\t\t\tswitch question.Qtype {\n\t\t\tcase dns.TypeA:\n\t\t\t\trr, err = dns.NewRR(question.Name + \" 1 IN A \" + aAnswer)\n\t\t\tcase dns.TypeAAAA:\n\t\t\t\trr, err = dns.NewRR(question.Name + \" 1 IN AAAA \" + aaaaAnswer)\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase err != nil:\n\t\t\t\tlog.Tracer(ctx).Errorf(\"nameserver: failed to create %s response for %s: %s\", responderName, question.Name, err)\n\t\t\t\thasErr = true\n\t\t\tcase rr != nil:\n\t\t\t\treply.Answer = append(reply.Answer, rr)\n\t\t\t}\n\t\t}\n\n\t\tswitch {\n\t\tcase hasErr && len(reply.Answer) == 0:\n\t\t\treply.SetRcode(request, dns.RcodeServerFailure)\n\t\tcase len(reply.Answer) == 0:\n\t\t\treply.SetRcode(request, dns.RcodeNameError)\n\t\tdefault:\n\t\t\treply.SetRcode(request, dns.RcodeSuccess)\n\t\t}\n\n\t\tAddMessagesToReply(ctx, reply, log.InfoLevel, msgs...)\n\n\t\treturn reply\n\t}\n}\n\n// NxDomain returns a ResponderFunc that replies with NXDOMAIN.\nfunc NxDomain(msgs ...string) ResponderFunc {\n\treturn func(ctx context.Context, request *dns.Msg) *dns.Msg {\n\t\treply := new(dns.Msg).SetRcode(request, dns.RcodeNameError)\n\t\tAddMessagesToReply(ctx, reply, log.InfoLevel, msgs...)\n\n\t\t// According to RFC4074 (https://tools.ietf.org/html/rfc4074), there are\n\t\t// nameservers that incorrectly respond with NXDomain instead of an empty\n\t\t// SUCCESS response when there are other RRs for the queried domain name.\n\t\t// This can lead to the software thinking that no RRs exist for that\n\t\t// domain. In order to mitigate this a bit, we slightly delay NXDomain\n\t\t// responses.\n\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\treturn reply\n\t}\n}\n\n// Refused returns a ResponderFunc that replies with REFUSED.\nfunc Refused(msgs ...string) ResponderFunc {\n\treturn func(ctx context.Context, request *dns.Msg) *dns.Msg {\n\t\treply := new(dns.Msg).SetRcode(request, dns.RcodeRefused)\n\t\tAddMessagesToReply(ctx, reply, log.InfoLevel, msgs...)\n\t\treturn reply\n\t}\n}\n\n// ServerFailure returns a ResponderFunc that replies with SERVFAIL.\nfunc ServerFailure(msgs ...string) ResponderFunc {\n\treturn func(ctx context.Context, request *dns.Msg) *dns.Msg {\n\t\treply := new(dns.Msg).SetRcode(request, dns.RcodeServerFailure)\n\t\tAddMessagesToReply(ctx, reply, log.InfoLevel, msgs...)\n\t\treturn reply\n\t}\n}\n\n// MakeMessageRecord creates an informational resource record that can be added\n// to the extra section of a reply.\nfunc MakeMessageRecord(level log.Severity, msg string) (dns.RR, error) { //nolint:interfacer\n\trr, err := dns.NewRR(fmt.Sprintf(\n\t\t`%s.portmaster. 0 IN TXT \"%s\"`,\n\t\tstrings.ToLower(level.String()),\n\t\tmsg,\n\t))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif rr == nil {\n\t\treturn nil, ErrNilRR\n\t}\n\treturn rr, nil\n}\n\n// AddMessagesToReply creates information resource records using\n// MakeMessageRecord and immediately adds them to the extra section of the given\n// reply. If an error occurs, the resource record will not be added, and the\n// error will be logged.\nfunc AddMessagesToReply(ctx context.Context, reply *dns.Msg, level log.Severity, msgs ...string) {\n\tfor _, msg := range msgs {\n\t\t// Ignore empty messages.\n\t\tif msg == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create resources record.\n\t\trr, err := MakeMessageRecord(level, msg)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Warningf(\"nameserver: failed to add message to reply: %s\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Add to extra section of the reply.\n\t\treply.Extra = append(reply.Extra, rr)\n\t}\n}\n"
  },
  {
    "path": "service/nameserver/response.go",
    "content": "package nameserver\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/nameserver/nsutil\"\n)\n\n// sendResponse sends a response to query using w. The response message is\n// created by responder. If addExtraRRs is not nil and implements the\n// RRProvider interface then it will be also used to add more RRs in the\n// extra section.\nfunc sendResponse(\n\tctx context.Context,\n\tw dns.ResponseWriter,\n\trequest *dns.Msg,\n\tresponder nsutil.Responder,\n\trrProviders ...nsutil.RRProvider,\n) error {\n\t// Have the Responder craft a DNS reply.\n\treply := responder.ReplyWithDNS(ctx, request)\n\tif reply == nil {\n\t\t// Dropping query.\n\t\treturn nil\n\t}\n\t// Signify that we are a recursive resolver.\n\t// While we do not handle recursion directly, we can safely assume, that we\n\t// always forward to a recursive resolver.\n\treply.RecursionAvailable = true\n\n\t// Add extra RRs through a custom RRProvider.\n\tfor _, rrProvider := range rrProviders {\n\t\tif rrProvider != nil {\n\t\t\trrs := rrProvider.GetExtraRRs(ctx, request)\n\t\t\treply.Extra = append(reply.Extra, rrs...)\n\t\t}\n\t}\n\n\t// Write reply.\n\tif err := writeDNSResponse(ctx, w, reply); err != nil {\n\t\treturn fmt.Errorf(\"failed to send response: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc writeDNSResponse(ctx context.Context, w dns.ResponseWriter, m *dns.Msg) (err error) {\n\tdefer func() {\n\t\t// recover from panic\n\t\tif panicErr := recover(); panicErr != nil {\n\t\t\terr = fmt.Errorf(\"panic: %s\", panicErr)\n\t\t\tlog.Tracer(ctx).Debugf(\"nameserver: panic caused by this msg: %#v\", m)\n\t\t}\n\t}()\n\n\terr = w.WriteMsg(m)\n\tif err != nil {\n\t\t// If we receive an error we might have exceeded the message size with all\n\t\t// our extra information records. Retry again without the extra section.\n\t\tlog.Tracer(ctx).Tracef(\"nameserver: retrying to write dns message without extra section, error was: %s\", err)\n\t\tm.Extra = nil\n\t\tnoExtraErr := w.WriteMsg(m)\n\t\tif noExtraErr == nil {\n\t\t\treturn fmt.Errorf(\"failed to write dns message without extra section: %w\", err)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "service/netenv/addresses_test.go",
    "content": "package netenv\n\nimport (\n\t\"testing\"\n)\n\nfunc TestGetAssignedAddresses(t *testing.T) {\n\tt.Parallel()\n\n\tipv4, ipv6, err := GetAssignedAddresses()\n\tt.Logf(\"all v4: %v\", ipv4)\n\tt.Logf(\"all v6: %v\", ipv6)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to get addresses: %s\", err)\n\t}\n\tif len(ipv4) == 0 && len(ipv6) == 0 {\n\t\tt.Fatal(\"GetAssignedAddresses did not return any addresses\")\n\t}\n}\n\nfunc TestGetAssignedGlobalAddresses(t *testing.T) {\n\tt.Parallel()\n\n\tipv4, ipv6, err := GetAssignedGlobalAddresses()\n\tt.Logf(\"all global v4: %v\", ipv4)\n\tt.Logf(\"all global v6: %v\", ipv6)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to get addresses: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "service/netenv/adresses.go",
    "content": "package netenv\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\n// GetAssignedAddresses returns the assigned IPv4 and IPv6 addresses of the host.\nfunc GetAssignedAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {\n\taddrs, err := osGetInterfaceAddrs()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tfor _, addr := range addrs {\n\t\tnetAddr, ok := addr.(*net.IPNet)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"netenv: interface address of unexpected type %T\", addr)\n\t\t\tcontinue\n\t\t}\n\n\t\tif ip4 := netAddr.IP.To4(); ip4 != nil {\n\t\t\tipv4 = append(ipv4, ip4)\n\t\t} else {\n\t\t\tipv6 = append(ipv6, netAddr.IP)\n\t\t}\n\t}\n\treturn\n}\n\n// GetAssignedGlobalAddresses returns the assigned global IPv4 and IPv6 addresses of the host.\nfunc GetAssignedGlobalAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {\n\tallv4, allv6, err := GetAssignedAddresses()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tfor _, ip4 := range allv4 {\n\t\tif netutils.GetIPScope(ip4).IsGlobal() {\n\t\t\tipv4 = append(ipv4, ip4)\n\t\t}\n\t}\n\tfor _, ip6 := range allv6 {\n\t\tif netutils.GetIPScope(ip6).IsGlobal() {\n\t\t\tipv6 = append(ipv6, ip6)\n\t\t}\n\t}\n\treturn\n}\n\nvar (\n\tmyNetworks                   []*net.IPNet\n\tmyNetworksLock               sync.Mutex\n\tmyNetworksNetworkChangedFlag = GetNetworkChangedFlag()\n\tmyNetworksRefreshError       error //nolint:errname // Not what the linter thinks this is for.\n\tmyNetworksDontRefreshUntil   time.Time\n)\n\n// refreshMyNetworks refreshes the networks held in refreshMyNetworks.\n// The caller must hold myNetworksLock.\nfunc refreshMyNetworks() error {\n\t// Check if we already refreshed recently.\n\tif time.Now().Before(myNetworksDontRefreshUntil) {\n\t\t// Return previous error, if available.\n\t\tif myNetworksRefreshError != nil {\n\t\t\treturn fmt.Errorf(\"failed to previously refresh interface addresses: %w\", myNetworksRefreshError)\n\t\t}\n\t\treturn nil\n\t}\n\tmyNetworksRefreshError = nil\n\tmyNetworksDontRefreshUntil = time.Now().Add(1 * time.Second)\n\n\t// Refresh assigned networks.\n\tinterfaceNetworks, err := osGetInterfaceAddrs()\n\tif err != nil {\n\t\t// In some cases the system blocks on this call, which piles up to\n\t\t// literally over thousand goroutines wanting to try this again.\n\t\tmyNetworksRefreshError = err\n\t\treturn fmt.Errorf(\"failed to refresh interface addresses: %w\", err)\n\t}\n\tmyNetworks = make([]*net.IPNet, 0, len(interfaceNetworks))\n\tfor _, ifNet := range interfaceNetworks {\n\t\tipNet, ok := ifNet.(*net.IPNet)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"netenv: interface network of unexpected type %T\", ifNet)\n\t\t\tcontinue\n\t\t}\n\n\t\tmyNetworks = append(myNetworks, ipNet)\n\t}\n\n\t// Reset changed flag.\n\tmyNetworksNetworkChangedFlag.Refresh()\n\n\treturn nil\n}\n\n// IsMyIP returns whether the given unicast IP is currently configured on the local host.\n// Broadcast or multicast addresses will never match, even if valid and in use.\n// Function is optimized with the assumption that is likely that the IP is mine.\nfunc IsMyIP(ip net.IP) (yes bool, err error) {\n\t// Check for IPs that don't need extra checks.\n\tswitch netutils.GetIPScope(ip) { //nolint:exhaustive // Only looking for specific values.\n\tcase netutils.HostLocal:\n\t\treturn true, nil\n\tcase netutils.LocalMulticast, netutils.GlobalMulticast:\n\t\treturn false, nil\n\t}\n\n\tmyNetworksLock.Lock()\n\tdefer myNetworksLock.Unlock()\n\n\t// Check if the network changed.\n\tif myNetworksNetworkChangedFlag.IsSet() {\n\t\terr := refreshMyNetworks()\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\t// Check against assigned IPs.\n\tfor _, myNet := range myNetworks {\n\t\tif ip.Equal(myNet.IP) {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\t// Check for other IPs in range and broadcast addresses.\n\t// Do this in a second loop, as an IP will match in\n\t// most cases and network matching is more expensive.\n\tfor _, myNet := range myNetworks {\n\t\tif myNet.Contains(ip) {\n\t\t\treturn false, nil\n\t\t}\n\t}\n\n\t// Could not find IP anywhere. Refresh network to be sure.\n\terr = refreshMyNetworks()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// Check against assigned IPs again.\n\tfor _, myNet := range myNetworks {\n\t\tif ip.Equal(myNet.IP) {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// GetLocalNetwork uses the given IP to search for a network configured on the\n// device and returns it.\nfunc GetLocalNetwork(ip net.IP) (myNet *net.IPNet, err error) {\n\tmyNetworksLock.Lock()\n\tdefer myNetworksLock.Unlock()\n\n\t// Check if the network changed.\n\tif myNetworksNetworkChangedFlag.IsSet() {\n\t\terr := refreshMyNetworks()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Check if the IP address is in my networks.\n\tfor _, myNet := range myNetworks {\n\t\tif myNet.Contains(ip) {\n\t\t\treturn myNet, nil\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/netenv/api.go",
    "content": "package netenv\n\nimport (\n\t\"errors\"\n\n\t\"github.com/safing/portmaster/base/api\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath: \"network/gateways\",\n\t\tRead: api.PermitUser,\n\t\tStructFunc: func(ar *api.Request) (i interface{}, err error) {\n\t\t\treturn Gateways(), nil\n\t\t},\n\t\tName:        \"Get Default Gateways\",\n\t\tDescription: \"Returns the current active default gateways of the network.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath: \"network/nameservers\",\n\t\tRead: api.PermitUser,\n\t\tStructFunc: func(ar *api.Request) (i interface{}, err error) {\n\t\t\treturn Nameservers(), nil\n\t\t},\n\t\tName:        \"Get System Nameservers\",\n\t\tDescription: \"Returns the currently configured nameservers on the OS.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath: \"network/location\",\n\t\tRead: api.PermitUser,\n\t\tStructFunc: func(ar *api.Request) (i interface{}, err error) {\n\t\t\tlocs, ok := GetInternetLocation()\n\t\t\tif ok {\n\t\t\t\treturn locs, nil\n\t\t\t}\n\t\t\treturn nil, errors.New(\"no location data available\")\n\t\t},\n\t\tName:        \"Get Approximate Internet Location\",\n\t\tDescription: \"Returns an approximation of where the device is on the Internet.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath: \"network/location/traceroute\",\n\t\tRead: api.PermitUser,\n\t\tStructFunc: func(ar *api.Request) (i interface{}, err error) {\n\t\t\treturn getLocationFromTraceroute(&DeviceLocations{})\n\t\t},\n\t\tName:        \"Get Approximate Internet Location via Traceroute\",\n\t\tDescription: \"Returns an approximation of where the device is on the Internet using a the traceroute technique.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/netenv/dbus_linux.go",
    "content": "//go:build !server\n\npackage netenv\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/godbus/dbus/v5\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\tdbusConn     *dbus.Conn\n\tdbusConnLock sync.Mutex\n)\n\nfunc getNameserversFromDbus() ([]Nameserver, error) { //nolint:gocognit // TODO\n\t// cmdline tool for exploring: gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager\n\n\tvar ns []Nameserver\n\tvar err error\n\n\tdbusConnLock.Lock()\n\tdefer dbusConnLock.Unlock()\n\n\tif dbusConn == nil {\n\t\tdbusConn, err = dbus.SystemBus()\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tprimaryConnectionVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath(\"/org/freedesktop/NetworkManager\"), \"org.freedesktop.NetworkManager.PrimaryConnection\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"dbus: failed to access NetworkManager.PrimaryConnection: %w\", err)\n\t}\n\tprimaryConnection, ok := primaryConnectionVariant.Value().(dbus.ObjectPath)\n\tif !ok {\n\t\treturn nil, errors.New(\"dbus: could not assert type of /org/freedesktop/NetworkManager:org.freedesktop.NetworkManager.PrimaryConnection\")\n\t}\n\n\tactiveConnectionsVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath(\"/org/freedesktop/NetworkManager\"), \"org.freedesktop.NetworkManager.ActiveConnections\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"dbus: failed to access NetworkManager.ActiveConnections: %w\", err)\n\t}\n\tactiveConnections, ok := activeConnectionsVariant.Value().([]dbus.ObjectPath)\n\tif !ok {\n\t\treturn nil, errors.New(\"dbus: could not assert type of /org/freedesktop/NetworkManager:org.freedesktop.NetworkManager.ActiveConnections\")\n\t}\n\n\tsortedConnections := []dbus.ObjectPath{primaryConnection}\n\tfor _, activeConnection := range activeConnections {\n\t\tif !objectPathInSlice(activeConnection, sortedConnections) {\n\t\t\tsortedConnections = append(sortedConnections, activeConnection)\n\t\t}\n\t}\n\n\tfor _, activeConnection := range sortedConnections {\n\t\tnewNameservers, err := dbusGetInterfaceNameservers(dbusConn, activeConnection, 4)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"failed to get nameserver: %s\", err)\n\t\t} else {\n\t\t\tns = append(ns, newNameservers...)\n\t\t}\n\n\t\tnewNameservers, err = dbusGetInterfaceNameservers(dbusConn, activeConnection, 6)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"failed to get nameserver: %s\", err)\n\t\t} else {\n\t\t\tns = append(ns, newNameservers...)\n\t\t}\n\t}\n\n\treturn ns, nil\n}\n\nfunc dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.ObjectPath, ipVersion uint8) ([]Nameserver, error) {\n\tipConfigPropertyKey := fmt.Sprintf(\"org.freedesktop.NetworkManager.Connection.Active.Ip%dConfig\", ipVersion)\n\tnameserversIPsPropertyKey := fmt.Sprintf(\"org.freedesktop.NetworkManager.IP%dConfig.Nameservers\", ipVersion)\n\tnameserversDomainsPropertyKey := fmt.Sprintf(\"org.freedesktop.NetworkManager.IP%dConfig.Domains\", ipVersion)\n\tnameserversSearchesPropertyKey := fmt.Sprintf(\"org.freedesktop.NetworkManager.IP%dConfig.Searches\", ipVersion)\n\n\t// Get Interface Configuration.\n\tipConfigVariant, err := getNetworkManagerProperty(dbusConn, interfaceObject, ipConfigPropertyKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to access %s:%s: %w\", interfaceObject, ipConfigPropertyKey, err)\n\t}\n\tipConfig, ok := ipConfigVariant.Value().(dbus.ObjectPath)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"could not assert type of %s:%s\", interfaceObject, ipConfigPropertyKey)\n\t}\n\n\t// Check if interface is active in the selected IP version\n\tif !ipConfig.IsValid() || ipConfig == \"/\" {\n\t\treturn nil, nil\n\t}\n\n\t// Get Nameserver IPs\n\tnameserverIPsVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversIPsPropertyKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to access %s:%s: %w\", ipConfig, nameserversIPsPropertyKey, err)\n\t}\n\tvar nameserverIPs []net.IP\n\tswitch ipVersion {\n\tcase 4:\n\t\tnameserverIP4s, ok := nameserverIPsVariant.Value().([]uint32)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"could not assert type of %s:%s\", ipConfig, nameserversIPsPropertyKey)\n\t\t}\n\t\tfor _, ip := range nameserverIP4s {\n\t\t\ta := uint8(ip / 16777216)\n\t\t\tb := uint8((ip % 16777216) / 65536)\n\t\t\tc := uint8((ip % 65536) / 256)\n\t\t\td := uint8(ip % 256)\n\t\t\tnameserverIPs = append(nameserverIPs, net.IPv4(d, c, b, a))\n\t\t}\n\tcase 6:\n\t\tnameserverIP6s, ok := nameserverIPsVariant.Value().([][]byte)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"could not assert type of %s:%s\", ipConfig, nameserversIPsPropertyKey)\n\t\t}\n\t\tfor _, ip := range nameserverIP6s {\n\t\t\tif len(ip) != 16 {\n\t\t\t\treturn nil, fmt.Errorf(\"query returned IPv6 address with invalid length: %q\", ip)\n\t\t\t}\n\t\t\tnameserverIPs = append(nameserverIPs, net.IP(ip))\n\t\t}\n\t}\n\n\t// Get Nameserver Domains\n\tnameserverDomainsVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversDomainsPropertyKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to access %s:%s: %w\", ipConfig, nameserversDomainsPropertyKey, err)\n\t}\n\tnameserverDomains, ok := nameserverDomainsVariant.Value().([]string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"could not assert type of %s:%s\", ipConfig, nameserversDomainsPropertyKey)\n\t}\n\n\t// Get Nameserver Searches\n\tnameserverSearchesVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversSearchesPropertyKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to access %s:%s: %w\", ipConfig, nameserversSearchesPropertyKey, err)\n\t}\n\tnameserverSearches, ok := nameserverSearchesVariant.Value().([]string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"could not assert type of %s:%s\", ipConfig, nameserversSearchesPropertyKey)\n\t}\n\n\tns := make([]Nameserver, 0, len(nameserverIPs))\n\tsearchDomains := append(nameserverDomains, nameserverSearches...) //nolint:gocritic\n\tfor _, nameserverIP := range nameserverIPs {\n\t\tns = append(ns, Nameserver{\n\t\t\tIP:     nameserverIP,\n\t\t\tSearch: searchDomains,\n\t\t})\n\t}\n\n\treturn ns, nil\n}\n\nfunc getConnectivityStateFromDbus() (OnlineStatus, error) {\n\tvar err error\n\n\tdbusConnLock.Lock()\n\tdefer dbusConnLock.Unlock()\n\n\tif dbusConn == nil {\n\t\tdbusConn, err = dbus.SystemBus()\n\t}\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tconnectivityStateVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath(\"/org/freedesktop/NetworkManager\"), \"org.freedesktop.NetworkManager.Connectivity\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tconnectivityState, ok := connectivityStateVariant.Value().(uint32)\n\tif !ok {\n\t\treturn 0, errors.New(\"dbus: could not assert type of /org/freedesktop/NetworkManager:org.freedesktop.NetworkManager.Connectivity\")\n\t}\n\n\t// NMConnectivityState\n\t// NM_CONNECTIVITY_UNKNOWN\t= 0 Network connectivity is unknown.\n\t// NM_CONNECTIVITY_NONE = 1 The host is not connected to any network.\n\t// NM_CONNECTIVITY_PORTAL = 2 The host is behind a captive portal and cannot reach the full Internet.\n\t// NM_CONNECTIVITY_LIMITED = 3 The host is connected to a network, but does not appear to be able to reach the full Internet.\n\t// NM_CONNECTIVITY_FULL = 4 The host is connected to a network, and appears to be able to reach the full Internet.\n\n\tswitch connectivityState {\n\tcase 0:\n\t\treturn StatusUnknown, nil\n\tcase 1:\n\t\treturn StatusOffline, nil\n\tcase 2:\n\t\treturn StatusPortal, nil\n\tcase 3:\n\t\treturn StatusLimited, nil\n\tcase 4:\n\t\treturn StatusOnline, nil\n\t}\n\n\treturn StatusUnknown, nil\n}\n\nfunc getNetworkManagerProperty(conn *dbus.Conn, objectPath dbus.ObjectPath, property string) (dbus.Variant, error) {\n\tobject := conn.Object(\"org.freedesktop.NetworkManager\", objectPath)\n\treturn object.GetProperty(property)\n}\n\nfunc objectPathInSlice(a dbus.ObjectPath, list []dbus.ObjectPath) bool {\n\tfor _, b := range list {\n\t\tif string(b) == string(a) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "service/netenv/dbus_linux_test.go",
    "content": "package netenv\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestDbus(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode because it fails in the CI\")\n\t}\n\n\tif _, err := os.Stat(\"/var/run/dbus/system_bus_socket\"); errors.Is(err, fs.ErrNotExist) {\n\t\tt.Logf(\"skipping dbus tests, as dbus does not seem to be installed: %s\", err)\n\t\treturn\n\t}\n\n\tnameservers, err := getNameserversFromDbus()\n\tif err != nil {\n\t\tt.Errorf(\"getNameserversFromDbus failed: %s\", err)\n\t}\n\tt.Logf(\"getNameserversFromDbus: %v\", nameservers)\n\n\tconnectivityState, err := getConnectivityStateFromDbus()\n\tif err != nil {\n\t\tt.Errorf(\"getConnectivityStateFromDbus failed: %s\", err)\n\t}\n\tt.Logf(\"getConnectivityStateFromDbus: %v\", connectivityState)\n}\n"
  },
  {
    "path": "service/netenv/dialing.go",
    "content": "package netenv\n\nimport \"net\"\n\nvar localAddrFactory func(network string) net.Addr\n\n// SetLocalAddrFactory supplies the environment package with a function to get permitted local addresses for connections.\nfunc SetLocalAddrFactory(laf func(network string) net.Addr) {\n\tif localAddrFactory == nil {\n\t\tlocalAddrFactory = laf\n\t}\n}\n\nfunc getLocalAddr(network string) net.Addr {\n\tif localAddrFactory != nil {\n\t\treturn localAddrFactory(network)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/netenv/environment.go",
    "content": "package netenv\n\nimport (\n\t\"net\"\n)\n\n// TODO: find a good way to identify a network\n// best options until now:\n// MAC of gateway\n// domain parameter of dhcp\n\n// TODO: get dhcp servers on windows:\n// doc: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365917\n// this info might already be included in the interfaces api provided by golang!\n\n// Nameserver describes a system assigned namserver.\ntype Nameserver struct {\n\tIP     net.IP\n\tSearch []string\n}\n"
  },
  {
    "path": "service/netenv/environment_default.go",
    "content": "//+build !windows,!linux\n\npackage netenv\n\nimport \"net\"\n\nfunc Nameservers() []Nameserver {\n\treturn nil\n}\n\nfunc Gateways() []net.IP {\n\treturn nil\n}\n\n// TODO: implement using\n// ifconfig\n// scutil --nwi\n// scutil --proxy\n// networksetup -listallnetworkservices\n// networksetup -listnetworkserviceorder\n// networksetup -getdnsservers \"Wi-Fi\"\n// networksetup -getsearchdomains <networkservice>\n// networksetup -getftpproxy <networkservice>\n// networksetup -getwebproxy <networkservice>\n// networksetup -getsecurewebproxy <networkservice>\n// networksetup -getstreamingproxy <networkservice>\n// networksetup -getgopherproxy <networkservice>\n// networksetup -getsocksfirewallproxy <networkservice>\n// route -n get default\n"
  },
  {
    "path": "service/netenv/environment_linux.go",
    "content": "package netenv\n\nimport (\n\t\"bufio\"\n\t\"encoding/hex\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\nvar (\n\tgateways                   = make([]net.IP, 0)\n\tgatewaysLock               sync.Mutex\n\tgatewaysNetworkChangedFlag = GetNetworkChangedFlag()\n\n\tnameservers                   = make([]Nameserver, 0)\n\tnameserversLock               sync.Mutex\n\tnameserversNetworkChangedFlag = GetNetworkChangedFlag()\n)\n\n// Gateways returns the currently active gateways.\nfunc Gateways() []net.IP {\n\tgatewaysLock.Lock()\n\tdefer gatewaysLock.Unlock()\n\t// Check if the network changed, if not, return cache.\n\tif !gatewaysNetworkChangedFlag.IsSet() {\n\t\treturn gateways\n\t}\n\tgatewaysNetworkChangedFlag.Refresh()\n\n\tgateways = make([]net.IP, 0)\n\tvar decoded []byte\n\n\t// open file\n\troute, err := os.Open(\"/proc/net/route\")\n\tif err != nil {\n\t\tlog.Warningf(\"environment: could not read /proc/net/route: %s\", err)\n\t\treturn gateways\n\t}\n\tdefer func() {\n\t\t_ = route.Close()\n\t}()\n\n\t// file scanner\n\tscanner := bufio.NewScanner(route)\n\tscanner.Split(bufio.ScanLines)\n\n\t// parse\n\tfor scanner.Scan() {\n\t\tline := strings.SplitN(scanner.Text(), \"\\t\", 4)\n\t\tif len(line) < 4 {\n\t\t\tcontinue\n\t\t}\n\t\tif line[1] == \"00000000\" {\n\t\t\tdecoded, err = hex.DecodeString(line[2])\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"environment: could not parse gateway %s from /proc/net/route: %s\", line[2], err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(decoded) != 4 {\n\t\t\t\tlog.Warningf(\"environment: decoded gateway %s from /proc/net/route has wrong length\", decoded)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tgate := net.IPv4(decoded[3], decoded[2], decoded[1], decoded[0])\n\t\t\tgateways = append(gateways, gate)\n\t\t}\n\t}\n\n\t// open file\n\tv6route, err := os.Open(\"/proc/net/ipv6_route\")\n\tif err != nil {\n\t\tlog.Warningf(\"environment: could not read /proc/net/ipv6_route: %s\", err)\n\t\treturn gateways\n\t}\n\tdefer func() {\n\t\t_ = v6route.Close()\n\t}()\n\n\t// file scanner\n\tscanner = bufio.NewScanner(v6route)\n\tscanner.Split(bufio.ScanLines)\n\n\t// parse\n\tfor scanner.Scan() {\n\t\tline := strings.SplitN(scanner.Text(), \" \", 6)\n\t\tif len(line) < 6 {\n\t\t\tcontinue\n\t\t}\n\t\tif line[0] == \"00000000000000000000000000000000\" && line[4] != \"00000000000000000000000000000000\" {\n\t\t\tdecoded, err := hex.DecodeString(line[4])\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"environment: could not parse gateway %s from /proc/net/ipv6_route: %s\", line[2], err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(decoded) != 16 {\n\t\t\t\tlog.Warningf(\"environment: decoded gateway %s from /proc/net/ipv6_route has wrong length\", decoded)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tgate := net.IP(decoded)\n\t\t\tgateways = append(gateways, gate)\n\t\t}\n\t}\n\n\treturn gateways\n}\n\n// Nameservers returns the currently active nameservers.\nfunc Nameservers() []Nameserver {\n\tnameserversLock.Lock()\n\tdefer nameserversLock.Unlock()\n\t// Check if the network changed, if not, return cache.\n\tif !nameserversNetworkChangedFlag.IsSet() {\n\t\treturn nameservers\n\t}\n\tnameserversNetworkChangedFlag.Refresh()\n\n\t// logic\n\t// TODO: try:\n\t// 1. NetworkManager DBUS\n\t// 2. /etc/resolv.conf\n\t// 2.1. if /etc/resolv.conf has localhost nameserver, check for dnsmasq config (are there others?)\n\tnameservers = make([]Nameserver, 0)\n\n\t// get nameservers from DBUS\n\tdbusNameservers, err := getNameserversFromDbus()\n\tif err != nil {\n\t\tlog.Warningf(\"environment: could not get nameservers from dbus: %s\", err)\n\t} else {\n\t\tnameservers = addNameservers(nameservers, dbusNameservers)\n\t}\n\n\t// get nameservers from /etc/resolv.conf\n\tresolvconfNameservers, err := getNameserversFromResolvconf()\n\tif err != nil {\n\t\tlog.Warningf(\"environment: could not get nameservers from resolvconf: %s\", err)\n\t} else {\n\t\tnameservers = addNameservers(nameservers, resolvconfNameservers)\n\t}\n\n\treturn nameservers\n}\n\nfunc getNameserversFromResolvconf() ([]Nameserver, error) {\n\t// open file\n\tresolvconf, err := os.Open(\"/etc/resolv.conf\")\n\tif err != nil {\n\t\tlog.Warningf(\"environment: could not read /etc/resolv.conf: %s\", err)\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = resolvconf.Close()\n\t}()\n\n\t// file scanner\n\tscanner := bufio.NewScanner(resolvconf)\n\tscanner.Split(bufio.ScanLines)\n\n\tvar searchDomains []string\n\tvar servers []net.IP\n\n\t// parse\n\tfor scanner.Scan() {\n\t\tline := strings.SplitN(scanner.Text(), \" \", 3)\n\t\tif len(line) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tswitch line[0] {\n\t\tcase \"search\":\n\t\t\tif netutils.IsValidFqdn(dns.Fqdn(line[1])) {\n\t\t\t\tsearchDomains = append(searchDomains, line[1])\n\t\t\t}\n\t\tcase \"nameserver\":\n\t\t\tip := net.ParseIP(line[1])\n\t\t\tif ip != nil {\n\t\t\t\tservers = append(servers, ip)\n\t\t\t}\n\t\t}\n\t}\n\n\t// build array\n\tnameservers := make([]Nameserver, 0, len(servers))\n\tfor _, server := range servers {\n\t\tnameservers = append(nameservers, Nameserver{\n\t\t\tIP:     server,\n\t\t\tSearch: searchDomains,\n\t\t})\n\t}\n\treturn nameservers, nil\n}\n\nfunc addNameservers(nameservers, newNameservers []Nameserver) []Nameserver {\n\tfor _, newNameserver := range newNameservers {\n\t\tfound := false\n\t\tfor _, nameserver := range nameservers {\n\t\t\tif nameserver.IP.Equal(newNameserver.IP) {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tnameservers = append(nameservers, newNameserver)\n\t\t}\n\t}\n\treturn nameservers\n}\n"
  },
  {
    "path": "service/netenv/environment_linux_test.go",
    "content": "package netenv\n\nimport \"testing\"\n\nfunc TestLinuxEnvironment(t *testing.T) {\n\tt.Parallel()\n\n\tnameserversTest, err := getNameserversFromResolvconf()\n\tif err != nil {\n\t\tt.Errorf(\"failed to get namerservers from resolvconf: %s\", err)\n\t}\n\tt.Logf(\"nameservers from resolvconf: %+v\", nameserversTest)\n}\n"
  },
  {
    "path": "service/netenv/environment_test.go",
    "content": "package netenv\n\nimport \"testing\"\n\nfunc TestEnvironment(t *testing.T) {\n\tt.Parallel()\n\n\tnameserversTest := Nameservers()\n\tt.Logf(\"nameservers: %+v\", nameserversTest)\n\n\tgatewaysTest := Gateways()\n\tt.Logf(\"gateways: %+v\", gatewaysTest)\n}\n"
  },
  {
    "path": "service/netenv/environment_windows.go",
    "content": "package netenv\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils/osdetail\"\n)\n\n// Gateways returns the currently active gateways.\nfunc Gateways() []net.IP {\n\tdefaultIf := getDefaultInterface()\n\tif defaultIf == nil {\n\t\treturn nil\n\t}\n\n\t// Collect gateways.\n\tvar gw []net.IP\n\tif defaultIf.IPv4DefaultGateway != nil {\n\t\tgw = append(gw, defaultIf.IPv4DefaultGateway)\n\t}\n\tif defaultIf.IPv6DefaultGateway != nil {\n\t\tgw = append(gw, defaultIf.IPv6DefaultGateway)\n\t}\n\n\treturn gw\n}\n\n// Nameservers returns the currently active nameservers.\nfunc Nameservers() []Nameserver {\n\tdefaultIf := getDefaultInterface()\n\tif defaultIf == nil {\n\t\treturn nil\n\t}\n\n\t// Compile search list.\n\tvar search []string\n\tif defaultIf.DNSServerConfig != nil {\n\t\tif defaultIf.DNSServerConfig.Suffix != \"\" {\n\t\t\tsearch = append(search, defaultIf.DNSServerConfig.Suffix)\n\t\t}\n\t\tif len(defaultIf.DNSServerConfig.SuffixSearchList) > 0 {\n\t\t\tsearch = append(search, defaultIf.DNSServerConfig.SuffixSearchList...)\n\t\t}\n\t}\n\n\t// Compile nameservers.\n\tvar ns []Nameserver\n\tfor _, nsIP := range defaultIf.DNSServer {\n\t\tns = append(ns, Nameserver{\n\t\t\tIP:     nsIP,\n\t\t\tSearch: search,\n\t\t})\n\t}\n\n\treturn ns\n}\n\nconst (\n\tdefaultInterfaceRecheck = 2 * time.Second\n)\n\nvar (\n\tdefaultInterface                   *defaultNetInterface\n\tdefaultInterfaceLock               sync.Mutex\n\tdefaultInterfaceNetworkChangedFlag = GetNetworkChangedFlag()\n)\n\ntype defaultNetInterface struct {\n\tInterfaceIndex     string\n\tIPv6Address        net.IP\n\tIPv4Address        net.IP\n\tIPv6DefaultGateway net.IP\n\tIPv4DefaultGateway net.IP\n\tDNSServer          []net.IP\n\tDNSServerConfig    *dnsServerConfig\n}\n\ntype dnsServerConfig struct {\n\tSuffix           string\n\tSuffixSearchList []string\n}\n\nfunc getDefaultInterface() *defaultNetInterface {\n\tdefaultInterfaceLock.Lock()\n\tdefer defaultInterfaceLock.Unlock()\n\t// Check if the network changed, if not, return cache.\n\tif !defaultInterfaceNetworkChangedFlag.IsSet() {\n\t\treturn defaultInterface\n\t}\n\tdefaultInterfaceNetworkChangedFlag.Refresh()\n\n\t// Get interface data from Windows.\n\tinterfaceData, err := osdetail.RunPowershellCmd(\"Get-NetRoute -DestinationPrefix '0.0.0.0/0' | Select-Object -First 1 | Get-NetIPConfiguration | Format-List\")\n\tif err != nil {\n\t\tlog.Warningf(\"netenv: failed to get interface data: %s\", err)\n\t\treturn nil\n\t}\n\n\t// TODO: It would be great to get this as json. Powershell can do this,\n\t// but it just spits out lots of weird data instead of the same strings\n\t// seen in the list.\n\tnewIf := &defaultNetInterface{}\n\n\t// Scan data for needed fields.\n\tscanner := bufio.NewScanner(bytes.NewBuffer(interfaceData))\n\tscanner.Split(bufio.ScanLines)\n\tvar segmentKey, segmentValue, previousKey string\n\tfor scanner.Scan() {\n\t\tsegments := strings.SplitN(scanner.Text(), \" : \", 2)\n\n\t\t// Check what the line gives us.\n\t\tswitch len(segments) {\n\t\tcase 2:\n\t\t\t// This is a new key and value.\n\t\t\tsegmentKey = strings.TrimSpace(segments[0])\n\t\t\tsegmentValue = strings.TrimSpace(segments[1])\n\t\t\tpreviousKey = segmentKey\n\t\tcase 1:\n\t\t\t// This is another value for the previous key.\n\t\t\tsegmentKey = previousKey\n\t\t\tsegmentValue = strings.TrimSpace(segments[0])\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\n\t\t// Ignore empty lines.\n\t\tif segmentValue == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Parse and assign value to struct.\n\t\tswitch segmentKey {\n\t\tcase \"InterfaceIndex\":\n\t\t\tnewIf.InterfaceIndex = segmentValue\n\t\tcase \"IPv6Address\":\n\t\t\tnewIf.IPv6Address = net.ParseIP(segmentValue)\n\t\tcase \"IPv4Address\":\n\t\t\tnewIf.IPv4Address = net.ParseIP(segmentValue)\n\t\tcase \"IPv6DefaultGateway\":\n\t\t\tnewIf.IPv6DefaultGateway = net.ParseIP(segmentValue)\n\t\tcase \"IPv4DefaultGateway\":\n\t\t\tnewIf.IPv4DefaultGateway = net.ParseIP(segmentValue)\n\t\tcase \"DNSServer\":\n\t\t\tnewIP := net.ParseIP(segmentValue)\n\t\t\tif newIP != nil {\n\t\t\t\tnewIf.DNSServer = append(newIf.DNSServer, newIP)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Get Search Scopes for this interface.\n\tif newIf.InterfaceIndex != \"\" {\n\t\tdnsConfigData, err := osdetail.RunPowershellCmd(fmt.Sprintf(\n\t\t\t\"Get-DnsClient -InterfaceIndex %s | ConvertTo-Json -Depth 1\",\n\t\t\tnewIf.InterfaceIndex,\n\t\t))\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"netenv: failed to get dns server config data: %s\", err)\n\t\t} else {\n\t\t\t// Parse data into struct.\n\t\t\tdnsConfig := &dnsServerConfig{}\n\t\t\terr := json.Unmarshal([]byte(dnsConfigData), dnsConfig)\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"netenv: failed to get dns server config data: %s\", err)\n\t\t\t} else {\n\t\t\t\tnewIf.DNSServerConfig = dnsConfig\n\t\t\t}\n\t\t}\n\t} else {\n\t\tlog.Warning(\"netenv: could not get dns server config data, because default interface index is missing\")\n\t}\n\n\t// Assign new value to cache and return.\n\tdefaultInterface = newIf\n\treturn defaultInterface\n}\n"
  },
  {
    "path": "service/netenv/environment_windows_test.go",
    "content": "package netenv\n\nimport \"testing\"\n\nfunc TestWindowsEnvironment(t *testing.T) {\n\tdefaultIf := getDefaultInterface()\n\tif defaultIf == nil {\n\t\tt.Error(\"failed to get default interface\")\n\t}\n\tt.Logf(\"default interface: %+v\", defaultIf)\n}\n"
  },
  {
    "path": "service/netenv/icmp_listener.go",
    "content": "package netenv\n\nimport (\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n/*\nThis ICMP listening system is a simple system for components to listen to ICMP\npackets via the firewall.\n\nThe main use case for this is to receive ICMP packets that are not always\ndelivered correctly, or need special permissions and or sockets to receive\nthem. This is the case when doing a traceroute.\n\nIn order to keep it simple, the system is only designed to be used by one\n\"user\" at a time. Further calls to ListenToICMP will wait for the previous\noperation to complete.\n*/\n\nvar (\n\t// listenICMPLock locks the ICMP listening system for one user at a time.\n\tlistenICMPLock sync.Mutex\n\n\t// listenICMPEnabled defines whether or not the firewall should submit ICMP\n\t// packets to this interface.\n\tlistenICMPEnabled = abool.New()\n\n\t// listenICMPInput is created for every use of the ICMP listenting system.\n\tlistenICMPInput         chan packet.Packet\n\tlistenICMPInputTargetIP net.IP\n\tlistenICMPInputLock     sync.Mutex\n)\n\n// ListenToICMP returns a new channel for listenting to icmp packets. Please\n// note that any icmp packet will be passed and filtering must be done on\n// the side of the caller. The caller must call the returned done function when\n// done with the listener.\nfunc ListenToICMP(targetIP net.IP) (packets chan packet.Packet, done func()) {\n\t// Lock for single use.\n\tlistenICMPLock.Lock()\n\n\t// Create new input channel.\n\tlistenICMPInputLock.Lock()\n\tlistenICMPInput = make(chan packet.Packet, 100)\n\tlistenICMPInputTargetIP = targetIP\n\tlistenICMPEnabled.Set()\n\tlistenICMPInputLock.Unlock()\n\n\treturn listenICMPInput, func() {\n\t\t// Release for someone else to use.\n\t\tdefer listenICMPLock.Unlock()\n\n\t\t// Close input channel.\n\t\tlistenICMPInputLock.Lock()\n\t\tlistenICMPEnabled.UnSet()\n\t\tlistenICMPInputTargetIP = nil\n\t\tclose(listenICMPInput)\n\t\tlistenICMPInputLock.Unlock()\n\t}\n}\n\n// SubmitPacketToICMPListener checks if an ICMP packet should be submitted to\n// the listener. If so, it is submitted right away. The function returns\n// whether or not the packet should be submitted, not if it was successful.\nfunc SubmitPacketToICMPListener(pkt packet.Packet) (submitted bool) {\n\t// Hot path.\n\tif !listenICMPEnabled.IsSet() {\n\t\treturn false\n\t}\n\n\t// Slow path.\n\treturn submitPacketToICMPListenerSlow(pkt)\n}\n\nfunc submitPacketToICMPListenerSlow(pkt packet.Packet) (submitted bool) {\n\t// Make sure the payload is available.\n\tif err := pkt.LoadPacketData(); err != nil {\n\t\tlog.Warningf(\"netenv: failed to get payload for ICMP listener: %s\", err)\n\t\treturn false\n\t}\n\n\t// Send to input channel.\n\tlistenICMPInputLock.Lock()\n\tdefer listenICMPInputLock.Unlock()\n\n\t// Check if still enabled.\n\tif !listenICMPEnabled.IsSet() {\n\t\treturn false\n\t}\n\n\t// Only listen for outbound packets to the target IP.\n\tif pkt.IsOutbound() &&\n\t\tlistenICMPInputTargetIP != nil &&\n\t\t!pkt.Info().Dst.Equal(listenICMPInputTargetIP) {\n\t\treturn false\n\t}\n\n\t// Send to channel, if possible.\n\tselect {\n\tcase listenICMPInput <- pkt:\n\tdefault:\n\t\tlog.Warning(\"netenv: failed to send packet payload to ICMP listener: channel full\")\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "service/netenv/init_test.go",
    "content": "package netenv\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/configure\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype testInstance struct {\n\tdb           *dbmodule.DBModule\n\tapi          *api.API\n\tconfig       *config.Config\n\tintelUpdates *updates.Updater\n}\n\nvar _ instance = &testInstance{}\n\nfunc (stub *testInstance) IntelUpdates() *updates.Updater              { return stub.intelUpdates }\nfunc (stub *testInstance) API() *api.API                               { return stub.api }\nfunc (stub *testInstance) Config() *config.Config                      { return stub.config }\nfunc (stub *testInstance) Notifications() *notifications.Notifications { return nil }\nfunc (stub *testInstance) Ready() bool                                 { return true }\nfunc (stub *testInstance) Restart()                                    {}\nfunc (stub *testInstance) Shutdown()                                   {}\nfunc (stub *testInstance) SetCmdLineOperation(f func() error)          {}\nfunc (stub *testInstance) UI() *ui.UI                                  { return nil }\nfunc (stub *testInstance) DataDir() string                             { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tvar err error\n\n\t// Create a temporary directory for testing\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temporary data directory: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Initialize the Intel update configuration\n\tintelUpdateConfig := updates.Config{\n\t\tName:              configure.DefaultIntelIndexName,\n\t\tDirectory:         filepath.Join(_dataDir, \"test_intel\"),\n\t\tDownloadDirectory: filepath.Join(_dataDir, \"test_download_intel\"),\n\t\tPurgeDirectory:    filepath.Join(_dataDir, \"test_upgrade_obsolete_intel\"),\n\t\tIndexURLs:         configure.DefaultIntelIndexURLs,\n\t\tIndexFile:         \"index.json\",\n\t\tAutoCheck:         true,\n\t\tAutoDownload:      true,\n\t\tAutoApply:         true,\n\t}\n\n\t// Set the default API listen address\n\tapi.SetDefaultAPIListenAddress(\"0.0.0.0:8080\")\n\n\t// Initialize the instance with the necessary components\n\tstub := &testInstance{}\n\tstub.db, err = dbmodule.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database: %w\", err)\n\t}\n\tstub.config, err = config.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config: %w\", err)\n\t}\n\tstub.api, err = api.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create api: %w\", err)\n\t}\n\tstub.intelUpdates, err = updates.New(stub, \"Intel Updater\", intelUpdateConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create updates: %w\", err)\n\t}\n\terr = stub.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start database: %w\", err)\n\t}\n\terr = stub.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start config: %w\", err)\n\t}\n\terr = stub.api.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start api: %w\", err)\n\t}\n\terr = stub.intelUpdates.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start updates: %w\", err)\n\t}\n\n\t_, err = New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to initialize module %w\", err)\n\t}\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\", err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "service/netenv/location.go",
    "content": "package netenv\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/gopacket/layers\"\n\t\"golang.org/x/net/icmp\"\n\t\"golang.org/x/net/ipv4\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\nvar (\n\t// locationTestingIPv4 holds the IP address of the server that should be\n\t// tracerouted to find the location of the device. The ping will never reach\n\t// the destination in most cases.\n\t// The selection of this IP requires sensitivity, as the IP address must be\n\t// far enough away to produce good results.\n\t// At the same time, the IP address should be common and not raise attention.\n\tlocationTestingIPv4     = \"1.1.1.1\"\n\tlocationTestingIPv4Addr *net.IPAddr\n\n\tlocations                  = &DeviceLocations{}\n\tlocationsLock              sync.Mutex\n\tgettingLocationsLock       sync.Mutex\n\tlocationNetworkChangedFlag = GetNetworkChangedFlag()\n)\n\nfunc prepLocation() (err error) {\n\tlocationTestingIPv4Addr, err = net.ResolveIPAddr(\"ip\", locationTestingIPv4)\n\treturn err\n}\n\n// DeviceLocations holds multiple device locations.\ntype DeviceLocations struct {\n\tAll []*DeviceLocation\n}\n\n// Best returns the best (most accurate) device location.\nfunc (dls *DeviceLocations) Best() *DeviceLocation {\n\tif len(dls.All) > 0 {\n\t\treturn dls.All[0]\n\t}\n\treturn nil\n}\n\n// BestV4 returns the best (most accurate) IPv4 device location.\nfunc (dls *DeviceLocations) BestV4() *DeviceLocation {\n\tfor _, loc := range dls.All {\n\t\tif loc.IPVersion == packet.IPv4 {\n\t\t\treturn loc\n\t\t}\n\t}\n\treturn nil\n}\n\n// BestV6 returns the best (most accurate) IPv6 device location.\nfunc (dls *DeviceLocations) BestV6() *DeviceLocation {\n\tfor _, loc := range dls.All {\n\t\tif loc.IPVersion == packet.IPv6 {\n\t\t\treturn loc\n\t\t}\n\t}\n\treturn nil\n}\n\n// Copy creates a copy of the locations, but not the individual entries.\nfunc (dls *DeviceLocations) Copy() *DeviceLocations {\n\tcp := &DeviceLocations{\n\t\tAll: make([]*DeviceLocation, len(locations.All)),\n\t}\n\tcopy(cp.All, locations.All)\n\n\treturn cp\n}\n\n// AddLocation adds a location.\nfunc (dls *DeviceLocations) AddLocation(dl *DeviceLocation) {\n\tif dls == nil {\n\t\treturn\n\t}\n\n\t// Add to locations, if better.\n\tvar exists bool\n\tfor i, existing := range dls.All {\n\t\tif (dl.IP == nil && existing.IP == nil) || dl.IP.Equal(existing.IP) {\n\t\t\texists = true\n\t\t\tif dl.IsMoreAccurateThan(existing) {\n\t\t\t\t// Replace\n\t\t\t\tdls.All[i] = dl\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif !exists {\n\t\tdls.All = append(dls.All, dl)\n\t}\n\n\t// Sort locations.\n\tsort.Sort(sortLocationsByAccuracy(dls.All))\n\n\tlog.Debugf(\"netenv: added new device location to IPv%d scope: %s from %s\", dl.IPVersion, dl, dl.Source)\n}\n\n// DeviceLocation represents a single IP and metadata. It must not be changed\n// once created.\ntype DeviceLocation struct {\n\tIP             net.IP\n\tIPVersion      packet.IPVersion\n\tLocation       *geoip.Location\n\tSource         DeviceLocationSource\n\tSourceAccuracy int\n}\n\n// IsMoreAccurateThan checks if the device location is more accurate than the\n// given one.\nfunc (dl *DeviceLocation) IsMoreAccurateThan(other *DeviceLocation) bool {\n\tswitch {\n\tcase dl.SourceAccuracy > other.SourceAccuracy:\n\t\t// Higher source accuracy is better.\n\t\treturn true\n\tcase dl.IP != nil && other.IP == nil:\n\t\t// Location based on IP is better than without.\n\t\treturn true\n\tcase dl.Location.AutonomousSystemNumber != 0 &&\n\t\tother.Location.AutonomousSystemNumber == 0:\n\t\t// Having an ASN is better than having none.\n\t\treturn true\n\tcase dl.Location.Country.Code != \"\" &&\n\t\tother.Location.Country.Code == \"\":\n\t\t// Having a Country is better than having none.\n\t\treturn true\n\tcase (dl.Location.Coordinates.Latitude != 0 ||\n\t\tdl.Location.Coordinates.Longitude != 0) &&\n\t\tother.Location.Coordinates.Latitude == 0 &&\n\t\tother.Location.Coordinates.Longitude == 0:\n\t\t// Having Coordinates is better than having none.\n\t\treturn true\n\tcase dl.Location.Coordinates.AccuracyRadius < other.Location.Coordinates.AccuracyRadius:\n\t\t// Higher geo accuracy is better.\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// LocationOrNil or returns the geoip location, or nil if not present.\nfunc (dl *DeviceLocation) LocationOrNil() *geoip.Location {\n\tif dl == nil {\n\t\treturn nil\n\t}\n\treturn dl.Location\n}\n\nfunc (dl *DeviceLocation) String() string {\n\tswitch {\n\tcase dl == nil:\n\t\treturn \"<none>\"\n\tcase dl.Location == nil:\n\t\treturn dl.IP.String()\n\tcase dl.Source == SourceTimezone:\n\t\treturn fmt.Sprintf(\n\t\t\t\"TZ(%.0f/%.0f)\",\n\t\t\tdl.Location.Coordinates.Latitude,\n\t\t\tdl.Location.Coordinates.Longitude,\n\t\t)\n\tdefault:\n\t\treturn fmt.Sprintf(\n\t\t\t\"%s (AS%d in %s - %s)\",\n\t\t\tdl.IP,\n\t\t\tdl.Location.AutonomousSystemNumber,\n\t\t\tdl.Location.Country.Name,\n\t\t\tdl.Location.Country.Code,\n\t\t)\n\t}\n}\n\n// DeviceLocationSource is a location source.\ntype DeviceLocationSource string\n\n// Location Sources.\nconst (\n\tSourceInterface  DeviceLocationSource = \"interface\"\n\tSourcePeer       DeviceLocationSource = \"peer\"\n\tSourceUPNP       DeviceLocationSource = \"upnp\"\n\tSourceTraceroute DeviceLocationSource = \"traceroute\"\n\tSourceTimezone   DeviceLocationSource = \"timezone\"\n\tSourceOther      DeviceLocationSource = \"other\"\n)\n\n// Accuracy returns the location accuracy of the source.\nfunc (dls DeviceLocationSource) Accuracy() int {\n\tswitch dls {\n\tcase SourceInterface:\n\t\treturn 6\n\tcase SourcePeer:\n\t\treturn 5\n\tcase SourceUPNP:\n\t\treturn 4\n\tcase SourceTraceroute:\n\t\treturn 3\n\tcase SourceOther:\n\t\treturn 2\n\tcase SourceTimezone:\n\t\treturn 1\n\tdefault:\n\t\treturn 0\n\t}\n}\n\ntype sortLocationsByAccuracy []*DeviceLocation\n\nfunc (a sortLocationsByAccuracy) Len() int           { return len(a) }\nfunc (a sortLocationsByAccuracy) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }\nfunc (a sortLocationsByAccuracy) Less(i, j int) bool { return !a[j].IsMoreAccurateThan(a[i]) }\n\n// SetInternetLocation provides the location management system with a possible Internet location.\nfunc SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) {\n\tlocationsLock.Lock()\n\tdefer locationsLock.Unlock()\n\n\treturn locations.AddIP(ip, source)\n}\n\n// AddIP adds a new location based on the given IP.\nfunc (dls *DeviceLocations) AddIP(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) {\n\t// Check if IP is global.\n\tif netutils.GetIPScope(ip) != netutils.Global {\n\t\treturn nil, false\n\t}\n\n\t// Create new location.\n\tloc := &DeviceLocation{\n\t\tIP:             ip,\n\t\tSource:         source,\n\t\tSourceAccuracy: source.Accuracy(),\n\t}\n\tif v4 := ip.To4(); v4 != nil {\n\t\tloc.IPVersion = packet.IPv4\n\t} else {\n\t\tloc.IPVersion = packet.IPv6\n\t}\n\n\t// Get geoip information, but continue if it fails.\n\tgeoLoc, err := geoip.GetLocation(ip)\n\tif err != nil {\n\t\tlog.Warningf(\"netenv: failed to get geolocation data of %s (from %s): %s\", ip, source, err)\n\t\treturn nil, false\n\t}\n\t// Only use location if there is data for it.\n\tif geoLoc.Country.Code == \"\" {\n\t\treturn nil, false\n\t}\n\tloc.Location = geoLoc\n\n\tdls.AddLocation(loc)\n\treturn loc, true\n}\n\n// GetApproximateInternetLocation returns the approximate Internet location.\n// Deprecated: Please use GetInternetLocation instead.\nfunc GetApproximateInternetLocation() (net.IP, error) {\n\tloc, ok := GetInternetLocation()\n\tif !ok || loc.Best() == nil {\n\t\treturn nil, errors.New(\"no device location data available\")\n\t}\n\treturn loc.Best().IP, nil\n}\n\n// GetInternetLocation returns the possible device locations.\nfunc GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) {\n\tgettingLocationsLock.Lock()\n\tdefer gettingLocationsLock.Unlock()\n\n\t// Check if the network changed, if not, return cache.\n\tif !locationNetworkChangedFlag.IsSet() {\n\t\tlocationsLock.Lock()\n\t\tdefer locationsLock.Unlock()\n\t\treturn locations.Copy(), true\n\t}\n\tlocationNetworkChangedFlag.Refresh()\n\n\t// Create new location list.\n\tdls := &DeviceLocations{}\n\tlog.Debug(\"netenv: getting new device locations\")\n\n\t// Check interfaces for global addresses.\n\tv4ok, v6ok := getLocationFromInterfaces(dls)\n\n\t// Try other methods for missing locations.\n\tif !v4ok {\n\t\t_, err := getLocationFromTraceroute(dls)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"netenv: failed to get IPv4 device location from traceroute: %s\", err)\n\t\t} else {\n\t\t\tv4ok = true\n\t\t}\n\n\t\t// Get location from timezone as final fallback.\n\t\tif !v4ok {\n\t\t\tgetLocationFromTimezone(dls, packet.IPv4)\n\t\t}\n\t}\n\tif !v6ok && IPv6Enabled() {\n\t\t// TODO: Find more ways to get IPv6 device location\n\n\t\t// Get location from timezone as final fallback.\n\t\tgetLocationFromTimezone(dls, packet.IPv6)\n\t}\n\n\t// As a last guard, make sure there is at least one location in the list.\n\tif len(dls.All) == 0 {\n\t\tgetLocationFromTimezone(dls, packet.IPv4)\n\t}\n\n\t// Set new locations.\n\tlocationsLock.Lock()\n\tdefer locationsLock.Unlock()\n\tlocations = dls\n\n\t// Return gathered locations.\n\treturn locations.Copy(), true\n}\n\nfunc getLocationFromInterfaces(dls *DeviceLocations) (v4ok, v6ok bool) {\n\tglobalIPv4, globalIPv6, err := GetAssignedGlobalAddresses()\n\tif err != nil {\n\t\tlog.Warningf(\"netenv: location: failed to get assigned global addresses: %s\", err)\n\t\treturn false, false\n\t}\n\tfor _, ip := range globalIPv4 {\n\t\tif _, ok := dls.AddIP(ip, SourceInterface); ok {\n\t\t\tv4ok = true\n\t\t}\n\t}\n\tfor _, ip := range globalIPv6 {\n\t\tif _, ok := dls.AddIP(ip, SourceInterface); ok {\n\t\t\tv6ok = true\n\t\t}\n\t}\n\n\treturn\n}\n\n// TODO: Check feasibility of getting the external IP via UPnP.\n/*\nfunc getLocationFromUPnP() (ok bool) {\n\t// Endoint: urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\n\t// A first test showed that a router did offer that endpoint, but did not\n\t// return an IP address.\n\treturn false\n}\n*/\n\nfunc getLocationFromTraceroute(dls *DeviceLocations) (dl *DeviceLocation, err error) {\n\t// Create connection.\n\tconn, err := icmp.ListenPacket(\"ip4:icmp\", \"\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open icmp conn: %w\", err)\n\t}\n\tv4Conn := conn.IPv4PacketConn()\n\n\t// Generate a random ID for the ICMP packets.\n\tgeneratedID, err := rng.Number(0xFFFF) // uint16\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate icmp msg ID: %w\", err)\n\t}\n\tmsgID := int(generatedID)\n\tvar msgSeq int\n\n\t// Create ICMP message body.\n\tpingMessage := icmp.Message{\n\t\tType: ipv4.ICMPTypeEcho,\n\t\tCode: 0,\n\t\tBody: &icmp.Echo{\n\t\t\tID:   msgID,\n\t\t\tSeq:  msgSeq, // Is increased before marshalling.\n\t\t\tData: []byte{},\n\t\t},\n\t}\n\tmaxHops := 4 // add one for every reply that is not global\n\n\t// Get additional listener for ICMP messages via the firewall.\n\ticmpPacketsViaFirewall, doneWithListeningToICMP := ListenToICMP(locationTestingIPv4Addr.IP)\n\tdefer doneWithListeningToICMP()\n\nnextHop:\n\tfor i := 1; i <= maxHops; i++ {\n\t\tminSeq := msgSeq + 1\n\n\trepeatHop:\n\t\tfor j := 1; j <= 2; j++ { // Try every hop twice.\n\t\t\t// Increase sequence number.\n\t\t\tmsgSeq++\n\t\t\tpingMessage.Body.(*icmp.Echo).Seq = msgSeq //nolint:forcetypeassert // Can only be *icmp.Echo.\n\n\t\t\t// Make packet data.\n\t\t\tpingPacket, err := pingMessage.Marshal(nil)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to build icmp packet: %w\", err)\n\t\t\t}\n\n\t\t\t// Set TTL on IP packet.\n\t\t\terr = v4Conn.SetTTL(i)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to set icmp packet TTL: %w\", err)\n\t\t\t}\n\n\t\t\t// Send ICMP packet.\n\t\t\t// Try to send three times, as this can be flaky.\n\t\tsendICMP:\n\t\t\tfor range 3 {\n\t\t\t\t_, err = conn.WriteTo(pingPacket, locationTestingIPv4Addr)\n\t\t\t\tif err == nil {\n\t\t\t\t\tbreak sendICMP\n\t\t\t\t}\n\t\t\t\ttime.Sleep(30 * time.Millisecond)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to send icmp packet: %w\", err)\n\t\t\t}\n\n\t\t\t// Listen for replies of the ICMP packet.\n\t\tlisten:\n\t\t\tfor {\n\t\t\t\tremoteIP, icmpPacket, ok := recvICMP(i, icmpPacketsViaFirewall)\n\t\t\t\tif !ok {\n\t\t\t\t\t// Timed out.\n\t\t\t\t\tcontinue repeatHop\n\t\t\t\t}\n\n\t\t\t\t// Pre-filter by message type.\n\t\t\t\tswitch icmpPacket.TypeCode.Type() {\n\t\t\t\tcase layers.ICMPv4TypeEchoReply:\n\t\t\t\t\t// Check if the ID and sequence match.\n\t\t\t\t\tif icmpPacket.Id != uint16(msgID) {\n\t\t\t\t\t\tcontinue listen\n\t\t\t\t\t}\n\t\t\t\t\tif icmpPacket.Seq < uint16(minSeq) {\n\t\t\t\t\t\tcontinue listen\n\t\t\t\t\t}\n\t\t\t\t\t// We received a reply, so we did not trigger a time exceeded response on the way.\n\t\t\t\t\t// This means we were not able to find the nearest router to us.\n\t\t\t\t\treturn nil, errors.New(\"received final echo reply without time exceeded messages\")\n\t\t\t\tcase layers.ICMPv4TypeDestinationUnreachable,\n\t\t\t\t\tlayers.ICMPv4TypeTimeExceeded:\n\t\t\t\t\t// Continue processing.\n\t\t\t\tdefault:\n\t\t\t\t\tcontinue listen\n\t\t\t\t}\n\n\t\t\t\t// Parse copy of origin icmp packet that triggered the error.\n\t\t\t\tif len(icmpPacket.Payload) != ipv4.HeaderLen+8 {\n\t\t\t\t\tcontinue listen\n\t\t\t\t}\n\t\t\t\toriginalMessage, err := icmp.ParseMessage(1, icmpPacket.Payload[ipv4.HeaderLen:])\n\t\t\t\tif err != nil {\n\t\t\t\t\tcontinue listen\n\t\t\t\t}\n\t\t\t\toriginalEcho, ok := originalMessage.Body.(*icmp.Echo)\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue listen\n\t\t\t\t}\n\t\t\t\t// Check if the ID and sequence match.\n\t\t\t\tif originalEcho.ID != msgID {\n\t\t\t\t\tcontinue listen\n\t\t\t\t}\n\t\t\t\tif originalEcho.Seq < minSeq {\n\t\t\t\t\tcontinue listen\n\t\t\t\t}\n\n\t\t\t\t// React based on message type.\n\t\t\t\tswitch icmpPacket.TypeCode.Type() {\n\t\t\t\tcase layers.ICMPv4TypeDestinationUnreachable:\n\t\t\t\t\t// We have received a valid destination unreachable response, abort.\n\t\t\t\t\treturn nil, errors.New(\"destination unreachable\")\n\n\t\t\t\tcase layers.ICMPv4TypeTimeExceeded:\n\t\t\t\t\t// We have received a valid time exceeded error.\n\t\t\t\t\t// If message came from a global unicast, us it!\n\t\t\t\t\tif netutils.GetIPScope(remoteIP) == netutils.Global {\n\t\t\t\t\t\tdl, ok := dls.AddIP(remoteIP, SourceTraceroute)\n\t\t\t\t\t\tif !ok {\n\t\t\t\t\t\t\treturn nil, errors.New(\"invalid IP address\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn dl, nil\n\t\t\t\t\t}\n\n\t\t\t\t\t// Add one max hop for every reply that was not global.\n\t\t\t\t\tmaxHops++\n\n\t\t\t\t\t// Otherwise, continue.\n\t\t\t\t\tcontinue nextHop\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// We did not receive anything actionable.\n\treturn nil, errors.New(\"did not receive any actionable ICMP reply\")\n}\n\nfunc recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) (\n\tremoteIP net.IP, imcpPacket *layers.ICMPv4, ok bool,\n) {\n\tfor {\n\t\tselect {\n\t\tcase pkt := <-icmpPacketsViaFirewall:\n\t\t\tif pkt.IsOutbound() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif pkt.Layers() == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ticmpLayer := pkt.Layers().Layer(layers.LayerTypeICMPv4)\n\t\t\tif icmpLayer == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ticmp4, ok := icmpLayer.(*layers.ICMPv4)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn pkt.Info().RemoteIP(), icmp4, true\n\n\t\tcase <-time.After(time.Duration(currentHop*20+100) * time.Millisecond):\n\t\t\treturn nil, nil, false\n\t\t}\n\t}\n}\n\nfunc getLocationFromTimezone(dls *DeviceLocations, ipVersion packet.IPVersion) {\n\t// Create base struct.\n\ttzLoc := &DeviceLocation{\n\t\tIPVersion:      ipVersion,\n\t\tLocation:       &geoip.Location{},\n\t\tSource:         SourceTimezone,\n\t\tSourceAccuracy: SourceTimezone.Accuracy(),\n\t}\n\n\t// Calculate longitude based on current timezone.\n\t_, offsetSeconds := time.Now().Zone()\n\ttzLoc.Location.Coordinates.AccuracyRadius = 1000\n\ttzLoc.Location.Coordinates.Latitude = 48\n\ttzLoc.Location.Coordinates.Longitude = float64(offsetSeconds) / 43200 * 180\n\n\tdls.AddLocation(tzLoc)\n}\n"
  },
  {
    "path": "service/netenv/location_default.go",
    "content": "//go:build !windows\n\npackage netenv\n\nimport \"net\"\n\nfunc newICMPListener(_ string) (net.PacketConn, error) { //nolint:unused,deadcode // TODO: clean with Windows code later.\n\treturn net.ListenPacket(\"ip4:icmp\", \"0.0.0.0\")\n}\n"
  },
  {
    "path": "service/netenv/location_test.go",
    "content": "package netenv\n\nimport (\n\t\"flag\"\n\t\"testing\"\n)\n\nvar privileged bool\n\nfunc init() {\n\tflag.BoolVar(&privileged, \"privileged\", false, \"run tests that require root/admin privileges\")\n}\n\nfunc TestGetInternetLocation(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\tif !privileged {\n\t\tt.Skip(\"skipping privileged test, active with -privileged argument\")\n\t}\n\n\tloc, ok := GetInternetLocation()\n\tif !ok {\n\t\tt.Fatal(\"GetApproximateInternetLocation failed\")\n\t}\n\tt.Logf(\"GetApproximateInternetLocation: %+v\", loc)\n}\n"
  },
  {
    "path": "service/netenv/location_windows.go",
    "content": "package netenv\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"syscall\"\n\t\"unsafe\"\n)\n\n// Windows specific constants for the WSAIoctl interface.\n//nolint:golint,stylecheck\nconst (\n\tSIO_RCVALL = syscall.IOC_IN | syscall.IOC_VENDOR | 1\n\n\tRCVALL_OFF             = 0\n\tRCVALL_ON              = 1\n\tRCVALL_SOCKETLEVELONLY = 2\n\tRCVALL_IPLEVEL         = 3\n)\n\nfunc newICMPListener(address string) (net.PacketConn, error) {\n\t// This is an attempt to work around the problem described here:\n\t// https://github.com/golang/go/issues/38427\n\n\t// First, get the correct local interface address, as SIO_RCVALL can't be set on a 0.0.0.0 listeners.\n\tdialedConn, err := net.Dial(\"ip4:icmp\", address)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to dial: %s\", err)\n\t}\n\tlocalAddr := dialedConn.LocalAddr()\n\tdialedConn.Close()\n\n\t// Configure the setup routine in order to extract the socket handle.\n\tvar socketHandle syscall.Handle\n\tcfg := net.ListenConfig{\n\t\tControl: func(network, address string, c syscall.RawConn) error {\n\t\t\treturn c.Control(func(s uintptr) {\n\t\t\t\tsocketHandle = syscall.Handle(s)\n\t\t\t})\n\t\t},\n\t}\n\n\t// Bind to interface.\n\tconn, err := cfg.ListenPacket(context.Background(), \"ip4:icmp\", localAddr.String())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Set socket option to receive all packets, such as ICMP error messages.\n\t// This is somewhat dirty, as there is guarantee that socketHandle is still valid.\n\t// WARNING: The Windows Firewall might just drop the incoming packets you might want to receive.\n\tunused := uint32(0) // Documentation states that this is unused, but WSAIoctl fails without it.\n\tflag := uint32(RCVALL_IPLEVEL)\n\tsize := uint32(unsafe.Sizeof(flag))\n\terr = syscall.WSAIoctl(socketHandle, SIO_RCVALL, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &unused, nil, 0)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to set socket to listen to all packests: %s\", os.NewSyscallError(\"WSAIoctl\", err))\n\t}\n\n\treturn conn, nil\n}\n"
  },
  {
    "path": "service/netenv/main.go",
    "content": "package netenv\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\n// Event Names.\nconst (\n\tModuleName               = \"netenv\"\n\tNetworkChangedEvent      = \"network changed\"\n\tOnlineStatusChangedEvent = \"online status changed\"\n)\n\ntype NetEnv struct {\n\tm        *mgr.Manager\n\tinstance instance\n\n\tEventNetworkChange      *mgr.EventMgr[struct{}]\n\tEventOnlineStatusChange *mgr.EventMgr[OnlineStatus]\n}\n\nfunc (ne *NetEnv) Manager() *mgr.Manager {\n\treturn ne.m\n}\n\nfunc (ne *NetEnv) Start() error {\n\tne.m.Go(\n\t\t\"monitor network changes\",\n\t\tmonitorNetworkChanges,\n\t)\n\n\tne.m.Go(\n\t\t\"monitor online status\",\n\t\tmonitorOnlineStatus,\n\t)\n\n\treturn nil\n}\n\nfunc (ne *NetEnv) Stop() error {\n\treturn nil\n}\n\nfunc prep() error {\n\tcheckForIPv6Stack()\n\n\tif err := registerAPIEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := prepOnlineStatus(); err != nil {\n\t\treturn err\n\t}\n\n\treturn prepLocation()\n}\n\nvar ipv6Enabled = abool.NewBool(true)\n\n// IPv6Enabled returns whether the device has an active IPv6 stack.\n// This is only checked once on startup in order to maintain consistency.\nfunc IPv6Enabled() bool {\n\treturn ipv6Enabled.IsSet()\n}\n\nfunc checkForIPv6Stack() {\n\t_, v6IPs, err := GetAssignedAddresses()\n\tif err != nil {\n\t\tlog.Warningf(\"netenv: failed to get assigned addresses to check for ipv6 stack: %s\", err)\n\t\treturn\n\t}\n\n\t// Set IPv6 as enabled if any IPv6 addresses are found.\n\tipv6Enabled.SetTo(len(v6IPs) > 0)\n}\n\nvar (\n\tmodule     *NetEnv\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new NetEnv module.\nfunc New(instance instance) (*NetEnv, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"NetEnv\")\n\tmodule = &NetEnv{\n\t\tm:        m,\n\t\tinstance: instance,\n\n\t\tEventNetworkChange:      mgr.NewEventMgr[struct{}](\"network change\", m),\n\t\tEventOnlineStatusChange: mgr.NewEventMgr[OnlineStatus](\"online status change\", m),\n\t}\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tIntelUpdates() *updates.Updater\n}\n"
  },
  {
    "path": "service/netenv/main_test.go",
    "content": "package netenv\n\n// func TestMain(m *testing.M) {\n// \tpmtesting.TestMain(m, module)\n// }\n"
  },
  {
    "path": "service/netenv/network-change.go",
    "content": "package netenv\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha1\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar (\n\tnetworkChangeCheckTrigger   = make(chan struct{}, 1)\n\tnetworkChangedBroadcastFlag = utils.NewBroadcastFlag()\n)\n\n// GetNetworkChangedFlag returns a flag to be notified about a network change.\nfunc GetNetworkChangedFlag() *utils.Flag {\n\treturn networkChangedBroadcastFlag.NewFlag()\n}\n\nfunc notifyOfNetworkChange() {\n\tnetworkChangedBroadcastFlag.NotifyAndReset()\n\tmodule.EventNetworkChange.Submit(struct{}{})\n}\n\n// TriggerNetworkChangeCheck triggers a network change check.\nfunc TriggerNetworkChangeCheck() {\n\tselect {\n\tcase networkChangeCheckTrigger <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc monitorNetworkChanges(ctx *mgr.WorkerCtx) error {\n\tvar lastNetworkChecksum []byte\n\nserviceLoop:\n\tfor {\n\t\ttrigger := false\n\n\t\tvar ticker *time.Ticker\n\t\tif Online() {\n\t\t\tticker = monitorNetworkChangeOnlineTicker\n\t\t} else {\n\t\t\tticker = monitorNetworkChangeOfflineTicker\n\t\t}\n\n\t\t// wait for trigger\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-networkChangeCheckTrigger:\n\t\t\t// don't fall through because the online change check\n\t\t\t// triggers the networkChangeCheck this way. If we would set\n\t\t\t// trigger == true we would trigger the online check again\n\t\t\t// resulting in a loop of pointless checks.\n\t\tcase <-ticker.C:\n\t\t\ttrigger = true\n\t\t}\n\n\t\t// check network for changes\n\t\t// create hashsum of current network config\n\t\thasher := sha1.New() //nolint:gosec // not used for security\n\t\tinterfaces, err := osGetNetworkInterfaces()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"netenv: failed to get interfaces: %s\", err)\n\t\t\tcontinue\n\t\t}\n\t\tfor _, iface := range interfaces {\n\t\t\t_, _ = io.WriteString(hasher, iface.Name)\n\t\t\t// log.Tracef(\"adding: %s\", iface.Name)\n\t\t\t_, _ = io.WriteString(hasher, iface.Flags.String())\n\t\t\t// log.Tracef(\"adding: %s\", iface.Flags.String())\n\t\t\taddrs, err := iface.Addrs()\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"netenv: failed to get addrs from interface %s: %s\", iface.Name, err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, addr := range addrs {\n\t\t\t\t_, _ = io.WriteString(hasher, addr.String())\n\t\t\t\t// log.Tracef(\"adding: %s\", addr.String())\n\t\t\t}\n\t\t}\n\t\tnewChecksum := hasher.Sum(nil)\n\n\t\t// compare checksum with last\n\t\tif !bytes.Equal(lastNetworkChecksum, newChecksum) {\n\t\t\tif len(lastNetworkChecksum) == 0 {\n\t\t\t\tlastNetworkChecksum = newChecksum\n\t\t\t\tcontinue serviceLoop\n\t\t\t}\n\t\t\tlastNetworkChecksum = newChecksum\n\n\t\t\tif trigger {\n\t\t\t\tTriggerOnlineStatusInvestigation()\n\t\t\t}\n\t\t\tnotifyOfNetworkChange()\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "service/netenv/notes.md",
    "content": "\n\nIntel:\n- First ever request: use first resolver as selected\n- If resolver fails:\n    - stop all requesting\n    - get network status\n        - if failed: do nothing, return offline error\n    - check list front to back, use first resolver that resolves one.one.one.one correctly\n\nNetEnv:\n- check for intercepted HTTP Request requests\n- if fails on:\n    - connection establishment: OFFLINE\n    - \n- check for intercepted HTTPS Request requests\n\n\n- check for intercepted DNS requests\n"
  },
  {
    "path": "service/netenv/online-status.go",
    "content": "package netenv\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\n// OnlineStatus represent a state of connectivity to the Internet.\ntype OnlineStatus uint8\n\n// Online Status Values.\nconst (\n\tStatusUnknown    OnlineStatus = 0\n\tStatusOffline    OnlineStatus = 1\n\tStatusLimited    OnlineStatus = 2 // local network only\n\tStatusPortal     OnlineStatus = 3 // there seems to be an internet connection, but we are being intercepted, possibly by a captive portal\n\tStatusSemiOnline OnlineStatus = 4 // we seem to online, but without full connectivity\n\tStatusOnline     OnlineStatus = 5\n)\n\n// Online Status and Resolver.\nvar (\n\tPortalTestIP  = net.IPv4(192, 0, 2, 1)\n\tPortalTestURL = fmt.Sprintf(\"http://%s/\", PortalTestIP)\n\n\t// IP address -> 100.127.247.245 is a special ip used by the android VPN service. Must be ignored during online check.\n\tIgnoreIPsInOnlineStatusCheck = []net.IP{net.IPv4(100, 127, 247, 245)}\n\n\tDNSTestDomain     = \"online-check.safing.io.\"\n\tDNSTestExpectedIP = net.IPv4(0, 65, 67, 75) // Ascii: \\0ACK\n\tDNSTestQueryFunc  func(ctx context.Context, fdqn string) (ips []net.IP, ok bool, err error)\n\n\tConnectedToSPN = abool.New()\n\tConnectedToDNS = abool.New()\n\n\t// SpecialCaptivePortalDomain is the domain name used to point to the detected captive portal IP\n\t// or the captive portal test IP. The default value should be overridden by the resolver package,\n\t// which defines the custom internal domain name to use.\n\tSpecialCaptivePortalDomain = \"captiveportal.invalid.\"\n\n\t// ConnectivityDomains holds all connectivity domains. This slice must not be modified.\n\tConnectivityDomains = []string{\n\t\tSpecialCaptivePortalDomain,\n\n\t\t// Windows\n\t\t\"dns.msftncsi.com.\", // DNS Check\n\t\t\"msftncsi.com.\",     // Older\n\t\t\"www.msftncsi.com.\",\n\t\t\"microsoftconnecttest.com.\", // Newer\n\t\t\"www.microsoftconnecttest.com.\",\n\t\t\"ipv6.microsoftconnecttest.com.\",\n\t\t// https://de.wikipedia.org/wiki/Captive_Portal\n\t\t// https://docs.microsoft.com/en-us/windows-hardware/drivers/mobilebroadband/captive-portals\n\t\t// TODO: read value from registry: HKLM:\\SYSTEM\\CurrentControlSet\\Services\\NlaSvc\\Parameters\\Internet\n\n\t\t// Apple\n\t\t\"captive.apple.com.\",\n\t\t// https://de.wikipedia.org/wiki/Captive_Portal\n\n\t\t// Linux\n\t\t\"connectivity-check.ubuntu.com.\", // Ubuntu\n\t\t\"nmcheck.gnome.org.\",             // Gnome DE\n\t\t\"network-test.debian.org.\",       // Debian\n\t\t\"204.pop-os.org.\",                // Pop OS\n\t\t\"conncheck.opensuse.org.\",        // OpenSUSE\n\t\t\"ping.archlinux.org\",             // Arch\n\t\t// There are probably a lot more domains for all the Linux Distro/DE Variants. Please raise issues and/or submit PRs!\n\t\t// https://github.com/solus-project/budgie-desktop/issues/807\n\t\t// https://www.lguruprasad.in/blog/2015/07/21/enabling-captive-portal-detection-in-gnome-3-14-on-debian-jessie/\n\t\t// TODO: read value from NetworkManager config: /etc/NetworkManager/conf.d/*.conf\n\n\t\t// Android\n\t\t\"connectivitycheck.gstatic.com.\",\n\t\t// https://de.wikipedia.org/wiki/Captive_Portal\n\n\t\t// Other\n\t\t\"neverssl.com.\",             // Common Community Service\n\t\t\"detectportal.firefox.com.\", // Firefox\n\t}\n\n\tparsedPortalTestURL *url.URL\n)\n\nfunc prepOnlineStatus() (err error) {\n\tparsedPortalTestURL, err = url.Parse(PortalTestURL)\n\treturn err\n}\n\n// IsConnectivityDomain checks whether the given domain (fqdn) is used for any\n// connectivity related network connections and should always be resolved using\n// the network assigned DNS server.\nfunc IsConnectivityDomain(domain string) bool {\n\tif domain == \"\" {\n\t\treturn false\n\t}\n\n\tfor _, connectivityDomain := range ConnectivityDomains {\n\t\tif domain == connectivityDomain {\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// Check for captive portal domain.\n\tcaptivePortal := GetCaptivePortal()\n\tif captivePortal.Domain != \"\" &&\n\t\tdomain == captivePortal.Domain {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (os OnlineStatus) String() string {\n\tswitch os {\n\tcase StatusOffline:\n\t\treturn \"Offline\"\n\tcase StatusLimited:\n\t\treturn \"Limited\"\n\tcase StatusPortal:\n\t\treturn \"Portal\"\n\tcase StatusSemiOnline:\n\t\treturn \"SemiOnline\"\n\tcase StatusOnline:\n\t\treturn \"Online\"\n\tcase StatusUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\nvar (\n\tonlineStatus           *int32\n\tonlineStatusQuickCheck = abool.NewBool(false)\n\n\tonlineStatusInvestigationTrigger    = make(chan struct{}, 1)\n\tonlineStatusInvestigationInProgress = abool.NewBool(false)\n\tonlineStatusInvestigationWg         sync.WaitGroup\n\tonlineStatusNotification            *notifications.Notification\n\n\tcaptivePortal             = &CaptivePortal{}\n\tcaptivePortalLock         sync.Mutex\n\tcaptivePortalNotification *notifications.Notification\n)\n\n// CaptivePortal holds information about a detected captive portal.\ntype CaptivePortal struct {\n\tURL    string\n\tDomain string\n\tIP     net.IP\n}\n\nfunc init() {\n\tvar onlineStatusValue int32\n\tonlineStatus = &onlineStatusValue\n}\n\n// Online returns true if online status is either SemiOnline or Online.\nfunc Online() bool {\n\treturn onlineStatusQuickCheck.IsSet()\n}\n\n// GetOnlineStatus returns the current online stats.\nfunc GetOnlineStatus() OnlineStatus {\n\treturn OnlineStatus(atomic.LoadInt32(onlineStatus))\n}\n\n// CheckAndGetOnlineStatus triggers a new online status check and returns the result.\nfunc CheckAndGetOnlineStatus() OnlineStatus {\n\t// trigger new investigation\n\tTriggerOnlineStatusInvestigation()\n\t// wait for completion\n\tonlineStatusInvestigationWg.Wait()\n\t// return current status\n\treturn GetOnlineStatus()\n}\n\nfunc updateOnlineStatus(status OnlineStatus, portalURL *url.URL, comment string) {\n\tchanged := false\n\n\t// Update online status.\n\tcurrentStatus := atomic.LoadInt32(onlineStatus)\n\tif status != OnlineStatus(currentStatus) && atomic.CompareAndSwapInt32(onlineStatus, currentStatus, int32(status)) {\n\t\t// status changed!\n\t\tonlineStatusQuickCheck.SetTo(\n\t\t\tstatus == StatusOnline || status == StatusSemiOnline,\n\t\t)\n\t\tchanged = true\n\t}\n\n\t// Update captive portal.\n\tsetCaptivePortal(portalURL)\n\n\t// Trigger events.\n\tif changed {\n\t\tmodule.EventOnlineStatusChange.Submit(status)\n\t\tif status == StatusPortal {\n\t\t\tlog.Infof(`netenv: setting online status to %s at \"%s\" (%s)`, status, portalURL, comment)\n\t\t} else {\n\t\t\tlog.Infof(\"netenv: setting online status to %s (%s)\", status, comment)\n\t\t}\n\t\tTriggerNetworkChangeCheck()\n\n\t\t// Notify user.\n\t\tnotifyOnlineStatus(status)\n\n\t\t// Trigger update check when coming (semi) online.\n\t\tif Online() {\n\t\t\tmodule.instance.IntelUpdates().EventResourcesUpdated.Submit(struct{}{})\n\t\t}\n\t}\n}\n\nfunc notifyOnlineStatus(status OnlineStatus) {\n\tvar eventID, title, message string\n\n\t// Check if status is worth notifying.\n\tswitch status { //nolint:exhaustive // Checking for selection only.\n\tcase StatusOffline:\n\t\teventID = \"netenv:online-status:offline\"\n\t\ttitle = \"Device is Offline\"\n\t\tmessage = \"Portmaster did not detect any network connectivity.\"\n\tcase StatusLimited:\n\t\teventID = \"netenv:online-status:limited\"\n\t\ttitle = \"Limited network connectivity.\"\n\t\tmessage = \"Portmaster did detect local network connectivity, but could not detect connectivity to the Internet.\"\n\tdefault:\n\t\t// Delete notification, if present.\n\t\tif onlineStatusNotification != nil {\n\t\t\tonlineStatusNotification.Delete()\n\t\t\tonlineStatusNotification = nil\n\t\t}\n\t\treturn\n\t}\n\n\t// Update notification if not present or online status changed.\n\tswitch {\n\tcase onlineStatusNotification == nil:\n\t\t// Continue creating new notification.\n\tcase onlineStatusNotification.EventID == eventID:\n\t\t// Notification stays the same, stick with the old one.\n\t\treturn\n\tdefault:\n\t\t// Delete old notification before triggering updated one.\n\t\tonlineStatusNotification.Delete()\n\t}\n\n\t// Create update status notification.\n\tonlineStatusNotification = notifications.Notify(&notifications.Notification{\n\t\tEventID: eventID,\n\t\tType:    notifications.Info,\n\t\tTitle:   title,\n\t\tMessage: message,\n\t})\n}\n\nfunc setCaptivePortal(portalURL *url.URL) {\n\tcaptivePortalLock.Lock()\n\tdefer captivePortalLock.Unlock()\n\n\t// Delete captive portal if no url is supplied.\n\tif portalURL == nil {\n\t\tcaptivePortal = &CaptivePortal{}\n\t\tif captivePortalNotification != nil {\n\t\t\tcaptivePortalNotification.Delete()\n\t\t\tcaptivePortalNotification = nil\n\t\t}\n\t\treturn\n\t}\n\n\t// Only set captive portal once per detection.\n\tif captivePortal.URL != \"\" {\n\t\treturn\n\t}\n\n\t// Compile captive portal data.\n\tcaptivePortal = &CaptivePortal{\n\t\tURL: portalURL.String(),\n\t}\n\tportalIP := net.ParseIP(portalURL.Hostname())\n\tif portalIP != nil {\n\t\tcaptivePortal.IP = portalIP\n\t\tcaptivePortal.Domain = SpecialCaptivePortalDomain\n\t} else {\n\t\tcaptivePortal.Domain = portalURL.Hostname()\n\t}\n\n\t// Notify user about portal.\n\tcaptivePortalNotification = notifications.Notify(&notifications.Notification{\n\t\tEventID:      \"netenv:captive-portal\",\n\t\tType:         notifications.Info,\n\t\tTitle:        \"Captive Portal Detected\",\n\t\tMessage:      \"The Portmaster detected a captive portal. You might experience limited network connectivity until the portal is handled.\",\n\t\tShowOnSystem: true,\n\t\tEventData:    captivePortal,\n\t\tAvailableActions: []*notifications.Action{\n\t\t\t{\n\t\t\t\tText:    \"Open Portal\",\n\t\t\t\tType:    notifications.ActionTypeOpenURL,\n\t\t\t\tPayload: captivePortal.URL,\n\t\t\t},\n\t\t\t{\n\t\t\t\tID:   \"ack\",\n\t\t\t\tText: \"Ignore\",\n\t\t\t},\n\t\t},\n\t})\n}\n\n// GetCaptivePortal returns the current captive portal. The returned struct must not be edited.\nfunc GetCaptivePortal() *CaptivePortal {\n\tcaptivePortalLock.Lock()\n\tdefer captivePortalLock.Unlock()\n\n\treturn captivePortal\n}\n\n// ReportSuccessfulConnection hints the online status monitoring system that a connection attempt was successful.\nfunc ReportSuccessfulConnection() {\n\tif !onlineStatusQuickCheck.IsSet() {\n\t\tTriggerOnlineStatusInvestigation()\n\t}\n}\n\n// ReportFailedConnection hints the online status monitoring system that a connection attempt has failed. This function has extremely low overhead and may be called as much as wanted.\nfunc ReportFailedConnection() {\n\tif onlineStatusQuickCheck.IsSet() {\n\t\tTriggerOnlineStatusInvestigation()\n\t}\n}\n\n// TriggerOnlineStatusInvestigation manually triggers the online status check.\n// It will not trigger it again, if it is already in progress.\nfunc TriggerOnlineStatusInvestigation() {\n\tif onlineStatusInvestigationInProgress.SetToIf(false, true) {\n\t\tonlineStatusInvestigationWg.Add(1)\n\t}\n\n\tselect {\n\tcase onlineStatusInvestigationTrigger <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc monitorOnlineStatus(ctx *mgr.WorkerCtx) error {\n\tTriggerOnlineStatusInvestigation()\n\tfor {\n\t\t// wait for trigger\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-onlineStatusInvestigationTrigger:\n\t\tcase <-getDynamicStatusTrigger():\n\t\t}\n\n\t\t// enable waiting\n\t\tif onlineStatusInvestigationInProgress.SetToIf(false, true) {\n\t\t\tonlineStatusInvestigationWg.Add(1)\n\t\t}\n\n\t\tcheckOnlineStatus(ctx.Ctx())\n\n\t\t// finished!\n\t\tonlineStatusInvestigationWg.Done()\n\t\tonlineStatusInvestigationInProgress.UnSet()\n\t}\n}\n\nfunc getDynamicStatusTrigger() <-chan time.Time {\n\tswitch GetOnlineStatus() {\n\tcase StatusOffline:\n\t\t// Will also be triggered by network change.\n\t\treturn time.After(10 * time.Second)\n\tcase StatusLimited, StatusPortal:\n\t\t// Change will not be detected otherwise, but impact is minor.\n\t\treturn time.After(5 * time.Second)\n\tcase StatusSemiOnline:\n\t\t// Very small impact.\n\t\treturn time.After(60 * time.Second)\n\tcase StatusOnline:\n\t\t// Don't check until resolver reports problems.\n\t\treturn nil\n\tcase StatusUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn time.After(5 * time.Minute)\n\t}\n}\n\nfunc ipInList(list []net.IP, ip net.IP) bool {\n\tfor _, ignoreIP := range list {\n\t\tif ignoreIP.Equal(ip) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc checkOnlineStatus(ctx context.Context) {\n\t// TODO: implement more methods\n\t/*status, err := getConnectivityStateFromDbus()\n\tif err != nil {\n\t\tlog.Warningf(\"environment: could not get connectivity: %s\", err)\n\t\tsetConnectivity(StatusUnknown)\n\t\treturn StatusUnknown\n\t}*/\n\n\t// 0) check if connected to SPN and/or DNS.\n\n\tif ConnectedToSPN.IsSet() {\n\t\tupdateOnlineStatus(StatusOnline, nil, \"connected to SPN\")\n\t\treturn\n\t}\n\n\tif ConnectedToDNS.IsSet() {\n\t\tupdateOnlineStatus(StatusOnline, nil, \"connected to DNS\")\n\t\treturn\n\t}\n\n\t// 1) check for addresses\n\n\tipv4, ipv6, err := GetAssignedAddresses()\n\tif err != nil {\n\t\tlog.Warningf(\"netenv: failed to get assigned network addresses: %s\", err)\n\t} else {\n\t\tvar lan bool\n\n\t\tfor _, ip := range ipv4 {\n\t\t\t// Ignore IP if it is in the online check ignore list.\n\t\t\tif ipInList(IgnoreIPsInOnlineStatusCheck, ip) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch netutils.GetIPScope(ip) { //nolint:exhaustive // Checking to specific values only.\n\t\t\tcase netutils.SiteLocal:\n\t\t\t\tlan = true\n\t\t\tcase netutils.Global:\n\t\t\t\t// we _are_ the Internet ;)\n\t\t\t\tupdateOnlineStatus(StatusOnline, nil, \"global IPv4 interface detected\")\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tfor _, ip := range ipv6 {\n\t\t\t// Ignore IP if it is in the online check ignore list.\n\t\t\tif ipInList(IgnoreIPsInOnlineStatusCheck, ip) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch netutils.GetIPScope(ip) { //nolint:exhaustive // Checking to specific values only.\n\t\t\tcase netutils.SiteLocal, netutils.Global:\n\t\t\t\t// IPv6 global addresses are also used in local networks\n\t\t\t\tlan = true\n\t\t\t}\n\t\t}\n\t\tif !lan {\n\t\t\tupdateOnlineStatus(StatusOffline, nil, \"no local or global interfaces detected\")\n\t\t\treturn\n\t\t}\n\t}\n\n\t// 2) try a http request\n\n\tdialer := &net.Dialer{\n\t\tTimeout:   5 * time.Second,\n\t\tLocalAddr: getLocalAddr(\"tcp\"),\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tDialContext:        dialer.DialContext,\n\t\t\tDisableKeepAlives:  true,\n\t\t\tDisableCompression: true,\n\t\t\tWriteBufferSize:    1024,\n\t\t\tReadBufferSize:     1024,\n\t\t},\n\t\tCheckRedirect: func(req *http.Request, via []*http.Request) error {\n\t\t\treturn http.ErrUseLastResponse\n\t\t},\n\t\tTimeout: 1 * time.Second,\n\t}\n\n\trequest := (&http.Request{\n\t\tMethod: http.MethodGet,\n\t\tURL:    parsedPortalTestURL,\n\t\tClose:  true,\n\t}).WithContext(ctx)\n\n\tresponse, err := client.Do(request)\n\tif err != nil {\n\t\tvar netErr net.Error\n\t\tif !errors.As(err, &netErr) || !netErr.Timeout() {\n\t\t\t// Timeout is the expected error when there is no portal\n\t\t\tlog.Debugf(\"netenv: http portal test failed: %s\", err)\n\t\t\t// TODO: discern between errors to detect StatusLimited\n\t\t}\n\t} else {\n\t\tdefer func() {\n\t\t\t_ = response.Body.Close()\n\t\t}()\n\t\t// Got a response, something is messing with the request\n\n\t\t// check location\n\t\tportalURL, err := response.Location()\n\t\tif err == nil {\n\t\t\tupdateOnlineStatus(StatusPortal, portalURL, \"portal test request succeeded with redirect\")\n\t\t\treturn\n\t\t}\n\n\t\t// direct response\n\t\tif response.StatusCode == http.StatusOK {\n\t\t\tupdateOnlineStatus(StatusPortal, &url.URL{\n\t\t\t\tScheme: \"http\",\n\t\t\t\tHost:   SpecialCaptivePortalDomain,\n\t\t\t\tPath:   \"/\",\n\t\t\t}, \"portal test request succeeded\")\n\t\t\treturn\n\t\t}\n\n\t\tlog.Debugf(\"netenv: unexpected http portal test response code: %d\", response.StatusCode)\n\t\t// other responses are undefined, continue with next test\n\t}\n\n\t// 3) resolve a query\n\n\t// Check if we can resolve the dns check domain.\n\tif DNSTestQueryFunc == nil {\n\t\tupdateOnlineStatus(StatusOnline, nil, \"all checks passed, dns query check disabled\")\n\t\treturn\n\t}\n\tips, ok, err := DNSTestQueryFunc(ctx, DNSTestDomain)\n\tswitch {\n\tcase ok && err != nil:\n\t\tupdateOnlineStatus(StatusOnline, nil, fmt.Sprintf(\n\t\t\t\"all checks passed, acceptable result for dns query check: %s\",\n\t\t\terr,\n\t\t))\n\tcase ok && len(ips) >= 1 && ips[0].Equal(DNSTestExpectedIP):\n\t\tupdateOnlineStatus(StatusOnline, nil, \"all checks passed\")\n\tcase ok && len(ips) >= 1:\n\t\tlog.Warningf(\"netenv: dns query check response mismatched: got %s\", ips[0])\n\t\tupdateOnlineStatus(StatusOnline, nil, \"all checks passed, dns query check response mismatched\")\n\tcase ok:\n\t\tlog.Warningf(\"netenv: dns query check response mismatched: empty response\")\n\t\tupdateOnlineStatus(StatusOnline, nil, \"all checks passed, dns query check response was empty\")\n\tdefault:\n\t\tlog.Warningf(\"netenv: dns query check failed: %s\", err)\n\t\tupdateOnlineStatus(StatusOffline, nil, \"dns query check failed\")\n\t}\n}\n"
  },
  {
    "path": "service/netenv/online-status_test.go",
    "content": "package netenv\n\nimport (\n\t\"context\"\n\t\"testing\"\n)\n\nfunc TestCheckOnlineStatus(t *testing.T) {\n\tt.Parallel()\n\n\tcheckOnlineStatus(context.Background())\n\tt.Logf(\"online status: %s\", GetOnlineStatus())\n\tt.Logf(\"captive portal: %+v\", GetCaptivePortal())\n}\n"
  },
  {
    "path": "service/netenv/os_android.go",
    "content": "package netenv\n\n// TODO: Re-enable Android interfaces.\n// Deactived for transition to new module system.\n\n// import (\n// \t\"net\"\n// \t\"time\"\n\n// \t\"github.com/safing/portmaster-android/go/app_interface\"\n// )\n\n// var (\n// \tmonitorNetworkChangeOnlineTicker  = time.NewTicker(time.Second)\n// \tmonitorNetworkChangeOfflineTicker = time.NewTicker(time.Second)\n// )\n\n// func init() {\n// \t// Network change event is monitored by the android system.\n// \tmonitorNetworkChangeOnlineTicker.Stop()\n// \tmonitorNetworkChangeOfflineTicker.Stop()\n// }\n\n// func osGetInterfaceAddrs() ([]net.Addr, error) {\n// \tlist, err := app_interface.GetNetworkAddresses()\n// \tif err != nil {\n// \t\treturn nil, err\n// \t}\n\n// \tvar netList []net.Addr\n// \tfor _, addr := range list {\n// \t\tipNetAddr, err := addr.ToIPNet()\n// \t\tif err == nil {\n// \t\t\tnetList = append(netList, ipNetAddr)\n// \t\t}\n// \t}\n\n// \treturn netList, nil\n// }\n\n// func osGetNetworkInterfaces() ([]app_interface.NetworkInterface, error) {\n// \treturn app_interface.GetNetworkInterfaces()\n// }\n"
  },
  {
    "path": "service/netenv/os_default.go",
    "content": "//go:build !android\n\npackage netenv\n\nimport (\n\t\"net\"\n\t\"time\"\n)\n\nvar (\n\tmonitorNetworkChangeOnlineTicker  = time.NewTicker(15 * time.Second)\n\tmonitorNetworkChangeOfflineTicker = time.NewTicker(time.Second)\n)\n\nfunc osGetInterfaceAddrs() ([]net.Addr, error) {\n\treturn net.InterfaceAddrs()\n}\n\nfunc osGetNetworkInterfaces() ([]net.Interface, error) {\n\treturn net.Interfaces()\n}\n"
  },
  {
    "path": "service/netquery/active_chart_handler.go",
    "content": "package netquery\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n)\n\n// ActiveChartHandler handles requests for connection charts.\ntype ActiveChartHandler struct {\n\tDatabase *Database\n}\n\nfunc (ch *ActiveChartHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { //nolint:dupl\n\trequestPayload, err := ch.parseRequest(req)\n\tif err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\treturn\n\t}\n\n\tquery, paramMap, err := requestPayload.generateSQL(req.Context(), ch.Database.Schema)\n\tif err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\treturn\n\t}\n\n\t// actually execute the query against the database and collect the result\n\tvar result []map[string]interface{}\n\tif err := ch.Database.Execute(\n\t\treq.Context(),\n\t\tquery,\n\t\torm.WithNamedArgs(paramMap),\n\t\torm.WithResult(&result),\n\t\torm.WithSchema(*ch.Database.Schema),\n\t); err != nil {\n\t\thttp.Error(resp, failedQuery+err.Error(), http.StatusInternalServerError)\n\n\t\treturn\n\t}\n\n\t// send the HTTP status code\n\tresp.WriteHeader(http.StatusOK)\n\n\t// prepare the result encoder.\n\tenc := json.NewEncoder(resp)\n\tenc.SetEscapeHTML(false)\n\tenc.SetIndent(\"\", \"  \")\n\n\t_ = enc.Encode(map[string]interface{}{ //nolint:errchkjson\n\t\t\"results\": result,\n\t\t\"query\":   query,\n\t\t\"params\":  paramMap,\n\t})\n}\n\nfunc (ch *ActiveChartHandler) parseRequest(req *http.Request) (*QueryActiveConnectionChartPayload, error) { //nolint:dupl\n\tvar body io.Reader\n\n\tswitch req.Method {\n\tcase http.MethodPost, http.MethodPut:\n\t\tbody = req.Body\n\tcase http.MethodGet:\n\t\tbody = strings.NewReader(req.URL.Query().Get(\"q\"))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid HTTP method\")\n\t}\n\n\tvar requestPayload QueryActiveConnectionChartPayload\n\tblob, err := io.ReadAll(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read body: %w\", err)\n\t}\n\n\tbody = bytes.NewReader(blob)\n\n\tdec := json.NewDecoder(body)\n\tdec.DisallowUnknownFields()\n\n\tif err := json.Unmarshal(blob, &requestPayload); err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\treturn &requestPayload, nil\n}\n\nfunc (req *QueryActiveConnectionChartPayload) generateSQL(ctx context.Context, schema *orm.TableSchema) (string, map[string]interface{}, error) {\n\ttemplate := `\nWITH RECURSIVE epoch(x) AS (\n\tSELECT strftime('%%s')-600\n\tUNION ALL\n\t\tSELECT x+1 FROM epoch WHERE x+1 < strftime('%%s')+0\n)\nSELECT x as timestamp, SUM(verdict IN (2, 5, 6)) AS value, SUM(verdict NOT IN (2, 5, 6)) as countBlocked\n\tFROM epoch\n\tJOIN connections\n\t\tON strftime('%%s', connections.started)+0 <= timestamp+0 AND (connections.ended IS NULL OR strftime('%%s', connections.ended)+0 >= timestamp+0)\n\t%s\n\tGROUP BY round(timestamp/10, 0)*10;`\n\n\tclause, params, err := req.Query.toSQLWhereClause(ctx, \"\", schema, orm.DefaultEncodeConfig)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tif params == nil {\n\t\tparams = make(map[string]interface{})\n\t}\n\n\tif req.TextSearch != nil {\n\t\ttextSearch, textParams, err := req.TextSearch.toSQLConditionClause(ctx, schema, \"\", orm.DefaultEncodeConfig)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, err\n\t\t}\n\n\t\tif textSearch != \"\" {\n\t\t\tif clause != \"\" {\n\t\t\t\tclause += \" AND \"\n\t\t\t}\n\t\t\tclause += textSearch\n\n\t\t\tfor key, val := range textParams {\n\t\t\t\tparams[key] = val\n\t\t\t}\n\t\t}\n\t}\n\n\tif clause == \"\" {\n\t\treturn fmt.Sprintf(template, \"\"), map[string]interface{}{}, nil\n\t}\n\n\treturn fmt.Sprintf(template, \"WHERE ( \"+clause+\")\"), params, nil\n}\n"
  },
  {
    "path": "service/netquery/bandwidth_chart_handler.go",
    "content": "package netquery\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n)\n\n// BandwidthChartHandler handles requests for connection charts.\ntype BandwidthChartHandler struct {\n\tDatabase *Database\n}\n\n// BandwidthChartRequest holds a request for a bandwidth chart.\ntype BandwidthChartRequest struct {\n\tInterval int      `json:\"interval\"`\n\tQuery    Query    `json:\"query\"`\n\tGroupBy  []string `json:\"groupBy\"`\n}\n\nfunc (ch *BandwidthChartHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { //nolint:dupl\n\trequestPayload, err := ch.parseRequest(req)\n\tif err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\treturn\n\t}\n\n\tquery, paramMap, err := requestPayload.generateSQL(req.Context(), ch.Database.Schema)\n\tif err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\treturn\n\t}\n\n\t// actually execute the query against the database and collect the result\n\tvar result []map[string]interface{}\n\tif err := ch.Database.Execute(\n\t\treq.Context(),\n\t\tquery,\n\t\torm.WithNamedArgs(paramMap),\n\t\torm.WithResult(&result),\n\t\torm.WithSchema(*ch.Database.Schema),\n\t); err != nil {\n\t\thttp.Error(resp, failedQuery+err.Error(), http.StatusInternalServerError)\n\n\t\treturn\n\t}\n\n\t// send the HTTP status code\n\tresp.WriteHeader(http.StatusOK)\n\n\t// prepare the result encoder.\n\tenc := json.NewEncoder(resp)\n\tenc.SetEscapeHTML(false)\n\tenc.SetIndent(\"\", \"  \")\n\n\t_ = enc.Encode(map[string]interface{}{ //nolint:errchkjson\n\t\t\"results\": result,\n\t\t\"query\":   query,\n\t\t\"params\":  paramMap,\n\t})\n}\n\nfunc (ch *BandwidthChartHandler) parseRequest(req *http.Request) (*BandwidthChartRequest, error) { //nolint:dupl\n\tvar body io.Reader\n\n\tswitch req.Method {\n\tcase http.MethodPost, http.MethodPut:\n\t\tbody = req.Body\n\tcase http.MethodGet:\n\t\tbody = strings.NewReader(req.URL.Query().Get(\"q\"))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid HTTP method\")\n\t}\n\n\tvar requestPayload BandwidthChartRequest\n\tblob, err := io.ReadAll(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read body: %w\", err)\n\t}\n\n\tbody = bytes.NewReader(blob)\n\n\tdec := json.NewDecoder(body)\n\tdec.DisallowUnknownFields()\n\n\tif err := json.Unmarshal(blob, &requestPayload); err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\treturn &requestPayload, nil\n}\n\nfunc (req *BandwidthChartRequest) generateSQL(ctx context.Context, schema *orm.TableSchema) (string, map[string]interface{}, error) {\n\tif req.Interval == 0 {\n\t\treq.Interval = 10\n\t}\n\n\tinterval := fmt.Sprintf(\"round(time/%d, 0)*%d\", req.Interval, req.Interval)\n\n\t// make sure there are only allowed fields specified in the request group-by\n\tfor _, gb := range req.GroupBy {\n\t\tdef := schema.GetColumnDef(gb)\n\t\tif def == nil {\n\t\t\treturn \"\", nil, fmt.Errorf(\"unsupported groupBy key: %q\", gb)\n\t\t}\n\t}\n\n\tselects := append([]string{\n\t\tinterval + \" as timestamp\",\n\t\t\"SUM(incoming) as incoming\",\n\t\t\"SUM(outgoing) as outgoing\",\n\t}, req.GroupBy...)\n\n\tgroupBy := append([]string{interval}, req.GroupBy...)\n\n\twhereClause, params, err := req.Query.toSQLWhereClause(ctx, \"\", schema, orm.DefaultEncodeConfig)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\tif whereClause != \"\" {\n\t\twhereClause = \"WHERE \" + whereClause\n\t}\n\n\ttemplate := fmt.Sprintf(\n\t\t`SELECT %s\n\t\tFROM main.bandwidth AS bw\n\t\tJOIN main.connections AS conns\n\t\t\tON bw.conn_id = conns.id\n\t\t%s\n\t\tGROUP BY %s\n\t\tORDER BY time ASC`,\n\t\tstrings.Join(selects, \", \"),\n\t\twhereClause,\n\t\tstrings.Join(groupBy, \", \"),\n\t)\n\n\treturn template, params, nil\n}\n"
  },
  {
    "path": "service/netquery/database.go",
    "content": "package netquery\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/jackc/puddle/v2\"\n\t\"zombiezen.com/go/sqlite\"\n\t\"zombiezen.com/go/sqlite/sqlitex\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\n// InMemory is the \"file path\" to open a new in-memory database.\nconst InMemory = \"file:inmem.db?mode=memory\"\n\n// Available connection types as their string representation.\nconst (\n\tConnTypeDNS = \"dns\"\n\tConnTypeIP  = \"ip\"\n)\n\n// ConnectionTypeToString is a lookup map to get the string representation\n// of a network.ConnectionType as used by this package.\nvar ConnectionTypeToString = map[network.ConnectionType]string{\n\tnetwork.DNSRequest:   ConnTypeDNS,\n\tnetwork.IPConnection: ConnTypeIP,\n}\n\ntype (\n\t// Database represents a SQLite3 backed connection database.\n\t// It's use is tailored for persistence and querying of network.Connection.\n\t// Access to the underlying SQLite database is synchronized.\n\t//\n\tDatabase struct {\n\t\tSchema *orm.TableSchema\n\n\t\treadConnPool *puddle.Pool[*sqlite.Conn]\n\t\thistoryPath  string\n\n\t\tl         sync.Mutex\n\t\twriteConn *sqlite.Conn\n\t}\n\n\t// BatchExecute executes multiple queries in one transaction.\n\tBatchExecute struct {\n\t\tID     string\n\t\tSQL    string\n\t\tParams map[string]any\n\t\tResult *[]map[string]any\n\t}\n\n\t// Conn is a network connection that is stored in a SQLite database and accepted\n\t// by the *Database type of this package. This also defines, using the ./orm package,\n\t// the table schema and the model that is exposed via the runtime database as well as\n\t// the query API.\n\t//\n\t// Use ConvertConnection from this package to convert a network.Connection to this\n\t// representation.\n\tConn struct { //nolint:maligned\n\t\t// ID is a device-unique identifier for the connection. It is built\n\t\t// from network.Connection by hashing the connection ID and the start\n\t\t// time. We cannot just use the network.Connection.ID because it is only unique\n\t\t// as long as the connection is still active and might be, although unlikely,\n\t\t// reused afterwards.\n\t\tID              string            `sqlite:\"id,primary\"`\n\t\tProfileID       string            `sqlite:\"profile\"`\n\t\tPath            string            `sqlite:\"path\"`\n\t\tType            string            `sqlite:\"type,varchar(8)\"`\n\t\tExternal        bool              `sqlite:\"external\"`\n\t\tIPVersion       packet.IPVersion  `sqlite:\"ip_version\"`\n\t\tIPProtocol      packet.IPProtocol `sqlite:\"ip_protocol\"`\n\t\tLocalIP         string            `sqlite:\"local_ip\"`\n\t\tLocalPort       uint16            `sqlite:\"local_port\"`\n\t\tRemoteIP        string            `sqlite:\"remote_ip\"`\n\t\tRemotePort      uint16            `sqlite:\"remote_port\"`\n\t\tDomain          string            `sqlite:\"domain\"`\n\t\tCountry         string            `sqlite:\"country,varchar(2)\"`\n\t\tASN             uint              `sqlite:\"asn\"`\n\t\tASOwner         string            `sqlite:\"as_owner\"`\n\t\tLatitude        float64           `sqlite:\"latitude\"`\n\t\tLongitude       float64           `sqlite:\"longitude\"`\n\t\tScope           netutils.IPScope  `sqlite:\"scope\"`\n\t\tWorstVerdict    network.Verdict   `sqlite:\"worst_verdict\"`\n\t\tActiveVerdict   network.Verdict   `sqlite:\"verdict\"`\n\t\tFirewallVerdict network.Verdict   `sqlite:\"firewall_verdict\"`\n\t\tStarted         time.Time         `sqlite:\"started,text,time\"`\n\t\tEnded           *time.Time        `sqlite:\"ended,text,time\"`\n\t\tTunneled        bool              `sqlite:\"tunneled\"`\n\t\tEncrypted       bool              `sqlite:\"encrypted\"`\n\t\tInternal        bool              `sqlite:\"internal\"`\n\t\tDirection       string            `sqlite:\"direction\"`\n\t\tExtraData       json.RawMessage   `sqlite:\"extra_data\"`\n\t\tAllowed         *bool             `sqlite:\"allowed\"`\n\t\tProfileRevision int               `sqlite:\"profile_revision\"`\n\t\tExitNode        *string           `sqlite:\"exit_node\"`\n\t\tBytesReceived   uint64            `sqlite:\"bytes_received,default=0\"`\n\t\tBytesSent       uint64            `sqlite:\"bytes_sent,default=0\"`\n\n\t\t// TODO(ppacher): support \"NOT\" in search query to get rid of the following helper fields\n\t\tActive bool `sqlite:\"active\"` // could use \"ended IS NOT NULL\" or \"ended IS NULL\"\n\n\t\t// TODO(ppacher): we need to profile here for \"suggestion\" support. It would be better to keep a table of profiles in sqlite and use joins here\n\t\tProfileName string `sqlite:\"profile_name\"`\n\t}\n)\n\n// New opens a new in-memory database named path and attaches a persistent history database.\n//\n// The returned Database used connection pooling for read-only connections\n// (see Execute). To perform database writes use either Save() or ExecuteWrite().\n// Note that write connections are serialized by the Database object before being\n// handed over to SQLite.\nfunc New(dbPath string) (*Database, error) {\n\thistoryParentDir := filepath.Join(module.instance.DataDir(), \"databases\")\n\terr := utils.EnsureDirectory(historyParentDir, utils.AdminOnlyExecPermission)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to ensure database directory exists: %w\", err)\n\t}\n\n\t// Get file location of history database.\n\thistoryFile := filepath.Join(historyParentDir, \"history.db\")\n\t// Convert to SQLite URI path.\n\thistoryURI := \"file:///\" + strings.TrimPrefix(filepath.ToSlash(historyFile), \"/\")\n\n\tconstructor := func(ctx context.Context) (*sqlite.Conn, error) {\n\t\tc, err := sqlite.OpenConn(\n\t\t\tdbPath,\n\t\t\tsqlite.OpenReadOnly,\n\t\t\tsqlite.OpenSharedCache,\n\t\t\tsqlite.OpenURI,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to open read-only sqlite connection at %s: %w\", dbPath, err)\n\t\t}\n\n\t\tif err := sqlitex.ExecuteTransient(c, \"ATTACH DATABASE '\"+historyURI+\"?mode=ro' AS history\", nil); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to attach history database: %w\", err)\n\t\t}\n\n\t\treturn c, nil\n\t}\n\n\tdestructor := func(resource *sqlite.Conn) {\n\t\tif err := resource.Close(); err != nil {\n\t\t\tlog.Errorf(\"failed to close pooled SQlite database connection: %s\", err)\n\t\t}\n\t}\n\n\tpool, err := puddle.NewPool(&puddle.Config[*sqlite.Conn]{\n\t\tConstructor: constructor,\n\t\tDestructor:  destructor,\n\t\tMaxSize:     10,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tschema, err := orm.GenerateTableSchema(\"connections\", Conn{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\twriteConn, err := sqlite.OpenConn(\n\t\tdbPath,\n\t\tsqlite.OpenCreate,\n\t\tsqlite.OpenReadWrite,\n\t\tsqlite.OpenWAL,\n\t\tsqlite.OpenSharedCache,\n\t\tsqlite.OpenURI,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open sqlite at %s: %w\", dbPath, err)\n\t}\n\n\treturn &Database{\n\t\treadConnPool: pool,\n\t\tSchema:       schema,\n\t\twriteConn:    writeConn,\n\t\thistoryPath:  historyURI,\n\t}, nil\n}\n\n// NewInMemory is like New but creates a new in-memory database and\n// automatically applies the connection table schema.\nfunc NewInMemory() (*Database, error) {\n\tdb, err := New(InMemory)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// this should actually never happen because an in-memory database\n\t// always starts empty...\n\tif err := db.ApplyMigrations(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to prepare database: %w\", err)\n\t}\n\n\treturn db, nil\n}\n\n// Close closes the database, including pools and connections.\nfunc (db *Database) Close() error {\n\tdb.readConnPool.Close()\n\n\tif err := db.writeConn.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// VacuumHistory rewrites the history database in order to purge deleted records.\nfunc VacuumHistory(ctx context.Context) (err error) {\n\thistoryParentDir := filepath.Join(module.instance.DataDir(), \"databases\")\n\terr = utils.EnsureDirectory(historyParentDir, utils.AdminOnlyExecPermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to ensure database directory exists: %w\", err)\n\t}\n\n\t// Get file location of history database.\n\thistoryFile := filepath.Join(historyParentDir, \"history.db\")\n\t// Convert to SQLite URI path.\n\thistoryURI := \"file:///\" + strings.TrimPrefix(filepath.ToSlash(historyFile), \"/\")\n\n\twriteConn, err := sqlite.OpenConn(\n\t\thistoryURI,\n\t\tsqlite.OpenCreate,\n\t\tsqlite.OpenReadWrite,\n\t\tsqlite.OpenWAL,\n\t\tsqlite.OpenSharedCache,\n\t\tsqlite.OpenURI,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif closeErr := writeConn.Close(); closeErr != nil && err == nil {\n\t\t\terr = closeErr\n\t\t}\n\t}()\n\n\treturn orm.RunQuery(ctx, writeConn, \"VACUUM\")\n}\n\n// ApplyMigrations applies any table and data migrations that are needed\n// to bring db up-to-date with the built-in schema.\n// TODO(ppacher): right now this only applies the current schema and ignores\n// any data-migrations. Once the history module is implemented this should\n// become/use a full migration system -- use zombiezen.com/go/sqlite/sqlitemigration.\nfunc (db *Database) ApplyMigrations() error {\n\tdb.l.Lock()\n\tdefer db.l.Unlock()\n\n\tif err := sqlitex.ExecuteTransient(db.writeConn, \"ATTACH DATABASE '\"+db.historyPath+\"?mode=rwc' AS 'history';\", nil); err != nil {\n\t\treturn fmt.Errorf(\"failed to attach history database: %w\", err)\n\t}\n\n\tdbNames := []string{\"main\", \"history\"}\n\tfor _, dbName := range dbNames {\n\t\t// get the create-table SQL statement from the inferred schema\n\t\tsql := db.Schema.CreateStatement(dbName, true)\n\t\tlog.Debugf(\"creating table schema for database %q\", dbName)\n\n\t\t// execute the SQL\n\t\tif err := sqlitex.ExecuteTransient(db.writeConn, sql, nil); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create schema on database %q: %w\", dbName, err)\n\t\t}\n\n\t\t// create a few indexes\n\t\tindexes := []string{\n\t\t\t`CREATE INDEX IF NOT EXISTS %sprofile_id_index ON %s (profile)`,\n\t\t\t`CREATE INDEX IF NOT EXISTS %sstarted_time_index ON %s (strftime('%%s', started)+0)`,\n\t\t\t`CREATE INDEX IF NOT EXISTS %sstarted_ended_time_index ON %s (strftime('%%s', started)+0, strftime('%%s', ended)+0) WHERE ended IS NOT NULL`,\n\t\t}\n\t\tfor _, idx := range indexes {\n\t\t\tname := \"\"\n\t\t\tif dbName != \"\" {\n\t\t\t\tname = dbName + \".\"\n\t\t\t}\n\n\t\t\tstmt := fmt.Sprintf(idx, name, db.Schema.Name)\n\n\t\t\tif err := sqlitex.ExecuteTransient(db.writeConn, stmt, nil); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create index on database %q: %q: %w\", dbName, idx, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tbwSchema := `CREATE TABLE IF NOT EXISTS main.bandwidth (\n\t\tconn_id TEXT NOT NULL,\n\t\ttime INTEGER NOT NULL,\n\t\tincoming INTEGER NOT NULL,\n\t\toutgoing INTEGER NOT NULL,\n\t\tCONSTRAINT fk_conn_id\n\t\t\tFOREIGN KEY(conn_id) REFERENCES connections(id)\n\t\t\tON DELETE CASCADE\n\t)`\n\tif err := sqlitex.ExecuteTransient(db.writeConn, bwSchema, nil); err != nil {\n\t\treturn fmt.Errorf(\"failed to create main.bandwidth database: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (db *Database) withConn(ctx context.Context, fn func(conn *sqlite.Conn) error) error {\n\tres, err := db.readConnPool.Acquire(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer res.Release()\n\n\treturn fn(res.Value())\n}\n\n// ExecuteWrite executes a custom SQL query using a writable connection against the SQLite\n// database used by db.\n// It uses orm.RunQuery() under the hood so please refer to the orm package for\n// more information about available options.\nfunc (db *Database) ExecuteWrite(ctx context.Context, sql string, args ...orm.QueryOption) error {\n\tdb.l.Lock()\n\tdefer db.l.Unlock()\n\n\treturn orm.RunQuery(ctx, db.writeConn, sql, args...)\n}\n\n// Execute executes a custom SQL query using a read-only connection against the SQLite\n// database used by db.\n// It uses orm.RunQuery() under the hood so please refer to the orm package for\n// more information about available options.\nfunc (db *Database) Execute(ctx context.Context, sql string, args ...orm.QueryOption) error {\n\treturn db.withConn(ctx, func(conn *sqlite.Conn) error {\n\t\treturn orm.RunQuery(ctx, conn, sql, args...)\n\t})\n}\n\n// ExecuteBatch executes multiple custom SQL query using a read-only connection against the SQLite\n// database used by db.\nfunc (db *Database) ExecuteBatch(ctx context.Context, batches []BatchExecute) error {\n\treturn db.withConn(ctx, func(conn *sqlite.Conn) error {\n\t\tmerr := new(multierror.Error)\n\n\t\tfor _, batch := range batches {\n\t\t\tif err := orm.RunQuery(ctx, conn, batch.SQL, orm.WithNamedArgs(batch.Params), orm.WithResult(batch.Result)); err != nil {\n\t\t\t\tmerr.Errors = append(merr.Errors, fmt.Errorf(\"%s: %w\", batch.ID, err))\n\t\t\t}\n\t\t}\n\n\t\treturn merr.ErrorOrNil()\n\t})\n}\n\n// CountRows returns the number of rows stored in the database.\nfunc (db *Database) CountRows(ctx context.Context) (int, error) {\n\tvar result []struct {\n\t\tCount int `sqlite:\"count\"`\n\t}\n\n\tif err := db.Execute(ctx, \"SELECT COUNT(*) AS count FROM (SELECT * FROM main.connections UNION SELECT * from history.connections)\", orm.WithResult(&result)); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to perform query: %w\", err)\n\t}\n\n\tif len(result) != 1 {\n\t\treturn 0, fmt.Errorf(\"unexpected number of rows returned, expected 1 got %d\", len(result))\n\t}\n\n\treturn result[0].Count, nil\n}\n\n// Cleanup removes all connections that have ended before threshold from the live database.\n//\n// NOTE(ppacher): there is no easy way to get the number of removed\n// rows other than counting them in a first step. Though, that's\n// probably not worth the cylces...\nfunc (db *Database) Cleanup(ctx context.Context, threshold time.Time) (int, error) {\n\twhere := `WHERE ended IS NOT NULL\n\t\t\tAND datetime(ended) < datetime(:threshold)`\n\tsql := \"DELETE FROM main.connections \" + where + \";\"\n\n\targs := orm.WithNamedArgs(map[string]interface{}{\n\t\t\":threshold\": threshold.UTC().Format(orm.SqliteTimeFormat),\n\t})\n\n\tvar result []struct {\n\t\tCount int `sqlite:\"count\"`\n\t}\n\tif err := db.Execute(\n\t\tctx,\n\t\t\"SELECT COUNT(*) AS count FROM connections \"+where,\n\t\targs,\n\t\torm.WithTransient(),\n\t\torm.WithResult(&result),\n\t); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to perform query: %w\", err)\n\t}\n\tif len(result) != 1 {\n\t\treturn 0, fmt.Errorf(\"unexpected number of rows, expected 1 got %d\", len(result))\n\t}\n\n\terr := db.ExecuteWrite(ctx, sql, args)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn result[0].Count, nil\n}\n\n// RemoveAllHistoryData removes all connections from the history database.\nfunc (db *Database) RemoveAllHistoryData(ctx context.Context) error {\n\tquery := fmt.Sprintf(\"DELETE FROM %s.connections\", HistoryDatabase)\n\treturn db.ExecuteWrite(ctx, query)\n}\n\n// RemoveHistoryForProfile removes all connections from the history database\n// for a given profile ID (source/id).\nfunc (db *Database) RemoveHistoryForProfile(ctx context.Context, profileID string) error {\n\tquery := fmt.Sprintf(\"DELETE FROM %s.connections WHERE profile = :profile\", HistoryDatabase)\n\treturn db.ExecuteWrite(ctx, query, orm.WithNamedArgs(map[string]any{\n\t\t\":profile\": profileID,\n\t}))\n}\n\n// MigrateProfileID migrates the given profile IDs in the history database.\n// This needs to be done when profiles are deleted and replaced by a different profile.\nfunc (db *Database) MigrateProfileID(ctx context.Context, from string, to string) error {\n\treturn db.ExecuteWrite(ctx, \"UPDATE history.connections SET profile = :to WHERE profile = :from\", orm.WithNamedArgs(map[string]any{\n\t\t\":from\": from,\n\t\t\":to\":   to,\n\t}))\n}\n\n// dumpTo is a simple helper method that dumps all rows stored in the SQLite database\n// as JSON to w.\n// Any error aborts dumping rows and is returned.\nfunc (db *Database) dumpTo(ctx context.Context, w io.Writer) error { //nolint:unused\n\tvar conns []Conn\n\terr := db.withConn(ctx, func(conn *sqlite.Conn) error {\n\t\treturn sqlitex.ExecuteTransient(conn, \"SELECT * FROM connections\", &sqlitex.ExecOptions{\n\t\t\tResultFunc: func(stmt *sqlite.Stmt) error {\n\t\t\t\tvar c Conn\n\t\t\t\tif err := orm.DecodeStmt(ctx, db.Schema, stmt, &c, orm.DefaultDecodeConfig); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tconns = append(conns, c)\n\t\t\t\treturn nil\n\t\t\t},\n\t\t})\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tenc := json.NewEncoder(w)\n\tenc.SetIndent(\"\", \"  \")\n\treturn enc.Encode(conns)\n}\n\n// CleanupHistory deletes history data outside of the (per-app) retention time frame.\nfunc (db *Database) CleanupHistory(ctx context.Context) error {\n\t// Setup tracer for the clean up process.\n\tctx, tracer := log.AddTracer(ctx)\n\tdefer tracer.Submit()\n\n\t// Get list of profiles in history.\n\tquery := \"SELECT DISTINCT profile FROM history.connections\"\n\tvar result []struct {\n\t\tProfile string `sqlite:\"profile\"`\n\t}\n\tif err := db.Execute(ctx, query, orm.WithResult(&result)); err != nil {\n\t\treturn fmt.Errorf(\"failed to get a list of profiles from the history database: %w\", err)\n\t}\n\n\tvar (\n\t\t// Get global retention days - do not delete in case of error.\n\t\tglobalRetentionDays = config.GetAsInt(profile.CfgOptionKeepHistoryKey, 0)()\n\n\t\tprofileName   string\n\t\tretentionDays int64\n\n\t\tprofileCnt int\n\t\tmerr       = new(multierror.Error)\n\t)\n\tfor _, row := range result {\n\t\t// Get profile and retention days.\n\t\tid := strings.TrimPrefix(row.Profile, string(profile.SourceLocal)+\"/\")\n\t\tp, err := profile.GetLocalProfile(id, nil, nil)\n\t\tif err == nil {\n\t\t\tprofileName = p.String()\n\t\t\tretentionDays = p.LayeredProfile().KeepHistory()\n\t\t} else {\n\t\t\t// Getting profile failed, fallback to global setting.\n\t\t\ttracer.Errorf(\"history: failed to load profile for id %s: %s\", id, err)\n\t\t\tprofileName = row.Profile\n\t\t\tretentionDays = globalRetentionDays\n\t\t}\n\n\t\t// Skip deleting if history should be kept forever.\n\t\tif retentionDays == 0 {\n\t\t\ttracer.Tracef(\"history: retention is disabled for %s, skipping\", profileName)\n\t\t\tcontinue\n\t\t}\n\t\t// Count profiles where connections were deleted.\n\t\tprofileCnt++\n\n\t\t// TODO: count cleared connections\n\t\tthreshold := time.Now().Add(-1 * time.Duration(retentionDays) * time.Hour * 24)\n\t\tif err := db.ExecuteWrite(ctx,\n\t\t\t\"DELETE FROM history.connections WHERE profile = :profile AND active = FALSE AND datetime(started) < datetime(:threshold)\",\n\t\t\torm.WithNamedArgs(map[string]any{\n\t\t\t\t\":profile\":   row.Profile,\n\t\t\t\t\":threshold\": threshold.Format(orm.SqliteTimeFormat),\n\t\t\t}),\n\t\t); err != nil {\n\t\t\ttracer.Warningf(\"history: failed to delete connections of %s: %s\", profileName, err)\n\t\t\tmerr.Errors = append(merr.Errors, fmt.Errorf(\"profile %s: %w\", row.Profile, err))\n\t\t} else {\n\t\t\ttracer.Debugf(\n\t\t\t\t\"history: deleted connections older than %d days (before %s) of %s\",\n\t\t\t\tretentionDays,\n\t\t\t\tthreshold.Format(time.RFC822),\n\t\t\t\tprofileName,\n\t\t\t)\n\t\t}\n\t}\n\n\t// Log summary.\n\ttracer.Infof(\"history: deleted connections outside of retention from %d profiles\", profileCnt)\n\n\treturn merr.ErrorOrNil()\n}\n\n// MarkAllHistoryConnectionsEnded marks all connections in the history database as ended.\nfunc (db *Database) MarkAllHistoryConnectionsEnded(ctx context.Context) error {\n\tquery := fmt.Sprintf(\"UPDATE %s.connections SET active = FALSE, ended = :ended WHERE active = TRUE\", HistoryDatabase)\n\n\tif err := db.ExecuteWrite(ctx, query, orm.WithNamedArgs(map[string]any{\n\t\t\":ended\": time.Now().Format(orm.SqliteTimeFormat),\n\t})); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// UpdateBandwidth updates bandwidth data for the connection and optionally also writes\n// the bandwidth data to the history database.\nfunc (db *Database) UpdateBandwidth(ctx context.Context, enableHistory bool, profileKey string, processKey string, connID string, bytesReceived uint64, bytesSent uint64) error {\n\tparams := map[string]any{\n\t\t\":id\": makeNqIDFromParts(processKey, connID),\n\t}\n\n\tparts := []string{}\n\tparts = append(parts, \"bytes_received = (bytes_received + :bytes_received)\")\n\tparams[\":bytes_received\"] = bytesReceived\n\tparts = append(parts, \"bytes_sent = (bytes_sent + :bytes_sent)\")\n\tparams[\":bytes_sent\"] = bytesSent\n\n\tupdateSet := strings.Join(parts, \", \")\n\n\tupdateStmts := []string{\n\t\tfmt.Sprintf(`UPDATE %s.connections SET %s WHERE id = :id`, LiveDatabase, updateSet),\n\t}\n\n\tif enableHistory {\n\t\tupdateStmts = append(updateStmts,\n\t\t\tfmt.Sprintf(`UPDATE %s.connections SET %s WHERE id = :id`, HistoryDatabase, updateSet),\n\t\t)\n\t}\n\n\tmerr := new(multierror.Error)\n\tfor _, stmt := range updateStmts {\n\t\tif err := db.ExecuteWrite(ctx, stmt, orm.WithNamedArgs(params)); err != nil {\n\t\t\tmerr.Errors = append(merr.Errors, err)\n\t\t}\n\t}\n\n\t// also add the date to the in-memory bandwidth database\n\tparams[\":time\"] = time.Now().Unix()\n\tstmt := \"INSERT INTO main.bandwidth (conn_id, time, incoming, outgoing) VALUES(:id, :time, :bytes_received, :bytes_sent)\"\n\tif err := db.ExecuteWrite(ctx, stmt, orm.WithNamedArgs(params)); err != nil {\n\t\tmerr.Errors = append(merr.Errors, fmt.Errorf(\"failed to update main.bandwidth: %w\", err))\n\t}\n\n\treturn merr.ErrorOrNil()\n}\n\n// Save inserts the connection conn into the SQLite database. If conn\n// already exists the table row is updated instead.\n//\n// Save uses the database write connection instead of relying on the\n// connection pool.\nfunc (db *Database) Save(ctx context.Context, conn Conn, enableHistory bool) error {\n\t// convert the connection to a param map where each key is already translated\n\t// to the sql column name. We also skip bytes_received and bytes_sent since those\n\t// will be updated independently from the connection object.\n\tconnMap, err := orm.ToParamMap(ctx, conn, \"\", orm.DefaultEncodeConfig, []string{\n\t\t\"bytes_received\",\n\t\t\"bytes_sent\",\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to encode connection for SQL: %w\", err)\n\t}\n\n\tcolumns := make([]string, 0, len(connMap))\n\tplaceholders := make([]string, 0, len(connMap))\n\tvalues := make(map[string]interface{}, len(connMap))\n\tupdateSets := make([]string, 0, len(connMap))\n\n\t// sort keys so we get a stable SQLite query that can be better cached.\n\tkeys := make([]string, 0, len(connMap))\n\tfor key := range connMap {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\n\tfor _, key := range keys {\n\t\tvalue := connMap[key]\n\n\t\tcolumns = append(columns, key)\n\t\tplaceholders = append(placeholders, \":\"+key)\n\t\tvalues[\":\"+key] = value\n\t\tupdateSets = append(updateSets, fmt.Sprintf(\"%s = :%s\", key, key))\n\t}\n\n\tdb.l.Lock()\n\tdefer db.l.Unlock()\n\n\t// TODO(ppacher): make sure this one can be cached to speed up inserting\n\t// and save some CPU cycles for the user\n\tdbNames := []DatabaseName{LiveDatabase}\n\n\t// TODO: Should we only add ended connection to the history database to save\n\t// a couple INSERTs per connection?\n\t// This means we need to write the current live DB to the history DB on\n\t// shutdown in order to be able to pick the back up after a restart.\n\n\t// Save to history DB if enabled.\n\tif enableHistory {\n\t\tdbNames = append(dbNames, HistoryDatabase)\n\t}\n\n\tfor _, dbName := range dbNames {\n\t\tsql := fmt.Sprintf(\n\t\t\t`INSERT INTO %s.connections (%s)\n\t\t\t\tVALUES(%s)\n\t\t\t\tON CONFLICT(id) DO UPDATE SET\n\t\t\t\t%s\n\t\t\t`,\n\t\t\tdbName,\n\t\t\tstrings.Join(columns, \", \"),\n\t\t\tstrings.Join(placeholders, \", \"),\n\t\t\tstrings.Join(updateSets, \", \"),\n\t\t)\n\n\t\tif err := sqlitex.Execute(db.writeConn, sql, &sqlitex.ExecOptions{\n\t\t\tNamed: values,\n\t\t\tResultFunc: func(stmt *sqlite.Stmt) error {\n\t\t\t\tlog.Errorf(\"netquery: got result statement with %d columns\", stmt.ColumnCount())\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}); err != nil {\n\t\t\tlog.Errorf(\"netquery: failed to execute:\\n\\t%q\\n\\treturned error was: %s\\n\\tparameters: %+v\", sql, err, values)\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/netquery/manager.go",
    "content": "package netquery\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/structures/dsd\"\n)\n\ntype (\n\t// ConnectionStore describes the interface that is used by Manager\n\t// to save new or updated connection objects.\n\t// It is implemented by the *Database type of this package.\n\tConnectionStore interface {\n\t\t// Save is called to perists the new or updated connection. If required,\n\t\t// It's up to the implementation to figure out if the operation is an\n\t\t// insert or an update.\n\t\t// The ID of Conn is unique and can be trusted to never collide with other\n\t\t// connections of the save device.\n\t\tSave(ctx context.Context, conn Conn, history bool) error\n\n\t\t// MarkAllHistoryConnectionsEnded marks all active connections in the history\n\t\t// database as ended NOW.\n\t\tMarkAllHistoryConnectionsEnded(ctx context.Context) error\n\n\t\t// RemoveAllHistoryData removes all connections from the history database.\n\t\tRemoveAllHistoryData(ctx context.Context) error\n\n\t\t// RemoveHistoryForProfile removes all connections from the history database.\n\t\t// for a given profile ID (source/id)\n\t\tRemoveHistoryForProfile(ctx context.Context, profile string) error\n\n\t\t// UpdateBandwidth updates bandwidth data for the connection and optionally also writes\n\t\t// the bandwidth data to the history database.\n\t\tUpdateBandwidth(ctx context.Context, enableHistory bool, profileKey string, processKey string, connID string, bytesReceived uint64, bytesSent uint64) error\n\n\t\t// CleanupHistory deletes data outside of the retention time frame from the history database.\n\t\tCleanupHistory(ctx context.Context) error\n\n\t\t// Close closes the connection store. It must not be used afterwards.\n\t\tClose() error\n\t}\n\n\t// Manager handles new and updated network.Connections feeds and persists them\n\t// at a connection store.\n\t// Manager also registers itself as a runtime database and pushes updates to\n\t// connections using the local format.\n\t// Users should use this update feed rather than the deprecated \"network:\" database.\n\tManager struct {\n\t\tstore      ConnectionStore\n\t\tpush       runtime.PushFunc\n\t\truntimeReg *runtime.Registry\n\t\tpushPrefix string\n\t}\n)\n\n// NewManager returns a new connection manager that persists all newly created or\n// updated connections at store.\nfunc NewManager(store ConnectionStore, pushPrefix string, reg *runtime.Registry) (*Manager, error) {\n\tmng := &Manager{\n\t\tstore:      store,\n\t\truntimeReg: reg,\n\t\tpushPrefix: pushPrefix,\n\t}\n\n\tpush, err := reg.Register(pushPrefix, runtime.SimpleValueGetterFunc(mng.runtimeGet))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmng.push = push\n\n\treturn mng, nil\n}\n\nfunc (mng *Manager) runtimeGet(keyOrPrefix string) ([]record.Record, error) {\n\t// TODO(ppacher):\n\t//\t\twe don't yet support querying using the runtime database here ...\n\t//\t\tconsider exposing connection from the database at least by ID.\n\t//\n\t// NOTE(ppacher):\n\t//\t\tfor debugging purposes use RuntimeQueryRunner to execute plain\n\t//\t\tSQL queries against the database using portbase/database/runtime.\n\treturn nil, nil\n}\n\n// HandleFeed starts reading new and updated connections from feed and persists them\n// in the configured ConnectionStore. HandleFeed blocks until either ctx is cancelled\n// or feed is closed.\n// Any errors encountered when processing new or updated connections are logged but\n// otherwise ignored.\n// HandleFeed handles and persists updates one after each other! Depending on the system\n// load the user might want to use a buffered channel for feed.\nfunc (mng *Manager) HandleFeed(ctx context.Context, feed <-chan *network.Connection) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\n\t\tcase conn, ok := <-feed:\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfunc() {\n\t\t\t\tconn.Lock()\n\t\t\t\tdefer conn.Unlock()\n\n\t\t\t\tif !conn.DataIsComplete() {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tmodel, err := convertConnection(conn)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(\"netquery: failed to convert connection %s to sqlite model: %s\", conn.ID, err)\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// DEBUG:\n\t\t\t\t// log.Tracef(\"netquery: updating connection %s\", conn.ID)\n\n\t\t\t\t// Save to netquery database.\n\t\t\t\t// Do not include internal connections in history.\n\t\t\t\tif err := mng.store.Save(ctx, *model, conn.HistoryEnabled); err != nil {\n\t\t\t\t\tlog.Errorf(\"netquery: failed to save connection %s in sqlite database: %s\", conn.ID, err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// we clone the record metadata from the connection\n\t\t\t\t// into the new model so the portbase/database layer\n\t\t\t\t// can handle NEW/UPDATE correctly.\n\t\t\t\tcloned := conn.Meta().Duplicate()\n\n\t\t\t\t// push an update for the connection\n\t\t\t\tif err := mng.pushConnUpdate(ctx, *cloned, *model); err != nil {\n\t\t\t\t\tlog.Errorf(\"netquery: failed to push update for conn %s via database system: %s\", conn.ID, err)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n}\n\nfunc (mng *Manager) pushConnUpdate(_ context.Context, meta record.Meta, conn Conn) error {\n\tblob, err := json.Marshal(conn)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal connection: %w\", err)\n\t}\n\n\tkey := fmt.Sprintf(\"%s:%s%s\", mng.runtimeReg.DatabaseName(), mng.pushPrefix, conn.ID)\n\twrapper, err := record.NewWrapper(\n\t\tkey,\n\t\t&meta,\n\t\tdsd.JSON,\n\t\tblob,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create record wrapper: %w\", err)\n\t}\n\n\tmng.push(wrapper)\n\treturn nil\n}\n\n// convertConnection converts conn to the local representation used\n// to persist the information in SQLite.\n// The caller must hold the lock to the given network.Connection.\nfunc convertConnection(conn *network.Connection) (*Conn, error) {\n\tdirection := \"outbound\"\n\tif conn.Inbound {\n\t\tdirection = \"inbound\"\n\t}\n\n\tc := Conn{\n\t\tID:              makeNqIDFromConn(conn),\n\t\tExternal:        conn.External,\n\t\tIPVersion:       conn.IPVersion,\n\t\tIPProtocol:      conn.IPProtocol,\n\t\tLocalIP:         conn.LocalIP.String(),\n\t\tLocalPort:       conn.LocalPort,\n\t\tActiveVerdict:   conn.Verdict,\n\t\tStarted:         time.Unix(conn.Started, 0),\n\t\tTunneled:        conn.Tunneled,\n\t\tEncrypted:       conn.Encrypted,\n\t\tInternal:        conn.Internal,\n\t\tDirection:       direction,\n\t\tType:            ConnectionTypeToString[conn.Type],\n\t\tProfileID:       conn.ProcessContext.Source + \"/\" + conn.ProcessContext.Profile,\n\t\tPath:            conn.ProcessContext.BinaryPath,\n\t\tProfileRevision: int(conn.ProfileRevisionCounter),\n\t\tProfileName:     conn.ProcessContext.ProfileName,\n\t}\n\n\tswitch conn.Type {\n\tcase network.DNSRequest:\n\t\tc.Type = \"dns\"\n\tcase network.IPConnection:\n\t\tc.Type = \"ip\"\n\tcase network.Undefined:\n\t\tc.Type = \"\"\n\t}\n\n\tc.Allowed = &conn.ConnectionEstablished\n\n\tif conn.Ended > 0 {\n\t\tended := time.Unix(conn.Ended, 0)\n\t\tc.Ended = &ended\n\t\tc.Active = false\n\t} else {\n\t\tc.Active = true\n\t}\n\n\textraData := map[string]interface{}{\n\t\t\"pid\":              conn.ProcessContext.PID,\n\t\t\"processCreatedAt\": conn.ProcessContext.CreatedAt,\n\t}\n\n\tif conn.TunnelContext != nil {\n\t\textraData[\"tunnel\"] = conn.TunnelContext\n\t\texitNode := conn.TunnelContext.GetExitNodeID()\n\t\tc.ExitNode = &exitNode\n\t}\n\n\tif conn.DNSContext != nil {\n\t\textraData[\"dns\"] = conn.DNSContext\n\t}\n\n\t// TODO(ppacher): enable when TLS inspection is merged\n\t// if conn.TLSContext != nil {\n\t// \textraData[\"tls\"] = conn.TLSContext\n\t// }\n\n\tif conn.Entity != nil {\n\t\textraData[\"cname\"] = conn.Entity.CNAME\n\t\textraData[\"blockedByLists\"] = conn.Entity.BlockedByLists\n\t\textraData[\"blockedEntities\"] = conn.Entity.BlockedEntities\n\t\textraData[\"reason\"] = conn.Reason\n\n\t\tc.RemoteIP = conn.Entity.IP.String()\n\t\tc.RemotePort = conn.Entity.Port\n\t\tc.Domain = conn.Entity.Domain\n\t\tc.Country = conn.Entity.Country\n\t\tc.ASN = conn.Entity.ASN\n\t\tc.ASOwner = conn.Entity.ASOrg\n\t\tc.Scope = conn.Entity.IPScope\n\t\tif conn.Entity.Coordinates != nil {\n\t\t\tc.Latitude = conn.Entity.Coordinates.Latitude\n\t\t\tc.Longitude = conn.Entity.Coordinates.Longitude\n\t\t}\n\t}\n\n\t// pre-compute the JSON blob for the extra data column\n\t// and assign it.\n\textraDataBlob, err := json.Marshal(extraData)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal extra data: %w\", err)\n\t}\n\tc.ExtraData = extraDataBlob\n\n\treturn &c, nil\n}\n\n// makeNqIDFromConn creates a netquery connection ID from the network connection.\nfunc makeNqIDFromConn(conn *network.Connection) string {\n\treturn makeNqIDFromParts(conn.Process().GetKey(), conn.ID)\n}\n\n// makeNqIDFromParts creates a netquery connection ID from the given network\n// connection ID and the process key.\nfunc makeNqIDFromParts(processKey string, netConnID string) string {\n\treturn processKey + \"-\" + netConnID\n}\n"
  },
  {
    "path": "service/netquery/module_api.go",
    "content": "package netquery\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\tservertiming \"github.com/mitchellh/go-server-timing\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\ntype NetQuery struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tStore *Database\n\n\tdb   *database.Interface\n\tmng  *Manager\n\tfeed chan *network.Connection\n}\n\nfunc (nq *NetQuery) prepare() error {\n\tvar err error\n\n\tnq.db = database.NewInterface(&database.Options{\n\t\tLocal:    true,\n\t\tInternal: true,\n\t})\n\n\t// TODO: Open database in start() phase.\n\tnq.Store, err = NewInMemory()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create in-memory database: %w\", err)\n\t}\n\n\tnq.mng, err = NewManager(nq.Store, \"netquery/data/\", runtime.DefaultRegistry)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create manager: %w\", err)\n\t}\n\n\tnq.feed = make(chan *network.Connection, 1000)\n\n\tqueryHander := &QueryHandler{\n\t\tDatabase:  nq.Store,\n\t\tIsDevMode: config.Concurrent.GetAsBool(config.CfgDevModeKey, false),\n\t}\n\n\tbatchHander := &BatchQueryHandler{\n\t\tDatabase:  nq.Store,\n\t\tIsDevMode: config.Concurrent.GetAsBool(config.CfgDevModeKey, false),\n\t}\n\n\tchartHandler := &ActiveChartHandler{\n\t\tDatabase: nq.Store,\n\t}\n\n\tbwChartHandler := &BandwidthChartHandler{\n\t\tDatabase: nq.Store,\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Query Connections\",\n\t\tDescription: \"Query the in-memory sqlite connection database.\",\n\t\tPath:        \"netquery/query\",\n\t\tMimeType:    \"application/json\",\n\t\tRead:        api.PermitUser, // Needs read+write as the query is sent using POST data.\n\t\tWrite:       api.PermitUser, // Needs read+write as the query is sent using POST data.\n\t\tHandlerFunc: servertiming.Middleware(queryHander, nil).ServeHTTP,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to register API endpoint: %w\", err)\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Batch Query Connections\",\n\t\tDescription: \"Batch query the in-memory sqlite connection database.\",\n\t\tPath:        \"netquery/query/batch\",\n\t\tMimeType:    \"application/json\",\n\t\tRead:        api.PermitUser, // Needs read+write as the query is sent using POST data.\n\t\tWrite:       api.PermitUser, // Needs read+write as the query is sent using POST data.\n\t\tHandlerFunc: servertiming.Middleware(batchHander, nil).ServeHTTP,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to register API endpoint: %w\", err)\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Active Connections Chart\",\n\t\tDescription: \"Query the in-memory sqlite connection database and return a chart of active connections.\",\n\t\tPath:        \"netquery/charts/connection-active\",\n\t\tMimeType:    \"application/json\",\n\t\tWrite:       api.PermitUser,\n\t\tHandlerFunc: servertiming.Middleware(chartHandler, nil).ServeHTTP,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to register API endpoint: %w\", err)\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\t// TODO: Use query parameters instead.\n\t\tPath:        \"netquery/charts/bandwidth\",\n\t\tMimeType:    \"application/json\",\n\t\tWrite:       api.PermitUser,\n\t\tHandlerFunc: bwChartHandler.ServeHTTP,\n\t\tName:        \"Bandwidth Chart\",\n\t\tDescription: \"Query the in-memory sqlite connection database and return a chart of bytes sent/received.\",\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to register API endpoint: %w\", err)\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Remove connections from profile history\",\n\t\tDescription: \"Remove all connections from the history database for one or more profiles\",\n\t\tPath:        \"netquery/history/clear\",\n\t\tMimeType:    \"application/json\",\n\t\tWrite:       api.PermitUser,\n\t\tActionFunc: func(ar *api.Request) (msg string, err error) {\n\t\t\tvar body struct {\n\t\t\t\tProfileIDs []string `json:\"profileIDs\"`\n\t\t\t}\n\t\t\tif err := json.Unmarshal(ar.InputData, &body); err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to decode parameters in body: %w\", err)\n\t\t\t}\n\n\t\t\tif len(body.ProfileIDs) == 0 {\n\t\t\t\tif err := nq.mng.store.RemoveAllHistoryData(ar.Context()); err != nil {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"failed to remove all history: %w\", err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmerr := new(multierror.Error)\n\t\t\t\tfor _, profileID := range body.ProfileIDs {\n\t\t\t\t\tif err := nq.mng.store.RemoveHistoryForProfile(ar.Context(), profileID); err != nil {\n\t\t\t\t\t\tmerr.Errors = append(merr.Errors, fmt.Errorf(\"failed to clear history for %q: %w\", profileID, err))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlog.Infof(\"netquery: successfully cleared history for %s\", profileID)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif err := merr.ErrorOrNil(); err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn \"Successfully cleared history.\", nil\n\t\t},\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to register API endpoint: %w\", err)\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:  \"Apply connection history retention threshold\",\n\t\tPath:  \"netquery/history/cleanup\",\n\t\tWrite: api.PermitUser,\n\t\tActionFunc: func(ar *api.Request) (msg string, err error) {\n\t\t\tif err := nq.Store.CleanupHistory(ar.Context()); err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\treturn \"Deleted outdated connections.\", nil\n\t\t},\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to register API endpoint: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (nq *NetQuery) Manager() *mgr.Manager {\n\treturn nq.mgr\n}\n\nfunc (nq *NetQuery) Start() error {\n\tnq.mgr.Go(\"netquery connection feed listener\", func(ctx *mgr.WorkerCtx) error {\n\t\tsub, err := nq.db.Subscribe(query.New(\"network:\"))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to subscribe to network tree: %w\", err)\n\t\t}\n\t\tdefer close(nq.feed)\n\t\tdefer func() {\n\t\t\t_ = sub.Cancel()\n\t\t}()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\tcase rec, ok := <-sub.Feed:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tconn, ok := rec.(*network.Connection)\n\t\t\t\tif !ok {\n\t\t\t\t\t// This is fine as we also receive process updates on\n\t\t\t\t\t// this channel.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tnq.feed <- conn\n\t\t\t}\n\t\t}\n\t})\n\n\tnq.mgr.Go(\"netquery connection feed handler\", func(ctx *mgr.WorkerCtx) error {\n\t\tnq.mng.HandleFeed(ctx.Ctx(), nq.feed)\n\t\treturn nil\n\t})\n\n\tnq.mgr.Go(\"netquery live db cleaner\", func(ctx *mgr.WorkerCtx) error {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\tcase <-time.After(10 * time.Second):\n\t\t\t\tthreshold := time.Now().Add(-network.DeleteConnsAfterEndedThreshold)\n\t\t\t\tcount, err := nq.Store.Cleanup(ctx.Ctx(), threshold)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Errorf(\"netquery: failed to removed old connections from live db: %s\", err)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Tracef(\"netquery: successfully removed %d old connections from live db that ended before %s\", count, threshold)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n\n\tnq.mgr.Delay(\"network history cleaner delay\", 10*time.Minute, func(w *mgr.WorkerCtx) error {\n\t\treturn nq.Store.CleanupHistory(w.Ctx())\n\t}).Repeat(1 * time.Hour)\n\n\t// For debugging, provide a simple direct SQL query interface using\n\t// the runtime database.\n\t// Only expose in development mode.\n\tif config.GetAsBool(config.CfgDevModeKey, false)() {\n\t\t_, err := NewRuntimeQueryRunner(nq.Store, \"netquery/query/\", runtime.DefaultRegistry)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to set up runtime SQL query runner: %w\", err)\n\t\t}\n\t}\n\n\t// Migrate profile IDs in history database when profiles are migrated/merged.\n\tnq.instance.Profile().EventMigrated.AddCallback(\"migrate profile IDs in history database\",\n\t\tfunc(ctx *mgr.WorkerCtx, profileIDs []string) (bool, error) {\n\t\t\tif len(profileIDs) == 2 {\n\t\t\t\treturn false, nq.Store.MigrateProfileID(ctx.Ctx(), profileIDs[0], profileIDs[1])\n\t\t\t}\n\t\t\treturn false, nil\n\t\t})\n\n\treturn nil\n}\n\nfunc (nq *NetQuery) Stop() error {\n\t// Cacnel the module context.\n\tnq.mgr.Cancel()\n\t// Wait for all workers before we start the shutdown.\n\tnq.mgr.WaitForWorkersFromStop(time.Minute)\n\n\t// we don't use the module ctx here because it is already canceled.\n\t// just give the clean up 1 minute to happen and abort otherwise.\n\tctx, cancel := context.WithTimeout(context.Background(), time.Minute)\n\tdefer cancel()\n\n\tif err := nq.mng.store.MarkAllHistoryConnectionsEnded(ctx); err != nil {\n\t\t// handle the error by just logging it. There's not much we can do here\n\t\t// and returning an error to the module system doesn't help much as well...\n\t\tlog.Errorf(\"netquery: failed to mark connections in history database as ended: %s\", err)\n\t}\n\n\tif err := nq.mng.store.Close(); err != nil {\n\t\tlog.Errorf(\"netquery: failed to close sqlite database: %s\", err)\n\t} else {\n\t\t// Clear deleted connections from database.\n\t\tif err := VacuumHistory(ctx); err != nil {\n\t\t\tlog.Errorf(\"netquery: failed to execute VACUUM in history database: %s\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nvar (\n\tmodule     *NetQuery\n\tshimLoaded atomic.Bool\n)\n\n// NewModule returns a new NetQuery module.\nfunc NewModule(instance instance) (*NetQuery, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"NetQuery\")\n\tmodule = &NetQuery{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\tif err := module.prepare(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to prepare netquery module: %w\", err)\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tDataDir() string\n\tProfile() *profile.ProfileModule\n}\n"
  },
  {
    "path": "service/netquery/orm/decoder.go",
    "content": "package orm\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"zombiezen.com/go/sqlite\"\n)\n\n// Commonly used error messages when working with orm.\nvar (\n\terrStructExpected        = errors.New(\"encode: can only encode structs to maps\")\n\terrStructPointerExpected = errors.New(\"decode: result must be pointer to a struct type or map[string]interface{}\")\n\terrUnexpectedColumnType  = errors.New(\"decode: unexpected column type\")\n)\n\n// constants used when transforming data to and from sqlite.\nvar (\n\t// sqliteTimeFromat defines the string representation that is\n\t// expected by SQLite DATETIME functions.\n\t// Note that SQLite itself does not include support for a DATETIME\n\t// column type. Instead, dates and times are stored either as INTEGER,\n\t// TEXT or REAL.\n\t// This package provides support for time.Time being stored as TEXT (using a\n\t// preconfigured timezone; UTC by default) or as INTEGER (the user can choose between\n\t// unixepoch and unixnano-epoch where the nano variant is not officially supported by\n\t// SQLITE).\n\tSqliteTimeFormat = \"2006-01-02 15:04:05\"\n)\n\ntype (\n\n\t// Stmt describes the interface that must be implemented in order to\n\t// be decodable to a struct type using DecodeStmt. This interface is implemented\n\t// by *sqlite.Stmt.\n\tStmt interface {\n\t\tColumnCount() int\n\t\tColumnName(col int) string\n\t\tColumnType(col int) sqlite.ColumnType\n\t\tColumnText(col int) string\n\t\tColumnBool(col int) bool\n\t\tColumnFloat(col int) float64\n\t\tColumnInt(col int) int\n\t\tColumnReader(col int) *bytes.Reader\n\t}\n\n\t// DecodeFunc is called for each non-basic type during decoding.\n\tDecodeFunc func(colIdx int, colDef *ColumnDef, stmt Stmt, fieldDef reflect.StructField, outval reflect.Value) (interface{}, bool, error)\n\n\t// DecodeConfig holds decoding functions.\n\tDecodeConfig struct {\n\t\tDecodeHooks []DecodeFunc\n\t}\n)\n\n// DecodeStmt decodes the current result row loaded in Stmt into the struct or map type result.\n// Decoding hooks configured in cfg are executed before trying to decode basic types and may\n// be specified to provide support for special types.\n// See DatetimeDecoder() for an example of a DecodeHook that handles graceful time.Time conversion.\nfunc DecodeStmt(ctx context.Context, schema *TableSchema, stmt Stmt, result interface{}, cfg DecodeConfig) error {\n\t// make sure we got something to decode into ...\n\tif result == nil {\n\t\treturn fmt.Errorf(\"%w, got %T\", errStructPointerExpected, result)\n\t}\n\n\t// fast path for decoding into a map\n\tif mp, ok := result.(*map[string]interface{}); ok {\n\t\treturn decodeIntoMap(ctx, schema, stmt, mp, cfg)\n\t}\n\n\t// make sure we got a pointer in result\n\tif reflect.TypeOf(result).Kind() != reflect.Ptr {\n\t\treturn fmt.Errorf(\"%w, got %T\", errStructPointerExpected, result)\n\t}\n\n\t// make sure it's a poiter to a struct type\n\tt := reflect.ValueOf(result).Elem().Type()\n\tif t.Kind() != reflect.Struct {\n\t\treturn fmt.Errorf(\"%w, got %T\", errStructPointerExpected, result)\n\t}\n\n\t// if result is a nil pointer make sure to allocate some space\n\t// for the resulting struct\n\tresultValue := reflect.ValueOf(result)\n\tif resultValue.IsNil() {\n\t\tresultValue.Set(\n\t\t\treflect.New(t),\n\t\t)\n\t}\n\n\t// we need access to the struct directly and not to the\n\t// pointer.\n\ttarget := reflect.Indirect(resultValue)\n\n\t// create a lookup map from field name (or sqlite:\"\" tag)\n\t// to the field name\n\tlm := make(map[string]string)\n\tfor i := range target.NumField() {\n\t\tfieldType := t.Field(i)\n\n\t\t// skip unexported fields\n\t\tif !fieldType.IsExported() {\n\t\t\tcontinue\n\t\t}\n\n\t\tlm[sqlColumnName(fieldType)] = fieldType.Name\n\t}\n\n\t// iterate over all columns and assign them to the correct\n\t// fields\n\tfor i := range stmt.ColumnCount() {\n\t\tcolName := stmt.ColumnName(i)\n\t\tfieldName, ok := lm[colName]\n\t\tif !ok {\n\t\t\t// there's no target field for this column\n\t\t\t// so we can skip it\n\t\t\tcontinue\n\t\t}\n\t\tfieldType, _ := t.FieldByName(fieldName)\n\n\t\tvalue := target.FieldByName(fieldName)\n\n\t\tcolType := stmt.ColumnType(i)\n\n\t\t// if the column is reported as NULL we keep\n\t\t// the field as it is.\n\t\t// TODO(ppacher): should we set it to nil here?\n\t\tif colType == sqlite.TypeNull {\n\t\t\tcontinue\n\t\t}\n\n\t\t// if value is a nil pointer we need to allocate some memory\n\t\t// first\n\t\tif getKind(value) == reflect.Ptr && value.IsNil() {\n\t\t\tstorage := reflect.New(fieldType.Type.Elem())\n\n\t\t\tvalue.Set(storage)\n\n\t\t\t// make sure value actually points the\n\t\t\t// dereferenced target storage\n\t\t\tvalue = storage.Elem()\n\t\t}\n\n\t\tcolDef := schema.GetColumnDef(colName)\n\n\t\t// execute all decode hooks but make sure we use decodeBasic() as the\n\t\t// last one.\n\t\tcolumnValue, err := runDecodeHooks(\n\t\t\ti,\n\t\t\tcolDef,\n\t\t\tstmt,\n\t\t\tfieldType,\n\t\t\tvalue,\n\t\t\tappend(cfg.DecodeHooks, decodeBasic()),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// if we don't have a converted value now we try to\n\t\t// decode basic types\n\t\tif columnValue == nil {\n\t\t\treturn fmt.Errorf(\"cannot decode column %d (type=%s)\", i, colType)\n\t\t}\n\n\t\t// Debugging:\n\t\t// log.Printf(\"valueTypeName: %s fieldName = %s value-orig = %s value = %s (%v) newValue = %s\", value.Type().String(), fieldName, target.FieldByName(fieldName).Type(), value.Type(), value, columnValue)\n\n\t\t// convert it to the target type if conversion is possible\n\t\tnewValue := reflect.ValueOf(columnValue)\n\t\tif newValue.Type().ConvertibleTo(value.Type()) {\n\t\t\tnewValue = newValue.Convert(value.Type())\n\t\t}\n\n\t\t// assign the new value to the struct field.\n\t\tvalue.Set(newValue)\n\t}\n\n\treturn nil\n}\n\n// DatetimeDecoder is capable of decoding sqlite INTEGER or TEXT storage classes into\n// time.Time. For INTEGER storage classes, it supports 'unixnano' struct tag value to\n// decide between Unix or UnixNano epoch timestamps.\n//\n// TODO(ppacher): update comment about loc parameter and TEXT storage class parsing.\nfunc DatetimeDecoder(loc *time.Location) DecodeFunc {\n\treturn func(colIdx int, colDef *ColumnDef, stmt Stmt, fieldDef reflect.StructField, outval reflect.Value) (interface{}, bool, error) {\n\t\t// if we have the column definition available we\n\t\t// use the target go type from there.\n\t\toutType := outval.Type()\n\n\t\tif colDef != nil {\n\t\t\toutType = colDef.GoType\n\t\t}\n\n\t\t// we only care about \"time.Time\" here\n\t\tif outType.String() != \"time.Time\" || (colDef != nil && !colDef.IsTime) {\n\t\t\t// log.Printf(\"not decoding %s %v\", outType, colDef)\n\t\t\treturn nil, false, nil\n\t\t}\n\n\t\tswitch stmt.ColumnType(colIdx) { //nolint:exhaustive // Only selecting specific types.\n\t\tcase sqlite.TypeInteger:\n\t\t\t// stored as unix-epoch, if unixnano is set in the struct field tag\n\t\t\t// we parse it with nano-second resolution\n\t\t\t// TODO(ppacher): actually split the tag value at \",\" and search\n\t\t\t// the slice for \"unixnano\"\n\t\t\tif strings.Contains(fieldDef.Tag.Get(\"sqlite\"), \",unixnano\") {\n\t\t\t\treturn time.Unix(0, int64(stmt.ColumnInt(colIdx))), true, nil\n\t\t\t}\n\n\t\t\treturn time.Unix(int64(stmt.ColumnInt(colIdx)), 0), true, nil\n\n\t\tcase sqlite.TypeText:\n\t\t\t// stored ISO8601 but does not have any timezone information\n\t\t\t// assigned so we always treat it as loc here.\n\t\t\tt, err := time.ParseInLocation(SqliteTimeFormat, stmt.ColumnText(colIdx), loc)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to parse %q in %s: %w\", stmt.ColumnText(colIdx), fieldDef.Name, err)\n\t\t\t}\n\n\t\t\treturn t, true, nil\n\n\t\tcase sqlite.TypeFloat:\n\t\t\t// stored as Julian day numbers\n\t\t\treturn nil, false, errors.New(\"REAL storage type not support for time.Time\")\n\n\t\tcase sqlite.TypeNull:\n\t\t\treturn nil, true, nil\n\n\t\tdefault:\n\t\t\treturn nil, false, fmt.Errorf(\"unsupported storage type for time.Time: %s\", stmt.ColumnType(colIdx))\n\t\t}\n\t}\n}\n\nfunc decodeIntoMap(_ context.Context, schema *TableSchema, stmt Stmt, mp *map[string]interface{}, cfg DecodeConfig) error {\n\tif *mp == nil {\n\t\t*mp = make(map[string]interface{})\n\t}\n\n\tfor i := range stmt.ColumnCount() {\n\t\tvar x interface{}\n\n\t\tcolDef := schema.GetColumnDef(stmt.ColumnName(i))\n\n\t\toutVal := reflect.ValueOf(&x).Elem()\n\t\tfieldType := reflect.StructField{}\n\t\tif colDef != nil {\n\t\t\toutVal = reflect.New(colDef.GoType).Elem()\n\t\t\tfieldType = reflect.StructField{\n\t\t\t\tType: colDef.GoType,\n\t\t\t}\n\t\t}\n\n\t\tval, err := runDecodeHooks(\n\t\t\ti,\n\t\t\tcolDef,\n\t\t\tstmt,\n\t\t\tfieldType,\n\t\t\toutVal,\n\t\t\tappend(cfg.DecodeHooks, decodeBasic()),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode column %s: %w\", stmt.ColumnName(i), err)\n\t\t}\n\n\t\t(*mp)[stmt.ColumnName(i)] = val\n\t}\n\n\treturn nil\n}\n\nfunc decodeBasic() DecodeFunc {\n\treturn func(colIdx int, colDef *ColumnDef, stmt Stmt, fieldDef reflect.StructField, outval reflect.Value) (result interface{}, handled bool, err error) {\n\t\tvalueKind := getKind(outval)\n\t\tcolType := stmt.ColumnType(colIdx)\n\t\tcolName := stmt.ColumnName(colIdx)\n\n\t\terrInvalidType := fmt.Errorf(\"%w %s for column %s with field type %s\", errUnexpectedColumnType, colType.String(), colName, outval.Type())\n\n\t\t// if we have the column definition available we\n\t\t// use the target go type from there.\n\t\tif colDef != nil {\n\t\t\tvalueKind = NormalizeKind(colDef.GoType.Kind())\n\n\t\t\t// if we have a column definition we try to convert the value to\n\t\t\t// the actual Go-type that was used in the model.\n\t\t\t// this is useful, for example, to ensure a []byte{} is always decoded into json.RawMessage\n\t\t\t// or that type aliases like (type myInt int) are decoded into myInt instead of int\n\t\t\tdefer func() {\n\t\t\t\tif handled {\n\t\t\t\t\tt := reflect.New(colDef.GoType).Elem()\n\n\t\t\t\t\tif result == nil || reflect.ValueOf(result).IsZero() {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tif reflect.ValueOf(result).Type().ConvertibleTo(colDef.GoType) {\n\t\t\t\t\t\tresult = reflect.ValueOf(result).Convert(colDef.GoType).Interface()\n\t\t\t\t\t}\n\t\t\t\t\tt.Set(reflect.ValueOf(result))\n\n\t\t\t\t\tresult = t.Interface()\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\n\t\t// log.Printf(\"decoding %s into kind %s\", colName, valueKind)\n\n\t\tif colType == sqlite.TypeNull {\n\t\t\tif colDef != nil && colDef.Nullable {\n\t\t\t\treturn nil, true, nil\n\t\t\t}\n\n\t\t\tif colDef != nil && !colDef.Nullable {\n\t\t\t\treturn reflect.New(colDef.GoType).Elem().Interface(), true, nil\n\t\t\t}\n\n\t\t\tif outval.Kind() == reflect.Ptr {\n\t\t\t\treturn nil, true, nil\n\t\t\t}\n\t\t}\n\n\t\tswitch valueKind { //nolint:exhaustive\n\t\tcase reflect.String:\n\t\t\tif colType != sqlite.TypeText {\n\t\t\t\treturn nil, false, errInvalidType\n\t\t\t}\n\t\t\treturn stmt.ColumnText(colIdx), true, nil\n\n\t\tcase reflect.Bool:\n\t\t\t// sqlite does not have a BOOL type, it rather stores a 1/0 in a column\n\t\t\t// with INTEGER affinity.\n\t\t\tif colType != sqlite.TypeInteger {\n\t\t\t\treturn nil, false, errInvalidType\n\t\t\t}\n\t\t\treturn stmt.ColumnBool(colIdx), true, nil\n\n\t\tcase reflect.Float64:\n\t\t\tif colType != sqlite.TypeFloat {\n\t\t\t\treturn nil, false, errInvalidType\n\t\t\t}\n\t\t\treturn stmt.ColumnFloat(colIdx), true, nil\n\n\t\tcase reflect.Int, reflect.Uint: // getKind() normalizes all ints to reflect.Int/Uint because sqlite doesn't really care ...\n\t\t\tif colType != sqlite.TypeInteger {\n\t\t\t\treturn nil, false, errInvalidType\n\t\t\t}\n\n\t\t\treturn stmt.ColumnInt(colIdx), true, nil\n\n\t\tcase reflect.Slice:\n\t\t\tif outval.Type().Elem().Kind() != reflect.Uint8 {\n\t\t\t\treturn nil, false, errors.New(\"slices other than []byte for BLOB are not supported\")\n\t\t\t}\n\n\t\t\tif colType != sqlite.TypeBlob {\n\t\t\t\treturn nil, false, errInvalidType\n\t\t\t}\n\n\t\t\tcolumnValue, err := io.ReadAll(stmt.ColumnReader(colIdx))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to read blob for column %s: %w\", fieldDef.Name, err)\n\t\t\t}\n\n\t\t\treturn columnValue, true, nil\n\n\t\tcase reflect.Interface:\n\t\t\tvar (\n\t\t\t\tt reflect.Type\n\t\t\t\tx interface{}\n\t\t\t)\n\t\t\tswitch colType {\n\t\t\tcase sqlite.TypeBlob:\n\t\t\t\tt = reflect.TypeOf([]byte{})\n\t\t\t\tcolumnValue, err := io.ReadAll(stmt.ColumnReader(colIdx))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, false, fmt.Errorf(\"failed to read blob for column %s: %w\", fieldDef.Name, err)\n\t\t\t\t}\n\t\t\t\tx = columnValue\n\n\t\t\tcase sqlite.TypeFloat:\n\t\t\t\tt = reflect.TypeOf(float64(0))\n\t\t\t\tx = stmt.ColumnFloat(colIdx)\n\n\t\t\tcase sqlite.TypeInteger:\n\t\t\t\tt = reflect.TypeOf(int(0))\n\t\t\t\tx = stmt.ColumnInt(colIdx)\n\n\t\t\tcase sqlite.TypeText:\n\t\t\t\tt = reflect.TypeOf(string(\"\"))\n\t\t\t\tx = stmt.ColumnText(colIdx)\n\n\t\t\tcase sqlite.TypeNull:\n\t\t\t\tt = nil\n\t\t\t\tx = nil\n\n\t\t\tdefault:\n\t\t\t\treturn nil, false, fmt.Errorf(\"unsupported column type %s\", colType)\n\t\t\t}\n\n\t\t\tif t == nil {\n\t\t\t\treturn nil, true, nil\n\t\t\t}\n\n\t\t\ttarget := reflect.New(t).Elem()\n\t\t\ttarget.Set(reflect.ValueOf(x))\n\n\t\t\treturn target.Interface(), true, nil\n\n\t\tdefault:\n\t\t\treturn nil, false, fmt.Errorf(\"cannot decode into %s\", valueKind)\n\t\t}\n\t}\n}\n\nfunc sqlColumnName(fieldType reflect.StructField) string {\n\ttagValue, hasTag := fieldType.Tag.Lookup(\"sqlite\")\n\tif !hasTag {\n\t\treturn fieldType.Name\n\t}\n\n\tparts := strings.Split(tagValue, \",\")\n\tif parts[0] != \"\" {\n\t\treturn parts[0]\n\t}\n\n\treturn fieldType.Name\n}\n\n// runDecodeHooks tries to decode the column value of stmt at index colIdx into outval by running all decode hooks.\n// The first hook that returns a non-nil interface wins, other hooks will not be executed. If an error is\n// returned by a decode hook runDecodeHooks stops the error is returned to the caller.\nfunc runDecodeHooks(colIdx int, colDef *ColumnDef, stmt Stmt, fieldDef reflect.StructField, outval reflect.Value, hooks []DecodeFunc) (interface{}, error) {\n\tfor _, fn := range hooks {\n\t\tres, end, err := fn(colIdx, colDef, stmt, fieldDef, outval)\n\t\tif err != nil {\n\t\t\treturn res, err\n\t\t}\n\n\t\tif end {\n\t\t\treturn res, nil\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n\n// getKind returns the kind of value but normalized Int, Uint and Float variants.\n// to their base type.\nfunc getKind(val reflect.Value) reflect.Kind {\n\tkind := val.Kind()\n\treturn NormalizeKind(kind)\n}\n\n// NormalizeKind returns a normalized kind of the given kind.\nfunc NormalizeKind(kind reflect.Kind) reflect.Kind {\n\tswitch {\n\tcase kind >= reflect.Int && kind <= reflect.Int64:\n\t\treturn reflect.Int\n\tcase kind >= reflect.Uint && kind <= reflect.Uint64:\n\t\treturn reflect.Uint\n\tcase kind >= reflect.Float32 && kind <= reflect.Float64:\n\t\treturn reflect.Float64\n\tdefault:\n\t\treturn kind\n\t}\n}\n\n// DefaultDecodeConfig holds the default decoding configuration.\nvar DefaultDecodeConfig = DecodeConfig{\n\tDecodeHooks: []DecodeFunc{\n\t\tDatetimeDecoder(time.UTC),\n\t},\n}\n"
  },
  {
    "path": "service/netquery/orm/decoder_test.go",
    "content": "package orm\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"zombiezen.com/go/sqlite\"\n)\n\ntype testStmt struct {\n\tcolumns []string\n\tvalues  []interface{}\n\ttypes   []sqlite.ColumnType\n}\n\nfunc (ts testStmt) ColumnCount() int                   { return len(ts.columns) }\nfunc (ts testStmt) ColumnName(i int) string            { return ts.columns[i] }\nfunc (ts testStmt) ColumnBool(i int) bool              { return ts.values[i].(bool) }                    //nolint:forcetypeassert\nfunc (ts testStmt) ColumnText(i int) string            { return ts.values[i].(string) }                  //nolint:forcetypeassert\nfunc (ts testStmt) ColumnFloat(i int) float64          { return ts.values[i].(float64) }                 //nolint:forcetypeassert\nfunc (ts testStmt) ColumnInt(i int) int                { return ts.values[i].(int) }                     //nolint:forcetypeassert\nfunc (ts testStmt) ColumnReader(i int) *bytes.Reader   { return bytes.NewReader(ts.values[i].([]byte)) } //nolint:forcetypeassert\nfunc (ts testStmt) ColumnType(i int) sqlite.ColumnType { return ts.types[i] }\n\n// Compile time check.\nvar _ Stmt = new(testStmt)\n\ntype exampleFieldTypes struct {\n\tS string\n\tI int\n\tF float64\n\tB bool\n}\n\ntype examplePointerTypes struct {\n\tS *string\n\tI *int\n\tF *float64\n\tB *bool\n}\n\ntype exampleStructTags struct {\n\tS string `sqlite:\"col_string\"`\n\tI int    `sqlite:\"col_int\"`\n}\n\ntype exampleIntConv struct {\n\tI8  int8\n\tI16 int16\n\tI32 int32\n\tI64 int64\n\tI   int\n}\n\ntype exampleBlobTypes struct {\n\tB []byte\n}\n\ntype exampleJSONRawTypes struct {\n\tB json.RawMessage\n}\n\ntype exampleTimeTypes struct {\n\tT  time.Time\n\tTP *time.Time\n}\n\ntype exampleInterface struct {\n\tI  interface{}\n\tIP *interface{}\n}\n\nfunc (ett *exampleTimeTypes) Equal(other interface{}) bool {\n\toett, ok := other.(*exampleTimeTypes)\n\tif !ok {\n\t\treturn false\n\t}\n\treturn ett.T.Equal(oett.T) && (ett.TP != nil && oett.TP != nil && ett.TP.Equal(*oett.TP)) || (ett.TP == nil && oett.TP == nil)\n}\n\ntype myInt int\n\ntype exampleTimeNano struct {\n\tT time.Time `sqlite:\",unixnano\"`\n}\n\nfunc (etn *exampleTimeNano) Equal(other interface{}) bool {\n\toetn, ok := other.(*exampleTimeNano)\n\tif !ok {\n\t\treturn false\n\t}\n\treturn etn.T.Equal(oetn.T)\n}\n\nfunc TestDecoder(t *testing.T) { //nolint:maintidx,tparallel\n\tt.Parallel()\n\n\tctx := context.TODO()\n\trefTime := time.Date(2022, time.February, 15, 9, 51, 0, 0, time.UTC)\n\n\tcases := []struct {\n\t\tDesc      string\n\t\tStmt      testStmt\n\t\tColumnDef []ColumnDef\n\t\tResult    interface{}\n\t\tExpected  interface{}\n\t}{\n\t\t{\n\t\t\t\"Decoding into nil is not allowed\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: nil,\n\t\t\t\tvalues:  nil,\n\t\t\t\ttypes:   nil,\n\t\t\t},\n\t\t\tnil,\n\t\t\tnil,\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Decoding into basic types\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"S\", \"I\", \"F\", \"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t\"string value\",\n\t\t\t\t\t1,\n\t\t\t\t\t1.2,\n\t\t\t\t\ttrue,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleFieldTypes{},\n\t\t\t&exampleFieldTypes{\n\t\t\t\tS: \"string value\",\n\t\t\t\tI: 1,\n\t\t\t\tF: 1.2,\n\t\t\t\tB: true,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into basic types with different order\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"I\", \"S\", \"B\", \"F\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t1,\n\t\t\t\t\t\"string value\",\n\t\t\t\t\ttrue,\n\t\t\t\t\t1.2,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleFieldTypes{},\n\t\t\t&exampleFieldTypes{\n\t\t\t\tS: \"string value\",\n\t\t\t\tI: 1,\n\t\t\t\tF: 1.2,\n\t\t\t\tB: true,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into basic types with missing values\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"F\", \"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t1.2,\n\t\t\t\t\ttrue,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleFieldTypes{},\n\t\t\t&exampleFieldTypes{\n\t\t\t\tF: 1.2,\n\t\t\t\tB: true,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into pointer types\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"S\", \"I\", \"F\", \"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t\"string value\",\n\t\t\t\t\t1,\n\t\t\t\t\t1.2,\n\t\t\t\t\ttrue,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&examplePointerTypes{},\n\t\t\tfunc() interface{} {\n\t\t\t\ts := \"string value\"\n\t\t\t\ti := 1\n\t\t\t\tf := 1.2\n\t\t\t\tb := true\n\n\t\t\t\treturn &examplePointerTypes{\n\t\t\t\t\tS: &s,\n\t\t\t\t\tI: &i,\n\t\t\t\t\tF: &f,\n\t\t\t\t\tB: &b,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into pointer types with missing values\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"S\", \"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t\"string value\",\n\t\t\t\t\ttrue,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&examplePointerTypes{},\n\t\t\tfunc() interface{} {\n\t\t\t\ts := \"string value\"\n\t\t\t\tb := true\n\n\t\t\t\treturn &examplePointerTypes{\n\t\t\t\t\tS: &s,\n\t\t\t\t\tB: &b,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into fields with struct tags\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"col_string\", \"col_int\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t\"string value\",\n\t\t\t\t\t1,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleStructTags{},\n\t\t\t&exampleStructTags{\n\t\t\t\tS: \"string value\",\n\t\t\t\tI: 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into correct int type\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"I8\", \"I16\", \"I32\", \"I64\", \"I\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t1,\n\t\t\t\t\t1,\n\t\t\t\t\t1,\n\t\t\t\t\t1,\n\t\t\t\t\t1,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleIntConv{},\n\t\t\t&exampleIntConv{\n\t\t\t\t1, 1, 1, 1, 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handling NULL values for basic types\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"S\", \"I\", \"F\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeNull,\n\t\t\t\t\tsqlite.TypeNull,\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t// we use nil here but actually that does not matter\n\t\t\t\t\tnil,\n\t\t\t\t\tnil,\n\t\t\t\t\t1.0,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleFieldTypes{},\n\t\t\t&exampleFieldTypes{\n\t\t\t\tF: 1.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handling NULL values for pointer types\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"S\", \"I\", \"F\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeNull,\n\t\t\t\t\tsqlite.TypeNull,\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t// we use nil here but actually that does not matter\n\t\t\t\t\tnil,\n\t\t\t\t\tnil,\n\t\t\t\t\t1.0,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&examplePointerTypes{},\n\t\t\tfunc() interface{} {\n\t\t\t\tf := 1.0\n\n\t\t\t\treturn &examplePointerTypes{F: &f}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handling blob types\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeBlob,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t([]byte)(\"hello world\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleBlobTypes{},\n\t\t\t&exampleBlobTypes{\n\t\t\t\tB: ([]byte)(\"hello world\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handling blob types as json.RawMessage\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeBlob,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t([]byte)(\"hello world\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleJSONRawTypes{},\n\t\t\t&exampleJSONRawTypes{\n\t\t\t\tB: (json.RawMessage)(\"hello world\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handling time.Time and pointers to it\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"T\", \"TP\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\tint(refTime.Unix()),\n\t\t\t\t\tint(refTime.Unix()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleTimeTypes{},\n\t\t\t&exampleTimeTypes{\n\t\t\t\tT:  refTime,\n\t\t\t\tTP: &refTime,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handling time.Time in nano-second resolution (struct tags)\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"T\", \"TP\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\tint(refTime.UnixNano()),\n\t\t\t\t\tint(refTime.UnixNano()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleTimeNano{},\n\t\t\t&exampleTimeNano{\n\t\t\t\tT: refTime,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into interface\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"I\", \"IP\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t\"value1\",\n\t\t\t\t\t\"value2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\t&exampleInterface{},\n\t\t\tfunc() interface{} {\n\t\t\t\tvar x interface{} = \"value2\"\n\n\t\t\t\treturn &exampleInterface{\n\t\t\t\t\tI:  \"value1\",\n\t\t\t\t\tIP: &x,\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into map[string]interface{}\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"I\", \"F\", \"S\", \"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeFloat,\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t\tsqlite.TypeBlob,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t1,\n\t\t\t\t\t1.1,\n\t\t\t\t\t\"string value\",\n\t\t\t\t\t[]byte(\"blob value\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t\tnew(map[string]interface{}),\n\t\t\t&map[string]interface{}{\n\t\t\t\t\"I\": 1,\n\t\t\t\t\"F\": 1.1,\n\t\t\t\t\"S\": \"string value\",\n\t\t\t\t\"B\": []byte(\"blob value\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding using type-hints\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"B\", \"T\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeInteger,\n\t\t\t\t\tsqlite.TypeText,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\ttrue,\n\t\t\t\t\trefTime.Format(SqliteTimeFormat),\n\t\t\t\t},\n\t\t\t},\n\t\t\t[]ColumnDef{\n\t\t\t\t{\n\t\t\t\t\tName:   \"B\",\n\t\t\t\t\tType:   sqlite.TypeInteger,\n\t\t\t\t\tGoType: reflect.TypeOf(true),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"T\",\n\t\t\t\t\tType:   sqlite.TypeText,\n\t\t\t\t\tGoType: reflect.TypeOf(time.Time{}),\n\t\t\t\t\tIsTime: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnew(map[string]interface{}),\n\t\t\t&map[string]interface{}{\n\t\t\t\t\"B\": true,\n\t\t\t\t\"T\": refTime,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into type aliases\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"B\"},\n\t\t\t\ttypes: []sqlite.ColumnType{\n\t\t\t\t\tsqlite.TypeBlob,\n\t\t\t\t},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t[]byte(`{\"foo\": \"bar}`),\n\t\t\t\t},\n\t\t\t},\n\t\t\t[]ColumnDef{\n\t\t\t\t{\n\t\t\t\t\tName:   \"B\",\n\t\t\t\t\tType:   sqlite.TypeBlob,\n\t\t\t\t\tGoType: reflect.TypeOf(json.RawMessage(`{\"foo\": \"bar}`)),\n\t\t\t\t},\n\t\t\t},\n\t\t\tnew(map[string]interface{}),\n\t\t\t&map[string]interface{}{\n\t\t\t\t\"B\": json.RawMessage(`{\"foo\": \"bar}`),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Decoding into type aliases #2\",\n\t\t\ttestStmt{\n\t\t\t\tcolumns: []string{\"I\"},\n\t\t\t\ttypes:   []sqlite.ColumnType{sqlite.TypeInteger},\n\t\t\t\tvalues: []interface{}{\n\t\t\t\t\t10,\n\t\t\t\t},\n\t\t\t},\n\t\t\t[]ColumnDef{\n\t\t\t\t{\n\t\t\t\t\tName:   \"I\",\n\t\t\t\t\tType:   sqlite.TypeInteger,\n\t\t\t\t\tGoType: reflect.TypeOf(myInt(0)),\n\t\t\t\t},\n\t\t\t},\n\t\t\tnew(map[string]interface{}),\n\t\t\t&map[string]interface{}{\n\t\t\t\t\"I\": myInt(10),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor idx := range cases { //nolint:paralleltest\n\t\tc := cases[idx]\n\t\tt.Run(c.Desc, func(t *testing.T) {\n\t\t\t// log.Println(c.Desc)\n\t\t\terr := DecodeStmt(ctx, &TableSchema{Columns: c.ColumnDef}, c.Stmt, c.Result, DefaultDecodeConfig)\n\t\t\tif fn, ok := c.Expected.(func() interface{}); ok {\n\t\t\t\tc.Expected = fn()\n\t\t\t}\n\n\t\t\tif c.Expected == nil {\n\t\t\t\tassert.Error(t, err, c.Desc)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err, c.Desc)\n\n\t\t\t\tif equaler, ok := c.Expected.(interface{ Equal(x interface{}) bool }); ok {\n\t\t\t\t\tassert.True(t, equaler.Equal(c.Result))\n\t\t\t\t} else {\n\t\t\t\t\tassert.Equal(t, c.Expected, c.Result)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "service/netquery/orm/encoder.go",
    "content": "package orm\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"golang.org/x/exp/slices\"\n\t\"zombiezen.com/go/sqlite\"\n)\n\ntype (\n\t// EncodeFunc is called for each non-basic type during encoding.\n\tEncodeFunc func(col *ColumnDef, valType reflect.Type, val reflect.Value) (interface{}, bool, error)\n\n\t// EncodeConfig holds encoding functions.\n\tEncodeConfig struct {\n\t\tEncodeHooks []EncodeFunc\n\t}\n)\n\n// ToParamMap returns a map that contains the sqlite compatible value of each struct field of\n// r using the sqlite column name as a map key. It either uses the name of the\n// exported struct field or the value of the \"sqlite\" tag.\nfunc ToParamMap(ctx context.Context, r interface{}, keyPrefix string, cfg EncodeConfig, skipFields []string) (map[string]interface{}, error) {\n\t// make sure we work on a struct type\n\tval := reflect.Indirect(reflect.ValueOf(r))\n\tif val.Kind() != reflect.Struct {\n\t\treturn nil, fmt.Errorf(\"%w, got %T\", errStructExpected, r)\n\t}\n\n\tres := make(map[string]interface{}, val.NumField())\n\n\tfor i := range val.NumField() {\n\t\tfieldType := val.Type().Field(i)\n\t\tfield := val.Field(i)\n\n\t\t// skip unexported fields\n\t\tif !fieldType.IsExported() {\n\t\t\tcontinue\n\t\t}\n\n\t\tcolDef, err := getColumnDef(fieldType)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get column definition for %s: %w\", fieldType.Name, err)\n\t\t}\n\n\t\tif slices.Contains(skipFields, colDef.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tx, found, err := runEncodeHooks(\n\t\t\tcolDef,\n\t\t\tfieldType.Type,\n\t\t\tfield,\n\t\t\tappend(\n\t\t\t\tcfg.EncodeHooks,\n\t\t\t\tencodeBasic(),\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to run encode hooks: %w\", err)\n\t\t}\n\n\t\tif !found {\n\t\t\tif reflect.Indirect(field).IsValid() {\n\t\t\t\tx = reflect.Indirect(field).Interface()\n\t\t\t}\n\t\t}\n\n\t\tres[keyPrefix+sqlColumnName(fieldType)] = x\n\n\t}\n\n\treturn res, nil\n}\n\n// EncodeValue encodes the given value.\nfunc EncodeValue(ctx context.Context, colDef *ColumnDef, val interface{}, cfg EncodeConfig) (interface{}, error) {\n\tfieldValue := reflect.ValueOf(val)\n\tfieldType := reflect.TypeOf(val)\n\n\tx, found, err := runEncodeHooks(\n\t\tcolDef,\n\t\tfieldType,\n\t\tfieldValue,\n\t\tappend(\n\t\t\tcfg.EncodeHooks,\n\t\t\tencodeBasic(),\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to run encode hooks: %w\", err)\n\t}\n\n\tif !found {\n\t\tif reflect.Indirect(fieldValue).IsValid() {\n\t\t\tx = reflect.Indirect(fieldValue).Interface()\n\t\t}\n\t}\n\n\treturn x, nil\n}\n\nfunc encodeBasic() EncodeFunc {\n\treturn func(col *ColumnDef, valType reflect.Type, val reflect.Value) (interface{}, bool, error) {\n\t\tkind := valType.Kind()\n\t\tif kind == reflect.Ptr {\n\t\t\tvalType = valType.Elem()\n\t\t\tkind = valType.Kind()\n\n\t\t\tif val.IsNil() {\n\t\t\t\tif !col.Nullable {\n\t\t\t\t\t// we need to set the zero value here since the column\n\t\t\t\t\t// is not marked as nullable\n\t\t\t\t\treturn reflect.New(valType).Elem().Interface(), true, nil\n\t\t\t\t}\n\n\t\t\t\treturn nil, true, nil\n\t\t\t}\n\n\t\t\tval = val.Elem()\n\t\t}\n\n\t\tswitch NormalizeKind(kind) { //nolint:exhaustive\n\t\tcase reflect.String,\n\t\t\treflect.Float64,\n\t\t\treflect.Bool,\n\t\t\treflect.Int,\n\t\t\treflect.Uint:\n\t\t\t// sqlite package handles conversion of those types\n\t\t\t// already\n\t\t\treturn val.Interface(), true, nil\n\n\t\tcase reflect.Slice:\n\t\t\tif valType.Elem().Kind() == reflect.Uint8 {\n\t\t\t\t// this is []byte\n\t\t\t\treturn val.Interface(), true, nil\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tdefault:\n\t\t\treturn nil, false, fmt.Errorf(\"cannot convert value of kind %s for use in SQLite\", kind)\n\t\t}\n\t}\n}\n\n// DatetimeEncoder returns a new datetime encoder for the given time zone.\nfunc DatetimeEncoder(loc *time.Location) EncodeFunc {\n\treturn func(colDef *ColumnDef, valType reflect.Type, val reflect.Value) (interface{}, bool, error) {\n\t\t// if fieldType holds a pointer we need to dereference the value\n\t\tft := valType.String()\n\t\tif valType.Kind() == reflect.Ptr {\n\t\t\tft = valType.Elem().String()\n\t\t\tval = reflect.Indirect(val)\n\t\t}\n\n\t\tnormalizedKind := NormalizeKind(valType.Kind())\n\n\t\t// we only care about \"time.Time\" here\n\t\tvar t time.Time\n\t\tswitch {\n\t\tcase ft == \"time.Time\":\n\t\t\t// handle the zero time as a NULL.\n\t\t\tif !val.IsValid() || val.IsZero() {\n\t\t\t\treturn nil, true, nil\n\t\t\t}\n\n\t\t\tvar ok bool\n\t\t\tvalInterface := val.Interface()\n\t\t\tt, ok = valInterface.(time.Time)\n\t\t\tif !ok {\n\t\t\t\treturn nil, false, errors.New(\"cannot convert reflect value to time.Time\")\n\t\t\t}\n\n\t\tcase valType.Kind() == reflect.String && colDef.IsTime:\n\t\t\tvar err error\n\t\t\tt, err = time.Parse(time.RFC3339, val.String())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to parse time as RFC3339: %w\", err)\n\t\t\t}\n\n\t\tcase (normalizedKind == reflect.Int || normalizedKind == reflect.Uint || normalizedKind == reflect.Float64) && colDef.IsTime:\n\t\t\tseconds := int64(0)\n\t\t\tswitch normalizedKind { //nolint:exhaustive // Previous switch case assures these types.\n\t\t\tcase reflect.Int:\n\t\t\t\tseconds = val.Int()\n\t\t\tcase reflect.Uint:\n\t\t\t\tseconds = int64(val.Uint())\n\t\t\tcase reflect.Float64:\n\t\t\t\tseconds = int64(val.Float())\n\t\t\t}\n\n\t\t\tt = time.Unix(seconds, 0)\n\n\t\tdefault:\n\t\t\t// we don't care ...\n\t\t\treturn nil, false, nil\n\t\t}\n\n\t\tswitch colDef.Type { //nolint:exhaustive\n\t\tcase sqlite.TypeInteger:\n\t\t\tif colDef.UnixNano {\n\t\t\t\treturn t.UnixNano(), true, nil\n\t\t\t}\n\t\t\treturn t.Unix(), true, nil\n\n\t\tcase sqlite.TypeText:\n\t\t\tstr := t.In(loc).Format(SqliteTimeFormat)\n\n\t\t\treturn str, true, nil\n\t\t}\n\n\t\treturn nil, false, fmt.Errorf(\"cannot store time.Time in %s\", colDef.Type)\n\t}\n}\n\nfunc runEncodeHooks(colDef *ColumnDef, valType reflect.Type, val reflect.Value, hooks []EncodeFunc) (interface{}, bool, error) {\n\tif valType == nil {\n\t\tif !colDef.Nullable {\n\t\t\tswitch colDef.Type { //nolint:exhaustive\n\t\t\tcase sqlite.TypeBlob:\n\t\t\t\treturn []byte{}, true, nil\n\t\t\tcase sqlite.TypeFloat:\n\t\t\t\treturn 0.0, true, nil\n\t\t\tcase sqlite.TypeText:\n\t\t\t\treturn \"\", true, nil\n\t\t\tcase sqlite.TypeInteger:\n\t\t\t\treturn 0, true, nil\n\t\t\tdefault:\n\t\t\t\treturn nil, false, fmt.Errorf(\"unsupported sqlite data type: %s\", colDef.Type)\n\t\t\t}\n\t\t}\n\n\t\treturn nil, true, nil\n\t}\n\n\tfor _, fn := range hooks {\n\t\tres, end, err := fn(colDef, valType, val)\n\t\tif err != nil {\n\t\t\treturn res, false, err\n\t\t}\n\n\t\tif end {\n\t\t\treturn res, true, nil\n\t\t}\n\t}\n\n\treturn nil, false, nil\n}\n\n// DefaultEncodeConfig holds the default encoding configuration.\nvar DefaultEncodeConfig = EncodeConfig{\n\tEncodeHooks: []EncodeFunc{\n\t\tDatetimeEncoder(time.UTC),\n\t},\n}\n"
  },
  {
    "path": "service/netquery/orm/encoder_test.go",
    "content": "package orm\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"zombiezen.com/go/sqlite\"\n)\n\nfunc TestEncodeAsMap(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tctx := context.TODO()\n\trefTime := time.Date(2022, time.February, 15, 9, 51, 0, 0, time.UTC)\n\n\tcases := []struct {\n\t\tDesc     string\n\t\tInput    interface{}\n\t\tExpected map[string]interface{}\n\t}{\n\t\t{\n\t\t\t\"Encode basic types\",\n\t\t\tstruct {\n\t\t\t\tI int\n\t\t\t\tF float64\n\t\t\t\tS string\n\t\t\t\tB []byte\n\t\t\t}{\n\t\t\t\tI: 1,\n\t\t\t\tF: 1.2,\n\t\t\t\tS: \"string\",\n\t\t\t\tB: ([]byte)(\"bytes\"),\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"I\": 1,\n\t\t\t\t\"F\": 1.2,\n\t\t\t\t\"S\": \"string\",\n\t\t\t\t\"B\": ([]byte)(\"bytes\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Encode using struct tags\",\n\t\t\tstruct {\n\t\t\t\tI int    `sqlite:\"col_int\"`\n\t\t\t\tS string `sqlite:\"col_string\"`\n\t\t\t}{\n\t\t\t\tI: 1,\n\t\t\t\tS: \"string value\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"col_int\":    1,\n\t\t\t\t\"col_string\": \"string value\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Ignore Private fields\",\n\t\t\tstruct {\n\t\t\t\tI int\n\t\t\t\ts string\n\t\t\t}{\n\t\t\t\tI: 1,\n\t\t\t\ts: \"string value\",\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"I\": 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handle Pointers\",\n\t\t\tstruct {\n\t\t\t\tI *int\n\t\t\t\tS *string\n\t\t\t}{\n\t\t\t\tI: new(int),\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"I\": 0,\n\t\t\t\t\"S\": nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handle time.Time types\",\n\t\t\tstruct {\n\t\t\t\tTinInt    time.Time `sqlite:\",integer,unixnano\"`\n\t\t\t\tTinString time.Time `sqlite:\",text\"`\n\t\t\t}{\n\t\t\t\tTinInt:    refTime,\n\t\t\t\tTinString: refTime,\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"TinInt\":    refTime.UnixNano(),\n\t\t\t\t\"TinString\": refTime.Format(SqliteTimeFormat),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Handle time.Time pointer types\",\n\t\t\tstruct {\n\t\t\t\tTinInt    *time.Time `sqlite:\",integer,unixnano\"`\n\t\t\t\tTinString *time.Time `sqlite:\",text\"`\n\t\t\t\tTnil1     *time.Time `sqlite:\",text\"`\n\t\t\t\tTnil2     *time.Time `sqlite:\",text\"`\n\t\t\t}{\n\t\t\t\tTinInt:    &refTime,\n\t\t\t\tTinString: &refTime,\n\t\t\t\tTnil1:     nil,\n\t\t\t\tTnil2:     (*time.Time)(nil),\n\t\t\t},\n\t\t\tmap[string]interface{}{\n\t\t\t\t\"TinInt\":    refTime.UnixNano(),\n\t\t\t\t\"TinString\": refTime.Format(SqliteTimeFormat),\n\t\t\t\t\"Tnil1\":     nil,\n\t\t\t\t\"Tnil2\":     nil,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor idx := range cases { //nolint:paralleltest\n\t\tc := cases[idx]\n\t\tt.Run(c.Desc, func(t *testing.T) {\n\t\t\tres, err := ToParamMap(ctx, c.Input, \"\", DefaultEncodeConfig, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, c.Expected, res)\n\t\t})\n\t}\n}\n\nfunc TestEncodeValue(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tctx := context.TODO()\n\trefTime := time.Date(2022, time.February, 15, 9, 51, 0, 0, time.UTC)\n\n\tcases := []struct {\n\t\tDesc   string\n\t\tColumn ColumnDef\n\t\tInput  interface{}\n\t\tOutput interface{}\n\t}{\n\t\t{\n\t\t\t\"Special value time.Time as text\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime: true,\n\t\t\t\tType:   sqlite.TypeText,\n\t\t\t},\n\t\t\trefTime,\n\t\t\trefTime.Format(SqliteTimeFormat),\n\t\t},\n\t\t{\n\t\t\t\"Special value time.Time as unix-epoch\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime: true,\n\t\t\t\tType:   sqlite.TypeInteger,\n\t\t\t},\n\t\t\trefTime,\n\t\t\trefTime.Unix(),\n\t\t},\n\t\t{\n\t\t\t\"Special value time.Time as unixnano-epoch\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime:   true,\n\t\t\t\tType:     sqlite.TypeInteger,\n\t\t\t\tUnixNano: true,\n\t\t\t},\n\t\t\trefTime,\n\t\t\trefTime.UnixNano(),\n\t\t},\n\t\t{\n\t\t\t\"Special value zero time\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime: true,\n\t\t\t\tType:   sqlite.TypeText,\n\t\t\t},\n\t\t\ttime.Time{},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Special value zero time pointer\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime: true,\n\t\t\t\tType:   sqlite.TypeText,\n\t\t\t},\n\t\t\tnew(time.Time),\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Special value *time.Time as text\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime: true,\n\t\t\t\tType:   sqlite.TypeText,\n\t\t\t},\n\t\t\t&refTime,\n\t\t\trefTime.Format(SqliteTimeFormat),\n\t\t},\n\t\t{\n\t\t\t\"Special value untyped nil\",\n\t\t\tColumnDef{\n\t\t\t\tNullable: true,\n\t\t\t\tIsTime:   true,\n\t\t\t\tType:     sqlite.TypeText,\n\t\t\t},\n\t\t\tnil,\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Special value typed nil\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime: true,\n\t\t\t\tType:   sqlite.TypeText,\n\t\t\t},\n\t\t\t(*time.Time)(nil),\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Time formated as string\",\n\t\t\tColumnDef{\n\t\t\t\tIsTime: true,\n\t\t\t\tType:   sqlite.TypeText,\n\t\t\t},\n\t\t\trefTime.In(time.Local).Format(time.RFC3339),\n\t\t\trefTime.Format(SqliteTimeFormat),\n\t\t},\n\t\t{\n\t\t\t\"Nullable integer\",\n\t\t\tColumnDef{\n\t\t\t\tType:     sqlite.TypeInteger,\n\t\t\t\tNullable: true,\n\t\t\t},\n\t\t\tnil,\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Not-Null integer\",\n\t\t\tColumnDef{\n\t\t\t\tName: \"test\",\n\t\t\t\tType: sqlite.TypeInteger,\n\t\t\t},\n\t\t\tnil,\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t\"Not-Null string\",\n\t\t\tColumnDef{\n\t\t\t\tType: sqlite.TypeText,\n\t\t\t},\n\t\t\tnil,\n\t\t\t\"\",\n\t\t},\n\t}\n\n\tfor idx := range cases { //nolint:paralleltest\n\t\tc := cases[idx]\n\t\tt.Run(c.Desc, func(t *testing.T) {\n\t\t\tres, err := EncodeValue(ctx, &c.Column, c.Input, DefaultEncodeConfig)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, c.Output, res)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "service/netquery/orm/query_runner.go",
    "content": "package orm\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"zombiezen.com/go/sqlite\"\n\t\"zombiezen.com/go/sqlite/sqlitex\"\n)\n\ntype (\n\t// QueryOption can be specified at RunQuery to alter the behavior\n\t// of the executed query.\n\tQueryOption func(opts *queryOpts)\n\n\tqueryOpts struct {\n\t\tTransient    bool\n\t\tArgs         []interface{}\n\t\tNamedArgs    map[string]interface{}\n\t\tResult       interface{}\n\t\tDecodeConfig DecodeConfig\n\t\tSchema       TableSchema\n\t}\n)\n\n// WithTransient marks the query as transient.\n//\n// Transient queries will not be cached for later\n// re-use after they have been prepared.\nfunc WithTransient() QueryOption {\n\treturn func(opts *queryOpts) {\n\t\topts.Transient = true\n\t}\n}\n\n// WithArgs adds a list of arguments for the query. Arguments\n// are applied in order.\n//\n// See SQL Language Expression documentation of SQLite for\n// details: https://sqlite.org/lang_expr.html\nfunc WithArgs(args ...interface{}) QueryOption {\n\treturn func(opts *queryOpts) {\n\t\topts.Args = args\n\t}\n}\n\n// WithNamedArgs adds args to the query. The query must used\n// named argument placeholders. According to the SQLite spec,\n// arguments must either start with ':', '@' or '$'.\n//\n// See SQL Language Expression documentation of SQLite for\n// details: https://sqlite.org/lang_expr.html\nfunc WithNamedArgs(args map[string]interface{}) QueryOption {\n\treturn func(opts *queryOpts) {\n\t\topts.NamedArgs = args\n\t}\n}\n\n// WithSchema returns a query option that adds the given table\n// schema to the query.\nfunc WithSchema(tbl TableSchema) QueryOption {\n\treturn func(opts *queryOpts) {\n\t\topts.Schema = tbl\n\t}\n}\n\n// WithResult sets the result receiver. result is expected to\n// be a pointer to a slice of struct or map types.\n//\n// For decoding DecodeStmt is used to decode each\n// row into a new slice element. It thus supports special values\n// like time.Time. See DecodeStmt() and WithDecodeConfig() for\n// more information.\nfunc WithResult(result interface{}) QueryOption {\n\treturn func(opts *queryOpts) {\n\t\topts.Result = result\n\t}\n}\n\n// WithDecodeConfig configures the DecodeConfig to use when\n// calling DecodeStmt to decode each row into the result slice.\n//\n// If not specified, DefaultDecodeConfig will be used.\nfunc WithDecodeConfig(cfg DecodeConfig) QueryOption {\n\treturn func(opts *queryOpts) {\n\t\topts.DecodeConfig = cfg\n\t}\n}\n\n// RunQuery executes the query stored in sql against the databased opened in\n// conn. Please refer to the documentation of QueryOption, especially WithResult()\n// for more information on how to retrieve the resulting rows.\n//\n// Example:\n//\n//\tvar result []struct{\n//\t\tCount int `sqlite:\"rowCount\"`\n//\t}\n//\n//\terr := RunQuery(ctx, conn, \"SELECT COUNT(*) AS rowCount FROM table\", WithResult(&result))\n//\tfmt.Println(result[0].Count)\nfunc RunQuery(ctx context.Context, conn *sqlite.Conn, sql string, modifiers ...QueryOption) error {\n\targs := queryOpts{\n\t\tDecodeConfig: DefaultDecodeConfig,\n\t}\n\n\tfor _, fn := range modifiers {\n\t\tfn(&args)\n\t}\n\n\topts := &sqlitex.ExecOptions{\n\t\tArgs:  args.Args,\n\t\tNamed: args.NamedArgs,\n\t}\n\n\tvar (\n\t\tsliceVal    reflect.Value\n\t\tvalElemType reflect.Type\n\t)\n\n\tif args.Result != nil {\n\t\ttarget := args.Result\n\t\toutVal := reflect.ValueOf(target)\n\t\tif outVal.Kind() != reflect.Ptr {\n\t\t\treturn fmt.Errorf(\"target must be a pointer, got %T\", target)\n\t\t}\n\n\t\tsliceVal = reflect.Indirect(outVal)\n\t\tif !sliceVal.IsValid() || sliceVal.IsNil() {\n\t\t\tnewVal := reflect.Zero(outVal.Type().Elem())\n\t\t\tsliceVal.Set(newVal)\n\t\t}\n\n\t\tkind := sliceVal.Kind()\n\t\tif kind != reflect.Slice {\n\t\t\treturn fmt.Errorf(\"target but be pointer to slice, got %T\", target)\n\t\t}\n\t\tvalType := sliceVal.Type()\n\t\tvalElemType = valType.Elem()\n\n\t\topts.ResultFunc = func(stmt *sqlite.Stmt) error {\n\t\t\tcurrentField := reflect.New(valElemType)\n\n\t\t\tif err := DecodeStmt(ctx, &args.Schema, stmt, currentField.Interface(), args.DecodeConfig); err != nil {\n\t\t\t\tresultDump := make(map[string]any)\n\n\t\t\t\tfor colIdx := range stmt.ColumnCount() {\n\t\t\t\t\tname := stmt.ColumnName(colIdx)\n\n\t\t\t\t\tswitch stmt.ColumnType(colIdx) { //nolint:exhaustive // TODO: handle type BLOB?\n\t\t\t\t\tcase sqlite.TypeText:\n\t\t\t\t\t\tresultDump[name] = stmt.ColumnText(colIdx)\n\t\t\t\t\tcase sqlite.TypeFloat:\n\t\t\t\t\t\tresultDump[name] = stmt.ColumnFloat(colIdx)\n\t\t\t\t\tcase sqlite.TypeInteger:\n\t\t\t\t\t\tresultDump[name] = stmt.ColumnInt(colIdx)\n\t\t\t\t\tcase sqlite.TypeNull:\n\t\t\t\t\t\tresultDump[name] = \"<null>\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn fmt.Errorf(\"%w: %+v\", err, resultDump)\n\t\t\t}\n\n\t\t\tsliceVal = reflect.Append(sliceVal, reflect.Indirect(currentField))\n\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tvar err error\n\tif args.Transient {\n\t\terr = sqlitex.ExecuteTransient(conn, sql, opts)\n\t} else {\n\t\terr = sqlitex.Execute(conn, sql, opts)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif args.Result != nil {\n\t\treflect.Indirect(reflect.ValueOf(args.Result)).Set(sliceVal)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/netquery/orm/schema_builder.go",
    "content": "package orm\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"zombiezen.com/go/sqlite\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar errSkipStructField = errors.New(\"struct field should be skipped\")\n\n// Struct Tags.\nvar (\n\tTagUnixNano          = \"unixnano\"\n\tTagPrimaryKey        = \"primary\"\n\tTagAutoIncrement     = \"autoincrement\"\n\tTagTime              = \"time\"\n\tTagNotNull           = \"not-null\"\n\tTagNullable          = \"nullable\"\n\tTagTypeInt           = \"integer\"\n\tTagTypeText          = \"text\"\n\tTagTypePrefixVarchar = \"varchar\"\n\tTagTypeBlob          = \"blob\"\n\tTagTypeFloat         = \"float\"\n\tTagTypePrefixDefault = \"default=\"\n)\n\nvar sqlTypeMap = map[sqlite.ColumnType]string{\n\tsqlite.TypeBlob:    \"BLOB\",\n\tsqlite.TypeFloat:   \"REAL\",\n\tsqlite.TypeInteger: \"INTEGER\",\n\tsqlite.TypeText:    \"TEXT\",\n}\n\ntype (\n\t// TableSchema defines a SQL table schema.\n\tTableSchema struct {\n\t\tName    string\n\t\tColumns []ColumnDef\n\t}\n\n\t// ColumnDef defines a SQL column.\n\tColumnDef struct { //nolint:maligned\n\t\tName          string\n\t\tNullable      bool\n\t\tType          sqlite.ColumnType\n\t\tGoType        reflect.Type\n\t\tLength        int\n\t\tPrimaryKey    bool\n\t\tAutoIncrement bool\n\t\tUnixNano      bool\n\t\tIsTime        bool\n\t\tDefault       any\n\t}\n)\n\n// GetColumnDef returns the column definition with the given name.\nfunc (ts TableSchema) GetColumnDef(name string) *ColumnDef {\n\tfor _, def := range ts.Columns {\n\t\tif def.Name == name {\n\t\t\treturn &def\n\t\t}\n\t}\n\treturn nil\n}\n\n// CreateStatement build the CREATE SQL statement for the table.\nfunc (ts TableSchema) CreateStatement(databaseName string, ifNotExists bool) string {\n\tsql := \"CREATE TABLE\"\n\tif ifNotExists {\n\t\tsql += \" IF NOT EXISTS\"\n\t}\n\tname := ts.Name\n\tif databaseName != \"\" {\n\t\tname = databaseName + \".\" + ts.Name\n\t}\n\n\tsql += \" \" + name + \" ( \"\n\n\tfor idx, col := range ts.Columns {\n\t\tsql += col.AsSQL()\n\t\tif idx < len(ts.Columns)-1 {\n\t\t\tsql += \", \"\n\t\t}\n\t}\n\n\tsql += \" );\"\n\treturn sql\n}\n\n// AsSQL builds the SQL column definition.\nfunc (def ColumnDef) AsSQL() string {\n\tsql := def.Name + \" \"\n\n\tif def.Type == sqlite.TypeText && def.Length > 0 {\n\t\tsql += fmt.Sprintf(\"VARCHAR(%d)\", def.Length)\n\t} else {\n\t\tsql += sqlTypeMap[def.Type]\n\t}\n\n\tif def.PrimaryKey {\n\t\tsql += \" PRIMARY KEY\"\n\t}\n\tif def.AutoIncrement {\n\t\tsql += \" AUTOINCREMENT\"\n\t}\n\tif def.Default != nil {\n\t\tsql += \" DEFAULT \"\n\t\tswitch def.Type { //nolint:exhaustive // TODO: handle types BLOB, NULL?\n\t\tcase sqlite.TypeFloat:\n\t\t\tsql += strconv.FormatFloat(def.Default.(float64), 'b', 0, 64) //nolint:forcetypeassert\n\t\tcase sqlite.TypeInteger:\n\t\t\tsql += strconv.FormatInt(def.Default.(int64), 10) //nolint:forcetypeassert\n\t\tcase sqlite.TypeText:\n\t\t\tsql += fmt.Sprintf(\"%q\", def.Default.(string)) //nolint:forcetypeassert\n\t\tdefault:\n\t\t\tlog.Errorf(\"unsupported default value: %q %q\", def.Type, def.Default)\n\t\t\tsql = strings.TrimSuffix(sql, \" DEFAULT \")\n\t\t}\n\t\tsql += \" \"\n\t}\n\tif !def.Nullable {\n\t\tsql += \" NOT NULL\"\n\t}\n\n\treturn sql\n}\n\n// GenerateTableSchema generates a table schema from the given struct.\nfunc GenerateTableSchema(name string, d interface{}) (*TableSchema, error) {\n\tts := &TableSchema{\n\t\tName: name,\n\t}\n\n\tval := reflect.Indirect(reflect.ValueOf(d))\n\tif val.Kind() != reflect.Struct {\n\t\treturn nil, fmt.Errorf(\"%w, got %T\", errStructExpected, d)\n\t}\n\n\tfor i := range val.NumField() {\n\t\tfieldType := val.Type().Field(i)\n\t\tif !fieldType.IsExported() {\n\t\t\tcontinue\n\t\t}\n\n\t\tdef, err := getColumnDef(fieldType)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, errSkipStructField) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"struct field %s: %w\", fieldType.Name, err)\n\t\t}\n\n\t\tts.Columns = append(ts.Columns, *def)\n\t}\n\n\treturn ts, nil\n}\n\nfunc getColumnDef(fieldType reflect.StructField) (*ColumnDef, error) {\n\tdef := &ColumnDef{\n\t\tName:     fieldType.Name,\n\t\tNullable: fieldType.Type.Kind() == reflect.Ptr,\n\t}\n\n\tft := fieldType.Type\n\n\tif fieldType.Type.Kind() == reflect.Ptr {\n\t\tft = fieldType.Type.Elem()\n\t}\n\n\tdef.GoType = ft\n\tkind := NormalizeKind(ft.Kind())\n\n\tswitch kind { //nolint:exhaustive\n\tcase reflect.Int, reflect.Uint:\n\t\tdef.Type = sqlite.TypeInteger\n\n\tcase reflect.Float64:\n\t\tdef.Type = sqlite.TypeFloat\n\n\tcase reflect.String:\n\t\tdef.Type = sqlite.TypeText\n\n\tcase reflect.Slice:\n\t\t// only []byte/[]uint8 is supported\n\t\tif ft.Elem().Kind() != reflect.Uint8 {\n\t\t\treturn nil, fmt.Errorf(\"slices of type %s is not supported\", ft.Elem())\n\t\t}\n\n\t\tdef.Type = sqlite.TypeBlob\n\t}\n\n\tif err := applyStructFieldTag(fieldType, def); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn def, nil\n}\n\n// applyStructFieldTag parses the sqlite:\"\" struct field tag and update the column\n// definition def accordingly.\nfunc applyStructFieldTag(fieldType reflect.StructField, def *ColumnDef) error {\n\tparts := strings.Split(fieldType.Tag.Get(\"sqlite\"), \",\")\n\tif len(parts) > 0 && parts[0] != \"\" {\n\t\tif parts[0] == \"-\" {\n\t\t\treturn errSkipStructField\n\t\t}\n\n\t\tdef.Name = parts[0]\n\t}\n\n\tif len(parts) > 1 {\n\t\tfor _, k := range parts[1:] {\n\t\t\tswitch k {\n\t\t\t// column modifiers\n\t\t\tcase TagPrimaryKey:\n\t\t\t\tdef.PrimaryKey = true\n\t\t\tcase TagAutoIncrement:\n\t\t\t\tdef.AutoIncrement = true\n\t\t\tcase TagNotNull:\n\t\t\t\tdef.Nullable = false\n\t\t\tcase TagNullable:\n\t\t\t\tdef.Nullable = true\n\t\t\tcase TagUnixNano:\n\t\t\t\tdef.UnixNano = true\n\t\t\tcase TagTime:\n\t\t\t\tdef.IsTime = true\n\n\t\t\t// basic column types\n\t\t\tcase TagTypeInt:\n\t\t\t\tdef.Type = sqlite.TypeInteger\n\t\t\tcase TagTypeText:\n\t\t\t\tdef.Type = sqlite.TypeText\n\t\t\tcase TagTypeFloat:\n\t\t\t\tdef.Type = sqlite.TypeFloat\n\t\t\tcase TagTypeBlob:\n\t\t\t\tdef.Type = sqlite.TypeBlob\n\n\t\t\t// advanced column types\n\t\t\tdefault:\n\t\t\t\tif strings.HasPrefix(k, TagTypePrefixVarchar) {\n\t\t\t\t\tlenStr := strings.TrimSuffix(strings.TrimPrefix(k, TagTypePrefixVarchar+\"(\"), \")\")\n\t\t\t\t\tlength, err := strconv.ParseInt(lenStr, 10, 0)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to parse varchar length %q: %w\", lenStr, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tdef.Type = sqlite.TypeText\n\t\t\t\t\tdef.Length = int(length)\n\t\t\t\t}\n\n\t\t\t\tif strings.HasPrefix(k, TagTypePrefixDefault) {\n\t\t\t\t\tdefaultValue := strings.TrimPrefix(k, TagTypePrefixDefault)\n\t\t\t\t\tswitch def.Type { //nolint:exhaustive\n\t\t\t\t\tcase sqlite.TypeFloat:\n\t\t\t\t\t\tfv, err := strconv.ParseFloat(defaultValue, 64)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to parse default value as float %q: %w\", defaultValue, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdef.Default = fv\n\t\t\t\t\tcase sqlite.TypeInteger:\n\t\t\t\t\t\tfv, err := strconv.ParseInt(defaultValue, 10, 0)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to parse default value as int %q: %w\", defaultValue, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdef.Default = fv\n\t\t\t\t\tcase sqlite.TypeText:\n\t\t\t\t\t\tdef.Default = defaultValue\n\t\t\t\t\tcase sqlite.TypeBlob:\n\t\t\t\t\t\treturn errors.New(\"default values for TypeBlob not yet supported\")\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to apply default value for unknown sqlite column type %s\", def.Type)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/netquery/orm/schema_builder_test.go",
    "content": "package orm\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSchemaBuilder(t *testing.T) {\n\tt.Parallel()\n\n\tcases := []struct {\n\t\tName        string\n\t\tModel       interface{}\n\t\tExpectedSQL string\n\t}{\n\t\t{\n\t\t\t\"Simple\",\n\t\t\tstruct {\n\t\t\t\tID    int         `sqlite:\"id,primary,autoincrement\"`\n\t\t\t\tText  string      `sqlite:\"text,nullable\"`\n\t\t\t\tInt   *int        `sqlite:\",not-null\"`\n\t\t\t\tFloat interface{} `sqlite:\",float,nullable\"`\n\t\t\t}{},\n\t\t\t`CREATE TABLE main.Simple ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, text TEXT, Int INTEGER NOT NULL, Float REAL );`,\n\t\t},\n\t\t{\n\t\t\t\"Varchar\",\n\t\t\tstruct {\n\t\t\t\tS string `sqlite:\",varchar(10)\"`\n\t\t\t}{},\n\t\t\t`CREATE TABLE main.Varchar ( S VARCHAR(10) NOT NULL );`,\n\t\t},\n\t}\n\n\tfor idx := range cases {\n\t\tc := cases[idx]\n\n\t\tres, err := GenerateTableSchema(c.Name, c.Model)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, c.ExpectedSQL, res.CreateStatement(\"main\", false))\n\t}\n}\n"
  },
  {
    "path": "service/netquery/query.go",
    "content": "package netquery\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"golang.org/x/exp/slices\"\n\t\"zombiezen.com/go/sqlite\"\n\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n)\n\n// DatabaseName is a database name constant.\ntype DatabaseName string\n\n// Databases.\nconst (\n\tLiveDatabase    = DatabaseName(\"main\")\n\tHistoryDatabase = DatabaseName(\"history\")\n)\n\n// Collection of Query and Matcher types.\n// NOTE: whenever adding support for new operators make sure\n// to update UnmarshalJSON as well.\n//\n//nolint:golint\ntype (\n\tQuery map[string][]Matcher\n\n\tMatchType interface {\n\t\tOperator() string\n\t}\n\n\tEqual interface{}\n\n\tMatcher struct {\n\t\tEqual          interface{}   `json:\"$eq,omitempty\"`\n\t\tNotEqual       interface{}   `json:\"$ne,omitempty\"`\n\t\tIn             []interface{} `json:\"$in,omitempty\"`\n\t\tNotIn          []interface{} `json:\"$notIn,omitempty\"`\n\t\tLike           string        `json:\"$like,omitempty\"`\n\t\tGreater        *float64      `json:\"$gt,omitempty\"`\n\t\tGreaterOrEqual *float64      `json:\"$ge,omitempty\"`\n\t\tLess           *float64      `json:\"$lt,omitempty\"`\n\t\tLessOrEqual    *float64      `json:\"$le,omitempty\"`\n\t}\n\n\tCount struct {\n\t\tAs       string `json:\"as\"`\n\t\tField    string `json:\"field\"`\n\t\tDistinct bool   `json:\"distinct\"`\n\t}\n\n\tSum struct {\n\t\tCondition Query  `json:\"condition\"`\n\t\tField     string `json:\"field\"`\n\t\tAs        string `json:\"as\"`\n\t\tDistinct  bool   `json:\"distinct\"`\n\t}\n\n\tMin struct {\n\t\tCondition *Query `json:\"condition,omitempty\"`\n\t\tField     string `json:\"field\"`\n\t\tAs        string `json:\"as\"`\n\t\tDistinct  bool   `json:\"distinct\"`\n\t}\n\n\tFieldSelect struct {\n\t\tField string `json:\"field\"`\n\t\tAs    string `json:\"as\"`\n\t}\n\n\tSelect struct {\n\t\tField       string       `json:\"field\"`\n\t\tFieldSelect *FieldSelect `json:\"$field\"`\n\t\tCount       *Count       `json:\"$count,omitempty\"`\n\t\tSum         *Sum         `json:\"$sum,omitempty\"`\n\t\tMin         *Min         `json:\"$min,omitempty\"`\n\t\tDistinct    *string      `json:\"$distinct,omitempty\"`\n\t}\n\n\tSelects []Select\n\n\tTextSearch struct {\n\t\tFields []string `json:\"fields\"`\n\t\tValue  string   `json:\"value\"`\n\t}\n\n\tQueryActiveConnectionChartPayload struct {\n\t\tQuery      Query       `json:\"query\"`\n\t\tTextSearch *TextSearch `json:\"textSearch\"`\n\t}\n\n\tOrderBy struct {\n\t\tField string `json:\"field\"`\n\t\tDesc  bool   `json:\"desc\"`\n\t}\n\n\tOrderBys []OrderBy\n\n\tPagination struct {\n\t\tPageSize int `json:\"pageSize\"`\n\t\tPage     int `json:\"page\"`\n\t}\n)\n\n// UnmarshalJSON unmarshals a Query from json.\nfunc (query *Query) UnmarshalJSON(blob []byte) error {\n\tif *query == nil {\n\t\t*query = make(Query)\n\t}\n\n\tvar model map[string]json.RawMessage\n\n\tif err := json.Unmarshal(blob, &model); err != nil {\n\t\treturn err\n\t}\n\n\tfor columnName, rawColumnQuery := range model {\n\t\tif len(rawColumnQuery) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch rawColumnQuery[0] {\n\t\tcase '{':\n\t\t\tm, err := parseMatcher(rawColumnQuery)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t(*query)[columnName] = []Matcher{*m}\n\n\t\tcase '[':\n\t\t\tvar rawMatchers []json.RawMessage\n\t\t\tif err := json.Unmarshal(rawColumnQuery, &rawMatchers); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t(*query)[columnName] = make([]Matcher, len(rawMatchers))\n\t\t\tfor idx, val := range rawMatchers {\n\t\t\t\t// this should not happen\n\t\t\t\tif len(val) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// if val starts with a { we have a matcher definition\n\t\t\t\tif val[0] == '{' {\n\t\t\t\t\tm, err := parseMatcher(val)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\t(*query)[columnName][idx] = *m\n\n\t\t\t\t\tcontinue\n\t\t\t\t} else if val[0] == '[' {\n\t\t\t\t\treturn fmt.Errorf(\"invalid token [ in query for column %s\", columnName)\n\t\t\t\t}\n\n\t\t\t\t// val is a dedicated JSON primitive and not an object or array\n\t\t\t\t// so we treat that as an EQUAL condition.\n\t\t\t\tvar x interface{}\n\t\t\t\tif err := json.Unmarshal(val, &x); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\t(*query)[columnName][idx] = Matcher{\n\t\t\t\t\tEqual: x,\n\t\t\t\t}\n\t\t\t}\n\n\t\tdefault:\n\t\t\t// value is a JSON primitive and not an object or array\n\t\t\t// so we treat that as an EQUAL condition.\n\t\t\tvar x interface{}\n\t\t\tif err := json.Unmarshal(rawColumnQuery, &x); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t(*query)[columnName] = []Matcher{\n\t\t\t\t{Equal: x},\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// TODO(ppacher): right now we only support LIMIT and OFFSET for pagination but that\n// has an issue that loading the same page twice might yield different results due to\n// new records shifting the result slice. To overcome this, return a \"PageToken\" to the\n// user that includes the time the initial query was created so paginated queries can\n// ensure new records don't end up in the result set.\nfunc (page *Pagination) toSQLLimitOffsetClause() string {\n\tlimit := page.PageSize\n\n\t// default and cap the limit to at most 100 items\n\t// per page to avoid out-of-memory conditions when loading\n\t// thousands of results at once.\n\tif limit <= 0 || limit > 100 {\n\t\tlimit = 100\n\t}\n\n\tsql := fmt.Sprintf(\"LIMIT %d\", limit)\n\n\tif page.Page > 0 {\n\t\tsql += fmt.Sprintf(\" OFFSET %d\", page.Page*limit)\n\t}\n\n\treturn sql\n}\n\nfunc parseMatcher(raw json.RawMessage) (*Matcher, error) {\n\tvar m Matcher\n\tif err := json.Unmarshal(raw, &m); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := m.Validate(); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid query matcher: %w\", err)\n\t}\n\n\t// log.Printf(\"parsed matcher %s: %+v\", string(raw), m)\n\treturn &m, nil\n}\n\n// Validate validates the matcher.\nfunc (match Matcher) Validate() error {\n\tfound := 0\n\n\tif match.Equal != nil {\n\t\tfound++\n\t}\n\n\tif match.NotEqual != nil {\n\t\tfound++\n\t}\n\n\tif match.In != nil {\n\t\tfound++\n\t}\n\n\tif match.NotIn != nil {\n\t\tfound++\n\t}\n\n\tif match.Like != \"\" {\n\t\tfound++\n\t}\n\n\tif match.Greater != nil {\n\t\tfound++\n\t}\n\n\tif match.GreaterOrEqual != nil {\n\t\tfound++\n\t}\n\n\tif match.Less != nil {\n\t\tfound++\n\t}\n\n\tif match.LessOrEqual != nil {\n\t\tfound++\n\t}\n\n\tif found == 0 {\n\t\treturn fmt.Errorf(\"no conditions specified\")\n\t}\n\n\treturn nil\n}\n\nfunc (text TextSearch) toSQLConditionClause(_ context.Context, schema *orm.TableSchema, suffix string, _ orm.EncodeConfig) (string, map[string]interface{}, error) {\n\tvar (\n\t\tqueryParts = make([]string, 0, len(text.Fields))\n\t\tparams     = make(map[string]interface{})\n\t)\n\n\tkey := fmt.Sprintf(\":t%s\", suffix)\n\tparams[key] = fmt.Sprintf(\"%%%s%%\", text.Value)\n\n\tfor _, field := range text.Fields {\n\t\tcolDef := schema.GetColumnDef(field)\n\t\tif colDef == nil {\n\t\t\treturn \"\", nil, fmt.Errorf(\"column %s is not allowed in text-search\", colDef.Name)\n\t\t}\n\t\tif colDef.Type != sqlite.TypeText {\n\t\t\treturn \"\", nil, fmt.Errorf(\"type of column %s cannot be used in text-search\", colDef.Name)\n\t\t}\n\n\t\tqueryParts = append(queryParts, fmt.Sprintf(\"%s LIKE %s\", colDef.Name, key))\n\t}\n\n\tif len(queryParts) == 0 {\n\t\treturn \"\", nil, nil\n\t}\n\n\treturn \"( \" + strings.Join(queryParts, \" OR \") + \" )\", params, nil\n}\n\nfunc (match Matcher) toSQLConditionClause(ctx context.Context, suffix string, conjunction string, colDef orm.ColumnDef, encoderConfig orm.EncodeConfig) (string, map[string]interface{}, error) {\n\tvar (\n\t\tqueryParts []string\n\t\tparams     = make(map[string]interface{})\n\t\terrs       = new(multierror.Error)\n\t\tkey        = fmt.Sprintf(\"%s%s\", colDef.Name, suffix)\n\t)\n\n\tadd := func(operator, suffix string, list bool, values ...interface{}) {\n\t\tvar placeholder []string\n\n\t\tfor idx, value := range values {\n\t\t\tvar (\n\t\t\t\tencodedValue any\n\t\t\t\terr          error\n\t\t\t)\n\n\t\t\tkind := orm.NormalizeKind(reflect.TypeOf(value).Kind())\n\t\t\tisNumber := slices.Contains([]reflect.Kind{\n\t\t\t\treflect.Uint,\n\t\t\t\treflect.Int,\n\t\t\t\treflect.Float64,\n\t\t\t}, kind)\n\n\t\t\t// if we query a time-field that is queried as a number, don't do any encoding\n\t\t\t// here as the orm.DateTimeEncoder would convert the number to a string.\n\t\t\tif colDef.IsTime && colDef.Type == sqlite.TypeText && isNumber {\n\t\t\t\tencodedValue = value\n\t\t\t} else {\n\t\t\t\tencodedValue, err = orm.EncodeValue(ctx, &colDef, value, encoderConfig)\n\t\t\t\tif err != nil {\n\t\t\t\t\terrs.Errors = append(errs.Errors,\n\t\t\t\t\t\tfmt.Errorf(\"failed to encode %v for column %s: %w\", value, colDef.Name, err),\n\t\t\t\t\t)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuniqKey := fmt.Sprintf(\":%s%s%d\", key, suffix, idx)\n\t\t\tplaceholder = append(placeholder, uniqKey)\n\t\t\tparams[uniqKey] = encodedValue\n\t\t}\n\n\t\tnameStmt := colDef.Name\n\n\t\tif len(values) > 0 {\n\t\t\t// NOTE(ppacher): for now we assume that the type of each element of values\n\t\t\t// is the same. We also can be sure that there is always at least one value.\n\t\t\t//\n\t\t\t// TODO(ppacher): if we start supporting values of different types here\n\t\t\t// we need to revisit the whole behavior as we might need to do more boolean\n\t\t\t// expression nesting to support that.\n\t\t\tkind := orm.NormalizeKind(reflect.TypeOf(values[0]).Kind())\n\t\t\tisNumber := slices.Contains([]reflect.Kind{\n\t\t\t\treflect.Uint,\n\t\t\t\treflect.Int,\n\t\t\t\treflect.Float64,\n\t\t\t}, kind)\n\n\t\t\t// if this is a time column that is stored in \"text\" format and the provided\n\t\t\t// value is a number type, we need to wrap the property in a strftime() method\n\t\t\t// call.\n\t\t\tif colDef.IsTime && colDef.Type == sqlite.TypeText && isNumber {\n\t\t\t\tnameStmt = fmt.Sprintf(\"strftime('%%s', %s)+0\", nameStmt)\n\t\t\t}\n\t\t}\n\n\t\tif len(placeholder) == 1 && !list {\n\t\t\tqueryParts = append(queryParts, fmt.Sprintf(\"%s %s %s\", nameStmt, operator, placeholder[0]))\n\t\t} else {\n\t\t\tqueryParts = append(queryParts, fmt.Sprintf(\"%s %s ( %s )\", nameStmt, operator, strings.Join(placeholder, \", \")))\n\t\t}\n\t}\n\n\tif match.Equal != nil {\n\t\tadd(\"=\", \"eq\", false, match.Equal)\n\t}\n\n\tif match.NotEqual != nil {\n\t\tadd(\"!=\", \"ne\", false, match.NotEqual)\n\t}\n\n\tif match.In != nil {\n\t\tadd(\"IN\", \"in\", true, match.In...)\n\t}\n\n\tif match.NotIn != nil {\n\t\tadd(\"NOT IN\", \"notin\", true, match.NotIn...)\n\t}\n\n\tif match.Like != \"\" {\n\t\tadd(\"LIKE\", \"like\", false, match.Like)\n\t}\n\n\tif match.Greater != nil {\n\t\tadd(\">\", \"gt\", false, *match.Greater)\n\t}\n\n\tif match.GreaterOrEqual != nil {\n\t\tadd(\">=\", \"ge\", false, *match.GreaterOrEqual)\n\t}\n\n\tif match.Less != nil {\n\t\tadd(\"<\", \"lt\", false, *match.Less)\n\t}\n\n\tif match.LessOrEqual != nil {\n\t\tadd(\"<=\", \"le\", false, *match.LessOrEqual)\n\t}\n\n\tif len(queryParts) == 0 {\n\t\t// this is an empty matcher without a single condition.\n\t\t// we convert that to a no-op TRUE value\n\t\treturn \"( 1 = 1 )\", nil, errs.ErrorOrNil()\n\t}\n\n\tif len(queryParts) == 1 {\n\t\treturn queryParts[0], params, errs.ErrorOrNil()\n\t}\n\n\treturn \"( \" + strings.Join(queryParts, \" \"+conjunction+\" \") + \" )\", params, errs.ErrorOrNil()\n}\n\nfunc (query Query) toSQLWhereClause(ctx context.Context, suffix string, m *orm.TableSchema, encoderConfig orm.EncodeConfig) (string, map[string]interface{}, error) {\n\tif len(query) == 0 {\n\t\treturn \"\", nil, nil\n\t}\n\n\t// create a lookup map to validate column names\n\tlm := make(map[string]orm.ColumnDef, len(m.Columns))\n\tfor _, col := range m.Columns {\n\t\tlm[col.Name] = col\n\t}\n\n\tparamMap := make(map[string]interface{})\n\tcolumnStmts := make([]string, 0, len(query))\n\n\t// get all keys and sort them so we get a stable output\n\tqueryKeys := make([]string, 0, len(query))\n\tfor column := range query {\n\t\tqueryKeys = append(queryKeys, column)\n\t}\n\tsort.Strings(queryKeys)\n\n\t// actually create the WHERE clause parts for each\n\t// column in query.\n\terrs := new(multierror.Error)\n\tfor _, column := range queryKeys {\n\t\tvalues := query[column]\n\t\tcolDef, ok := lm[column]\n\t\tif !ok {\n\n\t\t\terrs.Errors = append(errs.Errors, fmt.Errorf(\"column %s is not allowed\", column))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tqueryParts := make([]string, len(values))\n\t\tfor idx, val := range values {\n\t\t\tmatcherQuery, params, err := val.toSQLConditionClause(ctx, fmt.Sprintf(\"%s%d\", suffix, idx), \"AND\", colDef, encoderConfig)\n\t\t\tif err != nil {\n\t\t\t\terrs.Errors = append(errs.Errors,\n\t\t\t\t\tfmt.Errorf(\"invalid matcher at index %d for column %s: %w\", idx, colDef.Name, err),\n\t\t\t\t)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// merge parameters up into the superior parameter map\n\t\t\tfor key, val := range params {\n\t\t\t\tif _, ok := paramMap[key]; ok {\n\t\t\t\t\t// This is solely a developer mistake when implementing a matcher so no forgiving ...\n\t\t\t\t\tpanic(\"sqlite parameter collision\")\n\t\t\t\t}\n\n\t\t\t\tparamMap[key] = val\n\t\t\t}\n\n\t\t\tqueryParts[idx] = matcherQuery\n\t\t}\n\n\t\tcolumnStmts = append(columnStmts,\n\t\t\tfmt.Sprintf(\"( %s )\", strings.Join(queryParts, \" OR \")),\n\t\t)\n\t}\n\n\twhereClause := strings.Join(columnStmts, \" AND \")\n\n\treturn whereClause, paramMap, errs.ErrorOrNil()\n}\n\n// UnmarshalJSON unmarshals a Selects from json.\nfunc (sel *Selects) UnmarshalJSON(blob []byte) error {\n\tif len(blob) == 0 {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\n\t// if we are looking at a slice directly decode into\n\t// a []Select\n\tif blob[0] == '[' {\n\t\tvar result []Select\n\t\tif err := json.Unmarshal(blob, &result); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t(*sel) = result\n\n\t\treturn nil\n\t}\n\n\t// if it's an object decode into a single select\n\tif blob[0] == '{' {\n\t\tvar result Select\n\t\tif err := json.Unmarshal(blob, &result); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t*sel = []Select{result}\n\n\t\treturn nil\n\t}\n\n\t// otherwise this is just the field name\n\tvar field string\n\tif err := json.Unmarshal(blob, &field); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// UnmarshalJSON unmarshals a Select from json.\nfunc (sel *Select) UnmarshalJSON(blob []byte) error {\n\tif len(blob) == 0 {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\n\t// if we have an object at hand decode the select\n\t// directly\n\tif blob[0] == '{' {\n\t\tvar res struct {\n\t\t\tField       string       `json:\"field\"`\n\t\t\tCount       *Count       `json:\"$count\"`\n\t\t\tSum         *Sum         `json:\"$sum\"`\n\t\t\tMin         *Min         `json:\"$min\"`\n\t\t\tDistinct    *string      `json:\"$distinct\"`\n\t\t\tFieldSelect *FieldSelect `json:\"$field\"`\n\t\t}\n\n\t\tif err := json.Unmarshal(blob, &res); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsel.Count = res.Count\n\t\tsel.Field = res.Field\n\t\tsel.FieldSelect = res.FieldSelect\n\t\tsel.Distinct = res.Distinct\n\t\tsel.Sum = res.Sum\n\t\tsel.Min = res.Min\n\n\t\tif sel.Count != nil && sel.Count.As != \"\" {\n\t\t\tif !charOnlyRegexp.MatchString(sel.Count.As) {\n\t\t\t\treturn fmt.Errorf(\"invalid characters in $count.as, value must match [a-zA-Z]+\")\n\t\t\t}\n\t\t}\n\t\tif sel.Sum != nil && sel.Sum.As != \"\" {\n\t\t\tif !charOnlyRegexp.MatchString(sel.Sum.As) {\n\t\t\t\treturn fmt.Errorf(\"invalid characters in $sum.as, value must match [a-zA-Z]+\")\n\t\t\t}\n\t\t}\n\t\tif sel.Min != nil && sel.Min.As != \"\" {\n\t\t\tif !charOnlyRegexp.MatchString(sel.Min.As) {\n\t\t\t\treturn fmt.Errorf(\"invalid characters in $min.as, value must match [a-zA-Z]+\")\n\t\t\t}\n\t\t}\n\t\tif sel.FieldSelect != nil && sel.FieldSelect.As != \"\" {\n\t\t\tif !charOnlyRegexp.MatchString(sel.FieldSelect.As) {\n\t\t\t\treturn fmt.Errorf(\"invalid characters in $field.as, value must match [a-zA-Z]+\")\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tvar x string\n\tif err := json.Unmarshal(blob, &x); err != nil {\n\t\treturn err\n\t}\n\n\tsel.Field = x\n\n\treturn nil\n}\n\n// UnmarshalJSON unmarshals a OrderBys from json.\nfunc (orderBys *OrderBys) UnmarshalJSON(blob []byte) error {\n\tif len(blob) == 0 {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\n\tif blob[0] == '[' {\n\t\tvar result []OrderBy\n\t\tif err := json.Unmarshal(blob, &result); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t*orderBys = result\n\n\t\treturn nil\n\t}\n\n\tif blob[0] == '{' {\n\t\tvar result OrderBy\n\t\tif err := json.Unmarshal(blob, &result); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t*orderBys = []OrderBy{result}\n\n\t\treturn nil\n\t}\n\n\tvar field string\n\tif err := json.Unmarshal(blob, &field); err != nil {\n\t\treturn err\n\t}\n\n\t*orderBys = []OrderBy{\n\t\t{\n\t\t\tField: field,\n\t\t\tDesc:  false,\n\t\t},\n\t}\n\n\treturn nil\n}\n\n// UnmarshalJSON unmarshals a OrderBy from json.\nfunc (orderBy *OrderBy) UnmarshalJSON(blob []byte) error {\n\tif len(blob) == 0 {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\n\tif blob[0] == '{' {\n\t\tvar res struct {\n\t\t\tField string `json:\"field\"`\n\t\t\tDesc  bool   `json:\"desc\"`\n\t\t}\n\n\t\tif err := json.Unmarshal(blob, &res); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\torderBy.Desc = res.Desc\n\t\torderBy.Field = res.Field\n\n\t\treturn nil\n\t}\n\n\tvar field string\n\tif err := json.Unmarshal(blob, &field); err != nil {\n\t\treturn err\n\t}\n\n\torderBy.Field = field\n\torderBy.Desc = false\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/netquery/query_handler.go",
    "content": "package netquery\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\tservertiming \"github.com/mitchellh/go-server-timing\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n)\n\nvar charOnlyRegexp = regexp.MustCompile(\"[a-zA-Z]+\")\n\nconst failedQuery = \"Failed to execute query: \"\n\ntype (\n\n\t// QueryHandler implements http.Handler and allows to perform SQL\n\t// query and aggregate functions on Database.\n\tQueryHandler struct {\n\t\tIsDevMode func() bool\n\t\tDatabase  *Database\n\t}\n\n\t// BatchQueryHandler implements http.Handler and allows to perform SQL\n\t// query and aggregate functions on Database in batches.\n\tBatchQueryHandler struct {\n\t\tIsDevMode func() bool\n\t\tDatabase  *Database\n\t}\n)\n\nfunc (qh *QueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {\n\ttiming := servertiming.FromContext(req.Context())\n\n\ttimingQueryParsed := timing.NewMetric(\"query_parsed\").\n\t\tWithDesc(\"Query has been parsed\").\n\t\tStart()\n\n\trequestPayload, err := parseQueryRequestPayload[QueryRequestPayload](req)\n\tif err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\treturn\n\t}\n\n\ttimingQueryParsed.Stop()\n\n\ttimingQueryBuilt := timing.NewMetric(\"query_built\").\n\t\tWithDesc(\"The SQL query has been built\").\n\t\tStart()\n\n\tquery, paramMap, err := requestPayload.generateSQL(req.Context(), qh.Database.Schema)\n\tif err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\treturn\n\t}\n\n\ttimingQueryBuilt.Stop()\n\n\ttimingQueryExecute := timing.NewMetric(\"sql_exec\").\n\t\tWithDesc(\"SQL query execution time\").\n\t\tStart()\n\n\t// actually execute the query against the database and collect the result\n\tvar result []map[string]interface{}\n\tif err := qh.Database.Execute(\n\t\treq.Context(),\n\t\tquery,\n\t\torm.WithNamedArgs(paramMap),\n\t\torm.WithResult(&result),\n\t\torm.WithSchema(*qh.Database.Schema),\n\t); err != nil {\n\t\thttp.Error(resp, failedQuery+err.Error(), http.StatusInternalServerError)\n\n\t\treturn\n\t}\n\ttimingQueryExecute.Stop()\n\n\t// send the HTTP status code\n\tresp.WriteHeader(http.StatusOK)\n\n\t// prepare the result encoder.\n\tenc := json.NewEncoder(resp)\n\tenc.SetEscapeHTML(false)\n\tenc.SetIndent(\"\", \"  \")\n\n\t// prepare the result body that, in dev mode, contains\n\t// some diagnostics data about the query\n\tvar resultBody map[string]interface{}\n\tif qh.IsDevMode() {\n\t\tresultBody = map[string]interface{}{\n\t\t\t\"sql_prep_stmt\": query,\n\t\t\t\"sql_params\":    paramMap,\n\t\t\t\"query\":         requestPayload.Query,\n\t\t\t\"orderBy\":       requestPayload.OrderBy,\n\t\t\t\"groupBy\":       requestPayload.GroupBy,\n\t\t\t\"selects\":       requestPayload.Select,\n\t\t}\n\t} else {\n\t\tresultBody = make(map[string]interface{})\n\t}\n\tresultBody[\"results\"] = result\n\n\t// and finally stream the response\n\tif err := enc.Encode(resultBody); err != nil {\n\t\t// we failed to encode the JSON body to resp so we likely either already sent a\n\t\t// few bytes or the pipe was already closed. In either case, trying to send the\n\t\t// error using http.Error() is non-sense. We just log it out here and that's all\n\t\t// we can do.\n\t\tlog.Errorf(\"failed to encode JSON response: %s\", err)\n\n\t\treturn\n\t}\n}\n\nfunc (batch *BatchQueryHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {\n\ttiming := servertiming.FromContext(req.Context())\n\n\ttimingQueryParsed := timing.NewMetric(\"query_parsed\").\n\t\tWithDesc(\"Query has been parsed\").\n\t\tStart()\n\n\trequestPayload, err := parseQueryRequestPayload[BatchQueryRequestPayload](req)\n\tif err != nil {\n\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\treturn\n\t}\n\n\ttimingQueryParsed.Stop()\n\n\tresponse := make(map[string][]map[string]any, len(*requestPayload))\n\n\tbatches := make([]BatchExecute, 0, len(*requestPayload))\n\n\tfor key, query := range *requestPayload {\n\n\t\ttimingQueryBuilt := timing.NewMetric(\"query_built_\" + key).\n\t\t\tWithDesc(\"The SQL query has been built\").\n\t\t\tStart()\n\n\t\tsql, paramMap, err := query.generateSQL(req.Context(), batch.Database.Schema)\n\t\tif err != nil {\n\t\t\thttp.Error(resp, err.Error(), http.StatusBadRequest)\n\n\t\t\treturn\n\t\t}\n\n\t\ttimingQueryBuilt.Stop()\n\n\t\tvar result []map[string]any\n\t\tbatches = append(batches, BatchExecute{\n\t\t\tID:     key,\n\t\t\tSQL:    sql,\n\t\t\tParams: paramMap,\n\t\t\tResult: &result,\n\t\t})\n\t}\n\n\ttimingQueryExecute := timing.NewMetric(\"sql_exec\").\n\t\tWithDesc(\"SQL query execution time\").\n\t\tStart()\n\n\tstatus := http.StatusOK\n\tif err := batch.Database.ExecuteBatch(req.Context(), batches); err != nil {\n\t\tstatus = http.StatusInternalServerError\n\n\t\tvar merr *multierror.Error\n\t\tif errors.As(err, &merr) {\n\t\t\tfor _, e := range merr.Errors {\n\t\t\t\tresp.Header().Add(\"X-Query-Error\", e.Error())\n\t\t\t}\n\t\t} else {\n\t\t\t// Should not happen, ExecuteBatch always returns a multierror.Error\n\t\t\tresp.WriteHeader(status)\n\n\t\t\treturn\n\t\t}\n\t}\n\n\ttimingQueryExecute.Stop()\n\n\t// collect the results\n\tfor _, b := range batches {\n\t\tresponse[b.ID] = *b.Result\n\t}\n\n\t// send the HTTP status code\n\tresp.WriteHeader(status)\n\n\t// prepare the result encoder.\n\tenc := json.NewEncoder(resp)\n\tenc.SetEscapeHTML(false)\n\tenc.SetIndent(\"\", \"  \")\n\n\t// and finally stream the response\n\tif err := enc.Encode(response); err != nil {\n\t\t// we failed to encode the JSON body to resp so we likely either already sent a\n\t\t// few bytes or the pipe was already closed. In either case, trying to send the\n\t\t// error using http.Error() is non-sense. We just log it out here and that's all\n\t\t// we can do.\n\t\tlog.Errorf(\"failed to encode JSON response: %s\", err)\n\n\t\treturn\n\t}\n}\n\nfunc parseQueryRequestPayload[T any](req *http.Request) (*T, error) { //nolint:dupl\n\tvar (\n\t\tbody           io.Reader\n\t\trequestPayload T\n\t)\n\n\tswitch req.Method {\n\tcase http.MethodPost, http.MethodPut:\n\t\tbody = req.Body\n\tcase http.MethodGet:\n\t\tbody = strings.NewReader(req.URL.Query().Get(\"q\"))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid HTTP method\")\n\t}\n\n\tblob, err := io.ReadAll(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read body: %w\", err)\n\t}\n\n\tbody = bytes.NewReader(blob)\n\n\tdec := json.NewDecoder(body)\n\tdec.DisallowUnknownFields()\n\n\tif err := json.Unmarshal(blob, &requestPayload); err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"invalid query: %w\", err)\n\t}\n\n\treturn &requestPayload, nil\n}\n\n// Compile time check.\nvar _ http.Handler = new(QueryHandler)\n"
  },
  {
    "path": "service/netquery/query_request.go",
    "content": "package netquery\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n)\n\ntype (\n\t// QueryRequestPayload describes the payload of a netquery query.\n\tQueryRequestPayload struct {\n\t\tSelect     Selects     `json:\"select\"`\n\t\tQuery      Query       `json:\"query\"`\n\t\tOrderBy    OrderBys    `json:\"orderBy\"`\n\t\tGroupBy    []string    `json:\"groupBy\"`\n\t\tTextSearch *TextSearch `json:\"textSearch\"`\n\t\t// A list of databases to query. If left empty,\n\t\t// both, the LiveDatabase and the HistoryDatabase are queried\n\t\tDatabases []DatabaseName `json:\"databases\"`\n\n\t\tPagination\n\n\t\tselectedFields    []string\n\t\twhitelistedFields []string\n\t\tparamMap          map[string]interface{}\n\t}\n\n\t// BatchQueryRequestPayload describes the payload of a batch netquery\n\t// query. The map key is used in the response to identify the results\n\t// for each query of the batch request.\n\tBatchQueryRequestPayload map[string]QueryRequestPayload\n)\n\nfunc (req *QueryRequestPayload) generateSQL(ctx context.Context, schema *orm.TableSchema) (string, map[string]interface{}, error) {\n\tif err := req.prepareSelectedFields(ctx, schema); err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"perparing selected fields: %w\", err)\n\t}\n\n\t// build the SQL where clause from the payload query\n\twhereClause, paramMap, err := req.Query.toSQLWhereClause(\n\t\tctx,\n\t\t\"\",\n\t\tschema,\n\t\torm.DefaultEncodeConfig,\n\t)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"generating where clause: %w\", err)\n\t}\n\n\treq.mergeParams(paramMap)\n\n\tif req.TextSearch != nil {\n\t\ttextClause, textParams, err := req.TextSearch.toSQLConditionClause(ctx, schema, \"\", orm.DefaultEncodeConfig)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, fmt.Errorf(\"generating text-search clause: %w\", err)\n\t\t}\n\n\t\tif textClause != \"\" {\n\t\t\tif whereClause != \"\" {\n\t\t\t\twhereClause += \" AND \"\n\t\t\t}\n\n\t\t\twhereClause += textClause\n\n\t\t\treq.mergeParams(textParams)\n\t\t}\n\t}\n\n\tgroupByClause, err := req.generateGroupByClause(schema)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"generating group-by clause: %w\", err)\n\t}\n\n\torderByClause, err := req.generateOrderByClause(schema)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"generating order-by clause: %w\", err)\n\t}\n\n\tselectClause := req.generateSelectClause()\n\n\tif whereClause != \"\" {\n\t\twhereClause = \"WHERE \" + whereClause\n\t}\n\n\t// if no database is specified we default to LiveDatabase only.\n\tif len(req.Databases) == 0 {\n\t\treq.Databases = []DatabaseName{LiveDatabase}\n\t}\n\n\tsources := make([]string, len(req.Databases))\n\tfor idx, db := range req.Databases {\n\t\tsources[idx] = fmt.Sprintf(\"SELECT * FROM %s.connections %s\", db, whereClause)\n\t}\n\n\tsource := strings.Join(sources, \" UNION \")\n\n\tquery := `SELECT ` + selectClause + ` FROM ( ` + source + ` ) `\n\n\tquery += \" \" + groupByClause + \" \" + orderByClause + \" \" + req.Pagination.toSQLLimitOffsetClause()\n\n\treturn strings.TrimSpace(query), req.paramMap, nil\n}\n\nfunc (req *QueryRequestPayload) prepareSelectedFields(ctx context.Context, schema *orm.TableSchema) error {\n\tfor idx, s := range req.Select {\n\t\tvar field string\n\n\t\tswitch {\n\t\tcase s.Count != nil:\n\t\t\tfield = s.Count.Field\n\t\tcase s.Distinct != nil:\n\t\t\tfield = *s.Distinct\n\t\tcase s.Sum != nil:\n\t\t\tif s.Sum.Field != \"\" {\n\t\t\t\tfield = s.Sum.Field\n\t\t\t} else {\n\t\t\t\tfield = \"*\"\n\t\t\t}\n\t\tcase s.Min != nil:\n\t\t\tif s.Min.Field != \"\" {\n\t\t\t\tfield = s.Min.Field\n\t\t\t} else {\n\t\t\t\tfield = \"*\"\n\t\t\t}\n\t\tcase s.FieldSelect != nil:\n\t\t\tfield = s.FieldSelect.Field\n\t\tdefault:\n\t\t\tfield = s.Field\n\t\t}\n\n\t\tcolName := \"*\"\n\t\tif field != \"*\" || (s.Count == nil && s.Sum == nil) {\n\t\t\tvar err error\n\n\t\t\tcolName, err = req.validateColumnName(schema, field)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tswitch {\n\t\tcase s.FieldSelect != nil:\n\t\t\tas := s.FieldSelect.As\n\t\t\tif as == \"\" {\n\t\t\t\tas = s.FieldSelect.Field\n\t\t\t}\n\n\t\t\treq.selectedFields = append(\n\t\t\t\treq.selectedFields,\n\t\t\t\tfmt.Sprintf(\"%s AS %s\", s.FieldSelect.Field, as),\n\t\t\t)\n\t\t\treq.whitelistedFields = append(req.whitelistedFields, as)\n\n\t\tcase s.Count != nil:\n\t\t\tas := s.Count.As\n\t\t\tif as == \"\" {\n\t\t\t\tas = fmt.Sprintf(\"%s_count\", colName)\n\t\t\t}\n\t\t\tdistinct := \"\"\n\t\t\tif s.Count.Distinct {\n\t\t\t\tdistinct = \"DISTINCT \"\n\t\t\t}\n\t\t\treq.selectedFields = append(\n\t\t\t\treq.selectedFields,\n\t\t\t\tfmt.Sprintf(\"COUNT(%s%s) AS %s\", distinct, colName, as),\n\t\t\t)\n\t\t\treq.whitelistedFields = append(req.whitelistedFields, as)\n\n\t\tcase s.Sum != nil:\n\t\t\tif s.Sum.As == \"\" {\n\t\t\t\treturn fmt.Errorf(\"missing 'as' for $sum\")\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tclause string\n\t\t\t\tparams map[string]any\n\t\t\t)\n\n\t\t\tif s.Sum.Field != \"\" {\n\t\t\t\tclause = s.Sum.Field\n\t\t\t} else {\n\t\t\t\tvar err error\n\t\t\t\tclause, params, err = s.Sum.Condition.toSQLWhereClause(ctx, fmt.Sprintf(\"sel%d\", idx), schema, orm.DefaultEncodeConfig)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"in $sum: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treq.mergeParams(params)\n\t\t\treq.selectedFields = append(\n\t\t\t\treq.selectedFields,\n\t\t\t\tfmt.Sprintf(\"SUM(%s) AS %s\", clause, s.Sum.As),\n\t\t\t)\n\t\t\treq.whitelistedFields = append(req.whitelistedFields, s.Sum.As)\n\n\t\tcase s.Min != nil:\n\t\t\tif s.Min.As == \"\" {\n\t\t\t\treturn fmt.Errorf(\"missing 'as' for $min\")\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tclause string\n\t\t\t\tparams map[string]any\n\t\t\t)\n\n\t\t\tif s.Min.Field != \"\" {\n\t\t\t\tclause = field\n\t\t\t} else {\n\t\t\t\tvar err error\n\t\t\t\tclause, params, err = s.Min.Condition.toSQLWhereClause(ctx, fmt.Sprintf(\"sel%d\", idx), schema, orm.DefaultEncodeConfig)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"in $min: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treq.mergeParams(params)\n\t\t\treq.selectedFields = append(\n\t\t\t\treq.selectedFields,\n\t\t\t\tfmt.Sprintf(\"MIN(%s) AS %s\", clause, s.Min.As),\n\t\t\t)\n\t\t\treq.whitelistedFields = append(req.whitelistedFields, s.Min.As)\n\n\t\tcase s.Distinct != nil:\n\t\t\treq.selectedFields = append(req.selectedFields, fmt.Sprintf(\"DISTINCT %s\", colName))\n\t\t\treq.whitelistedFields = append(req.whitelistedFields, colName)\n\n\t\tdefault:\n\t\t\treq.selectedFields = append(req.selectedFields, colName)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (req *QueryRequestPayload) mergeParams(params map[string]any) {\n\tif req.paramMap == nil {\n\t\treq.paramMap = make(map[string]any)\n\t}\n\n\tfor key, value := range params {\n\t\treq.paramMap[key] = value\n\t}\n}\n\nfunc (req *QueryRequestPayload) generateGroupByClause(schema *orm.TableSchema) (string, error) {\n\tif len(req.GroupBy) == 0 {\n\t\treturn \"\", nil\n\t}\n\n\tgroupBys := make([]string, len(req.GroupBy))\n\tfor idx, name := range req.GroupBy {\n\t\tcolName, err := req.validateColumnName(schema, name)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tgroupBys[idx] = colName\n\t}\n\tgroupByClause := \"GROUP BY \" + strings.Join(groupBys, \", \")\n\n\t// if there are no explicitly selected fields we default to the\n\t// group-by columns as that's what's expected most of the time anyway...\n\tif len(req.selectedFields) == 0 {\n\t\treq.selectedFields = append(req.selectedFields, groupBys...)\n\t}\n\n\treturn groupByClause, nil\n}\n\nfunc (req *QueryRequestPayload) generateSelectClause() string {\n\tselectClause := \"*\"\n\tif len(req.selectedFields) > 0 {\n\t\tselectClause = strings.Join(req.selectedFields, \", \")\n\t}\n\n\treturn selectClause\n}\n\nfunc (req *QueryRequestPayload) generateOrderByClause(schema *orm.TableSchema) (string, error) {\n\tif len(req.OrderBy) == 0 {\n\t\treturn \"\", nil\n\t}\n\n\torderBys := make([]string, len(req.OrderBy))\n\tfor idx, sort := range req.OrderBy {\n\t\tcolName, err := req.validateColumnName(schema, sort.Field)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tif sort.Desc {\n\t\t\torderBys[idx] = fmt.Sprintf(\"%s DESC\", colName)\n\t\t} else {\n\t\t\torderBys[idx] = fmt.Sprintf(\"%s ASC\", colName)\n\t\t}\n\t}\n\n\treturn \"ORDER BY \" + strings.Join(orderBys, \", \"), nil\n}\n\nfunc (req *QueryRequestPayload) validateColumnName(schema *orm.TableSchema, field string) (string, error) {\n\tcolDef := schema.GetColumnDef(field)\n\tif colDef != nil {\n\t\treturn colDef.Name, nil\n\t}\n\n\tif slices.Contains(req.whitelistedFields, field) {\n\t\treturn field, nil\n\t}\n\n\tif slices.Contains(req.selectedFields, field) {\n\t\treturn field, nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"column name %q not allowed\", field)\n}\n"
  },
  {
    "path": "service/netquery/query_test.go",
    "content": "package netquery\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n)\n\nfunc TestUnmarshalQuery(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tcases := []struct {\n\t\tName     string\n\t\tInput    string\n\t\tExpected Query\n\t\tError    error\n\t}{\n\t\t{\n\t\t\t\"Parse a simple query\",\n\t\t\t`{ \"domain\": [\"example.com\", \"example.at\"] }`,\n\t\t\tQuery{\n\t\t\t\t\"domain\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tEqual: \"example.com\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tEqual: \"example.at\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Parse a more complex query\",\n\t\t\t`\n\t\t\t{\n\t\t\t\t\"domain\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"$in\": [\n\t\t\t\t\t\t\t\"example.at\",\n\t\t\t\t\t\t\t\"example.com\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"$like\": \"microsoft.%\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"path\": [\n\t\t\t\t\t\"/bin/ping\",\n\t\t\t\t\t{\n\t\t\t\t\t\t\"$notin\": [\n\t\t\t\t\t\t\t\"/sbin/ping\",\n\t\t\t\t\t\t\t\"/usr/sbin/ping\"\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t\t`,\n\t\t\tQuery{\n\t\t\t\t\"domain\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tIn: []interface{}{\n\t\t\t\t\t\t\t\"example.at\",\n\t\t\t\t\t\t\t\"example.com\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tLike: \"microsoft.%\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"path\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tEqual: \"/bin/ping\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tNotIn: []interface{}{\n\t\t\t\t\t\t\t\"/sbin/ping\",\n\t\t\t\t\t\t\t\"/usr/sbin/ping\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t}\n\n\tfor _, testCase := range cases { //nolint:paralleltest\n\t\tt.Run(testCase.Name, func(t *testing.T) {\n\t\t\tvar q Query\n\t\t\terr := json.Unmarshal([]byte(testCase.Input), &q)\n\n\t\t\tif testCase.Error != nil {\n\t\t\t\tif assert.Error(t, err) {\n\t\t\t\t\tassert.Equal(t, testCase.Error.Error(), err.Error())\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, testCase.Expected, q)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestQueryBuilder(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tnow := time.Now()\n\tcases := []struct {\n\t\tN string\n\t\tQ Query\n\t\tR string\n\t\tP map[string]interface{}\n\t\tE error\n\t}{\n\t\t{\n\t\t\t\"No filter\",\n\t\t\tnil,\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Simple, one-column filter\",\n\t\t\tQuery{\"domain\": []Matcher{\n\t\t\t\t{\n\t\t\t\t\tEqual: \"example.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tEqual: \"example.at\",\n\t\t\t\t},\n\t\t\t}},\n\t\t\t\"( domain = :domain0eq0 OR domain = :domain1eq0 )\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\":domain0eq0\": \"example.com\",\n\t\t\t\t\":domain1eq0\": \"example.at\",\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Two column filter\",\n\t\t\tQuery{\n\t\t\t\t\"domain\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tEqual: \"example.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"path\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tEqual: \"/bin/curl\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tEqual: \"/bin/ping\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"( domain = :domain0eq0 ) AND ( path = :path0eq0 OR path = :path1eq0 )\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\":domain0eq0\": \"example.com\",\n\t\t\t\t\":path0eq0\":   \"/bin/curl\",\n\t\t\t\t\":path1eq0\":   \"/bin/ping\",\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Time based filter\",\n\t\t\tQuery{\n\t\t\t\t\"started\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tEqual: now.Format(time.RFC3339),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"( started = :started0eq0 )\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\":started0eq0\": now.In(time.UTC).Format(orm.SqliteTimeFormat),\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\t\"Invalid column access\",\n\t\t\tQuery{\n\t\t\t\t\"forbiddenField\": []Matcher{{}},\n\t\t\t},\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\tfmt.Errorf(\"1 error occurred:\\n\\t* column forbiddenField is not allowed\\n\\n\"), //nolint:golint\n\t\t},\n\t\t{\n\t\t\t\"Complex example\",\n\t\t\tQuery{\n\t\t\t\t\"domain\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tIn: []interface{}{\"example.at\", \"example.com\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tLike: \"microsoft.%\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"path\": []Matcher{\n\t\t\t\t\t{\n\t\t\t\t\t\tNotIn: []interface{}{\n\t\t\t\t\t\t\t\"/bin/ping\",\n\t\t\t\t\t\t\t\"/sbin/ping\",\n\t\t\t\t\t\t\t\"/usr/bin/ping\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"( domain IN ( :domain0in0, :domain0in1 ) OR domain LIKE :domain1like0 ) AND ( path NOT IN ( :path0notin0, :path0notin1, :path0notin2 ) )\",\n\t\t\tmap[string]interface{}{\n\t\t\t\t\":domain0in0\":   \"example.at\",\n\t\t\t\t\":domain0in1\":   \"example.com\",\n\t\t\t\t\":domain1like0\": \"microsoft.%\",\n\t\t\t\t\":path0notin0\":  \"/bin/ping\",\n\t\t\t\t\":path0notin1\":  \"/sbin/ping\",\n\t\t\t\t\":path0notin2\":  \"/usr/bin/ping\",\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t}\n\n\ttbl, err := orm.GenerateTableSchema(\"connections\", Conn{})\n\trequire.NoError(t, err)\n\n\tfor cID, testCase := range cases { //nolint:paralleltest\n\t\tt.Run(testCase.N, func(t *testing.T) {\n\t\t\tstr, params, err := testCase.Q.toSQLWhereClause(context.TODO(), \"\", tbl, orm.DefaultEncodeConfig)\n\n\t\t\tif testCase.E != nil {\n\t\t\t\tif assert.Error(t, err) {\n\t\t\t\t\tassert.Equal(t, testCase.E.Error(), err.Error(), \"test case %d\", cID)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err, \"test case %d\", cID)\n\t\t\t\tassert.Equal(t, testCase.P, params, \"test case %d\", cID)\n\t\t\t\tassert.Equal(t, testCase.R, str, \"test case %d\", cID)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "service/netquery/runtime_query_runner.go",
    "content": "package netquery\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/service/netquery/orm\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// RuntimeQueryRunner provides a simple interface for the runtime database\n// that allows direct SQL queries to be performed against db.\n// Each resulting row of that query are marshaled as map[string]interface{}\n// and returned as a single record to the caller.\n//\n// Using portbase/database#Query is not possible because portbase/database will\n// complain about the SQL query being invalid. To work around that issue,\n// RuntimeQueryRunner uses a 'GET key' request where the SQL query is embedded into\n// the record key.\ntype RuntimeQueryRunner struct {\n\tdb        *Database\n\treg       *runtime.Registry\n\tkeyPrefix string\n}\n\n// NewRuntimeQueryRunner returns a new runtime SQL query runner that parses\n// and serves SQL queries form GET <prefix>/<plain sql query> requests.\nfunc NewRuntimeQueryRunner(db *Database, prefix string, reg *runtime.Registry) (*RuntimeQueryRunner, error) {\n\trunner := &RuntimeQueryRunner{\n\t\tdb:        db,\n\t\treg:       reg,\n\t\tkeyPrefix: prefix,\n\t}\n\n\tif _, err := reg.Register(prefix, runtime.SimpleValueGetterFunc(runner.get)); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to register runtime value provider: %w\", err)\n\t}\n\n\treturn runner, nil\n}\n\nfunc (runner *RuntimeQueryRunner) get(keyOrPrefix string) ([]record.Record, error) {\n\tquery := strings.TrimPrefix(\n\t\tkeyOrPrefix,\n\t\trunner.keyPrefix,\n\t)\n\n\tlog.Infof(\"netquery: executing custom SQL query: %q\", query)\n\n\tvar result []map[string]interface{}\n\tif err := runner.db.Execute(context.Background(), query, orm.WithResult(&result)); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to perform query %q: %w\", query, err)\n\t}\n\n\t// we need to wrap the result slice into a map as portbase/database attempts\n\t// to inject a _meta field.\n\tblob, err := json.Marshal(map[string]interface{}{\n\t\t\"result\": result,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal result: %w\", err)\n\t}\n\n\t// construct a new record wrapper that uses the already prepared JSON blob.\n\tkey := fmt.Sprintf(\"%s:%s\", runner.reg.DatabaseName(), keyOrPrefix)\n\twrapper, err := record.NewWrapper(key, new(record.Meta), dsd.JSON, blob)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create record wrapper: %w\", err)\n\t}\n\n\treturn []record.Record{wrapper}, nil\n}\n"
  },
  {
    "path": "service/network/api.go",
    "content": "package network\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/network/state\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/resolver\"\n\t\"github.com/safing/portmaster/service/status\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"debug/network\",\n\t\tRead:        api.PermitUser,\n\t\tDataFunc:    debugInfo,\n\t\tName:        \"Get Network Debug Information\",\n\t\tDescription: \"Returns network debugging information, similar to debug/core, but with connection data.\",\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"style\",\n\t\t\t\tValue:       \"github\",\n\t\t\t\tDescription: \"Specify the formatting style. The default is simple markdown formatting.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"profile\",\n\t\t\t\tValue:       \"<Source>/<ID>\",\n\t\t\t\tDescription: \"Specify a profile source and ID for which network connection should be reported.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"where\",\n\t\t\t\tValue:       \"<query>\",\n\t\t\t\tDescription: \"Specify a query to limit the connections included in the report. The default is to include all connections.\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath: \"debug/network/state\",\n\t\tRead: api.PermitUser,\n\t\tStructFunc: func(ar *api.Request) (i interface{}, err error) {\n\t\t\treturn state.GetInfo(), nil\n\t\t},\n\t\tName:        \"Get Network State Table Data\",\n\t\tDescription: \"Returns the current network state tables from the OS.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// debugInfo returns the debugging information for support requests.\nfunc debugInfo(ar *api.Request) (data []byte, err error) {\n\t// Create debug information helper.\n\tdi := new(debug.Info)\n\tdi.Style = ar.Request.URL.Query().Get(\"style\")\n\n\t// Add debug information.\n\n\t// Very basic information at the start.\n\tdi.AddVersionInfo()\n\tdi.AddPlatformInfo(ar.Context())\n\n\t// Unexpected logs.\n\tdi.AddLastUnexpectedLogs()\n\n\t// Network Connections.\n\tAddNetworkDebugData(\n\t\tdi,\n\t\tar.Request.URL.Query().Get(\"profile\"),\n\t\tar.Request.URL.Query().Get(\"where\"),\n\t)\n\n\t// Status Information from various modules.\n\tstatus.AddToDebugInfo(di)\n\t// captain.AddToDebugInfo(di) // TODO: Cannot use due to import loop.\n\tresolver.AddToDebugInfo(di)\n\tconfig.AddToDebugInfo(di)\n\n\t// Detailed information.\n\t// compat.AddToDebugInfo(di) // TODO: Cannot use due to interception import requirement which we don't want for SPN Hubs.\n\tdi.AddGoroutineStack()\n\n\t// Return data.\n\treturn di.Bytes(), nil\n}\n\n// AddNetworkDebugData adds the network debug data of the given profile to the debug data.\nfunc AddNetworkDebugData(di *debug.Info, profile, where string) {\n\t// Prepend where prefix to query if necessary.\n\tif where != \"\" && !strings.HasPrefix(where, \"where \") {\n\t\twhere = \"where \" + where\n\t}\n\n\t// Build query.\n\tq, err := query.ParseQuery(\"query network: \" + where)\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Network: Debug Failed\",\n\t\t\tdebug.NoFlags,\n\t\t\tfmt.Sprintf(\"Failed to build query: %s\", err),\n\t\t)\n\t\treturn\n\t}\n\n\t// Get iterator.\n\tit, err := dbController.Query(q, true, true)\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Network: Debug Failed\",\n\t\t\tdebug.NoFlags,\n\t\t\tfmt.Sprintf(\"Failed to run query: %s\", err),\n\t\t)\n\t\treturn\n\t}\n\n\t// Collect matching connections.\n\tvar ( //nolint:prealloc // We don't know the size.\n\t\tdebugConns []*Connection\n\t\taccepted   int\n\t\ttotal      int\n\t)\n\n\tfor maybeConn := range it.Next {\n\t\t// Switch to correct type.\n\t\tconn, ok := maybeConn.(*Connection)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check if the profile matches\n\t\tif profile != \"\" {\n\t\t\tfound := false\n\n\t\t\t// Get layer IDs and search for a match.\n\t\t\tlayerIDs := conn.Process().Profile().LayerIDs\n\t\t\tfor _, layerID := range layerIDs {\n\t\t\t\tif profile == layerID {\n\t\t\t\t\tfound = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Skip if the profile does not match.\n\t\t\tif !found {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Count.\n\t\ttotal++\n\t\tswitch conn.Verdict { //nolint:exhaustive\n\t\tcase VerdictAccept,\n\t\t\tVerdictRerouteToNameserver,\n\t\t\tVerdictRerouteToTunnel:\n\n\t\t\taccepted++\n\t\t}\n\n\t\t// Add to list.\n\t\tdebugConns = append(debugConns, conn)\n\t}\n\n\t// Add it all.\n\tdi.AddSection(\n\t\tfmt.Sprintf(\n\t\t\t\"Network: %d/%d Connections\",\n\t\t\taccepted,\n\t\t\ttotal,\n\t\t),\n\t\tdebug.UseCodeSection|debug.AddContentLineBreaks,\n\t\tbuildNetworkDebugInfoData(debugConns),\n\t)\n}\n\nfunc buildNetworkDebugInfoData(debugConns []*Connection) string {\n\t// Sort\n\tsort.Sort(connectionsByGroup(debugConns))\n\n\t// Format lines\n\tvar buf strings.Builder\n\tcurrentPID := process.UndefinedProcessID\n\tfor _, conn := range debugConns {\n\t\tconn.Lock()\n\n\t\t// Add process infomration if it differs from previous connection.\n\t\tif currentPID != conn.ProcessContext.PID {\n\t\t\tif currentPID != process.UndefinedProcessID {\n\t\t\t\tbuf.WriteString(\"\\n\\n\\n\")\n\t\t\t}\n\t\t\tbuf.WriteString(\"ProfileName: \" + conn.ProcessContext.ProfileName)\n\t\t\tbuf.WriteString(\"\\nProfile:     \" + conn.ProcessContext.Profile)\n\t\t\tbuf.WriteString(\"\\nSource:      \" + conn.ProcessContext.Source)\n\t\t\tbuf.WriteString(\"\\nProcessName: \" + conn.ProcessContext.ProcessName)\n\t\t\tbuf.WriteString(\"\\nBinaryPath:  \" + conn.ProcessContext.BinaryPath)\n\t\t\tbuf.WriteString(\"\\nCmdLine:     \" + conn.ProcessContext.CmdLine)\n\t\t\tbuf.WriteString(\"\\nPID:         \" + strconv.Itoa(conn.ProcessContext.PID))\n\t\t\tbuf.WriteString(\"\\n\")\n\n\t\t\t// Set current PID in order to not print the process information again.\n\t\t\tcurrentPID = conn.ProcessContext.PID\n\t\t}\n\n\t\t// Add connection.\n\t\tbuf.WriteString(\"\\n\")\n\t\tbuf.WriteString(conn.debugInfoLine())\n\n\t\tconn.Unlock()\n\t}\n\n\treturn buf.String()\n}\n\nfunc (conn *Connection) debugInfoLine() string {\n\tvar connectionData string\n\tif conn.Type == IPConnection {\n\t\t// Format IP/Port pair for connections.\n\t\tconnectionData = fmt.Sprintf(\n\t\t\t\"% 15s:%- 5s %s % 15s:%- 5s\",\n\t\t\tconn.LocalIP,\n\t\t\tstrconv.Itoa(int(conn.LocalPort)),\n\t\t\tconn.fmtProtocolAndDirectionComponent(conn.IPProtocol.String()),\n\t\t\tconn.Entity.IP,\n\t\t\tstrconv.Itoa(int(conn.Entity.Port)),\n\t\t)\n\t} else {\n\t\t// Leave empty for DNS Requests.\n\t\tconnectionData = \"                                                \"\n\t}\n\n\treturn fmt.Sprintf(\n\t\t\"% 14s %s%- 25s %s-%s P#%d [%s] %s - by %s @ %s\",\n\t\tconn.VerdictVerb(),\n\t\tconnectionData,\n\t\tconn.fmtDomainComponent(),\n\t\ttime.Unix(conn.Started, 0).Format(\"15:04:05\"),\n\t\tconn.fmtEndTimeComponent(),\n\t\tconn.ProcessContext.PID,\n\t\tconn.fmtFlagsComponent(),\n\t\tconn.Reason.Msg,\n\t\tconn.Reason.OptionKey,\n\t\tconn.fmtReasonProfileComponent(),\n\t)\n}\n\nfunc (conn *Connection) fmtDomainComponent() string {\n\tif conn.Entity.Domain != \"\" {\n\t\treturn \" to \" + conn.Entity.Domain\n\t}\n\treturn \"\"\n}\n\nfunc (conn *Connection) fmtProtocolAndDirectionComponent(protocol string) string {\n\tif conn.Inbound {\n\t\treturn \"<\" + protocol\n\t}\n\treturn protocol + \">\"\n}\n\nfunc (conn *Connection) fmtFlagsComponent() string {\n\tvar f string\n\n\tif conn.Internal {\n\t\tf += \"I\"\n\t}\n\tif conn.Encrypted {\n\t\tf += \"E\"\n\t}\n\tif conn.Tunneled {\n\t\tf += \"T\"\n\t}\n\tif len(conn.activeInspectors) > 0 {\n\t\tf += \"A\"\n\t}\n\tif conn.addedToMetrics {\n\t\tf += \"M\"\n\t}\n\n\treturn f\n}\n\nfunc (conn *Connection) fmtEndTimeComponent() string {\n\tif conn.Ended == 0 {\n\t\treturn \"        \" // Use same width as a timestamp.\n\t}\n\treturn time.Unix(conn.Ended, 0).Format(\"15:04:05\")\n}\n\nfunc (conn *Connection) fmtReasonProfileComponent() string {\n\tif conn.Reason.Profile == \"\" {\n\t\treturn \"global\"\n\t}\n\treturn conn.Reason.Profile\n}\n\ntype connectionsByGroup []*Connection\n\nfunc (a connectionsByGroup) Len() int      { return len(a) }\nfunc (a connectionsByGroup) Swap(i, j int) { a[i], a[j] = a[j], a[i] }\nfunc (a connectionsByGroup) Less(i, j int) bool {\n\t// Sort by:\n\n\t// 1. Profile ID\n\tif a[i].ProcessContext.Profile != a[j].ProcessContext.Profile {\n\t\treturn a[i].ProcessContext.Profile < a[j].ProcessContext.Profile\n\t}\n\n\t// 2. Process Binary\n\tif a[i].ProcessContext.BinaryPath != a[j].ProcessContext.BinaryPath {\n\t\treturn a[i].ProcessContext.BinaryPath < a[j].ProcessContext.BinaryPath\n\t}\n\n\t// 3. Process ID\n\tif a[i].ProcessContext.PID != a[j].ProcessContext.PID {\n\t\treturn a[i].ProcessContext.PID < a[j].ProcessContext.PID\n\t}\n\n\t// 4. Started\n\treturn a[i].Started < a[j].Started\n}\n"
  },
  {
    "path": "service/network/api_test.go",
    "content": "package network\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\nfunc TestDebugInfoLineFormatting(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, conn := range connectionTestData {\n\t\tfmt.Println(conn.debugInfoLine())\n\t}\n}\n\nfunc TestDebugInfoFormatting(t *testing.T) {\n\tt.Parallel()\n\n\tfmt.Println(buildNetworkDebugInfoData(connectionTestData))\n}\n\nvar connectionTestData = []*Connection{\n\t{\n\t\tID:         \"17-255.255.255.255-29810-192.168.0.23-40672\",\n\t\tScope:      \"IL\",\n\t\tIPVersion:  4,\n\t\tInbound:    true,\n\t\tIPProtocol: 17,\n\t\tLocalIP:    net.ParseIP(\"255.255.255.255\"),\n\t\tLocalPort:  29810,\n\t\tEntity: &intel.Entity{\n\t\t\tProtocol:      17,\n\t\t\tPort:          40672,\n\t\t\tDomain:        \"\",\n\t\t\tReverseDomain: \"\",\n\t\t\tIP:            net.ParseIP(\"192.168.0.23\"),\n\t\t\tCountry:       \"\",\n\t\t\tASN:           0,\n\t\t},\n\t\tVerdict: 2,\n\t\tReason: Reason{\n\t\t\tMsg:       \"incoming connection blocked by default\",\n\t\t\tOptionKey: \"filter/serviceEndpoints\",\n\t\t\tProfile:   \"\",\n\t\t},\n\t\tStarted:          1614010349,\n\t\tEnded:            1614010350,\n\t\tVerdictPermanent: true,\n\t\tInspecting:       false,\n\t\tTunneled:         false,\n\t\tEncrypted:        false,\n\t\tProcessContext: ProcessContext{\n\t\t\tProcessName: \"Unidentified Processes\",\n\t\t\tProfileName: \"Unidentified Processes\",\n\t\t\tBinaryPath:  \"\",\n\t\t\tPID:         -1,\n\t\t\tProfile:     \"_unidentified\",\n\t\t\tSource:      \"local\",\n\t\t},\n\t\tInternal:               false,\n\t\tProfileRevisionCounter: 1,\n\t},\n\t{\n\t\tID:         \"6-192.168.0.176-55216-13.32.6.15-80\",\n\t\tScope:      \"PI\",\n\t\tIPVersion:  4,\n\t\tInbound:    false,\n\t\tIPProtocol: 6,\n\t\tLocalIP:    net.ParseIP(\"192.168.0.176\"),\n\t\tLocalPort:  55216,\n\t\tEntity: &intel.Entity{\n\t\t\tProtocol:      6,\n\t\t\tPort:          80,\n\t\t\tDomain:        \"\",\n\t\t\tReverseDomain: \"\",\n\t\t\tIP:            net.ParseIP(\"13.32.6.15\"),\n\t\t\tCountry:       \"DE\",\n\t\t\tASN:           16509,\n\t\t},\n\t\tVerdict: 2,\n\t\tReason: Reason{\n\t\t\tMsg:       \"default permit\",\n\t\t\tOptionKey: \"filter/defaultAction\",\n\t\t\tProfile:   \"\",\n\t\t},\n\t\tStarted:          1614010475,\n\t\tEnded:            1614010565,\n\t\tVerdictPermanent: true,\n\t\tInspecting:       false,\n\t\tTunneled:         false,\n\t\tEncrypted:        false,\n\t\tProcessContext: ProcessContext{\n\t\t\tProcessName: \"NetworkManager\",\n\t\t\tProfileName: \"Network Manager\",\n\t\t\tBinaryPath:  \"/usr/sbin/NetworkManager\",\n\t\t\tPID:         1273,\n\t\t\tProfile:     \"3a9b0eb5-c7fe-4bc7-9b93-a90f4ff84b5b\",\n\t\t\tSource:      \"local\",\n\t\t},\n\t\tInternal:               true,\n\t\tProfileRevisionCounter: 1,\n\t},\n\t{\n\t\tID:         \"6-192.168.0.176-49982-142.250.74.211-443\",\n\t\tScope:      \"pkg.go.dev.\",\n\t\tIPVersion:  4,\n\t\tInbound:    false,\n\t\tIPProtocol: 6,\n\t\tLocalIP:    net.ParseIP(\"192.168.0.176\"),\n\t\tLocalPort:  49982,\n\t\tEntity: &intel.Entity{\n\t\t\tProtocol:      6,\n\t\t\tPort:          443,\n\t\t\tDomain:        \"pkg.go.dev.\",\n\t\t\tReverseDomain: \"\",\n\t\t\tCNAME: []string{\n\t\t\t\t\"ghs.googlehosted.com.\",\n\t\t\t},\n\t\t\tIP:      net.ParseIP(\"142.250.74.211\"),\n\t\t\tCountry: \"US\",\n\t\t\tASN:     15169,\n\t\t},\n\t\tVerdict: 2,\n\t\tReason: Reason{\n\t\t\tMsg:       \"default permit\",\n\t\t\tOptionKey: \"filter/defaultAction\",\n\t\t\tProfile:   \"\",\n\t\t},\n\t\tStarted:          1614010415,\n\t\tEnded:            1614010745,\n\t\tVerdictPermanent: true,\n\t\tInspecting:       false,\n\t\tTunneled:         false,\n\t\tEncrypted:        false,\n\t\tProcessContext: ProcessContext{\n\t\t\tProcessName: \"firefox\",\n\t\t\tProfileName: \"Firefox\",\n\t\t\tBinaryPath:  \"/usr/bin/firefox\",\n\t\t\tPID:         5710,\n\t\t\tProfile:     \"74b30392-9e4d-4157-83a9-fffafd3e2bde\",\n\t\t\tSource:      \"local\",\n\t\t},\n\t\tInternal:               false,\n\t\tProfileRevisionCounter: 1,\n\t},\n}\n"
  },
  {
    "path": "service/network/clean.go",
    "content": "package network\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/state\"\n\t\"github.com/safing/portmaster/service/process\"\n)\n\nconst (\n\t// EndConnsAfterInactiveFor defines the amount of time after not seen\n\t// connections of unsupported protocols are marked as ended.\n\tEndConnsAfterInactiveFor = 5 * time.Minute\n\n\t// EndICMPConnsAfterInactiveFor defines the amount of time after not seen\n\t// ICMP \"connections\" are marked as ended.\n\tEndICMPConnsAfterInactiveFor = 1 * time.Minute\n\n\t// DeleteConnsAfterEndedThreshold defines the amount of time after which\n\t// ended connections should be removed from the internal connection state.\n\tDeleteConnsAfterEndedThreshold = 10 * time.Minute\n\n\t// DeleteIncompleteConnsAfterStartedThreshold defines the amount of time after\n\t// which incomplete connections should be removed from the internal\n\t// connection state.\n\tDeleteIncompleteConnsAfterStartedThreshold = 1 * time.Minute\n\n\tcleanerTickDuration = 5 * time.Second\n)\n\nfunc connectionCleaner(ctx *mgr.WorkerCtx) error {\n\tmodule.connectionCleanerTicker = mgr.NewSleepyTicker(cleanerTickDuration, 0)\n\tdefer module.connectionCleanerTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-module.connectionCleanerTicker.Wait():\n\t\t\t// clean connections and processes\n\t\t\tactivePIDs := cleanConnections()\n\t\t\tprocess.CleanProcessStorage(activePIDs)\n\n\t\t\t// clean udp connection states\n\t\t\tstate.CleanUDPStates(ctx.Ctx())\n\t\t}\n\t}\n}\n\nfunc cleanConnections() (activePIDs map[int]struct{}) {\n\tactivePIDs = make(map[int]struct{})\n\n\t_ = module.mgr.Do(\"clean connections\", func(ctx *mgr.WorkerCtx) error {\n\t\tnow := time.Now().UTC()\n\t\tnowUnix := now.Unix()\n\t\tignoreNewer := nowUnix - 2\n\t\tendNotSeenSince := now.Add(-EndConnsAfterInactiveFor).Unix()\n\t\tendICMPNotSeenSince := now.Add(-EndICMPConnsAfterInactiveFor).Unix()\n\t\tdeleteOlderThan := now.Add(-DeleteConnsAfterEndedThreshold).Unix()\n\t\tdeleteIncompleteOlderThan := now.Add(-DeleteIncompleteConnsAfterStartedThreshold).Unix()\n\n\t\t// network connections\n\t\tfor _, conn := range conns.clone() {\n\t\t\tconn.Lock()\n\n\t\t\t// delete inactive connections\n\t\t\tswitch {\n\t\t\tcase conn.Started >= ignoreNewer:\n\t\t\t\t// Skip very fresh connections to evade edge cases.\n\t\t\tcase !conn.DataIsComplete():\n\t\t\t\t// Step 0: delete old incomplete connections\n\t\t\t\tif conn.Started < deleteIncompleteOlderThan {\n\t\t\t\t\t// Stop the firewall handler, in case one is running.\n\t\t\t\t\tconn.StopFirewallHandler()\n\t\t\t\t\t// Remove connection from state.\n\t\t\t\t\tconn.delete()\n\t\t\t\t}\n\n\t\t\tcase conn.Ended == 0:\n\t\t\t\t// Step 1: check if still active\n\t\t\t\tvar connActive bool\n\t\t\t\tswitch conn.IPProtocol { //nolint:exhaustive\n\t\t\t\tcase packet.TCP, packet.UDP:\n\t\t\t\t\tconnActive = state.Exists(&packet.Info{\n\t\t\t\t\t\tInbound:  false, // src == local\n\t\t\t\t\t\tVersion:  conn.IPVersion,\n\t\t\t\t\t\tProtocol: conn.IPProtocol,\n\t\t\t\t\t\tSrc:      conn.LocalIP,\n\t\t\t\t\t\tSrcPort:  conn.LocalPort,\n\t\t\t\t\t\tDst:      conn.Entity.IP,\n\t\t\t\t\t\tDstPort:  conn.Entity.Port,\n\t\t\t\t\t\tPID:      process.UndefinedProcessID,\n\t\t\t\t\t\tSeenAt:   time.Unix(conn.Started, 0), // State tables will be updated if older than this.\n\t\t\t\t\t}, now)\n\t\t\t\t\t// Update last seen value for permanent verdict connections.\n\t\t\t\t\tif connActive && conn.VerdictPermanent {\n\t\t\t\t\t\tconn.lastSeen.Store(nowUnix)\n\t\t\t\t\t}\n\n\t\t\t\tcase packet.ICMP, packet.ICMPv6:\n\t\t\t\t\tconnActive = conn.lastSeen.Load() > endICMPNotSeenSince\n\n\t\t\t\tdefault:\n\t\t\t\t\tconnActive = conn.lastSeen.Load() > endNotSeenSince\n\t\t\t\t}\n\n\t\t\t\t// Step 2: mark as ended\n\t\t\t\tif !connActive {\n\t\t\t\t\tconn.Ended = nowUnix\n\n\t\t\t\t\t// Stop the firewall handler, in case one is running.\n\t\t\t\t\tconn.StopFirewallHandler()\n\n\t\t\t\t\t// Save to database.\n\t\t\t\t\tconn.Save()\n\t\t\t\t}\n\n\t\t\t\t// If the connection has an associated process, add its PID to the active PID list.\n\t\t\t\tif conn.process != nil {\n\t\t\t\t\tactivePIDs[conn.process.Pid] = struct{}{}\n\t\t\t\t}\n\n\t\t\tcase conn.Ended < deleteOlderThan:\n\t\t\t\t// Step 3: delete\n\t\t\t\t// DEBUG:\n\t\t\t\t// log.Tracef(\"network.clean: deleted %s (ended at %s)\", conn.DatabaseKey(), time.Unix(conn.Ended, 0))\n\n\t\t\t\t// Remove connection from state.\n\t\t\t\tconn.delete()\n\t\t\t}\n\n\t\t\tconn.Unlock()\n\t\t}\n\n\t\t// dns requests\n\t\tfor _, conn := range dnsConns.clone() {\n\t\t\tconn.Lock()\n\n\t\t\t// delete old dns connections\n\t\t\tif conn.Ended < deleteOlderThan {\n\t\t\t\tlog.Tracef(\"network.clean: deleted %s (ended at %s)\", conn.DatabaseKey(), time.Unix(conn.Ended, 0))\n\t\t\t\tconn.delete()\n\t\t\t}\n\n\t\t\tconn.Unlock()\n\t\t}\n\n\t\t// rerouted dns requests\n\t\tcleanDNSRequestConnections()\n\n\t\treturn nil\n\t})\n\n\treturn activePIDs\n}\n"
  },
  {
    "path": "service/network/connection.go",
    "content": "package network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/reference\"\n\t\"github.com/safing/portmaster/service/process\"\n\t_ \"github.com/safing/portmaster/service/process/tags\"\n\t\"github.com/safing/portmaster/service/resolver\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/access/account\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n)\n\n// FirewallHandler defines the function signature for a firewall\n// handle function. A firewall handler is responsible for finding\n// a reasonable verdict for the connection conn. The connection is\n// locked before the firewall handler is called.\ntype FirewallHandler func(conn *Connection, pkt packet.Packet)\n\n// ProcessContext holds additional information about the process\n// that initiated a connection.\ntype ProcessContext struct {\n\t// ProcessName is the name of the process.\n\tProcessName string\n\t// ProfileName is the name of the profile.\n\tProfileName string\n\t// BinaryPath is the path to the process binary.\n\tBinaryPath string\n\t// CmdLine holds the execution parameters.\n\tCmdLine string\n\t// PID is the process identifier.\n\tPID int\n\t// CreatedAt the time when the process was created.\n\tCreatedAt int64\n\t// Profile is the ID of the main profile that\n\t// is applied to the process.\n\tProfile string\n\t// Source is the source of the profile.\n\tSource string\n}\n\n// ConnectionType is a type of connection.\ntype ConnectionType int8\n\n// Connection Types.\nconst (\n\tUndefined ConnectionType = iota\n\tIPConnection\n\tDNSRequest\n)\n\n// Connection describes a distinct physical network connection\n// identified by the IP/Port pair.\ntype Connection struct { //nolint:maligned // TODO: fix alignment\n\trecord.Base\n\tsync.Mutex\n\n\t// ID holds a unique request/connection id and is considered immutable after\n\t// creation.\n\tID string\n\t// Type defines the connection type.\n\tType ConnectionType\n\t// External defines if the connection represents an external request or\n\t// connection.\n\tExternal bool\n\t// Scope defines the scope of a connection. For DNS requests, the\n\t// scope is always set to the domain name. For direct packet\n\t// connections the scope consists of the involved network environment\n\t// and the packet direction. Once a connection object is created,\n\t// Scope is considered immutable.\n\t// Deprecated: This field holds duplicate information, which is accessible\n\t// clearer through other attributes. Please use conn.Type, conn.Inbound\n\t// and conn.Entity.Domain instead.\n\tScope string\n\t// IPVersion is set to the packet IP version. It is not set (0) for\n\t// connections created from a DNS request.\n\tIPVersion packet.IPVersion\n\t// Inbound is set to true if the connection is incoming. Inbound is\n\t// only set when a connection object is created and is considered\n\t// immutable afterwards.\n\tInbound bool\n\t// IPProtocol is set to the transport protocol used by the connection.\n\t// Is is considered immutable once a connection object has been\n\t// created. IPProtocol is not set for connections that have been\n\t// created from a DNS request.\n\tIPProtocol packet.IPProtocol\n\t// LocalIP holds the local IP address of the connection. It is not\n\t// set for connections created from DNS requests. LocalIP is\n\t// considered immutable once a connection object has been created.\n\tLocalIP net.IP\n\t// LocalIPScope holds the network scope of the local IP.\n\tLocalIPScope netutils.IPScope\n\t// LocalPort holds the local port of the connection. It is not\n\t// set for connections created from DNS requests. LocalPort is\n\t// considered immutable once a connection object has been created.\n\tLocalPort uint16\n\t// PID holds the PID of the owning process.\n\tPID int\n\t// Entity describes the remote entity that the connection has been\n\t// established to. The entity might be changed or information might\n\t// be added to it during the livetime of a connection. Access to\n\t// entity must be guarded by the connection lock.\n\tEntity *intel.Entity\n\t// Resolver holds information about the resolver used to resolve\n\t// Entity.Domain.\n\tResolver *resolver.ResolverInfo\n\t// Verdict holds the decisions that are made for a connection\n\t// The verdict may change so any access to it must be guarded by the\n\t// connection lock.\n\tVerdict Verdict\n\t// Whether or not the connection has been established at least once.\n\tConnectionEstablished bool\n\t// Reason holds information justifying the verdict, as well as additional\n\t// information about the reason.\n\t// Access to Reason must be guarded by the connection lock.\n\tReason Reason\n\t// Started holds the number of seconds in UNIX epoch time at which\n\t// the connection has been initiated and first seen by the portmaster.\n\t// Started is only ever set when creating a new connection object\n\t// and is considered immutable afterwards.\n\tStarted int64\n\t// Ended is set to the number of seconds in UNIX epoch time at which\n\t// the connection is considered terminated. Ended may be set at any\n\t// time so access must be guarded by the connection lock.\n\tEnded int64\n\t// VerdictPermanent is set to true if the final verdict is permanent\n\t// and the connection has been (or will be) handed back to the kernel.\n\t// VerdictPermanent may be changed together with the Verdict and Reason\n\t// properties and must be guarded using the connection lock.\n\tVerdictPermanent bool\n\t// Inspecting is set to true if the connection is being inspected\n\t// by one or more of the registered inspectors. This property may\n\t// be changed during the lifetime of a connection and must be guarded\n\t// using the connection lock.\n\tInspecting bool\n\t// Tunneled is set to true when the connection has been routed through the\n\t// SPN.\n\tTunneled bool\n\t// Encrypted is currently unused and MUST be ignored.\n\tEncrypted bool\n\t// TunnelOpts holds options for tunneling the connection.\n\tTunnelOpts *navigator.Options\n\t// ProcessContext holds additional information about the process\n\t// that initiated the connection. It is set once when the connection\n\t// object is created and is considered immutable afterwards.\n\tProcessContext ProcessContext\n\t// DNSContext holds additional information about the DNS request that was\n\t// probably used to resolve the IP of this connection.\n\tDNSContext *resolver.DNSRequestContext\n\t// TunnelContext holds additional information about the tunnel that this\n\t// connection is using.\n\tTunnelContext interface {\n\t\tGetExitNodeID() string\n\t\tStopTunnel() error\n\t}\n\n\t// HistoryEnabled is set to true when the connection should be persisted\n\t// in the history database.\n\tHistoryEnabled bool\n\t// BanwidthEnabled is set to true if connection bandwidth data should be persisted\n\t// in netquery.\n\tBandwidthEnabled bool\n\n\t// BytesReceived holds the observed received bytes of the connection.\n\tBytesReceived uint64\n\t// BytesSent holds the observed sent bytes of the connection.\n\tBytesSent uint64\n\n\t// lastSeen holds the timestamp when the connection was last seen.\n\t// If permanent verdicts are enabled and bandwidth reporting is not active,\n\t// this value will likely not be correct.\n\tlastSeen atomic.Int64\n\n\t// prompt holds the active prompt for this connection, if there is one.\n\tprompt *notifications.Notification\n\t// promptLock locks the prompt separately from the connection.\n\t// This allows goroutines to dismiss the notification, while another goroutine\n\t// is waiting for the prompt and holding a lock on the connection.\n\tpromptLock sync.Mutex\n\n\t// pkgQueue is used to serialize packet handling for a single\n\t// connection and is served by the connections packetHandler.\n\tpktQueue chan packet.Packet\n\t// pktQueueActive signifies whether the packet queue is active and may be written to.\n\tpktQueueActive bool\n\t// pktQueueLock locks access to pktQueueActive and writing to pktQueue.\n\tpktQueueLock sync.Mutex\n\n\t// dataComplete signifies that all information about the connection is\n\t// available and an actual packet has been seen.\n\t// As long as this flag is not set, the connection may not be evaluated for\n\t// a verdict and may not be sent to the UI.\n\tdataComplete *abool.AtomicBool\n\t// Internal is set to true if the connection is attributed as an\n\t// Portmaster internal connection. Internal may be set at different\n\t// points and access to it must be guarded by the connection lock.\n\tInternal bool\n\t// process holds a reference to the actor process. That is, the\n\t// process instance that initiated the connection.\n\tprocess *process.Process\n\t// firewallHandler is the firewall handler that is called for\n\t// each packet sent to pktQueue.\n\tfirewallHandler FirewallHandler\n\t// saveWhenFinished can be set to true during the life-time of\n\t// a connection and signals the firewallHandler that a Save()\n\t// should be issued after processing the connection.\n\tsaveWhenFinished bool\n\t// activeInspectors is a slice of booleans where each entry\n\t// maps to the index of an available inspector. If the value\n\t// is true the inspector is currently active. False indicates\n\t// that the inspector has finished and should be skipped.\n\tactiveInspectors []bool\n\t// inspectorData holds additional meta data for the inspectors.\n\t// using the inspectors index as a map key.\n\tinspectorData map[uint8]interface{}\n\t// ProfileRevisionCounter is used to track changes to the process\n\t// profile and required for correct re-evaluation of a connections\n\t// verdict.\n\tProfileRevisionCounter uint64\n\t// addedToMetrics signifies if the connection has already been counted in\n\t// the metrics.\n\taddedToMetrics bool\n}\n\n// Reason holds information justifying a verdict, as well as additional\n// information about the reason.\ntype Reason struct {\n\t// Msg is a human readable description of the reason.\n\tMsg string\n\t// OptionKey is the configuration option key of the setting that\n\t// was responsible for the verdict.\n\tOptionKey string\n\t// Profile is the database key of the profile that held the setting\n\t// that was responsible for the verdict.\n\tProfile string\n\t// ReasonContext may hold additional reason-specific information and\n\t// any access must be guarded by the connection lock.\n\tContext interface{}\n}\n\nfunc getProcessContext(ctx context.Context, proc *process.Process) ProcessContext {\n\t// Gather process information.\n\tpCtx := ProcessContext{\n\t\tProcessName: proc.Name,\n\t\tBinaryPath:  proc.Path,\n\t\tCmdLine:     proc.CmdLine,\n\t\tPID:         proc.Pid,\n\t\tCreatedAt:   proc.CreatedAt,\n\t}\n\n\t// Get local profile.\n\tlocalProfile := proc.Profile().LocalProfile()\n\tif localProfile == nil {\n\t\tlog.Tracer(ctx).Warningf(\"network: process %s has no profile\", proc)\n\t\treturn pCtx\n\t}\n\n\t// Add profile information and return.\n\tpCtx.ProfileName = localProfile.Name\n\tpCtx.Profile = localProfile.ID\n\tpCtx.Source = string(localProfile.Source)\n\treturn pCtx\n}\n\n// NewConnectionFromDNSRequest returns a new connection based on the given dns request.\nfunc NewConnectionFromDNSRequest(ctx context.Context, fqdn string, cnames []string, connID string, localIP net.IP, localPort uint16) *Connection {\n\t// Determine IP version.\n\tipVersion := packet.IPv6\n\tif localIP.To4() != nil {\n\t\tipVersion = packet.IPv4\n\t}\n\n\t// Create packet info for dns request connection.\n\tpi := &packet.Info{\n\t\tInbound:  false, // outbound as we are looking for the process of the source address\n\t\tVersion:  ipVersion,\n\t\tProtocol: packet.UDP,\n\t\tSrc:      localIP,   // source as in the process we are looking for\n\t\tSrcPort:  localPort, // source as in the process we are looking for\n\t\tDst:      nil,       // do not record direction\n\t\tDstPort:  0,         // do not record direction\n\t\tPID:      process.UndefinedProcessID,\n\t}\n\n\t// Check if the dns request connection was reported with process info.\n\tvar proc *process.Process\n\tdnsRequestConn, ok := GetDNSRequestConnection(pi)\n\tswitch {\n\tcase !ok:\n\t\t// No dns request connection found.\n\tcase dnsRequestConn.PID < 0:\n\t\t// Process is not identified or is special.\n\tcase dnsRequestConn.Ended > 0 && dnsRequestConn.Ended < time.Now().Unix()-3:\n\t\t// Connection has already ended (too long ago).\n\t\tlog.Tracer(ctx).Debugf(\"network: found ended dns request connection %s for dns request for %s\", dnsRequestConn, fqdn)\n\tdefault:\n\t\tlog.Tracer(ctx).Debugf(\"network: found matching dns request connection %s\", dnsRequestConn.String())\n\t\t// Inherit PID.\n\t\tpi.PID = dnsRequestConn.PID\n\t\t// Inherit process struct itself, as the PID may already be re-used.\n\t\tproc = dnsRequestConn.process\n\t}\n\n\t// Find process by remote IP/Port.\n\tif pi.PID == process.UndefinedProcessID {\n\t\tpi.PID, _, _ = process.GetPidOfConnection(\n\t\t\tctx,\n\t\t\tpi,\n\t\t)\n\t}\n\n\t// Get process and profile with PID.\n\tif proc == nil {\n\t\tproc, _ = process.GetProcessWithProfile(ctx, pi.PID)\n\t}\n\n\ttimestamp := time.Now().Unix()\n\tdnsConn := &Connection{\n\t\tID:    connID,\n\t\tType:  DNSRequest,\n\t\tScope: fqdn,\n\t\tPID:   proc.Pid,\n\t\tEntity: &intel.Entity{\n\t\t\tDomain:  fqdn,\n\t\t\tCNAME:   cnames,\n\t\t\tIPScope: netutils.Global, // Assign a global IP scope as default.\n\t\t},\n\t\tprocess:        proc,\n\t\tProcessContext: getProcessContext(ctx, proc),\n\t\tStarted:        timestamp,\n\t\tEnded:          timestamp,\n\t\tdataComplete:   abool.NewBool(true),\n\t}\n\tdnsConn.lastSeen.Store(timestamp)\n\n\t// Inherit internal status of profile.\n\tif localProfile := proc.Profile().LocalProfile(); localProfile != nil {\n\t\tdnsConn.Internal = localProfile.Internal\n\n\t\tif err := dnsConn.UpdateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {\n\t\t\tlog.Tracer(ctx).Warningf(\"network: failed to check for enabled features: %s\", err)\n\t\t}\n\t}\n\n\t// DNS Requests are saved by the nameserver depending on the result of the\n\t// query. Blocked requests are saved immediately, accepted ones are only\n\t// saved if they are not \"used\" by a connection.\n\n\tdnsConn.UpdateMeta()\n\treturn dnsConn\n}\n\n// NewConnectionFromExternalDNSRequest returns a connection for an external DNS request.\nfunc NewConnectionFromExternalDNSRequest(ctx context.Context, fqdn string, cnames []string, connID string, remoteIP net.IP) (*Connection, error) {\n\tremoteHost, err := process.GetNetworkHost(ctx, remoteIP)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttimestamp := time.Now().Unix()\n\tdnsConn := &Connection{\n\t\tID:       connID,\n\t\tType:     DNSRequest,\n\t\tExternal: true,\n\t\tScope:    fqdn,\n\t\tPID:      process.NetworkHostProcessID,\n\t\tEntity: &intel.Entity{\n\t\t\tDomain:  fqdn,\n\t\t\tCNAME:   cnames,\n\t\t\tIPScope: netutils.Global, // Assign a global IP scope as default.\n\t\t},\n\t\tprocess:        remoteHost,\n\t\tProcessContext: getProcessContext(ctx, remoteHost),\n\t\tStarted:        timestamp,\n\t\tEnded:          timestamp,\n\t\tdataComplete:   abool.NewBool(true),\n\t}\n\tdnsConn.lastSeen.Store(timestamp)\n\n\t// Inherit internal status of profile.\n\tif localProfile := remoteHost.Profile().LocalProfile(); localProfile != nil {\n\t\tdnsConn.Internal = localProfile.Internal\n\n\t\tif err := dnsConn.UpdateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {\n\t\t\tlog.Tracer(ctx).Warningf(\"network: failed to check for enabled features: %s\", err)\n\t\t}\n\t}\n\n\t// DNS Requests are saved by the nameserver depending on the result of the\n\t// query. Blocked requests are saved immediately, accepted ones are only\n\t// saved if they are not \"used\" by a connection.\n\n\tdnsConn.UpdateMeta()\n\treturn dnsConn, nil\n}\n\nvar tooOldTimestamp = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC).Unix()\n\n// NewIncompleteConnection creates a new incomplete connection with only minimal information.\nfunc NewIncompleteConnection(pkt packet.Packet) *Connection {\n\tinfo := pkt.Info()\n\n\t// Create new connection object.\n\t// We do not yet know the direction of the connection for sure, so we can only set minimal information.\n\tconn := &Connection{\n\t\tID:           pkt.GetConnectionID(),\n\t\tType:         IPConnection,\n\t\tIPVersion:    info.Version,\n\t\tIPProtocol:   info.Protocol,\n\t\tStarted:      info.SeenAt.Unix(),\n\t\tPID:          info.PID,\n\t\tInbound:      info.Inbound,\n\t\tdataComplete: abool.NewBool(false),\n\t}\n\tconn.lastSeen.Store(conn.Started)\n\n\t// Bullshit check Started timestamp.\n\tif conn.Started < tooOldTimestamp {\n\t\t// Fix timestamp, use current time as fallback.\n\t\tconn.Started = time.Now().Unix()\n\t}\n\n\t// Save connection to internal state in order to mitigate creation of\n\t// duplicates. Do not propagate yet, as data is not yet complete.\n\tconn.UpdateMeta()\n\tconns.add(conn)\n\n\treturn conn\n}\n\n// GatherConnectionInfo gathers information on the process and remote entity.\nfunc (conn *Connection) GatherConnectionInfo(pkt packet.Packet) (err error) {\n\t// Create remote entity.\n\tif conn.Entity == nil {\n\t\t// Remote\n\t\tconn.Entity = (&intel.Entity{\n\t\t\tIP:       pkt.Info().RemoteIP(),\n\t\t\tProtocol: uint8(pkt.Info().Protocol),\n\t\t\tPort:     pkt.Info().RemotePort(),\n\t\t}).Init(pkt.Info().DstPort)\n\n\t\t// Local\n\t\tconn.SetLocalIP(pkt.Info().LocalIP())\n\t\tconn.LocalPort = pkt.Info().LocalPort()\n\n\t\tif conn.Inbound {\n\t\t\tswitch conn.Entity.IPScope {\n\t\t\tcase netutils.HostLocal:\n\t\t\t\tconn.Scope = IncomingHost\n\t\t\tcase netutils.LinkLocal, netutils.SiteLocal, netutils.LocalMulticast:\n\t\t\t\tconn.Scope = IncomingLAN\n\t\t\tcase netutils.Global, netutils.GlobalMulticast:\n\t\t\t\tconn.Scope = IncomingInternet\n\n\t\t\tcase netutils.Undefined, netutils.Invalid:\n\t\t\t\tfallthrough\n\t\t\tdefault:\n\t\t\t\tconn.Scope = IncomingInvalid\n\t\t\t}\n\t\t} else {\n\t\t\t// Outbound direct (possibly P2P) connection.\n\t\t\tswitch conn.Entity.IPScope {\n\t\t\tcase netutils.HostLocal:\n\t\t\t\tconn.Scope = PeerHost\n\t\t\tcase netutils.LinkLocal, netutils.SiteLocal, netutils.LocalMulticast:\n\t\t\t\tconn.Scope = PeerLAN\n\t\t\tcase netutils.Global, netutils.GlobalMulticast:\n\t\t\t\tconn.Scope = PeerInternet\n\n\t\t\tcase netutils.Undefined, netutils.Invalid:\n\t\t\t\tfallthrough\n\t\t\tdefault:\n\t\t\t\tconn.Scope = PeerInvalid\n\t\t\t}\n\t\t}\n\t}\n\n\t// Get PID if not yet available.\n\tif conn.PID == process.UndefinedProcessID {\n\t\t// Get process by looking at the system state tables.\n\t\t// Apply direction as reported from the state tables.\n\t\tconn.PID, conn.Inbound, _ = process.GetPidOfConnection(pkt.Ctx(), pkt.Info())\n\t\t// Errors are informational and are logged to the context.\n\t}\n\n\t// Only get process and profile with first real packet.\n\t// TODO: Remove when we got full VM/Docker support.\n\tif pkt.InfoOnly() {\n\t\treturn nil\n\t}\n\n\t// Get Process and Profile.\n\tif conn.process == nil {\n\t\tconn.process, err = process.GetProcessWithProfile(pkt.Ctx(), conn.PID)\n\t\t// Errors are informational and are logged to the context.\n\t\tif err != nil {\n\t\t\tif pkt.InfoOnly() {\n\t\t\t\tconn.process = nil // Try again with real packet.\n\t\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"network: failed to get process and profile of PID %d: %s\", conn.PID, err)\n\t\t\t} else {\n\t\t\t\tlog.Tracer(pkt.Ctx()).Warningf(\"network: failed to get process and profile of PID %d: %s\", conn.PID, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Apply process/profile info to connection.\n\tif conn.ProfileRevisionCounter == 0 && conn.process != nil {\n\t\t// Add process/profile metadata for connection.\n\t\tconn.ProcessContext = getProcessContext(pkt.Ctx(), conn.process)\n\t\tconn.ProfileRevisionCounter = conn.process.Profile().RevisionCnt()\n\n\t\t// Inherit internal status of profile.\n\t\tif localProfile := conn.process.Profile().LocalProfile(); localProfile != nil {\n\t\t\tconn.Internal = localProfile.Internal\n\n\t\t\tif err := conn.UpdateFeatures(); err != nil && !errors.Is(err, access.ErrNotLoggedIn) {\n\t\t\t\tlog.Tracer(pkt.Ctx()).Warningf(\"network: connection %s failed to check for enabled features: %s\", conn, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Find domain and DNS context of entity.\n\tif conn.Entity.Domain == \"\" && conn.process.Profile() != nil {\n\t\tprofileScope := conn.process.Profile().LocalProfile().ID\n\t\t// check if we can find a domain for that IP\n\t\tipinfo, err := resolver.GetIPInfo(profileScope, pkt.Info().RemoteIP().String())\n\t\tif err != nil {\n\t\t\t// Try again with the global scope, in case DNS went through the system resolver.\n\t\t\tipinfo, err = resolver.GetIPInfo(resolver.IPInfoProfileScopeGlobal, pkt.Info().RemoteIP().String())\n\t\t}\n\n\t\tif runtime.GOOS == \"windows\" && err != nil {\n\t\t\t// On windows domains may come with delay.\n\t\t\tif module.instance.Resolver().IsDisabled() && conn.shouldWaitForDomain() {\n\t\t\t\t// Flush the dns listener buffer and try again.\n\t\t\t\tfor i := range 4 {\n\t\t\t\t\terr = module.instance.DNSMonitor().Flush()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t// Error flushing, dont try again.\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\t// Try with profile scope\n\t\t\t\t\tipinfo, err = resolver.GetIPInfo(profileScope, pkt.Info().RemoteIP().String())\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"network: found domain with scope (%s) from dnsmonitor after %d tries\", profileScope, +1)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\t// Try again with the global scope\n\t\t\t\t\tipinfo, err = resolver.GetIPInfo(resolver.IPInfoProfileScopeGlobal, pkt.Info().RemoteIP().String())\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tlog.Tracer(pkt.Ctx()).Debugf(\"network: found domain from dnsmonitor after %d tries\", i+1)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(5 * time.Millisecond)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err == nil {\n\t\t\tlastResolvedDomain := ipinfo.MostRecentDomain()\n\t\t\tif lastResolvedDomain != nil {\n\t\t\t\tconn.Scope = lastResolvedDomain.Domain\n\t\t\t\tconn.Entity.Domain = lastResolvedDomain.Domain\n\t\t\t\tconn.Entity.CNAME = lastResolvedDomain.CNAMEs\n\t\t\t\tconn.DNSContext = lastResolvedDomain.DNSRequestContext\n\t\t\t\tconn.Resolver = lastResolvedDomain.Resolver\n\t\t\t\tremoveOpenDNSRequest(conn.process.Pid, lastResolvedDomain.Domain)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check if destination IP is the captive portal's IP.\n\tif conn.Entity.Domain == \"\" {\n\t\tportal := netenv.GetCaptivePortal()\n\t\tif pkt.Info().RemoteIP().Equal(portal.IP) {\n\t\t\tconn.Scope = portal.Domain\n\t\t\tconn.Entity.Domain = portal.Domain\n\t\t}\n\t}\n\n\t// Check if we have all required data for a complete packet.\n\tswitch {\n\tcase pkt.InfoOnly():\n\t\t// We need a full packet.\n\tcase conn.process == nil:\n\t\t// We need a process.\n\tcase conn.process.Profile() == nil:\n\t\t// We need a profile.\n\tcase conn.Entity == nil:\n\t\t// We need an entity.\n\tdefault:\n\t\t// Data is complete!\n\t\tconn.dataComplete.Set()\n\t}\n\n\tconn.SaveWhenFinished()\n\treturn nil\n}\n\n// GetConnection fetches a Connection from the database.\nfunc GetConnection(connID string) (*Connection, bool) {\n\treturn conns.get(connID)\n}\n\n// GetAllConnections Gets all connection.\nfunc GetAllConnections() []*Connection {\n\treturn conns.list()\n}\n\n// GetDNSConnection fetches a DNS Connection from the database.\nfunc GetDNSConnection(dnsConnID string) (*Connection, bool) {\n\treturn dnsConns.get(dnsConnID)\n}\n\n// SetLocalIP sets the local IP address together with its network scope. The\n// connection is not locked for this.\nfunc (conn *Connection) SetLocalIP(ip net.IP) {\n\tconn.LocalIP = ip\n\tconn.LocalIPScope = netutils.GetIPScope(ip)\n}\n\n// UpdateFeatures checks which connection related features may and should be\n// used and sets the flags accordingly.\n// The caller must hold a lock on the connection.\nfunc (conn *Connection) UpdateFeatures() error {\n\t// Get user.\n\tuser, err := access.GetUser()\n\tif err != nil && !errors.Is(err, access.ErrNotLoggedIn) {\n\t\treturn err\n\t}\n\t// Caution: user may be nil!\n\n\t// Check if history may be used and if it is enabled for this application.\n\tconn.HistoryEnabled = false\n\tswitch {\n\tcase conn.Internal:\n\t\t// Do not record internal connections, as they are of low interest in the history.\n\t\t// TODO: Should we create a setting for this?\n\tcase conn.Entity.IPScope.IsLocalhost():\n\t\t// Do not record localhost-only connections, as they are very low interest in the history.\n\t\t// TODO: Should we create a setting for this?\n\tcase user.MayUse(account.FeatureHistory):\n\t\t// Check if history may be used and is enabled.\n\t\tlProfile := conn.Process().Profile()\n\t\tif lProfile != nil {\n\t\t\tconn.HistoryEnabled = lProfile.EnableHistory()\n\t\t}\n\t}\n\n\t// Check if bandwidth visibility may be used.\n\tconn.BandwidthEnabled = user.MayUse(account.FeatureBWVis)\n\n\treturn nil\n}\n\n// AcceptWithContext accepts the connection.\nfunc (conn *Connection) AcceptWithContext(reason, reasonOptionKey string, ctx interface{}) {\n\tif !conn.SetVerdict(VerdictAccept, reason, reasonOptionKey, ctx) {\n\t\tlog.Warningf(\"filter: tried to accept %s, but current verdict is %s\", conn, conn.Verdict)\n\t}\n}\n\n// Accept is like AcceptWithContext but only accepts a reason.\nfunc (conn *Connection) Accept(reason, reasonOptionKey string) {\n\tconn.AcceptWithContext(reason, reasonOptionKey, nil)\n}\n\n// BlockWithContext blocks the connection.\nfunc (conn *Connection) BlockWithContext(reason, reasonOptionKey string, ctx interface{}) {\n\tif !conn.SetVerdict(VerdictBlock, reason, reasonOptionKey, ctx) {\n\t\tlog.Warningf(\"filter: tried to block %s, but current verdict is %s\", conn, conn.Verdict)\n\t}\n}\n\n// Block is like BlockWithContext but does only accepts a reason.\nfunc (conn *Connection) Block(reason, reasonOptionKey string) {\n\tconn.BlockWithContext(reason, reasonOptionKey, nil)\n}\n\n// DropWithContext drops the connection.\nfunc (conn *Connection) DropWithContext(reason, reasonOptionKey string, ctx interface{}) {\n\tif !conn.SetVerdict(VerdictDrop, reason, reasonOptionKey, ctx) {\n\t\tlog.Warningf(\"filter: tried to drop %s, but current verdict is %s\", conn, conn.Verdict)\n\t}\n}\n\n// Drop is like DropWithContext but does only accepts a reason.\nfunc (conn *Connection) Drop(reason, reasonOptionKey string) {\n\tconn.DropWithContext(reason, reasonOptionKey, nil)\n}\n\n// DenyWithContext blocks or drops the link depending on the connection direction.\nfunc (conn *Connection) DenyWithContext(reason, reasonOptionKey string, ctx interface{}) {\n\tif conn.Inbound {\n\t\tconn.DropWithContext(reason, reasonOptionKey, ctx)\n\t} else {\n\t\tconn.BlockWithContext(reason, reasonOptionKey, ctx)\n\t}\n}\n\n// Deny is like DenyWithContext but only accepts a reason.\nfunc (conn *Connection) Deny(reason, reasonOptionKey string) {\n\tconn.DenyWithContext(reason, reasonOptionKey, nil)\n}\n\n// FailedWithContext marks the connection with VerdictFailed and stores the reason.\nfunc (conn *Connection) FailedWithContext(reason, reasonOptionKey string, ctx interface{}) {\n\tif !conn.SetVerdict(VerdictFailed, reason, reasonOptionKey, ctx) {\n\t\tlog.Warningf(\"filter: tried to drop %s due to error but current verdict is %s\", conn, conn.Verdict)\n\t}\n}\n\n// Failed is like FailedWithContext but only accepts a string.\nfunc (conn *Connection) Failed(reason, reasonOptionKey string) {\n\tconn.FailedWithContext(reason, reasonOptionKey, nil)\n}\n\n// SetVerdict sets a new verdict for the connection.\nfunc (conn *Connection) SetVerdict(newVerdict Verdict, reason, reasonOptionKey string, reasonCtx interface{}) (ok bool) {\n\tconn.SetVerdictDirectly(newVerdict)\n\n\t// Set reason and context.\n\tconn.Reason.Msg = reason\n\tconn.Reason.Context = reasonCtx\n\n\t// Reset option key.\n\tconn.Reason.OptionKey = \"\"\n\tconn.Reason.Profile = \"\"\n\n\t// Set option key if data is available.\n\tif reasonOptionKey != \"\" {\n\t\tlp := conn.Process().Profile()\n\t\tif lp != nil {\n\t\t\tconn.Reason.OptionKey = reasonOptionKey\n\t\t\tconn.Reason.Profile = lp.GetProfileSource(conn.Reason.OptionKey)\n\t\t}\n\t}\n\n\treturn true // TODO: remove\n}\n\n// SetVerdictDirectly sets the verdict.\nfunc (conn *Connection) SetVerdictDirectly(newVerdict Verdict) {\n\tconn.Verdict = newVerdict\n}\n\n// VerdictVerb returns the verdict as a verb, while taking any special states\n// into account.\nfunc (conn *Connection) VerdictVerb() string {\n\treturn conn.Verdict.Verb()\n}\n\n// DataIsComplete returns whether all information about the connection is\n// available and an actual packet has been seen.\n// As long as this flag is not set, the connection may not be evaluated for\n// a verdict and may not be sent to the UI.\nfunc (conn *Connection) DataIsComplete() bool {\n\treturn conn.dataComplete.IsSet()\n}\n\n// Process returns the connection's process.\nfunc (conn *Connection) Process() *process.Process {\n\treturn conn.process\n}\n\n// SaveWhenFinished marks the connection for saving it after the firewall handler.\nfunc (conn *Connection) SaveWhenFinished() {\n\tconn.saveWhenFinished = true\n}\n\n// Save saves the connection in the storage and propagates the change\n// through the database system. Save may lock dnsConnsLock or connsLock\n// in if Save() is called the first time.\n// Callers must make sure to lock the connection itself before calling\n// Save().\nfunc (conn *Connection) Save() {\n\tconn.UpdateMeta()\n\n\t// nolint:exhaustive\n\tswitch conn.Verdict {\n\tcase VerdictAccept, VerdictRerouteToNameserver:\n\t\tconn.ConnectionEstablished = true\n\tcase VerdictRerouteToTunnel:\n\t\t// this is already handled when the connection tunnel has been\n\t\t// established.\n\tdefault:\n\t}\n\n\t// Do not save/update until data is complete.\n\tif !conn.DataIsComplete() {\n\t\treturn\n\t}\n\n\tif !conn.KeyIsSet() {\n\t\tif conn.Type == DNSRequest {\n\t\t\tconn.SetKey(makeKey(conn.process.Pid, dbScopeDNS, conn.ID))\n\t\t\tdnsConns.add(conn)\n\t\t} else {\n\t\t\tconn.SetKey(makeKey(conn.process.Pid, dbScopeIP, conn.ID))\n\t\t\tconns.add(conn)\n\t\t}\n\t}\n\n\tconn.addToMetrics()\n\n\t// notify database controller\n\tdbController.PushUpdate(conn)\n}\n\n// delete deletes a link from the storage and propagates the change.\n// delete may lock either the dnsConnsLock or connsLock. Callers\n// must still make sure to lock the connection itself.\nfunc (conn *Connection) delete() {\n\t// A connection without an ID has been created from\n\t// a DNS request rather than a packet. Choose the correct\n\t// connection store here.\n\tif conn.Type == IPConnection {\n\t\tconns.delete(conn)\n\t} else {\n\t\tdnsConns.delete(conn)\n\t}\n\n\tconn.Meta().Delete()\n\n\t// Notify database controller if data is complete and thus connection was previously exposed.\n\tif conn.DataIsComplete() {\n\t\tdbController.PushUpdate(conn)\n\t}\n}\n\n// GetActiveInspectors returns the list of active inspectors.\nfunc (conn *Connection) GetActiveInspectors() []bool {\n\treturn conn.activeInspectors\n}\n\n// SetActiveInspectors sets the list of active inspectors.\nfunc (conn *Connection) SetActiveInspectors(newInspectors []bool) {\n\tconn.activeInspectors = newInspectors\n}\n\n// GetInspectorData returns the list of inspector data.\nfunc (conn *Connection) GetInspectorData() map[uint8]interface{} {\n\treturn conn.inspectorData\n}\n\n// SetInspectorData set the list of inspector data.\nfunc (conn *Connection) SetInspectorData(newInspectorData map[uint8]interface{}) {\n\tconn.inspectorData = newInspectorData\n}\n\n// SetPrompt sets the given prompt on the connection.\n// If there already is a prompt set, the previous prompt notification is deleted.\nfunc (conn *Connection) SetPrompt(prompt *notifications.Notification) {\n\tconn.promptLock.Lock()\n\tdefer conn.promptLock.Unlock()\n\n\tif conn.prompt != nil {\n\t\tconn.prompt.Delete()\n\t}\n\tconn.prompt = prompt\n}\n\n// RemovePrompt removes the prompt on the connection.\nfunc (conn *Connection) RemovePrompt() {\n\tconn.promptLock.Lock()\n\tdefer conn.promptLock.Unlock()\n\n\tif conn.prompt != nil {\n\t\tconn.prompt.Delete()\n\t}\n}\n\n// String returns a string representation of conn.\nfunc (conn *Connection) String() string {\n\tswitch {\n\tcase conn.process == nil || conn.Entity == nil:\n\t\treturn conn.ID\n\tcase conn.Inbound:\n\t\treturn fmt.Sprintf(\"%s <- %s\", conn.process, conn.Entity.IP)\n\tcase conn.Entity.Domain != \"\":\n\t\treturn fmt.Sprintf(\"%s to %s (%s)\", conn.process, conn.Entity.Domain, conn.Entity.IP)\n\tdefault:\n\t\treturn fmt.Sprintf(\"%s -> %s\", conn.process, conn.Entity.IP)\n\t}\n}\n\nfunc (conn *Connection) shouldWaitForDomain() bool {\n\t// Should wait for Global Unicast, outgoing and not ICMP connections\n\tswitch {\n\tcase conn.Entity.IPScope != netutils.Global:\n\t\treturn false\n\tcase conn.Inbound:\n\t\treturn false\n\tcase reference.IsICMP(conn.Entity.Protocol):\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "service/network/connection_android.go",
    "content": "package network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/tevino/abool\"\n)\n\n// NewDefaultConnection creates a new connection with default values except local and remote IPs and protocols.\nfunc NewDefaultConnection(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, ipVersion packet.IPVersion, protocol packet.IPProtocol) *Connection {\n\tconnInfo := &Connection{\n\t\tID:           fmt.Sprintf(\"%s-%s-%d-%s-%d\", protocol.String(), localIP, localPort, remoteIP, remotePort),\n\t\tType:         IPConnection,\n\t\tExternal:     false,\n\t\tIPVersion:    ipVersion,\n\t\tInbound:      false,\n\t\tIPProtocol:   protocol,\n\t\tLocalIP:      localIP,\n\t\tLocalIPScope: netutils.Global,\n\t\tLocalPort:    localPort,\n\t\tPID:          process.UnidentifiedProcessID,\n\t\tEntity: (&intel.Entity{\n\t\t\tIP:       remoteIP,\n\t\t\tProtocol: uint8(protocol),\n\t\t\tPort:     remotePort,\n\t\t}).Init(0),\n\t\tResolver:         nil,\n\t\tStarted:          time.Now().Unix(),\n\t\tVerdictPermanent: false,\n\t\tTunneled:         true,\n\t\tEncrypted:        false,\n\t\tDataComplete:     abool.NewBool(true),\n\t\tInternal:         false,\n\t\taddedToMetrics:   true, // Metrics are not needed for now. This will mark the Connection to be ignored.\n\t\tprocess:          process.GetUnidentifiedProcess(context.Background()),\n\t}\n\n\t// TODO: Quick fix for the SPN.\n\t// Use inspection framework for proper encryption detection.\n\tswitch connInfo.Entity.DstPort() {\n\tcase\n\t\t22,  // SSH\n\t\t443, // HTTPS\n\t\t465, // SMTP-SSL\n\t\t853, // DoT\n\t\t993, // IMAP-SSL\n\t\t995: // POP3-SSL\n\t\tconnInfo.Encrypted = true\n\t}\n\n\tvar layeredProfile = connInfo.process.Profile()\n\tconnInfo.TunnelOpts = &navigator.Options{\n\t\tHubPolicies:                   layeredProfile.StackedExitHubPolicies(),\n\t\tCheckHubExitPolicyWith:        connInfo.Entity,\n\t\tRequireTrustedDestinationHubs: !connInfo.Encrypted,\n\t\tRoutingProfile:                layeredProfile.SPNRoutingAlgorithm(),\n\t}\n\n\treturn connInfo\n}\n"
  },
  {
    "path": "service/network/connection_handler.go",
    "content": "package network\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\n// SetFirewallHandler sets the firewall handler for this link, and starts a\n// worker to handle the packets.\n// The caller needs to hold a lock on the connection.\n// Cannot be called with \"nil\" handler. Call StopFirewallHandler() instead.\nfunc (conn *Connection) SetFirewallHandler(handler FirewallHandler) {\n\tif handler == nil {\n\t\treturn\n\t}\n\n\t// Initialize packet queue, if needed.\n\tconn.pktQueueLock.Lock()\n\tdefer conn.pktQueueLock.Unlock()\n\tif !conn.pktQueueActive {\n\t\tconn.pktQueue = make(chan packet.Packet, 100)\n\t\tconn.pktQueueActive = true\n\t}\n\n\t// Start packet handler worker when new handler is set.\n\tif conn.firewallHandler == nil {\n\t\tmodule.mgr.Go(\"packet handler\", conn.packetHandlerWorker)\n\t}\n\n\t// Set new handler.\n\tconn.firewallHandler = handler\n}\n\n// UpdateFirewallHandler sets the firewall handler if it already set and the\n// given handler is not nil.\n// The caller needs to hold a lock on the connection.\nfunc (conn *Connection) UpdateFirewallHandler(handler FirewallHandler) {\n\tif handler != nil && conn.firewallHandler != nil {\n\t\tconn.firewallHandler = handler\n\t}\n}\n\n// StopFirewallHandler unsets the firewall handler and stops the handler worker.\n// The caller needs to hold a lock on the connection.\nfunc (conn *Connection) StopFirewallHandler() {\n\tconn.pktQueueLock.Lock()\n\tdefer conn.pktQueueLock.Unlock()\n\n\t// Unset the firewall handler to revert to the default handler.\n\tconn.firewallHandler = nil\n\n\t// Signal the packet handler worker that it can stop.\n\tif conn.pktQueueActive {\n\t\tclose(conn.pktQueue)\n\t\tconn.pktQueueActive = false\n\t}\n\n\t// Unset the packet queue so that it can be freed.\n\tconn.pktQueue = nil\n}\n\n// HandlePacket queues packet of Link for handling.\nfunc (conn *Connection) HandlePacket(pkt packet.Packet) {\n\t// Update last seen timestamp.\n\tconn.lastSeen.Store(time.Now().Unix())\n\n\tconn.pktQueueLock.Lock()\n\tdefer conn.pktQueueLock.Unlock()\n\n\t// execute handler or verdict\n\tif conn.pktQueueActive {\n\t\tselect {\n\t\tcase conn.pktQueue <- pkt:\n\t\tdefault:\n\t\t\tlog.Debugf(\n\t\t\t\t\"filter: dropping packet %s, as there is no space in the connection's handling queue\",\n\t\t\t\tpkt,\n\t\t\t)\n\t\t\t_ = pkt.Drop()\n\t\t}\n\t} else {\n\t\t// Run default handler.\n\t\tdefaultFirewallHandler(conn, pkt)\n\n\t\t// Record metrics.\n\t\tpacketHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)\n\t}\n}\n\nvar infoOnlyPacketsActive = abool.New()\n\n// packetHandlerWorker sequentially handles queued packets.\nfunc (conn *Connection) packetHandlerWorker(ctx *mgr.WorkerCtx) error {\n\t// Copy packet queue, so we can remove the reference from the connection\n\t// when we stop the firewall handler.\n\tvar pktQueue chan packet.Packet\n\tfunc() {\n\t\tconn.pktQueueLock.Lock()\n\t\tdefer conn.pktQueueLock.Unlock()\n\t\tpktQueue = conn.pktQueue\n\t}()\n\n\t// pktSeq counts the seen packets.\n\tvar pktSeq int\n\n\tfor {\n\t\tselect {\n\t\tcase pkt := <-pktQueue:\n\t\t\tif pkt == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tpktSeq++\n\n\t\t\t// Attempt to optimize packet handling order by handling info-only packets first.\n\t\t\tswitch {\n\t\t\tcase pktSeq > 1:\n\t\t\t\t// Order correction is only for first packet.\n\n\t\t\tcase pkt.InfoOnly():\n\t\t\t\t// Correct order only if first packet is not info-only.\n\n\t\t\t\t// We have observed a first packet that is info-only.\n\t\t\t\t// Info-only packets seem to be active and working.\n\t\t\t\tinfoOnlyPacketsActive.Set()\n\n\t\t\tcase pkt.ExpectInfo():\n\t\t\t\t// Packet itself tells us that we should expect an info-only packet.\n\t\t\t\tfallthrough\n\n\t\t\tcase infoOnlyPacketsActive.IsSet() && pkt.IsOutbound():\n\t\t\t\t// Info-only packets are active and the packet is outbound.\n\t\t\t\t// The probability is high that we will also get an info-only packet for this connection.\n\t\t\t\t// TODO: Do not do this for forwarded packets in the future.\n\n\t\t\t\t// DEBUG:\n\t\t\t\t// log.Debugf(\"filter: waiting for info only packet in order to pull forward: %s\", pkt)\n\t\t\t\tselect {\n\t\t\t\tcase infoPkt := <-pktQueue:\n\t\t\t\t\tif infoPkt != nil {\n\t\t\t\t\t\t// DEBUG:\n\t\t\t\t\t\t// log.Debugf(\"filter: packet #%d [pulled forward] info=%v PID=%d packet: %s\", pktSeq, infoPkt.InfoOnly(), infoPkt.Info().PID, pkt)\n\t\t\t\t\t\tpacketHandlerHandleConn(ctx.Ctx(), conn, infoPkt)\n\t\t\t\t\t\tpktSeq++\n\t\t\t\t\t}\n\t\t\t\tcase <-time.After(1 * time.Millisecond):\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// DEBUG:\n\t\t\t// switch {\n\t\t\t// case pkt.Info().Inbound:\n\t\t\t// \tlog.Debugf(\"filter: packet #%d info=%v PID=%d packet: %s\", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)\n\t\t\t// case pktSeq == 1 && !pkt.InfoOnly():\n\t\t\t// \tlog.Warningf(\"filter: packet #%d [should be info only!] info=%v PID=%d packet: %s\", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)\n\t\t\t// case pktSeq >= 2 && pkt.InfoOnly():\n\t\t\t// \tlog.Errorf(\"filter: packet #%d [should not be info only!] info=%v PID=%d packet: %s\", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)\n\t\t\t// default:\n\t\t\t// \tlog.Debugf(\"filter: packet #%d info=%v PID=%d packet: %s\", pktSeq, pkt.InfoOnly(), pkt.Info().PID, pkt)\n\t\t\t// }\n\n\t\t\tpacketHandlerHandleConn(ctx.Ctx(), conn, pkt)\n\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc packetHandlerHandleConn(ctx context.Context, conn *Connection, pkt packet.Packet) {\n\tconn.Lock()\n\tdefer conn.Unlock()\n\n\t// Check if we should use the default handler.\n\t// The default handler is only for fully decided\n\t// connections and just applying the verdict.\n\t// There is no logging for these packets.\n\tif conn.firewallHandler == nil {\n\t\t// Run default handler.\n\t\tdefaultFirewallHandler(conn, pkt)\n\n\t\t// Record metrics.\n\t\tpacketHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)\n\n\t\treturn\n\t}\n\n\t// Create tracing context.\n\t// Add context tracer and set context on packet.\n\ttraceCtx, tracer := log.AddTracer(ctx)\n\tif tracer != nil {\n\t\t// The trace is submitted in `network.Connection.packetHandler()`.\n\t\ttracer.Tracef(\"filter: handling packet: %s\", pkt)\n\t}\n\tpkt.SetCtx(traceCtx)\n\n\t// Handle packet with set handler.\n\tconn.firewallHandler(conn, pkt)\n\n\t// Record metrics.\n\tpacketHandlingHistogram.UpdateDuration(pkt.Info().SeenAt)\n\n\t// Log result and submit trace, when there are any changes.\n\tif conn.saveWhenFinished {\n\t\tswitch {\n\t\tcase conn.DataIsComplete():\n\t\t\ttracer.Infof(\"filter: connection %s %s: %s\", conn, conn.VerdictVerb(), conn.Reason.Msg)\n\t\tcase conn.Verdict != VerdictUndecided:\n\t\t\ttracer.Debugf(\"filter: connection %s fast-tracked\", pkt)\n\t\tdefault:\n\t\t\ttracer.Debugf(\"filter: gathered data on connection %s\", conn)\n\t\t}\n\t\t// Submit trace logs.\n\t\ttracer.Submit()\n\t}\n\n\t// Push changes, if there are any.\n\tif conn.saveWhenFinished {\n\t\tconn.saveWhenFinished = false\n\t\tconn.Save()\n\t}\n}\n"
  },
  {
    "path": "service/network/connection_store.go",
    "content": "package network\n\nimport (\n\t\"strings\"\n\t\"sync\"\n)\n\ntype connectionStore struct {\n\trw    sync.RWMutex\n\titems map[string]*Connection\n}\n\nfunc newConnectionStore() *connectionStore {\n\treturn &connectionStore{\n\t\titems: make(map[string]*Connection, 100),\n\t}\n}\n\nfunc (cs *connectionStore) add(conn *Connection) {\n\tcs.rw.Lock()\n\tdefer cs.rw.Unlock()\n\n\tcs.items[conn.ID] = conn\n}\n\nfunc (cs *connectionStore) delete(conn *Connection) {\n\tcs.rw.Lock()\n\tdefer cs.rw.Unlock()\n\n\tdelete(cs.items, conn.ID)\n}\n\nfunc (cs *connectionStore) get(id string) (*Connection, bool) {\n\tcs.rw.RLock()\n\tdefer cs.rw.RUnlock()\n\n\tconn, ok := cs.items[id]\n\treturn conn, ok\n}\n\n// findByPrefix returns the first connection where the key matches the given prefix.\n// If the prefix matches multiple entries, the result is not deterministic.\nfunc (cs *connectionStore) findByPrefix(prefix string) (*Connection, bool) { //nolint:unused\n\tcs.rw.RLock()\n\tdefer cs.rw.RUnlock()\n\n\tfor key, conn := range cs.items {\n\t\tif strings.HasPrefix(key, prefix) {\n\t\t\treturn conn, true\n\t\t}\n\t}\n\n\treturn nil, false\n}\n\nfunc (cs *connectionStore) clone() map[string]*Connection {\n\tcs.rw.RLock()\n\tdefer cs.rw.RUnlock()\n\n\tm := make(map[string]*Connection, len(cs.items))\n\tfor key, conn := range cs.items {\n\t\tm[key] = conn\n\t}\n\treturn m\n}\n\nfunc (cs *connectionStore) list() []*Connection {\n\tcs.rw.RLock()\n\tdefer cs.rw.RUnlock()\n\n\tl := make([]*Connection, 0, len(cs.items))\n\tfor _, conn := range cs.items {\n\t\tl = append(l, conn)\n\t}\n\treturn l\n}\n\nfunc (cs *connectionStore) len() int { //nolint:unused // TODO: Clean up if still unused.\n\tcs.rw.RLock()\n\tdefer cs.rw.RUnlock()\n\n\treturn len(cs.items)\n}\n\nfunc (cs *connectionStore) active() int {\n\t// Clone and count all active connections.\n\tvar cnt int\n\tfor _, conn := range cs.clone() {\n\t\tconn.Lock()\n\t\tif conn.Ended != 0 {\n\t\t\tcnt++\n\t\t}\n\t\tconn.Unlock()\n\t}\n\n\treturn cnt\n}\n"
  },
  {
    "path": "service/network/database.go",
    "content": "package network\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/process\"\n)\n\nconst (\n\tdbScopeNone = \"\"\n\tdbScopeDNS  = \"dns\"\n\tdbScopeIP   = \"ip\"\n)\n\nvar (\n\tdbController *database.Controller\n\n\tdnsConns = newConnectionStore()\n\tconns    = newConnectionStore()\n)\n\n// StorageInterface provices a storage.Interface to the\n// configuration manager.\ntype StorageInterface struct {\n\tstorage.InjectBase\n}\n\n// Database prefixes:\n// Processes:       network:tree/<PID>\n// DNS Requests:    network:tree/<PID>/dns/<ID>\n// IP Connections:  network:tree/<PID>/ip/<ID>\n\nfunc makeKey(pid int, scope, id string) string {\n\tif scope == \"\" {\n\t\treturn \"network:tree/\" + strconv.Itoa(pid)\n\t}\n\treturn fmt.Sprintf(\"network:tree/%d/%s/%s\", pid, scope, id)\n}\n\nfunc parseDBKey(key string) (processKey string, scope, id string, ok bool) {\n\t// Split into segments.\n\tsegments := strings.Split(key, \"/\")\n\n\t// Keys have 2 or 4 segments.\n\tswitch len(segments) {\n\tcase 4:\n\t\tid = segments[3]\n\n\t\tfallthrough\n\tcase 3:\n\t\tscope = segments[2]\n\t\t// Sanity check.\n\t\tswitch scope {\n\t\tcase dbScopeNone, dbScopeDNS, dbScopeIP:\n\t\t\t// Parsed id matches possible values.\n\t\t\t// The empty string is for matching a trailing slash for in query prefix.\n\t\t\t// TODO: For queries, also prefixes of these values are valid.\n\t\tdefault:\n\t\t\t// Unknown scope.\n\t\t\treturn \"\", \"\", \"\", false\n\t\t}\n\n\t\tfallthrough\n\tcase 2:\n\t\tprocessKey = segments[1]\n\t\treturn processKey, scope, id, true\n\tcase 1:\n\t\t// This is a valid query prefix, but not process ID was given.\n\t\treturn \"\", \"\", \"\", true\n\tdefault:\n\t\treturn \"\", \"\", \"\", false\n\t}\n}\n\n// Get returns a database record.\nfunc (s *StorageInterface) Get(key string) (record.Record, error) {\n\t// Parse key and check if valid.\n\tpid, scope, id, ok := parseDBKey(strings.TrimPrefix(key, \"network:\"))\n\tif !ok || pid == \"\" {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\tswitch scope {\n\tcase dbScopeDNS:\n\t\tif c, ok := dnsConns.get(id); ok && c.DataIsComplete() {\n\t\t\treturn c, nil\n\t\t}\n\tcase dbScopeIP:\n\t\tif c, ok := conns.get(id); ok && c.DataIsComplete() {\n\t\t\treturn c, nil\n\t\t}\n\tcase dbScopeNone:\n\t\tif proc, ok := process.GetProcessFromStorage(pid); ok {\n\t\t\treturn proc, nil\n\t\t}\n\t}\n\n\treturn nil, storage.ErrNotFound\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (s *StorageInterface) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\tit := iterator.New()\n\n\tmodule.mgr.Go(\"connection query\", func(_ *mgr.WorkerCtx) error {\n\t\ts.processQuery(q, it)\n\t\treturn nil\n\t})\n\n\treturn it, nil\n}\n\nfunc (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {\n\tvar matches bool\n\tpid, scope, _, ok := parseDBKey(q.DatabaseKeyPrefix())\n\tif !ok {\n\t\tit.Finish(nil)\n\t\treturn\n\t}\n\n\tif pid == \"\" {\n\t\t// processes\n\t\tfor _, proc := range process.All() {\n\t\t\tfunc() {\n\t\t\t\tproc.Lock()\n\t\t\t\tdefer proc.Unlock()\n\t\t\t\tmatches = q.Matches(proc)\n\t\t\t}()\n\t\t\tif matches {\n\t\t\t\tit.Next <- proc\n\t\t\t}\n\t\t}\n\t}\n\n\tif scope == dbScopeNone || scope == dbScopeDNS {\n\t\t// dns scopes only\n\t\tfor _, dnsConn := range dnsConns.clone() {\n\t\t\tif !dnsConn.DataIsComplete() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfunc() {\n\t\t\t\tdnsConn.Lock()\n\t\t\t\tdefer dnsConn.Unlock()\n\t\t\t\tmatches = q.Matches(dnsConn)\n\t\t\t}()\n\n\t\t\tif matches {\n\t\t\t\tit.Next <- dnsConn\n\t\t\t}\n\t\t}\n\t}\n\n\tif scope == dbScopeNone || scope == dbScopeIP {\n\t\t// connections\n\t\tfor _, conn := range conns.clone() {\n\t\t\tif !conn.DataIsComplete() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfunc() {\n\t\t\t\tconn.Lock()\n\t\t\t\tdefer conn.Unlock()\n\t\t\t\tmatches = q.Matches(conn)\n\t\t\t}()\n\n\t\t\tif matches {\n\t\t\t\tit.Next <- conn\n\t\t\t}\n\t\t}\n\t}\n\n\tit.Finish(nil)\n}\n\nfunc registerAsDatabase() error {\n\t_, err := database.Register(&database.Database{\n\t\tName:        \"network\",\n\t\tDescription: \"Network and Firewall Data\",\n\t\tStorageType: \"injected\",\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontroller, err := database.InjectDatabase(\"network\", &StorageInterface{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdbController = controller\n\tprocess.SetDBController(dbController)\n\treturn nil\n}\n"
  },
  {
    "path": "service/network/dns.go",
    "content": "package network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/nameserver/nsutil\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\nvar (\n\tdnsRequestConnections     = make(map[string]*Connection) // key: <protocol>-<local ip>-<local port>\n\tdnsRequestConnectionsLock sync.RWMutex\n\n\topenDNSRequests     = make(map[string]*Connection) // key: <pid>/<fqdn>\n\topenDNSRequestsLock sync.Mutex\n\n\tsupportedDomainToIPRecordTypes = []uint16{\n\t\tdns.TypeA,\n\t\tdns.TypeAAAA,\n\t\tdns.TypeSVCB,\n\t\tdns.TypeHTTPS,\n\t}\n)\n\nconst (\n\t// writeOpenDNSRequestsTickDuration defines the interval in which open dns\n\t// requests are written.\n\twriteOpenDNSRequestsTickDuration = 5 * time.Second\n\n\t// openDNSRequestLimit defines the duration after which DNS requests without\n\t// a following connection are logged.\n\topenDNSRequestLimit = 3 * time.Second\n)\n\nfunc getDNSRequestConnectionKey(packetInfo *packet.Info) (id string, ok bool) {\n\t// We only support protocols with ports.\n\tif packetInfo.SrcPort == 0 {\n\t\treturn \"\", false\n\t}\n\n\treturn fmt.Sprintf(\"%d-%s-%d\", packetInfo.Protocol, packetInfo.Src, packetInfo.SrcPort), true\n}\n\n// SaveDNSRequestConnection saves a dns request connection for later retrieval.\nfunc SaveDNSRequestConnection(conn *Connection, pkt packet.Packet) {\n\t// Check connection.\n\tif conn.PID == process.UndefinedProcessID || conn.PID == process.SystemProcessID {\n\t\t// When re-injecting packets on Windows, they are reported with kernel PID (4).\n\t\tlog.Tracer(pkt.Ctx()).Tracef(\"network: not saving dns request connection because the PID is undefined/kernel\")\n\t\treturn\n\t}\n\n\t// Create key.\n\tkey, ok := getDNSRequestConnectionKey(pkt.Info())\n\tif !ok {\n\t\tlog.Tracer(pkt.Ctx()).Debugf(\"network: not saving dns request connection %s because the protocol is not supported\", pkt)\n\t\treturn\n\t}\n\n\t// Add or update DNS request connection.\n\tlog.Tracer(pkt.Ctx()).Tracef(\"network: saving %s with PID %d as dns request connection for fast DNS request attribution\", pkt, conn.PID)\n\tdnsRequestConnectionsLock.Lock()\n\tdefer dnsRequestConnectionsLock.Unlock()\n\tdnsRequestConnections[key] = conn\n}\n\n// GetDNSRequestConnection returns a saved dns request connection.\nfunc GetDNSRequestConnection(packetInfo *packet.Info) (conn *Connection, ok bool) {\n\t// Make key.\n\tkey, ok := getDNSRequestConnectionKey(packetInfo)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\t// Get and return\n\tdnsRequestConnectionsLock.RLock()\n\tdefer dnsRequestConnectionsLock.RUnlock()\n\n\tconn, ok = dnsRequestConnections[key]\n\treturn conn, ok\n}\n\n// deleteDNSRequestConnection removes a connection from the dns request connections.\nfunc deleteDNSRequestConnection(packetInfo *packet.Info) { //nolint:unused,deadcode\n\tdnsRequestConnectionsLock.Lock()\n\tdefer dnsRequestConnectionsLock.Unlock()\n\n\tkey, ok := getDNSRequestConnectionKey(packetInfo)\n\tif ok {\n\t\tdelete(dnsRequestConnections, key)\n\t}\n}\n\n// cleanDNSRequestConnections deletes old DNS request connections.\nfunc cleanDNSRequestConnections() {\n\tdeleteOlderThan := time.Now().Unix() - 3\n\n\tdnsRequestConnectionsLock.Lock()\n\tdefer dnsRequestConnectionsLock.Unlock()\n\n\tfor key, conn := range dnsRequestConnections {\n\t\tconn.Lock()\n\n\t\tif conn.Ended > 0 && conn.Ended < deleteOlderThan {\n\t\t\tdelete(dnsRequestConnections, key)\n\t\t}\n\n\t\tconn.Unlock()\n\t}\n}\n\n// IsSupportDNSRecordType returns whether the given DSN RR type is supported\n// by the network package, as in the requests are specially handled and can be\n// \"merged\" into the resulting connection.\nfunc IsSupportDNSRecordType(rrType uint16) bool {\n\treturn slices.Contains[[]uint16, uint16](supportedDomainToIPRecordTypes, rrType)\n}\n\nfunc getDNSRequestCacheKey(pid int, fqdn string, qType uint16) string {\n\treturn strconv.Itoa(pid) + \"/\" + fqdn + dns.Type(qType).String()\n}\n\nfunc removeOpenDNSRequest(pid int, fqdn string) {\n\topenDNSRequestsLock.Lock()\n\tdefer openDNSRequestsLock.Unlock()\n\n\t// Delete PID-specific requests.\n\tfor _, dnsType := range supportedDomainToIPRecordTypes {\n\t\tdelete(openDNSRequests, getDNSRequestCacheKey(pid, fqdn, dnsType))\n\t}\n\n\t// If process is known, also check for non-attributed requests.\n\tif pid != process.UnidentifiedProcessID {\n\t\tfor _, dnsType := range supportedDomainToIPRecordTypes {\n\t\t\tdelete(openDNSRequests, getDNSRequestCacheKey(process.UnidentifiedProcessID, fqdn, dnsType))\n\t\t}\n\t}\n}\n\n// SaveOpenDNSRequest saves a dns request connection that was allowed to proceed.\nfunc SaveOpenDNSRequest(q *resolver.Query, rrCache *resolver.RRCache, conn *Connection) {\n\t// Only save requests that actually went out (or triggered an async resolve) to reduce clutter.\n\tif rrCache == nil || (rrCache.ServedFromCache && !rrCache.RequestingNew) {\n\t\treturn\n\t}\n\n\t// Try to \"merge\" supported requests into the resulting connection.\n\t// Save others immediately.\n\tif !IsSupportDNSRecordType(uint16(q.QType)) {\n\t\tconn.Save()\n\t\treturn\n\t}\n\n\topenDNSRequestsLock.Lock()\n\tdefer openDNSRequestsLock.Unlock()\n\n\t// Do not check for an existing open DNS request, as duplicates in such quick\n\t// succession are not worth keeping.\n\t// DNS queries are usually retried pretty quick.\n\n\t// Save to open dns requests.\n\tkey := getDNSRequestCacheKey(conn.process.Pid, conn.Entity.Domain, uint16(q.QType))\n\topenDNSRequests[key] = conn\n}\n\nfunc openDNSRequestWriter(ctx *mgr.WorkerCtx) error {\n\tmodule.dnsRequestTicker = mgr.NewSleepyTicker(writeOpenDNSRequestsTickDuration, 0)\n\tdefer module.dnsRequestTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-module.dnsRequestTicker.Wait():\n\t\t\twriteOpenDNSRequestsToDB()\n\t\t}\n\t}\n}\n\nfunc writeOpenDNSRequestsToDB() {\n\topenDNSRequestsLock.Lock()\n\tdefer openDNSRequestsLock.Unlock()\n\n\tthreshold := time.Now().Add(-openDNSRequestLimit).Unix()\n\tfor id, conn := range openDNSRequests {\n\t\tfunc() {\n\t\t\tconn.Lock()\n\t\t\tdefer conn.Unlock()\n\n\t\t\tif conn.Ended < threshold {\n\t\t\t\tconn.Save()\n\t\t\t\tdelete(openDNSRequests, id)\n\t\t\t}\n\t\t}()\n\t}\n}\n\n// ReplyWithDNS creates a new reply to the given request with the data from the RRCache, and additional informational records.\nfunc (conn *Connection) ReplyWithDNS(ctx context.Context, request *dns.Msg) *dns.Msg {\n\t// Select request responder.\n\tswitch conn.Verdict {\n\tcase VerdictBlock:\n\t\treturn nsutil.BlockIP().ReplyWithDNS(ctx, request)\n\tcase VerdictDrop:\n\t\treturn nil // Do not respond to request.\n\tcase VerdictFailed:\n\t\treturn nsutil.BlockIP().ReplyWithDNS(ctx, request)\n\tcase VerdictUndecided, VerdictUndeterminable,\n\t\tVerdictAccept, VerdictRerouteToNameserver, VerdictRerouteToTunnel:\n\t\tfallthrough\n\tdefault:\n\t\treply := nsutil.ServerFailure().ReplyWithDNS(ctx, request)\n\t\tnsutil.AddMessagesToReply(ctx, reply, log.ErrorLevel, \"INTERNAL ERROR: incorrect use of Connection DNS Responder\")\n\t\treturn reply\n\t}\n}\n\n// GetExtraRRs returns a slice of RRs with additional informational records.\nfunc (conn *Connection) GetExtraRRs(ctx context.Context, request *dns.Msg) []dns.RR {\n\t// Select level to add the verdict record with.\n\tvar level log.Severity\n\tswitch conn.Verdict {\n\tcase VerdictFailed:\n\t\tlevel = log.ErrorLevel\n\tcase VerdictUndecided, VerdictUndeterminable,\n\t\tVerdictAccept, VerdictBlock, VerdictDrop,\n\t\tVerdictRerouteToNameserver, VerdictRerouteToTunnel:\n\t\tfallthrough\n\tdefault:\n\t\tlevel = log.InfoLevel\n\t}\n\n\t// Create resource record with verdict and reason.\n\trr, err := nsutil.MakeMessageRecord(level, fmt.Sprintf(\"%s: %s\", conn.VerdictVerb(), conn.Reason.Msg))\n\tif err != nil {\n\t\tlog.Tracer(ctx).Warningf(\"filter: failed to add informational record to reply: %s\", err)\n\t\treturn nil\n\t}\n\textra := []dns.RR{rr}\n\n\t// Add additional records from Reason.Context.\n\tif rrProvider, ok := conn.Reason.Context.(nsutil.RRProvider); ok {\n\t\trrs := rrProvider.GetExtraRRs(ctx, request)\n\t\textra = append(extra, rrs...)\n\t}\n\n\treturn extra\n}\n"
  },
  {
    "path": "service/network/iphelper/get.go",
    "content": "//go:build windows\n\npackage iphelper\n\nimport (\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\nvar (\n\tipHelper *IPHelper\n\n\t// lock locks access to the whole DLL.\n\t// TODO: It's unproven if we can access the iphlpapi.dll concurrently, especially as we might be encountering various versions of the DLL. In the future, we could possibly investigate and improve performance here.\n\tlock sync.RWMutex\n)\n\n// GetTCP4Table returns the system table for IPv4 TCP activity.\nfunc GetTCP4Table() (connections []*socket.ConnectionInfo, listeners []*socket.BindInfo, err error) {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\n\terr = checkIPHelper()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn ipHelper.getTable(IPv4, TCP)\n}\n\n// GetTCP6Table returns the system table for IPv6 TCP activity.\nfunc GetTCP6Table() (connections []*socket.ConnectionInfo, listeners []*socket.BindInfo, err error) {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\n\terr = checkIPHelper()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn ipHelper.getTable(IPv6, TCP)\n}\n\n// GetUDP4Table returns the system table for IPv4 UDP activity.\nfunc GetUDP4Table() (binds []*socket.BindInfo, err error) {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\n\terr = checkIPHelper()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t_, binds, err = ipHelper.getTable(IPv4, UDP)\n\treturn\n}\n\n// GetUDP6Table returns the system table for IPv6 UDP activity.\nfunc GetUDP6Table() (binds []*socket.BindInfo, err error) {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\n\terr = checkIPHelper()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t_, binds, err = ipHelper.getTable(IPv6, UDP)\n\treturn\n}\n"
  },
  {
    "path": "service/network/iphelper/iphelper.go",
    "content": "//go:build windows\n\npackage iphelper\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/tevino/abool\"\n\t\"golang.org/x/sys/windows\"\n)\n\nvar (\n\terrInvalid = errors.New(\"IPHelper not initialized or broken\")\n)\n\n// IPHelper represents a subset of the Windows iphlpapi.dll.\ntype IPHelper struct {\n\tdll *windows.LazyDLL\n\n\tgetExtendedTCPTable *windows.LazyProc\n\tgetExtendedUDPTable *windows.LazyProc\n\n\tvalid *abool.AtomicBool\n}\n\nfunc checkIPHelper() (err error) {\n\tif ipHelper == nil {\n\t\tipHelper, err = New()\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// New returns a new IPHelper API (with an instance of iphlpapi.dll loaded).\nfunc New() (*IPHelper, error) {\n\n\tnew := &IPHelper{}\n\tnew.valid = abool.NewBool(false)\n\tvar err error\n\n\t// load dll\n\tnew.dll = windows.NewLazySystemDLL(\"iphlpapi.dll\")\n\terr = new.dll.Load()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// load functions\n\tnew.getExtendedTCPTable = new.dll.NewProc(\"GetExtendedTcpTable\")\n\terr = new.getExtendedTCPTable.Find()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could find proc GetExtendedTcpTable: %s\", err)\n\t}\n\tnew.getExtendedUDPTable = new.dll.NewProc(\"GetExtendedUdpTable\")\n\terr = new.getExtendedUDPTable.Find()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could find proc GetExtendedUdpTable: %s\", err)\n\t}\n\n\tnew.valid.Set()\n\treturn new, nil\n}\n"
  },
  {
    "path": "service/network/iphelper/tables.go",
    "content": "//go:build windows\n\npackage iphelper\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"unsafe\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\n// Windows API constants\nconst (\n\tiphelperTCPTableOwnerPIDAll uintptr = 5\n\tiphelperUDPTableOwnerPID    uintptr = 1\n\tiphelperTCPStateListen      uint32  = 2\n\n\twinErrInsufficientBuffer = uintptr(windows.ERROR_INSUFFICIENT_BUFFER)\n\twinErrInvalidParameter   = uintptr(windows.ERROR_INVALID_PARAMETER)\n)\n\ntype iphelperTCPTable struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366921(v=vs.85).aspx\n\tnumEntries uint32\n\ttable      [maxStateTableEntries]iphelperTCPRow\n}\n\ntype iphelperTCPRow struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366913(v=vs.85).aspx\n\tstate      uint32\n\tlocalAddr  uint32\n\tlocalPort  uint32\n\tremoteAddr uint32\n\tremotePort uint32\n\towningPid  uint32\n}\n\ntype iphelperTCP6Table struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366905(v=vs.85).aspx\n\tnumEntries uint32\n\ttable      [maxStateTableEntries]iphelperTCP6Row\n}\n\ntype iphelperTCP6Row struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366896(v=vs.85).aspx\n\tlocalAddr  [16]byte\n\t_          uint32 // localScopeID\n\tlocalPort  uint32\n\tremoteAddr [16]byte\n\t_          uint32 // remoteScopeID\n\tremotePort uint32\n\tstate      uint32\n\towningPid  uint32\n}\n\ntype iphelperUDPTable struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366932(v=vs.85).aspx\n\tnumEntries uint32\n\ttable      [maxStateTableEntries]iphelperUDPRow\n}\n\ntype iphelperUDPRow struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366928(v=vs.85).aspx\n\tlocalAddr uint32\n\tlocalPort uint32\n\towningPid uint32\n}\n\ntype iphelperUDP6Table struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366925(v=vs.85).aspx\n\tnumEntries uint32\n\ttable      [maxStateTableEntries]iphelperUDP6Row\n}\n\ntype iphelperUDP6Row struct {\n\t// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366923(v=vs.85).aspx\n\tlocalAddr [16]byte\n\t_         uint32 // localScopeID\n\tlocalPort uint32\n\towningPid uint32\n}\n\n// IP and Protocol constants\nconst (\n\tIPv4 uint8 = 4\n\tIPv6 uint8 = 6\n\n\tTCP uint8 = 6\n\tUDP uint8 = 17\n)\n\ntype learningBufSize struct {\n\tsync.Mutex\n\n\tsize     int\n\tusesLeft int\n\tuseFor   int\n\tstart    int\n\tmax      int\n}\n\nfunc newLearningBufSize(start, max, ttl int) *learningBufSize {\n\treturn &learningBufSize{\n\t\tsize:     start,\n\t\tusesLeft: ttl,\n\t\tuseFor:   ttl,\n\t\tstart:    start,\n\t\tmax:      max,\n\t}\n}\n\nconst (\n\tstartBufSize = 1024\n\n\t// bufSizeUsageTTL defines how often a buffer size is used before it is\n\t// shrunk again.\n\tbufSizeUsageTTL = 100\n\n\t// maxBufSize is the maximum size we will allocate for responses. This was\n\t// previously set at 65k, which was too little for some production cases.\n\tmaxBufSize = 1048576 // 2^20B, 1MB\n\n\t// maxStateTableEntries is the maximum supported amount of entries of the\n\t// state tables.\n\t// This is never allocated, but just casted to from an unsafe pointer.\n\tmaxStateTableEntries = 65535\n)\n\nvar (\n\ttcp4BufSize = newLearningBufSize(startBufSize, maxBufSize, bufSizeUsageTTL)\n\tudp4BufSize = newLearningBufSize(startBufSize, maxBufSize, bufSizeUsageTTL)\n\ttcp6BufSize = newLearningBufSize(startBufSize, maxBufSize, bufSizeUsageTTL)\n\tudp6BufSize = newLearningBufSize(startBufSize, maxBufSize, bufSizeUsageTTL)\n)\n\nfunc (lbf *learningBufSize) getBufSize() int {\n\tlbf.Lock()\n\tdefer lbf.Unlock()\n\n\t// using bufSize\n\tlbf.usesLeft--\n\t// check if we want to reset\n\tif lbf.usesLeft <= 0 {\n\t\t// decrease\n\t\tlbf.size /= 2\n\t\t// not too little\n\t\tif lbf.size < lbf.start {\n\t\t\tlbf.size = lbf.start\n\t\t}\n\t\t// reset TTL counter\n\t\tlbf.usesLeft = lbf.useFor\n\t}\n\n\treturn lbf.size\n}\n\nfunc (lbf *learningBufSize) increaseBufSize(minSize int) int {\n\tlbf.Lock()\n\tdefer lbf.Unlock()\n\n\t// increase\n\tlbf.size *= 2\n\t// increase until we reach the minimum size\n\tfor lbf.size < minSize {\n\t\tlbf.size *= 2\n\t}\n\t// not too much\n\tif lbf.size > lbf.max {\n\t\tlbf.size = lbf.max\n\t}\n\t// reset TTL counter\n\tlbf.usesLeft = lbf.useFor\n\t// return new bufSize\n\treturn lbf.size\n}\n\n// getTable returns the current connection state table of Windows of the given protocol and IP version.\nfunc (ipHelper *IPHelper) getTable(ipVersion, protocol uint8) (connections []*socket.ConnectionInfo, binds []*socket.BindInfo, err error) { //nolint:gocognit,gocycle // TODO\n\t// docs: https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getextendedtcptable\n\n\tif !ipHelper.valid.IsSet() {\n\t\treturn nil, nil, errInvalid\n\t}\n\n\tvar afClass int\n\tvar lbf *learningBufSize\n\tswitch ipVersion {\n\tcase IPv4:\n\t\tafClass = windows.AF_INET\n\t\tif protocol == TCP {\n\t\t\tlbf = tcp4BufSize\n\t\t} else {\n\t\t\tlbf = udp4BufSize\n\t\t}\n\tcase IPv6:\n\t\tafClass = windows.AF_INET6\n\t\tif protocol == TCP {\n\t\t\tlbf = tcp6BufSize\n\t\t} else {\n\t\t\tlbf = udp6BufSize\n\t\t}\n\tdefault:\n\t\treturn nil, nil, errors.New(\"invalid protocol\")\n\t}\n\n\t// try max 5 times\n\tmaxTries := 5\n\tusedBufSize := lbf.getBufSize()\n\tvar buf []byte\ntriesLoop:\n\tfor i := 1; i <= maxTries; i++ {\n\t\tbufSizeParam := usedBufSize\n\t\tbuf = make([]byte, bufSizeParam)\n\t\tvar r1 uintptr\n\n\t\tswitch protocol {\n\t\tcase TCP:\n\t\t\tr1, _, err = ipHelper.getExtendedTCPTable.Call(\n\t\t\t\tuintptr(unsafe.Pointer(&buf[0])),       // _Out_   PVOID           pTcpTable\n\t\t\t\tuintptr(unsafe.Pointer(&bufSizeParam)), // _Inout_ PDWORD          pdwSize\n\t\t\t\t0,                                      // _In_    BOOL            bOrder\n\t\t\t\tuintptr(afClass),                       // _In_    ULONG           ulAf\n\t\t\t\tiphelperTCPTableOwnerPIDAll,            // _In_    TCP_TABLE_CLASS TableClass\n\t\t\t\t0,                                      // _In_    ULONG           Reserved\n\t\t\t)\n\t\tcase UDP:\n\t\t\tr1, _, err = ipHelper.getExtendedUDPTable.Call(\n\t\t\t\tuintptr(unsafe.Pointer(&buf[0])),       // _Out_   PVOID           pUdpTable,\n\t\t\t\tuintptr(unsafe.Pointer(&bufSizeParam)), // _Inout_ PDWORD          pdwSize,\n\t\t\t\t0,                                      // _In_    BOOL            bOrder,\n\t\t\t\tuintptr(afClass),                       // _In_    ULONG           ulAf,\n\t\t\t\tiphelperUDPTableOwnerPID,               // _In_    UDP_TABLE_CLASS TableClass,\n\t\t\t\t0,                                      // _In_    ULONG           Reserved\n\t\t\t)\n\t\t}\n\n\t\tswitch r1 {\n\t\tcase winErrInsufficientBuffer:\n\t\t\tif i >= maxTries {\n\t\t\t\treturn nil, nil, fmt.Errorf(\n\t\t\t\t\t\"insufficient buffer error (tried %d times): provided %d bytes; required %d bytes - [NT 0x%X] %s\",\n\t\t\t\t\ti, usedBufSize, bufSizeParam, r1, err,\n\t\t\t\t)\n\t\t\t}\n\t\t\t// bufSizeParam was modified by ipHelper.getExtended*Table to hold the\n\t\t\t// required buffer size.\n\t\t\tusedBufSize = lbf.increaseBufSize(bufSizeParam)\n\t\tcase winErrInvalidParameter:\n\t\t\treturn nil, nil, fmt.Errorf(\"invalid parameter: [NT 0x%X] %s\", r1, err)\n\t\tcase windows.NO_ERROR:\n\t\t\t// success\n\t\t\tbreak triesLoop\n\t\tdefault:\n\t\t\treturn nil, nil, fmt.Errorf(\"unexpected error: [NT 0x%X] %s\", r1, err)\n\t\t}\n\t}\n\n\t// parse output\n\tswitch {\n\tcase protocol == TCP && ipVersion == IPv4:\n\n\t\ttcpTable := (*iphelperTCPTable)(unsafe.Pointer(&buf[0]))\n\t\t// Check if we got more entries than supported.\n\t\ttableEntries := tcpTable.numEntries\n\t\tif tableEntries > maxStateTableEntries {\n\t\t\ttableEntries = maxStateTableEntries\n\t\t\tlog.Warningf(\"network/iphelper: received TCPv4 table with more entries than supported: %d/%d\", tcpTable.numEntries, maxStateTableEntries)\n\t\t}\n\t\t// Cap table to actual entries.\n\t\ttable := tcpTable.table[:tableEntries]\n\n\t\tfor _, row := range table {\n\t\t\tif row.state == iphelperTCPStateListen {\n\t\t\t\tbinds = append(binds, &socket.BindInfo{\n\t\t\t\t\tLocal: socket.Address{\n\t\t\t\t\t\tIP:   convertIPv4(row.localAddr),\n\t\t\t\t\t\tPort: convertPort(row.localPort),\n\t\t\t\t\t},\n\t\t\t\t\tPID: int(row.owningPid),\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tconnections = append(connections, &socket.ConnectionInfo{\n\t\t\t\t\tLocal: socket.Address{\n\t\t\t\t\t\tIP:   convertIPv4(row.localAddr),\n\t\t\t\t\t\tPort: convertPort(row.localPort),\n\t\t\t\t\t},\n\t\t\t\t\tRemote: socket.Address{\n\t\t\t\t\t\tIP:   convertIPv4(row.remoteAddr),\n\t\t\t\t\t\tPort: convertPort(row.remotePort),\n\t\t\t\t\t},\n\t\t\t\t\tPID: int(row.owningPid),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\tcase protocol == TCP && ipVersion == IPv6:\n\n\t\ttcpTable := (*iphelperTCP6Table)(unsafe.Pointer(&buf[0]))\n\t\t// Check if we got more entries than supported.\n\t\ttableEntries := tcpTable.numEntries\n\t\tif tableEntries > maxStateTableEntries {\n\t\t\ttableEntries = maxStateTableEntries\n\t\t\tlog.Warningf(\"network/iphelper: received TCPv6 table with more entries than supported: %d/%d\", tcpTable.numEntries, maxStateTableEntries)\n\t\t}\n\t\t// Cap table to actual entries.\n\t\ttable := tcpTable.table[:tableEntries]\n\n\t\tfor _, row := range table {\n\t\t\tif row.state == iphelperTCPStateListen {\n\t\t\t\tbinds = append(binds, &socket.BindInfo{\n\t\t\t\t\tLocal: socket.Address{\n\t\t\t\t\t\tIP:   net.IP(row.localAddr[:]),\n\t\t\t\t\t\tPort: convertPort(row.localPort),\n\t\t\t\t\t},\n\t\t\t\t\tPID: int(row.owningPid),\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tconnections = append(connections, &socket.ConnectionInfo{\n\t\t\t\t\tLocal: socket.Address{\n\t\t\t\t\t\tIP:   net.IP(row.localAddr[:]),\n\t\t\t\t\t\tPort: convertPort(row.localPort),\n\t\t\t\t\t},\n\t\t\t\t\tRemote: socket.Address{\n\t\t\t\t\t\tIP:   net.IP(row.remoteAddr[:]),\n\t\t\t\t\t\tPort: convertPort(row.remotePort),\n\t\t\t\t\t},\n\t\t\t\t\tPID: int(row.owningPid),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\tcase protocol == UDP && ipVersion == IPv4:\n\n\t\tudpTable := (*iphelperUDPTable)(unsafe.Pointer(&buf[0]))\n\t\t// Check if we got more entries than supported.\n\t\ttableEntries := udpTable.numEntries\n\t\tif tableEntries > maxStateTableEntries {\n\t\t\ttableEntries = maxStateTableEntries\n\t\t\tlog.Warningf(\"network/iphelper: received UDPv4 table with more entries than supported: %d/%d\", udpTable.numEntries, maxStateTableEntries)\n\t\t}\n\t\t// Cap table to actual entries.\n\t\ttable := udpTable.table[:tableEntries]\n\n\t\tfor _, row := range table {\n\t\t\tbinds = append(binds, &socket.BindInfo{\n\t\t\t\tLocal: socket.Address{\n\t\t\t\t\tIP:   convertIPv4(row.localAddr),\n\t\t\t\t\tPort: convertPort(row.localPort),\n\t\t\t\t},\n\t\t\t\tPID: int(row.owningPid),\n\t\t\t})\n\t\t}\n\n\tcase protocol == UDP && ipVersion == IPv6:\n\n\t\tudpTable := (*iphelperUDP6Table)(unsafe.Pointer(&buf[0]))\n\t\t// Check if we got more entries than supported.\n\t\ttableEntries := udpTable.numEntries\n\t\tif tableEntries > maxStateTableEntries {\n\t\t\ttableEntries = maxStateTableEntries\n\t\t\tlog.Warningf(\"network/iphelper: received UDPv6 table with more entries than supported: %d/%d\", udpTable.numEntries, maxStateTableEntries)\n\t\t}\n\t\t// Cap table to actual entries.\n\t\ttable := udpTable.table[:tableEntries]\n\n\t\tfor _, row := range table {\n\t\t\tbinds = append(binds, &socket.BindInfo{\n\t\t\t\tLocal: socket.Address{\n\t\t\t\t\tIP:   net.IP(row.localAddr[:]),\n\t\t\t\t\tPort: convertPort(row.localPort),\n\t\t\t\t},\n\t\t\t\tPID: int(row.owningPid),\n\t\t\t})\n\t\t}\n\n\t}\n\n\treturn connections, binds, nil\n}\n\n// convertIPv4 as needed for iphlpapi.dll\nfunc convertIPv4(input uint32) net.IP {\n\taddressBuf := make([]byte, 4)\n\tbinary.LittleEndian.PutUint32(addressBuf, input)\n\treturn net.IP(addressBuf)\n}\n\n// convertPort converts ports received from iphlpapi.dll\nfunc convertPort(input uint32) uint16 {\n\treturn uint16(input>>8 | input<<8)\n}\n"
  },
  {
    "path": "service/network/iphelper/tables_test.go",
    "content": "//go:build windows\n\npackage iphelper\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestSockets(t *testing.T) {\n\tconnections, listeners, err := GetTCP4Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nTCP 4 connections:\")\n\tfor _, connection := range connections {\n\t\tfmt.Printf(\"%+v\\n\", connection)\n\t}\n\tfmt.Println(\"\\nTCP 4 listeners:\")\n\tfor _, listener := range listeners {\n\t\tfmt.Printf(\"%+v\\n\", listener)\n\t}\n\n\tconnections, listeners, err = GetTCP6Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nTCP 6 connections:\")\n\tfor _, connection := range connections {\n\t\tfmt.Printf(\"%+v\\n\", connection)\n\t}\n\tfmt.Println(\"\\nTCP 6 listeners:\")\n\tfor _, listener := range listeners {\n\t\tfmt.Printf(\"%+v\\n\", listener)\n\t}\n\n\tbinds, err := GetUDP4Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nUDP 4 binds:\")\n\tfor _, bind := range binds {\n\t\tfmt.Printf(\"%+v\\n\", bind)\n\t}\n\n\tbinds, err = GetUDP6Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nUDP 6 binds:\")\n\tfor _, bind := range binds {\n\t\tfmt.Printf(\"%+v\\n\", bind)\n\t}\n}\n"
  },
  {
    "path": "service/network/metrics.go",
    "content": "package network\n\nimport (\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/service/process\"\n)\n\nvar (\n\tpacketHandlingHistogram            *metrics.Histogram\n\tblockedOutConnCounter              *metrics.Counter\n\tencryptedAndTunneledOutConnCounter *metrics.Counter\n\tencryptedOutConnCounter            *metrics.Counter\n\ttunneledOutConnCounter             *metrics.Counter\n\toutConnCounter                     *metrics.Counter\n)\n\nfunc registerMetrics() (err error) {\n\t// This needed to be moved here, because every packet is now handled by the\n\t// connection handler worker.\n\tpacketHandlingHistogram, err = metrics.NewHistogram(\n\t\t\"firewall/handling/duration/seconds\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tPermission:     api.PermitUser,\n\t\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"network/connections/active/total\",\n\t\tnil,\n\t\tfunc() float64 {\n\t\t\treturn float64(conns.active())\n\t\t},\n\t\t&metrics.Options{\n\t\t\tInternalID:     \"active_connections\",\n\t\t\tPermission:     api.PermitUser,\n\t\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnCounterID := \"network/connections/total\"\n\tconnCounterOpts := &metrics.Options{\n\t\tName:           \"Connections\",\n\t\tPermission:     api.PermitUser,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tPersist:        true,\n\t}\n\n\tblockedOutConnCounter, err = metrics.NewCounter(\n\t\tconnCounterID,\n\t\tmap[string]string{\n\t\t\t\"direction\": \"out\",\n\t\t\t\"blocked\":   \"true\",\n\t\t},\n\t\t&metrics.Options{\n\t\t\tName:           \"Connections\",\n\t\t\tInternalID:     \"blocked_outgoing_connections\",\n\t\t\tPermission:     api.PermitUser,\n\t\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\t\tPersist:        true,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tencryptedAndTunneledOutConnCounter, err = metrics.NewCounter(\n\t\tconnCounterID,\n\t\tmap[string]string{\n\t\t\t\"direction\": \"out\",\n\t\t\t\"encrypted\": \"true\",\n\t\t\t\"tunneled\":  \"true\",\n\t\t},\n\t\tconnCounterOpts,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tencryptedOutConnCounter, err = metrics.NewCounter(\n\t\tconnCounterID,\n\t\tmap[string]string{\n\t\t\t\"direction\": \"out\",\n\t\t\t\"encrypted\": \"true\",\n\t\t},\n\t\tconnCounterOpts,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttunneledOutConnCounter, err = metrics.NewCounter(\n\t\tconnCounterID,\n\t\tmap[string]string{\n\t\t\t\"direction\": \"out\",\n\t\t\t\"tunneled\":  \"true\",\n\t\t},\n\t\tconnCounterOpts,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toutConnCounter, err = metrics.NewCounter(\n\t\tconnCounterID,\n\t\tmap[string]string{\n\t\t\t\"direction\": \"out\",\n\t\t},\n\t\tconnCounterOpts,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (conn *Connection) addToMetrics() {\n\tif conn.addedToMetrics {\n\t\treturn\n\t}\n\n\t// Don't count requests serviced to the network,\n\t// as we have an incomplete view here.\n\tif conn.Process() != nil &&\n\t\tconn.Process().Pid == process.NetworkHostProcessID {\n\t\treturn\n\t}\n\n\t// Only count outgoing connections for now.\n\tif conn.Inbound {\n\t\treturn\n\t}\n\n\t// Check the verdict.\n\tswitch conn.Verdict { //nolint:exhaustive // Not critical.\n\tcase VerdictBlock, VerdictDrop:\n\t\tblockedOutConnCounter.Inc()\n\t\tconn.addedToMetrics = true\n\t\treturn\n\tcase VerdictAccept, VerdictRerouteToTunnel:\n\t\t// Continue to next section.\n\tdefault:\n\t\t// Connection is not counted.\n\t\treturn\n\t}\n\n\t// Only count successful connections, not DNS requests.\n\tif conn.Type == DNSRequest {\n\t\treturn\n\t}\n\n\t// Select counter based on attributes.\n\tswitch {\n\tcase conn.Encrypted && conn.Tunneled:\n\t\tencryptedAndTunneledOutConnCounter.Inc()\n\tcase conn.Encrypted:\n\t\tencryptedOutConnCounter.Inc()\n\tcase conn.Tunneled:\n\t\ttunneledOutConnCounter.Inc()\n\tdefault:\n\t\toutConnCounter.Inc()\n\t}\n\tconn.addedToMetrics = true\n}\n"
  },
  {
    "path": "service/network/module.go",
    "content": "package network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/firewall/interception/dnsmonitor\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/state\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/resolver\"\n)\n\n// Events.\nconst (\n\tConnectionReattributedEvent = \"connection re-attributed\"\n)\n\ntype Network struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tdnsRequestTicker        *mgr.SleepyTicker\n\tconnectionCleanerTicker *mgr.SleepyTicker\n\n\tEventConnectionReattributed *mgr.EventMgr[string]\n}\n\nfunc (n *Network) Manager() *mgr.Manager {\n\treturn n.mgr\n}\n\nfunc (n *Network) Start() error {\n\treturn start()\n}\n\nfunc (n *Network) Stop() error {\n\treturn nil\n}\n\nfunc (n *Network) SetSleep(enabled bool) {\n\tif n.dnsRequestTicker != nil {\n\t\tn.dnsRequestTicker.SetSleep(enabled)\n\t}\n\tif n.connectionCleanerTicker != nil {\n\t\tn.connectionCleanerTicker.SetSleep(enabled)\n\t}\n}\n\nvar defaultFirewallHandler FirewallHandler\n\n// SetDefaultFirewallHandler sets the default firewall handler.\nfunc SetDefaultFirewallHandler(handler FirewallHandler) {\n\tif defaultFirewallHandler == nil {\n\t\tdefaultFirewallHandler = handler\n\t}\n}\n\nfunc prep() error {\n\tif netenv.IPv6Enabled() {\n\t\tstate.EnableTCPDualStack()\n\t\tstate.EnableUDPDualStack()\n\t}\n\n\treturn registerAPIEndpoints()\n}\n\nfunc start() error {\n\terr := registerAsDatabase()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerMetrics(); err != nil {\n\t\treturn err\n\t}\n\n\tmodule.mgr.Go(\"clean connections\", connectionCleaner)\n\tmodule.mgr.Go(\"write open dns requests\", openDNSRequestWriter)\n\tmodule.instance.Profile().EventDelete.AddCallback(\"re-attribute connections from deleted profile\", reAttributeConnections)\n\n\treturn nil\n}\n\nvar reAttributionLock sync.Mutex\n\n// reAttributeConnections finds all connections of a deleted profile and re-attributes them.\n// Expected event data: scoped profile ID.\nfunc reAttributeConnections(_ *mgr.WorkerCtx, profileID string) (bool, error) {\n\tprofileSource, profileID, ok := strings.Cut(profileID, \"/\")\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"event data does not seem to be a scoped profile ID: %v\", profileID)\n\t}\n\n\t// Hold a lock for re-attribution, to prevent simultaneous processing of the\n\t// same connections and make logging cleaner.\n\treAttributionLock.Lock()\n\tdefer reAttributionLock.Unlock()\n\n\t// Create tracing context.\n\tctx, tracer := log.AddTracer(context.Background())\n\tdefer tracer.Submit()\n\ttracer.Infof(\"network: re-attributing connections from deleted profile %s/%s\", profileSource, profileID)\n\n\t// Count and log how many connections were re-attributed.\n\tvar reAttributed int\n\n\t// Re-attribute connections.\n\tfor _, conn := range conns.clone() {\n\t\tif reAttributeConnection(ctx, conn, profileID, profileSource) {\n\t\t\treAttributed++\n\t\t\ttracer.Debugf(\"filter: re-attributed %s to %s\", conn, conn.process.PrimaryProfileID)\n\t\t}\n\t}\n\n\t// Re-attribute dns connections.\n\tfor _, conn := range dnsConns.clone() {\n\t\tif reAttributeConnection(ctx, conn, profileID, profileSource) {\n\t\t\treAttributed++\n\t\t\ttracer.Debugf(\"filter: re-attributed %s to %s\", conn, conn.process.PrimaryProfileID)\n\t\t}\n\t}\n\n\ttracer.Infof(\"filter: re-attributed %d connections\", reAttributed)\n\treturn false, nil\n}\n\nfunc reAttributeConnection(ctx context.Context, conn *Connection, profileID, profileSource string) (reAttributed bool) {\n\t// Lock the connection before checking anything to avoid a race condition with connection data collection.\n\tconn.Lock()\n\tdefer conn.Unlock()\n\n\t// Check if the connection has the profile we are looking for.\n\tswitch {\n\tcase !conn.DataIsComplete():\n\t\treturn false\n\tcase conn.ProcessContext.Profile != profileID:\n\t\treturn false\n\tcase conn.ProcessContext.Source != profileSource:\n\t\treturn false\n\t}\n\n\t// Attempt to assign new profile.\n\terr := conn.process.RefetchProfile(ctx)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Warningf(\"network: failed to refetch profile for %s: %s\", conn, err)\n\t\treturn false\n\t}\n\n\t// Set the new process context.\n\tconn.ProcessContext = getProcessContext(ctx, conn.process)\n\tconn.Save()\n\n\t// Trigger event for re-attribution.\n\tmodule.EventConnectionReattributed.Submit(conn.ID)\n\n\tlog.Tracer(ctx).Debugf(\"filter: re-attributed %s to %s\", conn, conn.process.PrimaryProfileID)\n\treturn true\n}\n\nvar (\n\tmodule     *Network\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Network module.\nfunc New(instance instance) (*Network, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Network\")\n\tmodule = &Network{\n\t\tmgr:                         m,\n\t\tinstance:                    instance,\n\t\tEventConnectionReattributed: mgr.NewEventMgr[string](ConnectionReattributedEvent, m),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tProfile() *profile.ProfileModule\n\tResolver() *resolver.ResolverModule\n\tDNSMonitor() *dnsmonitor.DNSMonitor\n}\n"
  },
  {
    "path": "service/network/multicast.go",
    "content": "package network\n\nimport (\n\t\"net\"\n\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\n// GetMulticastRequestConn searches for and returns the requesting connnection\n// of a possible multicast/broadcast response.\nfunc GetMulticastRequestConn(responseConn *Connection, responseFromNet *net.IPNet) *Connection {\n\t// Calculate the broadcast address the query would have gone to.\n\tresponseNetBroadcastIP := netutils.GetBroadcastAddress(responseFromNet.IP, responseFromNet.Mask)\n\n\t// Find requesting multicast/broadcast connection.\n\tfor _, conn := range conns.clone() {\n\t\tswitch {\n\t\tcase !conn.DataIsComplete():\n\t\t\t// Ignore connection with incomplete data.\n\t\tcase conn.Inbound:\n\t\t\t// Ignore incoming connections.\n\t\tcase conn.Ended != 0:\n\t\t\t// Ignore ended connections.\n\t\tcase conn.Entity.Protocol != responseConn.Entity.Protocol:\n\t\t\t// Ignore on protocol mismatch.\n\t\tcase conn.LocalPort != responseConn.LocalPort:\n\t\t\t// Ignore on local port mismatch.\n\t\tcase !conn.LocalIP.Equal(responseConn.LocalIP):\n\t\t\t// Ignore on local IP mismatch.\n\t\tcase !conn.Process().Equal(responseConn.Process()):\n\t\t\t// Ignore if processes mismatch.\n\t\tcase conn.Entity.IPScope == netutils.LocalMulticast &&\n\t\t\t(responseConn.Entity.IPScope == netutils.LinkLocal ||\n\t\t\t\tresponseConn.Entity.IPScope == netutils.SiteLocal):\n\t\t\t// We found a (possibly routed) multicast request that matches the response!\n\t\t\treturn conn\n\t\tcase conn.Entity.IP.Equal(responseNetBroadcastIP) &&\n\t\t\tresponseFromNet.Contains(conn.LocalIP):\n\t\t\t// We found a (link local) broadcast request that matches the response!\n\t\t\treturn conn\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/network/netutils/address.go",
    "content": "package netutils\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"strconv\"\n\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\nvar errInvalidIP = errors.New(\"invalid IP address\")\n\n// IPPortFromAddr extracts or parses the IP address and port contained in the given address.\nfunc IPPortFromAddr(addr net.Addr) (ip net.IP, port uint16, err error) {\n\t// Convert addr to IP if needed.\n\tswitch v := addr.(type) {\n\tcase *net.TCPAddr:\n\t\treturn v.IP, uint16(v.Port), nil\n\tcase *net.UDPAddr:\n\t\treturn v.IP, uint16(v.Port), nil\n\tcase *net.IPAddr:\n\t\treturn v.IP, 0, nil\n\tcase *net.UnixAddr:\n\t\treturn nil, 0, errors.New(\"unix addresses don't have IPs\")\n\tdefault:\n\t\treturn ParseIPPort(addr.String())\n\t}\n}\n\n// ProtocolFromNetwork returns the protocol from the given net, as used in the \"net\" golang stdlib.\nfunc ProtocolFromNetwork(net string) (protocol packet.IPProtocol) {\n\tswitch net {\n\tcase \"tcp\", \"tcp4\", \"tcp6\":\n\t\treturn packet.TCP\n\tcase \"udp\", \"udp4\", \"udp6\":\n\t\treturn packet.UDP\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// ParseIPPort parses a <ip>:port formatted address.\nfunc ParseIPPort(address string) (net.IP, uint16, error) {\n\tipString, portString, err := net.SplitHostPort(address)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\tip := net.ParseIP(ipString)\n\tif ip == nil {\n\t\treturn nil, 0, errInvalidIP\n\t}\n\n\tport, err := strconv.ParseUint(portString, 10, 16)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\treturn ip, uint16(port), nil\n}\n"
  },
  {
    "path": "service/network/netutils/dns.go",
    "content": "package netutils\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n)\n\nvar (\n\tcleanDomainRegex = regexp.MustCompile(\n\t\t`^` + // match beginning\n\t\t\t`(` + // start subdomain group\n\t\t\t`(xn--)?` + // idn prefix\n\t\t\t`[a-z0-9_-]{1,63}` + // main chunk\n\t\t\t`\\.` + // ending with a dot\n\t\t\t`)*` + // end subdomain group, allow any number of subdomains\n\t\t\t`(xn--)?` + // TLD idn prefix\n\t\t\t`[a-z0-9_-]{1,63}` + // TLD main chunk with at least one character (for custom ones)\n\t\t\t`\\.` + // ending with a dot\n\t\t\t`$`, // match end\n\t)\n\n\t// dnsSDDomainRegex is a lot more lax to better suit the allowed characters in DNS-SD.\n\t// Not all characters have been allowed - some special characters were\n\t// removed to reduce the general attack surface.\n\tdnsSDDomainRegex = regexp.MustCompile(\n\t\t// Start of charset selection.\n\t\t`^[` +\n\t\t\t// Printable ASCII (character code 32-127), excluding some special characters.\n\t\t\t` !#$%&()*+,\\-\\./0-9:;=?@A-Z[\\\\\\]^_\\a-z{|}~` +\n\t\t\t// Only latin characters from extended ASCII (character code 128-255).\n\t\t\t`ŠŒŽšœžŸ¡¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ` +\n\t\t\t// End of charset selection.\n\t\t\t`]*$`,\n\t)\n)\n\n// IsValidFqdn returns whether the given string is a valid fqdn.\nfunc IsValidFqdn(fqdn string) bool {\n\t// root zone\n\tif fqdn == \".\" {\n\t\treturn true\n\t}\n\n\t// check max length\n\tif len(fqdn) > 256 {\n\t\treturn false\n\t}\n\n\t// IsFqdn checks if a domain name is fully qualified.\n\tif !dns.IsFqdn(fqdn) {\n\t\treturn false\n\t}\n\n\t// Use special check for .local domains to support DNS-SD.\n\tif strings.HasSuffix(fqdn, \".local.\") {\n\t\treturn dnsSDDomainRegex.MatchString(fqdn)\n\t}\n\n\t// check with regex\n\tif !cleanDomainRegex.MatchString(fqdn) {\n\t\treturn false\n\t}\n\n\t// IsDomainName checks if s is a valid domain name, it returns the number of\n\t// labels and true, when a domain name is valid.  Note that non fully qualified\n\t// domain name is considered valid, in this case the last label is counted in\n\t// the number of labels.  When false is returned the number of labels is not\n\t// defined.  Also note that this function is extremely liberal; almost any\n\t// string is a valid domain name as the DNS is 8 bit protocol. It checks if each\n\t// label fits in 63 characters and that the entire name will fit into the 255\n\t// octet wire format limit.\n\t_, ok := dns.IsDomainName(fqdn)\n\treturn ok\n}\n\n// IPsToRRs transforms the given IPs to resource records.\nfunc IPsToRRs(domain string, ips []net.IP) ([]dns.RR, error) {\n\trecords := make([]dns.RR, 0, len(ips))\n\tvar rr dns.RR\n\tvar err error\n\n\tfor _, ip := range ips {\n\t\tif ip.To4() != nil {\n\t\t\trr, err = dns.NewRR(fmt.Sprintf(\"%s 17 IN A %s\", domain, ip))\n\t\t} else {\n\t\t\trr, err = dns.NewRR(fmt.Sprintf(\"%s 17 IN AAAA %s\", domain, ip))\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create record for %s: %w\", ip, err)\n\t\t}\n\t\trecords = append(records, rr)\n\t}\n\n\treturn records, nil\n}\n"
  },
  {
    "path": "service/network/netutils/dns_test.go",
    "content": "package netutils\n\nimport \"testing\"\n\nfunc testDomainValidity(t *testing.T, domain string, isValid bool) {\n\tt.Helper()\n\n\tif IsValidFqdn(domain) != isValid {\n\t\tt.Errorf(\"domain %s failed check: was valid=%v, expected valid=%v\", domain, IsValidFqdn(domain), isValid)\n\t}\n}\n\nfunc TestDNSValidation(t *testing.T) {\n\tt.Parallel()\n\n\t// valid\n\ttestDomainValidity(t, \".\", true)\n\ttestDomainValidity(t, \"at.\", true)\n\ttestDomainValidity(t, \"orf.at.\", true)\n\ttestDomainValidity(t, \"www.orf.at.\", true)\n\ttestDomainValidity(t, \"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.x.y.z.example.org.\", true)\n\ttestDomainValidity(t, \"a_a.com.\", true)\n\ttestDomainValidity(t, \"a-a.com.\", true)\n\ttestDomainValidity(t, \"a_a.com.\", true)\n\ttestDomainValidity(t, \"a-a.com.\", true)\n\ttestDomainValidity(t, \"xn--a.com.\", true)\n\ttestDomainValidity(t, \"xn--asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd.com.\", true)\n\n\t// maybe valid\n\ttestDomainValidity(t, \"-.com.\", true)\n\ttestDomainValidity(t, \"_.com.\", true)\n\ttestDomainValidity(t, \"a_.com.\", true)\n\ttestDomainValidity(t, \"a-.com.\", true)\n\ttestDomainValidity(t, \"_a.com.\", true)\n\ttestDomainValidity(t, \"-a.com.\", true)\n\n\t// invalid\n\ttestDomainValidity(t, \".com.\", false)\n\ttestDomainValidity(t, \".com.\", false)\n\ttestDomainValidity(t, \"xn--asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf.com.\", false)\n\ttestDomainValidity(t, \"asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf.com.\", false)\n\ttestDomainValidity(t, \"asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf.com.\", false)\n\ttestDomainValidity(t, \"asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.as.com.\", false)\n\n\t// real world examples\n\ttestDomainValidity(t, \"iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com.\", true)\n}\n"
  },
  {
    "path": "service/network/netutils/ip.go",
    "content": "package netutils\n\nimport \"net\"\n\n// IPScope is the scope of the IP address.\ntype IPScope int8\n\n// Defined IP Scopes.\nconst (\n\tInvalid IPScope = iota - 1\n\tUndefined\n\tHostLocal\n\tLinkLocal\n\tSiteLocal\n\tGlobal\n\tLocalMulticast\n\tGlobalMulticast\n)\n\n// ClassifyIP returns the network scope of the given IP address.\n// Deprecated: Please use the new GetIPScope instead.\nfunc ClassifyIP(ip net.IP) IPScope {\n\treturn GetIPScope(ip)\n}\n\n// GetIPScope returns the network scope of the given IP address.\nfunc GetIPScope(ip net.IP) IPScope { //nolint:gocognit\n\tif ip4 := ip.To4(); ip4 != nil {\n\t\t// IPv4\n\t\tswitch {\n\t\tcase ip4[0] == 0 && ip4[1] == 0 && ip4[2] == 0 && ip4[3] == 0:\n\t\t\t// 0.0.0.0/32\n\t\t\treturn LocalMulticast // Used as source for L2 based protocols with no L3 addressing.\n\t\tcase ip4[0] == 0:\n\t\t\t// 0.0.0.0/8\n\t\t\treturn Invalid\n\t\tcase ip4[0] == 10:\n\t\t\t// 10.0.0.0/8 (RFC1918)\n\t\t\treturn SiteLocal\n\t\tcase ip4[0] == 100 && ip4[1]&0b11000000 == 64:\n\t\t\t// 100.64.0.0/10 (RFC6598)\n\t\t\treturn SiteLocal\n\t\tcase ip4[0] == 127:\n\t\t\t// 127.0.0.0/8 (RFC1918)\n\t\t\treturn HostLocal\n\t\tcase ip4[0] == 169 && ip4[1] == 254:\n\t\t\t// 169.254.0.0/16 (RFC3927)\n\t\t\treturn LinkLocal\n\t\tcase ip4[0] == 172 && ip4[1]&0b11110000 == 16:\n\t\t\t// 172.16.0.0/12 (RFC1918)\n\t\t\treturn SiteLocal\n\t\tcase ip4[0] == 192 && ip4[1] == 0 && ip4[2] == 2:\n\t\t\t// 192.0.2.0/24 (TEST-NET-1, RFC5737)\n\t\t\treturn Invalid\n\t\tcase ip4[0] == 192 && ip4[1] == 168:\n\t\t\t// 192.168.0.0/16 (RFC1918)\n\t\t\treturn SiteLocal\n\t\tcase ip4[0] == 198 && ip4[1] == 51 && ip4[2] == 100:\n\t\t\t// 198.51.100.0/24 (TEST-NET-2, RFC5737)\n\t\t\treturn Invalid\n\t\tcase ip4[0] == 203 && ip4[1] == 0 && ip4[2] == 113:\n\t\t\t// 203.0.113.0/24 (TEST-NET-3, RFC5737)\n\t\t\treturn Invalid\n\t\tcase ip4[0] == 224:\n\t\t\t// 224.0.0.0/8 (RFC5771)\n\t\t\treturn LocalMulticast\n\t\tcase ip4[0] == 233 && ip4[1] == 252 && ip4[2] == 0:\n\t\t\t// 233.252.0.0/24 (MCAST-TEST-NET; RFC5771, RFC6676)\n\t\t\treturn Invalid\n\t\tcase ip4[0] >= 225 && ip4[0] <= 238:\n\t\t\t// 225.0.0.0/8 - 238.0.0.0/8 (RFC5771)\n\t\t\treturn GlobalMulticast\n\t\tcase ip4[0] == 239:\n\t\t\t// 239.0.0.0/8 (RFC2365)\n\t\t\treturn LocalMulticast\n\t\tcase ip4[0] == 255 && ip4[1] == 255 && ip4[2] == 255 && ip4[3] == 255:\n\t\t\t// 255.255.255.255/32\n\t\t\treturn LocalMulticast\n\t\tcase ip4[0] >= 240:\n\t\t\t// 240.0.0.0/8 - 255.0.0.0/8 (minus 255.255.255.255/32)\n\t\t\treturn Invalid\n\t\tdefault:\n\t\t\treturn Global\n\t\t}\n\t} else if len(ip) == net.IPv6len {\n\t\t// IPv6\n\n\t\t// TODO: Add IPv6 RFC5771 test / doc networks\n\t\t// 2001:db8::/32\n\t\t// 3fff::/20\n\t\tswitch {\n\t\tcase ip.Equal(net.IPv6zero):\n\t\t\treturn Invalid\n\t\tcase ip.Equal(net.IPv6loopback):\n\t\t\treturn HostLocal\n\t\tcase ip[0]&0xfe == 0xfc:\n\t\t\t// fc00::/7\n\t\t\treturn SiteLocal\n\t\tcase ip[0] == 0xfe && ip[1]&0xc0 == 0x80:\n\t\t\t// fe80::/10\n\t\t\treturn LinkLocal\n\t\tcase ip[0] == 0xff && ip[1] <= 0x05:\n\t\t\t// ff00::/16 - ff05::/16\n\t\t\treturn LocalMulticast\n\t\tcase ip[0] == 0xff:\n\t\t\t// other ff00::/8\n\t\t\treturn GlobalMulticast\n\t\tdefault:\n\t\t\treturn Global\n\t\t}\n\t}\n\treturn Invalid\n}\n\n// IsLocalhost returns whether the IP refers to the host itself.\nfunc (scope IPScope) IsLocalhost() bool {\n\treturn scope == HostLocal\n}\n\n// IsLAN returns true if the scope is site-local or link-local.\nfunc (scope IPScope) IsLAN() bool {\n\tswitch scope { //nolint:exhaustive // Looking for something specific.\n\tcase SiteLocal, LinkLocal, LocalMulticast:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// IsGlobal returns true if the scope is global.\nfunc (scope IPScope) IsGlobal() bool {\n\tswitch scope { //nolint:exhaustive // Looking for something specific.\n\tcase Global, GlobalMulticast:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// GetBroadcastAddress returns the broadcast address of the given IP and network mask.\n// If a mixed IPv4/IPv6 input is given, it returns nil.\nfunc GetBroadcastAddress(ip net.IP, netMask net.IPMask) net.IP {\n\t// Convert to standard v4.\n\tif ip4 := ip.To4(); ip4 != nil {\n\t\tip = ip4\n\t}\n\tmask := net.IP(netMask)\n\tif ip4Mask := mask.To4(); ip4Mask != nil {\n\t\tmask = ip4Mask\n\t}\n\n\t// Check for mixed v4/v6 input.\n\tif len(ip) != len(mask) {\n\t\treturn nil\n\t}\n\n\t// Merge to broadcast address\n\tn := len(ip)\n\tbroadcastAddress := make(net.IP, n)\n\tfor i := range n {\n\t\tbroadcastAddress[i] = ip[i] | ^mask[i]\n\t}\n\treturn broadcastAddress\n}\n"
  },
  {
    "path": "service/network/netutils/ip_test.go",
    "content": "package netutils\n\nimport (\n\t\"net\"\n\t\"testing\"\n)\n\nfunc TestIPScope(t *testing.T) {\n\tt.Parallel()\n\n\ttestScope(t, net.IPv4(71, 87, 113, 211), Global)\n\ttestScope(t, net.IPv4(127, 0, 0, 1), HostLocal)\n\ttestScope(t, net.IPv4(127, 255, 255, 1), HostLocal)\n\ttestScope(t, net.IPv4(192, 168, 172, 24), SiteLocal)\n\ttestScope(t, net.IPv4(172, 15, 1, 1), Global)\n\ttestScope(t, net.IPv4(172, 16, 1, 1), SiteLocal)\n\ttestScope(t, net.IPv4(172, 31, 1, 1), SiteLocal)\n\ttestScope(t, net.IPv4(172, 32, 1, 1), Global)\n}\n\nfunc testScope(t *testing.T, ip net.IP, expectedScope IPScope) {\n\tt.Helper()\n\n\tc := GetIPScope(ip)\n\tif c != expectedScope {\n\t\tt.Errorf(\"%s is %s, expected %s\", ip, scopeName(c), scopeName(expectedScope))\n\t}\n}\n\nfunc scopeName(c IPScope) string {\n\tswitch c {\n\tcase Invalid:\n\t\treturn \"invalid\"\n\tcase Undefined:\n\t\treturn \"undefined\"\n\tcase HostLocal:\n\t\treturn \"hostLocal\"\n\tcase LinkLocal:\n\t\treturn \"linkLocal\"\n\tcase SiteLocal:\n\t\treturn \"siteLocal\"\n\tcase Global:\n\t\treturn \"global\"\n\tcase LocalMulticast:\n\t\treturn \"localMulticast\"\n\tcase GlobalMulticast:\n\t\treturn \"globalMulticast\"\n\tdefault:\n\t\treturn \"undefined\"\n\t}\n}\n"
  },
  {
    "path": "service/network/netutils/tcpassembly.go",
    "content": "package netutils\n\nimport (\n\t\"sync\"\n\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacket/tcpassembly\"\n)\n\n// SimpleStreamAssemblerManager is a simple manager for github.com/google/gopacket/tcpassembly.\ntype SimpleStreamAssemblerManager struct {\n\tInitLock      sync.Mutex\n\tlastAssembler *SimpleStreamAssembler\n}\n\n// New returns a new stream assembler.\nfunc (m *SimpleStreamAssemblerManager) New(net, transport gopacket.Flow) tcpassembly.Stream {\n\tassembler := new(SimpleStreamAssembler)\n\tm.lastAssembler = assembler\n\treturn assembler\n}\n\n// GetLastAssembler returns the newest created stream assembler.\nfunc (m *SimpleStreamAssemblerManager) GetLastAssembler() *SimpleStreamAssembler {\n\treturn m.lastAssembler\n}\n\n// SimpleStreamAssembler is a simple assembler for github.com/google/gopacket/tcpassembly.\ntype SimpleStreamAssembler struct {\n\tCumulated    []byte\n\tCumulatedLen int\n\tComplete     bool\n}\n\n// NewSimpleStreamAssembler returns a new SimpleStreamAssembler.\nfunc NewSimpleStreamAssembler() *SimpleStreamAssembler {\n\treturn &SimpleStreamAssembler{}\n}\n\n// Reassembled implements tcpassembly.Stream's Reassembled function.\nfunc (a *SimpleStreamAssembler) Reassembled(reassembly []tcpassembly.Reassembly) {\n\tfor _, entry := range reassembly {\n\t\ta.Cumulated = append(a.Cumulated, entry.Bytes...)\n\t}\n\ta.CumulatedLen = len(a.Cumulated)\n}\n\n// ReassemblyComplete implements tcpassembly.Stream's ReassemblyComplete function.\nfunc (a *SimpleStreamAssembler) ReassemblyComplete() {\n\ta.Complete = true\n}\n"
  },
  {
    "path": "service/network/packet/bandwidth.go",
    "content": "package packet\n\nimport \"fmt\"\n\n// BandwidthUpdate holds an update to the seen bandwidth of a connection.\ntype BandwidthUpdate struct {\n\tConnID        string\n\tBytesReceived uint64\n\tBytesSent     uint64\n\tMethod        BandwidthUpdateMethod\n}\n\n// BandwidthUpdateMethod defines how the bandwidth data of a bandwidth update should be interpreted.\ntype BandwidthUpdateMethod uint8\n\n// Bandwidth Update Methods.\nconst (\n\tAbsolute BandwidthUpdateMethod = iota\n\tAdditive\n)\n\nfunc (bu *BandwidthUpdate) String() string {\n\treturn fmt.Sprintf(\"%s: %dB recv | %dB sent [%s]\", bu.ConnID, bu.BytesReceived, bu.BytesSent, bu.Method)\n}\n\nfunc (bum BandwidthUpdateMethod) String() string {\n\tswitch bum {\n\tcase Absolute:\n\t\treturn \"absolute\"\n\tcase Additive:\n\t\treturn \"additive\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n"
  },
  {
    "path": "service/network/packet/const.go",
    "content": "package packet\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// Basic Types.\ntype (\n\t// IPVersion represents an IP version.\n\tIPVersion uint8\n\t// IPProtocol represents an IP protocol.\n\tIPProtocol uint8\n\t// Verdict describes the decision on a packet.\n\tVerdict uint8\n)\n\n// Basic Constants.\nconst (\n\tIPv4 = IPVersion(4)\n\tIPv6 = IPVersion(6)\n\n\tInBound  = true\n\tOutBound = false\n\n\tICMP    = IPProtocol(1)\n\tIGMP    = IPProtocol(2)\n\tTCP     = IPProtocol(6)\n\tUDP     = IPProtocol(17)\n\tICMPv6  = IPProtocol(58)\n\tUDPLite = IPProtocol(136)\n\tRAW     = IPProtocol(255)\n\n\tAnyHostInternalProtocol61 = IPProtocol(61)\n)\n\n// Verdicts.\nconst (\n\tDROP Verdict = iota\n\tBLOCK\n\tACCEPT\n\tSTOLEN\n\tQUEUE\n\tREPEAT\n\tSTOP\n)\n\n// ErrFailedToLoadPayload is returned by GetPayload if it failed for an unspecified reason, or is not implemented on the current system.\nvar ErrFailedToLoadPayload = errors.New(\"could not load packet payload\")\n\n// ByteSize returns the byte size of the ip (IPv4 = 4 bytes, IPv6 = 16).\nfunc (v IPVersion) ByteSize() int {\n\tswitch v {\n\tcase IPv4:\n\t\treturn 4\n\tcase IPv6:\n\t\treturn 16\n\t}\n\treturn 0\n}\n\n// String returns the string representation of the IP version: \"IPv4\" or \"IPv6\".\nfunc (v IPVersion) String() string {\n\tswitch v {\n\tcase IPv4:\n\t\treturn \"IPv4\"\n\tcase IPv6:\n\t\treturn \"IPv6\"\n\t}\n\treturn fmt.Sprintf(\"<unknown ip version, %d>\", uint8(v))\n}\n\n// String returns the string representation (abbreviation) of the protocol.\nfunc (p IPProtocol) String() string {\n\tswitch p {\n\tcase RAW:\n\t\treturn \"RAW\"\n\tcase TCP:\n\t\treturn \"TCP\"\n\tcase UDP:\n\t\treturn \"UDP\"\n\tcase UDPLite:\n\t\treturn \"UDPLite\"\n\tcase ICMP:\n\t\treturn \"ICMP\"\n\tcase ICMPv6:\n\t\treturn \"ICMPv6\"\n\tcase IGMP:\n\t\treturn \"IGMP\"\n\tcase AnyHostInternalProtocol61:\n\t\tfallthrough\n\tdefault:\n\t\treturn fmt.Sprintf(\"<unknown protocol, %d>\", uint8(p))\n\t}\n}\n\n// String returns the string representation of the verdict.\nfunc (v Verdict) String() string {\n\tswitch v {\n\tcase DROP:\n\t\treturn \"DROP\"\n\tcase BLOCK:\n\t\treturn \"BLOCK\"\n\tcase ACCEPT:\n\t\treturn \"ACCEPT\"\n\tcase STOLEN:\n\t\treturn \"STOLEN\"\n\tcase QUEUE:\n\t\treturn \"QUEUE\"\n\tcase REPEAT:\n\t\treturn \"REPEAT\"\n\tcase STOP:\n\t\treturn \"STOP\"\n\tdefault:\n\t\treturn fmt.Sprintf(\"<unsupported verdict, %d>\", uint8(v))\n\t}\n}\n"
  },
  {
    "path": "service/network/packet/info_only.go",
    "content": "package packet\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// InfoPacket does not represent an actual packet, but only holds metadata.\n// Implements the packet.Packet interface.\ntype InfoPacket struct {\n\tBase\n}\n\n// NewInfoPacket returns a new InfoPacket with the given info.\nfunc NewInfoPacket(info Info) *InfoPacket {\n\treturn &InfoPacket{\n\t\tBase{\n\t\t\tinfo: info,\n\t\t},\n\t}\n}\n\n// InfoOnly returns whether the packet is informational only and does not\n// represent an actual packet.\nfunc (pkt *InfoPacket) InfoOnly() bool {\n\treturn true\n}\n\n// LoadPacketData does nothing on Linux, as data is always fully parsed.\nfunc (pkt *InfoPacket) LoadPacketData() error {\n\treturn fmt.Errorf(\"%w: info-only packet\", ErrFailedToLoadPayload)\n}\n\n// ErrInfoOnlyPacket is returned for unsupported operations on an info-only packet.\nvar ErrInfoOnlyPacket = errors.New(\"info-only packet\")\n\n// Accept does nothing on an info-only packet.\nfunc (pkt *InfoPacket) Accept() error {\n\treturn ErrInfoOnlyPacket\n}\n\n// Block does nothing on an info-only packet.\nfunc (pkt *InfoPacket) Block() error {\n\treturn ErrInfoOnlyPacket\n}\n\n// Drop does nothing on an info-only packet.\nfunc (pkt *InfoPacket) Drop() error {\n\treturn ErrInfoOnlyPacket\n}\n\n// PermanentAccept does nothing on an info-only packet.\nfunc (pkt *InfoPacket) PermanentAccept() error {\n\treturn ErrInfoOnlyPacket\n}\n\n// PermanentBlock does nothing on an info-only packet.\nfunc (pkt *InfoPacket) PermanentBlock() error {\n\treturn ErrInfoOnlyPacket\n}\n\n// PermanentDrop does nothing on an info-only packet.\nfunc (pkt *InfoPacket) PermanentDrop() error {\n\treturn ErrInfoOnlyPacket\n}\n\n// RerouteToNameserver does nothing on an info-only packet.\nfunc (pkt *InfoPacket) RerouteToNameserver() error {\n\treturn ErrInfoOnlyPacket\n}\n\n// RerouteToTunnel does nothing on an info-only packet.\nfunc (pkt *InfoPacket) RerouteToTunnel() error {\n\treturn ErrInfoOnlyPacket\n}\n\nvar _ Packet = &InfoPacket{}\n"
  },
  {
    "path": "service/network/packet/packet.go",
    "content": "package packet\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\n\t\"github.com/google/gopacket\"\n)\n\n// Base is a base structure for satisfying the Packet interface.\ntype Base struct {\n\tctx        context.Context\n\tinfo       Info\n\tconnID     string\n\tlayers     gopacket.Packet\n\tlayer3Data []byte\n\tlayer5Data []byte\n}\n\n// FastTrackedByIntegration returns whether the packet has been fast-track\n// accepted by the OS integration.\nfunc (pkt *Base) FastTrackedByIntegration() bool {\n\treturn false\n}\n\n// InfoOnly returns whether the packet is informational only and does not\n// represent an actual packet.\nfunc (pkt *Base) InfoOnly() bool {\n\treturn false\n}\n\n// ExpectInfo returns whether the next packet is expected to be informational only.\nfunc (pkt *Base) ExpectInfo() bool {\n\treturn false\n}\n\n// SetCtx sets the packet context.\nfunc (pkt *Base) SetCtx(ctx context.Context) {\n\tpkt.ctx = ctx\n}\n\n// Ctx returns the packet context.\nfunc (pkt *Base) Ctx() context.Context {\n\treturn pkt.ctx\n}\n\n// Info returns the packet Info.\nfunc (pkt *Base) Info() *Info {\n\treturn &pkt.info\n}\n\n// SetPacketInfo sets a new packet Info. This must only used when initializing the packet structure.\nfunc (pkt *Base) SetPacketInfo(packetInfo Info) {\n\tpkt.info = packetInfo\n}\n\n// SetInbound sets a the packet direction to inbound. This must only used when initializing the packet structure.\nfunc (pkt *Base) SetInbound() {\n\tpkt.info.Inbound = true\n}\n\n// SetOutbound sets a the packet direction to outbound. This must only used when initializing the packet structure.\nfunc (pkt *Base) SetOutbound() {\n\tpkt.info.Inbound = false\n}\n\n// IsInbound checks if the packet is inbound.\nfunc (pkt *Base) IsInbound() bool {\n\treturn pkt.info.Inbound\n}\n\n// IsOutbound checks if the packet is outbound.\nfunc (pkt *Base) IsOutbound() bool {\n\treturn !pkt.info.Inbound\n}\n\n// HasPorts checks if the packet has a protocol that uses ports.\nfunc (pkt *Base) HasPorts() bool {\n\tswitch pkt.info.Protocol {\n\tcase TCP:\n\t\treturn true\n\tcase UDP, UDPLite:\n\t\treturn true\n\tcase ICMP, ICMPv6, IGMP, RAW, AnyHostInternalProtocol61:\n\t\tfallthrough\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// LoadPacketData loads packet data from the integration, if not yet done.\nfunc (pkt *Base) LoadPacketData() error {\n\treturn ErrFailedToLoadPayload\n}\n\n// Layers returns the parsed layer data.\nfunc (pkt *Base) Layers() gopacket.Packet {\n\treturn pkt.layers\n}\n\n// Raw returns the raw Layer 3 Network Data.\nfunc (pkt *Base) Raw() []byte {\n\treturn pkt.layer3Data\n}\n\n// Payload returns the raw Layer 5 Network Data.\nfunc (pkt *Base) Payload() []byte {\n\treturn pkt.layer5Data\n}\n\n// GetConnectionID returns the link ID for this packet.\nfunc (pkt *Base) GetConnectionID() string {\n\tif pkt.connID == \"\" {\n\t\tpkt.connID = pkt.info.CreateConnectionID()\n\t}\n\treturn pkt.connID\n}\n\n// MatchesAddress checks if a the packet matches a given endpoint (remote or local) in protocol, network and port.\n//\n// Comparison matrix:\n//\n// ======  IN   OUT\n//\n// Local   Dst  Src\n// Remote  Src  Dst\n// .\nfunc (pkt *Base) MatchesAddress(remote bool, protocol IPProtocol, network *net.IPNet, port uint16) bool {\n\tif pkt.info.Protocol != protocol {\n\t\treturn false\n\t}\n\tif pkt.info.Inbound != remote {\n\t\tif !network.Contains(pkt.info.Src) {\n\t\t\treturn false\n\t\t}\n\t\tif pkt.info.SrcPort != port {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\tif !network.Contains(pkt.info.Dst) {\n\t\t\treturn false\n\t\t}\n\t\tif pkt.info.DstPort != port {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// MatchesIP checks if a the packet matches a given endpoint (remote or local) IP.\n//\n// Comparison matrix:\n//\n// ======  IN   OUT\n//\n// Local   Dst  Src\n// Remote  Src  Dst\n// .\nfunc (pkt *Base) MatchesIP(endpoint bool, network *net.IPNet) bool {\n\tif pkt.info.Inbound != endpoint {\n\t\tif network.Contains(pkt.info.Src) {\n\t\t\treturn true\n\t\t}\n\t} else {\n\t\tif network.Contains(pkt.info.Dst) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// FORMATTING\n\nfunc (pkt *Base) String() string {\n\treturn pkt.FmtPacket()\n}\n\n// FmtPacket returns the most important information about the packet as a string.\nfunc (pkt *Base) FmtPacket() string {\n\tif pkt.info.Protocol == TCP || pkt.info.Protocol == UDP {\n\t\tif pkt.info.Inbound {\n\t\t\treturn fmt.Sprintf(\"IN %s %s:%d <-> %s:%d\", pkt.info.Protocol, pkt.info.Dst, pkt.info.DstPort, pkt.info.Src, pkt.info.SrcPort)\n\t\t}\n\t\treturn fmt.Sprintf(\"OUT %s %s:%d <-> %s:%d\", pkt.info.Protocol, pkt.info.Src, pkt.info.SrcPort, pkt.info.Dst, pkt.info.DstPort)\n\t}\n\tif pkt.info.Inbound {\n\t\treturn fmt.Sprintf(\"IN %s %s <-> %s\", pkt.info.Protocol, pkt.info.Dst, pkt.info.Src)\n\t}\n\treturn fmt.Sprintf(\"OUT %s %s <-> %s\", pkt.info.Protocol, pkt.info.Src, pkt.info.Dst)\n}\n\n// FmtProtocol returns the protocol as a string.\nfunc (pkt *Base) FmtProtocol() string {\n\treturn pkt.info.Protocol.String()\n}\n\n// FmtRemoteIP returns the remote IP address as a string.\nfunc (pkt *Base) FmtRemoteIP() string {\n\tif pkt.info.Inbound {\n\t\treturn pkt.info.Src.String()\n\t}\n\treturn pkt.info.Dst.String()\n}\n\n// FmtRemotePort returns the remote port as a string.\nfunc (pkt *Base) FmtRemotePort() string {\n\tif pkt.info.SrcPort != 0 {\n\t\tif pkt.info.Inbound {\n\t\t\treturn strconv.FormatUint(uint64(pkt.info.SrcPort), 10)\n\t\t}\n\t\treturn strconv.FormatUint(uint64(pkt.info.DstPort), 10)\n\t}\n\treturn \"-\"\n}\n\n// FmtRemoteAddress returns the full remote address (protocol, IP, port) as a string.\nfunc (pkt *Base) FmtRemoteAddress() string {\n\treturn fmt.Sprintf(\"%s:%s:%s\", pkt.info.Protocol.String(), pkt.FmtRemoteIP(), pkt.FmtRemotePort())\n}\n\n// Packet is an interface to a network packet to provide object behavior the same across all systems.\ntype Packet interface {\n\t// Verdicts.\n\tAccept() error\n\tBlock() error\n\tDrop() error\n\tPermanentAccept() error\n\tPermanentBlock() error\n\tPermanentDrop() error\n\tRerouteToNameserver() error\n\tRerouteToTunnel() error\n\tFastTrackedByIntegration() bool\n\tInfoOnly() bool\n\tExpectInfo() bool\n\n\t// Info.\n\tSetCtx(ctx context.Context)\n\tCtx() context.Context\n\tInfo() *Info\n\tSetPacketInfo(info Info)\n\tIsInbound() bool\n\tIsOutbound() bool\n\tSetInbound()\n\tSetOutbound()\n\tHasPorts() bool\n\tGetConnectionID() string\n\n\t// Payload.\n\tLoadPacketData() error\n\tLayers() gopacket.Packet\n\tRaw() []byte\n\tPayload() []byte\n\n\t// Matching.\n\tMatchesAddress(remote bool, protocol IPProtocol, network *net.IPNet, port uint16) bool\n\tMatchesIP(endpoint bool, network *net.IPNet) bool\n\n\t// Formatting.\n\tString() string\n\tFmtPacket() string\n\tFmtProtocol() string\n\tFmtRemoteIP() string\n\tFmtRemotePort() string\n\tFmtRemoteAddress() string\n}\n"
  },
  {
    "path": "service/network/packet/packetinfo.go",
    "content": "package packet\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n)\n\n// Info holds IP and TCP/UDP header information.\ntype Info struct {\n\tInbound  bool\n\tInTunnel bool\n\n\tVersion          IPVersion\n\tProtocol         IPProtocol\n\tSrcPort, DstPort uint16\n\tSrc, Dst         net.IP\n\n\tPID    int\n\tSeenAt time.Time\n}\n\n// LocalIP returns the local IP of the packet.\nfunc (pi *Info) LocalIP() net.IP {\n\tif pi.Inbound {\n\t\treturn pi.Dst\n\t}\n\treturn pi.Src\n}\n\n// RemoteIP returns the remote IP of the packet.\nfunc (pi *Info) RemoteIP() net.IP {\n\tif pi.Inbound {\n\t\treturn pi.Src\n\t}\n\treturn pi.Dst\n}\n\n// LocalPort returns the local port of the packet.\nfunc (pi *Info) LocalPort() uint16 {\n\tif pi.Inbound {\n\t\treturn pi.DstPort\n\t}\n\treturn pi.SrcPort\n}\n\n// RemotePort returns the remote port of the packet.\nfunc (pi *Info) RemotePort() uint16 {\n\tif pi.Inbound {\n\t\treturn pi.SrcPort\n\t}\n\treturn pi.DstPort\n}\n\n// CreateConnectionID creates a connection ID.\n// In most circumstances, this method should not be used directly, but\n// packet.GetConnectionID() should be called instead.\nfunc (pi *Info) CreateConnectionID() string {\n\treturn CreateConnectionID(pi.Protocol, pi.Src, pi.SrcPort, pi.Dst, pi.DstPort, pi.Inbound)\n}\n\n// CreateConnectionID creates a connection ID.\nfunc CreateConnectionID(protocol IPProtocol, src net.IP, srcPort uint16, dst net.IP, dstPort uint16, inbound bool) string {\n\t// TODO: make this ID not depend on the packet direction for better support for forwarded packets.\n\tif protocol == TCP || protocol == UDP {\n\t\tif inbound {\n\t\t\treturn fmt.Sprintf(\"%d-%s-%d-%s-%d\", protocol, dst, dstPort, src, srcPort)\n\t\t}\n\t\treturn fmt.Sprintf(\"%d-%s-%d-%s-%d\", protocol, src, srcPort, dst, dstPort)\n\t}\n\n\tif inbound {\n\t\treturn fmt.Sprintf(\"%d-%s-%s\", protocol, dst, src)\n\t}\n\treturn fmt.Sprintf(\"%d-%s-%s\", protocol, src, dst)\n}\n"
  },
  {
    "path": "service/network/packet/parse.go",
    "content": "package packet\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacket/layers\"\n)\n\nvar layerType2IPProtocol map[gopacket.LayerType]IPProtocol\n\nfunc genIPProtocolFromLayerType() {\n\tlayerType2IPProtocol = make(map[gopacket.LayerType]IPProtocol)\n\tfor k, v := range layers.IPProtocolMetadata {\n\t\tlayerType2IPProtocol[v.LayerType] = IPProtocol(k)\n\t}\n}\n\nfunc parseIPv4(packet gopacket.Packet, info *Info) error {\n\tif ipv4, ok := packet.NetworkLayer().(*layers.IPv4); ok {\n\t\tinfo.Version = IPv4\n\t\tinfo.Src = ipv4.SrcIP\n\t\tinfo.Dst = ipv4.DstIP\n\t\tinfo.Protocol = IPProtocol(ipv4.Protocol)\n\t}\n\treturn nil\n}\n\nfunc parseIPv6(packet gopacket.Packet, info *Info) error {\n\tif ipv6, ok := packet.NetworkLayer().(*layers.IPv6); ok {\n\t\tinfo.Version = IPv6\n\t\tinfo.Src = ipv6.SrcIP\n\t\tinfo.Dst = ipv6.DstIP\n\t\t// we set Protocol to NextHeader as a fallback. If TCP or\n\t\t// UDP layers are detected (somewhere in the list of options)\n\t\t// the Protocol field is adjusted correctly.\n\t\tinfo.Protocol = IPProtocol(ipv6.NextHeader)\n\t}\n\treturn nil\n}\n\nfunc parseTCP(packet gopacket.Packet, info *Info) error {\n\tif tcp, ok := packet.TransportLayer().(*layers.TCP); ok {\n\t\tinfo.Protocol = TCP\n\t\tinfo.SrcPort = uint16(tcp.SrcPort)\n\t\tinfo.DstPort = uint16(tcp.DstPort)\n\t}\n\treturn nil\n}\n\nfunc parseUDP(packet gopacket.Packet, info *Info) error {\n\tif udp, ok := packet.TransportLayer().(*layers.UDP); ok {\n\t\tinfo.Protocol = UDP\n\t\tinfo.SrcPort = uint16(udp.SrcPort)\n\t\tinfo.DstPort = uint16(udp.DstPort)\n\t}\n\treturn nil\n}\n\n/*\nfunc parseUDPLite(packet gopacket.Packet, info *Info) error {\n\tif udpLite, ok := packet.TransportLayer().(*layers.UDPLite); ok {\n\t\tinfo.Protocol = UDPLite\n\t\tinfo.SrcPort = uint16(udpLite.SrcPort)\n\t\tinfo.DstPort = uint16(udpLite.DstPort)\n\t}\n\treturn nil\n}\n*/\n\nfunc parseICMPv4(packet gopacket.Packet, info *Info) error {\n\tif icmp, ok := packet.Layer(layers.LayerTypeICMPv4).(*layers.ICMPv4); ok {\n\t\tinfo.Protocol = ICMP\n\t\t_ = icmp\n\t}\n\treturn nil\n}\n\nfunc parseICMPv6(packet gopacket.Packet, info *Info) error {\n\tif icmp6, ok := packet.Layer(layers.LayerTypeICMPv6).(*layers.ICMPv6); ok {\n\t\tinfo.Protocol = ICMPv6\n\t\t_ = icmp6\n\t}\n\treturn nil\n}\n\nfunc parseIGMP(packet gopacket.Packet, info *Info) error {\n\t// gopacket uses LayerTypeIGMP for v1, v2 and v3 and may thus\n\t// either return layers.IGMP or layers.IGMPv1or2\n\tif layer := packet.Layer(layers.LayerTypeIGMP); layer != nil {\n\t\tinfo.Protocol = IGMP\n\t}\n\treturn nil\n}\n\nfunc checkError(packet gopacket.Packet, info *Info) error {\n\t// Check for known unparseable before checking the error layer.\n\tif info.Protocol == AnyHostInternalProtocol61 {\n\t\treturn nil\n\t}\n\n\tif err := packet.ErrorLayer(); err != nil {\n\t\treturn err.Error()\n\t}\n\treturn nil\n}\n\n// ParseLayer3 parses an IP packet and saves the information in the given packet object.\nfunc ParseLayer3(packetData []byte, pktBase *Base) (err error) {\n\tif len(packetData) == 0 {\n\t\treturn errors.New(\"empty packet\")\n\t}\n\n\tpktBase.layer3Data = packetData\n\n\tipVersion := packetData[0] >> 4\n\tvar networkLayerType gopacket.LayerType\n\n\tswitch ipVersion {\n\tcase 4:\n\t\tnetworkLayerType = layers.LayerTypeIPv4\n\tcase 6:\n\t\tnetworkLayerType = layers.LayerTypeIPv6\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown IP version or network protocol: %02x\", ipVersion)\n\t}\n\n\tpacket := gopacket.NewPacket(packetData, networkLayerType, gopacket.DecodeOptions{\n\t\tLazy:   true,\n\t\tNoCopy: true,\n\t})\n\n\tavailableDecoders := []func(gopacket.Packet, *Info) error{\n\t\tparseIPv4,\n\t\tparseIPv6,\n\t\tparseTCP,\n\t\tparseUDP,\n\t\t// parseUDPLite, // We don't yet support udplite.\n\t\tparseICMPv4,\n\t\tparseICMPv6,\n\t\tparseIGMP,\n\t\tcheckError,\n\t}\n\n\tfor _, dec := range availableDecoders {\n\t\tif err := dec(packet, pktBase.Info()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tpktBase.layers = packet\n\tif transport := packet.TransportLayer(); transport != nil {\n\t\tpktBase.layer5Data = transport.LayerPayload()\n\t}\n\treturn nil\n}\n\n// ParseLayer4 parses an layer 4 packet and saves the information in the given packet object.\nfunc ParseLayer4(packetData []byte, pktBase *Base) (err error) {\n\tif len(packetData) == 0 {\n\t\treturn errors.New(\"empty packet\")\n\t}\n\n\tvar layer gopacket.LayerType\n\tswitch pktBase.info.Protocol {\n\tcase ICMP:\n\t\tlayer = layers.LayerTypeICMPv4\n\tcase IGMP:\n\t\tlayer = layers.LayerTypeIGMP\n\tcase TCP:\n\t\tlayer = layers.LayerTypeTCP\n\tcase UDP:\n\t\tlayer = layers.LayerTypeUDP\n\tcase ICMPv6:\n\t\tlayer = layers.LayerTypeICMPv6\n\tcase UDPLite:\n\t\treturn fmt.Errorf(\"UDPLite not supported\")\n\tcase RAW:\n\t\treturn fmt.Errorf(\"RAW protocol not supported\")\n\tcase AnyHostInternalProtocol61:\n\t\treturn fmt.Errorf(\"AnyHostInternalProtocol61 protocol not supported\")\n\tdefault:\n\t\treturn fmt.Errorf(\"protocol not supported\")\n\t}\n\n\tpacket := gopacket.NewPacket(packetData, layer, gopacket.DecodeOptions{\n\t\tLazy:   true,\n\t\tNoCopy: true,\n\t})\n\n\tavailableDecoders := []func(gopacket.Packet, *Info) error{\n\t\tparseTCP,\n\t\tparseUDP,\n\t\t// parseUDPLite, // We don't yet support udplite.\n\t\tparseICMPv4,\n\t\tparseICMPv6,\n\t\tparseIGMP,\n\t\tcheckError,\n\t}\n\n\tfor _, dec := range availableDecoders {\n\t\tif err := dec(packet, pktBase.Info()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tpktBase.layers = packet\n\tif transport := packet.TransportLayer(); transport != nil {\n\t\tpktBase.layer5Data = transport.LayerPayload()\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tgenIPProtocolFromLayerType()\n}\n"
  },
  {
    "path": "service/network/ports.go",
    "content": "package network\n\nimport (\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n)\n\n// GetUnusedLocalPort returns a local port of the specified protocol that is\n// currently unused and is unlikely to be used within the next seconds.\nfunc GetUnusedLocalPort(protocol uint8) (port uint16, ok bool) {\n\tallConns := conns.clone()\n\ttries := 1000\n\n\t// Try up to 1000 times to find an unused port.\nnextPort:\n\tfor i := range tries {\n\t\t// Generate random port between 10000 and 65535\n\t\trN, err := rng.Number(55535)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"network: failed to generate random port: %s\", err)\n\t\t\treturn 0, false\n\t\t}\n\t\tport := uint16(rN + 10000)\n\n\t\t// Shrink range when we chew through the tries.\n\t\tportRangeStart := port - 10\n\n\t\t// Check if the generated port is unused.\n\tnextConnection:\n\t\tfor _, conn := range allConns {\n\t\t\tswitch {\n\t\t\tcase !conn.DataIsComplete():\n\t\t\t\t// Skip connection if the data is not complete.\n\t\t\t\tcontinue nextConnection\n\n\t\t\tcase conn.Entity.Protocol != protocol:\n\t\t\t\t// Skip connection if the protocol does not match the protocol of interest.\n\t\t\t\tcontinue nextConnection\n\n\t\t\tcase conn.LocalPort <= port && conn.LocalPort >= portRangeStart:\n\t\t\t\t// Skip port if the local port is in dangerous proximity.\n\t\t\t\t// Consecutive port numbers are very common.\n\t\t\t\tcontinue nextPort\n\t\t\t}\n\t\t}\n\n\t\t// Log if it took more than 10 attempts.\n\t\tif i >= 10 {\n\t\t\tlog.Warningf(\"network: took %d attempts to find a suitable unused port for pre-auth\", i+1)\n\t\t}\n\n\t\t// The checks have passed. We have found a good unused port.\n\t\treturn port, true\n\t}\n\n\treturn 0, false\n}\n"
  },
  {
    "path": "service/network/proc/findpid.go",
    "content": "//go:build linux\n\npackage proc\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\n// GetPID returns the already existing pid of the given socket info or searches for it.\n// This also acts as a getter for socket.Info.PID, as locking for that occurs here.\nfunc GetPID(socketInfo socket.Info) (pid int) {\n\t// Get currently assigned PID to the socket info.\n\tcurrentPid := socketInfo.GetPID()\n\n\t// If the current PID already is valid (ie. not unidentified), return it immediately.\n\tif currentPid != socket.UndefinedProcessID {\n\t\treturn currentPid\n\t}\n\n\t// Find PID for the given UID and inode.\n\tpid = findPID(socketInfo.GetUIDandInode())\n\n\t// Set the newly found PID on the socket info.\n\tsocketInfo.SetPID(pid)\n\n\t// Return found PID.\n\treturn pid\n}\n\n// findPID returns the pid of the given uid and socket inode.\nfunc findPID(uid, inode int) (pid int) {\n\tsocketName := \"socket:[\" + strconv.Itoa(inode) + \"]\"\n\n\t// Always update pid table (it has a call limiter anyway)\n\tupdatePids()\n\n\t// Get all pids for the given uid.\n\tpids, ok := getPidsByUser(uid)\n\tif !ok {\n\t\treturn socket.UndefinedProcessID\n\t}\n\n\t// Look through the PIDs in reverse order, because higher/newer PIDs will be more likely to\n\t// be searched for.\n\tfor j := len(pids) - 1; j >= 0; j-- {\n\t\tif pidHasSocket(pids[j], socketName) {\n\t\t\treturn pids[j]\n\t\t}\n\t}\n\n\treturn socket.UndefinedProcessID\n}\n\nfunc pidHasSocket(pid int, socketName string) bool {\n\tsocketBase := \"/proc/\" + strconv.Itoa(pid) + \"/fd\"\n\tentries := readDirNames(socketBase)\n\tif len(entries) == 0 {\n\t\treturn false\n\t}\n\n\tsocketBase += \"/\"\n\t// Look through the FDs in reverse order, because higher/newer FDs will be\n\t// more likely to be searched for.\n\tfor i := len(entries) - 1; i >= 0; i-- {\n\t\tlink, err := os.Readlink(socketBase + entries[i])\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tlog.Warningf(\"proc: failed to read link /proc/%d/fd/%s: %s\", pid, entries[i], err)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif link == socketName {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// readDirNames only reads the directory names. Using os.ReadDir() would call `lstat` on every\n// resulting directory name, which we don't need. This function will be called a lot, so we should\n// refrain from unnecessary work.\nfunc readDirNames(dir string) (names []string) {\n\tfile, err := os.Open(dir)\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\tlog.Warningf(\"proc: could not open directory %s: %s\", dir, err)\n\t\t}\n\t\treturn\n\t}\n\tdefer func() {\n\t\t_ = file.Close()\n\t}()\n\n\tnames, err = file.Readdirnames(0)\n\tif err != nil {\n\t\tlog.Warningf(\"proc: could not get entries from directory %s: %s\", dir, err)\n\t\treturn []string{}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "service/network/proc/pids_by_user.go",
    "content": "//go:build linux\n\npackage proc\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"strconv\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\nvar (\n\t// pidsByUserLock is also used for locking the socketInfo.PID on all socket.*Info structs.\n\tpidsByUser      = make(map[int][]int)\n\tpidsByUserLock  sync.RWMutex\n\tfetchPidsByUser = utils.NewCallLimiter2(10 * time.Millisecond)\n)\n\n// getPidsByUser returns the cached PIDs for the given UID.\nfunc getPidsByUser(uid int) (pids []int, ok bool) {\n\tpidsByUserLock.RLock()\n\tdefer pidsByUserLock.RUnlock()\n\n\tpids, ok = pidsByUser[uid]\n\treturn\n}\n\n// updatePids fetches and creates a new pidsByUser map using a call limiter.\nfunc updatePids() {\n\tfetchPidsByUser.Do(func() {\n\t\tnewPidsByUser := make(map[int][]int)\n\t\tpidCnt := 0\n\n\t\tentries := readDirNames(\"/proc\")\n\t\tif len(entries) == 0 {\n\t\t\tlog.Warning(\"proc: found no PIDs in /proc\")\n\t\t\treturn\n\t\t}\n\n\tentryLoop:\n\t\tfor _, entry := range entries {\n\t\t\tpid, err := strconv.ParseInt(entry, 10, 32)\n\t\t\tif err != nil {\n\t\t\t\tcontinue entryLoop\n\t\t\t}\n\n\t\t\tstatData, err := os.Stat(\"/proc/\" + strconv.FormatInt(pid, 10))\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\tlog.Warningf(\"proc: could not stat /proc/%d: %s\", pid, err)\n\t\t\t\t}\n\t\t\t\tcontinue entryLoop\n\t\t\t}\n\t\t\tsys, ok := statData.Sys().(*syscall.Stat_t)\n\t\t\tif !ok {\n\t\t\t\tlog.Warningf(\"proc: unable to parse /proc/%d: wrong type\", pid)\n\t\t\t\tcontinue entryLoop\n\t\t\t}\n\n\t\t\tpids, ok := newPidsByUser[int(sys.Uid)]\n\t\t\tif ok {\n\t\t\t\tnewPidsByUser[int(sys.Uid)] = append(pids, int(pid))\n\t\t\t} else {\n\t\t\t\tnewPidsByUser[int(sys.Uid)] = []int{int(pid)}\n\t\t\t}\n\t\t\tpidCnt++\n\t\t}\n\n\t\t// log.Tracef(\"proc: updated PID table with %d entries\", pidCnt)\n\n\t\tpidsByUserLock.Lock()\n\t\tdefer pidsByUserLock.Unlock()\n\t\tpidsByUser = newPidsByUser\n\t})\n}\n"
  },
  {
    "path": "service/network/proc/tables.go",
    "content": "//go:build linux\n\npackage proc\n\nimport (\n\t\"bufio\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\n/*\n\n1. find socket inode\n  - by incoming (listenting sockets) or outgoing (local port + external IP + port) - also local IP?\n  - /proc/net/{tcp|udp}[6]\n\n2. get list of processes of uid\n\n3. find socket inode in process fds\n\t- if not found, refresh map of uid->pids\n\t- if not found, check ALL pids: maybe euid != uid\n\n4. gather process info\n\nCache every step!\n\n*/\n\n// Network Related Constants.\nconst (\n\tTCP4 uint8 = iota\n\tUDP4\n\tTCP6\n\tUDP6\n\tICMP4\n\tICMP6\n\n\ttcp4ProcFile = \"/proc/net/tcp\"\n\ttcp6ProcFile = \"/proc/net/tcp6\"\n\tudp4ProcFile = \"/proc/net/udp\"\n\tudp6ProcFile = \"/proc/net/udp6\"\n\n\ttcpListenStateHex = \"0A\"\n)\n\n// GetTCP4Table returns the system table for IPv4 TCP activity.\nfunc GetTCP4Table() (connections []*socket.ConnectionInfo, listeners []*socket.BindInfo, err error) {\n\treturn getTableFromSource(TCP4, tcp4ProcFile)\n}\n\n// GetTCP6Table returns the system table for IPv6 TCP activity.\nfunc GetTCP6Table() (connections []*socket.ConnectionInfo, listeners []*socket.BindInfo, err error) {\n\treturn getTableFromSource(TCP6, tcp6ProcFile)\n}\n\n// GetUDP4Table returns the system table for IPv4 UDP activity.\nfunc GetUDP4Table() (binds []*socket.BindInfo, err error) {\n\t_, binds, err = getTableFromSource(UDP4, udp4ProcFile)\n\treturn\n}\n\n// GetUDP6Table returns the system table for IPv6 UDP activity.\nfunc GetUDP6Table() (binds []*socket.BindInfo, err error) {\n\t_, binds, err = getTableFromSource(UDP6, udp6ProcFile)\n\treturn\n}\n\nconst (\n\t// hint: we split fields by multiple delimiters, see procDelimiter\n\tfieldIndexLocalIP    = 1\n\tfieldIndexLocalPort  = 2\n\tfieldIndexRemoteIP   = 3\n\tfieldIndexRemotePort = 4\n\tfieldIndexUID        = 11\n\tfieldIndexInode      = 13\n)\n\nfunc getTableFromSource(stack uint8, procFile string) (connections []*socket.ConnectionInfo, binds []*socket.BindInfo, err error) {\n\tvar ipConverter func(string) net.IP\n\tswitch stack {\n\tcase TCP4, UDP4:\n\t\tipConverter = convertIPv4\n\tcase TCP6, UDP6:\n\t\tipConverter = convertIPv6\n\tdefault:\n\t\treturn nil, nil, fmt.Errorf(\"unsupported table stack: %d\", stack)\n\t}\n\n\t// open file\n\tsocketData, err := os.Open(procFile)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tdefer func() {\n\t\t_ = socketData.Close()\n\t}()\n\n\t// file scanner\n\tscanner := bufio.NewScanner(socketData)\n\tscanner.Split(bufio.ScanLines)\n\n\t// parse\n\tscanner.Scan() // skip first row\n\tfor scanner.Scan() {\n\t\tfields := strings.FieldsFunc(scanner.Text(), procDelimiter)\n\t\tif len(fields) < 14 {\n\t\t\t// log.Tracef(\"proc: too short: %s\", fields)\n\t\t\tcontinue\n\t\t}\n\n\t\tlocalIP := ipConverter(fields[fieldIndexLocalIP])\n\t\tif localIP == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tlocalPort, err := strconv.ParseUint(fields[fieldIndexLocalPort], 16, 16)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"proc: could not parse port: %s\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tuid, err := strconv.ParseInt(fields[fieldIndexUID], 10, 32)\n\t\t// log.Tracef(\"uid: %s\", fields[fieldIndexUID])\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"proc: could not parse uid %s: %s\", fields[11], err)\n\t\t\tcontinue\n\t\t}\n\n\t\tinode, err := strconv.ParseInt(fields[fieldIndexInode], 10, 32)\n\t\t// log.Tracef(\"inode: %s\", fields[fieldIndexInode])\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"proc: could not parse inode %s: %s\", fields[13], err)\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch stack {\n\t\tcase UDP4, UDP6:\n\n\t\t\tbinds = append(binds, &socket.BindInfo{\n\t\t\t\tLocal: socket.Address{\n\t\t\t\t\tIP:   localIP,\n\t\t\t\t\tPort: uint16(localPort),\n\t\t\t\t},\n\t\t\t\tPID:   socket.UndefinedProcessID,\n\t\t\t\tUID:   int(uid),\n\t\t\t\tInode: int(inode),\n\t\t\t})\n\n\t\tcase TCP4, TCP6:\n\n\t\t\tif fields[5] == tcpListenStateHex {\n\t\t\t\t// listener\n\n\t\t\t\tbinds = append(binds, &socket.BindInfo{\n\t\t\t\t\tLocal: socket.Address{\n\t\t\t\t\t\tIP:   localIP,\n\t\t\t\t\t\tPort: uint16(localPort),\n\t\t\t\t\t},\n\t\t\t\t\tPID:   socket.UndefinedProcessID,\n\t\t\t\t\tUID:   int(uid),\n\t\t\t\t\tInode: int(inode),\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\t// connection\n\n\t\t\t\tremoteIP := ipConverter(fields[fieldIndexRemoteIP])\n\t\t\t\tif remoteIP == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tremotePort, err := strconv.ParseUint(fields[fieldIndexRemotePort], 16, 16)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warningf(\"proc: could not parse port: %s\", err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconnections = append(connections, &socket.ConnectionInfo{\n\t\t\t\t\tLocal: socket.Address{\n\t\t\t\t\t\tIP:   localIP,\n\t\t\t\t\t\tPort: uint16(localPort),\n\t\t\t\t\t},\n\t\t\t\t\tRemote: socket.Address{\n\t\t\t\t\t\tIP:   remoteIP,\n\t\t\t\t\t\tPort: uint16(remotePort),\n\t\t\t\t\t},\n\t\t\t\t\tPID:   socket.UndefinedProcessID,\n\t\t\t\t\tUID:   int(uid),\n\t\t\t\t\tInode: int(inode),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn connections, binds, nil\n}\n\nfunc procDelimiter(c rune) bool {\n\treturn unicode.IsSpace(c) || c == ':'\n}\n\nfunc convertIPv4(data string) net.IP {\n\t// Decode and bullshit check the data length.\n\tdecoded, err := hex.DecodeString(data)\n\tif err != nil {\n\t\tlog.Warningf(\"proc: could not parse IPv4 %s: %s\", data, err)\n\t\treturn nil\n\t}\n\tif len(decoded) != 4 {\n\t\tlog.Warningf(\"proc: decoded IPv4 %s has wrong length\", decoded)\n\t\treturn nil\n\t}\n\n\t// Build the IPv4 address with the reversed byte order.\n\tip := net.IPv4(decoded[3], decoded[2], decoded[1], decoded[0])\n\treturn ip\n}\n\nfunc convertIPv6(data string) net.IP {\n\t// Decode and bullshit check the data length.\n\tdecoded, err := hex.DecodeString(data)\n\tif err != nil {\n\t\tlog.Warningf(\"proc: could not parse IPv6 %s: %s\", data, err)\n\t\treturn nil\n\t}\n\tif len(decoded) != 16 {\n\t\tlog.Warningf(\"proc: decoded IPv6 %s has wrong length\", decoded)\n\t\treturn nil\n\t}\n\n\t// Build the IPv6 address with the translated byte order.\n\tfor i := 0; i < 16; i += 4 {\n\t\tdecoded[i], decoded[i+1], decoded[i+2], decoded[i+3] = decoded[i+3], decoded[i+2], decoded[i+1], decoded[i]\n\t}\n\tip := net.IP(decoded)\n\treturn ip\n}\n"
  },
  {
    "path": "service/network/proc/tables_test.go",
    "content": "//go:build linux\n\npackage proc\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestSockets(t *testing.T) {\n\tt.Parallel()\n\n\tconnections, listeners, err := GetTCP4Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nTCP 4 connections:\")\n\tfor _, connection := range connections {\n\t\tpid := GetPID(connection)\n\t\tfmt.Printf(\"%d: %+v\\n\", pid, connection)\n\t}\n\tfmt.Println(\"\\nTCP 4 listeners:\")\n\tfor _, listener := range listeners {\n\t\tpid := GetPID(listener)\n\t\tfmt.Printf(\"%d: %+v\\n\", pid, listener)\n\t}\n\n\tconnections, listeners, err = GetTCP6Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nTCP 6 connections:\")\n\tfor _, connection := range connections {\n\t\tpid := GetPID(connection)\n\t\tfmt.Printf(\"%d: %+v\\n\", pid, connection)\n\t}\n\tfmt.Println(\"\\nTCP 6 listeners:\")\n\tfor _, listener := range listeners {\n\t\tpid := GetPID(listener)\n\t\tfmt.Printf(\"%d: %+v\\n\", pid, listener)\n\t}\n\n\tbinds, err := GetUDP4Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nUDP 4 binds:\")\n\tfor _, bind := range binds {\n\t\tpid := GetPID(bind)\n\t\tfmt.Printf(\"%d: %+v\\n\", pid, bind)\n\t}\n\n\tbinds, err = GetUDP6Table()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Println(\"\\nUDP 6 binds:\")\n\tfor _, bind := range binds {\n\t\tpid := GetPID(bind)\n\t\tfmt.Printf(\"%d: %+v\\n\", pid, bind)\n\t}\n}\n"
  },
  {
    "path": "service/network/reference/ports.go",
    "content": "package reference\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar (\n\tportNames = map[uint16]string{\n\t\t20:  \"FTP-DATA\",\n\t\t21:  \"FTP\",\n\t\t22:  \"SSH\",\n\t\t23:  \"TELNET\",\n\t\t25:  \"SMTP\",\n\t\t43:  \"WHOIS\",\n\t\t53:  \"DNS\",\n\t\t67:  \"DHCP_SERVER\",\n\t\t68:  \"DHCP_CLIENT\",\n\t\t69:  \"TFTP\",\n\t\t80:  \"HTTP\",\n\t\t110: \"POP3\",\n\t\t123: \"NTP\",\n\t\t143: \"IMAP\",\n\t\t161: \"SNMP\",\n\t\t179: \"BGP\",\n\t\t194: \"IRC\",\n\t\t389: \"LDAP\",\n\t\t443: \"HTTPS\",\n\t\t445: \"SMB\",\n\t\t587: \"SMTP_ALT\",\n\t\t465: \"SMTP_SSL\",\n\t\t993: \"IMAP_SSL\",\n\t\t995: \"POP3_SSL\",\n\t}\n\n\tportNumbers = map[string]uint16{\n\t\t\"FTP-DATA\":    20,\n\t\t\"FTP\":         21,\n\t\t\"SSH\":         22,\n\t\t\"TELNET\":      23,\n\t\t\"SMTP\":        25,\n\t\t\"WHOIS\":       43,\n\t\t\"DNS\":         53,\n\t\t\"DHCP-SERVER\": 67,\n\t\t\"DHCP_SERVER\": 67,\n\t\t\"DHCP-CLIENT\": 68,\n\t\t\"DHCP_CLIENT\": 68,\n\t\t\"TFTP\":        69,\n\t\t\"HTTP\":        80,\n\t\t\"POP3\":        110,\n\t\t\"NTP\":         123,\n\t\t\"IMAP\":        143,\n\t\t\"SNMP\":        161,\n\t\t\"BGP\":         179,\n\t\t\"IRC\":         194,\n\t\t\"LDAP\":        389,\n\t\t\"HTTPS\":       443,\n\t\t\"SMB\":         445,\n\t\t\"SMTP-ALT\":    587,\n\t\t\"SMTP_ALT\":    587,\n\t\t\"SMTP-SSL\":    465,\n\t\t\"SMTP_SSL\":    465,\n\t\t\"IMAP-SSL\":    993,\n\t\t\"IMAP_SSL\":    993,\n\t\t\"POP3-SSL\":    995,\n\t\t\"POP3_SSL\":    995,\n\t}\n)\n\n// GetPortName returns the name of a port number.\nfunc GetPortName(port uint16) (name string) {\n\tname, ok := portNames[port]\n\tif ok {\n\t\treturn name\n\t}\n\treturn strconv.Itoa(int(port))\n}\n\n// GetPortNumber returns the number of a port name.\nfunc GetPortNumber(port string) (number uint16, ok bool) {\n\tnumber, ok = portNumbers[strings.ToUpper(port)]\n\tif ok {\n\t\treturn number, true\n\t}\n\treturn 0, false\n}\n"
  },
  {
    "path": "service/network/reference/protocols.go",
    "content": "package reference\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar (\n\tprotocolNames = map[uint8]string{\n\t\t1:   \"ICMP\",\n\t\t2:   \"IGMP\",\n\t\t6:   \"TCP\",\n\t\t17:  \"UDP\",\n\t\t27:  \"RDP\",\n\t\t58:  \"ICMP6\",\n\t\t33:  \"DCCP\",\n\t\t136: \"UDP-LITE\",\n\t}\n\n\tprotocolNumbers = map[string]uint8{\n\t\t\"ICMP\":     1,\n\t\t\"IGMP\":     2,\n\t\t\"TCP\":      6,\n\t\t\"UDP\":      17,\n\t\t\"RDP\":      27,\n\t\t\"DCCP\":     33,\n\t\t\"ICMP6\":    58,\n\t\t\"UDP-LITE\": 136,\n\t}\n)\n\n// GetProtocolName returns the name of a IP protocol number.\nfunc GetProtocolName(protocol uint8) (name string) {\n\tname, ok := protocolNames[protocol]\n\tif ok {\n\t\treturn name\n\t}\n\treturn strconv.Itoa(int(protocol))\n}\n\n// GetProtocolNumber returns the number of a IP protocol name.\nfunc GetProtocolNumber(protocol string) (number uint8, ok bool) {\n\tnumber, ok = protocolNumbers[strings.ToUpper(protocol)]\n\tif ok {\n\t\treturn number, true\n\t}\n\treturn 0, false\n}\n\n// IsPacketProtocol returns whether the given protocol number is a known packet based protocol.\n// Note: Not fully complete. Calling IsPacketProtocol() does not equal calling !IsStreamProtocol().\nfunc IsPacketProtocol(protocol uint8) bool {\n\tswitch protocol {\n\tcase 1, // ICMP\n\t\t17,  // UDP\n\t\t27,  // RDP\n\t\t58,  // ICMP6\n\t\t33,  // DCCP\n\t\t136: // UDP-LITE\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// IsStreamProtocol returns whether the given protocol number is a known stream based protocol.\n// Note: Not fully complete. Calling IsPacketProtocol() does not equal calling !IsStreamProtocol().\nfunc IsStreamProtocol(protocol uint8) bool {\n\tswitch protocol {\n\tcase 6: // TCP\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// IsICMP returns whether the given protocol is ICMP or ICMPv6.\nfunc IsICMP(protocol uint8) bool {\n\tswitch protocol {\n\tcase 1, // ICMP\n\t\t58: // ICMP6\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "service/network/socket/socket.go",
    "content": "package socket\n\nimport (\n\t\"net\"\n\t\"sync\"\n)\n\nconst (\n\t// UndefinedProcessID signifies that the process ID is unknown.\n\t// It must match portmaster/process.UndefinedProcessID\n\t// It is duplicated here because of import loops.\n\tUndefinedProcessID = -1\n)\n\n// ConnectionInfo holds socket information returned by the system.\ntype ConnectionInfo struct {\n\tsync.Mutex\n\n\tLocal  Address\n\tRemote Address\n\tPID    int\n\tUID    int\n\tInode  int\n}\n\n// BindInfo holds socket information returned by the system.\ntype BindInfo struct {\n\tsync.Mutex\n\n\tLocal Address\n\tPID   int\n\tUID   int\n\tInode int\n\n\tListensAny bool\n}\n\n// Address is an IP + Port pair.\ntype Address struct {\n\tIP   net.IP\n\tPort uint16\n}\n\n// Info is a generic interface to both ConnectionInfo and BindInfo.\ntype Info interface {\n\tGetPID() int\n\tSetPID(pid int)\n\tGetUID() int\n\tGetUIDandInode() (int, int)\n}\n\n// GetPID returns the PID.\nfunc (i *ConnectionInfo) GetPID() int {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\treturn i.PID\n}\n\n// SetPID sets the PID to the given value.\nfunc (i *ConnectionInfo) SetPID(pid int) {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\ti.PID = pid\n}\n\n// GetUID returns the UID.\nfunc (i *ConnectionInfo) GetUID() int {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\treturn i.UID\n}\n\n// GetUIDandInode returns the UID and Inode.\nfunc (i *ConnectionInfo) GetUIDandInode() (int, int) {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\treturn i.UID, i.Inode\n}\n\n// GetPID returns the PID.\nfunc (i *BindInfo) GetPID() int {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\treturn i.PID\n}\n\n// SetPID sets the PID to the given value.\nfunc (i *BindInfo) SetPID(pid int) {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\ti.PID = pid\n}\n\n// GetUID returns the UID.\nfunc (i *BindInfo) GetUID() int {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\treturn i.UID\n}\n\n// GetUIDandInode returns the UID and Inode.\nfunc (i *BindInfo) GetUIDandInode() (int, int) {\n\ti.Lock()\n\tdefer i.Unlock()\n\n\treturn i.UID, i.Inode\n}\n\n// Compile time checks.\nvar (\n\t_ Info = new(ConnectionInfo)\n\t_ Info = new(BindInfo)\n)\n"
  },
  {
    "path": "service/network/state/exists.go",
    "content": "package state\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\nconst (\n\t// UDPConnectionTTL defines the duration after which unseen UDP connections are regarded as ended.\n\tUDPConnectionTTL = 10 * time.Minute\n)\n\n// Exists checks if the given connection is present in the system state tables.\nfunc Exists(pktInfo *packet.Info, now time.Time) (exists bool) {\n\t// TODO: create lookup maps before running a flurry of Exists() checks.\n\n\tswitch {\n\tcase pktInfo.Version == packet.IPv4 && pktInfo.Protocol == packet.TCP:\n\t\treturn tcp4Table.exists(pktInfo)\n\n\tcase pktInfo.Version == packet.IPv6 && pktInfo.Protocol == packet.TCP:\n\t\treturn tcp6Table.exists(pktInfo)\n\n\tcase pktInfo.Version == packet.IPv4 && pktInfo.Protocol == packet.UDP:\n\t\treturn udp4Table.exists(pktInfo, now)\n\n\tcase pktInfo.Version == packet.IPv6 && pktInfo.Protocol == packet.UDP:\n\t\treturn udp6Table.exists(pktInfo, now)\n\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (table *tcpTable) exists(pktInfo *packet.Info) (exists bool) {\n\t// Update tables if older than the connection that is checked.\n\tif table.lastUpdateAt.Load() < pktInfo.SeenAt.UnixNano() {\n\t\ttable.updateTables()\n\t}\n\n\ttable.lock.RLock()\n\tdefer table.lock.RUnlock()\n\n\tlocalIP := pktInfo.LocalIP()\n\tlocalPort := pktInfo.LocalPort()\n\tremoteIP := pktInfo.RemoteIP()\n\tremotePort := pktInfo.RemotePort()\n\n\t// search connections\n\tfor _, socketInfo := range table.connections {\n\t\tif localPort == socketInfo.Local.Port &&\n\t\t\tremotePort == socketInfo.Remote.Port &&\n\t\t\tremoteIP.Equal(socketInfo.Remote.IP) &&\n\t\t\tlocalIP.Equal(socketInfo.Local.IP) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (table *udpTable) exists(pktInfo *packet.Info, now time.Time) (exists bool) {\n\t// Update tables if older than the connection that is checked.\n\tif table.lastUpdateAt.Load() < pktInfo.SeenAt.UnixNano() {\n\t\ttable.updateTables()\n\t}\n\n\ttable.lock.RLock()\n\tdefer table.lock.RUnlock()\n\n\tlocalIP := pktInfo.LocalIP()\n\tlocalPort := pktInfo.LocalPort()\n\tremoteIP := pktInfo.RemoteIP()\n\tremotePort := pktInfo.RemotePort()\n\n\tconnThreshhold := now.Add(-UDPConnectionTTL)\n\n\t// search binds\n\tfor _, socketInfo := range table.binds {\n\t\tif localPort == socketInfo.Local.Port &&\n\t\t\t(socketInfo.Local.IP[0] == 0 || localIP.Equal(socketInfo.Local.IP)) {\n\n\t\t\tudpConnState, ok := table.getConnState(socketInfo, socket.Address{\n\t\t\t\tIP:   remoteIP,\n\t\t\t\tPort: remotePort,\n\t\t\t})\n\t\t\tswitch {\n\t\t\tcase !ok:\n\t\t\t\treturn false\n\t\t\tcase udpConnState.lastSeen.After(connThreshhold):\n\t\t\t\treturn true\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "service/network/state/info.go",
    "content": "package state\n\nimport (\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\n// Info holds network state information as provided by the system.\ntype Info struct {\n\trecord.Base\n\tsync.Mutex\n\n\tTCP4Connections []*socket.ConnectionInfo\n\tTCP4Listeners   []*socket.BindInfo\n\tTCP6Connections []*socket.ConnectionInfo\n\tTCP6Listeners   []*socket.BindInfo\n\tUDP4Binds       []*socket.BindInfo\n\tUDP6Binds       []*socket.BindInfo\n}\n\n// GetInfo returns all system state tables. The returned data must not be modified.\nfunc GetInfo() *Info {\n\tinfo := &Info{}\n\n\tinfo.TCP4Connections, info.TCP4Listeners = tcp4Table.updateTables()\n\tinfo.UDP4Binds = udp4Table.updateTables()\n\n\tif netenv.IPv6Enabled() {\n\t\tinfo.TCP6Connections, info.TCP6Listeners = tcp6Table.updateTables()\n\t\tinfo.UDP6Binds = udp6Table.updateTables()\n\t}\n\n\tinfo.UpdateMeta()\n\treturn info\n}\n"
  },
  {
    "path": "service/network/state/lookup.go",
    "content": "package state\n\nimport (\n\t\"errors\"\n\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\n// - TCP\n//   - Outbound: Match listeners (in!), then connections (out!)\n//   - Inbound: Match listeners (in!), then connections (out!)\n//   - Clean via connections\n// - UDP\n//   - Any connection: match specific local address or zero IP\n//   - In or out: save direction of first packet:\n//     - map[<local udp bind ip+port>]map[<remote ip+port>]{direction, lastSeen}\n//       - only clean if <local udp bind ip+port> is removed by OS\n//       - limit <remote ip+port> to 256 entries?\n//       - clean <remote ip+port> after 72hrs?\n//       - switch direction to outbound if outbound packet is seen?\n// - IP: Unidentified Process\n\n// Errors.\nvar (\n\tErrConnectionNotFound = errors.New(\"could not find connection in system state tables\")\n\tErrPIDNotFound        = errors.New(\"could not find pid for socket inode\")\n)\n\nconst (\n\tlookupTries     = 5\n\tfastLookupTries = 2 // 1. current table, 2. get table with max 10ms, could be 0ms, 3. 10ms wait\n)\n\n// Lookup looks for the given connection in the system state tables and returns the PID of the associated process and whether the connection is inbound.\nfunc Lookup(pktInfo *packet.Info, fast bool) (pid int, inbound bool, err error) {\n\t// auto-detect version\n\tif pktInfo.Version == 0 {\n\t\tif ip := pktInfo.LocalIP().To4(); ip != nil {\n\t\t\tpktInfo.Version = packet.IPv4\n\t\t} else {\n\t\t\tpktInfo.Version = packet.IPv6\n\t\t}\n\t}\n\n\tswitch {\n\tcase pktInfo.Version == packet.IPv4 && pktInfo.Protocol == packet.TCP:\n\t\treturn tcp4Table.lookup(pktInfo, fast)\n\n\tcase pktInfo.Version == packet.IPv6 && pktInfo.Protocol == packet.TCP:\n\t\treturn tcp6Table.lookup(pktInfo, fast)\n\n\tcase pktInfo.Version == packet.IPv4 && pktInfo.Protocol == packet.UDP:\n\t\treturn udp4Table.lookup(pktInfo, fast)\n\n\tcase pktInfo.Version == packet.IPv6 && pktInfo.Protocol == packet.UDP:\n\t\treturn udp6Table.lookup(pktInfo, fast)\n\n\tdefault:\n\t\treturn socket.UndefinedProcessID, pktInfo.Inbound, errors.New(\"unsupported protocol for finding process\")\n\t}\n}\n\nfunc (table *tcpTable) lookup(pktInfo *packet.Info, fast bool) (\n\tpid int,\n\tinbound bool,\n\terr error,\n) {\n\t// Prepare variables.\n\tvar (\n\t\tconnections []*socket.ConnectionInfo\n\t\tlisteners   []*socket.BindInfo\n\n\t\tdualStackConnections []*socket.ConnectionInfo\n\t\tdualStackListeners   []*socket.BindInfo\n\t)\n\n\t// Search for the socket until found.\n\tfor i := 1; i <= lookupTries; i++ {\n\t\t// Use existing tables for first check if packet was seen after last table update.\n\t\tif i == 1 && pktInfo.SeenAt.UnixNano() >= table.lastUpdateAt.Load() {\n\t\t\tconnections, listeners = table.getCurrentTables()\n\t\t} else {\n\t\t\tconnections, listeners = table.updateTables()\n\t\t}\n\n\t\t// Check tables for socket.\n\t\tsocketInfo, inbound := findTCPSocket(pktInfo, connections, listeners)\n\n\t\t// If there's a match, check if we have the PID and return.\n\t\tif socketInfo != nil {\n\t\t\treturn CheckPID(socketInfo, inbound)\n\t\t}\n\n\t\t// DUAL-STACK\n\n\t\t// Skip if dualStack is not enabled.\n\t\tif table.dualStack == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Use existing tables for first check if packet was seen after last table update.\n\t\tif i == 1 && pktInfo.SeenAt.UnixNano() >= table.dualStack.lastUpdateAt.Load() {\n\t\t\tdualStackConnections, dualStackListeners = table.dualStack.getCurrentTables()\n\t\t} else {\n\t\t\tdualStackConnections, dualStackListeners = table.dualStack.updateTables()\n\t\t}\n\n\t\t// Check tables for socket.\n\t\tsocketInfo, inbound = findTCPSocket(pktInfo, dualStackConnections, dualStackListeners)\n\n\t\t// If there's a match, check if we have the PID and return.\n\t\tif socketInfo != nil {\n\t\t\treturn CheckPID(socketInfo, inbound)\n\t\t}\n\n\t\t// Search less if we want to be fast.\n\t\tif fast && i >= fastLookupTries {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn socket.UndefinedProcessID, pktInfo.Inbound, ErrConnectionNotFound\n}\n\nfunc findTCPSocket(\n\tpktInfo *packet.Info,\n\tconnections []*socket.ConnectionInfo,\n\tlisteners []*socket.BindInfo,\n) (\n\tsocketInfo socket.Info,\n\tinbound bool,\n) {\n\tlocalIP := pktInfo.LocalIP()\n\tlocalPort := pktInfo.LocalPort()\n\n\t// always search listeners first\n\tfor _, socketInfo := range listeners {\n\t\tif localPort == socketInfo.Local.Port &&\n\t\t\t(socketInfo.ListensAny || localIP.Equal(socketInfo.Local.IP)) {\n\t\t\treturn socketInfo, true\n\t\t}\n\t}\n\n\tremoteIP := pktInfo.RemoteIP()\n\tremotePort := pktInfo.RemotePort()\n\n\t// search connections\n\tfor _, socketInfo := range connections {\n\t\tif localPort == socketInfo.Local.Port &&\n\t\t\tremotePort == socketInfo.Remote.Port &&\n\t\t\tremoteIP.Equal(socketInfo.Remote.IP) &&\n\t\t\tlocalIP.Equal(socketInfo.Local.IP) {\n\t\t\treturn socketInfo, false\n\t\t}\n\t}\n\n\treturn nil, false\n}\n\nfunc (table *udpTable) lookup(pktInfo *packet.Info, fast bool) (\n\tpid int,\n\tinbound bool,\n\terr error,\n) {\n\t// TODO: Currently broadcast/multicast scopes are not checked, so we might\n\t// attribute an incoming broadcast/multicast packet to the wrong process if\n\t// there are multiple processes listening on the same local port, but\n\t// binding to different addresses. This highly unusual for clients.\n\tisInboundMulticast := pktInfo.Inbound && netutils.GetIPScope(pktInfo.LocalIP()) == netutils.LocalMulticast\n\n\t// Prepare variables.\n\tvar (\n\t\tbinds          []*socket.BindInfo\n\t\tdualStackBinds []*socket.BindInfo\n\t)\n\n\t// Search for the socket until found.\n\tfor i := 1; i <= lookupTries; i++ {\n\t\t// Get or update tables.\n\t\tif i == 1 && pktInfo.SeenAt.UnixNano() >= table.lastUpdateAt.Load() {\n\t\t\tbinds = table.getCurrentTables()\n\t\t} else {\n\t\t\tbinds = table.updateTables()\n\t\t}\n\n\t\t// Check tables for socket.\n\t\tsocketInfo := findUDPSocket(pktInfo, binds, isInboundMulticast)\n\n\t\t// If there's a match, do some last checks and return.\n\t\tif socketInfo != nil {\n\t\t\t// If there is no remote port, do check for the direction of the\n\t\t\t// connection. This will be the case for pure checking functions\n\t\t\t// that do not want to change direction state.\n\t\t\tif pktInfo.RemotePort() == 0 {\n\t\t\t\treturn CheckPID(socketInfo, pktInfo.Inbound)\n\t\t\t}\n\n\t\t\t// Get (and save) the direction of the connection.\n\t\t\tconnInbound := table.getDirection(socketInfo, pktInfo)\n\n\t\t\t// Check we have the PID and return.\n\t\t\treturn CheckPID(socketInfo, connInbound)\n\t\t}\n\n\t\t// DUAL-STACK\n\n\t\t// Skip if dualStack is not enabled.\n\t\tif table.dualStack == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get or update tables.\n\t\tif i == 1 && pktInfo.SeenAt.UnixNano() >= table.lastUpdateAt.Load() {\n\t\t\tdualStackBinds = table.dualStack.getCurrentTables()\n\t\t} else {\n\t\t\tdualStackBinds = table.dualStack.updateTables()\n\t\t}\n\n\t\t// Check tables for socket.\n\t\tsocketInfo = findUDPSocket(pktInfo, dualStackBinds, isInboundMulticast)\n\n\t\t// If there's a match, do some last checks and return.\n\t\tif socketInfo != nil {\n\t\t\t// If there is no remote port, do check for the direction of the\n\t\t\t// connection. This will be the case for pure checking functions\n\t\t\t// that do not want to change direction state.\n\t\t\tif pktInfo.RemotePort() == 0 {\n\t\t\t\treturn CheckPID(socketInfo, pktInfo.Inbound)\n\t\t\t}\n\n\t\t\t// Get (and save) the direction of the connection.\n\t\t\tconnInbound := table.getDirection(socketInfo, pktInfo)\n\n\t\t\t// Check we have the PID and return.\n\t\t\treturn CheckPID(socketInfo, connInbound)\n\t\t}\n\n\t\t// Search less if we want to be fast.\n\t\tif fast && i >= fastLookupTries {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn socket.UndefinedProcessID, pktInfo.Inbound, ErrConnectionNotFound\n}\n\nfunc findUDPSocket(pktInfo *packet.Info, binds []*socket.BindInfo, isInboundMulticast bool) (socketInfo *socket.BindInfo) {\n\tlocalIP := pktInfo.LocalIP()\n\tlocalPort := pktInfo.LocalPort()\n\n\t// search binds\n\tfor _, socketInfo := range binds {\n\t\tif localPort == socketInfo.Local.Port &&\n\t\t\t(socketInfo.ListensAny || // zero IP (dual-stack)\n\t\t\t\tisInboundMulticast || // inbound broadcast, multicast\n\t\t\t\tlocalIP.Equal(socketInfo.Local.IP)) {\n\t\t\treturn socketInfo\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/network/state/system_default.go",
    "content": "//go:build !windows && !linux\n// +build !windows,!linux\n\npackage state\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\nfunc init() {\n\t// This increases performance on unsupported system.\n\t// It's not critical at all and does not break anything if it fails.\n\tgo func() {\n\t\t// Wait for one minute before we set the default value, as we\n\t\t// currently cannot easily integrate into the startup procedure.\n\t\ttime.Sleep(1 * time.Minute)\n\n\t\t// We cannot use process.CfgOptionEnableProcessDetectionKey, because of an import loop.\n\t\tconfig.SetDefaultConfigOption(\"core/enableProcessDetection\", false)\n\t}()\n}\n\nfunc getTCP4Table() (connections []*socket.ConnectionInfo, listeners []*socket.BindInfo, err error) {\n\treturn nil, nil, nil\n}\n\nfunc getTCP6Table() (connections []*socket.ConnectionInfo, listeners []*socket.BindInfo, err error) {\n\treturn nil, nil, nil\n}\n\nfunc getUDP4Table() (binds []*socket.BindInfo, err error) {\n\treturn nil, nil\n}\n\nfunc getUDP6Table() (binds []*socket.BindInfo, err error) {\n\treturn nil, nil\n}\n\n// CheckPID checks the if socket info already has a PID and if not, tries to find it.\n// Depending on the OS, this might be a no-op.\nfunc CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool, err error) {\n\treturn socketInfo.GetPID(), connInbound, nil\n}\n"
  },
  {
    "path": "service/network/state/system_linux.go",
    "content": "package state\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/network/proc\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\nvar (\n\tgetTCP4Table = proc.GetTCP4Table\n\tgetTCP6Table = proc.GetTCP6Table\n\tgetUDP4Table = proc.GetUDP4Table\n\tgetUDP6Table = proc.GetUDP6Table\n\n\tcheckPIDTries        = 5\n\tcheckPIDBaseWaitTime = 5 * time.Millisecond\n)\n\n// CheckPID checks the if socket info already has a PID and if not, tries to find it.\n// Depending on the OS, this might be a no-op.\nfunc CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool, err error) {\n\tfor i := 1; i <= checkPIDTries; i++ {\n\t\t// look for PID\n\t\tpid = proc.GetPID(socketInfo)\n\t\tif pid != socket.UndefinedProcessID {\n\t\t\t// if we found a PID, return\n\t\t\tbreak\n\t\t}\n\n\t\t// every time, except for the last iteration\n\t\tif i < checkPIDTries {\n\t\t\t// we found no PID, we could have been too fast, give the kernel some time to think\n\t\t\t// back off timer: with 5ms baseWaitTime: 5, 10, 15, 20, 25 - 75ms in total\n\t\t\ttime.Sleep(time.Duration(i) * checkPIDBaseWaitTime)\n\t\t}\n\t}\n\n\treturn pid, connInbound, nil\n}\n"
  },
  {
    "path": "service/network/state/system_windows.go",
    "content": "package state\n\nimport (\n\t\"github.com/safing/portmaster/service/network/iphelper\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\nvar (\n\tgetTCP4Table = iphelper.GetTCP4Table\n\tgetTCP6Table = iphelper.GetTCP6Table\n\tgetUDP4Table = iphelper.GetUDP4Table\n\tgetUDP6Table = iphelper.GetUDP6Table\n)\n\n// CheckPID checks the if socket info already has a PID and if not, tries to find it.\n// Depending on the OS, this might be a no-op.\nfunc CheckPID(socketInfo socket.Info, connInbound bool) (pid int, inbound bool, err error) {\n\treturn socketInfo.GetPID(), connInbound, nil\n}\n"
  },
  {
    "path": "service/network/state/tcp.go",
    "content": "package state\n\nimport (\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\nconst (\n\tminDurationBetweenTableUpdates = 10 * time.Millisecond\n)\n\ntype tcpTable struct {\n\tversion int\n\n\tconnections []*socket.ConnectionInfo\n\tlisteners   []*socket.BindInfo\n\tlock        sync.RWMutex\n\n\t// lastUpdateAt stores the time when the tables where last updated as unix nanoseconds.\n\tlastUpdateAt atomic.Int64\n\n\tfetchLimiter *utils.CallLimiter2\n\tfetchTable   func() (connections []*socket.ConnectionInfo, listeners []*socket.BindInfo, err error)\n\n\tdualStack *tcpTable\n}\n\nvar (\n\ttcp6Table = &tcpTable{\n\t\tversion:      6,\n\t\tfetchLimiter: utils.NewCallLimiter2(minDurationBetweenTableUpdates),\n\t\tfetchTable:   getTCP6Table,\n\t}\n\n\ttcp4Table = &tcpTable{\n\t\tversion:      4,\n\t\tfetchLimiter: utils.NewCallLimiter2(minDurationBetweenTableUpdates),\n\t\tfetchTable:   getTCP4Table,\n\t}\n)\n\n// EnableTCPDualStack adds the TCP6 table to the TCP4 table as a dual-stack.\n// Must be called before any lookup operation.\nfunc EnableTCPDualStack() {\n\ttcp4Table.dualStack = tcp6Table\n}\n\nfunc (table *tcpTable) getCurrentTables() (\n\tconnections []*socket.ConnectionInfo,\n\tlisteners []*socket.BindInfo,\n) {\n\ttable.lock.RLock()\n\tdefer table.lock.RUnlock()\n\n\treturn table.connections, table.listeners\n}\n\nfunc (table *tcpTable) updateTables() (\n\tconnections []*socket.ConnectionInfo,\n\tlisteners []*socket.BindInfo,\n) {\n\t// Fetch tables.\n\ttable.fetchLimiter.Do(func() {\n\t\t// Fetch new tables from system.\n\t\tconnections, listeners, err := table.fetchTable()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"state: failed to get TCP%d socket table: %s\", table.version, err)\n\t\t\treturn\n\t\t}\n\n\t\t// Pre-check for any listeners.\n\t\tfor _, bindInfo := range listeners {\n\t\t\tbindInfo.ListensAny = bindInfo.Local.IP.Equal(net.IPv4zero) || bindInfo.Local.IP.Equal(net.IPv6zero)\n\t\t}\n\n\t\t// Apply new tables.\n\t\ttable.lock.Lock()\n\t\tdefer table.lock.Unlock()\n\t\ttable.connections = connections\n\t\ttable.listeners = listeners\n\t\ttable.lastUpdateAt.Store(time.Now().UnixNano())\n\t})\n\n\treturn table.getCurrentTables()\n}\n"
  },
  {
    "path": "service/network/state/udp.go",
    "content": "package state\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n)\n\ntype udpTable struct {\n\tversion int\n\n\tbinds []*socket.BindInfo\n\tlock  sync.RWMutex\n\n\t// lastUpdateAt stores the time when the tables where last updated as unix nanoseconds.\n\tlastUpdateAt atomic.Int64\n\n\tfetchLimiter *utils.CallLimiter2\n\tfetchTable   func() (binds []*socket.BindInfo, err error)\n\n\tstates     map[string]map[string]*udpState\n\tstatesLock sync.Mutex\n\n\tdualStack *udpTable\n}\n\ntype udpState struct {\n\tinbound  bool\n\tlastSeen time.Time\n}\n\nconst (\n\t// UDPConnStateTTL is the maximum time a udp connection state is held.\n\tUDPConnStateTTL = 72 * time.Hour\n\n\t// UDPConnStateShortenedTTL is a shortened maximum time a udp connection state is held, if there more entries than defined by AggressiveCleaningThreshold.\n\tUDPConnStateShortenedTTL = 3 * time.Hour\n\n\t// AggressiveCleaningThreshold defines the soft limit of udp connection state held per udp socket.\n\tAggressiveCleaningThreshold = 256\n)\n\nvar (\n\tudp6Table = &udpTable{\n\t\tversion:      6,\n\t\tfetchLimiter: utils.NewCallLimiter2(minDurationBetweenTableUpdates),\n\t\tfetchTable:   getUDP6Table,\n\t\tstates:       make(map[string]map[string]*udpState),\n\t}\n\n\tudp4Table = &udpTable{\n\t\tversion:      4,\n\t\tfetchLimiter: utils.NewCallLimiter2(minDurationBetweenTableUpdates),\n\t\tfetchTable:   getUDP4Table,\n\t\tstates:       make(map[string]map[string]*udpState),\n\t}\n)\n\n// EnableUDPDualStack adds the UDP6 table to the UDP4 table as a dual-stack.\n// Must be called before any lookup operation.\nfunc EnableUDPDualStack() {\n\tudp4Table.dualStack = udp6Table\n}\n\nfunc (table *udpTable) getCurrentTables() (binds []*socket.BindInfo) {\n\ttable.lock.RLock()\n\tdefer table.lock.RUnlock()\n\n\treturn table.binds\n}\n\nfunc (table *udpTable) updateTables() (binds []*socket.BindInfo) {\n\t// Fetch tables.\n\ttable.fetchLimiter.Do(func() {\n\t\t// Fetch new tables from system.\n\t\tbinds, err := table.fetchTable()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"state: failed to get UDP%d socket table: %s\", table.version, err)\n\t\t\treturn\n\t\t}\n\n\t\t// Pre-check for any listeners.\n\t\tfor _, bindInfo := range binds {\n\t\t\tbindInfo.ListensAny = bindInfo.Local.IP.Equal(net.IPv4zero) || bindInfo.Local.IP.Equal(net.IPv6zero)\n\t\t}\n\n\t\t// Apply new tables.\n\t\ttable.lock.Lock()\n\t\tdefer table.lock.Unlock()\n\t\ttable.binds = binds\n\t\ttable.lastUpdateAt.Store(time.Now().UnixNano())\n\t})\n\n\treturn table.getCurrentTables()\n}\n\n// CleanUDPStates cleans the udp connection states which save connection directions.\nfunc CleanUDPStates(_ context.Context) {\n\tnow := time.Now().UTC()\n\n\tudp4Table.updateTables()\n\tudp4Table.cleanStates(now)\n\n\tif netenv.IPv6Enabled() {\n\t\tudp6Table.updateTables()\n\t\tudp6Table.cleanStates(now)\n\t}\n}\n\nfunc (table *udpTable) getConnState(\n\tsocketInfo *socket.BindInfo,\n\tremoteAddress socket.Address,\n) (udpConnState *udpState, ok bool) {\n\ttable.statesLock.Lock()\n\tdefer table.statesLock.Unlock()\n\n\tbindMap, ok := table.states[makeUDPStateKey(socketInfo.Local)]\n\tif ok {\n\t\tudpConnState, ok = bindMap[makeUDPStateKey(remoteAddress)]\n\t\treturn\n\t}\n\n\treturn nil, false\n}\n\nfunc (table *udpTable) getDirection(\n\tsocketInfo *socket.BindInfo,\n\tpktInfo *packet.Info,\n) (connDirection bool) {\n\ttable.statesLock.Lock()\n\tdefer table.statesLock.Unlock()\n\n\tlocalKey := makeUDPStateKey(socketInfo.Local)\n\n\tbindMap, ok := table.states[localKey]\n\tif !ok {\n\t\tbindMap = make(map[string]*udpState)\n\t\ttable.states[localKey] = bindMap\n\t}\n\n\tremoteKey := makeUDPStateKey(socket.Address{\n\t\tIP:   pktInfo.RemoteIP(),\n\t\tPort: pktInfo.RemotePort(),\n\t})\n\tudpConnState, ok := bindMap[remoteKey]\n\tif !ok {\n\t\tbindMap[remoteKey] = &udpState{\n\t\t\tinbound:  pktInfo.Inbound,\n\t\t\tlastSeen: time.Now().UTC(),\n\t\t}\n\t\treturn pktInfo.Inbound\n\t}\n\n\tudpConnState.lastSeen = time.Now().UTC()\n\treturn udpConnState.inbound\n}\n\nfunc (table *udpTable) cleanStates(now time.Time) {\n\t// compute thresholds\n\tthreshold := now.Add(-UDPConnStateTTL)\n\tshortThreshhold := now.Add(-UDPConnStateShortenedTTL)\n\n\t// make lookup map of all active keys\n\tbindKeys := make(map[string]struct{})\n\ttable.lock.RLock()\n\tfor _, socketInfo := range table.binds {\n\t\tbindKeys[makeUDPStateKey(socketInfo.Local)] = struct{}{}\n\t}\n\ttable.lock.RUnlock()\n\n\ttable.statesLock.Lock()\n\tdefer table.statesLock.Unlock()\n\n\t// clean the udp state storage\n\tfor localKey, bindMap := range table.states {\n\t\tif _, active := bindKeys[localKey]; active {\n\t\t\t// clean old entries\n\t\t\tfor remoteKey, udpConnState := range bindMap {\n\t\t\t\tif udpConnState.lastSeen.Before(threshold) {\n\t\t\t\t\tdelete(bindMap, remoteKey)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// if there are too many clean more aggressively\n\t\t\tif len(bindMap) > AggressiveCleaningThreshold {\n\t\t\t\tfor remoteKey, udpConnState := range bindMap {\n\t\t\t\t\tif udpConnState.lastSeen.Before(shortThreshhold) {\n\t\t\t\t\t\tdelete(bindMap, remoteKey)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// delete the whole thing\n\t\t\tdelete(table.states, localKey)\n\t\t}\n\t}\n}\n\nfunc makeUDPStateKey(address socket.Address) string {\n\t// This could potentially go wrong, but as all IPs are created by the same source, everything should be fine.\n\treturn string(address.IP) + strconv.Itoa(int(address.Port))\n}\n"
  },
  {
    "path": "service/network/status.go",
    "content": "package network\n\n// Verdict describes the decision made about a connection or link.\ntype Verdict int8\n\n// All possible verdicts that can be applied to a network\n// connection.\nconst (\n\t// VerdictUndecided is the default status of new connections.\n\tVerdictUndecided           Verdict = 0\n\tVerdictUndeterminable      Verdict = 1\n\tVerdictAccept              Verdict = 2\n\tVerdictBlock               Verdict = 3\n\tVerdictDrop                Verdict = 4\n\tVerdictRerouteToNameserver Verdict = 5\n\tVerdictRerouteToTunnel     Verdict = 6\n\tVerdictFailed              Verdict = 7\n)\n\nfunc (v Verdict) String() string {\n\tswitch v {\n\tcase VerdictUndecided:\n\t\treturn \"<Undecided>\"\n\tcase VerdictUndeterminable:\n\t\treturn \"<Undeterminable>\"\n\tcase VerdictAccept:\n\t\treturn \"Accept\"\n\tcase VerdictBlock:\n\t\treturn \"Block\"\n\tcase VerdictDrop:\n\t\treturn \"Drop\"\n\tcase VerdictRerouteToNameserver:\n\t\treturn \"RerouteToNameserver\"\n\tcase VerdictRerouteToTunnel:\n\t\treturn \"RerouteToTunnel\"\n\tcase VerdictFailed:\n\t\treturn \"Failed\"\n\tdefault:\n\t\treturn \"<INVALID VERDICT>\"\n\t}\n}\n\n// Verb returns the verdict as a past tense verb.\nfunc (v Verdict) Verb() string {\n\tswitch v {\n\tcase VerdictUndecided:\n\t\treturn \"undecided\"\n\tcase VerdictUndeterminable:\n\t\treturn \"undeterminable\"\n\tcase VerdictAccept:\n\t\treturn \"accepted\"\n\tcase VerdictBlock:\n\t\treturn \"blocked\"\n\tcase VerdictDrop:\n\t\treturn \"dropped\"\n\tcase VerdictRerouteToNameserver:\n\t\treturn \"redirected to nameserver\"\n\tcase VerdictRerouteToTunnel:\n\t\treturn \"tunneled\"\n\tcase VerdictFailed:\n\t\treturn \"failed\"\n\tdefault:\n\t\treturn \"invalid\"\n\t}\n}\n\n// Packet Directions.\nconst (\n\tInbound  = true\n\tOutbound = false\n)\n\n// Non-Domain Scopes.\nconst (\n\tIncomingHost     = \"IH\"\n\tIncomingLAN      = \"IL\"\n\tIncomingInternet = \"II\"\n\tIncomingInvalid  = \"IX\"\n\tPeerHost         = \"PH\"\n\tPeerLAN          = \"PL\"\n\tPeerInternet     = \"PI\"\n\tPeerInvalid      = \"PX\"\n)\n"
  },
  {
    "path": "service/process/api.go",
    "content": "package process\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Get Process Tag Metadata\",\n\t\tDescription: \"Get information about process tags.\",\n\t\tPath:        \"process/tags\",\n\t\tRead:        api.PermitUser,\n\t\tStructFunc:  handleProcessTagMetadata,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Get Processes by Profile\",\n\t\tDescription: \"Get all recently active processes using the given profile\",\n\t\tPath:        \"process/list/by-profile/{source:[a-z]+}/{id:[A-z0-9-]+}\",\n\t\tRead:        api.PermitUser,\n\t\tStructFunc:  handleGetProcessesByProfile,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Get Process Group Leader By PID\",\n\t\tDescription: \"Load a process group leader by a child PID\",\n\t\tPath:        \"process/group-leader/{pid:[0-9]+}\",\n\t\tRead:        api.PermitUser,\n\t\tStructFunc:  handleGetProcessGroupLeader,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleProcessTagMetadata(ar *api.Request) (i interface{}, err error) {\n\ttagRegistryLock.Lock()\n\tdefer tagRegistryLock.Unlock()\n\n\t// Create response struct.\n\tresp := struct {\n\t\tTags []TagDescription\n\t}{\n\t\tTags: make([]TagDescription, 0, len(tagRegistry)*2),\n\t}\n\n\t// Get all tag descriptions.\n\tfor _, th := range tagRegistry {\n\t\tresp.Tags = append(resp.Tags, th.TagDescriptions()...)\n\t}\n\n\treturn resp, nil\n}\n\nfunc handleGetProcessesByProfile(ar *api.Request) (any, error) {\n\tsource := ar.URLVars[\"source\"]\n\tid := ar.URLVars[\"id\"]\n\tif id == \"\" || source == \"\" {\n\t\treturn nil, api.ErrorWithStatus(errors.New(\"missing profile source/id\"), http.StatusBadRequest)\n\t}\n\n\tresult := GetProcessesWithProfile(ar.Context(), profile.ProfileSource(source), id, true)\n\treturn result, nil\n}\n\nfunc handleGetProcessGroupLeader(ar *api.Request) (any, error) {\n\tpid, err := strconv.ParseInt(ar.URLVars[\"pid\"], 10, 0)\n\tif err != nil {\n\t\treturn nil, api.ErrorWithStatus(err, http.StatusBadRequest)\n\t}\n\n\tprocess, err := GetOrFindProcess(ar.Context(), int(pid))\n\tif err != nil {\n\t\treturn nil, api.ErrorWithStatus(err, http.StatusInternalServerError)\n\t}\n\terr = process.FindProcessGroupLeader(ar.Context())\n\tswitch {\n\tcase process.Leader() != nil:\n\t\treturn process.Leader(), nil\n\tcase err != nil:\n\t\treturn nil, api.ErrorWithStatus(err, http.StatusInternalServerError)\n\tdefault:\n\t\treturn nil, api.ErrorWithStatus(errors.New(\"leader not found\"), http.StatusNotFound)\n\t}\n}\n"
  },
  {
    "path": "service/process/config.go",
    "content": "package process\n\nimport (\n\t\"github.com/safing/portmaster/base/config\"\n)\n\n// Configuration Keys.\nvar (\n\tCfgOptionEnableProcessDetectionKey = \"core/enableProcessDetection\"\n\n\tenableProcessDetection config.BoolOption\n)\n\nfunc registerConfiguration() error {\n\t// Enable Process Detection\n\t// This should be always enabled. Provided as an option to disable in case there are severe problems on a system, or for debugging.\n\terr := config.Register(&config.Option{\n\t\tName:           \"Process Detection\",\n\t\tKey:            CfgOptionEnableProcessDetectionKey,\n\t\tDescription:    \"This option enables the attribution of network traffic to processes. Without it, app settings are effectively disabled.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: 528,\n\t\t\tconfig.CategoryAnnotation:     \"Development\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tenableProcessDetection = config.Concurrent.GetAsBool(CfgOptionEnableProcessDetectionKey, true)\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/process/database.go",
    "content": "package process\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tprocessInfo \"github.com/shirou/gopsutil/process\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\nconst processDatabaseNamespace = \"network:tree\"\n\nvar (\n\tprocesses     = make(map[string]*Process)\n\tprocessesLock sync.RWMutex\n\n\tdbController     *database.Controller\n\tdbControllerFlag = abool.NewBool(false)\n\n\tdeleteProcessesThreshold = 7 * time.Minute\n)\n\n// GetProcessFromStorage returns a process from the internal storage.\nfunc GetProcessFromStorage(key string) (*Process, bool) {\n\tprocessesLock.RLock()\n\tdefer processesLock.RUnlock()\n\n\tp, ok := processes[key]\n\treturn p, ok\n}\n\n// All returns a copy of all process objects.\nfunc All() map[int]*Process {\n\tprocessesLock.RLock()\n\tdefer processesLock.RUnlock()\n\n\tall := make(map[int]*Process)\n\tfor _, proc := range processes {\n\t\tall[proc.Pid] = proc\n\t}\n\n\treturn all\n}\n\n// GetProcessesWithProfile returns all processes that use the given profile.\n// If preferProcessGroupLeader is set, it returns the process group leader instead, if available.\nfunc GetProcessesWithProfile(ctx context.Context, profileSource profile.ProfileSource, profileID string, preferProcessGroupLeader bool) []*Process {\n\tlog.Tracer(ctx).Debugf(\"process: searching for processes belonging to %s\", profile.MakeScopedID(profileSource, profileID))\n\n\t// Get all processes that match the given profile.\n\tprocs := make([]*Process, 0, 8)\n\tfor _, p := range All() {\n\t\tlp := p.profile.LocalProfile()\n\t\tif lp != nil && lp.Source == profileSource && lp.ID == profileID {\n\t\t\tif preferProcessGroupLeader && p.Leader() != nil {\n\t\t\t\tprocs = append(procs, p.Leader())\n\t\t\t} else {\n\t\t\t\tprocs = append(procs, p)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Sort and compact.\n\tslices.SortFunc[[]*Process, *Process](procs, func(a, b *Process) int {\n\t\treturn strings.Compare(a.processKey, b.processKey)\n\t})\n\n\tprocs = slices.CompactFunc[[]*Process, *Process](procs, func(a, b *Process) bool {\n\t\treturn a.processKey == b.processKey\n\t})\n\n\treturn procs\n}\n\n// Save saves the process to the internal state and pushes an update.\nfunc (p *Process) Save() {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\tp.UpdateMeta()\n\n\tif p.processKey == \"\" {\n\t\tp.processKey = getProcessKey(int32(p.Pid), p.CreatedAt)\n\t}\n\n\tif !p.KeyIsSet() {\n\t\t// set key\n\t\tp.SetKey(fmt.Sprintf(\"%s/%s\", processDatabaseNamespace, p.processKey))\n\n\t\t// save\n\t\tprocessesLock.Lock()\n\t\tprocesses[p.processKey] = p\n\t\tprocessesLock.Unlock()\n\t}\n\n\tif dbControllerFlag.IsSet() {\n\t\tdbController.PushUpdate(p)\n\t}\n}\n\n// Delete deletes a process from the storage and propagates the change.\nfunc (p *Process) Delete() {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\t// delete from internal storage\n\tprocessesLock.Lock()\n\tdelete(processes, p.processKey)\n\tprocessesLock.Unlock()\n\n\t// propagate delete\n\tp.Meta().Delete()\n\tif dbControllerFlag.IsSet() {\n\t\tdbController.PushUpdate(p)\n\t}\n\n\t// TODO: maybe mark the assigned profiles as no longer needed?\n}\n\n// CleanProcessStorage cleans the storage from old processes.\nfunc CleanProcessStorage(activePIDs map[int]struct{}) {\n\t// add system table of processes\n\tpids, err := processInfo.Pids()\n\tif err != nil {\n\t\tlog.Warningf(\"process: failed to get list of active PIDs: %s\", err)\n\t} else {\n\t\tfor _, pid := range pids {\n\t\t\tactivePIDs[int(pid)] = struct{}{}\n\t\t}\n\t}\n\n\tprocessesCopy := All()\n\tthreshold := time.Now().Add(-deleteProcessesThreshold).Unix()\n\n\t// clean primary processes\n\tfor _, p := range processesCopy {\n\t\t// The PID of a process does not change.\n\n\t\t// Check if this is a special process.\n\t\tswitch p.Pid {\n\t\tcase UnidentifiedProcessID, UnsolicitedProcessID, SystemProcessID:\n\t\t\tp.profile.MarkStillActive()\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check if process is active.\n\t\t_, active := activePIDs[p.Pid]\n\t\tif active {\n\t\t\tp.profile.MarkStillActive()\n\t\t\tcontinue\n\t\t}\n\n\t\t// Process is inactive, start deletion process\n\t\tlastSeen := p.GetLastSeen()\n\t\tswitch {\n\t\tcase lastSeen == 0:\n\t\t\t// add last seen timestamp\n\t\t\tp.SetLastSeen(time.Now().Unix())\n\t\tcase lastSeen > threshold:\n\t\t\t// within keep period\n\t\tdefault:\n\t\t\t// delete now\n\t\t\tp.Delete()\n\t\t\tlog.Tracef(\"process: cleaned %s\", p.DatabaseKey())\n\t\t}\n\t}\n}\n\n// SetDBController sets the database controller and allows the package to push database updates on a save. It must be set by the package that registers the \"network\" database.\nfunc SetDBController(controller *database.Controller) {\n\tdbController = controller\n\tdbControllerFlag.Set()\n}\n"
  },
  {
    "path": "service/process/doc.go",
    "content": "// Package process fetches process and socket information from the operating system.\n// It can find the process owning a network connection.\npackage process\n"
  },
  {
    "path": "service/process/executable.go",
    "content": "package process\n\nimport (\n\t\"crypto\"\n\t\"encoding/hex\"\n\t\"hash\"\n\t\"io\"\n\t\"os\"\n)\n\n// GetExecHash returns the hash of the executable with the given algorithm.\nfunc (p *Process) GetExecHash(algorithm string) (string, error) {\n\tsum, ok := p.ExecHashes[algorithm]\n\tif ok {\n\t\treturn sum, nil\n\t}\n\n\tvar hasher hash.Hash\n\tswitch algorithm {\n\tcase \"md5\":\n\t\thasher = crypto.MD5.New()\n\tcase \"sha1\":\n\t\thasher = crypto.SHA1.New()\n\tcase \"sha256\":\n\t\thasher = crypto.SHA256.New()\n\t}\n\n\tfile, err := os.Open(p.Path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer func() {\n\t\t_ = file.Close()\n\t}()\n\n\t_, err = io.Copy(hasher, file)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tsum = hex.EncodeToString(hasher.Sum(nil))\n\tp.ExecHashes[algorithm] = sum\n\treturn sum, nil\n}\n"
  },
  {
    "path": "service/process/find.go",
    "content": "package process\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/service/network/reference\"\n\t\"github.com/safing/portmaster/service/network/state\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\n// GetProcessWithProfile returns the process, including the profile.\n// Always returns valid data.\n// Errors are logged and returned for information or special handling purposes.\nfunc GetProcessWithProfile(ctx context.Context, pid int) (process *Process, err error) {\n\tif !enableProcessDetection() {\n\t\tlog.Tracer(ctx).Tracef(\"process: process detection disabled\")\n\t\treturn GetUnidentifiedProcess(ctx), nil\n\t}\n\n\tprocess, err = GetOrFindProcess(ctx, pid)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Debugf(\"process: failed to find process with PID: %s\", err)\n\t\treturn GetUnidentifiedProcess(ctx), err\n\t}\n\n\t// Get process group leader, which is the process \"nearest\" to the user and\n\t// will have more/better information for finding names ans icons, for example.\n\terr = process.FindProcessGroupLeader(ctx)\n\tif err != nil {\n\t\tlog.Warningf(\"process: failed to get process group leader for %s: %s\", process, err)\n\t}\n\n\tchanged, err := process.GetProfile(ctx)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Errorf(\"process: failed to get profile for process %s: %s\", process, err)\n\t}\n\n\tif changed {\n\t\tprocess.Save()\n\t}\n\n\treturn process, nil\n}\n\n// GetPidOfConnection returns the PID of the process that owns the described connection.\n// Always returns valid data.\n// Errors are logged and returned for information or special handling purposes.\nfunc GetPidOfConnection(ctx context.Context, pktInfo *packet.Info) (pid int, connInbound bool, err error) {\n\tif !enableProcessDetection() {\n\t\treturn UnidentifiedProcessID, pktInfo.Inbound, nil\n\t}\n\n\t// Use fast search for inbound packets, as the listening socket should\n\t// already be there for a while now.\n\tfastSearch := pktInfo.Inbound\n\tconnInbound = pktInfo.Inbound\n\n\t// Check if we need to get the PID.\n\tif pktInfo.PID == UndefinedProcessID {\n\t\tlog.Tracer(ctx).Tracef(\"process: getting pid from system network state\")\n\t\tpid, connInbound, err = state.Lookup(pktInfo, fastSearch)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"failed to find PID of connection: %w\", err)\n\t\t\tlog.Tracer(ctx).Tracef(\"process: %s\", err)\n\t\t\tpid = UndefinedProcessID\n\t\t}\n\t} else {\n\t\tlog.Tracer(ctx).Tracef(\"process: pid already set in packet (by ebpf or kext)\")\n\t\tpid = pktInfo.PID\n\t}\n\n\t// Fallback to special profiles if PID could not be found.\n\tif pid == UndefinedProcessID {\n\t\tswitch {\n\t\tcase !connInbound:\n\t\t\tpid = UnidentifiedProcessID\n\n\t\tcase netutils.ClassifyIP(pktInfo.Dst).IsLocalhost():\n\t\t\t// Always treat localhost connections as unidentified/unknown.\n\t\t\tpid = UnidentifiedProcessID\n\n\t\tcase reference.IsICMP(uint8(pktInfo.Protocol)):\n\t\t\t// Always treat ICMP as unidentified/unknown, as the direction\n\t\t\t// might change to outgoing by new ICMP echo packets.\n\t\t\tpid = UnidentifiedProcessID\n\n\t\tdefault:\n\t\t\t// All other inbound connections are \"unsolicited\".\n\t\t\tpid = UnsolicitedProcessID\n\t\t}\n\t}\n\n\treturn pid, connInbound, err\n}\n\n// GetNetworkHost returns a *Process that represents a host on the network.\nfunc GetNetworkHost(ctx context.Context, remoteIP net.IP) (process *Process, err error) { //nolint:interfacer\n\tnow := time.Now().Unix()\n\tnetworkHost := &Process{\n\t\tName:      fmt.Sprintf(\"Device at %s\", remoteIP),\n\t\tUserName:  \"N/A\",\n\t\tUserID:    NetworkHostProcessID,\n\t\tPid:       NetworkHostProcessID,\n\t\tParentPid: NetworkHostProcessID,\n\t\tTags: []profile.Tag{\n\t\t\t{\n\t\t\t\tKey:   \"ip\",\n\t\t\t\tValue: remoteIP.String(),\n\t\t\t},\n\t\t},\n\t\tFirstSeen: now,\n\t\tLastSeen:  now,\n\t}\n\n\t// Get the (linked) local profile.\n\tnetworkHostProfile, err := profile.GetLocalProfile(\"\", networkHost.MatchingData(), networkHost.CreateProfileCallback)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Assign profile to process.\n\tnetworkHost.PrimaryProfileID = networkHostProfile.ScopedID()\n\tnetworkHost.profile = networkHostProfile.LayeredProfile()\n\n\treturn networkHost, nil\n}\n\n// GetProcessByRequestOrigin returns the process that initiated the API request ar.\nfunc GetProcessByRequestOrigin(ar *api.Request) (*Process, error) {\n\t// get remote IP/Port\n\tremoteIP, remotePort, err := netutils.ParseIPPort(ar.RemoteAddr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get remote IP/Port: %w\", err)\n\t}\n\n\tpkt := &packet.Info{\n\t\tInbound:  false, // outbound as we are looking for the process of the source address\n\t\tVersion:  packet.IPv4,\n\t\tProtocol: packet.TCP,\n\t\tSrc:      remoteIP,   // source as in the process we are looking for\n\t\tSrcPort:  remotePort, // source as in the process we are looking for\n\t\tPID:      UndefinedProcessID,\n\t}\n\n\tpid, _, err := GetPidOfConnection(ar.Context(), pkt)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tproc, err := GetProcessWithProfile(ar.Context(), pid)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn proc, nil\n}\n"
  },
  {
    "path": "service/process/module.go",
    "content": "package process\n\nimport (\n\t\"errors\"\n\t\"runtime\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype ProcessModule struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tportmasterUIPath string\n}\n\nfunc (pm *ProcessModule) Manager() *mgr.Manager {\n\treturn pm.mgr\n}\n\nfunc (pm *ProcessModule) Start() error {\n\tidentifier := \"portmaster\"\n\tif runtime.GOOS == \"windows\" {\n\t\tidentifier += \".exe\"\n\t}\n\n\tfile, err := pm.instance.BinaryUpdates().GetFile(identifier)\n\tif err != nil {\n\t\tlog.Errorf(\"process: failed to get path of ui: %s\", err)\n\t} else {\n\t\tpm.portmasterUIPath = file.Path()\n\t}\n\treturn nil\n}\n\nfunc (pm *ProcessModule) Stop() error {\n\treturn nil\n}\n\nfunc prep() error {\n\tif err := registerConfiguration(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerAPIEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nvar (\n\tmodule     *ProcessModule\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Process module.\nfunc New(instance instance) (*ProcessModule, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"ProcessModule\")\n\tmodule = &ProcessModule{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tBinaryUpdates() *updates.Updater\n}\n"
  },
  {
    "path": "service/process/process.go",
    "content": "package process\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tprocessInfo \"github.com/shirou/gopsutil/process\"\n\t\"golang.org/x/sync/singleflight\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\nconst onLinux = runtime.GOOS == \"linux\"\n\nvar getProcessSingleInflight singleflight.Group\n\n// A Process represents a process running on the operating system.\ntype Process struct {\n\trecord.Base\n\tsync.Mutex\n\n\t// Process attributes.\n\t// Don't change; safe for concurrent access.\n\n\tName     string\n\tUserID   int\n\tUserName string\n\tUserHome string\n\n\tPid       int\n\tCreatedAt int64\n\n\tParentPid       int\n\tParentCreatedAt int64\n\n\tLeaderPid int\n\tleader    *Process\n\n\tPath     string\n\tExecName string\n\tCwd      string\n\tCmdLine  string\n\tFirstArg string\n\tEnv      map[string]string\n\n\t// unique process identifier (\"Pid-CreatedAt\")\n\tprocessKey string\n\n\t// Profile attributes.\n\t// Once set, these don't change; safe for concurrent access.\n\n\t// Tags holds extended information about the (virtual) process, which is used\n\t// to find a profile.\n\tTags []profile.Tag\n\t// MatchingPath holds an alternative binary path that can be used to find a\n\t// profile.\n\tMatchingPath string\n\n\t// PrimaryProfileID holds the scoped ID of the primary profile.\n\tPrimaryProfileID string\n\t// profile holds the layered profile based on the primary profile.\n\tprofile *profile.LayeredProfile\n\n\t// Mutable attributes.\n\n\tFirstSeen int64\n\tLastSeen  int64\n\tError     string // Cache errors\n\n\tExecHashes map[string]string\n}\n\n// GetTag returns the process tag with the given ID.\nfunc (p *Process) GetTag(tagID string) (profile.Tag, bool) {\n\tfor _, t := range p.Tags {\n\t\tif t.Key == tagID {\n\t\t\treturn t, true\n\t\t}\n\t}\n\treturn profile.Tag{}, false\n}\n\n// Profile returns the assigned layered profile.\nfunc (p *Process) Profile() *profile.LayeredProfile {\n\tif p == nil {\n\t\treturn nil\n\t}\n\n\treturn p.profile\n}\n\n// Leader returns the process group leader that is attached to the process.\n// This will not trigger a new search for the process group leader, it only\n// returns existing data.\nfunc (p *Process) Leader() *Process {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\treturn p.leader\n}\n\n// IsIdentified returns whether the process has been identified or if it\n// represents some kind of unidentified process.\nfunc (p *Process) IsIdentified() bool {\n\t// Check if process exists.\n\tif p == nil {\n\t\treturn false\n\t}\n\n\t// Check for special PIDs.\n\tswitch p.Pid {\n\tcase UndefinedProcessID:\n\t\treturn false\n\tcase UnidentifiedProcessID:\n\t\treturn false\n\tcase UnsolicitedProcessID:\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\n// HasValidPID returns whether the process has valid PID of an actual process.\nfunc (p *Process) HasValidPID() bool {\n\t// Check if process exists.\n\tif p == nil {\n\t\treturn false\n\t}\n\n\treturn p.Pid >= 0\n}\n\n// Equal returns if the two processes are both identified and have the same PID.\nfunc (p *Process) Equal(other *Process) bool {\n\treturn p.IsIdentified() && other.IsIdentified() && p.Pid == other.Pid\n}\n\nconst systemResolverScopedID = string(profile.SourceLocal) + \"/\" + profile.SystemResolverProfileID\n\n// IsSystemResolver is a shortcut to check if the process is or belongs to the\n// system resolver and needs special handling.\nfunc (p *Process) IsSystemResolver() bool {\n\t// Check if process exists.\n\tif p == nil {\n\t\treturn false\n\t}\n\n\t// Check ID.\n\treturn p.PrimaryProfileID == systemResolverScopedID\n}\n\n// GetLastSeen returns the unix timestamp when the process was last seen.\nfunc (p *Process) GetLastSeen() int64 {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\treturn p.LastSeen\n}\n\n// SetLastSeen sets the unix timestamp when the process was last seen.\nfunc (p *Process) SetLastSeen(lastSeen int64) {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\tp.LastSeen = lastSeen\n}\n\n// String returns a string representation of process.\nfunc (p *Process) String() string {\n\tif p == nil {\n\t\treturn \"?\"\n\t}\n\n\treturn fmt.Sprintf(\"%s:%s:%d\", p.UserName, p.Path, p.Pid)\n}\n\n// GetOrFindProcess returns the process for the given PID.\nfunc GetOrFindProcess(ctx context.Context, pid int) (*Process, error) {\n\tlog.Tracer(ctx).Tracef(\"process: getting process for PID %d\", pid)\n\n\t// Check for special processes\n\tswitch pid {\n\tcase UnidentifiedProcessID:\n\t\treturn GetUnidentifiedProcess(ctx), nil\n\tcase UnsolicitedProcessID:\n\t\treturn GetUnsolicitedProcess(ctx), nil\n\tcase SystemProcessID:\n\t\treturn GetSystemProcess(ctx), nil\n\t}\n\n\t// Get pid and creation time for identification.\n\tpInfo, err := processInfo.NewProcessWithContext(ctx, int32(pid))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcreatedAt, err := pInfo.CreateTimeWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkey := getProcessKey(int32(pid), createdAt)\n\n\t// Load process and make sure it is only loaded once.\n\tp, err, _ := getProcessSingleInflight.Do(key, func() (interface{}, error) {\n\t\treturn loadProcess(ctx, key, pInfo)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif p == nil {\n\t\treturn nil, errors.New(\"process getter returned nil\")\n\t}\n\n\treturn p.(*Process), nil // nolint:forcetypeassert // Can only be a *Process.\n}\n\nfunc loadProcess(ctx context.Context, key string, pInfo *processInfo.Process) (*Process, error) {\n\t// Check if we already have the process.\n\tprocess, ok := GetProcessFromStorage(key)\n\tif ok {\n\t\treturn process, nil\n\t}\n\n\t// Create new a process object.\n\tprocess = &Process{\n\t\tPid:        int(pInfo.Pid),\n\t\tFirstSeen:  time.Now().Unix(),\n\t\tprocessKey: key,\n\t}\n\n\t// Get creation time of process. (The value should be cached by the library.)\n\tvar err error\n\tprocess.CreatedAt, err = pInfo.CreateTimeWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// UID\n\t// TODO: implemented for windows\n\tif onLinux {\n\t\tvar uids []int32\n\t\tuids, err = pInfo.UidsWithContext(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get UID for p%d: %w\", pInfo.Pid, err)\n\t\t}\n\t\tprocess.UserID = int(uids[0])\n\t}\n\n\t// Username\n\tprocess.UserName, err = pInfo.UsernameWithContext(ctx)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Warningf(\"process: failed to get username (PID %d): %s\", pInfo.Pid, err)\n\t}\n\n\t// TODO: User Home\n\t// new.UserHome, err =\n\n\t// Parent process ID\n\tppid, err := pInfo.PpidWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get PPID for p%d: %w\", pInfo.Pid, err)\n\t}\n\tprocess.ParentPid = int(ppid)\n\n\t// Parent created time\n\tparentPInfo, err := processInfo.NewProcessWithContext(ctx, ppid)\n\tif err == nil {\n\t\tparentCreatedAt, err := parentPInfo.CreateTimeWithContext(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tprocess.ParentCreatedAt = parentCreatedAt\n\t}\n\n\t// Leader process ID\n\t// Get process group ID to find group leader, which is the process \"nearest\"\n\t// to the user and will have more/better information for finding names and\n\t// icons, for example.\n\tleaderPid, err := GetProcessGroupID(ctx, process.Pid)\n\tif err != nil {\n\t\t// Fail gracefully.\n\t\tlog.Warningf(\"process: failed to get process group ID for p%d: %s\", process.Pid, err)\n\t\tprocess.LeaderPid = UndefinedProcessID\n\t} else {\n\t\tprocess.LeaderPid = leaderPid\n\t}\n\n\t// Path\n\tprocess.Path, err = pInfo.ExeWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get Path for p%d: %w\", pInfo.Pid, err)\n\t}\n\t// remove linux \" (deleted)\" suffix for deleted files\n\tif onLinux {\n\t\tprocess.Path = strings.TrimSuffix(process.Path, \" (deleted)\")\n\t}\n\t// Executable Name\n\t_, process.ExecName = filepath.Split(process.Path)\n\n\t// Current working directory\n\t// not yet implemented for windows\n\tif runtime.GOOS != \"windows\" {\n\t\tprocess.Cwd, err = pInfo.CwdWithContext(ctx)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"process: failed to get current working dir (PID %d): %s\", pInfo.Pid, err)\n\t\t}\n\t}\n\n\t// Command line arguments\n\tprocess.CmdLine, err = pInfo.CmdlineWithContext(ctx)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Warningf(\"process: failed to get cmdline (PID %d): %s\", pInfo.Pid, err)\n\t}\n\n\t// Name\n\tprocess.Name, err = pInfo.NameWithContext(ctx)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Warningf(\"process: failed to get process name (PID %d): %s\", pInfo.Pid, err)\n\t}\n\tif process.Name == \"\" {\n\t\tprocess.Name = process.ExecName\n\t}\n\n\t// Get all environment variables\n\tenv, err := pInfo.EnvironWithContext(ctx)\n\tif err == nil {\n\t\t// Split env variables in key and value.\n\t\tprocess.Env = make(map[string]string, len(env))\n\t\tfor _, entry := range env {\n\t\t\tsplitted := strings.SplitN(entry, \"=\", 2)\n\t\t\tif len(splitted) == 2 {\n\t\t\t\tprocess.Env[strings.Trim(splitted[0], `'\"`)] = strings.Trim(splitted[1], `'\"`)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tlog.Tracer(ctx).Warningf(\"process: failed to get the process environment (PID %d): %s\", pInfo.Pid, err)\n\t}\n\n\t// Add process tags.\n\tprocess.addTags()\n\tif len(process.Tags) > 0 {\n\t\tlog.Tracer(ctx).Debugf(\"profile: added tags: %+v\", process.Tags)\n\t}\n\n\tprocess.Save()\n\treturn process, nil\n}\n\n// GetKey returns the key that is used internally to identify the process.\n// The key consists of the PID and the start time of the process as reported by\n// the system.\nfunc (p *Process) GetKey() string {\n\treturn p.processKey\n}\n\n// Builds a unique identifier for a processes.\nfunc getProcessKey(pid int32, createdTime int64) string {\n\treturn fmt.Sprintf(\"%d-%d\", pid, createdTime)\n}\n\n// MatchingData returns the matching data for the process.\nfunc (p *Process) MatchingData() *MatchingData {\n\treturn &MatchingData{p}\n}\n\n// MatchingData provides a interface compatible view on the process for profile matching.\ntype MatchingData struct {\n\tp *Process\n}\n\n// Tags returns process.Tags.\nfunc (md *MatchingData) Tags() []profile.Tag { return md.p.Tags }\n\n// Env returns process.Env.\nfunc (md *MatchingData) Env() map[string]string { return md.p.Env }\n\n// Path returns process.Path.\nfunc (md *MatchingData) Path() string { return md.p.Path }\n\n// MatchingPath returns process.MatchingPath.\nfunc (md *MatchingData) MatchingPath() string { return md.p.MatchingPath }\n\n// Cmdline returns the command line of the process.\nfunc (md *MatchingData) Cmdline() string { return md.p.CmdLine }\n"
  },
  {
    "path": "service/process/process_default.go",
    "content": "//go:build !windows && !linux\n// +build !windows,!linux\n\npackage process\n\nimport (\n\t\"context\"\n)\n\n// SystemProcessID is the PID of the System/Kernel itself.\nconst SystemProcessID = 0\n\n// GetProcessGroupLeader returns the process that leads the process group.\n// Returns nil on unsupported platforms.\nfunc (p *Process) FindProcessGroupLeader(ctx context.Context) error {\n\treturn nil\n}\n\n// GetProcessGroupID returns the process group ID of the given PID.\n// Returns undefined process ID on unsupported platforms.\nfunc GetProcessGroupID(ctx context.Context, pid int) (int, error) {\n\treturn UndefinedProcessID, nil\n}\n"
  },
  {
    "path": "service/process/process_linux.go",
    "content": "package process\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"syscall\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst (\n\t// SystemProcessID is the PID of the System/Kernel itself.\n\tSystemProcessID = 0\n\n\t// SystemInitID is the PID of the system init process.\n\tSystemInitID = 1\n)\n\n// FindProcessGroupLeader returns the process that leads the process group.\n// Returns nil when process ID is not valid (or virtual).\n// If the process group leader is found, it is set on the process.\n// If that process does not exist anymore, then the highest existing parent process is returned.\n// If an error occurs, the best match is set.\nfunc (p *Process) FindProcessGroupLeader(ctx context.Context) error {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\t// Return the leader if we already have it.\n\tif p.leader != nil {\n\t\treturn nil\n\t}\n\n\t// Check if we have the process group leader PID.\n\tif p.LeaderPid == UndefinedProcessID {\n\t\treturn nil\n\t}\n\n\t// Return nil if we already are the leader.\n\tif p.LeaderPid == p.Pid {\n\t\treturn nil\n\t}\n\n\t// Get process leader process.\n\tleader, err := GetOrFindProcess(ctx, p.LeaderPid)\n\tif err == nil {\n\t\tp.leader = leader\n\t\tlog.Tracer(ctx).Debugf(\"process: found process leader of %d: pid=%d pgid=%d\", p.Pid, leader.Pid, leader.LeaderPid)\n\t\treturn nil\n\t}\n\n\t// If we can't get the process leader process, it has likely already exited.\n\t// In that case, find the highest existing parent process within the process group.\n\tvar (\n\t\tnextParentPid = p.ParentPid\n\t\tlastParent    *Process\n\t)\n\tfor {\n\t\t// Get next parent.\n\t\tparent, err := GetOrFindProcess(ctx, nextParentPid)\n\t\tif err != nil {\n\t\t\tp.leader = lastParent\n\t\t\treturn fmt.Errorf(\"failed to find parent %d: %w\", nextParentPid, err)\n\t\t}\n\n\t\t// Check if we are ready to return.\n\t\tswitch {\n\t\tcase parent.Pid == p.LeaderPid:\n\t\t\t// Found the process group leader!\n\t\t\tp.leader = parent\n\t\t\treturn nil\n\n\t\tcase parent.LeaderPid != p.LeaderPid:\n\t\t\t// We are leaving the process group. Return the previous parent.\n\t\t\tp.leader = lastParent\n\t\t\tlog.Tracer(ctx).Debugf(\"process: found process leader (highest parent) of %d: pid=%d pgid=%d\", p.Pid, parent.Pid, parent.LeaderPid)\n\t\t\treturn nil\n\n\t\tcase parent.ParentPid == SystemProcessID,\n\t\t\tparent.ParentPid == SystemInitID:\n\t\t\t// Next parent is system or init.\n\t\t\t// Use current parent.\n\t\t\tp.leader = parent\n\t\t\tlog.Tracer(ctx).Debugf(\"process: found process leader (highest parent) of %d: pid=%d pgid=%d\", p.Pid, parent.Pid, parent.LeaderPid)\n\t\t\treturn nil\n\t\t}\n\n\t\t// Check next parent.\n\t\tlastParent = parent\n\t\tnextParentPid = parent.ParentPid\n\t}\n}\n\n// GetProcessGroupID returns the process group ID of the given PID.\nfunc GetProcessGroupID(ctx context.Context, pid int) (int, error) {\n\treturn syscall.Getpgid(pid)\n}\n"
  },
  {
    "path": "service/process/process_windows.go",
    "content": "package process\n\nimport (\n\t\"context\"\n)\n\n// SystemProcessID is the PID of the System/Kernel itself.\nconst SystemProcessID = 4\n\n// GetProcessGroupLeader returns the process that leads the process group.\n// Returns nil on Windows, as it does not have process groups.\nfunc (p *Process) FindProcessGroupLeader(ctx context.Context) error {\n\t// TODO: Get \"main\" process of process job object.\n\treturn nil\n}\n\n// GetProcessGroupID returns the process group ID of the given PID.\n// Returns the undefined process ID on Windows, as it does not have process groups.\nfunc GetProcessGroupID(ctx context.Context, pid int) (int, error) {\n\treturn UndefinedProcessID, nil\n}\n"
  },
  {
    "path": "service/process/profile.go",
    "content": "package process\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\nvar ownPID = os.Getpid()\n\n// GetProfile finds and assigns a profile set to the process.\nfunc (p *Process) GetProfile(ctx context.Context) (changed bool, err error) {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\t// Check if profile is already loaded.\n\tif p.profile != nil {\n\t\tlog.Tracer(ctx).Trace(\"process: profile already loaded\")\n\t\treturn\n\t}\n\n\t// If not, continue with loading the profile.\n\tlog.Tracer(ctx).Trace(\"process: loading profile\")\n\n\t// Get special or regular profile.\n\tlocalProfile, err := profile.GetLocalProfile(p.getSpecialProfileID(), p.MatchingData(), p.CreateProfileCallback)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to find profile: %w\", err)\n\t}\n\n\t// Assign profile to process.\n\tp.PrimaryProfileID = localProfile.ScopedID()\n\tp.profile = localProfile.LayeredProfile()\n\n\treturn true, nil\n}\n\n// RefetchProfile removes the profile and finds and assigns a new profile.\nfunc (p *Process) RefetchProfile(ctx context.Context) error {\n\tp.Lock()\n\tdefer p.Unlock()\n\n\t// Get special or regular profile.\n\tlocalProfile, err := profile.GetLocalProfile(p.getSpecialProfileID(), p.MatchingData(), p.CreateProfileCallback)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to find profile: %w\", err)\n\t}\n\n\t// Assign profile to process.\n\tp.PrimaryProfileID = localProfile.ScopedID()\n\tp.profile = localProfile.LayeredProfile()\n\n\treturn nil\n}\n\n// getSpecialProfileID returns the special profile ID for the process, if any.\nfunc (p *Process) getSpecialProfileID() (specialProfileID string) {\n\t// Check if we need a special profile.\n\tswitch p.Pid {\n\tcase UnidentifiedProcessID:\n\t\tspecialProfileID = profile.UnidentifiedProfileID\n\tcase UnsolicitedProcessID:\n\t\tspecialProfileID = profile.UnsolicitedProfileID\n\tcase SystemProcessID:\n\t\tspecialProfileID = profile.SystemProfileID\n\tcase ownPID:\n\t\tspecialProfileID = profile.PortmasterProfileID\n\tdefault:\n\t\t// Check if this is another Portmaster component.\n\t\tif p.IsPortmasterUi(context.Background()) {\n\t\t\tspecialProfileID = profile.PortmasterAppProfileID\n\t\t}\n\t\t// Check if this is the system resolver.\n\t\tswitch runtime.GOOS {\n\t\tcase \"windows\":\n\t\t\t// Depending on the OS version System32 may be capitalized or not.\n\t\t\tif (p.Path == `C:\\Windows\\System32\\svchost.exe` ||\n\t\t\t\tp.Path == `C:\\Windows\\system32\\svchost.exe`) &&\n\t\t\t\t// This comes from the windows tasklist command and should be pretty consistent.\n\t\t\t\t(profile.KeyAndValueInTags(p.Tags, \"svchost\", \"Dnscache\") ||\n\t\t\t\t\t// As an alternative in case of failure, we try to match the svchost.exe service parameter.\n\t\t\t\t\tstrings.Contains(p.CmdLine, \"-s Dnscache\")) {\n\t\t\t\tspecialProfileID = profile.SystemResolverProfileID\n\t\t\t}\n\t\tcase \"linux\":\n\t\t\tswitch p.Path {\n\t\t\tcase \"/lib/systemd/systemd-resolved\",\n\t\t\t\t\"/usr/lib/systemd/systemd-resolved\",\n\t\t\t\t\"/lib64/systemd/systemd-resolved\",\n\t\t\t\t\"/usr/lib64/systemd/systemd-resolved\",\n\t\t\t\t\"/usr/bin/nscd\",\n\t\t\t\t\"/usr/sbin/nscd\",\n\t\t\t\t\"/usr/bin/dnsmasq\",\n\t\t\t\t\"/usr/sbin/dnsmasq\":\n\t\t\t\tspecialProfileID = profile.SystemResolverProfileID\n\t\t\t}\n\t\t}\n\t}\n\n\treturn specialProfileID\n}\n\n// IsPortmasterUi checks if the process is the Portmaster UI or its child (up to 3 parent levels).\nfunc (p *Process) IsPortmasterUi(ctx context.Context) bool {\n\tif module.portmasterUIPath == \"\" {\n\t\treturn false\n\t}\n\n\t// Find parent for up to two levels, if we don't match the path.\n\tconst checkLevels = 3\n\n\tvar previousPid int\n\tproc := p\n\n\thasPmWebviewEnvVar := false\n\n\tfor i := 0; i < checkLevels; i++ {\n\t\tif proc.Pid == UnidentifiedProcessID || proc.Pid == SystemProcessID {\n\t\t\tbreak\n\t\t}\n\n\t\trealPath, err := filepath.EvalSymlinks(proc.Path)\n\t\tif err == nil && realPath == module.portmasterUIPath {\n\t\t\tif runtime.GOOS != \"windows\" {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// On Windows, avoid false positive detection of the Portmaster UI.\n\t\t\t// For example:\n\t\t\t//   There may be cases where a system browser is launched from the Portmaster UI,\n\t\t\t//   making it a child of the Portmaster UI process (e.g., user clicked a link in the UI).\n\t\t\t//   In this case, the parent process tree may look like this:\n\t\t\t//       Portmaster.exe\n\t\t\t//       ├─ WebView  (PM UI)\n\t\t\t//       │   └─ WebView (PM UI child)\n\t\t\t//       └─ System Web Browser ...\n\t\t\t//\n\t\t\t// To ensure that 'p' is the actual Portmaster UI process, we check for the presence\n\t\t\t// of the 'PORTMASTER_UI_WEBVIEW_PROCESS' environment variable in the process and its parents.\n\t\t\t// If the env var is set, we are a child (WebView window) of the Portmaster UI process.\n\t\t\t// Otherwise, the process was launched by the Portmaster UI, but should not be trusted as the Portmaster UI process.\n\t\t\tif i == 0 {\n\t\t\t\treturn true // We are the main Portmaster UI process.\n\t\t\t}\n\t\t\tif hasPmWebviewEnvVar {\n\t\t\t\treturn true // We are a WebView window of the Portmaster UI process.\n\t\t\t}\n\t\t\t// The process was launched by the Portmaster UI, but should not be trusted as the Portmaster UI process.\n\t\t\tlog.Tracer(ctx).Warningf(\"process: %d %q is a child of the Portmaster UI, but does not have the PORTMASTER_UI_WEBVIEW_PROCESS environment variable set. Ignoring.\", p.Pid, p.Path)\n\t\t\treturn false\n\t\t}\n\n\t\t// Check if the process has the environment variable set.\n\t\t//\n\t\t// It is OK to check for the existence of the environment variable in all\n\t\t// processes in the parent chain (on all loop iterations). This increases the\n\t\t// chance of correct detection, even if a child or grandchild WebView process\n\t\t// did not inherit the environment variable for some reason.\n\t\tif _, ok := proc.Env[\"PORTMASTER_UI_WEBVIEW_PROCESS\"]; ok {\n\t\t\thasPmWebviewEnvVar = true\n\t\t}\n\n\t\tif i < checkLevels-1 { // no need to check parent if we are at the last level\n\t\t\tpreviousPid = proc.Pid\n\t\t\tproc, err = GetOrFindProcess(ctx, proc.ParentPid)\n\t\t\tif err != nil || proc.Pid == previousPid {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "service/process/special.go",
    "content": "package process\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"golang.org/x/sync/singleflight\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/socket\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\nconst (\n\t// UndefinedProcessID is not used by any (virtual) process and signifies that\n\t// the PID is unset.\n\tUndefinedProcessID = -1\n\n\t// UnidentifiedProcessID is the PID used for outgoing connections that could\n\t// not be attributed to a PID for any reason.\n\tUnidentifiedProcessID = -2\n\n\t// UnsolicitedProcessID is the PID used for incoming connections that could\n\t// not be attributed to a PID for any reason.\n\tUnsolicitedProcessID = -3\n\n\t// NetworkHostProcessID is the PID used for requests served to the network.\n\tNetworkHostProcessID = -255\n)\n\nfunc init() {\n\t// Check required matching values.\n\tif UndefinedProcessID != socket.UndefinedProcessID {\n\t\tpanic(\"UndefinedProcessID does not match socket.UndefinedProcessID\")\n\t}\n}\n\nvar (\n\t// unidentifiedProcess is used for non-attributed outgoing connections.\n\tunidentifiedProcess = &Process{\n\t\tUserID:     UnidentifiedProcessID,\n\t\tUserName:   \"Unknown\",\n\t\tPid:        UnidentifiedProcessID,\n\t\tParentPid:  UnidentifiedProcessID,\n\t\tName:       profile.UnidentifiedProfileName,\n\t\tprocessKey: getProcessKey(UnidentifiedProcessID, 0),\n\t}\n\n\t// unsolicitedProcess is used for non-attributed incoming connections.\n\tunsolicitedProcess = &Process{\n\t\tUserID:     UnsolicitedProcessID,\n\t\tUserName:   \"Unknown\",\n\t\tPid:        UnsolicitedProcessID,\n\t\tParentPid:  UnsolicitedProcessID,\n\t\tName:       profile.UnsolicitedProfileName,\n\t\tprocessKey: getProcessKey(UnsolicitedProcessID, 0),\n\t}\n\n\t// systemProcess is used to represent the Kernel.\n\tsystemProcess = &Process{\n\t\tUserID:     SystemProcessID,\n\t\tUserName:   \"Kernel\",\n\t\tPid:        SystemProcessID,\n\t\tParentPid:  SystemProcessID,\n\t\tName:       profile.SystemProfileName,\n\t\tprocessKey: getProcessKey(SystemProcessID, 0),\n\t}\n\n\tgetSpecialProcessSingleInflight singleflight.Group\n)\n\n// GetUnidentifiedProcess returns the special process assigned to non-attributed outgoing connections.\nfunc GetUnidentifiedProcess(ctx context.Context) *Process {\n\treturn getSpecialProcess(ctx, unidentifiedProcess)\n}\n\n// GetUnsolicitedProcess returns the special process assigned to non-attributed incoming connections.\nfunc GetUnsolicitedProcess(ctx context.Context) *Process {\n\treturn getSpecialProcess(ctx, unsolicitedProcess)\n}\n\n// GetSystemProcess returns the special process used for the Kernel.\nfunc GetSystemProcess(ctx context.Context) *Process {\n\treturn getSpecialProcess(ctx, systemProcess)\n}\n\nfunc getSpecialProcess(ctx context.Context, template *Process) *Process {\n\tp, _, _ := getSpecialProcessSingleInflight.Do(template.processKey, func() (interface{}, error) {\n\t\t// Check if we have already loaded the special process.\n\t\tprocess, ok := GetProcessFromStorage(template.processKey)\n\t\tif ok {\n\t\t\treturn process, nil\n\t\t}\n\n\t\t// Create new process from template\n\t\tprocess = template\n\t\tprocess.FirstSeen = time.Now().Unix()\n\n\t\t// Get profile.\n\t\t_, err := process.GetProfile(ctx)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Errorf(\"process: failed to get profile for process %s: %s\", process, err)\n\t\t}\n\n\t\t// Save process to storage.\n\t\tprocess.Save()\n\t\treturn process, nil\n\t})\n\treturn p.(*Process) // nolint:forcetypeassert // Can only be a *Process.\n}\n"
  },
  {
    "path": "service/process/tags/appimage_unix.go",
    "content": "package tags\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nfunc init() {\n\terr := process.RegisterTagHandler(new(AppImageHandler))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nconst (\n\tappImageName          = \"AppImage\"\n\tappImagePathTagKey    = \"app-image-path\"\n\tappImageMountIDTagKey = \"app-image-mount-id\"\n)\n\nvar (\n\tappImageMountDirRegex         = regexp.MustCompile(`^/tmp/.mount_[^/]+`)\n\tappImageMountNameExtractRegex = regexp.MustCompile(`^[A-Za-z0-9]+`)\n)\n\n// AppImageHandler handles AppImage processes on Unix systems.\ntype AppImageHandler struct{}\n\n// Name returns the tag handler name.\nfunc (h *AppImageHandler) Name() string {\n\treturn appImageName\n}\n\n// TagDescriptions returns a list of all possible tags and their description\n// of this handler.\nfunc (h *AppImageHandler) TagDescriptions() []process.TagDescription {\n\treturn []process.TagDescription{\n\t\t{\n\t\t\tID:          appImagePathTagKey,\n\t\t\tName:        \"AppImage Path\",\n\t\t\tDescription: \"Path to the app image file itself.\",\n\t\t},\n\t\t{\n\t\t\tID:          appImageMountIDTagKey,\n\t\t\tName:        \"AppImage Mount ID\",\n\t\t\tDescription: \"Extracted ID from the AppImage mount name. Use AppImage Path instead, if available.\",\n\t\t},\n\t}\n}\n\n// AddTags adds tags to the given process.\nfunc (h *AppImageHandler) AddTags(p *process.Process) {\n\t// Detect app image path via ENV vars.\n\tfunc() {\n\t\t// Get and verify AppImage location.\n\t\tappImageLocation, ok := p.Env[\"APPIMAGE\"]\n\t\tif !ok || appImageLocation == \"\" {\n\t\t\treturn\n\t\t}\n\t\tappImageMountDir, ok := p.Env[\"APPDIR\"]\n\t\tif !ok || appImageMountDir == \"\" {\n\t\t\treturn\n\t\t}\n\t\t// Check if the process path is in the mount dir.\n\t\tif !strings.HasPrefix(p.Path, appImageMountDir) {\n\t\t\treturn\n\t\t}\n\n\t\t// Add matching path for regular profile matching.\n\t\tp.MatchingPath = appImageLocation\n\n\t\t// Add app image tag.\n\t\tp.Tags = append(p.Tags, profile.Tag{\n\t\t\tKey:   appImagePathTagKey,\n\t\t\tValue: appImageLocation,\n\t\t})\n\t}()\n\n\t// Detect app image mount point.\n\tfunc() {\n\t\t// Check if binary path matches app image mount pattern.\n\t\tmountDir := appImageMountDirRegex.FindString(p.Path)\n\t\tif mountDir == \"\" {\n\t\t\treturn\n\t\t}\n\n\t\t// Get mount name of mount dir.\n\t\t// Also, this confirm this is actually a mounted dir.\n\t\tmountName, err := getAppImageMountName(mountDir)\n\t\tif err != nil {\n\t\t\tlog.Debugf(\"process/tags: failed to get mount name: %s\", err)\n\t\t\treturn\n\t\t}\n\t\tif mountName == \"\" {\n\t\t\treturn\n\t\t}\n\n\t\t// Extract a usable ID from the mount name.\n\t\tmountName, _ = strings.CutPrefix(mountName, \"gearlever_\")\n\t\tmountName = appImageMountNameExtractRegex.FindString(mountName)\n\t\tif mountName == \"\" {\n\t\t\treturn\n\t\t}\n\n\t\t// Add app image tag.\n\t\tp.Tags = append(p.Tags, profile.Tag{\n\t\t\tKey:   appImageMountIDTagKey,\n\t\t\tValue: mountName,\n\t\t})\n\t}()\n}\n\n// CreateProfile creates a profile based on the tags of the process.\n// Returns nil to skip.\nfunc (h *AppImageHandler) CreateProfile(p *process.Process) *profile.Profile {\n\tif tag, ok := p.GetTag(appImagePathTagKey); ok {\n\t\treturn profile.New(&profile.Profile{\n\t\t\tSource:              profile.SourceLocal,\n\t\t\tName:                binmeta.GenerateBinaryNameFromPath(p.Path),\n\t\t\tPresentationPath:    p.Path,\n\t\t\tUsePresentationPath: true,\n\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t{\n\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\tKey:       tag.Key,\n\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\tValue:     tag.Value, // Value of appImagePathTagKey.\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\tif tag, ok := p.GetTag(appImageMountIDTagKey); ok {\n\t\treturn profile.New(&profile.Profile{\n\t\t\tSource:              profile.SourceLocal,\n\t\t\tName:                binmeta.GenerateBinaryNameFromPath(p.Path),\n\t\t\tPresentationPath:    p.Path,\n\t\t\tUsePresentationPath: true,\n\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t{\n\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\tKey:       tag.Key,\n\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\tValue:     tag.Value, // Value of appImageMountIDTagKey.\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc getAppImageMountName(mountPoint string) (mountName string, err error) {\n\t// Get mounts.\n\tdata, err := os.ReadFile(\"/proc/mounts\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tscanner := bufio.NewScanner(bytes.NewReader(data))\n\tfor scanner.Scan() {\n\t\tfields := strings.Fields(scanner.Text())\n\t\tif len(fields) >= 2 {\n\t\t\tswitch {\n\t\t\tcase fields[1] != mountPoint:\n\t\t\tcase !strings.HasSuffix(strings.ToLower(fields[0]), \".appimage\"):\n\t\t\tdefault:\n\t\t\t\t// Found AppImage mount!\n\t\t\t\treturn fields[0], nil\n\t\t\t}\n\t\t}\n\t}\n\tif scanner.Err() != nil {\n\t\treturn \"\", scanner.Err()\n\t}\n\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "service/process/tags/flatpak_unix.go",
    "content": "package tags\n\nimport (\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nfunc init() {\n\terr := process.RegisterTagHandler(new(flatpakHandler))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nconst (\n\tflatpakName     = \"Flatpak\"\n\tflatpakIDTagKey = \"flatpak-id\"\n)\n\n// flatpakHandler handles flatpak processes on Unix systems.\ntype flatpakHandler struct{}\n\n// Name returns the tag handler name.\nfunc (h *flatpakHandler) Name() string {\n\treturn flatpakName\n}\n\n// TagDescriptions returns a list of all possible tags and their description\n// of this handler.\nfunc (h *flatpakHandler) TagDescriptions() []process.TagDescription {\n\treturn []process.TagDescription{\n\t\t{\n\t\t\tID:          flatpakIDTagKey,\n\t\t\tName:        \"Flatpak ID\",\n\t\t\tDescription: \"ID of the flatpak.\",\n\t\t},\n\t}\n}\n\n// AddTags adds tags to the given process.\nfunc (h *flatpakHandler) AddTags(p *process.Process) {\n\t// Check if binary lives in the /app space.\n\tif !strings.HasPrefix(p.Path, \"/app/\") {\n\t\treturn\n\t}\n\n\t// Get the Flatpak ID.\n\tflatpakID, ok := p.Env[\"FLATPAK_ID\"]\n\tif !ok || flatpakID == \"\" {\n\t\treturn\n\t}\n\n\t// Add matching path for regular profile matching.\n\tp.MatchingPath = p.Path\n\n\t// Add app image tag.\n\tp.Tags = append(p.Tags, profile.Tag{\n\t\tKey:   flatpakIDTagKey,\n\t\tValue: flatpakID,\n\t})\n}\n\n// CreateProfile creates a profile based on the tags of the process.\n// Returns nil to skip.\nfunc (h *flatpakHandler) CreateProfile(p *process.Process) *profile.Profile {\n\tif tag, ok := p.GetTag(flatpakIDTagKey); ok {\n\t\treturn profile.New(&profile.Profile{\n\t\t\tSource:              profile.SourceLocal,\n\t\t\tName:                binmeta.GenerateBinaryNameFromPath(p.Path),\n\t\t\tPresentationPath:    p.Path,\n\t\t\tUsePresentationPath: true,\n\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t{\n\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\tKey:       tag.Key,\n\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\tValue:     tag.Value, // Value of flatpakIDTagKey.\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/process/tags/interpreter_unix.go",
    "content": "package tags\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/google/shlex\"\n\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nfunc init() {\n\tif err := process.RegisterTagHandler(new(InterpHandler)); err != nil {\n\t\tpanic(err)\n\t}\n}\n\ntype interpType struct {\n\tprocess.TagDescription\n\n\tExtensions []string\n\tRegex      *regexp.Regexp\n}\n\nvar knownInterperters = []interpType{\n\t{\n\t\tTagDescription: process.TagDescription{\n\t\t\tID:   \"python-script\",\n\t\t\tName: \"Python Script\",\n\t\t},\n\t\tExtensions: []string{\".py\", \".py2\", \".py3\"},\n\t\tRegex:      regexp.MustCompile(`^(/usr)?/bin/python[23](\\.[0-9]+)?$`),\n\t},\n\t{\n\t\tTagDescription: process.TagDescription{\n\t\t\tID:   \"shell-script\",\n\t\t\tName: \"Shell Script\",\n\t\t},\n\t\tExtensions: []string{\".sh\", \".bash\", \".ksh\", \".zsh\", \".ash\"},\n\t\tRegex:      regexp.MustCompile(`^(/usr)?/bin/(ba|k|z|a)?sh$`),\n\t},\n\t{\n\t\tTagDescription: process.TagDescription{\n\t\t\tID:   \"perl-script\",\n\t\t\tName: \"Perl Script\",\n\t\t},\n\t\tExtensions: []string{\".pl\"},\n\t\tRegex:      regexp.MustCompile(`^(/usr)?/bin/perl$`),\n\t},\n\t{\n\t\tTagDescription: process.TagDescription{\n\t\t\tID:   \"ruby-script\",\n\t\t\tName: \"Ruby Script\",\n\t\t},\n\t\tExtensions: []string{\".rb\"},\n\t\tRegex:      regexp.MustCompile(`^(/usr)?/bin/ruby$`),\n\t},\n\t{\n\t\tTagDescription: process.TagDescription{\n\t\t\tID:   \"nodejs-script\",\n\t\t\tName: \"NodeJS Script\",\n\t\t},\n\t\tExtensions: []string{\".js\"},\n\t\tRegex:      regexp.MustCompile(`^(/usr)?/bin/node(js)?$`),\n\t},\n\t/*\n\t   While similar to nodejs, electron is a bit harder as it uses a multiple processes\n\t   like Chromium and thus a interpreter match on them will but those processes into\n\t   different groups.\n\n\t   I'm still not sure how this could work in the future. Maybe processes should try to\n\t   inherit the profile of the parents if there is no profile that matches the current one....\n\n\t   \t{\n\t   \t\tTagDescription: process.TagDescription{\n\t   \t\t\tID:   \"electron-app\",\n\t   \t\t\tName: \"Electron App\",\n\t   \t\t},\n\t   \t\tRegex: regexp.MustCompile(`^(/usr)?/bin/electron([0-9]+)?$`),\n\t   \t},\n\t*/\n}\n\nfunc fileMustBeUTF8(path string) bool {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tdefer func() {\n\t\t_ = f.Close()\n\t}()\n\n\t// read the first chunk of bytes\n\tbuf := new(bytes.Buffer)\n\tsize, _ := io.CopyN(buf, f, 128)\n\tif size == 0 {\n\t\treturn false\n\t}\n\n\tb := buf.Bytes()[:size]\n\tfor len(b) > 0 {\n\t\tr, runeSize := utf8.DecodeRune(b)\n\t\tif r == utf8.RuneError {\n\t\t\treturn false\n\t\t}\n\n\t\tb = b[runeSize:]\n\t}\n\n\treturn true\n}\n\n// InterpHandler supports adding process tags based on well-known interpreter binaries.\ntype InterpHandler struct{}\n\n// Name returns \"Interpreter\".\nfunc (h *InterpHandler) Name() string {\n\treturn \"Interpreter\"\n}\n\n// TagDescriptions returns a set of tag descriptions that InterpHandler provides.\nfunc (h *InterpHandler) TagDescriptions() []process.TagDescription {\n\tl := make([]process.TagDescription, len(knownInterperters))\n\tfor idx, it := range knownInterperters {\n\t\tl[idx] = it.TagDescription\n\t}\n\n\treturn l\n}\n\n// CreateProfile creates a new profile for any process that has a tag created\n// by InterpHandler.\nfunc (h *InterpHandler) CreateProfile(p *process.Process) *profile.Profile {\n\tfor _, it := range knownInterperters {\n\t\tif tag, ok := p.GetTag(it.ID); ok {\n\t\t\t// we can safely ignore the error\n\t\t\targs, err := shlex.Split(p.CmdLine)\n\t\t\tif err != nil {\n\t\t\t\t// this should not happen since we already called shlex.Split()\n\t\t\t\t// when adding the tag. Though, make the linter happy and bail out\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// if arg0 is the interpreter name itself strip it away\n\t\t\t// and use the next one\n\t\t\tif it.Regex.MatchString(args[0]) && len(args) > 1 {\n\t\t\t\targs = args[1:]\n\t\t\t}\n\n\t\t\t// Create a nice script name from filename.\n\t\t\tscriptName := filepath.Base(args[0])\n\t\t\tfor _, ext := range it.Extensions {\n\t\t\t\tscriptName, _ = strings.CutSuffix(scriptName, ext)\n\t\t\t}\n\t\t\tscriptName = binmeta.GenerateBinaryNameFromPath(scriptName)\n\n\t\t\treturn profile.New(&profile.Profile{\n\t\t\t\tSource:              profile.SourceLocal,\n\t\t\t\tName:                fmt.Sprintf(\"%s: %s\", it.Name, scriptName),\n\t\t\t\tPresentationPath:    tag.Value,\n\t\t\t\tUsePresentationPath: true,\n\t\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\t\tKey:       it.ID,\n\t\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\t\tValue:     tag.Value,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\treturn nil\n}\n\n// AddTags inspects the process p and adds any interpreter tags that InterpHandler\n// detects.\nfunc (h *InterpHandler) AddTags(p *process.Process) {\n\t// check if we have a matching interpreter\n\tvar matched interpType\n\tfor _, it := range knownInterperters {\n\t\tif it.Regex.MatchString(p.Path) {\n\t\t\tmatched = it\n\t\t}\n\t}\n\n\t// zero value means we did not find any interpreter matches.\n\tif matched.ID == \"\" {\n\t\treturn\n\t}\n\n\targs, err := shlex.Split(p.CmdLine)\n\tif err != nil {\n\t\t// give up if we failed to parse the command line\n\t\treturn\n\t}\n\n\t// if args[0] matches the interpreter name we expect\n\t// the second arg to be a file-name\n\tif matched.Regex.MatchString(args[0]) {\n\t\tif len(args) == 1 {\n\t\t\t// there's no argument given, this is likely an interactive\n\t\t\t// interpreter session\n\t\t\treturn\n\t\t}\n\n\t\tscriptPath := args[1]\n\t\tif !filepath.IsAbs(scriptPath) {\n\t\t\tscriptPath = filepath.Join(\n\t\t\t\tp.Cwd,\n\t\t\t\tscriptPath,\n\t\t\t)\n\t\t}\n\n\t\t// TODO(ppacher): there could be some other arguments as well\n\t\t// so it may be better to scan the whole command line for a path to a UTF8\n\t\t// file and use that one.\n\t\tif !fileMustBeUTF8(scriptPath) {\n\t\t\treturn\n\t\t}\n\n\t\tp.Tags = append(p.Tags, profile.Tag{\n\t\t\tKey:   matched.ID,\n\t\t\tValue: scriptPath,\n\t\t})\n\n\t\tp.MatchingPath = scriptPath\n\n\t\treturn\n\t}\n\n\t// we know that this process is interpreted by some known interpreter but args[0]\n\t// does not contain the path to the interpreter.\n\tp.Tags = append(p.Tags, profile.Tag{\n\t\tKey:   matched.ID,\n\t\tValue: args[0],\n\t})\n\n\tp.MatchingPath = args[0]\n}\n"
  },
  {
    "path": "service/process/tags/net.go",
    "content": "package tags\n\nimport (\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\nfunc init() {\n\terr := process.RegisterTagHandler(new(NetworkHandler))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nconst (\n\tnetName     = \"Network\"\n\tnetIPTagKey = \"ip\"\n)\n\n// NetworkHandler handles AppImage processes on Unix systems.\ntype NetworkHandler struct{}\n\n// Name returns the tag handler name.\nfunc (h *NetworkHandler) Name() string {\n\treturn netName\n}\n\n// TagDescriptions returns a list of all possible tags and their description\n// of this handler.\nfunc (h *NetworkHandler) TagDescriptions() []process.TagDescription {\n\treturn []process.TagDescription{\n\t\t{\n\t\t\tID:          netIPTagKey,\n\t\t\tName:        \"IP Address\",\n\t\t\tDescription: \"The remote IP address of external requests to Portmaster, if enabled.\",\n\t\t},\n\t}\n}\n\n// AddTags adds tags to the given process.\nfunc (h *NetworkHandler) AddTags(p *process.Process) {\n\t// The \"net\" tag is added directly when creating the virtual process.\n}\n\n// CreateProfile creates a profile based on the tags of the process.\n// Returns nil to skip.\nfunc (h *NetworkHandler) CreateProfile(p *process.Process) *profile.Profile {\n\tfor _, tag := range p.Tags {\n\t\tif tag.Key == netIPTagKey {\n\t\t\treturn profile.New(&profile.Profile{\n\t\t\t\tSource: profile.SourceLocal,\n\t\t\t\tName:   p.Name,\n\t\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\t\tKey:       tag.Key,\n\t\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\t\tValue:     tag.Value,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/process/tags/snap_unix.go",
    "content": "package tags\n\nimport (\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nfunc init() {\n\terr := process.RegisterTagHandler(new(SnapHandler))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nconst (\n\tsnapName       = \"Snap\"\n\tsnapNameKey    = \"snap-name\"\n\tsnapVersionKey = \"snap-version\"\n\n\tsnapBaseDir = \"/snap/\"\n)\n\n// SnapHandler handles Snap processes on Unix systems.\ntype SnapHandler struct{}\n\n// Name returns the tag handler name.\nfunc (h *SnapHandler) Name() string {\n\treturn snapName\n}\n\n// TagDescriptions returns a list of all possible tags and their description\n// of this handler.\nfunc (h *SnapHandler) TagDescriptions() []process.TagDescription {\n\treturn []process.TagDescription{\n\t\t{\n\t\t\tID:          snapNameKey,\n\t\t\tName:        \"Snap Name\",\n\t\t\tDescription: \"Name of snap package.\",\n\t\t},\n\t\t{\n\t\t\tID:          snapVersionKey,\n\t\t\tName:        \"Snap Version\",\n\t\t\tDescription: \"Version and revision of the snap package.\",\n\t\t},\n\t}\n}\n\n// AddTags adds tags to the given process.\nfunc (h *SnapHandler) AddTags(p *process.Process) {\n\t// Check for snap env and verify location.\n\tsnapPkgBaseDir, ok := p.Env[\"SNAP\"]\n\tif ok && strings.HasPrefix(p.Path, snapPkgBaseDir) {\n\t\t// Try adding tags from env.\n\t\tadded := h.addTagsFromEnv(p)\n\t\tif added {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Attempt adding tags from path instead, if env did not work out.\n\th.addTagsFromPath(p)\n}\n\nfunc (h *SnapHandler) addTagsFromEnv(p *process.Process) (added bool) {\n\t// Get and verify snap metadata.\n\tsnapPkgName, ok := p.Env[\"SNAP_NAME\"]\n\tif !ok {\n\t\treturn false\n\t}\n\tsnapPkgVersion, ok := p.Env[\"SNAP_VERSION\"]\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// Add snap tags.\n\tp.Tags = append(p.Tags, profile.Tag{\n\t\tKey:   snapNameKey,\n\t\tValue: snapPkgName,\n\t})\n\tp.Tags = append(p.Tags, profile.Tag{\n\t\tKey:   snapVersionKey,\n\t\tValue: snapPkgVersion,\n\t})\n\n\treturn true\n}\n\nfunc (h *SnapHandler) addTagsFromPath(p *process.Process) {\n\t// Check if the binary is within the snap base dir.\n\tif !strings.HasPrefix(p.Path, snapBaseDir) {\n\t\treturn\n\t}\n\n\t// Get snap package name from path.\n\tsplitted := strings.SplitN(strings.TrimPrefix(p.Path, snapBaseDir), \"/\", 2)\n\tif len(splitted) < 2 || splitted[0] == \"\" {\n\t\treturn\n\t}\n\n\t// Add snap tags.\n\tp.Tags = append(p.Tags, profile.Tag{\n\t\tKey:   snapNameKey,\n\t\tValue: splitted[0],\n\t})\n}\n\n// CreateProfile creates a profile based on the tags of the process.\n// Returns nil to skip.\nfunc (h *SnapHandler) CreateProfile(p *process.Process) *profile.Profile {\n\tif tag, ok := p.GetTag(snapNameKey); ok {\n\t\t// Check if we have the snap version.\n\t\t// Only use presentation path if we have it.\n\t\t_, hasVersion := p.GetTag(snapVersionKey)\n\n\t\treturn profile.New(&profile.Profile{\n\t\t\tSource:              profile.SourceLocal,\n\t\t\tName:                binmeta.GenerateBinaryNameFromPath(tag.Value),\n\t\t\tPresentationPath:    p.Path,\n\t\t\tUsePresentationPath: hasVersion,\n\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t{\n\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\tKey:       tag.Key,\n\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\tValue:     tag.Value, // Value of snapNameKey.\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/process/tags/svchost_windows.go",
    "content": "package tags\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils/osdetail\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nfunc init() {\n\terr := process.RegisterTagHandler(new(SVCHostTagHandler))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nconst (\n\tsvchostName   = \"Service Host\"\n\tsvchostTagKey = \"svchost\"\n)\n\n// SVCHostTagHandler handles svchost processes on Windows.\ntype SVCHostTagHandler struct{}\n\n// Name returns the tag handler name.\nfunc (h *SVCHostTagHandler) Name() string {\n\treturn svchostName\n}\n\n// TagDescriptions returns a list of all possible tags and their description\n// of this handler.\nfunc (h *SVCHostTagHandler) TagDescriptions() []process.TagDescription {\n\treturn []process.TagDescription{\n\t\t{\n\t\t\tID:          svchostTagKey,\n\t\t\tName:        \"SvcHost Service Name\",\n\t\t\tDescription: \"Name of a service running in svchost.exe as reported by Windows.\",\n\t\t},\n\t}\n}\n\n// TagKeys returns a list of all possible tag keys of this handler.\nfunc (h *SVCHostTagHandler) TagKeys() []string {\n\treturn []string{svchostTagKey}\n}\n\n// AddTags adds tags to the given process.\nfunc (h *SVCHostTagHandler) AddTags(p *process.Process) {\n\t// Check for svchost.exe.\n\tif p.ExecName != \"svchost.exe\" {\n\t\treturn\n\t}\n\n\t// Get services of svchost instance.\n\tsvcNames, err := osdetail.GetServiceNames(int32(p.Pid))\n\tswitch err {\n\tcase nil:\n\t\t// Append service names to process name.\n\t\tp.Name += fmt.Sprintf(\" (%s)\", strings.Join(svcNames, \", \"))\n\t\t// Add services as tags.\n\t\tfor _, svcName := range svcNames {\n\t\t\t// Remove tags from service names, such as \"CDPUserSvc_1bf5729\".\n\t\t\tsvcName, _, _ := strings.Cut(svcName, \"_\")\n\t\t\t// Add service as tag.\n\t\t\tp.Tags = append(p.Tags, profile.Tag{\n\t\t\t\tKey:   svchostTagKey,\n\t\t\t\tValue: svcName,\n\t\t\t})\n\t\t}\n\tcase osdetail.ErrServiceNotFound:\n\t\tlog.Tracef(\"process/tags: failed to get service name for svchost.exe (pid %d): %s\", p.Pid, err)\n\tdefault:\n\t\tlog.Warningf(\"process/tags: failed to get service name for svchost.exe (pid %d): %s\", p.Pid, err)\n\t}\n}\n\n// CreateProfile creates a profile based on the tags of the process.\n// Returns nil to skip.\nfunc (h *SVCHostTagHandler) CreateProfile(p *process.Process) *profile.Profile {\n\tif tag, ok := p.GetTag(svchostTagKey); ok {\n\t\t// Create new profile based on tag.\n\t\tnewProfile := profile.New(&profile.Profile{\n\t\t\tSource:              profile.SourceLocal,\n\t\t\tName:                \"Windows Service: \" + binmeta.GenerateBinaryNameFromPath(tag.Value),\n\t\t\tUsePresentationPath: false,\n\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t{\n\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\tKey:       tag.Key,\n\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\tValue:     tag.Value, // Value of svchostTagKey.\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\n\t\t// Load default icon for windows service.\n\t\ticon, err := binmeta.LoadAndSaveIcon(context.TODO(), `C:\\Windows\\System32\\@WLOGO_48x48.png`)\n\t\tif err == nil {\n\t\t\tnewProfile.Icons = []binmeta.Icon{*icon}\n\t\t}\n\n\t\treturn newProfile\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/process/tags/winstore_windows.go",
    "content": "package tags\n\nimport (\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/process\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nfunc init() {\n\terr := process.RegisterTagHandler(new(WinStoreHandler))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// Add custom WindowsApps path.\n\tcustomWinStorePath := os.ExpandEnv(`%ProgramFiles%\\WindowsApps\\`)\n\tif !utils.StringInSlice(winStorePaths, customWinStorePath) {\n\t\twinStorePaths = append(winStorePaths, customWinStorePath)\n\t}\n}\n\nconst (\n\twinStoreName              = \"Windows Store\"\n\twinStoreAppNameTagKey     = \"winstore-app-name\"\n\twinStorePublisherIDTagKey = \"winstore-publisher-id\"\n)\n\nvar winStorePaths = []string{`C:\\Program Files\\WindowsApps\\`}\n\n// WinStoreHandler handles Windows Store Apps.\ntype WinStoreHandler struct{}\n\n// Name returns the tag handler name.\nfunc (h *WinStoreHandler) Name() string {\n\treturn winStoreName\n}\n\n// TagDescriptions returns a list of all possible tags and their description\n// of this handler.\nfunc (h *WinStoreHandler) TagDescriptions() []process.TagDescription {\n\treturn []process.TagDescription{\n\t\t{\n\t\t\tID:          winStoreAppNameTagKey,\n\t\t\tName:        \"Windows Store App Name\",\n\t\t\tDescription: \"Name of the Windows Store App, as found in the executable path.\",\n\t\t},\n\t\t{\n\t\t\tID:          winStorePublisherIDTagKey,\n\t\t\tName:        \"Windows Store Publisher ID\",\n\t\t\tDescription: \"Publisher ID of a Windows Store App.\",\n\t\t},\n\t}\n}\n\n// AddTags adds tags to the given process.\nfunc (h *WinStoreHandler) AddTags(p *process.Process) {\n\t// Check if the path is in one of the Windows Store Apps paths.\n\tvar appDir string\n\tfor _, winStorePath := range winStorePaths {\n\t\tif strings.HasPrefix(p.Path, winStorePath) {\n\t\t\tappDir = strings.SplitN(strings.TrimPrefix(p.Path, winStorePath), `\\`, 2)[0]\n\t\t\tbreak\n\t\t}\n\t}\n\tif appDir == \"\" {\n\t\treturn\n\t}\n\n\t// Extract information from path.\n\t// Example: Microsoft.Office.OneNote_17.6769.57631.0_x64__8wekyb3d8bbwe\n\tsplitted := strings.Split(appDir, \"_\")\n\tif len(splitted) != 5 { // Four fields, one \"__\".\n\t\tlog.Debugf(\"profile/tags: windows store app has incompatible app dir format: %q\", appDir)\n\t\treturn\n\t}\n\n\tname := splitted[0]\n\t// version  := splitted[1]\n\t// platform  := splitted[2]\n\tpublisherID := splitted[4]\n\n\t// Add tags.\n\tp.Tags = append(p.Tags, profile.Tag{\n\t\tKey:   winStoreAppNameTagKey,\n\t\tValue: name,\n\t})\n\tp.Tags = append(p.Tags, profile.Tag{\n\t\tKey:   winStorePublisherIDTagKey,\n\t\tValue: publisherID,\n\t})\n}\n\n// CreateProfile creates a profile based on the tags of the process.\n// Returns nil to skip.\nfunc (h *WinStoreHandler) CreateProfile(p *process.Process) *profile.Profile {\n\tif tag, ok := p.GetTag(winStoreAppNameTagKey); ok {\n\t\treturn profile.New(&profile.Profile{\n\t\t\tSource:              profile.SourceLocal,\n\t\t\tName:                binmeta.GenerateBinaryNameFromPath(tag.Value),\n\t\t\tPresentationPath:    p.Path,\n\t\t\tUsePresentationPath: true,\n\t\t\tFingerprints: []profile.Fingerprint{\n\t\t\t\t{\n\t\t\t\t\tType:      profile.FingerprintTypeTagID,\n\t\t\t\t\tKey:       tag.Key,\n\t\t\t\t\tOperation: profile.FingerprintOperationEqualsID,\n\t\t\t\t\tValue:     tag.Value, // Value of winStoreAppNameTagKey.\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/process/tags.go",
    "content": "package process\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\nvar (\n\ttagRegistry     []TagHandler\n\ttagRegistryLock sync.RWMutex\n)\n\n// TagHandler is a collection of process tag related interfaces.\ntype TagHandler interface {\n\t// Name returns the tag handler name.\n\tName() string\n\n\t// TagDescriptions returns a list of all possible tags and their description\n\t// of this handler.\n\tTagDescriptions() []TagDescription\n\n\t// AddTags adds tags to the given process.\n\tAddTags(p *Process)\n\n\t// CreateProfile creates a profile based on the tags of the process.\n\t// Returns nil to skip.\n\tCreateProfile(p *Process) *profile.Profile\n}\n\n// TagDescription describes a tag.\ntype TagDescription struct {\n\tID          string\n\tName        string\n\tDescription string\n}\n\n// RegisterTagHandler registers a tag handler.\nfunc RegisterTagHandler(th TagHandler) error {\n\ttagRegistryLock.Lock()\n\tdefer tagRegistryLock.Unlock()\n\n\t// Check if the handler is already registered.\n\tfor _, existingTH := range tagRegistry {\n\t\tif th.Name() == existingTH.Name() {\n\t\t\treturn errors.New(\"already registered\")\n\t\t}\n\t}\n\n\ttagRegistry = append(tagRegistry, th)\n\treturn nil\n}\n\nfunc (p *Process) addTags() {\n\ttagRegistryLock.RLock()\n\tdefer tagRegistryLock.RUnlock()\n\n\tfor _, th := range tagRegistry {\n\t\tth.AddTags(p)\n\t}\n}\n\n// CreateProfileCallback attempts to create a profile on special attributes\n// of the process.\nfunc (p *Process) CreateProfileCallback() *profile.Profile {\n\ttagRegistryLock.RLock()\n\tdefer tagRegistryLock.RUnlock()\n\n\t// Go through handlers and see which one wants to create a profile.\n\tfor _, th := range tagRegistry {\n\t\tnewProfile := th.CreateProfile(p)\n\t\tif newProfile != nil {\n\t\t\treturn newProfile\n\t\t}\n\t}\n\n\t// No handler wanted to create a profile.\n\treturn nil\n}\n"
  },
  {
    "path": "service/profile/active.go",
    "content": "package profile\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nconst (\n\tactiveProfileCleanerTickDuration = 5 * time.Minute\n\tactiveProfileCleanerThreshold    = 1 * time.Hour\n)\n\nvar (\n\tactiveProfiles     = make(map[string]*Profile)\n\tactiveProfilesLock sync.RWMutex\n)\n\n// getActiveProfile returns a cached copy of an active profile and\n// nil if it isn't found.\nfunc getActiveProfile(scopedID string) *Profile {\n\tactiveProfilesLock.RLock()\n\tdefer activeProfilesLock.RUnlock()\n\n\treturn activeProfiles[scopedID]\n}\n\n// getAllActiveProfiles returns a slice of active profiles.\nfunc getAllActiveProfiles() []*Profile {\n\tactiveProfilesLock.RLock()\n\tdefer activeProfilesLock.RUnlock()\n\n\tresult := make([]*Profile, 0, len(activeProfiles))\n\tfor _, p := range activeProfiles {\n\t\tresult = append(result, p)\n\t}\n\n\treturn result\n}\n\n// addActiveProfile registers a active profile.\nfunc addActiveProfile(profile *Profile) {\n\tactiveProfilesLock.Lock()\n\tdefer activeProfilesLock.Unlock()\n\n\t// Mark any previous profile as outdated.\n\tif previous, ok := activeProfiles[profile.ScopedID()]; ok {\n\t\tprevious.outdated.Set()\n\t}\n\n\t// Mark new profile active and add to active profiles.\n\tprofile.MarkStillActive()\n\tactiveProfiles[profile.ScopedID()] = profile\n}\n\nfunc cleanActiveProfiles(ctx *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-time.After(activeProfileCleanerTickDuration):\n\n\t\t\tthreshold := time.Now().Add(-activeProfileCleanerThreshold).Unix()\n\n\t\t\tactiveProfilesLock.Lock()\n\t\t\tfor id, profile := range activeProfiles {\n\t\t\t\t// Remove profile if it hasn't been used for a while.\n\t\t\t\tif profile.LastActive() < threshold {\n\t\t\t\t\tprofile.outdated.Set()\n\t\t\t\t\tdelete(activeProfiles, id)\n\t\t\t\t}\n\t\t\t}\n\t\t\tactiveProfilesLock.Unlock()\n\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/profile/api.go",
    "content": "package profile\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Merge profiles\",\n\t\tDescription: \"Merge multiple profiles into a new one.\",\n\t\tPath:        \"profile/merge\",\n\t\tWrite:       api.PermitUser,\n\t\tStructFunc:  handleMergeProfiles,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Get Profile Icon\",\n\t\tDescription: \"Returns the requested profile icon.\",\n\t\tPath:        \"profile/icon/{id:[a-f0-9]*\\\\.[a-z]{3,4}}\",\n\t\tRead:        api.PermitUser,\n\t\tDataFunc:    handleGetProfileIcon,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Update Profile Icon\",\n\t\tDescription: \"Updates a profile icon.\",\n\t\tPath:        \"profile/icon\",\n\t\tWrite:       api.PermitUser,\n\t\tStructFunc:  handleUpdateProfileIcon,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\ntype mergeProfilesRequest struct {\n\tName string   `json:\"name\"` // Name of the new merged profile.\n\tTo   string   `json:\"to\"`   // Profile scoped ID.\n\tFrom []string `json:\"from\"` // Profile scoped IDs.\n}\n\ntype mergeprofilesResponse struct {\n\tNew string `json:\"new\"` // Profile scoped ID.\n}\n\nfunc handleMergeProfiles(ar *api.Request) (i interface{}, err error) {\n\trequest := &mergeProfilesRequest{}\n\t_, err = dsd.MimeLoad(ar.InputData, ar.Header.Get(\"Content-Type\"), request)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse request: %w\", err)\n\t}\n\n\t// Get all profiles.\n\tvar (\n\t\tprimary     *Profile\n\t\tsecondaries = make([]*Profile, 0, len(request.From))\n\t)\n\tif primary, err = getProfile(request.To); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get profile %s: %w\", request.To, err)\n\t}\n\tfor _, from := range request.From {\n\t\tsp, err := getProfile(from)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get profile %s: %w\", request.To, err)\n\t\t}\n\t\tsecondaries = append(secondaries, sp)\n\t}\n\n\tnewProfile, err := MergeProfiles(request.Name, primary, secondaries...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to merge profiles: %w\", err)\n\t}\n\n\treturn &mergeprofilesResponse{\n\t\tNew: newProfile.ScopedID(),\n\t}, nil\n}\n\nfunc handleGetProfileIcon(ar *api.Request) (data []byte, err error) {\n\tname := ar.URLVars[\"id\"]\n\n\text := filepath.Ext(name)\n\n\t// Get profile icon.\n\tdata, err = binmeta.GetProfileIcon(name)\n\tswitch {\n\tcase err == nil:\n\t\t// Continue\n\tcase errors.Is(err, binmeta.ErrIconIgnored):\n\t\treturn nil, api.ErrorWithStatus(err, http.StatusNotFound)\n\tdefault:\n\t\treturn nil, err\n\t}\n\n\t// Set content type for icon.\n\tcontentType, ok := utils.MimeTypeByExtension(ext)\n\tif ok {\n\t\tar.ResponseHeader.Set(\"Content-Type\", contentType)\n\t}\n\n\treturn data, nil\n}\n\ntype updateProfileIconResponse struct {\n\tFilename string `json:\"filename\"`\n}\n\n//nolint:goconst\nfunc handleUpdateProfileIcon(ar *api.Request) (any, error) {\n\t// Check input.\n\tif len(ar.InputData) == 0 {\n\t\treturn nil, api.ErrorWithStatus(errors.New(\"no content\"), http.StatusBadRequest)\n\t}\n\tmimeType := ar.Header.Get(\"Content-Type\")\n\tif mimeType == \"\" {\n\t\treturn nil, api.ErrorWithStatus(errors.New(\"no content type\"), http.StatusBadRequest)\n\t}\n\n\t// Derive image format from content type.\n\tmimeType = strings.TrimSpace(mimeType)\n\tmimeType = strings.ToLower(mimeType)\n\tmimeType, _, _ = strings.Cut(mimeType, \";\")\n\tvar ext string\n\tswitch mimeType {\n\tcase \"image/gif\":\n\t\text = \"gif\"\n\tcase \"image/jpeg\":\n\t\text = \"jpg\"\n\tcase \"image/jpg\":\n\t\text = \"jpg\"\n\tcase \"image/png\":\n\t\text = \"png\"\n\tcase \"image/svg+xml\":\n\t\text = \"svg\"\n\tcase \"image/tiff\":\n\t\text = \"tiff\"\n\tcase \"image/webp\":\n\t\text = \"webp\"\n\tdefault:\n\t\treturn \"\", api.ErrorWithStatus(errors.New(\"unsupported image format\"), http.StatusBadRequest)\n\t}\n\n\t// Update profile icon.\n\tfilename, err := binmeta.UpdateProfileIcon(ar.InputData, ext)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &updateProfileIconResponse{\n\t\tFilename: filename,\n\t}, nil\n}\n"
  },
  {
    "path": "service/profile/binmeta/convert.go",
    "content": "package binmeta\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/fogleman/gg\"\n\n\t// Import the specialized ICO decoder package\n\t// This package seems to work better than \"github.com/mat/besticon/ico\" with ICO files\n\t// extracted from Windows binaries, particularly those containing cursor-related data\n\tico \"github.com/sergeymakinen/go-ico\"\n)\n\n// ConvertICOtoPNG converts a an .ico to a .png image.\nfunc ConvertICOtoPNG(icoBytes []byte) (png []byte, err error) {\n\t// Decode ICO image.\n\t// Note: The standard approach with `image.Decode(bytes.NewReader(icoBytes))` sometimes fails\n\t// when processing certain ICO files (particularly those with cursor data),\n\t// as it reads initial bytes for format detection before passing the stream to the decoder.\n\ticon, err := ico.Decode(bytes.NewReader(icoBytes))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode ICO: %w\", err)\n\t}\n\n\t// Convert to raw image.\n\timg := gg.NewContextForImage(icon)\n\n\t// Convert to PNG.\n\timgBuf := &bytes.Buffer{}\n\terr = img.EncodePNG(imgBuf)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to encode PNG: %w\", err)\n\t}\n\n\treturn imgBuf.Bytes(), nil\n}\n"
  },
  {
    "path": "service/profile/binmeta/find_default.go",
    "content": "//go:build !linux && !windows\n\npackage binmeta\n\nimport \"context\"\n\n// GetIconAndName returns zero values for unsupported platforms.\nfunc GetIconAndName(ctx context.Context, binPath string, homeDir string) (icon *Icon, name string, err error) {\n\treturn nil, \"\", nil\n}\n"
  },
  {
    "path": "service/profile/binmeta/find_linux.go",
    "content": "package binmeta\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// GetIconAndName returns an icon and name of the given binary path.\n// Providing the home directory of the user running the process of that binary can improve results.\n// Even if an error is returned, the other return values are valid, if set.\nfunc GetIconAndName(ctx context.Context, binPath string, homeDir string) (icon *Icon, name string, err error) {\n\t// Derive name from binary.\n\tname = GenerateBinaryNameFromPath(binPath)\n\n\t// Search for icon.\n\ticonPath, err := searchForIcon(binPath, homeDir)\n\tif iconPath == \"\" {\n\t\tif err != nil {\n\t\t\treturn nil, name, fmt.Errorf(\"failed to find icon for %s: %w\", binPath, err)\n\t\t}\n\t\treturn nil, name, nil\n\t}\n\n\t// Save icon to internal storage.\n\ticon, err = LoadAndSaveIcon(ctx, iconPath)\n\tif err != nil {\n\t\treturn nil, name, fmt.Errorf(\"failed to store icon for %s: %w\", binPath, err)\n\t}\n\n\treturn icon, name, nil\n}\n\nfunc searchForIcon(binPath string, homeDir string) (iconPath string, err error) {\n\tbinPath = strings.ToLower(binPath)\n\n\t// Search for icon path.\n\tfor _, iconLoc := range iconLocations {\n\t\tbasePath := iconLoc.GetPath(binPath, homeDir)\n\t\tif basePath == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch iconLoc.Type {\n\t\tcase FlatDir:\n\t\t\ticonPath, err = searchDirectory(basePath, binPath)\n\t\tcase XDGIcons:\n\t\t\ticonPath, err = searchXDGIconStructure(basePath, binPath)\n\t\t}\n\n\t\tif iconPath != \"\" {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\nfunc searchXDGIconStructure(baseDirectory string, binPath string) (iconPath string, err error) {\n\tfor _, xdgIconDir := range xdgIconPaths {\n\t\tdirectory := filepath.Join(baseDirectory, xdgIconDir)\n\t\ticonPath, err = searchDirectory(directory, binPath)\n\t\tif iconPath != \"\" {\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\nfunc searchDirectory(directory string, binPath string) (iconPath string, err error) {\n\tentries, err := os.ReadDir(directory)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn \"\", nil\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"failed to read directory %s: %w\", directory, err)\n\t}\n\t// DEBUG:\n\t// fmt.Println(directory)\n\n\tvar (\n\t\tbestMatch            string\n\t\tbestMatchExcessChars int\n\t)\n\tfor _, entry := range entries {\n\t\t// Skip dirs.\n\t\tif entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\ticonName := strings.ToLower(entry.Name())\n\t\ticonName = strings.TrimSuffix(iconName, filepath.Ext(iconName))\n\t\tswitch {\n\t\tcase len(iconName) < len(binPath):\n\t\t\t// Continue to next.\n\t\tcase iconName == binPath:\n\t\t\t// Exact match, return immediately.\n\t\t\treturn filepath.Join(directory, entry.Name()), nil\n\t\tcase strings.HasPrefix(iconName, binPath):\n\t\t\texcessChars := len(iconName) - len(binPath)\n\t\t\tif bestMatch == \"\" || excessChars < bestMatchExcessChars {\n\t\t\t\tbestMatch = entry.Name()\n\t\t\t\tbestMatchExcessChars = excessChars\n\t\t\t}\n\t\t}\n\t}\n\n\treturn bestMatch, nil\n}\n"
  },
  {
    "path": "service/profile/binmeta/find_linux_test.go",
    "content": "package binmeta\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestFindIcon(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"test depends on linux desktop environment\")\n\t}\n\tt.Parallel()\n\n\thome := os.Getenv(\"HOME\")\n\ttestFindIcon(t, \"evolution\", home)\n\ttestFindIcon(t, \"nextcloud\", home)\n}\n\nfunc testFindIcon(t *testing.T, binName string, homeDir string) {\n\tt.Helper()\n\n\ticonPath, err := searchForIcon(binName, homeDir)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif iconPath == \"\" {\n\t\tt.Errorf(\"no icon found for %s\", binName)\n\t\treturn\n\t}\n\tt.Logf(\"icon for %s found: %s\", binName, iconPath)\n}\n"
  },
  {
    "path": "service/profile/binmeta/find_windows.go",
    "content": "package binmeta\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/tc-hib/winres\"\n\t\"github.com/tc-hib/winres/version\"\n)\n\n// GetIconAndName returns an icon and name of the given binary path.\n// Providing the home directory of the user running the process of that binary can improve results.\n// Even if an error is returned, the other return values are valid, if set.\nfunc GetIconAndName(ctx context.Context, binPath string, homeDir string) (icon *Icon, name string, err error) {\n\t// Get name and png from exe.\n\tpng, name, err := getIconAndNamefromRSS(ctx, binPath)\n\n\t// Fall back to name generation if name is not set.\n\tif name == \"\" {\n\t\tname = GenerateBinaryNameFromPath(binPath)\n\t}\n\n\t// Handle previous error.\n\tif err != nil {\n\t\treturn nil, name, err\n\t}\n\n\t// Update profile icon and return icon object.\n\tfilename, err := UpdateProfileIcon(png, \"png\")\n\tif err != nil {\n\t\treturn nil, name, fmt.Errorf(\"failed to store icon: %w\", err)\n\t}\n\n\treturn &Icon{\n\t\tType:   IconTypeAPI,\n\t\tValue:  filename,\n\t\tSource: IconSourceCore,\n\t}, name, nil\n}\n\nfunc getIconAndNamefromRSS(ctx context.Context, binPath string) (png []byte, name string, err error) {\n\t// Open .exe file.\n\texeFile, err := os.Open(binPath)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil, \"\", nil\n\t\t}\n\t\treturn nil, \"\", fmt.Errorf(\"failed to open exe %s to get icon: %w\", binPath, err)\n\t}\n\tdefer exeFile.Close() //nolint:errcheck\n\n\t// Load .exe resources.\n\trss, err := winres.LoadFromEXE(exeFile)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"failed to get rss: %w\", err)\n\t}\n\n\t// DEBUG: Print all available resources:\n\t// rss.Walk(func(typeID, resID winres.Identifier, langID uint16, data []byte) bool {\n\t// \tfmt.Printf(\"typeID=%d resID=%d langID=%d\\n\", typeID, resID, langID)\n\t// \treturn true\n\t// })\n\n\t// Get name from version record.\n\tvar (\n\t\tversionInfo    *version.Info\n\t\tversionInfoErr error\n\t)\n\trss.WalkType(winres.RT_VERSION, func(resID winres.Identifier, langID uint16, data []byte) bool {\n\t\tversionInfo, versionInfoErr = version.FromBytes(data)\n\t\tswitch {\n\t\tcase versionInfoErr != nil:\n\t\t\treturn true\n\t\tcase versionInfo == nil:\n\t\t\treturn true\n\t\t}\n\n\t\t// Get metadata table and main language.\n\t\ttable := versionInfo.Table().GetMainTranslation()\n\t\tif table == nil {\n\t\t\treturn true\n\t\t}\n\n\t\tname = table[version.ProductName]\n\t\treturn name == \"\"\n\t})\n\tname = cleanFileDescription(name)\n\n\t// Get first icon.\n\tvar (\n\t\ticon    *winres.Icon\n\t\ticonErr error\n\t)\n\trss.WalkType(winres.RT_GROUP_ICON, func(resID winres.Identifier, langID uint16, _ []byte) bool {\n\t\ticon, iconErr = rss.GetIconTranslation(resID, langID)\n\t\treturn iconErr != nil\n\t})\n\tif iconErr != nil {\n\t\treturn nil, name, fmt.Errorf(\"failed to get icon: %w\", err)\n\t}\n\tif icon == nil {\n\t\treturn nil, name, errors.New(\"no icon in resources\")\n\t}\n\t// Convert icon, if it exists.\n\ticoBuf := &bytes.Buffer{}\n\terr = icon.SaveICO(icoBuf)\n\tif err != nil {\n\t\treturn nil, name, fmt.Errorf(\"failed to save ico: %w\", err)\n\t}\n\tpng, err = ConvertICOtoPNG(icoBuf.Bytes())\n\tif err != nil {\n\t\treturn nil, name, fmt.Errorf(\"failed to convert ico to png: %w\", err)\n\t}\n\n\treturn png, name, nil\n}\n"
  },
  {
    "path": "service/profile/binmeta/find_windows_test.go",
    "content": "package binmeta\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestFindIcon(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"test meant for compiling and running on desktop\")\n\t}\n\tt.Parallel()\n\n\tbinName := os.Args[len(os.Args)-1]\n\tt.Logf(\"getting name and icon for %s\", binName)\n\tpng, name, err := getIconAndNamefromRSS(context.Background(), binName)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tt.Logf(\"name: %s\", name)\n\terr = os.WriteFile(\"icon.png\", png, 0o0600)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "service/profile/binmeta/icon.go",
    "content": "package binmeta\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/vincent-petithory/dataurl\"\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// Icon describes an icon.\ntype Icon struct {\n\tType   IconType\n\tValue  string\n\tSource IconSource\n}\n\n// IconType describes the type of an Icon.\ntype IconType string\n\n// Supported icon types.\nconst (\n\tIconTypeFile     IconType = \"path\"\n\tIconTypeDatabase IconType = \"database\"\n\tIconTypeAPI      IconType = \"api\"\n)\n\nfunc (t IconType) sortOrder() int {\n\tswitch t {\n\tcase IconTypeAPI:\n\t\treturn 1\n\tcase IconTypeDatabase:\n\t\treturn 2\n\tcase IconTypeFile:\n\t\treturn 3\n\tdefault:\n\t\treturn 9\n\t}\n}\n\n// IconSource describes the source of an Icon.\ntype IconSource string\n\n// Supported icon sources.\nconst (\n\tIconSourceUser   IconSource = \"user\"\n\tIconSourceImport IconSource = \"import\"\n\tIconSourceUI     IconSource = \"ui\"\n\tIconSourceCore   IconSource = \"core\"\n)\n\nfunc (s IconSource) sortOrder() int {\n\tswitch s {\n\tcase IconSourceUser:\n\t\treturn 10\n\tcase IconSourceImport:\n\t\treturn 20\n\tcase IconSourceUI:\n\t\treturn 30\n\tcase IconSourceCore:\n\t\treturn 40\n\tdefault:\n\t\treturn 90\n\t}\n}\n\nfunc (icon Icon) sortOrder() int {\n\treturn icon.Source.sortOrder() + icon.Type.sortOrder()\n}\n\n// SortAndCompactIcons sorts and compacts a list of icons.\nfunc SortAndCompactIcons(icons []Icon) []Icon {\n\t// Sort.\n\tslices.SortFunc[[]Icon, Icon](icons, func(a, b Icon) int {\n\t\taOrder := a.sortOrder()\n\t\tbOrder := b.sortOrder()\n\n\t\tswitch {\n\t\tcase aOrder != bOrder:\n\t\t\treturn aOrder - bOrder\n\t\tcase a.Value != b.Value:\n\t\t\treturn strings.Compare(a.Value, b.Value)\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\t})\n\n\t// De-duplicate.\n\ticons = slices.CompactFunc[[]Icon, Icon](icons, func(a, b Icon) bool {\n\t\treturn a.Type == b.Type && a.Value == b.Value\n\t})\n\n\treturn icons\n}\n\n// GetIconAsDataURL returns the icon data as a data URL.\nfunc (icon Icon) GetIconAsDataURL() (bloburl string, err error) {\n\tswitch icon.Type {\n\tcase IconTypeFile:\n\t\treturn \"\", errors.New(\"getting icon from file is not supported\")\n\n\tcase IconTypeDatabase:\n\t\tif !strings.HasPrefix(icon.Value, \"cache:icons/\") {\n\t\t\treturn \"\", errors.New(\"invalid icon db key\")\n\t\t}\n\t\tr, err := iconDB.Get(icon.Value)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tdbIcon, err := EnsureIconInDatabase(r)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn dbIcon.IconData, nil\n\n\tcase IconTypeAPI:\n\t\tdata, err := GetProfileIcon(icon.Value)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn dataurl.EncodeBytes(data), nil\n\n\tdefault:\n\t\treturn \"\", errors.New(\"unknown icon type\")\n\t}\n}\n\nvar iconDB = database.NewInterface(&database.Options{\n\tLocal:    true,\n\tInternal: true,\n})\n\n// IconInDatabase represents an icon saved to the database.\ntype IconInDatabase struct {\n\tsync.Mutex\n\trecord.Base\n\n\tIconData string `json:\"iconData,omitempty\"` // DataURL\n}\n\n// EnsureIconInDatabase ensures that the given record is a *IconInDatabase, and returns it.\nfunc EnsureIconInDatabase(r record.Record) (*IconInDatabase, error) {\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewIcon := &IconInDatabase{}\n\t\terr := record.Unwrap(r, newIcon)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newIcon, nil\n\t}\n\n\t// or adjust type\n\tnewIcon, ok := r.(*IconInDatabase)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *IconInDatabase, but %T\", r)\n\t}\n\treturn newIcon, nil\n}\n"
  },
  {
    "path": "service/profile/binmeta/icons.go",
    "content": "package binmeta\n\nimport (\n\t\"context\"\n\t\"crypto\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/api\"\n)\n\n// ProfileIconStoragePath defines the location where profile icons are stored.\n// Must be set before anything else from this package is called.\n// Must not be changed once set.\nvar ProfileIconStoragePath = \"\"\n\n// ErrIconIgnored is returned when the icon should be ignored.\nvar ErrIconIgnored = errors.New(\"icon is ignored\")\n\n// GetProfileIcon returns the profile icon with the given ID and extension.\nfunc GetProfileIcon(name string) (data []byte, err error) {\n\t// Check if enabled.\n\tif ProfileIconStoragePath == \"\" {\n\t\treturn nil, errors.New(\"api icon storage not configured\")\n\t}\n\n\t// Check if icon should be ignored.\n\tif IgnoreIcon(name) {\n\t\treturn nil, ErrIconIgnored\n\t}\n\n\t// Build storage path.\n\ticonPath := filepath.Clean(\n\t\tfilepath.Join(ProfileIconStoragePath, name),\n\t)\n\n\ticonPath, err = filepath.Abs(iconPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to check icon path: %w\", err)\n\t}\n\n\t// Do a quick check if we are still within the right directory.\n\t// This check is not entirely correct, but is sufficient for this use case.\n\tif filepath.Dir(iconPath) != ProfileIconStoragePath {\n\t\treturn nil, api.ErrorWithStatus(errors.New(\"invalid icon\"), http.StatusBadRequest)\n\t}\n\n\treturn os.ReadFile(iconPath)\n}\n\n// UpdateProfileIcon creates or updates the given icon.\nfunc UpdateProfileIcon(data []byte, ext string) (filename string, err error) {\n\t// Check icon size.\n\tif len(data) > 1_000_000 {\n\t\treturn \"\", errors.New(\"icon too big\")\n\t}\n\n\t// Calculate sha1 sum of icon.\n\th := crypto.SHA1.New()\n\tif _, err := h.Write(data); err != nil {\n\t\treturn \"\", err\n\t}\n\tsum := hex.EncodeToString(h.Sum(nil))\n\n\t// Check if icon should be ignored.\n\tif IgnoreIcon(sum) {\n\t\treturn \"\", ErrIconIgnored\n\t}\n\n\t// Check ext.\n\text = strings.ToLower(ext)\n\tswitch ext {\n\tcase \"gif\":\n\tcase \"jpeg\":\n\t\text = \"jpg\"\n\tcase \"jpg\":\n\tcase \"png\":\n\tcase \"svg\":\n\tcase \"tiff\":\n\tcase \"webp\":\n\tdefault:\n\t\treturn \"\", errors.New(\"unsupported icon format\")\n\t}\n\n\t// Save to disk.\n\tfilename = sum + \".\" + ext\n\treturn filename, os.WriteFile(filepath.Join(ProfileIconStoragePath, filename), data, 0o0644) //nolint:gosec\n}\n\n// LoadAndSaveIcon loads an icon from disk, updates it in the icon database\n// and returns the icon object.\nfunc LoadAndSaveIcon(ctx context.Context, iconPath string) (*Icon, error) {\n\t// Load icon and save it.\n\tdata, err := os.ReadFile(iconPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read icon %s: %w\", iconPath, err)\n\t}\n\tfilename, err := UpdateProfileIcon(data, filepath.Ext(iconPath))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to import icon %s: %w\", iconPath, err)\n\t}\n\treturn &Icon{\n\t\tType:   IconTypeAPI,\n\t\tValue:  filename,\n\t\tSource: IconSourceCore,\n\t}, nil\n}\n\n// TODO: Clean up icons regularly.\n"
  },
  {
    "path": "service/profile/binmeta/ignore.go",
    "content": "package binmeta\n\nimport (\n\t\"strings\"\n)\n\nvar ignoreIcons = map[string]struct{}{\n\t// Windows Default Icons.\n\t\"a27898ddfa4e0481b62c69faa196919a738fcade\": {},\n\t\"5a3eea8bcd08b9336ce9c5083f26185164268ee9\": {},\n\t\"573393d6ad238d255b20dc1c1b303c95debe6965\": {},\n\t\"d459b2cb23c27cc31ccab5025533048d5d8301bf\": {},\n\t\"d35a0d91ebfda81df5286f68ec5ddb1d6ad6b850\": {},\n\t\"cc33187385498384f1b648e23be5ef1a2e9f5f71\": {},\n}\n\n// IgnoreIcon returns whether an icon should be ignored or not.\nfunc IgnoreIcon(name string) bool {\n\t// Make lower case.\n\tname = strings.ToLower(name)\n\t// Remove extension.\n\textIndex := strings.Index(name, \".\")\n\tif extIndex > 0 {\n\t\tname = name[:extIndex]\n\t}\n\n\t// Check if ID is in list.\n\t_, found := ignoreIcons[name]\n\treturn found\n}\n"
  },
  {
    "path": "service/profile/binmeta/locations_linux.go",
    "content": "package binmeta\n\nimport (\n\t\"fmt\"\n)\n\n// IconLocation describes an icon location.\ntype IconLocation struct {\n\tDirectory string\n\tType      IconLocationType\n\tPathArg   PathArg\n}\n\n// IconLocationType describes an icon location type.\ntype IconLocationType uint8\n\n// Icon Location Types.\nconst (\n\tFlatDir IconLocationType = iota\n\tXDGIcons\n)\n\n// PathArg describes an icon location path argument.\ntype PathArg uint8\n\n// Path Args.\nconst (\n\tNoPathArg PathArg = iota\n\tHome\n\tBinName\n)\n\nvar (\n\ticonLocations = []IconLocation{\n\t\t{Directory: \"/usr/share/pixmaps\", Type: FlatDir},\n\t\t{Directory: \"/usr/share\", Type: XDGIcons},\n\t\t{Directory: \"%s/.local/share\", Type: XDGIcons, PathArg: Home},\n\t\t{Directory: \"%s/.local/share/flatpak/exports/share\", Type: XDGIcons, PathArg: Home},\n\t\t{Directory: \"/usr/share/%s\", Type: XDGIcons, PathArg: BinName},\n\t}\n\n\txdgIconPaths = []string{\n\t\t// UI currently uses 48x48, so 256x256 should suffice for the future, even at 2x. (12.2023)\n\t\t\"icons/hicolor/256x256/apps\",\n\t\t\"icons/hicolor/192x192/apps\",\n\t\t\"icons/hicolor/128x128/apps\",\n\t\t\"icons/hicolor/96x96/apps\",\n\t\t\"icons/hicolor/72x72/apps\",\n\t\t\"icons/hicolor/64x64/apps\",\n\t\t\"icons/hicolor/48x48/apps\",\n\t\t\"icons/hicolor/512x512/apps\",\n\t}\n)\n\n// GetPath returns the path of an icon.\nfunc (il IconLocation) GetPath(binName string, homeDir string) string {\n\tswitch il.PathArg {\n\tcase NoPathArg:\n\t\treturn il.Directory\n\tcase Home:\n\t\tif homeDir != \"\" {\n\t\t\treturn fmt.Sprintf(il.Directory, homeDir)\n\t\t}\n\tcase BinName:\n\t\treturn fmt.Sprintf(il.Directory, binName)\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "service/profile/binmeta/name.go",
    "content": "package binmeta\n\nimport (\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nvar (\n\tsegmentsSplitter  = regexp.MustCompile(\"[^A-Za-z0-9]*[A-Z]?[a-z0-9]*\")\n\tnameOnly          = regexp.MustCompile(\"^[A-Za-z0-9]+$\")\n\tdelimitersAtStart = regexp.MustCompile(\"^[^A-Za-z0-9]+\")\n\tdelimitersOnly    = regexp.MustCompile(\"^[^A-Za-z0-9]+$\")\n\tremoveQuotes      = strings.NewReplacer(`\"`, ``, `'`, ``)\n)\n\n// GenerateBinaryNameFromPath generates a more human readable binary name from\n// the given path. This function is used as fallback in the GetBinaryName\n// functions.\nfunc GenerateBinaryNameFromPath(path string) string {\n\t// Get file name from path.\n\t_, fileName := filepath.Split(path)\n\n\t// Split up into segments.\n\tsegments := segmentsSplitter.FindAllString(fileName, -1)\n\n\t// Remove last segment if it's an extension.\n\tif len(segments) >= 2 {\n\t\tswitch strings.ToLower(segments[len(segments)-1]) {\n\t\tcase\n\t\t\t\".exe\",      // Windows Executable\n\t\t\t\".msi\",      // Windows Installer\n\t\t\t\".bat\",      // Windows Batch File\n\t\t\t\".cmd\",      // Windows Command Script\n\t\t\t\".ps1\",      // Windows Powershell Cmdlet\n\t\t\t\".run\",      // Linux Executable\n\t\t\t\".appimage\", // Linux AppImage\n\t\t\t\".app\",      // MacOS Executable\n\t\t\t\".action\",   // MacOS Automator Action\n\t\t\t\".out\":      // Generic Compiled Executable\n\t\t\tsegments = segments[:len(segments)-1]\n\t\t}\n\t}\n\n\t// Debugging snippet:\n\t// fmt.Printf(\"segments: %s\\n\", segments)\n\n\t// Go through segments and collect name parts.\n\tnameParts := make([]string, 0, len(segments))\n\tvar fragments string\n\tfor _, segment := range segments {\n\t\t// Group very short segments.\n\t\tif len(delimitersAtStart.ReplaceAllString(segment, \"\")) <= 2 {\n\t\t\tfragments += segment\n\t\t\tcontinue\n\t\t} else if fragments != \"\" {\n\t\t\tnameParts = append(nameParts, fragments)\n\t\t\tfragments = \"\"\n\t\t}\n\n\t\t// Add segment to name.\n\t\tnameParts = append(nameParts, segment)\n\t}\n\t// Add last fragment.\n\tif fragments != \"\" {\n\t\tnameParts = append(nameParts, fragments)\n\t}\n\n\t// Debugging snippet:\n\t// fmt.Printf(\"parts: %s\\n\", nameParts)\n\n\t// Post-process name parts\n\tfor i := range nameParts {\n\t\t// Remove any leading delimiters.\n\t\tnameParts[i] = delimitersAtStart.ReplaceAllString(nameParts[i], \"\")\n\n\t\t// Title-case name-only parts.\n\t\tif nameOnly.MatchString(nameParts[i]) {\n\t\t\tnameParts[i] = strings.Title(nameParts[i]) //nolint:staticcheck\n\t\t}\n\t}\n\n\t// Debugging snippet:\n\t// fmt.Printf(\"final: %s\\n\", nameParts)\n\n\treturn strings.Join(nameParts, \" \")\n}\n\nfunc cleanFileDescription(fileDescr string) string {\n\tfields := strings.Fields(fileDescr)\n\n\t// Clean out and `\"` and `'`.\n\tfor i := range fields {\n\t\tfields[i] = removeQuotes.Replace(fields[i])\n\t}\n\n\t// If there is a 1 or 2 character delimiter field, only use fields before it.\n\tendIndex := len(fields)\n\tfor i, field := range fields {\n\t\t// Ignore the first field as well as fields with more than two characters.\n\t\tif i >= 1 && len(field) <= 2 && !nameOnly.MatchString(field) {\n\t\t\tendIndex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Concatenate name\n\tbinName := strings.Join(fields[:endIndex], \" \")\n\n\t// If there are multiple sentences, only use the first.\n\tif strings.Contains(binName, \". \") {\n\t\tbinName = strings.SplitN(binName, \". \", 2)[0]\n\t}\n\n\t// If does not have any characters or numbers, return an empty string.\n\tif delimitersOnly.MatchString(binName) {\n\t\treturn \"\"\n\t}\n\n\treturn strings.TrimSpace(binName)\n}\n"
  },
  {
    "path": "service/profile/binmeta/name_test.go",
    "content": "package binmeta\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGenerateBinaryNameFromPath(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, \"Nslookup\", GenerateBinaryNameFromPath(\"nslookup.exe\"))\n\tassert.Equal(t, \"System Settings\", GenerateBinaryNameFromPath(\"SystemSettings.exe\"))\n\tassert.Equal(t, \"One Drive Setup\", GenerateBinaryNameFromPath(\"OneDriveSetup.exe\"))\n\tassert.Equal(t, \"Msedge\", GenerateBinaryNameFromPath(\"msedge.exe\"))\n\tassert.Equal(t, \"SIH Client\", GenerateBinaryNameFromPath(\"SIHClient.exe\"))\n\tassert.Equal(t, \"Openvpn Gui\", GenerateBinaryNameFromPath(\"openvpn-gui.exe\"))\n\tassert.Equal(t, \"Portmaster Core v0-1-2\", GenerateBinaryNameFromPath(\"portmaster-core_v0-1-2.exe\"))\n\tassert.Equal(t, \"Win Store App\", GenerateBinaryNameFromPath(\"WinStore.App.exe\"))\n\tassert.Equal(t, \"Test Script\", GenerateBinaryNameFromPath(\".test-script\"))\n\tassert.Equal(t, \"Browser Broker\", GenerateBinaryNameFromPath(\"browser_broker.exe\"))\n\tassert.Equal(t, \"Virtual Box VM\", GenerateBinaryNameFromPath(\"VirtualBoxVM\"))\n\tassert.Equal(t, \"Io Elementary Appcenter\", GenerateBinaryNameFromPath(\"io.elementary.appcenter\"))\n\tassert.Equal(t, \"Microsoft Windows Store\", GenerateBinaryNameFromPath(\"Microsoft.WindowsStore\"))\n}\n\nfunc TestCleanFileDescription(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, \"Product Name\", cleanFileDescription(\"Product Name\"))\n\tassert.Equal(t, \"Product Name\", cleanFileDescription(\"Product Name. Does this and that.\"))\n\tassert.Equal(t, \"Product Name\", cleanFileDescription(\"Product Name - Does this and that.\"))\n\tassert.Equal(t, \"Product Name\", cleanFileDescription(\"Product Name / Does this and that.\"))\n\tassert.Equal(t, \"Product Name\", cleanFileDescription(\"Product Name :: Does this and that.\"))\n\tassert.Equal(t, \"/ Product Name\", cleanFileDescription(\"/ Product Name\"))\n\tassert.Equal(t, \"Product\", cleanFileDescription(\"Product / Name\"))\n\tassert.Equal(t, \"Software 2\", cleanFileDescription(\"Software 2\"))\n\tassert.Equal(t, \"Launcher for Software 2\", cleanFileDescription(\"Launcher for 'Software 2'\"))\n\tassert.Equal(t, \"\", cleanFileDescription(\". / Name\"))\n\tassert.Equal(t, \"\", cleanFileDescription(\". \"))\n\tassert.Equal(t, \"\", cleanFileDescription(\".\"))\n\tassert.Equal(t, \"N/A\", cleanFileDescription(\"N/A\"))\n\n\tassert.Equal(t,\n\t\t\"Product Name a Does this and that.\",\n\t\tcleanFileDescription(\"Product Name a Does this and that.\"),\n\t)\n}\n"
  },
  {
    "path": "service/profile/config-update.go",
    "content": "package profile\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/intel/filterlists\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\nvar (\n\tcfgLock sync.RWMutex\n\n\tcfgDefaultAction       uint8\n\tcfgEndpoints           endpoints.Endpoints\n\tcfgServiceEndpoints    endpoints.Endpoints\n\tcfgSPNUsagePolicy      endpoints.Endpoints\n\tcfgSPNTransitHubPolicy endpoints.Endpoints\n\tcfgSPNExitHubPolicy    endpoints.Endpoints\n\tcfgFilterLists         []string\n)\n\nfunc registerGlobalConfigProfileUpdater() error {\n\tmodule.instance.Config().EventConfigChange.AddCallback(\"update global config profile\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\treturn false, updateGlobalConfigProfile(wc.Ctx())\n\t})\n\n\treturn nil\n}\n\nconst globalConfigProfileErrorID = \"profile:global-profile-error\"\n\nfunc updateGlobalConfigProfile(_ context.Context) error {\n\tcfgLock.Lock()\n\tdefer cfgLock.Unlock()\n\n\tvar err error\n\tvar lastErr error\n\n\taction := cfgOptionDefaultAction()\n\tswitch action {\n\tcase DefaultActionPermitValue:\n\t\tcfgDefaultAction = DefaultActionPermit\n\tcase DefaultActionAskValue:\n\t\tcfgDefaultAction = DefaultActionAsk\n\tcase DefaultActionBlockValue:\n\t\tcfgDefaultAction = DefaultActionBlock\n\tdefault:\n\t\t// TODO: module error?\n\t\tlastErr = fmt.Errorf(`default action \"%s\" invalid`, action)\n\t\tcfgDefaultAction = DefaultActionBlock // default to block in worst case\n\t}\n\n\tlist := cfgOptionEndpoints()\n\tcfgEndpoints, err = endpoints.ParseEndpoints(list)\n\tif err != nil {\n\t\t// TODO: module error?\n\t\tlastErr = err\n\t}\n\n\tlist = cfgOptionServiceEndpoints()\n\tcfgServiceEndpoints, err = endpoints.ParseEndpoints(list)\n\tif err != nil {\n\t\t// TODO: module error?\n\t\tlastErr = err\n\t}\n\n\tlist = cfgOptionFilterLists()\n\tcfgFilterLists, err = filterlists.ResolveListIDs(list)\n\tif err != nil {\n\t\tlastErr = err\n\t}\n\n\tlist = cfgOptionSPNUsagePolicy()\n\tcfgSPNUsagePolicy, err = endpoints.ParseEndpoints(list)\n\tif err != nil {\n\t\t// TODO: module error?\n\t\tlastErr = err\n\t}\n\n\tlist = cfgOptionTransitHubPolicy()\n\tcfgSPNTransitHubPolicy, err = endpoints.ParseEndpoints(list)\n\tif err != nil {\n\t\t// TODO: module error?\n\t\tlastErr = err\n\t}\n\n\tlist = cfgOptionExitHubPolicy()\n\tcfgSPNExitHubPolicy, err = endpoints.ParseEndpoints(list)\n\tif err != nil {\n\t\t// TODO: module error?\n\t\tlastErr = err\n\t}\n\n\t// Build config.\n\tnewConfig := make(map[string]interface{})\n\t// fill profile config options\n\tfor key, value := range cfgStringOptions {\n\t\tnewConfig[key] = value()\n\t}\n\tfor key, value := range cfgStringArrayOptions {\n\t\tnewConfig[key] = value()\n\t}\n\tfor key, value := range cfgIntOptions {\n\t\tnewConfig[key] = value()\n\t}\n\tfor key, value := range cfgBoolOptions {\n\t\tnewConfig[key] = value()\n\t}\n\n\t// Build global profile for reference.\n\tprofile := New(&Profile{\n\t\tID:       \"global-config\",\n\t\tSource:   SourceSpecial,\n\t\tName:     \"Global Configuration\",\n\t\tConfig:   newConfig,\n\t\tInternal: true,\n\t})\n\n\t// save profile\n\terr = profile.Save()\n\tif err != nil && lastErr == nil {\n\t\t// other errors are more important\n\t\tlastErr = err\n\t}\n\n\t// If there was any error, try again later until it succeeds.\n\tif lastErr == nil {\n\t\tmodule.states.Remove(globalConfigProfileErrorID)\n\t} else {\n\t\t// Create task after first failure.\n\n\t\t// Schedule task.\n\t\t_ = module.mgr.Delay(\"retry updating global config profile\", 15*time.Second,\n\t\t\tfunc(w *mgr.WorkerCtx) error {\n\t\t\t\treturn updateGlobalConfigProfile(w.Ctx())\n\t\t\t})\n\n\t\t// Add module warning to inform user.\n\t\tmodule.states.Add(mgr.State{\n\t\t\tID:      globalConfigProfileErrorID,\n\t\t\tName:    \"Internal Settings Failure\",\n\t\t\tMessage: fmt.Sprintf(\"Some global settings might not be applied correctly. You can try restarting the Portmaster to resolve this problem. Error: %s\", lastErr),\n\t\t\tType:    mgr.StateTypeWarning,\n\t\t})\n\t}\n\n\treturn lastErr\n}\n"
  },
  {
    "path": "service/profile/config.go",
    "content": "package profile\n\nimport (\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/service/status\"\n\t\"github.com/safing/portmaster/spn/access/account\"\n)\n\n// Configuration Keys.\nvar (\n\tcfgStringOptions      = make(map[string]config.StringOption)\n\tcfgStringArrayOptions = make(map[string]config.StringArrayOption)\n\tcfgIntOptions         = make(map[string]config.IntOption)\n\tcfgBoolOptions        = make(map[string]config.BoolOption)\n\n\t// General.\n\n\t// Setting \"Enable Filter\" at order 0.\n\n\tCfgOptionDefaultActionKey   = \"filter/defaultAction\"\n\tcfgOptionDefaultAction      config.StringOption\n\tcfgOptionDefaultActionOrder = 1\n\n\tDefaultActionPermitValue = \"permit\"\n\tDefaultActionBlockValue  = \"block\"\n\tDefaultActionAskValue    = \"ask\"\n\n\t// Setting \"Prompt Desktop Notifications\" at order 2.\n\t// Setting \"Prompt Timeout\" at order 3.\n\n\t// Network Scopes.\n\n\tCfgOptionBlockScopeInternetKey   = \"filter/blockInternet\"\n\tcfgOptionBlockScopeInternet      config.BoolOption\n\tcfgOptionBlockScopeInternetOrder = 16\n\n\tCfgOptionBlockScopeLANKey   = \"filter/blockLAN\"\n\tcfgOptionBlockScopeLAN      config.BoolOption\n\tcfgOptionBlockScopeLANOrder = 17\n\n\tCfgOptionBlockScopeLocalKey   = \"filter/blockLocal\"\n\tcfgOptionBlockScopeLocal      config.BoolOption\n\tcfgOptionBlockScopeLocalOrder = 18\n\n\t// Connection Types.\n\n\tCfgOptionBlockP2PKey   = \"filter/blockP2P\"\n\tcfgOptionBlockP2P      config.BoolOption\n\tcfgOptionBlockP2POrder = 19\n\n\tCfgOptionBlockInboundKey   = \"filter/blockInbound\"\n\tcfgOptionBlockInbound      config.BoolOption\n\tcfgOptionBlockInboundOrder = 20\n\n\t// Rules.\n\n\tCfgOptionEndpointsKey   = \"filter/endpoints\"\n\tcfgOptionEndpoints      config.StringArrayOption\n\tcfgOptionEndpointsOrder = 32\n\n\tCfgOptionServiceEndpointsKey   = \"filter/serviceEndpoints\"\n\tcfgOptionServiceEndpoints      config.StringArrayOption\n\tcfgOptionServiceEndpointsOrder = 33\n\n\tCfgOptionFilterListsKey   = \"filter/lists\"\n\tcfgOptionFilterLists      config.StringArrayOption\n\tcfgOptionFilterListsOrder = 34\n\n\t// Setting \"Custom Filter List\" at order 35.\n\n\tCfgOptionFilterSubDomainsKey   = \"filter/includeSubdomains\"\n\tcfgOptionFilterSubDomains      config.BoolOption\n\tcfgOptionFilterSubDomainsOrder = 36\n\n\t// DNS Filtering.\n\n\tCfgOptionFilterCNAMEKey   = \"filter/includeCNAMEs\"\n\tcfgOptionFilterCNAME      config.BoolOption\n\tcfgOptionFilterCNAMEOrder = 48\n\n\tCfgOptionRemoveOutOfScopeDNSKey   = \"filter/removeOutOfScopeDNS\"\n\tcfgOptionRemoveOutOfScopeDNS      config.BoolOption\n\tcfgOptionRemoveOutOfScopeDNSOrder = 49\n\n\tCfgOptionRemoveBlockedDNSKey   = \"filter/removeBlockedDNS\"\n\tcfgOptionRemoveBlockedDNS      config.BoolOption\n\tcfgOptionRemoveBlockedDNSOrder = 50\n\n\tCfgOptionDomainHeuristicsKey   = \"filter/domainHeuristics\"\n\tcfgOptionDomainHeuristics      config.BoolOption\n\tcfgOptionDomainHeuristicsOrder = 51\n\n\t// Advanced.\n\n\tCfgOptionPreventBypassingKey   = \"filter/preventBypassing\"\n\tcfgOptionPreventBypassing      config.BoolOption\n\tcfgOptionPreventBypassingOrder = 64\n\n\tCfgOptionDisableAutoPermitKey   = \"filter/disableAutoPermit\"\n\tcfgOptionDisableAutoPermit      config.BoolOption\n\tcfgOptionDisableAutoPermitOrder = 65\n\n\t// Setting \"Permanent Verdicts\" at order 80.\n\n\t// Network History.\n\n\tCfgOptionEnableHistoryKey   = \"history/enable\"\n\tcfgOptionEnableHistory      config.BoolOption\n\tcfgOptionEnableHistoryOrder = 96\n\n\tCfgOptionKeepHistoryKey   = \"history/keep\"\n\tcfgOptionKeepHistory      config.IntOption\n\tcfgOptionKeepHistoryOrder = 97\n\n\t// Setting \"Enable SPN\" at order 128.\n\n\tCfgOptionUseSPNKey   = \"spn/use\"\n\tcfgOptionUseSPN      config.BoolOption\n\tcfgOptionUseSPNOrder = 129\n\n\tCfgOptionSPNUsagePolicyKey   = \"spn/usagePolicy\"\n\tcfgOptionSPNUsagePolicy      config.StringArrayOption\n\tcfgOptionSPNUsagePolicyOrder = 130\n\n\tCfgOptionRoutingAlgorithmKey   = \"spn/routingAlgorithm\"\n\tcfgOptionRoutingAlgorithm      config.StringOption\n\tcfgOptionRoutingAlgorithmOrder = 144\n\tDefaultRoutingProfileID        = \"double-hop\" // Copied due to import loop.\n\n\t// Setting \"Home Node Rules\" at order 145.\n\n\tCfgOptionTransitHubPolicyKey   = \"spn/transitHubPolicy\"\n\tcfgOptionTransitHubPolicy      config.StringArrayOption\n\tcfgOptionTransitHubPolicyOrder = 146\n\n\tCfgOptionExitHubPolicyKey   = \"spn/exitHubPolicy\"\n\tcfgOptionExitHubPolicy      config.StringArrayOption\n\tcfgOptionExitHubPolicyOrder = 147\n\n\t// Setting \"DNS Exit Node Rules\" at order 148.\n)\n\nvar (\n\t// SPNRulesQuickSettings are now generated automatically shorty after start.\n\tSPNRulesQuickSettings = []config.QuickSetting{\n\t\t{Name: \"Loading...\", Action: config.QuickMergeTop, Value: []string{\"\"}},\n\t}\n\n\t// SPNRulesVerdictNames defines the verdicts names to be used for SPN Rules.\n\tSPNRulesVerdictNames = map[string]string{\n\t\t\"-\": \"Exclude\", // Default.\n\t\t\"+\": \"Allow\",\n\t}\n\n\t// SPNRulesHelp defines the help text for SPN related Hub selection rules.\n\tSPNRulesHelp = strings.ReplaceAll(`Rules are checked from top to bottom, stopping after the first match. They can match the following attributes of SPN Nodes:\n\n- Country (based on IPs): \"US\" (two-letter country codes according to ISO 3166-1 alpha-2)\n- AS number: \"AS123456\"\n- Address: \"192.168.0.1\"\n- Network: \"192.168.0.1/24\"\n- Anything: \"*\"\n`, `\"`, \"`\")\n)\n\nfunc registerConfiguration() error { //nolint:maintidx\n\t// Default Filter Action\n\t// permit - blocklist mode: everything is allowed unless blocked\n\t// ask - ask mode: if not verdict is found, the user is consulted\n\t// block - allowlist mode: everything is blocked unless explicitly allowed\n\terr := config.Register(&config.Option{\n\t\tName:         \"Default Network Action\",\n\t\tKey:          CfgOptionDefaultActionKey,\n\t\tDescription:  `The default network action is applied when nothing else allows or blocks a connection. This affects both outgoing and incoming connections. This setting is the weakest of all and is commonly overruled by Force Block settings or Rules.`,\n\t\tOptType:      config.OptTypeString,\n\t\tDefaultValue: DefaultActionPermitValue,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    config.DisplayHintOneOf,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionDefaultActionOrder,\n\t\t\tconfig.CategoryAnnotation:       \"General\",\n\t\t},\n\t\tPossibleValues: []config.PossibleValue{\n\t\t\t{\n\t\t\t\tName:        \"Allow\",\n\t\t\t\tValue:       DefaultActionPermitValue,\n\t\t\t\tDescription: \"Allow all connections\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Block\",\n\t\t\t\tValue:       DefaultActionBlockValue,\n\t\t\t\tDescription: \"Block all connections\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Prompt\",\n\t\t\t\tValue:       DefaultActionAskValue,\n\t\t\t\tDescription: \"Prompt for decisions\",\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionDefaultAction = config.Concurrent.GetAsString(CfgOptionDefaultActionKey, DefaultActionPermitValue)\n\tcfgStringOptions[CfgOptionDefaultActionKey] = cfgOptionDefaultAction\n\n\t// Disable Auto Permit\n\terr = config.Register(&config.Option{\n\t\t// TODO: Check how to best handle negation here.\n\t\tName:         \"Disable Auto Allow\",\n\t\tKey:          CfgOptionDisableAutoPermitKey,\n\t\tDescription:  `Auto Allow searches for a relation between an app and the destination of a connection - if there is a correlation, the connection will be allowed.`,\n\t\tOptType:      config.OptTypeBool,\n\t\tReleaseLevel: config.ReleaseLevelBeta,\n\t\tDefaultValue: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionDisableAutoPermitOrder,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.CategoryAnnotation:       \"Advanced\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionDisableAutoPermit = config.Concurrent.GetAsBool(CfgOptionDisableAutoPermitKey, true)\n\tcfgBoolOptions[CfgOptionDisableAutoPermitKey] = cfgOptionDisableAutoPermit\n\n\t// Enable History\n\terr = config.Register(&config.Option{\n\t\tName: \"Enable Network History\",\n\t\tKey:  CfgOptionEnableHistoryKey,\n\t\tDescription: `Save connections in a database (on disk) in order to view and search them later. Changes might take a couple minutes to apply to all connections.\n\nIn order to reduce noise optimize performance, internal and device-only (localhost) connections are not saved to history.`,\n\t\tOptType:        config.OptTypeBool,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tDefaultValue:   false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation:    true,\n\t\t\tconfig.DisplayOrderAnnotation:      cfgOptionEnableHistoryOrder,\n\t\t\tconfig.CategoryAnnotation:          \"General\",\n\t\t\tconfig.RequiresFeatureIDAnnotation: account.FeatureHistory,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionEnableHistory = config.Concurrent.GetAsBool(CfgOptionEnableHistoryKey, false)\n\tcfgBoolOptions[CfgOptionEnableHistoryKey] = cfgOptionEnableHistory\n\n\terr = config.Register(&config.Option{\n\t\tName: \"Keep Network History\",\n\t\tKey:  CfgOptionKeepHistoryKey,\n\t\tDescription: `Specify how many days the network history data should be kept. Please keep in mind that more available history data makes reports (coming soon) a lot more useful.\n\t\t\nOlder data is deleted in intervals and cleared from the database continually. If in a hurry, shutdown or restart Portmaster to clear deleted entries immediately.\n\nSet to 0 days to keep network history forever. Depending on your device, this might affect performance.`,\n\t\tOptType:        config.OptTypeInt,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tDefaultValue:   30,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation:    true,\n\t\t\tconfig.UnitAnnotation:              \"Days\",\n\t\t\tconfig.DisplayOrderAnnotation:      cfgOptionKeepHistoryOrder,\n\t\t\tconfig.CategoryAnnotation:          \"General\",\n\t\t\tconfig.RequiresFeatureIDAnnotation: account.FeatureHistory,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionKeepHistory = config.Concurrent.GetAsInt(CfgOptionKeepHistoryKey, 30)\n\tcfgIntOptions[CfgOptionKeepHistoryKey] = cfgOptionKeepHistory\n\n\trulesHelp := strings.ReplaceAll(`Rules are checked from top to bottom, stopping after the first match. They can match:\n\n- By address: \"192.168.0.1\"\n- By network: \"192.168.0.0/24\"\n- By network scope: \"Localhost\", \"LAN\" or \"Internet\"\n- By domain:\n\t- Matching a distinct domain: \"example.com\"\n\t- Matching a domain with subdomains: \".example.com\"\n\t- Matching with a wildcard prefix: \"*xample.com\"\n\t- Matching with a wildcard suffix: \"example.*\"\n\t- Matching domains containing text: \"*example*\"\n- By country (based on IP): \"US\" ([two-letter country codes according to ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2))\n- By continent (based on IP): \"C:US\" (prefix \"AF\", \"AN\", \"AS\", \"EU\", \"NA\", \"OC\", or \"SA\" with \"C:\")\n- By AS number: \"AS123456\"\n- By filter list - use the filterlist ID prefixed with \"L:\": \"L:MAL\"\n- Match anything: \"*\"\n\nAdditionally, you may supply a protocol and port using this format: \"<host> <IP protocol>/<port>\".\n\nProtocols and ports may be specified using numbers (\"6/80\") or names (\"TCP/HTTP\").  \nPort ranges are defined by using a hyphen (\"TCP/1-1024\"). Omit the port to match any.  \nUse a \"*\" for matching any protocol. If matching ports with any protocol, protocols without ports will not match.  \nRules with protocol and port definitions only match if the protocol and port also match.  \nPorts are always compared to the destination port, thus, the local listening port for incoming connections.  \n\nExamples:\n- \"192.168.0.1 TCP/HTTP\"\n- \"LAN UDP/50000-55000\"\n- \"example.com */HTTPS\"\n- \"1.1.1.1 ICMP\"\n\nImportant: DNS Requests are only matched against domain and filter list rules, all others require an IP address and are checked only with the following IP connection.\n\nPro Tip: You can use \"#\" to add a comment to a rule.\n`, `\"`, \"`\")\n\n\t// rulesVerdictNames defines the verdicts names to be used for filter rules.\n\trulesVerdictNames := map[string]string{\n\t\t\"-\": \"Block\", // Default.\n\t\t\"+\": \"Allow\",\n\t}\n\n\t// Endpoint Filter List\n\terr = config.Register(&config.Option{\n\t\tName:         \"Outgoing Rules\",\n\t\tKey:          CfgOptionEndpointsKey,\n\t\tDescription:  \"Rules that apply to outgoing network connections. Cannot overrule Network Scopes and Connection Types (see above).\",\n\t\tHelp:         rulesHelp,\n\t\tSensitive:    true,\n\t\tOptType:      config.OptTypeStringArray,\n\t\tDefaultValue: []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation:              true,\n\t\t\tconfig.StackableAnnotation:                   true,\n\t\t\tconfig.DisplayHintAnnotation:                 endpoints.DisplayHintEndpointList,\n\t\t\tconfig.DisplayOrderAnnotation:                cfgOptionEndpointsOrder,\n\t\t\tconfig.CategoryAnnotation:                    \"Rules\",\n\t\t\tendpoints.EndpointListVerdictNamesAnnotation: rulesVerdictNames,\n\t\t},\n\t\tValidationRegex: endpoints.ListEntryValidationRegex,\n\t\tValidationFunc:  endpoints.ValidateEndpointListConfigOption,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionEndpoints = config.Concurrent.GetAsStringArray(CfgOptionEndpointsKey, []string{})\n\tcfgStringArrayOptions[CfgOptionEndpointsKey] = cfgOptionEndpoints\n\n\t// Service Endpoint Filter List\n\terr = config.Register(&config.Option{\n\t\tName:           \"Incoming Rules\",\n\t\tKey:            CfgOptionServiceEndpointsKey,\n\t\tDescription:    \"Rules that apply to incoming network connections. Cannot overrule Network Scopes and Connection Types (see above).\",\n\t\tHelp:           rulesHelp,\n\t\tSensitive:      true,\n\t\tOptType:        config.OptTypeStringArray,\n\t\tDefaultValue:   []string{},\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation:              true,\n\t\t\tconfig.StackableAnnotation:                   true,\n\t\t\tconfig.DisplayHintAnnotation:                 endpoints.DisplayHintEndpointList,\n\t\t\tconfig.DisplayOrderAnnotation:                cfgOptionServiceEndpointsOrder,\n\t\t\tconfig.CategoryAnnotation:                    \"Rules\",\n\t\t\tendpoints.EndpointListVerdictNamesAnnotation: rulesVerdictNames,\n\t\t\tconfig.QuickSettingsAnnotation: []config.QuickSetting{\n\t\t\t\t{\n\t\t\t\t\tName:   \"Allow SSH\",\n\t\t\t\t\tAction: config.QuickMergeTop,\n\t\t\t\t\tValue:  []string{\"+ * tcp/22\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Allow HTTP/s\",\n\t\t\t\t\tAction: config.QuickMergeTop,\n\t\t\t\t\tValue:  []string{\"+ * tcp/80\", \"+ * tcp/443\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Allow RDP\",\n\t\t\t\t\tAction: config.QuickMergeTop,\n\t\t\t\t\tValue:  []string{\"+ * */3389\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Allow all from LAN\",\n\t\t\t\t\tAction: config.QuickMergeTop,\n\t\t\t\t\tValue:  []string{\"+ LAN\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Allow all from Internet\",\n\t\t\t\t\tAction: config.QuickMergeTop,\n\t\t\t\t\tValue:  []string{\"+ Internet\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Block everything else\",\n\t\t\t\t\tAction: config.QuickMergeBottom,\n\t\t\t\t\tValue:  []string{\"- *\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tValidationRegex: endpoints.ListEntryValidationRegex,\n\t\tValidationFunc:  endpoints.ValidateEndpointListConfigOption,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionServiceEndpoints = config.Concurrent.GetAsStringArray(CfgOptionServiceEndpointsKey, []string{})\n\tcfgStringArrayOptions[CfgOptionServiceEndpointsKey] = cfgOptionServiceEndpoints\n\n\t// Filter list IDs\n\tdefaultFilterListsValue := []string{\"TRAC\", \"MAL\", \"BAD\", \"UNBREAK\"}\n\terr = config.Register(&config.Option{\n\t\tName:         \"Filter Lists\",\n\t\tKey:          CfgOptionFilterListsKey,\n\t\tDescription:  \"Block connections that match enabled filter lists.\",\n\t\tOptType:      config.OptTypeStringArray,\n\t\tDefaultValue: defaultFilterListsValue,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    \"filter list\",\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionFilterListsOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Filter Lists\",\n\t\t},\n\t\tValidationRegex: `^[a-zA-Z0-9\\-]+$`,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionFilterLists = config.Concurrent.GetAsStringArray(CfgOptionFilterListsKey, defaultFilterListsValue)\n\tcfgStringArrayOptions[CfgOptionFilterListsKey] = cfgOptionFilterLists\n\n\t// Include CNAMEs\n\terr = config.Register(&config.Option{\n\t\tName:           \"Block Domain Aliases\",\n\t\tKey:            CfgOptionFilterCNAMEKey,\n\t\tDescription:    \"Block a domain if a resolved CNAME (alias) is blocked by a rule or filter list.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tDefaultValue:   true,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionFilterCNAMEOrder,\n\t\t\tconfig.CategoryAnnotation:       \"DNS Filtering\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionFilterCNAME = config.Concurrent.GetAsBool(CfgOptionFilterCNAMEKey, true)\n\tcfgBoolOptions[CfgOptionFilterCNAMEKey] = cfgOptionFilterCNAME\n\n\t// Include subdomains\n\terr = config.Register(&config.Option{\n\t\tName:         \"Block Subdomains of Filter List Entries\",\n\t\tKey:          CfgOptionFilterSubDomainsKey,\n\t\tDescription:  \"Additionally block all subdomains of entries in selected filter lists.\",\n\t\tOptType:      config.OptTypeBool,\n\t\tDefaultValue: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionFilterSubDomainsOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Filter Lists\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionFilterSubDomains = config.Concurrent.GetAsBool(CfgOptionFilterSubDomainsKey, true)\n\tcfgBoolOptions[CfgOptionFilterSubDomainsKey] = cfgOptionFilterSubDomains\n\n\t// Block Scope Local\n\terr = config.Register(&config.Option{\n\t\tName:           \"Force Block Device-Local Connections\",\n\t\tKey:            CfgOptionBlockScopeLocalKey,\n\t\tDescription:    \"Force Block all internal connections on your own device, ie. localhost. Is stronger than Rules (see below).\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tDefaultValue:   false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionBlockScopeLocalOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Network Scope\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionBlockScopeLocal = config.Concurrent.GetAsBool(CfgOptionBlockScopeLocalKey, false)\n\tcfgBoolOptions[CfgOptionBlockScopeLocalKey] = cfgOptionBlockScopeLocal\n\n\t// Block Scope LAN\n\terr = config.Register(&config.Option{\n\t\tName:         \"Force Block LAN\",\n\t\tKey:          CfgOptionBlockScopeLANKey,\n\t\tDescription:  \"Force Block all connections from and to the Local Area Network. Is stronger than Rules (see below).\",\n\t\tOptType:      config.OptTypeBool,\n\t\tDefaultValue: false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionBlockScopeLANOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Network Scope\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionBlockScopeLAN = config.Concurrent.GetAsBool(CfgOptionBlockScopeLANKey, false)\n\tcfgBoolOptions[CfgOptionBlockScopeLANKey] = cfgOptionBlockScopeLAN\n\n\t// Block Scope Internet\n\terr = config.Register(&config.Option{\n\t\tName:         \"Force Block Internet Access\",\n\t\tKey:          CfgOptionBlockScopeInternetKey,\n\t\tDescription:  \"Force Block connections from and to the Internet. Is stronger than Rules (see below).\",\n\t\tOptType:      config.OptTypeBool,\n\t\tDefaultValue: false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionBlockScopeInternetOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Network Scope\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionBlockScopeInternet = config.Concurrent.GetAsBool(CfgOptionBlockScopeInternetKey, false)\n\tcfgBoolOptions[CfgOptionBlockScopeInternetKey] = cfgOptionBlockScopeInternet\n\n\t// Block Peer to Peer Connections\n\terr = config.Register(&config.Option{\n\t\tName:         \"Force Block P2P/Direct Connections\",\n\t\tKey:          CfgOptionBlockP2PKey,\n\t\tDescription:  \"These are connections that are established directly to an IP address or peer on the Internet without resolving a domain name via DNS first. Is stronger than Rules (see below).\",\n\t\tOptType:      config.OptTypeBool,\n\t\tDefaultValue: false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionBlockP2POrder,\n\t\t\tconfig.CategoryAnnotation:       \"Connection Types\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionBlockP2P = config.Concurrent.GetAsBool(CfgOptionBlockP2PKey, false)\n\tcfgBoolOptions[CfgOptionBlockP2PKey] = cfgOptionBlockP2P\n\n\t// Block Inbound Connections\n\terr = config.Register(&config.Option{\n\t\tName:         \"Force Block Incoming Connections\",\n\t\tKey:          CfgOptionBlockInboundKey,\n\t\tDescription:  \"Connections initiated towards your device from the LAN or Internet. This will usually only be the case if you are running a network service or are using peer to peer software. Is stronger than Rules (see below).\",\n\t\tOptType:      config.OptTypeBool,\n\t\tDefaultValue: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionBlockInboundOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Connection Types\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionBlockInbound = config.Concurrent.GetAsBool(CfgOptionBlockInboundKey, false)\n\tcfgBoolOptions[CfgOptionBlockInboundKey] = cfgOptionBlockInbound\n\n\t// Filter Out-of-Scope DNS Records\n\terr = config.Register(&config.Option{\n\t\tName:           \"Enforce Global/Private Split-View\",\n\t\tKey:            CfgOptionRemoveOutOfScopeDNSKey,\n\t\tDescription:    \"Reject private IP addresses (RFC1918 et al.) from public DNS responses. If the system resolver is in use, the resulting connection will be blocked instead of the DNS request.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionRemoveOutOfScopeDNSOrder,\n\t\t\tconfig.CategoryAnnotation:       \"DNS Filtering\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionRemoveOutOfScopeDNS = config.Concurrent.GetAsBool(CfgOptionRemoveOutOfScopeDNSKey, true)\n\tcfgBoolOptions[CfgOptionRemoveOutOfScopeDNSKey] = cfgOptionRemoveOutOfScopeDNS\n\n\t// Filter DNS Records that would be blocked\n\terr = config.Register(&config.Option{\n\t\tName:           \"Reject Blocked IPs\",\n\t\tKey:            CfgOptionRemoveBlockedDNSKey,\n\t\tDescription:    \"Reject blocked IP addresses directly from the DNS response instead of handing them over to the app and blocking a resulting connection. This settings does not affect privacy and only takes effect when the system resolver is not in use.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionRemoveBlockedDNSOrder,\n\t\t\tconfig.CategoryAnnotation:       \"DNS Filtering\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionRemoveBlockedDNS = config.Concurrent.GetAsBool(CfgOptionRemoveBlockedDNSKey, true)\n\tcfgBoolOptions[CfgOptionRemoveBlockedDNSKey] = cfgOptionRemoveBlockedDNS\n\n\t// Domain heuristics\n\terr = config.Register(&config.Option{\n\t\tName:           \"Enable Domain Heuristics\",\n\t\tKey:            CfgOptionDomainHeuristicsKey,\n\t\tDescription:    \"Checks for suspicious domain names and blocks them. This option currently targets domain names generated by malware and DNS data exfiltration channels.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionDomainHeuristicsOrder,\n\t\t\tconfig.CategoryAnnotation:       \"DNS Filtering\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionDomainHeuristics = config.Concurrent.GetAsBool(CfgOptionDomainHeuristicsKey, true)\n\tcfgBoolOptions[CfgOptionDomainHeuristicsKey] = cfgOptionDomainHeuristics\n\n\t// Bypass prevention\n\terr = config.Register(&config.Option{\n\t\tName: \"Block Secure DNS Bypassing\",\n\t\tKey:  CfgOptionPreventBypassingKey,\n\t\tDescription: `Prevent apps from bypassing Portmaster's Secure DNS resolver.\nIf disabled, Portmaster might have reduced information to correctly enforce rules and filter lists.\nImportant: Portmaster's firewall itself cannot be bypassed.\n\nCurrent Features:  \n- Disable Firefox' internal DNS-over-HTTPs resolver\n- Block direct access to public DNS resolvers\n\nPlease note that DNS bypass attempts might be additionally blocked in the System DNS Client App.`,\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionPreventBypassingOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Advanced\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionPreventBypassing = config.Concurrent.GetAsBool(CfgOptionPreventBypassingKey, true)\n\tcfgBoolOptions[CfgOptionPreventBypassingKey] = cfgOptionPreventBypassing\n\n\t// Use SPN\n\terr = config.Register(&config.Option{\n\t\tName:         \"Use SPN\",\n\t\tKey:          CfgOptionUseSPNKey,\n\t\tDescription:  \"Protect network traffic with the Safing Privacy Network. If the SPN is not available or the connection is interrupted, network traffic will be blocked.\",\n\t\tOptType:      config.OptTypeBool,\n\t\tDefaultValue: true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionUseSPNOrder,\n\t\t\tconfig.CategoryAnnotation:       \"General\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionUseSPN = config.Concurrent.GetAsBool(CfgOptionUseSPNKey, true)\n\tcfgBoolOptions[CfgOptionUseSPNKey] = cfgOptionUseSPN\n\n\t// SPN Rules\n\terr = config.Register(&config.Option{\n\t\tName:         \"SPN Rules\",\n\t\tKey:          CfgOptionSPNUsagePolicyKey,\n\t\tDescription:  `Customize which websites should or should not be routed through the SPN. Only active if \"Use SPN\" is enabled.`,\n\t\tHelp:         rulesHelp,\n\t\tSensitive:    true,\n\t\tOptType:      config.OptTypeStringArray,\n\t\tDefaultValue: []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation:              true,\n\t\t\tconfig.StackableAnnotation:                   true,\n\t\t\tconfig.CategoryAnnotation:                    \"General\",\n\t\t\tconfig.DisplayOrderAnnotation:                cfgOptionSPNUsagePolicyOrder,\n\t\t\tconfig.DisplayHintAnnotation:                 endpoints.DisplayHintEndpointList,\n\t\t\tendpoints.EndpointListVerdictNamesAnnotation: SPNRulesVerdictNames,\n\t\t},\n\t\tValidationRegex: endpoints.ListEntryValidationRegex,\n\t\tValidationFunc:  endpoints.ValidateEndpointListConfigOption,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionSPNUsagePolicy = config.Concurrent.GetAsStringArray(CfgOptionSPNUsagePolicyKey, []string{})\n\tcfgStringArrayOptions[CfgOptionSPNUsagePolicyKey] = cfgOptionSPNUsagePolicy\n\n\t// Transit Node Rules\n\terr = config.Register(&config.Option{\n\t\tName:           \"Transit Node Rules\",\n\t\tKey:            CfgOptionTransitHubPolicyKey,\n\t\tDescription:    `Customize which countries should or should not be used as Transit Nodes. Transit Nodes are used to transit the SPN from your Home to your Exit Node.`,\n\t\tHelp:           SPNRulesHelp,\n\t\tSensitive:      true,\n\t\tOptType:        config.OptTypeStringArray,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tDefaultValue:   []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation:              true,\n\t\t\tconfig.StackableAnnotation:                   true,\n\t\t\tconfig.CategoryAnnotation:                    \"Routing\",\n\t\t\tconfig.DisplayOrderAnnotation:                cfgOptionTransitHubPolicyOrder,\n\t\t\tconfig.DisplayHintAnnotation:                 endpoints.DisplayHintEndpointList,\n\t\t\tconfig.QuickSettingsAnnotation:               SPNRulesQuickSettings,\n\t\t\tendpoints.EndpointListVerdictNamesAnnotation: SPNRulesVerdictNames,\n\t\t},\n\t\tValidationRegex: endpoints.ListEntryValidationRegex,\n\t\tValidationFunc:  endpoints.ValidateEndpointListConfigOption,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionTransitHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionTransitHubPolicyKey, []string{})\n\tcfgStringArrayOptions[CfgOptionTransitHubPolicyKey] = cfgOptionTransitHubPolicy\n\n\t// Exit Node Rules\n\terr = config.Register(&config.Option{\n\t\tName: \"Exit Node Rules\",\n\t\tKey:  CfgOptionExitHubPolicyKey,\n\t\tDescription: `Customize which countries should or should not be used for your Exit Nodes. Exit Nodes are used to exit the SPN and establish a connection to your destination.\n\nBy default, the Portmaster tries to choose the node closest to the destination as the Exit Node. This reduces your exposure to the open Internet. Exit Nodes are chosen for every destination separately.`,\n\t\tHelp:         SPNRulesHelp,\n\t\tSensitive:    true,\n\t\tOptType:      config.OptTypeStringArray,\n\t\tDefaultValue: []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation:              true,\n\t\t\tconfig.StackableAnnotation:                   true,\n\t\t\tconfig.CategoryAnnotation:                    \"Routing\",\n\t\t\tconfig.DisplayOrderAnnotation:                cfgOptionExitHubPolicyOrder,\n\t\t\tconfig.DisplayHintAnnotation:                 endpoints.DisplayHintEndpointList,\n\t\t\tconfig.QuickSettingsAnnotation:               SPNRulesQuickSettings,\n\t\t\tendpoints.EndpointListVerdictNamesAnnotation: SPNRulesVerdictNames,\n\t\t},\n\t\tValidationRegex: endpoints.ListEntryValidationRegex,\n\t\tValidationFunc:  endpoints.ValidateEndpointListConfigOption,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionExitHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionExitHubPolicyKey, []string{})\n\tcfgStringArrayOptions[CfgOptionExitHubPolicyKey] = cfgOptionExitHubPolicy\n\n\t// Select SPN Routing Algorithm\n\terr = config.Register(&config.Option{\n\t\tName:         \"Select SPN Routing Algorithm\",\n\t\tKey:          CfgOptionRoutingAlgorithmKey,\n\t\tDescription:  \"Select the routing algorithm for your connections through the SPN. Configure your preferred balance between speed and privacy. Portmaster may automatically upgrade the routing algorithm if necessary to protect your privacy.\",\n\t\tOptType:      config.OptTypeString,\n\t\tDefaultValue: DefaultRoutingProfileID,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.SettablePerAppAnnotation: true,\n\t\t\tconfig.DisplayHintAnnotation:    config.DisplayHintOneOf,\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionRoutingAlgorithmOrder,\n\t\t\tconfig.CategoryAnnotation:       \"Routing\",\n\t\t},\n\t\tPossibleValues: []config.PossibleValue{\n\t\t\t{\n\t\t\t\tName:        \"Plain VPN Mode\",\n\t\t\t\tValue:       \"home\",\n\t\t\t\tDescription: \"Always connect to the destination directly from the Home Hub. Only provides very basic privacy, as the Home Hub both knows where you are coming from and where you are connecting to.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Speed Focused\",\n\t\t\t\tValue:       \"single-hop\",\n\t\t\t\tDescription: \"Optimize routes with a minimum of one hop. Provides good speeds. This will often use the Home Hub to connect to destinations near you, but will use more hops to far away destinations for better privacy over long distances.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Balanced\",\n\t\t\t\tValue:       \"double-hop\",\n\t\t\t\tDescription: \"Optimize routes with a minimum of two hops. Provides good privacy as well as good speeds. No single node knows where you are coming from *and* where you are connecting to.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"Privacy Focused\",\n\t\t\t\tValue:       \"triple-hop\",\n\t\t\t\tDescription: \"Optimize routes with a minimum of three hops. Provides very good privacy. No single node knows where you are coming from *and* where you are connecting to - with an additional hop just to be sure.\",\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(CfgOptionRoutingAlgorithmKey, DefaultRoutingProfileID)\n\tcfgStringOptions[CfgOptionRoutingAlgorithmKey] = cfgOptionRoutingAlgorithm\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/profile/database.go",
    "content": "package profile\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// Database paths:\n// core:profiles/<scope>/<id>\n// cache:profiles/index/<identifier>/<value>\n\n// ProfilesDBPath is the base database path for profiles.\nconst ProfilesDBPath = \"core:profiles/\"\n\nvar profileDB = database.NewInterface(&database.Options{\n\tLocal:    true,\n\tInternal: true,\n})\n\n// MakeScopedID returns a scoped profile ID.\nfunc MakeScopedID(source ProfileSource, id string) string {\n\treturn string(source) + \"/\" + id\n}\n\n// MakeProfileKey returns a profile key.\nfunc MakeProfileKey(source ProfileSource, id string) string {\n\treturn ProfilesDBPath + string(source) + \"/\" + id\n}\n\nfunc registerValidationDBHook() (err error) {\n\t_, err = database.RegisterHook(query.New(ProfilesDBPath), &databaseHook{})\n\treturn\n}\n\nfunc startProfileUpdateChecker() error {\n\tmodule.mgr.Go(\"update active profiles\", func(ctx *mgr.WorkerCtx) (err error) {\n\t\tprofilesSub, err := profileDB.Subscribe(query.New(ProfilesDBPath))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer func() {\n\t\t\terr := profilesSub.Cancel()\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"profile: failed to cancel subscription for updating active profiles: %s\", err)\n\t\t\t}\n\t\t}()\n\n\tprofileFeed:\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase r := <-profilesSub.Feed:\n\t\t\t\t// Check if subscription was canceled.\n\t\t\t\tif r == nil {\n\t\t\t\t\treturn errors.New(\"subscription canceled\")\n\t\t\t\t}\n\n\t\t\t\t// Get active profile.\n\t\t\t\tscopedID := strings.TrimPrefix(r.Key(), ProfilesDBPath)\n\t\t\t\tactiveProfile := getActiveProfile(scopedID)\n\t\t\t\tif activeProfile == nil {\n\t\t\t\t\t// Check if profile is being deleted.\n\t\t\t\t\tif r.Meta().IsDeleted() {\n\t\t\t\t\t\tmeta.MarkDeleted(scopedID)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Don't do any additional actions if the profile is not active.\n\t\t\t\t\tcontinue profileFeed\n\t\t\t\t}\n\n\t\t\t\t// Always increase the revision counter of the layer profile.\n\t\t\t\t// This marks previous connections in the UI as decided with outdated settings.\n\t\t\t\tif activeProfile.layeredProfile != nil {\n\t\t\t\t\tactiveProfile.layeredProfile.increaseRevisionCounter(true)\n\t\t\t\t}\n\n\t\t\t\t// Always mark as outdated if the record is being deleted.\n\t\t\t\tif r.Meta().IsDeleted() {\n\t\t\t\t\tactiveProfile.outdated.Set()\n\n\t\t\t\t\tmeta.MarkDeleted(scopedID)\n\t\t\t\t\tmodule.EventDelete.Submit(scopedID)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// If the profile is saved externally (eg. via the API), have the\n\t\t\t\t// next one to use it reload the profile from the database.\n\t\t\t\treceivedProfile, err := EnsureProfile(r)\n\t\t\t\tif err != nil || !receivedProfile.savedInternally {\n\t\t\t\t\tactiveProfile.outdated.Set()\n\t\t\t\t\tmodule.EventConfigChange.Submit(scopedID)\n\t\t\t\t}\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t})\n\n\treturn nil\n}\n\ntype databaseHook struct {\n\tdatabase.HookBase\n}\n\n// UsesPrePut implements the Hook interface and returns false.\nfunc (h *databaseHook) UsesPrePut() bool {\n\treturn true\n}\n\n// PrePut implements the Hook interface.\nfunc (h *databaseHook) PrePut(r record.Record) (record.Record, error) {\n\t// Do not intervene with metadata key.\n\tif r.Key() == profilesMetadataKey {\n\t\treturn r, nil\n\t}\n\n\t// convert\n\tprofile, err := EnsureProfile(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// clean config\n\tconfig.CleanHierarchicalConfig(profile.Config)\n\n\t// prepare profile\n\tprofile.prepProfile()\n\n\t// parse config\n\terr = profile.parseConfig()\n\tif err != nil {\n\t\t// error here, warning when loading\n\t\treturn nil, err\n\t}\n\n\treturn profile, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/annotations.go",
    "content": "package endpoints\n\n// DisplayHintEndpointList marks an option as an endpoint\n// list option. It's meant to be used with DisplayHintAnnotation.\nconst DisplayHintEndpointList = \"endpoint list\"\n\n// EndpointListVerdictNamesAnnotation is the annotation identifier used in\n// configuration options to hint the UI on names to be used for endpoint list\n// verdicts.\n// If configured, it must be of type map[string]string, mapping the verdict\n// symbol to a name to be displayed in the UI.\n// May only used when config.DisplayHintAnnotation is set to DisplayHintEndpointList.\nconst EndpointListVerdictNamesAnnotation = \"safing/portmaster:ui:endpoint-list:verdict-names\"\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-any.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\n// EndpointAny matches anything.\ntype EndpointAny struct {\n\tEndpointBase\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointAny) Matches(_ context.Context, entity *intel.Entity) (EPResult, Reason) {\n\treturn ep.match(ep, entity, \"*\", \"matches\")\n}\n\nfunc (ep *EndpointAny) String() string {\n\treturn ep.renderPPP(\"*\")\n}\n\nfunc parseTypeAny(fields []string) (Endpoint, error) {\n\tif fields[1] == \"*\" {\n\t\tep := &EndpointAny{}\n\t\treturn ep.parsePPP(ep, fields)\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-asn.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\nvar asnRegex = regexp.MustCompile(\"^AS[0-9]+$\")\n\n// EndpointASN matches ASNs.\ntype EndpointASN struct {\n\tEndpointBase\n\n\tASN uint\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointASN) Matches(ctx context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tif entity.IP == nil {\n\t\treturn NoMatch, nil\n\t}\n\n\tif !entity.IPScope.IsGlobal() {\n\t\treturn NoMatch, nil\n\t}\n\n\tasn, ok := entity.GetASN(ctx)\n\tif !ok {\n\t\tasnStr := strconv.Itoa(int(ep.ASN))\n\t\treturn MatchError, ep.makeReason(ep, asnStr, \"ASN data not available to match\")\n\t}\n\n\tif asn == ep.ASN {\n\t\tasnStr := strconv.Itoa(int(ep.ASN))\n\t\treturn ep.match(ep, entity, asnStr, \"IP is part of AS\")\n\t}\n\n\treturn NoMatch, nil\n}\n\nfunc (ep *EndpointASN) String() string {\n\treturn ep.renderPPP(\"AS\" + strconv.FormatInt(int64(ep.ASN), 10))\n}\n\nfunc parseTypeASN(fields []string) (Endpoint, error) {\n\tif asnRegex.MatchString(fields[1]) {\n\t\tasnString := strings.TrimPrefix(fields[1], \"AS\")\n\t\tasn, err := strconv.ParseUint(asnString, 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse AS number %s\", asnString)\n\t\t}\n\n\t\tep := &EndpointASN{\n\t\t\tASN: uint(asn),\n\t\t}\n\t\treturn ep.parsePPP(ep, fields)\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-continent.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\nvar (\n\tcontinentCodePrefix = \"C:\"\n\tcontinentRegex      = regexp.MustCompile(`^C:[A-Z]{2}$`)\n)\n\n// EndpointContinent matches countries.\ntype EndpointContinent struct {\n\tEndpointBase\n\n\tContinentCode string\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointContinent) Matches(ctx context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tif entity.IP == nil {\n\t\treturn NoMatch, nil\n\t}\n\n\tif !entity.IPScope.IsGlobal() {\n\t\treturn NoMatch, nil\n\t}\n\n\tcountryInfo := entity.GetCountryInfo(ctx)\n\tif countryInfo == nil {\n\t\treturn MatchError, ep.makeReason(ep, \"\", \"country data not available to match\")\n\t}\n\n\tif ep.ContinentCode == countryInfo.Continent.Code {\n\t\treturn ep.match(\n\t\t\tep, entity,\n\t\t\tfmt.Sprintf(\"%s (%s)\", countryInfo.Continent.Name, countryInfo.Continent.Code),\n\t\t\t\"IP is located in\",\n\t\t)\n\t}\n\n\treturn NoMatch, nil\n}\n\nfunc (ep *EndpointContinent) String() string {\n\treturn ep.renderPPP(continentCodePrefix + ep.ContinentCode)\n}\n\nfunc parseTypeContinent(fields []string) (Endpoint, error) {\n\tif continentRegex.MatchString(fields[1]) {\n\t\tep := &EndpointContinent{\n\t\t\tContinentCode: strings.TrimPrefix(strings.ToUpper(fields[1]), continentCodePrefix),\n\t\t}\n\t\treturn ep.parsePPP(ep, fields)\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-country.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\nvar countryRegex = regexp.MustCompile(`^[A-Z]{2}$`)\n\n// EndpointCountry matches countries.\ntype EndpointCountry struct {\n\tEndpointBase\n\n\tCountryCode string\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointCountry) Matches(ctx context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tif entity.IP == nil {\n\t\treturn NoMatch, nil\n\t}\n\n\tif !entity.IPScope.IsGlobal() {\n\t\treturn NoMatch, nil\n\t}\n\n\tcountryInfo := entity.GetCountryInfo(ctx)\n\tif countryInfo == nil {\n\t\treturn MatchError, ep.makeReason(ep, \"\", \"country data not available to match\")\n\t}\n\n\tif ep.CountryCode == countryInfo.Code {\n\t\treturn ep.match(\n\t\t\tep, entity,\n\t\t\tfmt.Sprintf(\"%s (%s)\", countryInfo.Name, countryInfo.Code),\n\t\t\t\"IP is located in\",\n\t\t)\n\t}\n\treturn NoMatch, nil\n}\n\nfunc (ep *EndpointCountry) String() string {\n\treturn ep.renderPPP(ep.CountryCode)\n}\n\nfunc parseTypeCountry(fields []string) (Endpoint, error) {\n\tif countryRegex.MatchString(fields[1]) {\n\t\tep := &EndpointCountry{\n\t\t\tCountryCode: strings.ToUpper(fields[1]),\n\t\t}\n\t\treturn ep.parsePPP(ep, fields)\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-domain.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\nconst (\n\tdomainMatchTypeExact uint8 = iota\n\tdomainMatchTypeZone\n\tdomainMatchTypeSuffix\n\tdomainMatchTypePrefix\n\tdomainMatchTypeContains\n)\n\nvar (\n\tallowedDomainChars = regexp.MustCompile(`^[a-z0-9\\.-]+$`)\n\n\t// looksLikeAnIP matches domains that look like an IP address.\n\tlooksLikeAnIP = regexp.MustCompile(`^[0-9\\.:]+$`)\n)\n\n// EndpointDomain matches domains.\ntype EndpointDomain struct {\n\tEndpointBase\n\n\tOriginalValue string\n\tDomain        string\n\tDomainZone    string\n\tMatchType     uint8\n}\n\nfunc (ep *EndpointDomain) check(entity *intel.Entity, domain string) (EPResult, Reason) {\n\tresult, reason := ep.match(ep, entity, ep.OriginalValue, \"domain matches\")\n\n\tswitch ep.MatchType {\n\tcase domainMatchTypeExact:\n\t\tif domain == ep.Domain {\n\t\t\treturn result, reason\n\t\t}\n\tcase domainMatchTypeZone:\n\t\tif domain == ep.Domain {\n\t\t\treturn result, reason\n\t\t}\n\t\tif strings.HasSuffix(domain, ep.DomainZone) {\n\t\t\treturn result, reason\n\t\t}\n\tcase domainMatchTypeSuffix:\n\t\tif strings.HasSuffix(domain, ep.Domain) {\n\t\t\treturn result, reason\n\t\t}\n\tcase domainMatchTypePrefix:\n\t\tif strings.HasPrefix(domain, ep.Domain) {\n\t\t\treturn result, reason\n\t\t}\n\tcase domainMatchTypeContains:\n\t\tif strings.Contains(domain, ep.Domain) {\n\t\t\treturn result, reason\n\t\t}\n\t}\n\treturn NoMatch, nil\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointDomain) Matches(ctx context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tdomain, ok := entity.GetDomain(ctx, true /* mayUseReverseDomain */)\n\tif !ok {\n\t\treturn NoMatch, nil\n\t}\n\n\tresult, reason := ep.check(entity, domain)\n\tif result != NoMatch {\n\t\treturn result, reason\n\t}\n\n\tif entity.CNAMECheckEnabled() {\n\t\tfor _, cname := range entity.CNAME {\n\t\t\tresult, reason = ep.check(entity, cname)\n\t\t\tif result == Denied {\n\t\t\t\treturn result, reason\n\t\t\t}\n\t\t}\n\t}\n\n\treturn NoMatch, nil\n}\n\nfunc (ep *EndpointDomain) String() string {\n\treturn ep.renderPPP(ep.OriginalValue)\n}\n\nfunc parseTypeDomain(fields []string) (Endpoint, error) {\n\tdomain := fields[1]\n\tep := &EndpointDomain{\n\t\tOriginalValue: domain,\n\t}\n\n\t// Fix domain ending.\n\tswitch domain[len(domain)-1] {\n\tcase '.', '*':\n\tdefault:\n\t\tdomain += \".\"\n\t}\n\n\t// Check if this looks like an IP address.\n\t// At least the TLDs has characters.\n\tif looksLikeAnIP.MatchString(domain) {\n\t\treturn nil, nil\n\t}\n\n\t// Fix domain case.\n\tdomain = strings.ToLower(domain)\n\tneedValidFQDN := true\n\n\tswitch {\n\tcase strings.HasPrefix(domain, \"*\") && strings.HasSuffix(domain, \"*\"):\n\t\tep.MatchType = domainMatchTypeContains\n\t\tep.Domain = strings.TrimPrefix(domain, \"*\")\n\t\tep.Domain = strings.TrimSuffix(ep.Domain, \"*\")\n\t\tneedValidFQDN = false\n\n\tcase strings.HasSuffix(domain, \"*\"):\n\t\tep.MatchType = domainMatchTypePrefix\n\t\tep.Domain = strings.TrimSuffix(domain, \"*\")\n\t\tneedValidFQDN = false\n\n\t\t// Prefix matching cannot be combined with zone matching\n\t\tif strings.HasPrefix(ep.Domain, \".\") {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\t// Do not accept domains that look like an IP address and have a suffix wildcard.\n\t\t// This is confusing, because it looks like an IP Netmask matching rule.\n\t\tif looksLikeAnIP.MatchString(ep.Domain) {\n\t\t\treturn nil, errors.New(\"use CIDR notation (eg. 10.0.0.0/24) for matching ip address ranges\")\n\t\t}\n\n\tcase strings.HasPrefix(domain, \"*\"):\n\t\tep.MatchType = domainMatchTypeSuffix\n\t\tep.Domain = strings.TrimPrefix(domain, \"*\")\n\t\tneedValidFQDN = false\n\n\tcase strings.HasPrefix(domain, \".\"):\n\t\tep.MatchType = domainMatchTypeZone\n\t\tep.Domain = strings.TrimPrefix(domain, \".\")\n\t\tep.DomainZone = \".\" + ep.Domain\n\n\tdefault:\n\t\tep.MatchType = domainMatchTypeExact\n\t\tep.Domain = domain\n\t}\n\n\t// Validate domain \"content\".\n\tswitch {\n\tcase needValidFQDN && !netutils.IsValidFqdn(ep.Domain):\n\t\treturn nil, nil\n\tcase !needValidFQDN && !allowedDomainChars.MatchString(ep.Domain):\n\t\treturn nil, nil\n\tcase strings.Contains(ep.Domain, \"..\"):\n\t\t// The above regex does not catch double dots.\n\t\treturn nil, nil\n\t}\n\n\treturn ep.parsePPP(ep, fields)\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-ip.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\n// EndpointIP matches IPs.\ntype EndpointIP struct {\n\tEndpointBase\n\n\tIP net.IP\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointIP) Matches(_ context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tif entity.IP == nil {\n\t\treturn NoMatch, nil\n\t}\n\n\tif ep.IP.Equal(entity.IP) {\n\t\treturn ep.match(ep, entity, ep.IP.String(), \"IP matches\")\n\t}\n\treturn NoMatch, nil\n}\n\nfunc (ep *EndpointIP) String() string {\n\treturn ep.renderPPP(ep.IP.String())\n}\n\nfunc parseTypeIP(fields []string) (Endpoint, error) {\n\tip := net.ParseIP(fields[1])\n\tif ip != nil {\n\t\tep := &EndpointIP{\n\t\t\tIP: ip,\n\t\t}\n\t\treturn ep.parsePPP(ep, fields)\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-iprange.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\n// EndpointIPRange matches IP ranges.\ntype EndpointIPRange struct {\n\tEndpointBase\n\n\tNet *net.IPNet\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointIPRange) Matches(_ context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tif entity.IP == nil {\n\t\treturn NoMatch, nil\n\t}\n\n\tif ep.Net.Contains(entity.IP) {\n\t\treturn ep.match(ep, entity, ep.Net.String(), \"IP is in\")\n\t}\n\treturn NoMatch, nil\n}\n\nfunc (ep *EndpointIPRange) String() string {\n\treturn ep.renderPPP(ep.Net.String())\n}\n\nfunc parseTypeIPRange(fields []string) (Endpoint, error) {\n\t_, net, err := net.ParseCIDR(fields[1])\n\tif err == nil {\n\t\tep := &EndpointIPRange{\n\t\t\tNet: net,\n\t\t}\n\t\treturn ep.parsePPP(ep, fields)\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-lists.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\n// EndpointLists matches endpoint lists.\ntype EndpointLists struct {\n\tEndpointBase\n\n\tListSet []string\n\tLists   string\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointLists) Matches(ctx context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tif entity.MatchLists(ep.ListSet) {\n\t\treturn ep.match(ep, entity, ep.Lists, \"filterlist contains\", \"filterlist\", entity.ListBlockReason())\n\t}\n\n\treturn NoMatch, nil\n}\n\nfunc (ep *EndpointLists) String() string {\n\treturn ep.renderPPP(ep.Lists)\n}\n\nfunc parseTypeList(fields []string) (Endpoint, error) {\n\tif strings.HasPrefix(fields[1], \"L:\") {\n\t\tlists := strings.Split(strings.TrimPrefix(fields[1], \"L:\"), \",\")\n\t\tep := &EndpointLists{\n\t\t\tListSet: lists,\n\t\t\tLists:   \"L:\" + strings.Join(lists, \",\"),\n\t\t}\n\t\treturn ep.parsePPP(ep, fields)\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint-scopes.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\nconst (\n\tscopeLocalhost        = 1\n\tscopeLocalhostName    = \"Localhost\"\n\tscopeLocalhostMatcher = \"localhost\"\n\n\tscopeLAN        = 2\n\tscopeLANName    = \"LAN\"\n\tscopeLANMatcher = \"lan\"\n\n\tscopeInternet        = 4\n\tscopeInternetName    = \"Internet\"\n\tscopeInternetMatcher = \"internet\"\n)\n\n// EndpointScope matches network scopes.\ntype EndpointScope struct {\n\tEndpointBase\n\n\tscopes uint8\n}\n\n// Matches checks whether the given entity matches this endpoint definition.\nfunc (ep *EndpointScope) Matches(_ context.Context, entity *intel.Entity) (EPResult, Reason) {\n\tif entity.IP == nil {\n\t\treturn NoMatch, nil\n\t}\n\n\tvar scope uint8\n\tswitch entity.IPScope {\n\tcase netutils.HostLocal:\n\t\tscope = scopeLocalhost\n\tcase netutils.LinkLocal:\n\t\tscope = scopeLAN\n\tcase netutils.SiteLocal:\n\t\tscope = scopeLAN\n\tcase netutils.Global:\n\t\tscope = scopeInternet\n\tcase netutils.LocalMulticast:\n\t\tscope = scopeLAN\n\tcase netutils.GlobalMulticast:\n\t\tscope = scopeInternet\n\tcase netutils.Undefined, netutils.Invalid:\n\t\treturn NoMatch, nil\n\t}\n\n\tif ep.scopes&scope > 0 {\n\t\treturn ep.match(ep, entity, ep.Scopes(), \"scope matches\")\n\t}\n\treturn NoMatch, nil\n}\n\n// Scopes returns the string representation of all scopes.\nfunc (ep *EndpointScope) Scopes() string {\n\t// single scope\n\tswitch ep.scopes {\n\tcase scopeLocalhost:\n\t\treturn scopeLocalhostName\n\tcase scopeLAN:\n\t\treturn scopeLANName\n\tcase scopeInternet:\n\t\treturn scopeInternetName\n\t}\n\n\t// multiple scopes\n\tvar s []string\n\tif ep.scopes&scopeLocalhost > 0 {\n\t\ts = append(s, scopeLocalhostName)\n\t}\n\tif ep.scopes&scopeLAN > 0 {\n\t\ts = append(s, scopeLANName)\n\t}\n\tif ep.scopes&scopeInternet > 0 {\n\t\ts = append(s, scopeInternetName)\n\t}\n\treturn strings.Join(s, \",\")\n}\n\nfunc (ep *EndpointScope) String() string {\n\treturn ep.renderPPP(ep.Scopes())\n}\n\nfunc parseTypeScope(fields []string) (Endpoint, error) {\n\tep := &EndpointScope{}\n\tfor _, val := range strings.Split(strings.ToLower(fields[1]), \",\") {\n\t\tswitch val {\n\t\tcase scopeLocalhostMatcher:\n\t\t\tep.scopes ^= scopeLocalhost\n\t\tcase scopeLANMatcher:\n\t\t\tep.scopes ^= scopeLAN\n\t\tcase scopeInternetMatcher:\n\t\t\tep.scopes ^= scopeInternet\n\t\tdefault:\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\treturn ep.parsePPP(ep, fields)\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/network/reference\"\n)\n\n// Endpoint describes an Endpoint Matcher.\ntype Endpoint interface {\n\tMatches(ctx context.Context, entity *intel.Entity) (EPResult, Reason)\n\tString() string\n}\n\n// EndpointBase provides general functions for implementing an Endpoint to reduce boilerplate.\ntype EndpointBase struct { //nolint:maligned // TODO\n\tProtocol  uint8\n\tStartPort uint16\n\tEndPort   uint16\n\n\tPermitted bool\n}\n\nfunc (ep *EndpointBase) match(s fmt.Stringer, entity *intel.Entity, value, desc string, keyval ...interface{}) (EPResult, Reason) {\n\tresult := ep.matchesPPP(entity)\n\tif result == NoMatch {\n\t\treturn result, nil\n\t}\n\n\treturn result, ep.makeReason(s, value, desc, keyval...)\n}\n\nfunc (ep *EndpointBase) makeReason(s fmt.Stringer, value, desc string, keyval ...interface{}) Reason {\n\tr := &reason{\n\t\tdescription: desc,\n\t\tFilter:      s.String(),\n\t\tPermitted:   ep.Permitted,\n\t\tValue:       value,\n\t}\n\n\tr.Extra = make(map[string]interface{})\n\n\tfor idx := 0; idx < len(keyval)/2; idx += 2 {\n\t\tkey := keyval[idx]\n\t\tval := keyval[idx+1]\n\n\t\tif keyName, ok := key.(string); ok {\n\t\t\tr.Extra[keyName] = val\n\t\t}\n\t}\n\n\treturn r\n}\n\nfunc (ep *EndpointBase) matchesPPP(entity *intel.Entity) (result EPResult) {\n\t// only check if protocol is defined\n\tif ep.Protocol > 0 {\n\t\t// if protocol does not match, return NoMatch\n\t\tif entity.Protocol != ep.Protocol {\n\t\t\treturn NoMatch\n\t\t}\n\t}\n\n\t// only check if port is defined\n\tif ep.StartPort > 0 {\n\t\t// if port does not match, return NoMatch\n\t\tif entity.DstPort() < ep.StartPort || entity.DstPort() > ep.EndPort {\n\t\t\treturn NoMatch\n\t\t}\n\t}\n\n\t// protocol and port matched or were defined as any\n\tif ep.Permitted {\n\t\treturn Permitted\n\t}\n\treturn Denied\n}\n\nfunc (ep *EndpointBase) renderPPP(s string) string {\n\tvar rendered string\n\tif ep.Permitted {\n\t\trendered = \"+ \" + s\n\t} else {\n\t\trendered = \"- \" + s\n\t}\n\n\tif ep.Protocol > 0 || ep.StartPort > 0 {\n\t\tif ep.Protocol > 0 {\n\t\t\trendered += \" \" + reference.GetProtocolName(ep.Protocol)\n\t\t} else {\n\t\t\trendered += \" *\"\n\t\t}\n\n\t\tif ep.StartPort > 0 {\n\t\t\tif ep.StartPort == ep.EndPort {\n\t\t\t\trendered += \"/\" + reference.GetPortName(ep.StartPort)\n\t\t\t} else {\n\t\t\t\trendered += \"/\" + strconv.Itoa(int(ep.StartPort)) + \"-\" + strconv.Itoa(int(ep.EndPort))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn rendered\n}\n\nfunc (ep *EndpointBase) parsePPP(typedEp Endpoint, fields []string) (Endpoint, error) { //nolint:gocognit // TODO\n\tswitch len(fields) {\n\tcase 2:\n\t\t// nothing else to do here\n\tcase 3:\n\t\t// parse protocol and port(s)\n\t\tvar ok bool\n\t\tsplitted := strings.Split(fields[2], \"/\")\n\t\tif len(splitted) > 2 {\n\t\t\treturn nil, invalidDefinitionError(fields, \"protocol and port must be in format <protocol>/<port>\")\n\t\t}\n\t\t// protocol\n\t\tswitch splitted[0] {\n\t\tcase \"\":\n\t\t\treturn nil, invalidDefinitionError(fields, \"protocol can't be empty\")\n\t\tcase \"*\":\n\t\t\t// any protocol that supports ports\n\t\tdefault:\n\t\t\tn, err := strconv.ParseUint(splitted[0], 10, 8)\n\t\t\tn8 := uint8(n)\n\t\t\tif err != nil {\n\t\t\t\t// maybe it's a name?\n\t\t\t\tn8, ok = reference.GetProtocolNumber(splitted[0])\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, invalidDefinitionError(fields, \"protocol number parsing error\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tep.Protocol = n8\n\t\t}\n\t\t// port(s)\n\t\tif len(splitted) > 1 {\n\t\t\tswitch splitted[1] {\n\t\t\tcase \"\", \"*\":\n\t\t\t\treturn nil, invalidDefinitionError(fields, \"omit port if should match any\")\n\t\t\tdefault:\n\t\t\t\tportSplitted := strings.Split(splitted[1], \"-\")\n\t\t\t\tif len(portSplitted) > 2 {\n\t\t\t\t\treturn nil, invalidDefinitionError(fields, \"ports must be in format from-to\")\n\t\t\t\t}\n\t\t\t\t// parse start port\n\t\t\t\tn, err := strconv.ParseUint(portSplitted[0], 10, 16)\n\t\t\t\tn16 := uint16(n)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// maybe it's a name?\n\t\t\t\t\tn16, ok = reference.GetPortNumber(portSplitted[0])\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn nil, invalidDefinitionError(fields, \"port number parsing error\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif n16 == 0 {\n\t\t\t\t\treturn nil, invalidDefinitionError(fields, \"port number cannot be 0\")\n\t\t\t\t}\n\t\t\t\tep.StartPort = n16\n\t\t\t\t// parse end port\n\t\t\t\tif len(portSplitted) > 1 {\n\t\t\t\t\tn, err = strconv.ParseUint(portSplitted[1], 10, 16)\n\t\t\t\t\tn16 = uint16(n)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t// maybe it's a name?\n\t\t\t\t\t\tn16, ok = reference.GetPortNumber(portSplitted[1])\n\t\t\t\t\t\tif !ok {\n\t\t\t\t\t\t\treturn nil, invalidDefinitionError(fields, \"port number parsing error\")\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif n16 == 0 {\n\t\t\t\t\treturn nil, invalidDefinitionError(fields, \"port number cannot be 0\")\n\t\t\t\t}\n\t\t\t\tep.EndPort = n16\n\t\t\t}\n\t\t}\n\t\t// check if anything was parsed\n\t\tif ep.Protocol == 0 && ep.StartPort == 0 {\n\t\t\treturn nil, invalidDefinitionError(fields, \"omit protocol/port if should match any\")\n\t\t}\n\tdefault:\n\t\treturn nil, invalidDefinitionError(fields, \"there should be only 2 or 3 segments\")\n\t}\n\n\tswitch fields[0] {\n\tcase \"+\":\n\t\tep.Permitted = true\n\tcase \"-\":\n\t\tep.Permitted = false\n\tdefault:\n\t\treturn nil, invalidDefinitionError(fields, \"invalid permission prefix\")\n\t}\n\n\treturn typedEp, nil\n}\n\nfunc invalidDefinitionError(fields []string, msg string) error {\n\treturn fmt.Errorf(`invalid endpoint definition: \"%s\" - %s`, strings.Join(fields, \" \"), msg)\n}\n\n//nolint:gocognit,nakedret\nfunc parseEndpoint(value string) (endpoint Endpoint, err error) {\n\tfields := strings.Fields(value)\n\tif len(fields) < 2 {\n\t\treturn nil, fmt.Errorf(`invalid endpoint definition: \"%s\"`, value)\n\t}\n\n\t// Remove comment.\n\tfor i, field := range fields {\n\t\tif strings.HasPrefix(field, \"#\") {\n\t\t\tfields = fields[:i]\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// any\n\tif endpoint, err = parseTypeAny(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// ip\n\tif endpoint, err = parseTypeIP(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// ip range\n\tif endpoint, err = parseTypeIPRange(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// country\n\tif endpoint, err = parseTypeCountry(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// continent\n\tif endpoint, err = parseTypeContinent(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// asn\n\tif endpoint, err = parseTypeASN(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// scopes\n\tif endpoint, err = parseTypeScope(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// lists\n\tif endpoint, err = parseTypeList(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\t// domain\n\tif endpoint, err = parseTypeDomain(fields); endpoint != nil || err != nil {\n\t\treturn\n\t}\n\n\treturn nil, fmt.Errorf(`unknown endpoint definition: \"%s\"`, value)\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoint_test.go",
    "content": "package endpoints\n\nimport (\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestEndpointParsing(t *testing.T) {\n\tt.Parallel()\n\n\t// any (basics)\n\ttestParsing(t, \"- *\")\n\ttestParsing(t, \"+ *\")\n\n\t// domain\n\ttestDomainParsing(t, \"- *bad*\", domainMatchTypeContains, \"bad\")\n\ttestDomainParsing(t, \"- bad*\", domainMatchTypePrefix, \"bad\")\n\ttestDomainParsing(t, \"- *bad.com\", domainMatchTypeSuffix, \"bad.com.\")\n\ttestDomainParsing(t, \"- .bad.com\", domainMatchTypeZone, \"bad.com.\")\n\ttestDomainParsing(t, \"- bad.com\", domainMatchTypeExact, \"bad.com.\")\n\ttestDomainParsing(t, \"- www.bad.com.\", domainMatchTypeExact, \"www.bad.com.\")\n\ttestDomainParsing(t, \"- www.bad.com\", domainMatchTypeExact, \"www.bad.com.\")\n\n\t// ip\n\ttestParsing(t, \"+ 127.0.0.1\")\n\ttestParsing(t, \"+ 192.168.0.1\")\n\ttestParsing(t, \"+ ::1\")\n\ttestParsing(t, \"+ 2606:4700:4700::1111\")\n\n\t// ip\n\ttestParsing(t, \"+ 127.0.0.0/8\")\n\ttestParsing(t, \"+ 192.168.0.0/24\")\n\ttestParsing(t, \"+ 2606:4700:4700::/48\")\n\n\t// country\n\ttestParsing(t, \"+ DE\")\n\ttestParsing(t, \"+ AT\")\n\ttestParsing(t, \"+ CH\")\n\ttestParsing(t, \"+ AS\")\n\n\t// asn\n\ttestParsing(t, \"+ AS1\")\n\ttestParsing(t, \"+ AS12\")\n\ttestParsing(t, \"+ AS123\")\n\ttestParsing(t, \"+ AS1234\")\n\ttestParsing(t, \"+ AS12345\")\n\n\t// network scope\n\ttestParsing(t, \"+ Localhost\")\n\ttestParsing(t, \"+ LAN\")\n\ttestParsing(t, \"+ Internet\")\n\ttestParsing(t, \"+ Localhost,LAN,Internet\")\n\n\t// protocol and ports\n\ttestParsing(t, \"+ * TCP/1-1024\")\n\ttestParsing(t, \"+ * */DNS\")\n\ttestParsing(t, \"+ * ICMP\")\n\ttestParsing(t, \"+ * 127\")\n\ttestParsing(t, \"+ * UDP/1234\")\n\ttestParsing(t, \"+ * TCP/HTTP\")\n\ttestParsing(t, \"+ * TCP/80-443\")\n\n\t// TODO: Test fails:\n\t// testParsing(t, \"+ 1234\")\n}\n\nfunc testParsing(t *testing.T, value string) {\n\tt.Helper()\n\n\tep, err := parseEndpoint(value)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\t// t.Logf(\"%T: %+v\", ep, ep)\n\tif value != ep.String() {\n\t\tt.Errorf(`stringified endpoint mismatch: original was \"%s\", parsed is \"%s\"`, value, ep.String())\n\t}\n}\n\nfunc testDomainParsing(t *testing.T, value string, matchType uint8, matchValue string) {\n\tt.Helper()\n\n\ttestParsing(t, value)\n\n\tepGeneric, err := parseTypeDomain(strings.Fields(value))\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tep := epGeneric.(*EndpointDomain) //nolint:forcetypeassert\n\n\tif ep.MatchType != matchType {\n\t\tt.Errorf(`error parsing domain endpoint \"%s\": match type should be %d, was %d`, value, matchType, ep.MatchType)\n\t}\n\tif ep.Domain != matchValue {\n\t\tt.Errorf(`error parsing domain endpoint \"%s\": match domain value should be %s, was %s`, value, matchValue, ep.Domain)\n\t}\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoints.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n)\n\n// Endpoints is a list of permitted or denied endpoints.\ntype Endpoints []Endpoint\n\n// EPResult represents the result of a check against an EndpointPermission.\ntype EPResult uint8\n\n// Endpoint matching return values.\nconst (\n\tNoMatch EPResult = iota\n\tMatchError\n\tDenied\n\tPermitted\n)\n\n// IsDecision returns true if result represents a decision\n// and false if result is NoMatch or Undeterminable.\nfunc IsDecision(result EPResult) bool {\n\treturn result == Denied || result == Permitted || result == MatchError\n}\n\n// ParseEndpoints parses a list of endpoints and returns a list of Endpoints for matching.\nfunc ParseEndpoints(entries []string) (Endpoints, error) {\n\tvar firstErr error\n\tvar errCnt int\n\tendpoints := make(Endpoints, 0, len(entries))\n\nentriesLoop:\n\tfor _, entry := range entries {\n\t\tep, err := parseEndpoint(entry)\n\t\tif err != nil {\n\t\t\terrCnt++\n\t\t\tif firstErr == nil {\n\t\t\t\tfirstErr = err\n\t\t\t}\n\t\t\tcontinue entriesLoop\n\t\t}\n\n\t\tendpoints = append(endpoints, ep)\n\t}\n\n\tif firstErr != nil {\n\t\tif errCnt > 0 {\n\t\t\treturn endpoints, fmt.Errorf(\"encountered %d errors, first was: %w\", errCnt, firstErr)\n\t\t}\n\t\treturn endpoints, firstErr\n\t}\n\n\treturn endpoints, nil\n}\n\n// ListEntryValidationRegex is a regex to bullshit check endpoint list entries.\nvar ListEntryValidationRegex = strings.Join([]string{\n\t`^(\\+|\\-) `,                   // Rule verdict.\n\t`(! +)?`,                      // Invert matching.\n\t`[A-z0-9\\.:\\-*/]+`,            // Entity matching.\n\t`( `,                          // Start of optional matching.\n\t`[A-z0-9*]+`,                  // Protocol matching.\n\t`(/[A-z0-9]+(\\-[A-z0-9]+)?)?`, // Port and port range matching.\n\t`)?`,                          // End of optional matching.\n\t`( +#.*)?`,                    // Optional comment.\n}, \"\")\n\n// ValidateEndpointListConfigOption validates the given value.\nfunc ValidateEndpointListConfigOption(value interface{}) error {\n\tlist, ok := value.([]string)\n\tif !ok {\n\t\treturn errors.New(\"invalid type\")\n\t}\n\n\t_, err := ParseEndpoints(list)\n\treturn err\n}\n\n// IsSet returns whether the Endpoints object is \"set\".\nfunc (e Endpoints) IsSet() bool {\n\treturn len(e) > 0\n}\n\n// Match checks whether the given entity matches any of the endpoint definitions in the list.\nfunc (e Endpoints) Match(ctx context.Context, entity *intel.Entity) (result EPResult, reason Reason) {\n\tfor _, entry := range e {\n\t\tif entry == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif result, reason = entry.Matches(ctx, entity); result != NoMatch {\n\t\t\treturn\n\t\t}\n\t}\n\n\treturn NoMatch, nil\n}\n\n// MatchMulti checks whether the given entities match any of the endpoint\n// definitions in the list. Every rule is evaluated against all given entities\n// and only if not match was registered, the next rule is evaluated.\nfunc (e Endpoints) MatchMulti(ctx context.Context, entities ...*intel.Entity) (result EPResult, reason Reason) {\n\tfor _, entry := range e {\n\t\tif entry == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, entity := range entities {\n\t\t\tif entity == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif result, reason = entry.Matches(ctx, entity); result != NoMatch {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\treturn NoMatch, nil\n}\n\nfunc (e Endpoints) String() string {\n\ts := make([]string, 0, len(e))\n\tfor _, entry := range e {\n\t\ts = append(s, entry.String())\n\t}\n\treturn fmt.Sprintf(\"[%s]\", strings.Join(s, \", \"))\n}\n\nfunc (epr EPResult) String() string {\n\tswitch epr {\n\tcase NoMatch:\n\t\treturn \"No Match\"\n\tcase MatchError:\n\t\treturn \"Match Error\"\n\tcase Denied:\n\t\treturn \"Denied\"\n\tcase Permitted:\n\t\treturn \"Permitted\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n"
  },
  {
    "path": "service/profile/endpoints/endpoints_test.go",
    "content": "package endpoints\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/configure\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype testInstance struct {\n\tdb           *dbmodule.DBModule\n\tapi          *api.API\n\tconfig       *config.Config\n\tintelUpdates *updates.Updater\n\tgeoip        *geoip.GeoIP\n}\n\nfunc (stub *testInstance) IntelUpdates() *updates.Updater              { return stub.intelUpdates }\nfunc (stub *testInstance) API() *api.API                               { return stub.api }\nfunc (stub *testInstance) Config() *config.Config                      { return stub.config }\nfunc (stub *testInstance) Notifications() *notifications.Notifications { return nil }\nfunc (stub *testInstance) Ready() bool                                 { return true }\nfunc (stub *testInstance) Restart()                                    {}\nfunc (stub *testInstance) Shutdown()                                   {}\nfunc (stub *testInstance) SetCmdLineOperation(f func() error)          {}\nfunc (stub *testInstance) BinaryUpdates() *updates.Updater             { return nil }\nfunc (stub *testInstance) UI() *ui.UI                                  { return nil }\nfunc (stub *testInstance) DataDir() string                             { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tvar err error\n\n\t// Create a temporary directory for testing\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temporary data directory: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Initialize the Intel update configuration\n\tintelUpdateConfig := updates.Config{\n\t\tName:              configure.DefaultIntelIndexName,\n\t\tDirectory:         filepath.Join(_dataDir, \"test_intel\"),\n\t\tDownloadDirectory: filepath.Join(_dataDir, \"test_download_intel\"),\n\t\tPurgeDirectory:    filepath.Join(_dataDir, \"test_upgrade_obsolete_intel\"),\n\t\tIndexURLs:         configure.DefaultIntelIndexURLs,\n\t\tIndexFile:         \"index.json\",\n\t\tAutoCheck:         true,\n\t\tAutoDownload:      true,\n\t\tAutoApply:         true,\n\t}\n\n\t// Set the default API listen address\n\tapi.SetDefaultAPIListenAddress(\"0.0.0.0:8080\")\n\n\t// Initialize the instance with the necessary components\n\tstub := &testInstance{}\n\tstub.db, err = dbmodule.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database: %w\", err)\n\t}\n\tstub.config, err = config.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config: %w\", err)\n\t}\n\tstub.api, err = api.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create api: %w\", err)\n\t}\n\tstub.intelUpdates, err = updates.New(stub, \"Intel Updater\", intelUpdateConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create updates: %w\", err)\n\t}\n\tstub.geoip, err = geoip.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create geoip: %w\", err)\n\t}\n\n\terr = stub.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start database: %w\", err)\n\t}\n\terr = stub.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start config: %w\", err)\n\t}\n\terr = stub.api.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start api: %w\", err)\n\t}\n\terr = stub.intelUpdates.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start updates: %w\", err)\n\t}\n\terr = stub.geoip.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start geoip: %w\", err)\n\t}\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\", err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc testEndpointMatch(t *testing.T, ep Endpoint, entity *intel.Entity, expectedResult EPResult) {\n\tt.Helper()\n\n\tresult, _ := ep.Matches(context.TODO(), entity)\n\tif result != expectedResult {\n\t\tt.Errorf(\n\t\t\t\"line %d: unexpected result for endpoint %s and entity %+v: result=%s, expected=%s\",\n\t\t\tgetLineNumberOfCaller(1),\n\t\t\tep,\n\t\t\tentity,\n\t\t\tresult,\n\t\t\texpectedResult,\n\t\t)\n\t}\n}\n\nfunc testFormat(t *testing.T, endpoint string, shouldSucceed bool) {\n\tt.Helper()\n\n\t_, err := parseEndpoint(endpoint)\n\tif shouldSucceed {\n\t\tassert.NoError(t, err)\n\t} else {\n\t\tassert.Error(t, err)\n\t}\n}\n\nfunc TestEndpointFormat(t *testing.T) {\n\tt.Parallel()\n\n\ttestFormat(t, \"+ .\", false)\n\ttestFormat(t, \"+ .at\", true)\n\ttestFormat(t, \"+ .at.\", true)\n\ttestFormat(t, \"+ 1.at\", true)\n\ttestFormat(t, \"+ 1.at.\", true)\n\ttestFormat(t, \"+ 1.f.ix.de.\", true)\n\ttestFormat(t, \"+ *contains*\", true)\n\ttestFormat(t, \"+ *has.suffix\", true)\n\ttestFormat(t, \"+ *.has.suffix\", true)\n\ttestFormat(t, \"+ *has.prefix*\", true)\n\ttestFormat(t, \"+ *has.prefix.*\", true)\n\ttestFormat(t, \"+ .sub.and.prefix.*\", false)\n\ttestFormat(t, \"+ *.sub..and.prefix.*\", false)\n}\n\nfunc TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO\n\tt.Parallel()\n\n\t// ANY\n\n\tep, err := parseEndpoint(\"+ *\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\n\t// DOMAIN\n\n\t// wildcard domains\n\tep, err = parseEndpoint(\"+ *example.com\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc.example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc-example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc.example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc-example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\n\tep, err = parseEndpoint(\"+ *.example.com\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc.example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc-example.com.\",\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc.example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc-example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\n\tep, err = parseEndpoint(\"+ .example.com\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc.example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc-example.com.\",\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc.example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc-example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\n\tep, err = parseEndpoint(\"+ example.*\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc.example.com.\",\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc.example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\n\tep, err = parseEndpoint(\"+ *.exampl*\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"abc.example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"abc.example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\n\tep, err = parseEndpoint(\"+ *.com.\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.org.\",\n\t}).Init(0), NoMatch)\n\n\t// protocol\n\n\tep, err = parseEndpoint(\"+ example.com UDP\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 17,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), NoMatch)\n\n\t// ports\n\n\tep, err = parseEndpoint(\"+ example.com 17/442-444\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tentity := (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 17,\n\t\tPort:     441,\n\t}).Init(0)\n\ttestEndpointMatch(t, ep, entity, NoMatch)\n\n\tentity.Port = 442\n\tentity.Init(0)\n\ttestEndpointMatch(t, ep, entity, Permitted)\n\n\tentity.Port = 443\n\tentity.Init(0)\n\ttestEndpointMatch(t, ep, entity, Permitted)\n\n\tentity.Port = 444\n\tentity.Init(0)\n\ttestEndpointMatch(t, ep, entity, Permitted)\n\n\tentity.Port = 445\n\tentity.Init(0)\n\ttestEndpointMatch(t, ep, entity, NoMatch)\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), NoMatch)\n\n\t// IP\n\n\tep, err = parseEndpoint(\"+ 10.2.3.4\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 17,\n\t\tPort:     443,\n\t}).Init(0), Permitted)\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"\",\n\t\tIP:       net.ParseIP(\"10.2.3.3\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain:   \"example.com.\",\n\t\tIP:       net.ParseIP(\"10.2.3.5\"),\n\t\tProtocol: 17,\n\t\tPort:     443,\n\t}).Init(0), NoMatch)\n\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tDomain: \"example.com.\",\n\t}).Init(0), NoMatch)\n\n\t// IP Range\n\n\tep, err = parseEndpoint(\"+ 10.2.3.0/24\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tIP: net.ParseIP(\"10.2.2.4\"),\n\t}).Init(0), NoMatch)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tIP: net.ParseIP(\"10.2.3.4\"),\n\t}).Init(0), Permitted)\n\ttestEndpointMatch(t, ep, (&intel.Entity{\n\t\tIP: net.ParseIP(\"10.2.4.4\"),\n\t}).Init(0), NoMatch)\n\n\t// Skip test that need the geoip database in CI.\n\tif !testing.Short() {\n\n\t\t// ASN\n\n\t\tep, err = parseEndpoint(\"+ AS15169\")\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tentity = (&intel.Entity{IP: net.IPv4(8, 8, 8, 8)}).Init(0)\n\t\ttestEndpointMatch(t, ep, entity, Permitted)\n\n\t\tentity = (&intel.Entity{IP: net.IPv4(1, 1, 1, 1)}).Init(0)\n\t\ttestEndpointMatch(t, ep, entity, NoMatch)\n\n\t\t// Country\n\n\t\tep, err = parseEndpoint(\"+ AT\")\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tentity = (&intel.Entity{IP: net.IPv4(194, 232, 104, 1)}).Init(0) // orf.at\n\t\ttestEndpointMatch(t, ep, entity, Permitted)\n\n\t\tentity = (&intel.Entity{IP: net.IPv4(151, 101, 1, 164)}).Init(0) // nytimes.com\n\t\ttestEndpointMatch(t, ep, entity, NoMatch)\n\n\t}\n\n\t// Scope\n\n\tep, err = parseEndpoint(\"+ Localhost,LAN\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tentity = (&intel.Entity{IP: net.IPv4(192, 168, 0, 1)}).Init(0)\n\ttestEndpointMatch(t, ep, entity, Permitted)\n\n\tentity = (&intel.Entity{IP: net.IPv4(151, 101, 1, 164)}).Init(0) // nytimes.com\n\ttestEndpointMatch(t, ep, entity, NoMatch)\n\n\t// Port with protocol wildcard\n\n\tep, err = parseEndpoint(\"+ * */443\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tentity = &intel.Entity{\n\t\tDomain:   \"\",\n\t\tIP:       net.ParseIP(\"10.2.3.4\"),\n\t\tProtocol: 6,\n\t\tPort:     443,\n\t}\n\tentity.Init(0)\n\ttestEndpointMatch(t, ep, entity, Permitted)\n\n\t// Lists\n\n\t// Skip test that need the filter lists in CI.\n\tif !testing.Short() {\n\t\t_, err = parseEndpoint(\"+ L:A,B,C\")\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t}\n\n\t// TODO: write test for lists matcher\n}\n\nfunc getLineNumberOfCaller(levels int) int {\n\t_, _, line, _ := runtime.Caller(levels + 1) //nolint:dogsled\n\treturn line\n}\n"
  },
  {
    "path": "service/profile/endpoints/reason.go",
    "content": "package endpoints\n\n// Reason describes the reason why an endpoint has been\n// permitted or blocked.\ntype Reason interface {\n\t// String should return a human readable string\n\t// describing the decision reason.\n\tString() string\n\n\t// Context returns the context that was used\n\t// for the decision.\n\tContext() interface{}\n}\n\ntype reason struct {\n\tdescription string\n\tFilter      string\n\tValue       string\n\tPermitted   bool\n\tExtra       map[string]interface{}\n}\n\nfunc (r *reason) String() string {\n\tprefix := \"denied by rule: \"\n\tif r.Permitted {\n\t\tprefix = \"allowed by rule: \"\n\t}\n\n\treturn prefix + r.description + \" \" + r.Filter[2:]\n}\n\nfunc (r *reason) Context() interface{} {\n\treturn r\n}\n"
  },
  {
    "path": "service/profile/fingerprint.go",
    "content": "package profile\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/jess/lhash\"\n\t\"github.com/safing/structures/container\"\n)\n\n// # Matching and Scores\n//\n// There are three levels:\n//\n// 1. Type: What matched?\n//   1. Tag:            50.000 points\n//   2. Cmdline:        40.000 points\n//   3. Env:            30.000 points\n//   4. MatchingPath:   20.000 points\n//   5. Path:           10.000 points\n// 2. Operation: How was it mached?\n//   1. Equals:          3.000 points\n//   2. Prefix:          2.000 points\n//   3. Regex:           1.000 points\n// 3. How \"strong\" was the match?\n//   1. Equals:                Length of path (irrelevant)\n//   2. Prefix:                Length of prefix\n//   3. Regex:                 Length of match\n\n// Fingerprint Type IDs.\nconst (\n\tFingerprintTypeTagID     = \"tag\"\n\tFingerprintTypeCmdlineID = \"cmdline\"\n\tFingerprintTypeEnvID     = \"env\"\n\tFingerprintTypePathID    = \"path\" // Matches both MatchingPath and Path.\n\n\tFingerprintOperationEqualsID = \"equals\"\n\tFingerprintOperationPrefixID = \"prefix\"\n\tFingerprintOperationRegexID  = \"regex\"\n\n\ttagMatchBaseScore          = 50_000\n\tcmdlineMatchBaseScore      = 40_000\n\tenvMatchBaseScore          = 30_000\n\tmatchingPathMatchBaseScore = 20_000\n\tpathMatchBaseScore         = 10_000\n\n\tfingerprintEqualsBaseScore = 3_000\n\tfingerprintPrefixBaseScore = 2_000\n\tfingerprintRegexBaseScore  = 1_000\n\n\tmaxMatchStrength = 499\n)\n\ntype (\n\t// Fingerprint defines a way of matching a process.\n\t// The Key is only valid - but required - for some types.\n\tFingerprint struct {\n\t\tType      string\n\t\tKey       string // Key must always fully match.\n\t\tOperation string\n\t\tValue     string\n\n\t\t// MergedFrom holds the ID of the profile from which this fingerprint was\n\t\t// merged from. The merged profile should create a new profile ID derived\n\t\t// from the new fingerprints and add all fingerprints with this field set\n\t\t// to the originating profile ID\n\t\tMergedFrom string // `json:\"mergedFrom,omitempty\"`\n\t}\n\n\t// Tag represents a simple key/value kind of tag used in process metadata\n\t// and fingerprints.\n\tTag struct {\n\t\tKey   string\n\t\tValue string\n\t}\n\n\t// MatchingData is an interface to fetching data in the matching process.\n\tMatchingData interface {\n\t\tTags() []Tag\n\t\tEnv() map[string]string\n\t\tPath() string\n\t\tMatchingPath() string\n\t\tCmdline() string\n\t}\n\n\tmatchingFingerprint interface {\n\t\tMatchesKey(key string) bool\n\t\tMatch(value string) (score int)\n\t}\n)\n\n// MatchesKey returns whether the optional fingerprint key (for some types\n// only) matches the given key.\nfunc (fp Fingerprint) MatchesKey(key string) bool {\n\treturn key == fp.Key\n}\n\n// KeyInTags checks is the given key is in the tags.\nfunc KeyInTags(tags []Tag, key string) bool {\n\tfor _, tag := range tags {\n\t\tif key == tag.Key {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// KeyAndValueInTags checks is the given key/value pair is in the tags.\nfunc KeyAndValueInTags(tags []Tag, key, value string) bool {\n\tfor _, tag := range tags {\n\t\tif key == tag.Key && value == tag.Value {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype fingerprintEquals struct {\n\tFingerprint\n}\n\nfunc (fp fingerprintEquals) Match(value string) (score int) {\n\tif value == fp.Value {\n\t\treturn fingerprintEqualsBaseScore + checkMatchStrength(len(fp.Value))\n\t}\n\treturn 0\n}\n\ntype fingerprintPrefix struct {\n\tFingerprint\n}\n\nfunc (fp fingerprintPrefix) Match(value string) (score int) {\n\tif strings.HasPrefix(value, fp.Value) {\n\t\treturn fingerprintPrefixBaseScore + checkMatchStrength(len(fp.Value))\n\t}\n\treturn 0\n}\n\ntype fingerprintRegex struct {\n\tFingerprint\n\tregex *regexp.Regexp\n}\n\nfunc (fp fingerprintRegex) Match(value string) (score int) {\n\t// Find best match.\n\tfor _, match := range fp.regex.FindAllString(value, -1) {\n\t\t// Save match length if higher than score.\n\t\t// This will also ignore empty matches.\n\t\tif len(match) > score {\n\t\t\tscore = len(match)\n\t\t}\n\t}\n\n\t// Add base score and return if anything was found.\n\tif score > 0 {\n\t\treturn fingerprintRegexBaseScore + checkMatchStrength(score)\n\t}\n\n\treturn 0\n}\n\n// ParsedFingerprints holds parsed fingerprints for fast usage.\ntype ParsedFingerprints struct {\n\ttagPrints     []matchingFingerprint\n\tenvPrints     []matchingFingerprint\n\tpathPrints    []matchingFingerprint\n\tcmdlinePrints []matchingFingerprint\n}\n\n// ParseFingerprints parses the fingerprints to make them ready for matching.\nfunc ParseFingerprints(raw []Fingerprint, deprecatedLinkedPath string) (parsed *ParsedFingerprints, firstErr error) {\n\tparsed = &ParsedFingerprints{}\n\n\t// Add deprecated LinkedPath to fingerprints, if they are empty.\n\t// TODO: Remove in v1.5\n\tif len(raw) == 0 && deprecatedLinkedPath != \"\" {\n\t\tparsed.pathPrints = append(parsed.pathPrints, &fingerprintEquals{\n\t\t\tFingerprint: Fingerprint{\n\t\t\t\tType:      FingerprintTypePathID,\n\t\t\t\tOperation: FingerprintOperationEqualsID,\n\t\t\t\tValue:     deprecatedLinkedPath,\n\t\t\t},\n\t\t})\n\t}\n\n\t// Parse all fingerprints.\n\t// Do not fail when one fails, instead return the first encountered error.\n\tfor _, entry := range raw {\n\t\t// Check type and required key.\n\t\tswitch entry.Type {\n\t\tcase FingerprintTypeTagID, FingerprintTypeEnvID:\n\t\t\tif entry.Key == \"\" {\n\t\t\t\tif firstErr == nil {\n\t\t\t\t\tfirstErr = fmt.Errorf(\"%s fingerprint is missing key\", entry.Type)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\tcase FingerprintTypePathID, FingerprintTypeCmdlineID:\n\t\t\t// Don't need a key.\n\t\tdefault:\n\t\t\t// Unknown type.\n\t\t\tif firstErr == nil {\n\t\t\t\tfirstErr = fmt.Errorf(\"unknown fingerprint type: %q\", entry.Type)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create and/or collect operation match functions.\n\t\tswitch entry.Operation {\n\t\tcase FingerprintOperationEqualsID:\n\t\t\tparsed.addMatchingFingerprint(entry, fingerprintEquals{entry})\n\n\t\tcase FingerprintOperationPrefixID:\n\t\t\tparsed.addMatchingFingerprint(entry, fingerprintPrefix{entry})\n\n\t\tcase FingerprintOperationRegexID:\n\t\t\tregex, err := regexp.Compile(entry.Value)\n\t\t\tif err != nil {\n\t\t\t\tif firstErr == nil {\n\t\t\t\t\tfirstErr = fmt.Errorf(\"failed to compile regex fingerprint: %s\", entry.Value)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tparsed.addMatchingFingerprint(entry, fingerprintRegex{\n\t\t\t\t\tFingerprint: entry,\n\t\t\t\t\tregex:       regex,\n\t\t\t\t})\n\t\t\t}\n\n\t\tdefault:\n\t\t\tif firstErr == nil {\n\t\t\t\tfirstErr = fmt.Errorf(\"unknown fingerprint operation: %q\", entry.Operation)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn parsed, firstErr\n}\n\nfunc (parsed *ParsedFingerprints) addMatchingFingerprint(fp Fingerprint, matchingPrint matchingFingerprint) {\n\tswitch fp.Type {\n\tcase FingerprintTypeTagID:\n\t\tparsed.tagPrints = append(parsed.tagPrints, matchingPrint)\n\tcase FingerprintTypeEnvID:\n\t\tparsed.envPrints = append(parsed.envPrints, matchingPrint)\n\tcase FingerprintTypePathID:\n\t\tparsed.pathPrints = append(parsed.pathPrints, matchingPrint)\n\tcase FingerprintTypeCmdlineID:\n\t\tparsed.cmdlinePrints = append(parsed.cmdlinePrints, matchingPrint)\n\tdefault:\n\t\t// This should never happen, as the types are checked already.\n\t\tpanic(fmt.Sprintf(\"unknown fingerprint type: %q\", fp.Type))\n\t}\n}\n\n// MatchFingerprints returns the highest matching score of the given\n// fingerprints and matching data.\nfunc MatchFingerprints(prints *ParsedFingerprints, md MatchingData) (highestScore int) {\n\t// Check tags.\n\ttags := md.Tags()\n\tif len(tags) > 0 {\n\t\tfor _, tagPrint := range prints.tagPrints {\n\t\t\tfor _, tag := range tags {\n\t\t\t\t// Check if tag key matches.\n\t\t\t\tif !tagPrint.MatchesKey(tag.Key) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Try matching the tag value.\n\t\t\t\tscore := tagPrint.Match(tag.Value)\n\t\t\t\tif score > highestScore {\n\t\t\t\t\thighestScore = score\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// If something matched, add base score and return.\n\t\tif highestScore > 0 {\n\t\t\treturn tagMatchBaseScore + highestScore\n\t\t}\n\t}\n\n\t// Check cmdline.\n\tcmdline := md.Cmdline()\n\tif cmdline != \"\" {\n\t\tfor _, cmdlinePrint := range prints.cmdlinePrints {\n\t\t\tif score := cmdlinePrint.Match(cmdline); score > highestScore {\n\t\t\t\thighestScore = score\n\t\t\t}\n\t\t}\n\t\tif highestScore > 0 {\n\t\t\treturn cmdlineMatchBaseScore + highestScore\n\t\t}\n\t}\n\n\t// Check env.\n\tfor _, envPrint := range prints.envPrints {\n\t\tfor key, value := range md.Env() {\n\t\t\t// Check if env key matches.\n\t\t\tif !envPrint.MatchesKey(key) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Try matching the env value.\n\t\t\tscore := envPrint.Match(value)\n\t\t\tif score > highestScore {\n\t\t\t\thighestScore = score\n\t\t\t}\n\t\t}\n\t}\n\t// If something matched, add base score and return.\n\tif highestScore > 0 {\n\t\treturn envMatchBaseScore + highestScore\n\t}\n\n\t// Check matching path.\n\tmatchingPath := md.MatchingPath()\n\tif matchingPath != \"\" {\n\t\tfor _, pathPrint := range prints.pathPrints {\n\t\t\t// Try matching the path value.\n\t\t\tscore := pathPrint.Match(matchingPath)\n\t\t\tif score > highestScore {\n\t\t\t\thighestScore = score\n\t\t\t}\n\t\t}\n\t\t// If something matched, add base score and return.\n\t\tif highestScore > 0 {\n\t\t\treturn matchingPathMatchBaseScore + highestScore\n\t\t}\n\t}\n\n\t// Check path.\n\tpath := md.Path()\n\tif path != \"\" {\n\t\tfor _, pathPrint := range prints.pathPrints {\n\t\t\t// Try matching the path value.\n\t\t\tscore := pathPrint.Match(path)\n\t\t\tif score > highestScore {\n\t\t\t\thighestScore = score\n\t\t\t}\n\t\t}\n\t\t// If something matched, add base score and return.\n\t\tif highestScore > 0 {\n\t\t\treturn pathMatchBaseScore + highestScore\n\t\t}\n\t}\n\n\t// Nothing matched.\n\treturn 0\n}\n\nfunc checkMatchStrength(value int) int {\n\tif value > maxMatchStrength {\n\t\treturn maxMatchStrength\n\t}\n\tif value < -maxMatchStrength {\n\t\treturn -maxMatchStrength\n\t}\n\treturn value\n}\n\nconst (\n\tderiveFPKeyIDForItemStart = iota + 1\n\tderiveFPKeyIDForType\n\tderiveFPKeyIDForKey\n\tderiveFPKeyIDForOperation\n\tderiveFPKeyIDForValue\n)\n\n// DeriveProfileID derives a profile ID from the given fingerprints.\nfunc DeriveProfileID(fps []Fingerprint) string {\n\t// Sort the fingerprints.\n\tsortAndCompactFingerprints(fps)\n\n\t// Compile data for hashing.\n\tc := container.New(nil)\n\tc.AppendInt(len(fps))\n\tfor _, fp := range fps {\n\t\tc.AppendNumber(deriveFPKeyIDForItemStart)\n\t\tif fp.Type != \"\" {\n\t\t\tc.AppendNumber(deriveFPKeyIDForType)\n\t\t\tc.AppendAsBlock([]byte(fp.Type))\n\t\t}\n\t\tif fp.Key != \"\" {\n\t\t\tc.AppendNumber(deriveFPKeyIDForKey)\n\t\t\tc.AppendAsBlock([]byte(fp.Key))\n\t\t}\n\t\tif fp.Operation != \"\" {\n\t\t\tc.AppendNumber(deriveFPKeyIDForOperation)\n\t\t\tc.AppendAsBlock([]byte(fp.Operation))\n\t\t}\n\t\tif fp.Value != \"\" {\n\t\t\tc.AppendNumber(deriveFPKeyIDForValue)\n\t\t\tc.AppendAsBlock([]byte(fp.Value))\n\t\t}\n\t}\n\n\t// Hash and return.\n\th := lhash.Digest(lhash.SHA3_256, c.CompileData())\n\treturn h.Base58()\n}\n\nfunc sortAndCompactFingerprints(fps []Fingerprint) []Fingerprint {\n\t// Sort.\n\tslices.SortFunc[[]Fingerprint, Fingerprint](fps, func(a, b Fingerprint) int {\n\t\tswitch {\n\t\tcase a.Type != b.Type:\n\t\t\treturn strings.Compare(a.Type, b.Type)\n\t\tcase a.Key != b.Key:\n\t\t\treturn strings.Compare(a.Key, b.Key)\n\t\tcase a.Operation != b.Operation:\n\t\t\treturn strings.Compare(a.Operation, b.Operation)\n\t\tcase a.Value != b.Value:\n\t\t\treturn strings.Compare(a.Value, b.Value)\n\t\tcase a.MergedFrom != b.MergedFrom:\n\t\t\treturn strings.Compare(a.MergedFrom, b.MergedFrom)\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\t})\n\n\t// De-duplicate.\n\t// Important: Even if the fingerprint is the same, but MergedFrom is\n\t// different, we need to keep the separate fingerprint, so that new installs\n\t// will cleanly update to the synced state: Auto-generated profiles need to\n\t// be automatically replaced by the merged version.\n\tfps = slices.CompactFunc[[]Fingerprint, Fingerprint](fps, func(a, b Fingerprint) bool {\n\t\treturn a.Type == b.Type &&\n\t\t\ta.Key == b.Key &&\n\t\t\ta.Operation == b.Operation &&\n\t\t\ta.Value == b.Value &&\n\t\t\ta.MergedFrom == b.MergedFrom\n\t})\n\n\treturn fps\n}\n"
  },
  {
    "path": "service/profile/fingerprint_test.go",
    "content": "package profile\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDeriveProfileID(t *testing.T) {\n\tt.Parallel()\n\n\tfps := []Fingerprint{\n\t\t{\n\t\t\tType:      FingerprintTypePathID,\n\t\t\tOperation: FingerprintOperationEqualsID,\n\t\t\tValue:     \"/sbin/init\",\n\t\t},\n\t\t{\n\t\t\tType:      FingerprintTypePathID,\n\t\t\tOperation: FingerprintOperationPrefixID,\n\t\t\tValue:     \"/\",\n\t\t},\n\t\t{\n\t\t\tType:      FingerprintTypeEnvID,\n\t\t\tKey:       \"PORTMASTER_PROFILE\",\n\t\t\tOperation: FingerprintOperationEqualsID,\n\t\t\tValue:     \"TEST-1\",\n\t\t},\n\t\t{\n\t\t\tType:      FingerprintTypeTagID,\n\t\t\tKey:       \"tag-key-1\",\n\t\t\tOperation: FingerprintOperationEqualsID,\n\t\t\tValue:     \"tag-key-2\",\n\t\t},\n\t}\n\n\t// Create rand source for shuffling.\n\trnd := rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\n\t// Test 100 times.\n\tfor range 100 {\n\t\t// Shuffle fingerprints.\n\t\trnd.Shuffle(len(fps), func(i, j int) {\n\t\t\tfps[i], fps[j] = fps[j], fps[i]\n\t\t})\n\n\t\t// Check if fingerprint matches.\n\t\tid := DeriveProfileID(fps)\n\t\tassert.Equal(t, \"PTSRP7rdCnmvdjRoPMTrtjj7qk7PxR1a9YdBWUGwnZXJh2\", id)\n\t}\n}\n"
  },
  {
    "path": "service/profile/framework.go",
    "content": "package profile\n\n// DEACTIVATED\n\n// import (\n// \t\"fmt\"\n// \t\"os\"\n// \t\"path/filepath\"\n// \t\"regexp\"\n// \t\"strings\"\n//\n// \t\"github.com/safing/portmaster/base/log\"\n// )\n//\n// type Framework struct {\n// \t// go hirarchy up\n// \tFindParent uint8 `json:\",omitempty bson:\",omitempty\"`\n// \t// get path from parent, amount of levels to go up the tree (1 means parent, 2 means parent of parents, and so on)\n// \tMergeWithParent bool `json:\",omitempty bson:\",omitempty\"`\n// \t// instead of getting the path of the parent, merge with it by presenting connections as if they were from that parent\n//\n// \t// go hirarchy down\n// \tFind string `json:\",omitempty bson:\",omitempty\"`\n// \t// Regular expression for finding path elements\n// \tBuild string `json:\",omitempty bson:\",omitempty\"`\n// \t// Path definitions for building path\n// \tVirtual bool `json:\",omitempty bson:\",omitempty\"`\n// \t// Treat resulting path as virtual, do not check if valid\n// }\n//\n// func (f *Framework) GetNewPath(command string, cwd string) (string, error) {\n// \t// \"/usr/bin/python script\"\n// \t// to\n// \t// \"/path/to/script\"\n// \tregex, err := regexp.Compile(f.Find)\n// \tif err != nil {\n// \t\treturn \"\", fmt.Errorf(\"profiles(framework): failed to compile framework regex: %s\", err)\n// \t}\n// \tmatched := regex.FindAllStringSubmatch(command, -1)\n// \tif len(matched) == 0 || len(matched[0]) < 2 {\n// \t\treturn \"\", fmt.Errorf(\"profiles(framework): regex \\\"%s\\\" for constructing path did not match command \\\"%s\\\"\", f.Find, command)\n// \t}\n//\n// \tvar lastError error\n// \tvar buildPath string\n// \tfor _, buildPath = range strings.Split(f.Build, \"|\") {\n//\n// \t\tbuildPath = strings.Replace(buildPath, \"{CWD}\", cwd, -1)\n// \t\tfor i := 1; i < len(matched[0]); i++ {\n// \t\t\tbuildPath = strings.Replace(buildPath, fmt.Sprintf(\"{%d}\", i), matched[0][i], -1)\n// \t\t}\n//\n// \t\tbuildPath = filepath.Clean(buildPath)\n//\n// \t\tif !f.Virtual {\n// \t\t\tif !strings.HasPrefix(buildPath, \"~/\") && !filepath.IsAbs(buildPath) {\n// \t\t\t\tlastError = fmt.Errorf(\"constructed path \\\"%s\\\" from framework is not absolute\", buildPath)\n// \t\t\t\tcontinue\n// \t\t\t}\n// \t\t\tif _, err := os.Stat(buildPath); errors.Is(err, fs.ErrNotExist) {\n// \t\t\t\tlastError = fmt.Errorf(\"constructed path \\\"%s\\\" does not exist\", buildPath)\n// \t\t\t\tcontinue\n// \t\t\t}\n// \t\t}\n//\n// \t\tlastError = nil\n// \t\tbreak\n//\n// \t}\n//\n// \tif lastError != nil {\n// \t\treturn \"\", fmt.Errorf(\"profiles(framework): failed to construct valid path, last error: %s\", lastError)\n// \t}\n// \tlog.Tracef(\"profiles(framework): transformed \\\"%s\\\" (%s) to \\\"%s\\\"\", command, cwd, buildPath)\n// \treturn buildPath, nil\n// }\n"
  },
  {
    "path": "service/profile/framework_test.go",
    "content": "package profile\n\n// DEACTIVATED\n\n// import (\n// \t\"testing\"\n// )\n//\n// func testGetNewPath(t *testing.T, f *Framework, command, cwd, expect string) {\n// \tnewPath, err := f.GetNewPath(command, cwd)\n// \tif err != nil {\n// \t\tt.Errorf(\"GetNewPath failed: %s\", err)\n// \t}\n// \tif newPath != expect {\n// \t\tt.Errorf(\"GetNewPath return unexpected result: got %s, expected %s\", newPath, expect)\n// \t}\n// }\n//\n// func TestFramework(t *testing.T) {\n// \tf1 := &Framework{\n// \t\tFind:  \"([^ ]+)$\",\n// \t\tBuild: \"{CWD}/{1}\",\n// \t}\n// \ttestGetNewPath(t, f1, \"/usr/bin/python bash\", \"/bin\", \"/bin/bash\")\n// \tf2 := &Framework{\n// \t\tFind:  \"([^ ]+)$\",\n// \t\tBuild: \"{1}|{CWD}/{1}\",\n// \t}\n// \ttestGetNewPath(t, f2, \"/usr/bin/python /bin/bash\", \"/tmp\", \"/bin/bash\")\n// }\n"
  },
  {
    "path": "service/profile/get.go",
    "content": "package profile\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar getProfileLock sync.Mutex\n\n// GetLocalProfile fetches a profile. This function ensures that the loaded profile\n// is shared among all callers. Always provide all available data points.\n// Passing an ID without MatchingData is valid, but could lead to inconsistent\n// data - use with caution.\nfunc GetLocalProfile(id string, md MatchingData, createProfileCallback func() *Profile) ( //nolint:gocognit\n\tprofile *Profile,\n\terr error,\n) {\n\t// Globally lock getting a profile.\n\t// This does not happen too often, and it ensures we really have integrity\n\t// and no race conditions.\n\tgetProfileLock.Lock()\n\tdefer getProfileLock.Unlock()\n\n\tvar previousVersion *Profile\n\n\t// Get active profile based on the ID, if available.\n\tif id != \"\" {\n\t\t// Check if there already is an active profile.\n\t\tprofile = getActiveProfile(MakeScopedID(SourceLocal, id))\n\t\tif profile != nil {\n\t\t\t// Mark active and return if not outdated.\n\t\t\tif profile.outdated.IsNotSet() {\n\t\t\t\tprofile.MarkStillActive()\n\t\t\t\treturn profile, nil\n\t\t\t}\n\n\t\t\t// If outdated, get from database.\n\t\t\tpreviousVersion = profile\n\t\t\tprofile = nil\n\t\t}\n\t}\n\n\t// In some cases, we might need to get a profile directly, without matching data.\n\t// This could lead to inconsistent data - use with caution.\n\t// Example: Saving prompt results to profile should always be to the same ID!\n\tif md == nil {\n\t\tif id == \"\" {\n\t\t\treturn nil, errors.New(\"cannot get local profiles without ID and matching data\")\n\t\t}\n\n\t\tprofile, err = getProfile(MakeScopedID(SourceLocal, id))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to load profile %s by ID: %w\", MakeScopedID(SourceLocal, id), err)\n\t\t}\n\t}\n\n\t// Check if we are requesting a special profile.\n\tvar created, special bool\n\tif id != \"\" && isSpecialProfileID(id) {\n\t\tspecial = true\n\n\t\t// Get special profile from DB.\n\t\tif profile == nil {\n\t\t\tprofile, err = getProfile(MakeScopedID(SourceLocal, id))\n\t\t\tif err != nil && !errors.Is(err, database.ErrNotFound) {\n\t\t\t\tlog.Warningf(\"profile: failed to get special profile %s: %s\", id, err)\n\t\t\t}\n\t\t}\n\n\t\t// Create profile if not found or if it needs a reset.\n\t\tif profile == nil || specialProfileNeedsReset(profile) {\n\t\t\tprofile = createSpecialProfile(id, md.Path())\n\t\t\tcreated = true\n\t\t}\n\t}\n\n\t// If we don't have a profile yet, find profile based on matching data.\n\tif profile == nil {\n\t\tprofile, err = findProfile(SourceLocal, md)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to search for profile: %w\", err)\n\t\t}\n\t}\n\n\t// If we still don't have a profile, create a new one.\n\tif profile == nil {\n\t\tcreated = true\n\n\t\t// Try the profile creation callback, if we have one.\n\t\tif createProfileCallback != nil {\n\t\t\tprofile = createProfileCallback()\n\t\t}\n\n\t\t// If that did not work, create a standard profile.\n\t\tif profile == nil {\n\t\t\tfpPath := md.MatchingPath()\n\t\t\tif fpPath == \"\" {\n\t\t\t\tfpPath = md.Path()\n\t\t\t}\n\n\t\t\tprofile = New(&Profile{\n\t\t\t\tID:                  id,\n\t\t\t\tSource:              SourceLocal,\n\t\t\t\tPresentationPath:    md.Path(),\n\t\t\t\tUsePresentationPath: true,\n\t\t\t\tFingerprints: []Fingerprint{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:      FingerprintTypePathID,\n\t\t\t\t\t\tOperation: FingerprintOperationEqualsID,\n\t\t\t\t\t\tValue:     fpPath,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\n\t// Initialize and update profile.\n\n\t// Update metadata.\n\tvar changed bool\n\tif md != nil {\n\t\tif special {\n\t\t\tchanged = updateSpecialProfileMetadata(profile, md.Path())\n\t\t} else {\n\t\t\tchanged = profile.updateMetadata(md.Path())\n\t\t}\n\t}\n\n\t// Save if created or changed.\n\tif created || changed {\n\t\t// Save profile.\n\t\terr := profile.Save()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"profile: failed to save profile %s after creation: %s\", profile.ScopedID(), err)\n\t\t}\n\t}\n\n\t// Trigger further metadata fetching from system if profile was created.\n\tif created && profile.UsePresentationPath && !special {\n\t\tmodule.mgr.Go(\"get profile metadata\", func(wc *mgr.WorkerCtx) error {\n\t\t\treturn profile.updateMetadataFromSystem(wc.Ctx(), md)\n\t\t})\n\t}\n\n\t// Prepare profile for first use.\n\n\t// Process profiles are coming directly from the database or are new.\n\t// As we don't use any caching, these will be new objects.\n\n\t// Add a layeredProfile.\n\n\t// If we are refetching, assign the layered profile from the previous version.\n\t// The internal references will be updated when the layered profile checks for updates.\n\tif previousVersion != nil && previousVersion.layeredProfile != nil {\n\t\tprofile.layeredProfile = previousVersion.layeredProfile\n\t}\n\n\t// Profiles must have a layered profile, create a new one if it\n\t// does not yet exist.\n\tif profile.layeredProfile == nil {\n\t\tprofile.layeredProfile = NewLayeredProfile(profile)\n\t}\n\n\t// Add the profile to the currently active profiles.\n\taddActiveProfile(profile)\n\n\treturn profile, nil\n}\n\n// getProfile fetches the profile for the given scoped ID.\nfunc getProfile(scopedID string) (profile *Profile, err error) {\n\t// Get profile from the database.\n\tr, err := profileDB.Get(ProfilesDBPath + scopedID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Parse and prepare the profile, return the result.\n\treturn loadProfile(r)\n}\n\n// findProfile searches for a profile with the given linked path. If it cannot\n// find one, it will create a new profile for the given linked path.\nfunc findProfile(source ProfileSource, md MatchingData) (profile *Profile, err error) {\n\t// TODO: Loading every profile from database and parsing it for every new\n\t// process might be quite expensive. Measure impact and possibly improve.\n\n\t// Get iterator over all profiles.\n\tit, err := profileDB.Query(query.New(ProfilesDBPath + MakeScopedID(source, \"\")))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to query for profiles: %w\", err)\n\t}\n\n\t// Find best matching profile.\n\tvar (\n\t\thighestScore int\n\t\tbestMatch    record.Record\n\t)\nprofileFeed:\n\tfor r := range it.Next {\n\t\t// Parse fingerprints.\n\t\tprints, err := loadProfileFingerprints(r)\n\t\tif err != nil {\n\t\t\tlog.Debugf(\"profile: failed to load fingerprints of %s: %s\", r.Key(), err)\n\t\t}\n\t\t// Continue with any returned fingerprints.\n\t\tif prints == nil {\n\t\t\tcontinue profileFeed\n\t\t}\n\n\t\t// Get matching score and compare.\n\t\tscore := MatchFingerprints(prints, md)\n\t\tswitch {\n\t\tcase score == 0:\n\t\t\t// Continue to next.\n\t\tcase score > highestScore:\n\t\t\thighestScore = score\n\t\t\tbestMatch = r\n\t\tcase score == highestScore:\n\t\t\t// Notify user of conflict and abort.\n\t\t\t// Use first match - this should be consistent.\n\t\t\tnotifyConflictingProfiles(bestMatch, r, md)\n\t\t\tit.Cancel()\n\t\t\tbreak profileFeed\n\t\t}\n\t}\n\n\t// Check if there was an error while iterating.\n\tif it.Err() != nil {\n\t\treturn nil, fmt.Errorf(\"failed to iterate over profiles: %w\", err)\n\t}\n\n\t// Return nothing if no profile matched.\n\tif bestMatch == nil {\n\t\treturn nil, nil\n\t}\n\n\t// If we have a match, parse and return the profile.\n\tprofile, err = loadProfile(bestMatch)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse selected profile %s: %w\", bestMatch.Key(), err)\n\t}\n\n\t// Check if this profile is already active and return the active version instead.\n\tif activeProfile := getActiveProfile(profile.ScopedID()); activeProfile != nil && !activeProfile.IsOutdated() {\n\t\treturn activeProfile, nil\n\t}\n\n\t// Return nothing if no profile matched.\n\treturn profile, nil\n}\n\nfunc loadProfileFingerprints(r record.Record) (parsed *ParsedFingerprints, err error) {\n\t// Ensure it's a profile.\n\tprofile, err := EnsureProfile(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Parse and return fingerprints.\n\treturn ParseFingerprints(profile.Fingerprints, profile.LinkedPath)\n}\n\nfunc loadProfile(r record.Record) (*Profile, error) {\n\t// ensure its a profile\n\tprofile, err := EnsureProfile(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// prepare profile\n\tprofile.prepProfile()\n\n\t// parse config\n\terr = profile.parseConfig()\n\tif err != nil {\n\t\tlog.Errorf(\"profiles: profile %s has (partly) invalid configuration: %s\", profile.ID, err)\n\t}\n\n\t// Set saved internally to suppress outdating profiles if saving internally.\n\tprofile.savedInternally = true\n\n\t// Mark as recently seen.\n\tmeta.UpdateLastSeen(profile.ScopedID())\n\n\t// return parsed profile\n\treturn profile, nil\n}\n\nfunc notifyConflictingProfiles(a, b record.Record, md MatchingData) {\n\t// Get profile names.\n\tvar idA, nameA, idB, nameB string\n\tprofileA, err := EnsureProfile(a)\n\tif err == nil {\n\t\tidA = profileA.ScopedID()\n\t\tnameA = profileA.Name\n\t} else {\n\t\tidA = strings.TrimPrefix(a.Key(), ProfilesDBPath)\n\t\tnameA = path.Base(idA)\n\t}\n\tprofileB, err := EnsureProfile(b)\n\tif err == nil {\n\t\tidB = profileB.ScopedID()\n\t\tnameB = profileB.Name\n\t} else {\n\t\tidB = strings.TrimPrefix(b.Key(), ProfilesDBPath)\n\t\tnameB = path.Base(idB)\n\t}\n\n\t// Notify user about conflict.\n\tnotifications.NotifyWarn(\n\t\tfmt.Sprintf(\"profiles:match-conflict:%s:%s\", idA, idB),\n\t\t\"App Settings Match Conflict\",\n\t\tfmt.Sprintf(\n\t\t\t\"Multiple app settings match the app at %q with the same priority, please change one of them: %q or %q\",\n\t\t\tmd.Path(),\n\t\t\tnameA,\n\t\t\tnameB,\n\t\t),\n\t\tnotifications.Action{\n\t\t\tText:    \"Change (1)\",\n\t\t\tType:    notifications.ActionTypeOpenProfile,\n\t\t\tPayload: idA,\n\t\t},\n\t\tnotifications.Action{\n\t\t\tText:    \"Change (2)\",\n\t\t\tType:    notifications.ActionTypeOpenProfile,\n\t\t\tPayload: idB,\n\t\t},\n\t\tnotifications.Action{\n\t\t\tID:   \"ack\",\n\t\t\tText: \"OK\",\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "service/profile/merge.go",
    "content": "package profile\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\n// MergeProfiles merges multiple profiles into a new one.\n// The new profile is saved and returned.\n// Only the icon and fingerprints are inherited from other profiles.\n// All other information is taken only from the primary profile.\nfunc MergeProfiles(name string, primary *Profile, secondaries ...*Profile) (newProfile *Profile, err error) {\n\tif primary == nil || len(secondaries) == 0 {\n\t\treturn nil, errors.New(\"must supply both a primary and at least one secondary profile for merging\")\n\t}\n\n\t// Fill info from primary profile.\n\tnowUnix := time.Now().Unix()\n\tnewProfile = &Profile{\n\t\tBase:                record.Base{},\n\t\tRWMutex:             sync.RWMutex{},\n\t\tID:                  \"\", // Omit ID to derive it from the new fingerprints.\n\t\tSource:              primary.Source,\n\t\tName:                name,\n\t\tDescription:         primary.Description,\n\t\tHomepage:            primary.Homepage,\n\t\tUsePresentationPath: false, // Disable presentation path.\n\t\tConfig:              primary.Config,\n\t\tCreated:             nowUnix,\n\t}\n\n\t// Fall back to name of primary profile, if none is set.\n\tif newProfile.Name == \"\" {\n\t\tnewProfile.Name = primary.Name\n\t}\n\n\t// If any profile was edited, set LastEdited to now.\n\tif primary.LastEdited > 0 {\n\t\tnewProfile.LastEdited = nowUnix\n\t} else {\n\t\tfor _, sp := range secondaries {\n\t\t\tif sp.LastEdited > 0 {\n\t\t\t\tnewProfile.LastEdited = nowUnix\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// Collect all icons.\n\tnewProfile.Icons = make([]binmeta.Icon, 0, len(secondaries)+1) // Guess the needed space.\n\tnewProfile.Icons = append(newProfile.Icons, primary.Icons...)\n\tfor _, sp := range secondaries {\n\t\tnewProfile.Icons = append(newProfile.Icons, sp.Icons...)\n\t}\n\tnewProfile.Icons = binmeta.SortAndCompactIcons(newProfile.Icons)\n\n\t// Collect all fingerprints.\n\tnewProfile.Fingerprints = make([]Fingerprint, 0, len(primary.Fingerprints)+len(secondaries)) // Guess the needed space.\n\tnewProfile.Fingerprints = addFingerprints(newProfile.Fingerprints, primary.Fingerprints, primary.ScopedID())\n\tfor _, sp := range secondaries {\n\t\tnewProfile.Fingerprints = addFingerprints(newProfile.Fingerprints, sp.Fingerprints, sp.ScopedID())\n\t}\n\tnewProfile.Fingerprints = sortAndCompactFingerprints(newProfile.Fingerprints)\n\n\t// Save new profile.\n\tnewProfile = New(newProfile)\n\tif err := newProfile.Save(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to save merged profile: %w\", err)\n\t}\n\n\t// Delete all previous profiles.\n\tif err := primary.delete(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to delete primary profile %s: %w\", primary.ScopedID(), err)\n\t}\n\tmodule.EventMigrated.Submit([]string{primary.ScopedID(), newProfile.ScopedID()})\n\tfor _, sp := range secondaries {\n\t\tif err := sp.delete(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to delete secondary profile %s: %w\", sp.ScopedID(), err)\n\t\t}\n\t\tmodule.EventMigrated.Submit([]string{sp.ScopedID(), newProfile.ScopedID()})\n\t}\n\n\treturn newProfile, nil\n}\n\nfunc addFingerprints(existing, add []Fingerprint, from string) []Fingerprint {\n\t// Copy all fingerprints and add the they are from.\n\tfor _, addFP := range add {\n\t\texisting = append(existing, Fingerprint{\n\t\t\tType:       addFP.Type,\n\t\t\tKey:        addFP.Key,\n\t\t\tOperation:  addFP.Operation,\n\t\t\tValue:      addFP.Value,\n\t\t\tMergedFrom: from,\n\t\t})\n\t}\n\n\treturn existing\n}\n"
  },
  {
    "path": "service/profile/meta.go",
    "content": "package profile\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\n// ProfilesMetadata holds metadata about all profiles that are not fit to be\n// stored with the profiles themselves.\ntype ProfilesMetadata struct {\n\trecord.Base\n\tsync.Mutex\n\n\tStates map[string]*MetaState\n}\n\n// MetaState describes the state of a profile.\ntype MetaState struct {\n\tState string\n\tAt    time.Time\n}\n\n// Profile metadata states.\nconst (\n\tMetaStateSeen    = \"seen\"\n\tMetaStateDeleted = \"deleted\"\n)\n\n// EnsureProfilesMetadata ensures that the given record is a *ProfilesMetadata, and returns it.\nfunc EnsureProfilesMetadata(r record.Record) (*ProfilesMetadata, error) {\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewMeta := &ProfilesMetadata{}\n\t\terr := record.Unwrap(r, newMeta)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newMeta, nil\n\t}\n\n\t// or adjust type\n\tnewMeta, ok := r.(*ProfilesMetadata)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *Profile, but %T\", r)\n\t}\n\treturn newMeta, nil\n}\n\nvar (\n\tprofilesMetadataKey = \"core:profile-states\"\n\n\tmeta *ProfilesMetadata\n\n\tremoveDeletedEntriesAfter = 30 * 24 * time.Hour\n)\n\n// loadProfilesMetadata loads the profile metadata from the database.\n// It may only be called during module starting, as there is no lock for \"meta\" itself.\nfunc loadProfilesMetadata() error {\n\tr, err := profileDB.Get(profilesMetadataKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\tloadedMeta, err := EnsureProfilesMetadata(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Set package variable.\n\tmeta = loadedMeta\n\treturn nil\n}\n\nfunc (meta *ProfilesMetadata) check() {\n\tif meta.States == nil {\n\t\tmeta.States = make(map[string]*MetaState)\n\t}\n}\n\n// Save saves the profile metadata to the database.\nfunc (meta *ProfilesMetadata) Save() error {\n\tif meta == nil {\n\t\treturn nil\n\t}\n\n\tfunc() {\n\t\tmeta.Lock()\n\t\tdefer meta.Unlock()\n\n\t\tif !meta.KeyIsSet() {\n\t\t\tmeta.SetKey(profilesMetadataKey)\n\t\t}\n\t}()\n\n\tmeta.Clean()\n\treturn profileDB.Put(meta)\n}\n\n// Clean removes old entries.\nfunc (meta *ProfilesMetadata) Clean() {\n\tif meta == nil {\n\t\treturn\n\t}\n\n\tmeta.Lock()\n\tdefer meta.Unlock()\n\n\tfor key, state := range meta.States {\n\t\tswitch {\n\t\tcase state == nil:\n\t\t\tdelete(meta.States, key)\n\t\tcase state.State != MetaStateDeleted:\n\t\t\tcontinue\n\t\tcase time.Since(state.At) > removeDeletedEntriesAfter:\n\t\t\tdelete(meta.States, key)\n\t\t}\n\t}\n}\n\n// GetLastSeen returns when the profile with the given ID was last seen.\nfunc (meta *ProfilesMetadata) GetLastSeen(scopedID string) *time.Time {\n\tif meta == nil {\n\t\treturn nil\n\t}\n\n\tmeta.Lock()\n\tdefer meta.Unlock()\n\n\tstate := meta.States[scopedID]\n\tswitch {\n\tcase state == nil:\n\t\treturn nil\n\tcase state.State == MetaStateSeen:\n\t\treturn &state.At\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// UpdateLastSeen sets the profile with the given ID as last seen now.\nfunc (meta *ProfilesMetadata) UpdateLastSeen(scopedID string) {\n\tif meta == nil {\n\t\treturn\n\t}\n\n\tmeta.Lock()\n\tdefer meta.Unlock()\n\n\tmeta.States[scopedID] = &MetaState{\n\t\tState: MetaStateSeen,\n\t\tAt:    time.Now().UTC(),\n\t}\n}\n\n// MarkDeleted marks the profile with the given ID as deleted.\nfunc (meta *ProfilesMetadata) MarkDeleted(scopedID string) {\n\tif meta == nil {\n\t\treturn\n\t}\n\n\tmeta.Lock()\n\tdefer meta.Unlock()\n\n\tmeta.States[scopedID] = &MetaState{\n\t\tState: MetaStateDeleted,\n\t\tAt:    time.Now().UTC(),\n\t}\n}\n\n// RemoveState removes any state of the profile with the given ID.\nfunc (meta *ProfilesMetadata) RemoveState(scopedID string) {\n\tif meta == nil {\n\t\treturn\n\t}\n\n\tmeta.Lock()\n\tdefer meta.Unlock()\n\n\tdelete(meta.States, scopedID)\n}\n"
  },
  {
    "path": "service/profile/migrations.go",
    "content": "package profile\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/hashicorp/go-version\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/migration\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nfunc registerMigrations() error {\n\treturn migrations.Add(\n\t\tmigration.Migration{\n\t\t\tDescription: \"Migrate from LinkedPath to Fingerprints and PresentationPath\",\n\t\t\tVersion:     \"v0.9.9\",\n\t\t\tMigrateFunc: migrateLinkedPath,\n\t\t},\n\t\tmigration.Migration{\n\t\t\tDescription: \"Migrate from Icon Fields to Icon List\",\n\t\t\tVersion:     \"v1.4.7\",\n\t\t\tMigrateFunc: migrateIcons,\n\t\t},\n\t\tmigration.Migration{\n\t\t\tDescription: \"Migrate from random profile IDs to fingerprint-derived IDs\",\n\t\t\tVersion:     \"v1.6.3\", // Re-run after mixed results in v1.6.0\n\t\t\tMigrateFunc: migrateToDerivedIDs,\n\t\t},\n\t)\n}\n\nfunc migrateLinkedPath(ctx context.Context, _, to *version.Version, db *database.Interface) error {\n\t// Get iterator over all profiles.\n\tit, err := db.Query(query.New(ProfilesDBPath))\n\tif err != nil {\n\t\tlog.Tracer(ctx).Errorf(\"profile: failed to migrate from linked path: failed to start query: %s\", err)\n\t\treturn nil\n\t}\n\n\t// Migrate all profiles.\n\tfor r := range it.Next {\n\t\t// Parse profile.\n\t\tprofile, err := EnsureProfile(r)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Debugf(\"profiles: failed to parse profile %s for migration: %s\", r.Key(), err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Skip if there is no LinkedPath to migrate from.\n\t\tif profile.LinkedPath == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Update metadata and save if changed.\n\t\tif profile.updateMetadata(\"\") {\n\t\t\terr = db.Put(profile)\n\t\t\tif err != nil {\n\t\t\t\tlog.Tracer(ctx).Debugf(\"profiles: failed to save profile %s after migration: %s\", r.Key(), err)\n\t\t\t} else {\n\t\t\t\tlog.Tracer(ctx).Tracef(\"profiles: migrated profile %s to %s\", r.Key(), to)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check if there was an error while iterating.\n\tif err := it.Err(); err != nil {\n\t\tlog.Tracer(ctx).Errorf(\"profile: failed to migrate from linked path: failed to iterate over profiles for migration: %s\", err)\n\t}\n\n\treturn nil\n}\n\nfunc migrateIcons(ctx context.Context, _, to *version.Version, db *database.Interface) error {\n\t// Get iterator over all profiles.\n\tit, err := db.Query(query.New(ProfilesDBPath))\n\tif err != nil {\n\t\tlog.Tracer(ctx).Errorf(\"profile: failed to migrate from icon fields: failed to start query: %s\", err)\n\t\treturn nil\n\t}\n\n\t// Migrate all profiles.\n\tvar (\n\t\tlastErr error\n\t\tfailed  int\n\t\ttotal   int\n\t)\n\tfor r := range it.Next {\n\t\t// Parse profile.\n\t\tprofile, err := EnsureProfile(r)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Debugf(\"profiles: failed to parse profile %s for migration: %s\", r.Key(), err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Skip if there is no (valid) icon defined or the icon list is already populated.\n\t\tif profile.Icon == \"\" || profile.IconType == \"\" || len(profile.Icons) > 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Migrate to icon list.\n\t\tprofile.Icons = []binmeta.Icon{{\n\t\t\tType:  profile.IconType,\n\t\t\tValue: profile.Icon,\n\t\t}}\n\n\t\t// Save back to DB.\n\t\terr = db.Put(profile)\n\t\tif err != nil {\n\t\t\tfailed++\n\t\t\tlastErr = err\n\t\t\tlog.Tracer(ctx).Debugf(\"profiles: failed to save profile %s after migration: %s\", r.Key(), err)\n\t\t} else {\n\t\t\tlog.Tracer(ctx).Tracef(\"profiles: migrated profile %s to %s\", r.Key(), to)\n\t\t}\n\t\ttotal++\n\t}\n\n\t// Check if there was an error while iterating.\n\tif err := it.Err(); err != nil {\n\t\tlog.Tracer(ctx).Errorf(\"profile: failed to migrate from icon fields: failed to iterate over profiles for migration: %s\", err)\n\t}\n\n\t// Log migration failure and try again next time.\n\tif lastErr != nil {\n\t\t// Normally, an icon migration would not be such a big error, but this is a test\n\t\t// run for the profile IDs and we absolutely need to know if anything went wrong.\n\t\tmodule.states.Add(mgr.State{\n\t\t\tID:      \"migration-failed-icons\",\n\t\t\tName:    \"Profile Migration Failed\",\n\t\t\tMessage: fmt.Sprintf(\"Failed to migrate icons of %d profiles (out of %d pending). The last error was: %s\\n\\nPlease restart Portmaster to try the migration again.\", failed, total, lastErr),\n\t\t\tType:    mgr.StateTypeError,\n\t\t})\n\t\treturn fmt.Errorf(\"failed to migrate %d profiles (out of %d pending) - last error: %w\", failed, total, lastErr)\n\t}\n\n\treturn lastErr\n}\n\nvar randomUUIDRegex = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)\n\nfunc migrateToDerivedIDs(ctx context.Context, _, to *version.Version, db *database.Interface) error {\n\tvar profilesToDelete []string //nolint:prealloc // We don't know how many profiles there are.\n\n\t// Get iterator over all profiles.\n\tit, err := db.Query(query.New(ProfilesDBPath))\n\tif err != nil {\n\t\tlog.Tracer(ctx).Errorf(\"profile: failed to migrate to derived profile IDs: failed to start query: %s\", err)\n\t\treturn nil\n\t}\n\n\t// Migrate all profiles.\n\tvar (\n\t\tlastErr error\n\t\tfailed  int\n\t\ttotal   int\n\t)\n\tfor r := range it.Next {\n\t\t// Parse profile.\n\t\tprofile, err := EnsureProfile(r)\n\t\tif err != nil {\n\t\t\tfailed++\n\t\t\tlastErr = err\n\t\t\tlog.Tracer(ctx).Debugf(\"profiles: failed to parse profile %s for migration: %s\", r.Key(), err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Skip if the ID does not look like a random UUID.\n\t\tif !randomUUIDRegex.MatchString(profile.ID) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Generate new ID.\n\t\toldScopedID := profile.ScopedID()\n\t\tnewID := DeriveProfileID(profile.Fingerprints)\n\n\t\t// If they match, skip migration for this profile.\n\t\tif profile.ID == newID {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Reset key.\n\t\tprofile.ResetKey()\n\t\t// Set new ID and rebuild the key.\n\t\tprofile.ID = newID\n\t\tprofile.makeKey()\n\n\t\t// Save back to DB.\n\t\terr = db.Put(profile)\n\t\tif err != nil {\n\t\t\tfailed++\n\t\t\tlastErr = err\n\t\t\tlog.Tracer(ctx).Debugf(\"profiles: failed to save profile %s after migration: %s\", r.Key(), err)\n\t\t} else {\n\t\t\tlog.Tracer(ctx).Tracef(\"profiles: migrated profile %s to %s\", r.Key(), to)\n\n\t\t\t// Add old ID to profiles that we need to delete.\n\t\t\tprofilesToDelete = append(profilesToDelete, oldScopedID)\n\t\t}\n\t\ttotal++\n\t}\n\n\t// Check if there was an error while iterating.\n\tif err := it.Err(); err != nil {\n\t\tlog.Tracer(ctx).Errorf(\"profile: failed to migrate to derived profile IDs: failed to iterate over profiles for migration: %s\", err)\n\t}\n\n\t// Delete old migrated profiles.\n\tfor _, scopedID := range profilesToDelete {\n\t\tif err := db.Delete(ProfilesDBPath + scopedID); err != nil {\n\t\t\tlog.Tracer(ctx).Errorf(\"profile: failed to delete old profile %s during migration: %s\", scopedID, err)\n\t\t}\n\t}\n\n\t// Log migration failure and try again next time.\n\tif lastErr != nil {\n\t\tmodule.states.Add(mgr.State{\n\t\t\tID:      \"migration-failed-derived-IDs\",\n\t\t\tName:    \"Profile Migration Failed\",\n\t\t\tMessage: fmt.Sprintf(\"Failed to migrate profile IDs of %d profiles (out of %d pending). The last error was: %s\\n\\nPlease restart Portmaster to try the migration again.\", failed, total, lastErr),\n\t\t\tType:    mgr.StateTypeError,\n\t\t})\n\t\treturn fmt.Errorf(\"failed to migrate %d profiles (out of %d pending) - last error: %w\", failed, total, lastErr)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/profile/module.go",
    "content": "package profile\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/migration\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t_ \"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\nvar migrations = migration.New(\"core:migrations/profile\")\n\n// Events.\nconst (\n\tConfigChangeEvent = \"profile config change\"\n\tDeletedEvent      = \"profile deleted\"\n\tMigratedEvent     = \"profile migrated\"\n)\n\ntype ProfileModule struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tEventConfigChange *mgr.EventMgr[string]\n\tEventDelete       *mgr.EventMgr[string]\n\tEventMigrated     *mgr.EventMgr[[]string]\n\n\tstates *mgr.StateMgr\n}\n\nfunc (pm *ProfileModule) Manager() *mgr.Manager {\n\treturn pm.mgr\n}\n\nfunc (pm *ProfileModule) States() *mgr.StateMgr {\n\treturn pm.states\n}\n\nfunc (pm *ProfileModule) Start() error {\n\treturn start()\n}\n\nfunc (pm *ProfileModule) Stop() error {\n\treturn stop()\n}\n\nfunc prep() error {\n\tif err := registerConfiguration(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerMigrations(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := registerAPIEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\t// Setup icon storage location.\n\tdatabaseDir := filepath.Join(module.instance.DataDir(), \"databases\")\n\t// Ensure folder existents and permission\n\terr := utils.EnsureDirectory(databaseDir, utils.AdminOnlyExecPermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to ensure directory existence %s: %w\", databaseDir, err)\n\t}\n\ticonsDir := filepath.Join(databaseDir, \"icons\")\n\terr = utils.EnsureDirectory(iconsDir, utils.AdminOnlyExecPermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to ensure directory existence %s: %w\", iconsDir, err)\n\t}\n\n\tbinmeta.ProfileIconStoragePath = iconsDir\n\n\treturn nil\n}\n\nfunc start() error {\n\tif err := loadProfilesMetadata(); err != nil {\n\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\tlog.Warningf(\"profile: failed to load profiles metadata, falling back to empty state: %s\", err)\n\t\t}\n\t\tmeta = &ProfilesMetadata{}\n\t}\n\tmeta.check()\n\n\tif err := migrations.Migrate(module.mgr.Ctx()); err != nil {\n\t\tlog.Errorf(\"profile: migrations failed: %s\", err)\n\t}\n\n\terr := registerValidationDBHook()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = registerRevisionProvider()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = startProfileUpdateChecker()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmodule.mgr.Go(\"clean active profiles\", cleanActiveProfiles)\n\n\t// Register config callback when starting, as it depends on the updates module,\n\t// but the config system will already submit events earlier.\n\tif err := registerGlobalConfigProfileUpdater(); err != nil {\n\t\treturn err\n\t}\n\n\terr = updateGlobalConfigProfile(module.mgr.Ctx())\n\tif err != nil {\n\t\tlog.Warningf(\"profile: error during loading global profile from configuration: %s\", err)\n\t}\n\n\treturn nil\n}\n\nfunc stop() error {\n\treturn meta.Save()\n}\n\nvar (\n\tmodule     *ProfileModule\n\tshimLoaded atomic.Bool\n)\n\nfunc NewModule(instance instance) (*ProfileModule, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Profile\")\n\tmodule = &ProfileModule{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tEventConfigChange: mgr.NewEventMgr[string](ConfigChangeEvent, m),\n\t\tEventDelete:       mgr.NewEventMgr[string](DeletedEvent, m),\n\t\tEventMigrated:     mgr.NewEventMgr[[]string](MigratedEvent, m),\n\n\t\tstates: mgr.NewStateMgr(m),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tDataDir() string\n\tConfig() *config.Config\n}\n"
  },
  {
    "path": "service/profile/profile-layered-provider.go",
    "content": "package profile\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/runtime\"\n)\n\nconst (\n\trevisionProviderPrefix = \"layeredProfile/\"\n)\n\nvar (\n\terrProfileNotActive                  = errors.New(\"profile not active\")\n\terrNoLayeredProfile                  = errors.New(\"profile has no layered profile\")\n\tpushLayeredProfile  runtime.PushFunc = func(...record.Record) {}\n)\n\nfunc registerRevisionProvider() error {\n\tpush, err := runtime.Register(\n\t\trevisionProviderPrefix,\n\t\truntime.SimpleValueGetterFunc(getRevisions),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpushLayeredProfile = push\n\n\treturn nil\n}\n\nfunc getRevisions(key string) ([]record.Record, error) {\n\tkey = strings.TrimPrefix(key, revisionProviderPrefix)\n\n\tvar profiles []*Profile\n\n\tif key == \"\" {\n\t\tprofiles = getAllActiveProfiles()\n\t} else {\n\t\t// Get active profile.\n\t\tprofile := getActiveProfile(key)\n\t\tif profile == nil {\n\t\t\treturn nil, errProfileNotActive\n\t\t}\n\t\tprofiles = append(profiles, profile)\n\t}\n\n\trecords := make([]record.Record, 0, len(profiles))\n\n\tfor _, p := range profiles {\n\t\tlayered, err := getProfileRevision(p)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"failed to get layered profile for %s: %s\", p.ID, err)\n\t\t\tcontinue\n\t\t}\n\n\t\trecords = append(records, layered)\n\t}\n\n\treturn records, nil\n}\n\n// getProfileRevision returns the layered profile for p.\n// It also updates the layered profile if required.\nfunc getProfileRevision(p *Profile) (*LayeredProfile, error) {\n\t// Get layered profile.\n\tlayeredProfile := p.LayeredProfile()\n\tif layeredProfile == nil {\n\t\treturn nil, errNoLayeredProfile\n\t}\n\n\t// Update profiles if necessary.\n\t// TODO: Cannot update as we have too little information.\n\t// Just return the current state. Previous code:\n\t// if layeredProfile.NeedsUpdate() {\n\t// \tlayeredProfile.Update()\n\t// }\n\n\treturn layeredProfile, nil\n}\n"
  },
  {
    "path": "service/profile/profile-layered.go",
    "content": "package profile\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\n// LayeredProfile combines multiple Profiles.\ntype LayeredProfile struct {\n\trecord.Base\n\tsync.RWMutex\n\n\tlocalProfile *Profile\n\tlayers       []*Profile\n\n\tLayerIDs           []string\n\tRevisionCounter    uint64\n\tglobalValidityFlag *config.ValidityFlag\n\n\tsecurityLevel *uint32\n\n\t// These functions give layered access to configuration options and require\n\t// the layered profile to be read locked.\n\n\t// TODO(ppacher): we need JSON tags here so the layeredProfile can be exposed\n\t// via the API. If we ever switch away from JSON to something else supported\n\t// by DSD this WILL BREAK!\n\n\tDisableAutoPermit   config.BoolOption   `json:\"-\"`\n\tBlockScopeLocal     config.BoolOption   `json:\"-\"`\n\tBlockScopeLAN       config.BoolOption   `json:\"-\"`\n\tBlockScopeInternet  config.BoolOption   `json:\"-\"`\n\tBlockP2P            config.BoolOption   `json:\"-\"`\n\tBlockInbound        config.BoolOption   `json:\"-\"`\n\tRemoveOutOfScopeDNS config.BoolOption   `json:\"-\"`\n\tRemoveBlockedDNS    config.BoolOption   `json:\"-\"`\n\tFilterSubDomains    config.BoolOption   `json:\"-\"`\n\tFilterCNAMEs        config.BoolOption   `json:\"-\"`\n\tPreventBypassing    config.BoolOption   `json:\"-\"`\n\tDomainHeuristics    config.BoolOption   `json:\"-\"`\n\tUseSPN              config.BoolOption   `json:\"-\"`\n\tSPNRoutingAlgorithm config.StringOption `json:\"-\"`\n\tEnableHistory       config.BoolOption   `json:\"-\"`\n\tKeepHistory         config.IntOption    `json:\"-\"`\n}\n\n// NewLayeredProfile returns a new layered profile based on the given local profile.\nfunc NewLayeredProfile(localProfile *Profile) *LayeredProfile {\n\tvar securityLevelVal uint32\n\n\tlp := &LayeredProfile{\n\t\tlocalProfile:       localProfile,\n\t\tlayers:             make([]*Profile, 0, 1),\n\t\tLayerIDs:           make([]string, 0, 1),\n\t\tglobalValidityFlag: config.NewValidityFlag(),\n\t\tRevisionCounter:    1,\n\t\tsecurityLevel:      &securityLevelVal,\n\t}\n\n\tlp.DisableAutoPermit = lp.wrapBoolOption(\n\t\tCfgOptionDisableAutoPermitKey,\n\t\tcfgOptionDisableAutoPermit,\n\t)\n\tlp.BlockScopeLocal = lp.wrapBoolOption(\n\t\tCfgOptionBlockScopeLocalKey,\n\t\tcfgOptionBlockScopeLocal,\n\t)\n\tlp.BlockScopeLAN = lp.wrapBoolOption(\n\t\tCfgOptionBlockScopeLANKey,\n\t\tcfgOptionBlockScopeLAN,\n\t)\n\tlp.BlockScopeInternet = lp.wrapBoolOption(\n\t\tCfgOptionBlockScopeInternetKey,\n\t\tcfgOptionBlockScopeInternet,\n\t)\n\tlp.BlockP2P = lp.wrapBoolOption(\n\t\tCfgOptionBlockP2PKey,\n\t\tcfgOptionBlockP2P,\n\t)\n\tlp.BlockInbound = lp.wrapBoolOption(\n\t\tCfgOptionBlockInboundKey,\n\t\tcfgOptionBlockInbound,\n\t)\n\tlp.RemoveOutOfScopeDNS = lp.wrapBoolOption(\n\t\tCfgOptionRemoveOutOfScopeDNSKey,\n\t\tcfgOptionRemoveOutOfScopeDNS,\n\t)\n\tlp.RemoveBlockedDNS = lp.wrapBoolOption(\n\t\tCfgOptionRemoveBlockedDNSKey,\n\t\tcfgOptionRemoveBlockedDNS,\n\t)\n\tlp.FilterSubDomains = lp.wrapBoolOption(\n\t\tCfgOptionFilterSubDomainsKey,\n\t\tcfgOptionFilterSubDomains,\n\t)\n\tlp.FilterCNAMEs = lp.wrapBoolOption(\n\t\tCfgOptionFilterCNAMEKey,\n\t\tcfgOptionFilterCNAME,\n\t)\n\tlp.PreventBypassing = lp.wrapBoolOption(\n\t\tCfgOptionPreventBypassingKey,\n\t\tcfgOptionPreventBypassing,\n\t)\n\tlp.DomainHeuristics = lp.wrapBoolOption(\n\t\tCfgOptionDomainHeuristicsKey,\n\t\tcfgOptionDomainHeuristics,\n\t)\n\tlp.UseSPN = lp.wrapBoolOption(\n\t\tCfgOptionUseSPNKey,\n\t\tcfgOptionUseSPN,\n\t)\n\tlp.SPNRoutingAlgorithm = lp.wrapStringOption(\n\t\tCfgOptionRoutingAlgorithmKey,\n\t\tcfgOptionRoutingAlgorithm,\n\t)\n\tlp.EnableHistory = lp.wrapBoolOption(\n\t\tCfgOptionEnableHistoryKey,\n\t\tcfgOptionEnableHistory,\n\t)\n\tlp.KeepHistory = lp.wrapIntOption(\n\t\tCfgOptionKeepHistoryKey,\n\t\tcfgOptionKeepHistory,\n\t)\n\n\tlp.LayerIDs = append(lp.LayerIDs, localProfile.ScopedID())\n\tlp.layers = append(lp.layers, localProfile)\n\n\t// TODO: Load additional profiles.\n\n\tlp.CreateMeta()\n\tlp.SetKey(runtime.DefaultRegistry.DatabaseName() + \":\" + revisionProviderPrefix + localProfile.ScopedID())\n\n\t// Inform database subscribers about the new layered profile.\n\tlp.Lock()\n\tdefer lp.Unlock()\n\n\tpushLayeredProfile(lp)\n\n\treturn lp\n}\n\n// LockForUsage locks the layered profile, including all layers individually.\nfunc (lp *LayeredProfile) LockForUsage() {\n\tlp.RLock()\n\tfor _, layer := range lp.layers {\n\t\tlayer.RLock()\n\t}\n}\n\n// UnlockForUsage unlocks the layered profile, including all layers individually.\nfunc (lp *LayeredProfile) UnlockForUsage() {\n\tlp.RUnlock()\n\tfor _, layer := range lp.layers {\n\t\tlayer.RUnlock()\n\t}\n}\n\n// LocalProfile returns the local profile associated with this layered profile.\nfunc (lp *LayeredProfile) LocalProfile() *Profile {\n\tif lp == nil {\n\t\treturn nil\n\t}\n\n\tlp.RLock()\n\tdefer lp.RUnlock()\n\n\treturn lp.localProfile\n}\n\n// LocalProfileWithoutLocking returns the local profile associated with this\n// layered profile, but without locking the layered profile.\n// This method my only be used when the caller already has a lock on the layered profile.\nfunc (lp *LayeredProfile) LocalProfileWithoutLocking() *Profile {\n\tif lp == nil {\n\t\treturn nil\n\t}\n\n\treturn lp.localProfile\n}\n\n// increaseRevisionCounter increases the revision counter and pushes the\n// layered profile to listeners.\nfunc (lp *LayeredProfile) increaseRevisionCounter(lock bool) (revisionCounter uint64) { //nolint:unparam // This is documentation.\n\tif lp == nil {\n\t\treturn 0\n\t}\n\n\tif lock {\n\t\tlp.Lock()\n\t\tdefer lp.Unlock()\n\t}\n\n\t// Increase the revision counter.\n\tlp.RevisionCounter++\n\t// Push the increased counter to the UI.\n\tpushLayeredProfile(lp)\n\n\treturn lp.RevisionCounter\n}\n\n// RevisionCnt returns the current profile revision counter.\nfunc (lp *LayeredProfile) RevisionCnt() (revisionCounter uint64) {\n\tif lp == nil {\n\t\treturn 0\n\t}\n\n\tlp.RLock()\n\tdefer lp.RUnlock()\n\n\treturn lp.RevisionCounter\n}\n\n// MarkStillActive marks all the layers as still active.\nfunc (lp *LayeredProfile) MarkStillActive() {\n\tif lp == nil {\n\t\treturn\n\t}\n\n\tlp.RLock()\n\tdefer lp.RUnlock()\n\n\tfor _, layer := range lp.layers {\n\t\tlayer.MarkStillActive()\n\t}\n}\n\n// NeedsUpdate checks for outdated profiles.\nfunc (lp *LayeredProfile) NeedsUpdate() (outdated bool) {\n\tlp.RLock()\n\tdefer lp.RUnlock()\n\n\t// Check global config state.\n\tif !lp.globalValidityFlag.IsValid() {\n\t\treturn true\n\t}\n\n\t// Check config in layers.\n\tfor _, layer := range lp.layers {\n\t\tif layer.outdated.IsSet() {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// Update checks for and replaces any outdated profiles.\nfunc (lp *LayeredProfile) Update(md MatchingData, createProfileCallback func() *Profile) (revisionCounter uint64) {\n\tlp.Lock()\n\tdefer lp.Unlock()\n\n\tvar changed bool\n\tfor i, layer := range lp.layers {\n\t\tif layer.outdated.IsSet() {\n\t\t\t// Check for unsupported sources.\n\t\t\tif layer.Source != SourceLocal {\n\t\t\t\tlog.Warningf(\"profile: updating profiles outside of local source is not supported: %s\", layer.ScopedID())\n\t\t\t\tlayer.outdated.UnSet()\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Update layer.\n\t\t\tchanged = true\n\t\t\tnewLayer, err := GetLocalProfile(layer.ID, md, createProfileCallback)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(\"profiles: failed to update profile %s: %s\", layer.ScopedID(), err)\n\t\t\t} else {\n\t\t\t\tlp.layers[i] = newLayer\n\t\t\t}\n\n\t\t\t// Update local profile reference.\n\t\t\tif i == 0 {\n\t\t\t\tlp.localProfile = newLayer\n\t\t\t}\n\t\t}\n\t}\n\tif !lp.globalValidityFlag.IsValid() {\n\t\tchanged = true\n\t}\n\n\tif changed {\n\t\t// get global config validity flag\n\t\tlp.globalValidityFlag.Refresh()\n\n\t\t// bump revision counter\n\t\tlp.increaseRevisionCounter(false)\n\t}\n\n\treturn lp.RevisionCounter\n}\n\n// SecurityLevel returns the highest security level of all layered profiles. This function is atomic and does not require any locking.\nfunc (lp *LayeredProfile) SecurityLevel() uint8 {\n\treturn uint8(atomic.LoadUint32(lp.securityLevel))\n}\n\n// DefaultAction returns the active default action ID. This functions requires the layered profile to be read locked.\nfunc (lp *LayeredProfile) DefaultAction() uint8 {\n\tfor _, layer := range lp.layers {\n\t\tif layer.defaultAction > 0 {\n\t\t\treturn layer.defaultAction\n\t\t}\n\t}\n\n\tcfgLock.RLock()\n\tdefer cfgLock.RUnlock()\n\treturn cfgDefaultAction\n}\n\n// MatchEndpoint checks if the given endpoint matches an entry in any of the profiles. This functions requires the layered profile to be read locked.\nfunc (lp *LayeredProfile) MatchEndpoint(ctx context.Context, entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) {\n\tfor _, layer := range lp.layers {\n\t\tif layer.endpoints.IsSet() {\n\t\t\tresult, reason := layer.endpoints.Match(ctx, entity)\n\t\t\tif endpoints.IsDecision(result) {\n\t\t\t\treturn result, reason\n\t\t\t}\n\t\t}\n\t}\n\n\tcfgLock.RLock()\n\tdefer cfgLock.RUnlock()\n\treturn cfgEndpoints.Match(ctx, entity)\n}\n\n// MatchServiceEndpoint checks if the given endpoint of an inbound connection matches an entry in any of the profiles. This functions requires the layered profile to be read locked.\nfunc (lp *LayeredProfile) MatchServiceEndpoint(ctx context.Context, entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) {\n\tentity.EnableReverseResolving()\n\n\tfor _, layer := range lp.layers {\n\t\tif layer.serviceEndpoints.IsSet() {\n\t\t\tresult, reason := layer.serviceEndpoints.Match(ctx, entity)\n\t\t\tif endpoints.IsDecision(result) {\n\t\t\t\treturn result, reason\n\t\t\t}\n\t\t}\n\t}\n\n\tcfgLock.RLock()\n\tdefer cfgLock.RUnlock()\n\treturn cfgServiceEndpoints.Match(ctx, entity)\n}\n\n// MatchSPNUsagePolicy checks if the given endpoint matches an entry in any of the profiles. This functions requires the layered profile to be read locked.\nfunc (lp *LayeredProfile) MatchSPNUsagePolicy(ctx context.Context, entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) {\n\tfor _, layer := range lp.layers {\n\t\tif layer.spnUsagePolicy.IsSet() {\n\t\t\tresult, reason := layer.spnUsagePolicy.Match(ctx, entity)\n\t\t\tif endpoints.IsDecision(result) {\n\t\t\t\treturn result, reason\n\t\t\t}\n\t\t}\n\t}\n\n\tcfgLock.RLock()\n\tdefer cfgLock.RUnlock()\n\treturn cfgSPNUsagePolicy.Match(ctx, entity)\n}\n\n// StackedTransitHubPolicies returns all transit hub policies of the layered profile, including the global one.\nfunc (lp *LayeredProfile) StackedTransitHubPolicies() []endpoints.Endpoints {\n\tpolicies := make([]endpoints.Endpoints, 0, len(lp.layers)+3) // +1 for global policy, +2 for intel policies\n\n\tfor _, layer := range lp.layers {\n\t\tif layer.spnTransitHubPolicy.IsSet() {\n\t\t\tpolicies = append(policies, layer.spnTransitHubPolicy)\n\t\t}\n\t}\n\n\tcfgLock.RLock()\n\tdefer cfgLock.RUnlock()\n\tpolicies = append(policies, cfgSPNTransitHubPolicy)\n\n\treturn policies\n}\n\n// StackedExitHubPolicies returns all exit hub policies of the layered profile, including the global one.\nfunc (lp *LayeredProfile) StackedExitHubPolicies() []endpoints.Endpoints {\n\tpolicies := make([]endpoints.Endpoints, 0, len(lp.layers)+3) // +1 for global policy, +2 for intel policies\n\n\tfor _, layer := range lp.layers {\n\t\tif layer.spnExitHubPolicy.IsSet() {\n\t\t\tpolicies = append(policies, layer.spnExitHubPolicy)\n\t\t}\n\t}\n\n\tcfgLock.RLock()\n\tdefer cfgLock.RUnlock()\n\tpolicies = append(policies, cfgSPNExitHubPolicy)\n\n\treturn policies\n}\n\n// MatchFilterLists matches the entity against the set of filter\n// lists. This functions requires the layered profile to be read locked.\nfunc (lp *LayeredProfile) MatchFilterLists(ctx context.Context, entity *intel.Entity) (endpoints.EPResult, endpoints.Reason) {\n\tentity.ResolveSubDomainLists(ctx, lp.FilterSubDomains())\n\tentity.EnableCNAMECheck(ctx, lp.FilterCNAMEs())\n\n\tfor _, layer := range lp.layers {\n\t\t// Search for the first layer that has filter lists set.\n\t\tif layer.filterListsSet {\n\t\t\tif entity.MatchLists(layer.filterListIDs) {\n\t\t\t\treturn endpoints.Denied, entity.ListBlockReason()\n\t\t\t}\n\n\t\t\treturn endpoints.NoMatch, nil\n\t\t}\n\t}\n\n\tcfgLock.RLock()\n\tdefer cfgLock.RUnlock()\n\tif len(cfgFilterLists) > 0 {\n\t\tif entity.MatchLists(cfgFilterLists) {\n\t\t\treturn endpoints.Denied, entity.ListBlockReason()\n\t\t}\n\t}\n\n\treturn endpoints.NoMatch, nil\n}\n\nfunc (lp *LayeredProfile) wrapBoolOption(configKey string, globalConfig config.BoolOption) config.BoolOption {\n\tvar revCnt uint64 = 0\n\tvar value bool\n\tvar refreshLock sync.Mutex\n\n\treturn func() bool {\n\t\trefreshLock.Lock()\n\t\tdefer refreshLock.Unlock()\n\n\t\t// Check if we need to refresh the value.\n\t\tif revCnt != lp.RevisionCounter {\n\t\t\trevCnt = lp.RevisionCounter\n\n\t\t\t// Go through all layers to find an active value.\n\t\t\tfound := false\n\t\t\tfor _, layer := range lp.layers {\n\t\t\t\tlayerValue, ok := layer.configPerspective.GetAsBool(configKey)\n\t\t\t\tif ok {\n\t\t\t\t\tfound = true\n\t\t\t\t\tvalue = layerValue\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !found {\n\t\t\t\tvalue = globalConfig()\n\t\t\t}\n\t\t}\n\n\t\treturn value\n\t}\n}\n\nfunc (lp *LayeredProfile) wrapIntOption(configKey string, globalConfig config.IntOption) config.IntOption {\n\tvar revCnt uint64 = 0\n\tvar value int64\n\tvar refreshLock sync.Mutex\n\n\treturn func() int64 {\n\t\trefreshLock.Lock()\n\t\tdefer refreshLock.Unlock()\n\n\t\t// Check if we need to refresh the value.\n\t\tif revCnt != lp.RevisionCounter {\n\t\t\trevCnt = lp.RevisionCounter\n\n\t\t\t// Go through all layers to find an active value.\n\t\t\tfound := false\n\t\t\tfor _, layer := range lp.layers {\n\t\t\t\tlayerValue, ok := layer.configPerspective.GetAsInt(configKey)\n\t\t\t\tif ok {\n\t\t\t\t\tfound = true\n\t\t\t\t\tvalue = layerValue\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !found {\n\t\t\t\tvalue = globalConfig()\n\t\t\t}\n\t\t}\n\n\t\treturn value\n\t}\n}\n\n// GetProfileSource returns the database key of the first profile in the\n// layers that has the given configuration key set. If it returns an empty\n// string, the global profile can be assumed to have been effective.\nfunc (lp *LayeredProfile) GetProfileSource(configKey string) string {\n\tfor _, layer := range lp.layers {\n\t\tif layer.configPerspective.Has(configKey) {\n\t\t\treturn layer.Key()\n\t\t}\n\t}\n\n\t// Global Profile\n\treturn \"\"\n}\n\nfunc (lp *LayeredProfile) wrapStringOption(configKey string, globalConfig config.StringOption) config.StringOption {\n\tvar revCnt uint64 = 0\n\tvar value string\n\tvar refreshLock sync.Mutex\n\n\treturn func() string {\n\t\trefreshLock.Lock()\n\t\tdefer refreshLock.Unlock()\n\n\t\t// Check if we need to refresh the value.\n\t\tif revCnt != lp.RevisionCounter {\n\t\t\trevCnt = lp.RevisionCounter\n\n\t\t\t// Go through all layers to find an active value.\n\t\t\tfound := false\n\t\t\tfor _, layer := range lp.layers {\n\t\t\t\tlayerValue, ok := layer.configPerspective.GetAsString(configKey)\n\t\t\t\tif ok {\n\t\t\t\t\tfound = true\n\t\t\t\t\tvalue = layerValue\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !found {\n\t\t\t\tvalue = globalConfig()\n\t\t\t}\n\t\t}\n\n\t\treturn value\n\t}\n}\n"
  },
  {
    "path": "service/profile/profile.go",
    "content": "package profile\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/intel/filterlists\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\n// ProfileSource is the source of the profile.\ntype ProfileSource string //nolint:golint\n\n// Profile Sources.\nconst (\n\tSourceLocal   ProfileSource = \"local\"   // local, editable\n\tSourceSpecial ProfileSource = \"special\" // specials (read-only)\n)\n\n// Default Action IDs.\nconst (\n\tDefaultActionNotSet uint8 = 0\n\tDefaultActionBlock  uint8 = 1\n\tDefaultActionAsk    uint8 = 2\n\tDefaultActionPermit uint8 = 3\n)\n\n// Profile is used to predefine a security profile for applications.\ntype Profile struct { //nolint:maligned // not worth the effort\n\trecord.Base\n\tsync.RWMutex\n\n\t// ID is a unique identifier for the profile.\n\tID string // constant\n\t// Source describes the source of the profile.\n\tSource ProfileSource // constant\n\t// Name is a human readable name of the profile. It\n\t// defaults to the basename of the application.\n\tName string\n\t// Description may hold an optional description of the\n\t// profile or the purpose of the application.\n\tDescription string\n\t// Warning may hold an optional warning about this application.\n\t// It may be static or be added later on when the Portmaster detected an\n\t// issue with the application.\n\tWarning string\n\t// WarningLastUpdated holds the timestamp when the Warning field was last\n\t// updated.\n\tWarningLastUpdated time.Time\n\t// Homepage may refer to the website of the application\n\t// vendor.\n\tHomepage string\n\n\t// Deprecated: Icon holds the icon of the application. The value\n\t// may either be a filepath, a database key or a blob URL.\n\t// See IconType for more information.\n\tIcon string\n\t// Deprecated: IconType describes the type of the Icon property.\n\tIconType binmeta.IconType\n\t// Icons holds a list of icons to represent the application.\n\tIcons []binmeta.Icon\n\n\t// Deprecated: LinkedPath used to point to the executables this\n\t// profile was created for.\n\t// Until removed, it will be added to the Fingerprints as an exact path match.\n\tLinkedPath string // constant\n\t// PresentationPath holds the path of an executable that should be used for\n\t// get representative information from, like the name of the program or the icon.\n\t// Is automatically removed when the path does not exist.\n\t// Is automatically populated with the next match when empty.\n\tPresentationPath string\n\t// UsePresentationPath can be used to enable/disable fetching information\n\t// from the executable at PresentationPath. In some cases, this is not\n\t// desirable.\n\tUsePresentationPath bool\n\t// Fingerprints holds process matching information.\n\tFingerprints []Fingerprint\n\t// Config holds profile specific setttings. It's a nested\n\t// object with keys defining the settings database path. All keys\n\t// until the actual settings value (which is everything that is not\n\t// an object) need to be concatenated for the settings database\n\t// path.\n\tConfig map[string]interface{}\n\n\t// LastEdited holds the UTC timestamp in seconds when the profile was last\n\t// edited by the user. This is not set automatically, but has to be manually\n\t// set by the user interface.\n\tLastEdited int64\n\t// Created holds the UTC timestamp in seconds when the\n\t// profile has been created.\n\tCreated int64\n\n\t// Internal is set to true if the profile is attributed to a\n\t// Portmaster internal process. Internal is set during profile\n\t// creation and may be accessed without lock.\n\tInternal bool\n\n\t// layeredProfile is a link to the layered profile with this profile as the\n\t// main profile.\n\t// All processes with the same binary should share the same instance of the\n\t// local profile and the associated layered profile.\n\tlayeredProfile *LayeredProfile\n\n\t// Interpreted Data\n\tconfigPerspective   *config.Perspective\n\tdataParsed          bool\n\tdefaultAction       uint8\n\tendpoints           endpoints.Endpoints\n\tserviceEndpoints    endpoints.Endpoints\n\tfilterListsSet      bool\n\tfilterListIDs       []string\n\tspnUsagePolicy      endpoints.Endpoints\n\tspnTransitHubPolicy endpoints.Endpoints\n\tspnExitHubPolicy    endpoints.Endpoints\n\n\t// Lifecycle Management\n\toutdated   *abool.AtomicBool\n\tlastActive *int64\n\n\t// savedInternally is set to true for profiles that are saved internally.\n\tsavedInternally bool\n}\n\nfunc (profile *Profile) prepProfile() {\n\t// prepare configuration\n\tprofile.outdated = abool.New()\n\tprofile.lastActive = new(int64)\n\n\t// Migration of LinkedPath to PresentationPath\n\tif profile.PresentationPath == \"\" && profile.LinkedPath != \"\" {\n\t\tprofile.PresentationPath = profile.LinkedPath\n\t}\n}\n\nfunc (profile *Profile) parseConfig() error {\n\t// Check if already parsed.\n\tif profile.dataParsed {\n\t\treturn nil\n\t}\n\n\t// Create new perspective and marked as parsed.\n\tvar err error\n\tprofile.configPerspective, err = config.NewPerspective(profile.Config)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config perspective: %w\", err)\n\t}\n\tprofile.dataParsed = true\n\n\tvar lastErr error\n\taction, ok := profile.configPerspective.GetAsString(CfgOptionDefaultActionKey)\n\tprofile.defaultAction = DefaultActionNotSet\n\tif ok {\n\t\tswitch action {\n\t\tcase DefaultActionPermitValue:\n\t\t\tprofile.defaultAction = DefaultActionPermit\n\t\tcase DefaultActionAskValue:\n\t\t\tprofile.defaultAction = DefaultActionAsk\n\t\tcase DefaultActionBlockValue:\n\t\t\tprofile.defaultAction = DefaultActionBlock\n\t\tdefault:\n\t\t\tlastErr = fmt.Errorf(`default action \"%s\" invalid`, action)\n\t\t}\n\t}\n\n\tlist, ok := profile.configPerspective.GetAsStringArray(CfgOptionEndpointsKey)\n\tprofile.endpoints = nil\n\tif ok {\n\t\tprofile.endpoints, err = endpoints.ParseEndpoints(list)\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t}\n\n\tlist, ok = profile.configPerspective.GetAsStringArray(CfgOptionServiceEndpointsKey)\n\tprofile.serviceEndpoints = nil\n\tif ok {\n\t\tprofile.serviceEndpoints, err = endpoints.ParseEndpoints(list)\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t}\n\n\tlist, ok = profile.configPerspective.GetAsStringArray(CfgOptionFilterListsKey)\n\tprofile.filterListsSet = false\n\tif ok {\n\t\tprofile.filterListIDs, err = filterlists.ResolveListIDs(list)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"profiles: failed to resolve filter list IDs: %s\", err)\n\t\t} else {\n\t\t\tprofile.filterListsSet = true\n\t\t}\n\t}\n\n\tlist, ok = profile.configPerspective.GetAsStringArray(CfgOptionSPNUsagePolicyKey)\n\tprofile.spnUsagePolicy = nil\n\tif ok {\n\t\tprofile.spnUsagePolicy, err = endpoints.ParseEndpoints(list)\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t}\n\n\tlist, ok = profile.configPerspective.GetAsStringArray(CfgOptionTransitHubPolicyKey)\n\tprofile.spnTransitHubPolicy = nil\n\tif ok {\n\t\tprofile.spnTransitHubPolicy, err = endpoints.ParseEndpoints(list)\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t}\n\n\tlist, ok = profile.configPerspective.GetAsStringArray(CfgOptionExitHubPolicyKey)\n\tprofile.spnExitHubPolicy = nil\n\tif ok {\n\t\tprofile.spnExitHubPolicy, err = endpoints.ParseEndpoints(list)\n\t\tif err != nil {\n\t\t\tlastErr = err\n\t\t}\n\t}\n\n\treturn lastErr\n}\n\n// New returns a new Profile.\n// Optionally, you may supply custom configuration in the flat (key=value) form.\nfunc New(profile *Profile) *Profile {\n\t// Create profile if none is given.\n\tif profile == nil {\n\t\tprofile = &Profile{}\n\t}\n\n\t// Set default and internal values.\n\tprofile.Created = time.Now().Unix()\n\tprofile.savedInternally = true\n\n\t// Expand any given configuration.\n\tif profile.Config != nil {\n\t\tprofile.Config = config.Expand(profile.Config)\n\t} else {\n\t\tprofile.Config = make(map[string]interface{})\n\t}\n\n\t// Generate ID if none is given.\n\tif profile.ID == \"\" {\n\t\tif len(profile.Fingerprints) > 0 {\n\t\t\t// Derive from fingerprints.\n\t\t\tprofile.ID = DeriveProfileID(profile.Fingerprints)\n\t\t} else {\n\t\t\t// Generate random ID as fallback.\n\t\t\tlog.Warningf(\"profile: creating new profile without fingerprints to derive ID from\")\n\t\t\tprofile.ID = utils.RandomUUID(\"\").String()\n\t\t}\n\t}\n\n\t// Make key from ID and source.\n\tprofile.makeKey()\n\n\t// Prepare and parse initial profile config.\n\tprofile.prepProfile()\n\tif err := profile.parseConfig(); err != nil {\n\t\tlog.Errorf(\"profile: failed to parse new profile: %s\", err)\n\t}\n\n\treturn profile\n}\n\n// ScopedID returns the scoped ID (Source + ID) of the profile.\nfunc (profile *Profile) ScopedID() string {\n\treturn MakeScopedID(profile.Source, profile.ID)\n}\n\n// makeKey derives and sets the record Key from the profile attributes.\nfunc (profile *Profile) makeKey() {\n\tprofile.SetKey(MakeProfileKey(profile.Source, profile.ID))\n}\n\n// Save saves the profile to the database.\nfunc (profile *Profile) Save() error {\n\tif profile.ID == \"\" {\n\t\treturn errors.New(\"profile: tried to save profile without ID\")\n\t}\n\tif profile.Source == \"\" {\n\t\treturn fmt.Errorf(\"profile: profile %s does not specify a source\", profile.ID)\n\t}\n\n\treturn profileDB.Put(profile)\n}\n\n// delete deletes the profile from the database.\nfunc (profile *Profile) delete() error {\n\t// Check if a key is set.\n\tif !profile.KeyIsSet() {\n\t\treturn errors.New(\"key is not set\")\n\t}\n\n\t// Delete from database.\n\tprofile.Meta().Delete()\n\terr := profileDB.Put(profile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Post handling is done by the profile update feed.\n\treturn nil\n}\n\n// MarkStillActive marks the profile as still active.\nfunc (profile *Profile) MarkStillActive() {\n\tatomic.StoreInt64(profile.lastActive, time.Now().Unix())\n}\n\n// LastActive returns the unix timestamp when the profile was last marked as\n// still active.\nfunc (profile *Profile) LastActive() int64 {\n\treturn atomic.LoadInt64(profile.lastActive)\n}\n\n// String returns a string representation of the Profile.\nfunc (profile *Profile) String() string {\n\treturn fmt.Sprintf(\"<%s %s/%s>\", profile.Name, profile.Source, profile.ID)\n}\n\n// IsOutdated returns whether the this instance of the profile is marked as outdated.\nfunc (profile *Profile) IsOutdated() bool {\n\treturn profile.outdated.IsSet()\n}\n\n// GetEndpoints returns the endpoint list of the profile. This functions\n// requires the profile to be read locked.\nfunc (profile *Profile) GetEndpoints() endpoints.Endpoints {\n\treturn profile.endpoints\n}\n\n// GetServiceEndpoints returns the service endpoint list of the profile. This\n// functions requires the profile to be read locked.\nfunc (profile *Profile) GetServiceEndpoints() endpoints.Endpoints {\n\treturn profile.serviceEndpoints\n}\n\n// AddEndpoint adds an endpoint to the endpoint list, saves the profile and reloads the configuration.\nfunc (profile *Profile) AddEndpoint(newEntry string) {\n\tprofile.addEndpointEntry(CfgOptionEndpointsKey, newEntry)\n}\n\n// AddServiceEndpoint adds a service endpoint to the endpoint list, saves the profile and reloads the configuration.\nfunc (profile *Profile) AddServiceEndpoint(newEntry string) {\n\tprofile.addEndpointEntry(CfgOptionServiceEndpointsKey, newEntry)\n}\n\nfunc (profile *Profile) addEndpointEntry(cfgKey, newEntry string) {\n\tchanged := false\n\n\t// When finished, save the profile.\n\tdefer func() {\n\t\tif !changed {\n\t\t\treturn\n\t\t}\n\n\t\terr := profile.Save()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"profile: failed to save profile %s after add an endpoint rule: %s\", profile.ScopedID(), err)\n\t\t}\n\t}()\n\n\t// Lock the profile for editing.\n\tprofile.Lock()\n\tdefer profile.Unlock()\n\n\t// Get the endpoint list configuration value and add the new entry.\n\tendpointList, ok := profile.configPerspective.GetAsStringArray(cfgKey)\n\tif ok {\n\t\t// A list already exists, check for duplicates within the same prefix.\n\t\tnewEntryPrefix := strings.Split(newEntry, \" \")[0] + \" \"\n\t\tfor _, entry := range endpointList {\n\t\t\tif !strings.HasPrefix(entry, newEntryPrefix) {\n\t\t\t\t// We found an entry with a different prefix than the new entry.\n\t\t\t\t// Beyond this entry we cannot possibly know if identical entries will\n\t\t\t\t// match, so we will have to add the new entry no matter what the rest\n\t\t\t\t// of the list has.\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif entry == newEntry {\n\t\t\t\t// An identical entry is already in the list, abort.\n\t\t\t\tlog.Debugf(\"profile: ignoring new endpoint rule for %s, as identical is already present: %s\", profile, newEntry)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tendpointList = append([]string{newEntry}, endpointList...)\n\t} else {\n\t\tendpointList = []string{newEntry}\n\t}\n\n\t// Save new value back to profile.\n\tconfig.PutValueIntoHierarchicalConfig(profile.Config, cfgKey, endpointList)\n\tchanged = true\n\n\t// Reload the profile manually in order to parse the newly added entry.\n\tprofile.dataParsed = false\n\terr := profile.parseConfig()\n\tif err != nil {\n\t\tlog.Errorf(\"profile: failed to parse %s config after adding endpoint: %s\", profile, err)\n\t}\n}\n\n// LayeredProfile returns the layered profile associated with this profile.\nfunc (profile *Profile) LayeredProfile() *LayeredProfile {\n\tprofile.Lock()\n\tdefer profile.Unlock()\n\n\treturn profile.layeredProfile\n}\n\n// EnsureProfile ensures that the given record is a *Profile, and returns it.\nfunc EnsureProfile(r record.Record) (*Profile, error) {\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewProfile := &Profile{}\n\t\terr := record.Unwrap(r, newProfile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newProfile, nil\n\t}\n\n\t// or adjust type\n\tnewProfile, ok := r.(*Profile)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *Profile, but %T\", r)\n\t}\n\treturn newProfile, nil\n}\n\n// updateMetadata updates meta data fields on the profile and returns whether\n// the profile was changed.\nfunc (profile *Profile) updateMetadata(binaryPath string) (changed bool) {\n\t// Check if this is a local profile, else warn and return.\n\tif profile.Source != SourceLocal {\n\t\tlog.Warningf(\"tried to update metadata for non-local profile %s\", profile.ScopedID())\n\t\treturn false\n\t}\n\n\t// Set PresentationPath if unset.\n\tif profile.PresentationPath == \"\" && binaryPath != \"\" {\n\t\tprofile.PresentationPath = binaryPath\n\t\tchanged = true\n\t}\n\n\t// Migrate LinkedPath to PresentationPath.\n\t// TODO: Remove in v1.5\n\tif profile.PresentationPath == \"\" && profile.LinkedPath != \"\" {\n\t\tprofile.PresentationPath = profile.LinkedPath\n\t\tchanged = true\n\t}\n\n\t// Set Name if unset.\n\tif profile.Name == \"\" && profile.PresentationPath != \"\" {\n\t\t// Generate a default profile name from path.\n\t\tprofile.Name = binmeta.GenerateBinaryNameFromPath(profile.PresentationPath)\n\t\tchanged = true\n\t}\n\n\t// Migrate to Fingerprints.\n\t// TODO: Remove in v1.5\n\tif len(profile.Fingerprints) == 0 && profile.LinkedPath != \"\" {\n\t\tprofile.Fingerprints = []Fingerprint{\n\t\t\t{\n\t\t\t\tType:      FingerprintTypePathID,\n\t\t\t\tOperation: FingerprintOperationEqualsID,\n\t\t\t\tValue:     profile.LinkedPath,\n\t\t\t},\n\t\t}\n\t\tchanged = true\n\t}\n\n\t// UI Backward Compatibility:\n\t// Fill LinkedPath with PresentationPath\n\t// TODO: Remove in v1.1\n\tif profile.LinkedPath == \"\" && profile.PresentationPath != \"\" {\n\t\tprofile.LinkedPath = profile.PresentationPath\n\t\tchanged = true\n\t}\n\n\treturn changed\n}\n\n// updateMetadataFromSystem updates the profile metadata with data from the\n// operating system and saves it afterwards.\nfunc (profile *Profile) updateMetadataFromSystem(ctx context.Context, md MatchingData) error {\n\tvar changed bool\n\n\t// This function is only valid for local profiles.\n\tif profile.Source != SourceLocal || profile.PresentationPath == \"\" {\n\t\treturn fmt.Errorf(\"tried to update metadata for non-local or non-path profile %s\", profile.ScopedID())\n\t}\n\n\t// Get home from ENV.\n\tvar home string\n\tif env := md.Env(); env != nil {\n\t\thome = env[\"HOME\"]\n\t}\n\n\t// Get binary icon and name.\n\tnewIcon, newName, err := binmeta.GetIconAndName(ctx, profile.PresentationPath, home)\n\tswitch {\n\tcase err == nil:\n\t\t// Continue\n\tcase errors.Is(err, binmeta.ErrIconIgnored):\n\t\tnewIcon = nil\n\t\t// Continue\n\tdefault:\n\t\tlog.Warningf(\"profile: failed to get binary icon/name for %s: %s\", profile.PresentationPath, err)\n\t}\n\n\t// Apply new data to profile.\n\tfunc() {\n\t\t// Lock profile for applying metadata.\n\t\tprofile.Lock()\n\t\tdefer profile.Unlock()\n\n\t\t// Apply new name if it changed.\n\t\tif newName != \"\" && profile.Name != newName {\n\t\t\tprofile.Name = newName\n\t\t\tchanged = true\n\t\t}\n\n\t\t// Apply new icon if found.\n\t\tif newIcon != nil && !profile.iconExists(newIcon) {\n\t\t\tif len(profile.Icons) == 0 {\n\t\t\t\tprofile.Icons = []binmeta.Icon{*newIcon}\n\t\t\t} else {\n\t\t\t\tprofile.Icons = append(profile.Icons, *newIcon)\n\t\t\t\tprofile.Icons = binmeta.SortAndCompactIcons(profile.Icons)\n\t\t\t}\n\t\t\tchanged = true\n\t\t}\n\t}()\n\n\t// If anything changed, save the profile.\n\t// profile.Lock must not be held!\n\tif changed {\n\t\terr := profile.Save()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"profile: failed to save %s after metadata update: %s\", profile.ScopedID(), err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Checks if the given icon already assigned to the profile.\nfunc (profile *Profile) iconExists(newIcon *binmeta.Icon) bool {\n\tfor _, icon := range profile.Icons {\n\t\tif icon.Value == newIcon.Value && icon.Type == newIcon.Type && icon.Source == newIcon.Source {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "service/profile/special.go",
    "content": "package profile\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst (\n\t// UnidentifiedProfileID is the profile ID used for unidentified processes.\n\tUnidentifiedProfileID = \"_unidentified\"\n\t// UnidentifiedProfileName is the name used for unidentified processes.\n\tUnidentifiedProfileName = \"Other Connections\"\n\t// UnidentifiedProfileDescription is the description used for unidentified processes.\n\tUnidentifiedProfileDescription = `Connections that could not be attributed to a specific app.\n\nThe Portmaster attributes connections (only TCP/UDP) to specific apps. When attribution for a connection fails, it ends up here.\n\nConnections from unsupported protocols (like ICMP/\"ping\") are always collected here.\n`\n\n\t// UnsolicitedProfileID is the profile ID used for unsolicited connections.\n\tUnsolicitedProfileID = \"_unsolicited\"\n\t// UnsolicitedProfileName is the name used for unsolicited connections.\n\tUnsolicitedProfileName = \"Network Noise\"\n\t// UnsolicitedProfileDescription is the description used for unsolicited connections.\n\tUnsolicitedProfileDescription = `Common connections coming from your Local Area Network.\n\nLocal Area Networks usually have quite a lot of traffic from applications that are trying to find things on the network. This might be a computer trying to find a printer, or a file sharing application searching for local peers. These network packets will automatically arrive at your device.\n\nThese connections - the \"network noise\" - can be found in this app.`\n\n\t// SystemProfileID is the profile ID used for the system/kernel.\n\tSystemProfileID = \"_system\"\n\t// SystemProfileName is the name used for the system/kernel.\n\tSystemProfileName = \"Operating System\"\n\t// SystemProfileDescription is the description used for the system/kernel.\n\tSystemProfileDescription = \"This is the operation system itself.\"\n\n\t// SystemResolverProfileID is the profile ID used for the system's DNS resolver.\n\tSystemResolverProfileID = \"_system-resolver\"\n\t// SystemResolverProfileName is the name used for the system's DNS resolver.\n\tSystemResolverProfileName = \"System DNS Client\"\n\t// SystemResolverProfileDescription is the description used for the system's DNS resolver.\n\tSystemResolverProfileDescription = `The System DNS Client is a system service that requires special handling.\n\nFor regular network connections, the configured settings will apply as usual.\n\nDNS Requests coming from the System DNS Client, however, could actually be coming from any other application on the system: The System DNS Client resolves domain names on behalf of other applications.\n\nIn order to correctly handle these, DNS Requests (not regular connections), do not take the globally configured Outgoing Rules into account.\n\nAdditionally, the settings for the System DNS Client are specially pre-configured. If you are having issues or want to revert to the default settings, please delete this profile below. It will be automatically recreated with the default settings.\n`\n\n\t// PortmasterProfileID is the profile ID used for the Portmaster Core itself.\n\tPortmasterProfileID = \"_portmaster\"\n\t// PortmasterProfileName is the name used for the Portmaster Core itself.\n\tPortmasterProfileName = \"Portmaster Core Service\"\n\t// PortmasterProfileDescription is the description used for the Portmaster Core itself.\n\tPortmasterProfileDescription = `This is the Portmaster itself, which runs in the background as a system service. App specific settings have no effect.`\n\n\t// PortmasterAppProfileID is the profile ID used for the Portmaster App.\n\tPortmasterAppProfileID = \"_portmaster-app\"\n\t// PortmasterAppProfileName is the name used for the Portmaster App.\n\tPortmasterAppProfileName = \"Portmaster User Interface\"\n\t// PortmasterAppProfileDescription is the description used for the Portmaster App.\n\tPortmasterAppProfileDescription = `This is the Portmaster UI Windows.`\n\n\t// PortmasterNotifierProfileID is the profile ID used for the Portmaster Notifier.\n\tPortmasterNotifierProfileID = \"_portmaster-notifier\"\n\t// PortmasterNotifierProfileName is the name used for the Portmaster Notifier.\n\tPortmasterNotifierProfileName = \"Portmaster Notifier\"\n\t// PortmasterNotifierProfileDescription is the description used for the Portmaster Notifier.\n\tPortmasterNotifierProfileDescription = `This is the Portmaster UI Tray Notifier.`\n)\n\nfunc isSpecialProfileID(id string) bool {\n\tswitch id {\n\tcase UnidentifiedProfileID,\n\t\tUnsolicitedProfileID,\n\t\tSystemProfileID,\n\t\tSystemResolverProfileID,\n\t\tPortmasterProfileID,\n\t\tPortmasterAppProfileID,\n\t\tPortmasterNotifierProfileID:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc updateSpecialProfileMetadata(profile *Profile, binaryPath string) (changed bool) {\n\t// Get new profile name and check if profile is applicable to special handling.\n\tvar newProfileName, newDescription string\n\tswitch profile.ID {\n\tcase UnidentifiedProfileID:\n\t\tnewProfileName = UnidentifiedProfileName\n\t\tnewDescription = UnidentifiedProfileDescription\n\tcase UnsolicitedProfileID:\n\t\tnewProfileName = UnsolicitedProfileName\n\t\tnewDescription = UnsolicitedProfileDescription\n\tcase SystemProfileID:\n\t\tnewProfileName = SystemProfileName\n\t\tnewDescription = SystemProfileDescription\n\tcase SystemResolverProfileID:\n\t\tnewProfileName = SystemResolverProfileName\n\t\tnewDescription = SystemResolverProfileDescription\n\tcase PortmasterProfileID:\n\t\tnewProfileName = PortmasterProfileName\n\t\tnewDescription = PortmasterProfileDescription\n\tcase PortmasterAppProfileID:\n\t\tnewProfileName = PortmasterAppProfileName\n\t\tnewDescription = PortmasterAppProfileDescription\n\tcase PortmasterNotifierProfileID:\n\t\tnewProfileName = PortmasterNotifierProfileName\n\t\tnewDescription = PortmasterNotifierProfileDescription\n\tdefault:\n\t\treturn false\n\t}\n\n\t// Update profile name if needed.\n\tif profile.Name != newProfileName {\n\t\tprofile.Name = newProfileName\n\t\tchanged = true\n\t}\n\n\t// Update description if needed.\n\tif profile.Description != newDescription {\n\t\tprofile.Description = newDescription\n\t\tchanged = true\n\t}\n\n\t// Update PresentationPath to new value.\n\tif profile.PresentationPath != binaryPath {\n\t\tprofile.PresentationPath = binaryPath\n\t\tchanged = true\n\t}\n\n\treturn changed\n}\n\nfunc createSpecialProfile(profileID string, path string) *Profile {\n\tswitch profileID {\n\tcase UnidentifiedProfileID:\n\t\treturn New(&Profile{\n\t\t\tID:               UnidentifiedProfileID,\n\t\t\tSource:           SourceLocal,\n\t\t\tPresentationPath: path,\n\t\t})\n\n\tcase UnsolicitedProfileID:\n\t\treturn New(&Profile{\n\t\t\tID:               UnsolicitedProfileID,\n\t\t\tSource:           SourceLocal,\n\t\t\tPresentationPath: path,\n\t\t})\n\n\tcase SystemProfileID:\n\t\treturn New(&Profile{\n\t\t\tID:               SystemProfileID,\n\t\t\tSource:           SourceLocal,\n\t\t\tPresentationPath: path,\n\t\t})\n\n\tcase SystemResolverProfileID:\n\t\treturn New(&Profile{\n\t\t\tID:               SystemResolverProfileID,\n\t\t\tSource:           SourceLocal,\n\t\t\tPresentationPath: path,\n\t\t\tConfig: map[string]interface{}{\n\t\t\t\t// Explicitly setting the default action to \"permit\" will improve the\n\t\t\t\t// user experience for people who set the global default to \"prompt\".\n\t\t\t\t// Resolved domain from the system resolver are checked again when\n\t\t\t\t// attributed to a connection of a regular process. Otherwise, users\n\t\t\t\t// would see two connection prompts for the same domain.\n\t\t\t\tCfgOptionDefaultActionKey: DefaultActionPermitValue,\n\t\t\t\t// Disable force blockers.\n\t\t\t\tCfgOptionBlockScopeInternetKey: false,\n\t\t\t\tCfgOptionBlockScopeLANKey:      false,\n\t\t\t\tCfgOptionBlockScopeLocalKey:    false,\n\t\t\t\tCfgOptionBlockP2PKey:           false,\n\t\t\t\tCfgOptionBlockInboundKey:       false,\n\t\t\t\t// Explicitly allow localhost and answers to multicast protocols that\n\t\t\t\t// are commonly used by system resolvers.\n\t\t\t\t// TODO: When the Portmaster gains the ability to attribute multicast\n\t\t\t\t// responses to their requests, these rules can probably be removed\n\t\t\t\t// again.\n\t\t\t\tCfgOptionServiceEndpointsKey: []string{\n\t\t\t\t\t\"+ Localhost\",    // Allow everything from localhost.\n\t\t\t\t\t\"+ LAN UDP/5353\", // Allow inbound mDNS requests and multicast replies.\n\t\t\t\t\t\"+ LAN UDP/5355\", // Allow inbound LLMNR requests and multicast replies.\n\t\t\t\t\t\"+ LAN UDP/1900\", // Allow inbound SSDP requests and multicast replies.\n\t\t\t\t\t\"- *\",            // Deny everything else.\n\t\t\t\t},\n\t\t\t\t// Explicitly disable all filter lists, as these will be checked later\n\t\t\t\t// with the attributed connection. As this is the system resolver, this\n\t\t\t\t// list can instead be used as a global enforcement of filter lists, if\n\t\t\t\t// the system resolver is used. Users who want to\n\t\t\t\tCfgOptionFilterListsKey: []string{},\n\t\t\t},\n\t\t})\n\n\tcase PortmasterProfileID:\n\t\treturn New(&Profile{\n\t\t\tID:               PortmasterProfileID,\n\t\t\tSource:           SourceLocal,\n\t\t\tPresentationPath: path,\n\t\t\tConfig: map[string]interface{}{\n\t\t\t\t// In case anything slips through the internal self-allow, be sure to\n\t\t\t\t// allow everything explicitly.\n\t\t\t\t// Blocking connections here can lead to a very literal deadlock.\n\t\t\t\t// This can currently happen, as fast-tracked connections are also\n\t\t\t\t// reset in the OS integration and might show up in the connection\n\t\t\t\t// handling if a packet in the other direction hits the firewall first.\n\t\t\t\tCfgOptionDefaultActionKey:      DefaultActionPermitValue,\n\t\t\t\tCfgOptionBlockScopeInternetKey: false,\n\t\t\t\tCfgOptionBlockScopeLANKey:      false,\n\t\t\t\tCfgOptionBlockScopeLocalKey:    false,\n\t\t\t\tCfgOptionBlockP2PKey:           false,\n\t\t\t\tCfgOptionBlockInboundKey:       false,\n\t\t\t\tCfgOptionEndpointsKey: []string{\n\t\t\t\t\t\"+ *\",\n\t\t\t\t},\n\t\t\t\tCfgOptionServiceEndpointsKey: []string{\n\t\t\t\t\t\"+ Localhost\",\n\t\t\t\t\t\"+ LAN\",\n\t\t\t\t\t\"- *\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tInternal: true,\n\t\t})\n\n\tcase PortmasterAppProfileID:\n\t\treturn New(&Profile{\n\t\t\tID:               PortmasterAppProfileID,\n\t\t\tSource:           SourceLocal,\n\t\t\tPresentationPath: path,\n\t\t\tConfig: map[string]interface{}{\n\t\t\t\t// Block all connections by default for the Portmaster UI profile,\n\t\t\t\t// since the only required connections are to the Portmaster Core,\n\t\t\t\t// which are fast-tracked.\n\t\t\t\t//\n\t\t\t\t// This ensures that any unexpected connections —\n\t\t\t\t// possibly made by the internal WebView implementation —\n\t\t\t\t// are blocked.\n\t\t\t\tCfgOptionDefaultActionKey:      DefaultActionBlockValue,\n\t\t\t\tCfgOptionBlockScopeInternetKey: false, // This is stronger than the rules, and thus must be false in order to access safing.io.\n\t\t\t\tCfgOptionBlockScopeLANKey:      true,\n\t\t\t\tCfgOptionBlockScopeLocalKey:    true,\n\t\t\t\tCfgOptionBlockP2PKey:           true,\n\t\t\t\tCfgOptionBlockInboundKey:       true,\n\t\t\t\tCfgOptionEndpointsKey: []string{\n\t\t\t\t\t\"+ .safing.io\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tInternal: true,\n\t\t})\n\n\tcase PortmasterNotifierProfileID:\n\t\treturn New(&Profile{\n\t\t\tID:               PortmasterNotifierProfileID,\n\t\t\tSource:           SourceLocal,\n\t\t\tPresentationPath: path,\n\t\t\tConfig: map[string]interface{}{\n\t\t\t\tCfgOptionDefaultActionKey:      DefaultActionBlockValue,\n\t\t\t\tCfgOptionBlockScopeInternetKey: false,\n\t\t\t\tCfgOptionBlockScopeLANKey:      false,\n\t\t\t\tCfgOptionBlockScopeLocalKey:    false,\n\t\t\t\tCfgOptionBlockP2PKey:           false,\n\t\t\t\tCfgOptionBlockInboundKey:       true,\n\t\t\t\tCfgOptionEndpointsKey: []string{\n\t\t\t\t\t\"+ Localhost\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tInternal: true,\n\t\t})\n\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// specialProfileNeedsReset is used as a workaround until we can properly use\n// profile layering in a way that it is also correctly handled by the UI. We\n// check if the special profile has not been changed by the user and if not,\n// check if the profile is outdated and can be upgraded.\nfunc specialProfileNeedsReset(profile *Profile) bool {\n\tif profile == nil {\n\t\treturn false\n\t}\n\n\tswitch {\n\tcase profile.Source != SourceLocal:\n\t\t// Special profiles live in the local scope only.\n\t\treturn false\n\tcase profile.LastEdited > 0:\n\t\t// Profile was edited - don't override user settings.\n\t\treturn false\n\t}\n\n\tswitch profile.ID {\n\tcase SystemResolverProfileID:\n\t\treturn canBeUpgraded(profile, \"22.8.2023\")\n\tcase PortmasterProfileID:\n\t\treturn canBeUpgraded(profile, \"22.8.2023\")\n\tcase PortmasterAppProfileID:\n\t\treturn canBeUpgraded(profile, \"22.8.2023\")\n\tdefault:\n\t\t// Not a special profile or no upgrade available yet.\n\t\treturn false\n\t}\n}\n\nfunc canBeUpgraded(profile *Profile, upgradeDate string) bool {\n\t// Parse upgrade date.\n\tupgradeTime, err := time.Parse(\"2.1.2006\", upgradeDate)\n\tif err != nil {\n\t\tlog.Warningf(\"profile: failed to parse date %q: %s\", upgradeDate, err)\n\t\treturn false\n\t}\n\n\t// Check if the upgrade is applicable.\n\tif profile.Created < upgradeTime.Unix() {\n\t\tlog.Infof(\"profile: upgrading special profile %s\", profile.ScopedID())\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "service/resolver/api.go",
    "content": "package resolver\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nfunc registerAPI() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"dns/clear\",\n\t\tWrite:       api.PermitUser,\n\t\tActionFunc:  clearNameCacheHandler,\n\t\tName:        \"Clear cached DNS records\",\n\t\tDescription: \"Deletes all saved DNS records from the database.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"dns/resolvers\",\n\t\tRead:        api.PermitAnyone,\n\t\tStructFunc:  exportDNSResolvers,\n\t\tName:        \"List DNS Resolvers\",\n\t\tDescription: \"List currently configured DNS resolvers and their status.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath: `dns/cache/{query:[a-z0-9\\.-]{0,512}\\.[A-Z]{1,32}}`,\n\t\tRead: api.PermitUser,\n\t\tRecordFunc: func(r *api.Request) (record.Record, error) {\n\t\t\treturn recordDatabase.Get(nameRecordsKeyPrefix + r.URLVars[\"query\"])\n\t\t},\n\t\tName:        \"Get DNS Record from Cache\",\n\t\tDescription: \"Returns cached dns records from the internal cache.\",\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"query (in path)\",\n\t\t\tValue:       \"fqdn and query type\",\n\t\t\tDescription: \"Specify the query like this: `example.com.A`.\",\n\t\t}},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\ntype resolverExport struct {\n\t*Resolver\n\tFailing bool\n}\n\nfunc exportDNSResolvers(*api.Request) (interface{}, error) {\n\tresolversLock.RLock()\n\tdefer resolversLock.RUnlock()\n\n\texport := make([]resolverExport, 0, len(globalResolvers))\n\tfor _, r := range globalResolvers {\n\t\texport = append(export, resolverExport{\n\t\t\tResolver: r,\n\t\t\tFailing:  r.Conn.IsFailing(),\n\t\t})\n\t}\n\n\treturn export, nil\n}\n"
  },
  {
    "path": "service/resolver/block-detection.go",
    "content": "package resolver\n\nimport (\n\t\"net\"\n\n\t\"github.com/miekg/dns\"\n)\n\n// Supported upstream block detections.\nconst (\n\tBlockDetectionRefused     = \"refused\"\n\tBlockDetectionZeroIP      = \"zeroip\"\n\tBlockDetectionEmptyAnswer = \"empty\"\n\tBlockDetectionDisabled    = \"disabled\"\n)\n\nfunc isBlockedUpstream(resolver *Resolver, answer *dns.Msg) bool {\n\tif resolver.UpstreamBlockDetection == BlockDetectionDisabled {\n\t\treturn false\n\t}\n\n\tswitch resolver.UpstreamBlockDetection {\n\tcase BlockDetectionRefused:\n\t\treturn answer.Rcode == dns.RcodeRefused\n\tcase BlockDetectionZeroIP:\n\t\tif answer.Rcode != dns.RcodeSuccess {\n\t\t\treturn false\n\t\t}\n\t\tvar ips []net.IP\n\t\tfor _, rr := range answer.Answer {\n\t\t\tswitch v := rr.(type) {\n\t\t\tcase *dns.A:\n\t\t\t\tips = append(ips, v.A)\n\t\t\tcase *dns.AAAA:\n\t\t\t\tips = append(ips, v.AAAA)\n\t\t\t}\n\t\t}\n\n\t\tif len(ips) == 0 {\n\t\t\treturn false // we expected an empty IP\n\t\t}\n\n\t\tfor _, ip := range ips {\n\t\t\tif ip.To4() != nil {\n\t\t\t\tif !ip.Equal(net.IPv4zero) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif !ip.To16().Equal(net.IPv6zero) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true\n\tcase BlockDetectionEmptyAnswer:\n\t\treturn answer.Rcode == dns.RcodeNameError && len(answer.Ns) == 0 && len(answer.Answer) == 0 && len(answer.Extra) == 0\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "service/resolver/compat.go",
    "content": "package resolver\n\nimport \"net\"\n\n// This is a workaround for enabling the resolver to work with the compat\n// module without importing it. Long-term, the network module should not import\n// the resolver package, as this breaks the SPN hub.\nvar (\n\tCompatDNSCheckInternalDomainScope string\n\tCompatSelfCheckIsFailing          func() bool\n\tCompatSubmitDNSCheckDomain        func(subdomain string) (respondWith net.IP)\n)\n"
  },
  {
    "path": "service/resolver/config.go",
    "content": "package resolver\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/status\"\n)\n\n// Configuration Keys.\nvar (\n\tdefaultNameServers = []string{\n\t\t// Collection of default DNS Servers\n\n\t\t// For a detailed explanation how we choose our default resolvers, check out\n\t\t// https://safing.io/blog/2020/07/07/how-safing-selects-its-default-dns-providers/\n\n\t\t// These resolvers define a working set. Which provider we selected as the\n\t\t// primary depends on the current situation.\n\n\t\t// We encourage everyone who has the technical abilities to set their own preferred servers.\n\t\t// For a list of configuration options, see\n\t\t// https://github.com/safing/portmaster/service/wiki/DNS-Server-Settings\n\n\t\t// Quad9 (encrypted DNS)\n\t\t// \"dot://dns.quad9.net?ip=9.9.9.9&name=Quad9&blockedif=empty\",\n\t\t// \"dot://dns.quad9.net?ip=149.112.112.112&name=Quad9&blockedif=empty\",\n\n\t\t// Cloudflare (encrypted DNS, with malware protection)\n\t\t\"dot://cloudflare-dns.com?ip=1.1.1.2&name=Cloudflare&blockedif=zeroip\",\n\t\t\"dot://cloudflare-dns.com?ip=1.0.0.2&name=Cloudflare&blockedif=zeroip\",\n\n\t\t// AdGuard (encrypted DNS, default flavor)\n\t\t// \"dot://dns.adguard.com?ip=94.140.14.14&name=AdGuard&blockedif=zeroip\",\n\t\t// \"dot://dns.adguard.com?ip=94.140.15.15&name=AdGuard&blockedif=zeroip\",\n\n\t\t// Foundation for Applied Privacy (encrypted DNS)\n\t\t// \"dot://dot1.applied-privacy.net?ip=146.255.56.98&name=AppliedPrivacy\",\n\n\t\t// Quad9 (plain DNS)\n\t\t// `dns://9.9.9.9:53?name=Quad9&blockedif=empty`,\n\t\t// `dns://149.112.112.112:53?name=Quad9&blockedif=empty`,\n\n\t\t// Cloudflare (plain DNS, with malware protection)\n\t\t// `dns://1.1.1.2:53?name=Cloudflare&blockedif=zeroip`,\n\t\t// `dns://1.0.0.2:53?name=Cloudflare&blockedif=zeroip`,\n\n\t\t// AdGuard (plain DNS, default flavor)\n\t\t// `dns://94.140.14.14&name=AdGuard&blockedif=zeroip`,\n\t\t// `dns://94.140.15.15&name=AdGuard&blockedif=zeroip`,\n\t}\n\n\tCfgOptionNameServersKey   = \"dns/nameservers\"\n\tconfiguredNameServers     config.StringArrayOption\n\tcfgOptionNameServersOrder = 0\n\n\tCfgOptionNoAssignedNameserversKey   = \"dns/noAssignedNameservers\"\n\tnoAssignedNameservers               config.BoolOption\n\tcfgOptionNoAssignedNameserversOrder = 1\n\n\tCfgOptionUseStaleCacheKey   = \"dns/useStaleCache\"\n\tuseStaleCacheConfigOption   *config.Option\n\tuseStaleCache               config.BoolOption\n\tcfgOptionUseStaleCacheOrder = 2\n\n\tCfgOptionNoMulticastDNSKey   = \"dns/noMulticastDNS\"\n\tnoMulticastDNS               config.BoolOption\n\tcfgOptionNoMulticastDNSOrder = 3\n\n\tCfgOptionNoInsecureProtocolsKey   = \"dns/noInsecureProtocols\"\n\tnoInsecureProtocols               config.BoolOption\n\tcfgOptionNoInsecureProtocolsOrder = 4\n\n\tCfgOptionDontResolveSpecialDomainsKey   = \"dns/dontResolveSpecialDomains\"\n\tdontResolveSpecialDomains               config.BoolOption\n\tcfgOptionDontResolveSpecialDomainsOrder = 16\n\n\tCfgOptionNameserverRetryRateKey   = \"dns/nameserverRetryRate\"\n\tnameserverRetryRate               config.IntOption\n\tcfgOptionNameserverRetryRateOrder = 32\n)\n\nfunc prepConfig() error {\n\terr := config.Register(&config.Option{\n\t\tName:        \"DNS Servers\",\n\t\tKey:         CfgOptionNameServersKey,\n\t\tDescription: \"DNS servers to use for resolving DNS requests.\",\n\t\tHelp: strings.ReplaceAll(`DNS servers are used in the order as entered. The first one will be used as the primary DNS Server. Only if it fails, will the other servers be used as a fallback - in their respective order. If all fail, or if no DNS Server is configured here, the Portmaster will use the one configured in your system or network.\n\nAdditionally, if it is more likely that the DNS server of your system or network has a (better) answer to a request, they will be asked first. This will be the case for special local domains and domain spaces announced on the current network.\n\nDNS servers are configured in a URL format. This allows you to specify special settings for a resolver. If you just want to use a resolver at IP 10.2.3.4, please enter: \"dns://10.2.3.4\"  \nThe format is: \"protocol://host:port?parameter=value&parameter=value\"  \n\nFor DoH servers, you can also just paste the URL given by the DNS provider.  \nWhen referring to the DNS server using a domain name, as with DoH, it is highly recommended to also specify the IP address using the \"ip\" parameter, so Portmaster does not have to resolve it.\n\n- Protocol\n\t- \"dot\": DNS-over-TLS (or \"tls\"; recommended)  \n\t- \"doh\": DNS-over-HTTPS (or \"https\")\n\t- \"dns\": plain old DNS  \n\t- \"tcp\": plain old DNS over TCP\n- Host: specify the domain or IP of the resolver\n- Port: optionally define a custom port\n- Parameters:\n\t- \"name\": give your DNS Server a name that is used for messages and logs\n\t- \"verify\": domain name to verify for \"dot\", only valid for \"dot\" and \"doh\"\n\t- \"ip\": IP address (if using a domain), so Portmaster does not need to resolve it using the system resolver - this is highly recommended\n\t- \"blockedif\": detect if the name server blocks a query, options:\n\t\t- \"empty\": server replies with NXDomain status, but without any other record in any section\n\t\t- \"refused\": server replies with Refused status\n\t\t- \"zeroip\": server replies with an IP address, but it is zero\n\t- \"search\": specify prioritized domains/TLDs for this resolver (delimited by \",\")\n\t- \"search-only\": use this resolver for domains in the \"search\" parameter only (no value)\n`, `\"`, \"`\"),\n\t\tSensitive:       true,\n\t\tOptType:         config.OptTypeStringArray,\n\t\tExpertiseLevel:  config.ExpertiseLevelUser,\n\t\tReleaseLevel:    config.ReleaseLevelStable,\n\t\tDefaultValue:    defaultNameServers,\n\t\tValidationRegex: fmt.Sprintf(\"^(%s|%s|%s|%s|%s|%s)://.*\", ServerTypeDoT, ServerTypeDoH, ServerTypeDNS, ServerTypeTCP, HTTPSProtocol, TLSProtocol),\n\t\tValidationFunc:  validateNameservers,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayHintAnnotation:  config.DisplayHintOrdered,\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionNameServersOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Servers\",\n\t\t\tconfig.QuickSettingsAnnotation: []config.QuickSetting{\n\t\t\t\t{\n\t\t\t\t\tName:   \"Set Cloudflare (with Malware Filter)\",\n\t\t\t\t\tAction: config.QuickReplace,\n\t\t\t\t\tValue: []string{\n\t\t\t\t\t\t\"dot://cloudflare-dns.com?ip=1.1.1.2&name=Cloudflare&blockedif=zeroip\",\n\t\t\t\t\t\t\"dot://cloudflare-dns.com?ip=1.0.0.2&name=Cloudflare&blockedif=zeroip\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Set Quad9\",\n\t\t\t\t\tAction: config.QuickReplace,\n\t\t\t\t\tValue: []string{\n\t\t\t\t\t\t\"dot://dns.quad9.net?ip=9.9.9.9&name=Quad9&blockedif=empty\",\n\t\t\t\t\t\t\"dot://dns.quad9.net?ip=149.112.112.112&name=Quad9&blockedif=empty\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Set AdGuard\",\n\t\t\t\t\tAction: config.QuickReplace,\n\t\t\t\t\tValue: []string{\n\t\t\t\t\t\t\"dot://dns.adguard.com?ip=94.140.14.14&name=AdGuard&blockedif=zeroip\",\n\t\t\t\t\t\t\"dot://dns.adguard.com?ip=94.140.15.15&name=AdGuard&blockedif=zeroip\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Set Foundation for Applied Privacy\",\n\t\t\t\t\tAction: config.QuickReplace,\n\t\t\t\t\tValue: []string{\n\t\t\t\t\t\t\"dot://dot1.applied-privacy.net?ip=146.255.56.98&name=AppliedPrivacy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:   \"Add Cloudflare (as fallback)\",\n\t\t\t\t\tAction: config.QuickMergeBottom,\n\t\t\t\t\tValue: []string{\n\t\t\t\t\t\t\"dot://cloudflare-dns.com?ip=1.1.1.1&name=Cloudflare&blockedif=zeroip\",\n\t\t\t\t\t\t\"dot://cloudflare-dns.com?ip=1.0.0.1&name=Cloudflare&blockedif=zeroip\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"self:detail:internalSpecialUseDomains\": internalSpecialUseDomains,\n\t\t\t\"self:detail:connectivityDomains\":       netenv.ConnectivityDomains,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tconfiguredNameServers = config.Concurrent.GetAsStringArray(CfgOptionNameServersKey, defaultNameServers)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Retry Failing DNS Servers\",\n\t\tKey:            CfgOptionNameserverRetryRateKey,\n\t\tDescription:    \"Duration in seconds how often failing DNS server should be retried. This is done continuously in the background.\",\n\t\tOptType:        config.OptTypeInt,\n\t\tExpertiseLevel: config.ExpertiseLevelDeveloper,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   300,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionNameserverRetryRateOrder,\n\t\t\tconfig.UnitAnnotation:         \"seconds\",\n\t\t\tconfig.CategoryAnnotation:     \"Servers\",\n\t\t},\n\t\tValidationRegex: `^[1-9][0-9]{1,5}$`,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tnameserverRetryRate = config.Concurrent.GetAsInt(CfgOptionNameserverRetryRateKey, 300)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Ignore System/Network Servers\",\n\t\tKey:            CfgOptionNoAssignedNameserversKey,\n\t\tDescription:    \"Ignore DNS servers configured in your system or network. This may break domains from your local network.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation:   cfgOptionNoAssignedNameserversOrder,\n\t\t\tconfig.DisplayHintAnnotation:    status.DisplayHintSecurityLevel,\n\t\t\tconfig.CategoryAnnotation:       \"Servers\",\n\t\t\t\"self:detail:specialUseDomains\": specialUseDomains,\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tnoAssignedNameservers = config.Concurrent.GetAsBool(CfgOptionNoAssignedNameserversKey, false)\n\n\tuseStaleCacheConfigOption = &config.Option{\n\t\tName:           \"Always Use DNS Cache\",\n\t\tKey:            CfgOptionUseStaleCacheKey,\n\t\tDescription:    \"Always use the DNS cache, even if entries have expired. Expired entries are refreshed afterwards in the background. This can improve DNS resolving performance a lot, but may lead to occasional connection errors due to outdated DNS records.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelUser,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionUseStaleCacheOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Resolving\",\n\t\t},\n\t}\n\terr = config.Register(useStaleCacheConfigOption)\n\tif err != nil {\n\t\treturn err\n\t}\n\tuseStaleCache = config.Concurrent.GetAsBool(CfgOptionUseStaleCacheKey, false)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Ignore Multicast DNS\",\n\t\tKey:            CfgOptionNoMulticastDNSKey,\n\t\tDescription:    \"Do not resolve using Multicast DNS. This may break certain Plug and Play devices and services.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation:  cfgOptionNoMulticastDNSOrder,\n\t\t\tconfig.DisplayHintAnnotation:   status.DisplayHintSecurityLevel,\n\t\t\tconfig.CategoryAnnotation:      \"Resolving\",\n\t\t\t\"self:detail:multicastDomains\": multicastDomains,\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tnoMulticastDNS = config.Concurrent.GetAsBool(CfgOptionNoMulticastDNSKey, false)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Use Secure Protocols Only\",\n\t\tKey:            CfgOptionNoInsecureProtocolsKey,\n\t\tDescription:    \"Never resolve using insecure protocols, ie. plain DNS. This may break certain local DNS services, which always use plain DNS.\",\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionNoInsecureProtocolsOrder,\n\t\t\tconfig.DisplayHintAnnotation:  status.DisplayHintSecurityLevel,\n\t\t\tconfig.CategoryAnnotation:     \"Resolving\",\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tnoInsecureProtocols = config.Concurrent.GetAsBool(CfgOptionNoInsecureProtocolsKey, false)\n\n\terr = config.Register(&config.Option{\n\t\tName: \"Block Unofficial TLDs\",\n\t\tKey:  CfgOptionDontResolveSpecialDomainsKey,\n\t\tDescription: fmt.Sprintf(\n\t\t\t\"Block %s. Unofficial domains may pose a security risk. This setting does not affect .onion domains in the Tor Browser.\",\n\t\t\tformatScopeList(specialServiceDomains),\n\t\t),\n\t\tOptType:        config.OptTypeBool,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tReleaseLevel:   config.ReleaseLevelStable,\n\t\tDefaultValue:   true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation:       cfgOptionDontResolveSpecialDomainsOrder,\n\t\t\tconfig.DisplayHintAnnotation:        status.DisplayHintSecurityLevel,\n\t\t\tconfig.CategoryAnnotation:           \"Resolving\",\n\t\t\t\"self:detail:specialServiceDomains\": specialServiceDomains,\n\t\t},\n\t\tMigrations: []config.MigrationFunc{status.MigrateSecurityLevelToBoolean},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdontResolveSpecialDomains = config.Concurrent.GetAsBool(CfgOptionDontResolveSpecialDomainsKey, false)\n\n\treturn nil\n}\n\nfunc validateNameservers(value interface{}) error {\n\tlist, ok := value.([]string)\n\tif !ok {\n\t\treturn errors.New(\"invalid type\")\n\t}\n\n\tfor i, entry := range list {\n\t\t_, _, err := createResolver(entry, ServerSourceConfigured)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse DNS server \\\"%s\\\" (#%d): %w\", entry, i+1, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc formatScopeList(list []string) string {\n\tformatted := make([]string, 0, len(list))\n\tfor _, domain := range list {\n\t\tformatted = append(formatted, strings.TrimRight(domain, \".\"))\n\t}\n\treturn strings.Join(formatted, \", \")\n}\n"
  },
  {
    "path": "service/resolver/doc.go",
    "content": "/*\nPackage resolver is responsible for querying DNS.\n\n# DNS Servers\n\nInternal lists of resolvers to use are built on start and rebuilt on every config or network change.\nConfigured DNS servers are prioritized over servers assigned by dhcp. Domain and search options (here referred to as \"search scopes\") are being considered.\n\n# Security\n\nUsage of DNS Servers can be regulated using the configuration:\n\n\tDoNotUseAssignedDNS        // Do not use DNS servers assigned by DHCP\n\tDoNotUseMDNS               // Do not use mDNS\n\tDoNotForwardSpecialDomains // Do not forward special domains to local resolvers, except if they have a search scope for it\n\nNote: The DHCP options \"domain\" and \"search\" are ignored for servers assigned by DHCP that do not reside within local address space.\n\n# Resolving DNS\n\nVarious different queries require the resolver to behave in different manner:\n\nQueries for \"localhost.\" are immediately responded with 127.0.0.1 and ::1, for A and AAAA queries and NXDomain for others.\nReverse lookups on local address ranges (10/8, 172.16/12, 192.168/16, fe80::/7) will be tried against every local resolver and finally mDNS until a successful, non-NXDomain answer is received.\nSpecial domains (\"example.\", \"example.com.\", \"example.net.\", \"example.org.\", \"invalid.\", \"test.\", \"onion.\") are resolved using search scopes and local resolvers.\nAll other domains are resolved using search scopes and all available resolvers.\n*/\npackage resolver\n"
  },
  {
    "path": "service/resolver/failing.go",
    "content": "package resolver\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\nvar (\n\t// FailThreshold is amount of errors a resolvers must experience in order to be regarded as failed.\n\tFailThreshold = 5\n\n\t// FailObserveDuration is the duration in which failures are counted in order to mark a resolver as failed.\n\tFailObserveDuration = time.Duration(FailThreshold) * 10 * time.Second\n)\n\n// IsFailing returns if this resolver is currently failing.\nfunc (brc *BasicResolverConn) IsFailing() bool {\n\treturn brc.failing.IsSet()\n}\n\n// ReportFailure reports that an error occurred with this resolver.\nfunc (brc *BasicResolverConn) ReportFailure() {\n\t// Don't mark resolver as failed if we are offline.\n\tif !netenv.Online() {\n\t\treturn\n\t}\n\n\t// Ingore report when we are already failing.\n\tif brc.IsFailing() {\n\t\treturn\n\t}\n\n\tbrc.failLock.Lock()\n\tdefer brc.failLock.Unlock()\n\n\t// Check if we are within the observation period.\n\tif time.Since(brc.failingStarted) > FailObserveDuration {\n\t\tbrc.fails = 1\n\t\tbrc.failingStarted = time.Now()\n\t\treturn\n\t}\n\n\t// Increase and check if we need to set to failing.\n\tbrc.fails++\n\tif brc.fails > FailThreshold {\n\t\tbrc.failing.Set()\n\t}\n\n\t// Report to netenv that a configured server failed.\n\tif brc.resolver.Info.Source == ServerSourceConfigured {\n\t\tnetenv.ConnectedToDNS.UnSet()\n\t}\n}\n\n// ResetFailure resets the failure status.\nfunc (brc *BasicResolverConn) ResetFailure() {\n\tif brc.failing.SetToIf(true, false) {\n\t\tbrc.failLock.Lock()\n\t\tdefer brc.failLock.Unlock()\n\t\tbrc.fails = 0\n\t\tbrc.failingStarted = time.Time{}\n\t}\n\n\t// Report to netenv that a configured server succeeded.\n\tif brc.resolver.Info.Source == ServerSourceConfigured {\n\t\tnetenv.ConnectedToDNS.Set()\n\t}\n}\n\nfunc checkFailingResolvers(wc *mgr.WorkerCtx) error {\n\tvar resolvers []*Resolver\n\n\t// Set next execution time.\n\tmodule.failingResolverWorkerMgr.Delay(time.Duration(nameserverRetryRate()) * time.Second)\n\n\t// Make a copy of the resolver list.\n\tfunc() {\n\t\tresolversLock.Lock()\n\t\tdefer resolversLock.Unlock()\n\n\t\tresolvers = make([]*Resolver, len(globalResolvers))\n\t\tcopy(resolvers, globalResolvers)\n\t}()\n\n\t// Start logging.\n\tctx, tracer := log.AddTracer(wc.Ctx())\n\ttracer.Debugf(\"resolver: checking failed resolvers\")\n\tdefer tracer.Submit()\n\n\t// Go through all resolvers and check if they are reachable again.\n\tfor i, resolver := range resolvers {\n\t\t// Skip resolver that are not failing.\n\t\tif !resolver.Conn.IsFailing() {\n\t\t\tcontinue\n\t\t}\n\n\t\ttracer.Tracef(\"resolver: testing failed resolver [%d/%d] %s\", i+1, len(resolvers), resolver)\n\n\t\t// Test if we can resolve via this resolver.\n\t\tips, _, err := testConnectivity(ctx, netenv.DNSTestDomain, resolver)\n\t\tswitch {\n\t\tcase err != nil:\n\t\t\ttracer.Debugf(\"resolver: failed resolver %s is still failing: %s\", resolver, err)\n\t\tcase len(ips) == 0 || !ips[0].Equal(netenv.DNSTestExpectedIP):\n\t\t\ttracer.Debugf(\"resolver: failed resolver %s received unexpected A records: %s\", resolver, ips)\n\t\tdefault:\n\t\t\t// Resolver test successful.\n\t\t\ttracer.Infof(\"resolver: check successful, resolver %s is available again\", resolver)\n\t\t\tresolver.Conn.ResetFailure()\n\t\t}\n\n\t\t// Check if context was canceled.\n\t\tif ctx.Err() != nil {\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/resolver/ipinfo.go",
    "content": "package resolver\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nconst (\n\t// IPInfoProfileScopeGlobal is the profile scope used for unscoped IPInfo entries.\n\tIPInfoProfileScopeGlobal = \"global\"\n)\n\nvar ipInfoDatabase = database.NewInterface(&database.Options{\n\tLocal:    true,\n\tInternal: true,\n\n\t// Cache entries because new/updated entries will often be queries soon\n\t// after inserted.\n\tCacheSize: 256,\n\n\t// We only use the cache database here, so we can delay and batch all our\n\t// writes. Also, no one else accesses these records, so we are fine using\n\t// this.\n\tDelayCachedWrites: \"cache\",\n})\n\n// ResolvedDomain holds a Domain name and a list of\n// CNAMES that have been resolved.\ntype ResolvedDomain struct {\n\t// Domain is the domain as requested by the application.\n\tDomain string\n\n\t// CNAMEs is a list of CNAMEs that have been resolved for\n\t// Domain.\n\tCNAMEs []string\n\n\t// Resolver holds basic information about the resolver that provided this\n\t// information.\n\tResolver *ResolverInfo\n\n\t// DNSRequestContext holds the DNS request context.\n\tDNSRequestContext *DNSRequestContext\n\n\t// Expires holds the timestamp when this entry expires.\n\t// This does not mean that the entry may not be used anymore afterwards,\n\t// but that this is used to calcuate the TTL of the database record.\n\tExpires int64\n}\n\n// AddCNAMEs adds all cnames from the map related to its set Domain.\nfunc (resolved *ResolvedDomain) AddCNAMEs(cnames map[string]string) {\n\t// Resolve all CNAMEs in the correct order and add the to the record - up to max 50 layers.\n\tdomain := resolved.Domain\ndomainLoop:\n\tfor range 50 {\n\t\tnextDomain, isCNAME := cnames[domain]\n\t\tswitch {\n\t\tcase !isCNAME:\n\t\t\tbreak domainLoop\n\t\tcase nextDomain == resolved.Domain:\n\t\t\tbreak domainLoop\n\t\tcase nextDomain == domain:\n\t\t\tbreak domainLoop\n\t\t}\n\n\t\tresolved.CNAMEs = append(resolved.CNAMEs, nextDomain)\n\t\tdomain = nextDomain\n\t}\n}\n\n// String returns a string representation of ResolvedDomain including\n// the CNAME chain. It implements fmt.Stringer.\nfunc (resolved *ResolvedDomain) String() string {\n\tret := resolved.Domain\n\tcnames := \"\"\n\n\tif len(resolved.CNAMEs) > 0 {\n\t\tcnames = \" (-> \" + strings.Join(resolved.CNAMEs, \"->\") + \")\"\n\t}\n\n\treturn ret + cnames\n}\n\n// ResolvedDomains is a helper type for operating on a slice\n// of ResolvedDomain.\ntype ResolvedDomains []ResolvedDomain\n\n// String returns a string representation of all domains joined\n// to a single string.\nfunc (rds ResolvedDomains) String() string {\n\tdomains := make([]string, len(rds))\n\tfor idx, n := range rds {\n\t\tdomains[idx] = n.String()\n\t}\n\treturn strings.Join(domains, \" or \")\n}\n\n// IPInfo represents various information about an IP.\ntype IPInfo struct {\n\trecord.Base\n\tsync.Mutex\n\n\t// IP holds the actual IP address.\n\tIP string\n\n\t// ProfileID is used to scope this entry to a process group.\n\tProfileID string\n\n\t// ResolvedDomain is a slice of domains that\n\t// have been requested by various applications\n\t// and have been resolved to IP.\n\tResolvedDomains ResolvedDomains\n}\n\n// AddDomain adds a new resolved domain to IPInfo.\nfunc (info *IPInfo) AddDomain(resolved ResolvedDomain) {\n\tinfo.Lock()\n\tdefer info.Unlock()\n\n\t// Delete old for the same domain.\n\tfor idx, d := range info.ResolvedDomains {\n\t\tif d.Domain == resolved.Domain {\n\t\t\tinfo.ResolvedDomains = append(info.ResolvedDomains[:idx], info.ResolvedDomains[idx+1:]...)\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Add new entry to the end.\n\tinfo.ResolvedDomains = append(info.ResolvedDomains, resolved)\n}\n\n// MostRecentDomain returns the most recent domain.\nfunc (info *IPInfo) MostRecentDomain() *ResolvedDomain {\n\tinfo.Lock()\n\tdefer info.Unlock()\n\n\tif len(info.ResolvedDomains) == 0 {\n\t\treturn nil\n\t}\n\n\tmostRecent := info.ResolvedDomains[len(info.ResolvedDomains)-1]\n\treturn &mostRecent\n}\n\nfunc makeIPInfoKey(profileID, ip string) string {\n\treturn fmt.Sprintf(\"cache:intel/ipInfo/%s/%s\", profileID, ip)\n}\n\n// GetIPInfo gets an IPInfo record from the database.\nfunc GetIPInfo(profileID, ip string) (*IPInfo, error) {\n\tr, err := ipInfoDatabase.Get(makeIPInfoKey(profileID, ip))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewInfo := &IPInfo{}\n\t\terr = record.Unwrap(r, newInfo)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn newInfo, nil\n\t}\n\n\t// or adjust type\n\tnewInfo, ok := r.(*IPInfo)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *IPInfo, but %T\", r)\n\t}\n\treturn newInfo, nil\n}\n\n// Save saves the IPInfo record to the database.\nfunc (info *IPInfo) Save() error {\n\tinfo.Lock()\n\n\t// Set database key if not yet set already.\n\tif !info.KeyIsSet() {\n\t\t// Default to global scope if scope is unset.\n\t\tif info.ProfileID == \"\" {\n\t\t\tinfo.ProfileID = IPInfoProfileScopeGlobal\n\t\t}\n\t\tinfo.SetKey(makeIPInfoKey(info.ProfileID, info.IP))\n\t}\n\n\t// Calculate and set cache expiry.\n\texpires := time.Now().Unix() + 86400 // Minimum TTL of one day.\n\tfor _, rd := range info.ResolvedDomains {\n\t\tif rd.Expires > expires {\n\t\t\texpires = rd.Expires\n\t\t}\n\t}\n\tinfo.UpdateMeta()\n\texpires += 3600 // Add one hour to expiry as a buffer.\n\tinfo.Meta().SetAbsoluteExpiry(expires)\n\n\tinfo.Unlock()\n\n\treturn ipInfoDatabase.Put(info)\n}\n\n// String returns a string consisting of the domains that have seen to use this IP.\nfunc (info *IPInfo) String() string {\n\tinfo.Lock()\n\tdefer info.Unlock()\n\n\treturn fmt.Sprintf(\"<IPInfo[%s] %s: %s>\", info.Key(), info.IP, info.ResolvedDomains.String())\n}\n"
  },
  {
    "path": "service/resolver/ipinfo_test.go",
    "content": "package resolver\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestIPInfo(t *testing.T) {\n\tt.Parallel()\n\n\texample := ResolvedDomain{\n\t\tDomain: \"example.com.\",\n\t}\n\tsubExample := ResolvedDomain{\n\t\tDomain: \"sub1.example.com\",\n\t\tCNAMEs: []string{\"example.com\"},\n\t}\n\n\tinfo := &IPInfo{\n\t\tIP: \"1.2.3.4\",\n\t\tResolvedDomains: ResolvedDomains{\n\t\t\texample,\n\t\t\tsubExample,\n\t\t},\n\t}\n\n\tsub2Example := ResolvedDomain{\n\t\tDomain: \"sub2.example.com\",\n\t\tCNAMEs: []string{\"sub1.example.com\", \"example.com\"},\n\t}\n\tinfo.AddDomain(sub2Example)\n\tassert.Equal(t, ResolvedDomains{example, subExample, sub2Example}, info.ResolvedDomains)\n\n\t// try again, should do nothing now\n\tinfo.AddDomain(sub2Example)\n\tassert.Equal(t, ResolvedDomains{example, subExample, sub2Example}, info.ResolvedDomains)\n\n\tsubOverWrite := ResolvedDomain{\n\t\tDomain: \"sub1.example.com\",\n\t\tCNAMEs: []string{}, // now without CNAMEs\n\t}\n\n\tinfo.AddDomain(subOverWrite)\n\tassert.Equal(t, ResolvedDomains{example, sub2Example, subOverWrite}, info.ResolvedDomains)\n}\n"
  },
  {
    "path": "service/resolver/main.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t_ \"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// ResolverModule is the DNS resolver module.\ntype ResolverModule struct { //nolint\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tfailingResolverWorkerMgr   *mgr.WorkerMgr\n\tsuggestUsingStaleCacheTask *mgr.WorkerMgr\n\n\tisDisabled atomic.Bool\n\n\tstates *mgr.StateMgr\n}\n\n// Manager returns the module manager.\nfunc (rm *ResolverModule) Manager() *mgr.Manager {\n\treturn rm.mgr\n}\n\n// States returns the module state manager.\nfunc (rm *ResolverModule) States() *mgr.StateMgr {\n\treturn rm.states\n}\n\n// Start starts the module.\nfunc (rm *ResolverModule) Start() error {\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (rm *ResolverModule) Stop() error {\n\treturn nil\n}\n\nfunc (rm *ResolverModule) IsDisabled() bool {\n\treturn rm.isDisabled.Load()\n}\n\nfunc prep() error {\n\t// Set DNS test connectivity function for the online status check\n\tnetenv.DNSTestQueryFunc = func(ctx context.Context, fdqn string) (ips []net.IP, ok bool, err error) {\n\t\treturn testConnectivity(ctx, fdqn, nil)\n\t}\n\n\tintel.SetReverseResolver(ResolveIPAndValidate)\n\n\tif err := registerAPI(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := prepEnvResolver(); err != nil {\n\t\treturn err\n\t}\n\n\treturn prepConfig()\n}\n\nfunc start() error {\n\t// load resolvers from config and environment\n\tloadResolvers()\n\n\t// reload after network change\n\tmodule.instance.NetEnv().EventNetworkChange.AddCallback(\n\t\t\"update nameservers\",\n\t\tfunc(_ *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\tloadResolvers()\n\t\t\tlog.Debug(\"resolver: reloaded nameservers due to network change\")\n\t\t\treturn false, nil\n\t\t},\n\t)\n\n\t// Force resolvers to reconnect when SPN has connected.\n\tmodule.instance.GetEventSPNConnected().AddCallback(\n\t\t\"force resolver reconnect\",\n\t\tfunc(ctx *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\tForceResolverReconnect(ctx.Ctx())\n\t\t\treturn false, nil\n\t\t})\n\n\t// reload after config change\n\tprevNameservers := strings.Join(configuredNameServers(), \" \")\n\tmodule.instance.Config().EventConfigChange.AddCallback(\n\t\t\"update nameservers\",\n\t\tfunc(_ *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\tnewNameservers := strings.Join(configuredNameServers(), \" \")\n\t\t\tif newNameservers != prevNameservers {\n\t\t\t\tprevNameservers = newNameservers\n\n\t\t\t\tloadResolvers()\n\t\t\t\tlog.Debug(\"resolver: reloaded nameservers due to config change\")\n\t\t\t}\n\t\t\treturn false, nil\n\t\t})\n\n\t// Check failing resolvers regularly and when the network changes.\n\tmodule.failingResolverWorkerMgr = module.mgr.NewWorkerMgr(\"check failing resolvers\", checkFailingResolvers, nil)\n\tmodule.failingResolverWorkerMgr.Go()\n\tmodule.instance.NetEnv().EventNetworkChange.AddCallback(\n\t\t\"check failing resolvers\",\n\t\tfunc(wc *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\treturn false, checkFailingResolvers(wc)\n\t\t})\n\n\tmodule.suggestUsingStaleCacheTask = module.mgr.NewWorkerMgr(\"suggest using stale cache\", suggestUsingStaleCacheTask, nil)\n\tmodule.suggestUsingStaleCacheTask.Go()\n\n\tmodule.mgr.Go(\n\t\t\"mdns handler\",\n\t\tlistenToMDNS,\n\t)\n\n\tmodule.mgr.Go(\"name record delayed cache writer\", recordDatabase.DelayedCacheWriter)\n\tmodule.mgr.Go(\"ip info delayed cache writer\", ipInfoDatabase.DelayedCacheWriter)\n\n\treturn nil\n}\n\nvar localAddrFactory func(network string) net.Addr\n\n// SetLocalAddrFactory supplies the intel package with a function to get permitted local addresses for connections.\nfunc SetLocalAddrFactory(laf func(network string) net.Addr) {\n\tif localAddrFactory == nil {\n\t\tlocalAddrFactory = laf\n\t}\n}\n\nfunc getLocalAddr(network string) net.Addr {\n\tif localAddrFactory != nil {\n\t\treturn localAddrFactory(network)\n\t}\n\treturn nil\n}\n\nvar (\n\tfailingResolverNotification     *notifications.Notification\n\tfailingResolverNotificationSet  = abool.New()\n\tfailingResolverNotificationLock sync.Mutex\n\n\tfailingResolverErrorID = \"resolver:all-configured-resolvers-failed\"\n)\n\nfunc notifyAboutFailingResolvers() {\n\tfailingResolverNotificationLock.Lock()\n\tdefer failingResolverNotificationLock.Unlock()\n\tfailingResolverNotificationSet.Set()\n\n\t// Check if already set.\n\tif failingResolverNotification != nil {\n\t\treturn\n\t}\n\n\t// Create new notification.\n\tn := &notifications.Notification{\n\t\tEventID: failingResolverErrorID,\n\t\tType:    notifications.Error,\n\t\tTitle:   \"Configured DNS Servers Failing\",\n\t\tMessage: `All configured DNS servers in Portmaster are failing.\n\nYou might not be able to connect to these servers, or all of these servers are offline.  \nChoosing different DNS servers might fix this problem.\n\nWhile the issue persists, Portmaster will use the DNS servers from your system or network, if permitted by configuration.\n\nAlternatively, there might be something on your device that is interfering with Portmaster. This could be a firewall or another secure DNS resolver software. If that is your suspicion, please [check if you are running incompatible software here](https://docs.safing.io/portmaster/install/status/software-compatibility).\n\nThis notification will go away when Portmaster detects a working configured DNS server.`,\n\t\tShowOnSystem: true,\n\t\tAvailableActions: []*notifications.Action{{\n\t\t\tText: \"Change DNS Servers\",\n\t\t\tType: notifications.ActionTypeOpenSetting,\n\t\t\tPayload: &notifications.ActionTypeOpenSettingPayload{\n\t\t\t\tKey: CfgOptionNameServersKey,\n\t\t\t},\n\t\t}},\n\t}\n\tnotifications.Notify(n)\n\n\tfailingResolverNotification = n\n\tn.SyncWithState(module.states)\n}\n\nfunc resetFailingResolversNotification() {\n\tif failingResolverNotificationSet.IsNotSet() {\n\t\treturn\n\t}\n\n\tfailingResolverNotificationLock.Lock()\n\tdefer failingResolverNotificationLock.Unlock()\n\n\t// Remove the notification.\n\tif failingResolverNotification != nil {\n\t\tfailingResolverNotification.Delete()\n\t\tfailingResolverNotification = nil\n\t}\n\n\t// Additionally, resolve the module error, if not done through the notification.\n\tmodule.states.Remove(failingResolverErrorID)\n}\n\n// AddToDebugInfo adds the system status to the given debug.Info.\nfunc AddToDebugInfo(di *debug.Info) {\n\tresolversLock.Lock()\n\tdefer resolversLock.Unlock()\n\n\tcontent := make([]string, 0, (len(globalResolvers)*4)-1)\n\tvar working, total int\n\tfor i, resolver := range globalResolvers {\n\t\t// Count for summary.\n\t\ttotal++\n\t\tfailing := resolver.Conn.IsFailing()\n\t\tif !failing {\n\t\t\tworking++\n\t\t}\n\n\t\t// Add section.\n\t\tcontent = append(content, resolver.Info.DescriptiveName())\n\t\tcontent = append(content, fmt.Sprintf(\"  %s\", resolver.Info.ID()))\n\t\tif resolver.SearchOnly {\n\t\t\tcontent = append(content, \"  Used for search domains only!\")\n\t\t}\n\t\tif len(resolver.Search) > 0 {\n\t\t\tcontent = append(content, fmt.Sprintf(\"  Search Domains: %v\", strings.Join(resolver.Search, \", \")))\n\t\t}\n\t\tif resolver.LinkLocalUnavailable {\n\t\t\tcontent = append(content, \"  Link-local, but not available: ignoring\")\n\t\t}\n\t\tcontent = append(content, fmt.Sprintf(\"  Failing: %v\", resolver.Conn.IsFailing()))\n\n\t\t// Add a empty line for all but the last entry.\n\t\tif i+1 < len(globalResolvers) {\n\t\t\tcontent = append(content, \"\")\n\t\t}\n\t}\n\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Resolvers: %d/%d\", working, total),\n\t\tdebug.UseCodeSection|debug.AddContentLineBreaks,\n\t\tcontent...,\n\t)\n}\n\nvar (\n\tmodule     *ResolverModule\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Resolver module.\nfunc New(instance instance) (*ResolverModule, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Resolver\")\n\tmodule = &ResolverModule{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tstates: mgr.NewStateMgr(m),\n\t}\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn module, nil\n}\n\ntype instance interface {\n\tNetEnv() *netenv.NetEnv\n\tConfig() *config.Config\n\tGetEventSPNConnected() *mgr.EventMgr[struct{}]\n}\n"
  },
  {
    "path": "service/resolver/main_test.go",
    "content": "package resolver\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\nvar domainFeed = make(chan string)\n\ntype testInstance struct {\n\tdb     *dbmodule.DBModule\n\tbase   *base.Base\n\tconfig *config.Config\n\tnetenv *netenv.NetEnv\n}\n\nfunc (stub *testInstance) GetEventSPNConnected() *mgr.EventMgr[struct{}] {\n\treturn mgr.NewEventMgr[struct{}](\"spn connect\", nil)\n}\nfunc (stub *testInstance) IntelUpdates() *updates.Updater     { return nil }\nfunc (stub *testInstance) Config() *config.Config             { return stub.config }\nfunc (stub *testInstance) NetEnv() *netenv.NetEnv             { return stub.netenv }\nfunc (stub *testInstance) Ready() bool                        { return true }\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\nfunc (stub *testInstance) UI() *ui.UI                         { return nil }\nfunc (stub *testInstance) DataDir() string                    { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tvar err error\n\n\t// Create a temporary directory for testing\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\tfmt.Printf(\"failed to create temporary data directory: %s\", err)\n\t\tos.Exit(0)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Set the default API listen address\n\tapi.SetDefaultAPIListenAddress(\"0.0.0.0:8080\")\n\n\t// Initialize the instance with the necessary components\n\tstub := &testInstance{}\n\tstub.db, err = dbmodule.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database: %w\", err)\n\t}\n\tstub.config, err = config.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config: %w\", err)\n\t}\n\tstub.base, err = base.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create base: %w\", err)\n\t}\n\tstub.netenv, err = netenv.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create netenv: %w\", err)\n\t}\n\tmodule, err := New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create module: %w\", err)\n\t}\n\terr = stub.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start database: %w\", err)\n\t}\n\terr = stub.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start config: %w\", err)\n\t}\n\terr = stub.base.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start base: %w\", err)\n\t}\n\terr = stub.netenv.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start netenv: %w\", err)\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failed to start module: %w\", err)\n\t}\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\", err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc init() {\n\tgo feedDomains()\n}\n\nfunc feedDomains() {\n\tfor {\n\t\tfor _, domain := range testDomains {\n\t\t\tdomainFeed <- domain\n\t\t}\n\t}\n}\n\n// Data\n\nvar testDomains = []string{\n\t\"facebook.com.\",\n\t\"google.com.\",\n\t\"youtube.com.\",\n\t\"twitter.com.\",\n\t\"instagram.com.\",\n\t\"linkedin.com.\",\n\t\"microsoft.com.\",\n\t\"apple.com.\",\n\t\"wikipedia.org.\",\n\t\"plus.google.com.\",\n\t\"en.wikipedia.org.\",\n\t\"googletagmanager.com.\",\n\t\"youtu.be.\",\n\t\"adobe.com.\",\n\t\"vimeo.com.\",\n\t\"pinterest.com.\",\n\t\"itunes.apple.com.\",\n\t\"play.google.com.\",\n\t\"maps.google.com.\",\n\t\"goo.gl.\",\n\t\"wordpress.com.\",\n\t\"blogspot.com.\",\n\t\"bit.ly.\",\n\t\"github.com.\",\n\t\"player.vimeo.com.\",\n\t\"amazon.com.\",\n\t\"wordpress.org.\",\n\t\"docs.google.com.\",\n\t\"yahoo.com.\",\n\t\"mozilla.org.\",\n\t\"tumblr.com.\",\n\t\"godaddy.com.\",\n\t\"flickr.com.\",\n\t\"parked-content.godaddy.com.\",\n\t\"drive.google.com.\",\n\t\"support.google.com.\",\n\t\"apache.org.\",\n\t\"gravatar.com.\",\n\t\"europa.eu.\",\n\t\"qq.com.\",\n\t\"w3.org.\",\n\t\"nytimes.com.\",\n\t\"reddit.com.\",\n\t\"macromedia.com.\",\n\t\"get.adobe.com.\",\n\t\"soundcloud.com.\",\n\t\"sourceforge.net.\",\n\t\"sites.google.com.\",\n\t\"nih.gov.\",\n\t\"amazonaws.com.\",\n\t\"t.co.\",\n\t\"support.microsoft.com.\",\n\t\"forbes.com.\",\n\t\"theguardian.com.\",\n\t\"cnn.com.\",\n\t\"github.io.\",\n\t\"bbc.co.uk.\",\n\t\"dropbox.com.\",\n\t\"whatsapp.com.\",\n\t\"medium.com.\",\n\t\"creativecommons.org.\",\n\t\"www.ncbi.nlm.nih.gov.\",\n\t\"httpd.apache.org.\",\n\t\"archive.org.\",\n\t\"ec.europa.eu.\",\n\t\"php.net.\",\n\t\"apps.apple.com.\",\n\t\"weebly.com.\",\n\t\"support.apple.com.\",\n\t\"weibo.com.\",\n\t\"wixsite.com.\",\n\t\"issuu.com.\",\n\t\"who.int.\",\n\t\"paypal.com.\",\n\t\"m.facebook.com.\",\n\t\"oracle.com.\",\n\t\"msn.com.\",\n\t\"gnu.org.\",\n\t\"tinyurl.com.\",\n\t\"reuters.com.\",\n\t\"l.facebook.com.\",\n\t\"cloudflare.com.\",\n\t\"wsj.com.\",\n\t\"washingtonpost.com.\",\n\t\"domainmarket.com.\",\n\t\"imdb.com.\",\n\t\"bbc.com.\",\n\t\"bing.com.\",\n\t\"accounts.google.com.\",\n\t\"vk.com.\",\n\t\"api.whatsapp.com.\",\n\t\"opera.com.\",\n\t\"cdc.gov.\",\n\t\"slideshare.net.\",\n\t\"wpa.qq.com.\",\n\t\"harvard.edu.\",\n\t\"mit.edu.\",\n\t\"code.google.com.\",\n\t\"wikimedia.org.\",\n}\n"
  },
  {
    "path": "service/resolver/metrics.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar (\n\tslowQueriesSensorCnt atomic.Int64\n\tslowQueriesSensorSum atomic.Int64\n)\n\n// reportRequestDuration reports successful query request duration.\nfunc reportRequestDuration(started time.Time, resolver *Resolver) {\n\t// TODO: Record prometheus metrics for all resolvers separately.\n\n\t// Add query times from system and configured resolvers to slow queries sensor.\n\tswitch resolver.Info.Source {\n\tcase ServerSourceConfigured, ServerSourceOperatingSystem:\n\t\tslowQueriesSensorCnt.Add(1)\n\t\tslowQueriesSensorSum.Add(int64(time.Since(started)))\n\tdefault:\n\t}\n}\n\n// getSlowQueriesSensorValue returns the current avg query time recorded by the\n// slow queries sensor.\nfunc getSlowQueriesSensorValue() (avgQueryTime time.Duration) {\n\t// Get values and check them.\n\tsum := slowQueriesSensorSum.Load()\n\tcnt := slowQueriesSensorCnt.Load()\n\tif cnt < 1 {\n\t\tcnt = 1\n\t}\n\n\treturn time.Duration(sum / cnt)\n}\n\n// resetSlowQueriesSensorValue reset the slow queries sensor values.\nfunc resetSlowQueriesSensorValue() {\n\tslowQueriesSensorCnt.Store(0)\n\tslowQueriesSensorSum.Store(0)\n}\n\nvar suggestUsingStaleCacheNotification *notifications.Notification\nvar isFirstNotification = true\n\nfunc suggestUsingStaleCacheTask(_ *mgr.WorkerCtx) error {\n\tscheduleNextCall := true\n\tswitch {\n\tcase useStaleCache() || useStaleCacheConfigOption.IsSetByUser() || isNotificationSuppressed():\n\t\t// If setting is already active, disable task repeating.\n\t\tscheduleNextCall = false\n\n\t\t// Delete local reference, if used.\n\t\tif suggestUsingStaleCacheNotification != nil {\n\t\t\tsuggestUsingStaleCacheNotification.Delete()\n\t\t\tsuggestUsingStaleCacheNotification = nil\n\t\t}\n\n\tcase suggestUsingStaleCacheNotification != nil:\n\t\t// Check if notification is already active.\n\n\t\tsuggestUsingStaleCacheNotification.Lock()\n\t\tdefer suggestUsingStaleCacheNotification.Unlock()\n\t\tif suggestUsingStaleCacheNotification.Meta().IsDeleted() {\n\t\t\t// Reset local reference if notification was deleted.\n\t\t\tsuggestUsingStaleCacheNotification = nil\n\t\t}\n\n\tcase getSlowQueriesSensorValue() > 100*time.Millisecond:\n\t\tlog.Warningf(\n\t\t\t\"resolver: suggesting user to use stale dns cache with avg query time of %s for config and system resolvers\",\n\t\t\tgetSlowQueriesSensorValue().Round(time.Millisecond),\n\t\t)\n\n\t\tconst actionSuppressID = \"suppress\"\n\n\t\t// Notify user.\n\t\tsuggestUsingStaleCacheNotification = &notifications.Notification{\n\t\t\tEventID:      \"resolver:suggest-using-stale-cache\",\n\t\t\tType:         notifications.Info,\n\t\t\tTitle:        \"Speed Up Website Loading\",\n\t\t\tMessage:      \"Portmaster has detected that websites may load slower because DNS queries are currently slower than expected. You may want to switch your DNS provider or enable using expired DNS cache entries for better performance.\",\n\t\t\tShowOnSystem: isFirstNotification && getSlowQueriesSensorValue() > 500*time.Millisecond,\n\t\t\tExpires:      time.Now().Add(10 * time.Minute).Unix(),\n\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t{\n\t\t\t\t\tText: \"Open Setting\",\n\t\t\t\t\tType: notifications.ActionTypeOpenSetting,\n\t\t\t\t\tPayload: &notifications.ActionTypeOpenSettingPayload{\n\t\t\t\t\t\tKey: CfgOptionUseStaleCacheKey,\n\t\t\t\t\t},\n\t\t\t\t\tVisibility: notifications.ActionVisibilityInAppOnly,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tID:         actionSuppressID,\n\t\t\t\t\tText:       \"Don't show again\",\n\t\t\t\t\tVisibility: notifications.ActionVisibilityDetailed,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tID:   \"ack\",\n\t\t\t\t\tText: \"Got it!\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\t// Only show the notification on the system for the first time,\n\t\t// and do not bother user with multiple system notifications\n\t\tisFirstNotification = false\n\n\t\tsuggestUsingStaleCacheNotification.SetActionFunction(func(_ context.Context, n *notifications.Notification) error {\n\t\t\tn.Lock()\n\t\t\tactionID := n.SelectedActionID\n\t\t\tn.Unlock()\n\t\t\tif actionID == actionSuppressID {\n\t\t\t\tif err := suppressNotification(); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tn.Delete()\n\t\t\treturn nil\n\t\t})\n\n\t\tnotifications.Notify(suggestUsingStaleCacheNotification)\n\t}\n\n\tif scheduleNextCall {\n\t\t_ = module.suggestUsingStaleCacheTask.Delay(2 * time.Minute)\n\t}\n\tresetSlowQueriesSensorValue()\n\treturn nil\n}\n\n// === Notification state persistence ===\n\n// markerRecord is a minimal database record used as a presence-only marker.\ntype markerRecord struct {\n\trecord.Base\n\tsync.Mutex\n}\n\nvar db = database.NewInterface(&database.Options{Local: true, Internal: true})\n\n// Database key used to persist the user's choice to suppress the stale cache notification.\nconst Notification_DB_ID_StaleCacheSuppressed = \"core:notifications/resolver/StaleCache/suppressed\"\n\n// isNotificationSuppressed returns true if the user has chosen to never see the stale cache notification.\nfunc isNotificationSuppressed() bool {\n\t_, err := db.Get(Notification_DB_ID_StaleCacheSuppressed)\n\treturn err == nil\n}\n\n// suppressNotification persists the user's decision to never show the notification again.\nfunc suppressNotification() error {\n\tm := &markerRecord{}\n\tm.SetKey(Notification_DB_ID_StaleCacheSuppressed)\n\treturn db.Put(m)\n}\n"
  },
  {
    "path": "service/resolver/namerecord.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst (\n\t// databaseOvertime defines how much longer than the TTL name records are\n\t// cached in the database.\n\tdatabaseOvertime = 86400 * 14 // two weeks\n)\n\nvar (\n\trecordDatabase = database.NewInterface(&database.Options{\n\t\tLocal:    true,\n\t\tInternal: true,\n\n\t\t// Cache entries because application often resolve domains multiple times.\n\t\tCacheSize: 256,\n\n\t\t// We only use the cache database here, so we can delay and batch all our\n\t\t// writes. Also, no one else accesses these records, so we are fine using\n\t\t// this.\n\t\tDelayCachedWrites: \"cache\",\n\t})\n\n\tnameRecordsKeyPrefix = \"cache:intel/nameRecord/\"\n)\n\n// NameRecord is helper struct to RRCache to better save data to the database.\ntype NameRecord struct {\n\trecord.Base\n\tsync.Mutex\n\n\tDomain   string\n\tQuestion string\n\tRCode    int\n\tAnswer   []string\n\tNs       []string\n\tExtra    []string\n\tExpires  int64\n\n\tResolver *ResolverInfo\n}\n\n// IsValid returns whether the NameRecord is valid and may be used. Otherwise,\n// it should be disregarded.\nfunc (nameRecord *NameRecord) IsValid() bool {\n\tswitch {\n\tcase nameRecord.Resolver == nil || nameRecord.Resolver.Type == \"\":\n\t\t// Changed in v0.6.7: Introduced Resolver *ResolverInfo\n\t\treturn false\n\tdefault:\n\t\t// Up to date!\n\t\treturn true\n\t}\n}\n\nfunc makeNameRecordKey(domain string, question string) string {\n\treturn nameRecordsKeyPrefix + domain + question\n}\n\n// GetNameRecord gets a NameRecord from the database.\nfunc GetNameRecord(domain, question string) (*NameRecord, error) {\n\tkey := makeNameRecordKey(domain, question)\n\n\tr, err := recordDatabase.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Unwrap record if it's wrapped.\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewNR := &NameRecord{}\n\t\terr = record.Unwrap(r, newNR)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Check if the record is valid.\n\t\tif !newNR.IsValid() {\n\t\t\treturn nil, errors.New(\"record is invalid (outdated format)\")\n\t\t}\n\n\t\treturn newNR, nil\n\t}\n\n\t// Or just adjust the type.\n\tnewNR, ok := r.(*NameRecord)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *NameRecord, but %T\", r)\n\t}\n\t// Check if the record is valid.\n\tif !newNR.IsValid() {\n\t\treturn nil, errors.New(\"record is invalid (outdated format)\")\n\t}\n\n\treturn newNR, nil\n}\n\n// ResetCachedRecord deletes a NameRecord from the cache database.\nfunc ResetCachedRecord(domain, question string) error {\n\t// In order to properly delete an entry, we must also clear the caches.\n\trecordDatabase.FlushCache()\n\trecordDatabase.ClearCache()\n\n\tkey := makeNameRecordKey(domain, question)\n\treturn recordDatabase.Delete(key)\n}\n\n// Save saves the NameRecord to the database.\nfunc (nameRecord *NameRecord) Save() error {\n\tif nameRecord.Domain == \"\" || nameRecord.Question == \"\" {\n\t\treturn errors.New(\"could not save NameRecord, missing Domain and/or Question\")\n\t}\n\n\tnameRecord.SetKey(makeNameRecordKey(nameRecord.Domain, nameRecord.Question))\n\tnameRecord.UpdateMeta()\n\tnameRecord.Meta().SetAbsoluteExpiry(nameRecord.Expires + databaseOvertime)\n\n\treturn recordDatabase.PutNew(nameRecord)\n}\n\n// clearNameCacheHandler is an API handler that clears all dns caches from the database.\nfunc clearNameCacheHandler(ar *api.Request) (msg string, err error) {\n\tlog.Info(\"resolver: user requested dns cache clearing via action\")\n\n\treturn clearNameCache(ar.Context())\n}\n\n// clearNameCache clears all dns caches from the database.\nfunc clearNameCache(ctx context.Context) (msg string, err error) {\n\trecordDatabase.FlushCache()\n\trecordDatabase.ClearCache()\n\tn, err := recordDatabase.Purge(ctx, query.New(nameRecordsKeyPrefix))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tlog.Debugf(\"resolver: cleared %d entries from dns cache\", n)\n\treturn fmt.Sprintf(\"cleared %d dns cache entries\", n), nil\n}\n"
  },
  {
    "path": "service/resolver/namerecord_test.go",
    "content": "package resolver\n\nimport \"testing\"\n\nfunc TestNameRecordStorage(t *testing.T) {\n\tt.Parallel()\n\n\ttestDomain := \"Mk35mMqOWEHXSMk11MYcbjLOjTE8PQvDiAVUxf4BvwtgR.example.com.\"\n\ttestQuestion := \"A\"\n\n\ttestNameRecord := &NameRecord{\n\t\tDomain:   testDomain,\n\t\tQuestion: testQuestion,\n\t\tResolver: &ResolverInfo{\n\t\t\tType: \"dns\",\n\t\t},\n\t}\n\n\terr := testNameRecord.Save()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tr, err := GetNameRecord(testDomain, testQuestion)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif r.Domain != testDomain || r.Question != testQuestion {\n\t\tt.Fatal(\"mismatch\")\n\t}\n}\n"
  },
  {
    "path": "service/resolver/resolve.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\t\"golang.org/x/net/publicsuffix\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// Errors.\nvar (\n\t// Basic Errors.\n\n\t// ErrNotFound is a basic error that will match all \"not found\" errors.\n\tErrNotFound = errors.New(\"record could not be found\")\n\t// ErrBlocked is basic error that will match all \"blocked\" errors.\n\tErrBlocked = errors.New(\"query was blocked\")\n\t// ErrLocalhost is returned to *.localhost queries.\n\tErrLocalhost = errors.New(\"query for localhost\")\n\t// ErrTimeout is returned when a query times out.\n\tErrTimeout = errors.New(\"query timed out\")\n\t// ErrOffline is returned when no network connection is detected.\n\tErrOffline = errors.New(\"device is offine\")\n\t// ErrFailure is returned when the type of failure is unclear.\n\tErrFailure = errors.New(\"query failed\")\n\t// ErrContinue is returned when the resolver has no answer, and the next resolver should be asked.\n\tErrContinue = errors.New(\"resolver has no answer\")\n\t// ErrShuttingDown is returned when the resolver is shutting down.\n\tErrShuttingDown = errors.New(\"resolver is shutting down\")\n\n\t// Detailed Errors.\n\n\t// ErrTestDomainsDisabled wraps ErrBlocked.\n\tErrTestDomainsDisabled = fmt.Errorf(\"%w: test domains disabled\", ErrBlocked)\n\t// ErrSpecialDomainsDisabled wraps ErrBlocked.\n\tErrSpecialDomainsDisabled = fmt.Errorf(\"%w: special domains disabled\", ErrBlocked)\n\t// ErrInvalid wraps ErrNotFound.\n\tErrInvalid = fmt.Errorf(\"%w: invalid request\", ErrNotFound)\n\t// ErrNoCompliance wraps ErrBlocked and is returned when no resolvers were able to comply with the current settings.\n\tErrNoCompliance = fmt.Errorf(\"%w: no compliant resolvers for this query\", ErrBlocked)\n)\n\nconst (\n\tminTTL     = 60 // 1 Minute\n\trefreshTTL = minTTL / 2\n\tminMDnsTTL = 60           // 1 Minute\n\tmaxTTL     = 24 * 60 * 60 // 24 hours\n)\n\nvar (\n\tdupReqMap  = make(map[string]*dedupeStatus)\n\tdupReqLock sync.Mutex\n)\n\ntype dedupeStatus struct {\n\tcompleted  chan struct{}\n\twaitUntil  time.Time\n\tsuperseded bool\n}\n\n// BlockedUpstreamError is returned when a DNS request\n// has been blocked by the upstream server.\ntype BlockedUpstreamError struct {\n\tResolverName string\n}\n\nfunc (blocked *BlockedUpstreamError) Error() string {\n\treturn fmt.Sprintf(\"%s by upstream DNS resolver %s\", ErrBlocked, blocked.ResolverName)\n}\n\n// Unwrap implements errors.Unwrapper.\nfunc (blocked *BlockedUpstreamError) Unwrap() error {\n\treturn ErrBlocked\n}\n\n// Query describes a dns query.\ntype Query struct {\n\tFQDN               string\n\tQType              dns.Type\n\tNoCaching          bool\n\tIgnoreFailing      bool\n\tLocalResolversOnly bool\n\n\t// ICANNSpace signifies if the domain is within ICANN managed domain space.\n\tICANNSpace bool\n\t// Domain root is the effective TLD +1.\n\tDomainRoot string\n\n\t// internal\n\tdotPrefixedFQDN string\n}\n\n// ID returns the ID of the query consisting of the domain and question type.\nfunc (q *Query) ID() string {\n\treturn q.FQDN + q.QType.String()\n}\n\n// InitPublicSuffixData initializes the public suffix data.\nfunc (q *Query) InitPublicSuffixData() {\n\t// Get public suffix and derive if domain is in ICANN space.\n\tsuffix, icann := publicsuffix.PublicSuffix(strings.TrimSuffix(q.FQDN, \".\"))\n\tif icann || strings.Contains(suffix, \".\") {\n\t\tq.ICANNSpace = true\n\t}\n\t// Override some cases.\n\tswitch suffix {\n\tcase \"example\":\n\t\tq.ICANNSpace = true // Defined by ICANN.\n\tcase \"invalid\":\n\t\tq.ICANNSpace = true // Defined by ICANN.\n\tcase \"local\":\n\t\tq.ICANNSpace = true // Defined by ICANN.\n\tcase \"localhost\":\n\t\tq.ICANNSpace = true // Defined by ICANN.\n\tcase \"onion\":\n\t\tq.ICANNSpace = false // Defined by ICANN, but special.\n\tcase \"test\":\n\t\tq.ICANNSpace = true // Defined by ICANN.\n\t}\n\t// Add suffix to adhere to FQDN format.\n\tsuffix += \".\"\n\n\tswitch {\n\tcase len(q.FQDN) == len(suffix):\n\t\t// We are at or below the domain root, reset.\n\t\tq.DomainRoot = \"\"\n\tcase len(q.FQDN) > len(suffix):\n\t\tdomainRootStart := strings.LastIndex(q.FQDN[:len(q.FQDN)-len(suffix)-1], \".\") + 1\n\t\tq.DomainRoot = q.FQDN[domainRootStart:]\n\t}\n}\n\n// check runs sanity checks and does some initialization. Returns whether the query passed the basic checks.\nfunc (q *Query) check() (ok bool) {\n\tif q.FQDN == \"\" {\n\t\treturn false\n\t}\n\n\t// init\n\tq.FQDN = dns.Fqdn(q.FQDN)\n\tif q.FQDN == \".\" {\n\t\tq.dotPrefixedFQDN = q.FQDN\n\t} else {\n\t\tq.dotPrefixedFQDN = \".\" + q.FQDN\n\t}\n\n\treturn true\n}\n\n// Resolve resolves the given query for a domain and type and returns a RRCache object or nil, if the query failed.\nfunc Resolve(ctx context.Context, q *Query) (rrCache *RRCache, err error) {\n\t// sanity check\n\tif q == nil || !q.check() {\n\t\treturn nil, ErrInvalid\n\t}\n\n\t// log\n\t// try adding a context tracer\n\tctx, tracer := log.AddTracer(ctx)\n\tdefer tracer.Submit()\n\tlog.Tracer(ctx).Tracef(\"resolver: resolving %s%s\", q.FQDN, q.QType)\n\n\t// check query compliance\n\tif err = q.checkCompliance(); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// check the cache\n\tif !q.NoCaching {\n\t\trrCache = checkCache(ctx, q)\n\t\tif rrCache != nil {\n\t\t\tswitch {\n\t\t\tcase !rrCache.Expired():\n\t\t\t\t// Return non-expired cached entry immediately.\n\t\t\t\treturn rrCache, nil\n\t\t\tcase rrCache.RCode == dns.RcodeSuccess && useStaleCache():\n\t\t\t\t// Return expired cache if we should use stale cache entries,\n\t\t\t\t// but start an async query instead.\n\t\t\t\tlog.Tracer(ctx).Tracef(\n\t\t\t\t\t\"resolver: using stale cache entry that expired %s ago\",\n\t\t\t\t\ttime.Since(time.Unix(rrCache.Expires, 0)).Round(time.Second),\n\t\t\t\t)\n\t\t\t\tstartAsyncQuery(ctx, q, rrCache)\n\t\t\t\treturn rrCache, nil\n\t\t\t}\n\t\t}\n\n\t\t// dedupe!\n\t\tmarkRequestFinished := deduplicateRequest(ctx, q)\n\t\tif markRequestFinished == nil {\n\t\t\t// we waited for another request, recheck the cache!\n\t\t\trrCache = checkCache(ctx, q)\n\t\t\tif rrCache != nil && (!rrCache.Expired() || useStaleCache()) {\n\t\t\t\t// Return non-expired or expired entry if we should use stale cache entries.\n\t\t\t\t// There just was a request, so do not trigger an async query.\n\t\t\t\treturn rrCache, nil\n\t\t\t}\n\t\t\tlog.Tracer(ctx).Debugf(\"resolver: waited for another %s%s query, but cache missed!\", q.FQDN, q.QType)\n\t\t\t// if cache is still empty or non-compliant, go ahead and just query\n\t\t} else {\n\t\t\t// we are the first!\n\t\t\tdefer markRequestFinished()\n\t\t}\n\t}\n\n\treturn resolveAndCache(ctx, q, rrCache)\n}\n\nfunc checkCache(ctx context.Context, q *Query) *RRCache {\n\t// Never ask cache for connectivity domains.\n\tif netenv.IsConnectivityDomain(q.FQDN) {\n\t\treturn nil\n\t}\n\n\t// Get data from cache.\n\trrCache, err := GetRRCache(q.FQDN, q.QType)\n\t// Return if entry is not in cache.\n\tif err != nil {\n\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\tlog.Tracer(ctx).Warningf(\"resolver: getting RRCache %s%s from database failed: %s\", q.FQDN, q.QType.String(), err)\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Get the resolver that the rrCache was resolved with.\n\tresolver := getActiveResolverByIDWithLocking(rrCache.Resolver.ID())\n\tif resolver == nil {\n\t\tlog.Tracer(ctx).Debugf(\"resolver: ignoring RRCache %s%s because source server %q has been removed\", q.FQDN, q.QType.String(), rrCache.Resolver.ID())\n\t\treturn nil\n\t}\n\n\t// Check compliance of the resolver, return if non-compliant.\n\terr = resolver.checkCompliance(ctx, q)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Debugf(\"resolver: cached entry for %s%s does not comply to query parameters: %s\", q.FQDN, q.QType.String(), err)\n\t\treturn nil\n\t}\n\n\tswitch {\n\tcase shouldResetCache(q):\n\t\t// Check if we want to reset the cache for this entry.\n\t\terr := ResetCachedRecord(q.FQDN, q.QType.String())\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\tlog.Tracer(ctx).Infof(\"resolver: cache for %s%s was reset\", q.FQDN, q.QType)\n\t\tcase errors.Is(err, database.ErrNotFound):\n\t\t\tlog.Tracer(ctx).Tracef(\"resolver: cache for %s%s was already reset (is empty)\", q.FQDN, q.QType)\n\t\tdefault:\n\t\t\tlog.Tracer(ctx).Warningf(\"resolver: failed to reset cache for %s%s: %s\", q.FQDN, q.QType, err)\n\t\t}\n\t\treturn nil\n\n\tcase rrCache.Expired():\n\t\t// Check if the cache has already expired.\n\t\t// We still return the cache, if it isn't NXDomain, as it will be used if the\n\t\t// new query fails.\n\t\tif rrCache.RCode == dns.RcodeSuccess {\n\t\t\treturn rrCache\n\t\t}\n\t\treturn nil\n\n\tcase rrCache.ExpiresSoon():\n\t\t// Check if the cache will expire soon and start an async request.\n\t\tstartAsyncQuery(ctx, q, rrCache)\n\t\treturn rrCache\n\n\tdefault:\n\t\t// Return still valid cache entry.\n\t\tlog.Tracer(ctx).Tracef(\n\t\t\t\"resolver: using cached RR (expires in %s)\",\n\t\t\ttime.Until(time.Unix(rrCache.Expires, 0)).Round(time.Second),\n\t\t)\n\t\treturn rrCache\n\t}\n}\n\nfunc startAsyncQuery(ctx context.Context, q *Query, currentRRCache *RRCache) {\n\t// Check if an async query was already started.\n\tif currentRRCache.RequestingNew {\n\t\treturn\n\t}\n\n\t// Set flag and log that we are refreshing this entry.\n\tcurrentRRCache.RequestingNew = true\n\tif currentRRCache.Expired() {\n\t\tlog.Tracer(ctx).Tracef(\n\t\t\t\"resolver: cache for %s has expired %s ago, refreshing async now\",\n\t\t\tq.ID(),\n\t\t\ttime.Since(time.Unix(currentRRCache.Expires, 0)).Round(time.Second),\n\t\t)\n\t} else {\n\t\tlog.Tracer(ctx).Tracef(\n\t\t\t\"resolver: cache for %s will expire in %s, refreshing async now\",\n\t\t\tq.ID(),\n\t\t\ttime.Until(time.Unix(currentRRCache.Expires, 0)).Round(time.Second),\n\t\t)\n\t}\n\n\t// resolve async\n\tmodule.mgr.Go(\"resolve async\", func(wc *mgr.WorkerCtx) error {\n\t\ttracingCtx, tracer := log.AddTracer(wc.Ctx())\n\t\tdefer tracer.Submit()\n\t\ttracer.Tracef(\"resolver: resolving %s async\", q.ID())\n\t\t_, err := resolveAndCache(tracingCtx, q, nil)\n\t\tif err != nil {\n\t\t\ttracer.Warningf(\"resolver: async query for %s failed: %s\", q.ID(), err)\n\t\t} else {\n\t\t\ttracer.Infof(\"resolver: async query for %s succeeded\", q.ID())\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc deduplicateRequest(ctx context.Context, q *Query) (finishRequest func()) {\n\t// create identifier key\n\tdupKey := q.ID()\n\n\t// restart here if waiting timed out\nretry:\n\n\tdupReqLock.Lock()\n\n\t// get duplicate request waitgroup\n\tstatus, requestActive := dupReqMap[dupKey]\n\n\t// check if the request ist active\n\tif requestActive {\n\t\t// someone else is already on it!\n\t\tif time.Now().Before(status.waitUntil) {\n\t\t\tdupReqLock.Unlock()\n\n\t\t\t// log that we are waiting\n\t\t\tlog.Tracer(ctx).Tracef(\"resolver: waiting for duplicate query for %s to complete\", dupKey)\n\t\t\t// wait\n\t\t\tselect {\n\t\t\tcase <-status.completed:\n\t\t\t\t// done!\n\t\t\t\treturn nil\n\t\t\tcase <-time.After(maxRequestTimeout):\n\t\t\t\t// something went wrong with the query, retry\n\t\t\t\tgoto retry\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\t}\n\t\t} else {\n\t\t\t// but that someone is taking too long\n\t\t\tstatus.superseded = true\n\t\t}\n\t}\n\n\t// we are currently the only one doing a request for this\n\n\t// create new status\n\tstatus = &dedupeStatus{\n\t\tcompleted: make(chan struct{}),\n\t\twaitUntil: time.Now().Add(maxRequestTimeout),\n\t}\n\t// add to registry\n\tdupReqMap[dupKey] = status\n\n\tdupReqLock.Unlock()\n\n\t// return function to mark request as finished\n\treturn func() {\n\t\tdupReqLock.Lock()\n\t\tdefer dupReqLock.Unlock()\n\t\t// mark request as done\n\t\tclose(status.completed)\n\t\t// delete from registry\n\t\tif !status.superseded {\n\t\t\tdelete(dupReqMap, dupKey)\n\t\t}\n\t}\n}\n\nfunc resolveAndCache(ctx context.Context, q *Query, oldCache *RRCache) (rrCache *RRCache, err error) { //nolint:gocognit,gocyclo\n\t// get resolvers\n\tresolvers, primarySource, tryAll := GetResolversInScope(ctx, q)\n\tif len(resolvers) == 0 {\n\t\treturn nil, ErrNoCompliance\n\t}\n\n\t// check if we are online\n\tif netenv.GetOnlineStatus() == netenv.StatusOffline && primarySource != ServerSourceEnv {\n\t\tif q.FQDN != netenv.DNSTestDomain && !netenv.IsConnectivityDomain(q.FQDN) {\n\t\t\t// we are offline and this is not an online check query\n\t\t\treturn oldCache, ErrOffline\n\t\t}\n\t\tlog.Tracer(ctx).Debugf(\"resolver: allowing online status test domain %s to resolve even though offline\", q.FQDN)\n\t}\n\n\t// Report when all configured resolvers are failing.\n\tvar failureReported bool\n\tdefer func() {\n\t\tif failureReported &&\n\t\t\tnetenv.Online() &&\n\t\t\tprimarySource == ServerSourceConfigured &&\n\t\t\tallConfiguredResolversAreFailing() {\n\t\t\tnotifyAboutFailingResolvers()\n\t\t}\n\t}()\n\n\t// start resolving\n\tfor _, resolver := range resolvers {\n\t\tif module.mgr.IsDone() {\n\t\t\treturn nil, ErrShuttingDown\n\t\t}\n\n\t\t// Skip failing resolvers.\n\t\tif resolver.Conn.IsFailing() {\n\t\t\tlog.Tracer(ctx).Tracef(\"resolver: skipping resolver %s, because it is failing\", resolver)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Skip unreachable link-local resolvers.\n\t\tif resolver.LinkLocalUnavailable {\n\t\t\tlog.Tracer(ctx).Tracef(\"resolver: skipping resolver %s, because it is link-local and not available\", resolver)\n\t\t\tcontinue\n\t\t}\n\n\t\t// resolve\n\t\tlog.Tracer(ctx).Tracef(\"resolver: sending query for %s to %s\", q.ID(), resolver.Info.ID())\n\t\trrCache, err = resolver.Conn.Query(ctx, q)\n\t\tif err != nil {\n\t\t\tswitch {\n\t\t\tcase errors.Is(err, ErrNotFound):\n\t\t\t\t// NXDomain, or similar\n\t\t\t\tif tryAll {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn nil, err\n\t\t\tcase errors.Is(err, ErrBlocked):\n\t\t\t\t// some resolvers might also block\n\t\t\t\treturn nil, err\n\t\t\tcase netenv.GetOnlineStatus() == netenv.StatusOffline &&\n\t\t\t\tq.FQDN != netenv.DNSTestDomain &&\n\t\t\t\t!netenv.IsConnectivityDomain(q.FQDN):\n\t\t\t\t// we are offline and this is not an online check query\n\t\t\t\treturn oldCache, ErrOffline\n\t\t\tcase errors.Is(err, ErrContinue):\n\t\t\t\tcontinue\n\t\t\tcase errors.Is(err, ErrTimeout):\n\t\t\t\tresolver.Conn.ReportFailure()\n\t\t\t\tfailureReported = true\n\t\t\t\tlog.Tracer(ctx).Debugf(\"resolver: query to %s timed out\", resolver.Info.ID())\n\t\t\t\tcontinue\n\t\t\tcase errors.Is(err, context.Canceled):\n\t\t\t\treturn nil, err\n\t\t\tcase errors.Is(err, context.DeadlineExceeded):\n\t\t\t\treturn nil, err\n\t\t\tcase errors.Is(err, ErrShuttingDown):\n\t\t\t\treturn nil, err\n\t\t\tdefault:\n\t\t\t\tresolver.Conn.ReportFailure()\n\t\t\t\tfailureReported = true\n\t\t\t\tlog.Tracer(ctx).Warningf(\"resolver: query to %s failed: %s\", resolver.Info.ID(), err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif rrCache == nil {\n\t\t\t// Defensive: This should normally not happen.\n\t\t\tcontinue\n\t\t}\n\t\t// Check if request succeeded and whether we should try another resolver.\n\t\tif rrCache.RCode != dns.RcodeSuccess && tryAll {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Report a successful connection.\n\t\tresolver.Conn.ResetFailure()\n\t\t// Reset failing resolvers notification, if querying in global scope.\n\t\tif primarySource == ServerSourceConfigured && !allConfiguredResolversAreFailing() {\n\t\t\tresetFailingResolversNotification()\n\t\t}\n\n\t\tbreak\n\t}\n\n\t// Validate return values.\n\tif err == nil && rrCache == nil {\n\t\terr = ErrNotFound\n\t}\n\n\t// Handle error.\n\tif err != nil {\n\t\t// Check if we can return an older cache instead of the error.\n\t\tif oldCache != nil {\n\t\t\toldCache.IsBackup = true\n\t\t\tlog.Tracer(ctx).Debugf(\"resolver: serving backup cache of %s because query failed: %s\", q.ID(), err)\n\t\t\treturn oldCache, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"all %d query-compliant resolvers failed, last error: %w\", len(resolvers), err)\n\t}\n\n\t// Adjust TTLs.\n\trrCache.Clean(minTTL)\n\n\t// Save the new entry if cache is enabled and the record may be cached.\n\tif !q.NoCaching && rrCache.Cacheable() {\n\t\terr = rrCache.Save()\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Warningf(\"resolver: failed to cache RR for %s: %s\", q.ID(), err)\n\t\t}\n\t}\n\n\treturn rrCache, nil\n}\n\nvar (\n\tcacheResetLock    sync.Mutex\n\tcacheResetID      string\n\tcacheResetSeenCnt int\n)\n\nfunc shouldResetCache(q *Query) (reset bool) {\n\tcacheResetLock.Lock()\n\tdefer cacheResetLock.Unlock()\n\n\t// reset to new domain\n\tqID := q.ID()\n\tif qID != cacheResetID {\n\t\tcacheResetID = qID\n\t\tcacheResetSeenCnt = 1\n\t\treturn false\n\t}\n\n\t// increase and check if threshold is reached\n\tcacheResetSeenCnt++\n\tif cacheResetSeenCnt >= 3 { // 3 to trigger reset\n\t\tcacheResetSeenCnt = -7 // 10 for follow-up resets\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// testConnectivity test if resolving a query succeeds and returns whether the\n// query itself succeeded, separate from interpreting the result.\n// Provide a resolver to use or automatically select one if nil.\nfunc testConnectivity(ctx context.Context, fdqn string, resolver *Resolver) (ips []net.IP, ok bool, err error) {\n\tq := &Query{\n\t\tFQDN:      fdqn,\n\t\tQType:     dns.Type(dns.TypeA),\n\t\tNoCaching: true,\n\t}\n\tif !q.check() {\n\t\treturn nil, false, ErrInvalid\n\t}\n\n\t// Resolve with given resolver or auto-select.\n\tvar rrCache *RRCache\n\tif resolver != nil {\n\t\trrCache, err = resolver.Conn.Query(ctx, q)\n\t} else {\n\t\trrCache, err = resolveAndCache(ctx, q, nil)\n\t}\n\n\t// Enhance results.\n\tswitch {\n\tcase err == nil:\n\t\tswitch rrCache.RCode {\n\t\tcase dns.RcodeNameError:\n\t\t\treturn nil, true, ErrNotFound\n\t\tcase dns.RcodeRefused:\n\t\t\treturn nil, true, errors.New(\"refused\")\n\t\tdefault:\n\t\t\tips := rrCache.ExportAllARecords()\n\t\t\tif len(ips) > 0 {\n\t\t\t\treturn ips, true, nil\n\t\t\t}\n\t\t\treturn nil, true, ErrNotFound\n\t\t}\n\tcase errors.Is(err, ErrNotFound):\n\t\treturn nil, true, err\n\tcase errors.Is(err, ErrNoCompliance):\n\t\treturn nil, true, err\n\tcase errors.Is(err, ErrBlocked):\n\t\treturn nil, true, err\n\tdefault:\n\t\treturn nil, false, err\n\t}\n}\n"
  },
  {
    "path": "service/resolver/resolver-env.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\nconst (\n\t// InternalSpecialUseDomain is the domain scope used for internal services.\n\tInternalSpecialUseDomain = \"portmaster.home.arpa.\"\n\n\trouterDomain        = \"router.local.\" + InternalSpecialUseDomain\n\tcaptivePortalDomain = \"captiveportal.local.\" + InternalSpecialUseDomain\n)\n\nvar (\n\tenvResolver = &Resolver{\n\t\tConfigURL: ServerSourceEnv,\n\t\tInfo: &ResolverInfo{\n\t\t\tType:    ServerTypeEnv,\n\t\t\tSource:  ServerSourceEnv,\n\t\t\tIPScope: netutils.SiteLocal,\n\t\t},\n\t\tConn: &envResolverConn{},\n\t}\n\tenvResolvers = []*Resolver{envResolver}\n\n\tinternalSpecialUseSOA     dns.RR\n\tinternalSpecialUseComment dns.RR\n)\n\nfunc prepEnvResolver() (err error) {\n\tnetenv.SpecialCaptivePortalDomain = captivePortalDomain\n\n\tinternalSpecialUseSOA, err = dns.NewRR(fmt.Sprintf(\n\t\t\"%s 17 IN SOA localhost. none.localhost. 0 0 0 0 0\",\n\t\tInternalSpecialUseDomain,\n\t))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tinternalSpecialUseComment, err = dns.NewRR(fmt.Sprintf(\n\t\t`%s 17 IN TXT \"This is a special use TLD of the Portmaster.\"`,\n\t\tInternalSpecialUseDomain,\n\t))\n\treturn err\n}\n\ntype envResolverConn struct{}\n\nfunc (er *envResolverConn) Query(ctx context.Context, q *Query) (*RRCache, error) {\n\tswitch uint16(q.QType) {\n\tcase dns.TypeA, dns.TypeAAAA: // We respond with all IPv4/6 addresses we can find.\n\t\t// Check for exact matches.\n\t\tswitch q.FQDN {\n\t\tcase captivePortalDomain:\n\t\t\t// Get IP address of the captive portal.\n\t\t\tportal := netenv.GetCaptivePortal()\n\t\t\tportalIP := portal.IP\n\t\t\tif portalIP == nil {\n\t\t\t\tportalIP = netenv.PortalTestIP\n\t\t\t}\n\t\t\t// Convert IP to record and respond.\n\t\t\trecords, err := netutils.IPsToRRs(q.FQDN, []net.IP{portalIP})\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"nameserver: failed to create captive portal response to %s: %s\", q.FQDN, err)\n\t\t\t\treturn er.nxDomain(q), nil\n\t\t\t}\n\t\t\treturn er.makeRRCache(q, records), nil\n\n\t\tcase routerDomain:\n\t\t\t// Get gateways from netenv system.\n\t\t\trouters := netenv.Gateways()\n\t\t\tif len(routers) == 0 {\n\t\t\t\treturn er.nxDomain(q), nil\n\t\t\t}\n\t\t\t// Convert IP to record and respond.\n\t\t\trecords, err := netutils.IPsToRRs(q.FQDN, routers)\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"nameserver: failed to create gateway response to %s: %s\", q.FQDN, err)\n\t\t\t\treturn er.nxDomain(q), nil\n\t\t\t}\n\t\t\treturn er.makeRRCache(q, records), nil\n\t\t}\n\n\t\t// Check for suffix matches.\n\t\tif strings.HasSuffix(q.FQDN, CompatDNSCheckInternalDomainScope) {\n\t\t\tsubdomain := strings.TrimSuffix(q.FQDN, CompatDNSCheckInternalDomainScope)\n\t\t\trespondWith := CompatSubmitDNSCheckDomain(subdomain)\n\n\t\t\t// We'll get an A record. Only respond if it's an A question.\n\t\t\tif respondWith != nil && uint16(q.QType) == dns.TypeA {\n\t\t\t\trecords, err := netutils.IPsToRRs(q.FQDN, []net.IP{respondWith})\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warningf(\"nameserver: failed to create dns check response to %s: %s\", q.FQDN, err)\n\t\t\t\t\treturn er.nxDomain(q), nil\n\t\t\t\t}\n\t\t\t\treturn er.makeRRCache(q, records), nil\n\t\t\t}\n\t\t}\n\tcase dns.TypeSOA:\n\t\t// Direct query for the SOA record.\n\t\tif q.FQDN == InternalSpecialUseDomain {\n\t\t\treturn er.makeRRCache(q, []dns.RR{internalSpecialUseSOA}), nil\n\t\t}\n\t}\n\n\t// No match, reply with NXDOMAIN and SOA record\n\treply := er.nxDomain(q)\n\treply.Ns = []dns.RR{internalSpecialUseSOA}\n\treturn reply, nil\n}\n\nfunc (er *envResolverConn) nxDomain(q *Query) *RRCache {\n\treturn er.makeRRCache(q, nil)\n}\n\nfunc (er *envResolverConn) makeRRCache(q *Query, answers []dns.RR) *RRCache {\n\t// Disable caching, as the env always has the raw data available.\n\tq.NoCaching = true\n\n\trrCache := &RRCache{\n\t\tDomain:   q.FQDN,\n\t\tQuestion: q.QType,\n\t\tRCode:    dns.RcodeSuccess,\n\t\tAnswer:   answers,\n\t\tExtra:    []dns.RR{internalSpecialUseComment}, // Always add comment about this TLD.\n\t\tResolver: envResolver.Info.Copy(),\n\t}\n\tif len(rrCache.Answer) == 0 {\n\t\trrCache.RCode = dns.RcodeNameError\n\t}\n\treturn rrCache\n}\n\nfunc (er *envResolverConn) ReportFailure() {}\n\nfunc (er *envResolverConn) IsFailing() bool {\n\treturn false\n}\n\nfunc (er *envResolverConn) ResetFailure() {}\n\nfunc (er *envResolverConn) ForceReconnect(_ context.Context) {}\n\n// QueryPortmasterEnv queries the environment resolver directly.\nfunc QueryPortmasterEnv(ctx context.Context, q *Query) (*RRCache, error) {\n\treturn envResolver.Conn.Query(ctx, q)\n}\n"
  },
  {
    "path": "service/resolver/resolver-https.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// HTTPSResolver is a resolver using just a single tcp connection with pipelining.\ntype HTTPSResolver struct {\n\tBasicResolverConn\n\tclient     *http.Client\n\tclientLock sync.RWMutex\n}\n\n// HTTPSQuery holds the query information for a hTTPSResolverConn.\ntype HTTPSQuery struct {\n\tQuery    *Query\n\tResponse chan *dns.Msg\n}\n\n// MakeCacheRecord creates an RRCache record from a reply.\nfunc (tq *HTTPSQuery) MakeCacheRecord(reply *dns.Msg, resolverInfo *ResolverInfo) *RRCache {\n\treturn &RRCache{\n\t\tDomain:   tq.Query.FQDN,\n\t\tQuestion: tq.Query.QType,\n\t\tRCode:    reply.Rcode,\n\t\tAnswer:   reply.Answer,\n\t\tNs:       reply.Ns,\n\t\tExtra:    reply.Extra,\n\t\tResolver: resolverInfo.Copy(),\n\t}\n}\n\n// NewHTTPSResolver returns a new HTTPSResolver.\nfunc NewHTTPSResolver(resolver *Resolver) *HTTPSResolver {\n\tnewResolver := &HTTPSResolver{\n\t\tBasicResolverConn: BasicResolverConn{\n\t\t\tresolver: resolver,\n\t\t},\n\t}\n\tnewResolver.BasicResolverConn.init()\n\tnewResolver.refreshClient()\n\treturn newResolver\n}\n\n// Query executes the given query against the resolver.\nfunc (hr *HTTPSResolver) Query(ctx context.Context, q *Query) (*RRCache, error) {\n\tqueryStarted := time.Now()\n\n\tdnsQuery := new(dns.Msg)\n\tdnsQuery.SetQuestion(q.FQDN, uint16(q.QType))\n\n\t// Pack query and convert to base64 string\n\tbuf, err := dnsQuery.Pack()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tb64dns := base64.RawURLEncoding.EncodeToString(buf)\n\n\t// Build and execute http request\n\turl := &url.URL{\n\t\tScheme:     \"https\",\n\t\tHost:       hr.resolver.ServerAddress,\n\t\tPath:       hr.resolver.Path,\n\t\tForceQuery: true,\n\t\tRawQuery:   fmt.Sprintf(\"dns=%s\", b64dns),\n\t}\n\n\trequest, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Lock client for usage.\n\thr.clientLock.RLock()\n\tdefer hr.clientLock.RUnlock()\n\n\t// TODO: Check age of client and force a refresh similar to the TCP resolver.\n\n\tresp, err := hr.client.Do(request)\n\tif err != nil {\n\t\t// Hint network environment at failed connection.\n\t\tnetenv.ReportFailedConnection()\n\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\t_ = resp.Body.Close()\n\t}()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"http request failed with %s\", resp.Status)\n\t}\n\n\t// Try to read the result\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treply := new(dns.Msg)\n\n\terr = reply.Unpack(body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Hint network environment at successful connection.\n\tnetenv.ReportSuccessfulConnection()\n\n\t// Report request duration for metrics.\n\treportRequestDuration(queryStarted, hr.resolver)\n\n\tnewRecord := &RRCache{\n\t\tDomain:   q.FQDN,\n\t\tQuestion: q.QType,\n\t\tRCode:    reply.Rcode,\n\t\tAnswer:   reply.Answer,\n\t\tNs:       reply.Ns,\n\t\tExtra:    reply.Extra,\n\t\tResolver: hr.resolver.Info.Copy(),\n\t}\n\n\t// TODO: check if reply.Answer is valid\n\treturn newRecord, nil\n}\n\n// ForceReconnect forces the resolver to re-establish the connection to the server.\nfunc (hr *HTTPSResolver) ForceReconnect(ctx context.Context) {\n\thr.refreshClient()\n\tlog.Tracer(ctx).Tracef(\"resolver: created new HTTP client for %s\", hr.resolver)\n}\n\nfunc (hr *HTTPSResolver) refreshClient() {\n\t// Lock client for changing.\n\thr.clientLock.Lock()\n\tdefer hr.clientLock.Unlock()\n\n\t// Attempt to close connection of previous client.\n\tif hr.client != nil {\n\t\thr.client.CloseIdleConnections()\n\t}\n\n\t// Create new client.\n\ttr := &http.Transport{\n\t\tTLSClientConfig: &tls.Config{\n\t\t\tMinVersion: tls.VersionTLS12,\n\t\t\tServerName: hr.resolver.Info.Domain,\n\t\t\t// TODO: use portbase rng\n\t\t},\n\t\tIdleConnTimeout:     1 * time.Minute,\n\t\tTLSHandshakeTimeout: defaultConnectTimeout,\n\t}\n\thr.client = &http.Client{\n\t\tTransport: tr,\n\t\tTimeout:   maxRequestTimeout,\n\t}\n}\n"
  },
  {
    "path": "service/resolver/resolver-mdns.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\n// DNS Classes.\nconst (\n\tDNSClassMulticast = dns.ClassINET | 1<<15\n)\n\nvar (\n\tmulticast4Conn *net.UDPConn\n\tmulticast6Conn *net.UDPConn\n\tunicast4Conn   *net.UDPConn\n\tunicast6Conn   *net.UDPConn\n\n\tquestions     = make(map[uint16]*savedQuestion)\n\tquestionsLock sync.Mutex\n\n\tmDNSResolver = &Resolver{\n\t\tConfigURL: ServerSourceMDNS,\n\t\tInfo: &ResolverInfo{\n\t\t\tType:    ServerTypeMDNS,\n\t\t\tSource:  ServerSourceMDNS,\n\t\t\tIPScope: netutils.SiteLocal,\n\t\t},\n\t\tConn: &mDNSResolverConn{},\n\t}\n\tmDNSResolvers = []*Resolver{mDNSResolver}\n)\n\ntype mDNSResolverConn struct{}\n\nfunc (mrc *mDNSResolverConn) Query(ctx context.Context, q *Query) (*RRCache, error) {\n\treturn queryMulticastDNS(ctx, q)\n}\n\nfunc (mrc *mDNSResolverConn) ReportFailure() {}\n\nfunc (mrc *mDNSResolverConn) IsFailing() bool {\n\treturn false\n}\n\nfunc (mrc *mDNSResolverConn) ResetFailure() {}\n\nfunc (mrc *mDNSResolverConn) ForceReconnect(_ context.Context) {}\n\ntype savedQuestion struct {\n\tquestion dns.Question\n\texpires  time.Time\n\tresponse chan *RRCache\n}\n\nfunc indexOfRR(entry *dns.RR_Header, list *[]dns.RR) int {\n\tfor k, v := range *list {\n\t\tif entry.Name == v.Header().Name && entry.Rrtype == v.Header().Rrtype {\n\t\t\treturn k\n\t\t}\n\t}\n\treturn -1\n}\n\n//nolint:gocyclo,gocognit // TODO: make simpler\nfunc listenToMDNS(wc *mgr.WorkerCtx) error {\n\tvar err error\n\tmessages := make(chan *dns.Msg, 32)\n\n\t// TODO: init and start every listener in its own service worker\n\t// this will make the more resilient and actually able to restart\n\n\tmulticast4Conn, err = net.ListenMulticastUDP(\"udp4\", nil, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 251), Port: 5353})\n\tif err != nil {\n\t\t// TODO: retry after some time\n\t\tlog.Warningf(\"intel(mdns): failed to create udp4 listen multicast socket: %s\", err)\n\t} else {\n\t\tmodule.mgr.Go(\"mdns udp4 multicast listener\", func(wc *mgr.WorkerCtx) error {\n\t\t\treturn listenForDNSPackets(wc.Ctx(), multicast4Conn, messages)\n\t\t})\n\t\tdefer func() {\n\t\t\t_ = multicast4Conn.Close()\n\t\t}()\n\t}\n\n\tunicast4Conn, err = net.ListenUDP(\"udp4\", &net.UDPAddr{IP: net.IPv4zero, Port: 0})\n\tif err != nil {\n\t\t// TODO: retry after some time\n\t\tlog.Warningf(\"intel(mdns): failed to create udp4 listen socket: %s\", err)\n\t} else {\n\t\tmodule.mgr.Go(\"mdns udp4 unicast listener\", func(wc *mgr.WorkerCtx) error {\n\t\t\treturn listenForDNSPackets(wc.Ctx(), unicast4Conn, messages)\n\t\t})\n\t\tdefer func() {\n\t\t\t_ = unicast4Conn.Close()\n\t\t}()\n\t}\n\n\tif netenv.IPv6Enabled() {\n\t\tmulticast6Conn, err = net.ListenMulticastUDP(\"udp6\", nil, &net.UDPAddr{IP: net.IP([]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb}), Port: 5353})\n\t\tif err != nil {\n\t\t\t// TODO: retry after some time\n\t\t\tlog.Warningf(\"intel(mdns): failed to create udp6 listen multicast socket: %s\", err)\n\t\t} else {\n\t\t\tmodule.mgr.Go(\"mdns udp6 multicast listener\", func(wc *mgr.WorkerCtx) error {\n\t\t\t\treturn listenForDNSPackets(wc.Ctx(), multicast6Conn, messages)\n\t\t\t})\n\t\t\tdefer func() {\n\t\t\t\t_ = multicast6Conn.Close()\n\t\t\t}()\n\t\t}\n\n\t\tunicast6Conn, err = net.ListenUDP(\"udp6\", &net.UDPAddr{IP: net.IPv6zero, Port: 0})\n\t\tif err != nil {\n\t\t\t// TODO: retry after some time\n\t\t\tlog.Warningf(\"intel(mdns): failed to create udp6 listen socket: %s\", err)\n\t\t} else {\n\t\t\tmodule.mgr.Go(\"mdns udp6 unicast listener\", func(wc *mgr.WorkerCtx) error {\n\t\t\t\treturn listenForDNSPackets(wc.Ctx(), unicast6Conn, messages)\n\t\t\t})\n\t\t\tdefer func() {\n\t\t\t\t_ = unicast6Conn.Close()\n\t\t\t}()\n\t\t}\n\t} else {\n\t\tlog.Warningf(\"resolver: no IPv6 stack detected, disabling IPv6 mDNS resolver\")\n\t}\n\n\t// start message handler\n\tmodule.mgr.Go(\"mdns message handler\", func(wc *mgr.WorkerCtx) error {\n\t\treturn handleMDNSMessages(wc.Ctx(), messages)\n\t})\n\n\t// wait for shutdown\n\t<-wc.Done()\n\treturn nil\n}\n\nfunc handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error { //nolint:maintidx // TODO: Improve.\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase message := <-messages:\n\t\t\t// log.Tracef(\"resolver: got net mdns message: %s\", message)\n\n\t\t\tvar err error\n\t\t\tvar question *dns.Question\n\t\t\tvar saveFullRequest bool\n\t\t\tscavengedRecords := make(map[string]dns.RR)\n\t\t\tvar rrCache *RRCache\n\n\t\t\t// save every received response\n\t\t\t// if previous save was less than 2 seconds ago, add to response, else replace\n\t\t\t// pick out A and AAAA records and save separately\n\n\t\t\t// continue if not response\n\t\t\tif !message.Response {\n\t\t\t\t// log.Tracef(\"resolver: mdns message has no response, ignoring\")\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// continue if rcode is not success\n\t\t\tif message.Rcode != dns.RcodeSuccess {\n\t\t\t\t// log.Tracef(\"resolver: mdns message has error, ignoring\")\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// continue if answer section is empty\n\t\t\tif len(message.Answer) == 0 {\n\t\t\t\t// log.Tracef(\"resolver: mdns message has no answers, ignoring\")\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// return saved question\n\t\t\tquestionsLock.Lock()\n\t\t\tsavedQ := questions[message.MsgHdr.Id]\n\t\t\tquestionsLock.Unlock()\n\n\t\t\t// get question, some servers do not reply with question\n\t\t\tif len(message.Question) > 0 {\n\t\t\t\tquestion = &message.Question[0]\n\t\t\t\t// if questions do not match, disregard saved question\n\t\t\t\tif savedQ != nil && message.Question[0].String() != savedQ.question.String() {\n\t\t\t\t\tsavedQ = nil\n\t\t\t\t}\n\t\t\t} else if savedQ != nil {\n\t\t\t\tquestion = &savedQ.question\n\t\t\t}\n\n\t\t\tif question != nil {\n\t\t\t\t// continue if class is not INTERNET\n\t\t\t\tif question.Qclass != dns.ClassINET && question.Qclass != DNSClassMulticast {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// mark request to be saved\n\t\t\t\tsaveFullRequest = true\n\t\t\t}\n\n\t\t\t// get entry from database\n\t\t\tif saveFullRequest {\n\t\t\t\t// get from database\n\t\t\t\trrCache, err = GetRRCache(question.Name, dns.Type(question.Qtype))\n\t\t\t\t// if we have no cached entry, or it has been updated more than two seconds ago, or if it expired:\n\t\t\t\t// create new and do not append\n\t\t\t\tif err != nil || rrCache.Modified < time.Now().Add(-2*time.Second).Unix() || rrCache.Expired() {\n\t\t\t\t\trrCache = &RRCache{\n\t\t\t\t\t\tDomain:   question.Name,\n\t\t\t\t\t\tQuestion: dns.Type(question.Qtype),\n\t\t\t\t\t\tRCode:    dns.RcodeSuccess,\n\t\t\t\t\t\tResolver: mDNSResolver.Info.Copy(),\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// add all entries to RRCache\n\t\t\tfor _, entry := range message.Answer {\n\t\t\t\tif domainInScope(entry.Header().Name, multicastDomains) {\n\t\t\t\t\tif saveFullRequest {\n\t\t\t\t\t\tk := indexOfRR(entry.Header(), &rrCache.Answer)\n\t\t\t\t\t\tif k == -1 {\n\t\t\t\t\t\t\trrCache.Answer = append(rrCache.Answer, entry)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trrCache.Answer[k] = entry\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tswitch entry.(type) {\n\t\t\t\t\tcase *dns.A:\n\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sA\", entry.Header().Name)] = entry\n\t\t\t\t\tcase *dns.AAAA:\n\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sAAAA\", entry.Header().Name)] = entry\n\t\t\t\t\tcase *dns.PTR:\n\t\t\t\t\t\tif !strings.HasPrefix(entry.Header().Name, \"_\") {\n\t\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sPTR\", entry.Header().Name)] = entry\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, entry := range message.Ns {\n\t\t\t\tif domainInScope(entry.Header().Name, multicastDomains) {\n\t\t\t\t\tif saveFullRequest {\n\t\t\t\t\t\tk := indexOfRR(entry.Header(), &rrCache.Ns)\n\t\t\t\t\t\tif k == -1 {\n\t\t\t\t\t\t\trrCache.Ns = append(rrCache.Ns, entry)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trrCache.Ns[k] = entry\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tswitch entry.(type) {\n\t\t\t\t\tcase *dns.A:\n\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sA\", entry.Header().Name)] = entry\n\t\t\t\t\tcase *dns.AAAA:\n\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sAAAA\", entry.Header().Name)] = entry\n\t\t\t\t\tcase *dns.PTR:\n\t\t\t\t\t\tif !strings.HasPrefix(entry.Header().Name, \"_\") {\n\t\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sPTR\", entry.Header().Name)] = entry\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, entry := range message.Extra {\n\t\t\t\tif domainInScope(entry.Header().Name, multicastDomains) {\n\t\t\t\t\tif saveFullRequest {\n\t\t\t\t\t\tk := indexOfRR(entry.Header(), &rrCache.Extra)\n\t\t\t\t\t\tif k == -1 {\n\t\t\t\t\t\t\trrCache.Extra = append(rrCache.Extra, entry)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trrCache.Extra[k] = entry\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tswitch entry.(type) {\n\t\t\t\t\tcase *dns.A:\n\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sA\", entry.Header().Name)] = entry\n\t\t\t\t\tcase *dns.AAAA:\n\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sAAAA\", entry.Header().Name)] = entry\n\t\t\t\t\tcase *dns.PTR:\n\t\t\t\t\t\tif !strings.HasPrefix(entry.Header().Name, \"_\") {\n\t\t\t\t\t\t\tscavengedRecords[fmt.Sprintf(\"%sPTR\", entry.Header().Name)] = entry\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar questionID string\n\t\t\tif saveFullRequest {\n\t\t\t\trrCache.Clean(minMDnsTTL)\n\t\t\t\terr := rrCache.Save()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warningf(\"resolver: failed to cache RR %s: %s\", rrCache.Domain, err)\n\t\t\t\t}\n\n\t\t\t\t// return finished response\n\t\t\t\tif savedQ != nil {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase savedQ.response <- rrCache:\n\t\t\t\t\tdefault:\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tquestionID = fmt.Sprintf(\"%s%s\", question.Name, dns.Type(question.Qtype).String())\n\t\t\t}\n\n\t\t\tfor k, v := range scavengedRecords {\n\t\t\t\tif saveFullRequest && k == questionID {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\trrCache = &RRCache{\n\t\t\t\t\tDomain:   v.Header().Name,\n\t\t\t\t\tQuestion: dns.Type(v.Header().Class),\n\t\t\t\t\tRCode:    dns.RcodeSuccess,\n\t\t\t\t\tAnswer:   []dns.RR{v},\n\t\t\t\t\tResolver: mDNSResolver.Info.Copy(),\n\t\t\t\t}\n\t\t\t\trrCache.Clean(minMDnsTTL)\n\t\t\t\terr := rrCache.Save()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Warningf(\"resolver: failed to cache RR %s: %s\", rrCache.Domain, err)\n\t\t\t\t}\n\t\t\t\t// log.Tracef(\"resolver: mdns scavenged %s\", k)\n\t\t\t}\n\n\t\t}\n\n\t\tcleanSavedQuestions()\n\t}\n}\n\nfunc listenForDNSPackets(ctx context.Context, conn *net.UDPConn, messages chan *dns.Msg) error {\n\tbuf := make([]byte, 65536)\n\tfor {\n\t\tn, err := conn.Read(buf)\n\t\tif err != nil {\n\t\t\tif module.mgr.IsDone() {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tlog.Debugf(\"resolver: failed to read packet: %s\", err)\n\t\t\treturn err\n\t\t}\n\t\tmessage := new(dns.Msg)\n\t\tif err = message.Unpack(buf[:n]); err != nil {\n\t\t\tlog.Debugf(\"resolver: failed to unpack message: %s\", err)\n\t\t\tcontinue\n\t\t}\n\t\tselect {\n\t\tcase messages <- message:\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc queryMulticastDNS(ctx context.Context, q *Query) (*RRCache, error) {\n\t// check for active connections\n\tif unicast4Conn == nil && unicast6Conn == nil {\n\t\treturn nil, errors.New(\"unicast mdns connections not initialized\")\n\t}\n\n\t// trace log\n\tlog.Tracer(ctx).Trace(\"resolver: resolving with mDNS\")\n\n\t// create query\n\tdnsQuery := new(dns.Msg)\n\tdnsQuery.SetQuestion(q.FQDN, uint16(q.QType))\n\t// request unicast response\n\t// q.Question[0].Qclass |= 1 << 15\n\tdnsQuery.RecursionDesired = false\n\n\t// create response channel\n\tresponse := make(chan *RRCache)\n\n\t// save question\n\tquestionsLock.Lock()\n\tdefer questionsLock.Unlock()\n\tquestions[dnsQuery.MsgHdr.Id] = &savedQuestion{\n\t\tquestion: dnsQuery.Question[0],\n\t\texpires:  time.Now().Add(10 * time.Second),\n\t\tresponse: response,\n\t}\n\n\t// pack qeury\n\tbuf, err := dnsQuery.Pack()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to pack query: %w\", err)\n\t}\n\n\t// send queries\n\tif unicast4Conn != nil && uint16(q.QType) != dns.TypeAAAA {\n\t\terr = unicast4Conn.SetWriteDeadline(time.Now().Add(1 * time.Second))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to configure query (set timout): %w\", err)\n\t\t}\n\n\t\t_, err = unicast4Conn.WriteToUDP(buf, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 251), Port: 5353})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to send query: %w\", err)\n\t\t}\n\t}\n\tif unicast6Conn != nil && uint16(q.QType) != dns.TypeA {\n\t\terr = unicast6Conn.SetWriteDeadline(time.Now().Add(1 * time.Second))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to configure query (set timout): %w\", err)\n\t\t}\n\n\t\t_, err = unicast6Conn.WriteToUDP(buf, &net.UDPAddr{IP: net.IP([]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb}), Port: 5353})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to send query: %w\", err)\n\t\t}\n\t}\n\n\t// wait for response or timeout\n\tselect {\n\tcase rrCache := <-response:\n\t\tif rrCache != nil {\n\t\t\treturn rrCache, nil\n\t\t}\n\tcase <-time.After(1 * time.Second):\n\t\t// check cache again\n\t\trrCache, err := GetRRCache(q.FQDN, q.QType)\n\t\tif err == nil {\n\t\t\treturn rrCache, nil\n\t\t}\n\tcase <-ctx.Done():\n\t\treturn nil, ctx.Err()\n\t}\n\n\t// Respond with NXDomain.\n\treturn &RRCache{\n\t\tDomain:   q.FQDN,\n\t\tQuestion: q.QType,\n\t\tRCode:    dns.RcodeNameError,\n\t\tResolver: mDNSResolver.Info.Copy(),\n\t}, nil\n}\n\nfunc cleanSavedQuestions() {\n\tquestionsLock.Lock()\n\tdefer questionsLock.Unlock()\n\tnow := time.Now()\n\tfor msgID, savedQuestion := range questions {\n\t\tif now.After(savedQuestion.expires) {\n\t\t\tdelete(questions, msgID)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/resolver/resolver-plain.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\nvar (\n\tdefaultClientTTL      = 5 * time.Minute\n\tdefaultRequestTimeout = 3 * time.Second // dns query\n\tdefaultConnectTimeout = 5 * time.Second // tcp/tls\n\tmaxRequestTimeout     = 5 * time.Second\n)\n\n// PlainResolver is a resolver using plain DNS.\ntype PlainResolver struct {\n\tBasicResolverConn\n}\n\n// NewPlainResolver returns a new TPCResolver.\nfunc NewPlainResolver(resolver *Resolver) *PlainResolver {\n\tnewResolver := &PlainResolver{\n\t\tBasicResolverConn: BasicResolverConn{\n\t\t\tresolver: resolver,\n\t\t},\n\t}\n\tnewResolver.BasicResolverConn.init()\n\treturn newResolver\n}\n\n// Query executes the given query against the resolver.\nfunc (pr *PlainResolver) Query(ctx context.Context, q *Query) (*RRCache, error) {\n\tqueryStarted := time.Now()\n\n\t// create query\n\tdnsQuery := new(dns.Msg)\n\tdnsQuery.SetQuestion(q.FQDN, uint16(q.QType))\n\n\t// get timeout from context and config\n\tvar timeout time.Duration\n\tif deadline, ok := ctx.Deadline(); !ok {\n\t\ttimeout = 0\n\t} else {\n\t\ttimeout = time.Until(deadline)\n\t}\n\tif timeout > defaultRequestTimeout {\n\t\ttimeout = defaultRequestTimeout\n\t}\n\n\t// create client\n\tdnsClient := &dns.Client{\n\t\tUDPSize: 1024,\n\t\tTimeout: timeout,\n\t\tDialer: &net.Dialer{\n\t\t\tTimeout:   timeout,\n\t\t\tLocalAddr: getLocalAddr(\"udp\"),\n\t\t},\n\t}\n\n\t// query server\n\treply, ttl, err := dnsClient.Exchange(dnsQuery, pr.resolver.ServerAddress)\n\tlog.Tracer(ctx).Tracef(\"resolver: query took %s\", ttl)\n\t// error handling\n\tif err != nil {\n\t\t// Hint network environment at failed connection if err is not a timeout.\n\t\tvar nErr net.Error\n\t\tif errors.As(err, &nErr) && !nErr.Timeout() {\n\t\t\tnetenv.ReportFailedConnection()\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\t// check if blocked\n\tif pr.resolver.IsBlockedUpstream(reply) {\n\t\treturn nil, &BlockedUpstreamError{pr.resolver.Info.DescriptiveName()}\n\t}\n\n\t// Hint network environment at successful connection.\n\tnetenv.ReportSuccessfulConnection()\n\n\t// Report request duration for metrics.\n\treportRequestDuration(queryStarted, pr.resolver)\n\n\tnewRecord := &RRCache{\n\t\tDomain:   q.FQDN,\n\t\tQuestion: q.QType,\n\t\tRCode:    reply.Rcode,\n\t\tAnswer:   reply.Answer,\n\t\tNs:       reply.Ns,\n\t\tExtra:    reply.Extra,\n\t\tResolver: pr.resolver.Info.Copy(),\n\t}\n\n\t// TODO: check if reply.Answer is valid\n\treturn newRecord, nil\n}\n\n// ForceReconnect forces the resolver to re-establish the connection to the server.\n// Does nothing for PlainResolver, as every request uses its own connection.\nfunc (pr *PlainResolver) ForceReconnect(_ context.Context) {}\n"
  },
  {
    "path": "service/resolver/resolver-tcp.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\nconst (\n\ttcpConnectionEstablishmentTimeout = 3 * time.Second\n\ttcpWriteTimeout                   = 2 * time.Second\n\theartbeatTimeout                  = 5 * time.Second\n)\n\n// TCPResolver is a resolver using just a single tcp connection with pipelining.\ntype TCPResolver struct {\n\tBasicResolverConn\n\n\t// dnsClient holds the connection configuration of the resolver.\n\tdnsClient *dns.Client\n\t// resolverConn holds a connection to the DNS server, including query management.\n\tresolverConn *tcpResolverConn\n\t// resolverConnInstanceID holds the current ID of the resolverConn.\n\tresolverConnInstanceID int\n}\n\n// tcpResolverConn represents a single connection to an upstream DNS server.\ntype tcpResolverConn struct {\n\t// ctx is the context of the tcpResolverConn.\n\tctx context.Context\n\t// cancelCtx cancels ctx\n\tcancelCtx context.CancelFunc\n\t// id is the ID assigned to the resolver conn.\n\tid int\n\t// conn is the connection to the DNS server.\n\tconn *dns.Conn\n\t// resolverInfo holds information about the resolver to enhance error messages.\n\tresolverInfo *ResolverInfo\n\t// queries is used to submit queries to be sent to the connected DNS server.\n\tqueries chan *tcpQuery\n\t// responses is used to hand the responses from the reader to the handler.\n\tresponses chan *dns.Msg\n\t// inFlightQueries holds all in-flight queries of this connection.\n\tinFlightQueries map[uint16]*tcpQuery\n\t// heartbeat is a alive-checking channel from which the resolver conn must\n\t// always read asap.\n\theartbeat chan struct{}\n\t// abandoned signifies if the resolver conn has been abandoned.\n\tabandoned *abool.AtomicBool\n}\n\n// tcpQuery holds the query information for a tcpResolverConn.\ntype tcpQuery struct {\n\tQuery    *Query\n\tResponse chan *dns.Msg\n}\n\n// MakeCacheRecord creates an RRCache record from a reply.\nfunc (tq *tcpQuery) MakeCacheRecord(reply *dns.Msg, resolverInfo *ResolverInfo) *RRCache {\n\treturn &RRCache{\n\t\tDomain:   tq.Query.FQDN,\n\t\tQuestion: tq.Query.QType,\n\t\tRCode:    reply.Rcode,\n\t\tAnswer:   reply.Answer,\n\t\tNs:       reply.Ns,\n\t\tExtra:    reply.Extra,\n\t\tResolver: resolverInfo.Copy(),\n\t}\n}\n\n// NewTCPResolver returns a new TPCResolver.\nfunc NewTCPResolver(resolver *Resolver) *TCPResolver {\n\tnewResolver := &TCPResolver{\n\t\tBasicResolverConn: BasicResolverConn{\n\t\t\tresolver: resolver,\n\t\t},\n\t\tdnsClient: &dns.Client{\n\t\t\tNet:          \"tcp\",\n\t\t\tTimeout:      defaultConnectTimeout,\n\t\t\tWriteTimeout: tcpWriteTimeout,\n\t\t},\n\t}\n\tnewResolver.BasicResolverConn.init()\n\treturn newResolver\n}\n\n// UseTLS enabled TLS for the TCPResolver. TLS settings must be correctly configured in the Resolver.\nfunc (tr *TCPResolver) UseTLS() *TCPResolver {\n\ttr.dnsClient.Net = \"tcp-tls\"\n\ttr.dnsClient.TLSConfig = &tls.Config{\n\t\tMinVersion: tls.VersionTLS12,\n\t\tServerName: tr.resolver.Info.Domain,\n\t\t// TODO: use portbase rng\n\t}\n\treturn tr\n}\n\nfunc (tr *TCPResolver) getOrCreateResolverConn(ctx context.Context) (*tcpResolverConn, error) {\n\tvar existingConn *tcpResolverConn\n\n\t// Minimize the time we hold the lock to avoid blocking other threads.\n\ttr.Lock()\n\tif tr.resolverConn != nil && tr.resolverConn.abandoned.IsNotSet() {\n\t\texistingConn = tr.resolverConn\n\t}\n\ttr.Unlock()\n\n\t// Check if we have a resolver.\n\tif existingConn != nil {\n\t\t// If there is one, check if it's alive!\n\t\tselect {\n\t\tcase existingConn.heartbeat <- struct{}{}:\n\t\t\treturn existingConn, nil\n\t\tcase <-time.After(heartbeatTimeout):\n\t\t\tlog.Warningf(\"resolver: heartbeat for dns client %s failed\", tr.resolver.Info.DescriptiveName())\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tcase <-module.mgr.Done():\n\t\t\treturn nil, ErrShuttingDown\n\t\t}\n\t} else {\n\t\t// If there is no resolver, check if we are shutting down before dialing!\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tcase <-module.mgr.Done():\n\t\t\treturn nil, ErrShuttingDown\n\t\tdefault:\n\t\t}\n\t}\n\n\t// Create a new if no active one is available.\n\n\t// Refresh the dialer in order to set an authenticated local address.\n\ttr.dnsClient.Dialer = &net.Dialer{\n\t\tLocalAddr: getLocalAddr(\"tcp\"),\n\t\tTimeout:   tcpConnectionEstablishmentTimeout,\n\t\tKeepAlive: defaultClientTTL,\n\t}\n\n\t// Connect to server.\n\tconn, err := tr.dnsClient.Dial(tr.resolver.ServerAddress)\n\tif err != nil {\n\t\t// Hint network environment at failed connection.\n\t\tnetenv.ReportFailedConnection()\n\n\t\tlog.Debugf(\"resolver: failed to connect to %s: %s\", tr.resolver.Info.DescriptiveName(), err)\n\t\treturn nil, fmt.Errorf(\"%w: failed to connect to %s: %w\", ErrFailure, tr.resolver.Info.DescriptiveName(), err)\n\t}\n\n\t// Hint network environment at successful connection.\n\tnetenv.ReportSuccessfulConnection()\n\n\t// Log that a connection to the resolver was established.\n\tlog.Debugf(\n\t\t\"resolver: connected to %s\",\n\t\ttr.resolver.Info.DescriptiveName(),\n\t)\n\n\t// Thread-safe resolverConn creation.\n\ttr.Lock()\n\tdefer tr.Unlock()\n\n\t// Create resolver connection.\n\ttr.resolverConnInstanceID++\n\tresolverConn := &tcpResolverConn{\n\t\tid:              tr.resolverConnInstanceID,\n\t\tconn:            conn,\n\t\tresolverInfo:    tr.resolver.Info,\n\t\tqueries:         make(chan *tcpQuery, 10),\n\t\tresponses:       make(chan *dns.Msg, 10),\n\t\tinFlightQueries: make(map[uint16]*tcpQuery, 10),\n\t\theartbeat:       make(chan struct{}),\n\t\tabandoned:       abool.New(),\n\t}\n\n\t// Start worker.\n\tmodule.mgr.Go(\"dns client\", resolverConn.handler)\n\n\t// Set resolver conn for reuse.\n\ttr.resolverConn = resolverConn\n\n\treturn resolverConn, nil\n}\n\n// Query executes the given query against the resolver.\nfunc (tr *TCPResolver) Query(ctx context.Context, q *Query) (*RRCache, error) {\n\tqueryStarted := time.Now()\n\n\t// Get resolver connection.\n\tresolverConn, err := tr.getOrCreateResolverConn(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create query request.\n\ttq := &tcpQuery{\n\t\tQuery:    q,\n\t\tResponse: make(chan *dns.Msg),\n\t}\n\n\t// Submit query request to live connection.\n\tselect {\n\tcase resolverConn.queries <- tq:\n\tcase <-ctx.Done():\n\t\treturn nil, ctx.Err()\n\tcase <-module.mgr.Done():\n\t\treturn nil, ErrShuttingDown\n\tcase <-time.After(defaultRequestTimeout):\n\t\treturn nil, ErrTimeout\n\t}\n\n\t// Wait for reply.\n\tvar reply *dns.Msg\n\tselect {\n\tcase reply = <-tq.Response:\n\tcase <-ctx.Done():\n\t\treturn nil, ctx.Err()\n\tcase <-module.mgr.Done():\n\t\treturn nil, ErrShuttingDown\n\tcase <-time.After(defaultRequestTimeout):\n\t\treturn nil, ErrTimeout\n\t}\n\n\t// Check if we have a reply.\n\tif reply == nil {\n\t\t// Resolver is shutting down. The Portmaster may be shutting down, or\n\t\t// there is a connection error.\n\t\treturn nil, ErrFailure\n\t}\n\n\t// Check if the reply was blocked upstream.\n\tif tr.resolver.IsBlockedUpstream(reply) {\n\t\treturn nil, &BlockedUpstreamError{tr.resolver.Info.DescriptiveName()}\n\t}\n\n\t// Report request duration for metrics.\n\treportRequestDuration(queryStarted, tr.resolver)\n\n\t// Create RRCache from reply and return it.\n\treturn tq.MakeCacheRecord(reply, tr.resolver.Info), nil\n}\n\n// ForceReconnect forces the resolver to re-establish the connection to the server.\nfunc (tr *TCPResolver) ForceReconnect(ctx context.Context) {\n\ttr.Lock()\n\tdefer tr.Unlock()\n\n\t// Do nothing if no connection is available.\n\tif tr.resolverConn == nil {\n\t\treturn\n\t}\n\n\t// Set the abandoned to force a new connection on next request.\n\t// This will leave the previous connection and handler running until all requests are handled.\n\ttr.resolverConn.abandoned.Set()\n\n\tlog.Tracer(ctx).Tracef(\"resolver: marked %s for reconnecting\", tr.resolver)\n}\n\n// shutdown cleanly shuts down the resolver connection.\n// Must only be called once.\nfunc (trc *tcpResolverConn) shutdown() {\n\t// Set abandoned status and close connection to the DNS server.\n\ttrc.abandoned.Set()\n\t_ = trc.conn.Close()\n\n\t// Close all response channels for in-flight queries.\n\tfor _, tq := range trc.inFlightQueries {\n\t\tclose(tq.Response)\n\t}\n\n\t// Respond to any incoming queries for some time in order to not leave them\n\t// hanging longer than necessary.\n\tfor {\n\t\tselect {\n\t\tcase tq := <-trc.queries:\n\t\t\tclose(tq.Response)\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (trc *tcpResolverConn) handler(workerCtx *mgr.WorkerCtx) error {\n\t// Set up context and cleanup.\n\ttrc.ctx, trc.cancelCtx = context.WithCancel(workerCtx.Ctx())\n\tdefer trc.shutdown()\n\n\t// Set up variables.\n\tvar readyToRecycle bool\n\tttlTimer := time.After(defaultClientTTL)\n\n\t// Start connection reader.\n\tmodule.mgr.Go(\"dns client reader\", trc.reader)\n\n\t// Handle requests.\n\tfor {\n\t\tselect {\n\t\tcase <-trc.heartbeat:\n\t\t\t// Respond to alive checks.\n\n\t\tcase <-trc.ctx.Done():\n\t\t\t// Respond to module shutdown or conn error.\n\t\t\treturn nil\n\n\t\tcase <-ttlTimer:\n\t\t\t// Recycle the connection after the TTL is reached.\n\t\t\treadyToRecycle = true\n\t\t\t// Send dummy response to trigger the check.\n\t\t\tselect {\n\t\t\tcase trc.responses <- nil:\n\t\t\tdefault:\n\t\t\t\t// The response queue is full.\n\t\t\t\t// The check will be triggered by another response.\n\t\t\t}\n\n\t\tcase tq := <-trc.queries:\n\t\t\t// Handle DNS query request.\n\n\t\t\t// Create dns request message.\n\t\t\tmsg := &dns.Msg{}\n\t\t\tmsg.SetQuestion(tq.Query.FQDN, uint16(tq.Query.QType))\n\n\t\t\t// Assign a unique message ID.\n\t\t\ttrc.assignUniqueID(msg)\n\n\t\t\t// Add query to in flight registry.\n\t\t\ttrc.inFlightQueries[msg.Id] = tq\n\n\t\t\t// Write query to connected DNS server.\n\t\t\t_ = trc.conn.SetWriteDeadline(time.Now().Add(tcpWriteTimeout))\n\t\t\terr := trc.conn.WriteMsg(msg)\n\t\t\tif err != nil {\n\t\t\t\ttrc.logConnectionError(err, false)\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\tcase msg := <-trc.responses:\n\t\t\tif msg != nil {\n\t\t\t\ttrc.handleQueryResponse(msg)\n\t\t\t}\n\n\t\t\t// If we are ready to recycle and we have no in-flight queries, we can\n\t\t\t// shutdown the connection and create a new one for the next query.\n\t\t\tif readyToRecycle || trc.abandoned.IsSet() {\n\t\t\t\tif len(trc.inFlightQueries) == 0 {\n\t\t\t\t\tlog.Debugf(\"resolver: recycling connection to %s\", trc.resolverInfo.DescriptiveName())\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n}\n\n// assignUniqueID makes sure that ID assigned to msg is unique.\nfunc (trc *tcpResolverConn) assignUniqueID(msg *dns.Msg) {\n\t// try a random ID 10000 times\n\tfor range 10000 { // don't try forever\n\t\t_, exists := trc.inFlightQueries[msg.Id]\n\t\tif !exists {\n\t\t\treturn // we are unique, yay!\n\t\t}\n\t\tmsg.Id = dns.Id() // regenerate ID\n\t}\n\t// go through the complete space\n\tvar id uint16\n\tfor ; id <= (1<<16)-1; id++ { // don't try forever\n\t\t_, exists := trc.inFlightQueries[id]\n\t\tif !exists {\n\t\t\tmsg.Id = id\n\t\t\treturn // we are unique, yay!\n\t\t}\n\t}\n}\n\nfunc (trc *tcpResolverConn) handleQueryResponse(msg *dns.Msg) {\n\t// Get in flight from registry.\n\ttq, ok := trc.inFlightQueries[msg.Id]\n\tif ok {\n\t\tdelete(trc.inFlightQueries, msg.Id)\n\t} else {\n\t\tlog.Debugf(\n\t\t\t\"resolver: received possibly unsolicited reply from %s: txid=%d q=%+v\",\n\t\t\ttrc.resolverInfo.DescriptiveName(),\n\t\t\tmsg.Id,\n\t\t\tmsg.Question,\n\t\t)\n\t\treturn\n\t}\n\n\t// Send response to waiting query handler.\n\tselect {\n\tcase tq.Response <- msg:\n\t\treturn\n\tdefault:\n\t\t// No one is listening for that response.\n\t}\n\n\t// If caching is disabled for this query, we are done.\n\tif tq.Query.NoCaching {\n\t\treturn\n\t}\n\n\t// Otherwise, we can persist the answer in case the request is repeated.\n\trrCache := tq.MakeCacheRecord(msg, trc.resolverInfo)\n\trrCache.Clean(minTTL)\n\terr := rrCache.Save()\n\tif err != nil {\n\t\tlog.Warningf(\n\t\t\t\"resolver: failed to cache RR for %s: %s\",\n\t\t\ttq.Query.ID(),\n\t\t\terr,\n\t\t)\n\t}\n}\n\nfunc (trc *tcpResolverConn) reader(workerCtx *mgr.WorkerCtx) error {\n\tdefer trc.cancelCtx()\n\n\tfor {\n\t\tmsg, err := trc.conn.ReadMsg()\n\t\tif err != nil {\n\t\t\ttrc.logConnectionError(err, true)\n\t\t\treturn nil\n\t\t}\n\t\ttrc.responses <- msg\n\t}\n}\n\nfunc (trc *tcpResolverConn) logConnectionError(err error, reading bool) {\n\t// Check if we are the first to see an error.\n\tif trc.abandoned.SetToIf(false, true) {\n\t\t// Log error.\n\t\tswitch {\n\t\tcase errors.Is(err, io.EOF):\n\t\t\tlog.Debugf(\n\t\t\t\t\"resolver: connection to %s was closed\",\n\t\t\t\ttrc.resolverInfo.DescriptiveName(),\n\t\t\t)\n\t\tcase reading:\n\t\t\tlog.Warningf(\n\t\t\t\t\"resolver: read error from %s: %s\",\n\t\t\t\ttrc.resolverInfo.DescriptiveName(),\n\t\t\t\terr,\n\t\t\t)\n\t\tdefault:\n\t\t\tlog.Warningf(\n\t\t\t\t\"resolver: write error to %s: %s\",\n\t\t\t\ttrc.resolverInfo.DescriptiveName(),\n\t\t\t\terr,\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/resolver/resolver.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\n// DNS Resolver Attributes.\nconst (\n\tServerTypeDNS      = \"dns\"\n\tServerTypeTCP      = \"tcp\"\n\tServerTypeDoT      = \"dot\"\n\tServerTypeDoH      = \"doh\"\n\tServerTypeMDNS     = \"mdns\"\n\tServerTypeEnv      = \"env\"\n\tServerTypeMonitor  = \"monitor\"\n\tServerTypeFirewall = \"firewall\"\n\n\tServerSourceConfigured      = \"config\"\n\tServerSourceOperatingSystem = \"system\"\n\tServerSourceMDNS            = \"mdns\"\n\tServerSourceEnv             = \"env\"\n\tServerSourceETW             = \"etw\"\n\tServerSourceSystemd         = \"systemd\"\n\tServerSourceFirewall        = \"firewall\"\n)\n\n// DNS resolver scheme aliases.\nconst (\n\tHTTPSProtocol = \"https\"\n\tTLSProtocol   = \"tls\"\n)\n\n// Resolver holds information about an active resolver.\ntype Resolver struct {\n\t// Server config url (and ID)\n\t// Supported parameters:\n\t// - `verify=domain`: verify domain (dot only)\n\t// - `name=name`: human readable name for resolver\n\t// - `blockedif=empty`: how to detect if the dns service blocked something\n\t//\t- `empty`: NXDomain result, but without any other record in any section\n\t//  - `refused`: Request was refused\n\t//\t- `zeroip`: Answer only contains zeroip\n\tConfigURL string\n\n\t// Info holds the parsed configuration.\n\tInfo *ResolverInfo\n\n\t// ServerAddress holds the resolver address for easier use.\n\tServerAddress string\n\n\t// UpstreamBlockDetection defines the detection type\n\t// to identifier upstream DNS query blocking.\n\t// Valid values are:\n\t//\t - zeroip\n\t//\t - empty\n\t//   - refused (default)\n\t//\t - disabled\n\tUpstreamBlockDetection string\n\n\t// Special Options\n\tSearch     []string\n\tSearchOnly bool\n\tPath       string\n\t// Special States\n\tLinkLocalUnavailable bool\n\n\t// logic interface\n\tConn ResolverConn `json:\"-\"`\n}\n\n// ResolverInfo is a subset of resolver attributes that is attached to answers\n// from that server in order to use it later for decision making. It must not\n// be changed by anyone after creation and initialization is complete.\ntype ResolverInfo struct { //nolint:golint,maligned // TODO\n\t// Name describes the name given to the resolver. The name is configured in the config URL using the name parameter.\n\tName string\n\n\t// Type describes the type of the resolver.\n\t// Possible values include dns, tcp, dot, doh, mdns, env, monitor, firewall.\n\tType string\n\n\t// Source describes where the resolver configuration came from.\n\t// Possible values include config, system, mdns, env, etw, systemd, firewall.\n\tSource string\n\n\t// IP is the IP address of the resolver\n\tIP net.IP\n\n\t// Domain of the dns server if it has one\n\tDomain string\n\n\t// IPScope is the network scope of the IP address.\n\tIPScope netutils.IPScope\n\n\t// Port is the udp/tcp port of the resolver.\n\tPort uint16\n\n\t// id holds a unique ID for this resolver.\n\tid    string\n\tidGen sync.Once\n}\n\n// ID returns the unique ID of the resolver.\nfunc (info *ResolverInfo) ID() string {\n\t// Generate the ID the first time.\n\tinfo.idGen.Do(func() {\n\t\tswitch info.Type {\n\t\tcase ServerTypeMDNS:\n\t\t\tinfo.id = ServerTypeMDNS\n\t\tcase ServerTypeEnv:\n\t\t\tinfo.id = ServerTypeEnv\n\t\tcase ServerTypeDoH:\n\t\t\tinfo.id = fmt.Sprintf( //nolint:nosprintfhostport // Not used as URL.\n\t\t\t\t\"https://%s:%d#%s\",\n\t\t\t\tinfo.Domain,\n\t\t\t\tinfo.Port,\n\t\t\t\tinfo.Source,\n\t\t\t)\n\t\tcase ServerTypeDoT:\n\t\t\tinfo.id = fmt.Sprintf( //nolint:nosprintfhostport // Not used as URL.\n\t\t\t\t\"dot://%s:%d#%s\",\n\t\t\t\tinfo.Domain,\n\t\t\t\tinfo.Port,\n\t\t\t\tinfo.Source,\n\t\t\t)\n\t\tdefault:\n\t\t\tinfo.id = fmt.Sprintf(\n\t\t\t\t\"%s://%s:%d#%s\",\n\t\t\t\tinfo.Type,\n\t\t\t\tinfo.IP,\n\t\t\t\tinfo.Port,\n\t\t\t\tinfo.Source,\n\t\t\t)\n\t\t}\n\t})\n\n\treturn info.id\n}\n\n// DescriptiveName returns a human readable, but also detailed representation\n// of the resolver.\nfunc (info *ResolverInfo) DescriptiveName() string {\n\tswitch {\n\tcase info.Type == ServerTypeMDNS:\n\t\treturn \"MDNS\"\n\tcase info.Type == ServerTypeEnv:\n\t\treturn \"Portmaster Environment\"\n\tcase info.Name != \"\":\n\t\treturn fmt.Sprintf(\n\t\t\t\"%s (%s)\",\n\t\t\tinfo.Name,\n\t\t\tinfo.ID(),\n\t\t)\n\tcase info.Domain != \"\":\n\t\treturn fmt.Sprintf(\n\t\t\t\"%s (%s)\",\n\t\t\tinfo.Domain,\n\t\t\tinfo.ID(),\n\t\t)\n\tdefault:\n\t\treturn fmt.Sprintf(\n\t\t\t\"%s (%s)\",\n\t\t\tinfo.IP.String(),\n\t\t\tinfo.ID(),\n\t\t)\n\t}\n}\n\n// Copy returns a full copy of the ResolverInfo.\nfunc (info *ResolverInfo) Copy() *ResolverInfo {\n\t// Force idGen to run before we copy.\n\t_ = info.ID()\n\n\t// Copy manually in order to not copy the mutex.\n\tcp := &ResolverInfo{\n\t\tName:    info.Name,\n\t\tType:    info.Type,\n\t\tSource:  info.Source,\n\t\tIP:      info.IP,\n\t\tDomain:  info.Domain,\n\t\tIPScope: info.IPScope,\n\t\tPort:    info.Port,\n\t\tid:      info.id,\n\t}\n\t// Trigger idGen.Do(), as the ID is already generated.\n\tcp.idGen.Do(func() {})\n\n\treturn cp\n}\n\n// IsBlockedUpstream returns true if the request has been blocked\n// upstream.\nfunc (resolver *Resolver) IsBlockedUpstream(answer *dns.Msg) bool {\n\treturn isBlockedUpstream(resolver, answer)\n}\n\n// String returns the URL representation of the resolver.\nfunc (resolver *Resolver) String() string {\n\treturn resolver.Info.DescriptiveName()\n}\n\n// ResolverConn is an interface to implement different types of query backends.\ntype ResolverConn interface { //nolint:golint // TODO\n\tQuery(ctx context.Context, q *Query) (*RRCache, error)\n\tReportFailure()\n\tIsFailing() bool\n\tResetFailure()\n\tForceReconnect(ctx context.Context)\n}\n\n// BasicResolverConn implements ResolverConn for standard dns clients.\ntype BasicResolverConn struct {\n\tsync.Mutex // Also used by inheriting structs.\n\n\tresolver *Resolver\n\n\tfailing        *abool.AtomicBool\n\tfailingStarted time.Time\n\tfails          int\n\tfailLock       sync.Mutex\n\n\tnetworkChangedFlag *utils.Flag\n}\n\n// init initializes the basic resolver connection.\nfunc (brc *BasicResolverConn) init() {\n\tbrc.failing = abool.New()\n\tbrc.networkChangedFlag = netenv.GetNetworkChangedFlag()\n}\n"
  },
  {
    "path": "service/resolver/resolver_test.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\ttestResolver         string\n\tsilencingTraceCtx, _ = log.AddTracer(context.Background())\n)\n\nfunc init() {\n\tflag.StringVar(\n\t\t&testResolver,\n\t\t\"resolver\",\n\t\t\"dot://1.1.1.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip\",\n\t\t\"set custom resolver for testing\",\n\t)\n}\n\nfunc startQuery(t *testing.T, wg *sync.WaitGroup, rc ResolverConn, q *Query) {\n\tt.Helper()\n\n\tstart := time.Now()\n\t_, err := rc.Query(silencingTraceCtx, q)\n\tif err != nil {\n\t\tt.Logf(\"client failed: %s\", err)\n\t\twg.Done()\n\t\treturn\n\t}\n\tt.Logf(\"resolved %s in %s\", q.FQDN, time.Since(start))\n\twg.Done()\n}\n\nfunc TestSingleResolving(t *testing.T) {\n\tt.Parallel()\n\n\t// skip if short - this test depends on the Internet and might fail randomly\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\tdefaultRequestTimeout = 30 * time.Second\n\n\t// create separate resolver for this test\n\tresolver, _, err := createResolver(testResolver, \"config\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"running bulk query test with resolver %s\", resolver.Info.DescriptiveName())\n\n\tstarted := time.Now()\n\n\twg := &sync.WaitGroup{}\n\twg.Add(100)\n\tfor range 100 {\n\t\tstartQuery(t, wg, resolver.Conn, &Query{\n\t\t\tFQDN:  <-domainFeed,\n\t\t\tQType: dns.Type(dns.TypeA),\n\t\t})\n\t}\n\twg.Wait()\n\n\tt.Logf(\"total time taken: %s\", time.Since(started))\n}\n\nfunc TestBulkResolving(t *testing.T) {\n\tt.Parallel()\n\n\t// skip if short - this test depends on the Internet and might fail randomly\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\tdefaultRequestTimeout = 30 * time.Second\n\n\t// create separate resolver for this test\n\tresolver, _, err := createResolver(testResolver, \"config\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"running bulk query test with resolver %s\", resolver.Info.DescriptiveName())\n\n\tstarted := time.Now()\n\n\twg := &sync.WaitGroup{}\n\twg.Add(100)\n\tfor range 100 {\n\t\tgo startQuery(t, wg, resolver.Conn, &Query{\n\t\t\tFQDN:  <-domainFeed,\n\t\t\tQType: dns.Type(dns.TypeA),\n\t\t})\n\t}\n\twg.Wait()\n\n\tt.Logf(\"total time taken: %s\", time.Since(started))\n}\n\nfunc TestPublicSuffix(t *testing.T) {\n\tt.Parallel()\n\n\ttestSuffix(t, \"co.uk.\", \"\", true)\n\ttestSuffix(t, \"amazon.co.uk.\", \"amazon.co.uk.\", true)\n\ttestSuffix(t, \"books.amazon.co.uk.\", \"amazon.co.uk.\", true)\n\ttestSuffix(t, \"www.books.amazon.co.uk.\", \"amazon.co.uk.\", true)\n\ttestSuffix(t, \"com.\", \"\", true)\n\ttestSuffix(t, \"amazon.com.\", \"amazon.com.\", true)\n\ttestSuffix(t, \"example0.debian.net.\", \"example0.debian.net.\", true)\n\ttestSuffix(t, \"example1.debian.org.\", \"debian.org.\", true)\n\ttestSuffix(t, \"golang.dev.\", \"golang.dev.\", true)\n\ttestSuffix(t, \"golang.net.\", \"golang.net.\", true)\n\ttestSuffix(t, \"play.golang.org.\", \"golang.org.\", true)\n\ttestSuffix(t, \"gophers.in.space.museum.\", \"space.museum.\", true)\n\ttestSuffix(t, \"0emm.com.\", \"0emm.com.\", true)\n\ttestSuffix(t, \"a.0emm.com.\", \"\", true)\n\ttestSuffix(t, \"b.c.d.0emm.com.\", \"c.d.0emm.com.\", true)\n\ttestSuffix(t, \"org.\", \"\", true)\n\ttestSuffix(t, \"foo.org.\", \"foo.org.\", true)\n\ttestSuffix(t, \"foo.co.uk.\", \"foo.co.uk.\", true)\n\ttestSuffix(t, \"foo.dyndns.org.\", \"foo.dyndns.org.\", true)\n\ttestSuffix(t, \"foo.blogspot.co.uk.\", \"foo.blogspot.co.uk.\", true)\n\ttestSuffix(t, \"there.is.no.such-tld.\", \"no.such-tld.\", false)\n\ttestSuffix(t, \"www.some.bit.\", \"some.bit.\", false)\n\ttestSuffix(t, \"cromulent.\", \"\", false)\n\ttestSuffix(t, \"arpa.\", \"\", true)\n\ttestSuffix(t, \"in-addr.arpa.\", \"\", true)\n\ttestSuffix(t, \"1.in-addr.arpa.\", \"1.in-addr.arpa.\", true)\n\ttestSuffix(t, \"ip6.arpa.\", \"\", true)\n\ttestSuffix(t, \"1.ip6.arpa.\", \"1.ip6.arpa.\", true)\n\ttestSuffix(t, \"www.some.arpa.\", \"some.arpa.\", true)\n\ttestSuffix(t, \"www.some.home.arpa.\", \"home.arpa.\", true)\n\ttestSuffix(t, \".\", \"\", false)\n\ttestSuffix(t, \"\", \"\", false)\n\n\t// Test edge case domains.\n\ttestSuffix(t, \"www.some.example.\", \"some.example.\", true)\n\ttestSuffix(t, \"www.some.invalid.\", \"some.invalid.\", true)\n\ttestSuffix(t, \"www.some.local.\", \"some.local.\", true)\n\ttestSuffix(t, \"www.some.localhost.\", \"some.localhost.\", true)\n\ttestSuffix(t, \"www.some.onion.\", \"some.onion.\", false)\n\ttestSuffix(t, \"www.some.test.\", \"some.test.\", true)\n}\n\nfunc testSuffix(t *testing.T, fqdn, domainRoot string, icannSpace bool) {\n\tt.Helper()\n\n\tq := &Query{FQDN: fqdn}\n\tq.InitPublicSuffixData()\n\tassert.Equal(t, domainRoot, q.DomainRoot)\n\tassert.Equal(t, icannSpace, q.ICANNSpace)\n}\n"
  },
  {
    "path": "service/resolver/resolvers.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/miekg/dns\"\n\t\"golang.org/x/net/publicsuffix\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\nconst maxSearchDomains = 100\n\n// Scope defines a domain scope and which resolvers can resolve it.\ntype Scope struct {\n\tDomain    string\n\tResolvers []*Resolver\n}\n\nconst (\n\tparameterName       = \"name\"\n\tparameterVerify     = \"verify\"\n\tparameterIP         = \"ip\"\n\tparameterBlockedIf  = \"blockedif\"\n\tparameterSearch     = \"search\"\n\tparameterSearchOnly = \"search-only\"\n\tparameterLinkLocal  = \"link-local\"\n)\n\nvar (\n\tglobalResolvers       []*Resolver          // all (global) resolvers\n\tlocalResolvers        []*Resolver          // all resolvers that are in site-local or link-local IP ranges\n\tsystemResolvers       []*Resolver          // all resolvers that were assigned by the system\n\tlocalScopes           []*Scope             // list of scopes with a list of local resolvers that can resolve the scope\n\tactiveResolvers       map[string]*Resolver // lookup map of all resolvers\n\tcurrentResolverConfig []string             // current active resolver config, to detect changes\n\tresolverInitDomains   map[string]struct{}  // a set with all domains of the dns resolvers\n\n\tresolversLock sync.RWMutex\n)\n\nfunc indexOfScope(domain string, list []*Scope) int {\n\tfor k, v := range list {\n\t\tif v.Domain == domain {\n\t\t\treturn k\n\t\t}\n\t}\n\treturn -1\n}\n\nfunc getActiveResolverByIDWithLocking(server string) *Resolver {\n\tresolversLock.RLock()\n\tdefer resolversLock.RUnlock()\n\n\tresolver, ok := activeResolvers[server]\n\tif ok {\n\t\treturn resolver\n\t}\n\treturn nil\n}\n\nfunc formatIPAndPort(ip net.IP, port uint16) string {\n\tvar address string\n\tif ipv4 := ip.To4(); ipv4 != nil {\n\t\taddress = fmt.Sprintf(\"%s:%d\", ipv4.String(), port)\n\t} else {\n\t\taddress = fmt.Sprintf(\"[%s]:%d\", ip.String(), port)\n\t}\n\treturn address\n}\n\nfunc resolverConnFactory(resolver *Resolver) ResolverConn {\n\tswitch resolver.Info.Type {\n\tcase ServerTypeTCP:\n\t\treturn NewTCPResolver(resolver)\n\tcase ServerTypeDoT:\n\t\treturn NewTCPResolver(resolver).UseTLS()\n\tcase ServerTypeDoH:\n\t\treturn NewHTTPSResolver(resolver)\n\tcase ServerTypeDNS:\n\t\treturn NewPlainResolver(resolver)\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc createResolver(resolverURL, source string) (*Resolver, bool, error) {\n\tu, err := url.Parse(resolverURL)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\n\tif resolverInitDomains == nil {\n\t\tresolverInitDomains = make(map[string]struct{})\n\t}\n\n\tswitch u.Scheme {\n\tcase ServerTypeDNS, ServerTypeDoT, ServerTypeDoH, ServerTypeTCP:\n\tcase HTTPSProtocol:\n\t\tu.Scheme = ServerTypeDoH\n\tcase TLSProtocol:\n\t\tu.Scheme = ServerTypeDoT\n\tdefault:\n\t\treturn nil, false, fmt.Errorf(\"DNS resolver scheme %q invalid\", u.Scheme)\n\t}\n\n\tquery := u.Query()\n\n\t// Create Resolver object\n\tnewResolver := &Resolver{\n\t\tConfigURL: resolverURL,\n\t\tInfo: &ResolverInfo{\n\t\t\tName:    query.Get(parameterName),\n\t\t\tType:    u.Scheme,\n\t\t\tSource:  source,\n\t\t\tIP:      nil,\n\t\t\tDomain:  \"\",\n\t\t\tIPScope: netutils.Global,\n\t\t\tPort:    0,\n\t\t},\n\t\tServerAddress:          \"\",\n\t\tPath:                   u.Path, // Used for DoH\n\t\tUpstreamBlockDetection: \"\",\n\t}\n\n\t// Get parameters and check if keys exist.\n\terr = checkAndSetResolverParamters(u, newResolver)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\n\t// Check block detection type.\n\tnewResolver.UpstreamBlockDetection = query.Get(parameterBlockedIf)\n\tif newResolver.UpstreamBlockDetection == \"\" {\n\t\tnewResolver.UpstreamBlockDetection = BlockDetectionZeroIP\n\t}\n\n\tswitch newResolver.UpstreamBlockDetection {\n\tcase BlockDetectionDisabled, BlockDetectionEmptyAnswer, BlockDetectionRefused, BlockDetectionZeroIP:\n\tdefault:\n\t\treturn nil, false, fmt.Errorf(\"invalid value for upstream block detection (blockedif=)\")\n\t}\n\n\t// Get ip scope if we have ip\n\tif newResolver.Info.IP != nil {\n\t\tnewResolver.Info.IPScope = netutils.GetIPScope(newResolver.Info.IP)\n\t\t// Skip localhost resolvers from the OS, but not if configured.\n\t\tif newResolver.Info.IPScope.IsLocalhost() && source == ServerSourceOperatingSystem {\n\t\t\treturn nil, true, nil // skip\n\t\t}\n\t}\n\n\t// Parse search domains.\n\tsearchDomains := query.Get(parameterSearch)\n\tif searchDomains != \"\" {\n\t\terr = configureSearchDomains(newResolver, strings.Split(searchDomains, \",\"), true)\n\t\tif err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\t}\n\n\t// Check if searchOnly is set and valid.\n\tif query.Has(parameterSearchOnly) {\n\t\tnewResolver.SearchOnly = true\n\t\tif query.Get(parameterSearchOnly) != \"\" {\n\t\t\treturn nil, false, fmt.Errorf(\"%s may only be used as an empty parameter\", parameterSearchOnly)\n\t\t}\n\t\tif len(newResolver.Search) == 0 {\n\t\t\treturn nil, false, fmt.Errorf(\"cannot use %s without search scopes\", parameterSearchOnly)\n\t\t}\n\t}\n\n\t// Check if this is a link-local resolver.\n\tif query.Has(parameterLinkLocal) {\n\t\tif query.Get(parameterLinkLocal) != \"\" {\n\t\t\treturn nil, false, fmt.Errorf(\"%s may only be used as an empty parameter\", parameterLinkLocal)\n\t\t}\n\t\t// Check if resolver IP is link-local.\n\t\tresolverNet, err := netenv.GetLocalNetwork(newResolver.Info.IP)\n\t\tswitch {\n\t\tcase err != nil:\n\t\t\tnewResolver.LinkLocalUnavailable = true\n\t\tcase resolverNet == nil:\n\t\t\tnewResolver.LinkLocalUnavailable = true\n\t\t}\n\t}\n\n\tnewResolver.Conn = resolverConnFactory(newResolver)\n\treturn newResolver, false, nil\n}\n\nfunc checkAndSetResolverParamters(u *url.URL, resolver *Resolver) error {\n\t// Check if we are using domain name and if it's in a valid scheme\n\tip := net.ParseIP(u.Hostname())\n\thostnameIsDomaion := (ip == nil)\n\tif ip == nil && u.Scheme != ServerTypeDoH && u.Scheme != ServerTypeDoT {\n\t\treturn fmt.Errorf(\"resolver IP %q is invalid\", u.Hostname())\n\t}\n\n\t// Add default port for scheme if it is missing.\n\tport, err := parsePortFromURL(u)\n\tif err != nil {\n\t\treturn err\n\t}\n\tresolver.Info.Port = port\n\tresolver.Info.IP = ip\n\n\tquery := u.Query()\n\n\tfor key := range query {\n\t\tswitch key {\n\t\tcase parameterName,\n\t\t\tparameterVerify,\n\t\t\tparameterIP,\n\t\t\tparameterBlockedIf,\n\t\t\tparameterSearch,\n\t\t\tparameterSearchOnly,\n\t\t\tparameterLinkLocal:\n\t\t\t// Known key, continue.\n\t\tdefault:\n\t\t\t// Unknown key, abort.\n\t\t\treturn fmt.Errorf(`unknown parameter \"%q\"`, key)\n\t\t}\n\t}\n\n\tresolver.Info.Domain = query.Get(parameterVerify)\n\tparamterServerIP := query.Get(parameterIP)\n\n\tif u.Scheme == ServerTypeDoT || u.Scheme == ServerTypeDoH {\n\t\t// Check if IP and Domain are set correctly\n\t\tswitch {\n\t\tcase hostnameIsDomaion && resolver.Info.Domain != \"\":\n\t\t\treturn fmt.Errorf(\"cannot set the domain name via both the hostname in the URL and the verify parameter\")\n\t\tcase !hostnameIsDomaion && resolver.Info.Domain == \"\":\n\t\t\treturn fmt.Errorf(\"verify parameter must be set when using ip as domain\")\n\t\tcase !hostnameIsDomaion && paramterServerIP != \"\":\n\t\t\treturn fmt.Errorf(\"cannot set the IP address via both the hostname in the URL and the ip parameter\")\n\t\t}\n\n\t\t// Parse and set IP and Domain to the resolver\n\t\tswitch {\n\t\tcase hostnameIsDomaion && paramterServerIP != \"\": // domain and ip as parameter\n\t\t\tresolver.Info.IP = net.ParseIP(paramterServerIP)\n\t\t\tresolver.ServerAddress = net.JoinHostPort(paramterServerIP, strconv.Itoa(int(resolver.Info.Port)))\n\t\t\tresolver.Info.Domain = u.Hostname()\n\t\tcase !hostnameIsDomaion && resolver.Info.Domain != \"\": // ip and domain as parameter\n\t\t\tresolver.ServerAddress = net.JoinHostPort(ip.String(), strconv.Itoa(int(resolver.Info.Port)))\n\t\tcase hostnameIsDomaion && resolver.Info.Domain == \"\" && paramterServerIP == \"\": // only domain\n\t\t\tresolver.Info.Domain = u.Hostname()\n\t\t\tresolver.ServerAddress = net.JoinHostPort(resolver.Info.Domain, strconv.Itoa(int(port)))\n\t\t}\n\n\t\tif ip == nil {\n\t\t\tresolverInitDomains[dns.Fqdn(resolver.Info.Domain)] = struct{}{}\n\t\t}\n\n\t} else {\n\t\tif resolver.Info.Domain != \"\" {\n\t\t\treturn fmt.Errorf(\"domain verification is only supported by DoT and DoH servers\")\n\t\t}\n\t\tresolver.ServerAddress = net.JoinHostPort(ip.String(), strconv.Itoa(int(resolver.Info.Port)))\n\t}\n\n\treturn nil\n}\n\nfunc parsePortFromURL(url *url.URL) (uint16, error) {\n\tvar port uint16\n\thostPort := url.Port()\n\tif hostPort != \"\" {\n\t\t// There is a port in the url\n\t\tparsedPort, err := strconv.ParseUint(hostPort, 10, 16)\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"invalid port %q\", url.Port())\n\t\t}\n\t\tport = uint16(parsedPort)\n\t} else {\n\t\t// set the default port for the protocol\n\t\tswitch {\n\t\tcase url.Scheme == ServerTypeDNS, url.Scheme == ServerTypeTCP:\n\t\t\tport = 53\n\t\tcase url.Scheme == ServerTypeDoH:\n\t\t\tport = 443\n\t\tcase url.Scheme == ServerTypeDoT:\n\t\t\tport = 853\n\t\tdefault:\n\t\t\treturn 0, fmt.Errorf(\"cannot determine port for %q\", url.Scheme)\n\t\t}\n\t}\n\n\treturn port, nil\n}\n\nfunc configureSearchDomains(resolver *Resolver, searches []string, hardfail bool) error {\n\tresolver.Search = make([]string, 0, len(searches))\n\n\t// Check all search domains.\n\tfor i, value := range searches {\n\t\ttrimmedDomain := strings.ToLower(strings.Trim(value, \".\"))\n\t\terr := checkSearchScope(trimmedDomain)\n\t\tif err != nil {\n\t\t\tif hardfail {\n\t\t\t\tresolver.Search = nil\n\t\t\t\treturn fmt.Errorf(\"failed to validate search domain #%d: %w\", i+1, err)\n\t\t\t}\n\t\t\tlog.Warningf(\"resolver: skipping invalid search domain for resolver %s: %s\", resolver, utils.SafeFirst16Chars(value))\n\t\t} else {\n\t\t\tresolver.Search = append(resolver.Search, fmt.Sprintf(\".%s.\", trimmedDomain))\n\t\t}\n\t}\n\n\t// Limit search domains to mitigate exploitation via malicious local resolver.\n\tif len(resolver.Search) > maxSearchDomains {\n\t\tif hardfail {\n\t\t\treturn fmt.Errorf(\"too many search domains, for security reasons only %d search domains are supported\", maxSearchDomains)\n\t\t}\n\t\tlog.Warningf(\"resolver: limiting search domains for resolver %s to %d for security reasons\", resolver, maxSearchDomains)\n\t\tresolver.Search = resolver.Search[:maxSearchDomains]\n\t}\n\n\treturn nil\n}\n\nfunc getConfiguredResolvers(list []string) (resolvers []*Resolver) {\n\tfor _, server := range list {\n\t\tresolver, skip, err := createResolver(server, ServerSourceConfigured)\n\t\tif err != nil {\n\t\t\t// TODO(ppacher): module error\n\t\t\tlog.Errorf(\"cannot use resolver %s: %s\", server, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif skip {\n\t\t\tcontinue\n\t\t}\n\n\t\tresolvers = append(resolvers, resolver)\n\t}\n\treturn resolvers\n}\n\nfunc getSystemResolvers() (resolvers []*Resolver) {\n\tfor _, nameserver := range netenv.Nameservers() {\n\t\tserverURL := fmt.Sprintf(\"dns://%s\", formatIPAndPort(nameserver.IP, 53))\n\t\tresolver, skip, err := createResolver(serverURL, ServerSourceOperatingSystem)\n\t\tif err != nil {\n\t\t\t// that shouldn't happen but handle it anyway ...\n\t\t\tlog.Errorf(\"cannot use system resolver %s: %s\", serverURL, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif skip {\n\t\t\tcontinue\n\t\t}\n\n\t\tif resolver.Info.IPScope.IsLAN() {\n\t\t\t_ = configureSearchDomains(resolver, nameserver.Search, false)\n\t\t}\n\n\t\tresolvers = append(resolvers, resolver)\n\t}\n\treturn resolvers\n}\n\nconst missingResolversErrorID = \"missing-resolvers\"\n\nfunc loadResolvers() {\n\tdefer func() {\n\t\tif !allConfiguredResolversAreFailing() {\n\t\t\tresetFailingResolversNotification()\n\t\t}\n\t}()\n\n\t// TODO: what happens when a lot of processes want to reload at once? we do not need to run this multiple times in a short time frame.\n\tresolversLock.Lock()\n\tdefer resolversLock.Unlock()\n\n\t// Resolve module error about missing resolvers.\n\tmodule.states.Remove(missingResolversErrorID)\n\t// Check if settings were changed and clear name cache when they did.\n\tnewResolverConfig := configuredNameServers()\n\tif len(currentResolverConfig) > 0 &&\n\t\t!utils.StringSliceEqual(currentResolverConfig, newResolverConfig) {\n\t\tmodule.mgr.Go(\"clear dns cache\", func(ctx *mgr.WorkerCtx) error {\n\t\t\tlog.Info(\"resolver: clearing dns cache due to changed resolver config\")\n\t\t\t_, err := clearNameCache(ctx.Ctx())\n\t\t\treturn err\n\t\t})\n\t}\n\n\t// If no resolvers are configure set the disabled state. So other modules knows that the users does not want to use Portmaster resolver.\n\tif len(newResolverConfig) == 0 {\n\t\tmodule.isDisabled.Store(true)\n\t} else {\n\t\tmodule.isDisabled.Store(false)\n\t}\n\n\tcurrentResolverConfig = newResolverConfig\n\n\tnewResolvers := append(\n\t\tgetConfiguredResolvers(newResolverConfig),\n\t\tgetSystemResolvers()...,\n\t)\n\n\tif len(newResolvers) == 0 {\n\t\t// load defaults directly, overriding config system\n\t\tnewResolvers = getConfiguredResolvers(defaultNameServers)\n\t\tif len(newResolvers) > 0 {\n\t\t\tlog.Warning(\"resolver: no (valid) dns server found in config or system, falling back to global defaults\")\n\t\t\tmodule.states.Add(mgr.State{\n\t\t\t\tID:      missingResolversErrorID,\n\t\t\t\tName:    \"Using Factory Default DNS Servers\",\n\t\t\t\tMessage: \"The Portmaster could not find any (valid) DNS servers in the settings or system. In order to prevent being disconnected, the factory defaults are being used instead. If you just switched your network, this should be resolved shortly.\",\n\t\t\t\tType:    mgr.StateTypeWarning,\n\t\t\t})\n\t\t} else {\n\t\t\tlog.Critical(\"resolver: no (valid) dns server found in config, system or global defaults\")\n\t\t\tmodule.states.Add(mgr.State{\n\t\t\t\tID:      missingResolversErrorID,\n\t\t\t\tName:    \"No DNS Servers Configured\",\n\t\t\t\tMessage: \"The Portmaster could not find any (valid) DNS servers in the settings or system. You will experience severe connectivity problems until resolved. If you just switched your network, this should be resolved shortly.\",\n\t\t\t\tType:    mgr.StateTypeError,\n\t\t\t})\n\t\t}\n\t}\n\n\t// save resolvers\n\tglobalResolvers = newResolvers\n\n\t// assign resolvers to scopes\n\tsetScopedResolvers(globalResolvers)\n\n\t// set active resolvers (for cache validation)\n\t// reset\n\tactiveResolvers = make(map[string]*Resolver)\n\t// add\n\tfor _, resolver := range newResolvers {\n\t\tactiveResolvers[resolver.Info.ID()] = resolver\n\t}\n\tactiveResolvers[mDNSResolver.Info.ID()] = mDNSResolver\n\tactiveResolvers[envResolver.Info.ID()] = envResolver\n\n\t// log global resolvers\n\tif len(globalResolvers) > 0 {\n\t\tlog.Trace(\"resolver: loaded global resolvers:\")\n\t\tfor _, resolver := range globalResolvers {\n\t\t\tlog.Tracef(\"resolver: %s\", resolver.ConfigURL)\n\t\t}\n\t} else {\n\t\tlog.Warning(\"resolver: no global resolvers loaded\")\n\t}\n\n\t// log local resolvers\n\tif len(localResolvers) > 0 {\n\t\tlog.Trace(\"resolver: loaded local resolvers:\")\n\t\tfor _, resolver := range localResolvers {\n\t\t\tlog.Tracef(\"resolver: %s\", resolver.ConfigURL)\n\t\t}\n\t} else {\n\t\tlog.Info(\"resolver: no local resolvers loaded\")\n\t}\n\n\t// log system resolvers\n\tif len(systemResolvers) > 0 {\n\t\tlog.Trace(\"resolver: loaded system/network-assigned resolvers:\")\n\t\tfor _, resolver := range systemResolvers {\n\t\t\tlog.Tracef(\"resolver: %s\", resolver.ConfigURL)\n\t\t}\n\t} else {\n\t\tlog.Info(\"resolver: no system/network-assigned resolvers loaded\")\n\t}\n\n\t// log scopes\n\tif len(localScopes) > 0 {\n\t\tlog.Trace(\"resolver: loaded scopes:\")\n\t\tfor _, scope := range localScopes {\n\t\t\tvar scopeServers []string\n\t\t\tfor _, resolver := range scope.Resolvers {\n\t\t\t\tscopeServers = append(scopeServers, resolver.ConfigURL)\n\t\t\t}\n\t\t\tlog.Tracef(\"resolver: %s: %s\", scope.Domain, strings.Join(scopeServers, \", \"))\n\t\t}\n\t} else {\n\t\tlog.Info(\"resolver: no scopes loaded\")\n\t}\n\n\t// alert if no resolvers are loaded\n\tif len(globalResolvers) == 0 && len(localResolvers) == 0 {\n\t\tlog.Critical(\"resolver: no resolvers loaded!\")\n\t}\n}\n\nfunc setScopedResolvers(resolvers []*Resolver) {\n\t// make list with local resolvers\n\tlocalResolvers = make([]*Resolver, 0)\n\tsystemResolvers = make([]*Resolver, 0)\n\tlocalScopes = make([]*Scope, 0)\n\n\tfor _, resolver := range resolvers {\n\t\tif resolver.Info.IPScope.IsLAN() {\n\t\t\tlocalResolvers = append(localResolvers, resolver)\n\t\t} else if net, _ := netenv.GetLocalNetwork(resolver.Info.IP); net != nil {\n\t\t\tlocalResolvers = append(localResolvers, resolver)\n\t\t}\n\n\t\tif resolver.Info.Source == ServerSourceOperatingSystem {\n\t\t\tsystemResolvers = append(systemResolvers, resolver)\n\t\t}\n\n\t\tif resolver.Search != nil {\n\t\t\t// add resolver to custom searches\n\t\t\tfor _, search := range resolver.Search {\n\t\t\t\tif search == \".\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tkey := indexOfScope(search, localScopes)\n\t\t\t\tif key == -1 {\n\t\t\t\t\tlocalScopes = append(localScopes, &Scope{\n\t\t\t\t\t\tDomain:    search,\n\t\t\t\t\t\tResolvers: []*Resolver{resolver},\n\t\t\t\t\t})\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tlocalScopes[key].Resolvers = append(localScopes[key].Resolvers, resolver)\n\t\t\t}\n\t\t}\n\t}\n\n\t// sort scopes by length\n\tsort.Slice(localScopes,\n\t\tfunc(i, j int) bool {\n\t\t\treturn len(localScopes[i].Domain) > len(localScopes[j].Domain)\n\t\t},\n\t)\n}\n\nfunc checkSearchScope(searchDomain string) error {\n\t// Sanity check the input.\n\tif len(searchDomain) == 0 ||\n\t\tsearchDomain[0] == '.' ||\n\t\tsearchDomain[len(searchDomain)-1] == '.' {\n\t\treturn fmt.Errorf(\"invalid (1) search domain: %s\", searchDomain)\n\t}\n\n\t// Domains that are specifically listed in the special service domains may be\n\t// diverted completely.\n\tif domainInScope(\".\"+searchDomain+\".\", specialServiceDomains) {\n\t\treturn nil\n\t}\n\n\t// In order to check if the search domain is too high up in the hierarchy, we\n\t// need to add some more subdomains.\n\taugmentedSearchDomain := \"*.*.*.*.*.\" + searchDomain\n\n\t// Get the public suffix of the search domain and if the TLD is managed by ICANN.\n\tsuffix, icann := publicsuffix.PublicSuffix(augmentedSearchDomain)\n\t// Sanity check the result.\n\tif len(suffix) == 0 {\n\t\treturn fmt.Errorf(\"invalid (2) search domain: %s\", searchDomain)\n\t}\n\n\t// TLDs that are not managed by ICANN (ie. are unofficial) may be\n\t// diverted completely.\n\t// This might include special service domains like \".onion\" and \".bit\".\n\tif !icann && !strings.Contains(suffix, \".\") {\n\t\treturn nil\n\t}\n\n\t// Build the eTLD+1 domain, which is the highest that may be diverted.\n\tsplit := len(augmentedSearchDomain) - len(suffix) - 1\n\teTLDplus1 := augmentedSearchDomain[1+strings.LastIndex(augmentedSearchDomain[:split], \".\"):]\n\n\t// Check if the scope is being violated by checking if the eTLD+1 contains a wildcard.\n\tif strings.Contains(eTLDplus1, \"*\") {\n\t\treturn fmt.Errorf(`search domain \"%s\" is dangerously high up the hierarchy, stay at or below \"%s\"`, searchDomain, eTLDplus1)\n\t}\n\n\treturn nil\n}\n\n// IsResolverAddress returns whether the given ip and port match a configured resolver.\nfunc IsResolverAddress(ip net.IP, port uint16) bool {\n\tresolversLock.RLock()\n\tdefer resolversLock.RUnlock()\n\n\t// Check if the given IP and port matches a resolver.\n\tfor _, r := range globalResolvers {\n\t\tif port == r.Info.Port && r.Info.IP.Equal(ip) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// ForceResolverReconnect forces all resolvers to reconnect.\nfunc ForceResolverReconnect(ctx context.Context) {\n\tresolversLock.RLock()\n\tdefer resolversLock.RUnlock()\n\n\tctx, tracer := log.AddTracer(ctx)\n\tdefer tracer.Submit()\n\n\ttracer.Trace(\"resolver: forcing all active resolvers to reconnect\")\n\tfor _, r := range globalResolvers {\n\t\tr.Conn.ForceReconnect(ctx)\n\t}\n\ttracer.Info(\"resolver: all active resolvers were forced to reconnect\")\n}\n\n// allConfiguredResolversAreFailing reports whether all configured resolvers are failing.\n// Return false if there are no configured resolvers.\nfunc allConfiguredResolversAreFailing() bool {\n\tresolversLock.RLock()\n\tdefer resolversLock.RUnlock()\n\n\t// If there are no configured resolvers, return as not failing.\n\tif len(currentResolverConfig) == 0 {\n\t\treturn false\n\t}\n\n\t// Return as not failing, if we can find any non-failing configured resolver.\n\tfor _, resolver := range globalResolvers {\n\t\tif !resolver.Conn.IsFailing() && resolver.Info.Source == ServerSourceConfigured {\n\t\t\t// We found a non-failing configured resolver.\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "service/resolver/resolvers_test.go",
    "content": "package resolver\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCheckResolverSearchScope(t *testing.T) {\n\tt.Parallel()\n\n\t// should fail (invalid)\n\tassert.Error(t, checkSearchScope(\".\"))\n\tassert.Error(t, checkSearchScope(\".com.\"))\n\tassert.Error(t, checkSearchScope(\"com.\"))\n\tassert.Error(t, checkSearchScope(\".com\"))\n\n\t// should fail (too high scope)\n\tassert.Error(t, checkSearchScope(\"com\"))\n\tassert.Error(t, checkSearchScope(\"net\"))\n\tassert.Error(t, checkSearchScope(\"org\"))\n\tassert.Error(t, checkSearchScope(\"pvt.k12.ma.us\"))\n\n\t// should succeed\n\tassert.NoError(t, checkSearchScope(\"a.com\"))\n\tassert.NoError(t, checkSearchScope(\"b.a.com\"))\n\tassert.NoError(t, checkSearchScope(\"c.b.a.com\"))\n\tassert.NoError(t, checkSearchScope(\"test.pvt.k12.ma.us\"))\n\n\tassert.NoError(t, checkSearchScope(\"onion\"))\n\tassert.NoError(t, checkSearchScope(\"a.onion\"))\n\tassert.NoError(t, checkSearchScope(\"b.a.onion\"))\n\tassert.NoError(t, checkSearchScope(\"c.b.a.onion\"))\n\n\tassert.NoError(t, checkSearchScope(\"bit\"))\n\tassert.NoError(t, checkSearchScope(\"a.bit\"))\n\tassert.NoError(t, checkSearchScope(\"b.a.bit\"))\n\tassert.NoError(t, checkSearchScope(\"c.b.a.bit\"))\n\n\tassert.NoError(t, checkSearchScope(\"doesnotexist\"))\n\tassert.NoError(t, checkSearchScope(\"a.doesnotexist\"))\n\tassert.NoError(t, checkSearchScope(\"b.a.doesnotexist\"))\n\tassert.NoError(t, checkSearchScope(\"c.b.a.doesnotexist\"))\n}\n"
  },
  {
    "path": "service/resolver/reverse.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// ResolveIPAndValidate finds (reverse DNS), validates (forward DNS) and returns the domain name assigned to the given IP.\nfunc ResolveIPAndValidate(ctx context.Context, ip string) (domain string, err error) {\n\t// get reversed DNS address\n\treverseIP, err := dns.ReverseAddr(ip)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Tracef(\"resolver: failed to get reverse address of %s: %s\", ip, err)\n\t\treturn \"\", ErrInvalid\n\t}\n\n\t// get PTR record\n\tq := &Query{\n\t\tFQDN:  reverseIP,\n\t\tQType: dns.Type(dns.TypePTR),\n\t}\n\trrCache, err := Resolve(ctx, q)\n\tif err != nil || rrCache == nil {\n\t\treturn \"\", fmt.Errorf(\"failed to resolve %s%s: %w\", q.FQDN, q.QType, err)\n\t}\n\n\t// get result from record\n\tvar ptrName string\n\tfor _, rr := range rrCache.Answer {\n\t\tptrRec, ok := rr.(*dns.PTR)\n\t\tif ok {\n\t\t\tptrName = ptrRec.Ptr\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// check for nxDomain\n\tif ptrName == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: %s%s\", ErrNotFound, q.FQDN, q.QType)\n\t}\n\n\t// get forward record\n\tq = &Query{\n\t\tFQDN: ptrName,\n\t}\n\t// IPv4/6 switch\n\tif strings.Contains(ip, \":\") {\n\t\tq.QType = dns.Type(dns.TypeAAAA)\n\t} else {\n\t\tq.QType = dns.Type(dns.TypeA)\n\t}\n\t// resolve\n\trrCache, err = Resolve(ctx, q)\n\tif err != nil || rrCache == nil {\n\t\treturn \"\", fmt.Errorf(\"failed to resolve %s%s: %w\", q.FQDN, q.QType, err)\n\t}\n\n\t// check for matching A/AAAA record\n\tfor _, rr := range rrCache.Answer {\n\t\tswitch v := rr.(type) {\n\t\tcase *dns.A:\n\t\t\t// log.Debugf(\"A: %s\", v.A.String())\n\t\t\tif ip == v.A.String() {\n\t\t\t\treturn ptrName, nil\n\t\t\t}\n\t\tcase *dns.AAAA:\n\t\t\t// log.Debugf(\"AAAA: %s\", v.AAAA.String())\n\t\t\tif ip == v.AAAA.String() {\n\t\t\t\treturn ptrName, nil\n\t\t\t}\n\t\t}\n\t}\n\n\t// no match\n\treturn \"\", ErrBlocked\n}\n"
  },
  {
    "path": "service/resolver/reverse_test.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nfunc testReverse(t *testing.T, ip, result, expectedErr string) {\n\tt.Helper()\n\n\tctx, tracer := log.AddTracer(context.Background())\n\tdefer tracer.Submit()\n\n\tdomain, err := ResolveIPAndValidate(ctx, ip)\n\tif err != nil {\n\t\ttracer.Warning(err.Error())\n\t\tif expectedErr == \"\" || err.Error() != expectedErr {\n\t\t\tt.Errorf(\"reverse-validating %s: unexpected error: %s\", ip, err)\n\t\t}\n\t\treturn\n\t}\n\n\tif domain != result {\n\t\tt.Errorf(\"reverse-validating %s: unexpected result: %s\", ip, domain)\n\t}\n}\n\nfunc TestResolveIPAndValidate(t *testing.T) {\n\tt.Parallel()\n\n\ttestReverse(t, \"198.41.0.4\", \"a.root-servers.net.\", \"\")\n\t// testReverse(t, \"9.9.9.9\", \"dns.quad9.net.\", \"\") // started resolving to dns9.quad9.net.\n\t// testReverse(t, \"2620:fe::fe\", \"dns.quad9.net.\", \"\") // fails sometimes for some (external) reason\n\ttestReverse(t, \"1.1.1.1\", \"one.one.one.one.\", \"\")\n\ttestReverse(t, \"2606:4700:4700::1111\", \"one.one.one.one.\", \"\")\n\n\ttestReverse(t, \"93.184.216.34\", \"example.com.\", \"record could not be found: 34.216.184.93.in-addr.arpa.PTR\")\n\ttestReverse(t, \"185.199.109.153\", \"cdn-185-199-109-153.github.com.\", \"record could not be found: 153.109.199.185.in-addr.arpa.PTR\")\n}\n"
  },
  {
    "path": "service/resolver/rr_context.go",
    "content": "package resolver\n\nimport (\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n)\n\n// DNSRequestContext is a static structure to add information to DNS request connections.\ntype DNSRequestContext struct {\n\tDomain   string\n\tQuestion string\n\tRCode    string\n\n\tServedFromCache bool\n\tRequestingNew   bool\n\tIsBackup        bool\n\tFiltered        bool\n\n\tModified time.Time\n\tExpires  time.Time\n}\n\n// ToDNSRequestContext returns a new DNSRequestContext of the RRCache.\nfunc (rrCache *RRCache) ToDNSRequestContext() *DNSRequestContext {\n\treturn &DNSRequestContext{\n\t\tDomain:   rrCache.Domain,\n\t\tQuestion: rrCache.Question.String(),\n\t\tRCode:    dns.RcodeToString[rrCache.RCode],\n\n\t\tServedFromCache: rrCache.ServedFromCache,\n\t\tRequestingNew:   rrCache.RequestingNew,\n\t\tIsBackup:        rrCache.IsBackup,\n\t\tFiltered:        rrCache.Filtered,\n\n\t\tModified: time.Unix(rrCache.Modified, 0),\n\t\tExpires:  time.Unix(rrCache.Expires, 0),\n\t}\n}\n"
  },
  {
    "path": "service/resolver/rrcache.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/nameserver/nsutil\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// RRCache is a single-use structure to hold a DNS response.\n// Persistence is handled through NameRecords because of a limitation of the\n// underlying dns library.\n//\n//nolint:maligned\ntype RRCache struct {\n\t// Respnse Header\n\tDomain   string\n\tQuestion dns.Type\n\tRCode    int\n\n\t// Response Content\n\tAnswer  []dns.RR `json:\"-\"`\n\tNs      []dns.RR `json:\"-\"`\n\tExtra   []dns.RR `json:\"-\"`\n\tExpires int64\n\n\t// Resolver Information\n\tResolver *ResolverInfo `json:\"-\"`\n\n\t// Metadata about the request and handling\n\tServedFromCache bool\n\tRequestingNew   bool\n\tIsBackup        bool\n\tFiltered        bool\n\tFilteredEntries []string\n\n\t// Modified holds when this entry was last changed, ie. saved to database.\n\t// This field is only populated when the entry comes from the cache.\n\tModified int64\n}\n\n// ID returns the ID of the RRCache consisting of the domain and question type.\nfunc (rrCache *RRCache) ID() string {\n\treturn rrCache.Domain + rrCache.Question.String()\n}\n\n// Expired returns whether the record has expired.\nfunc (rrCache *RRCache) Expired() bool {\n\treturn rrCache.Expires <= time.Now().Unix()\n}\n\n// ExpiresSoon returns whether the record will expire soon (or already has) and\n// should already be refreshed.\nfunc (rrCache *RRCache) ExpiresSoon() bool {\n\treturn rrCache.Expires <= time.Now().Unix()+refreshTTL\n}\n\n// Clean sets all TTLs to 17 and sets cache expiry with specified minimum.\nfunc (rrCache *RRCache) Clean(minExpires uint32) {\n\tvar lowestTTL uint32 = 0xFFFFFFFF\n\tvar header *dns.RR_Header\n\n\t// set TTLs to 17\n\t// TODO: double append? is there something more elegant?\n\tfor _, rr := range append(rrCache.Answer, append(rrCache.Ns, rrCache.Extra...)...) {\n\t\theader = rr.Header()\n\t\tif lowestTTL > header.Ttl {\n\t\t\tlowestTTL = header.Ttl\n\t\t}\n\t\theader.Ttl = 17\n\t}\n\n\t// TTL range limits\n\tswitch {\n\tcase lowestTTL < minExpires:\n\t\tlowestTTL = minExpires\n\tcase lowestTTL > maxTTL:\n\t\tlowestTTL = maxTTL\n\t}\n\n\t// shorten caching\n\tswitch {\n\tcase rrCache.RCode != dns.RcodeSuccess:\n\t\t// Any sort of error.\n\t\tlowestTTL = 10\n\tcase netenv.IsConnectivityDomain(rrCache.Domain):\n\t\t// Responses from these domains might change very quickly depending on the environment.\n\t\tlowestTTL = 3\n\tcase len(rrCache.Answer) == 0:\n\t\t// Empty answer section: Domain exists, but not the queried RR.\n\t\tlowestTTL = 60\n\tcase !netenv.Online():\n\t\t// Not being fully online could mean that we get funny responses.\n\t\tlowestTTL = 60\n\t}\n\n\t// log.Tracef(\"lowest TTL is %d\", lowestTTL)\n\trrCache.Expires = time.Now().Unix() + int64(lowestTTL)\n}\n\n// ExportAllARecords return of a list of all A and AAAA IP addresses.\nfunc (rrCache *RRCache) ExportAllARecords() (ips []net.IP) {\n\tfor _, rr := range rrCache.Answer {\n\t\tif rr.Header().Class != dns.ClassINET {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch rr.Header().Rrtype {\n\t\tcase dns.TypeA:\n\t\t\taRecord, ok := rr.(*dns.A)\n\t\t\tif ok {\n\t\t\t\tips = append(ips, aRecord.A)\n\t\t\t}\n\t\tcase dns.TypeAAAA:\n\t\t\taaaaRecord, ok := rr.(*dns.AAAA)\n\t\t\tif ok {\n\t\t\t\tips = append(ips, aaaaRecord.AAAA)\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// ToNameRecord converts the RRCache to a NameRecord for cleaner persistence.\nfunc (rrCache *RRCache) ToNameRecord() *NameRecord {\n\tnewRecord := &NameRecord{\n\t\tDomain:   rrCache.Domain,\n\t\tQuestion: rrCache.Question.String(),\n\t\tRCode:    rrCache.RCode,\n\t\tExpires:  rrCache.Expires,\n\t\tResolver: rrCache.Resolver,\n\t}\n\n\t// Serialize RR entries to strings.\n\tnewRecord.Answer = toNameRecordSection(rrCache.Answer)\n\tnewRecord.Ns = toNameRecordSection(rrCache.Ns)\n\tnewRecord.Extra = toNameRecordSection(rrCache.Extra)\n\n\treturn newRecord\n}\n\nfunc toNameRecordSection(rrSection []dns.RR) []string {\n\tserialized := make([]string, 0, len(rrSection))\n\tfor _, entry := range rrSection {\n\t\t// Ignore some RR types.\n\t\tswitch entry.Header().Rrtype {\n\t\tcase dns.TypeOPT:\n\t\t\t// This record type cannot be unserialized again and only consists of\n\t\t\t// additional metadata.\n\t\tcase dns.TypeNULL:\n\t\tdefault:\n\t\t\tserialized = append(serialized, entry.String())\n\t\t}\n\t}\n\treturn serialized\n}\n\n// rcodeIsCacheable returns whether a record with the given RCode should be cached.\nfunc rcodeIsCacheable(rCode int) bool {\n\tswitch rCode {\n\tcase dns.RcodeSuccess, dns.RcodeNameError, dns.RcodeRefused:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// Cacheable returns whether the record should be cached.\nfunc (rrCache *RRCache) Cacheable() bool {\n\treturn rcodeIsCacheable(rrCache.RCode)\n}\n\n// Save saves the RRCache to the database as a NameRecord.\nfunc (rrCache *RRCache) Save() error {\n\tif !rrCache.Cacheable() {\n\t\treturn nil\n\t}\n\n\treturn rrCache.ToNameRecord().Save()\n}\n\n// GetRRCache tries to load the corresponding NameRecord from the database and convert it.\nfunc GetRRCache(domain string, question dns.Type) (*RRCache, error) {\n\trrCache := &RRCache{\n\t\tDomain:   domain,\n\t\tQuestion: question,\n\t}\n\n\tnameRecord, err := GetNameRecord(domain, question.String())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trrCache.RCode = nameRecord.RCode\n\trrCache.Expires = nameRecord.Expires\n\tfor _, entry := range nameRecord.Answer {\n\t\trrCache.Answer = parseRR(rrCache.Answer, entry)\n\t}\n\tfor _, entry := range nameRecord.Ns {\n\t\trrCache.Ns = parseRR(rrCache.Ns, entry)\n\t}\n\tfor _, entry := range nameRecord.Extra {\n\t\trrCache.Extra = parseRR(rrCache.Extra, entry)\n\t}\n\n\trrCache.Resolver = nameRecord.Resolver\n\trrCache.ServedFromCache = true\n\trrCache.Modified = nameRecord.Meta().Modified\n\treturn rrCache, nil\n}\n\nfunc parseRR(section []dns.RR, entry string) []dns.RR {\n\trr, err := dns.NewRR(entry)\n\tswitch {\n\tcase err != nil:\n\t\tlog.Warningf(\"resolver: failed to parse cached record %q: %s\", entry, err)\n\tcase rr == nil:\n\t\tlog.Warningf(\"resolver: failed to parse cached record %q: resulted in nil record\", entry)\n\tdefault:\n\t\treturn append(section, rr)\n\t}\n\treturn section\n}\n\n// Flags formats ServedFromCache and RequestingNew to a condensed, flag-like format.\nfunc (rrCache *RRCache) Flags() string {\n\tvar s string\n\tif rrCache.ServedFromCache {\n\t\ts += \"C\"\n\t}\n\tif rrCache.RequestingNew {\n\t\ts += \"R\"\n\t}\n\tif rrCache.IsBackup {\n\t\ts += \"B\"\n\t}\n\tif rrCache.Filtered {\n\t\ts += \"F\"\n\t}\n\n\tif s != \"\" {\n\t\treturn fmt.Sprintf(\" [%s]\", s)\n\t}\n\treturn \"\"\n}\n\n// ShallowCopy returns a shallow copy of the cache. slices are not copied, but referenced.\nfunc (rrCache *RRCache) ShallowCopy() *RRCache {\n\treturn &RRCache{\n\t\tDomain:   rrCache.Domain,\n\t\tQuestion: rrCache.Question,\n\t\tRCode:    rrCache.RCode,\n\n\t\tAnswer:  rrCache.Answer,\n\t\tNs:      rrCache.Ns,\n\t\tExtra:   rrCache.Extra,\n\t\tExpires: rrCache.Expires,\n\n\t\tResolver: rrCache.Resolver,\n\n\t\tServedFromCache: rrCache.ServedFromCache,\n\t\tRequestingNew:   rrCache.RequestingNew,\n\t\tIsBackup:        rrCache.IsBackup,\n\t\tFiltered:        rrCache.Filtered,\n\t\tFilteredEntries: rrCache.FilteredEntries,\n\t\tModified:        rrCache.Modified,\n\t}\n}\n\n// ReplaceAnswerNames is a helper function that replaces all answer names, that\n// match the query domain, with another value. This is used to support handling\n// non-standard query names, which are resolved normalized, but have to be\n// reverted back for the origin non-standard query name in order for the\n// clients to recognize the response.\nfunc (rrCache *RRCache) ReplaceAnswerNames(fqdn string) {\n\tfor _, answer := range rrCache.Answer {\n\t\tif answer.Header().Name == rrCache.Domain {\n\t\t\tanswer.Header().Name = fqdn\n\t\t}\n\t}\n}\n\n// ReplyWithDNS creates a new reply to the given query with the data from the\n// RRCache, and additional informational records.\nfunc (rrCache *RRCache) ReplyWithDNS(ctx context.Context, request *dns.Msg) *dns.Msg {\n\t// reply to query\n\treply := new(dns.Msg)\n\treply.SetRcode(request, rrCache.RCode)\n\treply.Answer = rrCache.Answer\n\treply.Ns = rrCache.Ns\n\treply.Extra = rrCache.Extra\n\n\treturn reply\n}\n\n// GetExtraRRs returns a slice of RRs with additional informational records.\nfunc (rrCache *RRCache) GetExtraRRs(ctx context.Context, query *dns.Msg) (extra []dns.RR) {\n\t// Add cache status and source of data.\n\tif rrCache.ServedFromCache {\n\t\textra = addExtra(ctx, extra, \"served from cache, resolved by \"+rrCache.Resolver.DescriptiveName())\n\t} else {\n\t\textra = addExtra(ctx, extra, \"freshly resolved by \"+rrCache.Resolver.DescriptiveName())\n\t}\n\n\t// Add expiry and cache information.\n\tswitch {\n\tcase rrCache.Expires == 0:\n\t\textra = addExtra(ctx, extra, \"record does not expire\")\n\tcase rrCache.Expired():\n\t\textra = addExtra(ctx, extra, fmt.Sprintf(\"record expired since %s\", time.Since(time.Unix(rrCache.Expires, 0)).Round(time.Second)))\n\tdefault:\n\t\textra = addExtra(ctx, extra, fmt.Sprintf(\"record valid for %s\", time.Until(time.Unix(rrCache.Expires, 0)).Round(time.Second)))\n\t}\n\tif rrCache.RequestingNew {\n\t\textra = addExtra(ctx, extra, \"async request to refresh the cache has been started\")\n\t}\n\tif rrCache.IsBackup {\n\t\textra = addExtra(ctx, extra, \"this record is served because a fresh request was unsuccessful\")\n\t}\n\n\t// Add information about filtered entries.\n\tif rrCache.Filtered {\n\t\tif len(rrCache.FilteredEntries) > 1 {\n\t\t\textra = addExtra(ctx, extra, fmt.Sprintf(\"%d RRs have been filtered:\", len(rrCache.FilteredEntries)))\n\t\t} else {\n\t\t\textra = addExtra(ctx, extra, fmt.Sprintf(\"%d RR has been filtered:\", len(rrCache.FilteredEntries)))\n\t\t}\n\t\tfor _, filteredRecord := range rrCache.FilteredEntries {\n\t\t\textra = addExtra(ctx, extra, filteredRecord)\n\t\t}\n\t}\n\n\treturn extra\n}\n\nfunc addExtra(ctx context.Context, extra []dns.RR, msg string) []dns.RR {\n\trr, err := nsutil.MakeMessageRecord(log.InfoLevel, msg)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Warningf(\"resolver: failed to add informational record to reply: %s\", err)\n\t\treturn extra\n\t}\n\textra = append(extra, rr)\n\treturn extra\n}\n"
  },
  {
    "path": "service/resolver/rrcache_test.go",
    "content": "package resolver\n\nimport (\n\t\"testing\"\n\n\t\"github.com/miekg/dns\"\n)\n\nfunc TestCaching(t *testing.T) {\n\tt.Parallel()\n\n\ttestDomain := \"Mk35mMqOWEHXSMk11MYcbjLOjTE8PQvDiAVUxf4BvwtgR.example.com.\"\n\ttestQuestion := \"A\"\n\n\ttestNameRecord := &NameRecord{\n\t\tDomain:   testDomain,\n\t\tQuestion: testQuestion,\n\t\tResolver: &ResolverInfo{\n\t\t\tType: \"dns\",\n\t\t},\n\t}\n\n\terr := testNameRecord.Save()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\trrCache, err := GetRRCache(testDomain, dns.Type(dns.TypeA))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = rrCache.Save()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\trrCache2, err := GetRRCache(testDomain, dns.Type(dns.TypeA))\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif rrCache2.Domain != rrCache.Domain {\n\t\tt.Fatal(\"something very is wrong\")\n\t}\n}\n"
  },
  {
    "path": "service/resolver/scopes.go",
    "content": "package resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/miekg/dns\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// Domain Scopes.\nvar (\n\t// Localhost Domain\n\t// Handling: Respond with 127.0.0.1 and ::1 to A and AAAA queries, respectively.\n\t// See RFC6761.\n\tlocalhostDomain = \".localhost.\"\n\n\t// Invalid Domain\n\t// Handling: Always respond with NXDOMAIN.\n\t// See RFC6761.\n\tinvalidDomain = \".invalid.\"\n\n\t// Internal Special-Use Domain\n\t// Used by Portmaster for special addressing.\n\tinternalSpecialUseDomains = []string{\n\t\t\".\" + InternalSpecialUseDomain,\n\t}\n\n\t// Multicast DNS\n\t// Handling: Send to nameservers with matching search scope, then MDNS\n\t// See RFC6762.\n\tmulticastDomains = []string{\n\t\t\".local.\",\n\t\t\".254.169.in-addr.arpa.\",\n\t\t\".8.e.f.ip6.arpa.\",\n\t\t\".9.e.f.ip6.arpa.\",\n\t\t\".a.e.f.ip6.arpa.\",\n\t\t\".b.e.f.ip6.arpa.\",\n\t}\n\n\t// Special-Use Domain Names\n\t// Handling: Send to nameservers with matching search scope, then local and system assigned nameservers\n\t// IANA Ref: https://www.iana.org/assignments/special-use-domain-names\n\tspecialUseDomains = []string{\n\t\t// RFC8375: Designated for non-unique use in residential home networks.\n\t\t\".home.arpa.\",\n\n\t\t// RFC6762 (Appendix G): Non-official, but officially listed, private use domains.\n\t\t\".intranet.\",\n\t\t\".internal.\",\n\t\t\".private.\",\n\t\t\".corp.\",\n\t\t\".home.\",\n\t\t\".lan.\",\n\n\t\t// RFC6761: IPv4 private-address reverse-mapping domains.\n\t\t\".10.in-addr.arpa.\",\n\t\t\".16.172.in-addr.arpa.\",\n\t\t\".17.172.in-addr.arpa.\",\n\t\t\".18.172.in-addr.arpa.\",\n\t\t\".19.172.in-addr.arpa.\",\n\t\t\".20.172.in-addr.arpa.\",\n\t\t\".21.172.in-addr.arpa.\",\n\t\t\".22.172.in-addr.arpa.\",\n\t\t\".23.172.in-addr.arpa.\",\n\t\t\".24.172.in-addr.arpa.\",\n\t\t\".25.172.in-addr.arpa.\",\n\t\t\".26.172.in-addr.arpa.\",\n\t\t\".27.172.in-addr.arpa.\",\n\t\t\".28.172.in-addr.arpa.\",\n\t\t\".29.172.in-addr.arpa.\",\n\t\t\".30.172.in-addr.arpa.\",\n\t\t\".31.172.in-addr.arpa.\",\n\t\t\".168.192.in-addr.arpa.\",\n\n\t\t// RFC4193: IPv6 private-address reverse-mapping domains.\n\t\t\".d.f.ip6.arpa.\",\n\t\t\".c.f.ip6.arpa.\",\n\n\t\t// RFC6761: Special use domains for documentation and testing.\n\t\t\".example.\",\n\t\t\".example.com.\",\n\t\t\".example.net.\",\n\t\t\".example.org.\",\n\t\t\".test.\",\n\t}\n\n\t// Special-Service Domain Names\n\t// Handling: Send to nameservers with matching search scope, then local and system assigned nameservers.\n\tspecialServiceDomains = []string{\n\t\t// RFC7686: Tor Hidden Services, https://www.torproject.org/\n\t\t\".onion.\",\n\n\t\t// I2P: Fully encrypted private network layer, https://geti2p.net/\n\t\t\".i2p.\",\n\n\t\t// Lokinet: Internal services on the decentralised network, https://lokinet.org/\n\t\t\".loki.\",\n\n\t\t// Namecoin: Blockchain based nameservice, https://www.namecoin.org/\n\t\t\".bit.\",\n\n\t\t// Ethereum Name Service (ENS): naming system based on the Ethereum blockchain, https://ens.domains/\n\t\t\".eth.\",\n\n\t\t// Unstoppable Domains: NFT based domain names, https://unstoppabledomains.com/\n\t\t\".888.\",\n\t\t\".bitcoin.\",\n\t\t\".coin.\",\n\t\t\".crypto.\",\n\t\t\".dao.\",\n\t\t\".nft.\",\n\t\t\".wallet.\",\n\t\t\".x.\",\n\t\t\".zil.\",\n\n\t\t// EmerDNS: Domain name registration on EmerCoin, https://emercoin.com/en/emerdns/\n\t\t\".bazar.\",\n\t\t\".coin.\",\n\t\t\".emc.\",\n\t\t\".lib.\",\n\n\t\t// OpenNIC TLDs: Democratic alternative to ICANN, https://www.opennic.org/\n\t\t\".bbs.\",\n\t\t\".chan.\",\n\t\t\".dyn.\",\n\t\t\".free.\",\n\t\t\".fur.\",\n\t\t\".geek.\",\n\t\t\".glue.\",\n\t\t\".gopher.\",\n\t\t\".indy.\",\n\t\t\".libre.\",\n\t\t\".neo.\",\n\t\t\".null.\",\n\t\t\".o.\",\n\t\t\".oss.\",\n\t\t\".oz.\",\n\t\t\".parody.\",\n\t\t\".pirate.\",\n\n\t\t// NewNations: TLDs for countries/regions without a ccTLD, http://new-nations.net/\n\t\t\".ku.\",\n\t\t\".te.\",\n\t\t\".ti.\",\n\t\t\".uu.\",\n\t}\n)\n\nfunc domainInScope(dotPrefixedFQDN string, scopeList []string) bool {\n\tfor _, scope := range scopeList {\n\t\tif strings.HasSuffix(dotPrefixedFQDN, scope) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// GetResolversInScope returns all resolvers that are in scope the resolve the given query and options.\nfunc GetResolversInScope(ctx context.Context, q *Query) (selected []*Resolver, primarySource string, tryAll bool) { //nolint:gocognit // TODO\n\tresolversLock.RLock()\n\tdefer resolversLock.RUnlock()\n\n\t// Internal use domains\n\tif domainInScope(q.dotPrefixedFQDN, internalSpecialUseDomains) {\n\t\treturn envResolvers, ServerSourceEnv, false\n\t}\n\n\t// Special connectivity domains\n\tif netenv.IsConnectivityDomain(q.FQDN) && len(systemResolvers) > 0 {\n\t\tselected = addResolvers(ctx, q, selected, systemResolvers)\n\t\tif len(selected) == 0 {\n\t\t\tselected = addResolvers(ctx, q, selected, localResolvers)\n\t\t\tselected = addResolvers(ctx, q, selected, globalResolvers)\n\t\t}\n\t\treturn selected, ServerSourceOperatingSystem, false\n\t}\n\n\t// Prioritize search scopes\n\tfor _, scope := range localScopes {\n\t\tif strings.HasSuffix(q.dotPrefixedFQDN, scope.Domain) {\n\t\t\tselected = addResolvers(ctx, q, selected, scope.Resolvers)\n\t\t}\n\t}\n\n\t// Handle multicast domains\n\tif domainInScope(q.dotPrefixedFQDN, multicastDomains) {\n\t\tselected = addResolvers(ctx, q, selected, mDNSResolvers)\n\t\tselected = addResolvers(ctx, q, selected, localResolvers)\n\t\tselected = addResolvers(ctx, q, selected, systemResolvers)\n\t\treturn selected, ServerSourceMDNS, true\n\t}\n\n\t// Special use domains\n\tif domainInScope(q.dotPrefixedFQDN, specialUseDomains) ||\n\t\tdomainInScope(q.dotPrefixedFQDN, specialServiceDomains) {\n\t\tselected = addResolvers(ctx, q, selected, localResolvers)\n\t\treturn selected, \"special\", true\n\t}\n\n\t// Global domains\n\tselected = addResolvers(ctx, q, selected, globalResolvers)\n\treturn selected, ServerSourceConfigured, false\n}\n\nfunc addResolvers(ctx context.Context, q *Query, selected []*Resolver, addResolvers []*Resolver) []*Resolver {\naddNextResolver:\n\tfor _, resolver := range addResolvers {\n\t\t// check for compliance\n\t\tif err := resolver.checkCompliance(ctx, q); err != nil {\n\t\t\tlog.Tracer(ctx).Tracef(\"skipping non-compliant resolver %s: %s\", resolver.Info.DescriptiveName(), err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// deduplicate\n\t\tfor _, selectedResolver := range selected {\n\t\t\tif selectedResolver.Info.ID() == resolver.Info.ID() {\n\t\t\t\tcontinue addNextResolver\n\t\t\t}\n\t\t}\n\n\t\t// the domains from the configured resolvers should not be resolved with the same resolvers\n\t\tif resolver.Info.Source == ServerSourceConfigured && resolver.Info.IP == nil {\n\t\t\tif _, ok := resolverInitDomains[q.FQDN]; ok {\n\t\t\t\tcontinue addNextResolver\n\t\t\t}\n\t\t}\n\n\t\t// add compliant and unique resolvers to selected resolvers\n\t\tselected = append(selected, resolver)\n\t}\n\treturn selected\n}\n\nvar (\n\terrInsecureProtocol = errors.New(\"insecure protocols disabled\")\n\terrAssignedServer   = errors.New(\"assigned (dhcp) nameservers disabled\")\n\terrMulticastDNS     = errors.New(\"multicast DNS disabled\")\n\terrOutOfScope       = errors.New(\"query out of scope for resolver\")\n)\n\nfunc (q *Query) checkCompliance() error {\n\t// RFC6761 - always respond with nxdomain\n\tif strings.HasSuffix(q.dotPrefixedFQDN, invalidDomain) {\n\t\treturn ErrNotFound\n\t}\n\n\t// RFC6761 - respond with 127.0.0.1 and ::1 to A and AAAA queries respectively, else nxdomain\n\tif strings.HasSuffix(q.dotPrefixedFQDN, localhostDomain) {\n\t\tswitch uint16(q.QType) {\n\t\tcase dns.TypeA, dns.TypeAAAA:\n\t\t\treturn ErrLocalhost\n\t\tdefault:\n\t\t\treturn ErrNotFound\n\t\t}\n\t}\n\n\t// special TLDs\n\tif dontResolveSpecialDomains() &&\n\t\tdomainInScope(q.dotPrefixedFQDN, specialServiceDomains) {\n\t\treturn ErrSpecialDomainsDisabled\n\t}\n\n\treturn nil\n}\n\nfunc (resolver *Resolver) checkCompliance(_ context.Context, q *Query) error {\n\tif noInsecureProtocols() {\n\t\tswitch resolver.Info.Type {\n\t\tcase ServerTypeDNS:\n\t\t\treturn errInsecureProtocol\n\t\tcase ServerTypeTCP:\n\t\t\treturn errInsecureProtocol\n\t\tcase ServerTypeDoT:\n\t\t\t// compliant\n\t\tcase ServerTypeDoH:\n\t\t\t// compliant\n\t\tcase ServerTypeEnv:\n\t\t\t// compliant (data is sourced from local network only and is highly limited)\n\t\tdefault:\n\t\t\treturn errInsecureProtocol\n\t\t}\n\t}\n\n\tif noAssignedNameservers() {\n\t\tif resolver.Info.Source == ServerSourceOperatingSystem {\n\t\t\treturn errAssignedServer\n\t\t}\n\t}\n\n\tif noMulticastDNS() {\n\t\tif resolver.Info.Source == ServerSourceMDNS {\n\t\t\treturn errMulticastDNS\n\t\t}\n\t}\n\n\t// Check if the resolver should only be used for the search scopes.\n\tif resolver.SearchOnly && !domainInScope(q.dotPrefixedFQDN, resolver.Search) {\n\t\treturn errOutOfScope\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/resolver/test/resolving.bash",
    "content": "#!/bin/bash\n\nDOMAINS=\"twitter.com news.ycombinator.com\"\n\nwhile true; do\n  for domain in $DOMAINS; do\n    # query domain\n    Q=$(dig $domain | tr '\\n' '§')\n    # check result\n    if [[ $(echo $Q | grep NOERROR | wc -l) -gt 0 ]]; then\n      echo \"$(date \"+%y%m%d %H:%M:%S\") [OK] $domain ($(echo $Q | grep -aoE 'valid for [a-z0-9]+'))\"\n    else\n      echo \"\"\n      echo \"$(date \"+%y%m%d %H:%M:%S\") [FAILED] $domain\"\n      echo $Q | tr '§' '\\n'\n      echo \"#####\"\n      echo \"\"\n    fi\n    # wait\n    sleep 5\n  done\ndone\n"
  },
  {
    "path": "service/status/module.go",
    "content": "package status\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// Status Module manages status information.\ntype Status struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tpublishUpdate runtime.PushFunc\n\ttriggerUpdate chan struct{}\n\n\tstates     map[string]mgr.StateUpdate\n\tstatesLock sync.Mutex\n\n\tnotifications     map[string]map[string]*notifications.Notification\n\tnotificationsLock sync.Mutex\n}\n\n// Manager returns the module manager.\nfunc (s *Status) Manager() *mgr.Manager {\n\treturn s.mgr\n}\n\n// Start starts the module.\nfunc (s *Status) Start() error {\n\ts.mgr.Go(\"status publisher\", s.statusPublisher)\n\n\ts.instance.NetEnv().EventOnlineStatusChange.AddCallback(\"update online status in system status\",\n\t\tfunc(_ *mgr.WorkerCtx, _ netenv.OnlineStatus) (bool, error) {\n\t\t\ts.triggerPublishStatus()\n\t\t\treturn false, nil\n\t\t},\n\t)\n\n\t// Make an initial status query.\n\ts.statesLock.Lock()\n\tdefer s.statesLock.Unlock()\n\t// Add status callback within the lock so we can force the right order.\n\ts.instance.AddStatesCallback(\"status update\", s.handleModuleStatusUpdate)\n\t// Get initial states.\n\tfor _, stateUpdate := range s.instance.GetStates() {\n\t\ts.states[stateUpdate.Module] = stateUpdate\n\t\ts.deriveNotificationsFromStateUpdate(stateUpdate)\n\t}\n\n\treturn nil\n}\n\n// Stop stops the module.\nfunc (s *Status) Stop() error {\n\treturn nil\n}\n\nfunc (s *Status) prep() error {\n\t// register status provider as soon as possible\n\tif err := s.setupRuntimeProvider(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// AddToDebugInfo adds the system status to the given debug.Info.\nfunc AddToDebugInfo(di *debug.Info) {\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Status: %s\", netenv.GetOnlineStatus()),\n\t\tdebug.UseCodeSection|debug.AddContentLineBreaks,\n\t\tfmt.Sprintf(\"OnlineStatus:          %s\", netenv.GetOnlineStatus()),\n\t\t\"CaptivePortal:         \"+netenv.GetCaptivePortal().URL,\n\t)\n}\n\nvar (\n\tmodule     *Status\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new status module.\nfunc New(instance instance) (*Status, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Status\")\n\tmodule = &Status{\n\t\tmgr:           m,\n\t\tinstance:      instance,\n\t\ttriggerUpdate: make(chan struct{}, 1),\n\t\tstates:        make(map[string]mgr.StateUpdate),\n\t\tnotifications: make(map[string]map[string]*notifications.Notification),\n\t}\n\n\tif err := module.prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tNetEnv() *netenv.NetEnv\n\tGetStates() []mgr.StateUpdate\n\tAddStatesCallback(callbackName string, callback mgr.EventCallbackFunc[mgr.StateUpdate])\n}\n"
  },
  {
    "path": "service/status/notifications.go",
    "content": "package status\n\nimport (\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc (s *Status) deriveNotificationsFromStateUpdate(update mgr.StateUpdate) {\n\ts.notificationsLock.Lock()\n\tdefer s.notificationsLock.Unlock()\n\n\tnotifs := s.notifications[update.Module]\n\tif notifs == nil {\n\t\tnotifs = make(map[string]*notifications.Notification)\n\t\ts.notifications[update.Module] = notifs\n\t}\n\n\t// Add notifications.\n\tseenStateIDs := make(map[string]struct{}, len(update.States))\n\tfor _, state := range update.States {\n\t\tseenStateIDs[state.ID] = struct{}{}\n\n\t\t// Check if we already have a notification registered.\n\t\tif _, ok := notifs[state.ID]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check if the notification was pre-created.\n\t\t// If a matching notification is found, assign it.\n\t\tn := notifications.Get(state.ID)\n\t\tif n != nil {\n\t\t\tnotifs[state.ID] = n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create a new notification.\n\t\tn = &notifications.Notification{\n\t\t\tEventID: state.ID,\n\t\t\tTitle:   state.Name,\n\t\t\tMessage: state.Message,\n\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t{\n\t\t\t\t\tText:    \"Get Help\",\n\t\t\t\t\tType:    notifications.ActionTypeOpenURL,\n\t\t\t\t\tPayload: \"https://safing.io/support/\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tswitch state.Type {\n\t\tcase mgr.StateTypeWarning:\n\t\t\tn.Type = notifications.Warning\n\t\t\tn.ShowOnSystem = true\n\t\tcase mgr.StateTypeError:\n\t\t\tn.Type = notifications.Error\n\t\t\tn.ShowOnSystem = true\n\t\tcase mgr.StateTypeHint, mgr.StateTypeUndefined:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\tn.Type = notifications.Info\n\t\t\tn.AvailableActions = nil\n\t\t}\n\n\t\tnotifs[state.ID] = n\n\t\tnotifications.Notify(n)\n\t}\n\n\t// Remove notifications.\n\tfor stateID, n := range notifs {\n\t\tif _, ok := seenStateIDs[stateID]; !ok {\n\t\t\tn.Delete()\n\t\t\tdelete(notifs, stateID)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "service/status/security_level.go",
    "content": "package status\n\nimport \"github.com/safing/portmaster/base/config\"\n\n// MigrateSecurityLevelToBoolean migrates a security level (int) option value to a boolean option value.\nfunc MigrateSecurityLevelToBoolean(option *config.Option, value any) any {\n\t// Check new (target) option type.\n\tif option.OptType != config.OptTypeBool {\n\t\t// This migration converts to boolean.\n\t\t// Thus, conversion is not applicable.\n\t\treturn value\n\t}\n\n\t// Convert value to uint8.\n\tvar nVal uint8\n\tswitch v := value.(type) {\n\tcase int:\n\t\tnVal = uint8(v)\n\tcase int8:\n\t\tnVal = uint8(v)\n\tcase int16:\n\t\tnVal = uint8(v)\n\tcase int32:\n\t\tnVal = uint8(v)\n\tcase int64:\n\t\tnVal = uint8(v)\n\tcase uint:\n\t\tnVal = uint8(v)\n\tcase uint8:\n\t\tnVal = v\n\tcase uint16:\n\t\tnVal = uint8(v)\n\tcase uint32:\n\t\tnVal = uint8(v)\n\tcase uint64:\n\t\tnVal = uint8(v)\n\tcase float32:\n\t\tnVal = uint8(v)\n\tcase float64:\n\t\tnVal = uint8(v)\n\tdefault:\n\t\t// Input type not compatible.\n\t\treturn value\n\t}\n\n\t// Convert to boolean.\n\treturn nVal&SecurityLevelNormal > 0\n}\n\n// DisplayHintSecurityLevel is an external option hint for security levels.\n// It's meant to be used as a value for config.DisplayHintAnnotation.\nconst DisplayHintSecurityLevel string = \"security level\"\n\n// Security levels.\nconst (\n\tSecurityLevelOff     uint8 = 0\n\tSecurityLevelNormal  uint8 = 1\n\tSecurityLevelHigh    uint8 = 2\n\tSecurityLevelExtreme uint8 = 4\n)\n"
  },
  {
    "path": "service/status/status.go",
    "content": "package status\n\nimport (\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// SystemStatusRecord describes the overall status of the Portmaster.\n// It's a read-only record exposed via runtime:system/status.\ntype SystemStatusRecord struct {\n\trecord.Base\n\tsync.Mutex\n\n\t// OnlineStatus holds the current online status as\n\t// seen by the netenv package.\n\tOnlineStatus netenv.OnlineStatus\n\t// CaptivePortal holds all information about the captive\n\t// portal of the network the portmaster is currently\n\t// connected to, if any.\n\tCaptivePortal *netenv.CaptivePortal\n\n\tModules    []mgr.StateUpdate\n\tWorstState struct {\n\t\tModule string\n\t\tmgr.State\n\t}\n}\n\nfunc (s *Status) handleModuleStatusUpdate(_ *mgr.WorkerCtx, update mgr.StateUpdate) (cancel bool, err error) {\n\ts.statesLock.Lock()\n\tdefer s.statesLock.Unlock()\n\n\ts.states[update.Module] = update\n\ts.deriveNotificationsFromStateUpdate(update)\n\ts.triggerPublishStatus()\n\n\treturn false, nil\n}\n\nfunc (s *Status) triggerPublishStatus() {\n\tselect {\n\tcase s.triggerUpdate <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc (s *Status) statusPublisher(w *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-w.Done():\n\t\t\treturn nil\n\t\tcase <-s.triggerUpdate:\n\t\t\ts.publishSystemStatus()\n\t\t}\n\t}\n}\n\nfunc (s *Status) setupRuntimeProvider() (err error) {\n\t// register the system status getter\n\tstatusProvider := runtime.SimpleValueGetterFunc(func(_ string) ([]record.Record, error) {\n\t\treturn []record.Record{s.buildSystemStatus()}, nil\n\t})\n\ts.publishUpdate, err = runtime.Register(\"system/status\", statusProvider)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// buildSystemStatus build a new system status record.\nfunc (s *Status) buildSystemStatus() *SystemStatusRecord {\n\ts.statesLock.Lock()\n\tdefer s.statesLock.Unlock()\n\n\tstatus := &SystemStatusRecord{\n\t\tCaptivePortal: netenv.GetCaptivePortal(),\n\t\tOnlineStatus:  netenv.GetOnlineStatus(),\n\t\tModules:       make([]mgr.StateUpdate, 0, len(s.states)),\n\t}\n\tfor _, newStateUpdate := range s.states {\n\t\t// Deep copy state.\n\t\tnewStateUpdate.States = append([]mgr.State(nil), newStateUpdate.States...)\n\t\tstatus.Modules = append(status.Modules, newStateUpdate)\n\n\t\t// Check if state is worst so far.\n\t\tfor _, state := range newStateUpdate.States {\n\t\t\tif state.Type.Severity() > status.WorstState.Type.Severity() {\n\t\t\t\ts.mgr.Error(\"new worst state\", \"state\", state)\n\t\t\t\tstatus.WorstState.State = state\n\t\t\t\tstatus.WorstState.Module = newStateUpdate.Module\n\t\t\t}\n\t\t}\n\t}\n\tslices.SortFunc(status.Modules, func(a, b mgr.StateUpdate) int {\n\t\treturn strings.Compare(a.Module, b.Module)\n\t})\n\n\tstatus.CreateMeta()\n\tstatus.SetKey(\"runtime:system/status\")\n\treturn status\n}\n\n// publishSystemStatus pushes a new system status via\n// the runtime database.\nfunc (s *Status) publishSystemStatus() {\n\tif s.publishUpdate == nil {\n\t\treturn\n\t}\n\n\trecord := s.buildSystemStatus()\n\trecord.Lock()\n\tdefer record.Unlock()\n\n\ts.publishUpdate(record)\n}\n"
  },
  {
    "path": "service/sync/module.go",
    "content": "package sync\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\ntype Sync struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc (s *Sync) Manager() *mgr.Manager {\n\treturn s.mgr\n}\n\nfunc (s *Sync) Start() error {\n\treturn nil\n}\n\nfunc (s *Sync) Stop() error {\n\treturn nil\n}\n\nvar db = database.NewInterface(&database.Options{\n\tLocal:    true,\n\tInternal: true,\n})\n\nfunc prep() error {\n\tif err := registerSettingsAPI(); err != nil {\n\t\treturn err\n\t}\n\tif err := registerSingleSettingAPI(); err != nil {\n\t\treturn err\n\t}\n\tif err := registerProfileAPI(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nvar (\n\tmodule     *Sync\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new NetEnv module.\nfunc New(instance instance) (*Sync, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Sync\")\n\tmodule = &Sync{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "service/sync/profile.go",
    "content": "package sync\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/vincent-petithory/dataurl\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/binmeta\"\n)\n\n// ProfileExport holds an export of a profile.\ntype ProfileExport struct { //nolint:maligned\n\tType Type `json:\"type\" yaml:\"type\"`\n\n\t// Identification\n\tID     string                `json:\"id,omitempty\"     yaml:\"id,omitempty\"`\n\tSource profile.ProfileSource `json:\"source,omitempty\" yaml:\"source,omitempty\"`\n\n\t// Human Metadata\n\tName                string `json:\"name\"                  yaml:\"name\"`\n\tDescription         string `json:\"description,omitempty\" yaml:\"description,omitempty\"`\n\tHomepage            string `json:\"homepage,omitempty\"    yaml:\"homepage,omitempty\"`\n\tPresentationPath    string `json:\"presPath,omitempty\"    yaml:\"presPath,omitempty\"`\n\tUsePresentationPath bool   `json:\"usePresPath,omitempty\" yaml:\"usePresPath,omitempty\"`\n\tIconData            string `json:\"iconData,omitempty\"    yaml:\"iconData,omitempty\"` // DataURL\n\n\t// Process matching\n\tFingerprints []ProfileFingerprint `json:\"fingerprints\" yaml:\"fingerprints\"`\n\n\t// Settings\n\tConfig map[string]any `json:\"config,omitempty\" yaml:\"config,omitempty\"`\n\n\t// Metadata\n\tLastEdited *time.Time `json:\"lastEdited,omitempty\" yaml:\"lastEdited,omitempty\"`\n\tCreated    *time.Time `json:\"created,omitempty\"    yaml:\"created,omitempty\"`\n\tInternal   bool       `json:\"internal,omitempty\"   yaml:\"internal,omitempty\"`\n}\n\n// ProfileIcon represents a profile icon only.\ntype ProfileIcon struct {\n\tIconData string `json:\"iconData,omitempty\" yaml:\"iconData,omitempty\"` // DataURL\n}\n\n// ProfileFingerprint represents a profile fingerprint.\ntype ProfileFingerprint struct {\n\tType       string `json:\"type\"                 yaml:\"type\"`\n\tKey        string `json:\"key,omitempty\"        yaml:\"key,omitempty\"`\n\tOperation  string `json:\"operation\"            yaml:\"operation\"`\n\tValue      string `json:\"value\"                yaml:\"value\"`\n\tMergedFrom string `json:\"mergedFrom,omitempty\" yaml:\"mergedFrom,omitempty\"`\n}\n\n// ProfileExportRequest is a request for a profile export.\ntype ProfileExportRequest struct {\n\tID string `json:\"id\"`\n}\n\n// ProfileImportRequest is a request to import Profile.\ntype ProfileImportRequest struct {\n\tImportRequest `json:\",inline\"`\n\n\t// AllowUnknown allows the import of unknown settings.\n\t// Otherwise, attempting to import an unknown setting will result in an error.\n\tAllowUnknown bool `json:\"allowUnknown\"`\n\n\t// AllowReplace allows the import to replace other existing profiles.\n\tAllowReplace bool `json:\"allowReplaceProfiles\"`\n\n\tExport *ProfileExport `json:\"export\"`\n}\n\n// ProfileImportResult is returned by successful import operations.\ntype ProfileImportResult struct {\n\tImportResult `json:\",inline\"`\n\n\tReplacesProfiles []string `json:\"replacesProfiles\"`\n}\n\nfunc registerProfileAPI() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Export App Profile\",\n\t\tDescription: \"Exports app fingerprints, settings and metadata in a share-able format.\",\n\t\tPath:        \"sync/profile/export\",\n\t\tRead:        api.PermitAdmin,\n\t\tWrite:       api.PermitAdmin,\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"id\",\n\t\t\tDescription: \"Specify scoped profile ID to export.\",\n\t\t}},\n\t\tDataFunc: handleExportProfile,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Import App Profile\",\n\t\tDescription: \"Imports full app profiles, including fingerprints, setting and metadata from the share-able format.\",\n\t\tPath:        \"sync/profile/import\",\n\t\tRead:        api.PermitAdmin,\n\t\tWrite:       api.PermitAdmin,\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodPost,\n\t\t\t\tField:       \"allowReplace\",\n\t\t\t\tDescription: \"Allow replacing existing profiles.\",\n\t\t\t}, {\n\t\t\t\tMethod:      http.MethodPost,\n\t\t\t\tField:       \"validate\",\n\t\t\t\tDescription: \"Validate only.\",\n\t\t\t}, {\n\t\t\t\tMethod:      http.MethodPost,\n\t\t\t\tField:       \"reset\",\n\t\t\t\tDescription: \"Replace all existing settings.\",\n\t\t\t}, {\n\t\t\t\tMethod:      http.MethodPost,\n\t\t\t\tField:       \"allowUnknown\",\n\t\t\t\tDescription: \"Allow importing of unknown values.\",\n\t\t\t},\n\t\t},\n\t\tStructFunc: handleImportProfile,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleExportProfile(ar *api.Request) (data []byte, err error) {\n\tvar request *ProfileExportRequest\n\n\t// Get parameters.\n\tq := ar.URL.Query()\n\tif len(q) > 0 {\n\t\trequest = &ProfileExportRequest{\n\t\t\tID: q.Get(\"id\"),\n\t\t}\n\t} else {\n\t\trequest = &ProfileExportRequest{}\n\t\tif err := json.Unmarshal(ar.InputData, request); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to parse export request: %w\", ErrExportFailed, err)\n\t\t}\n\t}\n\n\t// Check parameters.\n\tif request.ID == \"\" {\n\t\treturn nil, errors.New(\"missing parameters\")\n\t}\n\n\t// Export.\n\texport, err := ExportProfile(request.ID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn serializeProfileExport(export, ar)\n}\n\nfunc handleImportProfile(ar *api.Request) (any, error) {\n\tvar request ProfileImportRequest\n\n\t// Get parameters.\n\tq := ar.URL.Query()\n\tif len(q) > 0 {\n\t\trequest = ProfileImportRequest{\n\t\t\tImportRequest: ImportRequest{\n\t\t\t\tValidateOnly: q.Has(\"validate\"),\n\t\t\t\tRawExport:    string(ar.InputData),\n\t\t\t\tRawMime:      ar.Header.Get(\"Content-Type\"),\n\t\t\t},\n\t\t\tAllowUnknown: q.Has(\"allowUnknown\"),\n\t\t\tAllowReplace: q.Has(\"allowReplace\"),\n\t\t}\n\t} else {\n\t\tif err := json.Unmarshal(ar.InputData, &request); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to parse import request: %w\", ErrInvalidImportRequest, err)\n\t\t}\n\t}\n\n\t// Check if we need to parse the export.\n\tswitch {\n\tcase request.Export != nil && request.RawExport != \"\":\n\t\treturn nil, fmt.Errorf(\"%w: both Export and RawExport are defined\", ErrInvalidImportRequest)\n\tcase request.RawExport != \"\":\n\t\t// Parse export.\n\t\texport := &ProfileExport{}\n\t\tif err := parseExport(&request.ImportRequest, export); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trequest.Export = export\n\tcase request.Export != nil:\n\t\t// Export is aleady parsed.\n\tdefault:\n\t\treturn nil, ErrInvalidImportRequest\n\t}\n\n\t// Import.\n\treturn ImportProfile(&request, profile.SourceLocal)\n}\n\n// ExportProfile exports a profile.\nfunc ExportProfile(scopedID string) (*ProfileExport, error) {\n\t// Get Profile.\n\tr, err := db.Get(profile.ProfilesDBPath + scopedID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to find profile: %w\", ErrTargetNotFound, err)\n\t}\n\tp, err := profile.EnsureProfile(r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to load profile: %w\", ErrExportFailed, err)\n\t}\n\n\t// Copy exportable profile data.\n\texport := &ProfileExport{\n\t\tType: TypeProfile,\n\n\t\t// Identification\n\t\tID:     p.ID,\n\t\tSource: p.Source,\n\n\t\t// Human Metadata\n\t\tName:                p.Name,\n\t\tDescription:         p.Description,\n\t\tHomepage:            p.Homepage,\n\t\tPresentationPath:    p.PresentationPath,\n\t\tUsePresentationPath: p.UsePresentationPath,\n\n\t\t// Process matching\n\t\tFingerprints: convertFingerprintsToExport(p.Fingerprints),\n\n\t\t// Settings\n\t\tConfig: p.Config,\n\n\t\t// Metadata\n\t\tInternal: p.Internal,\n\t}\n\t// Add optional timestamps.\n\tif p.LastEdited > 0 {\n\t\tlastEdited := time.Unix(p.LastEdited, 0)\n\t\texport.LastEdited = &lastEdited\n\t}\n\tif p.Created > 0 {\n\t\tcreated := time.Unix(p.Created, 0)\n\t\texport.Created = &created\n\t}\n\n\t// Derive ID to ensure the ID is always correct.\n\texport.ID = profile.DeriveProfileID(p.Fingerprints)\n\n\t// Add first exportable icon to export.\n\tif len(p.Icons) > 0 {\n\t\tvar err error\n\t\tfor _, icon := range p.Icons {\n\t\t\tvar iconDataURL string\n\t\t\ticonDataURL, err = icon.GetIconAsDataURL()\n\t\t\tif err == nil {\n\t\t\t\texport.IconData = iconDataURL\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to export icon: %w\", ErrExportFailed, err)\n\t\t}\n\t}\n\n\t// Remove presentation path if both Name and Icon are set.\n\tif export.Name != \"\" && export.IconData != \"\" {\n\t\tp.UsePresentationPath = false\n\t}\n\tif !p.UsePresentationPath {\n\t\tp.PresentationPath = \"\"\n\t}\n\n\treturn export, nil\n}\n\n// ImportProfile imports a profile.\nfunc ImportProfile(r *ProfileImportRequest, requiredProfileSource profile.ProfileSource) (*ProfileImportResult, error) {\n\t// Check import.\n\tif r.Export.Type != TypeProfile {\n\t\treturn nil, ErrMismatch\n\t}\n\n\t// Check Source.\n\tif r.Export.Source != \"\" && r.Export.Source != requiredProfileSource {\n\t\treturn nil, ErrMismatch\n\t}\n\t// Convert fingerprints to internal representation.\n\tfingerprints := convertFingerprintsToInternal(r.Export.Fingerprints)\n\tif len(fingerprints) == 0 {\n\t\treturn nil, fmt.Errorf(\"%w: the export contains no fingerprints\", ErrInvalidProfileData)\n\t}\n\t// Derive ID from fingerprints.\n\tprofileID := profile.DeriveProfileID(fingerprints)\n\tif r.Export.ID != \"\" && r.Export.ID != profileID {\n\t\treturn nil, fmt.Errorf(\"%w: the export profile ID does not match the fingerprints, remove to ignore\", ErrInvalidProfileData)\n\t}\n\tr.Export.ID = profileID\n\t// Check Fingerprints.\n\t_, err := profile.ParseFingerprints(fingerprints, \"\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: the export contains invalid fingerprints: %w\", ErrInvalidProfileData, err)\n\t}\n\n\t// Flatten config.\n\tsettings := config.Flatten(r.Export.Config)\n\n\t// Check settings.\n\tsettingsResult, globalOnlySettingFound, err := checkSettings(settings)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif settingsResult.ContainsUnknown && !r.AllowUnknown && !r.ValidateOnly {\n\t\treturn nil, fmt.Errorf(\"%w: the export contains unknown settings\", ErrInvalidImportRequest)\n\t}\n\t// Check if a setting is settable per app.\n\tif globalOnlySettingFound {\n\t\treturn nil, fmt.Errorf(\"%w: export contains settings that cannot be set per app\", ErrNotSettablePerApp)\n\t}\n\n\t// Create result based on settings result.\n\tresult := &ProfileImportResult{\n\t\tImportResult: *settingsResult,\n\t}\n\n\t// Check if the profile already exists.\n\texists, err := db.Exists(profile.MakeProfileKey(r.Export.Source, r.Export.ID))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"internal import error: %w\", err)\n\t}\n\tif exists {\n\t\tresult.ReplacesExisting = true\n\t}\n\n\t// Check if import will delete any profiles.\n\trequiredSourcePrefix := string(r.Export.Source) + \"/\"\n\tresult.ReplacesProfiles = make([]string, 0, len(r.Export.Fingerprints))\n\tfor _, fp := range r.Export.Fingerprints {\n\t\tif fp.MergedFrom != \"\" {\n\t\t\tif !strings.HasPrefix(fp.MergedFrom, requiredSourcePrefix) {\n\t\t\t\treturn nil, fmt.Errorf(\"%w: exported profile was merged from different profile source\", ErrInvalidImportRequest)\n\t\t\t}\n\t\t\texists, err := db.Exists(profile.ProfilesDBPath + fp.MergedFrom)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"internal import error: %w\", err)\n\t\t\t}\n\t\t\tif exists {\n\t\t\t\tresult.ReplacesProfiles = append(result.ReplacesProfiles, fp.MergedFrom)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Stop here if we are only validating.\n\tif r.ValidateOnly {\n\t\treturn result, nil\n\t}\n\tif result.ReplacesExisting && !r.AllowReplace {\n\t\treturn nil, fmt.Errorf(\"%w: import would replace existing profile\", ErrImportFailed)\n\t}\n\n\t// Create profile from export.\n\t// Note: Don't use profile.New(), as this will not trigger a profile refresh if active.\n\tin := r.Export\n\tp := &profile.Profile{\n\t\t// Identification\n\t\tID:     in.ID,\n\t\tSource: requiredProfileSource,\n\n\t\t// Human Metadata\n\t\tName:                in.Name,\n\t\tDescription:         in.Description,\n\t\tHomepage:            in.Homepage,\n\t\tPresentationPath:    in.PresentationPath,\n\t\tUsePresentationPath: in.UsePresentationPath,\n\n\t\t// Process matching\n\t\tFingerprints: fingerprints,\n\n\t\t// Settings\n\t\tConfig: in.Config,\n\n\t\t// Metadata\n\t\tInternal: in.Internal,\n\t}\n\t// Add optional timestamps.\n\tif in.LastEdited != nil {\n\t\tp.LastEdited = in.LastEdited.Unix()\n\t}\n\tif in.Created != nil {\n\t\tp.Created = in.Created.Unix()\n\t}\n\n\t// Fill in required values.\n\tif p.Config == nil {\n\t\tp.Config = make(map[string]any)\n\t}\n\tif p.Created == 0 {\n\t\tp.Created = time.Now().Unix()\n\t}\n\n\t// Add icon to profile, if set.\n\tif in.IconData != \"\" {\n\t\tdu, err := dataurl.DecodeString(in.IconData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: icon data is invalid: %w\", ErrImportFailed, err)\n\t\t}\n\t\tfilename, err := binmeta.UpdateProfileIcon(du.Data, du.MediaType.Subtype)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: icon is invalid: %w\", ErrImportFailed, err)\n\t\t}\n\t\tp.Icons = []binmeta.Icon{{\n\t\t\tType:   binmeta.IconTypeAPI,\n\t\t\tValue:  filename,\n\t\t\tSource: binmeta.IconSourceImport,\n\t\t}}\n\t}\n\n\t// Save profile to db.\n\tp.SetKey(profile.MakeProfileKey(p.Source, p.ID))\n\terr = p.Save()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to save profile: %w\", ErrImportFailed, err)\n\t}\n\n\t// Delete profiles that were merged into the imported profile.\n\tfor _, profileID := range result.ReplacesProfiles {\n\t\terr := db.Delete(profile.ProfilesDBPath + profileID)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"sync: failed to delete merged profile %s on import: %s\", profileID, err)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc convertFingerprintsToExport(fingerprints []profile.Fingerprint) []ProfileFingerprint {\n\tconverted := make([]ProfileFingerprint, 0, len(fingerprints))\n\tfor _, fp := range fingerprints {\n\t\tconverted = append(converted, ProfileFingerprint{\n\t\t\tType:       fp.Type,\n\t\t\tKey:        fp.Key,\n\t\t\tOperation:  fp.Operation,\n\t\t\tValue:      fp.Value,\n\t\t\tMergedFrom: fp.MergedFrom,\n\t\t})\n\t}\n\treturn converted\n}\n\nfunc convertFingerprintsToInternal(fingerprints []ProfileFingerprint) []profile.Fingerprint {\n\tconverted := make([]profile.Fingerprint, 0, len(fingerprints))\n\tfor _, fp := range fingerprints {\n\t\tconverted = append(converted, profile.Fingerprint{\n\t\t\tType:       fp.Type,\n\t\t\tKey:        fp.Key,\n\t\t\tOperation:  fp.Operation,\n\t\t\tValue:      fp.Value,\n\t\t\tMergedFrom: fp.MergedFrom,\n\t\t})\n\t}\n\treturn converted\n}\n"
  },
  {
    "path": "service/sync/setting_single.go",
    "content": "package sync\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// SingleSettingExport holds an export of a single setting.\ntype SingleSettingExport struct {\n\tType Type   `json:\"type\" yaml:\"type\"` // Must be TypeSingleSetting\n\tID   string `json:\"id\"   yaml:\"id\"`   // Settings Key\n\n\tValue any `json:\"value\" yaml:\"value\"`\n}\n\n// SingleSettingImportRequest is a request to import a single setting.\ntype SingleSettingImportRequest struct {\n\tImportRequest `json:\",inline\"`\n\n\tExport *SingleSettingExport `json:\"export\"`\n}\n\nfunc registerSingleSettingAPI() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Export Single Setting\",\n\t\tDescription: \"Exports a single setting in a share-able format.\",\n\t\tPath:        \"sync/single-setting/export\",\n\t\tRead:        api.PermitAdmin,\n\t\tWrite:       api.PermitAdmin,\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"from\",\n\t\t\tDescription: \"Specify where to export from.\",\n\t\t}, {\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"key\",\n\t\t\tDescription: \"Specify which settings key to export.\",\n\t\t}},\n\t\tDataFunc: handleExportSingleSetting,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Import Single Setting\",\n\t\tDescription: \"Imports a single setting from the share-able format.\",\n\t\tPath:        \"sync/single-setting/import\",\n\t\tRead:        api.PermitAdmin,\n\t\tWrite:       api.PermitAdmin,\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodPost,\n\t\t\tField:       \"to\",\n\t\t\tDescription: \"Specify where to import to.\",\n\t\t}, {\n\t\t\tMethod:      http.MethodPost,\n\t\t\tField:       \"key\",\n\t\t\tDescription: \"Specify which setting key to import.\",\n\t\t}, {\n\t\t\tMethod:      http.MethodPost,\n\t\t\tField:       \"validate\",\n\t\t\tDescription: \"Validate only.\",\n\t\t}},\n\t\tStructFunc: handleImportSingleSetting,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleExportSingleSetting(ar *api.Request) (data []byte, err error) {\n\tvar request *ExportRequest\n\n\t// Get parameters.\n\tq := ar.URL.Query()\n\tif len(q) > 0 {\n\t\trequest = &ExportRequest{\n\t\t\tFrom: q.Get(\"from\"),\n\t\t\tKeys: q[\"key\"], // Get []string by direct map access.\n\t\t}\n\t} else {\n\t\trequest = &ExportRequest{}\n\t\tif err := json.Unmarshal(ar.InputData, request); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to parse export request: %w\", ErrExportFailed, err)\n\t\t}\n\t}\n\n\t// Check parameters.\n\tif request.From == \"\" || len(request.Keys) != 1 {\n\t\treturn nil, errors.New(\"missing or malformed parameters\")\n\t}\n\n\t// Export.\n\texport, err := ExportSingleSetting(request.Keys[0], request.From)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn serializeExport(export, ar)\n}\n\nfunc handleImportSingleSetting(ar *api.Request) (any, error) {\n\tvar request *SingleSettingImportRequest\n\n\t// Get parameters.\n\tq := ar.URL.Query()\n\tif len(q) > 0 {\n\t\trequest = &SingleSettingImportRequest{\n\t\t\tImportRequest: ImportRequest{\n\t\t\t\tTarget:       q.Get(\"to\"),\n\t\t\t\tValidateOnly: q.Has(\"validate\"),\n\t\t\t\tRawExport:    string(ar.InputData),\n\t\t\t\tRawMime:      ar.Header.Get(\"Content-Type\"),\n\t\t\t},\n\t\t}\n\t} else {\n\t\trequest = &SingleSettingImportRequest{}\n\t\tif _, err := dsd.MimeLoad(ar.InputData, ar.Header.Get(\"Accept\"), request); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to parse import request: %w\", ErrInvalidImportRequest, err)\n\t\t}\n\t}\n\n\t// Check if we need to parse the export.\n\tswitch {\n\tcase request.Export != nil && request.RawExport != \"\":\n\t\treturn nil, fmt.Errorf(\"%w: both Export and RawExport are defined\", ErrInvalidImportRequest)\n\tcase request.RawExport != \"\":\n\t\t// Parse export.\n\t\texport := &SingleSettingExport{}\n\t\tif err := parseExport(&request.ImportRequest, export); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trequest.Export = export\n\tcase request.Export != nil:\n\t\t// Export is aleady parsed.\n\tdefault:\n\t\treturn nil, ErrInvalidImportRequest\n\t}\n\n\t// Optional check if the setting key matches.\n\tif len(q) > 0 && q.Has(\"key\") && q.Get(\"key\") != request.Export.ID {\n\t\treturn nil, ErrMismatch\n\t}\n\n\t// Import.\n\treturn ImportSingeSetting(request)\n}\n\n// ExportSingleSetting export a single setting.\nfunc ExportSingleSetting(key, from string) (*SingleSettingExport, error) {\n\toption, err := config.GetOption(key)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: configuration %w\", ErrSettingNotFound, err)\n\t}\n\n\tvar value any\n\tif from == ExportTargetGlobal {\n\t\tvalue = option.UserValue()\n\t\tif value == nil {\n\t\t\treturn nil, ErrUnchanged\n\t\t}\n\t} else {\n\t\t// Check if the setting is settable per app.\n\t\tif !option.AnnotationEquals(config.SettablePerAppAnnotation, true) {\n\t\t\treturn nil, ErrNotSettablePerApp\n\t\t}\n\t\t// Get and load profile.\n\t\tr, err := db.Get(profile.ProfilesDBPath + from)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to find profile: %w\", ErrTargetNotFound, err)\n\t\t}\n\t\tp, err := profile.EnsureProfile(r)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to load profile: %w\", ErrExportFailed, err)\n\t\t}\n\t\t// Flatten config and get key we are looking for.\n\t\tflattened := config.Flatten(p.Config)\n\t\tvalue = flattened[key]\n\t\tif value == nil {\n\t\t\treturn nil, ErrUnchanged\n\t\t}\n\t}\n\n\treturn &SingleSettingExport{\n\t\tType:  TypeSingleSetting,\n\t\tID:    key,\n\t\tValue: value,\n\t}, nil\n}\n\n// ImportSingeSetting imports a single setting.\nfunc ImportSingeSetting(r *SingleSettingImportRequest) (*ImportResult, error) {\n\t// Check import.\n\tif r.Export.Type != TypeSingleSetting {\n\t\treturn nil, ErrMismatch\n\t}\n\n\t// Get option and validate value.\n\toption, err := config.GetOption(r.Export.ID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: configuration %w\", ErrSettingNotFound, err)\n\t}\n\tif err := option.ValidateValue(r.Export.Value); err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: %w\", ErrInvalidSettingValue, err)\n\t}\n\n\t// Import single global setting.\n\tif r.Target == ExportTargetGlobal {\n\t\t// Stop here if we are only validating.\n\t\tif r.ValidateOnly {\n\t\t\treturn &ImportResult{\n\t\t\t\tRestartRequired:  option.RequiresRestart,\n\t\t\t\tReplacesExisting: option.IsSetByUser(),\n\t\t\t}, nil\n\t\t}\n\n\t\t// Actually import the setting.\n\t\tif err := config.SetConfigOption(r.Export.ID, r.Export.Value); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %w\", ErrInvalidSettingValue, err)\n\t\t}\n\t} else {\n\t\t// Check if the setting is settable per app.\n\t\tif !option.AnnotationEquals(config.SettablePerAppAnnotation, true) {\n\t\t\treturn nil, ErrNotSettablePerApp\n\t\t}\n\t\t// Import single setting into profile.\n\t\trec, err := db.Get(profile.ProfilesDBPath + r.Target)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to find profile: %w\", ErrTargetNotFound, err)\n\t\t}\n\t\tp, err := profile.EnsureProfile(rec)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to load profile: %w\", ErrImportFailed, err)\n\t\t}\n\n\t\t// Stop here if we are only validating.\n\t\tif r.ValidateOnly {\n\t\t\treturn &ImportResult{\n\t\t\t\tRestartRequired:  option.RequiresRestart,\n\t\t\t\tReplacesExisting: option.IsSetByUser(),\n\t\t\t}, nil\n\t\t}\n\n\t\t// Set imported setting on profile.\n\t\tconfig.PutValueIntoHierarchicalConfig(p.Config, r.Export.ID, r.Export.Value)\n\n\t\t// Mark profile as edited by user.\n\t\tp.LastEdited = time.Now().Unix()\n\n\t\t// Save profile back to db.\n\t\tif err := p.Save(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to save profile: %w\", ErrImportFailed, err)\n\t\t}\n\t}\n\n\treturn &ImportResult{\n\t\tRestartRequired:  option.RequiresRestart,\n\t\tReplacesExisting: option.IsSetByUser(),\n\t}, nil\n}\n"
  },
  {
    "path": "service/sync/settings.go",
    "content": "package sync\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\n// SettingsExport holds an export of settings.\ntype SettingsExport struct {\n\tType Type `json:\"type\" yaml:\"type\"`\n\n\tConfig map[string]any `json:\"config\" yaml:\"config\"`\n}\n\n// SettingsImportRequest is a request to import settings.\ntype SettingsImportRequest struct {\n\tImportRequest `json:\",inline\" yaml:\",inline\"`\n\n\t// Reset all settings of target before import.\n\t// The ImportResult also reacts to this flag and correctly reports whether\n\t// any settings would be replaced or deleted.\n\tReset bool `json:\"reset\" yaml:\"reset\"`\n\n\t// AllowUnknown allows the import of unknown settings.\n\t// Otherwise, attempting to import an unknown setting will result in an error.\n\tAllowUnknown bool `json:\"allowUnknown\" yaml:\"allowUnknown\"`\n\n\tExport *SettingsExport `json:\"export\" yaml:\"export\"`\n}\n\nfunc registerSettingsAPI() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Export Settings\",\n\t\tDescription: \"Exports settings in a share-able format.\",\n\t\tPath:        \"sync/settings/export\",\n\t\tRead:        api.PermitAdmin,\n\t\tWrite:       api.PermitAdmin,\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"from\",\n\t\t\tDescription: \"Specify where to export from.\",\n\t\t}, {\n\t\t\tMethod:      http.MethodGet,\n\t\t\tField:       \"key\",\n\t\t\tDescription: \"Optionally select a single setting to export. Repeat to export selection.\",\n\t\t}},\n\t\tDataFunc: handleExportSettings,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tName:        \"Import Settings\",\n\t\tDescription: \"Imports settings from the share-able format.\",\n\t\tPath:        \"sync/settings/import\",\n\t\tRead:        api.PermitAdmin,\n\t\tWrite:       api.PermitAdmin,\n\t\tParameters: []api.Parameter{{\n\t\t\tMethod:      http.MethodPost,\n\t\t\tField:       \"to\",\n\t\t\tDescription: \"Specify where to import to.\",\n\t\t}, {\n\t\t\tMethod:      http.MethodPost,\n\t\t\tField:       \"validate\",\n\t\t\tDescription: \"Validate only.\",\n\t\t}, {\n\t\t\tMethod:      http.MethodPost,\n\t\t\tField:       \"reset\",\n\t\t\tDescription: \"Replace all existing settings.\",\n\t\t}, {\n\t\t\tMethod:      http.MethodPost,\n\t\t\tField:       \"allowUnknown\",\n\t\t\tDescription: \"Allow importing of unknown values.\",\n\t\t}},\n\t\tStructFunc: handleImportSettings,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleExportSettings(ar *api.Request) (data []byte, err error) {\n\tvar request *ExportRequest\n\n\t// Get parameters.\n\tq := ar.URL.Query()\n\tif len(q) > 0 {\n\t\trequest = &ExportRequest{\n\t\t\tFrom: q.Get(\"from\"),\n\t\t\tKeys: q[\"key\"], // Get []string by direct map access.\n\t\t}\n\t} else {\n\t\trequest = &ExportRequest{}\n\t\tif err := json.Unmarshal(ar.InputData, request); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to parse export request: %w\", ErrExportFailed, err)\n\t\t}\n\t}\n\n\t// Check parameters.\n\tif request.From == \"\" {\n\t\treturn nil, errors.New(\"missing parameters\")\n\t}\n\n\t// Export.\n\texport, err := ExportSettings(request.From, request.Keys)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn serializeExport(export, ar)\n}\n\nfunc handleImportSettings(ar *api.Request) (any, error) {\n\tvar request *SettingsImportRequest\n\n\t// Get parameters.\n\tq := ar.URL.Query()\n\tif len(q) > 0 {\n\t\trequest = &SettingsImportRequest{\n\t\t\tImportRequest: ImportRequest{\n\t\t\t\tTarget:       q.Get(\"to\"),\n\t\t\t\tValidateOnly: q.Has(\"validate\"),\n\t\t\t\tRawExport:    string(ar.InputData),\n\t\t\t\tRawMime:      ar.Header.Get(\"Content-Type\"),\n\t\t\t},\n\t\t\tReset:        q.Has(\"reset\"),\n\t\t\tAllowUnknown: q.Has(\"allowUnknown\"),\n\t\t}\n\t} else {\n\t\trequest = &SettingsImportRequest{}\n\t\tif err := json.Unmarshal(ar.InputData, request); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to parse import request: %w\", ErrInvalidImportRequest, err)\n\t\t}\n\t}\n\n\t// Check if we need to parse the export.\n\tswitch {\n\tcase request.Export != nil && request.RawExport != \"\":\n\t\treturn nil, fmt.Errorf(\"%w: both Export and RawExport are defined\", ErrInvalidImportRequest)\n\tcase request.RawExport != \"\":\n\t\t// Parse export.\n\t\texport := &SettingsExport{}\n\t\tif err := parseExport(&request.ImportRequest, export); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trequest.Export = export\n\tcase request.Export != nil:\n\t\t// Export is already parsed.\n\tdefault:\n\t\treturn nil, ErrInvalidImportRequest\n\t}\n\n\t// Import.\n\treturn ImportSettings(request)\n}\n\n// ExportSettings exports the global settings.\nfunc ExportSettings(from string, keys []string) (*SettingsExport, error) {\n\tvar settings map[string]any\n\tif from == ExportTargetGlobal {\n\t\t// Collect all changed global settings.\n\t\tsettings = make(map[string]any)\n\t\t_ = config.ForEachOption(func(option *config.Option) error {\n\t\t\tv := option.UserValue()\n\t\t\tif v != nil {\n\t\t\t\tsettings[option.Key] = v\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t} else {\n\t\tr, err := db.Get(profile.ProfilesDBPath + from)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to find profile: %w\", ErrTargetNotFound, err)\n\t\t}\n\t\tp, err := profile.EnsureProfile(r)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: failed to load profile: %w\", ErrExportFailed, err)\n\t\t}\n\t\tsettings = config.Flatten(p.Config)\n\t}\n\n\t// Only extract some setting keys, if wanted.\n\tif len(keys) > 0 {\n\t\tselection := make(map[string]any, len(keys))\n\t\tfor _, key := range keys {\n\t\t\tif v, ok := settings[key]; ok {\n\t\t\t\tselection[key] = v\n\t\t\t}\n\t\t}\n\t\tsettings = selection\n\t}\n\n\t// Check if there any changed settings.\n\tif len(settings) == 0 {\n\t\treturn nil, ErrUnchanged\n\t}\n\n\t// Expand config to hierarchical form.\n\tsettings = config.Expand(settings)\n\n\treturn &SettingsExport{\n\t\tType:   TypeSettings,\n\t\tConfig: settings,\n\t}, nil\n}\n\n// ImportSettings imports the global settings.\nfunc ImportSettings(r *SettingsImportRequest) (*ImportResult, error) {\n\t// Check import.\n\tif r.Export.Type != TypeSettings {\n\t\treturn nil, ErrMismatch\n\t}\n\t// Flatten config.\n\tsettings := config.Flatten(r.Export.Config)\n\n\t// Check settings.\n\tresult, globalOnlySettingFound, err := checkSettings(settings)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif result.ContainsUnknown && !r.AllowUnknown && !r.ValidateOnly {\n\t\treturn nil, fmt.Errorf(\"%w: the export contains unknown settings\", ErrInvalidImportRequest)\n\t}\n\n\t// Import global settings.\n\tif r.Target == ExportTargetGlobal {\n\t\t// Stop here if we are only validating.\n\t\tif r.ValidateOnly {\n\t\t\treturn result, nil\n\t\t}\n\n\t\t// Import to global config.\n\t\tvErrs, restartRequired := config.ReplaceConfig(settings)\n\t\tif len(vErrs) > 0 {\n\t\t\ts := make([]string, 0, len(vErrs))\n\t\t\tfor _, err := range vErrs {\n\t\t\t\ts = append(s, err.Error())\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"%w: the supplied configuration could not be applied:\\n%s\",\n\t\t\t\tErrImportFailed,\n\t\t\t\tstrings.Join(s, \"\\n\"),\n\t\t\t)\n\t\t}\n\n\t\t// Save new config to disk.\n\t\terr := config.SaveConfig()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to save config: %w\", err)\n\t\t}\n\n\t\tresult.RestartRequired = restartRequired\n\t\treturn result, nil\n\t}\n\n\t// Check if a setting is settable per app.\n\tif globalOnlySettingFound {\n\t\treturn nil, fmt.Errorf(\"%w: export contains settings that cannot be set per app\", ErrNotSettablePerApp)\n\t}\n\n\t// Get and load profile.\n\trec, err := db.Get(profile.ProfilesDBPath + r.Target)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to find profile: %w\", ErrTargetNotFound, err)\n\t}\n\tp, err := profile.EnsureProfile(rec)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to load profile: %w\", ErrImportFailed, err)\n\t}\n\n\t// Stop here if we are only validating.\n\tif r.ValidateOnly {\n\t\treturn result, nil\n\t}\n\n\t// Import settings into profile.\n\tif r.Reset {\n\t\tp.Config = config.Expand(settings)\n\t} else {\n\t\tfor k, v := range settings {\n\t\t\tconfig.PutValueIntoHierarchicalConfig(p.Config, k, v)\n\t\t}\n\t}\n\n\t// Mark profile as edited by user.\n\tp.LastEdited = time.Now().Unix()\n\n\t// Save profile back to db.\n\terr = p.Save()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to save profile: %w\", ErrImportFailed, err)\n\t}\n\n\treturn result, nil\n}\n\nfunc checkSettings(settings map[string]any) (result *ImportResult, globalOnlySettingFound bool, err error) {\n\tresult = &ImportResult{}\n\n\t// Validate config and gather some metadata.\n\tvar checked int\n\terr = config.ForEachOption(func(option *config.Option) error {\n\t\t// Check if any setting is set.\n\t\t// TODO: Fix this - it only checks for global settings.\n\t\t// if r.Reset && option.IsSetByUser() {\n\t\t// \tresult.ReplacesExisting = true\n\t\t// }\n\n\t\tnewValue, ok := settings[option.Key]\n\t\tif ok {\n\t\t\tchecked++\n\n\t\t\t// Validate the new value.\n\t\t\tif err := option.ValidateValue(newValue); err != nil {\n\t\t\t\treturn fmt.Errorf(\"%w: configuration value for %s is invalid: %w\", ErrInvalidSettingValue, option.Key, err)\n\t\t\t}\n\n\t\t\t// Collect metadata.\n\t\t\tif option.RequiresRestart {\n\t\t\t\tresult.RestartRequired = true\n\t\t\t}\n\t\t\t// TODO: Fix this - it only checks for global settings.\n\t\t\t// if !r.Reset && option.IsSetByUser() {\n\t\t\t// \tresult.ReplacesExisting = true\n\t\t\t// }\n\t\t\tif !option.AnnotationEquals(config.SettablePerAppAnnotation, true) {\n\t\t\t\tglobalOnlySettingFound = true\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\tif checked < len(settings) {\n\t\tresult.ContainsUnknown = true\n\t}\n\n\treturn result, globalOnlySettingFound, nil\n}\n"
  },
  {
    "path": "service/sync/util.go",
    "content": "package sync\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\n\tyaml \"gopkg.in/yaml.v3\"\n\n\t\"github.com/safing/jess/filesig\"\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// Type is the type of an export.\ntype Type string\n\n// Export Types.\nconst (\n\tTypeProfile       = \"profile\"\n\tTypeSettings      = \"settings\"\n\tTypeSingleSetting = \"single-setting\"\n)\n\n// Export IDs.\nconst (\n\tExportTargetGlobal = \"global\"\n)\n\n// Messages.\nvar (\n\tMsgNone           = \"\"\n\tMsgValid          = \"Import is valid.\"\n\tMsgSuccess        = \"Import successful.\"\n\tMsgRequireRestart = \"Import successful. Restart required for setting to take effect.\"\n)\n\n// ExportRequest is a request for an export.\ntype ExportRequest struct {\n\tFrom string   `json:\"from\"`\n\tKeys []string `json:\"keys\"`\n}\n\n// ImportRequest is a request to import an export.\ntype ImportRequest struct {\n\t// Where the export should be import to.\n\tTarget string `json:\"target\"`\n\t// Only validate, but do not actually change anything.\n\tValidateOnly bool `json:\"validateOnly\"`\n\n\tRawExport string `json:\"rawExport\"`\n\tRawMime   string `json:\"rawMime\"`\n}\n\n// ImportResult is returned by successful import operations.\ntype ImportResult struct {\n\tRestartRequired  bool `json:\"restartRequired\"`\n\tReplacesExisting bool `json:\"replacesExisting\"`\n\tContainsUnknown  bool `json:\"containsUnknown\"`\n}\n\n// Errors.\nvar (\n\tErrMismatch = api.ErrorWithStatus(\n\t\terrors.New(\"the supplied export cannot be imported here\"),\n\t\thttp.StatusPreconditionFailed,\n\t)\n\tErrSettingNotFound = api.ErrorWithStatus(\n\t\terrors.New(\"setting not found\"),\n\t\thttp.StatusPreconditionFailed,\n\t)\n\tErrTargetNotFound = api.ErrorWithStatus(\n\t\terrors.New(\"import/export target does not exist\"),\n\t\thttp.StatusGone,\n\t)\n\tErrUnchanged = api.ErrorWithStatus(\n\t\terrors.New(\"cannot export unchanged setting\"),\n\t\thttp.StatusGone,\n\t)\n\tErrNotSettablePerApp = api.ErrorWithStatus(\n\t\terrors.New(\"cannot be set per app\"),\n\t\thttp.StatusGone,\n\t)\n\tErrInvalidImportRequest = api.ErrorWithStatus(\n\t\terrors.New(\"invalid import request\"),\n\t\thttp.StatusUnprocessableEntity,\n\t)\n\tErrInvalidSettingValue = api.ErrorWithStatus(\n\t\terrors.New(\"invalid setting value\"),\n\t\thttp.StatusUnprocessableEntity,\n\t)\n\tErrInvalidProfileData = api.ErrorWithStatus(\n\t\terrors.New(\"invalid profile data\"),\n\t\thttp.StatusUnprocessableEntity,\n\t)\n\tErrImportFailed = api.ErrorWithStatus(\n\t\terrors.New(\"import failed\"),\n\t\thttp.StatusInternalServerError,\n\t)\n\tErrExportFailed = api.ErrorWithStatus(\n\t\terrors.New(\"export failed\"),\n\t\thttp.StatusInternalServerError,\n\t)\n)\n\nfunc serializeExport(export any, ar *api.Request) (data []byte, err error) {\n\t// Get format.\n\tformat := dsd.FormatFromAccept(ar.Header.Get(\"Accept\"))\n\n\t// Serialize and add checksum.\n\tswitch format {\n\tcase dsd.JSON:\n\t\tdata, err = json.Marshal(export)\n\t\tif err == nil {\n\t\t\tdata, err = filesig.AddJSONChecksum(data)\n\t\t}\n\tcase dsd.YAML:\n\t\tdata, err = yaml.Marshal(export)\n\t\tif err == nil {\n\t\t\tdata, err = filesig.AddYAMLChecksum(data, filesig.TextPlacementBottom)\n\t\t}\n\tdefault:\n\t\treturn nil, dsd.ErrIncompatibleFormat\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to serialize: %w\", err)\n\t}\n\n\t// Set Content-Type HTTP Header.\n\tar.ResponseHeader.Set(\"Content-Type\", dsd.FormatToMimeType[format])\n\n\treturn data, nil\n}\n\nfunc serializeProfileExport(export *ProfileExport, ar *api.Request) ([]byte, error) {\n\t// Do a regular serialize, if we don't need parts.\n\tswitch {\n\tcase export.IconData == \"\":\n\t\t// With no icon, do a regular export.\n\t\treturn serializeExport(export, ar)\n\tcase dsd.FormatFromAccept(ar.Header.Get(\"Accept\")) != dsd.YAML:\n\t\t// Only export in parts for yaml.\n\t\treturn serializeExport(export, ar)\n\t}\n\n\t// Step 1: Separate profile icon.\n\tprofileIconExport := &ProfileIcon{\n\t\tIconData: export.IconData,\n\t}\n\texport.IconData = \"\"\n\n\t// Step 2: Serialize main export.\n\tprofileData, err := yaml.Marshal(export)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to serialize profile data: %w\", err)\n\t}\n\n\t// Step 3: Serialize icon only.\n\ticonData, err := yaml.Marshal(profileIconExport)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to serialize profile icon: %w\", err)\n\t}\n\n\t// Step 4: Stitch data together and add copyright notice for icon.\n\texportData := container.New(\n\t\tprofileData,\n\t\t[]byte(`\n# The application icon below is the property of its respective owner.\n# The icon is used for identification purposes only, and does not imply any endorsement or affiliation with their respective owners.\n# It is the sole responsibility of the individual or entity sharing this dataset to ensure they have the necessary permissions to do so.\n`),\n\t\ticonData,\n\t).CompileData()\n\n\t// Step 4: Add checksum.\n\texportData, err = filesig.AddYAMLChecksum(exportData, filesig.TextPlacementBottom)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to add checksum: %w\", err)\n\t}\n\n\t// Set Content-Type HTTP Header.\n\tar.ResponseHeader.Set(\"Content-Type\", dsd.FormatToMimeType[dsd.YAML])\n\n\treturn exportData, nil\n}\n\nfunc parseExport(request *ImportRequest, export any) error {\n\tformat, err := dsd.MimeLoad([]byte(request.RawExport), request.RawMime, export)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%w: failed to parse export: %w\", ErrInvalidImportRequest, err)\n\t}\n\n\t// Verify checksum, if available.\n\tswitch format {\n\tcase dsd.JSON:\n\t\terr = filesig.VerifyJSONChecksum([]byte(request.RawExport))\n\tcase dsd.YAML:\n\t\terr = filesig.VerifyYAMLChecksum([]byte(request.RawExport))\n\tdefault:\n\t\t// Checksums not supported.\n\t}\n\tif err != nil && !errors.Is(err, filesig.ErrChecksumMissing) {\n\t\treturn fmt.Errorf(\"failed to verify checksum: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/ui/api.go",
    "content": "package ui\n\nimport (\n\t\"github.com/safing/portmaster/base/api\"\n)\n\nfunc (ui *UI) registerAPIEndpoints() error {\n\treturn api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        \"ui/reload\",\n\t\tWrite:       api.PermitUser,\n\t\tActionFunc:  ui.reloadUI,\n\t\tName:        \"Reload UI Assets\",\n\t\tDescription: \"Removes all assets from the cache and reloads the current (possibly updated) version from disk when requested.\",\n\t})\n}\n\nfunc (ui *UI) reloadUI(_ *api.Request) (msg string, err error) {\n\t// Close all archives.\n\tui.CloseArchives()\n\n\treturn \"all ui archives successfully reloaded\", nil\n}\n"
  },
  {
    "path": "service/ui/module.go",
    "content": "package ui\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/spkg/zipfs\"\n)\n\n// UI serves the user interface files.\ntype UI struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tarchives     map[string]*zipfs.FileSystem\n\tarchivesLock sync.RWMutex\n\n\tupgradeLock atomic.Bool\n}\n\n// New returns a new UI module.\nfunc New(instance instance) (*UI, error) {\n\tm := mgr.New(\"UI\")\n\tui := &UI{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tarchives: make(map[string]*zipfs.FileSystem),\n\t}\n\n\tif err := ui.registerAPIEndpoints(); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := ui.registerRoutes(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ui, nil\n}\n\nfunc (ui *UI) Manager() *mgr.Manager {\n\treturn ui.mgr\n}\n\n// Start starts the module.\nfunc (ui *UI) Start() error {\n\t// Create a dummy directory to which processes change their working directory\n\t// to. Currently this includes the App and the Notifier. The aim is protect\n\t// all other directories and increase compatibility should any process want\n\t// to read or write something to the current working directory. This can also\n\t// be useful in the future to dump data to for debugging. The permission used\n\t// may seem dangerous, but proper permission on the parent directory provide\n\t// (some) protection.\n\t// Processes must _never_ read from this directory.\n\texecDir := filepath.Join(ui.instance.DataDir(), \"exec\")\n\terr := os.MkdirAll(execDir, 0o0777) //nolint:gosec // This is intentional.\n\tif err != nil {\n\t\tlog.Warningf(\"ui: failed to create safe exec dir: %s\", err)\n\t}\n\n\t// Ensure directory permission\n\terr = utils.EnsureDirectory(execDir, utils.PublicWriteExecPermission)\n\tif err != nil {\n\t\tlog.Warningf(\"ui: failed to set permissions to directory %s: %s\", execDir, err)\n\t}\n\n\treturn nil\n}\n\n// Stop stops the module.\nfunc (ui *UI) Stop() error {\n\treturn nil\n}\n\nfunc (ui *UI) getArchive(name string) (archive *zipfs.FileSystem, ok bool) {\n\tui.archivesLock.RLock()\n\tdefer ui.archivesLock.RUnlock()\n\n\tarchive, ok = ui.archives[name]\n\treturn\n}\n\nfunc (ui *UI) setArchive(name string, archive *zipfs.FileSystem) {\n\tui.archivesLock.Lock()\n\tdefer ui.archivesLock.Unlock()\n\n\tui.archives[name] = archive\n}\n\n// CloseArchives closes all open archives.\nfunc (ui *UI) CloseArchives() {\n\tif ui == nil {\n\t\treturn\n\t}\n\n\tui.archivesLock.Lock()\n\tdefer ui.archivesLock.Unlock()\n\n\t// Close archives.\n\tfor _, archive := range ui.archives {\n\t\tif err := archive.Close(); err != nil {\n\t\t\tui.mgr.Warn(\"failed to close ui archive\", \"err\", err)\n\t\t}\n\t}\n\n\t// Reset map.\n\tclear(ui.archives)\n}\n\n// EnableUpgradeLock enables the upgrade lock and closes all open archives.\nfunc (ui *UI) EnableUpgradeLock() {\n\tif ui == nil {\n\t\treturn\n\t}\n\n\tui.upgradeLock.Store(true)\n\tui.CloseArchives()\n}\n\n// DisableUpgradeLock disables the upgrade lock.\nfunc (ui *UI) DisableUpgradeLock() {\n\tif ui == nil {\n\t\treturn\n\t}\n\n\tui.upgradeLock.Store(false)\n}\n\ntype instance interface {\n\tDataDir() string\n\tAPI() *api.API\n\tGetBinaryUpdateFile(name string) (path string, err error)\n}\n"
  },
  {
    "path": "service/ui/serve.go",
    "content": "package ui\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/spkg/zipfs\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\nfunc (ui *UI) registerRoutes() error {\n\t// Server assets.\n\tapi.RegisterHandler(\n\t\t\"/assets/{resPath:[a-zA-Z0-9/\\\\._-]+}\",\n\t\t&archiveServer{ui: ui, defaultModuleName: \"assets\"},\n\t)\n\n\t// Add slash to plain module namespaces.\n\tapi.RegisterHandler(\n\t\t\"/ui/modules/{moduleName:[a-z]+}\",\n\t\tapi.WrapInAuthHandler(redirAddSlash, api.PermitAnyone, api.NotSupported),\n\t)\n\n\t// Serve modules.\n\tsrv := &archiveServer{ui: ui}\n\tapi.RegisterHandler(\"/ui/modules/{moduleName:[a-z]+}/\", srv)\n\tapi.RegisterHandler(\"/ui/modules/{moduleName:[a-z]+}/{resPath:[a-zA-Z0-9/\\\\._-]+}\", srv)\n\n\t// Redirect \"/\" to default module.\n\tapi.RegisterHandler(\n\t\t\"/\",\n\t\tapi.WrapInAuthHandler(redirectToDefault, api.PermitAnyone, api.NotSupported),\n\t)\n\n\treturn nil\n}\n\ntype archiveServer struct {\n\tui                *UI\n\tdefaultModuleName string\n}\n\nfunc (bs *archiveServer) ReadPermission(*http.Request) api.Permission { return api.PermitAnyone }\n\nfunc (bs *archiveServer) WritePermission(*http.Request) api.Permission { return api.NotSupported }\n\nfunc (bs *archiveServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\t// Get request context.\n\tar := api.GetAPIRequest(r)\n\tif ar == nil {\n\t\tlog.Errorf(\"ui: missing api request context\")\n\t\thttp.Error(w, \"Internal server error.\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tmoduleName, ok := ar.URLVars[\"moduleName\"]\n\tif !ok {\n\t\tmoduleName = bs.defaultModuleName\n\t\tif moduleName == \"\" {\n\t\t\thttp.Error(w, \"missing module name\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t}\n\n\tresPath, ok := ar.URLVars[\"resPath\"]\n\tif !ok || strings.HasSuffix(resPath, \"/\") {\n\t\tresPath = \"index.html\"\n\t}\n\n\tarchiveFS, ok := bs.ui.getArchive(moduleName)\n\tif ok {\n\t\tServeFileFromArchive(w, r, moduleName, archiveFS, resPath)\n\t\treturn\n\t}\n\n\t// Check if the upgrade lock is enabled.\n\tif bs.ui.upgradeLock.Load() {\n\t\thttp.Error(w, \"Resources locked, upgrade in progress.\", http.StatusLocked)\n\t\treturn\n\t}\n\n\t// get file from update system\n\tzipFile, err := bs.ui.instance.GetBinaryUpdateFile(fmt.Sprintf(\"%s.zip\", moduleName))\n\tif err != nil {\n\t\tlog.Tracef(\"ui: error loading module %s: %s\", moduleName, err)\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Open archive from disk.\n\tarchiveFS, err = zipfs.New(zipFile)\n\tif err != nil {\n\t\tlog.Tracef(\"ui: error prepping module %s: %s\", moduleName, err)\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tbs.ui.setArchive(moduleName, archiveFS)\n\tServeFileFromArchive(w, r, moduleName, archiveFS, resPath)\n}\n\n// ServeFileFromArchive serves a file from the given archive.\nfunc ServeFileFromArchive(w http.ResponseWriter, r *http.Request, archiveName string, archiveFS *zipfs.FileSystem, path string) {\n\treadCloser, err := archiveFS.Open(path)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t// Check if there is a base index.html file we can serve instead.\n\t\t\tvar indexErr error\n\t\t\tpath = \"index.html\"\n\t\t\treadCloser, indexErr = archiveFS.Open(path)\n\t\t\tif indexErr != nil {\n\t\t\t\t// If we cannot get an index, continue with handling the original error.\n\t\t\t\tlog.Tracef(\"ui: requested resource \\\"%s\\\" not found in archive %s: %s\", path, archiveName, err)\n\t\t\t\thttp.Error(w, err.Error(), http.StatusNotFound)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Tracef(\"ui: error opening module %s: %s\", archiveName, err)\n\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// set content type\n\t_, ok := w.Header()[\"Content-Type\"]\n\tif !ok {\n\t\tcontentType, _ := utils.MimeTypeByExtension(filepath.Ext(path))\n\t\tw.Header().Set(\"Content-Type\", contentType)\n\t}\n\n\tw.WriteHeader(http.StatusOK)\n\tif r.Method != http.MethodHead {\n\t\t_, err = io.Copy(w, readCloser)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"ui: failed to serve file: %s\", err)\n\t\t\treturn\n\t\t}\n\t}\n\n\t_ = readCloser.Close()\n}\n\n// redirectToDefault redirects the request to the default UI module.\nfunc redirectToDefault(w http.ResponseWriter, r *http.Request) {\n\tu, err := url.Parse(\"/ui/modules/portmaster/\")\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\thttp.Redirect(w, r, r.URL.ResolveReference(u).String(), http.StatusTemporaryRedirect)\n}\n\n// redirAddSlash redirects the request to the same, but with a trailing slash.\nfunc redirAddSlash(w http.ResponseWriter, r *http.Request) {\n\thttp.Redirect(w, r, r.RequestURI+\"/\", http.StatusPermanentRedirect)\n}\n"
  },
  {
    "path": "service/updates/downloader.go",
    "content": "package updates\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\ntype Downloader struct {\n\tu         *Updater\n\tindex     *Index\n\tindexURLs []string\n\n\texistingFiles map[string]string\n\n\thttpClient http.Client\n}\n\nfunc NewDownloader(u *Updater, indexURLs []string) *Downloader {\n\treturn &Downloader{\n\t\tu:         u,\n\t\tindexURLs: indexURLs,\n\t}\n}\n\nfunc (d *Downloader) updateIndex(ctx context.Context) error {\n\t// Make sure dir exists.\n\terr := utils.EnsureDirectory(d.u.cfg.DownloadDirectory, utils.PublicReadExecPermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create download directory: %s\", d.u.cfg.DownloadDirectory)\n\t}\n\n\t// Try to download the index from one of the index URLs.\n\tvar (\n\t\tindexData []byte\n\t\tindex     *Index\n\t)\n\tfor _, url := range d.indexURLs {\n\t\t// Download and verify index.\n\t\tindexData, index, err = d.getIndex(ctx, url)\n\t\tif err == nil {\n\t\t\t// Valid index found!\n\t\t\tbreak\n\t\t}\n\n\t\tlog.Warningf(\"updates/%s: failed to update index from %q: %s\", d.u.cfg.Name, url, err)\n\t\terr = fmt.Errorf(\"update index file from %q: %w\", url, err)\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"all index URLs failed, last error: %w\", err)\n\t}\n\td.index = index\n\n\t// Write the index into a file.\n\tindexFilepath := filepath.Join(d.u.cfg.DownloadDirectory, d.u.cfg.IndexFile)\n\terr = os.WriteFile(indexFilepath, indexData, utils.PublicReadExecPermission.AsUnixPermission())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"write index file: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (d *Downloader) getIndex(ctx context.Context, url string) (indexData []byte, bundle *Index, err error) {\n\t// Download data from URL.\n\tindexData, err = d.downloadData(ctx, url)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"GET index: %w\", err)\n\t}\n\n\t// Verify and parse index.\n\tbundle, err = ParseIndex(indexData, d.u.cfg.Platform, d.u.cfg.Verify)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"parse index: %w\", err)\n\t}\n\n\treturn indexData, bundle, nil\n}\n\n// gatherExistingFiles gathers the checksums on existing files.\nfunc (d *Downloader) gatherExistingFiles(dir string) error {\n\t// Make sure map is initialized.\n\tif d.existingFiles == nil {\n\t\td.existingFiles = make(map[string]string)\n\t}\n\n\t// Walk directory, just log errors.\n\terr := filepath.WalkDir(dir, func(fullpath string, entry fs.DirEntry, err error) error {\n\t\t// Fail on access error.\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Skip folders.\n\t\tif entry.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Read full file.\n\t\tfileData, err := os.ReadFile(fullpath)\n\t\tif err != nil {\n\t\t\tlog.Debugf(\"updates/%s: failed to read file %q while searching for existing files: %s\", d.u.cfg.Name, fullpath, err)\n\t\t\treturn fmt.Errorf(\"failed to read file %s: %w\", fullpath, err)\n\t\t}\n\n\t\t// Calculate checksum and add it to the existing files.\n\t\thashSum := sha256.Sum256(fileData)\n\t\td.existingFiles[hex.EncodeToString(hashSum[:])] = fullpath\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"searching for existing files: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (d *Downloader) downloadArtifacts(ctx context.Context) error {\n\t// Make sure dir exists.\n\terr := utils.EnsureDirectory(d.u.cfg.DownloadDirectory, utils.PublicReadExecPermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create download directory: %s\", d.u.cfg.DownloadDirectory)\n\t}\n\nartifacts:\n\tfor _, artifact := range d.index.Artifacts {\n\t\tdstFilePath := filepath.Join(d.u.cfg.DownloadDirectory, artifact.Filename)\n\n\t\t// Check if we can copy the artifact from disk instead.\n\t\tif existingFile, ok := d.existingFiles[artifact.SHA256]; ok {\n\t\t\t// Check if this is the same file.\n\t\t\tif existingFile == dstFilePath {\n\t\t\t\tcontinue artifacts\n\t\t\t}\n\t\t\t// Copy and check.\n\t\t\terr = copyAndCheckSHA256Sum(existingFile, dstFilePath, artifact.SHA256, artifact.GetFileMode())\n\t\t\tif err == nil {\n\t\t\t\tcontinue artifacts\n\t\t\t}\n\t\t\tlog.Debugf(\"updates/%s: failed to copy existing file %s: %s\", d.u.cfg.Name, artifact.Filename, err)\n\t\t}\n\n\t\t// Check if the artifact has download URLs.\n\t\tif len(artifact.URLs) == 0 {\n\t\t\treturn fmt.Errorf(\"artifact %s is missing download URLs\", artifact.Filename)\n\t\t}\n\n\t\t// Try to download the artifact from one of the URLs.\n\t\tvar artifactData []byte\n\tartifactURLs:\n\t\tfor _, url := range artifact.URLs {\n\t\t\t// Download and verify index.\n\t\t\tartifactData, err = d.getArtifact(ctx, artifact, url)\n\t\t\tif err == nil {\n\t\t\t\t// Valid artifact found!\n\t\t\t\tbreak artifactURLs\n\t\t\t}\n\t\t\terr = fmt.Errorf(\"update index file from %q: %w\", url, err)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"all artifact URLs for %s failed, last error: %w\", artifact.Filename, err)\n\t\t}\n\n\t\t// Write artifact to temporary file.\n\t\ttmpFilename := dstFilePath + \".download\"\n\t\terr = os.WriteFile(tmpFilename, artifactData, artifact.GetFileMode().AsUnixPermission())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"write %s to temp file: %w\", artifact.Filename, err)\n\t\t}\n\n\t\t_ = utils.SetFilePermission(tmpFilename, artifact.GetFileMode())\n\n\t\t// Rename/Move to actual location.\n\t\terr = os.Rename(tmpFilename, dstFilePath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"rename %s after write: %w\", artifact.Filename, err)\n\t\t}\n\n\t\tlog.Infof(\"updates/%s: downloaded and verified %s\", d.u.cfg.Name, artifact.Filename)\n\t}\n\treturn nil\n}\n\nfunc (d *Downloader) getArtifact(ctx context.Context, artifact *Artifact, url string) ([]byte, error) {\n\t// Download data from URL.\n\tartifactData, err := d.downloadData(ctx, url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"GET artifact: %w\", err)\n\t}\n\n\t// Decompress artifact data, if configured.\n\t// TODO: Normally we should do operations on \"untrusted\" data _after_ verification,\n\t// but we really want the checksum to be for the unpacked data. Should we add another checksum, or is HTTPS enough?\n\tif artifact.Unpack != \"\" {\n\t\tartifactData, err = Decompress(artifact.Unpack, artifactData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decompress: %w\", err)\n\t\t}\n\t}\n\n\t// Verify checksum.\n\tif err := CheckSHA256Sum(artifactData, artifact.SHA256); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn artifactData, nil\n}\n\nfunc (d *Downloader) downloadData(ctx context.Context, url string) ([]byte, error) {\n\t// Setup request.\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create GET request to %s: %w\", url, err)\n\t}\n\tif UserAgent != \"\" {\n\t\treq.Header.Set(\"User-Agent\", UserAgent)\n\t}\n\n\t// Start request with shared http client.\n\tresp, err := d.httpClient.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed a get file request to: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\t// Check for HTTP status errors.\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"server returned non-OK status: %d %s\", resp.StatusCode, resp.Status)\n\t}\n\n\t// Read the full body and return it.\n\tcontent, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read body of response: %w\", err)\n\t}\n\treturn content, nil\n}\n\n// Decompress decompresses the given data according to the specified type.\nfunc Decompress(cType string, fileBytes []byte) ([]byte, error) {\n\tswitch cType {\n\tcase \"zip\":\n\t\treturn decompressZip(fileBytes)\n\tcase \"gz\":\n\t\treturn decompressGzip(fileBytes)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported compression type\")\n\t}\n}\n\nfunc decompressGzip(data []byte) ([]byte, error) {\n\t// Create a gzip reader from the byte slice.\n\tgzipReader, err := gzip.NewReader(bytes.NewReader(data))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create gzip reader: %w\", err)\n\t}\n\tdefer func() { _ = gzipReader.Close() }()\n\n\t// Copy from the gzip reader into a new buffer.\n\tvar buf bytes.Buffer\n\t_, err = io.CopyN(&buf, gzipReader, MaxUnpackSize)\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"read gzip file: %w\", err)\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\nfunc decompressZip(data []byte) ([]byte, error) {\n\t// Create a zip reader from the byte slice.\n\tzipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create zip reader: %w\", err)\n\t}\n\n\t// Ensure there is only one file in the zip.\n\tif len(zipReader.File) != 1 {\n\t\treturn nil, fmt.Errorf(\"zip file must contain exactly one file\")\n\t}\n\n\t// Open single file in the zip.\n\tfile := zipReader.File[0]\n\tfileReader, err := file.Open()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"open file in zip: %w\", err)\n\t}\n\tdefer func() { _ = fileReader.Close() }()\n\n\t// Copy from the zip reader into a new buffer.\n\tvar buf bytes.Buffer\n\t_, err = io.CopyN(&buf, fileReader, MaxUnpackSize)\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"read file in zip: %w\", err)\n\t}\n\n\treturn buf.Bytes(), nil\n}\n"
  },
  {
    "path": "service/updates/index.go",
    "content": "package updates\n\nimport (\n\t\"crypto/sha256\"\n\t\"crypto/subtle\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"time\"\n\n\tsemver \"github.com/hashicorp/go-version\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/jess/filesig\"\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\n// MaxUnpackSize defines the maximum size that is allowed to be unpacked.\nconst MaxUnpackSize = 1 << 30 // 2^30 == 1GB\n\nconst currentPlatform = runtime.GOOS + \"_\" + runtime.GOARCH\n\nvar zeroVersion = semver.Must(semver.NewVersion(\"0.0.0\"))\n\n// Artifact represents a single file with metadata.\ntype Artifact struct {\n\tFilename string   `json:\"Filename\"`\n\tSHA256   string   `json:\"SHA256\"`\n\tURLs     []string `json:\"URLs\"`\n\tPlatform string   `json:\"Platform,omitempty\"`\n\tUnpack   string   `json:\"Unpack,omitempty\"`\n\tVersion  string   `json:\"Version,omitempty\"`\n\n\tlocalFile  string\n\tversionNum *semver.Version\n}\n\n// GetFileMode returns the required filesystem permission for the artifact.\nfunc (a *Artifact) GetFileMode() utils.FSPermission {\n\tif a.Platform == currentPlatform {\n\t\treturn utils.PublicReadExecPermission\n\t}\n\n\treturn utils.PublicReadPermission\n}\n\n// Path returns the absolute path to the local file.\nfunc (a *Artifact) Path() string {\n\treturn a.localFile\n}\n\n// SemVer returns the version of the artifact.\nfunc (a *Artifact) SemVer() *semver.Version {\n\treturn a.versionNum\n}\n\nfunc (a *Artifact) String() string {\n\treturn fmt.Sprintf(\"%s(v%s)\", a.Filename, a.Version)\n}\n\n// IsNewerThan returns whether the artifact is newer than the given artifact.\n// Returns true if the given artifact is nil.\n// The second return value \"ok\" is false when version could not be compared.\n// In this case, it is up to the caller to decide how to proceed.\nfunc (a *Artifact) IsNewerThan(b *Artifact) (newer, ok bool) {\n\tswitch {\n\tcase a == nil:\n\t\treturn false, false\n\tcase b == nil:\n\t\treturn true, true\n\tcase a.versionNum == nil:\n\t\treturn false, false\n\tcase b.versionNum == nil:\n\t\treturn false, false\n\tcase a.versionNum.GreaterThan(b.versionNum):\n\t\treturn true, true\n\tdefault:\n\t\treturn false, true\n\t}\n}\n\nfunc (a *Artifact) export(dir string, indexVersion *semver.Version) *Artifact {\n\tcopied := &Artifact{\n\t\tFilename:   a.Filename,\n\t\tSHA256:     a.SHA256,\n\t\tURLs:       a.URLs,\n\t\tPlatform:   a.Platform,\n\t\tUnpack:     a.Unpack,\n\t\tVersion:    a.Version,\n\t\tlocalFile:  filepath.Join(dir, a.Filename),\n\t\tversionNum: a.versionNum,\n\t}\n\n\t// Make sure we have a version number.\n\tswitch {\n\tcase copied.versionNum != nil:\n\t\t// Version already parsed.\n\tcase copied.Version != \"\":\n\t\t// Need to parse version.\n\t\tv, err := semver.NewVersion(copied.Version)\n\t\tif err == nil {\n\t\t\tcopied.versionNum = v\n\t\t}\n\tdefault:\n\t\t// No version defined, inherit index version.\n\t\tcopied.versionNum = indexVersion\n\t}\n\n\treturn copied\n}\n\n// Index represents a collection of artifacts with metadata.\ntype Index struct {\n\tName      string      `json:\"Name\"`\n\tVersion   string      `json:\"Version\"`\n\tPublished time.Time   `json:\"Published\"`\n\tArtifacts []*Artifact `json:\"Artifacts\"`\n\n\tversionNum *semver.Version\n\n\t// isLocallyGenerated indicates whether the index was generated from a local directory\n\t// rather than downloaded from an official release channel.\n\t//\n\t// When true, the Published field reflects the local generation time rather than an\n\t// official release date. Time-based sanity checks (version/date mismatch detection)\n\t// are therefore skipped when this index is the current one.\n\tisLocallyGenerated bool\n}\n\n// LoadIndex loads and parses an index from the given filename.\n// Leave platform empty to use current platform.\nfunc LoadIndex(filename string, platform string, trustStore jess.TrustStore) (*Index, error) {\n\t// Read index file from disk.\n\tcontent, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read index file: %w\", err)\n\t}\n\n\t// Parse and return.\n\treturn ParseIndex(content, platform, trustStore)\n}\n\n// ParseIndex parses an index from a json string.\n// Leave platform empty to use current platform.\nfunc ParseIndex(jsonContent []byte, platform string, trustStore jess.TrustStore) (*Index, error) {\n\t// Verify signature.\n\tif trustStore != nil {\n\t\tif err := filesig.VerifyJSONSignature(jsonContent, trustStore); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"verify: %w\", err)\n\t\t}\n\t}\n\n\t// Parse json.\n\tindex := &Index{}\n\terr := json.Unmarshal(jsonContent, index)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse index: %w\", err)\n\t}\n\n\t// Check platform.\n\tif platform == \"\" {\n\t\tplatform = currentPlatform\n\t}\n\n\t// Initialize data.\n\terr = index.init(platform)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn index, nil\n}\n\nfunc (index *Index) init(platform string) error {\n\t// Parse version number, if set.\n\tif index.Version != \"\" {\n\t\tversionNum, err := semver.NewVersion(index.Version)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid index version %q: %w\", index.Version, err)\n\t\t}\n\t\tindex.versionNum = versionNum\n\t}\n\n\t// Filter artifacts by platform.\n\tfiltered := make([]*Artifact, 0)\n\tfor _, a := range index.Artifacts {\n\t\tif a.Platform == \"\" || a.Platform == platform {\n\t\t\tfiltered = append(filtered, a)\n\t\t}\n\t}\n\tindex.Artifacts = filtered\n\n\t// Parse artifact version numbers.\n\tfor _, a := range index.Artifacts {\n\t\tif a.Version != \"\" {\n\t\t\tv, err := semver.NewVersion(a.Version)\n\t\t\tif err == nil {\n\t\t\t\ta.versionNum = v\n\t\t\t}\n\t\t} else {\n\t\t\ta.Version = index.Version\n\t\t\ta.versionNum = index.versionNum\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// CanDoUpgrades returns whether the index is able to follow a secure upgrade path.\nfunc (index *Index) CanDoUpgrades() error {\n\tswitch {\n\tcase index.versionNum == nil:\n\t\treturn errors.New(\"missing version number\")\n\n\tcase index.Published.IsZero():\n\t\treturn errors.New(\"missing publish date\")\n\n\tcase index.Published.After(time.Now().Add(15 * time.Minute)):\n\t\treturn fmt.Errorf(\"is from the future (%s)\", time.Until(index.Published).Round(time.Minute))\n\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// ShouldUpgradeTo returns whether the given index is a successor and should be upgraded to.\nfunc (index *Index) ShouldUpgradeTo(newIndex *Index) error {\n\t// Check if both indexes can do upgrades.\n\tif err := index.CanDoUpgrades(); err != nil {\n\t\treturn fmt.Errorf(\"current index cannot do upgrades: %w\", err)\n\t}\n\tif err := newIndex.CanDoUpgrades(); err != nil {\n\t\treturn fmt.Errorf(\"new index cannot do upgrade: %w\", err)\n\t}\n\n\tswitch {\n\tcase index.versionNum.Equal(zeroVersion):\n\t\t// The zero version is used for bootstrapping.\n\t\t// Upgrade in any case.\n\t\treturn nil\n\n\tcase index.Name != newIndex.Name:\n\t\treturn fmt.Errorf(\n\t\t\t\"new index name (%q) does not match current index name (%q)\",\n\t\t\tnewIndex.Name, index.Name,\n\t\t)\n\tcase index.versionNum.LessThan(newIndex.versionNum) && index.Published.After(newIndex.Published) && !index.isLocallyGenerated:\n\t\t// The new index is newer in version (upgrade), but older in publish date. This is suspicious and should be prevented.\n\t\treturn errors.New(\"new index has newer version but older publish date\")\n\n\tcase index.versionNum.GreaterThan(newIndex.versionNum) && index.Published.Before(newIndex.Published) && !index.isLocallyGenerated:\n\t\t// The new index is older in version (downgrade), but newer in publish date. This is suspicious and should be prevented.\n\t\treturn errors.New(\"new index has older version but newer publish date\")\n\n\tcase index.versionNum.Segments()[0] > newIndex.versionNum.Segments()[0]:\n\t\t// Downgrades are allowed, if they are not breaking changes.\n\t\treturn errors.New(\"new index is a breaking change downgrade\")\n\n\tcase index.Published.Equal(newIndex.Published):\n\t\t// \"Do nothing\".\n\t\treturn ErrSameIndex\n\n\tcase index.versionNum.Equal(newIndex.versionNum) && index.isLocallyGenerated:\n\t\t// This is especially important for locally generated indexes, where the publish date is not a reliable indicator of the index's age.\n\t\t// \"Do nothing\".\n\t\treturn ErrSameIndex\n\n\tdefault:\n\t\t// Upgrade!\n\t\treturn nil\n\t}\n}\n\n// VerifyArtifacts checks if all artifacts are present in the given dir and have the correct hash.\nfunc (index *Index) VerifyArtifacts(dir string) error {\n\tfor _, artifact := range index.Artifacts {\n\t\terr := CheckSHA256SumFile(filepath.Join(dir, artifact.Filename), artifact.SHA256)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"verify %s: %w\", artifact.Filename, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (index *Index) Export(signingKey *jess.Signet, trustStore jess.TrustStore) ([]byte, error) {\n\t// Serialize to json.\n\tindexData, err := json.Marshal(index)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"serialize: %w\", err)\n\t}\n\n\t// Do not sign if signing key is not given.\n\tif signingKey == nil {\n\t\treturn indexData, nil\n\t}\n\n\t// Make envelope.\n\tenvelope := jess.NewUnconfiguredEnvelope()\n\tenvelope.SuiteID = jess.SuiteSignV1\n\tenvelope.Senders = []*jess.Signet{signingKey}\n\n\t// Sign json data.\n\tsignedIndex, err := filesig.AddJSONSignature(indexData, envelope, trustStore)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sign: %w\", err)\n\t}\n\n\treturn signedIndex, nil\n}\n\n// CheckSHA256SumFile checks the sha256sum of the given file.\nfunc CheckSHA256SumFile(filename string, sha256sum string) error {\n\t// Check expected hash.\n\texpectedDigest, err := hex.DecodeString(sha256sum)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid hex encoding for expected hash %s: %w\", sha256sum, err)\n\t}\n\tif len(expectedDigest) != sha256.Size {\n\t\treturn fmt.Errorf(\"invalid size for expected hash %s: %w\", sha256sum, err)\n\t}\n\n\t// Open file for checking.\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open file: %w\", err)\n\t}\n\tdefer func() { _ = file.Close() }()\n\n\t// Calculate hash of the file.\n\tfileHash := sha256.New()\n\tif _, err := io.Copy(fileHash, file); err != nil {\n\t\treturn fmt.Errorf(\"read file: %w\", err)\n\t}\n\tif subtle.ConstantTimeCompare(fileHash.Sum(nil), expectedDigest) != 1 {\n\t\treturn errors.New(\"sha256sum mismatch\")\n\t}\n\n\treturn nil\n}\n\n// CheckSHA256Sum checks the sha256sum of the given data.\nfunc CheckSHA256Sum(fileData []byte, sha256sum string) error {\n\t// Check expected hash.\n\texpectedDigest, err := hex.DecodeString(sha256sum)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid hex encoding for expected hash %s: %w\", sha256sum, err)\n\t}\n\tif len(expectedDigest) != sha256.Size {\n\t\treturn fmt.Errorf(\"invalid size for expected hash %s: %w\", sha256sum, err)\n\t}\n\n\t// Calculate and compare hash of the file.\n\thashSum := sha256.Sum256(fileData)\n\tif subtle.ConstantTimeCompare(hashSum[:], expectedDigest) != 1 {\n\t\treturn errors.New(\"sha256sum mismatch\")\n\t}\n\n\treturn nil\n}\n\n// copyAndCheckSHA256Sum copies the file from src to dst and check the sha256 sum.\n// As a special case, if the sha256sum is not given, it is not checked.\nfunc copyAndCheckSHA256Sum(src, dst, sha256sum string, filePermission utils.FSPermission) error {\n\t// Check expected hash.\n\tvar expectedDigest []byte\n\tif sha256sum != \"\" {\n\t\texpectedDigest, err := hex.DecodeString(sha256sum)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid hex encoding for expected hash %s: %w\", sha256sum, err)\n\t\t}\n\t\tif len(expectedDigest) != sha256.Size {\n\t\t\treturn fmt.Errorf(\"invalid size for expected hash %s: %w\", sha256sum, err)\n\t\t}\n\t}\n\n\t// Read file from source.\n\tfileData, err := os.ReadFile(src)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read src file: %w\", err)\n\t}\n\n\t// Calculate and compare hash of the file.\n\tif len(expectedDigest) > 0 {\n\t\thashSum := sha256.Sum256(fileData)\n\t\tif subtle.ConstantTimeCompare(hashSum[:], expectedDigest) != 1 {\n\t\t\treturn errors.New(\"sha256sum mismatch\")\n\t\t}\n\t}\n\n\t// Write to temporary file.\n\ttmpDst := dst + \".copy\"\n\terr = os.WriteFile(tmpDst, fileData, filePermission.AsUnixPermission())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"write temp dst file: %w\", err)\n\t}\n\n\t// Rename/Move to actual location.\n\terr = os.Rename(tmpDst, dst)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"rename dst file after write: %w\", err)\n\t}\n\tutils.SetFilePermission(dst, filePermission)\n\n\treturn nil\n}\n"
  },
  {
    "path": "service/updates/index_scan.go",
    "content": "package updates\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gobwas/glob\"\n\tsemver \"github.com/hashicorp/go-version\"\n)\n\ntype IndexScanConfig struct {\n\tName            string\n\tVersion         string\n\tPrimaryArtifact string\n\tBaseURL         string\n\n\tTemplates   map[string]Artifact\n\tIgnoreFiles []string\n\tUnpackFiles map[string]string\n\n\tcleanedBaseURL   string\n\tignoreFilesGlobs []glob.Glob\n\tunpackFilesGlobs map[string]glob.Glob\n}\n\nfunc (bs *IndexScanConfig) init() error {\n\t// Transform base URL into expected format.\n\tbs.cleanedBaseURL = strings.TrimSuffix(bs.BaseURL, \"/\") + \"/\"\n\n\t// Parse ignore files patterns.\n\tbs.ignoreFilesGlobs = make([]glob.Glob, 0, len(bs.IgnoreFiles))\n\tfor _, pattern := range bs.IgnoreFiles {\n\t\tg, err := glob.Compile(pattern, os.PathSeparator)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid ingore files pattern %q: %w\", pattern, err)\n\t\t}\n\t\tbs.ignoreFilesGlobs = append(bs.ignoreFilesGlobs, g)\n\t}\n\n\t// Parse unpack files patterns.\n\tbs.unpackFilesGlobs = make(map[string]glob.Glob)\n\tfor setting, pattern := range bs.UnpackFiles {\n\t\tg, err := glob.Compile(pattern, os.PathSeparator)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid unpack files pattern %q: %w\", pattern, err)\n\t\t}\n\t\tbs.unpackFilesGlobs[setting] = g\n\t}\n\n\treturn nil\n}\n\n// IsIgnored returns whether a filename should be ignored.\nfunc (bs *IndexScanConfig) IsIgnored(filename string) bool {\n\tfor _, ignoreGlob := range bs.ignoreFilesGlobs {\n\t\tif ignoreGlob.Match(filename) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// UnpackSetting returns the unpack setings for the given filename.\nfunc (bs *IndexScanConfig) UnpackSetting(filename string) (string, error) {\n\tvar foundSetting string\n\nsettings:\n\tfor unpackSetting, matchGlob := range bs.unpackFilesGlobs {\n\t\tswitch {\n\t\tcase !matchGlob.Match(filename):\n\t\t\t// Check next if glob does not match.\n\t\t\tcontinue settings\n\t\tcase foundSetting == \"\":\n\t\t\t// First find, save setting.\n\t\t\tfoundSetting = unpackSetting\n\t\tcase foundSetting != unpackSetting:\n\t\t\t// Additional find, and setting is not the same.\n\t\t\treturn \"\", errors.New(\"matches contradicting unpack settings\")\n\t\t}\n\t}\n\n\treturn foundSetting, nil\n}\n\n// GenerateIndexFromDir generates a index from a given folder.\nfunc GenerateIndexFromDir(sourceDir string, cfg IndexScanConfig) (*Index, error) { //nolint:maintidx\n\tartifacts := make(map[string]*Artifact)\n\n\t// Initialize.\n\terr := cfg.init()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid index scan config: %w\", err)\n\t}\n\tsourceDir, err = filepath.Abs(sourceDir)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid index dir: %w\", err)\n\t}\n\tvar indexVersion *semver.Version\n\tif cfg.Version != \"\" {\n\t\tindexVersion, err = semver.NewVersion(cfg.Version)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid index version: %w\", err)\n\t\t}\n\t}\n\n\terr = filepath.WalkDir(sourceDir, func(fullpath string, d fs.DirEntry, err error) error {\n\t\t// Fail on access error.\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Step 1: Extract information and check ignores.\n\n\t\t// Skip folders.\n\t\tif d.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Get relative path for processing.\n\t\trelpath, err := filepath.Rel(sourceDir, fullpath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid relative path for %s: %w\", fullpath, err)\n\t\t}\n\n\t\t// Check if file is in the ignore list.\n\t\tif cfg.IsIgnored(relpath) {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Extract version, if present.\n\t\tidentifier, version, ok := getIdentifierAndVersion(d.Name())\n\t\tif !ok {\n\t\t\t// Fallback to using filename as identifier, which is normal for the simplified system.\n\t\t\tidentifier = d.Name()\n\t\t\tversion = \"\"\n\t\t}\n\t\tvar versionNum *semver.Version\n\t\tif version != \"\" {\n\t\t\tversionNum, err = semver.NewVersion(version)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"invalid version %s for %s: %w\", relpath, version, err)\n\t\t\t}\n\t\t}\n\n\t\t// Extract platform.\n\t\tplatform := \"all\"\n\t\tbefore, _, found := strings.Cut(relpath, string(os.PathSeparator))\n\t\tif found {\n\t\t\tplatform = before\n\t\t}\n\n\t\t// Step 2: Check and compare file version.\n\n\t\t// Make the key platform specific since there can be same filename for multiple platforms.\n\t\tkey := platform + \"/\" + identifier\n\t\texisting, ok := artifacts[key]\n\t\tif ok {\n\t\t\t// Check for duplicates and mixed versioned/non-versioned.\n\t\t\tswitch {\n\t\t\tcase existing.Version == version:\n\t\t\t\treturn fmt.Errorf(\"duplicate version for %s: %s and %s\", key, existing.localFile, fullpath)\n\t\t\tcase (existing.Version == \"\") != (version == \"\"):\n\t\t\t\treturn fmt.Errorf(\"both a versioned and non-versioned file for: %s: %s and %s\", key, existing.localFile, fullpath)\n\t\t\t}\n\n\t\t\t// Compare versions.\n\t\t\texistingVersion, _ := semver.NewVersion(existing.Version)\n\t\t\tswitch {\n\t\t\tcase existingVersion.Equal(versionNum):\n\t\t\t\treturn fmt.Errorf(\"duplicate version for %s: %s and %s\", key, existing.localFile, fullpath)\n\t\t\tcase existingVersion.GreaterThan(versionNum):\n\t\t\t\t// New version is older, skip.\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\t// Step 3: Create new Artifact.\n\n\t\tartifact := &Artifact{}\n\n\t\t// Check if the caller provided a template for the artifact.\n\t\tif t, ok := cfg.Templates[identifier]; ok {\n\t\t\tfromTemplate := t\n\t\t\tartifact = &fromTemplate\n\t\t}\n\n\t\t// Set artifact properties.\n\t\tif artifact.Filename == \"\" {\n\t\t\tartifact.Filename = identifier\n\t\t}\n\t\tif len(artifact.URLs) == 0 && cfg.BaseURL != \"\" {\n\t\t\tartifact.URLs = []string{cfg.cleanedBaseURL + relpath}\n\t\t}\n\t\tif artifact.Platform == \"\" {\n\t\t\tartifact.Platform = platform\n\t\t}\n\t\tif artifact.Unpack == \"\" {\n\t\t\tunpackSetting, err := cfg.UnpackSetting(relpath)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"invalid unpack setting for %s at %s: %w\", key, relpath, err)\n\t\t\t}\n\t\t\tartifact.Unpack = unpackSetting\n\t\t}\n\t\tif artifact.Version == \"\" {\n\t\t\tartifact.Version = version\n\t\t}\n\n\t\t// Remove unpack suffix.\n\t\tif artifact.Unpack != \"\" {\n\t\t\tartifact.Filename, _ = strings.CutSuffix(artifact.Filename, \".\"+artifact.Unpack)\n\t\t}\n\n\t\t// Set local file path.\n\t\tartifact.localFile = fullpath\n\n\t\t// Save new artifact to map.\n\t\tartifacts[key] = artifact\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"scanning dir: %w\", err)\n\t}\n\n\t// Create base index.\n\tindex := &Index{\n\t\tName:               cfg.Name,\n\t\tVersion:            cfg.Version,\n\t\tPublished:          time.Now(),\n\t\tversionNum:         indexVersion,\n\t\tisLocallyGenerated: true,\n\t}\n\tif index.Version == \"\" && cfg.PrimaryArtifact != \"\" {\n\t\tpv, ok := artifacts[cfg.PrimaryArtifact]\n\t\tif ok {\n\t\t\tindex.Version = pv.Version\n\t\t}\n\t}\n\tif index.Name == \"\" {\n\t\tindex.Name = strings.Trim(filepath.Base(sourceDir), \"./\\\\\")\n\t}\n\n\t// Convert to slice and compute hashes.\n\texport := make([]*Artifact, 0, len(artifacts))\n\tfor _, artifact := range artifacts {\n\t\t// Compute hash.\n\t\thash, err := GetSHA256(artifact.localFile, artifact.Unpack)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"calculate hash of file: %s %w\", artifact.localFile, err)\n\t\t}\n\t\tartifact.SHA256 = hash\n\n\t\t// Remove \"all\" platform IDs.\n\t\tif artifact.Platform == \"all\" {\n\t\t\tartifact.Platform = \"\"\n\t\t}\n\n\t\t// Remove default versions.\n\t\tif artifact.Version == index.Version {\n\t\t\tartifact.Version = \"\"\n\t\t}\n\n\t\t// Add to export slice.\n\t\texport = append(export, artifact)\n\t}\n\n\t// Sort final artifacts.\n\tslices.SortFunc(export, func(a, b *Artifact) int {\n\t\tswitch {\n\t\tcase a.Filename != b.Filename:\n\t\t\treturn strings.Compare(a.Filename, b.Filename)\n\t\tcase a.Platform != b.Platform:\n\t\t\treturn strings.Compare(a.Platform, b.Platform)\n\t\tcase a.Version != b.Version:\n\t\t\treturn strings.Compare(a.Version, b.Version)\n\t\tcase a.SHA256 != b.SHA256:\n\t\t\treturn strings.Compare(a.SHA256, b.SHA256)\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\t})\n\n\t// Assign and return.\n\tindex.Artifacts = export\n\treturn index, nil\n}\n\n// GetSHA256 gets the sha256sum of the given file and unpacks it if necessary.\nfunc GetSHA256(path string, unpackType string) (string, error) {\n\tcontent, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// Decompress if compression was applied to the file.\n\tif unpackType != \"\" {\n\t\tcontent, err = Decompress(unpackType, content)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\t// Calculate hash\n\thash := sha256.Sum256(content)\n\treturn hex.EncodeToString(hash[:]), nil\n}\n\nvar fileVersionRegex = regexp.MustCompile(`_v[0-9]+-[0-9]+-[0-9]+(-[a-z]+)?`)\n\nfunc getIdentifierAndVersion(versionedPath string) (identifier, version string, ok bool) {\n\tdirPath, filename := path.Split(versionedPath)\n\n\t// Extract version from filename.\n\trawVersion := fileVersionRegex.FindString(filename)\n\tif rawVersion == \"\" {\n\t\t// No version present in file, making it invalid.\n\t\treturn \"\", \"\", false\n\t}\n\n\t// Trim the `_v` that gets caught by the regex and\n\t// replace `-` with `.` to get the version string.\n\tversion = strings.Replace(strings.TrimLeft(rawVersion, \"_v\"), \"-\", \".\", 2)\n\n\t// Put the filename back together without version.\n\ti := strings.Index(filename, rawVersion)\n\tif i < 0 {\n\t\t// extracted version not in string (impossible)\n\t\treturn \"\", \"\", false\n\t}\n\tfilename = filename[:i] + filename[i+len(rawVersion):]\n\n\t// Put the full path back together and return it.\n\t// `dirPath + filename` is guaranteed by path.Split()\n\treturn dirPath + filename, version, true\n}\n"
  },
  {
    "path": "service/updates/module.go",
    "content": "package updates\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/ui\"\n)\n\nconst (\n\tupdateTaskRepeatDuration          = 1 * time.Hour\n\tnoNewUpdateNotificationID         = \"updates:no-new-update\"\n\tupdateAvailableNotificationID     = \"updates:update-available\"\n\trestartRequiredNotificationID     = \"updates:restart-required\"\n\tupdateFailedNotificationID        = \"updates:update-failed\"\n\tcorruptInstallationNotificationID = \"updates:corrupt-installation\"\n\n\t// ResourceUpdateEvent is emitted every time the\n\t// updater successfully performed a resource update.\n\tResourceUpdateEvent = \"resource update\"\n)\n\n// UserAgent is an HTTP User-Agent that is used to add\n// more context to requests made by the registry when\n// fetching resources from the update server.\nvar UserAgent = fmt.Sprintf(\"Portmaster (%s %s)\", runtime.GOOS, runtime.GOARCH)\n\n// Errors.\nvar (\n\tErrNotFound  = errors.New(\"file not found\")\n\tErrSameIndex = errors.New(\"same index\")\n\n\tErrAutoCheckDisabled = errors.New(\"automatic update checks are disabled\")\n\tErrNoUpdateAvailable = errors.New(\"no update available\")\n\tErrActionRequired    = errors.New(\"action required\")\n)\n\n// UpdateCommandConfig defines the configuration for a shell command\n// that is executed when an update is applied\ntype UpdateCommandConfig struct {\n\t// Shell command to execute\n\tCommand string\n\t// Arguments to pass to the command\n\tArgs []string\n\t// Execute triggers: if not empty, the command will be executed only if specified file was updated\n\t// if empty, the command will be executed always\n\tTriggerArtifactFName string\n\t// FailOnError defines whether the upgrade should fail if the command fails\n\t// true - upgrade will fail if the command fails\n\t// false - upgrade will continue even if the command fails\n\tFailOnError bool\n}\n\n// Config holds the configuration for the updates module.\ntype Config struct {\n\t// Name of the updater.\n\tName string\n\t// Directory is the main directory where the currently to-be-used artifacts live.\n\tDirectory string\n\t// DownloadDirectory is the directory where new artifacts are downloaded to and prepared for upgrading.\n\t// After the upgrade, this directory is cleared.\n\tDownloadDirectory string\n\t// PurgeDirectory is the directory where old artifacts are moved to during the upgrade process.\n\t// After the upgrade, this directory is cleared.\n\tPurgeDirectory string\n\t// Ignore defines file and directory names within the main directory that should be ignored during the upgrade.\n\tIgnore []string\n\n\t// IndexURLs defines file\n\tIndexURLs []string\n\t// IndexFile is the name of the index file used in the directories.\n\tIndexFile string\n\t// Verify enables and specifies the trust the index signatures will be checked against.\n\tVerify jess.TrustStore\n\t// Platform defines the platform to download artifacts for. Defaults to current platform.\n\tPlatform string\n\n\t// AutoCheck defines that new indexes may be downloaded automatically without outside trigger.\n\tAutoCheck bool\n\t// AutoDownload defines that updates may be downloaded automatically without outside trigger.\n\tAutoDownload bool\n\t// AutoApply defines that updates may be automatically applied without outside trigger.\n\t// Requires AutoDownload the be enabled.\n\tAutoApply bool\n\t// NeedsRestart defines that a restart is required after an upgrade has been completed.\n\t// Restart is triggered automatically, if Notify is disabled.\n\tNeedsRestart bool\n\t// Notify defines whether the user shall be informed about events via notifications.\n\t// If enabled, disables automatic restart after upgrade.\n\tNotify bool\n\n\t// list of shell commands needed to run after the upgrade (if any)\n\tPostUpgradeCommands []UpdateCommandConfig\n}\n\n// Check looks for obvious configuration errors.\nfunc (cfg *Config) Check() error {\n\t// Check if required fields are set.\n\tswitch {\n\tcase cfg.Name == \"\":\n\t\treturn errors.New(\"name must be set\")\n\tcase cfg.Directory == \"\":\n\t\treturn errors.New(\"directory must be set\")\n\tcase cfg.DownloadDirectory == \"\":\n\t\treturn errors.New(\"download directory must be set\")\n\tcase cfg.PurgeDirectory == \"\":\n\t\treturn errors.New(\"purge directory must be set\")\n\tcase cfg.IndexFile == \"\":\n\t\treturn errors.New(\"index file must be set\")\n\tcase cfg.AutoApply && !cfg.AutoDownload:\n\t\treturn errors.New(\"auto apply is set, but auto download is not\")\n\t}\n\n\t// Check if Ignore contains paths.\n\tfor i, s := range cfg.Ignore {\n\t\tif strings.ContainsRune(s, filepath.Separator) {\n\t\t\treturn fmt.Errorf(\"ignore entry #%d invalid: must be file or directory name, not path\", i+1)\n\t\t}\n\t}\n\n\t// Check if IndexURLs are HTTPS.\n\tfor i, url := range cfg.IndexURLs {\n\t\tif !strings.HasPrefix(url, \"https://\") {\n\t\t\treturn fmt.Errorf(\"index URL #%d invalid: is not a HTTPS url\", i+1)\n\t\t}\n\t}\n\n\t// Check platform.\n\tif cfg.Platform == \"\" {\n\t\tcfg.Platform = currentPlatform\n\t}\n\n\treturn nil\n}\n\n// Updater provides access to released artifacts.\ntype Updater struct {\n\tm      *mgr.Manager\n\tstates *mgr.StateMgr\n\tcfg    Config\n\n\tindex     *Index\n\tindexLock sync.Mutex\n\n\tupdateCheckWorkerMgr *mgr.WorkerMgr\n\tupgradeWorkerMgr     *mgr.WorkerMgr\n\n\tEventResourcesUpdated *mgr.EventMgr[struct{}]\n\n\tcorruptedInstallation error\n\n\tisUpdateRunning *abool.AtomicBool\n\tstarted         *abool.AtomicBool\n\tconfigureLock   sync.Mutex\n\n\tinstance instance\n}\n\n// New returns a new Updates module.\nfunc New(instance instance, name string, cfg Config) (*Updater, error) {\n\tm := mgr.New(name)\n\tmodule := &Updater{\n\t\tm:      m,\n\t\tstates: m.NewStateMgr(),\n\t\tcfg:    cfg,\n\n\t\tEventResourcesUpdated: mgr.NewEventMgr[struct{}](ResourceUpdateEvent, m),\n\n\t\tisUpdateRunning: abool.NewBool(false),\n\t\tstarted:         abool.NewBool(false),\n\n\t\tinstance: instance,\n\t}\n\n\t// Check config.\n\tif err := module.cfg.Check(); err != nil {\n\t\treturn nil, fmt.Errorf(\"config is invalid: %w\", err)\n\t}\n\n\t// Make sure main dir exists.\n\terr := utils.EnsureDirectory(module.cfg.Directory, utils.PublicReadExecPermission)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"create update target directory: %s\", module.cfg.DownloadDirectory)\n\t}\n\n\t// Create Workers.\n\tmodule.updateCheckWorkerMgr = m.NewWorkerMgr(\"update checker\", module.updateCheckWorker, nil)\n\tmodule.upgradeWorkerMgr = m.NewWorkerMgr(\"upgrader\", module.upgradeWorker, nil)\n\n\t// Load index.\n\tindex, err := LoadIndex(filepath.Join(cfg.Directory, cfg.IndexFile), cfg.Platform, cfg.Verify)\n\tif err == nil {\n\t\t// Verify artifacts.\n\t\tif err := index.VerifyArtifacts(cfg.Directory); err != nil {\n\t\t\tmodule.corruptedInstallation = fmt.Errorf(\"invalid artifact: %w\", err)\n\t\t}\n\n\t\t// Save index to module and return.\n\t\tmodule.index = index\n\t\treturn module, nil\n\t}\n\n\t// Fall back to scanning the directory.\n\tif !errors.Is(err, os.ErrNotExist) {\n\t\tlog.Errorf(\"updates/%s: invalid index file, falling back to dir scan: %s\", cfg.Name, err)\n\t\tmodule.corruptedInstallation = fmt.Errorf(\"invalid index: %w\", err)\n\t}\n\tindex, err = GenerateIndexFromDir(cfg.Directory, IndexScanConfig{\n\t\tName:    cfg.Name,\n\t\tVersion: info.VersionNumber(),\n\t})\n\tif err == nil && index.init(currentPlatform) == nil {\n\t\tmodule.index = index\n\t\treturn module, nil\n\t}\n\n\t// Fall back to empty index.\n\treturn module, nil\n}\n\nfunc (u *Updater) updateAndUpgrade(w *mgr.WorkerCtx, indexURLs []string, ignoreVersion, forceApply bool) (err error) { //nolint:maintidx\n\t// Make sure only one update process is running.\n\tif !u.isUpdateRunning.SetToIf(false, true) {\n\t\treturn fmt.Errorf(\"an updater task is already running, please try again later\")\n\t}\n\tdefer u.isUpdateRunning.UnSet()\n\n\t// Create a new downloader.\n\tdownloader := NewDownloader(u, indexURLs)\n\n\t// Update or load the index file.\n\tif len(indexURLs) > 0 {\n\t\t// Download fresh copy, if indexURLs are given.\n\t\terr = downloader.updateIndex(w.Ctx())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"update index file: %w\", err)\n\t\t}\n\t} else {\n\t\t// Otherwise, load index from download dir.\n\t\tdownloader.index, err = LoadIndex(filepath.Join(u.cfg.DownloadDirectory, u.cfg.IndexFile), u.cfg.Platform, u.cfg.Verify)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"load previously downloaded index file: %w\", err)\n\t\t}\n\t}\n\n\t// Get index to check version.\n\tu.indexLock.Lock()\n\tindex := u.index\n\tu.indexLock.Unlock()\n\n\t// Check if there is a new version.\n\tif !ignoreVersion && index != nil {\n\t\t// Check with local pointer to index.\n\t\tif err := index.ShouldUpgradeTo(downloader.index); err != nil {\n\t\t\tif errors.Is(err, ErrSameIndex) {\n\t\t\t\tlog.Infof(\"updates/%s: no new update\", u.cfg.Name)\n\t\t\t\tif u.cfg.Notify && u.instance.Notifications() != nil {\n\t\t\t\t\tu.instance.Notifications().Notify(&notifications.Notification{\n\t\t\t\t\t\tEventID: noNewUpdateNotificationID,\n\t\t\t\t\t\tType:    notifications.Info,\n\t\t\t\t\t\tTitle:   \"Portmaster Is Up-To-Date\",\n\t\t\t\t\t\tMessage: \"Portmaster v\" + index.Version + \" is the newest version.\",\n\t\t\t\t\t\tExpires: time.Now().Add(1 * time.Minute).Unix(),\n\t\t\t\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tID:   \"ack\",\n\t\t\t\t\t\t\t\tText: \"OK\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlog.Warningf(\"updates/%s: cannot update: %s\", u.cfg.Name, err)\n\t\t\t\tif u.cfg.Notify && u.instance.Notifications() != nil {\n\t\t\t\t\tu.instance.Notifications().Notify(&notifications.Notification{\n\t\t\t\t\t\tEventID: noNewUpdateNotificationID,\n\t\t\t\t\t\tType:    notifications.Info,\n\t\t\t\t\t\tTitle:   \"Portmaster Is Up-To-Date*\",\n\t\t\t\t\t\tMessage: \"While Portmaster v\" + index.Version + \" is the newest version, there is an internal issue with checking for updates: \" + err.Error(),\n\t\t\t\t\t\tExpires: time.Now().Add(1 * time.Minute).Unix(),\n\t\t\t\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tID:   \"ack\",\n\t\t\t\t\t\t\t\tText: \"OK\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"%w: %w\", ErrNoUpdateAvailable, err)\n\t\t}\n\t}\n\n\t// Check if automatic downloads are enabled.\n\tif !u.cfg.AutoDownload && !forceApply {\n\t\tlog.Infof(\"updates/%s: new update to v%s available, action required to download and upgrade\", u.cfg.Name, downloader.index.Version)\n\t\tif u.cfg.Notify && u.instance.Notifications() != nil {\n\t\t\tu.instance.Notifications().Notify(&notifications.Notification{\n\t\t\t\tEventID: updateAvailableNotificationID,\n\t\t\t\tType:    notifications.Info,\n\t\t\t\tTitle:   \"New Update Available\",\n\t\t\t\tMessage: \"Portmaster v\" + downloader.index.Version + \" is available. Click Upgrade to download and upgrade now.\",\n\t\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:   \"ack\",\n\t\t\t\t\t\tText: \"OK\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:   \"upgrade\",\n\t\t\t\t\t\tText: \"Upgrade Now\",\n\t\t\t\t\t\tType: notifications.ActionTypeWebhook,\n\t\t\t\t\t\tPayload: notifications.ActionTypeWebhookPayload{\n\t\t\t\t\t\t\tMethod: \"POST\",\n\t\t\t\t\t\t\tURL:    \"updates/apply\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\treturn fmt.Errorf(\"%w: apply updates to download and upgrade\", ErrActionRequired)\n\t}\n\n\t// Check for existing resources before starting to download.\n\t_ = downloader.gatherExistingFiles(u.cfg.Directory)         // Artifacts are re-used between versions.\n\t_ = downloader.gatherExistingFiles(u.cfg.DownloadDirectory) // Previous download may have been interrupted.\n\t_ = downloader.gatherExistingFiles(u.cfg.PurgeDirectory)    // Revover faster from a failed upgrade.\n\n\t// Download any remaining needed files.\n\t// If everything is already found in the download directory, then this is a no-op.\n\tlog.Infof(\"updates/%s: downloading new version: %s %s\", u.cfg.Name, downloader.index.Name, downloader.index.Version)\n\terr = downloader.downloadArtifacts(w.Ctx())\n\tif err != nil {\n\t\tlog.Errorf(\"updates/%s: failed to download update: %s\", u.cfg.Name, err)\n\t\tif err := u.deleteUnfinishedFiles(u.cfg.DownloadDirectory); err != nil {\n\t\t\tlog.Debugf(\"updates/%s: failed to delete unfinished files in download directory %s\", u.cfg.Name, u.cfg.DownloadDirectory)\n\t\t}\n\t\treturn fmt.Errorf(\"downloading failed: %w\", err)\n\t}\n\n\t// Notify the user that an upgrade is available.\n\tif !u.cfg.AutoApply && !forceApply {\n\t\tlog.Infof(\"updates/%s: new update to v%s available, action required to upgrade\", u.cfg.Name, downloader.index.Version)\n\t\tif u.cfg.Notify && u.instance.Notifications() != nil {\n\t\t\tu.instance.Notifications().Notify(&notifications.Notification{\n\t\t\t\tEventID: updateAvailableNotificationID,\n\t\t\t\tType:    notifications.Info,\n\t\t\t\tTitle:   \"New Update Ready\",\n\t\t\t\tMessage: \"Portmaster v\" + downloader.index.Version + \" is available. Click Upgrade to upgrade now.\",\n\t\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:   \"ack\",\n\t\t\t\t\t\tText: \"OK\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:   \"upgrade\",\n\t\t\t\t\t\tText: \"Upgrade Now\",\n\t\t\t\t\t\tType: notifications.ActionTypeWebhook,\n\t\t\t\t\t\tPayload: notifications.ActionTypeWebhookPayload{\n\t\t\t\t\t\t\tMethod: \"POST\",\n\t\t\t\t\t\t\tURL:    \"updates/apply\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\treturn fmt.Errorf(\"%w: apply updates to download and upgrade\", ErrActionRequired)\n\t}\n\n\t// Run upgrade procedure.\n\terr = u.upgrade(downloader, ignoreVersion)\n\tif err != nil {\n\t\tif err := u.deleteUnfinishedFiles(u.cfg.PurgeDirectory); err != nil {\n\t\t\tlog.Debugf(\"updates/%s: failed to delete unfinished files in purge directory %s\", u.cfg.Name, u.cfg.PurgeDirectory)\n\t\t}\n\t\treturn err\n\t}\n\n\t// Install is complete!\n\n\t// Clean up and notify modules of changed files.\n\terr = u.cleanupAfterUpgrade()\n\tif err != nil {\n\t\tlog.Debugf(\"updates/%s: failed to clean up after upgrade: %s\", u.cfg.Name, err)\n\t}\n\tu.EventResourcesUpdated.Submit(struct{}{})\n\n\t// If no restart is needed, we are done.\n\tif !u.cfg.NeedsRestart {\n\t\treturn nil\n\t}\n\n\t// Notify user that a restart is required.\n\tif u.cfg.Notify {\n\t\tif u.instance.Notifications() != nil {\n\t\t\tu.instance.Notifications().Notify(&notifications.Notification{\n\t\t\t\tEventID: restartRequiredNotificationID,\n\t\t\t\tType:    notifications.Info,\n\t\t\t\tTitle:   \"Restart Required\",\n\t\t\t\tMessage: \"Portmaster v\" + downloader.index.Version + \" is installed. Restart to use new version.\",\n\t\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t\t{\n\t\t\t\t\t\tID:   \"ack\",\n\t\t\t\t\t\tText: \"Later\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tID:   \"restart\",\n\t\t\t\t\t\tText: \"Restart Now\",\n\t\t\t\t\t\tType: notifications.ActionTypeWebhook,\n\t\t\t\t\t\tPayload: notifications.ActionTypeWebhookPayload{\n\t\t\t\t\t\t\tMethod: \"POST\",\n\t\t\t\t\t\t\tURL:    \"core/restart\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\n\t\treturn fmt.Errorf(\"%w: restart required\", ErrActionRequired)\n\t}\n\n\t// Otherwise, trigger restart immediately.\n\tu.instance.Restart()\n\treturn nil\n}\n\nfunc (u *Updater) getIndexURLsWithLock() []string {\n\tu.configureLock.Lock()\n\tdefer u.configureLock.Unlock()\n\n\treturn u.cfg.IndexURLs\n}\n\nfunc (u *Updater) updateCheckWorker(w *mgr.WorkerCtx) error {\n\terr := u.updateAndUpgrade(w, u.getIndexURLsWithLock(), false, false)\n\tswitch {\n\tcase err == nil:\n\t\treturn nil // Success!\n\tcase errors.Is(err, ErrSameIndex):\n\t\treturn nil // Nothing to do.\n\tcase errors.Is(err, ErrNoUpdateAvailable):\n\t\treturn nil // Already logged.\n\tcase errors.Is(err, ErrActionRequired) && !u.cfg.Notify:\n\t\treturn fmt.Errorf(\"user action required, but notifying user is disabled: %w\", err)\n\tdefault:\n\t\treturn fmt.Errorf(\"udpating failed: %w\", err)\n\t}\n}\n\nfunc (u *Updater) upgradeWorker(w *mgr.WorkerCtx) error {\n\terr := u.updateAndUpgrade(w, u.getIndexURLsWithLock(), false, true)\n\tswitch {\n\tcase err == nil:\n\t\treturn nil // Success!\n\tcase errors.Is(err, ErrSameIndex):\n\t\treturn nil // Nothing to do.\n\tcase errors.Is(err, ErrNoUpdateAvailable):\n\t\treturn nil // Already logged.\n\tcase errors.Is(err, ErrActionRequired) && !u.cfg.Notify:\n\t\treturn fmt.Errorf(\"user action required, but notifying user is disabled: %w\", err)\n\tdefault:\n\t\treturn fmt.Errorf(\"udpating failed: %w\", err)\n\t}\n}\n\n// ForceUpdate executes a forced update and upgrade directly and synchronously\n// and is intended to be used only within a tool, not a service.\nfunc (u *Updater) ForceUpdate() error {\n\treturn u.m.Do(\"update and upgrade\", func(w *mgr.WorkerCtx) error {\n\t\treturn u.updateAndUpgrade(w, u.getIndexURLsWithLock(), true, true)\n\t})\n}\n\n// UpdateFromURL installs an update from the provided url.\nfunc (u *Updater) UpdateFromURL(url string) error {\n\tu.m.Go(\"custom update from url\", func(w *mgr.WorkerCtx) error {\n\t\t_ = u.updateAndUpgrade(w, []string{url}, true, true)\n\t\treturn nil\n\t})\n\n\treturn nil\n}\n\n// Configure makes slight configuration changes to the updater.\n// It locks the index, which can take a while an update is running.\nfunc (u *Updater) Configure(autoCheck bool, indexURLs []string) {\n\tu.configureLock.Lock()\n\tdefer u.configureLock.Unlock()\n\n\t// Apply new config.\n\tvar changed bool\n\tif u.cfg.AutoCheck != autoCheck {\n\t\tu.cfg.AutoCheck = autoCheck\n\t\tchanged = true\n\t}\n\tif !slices.Equal(u.cfg.IndexURLs, indexURLs) {\n\t\tu.cfg.IndexURLs = indexURLs\n\t\tchanged = true\n\t}\n\n\t// Trigger update check if enabled and something changed.\n\tif changed && u.started.IsSet() {\n\t\tif autoCheck {\n\t\t\tu.updateCheckWorkerMgr.Repeat(updateTaskRepeatDuration).Go()\n\t\t} else {\n\t\t\tu.updateCheckWorkerMgr.Repeat(0)\n\t\t}\n\t}\n}\n\n// TriggerUpdateCheck triggers an update check.\nfunc (u *Updater) TriggerUpdateCheck() {\n\tu.updateCheckWorkerMgr.Go()\n}\n\n// TriggerApplyUpdates triggers upgrade.\nfunc (u *Updater) TriggerApplyUpdates() {\n\tu.upgradeWorkerMgr.Go()\n}\n\n// States returns the state manager.\nfunc (u *Updater) States() *mgr.StateMgr {\n\treturn u.states\n}\n\n// Manager returns the module manager.\nfunc (u *Updater) Manager() *mgr.Manager {\n\treturn u.m\n}\n\n// Start starts the module.\nfunc (u *Updater) Start() error {\n\tu.configureLock.Lock()\n\tdefer u.configureLock.Unlock()\n\n\tif u.corruptedInstallation != nil && u.cfg.Notify && u.instance.Notifications() != nil {\n\t\tu.states.Add(mgr.State{\n\t\t\tID:      corruptInstallationNotificationID,\n\t\t\tName:    \"Install Corruption\",\n\t\t\tMessage: \"Portmaster has detected that one or more of its own files have been corrupted. Please re-install the software. Error: \" + u.corruptedInstallation.Error(),\n\t\t\tType:    mgr.StateTypeError,\n\t\t\tData:    u.corruptedInstallation,\n\t\t})\n\t}\n\n\t// Check for updates automatically, if enabled.\n\tif u.cfg.AutoCheck {\n\t\tu.updateCheckWorkerMgr.\n\t\t\tRepeat(updateTaskRepeatDuration).\n\t\t\tDelay(15 * time.Second)\n\t}\n\n\tu.started.SetTo(true)\n\treturn nil\n}\n\nfunc (u *Updater) GetMainDir() string {\n\treturn u.cfg.Directory\n}\n\n// GetIndex returns a copy of the index.\nfunc (u *Updater) GetIndex() (*Index, error) {\n\t// Copy Artifacts.\n\tartifacts, err := u.GetFiles()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tu.indexLock.Lock()\n\tdefer u.indexLock.Unlock()\n\n\t// Check if any index is active.\n\tif u.index == nil {\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn &Index{\n\t\tName:       u.index.Name,\n\t\tVersion:    u.index.Version,\n\t\tPublished:  u.index.Published,\n\t\tArtifacts:  artifacts,\n\t\tversionNum: u.index.versionNum,\n\t}, nil\n}\n\n// GetFiles returns all artifacts. Returns ErrNotFound if no artifacts are found.\nfunc (u *Updater) GetFiles() ([]*Artifact, error) {\n\tu.indexLock.Lock()\n\tdefer u.indexLock.Unlock()\n\n\t// Check if any index is active.\n\tif u.index == nil {\n\t\treturn nil, ErrNotFound\n\t}\n\n\t// Export all artifacts.\n\texport := make([]*Artifact, 0, len(u.index.Artifacts))\n\tfor _, artifact := range u.index.Artifacts {\n\t\tswitch {\n\t\tcase artifact.Platform != \"\" && artifact.Platform != u.cfg.Platform:\n\t\t\t// Platform is defined and does not match.\n\t\t\t// Platforms are usually pre-filtered, but just to be sure.\n\t\tdefault:\n\t\t\t// Artifact matches!\n\t\t\texport = append(export, artifact.export(u.cfg.Directory, u.index.versionNum))\n\t\t}\n\t}\n\n\t// Check if anything was exported.\n\tif len(export) == 0 {\n\t\treturn nil, ErrNotFound\n\t}\n\n\treturn export, nil\n}\n\n// GetFile returns the path of a file given the name. Returns ErrNotFound if file is not found.\nfunc (u *Updater) GetFile(name string) (*Artifact, error) {\n\tu.indexLock.Lock()\n\tdefer u.indexLock.Unlock()\n\n\t// Check if any index is active.\n\tif u.index == nil {\n\t\treturn nil, ErrNotFound\n\t}\n\n\tfor _, artifact := range u.index.Artifacts {\n\t\tswitch {\n\t\tcase artifact.Filename != name:\n\t\t\t// Name does not match.\n\t\tcase artifact.Platform != \"\" && artifact.Platform != u.cfg.Platform:\n\t\t\t// Platform is defined and does not match.\n\t\t\t// Platforms are usually pre-filtered, but just to be sure.\n\t\tdefault:\n\t\t\t// Artifact matches!\n\t\t\treturn artifact.export(u.cfg.Directory, u.index.versionNum), nil\n\t\t}\n\t}\n\n\treturn nil, ErrNotFound\n}\n\n// Stop stops the module.\nfunc (u *Updater) Stop() error {\n\tu.started.SetTo(false)\n\treturn nil\n}\n\ntype instance interface {\n\tRestart()\n\tShutdown()\n\tNotifications() *notifications.Notifications\n\tUI() *ui.UI\n}\n"
  },
  {
    "path": "service/updates/updates_test.go",
    "content": "package updates\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/ui\"\n)\n\ntype testInstance struct{}\n\nfunc (i *testInstance) Restart()                                    {}\nfunc (i *testInstance) Shutdown()                                   {}\nfunc (i *testInstance) Notifications() *notifications.Notifications { return nil }\nfunc (i *testInstance) Ready() bool                                 { return true }\nfunc (i *testInstance) SetCmdLineOperation(f func() error)          {}\nfunc (i *testInstance) UI() *ui.UI                                  { return nil }\n\nfunc TestPerformUpdate(t *testing.T) {\n\tt.Parallel()\n\n\t// Initialize mock instance\n\tstub := &testInstance{}\n\n\t// Make tmp dirs\n\tinstalledDir, err := os.MkdirTemp(\"\", \"updates_current_\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer func() { _ = os.RemoveAll(installedDir) }()\n\n\tupdateDir, err := os.MkdirTemp(\"\", \"updates_new_\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer func() { _ = os.RemoveAll(updateDir) }()\n\n\tpurgeDir, err := os.MkdirTemp(\"\", \"updates_purge_\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer func() { _ = os.RemoveAll(purgeDir) }()\n\n\t// Generate mock files\n\tnow := time.Now()\n\tif err := GenerateMockFolder(installedDir, \"Test\", \"1.0.0\", now); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif err := GenerateMockFolder(updateDir, \"Test\", \"1.0.1\", now.Add(1*time.Minute)); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Create updater (loads index).\n\tupdater, err := New(stub, \"Test\", Config{\n\t\tName:              \"Test\",\n\t\tDirectory:         installedDir,\n\t\tDownloadDirectory: updateDir,\n\t\tPurgeDirectory:    purgeDir,\n\t\tIndexFile:         \"index.json\",\n\t\tAutoDownload:      true,\n\t\tAutoApply:         true,\n\t})\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Try to apply the updates\n\tm := mgr.New(\"updates test\")\n\t_ = m.Do(\"test update and upgrade\", func(w *mgr.WorkerCtx) error {\n\t\tif err := updater.updateAndUpgrade(w, nil, false, false); err != nil {\n\t\t\tif data, err := os.ReadFile(filepath.Join(installedDir, \"index.json\")); err == nil {\n\t\t\t\tfmt.Println(string(data))\n\t\t\t\tfmt.Println(updater.index.Version)\n\t\t\t\tfmt.Println(updater.index.versionNum)\n\t\t\t}\n\t\t\tif data, err := os.ReadFile(filepath.Join(updateDir, \"index.json\")); err == nil {\n\t\t\t\tfmt.Println(string(data))\n\t\t\t\tidx, err := ParseIndex(data, updater.cfg.Platform, nil)\n\t\t\t\tif err == nil {\n\t\t\t\t\tfmt.Println(idx.Version)\n\t\t\t\t\tfmt.Println(idx.versionNum)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tt.Fatal(err)\n\t\t}\n\t\treturn nil\n\t})\n\n\t// Check if the current version is now the new.\n\tnewIndex, err := LoadIndex(filepath.Join(installedDir, \"index.json\"), updater.cfg.Platform, nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif newIndex.Version != \"1.0.1\" {\n\t\tt.Fatalf(\"expected version 1.0.1 found %s\", newIndex.Version)\n\t}\n}\n\n// GenerateMockFolder generates mock index folder for testing.\nfunc GenerateMockFolder(dir, name, version string, published time.Time) error {\n\t// Make sure dir exists\n\t_ = os.MkdirAll(dir, 0o750)\n\n\t// Create empty files\n\tfile, err := os.Create(filepath.Join(dir, \"portmaster\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\t_ = file.Close()\n\tfile, err = os.Create(filepath.Join(dir, \"portmaster-core\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\t_ = file.Close()\n\tfile, err = os.Create(filepath.Join(dir, \"portmaster.zip\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\t_ = file.Close()\n\tfile, err = os.Create(filepath.Join(dir, \"assets.zip\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\t_ = file.Close()\n\n\tindex, err := GenerateIndexFromDir(dir, IndexScanConfig{\n\t\tName:    name,\n\t\tVersion: version,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tindex.Published = published\n\n\tindexJSON, err := json.MarshalIndent(index, \"\", \"  \")\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to marshal index: %s\\n\", err)\n\t}\n\n\terr = os.WriteFile(filepath.Join(dir, \"index.json\"), indexJSON, 0o600)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "service/updates/upgrade.go",
    "content": "package updates\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n)\n\nfunc (u *Updater) upgrade(downloader *Downloader, ignoreVersion bool) error {\n\t// Lock index for the upgrade.\n\tu.indexLock.Lock()\n\tdefer u.indexLock.Unlock()\n\n\t// Check if we should upgrade at all.\n\tif !ignoreVersion && u.index != nil {\n\t\tif err := u.index.ShouldUpgradeTo(downloader.index); err != nil {\n\t\t\treturn fmt.Errorf(\"cannot upgrade: %w\", ErrNoUpdateAvailable)\n\t\t}\n\t}\n\n\t// If we are running in a UI instance, we need to unload the UI assets\n\tif u.instance != nil {\n\t\tu.instance.UI().EnableUpgradeLock()\n\t\tdefer u.instance.UI().DisableUpgradeLock()\n\t}\n\n\t// Execute the upgrade.\n\tupgradeError := u.upgradeMoveFiles(downloader)\n\tif upgradeError == nil {\n\t\t// Files upgraded successfully.\n\t\t// Applying post-upgrade tasks, if any.\n\t\tupgradeError = u.applyPostUpgradeCommands()\n\t}\n\n\tif upgradeError == nil {\n\t\treturn nil\n\t}\n\n\t// Attempt to recover from failed upgrade.\n\trecoveryErr := u.recoverFromFailedUpgrade()\n\tif recoveryErr == nil {\n\t\treturn fmt.Errorf(\"upgrade failed, but recovery was successful: %w\", upgradeError)\n\t}\n\n\t// Recovery failed too.\n\treturn fmt.Errorf(\"upgrade (including recovery) failed: %w\", upgradeError)\n}\n\nfunc (u *Updater) upgradeMoveFiles(downloader *Downloader) error {\n\t// Important:\n\t// We assume that the downloader has done its job and all artifacts are verified.\n\t// Files will just be moved here.\n\t// In case the files are copied, they are verified in the process.\n\n\t// Reset purge directory, so that we can do a clean rollback later.\n\t_ = os.RemoveAll(u.cfg.PurgeDirectory)\n\terr := utils.EnsureDirectory(u.cfg.PurgeDirectory, utils.PublicReadExecPermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create purge directory: %w\", err)\n\t}\n\n\t// Move current version files into purge folder.\n\tif u.index != nil {\n\t\tlog.Debugf(\"updates/%s: removing the old version (v%s from %s)\", u.cfg.Name, u.index.Version, u.index.Published)\n\t}\n\tfiles, err := os.ReadDir(u.cfg.Directory)\n\tif err != nil {\n\t\tif !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"read current directory: %w\", err)\n\t\t}\n\t\terr := utils.EnsureDirectory(u.cfg.PurgeDirectory, utils.PublicReadExecPermission)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"create current directory: %w\", err)\n\t\t}\n\t} else {\n\t\t// Move files.\n\t\tfor _, file := range files {\n\t\t\t// Check if file is ignored.\n\t\t\tif slices.Contains(u.cfg.Ignore, file.Name()) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// ignore PurgeDirectory itself\n\t\t\tif strings.EqualFold(u.cfg.PurgeDirectory, filepath.Join(u.cfg.Directory, file.Name())) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Otherwise, move file to purge dir.\n\t\t\tsrc := filepath.Join(u.cfg.Directory, file.Name())\n\t\t\tdst := filepath.Join(u.cfg.PurgeDirectory, file.Name())\n\t\t\terr := u.moveFile(src, dst, \"\", utils.PublicReadPermission)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to move current file %s to purge dir: %w\", file.Name(), err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Move the new index file into main directory.\n\tlog.Debugf(\"updates/%s: installing the new version (v%s from %s)\", u.cfg.Name, downloader.index.Version, downloader.index.Published)\n\tsrc := filepath.Join(u.cfg.DownloadDirectory, u.cfg.IndexFile)\n\tdst := filepath.Join(u.cfg.Directory, u.cfg.IndexFile)\n\terr = u.moveFile(src, dst, \"\", utils.PublicReadPermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to move index file to %s: %w\", dst, err)\n\t}\n\n\t// Move downloaded files to the current version folder.\n\tfor _, artifact := range downloader.index.Artifacts {\n\t\tsrc = filepath.Join(u.cfg.DownloadDirectory, artifact.Filename)\n\t\tdst = filepath.Join(u.cfg.Directory, artifact.Filename)\n\t\terr = u.moveFile(src, dst, artifact.SHA256, artifact.GetFileMode())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to move file %s: %w\", artifact.Filename, err)\n\t\t} else {\n\t\t\tlog.Debugf(\"updates/%s: %s moved\", u.cfg.Name, artifact.Filename)\n\t\t}\n\t}\n\n\t// Set new index on module.\n\tu.index = downloader.index\n\tlog.Infof(\"updates/%s: update complete (v%s from %s)\", u.cfg.Name, u.index.Version, u.index.Published)\n\n\treturn nil\n}\n\n// moveFile moves a file and falls back to copying if it fails.\nfunc (u *Updater) moveFile(currentPath, newPath string, sha256sum string, filePermission utils.FSPermission) error {\n\t// Try to simply move file.\n\terr := os.Rename(currentPath, newPath)\n\tif err == nil {\n\t\t// Moving was successful, return.\n\t\tutils.SetFilePermission(newPath, filePermission)\n\t\treturn nil\n\t}\n\tlog.Tracef(\"updates/%s: failed to move to %q, falling back to copy+delete: %s\", u.cfg.Name, newPath, err)\n\n\t// Copy and check the checksum while we are at it.\n\terr = copyAndCheckSHA256Sum(currentPath, newPath, sha256sum, filePermission)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"move failed, copy+delete fallback failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// recoverFromFailedUpgrade attempts to roll back any moved files by the upgrade process.\nfunc (u *Updater) recoverFromFailedUpgrade() error {\n\t// Get list of files from purge dir.\n\tfiles, err := os.ReadDir(u.cfg.PurgeDirectory)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Move all files back to main dir.\n\tfor _, file := range files {\n\t\tpurgedFile := filepath.Join(u.cfg.PurgeDirectory, file.Name())\n\t\tactiveFile := filepath.Join(u.cfg.Directory, file.Name())\n\t\terr := u.moveFile(purgedFile, activeFile, \"\", utils.PublicReadPermission)\n\t\tif err != nil {\n\t\t\t// Only warn and continue to recover as many files as possible.\n\t\t\tlog.Warningf(\"updates/%s: failed to roll back file %s: %s\", u.cfg.Name, file.Name(), err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (u *Updater) cleanupAfterUpgrade() error {\n\terr := os.RemoveAll(u.cfg.PurgeDirectory)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"delete purge dir: %w\", err)\n\t}\n\n\terr = os.RemoveAll(u.cfg.DownloadDirectory)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"delete download dir: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (u *Updater) deleteUnfinishedFiles(dir string) error {\n\tentries, err := os.ReadDir(dir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, e := range entries {\n\t\tswitch {\n\t\tcase e.IsDir():\n\t\t\t// Continue.\n\n\t\tcase strings.HasSuffix(e.Name(), \".download\"):\n\t\t\tpath := filepath.Join(dir, e.Name())\n\t\t\tlog.Warningf(\"updates/%s: deleting unfinished download file: %s\", u.cfg.Name, path)\n\t\t\terr := os.Remove(path)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(\"updates/%s: failed to delete unfinished download file %s: %s\", u.cfg.Name, path, err)\n\t\t\t}\n\n\t\tcase strings.HasSuffix(e.Name(), \".copy\"):\n\t\t\tpath := filepath.Join(dir, e.Name())\n\t\t\tlog.Warningf(\"updates/%s: deleting unfinished copied file: %s\", u.cfg.Name, path)\n\t\t\terr := os.Remove(path)\n\t\t\tif err != nil {\n\t\t\t\tlog.Errorf(\"updates/%s: failed to delete unfinished copied file %s: %s\", u.cfg.Name, path, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (u *Updater) applyPostUpgradeCommands() error {\n\t// At this point, we assume that the upgrade was successful and all files are in place.\n\t// We need to execute the post-upgrade commands, if any.\n\n\tif len(u.cfg.PostUpgradeCommands) == 0 {\n\t\treturn nil\n\t}\n\n\t// collect full paths to files that were upgraded, required to check the trigger.\n\tupgradedFiles := make(map[string]struct{})\n\tfor _, artifact := range u.index.Artifacts {\n\t\tupgradedFiles[filepath.Join(u.cfg.Directory, artifact.Filename)] = struct{}{}\n\t}\n\n\t// Execute post-upgrade commands.\n\tfor _, puCmd := range u.cfg.PostUpgradeCommands {\n\n\t\t// Check trigger to ensure that we need to run this command.\n\t\tif len(puCmd.TriggerArtifactFName) > 0 {\n\t\t\tif _, ok := upgradedFiles[puCmd.TriggerArtifactFName]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tlog.Debugf(\"updates/%s: executing post-upgrade command: '%s %s'\", u.cfg.Name, puCmd.Command, strings.Join(puCmd.Args, \" \"))\n\t\toutput, err := exec.Command(puCmd.Command, puCmd.Args...).CombinedOutput()\n\t\tif err != nil {\n\t\t\tif puCmd.FailOnError {\n\t\t\t\treturn fmt.Errorf(\"post-upgrade command '%s %s' failed: %w, output: %s\", puCmd.Command, strings.Join(puCmd.Args, \" \"), err, string(output))\n\t\t\t}\n\n\t\t\tlog.Warningf(\"updates/%s: post-upgrade command '%s %s' failed, but ignored. Error: %s\", u.cfg.Name, puCmd.Command, strings.Join(puCmd.Args, \" \"), err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/TESTING.md",
    "content": "# Testing SPN\n\nThis page documents ways to test if the SPN works as intended.\n\n⚠ Work in Progress. Currently we are just collecting helpful things we find.\n\n## Test Multi-Identity Routing\n\nIn order to test if the multi-identity routing is working, you can request multiple websites to display your public IP.\nIf they show different values, multi-identity routing is working.\n\n### Websites\n\n- <https://icanhazip.com>\n- <https://ipecho.net>\n- <https://ipinfo.io>\n- <https://ipinfo.tw>\n\n### Terminal\n\n```sh\ncurl https://icanhazip.com\ncurl https://ipecho.net/plain\ncurl https://ipinfo.io/ip\ncurl https://ipinfo.tw/ip\n```\n"
  },
  {
    "path": "spn/TRADEMARKS",
    "content": "The names \"Safing\", \"Portmaster\", \"SPN\" and their logos are trademarks owned by Safing ICS Technologies GmbH (Austria).\n\nAlthough our code is free, it is very important that we strictly enforce our trademark rights, in order to be able to protect our users against people who use the marks to commit fraud. This means that, while you have considerable freedom to redistribute and modify our software, there are tight restrictions on your ability to use our names and logos in ways which fall in the domain of trademark law, even when built into binaries that we provide.\n\nThis file is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. Parts of it were taken from https://www.mozilla.org/en-US/foundation/licensing/.\n"
  },
  {
    "path": "spn/access/account/auth.go",
    "content": "package account\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n)\n\n// Authentication Headers.\nconst (\n\tAuthHeaderDevice              = \"Device-17\"\n\tAuthHeaderToken               = \"Token-17\"\n\tAuthHeaderNextToken           = \"Next-Token-17\"\n\tAuthHeaderNextTokenDeprecated = \"Next_token_17\"\n)\n\n// Errors.\nvar (\n\tErrMissingDeviceID = errors.New(\"missing device ID\")\n\tErrMissingToken    = errors.New(\"missing token\")\n)\n\n// AuthToken holds an authentication token.\ntype AuthToken struct {\n\tDevice string\n\tToken  string\n}\n\n// GetAuthTokenFromRequest extracts an authentication token from a request.\nfunc GetAuthTokenFromRequest(request *http.Request) (*AuthToken, error) {\n\tdevice := request.Header.Get(AuthHeaderDevice)\n\tif device == \"\" {\n\t\treturn nil, ErrMissingDeviceID\n\t}\n\ttoken := request.Header.Get(AuthHeaderToken)\n\tif token == \"\" {\n\t\treturn nil, ErrMissingToken\n\t}\n\n\treturn &AuthToken{\n\t\tDevice: device,\n\t\tToken:  token,\n\t}, nil\n}\n\n// ApplyTo applies the authentication token to a request.\nfunc (at *AuthToken) ApplyTo(request *http.Request) {\n\trequest.Header.Set(AuthHeaderDevice, at.Device)\n\trequest.Header.Set(AuthHeaderToken, at.Token)\n}\n\n// GetNextTokenFromResponse extracts an authentication token from a response.\nfunc GetNextTokenFromResponse(resp *http.Response) (token string, ok bool) {\n\ttoken = resp.Header.Get(AuthHeaderNextToken)\n\tif token == \"\" {\n\t\t// TODO: Remove when fixed on server.\n\t\ttoken = resp.Header.Get(AuthHeaderNextTokenDeprecated)\n\t}\n\n\treturn token, token != \"\"\n}\n\n// ApplyNextTokenToResponse applies the next authentication token to a response.\nfunc ApplyNextTokenToResponse(w http.ResponseWriter, token string) {\n\tw.Header().Set(AuthHeaderNextToken, token)\n}\n"
  },
  {
    "path": "spn/access/account/client.go",
    "content": "package account\n\n// Customer Agent URLs.\nconst (\n\tCAAuthenticateURL = \"/authenticate\"\n\tCAProfileURL      = \"/user/profile\"\n\tCAGetTokensURL    = \"/tokens\"\n)\n\n// Customer Hub URLs.\nconst (\n\tCHAuthenticateURL = \"/v1/authenticate\"\n\tCHUserProfileURL  = \"/v1/user_profile\"\n)\n"
  },
  {
    "path": "spn/access/account/types.go",
    "content": "package account\n\nimport (\n\t\"time\"\n\n\t\"golang.org/x/exp/slices\"\n)\n\n// User, Subscription and Charge states.\nconst (\n\t// UserStateNone is only used within Portmaster for saving information for\n\t// logging into the same device.\n\tUserStateNone      = \"\"\n\tUserStateFresh     = \"fresh\"\n\tUserStateQueued    = \"queued\"\n\tUserStateApproved  = \"approved\"\n\tUserStateSuspended = \"suspended\"\n\tUserStateLoggedOut = \"loggedout\" // Portmaster only.\n\n\tSubscriptionStateManual    = \"manual\"    // Manual renewal.\n\tSubscriptionStateActive    = \"active\"    // Automatic renewal.\n\tSubscriptionStateCancelled = \"cancelled\" // Automatic, but canceled.\n\n\tChargeStatePending   = \"pending\"\n\tChargeStateCompleted = \"completed\"\n\tChargeStateDead      = \"dead\"\n)\n\n// Agent and Hub return statuses.\nconst (\n\t// StatusInvalidAuth [401 Unauthorized] is returned when the credentials are\n\t// invalid or the user was logged out.\n\tStatusInvalidAuth = 401\n\t// StatusNoAccess [403 Forbidden] is returned when the user does not have\n\t// an active subscription or the subscription does not include the required\n\t// feature for the request.\n\tStatusNoAccess = 403\n\t// StatusInvalidDevice [410 Gone] is returned when the device trying to\n\t// log into does not exist.\n\tStatusInvalidDevice = 410\n\t// StatusReachedDeviceLimit [409 Conflict] is returned when the device limit is reached.\n\tStatusReachedDeviceLimit = 409\n\t// StatusDeviceInactive [423 Locked] is returned when the device is locked.\n\tStatusDeviceInactive = 423\n\t// StatusNotLoggedIn [412 Precondition] is returned by the Portmaster, if an action required to be logged in, but the user is not logged in.\n\tStatusNotLoggedIn = 412\n\n\t// StatusUnknownError is a special status code that signifies an unknown or\n\t// unexpected error by the API.\n\tStatusUnknownError = -1\n\t// StatusConnectionError is a special status code that signifies a\n\t// connection error.\n\tStatusConnectionError = -2\n)\n\n// User describes an SPN user account.\ntype User struct {\n\tUsername     string        `json:\"username\"`\n\tState        string        `json:\"state\"`\n\tBalance      int           `json:\"balance\"`\n\tDevice       *Device       `json:\"device\"`\n\tSubscription *Subscription `json:\"subscription\"`\n\tCurrentPlan  *Plan         `json:\"current_plan\"`\n\tNextPlan     *Plan         `json:\"next_plan\"`\n\tView         *View         `json:\"view\"`\n}\n\n// MayUseSPN returns whether the user may currently use the SPN.\nfunc (u *User) MayUseSPN() bool {\n\treturn u.MayUse(FeatureSPN)\n}\n\n// MayUsePrioritySupport returns whether the user may currently use the priority support.\nfunc (u *User) MayUsePrioritySupport() bool {\n\treturn u.MayUse(FeatureSafingSupport)\n}\n\n// MayUse returns whether the user may currently use the feature identified by\n// the given feature ID.\n// Leave feature ID empty to check without feature.\nfunc (u *User) MayUse(featureID FeatureID) bool {\n\tswitch {\n\tcase u == nil:\n\t\t// We need a user, obviously.\n\tcase u.State != UserStateApproved:\n\t\t// Only approved users may use the SPN.\n\tcase u.Subscription == nil:\n\t\t// Need a subscription.\n\tcase u.Subscription.EndsAt == nil:\n\tcase time.Now().After(*u.Subscription.EndsAt):\n\t\t// Subscription needs to be active.\n\tcase u.CurrentPlan == nil:\n\t\t// Need a plan / package.\n\tcase featureID != \"\" &&\n\t\t!slices.Contains(u.CurrentPlan.FeatureIDs, featureID):\n\t\t// Required feature ID must be in plan / package feature IDs.\n\tdefault:\n\t\t// All checks passed!\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Device describes a device of an SPN user.\ntype Device struct {\n\tName string `json:\"name\"`\n\tID   string `json:\"id\"`\n}\n\n// Subscription describes an SPN subscription.\ntype Subscription struct {\n\tEndsAt          *time.Time `json:\"ends_at\"`\n\tState           string     `json:\"state\"`\n\tNextBillingDate *time.Time `json:\"next_billing_date\"`\n\tPaymentProvider string     `json:\"payment_provider\"`\n}\n\n// FeatureID defines a feature that requires a plan/subscription.\ntype FeatureID string\n\n// A list of all supported features.\nconst (\n\tFeatureSPN           = FeatureID(\"spn\")\n\tFeatureSafingSupport = FeatureID(\"support\")\n\tFeatureHistory       = FeatureID(\"history\")\n\tFeatureBWVis         = FeatureID(\"bw-vis\")\n\tFeatureVPNCompat     = FeatureID(\"vpn-compat\")\n)\n\n// Plan describes an SPN subscription plan.\ntype Plan struct {\n\tName       string      `json:\"name\"`\n\tAmount     int         `json:\"amount\"`\n\tMonths     int         `json:\"months\"`\n\tRenewable  bool        `json:\"renewable\"`\n\tFeatureIDs []FeatureID `json:\"feature_ids\"`\n}\n"
  },
  {
    "path": "spn/access/account/view.go",
    "content": "package account\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n)\n\n// View holds metadata that assists in displaying account information.\ntype View struct {\n\tMessage           string\n\tShowAccountData   bool\n\tShowAccountButton bool\n\tShowLoginButton   bool\n\tShowRefreshButton bool\n\tShowLogoutButton  bool\n}\n\n// UpdateView updates the view and handles plan/package fallbacks.\nfunc (u *User) UpdateView(requestStatusCode int) {\n\tv := &View{}\n\n\t// Clean up naming and fallbacks when finished.\n\tdefer func() {\n\t\t// Display \"Free\" package if no plan is set or if it expired.\n\t\tswitch {\n\t\tcase u.CurrentPlan == nil,\n\t\t\tu.Subscription == nil,\n\t\t\tu.Subscription.EndsAt == nil:\n\t\t\t// Reset to free plan.\n\t\t\tu.CurrentPlan = &Plan{\n\t\t\t\tName: \"Free\",\n\t\t\t}\n\t\t\tu.Subscription = nil\n\n\t\tcase u.Subscription.NextBillingDate != nil:\n\t\t\t// Subscription is on auto-renew.\n\t\t\t// Wait for update from server.\n\n\t\tcase time.Since(*u.Subscription.EndsAt) > 0:\n\t\t\t// Reset to free plan.\n\t\t\tu.CurrentPlan = &Plan{\n\t\t\t\tName: \"Free\",\n\t\t\t}\n\t\t\tu.Subscription = nil\n\t\t}\n\n\t\t// Prepend \"Portmaster \" to plan name.\n\t\t// TODO: Remove when Plan/Package naming has been updated.\n\t\tif u.CurrentPlan != nil && !strings.HasPrefix(u.CurrentPlan.Name, \"Portmaster \") {\n\t\t\tu.CurrentPlan.Name = \"Portmaster \" + u.CurrentPlan.Name\n\t\t}\n\n\t\t// Apply new view to user.\n\t\tu.View = v\n\t}()\n\n\t// Set view data based on return code.\n\tswitch requestStatusCode {\n\tcase StatusInvalidAuth, StatusInvalidDevice, StatusDeviceInactive:\n\t\t// Account deleted or Device inactive or deleted.\n\t\t// When using token based auth, there is no difference between these cases.\n\t\tv.Message = \"This device may have been deactivated or removed from your account. Please log in again.\"\n\t\tv.ShowAccountData = true\n\t\tv.ShowAccountButton = true\n\t\tv.ShowLoginButton = true\n\t\tv.ShowLogoutButton = true\n\t\treturn\n\n\tcase StatusUnknownError:\n\t\tv.Message = \"There is an unknown error in the communication with the account server. The shown information may not be accurate. \"\n\n\tcase StatusConnectionError:\n\t\tv.Message = \"Portmaster could not connect to the account server. The shown information may not be accurate. \"\n\t}\n\n\t// Set view data based on profile data.\n\tswitch {\n\tcase u.State == UserStateLoggedOut:\n\t\t// User logged out.\n\t\tv.ShowAccountButton = true\n\t\tv.ShowLoginButton = true\n\t\treturn\n\n\tcase u.State == UserStateSuspended:\n\t\t// Account is suspended.\n\t\tv.Message += fmt.Sprintf(\"Your account (%s) was suspended. Please contact support for details.\", u.Username)\n\t\tv.ShowAccountButton = true\n\t\tv.ShowRefreshButton = true\n\t\tv.ShowLogoutButton = true\n\t\treturn\n\n\tcase u.Subscription == nil || u.Subscription.EndsAt == nil:\n\t\t// Account has never had a subscription.\n\t\tv.Message += \"Get more features. Upgrade today.\"\n\n\tcase u.Subscription.NextBillingDate != nil:\n\t\tswitch {\n\t\tcase time.Since(*u.Subscription.NextBillingDate) > 0:\n\t\t\tv.Message += \"Your auto-renewal seems to be delayed. Please refresh and check the status of your payment. Payment information may be delayed.\"\n\t\tcase time.Until(*u.Subscription.NextBillingDate) < 24*time.Hour:\n\t\t\tv.Message += \"Your subscription will auto-renew soon. Please note that payment information may be delayed.\"\n\t\t}\n\n\tcase time.Since(*u.Subscription.EndsAt) > 0:\n\t\t// Subscription expired.\n\t\tif u.CurrentPlan != nil {\n\t\t\tv.Message += fmt.Sprintf(\"Your package %s has ended. Extend it on the Account Page.\", u.CurrentPlan.Name)\n\t\t} else {\n\t\t\tv.Message += \"Your package has ended. Extend it on the Account Page.\"\n\t\t}\n\n\tcase time.Until(*u.Subscription.EndsAt) < 7*24*time.Hour:\n\t\t// Add generic ending soon message if the package ends in less than 7 days.\n\t\tv.Message += \"Your package ends soon. Extend it on the Account Page.\"\n\t}\n\n\t// Defaults for generally good accounts.\n\tv.ShowAccountData = true\n\tv.ShowAccountButton = true\n\tv.ShowRefreshButton = true\n\tv.ShowLogoutButton = true\n}\n"
  },
  {
    "path": "spn/access/api.go",
    "content": "package access\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/access/account\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/account/login`,\n\t\tWrite:       api.PermitAdmin,\n\t\tWriteMethod: http.MethodPost,\n\t\tHandlerFunc: handleLogin,\n\t\tName:        \"SPN Login\",\n\t\tDescription: \"Log into your SPN account.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/account/logout`,\n\t\tWrite:       api.PermitAdmin,\n\t\tWriteMethod: http.MethodDelete,\n\t\tActionFunc:  handleLogout,\n\t\tName:        \"SPN Logout\",\n\t\tDescription: \"Logout from your SPN account.\",\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodDelete,\n\t\t\t\tField:       \"purge\",\n\t\t\t\tValue:       \"\",\n\t\t\t\tDescription: \"If set, account data is purged. Otherwise, the username and device ID are kept in order to log into the same device when logging in with the same user again.\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/account/user/profile`,\n\t\tRead:        api.PermitUser,\n\t\tReadMethod:  http.MethodGet,\n\t\tRecordFunc:  handleGetUserProfile,\n\t\tName:        \"SPN User Profile\",\n\t\tDescription: \"Get the user profile of the logged in SPN account.\",\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"refresh\",\n\t\t\t\tValue:       \"\",\n\t\t\t\tDescription: \"If set, the user profile is freshly fetched from the account server.\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:       `account/features`,\n\t\tRead:       api.PermitUser,\n\t\tReadMethod: http.MethodGet,\n\t\tStructFunc: func(_ *api.Request) (i interface{}, err error) {\n\t\t\treturn struct {\n\t\t\t\tFeatures []Feature\n\t\t\t}{\n\t\t\t\tFeatures: features,\n\t\t\t}, nil\n\t\t},\n\t\tName:        \"Get Account Features\",\n\t\tDescription: \"Returns all account features.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:       `account/features/{id:[A-Za-z0-9_-]+}/icon`,\n\t\tRead:       api.PermitUser,\n\t\tReadMethod: http.MethodGet,\n\t\tName:       \"Returns the image of the featuare\",\n\t\tMimeType:   \"image/svg+xml\",\n\t\tDataFunc: func(ar *api.Request) (data []byte, err error) {\n\t\t\tfeatureID, ok := ar.URLVars[\"id\"]\n\t\t\tif !ok {\n\t\t\t\treturn nil, errors.New(\"invalid feature id\")\n\t\t\t}\n\n\t\t\tfor _, feature := range features {\n\t\t\t\tif feature.ID == featureID {\n\t\t\t\t\treturn []byte(feature.icon), nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil, errors.New(\"feature id not found\")\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleLogin(w http.ResponseWriter, r *http.Request) {\n\t// Get username and password.\n\tusername, password, ok := r.BasicAuth()\n\t// Request, if omitted.\n\tif !ok || username == \"\" || password == \"\" {\n\t\tw.Header().Set(\"WWW-Authenticate\", \"Basic realm=SPN Login\")\n\t\thttp.Error(w, \"Login with your SPN account.\", http.StatusUnauthorized)\n\t\treturn\n\t}\n\n\t// Process login.\n\tuser, code, err := Login(username, password)\n\tif err != nil {\n\t\tlog.Warningf(\"spn/access: failed to login: %s\", err)\n\t\tif code == 0 {\n\t\t\thttp.Error(w, \"Internal error: \"+err.Error(), http.StatusInternalServerError)\n\t\t} else {\n\t\t\thttp.Error(w, err.Error(), code)\n\t\t}\n\t\treturn\n\t}\n\n\t// Return success.\n\t_, _ = w.Write([]byte(\n\t\tfmt.Sprintf(\"Now logged in as %s as device %s\", user.Username, user.Device.Name),\n\t))\n}\n\nfunc handleLogout(ar *api.Request) (msg string, err error) {\n\tpurge := ar.URL.Query().Get(\"purge\") != \"\"\n\terr = Logout(false, purge)\n\tswitch {\n\tcase err != nil:\n\t\tlog.Warningf(\"spn/access: failed to logout: %s\", err)\n\t\treturn \"\", err\n\tcase purge:\n\t\treturn \"Logged out and user data purged.\", nil\n\tdefault:\n\t\treturn \"Logged out.\", nil\n\t}\n}\n\nfunc handleGetUserProfile(ar *api.Request) (r record.Record, err error) {\n\t// Check if we are already authenticated.\n\tuser, err := GetUser()\n\tif err != nil || user.State == account.UserStateNone {\n\t\treturn nil, api.ErrorWithStatus(\n\t\t\tErrNotLoggedIn,\n\t\t\taccount.StatusInvalidAuth,\n\t\t)\n\t}\n\n\t// Should we refresh the user profile?\n\tif ar.URL.Query().Get(\"refresh\") != \"\" {\n\t\tuser, _, err = UpdateUser()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn user, nil\n}\n"
  },
  {
    "path": "spn/access/client.go",
    "content": "package access\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/access/account\"\n\t\"github.com/safing/portmaster/spn/access/token\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// Client URLs.\nconst (\n\tAccountServer         = \"https://api.account.safing.io\"\n\tLoginPath             = \"/api/v1/authenticate\"\n\tUserProfilePath       = \"/api/v1/user/profile\"\n\tTokenRequestSetupPath = \"/api/v1/token/request/setup\" //nolint:gosec\n\tTokenRequestIssuePath = \"/api/v1/token/request/issue\" //nolint:gosec\n\tHealthCheckPath       = \"/api/v1/health\"\n\n\tdefaultDataFormat     = dsd.CBOR\n\tdefaultRequestTimeout = 30 * time.Second\n)\n\nvar (\n\taccountClient     = &http.Client{}\n\tclientRequestLock sync.Mutex\n\n\t// EnableAfterLogin automatically enables the SPN subsystem/module after login.\n\tEnableAfterLogin = true\n)\n\ntype clientRequestOptions struct {\n\tmethod               string\n\turl                  string\n\tsend                 interface{}\n\trecv                 interface{}\n\trequestTimeout       time.Duration\n\tdataFormat           uint8\n\tsetAuthToken         bool\n\trequireNextAuthToken bool\n\tlogoutOnAuthError    bool\n\trequestSetupFunc     func(*http.Request) error\n}\n\nfunc makeClientRequest(opts *clientRequestOptions) (resp *http.Response, err error) {\n\t// Get request timeout.\n\tif opts.requestTimeout == 0 {\n\t\topts.requestTimeout = defaultRequestTimeout\n\t}\n\t// Get context for request.\n\tvar ctx context.Context\n\tvar cancel context.CancelFunc\n\tctx, cancel = context.WithTimeout(module.mgr.Ctx(), opts.requestTimeout)\n\tdefer cancel()\n\n\t// Create new request.\n\trequest, err := http.NewRequestWithContext(ctx, opts.method, opts.url, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create request structure: %w\", err)\n\t}\n\n\t// Prepare body and content type.\n\tif opts.dataFormat == dsd.AUTO {\n\t\topts.dataFormat = defaultDataFormat\n\t}\n\tif opts.send != nil {\n\t\t// Add data to body.\n\t\terr = dsd.DumpToHTTPRequest(request, opts.send, opts.dataFormat)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to add request body: %w\", err)\n\t\t}\n\t} else {\n\t\t// Set requested HTTP response format.\n\t\t_, err = dsd.RequestHTTPResponseFormat(request, opts.dataFormat)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to set requested response format: %w\", err)\n\t\t}\n\t}\n\n\t// Get auth token to apply to request.\n\tvar authToken *AuthTokenRecord\n\tif opts.setAuthToken {\n\t\tauthToken, err = GetAuthToken()\n\t\tif err != nil {\n\t\t\treturn nil, ErrNotLoggedIn\n\t\t}\n\t\tauthToken.Token.ApplyTo(request)\n\t}\n\n\t// Do any additional custom request setup.\n\tif opts.requestSetupFunc != nil {\n\t\terr = opts.requestSetupFunc(request)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Make request.\n\tresp, err = accountClient.Do(request)\n\tif err != nil {\n\t\tupdateUserWithFailedRequest(account.StatusConnectionError, false)\n\t\ttokenIssuerFailed()\n\t\treturn nil, fmt.Errorf(\"http request failed: %w\", err)\n\t}\n\tlog.Debugf(\"spn/access: request to %s returned %s\", request.URL, resp.Status)\n\tdefer func() {\n\t\t_ = resp.Body.Close()\n\t}()\n\t// Handle request error.\n\tswitch resp.StatusCode {\n\tcase http.StatusOK, http.StatusCreated:\n\t\t// All good!\n\n\tcase account.StatusInvalidAuth, account.StatusInvalidDevice:\n\t\t// Wrong username / password.\n\t\tupdateUserWithFailedRequest(resp.StatusCode, true)\n\t\treturn resp, ErrInvalidCredentials\n\n\tcase account.StatusReachedDeviceLimit:\n\t\t// Device limit is reached.\n\t\tupdateUserWithFailedRequest(resp.StatusCode, true)\n\t\treturn resp, ErrDeviceLimitReached\n\n\tcase account.StatusDeviceInactive:\n\t\t// Device is locked.\n\t\tupdateUserWithFailedRequest(resp.StatusCode, true)\n\t\treturn resp, ErrDeviceIsLocked\n\n\tdefault:\n\t\tupdateUserWithFailedRequest(account.StatusUnknownError, false)\n\t\ttokenIssuerFailed()\n\t\treturn resp, fmt.Errorf(\"unexpected reply: [%d] %s\", resp.StatusCode, resp.Status)\n\t}\n\n\t// Save next auth token.\n\tif authToken != nil {\n\t\terr = authToken.Update(resp)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, account.ErrMissingToken) {\n\t\t\t\tif opts.requireNextAuthToken {\n\t\t\t\t\treturn resp, fmt.Errorf(\"failed to save next auth token: %w\", err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn resp, fmt.Errorf(\"failed to save next auth token: %w\", err)\n\t\t\t}\n\t\t}\n\t} else if opts.requireNextAuthToken {\n\t\treturn resp, fmt.Errorf(\"failed to save next auth token: %w\", account.ErrMissingToken)\n\t}\n\n\t// Load response data.\n\tif opts.recv != nil {\n\t\t_, err = dsd.LoadFromHTTPResponse(resp, opts.recv)\n\t\tif err != nil {\n\t\t\treturn resp, fmt.Errorf(\"failed to parse response: %w\", err)\n\t\t}\n\t}\n\n\ttokenIssuerIsFailing.UnSet()\n\treturn resp, nil\n}\n\nfunc updateUserWithFailedRequest(statusCode int, disableSubscription bool) {\n\t// Get user from database.\n\tuser, err := GetUser()\n\tif err != nil {\n\t\tif !errors.Is(err, ErrNotLoggedIn) {\n\t\t\tlog.Warningf(\"spn/access: failed to get user to update with failed request: %s\", err)\n\t\t}\n\t\treturn\n\t}\n\n\tfunc() {\n\t\tuser.Lock()\n\t\tdefer user.Unlock()\n\n\t\t// Ignore update if user state is undefined or logged out.\n\t\tif user.State == \"\" || user.State == account.UserStateLoggedOut {\n\t\t\treturn\n\t\t}\n\n\t\t// Disable the subscription if desired.\n\t\tif disableSubscription && user.Subscription != nil {\n\t\t\tuser.Subscription.EndsAt = nil\n\t\t}\n\n\t\t// Update view with the status code and save user.\n\t\tuser.UpdateView(statusCode)\n\t}()\n\n\terr = user.Save()\n\tif err != nil {\n\t\tlog.Warningf(\"spn/access: failed to save user after update with failed request: %s\", err)\n\t}\n}\n\n// Login logs the user into the SPN account with the given username and password.\nfunc Login(username, password string) (user *UserRecord, code int, err error) {\n\tclientRequestLock.Lock()\n\tdefer clientRequestLock.Unlock()\n\n\t// Trigger account update when done.\n\tdefer module.EventAccountUpdate.Submit(struct{}{})\n\n\t// Get previous user.\n\tpreviousUser, err := GetUser()\n\tif err != nil {\n\t\tif !errors.Is(err, ErrNotLoggedIn) {\n\t\t\tlog.Warningf(\"spn/access: failed to get previous for re-login: %s\", err)\n\t\t}\n\t\tpreviousUser = nil\n\t}\n\n\t// Create request options.\n\tuserAccount := &account.User{}\n\trequestOptions := &clientRequestOptions{\n\t\tmethod:     http.MethodPost,\n\t\turl:        AccountServer + LoginPath,\n\t\trecv:       userAccount,\n\t\tdataFormat: dsd.JSON,\n\t\trequestSetupFunc: func(request *http.Request) error {\n\t\t\t// Add username and password.\n\t\t\trequest.SetBasicAuth(username, password)\n\n\t\t\t// Try to reuse the device ID, if the username matches the previous user.\n\t\t\tif previousUser != nil && username == previousUser.Username {\n\t\t\t\trequest.Header.Set(account.AuthHeaderDevice, previousUser.Device.ID)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n\n\t// Make request.\n\tresp, err := makeClientRequest(requestOptions) //nolint:bodyclose // Body is closed in function.\n\tif err != nil {\n\t\tif resp != nil && resp.StatusCode == account.StatusInvalidDevice {\n\t\t\t// Try again without the previous device ID.\n\t\t\tpreviousUser = nil\n\t\t\tlog.Info(\"spn/access: retrying log in without re-using previous device ID\")\n\t\t\tresp, err = makeClientRequest(requestOptions) //nolint:bodyclose // Body is closed in function.\n\t\t}\n\t\tif err != nil {\n\t\t\tif resp != nil {\n\t\t\t\treturn nil, resp.StatusCode, err\n\t\t\t}\n\t\t\treturn nil, 0, err\n\t\t}\n\t}\n\n\t// Save new user.\n\tnow := time.Now()\n\tuser = &UserRecord{\n\t\tUser:       userAccount,\n\t\tLoggedInAt: &now,\n\t}\n\n\tuser.UpdateView(0)\n\terr = user.Save()\n\tif err != nil {\n\t\treturn user, resp.StatusCode, fmt.Errorf(\"failed to save new user profile: %w\", err)\n\t}\n\n\t// Save initial auth token.\n\terr = SaveNewAuthToken(user.Device.ID, resp)\n\tif err != nil {\n\t\treturn user, resp.StatusCode, fmt.Errorf(\"failed to save initial auth token: %w\", err)\n\t}\n\n\t// Enable the SPN right after login.\n\tif user.MayUseSPN() && EnableAfterLogin {\n\t\tenableSPN()\n\t}\n\n\tlog.Infof(\"spn/access: logged in as %q on device %q\", user.Username, user.Device.Name)\n\treturn user, resp.StatusCode, nil\n}\n\n// Logout logs the user out of the SPN account.\n// Specify \"shallow\" to keep user data in order to display data in the\n// UI - preferably when logged out be the server.\n// Specify \"purge\" in order to fully delete all user account data, even\n// the device ID so that logging in again will create a new device.\nfunc Logout(shallow, purge bool) error {\n\tclientRequestLock.Lock()\n\tdefer clientRequestLock.Unlock()\n\n\t// Trigger account update when done.\n\tdefer module.EventAccountUpdate.Submit(struct{}{})\n\n\t// Clear caches.\n\tclearUserCaches()\n\n\t// Clear tokens.\n\tclearTokens()\n\n\t// Delete auth token.\n\terr := db.Delete(authTokenRecordKey)\n\tif err != nil && !errors.Is(err, database.ErrNotFound) {\n\t\treturn fmt.Errorf(\"failed to delete auth token: %w\", err)\n\t}\n\n\t// Delete all user data if purging.\n\tif purge {\n\t\terr := db.Delete(userRecordKey)\n\t\tif err != nil && !errors.Is(err, database.ErrNotFound) {\n\t\t\treturn fmt.Errorf(\"failed to delete user: %w\", err)\n\t\t}\n\n\t\t// Disable SPN when the user logs out directly.\n\t\tdisableSPN()\n\n\t\tlog.Info(\"spn/access: logged out and purged data\")\n\t\treturn nil\n\t}\n\n\t// Else, just update the user.\n\tuser, err := GetUser()\n\tif err != nil {\n\t\tif errors.Is(err, ErrNotLoggedIn) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"failed to load user for logout: %w\", err)\n\t}\n\n\tfunc() {\n\t\tuser.Lock()\n\t\tdefer user.Unlock()\n\n\t\tif shallow {\n\t\t\t// Shallow logout: User stays logged in the UI to display status when\n\t\t\t// logged out from the Portmaster or Customer Hub.\n\t\t\tuser.User.State = account.UserStateLoggedOut\n\t\t} else {\n\t\t\t// Proper logout: User is logged out from UI.\n\t\t\t// Reset all user data, except for username and device ID in order to log\n\t\t\t// into the same device again.\n\t\t\tuser.User = &account.User{\n\t\t\t\tUsername: user.Username,\n\t\t\t\tDevice: &account.Device{\n\t\t\t\t\tID: user.Device.ID,\n\t\t\t\t},\n\t\t\t}\n\t\t\tuser.LoggedInAt = &time.Time{}\n\t\t}\n\t\tuser.UpdateView(0)\n\t}()\n\terr = user.Save()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to save user for logout: %w\", err)\n\t}\n\n\tif shallow {\n\t\tlog.Info(\"spn/access: logged out shallow\")\n\t} else {\n\t\tlog.Info(\"spn/access: logged out\")\n\n\t\t// Disable SPN when the user logs out directly.\n\t\tdisableSPN()\n\t}\n\n\treturn nil\n}\n\n// UpdateUser fetches the current user information from the server.\nfunc UpdateUser() (user *UserRecord, statusCode int, err error) {\n\tclientRequestLock.Lock()\n\tdefer clientRequestLock.Unlock()\n\n\t// Trigger account update when done.\n\tdefer module.EventAccountUpdate.Submit(struct{}{})\n\n\t// Create request options.\n\tuserData := &account.User{}\n\trequestOptions := &clientRequestOptions{\n\t\tmethod:               http.MethodGet,\n\t\turl:                  AccountServer + UserProfilePath,\n\t\trecv:                 userData,\n\t\tdataFormat:           dsd.JSON,\n\t\tsetAuthToken:         true,\n\t\trequireNextAuthToken: true,\n\t\tlogoutOnAuthError:    true,\n\t}\n\n\t// Make request.\n\tresp, err := makeClientRequest(requestOptions) //nolint:bodyclose // Body is closed in function.\n\tif err != nil {\n\t\tif resp != nil {\n\t\t\treturn nil, resp.StatusCode, err\n\t\t}\n\t\treturn nil, 0, err\n\t}\n\n\t// Save to previous user, if exists.\n\tpreviousUser, err := GetUser()\n\tif err == nil {\n\t\tfunc() {\n\t\t\tpreviousUser.Lock()\n\t\t\tdefer previousUser.Unlock()\n\t\t\tpreviousUser.User = userData\n\t\t\tpreviousUser.UpdateView(resp.StatusCode)\n\t\t}()\n\t\terr := previousUser.Save()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/access: failed to save updated user profile: %s\", err)\n\t\t}\n\n\t\t// Notify user of nearing end of package.\n\t\tnotifyOfPackageEnd(previousUser)\n\n\t\tlog.Infof(\"spn/access: got user profile, updated existing\")\n\t\treturn previousUser, resp.StatusCode, nil\n\t}\n\n\t// Else, save as new user.\n\tnow := time.Now()\n\tnewUser := &UserRecord{\n\t\tUser:       userData,\n\t\tLoggedInAt: &now,\n\t}\n\tnewUser.UpdateView(resp.StatusCode)\n\terr = newUser.Save()\n\tif err != nil {\n\t\tlog.Warningf(\"spn/access: failed to save new user profile: %s\", err)\n\t}\n\n\t// Notify user of nearing end of package.\n\tnotifyOfPackageEnd(newUser)\n\n\tlog.Infof(\"spn/access: got user profile, saved as new\")\n\treturn newUser, resp.StatusCode, nil\n}\n\n// UpdateTokens fetches more tokens for handlers that need it.\nfunc UpdateTokens() error {\n\tclientRequestLock.Lock()\n\tdefer clientRequestLock.Unlock()\n\n\t// Check if the user may request tokens.\n\tuser, err := GetUser()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get user: %w\", err)\n\t}\n\tif !user.MayUseTheSPN() {\n\t\treturn ErrMayNotUseSPN\n\t}\n\n\t// Create setup request, return if not required.\n\tsetupRequest, setupRequired := token.CreateSetupRequest()\n\tvar setupResponse *token.SetupResponse\n\tif setupRequired {\n\t\t// Request setup data.\n\t\tsetupResponse = &token.SetupResponse{}\n\t\t_, err := makeClientRequest(&clientRequestOptions{ //nolint:bodyclose // Body is closed in function.\n\t\t\tmethod:            http.MethodPost,\n\t\t\turl:               AccountServer + TokenRequestSetupPath,\n\t\t\tsend:              setupRequest,\n\t\t\trecv:              setupResponse,\n\t\t\tdataFormat:        dsd.MsgPack,\n\t\t\tsetAuthToken:      true,\n\t\t\tlogoutOnAuthError: true,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to request setup data: %w\", err)\n\t\t}\n\t}\n\n\t// Create request for issuing new tokens.\n\ttokenRequest, requestRequired, err := token.CreateTokenRequest(setupResponse)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create token request: %w\", err)\n\t}\n\tif !requestRequired {\n\t\treturn nil\n\t}\n\n\t// Request issuing new tokens.\n\tissuedTokens := &token.IssuedTokens{}\n\t_, err = makeClientRequest(&clientRequestOptions{ //nolint:bodyclose // Body is closed in function.\n\t\tmethod:            http.MethodPost,\n\t\turl:               AccountServer + TokenRequestIssuePath,\n\t\tsend:              tokenRequest,\n\t\trecv:              issuedTokens,\n\t\tdataFormat:        dsd.MsgPack,\n\t\tsetAuthToken:      true,\n\t\tlogoutOnAuthError: true,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to request tokens: %w\", err)\n\t}\n\n\t// Save tokens to handlers.\n\terr = token.ProcessIssuedTokens(issuedTokens)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to process issued tokens: %w\", err)\n\t}\n\n\t// Log new status.\n\tregular, fallback := GetTokenAmount(ExpandAndConnectZones)\n\tlog.Infof(\n\t\t\"spn/access: got new tokens, now at %d regular and %d fallback tokens for expand and connect\",\n\t\tregular,\n\t\tfallback,\n\t)\n\n\treturn nil\n}\n\nvar (\n\tlastHealthCheckExpires          time.Time\n\tlastHealthCheckLock             sync.Mutex\n\tlastHealthCheckValidityDuration = 30 * time.Second\n)\n\nfunc healthCheck() (ok bool) {\n\tlastHealthCheckLock.Lock()\n\tdefer lastHealthCheckLock.Unlock()\n\n\t// Return current value if recently checked.\n\tif time.Now().Before(lastHealthCheckExpires) {\n\t\treturn tokenIssuerIsFailing.IsNotSet()\n\t}\n\n\t// Check health.\n\t_, err := makeClientRequest(&clientRequestOptions{ //nolint:bodyclose // Body is closed in function.\n\t\tmethod: http.MethodGet,\n\t\turl:    AccountServer + HealthCheckPath,\n\t})\n\tif err != nil {\n\t\tlog.Warningf(\"spn/access: token issuer health check failed: %s\", err)\n\t}\n\t// Update health check expiry.\n\tlastHealthCheckExpires = time.Now().Add(lastHealthCheckValidityDuration)\n\n\treturn tokenIssuerIsFailing.IsNotSet()\n}\n"
  },
  {
    "path": "spn/access/client_test.go",
    "content": "package access\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\nvar (\n\ttestUsername = os.Getenv(\"SPN_TEST_USERNAME\")\n\ttestPassword = os.Getenv(\"SPN_TEST_PASSWORD\")\n)\n\nfunc TestClient(t *testing.T) {\n\t// Skip test in CI.\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\tt.Parallel()\n\n\tif testUsername == \"\" || testPassword == \"\" {\n\t\tt.Fatal(\"test username or password not configured\")\n\t}\n\n\tloginAndRefresh(t, true, 5)\n\tclearUserCaches()\n\tloginAndRefresh(t, false, 1)\n\n\terr := Logout(false, false)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to log out: %s\", err)\n\t}\n\tt.Logf(\"logged out\")\n\n\tloginAndRefresh(t, true, 1)\n\n\terr = Logout(false, true)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to log out: %s\", err)\n\t}\n\tt.Logf(\"logged out with purge\")\n\n\tloginAndRefresh(t, true, 1)\n}\n\nfunc loginAndRefresh(t *testing.T, doLogin bool, refreshTimes int) {\n\tt.Helper()\n\n\tif doLogin {\n\t\t_, _, err := Login(testUsername, testPassword)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"login failed: %s\", err)\n\t\t}\n\t\tuser, err := GetUser()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to get user: %s\", err)\n\t\t}\n\t\tt.Logf(\"user (from login): %+v\", user.User)\n\t\tt.Logf(\"device (from login): %+v\", user.User.Device)\n\t\tauthToken, err := GetAuthToken()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to get auth token: %s\", err)\n\t\t}\n\t\tt.Logf(\"auth token: %+v\", authToken.Token)\n\t}\n\n\tfor range refreshTimes {\n\t\tuser, _, err := UpdateUser()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"getting profile failed: %s\", err)\n\t\t}\n\t\tt.Logf(\"user (from refresh): %+v\", user.User)\n\n\t\tauthToken, err := GetAuthToken()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to get auth token: %s\", err)\n\t\t}\n\t\tt.Logf(\"auth token: %+v\", authToken.Token)\n\t}\n}\n"
  },
  {
    "path": "spn/access/database.go",
    "content": "package access\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/spn/access/account\"\n)\n\nconst (\n\tuserRecordKey           = \"core:spn/account/user\"\n\tauthTokenRecordKey      = \"core:spn/account/authtoken\" //nolint:gosec // Not a credential.\n\ttokenStorageKeyTemplate = \"core:spn/account/tokens/%s\" //nolint:gosec // Not a credential.\n)\n\nvar db = database.NewInterface(&database.Options{\n\tLocal:    true,\n\tInternal: true,\n})\n\n// UserRecord holds a SPN user account.\ntype UserRecord struct {\n\trecord.Base\n\tsync.Mutex\n\n\t*account.User\n\n\tLastNotifiedOfEnd *time.Time\n\tLoggedInAt        *time.Time\n}\n\n// MayUseSPN returns whether the user may currently use the SPN.\nfunc (user *UserRecord) MayUseSPN() bool {\n\t// Shadow this function in order to allow calls on a nil user.\n\tif user == nil || user.User == nil {\n\t\treturn false\n\t}\n\treturn user.User.MayUseSPN()\n}\n\n// MayUsePrioritySupport returns whether the user may currently use the priority support.\nfunc (user *UserRecord) MayUsePrioritySupport() bool {\n\t// Shadow this function in order to allow calls on a nil user.\n\tif user == nil || user.User == nil {\n\t\treturn false\n\t}\n\treturn user.User.MayUsePrioritySupport()\n}\n\n// MayUse returns whether the user may currently use the feature identified by\n// the given feature ID.\n// Leave feature ID empty to check without feature.\nfunc (user *UserRecord) MayUse(featureID account.FeatureID) bool {\n\t// Shadow this function in order to allow calls on a nil user.\n\tif user == nil || user.User == nil {\n\t\treturn false\n\t}\n\treturn user.User.MayUse(featureID)\n}\n\n// AuthTokenRecord holds an authentication token.\ntype AuthTokenRecord struct {\n\trecord.Base\n\tsync.Mutex\n\n\tToken *account.AuthToken\n}\n\n// GetToken returns the token from the record.\nfunc (authToken *AuthTokenRecord) GetToken() *account.AuthToken {\n\tauthToken.Lock()\n\tdefer authToken.Unlock()\n\n\treturn authToken.Token\n}\n\n// SaveNewAuthToken saves a new auth token to the database.\nfunc SaveNewAuthToken(deviceID string, resp *http.Response) error {\n\ttoken, ok := account.GetNextTokenFromResponse(resp)\n\tif !ok {\n\t\treturn account.ErrMissingToken\n\t}\n\n\tnewAuthToken := &AuthTokenRecord{\n\t\tToken: &account.AuthToken{\n\t\t\tDevice: deviceID,\n\t\t\tToken:  token,\n\t\t},\n\t}\n\treturn newAuthToken.Save()\n}\n\n// Update updates an existing auth token with the next token from a response.\nfunc (authToken *AuthTokenRecord) Update(resp *http.Response) error {\n\ttoken, ok := account.GetNextTokenFromResponse(resp)\n\tif !ok {\n\t\treturn account.ErrMissingToken\n\t}\n\n\t// Update token with new account.AuthToken.\n\tfunc() {\n\t\tauthToken.Lock()\n\t\tdefer authToken.Unlock()\n\n\t\tauthToken.Token = &account.AuthToken{\n\t\t\tDevice: authToken.Token.Device,\n\t\t\tToken:  token,\n\t\t}\n\t}()\n\n\treturn authToken.Save()\n}\n\nvar (\n\taccountCacheLock sync.Mutex\n\n\tcachedUser    *UserRecord\n\tcachedUserSet bool\n\n\tcachedAuthToken *AuthTokenRecord\n)\n\nfunc clearUserCaches() {\n\taccountCacheLock.Lock()\n\tdefer accountCacheLock.Unlock()\n\n\tcachedUser = nil\n\tcachedUserSet = false\n\tcachedAuthToken = nil\n}\n\n// GetUser returns the current user account.\n// Returns nil when no user is logged in.\nfunc GetUser() (*UserRecord, error) {\n\t// Check cache.\n\taccountCacheLock.Lock()\n\tdefer accountCacheLock.Unlock()\n\tif cachedUserSet {\n\t\tif cachedUser == nil {\n\t\t\treturn nil, ErrNotLoggedIn\n\t\t}\n\t\treturn cachedUser, nil\n\t}\n\n\t// Load from disk.\n\tr, err := db.Get(userRecordKey)\n\tif err != nil {\n\t\tif errors.Is(err, database.ErrNotFound) {\n\t\t\tcachedUser = nil\n\t\t\tcachedUserSet = true\n\t\t\treturn nil, ErrNotLoggedIn\n\t\t}\n\t\treturn nil, err\n\t}\n\n\t// Unwrap record.\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewUser := &UserRecord{}\n\t\terr = record.Unwrap(r, newUser)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcachedUser = newUser\n\t\tcachedUserSet = true\n\t\treturn cachedUser, nil\n\t}\n\n\t// Or adjust type.\n\tnewUser, ok := r.(*UserRecord)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *UserRecord, but %T\", r)\n\t}\n\tcachedUser = newUser\n\tcachedUserSet = true\n\treturn cachedUser, nil\n}\n\n// Save saves the User.\nfunc (user *UserRecord) Save() error {\n\t// Update cache.\n\taccountCacheLock.Lock()\n\tdefer accountCacheLock.Unlock()\n\tcachedUser = user\n\tcachedUserSet = true\n\n\t// Update view if unset.\n\tif user.View == nil {\n\t\tuser.UpdateView(0)\n\t}\n\n\t// Set, check and update metadata.\n\tif !user.KeyIsSet() {\n\t\tuser.SetKey(userRecordKey)\n\t}\n\tuser.UpdateMeta()\n\n\treturn db.Put(user)\n}\n\n// GetAuthToken returns the current auth token.\nfunc GetAuthToken() (*AuthTokenRecord, error) {\n\t// Check cache.\n\taccountCacheLock.Lock()\n\tdefer accountCacheLock.Unlock()\n\tif cachedAuthToken != nil {\n\t\treturn cachedAuthToken, nil\n\t}\n\n\t// Load from disk.\n\tr, err := db.Get(authTokenRecordKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Unwrap record.\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewAuthRecord := &AuthTokenRecord{}\n\t\terr = record.Unwrap(r, newAuthRecord)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcachedAuthToken = newAuthRecord\n\t\treturn newAuthRecord, nil\n\t}\n\n\t// Or adjust type.\n\tnewAuthRecord, ok := r.(*AuthTokenRecord)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *AuthTokenRecord, but %T\", r)\n\t}\n\tcachedAuthToken = newAuthRecord\n\treturn newAuthRecord, nil\n}\n\n// Save saves the auth token to the database.\nfunc (authToken *AuthTokenRecord) Save() error {\n\t// Update cache.\n\taccountCacheLock.Lock()\n\tdefer accountCacheLock.Unlock()\n\tcachedAuthToken = authToken\n\n\t// Set, check and update metadata.\n\tif !authToken.KeyIsSet() {\n\t\tauthToken.SetKey(authTokenRecordKey)\n\t}\n\tauthToken.UpdateMeta()\n\tauthToken.Meta().MakeSecret()\n\tauthToken.Meta().MakeCrownJewel()\n\n\treturn db.Put(authToken)\n}\n"
  },
  {
    "path": "spn/access/features.go",
    "content": "package access\n\nimport \"github.com/safing/portmaster/spn/access/account\"\n\n// Feature describes a notable part of the program.\ntype Feature struct {\n\tName              string\n\tID                string\n\tRequiredFeatureID account.FeatureID\n\tConfigKey         string\n\tConfigScope       string\n\tInPackage         *Package\n\tComment           string\n\tBeta              bool\n\tComingSoon        bool\n\ticon              string\n}\n\n// Package combines a set of features.\ntype Package struct {\n\tName     string\n\tHexColor string\n\tInfoURL  string\n}\n\nvar (\n\tinfoURL     = \"https://safing.io/pricing/\"\n\tpackageFree = &Package{\n\t\tName:     \"Free\",\n\t\tHexColor: \"#ffffff\",\n\t\tInfoURL:  infoURL,\n\t}\n\tpackagePlus = &Package{\n\t\tName:     \"Plus\",\n\t\tHexColor: \"#2fcfae\",\n\t\tInfoURL:  infoURL,\n\t}\n\tpackagePro = &Package{\n\t\tName:     \"Pro\",\n\t\tHexColor: \"#029ad0\",\n\t\tInfoURL:  infoURL,\n\t}\n\tfeatures = []Feature{\n\t\t{\n\t\t\tName:        \"Secure DNS\",\n\t\t\tID:          \"dns\",\n\t\t\tConfigScope: \"dns/\",\n\t\t\tInPackage:   packageFree,\n\t\t\ticon: `\n\t\t\t    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n    \t\t\t  <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n    \t\t\t    d=\"M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418\" />\n    \t\t\t</svg>\n\t\t\t`,\n\t\t},\n\t\t{\n\t\t\tName:        \"Privacy Filter\",\n\t\t\tID:          \"filter\",\n\t\t\tConfigScope: \"filter/\",\n\t\t\tInPackage:   packageFree,\n\t\t\ticon: `\n<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88\" />\n</svg>\n\t\t\t`,\n\t\t},\n\t\t{\n\t\t\tName:              \"Network History\",\n\t\t\tID:                string(account.FeatureHistory),\n\t\t\tRequiredFeatureID: account.FeatureHistory,\n\t\t\tConfigKey:         \"history/enable\",\n\t\t\tConfigScope:       \"history/\",\n\t\t\tInPackage:         packagePlus,\n\t\t\ticon: `\n<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n    d=\"M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25\" />\n</svg>\t\n\t\t\t`,\n\t\t},\n\t\t{\n\t\t\tName:              \"Bandwidth Visibility\",\n\t\t\tID:                string(account.FeatureBWVis),\n\t\t\tRequiredFeatureID: account.FeatureBWVis,\n\t\t\tInPackage:         packagePlus,\n\t\t\tBeta:              true,\n\t\t\ticon: `\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z\" />\n    </svg>\n\t\t\t`,\n\t\t},\n\t\t{\n\t\t\tName:              \"Safing Support\",\n\t\t\tID:                string(account.FeatureSafingSupport),\n\t\t\tRequiredFeatureID: account.FeatureSafingSupport,\n\t\t\tInPackage:         packagePlus,\n\t\t\ticon: `\n    <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\">\n      <path stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        d=\"M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z\" />\n    </svg>\t\n\t\t\t`,\n\t\t},\n\t\t{\n\t\t\tName:              \"Safing Privacy Network\",\n\t\t\tID:                string(account.FeatureSPN),\n\t\t\tRequiredFeatureID: account.FeatureSPN,\n\t\t\tConfigKey:         \"spn/enable\",\n\t\t\tConfigScope:       \"spn/\",\n\t\t\tInPackage:         packagePro,\n\t\t\ticon: `\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" class=\"text-green-300\">\n      <g fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\">\n        <path\n          d=\"M6.488 15.581c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0M13.415 3.586c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.049-.781 2.83 0M20.343 15.58c.782.781.782 2.048 0 2.829-.782.781-2.049.781-2.83 0-.782-.781-.782-2.048 0-2.829.781-.781 2.048-.781 2.83 0\">\n        </path>\n        <path\n          d=\"M17.721 18.581C16.269 20.071 14.246 21 12 21c-1.146 0-2.231-.246-3.215-.68M4.293 15.152c-.56-1.999-.352-4.21.769-6.151.574-.995 1.334-1.814 2.205-2.449M13.975 5.254c2.017.512 3.834 1.799 4.957 3.743.569.985.899 2.041 1.018 3.103\">\n        </path>\n      </g>\n    </svg>\n\t\t\t`,\n\t\t},\n\t}\n)\n"
  },
  {
    "path": "spn/access/module.go",
    "content": "package access\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/access/account\"\n\t\"github.com/safing/portmaster/spn/access/token\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype Access struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tupdateAccountWorkerMgr *mgr.WorkerMgr\n\n\tEventAccountUpdate *mgr.EventMgr[struct{}]\n}\n\nfunc (a *Access) Manager() *mgr.Manager {\n\treturn a.mgr\n}\n\nfunc (a *Access) Start() error {\n\treturn start()\n}\n\nfunc (a *Access) Stop() error {\n\treturn stop()\n}\n\nvar (\n\tmodule     *Access\n\tshimLoaded atomic.Bool\n\n\ttokenIssuerIsFailing     = abool.New()\n\ttokenIssuerRetryDuration = 10 * time.Minute\n\n\t// AccountUpdateEvent is fired when the account has changed in any way.\n\tAccountUpdateEvent = \"account update\"\n)\n\n// Errors.\nvar (\n\tErrDeviceIsLocked       = errors.New(\"device is locked\")\n\tErrDeviceLimitReached   = errors.New(\"device limit reached\")\n\tErrFallbackNotAvailable = errors.New(\"fallback tokens not available, token issuer is online\")\n\tErrInvalidCredentials   = errors.New(\"invalid credentials\")\n\tErrMayNotUseSPN         = errors.New(\"may not use SPN\")\n\tErrNotLoggedIn          = errors.New(\"not logged in\")\n)\n\nfunc prep() error {\n\t// Register API handlers.\n\tif conf.Integrated() {\n\t\terr := registerAPIEndpoints()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc start() error {\n\t// Initialize zones.\n\tif err := InitializeZones(); err != nil {\n\t\treturn err\n\t}\n\n\tif conf.Integrated() {\n\t\t// Add config listener to enable/disable SPN.\n\t\tmodule.instance.Config().EventConfigChange.AddCallback(\"spn enable check\", func(wc *mgr.WorkerCtx, s struct{}) (bool, error) {\n\t\t\t// Do not do anything when we are shutting down.\n\t\t\tif module.instance.IsShuttingDown() {\n\t\t\t\treturn true, nil\n\t\t\t}\n\n\t\t\tenabled := config.GetAsBool(\"spn/enable\", false)\n\t\t\tif enabled() {\n\t\t\t\tlog.Info(\"spn: starting SPN\")\n\t\t\t\tmodule.mgr.Go(\"ensure SPN is started\", module.instance.SPNGroup().EnsureStartedWorker)\n\t\t\t} else {\n\t\t\t\tlog.Info(\"spn: stopping SPN\")\n\t\t\t\tmodule.mgr.Go(\"ensure SPN is stopped\", module.instance.SPNGroup().EnsureStoppedWorker)\n\t\t\t}\n\t\t\treturn false, nil\n\t\t})\n\n\t\t// Load tokens from database.\n\t\tloadTokens()\n\n\t\t// Check if we need to enable SPN now.\n\t\tenabled := config.GetAsBool(\"spn/enable\", false)\n\t\tif enabled() {\n\t\t\tmodule.mgr.Go(\"ensure SPN is started\", module.instance.SPNGroup().EnsureStartedWorker)\n\t\t}\n\n\t\t// Register new task.\n\t\tmodule.updateAccountWorkerMgr.Delay(1 * time.Minute)\n\t}\n\n\treturn nil\n}\n\nfunc stop() error {\n\tif conf.Integrated() {\n\t\t// Make sure SPN is stopped before we proceed.\n\t\terr := module.mgr.Do(\"ensure SPN is shut down\", module.instance.SPNGroup().EnsureStoppedWorker)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"access: stop SPN: %s\", err)\n\t\t}\n\n\t\t// Store tokens to database.\n\t\tstoreTokens()\n\t}\n\n\t// Reset zones.\n\ttoken.ResetRegistry()\n\n\treturn nil\n}\n\n// UpdateAccount updates the user account and fetches new tokens, if needed.\nfunc UpdateAccount(_ *mgr.WorkerCtx) error {\n\t// Schedule next call - this will change if other conditions are met bellow.\n\tmodule.updateAccountWorkerMgr.Delay(24 * time.Hour)\n\n\t// Retry sooner if the token issuer is failing.\n\tdefer func() {\n\t\tif tokenIssuerIsFailing.IsSet() {\n\t\t\tmodule.updateAccountWorkerMgr.Delay(tokenIssuerRetryDuration)\n\t\t}\n\t}()\n\n\t// Get current user.\n\tu, err := GetUser()\n\tif err == nil {\n\t\t// Do not update if we just updated.\n\t\tif time.Since(time.Unix(u.Meta().Modified, 0)) < 2*time.Minute {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tu, _, err = UpdateUser()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to update user profile: %w\", err)\n\t}\n\n\terr = UpdateTokens()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get tokens: %w\", err)\n\t}\n\n\t// Schedule next check.\n\tswitch {\n\tcase u == nil: // No user.\n\tcase u.Subscription == nil: // No subscription.\n\tcase u.Subscription.EndsAt == nil: // Subscription not active\n\n\tcase time.Until(*u.Subscription.EndsAt) < 24*time.Hour &&\n\t\ttime.Since(*u.Subscription.EndsAt) < 24*time.Hour:\n\t\t// Update account every hour for 24h hours before and after the subscription ends.\n\t\tmodule.updateAccountWorkerMgr.Delay(1 * time.Hour)\n\n\tcase u.Subscription.NextBillingDate == nil: // No auto-subscription.\n\n\tcase time.Until(*u.Subscription.NextBillingDate) < 24*time.Hour &&\n\t\ttime.Since(*u.Subscription.NextBillingDate) < 24*time.Hour:\n\t\t// Update account every hour 24h hours before and after the next billing date.\n\t\tmodule.updateAccountWorkerMgr.Delay(1 * time.Hour)\n\t}\n\n\treturn nil\n}\n\nfunc enableSPN() {\n\terr := config.SetConfigOption(\"spn/enable\", true)\n\tif err != nil {\n\t\tlog.Warningf(\"spn/access: failed to enable the SPN during login: %s\", err)\n\t}\n}\n\nfunc disableSPN() {\n\terr := config.SetConfigOption(\"spn/enable\", false)\n\tif err != nil {\n\t\tlog.Warningf(\"spn/access: failed to disable the SPN during logout: %s\", err)\n\t}\n}\n\n// TokenIssuerIsFailing returns whether token issuing is currently failing.\nfunc TokenIssuerIsFailing() bool {\n\treturn tokenIssuerIsFailing.IsSet()\n}\n\nfunc tokenIssuerFailed() {\n\tif !tokenIssuerIsFailing.SetToIf(false, true) {\n\t\treturn\n\t}\n\n\tmodule.updateAccountWorkerMgr.Delay(tokenIssuerRetryDuration)\n}\n\n// IsLoggedIn returns whether a User is currently logged in.\nfunc (user *UserRecord) IsLoggedIn() bool {\n\tuser.Lock()\n\tdefer user.Unlock()\n\n\tswitch user.State {\n\tcase account.UserStateNone, account.UserStateLoggedOut:\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\n// MayUseTheSPN returns whether the currently logged in User may use the SPN.\nfunc (user *UserRecord) MayUseTheSPN() bool {\n\tuser.Lock()\n\tdefer user.Unlock()\n\n\treturn user.User.MayUseSPN()\n}\n\n// New returns a new Access module.\nfunc New(instance instance) (*Access, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"Access\")\n\tmodule = &Access{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tEventAccountUpdate:     mgr.NewEventMgr[struct{}](AccountUpdateEvent, m),\n\t\tupdateAccountWorkerMgr: m.NewWorkerMgr(\"update account\", UpdateAccount, nil),\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tConfig() *config.Config\n\tSPNGroup() *mgr.ExtendedGroup\n\tIsShuttingDown() bool\n}\n"
  },
  {
    "path": "spn/access/module_test.go",
    "content": "package access\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database\"\n\t_ \"github.com/safing/portmaster/base/database/storage/hashmap\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype testInstance struct {\n\tconfig *config.Config\n}\n\nfunc (stub *testInstance) Config() *config.Config             { return stub.config }\nfunc (stub *testInstance) SPNGroup() *mgr.ExtendedGroup       { return nil }\nfunc (stub *testInstance) Stopping() bool                     { return false }\nfunc (stub *testInstance) IsShuttingDown() bool               { return false }\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\nfunc (stub *testInstance) DataDir() string                    { return _dataDir }\n\nvar _dataDir string\n\nfunc TestMain(m *testing.M) {\n\texitCode := 1\n\tdefer func() {\n\t\tif exitCode != 0 {\n\t\t\tos.Exit(exitCode)\n\t\t}\n\t}()\n\n\tvar err error\n\t// Create a temporary directory for the data\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\tfmt.Printf(\"failed to create temporary data directory: %s\", err)\n\t\treturn // Exit with error\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Initialize the database module\n\terr = database.Initialize(_dataDir)\n\tif err != nil {\n\t\tfmt.Printf(\"failed to initialize database module: %s\", err)\n\t\treturn // Exit with error\n\t}\n\t_, err = database.Register(&database.Database{\n\t\tName:        \"core\",\n\t\tDescription: \"Holds core data, such as settings and profiles\",\n\t\tStorageType: \"hashmap\",\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"failed to register core database: %s\", err)\n\t\treturn // Exit with error\n\t}\n\n\t// Initialize the instance\n\tinstance := &testInstance{}\n\n\tinstance.config, err = config.New(instance)\n\tif err != nil {\n\t\tfmt.Printf(\"failed to create config module: %s\", err)\n\t\treturn // Exit with error\n\t}\n\tmodule, err = New(instance)\n\tif err != nil {\n\t\tfmt.Printf(\"failed to create access module: %s\", err)\n\t\treturn // Exit with error\n\t}\n\n\terr = instance.config.Start()\n\tif err != nil {\n\t\tfmt.Printf(\"failed to start config module: %s\", err)\n\t\treturn // Exit with error\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\tfmt.Printf(\"failed to start access module: %s\", err)\n\t\treturn // Exit with error\n\t}\n\n\tconf.EnableClient(true)\n\tm.Run()\n\n\texitCode = 0 // success\n}\n"
  },
  {
    "path": "spn/access/notify.go",
    "content": "package access\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n)\n\nconst (\n\tday  = 24 * time.Hour\n\tweek = 7 * day\n\n\tendOfPackageNearNotifID = \"access:end-of-package-near\"\n)\n\nfunc notifyOfPackageEnd(u *UserRecord) {\n\t// TODO: Check if subscription auto-renews.\n\n\t// Skip if there is not active subscription or if it has ended already.\n\tswitch {\n\tcase u.Subscription == nil, // No subscription.\n\t\tu.Subscription.EndsAt == nil,             // Subscription not active.\n\t\tu.Subscription.NextBillingDate != nil,    // Subscription is auto-renewing.\n\t\ttime.Now().After(*u.Subscription.EndsAt): // Subscription has ended.\n\t\treturn\n\t}\n\n\t// Calculate durations.\n\tsinceLastNotified := 52 * week // Never.\n\tif u.LastNotifiedOfEnd != nil {\n\t\tsinceLastNotified = time.Since(*u.LastNotifiedOfEnd)\n\t}\n\tuntilEnd := time.Until(*u.Subscription.EndsAt)\n\n\t// Notify every two days in the week before end.\n\tnotifType := notifications.Info\n\tswitch {\n\tcase untilEnd < week && sinceLastNotified > 2*day:\n\t\t// Notify 7, 5, 3 and 1 days before end.\n\t\tif untilEnd < 4*day {\n\t\t\tnotifType = notifications.Warning\n\t\t}\n\t\tfallthrough\n\n\tcase u.CurrentPlan != nil && u.CurrentPlan.Months >= 6 &&\n\t\tuntilEnd < 4*week && sinceLastNotified > week:\n\t\t// Notify 4, 3 and 2 weeks before end - on long running packages.\n\n\t\t// Get names and messages.\n\t\tpackageNameTitle := \"Portmaster Package\"\n\t\tif u.CurrentPlan != nil {\n\t\t\tpackageNameTitle = u.CurrentPlan.Name\n\t\t}\n\t\tpackageNameBody := packageNameTitle\n\t\tif !strings.HasSuffix(packageNameBody, \" Package\") {\n\t\t\tpackageNameBody += \" Package\"\n\t\t}\n\n\t\tvar endsText string\n\t\tdaysUntilEnd := untilEnd / day\n\t\tswitch daysUntilEnd { //nolint:exhaustive\n\t\tcase 0:\n\t\t\tendsText = \"today\"\n\t\tcase 1:\n\t\t\tendsText = \"tomorrow\"\n\t\tdefault:\n\t\t\tendsText = fmt.Sprintf(\"in %d days\", daysUntilEnd)\n\t\t}\n\n\t\t// Send notification.\n\t\tnotifications.Notify(&notifications.Notification{\n\t\t\tEventID: endOfPackageNearNotifID,\n\t\t\tType:    notifType,\n\t\t\tTitle:   fmt.Sprintf(\"%s About to Expire\", packageNameTitle),\n\t\t\tMessage: fmt.Sprintf(\n\t\t\t\t\"Your current %s ends %s. Extend it to keep your full privacy protections.\",\n\t\t\t\tpackageNameBody,\n\t\t\t\tendsText,\n\t\t\t),\n\t\t\tShowOnSystem: notifType == notifications.Warning,\n\t\t\tAvailableActions: []*notifications.Action{\n\t\t\t\t{\n\t\t\t\t\tText:    \"Open Account Page\",\n\t\t\t\t\tType:    notifications.ActionTypeOpenURL,\n\t\t\t\t\tPayload: \"https://account.safing.io\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tID:   \"ack\",\n\t\t\t\t\tText: \"Got it!\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\n\t\t// Save that we sent a notification.\n\t\tnow := time.Now()\n\t\tu.LastNotifiedOfEnd = &now\n\t\terr := u.Save()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/access: failed to save user after sending subscription ending soon notification: %s\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/access/op_auth.go",
    "content": "package access\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/access/token\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n)\n\n// OpTypeAccessCodeAuth is the type ID of the auth operation.\nconst OpTypeAccessCodeAuth = \"auth\"\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:  OpTypeAccessCodeAuth,\n\t\tStart: checkAccessCode,\n\t})\n}\n\n// AuthorizeOp is used to authorize a session.\ntype AuthorizeOp struct {\n\tterminal.OneOffOperationBase\n}\n\n// Type returns the type ID.\nfunc (op *AuthorizeOp) Type() string {\n\treturn OpTypeAccessCodeAuth\n}\n\n// AuthorizeToTerminal starts an authorization operation.\nfunc AuthorizeToTerminal(t terminal.Terminal) (*AuthorizeOp, *terminal.Error) {\n\top := &AuthorizeOp{}\n\top.Init()\n\n\tnewToken, err := GetToken(ExpandAndConnectZones)\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to get access token: %w\", err)\n\t}\n\n\ttErr := t.StartOperation(op, container.New(newToken.Raw()), 10*time.Second)\n\tif tErr != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to init auth op: %w\", tErr)\n\t}\n\n\treturn op, nil\n}\n\nfunc checkAccessCode(t terminal.Terminal, opID uint32, initData *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Parse provided access token.\n\treceivedToken, err := token.ParseRawToken(initData.CompileData())\n\tif err != nil {\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to parse access token: %w\", err)\n\t}\n\n\t// Check if token is valid.\n\tgranted, err := VerifyToken(receivedToken)\n\tif err != nil {\n\t\treturn nil, terminal.ErrPermissionDenied.With(\"invalid access token: %w\", err)\n\t}\n\n\t// Get the authorizing terminal for applying the granted permission.\n\tauthTerm, ok := t.(terminal.AuthorizingTerminal)\n\tif !ok {\n\t\treturn nil, terminal.ErrIncorrectUsage.With(\"terminal does not handle authorization\")\n\t}\n\n\t// Grant permissions.\n\tauthTerm.GrantPermission(granted)\n\tlog.Debugf(\"spn/access: granted %s permissions via %s zone\", t.FmtID(), receivedToken.Zone)\n\n\t// End successfully.\n\treturn nil, terminal.ErrExplicitAck\n}\n"
  },
  {
    "path": "spn/access/storage.go",
    "content": "package access\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/access/token\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nfunc loadTokens() {\n\tfor _, zone := range persistentZones {\n\t\t// Get handler of zone.\n\t\thandler, ok := token.GetHandler(zone)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/access: could not find zone %s for loading tokens\", zone)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get data from database.\n\t\tr, err := db.Get(fmt.Sprintf(tokenStorageKeyTemplate, zone))\n\t\tif err != nil {\n\t\t\tif errors.Is(err, database.ErrNotFound) {\n\t\t\t\tlog.Debugf(\"spn/access: no %s tokens to load\", zone)\n\t\t\t} else {\n\t\t\t\tlog.Warningf(\"spn/access: failed to load %s tokens: %s\", zone, err)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get wrapper.\n\t\twrapper, ok := r.(*record.Wrapper)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/access: failed to parse %s tokens: expected wrapper, got %T\", zone, r)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Load into handler.\n\t\terr = handler.Load(wrapper.Data)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/access: failed to load %s tokens: %s\", zone, err)\n\t\t}\n\t\tlog.Infof(\"spn/access: loaded %d %s tokens\", handler.Amount(), zone)\n\t}\n}\n\nfunc storeTokens() {\n\tfor _, zone := range persistentZones {\n\t\t// Get handler of zone.\n\t\thandler, ok := token.GetHandler(zone)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/access: could not find zone %s for storing tokens\", zone)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Generate storage key.\n\t\tstorageKey := fmt.Sprintf(tokenStorageKeyTemplate, zone)\n\n\t\t// Check if there is data to save.\n\t\tamount := handler.Amount()\n\t\tif amount == 0 {\n\t\t\t// Remove possible old entry from database.\n\t\t\terr := db.Delete(storageKey)\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"spn/access: failed to delete possible old %s tokens from storage: %s\", zone, err)\n\t\t\t}\n\t\t\tlog.Debugf(\"spn/access: no %s tokens to store\", zone)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Export data.\n\t\tdata, err := handler.Save()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/access: failed to export %s tokens for storing: %s\", zone, err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Wrap data into raw record.\n\t\tr, err := record.NewWrapper(storageKey, nil, dsd.RAW, data)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/access: failed to prepare %s token export for storing: %s\", zone, err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Let tokens expire after one month.\n\t\t// This will regularly happen when we switch zones.\n\t\tr.UpdateMeta()\n\t\tr.Meta().MakeSecret()\n\t\tr.Meta().MakeCrownJewel()\n\t\tr.Meta().SetRelativateExpiry(30 * 86400)\n\n\t\t// Save to database.\n\t\terr = db.Put(r)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/access: failed to store %s tokens: %s\", zone, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Infof(\"spn/access: stored %d %s tokens\", amount, zone)\n\t}\n}\n\nfunc clearTokens() {\n\tfor _, zone := range persistentZones {\n\t\t// Get handler of zone.\n\t\thandler, ok := token.GetHandler(zone)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/access: could not find zone %s for clearing tokens\", zone)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Clear tokens.\n\t\thandler.Clear()\n\t}\n\n\t// Purge database storage prefix.\n\tctx, cancel := context.WithTimeout(module.mgr.Ctx(), 10*time.Second)\n\tdefer cancel()\n\tn, err := db.Purge(ctx, query.New(fmt.Sprintf(tokenStorageKeyTemplate, \"\")))\n\tif err != nil {\n\t\tlog.Warningf(\"spn/access: failed to clear token storages: %s\", err)\n\t\treturn\n\t}\n\tlog.Infof(\"spn/access: cleared %d token storages\", n)\n}\n"
  },
  {
    "path": "spn/access/token/errors.go",
    "content": "package token\n\nimport \"errors\"\n\n// Errors.\nvar (\n\tErrEmpty          = errors.New(\"token storage is empty\")\n\tErrNoZone         = errors.New(\"no zone specified\")\n\tErrTokenInvalid   = errors.New(\"token is invalid\")\n\tErrTokenMalformed = errors.New(\"token malformed\")\n\tErrTokenUsed      = errors.New(\"token already used\")\n\tErrZoneMismatch   = errors.New(\"zone mismatch\")\n\tErrZoneTaken      = errors.New(\"zone taken\")\n\tErrZoneUnknown    = errors.New(\"zone unknown\")\n)\n"
  },
  {
    "path": "spn/access/token/module_test.go",
    "content": "package token\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/rng\"\n)\n\ntype testInstance struct{}\n\nfunc TestMain(m *testing.M) {\n\trng, err := rng.New(testInstance{})\n\tif err != nil {\n\t\tfmt.Printf(\"failed to create RNG module: %s\", err)\n\t\tos.Exit(1)\n\t}\n\n\terr = rng.Start()\n\tif err != nil {\n\t\tfmt.Printf(\"failed to start RNG module: %s\", err)\n\t\tos.Exit(1)\n\t}\n\tm.Run()\n}\n"
  },
  {
    "path": "spn/access/token/pblind.go",
    "content": "package token\n\nimport (\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/big\"\n\tmrand \"math/rand\"\n\t\"sync\"\n\n\t\"github.com/mr-tron/base58\"\n\t\"github.com/rot256/pblind\"\n\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nconst pblindSecretSize = 32\n\n// PBlindToken is token based on the pblind library.\ntype PBlindToken struct {\n\tSerial    int               `json:\"N,omitempty\"`\n\tToken     []byte            `json:\"T,omitempty\"`\n\tSignature *pblind.Signature `json:\"S,omitempty\"`\n}\n\n// Pack packs the token.\nfunc (pbt *PBlindToken) Pack() ([]byte, error) {\n\treturn dsd.Dump(pbt, dsd.CBOR)\n}\n\n// UnpackPBlindToken unpacks the token.\nfunc UnpackPBlindToken(token []byte) (*PBlindToken, error) {\n\tt := &PBlindToken{}\n\n\t_, err := dsd.Load(token, t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn t, nil\n}\n\n// PBlindHandler is a handler for the pblind tokens.\ntype PBlindHandler struct {\n\tsync.Mutex\n\topts *PBlindOptions\n\n\tpublicKey  *pblind.PublicKey\n\tprivateKey *pblind.SecretKey\n\n\tstorageLock sync.Mutex\n\tStorage     []*PBlindToken\n\n\t// Client request state.\n\trequestStateLock sync.Mutex\n\trequestState     []RequestState\n}\n\n// PBlindOptions are options for the PBlindHandler.\ntype PBlindOptions struct {\n\tZone                  string\n\tCurveName             string\n\tCurve                 elliptic.Curve\n\tPublicKey             string\n\tPrivateKey            string\n\tBatchSize             int\n\tUseSerials            bool\n\tRandomizeOrder        bool\n\tFallback              bool\n\tSignalShouldRequest   func(Handler)\n\tDoubleSpendProtection func([]byte) error\n}\n\n// PBlindSignerState is a signer state.\ntype PBlindSignerState struct {\n\tsigners []*pblind.StateSigner\n}\n\n// PBlindSetupResponse is a setup response.\ntype PBlindSetupResponse struct {\n\tMsgs []*pblind.Message1\n}\n\n// PBlindTokenRequest is a token request.\ntype PBlindTokenRequest struct {\n\tMsgs []*pblind.Message2\n}\n\n// IssuedPBlindTokens are issued pblind tokens.\ntype IssuedPBlindTokens struct {\n\tMsgs []*pblind.Message3\n}\n\n// RequestState is a request state.\ntype RequestState struct {\n\tToken []byte\n\tState *pblind.StateRequester\n}\n\n// NewPBlindHandler creates a new pblind handler.\nfunc NewPBlindHandler(opts PBlindOptions) (*PBlindHandler, error) {\n\tpbh := &PBlindHandler{\n\t\topts: &opts,\n\t}\n\n\t// Check curve, get from name.\n\tif opts.Curve == nil {\n\t\tswitch opts.CurveName {\n\t\tcase \"P-256\":\n\t\t\topts.Curve = elliptic.P256()\n\t\tcase \"P-384\":\n\t\t\topts.Curve = elliptic.P384()\n\t\tcase \"P-521\":\n\t\t\topts.Curve = elliptic.P521()\n\t\tdefault:\n\t\t\treturn nil, errors.New(\"no curve supplied\")\n\t\t}\n\t} else if opts.CurveName != \"\" {\n\t\treturn nil, errors.New(\"both curve and curve name supplied\")\n\t}\n\n\t// Load keys.\n\tswitch {\n\tcase pbh.opts.PrivateKey != \"\":\n\t\tkeyData, err := base58.Decode(pbh.opts.PrivateKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode private key: %w\", err)\n\t\t}\n\t\tpivateKey := pblind.SecretKeyFromBytes(pbh.opts.Curve, keyData)\n\t\tpbh.privateKey = &pivateKey\n\t\tpublicKey := pbh.privateKey.GetPublicKey()\n\t\tpbh.publicKey = &publicKey\n\n\t\t// Check public key if also provided.\n\t\tif pbh.opts.PublicKey != \"\" {\n\t\t\tif pbh.opts.PublicKey != base58.Encode(pbh.publicKey.Bytes()) {\n\t\t\t\treturn nil, errors.New(\"private and public mismatch\")\n\t\t\t}\n\t\t}\n\n\tcase pbh.opts.PublicKey != \"\":\n\t\tkeyData, err := base58.Decode(pbh.opts.PublicKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode public key: %w\", err)\n\t\t}\n\t\tpublicKey, err := pblind.PublicKeyFromBytes(pbh.opts.Curve, keyData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode public key: %w\", err)\n\t\t}\n\t\tpbh.publicKey = &publicKey\n\n\tdefault:\n\t\treturn nil, errors.New(\"no key supplied\")\n\t}\n\n\treturn pbh, nil\n}\n\nfunc (pbh *PBlindHandler) makeInfo(serial int) (*pblind.Info, error) {\n\t// Gather data for info.\n\tinfoData := container.New()\n\tinfoData.AppendAsBlock([]byte(pbh.opts.Zone))\n\tif pbh.opts.UseSerials {\n\t\tinfoData.AppendInt(serial)\n\t}\n\n\t// Compress to point.\n\tinfo, err := pblind.CompressInfo(pbh.opts.Curve, infoData.CompileData())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to compress info: %w\", err)\n\t}\n\n\treturn &info, nil\n}\n\n// Zone returns the zone name.\nfunc (pbh *PBlindHandler) Zone() string {\n\treturn pbh.opts.Zone\n}\n\n// ShouldRequest returns whether the new tokens should be requested.\nfunc (pbh *PBlindHandler) ShouldRequest() bool {\n\tpbh.storageLock.Lock()\n\tdefer pbh.storageLock.Unlock()\n\n\treturn pbh.shouldRequest()\n}\n\nfunc (pbh *PBlindHandler) shouldRequest() bool {\n\t// Return true if storage is at or below 10%.\n\treturn len(pbh.Storage) == 0 || pbh.opts.BatchSize/len(pbh.Storage) > 10\n}\n\n// Amount returns the current amount of tokens in this handler.\nfunc (pbh *PBlindHandler) Amount() int {\n\tpbh.storageLock.Lock()\n\tdefer pbh.storageLock.Unlock()\n\n\treturn len(pbh.Storage)\n}\n\n// IsFallback returns whether this handler should only be used as a fallback.\nfunc (pbh *PBlindHandler) IsFallback() bool {\n\treturn pbh.opts.Fallback\n}\n\n// CreateSetup sets up signers for a request.\nfunc (pbh *PBlindHandler) CreateSetup() (state *PBlindSignerState, setupResponse *PBlindSetupResponse, err error) {\n\tstate = &PBlindSignerState{\n\t\tsigners: make([]*pblind.StateSigner, pbh.opts.BatchSize),\n\t}\n\tsetupResponse = &PBlindSetupResponse{\n\t\tMsgs: make([]*pblind.Message1, pbh.opts.BatchSize),\n\t}\n\n\t// Go through the batch.\n\tfor i := range pbh.opts.BatchSize {\n\t\tinfo, err := pbh.makeInfo(i + 1)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to create info #%d: %w\", i, err)\n\t\t}\n\n\t\t// Create signer.\n\t\tsigner, err := pblind.CreateSigner(*pbh.privateKey, *info)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to create signer #%d: %w\", i, err)\n\t\t}\n\t\tstate.signers[i] = signer\n\n\t\t// Create request setup.\n\t\tsetupMsg, err := signer.CreateMessage1()\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to create setup msg #%d: %w\", i, err)\n\t\t}\n\t\tsetupResponse.Msgs[i] = &setupMsg\n\t}\n\n\treturn state, setupResponse, nil\n}\n\n// CreateTokenRequest creates a token request to be sent to the token server.\nfunc (pbh *PBlindHandler) CreateTokenRequest(requestSetup *PBlindSetupResponse) (request *PBlindTokenRequest, err error) {\n\t// Check request setup data.\n\tif len(requestSetup.Msgs) != pbh.opts.BatchSize {\n\t\treturn nil, fmt.Errorf(\"invalid request setup msg count of %d\", len(requestSetup.Msgs))\n\t}\n\n\t// Lock and reset the request state.\n\tpbh.requestStateLock.Lock()\n\tdefer pbh.requestStateLock.Unlock()\n\tpbh.requestState = make([]RequestState, pbh.opts.BatchSize)\n\trequest = &PBlindTokenRequest{\n\t\tMsgs: make([]*pblind.Message2, pbh.opts.BatchSize),\n\t}\n\n\t// Go through the batch.\n\tfor i := range pbh.opts.BatchSize {\n\t\t// Check if we have setup data.\n\t\tif requestSetup.Msgs[i] == nil {\n\t\t\treturn nil, fmt.Errorf(\"missing setup data #%d\", i)\n\t\t}\n\n\t\t// Generate secret token.\n\t\ttoken := make([]byte, pblindSecretSize)\n\t\tn, err := rand.Read(token) //nolint:gosec // False positive - check the imports.\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get random token #%d: %w\", i, err)\n\t\t}\n\t\tif n != pblindSecretSize {\n\t\t\treturn nil, fmt.Errorf(\"failed to get full random token #%d: only got %d bytes\", i, n)\n\t\t}\n\t\tpbh.requestState[i].Token = token\n\n\t\t// Create public metadata.\n\t\tinfo, err := pbh.makeInfo(i + 1)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to make token info #%d: %w\", i, err)\n\t\t}\n\n\t\t// Create request and request state.\n\t\trequester, err := pblind.CreateRequester(*pbh.publicKey, *info, token)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create request state #%d: %w\", i, err)\n\t\t}\n\t\tpbh.requestState[i].State = requester\n\n\t\terr = requester.ProcessMessage1(*requestSetup.Msgs[i])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to process setup message #%d: %w\", i, err)\n\t\t}\n\n\t\t// Create request message.\n\t\trequestMsg, err := requester.CreateMessage2()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create request message #%d: %w\", i, err)\n\t\t}\n\t\trequest.Msgs[i] = &requestMsg\n\t}\n\n\treturn request, nil\n}\n\n// IssueTokens sign the requested tokens.\nfunc (pbh *PBlindHandler) IssueTokens(state *PBlindSignerState, request *PBlindTokenRequest) (response *IssuedPBlindTokens, err error) {\n\t// Check request data.\n\tif len(request.Msgs) != pbh.opts.BatchSize {\n\t\treturn nil, fmt.Errorf(\"invalid request msg count of %d\", len(request.Msgs))\n\t}\n\tif len(state.signers) != pbh.opts.BatchSize {\n\t\treturn nil, fmt.Errorf(\"invalid request state count of %d\", len(request.Msgs))\n\t}\n\n\t// Create response.\n\tresponse = &IssuedPBlindTokens{\n\t\tMsgs: make([]*pblind.Message3, pbh.opts.BatchSize),\n\t}\n\n\t// Go through the batch.\n\tfor i := range pbh.opts.BatchSize {\n\t\t// Check if we have request data.\n\t\tif request.Msgs[i] == nil {\n\t\t\treturn nil, fmt.Errorf(\"missing request data #%d\", i)\n\t\t}\n\n\t\t// Process request msg.\n\t\terr = state.signers[i].ProcessMessage2(*request.Msgs[i])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to process request msg #%d: %w\", i, err)\n\t\t}\n\n\t\t// Issue token.\n\t\tresponseMsg, err := state.signers[i].CreateMessage3()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to issue token #%d: %w\", i, err)\n\t\t}\n\t\tresponse.Msgs[i] = &responseMsg\n\t}\n\n\treturn response, nil\n}\n\n// ProcessIssuedTokens processes the issued token from the server.\nfunc (pbh *PBlindHandler) ProcessIssuedTokens(issuedTokens *IssuedPBlindTokens) error {\n\t// Check data.\n\tif len(issuedTokens.Msgs) != pbh.opts.BatchSize {\n\t\treturn fmt.Errorf(\"invalid issued token count of %d\", len(issuedTokens.Msgs))\n\t}\n\n\t// Step 1: Process issued tokens.\n\n\t// Lock and reset the request state.\n\tpbh.requestStateLock.Lock()\n\tdefer pbh.requestStateLock.Unlock()\n\tdefer func() {\n\t\tpbh.requestState = make([]RequestState, pbh.opts.BatchSize)\n\t}()\n\tfinalizedTokens := make([]*PBlindToken, pbh.opts.BatchSize)\n\n\t// Go through the batch.\n\tfor i := range pbh.opts.BatchSize {\n\t\t// Finalize token.\n\t\terr := pbh.requestState[i].State.ProcessMessage3(*issuedTokens.Msgs[i])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create final signature #%d: %w\", i, err)\n\t\t}\n\n\t\t// Get and check final signature.\n\t\tsignature, err := pbh.requestState[i].State.Signature()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create final signature #%d: %w\", i, err)\n\t\t}\n\t\tinfo, err := pbh.makeInfo(i + 1)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to make token info #%d: %w\", i, err)\n\t\t}\n\t\tif !pbh.publicKey.Check(signature, *info, pbh.requestState[i].Token) {\n\t\t\treturn fmt.Errorf(\"invalid signature on #%d\", i)\n\t\t}\n\n\t\t// Save to temporary slice.\n\t\tnewToken := &PBlindToken{\n\t\t\tToken:     pbh.requestState[i].Token,\n\t\t\tSignature: &signature,\n\t\t}\n\t\tif pbh.opts.UseSerials {\n\t\t\tnewToken.Serial = i + 1\n\t\t}\n\t\tfinalizedTokens[i] = newToken\n\t}\n\n\t// Step 2: Randomize received tokens\n\n\tif pbh.opts.RandomizeOrder {\n\t\trInt, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get seed for shuffle: %w\", err)\n\t\t}\n\t\tmr := mrand.New(mrand.NewSource(rInt.Int64())) //nolint:gosec\n\t\tmr.Shuffle(len(finalizedTokens), func(i, j int) {\n\t\t\tfinalizedTokens[i], finalizedTokens[j] = finalizedTokens[j], finalizedTokens[i]\n\t\t})\n\t}\n\n\t// Step 3: Add tokens to storage.\n\n\t// Wait for all processing to be complete, as using tokens from a faulty\n\t// batch can be dangerous, as the server could be doing this purposely to\n\t// create conditions that may benefit an attacker.\n\n\tpbh.storageLock.Lock()\n\tdefer pbh.storageLock.Unlock()\n\n\t// Add finalized tokens to storage.\n\tpbh.Storage = append(pbh.Storage, finalizedTokens...)\n\n\treturn nil\n}\n\n// GetToken returns a token.\nfunc (pbh *PBlindHandler) GetToken() (token *Token, err error) {\n\tpbh.storageLock.Lock()\n\tdefer pbh.storageLock.Unlock()\n\n\t// Check if we have supply.\n\tif len(pbh.Storage) == 0 {\n\t\treturn nil, ErrEmpty\n\t}\n\n\t// Pack token.\n\tdata, err := pbh.Storage[0].Pack()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to pack token: %w\", err)\n\t}\n\n\t// Shift to next token.\n\tpbh.Storage = pbh.Storage[1:]\n\n\t// Check if we should signal that we should request tokens.\n\tif pbh.opts.SignalShouldRequest != nil && pbh.shouldRequest() {\n\t\tpbh.opts.SignalShouldRequest(pbh)\n\t}\n\n\treturn &Token{\n\t\tZone: pbh.opts.Zone,\n\t\tData: data,\n\t}, nil\n}\n\n// Verify verifies the given token.\nfunc (pbh *PBlindHandler) Verify(token *Token) error {\n\t// Check if zone matches.\n\tif token.Zone != pbh.opts.Zone {\n\t\treturn ErrZoneMismatch\n\t}\n\n\t// Unpack token.\n\tt, err := UnpackPBlindToken(token.Data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%w: %w\", ErrTokenMalformed, err)\n\t}\n\n\t// Check if serial is valid.\n\tswitch {\n\tcase pbh.opts.UseSerials && t.Serial > 0 && t.Serial <= pbh.opts.BatchSize:\n\t\t// Using serials in accepted range.\n\tcase !pbh.opts.UseSerials && t.Serial == 0:\n\t\t// Not using serials and serial is zero.\n\tdefault:\n\t\treturn fmt.Errorf(\"%w: invalid serial\", ErrTokenMalformed)\n\t}\n\n\t// Build info for checking signature.\n\tinfo, err := pbh.makeInfo(t.Serial)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%w: %w\", ErrTokenMalformed, err)\n\t}\n\n\t// Check signature.\n\tif !pbh.publicKey.Check(*t.Signature, *info, t.Token) {\n\t\treturn ErrTokenInvalid\n\t}\n\n\t// Check for double spending.\n\tif pbh.opts.DoubleSpendProtection != nil {\n\t\tif err := pbh.opts.DoubleSpendProtection(t.Token); err != nil {\n\t\t\treturn fmt.Errorf(\"%w: %w\", ErrTokenUsed, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// PBlindStorage is a storage for pblind tokens.\ntype PBlindStorage struct {\n\tStorage []*PBlindToken\n}\n\n// Save serializes and returns the current tokens.\nfunc (pbh *PBlindHandler) Save() ([]byte, error) {\n\tpbh.storageLock.Lock()\n\tdefer pbh.storageLock.Unlock()\n\n\tif len(pbh.Storage) == 0 {\n\t\treturn nil, ErrEmpty\n\t}\n\n\ts := &PBlindStorage{\n\t\tStorage: pbh.Storage,\n\t}\n\n\treturn dsd.Dump(s, dsd.CBOR)\n}\n\n// Load loads the given tokens into the handler.\nfunc (pbh *PBlindHandler) Load(data []byte) error {\n\tpbh.storageLock.Lock()\n\tdefer pbh.storageLock.Unlock()\n\n\ts := &PBlindStorage{}\n\t_, err := dsd.Load(data, s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Check signatures on load.\n\tfor _, t := range s.Storage {\n\t\t// Build info for checking signature.\n\t\tinfo, err := pbh.makeInfo(t.Serial)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Check signature.\n\t\tif !pbh.publicKey.Check(*t.Signature, *info, t.Token) {\n\t\t\treturn ErrTokenInvalid\n\t\t}\n\t}\n\n\tpbh.Storage = s.Storage\n\treturn nil\n}\n\n// Clear clears all the tokens in the handler.\nfunc (pbh *PBlindHandler) Clear() {\n\tpbh.storageLock.Lock()\n\tdefer pbh.storageLock.Unlock()\n\n\tpbh.Storage = nil\n}\n"
  },
  {
    "path": "spn/access/token/pblind_gen_test.go",
    "content": "package token\n\nimport (\n\t\"crypto/elliptic\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/mr-tron/base58\"\n\t\"github.com/rot256/pblind\"\n)\n\nfunc TestGeneratePBlindKeys(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, curve := range []elliptic.Curve{\n\t\telliptic.P256(),\n\t\telliptic.P384(),\n\t\telliptic.P521(),\n\t} {\n\t\tprivateKey, err := pblind.NewSecretKey(curve)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tpublicKey := privateKey.GetPublicKey()\n\n\t\tfmt.Printf(\n\t\t\t\"%s (%dbit) private key: %s\\n\",\n\t\t\tcurve.Params().Name,\n\t\t\tcurve.Params().BitSize,\n\t\t\tbase58.Encode(privateKey.Bytes()),\n\t\t)\n\t\tfmt.Printf(\n\t\t\t\"%s (%dbit) public key: %s\\n\",\n\t\t\tcurve.Params().Name,\n\t\t\tcurve.Params().BitSize,\n\t\t\tbase58.Encode(publicKey.Bytes()),\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "spn/access/token/pblind_test.go",
    "content": "package token\n\nimport (\n\t\"crypto/elliptic\"\n\t\"encoding/asn1\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/rot256/pblind\"\n)\n\nconst PBlindTestZone = \"test-pblind\"\n\nfunc init() {\n\t// Combined testing config.\n\n\th, err := NewPBlindHandler(PBlindOptions{\n\t\tZone:           PBlindTestZone,\n\t\tCurve:          elliptic.P256(),\n\t\tPrivateKey:     \"HbwGtLsqek1Fdwuz1MhNQfiY7tj9EpWHeMWHPZ9c6KYY\",\n\t\tUseSerials:     true,\n\t\tBatchSize:      1000,\n\t\tRandomizeOrder: true,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = RegisterPBlindHandler(h)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc TestPBlind(t *testing.T) {\n\tt.Parallel()\n\n\topts := &PBlindOptions{\n\t\tZone:           PBlindTestZone,\n\t\tCurve:          elliptic.P256(),\n\t\tUseSerials:     true,\n\t\tBatchSize:      1000,\n\t\tRandomizeOrder: true,\n\t}\n\n\t// Issuer\n\topts.PrivateKey = \"HbwGtLsqek1Fdwuz1MhNQfiY7tj9EpWHeMWHPZ9c6KYY\"\n\tissuer, err := NewPBlindHandler(*opts)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Client\n\topts.PrivateKey = \"\"\n\topts.PublicKey = \"285oMDh3w5mxyFgpmmURifKfhkcqwwsdnePpPZ6Nqm8cc\"\n\tclient, err := NewPBlindHandler(*opts)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Verifier\n\tverifier, err := NewPBlindHandler(*opts)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Play through the whole use case.\n\n\tsignerState, setupResponse, err := issuer.CreateSetup()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\trequest, err := client.CreateTokenRequest(setupResponse)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tissuedTokens, err := issuer.IssueTokens(signerState, request)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = client.ProcessIssuedTokens(issuedTokens)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttoken, err := client.GetToken()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = verifier.Verify(token)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc TestPBlindLibrary(t *testing.T) {\n\tt.Parallel()\n\n\t// generate a key-pair\n\n\tcurve := elliptic.P256()\n\n\tsk, _ := pblind.NewSecretKey(curve)\n\tpk := sk.GetPublicKey()\n\n\tmsgStr := []byte(\"128b_accesstoken\")\n\tinfoStr := []byte(\"v=1 serial=12345\")\n\tinfo, err := pblind.CompressInfo(curve, infoStr)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttotalStart := time.Now()\n\tbatchSize := 1000\n\n\tsigners := make([]*pblind.StateSigner, batchSize)\n\trequesters := make([]*pblind.StateRequester, batchSize)\n\ttoServer := make([][]byte, batchSize)\n\ttoClient := make([][]byte, batchSize)\n\n\t// Create signers and prep requests.\n\tstart := time.Now()\n\tfor i := range batchSize {\n\t\tsigner, err := pblind.CreateSigner(sk, info)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tsigners[i] = signer\n\n\t\tmsg1S, err := signer.CreateMessage1()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tser1S, err := asn1.Marshal(msg1S)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\ttoClient[i] = ser1S\n\t}\n\tt.Logf(\"created %d signers and request preps in %s\", batchSize, time.Since(start))\n\tt.Logf(\"sending %d bytes to client\", lenOfByteSlices(toClient))\n\n\t// Create requesters and create requests.\n\tstart = time.Now()\n\tfor i := range batchSize {\n\t\trequester, err := pblind.CreateRequester(pk, info, msgStr)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\trequesters[i] = requester\n\n\t\tvar msg1R pblind.Message1\n\t\t_, err = asn1.Unmarshal(toClient[i], &msg1R)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\terr = requester.ProcessMessage1(msg1R)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tmsg2R, err := requester.CreateMessage2()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tser2R, err := asn1.Marshal(msg2R)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\ttoServer[i] = ser2R\n\t}\n\tt.Logf(\"created %d requesters and requests in %s\", batchSize, time.Since(start))\n\tt.Logf(\"sending %d bytes to server\", lenOfByteSlices(toServer))\n\n\t// Sign requests\n\tstart = time.Now()\n\tfor i := range batchSize {\n\t\tvar msg2S pblind.Message2\n\t\t_, err = asn1.Unmarshal(toServer[i], &msg2S)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\terr = signers[i].ProcessMessage2(msg2S)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tmsg3S, err := signers[i].CreateMessage3()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tser3S, err := asn1.Marshal(msg3S)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\ttoClient[i] = ser3S\n\t}\n\tt.Logf(\"signed %d requests in %s\", batchSize, time.Since(start))\n\tt.Logf(\"sending %d bytes to client\", lenOfByteSlices(toClient))\n\n\t// Verify signed requests\n\tstart = time.Now()\n\tfor i := range batchSize {\n\t\tvar msg3R pblind.Message3\n\t\t_, err := asn1.Unmarshal(toClient[i], &msg3R)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\terr = requesters[i].ProcessMessage3(msg3R)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tsignature, err := requesters[i].Signature()\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tsig, err := asn1.Marshal(signature)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\ttoServer[i] = sig\n\n\t\t// check signature\n\t\tif !pk.Check(signature, info, msgStr) {\n\t\t\tt.Fatal(\"signature invalid\")\n\t\t}\n\t}\n\tt.Logf(\"finalized and verified %d signed tokens in %s\", batchSize, time.Since(start))\n\tt.Logf(\"stored %d signed tokens in %d bytes\", batchSize, lenOfByteSlices(toServer))\n\n\t// Verify on server\n\tstart = time.Now()\n\tfor i := range batchSize {\n\t\tvar sig pblind.Signature\n\t\t_, err := asn1.Unmarshal(toServer[i], &sig)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\t// check signature\n\t\tif !pk.Check(sig, info, msgStr) {\n\t\t\tt.Fatal(\"signature invalid\")\n\t\t}\n\t}\n\tt.Logf(\"verified %d signed tokens in %s\", batchSize, time.Since(start))\n\n\tt.Logf(\"process complete\")\n\tt.Logf(\"simulated the whole process for %d tokens in %s\", batchSize, time.Since(totalStart))\n}\n\nfunc lenOfByteSlices(v [][]byte) (length int) {\n\tfor _, s := range v {\n\t\tlength += len(s)\n\t}\n\treturn\n}\n"
  },
  {
    "path": "spn/access/token/registry.go",
    "content": "package token\n\nimport \"sync\"\n\n// Handler represents a token handling system.\ntype Handler interface {\n\t// Zone returns the zone name.\n\tZone() string\n\n\t// ShouldRequest returns whether the new tokens should be requested.\n\tShouldRequest() bool\n\n\t// Amount returns the current amount of tokens in this handler.\n\tAmount() int\n\n\t// IsFallback returns whether this handler should only be used as a fallback.\n\tIsFallback() bool\n\n\t// GetToken returns a token.\n\tGetToken() (token *Token, err error)\n\n\t// Verify verifies the given token.\n\tVerify(token *Token) error\n\n\t// Save serializes and returns the current tokens.\n\tSave() ([]byte, error)\n\n\t// Load loads the given tokens into the handler.\n\tLoad(data []byte) error\n\n\t// Clear clears all the tokens in the handler.\n\tClear()\n}\n\nvar (\n\tregistry         map[string]Handler\n\tpblindRegistry   []*PBlindHandler\n\tscrambleRegistry []*ScrambleHandler\n\n\tregistryLock sync.RWMutex\n)\n\nfunc init() {\n\tinitRegistry()\n}\n\nfunc initRegistry() {\n\tregistry = make(map[string]Handler)\n\tpblindRegistry = make([]*PBlindHandler, 0, 1)\n\tscrambleRegistry = make([]*ScrambleHandler, 0, 1)\n}\n\n// RegisterPBlindHandler registers a pblind handler with the registry.\nfunc RegisterPBlindHandler(h *PBlindHandler) error {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\tif err := registerHandler(h, h.opts.Zone); err != nil {\n\t\treturn err\n\t}\n\n\tpblindRegistry = append(pblindRegistry, h)\n\treturn nil\n}\n\n// RegisterScrambleHandler registers a scramble handler with the registry.\nfunc RegisterScrambleHandler(h *ScrambleHandler) error {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\tif err := registerHandler(h, h.opts.Zone); err != nil {\n\t\treturn err\n\t}\n\n\tscrambleRegistry = append(scrambleRegistry, h)\n\treturn nil\n}\n\nfunc registerHandler(h Handler, zone string) error {\n\tif zone == \"\" {\n\t\treturn ErrNoZone\n\t}\n\n\t_, ok := registry[zone]\n\tif ok {\n\t\treturn ErrZoneTaken\n\t}\n\n\tregistry[zone] = h\n\treturn nil\n}\n\n// GetHandler returns the handler of the given zone.\nfunc GetHandler(zone string) (handler Handler, ok bool) {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\thandler, ok = registry[zone]\n\treturn\n}\n\n// ResetRegistry resets the token handler registry.\nfunc ResetRegistry() {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\tinitRegistry()\n}\n\n// RegistrySize returns the amount of handler registered.\nfunc RegistrySize() int {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\treturn len(registry)\n}\n"
  },
  {
    "path": "spn/access/token/request.go",
    "content": "package token\n\nimport (\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/mr-tron/base58\"\n)\n\nconst sessionIDSize = 32\n\n// RequestHandlingState is a request handling state.\ntype RequestHandlingState struct {\n\tSessionID string\n\tPBlind    map[string]*PBlindSignerState\n}\n\n// SetupRequest is a setup request.\ntype SetupRequest struct {\n\tPBlind map[string]struct{} `json:\"PB,omitempty\"`\n}\n\n// SetupResponse is a setup response.\ntype SetupResponse struct {\n\tSessionID string                          `json:\"ID,omitempty\"`\n\tPBlind    map[string]*PBlindSetupResponse `json:\"PB,omitempty\"`\n}\n\n// TokenRequest is a token request.\ntype TokenRequest struct { //nolint:golint // Be explicit.\n\tSessionID string                           `json:\"ID,omitempty\"`\n\tPBlind    map[string]*PBlindTokenRequest   `json:\"PB,omitempty\"`\n\tScramble  map[string]*ScrambleTokenRequest `json:\"S,omitempty\"`\n}\n\n// IssuedTokens are issued tokens.\ntype IssuedTokens struct {\n\tPBlind   map[string]*IssuedPBlindTokens   `json:\"PB,omitempty\"`\n\tScramble map[string]*IssuedScrambleTokens `json:\"SC,omitempty\"`\n}\n\n// CreateSetupRequest creates a combined setup request for all registered tokens, if needed.\nfunc CreateSetupRequest() (request *SetupRequest, setupRequired bool) {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\trequest = &SetupRequest{\n\t\tPBlind: make(map[string]struct{}, len(pblindRegistry)),\n\t}\n\n\t// Go through handlers and create request setups.\n\tfor _, pblindHandler := range pblindRegistry {\n\t\t// Check if we need to request with this handler.\n\t\tif pblindHandler.ShouldRequest() {\n\t\t\trequest.PBlind[pblindHandler.Zone()] = struct{}{}\n\t\t\tsetupRequired = true\n\t\t}\n\t}\n\n\treturn\n}\n\n// HandleSetupRequest handles a setup request for all registered tokens.\nfunc HandleSetupRequest(request *SetupRequest) (*RequestHandlingState, *SetupResponse, error) {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\t// Generate session token.\n\trandomID := make([]byte, sessionIDSize)\n\tn, err := rand.Read(randomID)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to generate session ID: %w\", err)\n\t}\n\tif n != sessionIDSize {\n\t\treturn nil, nil, fmt.Errorf(\"failed to get full session ID: only got %d bytes\", n)\n\t}\n\tsessionID := base58.Encode(randomID)\n\n\t// Create state and response.\n\tstate := &RequestHandlingState{\n\t\tSessionID: sessionID,\n\t\tPBlind:    make(map[string]*PBlindSignerState, len(pblindRegistry)),\n\t}\n\tsetup := &SetupResponse{\n\t\tSessionID: sessionID,\n\t\tPBlind:    make(map[string]*PBlindSetupResponse, len(pblindRegistry)),\n\t}\n\n\t// Go through handlers and create setups.\n\tfor _, pblindHandler := range pblindRegistry {\n\t\t// Check if we have a request for this handler.\n\t\t_, ok := request.PBlind[pblindHandler.Zone()]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tplindState, pblindSetup, err := pblindHandler.CreateSetup()\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to create setup for %s: %w\", pblindHandler.Zone(), err)\n\t\t}\n\n\t\tstate.PBlind[pblindHandler.Zone()] = plindState\n\t\tsetup.PBlind[pblindHandler.Zone()] = pblindSetup\n\t}\n\n\treturn state, setup, nil\n}\n\n// CreateTokenRequest creates a token request for all registered tokens.\nfunc CreateTokenRequest(setup *SetupResponse) (request *TokenRequest, requestRequired bool, err error) {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\t// Check setup data.\n\tif setup != nil && setup.SessionID == \"\" {\n\t\treturn nil, false, errors.New(\"setup data is missing a session ID\")\n\t}\n\n\t// Create token request.\n\trequest = &TokenRequest{\n\t\tPBlind:   make(map[string]*PBlindTokenRequest, len(pblindRegistry)),\n\t\tScramble: make(map[string]*ScrambleTokenRequest, len(scrambleRegistry)),\n\t}\n\tif setup != nil {\n\t\trequest.SessionID = setup.SessionID\n\t}\n\n\t// Go through handlers and create requests.\n\tif setup != nil {\n\t\tfor _, pblindHandler := range pblindRegistry {\n\t\t\t// Check if we have setup data for this handler.\n\t\t\tpblindSetup, ok := setup.PBlind[pblindHandler.Zone()]\n\t\t\tif !ok {\n\t\t\t\t// TODO: Abort if we should have received request data.\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Create request.\n\t\t\tpblindRequest, err := pblindHandler.CreateTokenRequest(pblindSetup)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to create token request for %s: %w\", pblindHandler.Zone(), err)\n\t\t\t}\n\n\t\t\trequestRequired = true\n\t\t\trequest.PBlind[pblindHandler.Zone()] = pblindRequest\n\t\t}\n\t}\n\tfor _, scrambleHandler := range scrambleRegistry {\n\t\t// Check if we need to request with this handler.\n\t\tif scrambleHandler.ShouldRequest() {\n\t\t\trequestRequired = true\n\t\t\trequest.Scramble[scrambleHandler.Zone()] = scrambleHandler.CreateTokenRequest()\n\t\t}\n\t}\n\n\treturn request, requestRequired, nil\n}\n\n// IssueTokens issues tokens for all registered tokens.\nfunc IssueTokens(state *RequestHandlingState, request *TokenRequest) (response *IssuedTokens, err error) {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\t// Create token response.\n\tresponse = &IssuedTokens{\n\t\tPBlind:   make(map[string]*IssuedPBlindTokens, len(pblindRegistry)),\n\t\tScramble: make(map[string]*IssuedScrambleTokens, len(scrambleRegistry)),\n\t}\n\n\t// Go through handlers and create requests.\n\tfor _, pblindHandler := range pblindRegistry {\n\t\t// Check if we have all the data for issuing.\n\t\tpblindState, ok := state.PBlind[pblindHandler.Zone()]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tpblindRequest, ok := request.PBlind[pblindHandler.Zone()]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Issue tokens.\n\t\tpblindTokens, err := pblindHandler.IssueTokens(pblindState, pblindRequest)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to issue tokens for %s: %w\", pblindHandler.Zone(), err)\n\t\t}\n\n\t\tresponse.PBlind[pblindHandler.Zone()] = pblindTokens\n\t}\n\tfor _, scrambleHandler := range scrambleRegistry {\n\t\t// Check if we have all the data for issuing.\n\t\tscrambleRequest, ok := request.Scramble[scrambleHandler.Zone()]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Issue tokens.\n\t\tscrambleTokens, err := scrambleHandler.IssueTokens(scrambleRequest)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to issue tokens for %s: %w\", scrambleHandler.Zone(), err)\n\t\t}\n\n\t\tresponse.Scramble[scrambleHandler.Zone()] = scrambleTokens\n\t}\n\n\treturn response, nil\n}\n\n// ProcessIssuedTokens processes issued tokens for all registered tokens.\nfunc ProcessIssuedTokens(response *IssuedTokens) error {\n\tregistryLock.RLock()\n\tdefer registryLock.RUnlock()\n\n\t// Go through handlers and create requests.\n\tfor _, pblindHandler := range pblindRegistry {\n\t\t// Check if we received tokens.\n\t\tpblindResponse, ok := response.PBlind[pblindHandler.Zone()]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Process issued tokens.\n\t\terr := pblindHandler.ProcessIssuedTokens(pblindResponse)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to process issued tokens for %s: %w\", pblindHandler.Zone(), err)\n\t\t}\n\t}\n\tfor _, scrambleHandler := range scrambleRegistry {\n\t\t// Check if we received tokens.\n\t\tscrambleResponse, ok := response.Scramble[scrambleHandler.Zone()]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Process issued tokens.\n\t\terr := scrambleHandler.ProcessIssuedTokens(scrambleResponse)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to process issued tokens for %s: %w\", scrambleHandler.Zone(), err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/access/token/request_test.go",
    "content": "package token\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/structures/dsd\"\n)\n\nfunc TestFull(t *testing.T) {\n\tt.Parallel()\n\n\ttestStart := time.Now()\n\n\t// Roundtrip 1\n\n\tstart := time.Now()\n\tsetupRequest, setupRequired := CreateSetupRequest()\n\tif !setupRequired {\n\t\tt.Fatal(\"setup should be required\")\n\t}\n\tsetupRequestData, err := dsd.Dump(setupRequest, dsd.CBOR)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tsetupRequest = nil // nolint:ineffassign,wastedassign // Just to be sure.\n\tt.Logf(\"setupRequest: %s, %d bytes\", time.Since(start), len(setupRequestData))\n\n\tstart = time.Now()\n\tloadedSetupRequest := &SetupRequest{}\n\t_, err = dsd.Load(setupRequestData, loadedSetupRequest)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tserverState, setupResponse, err := HandleSetupRequest(loadedSetupRequest)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tsetupResponseData, err := dsd.Dump(setupResponse, dsd.CBOR)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tsetupResponse = nil // nolint:ineffassign,wastedassign // Just to be sure.\n\tt.Logf(\"setupResponse: %s, %d bytes\", time.Since(start), len(setupResponseData))\n\n\t// Roundtrip 2\n\n\tstart = time.Now()\n\tloadedSetupResponse := &SetupResponse{}\n\t_, err = dsd.Load(setupResponseData, loadedSetupResponse)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\trequest, requestRequired, err := CreateTokenRequest(loadedSetupResponse)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !requestRequired {\n\t\tt.Fatal(\"request should be required\")\n\t}\n\trequestData, err := dsd.Dump(request, dsd.CBOR)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\trequest = nil // nolint:ineffassign,wastedassign // Just to be sure.\n\tt.Logf(\"request: %s, %d bytes\", time.Since(start), len(requestData))\n\n\tstart = time.Now()\n\tloadedRequest := &TokenRequest{}\n\t_, err = dsd.Load(requestData, loadedRequest)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tresponse, err := IssueTokens(serverState, loadedRequest)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tresponseData, err := dsd.Dump(response, dsd.CBOR)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tresponse = nil // nolint:ineffassign,wastedassign // Just to be sure.\n\tt.Logf(\"response: %s, %d bytes\", time.Since(start), len(responseData))\n\n\tstart = time.Now()\n\tloadedResponse := &IssuedTokens{}\n\t_, err = dsd.Load(responseData, loadedResponse)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\terr = ProcessIssuedTokens(loadedResponse)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tt.Logf(\"processing: %s\", time.Since(start))\n\n\t// Token Usage\n\n\tfor _, testZone := range []string{\n\t\tPBlindTestZone,\n\t\tScrambleTestZone,\n\t} {\n\t\tstart = time.Now()\n\n\t\ttoken, err := GetToken(testZone)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\ttokenData := token.Raw()\n\t\ttoken = nil // nolint:wastedassign // Just to be sure.\n\n\t\tloadedToken, err := ParseRawToken(tokenData)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\terr = VerifyToken(loadedToken)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tt.Logf(\"using %s token: %s\", testZone, time.Since(start))\n\t}\n\n\tt.Logf(\"full simulation took %s\", time.Since(testStart))\n}\n"
  },
  {
    "path": "spn/access/token/scramble.go",
    "content": "package token\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/mr-tron/base58\"\n\n\t\"github.com/safing/jess/lhash\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nconst (\n\tscrambleSecretSize = 32\n)\n\n// ScrambleToken is token based on hashing.\ntype ScrambleToken struct {\n\tToken []byte\n}\n\n// Pack packs the token.\nfunc (pbt *ScrambleToken) Pack() ([]byte, error) {\n\treturn pbt.Token, nil\n}\n\n// UnpackScrambleToken unpacks the token.\nfunc UnpackScrambleToken(token []byte) (*ScrambleToken, error) {\n\treturn &ScrambleToken{Token: token}, nil\n}\n\n// ScrambleHandler is a handler for the scramble tokens.\ntype ScrambleHandler struct {\n\tsync.Mutex\n\topts *ScrambleOptions\n\n\tstorageLock sync.Mutex\n\tStorage     []*ScrambleToken\n\n\tverifiersLock sync.RWMutex\n\tverifiers     map[string]*ScrambleToken\n}\n\n// ScrambleOptions are options for the ScrambleHandler.\ntype ScrambleOptions struct {\n\tZone             string\n\tAlgorithm        lhash.Algorithm\n\tInitialTokens    []string\n\tInitialVerifiers []string\n\tFallback         bool\n}\n\n// ScrambleTokenRequest is a token request.\ntype ScrambleTokenRequest struct{}\n\n// IssuedScrambleTokens are issued scrambled tokens.\ntype IssuedScrambleTokens struct {\n\tTokens []*ScrambleToken\n}\n\n// NewScrambleHandler creates a new scramble handler.\nfunc NewScrambleHandler(opts ScrambleOptions) (*ScrambleHandler, error) {\n\tsh := &ScrambleHandler{\n\t\topts:      &opts,\n\t\tverifiers: make(map[string]*ScrambleToken, len(opts.InitialTokens)+len(opts.InitialVerifiers)),\n\t}\n\n\t// Add initial tokens.\n\tsh.Storage = make([]*ScrambleToken, len(opts.InitialTokens))\n\tfor i, token := range opts.InitialTokens {\n\t\t// Add to storage.\n\t\ttokenData, err := base58.Decode(token)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode initial token %q: %w\", token, err)\n\t\t}\n\t\tsh.Storage[i] = &ScrambleToken{\n\t\t\tToken: tokenData,\n\t\t}\n\n\t\t// Add to verifiers.\n\t\tscrambledToken := lhash.Digest(sh.opts.Algorithm, tokenData).Bytes()\n\t\tsh.verifiers[string(scrambledToken)] = sh.Storage[i]\n\t}\n\n\t// Add initial verifiers.\n\tfor _, verifier := range opts.InitialVerifiers {\n\t\tverifierData, err := base58.Decode(verifier)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode verifier %q: %w\", verifier, err)\n\t\t}\n\t\tsh.verifiers[string(verifierData)] = &ScrambleToken{}\n\t}\n\n\treturn sh, nil\n}\n\n// Zone returns the zone name.\nfunc (sh *ScrambleHandler) Zone() string {\n\treturn sh.opts.Zone\n}\n\n// ShouldRequest returns whether the new tokens should be requested.\nfunc (sh *ScrambleHandler) ShouldRequest() bool {\n\tsh.storageLock.Lock()\n\tdefer sh.storageLock.Unlock()\n\n\treturn len(sh.Storage) == 0\n}\n\n// Amount returns the current amount of tokens in this handler.\nfunc (sh *ScrambleHandler) Amount() int {\n\tsh.storageLock.Lock()\n\tdefer sh.storageLock.Unlock()\n\n\treturn len(sh.Storage)\n}\n\n// IsFallback returns whether this handler should only be used as a fallback.\nfunc (sh *ScrambleHandler) IsFallback() bool {\n\treturn sh.opts.Fallback\n}\n\n// CreateTokenRequest creates a token request to be sent to the token server.\nfunc (sh *ScrambleHandler) CreateTokenRequest() (request *ScrambleTokenRequest) {\n\treturn &ScrambleTokenRequest{}\n}\n\n// IssueTokens sign the requested tokens.\nfunc (sh *ScrambleHandler) IssueTokens(request *ScrambleTokenRequest) (response *IssuedScrambleTokens, err error) {\n\t// Copy the storage.\n\ttokens := make([]*ScrambleToken, len(sh.Storage))\n\tcopy(tokens, sh.Storage)\n\n\treturn &IssuedScrambleTokens{\n\t\tTokens: tokens,\n\t}, nil\n}\n\n// ProcessIssuedTokens processes the issued token from the server.\nfunc (sh *ScrambleHandler) ProcessIssuedTokens(issuedTokens *IssuedScrambleTokens) error {\n\tsh.verifiersLock.RLock()\n\tdefer sh.verifiersLock.RUnlock()\n\n\t// Validate tokens.\n\tfor i, newToken := range issuedTokens.Tokens {\n\t\t// Scramle token.\n\t\tscrambledToken := lhash.Digest(sh.opts.Algorithm, newToken.Token).Bytes()\n\n\t\t// Check if token is valid.\n\t\t_, ok := sh.verifiers[string(scrambledToken)]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"invalid token on #%d\", i)\n\t\t}\n\t}\n\n\t// Copy to storage.\n\tsh.Storage = issuedTokens.Tokens\n\n\treturn nil\n}\n\n// Verify verifies the given token.\nfunc (sh *ScrambleHandler) Verify(token *Token) error {\n\tif token.Zone != sh.opts.Zone {\n\t\treturn ErrZoneMismatch\n\t}\n\n\t// Hash the data.\n\tscrambledToken := lhash.Digest(sh.opts.Algorithm, token.Data).Bytes()\n\n\tsh.verifiersLock.RLock()\n\tdefer sh.verifiersLock.RUnlock()\n\n\t// Check if token is valid.\n\t_, ok := sh.verifiers[string(scrambledToken)]\n\tif !ok {\n\t\treturn ErrTokenInvalid\n\t}\n\n\treturn nil\n}\n\n// GetToken returns a token.\nfunc (sh *ScrambleHandler) GetToken() (*Token, error) {\n\tsh.storageLock.Lock()\n\tdefer sh.storageLock.Unlock()\n\n\tif len(sh.Storage) == 0 {\n\t\treturn nil, ErrEmpty\n\t}\n\n\treturn &Token{\n\t\tZone: sh.opts.Zone,\n\t\tData: sh.Storage[0].Token,\n\t}, nil\n}\n\n// ScrambleStorage is a storage for scramble tokens.\ntype ScrambleStorage struct {\n\tStorage []*ScrambleToken\n}\n\n// Save serializes and returns the current tokens.\nfunc (sh *ScrambleHandler) Save() ([]byte, error) {\n\tsh.storageLock.Lock()\n\tdefer sh.storageLock.Unlock()\n\n\tif len(sh.Storage) == 0 {\n\t\treturn nil, ErrEmpty\n\t}\n\n\ts := &ScrambleStorage{\n\t\tStorage: sh.Storage,\n\t}\n\n\treturn dsd.Dump(s, dsd.CBOR)\n}\n\n// Load loads the given tokens into the handler.\nfunc (sh *ScrambleHandler) Load(data []byte) error {\n\tsh.storageLock.Lock()\n\tdefer sh.storageLock.Unlock()\n\n\ts := &ScrambleStorage{}\n\t_, err := dsd.Load(data, s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsh.Storage = s.Storage\n\treturn nil\n}\n\n// Clear clears all the tokens in the handler.\nfunc (sh *ScrambleHandler) Clear() {\n\tsh.storageLock.Lock()\n\tdefer sh.storageLock.Unlock()\n\n\tsh.Storage = nil\n}\n"
  },
  {
    "path": "spn/access/token/scramble_gen_test.go",
    "content": "package token\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/mr-tron/base58\"\n\n\t\"github.com/safing/jess/lhash\"\n)\n\ntype genAlgs struct {\n\talg  lhash.Algorithm\n\tname string\n}\n\nfunc TestGenerateScrambleKeys(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, alg := range []genAlgs{\n\t\t{alg: lhash.SHA2_256, name: \"SHA2_256\"},\n\t\t{alg: lhash.SHA3_256, name: \"SHA3_256\"},\n\t\t{alg: lhash.SHA3_512, name: \"SHA3_512\"},\n\t\t{alg: lhash.BLAKE2b_256, name: \"BLAKE2b_256\"},\n\t} {\n\t\ttoken := make([]byte, scrambleSecretSize)\n\t\tn, err := rand.Read(token)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif n != scrambleSecretSize {\n\t\t\tt.Fatalf(\"only got %d bytes\", n)\n\t\t}\n\t\tscrambledToken := lhash.Digest(alg.alg, token).Bytes()\n\n\t\tfmt.Printf(\n\t\t\t\"%s secret token: %s\\n\",\n\t\t\talg.name,\n\t\t\tbase58.Encode(token),\n\t\t)\n\t\tfmt.Printf(\n\t\t\t\"%s scrambled (public) token: %s\\n\",\n\t\t\talg.name,\n\t\t\tbase58.Encode(scrambledToken),\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "spn/access/token/scramble_test.go",
    "content": "package token\n\nimport (\n\t\"testing\"\n\n\t\"github.com/safing/jess/lhash\"\n)\n\nconst ScrambleTestZone = \"test-scramble\"\n\nfunc init() {\n\t// Combined testing config.\n\n\th, err := NewScrambleHandler(ScrambleOptions{\n\t\tZone:          ScrambleTestZone,\n\t\tAlgorithm:     lhash.SHA2_256,\n\t\tInitialTokens: []string{\"2VqJ8BvDew1tUpytZhR7tuvq7ToPpW3tQtHvu3veE3iW\"},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = RegisterScrambleHandler(h)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc TestScramble(t *testing.T) {\n\tt.Parallel()\n\n\topts := &ScrambleOptions{\n\t\tZone:      ScrambleTestZone,\n\t\tAlgorithm: lhash.SHA2_256,\n\t}\n\n\t// Issuer\n\topts.InitialTokens = []string{\"2VqJ8BvDew1tUpytZhR7tuvq7ToPpW3tQtHvu3veE3iW\"}\n\tissuer, err := NewScrambleHandler(*opts)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Client\n\topts.InitialTokens = nil\n\topts.InitialVerifiers = []string{\"Cy9tz37Xq9NiXGDRU9yicjGU62GjXskE9KqUmuoddSxaE3\"}\n\tclient, err := NewScrambleHandler(*opts)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Verifier\n\tverifier, err := NewScrambleHandler(*opts)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Play through the whole use case.\n\n\trequest := client.CreateTokenRequest()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tissuedTokens, err := issuer.IssueTokens(request)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = client.ProcessIssuedTokens(issuedTokens)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttoken, err := client.GetToken()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\terr = verifier.Verify(token)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "spn/access/token/token.go",
    "content": "package token\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/mr-tron/base58\"\n\n\t\"github.com/safing/structures/container\"\n)\n\n// Token represents a token, consisting of a zone (name) and some data.\ntype Token struct {\n\tZone string\n\tData []byte\n}\n\n// GetToken returns a token of the given zone.\nfunc GetToken(zone string) (*Token, error) {\n\thandler, ok := GetHandler(zone)\n\tif !ok {\n\t\treturn nil, ErrZoneUnknown\n\t}\n\n\treturn handler.GetToken()\n}\n\n// VerifyToken verifies the given token.\nfunc VerifyToken(token *Token) error {\n\thandler, ok := GetHandler(token.Zone)\n\tif !ok {\n\t\treturn ErrZoneUnknown\n\t}\n\n\treturn handler.Verify(token)\n}\n\n// Raw returns the raw format of the token.\nfunc (c *Token) Raw() []byte {\n\tcont := container.New()\n\tcont.Append([]byte(c.Zone))\n\tcont.Append([]byte(\":\"))\n\tcont.Append(c.Data)\n\treturn cont.CompileData()\n}\n\n// String returns the stringified format of the token.\nfunc (c *Token) String() string {\n\treturn c.Zone + \":\" + base58.Encode(c.Data)\n}\n\n// ParseRawToken parses a raw token.\nfunc ParseRawToken(code []byte) (*Token, error) {\n\tsplitted := bytes.SplitN(code, []byte(\":\"), 2)\n\tif len(splitted) < 2 {\n\t\treturn nil, errors.New(\"invalid code format: zone/data separator missing\")\n\t}\n\n\treturn &Token{\n\t\tZone: string(splitted[0]),\n\t\tData: splitted[1],\n\t}, nil\n}\n\n// ParseToken parses a stringified token.\nfunc ParseToken(code string) (*Token, error) {\n\tsplitted := strings.SplitN(code, \":\", 2)\n\tif len(splitted) < 2 {\n\t\treturn nil, errors.New(\"invalid code format: zone/data separator missing\")\n\t}\n\n\tdata, err := base58.Decode(splitted[1])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid code format: %w\", err)\n\t}\n\n\treturn &Token{\n\t\tZone: splitted[0],\n\t\tData: data,\n\t}, nil\n}\n"
  },
  {
    "path": "spn/access/token/token_test.go",
    "content": "package token\n\nimport (\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/rng\"\n)\n\nfunc TestToken(t *testing.T) {\n\tt.Parallel()\n\n\trandomData, err := rng.Bytes(32)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tc := &Token{\n\t\tZone: \"test\",\n\t\tData: randomData,\n\t}\n\n\ts := c.String()\n\t_, err = ParseToken(s)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tr := c.Raw()\n\t_, err = ParseRawToken(r)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "spn/access/zones.go",
    "content": "package access\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/jess/lhash\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/access/token\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nvar (\n\t// ExpandAndConnectZones are the zones that grant access to the expand and\n\t// connect operations.\n\tExpandAndConnectZones = []string{\"pblind1\", \"alpha2\", \"fallback1\"}\n\n\tzonePermissions = map[string]terminal.Permission{\n\t\t\"pblind1\":   terminal.AddPermissions(terminal.MayExpand, terminal.MayConnect),\n\t\t\"alpha2\":    terminal.AddPermissions(terminal.MayExpand, terminal.MayConnect),\n\t\t\"fallback1\": terminal.AddPermissions(terminal.MayExpand, terminal.MayConnect),\n\t}\n\tpersistentZones = ExpandAndConnectZones\n\n\tenableTestMode = abool.New()\n)\n\n// EnableTestMode enables the test mode, leading the access module to only\n// register a test zone.\n// This should not be used to test the access module itself.\nfunc EnableTestMode() {\n\tenableTestMode.Set()\n}\n\n// InitializeZones initialized the permission zones.\n// It initializes the test zones, if EnableTestMode was called before.\n// Must only be called once.\nfunc InitializeZones() error {\n\t// Check if we are testing.\n\tif enableTestMode.IsSet() {\n\t\treturn initializeTestZone()\n\t}\n\n\t// Special client zone config.\n\tvar requestSignalHandler func(token.Handler)\n\tif conf.Integrated() {\n\t\trequestSignalHandler = shouldRequestTokensHandler\n\t}\n\n\t// Register pblind1 as the first primary zone.\n\tph, err := token.NewPBlindHandler(token.PBlindOptions{\n\t\tZone:                \"pblind1\",\n\t\tCurveName:           \"P-256\",\n\t\tPublicKey:           \"eXoJXzXbM66UEsM2eVi9HwyBPLMfVnNrC7gNrsfMUJDs\",\n\t\tUseSerials:          true,\n\t\tBatchSize:           1000,\n\t\tRandomizeOrder:      true,\n\t\tSignalShouldRequest: requestSignalHandler,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create pblind1 token handler: %w\", err)\n\t}\n\terr = token.RegisterPBlindHandler(ph)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to register pblind1 token handler: %w\", err)\n\t}\n\n\t// Register fallback1 zone as fallback when the issuer is not available.\n\tsh, err := token.NewScrambleHandler(token.ScrambleOptions{\n\t\tZone:             \"fallback1\",\n\t\tAlgorithm:        lhash.BLAKE2b_256,\n\t\tInitialVerifiers: []string{\"ZwkQoaAttVBMURzeLzNXokFBMAMUUwECfM1iHojcVKBmjk\"},\n\t\tFallback:         true,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create fallback1 token handler: %w\", err)\n\t}\n\terr = token.RegisterScrambleHandler(sh)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to register fallback1 token handler: %w\", err)\n\t}\n\n\t// Register alpha2 zone for transition phase.\n\tsh, err = token.NewScrambleHandler(token.ScrambleOptions{\n\t\tZone:             \"alpha2\",\n\t\tAlgorithm:        lhash.BLAKE2b_256,\n\t\tInitialVerifiers: []string{\"ZwojEvXZmAv7SZdNe7m94Xzu7F9J8vULqKf7QYtoTpN2tH\"},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create alpha2 token handler: %w\", err)\n\t}\n\terr = token.RegisterScrambleHandler(sh)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to register alpha2 token handler: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc initializeTestZone() error {\n\t// Safeguard checks if we should really enable the test zone.\n\tif !strings.HasSuffix(os.Args[0], \".test\") {\n\t\treturn errors.New(\"tried to enable test mode, but no test binary was detected\")\n\t}\n\tif token.RegistrySize() > 0 {\n\t\treturn fmt.Errorf(\"tried to enable test zone, but %d handlers are already registered\", token.RegistrySize())\n\t}\n\n\t// Reset zones.\n\ttoken.ResetRegistry()\n\n\t// Set eligible zones.\n\tExpandAndConnectZones = []string{\"unittest\"}\n\tzonePermissions = map[string]terminal.Permission{\n\t\t\"unittest\": terminal.AddPermissions(terminal.MayExpand, terminal.MayConnect),\n\t}\n\n\t// Register unittest zone as for testing.\n\tsh, err := token.NewScrambleHandler(token.ScrambleOptions{\n\t\tZone:             \"unittest\",\n\t\tAlgorithm:        lhash.BLAKE2b_256,\n\t\tInitialTokens:    []string{\"6jFqLA93uSLL52utGKrvctG3ZfopSQ8WFqjsRK1c2Svt\"},\n\t\tInitialVerifiers: []string{\"ZwoEoL59sr81s7WnF2vydGzjeejE3u8CqVafig1NTQzUr7\"},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create unittest token handler: %w\", err)\n\t}\n\terr = token.RegisterScrambleHandler(sh)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to register unittest token handler: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc shouldRequestTokensHandler(_ token.Handler) {\n\t// Run the account update task as now.\n\tmodule.updateAccountWorkerMgr.Go()\n}\n\n// GetTokenAmount returns the amount of tokens for the given zones.\nfunc GetTokenAmount(zones []string) (regular, fallback int) {\nhandlerLoop:\n\tfor _, zone := range zones {\n\t\t// Get handler and check if it should be used.\n\t\thandler, ok := token.GetHandler(zone)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/access: use of non-registered zone %q\", zone)\n\t\t\tcontinue handlerLoop\n\t\t}\n\n\t\tif handler.IsFallback() {\n\t\t\tfallback += handler.Amount()\n\t\t} else {\n\t\t\tregular += handler.Amount()\n\t\t}\n\t}\n\n\treturn\n}\n\n// ShouldRequest returns whether tokens should be requested for the given zones.\nfunc ShouldRequest(zones []string) (shouldRequest bool) {\nhandlerLoop:\n\tfor _, zone := range zones {\n\t\t// Get handler and check if it should be used.\n\t\thandler, ok := token.GetHandler(zone)\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/access: use of non-registered zone %q\", zone)\n\t\t\tcontinue handlerLoop\n\t\t}\n\n\t\t// Go through all handlers every time as this will be the case anyway most\n\t\t// of the time and will help us better catch zone misconfiguration.\n\t\tif handler.ShouldRequest() {\n\t\t\tshouldRequest = true\n\t\t}\n\t}\n\n\treturn shouldRequest\n}\n\n// GetToken returns a token of one of the given zones.\nfunc GetToken(zones []string) (t *token.Token, err error) {\nhandlerSelection:\n\tfor _, zone := range zones {\n\t\t// Get handler and check if it should be used.\n\t\thandler, ok := token.GetHandler(zone)\n\t\tswitch {\n\t\tcase !ok:\n\t\t\tlog.Warningf(\"spn/access: use of non-registered zone %q\", zone)\n\t\t\tcontinue handlerSelection\n\t\tcase handler.IsFallback() && !TokenIssuerIsFailing():\n\t\t\t// Skip fallback zone if everything works.\n\t\t\tcontinue handlerSelection\n\t\t}\n\n\t\t// Get token from handler.\n\t\tt, err = token.GetToken(zone)\n\t\tif err == nil {\n\t\t\treturn t, nil\n\t\t}\n\t}\n\n\t// Return existing error, if exists.\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn nil, token.ErrEmpty\n}\n\n// VerifyRawToken verifies a raw token.\nfunc VerifyRawToken(data []byte) (granted terminal.Permission, err error) {\n\tt, err := token.ParseRawToken(data)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to parse token: %w\", err)\n\t}\n\n\treturn VerifyToken(t)\n}\n\n// VerifyToken verifies a token.\nfunc VerifyToken(t *token.Token) (granted terminal.Permission, err error) {\n\thandler, ok := token.GetHandler(t.Zone)\n\tif !ok {\n\t\treturn terminal.NoPermission, token.ErrZoneUnknown\n\t}\n\n\t// Check if the token is a fallback token.\n\tif handler.IsFallback() && !healthCheck() {\n\t\treturn terminal.NoPermission, ErrFallbackNotAvailable\n\t}\n\n\t// Verify token.\n\terr = handler.Verify(t)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to verify token: %w\", err)\n\t}\n\n\t// Return permission of zone.\n\tgranted, ok = zonePermissions[t.Zone]\n\tif !ok {\n\t\treturn terminal.NoPermission, nil\n\t}\n\treturn granted, nil\n}\n"
  },
  {
    "path": "spn/cabin/config-public.go",
    "content": "package cabin\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// Configuration Keys.\nvar (\n\t// Name of the node.\n\tpublicCfgOptionNameKey     = \"spn/publicHub/name\"\n\tpublicCfgOptionName        config.StringOption\n\tpublicCfgOptionNameDefault = \"\"\n\tpublicCfgOptionNameOrder   = 512\n\n\t// Person or organisation, who is in control of the node (should be same for all nodes of this person or organisation).\n\tpublicCfgOptionGroupKey     = \"spn/publicHub/group\"\n\tpublicCfgOptionGroup        config.StringOption\n\tpublicCfgOptionGroupDefault = \"\"\n\tpublicCfgOptionGroupOrder   = 513\n\n\t// Contact possibility  (recommended, but optional).\n\tpublicCfgOptionContactAddressKey     = \"spn/publicHub/contactAddress\"\n\tpublicCfgOptionContactAddress        config.StringOption\n\tpublicCfgOptionContactAddressDefault = \"\"\n\tpublicCfgOptionContactAddressOrder   = 514\n\n\t// Type of service of the contact address, if not email.\n\tpublicCfgOptionContactServiceKey     = \"spn/publicHub/contactService\"\n\tpublicCfgOptionContactService        config.StringOption\n\tpublicCfgOptionContactServiceDefault = \"\"\n\tpublicCfgOptionContactServiceOrder   = 515\n\n\t// Hosters - supply chain (reseller, hosting provider, datacenter operator, ...).\n\tpublicCfgOptionHostersKey     = \"spn/publicHub/hosters\"\n\tpublicCfgOptionHosters        config.StringArrayOption\n\tpublicCfgOptionHostersDefault = []string{}\n\tpublicCfgOptionHostersOrder   = 516\n\n\t// Datacenter\n\t// Format: CC-COMPANY-INTERNALCODE\n\t// Eg: DE-Hetzner-FSN1-DC5\n\t//.\n\tpublicCfgOptionDatacenterKey     = \"spn/publicHub/datacenter\"\n\tpublicCfgOptionDatacenter        config.StringOption\n\tpublicCfgOptionDatacenterDefault = \"\"\n\tpublicCfgOptionDatacenterOrder   = 517\n\n\t// Network Location and Access.\n\n\t// IPv4 must be global and accessible.\n\tpublicCfgOptionIPv4Key     = \"spn/publicHub/ip4\"\n\tpublicCfgOptionIPv4        config.StringOption\n\tpublicCfgOptionIPv4Default = \"\"\n\tpublicCfgOptionIPv4Order   = 518\n\n\t// IPv6 must be global and accessible.\n\tpublicCfgOptionIPv6Key     = \"spn/publicHub/ip6\"\n\tpublicCfgOptionIPv6        config.StringOption\n\tpublicCfgOptionIPv6Default = \"\"\n\tpublicCfgOptionIPv6Order   = 519\n\n\t// Transports.\n\tpublicCfgOptionTransportsKey     = \"spn/publicHub/transports\"\n\tpublicCfgOptionTransports        config.StringArrayOption\n\tpublicCfgOptionTransportsDefault = []string{\n\t\t\"tcp:17\",\n\t}\n\tpublicCfgOptionTransportsOrder = 520\n\n\t// Entry Policy.\n\tpublicCfgOptionEntryKey     = \"spn/publicHub/entry\"\n\tpublicCfgOptionEntry        config.StringArrayOption\n\tpublicCfgOptionEntryDefault = []string{}\n\tpublicCfgOptionEntryOrder   = 521\n\n\t// Exit Policy.\n\tpublicCfgOptionExitKey     = \"spn/publicHub/exit\"\n\tpublicCfgOptionExit        config.StringArrayOption\n\tpublicCfgOptionExitDefault = []string{\"- * TCP/25\"}\n\tpublicCfgOptionExitOrder   = 522\n\n\t// Allow Unencrypted.\n\tpublicCfgOptionAllowUnencryptedKey     = \"spn/publicHub/allowUnencrypted\"\n\tpublicCfgOptionAllowUnencrypted        config.BoolOption\n\tpublicCfgOptionAllowUnencryptedDefault = false\n\tpublicCfgOptionAllowUnencryptedOrder   = 523\n)\n\nfunc prepPublicHubConfig() error {\n\terr := config.Register(&config.Option{\n\t\tName:            \"Name\",\n\t\tKey:             publicCfgOptionNameKey,\n\t\tDescription:     \"Human readable name of the Hub.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionNameDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionNameOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionName = config.GetAsString(publicCfgOptionNameKey, publicCfgOptionNameDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Group\",\n\t\tKey:             publicCfgOptionGroupKey,\n\t\tDescription:     \"Name of the hub group this Hub belongs to.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionGroupDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionGroupOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionGroup = config.GetAsString(publicCfgOptionGroupKey, publicCfgOptionGroupDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Contact Address\",\n\t\tKey:             publicCfgOptionContactAddressKey,\n\t\tDescription:     \"Contact address where the Hub operator can be reached.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionContactAddressDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionContactAddressOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionContactAddress = config.GetAsString(publicCfgOptionContactAddressKey, publicCfgOptionContactAddressDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Contact Service\",\n\t\tKey:             publicCfgOptionContactServiceKey,\n\t\tDescription:     \"Name of the service the contact address corresponds to, if not email.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionContactServiceDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionContactServiceOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionContactService = config.GetAsString(publicCfgOptionContactServiceKey, publicCfgOptionContactServiceDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Hosters\",\n\t\tKey:             publicCfgOptionHostersKey,\n\t\tDescription:     \"List of all involved entities and organisations that are involved in hosting this Hub.\",\n\t\tOptType:         config.OptTypeStringArray,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionHostersDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionHostersOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionHosters = config.GetAsStringArray(publicCfgOptionHostersKey, publicCfgOptionHostersDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Datacenter\",\n\t\tKey:             publicCfgOptionDatacenterKey,\n\t\tDescription:     \"Identifier of the datacenter this Hub is hosted in.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionDatacenterDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionDatacenterOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionDatacenter = config.GetAsString(publicCfgOptionDatacenterKey, publicCfgOptionDatacenterDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"IPv4\",\n\t\tKey:             publicCfgOptionIPv4Key,\n\t\tDescription:     \"IPv4 address of this Hub. Must be globally reachable.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionIPv4Default,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionIPv4Order,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionIPv4 = config.GetAsString(publicCfgOptionIPv4Key, publicCfgOptionIPv4Default)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"IPv6\",\n\t\tKey:             publicCfgOptionIPv6Key,\n\t\tDescription:     \"IPv6 address of this Hub. Must be globally reachable.\",\n\t\tOptType:         config.OptTypeString,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionIPv6Default,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionIPv6Order,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionIPv6 = config.GetAsString(publicCfgOptionIPv6Key, publicCfgOptionIPv6Default)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Transports\",\n\t\tKey:             publicCfgOptionTransportsKey,\n\t\tDescription:     \"List of transports this Hub supports.\",\n\t\tOptType:         config.OptTypeStringArray,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionTransportsDefault,\n\t\tValidationFunc: func(value any) error {\n\t\t\tif transports, ok := value.([]string); ok {\n\t\t\t\tfor i, transport := range transports {\n\t\t\t\t\tif _, err := hub.ParseTransport(transport); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to parse transport #%d: %w\", i, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"not a []string, but %T\", value)\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionTransportsOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionTransports = config.GetAsStringArray(publicCfgOptionTransportsKey, publicCfgOptionTransportsDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Entry\",\n\t\tKey:             publicCfgOptionEntryKey,\n\t\tDescription:     \"Define an entry policy. The format is the same for the endpoint lists. Default is permit.\",\n\t\tOptType:         config.OptTypeStringArray,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionEntryDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionEntryOrder,\n\t\t\tconfig.DisplayHintAnnotation:  endpoints.DisplayHintEndpointList,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionEntry = config.GetAsStringArray(publicCfgOptionEntryKey, publicCfgOptionEntryDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Exit\",\n\t\tKey:             publicCfgOptionExitKey,\n\t\tDescription:     \"Define an exit policy. The format is the same for the endpoint lists. Default is permit.\",\n\t\tOptType:         config.OptTypeStringArray,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionExitDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionExitOrder,\n\t\t\tconfig.DisplayHintAnnotation:  endpoints.DisplayHintEndpointList,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionExit = config.GetAsStringArray(publicCfgOptionExitKey, publicCfgOptionExitDefault)\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Allow Unencrypted Connections\",\n\t\tKey:             publicCfgOptionAllowUnencryptedKey,\n\t\tDescription:     \"Advertise that this Hub is available for handling unencrypted connections, as detected by clients.\",\n\t\tOptType:         config.OptTypeBool,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    publicCfgOptionAllowUnencryptedDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: publicCfgOptionAllowUnencryptedOrder,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tpublicCfgOptionAllowUnencrypted = config.GetAsBool(publicCfgOptionAllowUnencryptedKey, publicCfgOptionAllowUnencryptedDefault)\n\n\t// update defaults from system\n\tsetDynamicPublicDefaults()\n\n\treturn nil\n}\n\nfunc getPublicHubInfo() *hub.Announcement {\n\t// get configuration\n\tinfo := &hub.Announcement{\n\t\tName:           publicCfgOptionName(),\n\t\tGroup:          publicCfgOptionGroup(),\n\t\tContactAddress: publicCfgOptionContactAddress(),\n\t\tContactService: publicCfgOptionContactService(),\n\t\tHosters:        publicCfgOptionHosters(),\n\t\tDatacenter:     publicCfgOptionDatacenter(),\n\t\tTransports:     publicCfgOptionTransports(),\n\t\tEntry:          publicCfgOptionEntry(),\n\t\tExit:           publicCfgOptionExit(),\n\t\tFlags:          []string{},\n\t}\n\n\tif publicCfgOptionAllowUnencrypted() {\n\t\tinfo.Flags = append(info.Flags, hub.FlagAllowUnencrypted)\n\t}\n\n\tip4 := publicCfgOptionIPv4()\n\tif ip4 != \"\" {\n\t\tip := net.ParseIP(ip4)\n\t\tif ip == nil {\n\t\t\tlog.Warningf(\"spn/cabin: invalid %s config: %s\", publicCfgOptionIPv4Key, ip4)\n\t\t} else {\n\t\t\tinfo.IPv4 = ip\n\t\t}\n\t}\n\n\tip6 := publicCfgOptionIPv6()\n\tif ip6 != \"\" {\n\t\tip := net.ParseIP(ip6)\n\t\tif ip == nil {\n\t\t\tlog.Warningf(\"spn/cabin: invalid %s config: %s\", publicCfgOptionIPv6Key, ip6)\n\t\t} else {\n\t\t\tinfo.IPv6 = ip\n\t\t}\n\t}\n\n\treturn info\n}\n\nfunc setDynamicPublicDefaults() {\n\t// name\n\thostname, err := os.Hostname()\n\tif err == nil {\n\t\terr := config.SetDefaultConfigOption(publicCfgOptionNameKey, hostname)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/cabin: failed to set %s default to %s\", publicCfgOptionNameKey, hostname)\n\t\t}\n\t}\n\n\t// IPs\n\tv4IPs, v6IPs, err := netenv.GetAssignedGlobalAddresses()\n\tif err != nil {\n\t\tlog.Warningf(\"spn/cabin: failed to get assigned addresses: %s\", err)\n\t\treturn\n\t}\n\tif len(v4IPs) == 1 {\n\t\terr = config.SetDefaultConfigOption(publicCfgOptionIPv4Key, v4IPs[0].String())\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/cabin: failed to set %s default to %s\", publicCfgOptionIPv4Key, v4IPs[0].String())\n\t\t}\n\t}\n\tif len(v6IPs) == 1 {\n\t\terr = config.SetDefaultConfigOption(publicCfgOptionIPv6Key, v6IPs[0].String())\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/cabin: failed to set %s default to %s\", publicCfgOptionIPv6Key, v6IPs[0].String())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/cabin/database.go",
    "content": "package cabin\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nvar db = database.NewInterface(nil)\n\n// LoadIdentity loads an identify with the given key.\nfunc LoadIdentity(key string) (id *Identity, changed bool, err error) {\n\tr, err := db.Get(key)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\tid, err = EnsureIdentity(r)\n\tif err != nil {\n\t\treturn nil, false, fmt.Errorf(\"failed to parse identity: %w\", err)\n\t}\n\n\t// Check if required fields are present.\n\tswitch {\n\tcase id.Hub == nil:\n\t\treturn nil, false, errors.New(\"missing id.Hub\")\n\tcase id.Signet == nil:\n\t\treturn nil, false, errors.New(\"missing id.Signet\")\n\tcase id.Hub.Info == nil:\n\t\treturn nil, false, errors.New(\"missing hub.Info\")\n\tcase id.Hub.Status == nil:\n\t\treturn nil, false, errors.New(\"missing hub.Status\")\n\tcase id.ID != id.Hub.ID:\n\t\treturn nil, false, errors.New(\"hub.ID mismatch\")\n\tcase id.ID != id.Hub.Info.ID:\n\t\treturn nil, false, errors.New(\"hub.Info.ID mismatch\")\n\tcase id.Map == \"\":\n\t\treturn nil, false, errors.New(\"invalid id.Map\")\n\tcase id.Hub.Map == \"\":\n\t\treturn nil, false, errors.New(\"invalid hub.Map\")\n\tcase id.Hub.FirstSeen.IsZero():\n\t\treturn nil, false, errors.New(\"missing hub.FirstSeen\")\n\tcase id.Hub.Info.Timestamp == 0:\n\t\treturn nil, false, errors.New(\"missing hub.Info.Timestamp\")\n\tcase id.Hub.Status.Timestamp == 0:\n\t\treturn nil, false, errors.New(\"missing hub.Status.Timestamp\")\n\t}\n\n\t// Run a initial maintenance routine.\n\tinfoChanged, err := id.MaintainAnnouncement(nil, true)\n\tif err != nil {\n\t\treturn nil, false, fmt.Errorf(\"failed to initialize announcement: %w\", err)\n\t}\n\tstatusChanged, err := id.MaintainStatus(nil, nil, nil, true)\n\tif err != nil {\n\t\treturn nil, false, fmt.Errorf(\"failed to initialize status: %w\", err)\n\t}\n\n\t// Ensure the Measurements reset the values.\n\tmeasurements := id.Hub.GetMeasurements()\n\tmeasurements.SetLatency(0)\n\tmeasurements.SetCapacity(0)\n\tmeasurements.SetCalculatedCost(hub.MaxCalculatedCost)\n\n\treturn id, infoChanged || statusChanged, nil\n}\n\n// EnsureIdentity makes sure a database record is an Identity.\nfunc EnsureIdentity(r record.Record) (*Identity, error) {\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tid := &Identity{}\n\t\terr := record.Unwrap(r, id)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn id, nil\n\t}\n\n\t// or adjust type\n\tid, ok := r.(*Identity)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *Identity, but %T\", r)\n\t}\n\treturn id, nil\n}\n\n// Save saves the Identity to the database.\nfunc (id *Identity) Save() error {\n\tif !id.KeyIsSet() {\n\t\treturn errors.New(\"no key set\")\n\t}\n\n\treturn db.Put(id)\n}\n"
  },
  {
    "path": "spn/cabin/identity.go",
    "content": "package cabin\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/jess/tools\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nconst (\n\t// DefaultIDKeyScheme is the default jess tool for creating ID keys.\n\tDefaultIDKeyScheme = \"Ed25519\"\n\n\t// DefaultIDKeySecurityLevel is the default security level for creating ID keys.\n\tDefaultIDKeySecurityLevel = 256 // Ed25519 security level is fixed, setting is ignored.\n)\n\n// Identity holds the identity of a Hub.\ntype Identity struct {\n\trecord.Base\n\n\tID     string\n\tMap    string\n\tHub    *hub.Hub\n\tSignet *jess.Signet\n\n\tExchKeys map[string]*ExchKey\n\n\tinfoExportCache   []byte\n\tstatusExportCache []byte\n}\n\n// Lock locks the Identity through the Hub lock.\nfunc (id *Identity) Lock() {\n\tid.Hub.Lock()\n}\n\n// Unlock unlocks the Identity through the Hub lock.\nfunc (id *Identity) Unlock() {\n\tid.Hub.Unlock()\n}\n\n// ExchKey holds the private information of a HubKey.\ntype ExchKey struct {\n\tCreated time.Time\n\tExpires time.Time\n\tkey     *jess.Signet\n\ttool    *tools.Tool\n}\n\n// CreateIdentity creates a new identity.\nfunc CreateIdentity(ctx context.Context, mapName string) (*Identity, error) {\n\tid := &Identity{\n\t\tMap:      mapName,\n\t\tExchKeys: make(map[string]*ExchKey),\n\t}\n\n\t// create signet\n\tsignet, recipient, err := hub.CreateHubSignet(DefaultIDKeyScheme, DefaultIDKeySecurityLevel)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tid.Signet = signet\n\tid.ID = signet.ID\n\tid.Hub = &hub.Hub{\n\t\tID:        id.ID,\n\t\tMap:       mapName,\n\t\tPublicKey: recipient,\n\t}\n\n\t// initial maintenance routine\n\t_, err = id.MaintainAnnouncement(nil, true)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize announcement: %w\", err)\n\t}\n\t_, err = id.MaintainStatus([]*hub.Lane{}, new(int), nil, true)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize status: %w\", err)\n\t}\n\n\treturn id, nil\n}\n\n// MaintainAnnouncement maintains the Hub's Announcenemt and returns whether\n// there was a change that should be communicated to other Hubs.\n// If newInfo is nil, it will be derived from configuration.\nfunc (id *Identity) MaintainAnnouncement(newInfo *hub.Announcement, selfcheck bool) (changed bool, err error) {\n\tid.Lock()\n\tdefer id.Unlock()\n\n\t// Populate new info with data.\n\tif newInfo == nil {\n\t\tnewInfo = getPublicHubInfo()\n\t}\n\tnewInfo.ID = id.Hub.ID\n\tif id.Hub.Info != nil {\n\t\tnewInfo.Timestamp = id.Hub.Info.Timestamp\n\t}\n\tif !newInfo.Equal(id.Hub.Info) {\n\t\tchanged = true\n\t}\n\n\tif changed {\n\t\t// Update timestamp.\n\t\tnewInfo.Timestamp = time.Now().Unix()\n\t}\n\n\tif changed || selfcheck {\n\t\t// Export new data.\n\t\tnewInfoData, err := newInfo.Export(id.signingEnvelope())\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to export: %w\", err)\n\t\t}\n\n\t\t// Apply the status as all other Hubs would in order to check if it's valid.\n\t\t_, _, _, err = hub.ApplyAnnouncement(id.Hub, newInfoData, conf.MainMapName, conf.MainMapScope, true)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to apply new announcement: %w\", err)\n\t\t}\n\t\tid.infoExportCache = newInfoData\n\n\t\t// Save message to hub message storage.\n\t\terr = hub.SaveHubMsg(id.ID, conf.MainMapName, hub.MsgTypeAnnouncement, newInfoData)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/cabin: failed to save own new/updated announcement of %s: %s\", id.ID, err)\n\t\t}\n\t}\n\n\treturn changed, nil\n}\n\n// MaintainStatus maintains the Hub's Status and returns whether there was a change that should be communicated to other Hubs.\nfunc (id *Identity) MaintainStatus(lanes []*hub.Lane, load *int, flags []string, selfcheck bool) (changed bool, err error) {\n\tid.Lock()\n\tdefer id.Unlock()\n\n\t// Create a new status or make a copy of the status for editing.\n\tvar newStatus *hub.Status\n\tif id.Hub.Status != nil {\n\t\tnewStatus = id.Hub.Status.Copy()\n\t} else {\n\t\tnewStatus = &hub.Status{}\n\t}\n\n\t// Update software version.\n\tif newStatus.Version != info.Version() {\n\t\tnewStatus.Version = info.Version()\n\t\tchanged = true\n\t}\n\n\t// Update keys.\n\tkeysChanged, err := id.MaintainExchKeys(newStatus, time.Now())\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to maintain keys: %w\", err)\n\t}\n\tif keysChanged {\n\t\tchanged = true\n\t}\n\n\t// Update lanes.\n\tif lanes != nil && !hub.LanesEqual(newStatus.Lanes, lanes) {\n\t\tnewStatus.Lanes = lanes\n\t\tchanged = true\n\t}\n\n\t// Update load.\n\tif load != nil && newStatus.Load != *load {\n\t\tnewStatus.Load = *load\n\t\tchanged = true\n\t}\n\n\t// Update flags.\n\tif !hub.FlagsEqual(newStatus.Flags, flags) {\n\t\tnewStatus.Flags = flags\n\t\tchanged = true\n\t}\n\n\t// Update timestamp if something changed.\n\tif changed {\n\t\tnewStatus.Timestamp = time.Now().Unix()\n\t}\n\n\tif changed || selfcheck {\n\t\t// Export new data.\n\t\tnewStatusData, err := newStatus.Export(id.signingEnvelope())\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to export: %w\", err)\n\t\t}\n\n\t\t// Apply the status as all other Hubs would in order to check if it's valid.\n\t\t_, _, _, err = hub.ApplyStatus(id.Hub, newStatusData, conf.MainMapName, conf.MainMapScope, true)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to apply new status: %w\", err)\n\t\t}\n\t\tid.statusExportCache = newStatusData\n\n\t\t// Save message to hub message storage.\n\t\terr = hub.SaveHubMsg(id.ID, conf.MainMapName, hub.MsgTypeStatus, newStatusData)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/cabin: failed to save own new/updated status: %s\", err)\n\t\t}\n\t}\n\n\treturn changed, nil\n}\n\n// MakeOfflineStatus creates and signs an offline status message.\nfunc (id *Identity) MakeOfflineStatus() (offlineStatusExport []byte, err error) {\n\t// Make offline status.\n\tnewStatus := &hub.Status{\n\t\tTimestamp: time.Now().Unix(),\n\t\tVersion:   info.Version(),\n\t\tFlags:     []string{hub.FlagOffline},\n\t}\n\n\t// Export new data.\n\tnewStatusData, err := newStatus.Export(id.signingEnvelope())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to export: %w\", err)\n\t}\n\n\treturn newStatusData, nil\n}\n\nfunc (id *Identity) signingEnvelope() *jess.Envelope {\n\tenv := jess.NewUnconfiguredEnvelope()\n\tenv.SuiteID = jess.SuiteSignV1\n\tenv.Senders = []*jess.Signet{id.Signet}\n\n\treturn env\n}\n\n// ExportAnnouncement serializes and signs the Announcement.\nfunc (id *Identity) ExportAnnouncement() ([]byte, error) {\n\tid.Lock()\n\tdefer id.Unlock()\n\n\tif id.infoExportCache == nil {\n\t\treturn nil, errors.New(\"announcement not exported\")\n\t}\n\n\treturn id.infoExportCache, nil\n}\n\n// ExportStatus serializes and signs the Status.\nfunc (id *Identity) ExportStatus() ([]byte, error) {\n\tid.Lock()\n\tdefer id.Unlock()\n\n\tif id.statusExportCache == nil {\n\t\treturn nil, errors.New(\"status not exported\")\n\t}\n\n\treturn id.statusExportCache, nil\n}\n\n// SignHubMsg signs a data blob with the identity's private key.\nfunc (id *Identity) SignHubMsg(data []byte) ([]byte, error) {\n\treturn hub.SignHubMsg(data, id.signingEnvelope(), false)\n}\n\n// GetSignet returns the private exchange key with the given ID.\nfunc (id *Identity) GetSignet(keyID string, recipient bool) (*jess.Signet, error) {\n\tif recipient {\n\t\treturn nil, errors.New(\"cabin.Identity only serves private keys\")\n\t}\n\n\tid.Lock()\n\tdefer id.Unlock()\n\n\tkey, ok := id.ExchKeys[keyID]\n\tif !ok {\n\t\treturn nil, errors.New(\"the requested key does not exist\")\n\t}\n\tif time.Now().After(key.Expires) || key.key == nil {\n\t\treturn nil, errors.New(\"the requested key has expired\")\n\t}\n\n\treturn key.key, nil\n}\n\nfunc (ek *ExchKey) toHubKey() (*hub.Key, error) {\n\tif ek.key == nil {\n\t\treturn nil, errors.New(\"no key\")\n\t}\n\n\t// export public key\n\trcpt, err := ek.key.AsRecipient()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = rcpt.StoreKey()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// repackage\n\treturn &hub.Key{\n\t\tScheme:  rcpt.Scheme,\n\t\tKey:     rcpt.Key,\n\t\tExpires: ek.Expires.Unix(),\n\t}, nil\n}\n"
  },
  {
    "path": "spn/cabin/identity_test.go",
    "content": "package cabin\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nfunc TestIdentity(t *testing.T) {\n\tt.Parallel()\n\n\t// Register config options for public hub.\n\tif err := prepPublicHubConfig(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Create new identity.\n\tidentityTestKey := \"core:spn/public/identity-test\"\n\tid, err := CreateIdentity(module.m.Ctx(), conf.MainMapName)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tid.SetKey(identityTestKey)\n\n\t// Check values\n\t// Identity\n\tassert.NotEmpty(t, id.ID, \"id.ID must be set\")\n\tassert.NotEmpty(t, id.Map, \"id.Map must be set\")\n\tassert.NotNil(t, id.Signet, \"id.Signet must be set\")\n\tassert.NotNil(t, id.infoExportCache, \"id.infoExportCache must be set\")\n\tassert.NotNil(t, id.statusExportCache, \"id.statusExportCache must be set\")\n\t// Hub\n\tassert.NotEmpty(t, id.Hub.ID, \"hub.ID must be set\")\n\tassert.NotEmpty(t, id.Hub.Map, \"hub.Map must be set\")\n\tassert.NotZero(t, id.Hub.FirstSeen, \"hub.FirstSeen must be set\")\n\t// Info\n\tassert.NotEmpty(t, id.Hub.Info.ID, \"info.ID must be set\")\n\tassert.NotEqual(t, 0, id.Hub.Info.Timestamp, \"info.Timestamp must be set\")\n\tassert.NotEqual(t, \"\", id.Hub.Info.Name, \"info.Name must be set (to hostname)\")\n\t// Status\n\tassert.NotEqual(t, 0, id.Hub.Status.Timestamp, \"status.Timestamp must be set\")\n\tassert.NotEmpty(t, id.Hub.Status.Keys, \"status.Keys must be set\")\n\n\tfmt.Printf(\"id: %+v\\n\", id)\n\tfmt.Printf(\"id.hub: %+v\\n\", id.Hub)\n\tfmt.Printf(\"id.Hub.Info: %+v\\n\", id.Hub.Info)\n\tfmt.Printf(\"id.Hub.Status: %+v\\n\", id.Hub.Status)\n\n\t// Maintenance is run in creation, so nothing should change now.\n\tchanged, err := id.MaintainAnnouncement(nil, false)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif changed {\n\t\tt.Error(\"unexpected change of announcement\")\n\t}\n\tchanged, err = id.MaintainStatus(nil, nil, nil, false)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif changed {\n\t\tt.Error(\"unexpected change of status\")\n\t}\n\n\t// Change lanes.\n\tlanes := []*hub.Lane{\n\t\t{\n\t\t\tID:       \"A\",\n\t\t\tCapacity: 1,\n\t\t\tLatency:  2,\n\t\t},\n\t\t{\n\t\t\tID:       \"B\",\n\t\t\tCapacity: 3,\n\t\t\tLatency:  4,\n\t\t},\n\t\t{\n\t\t\tID:       \"C\",\n\t\t\tCapacity: 5,\n\t\t\tLatency:  6,\n\t\t},\n\t}\n\tchanged, err = id.MaintainStatus(lanes, new(int), nil, false)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !changed {\n\t\tt.Error(\"status should have changed\")\n\t}\n\n\t// Change nothing.\n\tchanged, err = id.MaintainStatus(lanes, new(int), nil, false)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif changed {\n\t\tt.Error(\"unexpected change of status\")\n\t}\n\n\t// Exporting\n\t_, err = id.ExportAnnouncement()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\t_, err = id.ExportStatus()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Ensure the Measurements reset the values.\n\tmeasurements := id.Hub.GetMeasurements()\n\tmeasurements.SetLatency(0)\n\tmeasurements.SetCapacity(0)\n\tmeasurements.SetCalculatedCost(hub.MaxCalculatedCost)\n\n\t// Save to and load from database.\n\terr = id.Save()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tid2, _, err := LoadIdentity(identityTestKey)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Reset everything that should not be compared.\n\tid.infoExportCache = nil\n\tid2.infoExportCache = nil\n\tid.statusExportCache = nil\n\tid2.statusExportCache = nil\n\tid.ExchKeys = nil\n\tid2.ExchKeys = nil\n\tid.Hub.Status = nil\n\tid2.Hub.Status = nil\n\tid.Hub.PublicKey = nil\n\tid2.Hub.PublicKey = nil\n\n\t// Check important aspects of the identities.\n\tassert.Equal(t, id.ID, id2.ID, \"identity IDs must be equal\")\n\tassert.Equal(t, id.Map, id2.Map, \"identity Maps should be equal\")\n\tassert.Equal(t, id.Hub, id2.Hub, \"identity Hubs should be equal\")\n\tassert.Equal(t, id.Signet, id2.Signet, \"identity Signets should be equal\")\n}\n"
  },
  {
    "path": "spn/cabin/keys.go",
    "content": "package cabin\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/jess/tools\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\ntype providedExchKeyScheme struct {\n\tid            string\n\tsecurityLevel int //nolint:structcheck // TODO\n\ttool          *tools.Tool\n}\n\nvar (\n\t// validFor defines how long keys are valid for use by clients.\n\tvalidFor = 48 * time.Hour // 2 days\n\t// renewBeforeExpiry defines the duration how long before expiry keys should be renewed.\n\trenewBeforeExpiry = 24 * time.Hour // 1 day\n\n\t// burnAfter defines how long after expiry keys are burnt/deleted.\n\tburnAfter = 12 * time.Hour // 1/2 day\n\t// reuseAfter defines how long IDs should be blocked after expiry (and not be reused for new keys).\n\treuseAfter = 2 * 7 * 24 * time.Hour // 2 weeks\n\n\t// provideExchKeySchemes defines the jess tools for creating exchange keys.\n\tprovideExchKeySchemes = []*providedExchKeyScheme{\n\t\t{\n\t\t\tid:            \"ECDH-X25519\",\n\t\t\tsecurityLevel: 128, // informative only, security level of ECDH-X25519 is fixed\n\t\t},\n\t\t// TODO: test with rsa keys\n\t}\n)\n\nfunc initProvidedExchKeySchemes() error {\n\tfor _, eks := range provideExchKeySchemes {\n\t\ttool, err := tools.Get(eks.id)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\teks.tool = tool\n\t}\n\treturn nil\n}\n\n// MaintainExchKeys maintains the exchange keys, creating new ones and\n// deprecating and deleting old ones.\nfunc (id *Identity) MaintainExchKeys(newStatus *hub.Status, now time.Time) (changed bool, err error) {\n\t// create Keys map\n\tif id.ExchKeys == nil {\n\t\tid.ExchKeys = make(map[string]*ExchKey)\n\t}\n\n\t// lifecycle management\n\tfor keyID, exchKey := range id.ExchKeys {\n\t\tif exchKey.key != nil && now.After(exchKey.Expires.Add(burnAfter)) {\n\t\t\t// delete key\n\t\t\terr := exchKey.tool.StaticLogic.BurnKey(exchKey.key)\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\n\t\t\t\t\t\"spn/cabin: failed to burn key %s (%s) of %s: %s\",\n\t\t\t\t\tkeyID,\n\t\t\t\t\texchKey.tool.Info.Name,\n\t\t\t\t\tid.Hub.ID,\n\t\t\t\t\terr,\n\t\t\t\t)\n\t\t\t}\n\t\t\t// remove reference\n\t\t\texchKey.key = nil\n\t\t}\n\t\tif now.After(exchKey.Expires.Add(reuseAfter)) {\n\t\t\t// remove key\n\t\t\tdelete(id.ExchKeys, keyID)\n\t\t}\n\t}\n\n\t// find or create current keys\n\tfor _, eks := range provideExchKeySchemes {\n\t\tfound := false\n\t\tfor _, exchKey := range id.ExchKeys {\n\t\t\tif exchKey.key != nil &&\n\t\t\t\texchKey.key.Scheme == eks.id &&\n\t\t\t\tnow.Before(exchKey.Expires.Add(-renewBeforeExpiry)) {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !found {\n\t\t\terr := id.createExchKey(eks, now)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"failed to create %s exchange key: %w\", eks.tool.Info.Name, err)\n\t\t\t}\n\t\t\tchanged = true\n\t\t}\n\t}\n\n\t// export most recent keys to HubStatus\n\tif changed || len(newStatus.Keys) == 0 {\n\t\t// reset\n\t\tnewStatus.Keys = make(map[string]*hub.Key)\n\n\t\t// find longest valid key for every provided scheme\n\t\tfor _, eks := range provideExchKeySchemes {\n\t\t\t// find key of scheme that is valid the longest\n\t\t\tlongestValid := &ExchKey{\n\t\t\t\tExpires: now,\n\t\t\t}\n\t\t\tfor _, exchKey := range id.ExchKeys {\n\t\t\t\tif exchKey.key != nil &&\n\t\t\t\t\texchKey.key.Scheme == eks.id &&\n\t\t\t\t\texchKey.Expires.After(longestValid.Expires) {\n\t\t\t\t\tlongestValid = exchKey\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// check result\n\t\t\tif longestValid.key == nil {\n\t\t\t\tlog.Warningf(\"spn/cabin: could not find export candidate for exchange key scheme %s\", eks.id)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// export\n\t\t\thubKey, err := longestValid.toHubKey()\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"failed to export %s exchange key: %w\", longestValid.tool.Info.Name, err)\n\t\t\t}\n\t\t\t// add\n\t\t\tnewStatus.Keys[longestValid.key.ID] = hubKey\n\t\t}\n\t}\n\n\treturn changed, nil\n}\n\nfunc (id *Identity) createExchKey(eks *providedExchKeyScheme, now time.Time) error {\n\t// get ID\n\tvar keyID string\n\tfor range 1000000 { // not forever\n\t\t// generate new ID\n\t\tb, err := rng.Bytes(3)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get random data for key ID: %w\", err)\n\t\t}\n\t\tkeyID = base64.RawURLEncoding.EncodeToString(b)\n\t\t_, exists := id.ExchKeys[keyID]\n\t\tif !exists {\n\t\t\tbreak\n\t\t}\n\t}\n\tif keyID == \"\" {\n\t\treturn errors.New(\"unable to find available exchange key ID\")\n\t}\n\n\t// generate key\n\tsignet := jess.NewSignetBase(eks.tool)\n\tsignet.ID = keyID\n\t// TODO: use security level for key generation\n\tif err := signet.GenerateKey(); err != nil {\n\t\treturn fmt.Errorf(\"failed to get new exchange key: %w\", err)\n\t}\n\n\t// add to key map\n\tid.ExchKeys[keyID] = &ExchKey{\n\t\tCreated: now,\n\t\tExpires: now.Add(validFor),\n\t\tkey:     signet,\n\t\ttool:    eks.tool,\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "spn/cabin/keys_test.go",
    "content": "package cabin\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\nfunc TestKeyMaintenance(t *testing.T) {\n\tt.Parallel()\n\n\tid, err := CreateIdentity(module.m.Ctx(), conf.MainMapName)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\titerations := 1000\n\tchangeCnt := 0\n\n\tnow := time.Now()\n\tfor range iterations {\n\t\tchanged, err := id.MaintainExchKeys(id.Hub.Status, now)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\tif changed {\n\t\t\tchangeCnt++\n\t\t\tt.Logf(\"===== exchange keys updated at %s:\\n\", now)\n\t\t\tfor keyID, exchKey := range id.ExchKeys {\n\t\t\t\tt.Logf(\"[%s] %s %v\\n\", exchKey.Created, keyID, exchKey.key)\n\t\t\t}\n\t\t}\n\t\tnow = now.Add(1 * time.Hour)\n\t}\n\n\tif iterations/changeCnt > 25 { // one new key every 24 hours/ticks\n\t\tt.Fatal(\"more changes than expected\")\n\t}\n\tif len(id.ExchKeys) > 17 { // one new key every day for two weeks + 3 in use\n\t\tt.Fatal(\"more keys than expected\")\n\t}\n}\n"
  },
  {
    "path": "spn/cabin/module.go",
    "content": "package cabin\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype Cabin struct {\n\tm        *mgr.Manager\n\tinstance instance\n}\n\nfunc (c *Cabin) Manager() *mgr.Manager {\n\treturn c.m\n}\n\nfunc (c *Cabin) Start() error {\n\treturn nil\n}\n\nfunc (c *Cabin) Stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *Cabin\n\tshimLoaded atomic.Bool\n)\n\nfunc prep() error {\n\tif err := initProvidedExchKeySchemes(); err != nil {\n\t\treturn err\n\t}\n\n\tif conf.PublicHub() {\n\t\tif err := prepPublicHubConfig(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// New returns a new Cabin module.\nfunc New(instance instance) (*Cabin, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\n\tm := mgr.New(\"Cabin\")\n\tmodule = &Cabin{\n\t\tm:        m,\n\t\tinstance: instance,\n\t}\n\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/cabin/module_test.go",
    "content": "package cabin\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype testInstance struct {\n\tdb     *dbmodule.DBModule\n\tapi    *api.API\n\tconfig *config.Config\n\trng    *rng.Rng\n\tbase   *base.Base\n}\n\nfunc (stub *testInstance) Config() *config.Config             { return stub.config }\nfunc (stub *testInstance) SPNGroup() *mgr.ExtendedGroup       { return nil }\nfunc (stub *testInstance) Stopping() bool                     { return false }\nfunc (stub *testInstance) Ready() bool                        { return true }\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\nfunc (stub *testInstance) DataDir() string                    { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tapi.SetDefaultAPIListenAddress(\"0.0.0.0:8080\")\n\tvar err error\n\t// Create a temporary directory for the data\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to initialize dataroot: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Init\n\tinstance := &testInstance{}\n\tinstance.db, err = dbmodule.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database: %w\", err)\n\t}\n\tinstance.api, err = api.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create api: %w\", err)\n\t}\n\tinstance.config, err = config.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config module: %w\", err)\n\t}\n\tinstance.rng, err = rng.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create rng module: %w\", err)\n\t}\n\tinstance.base, err = base.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create base module: %w\", err)\n\t}\n\tmodule, err = New(struct{}{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create cabin module: %w\", err)\n\t}\n\t// Start\n\terr = instance.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start database: %w\", err)\n\t}\n\terr = instance.api.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start api: %w\", err)\n\t}\n\terr = instance.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start config module: %w\", err)\n\t}\n\terr = instance.rng.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start rng module: %w\", err)\n\t}\n\terr = instance.base.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start base module: %w\", err)\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start cabin module: %w\", err)\n\t}\n\tconf.EnablePublicHub(true)\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "spn/cabin/verification.go",
    "content": "package cabin\n\nimport (\n\t\"crypto/subtle\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nvar (\n\tverificationChallengeSize    = 32\n\tverificationChallengeMinSize = 16\n\tverificationSigningSuite     = jess.SuiteSignV1\n\tverificationRequirements     = jess.NewRequirements().\n\t\t\t\t\tRemove(jess.Confidentiality).\n\t\t\t\t\tRemove(jess.Integrity).\n\t\t\t\t\tRemove(jess.RecipientAuthentication)\n)\n\n// Verification is used to verify certain aspects of another Hub.\ntype Verification struct {\n\t// Challenge is a random value chosen by the client.\n\tChallenge []byte `json:\"c\"`\n\t// Purpose defines the purpose of the verification. Protects against using verification for other purposes.\n\tPurpose string `json:\"p\"`\n\t// ClientReference is an optional field for exchanging metadata about the client. Protects against forwarding/relay attacks.\n\tClientReference string `json:\"cr\"`\n\t// ServerReference is an optional field for exchanging metadata about the server. Protects against forwarding/relay attacks.\n\tServerReference string `json:\"sr\"`\n}\n\n// CreateVerificationRequest creates a new verification request with the given\n// purpose and references.\nfunc CreateVerificationRequest(purpose, clientReference, serverReference string) (v *Verification, request []byte, err error) {\n\t// Generate random challenge.\n\tchallenge, err := rng.Bytes(verificationChallengeSize)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to generate challenge: %w\", err)\n\t}\n\n\t// Create verification object.\n\tv = &Verification{\n\t\tPurpose:         purpose,\n\t\tClientReference: clientReference,\n\t\tChallenge:       challenge,\n\t}\n\n\t// Serialize verification.\n\trequest, err = dsd.Dump(v, dsd.JSON)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to serialize verification request: %w\", err)\n\t}\n\n\t// The server reference is not sent to the server, but needs to be supplied\n\t// by the server.\n\tv.ServerReference = serverReference\n\n\treturn v, request, nil\n}\n\n// SignVerificationRequest sign a verification request.\n// The purpose and references must match the request, else the verification\n// will fail.\nfunc (id *Identity) SignVerificationRequest(request []byte, purpose, clientReference, serverReference string) (response []byte, err error) {\n\t// Parse request.\n\tv := new(Verification)\n\t_, err = dsd.Load(request, v)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse request: %w\", err)\n\t}\n\n\t// Validate request.\n\tif len(v.Challenge) < verificationChallengeMinSize {\n\t\treturn nil, errors.New(\"challenge too small\")\n\t}\n\tif v.Purpose != purpose {\n\t\treturn nil, errors.New(\"purpose mismatch\")\n\t}\n\tif v.ClientReference != clientReference {\n\t\treturn nil, errors.New(\"client reference mismatch\")\n\t}\n\n\t// Assign server reference and serialize.\n\tv.ServerReference = serverReference\n\tdataToSign, err := dsd.Dump(v, dsd.JSON)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to serialize verification response: %w\", err)\n\t}\n\n\t// Sign response.\n\te := jess.NewUnconfiguredEnvelope()\n\te.SuiteID = verificationSigningSuite\n\te.Senders = []*jess.Signet{id.Signet}\n\tjession, err := e.Correspondence(nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to setup signer: %w\", err)\n\t}\n\tletter, err := jession.Close(dataToSign)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to sign: %w\", err)\n\t}\n\n\t// Serialize and return.\n\tsignedResponse, err := letter.ToDSD(dsd.JSON)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to serialize letter: %w\", err)\n\t}\n\n\treturn signedResponse, nil\n}\n\n// Verify verifies the verification response and checks if everything is valid.\nfunc (v *Verification) Verify(response []byte, h *hub.Hub) error {\n\t// Parse response.\n\tletter, err := jess.LetterFromDSD(response)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse response: %w\", err)\n\t}\n\n\t// Verify response.\n\tresponseData, err := letter.Open(\n\t\tverificationRequirements,\n\t\t&hub.SingleTrustStore{\n\t\t\tSignet: h.PublicKey,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to verify response: %w\", err)\n\t}\n\n\t// Parse verified response.\n\tresponseV := new(Verification)\n\t_, err = dsd.Load(responseData, responseV)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse verified response: %w\", err)\n\t}\n\n\t// Validate request.\n\tif subtle.ConstantTimeCompare(v.Challenge, responseV.Challenge) != 1 {\n\t\treturn errors.New(\"challenge mismatch\")\n\t}\n\tif subtle.ConstantTimeCompare([]byte(v.Purpose), []byte(responseV.Purpose)) != 1 {\n\t\treturn errors.New(\"purpose mismatch\")\n\t}\n\tif subtle.ConstantTimeCompare([]byte(v.ClientReference), []byte(responseV.ClientReference)) != 1 {\n\t\treturn errors.New(\"client reference mismatch\")\n\t}\n\tif subtle.ConstantTimeCompare([]byte(v.ServerReference), []byte(responseV.ServerReference)) != 1 {\n\t\treturn errors.New(\"server reference mismatch\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/cabin/verification_test.go",
    "content": "package cabin\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestVerification(t *testing.T) {\n\tt.Parallel()\n\n\tid, err := CreateIdentity(module.m.Ctx(), \"test\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"a\", \"b\", \"c\",\n\t\t\"\", \"\", \"\", nil,\n\t); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"x\", \"b\", \"c\",\n\t\t\"\", \"\", \"\", nil,\n\t); err == nil {\n\t\tt.Fatal(\"should fail on purpose mismatch\")\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"a\", \"x\", \"c\",\n\t\t\"\", \"\", \"\", nil,\n\t); err == nil {\n\t\tt.Fatal(\"should fail on client ref mismatch\")\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"a\", \"b\", \"x\",\n\t\t\"\", \"\", \"\", nil,\n\t); err == nil {\n\t\tt.Fatal(\"should fail on server ref mismatch\")\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"a\", \"b\", \"c\",\n\t\t\"x\", \"\", \"\", nil,\n\t); err == nil {\n\t\tt.Fatal(\"should fail on purpose mismatch\")\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"a\", \"b\", \"c\",\n\t\t\"\", \"x\", \"\", nil,\n\t); err == nil {\n\t\tt.Fatal(\"should fail on client ref mismatch\")\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"a\", \"b\", \"c\",\n\t\t\"\", \"\", \"x\", nil,\n\t); err == nil {\n\t\tt.Fatal(\"should fail on server ref mismatch\")\n\t}\n\n\tif err := testVerificationWith(\n\t\tt, id,\n\t\t\"a\", \"b\", \"c\",\n\t\t\"a\", \"b\", \"c\",\n\t\t\"\", \"\", \"\", []byte{1, 2, 3, 4},\n\t); err == nil {\n\t\tt.Fatal(\"should fail on challenge mismatch\")\n\t}\n}\n\nfunc testVerificationWith(\n\tt *testing.T, id *Identity,\n\tpurpose1, clientRef1, serverRef1 string, //nolint:unparam\n\tpurpose2, clientRef2, serverRef2 string,\n\tmitmPurpose, mitmClientRef, mitmServerRef string,\n\tmitmChallenge []byte,\n) error {\n\tt.Helper()\n\n\tv, request, err := CreateVerificationRequest(purpose1, clientRef1, serverRef1)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create verification request: %w\", err)\n\t}\n\n\tresponse, err := id.SignVerificationRequest(request, purpose2, clientRef2, serverRef2)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to sign verification response: %w\", err)\n\t}\n\n\tif mitmPurpose != \"\" {\n\t\tv.Purpose = mitmPurpose\n\t}\n\tif mitmClientRef != \"\" {\n\t\tv.ClientReference = mitmClientRef\n\t}\n\tif mitmServerRef != \"\" {\n\t\tv.ServerReference = mitmServerRef\n\t}\n\tif mitmChallenge != nil {\n\t\tv.Challenge = mitmChallenge\n\t}\n\n\terr = v.Verify(response, id.Hub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to verify: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/captain/api.go",
    "content": "package captain\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\nconst (\n\tapiPathForSPNReInit = \"spn/reinit\"\n)\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        apiPathForSPNReInit,\n\t\tWrite:       api.PermitAdmin,\n\t\tActionFunc:  handleReInit,\n\t\tName:        \"Re-initialize SPN\",\n\t\tDescription: \"Stops the SPN, resets all caches and starts it again. The SPN account and settings are not changed.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleReInit(ar *api.Request) (msg string, err error) {\n\tif !conf.Client() && !conf.Integrated() {\n\t\treturn \"\", fmt.Errorf(\"re-initialization only possible on integrated clients\")\n\t}\n\n\t// Make sure SPN is stopped and wait for it to complete.\n\terr = module.mgr.DoAsStopWorker(\"stop SPN for re-init\", module.instance.SPNGroup().EnsureStoppedWorker)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to stop SPN for re-init: %w\", err)\n\t}\n\n\t// Delete SPN cache.\n\tdb := database.NewInterface(&database.Options{\n\t\tLocal:    true,\n\t\tInternal: true,\n\t})\n\tdeletedRecords, err := db.Purge(ar.Context(), query.New(\"cache:spn/\"))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to delete SPN cache: %w\", err)\n\t}\n\n\t// Start SPN if it is enabled.\n\tenabled := config.GetAsBool(\"spn/enable\", false)\n\tif enabled() {\n\t\tmodule.mgr.Go(\"ensure SPN is started\", module.instance.SPNGroup().EnsureStartedWorker)\n\t}\n\n\treturn fmt.Sprintf(\n\t\t\"Completed SPN re-initialization and deleted %d cache records in the process.\",\n\t\tdeletedRecords,\n\t), nil\n}\n"
  },
  {
    "path": "spn/captain/bootstrap.go",
    "content": "package captain\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// BootstrapFile is used for sideloading bootstrap data.\ntype BootstrapFile struct {\n\tMain BootstrapFileEntry\n}\n\n// BootstrapFileEntry is the bootstrap data structure for one map.\ntype BootstrapFileEntry struct {\n\tHubs []string\n}\n\nvar (\n\tbootstrapHubFlag  string\n\tbootstrapFileFlag string\n)\n\nfunc init() {\n\tflag.StringVar(&bootstrapHubFlag, \"bootstrap-hub\", \"\", \"transport address of hub for bootstrapping with the hub ID in the fragment\")\n\tflag.StringVar(&bootstrapFileFlag, \"bootstrap-file\", \"\", \"bootstrap file containing bootstrap hubs - will be initialized if running a public hub and it doesn't exist\")\n}\n\n// prepBootstrapHubFlag checks the bootstrap-hub argument if it is valid.\nfunc prepBootstrapHubFlag() error {\n\tif bootstrapHubFlag != \"\" {\n\t\t_, _, _, err := hub.ParseBootstrapHub(bootstrapHubFlag)\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// processBootstrapHubFlag processes the bootstrap-hub argument.\nfunc processBootstrapHubFlag() error {\n\tif bootstrapHubFlag != \"\" {\n\t\treturn navigator.Main.AddBootstrapHubs([]string{bootstrapHubFlag})\n\t}\n\treturn nil\n}\n\n// processBootstrapFileFlag processes the bootstrap-file argument.\nfunc processBootstrapFileFlag() error {\n\tif bootstrapFileFlag == \"\" {\n\t\treturn nil\n\t}\n\n\t_, err := os.Stat(bootstrapFileFlag)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn createBootstrapFile(bootstrapFileFlag)\n\t\t}\n\t\treturn fmt.Errorf(\"failed to access bootstrap hub file: %w\", err)\n\t}\n\n\treturn loadBootstrapFile(bootstrapFileFlag)\n}\n\n// bootstrapWithUpdates loads bootstrap hubs from the updates server and imports them.\nfunc bootstrapWithUpdates() error {\n\tif bootstrapFileFlag != \"\" {\n\t\treturn errors.New(\"using the bootstrap-file argument disables bootstrapping via the update system\")\n\t}\n\n\treturn updateSPNIntel(module.mgr.Ctx(), nil)\n}\n\n// loadBootstrapFile loads a file with bootstrap hub entries and imports them.\nfunc loadBootstrapFile(filename string) (err error) {\n\t// Load bootstrap file from disk and parse it.\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to load bootstrap file: %w\", err)\n\t}\n\tbootstrapFile := &BootstrapFile{}\n\t_, err = dsd.Load(data, bootstrapFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse bootstrap file: %w\", err)\n\t}\n\tif len(bootstrapFile.Main.Hubs) == 0 {\n\t\treturn errors.New(\"bootstrap holds no hubs for main map\")\n\t}\n\n\t// Add Hubs to map.\n\terr = navigator.Main.AddBootstrapHubs(bootstrapFile.Main.Hubs)\n\tif err == nil {\n\t\tlog.Infof(\"spn/captain: loaded bootstrap file %s\", filename)\n\t}\n\treturn err\n}\n\n// createBootstrapFile save a bootstrap hub file with an entry of the public identity.\nfunc createBootstrapFile(filename string) error {\n\tif !conf.PublicHub() {\n\t\tlog.Infof(\"spn/captain: skipped writing a bootstrap hub file, as this is not a public hub\")\n\t\treturn nil\n\t}\n\n\t// create bootstrap hub\n\tif len(publicIdentity.Hub.Info.Transports) == 0 {\n\t\treturn errors.New(\"public identity has no transports available\")\n\t}\n\t// parse first transport\n\tt, err := hub.ParseTransport(publicIdentity.Hub.Info.Transports[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse transport of public identity: %w\", err)\n\t}\n\t// add IP address\n\tswitch {\n\tcase publicIdentity.Hub.Info.IPv4 != nil:\n\t\tt.Domain = publicIdentity.Hub.Info.IPv4.String()\n\tcase publicIdentity.Hub.Info.IPv6 != nil:\n\t\tt.Domain = \"[\" + publicIdentity.Hub.Info.IPv6.String() + \"]\"\n\tdefault:\n\t\treturn errors.New(\"public identity has no IP address available\")\n\t}\n\t// add Hub ID\n\tt.Option = publicIdentity.Hub.ID\n\t// put together\n\tbs := &BootstrapFile{\n\t\tMain: BootstrapFileEntry{\n\t\t\tHubs: []string{t.String()},\n\t\t},\n\t}\n\n\t// serialize\n\tfileData, err := dsd.Dump(bs, dsd.JSON)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// save to disk\n\terr = os.WriteFile(filename, fileData, 0o0664) //nolint:gosec // Should be able to be read by others.\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Infof(\"spn/captain: created bootstrap file %s\", filename)\n\treturn nil\n}\n"
  },
  {
    "path": "spn/captain/client.go",
    "content": "package captain\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/crew\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nvar (\n\tready = abool.New()\n\n\tspnLoginButton = notifications.Action{\n\t\tText:    \"Login\",\n\t\tType:    notifications.ActionTypeOpenPage,\n\t\tPayload: \"spn\",\n\t}\n\tspnOpenAccountPage = notifications.Action{\n\t\tText:    \"Open Account Page\",\n\t\tType:    notifications.ActionTypeOpenURL,\n\t\tPayload: \"https://account.safing.io\",\n\t}\n)\n\n// ClientReady signifies if the SPN client is fully ready to handle connections.\nfunc ClientReady() bool {\n\treturn ready.IsSet()\n}\n\ntype (\n\tclientComponentFunc   func(ctx *mgr.WorkerCtx) clientComponentResult\n\tclientComponentResult uint8\n)\n\nconst (\n\tclientResultOk        clientComponentResult = iota // Continue and clean module status.\n\tclientResultRetry                                  // Go back to start of current step, don't clear module status.\n\tclientResultReconnect                              // Stop current connection and start from zero.\n\tclientResultShutdown                               // SPN Module is shutting down.\n)\n\nvar (\n\tclientNetworkChangedFlag               = netenv.GetNetworkChangedFlag()\n\tclientIneligibleAccountUpdateDelay     = 1 * time.Minute\n\tclientRetryConnectBackoffDuration      = 5 * time.Second\n\tclientInitialHealthCheckDelay          = 10 * time.Second\n\tclientHealthCheckTickDuration          = 1 * time.Minute\n\tclientHealthCheckTickDurationSleepMode = 5 * time.Minute\n\tclientHealthCheckTimeout               = 15 * time.Second\n\n\tclientHealthCheckTrigger = make(chan struct{}, 1)\n\tlastHealthCheck          time.Time\n)\n\nfunc triggerClientHealthCheck() {\n\tselect {\n\tcase clientHealthCheckTrigger <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc clientManager(ctx *mgr.WorkerCtx) error {\n\tdefer func() {\n\t\tready.UnSet()\n\t\tnetenv.ConnectedToSPN.UnSet()\n\t\tresetSPNStatus(StatusDisabled, true)\n\t\tmodule.states.Clear()\n\t\tclientStopHomeHub(ctx)\n\t}()\n\n\tmodule.states.Add(mgr.State{\n\t\tID:      \"spn:establishing-home-hub\",\n\t\tName:    \"Connecting to SPN...\",\n\t\tMessage: \"Connecting to the SPN network is in progress.\",\n\t\tType:    mgr.StateTypeHint,\n\t})\n\n\t// TODO: When we are starting and the SPN module is faster online than the\n\t// nameserver, then updating the account will fail as the DNS query is\n\t// redirected to a closed port.\n\t// We also can't add the nameserver as a module dependency, as the nameserver\n\t// is not part of the server.\n\tselect {\n\tcase <-time.After(1 * time.Second):\n\tcase <-ctx.Done():\n\t\treturn nil\n\t}\n\n\tmodule.healthCheckTicker = mgr.NewSleepyTicker(clientHealthCheckTickDuration, clientHealthCheckTickDurationSleepMode)\n\tdefer module.healthCheckTicker.Stop()\n\nreconnect:\n\tfor {\n\t\t// Check if we are shutting down.\n\t\tif ctx.IsDone() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Reset SPN status.\n\t\tif ready.SetToIf(true, false) {\n\t\t\tnetenv.ConnectedToSPN.UnSet()\n\t\t\tlog.Info(\"spn/captain: client not ready\")\n\t\t}\n\t\tresetSPNStatus(StatusConnecting, true)\n\n\t\t// Check everything and connect to the SPN.\n\t\tfor _, clientFunc := range []clientComponentFunc{\n\t\t\tclientStopHomeHub,\n\t\t\tclientCheckNetworkReady,\n\t\t\tclientCheckAccountAndTokens,\n\t\t\tclientConnectToHomeHub,\n\t\t\tclientSetActiveConnectionStatus,\n\t\t} {\n\t\t\tswitch clientFunc(ctx) {\n\t\t\tcase clientResultOk:\n\t\t\t\t// Continue\n\t\t\tcase clientResultRetry, clientResultReconnect:\n\t\t\t\t// Wait for a short time to not loop too quickly.\n\t\t\t\tselect {\n\t\t\t\tcase <-time.After(clientRetryConnectBackoffDuration):\n\t\t\t\t\tcontinue reconnect\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\tcase clientResultShutdown:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tlog.Info(\"spn/captain: client is ready\")\n\t\tready.Set()\n\t\tnetenv.ConnectedToSPN.Set()\n\n\t\tmodule.EventSPNConnected.Submit(struct{}{})\n\t\tif conf.Integrated() {\n\t\t\tmodule.mgr.Go(\"update quick setting countries\", navigator.Main.UpdateConfigQuickSettings)\n\t\t}\n\n\t\t// Reset last health check value, as we have just connected.\n\t\tlastHealthCheck = time.Now()\n\n\t\t// Back off before starting initial health checks.\n\t\tselect {\n\t\tcase <-time.After(clientInitialHealthCheckDelay):\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tfor {\n\t\t\t// Check health of the current SPN connection and monitor the user status.\n\t\tmaintainers:\n\t\t\tfor _, clientFunc := range []clientComponentFunc{\n\t\t\t\tclientCheckHomeHubConnection,\n\t\t\t\tclientCheckAccountAndTokens,\n\t\t\t\tclientSetActiveConnectionStatus,\n\t\t\t} {\n\t\t\t\tswitch clientFunc(ctx) {\n\t\t\t\tcase clientResultOk:\n\t\t\t\t\t// Continue\n\t\t\t\tcase clientResultRetry:\n\t\t\t\t\t// Abort and wait for the next run.\n\t\t\t\t\tbreak maintainers\n\t\t\t\tcase clientResultReconnect:\n\t\t\t\t\tcontinue reconnect\n\t\t\t\tcase clientResultShutdown:\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Wait for signal to run maintenance again.\n\t\t\tselect {\n\t\t\tcase <-module.healthCheckTicker.Wait():\n\t\t\tcase <-clientHealthCheckTrigger:\n\t\t\tcase <-crew.ConnectErrors():\n\t\t\tcase <-clientNetworkChangedFlag.Signal():\n\t\t\t\tclientNetworkChangedFlag.Refresh()\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc clientCheckNetworkReady(ctx *mgr.WorkerCtx) clientComponentResult {\n\t// Check if we are online enough for connecting.\n\tswitch netenv.GetOnlineStatus() { //nolint:exhaustive\n\tcase netenv.StatusOffline,\n\t\tnetenv.StatusLimited:\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn clientResultShutdown\n\t\tcase <-time.After(1 * time.Second):\n\t\t\treturn clientResultRetry\n\t\t}\n\t}\n\n\treturn clientResultOk\n}\n\n// DisableAccount disables using any account related SPN functionality.\n// Attempts to use the same will result in errors.\nvar DisableAccount bool\n\nfunc clientCheckAccountAndTokens(ctx *mgr.WorkerCtx) clientComponentResult {\n\tif DisableAccount {\n\t\treturn clientResultOk\n\t}\n\n\t// Get SPN user.\n\tuser, err := access.GetUser()\n\tif err != nil && !errors.Is(err, access.ErrNotLoggedIn) {\n\t\tnotifications.NotifyError(\n\t\t\t\"spn:failed-to-get-user\",\n\t\t\t\"SPN Internal Error\",\n\t\t\t`Please restart Portmaster.`,\n\t\t\t// TODO: Add restart button.\n\t\t\t// TODO: Use special UI restart action in order to reload UI on restart.\n\t\t).SyncWithState(module.states)\n\t\tresetSPNStatus(StatusFailed, true)\n\t\tlog.Errorf(\"spn/captain: client internal error: %s\", err)\n\t\treturn clientResultReconnect\n\t}\n\n\t// Check if user is logged in.\n\tif user == nil || !user.IsLoggedIn() {\n\t\tnotifications.NotifyWarn(\n\t\t\t\"spn:not-logged-in\",\n\t\t\t\"SPN Login Required\",\n\t\t\t`Please log in to access the SPN.`,\n\t\t\tspnLoginButton,\n\t\t).SyncWithState(module.states)\n\t\tresetSPNStatus(StatusFailed, true)\n\t\tlog.Warningf(\"spn/captain: enabled but not logged in\")\n\t\treturn clientResultReconnect\n\t}\n\n\t// Check if user is eligible.\n\tif !user.MayUseTheSPN() {\n\t\t// Update user in case there was a change.\n\t\t// Only update here if we need to - there is an update task in the access\n\t\t// module for periodic updates.\n\t\tif time.Now().Add(-clientIneligibleAccountUpdateDelay).After(time.Unix(user.Meta().Modified, 0)) {\n\t\t\t_, _, err := access.UpdateUser()\n\t\t\tif err != nil {\n\t\t\t\tnotifications.NotifyError(\n\t\t\t\t\t\"spn:failed-to-update-user\",\n\t\t\t\t\t\"SPN Account Server Error\",\n\t\t\t\t\tfmt.Sprintf(`The status of your SPN account could not be updated: %s`, err),\n\t\t\t\t).SyncWithState(module.states)\n\t\t\t\tresetSPNStatus(StatusFailed, true)\n\t\t\t\tlog.Errorf(\"spn/captain: failed to update ineligible account: %s\", err)\n\t\t\t\treturn clientResultReconnect\n\t\t\t}\n\t\t}\n\n\t\t// Check if user is eligible after a possible update.\n\t\tif !user.MayUseTheSPN() {\n\n\t\t\t// If package is generally valid, then the current package does not have access to the SPN.\n\t\t\tif user.MayUse(\"\") {\n\t\t\t\tnotifications.NotifyError(\n\t\t\t\t\t\"spn:package-not-eligible\",\n\t\t\t\t\t\"SPN Not Included In Package\",\n\t\t\t\t\t\"Your current Portmaster Package does not include access to the SPN. Please upgrade your package on the Account Page.\",\n\t\t\t\t\tspnOpenAccountPage,\n\t\t\t\t).SyncWithState(module.states)\n\t\t\t\tresetSPNStatus(StatusFailed, true)\n\t\t\t\treturn clientResultReconnect\n\t\t\t}\n\n\t\t\t// Otherwise, include the message from the user view.\n\t\t\tmessage := \"There is an issue with your Portmaster Package. Please check the Account Page.\"\n\t\t\tif user.View != nil && user.View.Message != \"\" {\n\t\t\t\tmessage = user.View.Message\n\t\t\t}\n\t\t\tnotifications.NotifyError(\n\t\t\t\t\"spn:subscription-inactive\",\n\t\t\t\t\"Portmaster Package Issue\",\n\t\t\t\t\"Cannot enable SPN: \"+message,\n\t\t\t\tspnOpenAccountPage,\n\t\t\t).SyncWithState(module.states)\n\t\t\tresetSPNStatus(StatusFailed, true)\n\t\t\treturn clientResultReconnect\n\t\t}\n\t}\n\n\t// Check if we have enough tokens.\n\tif access.ShouldRequest(access.ExpandAndConnectZones) {\n\t\terr := access.UpdateTokens()\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"spn/captain: failed to get tokens: %s\", err)\n\n\t\t\t// There was an error updating the account.\n\t\t\t// Check if we have enough tokens to continue anyway.\n\t\t\tregular, _ := access.GetTokenAmount(access.ExpandAndConnectZones)\n\t\t\tif regular == 0 /* && fallback == 0 */ { // TODO: Add fallback token check when fallback was tested on servers.\n\t\t\t\tnotifications.NotifyError(\n\t\t\t\t\t\"spn:tokens-exhausted\",\n\t\t\t\t\t\"SPN Access Tokens Exhausted\",\n\t\t\t\t\t`The Portmaster failed to get new access tokens to access the SPN. The Portmaster will automatically retry to get new access tokens.`,\n\t\t\t\t).SyncWithState(module.states)\n\t\t\t\tresetSPNStatus(StatusFailed, false)\n\t\t\t}\n\t\t\treturn clientResultRetry\n\t\t}\n\t}\n\n\treturn clientResultOk\n}\n\nfunc clientStopHomeHub(ctx *mgr.WorkerCtx) clientComponentResult {\n\t// Don't use the context in this function, as it will likely be canceled\n\t// already and would disrupt any context usage in here.\n\n\t// Get crane connecting to home.\n\thome, _ := navigator.Main.GetHome()\n\tif home == nil {\n\t\treturn clientResultOk\n\t}\n\tcrane := docks.GetAssignedCrane(home.Hub.ID)\n\tif crane == nil {\n\t\treturn clientResultOk\n\t}\n\n\t// Stop crane and all connected terminals.\n\tcrane.Stop(nil)\n\treturn clientResultOk\n}\n\nfunc clientConnectToHomeHub(ctx *mgr.WorkerCtx) clientComponentResult {\n\terr := establishHomeHub(ctx)\n\tif err != nil {\n\t\tif ctx.IsDone() {\n\t\t\treturn clientResultShutdown\n\t\t}\n\n\t\tlog.Errorf(\"spn/captain: failed to establish connection to home hub: %s\", err)\n\t\tresetSPNStatus(StatusFailed, true)\n\n\t\tswitch {\n\t\tcase errors.Is(err, ErrAllHomeHubsExcluded):\n\t\t\tnotifications.NotifyError(\n\t\t\t\t\"spn:all-home-hubs-excluded\",\n\t\t\t\t\"All Home Nodes Excluded\",\n\t\t\t\t\"Your current Home Node Rules exclude all available and eligible SPN Nodes. Please change your rules to allow for at least one available and eligible Home Node.\",\n\t\t\t\tnotifications.Action{\n\t\t\t\t\tText: \"Configure\",\n\t\t\t\t\tType: notifications.ActionTypeOpenSetting,\n\t\t\t\t\tPayload: &notifications.ActionTypeOpenSettingPayload{\n\t\t\t\t\t\tKey: CfgOptionHomeHubPolicyKey,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t).SyncWithState(module.states)\n\n\t\tcase errors.Is(err, ErrReInitSPNSuggested):\n\t\t\tnotifications.NotifyError(\n\t\t\t\t\"spn:cannot-bootstrap\",\n\t\t\t\t\"SPN Cannot Bootstrap\",\n\t\t\t\t\"The local state of the SPN network is likely outdated. Portmaster was not able to identify a server to connect to. Please re-initialize the SPN using the tools menu or the button on the notification.\",\n\t\t\t\tnotifications.Action{\n\t\t\t\t\tID:   \"re-init\",\n\t\t\t\t\tText: \"Re-Init SPN\",\n\t\t\t\t\tType: notifications.ActionTypeWebhook,\n\t\t\t\t\tPayload: &notifications.ActionTypeWebhookPayload{\n\t\t\t\t\t\tURL:          apiPathForSPNReInit,\n\t\t\t\t\t\tResultAction: \"display\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t).SyncWithState(module.states)\n\n\t\tdefault:\n\t\t\tnotifications.NotifyWarn(\n\t\t\t\t\"spn:home-hub-failure\",\n\t\t\t\t\"SPN Failed to Connect\",\n\t\t\t\tfmt.Sprintf(\"Failed to connect to a home hub: %s. The Portmaster will retry to connect automatically.\", err),\n\t\t\t).SyncWithState(module.states)\n\t\t}\n\n\t\treturn clientResultReconnect\n\t}\n\n\t// Log new connection.\n\thome, _ := navigator.Main.GetHome()\n\tif home != nil {\n\t\tlog.Infof(\"spn/captain: established new home %s\", home.Hub)\n\t}\n\n\treturn clientResultOk\n}\n\nfunc clientSetActiveConnectionStatus(ctx *mgr.WorkerCtx) clientComponentResult {\n\t// Get current home.\n\thome, homeTerminal := navigator.Main.GetHome()\n\tif home == nil || homeTerminal == nil {\n\t\treturn clientResultReconnect\n\t}\n\n\t// Resolve any connection error.\n\tmodule.states.Clear()\n\n\t// Update SPN Status with connection information, if not already correctly set.\n\tspnStatus.Lock()\n\tdefer spnStatus.Unlock()\n\n\tif spnStatus.Status != StatusConnected || spnStatus.HomeHubID != home.Hub.ID {\n\t\t// Fill connection status data.\n\t\tspnStatus.Status = StatusConnected\n\t\tspnStatus.HomeHubID = home.Hub.ID\n\t\tspnStatus.HomeHubName = home.Hub.Info.Name\n\n\t\tconnectedIP, _, err := netutils.IPPortFromAddr(homeTerminal.RemoteAddr())\n\t\tif err != nil {\n\t\t\tspnStatus.ConnectedIP = homeTerminal.RemoteAddr().String()\n\t\t} else {\n\t\t\tspnStatus.ConnectedIP = connectedIP.String()\n\t\t}\n\t\tspnStatus.ConnectedTransport = homeTerminal.Transport().String()\n\n\t\tgeoLoc := home.GetLocation(connectedIP)\n\t\tif geoLoc != nil {\n\t\t\tspnStatus.ConnectedCountry = &geoLoc.Country\n\t\t}\n\n\t\tnow := time.Now()\n\t\tspnStatus.ConnectedSince = &now\n\n\t\t// Push new status.\n\t\tpushSPNStatusUpdate()\n\t}\n\n\treturn clientResultOk\n}\n\nfunc clientCheckHomeHubConnection(ctx *mgr.WorkerCtx) clientComponentResult {\n\t// Check the status of the Home Hub.\n\thome, homeTerminal := navigator.Main.GetHome()\n\tif home == nil || homeTerminal == nil || homeTerminal.IsBeingAbandoned() {\n\t\treturn clientResultReconnect\n\t}\n\n\t// Get crane controller for health check.\n\tcrane := docks.GetAssignedCrane(home.Hub.ID)\n\tif crane == nil {\n\t\tlog.Errorf(\"spn/captain: could not find home hub crane for health check\")\n\t\treturn clientResultOk\n\t}\n\n\t// Ping home hub.\n\tlatency, tErr := pingHome(ctx, crane.Controller, clientHealthCheckTimeout)\n\tif tErr != nil {\n\t\tlog.Warningf(\"spn/captain: failed to ping home hub: %s\", tErr)\n\n\t\t// Prepare to reconnect to the network.\n\n\t\t// Reset all failing states, as these might have been caused by the failing home hub.\n\t\tnavigator.Main.ResetFailingStates()\n\n\t\t// If the last health check is clearly too long ago, assume that the device was sleeping and do not set the home node to failing yet.\n\t\tif time.Since(lastHealthCheck) > clientHealthCheckTickDuration+\n\t\t\tclientHealthCheckTickDurationSleepMode+\n\t\t\t(clientHealthCheckTimeout*2) {\n\t\t\treturn clientResultReconnect\n\t\t}\n\n\t\t// Mark the home hub itself as failing, as we want to try to connect to somewhere else.\n\t\thome.MarkAsFailingFor(5 * time.Minute)\n\n\t\treturn clientResultReconnect\n\t}\n\tlastHealthCheck = time.Now()\n\n\tlog.Debugf(\"spn/captain: pinged home hub in %s\", latency)\n\treturn clientResultOk\n}\n\nfunc pingHome(ctx *mgr.WorkerCtx, t terminal.Terminal, timeout time.Duration) (latency time.Duration, err *terminal.Error) {\n\tstarted := time.Now()\n\n\t// Start ping operation.\n\tpingOp, tErr := crew.NewPingOp(t)\n\tif tErr != nil {\n\t\treturn 0, tErr\n\t}\n\n\t// Wait for response.\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn 0, terminal.ErrCanceled\n\tcase <-time.After(timeout):\n\t\treturn 0, terminal.ErrTimeout\n\tcase result := <-pingOp.Result:\n\t\tif result.Is(terminal.ErrExplicitAck) {\n\t\t\treturn time.Since(started), nil\n\t\t}\n\t\tif result.IsOK() {\n\t\t\treturn 0, result.Wrap(\"unexpected response\")\n\t\t}\n\t\treturn 0, result\n\t}\n}\n"
  },
  {
    "path": "spn/captain/config.go",
    "content": "package captain\n\nimport (\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n)\n\nvar (\n\t// CfgOptionEnableSPNKey is the configuration key for the SPN module.\n\tCfgOptionEnableSPNKey   = \"spn/enable\"\n\tcfgOptionEnableSPNOrder = 128\n\n\t// CfgOptionHomeHubPolicyKey is the configuration key for the SPN home policy.\n\tCfgOptionHomeHubPolicyKey   = \"spn/homePolicy\"\n\tcfgOptionHomeHubPolicy      config.StringArrayOption\n\tcfgOptionHomeHubPolicyOrder = 145\n\n\t// CfgOptionDNSExitHubPolicyKey is the configuration key for the SPN DNS exit policy.\n\tCfgOptionDNSExitHubPolicyKey   = \"spn/dnsExitPolicy\"\n\tcfgOptionDNSExitHubPolicy      config.StringArrayOption\n\tcfgOptionDNSExitHubPolicyOrder = 148\n\n\t// CfgOptionUseCommunityNodesKey is the configuration key for whether to use community nodes.\n\tCfgOptionUseCommunityNodesKey   = \"spn/useCommunityNodes\"\n\tcfgOptionUseCommunityNodes      config.BoolOption\n\tcfgOptionUseCommunityNodesOrder = 149\n\n\t// NonCommunityVerifiedOwners holds a list of verified owners that are not\n\t// considered \"community\".\n\tNonCommunityVerifiedOwners = []string{\"Safing\"}\n\n\t// CfgOptionTrustNodeNodesKey is the configuration key for whether additional trusted nodes.\n\tCfgOptionTrustNodeNodesKey   = \"spn/trustNodes\"\n\tcfgOptionTrustNodeNodes      config.StringArrayOption\n\tcfgOptionTrustNodeNodesOrder = 150\n\n\t// Special Access Code.\n\tcfgOptionSpecialAccessCodeKey     = \"spn/specialAccessCode\"\n\tcfgOptionSpecialAccessCodeDefault = \"none\"\n\tcfgOptionSpecialAccessCode        config.StringOption //nolint:unused // Linter, you drunk?\n\tcfgOptionSpecialAccessCodeOrder   = 160\n\n\t// IPv6 must be global and accessible.\n\tcfgOptionBindToAdvertisedKey     = \"spn/publicHub/bindToAdvertised\"\n\tcfgOptionBindToAdvertised        config.BoolOption\n\tcfgOptionBindToAdvertisedDefault = false\n\tcfgOptionBindToAdvertisedOrder   = 161\n\n\t// Config options for use.\n\tcfgOptionRoutingAlgorithm config.StringOption\n)\n\nfunc prepConfig() error {\n\t// Register spn module setting.\n\terr := config.Register(&config.Option{\n\t\tName:         \"SPN Module\",\n\t\tKey:          CfgOptionEnableSPNKey,\n\t\tDescription:  \"Start the Safing Privacy Network module. If turned off, the SPN is fully disabled on this device.\",\n\t\tOptType:      config.OptTypeBool,\n\t\tDefaultValue: false,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionEnableSPNOrder,\n\t\t\tconfig.CategoryAnnotation:     \"General\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Home Node Rules\n\terr = config.Register(&config.Option{\n\t\tName: \"Home Node Rules\",\n\t\tKey:  CfgOptionHomeHubPolicyKey,\n\t\tDescription: `Customize which countries should or should not be used for your Home Node. The Home Node is your entry into the SPN. You connect directly to it and all your connections are routed through it.\n\nBy default, the Portmaster tries to choose the nearest node as your Home Node in order to reduce your exposure to the open Internet.\n\nReconnect to the SPN in order to apply new rules.`,\n\t\tHelp:            profile.SPNRulesHelp,\n\t\tSensitive:       true,\n\t\tOptType:         config.OptTypeStringArray,\n\t\tRequiresRestart: true,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tDefaultValue:    []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.CategoryAnnotation:                    \"Routing\",\n\t\t\tconfig.DisplayOrderAnnotation:                cfgOptionHomeHubPolicyOrder,\n\t\t\tconfig.DisplayHintAnnotation:                 endpoints.DisplayHintEndpointList,\n\t\t\tconfig.QuickSettingsAnnotation:               profile.SPNRulesQuickSettings,\n\t\t\tendpoints.EndpointListVerdictNamesAnnotation: profile.SPNRulesVerdictNames,\n\t\t},\n\t\tValidationRegex: endpoints.ListEntryValidationRegex,\n\t\tValidationFunc:  endpoints.ValidateEndpointListConfigOption,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionHomeHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionHomeHubPolicyKey, []string{})\n\n\t// DNS Exit Node Rules\n\terr = config.Register(&config.Option{\n\t\tName: \"DNS Exit Node Rules\",\n\t\tKey:  CfgOptionDNSExitHubPolicyKey,\n\t\tDescription: `Customize which countries should or should not be used as DNS Exit Nodes.\n\nBy default, the Portmaster will exit DNS requests directly at your Home Node in order to keep them fast and close to your location. This is important, as DNS resolution often takes your approximate location into account when deciding which optimized DNS records are returned to you. As the Portmaster encrypts your DNS requests by default, you effectively gain a two-hop security level for your DNS requests in order to protect your privacy.\n\nThis setting mainly exists for when you need to simulate your presence in another location on a lower level too. This might be necessary to defeat more intelligent geo-blocking systems.`,\n\t\tHelp:            profile.SPNRulesHelp,\n\t\tSensitive:       true,\n\t\tOptType:         config.OptTypeStringArray,\n\t\tRequiresRestart: true,\n\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\tDefaultValue:    []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.CategoryAnnotation:                    \"Routing\",\n\t\t\tconfig.DisplayOrderAnnotation:                cfgOptionDNSExitHubPolicyOrder,\n\t\t\tconfig.DisplayHintAnnotation:                 endpoints.DisplayHintEndpointList,\n\t\t\tconfig.QuickSettingsAnnotation:               profile.SPNRulesQuickSettings,\n\t\t\tendpoints.EndpointListVerdictNamesAnnotation: profile.SPNRulesVerdictNames,\n\t\t},\n\t\tValidationRegex: endpoints.ListEntryValidationRegex,\n\t\tValidationFunc:  endpoints.ValidateEndpointListConfigOption,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionDNSExitHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionDNSExitHubPolicyKey, []string{})\n\n\terr = config.Register(&config.Option{\n\t\tName:            \"Use Community Nodes\",\n\t\tKey:             CfgOptionUseCommunityNodesKey,\n\t\tDescription:     \"Use nodes (servers) not operated by Safing themselves. The use of community nodes is recommended as it diversifies the ownership of the nodes you use for your connections and further strengthens your privacy. Plain connections (eg. http, smtp, ...) will never exit via community nodes, making this setting safe to use.\",\n\t\tSensitive:       true,\n\t\tOptType:         config.OptTypeBool,\n\t\tRequiresRestart: true,\n\t\tDefaultValue:    true,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionUseCommunityNodesOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Routing\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionUseCommunityNodes = config.Concurrent.GetAsBool(CfgOptionUseCommunityNodesKey, true)\n\n\terr = config.Register(&config.Option{\n\t\tName:           \"Trust Nodes\",\n\t\tKey:            CfgOptionTrustNodeNodesKey,\n\t\tDescription:    \"Specify which community nodes to additionally trust. These nodes may then also be used as a Home Node, as well as an Exit Node for unencrypted connections.\",\n\t\tHelp:           \"You can specify nodes by their ID or their verified operator.\",\n\t\tSensitive:      true,\n\t\tOptType:        config.OptTypeStringArray,\n\t\tExpertiseLevel: config.ExpertiseLevelExpert,\n\t\tDefaultValue:   []string{},\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionTrustNodeNodesOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Routing\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionTrustNodeNodes = config.Concurrent.GetAsStringArray(CfgOptionTrustNodeNodesKey, []string{})\n\n\terr = config.Register(&config.Option{\n\t\tName:         \"Special Access Code\",\n\t\tKey:          cfgOptionSpecialAccessCodeKey,\n\t\tDescription:  \"Special Access Codes grant access to the SPN for testing or evaluation purposes.\",\n\t\tSensitive:    true,\n\t\tOptType:      config.OptTypeString,\n\t\tDefaultValue: cfgOptionSpecialAccessCodeDefault,\n\t\tAnnotations: config.Annotations{\n\t\t\tconfig.DisplayOrderAnnotation: cfgOptionSpecialAccessCodeOrder,\n\t\t\tconfig.CategoryAnnotation:     \"Advanced\",\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcfgOptionSpecialAccessCode = config.Concurrent.GetAsString(cfgOptionSpecialAccessCodeKey, \"\")\n\n\tif conf.PublicHub() {\n\t\terr = config.Register(&config.Option{\n\t\t\tName:            \"Connect From Advertised IPs Only\",\n\t\t\tKey:             cfgOptionBindToAdvertisedKey,\n\t\t\tDescription:     \"Only connect from (bind to) the advertised IP addresses.\",\n\t\t\tOptType:         config.OptTypeBool,\n\t\t\tExpertiseLevel:  config.ExpertiseLevelExpert,\n\t\t\tDefaultValue:    cfgOptionBindToAdvertisedDefault,\n\t\t\tRequiresRestart: true,\n\t\t\tAnnotations: config.Annotations{\n\t\t\t\tconfig.DisplayOrderAnnotation: cfgOptionBindToAdvertisedOrder,\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tcfgOptionBindToAdvertised = config.GetAsBool(cfgOptionBindToAdvertisedKey, cfgOptionBindToAdvertisedDefault)\n\t}\n\n\t// Config options for use.\n\tif conf.Integrated() {\n\t\tcfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(profile.CfgOptionRoutingAlgorithmKey, navigator.DefaultRoutingProfileID)\n\t} else {\n\t\tcfgOptionRoutingAlgorithm = func() string { return navigator.DefaultRoutingProfileID }\n\t}\n\n\treturn nil\n}\n\nvar (\n\thomeHubPolicy           endpoints.Endpoints\n\thomeHubPolicyLock       sync.Mutex\n\thomeHubPolicyConfigFlag = config.NewValidityFlag()\n)\n\nfunc getHomeHubPolicy() (endpoints.Endpoints, error) {\n\thomeHubPolicyLock.Lock()\n\tdefer homeHubPolicyLock.Unlock()\n\n\t// Return cached value if config is still valid.\n\tif homeHubPolicyConfigFlag.IsValid() {\n\t\treturn homeHubPolicy, nil\n\t}\n\thomeHubPolicyConfigFlag.Refresh()\n\n\t// Parse new policy.\n\tpolicy, err := endpoints.ParseEndpoints(cfgOptionHomeHubPolicy())\n\tif err != nil {\n\t\thomeHubPolicy = nil\n\t\treturn nil, err\n\t}\n\n\t// Save and return the new policy.\n\thomeHubPolicy = policy\n\treturn homeHubPolicy, nil\n}\n\nvar (\n\tdnsExitHubPolicy           endpoints.Endpoints\n\tdnsExitHubPolicyLock       sync.Mutex\n\tdnsExitHubPolicyConfigFlag = config.NewValidityFlag()\n)\n\n// GetDNSExitHubPolicy return the current DNS exit policy.\nfunc GetDNSExitHubPolicy() (endpoints.Endpoints, error) {\n\tdnsExitHubPolicyLock.Lock()\n\tdefer dnsExitHubPolicyLock.Unlock()\n\n\t// Return cached value if config is still valid.\n\tif dnsExitHubPolicyConfigFlag.IsValid() {\n\t\treturn dnsExitHubPolicy, nil\n\t}\n\tdnsExitHubPolicyConfigFlag.Refresh()\n\n\t// Parse new policy.\n\tpolicy, err := endpoints.ParseEndpoints(cfgOptionDNSExitHubPolicy())\n\tif err != nil {\n\t\tdnsExitHubPolicy = nil\n\t\treturn nil, err\n\t}\n\n\t// Save and return the new policy.\n\tdnsExitHubPolicy = policy\n\treturn dnsExitHubPolicy, nil\n}\n"
  },
  {
    "path": "spn/captain/establish.go",
    "content": "package captain\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\n// EstablishCrane establishes a crane to another Hub.\nfunc EstablishCrane(callerCtx context.Context, dst *hub.Hub) (*docks.Crane, error) {\n\tif conf.PublicHub() && dst.ID == publicIdentity.ID {\n\t\treturn nil, errors.New(\"connecting to self\")\n\t}\n\tif docks.GetAssignedCrane(dst.ID) != nil {\n\t\treturn nil, fmt.Errorf(\"route to %s already exists\", dst.ID)\n\t}\n\n\tship, err := ships.Launch(callerCtx, dst, nil, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to launch ship: %w\", err)\n\t}\n\n\t// If not a public hub, mark all ships as public in order to show unmasked data in logs.\n\tif !conf.PublicHub() {\n\t\tship.MarkPublic()\n\t}\n\n\tcrane, err := docks.NewCrane(ship, dst, publicIdentity)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create crane: %w\", err)\n\t}\n\n\terr = crane.Start(callerCtx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to start crane: %w\", err)\n\t}\n\n\t// Start gossip op for live map updates.\n\t_, tErr := NewGossipOp(crane.Controller)\n\tif tErr != nil {\n\t\tcrane.Stop(tErr)\n\t\treturn nil, fmt.Errorf(\"failed to start gossip op: %w\", tErr)\n\t}\n\n\treturn crane, nil\n}\n\n// EstablishPublicLane establishes a crane to another Hub and publishes it.\nfunc EstablishPublicLane(ctx context.Context, dst *hub.Hub) (*docks.Crane, *terminal.Error) {\n\t// Create new context with timeout.\n\t// The maximum timeout is a worst case safeguard.\n\t// Keep in mind that multiple IPs and protocols may be tried in all configurations.\n\t// Some servers will be (possibly on purpose) hard to reach.\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n\tdefer cancel()\n\n\t// Connect to destination and establish communication.\n\tcrane, err := EstablishCrane(ctx, dst)\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to establish crane: %w\", err)\n\t}\n\n\t// Publish as Lane.\n\tpublishOp, tErr := NewPublishOp(crane.Controller, publicIdentity)\n\tif tErr != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to publish: %w\", err)\n\t}\n\n\t// Wait for publishing to complete.\n\tselect {\n\tcase tErr := <-publishOp.Result():\n\t\tif !tErr.Is(terminal.ErrExplicitAck) {\n\t\t\t// Stop crane again, because we failed to publish it.\n\t\t\tdefer crane.Stop(nil)\n\t\t\treturn nil, terminal.ErrInternalError.With(\"failed to publish lane: %w\", tErr)\n\t\t}\n\n\tcase <-crane.Controller.Ctx().Done():\n\t\tdefer crane.Stop(nil)\n\t\treturn nil, terminal.ErrStopping\n\n\tcase <-ctx.Done():\n\t\tdefer crane.Stop(nil)\n\t\tif errors.Is(ctx.Err(), context.DeadlineExceeded) {\n\t\t\treturn nil, terminal.ErrTimeout\n\t\t}\n\t\treturn nil, terminal.ErrCanceled\n\t}\n\n\t// Query all gossip msgs.\n\t_, tErr = NewGossipQueryOp(crane.Controller)\n\tif tErr != nil {\n\t\tlog.Warningf(\"spn/captain: failed to start initial gossip query: %s\", tErr)\n\t}\n\n\treturn crane, nil\n}\n"
  },
  {
    "path": "spn/captain/exceptions.go",
    "content": "package captain\n\nimport (\n\t\"net\"\n\t\"sync\"\n)\n\nvar (\n\texceptionLock sync.Mutex\n\texceptIPv4    net.IP\n\texceptIPv6    net.IP\n)\n\nfunc setExceptions(ipv4, ipv6 net.IP) {\n\texceptionLock.Lock()\n\tdefer exceptionLock.Unlock()\n\n\texceptIPv4 = ipv4\n\texceptIPv6 = ipv6\n}\n\n// IsExcepted checks if the given IP is currently excepted from the SPN.\nfunc IsExcepted(ip net.IP) bool {\n\texceptionLock.Lock()\n\tdefer exceptionLock.Unlock()\n\n\treturn ip.Equal(exceptIPv4) || ip.Equal(exceptIPv6)\n}\n"
  },
  {
    "path": "spn/captain/gossip.go",
    "content": "package captain\n\nimport (\n\t\"sync\"\n)\n\nvar (\n\tgossipOps     = make(map[string]*GossipOp)\n\tgossipOpsLock sync.RWMutex\n)\n\nfunc registerGossipOp(craneID string, op *GossipOp) {\n\tgossipOpsLock.Lock()\n\tdefer gossipOpsLock.Unlock()\n\n\tgossipOps[craneID] = op\n}\n\nfunc deleteGossipOp(craneID string) {\n\tgossipOpsLock.Lock()\n\tdefer gossipOpsLock.Unlock()\n\n\tdelete(gossipOps, craneID)\n}\n\nfunc gossipRelayMsg(receivedFrom string, msgType GossipMsgType, data []byte) {\n\tgossipOpsLock.RLock()\n\tdefer gossipOpsLock.RUnlock()\n\n\tfor craneID, gossipOp := range gossipOps {\n\t\t// Don't return same msg back to sender.\n\t\tif craneID == receivedFrom {\n\t\t\tcontinue\n\t\t}\n\n\t\tgossipOp.sendMsg(msgType, data)\n\t}\n}\n"
  },
  {
    "path": "spn/captain/hooks.go",
    "content": "package captain\n\nimport (\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/docks\"\n)\n\nfunc startDockHooks() {\n\tdocks.RegisterCraneUpdateHook(handleCraneUpdate)\n}\n\nfunc stopDockHooks() {\n\tdocks.ResetCraneUpdateHook()\n}\n\nfunc handleCraneUpdate(crane *docks.Crane) {\n\tif crane == nil {\n\t\treturn\n\t}\n\n\tif conf.Client() && crane.Controller != nil && crane.Controller.Abandoning.IsSet() {\n\t\t// Check connection to home hub.\n\t\ttriggerClientHealthCheck()\n\t}\n\n\tif conf.PublicHub() && crane.Public() {\n\t\t// Update Hub status.\n\t\tupdateConnectionStatus()\n\t}\n}\n\nfunc updateConnectionStatus() {\n\t// Delay updating status for a better chance to combine multiple changes.\n\tmodule.statusUpdater.Delay(maintainStatusUpdateDelay)\n\n\t// Check if we lost all connections and trigger a pending restart if we did.\n\tfor _, crane := range docks.GetAllAssignedCranes() {\n\t\tif crane.Public() && !crane.Stopped() {\n\t\t\t// There is at least one public and active crane, so don't restart now.\n\t\t\treturn\n\t\t}\n\t}\n\n\t// TODO(vladimir): what was this needed for?\n\t// updates.TriggerRestartIfPending()\n}\n"
  },
  {
    "path": "spn/captain/intel.go",
    "content": "package captain\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/updates\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/ships\"\n)\n\nvar (\n\tintelResource           *updates.Artifact\n\tintelResourceName       = \"main-intel.yaml\"\n\tintelResourceMapName    = \"main\"\n\tintelResourceUpdateLock sync.Mutex\n)\n\nfunc registerIntelUpdateHook() error {\n\tmodule.instance.IntelUpdates().EventResourcesUpdated.AddCallback(\"update SPN intel\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\treturn false, updateSPNIntel(wc.Ctx(), nil)\n\t})\n\n\tmodule.instance.Config().EventConfigChange.AddCallback(\"update SPN intel\", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\treturn false, updateSPNIntel(wc.Ctx(), nil)\n\t})\n\n\treturn nil\n}\n\nfunc updateSPNIntel(_ context.Context, _ interface{}) (err error) {\n\tintelResourceUpdateLock.Lock()\n\tdefer intelResourceUpdateLock.Unlock()\n\n\t// Only update SPN intel when using the matching map.\n\tif conf.MainMapName != intelResourceMapName {\n\t\treturn fmt.Errorf(\"intel resource not for map %q\", conf.MainMapName)\n\t}\n\n\t// Get possibly updated file.\n\tfile, err := module.instance.IntelUpdates().GetFile(intelResourceName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get SPN intel update: %w\", err)\n\t}\n\n\t// If intel is not initialized, skip version comparison.\n\tif navigator.Main.GetIntel() != nil {\n\t\t// Check if file is newer.\n\t\t// Continue on check failure.\n\t\tnewer, ok := file.IsNewerThan(intelResource)\n\t\tif ok && !newer {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// Load intel file from disk.\n\tintelData, err := os.ReadFile(file.Path())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to load SPN intel update: %w\", err)\n\t}\n\n\t// Parse and apply intel data.\n\tintel, err := hub.ParseIntel(intelData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse SPN intel update: %w\", err)\n\t}\n\n\t// Apply new intel.\n\tsetVirtualNetworkConfig(intel.VirtualNetworks)\n\terr = navigator.Main.UpdateIntel(intel, cfgOptionTrustNodeNodes())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to update intel on map: %w\", err)\n\t}\n\n\tintelResource = file\n\treturn nil\n}\n\nfunc resetSPNIntel() {\n\tintelResourceUpdateLock.Lock()\n\tdefer intelResourceUpdateLock.Unlock()\n\n\tintelResource = nil\n}\n\nfunc setVirtualNetworkConfig(configs []*hub.VirtualNetworkConfig) {\n\t// Do nothing if not public Hub.\n\tif !conf.PublicHub() {\n\t\treturn\n\t}\n\t// Reset if there are no virtual networks configured.\n\tif len(configs) == 0 {\n\t\tships.SetVirtualNetworkConfig(nil)\n\t}\n\n\t// Check if we are in a virtual network.\n\tfor _, config := range configs {\n\t\tif _, ok := config.Mapping[publicIdentity.Hub.ID]; ok {\n\t\t\tships.SetVirtualNetworkConfig(config)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// If not, reset - we might have been in one before.\n\tships.SetVirtualNetworkConfig(nil)\n}\n"
  },
  {
    "path": "spn/captain/module.go",
    "content": "package captain\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/updates\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/crew\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/patrol\"\n\t\"github.com/safing/portmaster/spn/ships\"\n)\n\n// SPNConnectedEvent is the name of the event that is fired when the SPN has connected and is ready.\nconst SPNConnectedEvent = \"spn connect\"\n\n// Captain is the main module of the SPN.\ntype Captain struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\thealthCheckTicker *mgr.SleepyTicker\n\n\tpublicIdentityUpdater *mgr.WorkerMgr\n\tstatusUpdater         *mgr.WorkerMgr\n\n\tstates            *mgr.StateMgr\n\tEventSPNConnected *mgr.EventMgr[struct{}]\n}\n\n// Manager returns the module manager.\nfunc (c *Captain) Manager() *mgr.Manager {\n\treturn c.mgr\n}\n\n// States returns the module states.\nfunc (c *Captain) States() *mgr.StateMgr {\n\treturn c.states\n}\n\n// Start starts the module.\nfunc (c *Captain) Start() error {\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (c *Captain) Stop() error {\n\treturn stop()\n}\n\n// SetSleep sets the sleep mode of the module.\nfunc (c *Captain) SetSleep(enabled bool) {\n\tif c.healthCheckTicker != nil {\n\t\tc.healthCheckTicker.SetSleep(enabled)\n\t}\n}\n\nfunc (c *Captain) prep() error {\n\t// Check if we can parse the bootstrap hub flag.\n\tif err := prepBootstrapHubFlag(); err != nil {\n\t\treturn err\n\t}\n\n\t// Register SPN status provider.\n\tif err := registerSPNStatusProvider(); err != nil {\n\t\treturn err\n\t}\n\n\t// Register API endpoints.\n\tif err := registerAPIEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\tif conf.PublicHub() {\n\t\t// Register API authenticator.\n\t\tif err := api.SetAuthenticator(apiAuthenticator); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tc.instance.Patrol().EventChangeSignal.AddCallback(\n\t\t\t\"trigger hub status maintenance\",\n\t\t\tfunc(_ *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\t\tTriggerHubStatusMaintenance()\n\t\t\t\treturn false, nil\n\t\t\t},\n\t\t)\n\t}\n\n\treturn prepConfig()\n}\n\nfunc start() error {\n\tmaskingBytes, err := rng.Bytes(16)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get random bytes for masking: %w\", err)\n\t}\n\tships.EnableMasking(maskingBytes)\n\n\t// Initialize identity and piers.\n\tif conf.PublicHub() {\n\t\t// Load identity.\n\t\tif err := loadPublicIdentity(); err != nil {\n\t\t\treturn fmt.Errorf(\"load public identity: %w\", err)\n\t\t}\n\n\t\t// Check if any networks are configured.\n\t\tif !conf.HubHasIPv4() && !conf.HubHasIPv6() {\n\t\t\treturn errors.New(\"no IP addresses for Hub configured (or detected)\")\n\t\t}\n\n\t\t// Start management of identity and piers.\n\t\tif err := prepPublicIdentityMgmt(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Set ID to display on http info page.\n\t\tships.DisplayHubID = publicIdentity.ID\n\t\t// Start listeners.\n\t\tif err := startPiers(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Enable connect operation.\n\t\tcrew.EnableConnecting(publicIdentity.Hub)\n\t}\n\n\t// Initialize SPN intel.\n\t// Do this synchronously to ensure everything is up to date before\n\terr = module.mgr.Do(\"start\", func(wc *mgr.WorkerCtx) error {\n\t\tif err := registerIntelUpdateHook(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := updateSPNIntel(module.mgr.Ctx(), nil); err != nil {\n\t\t\tlog.Errorf(\"spn/captain: failed to update SPN intel: %s\", err)\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Subscribe to updates of cranes.\n\tstartDockHooks()\n\n\t// bootstrapping\n\tif err := processBootstrapHubFlag(); err != nil {\n\t\treturn err\n\t}\n\tif err := processBootstrapFileFlag(); err != nil {\n\t\treturn err\n\t}\n\n\t// network optimizer\n\tif conf.PublicHub() {\n\t\tmodule.mgr.Delay(\"optimize network delay\", 15*time.Second, optimizeNetwork).Repeat(1 * time.Minute)\n\t}\n\n\t// client + home hub manager\n\tif conf.Client() {\n\t\tmodule.mgr.Go(\"client manager\", clientManager)\n\n\t\t// Reset failing hubs when the network changes while not connected.\n\t\tmodule.instance.NetEnv().EventNetworkChange.AddCallback(\"reset failing hubs\", func(_ *mgr.WorkerCtx, _ struct{}) (bool, error) {\n\t\t\tif ready.IsNotSet() {\n\t\t\t\tnavigator.Main.ResetFailingStates()\n\t\t\t}\n\t\t\treturn false, nil\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc stop() error {\n\t// Reset intel resource so that it is loaded again when starting.\n\tresetSPNIntel()\n\n\t// Unregister crane update hook.\n\tstopDockHooks()\n\n\t// Send shutdown status message.\n\tif conf.PublicHub() {\n\t\tpublishShutdownStatus()\n\t\tstopPiers()\n\t}\n\n\treturn nil\n}\n\n// apiAuthenticator grants User permissions for local API requests.\nfunc apiAuthenticator(r *http.Request, s *http.Server) (*api.AuthToken, error) {\n\t// Get remote IP.\n\thost, _, err := net.SplitHostPort(r.RemoteAddr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to split host/port: %w\", err)\n\t}\n\tremoteIP := net.ParseIP(host)\n\tif remoteIP == nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse remote address %s\", host)\n\t}\n\n\tif !netutils.GetIPScope(remoteIP).IsLocalhost() {\n\t\treturn nil, api.ErrAPIAccessDeniedMessage\n\t}\n\n\treturn &api.AuthToken{\n\t\tRead:  api.PermitUser,\n\t\tWrite: api.PermitUser,\n\t}, nil\n}\n\nvar (\n\tmodule     *Captain\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Captain module.\nfunc New(instance instance) (*Captain, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Captain\")\n\tmodule = &Captain{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tstates:            mgr.NewStateMgr(m),\n\t\tEventSPNConnected: mgr.NewEventMgr[struct{}](SPNConnectedEvent, m),\n\n\t\tpublicIdentityUpdater: m.NewWorkerMgr(\"maintain public identity\", maintainPublicIdentity, nil),\n\t\tstatusUpdater:         m.NewWorkerMgr(\"maintain public status\", maintainPublicStatus, nil),\n\t}\n\n\tif err := module.prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface {\n\tNetEnv() *netenv.NetEnv\n\tPatrol() *patrol.Patrol\n\tConfig() *config.Config\n\tIntelUpdates() *updates.Updater\n\tSPNGroup() *mgr.ExtendedGroup\n}\n"
  },
  {
    "path": "spn/captain/navigation.go",
    "content": "package captain\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nconst stopCraneAfterBeingUnsuggestedFor = 6 * time.Hour\n\nvar (\n\t// ErrAllHomeHubsExcluded is returned when all available home hubs were excluded.\n\tErrAllHomeHubsExcluded = errors.New(\"all home hubs are excluded\")\n\n\t// ErrReInitSPNSuggested is returned when no home hub can be found, even without rules.\n\tErrReInitSPNSuggested = errors.New(\"SPN re-init suggested\")\n)\n\nfunc establishHomeHub(ctx *mgr.WorkerCtx) error {\n\t// Get own IP.\n\tlocations, ok := netenv.GetInternetLocation()\n\tif !ok || len(locations.All) == 0 {\n\t\treturn errors.New(\"failed to locate own device\")\n\t}\n\tlog.Debugf(\n\t\t\"spn/captain: looking for new home hub near %s and %s\",\n\t\tlocations.BestV4(),\n\t\tlocations.BestV6(),\n\t)\n\n\t// Get own entity.\n\t// Checking the entity against the entry policies is somewhat hit and miss\n\t// anyway, as the device location is an approximation.\n\tvar myEntity *intel.Entity\n\tif dl := locations.BestV4(); dl != nil && dl.IP != nil {\n\t\tmyEntity = (&intel.Entity{IP: dl.IP}).Init(0)\n\t\tmyEntity.FetchData(ctx.Ctx())\n\t} else if dl := locations.BestV6(); dl != nil && dl.IP != nil {\n\t\tmyEntity = (&intel.Entity{IP: dl.IP}).Init(0)\n\t\tmyEntity.FetchData(ctx.Ctx())\n\t}\n\n\t// Get home hub policy for selecting the home hub.\n\thomePolicy, err := getHomeHubPolicy()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Build navigation options for searching for a home hub.\n\topts := &navigator.Options{\n\t\tHome: &navigator.HomeHubOptions{\n\t\t\tHubPolicies:        []endpoints.Endpoints{homePolicy},\n\t\t\tCheckHubPolicyWith: myEntity,\n\t\t},\n\t}\n\n\t// Add requirement to only use Safing nodes when not using community nodes.\n\tif !cfgOptionUseCommunityNodes() {\n\t\topts.Home.RequireVerifiedOwners = NonCommunityVerifiedOwners\n\t}\n\n\t// Require a trusted home node when the routing profile requires less than two hops.\n\troutingProfile := navigator.GetRoutingProfile(cfgOptionRoutingAlgorithm())\n\tif routingProfile.MinHops < 2 {\n\t\topts.Home.Regard = opts.Home.Regard.Add(navigator.StateTrusted)\n\t}\n\n\t// Find nearby hubs.\nfindCandidates:\n\tcandidates, err := navigator.Main.FindNearestHubs(\n\t\tlocations.BestV4().LocationOrNil(),\n\t\tlocations.BestV6().LocationOrNil(),\n\t\topts, navigator.HomeHub,\n\t)\n\tif err != nil {\n\t\tswitch {\n\t\tcase errors.Is(err, navigator.ErrEmptyMap):\n\t\t\t// bootstrap to the network!\n\t\t\terr := bootstrapWithUpdates()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tgoto findCandidates\n\n\t\tcase errors.Is(err, navigator.ErrAllPinsDisregarded):\n\t\t\tif len(homePolicy) > 0 {\n\t\t\t\treturn ErrAllHomeHubsExcluded\n\t\t\t}\n\t\t\treturn ErrReInitSPNSuggested\n\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"failed to find nearby hubs: %w\", err)\n\t\t}\n\t}\n\n\t// Try connecting to a hub.\n\tvar tries int\n\tvar candidate *hub.Hub\n\tfor tries, candidate = range candidates {\n\t\terr = connectToHomeHub(ctx, candidate)\n\t\tif err != nil {\n\t\t\t// Check if context is canceled.\n\t\t\tif ctx.IsDone() {\n\t\t\t\treturn ctx.Ctx().Err()\n\t\t\t}\n\t\t\t// Check if the SPN protocol is stopping again.\n\t\t\tif errors.Is(err, terminal.ErrStopping) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Warningf(\"spn/captain: failed to connect to %s as new home: %s\", candidate, err)\n\t\t} else {\n\t\t\tlog.Infof(\"spn/captain: established connection to %s as new home with %d failed tries\", candidate, tries)\n\t\t\treturn nil\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to connect to a new home hub - tried %d hubs: %w\", tries+1, err)\n\t}\n\treturn errors.New(\"no home hub candidates available\")\n}\n\nfunc connectToHomeHub(wCtx *mgr.WorkerCtx, dst *hub.Hub) error {\n\t// Create new context with timeout.\n\t// The maximum timeout is a worst case safeguard.\n\t// Keep in mind that multiple IPs and protocols may be tried in all configurations.\n\t// Some servers will be (possibly on purpose) hard to reach.\n\tctx, cancel := context.WithTimeout(wCtx.Ctx(), 5*time.Minute)\n\tdefer cancel()\n\n\t// Set and clean up exceptions.\n\tsetExceptions(dst.Info.IPv4, dst.Info.IPv6)\n\tdefer setExceptions(nil, nil)\n\n\t// Connect to hub.\n\tcrane, err := EstablishCrane(ctx, dst)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Cleanup connection in case of failure.\n\tvar success bool\n\tdefer func() {\n\t\tif !success {\n\t\t\tcrane.Stop(nil)\n\t\t}\n\t}()\n\n\t// Query all gossip msgs on first connection.\n\tgossipQuery, tErr := NewGossipQueryOp(crane.Controller)\n\tif tErr != nil {\n\t\tlog.Warningf(\"spn/captain: failed to start initial gossip query: %s\", tErr)\n\t}\n\t// Wait for gossip query to complete.\n\tselect {\n\tcase <-gossipQuery.ctx.Done():\n\tcase <-ctx.Done():\n\t\treturn context.Canceled\n\t}\n\n\t// Create communication terminal.\n\thomeTerminal, initData, tErr := docks.NewLocalCraneTerminal(crane, nil, terminal.DefaultHomeHubTerminalOpts())\n\tif tErr != nil {\n\t\treturn tErr.Wrap(\"failed to create home terminal\")\n\t}\n\ttErr = crane.EstablishNewTerminal(homeTerminal, initData)\n\tif tErr != nil {\n\t\treturn tErr.Wrap(\"failed to connect home terminal\")\n\t}\n\n\tif !DisableAccount {\n\t\t// Authenticate to home hub.\n\t\tauthOp, tErr := access.AuthorizeToTerminal(homeTerminal)\n\t\tif tErr != nil {\n\t\t\treturn tErr.Wrap(\"failed to authorize\")\n\t\t}\n\t\tselect {\n\t\tcase tErr := <-authOp.Result:\n\t\t\tif !tErr.Is(terminal.ErrExplicitAck) {\n\t\t\t\treturn tErr.Wrap(\"failed to authenticate to\")\n\t\t\t}\n\t\tcase <-time.After(3 * time.Second):\n\t\t\treturn terminal.ErrTimeout.With(\"waiting for auth to complete\")\n\t\tcase <-ctx.Done():\n\t\t\treturn terminal.ErrStopping\n\t\t}\n\t}\n\n\t// Set new home on map.\n\tok := navigator.Main.SetHome(dst.ID, homeTerminal)\n\tif !ok {\n\t\treturn errors.New(\"failed to set home hub on map\")\n\t}\n\n\t// Assign crane to home hub in order to query it later.\n\tdocks.AssignCrane(crane.ConnectedHub.ID, crane)\n\n\tsuccess = true\n\treturn nil\n}\n\nfunc optimizeNetwork(ctx *mgr.WorkerCtx) error {\n\tif publicIdentity == nil {\n\t\treturn nil\n\t}\n\noptimize:\n\tresult, err := navigator.Main.Optimize(nil)\n\tif err != nil {\n\t\tif errors.Is(err, navigator.ErrEmptyMap) {\n\t\t\t// bootstrap to the network!\n\t\t\terr := bootstrapWithUpdates()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tgoto optimize\n\t\t}\n\n\t\treturn err\n\t}\n\n\t// Create any new connections.\n\tvar createdConnections int\n\tvar attemptedConnections int\n\tfor _, connectTo := range result.SuggestedConnections {\n\t\t// Skip duplicates.\n\t\tif connectTo.Duplicate {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check if connection already exists.\n\t\tcrane := docks.GetAssignedCrane(connectTo.Hub.ID)\n\t\tif crane != nil {\n\t\t\t// Update last suggested timestamp.\n\t\t\tcrane.NetState.UpdateLastSuggestedAt()\n\t\t\t// Continue crane if stopping.\n\t\t\tif crane.AbortStopping() {\n\t\t\t\tlog.Infof(\"spn/captain: optimization aborted retiring of %s, removed stopping mark\", crane)\n\t\t\t\tcrane.NotifyUpdate()\n\t\t\t}\n\n\t\t\t// Create new connections if we have connects left.\n\t\t} else if createdConnections < result.MaxConnect {\n\t\t\tattemptedConnections++\n\n\t\t\tcrane, tErr := EstablishPublicLane(ctx.Ctx(), connectTo.Hub)\n\t\t\tif !tErr.IsOK() {\n\t\t\t\tlog.Warningf(\"spn/captain: failed to establish lane to %s: %s\", connectTo.Hub, tErr)\n\t\t\t} else {\n\t\t\t\tcreatedConnections++\n\t\t\t\tcrane.NetState.UpdateLastSuggestedAt()\n\n\t\t\t\tlog.Infof(\"spn/captain: established lane to %s\", connectTo.Hub)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Log optimization result.\n\tif attemptedConnections > 0 {\n\t\tlog.Infof(\n\t\t\t\"spn/captain: created %d/%d new connections for %s optimization\",\n\t\t\tcreatedConnections,\n\t\t\tattemptedConnections,\n\t\t\tresult.Purpose)\n\t} else {\n\t\tlog.Infof(\n\t\t\t\"spn/captain: checked %d connections for %s optimization\",\n\t\t\tlen(result.SuggestedConnections),\n\t\t\tresult.Purpose,\n\t\t)\n\t}\n\n\t// Retire cranes if unsuggested for a while.\n\tif result.StopOthers {\n\t\tfor _, crane := range docks.GetAllAssignedCranes() {\n\t\t\tswitch {\n\t\t\tcase crane.Stopped():\n\t\t\t\t// Crane already stopped.\n\t\t\tcase crane.IsStopping():\n\t\t\t\t// Crane is stopping, forcibly stop if mine and suggested.\n\t\t\t\tif crane.IsMine() && crane.NetState.StopSuggested() {\n\t\t\t\t\tcrane.Stop(nil)\n\t\t\t\t}\n\t\t\tcase crane.IsMine() && crane.NetState.StoppingSuggested():\n\t\t\t\t// Mark as stopping if mine and suggested.\n\t\t\t\tcrane.MarkStopping()\n\t\t\tcase crane.NetState.RequestStoppingSuggested(stopCraneAfterBeingUnsuggestedFor):\n\t\t\t\t// Mark as stopping requested.\n\t\t\t\tcrane.MarkStoppingRequested()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/captain/op_gossip.go",
    "content": "package captain\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/varint\"\n)\n\n// GossipOpType is the type ID of the gossip operation.\nconst GossipOpType string = \"gossip\"\n\n// GossipMsgType is the gossip message type.\ntype GossipMsgType uint8\n\n// Gossip Message Types.\nconst (\n\tGossipHubAnnouncementMsg GossipMsgType = 1\n\tGossipHubStatusMsg       GossipMsgType = 2\n)\n\nfunc (msgType GossipMsgType) String() string {\n\tswitch msgType {\n\tcase GossipHubAnnouncementMsg:\n\t\treturn \"hub announcement\"\n\tcase GossipHubStatusMsg:\n\t\treturn \"hub status\"\n\tdefault:\n\t\treturn \"unknown gossip msg\"\n\t}\n}\n\n// GossipOp is used to gossip Hub messages.\ntype GossipOp struct {\n\tterminal.OperationBase\n\n\tcraneID string\n}\n\n// Type returns the type ID.\nfunc (op *GossipOp) Type() string {\n\treturn GossipOpType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     GossipOpType,\n\t\tRequires: terminal.IsCraneController,\n\t\tStart:    runGossipOp,\n\t})\n}\n\n// NewGossipOp start a new gossip operation.\nfunc NewGossipOp(controller *docks.CraneControllerTerminal) (*GossipOp, *terminal.Error) {\n\t// Create and init.\n\top := &GossipOp{\n\t\tcraneID: controller.Crane.ID,\n\t}\n\terr := controller.StartOperation(op, nil, 1*time.Minute)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\top.InitOperationBase(controller, op.ID())\n\n\t// Register and return.\n\tregisterGossipOp(controller.Crane.ID, op)\n\treturn op, nil\n}\n\nfunc runGossipOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Check if we are run by a controller.\n\tcontroller, ok := t.(*docks.CraneControllerTerminal)\n\tif !ok {\n\t\treturn nil, terminal.ErrIncorrectUsage.With(\"gossip op may only be started by a crane controller terminal, but was started by %T\", t)\n\t}\n\n\t// Create, init, register and return.\n\top := &GossipOp{\n\t\tcraneID: controller.Crane.ID,\n\t}\n\top.InitOperationBase(t, opID)\n\tregisterGossipOp(controller.Crane.ID, op)\n\treturn op, nil\n}\n\nfunc (op *GossipOp) sendMsg(msgType GossipMsgType, data []byte) {\n\t// Create message.\n\tmsg := op.NewEmptyMsg()\n\tmsg.Data = container.New(\n\t\tvarint.Pack8(uint8(msgType)),\n\t\tdata,\n\t)\n\tmsg.Unit.MakeHighPriority()\n\n\t// Send.\n\terr := op.Send(msg, 1*time.Second)\n\tif err != nil {\n\t\tlog.Debugf(\"spn/captain: failed to forward %s via %s: %s\", msgType, op.craneID, err)\n\t}\n}\n\n// Deliver delivers a message to the operation.\nfunc (op *GossipOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\tdefer msg.Finish()\n\n\tgossipMsgTypeN, err := msg.Data.GetNextN8()\n\tif err != nil {\n\t\treturn terminal.ErrMalformedData.With(\"failed to parse gossip message type\")\n\t}\n\tgossipMsgType := GossipMsgType(gossipMsgTypeN)\n\n\t// Prepare data.\n\tdata := msg.Data.CompileData()\n\tvar announcementData, statusData []byte\n\tswitch gossipMsgType {\n\tcase GossipHubAnnouncementMsg:\n\t\tannouncementData = data\n\tcase GossipHubStatusMsg:\n\t\tstatusData = data\n\tdefault:\n\t\tlog.Warningf(\"spn/captain: received unknown gossip message type from %s: %d\", op.craneID, gossipMsgType)\n\t\treturn nil\n\t}\n\n\t// Import and verify.\n\th, forward, tErr := docks.ImportAndVerifyHubInfo(module.mgr.Ctx(), \"\", announcementData, statusData, conf.MainMapName, conf.MainMapScope)\n\tif tErr != nil {\n\t\tif tErr.Is(hub.ErrOldData) {\n\t\t\tlog.Debugf(\"spn/captain: ignoring old %s from %s\", gossipMsgType, op.craneID)\n\t\t} else {\n\t\t\tlog.Warningf(\"spn/captain: failed to import %s from %s: %s\", gossipMsgType, op.craneID, tErr)\n\t\t}\n\t} else if forward {\n\t\t// Only log if we received something to save/forward.\n\t\tlog.Infof(\"spn/captain: received %s for %s\", gossipMsgType, h)\n\t}\n\n\t// Relay data.\n\tif forward {\n\t\tgossipRelayMsg(op.craneID, gossipMsgType, data)\n\t}\n\treturn nil\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *GossipOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {\n\tdeleteGossipOp(op.craneID)\n\treturn err\n}\n"
  },
  {
    "path": "spn/captain/op_gossip_query.go",
    "content": "package captain\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/varint\"\n)\n\n// GossipQueryOpType is the type ID of the gossip query operation.\nconst GossipQueryOpType string = \"gossip/query\"\n\n// GossipQueryOp is used to query gossip messages.\ntype GossipQueryOp struct {\n\tterminal.OperationBase\n\n\tt         terminal.Terminal\n\tclient    bool\n\timportCnt int\n\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n}\n\n// Type returns the type ID.\nfunc (op *GossipQueryOp) Type() string {\n\treturn GossipQueryOpType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     GossipQueryOpType,\n\t\tRequires: terminal.IsCraneController,\n\t\tStart:    runGossipQueryOp,\n\t})\n}\n\n// NewGossipQueryOp starts a new gossip query operation.\nfunc NewGossipQueryOp(t terminal.Terminal) (*GossipQueryOp, *terminal.Error) {\n\t// Create and init.\n\top := &GossipQueryOp{\n\t\tt:      t,\n\t\tclient: true,\n\t}\n\top.ctx, op.cancelCtx = context.WithCancel(t.Ctx())\n\terr := t.StartOperation(op, nil, 1*time.Minute)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn op, nil\n}\n\nfunc runGossipQueryOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Create, init, register and return.\n\top := &GossipQueryOp{t: t}\n\top.ctx, op.cancelCtx = context.WithCancel(t.Ctx())\n\top.InitOperationBase(t, opID)\n\n\tmodule.mgr.Go(\"gossip query handler\", op.handler)\n\n\treturn op, nil\n}\n\nfunc (op *GossipQueryOp) handler(_ *mgr.WorkerCtx) error {\n\ttErr := op.sendMsgs(hub.MsgTypeAnnouncement)\n\tif tErr != nil {\n\t\top.Stop(op, tErr)\n\t\treturn nil // Clean worker exit.\n\t}\n\n\ttErr = op.sendMsgs(hub.MsgTypeStatus)\n\tif tErr != nil {\n\t\top.Stop(op, tErr)\n\t\treturn nil // Clean worker exit.\n\t}\n\n\top.Stop(op, nil)\n\treturn nil // Clean worker exit.\n}\n\nfunc (op *GossipQueryOp) sendMsgs(msgType hub.MsgType) *terminal.Error {\n\tit, err := hub.QueryRawGossipMsgs(conf.MainMapName, msgType)\n\tif err != nil {\n\t\treturn terminal.ErrInternalError.With(\"failed to query: %w\", err)\n\t}\n\tdefer it.Cancel()\n\niterating:\n\tfor {\n\t\tselect {\n\t\tcase r := <-it.Next:\n\t\t\t// Check if we are done.\n\t\t\tif r == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Ensure we're handling a hub msg.\n\t\t\thubMsg, err := hub.EnsureHubMsg(r)\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"spn/captain: failed to load hub msg: %s\", err)\n\t\t\t\tcontinue iterating\n\t\t\t}\n\n\t\t\t// Create gossip msg.\n\t\t\tvar c *container.Container\n\t\t\tswitch hubMsg.Type {\n\t\t\tcase hub.MsgTypeAnnouncement:\n\t\t\t\tc = container.New(\n\t\t\t\t\tvarint.Pack8(uint8(GossipHubAnnouncementMsg)),\n\t\t\t\t\thubMsg.Data,\n\t\t\t\t)\n\t\t\tcase hub.MsgTypeStatus:\n\t\t\t\tc = container.New(\n\t\t\t\t\tvarint.Pack8(uint8(GossipHubStatusMsg)),\n\t\t\t\t\thubMsg.Data,\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\tlog.Warningf(\"spn/captain: unknown hub msg for gossip query at %q: %s\", hubMsg.Key(), hubMsg.Type)\n\t\t\t}\n\n\t\t\t// Send msg.\n\t\t\tif c != nil {\n\t\t\t\tmsg := op.NewEmptyMsg()\n\t\t\t\tmsg.Unit.MakeHighPriority()\n\t\t\t\tmsg.Data = c\n\t\t\t\ttErr := op.Send(msg, 1*time.Second)\n\t\t\t\tif tErr != nil {\n\t\t\t\t\treturn tErr.Wrap(\"failed to send msg\")\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase <-op.ctx.Done():\n\t\t\treturn terminal.ErrStopping\n\t\t}\n\t}\n}\n\n// Deliver delivers the message to the operation.\nfunc (op *GossipQueryOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\tdefer msg.Finish()\n\n\tgossipMsgTypeN, err := msg.Data.GetNextN8()\n\tif err != nil {\n\t\treturn terminal.ErrMalformedData.With(\"failed to parse gossip message type\")\n\t}\n\tgossipMsgType := GossipMsgType(gossipMsgTypeN)\n\n\t// Prepare data.\n\tdata := msg.Data.CompileData()\n\tvar announcementData, statusData []byte\n\tswitch gossipMsgType {\n\tcase GossipHubAnnouncementMsg:\n\t\tannouncementData = data\n\tcase GossipHubStatusMsg:\n\t\tstatusData = data\n\tdefault:\n\t\tlog.Warningf(\"spn/captain: received unknown gossip message type from gossip query: %d\", gossipMsgType)\n\t\treturn nil\n\t}\n\n\t// Import and verify.\n\th, forward, tErr := docks.ImportAndVerifyHubInfo(module.mgr.Ctx(), \"\", announcementData, statusData, conf.MainMapName, conf.MainMapScope)\n\tif tErr != nil {\n\t\tlog.Warningf(\"spn/captain: failed to import %s from gossip query: %s\", gossipMsgType, tErr)\n\t} else {\n\t\tlog.Infof(\"spn/captain: received %s for %s from gossip query\", gossipMsgType, h)\n\t\top.importCnt++\n\t}\n\n\t// Relay data.\n\tif forward {\n\t\t// TODO: Find better way to get craneID.\n\t\tcraneID := strings.SplitN(op.t.FmtID(), \"#\", 2)[0]\n\t\tgossipRelayMsg(craneID, gossipMsgType, data)\n\t}\n\treturn nil\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *GossipQueryOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {\n\tif op.client {\n\t\tlog.Infof(\"spn/captain: gossip query imported %d entries\", op.importCnt)\n\t}\n\top.cancelCtx()\n\treturn err\n}\n"
  },
  {
    "path": "spn/captain/op_publish.go",
    "content": "package captain\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n)\n\n// PublishOpType is the type ID of the publish operation.\nconst PublishOpType string = \"publish\"\n\n// PublishOp is used to publish a connection.\ntype PublishOp struct {\n\tterminal.OperationBase\n\tcontroller *docks.CraneControllerTerminal\n\n\tidentity      *cabin.Identity\n\trequestingHub *hub.Hub\n\tverification  *cabin.Verification\n\tresult        chan *terminal.Error\n}\n\n// Type returns the type ID.\nfunc (op *PublishOp) Type() string {\n\treturn PublishOpType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     PublishOpType,\n\t\tRequires: terminal.IsCraneController,\n\t\tStart:    runPublishOp,\n\t})\n}\n\n// NewPublishOp start a new publish operation.\nfunc NewPublishOp(controller *docks.CraneControllerTerminal, identity *cabin.Identity) (*PublishOp, *terminal.Error) {\n\t// Create and init.\n\top := &PublishOp{\n\t\tcontroller: controller,\n\t\tidentity:   identity,\n\t\tresult:     make(chan *terminal.Error, 1),\n\t}\n\tmsg := container.New()\n\n\t// Add Hub Announcement.\n\tannouncementData, err := identity.ExportAnnouncement()\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to export announcement: %w\", err)\n\t}\n\tmsg.AppendAsBlock(announcementData)\n\n\t// Add Hub Status.\n\tstatusData, err := identity.ExportStatus()\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to export status: %w\", err)\n\t}\n\tmsg.AppendAsBlock(statusData)\n\n\ttErr := controller.StartOperation(op, msg, 10*time.Second)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\treturn op, nil\n}\n\nfunc runPublishOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Check if we are run by a controller.\n\tcontroller, ok := t.(*docks.CraneControllerTerminal)\n\tif !ok {\n\t\treturn nil, terminal.ErrIncorrectUsage.With(\"publish op may only be started by a crane controller terminal, but was started by %T\", t)\n\t}\n\n\t// Parse and import Announcement and Status.\n\tannouncementData, err := data.GetNextBlock()\n\tif err != nil {\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to get announcement: %w\", err)\n\t}\n\tstatusData, err := data.GetNextBlock()\n\tif err != nil {\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to get status: %w\", err)\n\t}\n\th, forward, tErr := docks.ImportAndVerifyHubInfo(module.mgr.Ctx(), \"\", announcementData, statusData, conf.MainMapName, conf.MainMapScope)\n\tif tErr != nil {\n\t\treturn nil, tErr.Wrap(\"failed to import and verify hub\")\n\t}\n\t// Update reference in case it was changed by the import.\n\tcontroller.Crane.ConnectedHub = h\n\n\t// Relay data.\n\tif forward {\n\t\tgossipRelayMsg(controller.Crane.ID, GossipHubAnnouncementMsg, announcementData)\n\t\tgossipRelayMsg(controller.Crane.ID, GossipHubStatusMsg, statusData)\n\t}\n\n\t// Create verification request.\n\tv, request, err := cabin.CreateVerificationRequest(PublishOpType, \"\", \"\")\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to create verification request: %w\", err)\n\t}\n\n\t// Create operation.\n\top := &PublishOp{\n\t\tcontroller:    controller,\n\t\trequestingHub: h,\n\t\tverification:  v,\n\t\tresult:        make(chan *terminal.Error, 1),\n\t}\n\top.InitOperationBase(controller, opID)\n\n\t// Reply with verification request.\n\ttErr = op.Send(op.NewMsg(request), 10*time.Second)\n\tif tErr != nil {\n\t\treturn nil, tErr.Wrap(\"failed to send verification request\")\n\t}\n\n\treturn op, nil\n}\n\n// Deliver delivers a message to the operation.\nfunc (op *PublishOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\tdefer msg.Finish()\n\n\tif op.identity != nil {\n\t\t// Client\n\n\t\t// Sign the received verification request.\n\t\tresponse, err := op.identity.SignVerificationRequest(msg.Data.CompileData(), PublishOpType, \"\", \"\")\n\t\tif err != nil {\n\t\t\treturn terminal.ErrPermissionDenied.With(\"signing verification request failed: %w\", err)\n\t\t}\n\n\t\treturn op.Send(op.NewMsg(response), 10*time.Second)\n\t} else if op.requestingHub != nil {\n\t\t// Server\n\n\t\t// Verify the signed request.\n\t\terr := op.verification.Verify(msg.Data.CompileData(), op.requestingHub)\n\t\tif err != nil {\n\t\t\treturn terminal.ErrPermissionDenied.With(\"checking verification request failed: %w\", err)\n\t\t}\n\t\treturn terminal.ErrExplicitAck\n\t}\n\n\treturn terminal.ErrInternalError.With(\"invalid operation state\")\n}\n\n// Result returns the result (end error) of the operation.\nfunc (op *PublishOp) Result() <-chan *terminal.Error {\n\treturn op.result\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *PublishOp) HandleStop(tErr *terminal.Error) (errorToSend *terminal.Error) {\n\tif tErr.Is(terminal.ErrExplicitAck) {\n\t\t// TODO: Check for concurrenct access.\n\t\tif op.controller.Crane.ConnectedHub == nil {\n\t\t\top.controller.Crane.ConnectedHub = op.requestingHub\n\t\t}\n\n\t\t// Publish crane, abort if it fails.\n\t\terr := op.controller.Crane.Publish()\n\t\tif err != nil {\n\t\t\ttErr = terminal.ErrInternalError.With(\"failed to publish crane: %w\", err)\n\t\t\top.controller.Crane.Stop(tErr)\n\t\t} else {\n\t\t\top.controller.Crane.NotifyUpdate()\n\t\t}\n\t}\n\n\tselect {\n\tcase op.result <- tErr:\n\tdefault:\n\t}\n\treturn tErr\n}\n"
  },
  {
    "path": "spn/captain/piers.go",
    "content": "package captain\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/ships\"\n)\n\nvar (\n\tdockingRequests = make(chan ships.Ship, 100)\n\tpiers           []ships.Pier\n)\n\nfunc startPiers() error {\n\t// Get and check transports.\n\ttransports := publicIdentity.Hub.Info.Transports\n\tif len(transports) == 0 {\n\t\treturn errors.New(\"no transports defined\")\n\t}\n\n\tpiers = make([]ships.Pier, 0, len(transports))\n\tfor _, t := range transports {\n\t\t// Parse transport.\n\t\ttransport, err := hub.ParseTransport(t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot build pier for invalid transport %q: %w\", t, err)\n\t\t}\n\n\t\t// Establish pier / listener.\n\t\tpier, err := ships.EstablishPier(transport, dockingRequests)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to establish pier for transport %q: %w\", t, err)\n\t\t}\n\n\t\tpiers = append(piers, pier)\n\t\tlog.Infof(\"spn/captain: pier for transport %q built\", t)\n\t}\n\n\t// Start worker to handle docking requests.\n\tmodule.mgr.Go(\"docking request handler\", dockingRequestHandler)\n\n\treturn nil\n}\n\nfunc stopPiers() {\n\tfor _, pier := range piers {\n\t\tpier.Abolish()\n\t}\n}\n\nfunc dockingRequestHandler(wc *mgr.WorkerCtx) error {\n\t// Sink all waiting ships when this worker ends.\n\t// But don't be destructive so the service worker could recover.\n\tdefer func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase ship := <-dockingRequests:\n\t\t\t\tif ship != nil {\n\t\t\t\t\tship.Sink()\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-wc.Done():\n\t\t\treturn nil\n\t\tcase ship := <-dockingRequests:\n\t\t\t// Ignore nil ships.\n\t\t\tif ship == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := checkDockingPermission(wc.Ctx(), ship); err != nil {\n\t\t\t\tlog.Warningf(\"spn/captain: denied ship from %s to dock at pier %s: %s\", ship.RemoteAddr(), ship.Transport().String(), err)\n\t\t\t} else {\n\t\t\t\thandleDockingRequest(ship)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc checkDockingPermission(ctx context.Context, ship ships.Ship) error {\n\tremoteIP, remotePort, err := netutils.IPPortFromAddr(ship.RemoteAddr())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse remote IP: %w\", err)\n\t}\n\n\t// Create entity.\n\tentity := (&intel.Entity{\n\t\tIP:       remoteIP,\n\t\tProtocol: uint8(netutils.ProtocolFromNetwork(ship.RemoteAddr().Network())),\n\t\tPort:     remotePort,\n\t}).Init(ship.Transport().Port)\n\tentity.FetchData(ctx)\n\n\t// Check against policy.\n\tresult, reason := publicIdentity.Hub.GetInfo().EntryPolicy().Match(ctx, entity)\n\tif result == endpoints.Denied {\n\t\treturn fmt.Errorf(\"entry policy violated: %s\", reason)\n\t}\n\n\treturn nil\n}\n\nfunc handleDockingRequest(ship ships.Ship) {\n\tlog.Infof(\"spn/captain: pemitting %s to dock\", ship)\n\n\tcrane, err := docks.NewCrane(ship, nil, publicIdentity)\n\tif err != nil {\n\t\tlog.Warningf(\"spn/captain: failed to commission crane for %s: %s\", ship, err)\n\t\treturn\n\t}\n\n\tmodule.mgr.Go(\"start crane\", func(wc *mgr.WorkerCtx) error {\n\t\t_ = crane.Start(wc.Ctx())\n\t\t// Crane handles errors internally.\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "spn/captain/public.go",
    "content": "package captain\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/patrol\"\n)\n\nconst (\n\tmaintainStatusInterval    = 15 * time.Minute\n\tmaintainStatusUpdateDelay = 5 * time.Second\n)\n\nvar (\n\tpublicIdentity    *cabin.Identity\n\tpublicIdentityKey = \"core:spn/public/identity\"\n)\n\nfunc loadPublicIdentity() (err error) {\n\tvar changed bool\n\n\tpublicIdentity, changed, err = cabin.LoadIdentity(publicIdentityKey)\n\tswitch {\n\tcase err == nil:\n\t\t// load was successful\n\t\tlog.Infof(\"spn/captain: loaded public hub identity %s\", publicIdentity.Hub.ID)\n\tcase errors.Is(err, database.ErrNotFound):\n\t\t// does not exist, create new\n\t\tpublicIdentity, err = cabin.CreateIdentity(module.mgr.Ctx(), conf.MainMapName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create new identity: %w\", err)\n\t\t}\n\t\tpublicIdentity.SetKey(publicIdentityKey)\n\t\tchanged = true\n\n\t\tlog.Infof(\"spn/captain: created new public hub identity %s\", publicIdentity.ID)\n\tdefault:\n\t\t// loading error, abort\n\t\treturn fmt.Errorf(\"failed to load public identity: %w\", err)\n\t}\n\n\t// Save to database if the identity changed.\n\tif changed {\n\t\terr = publicIdentity.Save()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to save new/updated identity to database: %w\", err)\n\t\t}\n\t}\n\n\t// Set available networks.\n\tconf.SetHubNetworks(\n\t\tpublicIdentity.Hub.Info.IPv4 != nil,\n\t\tpublicIdentity.Hub.Info.IPv6 != nil,\n\t)\n\tif cfgOptionBindToAdvertised() {\n\t\tconf.SetBindAddr(publicIdentity.Hub.Info.IPv4, publicIdentity.Hub.Info.IPv6)\n\t}\n\n\t// Set Home Hub before updating the hub on the map, as this would trigger a\n\t// recalculation without a Home Hub.\n\tok := navigator.Main.SetHome(publicIdentity.ID, nil)\n\t// Always update the navigator in any case in order to sync the reference to\n\t// the active struct of the identity.\n\tnavigator.Main.UpdateHub(publicIdentity.Hub)\n\t// Setting the Home Hub will have failed if the identidy was only just\n\t// created - try again if it failed.\n\tif !ok {\n\t\tok = navigator.Main.SetHome(publicIdentity.ID, nil)\n\t\tif !ok {\n\t\t\treturn errors.New(\"failed to set self as home hub\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc prepPublicIdentityMgmt() error {\n\tmodule.statusUpdater.Repeat(maintainStatusInterval)\n\n\tmodule.instance.Config().EventConfigChange.AddCallback(\"update public identity from config\",\n\t\tfunc(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {\n\t\t\tmodule.publicIdentityUpdater.Delay(5 * time.Minute)\n\t\t\treturn false, nil\n\t\t})\n\treturn nil\n}\n\n// TriggerHubStatusMaintenance queues the Hub status update task to be executed.\nfunc TriggerHubStatusMaintenance() {\n\tmodule.statusUpdater.Go()\n}\n\nfunc maintainPublicIdentity(_ *mgr.WorkerCtx) error {\n\tchanged, err := publicIdentity.MaintainAnnouncement(nil, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to maintain announcement: %w\", err)\n\t}\n\n\tif !changed {\n\t\treturn nil\n\t}\n\n\t// Update on map.\n\tnavigator.Main.UpdateHub(publicIdentity.Hub)\n\tlog.Debug(\"spn/captain: updated own hub on map after announcement change\")\n\n\t// export announcement\n\tannouncementData, err := publicIdentity.ExportAnnouncement()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to export announcement: %w\", err)\n\t}\n\n\t// forward to other connected Hubs\n\tgossipRelayMsg(\"\", GossipHubAnnouncementMsg, announcementData)\n\n\treturn nil\n}\n\nfunc maintainPublicStatus(ctx *mgr.WorkerCtx) error {\n\t// Get current lanes.\n\tcranes := docks.GetAllAssignedCranes()\n\tlanes := make([]*hub.Lane, 0, len(cranes))\n\tfor _, crane := range cranes {\n\t\t// Ignore private, stopped or stopping cranes.\n\t\tif !crane.Public() || crane.Stopped() || crane.IsStopping() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get measurements.\n\t\tmeasurements := crane.ConnectedHub.GetMeasurements()\n\t\tlatency, _ := measurements.GetLatency()\n\t\tcapacity, _ := measurements.GetCapacity()\n\n\t\t// Add crane lane.\n\t\tlanes = append(lanes, &hub.Lane{\n\t\t\tID:       crane.ConnectedHub.ID,\n\t\t\tLatency:  latency,\n\t\t\tCapacity: capacity,\n\t\t})\n\t}\n\t// Sort Lanes for comparing.\n\thub.SortLanes(lanes)\n\n\t// Get system load and convert to fixed steps.\n\tvar load int\n\tloadAvg, ok := metrics.LoadAvg15()\n\tswitch {\n\tcase !ok:\n\t\tload = -1\n\tcase loadAvg >= 1:\n\t\tload = 100\n\tcase loadAvg >= 0.95:\n\t\tload = 95\n\tcase loadAvg >= 0.8:\n\t\tload = 80\n\tdefault:\n\t\tload = 0\n\t}\n\tif loadAvg >= 0.8 {\n\t\tlog.Warningf(\"spn/captain: publishing 15m system load average of %.2f as %d\", loadAvg, load)\n\t}\n\n\t// Set flags.\n\tvar flags []string\n\tif !patrol.HTTPSConnectivityConfirmed() {\n\t\tflags = append(flags, hub.FlagNetError)\n\t}\n\t// Sort Lanes for comparing.\n\tsort.Strings(flags)\n\n\t// Run maintenance with the new data.\n\tchanged, err := publicIdentity.MaintainStatus(lanes, &load, flags, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to maintain status: %w\", err)\n\t}\n\n\tif !changed {\n\t\treturn nil\n\t}\n\n\t// Update on map.\n\tnavigator.Main.UpdateHub(publicIdentity.Hub)\n\tlog.Debug(\"spn/captain: updated own hub on map after status change\")\n\n\t// export status\n\tstatusData, err := publicIdentity.ExportStatus()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to export status: %w\", err)\n\t}\n\n\t// forward to other connected Hubs\n\tgossipRelayMsg(\"\", GossipHubStatusMsg, statusData)\n\n\tlog.Infof(\n\t\t\"spn/captain: updated status with load %d and current lanes: %v\",\n\t\tpublicIdentity.Hub.Status.Load,\n\t\tpublicIdentity.Hub.Status.Lanes,\n\t)\n\treturn nil\n}\n\nfunc publishShutdownStatus() {\n\t// Create offline status.\n\tofflineStatusData, err := publicIdentity.MakeOfflineStatus()\n\tif err != nil {\n\t\tlog.Errorf(\"spn/captain: failed to create offline status: %s\", err)\n\t\treturn\n\t}\n\n\t// Forward to other connected Hubs.\n\tgossipRelayMsg(\"\", GossipHubStatusMsg, offlineStatusData)\n\n\t// Leave some time for the message to broadcast.\n\ttime.Sleep(2 * time.Second)\n\n\tlog.Infof(\"spn/captain: broadcasted offline status\")\n}\n"
  },
  {
    "path": "spn/captain/status.go",
    "content": "package captain\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n)\n\n// SPNStatus holds SPN status information.\ntype SPNStatus struct {\n\trecord.Base\n\tsync.Mutex\n\n\tStatus             SPNStatusName\n\tHomeHubID          string\n\tHomeHubName        string\n\tConnectedIP        string\n\tConnectedTransport string\n\tConnectedCountry   *geoip.CountryInfo\n\tConnectedSince     *time.Time\n}\n\n// SPNStatusName is a SPN status.\ntype SPNStatusName string\n\n// SPN Stati.\nconst (\n\tStatusFailed     SPNStatusName = \"failed\"\n\tStatusDisabled   SPNStatusName = \"disabled\"\n\tStatusConnecting SPNStatusName = \"connecting\"\n\tStatusConnected  SPNStatusName = \"connected\"\n)\n\nvar (\n\tspnStatus = &SPNStatus{\n\t\tStatus: StatusDisabled,\n\t}\n\tspnStatusPushFunc runtime.PushFunc\n)\n\nfunc registerSPNStatusProvider() (err error) {\n\tspnStatus.SetKey(\"runtime:spn/status\")\n\tspnStatus.UpdateMeta()\n\tspnStatusPushFunc, err = runtime.Register(\"spn/status\", runtime.ProvideRecord(spnStatus))\n\treturn\n}\n\nfunc resetSPNStatus(statusName SPNStatusName, overrideEvenIfConnected bool) {\n\t// Lock for updating values.\n\tspnStatus.Lock()\n\tdefer spnStatus.Unlock()\n\n\t// Ignore when connected and not overriding\n\tif !overrideEvenIfConnected && spnStatus.Status == StatusConnected {\n\t\treturn\n\t}\n\n\t// Reset status.\n\tspnStatus.Status = statusName\n\tspnStatus.HomeHubID = \"\"\n\tspnStatus.HomeHubName = \"\"\n\tspnStatus.ConnectedIP = \"\"\n\tspnStatus.ConnectedTransport = \"\"\n\tspnStatus.ConnectedCountry = nil\n\tspnStatus.ConnectedSince = nil\n\n\t// Push new status.\n\tpushSPNStatusUpdate()\n}\n\n// pushSPNStatusUpdate pushes an update of spnStatus, which must be locked.\nfunc pushSPNStatusUpdate() {\n\tspnStatus.UpdateMeta()\n\tspnStatusPushFunc(spnStatus)\n}\n\n// GetSPNStatus returns the current SPN status.\nfunc GetSPNStatus() *SPNStatus {\n\tspnStatus.Lock()\n\tdefer spnStatus.Unlock()\n\n\treturn &SPNStatus{\n\t\tStatus:             spnStatus.Status,\n\t\tHomeHubID:          spnStatus.HomeHubID,\n\t\tHomeHubName:        spnStatus.HomeHubName,\n\t\tConnectedIP:        spnStatus.ConnectedIP,\n\t\tConnectedTransport: spnStatus.ConnectedTransport,\n\t\tConnectedCountry:   spnStatus.ConnectedCountry,\n\t\tConnectedSince:     spnStatus.ConnectedSince,\n\t}\n}\n\n// AddToDebugInfo adds the SPN status to the given debug.Info.\nfunc AddToDebugInfo(di *debug.Info) {\n\tspnStatus.Lock()\n\tdefer spnStatus.Unlock()\n\n\t// Check if SPN module is enabled.\n\tvar moduleStatus string\n\tspnEnabled := config.GetAsBool(CfgOptionEnableSPNKey, false)\n\tif spnEnabled() {\n\t\tmoduleStatus = \"enabled\"\n\t} else {\n\t\tmoduleStatus = \"disabled\"\n\t}\n\n\t// Collect status data.\n\tlines := make([]string, 0, 20)\n\tlines = append(lines, fmt.Sprintf(\"HomeHubID:    %v\", spnStatus.HomeHubID))\n\tlines = append(lines, fmt.Sprintf(\"HomeHubName:  %v\", spnStatus.HomeHubName))\n\tlines = append(lines, fmt.Sprintf(\"HomeHubIP:    %v\", spnStatus.ConnectedIP))\n\tlines = append(lines, fmt.Sprintf(\"Transport:    %v\", spnStatus.ConnectedTransport))\n\tif spnStatus.ConnectedSince != nil {\n\t\tlines = append(lines, fmt.Sprintf(\"Connected:    %v ago\", time.Since(*spnStatus.ConnectedSince).Round(time.Minute)))\n\t}\n\tlines = append(lines, \"---\")\n\tlines = append(lines, fmt.Sprintf(\"Client:       %v\", conf.Client()))\n\tlines = append(lines, fmt.Sprintf(\"PublicHub:    %v\", conf.PublicHub()))\n\tlines = append(lines, fmt.Sprintf(\"HubHasIPv4:   %v\", conf.HubHasIPv4()))\n\tlines = append(lines, fmt.Sprintf(\"HubHasIPv6:   %v\", conf.HubHasIPv6()))\n\n\t// Collect status data of map.\n\tif navigator.Main != nil {\n\t\tlines = append(lines, \"---\")\n\t\tmainMapStats := navigator.Main.Stats()\n\t\tlines = append(lines, fmt.Sprintf(\"Map %s:\", navigator.Main.Name))\n\t\tlines = append(lines, fmt.Sprintf(\"Active Terminals: %d Hubs\", mainMapStats.ActiveTerminals))\n\t\t// Collect hub states.\n\t\tmapStateSummary := make([]string, 0, len(mainMapStats.States))\n\t\tfor state, cnt := range mainMapStats.States {\n\t\t\tif cnt > 0 {\n\t\t\t\tmapStateSummary = append(mapStateSummary, fmt.Sprintf(\"State %s: %d Hubs\", state, cnt))\n\t\t\t}\n\t\t}\n\t\tsort.Strings(mapStateSummary)\n\t\tlines = append(lines, mapStateSummary...)\n\t}\n\n\t// Add all data as section.\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"SPN: %s (module %s)\", spnStatus.Status, moduleStatus),\n\t\tdebug.UseCodeSection|debug.AddContentLineBreaks,\n\t\tlines...,\n\t)\n}\n"
  },
  {
    "path": "spn/conf/map.go",
    "content": "package conf\n\nimport (\n\t\"flag\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// Primary Map Configuration.\nvar (\n\tMainMapName  = \"main\"\n\tMainMapScope = hub.ScopePublic\n)\n\nfunc init() {\n\tflag.StringVar(&MainMapName, \"spn-map\", \"main\", \"set main SPN map - use only for testing\")\n}\n"
  },
  {
    "path": "spn/conf/mode.go",
    "content": "package conf\n\nimport (\n\t\"sync/atomic\"\n)\n\nvar (\n\tpublicHub  atomic.Bool\n\tclient     atomic.Bool\n\tintegrated atomic.Bool\n)\n\n// PublicHub returns whether this is a public Hub.\nfunc PublicHub() bool {\n\treturn publicHub.Load()\n}\n\n// EnablePublicHub enables the public hub mode.\nfunc EnablePublicHub(enable bool) {\n\tpublicHub.Store(enable)\n}\n\n// Client returns whether this is a client.\nfunc Client() bool {\n\treturn client.Load()\n}\n\n// EnableClient enables the client mode.\nfunc EnableClient(enable bool) {\n\tclient.Store(enable)\n}\n\n// Integrated returns whether SPN is running integrated into Portmaster.\nfunc Integrated() bool {\n\treturn integrated.Load()\n}\n\n// EnableIntegration enables the integrated mode.\nfunc EnableIntegration(enable bool) {\n\tintegrated.Store(enable)\n}\n"
  },
  {
    "path": "spn/conf/networks.go",
    "content": "package conf\n\nimport (\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/tevino/abool\"\n)\n\nvar (\n\thubHasV4 = abool.New()\n\thubHasV6 = abool.New()\n)\n\n// SetHubNetworks sets the available IP networks on the Hub.\nfunc SetHubNetworks(v4, v6 bool) {\n\thubHasV4.SetTo(v4)\n\thubHasV6.SetTo(v6)\n}\n\n// HubHasIPv4 returns whether the Hub has IPv4 support.\nfunc HubHasIPv4() bool {\n\treturn hubHasV4.IsSet()\n}\n\n// HubHasIPv6 returns whether the Hub has IPv6 support.\nfunc HubHasIPv6() bool {\n\treturn hubHasV6.IsSet()\n}\n\nvar (\n\tbindIPv4   net.IP\n\tbindIPv6   net.IP\n\tbindIPLock sync.Mutex\n)\n\n// SetBindAddr sets the preferred connect (bind) addresses.\nfunc SetBindAddr(ip4, ip6 net.IP) {\n\tbindIPLock.Lock()\n\tdefer bindIPLock.Unlock()\n\n\tbindIPv4 = ip4\n\tbindIPv6 = ip6\n}\n\n// BindAddrIsSet returns whether any bind address is set.\nfunc BindAddrIsSet() bool {\n\tbindIPLock.Lock()\n\tdefer bindIPLock.Unlock()\n\n\treturn bindIPv4 != nil || bindIPv6 != nil\n}\n\n// GetBindAddr returns an address with the preferred binding address for the\n// given dial network.\n// The dial network must have a suffix specifying the IP version.\nfunc GetBindAddr(dialNetwork string) net.Addr {\n\tbindIPLock.Lock()\n\tdefer bindIPLock.Unlock()\n\n\tswitch dialNetwork {\n\tcase \"ip4\":\n\t\tif bindIPv4 != nil {\n\t\t\treturn &net.IPAddr{IP: bindIPv4}\n\t\t}\n\tcase \"ip6\":\n\t\tif bindIPv6 != nil {\n\t\t\treturn &net.IPAddr{IP: bindIPv6}\n\t\t}\n\tcase \"tcp4\":\n\t\tif bindIPv4 != nil {\n\t\t\treturn &net.TCPAddr{IP: bindIPv4}\n\t\t}\n\tcase \"tcp6\":\n\t\tif bindIPv6 != nil {\n\t\t\treturn &net.TCPAddr{IP: bindIPv6}\n\t\t}\n\tcase \"udp4\":\n\t\tif bindIPv4 != nil {\n\t\t\treturn &net.UDPAddr{IP: bindIPv4}\n\t\t}\n\tcase \"udp6\":\n\t\tif bindIPv6 != nil {\n\t\t\treturn &net.UDPAddr{IP: bindIPv6}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// GetBindIPs returns the preferred binding IPs.\n// Returns a slice with a single nil IP if no preferred binding IPs are set.\nfunc GetBindIPs() []net.IP {\n\tbindIPLock.Lock()\n\tdefer bindIPLock.Unlock()\n\n\tswitch {\n\tcase bindIPv4 == nil && bindIPv6 == nil:\n\t\t// Match most common case first.\n\t\treturn []net.IP{nil}\n\tcase bindIPv4 != nil && bindIPv6 != nil:\n\t\treturn []net.IP{bindIPv4, bindIPv6}\n\tcase bindIPv4 != nil:\n\t\treturn []net.IP{bindIPv4}\n\tcase bindIPv6 != nil:\n\t\treturn []net.IP{bindIPv6}\n\t}\n\n\treturn []net.IP{nil}\n}\n"
  },
  {
    "path": "spn/conf/version.go",
    "content": "package conf\n\nconst (\n\t// VersionOne is the first protocol version.\n\tVersionOne = 1\n\n\t// CurrentVersion always holds the newest version in production.\n\tCurrentVersion = 1\n)\n"
  },
  {
    "path": "spn/crew/connect.go",
    "content": "package crew\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\n// connectLock locks all routing operations to mitigate racy stuff for now.\n// TODO: Find a nice way to parallelize route creation.\nvar connectLock sync.Mutex\n\n// HandleSluiceRequest handles a sluice request to build a tunnel.\nfunc HandleSluiceRequest(connInfo *network.Connection, conn net.Conn) {\n\tif conn == nil {\n\t\tlog.Debugf(\"spn/crew: closing tunnel for %s before starting because of shutdown\", connInfo)\n\n\t\t// This is called within the connInfo lock.\n\t\tconnInfo.Failed(\"tunnel entry closed\", \"\")\n\t\tconnInfo.SaveWhenFinished()\n\t\treturn\n\t}\n\n\tt := &Tunnel{\n\t\tconnInfo: connInfo,\n\t\tconn:     conn,\n\t}\n\tmodule.mgr.Go(\"tunnel handler\", t.connectWorker)\n}\n\n// Tunnel represents the local information and endpoint of a data tunnel.\ntype Tunnel struct {\n\tconnInfo *network.Connection\n\tconn     net.Conn\n\n\tdstPin      *navigator.Pin\n\tdstTerminal terminal.Terminal\n\troute       *navigator.Route\n\tfailedTries int\n\tstickied    bool\n}\n\nfunc (t *Tunnel) connectWorker(wc *mgr.WorkerCtx) (err error) {\n\t// Get tracing logger.\n\tctx, tracer := log.AddTracer(wc.Ctx())\n\tdefer tracer.Submit()\n\n\t// Save start time.\n\tstarted := time.Now()\n\n\t// Check the status of the Home Hub.\n\thome, homeTerminal := navigator.Main.GetHome()\n\tif home == nil || homeTerminal == nil || homeTerminal.IsBeingAbandoned() {\n\t\treportConnectError(terminal.ErrUnknownError.With(\"home terminal is abandoned\"))\n\n\t\tt.connInfo.Lock()\n\t\tdefer t.connInfo.Unlock()\n\t\tt.connInfo.Failed(\"SPN not ready for tunneling\", \"\")\n\t\tt.connInfo.Save()\n\n\t\ttracer.Infof(\"spn/crew: not tunneling %s, as the SPN is not ready\", t.connInfo)\n\t\treturn nil\n\t}\n\n\t// Create path through the SPN.\n\terr = t.establish(ctx)\n\tif err != nil {\n\t\tlog.Warningf(\"spn/crew: failed to establish route for %s: %s\", t.connInfo, err)\n\n\t\t// TODO: Clean this up.\n\t\tt.connInfo.Lock()\n\t\tdefer t.connInfo.Unlock()\n\t\tt.connInfo.Failed(\"SPN failed to establish route: \"+err.Error(), \"\")\n\t\tt.connInfo.Save()\n\n\t\ttracer.Warningf(\"spn/crew: failed to establish route for %s: %s\", t.connInfo, err)\n\t\treturn nil\n\t}\n\n\t// Connect via established tunnel.\n\t_, tErr := NewConnectOp(t)\n\tif tErr != nil {\n\t\ttErr = tErr.Wrap(\"failed to initialize tunnel\")\n\t\treportConnectError(tErr)\n\n\t\tt.connInfo.Lock()\n\t\tdefer t.connInfo.Unlock()\n\t\tt.connInfo.Failed(\"SPN failed to initialize data tunnel (connect op): \"+tErr.Error(), \"\")\n\t\tt.connInfo.Save()\n\n\t\t// TODO: try with another route?\n\t\ttracer.Warningf(\"spn/crew: failed to initialize data tunnel (connect op) for %s: %s\", t.connInfo, err)\n\t\treturn tErr\n\t}\n\n\t// Report time taken to find, build and check route and send connect request.\n\tconnectOpTTCRDurationHistogram.UpdateDuration(started)\n\n\tt.connInfo.Lock()\n\tdefer t.connInfo.Unlock()\n\taddTunnelContextToConnection(t)\n\tt.connInfo.Save()\n\n\ttracer.Infof(\"spn/crew: connected %s via %s\", t.connInfo, t.dstPin.Hub)\n\treturn nil\n}\n\nfunc (t *Tunnel) establish(ctx context.Context) (err error) {\n\tvar routes *navigator.Routes\n\n\t// Check if the destination sticks to a Hub.\n\tsticksTo := getStickiedHub(t.connInfo)\n\tswitch {\n\tcase sticksTo == nil:\n\t\t// Continue.\n\n\tcase sticksTo.Avoid:\n\t\tlog.Tracer(ctx).Tracef(\"spn/crew: avoiding %s\", sticksTo.Pin.Hub)\n\n\t\t// Avoid this Hub.\n\t\t// TODO: Remember more than one hub to avoid.\n\t\tavoidPolicy := []endpoints.Endpoint{\n\t\t\t&endpoints.EndpointDomain{\n\t\t\t\tOriginalValue: sticksTo.Pin.Hub.ID,\n\t\t\t\tDomain:        strings.ToLower(sticksTo.Pin.Hub.ID) + \".\",\n\t\t\t},\n\t\t}\n\n\t\t// Append to policies.\n\t\tt.connInfo.TunnelOpts.Destination.HubPolicies = append(t.connInfo.TunnelOpts.Destination.HubPolicies, avoidPolicy)\n\n\tdefault:\n\t\tlog.Tracer(ctx).Tracef(\"spn/crew: using stickied %s\", sticksTo.Pin.Hub)\n\n\t\t// Check if the stickied Hub has an active terminal.\n\t\tdstTerminal := sticksTo.Pin.GetActiveTerminal()\n\t\tif dstTerminal != nil {\n\t\t\tt.dstPin = sticksTo.Pin\n\t\t\tt.dstTerminal = dstTerminal\n\t\t\tt.route = sticksTo.Route\n\t\t\tt.stickied = true\n\t\t\treturn nil\n\t\t}\n\n\t\t// If not, attempt to find a route to the stickied hub.\n\t\troutes, err = navigator.Main.FindRouteToHub(\n\t\t\tsticksTo.Pin.Hub.ID,\n\t\t\tt.connInfo.TunnelOpts,\n\t\t)\n\t\tif err != nil {\n\t\t\tlog.Tracer(ctx).Tracef(\"spn/crew: failed to find route to stickied %s: %s\", sticksTo.Pin.Hub, err)\n\t\t\troutes = nil\n\t\t} else {\n\t\t\tt.stickied = true\n\t\t}\n\t}\n\n\t// Find possible routes to destination.\n\tif routes == nil {\n\t\tlog.Tracer(ctx).Trace(\"spn/crew: finding routes...\")\n\t\troutes, err = navigator.Main.FindRoutes(\n\t\t\tt.connInfo.Entity.IP,\n\t\t\tt.connInfo.TunnelOpts,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to find routes to %s: %w\", t.connInfo.Entity.IP, err)\n\t\t}\n\t}\n\n\t// Check if routes are okay (again).\n\tif len(routes.All) == 0 {\n\t\treturn fmt.Errorf(\"no routes to %s\", t.connInfo.Entity.IP)\n\t}\n\n\t// Try routes until one succeeds.\n\tlog.Tracer(ctx).Trace(\"spn/crew: establishing route...\")\n\tvar dstPin *navigator.Pin\n\tvar dstTerminal terminal.Terminal\n\tfor tries, route := range routes.All {\n\t\tdstPin, dstTerminal, err = establishRoute(route)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Assign route data to tunnel.\n\t\tt.dstPin = dstPin\n\t\tt.dstTerminal = dstTerminal\n\t\tt.route = route\n\t\tt.failedTries = tries\n\n\t\t// Push changes to Pins and return.\n\t\tnavigator.Main.PushPinChanges()\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"failed to establish a route to %s: %w\", t.connInfo.Entity.IP, err)\n}\n\ntype hopCheck struct {\n\tpin       *navigator.Pin\n\troute     *navigator.Route\n\texpansion *docks.ExpansionTerminal\n\tauthOp    *access.AuthorizeOp\n\tpingOp    *PingOp\n}\n\nfunc establishRoute(route *navigator.Route) (dstPin *navigator.Pin, dstTerminal terminal.Terminal, err error) {\n\tconnectLock.Lock()\n\tdefer connectLock.Unlock()\n\n\t// Check for path length.\n\tif len(route.Path) < 1 {\n\t\treturn nil, nil, errors.New(\"path too short\")\n\t}\n\n\t// Check for failing hubs in path.\n\tfor _, hop := range route.Path[1:] {\n\t\tif hop.Pin().GetState().Has(navigator.StateFailing) {\n\t\t\treturn nil, nil, fmt.Errorf(\"failing hub in path: %s\", hop.Pin().Hub.Name())\n\t\t}\n\t}\n\n\t// Get home hub.\n\tpreviousHop, homeTerminal := navigator.Main.GetHome()\n\tif previousHop == nil || homeTerminal == nil {\n\t\treturn nil, nil, navigator.ErrHomeHubUnset\n\t}\n\t// Convert to interface for later use.\n\tvar previousTerminal terminal.Terminal = homeTerminal\n\n\t// Check if first hub in path is the home hub.\n\tif route.Path[0].HubID != previousHop.Hub.ID {\n\t\treturn nil, nil, errors.New(\"path start does not match home hub\")\n\t}\n\n\t// Check if path only exists of home hub.\n\tif len(route.Path) == 1 {\n\t\treturn previousHop, previousTerminal, nil\n\t}\n\n\t// TODO: Check what needs locking.\n\n\t// Build path and save created paths.\n\thopChecks := make([]*hopCheck, 0, len(route.Path)-1)\n\tfor i, hop := range route.Path[1:] {\n\t\t// Check if we already have a connection to the Hub.\n\t\tactiveTerminal := hop.Pin().GetActiveTerminal()\n\t\tif activeTerminal != nil {\n\t\t\t// Ping terminal if not recently checked.\n\t\t\tif activeTerminal.NeedsReachableCheck(1 * time.Minute) {\n\t\t\t\tpingOp, tErr := NewPingOp(activeTerminal)\n\t\t\t\tif tErr.IsError() {\n\t\t\t\t\treturn nil, nil, tErr.Wrap(\"failed start ping to %s\", hop.Pin())\n\t\t\t\t}\n\t\t\t\t// Add for checking results later.\n\t\t\t\thopChecks = append(hopChecks, &hopCheck{\n\t\t\t\t\tpin:       hop.Pin(),\n\t\t\t\t\troute:     route.CopyUpTo(i + 2),\n\t\t\t\t\texpansion: activeTerminal,\n\t\t\t\t\tpingOp:    pingOp,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tpreviousHop = hop.Pin()\n\t\t\tpreviousTerminal = activeTerminal\n\t\t\tcontinue\n\t\t}\n\n\t\t// Expand to next Hub.\n\t\texpansion, authOp, tErr := expand(previousTerminal, previousHop, hop.Pin())\n\t\tif tErr != nil {\n\t\t\treturn nil, nil, tErr.Wrap(\"failed to expand to %s\", hop.Pin())\n\t\t}\n\n\t\t// Add for checking results later.\n\t\thopChecks = append(hopChecks, &hopCheck{\n\t\t\tpin:       hop.Pin(),\n\t\t\troute:     route.CopyUpTo(i + 2),\n\t\t\texpansion: expansion,\n\t\t\tauthOp:    authOp,\n\t\t})\n\n\t\t// Save previous pin for next loop or end.\n\t\tpreviousHop = hop.Pin()\n\t\tpreviousTerminal = expansion\n\t}\n\n\t// Check results.\n\tfor _, check := range hopChecks {\n\t\tswitch {\n\t\tcase check.authOp != nil:\n\t\t\t// Wait for authOp result.\n\t\t\tselect {\n\t\t\tcase tErr := <-check.authOp.Result:\n\t\t\t\tswitch {\n\t\t\t\tcase tErr.IsError():\n\t\t\t\t\t// There was a network or authentication error.\n\t\t\t\t\tcheck.pin.MarkAsFailingFor(3 * time.Minute)\n\t\t\t\t\tlog.Warningf(\"spn/crew: failed to auth to %s: %s\", check.pin.Hub, tErr)\n\t\t\t\t\treturn nil, nil, tErr.Wrap(\"failed to authenticate to %s: %w\", check.pin.Hub, tErr)\n\n\t\t\t\tcase tErr.Is(terminal.ErrExplicitAck):\n\t\t\t\t\t// Authentication was successful.\n\n\t\t\t\tdefault:\n\t\t\t\t\t// Authentication was aborted.\n\t\t\t\t\tif tErr != nil {\n\t\t\t\t\t\ttErr = terminal.ErrUnknownError\n\t\t\t\t\t}\n\t\t\t\t\tlog.Warningf(\"spn/crew: auth to %s aborted with %s\", check.pin.Hub, tErr)\n\t\t\t\t\treturn nil, nil, tErr.Wrap(\"authentication to %s aborted: %w\", check.pin.Hub, tErr)\n\t\t\t\t}\n\n\t\t\tcase <-time.After(5 * time.Second):\n\t\t\t\t// Mark as failing for just a minute, until server load may be less.\n\t\t\t\tcheck.pin.MarkAsFailingFor(1 * time.Minute)\n\t\t\t\tlog.Warningf(\"spn/crew: auth to %s timed out\", check.pin.Hub)\n\n\t\t\t\treturn nil, nil, terminal.ErrTimeout.With(\"waiting for auth to %s\", check.pin.Hub)\n\t\t\t}\n\n\t\t\t// Add terminal extension to the map.\n\t\t\tcheck.pin.SetActiveTerminal(&navigator.PinConnection{\n\t\t\t\tTerminal: check.expansion,\n\t\t\t\tRoute:    check.route,\n\t\t\t})\n\t\t\tcheck.expansion.MarkReachable()\n\t\t\tlog.Infof(\"spn/crew: added conn to %s via %s\", check.pin, check.route)\n\n\t\tcase check.pingOp != nil:\n\t\t\t// Wait for ping result.\n\t\t\tselect {\n\t\t\tcase tErr := <-check.pingOp.Result:\n\t\t\t\tif !tErr.Is(terminal.ErrExplicitAck) {\n\t\t\t\t\t// Mark as failing long enough to expire connections and session and shutdown connections.\n\t\t\t\t\t// TODO: Should we forcibly disconnect instead?\n\t\t\t\t\t// TODO: This might also be triggered if a relay fails and ends the operation.\n\t\t\t\t\tcheck.pin.MarkAsFailingFor(7 * time.Minute)\n\t\t\t\t\t// Forget about existing active terminal, re-create if needed.\n\t\t\t\t\tcheck.pin.SetActiveTerminal(nil)\n\t\t\t\t\tlog.Warningf(\"spn/crew: failed to check reachability of %s: %s\", check.pin.Hub, tErr)\n\n\t\t\t\t\treturn nil, nil, tErr.Wrap(\"failed to check reachability of %s: %w\", check.pin.Hub, tErr)\n\t\t\t\t}\n\n\t\t\tcase <-time.After(5 * time.Second):\n\t\t\t\t// Mark as failing for just a minute, until server load may be less.\n\t\t\t\tcheck.pin.MarkAsFailingFor(1 * time.Minute)\n\t\t\t\t// Forget about existing active terminal, re-create if needed.\n\t\t\t\tcheck.pin.SetActiveTerminal(nil)\n\t\t\t\tlog.Warningf(\"spn/crew: reachability check to %s timed out\", check.pin.Hub)\n\n\t\t\t\treturn nil, nil, terminal.ErrTimeout.With(\"waiting for ping to %s\", check.pin.Hub)\n\t\t\t}\n\n\t\t\tcheck.expansion.MarkReachable()\n\t\t\tlog.Debugf(\"spn/crew: checked conn to %s via %s\", check.pin.Hub, check.route)\n\n\t\tdefault:\n\t\t\tlog.Errorf(\"spn/crew: invalid hop check for %s\", check.pin.Hub)\n\t\t\treturn nil, nil, terminal.ErrInternalError.With(\"invalid hop check\")\n\t\t}\n\t}\n\n\t// Return last hop.\n\treturn previousHop, previousTerminal, nil\n}\n\nfunc expand(fromTerminal terminal.Terminal, from, to *navigator.Pin) (expansion *docks.ExpansionTerminal, authOp *access.AuthorizeOp, tErr *terminal.Error) {\n\texpansion, tErr = docks.ExpandTo(fromTerminal, to.Hub.ID, to.Hub)\n\tif tErr != nil {\n\t\treturn nil, nil, tErr.Wrap(\"failed to expand to %s\", to.Hub)\n\t}\n\n\tauthOp, tErr = access.AuthorizeToTerminal(expansion)\n\tif tErr != nil {\n\t\texpansion.Abandon(nil)\n\t\treturn nil, nil, tErr.Wrap(\"failed to authorize\")\n\t}\n\n\tlog.Infof(\"spn/crew: expanded to %s (from %s)\", to.Hub, from.Hub)\n\treturn expansion, authOp, nil\n}\n\n// TunnelContext holds additional information about the tunnel to be added to a\n// connection.\ntype TunnelContext struct {\n\tPath       []*TunnelContextHop\n\tPathCost   float32\n\tRoutingAlg string\n\n\ttunnel *Tunnel\n}\n\n// GetExitNodeID returns the ID of the exit node.\n// It returns an empty string in case no path exists.\nfunc (tc *TunnelContext) GetExitNodeID() string {\n\tif len(tc.Path) == 0 {\n\t\treturn \"\"\n\t}\n\n\treturn tc.Path[len(tc.Path)-1].ID\n}\n\n// StopTunnel stops the tunnel.\nfunc (tc *TunnelContext) StopTunnel() error {\n\tif tc.tunnel != nil && tc.tunnel.conn != nil {\n\t\treturn tc.tunnel.conn.Close()\n\t}\n\treturn nil\n}\n\n// TunnelContextHop holds hop data for TunnelContext.\ntype TunnelContextHop struct {\n\tID   string\n\tName string\n\tIPv4 *TunnelContextHopIPInfo `json:\",omitempty\"`\n\tIPv6 *TunnelContextHopIPInfo `json:\",omitempty\"`\n}\n\n// TunnelContextHopIPInfo holds hop IP data for TunnelContextHop.\ntype TunnelContextHopIPInfo struct {\n\tIP      net.IP\n\tCountry string\n\tASN     uint\n\tASOwner string\n}\n\nfunc addTunnelContextToConnection(t *Tunnel) {\n\t// Create and add basic info.\n\ttunnelCtx := &TunnelContext{\n\t\tPath:       make([]*TunnelContextHop, len(t.route.Path)),\n\t\tPathCost:   t.route.TotalCost,\n\t\tRoutingAlg: t.route.Algorithm,\n\t\ttunnel:     t,\n\t}\n\tt.connInfo.TunnelContext = tunnelCtx\n\n\t// Add path info.\n\tfor i, hop := range t.route.Path {\n\t\t// Add hub info.\n\t\thopCtx := &TunnelContextHop{\n\t\t\tID:   hop.HubID,\n\t\t\tName: hop.Pin().Hub.Info.Name,\n\t\t}\n\t\ttunnelCtx.Path[i] = hopCtx\n\t\t// Add hub IPv4 info.\n\t\tif hop.Pin().Hub.Info.IPv4 != nil {\n\t\t\thopCtx.IPv4 = &TunnelContextHopIPInfo{\n\t\t\t\tIP: hop.Pin().Hub.Info.IPv4,\n\t\t\t}\n\t\t\tif hop.Pin().LocationV4 != nil {\n\t\t\t\thopCtx.IPv4.Country = hop.Pin().LocationV4.Country.Code\n\t\t\t\thopCtx.IPv4.ASN = hop.Pin().LocationV4.AutonomousSystemNumber\n\t\t\t\thopCtx.IPv4.ASOwner = hop.Pin().LocationV4.AutonomousSystemOrganization\n\t\t\t}\n\t\t}\n\t\t// Add hub IPv6 info.\n\t\tif hop.Pin().Hub.Info.IPv6 != nil {\n\t\t\thopCtx.IPv6 = &TunnelContextHopIPInfo{\n\t\t\t\tIP: hop.Pin().Hub.Info.IPv6,\n\t\t\t}\n\t\t\tif hop.Pin().LocationV6 != nil {\n\t\t\t\thopCtx.IPv6.Country = hop.Pin().LocationV6.Country.Code\n\t\t\t\thopCtx.IPv6.ASN = hop.Pin().LocationV6.AutonomousSystemNumber\n\t\t\t\thopCtx.IPv6.ASOwner = hop.Pin().LocationV6.AutonomousSystemOrganization\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/crew/metrics.go",
    "content": "package crew\n\nimport (\n\t\"sync/atomic\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/metrics\"\n)\n\nvar (\n\tconnectOpCnt            *metrics.Counter\n\tconnectOpCntError       *metrics.Counter\n\tconnectOpCntBadRequest  *metrics.Counter\n\tconnectOpCntCanceled    *metrics.Counter\n\tconnectOpCntFailed      *metrics.Counter\n\tconnectOpCntConnected   *metrics.Counter\n\tconnectOpCntRateLimited *metrics.Counter\n\n\tconnectOpIncomingBytes *metrics.Counter\n\tconnectOpOutgoingBytes *metrics.Counter\n\n\tconnectOpTTCRDurationHistogram *metrics.Histogram\n\tconnectOpTTFBDurationHistogram *metrics.Histogram\n\tconnectOpDurationHistogram     *metrics.Histogram\n\tconnectOpIncomingDataHistogram *metrics.Histogram\n\tconnectOpOutgoingDataHistogram *metrics.Histogram\n\n\tmetricsRegistered = abool.New()\n)\n\nfunc registerMetrics() (err error) {\n\t// Only register metrics once.\n\tif !metricsRegistered.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Connect Op Stats on client.\n\n\tconnectOpCnt, err = metrics.NewCounter(\n\t\t\"spn/op/connect/total\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Total Connect Operations\",\n\t\t\tInternalID: \"spn_connect_count\",\n\t\t\tPermission: api.PermitUser,\n\t\t\tPersist:    true,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Connect Op Stats on server.\n\n\tconnectOpCntOptions := &metrics.Options{\n\t\tName:       \"SPN Total Connect Operations\",\n\t\tPermission: api.PermitUser,\n\t\tPersist:    true,\n\t}\n\n\tconnectOpCntError, err = metrics.NewCounter(\n\t\t\"spn/op/connect/total\",\n\t\tmap[string]string{\"result\": \"error\"},\n\t\tconnectOpCntOptions,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpCntBadRequest, err = metrics.NewCounter(\n\t\t\"spn/op/connect/total\",\n\t\tmap[string]string{\"result\": \"bad_request\"},\n\t\tconnectOpCntOptions,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpCntCanceled, err = metrics.NewCounter(\n\t\t\"spn/op/connect/total\",\n\t\tmap[string]string{\"result\": \"canceled\"},\n\t\tconnectOpCntOptions,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpCntFailed, err = metrics.NewCounter(\n\t\t\"spn/op/connect/total\",\n\t\tmap[string]string{\"result\": \"failed\"},\n\t\tconnectOpCntOptions,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpCntConnected, err = metrics.NewCounter(\n\t\t\"spn/op/connect/total\",\n\t\tmap[string]string{\"result\": \"connected\"},\n\t\tconnectOpCntOptions,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpCntRateLimited, err = metrics.NewCounter(\n\t\t\"spn/op/connect/total\",\n\t\tmap[string]string{\"result\": \"rate_limited\"},\n\t\tconnectOpCntOptions,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/op/connect/active\",\n\t\tnil,\n\t\tgetActiveConnectOpsStat,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Active Connect Operations\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpIncomingBytes, err = metrics.NewCounter(\n\t\t\"spn/op/connect/incoming/bytes\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Connect Operation Incoming Bytes\",\n\t\t\tInternalID: \"spn_connect_in_bytes\",\n\t\t\tPermission: api.PermitUser,\n\t\t\tPersist:    true,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpOutgoingBytes, err = metrics.NewCounter(\n\t\t\"spn/op/connect/outgoing/bytes\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Connect Operation Outgoing Bytes\",\n\t\t\tInternalID: \"spn_connect_out_bytes\",\n\t\t\tPermission: api.PermitUser,\n\t\t\tPersist:    true,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpTTCRDurationHistogram, err = metrics.NewHistogram(\n\t\t\"spn/op/connect/histogram/ttcr/seconds\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Connect Operation time-to-connect-request Histogram\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpTTFBDurationHistogram, err = metrics.NewHistogram(\n\t\t\"spn/op/connect/histogram/ttfb/seconds\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Connect Operation time-to-first-byte (from TTCR) Histogram\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpDurationHistogram, err = metrics.NewHistogram(\n\t\t\"spn/op/connect/histogram/duration/seconds\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Connect Operation Duration Histogram\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpIncomingDataHistogram, err = metrics.NewHistogram(\n\t\t\"spn/op/connect/histogram/incoming/bytes\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Connect Operation Downloaded Data Histogram\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnectOpOutgoingDataHistogram, err = metrics.NewHistogram(\n\t\t\"spn/op/connect/histogram/outgoing/bytes\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Connect Operation Outgoing Data Histogram\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc getActiveConnectOpsStat() float64 {\n\treturn float64(atomic.LoadInt64(activeConnectOps))\n}\n"
  },
  {
    "path": "spn/crew/module.go",
    "content": "package crew\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\ntype Crew struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc (c *Crew) Manager() *mgr.Manager {\n\treturn c.mgr\n}\n\nfunc (c *Crew) Start() error {\n\treturn start()\n}\n\nfunc (c *Crew) Stop() error {\n\treturn stop()\n}\n\nfunc start() error {\n\t_ = module.mgr.Repeat(\"sticky cleaner\", 10*time.Minute, cleanStickyHubs)\n\treturn registerMetrics()\n}\n\nfunc stop() error {\n\tclearStickyHubs()\n\tterminal.StopScheduler()\n\n\treturn nil\n}\n\nvar connectErrors = make(chan *terminal.Error, 10)\n\nfunc reportConnectError(tErr *terminal.Error) {\n\tselect {\n\tcase connectErrors <- tErr:\n\tdefault:\n\t}\n}\n\n// ConnectErrors returns errors of connect operations.\n// It only has a small and shared buffer and may only be used for indications,\n// not for full monitoring.\nfunc ConnectErrors() <-chan *terminal.Error {\n\treturn connectErrors\n}\n\nvar (\n\tmodule     *Crew\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Config module.\nfunc New(instance instance) (*Crew, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Crew\")\n\tmodule = &Crew{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/crew/module_test.go",
    "content": "package crew\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\ntype testInstance struct {\n\tdb       *dbmodule.DBModule\n\tconfig   *config.Config\n\tmetrics  *metrics.Metrics\n\trng      *rng.Rng\n\tbase     *base.Base\n\tterminal *terminal.TerminalModule\n\tcabin    *cabin.Cabin\n}\n\nfunc (stub *testInstance) Config() *config.Config {\n\treturn stub.config\n}\n\nfunc (stub *testInstance) Metrics() *metrics.Metrics {\n\treturn stub.metrics\n}\n\nfunc (stub *testInstance) SPNGroup() *mgr.ExtendedGroup {\n\treturn nil\n}\n\nfunc (stub *testInstance) Stopping() bool {\n\treturn false\n}\n\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\n\nfunc (stub *testInstance) DataDir() string {\n\treturn _dataDir\n}\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tconf.EnablePublicHub(true) // Make hub config available.\n\tvar err error\n\t// Create a temporary directory for the data\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to initialize dataroot: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\tinstance := &testInstance{}\n\t// Init\n\tinstance.db, err = dbmodule.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database module: %w\", err)\n\t}\n\tinstance.config, err = config.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config module: %w\", err)\n\t}\n\tinstance.metrics, err = metrics.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create metrics module: %w\", err)\n\t}\n\tinstance.rng, err = rng.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create rng module: %w\", err)\n\t}\n\tinstance.base, err = base.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create base module: %w\", err)\n\t}\n\tinstance.terminal, err = terminal.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create terminal module: %w\", err)\n\t}\n\tinstance.cabin, err = cabin.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create cabin module: %w\", err)\n\t}\n\tmodule, err = New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create crew module: %w\", err)\n\t}\n\n\t// Start\n\terr = instance.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start db module: %w\", err)\n\t}\n\terr = instance.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start config module: %w\", err)\n\t}\n\terr = instance.metrics.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start metrics module: %w\", err)\n\t}\n\terr = instance.rng.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start rng module: %w\", err)\n\t}\n\terr = instance.base.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start base module: %w\", err)\n\t}\n\terr = instance.terminal.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start terminal module: %w\", err)\n\t}\n\terr = instance.cabin.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start cabin module: %w\", err)\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start crew module: %w\", err)\n\t}\n\n\tconf.EnablePublicHub(true)\n\tm.Run()\n\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\", err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "spn/crew/op_connect.go",
    "content": "package crew\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// ConnectOpType is the type ID for the connection operation.\nconst ConnectOpType string = \"connect\"\n\nvar activeConnectOps = new(int64)\n\n// ConnectOp is used to connect data tunnels to servers on the Internet.\ntype ConnectOp struct {\n\tterminal.OperationBase\n\n\t// Flow Control\n\tdfq *terminal.DuplexFlowQueue\n\n\t// Context and shutdown handling\n\t// ctx is the context of the Terminal.\n\tctx context.Context\n\t// cancelCtx cancels ctx.\n\tcancelCtx context.CancelFunc\n\t// doneWriting signals that the writer has finished writing.\n\tdoneWriting chan struct{}\n\n\t// Metrics\n\tincomingTraffic atomic.Uint64\n\toutgoingTraffic atomic.Uint64\n\tstarted         time.Time\n\n\t// Connection\n\tt       terminal.Terminal\n\tconn    net.Conn\n\trequest *ConnectRequest\n\tentry   bool\n\ttunnel  *Tunnel\n}\n\n// Type returns the type ID.\nfunc (op *ConnectOp) Type() string {\n\treturn ConnectOpType\n}\n\n// Ctx returns the operation context.\nfunc (op *ConnectOp) Ctx() context.Context {\n\treturn op.ctx\n}\n\n// ConnectRequest holds all the information necessary for a connect operation.\ntype ConnectRequest struct {\n\tDomain              string            `json:\"d,omitempty\"`\n\tIP                  net.IP            `json:\"ip,omitempty\"`\n\tUsePriorityDataMsgs bool              `json:\"pr,omitempty\"`\n\tProtocol            packet.IPProtocol `json:\"p,omitempty\"`\n\tPort                uint16            `json:\"po,omitempty\"`\n\tQueueSize           uint32            `json:\"qs,omitempty\"`\n}\n\n// DialNetwork returns the address of the connect request.\nfunc (r *ConnectRequest) DialNetwork() string {\n\tif ip4 := r.IP.To4(); ip4 != nil {\n\t\tswitch r.Protocol { //nolint:exhaustive // Only looking for supported protocols.\n\t\tcase packet.TCP:\n\t\t\treturn \"tcp4\"\n\t\tcase packet.UDP:\n\t\t\treturn \"udp4\"\n\t\t}\n\t} else {\n\t\tswitch r.Protocol { //nolint:exhaustive // Only looking for supported protocols.\n\t\tcase packet.TCP:\n\t\t\treturn \"tcp6\"\n\t\tcase packet.UDP:\n\t\t\treturn \"udp6\"\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\n// Address returns the address of the connext request.\nfunc (r *ConnectRequest) Address() string {\n\treturn net.JoinHostPort(r.IP.String(), strconv.Itoa(int(r.Port)))\n}\n\nfunc (r *ConnectRequest) String() string {\n\tif r.Domain != \"\" {\n\t\treturn fmt.Sprintf(\"%s (%s %s)\", r.Domain, r.Protocol, r.Address())\n\t}\n\treturn fmt.Sprintf(\"%s %s\", r.Protocol, r.Address())\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     ConnectOpType,\n\t\tRequires: terminal.MayConnect,\n\t\tStart:    startConnectOp,\n\t})\n}\n\n// NewConnectOp starts a new connect operation.\nfunc NewConnectOp(tunnel *Tunnel) (*ConnectOp, *terminal.Error) {\n\t// Submit metrics.\n\tconnectOpCnt.Inc()\n\n\t// Create request.\n\trequest := &ConnectRequest{\n\t\tDomain:              tunnel.connInfo.Entity.Domain,\n\t\tIP:                  tunnel.connInfo.Entity.IP,\n\t\tProtocol:            packet.IPProtocol(tunnel.connInfo.Entity.Protocol),\n\t\tPort:                tunnel.connInfo.Entity.Port,\n\t\tUsePriorityDataMsgs: terminal.UsePriorityDataMsgs,\n\t}\n\n\t// Set defaults.\n\tif request.QueueSize == 0 {\n\t\trequest.QueueSize = terminal.DefaultQueueSize\n\t}\n\n\t// Create new op.\n\top := &ConnectOp{\n\t\tdoneWriting: make(chan struct{}),\n\t\tt:           tunnel.dstTerminal,\n\t\tconn:        tunnel.conn,\n\t\trequest:     request,\n\t\tentry:       true,\n\t\ttunnel:      tunnel,\n\t}\n\top.ctx, op.cancelCtx = context.WithCancel(module.mgr.Ctx())\n\top.dfq = terminal.NewDuplexFlowQueue(op.Ctx(), request.QueueSize, op.submitUpstream)\n\n\t// Prepare init msg.\n\tdata, err := dsd.Dump(request, dsd.CBOR)\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to pack connect request: %w\", err)\n\t}\n\n\t// Initialize.\n\ttErr := op.t.StartOperation(op, container.New(data), 5*time.Second)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\t// Setup metrics.\n\top.started = time.Now()\n\n\tmodule.mgr.Go(\"connect op conn reader\", op.connReader)\n\tmodule.mgr.Go(\"connect op conn writer\", op.connWriter)\n\tmodule.mgr.Go(\"connect op flow handler\", op.dfq.FlowHandler)\n\n\tlog.Infof(\"spn/crew: connected to %s via %s\", request, tunnel.dstPin.Hub)\n\treturn op, nil\n}\n\nfunc startConnectOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Check if we are running a public hub.\n\tif !conf.PublicHub() {\n\t\treturn nil, terminal.ErrPermissionDenied.With(\"connecting is only allowed on public hubs\")\n\t}\n\n\t// Parse connect request.\n\trequest := &ConnectRequest{}\n\t_, err := dsd.Load(data.CompileData(), request)\n\tif err != nil {\n\t\tconnectOpCntError.Inc() // More like a protocol/system error than a bad request.\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to parse connect request: %w\", err)\n\t}\n\tif request.QueueSize == 0 || request.QueueSize > terminal.MaxQueueSize {\n\t\tconnectOpCntError.Inc() // More like a protocol/system error than a bad request.\n\t\treturn nil, terminal.ErrInvalidOptions.With(\"invalid queue size of %d\", request.QueueSize)\n\t}\n\n\t// Check if IP seems valid.\n\tif len(request.IP) != net.IPv4len && len(request.IP) != net.IPv6len {\n\t\tconnectOpCntError.Inc() // More like a protocol/system error than a bad request.\n\t\treturn nil, terminal.ErrInvalidOptions.With(\"ip address is not valid\")\n\t}\n\n\t// Create and initialize operation.\n\top := &ConnectOp{\n\t\tdoneWriting: make(chan struct{}),\n\t\tt:           t,\n\t\trequest:     request,\n\t}\n\top.InitOperationBase(t, opID)\n\top.ctx, op.cancelCtx = context.WithCancel(t.Ctx())\n\top.dfq = terminal.NewDuplexFlowQueue(op.Ctx(), request.QueueSize, op.submitUpstream)\n\n\t// Start worker to complete setting up the connection.\n\tmodule.mgr.Go(\"connect op setup\", op.handleSetup)\n\n\treturn op, nil\n}\n\nfunc (op *ConnectOp) handleSetup(_ *mgr.WorkerCtx) error {\n\t// Get terminal session for rate limiting.\n\tvar session *terminal.Session\n\tif sessionTerm, ok := op.t.(terminal.SessionTerminal); ok {\n\t\tsession = sessionTerm.GetSession()\n\t} else {\n\t\tconnectOpCntError.Inc()\n\t\tlog.Errorf(\"spn/crew: %T is not a session terminal, aborting op %s#%d\", op.t, op.t.FmtID(), op.ID())\n\t\top.Stop(op, terminal.ErrInternalError.With(\"no session available\"))\n\t\treturn nil\n\t}\n\n\t// Limit concurrency of connecting.\n\tcancelErr := session.LimitConcurrency(op.Ctx(), func() {\n\t\top.setup(session)\n\t})\n\n\t// If context was canceled, stop operation.\n\tif cancelErr != nil {\n\t\tconnectOpCntCanceled.Inc()\n\t\top.Stop(op, terminal.ErrCanceled.With(cancelErr.Error()))\n\t}\n\n\t// Do not return a worker error.\n\treturn nil\n}\n\nfunc (op *ConnectOp) setup(session *terminal.Session) {\n\t// Rate limit before connecting.\n\tif tErr := session.RateLimit(); tErr != nil {\n\t\t// Add rate limit info to error.\n\t\tif tErr.Is(terminal.ErrRateLimited) {\n\t\t\tconnectOpCntRateLimited.Inc()\n\t\t\top.Stop(op, tErr.With(session.RateLimitInfo()))\n\t\t\treturn\n\t\t}\n\n\t\tconnectOpCntError.Inc()\n\t\top.Stop(op, tErr)\n\t\treturn\n\t}\n\n\t// Check if connection target is in global scope.\n\tipScope := netutils.GetIPScope(op.request.IP)\n\tif ipScope != netutils.Global {\n\t\tsession.ReportSuspiciousActivity(terminal.SusFactorQuiteUnusual)\n\t\tconnectOpCntBadRequest.Inc()\n\t\top.Stop(op, terminal.ErrPermissionDenied.With(\"denied request to connect to non-global IP %s\", op.request.IP))\n\t\treturn\n\t}\n\n\t// Check exit policy.\n\tif tErr := checkExitPolicy(op.request); tErr != nil {\n\t\tsession.ReportSuspiciousActivity(terminal.SusFactorQuiteUnusual)\n\t\tconnectOpCntBadRequest.Inc()\n\t\top.Stop(op, tErr)\n\t\treturn\n\t}\n\n\t// Check one last time before connecting if operation was not canceled.\n\tif op.Ctx().Err() != nil {\n\t\top.Stop(op, terminal.ErrCanceled.With(op.Ctx().Err().Error()))\n\t\tconnectOpCntCanceled.Inc()\n\t\treturn\n\t}\n\n\t// Connect to destination.\n\tdialNet := op.request.DialNetwork()\n\tif dialNet == \"\" {\n\t\tsession.ReportSuspiciousActivity(terminal.SusFactorCommon)\n\t\tconnectOpCntBadRequest.Inc()\n\t\top.Stop(op, terminal.ErrIncorrectUsage.With(\"protocol %s is not supported\", op.request.Protocol))\n\t\treturn\n\t}\n\tdialer := &net.Dialer{\n\t\tTimeout:       10 * time.Second,\n\t\tLocalAddr:     conf.GetBindAddr(dialNet),\n\t\tFallbackDelay: -1, // Disables Fast Fallback from IPv6 to IPv4.\n\t\tKeepAlive:     -1, // Disable keep-alive.\n\t}\n\tconn, err := dialer.DialContext(op.Ctx(), dialNet, op.request.Address())\n\tif err != nil {\n\t\t// Connection errors are common, but still a bit suspicious.\n\t\tvar netError net.Error\n\t\tswitch {\n\t\tcase errors.As(err, &netError) && netError.Timeout():\n\t\t\tsession.ReportSuspiciousActivity(terminal.SusFactorCommon)\n\t\t\tconnectOpCntFailed.Inc()\n\t\tcase errors.Is(err, context.Canceled):\n\t\t\tsession.ReportSuspiciousActivity(terminal.SusFactorCommon)\n\t\t\tconnectOpCntCanceled.Inc()\n\t\tdefault:\n\t\t\tsession.ReportSuspiciousActivity(terminal.SusFactorWeirdButOK)\n\t\t\tconnectOpCntFailed.Inc()\n\t\t}\n\n\t\top.Stop(op, terminal.ErrConnectionError.With(\"failed to connect to %s: %w\", op.request, err))\n\t\treturn\n\t}\n\top.conn = conn\n\n\t// Start worker.\n\tmodule.mgr.Go(\"connect op conn reader\", op.connReader)\n\tmodule.mgr.Go(\"connect op conn writer\", op.connWriter)\n\tmodule.mgr.Go(\"connect op flow handler\", op.dfq.FlowHandler)\n\n\tconnectOpCntConnected.Inc()\n\tlog.Infof(\"spn/crew: connected op %s#%d to %s\", op.t.FmtID(), op.ID(), op.request)\n}\n\nfunc (op *ConnectOp) submitUpstream(msg *terminal.Msg, timeout time.Duration) {\n\terr := op.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t\top.Stop(op, err.Wrap(\"failed to send data (op) read from %s\", op.connectedType()))\n\t}\n}\n\nconst (\n\treadBufSize = 1500\n\n\t// High priority up to first 10MB.\n\thighPrioThreshold = 10_000_000\n\n\t// Rate limit to 128 Mbit/s after 1GB traffic.\n\t// Do NOT use time.Sleep per packet, as it is very inaccurate and will sleep a lot longer than desired.\n\trateLimitThreshold = 1_000_000_000\n\trateLimitMaxMbit   = 128\n)\n\nfunc (op *ConnectOp) connReader(_ *mgr.WorkerCtx) error {\n\t// Metrics setup and submitting.\n\tatomic.AddInt64(activeConnectOps, 1)\n\tdefer func() {\n\t\tatomic.AddInt64(activeConnectOps, -1)\n\t\tconnectOpDurationHistogram.UpdateDuration(op.started)\n\t\tconnectOpIncomingDataHistogram.Update(float64(op.incomingTraffic.Load()))\n\t}()\n\n\trateLimiter := terminal.NewRateLimiter(rateLimitMaxMbit)\n\n\tfor {\n\t\t// Read from connection.\n\t\tbuf := make([]byte, readBufSize)\n\t\tn, err := op.conn.Read(buf)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\top.Stop(op, terminal.ErrStopping.With(\"connection to %s was closed on read\", op.connectedType()))\n\t\t\t} else {\n\t\t\t\top.Stop(op, terminal.ErrConnectionError.With(\"failed to read from %s: %w\", op.connectedType(), err))\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tif n == 0 {\n\t\t\tlog.Tracef(\"spn/crew: connect op %s>%d read 0 bytes from %s\", op.t.FmtID(), op.ID(), op.connectedType())\n\t\t\tcontinue\n\t\t}\n\n\t\t// Submit metrics.\n\t\tconnectOpIncomingBytes.Add(n)\n\t\tinBytes := op.incomingTraffic.Add(uint64(n))\n\n\t\t// Rate limit if over threshold.\n\t\tif inBytes > rateLimitThreshold {\n\t\t\trateLimiter.Limit(uint64(n))\n\t\t}\n\n\t\t// Create message from data.\n\t\tmsg := op.NewMsg(buf[:n])\n\n\t\t// Define priority and possibly wait for slot.\n\t\tswitch {\n\t\tcase inBytes > highPrioThreshold:\n\t\t\tmsg.Unit.WaitForSlot()\n\t\tcase op.request.UsePriorityDataMsgs:\n\t\t\tmsg.Unit.MakeHighPriority()\n\t\t}\n\n\t\t// Send packet.\n\t\ttErr := op.dfq.Send(\n\t\t\tmsg,\n\t\t\t30*time.Second,\n\t\t)\n\t\tif tErr != nil {\n\t\t\tmsg.Finish()\n\t\t\top.Stop(op, tErr.Wrap(\"failed to send data (dfq) from %s\", op.connectedType()))\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n// Deliver delivers a messages to the operation.\nfunc (op *ConnectOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\treturn op.dfq.Deliver(msg)\n}\n\nfunc (op *ConnectOp) connWriter(_ *mgr.WorkerCtx) error {\n\t// Metrics submitting.\n\tdefer func() {\n\t\tconnectOpOutgoingDataHistogram.Update(float64(op.outgoingTraffic.Load()))\n\t}()\n\n\tdefer func() {\n\t\t// Signal that we are done with writing.\n\t\tclose(op.doneWriting)\n\t\t// Close connection.\n\t\t_ = op.conn.Close()\n\t}()\n\n\tvar msg *terminal.Msg\n\tdefer msg.Finish()\n\n\trateLimiter := terminal.NewRateLimiter(rateLimitMaxMbit)\n\nwriting:\n\tfor {\n\t\tmsg.Finish()\n\n\t\tselect {\n\t\tcase msg = <-op.dfq.Receive():\n\t\tcase <-op.ctx.Done():\n\t\t\top.Stop(op, terminal.ErrCanceled)\n\t\t\treturn nil\n\t\tdefault:\n\t\t\t// Handle all data before also listening for the context cancel.\n\t\t\t// This ensures all data is written properly before stopping.\n\t\t\tselect {\n\t\t\tcase msg = <-op.dfq.Receive():\n\t\t\tcase op.doneWriting <- struct{}{}:\n\t\t\t\top.Stop(op, terminal.ErrStopping)\n\t\t\t\treturn nil\n\t\t\tcase <-op.ctx.Done():\n\t\t\t\top.Stop(op, terminal.ErrCanceled)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\t// TODO: Instead of compiling data here again, can we send it as in the container?\n\t\tdata := msg.Data.CompileData()\n\t\tif len(data) == 0 {\n\t\t\tcontinue writing\n\t\t}\n\n\t\t// Submit metrics.\n\t\tconnectOpOutgoingBytes.Add(len(data))\n\t\tout := op.outgoingTraffic.Add(uint64(len(data)))\n\n\t\t// Rate limit if over threshold.\n\t\tif out > rateLimitThreshold {\n\t\t\trateLimiter.Limit(uint64(len(data)))\n\t\t}\n\n\t\t// Special handling after first data was received on client.\n\t\tif op.entry &&\n\t\t\tout == uint64(len(data)) {\n\t\t\t// Report time taken to receive first byte.\n\t\t\tconnectOpTTFBDurationHistogram.UpdateDuration(op.started)\n\n\t\t\t// If not stickied yet, stick destination to Hub.\n\t\t\tif !op.tunnel.stickied {\n\t\t\t\top.tunnel.stickDestinationToHub()\n\t\t\t}\n\t\t}\n\n\t\t// Send all given data.\n\t\tfor {\n\t\t\tn, err := op.conn.Write(data)\n\t\t\tswitch {\n\t\t\tcase err != nil:\n\t\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\t\top.Stop(op, terminal.ErrStopping.With(\"connection to %s was closed on write\", op.connectedType()))\n\t\t\t\t} else {\n\t\t\t\t\top.Stop(op, terminal.ErrConnectionError.With(\"failed to send to %s: %w\", op.connectedType(), err))\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\tcase n == 0:\n\t\t\t\top.Stop(op, terminal.ErrConnectionError.With(\"sent 0 bytes to %s\", op.connectedType()))\n\t\t\t\treturn nil\n\t\t\tcase n < len(data):\n\t\t\t\t// If not all data was sent, try again.\n\t\t\t\tlog.Debugf(\"spn/crew: %s#%d only sent %d/%d bytes to %s\", op.t.FmtID(), op.ID(), n, len(data), op.connectedType())\n\t\t\t\tdata = data[n:]\n\t\t\tdefault:\n\t\t\t\tcontinue writing\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (op *ConnectOp) connectedType() string {\n\tif op.entry {\n\t\treturn \"origin\"\n\t}\n\treturn \"destination\"\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *ConnectOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {\n\tif err.IsError() {\n\t\treportConnectError(err)\n\t}\n\n\t// If the connection has sent or received any data so far, finish the data\n\t// flows as it makes sense.\n\tif op.incomingTraffic.Load() > 0 || op.outgoingTraffic.Load() > 0 {\n\t\t// If the op was ended locally, send all data before closing.\n\t\t// If the op was ended remotely, don't bother sending remaining data.\n\t\tif !err.IsExternal() {\n\t\t\t// Flushing could mean sending a full buffer of 50000 packets.\n\t\t\top.dfq.Flush(5 * time.Minute)\n\t\t}\n\n\t\t// If the op was ended remotely, write all remaining received data.\n\t\t// If the op was ended locally, don't bother writing remaining data.\n\t\tif err.IsExternal() {\n\t\t\tselect {\n\t\t\tcase <-op.doneWriting:\n\t\t\tdefault:\n\t\t\t\tselect {\n\t\t\t\tcase <-op.doneWriting:\n\t\t\t\tcase <-time.After(5 * time.Second):\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Cancel workers.\n\top.cancelCtx()\n\n\t// Special client-side handling.\n\tif op.entry {\n\t\t// Mark the connection as failed if there was an error and no data was sent to the app yet.\n\t\tif err.IsError() && op.outgoingTraffic.Load() == 0 {\n\t\t\t// Set connection to failed and save it to propagate the update.\n\t\t\tc := op.tunnel.connInfo\n\t\t\tfunc() {\n\t\t\t\tc.Lock()\n\t\t\t\tdefer c.Unlock()\n\n\t\t\t\tif err.IsExternal() {\n\t\t\t\t\tc.Failed(fmt.Sprintf(\n\t\t\t\t\t\t\"the exit node reported an error: %s\", err,\n\t\t\t\t\t), \"\")\n\t\t\t\t} else {\n\t\t\t\t\tc.Failed(fmt.Sprintf(\n\t\t\t\t\t\t\"connection failed locally: %s\", err,\n\t\t\t\t\t), \"\")\n\t\t\t\t}\n\n\t\t\t\tc.Save()\n\t\t\t}()\n\t\t}\n\n\t\t// Avoid connecting to the destination via this Hub if:\n\t\t// - The error is external - ie. from the server.\n\t\t// - The error is a connection error.\n\t\t// - No data was received.\n\t\t// This indicates that there is some network level issue that we can\n\t\t// possibly work around by using another exit node.\n\t\tif err.IsError() && err.IsExternal() &&\n\t\t\terr.Is(terminal.ErrConnectionError) &&\n\t\t\top.outgoingTraffic.Load() == 0 {\n\t\t\top.tunnel.avoidDestinationHub()\n\t\t}\n\n\t\t// Don't leak local errors to the server.\n\t\tif !err.IsExternal() {\n\t\t\t// Change error that is reported.\n\t\t\treturn terminal.ErrStopping\n\t\t}\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "spn/crew/op_connect_test.go",
    "content": "package crew\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nconst (\n\ttestPadding   = 8\n\ttestQueueSize = 10\n)\n\nfunc TestConnectOp(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode, as it interacts with the network\")\n\t}\n\n\t// Create test terminal pair.\n\ta, b, err := terminal.NewSimpleTestTerminalPair(0, 0,\n\t\t&terminal.TerminalOpts{\n\t\t\tFlowControl:     terminal.FlowControlDFQ,\n\t\t\tFlowControlSize: testQueueSize,\n\t\t\tPadding:         testPadding,\n\t\t},\n\t)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create test terminal pair: %s\", err)\n\t}\n\n\t// Set up connect op.\n\tb.GrantPermission(terminal.MayConnect)\n\tconf.EnablePublicHub(true)\n\tidentity, err := cabin.CreateIdentity(module.mgr.Ctx(), \"test\")\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create identity: %s\", err)\n\t}\n\t_, err = identity.MaintainAnnouncement(&hub.Announcement{\n\t\tTransports: []string{\n\t\t\t\"tcp:17\",\n\t\t},\n\t\tExit: []string{\n\t\t\t\"+ * */80\",\n\t\t\t\"- *\",\n\t\t},\n\t}, true)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to update identity: %s\", err)\n\t}\n\tEnableConnecting(identity.Hub)\n\t{\n\t\tappConn, sluiceConn := net.Pipe()\n\t\t_, tErr := NewConnectOp(&Tunnel{\n\t\t\tconnInfo: &network.Connection{\n\t\t\t\tEntity: (&intel.Entity{\n\t\t\t\t\tProtocol: 6,\n\t\t\t\t\tPort:     80,\n\t\t\t\t\tDomain:   \"orf.at.\",\n\t\t\t\t\tIP:       net.IPv4(194, 232, 104, 142),\n\t\t\t\t}).Init(0),\n\t\t\t},\n\t\t\tconn:        sluiceConn,\n\t\t\tdstTerminal: a,\n\t\t\tdstPin: &navigator.Pin{\n\t\t\t\tHub: identity.Hub,\n\t\t\t},\n\t\t})\n\t\tif tErr != nil {\n\t\t\tt.Fatalf(\"failed to start connect op: %s\", tErr)\n\t\t}\n\n\t\t// Send request.\n\t\trequestURL, err := url.Parse(\"http://orf.at/\")\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to parse request url: %s\", err)\n\t\t}\n\t\tr := http.Request{\n\t\t\tMethod: http.MethodHead,\n\t\t\tURL:    requestURL,\n\t\t}\n\t\terr = r.Write(appConn)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to write request: %s\", err)\n\t\t}\n\n\t\t// Recv response.\n\t\tdata := make([]byte, 1500)\n\t\tn, err := appConn.Read(data)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to read request: %s\", err)\n\t\t}\n\t\tif n == 0 {\n\t\t\tt.Fatal(\"received empty reply\")\n\t\t}\n\n\t\tt.Log(\"received data:\")\n\t\tfmt.Println(string(data[:n]))\n\n\t\ttime.Sleep(500 * time.Millisecond)\n\t}\n}\n"
  },
  {
    "path": "spn/crew/op_ping.go",
    "content": "package crew\n\nimport (\n\t\"crypto/subtle\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nconst (\n\t// PingOpType is the type ID of the latency test operation.\n\tPingOpType = \"ping\"\n\n\tpingOpNonceSize = 16\n\tpingOpTimeout   = 3 * time.Second\n)\n\n// PingOp is used to measure latency.\ntype PingOp struct {\n\tterminal.OneOffOperationBase\n\n\tstarted time.Time\n\tnonce   []byte\n}\n\n// PingOpRequest is a ping request.\ntype PingOpRequest struct {\n\tNonce []byte `json:\"n,omitempty\"`\n}\n\n// PingOpResponse is a ping response.\ntype PingOpResponse struct {\n\tNonce []byte    `json:\"n,omitempty\"`\n\tTime  time.Time `json:\"t,omitempty\"`\n}\n\n// Type returns the type ID.\nfunc (op *PingOp) Type() string {\n\treturn PingOpType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:  PingOpType,\n\t\tStart: startPingOp,\n\t})\n}\n\n// NewPingOp runs a latency test.\nfunc NewPingOp(t terminal.Terminal) (*PingOp, *terminal.Error) {\n\t// Generate nonce.\n\tnonce, err := rng.Bytes(pingOpNonceSize)\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to generate ping nonce: %w\", err)\n\t}\n\n\t// Create operation and init.\n\top := &PingOp{\n\t\tstarted: time.Now().UTC(),\n\t\tnonce:   nonce,\n\t}\n\top.OneOffOperationBase.Init()\n\n\t// Create request.\n\tpingRequest, err := dsd.Dump(&PingOpRequest{\n\t\tNonce: op.nonce,\n\t}, dsd.CBOR)\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to create ping request: %w\", err)\n\t}\n\n\t// Send ping.\n\ttErr := t.StartOperation(op, container.New(pingRequest), pingOpTimeout)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\treturn op, nil\n}\n\n// Deliver delivers a message to the operation.\nfunc (op *PingOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\tdefer msg.Finish()\n\n\t// Parse response.\n\tresponse := &PingOpResponse{}\n\t_, err := dsd.Load(msg.Data.CompileData(), response)\n\tif err != nil {\n\t\treturn terminal.ErrMalformedData.With(\"failed to parse ping response: %w\", err)\n\t}\n\n\t// Check if the nonce matches.\n\tif subtle.ConstantTimeCompare(op.nonce, response.Nonce) != 1 {\n\t\treturn terminal.ErrIntegrity.With(\"ping nonce mismatched\")\n\t}\n\n\treturn terminal.ErrExplicitAck\n}\n\nfunc startPingOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Parse request.\n\trequest := &PingOpRequest{}\n\t_, err := dsd.Load(data.CompileData(), request)\n\tif err != nil {\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to parse ping request: %w\", err)\n\t}\n\n\t// Create response.\n\tresponse, err := dsd.Dump(&PingOpResponse{\n\t\tNonce: request.Nonce,\n\t\tTime:  time.Now().UTC(),\n\t}, dsd.CBOR)\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to create ping response: %w\", err)\n\t}\n\n\t// Send response.\n\tmsg := terminal.NewMsg(response)\n\tmsg.FlowID = opID\n\tmsg.Unit.MakeHighPriority()\n\tif terminal.UsePriorityDataMsgs {\n\t\tmsg.Type = terminal.MsgTypePriorityData\n\t}\n\ttErr := t.Send(msg, pingOpTimeout)\n\tif tErr != nil {\n\t\t// Finish message unit on failure.\n\t\tmsg.Finish()\n\t\treturn nil, tErr.With(\"failed to send ping response\")\n\t}\n\n\t// Operation is just one response and finished successfully.\n\treturn nil, nil\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *PingOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {\n\t// Prevent remote from sending explicit ack, as we use it as a success signal internally.\n\tif err.Is(terminal.ErrExplicitAck) && err.IsExternal() {\n\t\terr = terminal.ErrStopping.AsExternal()\n\t}\n\n\t// Continue with usual handling of inherited base.\n\treturn op.OneOffOperationBase.HandleStop(err)\n}\n"
  },
  {
    "path": "spn/crew/op_ping_test.go",
    "content": "package crew\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nfunc TestPingOp(t *testing.T) {\n\tt.Parallel()\n\n\t// Create test terminal pair.\n\ta, _, err := terminal.NewSimpleTestTerminalPair(0, 0, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create test terminal pair: %s\", err)\n\t}\n\n\t// Create ping op.\n\top, tErr := NewPingOp(a)\n\tif tErr.IsError() {\n\t\tt.Fatal(tErr)\n\t}\n\n\t// Wait for result.\n\tselect {\n\tcase result := <-op.Result:\n\t\tt.Logf(\"ping result: %s\", result.Error())\n\tcase <-time.After(pingOpTimeout):\n\t\tt.Fatal(\"timed out\")\n\t}\n}\n"
  },
  {
    "path": "spn/crew/policy.go",
    "content": "package crew\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nvar (\n\tconnectingHubLock sync.Mutex\n\tconnectingHub     *hub.Hub\n)\n\n// EnableConnecting enables connecting from this Hub.\nfunc EnableConnecting(my *hub.Hub) {\n\tconnectingHubLock.Lock()\n\tdefer connectingHubLock.Unlock()\n\n\tconnectingHub = my\n}\n\nfunc checkExitPolicy(request *ConnectRequest) *terminal.Error {\n\tconnectingHubLock.Lock()\n\tdefer connectingHubLock.Unlock()\n\n\t// Check if connect requests are allowed.\n\tif connectingHub == nil {\n\t\treturn terminal.ErrPermissionDenied.With(\"connect requests disabled\")\n\t}\n\n\t// Create entity.\n\tentity := (&intel.Entity{\n\t\tIP:       request.IP,\n\t\tProtocol: uint8(request.Protocol),\n\t\tPort:     request.Port,\n\t\tDomain:   request.Domain,\n\t}).Init(0)\n\tentity.FetchData(context.TODO())\n\n\t// Check against policy.\n\tresult, reason := connectingHub.GetInfo().ExitPolicy().Match(context.TODO(), entity)\n\tif result == endpoints.Denied {\n\t\treturn terminal.ErrPermissionDenied.With(\"connect request for %s violates the exit policy: %s\", request, reason)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/crew/sticky.go",
    "content": "package crew\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n)\n\nconst (\n\tstickyTTL = 1 * time.Hour\n)\n\nvar (\n\tstickyIPs     = make(map[string]*stickyHub)\n\tstickyDomains = make(map[string]*stickyHub)\n\tstickyLock    sync.Mutex\n)\n\ntype stickyHub struct {\n\tPin      *navigator.Pin\n\tRoute    *navigator.Route\n\tLastSeen time.Time\n\tAvoid    bool\n}\n\nfunc (sh *stickyHub) isExpired() bool {\n\treturn time.Now().Add(-stickyTTL).After(sh.LastSeen)\n}\n\nfunc makeStickyIPKey(conn *network.Connection) string {\n\tif p := conn.Process().Profile(); p != nil {\n\t\treturn fmt.Sprintf(\n\t\t\t\"%s/%s>%s\",\n\t\t\tp.LocalProfile().Source,\n\t\t\tp.LocalProfile().ID,\n\t\t\tconn.Entity.IP,\n\t\t)\n\t}\n\n\treturn \"?>\" + string(conn.Entity.IP)\n}\n\nfunc makeStickyDomainKey(conn *network.Connection) string {\n\tif p := conn.Process().Profile(); p != nil {\n\t\treturn fmt.Sprintf(\n\t\t\t\"%s/%s>%s\",\n\t\t\tp.LocalProfile().Source,\n\t\t\tp.LocalProfile().ID,\n\t\t\tconn.Entity.Domain,\n\t\t)\n\t}\n\n\treturn \"?>\" + conn.Entity.Domain\n}\n\nfunc getStickiedHub(conn *network.Connection) (sticksTo *stickyHub) {\n\tstickyLock.Lock()\n\tdefer stickyLock.Unlock()\n\n\t// Check if IP is sticky.\n\tsticksTo = stickyIPs[makeStickyIPKey(conn)] // byte comparison\n\tif sticksTo != nil && !sticksTo.isExpired() {\n\t\tsticksTo.LastSeen = time.Now()\n\t}\n\n\t// If the IP did not stick and we have a domain, check if that sticks.\n\tif sticksTo == nil && conn.Entity.Domain != \"\" {\n\t\tvar ok bool\n\t\tsticksTo, ok = stickyDomains[makeStickyDomainKey(conn)]\n\t\tif ok && !sticksTo.isExpired() {\n\t\t\tsticksTo.LastSeen = time.Now()\n\t\t}\n\t}\n\n\t// If nothing sticked, return now.\n\tif sticksTo == nil {\n\t\treturn nil\n\t}\n\n\t// Get intel from map before locking pin to avoid simultaneous locking.\n\tmapIntel := navigator.Main.GetIntel()\n\n\t// Lock Pin for checking.\n\tsticksTo.Pin.Lock()\n\tdefer sticksTo.Pin.Unlock()\n\n\t// Check if the stickied Hub supports the needed IP version.\n\tswitch {\n\tcase conn.IPVersion == packet.IPv4 && sticksTo.Pin.EntityV4 == nil:\n\t\t// Connection is IPv4, but stickied Hub has no IPv4.\n\t\treturn nil\n\tcase conn.IPVersion == packet.IPv6 && sticksTo.Pin.EntityV6 == nil:\n\t\t// Connection is IPv4, but stickied Hub has no IPv4.\n\t\treturn nil\n\t}\n\n\t// Disregard stickied Hub if it is disregard with the current options.\n\tmatcher := conn.TunnelOpts.Destination.Matcher(mapIntel)\n\tif !matcher(sticksTo.Pin) {\n\t\treturn nil\n\t}\n\n\t// Return fully checked stickied Hub.\n\treturn sticksTo\n}\n\nfunc (t *Tunnel) stickDestinationToHub() {\n\tstickyLock.Lock()\n\tdefer stickyLock.Unlock()\n\n\t// Stick to IP.\n\tipKey := makeStickyIPKey(t.connInfo)\n\tstickyIPs[ipKey] = &stickyHub{\n\t\tPin:      t.dstPin,\n\t\tRoute:    t.route,\n\t\tLastSeen: time.Now(),\n\t}\n\tlog.Infof(\"spn/crew: sticking %s to %s\", ipKey, t.dstPin.Hub)\n\n\t// Stick to Domain, if present.\n\tif t.connInfo.Entity.Domain != \"\" {\n\t\tdomainKey := makeStickyDomainKey(t.connInfo)\n\t\tstickyDomains[domainKey] = &stickyHub{\n\t\t\tPin:      t.dstPin,\n\t\t\tRoute:    t.route,\n\t\t\tLastSeen: time.Now(),\n\t\t}\n\t\tlog.Infof(\"spn/crew: sticking %s to %s\", domainKey, t.dstPin.Hub)\n\t}\n}\n\nfunc (t *Tunnel) avoidDestinationHub() {\n\tstickyLock.Lock()\n\tdefer stickyLock.Unlock()\n\n\t// Stick to Hub/IP Pair.\n\tipKey := makeStickyIPKey(t.connInfo)\n\tstickyIPs[ipKey] = &stickyHub{\n\t\tPin:      t.dstPin,\n\t\tLastSeen: time.Now(),\n\t\tAvoid:    true,\n\t}\n\tlog.Warningf(\"spn/crew: avoiding %s for %s\", t.dstPin.Hub, ipKey)\n\n\t// TODO: Question: Should we avoid the domain as well? (stickyDomains)\n}\n\nfunc cleanStickyHubs(ctx *mgr.WorkerCtx) error {\n\tstickyLock.Lock()\n\tdefer stickyLock.Unlock()\n\n\tfor _, stickyRegistry := range []map[string]*stickyHub{stickyIPs, stickyDomains} {\n\t\tfor key, stickedEntry := range stickyRegistry {\n\t\t\tif stickedEntry.isExpired() {\n\t\t\t\tdelete(stickyRegistry, key)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc clearStickyHubs() {\n\tstickyLock.Lock()\n\tdefer stickyLock.Unlock()\n\n\tfor _, stickyRegistry := range []map[string]*stickyHub{stickyIPs, stickyDomains} {\n\t\tfor key := range stickyRegistry {\n\t\t\tdelete(stickyRegistry, key)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/debug.go",
    "content": "package spn\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"runtime\"\n\n\t\"github.com/maruel/panicparse/v2/stack\"\n\n\t\"github.com/safing/portmaster/base/utils/debug\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// GetWorkerInfo returns the worker info of all running workers.\nfunc (i *Instance) GetWorkerInfo() (*mgr.WorkerInfo, error) {\n\tsnapshot, _, err := stack.ScanSnapshot(bytes.NewReader(fullStack()), io.Discard, stack.DefaultOpts())\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"get stack: %w\", err)\n\t}\n\n\tinfos := make([]*mgr.WorkerInfo, 0, 32)\n\tfor _, m := range i.serviceGroup.Modules() {\n\t\twi, _ := m.Manager().WorkerInfo(snapshot) // Does not fail when we provide a snapshot.\n\t\tinfos = append(infos, wi)\n\t}\n\n\treturn mgr.MergeWorkerInfo(infos...), nil\n}\n\n// AddWorkerInfoToDebugInfo adds the worker info of all running workers to the debug info.\nfunc (i *Instance) AddWorkerInfoToDebugInfo(di *debug.Info) {\n\tinfo, err := i.GetWorkerInfo()\n\tif err != nil {\n\t\tdi.AddSection(\n\t\t\t\"Worker Status Failed\",\n\t\t\tdebug.UseCodeSection,\n\t\t\terr.Error(),\n\t\t)\n\t\treturn\n\t}\n\n\tdi.AddSection(\n\t\tfmt.Sprintf(\"Worker Status: %d/%d (%d?)\", info.Running, len(info.Workers), info.Missing+info.Other),\n\t\tdebug.UseCodeSection,\n\t\tinfo.Format(),\n\t)\n}\n\nfunc fullStack() []byte {\n\tbuf := make([]byte, 8096)\n\tfor {\n\t\tn := runtime.Stack(buf, true)\n\t\tif n < len(buf) {\n\t\t\treturn buf[:n]\n\t\t}\n\t\tbuf = make([]byte, 2*len(buf))\n\t}\n}\n"
  },
  {
    "path": "spn/docks/bandwidth_test.go",
    "content": "package docks\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nfunc TestEffectiveBandwidth(t *testing.T) { //nolint:paralleltest // Run alone.\n\t// Skip in CI.\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\tvar (\n\t\tbwTestDelay            = 50 * time.Millisecond\n\t\tbwTestQueueSize uint32 = 1000\n\t\tbwTestVolume           = 10000000 // 10MB\n\t\tbwTestTime             = 10 * time.Second\n\t)\n\n\t// Create test terminal pair.\n\ta, b, err := terminal.NewSimpleTestTerminalPair(\n\t\tbwTestDelay,\n\t\tint(bwTestQueueSize),\n\t\t&terminal.TerminalOpts{\n\t\t\tFlowControl:     terminal.FlowControlDFQ,\n\t\t\tFlowControlSize: bwTestQueueSize,\n\t\t},\n\t)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create test terminal pair: %s\", err)\n\t}\n\n\t// Grant permission for op on remote terminal and start op.\n\tb.GrantPermission(terminal.IsCraneController)\n\n\t// Re-use the capacity test for the bandwidth test.\n\top := &CapacityTestOp{\n\t\topts: &CapacityTestOptions{\n\t\t\tTestVolume: bwTestVolume,\n\t\t\tMaxTime:    bwTestTime,\n\t\t\ttesting:    true,\n\t\t},\n\t\trecvQueue:       make(chan *terminal.Msg),\n\t\tdataSent:        new(int64),\n\t\tdataSentWasAckd: abool.New(),\n\t\tresult:          make(chan *terminal.Error, 1),\n\t}\n\t// Disable sender again.\n\top.senderStarted = true\n\top.dataSentWasAckd.Set()\n\t// Make capacity test request.\n\trequest, err := dsd.Dump(op.opts, dsd.CBOR)\n\tif err != nil {\n\t\tt.Fatal(terminal.ErrInternalError.With(\"failed to serialize capactity test options: %w\", err))\n\t}\n\t// Send test request.\n\ttErr := a.StartOperation(op, container.New(request), 1*time.Second)\n\tif tErr != nil {\n\t\tt.Fatal(tErr)\n\t}\n\t// Start handler.\n\tmodule.mgr.Go(\"op capacity handler\", op.handler)\n\n\t// Wait for result and check error.\n\ttErr = <-op.Result()\n\tif !tErr.IsOK() {\n\t\tt.Fatalf(\"op failed: %s\", tErr)\n\t}\n\tt.Logf(\"measured capacity: %d bit/s\", op.testResult)\n\n\t// Calculate expected bandwidth.\n\texpectedBitsPerSecond := (float64(capacityTestMsgSize*8*int64(bwTestQueueSize)) / float64(bwTestDelay)) * float64(time.Second)\n\tt.Logf(\"expected capacity: %f bit/s\", expectedBitsPerSecond)\n\n\t// Check if measured bandwidth is within parameters.\n\tif float64(op.testResult) > expectedBitsPerSecond*1.6 {\n\t\tt.Fatal(\"measured capacity too high\")\n\t}\n\t// TODO: Check if we can raise this to at least 90%.\n\tif float64(op.testResult) < expectedBitsPerSecond*0.2 {\n\t\tt.Fatal(\"measured capacity too low\")\n\t}\n}\n"
  },
  {
    "path": "spn/docks/controller.go",
    "content": "package docks\n\nimport (\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n)\n\n// CraneControllerTerminal is a terminal for the crane itself.\ntype CraneControllerTerminal struct {\n\t*terminal.TerminalBase\n\n\tCrane *Crane\n}\n\n// NewLocalCraneControllerTerminal returns a new local crane controller.\nfunc NewLocalCraneControllerTerminal(\n\tcrane *Crane,\n\tinitMsg *terminal.TerminalOpts,\n) (*CraneControllerTerminal, *container.Container, *terminal.Error) {\n\t// Remove unnecessary options from the crane controller.\n\tinitMsg.Padding = 0\n\n\t// Create Terminal Base.\n\tt, initData, err := terminal.NewLocalBaseTerminal(\n\t\tcrane.ctx,\n\t\t0,\n\t\tcrane.ID,\n\t\tnil,\n\t\tinitMsg,\n\t\tterminal.UpstreamSendFunc(crane.sendImportantTerminalMsg),\n\t)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn initCraneController(crane, t, initMsg), initData, nil\n}\n\n// NewRemoteCraneControllerTerminal returns a new remote crane controller.\nfunc NewRemoteCraneControllerTerminal(\n\tcrane *Crane,\n\tinitData *container.Container,\n) (*CraneControllerTerminal, *terminal.TerminalOpts, *terminal.Error) {\n\t// Create Terminal Base.\n\tt, initMsg, err := terminal.NewRemoteBaseTerminal(\n\t\tcrane.ctx,\n\t\t0,\n\t\tcrane.ID,\n\t\tnil,\n\t\tinitData,\n\t\tterminal.UpstreamSendFunc(crane.sendImportantTerminalMsg),\n\t)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn initCraneController(crane, t, initMsg), initMsg, nil\n}\n\nfunc initCraneController(\n\tcrane *Crane,\n\tt *terminal.TerminalBase,\n\tinitMsg *terminal.TerminalOpts,\n) *CraneControllerTerminal {\n\t// Create Crane Terminal and assign it as the extended Terminal.\n\tcct := &CraneControllerTerminal{\n\t\tTerminalBase: t,\n\t\tCrane:        crane,\n\t}\n\tt.SetTerminalExtension(cct)\n\n\t// Assign controller to crane.\n\tcrane.Controller = cct\n\tcrane.terminals[cct.ID()] = cct\n\n\t// Copy the options to the crane itself.\n\tcrane.opts = *initMsg\n\n\t// Grant crane controller permission.\n\tt.GrantPermission(terminal.IsCraneController)\n\n\t// Start workers.\n\tt.StartWorkers(module.mgr, \"crane controller terminal\")\n\n\treturn cct\n}\n\n// HandleAbandon gives the terminal the ability to cleanly shut down.\nfunc (controller *CraneControllerTerminal) HandleAbandon(err *terminal.Error) (errorToSend *terminal.Error) {\n\t// Abandon terminal.\n\tcontroller.Crane.AbandonTerminal(0, err)\n\n\treturn err\n}\n\n// HandleDestruction gives the terminal the ability to clean up.\nfunc (controller *CraneControllerTerminal) HandleDestruction(err *terminal.Error) {\n\t// Stop controlled crane.\n\tcontroller.Crane.Stop(nil)\n}\n"
  },
  {
    "path": "spn/docks/crane.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/varint\"\n)\n\nconst (\n\t// QOTD holds the quote of the day to return on idling unused connections.\n\tQOTD = \"Privacy is not an option, and it shouldn't be the price we accept for just getting on the Internet.\\nGary Kovacs\\n\"\n\n\t// maxUnloadSize defines the maximum size of a message to unload.\n\tmaxUnloadSize            = 16384\n\tmaxSegmentLength         = 16384\n\tmaxCraneStoppingDuration = 6 * time.Hour\n\tmaxCraneStopDuration     = 10 * time.Second\n)\n\nvar (\n\t// optimalMinLoadSize defines minimum for Crane.targetLoadSize.\n\toptimalMinLoadSize = 3072 // Targeting around 4096.\n\n\t// loadingMaxWaitDuration is the maximum time a crane will wait for\n\t// additional data to send.\n\tloadingMaxWaitDuration = 5 * time.Millisecond\n)\n\n// Errors.\nvar (\n\tErrDone = errors.New(\"crane is done\")\n)\n\n// Crane is the primary duplexer and connection manager.\ntype Crane struct {\n\t// ID is the ID of the Crane.\n\tID string\n\t// opts holds options.\n\topts terminal.TerminalOpts\n\n\t// ctx is the context of the Terminal.\n\tctx context.Context\n\t// cancelCtx cancels ctx.\n\tcancelCtx context.CancelFunc\n\t// stopping indicates if the Crane will be stopped soon. The Crane may still\n\t// be used until stopped, but must not be advertised anymore.\n\tstopping *abool.AtomicBool\n\t// stopped indicates if the Crane has been stopped. Whoever stopped the Crane\n\t// already took care of notifying everyone, so a silent fail is normally the\n\t// best response.\n\tstopped *abool.AtomicBool\n\t// authenticated indicates if there is has been any successful authentication.\n\tauthenticated *abool.AtomicBool\n\n\t// ConnectedHub is the identity of the remote Hub.\n\tConnectedHub *hub.Hub\n\t// NetState holds the network optimization state.\n\t// It must always be set and the reference must not be changed.\n\t// Access to fields within are coordinated by itself.\n\tNetState *NetworkOptimizationState\n\t// identity is identity of this instance and is usually only populated on a server.\n\tidentity *cabin.Identity\n\n\t// jession is the jess session used for encryption.\n\tjession *jess.Session\n\t// jessionLock locks jession.\n\tjessionLock sync.Mutex\n\n\t// Controller is the Crane's Controller Terminal.\n\tController *CraneControllerTerminal\n\n\t// ship represents the underlying physical connection.\n\tship ships.Ship\n\t// unloading moves containers from the ship to the crane.\n\tunloading chan *container.Container\n\t// loading moves containers from the crane to the ship.\n\tloading chan *container.Container\n\t// terminalMsgs holds containers from terminals waiting to be laoded.\n\tterminalMsgs chan *terminal.Msg\n\t// controllerMsgs holds important containers from terminals waiting to be laoded.\n\tcontrollerMsgs chan *terminal.Msg\n\n\t// terminals holds all the connected terminals.\n\tterminals map[uint32]terminal.Terminal\n\t// terminalsLock locks terminals.\n\tterminalsLock sync.Mutex\n\t// nextTerminalID holds the next terminal ID.\n\tnextTerminalID uint32\n\n\t// targetLoadSize defines the optimal loading size.\n\ttargetLoadSize int\n}\n\n// NewCrane returns a new crane.\nfunc NewCrane(ship ships.Ship, connectedHub *hub.Hub, id *cabin.Identity) (*Crane, error) {\n\t// Cranes always run in module context.\n\tctx, cancelCtx := context.WithCancel(module.mgr.Ctx())\n\n\tnewCrane := &Crane{\n\t\tctx:           ctx,\n\t\tcancelCtx:     cancelCtx,\n\t\tstopping:      abool.NewBool(false),\n\t\tstopped:       abool.NewBool(false),\n\t\tauthenticated: abool.NewBool(false),\n\n\t\tConnectedHub: connectedHub,\n\t\tNetState:     newNetworkOptimizationState(),\n\t\tidentity:     id,\n\n\t\tship:           ship,\n\t\tunloading:      make(chan *container.Container),\n\t\tloading:        make(chan *container.Container, 100),\n\t\tterminalMsgs:   make(chan *terminal.Msg, 100),\n\t\tcontrollerMsgs: make(chan *terminal.Msg, 100),\n\n\t\tterminals: make(map[uint32]terminal.Terminal),\n\t}\n\terr := registerCrane(newCrane)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to register crane: %w\", err)\n\t}\n\n\t// Shift next terminal IDs on the server.\n\tif !ship.IsMine() {\n\t\tnewCrane.nextTerminalID += 4\n\t}\n\n\t// Calculate target load size.\n\tloadSize := ship.LoadSize()\n\tif loadSize <= 0 {\n\t\tloadSize = ships.BaseMTU\n\t}\n\tnewCrane.targetLoadSize = loadSize\n\tfor newCrane.targetLoadSize < optimalMinLoadSize {\n\t\tnewCrane.targetLoadSize += loadSize\n\t}\n\t// Subtract overhead needed for encryption.\n\tnewCrane.targetLoadSize -= 25 // Manually tested for jess.SuiteWireV1\n\t// Subtract space needed for length encoding the final chunk.\n\tnewCrane.targetLoadSize -= varint.EncodedSize(uint64(newCrane.targetLoadSize))\n\n\treturn newCrane, nil\n}\n\n// IsMine returns whether the crane was started on this side.\nfunc (crane *Crane) IsMine() bool {\n\treturn crane.ship.IsMine()\n}\n\n// Public returns whether the crane has been published.\nfunc (crane *Crane) Public() bool {\n\treturn crane.ship.Public()\n}\n\n// IsStopping returns whether the crane is stopping.\nfunc (crane *Crane) IsStopping() bool {\n\treturn crane.stopping.IsSet()\n}\n\n// MarkStoppingRequested marks the crane as stopping requested.\nfunc (crane *Crane) MarkStoppingRequested() {\n\tcrane.NetState.lock.Lock()\n\tdefer crane.NetState.lock.Unlock()\n\n\tif !crane.NetState.stoppingRequested {\n\t\tcrane.NetState.stoppingRequested = true\n\t\tcrane.startSyncStateOp()\n\t}\n}\n\n// MarkStopping marks the crane as stopping.\nfunc (crane *Crane) MarkStopping() (stopping bool) {\n\t// Can only stop owned cranes.\n\tif !crane.IsMine() {\n\t\treturn false\n\t}\n\n\tif !crane.stopping.SetToIf(false, true) {\n\t\treturn false\n\t}\n\n\tcrane.NetState.lock.Lock()\n\tdefer crane.NetState.lock.Unlock()\n\tcrane.NetState.markedStoppingAt = time.Now()\n\n\tcrane.startSyncStateOp()\n\treturn true\n}\n\n// AbortStopping aborts the stopping.\nfunc (crane *Crane) AbortStopping() (aborted bool) {\n\taborted = crane.stopping.SetToIf(true, false)\n\n\tcrane.NetState.lock.Lock()\n\tdefer crane.NetState.lock.Unlock()\n\n\tabortedStoppingRequest := crane.NetState.stoppingRequested\n\tcrane.NetState.stoppingRequested = false\n\tcrane.NetState.markedStoppingAt = time.Time{}\n\n\t// Sync if any state changed.\n\tif aborted || abortedStoppingRequest {\n\t\tcrane.startSyncStateOp()\n\t}\n\n\treturn aborted\n}\n\n// Authenticated returns whether the other side of the crane has authenticated\n// itself with an access code.\nfunc (crane *Crane) Authenticated() bool {\n\treturn crane.authenticated.IsSet()\n}\n\n// Publish publishes the connection as a lane.\nfunc (crane *Crane) Publish() error {\n\t// Check if crane is connected.\n\tif crane.ConnectedHub == nil {\n\t\treturn fmt.Errorf(\"spn/docks: %s: cannot publish without defined connected hub\", crane)\n\t}\n\n\t// Submit metrics.\n\tif !crane.Public() {\n\t\tnewPublicCranes.Inc()\n\t}\n\n\t// Mark crane as public.\n\tmaskedID := crane.ship.MaskAddress(crane.ship.RemoteAddr())\n\tcrane.ship.MarkPublic()\n\n\t// Assign crane to make it available to others.\n\tAssignCrane(crane.ConnectedHub.ID, crane)\n\n\tlog.Infof(\"spn/docks: %s (was %s) is now public\", crane, maskedID)\n\treturn nil\n}\n\n// LocalAddr returns ship's local address.\nfunc (crane *Crane) LocalAddr() net.Addr {\n\treturn crane.ship.LocalAddr()\n}\n\n// RemoteAddr returns ship's local address.\nfunc (crane *Crane) RemoteAddr() net.Addr {\n\treturn crane.ship.RemoteAddr()\n}\n\n// Transport returns ship's transport.\nfunc (crane *Crane) Transport() *hub.Transport {\n\treturn crane.ship.Transport()\n}\n\nfunc (crane *Crane) getNextTerminalID() uint32 {\n\tcrane.terminalsLock.Lock()\n\tdefer crane.terminalsLock.Unlock()\n\n\tfor {\n\t\t// Bump to next ID.\n\t\tcrane.nextTerminalID += 8\n\n\t\t// Check if it's free.\n\t\t_, ok := crane.terminals[crane.nextTerminalID]\n\t\tif !ok {\n\t\t\treturn crane.nextTerminalID\n\t\t}\n\t}\n}\n\nfunc (crane *Crane) terminalCount() int {\n\tcrane.terminalsLock.Lock()\n\tdefer crane.terminalsLock.Unlock()\n\n\treturn len(crane.terminals)\n}\n\nfunc (crane *Crane) getTerminal(id uint32) (t terminal.Terminal, ok bool) {\n\tcrane.terminalsLock.Lock()\n\tdefer crane.terminalsLock.Unlock()\n\n\tt, ok = crane.terminals[id]\n\treturn\n}\n\nfunc (crane *Crane) setTerminal(t terminal.Terminal) {\n\tcrane.terminalsLock.Lock()\n\tdefer crane.terminalsLock.Unlock()\n\n\tcrane.terminals[t.ID()] = t\n}\n\nfunc (crane *Crane) deleteTerminal(id uint32) (t terminal.Terminal, ok bool) {\n\tcrane.terminalsLock.Lock()\n\tdefer crane.terminalsLock.Unlock()\n\n\tt, ok = crane.terminals[id]\n\tif ok {\n\t\tdelete(crane.terminals, id)\n\t\treturn t, true\n\t}\n\treturn nil, false\n}\n\n// AbandonTerminal abandons the terminal with the given ID.\nfunc (crane *Crane) AbandonTerminal(id uint32, err *terminal.Error) {\n\t// Get active terminal.\n\tt, ok := crane.deleteTerminal(id)\n\tif ok {\n\t\t// If the terminal was registered, abandon it.\n\n\t\t// Log reason the terminal is ending. Override stopping error with nil.\n\t\tswitch {\n\t\tcase err == nil || err.IsOK():\n\t\t\tlog.Debugf(\"spn/docks: %T %s is being abandoned\", t, t.FmtID())\n\t\tcase err.Is(terminal.ErrStopping):\n\t\t\terr = nil\n\t\t\tlog.Debugf(\"spn/docks: %T %s is being abandoned by peer\", t, t.FmtID())\n\t\tcase err.Is(terminal.ErrNoActivity):\n\t\t\terr = nil\n\t\t\tlog.Debugf(\"spn/docks: %T %s is being abandoned due to no activity\", t, t.FmtID())\n\t\tdefault:\n\t\t\tlog.Warningf(\"spn/docks: %T %s: %s\", t, t.FmtID(), err)\n\t\t}\n\n\t\t// Call the terminal's abandon function.\n\t\tt.Abandon(err)\n\t} else { //nolint:gocritic\n\t\t// When a crane terminal is abandoned, it calls crane.AbandonTerminal when\n\t\t// finished. This time, the terminal won't be in the registry anymore and\n\t\t// it finished shutting down, so we can now check if the crane needs to be\n\t\t// stopped.\n\n\t\t// If the crane is stopping, check if we can stop.\n\t\t// We can stop when all terminals are abandoned or after a timeout.\n\t\t// FYI: The crane controller will always take up one slot.\n\t\tif crane.stopping.IsSet() &&\n\t\t\tcrane.terminalCount() <= 1 {\n\t\t\t// Stop the crane in worker, so the caller can do some work.\n\t\t\tmodule.mgr.Go(\"retire crane\", func(_ *mgr.WorkerCtx) error {\n\t\t\t\t// Let enough time for the last errors to be sent, as terminals are abandoned in a goroutine.\n\t\t\t\ttime.Sleep(3 * time.Second)\n\t\t\t\tcrane.Stop(nil)\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc (crane *Crane) sendImportantTerminalMsg(msg *terminal.Msg, timeout time.Duration) *terminal.Error {\n\tselect {\n\tcase crane.controllerMsgs <- msg:\n\t\treturn nil\n\tcase <-crane.ctx.Done():\n\t\tmsg.Finish()\n\t\treturn terminal.ErrCanceled\n\t}\n}\n\n// Send is used by others to send a message through the crane.\nfunc (crane *Crane) Send(msg *terminal.Msg, timeout time.Duration) *terminal.Error {\n\tselect {\n\tcase crane.terminalMsgs <- msg:\n\t\treturn nil\n\tcase <-crane.ctx.Done():\n\t\tmsg.Finish()\n\t\treturn terminal.ErrCanceled\n\t}\n}\n\nfunc (crane *Crane) encrypt(shipment *container.Container) (encrypted *container.Container, err error) {\n\t// Skip if encryption is not enabled.\n\tif crane.jession == nil {\n\t\treturn shipment, nil\n\t}\n\n\tcrane.jessionLock.Lock()\n\tdefer crane.jessionLock.Unlock()\n\n\tletter, err := crane.jession.Close(shipment.CompileData())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tencrypted, err = letter.ToWire()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to pack letter: %w\", err)\n\t}\n\n\treturn encrypted, nil\n}\n\nfunc (crane *Crane) decrypt(shipment *container.Container) (decrypted *container.Container, err error) {\n\t// Skip if encryption is not enabled.\n\tif crane.jession == nil {\n\t\treturn shipment, nil\n\t}\n\n\tcrane.jessionLock.Lock()\n\tdefer crane.jessionLock.Unlock()\n\n\tletter, err := jess.LetterFromWire(shipment)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse letter: %w\", err)\n\t}\n\n\tdecryptedData, err := crane.jession.Open(letter)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn container.New(decryptedData), nil\n}\n\nfunc (crane *Crane) unloader(workerCtx *mgr.WorkerCtx) error {\n\t// Unclean shutdown safeguard.\n\tdefer crane.Stop(terminal.ErrUnknownError.With(\"unloader died\"))\n\n\tfor {\n\t\t// Get first couple bytes to get the packet length.\n\t\t// 2 bytes are enough to encode 65535.\n\t\t// On the other hand, packets can be only 2 bytes small.\n\t\tlenBuf := make([]byte, 2)\n\t\terr := crane.unloadUntilFull(lenBuf)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tcrane.Stop(terminal.ErrStopping.With(\"connection closed\"))\n\t\t\t} else {\n\t\t\t\tcrane.Stop(terminal.ErrInternalError.With(\"failed to unload: %w\", err))\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\t// Unpack length.\n\t\tcontainerLen, n, err := varint.Unpack64(lenBuf)\n\t\tif err != nil {\n\t\t\tcrane.Stop(terminal.ErrMalformedData.With(\"failed to get container length: %w\", err))\n\t\t\treturn nil\n\t\t}\n\t\tswitch {\n\t\tcase containerLen <= 0:\n\t\t\tcrane.Stop(terminal.ErrMalformedData.With(\"received empty container with length %d\", containerLen))\n\t\t\treturn nil\n\t\tcase containerLen > maxUnloadSize:\n\t\t\tcrane.Stop(terminal.ErrMalformedData.With(\"received oversized container with length %d\", containerLen))\n\t\t\treturn nil\n\t\t}\n\n\t\t// Build shipment.\n\t\tvar shipmentBuf []byte\n\t\tleftovers := len(lenBuf) - n\n\n\t\tif leftovers == int(containerLen) {\n\t\t\t// We already have all the shipment data.\n\t\t\tshipmentBuf = lenBuf[n:]\n\t\t} else {\n\t\t\t// Create a shipment buffer, copy leftovers and read the rest from the connection.\n\t\t\tshipmentBuf = make([]byte, containerLen)\n\t\t\tif leftovers > 0 {\n\t\t\t\tcopy(shipmentBuf, lenBuf[n:])\n\t\t\t}\n\n\t\t\t// Read remaining shipment.\n\t\t\terr = crane.unloadUntilFull(shipmentBuf[leftovers:])\n\t\t\tif err != nil {\n\t\t\t\tcrane.Stop(terminal.ErrInternalError.With(\"failed to unload: %w\", err))\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\t// Submit to handler.\n\t\tselect {\n\t\tcase <-crane.ctx.Done():\n\t\t\tcrane.Stop(nil)\n\t\t\treturn nil\n\t\tcase crane.unloading <- container.New(shipmentBuf):\n\t\t}\n\t}\n}\n\nfunc (crane *Crane) unloadUntilFull(buf []byte) error {\n\tvar bytesRead int\n\tfor {\n\t\t// Get shipment from ship.\n\t\tn, err := crane.ship.UnloadTo(buf[bytesRead:])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif n == 0 {\n\t\t\tlog.Tracef(\"spn/docks: %s unloaded 0 bytes\", crane)\n\t\t}\n\t\tbytesRead += n\n\n\t\t// Return if buffer has been fully filled.\n\t\tif bytesRead == len(buf) {\n\t\t\t// Submit metrics.\n\t\t\tcrane.submitCraneTrafficStats(bytesRead)\n\t\t\tcrane.NetState.ReportTraffic(uint64(bytesRead), true)\n\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (crane *Crane) handler(workerCtx *mgr.WorkerCtx) error {\n\tvar partialShipment *container.Container\n\tvar segmentLength uint32\n\n\t// Unclean shutdown safeguard.\n\tdefer crane.Stop(terminal.ErrUnknownError.With(\"handler died\"))\n\nhandling:\n\tfor {\n\t\tselect {\n\t\tcase <-crane.ctx.Done():\n\t\t\tcrane.Stop(nil)\n\t\t\treturn nil\n\n\t\tcase shipment := <-crane.unloading:\n\t\t\t// log.Debugf(\"spn/crane %s: before decrypt: %v ... %v\", crane.ID, c.CompileData()[:10], c.CompileData()[c.Length()-10:])\n\n\t\t\t// Decrypt shipment.\n\t\t\tshipment, err := crane.decrypt(shipment)\n\t\t\tif err != nil {\n\t\t\t\tcrane.Stop(terminal.ErrIntegrity.With(\"failed to decrypt: %w\", err))\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Process all segments/containers of the shipment.\n\t\t\tfor shipment.HoldsData() {\n\t\t\t\tif partialShipment != nil {\n\t\t\t\t\t// Continue processing partial segment.\n\t\t\t\t\t// Append new shipment to previous partial segment.\n\t\t\t\t\tpartialShipment.AppendContainer(shipment)\n\t\t\t\t\tshipment, partialShipment = partialShipment, nil\n\t\t\t\t}\n\n\t\t\t\t// Get next segment length.\n\t\t\t\tif segmentLength == 0 {\n\t\t\t\t\tsegmentLength, err = shipment.GetNextN32()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif errors.Is(err, varint.ErrBufTooSmall) {\n\t\t\t\t\t\t\t// Continue handling when there is not yet enough data.\n\t\t\t\t\t\t\tpartialShipment = shipment\n\t\t\t\t\t\t\tsegmentLength = 0\n\t\t\t\t\t\t\tcontinue handling\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcrane.Stop(terminal.ErrMalformedData.With(\"failed to get segment length: %w\", err))\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\tif segmentLength == 0 {\n\t\t\t\t\t\t// Remainder is padding.\n\t\t\t\t\t\tcontinue handling\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if the segment is within the boundary.\n\t\t\t\t\tif segmentLength > maxSegmentLength {\n\t\t\t\t\t\tcrane.Stop(terminal.ErrMalformedData.With(\"received oversized segment with length %d\", segmentLength))\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check if we have enough data for the segment.\n\t\t\t\tif uint32(shipment.Length()) < segmentLength {\n\t\t\t\t\tpartialShipment = shipment\n\t\t\t\t\tcontinue handling\n\t\t\t\t}\n\n\t\t\t\t// Get segment from shipment.\n\t\t\t\tsegment, err := shipment.GetAsContainer(int(segmentLength))\n\t\t\t\tif err != nil {\n\t\t\t\t\tcrane.Stop(terminal.ErrMalformedData.With(\"failed to get segment: %w\", err))\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tsegmentLength = 0\n\n\t\t\t\t// Get terminal ID and message type of segment.\n\t\t\t\tterminalID, terminalMsgType, err := terminal.ParseIDType(segment)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcrane.Stop(terminal.ErrMalformedData.With(\"failed to get terminal ID and msg type: %w\", err))\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tswitch terminalMsgType {\n\t\t\t\tcase terminal.MsgTypeInit:\n\t\t\t\t\tcrane.establishTerminal(terminalID, segment)\n\n\t\t\t\tcase terminal.MsgTypeData, terminal.MsgTypePriorityData:\n\t\t\t\t\t// Get terminal and let it further handle the message.\n\t\t\t\t\tt, ok := crane.getTerminal(terminalID)\n\t\t\t\t\tif ok {\n\t\t\t\t\t\t// Create msg and set priority.\n\t\t\t\t\t\tmsg := terminal.NewEmptyMsg()\n\t\t\t\t\t\tmsg.FlowID = terminalID\n\t\t\t\t\t\tmsg.Type = terminalMsgType\n\t\t\t\t\t\tmsg.Data = segment\n\t\t\t\t\t\tif msg.Type == terminal.MsgTypePriorityData {\n\t\t\t\t\t\t\tmsg.Unit.MakeHighPriority()\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Deliver to terminal.\n\t\t\t\t\t\tdeliveryErr := t.Deliver(msg)\n\t\t\t\t\t\tif deliveryErr != nil {\n\t\t\t\t\t\t\tmsg.Finish()\n\t\t\t\t\t\t\t// This is a hot path. Start a worker for abandoning the terminal.\n\t\t\t\t\t\t\tmodule.mgr.Go(\"end terminal\", func(_ *mgr.WorkerCtx) error {\n\t\t\t\t\t\t\t\tcrane.AbandonTerminal(t.ID(), deliveryErr.Wrap(\"failed to deliver data\"))\n\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlog.Tracef(\"spn/docks: %s received msg for unknown terminal %d\", crane, terminalID)\n\t\t\t\t\t}\n\n\t\t\t\tcase terminal.MsgTypeStop:\n\t\t\t\t\t// Parse error.\n\t\t\t\t\treceivedErr, err := terminal.ParseExternalError(segment.CompileData())\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Warningf(\"spn/docks: %s failed to parse abandon error: %s\", crane, err)\n\t\t\t\t\t\treceivedErr = terminal.ErrUnknownError.AsExternal()\n\t\t\t\t\t}\n\t\t\t\t\t// This is a hot path. Start a worker for abandoning the terminal.\n\t\t\t\t\tmodule.mgr.Go(\"end terminal\", func(_ *mgr.WorkerCtx) error {\n\t\t\t\t\t\tcrane.AbandonTerminal(terminalID, receivedErr)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (crane *Crane) loader(workerCtx *mgr.WorkerCtx) (err error) {\n\tshipment := container.New()\n\tvar partialShipment *container.Container\n\tvar loadingTimer *time.Timer\n\n\t// Unclean shutdown safeguard.\n\tdefer crane.Stop(terminal.ErrUnknownError.With(\"loader died\"))\n\n\t// Return the loading wait channel if waiting.\n\tloadNow := func() <-chan time.Time {\n\t\tif loadingTimer != nil {\n\t\t\treturn loadingTimer.C\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Make sure any received message is finished\n\tvar msg, firstMsg *terminal.Msg\n\tdefer msg.Finish()\n\tdefer firstMsg.Finish()\n\n\tfor {\n\t\t// Reset first message in shipment.\n\t\tfirstMsg.Finish()\n\t\tfirstMsg = nil\n\n\tfillingShipment:\n\t\tfor shipment.Length() < crane.targetLoadSize {\n\t\t\t// Gather segments until shipment is filled.\n\n\t\t\t// Prioritize messages from the controller.\n\t\t\tselect {\n\t\t\tcase msg = <-crane.controllerMsgs:\n\t\t\tcase <-crane.ctx.Done():\n\t\t\t\tcrane.Stop(nil)\n\t\t\t\treturn nil\n\n\t\t\tdefault:\n\t\t\t\t// Then listen for all.\n\t\t\t\tselect {\n\t\t\t\tcase msg = <-crane.controllerMsgs:\n\t\t\t\tcase msg = <-crane.terminalMsgs:\n\t\t\t\tcase <-loadNow():\n\t\t\t\t\tbreak fillingShipment\n\t\t\t\tcase <-crane.ctx.Done():\n\t\t\t\t\tcrane.Stop(nil)\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Debug unit leaks.\n\t\t\tmsg.Debug()\n\n\t\t\t// Handle new message.\n\t\t\tif msg != nil {\n\t\t\t\t// Pack msg and add to segment.\n\t\t\t\tmsg.Pack()\n\t\t\t\tnewSegment := msg.Data\n\n\t\t\t\t// Check if this is the first message.\n\t\t\t\t// This is the only message where we wait for a slot.\n\t\t\t\tif firstMsg == nil {\n\t\t\t\t\tfirstMsg = msg\n\t\t\t\t\tfirstMsg.Unit.WaitForSlot()\n\t\t\t\t} else {\n\t\t\t\t\tmsg.Finish()\n\t\t\t\t}\n\n\t\t\t\t// Check length.\n\t\t\t\tif newSegment.Length() > maxSegmentLength {\n\t\t\t\t\tlog.Warningf(\"spn/docks: %s ignored oversized segment with length %d\", crane, newSegment.Length())\n\t\t\t\t\tcontinue fillingShipment\n\t\t\t\t}\n\n\t\t\t\t// Append to shipment.\n\t\t\t\tshipment.AppendContainer(newSegment)\n\n\t\t\t\t// Set loading max wait timer on first segment.\n\t\t\t\tif loadingTimer == nil {\n\t\t\t\t\tloadingTimer = time.NewTimer(loadingMaxWaitDuration)\n\t\t\t\t}\n\n\t\t\t} else if crane.stopped.IsSet() {\n\t\t\t\t// If there is no new segment, this might have been triggered by a\n\t\t\t\t// closed channel. Check if the crane is still active.\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\tsendingShipment:\n\t\tfor {\n\t\t\t// Check if we are over the target load size and split the shipment.\n\t\t\tif shipment.Length() > crane.targetLoadSize {\n\t\t\t\tpartialShipment, err = shipment.GetAsContainer(crane.targetLoadSize)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcrane.Stop(terminal.ErrInternalError.With(\"failed to split segment: %w\", err))\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tshipment, partialShipment = partialShipment, shipment\n\t\t\t}\n\n\t\t\t// Load shipment.\n\t\t\terr = crane.load(shipment)\n\t\t\tif err != nil {\n\t\t\t\tcrane.Stop(terminal.ErrShipSunk.With(\"failed to load shipment: %w\", err))\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Reset loading timer.\n\t\t\tloadingTimer = nil\n\n\t\t\t// Continue loading with partial shipment, or a new one.\n\t\t\tif partialShipment != nil {\n\t\t\t\t// Continue loading with a partial previous shipment.\n\t\t\t\tshipment, partialShipment = partialShipment, nil\n\n\t\t\t\t// If shipment is not big enough to send immediately, wait for more data.\n\t\t\t\tif shipment.Length() < crane.targetLoadSize {\n\t\t\t\t\tloadingTimer = time.NewTimer(loadingMaxWaitDuration)\n\t\t\t\t\tbreak sendingShipment\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\t// Continue loading with new shipment.\n\t\t\t\tshipment = container.New()\n\t\t\t\tbreak sendingShipment\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (crane *Crane) load(c *container.Container) error {\n\t// Add Padding if needed.\n\tif crane.opts.Padding > 0 {\n\t\tpaddingNeeded := int(crane.opts.Padding) -\n\t\t\t((c.Length() + varint.EncodedSize(uint64(c.Length()))) % int(crane.opts.Padding))\n\t\t// As the length changes slightly with the padding, we should avoid loading\n\t\t// lengths around the varint size hops:\n\t\t// - 128\n\t\t// - 16384\n\t\t// - 2097152\n\t\t// - 268435456\n\n\t\t// Pad to target load size at maximum.\n\t\tmaxPadding := crane.targetLoadSize - c.Length()\n\t\tif paddingNeeded > maxPadding {\n\t\t\tpaddingNeeded = maxPadding\n\t\t}\n\n\t\tif paddingNeeded > 0 {\n\t\t\t// Add padding indicator.\n\t\t\tc.Append([]byte{0})\n\t\t\tpaddingNeeded--\n\n\t\t\t// Add needed padding data.\n\t\t\tif paddingNeeded > 0 {\n\t\t\t\tpadding, err := rng.Bytes(paddingNeeded)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Debugf(\"spn/docks: %s failed to get random padding data, using zeros instead\", crane)\n\t\t\t\t\tpadding = make([]byte, paddingNeeded)\n\t\t\t\t}\n\t\t\t\tc.Append(padding)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Encrypt shipment.\n\tc, err := crane.encrypt(c)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to encrypt: %w\", err)\n\t}\n\n\t// Finalize data.\n\tc.PrependLength()\n\treadyToSend := c.CompileData()\n\n\t// Submit metrics.\n\tcrane.submitCraneTrafficStats(len(readyToSend))\n\tcrane.NetState.ReportTraffic(uint64(len(readyToSend)), false)\n\n\t// Load onto ship.\n\terr = crane.ship.Load(readyToSend)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to load ship: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Stop stops the crane.\nfunc (crane *Crane) Stop(err *terminal.Error) {\n\tif !crane.stopped.SetToIf(false, true) {\n\t\treturn\n\t}\n\n\t// Log error message.\n\tif err != nil {\n\t\tif err.IsOK() {\n\t\t\tlog.Infof(\"spn/docks: %s is done\", crane)\n\t\t} else {\n\t\t\tlog.Warningf(\"spn/docks: %s is stopping: %s\", crane, err)\n\t\t}\n\t}\n\n\t// Unregister crane.\n\tunregisterCrane(crane)\n\n\t// Stop all terminals.\n\tfor _, t := range crane.allTerms() {\n\t\tt.Abandon(err) // Async!\n\t}\n\n\t// Stop controller.\n\tif crane.Controller != nil {\n\t\tcrane.Controller.Abandon(err) // Async!\n\t}\n\n\t// Wait shortly for all terminals to finish abandoning.\n\twaitStep := 50 * time.Millisecond\n\tfor i := time.Duration(0); i < maxCraneStopDuration; i += waitStep {\n\t\t// Check if all terminals are done.\n\t\tif crane.terminalCount() == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\ttime.Sleep(waitStep)\n\t}\n\n\t// Close connection.\n\tcrane.ship.Sink()\n\n\t// Cancel crane context.\n\tcrane.cancelCtx()\n\n\t// Notify about change.\n\tcrane.NotifyUpdate()\n}\n\nfunc (crane *Crane) allTerms() []terminal.Terminal {\n\tcrane.terminalsLock.Lock()\n\tdefer crane.terminalsLock.Unlock()\n\n\tterms := make([]terminal.Terminal, 0, len(crane.terminals))\n\tfor _, term := range crane.terminals {\n\t\tterms = append(terms, term)\n\t}\n\n\treturn terms\n}\n\nfunc (crane *Crane) String() string {\n\tremoteAddr := crane.ship.RemoteAddr()\n\tswitch {\n\tcase remoteAddr == nil:\n\t\treturn fmt.Sprintf(\"crane %s\", crane.ID)\n\tcase crane.ship.IsMine():\n\t\treturn fmt.Sprintf(\"crane %s to %s\", crane.ID, crane.ship.MaskAddress(crane.ship.RemoteAddr()))\n\tdefault:\n\t\treturn fmt.Sprintf(\"crane %s from %s\", crane.ID, crane.ship.MaskAddress(crane.ship.RemoteAddr()))\n\t}\n}\n\n// Stopped returns whether the crane has stopped.\nfunc (crane *Crane) Stopped() bool {\n\treturn crane.stopped.IsSet()\n}\n"
  },
  {
    "path": "spn/docks/crane_establish.go",
    "content": "package docks\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n)\n\nconst (\n\tdefaultTerminalIdleTimeout = 15 * time.Minute\n\tremoteTerminalIdleTimeout  = 30 * time.Minute\n)\n\n// EstablishNewTerminal establishes a new terminal with the crane.\nfunc (crane *Crane) EstablishNewTerminal(\n\tlocalTerm terminal.Terminal,\n\tinitData *container.Container,\n) *terminal.Error {\n\t// Create message.\n\tmsg := terminal.NewEmptyMsg()\n\tmsg.FlowID = localTerm.ID()\n\tmsg.Type = terminal.MsgTypeInit\n\tmsg.Data = initData\n\n\t// Register terminal with crane.\n\tcrane.setTerminal(localTerm)\n\n\t// Send message.\n\tselect {\n\tcase crane.controllerMsgs <- msg:\n\t\tlog.Debugf(\"spn/docks: %s initiated new terminal %d\", crane, localTerm.ID())\n\t\treturn nil\n\tcase <-crane.ctx.Done():\n\t\tcrane.AbandonTerminal(localTerm.ID(), terminal.ErrStopping.With(\"initiation aborted\"))\n\t\treturn terminal.ErrStopping\n\t}\n}\n\nfunc (crane *Crane) establishTerminal(id uint32, initData *container.Container) {\n\t// Create new remote crane terminal.\n\tnewTerminal, _, err := NewRemoteCraneTerminal(\n\t\tcrane,\n\t\tid,\n\t\tinitData,\n\t)\n\tif err == nil {\n\t\t// Connections via public cranes have a timeout.\n\t\tif crane.Public() {\n\t\t\tnewTerminal.TerminalBase.SetTimeout(remoteTerminalIdleTimeout)\n\t\t}\n\t\t// Register terminal with crane.\n\t\tcrane.setTerminal(newTerminal)\n\t\tlog.Debugf(\"spn/docks: %s established new crane terminal %d\", crane, newTerminal.ID())\n\t\treturn\n\t}\n\n\t// If something goes wrong, send an error back.\n\tlog.Warningf(\"spn/docks: %s failed to establish crane terminal: %s\", crane, err)\n\n\t// Build abandon message.\n\tmsg := terminal.NewMsg(err.Pack())\n\tmsg.FlowID = id\n\tmsg.Type = terminal.MsgTypeStop\n\n\t// Send message directly, or async.\n\tselect {\n\tcase crane.terminalMsgs <- msg:\n\tdefault:\n\t\t// Send error async.\n\t\tmodule.mgr.Go(\"abandon terminal\", func(ctx *mgr.WorkerCtx) error {\n\t\t\tselect {\n\t\t\tcase crane.terminalMsgs <- msg:\n\t\t\tcase <-ctx.Done():\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "spn/docks/crane_init.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n\t\"github.com/safing/structures/varint\"\n)\n\n/*\n\nCrane Init Message Format:\nused by init procedures\n\n- Data [bytes block]\n\t- MsgType [varint]\n\t- Data [bytes; only when MsgType is Verify or Start*]\n\nCrane Init Response Format:\n\n- Data [bytes block]\n\nCrane Operational Message Format:\n\n- Data [bytes block]\n\t- possibly encrypted\n\n*/\n\n// Crane Msg Types.\nconst (\n\tCraneMsgTypeEnd              = 0\n\tCraneMsgTypeInfo             = 1\n\tCraneMsgTypeRequestHubInfo   = 2\n\tCraneMsgTypeVerify           = 3\n\tCraneMsgTypeStartEncrypted   = 4\n\tCraneMsgTypeStartUnencrypted = 5\n)\n\n// Start starts the crane.\nfunc (crane *Crane) Start(callerCtx context.Context) error {\n\tlog.Infof(\"spn/docks: %s is starting\", crane)\n\n\t// Submit metrics.\n\tnewCranes.Inc()\n\n\t// Start crane depending on situation.\n\tvar tErr *terminal.Error\n\tif crane.ship.IsMine() {\n\t\ttErr = crane.startLocal(callerCtx)\n\t} else {\n\t\ttErr = crane.startRemote(callerCtx)\n\t}\n\n\t// Stop crane again if starting failed.\n\tif tErr != nil {\n\t\tcrane.Stop(tErr)\n\t\treturn tErr\n\t}\n\n\tlog.Debugf(\"spn/docks: %s started\", crane)\n\t// Return an explicit nil for working \"!= nil\" checks.\n\treturn nil\n}\n\nfunc (crane *Crane) startLocal(callerCtx context.Context) *terminal.Error {\n\tmodule.mgr.Go(\"crane unloader\", crane.unloader)\n\n\tif !crane.ship.IsSecure() {\n\t\t// Start encrypted channel.\n\t\t// Check if we have all the data we need from the Hub.\n\t\tif crane.ConnectedHub == nil {\n\t\t\treturn terminal.ErrIncorrectUsage.With(\"cannot start encrypted channel without connected hub\")\n\t\t}\n\n\t\t// Always request hub info, as we don't know if the hub has restarted in\n\t\t// the meantime and lost ephemeral keys.\n\t\thubInfoRequest := container.New(\n\t\t\tvarint.Pack8(CraneMsgTypeRequestHubInfo),\n\t\t)\n\t\thubInfoRequest.PrependLength()\n\t\terr := crane.ship.Load(hubInfoRequest.CompileData())\n\t\tif err != nil {\n\t\t\treturn terminal.ErrShipSunk.With(\"failed to request hub info: %w\", err)\n\t\t}\n\n\t\t// Wait for reply.\n\t\tvar reply *container.Container\n\t\tselect {\n\t\tcase reply = <-crane.unloading:\n\t\tcase <-time.After(30 * time.Second):\n\t\t\treturn terminal.ErrTimeout.With(\"waiting for hub info\")\n\t\tcase <-crane.ctx.Done():\n\t\t\treturn terminal.ErrShipSunk.With(\"waiting for hub info\")\n\t\tcase <-callerCtx.Done():\n\t\t\treturn terminal.ErrCanceled.With(\"waiting for hub info\")\n\t\t}\n\n\t\t// Parse and import Announcement and Status.\n\t\tannouncementData, err := reply.GetNextBlock()\n\t\tif err != nil {\n\t\t\treturn terminal.ErrMalformedData.With(\"failed to get announcement: %w\", err)\n\t\t}\n\t\tstatusData, err := reply.GetNextBlock()\n\t\tif err != nil {\n\t\t\treturn terminal.ErrMalformedData.With(\"failed to get status: %w\", err)\n\t\t}\n\t\th, _, tErr := ImportAndVerifyHubInfo(\n\t\t\tcallerCtx,\n\t\t\tcrane.ConnectedHub.ID,\n\t\t\tannouncementData, statusData, conf.MainMapName, conf.MainMapScope,\n\t\t)\n\t\tif tErr != nil {\n\t\t\treturn tErr.Wrap(\"failed to import and verify hub\")\n\t\t}\n\t\t// Update reference in case it was changed by the import.\n\t\tcrane.ConnectedHub = h\n\n\t\t// Now, try to select a public key again.\n\t\tsignet := crane.ConnectedHub.SelectSignet()\n\t\tif signet == nil {\n\t\t\treturn terminal.ErrHubNotReady.With(\"failed to select signet (after updating hub info)\")\n\t\t}\n\n\t\t// Configure encryption.\n\t\tenv := jess.NewUnconfiguredEnvelope()\n\t\tenv.SuiteID = jess.SuiteWireV1\n\t\tenv.Recipients = []*jess.Signet{signet}\n\n\t\t// Do not encrypt directly, rather get session for future use, then encrypt.\n\t\tcrane.jession, err = env.WireCorrespondence(nil)\n\t\tif err != nil {\n\t\t\treturn terminal.ErrInternalError.With(\"failed to create encryption session: %w\", err)\n\t\t}\n\t}\n\n\t// Create crane controller.\n\t_, initData, tErr := NewLocalCraneControllerTerminal(crane, terminal.DefaultCraneControllerOpts())\n\tif tErr != nil {\n\t\treturn tErr.Wrap(\"failed to set up controller\")\n\t}\n\n\t// Prepare init message for sending.\n\tif crane.ship.IsSecure() {\n\t\tinitData.PrependNumber(CraneMsgTypeStartUnencrypted)\n\t} else {\n\t\t// Encrypt controller initializer.\n\t\tletter, err := crane.jession.Close(initData.CompileData())\n\t\tif err != nil {\n\t\t\treturn terminal.ErrInternalError.With(\"failed to encrypt initial packet: %w\", err)\n\t\t}\n\t\tinitData, err = letter.ToWire()\n\t\tif err != nil {\n\t\t\treturn terminal.ErrInternalError.With(\"failed to pack initial packet: %w\", err)\n\t\t}\n\t\tinitData.PrependNumber(CraneMsgTypeStartEncrypted)\n\t}\n\n\t// Send start message.\n\tinitData.PrependLength()\n\terr := crane.ship.Load(initData.CompileData())\n\tif err != nil {\n\t\treturn terminal.ErrShipSunk.With(\"failed to send init msg: %w\", err)\n\t}\n\n\t// Start remaining workers.\n\tmodule.mgr.Go(\"crane loader\", crane.loader)\n\tmodule.mgr.Go(\"crane handler\", crane.handler)\n\n\treturn nil\n}\n\nfunc (crane *Crane) startRemote(callerCtx context.Context) *terminal.Error {\n\tvar initMsg *container.Container\n\n\tmodule.mgr.Go(\"crane unloader\", crane.unloader)\n\nhandling:\n\tfor {\n\t\t// Wait for request.\n\t\tvar request *container.Container\n\t\tselect {\n\t\tcase request = <-crane.unloading:\n\n\t\tcase <-time.After(30 * time.Second):\n\t\t\treturn terminal.ErrTimeout.With(\"waiting for crane init msg\")\n\t\tcase <-crane.ctx.Done():\n\t\t\treturn terminal.ErrShipSunk.With(\"waiting for crane init msg\")\n\t\tcase <-callerCtx.Done():\n\t\t\treturn terminal.ErrCanceled.With(\"waiting for crane init msg\")\n\t\t}\n\n\t\tmsgType, err := request.GetNextN8()\n\t\tif err != nil {\n\t\t\treturn terminal.ErrMalformedData.With(\"failed to parse crane msg type: %s\", err)\n\t\t}\n\n\t\tswitch msgType {\n\t\tcase CraneMsgTypeEnd:\n\t\t\t// End connection.\n\t\t\treturn terminal.ErrStopping\n\n\t\tcase CraneMsgTypeInfo:\n\t\t\t// Info is a terminating request.\n\t\t\terr := crane.handleCraneInfo()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Debugf(\"spn/docks: %s sent version info\", crane)\n\n\t\tcase CraneMsgTypeRequestHubInfo:\n\t\t\t// Handle Hub info request.\n\t\t\terr := crane.handleCraneHubInfo()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Debugf(\"spn/docks: %s sent hub info\", crane)\n\n\t\tcase CraneMsgTypeVerify:\n\t\t\t// Verify is a terminating request.\n\t\t\terr := crane.handleCraneVerification(request)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tlog.Infof(\"spn/docks: %s sent hub verification\", crane)\n\n\t\tcase CraneMsgTypeStartUnencrypted:\n\t\t\tinitMsg = request\n\n\t\t\t// Start crane with initMsg.\n\t\t\tlog.Debugf(\"spn/docks: %s initiated unencrypted channel\", crane)\n\t\t\tbreak handling\n\n\t\tcase CraneMsgTypeStartEncrypted:\n\t\t\tif crane.identity == nil {\n\t\t\t\treturn terminal.ErrIncorrectUsage.With(\"cannot start incoming crane without designated identity\")\n\t\t\t}\n\n\t\t\t// Set up encryption.\n\t\t\tletter, err := jess.LetterFromWire(container.New(request.CompileData()))\n\t\t\tif err != nil {\n\t\t\t\treturn terminal.ErrMalformedData.With(\"failed to unpack initial packet: %w\", err)\n\t\t\t}\n\t\t\tcrane.jession, err = letter.WireCorrespondence(crane.identity)\n\t\t\tif err != nil {\n\t\t\t\treturn terminal.ErrInternalError.With(\"failed to create encryption session: %w\", err)\n\t\t\t}\n\t\t\tinitMsgData, err := crane.jession.Open(letter)\n\t\t\tif err != nil {\n\t\t\t\treturn terminal.ErrIntegrity.With(\"failed to decrypt initial packet: %w\", err)\n\t\t\t}\n\t\t\tinitMsg = container.New(initMsgData)\n\n\t\t\t// Start crane with initMsg.\n\t\t\tlog.Debugf(\"spn/docks: %s initiated encrypted channel\", crane)\n\t\t\tbreak handling\n\t\t}\n\t}\n\n\t_, _, err := NewRemoteCraneControllerTerminal(crane, initMsg)\n\tif err != nil {\n\t\treturn err.Wrap(\"failed to start crane controller\")\n\t}\n\n\t// Start remaining workers.\n\tmodule.mgr.Go(\"crane loader\", crane.loader)\n\tmodule.mgr.Go(\"crane handler\", crane.handler)\n\n\treturn nil\n}\n\nfunc (crane *Crane) endInit() *terminal.Error {\n\tendMsg := container.New(\n\t\tvarint.Pack8(CraneMsgTypeEnd),\n\t)\n\tendMsg.PrependLength()\n\terr := crane.ship.Load(endMsg.CompileData())\n\tif err != nil {\n\t\treturn terminal.ErrShipSunk.With(\"failed to send end msg: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (crane *Crane) handleCraneInfo() *terminal.Error {\n\t// Pack info data.\n\tinfoData, err := dsd.Dump(info.GetInfo(), dsd.JSON)\n\tif err != nil {\n\t\treturn terminal.ErrInternalError.With(\"failed to pack info: %w\", err)\n\t}\n\tmsg := container.New(infoData)\n\n\t// Manually send reply.\n\tmsg.PrependLength()\n\terr = crane.ship.Load(msg.CompileData())\n\tif err != nil {\n\t\treturn terminal.ErrShipSunk.With(\"failed to send info reply: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (crane *Crane) handleCraneHubInfo() *terminal.Error {\n\tmsg := container.New()\n\n\t// Check if we have an identity.\n\tif crane.identity == nil {\n\t\treturn terminal.ErrIncorrectUsage.With(\"cannot handle hub info request without designated identity\")\n\t}\n\n\t// Add Hub Announcement.\n\tannouncementData, err := crane.identity.ExportAnnouncement()\n\tif err != nil {\n\t\treturn terminal.ErrInternalError.With(\"failed to export announcement: %w\", err)\n\t}\n\tmsg.AppendAsBlock(announcementData)\n\n\t// Add Hub Status.\n\tstatusData, err := crane.identity.ExportStatus()\n\tif err != nil {\n\t\treturn terminal.ErrInternalError.With(\"failed to export status: %w\", err)\n\t}\n\tmsg.AppendAsBlock(statusData)\n\n\t// Manually send reply.\n\tmsg.PrependLength()\n\terr = crane.ship.Load(msg.CompileData())\n\tif err != nil {\n\t\treturn terminal.ErrShipSunk.With(\"failed to send hub info reply: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/docks/crane_netstate.go",
    "content": "package docks\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// NetStatePeriodInterval defines the interval some of the net state should be reset.\nconst NetStatePeriodInterval = 15 * time.Minute\n\n// NetworkOptimizationState holds data for optimization purposes.\ntype NetworkOptimizationState struct {\n\tlock sync.Mutex\n\n\t// lastSuggestedAt holds the time when the connection to the connected Hub was last suggested by the network optimization.\n\tlastSuggestedAt time.Time\n\n\t// stoppingRequested signifies whether stopping this lane is requested.\n\tstoppingRequested bool\n\t// stoppingRequestedByPeer signifies whether stopping this lane is requested by the peer.\n\tstoppingRequestedByPeer bool\n\t// markedStoppingAt holds the time when the crane was last marked as stopping.\n\tmarkedStoppingAt time.Time\n\n\tlifetimeBytesIn  *uint64\n\tlifetimeBytesOut *uint64\n\tlifetimeStarted  time.Time\n\tperiodBytesIn    *uint64\n\tperiodBytesOut   *uint64\n\tperiodStarted    time.Time\n}\n\nfunc newNetworkOptimizationState() *NetworkOptimizationState {\n\treturn &NetworkOptimizationState{\n\t\tlifetimeBytesIn:  new(uint64),\n\t\tlifetimeBytesOut: new(uint64),\n\t\tlifetimeStarted:  time.Now(),\n\t\tperiodBytesIn:    new(uint64),\n\t\tperiodBytesOut:   new(uint64),\n\t\tperiodStarted:    time.Now(),\n\t}\n}\n\n// UpdateLastSuggestedAt sets when the lane was last suggested to the current time.\nfunc (netState *NetworkOptimizationState) UpdateLastSuggestedAt() {\n\tnetState.lock.Lock()\n\tdefer netState.lock.Unlock()\n\n\tnetState.lastSuggestedAt = time.Now()\n}\n\n// StoppingState returns when the stopping state.\nfunc (netState *NetworkOptimizationState) StoppingState() (requested, requestedByPeer bool, markedAt time.Time) {\n\tnetState.lock.Lock()\n\tdefer netState.lock.Unlock()\n\n\treturn netState.stoppingRequested, netState.stoppingRequestedByPeer, netState.markedStoppingAt\n}\n\n// RequestStoppingSuggested returns whether the crane should request stopping.\nfunc (netState *NetworkOptimizationState) RequestStoppingSuggested(maxNotSuggestedDuration time.Duration) bool {\n\tnetState.lock.Lock()\n\tdefer netState.lock.Unlock()\n\n\treturn time.Now().Add(-maxNotSuggestedDuration).After(netState.lastSuggestedAt)\n}\n\n// StoppingSuggested returns whether the crane should be marked as stopping.\nfunc (netState *NetworkOptimizationState) StoppingSuggested() bool {\n\tnetState.lock.Lock()\n\tdefer netState.lock.Unlock()\n\n\treturn netState.stoppingRequested &&\n\t\tnetState.stoppingRequestedByPeer\n}\n\n// StopSuggested returns whether the crane should be stopped.\nfunc (netState *NetworkOptimizationState) StopSuggested() bool {\n\tnetState.lock.Lock()\n\tdefer netState.lock.Unlock()\n\n\treturn netState.stoppingRequested &&\n\t\tnetState.stoppingRequestedByPeer &&\n\t\t!netState.markedStoppingAt.IsZero() &&\n\t\ttime.Now().Add(-maxCraneStoppingDuration).After(netState.markedStoppingAt)\n}\n\n// ReportTraffic adds the reported transferred data to the traffic stats.\nfunc (netState *NetworkOptimizationState) ReportTraffic(bytes uint64, in bool) {\n\tif in {\n\t\tatomic.AddUint64(netState.lifetimeBytesIn, bytes)\n\t\tatomic.AddUint64(netState.periodBytesIn, bytes)\n\t} else {\n\t\tatomic.AddUint64(netState.lifetimeBytesOut, bytes)\n\t\tatomic.AddUint64(netState.periodBytesOut, bytes)\n\t}\n}\n\n// LapsePeriod lapses the net state period, if needed.\nfunc (netState *NetworkOptimizationState) LapsePeriod() {\n\tnetState.lock.Lock()\n\tdefer netState.lock.Unlock()\n\n\t// Reset period if interval elapsed.\n\tif time.Now().Add(-NetStatePeriodInterval).After(netState.periodStarted) {\n\t\tatomic.StoreUint64(netState.periodBytesIn, 0)\n\t\tatomic.StoreUint64(netState.periodBytesOut, 0)\n\t\tnetState.periodStarted = time.Now()\n\t}\n}\n\n// GetTrafficStats returns the traffic stats.\nfunc (netState *NetworkOptimizationState) GetTrafficStats() (\n\tlifetimeBytesIn uint64,\n\tlifetimeBytesOut uint64,\n\tlifetimeStarted time.Time,\n\tperiodBytesIn uint64,\n\tperiodBytesOut uint64,\n\tperiodStarted time.Time,\n) {\n\tnetState.lock.Lock()\n\tdefer netState.lock.Unlock()\n\n\treturn atomic.LoadUint64(netState.lifetimeBytesIn),\n\t\tatomic.LoadUint64(netState.lifetimeBytesOut),\n\t\tnetState.lifetimeStarted,\n\t\tatomic.LoadUint64(netState.periodBytesIn),\n\t\tatomic.LoadUint64(netState.periodBytesOut),\n\t\tnetState.periodStarted\n}\n"
  },
  {
    "path": "spn/docks/crane_terminal.go",
    "content": "package docks\n\nimport (\n\t\"net\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n)\n\n// CraneTerminal is a terminal started by a crane.\ntype CraneTerminal struct {\n\t*terminal.TerminalBase\n\n\t// Add-Ons\n\tterminal.SessionAddOn\n\n\tcrane *Crane\n}\n\n// NewLocalCraneTerminal returns a new local crane terminal.\nfunc NewLocalCraneTerminal(\n\tcrane *Crane,\n\tremoteHub *hub.Hub,\n\tinitMsg *terminal.TerminalOpts,\n) (*CraneTerminal, *container.Container, *terminal.Error) {\n\t// Create Terminal Base.\n\tt, initData, err := terminal.NewLocalBaseTerminal(\n\t\tcrane.ctx,\n\t\tcrane.getNextTerminalID(),\n\t\tcrane.ID,\n\t\tremoteHub,\n\t\tinitMsg,\n\t\tcrane,\n\t)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn initCraneTerminal(crane, t), initData, nil\n}\n\n// NewRemoteCraneTerminal returns a new remote crane terminal.\nfunc NewRemoteCraneTerminal(\n\tcrane *Crane,\n\tid uint32,\n\tinitData *container.Container,\n) (*CraneTerminal, *terminal.TerminalOpts, *terminal.Error) {\n\t// Create Terminal Base.\n\tt, initMsg, err := terminal.NewRemoteBaseTerminal(\n\t\tcrane.ctx,\n\t\tid,\n\t\tcrane.ID,\n\t\tcrane.identity,\n\t\tinitData,\n\t\tcrane,\n\t)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn initCraneTerminal(crane, t), initMsg, nil\n}\n\nfunc initCraneTerminal(\n\tcrane *Crane,\n\tt *terminal.TerminalBase,\n) *CraneTerminal {\n\t// Create Crane Terminal and assign it as the extended Terminal.\n\tct := &CraneTerminal{\n\t\tTerminalBase: t,\n\t\tcrane:        crane,\n\t}\n\tt.SetTerminalExtension(ct)\n\n\t// Start workers.\n\tt.StartWorkers(module.mgr, \"crane terminal\")\n\n\treturn ct\n}\n\n// GrantPermission grants the given permissions.\n// Additionally, it will mark the crane as authenticated, if not public.\nfunc (t *CraneTerminal) GrantPermission(grant terminal.Permission) {\n\t// Forward granted permission to base terminal.\n\tt.TerminalBase.GrantPermission(grant)\n\n\t// Mark crane as authenticated if not public or already authenticated.\n\tif !t.crane.Public() && !t.crane.Authenticated() {\n\t\tt.crane.authenticated.Set()\n\n\t\t// Submit metrics.\n\t\tnewAuthenticatedCranes.Inc()\n\t}\n}\n\n// LocalAddr returns the crane's local address.\nfunc (t *CraneTerminal) LocalAddr() net.Addr {\n\treturn t.crane.LocalAddr()\n}\n\n// RemoteAddr returns the crane's remote address.\nfunc (t *CraneTerminal) RemoteAddr() net.Addr {\n\treturn t.crane.RemoteAddr()\n}\n\n// Transport returns the crane's transport.\nfunc (t *CraneTerminal) Transport() *hub.Transport {\n\treturn t.crane.Transport()\n}\n\n// IsBeingAbandoned returns whether the terminal is being abandoned.\nfunc (t *CraneTerminal) IsBeingAbandoned() bool {\n\treturn t.Abandoning.IsSet()\n}\n\n// HandleDestruction gives the terminal the ability to clean up.\n// The terminal has already fully shut down at this point.\n// Should never be called directly. Call Abandon() instead.\nfunc (t *CraneTerminal) HandleDestruction(err *terminal.Error) {\n\tt.crane.AbandonTerminal(t.ID(), err)\n}\n"
  },
  {
    "path": "spn/docks/crane_test.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/pprof\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nfunc TestCraneCommunication(t *testing.T) {\n\tt.Parallel()\n\n\ttestCraneWithCounter(t, \"plain-counter-load-100\", false, 100, 1000)\n\ttestCraneWithCounter(t, \"plain-counter-load-1000\", false, 1000, 1000)\n\ttestCraneWithCounter(t, \"plain-counter-load-10000\", false, 10000, 1000)\n\ttestCraneWithCounter(t, \"encrypted-counter\", true, 1000, 1000)\n}\n\nfunc testCraneWithCounter(t *testing.T, testID string, encrypting bool, loadSize int, countTo uint64) { //nolint:unparam,thelper\n\tvar identity *cabin.Identity\n\tvar connectedHub *hub.Hub\n\tif encrypting {\n\t\tidentity, connectedHub = getTestIdentity(t)\n\t}\n\n\t// Build ship and cranes.\n\toptimalMinLoadSize = loadSize * 2\n\tship := ships.NewTestShip(!encrypting, loadSize)\n\n\tvar crane1, crane2 *Crane\n\tvar craneWg sync.WaitGroup\n\tcraneWg.Add(2)\n\n\tgo func() {\n\t\tvar err error\n\t\tcrane1, err = NewCrane(ship, connectedHub, nil)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not create crane1: %s\", testID, err))\n\t\t}\n\t\terr = crane1.Start(module.mgr.Ctx())\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not start crane1: %s\", testID, err))\n\t\t}\n\t\tcraneWg.Done()\n\t}()\n\tgo func() {\n\t\tvar err error\n\t\tcrane2, err = NewCrane(ship.Reverse(), nil, identity)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not create crane2: %s\", testID, err))\n\t\t}\n\t\terr = crane2.Start(module.mgr.Ctx())\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not start crane2: %s\", testID, err))\n\t\t}\n\t\tcraneWg.Done()\n\t}()\n\n\tcraneWg.Wait()\n\tt.Logf(\"crane test %s setup complete\", testID)\n\n\t// Wait async for test to complete, print stack after timeout.\n\tfinished := make(chan struct{})\n\tgo func() {\n\t\tselect {\n\t\tcase <-finished:\n\t\tcase <-time.After(10 * time.Second):\n\t\t\tt.Logf(\"crane test %s is taking too long, print stack:\", testID)\n\t\t\t_ = pprof.Lookup(\"goroutine\").WriteTo(os.Stdout, 1)\n\t\t\tos.Exit(1)\n\t\t}\n\t}()\n\n\tt.Logf(\"crane1 controller: %+v\", crane1.Controller)\n\tt.Logf(\"crane2 controller: %+v\", crane2.Controller)\n\n\t// Start counters for testing.\n\top1, tErr := terminal.NewCounterOp(crane1.Controller, terminal.CounterOpts{\n\t\tClientCountTo: countTo,\n\t\tServerCountTo: countTo,\n\t})\n\tif tErr != nil {\n\t\tt.Fatalf(\"crane test %s failed to run counter op: %s\", testID, tErr)\n\t}\n\n\t// Wait for completion.\n\top1.Wait()\n\tclose(finished)\n\n\t// Wait a little so that all errors can be propagated, so we can truly see\n\t// if we succeeded.\n\ttime.Sleep(1 * time.Second)\n\n\t// Check errors.\n\tif op1.Error != nil {\n\t\tt.Fatalf(\"crane test %s counter op1 failed: %s\", testID, op1.Error)\n\t}\n}\n\ntype StreamingTerminal struct {\n\tterminal.BareTerminal\n\n\ttest     *testing.T\n\tid       uint32\n\tcrane    *Crane\n\trecv     chan *terminal.Msg\n\ttestData []byte\n}\n\nfunc (t *StreamingTerminal) ID() uint32 {\n\treturn t.id\n}\n\nfunc (t *StreamingTerminal) Ctx() context.Context {\n\treturn module.mgr.Ctx()\n}\n\nfunc (t *StreamingTerminal) Deliver(msg *terminal.Msg) *terminal.Error {\n\tt.recv <- msg\n\tmsg.Finish()\n\treturn nil\n}\n\nfunc (t *StreamingTerminal) Abandon(err *terminal.Error) {\n\tt.crane.AbandonTerminal(t.ID(), err)\n\tif err != nil {\n\t\tt.test.Errorf(\"streaming terminal %d failed: %s\", t.id, err)\n\t}\n}\n\nfunc (t *StreamingTerminal) FmtID() string {\n\treturn fmt.Sprintf(\"test-%d\", t.id)\n}\n\nfunc TestCraneLoadingUnloading(t *testing.T) {\n\tt.Parallel()\n\n\ttestCraneWithStreaming(t, \"plain-streaming\", false, 100)\n\ttestCraneWithStreaming(t, \"encrypted-streaming\", true, 100)\n}\n\nfunc testCraneWithStreaming(t *testing.T, testID string, encrypting bool, loadSize int) { //nolint:thelper\n\tvar identity *cabin.Identity\n\tvar connectedHub *hub.Hub\n\tif encrypting {\n\t\tidentity, connectedHub = getTestIdentity(t)\n\t}\n\n\t// Build ship and cranes.\n\toptimalMinLoadSize = loadSize * 2\n\tship := ships.NewTestShip(!encrypting, loadSize)\n\n\tvar crane1, crane2 *Crane\n\tvar craneWg sync.WaitGroup\n\tcraneWg.Add(2)\n\n\tgo func() {\n\t\tvar err error\n\t\tcrane1, err = NewCrane(ship, connectedHub, nil)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not create crane1: %s\", testID, err))\n\t\t}\n\t\terr = crane1.Start(module.mgr.Ctx())\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not start crane1: %s\", testID, err))\n\t\t}\n\t\tcraneWg.Done()\n\t}()\n\tgo func() {\n\t\tvar err error\n\t\tcrane2, err = NewCrane(ship.Reverse(), nil, identity)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not create crane2: %s\", testID, err))\n\t\t}\n\t\terr = crane2.Start(module.mgr.Ctx())\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"crane test %s could not start crane2: %s\", testID, err))\n\t\t}\n\t\tcraneWg.Done()\n\t}()\n\n\tcraneWg.Wait()\n\tt.Logf(\"crane test %s setup complete\", testID)\n\n\t// Wait async for test to complete, print stack after timeout.\n\tfinished := make(chan struct{})\n\tgo func() {\n\t\tselect {\n\t\tcase <-finished:\n\t\tcase <-time.After(10 * time.Second):\n\t\t\tt.Logf(\"crane test %s is taking too long, print stack:\", testID)\n\t\t\t_ = pprof.Lookup(\"goroutine\").WriteTo(os.Stdout, 1)\n\t\t\tos.Exit(1)\n\t\t}\n\t}()\n\n\tt.Logf(\"crane1 controller: %+v\", crane1.Controller)\n\tt.Logf(\"crane2 controller: %+v\", crane2.Controller)\n\n\t// Create terminals and run test.\n\tst := &StreamingTerminal{\n\t\ttest:     t,\n\t\tid:       8,\n\t\tcrane:    crane2,\n\t\trecv:     make(chan *terminal.Msg),\n\t\ttestData: []byte(\"The quick brown fox jumps over the lazy dog.\"),\n\t}\n\tcrane2.terminals[st.ID()] = st\n\n\t// Run streaming test.\n\tvar streamingWg sync.WaitGroup\n\tstreamingWg.Add(2)\n\tcount := 10000\n\tgo func() {\n\t\tfor i := 1; i <= count; i++ {\n\t\t\tmsg := terminal.NewMsg(st.testData)\n\t\t\tmsg.FlowID = st.id\n\t\t\terr := crane1.Send(msg, 1*time.Second)\n\t\t\tif err != nil {\n\t\t\t\tmsg.Finish()\n\t\t\t\tcrane1.Stop(err.Wrap(\"failed to submit terminal msg\"))\n\t\t\t}\n\t\t\t// log.Tracef(\"spn/testing: + %d\", i)\n\t\t}\n\t\tt.Logf(\"crane test %s done with sending\", testID)\n\t\tstreamingWg.Done()\n\t}()\n\tgo func() {\n\t\tfor i := 1; i <= count; i++ {\n\t\t\tmsg := <-st.recv\n\t\t\tassert.Equal(t, st.testData, msg.Data.CompileData(), \"data mismatched\")\n\t\t\t// log.Tracef(\"spn/testing: - %d\", i)\n\t\t}\n\t\tt.Logf(\"crane test %s done with receiving\", testID)\n\t\tstreamingWg.Done()\n\t}()\n\n\t// Wait for completion.\n\tstreamingWg.Wait()\n\tclose(finished)\n}\n\nvar testIdentity *cabin.Identity\n\nfunc getTestIdentity(t *testing.T) (*cabin.Identity, *hub.Hub) {\n\tt.Helper()\n\n\tif testIdentity == nil {\n\t\tvar err error\n\t\ttestIdentity, err = cabin.CreateIdentity(module.mgr.Ctx(), \"test\")\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to create identity: %s\", err)\n\t\t}\n\t}\n\n\treturn testIdentity, testIdentity.Hub\n}\n"
  },
  {
    "path": "spn/docks/crane_verify.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/varint\"\n)\n\nconst (\n\thubVerificationPurpose = \"hub identify verification\"\n)\n\n// VerifyConnectedHub verifies the connected Hub.\nfunc (crane *Crane) VerifyConnectedHub(callerCtx context.Context) error {\n\tif !crane.ship.IsMine() || crane.nextTerminalID != 0 || crane.Public() {\n\t\treturn errors.New(\"hub verification can only be executed in init phase by the client\")\n\t}\n\n\t// Create verification request.\n\tv, request, err := cabin.CreateVerificationRequest(hubVerificationPurpose, \"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create verification request: %w\", err)\n\t}\n\n\t// Send it.\n\tmsg := container.New(\n\t\tvarint.Pack8(CraneMsgTypeVerify),\n\t\trequest,\n\t)\n\tmsg.PrependLength()\n\terr = crane.ship.Load(msg.CompileData())\n\tif err != nil {\n\t\treturn terminal.ErrShipSunk.With(\"failed to send verification request: %w\", err)\n\t}\n\n\t// Wait for reply.\n\tvar reply *container.Container\n\tselect {\n\tcase reply = <-crane.unloading:\n\tcase <-time.After(2 * time.Minute):\n\t\t// Use a big timeout here, as this might keep servers from joining the\n\t\t// network at all, as every servers needs to verify every server, no\n\t\t// matter how far away.\n\t\treturn terminal.ErrTimeout.With(\"waiting for verification reply\")\n\tcase <-crane.ctx.Done():\n\t\treturn terminal.ErrShipSunk.With(\"waiting for verification reply\")\n\tcase <-callerCtx.Done():\n\t\treturn terminal.ErrShipSunk.With(\"waiting for verification reply\")\n\t}\n\n\t// Verify reply.\n\treturn v.Verify(reply.CompileData(), crane.ConnectedHub)\n}\n\nfunc (crane *Crane) handleCraneVerification(request *container.Container) *terminal.Error {\n\t// Check if we have an identity.\n\tif crane.identity == nil {\n\t\treturn terminal.ErrIncorrectUsage.With(\"cannot handle verification request without designated identity\")\n\t}\n\n\tresponse, err := crane.identity.SignVerificationRequest(\n\t\trequest.CompileData(),\n\t\thubVerificationPurpose,\n\t\t\"\", \"\",\n\t)\n\tif err != nil {\n\t\treturn terminal.ErrInternalError.With(\"failed to sign verification request: %w\", err)\n\t}\n\tmsg := container.New(response)\n\n\t// Manually send reply.\n\tmsg.PrependLength()\n\terr = crane.ship.Load(msg.CompileData())\n\tif err != nil {\n\t\treturn terminal.ErrShipSunk.With(\"failed to send verification reply: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/docks/cranehooks.go",
    "content": "package docks\n\nimport (\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\tcraneUpdateHook     func(crane *Crane)\n\tcraneUpdateHookLock sync.Mutex\n)\n\n// RegisterCraneUpdateHook allows the captain to hook into receiving updates for cranes.\nfunc RegisterCraneUpdateHook(fn func(crane *Crane)) {\n\tcraneUpdateHookLock.Lock()\n\tdefer craneUpdateHookLock.Unlock()\n\n\tif craneUpdateHook == nil {\n\t\tcraneUpdateHook = fn\n\t} else {\n\t\tlog.Error(\"spn/docks: crane update hook already registered\")\n\t}\n}\n\n// ResetCraneUpdateHook resets the hook for receiving updates for cranes.\nfunc ResetCraneUpdateHook() {\n\tcraneUpdateHookLock.Lock()\n\tdefer craneUpdateHookLock.Unlock()\n\n\tcraneUpdateHook = nil\n}\n\n// NotifyUpdate calls the registers crane update hook function.\nfunc (crane *Crane) NotifyUpdate() {\n\tif crane == nil {\n\t\treturn\n\t}\n\n\tcraneUpdateHookLock.Lock()\n\tdefer craneUpdateHookLock.Unlock()\n\n\tif craneUpdateHook != nil {\n\t\tcraneUpdateHook(crane)\n\t}\n}\n"
  },
  {
    "path": "spn/docks/hub_import.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nvar hubImportLock sync.Mutex\n\n// ImportAndVerifyHubInfo imports the given hub message and verifies them.\nfunc ImportAndVerifyHubInfo(ctx context.Context, hubID string, announcementData, statusData []byte, mapName string, scope hub.Scope) (h *hub.Hub, forward bool, tErr *terminal.Error) {\n\tvar firstErr *terminal.Error\n\n\t// Synchronize import, as we might easily learn of a new hub from different\n\t// gossip channels simultaneously.\n\thubImportLock.Lock()\n\tdefer hubImportLock.Unlock()\n\n\t// Check arguments.\n\tif announcementData == nil && statusData == nil {\n\t\treturn nil, false, terminal.ErrInternalError.With(\"no announcement or status supplied\")\n\t}\n\n\t// Import Announcement, if given.\n\tvar hubKnown, hubChanged bool\n\tif announcementData != nil {\n\t\thubFromMsg, known, changed, err := hub.ApplyAnnouncement(nil, announcementData, mapName, scope, false)\n\t\tif err != nil {\n\t\t\tfirstErr = terminal.ErrInternalError.With(\"failed to apply announcement: %w\", err)\n\t\t}\n\t\tif known {\n\t\t\thubKnown = true\n\t\t}\n\t\tif changed {\n\t\t\thubChanged = true\n\t\t}\n\t\tif hubFromMsg != nil {\n\t\t\th = hubFromMsg\n\t\t}\n\t}\n\n\t// Import Status, if given.\n\tif statusData != nil {\n\t\thubFromMsg, known, changed, err := hub.ApplyStatus(h, statusData, mapName, scope, false)\n\t\tif err != nil && firstErr == nil {\n\t\t\tfirstErr = terminal.ErrInternalError.With(\"failed to apply status: %w\", err)\n\t\t}\n\t\tif known && announcementData == nil {\n\t\t\t// If we parsed an announcement before, \"known\" will always be true here,\n\t\t\t// as we supply hub.ApplyStatus with a hub.\n\t\t\thubKnown = true\n\t\t}\n\t\tif changed {\n\t\t\thubChanged = true\n\t\t}\n\t\tif hubFromMsg != nil {\n\t\t\th = hubFromMsg\n\t\t}\n\t}\n\n\t// Only continue if we now have a Hub.\n\tif h == nil {\n\t\tif firstErr != nil {\n\t\t\treturn nil, false, firstErr\n\t\t}\n\t\treturn nil, false, terminal.ErrInternalError.With(\"got not hub after data import\")\n\t}\n\n\t// Abort if the given hub ID does not match.\n\t// We may have just connected to the wrong IP address.\n\tif hubID != \"\" && h.ID != hubID {\n\t\treturn nil, false, terminal.ErrInternalError.With(\"hub mismatch\")\n\t}\n\n\t// Verify hub if:\n\t// - There is no error up until here.\n\t// - There has been any change.\n\t// - The hub is not verified yet.\n\t// - We're a public Hub.\n\t// - We're not testing.\n\tif firstErr == nil && hubChanged && !h.Verified() && conf.PublicHub() && !runningTests {\n\t\tif !conf.HubHasIPv4() && !conf.HubHasIPv6() {\n\t\t\tfirstErr = terminal.ErrInternalError.With(\"no hub networks set\")\n\t\t}\n\t\tif h.Info.IPv4 != nil && conf.HubHasIPv4() {\n\t\t\terr := verifyHubIP(ctx, h, h.Info.IPv4)\n\t\t\tif err != nil {\n\t\t\t\tfirstErr = terminal.ErrIntegrity.With(\"failed to verify IPv4 address %s of %s: %w\", h.Info.IPv4, h, err)\n\t\t\t}\n\t\t}\n\t\tif h.Info.IPv6 != nil && conf.HubHasIPv6() {\n\t\t\terr := verifyHubIP(ctx, h, h.Info.IPv6)\n\t\t\tif err != nil {\n\t\t\t\tfirstErr = terminal.ErrIntegrity.With(\"failed to verify IPv6 address %s of %s: %w\", h.Info.IPv6, h, err)\n\t\t\t}\n\t\t}\n\n\t\tif firstErr != nil {\n\t\t\tfunc() {\n\t\t\t\th.Lock()\n\t\t\t\tdefer h.Unlock()\n\t\t\t\th.InvalidInfo = true\n\t\t\t}()\n\t\t\tlog.Warningf(\"spn/docks: failed to verify IPs of %s: %s\", h, firstErr)\n\t\t} else {\n\t\t\tfunc() {\n\t\t\t\th.Lock()\n\t\t\t\tdefer h.Unlock()\n\t\t\t\th.VerifiedIPs = true\n\t\t\t}()\n\t\t\tlog.Infof(\"spn/docks: verified IPs of %s: IPv4=%s IPv6=%s\", h, h.Info.IPv4, h.Info.IPv6)\n\t\t}\n\t}\n\n\t// Dismiss initial imports with errors.\n\tif !hubKnown && firstErr != nil {\n\t\treturn nil, false, firstErr\n\t}\n\n\t// Don't do anything if nothing changed.\n\tif !hubChanged {\n\t\treturn h, false, firstErr\n\t}\n\n\t// We now have one of:\n\t// - A unknown Hub without error.\n\t// - A known Hub without error.\n\t// - A known Hub with error, which we want to save and propagate.\n\n\t// Save the Hub to the database.\n\terr := h.Save()\n\tif err != nil {\n\t\tlog.Errorf(\"spn/docks: failed to persist %s: %s\", h, err)\n\t}\n\n\t// Save the raw messages to the database.\n\tif announcementData != nil {\n\t\terr = hub.SaveHubMsg(h.ID, h.Map, hub.MsgTypeAnnouncement, announcementData)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"spn/docks: failed to save raw announcement msg of %s: %s\", h, err)\n\t\t}\n\t}\n\tif statusData != nil {\n\t\terr = hub.SaveHubMsg(h.ID, h.Map, hub.MsgTypeStatus, statusData)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"spn/docks: failed to save raw status msg of %s: %s\", h, err)\n\t\t}\n\t}\n\n\treturn h, true, firstErr\n}\n\nfunc verifyHubIP(ctx context.Context, h *hub.Hub, ip net.IP) error {\n\t// Create connection.\n\tship, err := ships.Launch(ctx, h, nil, ip)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to launch ship to %s: %w\", ip, err)\n\t}\n\n\t// Start crane for receiving reply.\n\tcrane, err := NewCrane(ship, h, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create crane: %w\", err)\n\t}\n\tmodule.mgr.Go(\"crane unloader\", crane.unloader)\n\tdefer crane.Stop(nil)\n\n\t// Verify Hub.\n\terr = crane.VerifyConnectedHub(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// End connection.\n\ttErr := crane.endInit()\n\tif tErr != nil {\n\t\tlog.Debugf(\"spn/docks: failed to end verification connection to %s: %s\", ip, tErr)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/docks/measurements.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\n// Measurement Configuration.\nconst (\n\tCraneMeasurementTTLDefault    = 30 * time.Minute\n\tCraneMeasurementTTLByCostBase = 1 * time.Minute\n\tCraneMeasurementTTLByCostMin  = 30 * time.Minute\n\tCraneMeasurementTTLByCostMax  = 3 * time.Hour\n\n\t// With a base TTL of 1m, this leads to:\n\t// 20c     -> 20m -> raised to 30m\n\t// 50c     -> 50m\n\t// 100c    -> 1h40m\n\t// 1000c   -> 16h40m -> capped to 3h.\n)\n\n// MeasureHub measures the connection to this Hub and saves the results to the\n// Hub.\nfunc MeasureHub(ctx context.Context, h *hub.Hub, checkExpiryWith time.Duration) *terminal.Error {\n\t// Check if we are measuring before building a connection.\n\tif capacityTestRunning.IsSet() {\n\t\treturn terminal.ErrTryAgainLater.With(\"another capacity op is already running\")\n\t}\n\n\t// Check if we have a connection to this Hub.\n\tcrane := GetAssignedCrane(h.ID)\n\tif crane == nil {\n\t\t// Connect to Hub.\n\t\tvar err error\n\t\tcrane, err = establishCraneForMeasuring(ctx, h)\n\t\tif err != nil {\n\t\t\treturn terminal.ErrConnectionError.With(\"failed to connect to %s: %s\", h, err)\n\t\t}\n\t\t// Stop crane if established just for measuring.\n\t\tdefer crane.Stop(nil)\n\t}\n\n\t// Run latency test.\n\t_, expires := h.GetMeasurements().GetLatency()\n\tif checkExpiryWith == 0 || time.Now().Add(-checkExpiryWith).After(expires) {\n\t\tlatOp, tErr := NewLatencyTestOp(crane.Controller)\n\t\tif !tErr.IsOK() {\n\t\t\treturn tErr\n\t\t}\n\t\tselect {\n\t\tcase tErr = <-latOp.Result():\n\t\t\tif !tErr.IsOK() {\n\t\t\t\treturn tErr\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn terminal.ErrCanceled\n\t\tcase <-time.After(1 * time.Minute):\n\t\t\tcrane.Controller.StopOperation(latOp, terminal.ErrTimeout)\n\t\t\treturn terminal.ErrTimeout.With(\"waiting for latency test\")\n\t\t}\n\t}\n\n\t// Run capacity test.\n\t_, expires = h.GetMeasurements().GetCapacity()\n\tif checkExpiryWith == 0 || time.Now().Add(-checkExpiryWith).After(expires) {\n\t\tcapOp, tErr := NewCapacityTestOp(crane.Controller, nil)\n\t\tif !tErr.IsOK() {\n\t\t\treturn tErr\n\t\t}\n\t\tselect {\n\t\tcase tErr = <-capOp.Result():\n\t\t\tif !tErr.IsOK() {\n\t\t\t\treturn tErr\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn terminal.ErrCanceled\n\t\tcase <-time.After(1 * time.Minute):\n\t\t\tcrane.Controller.StopOperation(capOp, terminal.ErrTimeout)\n\t\t\treturn terminal.ErrTimeout.With(\"waiting for capacity test\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc establishCraneForMeasuring(ctx context.Context, dst *hub.Hub) (*Crane, error) {\n\tship, err := ships.Launch(ctx, dst, nil, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to launch ship: %w\", err)\n\t}\n\n\tcrane, err := NewCrane(ship, dst, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create crane: %w\", err)\n\t}\n\n\terr = crane.Start(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to start crane: %w\", err)\n\t}\n\n\treturn crane, nil\n}\n"
  },
  {
    "path": "spn/docks/metrics.go",
    "content": "package docks\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/metrics\"\n)\n\nvar (\n\tnewCranes              *metrics.Counter\n\tnewPublicCranes        *metrics.Counter\n\tnewAuthenticatedCranes *metrics.Counter\n\n\ttrafficBytesPublicCranes        *metrics.Counter\n\ttrafficBytesAuthenticatedCranes *metrics.Counter\n\ttrafficBytesPrivateCranes       *metrics.Counter\n\n\tnewExpandOp                  *metrics.Counter\n\texpandOpDurationHistogram    *metrics.Histogram\n\texpandOpRelayedDataHistogram *metrics.Histogram\n\n\tmetricsRegistered = abool.New()\n)\n\nfunc registerMetrics() (err error) {\n\t// Only register metrics once.\n\tif !metricsRegistered.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Total Crane Stats.\n\n\tnewCranes, err = metrics.NewCounter(\n\t\t\"spn/cranes/total\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN New Cranes\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewPublicCranes, err = metrics.NewCounter(\n\t\t\"spn/cranes/public/total\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN New Public Cranes\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewAuthenticatedCranes, err = metrics.NewCounter(\n\t\t\"spn/cranes/authenticated/total\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN New Authenticated Cranes\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Active Crane Stats.\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/cranes/active\",\n\t\tmap[string]string{\n\t\t\t\"status\": \"public\",\n\t\t},\n\t\tgetActivePublicCranes,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Active Public Cranes\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/cranes/active\",\n\t\tmap[string]string{\n\t\t\t\"status\": \"authenticated\",\n\t\t},\n\t\tgetActiveAuthenticatedCranes,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Active Authenticated Cranes\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/cranes/active\",\n\t\tmap[string]string{\n\t\t\t\"status\": \"private\",\n\t\t},\n\t\tgetActivePrivateCranes,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Active Private Cranes\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/cranes/active\",\n\t\tmap[string]string{\n\t\t\t\"status\": \"stopping\",\n\t\t},\n\t\tgetActiveStoppingCranes,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Active Stopping Cranes\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Crane Traffic Stats.\n\n\ttrafficBytesPublicCranes, err = metrics.NewCounter(\n\t\t\"spn/cranes/bytes\",\n\t\tmap[string]string{\n\t\t\t\"status\": \"public\",\n\t\t},\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Public Crane Traffic\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttrafficBytesAuthenticatedCranes, err = metrics.NewCounter(\n\t\t\"spn/cranes/bytes\",\n\t\tmap[string]string{\n\t\t\t\"status\": \"authenticated\",\n\t\t},\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Authenticated Crane Traffic\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttrafficBytesPrivateCranes, err = metrics.NewCounter(\n\t\t\"spn/cranes/bytes\",\n\t\tmap[string]string{\n\t\t\t\"status\": \"private\",\n\t\t},\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Private Crane Traffic\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Lane Stats.\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/lanes/latency/avg/seconds\",\n\t\tnil,\n\t\tgetAvgLaneLatencyStat,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Avg Lane Latency\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/lanes/latency/min/seconds\",\n\t\tnil,\n\t\tgetMinLaneLatencyStat,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Min Lane Latency\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/lanes/capacity/avg/bytes\",\n\t\tnil,\n\t\tgetAvgLaneCapacityStat,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Avg Lane Capacity\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/lanes/capacity/max/bytes\",\n\t\tnil,\n\t\tgetMaxLaneCapacityStat,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Max Lane Capacity\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Expand Op Stats.\n\n\tnewExpandOp, err = metrics.NewCounter(\n\t\t\"spn/op/expand/total\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Total Expand Operations\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/op/expand/active\",\n\t\tnil,\n\t\tgetActiveExpandOpsStat,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Active Expand Operations\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texpandOpDurationHistogram, err = metrics.NewHistogram(\n\t\t\"spn/op/expand/histogram/duration/seconds\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Expand Operation Duration Histogram\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texpandOpRelayedDataHistogram, err = metrics.NewHistogram(\n\t\t\"spn/op/expand/histogram/traffic/bytes\",\n\t\tnil,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Expand Operation Relayed Data Histogram\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn err\n}\n\nfunc getActiveExpandOpsStat() float64 {\n\treturn float64(atomic.LoadInt64(activeExpandOps))\n}\n\nvar (\n\tcraneStats        *craneGauges\n\tcraneStatsExpires time.Time\n\tcraneStatsLock    sync.Mutex\n\tcraneStatsTTL     = 55 * time.Second\n)\n\ntype craneGauges struct {\n\tpublicActive        float64\n\tauthenticatedActive float64\n\tprivateActive       float64\n\tstoppingActive      float64\n\n\tlaneLatencyAvg  float64\n\tlaneLatencyMin  float64\n\tlaneCapacityAvg float64\n\tlaneCapacityMax float64\n}\n\nfunc getActivePublicCranes() float64        { return getCraneStats().publicActive }\nfunc getActiveAuthenticatedCranes() float64 { return getCraneStats().authenticatedActive }\nfunc getActivePrivateCranes() float64       { return getCraneStats().privateActive }\nfunc getActiveStoppingCranes() float64      { return getCraneStats().stoppingActive }\nfunc getAvgLaneLatencyStat() float64        { return getCraneStats().laneLatencyAvg }\nfunc getMinLaneLatencyStat() float64        { return getCraneStats().laneLatencyMin }\nfunc getAvgLaneCapacityStat() float64       { return getCraneStats().laneCapacityAvg }\nfunc getMaxLaneCapacityStat() float64       { return getCraneStats().laneCapacityMax }\n\nfunc getCraneStats() *craneGauges {\n\tcraneStatsLock.Lock()\n\tdefer craneStatsLock.Unlock()\n\n\t// Return cache if still valid.\n\tif time.Now().Before(craneStatsExpires) {\n\t\treturn craneStats\n\t}\n\n\t// Refresh.\n\tcraneStats = &craneGauges{}\n\tvar laneStatCnt float64\n\tfor _, crane := range getAllCranes() {\n\t\tswitch {\n\t\tcase crane.Stopped():\n\t\t\tcontinue\n\t\tcase crane.IsStopping():\n\t\t\tcraneStats.stoppingActive++\n\t\t\tcontinue\n\t\tcase crane.Public():\n\t\t\tcraneStats.publicActive++\n\t\tcase crane.Authenticated():\n\t\t\tcraneStats.authenticatedActive++\n\t\t\tcontinue\n\t\tdefault:\n\t\t\tcraneStats.privateActive++\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get lane stats.\n\t\tif crane.ConnectedHub == nil {\n\t\t\tcontinue\n\t\t}\n\t\tmeasurements := crane.ConnectedHub.GetMeasurements()\n\t\tlaneLatency, _ := measurements.GetLatency()\n\t\tif laneLatency == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tlaneCapacity, _ := measurements.GetCapacity()\n\t\tif laneCapacity == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Only use data if both latency and capacity is available.\n\t\tlaneStatCnt++\n\n\t\t// Convert to base unit: seconds.\n\t\tlatency := laneLatency.Seconds()\n\t\t// Add to avg and set min if lower.\n\t\tcraneStats.laneLatencyAvg += latency\n\t\tif craneStats.laneLatencyMin > latency || craneStats.laneLatencyMin == 0 {\n\t\t\tcraneStats.laneLatencyMin = latency\n\t\t}\n\n\t\t// Convert in base unit: bytes.\n\t\tcapacity := float64(laneCapacity) / 8\n\t\t// Add to avg and set max if higher.\n\t\tcraneStats.laneCapacityAvg += capacity\n\t\tif craneStats.laneCapacityMax < capacity {\n\t\t\tcraneStats.laneCapacityMax = capacity\n\t\t}\n\t}\n\n\t// Create averages.\n\tif laneStatCnt > 0 {\n\t\tcraneStats.laneLatencyAvg /= laneStatCnt\n\t\tcraneStats.laneCapacityAvg /= laneStatCnt\n\t}\n\n\tcraneStatsExpires = time.Now().Add(craneStatsTTL)\n\treturn craneStats\n}\n\nfunc (crane *Crane) submitCraneTrafficStats(bytes int) {\n\tswitch {\n\tcase crane.Stopped():\n\t\treturn\n\tcase crane.Public():\n\t\ttrafficBytesPublicCranes.Add(bytes)\n\tcase crane.Authenticated():\n\t\ttrafficBytesAuthenticatedCranes.Add(bytes)\n\tdefault:\n\t\ttrafficBytesPrivateCranes.Add(bytes)\n\t}\n}\n"
  },
  {
    "path": "spn/docks/module.go",
    "content": "package docks\n\nimport (\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t_ \"github.com/safing/portmaster/spn/access\"\n)\n\n// Docks handles connections to other network participants.\ntype Docks struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\n// Manager returns the module manager.\nfunc (d *Docks) Manager() *mgr.Manager {\n\treturn d.mgr\n}\n\n// Start starts the module.\nfunc (d *Docks) Start() error {\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (d *Docks) Stop() error {\n\treturn stopAllCranes()\n}\n\nvar (\n\tallCranes      = make(map[string]*Crane) // ID = Crane ID\n\tassignedCranes = make(map[string]*Crane) // ID = connected Hub ID\n\tcranesLock     sync.RWMutex\n\n\trunningTests bool\n)\n\nfunc start() error {\n\treturn registerMetrics()\n}\n\nfunc registerCrane(crane *Crane) error {\n\tcranesLock.Lock()\n\tdefer cranesLock.Unlock()\n\n\t// Generate new IDs until a unique one is found.\n\tfor range 100 {\n\t\t// Generate random ID.\n\t\trandomID, err := rng.Bytes(3)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to generate crane ID: %w\", err)\n\t\t}\n\t\tnewID := hex.EncodeToString(randomID)\n\n\t\t// Check if ID already exists.\n\t\t_, ok := allCranes[newID]\n\t\tif !ok {\n\t\t\tcrane.ID = newID\n\t\t\tallCranes[crane.ID] = crane\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn errors.New(\"failed to find unique crane ID\")\n}\n\nfunc unregisterCrane(crane *Crane) {\n\tcranesLock.Lock()\n\tdefer cranesLock.Unlock()\n\n\tdelete(allCranes, crane.ID)\n\tif crane.ConnectedHub != nil {\n\t\tdelete(assignedCranes, crane.ConnectedHub.ID)\n\t}\n}\n\nfunc stopAllCranes() error {\n\tfor _, crane := range getAllCranes() {\n\t\tcrane.Stop(nil)\n\t}\n\treturn nil\n}\n\n// AssignCrane assigns a crane to the given Hub ID.\nfunc AssignCrane(hubID string, crane *Crane) {\n\tcranesLock.Lock()\n\tdefer cranesLock.Unlock()\n\n\tassignedCranes[hubID] = crane\n}\n\n// GetAssignedCrane returns the assigned crane of the given Hub ID.\nfunc GetAssignedCrane(hubID string) *Crane {\n\tcranesLock.RLock()\n\tdefer cranesLock.RUnlock()\n\n\tcrane, ok := assignedCranes[hubID]\n\tif ok {\n\t\treturn crane\n\t}\n\treturn nil\n}\n\nfunc getAllCranes() map[string]*Crane {\n\tcopiedCranes := make(map[string]*Crane, len(allCranes))\n\n\tcranesLock.RLock()\n\tdefer cranesLock.RUnlock()\n\n\tfor id, crane := range allCranes {\n\t\tcopiedCranes[id] = crane\n\t}\n\treturn copiedCranes\n}\n\n// GetAllAssignedCranes returns a copy of the map of all assigned cranes.\nfunc GetAllAssignedCranes() map[string]*Crane {\n\tcopiedCranes := make(map[string]*Crane, len(assignedCranes))\n\n\tcranesLock.RLock()\n\tdefer cranesLock.RUnlock()\n\n\tfor destination, crane := range assignedCranes {\n\t\tcopiedCranes[destination] = crane\n\t}\n\treturn copiedCranes\n}\n\nvar (\n\tmodule     *Docks\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Docks module.\nfunc New(instance instance) (*Docks, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Docks\")\n\tmodule = &Docks{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/docks/module_test.go",
    "content": "package docks\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\ntype testInstance struct {\n\tdb       *dbmodule.DBModule\n\tconfig   *config.Config\n\tmetrics  *metrics.Metrics\n\trng      *rng.Rng\n\tbase     *base.Base\n\taccess   *access.Access\n\tterminal *terminal.TerminalModule\n\tcabin    *cabin.Cabin\n}\n\nfunc (stub *testInstance) Config() *config.Config             { return stub.config }\nfunc (stub *testInstance) SPNGroup() *mgr.ExtendedGroup       { return nil }\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\nfunc (stub *testInstance) IsShuttingDown() bool               { return false }\nfunc (stub *testInstance) DataDir() string                    { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\t_ = log.Start(\"info\", true, \"\")\n\n\tvar err error\n\n\t// Create a temporary directory for the data\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to initialize dataroot: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\tinstance := &testInstance{}\n\trunningTests = true\n\tconf.EnablePublicHub(true) // Make hub config available.\n\taccess.EnableTestMode()    // Register test zone instead of real ones.\n\n\t// Init\n\tinstance.db, err = dbmodule.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database module: %w\", err)\n\t}\n\tinstance.config, err = config.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config module: %w\", err)\n\t}\n\tinstance.metrics, err = metrics.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create metrics module: %w\", err)\n\t}\n\tinstance.rng, err = rng.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create rng module: %w\", err)\n\t}\n\tinstance.base, err = base.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create base module: %w\", err)\n\t}\n\tinstance.access, err = access.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create access module: %w\", err)\n\t}\n\tinstance.terminal, err = terminal.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create terminal module: %w\", err)\n\t}\n\tinstance.cabin, err = cabin.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create cabin module: %w\", err)\n\t}\n\tmodule, err = New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create docks module: %w\", err)\n\t}\n\n\t// Start\n\terr = instance.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start db module: %w\", err)\n\t}\n\terr = instance.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start config module: %w\", err)\n\t}\n\terr = instance.metrics.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start metrics module: %w\", err)\n\t}\n\terr = instance.rng.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start rng module: %w\", err)\n\t}\n\terr = instance.base.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start base module: %w\", err)\n\t}\n\terr = instance.access.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start access module: %w\", err)\n\t}\n\terr = instance.terminal.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start terminal module: %w\", err)\n\t}\n\terr = instance.cabin.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start cabin module: %w\", err)\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start docks module: %w\", err)\n\t}\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "spn/docks/op_capacity.go",
    "content": "package docks\n\nimport (\n\t\"bytes\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nconst (\n\t// CapacityTestOpType is the type ID of the capacity test operation.\n\tCapacityTestOpType = \"capacity\"\n\n\tdefaultCapacityTestVolume = 50000000  // 50MB\n\tmaxCapacityTestVolume     = 100000000 // 100MB\n\n\tdefaultCapacityTestMaxTime = 5 * time.Second\n\tmaxCapacityTestMaxTime     = 15 * time.Second\n\tcapacityTestTimeout        = 30 * time.Second\n\n\tcapacityTestMsgSize     = 1000\n\tcapacityTestSendTimeout = 1000 * time.Millisecond\n)\n\nvar (\n\tcapacityTestSendData           = make([]byte, capacityTestMsgSize)\n\tcapacityTestDataReceivedSignal = []byte(\"ACK\")\n\n\tcapacityTestRunning = abool.New()\n)\n\n// CapacityTestOp is used for capacity test operations.\ntype CapacityTestOp struct { //nolint:maligned\n\tterminal.OperationBase\n\n\topts *CapacityTestOptions\n\n\tstarted       bool\n\tstartTime     time.Time\n\tsenderStarted bool\n\n\trecvQueue              chan *terminal.Msg\n\tdataReceived           int\n\tdataReceivedAckWasAckd bool\n\n\tdataSent        *int64\n\tdataSentWasAckd *abool.AtomicBool\n\n\ttestResult int\n\tresult     chan *terminal.Error\n}\n\n// CapacityTestOptions holds options for the capacity test.\ntype CapacityTestOptions struct {\n\tTestVolume int\n\tMaxTime    time.Duration\n\ttesting    bool\n}\n\n// Type returns the type ID.\nfunc (op *CapacityTestOp) Type() string {\n\treturn CapacityTestOpType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     CapacityTestOpType,\n\t\tRequires: terminal.IsCraneController,\n\t\tStart:    startCapacityTestOp,\n\t})\n}\n\n// NewCapacityTestOp runs a capacity test.\nfunc NewCapacityTestOp(t terminal.Terminal, opts *CapacityTestOptions) (*CapacityTestOp, *terminal.Error) {\n\t// Check options.\n\tif opts == nil {\n\t\topts = &CapacityTestOptions{\n\t\t\tTestVolume: defaultCapacityTestVolume,\n\t\t\tMaxTime:    defaultCapacityTestMaxTime,\n\t\t}\n\t}\n\n\t// Check if another test is already running.\n\tif !opts.testing && !capacityTestRunning.SetToIf(false, true) {\n\t\treturn nil, terminal.ErrTryAgainLater.With(\"another capacity op is already running\")\n\t}\n\n\t// Create and init.\n\top := &CapacityTestOp{\n\t\topts:            opts,\n\t\trecvQueue:       make(chan *terminal.Msg),\n\t\tdataSent:        new(int64),\n\t\tdataSentWasAckd: abool.New(),\n\t\tresult:          make(chan *terminal.Error, 1),\n\t}\n\n\t// Make capacity test request.\n\trequest, err := dsd.Dump(op.opts, dsd.CBOR)\n\tif err != nil {\n\t\tcapacityTestRunning.UnSet()\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to serialize capactity test options: %w\", err)\n\t}\n\n\t// Send test request.\n\ttErr := t.StartOperation(op, container.New(request), 1*time.Second)\n\tif tErr != nil {\n\t\tcapacityTestRunning.UnSet()\n\t\treturn nil, tErr\n\t}\n\n\t// Start handler.\n\tmodule.mgr.Go(\"op capacity handler\", op.handler)\n\n\treturn op, nil\n}\n\nfunc startCapacityTestOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Check if another test is already running.\n\tif !capacityTestRunning.SetToIf(false, true) {\n\t\treturn nil, terminal.ErrTryAgainLater.With(\"another capacity op is already running\")\n\t}\n\n\t// Parse options.\n\topts := &CapacityTestOptions{}\n\t_, err := dsd.Load(data.CompileData(), opts)\n\tif err != nil {\n\t\tcapacityTestRunning.UnSet()\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to parse options: %w\", err)\n\t}\n\n\t// Check options.\n\tif opts.TestVolume > maxCapacityTestVolume {\n\t\tcapacityTestRunning.UnSet()\n\t\treturn nil, terminal.ErrInvalidOptions.With(\"maximum volume exceeded\")\n\t}\n\tif opts.MaxTime > maxCapacityTestMaxTime {\n\t\tcapacityTestRunning.UnSet()\n\t\treturn nil, terminal.ErrInvalidOptions.With(\"maximum maxtime exceeded\")\n\t}\n\n\t// Create operation.\n\top := &CapacityTestOp{\n\t\topts:            opts,\n\t\trecvQueue:       make(chan *terminal.Msg, 1000),\n\t\tdataSent:        new(int64),\n\t\tdataSentWasAckd: abool.New(),\n\t\tresult:          make(chan *terminal.Error, 1),\n\t}\n\top.InitOperationBase(t, opID)\n\n\t// Start handler and sender.\n\top.senderStarted = true\n\tmodule.mgr.Go(\"op capacity handler\", op.handler)\n\tmodule.mgr.Go(\"op capacity sender\", op.sender)\n\n\treturn op, nil\n}\n\nfunc (op *CapacityTestOp) handler(ctx *mgr.WorkerCtx) error {\n\tdefer capacityTestRunning.UnSet()\n\n\treturnErr := terminal.ErrStopping\n\tdefer func() {\n\t\t// Linters don't get that returnErr is used when directly used as defer.\n\t\top.Stop(op, returnErr)\n\t}()\n\n\tvar maxTestTimeReached <-chan time.Time\n\topTimeout := time.After(capacityTestTimeout)\n\n\t// Setup unit handling\n\tvar msg *terminal.Msg\n\tdefer msg.Finish()\n\n\t// Handle receives.\n\tfor {\n\t\tmsg.Finish()\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturnErr = terminal.ErrCanceled\n\t\t\treturn nil\n\n\t\tcase <-opTimeout:\n\t\t\treturnErr = terminal.ErrTimeout\n\t\t\treturn nil\n\n\t\tcase <-maxTestTimeReached:\n\t\t\treturnErr = op.reportMeasuredCapacity()\n\t\t\treturn nil\n\n\t\tcase msg = <-op.recvQueue:\n\t\t\t// Record start time and start sender.\n\t\t\tif !op.started {\n\t\t\t\top.started = true\n\t\t\t\top.startTime = time.Now()\n\t\t\t\tmaxTestTimeReached = time.After(op.opts.MaxTime)\n\t\t\t\tif !op.senderStarted {\n\t\t\t\t\top.senderStarted = true\n\t\t\t\t\tmodule.mgr.Go(\"op capacity sender\", op.sender)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to received data counter.\n\t\t\top.dataReceived += msg.Data.Length()\n\n\t\t\t// Check if we received the data received signal.\n\t\t\tif msg.Data.Length() == len(capacityTestDataReceivedSignal) &&\n\t\t\t\tbytes.Equal(msg.Data.CompileData(), capacityTestDataReceivedSignal) {\n\t\t\t\top.dataSentWasAckd.Set()\n\t\t\t}\n\n\t\t\t// Send the data received signal when we received the full test volume.\n\t\t\tif op.dataReceived >= op.opts.TestVolume && !op.dataReceivedAckWasAckd {\n\t\t\t\ttErr := op.Send(op.NewMsg(capacityTestDataReceivedSignal), capacityTestSendTimeout)\n\t\t\t\tif tErr != nil {\n\t\t\t\t\treturnErr = tErr.Wrap(\"failed to send data received signal\")\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tatomic.AddInt64(op.dataSent, int64(len(capacityTestDataReceivedSignal)))\n\t\t\t\top.dataReceivedAckWasAckd = true\n\n\t\t\t\t// Flush last message.\n\t\t\t\top.Flush(10 * time.Second)\n\t\t\t}\n\n\t\t\t// Check if we can complete the test.\n\t\t\tif op.dataReceivedAckWasAckd &&\n\t\t\t\top.dataSentWasAckd.IsSet() {\n\t\t\t\treturnErr = op.reportMeasuredCapacity()\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (op *CapacityTestOp) sender(ctx *mgr.WorkerCtx) error {\n\tfor {\n\t\t// Send next chunk.\n\t\tmsg := op.NewMsg(capacityTestSendData)\n\t\tmsg.Unit.MakeHighPriority()\n\t\ttErr := op.Send(msg, capacityTestSendTimeout)\n\t\tif tErr != nil {\n\t\t\top.Stop(op, tErr.Wrap(\"failed to send capacity test data\"))\n\t\t\treturn nil\n\t\t}\n\n\t\t// Add to sent data counter and stop sending if sending is complete.\n\t\tif atomic.AddInt64(op.dataSent, int64(len(capacityTestSendData))) >= int64(op.opts.TestVolume) {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Check if we have received an ack.\n\t\tif op.dataSentWasAckd.IsSet() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Check if op has ended.\n\t\tif op.Stopped() {\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (op *CapacityTestOp) reportMeasuredCapacity() *terminal.Error {\n\t// Calculate lane capacity and set it.\n\ttimeNeeded := time.Since(op.startTime)\n\tif timeNeeded <= 0 {\n\t\ttimeNeeded = 1\n\t}\n\tduplexBits := float64((int64(op.dataReceived) + atomic.LoadInt64(op.dataSent)) * 8)\n\tduplexNSBitRate := duplexBits / float64(timeNeeded)\n\tbitRate := (duplexNSBitRate / 2) * float64(time.Second)\n\top.testResult = int(bitRate)\n\n\t// Save the result to the crane.\n\tif controller, ok := op.Terminal().(*CraneControllerTerminal); ok {\n\t\tif controller.Crane.ConnectedHub != nil {\n\t\t\tcontroller.Crane.ConnectedHub.GetMeasurements().SetCapacity(op.testResult)\n\t\t\tlog.Infof(\n\t\t\t\t\"docks: measured capacity to %s: %.2f Mbit/s (%.2fMB down / %.2fMB up in %s)\",\n\t\t\t\tcontroller.Crane.ConnectedHub,\n\t\t\t\tfloat64(op.testResult)/1000000,\n\t\t\t\tfloat64(op.dataReceived)/1000000,\n\t\t\t\tfloat64(atomic.LoadInt64(op.dataSent))/1000000,\n\t\t\t\ttimeNeeded,\n\t\t\t)\n\t\t\treturn nil\n\t\t} else if controller.Crane.IsMine() {\n\t\t\treturn terminal.ErrInternalError.With(\"capacity operation was run on %s without a connected hub set\", controller.Crane)\n\t\t}\n\t} else if !runningTests {\n\t\treturn terminal.ErrInternalError.With(\"capacity operation was run on terminal that is not a crane controller, but %T\", op.Terminal())\n\t}\n\n\treturn nil\n}\n\n// Deliver delivers a message.\nfunc (op *CapacityTestOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\t// Optimized delivery with 1s timeout.\n\tselect {\n\tcase op.recvQueue <- msg:\n\tdefault:\n\t\tselect {\n\t\tcase op.recvQueue <- msg:\n\t\tcase <-time.After(1 * time.Second):\n\t\t\tmsg.Finish()\n\t\t\treturn terminal.ErrTimeout\n\t\t}\n\t}\n\treturn nil\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *CapacityTestOp) HandleStop(tErr *terminal.Error) (errorToSend *terminal.Error) {\n\t// Return result to waiting routine.\n\tselect {\n\tcase op.result <- tErr:\n\tdefault:\n\t}\n\n\t// Drain the recvQueue to finish the message units.\ndrain:\n\tfor {\n\t\tselect {\n\t\tcase msg := <-op.recvQueue:\n\t\t\tmsg.Finish()\n\t\tdefault:\n\t\t\tselect {\n\t\t\tcase msg := <-op.recvQueue:\n\t\t\t\tmsg.Finish()\n\t\t\tcase <-time.After(3 * time.Millisecond):\n\t\t\t\t// Give some additional time buffer to drain the queue.\n\t\t\t\tbreak drain\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return error as is.\n\treturn tErr\n}\n\n// Result returns the result (end error) of the operation.\nfunc (op *CapacityTestOp) Result() <-chan *terminal.Error {\n\treturn op.result\n}\n"
  },
  {
    "path": "spn/docks/op_capacity_test.go",
    "content": "package docks\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nvar (\n\ttestCapacityTestVolume  = 1_000_000\n\ttestCapacitytestMaxTime = 1 * time.Second\n)\n\nfunc TestCapacityOp(t *testing.T) { //nolint:paralleltest // Performance test.\n\t// Defaults.\n\ttestCapacityOp(t, &CapacityTestOptions{\n\t\tTestVolume: testCapacityTestVolume,\n\t\tMaxTime:    testCapacitytestMaxTime,\n\t\ttesting:    true,\n\t})\n\n\t// Hit max time first.\n\ttestCapacityOp(t, &CapacityTestOptions{\n\t\tTestVolume: testCapacityTestVolume,\n\t\tMaxTime:    100 * time.Millisecond,\n\t\ttesting:    true,\n\t})\n\n\t// Hit volume first.\n\ttestCapacityOp(t, &CapacityTestOptions{\n\t\tTestVolume: 100_000,\n\t\tMaxTime:    testCapacitytestMaxTime,\n\t\ttesting:    true,\n\t})\n}\n\nfunc testCapacityOp(t *testing.T, opts *CapacityTestOptions) {\n\tt.Helper()\n\n\tvar (\n\t\tcapTestDelay            = 5 * time.Millisecond\n\t\tcapTestQueueSize uint32 = 10\n\t)\n\n\t// Create test terminal pair.\n\ta, b, err := terminal.NewSimpleTestTerminalPair(\n\t\tcapTestDelay,\n\t\tint(capTestQueueSize),\n\t\t&terminal.TerminalOpts{\n\t\t\tFlowControl:     terminal.FlowControlDFQ,\n\t\t\tFlowControlSize: capTestQueueSize,\n\t\t},\n\t)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create test terminal pair: %s\", err)\n\t}\n\n\t// Grant permission for op on remote terminal and start op.\n\tb.GrantPermission(terminal.IsCraneController)\n\top, tErr := NewCapacityTestOp(a, opts)\n\tif tErr != nil {\n\t\tt.Fatalf(\"failed to start op: %s\", tErr)\n\t}\n\n\t// Wait for result and check error.\n\ttErr = <-op.Result()\n\tif !tErr.IsOK() {\n\t\tt.Fatalf(\"op failed: %s\", tErr)\n\t}\n\tt.Logf(\"measured capacity: %d bit/s\", op.testResult)\n\n\t// Calculate expected bandwidth.\n\texpectedBitsPerSecond := float64(capacityTestMsgSize*8*int64(capTestQueueSize)) / float64(capTestDelay) * float64(time.Second)\n\tt.Logf(\"expected capacity: %f bit/s\", expectedBitsPerSecond)\n\n\t// Check if measured bandwidth is within parameters.\n\tif float64(op.testResult) > expectedBitsPerSecond*1.6 {\n\t\tt.Fatal(\"measured capacity too high\")\n\t}\n\t// TODO: Check if we can raise this to at least 90%.\n\tif float64(op.testResult) < expectedBitsPerSecond*0.2 {\n\t\tt.Fatal(\"measured capacity too low\")\n\t}\n}\n"
  },
  {
    "path": "spn/docks/op_expand.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n)\n\n// ExpandOpType is the type ID of the expand operation.\nconst ExpandOpType string = \"expand\"\n\nvar activeExpandOps = new(int64)\n\n// ExpandOp is used to expand to another Hub.\ntype ExpandOp struct {\n\tterminal.OperationBase\n\topts *terminal.TerminalOpts\n\n\t// ctx is the context of the Terminal.\n\tctx context.Context\n\t// cancelCtx cancels ctx.\n\tcancelCtx context.CancelFunc\n\n\tdataRelayed *uint64\n\tended       *abool.AtomicBool\n\n\trelayTerminal *ExpansionRelayTerminal\n\n\t// flowControl holds the flow control system.\n\tflowControl terminal.FlowControl\n\t// deliverProxy is populated with the configured deliver function\n\tdeliverProxy func(msg *terminal.Msg) *terminal.Error\n\t// recvProxy is populated with the configured recv function\n\trecvProxy func() <-chan *terminal.Msg\n\t// sendProxy is populated with the configured send function\n\tsendProxy func(msg *terminal.Msg, timeout time.Duration)\n}\n\n// ExpansionRelayTerminal is a relay used for expansion.\ntype ExpansionRelayTerminal struct {\n\tterminal.BareTerminal\n\n\top *ExpandOp\n\n\tid    uint32\n\tcrane *Crane\n\n\tabandoning *abool.AtomicBool\n\n\t// flowControl holds the flow control system.\n\tflowControl terminal.FlowControl\n\t// deliverProxy is populated with the configured deliver function\n\tdeliverProxy func(msg *terminal.Msg) *terminal.Error\n\t// recvProxy is populated with the configured recv function\n\trecvProxy func() <-chan *terminal.Msg\n\t// sendProxy is populated with the configured send function\n\tsendProxy func(msg *terminal.Msg, timeout time.Duration)\n}\n\n// Type returns the type ID.\nfunc (op *ExpandOp) Type() string {\n\treturn ExpandOpType\n}\n\n// ID returns the operation ID.\nfunc (t *ExpansionRelayTerminal) ID() uint32 {\n\treturn t.id\n}\n\n// Ctx returns the operation context.\nfunc (op *ExpandOp) Ctx() context.Context {\n\treturn op.ctx\n}\n\n// Ctx returns the relay terminal context.\nfunc (t *ExpansionRelayTerminal) Ctx() context.Context {\n\treturn t.op.ctx\n}\n\n// Deliver delivers a message to the relay operation.\nfunc (op *ExpandOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\treturn op.deliverProxy(msg)\n}\n\n// Deliver delivers a message to the relay terminal.\nfunc (t *ExpansionRelayTerminal) Deliver(msg *terminal.Msg) *terminal.Error {\n\treturn t.deliverProxy(msg)\n}\n\n// Flush writes all data in the queues.\nfunc (op *ExpandOp) Flush(timeout time.Duration) {\n\tif op.flowControl != nil {\n\t\top.flowControl.Flush(timeout)\n\t}\n}\n\n// Flush writes all data in the queues.\nfunc (t *ExpansionRelayTerminal) Flush(timeout time.Duration) {\n\tif t.flowControl != nil {\n\t\tt.flowControl.Flush(timeout)\n\t}\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     ExpandOpType,\n\t\tRequires: terminal.MayExpand,\n\t\tStart:    expand,\n\t})\n}\n\nfunc expand(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Submit metrics.\n\tnewExpandOp.Inc()\n\n\t// Check if we are running a public hub.\n\tif !conf.PublicHub() {\n\t\treturn nil, terminal.ErrPermissionDenied.With(\"expanding is only allowed on public hubs\")\n\t}\n\n\t// Parse destination hub ID.\n\tdstData, err := data.GetNextBlock()\n\tif err != nil {\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to parse destination: %w\", err)\n\t}\n\n\t// Parse terminal options.\n\topts, tErr := terminal.ParseTerminalOpts(data)\n\tif tErr != nil {\n\t\treturn nil, tErr.Wrap(\"failed to parse terminal options\")\n\t}\n\n\t// Get crane with destination.\n\trelayCrane := GetAssignedCrane(string(dstData))\n\tif relayCrane == nil {\n\t\treturn nil, terminal.ErrHubUnavailable.With(\"no crane assigned to %q\", string(dstData))\n\t}\n\n\t// TODO: Expand outside of hot path.\n\n\t// Create operation and terminal.\n\top := &ExpandOp{\n\t\topts:        opts,\n\t\tdataRelayed: new(uint64),\n\t\tended:       abool.New(),\n\t\trelayTerminal: &ExpansionRelayTerminal{\n\t\t\tcrane:      relayCrane,\n\t\t\tid:         relayCrane.getNextTerminalID(),\n\t\t\tabandoning: abool.New(),\n\t\t},\n\t}\n\top.InitOperationBase(t, opID)\n\top.ctx, op.cancelCtx = context.WithCancel(t.Ctx())\n\top.relayTerminal.op = op\n\n\t// Create flow control.\n\tswitch opts.FlowControl {\n\tcase terminal.FlowControlDFQ:\n\t\t// Operation\n\t\top.flowControl = terminal.NewDuplexFlowQueue(op.ctx, opts.FlowControlSize, op.submitBackwardUpstream)\n\t\top.deliverProxy = op.flowControl.Deliver\n\t\top.recvProxy = op.flowControl.Receive\n\t\top.sendProxy = op.submitBackwardFlowControl\n\t\t// Relay Terminal\n\t\top.relayTerminal.flowControl = terminal.NewDuplexFlowQueue(op.ctx, opts.FlowControlSize, op.submitForwardUpstream)\n\t\top.relayTerminal.deliverProxy = op.relayTerminal.flowControl.Deliver\n\t\top.relayTerminal.recvProxy = op.relayTerminal.flowControl.Receive\n\t\top.relayTerminal.sendProxy = op.submitForwardFlowControl\n\tcase terminal.FlowControlNone:\n\t\t// Operation\n\t\tdeliverToOp := make(chan *terminal.Msg, opts.FlowControlSize)\n\t\top.deliverProxy = terminal.MakeDirectDeliveryDeliverFunc(op.ctx, deliverToOp)\n\t\top.recvProxy = terminal.MakeDirectDeliveryRecvFunc(deliverToOp)\n\t\top.sendProxy = op.submitBackwardUpstream\n\t\t// Relay Terminal\n\t\tdeliverToRelay := make(chan *terminal.Msg, opts.FlowControlSize)\n\t\top.relayTerminal.deliverProxy = terminal.MakeDirectDeliveryDeliverFunc(op.ctx, deliverToRelay)\n\t\top.relayTerminal.recvProxy = terminal.MakeDirectDeliveryRecvFunc(deliverToRelay)\n\t\top.relayTerminal.sendProxy = op.submitForwardUpstream\n\tcase terminal.FlowControlDefault:\n\t\tfallthrough\n\tdefault:\n\t\treturn nil, terminal.ErrInternalError.With(\"unknown flow control type %d\", opts.FlowControl)\n\t}\n\n\t// Establish terminal on destination.\n\tnewInitData, tErr := opts.Pack()\n\tif tErr != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to re-pack options: %w\", err)\n\t}\n\ttErr = op.relayTerminal.crane.EstablishNewTerminal(op.relayTerminal, newInitData)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\t// Start workers.\n\tmodule.mgr.Go(\"expand op forward relay\", op.forwardHandler)\n\tmodule.mgr.Go(\"expand op backward relay\", op.backwardHandler)\n\tif op.flowControl != nil {\n\t\top.flowControl.StartWorkers(module.mgr, \"expand op\")\n\t}\n\tif op.relayTerminal.flowControl != nil {\n\t\top.relayTerminal.flowControl.StartWorkers(module.mgr, \"expand op terminal\")\n\t}\n\n\treturn op, nil\n}\n\nfunc (op *ExpandOp) submitForwardFlowControl(msg *terminal.Msg, timeout time.Duration) {\n\terr := op.relayTerminal.flowControl.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t\top.Stop(op, err.Wrap(\"failed to submit to forward flow control\"))\n\t}\n}\n\nfunc (op *ExpandOp) submitBackwardFlowControl(msg *terminal.Msg, timeout time.Duration) {\n\terr := op.flowControl.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t\top.Stop(op, err.Wrap(\"failed to submit to backward flow control\"))\n\t}\n}\n\nfunc (op *ExpandOp) submitForwardUpstream(msg *terminal.Msg, timeout time.Duration) {\n\tmsg.FlowID = op.relayTerminal.id\n\tif msg.Unit.IsHighPriority() && op.opts.UsePriorityDataMsgs {\n\t\tmsg.Type = terminal.MsgTypePriorityData\n\t} else {\n\t\tmsg.Type = terminal.MsgTypeData\n\t}\n\terr := op.relayTerminal.crane.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t\top.Stop(op, err.Wrap(\"failed to submit to forward upstream\"))\n\t}\n}\n\nfunc (op *ExpandOp) submitBackwardUpstream(msg *terminal.Msg, timeout time.Duration) {\n\tmsg.FlowID = op.relayTerminal.id\n\tif msg.Unit.IsHighPriority() && op.opts.UsePriorityDataMsgs {\n\t\tmsg.Type = terminal.MsgTypePriorityData\n\t} else {\n\t\tmsg.Type = terminal.MsgTypeData\n\t\tmsg.Unit.RemovePriority()\n\t}\n\t// Note: op.Send() will transform high priority units to priority data msgs.\n\terr := op.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t\top.Stop(op, err.Wrap(\"failed to submit to backward upstream\"))\n\t}\n}\n\nfunc (op *ExpandOp) forwardHandler(_ *mgr.WorkerCtx) error {\n\t// Metrics setup and submitting.\n\tatomic.AddInt64(activeExpandOps, 1)\n\tstarted := time.Now()\n\tdefer func() {\n\t\tatomic.AddInt64(activeExpandOps, -1)\n\t\texpandOpDurationHistogram.UpdateDuration(started)\n\t\texpandOpRelayedDataHistogram.Update(float64(atomic.LoadUint64(op.dataRelayed)))\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase msg := <-op.recvProxy():\n\t\t\t// Debugging:\n\t\t\t// log.Debugf(\"spn/testing: forwarding at %s: %s\", op.FmtID(), spew.Sdump(c.CompileData()))\n\n\t\t\t// Wait for processing slot.\n\t\t\tmsg.Unit.WaitForSlot()\n\n\t\t\t// Count relayed data for metrics.\n\t\t\tatomic.AddUint64(op.dataRelayed, uint64(msg.Data.Length()))\n\n\t\t\t// Receive data from the origin and forward it to the relay.\n\t\t\top.relayTerminal.sendProxy(msg, 1*time.Minute)\n\n\t\tcase <-op.ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (op *ExpandOp) backwardHandler(_ *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase msg := <-op.relayTerminal.recvProxy():\n\t\t\t// Debugging:\n\t\t\t// log.Debugf(\"spn/testing: backwarding at %s: %s\", op.FmtID(), spew.Sdump(c.CompileData()))\n\n\t\t\t// Wait for processing slot.\n\t\t\tmsg.Unit.WaitForSlot()\n\n\t\t\t// Count relayed data for metrics.\n\t\t\tatomic.AddUint64(op.dataRelayed, uint64(msg.Data.Length()))\n\n\t\t\t// Receive data from the relay and forward it to the origin.\n\t\t\top.sendProxy(msg, 1*time.Minute)\n\n\t\tcase <-op.ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *ExpandOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {\n\t// Flush all messages before stopping.\n\top.Flush(1 * time.Minute)\n\top.relayTerminal.Flush(1 * time.Minute)\n\n\t// Stop connected workers.\n\top.cancelCtx()\n\n\t// Abandon connected terminal.\n\top.relayTerminal.Abandon(nil)\n\n\t// Add context to error.\n\tif err.IsError() {\n\t\treturn err.Wrap(\"relay operation failed with\")\n\t}\n\treturn err\n}\n\n// Abandon shuts down the terminal unregistering it from upstream and calling HandleAbandon().\nfunc (t *ExpansionRelayTerminal) Abandon(err *terminal.Error) {\n\tif t.abandoning.SetToIf(false, true) {\n\t\tmodule.mgr.Go(\"terminal abandon procedure\", func(_ *mgr.WorkerCtx) error {\n\t\t\tt.handleAbandonProcedure(err)\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\n// HandleAbandon gives the terminal the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Abandon() instead.\nfunc (t *ExpansionRelayTerminal) HandleAbandon(err *terminal.Error) (errorToSend *terminal.Error) {\n\t// Stop the connected relay operation.\n\tt.op.Stop(t.op, err)\n\n\t// Add context to error.\n\tif err.IsError() {\n\t\treturn err.Wrap(\"relay terminal failed with\")\n\t}\n\treturn err\n}\n\n// HandleDestruction gives the terminal the ability to clean up.\n// The terminal has already fully shut down at this point.\n// Should never be called directly. Call Abandon() instead.\nfunc (t *ExpansionRelayTerminal) HandleDestruction(err *terminal.Error) {}\n\nfunc (t *ExpansionRelayTerminal) handleAbandonProcedure(err *terminal.Error) {\n\t// Call operation stop handle function for proper shutdown cleaning up.\n\terr = t.HandleAbandon(err)\n\n\t// Flush all messages before stopping.\n\tt.Flush(1 * time.Minute)\n\n\t// Send error to the connected Operation, if the error is internal.\n\tif !err.IsExternal() {\n\t\tif err == nil {\n\t\t\terr = terminal.ErrStopping\n\t\t}\n\n\t\tmsg := terminal.NewMsg(err.Pack())\n\t\tmsg.FlowID = t.ID()\n\t\tmsg.Type = terminal.MsgTypeStop\n\t\tt.op.submitForwardUpstream(msg, 1*time.Second)\n\t}\n}\n\n// FmtID returns the expansion ID hierarchy.\nfunc (op *ExpandOp) FmtID() string {\n\treturn fmt.Sprintf(\"%s>%d <r> %s#%d\", op.Terminal().FmtID(), op.ID(), op.relayTerminal.crane.ID, op.relayTerminal.id)\n}\n\n// FmtID returns the expansion ID hierarchy.\nfunc (t *ExpansionRelayTerminal) FmtID() string {\n\treturn fmt.Sprintf(\"%s#%d\", t.crane.ID, t.id)\n}\n"
  },
  {
    "path": "spn/docks/op_latency.go",
    "content": "package docks\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/varint\"\n)\n\nconst (\n\t// LatencyTestOpType is the type ID of the latency test operation.\n\tLatencyTestOpType = \"latency\"\n\n\tlatencyPingRequest  = 1\n\tlatencyPingResponse = 2\n\n\tlatencyTestNonceSize = 16\n\tlatencyTestRuns      = 10\n)\n\nvar (\n\tlatencyTestPauseDuration = 1 * time.Second\n\tlatencyTestOpTimeout     = latencyTestRuns * latencyTestPauseDuration * 3\n)\n\n// LatencyTestOp is used to measure latency.\ntype LatencyTestOp struct {\n\tterminal.OperationBase\n}\n\n// LatencyTestClientOp is the client version of LatencyTestOp.\ntype LatencyTestClientOp struct {\n\tLatencyTestOp\n\n\tlastPingSentAt    time.Time\n\tlastPingNonce     []byte\n\tmeasuredLatencies []time.Duration\n\tresponses         chan *terminal.Msg\n\ttestResult        time.Duration\n\n\tresult chan *terminal.Error\n}\n\n// Type returns the type ID.\nfunc (op *LatencyTestOp) Type() string {\n\treturn LatencyTestOpType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     LatencyTestOpType,\n\t\tRequires: terminal.IsCraneController,\n\t\tStart:    startLatencyTestOp,\n\t})\n}\n\n// NewLatencyTestOp runs a latency test.\nfunc NewLatencyTestOp(t terminal.Terminal) (*LatencyTestClientOp, *terminal.Error) {\n\t// Create and init.\n\top := &LatencyTestClientOp{\n\t\tresponses:         make(chan *terminal.Msg),\n\t\tmeasuredLatencies: make([]time.Duration, 0, latencyTestRuns),\n\t\tresult:            make(chan *terminal.Error, 1),\n\t}\n\n\t// Make ping request.\n\tpingRequest, err := op.createPingRequest()\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"%w\", err)\n\t}\n\n\t// Send ping.\n\ttErr := t.StartOperation(op, pingRequest, 1*time.Second)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\t// Start handler.\n\tmodule.mgr.Go(\"op latency handler\", op.handler)\n\n\treturn op, nil\n}\n\nfunc (op *LatencyTestClientOp) handler(ctx *mgr.WorkerCtx) error {\n\treturnErr := terminal.ErrStopping\n\tdefer func() {\n\t\t// Linters don't get that returnErr is used when directly used as defer.\n\t\top.Stop(op, returnErr)\n\t}()\n\n\tvar nextTest <-chan time.Time\n\topTimeout := time.After(latencyTestOpTimeout)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\n\t\tcase <-opTimeout:\n\t\t\treturn nil\n\n\t\tcase <-nextTest:\n\t\t\t// Create ping request msg.\n\t\t\tpingRequest, err := op.createPingRequest()\n\t\t\tif err != nil {\n\t\t\t\treturnErr = terminal.ErrInternalError.With(\"%w\", err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tmsg := op.NewEmptyMsg()\n\t\t\tmsg.Unit.MakeHighPriority()\n\t\t\tmsg.Data = pingRequest\n\n\t\t\t// Send it.\n\t\t\ttErr := op.Send(msg, latencyTestOpTimeout)\n\t\t\tif tErr != nil {\n\t\t\t\treturnErr = tErr.Wrap(\"failed to send ping request\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\top.Flush(1 * time.Second)\n\n\t\t\tnextTest = nil\n\n\t\tcase msg := <-op.responses:\n\t\t\t// Check if the op ended.\n\t\t\tif msg == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Handle response\n\t\t\ttErr := op.handleResponse(msg)\n\t\t\tif tErr != nil {\n\t\t\t\treturnErr = tErr\n\t\t\t\treturn nil //nolint:nilerr\n\t\t\t}\n\n\t\t\t// Check if we have enough latency tests.\n\t\t\tif len(op.measuredLatencies) >= latencyTestRuns {\n\t\t\t\treturnErr = op.reportMeasuredLatencies()\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Schedule next latency test, if not yet scheduled.\n\t\t\tif nextTest == nil {\n\t\t\t\tnextTest = time.After(latencyTestPauseDuration)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (op *LatencyTestClientOp) createPingRequest() (*container.Container, error) {\n\t// Generate nonce.\n\tnonce, err := rng.Bytes(latencyTestNonceSize)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create ping nonce\")\n\t}\n\n\t// Set client request state.\n\top.lastPingSentAt = time.Now()\n\top.lastPingNonce = nonce\n\n\treturn container.New(\n\t\tvarint.Pack8(latencyPingRequest),\n\t\tnonce,\n\t), nil\n}\n\nfunc (op *LatencyTestClientOp) handleResponse(msg *terminal.Msg) *terminal.Error {\n\tdefer msg.Finish()\n\n\trType, err := msg.Data.GetNextN8()\n\tif err != nil {\n\t\treturn terminal.ErrMalformedData.With(\"failed to get response type: %w\", err)\n\t}\n\n\tswitch rType {\n\tcase latencyPingResponse:\n\t\t// Check if the ping nonce matches.\n\t\tif !bytes.Equal(op.lastPingNonce, msg.Data.CompileData()) {\n\t\t\treturn terminal.ErrIntegrity.With(\"ping nonce mismatch\")\n\t\t}\n\t\top.lastPingNonce = nil\n\t\t// Save latency.\n\t\top.measuredLatencies = append(op.measuredLatencies, time.Since(op.lastPingSentAt))\n\n\t\treturn nil\n\tdefault:\n\t\treturn terminal.ErrIncorrectUsage.With(\"unknown response type\")\n\t}\n}\n\nfunc (op *LatencyTestClientOp) reportMeasuredLatencies() *terminal.Error {\n\t// Find lowest value.\n\tlowestLatency := time.Hour\n\tfor _, latency := range op.measuredLatencies {\n\t\tif latency < lowestLatency {\n\t\t\tlowestLatency = latency\n\t\t}\n\t}\n\top.testResult = lowestLatency\n\n\t// Save the result to the crane.\n\tif controller, ok := op.Terminal().(*CraneControllerTerminal); ok {\n\t\tif controller.Crane.ConnectedHub != nil {\n\t\t\tcontroller.Crane.ConnectedHub.GetMeasurements().SetLatency(op.testResult)\n\t\t\tlog.Infof(\"spn/docks: measured latency to %s: %s\", controller.Crane.ConnectedHub, op.testResult)\n\t\t\treturn nil\n\t\t} else if controller.Crane.IsMine() {\n\t\t\treturn terminal.ErrInternalError.With(\"latency operation was run on %s without a connected hub set\", controller.Crane)\n\t\t}\n\t} else if !runningTests {\n\t\treturn terminal.ErrInternalError.With(\"latency operation was run on terminal that is not a crane controller, but %T\", op.Terminal())\n\t}\n\treturn nil\n}\n\n// Deliver delivers a message to the operation.\nfunc (op *LatencyTestClientOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\t// Optimized delivery with 1s timeout.\n\tselect {\n\tcase op.responses <- msg:\n\tdefault:\n\t\tselect {\n\t\tcase op.responses <- msg:\n\t\tcase <-time.After(1 * time.Second):\n\t\t\treturn terminal.ErrTimeout\n\t\t}\n\t}\n\treturn nil\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *LatencyTestClientOp) HandleStop(tErr *terminal.Error) (errorToSend *terminal.Error) {\n\tclose(op.responses)\n\tselect {\n\tcase op.result <- tErr:\n\tdefault:\n\t}\n\treturn tErr\n}\n\n// Result returns the result (end error) of the operation.\nfunc (op *LatencyTestClientOp) Result() <-chan *terminal.Error {\n\treturn op.result\n}\n\nfunc startLatencyTestOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Create operation.\n\top := &LatencyTestOp{}\n\top.InitOperationBase(t, opID)\n\n\t// Handle first request.\n\tmsg := op.NewEmptyMsg()\n\tmsg.Data = data\n\ttErr := op.Deliver(msg)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\treturn op, nil\n}\n\n// Deliver delivers a message to the operation.\nfunc (op *LatencyTestOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\t// Get request type.\n\trType, err := msg.Data.GetNextN8()\n\tif err != nil {\n\t\treturn terminal.ErrMalformedData.With(\"failed to get response type: %w\", err)\n\t}\n\n\tswitch rType {\n\tcase latencyPingRequest:\n\t\t// Keep the nonce and just replace the msg type.\n\t\tmsg.Data.PrependNumber(latencyPingResponse)\n\t\tmsg.Type = terminal.MsgTypeData\n\t\tmsg.Unit.ReUse()\n\t\tmsg.Unit.MakeHighPriority()\n\n\t\t// Send response.\n\t\ttErr := op.Send(msg, latencyTestOpTimeout)\n\t\tif tErr != nil {\n\t\t\treturn tErr.Wrap(\"failed to send ping response\")\n\t\t}\n\t\top.Flush(1 * time.Second)\n\n\t\treturn nil\n\n\tdefault:\n\t\treturn terminal.ErrIncorrectUsage.With(\"unknown request type\")\n\t}\n}\n"
  },
  {
    "path": "spn/docks/op_latency_test.go",
    "content": "package docks\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nfunc TestLatencyOp(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\tlatTestDelay            = 10 * time.Millisecond\n\t\tlatTestQueueSize uint32 = 10\n\t)\n\n\t// Reduce waiting time.\n\tlatencyTestPauseDuration = 100 * time.Millisecond\n\n\t// Create test terminal pair.\n\ta, b, err := terminal.NewSimpleTestTerminalPair(\n\t\tlatTestDelay,\n\t\tint(latTestQueueSize),\n\t\t&terminal.TerminalOpts{\n\t\t\tFlowControl:     terminal.FlowControlNone,\n\t\t\tFlowControlSize: latTestQueueSize,\n\t\t},\n\t)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create test terminal pair: %s\", err)\n\t}\n\n\t// Grant permission for op on remote terminal and start op.\n\tb.GrantPermission(terminal.IsCraneController)\n\top, tErr := NewLatencyTestOp(a)\n\tif tErr != nil {\n\t\tt.Fatalf(\"failed to start op: %s\", tErr)\n\t}\n\n\t// Wait for result and check error.\n\ttErr = <-op.Result()\n\tif tErr.IsError() {\n\t\tt.Fatalf(\"op failed: %s\", tErr)\n\t}\n\tt.Logf(\"measured latency: %f ms\", float64(op.testResult)/float64(time.Millisecond))\n\n\t// Calculate expected latency.\n\texpectedLatency := float64(latTestDelay * 2)\n\tt.Logf(\"expected latency: %f ms\", expectedLatency/float64(time.Millisecond))\n\n\t// Check if measured latency is within parameters.\n\tif float64(op.testResult) > expectedLatency*1.2 {\n\t\tt.Fatal(\"measured latency too high\")\n\t}\n\tif float64(op.testResult) < expectedLatency*0.9 {\n\t\tt.Fatal(\"measured latency too low\")\n\t}\n}\n"
  },
  {
    "path": "spn/docks/op_sync_state.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\n// SyncStateOpType is the type ID of the sync state operation.\nconst SyncStateOpType = \"sync/state\"\n\n// SyncStateOp is used to sync the crane state.\ntype SyncStateOp struct {\n\tterminal.OneOffOperationBase\n}\n\n// SyncStateMessage holds the sync data.\ntype SyncStateMessage struct {\n\tStopping        bool\n\tRequestStopping bool\n}\n\n// Type returns the type ID.\nfunc (op *SyncStateOp) Type() string {\n\treturn SyncStateOpType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:     SyncStateOpType,\n\t\tRequires: terminal.IsCraneController,\n\t\tStart:    runSyncStateOp,\n\t})\n}\n\n// startSyncStateOp starts a worker that runs the sync state operation.\nfunc (crane *Crane) startSyncStateOp() {\n\tmodule.mgr.Go(\"sync crane state\", func(wc *mgr.WorkerCtx) error {\n\t\ttErr := crane.Controller.SyncState(wc.Ctx())\n\t\tif tErr != nil {\n\t\t\treturn tErr\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// SyncState runs a sync state operation.\nfunc (controller *CraneControllerTerminal) SyncState(ctx context.Context) *terminal.Error {\n\t// Check if we are a public Hub, whether we own the crane and whether the lane is public too.\n\tif !conf.PublicHub() || !controller.Crane.Public() {\n\t\treturn nil\n\t}\n\n\t// Create and init.\n\top := &SyncStateOp{}\n\top.Init()\n\n\t// Get optimization states.\n\trequestStopping := false\n\tfunc() {\n\t\tcontroller.Crane.NetState.lock.Lock()\n\t\tdefer controller.Crane.NetState.lock.Unlock()\n\n\t\trequestStopping = controller.Crane.NetState.stoppingRequested\n\t}()\n\n\t// Create sync message.\n\tmsg := &SyncStateMessage{\n\t\tStopping:        controller.Crane.stopping.IsSet(),\n\t\tRequestStopping: requestStopping,\n\t}\n\tdata, err := dsd.Dump(msg, dsd.CBOR)\n\tif err != nil {\n\t\treturn terminal.ErrInternalError.With(\"%w\", err)\n\t}\n\n\t// Send message.\n\ttErr := controller.StartOperation(op, container.New(data), 30*time.Second)\n\tif tErr != nil {\n\t\treturn tErr\n\t}\n\n\t// Wait for reply\n\tselect {\n\tcase tErr = <-op.Result:\n\t\tif tErr.IsError() {\n\t\t\treturn tErr\n\t\t}\n\t\treturn nil\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-time.After(1 * time.Minute):\n\t\treturn terminal.ErrTimeout.With(\"timed out while waiting for sync crane result\")\n\t}\n}\n\nfunc runSyncStateOp(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Check if we are a on a crane controller.\n\tvar ok bool\n\tvar controller *CraneControllerTerminal\n\tif controller, ok = t.(*CraneControllerTerminal); !ok {\n\t\treturn nil, terminal.ErrIncorrectUsage.With(\"can only be used with a crane controller\")\n\t}\n\n\t// Check if we are a public Hub and whether the lane is public too.\n\tif !conf.PublicHub() || !controller.Crane.Public() {\n\t\treturn nil, terminal.ErrPermissionDenied.With(\"only public lanes can sync crane status\")\n\t}\n\n\t// Load message.\n\tsyncState := &SyncStateMessage{}\n\t_, err := dsd.Load(data.CompileData(), syncState)\n\tif err != nil {\n\t\treturn nil, terminal.ErrMalformedData.With(\"failed to load sync state message: %w\", err)\n\t}\n\n\t// Apply optimization state.\n\tcontroller.Crane.NetState.lock.Lock()\n\tdefer controller.Crane.NetState.lock.Unlock()\n\tcontroller.Crane.NetState.stoppingRequestedByPeer = syncState.RequestStopping\n\n\t// Apply crane state only when we don't own the crane.\n\tif !controller.Crane.IsMine() {\n\t\t// Apply sync state.\n\t\tvar changed bool\n\t\tif syncState.Stopping {\n\t\t\tif controller.Crane.stopping.SetToIf(false, true) {\n\t\t\t\tcontroller.Crane.NetState.markedStoppingAt = time.Now()\n\t\t\t\tchanged = true\n\t\t\t}\n\t\t} else {\n\t\t\tif controller.Crane.stopping.SetToIf(true, false) {\n\t\t\t\tcontroller.Crane.NetState.markedStoppingAt = time.Time{}\n\t\t\t\tchanged = true\n\t\t\t}\n\t\t}\n\n\t\t// Notify of change.\n\t\tif changed {\n\t\t\tcontroller.Crane.NotifyUpdate()\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "spn/docks/op_whoami.go",
    "content": "package docks\n\nimport (\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nconst (\n\t// WhoAmIType is the type ID of the latency test operation.\n\tWhoAmIType = \"whoami\"\n\n\twhoAmITimeout = 3 * time.Second\n)\n\n// WhoAmIOp is used to request some metadata about the other side.\ntype WhoAmIOp struct {\n\tterminal.OneOffOperationBase\n\n\tresponse *WhoAmIResponse\n}\n\n// WhoAmIResponse is a whoami response.\ntype WhoAmIResponse struct {\n\t// Timestamp in nanoseconds\n\tTimestamp int64 `cbor:\"t,omitempty\" json:\"t,omitempty\"`\n\n\t// Addr is the remote address as reported by the crane terminal (IP and port).\n\tAddr string `cbor:\"a,omitempty\" json:\"a,omitempty\"`\n}\n\n// Type returns the type ID.\nfunc (op *WhoAmIOp) Type() string {\n\treturn WhoAmIType\n}\n\nfunc init() {\n\tterminal.RegisterOpType(terminal.OperationFactory{\n\t\tType:  WhoAmIType,\n\t\tStart: startWhoAmI,\n\t})\n}\n\n// WhoAmI executes a whoami operation and returns the response.\nfunc WhoAmI(t terminal.Terminal) (*WhoAmIResponse, *terminal.Error) {\n\twhoami, err := NewWhoAmIOp(t)\n\tif err.IsError() {\n\t\treturn nil, err\n\t}\n\n\t// Wait for response.\n\tselect {\n\tcase tErr := <-whoami.Result:\n\t\tif tErr.IsError() {\n\t\t\treturn nil, tErr\n\t\t}\n\t\treturn whoami.response, nil\n\tcase <-time.After(whoAmITimeout * 2):\n\t\treturn nil, terminal.ErrTimeout\n\t}\n}\n\n// NewWhoAmIOp starts a new whoami operation.\nfunc NewWhoAmIOp(t terminal.Terminal) (*WhoAmIOp, *terminal.Error) {\n\t// Create operation and init.\n\top := &WhoAmIOp{}\n\top.OneOffOperationBase.Init()\n\n\t// Send ping.\n\ttErr := t.StartOperation(op, nil, whoAmITimeout)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\treturn op, nil\n}\n\n// Deliver delivers a message to the operation.\nfunc (op *WhoAmIOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\tdefer msg.Finish()\n\n\t// Parse response.\n\tresponse := &WhoAmIResponse{}\n\t_, err := dsd.Load(msg.Data.CompileData(), response)\n\tif err != nil {\n\t\treturn terminal.ErrMalformedData.With(\"failed to parse ping response: %w\", err)\n\t}\n\n\top.response = response\n\treturn terminal.ErrExplicitAck\n}\n\nfunc startWhoAmI(t terminal.Terminal, opID uint32, data *container.Container) (terminal.Operation, *terminal.Error) {\n\t// Get crane terminal, if available.\n\tct, _ := t.(*CraneTerminal)\n\n\t// Create response.\n\tr := &WhoAmIResponse{\n\t\tTimestamp: time.Now().UnixNano(),\n\t}\n\tif ct != nil {\n\t\tr.Addr = ct.RemoteAddr().String()\n\t}\n\tresponse, err := dsd.Dump(r, dsd.CBOR)\n\tif err != nil {\n\t\treturn nil, terminal.ErrInternalError.With(\"failed to create whoami response: %w\", err)\n\t}\n\n\t// Send response.\n\tmsg := terminal.NewMsg(response)\n\tmsg.FlowID = opID\n\tmsg.Unit.MakeHighPriority()\n\tif terminal.UsePriorityDataMsgs {\n\t\tmsg.Type = terminal.MsgTypePriorityData\n\t}\n\ttErr := t.Send(msg, whoAmITimeout)\n\tif tErr != nil {\n\t\t// Finish message unit on failure.\n\t\tmsg.Finish()\n\t\treturn nil, tErr.With(\"failed to send ping response\")\n\t}\n\n\t// Operation is just one response and finished successfully.\n\treturn nil, nil\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *WhoAmIOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {\n\t// Continue with usual handling of inherited base.\n\treturn op.OneOffOperationBase.HandleStop(err)\n}\n"
  },
  {
    "path": "spn/docks/op_whoami_test.go",
    "content": "package docks\n\nimport (\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nfunc TestWhoAmIOp(t *testing.T) {\n\tt.Parallel()\n\n\t// Create test terminal pair.\n\ta, _, err := terminal.NewSimpleTestTerminalPair(0, 0, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create test terminal pair: %s\", err)\n\t}\n\n\t// Run op.\n\tresp, tErr := WhoAmI(a)\n\tif tErr.IsError() {\n\t\tt.Fatal(tErr)\n\t}\n\tt.Logf(\"whoami: %+v\", resp)\n}\n"
  },
  {
    "path": "spn/docks/terminal_expansion.go",
    "content": "package docks\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n\t\"github.com/safing/structures/container\"\n)\n\n// ExpansionTerminal is used for expanding to another Hub.\ntype ExpansionTerminal struct {\n\t*terminal.TerminalBase\n\n\trelayOp *ExpansionTerminalRelayOp\n\n\tchangeNotifyFuncReady *abool.AtomicBool\n\tchangeNotifyFunc      func()\n\n\treachableChecked time.Time\n\treachableLock    sync.Mutex\n}\n\n// ExpansionTerminalRelayOp is the operation that connects to the relay.\ntype ExpansionTerminalRelayOp struct {\n\tterminal.OperationBase\n\n\texpansionTerminal *ExpansionTerminal\n}\n\n// Type returns the type ID.\nfunc (op *ExpansionTerminalRelayOp) Type() string {\n\treturn ExpandOpType\n}\n\n// ExpandTo initiates an expansion.\nfunc ExpandTo(from terminal.Terminal, routeTo string, encryptFor *hub.Hub) (*ExpansionTerminal, *terminal.Error) {\n\t// First, create the local endpoint terminal to generate the init data.\n\n\t// Create options and bare expansion terminal.\n\topts := terminal.DefaultExpansionTerminalOpts()\n\topts.Encrypt = encryptFor != nil\n\texpansion := &ExpansionTerminal{\n\t\tchangeNotifyFuncReady: abool.New(),\n\t}\n\texpansion.relayOp = &ExpansionTerminalRelayOp{\n\t\texpansionTerminal: expansion,\n\t}\n\n\t// Create base terminal for expansion.\n\tbase, initData, tErr := terminal.NewLocalBaseTerminal(\n\t\tmodule.mgr.Ctx(),\n\t\t0, // Ignore; The ID of the operation is used for communication.\n\t\tfrom.FmtID(),\n\t\tencryptFor,\n\t\topts,\n\t\texpansion.relayOp,\n\t)\n\tif tErr != nil {\n\t\treturn nil, tErr.Wrap(\"failed to create expansion terminal base\")\n\t}\n\texpansion.TerminalBase = base\n\tbase.SetTerminalExtension(expansion)\n\tbase.SetTimeout(defaultTerminalIdleTimeout)\n\n\t// Second, start the actual relay operation.\n\n\t// Create setup message for relay operation.\n\topInitData := container.New()\n\topInitData.AppendAsBlock([]byte(routeTo))\n\topInitData.AppendContainer(initData)\n\n\t// Start relay operation on connected Hub.\n\ttErr = from.StartOperation(expansion.relayOp, opInitData, 5*time.Second)\n\tif tErr != nil {\n\t\treturn nil, tErr.Wrap(\"failed to start expansion operation\")\n\t}\n\n\t// Start Workers.\n\tbase.StartWorkers(module.mgr, \"expansion terminal\")\n\n\treturn expansion, nil\n}\n\n// SetChangeNotifyFunc sets a callback function that is called when the terminal state changes.\nfunc (t *ExpansionTerminal) SetChangeNotifyFunc(f func()) {\n\tif t.changeNotifyFuncReady.IsSet() {\n\t\treturn\n\t}\n\tt.changeNotifyFunc = f\n\tt.changeNotifyFuncReady.Set()\n}\n\n// NeedsReachableCheck returns whether the terminal should be checked if it is\n// reachable via the existing network internal relayed connection.\nfunc (t *ExpansionTerminal) NeedsReachableCheck(maxCheckAge time.Duration) bool {\n\tt.reachableLock.Lock()\n\tdefer t.reachableLock.Unlock()\n\n\treturn time.Since(t.reachableChecked) > maxCheckAge\n}\n\n// MarkReachable marks the terminal as reachable via the existing network\n// internal relayed connection.\nfunc (t *ExpansionTerminal) MarkReachable() {\n\tt.reachableLock.Lock()\n\tdefer t.reachableLock.Unlock()\n\n\tt.reachableChecked = time.Now()\n}\n\n// HandleDestruction gives the terminal the ability to clean up.\n// The terminal has already fully shut down at this point.\n// Should never be called directly. Call Abandon() instead.\nfunc (t *ExpansionTerminal) HandleDestruction(err *terminal.Error) {\n\t// Trigger update of connected Pin.\n\tif t.changeNotifyFuncReady.IsSet() {\n\t\tt.changeNotifyFunc()\n\t}\n\n\t// Stop the relay operation.\n\t// The error message is arlready sent by the terminal.\n\tt.relayOp.Stop(t.relayOp, nil)\n}\n\n// CustomIDFormat formats the terminal ID.\nfunc (t *ExpansionTerminal) CustomIDFormat() string {\n\treturn fmt.Sprintf(\"%s~%d\", t.relayOp.Terminal().FmtID(), t.relayOp.ID())\n}\n\n// Deliver delivers a message to the operation.\nfunc (op *ExpansionTerminalRelayOp) Deliver(msg *terminal.Msg) *terminal.Error {\n\t// Proxy directly to expansion terminal.\n\treturn op.expansionTerminal.Deliver(msg)\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *ExpansionTerminalRelayOp) HandleStop(err *terminal.Error) (errorToSend *terminal.Error) {\n\t// Stop the expansion terminal.\n\t// The error message will be sent by the operation.\n\top.expansionTerminal.Abandon(nil)\n\n\treturn err\n}\n"
  },
  {
    "path": "spn/docks/terminal_expansion_test.go",
    "content": "package docks\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/pprof\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\nconst defaultTestQueueSize = 200\n\nfunc TestExpansion(t *testing.T) {\n\tt.Parallel()\n\n\t// Test without and with encryption.\n\tfor _, encrypt := range []bool{false, true} {\n\t\t// Test down/up separately and in parallel.\n\t\tfor _, parallel := range []bool{false, true} {\n\t\t\t// Test with different flow controls.\n\t\t\tfor _, fc := range []struct {\n\t\t\t\tflowControl     terminal.FlowControlType\n\t\t\t\tflowControlSize uint32\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tflowControl:     terminal.FlowControlNone,\n\t\t\t\t\tflowControlSize: 5,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tflowControl:     terminal.FlowControlDFQ,\n\t\t\t\t\tflowControlSize: defaultTestQueueSize,\n\t\t\t\t},\n\t\t\t} {\n\t\t\t\t// Run tests with combined options.\n\t\t\t\ttestExpansion(\n\t\t\t\t\tt,\n\t\t\t\t\t\"expansion-hop-test\",\n\t\t\t\t\t&terminal.TerminalOpts{\n\t\t\t\t\t\tEncrypt:         encrypt,\n\t\t\t\t\t\tPadding:         8,\n\t\t\t\t\t\tFlowControl:     fc.flowControl,\n\t\t\t\t\t\tFlowControlSize: fc.flowControlSize,\n\t\t\t\t\t},\n\t\t\t\t\tdefaultTestQueueSize,\n\t\t\t\t\tdefaultTestQueueSize,\n\t\t\t\t\tparallel,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\tstressTestOpts := &terminal.TerminalOpts{\n\t\tEncrypt:         true,\n\t\tPadding:         8,\n\t\tFlowControl:     terminal.FlowControlDFQ,\n\t\tFlowControlSize: defaultTestQueueSize,\n\t}\n\ttestExpansion(t, \"expansion-stress-test-down\", stressTestOpts, defaultTestQueueSize*100, 0, false)\n\ttestExpansion(t, \"expansion-stress-test-up\", stressTestOpts, 0, defaultTestQueueSize*100, false)\n\ttestExpansion(t, \"expansion-stress-test-duplex\", stressTestOpts, defaultTestQueueSize*100, defaultTestQueueSize*100, false)\n}\n\nfunc testExpansion( //nolint:maintidx,thelper\n\tt *testing.T,\n\ttestID string,\n\tterminalOpts *terminal.TerminalOpts,\n\tclientCountTo,\n\tserverCountTo uint64,\n\tinParallel bool,\n) {\n\ttestID += fmt.Sprintf(\":encrypt=%v,flowCtrl=%d,parallel=%v\", terminalOpts.Encrypt, terminalOpts.FlowControl, inParallel)\n\n\tvar identity2, identity3, identity4 *cabin.Identity\n\tvar connectedHub2, connectedHub3, connectedHub4 *hub.Hub\n\tif terminalOpts.Encrypt {\n\t\tidentity2, connectedHub2 = getTestIdentity(t)\n\t\tidentity3, connectedHub3 = getTestIdentity(t)\n\t\tidentity4, connectedHub4 = getTestIdentity(t)\n\t}\n\n\t// Build ships and cranes.\n\toptimalMinLoadSize = 100\n\tship1to2 := ships.NewTestShip(!terminalOpts.Encrypt, 100)\n\tship2to3 := ships.NewTestShip(!terminalOpts.Encrypt, 100)\n\tship3to4 := ships.NewTestShip(!terminalOpts.Encrypt, 100)\n\n\tvar crane1, crane2to1, crane2to3, crane3to2, crane3to4, crane4 *Crane\n\tvar craneWg sync.WaitGroup\n\tcraneWg.Add(6)\n\n\tcraneCtx, cancelCraneCtx := context.WithCancel(context.Background())\n\tdefer cancelCraneCtx()\n\n\tgo func() {\n\t\tvar err error\n\t\tcrane1, err = NewCrane(ship1to2, connectedHub2, nil)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not create crane1: %s\", testID, err))\n\t\t}\n\t\tcrane1.ID = \"c1\"\n\t\terr = crane1.Start(craneCtx)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not start crane1: %s\", testID, err))\n\t\t}\n\t\tcrane1.ship.MarkPublic()\n\t\tcraneWg.Done()\n\t}()\n\tgo func() {\n\t\tvar err error\n\t\tcrane2to1, err = NewCrane(ship1to2.Reverse(), nil, identity2)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not create crane2to1: %s\", testID, err))\n\t\t}\n\t\tcrane2to1.ID = \"c2to1\"\n\t\terr = crane2to1.Start(craneCtx)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not start crane2to1: %s\", testID, err))\n\t\t}\n\t\tcrane2to1.ship.MarkPublic()\n\t\tcraneWg.Done()\n\t}()\n\tgo func() {\n\t\tvar err error\n\t\tcrane2to3, err = NewCrane(ship2to3, connectedHub3, nil)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not create crane2to3: %s\", testID, err))\n\t\t}\n\t\tcrane2to3.ID = \"c2to3\"\n\t\terr = crane2to3.Start(craneCtx)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not start crane2to3: %s\", testID, err))\n\t\t}\n\t\tcrane2to3.ship.MarkPublic()\n\t\tcraneWg.Done()\n\t}()\n\tgo func() {\n\t\tvar err error\n\t\tcrane3to2, err = NewCrane(ship2to3.Reverse(), nil, identity3)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not create crane3to2: %s\", testID, err))\n\t\t}\n\t\tcrane3to2.ID = \"c3to2\"\n\t\terr = crane3to2.Start(craneCtx)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not start crane3to2: %s\", testID, err))\n\t\t}\n\t\tcrane3to2.ship.MarkPublic()\n\t\tcraneWg.Done()\n\t}()\n\tgo func() {\n\t\tvar err error\n\t\tcrane3to4, err = NewCrane(ship3to4, connectedHub4, nil)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not create crane3to4: %s\", testID, err))\n\t\t}\n\t\tcrane3to4.ID = \"c3to4\"\n\t\terr = crane3to4.Start(craneCtx)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not start crane3to4: %s\", testID, err))\n\t\t}\n\t\tcrane3to4.ship.MarkPublic()\n\t\tcraneWg.Done()\n\t}()\n\tgo func() {\n\t\tvar err error\n\t\tcrane4, err = NewCrane(ship3to4.Reverse(), nil, identity4)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not create crane4: %s\", testID, err))\n\t\t}\n\t\tcrane4.ID = \"c4\"\n\t\terr = crane4.Start(craneCtx)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"expansion test %s could not start crane4: %s\", testID, err))\n\t\t}\n\t\tcrane4.ship.MarkPublic()\n\t\tcraneWg.Done()\n\t}()\n\tcraneWg.Wait()\n\n\t// Assign cranes.\n\tcrane3HubID := testID + \"-crane3HubID\"\n\tAssignCrane(crane3HubID, crane2to3)\n\tcrane4HubID := testID + \"-crane4HubID\"\n\tAssignCrane(crane4HubID, crane3to4)\n\n\tt.Logf(\"expansion test %s: initial setup complete\", testID)\n\n\t// Wait async for test to complete, print stack after timeout.\n\tfinished := make(chan struct{})\n\tgo func() {\n\t\tselect {\n\t\tcase <-finished:\n\t\tcase <-time.After(30 * time.Second):\n\t\t\tfmt.Printf(\"expansion test %s is taking too long, print stack:\\n\", testID)\n\t\t\t_ = pprof.Lookup(\"goroutine\").WriteTo(os.Stdout, 1)\n\t\t\tos.Exit(1)\n\t\t}\n\t}()\n\n\t// Start initial crane.\n\thomeTerminal, initData, tErr := NewLocalCraneTerminal(crane1, nil, &terminal.TerminalOpts{})\n\tif tErr != nil {\n\t\tt.Fatalf(\"expansion test %s failed to create home terminal: %s\", testID, tErr)\n\t}\n\ttErr = crane1.EstablishNewTerminal(homeTerminal, initData)\n\tif tErr != nil {\n\t\tt.Fatalf(\"expansion test %s failed to connect home terminal: %s\", testID, tErr)\n\t}\n\n\tt.Logf(\"expansion test %s: home terminal setup complete\", testID)\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// Start counters for testing.\n\top0, tErr := terminal.NewCounterOp(homeTerminal, terminal.CounterOpts{\n\t\tClientCountTo: clientCountTo,\n\t\tServerCountTo: serverCountTo,\n\t})\n\tif tErr != nil {\n\t\tt.Fatalf(\"expansion test %s failed to run counter op: %s\", testID, tErr)\n\t}\n\tt.Logf(\"expansion test %s: home terminal counter setup complete\", testID)\n\tif !inParallel {\n\t\top0.Wait()\n\t}\n\n\t// Start expansion to crane 3.\n\topAuthTo2, tErr := access.AuthorizeToTerminal(homeTerminal)\n\tif tErr != nil {\n\t\tt.Fatalf(\"expansion test %s failed to auth with home terminal: %s\", testID, tErr)\n\t}\n\ttErr = <-opAuthTo2.Result\n\tif tErr.IsError() {\n\t\tt.Fatalf(\"expansion test %s failed to auth with home terminal: %s\", testID, tErr)\n\t}\n\texpansionTerminalTo3, err := ExpandTo(homeTerminal, crane3HubID, connectedHub3)\n\tif err != nil {\n\t\tt.Fatalf(\"expansion test %s failed to expand to %s: %s\", testID, crane3HubID, tErr)\n\t}\n\n\t// Start counters for testing.\n\top1, tErr := terminal.NewCounterOp(expansionTerminalTo3, terminal.CounterOpts{\n\t\tClientCountTo: clientCountTo,\n\t\tServerCountTo: serverCountTo,\n\t})\n\tif tErr != nil {\n\t\tt.Fatalf(\"expansion test %s failed to run counter op: %s\", testID, tErr)\n\t}\n\n\tt.Logf(\"expansion test %s: expansion to crane3 and counter setup complete\", testID)\n\tif !inParallel {\n\t\top1.Wait()\n\t}\n\n\t// Start expansion to crane 4.\n\topAuthTo3, tErr := access.AuthorizeToTerminal(expansionTerminalTo3)\n\tif tErr != nil {\n\t\tt.Fatalf(\"expansion test %s failed to auth with extenstion terminal: %s\", testID, tErr)\n\t}\n\ttErr = <-opAuthTo3.Result\n\tif tErr.IsError() {\n\t\tt.Fatalf(\"expansion test %s failed to auth with extenstion terminal: %s\", testID, tErr)\n\t}\n\n\texpansionTerminalTo4, err := ExpandTo(expansionTerminalTo3, crane4HubID, connectedHub4)\n\tif err != nil {\n\t\tt.Fatalf(\"expansion test %s failed to expand to %s: %s\", testID, crane4HubID, tErr)\n\t}\n\n\t// Start counters for testing.\n\top2, tErr := terminal.NewCounterOp(expansionTerminalTo4, terminal.CounterOpts{\n\t\tClientCountTo: clientCountTo,\n\t\tServerCountTo: serverCountTo,\n\t})\n\tif tErr != nil {\n\t\tt.Fatalf(\"expansion test %s failed to run counter op: %s\", testID, tErr)\n\t}\n\n\tt.Logf(\"expansion test %s: expansion to crane4 and counter setup complete\", testID)\n\top2.Wait()\n\n\t// Wait for op1 if not already.\n\tif inParallel {\n\t\top0.Wait()\n\t\top1.Wait()\n\t}\n\n\t// Signal completion.\n\tclose(finished)\n\n\t// Wait a little so that all errors can be propagated, so we can truly see\n\t// if we succeeded.\n\ttime.Sleep(100 * time.Millisecond)\n\n\t// Check errors.\n\tif op1.Error != nil {\n\t\tt.Fatalf(\"crane test %s counter op1 failed: %s\", testID, op1.Error)\n\t}\n\tif op2.Error != nil {\n\t\tt.Fatalf(\"crane test %s counter op2 failed: %s\", testID, op2.Error)\n\t}\n}\n"
  },
  {
    "path": "spn/hub/database.go",
    "content": "package hub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n)\n\nvar (\n\tdb = database.NewInterface(&database.Options{\n\t\tLocal:    true,\n\t\tInternal: true,\n\t})\n\n\tgetFromNavigator func(mapName, hubID string) *Hub\n)\n\n// MakeHubDBKey makes a hub db key.\nfunc MakeHubDBKey(mapName, hubID string) string {\n\treturn fmt.Sprintf(\"cache:spn/hubs/%s/%s\", mapName, hubID)\n}\n\n// MakeHubMsgDBKey makes a hub msg db key.\nfunc MakeHubMsgDBKey(mapName string, msgType MsgType, hubID string) string {\n\treturn fmt.Sprintf(\"cache:spn/msgs/%s/%s/%s\", mapName, msgType, hubID)\n}\n\n// SetNavigatorAccess sets a shortcut function to access hubs from the navigator instead of having go through the database.\n// This also reduces the number of object in RAM and better caches parsed attributes.\nfunc SetNavigatorAccess(fn func(mapName, hubID string) *Hub) {\n\tif getFromNavigator == nil {\n\t\tgetFromNavigator = fn\n\t}\n}\n\n// GetHub get a Hub from the database - or the navigator, if configured.\nfunc GetHub(mapName string, hubID string) (*Hub, error) {\n\tif getFromNavigator != nil {\n\t\thub := getFromNavigator(mapName, hubID)\n\t\tif hub != nil {\n\t\t\treturn hub, nil\n\t\t}\n\t}\n\n\treturn GetHubByKey(MakeHubDBKey(mapName, hubID))\n}\n\n// GetHubByKey returns a hub by its raw DB key.\nfunc GetHubByKey(key string) (*Hub, error) {\n\tr, err := db.Get(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thub, err := EnsureHub(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn hub, nil\n}\n\n// EnsureHub makes sure a database record is a Hub.\nfunc EnsureHub(r record.Record) (*Hub, error) {\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewHub := &Hub{}\n\t\terr := record.Unwrap(r, newHub)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewHub = prepHub(newHub)\n\n\t\t// Fully validate when getting from database.\n\t\tif err := newHub.Info.validateFormatting(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"announcement failed format validation: %w\", err)\n\t\t}\n\t\tif err := newHub.Status.validateFormatting(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"status failed format validation: %w\", err)\n\t\t}\n\t\tif err := newHub.Info.prepare(false); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to prepare announcement: %w\", err)\n\t\t}\n\n\t\treturn newHub, nil\n\t}\n\n\t// or adjust type\n\tnewHub, ok := r.(*Hub)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *Hub, but %T\", r)\n\t}\n\tnewHub = prepHub(newHub)\n\n\t// Prepare only when already parsed.\n\tif err := newHub.Info.prepare(false); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to prepare announcement: %w\", err)\n\t}\n\n\t// ensure status\n\treturn newHub, nil\n}\n\nfunc prepHub(h *Hub) *Hub {\n\tif h.Status == nil {\n\t\th.Status = &Status{}\n\t}\n\th.Measurements = getSharedMeasurements(h.ID, h.Measurements)\n\treturn h\n}\n\n// Save saves to Hub to the correct scope in the database.\nfunc (h *Hub) Save() error {\n\tif !h.KeyIsSet() {\n\t\th.SetKey(MakeHubDBKey(h.Map, h.ID))\n\t}\n\n\treturn db.Put(h)\n}\n\n// RemoveHubAndMsgs deletes a Hub and it's saved messages from the database.\nfunc RemoveHubAndMsgs(mapName string, hubID string) (err error) {\n\terr = db.Delete(MakeHubDBKey(mapName, hubID))\n\tif err != nil && !errors.Is(err, database.ErrNotFound) {\n\t\treturn fmt.Errorf(\"failed to delete main hub entry: %w\", err)\n\t}\n\n\terr = db.Delete(MakeHubMsgDBKey(mapName, MsgTypeAnnouncement, hubID))\n\tif err != nil && !errors.Is(err, database.ErrNotFound) {\n\t\treturn fmt.Errorf(\"failed to delete hub announcement data: %w\", err)\n\t}\n\n\terr = db.Delete(MakeHubMsgDBKey(mapName, MsgTypeStatus, hubID))\n\tif err != nil && !errors.Is(err, database.ErrNotFound) {\n\t\treturn fmt.Errorf(\"failed to delete hub status data: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// HubMsg stores raw Hub messages.\ntype HubMsg struct { //nolint:golint\n\trecord.Base\n\tsync.Mutex\n\n\tID   string\n\tMap  string\n\tType MsgType\n\tData []byte\n\n\tReceived int64\n}\n\n// SaveHubMsg saves a raw (and signed) message received by another Hub.\nfunc SaveHubMsg(id string, mapName string, msgType MsgType, data []byte) error {\n\t// create wrapper record\n\tmsg := &HubMsg{\n\t\tID:       id,\n\t\tMap:      mapName,\n\t\tType:     msgType,\n\t\tData:     data,\n\t\tReceived: time.Now().Unix(),\n\t}\n\t// set key\n\tmsg.SetKey(MakeHubMsgDBKey(msg.Map, msg.Type, msg.ID))\n\t// save\n\treturn db.PutNew(msg)\n}\n\n// QueryRawGossipMsgs queries the database for raw gossip messages.\nfunc QueryRawGossipMsgs(mapName string, msgType MsgType) (it *iterator.Iterator, err error) {\n\tit, err = db.Query(query.New(MakeHubMsgDBKey(mapName, msgType, \"\")))\n\treturn\n}\n\n// EnsureHubMsg makes sure a database record is a HubMsg.\nfunc EnsureHubMsg(r record.Record) (*HubMsg, error) {\n\t// unwrap\n\tif r.IsWrapped() {\n\t\t// only allocate a new struct, if we need it\n\t\tnewHubMsg := &HubMsg{}\n\t\terr := record.Unwrap(r, newHubMsg)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn newHubMsg, nil\n\t}\n\n\t// or adjust type\n\tnewHubMsg, ok := r.(*HubMsg)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"record not of type *Hub, but %T\", r)\n\t}\n\treturn newHubMsg, nil\n}\n"
  },
  {
    "path": "spn/hub/errors.go",
    "content": "package hub\n\nimport \"errors\"\n\nvar (\n\t// ErrMissingInfo signifies that the hub is missing the HubAnnouncement.\n\tErrMissingInfo = errors.New(\"hub has no announcement\")\n\n\t// ErrMissingTransports signifies that the hub announcement did not specify any transports.\n\tErrMissingTransports = errors.New(\"hub announcement has no transports\")\n\n\t// ErrMissingIPs signifies that the hub announcement did not specify any IPs,\n\t// or none of the IPs is supported by the client.\n\tErrMissingIPs = errors.New(\"hub announcement has no (supported) IPs\")\n\n\t// ErrTemporaryValidationError is returned when a validation error might be temporary.\n\tErrTemporaryValidationError = errors.New(\"temporary validation error\")\n\n\t// ErrOldData is returned when received data is outdated.\n\tErrOldData = errors.New(\"\")\n)\n"
  },
  {
    "path": "spn/hub/format.go",
    "content": "package hub\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"regexp\"\n\n\t\"github.com/safing/portmaster/service/network/netutils\"\n)\n\n// BaselineCharset defines the permitted characters.\nvar BaselineCharset = regexp.MustCompile(\n\t// Start of charset selection.\n\t`^[` +\n\t\t// Printable ASCII (character code 32-127), excluding common control characters of different languages: \"$%&';<>\\` and DELETE.\n\t\t` !#()*+,\\-\\./0-9:=?@A-Z[\\]^_a-z{|}~` +\n\t\t// Only latin characters from extended ASCII (character code 128-255).\n\t\t`ŠŒŽšœžŸ¡¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ` +\n\t\t// End of charset selection.\n\t\t`]*$`,\n)\n\nfunc checkStringFormat(fieldName, value string, maxLength int) error {\n\tswitch {\n\tcase len(value) > maxLength:\n\t\treturn fmt.Errorf(\"field %s with length of %d exceeds max length of %d\", fieldName, len(value), maxLength)\n\tcase !BaselineCharset.MatchString(value):\n\t\treturn fmt.Errorf(\"field %s contains characters not permitted by baseline validation\", fieldName)\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc checkStringSliceFormat(fieldName string, value []string, maxLength, maxStringLength int) error { //nolint:unparam\n\tif len(value) > maxLength {\n\t\treturn fmt.Errorf(\"field %s with array/slice length of %d exceeds max length of %d\", fieldName, len(value), maxLength)\n\t}\n\tfor _, s := range value {\n\t\tif err := checkStringFormat(fieldName, s, maxStringLength); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc checkByteSliceFormat(fieldName string, value []byte, maxLength int) error {\n\tswitch {\n\tcase len(value) > maxLength:\n\t\treturn fmt.Errorf(\"field %s with length of %d exceeds max length of %d\", fieldName, len(value), maxLength)\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc checkIPFormat(fieldName string, value net.IP) error {\n\t// Check if there is an IP address.\n\tif value == nil {\n\t\treturn nil\n\t}\n\n\tswitch {\n\tcase len(value) != 4 && len(value) != 16:\n\t\treturn fmt.Errorf(\"field %s has an invalid length of %d for an IP address\", fieldName, len(value))\n\tcase netutils.GetIPScope(value) == netutils.Invalid:\n\t\treturn fmt.Errorf(\"field %s holds an invalid IP address: %s\", fieldName, value)\n\tdefault:\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "spn/hub/format_test.go",
    "content": "package hub\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCheckStringFormat(t *testing.T) {\n\tt.Parallel()\n\n\ttestSet := map[string]bool{\n\t\t// Printable ASCII (character code 32-127)\n\t\t\" \": true, \"!\": true, `\"`: false, \"#\": true, \"$\": false, \"%\": false, \"&\": false, \"'\": false,\n\t\t\"(\": true, \")\": true, \"*\": true, \"+\": true, \",\": true, \"-\": true, \".\": true, \"/\": true,\n\t\t\"0\": true, \"1\": true, \"2\": true, \"3\": true, \"4\": true, \"5\": true, \"6\": true, \"7\": true,\n\t\t\"8\": true, \"9\": true, \":\": true, \";\": false, \"<\": false, \"=\": true, \">\": false, \"?\": true,\n\t\t\"@\": true, \"A\": true, \"B\": true, \"C\": true, \"D\": true, \"E\": true, \"F\": true, \"G\": true,\n\t\t\"H\": true, \"I\": true, \"J\": true, \"K\": true, \"L\": true, \"M\": true, \"N\": true, \"O\": true,\n\t\t\"P\": true, \"Q\": true, \"R\": true, \"S\": true, \"T\": true, \"U\": true, \"V\": true, \"W\": true,\n\t\t\"X\": true, \"Y\": true, \"Z\": true, \"[\": true, `\\`: false, \"]\": true, \"^\": true, \"_\": true,\n\t\t\"`\": false, \"a\": true, \"b\": true, \"c\": true, \"d\": true, \"e\": true, \"f\": true, \"g\": true,\n\t\t\"h\": true, \"i\": true, \"j\": true, \"k\": true, \"l\": true, \"m\": true, \"n\": true, \"o\": true,\n\t\t\"p\": true, \"q\": true, \"r\": true, \"s\": true, \"t\": true, \"u\": true, \"v\": true, \"w\": true,\n\t\t\"x\": true, \"y\": true, \"z\": true, \"{\": true, \"|\": true, \"}\": true, \"~\": true,\n\t\t// Not testing for DELETE character.\n\n\t\t// Extended ASCII (character code 128-255)\n\t\t\"€\": false, \"‚\": false, \"ƒ\": false, \"„\": false, \"…\": false, \"†\": false, \"‡\": false, \"ˆ\": false,\n\t\t\"‰\": false, \"Š\": true, \"‹\": false, \"Œ\": true, \"Ž\": true, \"‘\": false, \"’\": false, \"“\": false,\n\t\t\"”\": false, \"•\": false, \"–\": false, \"—\": false, \"˜\": false, \"™\": false, \"š\": true, \"›\": false,\n\t\t\"œ\": true, \"ž\": true, \"Ÿ\": true, \"¡\": true, \"¢\": false, \"£\": false, \"¤\": false, \"¥\": false,\n\t\t\"¦\": false, \"§\": false, \"¨\": false, \"©\": false, \"ª\": false, \"«\": false, \"¬\": false, \"®\": false,\n\t\t\"¯\": false, \"°\": false, \"±\": false, \"²\": false, \"³\": false, \"´\": false, \"µ\": false, \"¶\": false,\n\t\t\"·\": false, \"¸\": false, \"¹\": false, \"º\": false, \"»\": false, \"¼\": false, \"½\": false, \"¾\": false,\n\t\t\"¿\": true, \"À\": true, \"Á\": true, \"Â\": true, \"Ã\": true, \"Ä\": true, \"Å\": true, \"Æ\": true,\n\t\t\"Ç\": true, \"È\": true, \"É\": true, \"Ê\": true, \"Ë\": true, \"Ì\": true, \"Í\": true, \"Î\": true,\n\t\t\"Ï\": true, \"Ð\": true, \"Ñ\": true, \"Ò\": true, \"Ó\": true, \"Ô\": true, \"Õ\": true, \"Ö\": true,\n\t\t\"×\": false, \"Ø\": true, \"Ù\": true, \"Ú\": true, \"Û\": true, \"Ü\": true, \"Ý\": true, \"Þ\": true,\n\t\t\"ß\": true, \"à\": true, \"á\": true, \"â\": true, \"ã\": true, \"ä\": true, \"å\": true, \"æ\": true,\n\t\t\"ç\": true, \"è\": true, \"é\": true, \"ê\": true, \"ë\": true, \"ì\": true, \"í\": true, \"î\": true,\n\t\t\"ï\": true, \"ð\": true, \"ñ\": true, \"ò\": true, \"ó\": true, \"ô\": true, \"õ\": true, \"ö\": true,\n\t\t\"÷\": false, \"ø\": true, \"ù\": true, \"ú\": true, \"û\": true, \"ü\": true, \"ý\": true, \"þ\": true,\n\t\t\"ÿ\": true,\n\t}\n\n\tfor testCharacter, isPermitted := range testSet {\n\t\tif isPermitted {\n\t\t\trequire.NoError(t, checkStringFormat(fmt.Sprintf(\"test character %q\", testCharacter), testCharacter, 3))\n\t\t} else {\n\t\t\trequire.Error(t, checkStringFormat(fmt.Sprintf(\"test character %q\", testCharacter), testCharacter, 3))\n\t\t}\n\t}\n}\n\nfunc TestCheckIPFormat(t *testing.T) {\n\tt.Parallel()\n\n\t// IPv4\n\trequire.NoError(t, checkIPFormat(\"test IP 1.1.1.1\", net.IPv4(1, 1, 1, 1)))\n\trequire.NoError(t, checkIPFormat(\"test IP 192.168.1.1\", net.IPv4(192, 168, 1, 1)))\n\trequire.Error(t, checkIPFormat(\"test IP 255.0.0.1\", net.IPv4(255, 0, 0, 1)))\n\n\t// IPv6\n\trequire.NoError(t, checkIPFormat(\"test IP ::1\", net.ParseIP(\"::1\")))\n\trequire.NoError(t, checkIPFormat(\"test IP 2606:4700:4700::1111\", net.ParseIP(\"2606:4700:4700::1111\")))\n\n\t// Invalid\n\trequire.Error(t, checkIPFormat(\"test IP with length 3\", net.IP([]byte{0, 0, 0})))\n\trequire.Error(t, checkIPFormat(\"test IP with length 5\", net.IP([]byte{0, 0, 0, 0, 0})))\n\trequire.Error(t, checkIPFormat(\n\t\t\"test IP with length 15\",\n\t\tnet.IP([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}),\n\t))\n\trequire.Error(t, checkIPFormat(\n\t\t\"test IP with length 17\",\n\t\tnet.IP([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}),\n\t))\n}\n"
  },
  {
    "path": "spn/hub/hub.go",
    "content": "package hub\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\n// Scope is the network scope a Hub can be in.\ntype Scope uint8\n\nconst (\n\t// ScopeInvalid defines an invalid scope.\n\tScopeInvalid Scope = 0\n\n\t// ScopeLocal identifies local Hubs.\n\tScopeLocal Scope = 1\n\n\t// ScopePublic identifies public Hubs.\n\tScopePublic Scope = 2\n\n\t// ScopeTest identifies Hubs for testing.\n\tScopeTest Scope = 0xFF\n)\n\nconst (\n\tobsoleteValidAfter   = 30 * 24 * time.Hour\n\tobsoleteInvalidAfter = 7 * 24 * time.Hour\n)\n\n// MsgType defines the message type.\ntype MsgType string\n\n// Message Types.\nconst (\n\tMsgTypeAnnouncement = \"announcement\"\n\tMsgTypeStatus       = \"status\"\n)\n\n// Hub represents a network node in the SPN.\ntype Hub struct { //nolint:maligned\n\tsync.Mutex\n\trecord.Base\n\n\tID        string\n\tPublicKey *jess.Signet\n\tMap       string\n\n\tInfo   *Announcement\n\tStatus *Status\n\n\tMeasurements            *Measurements\n\tmeasurementsInitialized bool\n\n\tFirstSeen     time.Time\n\tVerifiedIPs   bool\n\tInvalidInfo   bool\n\tInvalidStatus bool\n}\n\n// Announcement is the main message type to publish Hub Information. This only changes if updated manually.\ntype Announcement struct {\n\t// Primary Key\n\t// hash of public key\n\t// must be checked if it matches the public key\n\tID string `cbor:\"i\"` // via jess.LabeledHash\n\n\t// PublicKey *jess.Signet\n\t// PublicKey // if not part of signature\n\t// Signature *jess.Letter\n\tTimestamp int64 `cbor:\"t\"` // Unix timestamp in seconds\n\n\t// Node Information\n\tName           string `cbor:\"n\"`                              // name of the node\n\tGroup          string `cbor:\"g,omitempty\"  json:\",omitempty\"` // person or organisation, who is in control of the node (should be same for all nodes of this person or organisation)\n\tContactAddress string `cbor:\"ca,omitempty\" json:\",omitempty\"` // contact possibility  (recommended, but optional)\n\tContactService string `cbor:\"cs,omitempty\" json:\",omitempty\"` // type of service of the contact address, if not email\n\n\t// currently unused, but collected for later use\n\tHosters    []string `cbor:\"ho,omitempty\" json:\",omitempty\"` // hoster supply chain (reseller, hosting provider, datacenter operator, ...)\n\tDatacenter string   `cbor:\"dc,omitempty\" json:\",omitempty\"` // datacenter will be bullshit checked\n\t// Format: CC-COMPANY-INTERNALCODE\n\t// Eg: DE-Hetzner-FSN1-DC5\n\n\t// Network Location and Access\n\t// If node is behind NAT (or similar), IP addresses must be configured\n\tIPv4       net.IP   `cbor:\"ip4,omitempty\" json:\",omitempty\"` // must be global and accessible\n\tIPv6       net.IP   `cbor:\"ip6,omitempty\" json:\",omitempty\"` // must be global and accessible\n\tTransports []string `cbor:\"tp,omitempty\"  json:\",omitempty\"`\n\t// {\n\t//   \"spn:17\",\n\t//   \"smtp:25\", // also support \"smtp://:25\n\t//   \"smtp:587\",\n\t//   \"imap:143\",\n\t//   \"http:80\",\n\t//   \"http://example.com:80\", // HTTP (based): use full path for request\n\t//   \"https:443\",\n\t//   \"ws:80\",\n\t//   \"wss://example.com:443/spn\",\n\t// } // protocols with metadata\n\tparsedTransports []*Transport\n\n\t// Policies - default permit\n\tEntry       []string `cbor:\"pi,omitempty\" json:\",omitempty\"`\n\tentryPolicy endpoints.Endpoints\n\t// {\"+ \", \"- *\"}\n\tExit       []string `cbor:\"po,omitempty\" json:\",omitempty\"`\n\texitPolicy endpoints.Endpoints\n\t// {\"- * TCP/25\", \"- US\"}\n\n\t// Flags holds flags that signify special states.\n\tFlags []string `cbor:\"f,omitempty\" json:\",omitempty\"`\n}\n\n// Copy returns a deep copy of the Announcement.\nfunc (a *Announcement) Copy() *Announcement {\n\treturn &Announcement{\n\t\tID:               a.ID,\n\t\tTimestamp:        a.Timestamp,\n\t\tName:             a.Name,\n\t\tContactAddress:   a.ContactAddress,\n\t\tContactService:   a.ContactService,\n\t\tHosters:          slices.Clone(a.Hosters),\n\t\tDatacenter:       a.Datacenter,\n\t\tIPv4:             a.IPv4,\n\t\tIPv6:             a.IPv6,\n\t\tTransports:       slices.Clone(a.Transports),\n\t\tparsedTransports: slices.Clone(a.parsedTransports),\n\t\tEntry:            slices.Clone(a.Entry),\n\t\tentryPolicy:      slices.Clone(a.entryPolicy),\n\t\tExit:             slices.Clone(a.Exit),\n\t\texitPolicy:       slices.Clone(a.exitPolicy),\n\t\tFlags:            slices.Clone(a.Flags),\n\t}\n}\n\n// GetInfo returns the hub info.\nfunc (h *Hub) GetInfo() *Announcement {\n\th.Lock()\n\tdefer h.Unlock()\n\n\treturn h.Info\n}\n\n// GetStatus returns the hub status.\nfunc (h *Hub) GetStatus() *Status {\n\th.Lock()\n\tdefer h.Unlock()\n\n\treturn h.Status\n}\n\n// GetMeasurements returns the hub measurements.\n// This method should always be used instead of direct access.\nfunc (h *Hub) GetMeasurements() *Measurements {\n\th.Lock()\n\tdefer h.Unlock()\n\n\treturn h.GetMeasurementsWithLockedHub()\n}\n\n// GetMeasurementsWithLockedHub returns the hub measurements.\n// The caller must hold the lock to Hub.\n// This method should always be used instead of direct access.\nfunc (h *Hub) GetMeasurementsWithLockedHub() *Measurements {\n\tif !h.measurementsInitialized {\n\t\th.Measurements = getSharedMeasurements(h.ID, h.Measurements)\n\t\th.Measurements.check()\n\t\th.measurementsInitialized = true\n\t}\n\n\treturn h.Measurements\n}\n\n// Verified return whether the Hub has been verified.\nfunc (h *Hub) Verified() bool {\n\th.Lock()\n\tdefer h.Unlock()\n\n\treturn h.VerifiedIPs\n}\n\n// String returns a human-readable representation of the Hub.\nfunc (h *Hub) String() string {\n\th.Lock()\n\tdefer h.Unlock()\n\n\treturn \"<Hub \" + h.getName() + \">\"\n}\n\n// StringWithoutLocking returns a human-readable representation of the Hub without locking it.\nfunc (h *Hub) StringWithoutLocking() string {\n\treturn \"<Hub \" + h.getName() + \">\"\n}\n\n// Name returns a human-readable version of a Hub's name. This name will likely consist of two parts: the given name and the ending of the ID to make it unique.\nfunc (h *Hub) Name() string {\n\th.Lock()\n\tdefer h.Unlock()\n\n\treturn h.getName()\n}\n\nfunc (h *Hub) getName() string {\n\t// Check for a short ID that is sometimes used for testing.\n\tif len(h.ID) < 8 {\n\t\treturn h.ID\n\t}\n\n\tshortenedID := h.ID[len(h.ID)-8:len(h.ID)-4] +\n\t\t\"-\" +\n\t\th.ID[len(h.ID)-4:]\n\n\t// Be more careful, as the Hub name is user input.\n\tswitch {\n\tcase h.Info.Name == \"\":\n\t\treturn shortenedID\n\tcase len(h.Info.Name) > 16:\n\t\treturn h.Info.Name[:16] + \" \" + shortenedID\n\tdefault:\n\t\treturn h.Info.Name + \" \" + shortenedID\n\t}\n}\n\n// Obsolete returns if the Hub is obsolete and may be deleted.\nfunc (h *Hub) Obsolete() bool {\n\th.Lock()\n\tdefer h.Unlock()\n\n\t// Check if Hub is valid.\n\tvar valid bool\n\tswitch {\n\tcase h.InvalidInfo:\n\tcase h.InvalidStatus:\n\tcase h.HasFlag(FlagOffline):\n\t\t// Treat offline as invalid.\n\tdefault:\n\t\tvalid = true\n\t}\n\n\t// Check when Hub was last seen.\n\tlastSeen := h.FirstSeen\n\tif h.Status.Timestamp != 0 {\n\t\tlastSeen = time.Unix(h.Status.Timestamp, 0)\n\t}\n\n\t// Check if Hub is obsolete.\n\tif valid {\n\t\treturn time.Now().Add(-obsoleteValidAfter).After(lastSeen)\n\t}\n\treturn time.Now().Add(-obsoleteInvalidAfter).After(lastSeen)\n}\n\n// HasFlag returns whether the Announcement or Status has the given flag set.\nfunc (h *Hub) HasFlag(flagName string) bool {\n\tswitch {\n\tcase h.Status != nil && slices.Contains[[]string, string](h.Status.Flags, flagName):\n\t\treturn true\n\tcase h.Info != nil && slices.Contains[[]string, string](h.Info.Flags, flagName):\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Equal returns whether the given Announcements are equal.\nfunc (a *Announcement) Equal(b *Announcement) bool {\n\tswitch {\n\tcase a == nil || b == nil:\n\t\treturn false\n\tcase a.ID != b.ID:\n\t\treturn false\n\tcase a.Timestamp != b.Timestamp:\n\t\treturn false\n\tcase a.Name != b.Name:\n\t\treturn false\n\tcase a.ContactAddress != b.ContactAddress:\n\t\treturn false\n\tcase a.ContactService != b.ContactService:\n\t\treturn false\n\tcase !equalStringSlice(a.Hosters, b.Hosters):\n\t\treturn false\n\tcase a.Datacenter != b.Datacenter:\n\t\treturn false\n\tcase !a.IPv4.Equal(b.IPv4):\n\t\treturn false\n\tcase !a.IPv6.Equal(b.IPv6):\n\t\treturn false\n\tcase !equalStringSlice(a.Transports, b.Transports):\n\t\treturn false\n\tcase !equalStringSlice(a.Entry, b.Entry):\n\t\treturn false\n\tcase !equalStringSlice(a.Exit, b.Exit):\n\t\treturn false\n\tcase !equalStringSlice(a.Flags, b.Flags):\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\n// validateFormatting check if all values conform to the basic format.\nfunc (a *Announcement) validateFormatting() error {\n\tif err := checkStringFormat(\"ID\", a.ID, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringFormat(\"Name\", a.Name, 32); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringFormat(\"Group\", a.Group, 32); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringFormat(\"ContactAddress\", a.ContactAddress, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringFormat(\"ContactService\", a.ContactService, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringSliceFormat(\"Hosters\", a.Hosters, 255, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringFormat(\"Datacenter\", a.Datacenter, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkIPFormat(\"IPv4\", a.IPv4); err != nil {\n\t\treturn err\n\t}\n\tif err := checkIPFormat(\"IPv6\", a.IPv6); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringSliceFormat(\"Transports\", a.Transports, 255, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringSliceFormat(\"Entry\", a.Entry, 255, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringSliceFormat(\"Exit\", a.Exit, 255, 255); err != nil {\n\t\treturn err\n\t}\n\tif err := checkStringSliceFormat(\"Flags\", a.Flags, 16, 32); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Prepare prepares the announcement by parsing policies and transports.\n// If fields are already parsed, they will only be parsed again, when force is set to true.\nfunc (a *Announcement) prepare(force bool) error {\n\tvar err error\n\n\t// Parse policies.\n\tif len(a.entryPolicy) == 0 || force {\n\t\tif a.entryPolicy, err = endpoints.ParseEndpoints(a.Entry); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse entry policy: %w\", err)\n\t\t}\n\t}\n\tif len(a.exitPolicy) == 0 || force {\n\t\tif a.exitPolicy, err = endpoints.ParseEndpoints(a.Exit); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse exit policy: %w\", err)\n\t\t}\n\t}\n\n\t// Parse transports.\n\tif len(a.parsedTransports) == 0 || force {\n\t\tparsed, errs := ParseTransports(a.Transports)\n\t\t// Log parsing warnings.\n\t\tfor _, err := range errs {\n\t\t\tlog.Warningf(\"hub: Hub %s (%s) has configured an %s\", a.Name, a.ID, err)\n\t\t}\n\t\t// Check if there are any valid transports.\n\t\tif len(parsed) == 0 {\n\t\t\treturn ErrMissingTransports\n\t\t}\n\t\ta.parsedTransports = parsed\n\t}\n\n\treturn nil\n}\n\n// EntryPolicy returns the Hub's entry policy.\nfunc (a *Announcement) EntryPolicy() endpoints.Endpoints {\n\treturn a.entryPolicy\n}\n\n// ExitPolicy returns the Hub's exit policy.\nfunc (a *Announcement) ExitPolicy() endpoints.Endpoints {\n\treturn a.exitPolicy\n}\n\n// ParsedTransports returns the Hub's parsed transports.\nfunc (a *Announcement) ParsedTransports() []*Transport {\n\treturn a.parsedTransports\n}\n\n// HasFlag returns whether the Announcement has the given flag set.\nfunc (a *Announcement) HasFlag(flagName string) bool {\n\treturn slices.Contains[[]string, string](a.Flags, flagName)\n}\n\n// String returns the string representation of the scope.\nfunc (s Scope) String() string {\n\tswitch s {\n\tcase ScopeInvalid:\n\t\treturn \"invalid\"\n\tcase ScopeLocal:\n\t\treturn \"local\"\n\tcase ScopePublic:\n\t\treturn \"public\"\n\tcase ScopeTest:\n\t\treturn \"test\"\n\tdefault:\n\t\treturn \"unknown\"\n\t}\n}\n\nfunc equalStringSlice(a, b []string) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\n\tfor i := range len(a) {\n\t\tif a[i] != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "spn/hub/hub_test.go",
    "content": "package hub\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/service/core/base\"\n)\n\ntype testInstance struct {\n\tdb   *dbmodule.DBModule\n\tbase *base.Base\n}\n\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\nfunc (stub *testInstance) DataDir() string                    { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tvar err error\n\n\t// Create a temporary directory for testing\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temporary data directory: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Initialize the instance with the necessary components\n\tstub := &testInstance{}\n\t// Init\n\tstub.db, err = dbmodule.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database: %w\", err)\n\t}\n\tstub.base, err = base.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to base updates: %w\", err)\n\t}\n\n\t// Start\n\terr = stub.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start database: %w\", err)\n\t}\n\terr = stub.base.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start base: %w\", err)\n\t}\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\", err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc TestEquality(t *testing.T) {\n\tt.Parallel()\n\n\t// empty match\n\ta := &Announcement{}\n\tassert.True(t, a.Equal(a), \"should match itself\") //nolint:gocritic // This is a test.\n\n\t// full match\n\ta = &Announcement{\n\t\tID:             \"a\",\n\t\tTimestamp:      1,\n\t\tName:           \"a\",\n\t\tContactAddress: \"a\",\n\t\tContactService: \"a\",\n\t\tHosters:        []string{\"a\", \"b\"},\n\t\tDatacenter:     \"a\",\n\t\tIPv4:           net.IPv4(1, 2, 3, 4),\n\t\tIPv6:           net.ParseIP(\"::1\"),\n\t\tTransports:     []string{\"a\", \"b\"},\n\t\tEntry:          []string{\"a\", \"b\"},\n\t\tExit:           []string{\"a\", \"b\"},\n\t}\n\tassert.True(t, a.Equal(a), \"should match itself\") //nolint:gocritic // This is a test.\n\n\t// no match\n\tb := &Announcement{ID: \"b\"}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{Timestamp: 2}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{Name: \"b\"}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{ContactAddress: \"b\"}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{ContactService: \"b\"}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{Hosters: []string{\"b\", \"c\"}}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{Datacenter: \"b\"}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{IPv4: net.IPv4(1, 2, 3, 5)}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{IPv6: net.ParseIP(\"::2\")}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{Transports: []string{\"b\", \"c\"}}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{Entry: []string{\"b\", \"c\"}}\n\tassert.False(t, a.Equal(b), \"should not match\")\n\tb = &Announcement{Exit: []string{\"b\", \"c\"}}\n\tassert.False(t, a.Equal(b), \"should not match\")\n}\n\nfunc TestStringify(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, \"<Hub abcdefg>\", (&Hub{ID: \"abcdefg\", Info: &Announcement{}}).String())\n\tassert.Equal(t, \"<Hub abcd-efgh>\", (&Hub{ID: \"abcdefgh\", Info: &Announcement{}}).String())\n\tassert.Equal(t, \"<Hub bcde-fghi>\", (&Hub{ID: \"abcdefghi\", Info: &Announcement{}}).String())\n\tassert.Equal(t, \"<Hub Franz bcde-fghi>\", (&Hub{ID: \"abcdefghi\", Info: &Announcement{Name: \"Franz\"}}).String())\n\tassert.Equal(t, \"<Hub AProbablyAutoGen bcde-fghi>\", (&Hub{ID: \"abcdefghi\", Info: &Announcement{Name: \"AProbablyAutoGeneratedName\"}}).String())\n}\n"
  },
  {
    "path": "spn/hub/intel.go",
    "content": "package hub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/ghodss/yaml\"\n\n\t\"github.com/safing/jess/lhash\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\n// Intel holds a collection of various security related data collections on Hubs.\ntype Intel struct {\n\t// BootstrapHubs is list of transports that also contain an IP and the Hub's ID.\n\tBootstrapHubs []string\n\n\t// Hubs holds intel regarding specific Hubs.\n\tHubs map[string]*HubIntel\n\n\t// AdviseOnlyTrustedHubs advises to only use trusted Hubs regardless of intended purpose.\n\tAdviseOnlyTrustedHubs bool\n\t// AdviseOnlyTrustedHomeHubs advises to only use trusted Hubs for Home Hubs.\n\tAdviseOnlyTrustedHomeHubs bool\n\t// AdviseOnlyTrustedDestinationHubs advises to only use trusted Hubs for Destination Hubs.\n\tAdviseOnlyTrustedDestinationHubs bool\n\n\t// Hub Advisories advise on the usage of Hubs and take the form of Endpoint Lists that match on both IPv4 and IPv6 addresses and their related data.\n\n\t// HubAdvisory always affects all Hubs.\n\tHubAdvisory []string\n\t// HomeHubAdvisory is only taken into account when selecting a Home Hub.\n\tHomeHubAdvisory []string\n\t// DestinationHubAdvisory is only taken into account when selecting a Destination Hub.\n\tDestinationHubAdvisory []string\n\n\t// Regions defines regions to assist network optimization.\n\tRegions []*RegionConfig\n\n\t// VirtualNetworks holds network configurations for virtual cloud networks.\n\tVirtualNetworks []*VirtualNetworkConfig\n\n\tparsed *ParsedIntel\n}\n\n// HubIntel holds Hub-related data.\ntype HubIntel struct { //nolint:golint\n\t// Trusted specifies if the Hub is specially designated for more sensitive tasks, such as handling unencrypted traffic.\n\tTrusted bool\n\n\t// Discontinued specifies if the Hub has been discontinued and should be marked as offline and removed.\n\tDiscontinued bool\n\n\t// VerifiedOwner holds the name of the verified owner / operator of the Hub.\n\tVerifiedOwner string\n\n\t// Override is used to override certain Hub information.\n\tOverride *InfoOverride\n}\n\n// RegionConfig holds the configuration of a region.\ntype RegionConfig struct {\n\t// ID is the internal identifier of the region.\n\tID string\n\t// Name is a human readable name of the region.\n\tName string\n\t// MemberPolicy specifies a list for including members.\n\tMemberPolicy []string\n\n\t// RegionalMinLanes specifies how many lanes other regions should build\n\t// to this region.\n\tRegionalMinLanes int\n\t// RegionalMinLanesPerHub specifies how many lanes other regions should\n\t// build to this region, per Hub in this region.\n\t// This value will usually be below one.\n\tRegionalMinLanesPerHub float64\n\t// RegionalMaxLanesOnHub specifies how many lanes from or to another region may be\n\t// built on one Hub per region.\n\tRegionalMaxLanesOnHub int\n\n\t// SatelliteMinLanes specifies how many lanes satellites (Hubs without\n\t// region) should build to this region.\n\tSatelliteMinLanes int\n\t// SatelliteMinLanesPerHub specifies how many lanes satellites (Hubs without\n\t// region) should build to this region, per Hub in this region.\n\t// This value will usually be below one.\n\tSatelliteMinLanesPerHub float64\n\n\t// InternalMinLanesOnHub specifies how many lanes every Hub should create\n\t// within the region at minimum.\n\tInternalMinLanesOnHub int\n\t// InternalMaxHops specifies the max hop constraint for internally optimizing\n\t// the region.\n\tInternalMaxHops int\n}\n\n// VirtualNetworkConfig holds configuration of a virtual network that binds multiple Hubs together.\ntype VirtualNetworkConfig struct {\n\t// Name is a human readable name of the virtual network.\n\tName string\n\t// Force forces the use of the mapped IP addresses after the Hub's IPs have been verified.\n\tForce bool\n\t// Mapping maps Hub IDs to internal IP addresses.\n\tMapping map[string]net.IP\n}\n\n// ParsedIntel holds a collection of parsed intel data.\ntype ParsedIntel struct {\n\t// HubAdvisory always affects all Hubs.\n\tHubAdvisory endpoints.Endpoints\n\n\t// HomeHubAdvisory is only taken into account when selecting a Home Hub.\n\tHomeHubAdvisory endpoints.Endpoints\n\n\t// DestinationHubAdvisory is only taken into account when selecting a Destination Hub.\n\tDestinationHubAdvisory endpoints.Endpoints\n}\n\n// Parsed returns the collection of parsed intel data.\nfunc (i *Intel) Parsed() *ParsedIntel {\n\treturn i.parsed\n}\n\n// ParseIntel parses Hub intelligence data.\nfunc ParseIntel(data []byte) (*Intel, error) {\n\t// Load data into struct.\n\tintel := &Intel{}\n\terr := yaml.Unmarshal(data, intel)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse data: %w\", err)\n\t}\n\n\t// Parse all endpoint lists.\n\terr = intel.ParseAdvisories()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn intel, nil\n}\n\n// ParseAdvisories parses all advisory endpoint lists.\nfunc (i *Intel) ParseAdvisories() (err error) {\n\ti.parsed = &ParsedIntel{}\n\n\ti.parsed.HubAdvisory, err = endpoints.ParseEndpoints(i.HubAdvisory)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse HubAdvisory list: %w\", err)\n\t}\n\n\ti.parsed.HomeHubAdvisory, err = endpoints.ParseEndpoints(i.HomeHubAdvisory)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse HomeHubAdvisory list: %w\", err)\n\t}\n\n\ti.parsed.DestinationHubAdvisory, err = endpoints.ParseEndpoints(i.DestinationHubAdvisory)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse DestinationHubAdvisory list: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// ParseBootstrapHub parses a bootstrap hub.\nfunc ParseBootstrapHub(bootstrapTransport string) (t *Transport, hubID string, hubIP net.IP, err error) {\n\t// Parse transport and check Hub ID.\n\tt, err = ParseTransport(bootstrapTransport)\n\tif err != nil {\n\t\treturn nil, \"\", nil, fmt.Errorf(\"failed to parse transport: %w\", err)\n\t}\n\tif t.Option == \"\" {\n\t\treturn nil, \"\", nil, errors.New(\"missing hub ID in URL fragment\")\n\t}\n\tif _, err := lhash.FromBase58(t.Option); err != nil {\n\t\treturn nil, \"\", nil, fmt.Errorf(\"hub ID is invalid: %w\", err)\n\t}\n\n\t// Parse IP address from transport.\n\tip := net.ParseIP(t.Domain)\n\tif ip == nil {\n\t\treturn nil, \"\", nil, errors.New(\"invalid IP address (domains are not supported for bootstrapping)\")\n\t}\n\n\t// Clean up transport for hub info.\n\tid := t.Option\n\tt.Domain = \"\"\n\tt.Option = \"\"\n\n\treturn t, id, ip, nil\n}\n"
  },
  {
    "path": "spn/hub/intel_override.go",
    "content": "package hub\n\nimport \"github.com/safing/portmaster/service/intel/geoip\"\n\n// InfoOverride holds data to overide hub info information.\ntype InfoOverride struct {\n\t// ContinentCode overrides the continent code of the geoip data.\n\tContinentCode string\n\t// CountryCode overrides the country code of the geoip data.\n\tCountryCode string\n\t// Coordinates overrides the geo coordinates code of the geoip data.\n\tCoordinates *geoip.Coordinates\n\t// ASN overrides the Autonomous System Number of the geoip data.\n\tASN uint\n\t// ASOrg overrides the Autonomous System Organization of the geoip data.\n\tASOrg string\n}\n"
  },
  {
    "path": "spn/hub/measurements.go",
    "content": "package hub\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n)\n\n// MaxCalculatedCost specifies the max calculated cost to be used for an unknown high cost.\nconst MaxCalculatedCost = 1000000\n\n// Measurements holds various measurements relating to a Hub.\n// Fields may not be accessed directly.\ntype Measurements struct {\n\tsync.Mutex\n\n\t// Latency designates the latency between these Hubs.\n\t// It is specified in nanoseconds.\n\tLatency time.Duration\n\t// LatencyMeasuredAt holds when the latency was measured.\n\tLatencyMeasuredAt time.Time\n\n\t// Capacity designates the available bandwidth between these Hubs.\n\t// It is specified in bit/s.\n\tCapacity int\n\t// CapacityMeasuredAt holds when the capacity measurement expires.\n\tCapacityMeasuredAt time.Time\n\n\t// CalculatedCost stores the calculated cost for direct access.\n\t// It is not set automatically, but needs to be set when needed.\n\tCalculatedCost float32\n\n\t// GeoProximity stores an approximation of the geolocation proximity.\n\t// The value is between 0 (other side of the world) and 100 (same location).\n\tGeoProximity float32\n\n\t// persisted holds whether the Measurements have been persisted to the\n\t// database.\n\tpersisted *abool.AtomicBool\n}\n\n// NewMeasurements returns a new measurements struct.\nfunc NewMeasurements() *Measurements {\n\tm := &Measurements{\n\t\tCalculatedCost: MaxCalculatedCost, // Push to back when sorting without data.\n\t}\n\tm.check()\n\treturn m\n}\n\n// Copy returns a copy of the measurements.\nfunc (m *Measurements) Copy() *Measurements {\n\tcopied := &Measurements{\n\t\tLatency:            m.Latency,\n\t\tLatencyMeasuredAt:  m.LatencyMeasuredAt,\n\t\tCapacity:           m.Capacity,\n\t\tCapacityMeasuredAt: m.CapacityMeasuredAt,\n\t\tCalculatedCost:     m.CalculatedCost,\n\t}\n\tcopied.check()\n\treturn copied\n}\n\n// Check checks if the Measurements are properly initialized and ready to use.\nfunc (m *Measurements) check() {\n\tif m == nil {\n\t\treturn\n\t}\n\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tif m.persisted == nil {\n\t\tm.persisted = abool.NewBool(true)\n\t}\n}\n\n// IsPersisted return whether changes to the measurements have been persisted.\nfunc (m *Measurements) IsPersisted() bool {\n\treturn m.persisted.IsSet()\n}\n\n// Valid returns whether there is a valid value .\nfunc (m *Measurements) Valid() bool {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tswitch {\n\tcase m.Latency == 0:\n\t\t// Latency is not set.\n\tcase m.Capacity == 0:\n\t\t// Capacity is not set.\n\tcase m.CalculatedCost == 0:\n\t\t// CalculatedCost is not set.\n\tcase m.CalculatedCost == MaxCalculatedCost:\n\t\t// CalculatedCost is set to static max value.\n\tdefault:\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// Expired returns whether any of the measurements has expired - calculated\n// with the given TTL.\nfunc (m *Measurements) Expired(ttl time.Duration) bool {\n\texpiry := time.Now().Add(-ttl)\n\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tswitch {\n\tcase expiry.After(m.LatencyMeasuredAt):\n\t\treturn true\n\tcase expiry.After(m.CapacityMeasuredAt):\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// SetLatency sets the latency to the given value.\nfunc (m *Measurements) SetLatency(latency time.Duration) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tm.Latency = latency\n\tm.LatencyMeasuredAt = time.Now()\n\tm.persisted.UnSet()\n}\n\n// GetLatency returns the latency and when it expires.\nfunc (m *Measurements) GetLatency() (latency time.Duration, measuredAt time.Time) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\treturn m.Latency, m.LatencyMeasuredAt\n}\n\n// SetCapacity sets the capacity to the given value.\n// The capacity is measued in bit/s.\nfunc (m *Measurements) SetCapacity(capacity int) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tm.Capacity = capacity\n\tm.CapacityMeasuredAt = time.Now()\n\tm.persisted.UnSet()\n}\n\n// GetCapacity returns the capacity and when it expires.\n// The capacity is measued in bit/s.\nfunc (m *Measurements) GetCapacity() (capacity int, measuredAt time.Time) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\treturn m.Capacity, m.CapacityMeasuredAt\n}\n\n// SetCalculatedCost sets the calculated cost to the given value.\n// The calculated cost is not set automatically, but needs to be set when needed.\nfunc (m *Measurements) SetCalculatedCost(cost float32) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tm.CalculatedCost = cost\n\tm.persisted.UnSet()\n}\n\n// GetCalculatedCost returns the calculated cost.\n// The calculated cost is not set automatically, but needs to be set when needed.\nfunc (m *Measurements) GetCalculatedCost() (cost float32) {\n\tif m == nil {\n\t\treturn MaxCalculatedCost\n\t}\n\n\tm.Lock()\n\tdefer m.Unlock()\n\n\treturn m.CalculatedCost\n}\n\n// SetGeoProximity sets the geolocation proximity to the given value.\nfunc (m *Measurements) SetGeoProximity(geoProximity float32) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tm.GeoProximity = geoProximity\n\tm.persisted.UnSet()\n}\n\n// GetGeoProximity returns the geolocation proximity.\nfunc (m *Measurements) GetGeoProximity() (geoProximity float32) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\n\tm.Lock()\n\tdefer m.Unlock()\n\n\treturn m.GeoProximity\n}\n\nvar (\n\tmeasurementsRegistry     = make(map[string]*Measurements)\n\tmeasurementsRegistryLock sync.Mutex\n)\n\nfunc getSharedMeasurements(hubID string, existing *Measurements) *Measurements {\n\tmeasurementsRegistryLock.Lock()\n\tdefer measurementsRegistryLock.Unlock()\n\n\t// 1. Check registry and return shared measurements.\n\tm, ok := measurementsRegistry[hubID]\n\tif ok {\n\t\treturn m\n\t}\n\n\t// 2. Use existing and make it shared, if available.\n\tif existing != nil {\n\t\texisting.check()\n\t\tmeasurementsRegistry[hubID] = existing\n\t\treturn existing\n\t}\n\n\t// 3. Create new measurements.\n\tm = NewMeasurements()\n\tmeasurementsRegistry[hubID] = m\n\treturn m\n}\n"
  },
  {
    "path": "spn/hub/status.go",
    "content": "package hub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"time\"\n\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/jess\"\n)\n\n// VersionOffline is a special version used to signify that the Hub has gone offline.\n// This is depracated, please use FlagOffline instead.\nconst VersionOffline = \"offline\"\n\n// Status Flags.\nconst (\n\t// FlagNetError signifies that the Hub reports a network connectivity failure or impairment.\n\tFlagNetError = \"net-error\"\n\n\t// FlagOffline signifies that the Hub has gone offline by itself.\n\tFlagOffline = \"offline\"\n\n\t// FlagAllowUnencrypted signifies that the Hub is available to handle unencrypted connections.\n\tFlagAllowUnencrypted = \"allow-unencrypted\"\n)\n\n// Status is the message type used to update changing Hub Information. Changes are made automatically.\ntype Status struct {\n\tTimestamp int64 `cbor:\"t\"`\n\n\t// Version holds the current software version of the Hub.\n\tVersion string `cbor:\"v\"`\n\n\t// Routing Information\n\tKeys  map[string]*Key `cbor:\"k,omitempty\" json:\",omitempty\"` // public keys (with type)\n\tLanes []*Lane         `cbor:\"c,omitempty\" json:\",omitempty\"` // Connections to other Hubs.\n\n\t// Status Information\n\t// Load describes max(CPU, Memory) in percent, averaged over at least 15\n\t// minutes. Load is published in fixed steps only.\n\tLoad int `cbor:\"l,omitempty\" json:\",omitempty\"`\n\n\t// Flags holds flags that signify special states.\n\tFlags []string `cbor:\"f,omitempty\" json:\",omitempty\"`\n}\n\n// Key represents a semi-ephemeral public key used for 0-RTT connection establishment.\ntype Key struct {\n\tScheme  string\n\tKey     []byte\n\tExpires int64\n}\n\n// Lane represents a connection to another Hub.\ntype Lane struct {\n\t// ID is the Hub ID of the peer.\n\tID string\n\n\t// Capacity designates the available bandwidth between these Hubs.\n\t// It is specified in bit/s.\n\tCapacity int\n\n\t// Lateny designates the latency between these Hubs.\n\t// It is specified in nanoseconds.\n\tLatency time.Duration\n}\n\n// Copy returns a deep copy of the Status.\nfunc (s *Status) Copy() *Status {\n\tnewStatus := &Status{\n\t\tTimestamp: s.Timestamp,\n\t\tVersion:   s.Version,\n\t\tLanes:     slices.Clone(s.Lanes),\n\t\tLoad:      s.Load,\n\t\tFlags:     slices.Clone(s.Flags),\n\t}\n\t// Copy map.\n\tnewStatus.Keys = make(map[string]*Key, len(s.Keys))\n\tfor k, v := range s.Keys {\n\t\tnewStatus.Keys[k] = v\n\t}\n\treturn newStatus\n}\n\n// SelectSignet selects the public key to use for initiating connections to that Hub.\nfunc (h *Hub) SelectSignet() *jess.Signet {\n\th.Lock()\n\tdefer h.Unlock()\n\n\t// Return no Signet if we don't have a Status.\n\tif h.Status == nil {\n\t\treturn nil\n\t}\n\n\t// TODO: select key based on preferred alg?\n\tnow := time.Now().Unix()\n\tfor id, key := range h.Status.Keys {\n\t\tif now < key.Expires {\n\t\t\treturn &jess.Signet{\n\t\t\t\tID:     id,\n\t\t\t\tScheme: key.Scheme,\n\t\t\t\tKey:    key.Key,\n\t\t\t\tPublic: true,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// GetSignet returns the public key identified by the given ID from the Hub Status.\nfunc (h *Hub) GetSignet(id string, recipient bool) (*jess.Signet, error) {\n\th.Lock()\n\tdefer h.Unlock()\n\n\t// check if public key is being requested\n\tif !recipient {\n\t\treturn nil, jess.ErrSignetNotFound\n\t}\n\t// check if ID exists\n\tkey, ok := h.Status.Keys[id]\n\tif !ok {\n\t\treturn nil, jess.ErrSignetNotFound\n\t}\n\t// transform and return\n\treturn &jess.Signet{\n\t\tID:     id,\n\t\tScheme: key.Scheme,\n\t\tKey:    key.Key,\n\t\tPublic: true,\n\t}, nil\n}\n\n// AddLane adds a new Lane to the Hub Status.\nfunc (h *Hub) AddLane(newLane *Lane) error {\n\th.Lock()\n\tdefer h.Unlock()\n\n\t// validity check\n\tif h.Status == nil {\n\t\treturn ErrMissingInfo\n\t}\n\n\t// check if duplicate\n\tfor _, lane := range h.Status.Lanes {\n\t\tif newLane.ID == lane.ID {\n\t\t\treturn errors.New(\"lane already exists\")\n\t\t}\n\t}\n\n\t// add\n\th.Status.Lanes = append(h.Status.Lanes, newLane)\n\treturn nil\n}\n\n// RemoveLane removes a Lane from the Hub Status.\nfunc (h *Hub) RemoveLane(hubID string) error {\n\th.Lock()\n\tdefer h.Unlock()\n\n\t// validity check\n\tif h.Status == nil {\n\t\treturn ErrMissingInfo\n\t}\n\n\tfor key, lane := range h.Status.Lanes {\n\t\tif lane.ID == hubID {\n\t\t\th.Status.Lanes = append(h.Status.Lanes[:key], h.Status.Lanes[key+1:]...)\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// GetLaneTo returns the lane to the given Hub, if it exists.\nfunc (h *Hub) GetLaneTo(hubID string) *Lane {\n\th.Lock()\n\tdefer h.Unlock()\n\n\t// validity check\n\tif h.Status == nil {\n\t\treturn nil\n\t}\n\n\tfor _, lane := range h.Status.Lanes {\n\t\tif lane.ID == hubID {\n\t\t\treturn lane\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Equal returns whether the Lane is equal to the given one.\nfunc (l *Lane) Equal(other *Lane) bool {\n\tswitch {\n\tcase l == nil || other == nil:\n\t\treturn false\n\tcase l.ID != other.ID:\n\t\treturn false\n\tcase l.Capacity != other.Capacity:\n\t\treturn false\n\tcase l.Latency != other.Latency:\n\t\treturn false\n\t}\n\treturn true\n}\n\n// validateFormatting check if all values conform to the basic format.\nfunc (s *Status) validateFormatting() error {\n\t// public keys\n\tif len(s.Keys) > 255 {\n\t\treturn fmt.Errorf(\"field Keys with array/slice length of %d exceeds max length of %d\", len(s.Keys), 255)\n\t}\n\tfor keyID, key := range s.Keys {\n\t\tif err := checkStringFormat(\"Keys#ID\", keyID, 255); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := checkStringFormat(\"Keys.Scheme\", key.Scheme, 255); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := checkByteSliceFormat(\"Keys.Key\", key.Key, 1024); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// connections\n\tif len(s.Lanes) > 255 {\n\t\treturn fmt.Errorf(\"field Lanes with array/slice length of %d exceeds max length of %d\", len(s.Lanes), 255)\n\t}\n\tfor _, lanes := range s.Lanes {\n\t\tif err := checkStringFormat(\"Lanes.ID\", lanes.ID, 255); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Flags\n\tif err := checkStringSliceFormat(\"Flags\", s.Flags, 255, 255); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (l *Lane) String() string {\n\treturn fmt.Sprintf(\"<%s cap=%d lat=%d>\", l.ID, l.Capacity, l.Latency)\n}\n\n// LanesEqual returns whether the given []*Lane are equal.\nfunc LanesEqual(a, b []*Lane) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\n\tfor i, l := range a {\n\t\tif !l.Equal(b[i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\ntype lanes []*Lane\n\nfunc (l lanes) Len() int           { return len(l) }\nfunc (l lanes) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }\nfunc (l lanes) Less(i, j int) bool { return l[i].ID < l[j].ID }\n\n// SortLanes sorts a slice of Lanes.\nfunc SortLanes(l []*Lane) {\n\tsort.Sort(lanes(l))\n}\n\n// HasFlag returns whether the Status has the given flag set.\nfunc (s *Status) HasFlag(flagName string) bool {\n\treturn slices.Contains[[]string, string](s.Flags, flagName)\n}\n\n// FlagsEqual returns whether the given status flags are equal.\nfunc FlagsEqual(a, b []string) bool {\n\t// Cannot be equal if lengths are different.\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\n\t// If both are empty, they are equal.\n\tif len(a) == 0 {\n\t\treturn true\n\t}\n\n\t// Make sure flags are sorted before comparing values.\n\tsort.Strings(a)\n\tsort.Strings(b)\n\n\t// Compare values.\n\tfor i, v := range a {\n\t\tif v != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "spn/hub/transport.go",
    "content": "package hub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/exp/slices\"\n)\n\n// Examples:\n// \"spn:17\",\n// \"smtp:25\",\n// \"smtp:587\",\n// \"imap:143\",\n// \"http:80\",\n// \"http://example.com:80/example\", // HTTP (based): use full path for request\n// \"https:443\",\n// \"ws:80\",\n// \"wss://example.com:443/spn\",\n\n// Transport represents a \"endpoint\" that others can connect to. This allows for use of different protocols, ports and infrastructure integration.\ntype Transport struct {\n\tProtocol string\n\tDomain   string\n\tPort     uint16\n\tPath     string\n\tOption   string\n}\n\n// ParseTransports returns a list of parsed transports and errors from parsing\n// the given definitions.\nfunc ParseTransports(definitions []string) (transports []*Transport, errs []error) {\n\ttransports = make([]*Transport, 0, len(definitions))\n\tfor _, definition := range definitions {\n\t\tparsed, err := ParseTransport(definition)\n\t\tif err != nil {\n\t\t\terrs = append(errs, fmt.Errorf(\n\t\t\t\t\"unknown or invalid transport %q: %w\", definition, err,\n\t\t\t))\n\t\t} else {\n\t\t\ttransports = append(transports, parsed)\n\t\t}\n\t}\n\n\tSortTransports(transports)\n\treturn transports, errs\n}\n\n// ParseTransport parses a transport definition.\nfunc ParseTransport(definition string) (*Transport, error) {\n\tu, err := url.Parse(definition)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// check for invalid parts\n\tif u.User != nil {\n\t\treturn nil, errors.New(\"user/pass is not allowed\")\n\t}\n\n\t// put into transport\n\tt := &Transport{\n\t\tProtocol: u.Scheme,\n\t\tDomain:   u.Hostname(),\n\t\tPath:     u.RequestURI(),\n\t\tOption:   u.Fragment,\n\t}\n\n\t// parse port\n\tportData := u.Port()\n\tif portData == \"\" {\n\t\t// no port available - it might be in u.Opaque, which holds both the port and possibly a path\n\t\tportData = strings.SplitN(u.Opaque, \"/\", 2)[0] // get port\n\t\tt.Path = strings.TrimPrefix(t.Path, portData)  // trim port from path\n\t\t// check again for port\n\t\tif portData == \"\" {\n\t\t\treturn nil, errors.New(\"missing port\")\n\t\t}\n\t}\n\tport, err := strconv.ParseUint(portData, 10, 16)\n\tif err != nil {\n\t\treturn nil, errors.New(\"invalid port\")\n\t}\n\tt.Port = uint16(port)\n\n\t// check port\n\tif t.Port == 0 {\n\t\treturn nil, errors.New(\"invalid port\")\n\t}\n\n\t// remove root paths\n\tif t.Path == \"/\" {\n\t\tt.Path = \"\"\n\t}\n\n\t// check for protocol\n\tif t.Protocol == \"\" {\n\t\treturn nil, errors.New(\"missing scheme/protocol\")\n\t}\n\n\treturn t, nil\n}\n\n// String returns the definition form of the transport.\nfunc (t *Transport) String() string {\n\tswitch {\n\tcase t.Option != \"\":\n\t\treturn fmt.Sprintf(\"%s://%s:%d%s#%s\", t.Protocol, t.Domain, t.Port, t.Path, t.Option)\n\tcase t.Domain != \"\":\n\t\treturn fmt.Sprintf(\"%s://%s:%d%s\", t.Protocol, t.Domain, t.Port, t.Path)\n\tdefault:\n\t\treturn fmt.Sprintf(\"%s:%d%s\", t.Protocol, t.Port, t.Path)\n\t}\n}\n\n// SortTransports sorts the transports to emphasize certain protocols, but\n// otherwise leaves the order intact.\nfunc SortTransports(ts []*Transport) {\n\tslices.SortStableFunc[[]*Transport, *Transport](ts, func(a, b *Transport) int {\n\t\taOrder := a.protocolOrder()\n\t\tbOrder := b.protocolOrder()\n\n\t\tswitch {\n\t\tcase aOrder != bOrder:\n\t\t\treturn aOrder - bOrder\n\t\t// case a.Port != b.Port:\n\t\t// \treturn int(a.Port) - int(b.Port)\n\t\t// case a.Domain != b.Domain:\n\t\t// \treturn strings.Compare(a.Domain, b.Domain)\n\t\t// case a.Path != b.Path:\n\t\t// \treturn strings.Compare(a.Path, b.Path)\n\t\t// case a.Option != b.Option:\n\t\t// \treturn strings.Compare(a.Option, b.Option)\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\t})\n}\n\nfunc (t *Transport) protocolOrder() int {\n\tswitch t.Protocol {\n\tcase \"http\":\n\t\treturn 1\n\tcase \"spn\":\n\t\treturn 2\n\tdefault:\n\t\treturn 100\n\t}\n}\n"
  },
  {
    "path": "spn/hub/transport_test.go",
    "content": "package hub\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc parseT(t *testing.T, definition string) *Transport {\n\tt.Helper()\n\n\ttr, err := ParseTransport(definition)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t\treturn nil\n\t}\n\treturn tr\n}\n\nfunc parseTError(definition string) error {\n\t_, err := ParseTransport(definition)\n\treturn err\n}\n\nfunc TestTransportParsing(t *testing.T) {\n\tt.Parallel()\n\n\t// test parsing\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"spn\",\n\t\tPort:     17,\n\t}, parseT(t, \"spn:17\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"smtp\",\n\t\tPort:     25,\n\t}, parseT(t, \"smtp:25\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"smtp\",\n\t\tPort:     25,\n\t}, parseT(t, \"smtp://:25\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"smtp\",\n\t\tPort:     587,\n\t}, parseT(t, \"smtp:587\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"imap\",\n\t\tPort:     143,\n\t}, parseT(t, \"imap:143\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"http\",\n\t\tPort:     80,\n\t}, parseT(t, \"http:80\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"http\",\n\t\tDomain:   \"example.com\",\n\t\tPort:     80,\n\t}, parseT(t, \"http://example.com:80\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"https\",\n\t\tPort:     443,\n\t}, parseT(t, \"https:443\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"ws\",\n\t\tPort:     80,\n\t}, parseT(t, \"ws:80\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"wss\",\n\t\tDomain:   \"example.com\",\n\t\tPort:     443,\n\t\tPath:     \"/spn\",\n\t}, parseT(t, \"wss://example.com:443/spn\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"http\",\n\t\tDomain:   \"example.com\",\n\t\tPort:     80,\n\t}, parseT(t, \"http://example.com:80\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"http\",\n\t\tDomain:   \"example.com\",\n\t\tPort:     80,\n\t\tPath:     \"/test%20test\",\n\t}, parseT(t, \"http://example.com:80/test test\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"http\",\n\t\tDomain:   \"example.com\",\n\t\tPort:     80,\n\t\tPath:     \"/test%20test\",\n\t}, parseT(t, \"http://example.com:80/test%20test\"), \"should match\")\n\n\tassert.Equal(t, &Transport{\n\t\tProtocol: \"http\",\n\t\tDomain:   \"example.com\",\n\t\tPort:     80,\n\t\tPath:     \"/test?key=value\",\n\t}, parseT(t, \"http://example.com:80/test?key=value\"), \"should match\")\n\n\t// test parsing and formatting\n\n\tassert.Equal(t, \"spn:17\",\n\t\tparseT(t, \"spn:17\").String(), \"should match\")\n\tassert.Equal(t, \"smtp:25\",\n\t\tparseT(t, \"smtp:25\").String(), \"should match\")\n\tassert.Equal(t, \"smtp:25\",\n\t\tparseT(t, \"smtp://:25\").String(), \"should match\")\n\tassert.Equal(t, \"smtp:587\",\n\t\tparseT(t, \"smtp:587\").String(), \"should match\")\n\tassert.Equal(t, \"imap:143\",\n\t\tparseT(t, \"imap:143\").String(), \"should match\")\n\tassert.Equal(t, \"http:80\",\n\t\tparseT(t, \"http:80\").String(), \"should match\")\n\tassert.Equal(t, \"http://example.com:80\",\n\t\tparseT(t, \"http://example.com:80\").String(), \"should match\")\n\tassert.Equal(t, \"https:443\",\n\t\tparseT(t, \"https:443\").String(), \"should match\")\n\tassert.Equal(t, \"ws:80\",\n\t\tparseT(t, \"ws:80\").String(), \"should match\")\n\tassert.Equal(t, \"wss://example.com:443/spn\",\n\t\tparseT(t, \"wss://example.com:443/spn\").String(), \"should match\")\n\tassert.Equal(t, \"http://example.com:80\",\n\t\tparseT(t, \"http://example.com:80\").String(), \"should match\")\n\tassert.Equal(t, \"http://example.com:80/test%20test\",\n\t\tparseT(t, \"http://example.com:80/test test\").String(), \"should match\")\n\tassert.Equal(t, \"http://example.com:80/test%20test\",\n\t\tparseT(t, \"http://example.com:80/test%20test\").String(), \"should match\")\n\tassert.Equal(t, \"http://example.com:80/test?key=value\",\n\t\tparseT(t, \"http://example.com:80/test?key=value\").String(), \"should match\")\n\n\t// test invalid\n\n\trequire.Error(t, parseTError(\"spn\"), \"should fail\")\n\trequire.Error(t, parseTError(\"spn:\"), \"should fail\")\n\trequire.Error(t, parseTError(\"spn:0\"), \"should fail\")\n\trequire.Error(t, parseTError(\"spn:65536\"), \"should fail\")\n}\n"
  },
  {
    "path": "spn/hub/truststores.go",
    "content": "package hub\n\nimport \"github.com/safing/jess\"\n\n// SingleTrustStore is a simple truststore that always returns the same Signet.\ntype SingleTrustStore struct {\n\tSignet *jess.Signet\n}\n\n// GetSignet implements the truststore interface.\nfunc (ts *SingleTrustStore) GetSignet(id string, recipient bool) (*jess.Signet, error) {\n\tif ts.Signet.ID != id || recipient != ts.Signet.Public {\n\t\treturn nil, jess.ErrSignetNotFound\n\t}\n\n\treturn ts.Signet, nil\n}\n"
  },
  {
    "path": "spn/hub/update.go",
    "content": "package hub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/jess/lhash\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nvar (\n\t// hubMsgRequirements defines which security attributes message need to have.\n\thubMsgRequirements = jess.NewRequirements().\n\t\t\t\tRemove(jess.RecipientAuthentication). // Recipient don't need a private key.\n\t\t\t\tRemove(jess.Confidentiality).         // Message contents are out in the open.\n\t\t\t\tRemove(jess.Integrity)                // Only applies to decryption.\n\t// SenderAuthentication provides pre-decryption integrity. That is all we need.\n\n\tclockSkewTolerance = 12 * time.Hour\n)\n\n// SignHubMsg signs the given serialized hub msg with the given configuration.\nfunc SignHubMsg(msg []byte, env *jess.Envelope, enableTofu bool) ([]byte, error) {\n\t// start session from envelope\n\tsession, err := env.Correspondence(nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initiate signing session: %w\", err)\n\t}\n\t// sign the data\n\tletter, err := session.Close(msg)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to sign msg: %w\", err)\n\t}\n\n\tif enableTofu {\n\t\t// smuggle the public key\n\t\t// letter.Keys is usually only used for key exchanges and encapsulation\n\t\t// neither is used when signing, so we can use letter.Keys to transport public keys\n\t\tfor _, sender := range env.Senders {\n\t\t\t// get public key\n\t\t\tpublic, err := sender.AsRecipient()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get public key of %s: %w\", sender.ID, err)\n\t\t\t}\n\t\t\t// serialize key\n\t\t\terr = public.StoreKey()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to serialize public key %s: %w\", sender.ID, err)\n\t\t\t}\n\t\t\t// add to keys\n\t\t\tletter.Keys = append(letter.Keys, &jess.Seal{\n\t\t\t\tValue: public.Key,\n\t\t\t})\n\t\t}\n\t}\n\n\t// pack\n\tdata, err := letter.ToDSD(dsd.JSON)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\n// OpenHubMsg opens a signed hub msg and verifies the signature using the\n// provided hub or the local database. If TOFU is enabled, the signature is\n// always accepted, if valid.\nfunc OpenHubMsg(hub *Hub, data []byte, mapName string, tofu bool) (msg []byte, sendingHub *Hub, known bool, err error) {\n\tletter, err := jess.LetterFromDSD(data)\n\tif err != nil {\n\t\treturn nil, nil, false, fmt.Errorf(\"malformed letter: %w\", err)\n\t}\n\n\t// check signatures\n\tvar seal *jess.Seal\n\tswitch len(letter.Signatures) {\n\tcase 0:\n\t\treturn nil, nil, false, errors.New(\"missing signature\")\n\tcase 1:\n\t\tseal = letter.Signatures[0]\n\tdefault:\n\t\treturn nil, nil, false, fmt.Errorf(\"too many signatures (%d)\", len(letter.Signatures))\n\t}\n\n\t// check signature signer ID\n\tif seal.ID == \"\" {\n\t\treturn nil, nil, false, errors.New(\"signature is missing signer ID\")\n\t}\n\n\t// get hub for public key\n\tif hub == nil {\n\t\thub, err = GetHub(mapName, seal.ID)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, database.ErrNotFound) {\n\t\t\t\treturn nil, nil, false, fmt.Errorf(\"failed to get existing hub %s: %w\", seal.ID, err)\n\t\t\t}\n\t\t\thub = nil\n\t\t} else {\n\t\t\tknown = true\n\t\t}\n\t} else {\n\t\tknown = true\n\t}\n\n\tvar truststore jess.TrustStore\n\tif hub != nil && hub.PublicKey != nil { // bootstrap entries will not have a public key\n\t\t// check ID integrity\n\t\tif hub.ID != seal.ID {\n\t\t\treturn nil, hub, known, fmt.Errorf(\"ID mismatch with hub msg ID %s and hub ID %s\", seal.ID, hub.ID)\n\t\t}\n\t\tif !verifyHubID(seal.ID, hub.PublicKey.Scheme, hub.PublicKey.Key) {\n\t\t\treturn nil, hub, known, fmt.Errorf(\"ID integrity of %s violated with existing key\", seal.ID)\n\t\t}\n\t} else {\n\t\tif !tofu {\n\t\t\treturn nil, nil, false, fmt.Errorf(\"hub msg ID %s unknown (missing announcement)\", seal.ID)\n\t\t}\n\n\t\t// trust on first use, extract key from keys\n\t\t// TODO: Test if works without TOFU.\n\n\t\t// get key\n\t\tvar pubkey *jess.Seal\n\t\tswitch len(letter.Keys) {\n\t\tcase 0:\n\t\t\treturn nil, nil, false, fmt.Errorf(\"missing key for TOFU of %s\", seal.ID)\n\t\tcase 1:\n\t\t\tpubkey = letter.Keys[0]\n\t\tdefault:\n\t\t\treturn nil, nil, false, fmt.Errorf(\"too many keys (%d) for TOFU of %s\", len(letter.Keys), seal.ID)\n\t\t}\n\n\t\t// check ID integrity\n\t\tif !verifyHubID(seal.ID, seal.Scheme, pubkey.Value) {\n\t\t\treturn nil, nil, false, fmt.Errorf(\"ID integrity of %s violated with new key\", seal.ID)\n\t\t}\n\n\t\thub = &Hub{\n\t\t\tID:  seal.ID,\n\t\t\tMap: mapName,\n\t\t\tPublicKey: &jess.Signet{\n\t\t\t\tID:     seal.ID,\n\t\t\t\tScheme: seal.Scheme,\n\t\t\t\tKey:    pubkey.Value,\n\t\t\t\tPublic: true,\n\t\t\t},\n\t\t}\n\t\terr = hub.PublicKey.LoadKey()\n\t\tif err != nil {\n\t\t\treturn nil, nil, false, err\n\t\t}\n\t}\n\n\t// create trust store\n\ttruststore = &SingleTrustStore{hub.PublicKey}\n\n\t// remove keys from letter, as they are only used to transfer the public key\n\tletter.Keys = nil\n\n\t// check signature\n\terr = letter.Verify(hubMsgRequirements, truststore)\n\tif err != nil {\n\t\treturn nil, nil, false, err\n\t}\n\n\treturn letter.Data, hub, known, nil\n}\n\n// Export exports the announcement with the given signature configuration.\nfunc (a *Announcement) Export(env *jess.Envelope) ([]byte, error) {\n\t// pack\n\tmsg, err := dsd.Dump(a, dsd.JSON)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to pack announcement: %w\", err)\n\t}\n\n\treturn SignHubMsg(msg, env, true)\n}\n\n// ApplyAnnouncement applies the announcement to the Hub if it passes all the\n// checks. If no Hub is provided, it is loaded from the database or created.\nfunc ApplyAnnouncement(existingHub *Hub, data []byte, mapName string, scope Scope, selfcheck bool) (hub *Hub, known, changed bool, err error) {\n\t// Set valid/invalid status based on the return error.\n\tvar announcement *Announcement\n\tdefer func() {\n\t\tif hub != nil {\n\t\t\tif err != nil && !errors.Is(err, ErrOldData) {\n\t\t\t\thub.InvalidInfo = true\n\t\t\t} else {\n\t\t\t\thub.InvalidInfo = false\n\t\t\t}\n\t\t}\n\t}()\n\n\t// open and verify\n\tvar msg []byte\n\tmsg, hub, known, err = OpenHubMsg(existingHub, data, mapName, true)\n\n\t// Lock hub if we have one.\n\tif hub != nil && !selfcheck {\n\t\thub.Lock()\n\t\tdefer hub.Unlock()\n\t}\n\n\t// Check if there was an error with the Hub msg.\n\tif err != nil {\n\t\treturn //nolint:nakedret\n\t}\n\n\t// parse\n\tannouncement = &Announcement{}\n\t_, err = dsd.Load(msg, announcement)\n\tif err != nil {\n\t\treturn //nolint:nakedret\n\t}\n\n\t// integrity check\n\n\t// `hub.ID` is taken from the first ever received announcement message.\n\t// `announcement.ID` is additionally present in the message as we need\n\t// a signed version of the ID to mitigate fake IDs.\n\t// Fake IDs are possible because the hash algorithm of the ID is dynamic.\n\tif hub.ID != announcement.ID {\n\t\terr = fmt.Errorf(\"announcement ID %q mismatches hub ID %q\", announcement.ID, hub.ID)\n\t\treturn //nolint:nakedret\n\t}\n\n\t// version check\n\tif hub.Info != nil {\n\t\t// check if we already have this version\n\t\tswitch {\n\t\tcase announcement.Timestamp == hub.Info.Timestamp && !selfcheck:\n\t\t\t// The new copy is not saved, as we expect the versions to be identical.\n\t\t\t// Also, the new version has not been validated at this point.\n\t\t\treturn //nolint:nakedret\n\t\tcase announcement.Timestamp < hub.Info.Timestamp:\n\t\t\t// Received an old version, do not update.\n\t\t\terr = fmt.Errorf(\n\t\t\t\t\"%wannouncement from %s @ %s is older than current status @ %s\",\n\t\t\t\tErrOldData, hub.StringWithoutLocking(), time.Unix(announcement.Timestamp, 0), time.Unix(hub.Info.Timestamp, 0),\n\t\t\t)\n\t\t\treturn //nolint:nakedret\n\t\t}\n\t}\n\n\t// We received a new version.\n\tchanged = true\n\n\t// Update timestamp here already in case validation fails.\n\tif hub.Info != nil {\n\t\thub.Info.Timestamp = announcement.Timestamp\n\t}\n\n\t// Validate the announcement.\n\terr = hub.validateAnnouncement(announcement, scope)\n\tif err != nil {\n\t\tif selfcheck || hub.FirstSeen.IsZero() {\n\t\t\terr = fmt.Errorf(\"failed to validate announcement of %s: %w\", hub.StringWithoutLocking(), err)\n\t\t\treturn //nolint:nakedret\n\t\t}\n\n\t\tlog.Warningf(\"spn/hub: received an invalid announcement of %s: %s\", hub.StringWithoutLocking(), err)\n\t\t// If a previously fully validated Hub publishes an update that breaks it, a\n\t\t// soft-fail will accept the faulty changes, but mark is as invalid and\n\t\t// forward it to neighbors. This way the invalid update is propagated through\n\t\t// the network and all nodes will mark it as invalid an thus ingore the Hub\n\t\t// until the issue is fixed.\n\t}\n\n\t// Only save announcement if it is valid.\n\tif err == nil {\n\t\thub.Info = announcement\n\t}\n\t// Set FirstSeen timestamp when we see this Hub for the first time.\n\tif hub.FirstSeen.IsZero() {\n\t\thub.FirstSeen = time.Now().UTC()\n\t}\n\n\treturn //nolint:nakedret\n}\n\nfunc (h *Hub) validateAnnouncement(announcement *Announcement, scope Scope) error {\n\t// value formatting\n\tif err := announcement.validateFormatting(); err != nil {\n\t\treturn err\n\t}\n\t// check parsables\n\tif err := announcement.prepare(true); err != nil {\n\t\treturn fmt.Errorf(\"failed to prepare announcement: %w\", err)\n\t}\n\n\t// check timestamp\n\tif announcement.Timestamp > time.Now().Add(clockSkewTolerance).Unix() {\n\t\treturn fmt.Errorf(\n\t\t\t\"announcement from %s @ %s is from the future\",\n\t\t\tannouncement.ID,\n\t\t\ttime.Unix(announcement.Timestamp, 0),\n\t\t)\n\t}\n\n\t// check for illegal IP address changes\n\tif h.Info != nil {\n\t\tswitch {\n\t\tcase h.Info.IPv4 != nil && announcement.IPv4 == nil:\n\t\t\th.VerifiedIPs = false\n\t\t\treturn errors.New(\"previously announced IPv4 address missing\")\n\t\tcase h.Info.IPv4 != nil && !announcement.IPv4.Equal(h.Info.IPv4):\n\t\t\th.VerifiedIPs = false\n\t\t\treturn errors.New(\"IPv4 address changed\")\n\t\tcase h.Info.IPv6 != nil && announcement.IPv6 == nil:\n\t\t\th.VerifiedIPs = false\n\t\t\treturn errors.New(\"previously announced IPv6 address missing\")\n\t\tcase h.Info.IPv6 != nil && !announcement.IPv6.Equal(h.Info.IPv6):\n\t\t\th.VerifiedIPs = false\n\t\t\treturn errors.New(\"IPv6 address changed\")\n\t\t}\n\t}\n\n\t// validate IP scopes\n\tif announcement.IPv4 != nil {\n\t\tipScope := netutils.GetIPScope(announcement.IPv4)\n\t\tswitch {\n\t\tcase scope == ScopeLocal && !ipScope.IsLAN():\n\t\t\treturn errors.New(\"IPv4 scope violation: outside of local scope\")\n\t\tcase scope == ScopePublic && !ipScope.IsGlobal():\n\t\t\treturn errors.New(\"IPv4 scope violation: outside of global scope\")\n\t\t}\n\t\t// Reset IP verification flag if IPv4 was added.\n\t\tif h.Info == nil || h.Info.IPv4 == nil {\n\t\t\th.VerifiedIPs = false\n\t\t}\n\t}\n\tif announcement.IPv6 != nil {\n\t\tipScope := netutils.GetIPScope(announcement.IPv6)\n\t\tswitch {\n\t\tcase scope == ScopeLocal && !ipScope.IsLAN():\n\t\t\treturn errors.New(\"IPv6 scope violation: outside of local scope\")\n\t\tcase scope == ScopePublic && !ipScope.IsGlobal():\n\t\t\treturn errors.New(\"IPv6 scope violation: outside of global scope\")\n\t\t}\n\t\t// Reset IP verification flag if IPv6 was added.\n\t\tif h.Info == nil || h.Info.IPv6 == nil {\n\t\t\th.VerifiedIPs = false\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Export exports the status with the given signature configuration.\nfunc (s *Status) Export(env *jess.Envelope) ([]byte, error) {\n\t// pack\n\tmsg, err := dsd.Dump(s, dsd.JSON)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to pack status: %w\", err)\n\t}\n\n\treturn SignHubMsg(msg, env, false)\n}\n\n// ApplyStatus applies a status update if it passes all the checks.\nfunc ApplyStatus(existingHub *Hub, data []byte, mapName string, scope Scope, selfcheck bool) (hub *Hub, known, changed bool, err error) {\n\t// Set valid/invalid status based on the return error.\n\tdefer func() {\n\t\tif hub != nil {\n\t\t\tif err != nil && !errors.Is(err, ErrOldData) {\n\t\t\t\thub.InvalidStatus = true\n\t\t\t} else {\n\t\t\t\thub.InvalidStatus = false\n\t\t\t}\n\t\t}\n\t}()\n\n\t// open and verify\n\tvar msg []byte\n\tmsg, hub, known, err = OpenHubMsg(existingHub, data, mapName, false)\n\n\t// Lock hub if we have one.\n\tif hub != nil && !selfcheck {\n\t\thub.Lock()\n\t\tdefer hub.Unlock()\n\t}\n\n\t// Check if there was an error with the Hub msg.\n\tif err != nil {\n\t\treturn //nolint:nakedret\n\t}\n\n\t// parse\n\tstatus := &Status{}\n\t_, err = dsd.Load(msg, status)\n\tif err != nil {\n\t\treturn //nolint:nakedret\n\t}\n\n\t// version check\n\tif hub.Status != nil {\n\t\t// check if we already have this version\n\t\tswitch {\n\t\tcase status.Timestamp == hub.Status.Timestamp && !selfcheck:\n\t\t\t// The new copy is not saved, as we expect the versions to be identical.\n\t\t\t// Also, the new version has not been validated at this point.\n\t\t\treturn //nolint:nakedret\n\t\tcase status.Timestamp < hub.Status.Timestamp:\n\t\t\t// Received an old version, do not update.\n\t\t\terr = fmt.Errorf(\n\t\t\t\t\"%wstatus from %s @ %s is older than current status @ %s\",\n\t\t\t\tErrOldData, hub.StringWithoutLocking(), time.Unix(status.Timestamp, 0), time.Unix(hub.Status.Timestamp, 0),\n\t\t\t)\n\t\t\treturn //nolint:nakedret\n\t\t}\n\t}\n\n\t// We received a new version.\n\tchanged = true\n\n\t// Update timestamp here already in case validation fails.\n\tif hub.Status != nil {\n\t\thub.Status.Timestamp = status.Timestamp\n\t}\n\n\t// Validate the status.\n\terr = hub.validateStatus(status)\n\tif err != nil {\n\t\tif selfcheck {\n\t\t\terr = fmt.Errorf(\"failed to validate status of %s: %w\", hub.StringWithoutLocking(), err)\n\t\t\treturn //nolint:nakedret\n\t\t}\n\n\t\tlog.Warningf(\"spn/hub: received an invalid status of %s: %s\", hub.StringWithoutLocking(), err)\n\t\t// If a previously fully validated Hub publishes an update that breaks it, a\n\t\t// soft-fail will accept the faulty changes, but mark is as invalid and\n\t\t// forward it to neighbors. This way the invalid update is propagated through\n\t\t// the network and all nodes will mark it as invalid an thus ingore the Hub\n\t\t// until the issue is fixed.\n\t}\n\n\t// Only save status if it is valid, else mark it as invalid.\n\tif err == nil {\n\t\thub.Status = status\n\t}\n\n\treturn //nolint:nakedret\n}\n\nfunc (h *Hub) validateStatus(status *Status) error {\n\t// value formatting\n\tif err := status.validateFormatting(); err != nil {\n\t\treturn err\n\t}\n\n\t// check timestamp\n\tif status.Timestamp > time.Now().Add(clockSkewTolerance).Unix() {\n\t\treturn fmt.Errorf(\n\t\t\t\"status from %s @ %s is from the future\",\n\t\t\th.ID,\n\t\t\ttime.Unix(status.Timestamp, 0),\n\t\t)\n\t}\n\n\t// TODO: validate status.Keys\n\n\treturn nil\n}\n\n// CreateHubSignet creates a signet with the correct ID for usage as a Hub Identity.\nfunc CreateHubSignet(toolID string, securityLevel int) (private, public *jess.Signet, err error) {\n\tprivate, err = jess.GenerateSignet(toolID, securityLevel)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to generate key: %w\", err)\n\t}\n\terr = private.StoreKey()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to store private key: %w\", err)\n\t}\n\n\t// get public key for creating the Hub ID\n\tpublic, err = private.AsRecipient()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to get public key: %w\", err)\n\t}\n\terr = public.StoreKey()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to store public key: %w\", err)\n\t}\n\n\t// assign IDs\n\tprivate.ID = createHubID(public.Scheme, public.Key)\n\tpublic.ID = private.ID\n\n\treturn private, public, nil\n}\n\nfunc createHubID(scheme string, pubkey []byte) string {\n\t// compile scheme and public key\n\tc := container.New()\n\tc.AppendAsBlock([]byte(scheme))\n\tc.AppendAsBlock(pubkey)\n\n\treturn lhash.Digest(lhash.BLAKE2b_256, c.CompileData()).Base58()\n}\n\nfunc verifyHubID(id string, scheme string, pubkey []byte) (ok bool) {\n\t// load labeled hash from ID\n\tlabeledHash, err := lhash.FromBase58(id)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\t// compile scheme and public key\n\tc := container.New()\n\tc.AppendAsBlock([]byte(scheme))\n\tc.AppendAsBlock(pubkey)\n\n\t// check if it matches\n\treturn labeledHash.MatchesData(c.CompileData())\n}\n"
  },
  {
    "path": "spn/hub/update_test.go",
    "content": "package hub\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/structures/dsd\"\n)\n\nfunc TestHubUpdate(t *testing.T) {\n\tt.Parallel()\n\n\t// message signing\n\n\ttestData := []byte{0}\n\n\ts1, err := jess.GenerateSignet(\"Ed25519\", 0)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\terr = s1.StoreKey()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tfmt.Printf(\"s1: %+v\\n\", s1)\n\n\ts1e, err := s1.AsRecipient()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\terr = s1e.StoreKey()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\ts1e.ID = createHubID(s1e.Scheme, s1e.Key)\n\ts1.ID = s1e.ID\n\n\tt.Logf(\"generated hub ID: %s\", s1.ID)\n\n\tenv := jess.NewUnconfiguredEnvelope()\n\tenv.SuiteID = jess.SuiteSignV1\n\tenv.Senders = []*jess.Signet{s1}\n\n\ts, err := env.Correspondence(nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tletter, err := s.Close(testData)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// smuggle the key\n\tletter.Keys = append(letter.Keys, &jess.Seal{\n\t\tValue: s1e.Key,\n\t})\n\tt.Logf(\"letter with smuggled key: %+v\", letter)\n\n\t// pack\n\tdata, err := letter.ToDSD(dsd.JSON)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t_, _, _, err = OpenHubMsg(nil, data, \"test\", true) //nolint:dogsled\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "spn/instance.go",
    "content": "package spn\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/base/runtime\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service\"\n\t\"github.com/safing/portmaster/service/core\"\n\t\"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/intel/filterlists\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n\t\"github.com/safing/portmaster/spn/access\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/captain\"\n\t\"github.com/safing/portmaster/spn/crew\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/navigator\"\n\t\"github.com/safing/portmaster/spn/patrol\"\n\t\"github.com/safing/portmaster/spn/ships\"\n\t\"github.com/safing/portmaster/spn/sluice\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\n// Instance is an instance of a Portmaster service.\ntype Instance struct {\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n\n\tshutdownCtx       context.Context\n\tcancelShutdownCtx context.CancelFunc\n\n\tserviceGroup *mgr.Group\n\n\tbinDir  string\n\tdataDir string\n\n\texitCode atomic.Int32\n\n\tbase     *base.Base\n\tdatabase *dbmodule.DBModule\n\tconfig   *config.Config\n\tapi      *api.API\n\tmetrics  *metrics.Metrics\n\truntime  *runtime.Runtime\n\trng      *rng.Rng\n\n\tcore          *core.Core\n\tbinaryUpdates *updates.Updater\n\tintelUpdates  *updates.Updater\n\tgeoip         *geoip.GeoIP\n\tnetenv        *netenv.NetEnv\n\tfilterLists   *filterlists.FilterLists\n\n\taccess    *access.Access\n\tcabin     *cabin.Cabin\n\tnavigator *navigator.Navigator\n\tcaptain   *captain.Captain\n\tcrew      *crew.Crew\n\tdocks     *docks.Docks\n\tpatrol    *patrol.Patrol\n\tships     *ships.Ships\n\tsluice    *sluice.SluiceModule\n\tterminal  *terminal.TerminalModule\n\tui        *ui.UI\n\n\tCommandLineOperation func() error\n\tShouldRestart        bool\n}\n\n// New returns a new Portmaster service instance.\nfunc New(svcCfg *service.ServiceConfig) (*Instance, error) {\n\t// Initialize config.\n\terr := svcCfg.Init()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"internal service config error: %w\", err)\n\t}\n\n\t// Make sure data dir exists, so that child directories don't dictate the permissions.\n\terr = utils.EnsureDirectory(svcCfg.DataDir, utils.PublicReadExecPermission)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"data directory %s is not accessible: %w\", svcCfg.DataDir, err)\n\t}\n\n\t// Create instance to pass it to modules.\n\tinstance := &Instance{\n\t\tbinDir:  svcCfg.BinDir,\n\t\tdataDir: svcCfg.DataDir,\n\t}\n\tinstance.ctx, instance.cancelCtx = context.WithCancel(context.Background())\n\tinstance.shutdownCtx, instance.cancelShutdownCtx = context.WithCancel(context.Background())\n\n\t// Base modules\n\tinstance.base, err = base.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create base module: %w\", err)\n\t}\n\tinstance.database, err = dbmodule.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create database module: %w\", err)\n\t}\n\tinstance.config, err = config.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create config module: %w\", err)\n\t}\n\tinstance.api, err = api.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create api module: %w\", err)\n\t}\n\tinstance.metrics, err = metrics.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create metrics module: %w\", err)\n\t}\n\tinstance.runtime, err = runtime.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create runtime module: %w\", err)\n\t}\n\tinstance.rng, err = rng.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create rng module: %w\", err)\n\t}\n\n\t// Service modules\n\tbinaryUpdateConfig, intelUpdateConfig, err := service.MakeUpdateConfigs(svcCfg)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create updates config: %w\", err)\n\t}\n\n\t//Enable autodownload and autoapply\n\tbinaryUpdateConfig.AutoDownload = true\n\tbinaryUpdateConfig.AutoApply = true\n\n\tinstance.binaryUpdates, err = updates.New(instance, \"Binary Updater\", *binaryUpdateConfig)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create updates module: %w\", err)\n\t}\n\tinstance.intelUpdates, err = updates.New(instance, \"Intel Updater\", *intelUpdateConfig)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create updates module: %w\", err)\n\t}\n\tinstance.core, err = core.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create core module: %w\", err)\n\t}\n\tinstance.geoip, err = geoip.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create customlist module: %w\", err)\n\t}\n\tinstance.netenv, err = netenv.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create netenv module: %w\", err)\n\t}\n\tinstance.filterLists, err = filterlists.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create filterLists module: %w\", err)\n\t}\n\n\t// SPN modules\n\tinstance.access, err = access.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create access module: %w\", err)\n\t}\n\tinstance.cabin, err = cabin.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create cabin module: %w\", err)\n\t}\n\tinstance.navigator, err = navigator.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create navigator module: %w\", err)\n\t}\n\tinstance.crew, err = crew.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create crew module: %w\", err)\n\t}\n\tinstance.docks, err = docks.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create docks module: %w\", err)\n\t}\n\tinstance.patrol, err = patrol.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create patrol module: %w\", err)\n\t}\n\tinstance.ships, err = ships.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create ships module: %w\", err)\n\t}\n\tinstance.sluice, err = sluice.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create sluice module: %w\", err)\n\t}\n\tinstance.terminal, err = terminal.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create terminal module: %w\", err)\n\t}\n\tinstance.captain, err = captain.New(instance)\n\tif err != nil {\n\t\treturn instance, fmt.Errorf(\"create captain module: %w\", err)\n\t}\n\n\t// Add all modules to instance group.\n\tinstance.serviceGroup = mgr.NewGroup(\n\t\tinstance.base,\n\t\tinstance.database,\n\t\tinstance.config,\n\t\tinstance.api,\n\t\tinstance.metrics,\n\t\tinstance.runtime,\n\t\tinstance.rng,\n\n\t\tinstance.core,\n\t\tinstance.binaryUpdates,\n\t\tinstance.intelUpdates,\n\t\tinstance.geoip,\n\t\tinstance.netenv,\n\n\t\tinstance.access,\n\t\tinstance.cabin,\n\t\tinstance.navigator,\n\t\tinstance.captain,\n\t\tinstance.crew,\n\t\tinstance.docks,\n\t\tinstance.patrol,\n\t\tinstance.ships,\n\t\tinstance.sluice,\n\t\tinstance.terminal,\n\t)\n\n\treturn instance, nil\n}\n\n// AddModule validates the given module and adds it to the service group, if all requirements are met.\n// All modules must be added before anything is done with the instance.\nfunc (i *Instance) AddModule(m mgr.Module) {\n\ti.serviceGroup.Add(m)\n}\n\n// SleepyModule is an interface for modules that can enter some sort of sleep mode.\ntype SleepyModule interface {\n\tSetSleep(enabled bool)\n}\n\n// SetSleep sets sleep mode on all modules that satisfy the SleepyModule interface.\nfunc (i *Instance) SetSleep(enabled bool) {\n\tfor _, module := range i.serviceGroup.Modules() {\n\t\tif sm, ok := module.(SleepyModule); ok {\n\t\t\tsm.SetSleep(enabled)\n\t\t}\n\t}\n}\n\n// BinDir returns the directory for binaries.\n// This directory may be read-only.\nfunc (i *Instance) BinDir() string {\n\treturn i.binDir\n}\n\n// DataDir returns the directory for variable data.\n// This directory is expected to be read/writeable.\nfunc (i *Instance) DataDir() string {\n\treturn i.dataDir\n}\n\n// Database returns the database module.\nfunc (i *Instance) Database() *dbmodule.DBModule {\n\treturn i.database\n}\n\n// Config returns the config module.\nfunc (i *Instance) Config() *config.Config {\n\treturn i.config\n}\n\n// API returns the api module.\nfunc (i *Instance) API() *api.API {\n\treturn i.api\n}\n\n// Metrics returns the metrics module.\nfunc (i *Instance) Metrics() *metrics.Metrics {\n\treturn i.metrics\n}\n\n// Runtime returns the runtime module.\nfunc (i *Instance) Runtime() *runtime.Runtime {\n\treturn i.runtime\n}\n\n// Rng returns the rng module.\nfunc (i *Instance) Rng() *rng.Rng {\n\treturn i.rng\n}\n\n// Base returns the base module.\nfunc (i *Instance) Base() *base.Base {\n\treturn i.base\n}\n\n// BinaryUpdates returns the updates module.\nfunc (i *Instance) BinaryUpdates() *updates.Updater {\n\treturn i.binaryUpdates\n}\n\n// IntelUpdates returns the updates module.\nfunc (i *Instance) IntelUpdates() *updates.Updater {\n\treturn i.intelUpdates\n}\n\n// GeoIP returns the geoip module.\nfunc (i *Instance) GeoIP() *geoip.GeoIP {\n\treturn i.geoip\n}\n\n// NetEnv returns the netenv module.\nfunc (i *Instance) NetEnv() *netenv.NetEnv {\n\treturn i.netenv\n}\n\n// Access returns the access module.\nfunc (i *Instance) Access() *access.Access {\n\treturn i.access\n}\n\n// Cabin returns the cabin module.\nfunc (i *Instance) Cabin() *cabin.Cabin {\n\treturn i.cabin\n}\n\n// Captain returns the captain module.\nfunc (i *Instance) Captain() *captain.Captain {\n\treturn i.captain\n}\n\n// Crew returns the crew module.\nfunc (i *Instance) Crew() *crew.Crew {\n\treturn i.crew\n}\n\n// Docks returns the crew module.\nfunc (i *Instance) Docks() *docks.Docks {\n\treturn i.docks\n}\n\n// Navigator returns the navigator module.\nfunc (i *Instance) Navigator() *navigator.Navigator {\n\treturn i.navigator\n}\n\n// Patrol returns the patrol module.\nfunc (i *Instance) Patrol() *patrol.Patrol {\n\treturn i.patrol\n}\n\n// Ships returns the ships module.\nfunc (i *Instance) Ships() *ships.Ships {\n\treturn i.ships\n}\n\n// Sluice returns the ships module.\nfunc (i *Instance) Sluice() *sluice.SluiceModule {\n\treturn i.sluice\n}\n\n// Terminal returns the terminal module.\nfunc (i *Instance) Terminal() *terminal.TerminalModule {\n\treturn i.terminal\n}\n\n// UI returns the ui module.\nfunc (i *Instance) UI() *ui.UI {\n\treturn i.ui\n}\n\n// FilterLists returns the filterLists module.\nfunc (i *Instance) FilterLists() *filterlists.FilterLists {\n\treturn i.filterLists\n}\n\n// Core returns the core module.\nfunc (i *Instance) Core() *core.Core {\n\treturn i.core\n}\n\n// Events\n\n// GetEventSPNConnected return the event manager for the SPN connected event.\nfunc (i *Instance) GetEventSPNConnected() *mgr.EventMgr[struct{}] {\n\treturn i.captain.EventSPNConnected\n}\n\n// Special functions\n\n// SetCmdLineOperation sets a command line operation to be executed instead of starting the system. This is useful when functions need all modules to be prepared for a special operation.\nfunc (i *Instance) SetCmdLineOperation(f func() error) {\n\ti.CommandLineOperation = f\n}\n\n// GetStates returns the current states of all group modules.\nfunc (i *Instance) GetStates() []mgr.StateUpdate {\n\treturn i.serviceGroup.GetStates()\n}\n\n// AddStatesCallback adds the given callback function to all group modules that\n// expose a state manager at States().\nfunc (i *Instance) AddStatesCallback(callbackName string, callback mgr.EventCallbackFunc[mgr.StateUpdate]) {\n\ti.serviceGroup.AddStatesCallback(callbackName, callback)\n}\n\n// Ready returns whether all modules in the main service module group have been started and are still running.\nfunc (i *Instance) Ready() bool {\n\treturn i.serviceGroup.Ready()\n}\n\n// Start starts the instance.\nfunc (i *Instance) Start() error {\n\treturn i.serviceGroup.Start()\n}\n\n// Stop stops the instance and cancels the instance context when done.\nfunc (i *Instance) Stop() error {\n\treturn i.serviceGroup.Stop()\n}\n\n// RestartExitCode will instruct portmaster-start to restart the process immediately, potentially with a new version.\nconst RestartExitCode = 23\n\n// Restart asynchronously restarts the instance.\n// This only works if the underlying system/process supports this.\nfunc (i *Instance) Restart() {\n\t// Send a restart event, give it 10ms extra to propagate.\n\ti.core.EventRestart.Submit(struct{}{})\n\ttime.Sleep(10 * time.Millisecond)\n\n\t// Set the restart flag and shutdown.\n\ti.ShouldRestart = true\n\ti.shutdown(RestartExitCode)\n}\n\n// Shutdown asynchronously stops the instance.\nfunc (i *Instance) Shutdown() {\n\t// Send a shutdown event, give it 10ms extra to propagate.\n\ti.core.EventShutdown.Submit(struct{}{})\n\ttime.Sleep(10 * time.Millisecond)\n\n\ti.shutdown(0)\n}\n\nfunc (i *Instance) shutdown(exitCode int) {\n\t// Only shutdown once.\n\tif i.IsShuttingDown() {\n\t\treturn\n\t}\n\n\t// Cancel main  context.\n\ti.cancelCtx()\n\n\t// Set given exit code.\n\ti.exitCode.Store(int32(exitCode))\n\n\t// Start shutdown asynchronously in a separate manager.\n\tm := mgr.New(\"instance\")\n\tm.Go(\"shutdown\", func(w *mgr.WorkerCtx) error {\n\t\t// Stop all modules.\n\t\tif err := i.Stop(); err != nil {\n\t\t\tw.Error(\"failed to shutdown\", \"err\", err)\n\t\t}\n\n\t\t// Cancel shutdown process context.\n\t\ti.cancelShutdownCtx()\n\t\treturn nil\n\t})\n}\n\n// Ctx returns the instance context.\n// It is canceled when shutdown is started.\nfunc (i *Instance) Ctx() context.Context {\n\treturn i.ctx\n}\n\n// IsShuttingDown returns whether the instance is shutting down.\nfunc (i *Instance) IsShuttingDown() bool {\n\treturn i.ctx.Err() != nil\n}\n\n// ShuttingDown returns a channel that is triggered when the instance starts shutting down.\nfunc (i *Instance) ShuttingDown() <-chan struct{} {\n\treturn i.ctx.Done()\n}\n\n// ShutdownCtx returns the instance shutdown context.\n// It is canceled when shutdown is complete.\nfunc (i *Instance) ShutdownCtx() context.Context {\n\treturn i.shutdownCtx\n}\n\n// IsShutDown returns whether the instance has stopped.\nfunc (i *Instance) IsShutDown() bool {\n\treturn i.shutdownCtx.Err() != nil\n}\n\n// ShutDownComplete returns a channel that is triggered when the instance has shut down.\nfunc (i *Instance) ShutdownComplete() <-chan struct{} {\n\treturn i.shutdownCtx.Done()\n}\n\n// ExitCode returns the set exit code of the instance.\nfunc (i *Instance) ExitCode() int {\n\treturn int(i.exitCode.Load())\n}\n\n// ShouldRestartIsSet returns whether the service/instance should be restarted.\nfunc (i *Instance) ShouldRestartIsSet() bool {\n\treturn i.ShouldRestart\n}\n\n// CommandLineOperationIsSet returns whether the command line option is set.\nfunc (i *Instance) CommandLineOperationIsSet() bool {\n\treturn i.CommandLineOperation != nil\n}\n\n// CommandLineOperationExecute executes the set command line option.\nfunc (i *Instance) CommandLineOperationExecute() error {\n\treturn i.CommandLineOperation()\n}\n\n// SPNGroup fakes interface conformance.\n// SPNGroup is only needed on SPN clients.\nfunc (i *Instance) SPNGroup() *mgr.ExtendedGroup {\n\treturn nil\n}\n\n// Unsupported Modules.\n\n// Notifications returns nil.\nfunc (i *Instance) Notifications() *notifications.Notifications { return nil }\n"
  },
  {
    "path": "spn/navigator/api.go",
    "content": "package navigator\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\t\"github.com/awalterschulze/gographviz\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nvar (\n\tapiMapsLock sync.Mutex\n\tapiMaps     = make(map[string]*Map)\n)\n\nfunc addMapToAPI(m *Map) {\n\tapiMapsLock.Lock()\n\tdefer apiMapsLock.Unlock()\n\n\tapiMaps[m.Name] = m\n}\n\nfunc getMapForAPI(name string) (m *Map, ok bool) {\n\tapiMapsLock.Lock()\n\tdefer apiMapsLock.Unlock()\n\n\tm, ok = apiMaps[name]\n\treturn\n}\n\nfunc removeMapFromAPI(name string) {\n\tapiMapsLock.Lock()\n\tdefer apiMapsLock.Unlock()\n\n\tdelete(apiMaps, name)\n}\n\nfunc registerAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/pins`,\n\t\tRead:        api.PermitUser,\n\t\tStructFunc:  handleMapPinsRequest,\n\t\tName:        \"Get SPN map pins\",\n\t\tDescription: \"Returns a list of pins on the map.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/intel/update`,\n\t\tWrite:       api.PermitSelf,\n\t\tActionFunc:  handleIntelUpdateRequest,\n\t\tName:        \"Update map intelligence.\",\n\t\tDescription: \"Updates the intel data of the map.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/optimization`,\n\t\tRead:        api.PermitUser,\n\t\tStructFunc:  handleMapOptimizationRequest,\n\t\tName:        \"Get SPN map optimization\",\n\t\tDescription: \"Returns the calculated optimization for the map.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/optimization/table`,\n\t\tRead:        api.PermitUser,\n\t\tDataFunc:    handleMapOptimizationTableRequest,\n\t\tName:        \"Get SPN map optimization as a table\",\n\t\tDescription: \"Returns the calculated optimization for the map as a table.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/measurements`,\n\t\tRead:        api.PermitUser,\n\t\tStructFunc:  handleMapMeasurementsRequest,\n\t\tName:        \"Get SPN map measurements\",\n\t\tDescription: \"Returns the measurements of the map.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/measurements/table`,\n\t\tMimeType:    api.MimeTypeText,\n\t\tRead:        api.PermitUser,\n\t\tDataFunc:    handleMapMeasurementsTableRequest,\n\t\tName:        \"Get SPN map measurements as a table\",\n\t\tDescription: \"Returns the measurements of the map as a table.\",\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/graph{format:\\.[a-z]{2,4}}`,\n\t\tRead:        api.PermitUser,\n\t\tHandlerFunc: handleMapGraphRequest,\n\t\tName:        \"Get SPN map graph\",\n\t\tDescription: \"Returns a graph of the given SPN map.\",\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"map (in path)\",\n\t\t\t\tValue:       \"name of map\",\n\t\t\t\tDescription: \"Specify the map you want to get the map for. The main map is called `main`.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"format (in path)\",\n\t\t\t\tValue:       \"file type\",\n\t\t\t\tDescription: \"Specify the format you want to get the map in. Available values: `dot`, `html`. Please note that the html format is only available in development mode.\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\t// Register API endpoints from other files.\n\tif err := registerRouteAPIEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleMapPinsRequest(ar *api.Request) (i interface{}, err error) {\n\t// Get map.\n\tm, ok := getMapForAPI(ar.URLVars[\"map\"])\n\tif !ok {\n\t\treturn nil, errors.New(\"map not found\")\n\t}\n\n\t// Export all pins.\n\tsortedPins := m.sortedPins(true)\n\texportedPins := make([]*PinExport, len(sortedPins))\n\tfor key, pin := range sortedPins {\n\t\texportedPins[key] = pin.Export()\n\t}\n\n\treturn exportedPins, nil\n}\n\nfunc handleIntelUpdateRequest(ar *api.Request) (msg string, err error) {\n\t// Get map.\n\tm, ok := getMapForAPI(ar.URLVars[\"map\"])\n\tif !ok {\n\t\treturn \"\", errors.New(\"map not found\")\n\t}\n\n\t// Parse new intel data.\n\tnewIntel, err := hub.ParseIntel(ar.InputData)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to parse intel data: %w\", err)\n\t}\n\n\t// Apply intel data.\n\terr = m.UpdateIntel(newIntel, cfgOptionTrustNodeNodes())\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to apply intel data: %w\", err)\n\t}\n\n\treturn \"successfully applied given intel data\", nil\n}\n\nfunc handleMapOptimizationRequest(ar *api.Request) (i interface{}, err error) {\n\t// Get map.\n\tm, ok := getMapForAPI(ar.URLVars[\"map\"])\n\tif !ok {\n\t\treturn nil, errors.New(\"map not found\")\n\t}\n\n\treturn m.Optimize(nil)\n}\n\nfunc handleMapOptimizationTableRequest(ar *api.Request) (data []byte, err error) {\n\t// Get map.\n\tm, ok := getMapForAPI(ar.URLVars[\"map\"])\n\tif !ok {\n\t\treturn nil, errors.New(\"map not found\")\n\t}\n\n\t// Get optimization result.\n\tresult, err := m.Optimize(nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Read lock map, as we access pins.\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\t// Get cranes for additional metadata.\n\tassignedCranes := docks.GetAllAssignedCranes()\n\n\t// Write metadata.\n\tbuf := bytes.NewBuffer(nil)\n\tbuf.WriteString(\"Optimization:\\n\")\n\tfmt.Fprintf(buf, \"Purpose: %s\\n\", result.Purpose)\n\tif len(result.Approach) == 1 {\n\t\tfmt.Fprintf(buf, \"Approach: %s\\n\", result.Approach[0])\n\t} else if len(result.Approach) > 1 {\n\t\tbuf.WriteString(\"Approach:\\n\")\n\t\tfor _, approach := range result.Approach {\n\t\t\tfmt.Fprintf(buf, \"  - %s\\n\", approach)\n\t\t}\n\t}\n\tfmt.Fprintf(buf, \"MaxConnect: %d\\n\", result.MaxConnect)\n\tfmt.Fprintf(buf, \"StopOthers: %v\\n\", result.StopOthers)\n\n\t// Build table of suggested connections.\n\tbuf.WriteString(\"\\nSuggested Connections:\\n\")\n\ttabWriter := tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)\n\tfmt.Fprint(tabWriter, \"Hub Name\\tReason\\tDuplicate\\tCountry\\tRegion\\tLatency\\tCapacity\\tCost\\tGeo Prox.\\tHub ID\\tLifetime Usage\\tPeriod Usage\\tProt\\tStatus\\n\")\n\tfor _, suggested := range result.SuggestedConnections {\n\t\tvar dupe string\n\t\tif suggested.Duplicate {\n\t\t\tdupe = \"yes\"\n\t\t} else {\n\t\t\t// Only lock dupes once.\n\t\t\tsuggested.pin.measurements.Lock()\n\t\t\tdefer suggested.pin.measurements.Unlock()\n\t\t}\n\n\t\t// Add row.\n\t\tfmt.Fprintf(tabWriter,\n\t\t\t\"%s\\t%s\\t%s\\t%s\\t%s\\t%s\\t%.2fMbit/s\\t%.2fc\\t%.2f%%\\t%s\",\n\t\t\tsuggested.Hub.Info.Name,\n\t\t\tsuggested.Reason,\n\t\t\tdupe,\n\t\t\tgetPinCountry(suggested.pin),\n\t\t\tsuggested.pin.region.getName(),\n\t\t\tsuggested.pin.measurements.Latency,\n\t\t\tfloat64(suggested.pin.measurements.Capacity)/1000000,\n\t\t\tsuggested.pin.measurements.CalculatedCost,\n\t\t\tsuggested.pin.measurements.GeoProximity,\n\t\t\tsuggested.Hub.ID,\n\t\t)\n\n\t\t// Add usage stats.\n\t\tif crane, ok := assignedCranes[suggested.Hub.ID]; ok {\n\t\t\taddUsageStatsToTable(crane, tabWriter)\n\t\t}\n\n\t\t// Add linebreak.\n\t\tfmt.Fprint(tabWriter, \"\\n\")\n\t}\n\t_ = tabWriter.Flush()\n\n\treturn buf.Bytes(), nil\n}\n\n// addUsageStatsToTable compiles some usage stats of a lane and addes them to the table.\n// Table Fields: Lifetime Usage, Period Usage, Prot, Mine.\nfunc addUsageStatsToTable(crane *docks.Crane, tabWriter *tabwriter.Writer) {\n\tltIn, ltOut, ltStart, pIn, pOut, pStart := crane.NetState.GetTrafficStats()\n\tltDuration := time.Since(ltStart)\n\tpDuration := time.Since(pStart)\n\n\t// Build ownership and stopping info.\n\tvar status string\n\tisMine := crane.IsMine()\n\tisStopping := crane.IsStopping()\n\tstoppingRequested, stoppingRequestedByPeer, markedStoppingAt := crane.NetState.StoppingState()\n\tif isMine {\n\t\tstatus = \"mine\"\n\t}\n\tif isStopping || stoppingRequested || stoppingRequestedByPeer {\n\t\tif isMine {\n\t\t\tstatus += \" - \"\n\t\t}\n\t\tstatus += \"stopping \"\n\t\tif stoppingRequested {\n\t\t\tstatus += \"<r\"\n\t\t}\n\t\tif isStopping {\n\t\t\tstatus += \"!\"\n\t\t}\n\t\tif stoppingRequestedByPeer {\n\t\t\tstatus += \"r>\"\n\t\t}\n\t\tif isStopping && !markedStoppingAt.IsZero() {\n\t\t\tstatus += \" since \" + markedStoppingAt.Truncate(time.Minute).String()\n\t\t}\n\t}\n\n\tfmt.Fprintf(tabWriter,\n\t\t\"\\t%.2fGB %.2fMbit/s %.2f%%out since %s\\t%.2fGB %.2fMbit/s %.2f%%out since %s\\t%s\\t%s\",\n\t\tfloat64(ltIn+ltOut)/1000000000,\n\t\t(float64(ltIn+ltOut)/1000000/ltDuration.Seconds())*8,\n\t\tfloat64(ltOut)/float64(ltIn+ltOut)*100,\n\t\tltDuration.Truncate(time.Second),\n\t\tfloat64(pIn+pOut)/1000000000,\n\t\t(float64(pIn+pOut)/1000000/pDuration.Seconds())*8,\n\t\tfloat64(pOut)/float64(pIn+pOut)*100,\n\t\tpDuration.Truncate(time.Second),\n\t\tcrane.Transport().Protocol,\n\t\tstatus,\n\t)\n}\n\nfunc handleMapMeasurementsRequest(ar *api.Request) (i interface{}, err error) {\n\t// Get map.\n\tm, ok := getMapForAPI(ar.URLVars[\"map\"])\n\tif !ok {\n\t\treturn nil, errors.New(\"map not found\")\n\t}\n\n\t// Get and sort pins.\n\tlist := m.pinList(true)\n\tsort.Sort(sortByLowestMeasuredCost(list))\n\n\t// Copy data and return.\n\tmeasurements := make([]*hub.Measurements, 0, len(list))\n\tfor _, pin := range list {\n\t\tmeasurements = append(measurements, pin.measurements.Copy())\n\t}\n\treturn measurements, nil\n}\n\nfunc handleMapMeasurementsTableRequest(ar *api.Request) (data []byte, err error) {\n\t// Get map.\n\tm, ok := getMapForAPI(ar.URLVars[\"map\"])\n\tif !ok {\n\t\treturn nil, errors.New(\"map not found\")\n\t}\n\tmatcher := m.DefaultOptions().Transit.Matcher(m.GetIntel())\n\n\t// Get and sort pins.\n\tlist := m.pinList(true)\n\tsort.Sort(sortByLowestMeasuredCost(list))\n\n\t// Get cranes for usage stats.\n\tassignedCranes := docks.GetAllAssignedCranes()\n\n\t// Build table and return.\n\tbuf := bytes.NewBuffer(nil)\n\ttabWriter := tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)\n\tfmt.Fprint(tabWriter, \"Hub Name\\tCountry\\tRegion\\tLatency\\tCapacity\\tCost\\tGeo Prox.\\tHub ID\\tLifetime Usage\\tPeriod Usage\\tProt\\tStatus\\n\")\n\tfor _, pin := range list {\n\t\t// Only print regarded Hubs.\n\t\tif !matcher(pin) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Add row.\n\t\tpin.measurements.Lock()\n\t\tdefer pin.measurements.Unlock()\n\t\tfmt.Fprintf(tabWriter,\n\t\t\t\"%s\\t%s\\t%s\\t%s\\t%.2fMbit/s\\t%.2fc\\t%.2f%%\\t%s\",\n\t\t\tpin.Hub.Info.Name,\n\t\t\tgetPinCountry(pin),\n\t\t\tpin.region.getName(),\n\t\t\tpin.measurements.Latency,\n\t\t\tfloat64(pin.measurements.Capacity)/1000000,\n\t\t\tpin.measurements.CalculatedCost,\n\t\t\tpin.measurements.GeoProximity,\n\t\t\tpin.Hub.ID,\n\t\t)\n\n\t\t// Add usage stats.\n\t\tif crane, ok := assignedCranes[pin.Hub.ID]; ok {\n\t\t\taddUsageStatsToTable(crane, tabWriter)\n\t\t}\n\n\t\t// Add linebreak.\n\t\tfmt.Fprint(tabWriter, \"\\n\")\n\t}\n\t_ = tabWriter.Flush()\n\n\treturn buf.Bytes(), nil\n}\n\nfunc getPinCountry(pin *Pin) string {\n\tswitch {\n\tcase pin.LocationV4 != nil && pin.LocationV4.Country.Code != \"\":\n\t\treturn pin.LocationV4.Country.Code\n\tcase pin.LocationV6 != nil && pin.LocationV6.Country.Code != \"\":\n\t\treturn pin.LocationV6.Country.Code\n\tcase pin.EntityV4 != nil && pin.EntityV4.Country != \"\":\n\t\treturn pin.EntityV4.Country\n\tcase pin.EntityV6 != nil && pin.EntityV6.Country != \"\":\n\t\treturn pin.EntityV6.Country\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc handleMapGraphRequest(w http.ResponseWriter, hr *http.Request) {\n\tr := api.GetAPIRequest(hr)\n\tif r == nil {\n\t\thttp.Error(w, \"API request invalid.\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Get map.\n\tm, ok := getMapForAPI(r.URLVars[\"map\"])\n\tif !ok {\n\t\thttp.Error(w, \"Map not found.\", http.StatusNotFound)\n\t\treturn\n\t}\n\n\t// Check format.\n\tvar format string\n\tswitch r.URLVars[\"format\"] {\n\tcase \".dot\":\n\t\tformat = \"dot\"\n\tcase \".html\":\n\t\tformat = \"html\"\n\n\t\t// Check if we are in dev mode.\n\t\tif !devMode() {\n\t\t\thttp.Error(w, \"Graph html formatting (js rendering) is only available in dev mode.\", http.StatusPreconditionFailed)\n\t\t\treturn\n\t\t}\n\tdefault:\n\t\thttp.Error(w, \"Unsupported format.\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Build graph.\n\tgraph := gographviz.NewGraph()\n\t_ = graph.AddAttr(\"\", \"overlap\", \"scale\")\n\t_ = graph.AddAttr(\"\", \"center\", \"true\")\n\t_ = graph.AddAttr(\"\", \"ratio\", \"fill\")\n\tfor _, pin := range m.sortedPins(true) {\n\t\t_ = graph.AddNode(\"\", pin.Hub.ID, map[string]string{\n\t\t\t\"label\":     graphNodeLabel(pin),\n\t\t\t\"tooltip\":   graphNodeTooltip(pin),\n\t\t\t\"color\":     graphNodeBorderColor(pin),\n\t\t\t\"fillcolor\": graphNodeColor(pin),\n\t\t\t\"shape\":     \"circle\",\n\t\t\t\"style\":     \"filled\",\n\t\t\t\"fontsize\":  \"20\",\n\t\t\t\"penwidth\":  \"4\",\n\t\t\t\"margin\":    \"0\",\n\t\t})\n\t\tfor _, lane := range pin.ConnectedTo {\n\t\t\tif graph.IsNode(lane.Pin.Hub.ID) && pin.State != StateNone {\n\t\t\t\t// Create attributes.\n\t\t\t\tedgeOptions := map[string]string{\n\t\t\t\t\t\"tooltip\":  graphEdgeTooltip(pin, lane.Pin, lane),\n\t\t\t\t\t\"color\":    graphEdgeColor(pin, lane.Pin, lane),\n\t\t\t\t\t\"len\":      fmt.Sprintf(\"%f\", lane.Latency.Seconds()*200),\n\t\t\t\t\t\"penwidth\": fmt.Sprintf(\"%f\", math.Sqrt(float64(lane.Capacity)/1000000)*2),\n\t\t\t\t}\n\t\t\t\t// Add edge.\n\t\t\t\t_ = graph.AddEdge(pin.Hub.ID, lane.Pin.Hub.ID, false, edgeOptions)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar mimeType string\n\tvar responseData []byte\n\tswitch format {\n\tcase \"dot\":\n\t\tmimeType = \"text/x-dot\"\n\t\tresponseData = []byte(graph.String())\n\tcase \"html\":\n\t\tmimeType = \"text/html\"\n\t\tresponseData = []byte(fmt.Sprintf(\n\t\t\t`<!DOCTYPE html><html><meta charset=\"utf-8\"><body style=\"margin:0;padding:0;\">\n<style>#graph svg {height: 99.5vh; width: 99.5vw;}</style>\n<div id=\"graph\"></div>\n<script src=\"/assets/vendor/js/hpcc-js-wasm-1.13.0/index.min.js\"></script>\n<script src=\"/assets/vendor/js/d3-7.3.0/d3.min.js\"></script>\n<script src=\"/assets/vendor/js/d3-graphviz-4.1.0/d3-graphviz.min.js\"></script>\n<script>\nd3.select(\"#graph\").graphviz(useWorker=false).engine(\"neato\").renderDot(%s%s%s);\n</script>\n</body></html>`,\n\t\t\t\"`\", graph.String(), \"`\",\n\t\t))\n\t}\n\n\t// Write response.\n\tw.Header().Set(\"Content-Type\", mimeType+\"; charset=utf-8\")\n\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(responseData)))\n\tw.WriteHeader(http.StatusOK)\n\t_, err := w.Write(responseData)\n\tif err != nil {\n\t\tlog.Tracer(r.Context()).Warningf(\"api: failed to write response: %s\", err)\n\t}\n}\n\nfunc graphNodeLabel(pin *Pin) (s string) {\n\tvar comment string\n\tswitch {\n\tcase pin.State == StateNone:\n\t\tcomment = \"dead\"\n\tcase pin.State.Has(StateIsHomeHub):\n\t\tcomment = \"Home\"\n\tcase pin.State.HasAnyOf(StateSummaryDisregard):\n\t\tcomment = \"disregarded\"\n\tcase !pin.State.Has(StateSummaryRegard):\n\t\tcomment = \"not regarded\"\n\tcase pin.State.Has(StateTrusted):\n\t\tcomment = \"trusted\"\n\t}\n\tif comment != \"\" {\n\t\tcomment = fmt.Sprintf(\"\\n(%s)\", comment)\n\t}\n\n\tif pin.Hub.Status.Load >= 80 {\n\t\tcomment += fmt.Sprintf(\"\\nHIGH LOAD: %d\", pin.Hub.Status.Load)\n\t}\n\n\treturn fmt.Sprintf(\n\t\t`\"%s%s\"`,\n\t\tstrings.ReplaceAll(pin.Hub.Name(), \" \", \"\\n\"),\n\t\tcomment,\n\t)\n}\n\nfunc graphNodeTooltip(pin *Pin) string {\n\t// Gather IP info.\n\tvar v4Info, v6Info string\n\tif pin.Hub.Info.IPv4 != nil {\n\t\tif pin.LocationV4 != nil {\n\t\t\tv4Info = fmt.Sprintf(\n\t\t\t\t\"%s (%s AS%d %s)\",\n\t\t\t\tpin.Hub.Info.IPv4.String(),\n\t\t\t\tpin.LocationV4.Country.Code,\n\t\t\t\tpin.LocationV4.AutonomousSystemNumber,\n\t\t\t\tpin.LocationV4.AutonomousSystemOrganization,\n\t\t\t)\n\t\t} else {\n\t\t\tv4Info = pin.Hub.Info.IPv4.String()\n\t\t}\n\t}\n\tif pin.Hub.Info.IPv6 != nil {\n\t\tif pin.LocationV6 != nil {\n\t\t\tv6Info = fmt.Sprintf(\n\t\t\t\t\"%s (%s AS%d %s)\",\n\t\t\t\tpin.Hub.Info.IPv6.String(),\n\t\t\t\tpin.LocationV6.Country.Code,\n\t\t\t\tpin.LocationV6.AutonomousSystemNumber,\n\t\t\t\tpin.LocationV6.AutonomousSystemOrganization,\n\t\t\t)\n\t\t} else {\n\t\t\tv6Info = pin.Hub.Info.IPv6.String()\n\t\t}\n\t}\n\n\treturn fmt.Sprintf(\n\t\t`\"ID: %s\nStates: %s\nVersion: %s\nIPv4: %s\nIPv6: %s\nLoad: %d\nCost: %.2f\"`,\n\t\tpin.Hub.ID,\n\t\tpin.State,\n\t\tpin.Hub.Status.Version,\n\t\tv4Info,\n\t\tv6Info,\n\t\tpin.Hub.Status.Load,\n\t\tpin.Cost,\n\t)\n}\n\nfunc graphEdgeTooltip(from, to *Pin, lane *Lane) string {\n\treturn fmt.Sprintf(\n\t\t`\"%s <> %s\nLatency: %s\nCapacity: %.2f Mbit/s\nCost: %.2f\"`,\n\t\tfrom.Hub.Info.Name, to.Hub.Info.Name,\n\t\tlane.Latency,\n\t\tfloat64(lane.Capacity)/1000000,\n\t\tlane.Cost,\n\t)\n}\n\n// Graphviz colors.\n// See https://graphviz.org/doc/info/colors.html\nconst (\n\tgraphColorWarning          = \"orange2\"\n\tgraphColorError            = \"red2\"\n\tgraphColorHomeAndConnected = \"steelblue2\"\n\tgraphColorDisregard        = \"tomato2\"\n\tgraphColorNotRegard        = \"tan2\"\n\tgraphColorTrusted          = \"seagreen2\"\n\tgraphColorDefaultNode      = \"seashell2\"\n\tgraphColorDefaultEdge      = \"black\"\n\tgraphColorNone             = \"transparent\"\n)\n\nfunc graphNodeColor(pin *Pin) string {\n\tswitch {\n\tcase pin.State == StateNone:\n\t\treturn graphColorNone\n\tcase pin.Hub.Status.Load >= 95:\n\t\treturn graphColorError\n\tcase pin.Hub.Status.Load >= 80:\n\t\treturn graphColorWarning\n\tcase pin.State.Has(StateIsHomeHub):\n\t\treturn graphColorHomeAndConnected\n\tcase pin.State.HasAnyOf(StateSummaryDisregard):\n\t\treturn graphColorDisregard\n\tcase !pin.State.Has(StateSummaryRegard):\n\t\treturn graphColorNotRegard\n\tcase pin.State.Has(StateTrusted):\n\t\treturn graphColorTrusted\n\tdefault:\n\t\treturn graphColorDefaultNode\n\t}\n}\n\nfunc graphNodeBorderColor(pin *Pin) string {\n\tswitch {\n\tcase pin.HasActiveTerminal():\n\t\treturn graphColorHomeAndConnected\n\tdefault:\n\t\treturn graphColorNone\n\t}\n}\n\nfunc graphEdgeColor(from, to *Pin, lane *Lane) string {\n\t// Check lane stats.\n\tif lane.Capacity == 0 || lane.Latency == 0 {\n\t\treturn graphColorWarning\n\t}\n\t// Alert if capacity is under 10Mbit/s or latency is over 100ms.\n\tif lane.Capacity < 10000000 || lane.Latency > 100*time.Millisecond {\n\t\treturn graphColorError\n\t}\n\n\t// Check for active edge forward.\n\tif to.HasActiveTerminal() && len(to.Connection.Route.Path) >= 2 {\n\t\tsecondLastHopIndex := len(to.Connection.Route.Path) - 2\n\t\tif to.Connection.Route.Path[secondLastHopIndex].HubID == from.Hub.ID {\n\t\t\treturn graphColorHomeAndConnected\n\t\t}\n\t}\n\t// Check for active edge backward.\n\tif from.HasActiveTerminal() && len(from.Connection.Route.Path) >= 2 {\n\t\tsecondLastHopIndex := len(from.Connection.Route.Path) - 2\n\t\tif from.Connection.Route.Path[secondLastHopIndex].HubID == to.Hub.ID {\n\t\t\treturn graphColorHomeAndConnected\n\t\t}\n\t}\n\n\t// Return default color if edge is not active.\n\treturn graphColorDefaultEdge\n}\n"
  },
  {
    "path": "spn/navigator/api_route.go",
    "content": "package navigator\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\tmrand \"math/rand\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/network/netutils\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n)\n\nfunc registerRouteAPIEndpoints() error {\n\tif err := api.RegisterEndpoint(api.Endpoint{\n\t\tPath:        `spn/map/{map:[A-Za-z0-9]{1,255}}/route/to/{destination:[a-z0-9_\\.:-]{1,255}}`,\n\t\tRead:        api.PermitUser,\n\t\tActionFunc:  handleRouteCalculationRequest,\n\t\tName:        \"Calculate Route through SPN\",\n\t\tDescription: \"Returns a textual representation of the routing process.\",\n\t\tParameters: []api.Parameter{\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"profile\",\n\t\t\t\tValue:       \"<id>|global\",\n\t\t\t\tDescription: \"Specify a profile ID to load more settings for simulation.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMethod:      http.MethodGet,\n\t\t\t\tField:       \"encrypted\",\n\t\t\t\tValue:       \"true\",\n\t\t\t\tDescription: \"Specify to signify that the simulated connection should be regarded as encrypted. Only valid with a profile.\",\n\t\t\t},\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc handleRouteCalculationRequest(ar *api.Request) (msg string, err error) { //nolint:maintidx\n\t// Get map.\n\tm, ok := getMapForAPI(ar.URLVars[\"map\"])\n\tif !ok {\n\t\treturn \"\", errors.New(\"map not found\")\n\t}\n\t// Get profile ID.\n\tprofileID := ar.Request.URL.Query().Get(\"profile\")\n\n\t// Parse destination and prepare options.\n\tentity := &intel.Entity{}\n\tdestination := ar.URLVars[\"destination\"]\n\tmatchFor := DestinationHub\n\tvar (\n\t\tintroText              string\n\t\tlocationV4, locationV6 *geoip.Location\n\t\topts                   *Options\n\t)\n\tswitch {\n\tcase destination == \"\":\n\t\t// Destination is required.\n\t\treturn \"\", errors.New(\"no destination provided\")\n\n\tcase destination == \"home\":\n\t\tif profileID != \"\" {\n\t\t\treturn \"\", errors.New(\"cannot apply profile to home hub route\")\n\t\t}\n\t\t// Simulate finding home hub.\n\t\tlocations, ok := netenv.GetInternetLocation()\n\t\tif !ok || len(locations.All) == 0 {\n\t\t\treturn \"\", errors.New(\"failed to locate own device for finding home hub\")\n\t\t}\n\t\tintroText = fmt.Sprintf(\"looking for home hub near %s and %s\", locations.BestV4(), locations.BestV6())\n\t\tlocationV4 = locations.BestV4().LocationOrNil()\n\t\tlocationV6 = locations.BestV6().LocationOrNil()\n\t\tmatchFor = HomeHub\n\n\t\t// START of copied from captain/navigation.go\n\n\t\t// Get own entity.\n\t\t// Checking the entity against the entry policies is somewhat hit and miss\n\t\t// anyway, as the device location is an approximation.\n\t\tvar myEntity *intel.Entity\n\t\tif dl := locations.BestV4(); dl != nil && dl.IP != nil {\n\t\t\tmyEntity = (&intel.Entity{IP: dl.IP}).Init(0)\n\t\t\tmyEntity.FetchData(ar.Context())\n\t\t} else if dl := locations.BestV6(); dl != nil && dl.IP != nil {\n\t\t\tmyEntity = (&intel.Entity{IP: dl.IP}).Init(0)\n\t\t\tmyEntity.FetchData(ar.Context())\n\t\t}\n\n\t\t// Build navigation options for searching for a home hub.\n\t\thomePolicy, err := endpoints.ParseEndpoints(config.GetAsStringArray(\"spn/homePolicy\", []string{})())\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to parse home hub policy: %w\", err)\n\t\t}\n\n\t\topts = &Options{\n\t\t\tHome: &HomeHubOptions{\n\t\t\t\tHubPolicies:        []endpoints.Endpoints{homePolicy},\n\t\t\t\tCheckHubPolicyWith: myEntity,\n\t\t\t},\n\t\t}\n\n\t\t// Add requirement to only use Safing nodes when not using community nodes.\n\t\tif !config.GetAsBool(\"spn/useCommunityNodes\", true)() {\n\t\t\topts.Home.RequireVerifiedOwners = []string{\"Safing\"}\n\t\t}\n\n\t\t// Require a trusted home node when the routing profile requires less than two hops.\n\t\troutingProfile := GetRoutingProfile(config.GetAsString(profile.CfgOptionRoutingAlgorithmKey, DefaultRoutingProfileID)())\n\t\tif routingProfile.MinHops < 2 {\n\t\t\topts.Home.Regard = opts.Home.Regard.Add(StateTrusted)\n\t\t}\n\n\t\t// END of copied\n\n\tcase net.ParseIP(destination) != nil:\n\t\tentity.IP = net.ParseIP(destination)\n\n\t\tfallthrough\n\tcase netutils.IsValidFqdn(destination):\n\t\tfallthrough\n\tcase netutils.IsValidFqdn(destination + \".\"):\n\t\t// Resolve domain to IP, if not inherired from a previous case.\n\t\tvar ignoredIPs int\n\t\tif entity.IP == nil {\n\t\t\tentity.Domain = destination\n\n\t\t\t// Resolve name to IPs.\n\t\t\tips, err := net.DefaultResolver.LookupIP(ar.Context(), \"ip\", destination)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to lookup IP address of %s: %w\", destination, err)\n\t\t\t}\n\t\t\tif len(ips) == 0 {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to lookup IP address of %s: no result\", destination)\n\t\t\t}\n\n\t\t\t// Shuffle IPs.\n\t\t\tif len(ips) >= 2 {\n\t\t\t\tmr := mrand.New(mrand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\t\t\t\tmr.Shuffle(len(ips), func(i, j int) {\n\t\t\t\t\tips[i], ips[j] = ips[j], ips[i]\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tentity.IP = ips[0]\n\t\t\tignoredIPs = len(ips) - 1\n\t\t}\n\t\tentity.Init(0)\n\n\t\t// Get location of IP.\n\t\tlocation, ok := entity.GetLocation(ar.Context())\n\t\tif !ok {\n\t\t\treturn \"\", fmt.Errorf(\"failed to get geoip location for %s: %s\", entity.IP, entity.LocationError)\n\t\t}\n\t\t// Assign location to separate variables.\n\t\tif entity.IP.To4() != nil {\n\t\t\tlocationV4 = location\n\t\t} else {\n\t\t\tlocationV6 = location\n\t\t}\n\n\t\t// Set intro text.\n\t\tif entity.Domain != \"\" {\n\t\t\tintroText = fmt.Sprintf(\"looking for route to %s at %s\\n(ignoring %d additional IPs returned by DNS)\", entity.IP, formatLocation(location), ignoredIPs)\n\t\t} else {\n\t\t\tintroText = fmt.Sprintf(\"looking for route to %s at %s\", entity.IP, formatLocation(location))\n\t\t}\n\n\t\t// Get profile.\n\t\tif profileID != \"\" {\n\t\t\tvar lp *profile.LayeredProfile\n\t\t\tif profileID == \"global\" {\n\t\t\t\t// Create new empty profile for easy access to global settings.\n\t\t\t\tlp = profile.NewLayeredProfile(profile.New(nil))\n\t\t\t} else {\n\t\t\t\t// Get local profile by ID.\n\t\t\t\tlocalProfile, err := profile.GetLocalProfile(profileID, nil, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"failed to get profile: %w\", err)\n\t\t\t\t}\n\t\t\t\tlp = localProfile.LayeredProfile()\n\t\t\t}\n\t\t\topts = DeriveTunnelOptions(\n\t\t\t\tlp,\n\t\t\t\tentity,\n\t\t\t\tar.Request.URL.Query().Has(\"encrypted\"),\n\t\t\t)\n\t\t} else {\n\t\t\topts = m.defaultOptions()\n\t\t}\n\n\tdefault:\n\t\treturn \"\", errors.New(\"invalid destination provided\")\n\t}\n\n\t// Finalize entity.\n\tentity.Init(0)\n\n\t// Start formatting output.\n\tlines := []string{\n\t\t\"Routing simulation: \" + introText,\n\t\t\"Please note that this routing simulation does match the behavior of regular routing to 100%.\",\n\t\t\"\",\n\t}\n\n\t// Print options.\n\t// ==================\n\n\tlines = append(lines, \"Routing Options:\")\n\tlines = append(lines, \"Algorithm: \"+opts.RoutingProfile)\n\tif opts.Home != nil {\n\t\tlines = append(lines, \"Home Options:\")\n\t\tlines = append(lines, fmt.Sprintf(\"  Regard: %s\", opts.Home.Regard))\n\t\tlines = append(lines, fmt.Sprintf(\"  Disregard: %s\", opts.Home.Disregard))\n\t\tlines = append(lines, fmt.Sprintf(\"  No Default: %v\", opts.Home.NoDefaults))\n\t\tlines = append(lines, fmt.Sprintf(\"  Hub Policies: %v\", opts.Home.HubPolicies))\n\t\tlines = append(lines, fmt.Sprintf(\"  Require Verified Owners: %v\", opts.Home.RequireVerifiedOwners))\n\t}\n\tif opts.Transit != nil {\n\t\tlines = append(lines, \"Transit Options:\")\n\t\tlines = append(lines, fmt.Sprintf(\"  Regard: %s\", opts.Transit.Regard))\n\t\tlines = append(lines, fmt.Sprintf(\"  Disregard: %s\", opts.Transit.Disregard))\n\t\tlines = append(lines, fmt.Sprintf(\"  No Default: %v\", opts.Transit.NoDefaults))\n\t\tlines = append(lines, fmt.Sprintf(\"  Hub Policies: %v\", opts.Transit.HubPolicies))\n\t\tlines = append(lines, fmt.Sprintf(\"  Require Verified Owners: %v\", opts.Transit.RequireVerifiedOwners))\n\t}\n\tif opts.Destination != nil {\n\t\tlines = append(lines, \"Destination Options:\")\n\t\tlines = append(lines, fmt.Sprintf(\"  Regard: %s\", opts.Destination.Regard))\n\t\tlines = append(lines, fmt.Sprintf(\"  Disregard: %s\", opts.Destination.Disregard))\n\t\tlines = append(lines, fmt.Sprintf(\"  No Default: %v\", opts.Destination.NoDefaults))\n\t\tlines = append(lines, fmt.Sprintf(\"  Hub Policies: %v\", opts.Destination.HubPolicies))\n\t\tlines = append(lines, fmt.Sprintf(\"  Require Verified Owners: %v\", opts.Destination.RequireVerifiedOwners))\n\t\tif opts.Destination.CheckHubPolicyWith != nil {\n\t\t\tlines = append(lines, \"  Check Hub Policy With:\")\n\t\t\tif opts.Destination.CheckHubPolicyWith.Domain != \"\" {\n\t\t\t\tlines = append(lines, fmt.Sprintf(\"    Domain: %v\", opts.Destination.CheckHubPolicyWith.Domain))\n\t\t\t}\n\t\t\tif opts.Destination.CheckHubPolicyWith.IP != nil {\n\t\t\t\tlines = append(lines, fmt.Sprintf(\"    IP: %v\", opts.Destination.CheckHubPolicyWith.IP))\n\t\t\t}\n\t\t\tif opts.Destination.CheckHubPolicyWith.Port != 0 {\n\t\t\t\tlines = append(lines, fmt.Sprintf(\"    Port: %v\", opts.Destination.CheckHubPolicyWith.Port))\n\t\t\t}\n\t\t}\n\t}\n\tlines = append(lines, \"\\n\")\n\n\t// Find nearest hubs.\n\t// ==================\n\n\t// Start operating in map.\n\tm.RLock()\n\tdefer m.RUnlock()\n\t// Check if map is populated.\n\tif m.isEmpty() {\n\t\treturn \"\", ErrEmptyMap\n\t}\n\n\t// Find nearest hubs.\n\tnbPins, err := m.findNearestPins(locationV4, locationV6, opts, matchFor, true)\n\tif err != nil {\n\t\tlines = append(lines, fmt.Sprintf(\"FAILED to find any suitable exit hub: %s\", err))\n\t\treturn strings.Join(lines, \"\\n\"), nil\n\t\t// return \"\", fmt.Errorf(\"failed to search for nearby pins: %w\", err)\n\t}\n\n\t// Print found exits to table.\n\tlines = append(lines, \"Considered Exits (cheapest 10% are shuffled)\")\n\tbuf := bytes.NewBuffer(nil)\n\ttabWriter := tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)\n\tfmt.Fprint(tabWriter, \"Hub Name\\tCost\\tLocation\\n\")\n\tfor _, nbPin := range nbPins.pins {\n\t\tfmt.Fprintf(tabWriter,\n\t\t\t\"%s\\t%.0f\\t%s\\n\",\n\t\t\tnbPin.pin.Hub.Name(),\n\t\t\tnbPin.cost,\n\t\t\tformatMultiLocation(nbPin.pin.LocationV4, nbPin.pin.LocationV6),\n\t\t)\n\t}\n\t_ = tabWriter.Flush()\n\tlines = append(lines, buf.String())\n\n\t// Print too expensive exits to table.\n\tlines = append(lines, \"Too Expensive Exits:\")\n\tbuf = bytes.NewBuffer(nil)\n\ttabWriter = tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)\n\tfmt.Fprint(tabWriter, \"Hub Name\\tCost\\tLocation\\n\")\n\tfor _, nbPin := range nbPins.debug.tooExpensive {\n\t\tfmt.Fprintf(tabWriter,\n\t\t\t\"%s\\t%.0f\\t%s\\n\",\n\t\t\tnbPin.pin.Hub.Name(),\n\t\t\tnbPin.cost,\n\t\t\tformatMultiLocation(nbPin.pin.LocationV4, nbPin.pin.LocationV6),\n\t\t)\n\t}\n\t_ = tabWriter.Flush()\n\tlines = append(lines, buf.String())\n\n\t// Print disregarded exits to table.\n\tlines = append(lines, \"Disregarded Exits:\")\n\tbuf = bytes.NewBuffer(nil)\n\ttabWriter = tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)\n\tfmt.Fprint(tabWriter, \"Hub Name\\tReason\\tStates\\n\")\n\tfor _, nbPin := range nbPins.debug.disregarded {\n\t\tfmt.Fprintf(tabWriter,\n\t\t\t\"%s\\t%s\\t%s\\n\",\n\t\t\tnbPin.pin.Hub.Name(),\n\t\t\tnbPin.reason,\n\t\t\tnbPin.pin.State,\n\t\t)\n\t}\n\t_ = tabWriter.Flush()\n\tlines = append(lines, buf.String())\n\n\t// Find routes.\n\t// ============\n\n\t// Unless we looked for a home node.\n\tif destination == \"home\" {\n\t\treturn strings.Join(lines, \"\\n\"), nil\n\t}\n\n\t// Find routes.\n\troutes, err := m.findRoutes(nbPins, opts)\n\tif err != nil {\n\t\tlines = append(lines, fmt.Sprintf(\"FAILED to find routes: %s\", err))\n\t\treturn strings.Join(lines, \"\\n\"), nil\n\t\t// return \"\", fmt.Errorf(\"failed to find routes: %w\", err)\n\t}\n\n\t// Print found routes to table.\n\tlines = append(lines, \"Considered Routes (cheapest 10% are shuffled)\")\n\tbuf = bytes.NewBuffer(nil)\n\ttabWriter = tabwriter.NewWriter(buf, 8, 4, 3, ' ', 0)\n\tfmt.Fprint(tabWriter, \"Cost\\tPath\\n\")\n\tfor _, route := range routes.All {\n\t\tfmt.Fprintf(tabWriter,\n\t\t\t\"%.0f\\t%s\\n\",\n\t\t\troute.TotalCost,\n\t\t\tformatRoute(route, entity.IP),\n\t\t)\n\t}\n\t_ = tabWriter.Flush()\n\tlines = append(lines, buf.String())\n\n\treturn strings.Join(lines, \"\\n\"), nil\n}\n\nfunc formatLocation(loc *geoip.Location) string {\n\treturn fmt.Sprintf(\n\t\t\"%s (%s - AS%d %s)\",\n\t\tloc.Country.Name,\n\t\tloc.Country.Code,\n\t\tloc.AutonomousSystemNumber,\n\t\tloc.AutonomousSystemOrganization,\n\t)\n}\n\nfunc formatMultiLocation(a, b *geoip.Location) string {\n\tswitch {\n\tcase a != nil:\n\t\treturn formatLocation(a)\n\tcase b != nil:\n\t\treturn formatLocation(b)\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc formatRoute(r *Route, dst net.IP) string {\n\ts := make([]string, 0, len(r.Path)+1)\n\tfor i, hop := range r.Path {\n\t\tif i == 0 {\n\t\t\ts = append(s, hop.pin.Hub.Name())\n\t\t} else {\n\t\t\ts = append(s, fmt.Sprintf(\">> %.2fc >> %s\", hop.Cost, hop.pin.Hub.Name()))\n\t\t}\n\t}\n\ts = append(s, fmt.Sprintf(\">> %.2fc >> %s\", r.DstCost, dst))\n\treturn strings.Join(s, \" \")\n}\n"
  },
  {
    "path": "spn/navigator/costs.go",
    "content": "package navigator\n\nimport \"time\"\n\nconst (\n\tnearestPinsMaxCostDifference = 5000\n\tnearestPinsMinimum           = 10\n)\n\n// CalculateLaneCost calculates the cost of using a Lane based on the given\n// Lane latency and capacity.\n// Ranges from 0 to 10000.\nfunc CalculateLaneCost(latency time.Duration, capacity int) (cost float32) {\n\t// - One point for every ms in latency (linear)\n\tif latency != 0 {\n\t\tcost += float32(latency) / float32(time.Millisecond)\n\t} else {\n\t\t// Add cautious default cost if latency is not available.\n\t\tcost += 1000\n\t}\n\n\tcapacityFloat := float32(capacity)\n\tswitch {\n\tcase capacityFloat == 0:\n\t\t// Add cautious default cost if capacity is not available.\n\t\tcost += 4000\n\tcase capacityFloat < cap1Mbit:\n\t\t// - Between 1000 and 10000 points for ranges below 1Mbit/s\n\t\tcost += 1000 + 9000*((cap1Mbit-capacityFloat)/cap1Mbit)\n\tcase capacityFloat < cap10Mbit:\n\t\t// - Between 100 and 1000 points for ranges below 10Mbit/s\n\t\tcost += 100 + 900*((cap10Mbit-capacityFloat)/cap10Mbit)\n\tcase capacityFloat < cap100Mbit:\n\t\t// - Between 20 and 100 points for ranges below 100Mbit/s\n\t\tcost += 20 + 80*((cap100Mbit-capacityFloat)/cap100Mbit)\n\tcase capacityFloat < cap1Gbit:\n\t\t// - Between 5 and 20 points for ranges below 1Gbit/s\n\t\tcost += 5 + 15*((cap1Gbit-capacityFloat)/cap1Gbit)\n\tcase capacityFloat < cap10Gbit:\n\t\t// - Between 0 and 5 points for ranges below 10Gbit/s\n\t\tcost += 5 * ((cap10Gbit - float32(capacity)) / cap10Gbit)\n\t}\n\n\treturn cost\n}\n\n// CalculateHubCost calculates the cost of using a Hub based on the given Hub load.\n// Ranges from 100 to 10000.\nfunc CalculateHubCost(load int) (cost float32) {\n\tswitch {\n\tcase load >= 100:\n\t\treturn 10000\n\tcase load >= 95:\n\t\treturn 1000\n\tcase load >= 80:\n\t\treturn 500\n\tdefault:\n\t\treturn 100\n\t}\n}\n\n// CalculateDestinationCost calculates the cost of a destination hub to a\n// destination server based on the given proximity.\n// Ranges from 0 to 2500.\nfunc CalculateDestinationCost(proximity float32) (cost float32) {\n\t// Invert from proximity (0-100) to get a distance value.\n\tdistance := 100 - proximity\n\n\t// Take the distance to the power of three and then divide by hundred in order to\n\t// make high distances exponentially more expensive.\n\treturn (distance * distance * distance) / 100\n}\n"
  },
  {
    "path": "spn/navigator/database.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/iterator\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/database/storage\"\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nvar mapDBController *database.Controller\n\n// StorageInterface provices a storage.Interface to the\n// configuration manager.\ntype StorageInterface struct {\n\tstorage.InjectBase\n}\n\n// Database prefixes:\n// Pins:       map:main/<Hub ID>\n// DNS Requests:    network:tree/<PID>/dns/<ID>\n// IP Connections:  network:tree/<PID>/ip/<ID>\n\nfunc makeDBKey(mapName, hubID string) string {\n\treturn fmt.Sprintf(\"map:%s/%s\", mapName, hubID)\n}\n\nfunc parseDBKey(key string) (mapName, hubID string) {\n\t// Split into segments.\n\tsegments := strings.Split(key, \"/\")\n\n\t// Keys have 1 or 2 segments.\n\tswitch len(segments) {\n\tcase 1:\n\t\treturn segments[0], \"\"\n\tcase 2:\n\t\treturn segments[0], segments[1]\n\tdefault:\n\t\treturn \"\", \"\"\n\t}\n}\n\n// Get returns a database record.\nfunc (s *StorageInterface) Get(key string) (record.Record, error) {\n\t// Parse key and check if valid.\n\tmapName, hubID := parseDBKey(key)\n\tif mapName == \"\" || hubID == \"\" {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\t// Get map.\n\tm, ok := getMapForAPI(mapName)\n\tif !ok {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\t// Get Pin from map.\n\tpin, ok := m.GetPin(hubID)\n\tif !ok {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\treturn pin.Export(), nil\n}\n\n// Query returns a an iterator for the supplied query.\nfunc (s *StorageInterface) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {\n\t// Parse key and check if valid.\n\tmapName, _ := parseDBKey(q.DatabaseKeyPrefix())\n\tif mapName == \"\" {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\t// Get map.\n\tm, ok := getMapForAPI(mapName)\n\tif !ok {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\n\t// Start query worker.\n\tit := iterator.New()\n\tmodule.mgr.Go(\"map query\", func(_ *mgr.WorkerCtx) error {\n\t\ts.processQuery(m, q, it)\n\t\treturn nil\n\t})\n\n\treturn it, nil\n}\n\nfunc (s *StorageInterface) processQuery(m *Map, q *query.Query, it *iterator.Iterator) {\n\t// Return all matching pins.\n\tfor _, pin := range m.sortedPins(true) {\n\t\texport := pin.Export()\n\t\tif q.Matches(export) {\n\t\t\tselect {\n\t\t\tcase it.Next <- export:\n\t\t\tcase <-it.Done:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tit.Finish(nil)\n}\n\nfunc registerMapDatabase() error {\n\t_, err := database.Register(&database.Database{\n\t\tName:        \"map\",\n\t\tDescription: \"SPN Network Maps\",\n\t\tStorageType: database.StorageTypeInjected,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontroller, err := database.InjectDatabase(\"map\", &StorageInterface{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmapDBController = controller\n\treturn nil\n}\n\nfunc withdrawMapDatabase() {\n\tmapDBController.Withdraw()\n}\n\n// PushPinChanges pushes all changed pins to subscribers.\nfunc (m *Map) PushPinChanges() {\n\tmodule.mgr.Go(\"push pin changes\", m.pushPinChangesWorker)\n}\n\nfunc (m *Map) pushPinChangesWorker(ctx *mgr.WorkerCtx) error {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\tfor _, pin := range m.all {\n\t\tif pin.pushChanges.SetToIf(true, false) {\n\t\t\tmapDBController.PushUpdate(pin.Export())\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// pushChange pushes changes of the pin, if the pushChanges flag is set.\nfunc (pin *Pin) pushChange() {\n\t// Check before starting the worker.\n\tif pin.pushChanges.IsNotSet() {\n\t\treturn\n\t}\n\n\t// Start worker to push changes.\n\tmodule.mgr.Go(\"push pin change\", func(ctx *mgr.WorkerCtx) error {\n\t\tif pin.pushChanges.SetToIf(true, false) {\n\t\t\tmapDBController.PushUpdate(pin.Export())\n\t\t}\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "spn/navigator/findnearest.go",
    "content": "package navigator\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\tmrand \"math/rand\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nconst (\n\t// defaultMaxNearbyMatches defines a default value of how many matches a\n\t// nearby pin find operation in a map should return.\n\tdefaultMaxNearbyMatches = 100\n\n\t// defaultRandomizeNearbyPinTopPercent defines the top percent of a nearby\n\t// pins set that should be randomized for balancing purposes.\n\t// Range: 0-1.\n\tdefaultRandomizeNearbyPinTopPercent = 0.1\n)\n\n// nearbyPins is a list of nearby Pins to a certain location.\ntype nearbyPins struct {\n\tpins                []*nearbyPin\n\tminPins             int\n\tmaxPins             int\n\tmaxCost             float32\n\tcutOffLimit         float32\n\trandomizeTopPercent float32\n\n\tdebug *nearbyPinsDebug\n}\n\n// nearbyPinsDebug holds additional debugging for nearbyPins.\ntype nearbyPinsDebug struct {\n\ttooExpensive []*nearbyPin\n\tdisregarded  []*nearbyDisregardedPin\n}\n\n// nearbyDisregardedPin represents a disregarded pin.\ntype nearbyDisregardedPin struct {\n\tpin    *Pin\n\treason string\n}\n\n// nearbyPin represents a Pin and the proximity to a certain location.\ntype nearbyPin struct {\n\tpin  *Pin\n\tcost float32\n}\n\n// Len is the number of elements in the collection.\nfunc (nb *nearbyPins) Len() int {\n\treturn len(nb.pins)\n}\n\n// Less reports whether the element with index i should sort before the element\n// with index j.\nfunc (nb *nearbyPins) Less(i, j int) bool {\n\treturn nb.pins[i].cost < nb.pins[j].cost\n}\n\n// Swap swaps the elements with indexes i and j.\nfunc (nb *nearbyPins) Swap(i, j int) {\n\tnb.pins[i], nb.pins[j] = nb.pins[j], nb.pins[i]\n}\n\n// add potentially adds a Pin to the list of nearby Pins.\nfunc (nb *nearbyPins) add(pin *Pin, cost float32) {\n\tif len(nb.pins) > nb.minPins && nb.maxCost > 0 && cost > nb.maxCost {\n\t\t// Add debug data if enabled.\n\t\tif nb.debug != nil {\n\t\t\tnb.debug.tooExpensive = append(nb.debug.tooExpensive,\n\t\t\t\t&nearbyPin{\n\t\t\t\t\tpin:  pin,\n\t\t\t\t\tcost: cost,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\treturn\n\t}\n\n\tnb.pins = append(nb.pins, &nearbyPin{\n\t\tpin:  pin,\n\t\tcost: cost,\n\t})\n}\n\n// contains checks if the collection contains a Pin.\nfunc (nb *nearbyPins) get(id string) *nearbyPin {\n\tfor _, nbPin := range nb.pins {\n\t\tif nbPin.pin.Hub.ID == id {\n\t\t\treturn nbPin\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// clean sort and shortens the list to the configured maximum.\nfunc (nb *nearbyPins) clean() {\n\t// Sort nearby Pins so that the closest one is on top.\n\tsort.Sort(nb)\n\n\t// Set maximum cost based on max difference, if we have enough pins.\n\tif len(nb.pins) >= nb.minPins {\n\t\tnb.maxCost = nb.pins[0].cost + nb.cutOffLimit\n\t}\n\n\t// Remove superfluous Pins from the list.\n\tif len(nb.pins) > nb.maxPins {\n\t\t// Add debug data if enabled.\n\t\tif nb.debug != nil {\n\t\t\tnb.debug.tooExpensive = append(nb.debug.tooExpensive, nb.pins[nb.maxPins:]...)\n\t\t}\n\n\t\tnb.pins = nb.pins[:nb.maxPins]\n\t}\n\t// Remove Pins that are too costly.\n\tif len(nb.pins) > nb.minPins {\n\t\t// Search for first pin that is too costly.\n\t\tokUntil := nb.minPins\n\t\tfor ; okUntil < len(nb.pins); okUntil++ {\n\t\t\tif nb.pins[okUntil].cost > nb.maxCost {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// Add debug data if enabled.\n\t\tif nb.debug != nil {\n\t\t\tnb.debug.tooExpensive = append(nb.debug.tooExpensive, nb.pins[okUntil:]...)\n\t\t}\n\n\t\t// Cut off the list at that point.\n\t\tnb.pins = nb.pins[:okUntil]\n\t}\n}\n\n// randomizeTop randomized to the top nearest pins for balancing the network.\nfunc (nb *nearbyPins) randomizeTop() {\n\tswitch {\n\tcase nb.randomizeTopPercent == 0:\n\t\t// Check if randomization is enabled.\n\t\treturn\n\tcase len(nb.pins) < 2:\n\t\t// Check if we have enough pins to work with.\n\t\treturn\n\t}\n\n\t// Find randomization set.\n\trandomizeUpTo := len(nb.pins)\n\tthreshold := nb.pins[0].cost * (1 + nb.randomizeTopPercent)\n\tfor i, nb := range nb.pins {\n\t\t// Find first value above the threshold to stop.\n\t\tif nb.cost > threshold {\n\t\t\trandomizeUpTo = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Shuffle top set.\n\tif randomizeUpTo >= 2 {\n\t\tmr := mrand.New(mrand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\t\tmr.Shuffle(randomizeUpTo, nb.Swap)\n\t}\n}\n\n// FindNearestHubs searches for the nearest Hubs to the given IP address. The returned Hubs must not be modified in any way.\nfunc (m *Map) FindNearestHubs(locationV4, locationV6 *geoip.Location, opts *Options, matchFor HubType) ([]*hub.Hub, error) {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\t// Check if map is populated.\n\tif m.isEmpty() {\n\t\treturn nil, ErrEmptyMap\n\t}\n\n\t// Set default options if unset.\n\tif opts == nil {\n\t\topts = m.defaultOptions()\n\t}\n\n\t// Find nearest Pins.\n\tnearby, err := m.findNearestPins(locationV4, locationV6, opts, matchFor, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Convert to Hub list and return.\n\thubs := make([]*hub.Hub, 0, len(nearby.pins))\n\tfor _, nbPin := range nearby.pins {\n\t\thubs = append(hubs, nbPin.pin.Hub)\n\t}\n\treturn hubs, nil\n}\n\nfunc (m *Map) findNearestPins(locationV4, locationV6 *geoip.Location, opts *Options, matchFor HubType, debug bool) (*nearbyPins, error) {\n\t// Fail if no location is provided.\n\tif locationV4 == nil && locationV6 == nil {\n\t\treturn nil, errors.New(\"no location provided\")\n\t}\n\n\t// Raise maxMatches to nearestPinsMinimum.\n\tmaxMatches := defaultMaxNearbyMatches\n\tif maxMatches < nearestPinsMinimum {\n\t\tmaxMatches = nearestPinsMinimum\n\t}\n\n\t// Create nearby Pins list.\n\tnearby := &nearbyPins{\n\t\tminPins:             nearestPinsMinimum,\n\t\tmaxPins:             maxMatches,\n\t\tcutOffLimit:         nearestPinsMaxCostDifference,\n\t\trandomizeTopPercent: defaultRandomizeNearbyPinTopPercent,\n\t}\n\tif debug {\n\t\tnearby.debug = &nearbyPinsDebug{}\n\t}\n\n\t// Create pin matcher.\n\tmatcher := opts.Matcher(matchFor, m.intel)\n\n\t// Iterate over all Pins in the Map to find the nearest ones.\n\tfor _, pin := range m.all {\n\t\tvar cost float32\n\n\t\t// Check if the Pin matches the criteria.\n\t\tif !matcher(pin) {\n\t\t\t// Add debug data if enabled.\n\t\t\tif nearby.debug != nil && pin.State.Has(StateActive|StateReachable) {\n\t\t\t\tnearby.debug.disregarded = append(nearby.debug.disregarded,\n\t\t\t\t\t&nearbyDisregardedPin{\n\t\t\t\t\t\tpin:    pin,\n\t\t\t\t\t\treason: \"does not match general criteria\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Debugging:\n\t\t\t// log.Tracef(\"spn/navigator: skipping %s with states %s for finding nearest\", pin, pin.State)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check if the Hub supports at least one IP version we are looking for.\n\t\tswitch {\n\t\tcase locationV4 != nil && pin.LocationV4 != nil:\n\t\t\t// Both have IPv4!\n\t\tcase locationV6 != nil && pin.LocationV6 != nil:\n\t\t\t// Both have IPv6!\n\t\tdefault:\n\t\t\t// Hub does not support any IP version we need.\n\n\t\t\t// Add debug data if enabled.\n\t\t\tif nearby.debug != nil {\n\t\t\t\tnearby.debug.disregarded = append(nearby.debug.disregarded,\n\t\t\t\t\t&nearbyDisregardedPin{\n\t\t\t\t\t\tpin:    pin,\n\t\t\t\t\t\treason: \"does not support the required IP version\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// If finding a home hub and the global routing profile is set to home (\"VPN\"),\n\t\t// check if all local IP versions are available on the Hub.\n\t\tif matchFor == HomeHub && cfgOptionRoutingAlgorithm() == RoutingProfileHomeID {\n\t\t\tswitch {\n\t\t\tcase locationV4 != nil && pin.LocationV4 == nil:\n\t\t\t\t// Device has IPv4, but Hub does not!\n\t\t\t\tfallthrough\n\t\t\tcase locationV6 != nil && pin.LocationV6 == nil:\n\t\t\t\t// Device has IPv6, but Hub does not!\n\n\t\t\t\t// Add debug data if enabled.\n\t\t\t\tif nearby.debug != nil {\n\t\t\t\t\tnearby.debug.disregarded = append(nearby.debug.disregarded,\n\t\t\t\t\t\t&nearbyDisregardedPin{\n\t\t\t\t\t\t\tpin:    pin,\n\t\t\t\t\t\t\treason: \"home hub needs all IP versions of client (when Home/VPN routing)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// 1. Calculate cost based on distance\n\n\t\tif locationV4 != nil && pin.LocationV4 != nil {\n\t\t\tif locationV4.IsAnycast && m.home != nil {\n\t\t\t\t// If the destination is anycast, calculate cost though proximity to home hub instead, if possible.\n\t\t\t\tcost = lessButPositive(cost, CalculateDestinationCost(\n\t\t\t\t\tproximityBetweenPins(pin, m.home),\n\t\t\t\t))\n\t\t\t} else {\n\t\t\t\t// Regular cost calculation through proximity.\n\t\t\t\tcost = lessButPositive(cost, CalculateDestinationCost(\n\t\t\t\t\tlocationV4.EstimateNetworkProximity(pin.LocationV4),\n\t\t\t\t))\n\t\t\t}\n\t\t}\n\n\t\tif locationV6 != nil && pin.LocationV6 != nil {\n\t\t\tif locationV6.IsAnycast && m.home != nil {\n\t\t\t\t// If the destination is anycast, calculate cost though proximity to home hub instead, if possible.\n\t\t\t\tcost = lessButPositive(cost, CalculateDestinationCost(\n\t\t\t\t\tproximityBetweenPins(pin, m.home),\n\t\t\t\t))\n\t\t\t} else {\n\t\t\t\t// Regular cost calculation through proximity.\n\t\t\t\tcost = lessButPositive(cost, CalculateDestinationCost(\n\t\t\t\t\tlocationV6.EstimateNetworkProximity(pin.LocationV6),\n\t\t\t\t))\n\t\t\t}\n\t\t}\n\n\t\t// If no cost could be calculated, fall back to a default value.\n\t\tif cost == 0 {\n\t\t\tcost = CalculateDestinationCost(50) // proximity out of 0-100\n\t\t}\n\n\t\t// Debugging:\n\t\t// if matchFor == HomeHub {\n\t\t// \tlog.Tracef(\"spn/navigator: adding %.2f proximity cost to home hub %s\", cost, pin.Hub)\n\t\t// }\n\n\t\t// 2. Add cost based on Hub status\n\n\t\tcost += CalculateHubCost(pin.Hub.Status.Load)\n\n\t\t// Debugging:\n\t\t// if matchFor == HomeHub {\n\t\t// \tlog.Tracef(\"spn/navigator: adding %.2f hub cost to home hub %s\", CalculateHubCost(pin.Hub.Status.Load), pin.Hub)\n\t\t// }\n\n\t\t// 3. If matching a home hub, add cost based on capacity/latency performance.\n\n\t\tif matchFor == HomeHub {\n\t\t\t// Find best capacity/latency values.\n\t\t\tvar (\n\t\t\t\tbestCapacity int\n\t\t\t\tbestLatency  time.Duration\n\t\t\t)\n\t\t\tfor _, lane := range pin.Hub.Status.Lanes {\n\t\t\t\tif lane.Capacity > bestCapacity {\n\t\t\t\t\tbestCapacity = lane.Capacity\n\t\t\t\t}\n\t\t\t\tif bestLatency == 0 || lane.Latency < bestLatency {\n\t\t\t\t\tbestLatency = lane.Latency\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Add cost of best capacity/latency values.\n\t\t\tcost += CalculateLaneCost(bestLatency, bestCapacity)\n\n\t\t\t// Debugging:\n\t\t\t// log.Tracef(\"spn/navigator: adding %.2f lane cost to home hub %s\", CalculateLaneCost(bestLatency, bestCapacity), pin.Hub)\n\t\t\t// log.Debugf(\"spn/navigator: total cost of %.2f to home hub %s\", cost, pin.Hub)\n\t\t}\n\n\t\tnearby.add(pin, cost)\n\n\t\t// Clean the nearby list if have collected more than two times the max amount.\n\t\tif len(nearby.pins) >= nearby.maxPins*2 {\n\t\t\tnearby.clean()\n\t\t}\n\t}\n\n\t// Check if we found any nearby pins\n\tif nearby.Len() == 0 {\n\t\treturn nil, ErrAllPinsDisregarded\n\t}\n\n\t// Clean one last time and return the list.\n\tnearby.clean()\n\n\t// Randomize top nearest pins for load balancing.\n\tnearby.randomizeTop()\n\n\t// Debugging:\n\t// if matchFor == HomeHub {\n\t// \tlog.Debug(\"spn/navigator: nearby pins:\")\n\t// \tfor _, nbPin := range nearby.pins {\n\t// \t\tlog.Debugf(\"spn/navigator: nearby pin %s\", nbPin)\n\t// \t}\n\t// }\n\n\treturn nearby, nil\n}\n\nfunc (nb *nearbyPins) String() string {\n\ts := make([]string, 0, len(nb.pins))\n\tfor _, nbPin := range nb.pins {\n\t\ts = append(s, nbPin.String())\n\t}\n\treturn strings.Join(s, \", \")\n}\n\nfunc (nb *nearbyPin) String() string {\n\treturn fmt.Sprintf(\"%s at %.2fc\", nb.pin, nb.cost)\n}\n\nfunc proximityBetweenPins(a, b *Pin) float32 {\n\tvar x, y float32\n\n\t// Get IPv4 network proximity.\n\tif a.LocationV4 != nil && b.LocationV4 != nil {\n\t\tx = a.LocationV4.EstimateNetworkProximity(b.LocationV4)\n\t}\n\n\t// Get IPv6 network proximity.\n\tif a.LocationV6 != nil && b.LocationV6 != nil {\n\t\ty = a.LocationV6.EstimateNetworkProximity(b.LocationV6)\n\t}\n\n\t// Return higher proximity.\n\tif x > y {\n\t\treturn x\n\t}\n\treturn y\n}\n\nfunc lessButPositive(a, b float32) float32 {\n\tswitch {\n\tcase a == 0:\n\t\treturn b\n\tcase b == 0:\n\t\treturn a\n\tcase a < b:\n\t\treturn a\n\tdefault:\n\t\treturn b\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/findnearest_test.go",
    "content": "package navigator\n\nimport (\n\t\"testing\"\n)\n\nfunc TestFindNearest(t *testing.T) {\n\tt.Parallel()\n\n\t// Create map and lock faking in order to guarantee reproducability of faked data.\n\tm := getDefaultTestMap()\n\tfakeLock.Lock()\n\tdefer fakeLock.Unlock()\n\n\tfor range 100 {\n\t\t// Create a random destination address\n\t\tip4, loc4 := createGoodIP(true)\n\n\t\tnbPins, err := m.findNearestPins(loc4, nil, m.DefaultOptions(), DestinationHub, false)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t} else {\n\t\t\tt.Logf(\"Pins near %s: %s\", ip4, nbPins)\n\t\t}\n\t}\n\n\tfor range 100 {\n\t\t// Create a random destination address\n\t\tip6, loc6 := createGoodIP(true)\n\n\t\tnbPins, err := m.findNearestPins(nil, loc6, m.DefaultOptions(), DestinationHub, false)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t} else {\n\t\t\tt.Logf(\"Pins near %s: %s\", ip6, nbPins)\n\t\t}\n\t}\n}\n\n/*\nTODO: Find a way to quickly generate good geoip data on the fly, as we don't want to measure IP address generation, but only finding the nearest pins.\n\nfunc BenchmarkFindNearest(b *testing.B) {\n\t// Create map and lock faking in order to guarantee reproducability of faked data.\n\tm := getDefaultTestMap()\n\tfakeLock.Lock()\n\tdefer fakeLock.Unlock()\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\t// Create a random destination address\n\t\tvar dstIP net.IP\n\t\tif i%2 == 0 {\n\t\t\tdstIP = net.ParseIP(gofakeit.IPv4Address())\n\t\t} else {\n\t\t\tdstIP = net.ParseIP(gofakeit.IPv6Address())\n\t\t}\n\n\t\t_, err := m.findNearestPins(dstIP, m.DefaultOptions(),DestinationHub\t\tif err != nil {\n\t\t\tb.Error(err)\n\t\t}\n\t}\n}\n*/\n\nfunc findFakeHomeHub(m *Map) {\n\t// Create fake IP address.\n\t_, loc4 := createGoodIP(true)\n\t_, loc6 := createGoodIP(false)\n\n\tnbPins, err := m.findNearestPins(loc4, loc6, m.defaultOptions(), HomeHub, false)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif len(nbPins.pins) == 0 {\n\t\tpanic(\"could not find a Home Hub\")\n\t}\n\n\t// Set Home.\n\tm.home = nbPins.pins[0].pin\n\n\t// Recalculate reachability.\n\tif err := m.recalculateReachableHubs(); err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc TestNearbyPinsCleaning(t *testing.T) {\n\tt.Parallel()\n\n\ttestCleaning(t, []float32{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}, 3)\n\ttestCleaning(t, []float32{10, 11, 12, 13, 50, 60, 70, 80, 90, 100}, 4)\n\ttestCleaning(t, []float32{10, 11, 12, 40, 50, 60, 70, 80, 90, 100}, 3)\n\ttestCleaning(t, []float32{10, 11, 30, 40, 50, 60, 70, 80, 90, 100}, 3)\n}\n\nfunc testCleaning(t *testing.T, costs []float32, expectedLeftOver int) {\n\tt.Helper()\n\n\tnb := &nearbyPins{\n\t\tminPins:     3,\n\t\tmaxPins:     5,\n\t\tcutOffLimit: 10,\n\t}\n\n\t// Simulate usage.\n\tfor _, cost := range costs {\n\t\t// Add to list.\n\t\tnb.add(nil, cost)\n\n\t\t// Clean once in a while.\n\t\tif len(nb.pins) > nb.maxPins {\n\t\t\tnb.clean()\n\t\t}\n\t}\n\t// Final clean.\n\tnb.clean()\n\n\t// Check results.\n\tt.Logf(\"result: %+v\", nb.pins)\n\tif len(nb.pins) != expectedLeftOver {\n\t\tt.Errorf(\"unexpected amount of left over pins: %+v\", nb.pins)\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/findroutes.go",
    "content": "package navigator\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n)\n\nconst (\n\t// defaultMaxRouteMatches defines a default value of how many matches a\n\t// route find operation in a map should return.\n\tdefaultMaxRouteMatches = 10\n\n\t// defaultRandomizeRoutesTopPercent defines the top percent of a routes\n\t// set that should be randomized for balancing purposes.\n\t// Range: 0-1.\n\tdefaultRandomizeRoutesTopPercent = 0.1\n)\n\n// FindRoutes finds possible routes to the given IP, with the given options.\nfunc (m *Map) FindRoutes(ip net.IP, opts *Options) (*Routes, error) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// Check if map is populated.\n\tif m.isEmpty() {\n\t\treturn nil, ErrEmptyMap\n\t}\n\n\t// Check if home hub is set.\n\tif m.home == nil {\n\t\treturn nil, ErrHomeHubUnset\n\t}\n\n\t// Get the location of the given IP address.\n\tvar locationV4, locationV6 *geoip.Location\n\tvar err error\n\t// Save whether the given IP address is a IPv4 or IPv6 address.\n\tif v4 := ip.To4(); v4 != nil {\n\t\tlocationV4, err = geoip.GetLocation(ip)\n\t} else {\n\t\tlocationV6, err = geoip.GetLocation(ip)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get IP location: %w\", err)\n\t}\n\n\t// Set default options if unset.\n\tif opts == nil {\n\t\topts = m.defaultOptions()\n\t}\n\n\t// Handle special home routing profile.\n\tif opts.RoutingProfile == RoutingProfileHomeID {\n\t\tswitch {\n\t\tcase locationV4 != nil && m.home.LocationV4 == nil:\n\t\t\t// Destination is IPv4, but Hub has no IPv4!\n\t\t\t// Upgrade routing profile.\n\t\t\topts.RoutingProfile = RoutingProfileSingleHopID\n\n\t\tcase locationV6 != nil && m.home.LocationV6 == nil:\n\t\t\t// Destination is IPv6, but Hub has no IPv6!\n\t\t\t// Upgrade routing profile.\n\t\t\topts.RoutingProfile = RoutingProfileSingleHopID\n\n\t\tdefault:\n\t\t\t// Return route with only home hub for home hub routing.\n\t\t\treturn &Routes{\n\t\t\t\tAll: []*Route{{\n\t\t\t\t\tPath: []*Hop{{\n\t\t\t\t\t\tpin:   m.home,\n\t\t\t\t\t\tHubID: m.home.Hub.ID,\n\t\t\t\t\t}},\n\t\t\t\t\tAlgorithm: RoutingProfileHomeID,\n\t\t\t\t}},\n\t\t\t}, nil\n\t\t}\n\t}\n\n\t// Find nearest Pins.\n\tnearby, err := m.findNearestPins(locationV4, locationV6, opts, DestinationHub, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn m.findRoutes(nearby, opts)\n}\n\n// FindRouteToHub finds possible routes to the given Hub, with the given options.\nfunc (m *Map) FindRouteToHub(hubID string, opts *Options) (*Routes, error) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// Get Pin.\n\tpin, ok := m.all[hubID]\n\tif !ok {\n\t\treturn nil, ErrHubNotFound\n\t}\n\n\t// Create a nearby with a single Pin.\n\tnearby := &nearbyPins{\n\t\tpins: []*nearbyPin{\n\t\t\t{\n\t\t\t\tpin: pin,\n\t\t\t},\n\t\t},\n\t}\n\n\t// Find a route to the given Hub.\n\treturn m.findRoutes(nearby, opts)\n}\n\nfunc (m *Map) findRoutes(dsts *nearbyPins, opts *Options) (*Routes, error) {\n\tif m.home == nil {\n\t\treturn nil, ErrHomeHubUnset\n\t}\n\n\t// Initialize matchers.\n\tvar done bool\n\ttransitMatcher := opts.Transit.Matcher(m.intel)\n\tdestinationMatcher := opts.Destination.Matcher(m.intel)\n\troutingProfile := GetRoutingProfile(opts.RoutingProfile)\n\n\t// Create routes collector.\n\troutes := &Routes{\n\t\tmaxRoutes:           defaultMaxRouteMatches,\n\t\trandomizeTopPercent: defaultRandomizeRoutesTopPercent,\n\t}\n\n\t// TODO:\n\t// Start from the destination and use HopDistance to prioritize\n\t// exploring routes that are in the right direction.\n\t// How would we handle selecting the destination node based on route to client?\n\t// Should we just try all destinations?\n\n\t// Create initial route.\n\troute := &Route{\n\t\t// Estimate how much space we will need, else it'll just expand.\n\t\tPath: make([]*Hop, 1, routingProfile.MinHops+routingProfile.MaxExtraHops),\n\t}\n\troute.Path[0] = &Hop{\n\t\tpin: m.home,\n\t\t// TODO: add initial cost\n\t}\n\n\t// exploreHop explores a hop (Lane) to a connected Pin.\n\tvar exploreHop func(route *Route, lane *Lane)\n\n\t// exploreLanes explores all Lanes of a Pin.\n\texploreLanes := func(route *Route) {\n\t\tfor _, lane := range route.Path[len(route.Path)-1].pin.ConnectedTo {\n\t\t\t// Check if we are done and can skip the rest.\n\t\t\tif done {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Explore!\n\t\t\texploreHop(route, lane)\n\t\t}\n\t}\n\n\texploreHop = func(route *Route, lane *Lane) {\n\t\t// Check if the Pin should be regarded as Transit Hub.\n\t\tif !transitMatcher(lane.Pin) {\n\t\t\treturn\n\t\t}\n\n\t\t// Add Pin to the current path and remove when done.\n\t\troute.addHop(lane.Pin, lane.Cost+lane.Pin.Cost)\n\t\tdefer route.removeHop()\n\n\t\t// Check if the route would even make it into the list.\n\t\tif !routes.isGoodEnough(route) {\n\t\t\treturn\n\t\t}\n\n\t\t// Check route compliance.\n\t\t// This also includes some algorithm-based optimizations.\n\t\tswitch routingProfile.checkRouteCompliance(route, routes) {\n\t\tcase routeOk:\n\t\t\t// Route would be compliant.\n\t\t\t// Now, check if the last hop qualifies as a Destination Hub.\n\t\t\tif destinationMatcher(lane.Pin) {\n\t\t\t\t// Get Pin as nearby Pin.\n\t\t\t\tnbPin := dsts.get(lane.Pin.Hub.ID)\n\t\t\t\tif nbPin != nil {\n\t\t\t\t\t// Pin is listed as selected Destination Hub!\n\t\t\t\t\t// Complete route to add destination (\"last mile\") cost.\n\t\t\t\t\troute.completeRoute(nbPin.cost)\n\t\t\t\t\troutes.add(route)\n\n\t\t\t\t\t// We have found a route and have come to an end here.\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The Route is compliant, but we haven't found a Destination Hub yet.\n\t\t\tfallthrough\n\t\tcase routeNonCompliant:\n\t\t\t// Continue exploration.\n\t\t\texploreLanes(route)\n\t\tcase routeDisqualified:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\t// Route is disqualified and we can return without further exploration.\n\t\t}\n\t}\n\n\t// Start the hop exploration tree.\n\t// This will fork into about a gazillion branches and add all the found valid\n\t// routes to the list.\n\texploreLanes(route)\n\n\t// Check if we found anything.\n\tif len(routes.All) == 0 {\n\t\treturn nil, errors.New(\"failed to find any routes\")\n\t}\n\n\t// Randomize top routes for load balancing.\n\troutes.randomizeTop()\n\n\t// Copy remaining data to routes.\n\troutes.makeExportReady(opts.RoutingProfile)\n\n\t// Debugging:\n\t// log.Debug(\"spn/navigator: routes:\")\n\t// for _, route := range routes.All {\n\t// \tlog.Debugf(\"spn/navigator: %s\", route)\n\t// }\n\n\treturn routes, nil\n}\n"
  },
  {
    "path": "spn/navigator/findroutes_test.go",
    "content": "package navigator\n\nimport (\n\t\"net\"\n\t\"testing\"\n)\n\nfunc TestFindRoutes(t *testing.T) {\n\tt.Parallel()\n\n\t// Create map and lock faking in order to guarantee reproducability of faked data.\n\tm := getOptimizedDefaultTestMap(t)\n\tfakeLock.Lock()\n\tdefer fakeLock.Unlock()\n\n\tfor i := range 1 {\n\t\t// Create a random destination address\n\t\tdstIP, _ := createGoodIP(i%2 == 0)\n\n\t\troutes, err := m.FindRoutes(dstIP, m.DefaultOptions())\n\t\tswitch {\n\t\tcase err != nil:\n\t\t\tt.Error(err)\n\t\tcase len(routes.All) == 0:\n\t\t\tt.Logf(\"No routes for %s\", dstIP)\n\t\tdefault:\n\t\t\tt.Logf(\"Best route for %s: %s\", dstIP, routes.All[0])\n\t\t}\n\t}\n}\n\nfunc BenchmarkFindRoutes(b *testing.B) {\n\t// Create map and lock faking in order to guarantee reproducability of faked data.\n\tm := getOptimizedDefaultTestMap(nil)\n\tfakeLock.Lock()\n\tdefer fakeLock.Unlock()\n\n\t// Pre-generate 100 IPs\n\tpreGenIPs := make([]net.IP, 0, 100)\n\tfor i := range cap(preGenIPs) {\n\t\tip, _ := createGoodIP(i%2 == 0)\n\t\tpreGenIPs = append(preGenIPs, ip)\n\t}\n\n\tb.ResetTimer()\n\tfor i := range b.N {\n\t\troutes, err := m.FindRoutes(preGenIPs[i%len(preGenIPs)], m.DefaultOptions())\n\t\tif err != nil {\n\t\t\tb.Error(err)\n\t\t} else {\n\t\t\tb.Logf(\"Best route for %s: %s\", preGenIPs[i%len(preGenIPs)], routes.All[0])\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/intel.go",
    "content": "package navigator\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// UpdateIntel supplies the map with new intel data. The data is not copied, so\n// it must not be modified after being supplied. If the map is empty, the\n// bootstrap hubs will be added to the map.\nfunc (m *Map) UpdateIntel(update *hub.Intel, trustNodes []string) error {\n\t// Check if intel data is already parsed.\n\tif update.Parsed() == nil {\n\t\treturn errors.New(\"intel data is not parsed\")\n\t}\n\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// Update the map's reference to the intel data.\n\tm.intel = update\n\n\t// Update pins with new intel data.\n\tfor _, pin := range m.all {\n\t\t// Add/Update location data from IP addresses.\n\t\tpin.updateLocationData()\n\n\t\t// Override Pin Data.\n\t\tm.updateInfoOverrides(pin)\n\n\t\t// Update Trust and Advisory Statuses.\n\t\tm.updateIntelStatuses(pin, trustNodes)\n\n\t\t// Push changes.\n\t\t// TODO: Only set when pin changed.\n\t\tpin.pushChanges.Set()\n\t}\n\n\t// Configure the map's regions.\n\tm.updateRegions(m.intel.Regions)\n\n\t// Push pin changes.\n\tm.PushPinChanges()\n\n\tlog.Infof(\"spn/navigator: updated intel on map %s\", m.Name)\n\n\t// Add bootstrap hubs if map is empty.\n\tif m.isEmpty() {\n\t\treturn m.addBootstrapHubs(m.intel.BootstrapHubs)\n\t}\n\treturn nil\n}\n\n// GetIntel returns the map's intel data.\nfunc (m *Map) GetIntel() *hub.Intel {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\treturn m.intel\n}\n\nfunc (m *Map) updateIntelStatuses(pin *Pin, trustNodes []string) {\n\t// Reset all related states (StateSummaryStatusesAppliedFromIntel).\n\tpin.stateIntelApplied.UnSet()\n\tpin.removeStates(StateTrusted | StateUsageDiscouraged | StateUsageAsHomeDiscouraged | StateUsageAsDestinationDiscouraged) // same as: StateSummaryStatusesAppliedFromIntel\n\n\t// Check if Intel data is loaded.\n\tif m.intel == nil {\n\t\treturn\n\t}\n\n\t// Indicate that intel statuses have been applied to the pin\n\tdefer pin.stateIntelApplied.Set()\n\n\t// Check Hub Intel\n\thubIntel, ok := m.intel.Hubs[pin.Hub.ID]\n\tif ok {\n\t\t// Apply the verified owner, if any.\n\t\tpin.VerifiedOwner = hubIntel.VerifiedOwner\n\n\t\t// Check if Hub is discontinued.\n\t\tif hubIntel.Discontinued {\n\t\t\t// Reset state, set offline and return.\n\t\t\tpin.State = StateNone\n\t\t\tpin.addStates(StateOffline)\n\t\t\treturn\n\t\t}\n\n\t\t// Check if Hub is trusted.\n\t\tif hubIntel.Trusted {\n\t\t\tpin.addStates(StateTrusted)\n\t\t}\n\t}\n\n\t// Check manual trust status.\n\tswitch {\n\tcase slices.Contains[[]string, string](trustNodes, pin.VerifiedOwner):\n\t\tpin.addStates(StateTrusted)\n\tcase slices.Contains[[]string, string](trustNodes, pin.Hub.ID):\n\t\tpin.addStates(StateTrusted)\n\t}\n\n\t// Check advisories.\n\t// Check for UsageDiscouraged.\n\tcheckStatusList(\n\t\tpin,\n\t\tStateUsageDiscouraged,\n\t\tm.intel.AdviseOnlyTrustedHubs,\n\t\tm.intel.Parsed().HubAdvisory,\n\t)\n\t// Check for UsageAsHomeDiscouraged.\n\tcheckStatusList(\n\t\tpin,\n\t\tStateUsageAsHomeDiscouraged,\n\t\tm.intel.AdviseOnlyTrustedHomeHubs,\n\t\tm.intel.Parsed().HomeHubAdvisory,\n\t)\n\t// Check for UsageAsDestinationDiscouraged.\n\tcheckStatusList(\n\t\tpin,\n\t\tStateUsageAsDestinationDiscouraged,\n\t\tm.intel.AdviseOnlyTrustedDestinationHubs,\n\t\tm.intel.Parsed().DestinationHubAdvisory,\n\t)\n}\n\nfunc checkStatusList(pin *Pin, state PinState, requireTrusted bool, endpointList endpoints.Endpoints) {\n\tif requireTrusted && !pin.State.Has(StateTrusted) {\n\t\tpin.addStates(state)\n\t\treturn\n\t}\n\n\tif pin.EntityV4 != nil {\n\t\tresult, _ := endpointList.Match(context.TODO(), pin.EntityV4)\n\t\tif result == endpoints.Denied {\n\t\t\tpin.addStates(state)\n\t\t\treturn\n\t\t}\n\t}\n\n\tif pin.EntityV6 != nil {\n\t\tresult, _ := endpointList.Match(context.TODO(), pin.EntityV6)\n\t\tif result == endpoints.Denied {\n\t\t\tpin.addStates(state)\n\t\t}\n\t}\n}\n\nfunc (m *Map) updateInfoOverrides(pin *Pin) {\n\t// Check if Intel data is loaded and if there are any overrides.\n\tif m.intel == nil {\n\t\treturn\n\t}\n\n\t// Get overrides for this pin.\n\thubIntel, ok := m.intel.Hubs[pin.Hub.ID]\n\tif !ok || hubIntel.Override == nil {\n\t\treturn\n\t}\n\toverrides := hubIntel.Override\n\n\t// Apply overrides\n\tif overrides.CountryCode != \"\" {\n\t\tif pin.LocationV4 != nil {\n\t\t\tpin.LocationV4.Country = geoip.GetCountryInfo(overrides.CountryCode)\n\t\t}\n\t\tif pin.EntityV4 != nil {\n\t\t\tpin.EntityV4.Country = overrides.CountryCode\n\t\t}\n\t\tif pin.LocationV6 != nil {\n\t\t\tpin.LocationV6.Country = geoip.GetCountryInfo(overrides.CountryCode)\n\t\t}\n\t\tif pin.EntityV6 != nil {\n\t\t\tpin.EntityV6.Country = overrides.CountryCode\n\t\t}\n\t}\n\tif overrides.Coordinates != nil {\n\t\tif pin.LocationV4 != nil {\n\t\t\tpin.LocationV4.Coordinates = *overrides.Coordinates\n\t\t}\n\t\tif pin.EntityV4 != nil {\n\t\t\tpin.EntityV4.Coordinates = overrides.Coordinates\n\t\t}\n\t\tif pin.LocationV6 != nil {\n\t\t\tpin.LocationV6.Coordinates = *overrides.Coordinates\n\t\t}\n\t\tif pin.EntityV6 != nil {\n\t\t\tpin.EntityV6.Coordinates = overrides.Coordinates\n\t\t}\n\t}\n\tif overrides.ASN != 0 {\n\t\tif pin.LocationV4 != nil {\n\t\t\tpin.LocationV4.AutonomousSystemNumber = overrides.ASN\n\t\t}\n\t\tif pin.EntityV4 != nil {\n\t\t\tpin.EntityV4.ASN = overrides.ASN\n\t\t}\n\t\tif pin.LocationV6 != nil {\n\t\t\tpin.LocationV6.AutonomousSystemNumber = overrides.ASN\n\t\t}\n\t\tif pin.EntityV6 != nil {\n\t\t\tpin.EntityV6.ASN = overrides.ASN\n\t\t}\n\t}\n\tif overrides.ASOrg != \"\" {\n\t\tif pin.LocationV4 != nil {\n\t\t\tpin.LocationV4.AutonomousSystemOrganization = overrides.ASOrg\n\t\t}\n\t\tif pin.EntityV4 != nil {\n\t\t\tpin.EntityV4.ASOrg = overrides.ASOrg\n\t\t}\n\t\tif pin.LocationV6 != nil {\n\t\t\tpin.LocationV6.AutonomousSystemOrganization = overrides.ASOrg\n\t\t}\n\t\tif pin.EntityV6 != nil {\n\t\t\tpin.EntityV6.ASOrg = overrides.ASOrg\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/map.go",
    "content": "package navigator\n\nimport (\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// Map represent a collection of Pins and their relationship and status.\ntype Map struct {\n\tsync.RWMutex\n\tName string\n\n\tall     map[string]*Pin\n\tintel   *hub.Intel\n\tregions []*Region\n\n\thome         *Pin\n\thomeTerminal *docks.CraneTerminal\n\n\tmeasuringEnabled bool\n\thubUpdateHook    *database.RegisteredHook\n\n\t// analysisLock guards access to all of this map's Pin.analysis,\n\t// regardedPins and the lastDesegrationAttempt fields.\n\tanalysisLock           sync.Mutex\n\tregardedPins           []*Pin\n\tlastDesegrationAttempt time.Time\n}\n\n// NewMap returns a new and empty Map.\nfunc NewMap(name string, enableMeasuring bool) *Map {\n\tm := &Map{\n\t\tName:             name,\n\t\tall:              make(map[string]*Pin),\n\t\tmeasuringEnabled: enableMeasuring,\n\t}\n\taddMapToAPI(m)\n\n\treturn m\n}\n\n// Close removes the map's integration, taking it \"offline\".\nfunc (m *Map) Close() {\n\tremoveMapFromAPI(m.Name)\n}\n\n// GetPin returns the Pin of the Hub with the given ID.\nfunc (m *Map) GetPin(hubID string) (pin *Pin, ok bool) {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\tpin, ok = m.all[hubID]\n\treturn\n}\n\n// GetHome returns the current home and it's accompanying terminal.\n// Both may be nil.\nfunc (m *Map) GetHome() (*Pin, *docks.CraneTerminal) {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\treturn m.home, m.homeTerminal\n}\n\n// SetHome sets the given hub as the new home. Optionally, a terminal may be\n// supplied to accompany the home hub.\nfunc (m *Map) SetHome(id string, t *docks.CraneTerminal) (ok bool) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// Get pin from map.\n\tnewHome, ok := m.all[id]\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// Remove home hub state from all pins.\n\tfor _, pin := range m.all {\n\t\tpin.removeStates(StateIsHomeHub)\n\t}\n\n\t// Set pin as home.\n\tm.home = newHome\n\tm.homeTerminal = t\n\tm.home.addStates(StateIsHomeHub)\n\n\t// Recalculate reachable.\n\terr := m.recalculateReachableHubs()\n\tif err != nil {\n\t\tlog.Warningf(\"spn/navigator: failed to recalculate reachable hubs: %s\", err)\n\t}\n\n\tm.PushPinChanges()\n\treturn true\n}\n\n// GetAvailableCountries returns a map of countries including their information\n// where the map has pins suitable for the given type.\nfunc (m *Map) GetAvailableCountries(opts *Options, forType HubType) map[string]*geoip.CountryInfo {\n\tif opts == nil {\n\t\topts = m.defaultOptions()\n\t}\n\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\tmatcher := opts.Matcher(forType, m.intel)\n\tcountries := make(map[string]*geoip.CountryInfo)\n\tfor _, pin := range m.all {\n\t\tif !matcher(pin) {\n\t\t\tcontinue\n\t\t}\n\t\tif pin.LocationV4 != nil && countries[pin.LocationV4.Country.Code] == nil {\n\t\t\tcountries[pin.LocationV4.Country.Code] = &pin.LocationV4.Country\n\t\t}\n\t\tif pin.LocationV6 != nil && countries[pin.LocationV6.Country.Code] == nil {\n\t\t\tcountries[pin.LocationV6.Country.Code] = &pin.LocationV6.Country\n\t\t}\n\t}\n\n\treturn countries\n}\n\n// isEmpty returns whether the Map is regarded as empty.\nfunc (m *Map) isEmpty() bool {\n\tif m.home != nil {\n\t\t// When a home hub is set, we also regard a map with only one entry to be\n\t\t// empty, as this will be the case for Hubs, which will have their own\n\t\t// entry in the Map.\n\t\treturn len(m.all) <= 1\n\t}\n\n\treturn len(m.all) == 0\n}\n\nfunc (m *Map) pinList(lockMap bool) []*Pin {\n\tif lockMap {\n\t\tm.RLock()\n\t\tdefer m.RUnlock()\n\t}\n\n\t// Copy into slice.\n\tlist := make([]*Pin, 0, len(m.all))\n\tfor _, pin := range m.all {\n\t\tlist = append(list, pin)\n\t}\n\n\treturn list\n}\n\nfunc (m *Map) sortedPins(lockMap bool) []*Pin {\n\t// Get list.\n\tlist := m.pinList(lockMap)\n\n\t// Sort list.\n\tsort.Sort(sortByPinID(list))\n\treturn list\n}\n"
  },
  {
    "path": "spn/navigator/map_stats.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// MapStats holds generic map statistics.\ntype MapStats struct {\n\tName            string\n\tStates          map[PinState]int\n\tLanes           map[int]int\n\tActiveTerminals int\n}\n\n// Stats collects and returns statistics from the map.\nfunc (m *Map) Stats() *MapStats {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// Create stats struct.\n\tstats := &MapStats{\n\t\tName:   m.Name,\n\t\tStates: make(map[PinState]int),\n\t\tLanes:  make(map[int]int),\n\t}\n\tfor _, state := range allStates {\n\t\tstats.States[state] = 0\n\t}\n\n\t// Iterate over all Pins to collect data.\n\tfor _, pin := range m.all {\n\t\t// Count active terminals.\n\t\tif pin.HasActiveTerminal() {\n\t\t\tstats.ActiveTerminals++\n\t\t}\n\n\t\t// Check all states.\n\t\tfor _, state := range allStates {\n\t\t\tif pin.State.Has(state) {\n\t\t\t\tstats.States[state]++\n\t\t\t}\n\t\t}\n\n\t\t// Count lanes.\n\t\tlaneCnt, ok := stats.Lanes[len(pin.ConnectedTo)]\n\t\tif ok {\n\t\t\tstats.Lanes[len(pin.ConnectedTo)] = laneCnt + 1\n\t\t} else {\n\t\t\tstats.Lanes[len(pin.ConnectedTo)] = 1\n\t\t}\n\t}\n\n\treturn stats\n}\n\nfunc (ms *MapStats) String() string {\n\tvar builder strings.Builder\n\n\t// Write header.\n\tfmt.Fprintf(&builder, \"Stats for Map %s:\\n\", ms.Name)\n\n\t// Write State Stats\n\tstateSummary := make([]string, 0, len(ms.States))\n\tfor state, cnt := range ms.States {\n\t\tstateSummary = append(stateSummary, fmt.Sprintf(\"State %s: %d Hubs\", state, cnt))\n\t}\n\tsort.Strings(stateSummary)\n\tfor _, stateSum := range stateSummary {\n\t\tfmt.Fprintln(&builder, stateSum)\n\t}\n\n\t// Write Lane Stats\n\tlaneStats := make([]string, 0, len(ms.Lanes))\n\tfor laneCnt, pinCnt := range ms.Lanes {\n\t\tlaneStats = append(laneStats, fmt.Sprintf(\"%d Lanes: %d Hubs\", laneCnt, pinCnt))\n\t}\n\tsort.Strings(laneStats)\n\tfor _, laneStat := range laneStats {\n\t\tfmt.Fprintln(&builder, laneStat)\n\t}\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "spn/navigator/map_test.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/brianvoe/gofakeit\"\n\n\t\"github.com/safing/jess/lhash\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nvar (\n\tfakeLock sync.Mutex\n\n\tdefaultMapCreate sync.Once\n\tdefaultMap       *Map\n)\n\nfunc getDefaultTestMap() *Map {\n\tdefaultMapCreate.Do(func() {\n\t\tdefaultMap = createRandomTestMap(1, 200)\n\t})\n\treturn defaultMap\n}\n\nfunc TestRandomMapCreation(t *testing.T) {\n\tt.Parallel()\n\n\tm := getDefaultTestMap()\n\n\tfmt.Println(\"All Pins:\")\n\tfor _, pin := range m.all {\n\t\tfmt.Printf(\"%s: %s %s\\n\", pin, pin.Hub.Info.IPv4, pin.Hub.Info.IPv6)\n\t}\n\n\t// Print stats\n\tfmt.Printf(\"\\n%s\\n\", m.Stats())\n\n\t// Print home\n\tfmt.Printf(\"Selected Home Hub: %s\\n\", m.home)\n}\n\nfunc createRandomTestMap(seed int64, size int) *Map {\n\tfakeLock.Lock()\n\tdefer fakeLock.Unlock()\n\n\t// Seed with parameter to make it reproducible.\n\tgofakeit.Seed(seed)\n\n\t// Enforce minimum size.\n\tif size < 10 {\n\t\tsize = 10\n\t}\n\n\t// Create Hub list.\n\thubs := make([]*hub.Hub, 0, size)\n\n\t// Create Intel data structure.\n\tmapIntel := &hub.Intel{\n\t\tHubs: make(map[string]*hub.HubIntel),\n\t}\n\n\t// Define periodic values.\n\tvar currentGroup string\n\n\t// Create [size] fake Hubs.\n\tfor i := range size {\n\t\t// Change group every 5 Hubs.\n\t\tif i%5 == 0 {\n\t\t\tcurrentGroup = gofakeit.Username()\n\t\t}\n\n\t\t// Create new fake Hub and add to the list.\n\t\th := createFakeHub(currentGroup, true, mapIntel)\n\t\thubs = append(hubs, h)\n\t}\n\n\t// Fake three superseeded Hubs.\n\tfor i := range 3 {\n\t\th := hubs[size-1-i]\n\n\t\t// Set FirstSeen in the past and copy an IP address of an existing Hub.\n\t\th.FirstSeen = time.Now().Add(-1 * time.Hour)\n\t\tif i%2 == 0 {\n\t\t\th.Info.IPv4 = hubs[i].Info.IPv4\n\t\t} else {\n\t\t\th.Info.IPv6 = hubs[i].Info.IPv6\n\t\t}\n\t}\n\n\t// Create Lanes between Hubs in order to create the network.\n\ttotalConnections := size * 10\n\tfor range totalConnections {\n\t\t// Get new random indexes.\n\t\tindexA := gofakeit.Number(0, size-1)\n\t\tindexB := gofakeit.Number(0, size-1)\n\t\tif indexA == indexB {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Get Hubs and check if they are already connected.\n\t\thubA := hubs[indexA]\n\t\thubB := hubs[indexB]\n\t\tif hubA.GetLaneTo(hubB.ID) != nil {\n\t\t\t// already connected\n\t\t\tcontinue\n\t\t}\n\t\tif hubB.GetLaneTo(hubA.ID) != nil {\n\t\t\t// already connected\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create connections.\n\t\t_ = hubA.AddLane(createLane(hubB.ID))\n\t\t// Add the second connection in 99% of cases.\n\t\t// If this is missing, the Pins should not show up as connected.\n\t\tif gofakeit.Number(0, 100) != 0 {\n\t\t\t_ = hubB.AddLane(createLane(hubA.ID))\n\t\t}\n\t}\n\n\t// Parse constructed intel data\n\terr := mapIntel.ParseAdvisories()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// Create map and add Pins.\n\tm := NewMap(fmt.Sprintf(\"Test-Map-%d\", seed), true)\n\tm.intel = mapIntel\n\tfor _, h := range hubs {\n\t\tm.UpdateHub(h)\n\t}\n\n\t// Fake communication error with three Hubs.\n\tvar i int\n\tfor _, pin := range m.all {\n\t\tpin.MarkAsFailingFor(1 * time.Hour)\n\t\tpin.addStates(StateFailing)\n\n\t\tif i++; i >= 3 {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Set a Home Hub.\n\tfindFakeHomeHub(m)\n\n\treturn m\n}\n\nfunc createFakeHub(group string, randomFailes bool, mapIntel *hub.Intel) *hub.Hub {\n\t// Create fake Hub ID.\n\tidSrc := gofakeit.Password(true, true, true, true, true, 64)\n\tid := lhash.Digest(lhash.BLAKE2b_256, []byte(idSrc)).Base58()\n\tip4, _ := createGoodIP(true)\n\tip6, _ := createGoodIP(false)\n\n\t// Create and return new fake Hub.\n\th := &hub.Hub{\n\t\tID: id,\n\t\tInfo: &hub.Announcement{\n\t\t\tID:        id,\n\t\t\tTimestamp: time.Now().Unix(),\n\t\t\tName:      gofakeit.Username(),\n\t\t\tGroup:     group,\n\t\t\t// ContactAddress // TODO\n\t\t\t// ContactService // TODO\n\t\t\t// Hosters    []string // TODO\n\t\t\t// Datacenter string   // TODO\n\t\t\tIPv4: ip4,\n\t\t\tIPv6: ip6,\n\t\t},\n\t\tStatus: &hub.Status{\n\t\t\tTimestamp: time.Now().Unix(),\n\t\t\tKeys: map[string]*hub.Key{\n\t\t\t\t\"a\": {\n\t\t\t\t\tExpires: time.Now().Add(48 * time.Hour).Unix(),\n\t\t\t\t},\n\t\t\t},\n\t\t\tLoad: gofakeit.Number(10, 100),\n\t\t},\n\t\tMeasurements: hub.NewMeasurements(),\n\t\tFirstSeen:    time.Now(),\n\t}\n\th.Measurements.Latency = createLatency()\n\th.Measurements.Capacity = createCapacity()\n\th.Measurements.CalculatedCost = CalculateLaneCost(\n\t\th.Measurements.Latency,\n\t\th.Measurements.Capacity,\n\t)\n\n\t// Return if not failures of any kind should be simulated.\n\tif !randomFailes {\n\t\treturn h\n\t}\n\n\t// Set hub-based states.\n\tif gofakeit.Number(0, 100) == 0 {\n\t\t// Fake Info message error.\n\t\th.InvalidInfo = true\n\t}\n\tif gofakeit.Number(0, 100) == 0 {\n\t\t// Fake Status message error.\n\t\th.InvalidStatus = true\n\t}\n\tif gofakeit.Number(0, 100) == 0 {\n\t\t// Fake expired exchange keys.\n\t\tfor _, key := range h.Status.Keys {\n\t\t\tkey.Expires = time.Now().Add(-1 * time.Hour).Unix()\n\t\t}\n\t}\n\n\t// Return if not failures of any kind should be simulated.\n\tif mapIntel == nil {\n\t\treturn h\n\t}\n\n\t// Set advisory-based states.\n\tif gofakeit.Number(0, 10) == 0 {\n\t\t// Make Trusted State\n\t\tmapIntel.Hubs[h.ID] = &hub.HubIntel{\n\t\t\tTrusted: true,\n\t\t}\n\t}\n\tif gofakeit.Number(0, 100) == 0 {\n\t\t// Discourage any usage.\n\t\tmapIntel.HubAdvisory = append(mapIntel.HubAdvisory, \"- \"+h.Info.IPv4.String())\n\t}\n\tif gofakeit.Number(0, 100) == 0 {\n\t\t// Discourage Home Hub usage.\n\t\tmapIntel.HomeHubAdvisory = append(mapIntel.HomeHubAdvisory, \"- \"+h.Info.IPv4.String())\n\t}\n\tif gofakeit.Number(0, 100) == 0 {\n\t\t// Discourage Destination Hub usage.\n\t\tmapIntel.DestinationHubAdvisory = append(mapIntel.DestinationHubAdvisory, \"- \"+h.Info.IPv4.String())\n\t}\n\n\treturn h\n}\n\nfunc createGoodIP(v4 bool) (net.IP, *geoip.Location) {\n\tvar candidate net.IP\n\tfor range 100 {\n\t\tif v4 {\n\t\t\tcandidate = net.ParseIP(gofakeit.IPv4Address())\n\t\t} else {\n\t\t\tcandidate = net.ParseIP(gofakeit.IPv6Address())\n\t\t}\n\t\tloc, err := geoip.GetLocation(candidate)\n\t\tif err == nil && loc.Coordinates.Latitude != 0 {\n\t\t\treturn candidate, loc\n\t\t}\n\t}\n\treturn candidate, nil\n}\n\nfunc createLane(toHubID string) *hub.Lane {\n\treturn &hub.Lane{\n\t\tID:       toHubID,\n\t\tLatency:  createLatency(),\n\t\tCapacity: createCapacity(),\n\t}\n}\n\nfunc createLatency() time.Duration {\n\t// Return a value between 10ms and 100ms.\n\treturn time.Duration(gofakeit.Float64Range(10, 100) * float64(time.Millisecond))\n}\n\nfunc createCapacity() int {\n\t// Return a value between 10Mbit/s and 1Gbit/s.\n\treturn gofakeit.Number(10000000, 1000000000)\n}\n"
  },
  {
    "path": "spn/navigator/measurements.go",
    "content": "package navigator\n\nimport (\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/terminal\"\n)\n\n// Measurements Configuration.\nconst (\n\tNavigatorMeasurementTTLDefault    = 4 * time.Hour\n\tNavigatorMeasurementTTLByCostBase = 6 * time.Minute\n\tNavigatorMeasurementTTLByCostMin  = 4 * time.Hour\n\tNavigatorMeasurementTTLByCostMax  = 50 * time.Hour\n\n\t// With a base TTL of 3m, this leads to:\n\t// 20c     -> 2h -> raised to 4h.\n\t// 50c     -> 5h\n\t// 100c    -> 10h\n\t// 1000c   -> 100h -> capped to 50h.\n)\n\nfunc (m *Map) measureHubs(wc *mgr.WorkerCtx) error {\n\tif home, _ := m.GetHome(); home == nil {\n\t\tlog.Debug(\"spn/navigator: skipping measuring, no home hub set\")\n\t\treturn nil\n\t}\n\n\tvar unknownErrCnt int\n\tmatcher := m.DefaultOptions().Transit.Matcher(m.GetIntel())\n\n\t// Get list and sort in order to check near/low-cost hubs earlier.\n\tlist := m.pinList(true)\n\tsort.Sort(sortByLowestMeasuredCost(list))\n\n\t// Find first pin where any measurement has expired.\n\tfor _, pin := range list {\n\t\t// Check if measuring is enabled.\n\t\tif pin.measurements == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Check if Pin is regarded.\n\t\tif !matcher(pin) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Calculate dynamic TTL.\n\t\tvar checkWithTTL time.Duration\n\t\tif pin.HopDistance == 2 { // Hub is directly connected.\n\t\t\tcheckWithTTL = calculateMeasurementTTLByCost(\n\t\t\t\tpin.measurements.GetCalculatedCost(),\n\t\t\t\tdocks.CraneMeasurementTTLByCostBase,\n\t\t\t\tdocks.CraneMeasurementTTLByCostMin,\n\t\t\t\tdocks.CraneMeasurementTTLByCostMax,\n\t\t\t)\n\t\t} else {\n\t\t\tcheckWithTTL = calculateMeasurementTTLByCost(\n\t\t\t\tpin.measurements.GetCalculatedCost(),\n\t\t\t\tNavigatorMeasurementTTLByCostBase,\n\t\t\t\tNavigatorMeasurementTTLByCostMin,\n\t\t\t\tNavigatorMeasurementTTLByCostMax,\n\t\t\t)\n\t\t}\n\n\t\t// Check if we have measured the pin within the TTL.\n\t\tif !pin.measurements.Expired(checkWithTTL) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Measure connection.\n\t\ttErr := docks.MeasureHub(wc.Ctx(), pin.Hub, checkWithTTL)\n\n\t\t// Independent of outcome, recalculate the cost.\n\t\tlatency, _ := pin.measurements.GetLatency()\n\t\tcapacity, _ := pin.measurements.GetCapacity()\n\t\tcalculatedCost := CalculateLaneCost(latency, capacity)\n\t\tpin.measurements.SetCalculatedCost(calculatedCost)\n\t\t// Log result.\n\t\tlog.Infof(\n\t\t\t\"spn/navigator: updated measurements for connection to %s: %s %.2fMbit/s %.2fc\",\n\t\t\tpin.Hub,\n\t\t\tlatency,\n\t\t\tfloat64(capacity)/1000000,\n\t\t\tcalculatedCost,\n\t\t)\n\n\t\tswitch {\n\t\tcase tErr.IsOK():\n\t\t\t// All good, continue.\n\n\t\tcase tErr.Is(terminal.ErrTryAgainLater):\n\t\t\tif tErr.IsExternal() {\n\t\t\t\t// Remote is measuring, just continue with next.\n\t\t\t\tlog.Debugf(\"spn/navigator: remote %s is measuring, continuing with next\", pin.Hub)\n\t\t\t} else {\n\t\t\t\t// We are measuring, abort and restart measuring again later.\n\t\t\t\tlog.Debugf(\"spn/navigator: postponing measuring because we are currently engaged in measuring\")\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\tdefault:\n\t\t\tlog.Warningf(\"spn/navigator: failed to measure connection to %s: %s\", pin.Hub, tErr)\n\t\t\tunknownErrCnt++\n\t\t\tif unknownErrCnt >= 3 {\n\t\t\t\tlog.Warningf(\"spn/navigator: postponing measuring task because of multiple errors\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// SaveMeasuredHubs saves all Hubs that have unsaved measurements.\nfunc (m *Map) SaveMeasuredHubs() {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\tfor _, pin := range m.all {\n\t\tif !pin.measurements.IsPersisted() {\n\t\t\tif err := pin.Hub.Save(); err != nil {\n\t\t\t\tlog.Warningf(\"spn/navigator: failed to save Hub %s to persist measurements: %s\", pin.Hub, err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc calculateMeasurementTTLByCost(cost float32, base, min, max time.Duration) time.Duration {\n\tcalculated := time.Duration(cost) * base\n\tswitch {\n\tcase calculated < min:\n\t\treturn min\n\tcase calculated > max:\n\t\treturn max\n\tdefault:\n\t\treturn calculated\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/metrics.go",
    "content": "package navigator\n\nimport (\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/metrics\"\n)\n\nvar metricsRegistered = abool.New()\n\nfunc registerMetrics() (err error) {\n\t// Only register metrics once.\n\tif !metricsRegistered.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Map Stats.\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/map/main/latency/all/lowest/seconds\",\n\t\tnil,\n\t\tgetLowestLatency,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Map Lowest Latency\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/map/main/latency/fas/lowest/seconds\",\n\t\tnil,\n\t\tgetLowestLatencyFromFas,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Map Lowest Latency\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/map/main/capacity/all/highest/bytes\",\n\t\tnil,\n\t\tgetHighestCapacity,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Map Lowest Latency\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/map/main/capacity/fas/highest/bytes\",\n\t\tnil,\n\t\tgetHighestCapacityFromFas,\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Map Lowest Latency\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nvar (\n\tmapStats        *mapMetrics\n\tmapStatsExpires time.Time\n\tmapStatsLock    sync.Mutex\n\tmapStatsTTL     = 55 * time.Second\n)\n\ntype mapMetrics struct {\n\tlowestLatency            float64\n\tlowestForeignASLatency   float64\n\thighestCapacity          float64\n\thighestForeignASCapacity float64\n}\n\nfunc getLowestLatency() float64          { return getMapStats().lowestLatency }\nfunc getLowestLatencyFromFas() float64   { return getMapStats().lowestForeignASLatency }\nfunc getHighestCapacity() float64        { return getMapStats().highestCapacity }\nfunc getHighestCapacityFromFas() float64 { return getMapStats().highestForeignASCapacity }\n\nfunc getMapStats() *mapMetrics {\n\tmapStatsLock.Lock()\n\tdefer mapStatsLock.Unlock()\n\n\t// Return cache if still valid.\n\tif time.Now().Before(mapStatsExpires) {\n\t\treturn mapStats\n\t}\n\n\t// Refresh.\n\tmapStats = &mapMetrics{}\n\n\t// Get all pins and home.\n\tlist := Main.pinList(true)\n\thome, _ := Main.GetHome()\n\n\t// Return empty stats if we have incomplete data.\n\tif len(list) <= 1 || home == nil {\n\t\tmapStatsExpires = time.Now().Add(mapStatsTTL)\n\t\treturn mapStats\n\t}\n\n\t// Sort by latency.\n\tsort.Sort(sortByLowestMeasuredLatency(list))\n\t// Get lowest latency.\n\tlowestLatency, _ := list[0].measurements.GetLatency()\n\tmapStats.lowestLatency = lowestLatency.Seconds()\n\t// Find best foreign AS latency.\n\tbestForeignASPin := findFirstForeignASStatsPin(home, list)\n\tif bestForeignASPin != nil {\n\t\tlowestForeignASLatency, _ := bestForeignASPin.measurements.GetLatency()\n\t\tmapStats.lowestForeignASLatency = lowestForeignASLatency.Seconds()\n\t}\n\n\t// Sort by capacity.\n\tsort.Sort(sortByHighestMeasuredCapacity(list))\n\t// Get highest capacity.\n\thighestCapacity, _ := list[0].measurements.GetCapacity()\n\tmapStats.highestCapacity = float64(highestCapacity) / 8\n\t// Find best foreign AS capacity.\n\tbestForeignASPin = findFirstForeignASStatsPin(home, list)\n\tif bestForeignASPin != nil {\n\t\thighestForeignASCapacity, _ := bestForeignASPin.measurements.GetCapacity()\n\t\tmapStats.highestForeignASCapacity = float64(highestForeignASCapacity) / 8\n\t}\n\n\tmapStatsExpires = time.Now().Add(mapStatsTTL)\n\treturn mapStats\n}\n\nfunc findFirstForeignASStatsPin(home *Pin, list []*Pin) *Pin {\n\t// Find best foreign AS latency.\n\tfor _, pin := range list {\n\t\tcompared := false\n\n\t\t// Skip if IPv4 AS matches.\n\t\tif home.LocationV4 != nil && pin.LocationV4 != nil {\n\t\t\tif home.LocationV4.AutonomousSystemNumber == pin.LocationV4.AutonomousSystemNumber {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcompared = true\n\t\t}\n\n\t\t// Skip if IPv6 AS matches.\n\t\tif home.LocationV6 != nil && pin.LocationV6 != nil {\n\t\t\tif home.LocationV6.AutonomousSystemNumber == pin.LocationV6.AutonomousSystemNumber {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcompared = true\n\t\t}\n\n\t\t// Skip if no data was compared\n\t\tif !compared {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn pin\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "spn/navigator/module.go",
    "content": "package navigator\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\nconst (\n\t// cfgOptionRoutingAlgorithmKey is copied from profile/config.go to avoid import loop.\n\tcfgOptionRoutingAlgorithmKey = \"spn/routingAlgorithm\"\n\n\t// cfgOptionRoutingAlgorithmKey is copied from captain/config.go to avoid import loop.\n\tcfgOptionTrustNodeNodesKey = \"spn/trustNodes\"\n)\n\nvar (\n\t// ErrHomeHubUnset is returned when the Home Hub is required and not set.\n\tErrHomeHubUnset = errors.New(\"map has no Home Hub set\")\n\n\t// ErrEmptyMap is returned when the Map is empty.\n\tErrEmptyMap = errors.New(\"map is empty\")\n\n\t// ErrHubNotFound is returned when the Hub was not found on the Map.\n\tErrHubNotFound = errors.New(\"hub not found\")\n\n\t// ErrAllPinsDisregarded is returned when all pins have been disregarded.\n\tErrAllPinsDisregarded = errors.New(\"all pins have been disregarded\")\n)\n\ntype Navigator struct {\n\tmgr *mgr.Manager\n\n\tinstance instance\n}\n\nfunc (n *Navigator) Manager() *mgr.Manager {\n\treturn n.mgr\n}\n\nfunc (n *Navigator) Start() error {\n\treturn start()\n}\n\nfunc (n *Navigator) Stop() error {\n\treturn stop()\n}\n\nvar (\n\tmodule     *Navigator\n\tshimLoaded atomic.Bool\n\n\t// Main is the primary map used.\n\tMain *Map\n\n\tdevMode                   config.BoolOption\n\tcfgOptionRoutingAlgorithm config.StringOption\n\tcfgOptionTrustNodeNodes   config.StringArrayOption\n)\n\nfunc prep() error {\n\treturn registerAPIEndpoints()\n}\n\nfunc start() error {\n\tMain = NewMap(conf.MainMapName, true)\n\tdevMode = config.Concurrent.GetAsBool(config.CfgDevModeKey, false)\n\tcfgOptionTrustNodeNodes = config.Concurrent.GetAsStringArray(cfgOptionTrustNodeNodesKey, []string{})\n\n\tif conf.Integrated() {\n\t\tcfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(cfgOptionRoutingAlgorithmKey, DefaultRoutingProfileID)\n\t} else {\n\t\tcfgOptionRoutingAlgorithm = func() string { return DefaultRoutingProfileID }\n\t}\n\n\terr := registerMapDatabase()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmodule.mgr.Go(\"initializing hubs\", func(wc *mgr.WorkerCtx) error {\n\t\t// Wait for geoip databases to be ready.\n\t\t// Try again if not yet ready, as this is critical.\n\t\t// The \"wait\" parameter times out after 1 second.\n\t\t// Allow 30 seconds for both databases to load.\n\tgeoInitCheck:\n\t\tfor range 30 {\n\t\t\tswitch {\n\t\t\tcase !geoip.IsInitialized(false, true): // First, IPv4.\n\t\t\tcase !geoip.IsInitialized(true, true): // Then, IPv6.\n\t\t\tdefault:\n\t\t\t\tbreak geoInitCheck\n\t\t\t}\n\t\t}\n\n\t\terr = Main.InitializeFromDatabase()\n\t\tif err != nil {\n\t\t\t// Wait for three seconds, then try again.\n\t\t\ttime.Sleep(3 * time.Second)\n\t\t\terr = Main.InitializeFromDatabase()\n\t\t\tif err != nil {\n\t\t\t\t// Even if the init fails, we can try to start without it and get data along the way.\n\t\t\t\tlog.Warningf(\"spn/navigator: %s\", err)\n\t\t\t}\n\t\t}\n\t\terr = Main.RegisterHubUpdateHook()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// TODO: delete superseded hubs after x amount of time\n\t\t_ = module.mgr.Delay(\"update states\", 3*time.Minute, Main.updateStates).Repeat(1 * time.Hour)\n\t\t_ = module.mgr.Delay(\"update failing states\", 3*time.Minute, Main.updateFailingStates).Repeat(1 * time.Minute)\n\n\t\tif conf.PublicHub() {\n\t\t\t// Only measure Hubs on public Hubs.\n\t\t\tmodule.mgr.Delay(\"measure hubs\", 5*time.Minute, Main.measureHubs).Repeat(1 * time.Minute)\n\n\t\t\t// Only register metrics on Hubs, as they only make sense there.\n\t\t\terr := registerMetrics()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n\n\treturn nil\n}\n\nfunc stop() error {\n\twithdrawMapDatabase()\n\n\tMain.CancelHubUpdateHook()\n\tMain.SaveMeasuredHubs()\n\tMain.Close()\n\n\treturn nil\n}\n\n// New returns a new Navigator module.\nfunc New(instance instance) (*Navigator, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Navigator\")\n\tmodule = &Navigator{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\tif err := prep(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/navigator/module_test.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/notifications\"\n\t\"github.com/safing/portmaster/service/configure\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/ui\"\n\t\"github.com/safing/portmaster/service/updates\"\n)\n\ntype testInstance struct {\n\tdb           *dbmodule.DBModule\n\tconfig       *config.Config\n\tintelUpdates *updates.Updater\n\tgeoip        *geoip.GeoIP\n}\n\nfunc (stub *testInstance) IntelUpdates() *updates.Updater              { return stub.intelUpdates }\nfunc (stub *testInstance) Config() *config.Config                      { return stub.config }\nfunc (stub *testInstance) Notifications() *notifications.Notifications { return nil }\nfunc (stub *testInstance) Ready() bool                                 { return true }\nfunc (stub *testInstance) Restart()                                    {}\nfunc (stub *testInstance) Shutdown()                                   {}\nfunc (stub *testInstance) SetCmdLineOperation(f func() error)          {}\nfunc (stub *testInstance) BinaryUpdates() *updates.Updater             { return nil }\nfunc (stub *testInstance) UI() *ui.UI                                  { return nil }\nfunc (stub *testInstance) DataDir() string                             { return _dataDir }\n\nvar _dataDir string\n\nfunc runTest(m *testing.M) error {\n\tvar err error\n\n\t// Create a temporary directory for testing\n\t_dataDir, err = os.MkdirTemp(\"\", \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temporary data directory: %w\", err)\n\t}\n\tdefer func() { _ = os.RemoveAll(_dataDir) }()\n\n\t// Initialize the Intel update configuration\n\tintelUpdateConfig := updates.Config{\n\t\tName:              configure.DefaultIntelIndexName,\n\t\tDirectory:         filepath.Join(_dataDir, \"test_intel\"),\n\t\tDownloadDirectory: filepath.Join(_dataDir, \"test_download_intel\"),\n\t\tPurgeDirectory:    filepath.Join(_dataDir, \"test_upgrade_obsolete_intel\"),\n\t\tIndexURLs:         configure.DefaultIntelIndexURLs,\n\t\tIndexFile:         \"index.json\",\n\t\tAutoCheck:         true,\n\t\tAutoDownload:      true,\n\t\tAutoApply:         true,\n\t}\n\n\t// Set the default API listen address\n\tapi.SetDefaultAPIListenAddress(\"0.0.0.0:8080\")\n\n\t// Initialize the instance with the necessary components\n\tstub := &testInstance{}\n\tlog.SetLogLevel(log.DebugLevel)\n\n\t// Init\n\tstub.db, err = dbmodule.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create db: %w\", err)\n\t}\n\tstub.config, err = config.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config: %w\", err)\n\t}\n\tstub.intelUpdates, err = updates.New(stub, \"Intel Updater\", intelUpdateConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create updates: %w\", err)\n\t}\n\tstub.geoip, err = geoip.New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create geoip: %w\", err)\n\t}\n\tmodule, err = New(stub)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create navigator module: %w\", err)\n\t}\n\t// Start\n\terr = stub.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start db module: %w\", err)\n\t}\n\terr = stub.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start config: %w\", err)\n\t}\n\terr = stub.intelUpdates.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start updates: %w\", err)\n\t}\n\terr = stub.geoip.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start geoip module: %w\", err)\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start navigator module: %w\", err)\n\t}\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tfmt.Printf(\"%s\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/optimize.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nconst (\n\toptimizationLowestCostConnections = 3\n\toptimizationHopDistanceTarget     = 3\n\twaitUntilMeasuredUpToPercent      = 0.5\n\n\tdesegrationAttemptBackoff = time.Hour\n)\n\n// Optimization Purposes.\nconst (\n\tOptimizePurposeBootstrap       = \"bootstrap\"\n\tOptimizePurposeDesegregate     = \"desegregate\"\n\tOptimizePurposeWait            = \"wait\"\n\tOptimizePurposeTargetStructure = \"target-structure\"\n)\n\n// AnalysisState holds state for analyzing the network for optimizations.\ntype AnalysisState struct { //nolint:maligned\n\t// Suggested signifies that a direct connection to this Hub is suggested by\n\t// the optimization algorithm.\n\tSuggested bool\n\n\t// SuggestedHopDistance holds the hop distance to this Hub when only\n\t// considering the suggested Hubs as connected.\n\tSuggestedHopDistance int\n\n\t// SuggestedHopDistanceInRegion holds the hop distance to this Hub in the\n\t// same region when only considering the suggested Hubs as connected.\n\tSuggestedHopDistanceInRegion int\n\n\t// CrossRegionalConnections holds the amount of connections a Pin has from\n\t// the current region.\n\tCrossRegionalConnections int\n\t// CrossRegionalLowestCostLane holds the lowest cost of the counted\n\t// connections from the current region.\n\tCrossRegionalLowestCostLane float32\n\t// CrossRegionalLaneCosts holds all the cross regional lane costs.\n\tCrossRegionalLaneCosts []float32\n\t// CrossRegionalHighestCostInHubLimit holds to highest cost of the lowest\n\t// cost connections within the maximum allowed lanes on a Hub from the\n\t// current region.\n\tCrossRegionalHighestCostInHubLimit float32\n}\n\n// initAnalysis creates all Pin.analysis fields.\n// The caller needs to hold the map and analysis lock..\nfunc (m *Map) initAnalysis(result *OptimizationResult) {\n\t// Compile lists of regarded pins.\n\tm.regardedPins = make([]*Pin, 0, len(m.all))\n\tfor _, region := range m.regions {\n\t\tregion.regardedPins = make([]*Pin, 0, len(m.all))\n\t}\n\t// Find all regarded pins.\n\tfor _, pin := range m.all {\n\t\tif result.matcher(pin) {\n\t\t\tm.regardedPins = append(m.regardedPins, pin)\n\t\t\t// Add to region.\n\t\t\tif pin.region != nil {\n\t\t\t\tpin.region.regardedPins = append(pin.region.regardedPins, pin)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Initialize analysis state.\n\tfor _, pin := range m.all {\n\t\tpin.analysis = &AnalysisState{}\n\t}\n}\n\n// clearAnalysis reset all Pin.analysis fields.\n// The caller needs to hold the map and analysis lock.\nfunc (m *Map) clearAnalysis() {\n\tm.regardedPins = nil\n\tfor _, region := range m.regions {\n\t\tregion.regardedPins = nil\n\t}\n\tfor _, pin := range m.all {\n\t\tpin.analysis = nil\n\t}\n}\n\n// OptimizationResult holds the result of an optimizaion analysis.\ntype OptimizationResult struct {\n\t// Purpose holds a semi-human readable constant of the optimization purpose.\n\tPurpose string\n\n\t// Approach holds human readable descriptions of how the stated purpose\n\t// should be achieved.\n\tApproach []string\n\n\t// SuggestedConnections holds the Hubs to which connections are suggested.\n\tSuggestedConnections []*SuggestedConnection\n\n\t// MaxConnect specifies how many connections should be created at maximum\n\t// based on this optimization.\n\tMaxConnect int\n\n\t// StopOthers specifies if other connections than the suggested ones may\n\t// be stopped.\n\tStopOthers bool\n\n\t// opts holds the options for matching Hubs in this optimization.\n\topts *HubOptions\n\n\t// matcher is the matcher used to create the regarded Pins.\n\t// Required for updating suggested hop distance.\n\tmatcher PinMatcher\n}\n\n// SuggestedConnection holds suggestions by the optimization system.\ntype SuggestedConnection struct {\n\t// Hub holds the Hub to which a connection is suggested.\n\tHub *hub.Hub\n\t// pin holds the Pin of the Hub.\n\tpin *Pin\n\t// Reason holds a reason why this connection is suggested.\n\tReason string\n\t// Duplicate marks duplicate entries. These should be ignored when\n\t// connecting, but are helpful for understand the optimization result.\n\tDuplicate bool\n}\n\nfunc (or *OptimizationResult) addApproach(description string) {\n\tor.Approach = append(or.Approach, description)\n}\n\nfunc (or *OptimizationResult) addSuggested(reason string, pins ...*Pin) {\n\tfor _, pin := range pins {\n\t\t// Mark as suggested.\n\t\tpin.analysis.Suggested = true\n\n\t\t// Check if this is a duplicate.\n\t\tvar duplicate bool\n\t\tfor _, sc := range or.SuggestedConnections {\n\t\t\tif pin.Hub.ID == sc.Hub.ID {\n\t\t\t\tduplicate = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// Add to suggested connections.\n\t\tor.SuggestedConnections = append(or.SuggestedConnections, &SuggestedConnection{\n\t\t\tHub:       pin.Hub,\n\t\t\tpin:       pin,\n\t\t\tReason:    reason,\n\t\t\tDuplicate: duplicate,\n\t\t})\n\n\t\t// Update hop distances if we have a matcher.\n\t\tif or.matcher != nil {\n\t\t\tor.markSuggestedReachable(pin, 2)\n\t\t\tor.markSuggestedReachableInRegion(pin, 2)\n\t\t}\n\t}\n}\n\nfunc (or *OptimizationResult) markSuggestedReachable(suggested *Pin, hopDistance int) {\n\t// Don't update if distance is greater or equal than current one.\n\tif hopDistance >= suggested.analysis.SuggestedHopDistance {\n\t\treturn\n\t}\n\n\t// Set suggested hop distance.\n\tsuggested.analysis.SuggestedHopDistance = hopDistance\n\n\t// Increase distance and apply to matching Pins.\n\thopDistance++\n\tfor _, lane := range suggested.ConnectedTo {\n\t\tif or.matcher(lane.Pin) {\n\t\t\tor.markSuggestedReachable(lane.Pin, hopDistance)\n\t\t}\n\t}\n}\n\n// Optimize analyzes the map and suggests changes.\nfunc (m *Map) Optimize(opts *HubOptions) (result *OptimizationResult, err error) {\n\tm.RLock()\n\tdefer m.RUnlock()\n\n\t// Check if the map is empty.\n\tif m.isEmpty() {\n\t\treturn nil, ErrEmptyMap\n\t}\n\n\t// Set default options if unset.\n\tif opts == nil {\n\t\topts = &HubOptions{}\n\t}\n\n\treturn m.optimize(opts)\n}\n\nfunc (m *Map) optimize(opts *HubOptions) (result *OptimizationResult, err error) {\n\tif m.home == nil {\n\t\treturn nil, ErrHomeHubUnset\n\t}\n\n\t// Set default options if unset.\n\tif opts == nil {\n\t\topts = &HubOptions{}\n\t}\n\n\t// Create result.\n\tresult = &OptimizationResult{\n\t\topts:    opts,\n\t\tmatcher: opts.Matcher(TransitHub, m.intel),\n\t}\n\n\t// Setup analyis.\n\tm.analysisLock.Lock()\n\tdefer m.analysisLock.Unlock()\n\tm.initAnalysis(result)\n\tdefer m.clearAnalysis()\n\n\t// Bootstrap to the network and desegregate map.\n\t// If there is a result, return it immediately.\n\treturnImmediately := m.optimizeForBootstrappingAndDesegregation(result)\n\tif returnImmediately {\n\t\treturn result, nil\n\t}\n\n\t// Check if we have the measurements we need.\n\tif m.measuringEnabled {\n\t\t// Cound pins with valid measurements.\n\t\tvar validMeasurements float32\n\t\tfor _, pin := range m.regardedPins {\n\t\t\tif pin.measurements.Valid() {\n\t\t\t\tvalidMeasurements++\n\t\t\t}\n\t\t}\n\n\t\t// If less than the required amount of regarded Pins have valid\n\t\t// measurements, let's wait until we have that.\n\t\tif validMeasurements/float32(len(m.regardedPins)) < waitUntilMeasuredUpToPercent {\n\t\t\treturn &OptimizationResult{\n\t\t\t\tPurpose:  OptimizePurposeWait,\n\t\t\t\tApproach: []string{\"Wait for measurements of 80% of regarded nodes for better optimization.\"},\n\t\t\t}, nil\n\t\t}\n\t}\n\n\t// Set default values for target structure optimization.\n\tresult.Purpose = OptimizePurposeTargetStructure\n\tresult.MaxConnect = 3\n\tresult.StopOthers = true\n\n\t// Optimize for lowest cost.\n\tm.optimizeForLowestCost(result, optimizationLowestCostConnections)\n\n\t// Optimize for lowest cost in region.\n\tm.optimizeForLowestCostInRegion(result)\n\n\t// Optimize for distance constraint in region.\n\tm.optimizeForDistanceConstraintInRegion(result, 3)\n\n\t// Optimize for region-to-region connectivity.\n\tm.optimizeForRegionConnectivity(result)\n\n\t// Optimize for satellite-to-region connectivity.\n\tm.optimizeForSatelliteConnectivity(result)\n\n\t// Lapse traffic stats after optimizing for good fresh data next time.\n\tfor _, crane := range docks.GetAllAssignedCranes() {\n\t\tcrane.NetState.LapsePeriod()\n\t}\n\n\t// Clean and return.\n\treturn result, nil\n}\n\nfunc (m *Map) optimizeForBootstrappingAndDesegregation(result *OptimizationResult) (returnImmediately bool) {\n\t// All regarded Pins are reachable.\n\treachable := len(m.regardedPins)\n\n\t// Count Pins that may be connectable.\n\tconnectable := make([]*Pin, 0, len(m.all))\n\t// Copy opts as we are going to make changes.\n\topts := result.opts.Copy()\n\topts.NoDefaults = true\n\topts.Regard = StateNone\n\topts.Disregard = StateSummaryDisregard\n\t// Collect Pins with matcher.\n\tmatcher := opts.Matcher(TransitHub, m.intel)\n\tfor _, pin := range m.all {\n\t\tif matcher(pin) {\n\t\t\tconnectable = append(connectable, pin)\n\t\t}\n\t}\n\n\tswitch {\n\tcase reachable == 0:\n\n\t\t// Sort by lowest cost.\n\t\tsort.Sort(sortByLowestMeasuredCost(connectable))\n\n\t\t// Return bootstrap optimization.\n\t\tresult.Purpose = OptimizePurposeBootstrap\n\t\tresult.Approach = []string{\"Connect to a near Hub to connect to the network.\"}\n\t\tresult.MaxConnect = 1\n\t\tresult.addSuggested(\"bootstrap\", connectable...)\n\t\treturn true\n\n\tcase reachable > len(connectable)/2:\n\t\t// We are part of the majority network, continue with regular optimization.\n\n\tcase time.Now().Add(-desegrationAttemptBackoff).Before(m.lastDesegrationAttempt):\n\t\t// We tried to desegregate recently, continue with regular optimization.\n\n\tdefault:\n\t\t// We are in a network comprised of less than half of the known nodes.\n\t\t// Attempt to connect to an unconnected one to desegregate the network.\n\n\t\t// Copy opts as we are going to make changes.\n\t\topts = opts.Copy()\n\t\topts.NoDefaults = true\n\t\topts.Regard = StateNone\n\t\topts.Disregard = StateSummaryDisregard | StateReachable\n\n\t\t// Iterate over all Pins to find any matching Pin.\n\t\tdesegregateWith := make([]*Pin, 0, len(m.all)-reachable)\n\t\tmatcher := opts.Matcher(TransitHub, m.intel)\n\t\tfor _, pin := range m.all {\n\t\t\tif matcher(pin) {\n\t\t\t\tdesegregateWith = append(desegregateWith, pin)\n\t\t\t}\n\t\t}\n\n\t\t// Sort by lowest connection cost.\n\t\tsort.Sort(sortByLowestMeasuredCost(desegregateWith))\n\n\t\t// Build desegration optimization.\n\t\tresult.Purpose = OptimizePurposeDesegregate\n\t\tresult.Approach = []string{\"Attempt to desegregate network by connection to an unreachable Hub.\"}\n\t\tresult.MaxConnect = 1\n\t\tresult.addSuggested(\"desegregate\", desegregateWith...)\n\n\t\t// Record desegregation attempt.\n\t\tm.lastDesegrationAttempt = time.Now()\n\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (m *Map) optimizeForLowestCost(result *OptimizationResult, max int) {\n\t// Add approach.\n\tresult.addApproach(fmt.Sprintf(\"Connect to best (lowest cost) %d Hubs globally.\", max))\n\n\t// Sort by lowest cost.\n\tsort.Sort(sortByLowestMeasuredCost(m.regardedPins))\n\n\t// Add to suggested pins.\n\tif len(m.regardedPins) <= max {\n\t\tresult.addSuggested(\"best globally\", m.regardedPins...)\n\t} else {\n\t\tresult.addSuggested(\"best globally\", m.regardedPins[:max]...)\n\t}\n}\n\nfunc (m *Map) optimizeForDistanceConstraint(result *OptimizationResult, max int) { //nolint:unused // TODO: Likely to be used again.\n\t// Add approach.\n\tresult.addApproach(fmt.Sprintf(\"Satisfy max hop constraint of %d globally.\", optimizationHopDistanceTarget))\n\n\tfor range max {\n\t\t// Sort by lowest cost.\n\t\tsort.Sort(sortBySuggestedHopDistanceAndLowestMeasuredCost(m.regardedPins))\n\n\t\t// Return when all regarded Pins are within the distance constraint.\n\t\tif m.regardedPins[0].analysis.SuggestedHopDistance <= optimizationHopDistanceTarget {\n\t\t\treturn\n\t\t}\n\n\t\t// If not, suggest a connection to the best match.\n\t\tresult.addSuggested(\"satisfy global hop constraint\", m.regardedPins[0])\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/optimize_region.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\nfunc (or *OptimizationResult) markSuggestedReachableInRegion(suggested *Pin, hopDistance int) {\n\t// Abort if suggested Pin has no region.\n\tif suggested.region == nil {\n\t\treturn\n\t}\n\n\t// Don't update if distance is greater or equal than current one.\n\tif hopDistance >= suggested.analysis.SuggestedHopDistanceInRegion {\n\t\treturn\n\t}\n\n\t// Set suggested hop distance.\n\tsuggested.analysis.SuggestedHopDistanceInRegion = hopDistance\n\n\t// Increase distance and apply to matching Pins.\n\thopDistance++\n\tfor _, lane := range suggested.ConnectedTo {\n\t\tif lane.Pin.region != nil &&\n\t\t\tlane.Pin.region.ID == suggested.region.ID &&\n\t\t\tor.matcher(lane.Pin) {\n\t\t\tor.markSuggestedReachableInRegion(lane.Pin, hopDistance)\n\t\t}\n\t}\n}\n\nfunc (m *Map) optimizeForLowestCostInRegion(result *OptimizationResult) {\n\tif m.home == nil || m.home.region == nil {\n\t\treturn\n\t}\n\tregion := m.home.region\n\n\t// Add approach.\n\tresult.addApproach(fmt.Sprintf(\"Connect to best (lowest cost) %d Hubs within the region.\", region.internalMinLanesOnHub))\n\n\t// Sort by lowest cost.\n\tsort.Sort(sortByLowestMeasuredCost(region.regardedPins))\n\n\t// Add to suggested pins.\n\tif len(region.regardedPins) <= region.internalMinLanesOnHub {\n\t\tresult.addSuggested(\"best in region\", region.regardedPins...)\n\t} else {\n\t\tresult.addSuggested(\"best in region\", region.regardedPins[:region.internalMinLanesOnHub]...)\n\t}\n}\n\nfunc (m *Map) optimizeForDistanceConstraintInRegion(result *OptimizationResult, max int) {\n\tif m.home == nil || m.home.region == nil {\n\t\treturn\n\t}\n\tregion := m.home.region\n\n\t// Add approach.\n\tresult.addApproach(fmt.Sprintf(\"Satisfy max hop constraint of %d within the region.\", region.internalMaxHops))\n\n\t// Sort by lowest cost.\n\tsort.Sort(sortBySuggestedHopDistanceInRegionAndLowestMeasuredCost(region.regardedPins))\n\n\tfor i := 0; i < max && i < len(region.regardedPins); i++ {\n\t\t// Return when all regarded Pins are within the distance constraint.\n\t\tif region.regardedPins[i].analysis.SuggestedHopDistanceInRegion <= region.internalMaxHops {\n\t\t\treturn\n\t\t}\n\n\t\t// If not, suggest a connection to the best match.\n\t\tresult.addSuggested(\"satisfy regional hop constraint\", region.regardedPins[i])\n\t}\n}\n\nfunc (m *Map) optimizeForRegionConnectivity(result *OptimizationResult) {\n\tif m.home == nil || m.home.region == nil {\n\t\treturn\n\t}\n\tregion := m.home.region\n\n\t// Add approach.\n\tresult.addApproach(\"Connect region to other regions.\")\n\n\t// Optimize for every region.\ncheckRegions:\n\tfor _, otherRegion := range m.regions {\n\t\t// Skip own region.\n\t\tif region.ID == otherRegion.ID {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Collect data on connections to that region.\n\t\tlanesToRegion, highestCostWithinLaneLimit := m.countConnectionsToRegion(result, region, otherRegion)\n\n\t\t// Sort by lowest cost.\n\t\tsort.Sort(sortByLowestMeasuredCost(otherRegion.regardedPins))\n\n\t\t// Find cheapest connections with a free slot or better values.\n\t\tvar lanesSuggested int\n\t\tfor _, pin := range otherRegion.regardedPins {\n\t\t\tmyCost := pin.measurements.GetCalculatedCost()\n\n\t\t\t// Check if we are done or region is satisfied.\n\t\t\tswitch {\n\t\t\tcase lanesSuggested >= region.regionalMaxLanesOnHub:\n\t\t\t\t// We hit our max.\n\t\t\t\tcontinue checkRegions\n\t\t\tcase lanesToRegion >= otherRegion.regionalMinLanes && myCost >= highestCostWithinLaneLimit:\n\t\t\t\t// Region has enough lanes and we are not better.\n\t\t\t\tcontinue checkRegions\n\t\t\t}\n\n\t\t\t// Check if we can contribute on this Pin.\n\t\t\tswitch {\n\t\t\tcase pin.analysis.CrossRegionalConnections < otherRegion.regionalMaxLanesOnHub &&\n\t\t\t\tlanesToRegion < otherRegion.regionalMinLanes:\n\t\t\t\t// There is a free spot on this Pin and the region needs more connections.\n\t\t\t\tresult.addSuggested(\"occupy cross-region lane on pin\", pin)\n\t\t\t\tlanesSuggested++\n\t\t\t\tlanesToRegion++\n\t\t\t\t// Because our own Pin is not counted, this should be the default\n\t\t\t\t// suggestion for a stable network.\n\n\t\t\tcase myCost < pin.analysis.CrossRegionalHighestCostInHubLimit:\n\t\t\t\t// We have a better connection to this Pin than at least one other existing connection (within the limit!).\n\t\t\t\tresult.addSuggested(\"replace cross-region lane on pin\", pin)\n\t\t\t\tlanesSuggested++\n\t\t\t\tlanesToRegion++\n\n\t\t\tcase myCost < highestCostWithinLaneLimit &&\n\t\t\t\tpin.analysis.CrossRegionalConnections < otherRegion.regionalMaxLanesOnHub:\n\t\t\t\t// We have a better connection to this Pin than another existing region-to-region connection.\n\t\t\t\tresult.addSuggested(\"replace unrelated cross-region lane\", pin)\n\t\t\t\tlanesSuggested++\n\t\t\t\tlanesToRegion++\n\t\t\t}\n\t\t}\n\t}\n}\n\n// countConnectionsToRegion analyzes existing lanes from this to another\n// region, with taking lanes from this Hub into account.\nfunc (m *Map) countConnectionsToRegion(result *OptimizationResult, region *Region, otherRegion *Region) (lanesToRegion int, highestCostWithinLaneLimit float32) {\n\tfor _, pin := range region.regardedPins {\n\t\t// Skip self.\n\t\tif m.home.Hub.ID == pin.Hub.ID {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Find lanes to other region.\n\t\tfor _, lane := range pin.ConnectedTo {\n\t\t\tif lane.Pin.region != nil &&\n\t\t\t\tlane.Pin.region.ID == otherRegion.ID &&\n\t\t\t\tresult.matcher(lane.Pin) {\n\t\t\t\t// This is a lane from this region to a regarded Pin in the other region.\n\t\t\t\tlanesToRegion++\n\n\t\t\t\t// Count cross region connection.\n\t\t\t\tlane.Pin.analysis.CrossRegionalConnections++\n\n\t\t\t\t// Collect lane costs.\n\t\t\t\tlane.Pin.analysis.CrossRegionalLaneCosts = append(\n\t\t\t\t\tlane.Pin.analysis.CrossRegionalLaneCosts,\n\t\t\t\t\tlane.Cost,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Calculate lane costs from collected lane costs.\n\tfor _, pin := range otherRegion.regardedPins {\n\t\tsort.Sort(sortCostsByLowest(pin.analysis.CrossRegionalLaneCosts))\n\t\tswitch {\n\t\tcase len(pin.analysis.CrossRegionalLaneCosts) == 0:\n\t\t\t// Nothing to do.\n\t\tcase len(pin.analysis.CrossRegionalLaneCosts) < otherRegion.regionalMaxLanesOnHub:\n\t\t\tpin.analysis.CrossRegionalLowestCostLane = pin.analysis.CrossRegionalLaneCosts[0]\n\t\t\tpin.analysis.CrossRegionalHighestCostInHubLimit = pin.analysis.CrossRegionalLaneCosts[len(pin.analysis.CrossRegionalLaneCosts)-1]\n\t\tdefault:\n\t\t\tpin.analysis.CrossRegionalLowestCostLane = pin.analysis.CrossRegionalLaneCosts[0]\n\t\t\tpin.analysis.CrossRegionalHighestCostInHubLimit = pin.analysis.CrossRegionalLaneCosts[otherRegion.regionalMaxLanesOnHub-1]\n\t\t}\n\n\t\t// Find highest cost within limit.\n\t\tif pin.analysis.CrossRegionalHighestCostInHubLimit > highestCostWithinLaneLimit {\n\t\t\thighestCostWithinLaneLimit = pin.analysis.CrossRegionalHighestCostInHubLimit\n\t\t}\n\t}\n\n\treturn lanesToRegion, highestCostWithinLaneLimit\n}\n\nfunc (m *Map) optimizeForSatelliteConnectivity(result *OptimizationResult) {\n\tif m.home == nil {\n\t\treturn\n\t}\n\t// This is only for Hubs that are not in a region.\n\tif m.home.region != nil {\n\t\treturn\n\t}\n\n\t// Add approach.\n\tresult.addApproach(\"Connect satellite to regions.\")\n\n\t// Optimize for every region.\n\tfor _, region := range m.regions {\n\t\t// Sort by lowest cost.\n\t\tsort.Sort(sortByLowestMeasuredCost(region.regardedPins))\n\n\t\t// Add to suggested pins.\n\t\tif len(region.regardedPins) <= region.satelliteMinLanes {\n\t\t\tresult.addSuggested(\"best to region \"+region.ID, region.regardedPins...)\n\t\t} else {\n\t\t\tresult.addSuggested(\"best to region \"+region.ID, region.regardedPins[:region.satelliteMinLanes]...)\n\t\t}\n\t}\n}\n\ntype sortCostsByLowest []float32\n\nfunc (a sortCostsByLowest) Len() int           { return len(a) }\nfunc (a sortCostsByLowest) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }\nfunc (a sortCostsByLowest) Less(i, j int) bool { return a[i] < a[j] }\n"
  },
  {
    "path": "spn/navigator/optimize_test.go",
    "content": "package navigator\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nvar (\n\toptimizedDefaultMapCreate sync.Once\n\toptimizedDefaultMap       *Map\n)\n\nfunc getOptimizedDefaultTestMap(t *testing.T) *Map {\n\tt.Helper()\n\n\toptimizedDefaultMapCreate.Do(func() {\n\t\toptimizedDefaultMap = createRandomTestMap(2, 100)\n\t\toptimizedDefaultMap.optimizeTestMap(t)\n\t})\n\treturn optimizedDefaultMap\n}\n\nfunc (m *Map) optimizeTestMap(t *testing.T) {\n\tt.Helper()\n\tt.Logf(\"optimizing test map %s with %d pins\", m.Name, len(m.all))\n\n\t// Save original Home, as we will be switching around the home for the\n\t// optimization.\n\trun := 0\n\tnewLanes := 0\n\toriginalHome := m.home\n\tmcf := newMeasurementCachedFactory()\n\n\tfor {\n\t\trun++\n\t\tnewLanesInRun := 0\n\t\t// Let's check if we have a run without any map changes.\n\t\tlastRun := true\n\n\t\tfor _, pin := range m.all {\n\t\t\t// Set Home to this Pin for this iteration.\n\t\t\tif !m.SetHome(pin.Hub.ID, nil) {\n\t\t\t\tpanic(\"failed to set home\")\n\t\t\t}\n\n\t\t\t// Update measurements for the new home.\n\t\t\tupdateMeasurements(m, mcf)\n\n\t\t\toptimizeResult, err := m.optimize(nil)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tlanesCreatedWithResult := 0\n\t\t\tfor _, connectTo := range optimizeResult.SuggestedConnections {\n\t\t\t\t// Check if lane to suggested Hub already exists.\n\t\t\t\tif m.home.Hub.GetLaneTo(connectTo.Hub.ID) != nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Add lanes to the Hub status.\n\t\t\t\t_ = m.home.Hub.AddLane(createLane(connectTo.Hub.ID))\n\t\t\t\t_ = connectTo.Hub.AddLane(createLane(m.home.Hub.ID))\n\n\t\t\t\t// Update Hubs in map.\n\t\t\t\tm.UpdateHub(m.home.Hub)\n\t\t\t\tm.UpdateHub(connectTo.Hub)\n\t\t\t\tnewLanes++\n\t\t\t\tnewLanesInRun++\n\n\t\t\t\t// We are changing the map in this run, so this is not the last.\n\t\t\t\tlastRun = false\n\n\t\t\t\t// Only create as many lanes as suggested by the result.\n\t\t\t\tlanesCreatedWithResult++\n\t\t\t\tif lanesCreatedWithResult >= optimizeResult.MaxConnect {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif optimizeResult.Purpose != OptimizePurposeTargetStructure {\n\t\t\t\t// If we aren't yet building the target structure, we need to keep building.\n\t\t\t\tlastRun = false\n\t\t\t}\n\t\t}\n\n\t\t// Log progress.\n\t\tif t != nil {\n\t\t\tt.Logf(\n\t\t\t\t\"optimizing: added %d lanes in run #%d (%d Hubs) - %d new lanes in total\",\n\t\t\t\tnewLanesInRun,\n\t\t\t\trun,\n\t\t\t\tlen(m.all),\n\t\t\t\tnewLanes,\n\t\t\t)\n\t\t}\n\n\t\t// End optimization after last run.\n\t\tif lastRun {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Log what was done and set home back to the original value.\n\tif t != nil {\n\t\tt.Logf(\"finished optimizing test map %s: added %d lanes in %d runs\", m.Name, newLanes, run)\n\t}\n\tm.home = originalHome\n}\n\nfunc TestOptimize(t *testing.T) {\n\tt.Parallel()\n\n\tm := getOptimizedDefaultTestMap(t)\n\tmatcher := m.defaultOptions().Destination.Matcher(m.intel)\n\toriginalHome := m.home\n\n\tfor _, pin := range m.all {\n\t\t// Set Home to this Pin for this iteration.\n\t\tm.home = pin\n\t\terr := m.recalculateReachableHubs()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tfor _, peer := range m.all {\n\t\t\t// Check if the Pin matches the criteria.\n\t\t\tif !matcher(peer) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// TODO: Adapt test to new regions.\n\t\t\tif peer.HopDistance > 5 {\n\t\t\t\tt.Errorf(\"Optimization error: %s is %d hops away from %s\", peer, peer.HopDistance, pin)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Print stats\n\tt.Logf(\"optimized map:\\n%s\\n\", m.Stats())\n\n\tm.home = originalHome\n}\n\nfunc updateMeasurements(m *Map, mcf *measurementCachedFactory) {\n\tfor _, pin := range m.all {\n\t\tpin.measurements = mcf.getOrCreate(m.home.Hub.ID, pin.Hub.ID)\n\t}\n}\n\ntype measurementCachedFactory struct {\n\tcache map[string]*hub.Measurements\n}\n\nfunc newMeasurementCachedFactory() *measurementCachedFactory {\n\treturn &measurementCachedFactory{\n\t\tcache: make(map[string]*hub.Measurements),\n\t}\n}\n\nfunc (mcf *measurementCachedFactory) getOrCreate(from, to string) *hub.Measurements {\n\tvar id string\n\tcomparison := strings.Compare(from, to)\n\tswitch {\n\tcase comparison == 0:\n\t\treturn nil\n\tcase comparison > 0:\n\t\tid = from + \"-\" + to\n\tcase comparison < 0:\n\t\tid = to + \"-\" + from\n\t}\n\n\tm, ok := mcf.cache[id]\n\tif ok {\n\t\treturn m\n\t}\n\n\tm = hub.NewMeasurements()\n\tm.Latency = createLatency()\n\tm.Capacity = createCapacity()\n\tm.CalculatedCost = CalculateLaneCost(\n\t\tm.Latency,\n\t\tm.Capacity,\n\t)\n\tmcf.cache[id] = m\n\treturn m\n}\n"
  },
  {
    "path": "spn/navigator/options.go",
    "content": "package navigator\n\nimport (\n\t\"context\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// HubType is the usage type of a Hub in routing.\ntype HubType uint8\n\n// Hub Types.\nconst (\n\tHomeHub HubType = iota\n\tTransitHub\n\tDestinationHub\n)\n\n// DeriveTunnelOptions derives and returns the tunnel options from the connection and profile.\n// This function lives in firewall/tunnel.go and is set here to avoid import loops.\nvar DeriveTunnelOptions func(lp *profile.LayeredProfile, destination *intel.Entity, connEncrypted bool) *Options\n\n// Options holds configuration options for operations with the Map.\ntype Options struct { //nolint:maligned\n\t// Home holds the options for Home Hubs.\n\tHome *HomeHubOptions\n\n\t// Transit holds the options for Transit Hubs.\n\tTransit *TransitHubOptions\n\n\t// Destination holds the options for Destination Hubs.\n\tDestination *DestinationHubOptions\n\n\t// RoutingProfile defines the algorithm to use to find a route.\n\tRoutingProfile string\n}\n\n// HomeHubOptions holds configuration options for Home Hub operations with the Map.\ntype HomeHubOptions HubOptions\n\n// TransitHubOptions holds configuration options for Transit Hub operations with the Map.\ntype TransitHubOptions HubOptions\n\n// DestinationHubOptions holds configuration options for Destination Hub operations with the Map.\ntype DestinationHubOptions HubOptions\n\n// HubOptions holds configuration options for a specific hub type for operations with the Map.\ntype HubOptions struct {\n\t// Regard holds required States. Only Hubs where all of these are present\n\t// will taken into account for the operation. If NoDefaults is not set, a\n\t// basic set of desirable states is added automatically.\n\tRegard PinState\n\n\t// Disregard holds disqualifying States. Only Hubs where none of these are\n\t// present will be taken into account for the operation. If NoDefaults is not\n\t// set, a basic set of undesirable states is added automatically.\n\tDisregard PinState\n\n\t// NoDefaults declares whether default and recommended Regard and Disregard states should not be used.\n\tNoDefaults bool\n\n\t// HubPolicies is a collection of endpoint lists that Hubs must pass in order\n\t// to be taken into account for the operation.\n\tHubPolicies []endpoints.Endpoints\n\n\t// RequireVerifiedOwners specifies which verified owners are allowed to be used.\n\t// If the list is empty, all owners are allowed.\n\tRequireVerifiedOwners []string\n\n\t// CheckHubPolicyWith provides an entity that must match the Hubs entry or exit\n\t// policy (depending on type) in order to be taken into account for the operation.\n\tCheckHubPolicyWith *intel.Entity\n}\n\n// Copy returns a shallow copy of the Options.\nfunc (o *Options) Copy() *Options {\n\tcopied := &Options{\n\t\tRoutingProfile: o.RoutingProfile,\n\t}\n\tif o.Home != nil {\n\t\tc := HomeHubOptions(HubOptions(*o.Home).Copy())\n\t\tcopied.Home = &c\n\t}\n\tif o.Transit != nil {\n\t\tc := TransitHubOptions(HubOptions(*o.Transit).Copy())\n\t\tcopied.Transit = &c\n\t}\n\tif o.Destination != nil {\n\t\tc := DestinationHubOptions(HubOptions(*o.Destination).Copy())\n\t\tcopied.Destination = &c\n\t}\n\treturn copied\n}\n\n// Copy returns a shallow copy of the Options.\nfunc (o HubOptions) Copy() HubOptions {\n\treturn HubOptions{\n\t\tRegard:                o.Regard,\n\t\tDisregard:             o.Disregard,\n\t\tNoDefaults:            o.NoDefaults,\n\t\tHubPolicies:           o.HubPolicies,\n\t\tRequireVerifiedOwners: o.RequireVerifiedOwners,\n\t\tCheckHubPolicyWith:    o.CheckHubPolicyWith,\n\t}\n}\n\n// PinMatcher is a stateful matching function generated by Options.\ntype PinMatcher func(pin *Pin) bool\n\n// DefaultOptions returns the default options for this Map.\nfunc (m *Map) DefaultOptions() *Options {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\treturn m.defaultOptions()\n}\n\nfunc (m *Map) defaultOptions() *Options {\n\topts := &Options{\n\t\tRoutingProfile: DefaultRoutingProfileID,\n\t}\n\n\treturn opts\n}\n\n// HubPoliciesAreSet returns whether any of the given hub policies are set and non-empty.\nfunc HubPoliciesAreSet(policies []endpoints.Endpoints) bool {\n\tfor _, policy := range policies {\n\t\tif policy.IsSet() {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nvar emptyHubOptions = &HubOptions{}\n\n// Matcher generates a PinMatcher based on the Options.\nfunc (o *HomeHubOptions) Matcher(hubIntel *hub.Intel) PinMatcher {\n\tif o == nil {\n\t\treturn emptyHubOptions.Matcher(HomeHub, hubIntel)\n\t}\n\n\t// Convert and call base func.\n\tho := HubOptions(*o)\n\treturn ho.Matcher(HomeHub, hubIntel)\n}\n\n// Matcher generates a PinMatcher based on the Options.\nfunc (o *TransitHubOptions) Matcher(hubIntel *hub.Intel) PinMatcher {\n\tif o == nil {\n\t\treturn emptyHubOptions.Matcher(TransitHub, hubIntel)\n\t}\n\n\t// Convert and call base func.\n\tho := HubOptions(*o)\n\treturn ho.Matcher(TransitHub, hubIntel)\n}\n\n// Matcher generates a PinMatcher based on the Options.\nfunc (o *DestinationHubOptions) Matcher(hubIntel *hub.Intel) PinMatcher {\n\tif o == nil {\n\t\treturn emptyHubOptions.Matcher(DestinationHub, hubIntel)\n\t}\n\n\t// Convert and call base func.\n\tho := HubOptions(*o)\n\treturn ho.Matcher(DestinationHub, hubIntel)\n}\n\n// Matcher generates a PinMatcher based on the Options.\n// Always use the Matcher on option structs if you can.\nfunc (o *Options) Matcher(hubType HubType, hubIntel *hub.Intel) PinMatcher {\n\tswitch hubType {\n\tcase HomeHub:\n\t\treturn o.Home.Matcher(hubIntel)\n\tcase TransitHub:\n\t\treturn o.Transit.Matcher(hubIntel)\n\tcase DestinationHub:\n\t\treturn o.Destination.Matcher(hubIntel)\n\tdefault:\n\t\treturn nil // This will panic, but should never be used.\n\t}\n}\n\n// Matcher generates a PinMatcher based on the Options.\nfunc (o *HubOptions) Matcher(hubType HubType, hubIntel *hub.Intel) PinMatcher {\n\t// Fallback to empty hub options.\n\tif o == nil {\n\t\to = emptyHubOptions\n\t}\n\n\t// Compile states to regard and disregard.\n\tregard := o.Regard\n\tdisregard := o.Disregard\n\n\t// Add default states.\n\tif !o.NoDefaults {\n\t\t// Add default States.\n\t\tregard = regard.Add(StateSummaryRegard)\n\t\tdisregard = disregard.Add(StateSummaryDisregard)\n\n\t\t// Add type based Advisories.\n\t\tswitch hubType {\n\t\tcase HomeHub:\n\t\t\t// Home Hubs don't need to be reachable and don't need keys ready to be used.\n\t\t\tregard = regard.Remove(StateReachable)\n\t\t\tregard = regard.Remove(StateActive)\n\t\t\t// Follow advisory.\n\t\t\tdisregard = disregard.Add(StateUsageAsHomeDiscouraged)\n\t\t\t// Home Hub may be the current Home Hub.\n\t\t\tdisregard = disregard.Remove(StateIsHomeHub)\n\t\tcase TransitHub:\n\t\t\t// Transit Hubs get no additional states.\n\t\tcase DestinationHub:\n\t\t\t// Follow advisory.\n\t\t\tdisregard = disregard.Add(StateUsageAsDestinationDiscouraged)\n\t\t\t// Do not use if Hub reports network issues.\n\t\t\tdisregard = disregard.Add(StateConnectivityIssues)\n\t\t}\n\t}\n\n\t// Add intel policies.\n\thubPolicies := o.HubPolicies\n\tif hubIntel != nil && hubIntel.Parsed() != nil {\n\t\tswitch hubType {\n\t\tcase HomeHub:\n\t\t\thubPolicies = append(hubPolicies, hubIntel.Parsed().HubAdvisory, hubIntel.Parsed().HomeHubAdvisory)\n\t\tcase TransitHub:\n\t\t\thubPolicies = append(hubPolicies, hubIntel.Parsed().HubAdvisory)\n\t\tcase DestinationHub:\n\t\t\thubPolicies = append(hubPolicies, hubIntel.Parsed().HubAdvisory, hubIntel.Parsed().DestinationHubAdvisory)\n\t\t}\n\t}\n\n\t// Add entry/exit policiy checks.\n\tcheckHubPolicyWith := o.CheckHubPolicyWith\n\n\treturn func(pin *Pin) bool {\n\t\t// Check required Pin States.\n\t\tif !pin.State.Has(regard) || pin.State.HasAnyOf(disregard) {\n\t\t\treturn false\n\t\t}\n\n\t\t// Check if all required states from intel were applied.\n\t\tif regard.HasAnyOf(StateSummaryStatusesAppliedFromIntel) || disregard.HasAnyOf(StateSummaryStatusesAppliedFromIntel) {\n\t\t\tif pin.stateIntelApplied.IsNotSet() {\n\t\t\t\tlog.Warningf(\"spn/navigator: pin %s skipped as intel statuses were not applied\", pin.Hub.ID)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\t// Check verified owners.\n\t\tif len(o.RequireVerifiedOwners) > 0 {\n\t\t\t// Check if Pin has a verified owner at all.\n\t\t\tif pin.VerifiedOwner == \"\" {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check if verified owner is in the list.\n\t\t\tinList := false\n\t\t\tfor _, allowed := range o.RequireVerifiedOwners {\n\t\t\t\tif pin.VerifiedOwner == allowed {\n\t\t\t\t\tinList = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Pin does not have a verified owner from the allowed list.\n\t\t\tif !inList {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\t// Check policies.\n\tpolicyCheck:\n\t\tfor _, policy := range hubPolicies {\n\t\t\t// Check if policy is set.\n\t\t\tif !policy.IsSet() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Check if policy matches.\n\t\t\tresult, reason := policy.MatchMulti(context.TODO(), pin.EntityV4, pin.EntityV6)\n\t\t\tswitch result {\n\t\t\tcase endpoints.NoMatch:\n\t\t\t\t// Continue with check.\n\t\t\tcase endpoints.MatchError:\n\t\t\t\tlog.Warningf(\"spn/navigator: failed to match policy: %s\", reason)\n\t\t\t\t// Continue with check for now.\n\t\t\t\t// TODO: Rethink how to do this. If eg. the geoip database has a\n\t\t\t\t// problem, then no Hub will match. For now, just continue to the\n\t\t\t\t// next rule set. Not optimal, but fail safe.\n\t\t\tcase endpoints.Denied:\n\t\t\t\t// Explicitly denied, abort immediately.\n\t\t\t\treturn false\n\t\t\tcase endpoints.Permitted:\n\t\t\t\t// Explicitly allowed, abort check and continue.\n\t\t\t\tbreak policyCheck\n\t\t\t}\n\t\t}\n\n\t\t// Check entry/exit policies.\n\t\tif checkHubPolicyWith != nil {\n\t\t\tswitch hubType {\n\t\t\tcase HomeHub:\n\t\t\t\tif endpointListMatch(pin.Hub.Info.EntryPolicy(), checkHubPolicyWith) == endpoints.Denied {\n\t\t\t\t\t// Hub does not allow entry from the given entity.\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\tcase TransitHub:\n\t\t\t\t// Transit Hubs do not have a hub policy.\n\t\t\tcase DestinationHub:\n\t\t\t\tif endpointListMatch(pin.Hub.Info.ExitPolicy(), checkHubPolicyWith) == endpoints.Denied {\n\t\t\t\t\t// Hub does not allow exit to the given entity.\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true // All checks have passed.\n\t}\n}\n\nfunc endpointListMatch(list endpoints.Endpoints, entity *intel.Entity) endpoints.EPResult {\n\t// Check if endpoint list and entity are available.\n\tif !list.IsSet() || entity == nil {\n\t\treturn endpoints.NoMatch\n\t}\n\n\t// Match and return result only.\n\tresult, _ := list.Match(context.TODO(), entity)\n\treturn result\n}\n"
  },
  {
    "path": "spn/navigator/pin.go",
    "content": "package navigator\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/spn/docks\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// Pin represents a Hub on a Map.\ntype Pin struct { //nolint:maligned\n\t// Hub Information\n\tHub        *hub.Hub\n\tEntityV4   *intel.Entity\n\tEntityV6   *intel.Entity\n\tLocationV4 *geoip.Location\n\tLocationV6 *geoip.Location\n\n\t// Hub Status\n\tState PinState\n\n\t// stateIntelApplied signifies that states from intel file were applied to the pin.\n\tstateIntelApplied *abool.AtomicBool\n\n\t// VerifiedOwner holds the name of the verified owner / operator of the Hub.\n\tVerifiedOwner string\n\t// HopDistance signifies the needed hops to reach this Hub.\n\t// HopDistance is measured from the view of a client.\n\t// A Hub itself will have itself at distance 1.\n\t// Directly connected Hubs have a distance of 2.\n\tHopDistance int\n\t// Cost is the routing cost of this Hub.\n\tCost float32\n\t// ConnectedTo holds validated lanes.\n\tConnectedTo map[string]*Lane // Key is Hub ID.\n\n\t// FailingUntil specifies until when this Hub should be regarded as failing.\n\t// This is connected to StateFailing.\n\tFailingUntil time.Time\n\n\t// Connection holds a information about a connection to the Hub of this Pin.\n\tConnection *PinConnection\n\n\t// Internal\n\n\t// pushChanges is set to true if something noteworthy on the Pin changed and\n\t// an update needs to be pushed by the database storage interface to whoever\n\t// is listening.\n\tpushChanges *abool.AtomicBool\n\n\t// measurements holds Measurements regarding this Pin.\n\t// It must always be set and the reference must not be changed when measuring\n\t// is enabled.\n\t// Access to fields within are coordinated by itself.\n\tmeasurements *hub.Measurements\n\n\t// analysis holds the analysis state.\n\t// Should only be set during analysis and be reset at the start and removed at the end of an analysis.\n\tanalysis *AnalysisState\n\n\t// region is the region this Pin belongs to.\n\tregion *Region\n}\n\n// PinConnection represents a connection to a terminal on the Hub.\ntype PinConnection struct {\n\t// Terminal holds the active terminal session.\n\tTerminal *docks.ExpansionTerminal\n\n\t// Route is the route built for this terminal.\n\tRoute *Route\n}\n\n// Lane is a connection to another Hub.\ntype Lane struct {\n\t// Pin is the Pin/Hub this Lane connects to.\n\tPin *Pin\n\n\t// Capacity designates the available bandwidth between these Hubs.\n\t// It is specified in bit/s.\n\tCapacity int\n\n\t// Lateny designates the latency between these Hubs.\n\t// It is specified in nanoseconds.\n\tLatency time.Duration\n\n\t// Cost is the routing cost of this lane.\n\tCost float32\n\n\t// active is a helper flag in order help remove abandoned Lanes.\n\tactive bool\n}\n\n// Lock locks the Pin via the Hub's lock.\nfunc (pin *Pin) Lock() {\n\tpin.Hub.Lock()\n}\n\n// Unlock unlocks the Pin via the Hub's lock.\nfunc (pin *Pin) Unlock() {\n\tpin.Hub.Unlock()\n}\n\n// String returns a human-readable representation of the Pin.\nfunc (pin *Pin) String() string {\n\treturn \"<Pin \" + pin.Hub.Name() + \">\"\n}\n\n// GetState returns the state of the pin.\nfunc (pin *Pin) GetState() PinState {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\treturn pin.State\n}\n\n// updateLocationData fetches the necessary location data in order to correctly map out the Pin.\nfunc (pin *Pin) updateLocationData() {\n\t// TODO: We are currently assigning the Hub ID to the entity domain to\n\t// support matching a Hub by its ID. The issue here is that the domain\n\t// rules are lower-cased, so we have to lower-case the ID here too.\n\t// This is not optimal from a security perspective, but there are still\n\t// enough bits left that this cannot be easily exploited.\n\n\tif pin.Hub.Info.IPv4 != nil {\n\t\tpin.EntityV4 = (&intel.Entity{\n\t\t\tIP:     pin.Hub.Info.IPv4,\n\t\t\tDomain: strings.ToLower(pin.Hub.ID) + \".\",\n\t\t}).Init(0)\n\n\t\tvar ok bool\n\t\tpin.LocationV4, ok = pin.EntityV4.GetLocation(context.TODO())\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/navigator: failed to get location of %s of %s\", pin.Hub.Info.IPv4, pin.Hub.StringWithoutLocking())\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tpin.EntityV4 = nil\n\t\tpin.LocationV4 = nil\n\t}\n\n\tif pin.Hub.Info.IPv6 != nil {\n\t\tpin.EntityV6 = (&intel.Entity{\n\t\t\tIP:     pin.Hub.Info.IPv6,\n\t\t\tDomain: strings.ToLower(pin.Hub.ID) + \".\",\n\t\t}).Init(0)\n\n\t\tvar ok bool\n\t\tpin.LocationV6, ok = pin.EntityV6.GetLocation(context.TODO())\n\t\tif !ok {\n\t\t\tlog.Warningf(\"spn/navigator: failed to get location of %s of %s\", pin.Hub.Info.IPv6, pin.Hub.StringWithoutLocking())\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tpin.EntityV6 = nil\n\t\tpin.LocationV6 = nil\n\t}\n}\n\n// GetLocation returns the geoip location of the Pin, preferring first the given IP, then IPv4.\nfunc (pin *Pin) GetLocation(ip net.IP) *geoip.Location {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\tswitch {\n\tcase ip != nil && ip.Equal(pin.Hub.Info.IPv4) && pin.LocationV4 != nil:\n\t\treturn pin.LocationV4\n\tcase ip != nil && ip.Equal(pin.Hub.Info.IPv6) && pin.LocationV6 != nil:\n\t\treturn pin.LocationV6\n\tcase pin.LocationV4 != nil:\n\t\treturn pin.LocationV4\n\tcase pin.LocationV6 != nil:\n\t\treturn pin.LocationV6\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// SetActiveTerminal sets an active terminal for the pin.\nfunc (pin *Pin) SetActiveTerminal(pc *PinConnection) {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\tpin.Connection = pc\n\tif pin.Connection != nil && pin.Connection.Terminal != nil {\n\t\tpin.Connection.Terminal.SetChangeNotifyFunc(pin.NotifyTerminalChange)\n\t}\n\n\tpin.pushChanges.Set()\n}\n\n// GetActiveTerminal returns the active terminal of the pin.\nfunc (pin *Pin) GetActiveTerminal() *docks.ExpansionTerminal {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\tif !pin.hasActiveTerminal() {\n\t\treturn nil\n\t}\n\treturn pin.Connection.Terminal\n}\n\n// HasActiveTerminal returns whether the Pin has an active terminal.\nfunc (pin *Pin) HasActiveTerminal() bool {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\treturn pin.hasActiveTerminal()\n}\n\nfunc (pin *Pin) hasActiveTerminal() bool {\n\treturn pin.Connection != nil &&\n\t\tpin.Connection.Terminal.Abandoning.IsNotSet()\n}\n\n// NotifyTerminalChange notifies subscribers of the changed terminal.\nfunc (pin *Pin) NotifyTerminalChange() {\n\tpin.pushChanges.Set()\n\tpin.pushChange()\n}\n\n// IsFailing returns whether the pin should be treated as failing.\n// The Pin is locked for this.\nfunc (pin *Pin) IsFailing() bool {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\treturn time.Now().Before(pin.FailingUntil)\n}\n\n// MarkAsFailingFor marks the pin as failing.\n// The Pin is locked for this.\n// Changes are pushed.\nfunc (pin *Pin) MarkAsFailingFor(duration time.Duration) {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\tuntil := time.Now().Add(duration)\n\t// Only ever increase failing until, never reduce.\n\tif until.After(pin.FailingUntil) {\n\t\tpin.FailingUntil = until\n\t}\n\n\tpin.addStates(StateFailing)\n\n\tpin.pushChanges.Set()\n\tpin.pushChange()\n}\n\n// ResetFailingState resets the failing state.\n// The Pin is locked for this.\n// Changes are not pushed, but Pins are marked.\nfunc (pin *Pin) ResetFailingState() {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\tif time.Now().Before(pin.FailingUntil) {\n\t\tpin.FailingUntil = time.Now()\n\t\tpin.pushChanges.Set()\n\t}\n\tif pin.State.Has(StateFailing) {\n\t\tpin.removeStates(StateFailing)\n\t\tpin.pushChanges.Set()\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/pin_export.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/service/intel\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// PinExport is the exportable version of a Pin.\ntype PinExport struct {\n\trecord.Base\n\tsync.Mutex\n\n\tID        string\n\tName      string\n\tMap       string\n\tFirstSeen time.Time\n\n\tEntityV4 *intel.Entity\n\tEntityV6 *intel.Entity\n\t// TODO: add coords\n\n\tStates        []string // From pin.State\n\tVerifiedOwner string\n\tHopDistance   int\n\n\tConnectedTo   map[string]*LaneExport // Key is Hub ID.\n\tRoute         []string               // Includes Home Hub and this Pin's ID.\n\tSessionActive bool\n\n\tInfo   *hub.Announcement\n\tStatus *hub.Status\n}\n\n// LaneExport is the exportable version of a Lane.\ntype LaneExport struct {\n\tHubID string\n\n\t// Capacity designates the available bandwidth between these Hubs.\n\t// It is specified in bit/s.\n\tCapacity int\n\n\t// Lateny designates the latency between these Hubs.\n\t// It is specified in nanoseconds.\n\tLatency time.Duration\n}\n\n// Export puts the Pin's information into an exportable format.\nfunc (pin *Pin) Export() *PinExport {\n\tpin.Lock()\n\tdefer pin.Unlock()\n\n\t// Shallow copy static values.\n\texport := &PinExport{\n\t\tID:            pin.Hub.ID,\n\t\tName:          pin.Hub.Info.Name,\n\t\tMap:           pin.Hub.Map,\n\t\tFirstSeen:     pin.Hub.FirstSeen,\n\t\tEntityV4:      pin.EntityV4,\n\t\tEntityV6:      pin.EntityV6,\n\t\tStates:        pin.State.Export(),\n\t\tVerifiedOwner: pin.VerifiedOwner,\n\t\tHopDistance:   pin.HopDistance,\n\t\tSessionActive: pin.hasActiveTerminal() || pin.State.Has(StateIsHomeHub),\n\t\tInfo:          pin.Hub.Info,   // Is updated as a whole, no need to copy.\n\t\tStatus:        pin.Hub.Status, // Is updated as a whole, no need to copy.\n\t}\n\n\t// Export lanes.\n\texport.ConnectedTo = make(map[string]*LaneExport, len(pin.ConnectedTo))\n\tfor key, lane := range pin.ConnectedTo {\n\t\texport.ConnectedTo[key] = &LaneExport{\n\t\t\tHubID:    lane.Pin.Hub.ID,\n\t\t\tCapacity: lane.Capacity,\n\t\t\tLatency:  lane.Latency,\n\t\t}\n\t}\n\n\t// Export route to Pin, if connected.\n\tif pin.Connection != nil && pin.Connection.Route != nil {\n\t\texport.Route = make([]string, len(pin.Connection.Route.Path))\n\t\tfor key, hop := range pin.Connection.Route.Path {\n\t\t\texport.Route[key] = hop.HubID\n\t\t}\n\t}\n\n\t// Create database record metadata.\n\texport.SetKey(makeDBKey(export.Map, export.ID))\n\texport.SetMeta(&record.Meta{\n\t\tCreated:  export.FirstSeen.Unix(),\n\t\tModified: time.Now().Unix(),\n\t})\n\n\treturn export\n}\n\n// HumanName returns a human-readable version of a Hub's name.\n// This name will likely consist of two parts: the given name and the ending of the ID to make it unique.\nfunc (h *PinExport) HumanName() string {\n\tif len(h.ID) < 8 {\n\t\treturn fmt.Sprintf(\"<Hub %s>\", h.ID)\n\t}\n\n\tshortenedID := h.ID[len(h.ID)-8:len(h.ID)-4] +\n\t\t\"-\" +\n\t\th.ID[len(h.ID)-4:]\n\n\t// Be more careful, as the Hub name is user input.\n\tswitch {\n\tcase h.Info.Name == \"\":\n\t\treturn fmt.Sprintf(\"<Hub %s>\", shortenedID)\n\tcase len(h.Info.Name) > 16:\n\t\treturn fmt.Sprintf(\"<Hub %s %s>\", h.Info.Name[:16], shortenedID)\n\tdefault:\n\t\treturn fmt.Sprintf(\"<Hub %s %s>\", h.Info.Name, shortenedID)\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/region.go",
    "content": "package navigator\n\nimport (\n\t\"context\"\n\t\"math\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/profile/endpoints\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nconst (\n\tdefaultRegionalMinLanesPerHub  = 0.5\n\tdefaultRegionalMaxLanesOnHub   = 2\n\tdefaultSatelliteMinLanesPerHub = 0.3\n\tdefaultInternalMinLanesOnHub   = 3\n\tdefaultInternalMaxHops         = 3\n)\n\n// Region specifies a group of Hubs for optimization purposes.\ntype Region struct {\n\tID           string\n\tName         string\n\tconfig       *hub.RegionConfig\n\tmemberPolicy endpoints.Endpoints\n\n\tpins         []*Pin\n\tregardedPins []*Pin\n\n\tregionalMinLanes      int\n\tregionalMaxLanesOnHub int\n\tsatelliteMinLanes     int\n\tinternalMinLanesOnHub int\n\tinternalMaxHops       int\n}\n\nfunc (region *Region) getName() string {\n\tswitch {\n\tcase region == nil:\n\t\treturn \"-\"\n\tcase region.Name != \"\":\n\t\treturn region.Name\n\tdefault:\n\t\treturn region.ID\n\t}\n}\n\nfunc (m *Map) updateRegions(config []*hub.RegionConfig) {\n\t// Reset map and pins.\n\tm.regions = make([]*Region, 0, len(config))\n\tfor _, pin := range m.all {\n\t\tpin.region = nil\n\t}\n\n\t// Stop if not regions are defined.\n\tif len(config) == 0 {\n\t\treturn\n\t}\n\n\t// Build regions from config.\n\tfor _, regionConfig := range config {\n\t\t// Check if region has an ID.\n\t\tif regionConfig.ID == \"\" {\n\t\t\tlog.Error(\"spn/navigator: region is missing ID\")\n\t\t\t// Abort adding this region to the map.\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create new region.\n\t\tregion := &Region{\n\t\t\tID:     regionConfig.ID,\n\t\t\tName:   regionConfig.Name,\n\t\t\tconfig: regionConfig,\n\t\t}\n\n\t\t// Parse member policy.\n\t\tif len(regionConfig.MemberPolicy) == 0 {\n\t\t\tlog.Errorf(\"spn/navigator: member policy of region %s is missing\", region.ID)\n\t\t\t// Abort adding this region to the map.\n\t\t\tcontinue\n\t\t}\n\t\tmemberPolicy, err := endpoints.ParseEndpoints(regionConfig.MemberPolicy)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"spn/navigator: failed to parse member policy of region %s: %s\", region.ID, err)\n\t\t\t// Abort adding this region to the map.\n\t\t\tcontinue\n\t\t}\n\t\tregion.memberPolicy = memberPolicy\n\n\t\t// Recalculate region properties.\n\t\tregion.recalculateProperties()\n\n\t\t// Add region to map.\n\t\tm.regions = append(m.regions, region)\n\t}\n\n\t// Update region in all Pins.\n\tfor _, pin := range m.all {\n\t\tm.updatePinRegion(pin)\n\t}\n}\n\nfunc (region *Region) addPin(pin *Pin) {\n\t// Find pin in region.\n\tfor _, regionPin := range region.pins {\n\t\tif pin.Hub.ID == regionPin.Hub.ID {\n\t\t\t// Pin is already part of region.\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Check if pin is already part of this region.\n\tif pin.region != nil && pin.region.ID == region.ID {\n\t\treturn\n\t}\n\n\t// Remove pin from previous region.\n\tif pin.region != nil {\n\t\tpin.region.removePin(pin)\n\t}\n\n\t// Add new pin to region.\n\tregion.pins = append(region.pins, pin)\n\tpin.region = region\n\n\t// Recalculate region properties.\n\tregion.recalculateProperties()\n}\n\nfunc (region *Region) removePin(pin *Pin) {\n\t// Find pin index in region.\n\tremoveIndex := -1\n\tfor index, regionPin := range region.pins {\n\t\tif pin.Hub.ID == regionPin.Hub.ID {\n\t\t\tremoveIndex = index\n\t\t\tbreak\n\t\t}\n\t}\n\tif removeIndex < 0 {\n\t\t// Pin is not part of region.\n\t\treturn\n\t}\n\n\t// Remove pin from region.\n\tregion.pins = append(region.pins[:removeIndex], region.pins[removeIndex+1:]...)\n\n\t// Recalculate region properties.\n\tregion.recalculateProperties()\n}\n\nfunc (region *Region) recalculateProperties() {\n\t// Regional properties.\n\tregion.regionalMinLanes = calculateMinLanes(\n\t\tlen(region.pins),\n\t\tregion.config.RegionalMinLanes,\n\t\tregion.config.RegionalMinLanesPerHub,\n\t\tdefaultRegionalMinLanesPerHub,\n\t)\n\tregion.regionalMaxLanesOnHub = region.config.RegionalMaxLanesOnHub\n\tif region.regionalMaxLanesOnHub <= 0 {\n\t\tregion.regionalMaxLanesOnHub = defaultRegionalMaxLanesOnHub\n\t}\n\n\t// Satellite properties.\n\tregion.satelliteMinLanes = calculateMinLanes(\n\t\tlen(region.pins),\n\t\tregion.config.SatelliteMinLanes,\n\t\tregion.config.SatelliteMinLanesPerHub,\n\t\tdefaultSatelliteMinLanesPerHub,\n\t)\n\n\t// Internal properties.\n\tregion.internalMinLanesOnHub = region.config.InternalMinLanesOnHub\n\tif region.internalMinLanesOnHub <= 0 {\n\t\tregion.internalMinLanesOnHub = defaultInternalMinLanesOnHub\n\t}\n\tregion.internalMaxHops = region.config.InternalMaxHops\n\tif region.internalMaxHops <= 0 {\n\t\tregion.internalMaxHops = defaultInternalMaxHops\n\t}\n\t// Values below 2 do not make any sense for max hops.\n\tif region.internalMaxHops < 2 {\n\t\tregion.internalMaxHops = 2\n\t}\n}\n\nfunc calculateMinLanes(regionHubCount, minLanes int, minLanesPerHub, defaultMinLanesPerHub float64) (minLaneCount int) {\n\t// Validate hub count.\n\tif regionHubCount <= 0 {\n\t\t// Reset to safe value.\n\t\tregionHubCount = 1\n\t}\n\n\t// Set to configured minimum lanes.\n\tminLaneCount = minLanes\n\n\t// Raise to configured minimum lanes per Hub.\n\tif minLanesPerHub != 0 {\n\t\tminLanesFromSize := int(math.Ceil(float64(regionHubCount) * minLanesPerHub))\n\t\tif minLanesFromSize > minLaneCount {\n\t\t\tminLaneCount = minLanesFromSize\n\t\t}\n\t}\n\n\t// Raise to default minimum lanes per Hub, if still 0.\n\tif minLaneCount <= 0 {\n\t\tminLaneCount = int(math.Ceil(float64(regionHubCount) * defaultMinLanesPerHub))\n\t}\n\n\treturn minLaneCount\n}\n\nfunc (m *Map) updatePinRegion(pin *Pin) {\n\tfor _, region := range m.regions {\n\t\t// Check if pin matches the region's member policy.\n\t\tif pin.EntityV4 != nil {\n\t\t\tresult, _ := region.memberPolicy.Match(context.TODO(), pin.EntityV4)\n\t\t\tif result == endpoints.Permitted {\n\t\t\t\tregion.addPin(pin)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif pin.EntityV6 != nil {\n\t\t\tresult, _ := region.memberPolicy.Match(context.TODO(), pin.EntityV6)\n\t\t\tif result == endpoints.Permitted {\n\t\t\t\tregion.addPin(pin)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/route.go",
    "content": "package navigator\n\nimport (\n\t\"fmt\"\n\tmrand \"math/rand\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Routes holds a collection of Routes.\ntype Routes struct {\n\tAll                 []*Route\n\trandomizeTopPercent float32\n\tmaxCost             float32 // automatic\n\tmaxRoutes           int     // manual setting\n}\n\n// Len is the number of elements in the collection.\nfunc (r *Routes) Len() int {\n\treturn len(r.All)\n}\n\n// Less reports whether the element with index i should sort before the element\n// with index j.\nfunc (r *Routes) Less(i, j int) bool {\n\treturn r.All[i].TotalCost < r.All[j].TotalCost\n}\n\n// Swap swaps the elements with indexes i and j.\nfunc (r *Routes) Swap(i, j int) {\n\tr.All[i], r.All[j] = r.All[j], r.All[i]\n}\n\n// isGoodEnough reports whether the route would survive a clean process.\nfunc (r *Routes) isGoodEnough(route *Route) bool {\n\tif r.maxCost > 0 && route.TotalCost > r.maxCost {\n\t\treturn false\n\t}\n\treturn true\n}\n\n// add adds a Route if it is good enough.\nfunc (r *Routes) add(route *Route) {\n\tif !r.isGoodEnough(route) {\n\t\treturn\n\t}\n\tr.All = append(r.All, route.CopyUpTo(0))\n\tr.clean()\n}\n\n// clean sort and shortens the list to the configured maximum.\nfunc (r *Routes) clean() {\n\t// Sort Routes so that the best ones are on top.\n\tsort.Sort(r)\n\t// Remove all remaining from the list.\n\tif len(r.All) > r.maxRoutes {\n\t\tr.All = r.All[:r.maxRoutes]\n\t}\n\t// Set new maximum total cost.\n\tif len(r.All) >= r.maxRoutes {\n\t\tr.maxCost = r.All[len(r.All)-1].TotalCost\n\t}\n}\n\n// randomizeTop randomized to the top nearest pins for balancing the network.\nfunc (r *Routes) randomizeTop() {\n\tswitch {\n\tcase r.randomizeTopPercent == 0:\n\t\t// Check if randomization is enabled.\n\t\treturn\n\tcase len(r.All) < 2:\n\t\t// Check if we have enough pins to work with.\n\t\treturn\n\t}\n\n\t// Find randomization set.\n\trandomizeUpTo := len(r.All)\n\tthreshold := r.All[0].TotalCost * (1 + r.randomizeTopPercent)\n\tfor i, r := range r.All {\n\t\t// Find first value above the threshold to stop.\n\t\tif r.TotalCost > threshold {\n\t\t\trandomizeUpTo = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Shuffle top set.\n\tif randomizeUpTo >= 2 {\n\t\tmr := mrand.New(mrand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\t\tmr.Shuffle(randomizeUpTo, r.Swap)\n\t}\n}\n\n// Route is a path through the map.\ntype Route struct {\n\t// Path is a list of Transit Hubs and the Destination Hub, including the Cost\n\t// for each Hop.\n\tPath []*Hop\n\n\t// DstCost is the calculated cost between the Destination Hub and the destination IP.\n\tDstCost float32\n\n\t// TotalCost is the sum of all costs of this Route.\n\tTotalCost float32\n\n\t// Algorithm is the ID of the algorithm used to calculate the route.\n\tAlgorithm string\n}\n\n// Hop is one hop of a route's path.\ntype Hop struct {\n\tpin *Pin\n\n\t// HubID is the Hub ID.\n\tHubID string\n\n\t// Cost is the cost for both Lane to this Hub and the Hub itself.\n\tCost float32\n}\n\n// addHop adds a hop to the route.\nfunc (r *Route) addHop(pin *Pin, cost float32) {\n\tr.Path = append(r.Path, &Hop{\n\t\tpin:  pin,\n\t\tCost: cost,\n\t})\n\tr.recalculateTotalCost()\n}\n\n// completeRoute completes the route by adding the destination cost of the\n// connection between the last hop and the destination IP.\nfunc (r *Route) completeRoute(dstCost float32) {\n\tr.DstCost = dstCost\n\tr.recalculateTotalCost()\n}\n\n// removeHop removes the last hop from the Route.\nfunc (r *Route) removeHop() {\n\t// Reset DstCost, as the route might have been completed.\n\tr.DstCost = 0\n\n\tif len(r.Path) >= 1 {\n\t\tr.Path = r.Path[:len(r.Path)-1]\n\t}\n\tr.recalculateTotalCost()\n}\n\n// recalculateTotalCost recalculates to total cost of this route.\nfunc (r *Route) recalculateTotalCost() {\n\tr.TotalCost = r.DstCost\n\tfor _, hop := range r.Path {\n\t\tif hop.pin.HasActiveTerminal() {\n\t\t\t// If we have an active connection, only take 80% of the cost.\n\t\t\tr.TotalCost += hop.Cost * 0.8\n\t\t} else {\n\t\t\tr.TotalCost += hop.Cost\n\t\t}\n\t}\n}\n\n// CopyUpTo makes a somewhat deep copy of the Route up to the specified amount\n// and returns it. Hops themselves are not copied, because their data does not\n// change. Therefore, returned Hops may not be edited.\n// Specify an amount of 0 to copy all.\nfunc (r *Route) CopyUpTo(n int) *Route {\n\t// Check amount.\n\tif n == 0 || n > len(r.Path) {\n\t\tn = len(r.Path)\n\t}\n\n\tnewRoute := &Route{\n\t\tPath:      make([]*Hop, n),\n\t\tDstCost:   r.DstCost,\n\t\tTotalCost: r.TotalCost,\n\t}\n\tcopy(newRoute.Path, r.Path)\n\treturn newRoute\n}\n\n// makeExportReady fills in all the missing data fields which are meant for\n// exporting only.\nfunc (r *Routes) makeExportReady(algorithm string) {\n\tfor _, route := range r.All {\n\t\troute.makeExportReady(algorithm)\n\t}\n}\n\n// makeExportReady fills in all the missing data fields which are meant for\n// exporting only.\nfunc (r *Route) makeExportReady(algorithm string) {\n\tr.Algorithm = algorithm\n\tfor _, hop := range r.Path {\n\t\thop.makeExportReady()\n\t}\n}\n\n// makeExportReady fills in all the missing data fields which are meant for\n// exporting only.\nfunc (hop *Hop) makeExportReady() {\n\thop.HubID = hop.pin.Hub.ID\n}\n\n// Pin returns the Pin of the Hop.\nfunc (hop *Hop) Pin() *Pin {\n\treturn hop.pin\n}\n\nfunc (r *Route) String() string {\n\ts := make([]string, 0, len(r.Path)+2)\n\ts = append(s, fmt.Sprintf(\"route with %.2fc:\", r.TotalCost))\n\tfor i, hop := range r.Path {\n\t\tif i == 0 {\n\t\t\ts = append(s, hop.pin.String())\n\t\t} else {\n\t\t\ts = append(s, fmt.Sprintf(\"--> %.2fc %s\", hop.Cost, hop.pin))\n\t\t}\n\t}\n\ts = append(s, fmt.Sprintf(\"--> %.2fc\", r.DstCost))\n\treturn strings.Join(s, \" \")\n}\n"
  },
  {
    "path": "spn/navigator/routing-profiles.go",
    "content": "package navigator\n\nimport (\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/profile\"\n)\n\n// RoutingProfile defines a routing algorithm with some options.\ntype RoutingProfile struct {\n\tID string\n\n\t// Name is the human readable name of the profile.\n\tName string\n\n\t// MinHops defines how many hops a route must have at minimum. In order to\n\t// reduce confusion, the Home Hub is also counted.\n\tMinHops int\n\n\t// MaxHops defines the limit on how many hops a route may have. In order to\n\t// reduce confusion, the Home Hub is also counted.\n\tMaxHops int\n\n\t// MaxExtraHops sets a limit on how many extra hops are allowed in addition\n\t// to the amount of Hops in the currently best route. This is an optimization\n\t// option and should not interfere with finding the best route, but might\n\t// reduce the amount of routes found.\n\tMaxExtraHops int\n\n\t// MaxExtraCost sets a limit on the extra cost allowed in addition to the\n\t// cost of the currently best route. This is an optimization option and\n\t// should not interfere with finding the best route, but might reduce the\n\t// amount of routes found.\n\tMaxExtraCost float32\n}\n\n// Routing Profile Names.\nconst (\n\tRoutingProfileHomeID      = \"home\"\n\tRoutingProfileSingleHopID = \"single-hop\"\n\tRoutingProfileDoubleHopID = \"double-hop\"\n\tRoutingProfileTripleHopID = \"triple-hop\"\n)\n\n// Routing Profiles.\nvar (\n\tDefaultRoutingProfileID = profile.DefaultRoutingProfileID\n\n\tRoutingProfileHome = &RoutingProfile{\n\t\tID:      \"home\",\n\t\tName:    \"Plain VPN Mode\",\n\t\tMinHops: 1,\n\t\tMaxHops: 1,\n\t}\n\tRoutingProfileSingleHop = &RoutingProfile{\n\t\tID:           \"single-hop\",\n\t\tName:         \"Speed Focused\",\n\t\tMinHops:      1,\n\t\tMaxHops:      3,\n\t\tMaxExtraHops: 1,\n\t\tMaxExtraCost: 10000,\n\t}\n\tRoutingProfileDoubleHop = &RoutingProfile{\n\t\tID:           \"double-hop\",\n\t\tName:         \"Balanced\",\n\t\tMinHops:      2,\n\t\tMaxHops:      4,\n\t\tMaxExtraHops: 2,\n\t\tMaxExtraCost: 10000,\n\t}\n\tRoutingProfileTripleHop = &RoutingProfile{\n\t\tID:           \"triple-hop\",\n\t\tName:         \"Privacy Focused\",\n\t\tMinHops:      3,\n\t\tMaxHops:      5,\n\t\tMaxExtraHops: 3,\n\t\tMaxExtraCost: 10000,\n\t}\n)\n\n// GetRoutingProfile returns the routing profile with the given ID.\nfunc GetRoutingProfile(id string) *RoutingProfile {\n\tswitch id {\n\tcase RoutingProfileHomeID:\n\t\treturn RoutingProfileHome\n\tcase RoutingProfileSingleHopID:\n\t\treturn RoutingProfileSingleHop\n\tcase RoutingProfileDoubleHopID:\n\t\treturn RoutingProfileDoubleHop\n\tcase RoutingProfileTripleHopID:\n\t\treturn RoutingProfileTripleHop\n\tdefault:\n\t\treturn RoutingProfileDoubleHop\n\t}\n}\n\ntype routeCompliance uint8\n\nconst (\n\trouteOk           routeCompliance = iota // Route is fully compliant and can be used.\n\trouteNonCompliant                        // Route is not compliant, but this might change if more hops are added.\n\trouteDisqualified                        // Route is disqualified and won't be able to become compliant.\n)\n\nfunc (rp *RoutingProfile) checkRouteCompliance(route *Route, foundRoutes *Routes) routeCompliance {\n\tswitch {\n\tcase len(route.Path) < rp.MinHops:\n\t\t// Route is shorter than the defined minimum.\n\t\treturn routeNonCompliant\n\tcase len(route.Path) > rp.MaxHops:\n\t\t// Route is longer than the defined maximum.\n\t\treturn routeDisqualified\n\t}\n\n\t// Check for hub re-use.\n\tif len(route.Path) >= 2 {\n\t\tlastHop := route.Path[len(route.Path)-1]\n\t\tfor _, hop := range route.Path[:len(route.Path)-1] {\n\t\t\tif lastHop.pin.Hub.ID == hop.pin.Hub.ID {\n\t\t\t\treturn routeDisqualified\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check if hub is already in use, if so check if the route matches.\n\tif len(route.Path) >= 2 {\n\t\t// Get active connection to the last pin of the current path.\n\t\tlastPinConnection := route.Path[len(route.Path)-1].pin.Connection\n\n\t\tswitch {\n\t\tcase lastPinConnection == nil:\n\t\t\t// Last pin is not yet connected.\n\t\tcase len(lastPinConnection.Route.Path) < 2:\n\t\t\t// Path of last pin does not have enough hops.\n\t\t\t// This is unexpected and should not happen.\n\t\t\tlog.Errorf(\n\t\t\t\t\"navigator: expected active connection to %s to have 2 hops or more on path, but it had %d\",\n\t\t\t\troute.Path[len(route.Path)-1].pin.Hub.StringWithoutLocking(),\n\t\t\t\tlen(lastPinConnection.Route.Path),\n\t\t\t)\n\t\tcase lastPinConnection.Route.Path[len(lastPinConnection.Route.Path)-2].pin.Hub.ID != route.Path[len(route.Path)-2].pin.Hub.ID:\n\t\t\t// The previous hop of the existing route and the one we are evaluating don't match.\n\t\t\t// Currently, we only allow one session per Hub.\n\t\t\treturn routeDisqualified\n\t\t}\n\t}\n\n\t// Abort route exploration when we are outside the optimization boundaries.\n\tif len(foundRoutes.All) > 0 {\n\t\t// Get the best found route.\n\t\tbest := foundRoutes.All[0]\n\t\t// Abort if current route exceeds max extra costs.\n\t\tif route.TotalCost > best.TotalCost+rp.MaxExtraCost {\n\t\t\treturn routeDisqualified\n\t\t}\n\t\t// Abort if current route exceeds max extra hops.\n\t\tif len(route.Path) > len(best.Path)+rp.MaxExtraHops {\n\t\t\treturn routeDisqualified\n\t\t}\n\t}\n\n\treturn routeOk\n}\n"
  },
  {
    "path": "spn/navigator/sort.go",
    "content": "package navigator\n\ntype sortByPinID []*Pin\n\nfunc (a sortByPinID) Len() int           { return len(a) }\nfunc (a sortByPinID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }\nfunc (a sortByPinID) Less(i, j int) bool { return a[i].Hub.ID < a[j].Hub.ID }\n\ntype sortByLowestMeasuredCost []*Pin\n\nfunc (a sortByLowestMeasuredCost) Len() int      { return len(a) }\nfunc (a sortByLowestMeasuredCost) Swap(i, j int) { a[i], a[j] = a[j], a[i] }\nfunc (a sortByLowestMeasuredCost) Less(i, j int) bool {\n\tx := a[i].measurements.GetCalculatedCost()\n\ty := a[j].measurements.GetCalculatedCost()\n\tif x != y {\n\t\treturn x < y\n\t}\n\n\t// Fall back to geo proximity.\n\tgx := a[i].measurements.GetGeoProximity()\n\tgy := a[j].measurements.GetGeoProximity()\n\tif gx != gy {\n\t\treturn gx > gy\n\t}\n\n\t// Fall back to Hub ID.\n\treturn a[i].Hub.ID < a[j].Hub.ID\n}\n\ntype sortBySuggestedHopDistanceAndLowestMeasuredCost []*Pin\n\nfunc (a sortBySuggestedHopDistanceAndLowestMeasuredCost) Len() int      { return len(a) }\nfunc (a sortBySuggestedHopDistanceAndLowestMeasuredCost) Swap(i, j int) { a[i], a[j] = a[j], a[i] }\nfunc (a sortBySuggestedHopDistanceAndLowestMeasuredCost) Less(i, j int) bool {\n\t// First sort by suggested hop distance.\n\tif a[i].analysis.SuggestedHopDistance != a[j].analysis.SuggestedHopDistance {\n\t\treturn a[i].analysis.SuggestedHopDistance > a[j].analysis.SuggestedHopDistance\n\t}\n\n\t// Then by cost.\n\tx := a[i].measurements.GetCalculatedCost()\n\ty := a[j].measurements.GetCalculatedCost()\n\tif x != y {\n\t\treturn x < y\n\t}\n\n\t// Fall back to geo proximity.\n\tgx := a[i].measurements.GetGeoProximity()\n\tgy := a[j].measurements.GetGeoProximity()\n\tif gx != gy {\n\t\treturn gx > gy\n\t}\n\n\t// Fall back to Hub ID.\n\treturn a[i].Hub.ID < a[j].Hub.ID\n}\n\ntype sortBySuggestedHopDistanceInRegionAndLowestMeasuredCost []*Pin\n\nfunc (a sortBySuggestedHopDistanceInRegionAndLowestMeasuredCost) Len() int { return len(a) }\nfunc (a sortBySuggestedHopDistanceInRegionAndLowestMeasuredCost) Swap(i, j int) {\n\ta[i], a[j] = a[j], a[i]\n}\n\nfunc (a sortBySuggestedHopDistanceInRegionAndLowestMeasuredCost) Less(i, j int) bool {\n\t// First sort by suggested hop distance.\n\tif a[i].analysis.SuggestedHopDistanceInRegion != a[j].analysis.SuggestedHopDistanceInRegion {\n\t\treturn a[i].analysis.SuggestedHopDistanceInRegion > a[j].analysis.SuggestedHopDistanceInRegion\n\t}\n\n\t// Then by cost.\n\tx := a[i].measurements.GetCalculatedCost()\n\ty := a[j].measurements.GetCalculatedCost()\n\tif x != y {\n\t\treturn x < y\n\t}\n\n\t// Fall back to geo proximity.\n\tgx := a[i].measurements.GetGeoProximity()\n\tgy := a[j].measurements.GetGeoProximity()\n\tif gx != gy {\n\t\treturn gx > gy\n\t}\n\n\t// Fall back to Hub ID.\n\treturn a[i].Hub.ID < a[j].Hub.ID\n}\n\ntype sortByLowestMeasuredLatency []*Pin\n\nfunc (a sortByLowestMeasuredLatency) Len() int      { return len(a) }\nfunc (a sortByLowestMeasuredLatency) Swap(i, j int) { a[i], a[j] = a[j], a[i] }\nfunc (a sortByLowestMeasuredLatency) Less(i, j int) bool {\n\tx, _ := a[i].measurements.GetLatency()\n\ty, _ := a[j].measurements.GetLatency()\n\tswitch {\n\tcase x == y:\n\t\t// Go to fallbacks.\n\tcase x == 0:\n\t\t// Ignore zero values.\n\t\treturn false // j/y is better.\n\tcase y == 0:\n\t\t// Ignore zero values.\n\t\treturn true // i/x is better.\n\tdefault:\n\t\treturn x < y\n\t}\n\n\t// Fall back to geo proximity.\n\tgx := a[i].measurements.GetGeoProximity()\n\tgy := a[j].measurements.GetGeoProximity()\n\tif gx != gy {\n\t\treturn gx > gy\n\t}\n\n\t// Fall back to Hub ID.\n\treturn a[i].Hub.ID < a[j].Hub.ID\n}\n\ntype sortByHighestMeasuredCapacity []*Pin\n\nfunc (a sortByHighestMeasuredCapacity) Len() int      { return len(a) }\nfunc (a sortByHighestMeasuredCapacity) Swap(i, j int) { a[i], a[j] = a[j], a[i] }\nfunc (a sortByHighestMeasuredCapacity) Less(i, j int) bool {\n\tx, _ := a[i].measurements.GetCapacity()\n\ty, _ := a[j].measurements.GetCapacity()\n\tif x != y {\n\t\treturn x > y\n\t}\n\n\t// Fall back to geo proximity.\n\tgx := a[i].measurements.GetGeoProximity()\n\tgy := a[j].measurements.GetGeoProximity()\n\tif gx != gy {\n\t\treturn gx > gy\n\t}\n\n\t// Fall back to Hub ID.\n\treturn a[i].Hub.ID < a[j].Hub.ID\n}\n"
  },
  {
    "path": "spn/navigator/sort_test.go",
    "content": "package navigator\n\nimport (\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nfunc TestSorting(t *testing.T) {\n\tt.Parallel()\n\n\tlist := []*Pin{\n\t\t{\n\t\t\tHub: &hub.Hub{\n\t\t\t\tID: \"a\",\n\t\t\t},\n\t\t\tmeasurements: &hub.Measurements{\n\t\t\t\tLatency:        3,\n\t\t\t\tCapacity:       4,\n\t\t\t\tCalculatedCost: 5,\n\t\t\t},\n\t\t\tanalysis: &AnalysisState{\n\t\t\t\tSuggestedHopDistance: 3,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tHub: &hub.Hub{\n\t\t\t\tID: \"b\",\n\t\t\t},\n\t\t\tmeasurements: &hub.Measurements{\n\t\t\t\tLatency:        4,\n\t\t\t\tCapacity:       3,\n\t\t\t\tCalculatedCost: 1,\n\t\t\t},\n\t\t\tanalysis: &AnalysisState{\n\t\t\t\tSuggestedHopDistance: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tHub: &hub.Hub{\n\t\t\t\tID: \"c\",\n\t\t\t},\n\t\t\tmeasurements: &hub.Measurements{\n\t\t\t\tLatency:        5,\n\t\t\t\tCapacity:       2,\n\t\t\t\tCalculatedCost: 2,\n\t\t\t},\n\t\t\tanalysis: &AnalysisState{\n\t\t\t\tSuggestedHopDistance: 4,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tHub: &hub.Hub{\n\t\t\t\tID: \"d\",\n\t\t\t},\n\t\t\tmeasurements: &hub.Measurements{\n\t\t\t\tLatency:        1,\n\t\t\t\tCapacity:       1,\n\t\t\t\tCalculatedCost: 3,\n\t\t\t},\n\t\t\tanalysis: &AnalysisState{\n\t\t\t\tSuggestedHopDistance: 4,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tHub: &hub.Hub{\n\t\t\t\tID: \"e\",\n\t\t\t},\n\t\t\tmeasurements: &hub.Measurements{\n\t\t\t\tLatency:        2,\n\t\t\t\tCapacity:       5,\n\t\t\t\tCalculatedCost: 4,\n\t\t\t},\n\t\t\tanalysis: &AnalysisState{\n\t\t\t\tSuggestedHopDistance: 4,\n\t\t\t},\n\t\t},\n\t}\n\n\tsort.Sort(sortByLowestMeasuredCost(list))\n\tcheckSorting(t, list, \"b-c-d-e-a\")\n\n\tsort.Sort(sortBySuggestedHopDistanceAndLowestMeasuredCost(list))\n\tcheckSorting(t, list, \"c-d-e-a-b\")\n\n\tsort.Sort(sortByLowestMeasuredLatency(list))\n\tcheckSorting(t, list, \"d-e-a-b-c\")\n\n\tsort.Sort(sortByHighestMeasuredCapacity(list))\n\tcheckSorting(t, list, \"e-a-b-c-d\")\n\n\tsort.Sort(sortByPinID(list))\n\tcheckSorting(t, list, \"a-b-c-d-e\")\n}\n\nfunc checkSorting(t *testing.T, sortedList []*Pin, expectedOrder string) {\n\tt.Helper()\n\n\t// Build list ID string.\n\tids := make([]string, 0, len(sortedList))\n\tfor _, pin := range sortedList {\n\t\tids = append(ids, pin.Hub.ID)\n\t}\n\tsortedIDs := strings.Join(ids, \"-\")\n\n\t// Check for matching order.\n\tassert.Equal(t, expectedOrder, sortedIDs, \"should match\")\n}\n"
  },
  {
    "path": "spn/navigator/state.go",
    "content": "package navigator\n\nimport (\n\t\"strings\"\n\t\"time\"\n)\n\n// PinState holds a bit-mapped collection of Pin states, or a single state used\n// for assigment and matching.\ntype PinState uint16\n\nconst (\n\t// StateNone represents an empty state.\n\tStateNone PinState = 0\n\n\t// Negative States.\n\n\t// StateInvalid signifies that there was an error while processing or\n\t// handling this Hub.\n\tStateInvalid PinState = 1 << (iota - 1) // 1 << 0 => 00000001 => 0x01\n\n\t// StateSuperseded signifies that this Hub was superseded by another. This is\n\t// the case if any other Hub with a matching IP was verified after this one.\n\t// Verification timestamp equals Hub.FirstSeen.\n\tStateSuperseded // 0x02\n\n\t// StateFailing signifies that a recent error was encountered while\n\t// communicating with this Hub. Pin.FailingUntil specifies when this state is\n\t// re-evaluated at earliest.\n\tStateFailing // 0x04\n\n\t// StateOffline signifies that the Hub is offline.\n\tStateOffline // 0x08\n\n\t// Positive States.\n\n\t// StateHasRequiredInfo signifies that the Hub announces the minimum required\n\t// information about itself.\n\tStateHasRequiredInfo // 0x10\n\n\t// StateReachable signifies that the Hub is reachable via the network from\n\t// the currently connected primary Hub.\n\tStateReachable // 0x20\n\n\t// StateActive signifies that everything seems fine with the Hub and\n\t// connections to it should succeed. This is tested by checking if a valid\n\t// semi-ephemeral public key is available.\n\tStateActive // 0x40\n\n\t_ // 0x80: Reserved\n\n\t// Trust and Advisory States.\n\n\t// StateTrusted signifies the Hub has the special trusted status.\n\tStateTrusted // 0x0100\n\n\t// StateUsageDiscouraged signifies that usage of the Hub is discouraged for any task.\n\tStateUsageDiscouraged // 0x0200\n\n\t// StateUsageAsHomeDiscouraged signifies that usage of the Hub as a Home Hub is discouraged.\n\tStateUsageAsHomeDiscouraged // 0x0400\n\n\t// StateUsageAsDestinationDiscouraged signifies that usage of the Hub as a Destination Hub is discouraged.\n\tStateUsageAsDestinationDiscouraged // 0x0800\n\n\t// Special States.\n\n\t// StateIsHomeHub signifies that the Hub is the current Home Hub. While not\n\t// negative in itself, selecting the Home Hub does not make sense in almost\n\t// all cases.\n\tStateIsHomeHub // 0x1000\n\n\t// StateConnectivityIssues signifies that the Hub reports connectivity issues.\n\t// This might impact all connectivity or just some.\n\t// This does not invalidate the Hub for all operations and not in all cases.\n\tStateConnectivityIssues // 0x2000\n\n\t// StateAllowUnencrypted signifies that the Hub is available to handle unencrypted connections.\n\tStateAllowUnencrypted // 0x4000\n\n\t// State Summaries.\n\n\t// StateSummaryRegard summarizes all states that must always be set in order to take a Hub into consideration for any task.\n\t// TODO: Add StateHasRequiredInfo when we start enforcing Hub information.\n\tStateSummaryRegard = StateReachable | StateActive\n\n\t// StateSummaryDisregard summarizes all states that must not be set in order to take a Hub into consideration for any task.\n\tStateSummaryDisregard = StateInvalid |\n\t\tStateSuperseded |\n\t\tStateFailing |\n\t\tStateOffline |\n\t\tStateUsageDiscouraged |\n\t\tStateIsHomeHub\n\n\t// StateSummaryStatusesAppliedFromIntel summarizes all states that are applied from the intel file.\n\tStateSummaryStatusesAppliedFromIntel = StateTrusted |\n\t\tStateUsageDiscouraged |\n\t\tStateUsageAsHomeDiscouraged |\n\t\tStateUsageAsDestinationDiscouraged\n)\n\nvar allStates = []PinState{\n\tStateInvalid,\n\tStateSuperseded,\n\tStateFailing,\n\tStateOffline,\n\tStateHasRequiredInfo,\n\tStateReachable,\n\tStateActive,\n\tStateTrusted,\n\tStateUsageDiscouraged,\n\tStateUsageAsHomeDiscouraged,\n\tStateUsageAsDestinationDiscouraged,\n\tStateIsHomeHub,\n\tStateConnectivityIssues,\n\tStateAllowUnencrypted,\n}\n\n// Add returns a new PinState with the given states added.\nfunc (pinState PinState) Add(states PinState) PinState {\n\t// OR:\n\t//   0011\n\t// | 0101\n\t// = 0111\n\treturn pinState | states\n}\n\n// Remove returns a new PinState with the given states removed.\nfunc (pinState PinState) Remove(states PinState) PinState {\n\t// AND NOT:\n\t//    0011\n\t// &^ 0101\n\t// =  0010\n\treturn pinState &^ states\n}\n\n// Has returns whether the state has all of the given states.\nfunc (pinState PinState) Has(states PinState) bool {\n\t// AND:\n\t//   0011\n\t// & 0101\n\t// = 0001\n\n\treturn pinState&states == states\n}\n\n// HasAnyOf returns whether the state has any of the given states.\nfunc (pinState PinState) HasAnyOf(states PinState) bool {\n\t// AND:\n\t//   0011\n\t// & 0101\n\t// = 0001\n\n\treturn (pinState & states) != 0\n}\n\n// HasNoneOf returns whether the state does not have any of the given states.\nfunc (pinState PinState) HasNoneOf(states PinState) bool {\n\t// AND:\n\t//   0011\n\t// & 0101\n\t// = 0001\n\n\treturn (pinState & states) == 0\n}\n\n// addStates adds the given states on the Pin.\nfunc (pin *Pin) addStates(states PinState) {\n\tpin.State = pin.State.Add(states)\n}\n\n// removeStates removes the given states on the Pin.\nfunc (pin *Pin) removeStates(states PinState) {\n\tpin.State = pin.State.Remove(states)\n}\n\nfunc (m *Map) updateStateSuperseded(pin *Pin) {\n\tpin.removeStates(StateSuperseded)\n\n\t// Update StateSuperseded\n\t// Iterate over all Pins in order to find a matching IP address.\n\t// In order to prevent false positive matching, we have to go through IPv4\n\t// and IPv6 separately.\n\t// TODO: This will not scale well beyond about 1000 Hubs.\n\n\t// IPv4 Loop\n\tif pin.Hub.Info.IPv4 != nil {\n\t\tfor _, mapPin := range m.all {\n\t\t\t// Skip Pin itself\n\t\t\tif mapPin.Hub.ID == pin.Hub.ID {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Check for a matching IPv4 address.\n\t\t\tif mapPin.Hub.Info.IPv4 != nil && pin.Hub.Info.IPv4.Equal(mapPin.Hub.Info.IPv4) {\n\t\t\t\tcontinueChecking := checkAndHandleSuperseding(pin, mapPin)\n\t\t\t\tif !continueChecking {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// IPv6 Loop\n\tif pin.Hub.Info.IPv6 != nil {\n\t\tfor _, mapPin := range m.all {\n\t\t\t// Skip Pin itself\n\t\t\tif mapPin.Hub.ID == pin.Hub.ID {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Check for a matching IPv6 address.\n\t\t\tif mapPin.Hub.Info.IPv6 != nil && pin.Hub.Info.IPv6.Equal(mapPin.Hub.Info.IPv6) {\n\t\t\t\tcontinueChecking := checkAndHandleSuperseding(pin, mapPin)\n\t\t\t\tif !continueChecking {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc checkAndHandleSuperseding(newPin, existingPin *Pin) (continueChecking bool) {\n\tconst (\n\t\tsupersedeNone = iota\n\t\tsupersedeExisting\n\t\tsupersedeNew\n\t)\n\tvar action int\n\n\tswitch {\n\tcase newPin.Hub.ID == existingPin.Hub.ID:\n\t\t// Cannot supersede same Hub.\n\t\t// Continue checking.\n\t\taction = supersedeNone\n\n\t// Step 1: Check if only one is active.\n\n\tcase newPin.State.Has(StateActive) && existingPin.State.HasNoneOf(StateActive):\n\t\t// If only the new Hub is active, supersede the existing one.\n\t\taction = supersedeExisting\n\tcase newPin.State.HasNoneOf(StateActive) && existingPin.State.Has(StateActive):\n\t\t// If only the existing Hub is active, supersede the new one.\n\t\taction = supersedeNew\n\n\t// Step 2: Check if only one is reachable.\n\n\tcase newPin.State.Has(StateReachable) && existingPin.State.HasNoneOf(StateReachable):\n\t\t// If only the new Hub is reachable, supersede the existing one.\n\t\taction = supersedeExisting\n\tcase newPin.State.HasNoneOf(StateReachable) && existingPin.State.Has(StateReachable):\n\t\t// If only the existing Hub is reachable, supersede the new one.\n\t\taction = supersedeNew\n\n\t// Step 3: Check which one has been seen first.\n\n\tcase newPin.Hub.FirstSeen.After(existingPin.Hub.FirstSeen):\n\t\t// If the new Hub has been first seen later, supersede the existing one.\n\t\taction = supersedeExisting\n\tdefault:\n\t\t// If the existing Hub has been first seen later, supersede the new one.\n\t\taction = supersedeNew\n\t}\n\n\tswitch action {\n\tcase supersedeExisting:\n\t\texistingPin.addStates(StateSuperseded)\n\t\texistingPin.pushChanges.Set()\n\t\t// Continue checking, as there might be other Hubs to be superseded.\n\t\treturn true\n\n\tcase supersedeNew:\n\t\tnewPin.addStates(StateSuperseded)\n\t\tnewPin.pushChanges.Set()\n\t\t// If the new pin is superseded, do _not_ continue, as this will lead to an incorrect state.\n\t\treturn false\n\n\tcase supersedeNone:\n\t\tfallthrough\n\tdefault:\n\t\t// Do nothing, continue checking.\n\t\treturn true\n\t}\n}\n\nfunc (pin *Pin) updateStateHasRequiredInfo() {\n\tpin.removeStates(StateHasRequiredInfo)\n\n\t// Check for required Hub Information.\n\tswitch {\n\tcase len(pin.Hub.Info.Name) == 0:\n\tcase len(pin.Hub.Info.Group) == 0:\n\tcase len(pin.Hub.Info.ContactAddress) == 0:\n\tcase len(pin.Hub.Info.ContactService) == 0:\n\tcase len(pin.Hub.Info.Hosters) == 0:\n\tcase len(pin.Hub.Info.Hosters[0]) == 0:\n\tcase len(pin.Hub.Info.Datacenter) == 0:\n\tdefault:\n\t\tpin.addStates(StateHasRequiredInfo)\n\t}\n}\n\nfunc (m *Map) updateActiveHubs() {\n\tnow := time.Now().Unix()\n\tfor _, pin := range m.all {\n\t\tpin.updateStateActive(now)\n\t}\n}\n\nfunc (pin *Pin) updateStateActive(now int64) {\n\tpin.removeStates(StateActive)\n\n\t// Check for active key.\n\tfor _, key := range pin.Hub.Status.Keys {\n\t\tif now < key.Expires {\n\t\t\tpin.addStates(StateActive)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (m *Map) recalculateReachableHubs() error {\n\tif m.home == nil {\n\t\treturn ErrHomeHubUnset\n\t}\n\n\t// reset\n\tfor _, pin := range m.all {\n\t\tpin.removeStates(StateReachable)\n\t\tpin.HopDistance = 0\n\t\tpin.pushChanges.Set()\n\t}\n\n\t// find all connected Hubs\n\tm.home.markReachable(1)\n\treturn nil\n}\n\nfunc (pin *Pin) markReachable(hopDistance int) {\n\tswitch {\n\tcase !pin.State.Has(StateReachable):\n\t\t// Pin wasn't reachable before.\n\tcase hopDistance < pin.HopDistance:\n\t\t// New path has a shorter distance.\n\tcase pin.State.HasAnyOf(StateSummaryDisregard): //nolint:staticcheck\n\t\t// Ignore disregarded pins for reachability calculation.\n\t\treturn\n\tdefault:\n\t\t// Pin is already reachable at same or better distance.\n\t\treturn\n\t}\n\n\t// Update reachability.\n\tpin.addStates(StateReachable)\n\tpin.HopDistance = hopDistance\n\tpin.pushChanges.Set()\n\n\t// Propagate to connected Pins.\n\thopDistance++\n\tfor _, lane := range pin.ConnectedTo {\n\t\tlane.Pin.markReachable(hopDistance)\n\t}\n}\n\n// Export returns a list of all state names.\nfunc (pinState PinState) Export() []string {\n\t// Check if there are no states.\n\tif pinState == StateNone {\n\t\treturn nil\n\t}\n\n\t// Collect state names.\n\tvar stateNames []string\n\tfor _, state := range allStates {\n\t\tif pinState.Has(state) {\n\t\t\tstateNames = append(stateNames, state.Name())\n\t\t}\n\t}\n\n\treturn stateNames\n}\n\n// String returns the states as a human readable string.\nfunc (pinState PinState) String() string {\n\tstateNames := pinState.Export()\n\tif len(stateNames) == 0 {\n\t\treturn \"None\"\n\t}\n\n\treturn strings.Join(stateNames, \", \")\n}\n\n// Name returns the name of a single state flag.\nfunc (pinState PinState) Name() string {\n\tswitch pinState {\n\tcase StateNone:\n\t\treturn \"None\"\n\tcase StateInvalid:\n\t\treturn \"Invalid\"\n\tcase StateSuperseded:\n\t\treturn \"Superseded\"\n\tcase StateFailing:\n\t\treturn \"Failing\"\n\tcase StateOffline:\n\t\treturn \"Offline\"\n\tcase StateHasRequiredInfo:\n\t\treturn \"HasRequiredInfo\"\n\tcase StateReachable:\n\t\treturn \"Reachable\"\n\tcase StateActive:\n\t\treturn \"Active\"\n\tcase StateTrusted:\n\t\treturn \"Trusted\"\n\tcase StateUsageDiscouraged:\n\t\treturn \"UsageDiscouraged\"\n\tcase StateUsageAsHomeDiscouraged:\n\t\treturn \"UsageAsHomeDiscouraged\"\n\tcase StateUsageAsDestinationDiscouraged:\n\t\treturn \"UsageAsDestinationDiscouraged\"\n\tcase StateIsHomeHub:\n\t\treturn \"IsHomeHub\"\n\tcase StateConnectivityIssues:\n\t\treturn \"ConnectivityIssues\"\n\tcase StateAllowUnencrypted:\n\t\treturn \"AllowUnencrypted\"\n\tcase StateSummaryRegard, StateSummaryDisregard:\n\t\t// Satisfy exhaustive linter.\n\t\tfallthrough\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n"
  },
  {
    "path": "spn/navigator/state_test.go",
    "content": "package navigator\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStates(t *testing.T) {\n\tt.Parallel()\n\n\tp := &Pin{}\n\n\tp.addStates(StateInvalid | StateFailing | StateSuperseded)\n\tassert.Equal(t, StateInvalid|StateFailing|StateSuperseded, p.State)\n\n\tp.removeStates(StateFailing | StateSuperseded)\n\tassert.Equal(t, StateInvalid, p.State)\n\n\tp.addStates(StateTrusted | StateActive)\n\tassert.True(t, p.State.Has(StateInvalid|StateTrusted))\n\tassert.False(t, p.State.Has(StateInvalid|StateSuperseded))\n\tassert.True(t, p.State.HasAnyOf(StateInvalid|StateTrusted))\n\tassert.True(t, p.State.HasAnyOf(StateInvalid|StateSuperseded))\n\tassert.False(t, p.State.HasAnyOf(StateSuperseded|StateFailing))\n\n\tassert.False(t, p.State.Has(StateSummaryRegard))\n\tassert.False(t, p.State.Has(StateSummaryDisregard))\n\tassert.True(t, p.State.HasAnyOf(StateSummaryRegard))\n\tassert.True(t, p.State.HasAnyOf(StateSummaryDisregard))\n}\n"
  },
  {
    "path": "spn/navigator/update.go",
    "content": "package navigator\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\t\"golang.org/x/exp/slices\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database\"\n\t\"github.com/safing/portmaster/base/database/query\"\n\t\"github.com/safing/portmaster/base/database/record\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/intel/geoip\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/service/profile\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nvar db = database.NewInterface(&database.Options{\n\tLocal:    true,\n\tInternal: true,\n})\n\n// InitializeFromDatabase loads all Hubs from the given database prefix and adds them to the Map.\nfunc (m *Map) InitializeFromDatabase() error {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// start query for Hubs\n\titer, err := db.Query(query.New(hub.MakeHubDBKey(m.Name, \"\")))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start query for initialization feed of %s map: %w\", m.Name, err)\n\t}\n\n\t// update navigator\n\tvar hubCount int\n\tlog.Tracef(\"spn/navigator: starting to initialize %s map from database\", m.Name)\n\tfor r := range iter.Next {\n\t\th, err := hub.EnsureHub(r)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/navigator: could not parse hub %q while initializing %s map: %s\", r.Key(), m.Name, err)\n\t\t\tcontinue\n\t\t}\n\n\t\thubCount++\n\t\tm.updateHub(h, false, true)\n\t}\n\tswitch {\n\tcase iter.Err() != nil:\n\t\treturn fmt.Errorf(\"failed to (fully) initialize %s map: %w\", m.Name, iter.Err())\n\tcase hubCount == 0:\n\t\tlog.Warningf(\"spn/navigator: no hubs available for %s map - this is normal on first start\", m.Name)\n\tdefault:\n\t\tlog.Infof(\"spn/navigator: added %d hubs from database to %s map\", hubCount, m.Name)\n\t}\n\treturn nil\n}\n\n// UpdateHook updates the a map from database changes.\ntype UpdateHook struct {\n\tdatabase.HookBase\n\tm *Map\n}\n\n// UsesPrePut implements the Hook interface.\nfunc (hook *UpdateHook) UsesPrePut() bool {\n\treturn true\n}\n\n// PrePut implements the Hook interface.\nfunc (hook *UpdateHook) PrePut(r record.Record) (record.Record, error) {\n\t// Remove deleted hubs from the map.\n\tif r.Meta().IsDeleted() {\n\t\thook.m.RemoveHub(path.Base(r.Key()))\n\t\treturn r, nil\n\t}\n\n\t// Ensure we have a hub and update it in navigation map.\n\th, err := hub.EnsureHub(r)\n\tif err != nil {\n\t\tlog.Debugf(\"spn/navigator: record %s is not a hub\", r.Key())\n\t} else {\n\t\thook.m.updateHub(h, true, false)\n\t}\n\n\treturn r, nil\n}\n\n// RegisterHubUpdateHook registers a database pre-put hook that updates all\n// Hubs saved at the given database prefix.\nfunc (m *Map) RegisterHubUpdateHook() (err error) {\n\tm.hubUpdateHook, err = database.RegisterHook(\n\t\tquery.New(hub.MakeHubDBKey(m.Name, \"\")),\n\t\t&UpdateHook{m: m},\n\t)\n\treturn err\n}\n\n// CancelHubUpdateHook cancels the map's update hook.\nfunc (m *Map) CancelHubUpdateHook() {\n\tif m.hubUpdateHook != nil {\n\t\tif err := m.hubUpdateHook.Cancel(); err != nil {\n\t\t\tlog.Warningf(\"spn/navigator: failed to cancel update hook for map %s: %s\", m.Name, err)\n\t\t}\n\t}\n}\n\n// RemoveHub removes a Hub from the Map.\nfunc (m *Map) RemoveHub(id string) {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\t// Get pin and remove it from the map, if it exists.\n\tpin, ok := m.all[id]\n\tif !ok {\n\t\treturn\n\t}\n\tdelete(m.all, id)\n\n\t// Remove lanes from removed Pin.\n\tfor id := range pin.ConnectedTo {\n\t\t// Remove Lane from peer.\n\t\tpeer, ok := m.all[id]\n\t\tif ok {\n\t\t\tdelete(peer.ConnectedTo, pin.Hub.ID)\n\t\t\tpeer.pushChanges.Set()\n\t\t}\n\t}\n\n\t// Push update to subscriptions.\n\texport := pin.Export()\n\texport.Meta().Delete()\n\tmapDBController.PushUpdate(export)\n\t// Push lane changes.\n\tm.PushPinChanges()\n}\n\n// UpdateHub updates a Hub on the Map.\nfunc (m *Map) UpdateHub(h *hub.Hub) {\n\tm.updateHub(h, true, true)\n}\n\nfunc (m *Map) updateHub(h *hub.Hub, lockMap, lockHub bool) {\n\tif lockMap {\n\t\tm.Lock()\n\t\tdefer m.Unlock()\n\t}\n\tif lockHub {\n\t\th.Lock()\n\t\tdefer h.Unlock()\n\t}\n\n\t// Hub requires both Info and Status to be added to the Map.\n\tif h.Info == nil || h.Status == nil {\n\t\treturn\n\t}\n\n\t// Create or update Pin.\n\tpin, ok := m.all[h.ID]\n\tif ok {\n\t\tpin.Hub = h\n\t} else {\n\t\tpin = &Pin{\n\t\t\tHub:               h,\n\t\t\tConnectedTo:       make(map[string]*Lane),\n\t\t\tstateIntelApplied: abool.New(),\n\t\t\tpushChanges:       abool.New(),\n\t\t}\n\t\tm.all[h.ID] = pin\n\t}\n\tpin.pushChanges.Set()\n\n\t// 1. Update Pin Data.\n\n\t// Add/Update location data from IP addresses.\n\tpin.updateLocationData()\n\n\t// Override Pin Data.\n\tm.updateInfoOverrides(pin)\n\n\t// Update Hub cost.\n\tpin.Cost = CalculateHubCost(pin.Hub.Status.Load)\n\n\t// Ensure measurements are set when enabled.\n\tif m.measuringEnabled && pin.measurements == nil {\n\t\t// Get shared measurements.\n\t\tpin.measurements = pin.Hub.GetMeasurementsWithLockedHub()\n\n\t\t// Update cost calculation.\n\t\tlatency, _ := pin.measurements.GetLatency()\n\t\tcapacity, _ := pin.measurements.GetCapacity()\n\t\tpin.measurements.SetCalculatedCost(CalculateLaneCost(latency, capacity))\n\n\t\t// Update geo proximity.\n\t\t// Get own location.\n\t\tvar myLocation *geoip.Location\n\t\tswitch {\n\t\tcase m.home != nil && m.home.LocationV4 != nil:\n\t\t\tmyLocation = m.home.LocationV4\n\t\tcase m.home != nil && m.home.LocationV6 != nil:\n\t\t\tmyLocation = m.home.LocationV6\n\t\tdefault:\n\t\t\tlocations, ok := netenv.GetInternetLocation()\n\t\t\tif ok {\n\t\t\t\tmyLocation = locations.Best().LocationOrNil()\n\t\t\t}\n\t\t}\n\t\t// Calculate proximity with available location.\n\t\tif myLocation != nil {\n\t\t\tswitch {\n\t\t\tcase pin.LocationV4 != nil:\n\t\t\t\tpin.measurements.SetGeoProximity(\n\t\t\t\t\tmyLocation.EstimateNetworkProximity(pin.LocationV4),\n\t\t\t\t)\n\t\t\tcase pin.LocationV6 != nil:\n\t\t\t\tpin.measurements.SetGeoProximity(\n\t\t\t\t\tmyLocation.EstimateNetworkProximity(pin.LocationV6),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Update Pin States.\n\n\t// Update the invalid status of the Pin.\n\tif pin.Hub.InvalidInfo || pin.Hub.InvalidStatus {\n\t\tpin.addStates(StateInvalid)\n\t} else {\n\t\tpin.removeStates(StateInvalid)\n\t}\n\n\t// Update online status of the Pin.\n\tif pin.Hub.HasFlag(hub.FlagOffline) || pin.Hub.Status.Version == hub.VersionOffline {\n\t\tpin.addStates(StateOffline)\n\t} else {\n\t\tpin.removeStates(StateOffline)\n\t}\n\n\t// Update online status of the Pin.\n\tif pin.Hub.HasFlag(hub.FlagAllowUnencrypted) {\n\t\tpin.addStates(StateAllowUnencrypted)\n\t} else {\n\t\tpin.removeStates(StateAllowUnencrypted)\n\t}\n\n\t// Update from status flags.\n\tif pin.Hub.HasFlag(hub.FlagNetError) {\n\t\tpin.addStates(StateConnectivityIssues)\n\t} else {\n\t\tpin.removeStates(StateConnectivityIssues)\n\t}\n\n\t// Update Trust and Advisory Statuses.\n\tm.updateIntelStatuses(pin, cfgOptionTrustNodeNodes())\n\n\t// Update Statuses derived from Hub.\n\tpin.updateStateHasRequiredInfo()\n\tpin.updateStateActive(time.Now().Unix())\n\n\t// 3. Update Lanes.\n\n\t// Mark all existing Lanes as inactive.\n\tfor _, lane := range pin.ConnectedTo {\n\t\tlane.active = false\n\t}\n\n\t// Update Lanes (connections to other Hubs) from the Status.\n\tfor _, lane := range pin.Hub.Status.Lanes {\n\t\t// Check if this is a Lane to itself.\n\t\tif lane.ID == pin.Hub.ID {\n\t\t\tcontinue\n\t\t}\n\n\t\t// First, get the Lane peer.\n\t\tpeer, ok := m.all[lane.ID]\n\t\tif !ok {\n\t\t\t// We need to wait for peer to be added to the Map.\n\t\t\tcontinue\n\t\t}\n\n\t\tm.updateHubLane(pin, lane, peer)\n\t}\n\n\t// Remove all inactive/abandoned Lanes from both Pins.\n\tvar removedLanes bool\n\tfor id, lane := range pin.ConnectedTo {\n\t\tif !lane.active {\n\t\t\t// Remove Lane from this Pin.\n\t\t\tdelete(pin.ConnectedTo, id)\n\t\t\tpin.pushChanges.Set()\n\t\t\tremovedLanes = true\n\t\t\t// Remove Lane from peer.\n\t\t\tpeer, ok := m.all[id]\n\t\t\tif ok {\n\t\t\t\tdelete(peer.ConnectedTo, pin.Hub.ID)\n\t\t\t\tpeer.pushChanges.Set()\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fully recalculate reachability if any Lanes were removed.\n\tif removedLanes {\n\t\terr := m.recalculateReachableHubs()\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/navigator: failed to recalculate reachable Hubs: %s\", err)\n\t\t}\n\t}\n\n\t// 4. Update states that depend on other information.\n\n\t// Check if hub is superseded or if it supersedes another hub.\n\tm.updateStateSuperseded(pin)\n\n\t// Push updates.\n\tm.PushPinChanges()\n}\n\nconst (\n\tminUnconfirmedLatency  = 10 * time.Millisecond\n\tmaxUnconfirmedCapacity = 100000000 // 100Mbit/s\n\n\tcap1Mbit   float32 = 1000000\n\tcap10Mbit  float32 = 10000000\n\tcap100Mbit float32 = 100000000\n\tcap1Gbit   float32 = 1000000000\n\tcap10Gbit  float32 = 10000000000\n)\n\n// updateHubLane updates a lane between two Hubs on the Map.\n// pin must already be locked, lane belongs to pin.\n// peer will be locked by this function.\nfunc (m *Map) updateHubLane(pin *Pin, lane *hub.Lane, peer *Pin) {\n\tpeer.Hub.Lock()\n\tdefer peer.Hub.Unlock()\n\n\t// Then get the corresponding Lane from that peer, if it exists.\n\tvar peerLane *hub.Lane\n\tfor _, possiblePeerLane := range peer.Hub.Status.Lanes {\n\t\tif possiblePeerLane.ID == pin.Hub.ID {\n\t\t\tpeerLane = possiblePeerLane\n\t\t\t// We have found the corresponding peerLane, break the loop.\n\t\t\tbreak\n\t\t}\n\t}\n\tif peerLane == nil {\n\t\t// The peer obviously does not advertise a Lane to this Hub.\n\t\t// Maybe this is a fresh Lane, and the message has not yet reached us.\n\t\t// Alternatively, the Lane could have been recently removed.\n\n\t\t// Abandon this Lane for now.\n\t\tdelete(pin.ConnectedTo, peer.Hub.ID)\n\t\treturn\n\t}\n\n\t// Calculate combined latency, use the greater value.\n\tcombinedLatency := lane.Latency\n\tif peerLane.Latency > combinedLatency {\n\t\tcombinedLatency = peerLane.Latency\n\t}\n\t// Enforce minimum value if at least one side has no data.\n\tif (lane.Latency == 0 || peerLane.Latency == 0) && combinedLatency < minUnconfirmedLatency {\n\t\tcombinedLatency = minUnconfirmedLatency\n\t}\n\n\t// Calculate combined capacity, use the lesser existing value.\n\tcombinedCapacity := lane.Capacity\n\tif combinedCapacity == 0 || (peerLane.Capacity > 0 && peerLane.Capacity < combinedCapacity) {\n\t\tcombinedCapacity = peerLane.Capacity\n\t}\n\t// Enforce maximum value if at least one side has no data.\n\tif (lane.Capacity == 0 || peerLane.Capacity == 0) && combinedCapacity > maxUnconfirmedCapacity {\n\t\tcombinedCapacity = maxUnconfirmedCapacity\n\t}\n\n\t// Calculate lane cost.\n\tlaneCost := CalculateLaneCost(combinedLatency, combinedCapacity)\n\n\t// Add Lane to both Pins and override old values in the process.\n\tpin.ConnectedTo[peer.Hub.ID] = &Lane{\n\t\tPin:      peer,\n\t\tCapacity: combinedCapacity,\n\t\tLatency:  combinedLatency,\n\t\tCost:     laneCost,\n\t\tactive:   true,\n\t}\n\tpeer.ConnectedTo[pin.Hub.ID] = &Lane{\n\t\tPin:      pin,\n\t\tCapacity: combinedCapacity,\n\t\tLatency:  combinedLatency,\n\t\tCost:     laneCost,\n\t\tactive:   true,\n\t}\n\tpeer.pushChanges.Set()\n\n\t// Check for reachability.\n\n\tif pin.State.Has(StateReachable) {\n\t\tpeer.markReachable(pin.HopDistance + 1)\n\t}\n\tif peer.State.Has(StateReachable) {\n\t\tpin.markReachable(peer.HopDistance + 1)\n\t}\n}\n\n// ResetFailingStates resets the failing state on all pins.\nfunc (m *Map) ResetFailingStates() {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tfor _, pin := range m.all {\n\t\tpin.ResetFailingState()\n\t}\n\n\tm.PushPinChanges()\n}\n\nfunc (m *Map) updateFailingStates(ctx *mgr.WorkerCtx) error {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\tfor _, pin := range m.all {\n\t\tif pin.State.Has(StateFailing) && !pin.IsFailing() {\n\t\t\tpin.removeStates(StateFailing)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *Map) updateStates(ctx *mgr.WorkerCtx) error {\n\tvar toDelete []string\n\n\tm.Lock()\n\tdefer m.Unlock()\n\npinLoop:\n\tfor _, pin := range m.all {\n\t\t// Check for discontinued Hubs.\n\t\tif m.intel != nil {\n\t\t\thubIntel, ok := m.intel.Hubs[pin.Hub.ID]\n\t\t\tif ok && hubIntel.Discontinued {\n\t\t\t\ttoDelete = append(toDelete, pin.Hub.ID)\n\t\t\t\tlog.Infof(\"spn/navigator: deleting discontinued %s\", pin.Hub)\n\t\t\t\tcontinue pinLoop\n\t\t\t}\n\t\t}\n\t\t// Check for obsoleted Hubs.\n\t\tif pin.State.HasNoneOf(StateActive) && pin.Hub.Obsolete() {\n\t\t\ttoDelete = append(toDelete, pin.Hub.ID)\n\t\t\tlog.Infof(\"spn/navigator: deleting obsolete %s\", pin.Hub)\n\t\t}\n\n\t\t// Delete hubs async, as deleting triggers a couple hooks that lock the map.\n\t\tif len(toDelete) > 0 {\n\t\t\tmodule.mgr.Go(\"delete hubs\", func(_ *mgr.WorkerCtx) error {\n\t\t\t\tfor _, idToDelete := range toDelete {\n\t\t\t\t\terr := hub.RemoveHubAndMsgs(m.Name, idToDelete)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Warningf(\"spn/navigator: failed to delete Hub %s: %s\", idToDelete, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t}\n\n\t// Update StateActive.\n\tm.updateActiveHubs()\n\n\t// Update StateReachable.\n\treturn m.recalculateReachableHubs()\n}\n\n// AddBootstrapHubs adds the given bootstrap hubs to the map.\nfunc (m *Map) AddBootstrapHubs(bootstrapTransports []string) error {\n\tm.Lock()\n\tdefer m.Unlock()\n\n\treturn m.addBootstrapHubs(bootstrapTransports)\n}\n\nfunc (m *Map) addBootstrapHubs(bootstrapTransports []string) error {\n\tvar anyAdded bool\n\tvar lastErr error\n\tvar failed int\n\tfor _, bootstrapTransport := range bootstrapTransports {\n\t\terr := m.addBootstrapHub(bootstrapTransport)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/navigator: failed to add bootstrap hub %q to map %s: %s\", bootstrapTransport, m.Name, err)\n\t\t\tlastErr = err\n\t\t\tfailed++\n\t\t} else {\n\t\t\tanyAdded = true\n\t\t}\n\t}\n\n\tif lastErr != nil && !anyAdded {\n\t\treturn lastErr\n\t}\n\treturn nil\n}\n\nfunc (m *Map) addBootstrapHub(bootstrapTransport string) error {\n\t// Parse bootstrap hub.\n\ttransport, hubID, hubIP, err := hub.ParseBootstrapHub(bootstrapTransport)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid bootstrap hub: %w\", err)\n\t}\n\n\t// Check if hub already exists.\n\tvar h *hub.Hub\n\tpin, ok := m.all[hubID]\n\tif ok {\n\t\th = pin.Hub\n\t} else {\n\t\th = &hub.Hub{\n\t\t\tID:  hubID,\n\t\t\tMap: m.Name,\n\t\t\tInfo: &hub.Announcement{\n\t\t\t\tID: hubID,\n\t\t\t},\n\t\t\tStatus:    &hub.Status{},\n\t\t\tFirstSeen: time.Now(), // Do not garbage collect bootstrap hubs.\n\t\t}\n\t}\n\n\t// Add IP if it does not yet exist.\n\tif hubIP4 := hubIP.To4(); hubIP4 != nil {\n\t\tif h.Info.IPv4 == nil {\n\t\t\th.Info.IPv4 = hubIP4\n\t\t} else if !h.Info.IPv4.Equal(hubIP4) {\n\t\t\treturn fmt.Errorf(\"additional bootstrap entry with same ID but mismatching IP address: %s\", hubIP)\n\t\t}\n\t} else {\n\t\tif h.Info.IPv6 == nil {\n\t\t\th.Info.IPv6 = hubIP\n\t\t} else if !h.Info.IPv6.Equal(hubIP) {\n\t\t\treturn fmt.Errorf(\"additional bootstrap entry with same ID but mismatching IP address: %s\", hubIP)\n\t\t}\n\t}\n\n\t// Add transport if it does not yet exist.\n\tt := transport.String()\n\tif !utils.StringInSlice(h.Info.Transports, t) {\n\t\th.Info.Transports = append(h.Info.Transports, t)\n\t}\n\n\t// Add/update to map for bootstrapping.\n\tm.updateHub(h, false, false)\n\tlog.Infof(\"spn/navigator: added/updated bootstrap %s to map %s\", h, m.Name)\n\treturn nil\n}\n\n// UpdateConfigQuickSettings updates config quick settings with available countries.\nfunc (m *Map) UpdateConfigQuickSettings(wc *mgr.WorkerCtx) error {\n\tctx, tracer := log.AddTracer(wc.Ctx())\n\ttracer.Trace(\"navigator: updating SPN rules country quick settings\")\n\tdefer tracer.Submit()\n\n\topts := m.DefaultOptions()\n\topts.Home = &HomeHubOptions{\n\t\tRegard: StateTrusted,\n\t}\n\topts.Destination = &DestinationHubOptions{\n\t\tRegard:    StateTrusted,\n\t\tDisregard: StateIsHomeHub,\n\t}\n\n\t// Home Policy.\n\tif err := m.updateQuickSettingExcludeCountryList(ctx, \"spn/homePolicy\", opts, HomeHub); err != nil {\n\t\treturn err\n\t}\n\t// Transit Policy.\n\tif err := m.updateQuickSettingExcludeCountryList(ctx, profile.CfgOptionTransitHubPolicyKey, opts, TransitHub); err != nil {\n\t\treturn err\n\t}\n\t// Exit Policy.\n\tif err := m.updateSelectRuleCountryList(ctx, profile.CfgOptionExitHubPolicyKey, opts, DestinationHub); err != nil {\n\t\treturn err\n\t}\n\t// DNS Exit Policy.\n\tif err := m.updateSelectRuleCountryList(ctx, \"spn/dnsExitPolicy\", opts, DestinationHub); err != nil {\n\t\treturn err\n\t}\n\n\t// Trust Nodes.\n\tif err := m.updateQuickSettingVerifiedOwnerList(ctx, \"spn/trustNodes\"); err != nil {\n\t\treturn err\n\t}\n\n\ttracer.Trace(\"navigator: finished updating SPN rules country quick settings\")\n\treturn nil\n}\n\nfunc (m *Map) updateQuickSettingExcludeCountryList(ctx context.Context, configKey string, opts *Options, matchFor HubType) error {\n\t// Get config option.\n\tcfgOption, err := config.GetOption(configKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get config option %s: %w\", configKey, err)\n\t}\n\n\t// Get list of countries for this config option.\n\tcountries := m.GetAvailableCountries(opts, matchFor)\n\t// Convert to list.\n\tcountryList := make([]*geoip.CountryInfo, 0, len(countries))\n\tfor _, country := range countries {\n\t\tcountryList = append(countryList, country)\n\t}\n\t// Sort list.\n\tslices.SortFunc[[]*geoip.CountryInfo, *geoip.CountryInfo](countryList, func(a, b *geoip.CountryInfo) int {\n\t\treturn strings.Compare(a.Name, b.Name)\n\t})\n\n\t// Compile list of quick settings.\n\tquickSettings := make([]config.QuickSetting, 0, len(countries))\n\tfor _, country := range countryList {\n\t\tquickSettings = append(quickSettings, config.QuickSetting{\n\t\t\tName:   fmt.Sprintf(\"Exclude %s (%s)\", country.Name, country.Code),\n\t\t\tValue:  []string{\"- \" + country.Code},\n\t\t\tAction: config.QuickMergeTop,\n\t\t})\n\t}\n\n\t// Lock config option and set new quick settings.\n\tcfgOption.Lock()\n\tdefer cfgOption.Unlock()\n\tcfgOption.Annotations[config.QuickSettingsAnnotation] = quickSettings\n\n\tlog.Tracer(ctx).Debugf(\"navigator: updated %d countries in quick settings for %s\", len(quickSettings), configKey)\n\treturn nil\n}\n\ntype selectCountry struct {\n\tconfig.QuickSetting\n\tFlagID string\n}\n\nfunc (m *Map) updateSelectRuleCountryList(ctx context.Context, configKey string, opts *Options, matchFor HubType) error {\n\t// Get config option.\n\tcfgOption, err := config.GetOption(configKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get config option %s: %w\", configKey, err)\n\t}\n\n\t// Get list of countries for this config option.\n\tcountries := m.GetAvailableCountries(opts, matchFor)\n\t// Convert to list.\n\tcountryList := make([]*geoip.CountryInfo, 0, len(countries))\n\tfor _, country := range countries {\n\t\tcountryList = append(countryList, country)\n\t}\n\t// Sort list.\n\tslices.SortFunc[[]*geoip.CountryInfo, *geoip.CountryInfo](countryList, func(a, b *geoip.CountryInfo) int {\n\t\treturn strings.Compare(a.Name, b.Name)\n\t})\n\n\t// Get continents from countries.\n\tcontinents := make(map[string]*geoip.ContinentInfo)\n\tfor _, country := range countryList {\n\t\tcontinents[country.Continent.Code] = &country.Continent\n\t}\n\t// Convert to list.\n\tcontinentList := make([]*geoip.ContinentInfo, 0, len(continents))\n\tfor _, continent := range continents {\n\t\tcontinentList = append(continentList, continent)\n\t}\n\t// Sort list.\n\tslices.SortFunc[[]*geoip.ContinentInfo, *geoip.ContinentInfo](continentList, func(a, b *geoip.ContinentInfo) int {\n\t\treturn strings.Compare(a.Name, b.Name)\n\t})\n\n\t// Start compiling all options.\n\tselections := make([]selectCountry, 0, len(continents)+len(countries)+2)\n\n\t// Add EU as special region.\n\tselections = append(selections, selectCountry{\n\t\tQuickSetting: config.QuickSetting{\n\t\t\tName:   \"European Union\",\n\t\t\tValue:  []string{\"+ AT\", \"+ BE\", \"+ BG\", \"+ CY\", \"+ CZ\", \"+ DE\", \"+ DK\", \"+ EE\", \"+ ES\", \"+ FI\", \"+ FR\", \"+ GR\", \"+ HR\", \"+ HU\", \"+ IE\", \"+ IT\", \"+ LT\", \"+ LU\", \"+ LV\", \"+ MT\", \"+ NL\", \"+ PL\", \"+ PT\", \"+ RO\", \"+ SE\", \"+ SI\", \"+ SK\", \"- *\"},\n\t\t\tAction: config.QuickReplace,\n\t\t},\n\t\tFlagID: \"EU\",\n\t})\n\tselections = append(selections, selectCountry{\n\t\tQuickSetting: config.QuickSetting{\n\t\t\tName:   \"US and Canada\",\n\t\t\tValue:  []string{\"+ US\", \"+ CA\", \"- *\"},\n\t\t\tAction: config.QuickReplace,\n\t\t},\n\t})\n\n\t// Add countries to quick settings.\n\tfor _, country := range countryList {\n\t\tselections = append(selections, selectCountry{\n\t\t\tQuickSetting: config.QuickSetting{\n\t\t\t\tName:   fmt.Sprintf(\"%s (%s)\", country.Name, country.Code),\n\t\t\t\tValue:  []string{\"+ \" + country.Code, \"- *\"},\n\t\t\t\tAction: config.QuickReplace,\n\t\t\t},\n\t\t\tFlagID: country.Code,\n\t\t})\n\t}\n\n\t// Add continents to quick settings.\n\tfor _, continent := range continentList {\n\t\tselections = append(selections, selectCountry{\n\t\t\tQuickSetting: config.QuickSetting{\n\t\t\t\tName:   fmt.Sprintf(\"%s (C:%s)\", continent.Name, continent.Code),\n\t\t\t\tValue:  []string{\"+ C:\" + continent.Code, \"- *\"},\n\t\t\t\tAction: config.QuickReplace,\n\t\t\t},\n\t\t})\n\t}\n\n\t// Lock config option and set new quick settings.\n\tcfgOption.Lock()\n\tdefer cfgOption.Unlock()\n\tcfgOption.Annotations[config.QuickSettingsAnnotation] = selections\n\n\tlog.Tracer(ctx).Debugf(\"navigator: updated %d countries in quick settings for %s\", len(selections), configKey)\n\treturn nil\n}\n\nfunc (m *Map) updateQuickSettingVerifiedOwnerList(ctx context.Context, configKey string) error {\n\t// Get config option.\n\tcfgOption, err := config.GetOption(configKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get config option %s: %w\", configKey, err)\n\t}\n\n\tpins := m.pinList(true)\n\tverifiedOwners := make([]string, 0, len(pins)/5) // Capacity is an estimation.\n\tfor _, pin := range pins {\n\t\tpin.Lock()\n\t\tvo := pin.VerifiedOwner\n\t\tpin.Unlock()\n\n\t\t// Skip invalid/unneeded values.\n\t\tswitch vo {\n\t\tcase \"\", \"Safing\":\n\t\t\tcontinue\n\t\t}\n\n\t\t// Add to list, if not yet in there.\n\t\tif !slices.Contains[[]string, string](verifiedOwners, vo) {\n\t\t\tverifiedOwners = append(verifiedOwners, vo)\n\t\t}\n\t}\n\n\t// Sort list.\n\tslices.Sort[[]string](verifiedOwners)\n\n\t// Compile list of quick settings.\n\tquickSettings := make([]config.QuickSetting, 0, len(verifiedOwners))\n\tfor _, vo := range verifiedOwners {\n\t\tquickSettings = append(quickSettings, config.QuickSetting{\n\t\t\tName:   fmt.Sprintf(\"Trust %s\", vo),\n\t\t\tValue:  []string{vo},\n\t\t\tAction: config.QuickMergeBottom,\n\t\t})\n\t}\n\n\t// Lock config option and set new quick settings.\n\tcfgOption.Lock()\n\tdefer cfgOption.Unlock()\n\tcfgOption.Annotations[config.QuickSettingsAnnotation] = quickSettings\n\n\tlog.Tracer(ctx).Debugf(\"navigator: updated %d verified owners in quick settings for %s\", len(quickSettings), configKey)\n\treturn nil\n}\n"
  },
  {
    "path": "spn/patrol/domains.go",
    "content": "package patrol\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n)\n\n// getRandomTestDomain returns a random test domain from the test domain list.\n// Not cryptographically secure random, though.\nfunc getRandomTestDomain() string {\n\trng := rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\treturn testDomains[rng.Intn(len(testDomains)-1)]       //nolint:gosec // Weak randomness is not an issue here.\n}\n\n// testDomains is a list of domains to check if they respond successfully to a HTTP GET request.\n// They are sourced from tranco - trimmed, checked, and cleaned.\n// Use TestCleanDomains to clean a new/updated list.\n// Treat as a constant.\nvar testDomains = []string{\n\t\"about.com\",\n\t\"addtoany.com\",\n\t\"adobe.com\",\n\t\"aliyun.com\",\n\t\"ampproject.org\",\n\t\"android.com\",\n\t\"apache.org\",\n\t\"apple.com\",\n\t\"apple.news\",\n\t\"appspot.com\",\n\t\"arnebrachhold.de\",\n\t\"avast.com\",\n\t\"bbc.co.uk\",\n\t\"bbc.com\",\n\t\"bing.com\",\n\t\"blogger.com\",\n\t\"blogspot.com\",\n\t\"branch.io\",\n\t\"calendly.com\",\n\t\"cam.ac.uk\",\n\t\"canonical.com\",\n\t\"canva.com\",\n\t\"cisco.com\",\n\t\"cloudflare.com\",\n\t\"cloudns.net\",\n\t\"cnblogs.com\",\n\t\"cnn.com\",\n\t\"creativecommons.org\",\n\t\"criteo.com\",\n\t\"cupfox.app\",\n\t\"dailymail.co.uk\",\n\t\"ddnss.de\",\n\t\"debian.org\",\n\t\"digitalocean.com\",\n\t\"doi.org\",\n\t\"domainmarket.com\",\n\t\"doubleclick.net\",\n\t\"dreamhost.com\",\n\t\"dropbox.com\",\n\t\"dynect.net\",\n\t\"ed.gov\",\n\t\"elegantthemes.com\",\n\t\"elpais.com\",\n\t\"epa.gov\",\n\t\"eporner.com\",\n\t\"espn.com\",\n\t\"europa.eu\",\n\t\"example.com\",\n\t\"facebook.com\",\n\t\"fb.com\",\n\t\"fb.me\",\n\t\"fb.watch\",\n\t\"fbcdn.net\",\n\t\"feedburner.com\",\n\t\"free.fr\",\n\t\"ftc.gov\",\n\t\"g.page\",\n\t\"getbootstrap.com\",\n\t\"gitlab.com\",\n\t\"gmail.com\",\n\t\"gnu.org\",\n\t\"goo.gl\",\n\t\"google-analytics.com\",\n\t\"google.ca\",\n\t\"google.co.in\",\n\t\"google.co.jp\",\n\t\"google.co.th\",\n\t\"google.co.uk\",\n\t\"google.com.au\",\n\t\"google.com.br\",\n\t\"google.com.hk\",\n\t\"google.com.mx\",\n\t\"google.com.tr\",\n\t\"google.com.tw\",\n\t\"google.com\",\n\t\"google.de\",\n\t\"google.es\",\n\t\"google.fr\",\n\t\"google.it\",\n\t\"googledomains.com\",\n\t\"googlesyndication.com\",\n\t\"gstatic.com\",\n\t\"harvard.edu\",\n\t\"hitomi.la\",\n\t\"hubspot.com\",\n\t\"hugedomains.com\",\n\t\"ibm.com\",\n\t\"icloud.com\",\n\t\"ikea.com\",\n\t\"ilovepdf.com\",\n\t\"indiatimes.com\",\n\t\"instagram.com\",\n\t\"investing.com\",\n\t\"investopedia.com\",\n\t\"irs.gov\",\n\t\"kickstarter.com\",\n\t\"launchpad.net\",\n\t\"lencr.org\",\n\t\"lijit.com\",\n\t\"linkedin.com\",\n\t\"linode.com\",\n\t\"mashable.com\",\n\t\"medium.com\",\n\t\"mega.co.nz\",\n\t\"mega.nz\",\n\t\"merriam-webster.com\",\n\t\"mit.edu\",\n\t\"netflix.com\",\n\t\"nginx.org\",\n\t\"nist.gov\",\n\t\"notion.so\",\n\t\"nsone.net\",\n\t\"office.com\",\n\t\"onetrust.com\",\n\t\"openstreetmap.org\",\n\t\"patreon.com\",\n\t\"pexels.com\",\n\t\"photobucket.com\",\n\t\"php.net\",\n\t\"pki.goog\",\n\t\"plos.org\",\n\t\"ps.kz\",\n\t\"readthedocs.io\",\n\t\"redd.it\",\n\t\"reddit.com\",\n\t\"remove.bg\",\n\t\"rfc-editor.org\",\n\t\"savefrom.net\",\n\t\"sedo.com\",\n\t\"so-net.ne.jp\",\n\t\"sourceforge.net\",\n\t\"spamhaus.org\",\n\t\"speedtest.net\",\n\t\"spotify.com\",\n\t\"stanford.edu\",\n\t\"state.gov\",\n\t\"substack.com\",\n\t\"t.me\",\n\t\"taboola.com\",\n\t\"techcrunch.com\",\n\t\"telegram.me\",\n\t\"telegram.org\",\n\t\"threema.ch\",\n\t\"tinyurl.com\",\n\t\"ubuntu.com\",\n\t\"ui.com\",\n\t\"umich.edu\",\n\t\"uol.com.br\",\n\t\"upenn.edu\",\n\t\"usgs.gov\",\n\t\"utexas.edu\",\n\t\"va.gov\",\n\t\"verisign.com\",\n\t\"vmware.com\",\n\t\"w3.org\",\n\t\"wa.me\",\n\t\"webs.com\",\n\t\"whatsapp.com\",\n\t\"whatsapp.net\",\n\t\"whitehouse.gov\",\n\t\"wikimedia.org\",\n\t\"wikipedia.org\",\n\t\"wiktionary.org\",\n\t\"www.aliyundrive.com\",\n\t\"www.amazon.ca\",\n\t\"www.amazon.co.jp\",\n\t\"www.amazon.co.uk\",\n\t\"www.amazon.com\",\n\t\"www.amazon.de\",\n\t\"www.amazon.es\",\n\t\"www.amazon.fr\",\n\t\"www.amazon.in\",\n\t\"www.amazon.it\",\n\t\"www.aol.com\",\n\t\"www.appsflyer.com\",\n\t\"www.att.com\",\n\t\"www.business.site\",\n\t\"www.ca.gov\",\n\t\"www.canada.ca\",\n\t\"www.cctv.com\",\n\t\"www.cdc.gov\",\n\t\"www.chinaz.com\",\n\t\"www.cloud.com\",\n\t\"www.cnet.com\",\n\t\"www.comcast.com\",\n\t\"www.comcast.net\",\n\t\"www.cornell.edu\",\n\t\"www.crashlytics.com\",\n\t\"www.datadoghq.com\",\n\t\"www.db.com\",\n\t\"www.deloitte.com\",\n\t\"www.dw.com\",\n\t\"www.engadget.com\",\n\t\"www.eset.com\",\n\t\"www.fao.org\",\n\t\"www.fedex.com\",\n\t\"www.flickr.com\",\n\t\"www.force.com\",\n\t\"www.ford.com\",\n\t\"www.frontiersin.org\",\n\t\"www.geeksforgeeks.org\",\n\t\"www.gene.com\",\n\t\"www.genius.com\",\n\t\"www.github.io\",\n\t\"www.gov.uk\",\n\t\"www.gravatar.com\",\n\t\"www.healthline.com\",\n\t\"www.hhs.gov\",\n\t\"www.hichina.com\",\n\t\"www.hinet.net\",\n\t\"www.house.gov\",\n\t\"www.hp.com\",\n\t\"www.huawei.com\",\n\t\"www.hupu.com\",\n\t\"www.ietf.org\",\n\t\"www.immunet.com\",\n\t\"www.independent.co.uk\",\n\t\"www.intel.com\",\n\t\"www.jotform.com\",\n\t\"www.klaviyo.com\",\n\t\"www.launchdarkly.com\",\n\t\"www.live.com\",\n\t\"www.macromedia.com\",\n\t\"www.medallia.com\",\n\t\"www.mediatek.com\",\n\t\"www.medicalnewstoday.com\",\n\t\"www.microsoft.com\",\n\t\"www.mongodb.com\",\n\t\"www.mysql.com\",\n\t\"www.namu.wiki\",\n\t\"www.nasa.gov\",\n\t\"www.nba.com\",\n\t\"www.nbcnews.com\",\n\t\"www.nih.gov\",\n\t\"www.noaa.gov\",\n\t\"www.npr.org\",\n\t\"www.nps.gov\",\n\t\"www.ny.gov\",\n\t\"www.okta.com\",\n\t\"www.openai.com\",\n\t\"www.optimizely.com\",\n\t\"www.oracle.com\",\n\t\"www.outlook.com\",\n\t\"www.paloaltonetworks.com\",\n\t\"www.pbs.org\",\n\t\"www.pixabay.com\",\n\t\"www.plala.or.jp\",\n\t\"www.playstation.com\",\n\t\"www.plesk.com\",\n\t\"www.princeton.edu\",\n\t\"www.prnewswire.com\",\n\t\"www.psu.edu\",\n\t\"www.python.org\",\n\t\"www.qq.com\",\n\t\"www.quantserve.com\",\n\t\"www.quillbot.com\",\n\t\"www.rackspace.com\",\n\t\"www.redhat.com\",\n\t\"www.researchgate.net\",\n\t\"www.roku.com\",\n\t\"www.salesforce.com\",\n\t\"www.skype.com\",\n\t\"www.sun.com\",\n\t\"www.teamviewer.com\",\n\t\"www.ted.com\",\n\t\"www.tesla.com\",\n\t\"www.theguardian.com\",\n\t\"www.typeform.com\",\n\t\"www.uchicago.edu\",\n\t\"www.ucla.edu\",\n\t\"www.usda.gov\",\n\t\"www.usps.com\",\n\t\"www.utorrent.com\",\n\t\"www.warnerbros.com\",\n\t\"www.webex.com\",\n\t\"www.who.int\",\n\t\"www.worldbank.org\",\n\t\"www.xbox.com\",\n\t\"www.xerox.com\",\n\t\"www.youdao.com\",\n\t\"www.zdnet.com\",\n\t\"www.zebra.com\",\n\t\"yahoo.com\",\n\t\"yale.edu\",\n\t\"yandex.com\",\n\t\"yandex.net\",\n\t\"youku.com\",\n\t\"youtu.be\",\n\t\"youtube.com\",\n\t\"zemanta.com\",\n\t\"zoro.to\",\n}\n"
  },
  {
    "path": "spn/patrol/domains_test.go",
    "content": "package patrol\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\t\"testing\"\n)\n\nvar enableDomainTools = \"no\" // change to \"yes\" to enable\n\n// TestCleanDomains checks, cleans and prints an improved domain list.\n// Run with:\n// go test -run ^TestCleanDomains$ github.com/safing/portmaster/spn/patrol -ldflags \"-X github.com/safing/portmaster/spn/patrol.enableDomainTools=yes\" -timeout 3h -v\n// This is provided as a test for easier maintenance and ops.\nfunc TestCleanDomains(t *testing.T) { //nolint:paralleltest\n\tif enableDomainTools != \"yes\" {\n\t\tt.Skip()\n\t\treturn\n\t}\n\n\t// Setup context.\n\tctx := context.Background()\n\n\t// Go through all domains and check if they are reachable.\n\tgoodDomains := make([]string, 0, len(testDomains))\n\tfor _, domain := range testDomains {\n\t\t// Check if domain is reachable.\n\t\tcode, err := domainIsUsable(ctx, domain)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"FAIL: %s: %s\\n\", domain, err)\n\t\t} else {\n\t\t\tfmt.Printf(\"OK: %s [%d]\\n\", domain, code)\n\t\t\tgoodDomains = append(goodDomains, domain)\n\t\t\tcontinue\n\t\t}\n\n\t\t// If failed, try again with a www. prefix\n\t\twwwDomain := \"www.\" + domain\n\t\tcode, err = domainIsUsable(ctx, wwwDomain)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"FAIL: %s: %s\\n\", wwwDomain, err)\n\t\t} else {\n\t\t\tfmt.Printf(\"OK: %s [%d]\\n\", wwwDomain, code)\n\t\t\tgoodDomains = append(goodDomains, wwwDomain)\n\t\t}\n\n\t}\n\n\tsort.Strings(goodDomains)\n\tfmt.Println(\"printing good domains:\")\n\tfor _, domain := range goodDomains {\n\t\tfmt.Printf(\"%q,\\n\", domain)\n\t}\n\n\tfmt.Println(\"IMPORTANT: do not forget to go through list and check if everything looks good\")\n}\n\nfunc domainIsUsable(ctx context.Context, domain string) (statusCode int, err error) {\n\t// Try IPv6 first as it is way more likely to fail.\n\tstatusCode, err = CheckHTTPSConnection(ctx, \"tcp6\", domain)\n\tif err != nil {\n\t\treturn\n\t}\n\n\treturn CheckHTTPSConnection(ctx, \"tcp4\", domain)\n}\n"
  },
  {
    "path": "spn/patrol/http.go",
    "content": "package patrol\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\nvar httpsConnectivityConfirmed = abool.NewBool(true)\n\n// HTTPSConnectivityConfirmed returns whether the last HTTPS connectivity check succeeded.\n// Is \"true\" before first test.\nfunc HTTPSConnectivityConfirmed() bool {\n\treturn httpsConnectivityConfirmed.IsSet()\n}\n\nfunc connectivityCheckTask(wc *mgr.WorkerCtx) error {\n\t// Start tracing logs.\n\tctx, tracer := log.AddTracer(wc.Ctx())\n\tdefer tracer.Submit()\n\n\t// Run checks and report status.\n\tsuccess := runConnectivityChecks(ctx)\n\tif success {\n\t\ttracer.Info(\"spn/patrol: all connectivity checks succeeded\")\n\t\tif httpsConnectivityConfirmed.SetToIf(false, true) {\n\t\t\tmodule.EventChangeSignal.Submit(struct{}{})\n\t\t}\n\t\treturn nil\n\t}\n\n\ttracer.Errorf(\"spn/patrol: connectivity check failed\")\n\tif httpsConnectivityConfirmed.SetToIf(true, false) {\n\t\tmodule.EventChangeSignal.Submit(struct{}{})\n\t}\n\treturn nil\n}\n\nfunc runConnectivityChecks(ctx context.Context) (ok bool) {\n\tswitch {\n\tcase conf.HubHasIPv4() && !runHTTPSConnectivityChecks(ctx, \"tcp4\"):\n\t\treturn false\n\tcase conf.HubHasIPv6() && !runHTTPSConnectivityChecks(ctx, \"tcp6\"):\n\t\treturn false\n\tdefault:\n\t\t// All checks passed.\n\t\treturn true\n\t}\n}\n\nfunc runHTTPSConnectivityChecks(ctx context.Context, network string) (ok bool) {\n\t// Step 1: Check 1 domain, require 100%\n\tif checkHTTPSConnectivity(ctx, network, 1, 1) {\n\t\treturn true\n\t}\n\n\t// Step 2: Check 5 domains, require 80%\n\tif checkHTTPSConnectivity(ctx, network, 5, 0.8) {\n\t\treturn true\n\t}\n\n\t// Step 3: Check 20 domains, require 70%\n\tif checkHTTPSConnectivity(ctx, network, 20, 0.7) {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc checkHTTPSConnectivity(ctx context.Context, network string, checks int, requiredSuccessFraction float32) (ok bool) {\n\tlog.Tracer(ctx).Tracef(\n\t\t\"spn/patrol: testing connectivity via https (%d checks; %.0f%% required)\",\n\t\tchecks,\n\t\trequiredSuccessFraction*100,\n\t)\n\n\t// Run tests.\n\tvar succeeded int\n\tfor range checks {\n\t\tif checkHTTPSConnection(ctx, network) {\n\t\t\tsucceeded++\n\t\t}\n\t}\n\n\t// Check success.\n\tsuccessFraction := float32(succeeded) / float32(checks)\n\tif successFraction < requiredSuccessFraction {\n\t\tlog.Tracer(ctx).Warningf(\n\t\t\t\"spn/patrol: https/%s connectivity check failed: %d/%d (%.0f%%)\",\n\t\t\tnetwork,\n\t\t\tsucceeded,\n\t\t\tchecks,\n\t\t\tsuccessFraction*100,\n\t\t)\n\t\treturn false\n\t}\n\n\tlog.Tracer(ctx).Debugf(\n\t\t\"spn/patrol: https/%s connectivity check succeeded: %d/%d (%.0f%%)\",\n\t\tnetwork,\n\t\tsucceeded,\n\t\tchecks,\n\t\tsuccessFraction*100,\n\t)\n\treturn true\n}\n\nfunc checkHTTPSConnection(ctx context.Context, network string) (ok bool) {\n\ttestDomain := getRandomTestDomain()\n\tcode, err := CheckHTTPSConnection(ctx, network, testDomain)\n\tif err != nil {\n\t\tlog.Tracer(ctx).Debugf(\"spn/patrol: https/%s connect check failed: %s: %s\", network, testDomain, err)\n\t\treturn false\n\t}\n\n\tlog.Tracer(ctx).Tracef(\"spn/patrol: https/%s connect check succeeded: %s [%d]\", network, testDomain, code)\n\treturn true\n}\n\n// CheckHTTPSConnection checks if a HTTPS connection to the given domain can be established.\nfunc CheckHTTPSConnection(ctx context.Context, network, domain string) (statusCode int, err error) {\n\t// Check network parameter.\n\tswitch network {\n\tcase \"tcp4\":\n\tcase \"tcp6\":\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"provided unsupported network: %s\", network)\n\t}\n\n\t// Build URL.\n\t// Use HTTPS to ensure that we have really communicated with the desired\n\t// server and not with an intermediate.\n\turl := fmt.Sprintf(\"https://%s/\", domain)\n\n\t// Prepare all parts of the request.\n\t// TODO: Evaluate if we want to change the User-Agent.\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tdialer := &net.Dialer{\n\t\tTimeout:       15 * time.Second,\n\t\tLocalAddr:     conf.GetBindAddr(network),\n\t\tFallbackDelay: -1, // Disables Fast Fallback from IPv6 to IPv4.\n\t\tKeepAlive:     -1, // Disable keep-alive.\n\t}\n\tdialWithNet := func(ctx context.Context, _, addr string) (net.Conn, error) {\n\t\t// Ignore network by http client.\n\t\t// Instead, force either tcp4 or tcp6.\n\t\treturn dialer.DialContext(ctx, network, addr)\n\t}\n\tclient := &http.Client{\n\t\tTransport: &http.Transport{\n\t\t\tDialContext:         dialWithNet,\n\t\t\tDisableKeepAlives:   true,\n\t\t\tDisableCompression:  true,\n\t\t\tTLSHandshakeTimeout: 15 * time.Second,\n\t\t},\n\t\tCheckRedirect: func(req *http.Request, via []*http.Request) error {\n\t\t\treturn http.ErrUseLastResponse\n\t\t},\n\t\tTimeout: 30 * time.Second,\n\t}\n\n\t// Make request to server.\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to send http request: %w\", err)\n\t}\n\tdefer func() {\n\t\t_ = resp.Body.Close()\n\t}()\n\tif resp.StatusCode < 200 || resp.StatusCode >= 400 {\n\t\treturn resp.StatusCode, fmt.Errorf(\"unexpected status code: %s\", resp.Status)\n\t}\n\n\treturn resp.StatusCode, nil\n}\n"
  },
  {
    "path": "spn/patrol/module.go",
    "content": "package patrol\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\n// ChangeSignalEventName is the name of the event that signals any change in the patrol system.\nconst ChangeSignalEventName = \"change signal\"\n\ntype Patrol struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n\n\tEventChangeSignal *mgr.EventMgr[struct{}]\n}\n\nfunc (p *Patrol) Manager() *mgr.Manager {\n\treturn p.mgr\n}\n\nfunc (p *Patrol) Start() error {\n\tif conf.PublicHub() {\n\t\tp.mgr.Repeat(\"connectivity test\", 5*time.Minute, connectivityCheckTask)\n\t}\n\treturn nil\n}\n\nfunc (p *Patrol) Stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *Patrol\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Config module.\nfunc New(instance instance) (*Patrol, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Patrol\")\n\tmodule = &Patrol{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\n\t\tEventChangeSignal: mgr.NewEventMgr[struct{}](ChangeSignalEventName, m),\n\t}\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/ships/connection_test.go",
    "content": "package ships\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nvar (\n\ttestPort  uint16 = 65000\n\ttestData         = []byte(\"The quick brown fox jumps over the lazy dog\")\n\tlocalhost        = net.IPv4(127, 0, 0, 1)\n)\n\nfunc getTestPort() uint16 {\n\ttestPort++\n\treturn testPort\n}\n\nfunc getTestBuf() []byte {\n\treturn make([]byte, len(testData))\n}\n\nfunc TestConnections(t *testing.T) {\n\tt.Parallel()\n\n\tregistryLock.Lock()\n\tt.Cleanup(func() {\n\t\tregistryLock.Unlock()\n\t})\n\n\tfor protocol, builder := range registry {\n\t\tt.Run(protocol, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar wg sync.WaitGroup\n\t\t\tctx, cancelCtx := context.WithCancel(context.Background())\n\n\t\t\t// docking requests\n\t\t\tdockingRequests := make(chan Ship, 1)\n\t\t\ttransport := &hub.Transport{\n\t\t\t\tProtocol: protocol,\n\t\t\t\tPort:     getTestPort(),\n\t\t\t}\n\n\t\t\t// create listener\n\t\t\tpier, err := builder.EstablishPier(transport, dockingRequests)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\t// connect to listener\n\t\t\tship, err := builder.LaunchShip(ctx, transport, localhost)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\t\t// client send\n\t\t\terr = ship.Load(testData)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t\t}\n\n\t\t\t// dock client\n\t\t\tsrvShip := <-dockingRequests\n\t\t\tif srvShip == nil {\n\t\t\t\tt.Fatalf(\"%s failed to dock\", pier)\n\t\t\t}\n\n\t\t\t// server recv\n\t\t\tbuf := getTestBuf()\n\t\t\t_, err = srvShip.UnloadTo(buf)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t\t}\n\n\t\t\t// check data\n\t\t\tassert.Equal(t, testData, buf, \"should match\")\n\t\t\tfmt.Print(\".\")\n\n\t\t\tfor range 100 {\n\t\t\t\t// server send\n\t\t\t\terr = srvShip.Load(testData)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t\t\t}\n\n\t\t\t\t// client recv\n\t\t\t\tbuf = getTestBuf()\n\t\t\t\t_, err = ship.UnloadTo(buf)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t\t\t}\n\n\t\t\t\t// check data\n\t\t\t\tassert.Equal(t, testData, buf, \"should match\")\n\t\t\t\tfmt.Print(\".\")\n\n\t\t\t\t// client send\n\t\t\t\terr = ship.Load(testData)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t\t\t}\n\n\t\t\t\t// server recv\n\t\t\t\tbuf = getTestBuf()\n\t\t\t\t_, err = srvShip.UnloadTo(buf)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t\t\t}\n\n\t\t\t\t// check data\n\t\t\t\tassert.Equal(t, testData, buf, \"should match\")\n\t\t\t\tfmt.Print(\".\")\n\t\t\t}\n\n\t\t\tship.Sink()\n\t\t\tsrvShip.Sink()\n\t\t\tpier.Abolish()\n\t\t\tcancelCtx()\n\t\t\twg.Wait() // wait for docking procedure to end\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "spn/ships/http.go",
    "content": "package ships\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// HTTPShip is a ship that uses HTTP.\ntype HTTPShip struct {\n\tShipBase\n}\n\n// HTTPPier is a pier that uses HTTP.\ntype HTTPPier struct {\n\tPierBase\n\n\tnewDockings chan net.Conn\n}\n\nfunc init() {\n\tRegister(\"http\", &Builder{\n\t\tLaunchShip:    launchHTTPShip,\n\t\tEstablishPier: establishHTTPPier,\n\t})\n}\n\n/*\nHTTP Transport Variants:\n\n1. Hijack connection and switch to raw SPN protocol:\n\nRequest:\n\n\t\tGET <path> HTTP/1.1\n\t\tConnection: Upgrade\n\t\tUpgrade: SPN\n\nResponse:\n\n\t\tHTTP/1.1 101 Switching Protocols\n\t\tConnection: Upgrade\n\t\tUpgrade: SPN\n\n*/\n\nfunc launchHTTPShip(ctx context.Context, transport *hub.Transport, ip net.IP) (Ship, error) {\n\t// Default to root path.\n\tpath := transport.Path\n\tif path == \"\" {\n\t\tpath = \"/\"\n\t}\n\n\t// Build request for Variant 1.\n\tvariant := 1\n\trequest, err := http.NewRequest(http.MethodGet, path, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build HTTP request: %w\", err)\n\t}\n\trequest.Header.Set(\"Connection\", \"Upgrade\")\n\trequest.Header.Set(\"Upgrade\", \"SPN\")\n\n\t// Create connection.\n\tvar dialNet string\n\tif ip4 := ip.To4(); ip4 != nil {\n\t\tdialNet = \"tcp4\"\n\t} else {\n\t\tdialNet = \"tcp6\"\n\t}\n\tdialer := &net.Dialer{\n\t\tTimeout:       30 * time.Second,\n\t\tLocalAddr:     conf.GetBindAddr(dialNet),\n\t\tFallbackDelay: -1, // Disables Fast Fallback from IPv6 to IPv4.\n\t\tKeepAlive:     -1, // Disable keep-alive.\n\t}\n\tconn, err := dialer.DialContext(ctx, dialNet, net.JoinHostPort(ip.String(), portToA(transport.Port)))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to connect: %w\", err)\n\t}\n\n\t// Send HTTP request.\n\terr = request.Write(conn)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to send HTTP request: %w\", err)\n\t}\n\n\t// Receive HTTP response.\n\tresponse, err := http.ReadResponse(bufio.NewReader(conn), request)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read HTTP response: %w\", err)\n\t}\n\tdefer response.Body.Close() //nolint:errcheck,gosec\n\n\t// Handle response according to variant.\n\tswitch variant {\n\tcase 1:\n\t\tif response.StatusCode == http.StatusSwitchingProtocols &&\n\t\t\tresponse.Header.Get(\"Connection\") == \"Upgrade\" &&\n\t\t\tresponse.Header.Get(\"Upgrade\") == \"SPN\" {\n\t\t\t// Continue\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"received unexpected response for variant 1: %s\", response.Status)\n\t\t}\n\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"internal error: unsupported http transport variant: %d\", variant)\n\t}\n\n\t// Create ship.\n\tship := &HTTPShip{\n\t\tShipBase: ShipBase{\n\t\t\tconn:      conn,\n\t\t\ttransport: transport,\n\t\t\tmine:      true,\n\t\t\tsecure:    false,\n\t\t},\n\t}\n\n\t// Init and return.\n\tship.calculateLoadSize(ip, nil, TCPHeaderMTUSize)\n\tship.initBase()\n\treturn ship, nil\n}\n\nfunc (pier *HTTPPier) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tswitch {\n\tcase r.Method == http.MethodGet &&\n\t\tr.Header.Get(\"Connection\") == \"Upgrade\" &&\n\t\tr.Header.Get(\"Upgrade\") == \"SPN\":\n\t\t// Request for Variant 1.\n\n\t\t// Hijack connection.\n\t\tvar conn net.Conn\n\t\tif hijacker, ok := w.(http.Hijacker); ok {\n\t\t\t// Empty body, so the hijacked connection starts with a clean buffer.\n\t\t\t_, err := io.ReadAll(r.Body)\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(w, \"\", http.StatusInternalServerError)\n\t\t\t\tlog.Warningf(\"ships: failed to empty body for hijack for %s: %s\", r.RemoteAddr, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t_ = r.Body.Close()\n\n\t\t\t// Reply with upgrade confirmation.\n\t\t\tw.Header().Set(\"Connection\", \"Upgrade\")\n\t\t\tw.Header().Set(\"Upgrade\", \"SPN\")\n\t\t\tw.WriteHeader(http.StatusSwitchingProtocols)\n\n\t\t\t// Get connection.\n\t\t\tconn, _, err = hijacker.Hijack()\n\t\t\tif err != nil {\n\t\t\t\tlog.Warningf(\"ships: failed to hijack http connection from %s: %s\", r.RemoteAddr, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t} else {\n\t\t\thttp.Error(w, \"\", http.StatusInternalServerError)\n\t\t\tlog.Warningf(\"ships: connection from %s cannot be hijacked\", r.RemoteAddr)\n\t\t\treturn\n\t\t}\n\n\t\t// Create new ship.\n\t\tship := &HTTPShip{\n\t\t\tShipBase: ShipBase{\n\t\t\t\ttransport: pier.transport,\n\t\t\t\tconn:      conn,\n\t\t\t\tmine:      false,\n\t\t\t\tsecure:    false,\n\t\t\t},\n\t\t}\n\t\tship.calculateLoadSize(nil, conn.RemoteAddr(), TCPHeaderMTUSize)\n\t\tship.initBase()\n\n\t\t// Submit new docking request.\n\t\tselect {\n\t\tcase pier.dockingRequests <- ship:\n\t\tcase <-r.Context().Done():\n\t\t\treturn\n\t\t}\n\n\tdefault:\n\t\t// Reply with info page if no variant matches the request.\n\t\tServeInfoPage(w, r)\n\t}\n}\n\nfunc establishHTTPPier(transport *hub.Transport, dockingRequests chan Ship) (Pier, error) {\n\t// Default to root path.\n\tpath := transport.Path\n\tif path == \"\" {\n\t\tpath = \"/\"\n\t}\n\n\t// Create pier.\n\tpier := &HTTPPier{\n\t\tnewDockings: make(chan net.Conn),\n\t\tPierBase: PierBase{\n\t\t\ttransport:       transport,\n\t\t\tdockingRequests: dockingRequests,\n\t\t},\n\t}\n\tpier.initBase()\n\n\t// Register handler.\n\terr := addHTTPHandler(transport.Port, path, pier.ServeHTTP)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to add HTTP handler: %w\", err)\n\t}\n\n\treturn pier, nil\n}\n\n// Abolish closes the underlying listener and cleans up any related resources.\nfunc (pier *HTTPPier) Abolish() {\n\t// Only abolish once.\n\tif !pier.abolishing.SetToIf(false, true) {\n\t\treturn\n\t}\n\n\t// Do not close the listener, as it is shared.\n\t// Instead, remove the HTTP handler and the shared server will shutdown itself when needed.\n\t_ = removeHTTPHandler(pier.transport.Port, pier.transport.Path)\n}\n"
  },
  {
    "path": "spn/ships/http_info.go",
    "content": "package ships\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"html/template\"\n\t\"net/http\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/info\"\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nvar (\n\t//go:embed http_info_page.html.tmpl\n\tinfoPageData string\n\n\tinfoPageTemplate *template.Template\n\n\t// DisplayHubID holds the Hub ID for displaying it on the info page.\n\tDisplayHubID string\n)\n\ntype infoPageInput struct {\n\tVersion        string\n\tInfo           *info.Info\n\tID             string\n\tName           string\n\tGroup          string\n\tContactAddress string\n\tContactService string\n}\n\nvar (\n\tpageInputName           config.StringOption\n\tpageInputGroup          config.StringOption\n\tpageInputContactAddress config.StringOption\n\tpageInputContactService config.StringOption\n)\n\nfunc initPageInput() {\n\tinfoPageTemplate = template.Must(template.New(\"info-page\").Parse(infoPageData))\n\n\tpageInputName = config.Concurrent.GetAsString(\"spn/publicHub/name\", \"\")\n\tpageInputGroup = config.Concurrent.GetAsString(\"spn/publicHub/group\", \"\")\n\tpageInputContactAddress = config.Concurrent.GetAsString(\"spn/publicHub/contactAddress\", \"\")\n\tpageInputContactService = config.Concurrent.GetAsString(\"spn/publicHub/contactService\", \"\")\n}\n\n// ServeInfoPage serves the info page for the given request.\nfunc ServeInfoPage(w http.ResponseWriter, r *http.Request) {\n\tpageData, err := renderInfoPage()\n\tif err != nil {\n\t\tlog.Warningf(\"ships: failed to render SPN info page: %s\", err)\n\t\thttp.Error(w, \"\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t_, err = w.Write(pageData)\n\tif err != nil {\n\t\tlog.Warningf(\"ships: failed to write info page: %s\", err)\n\t}\n}\n\nfunc renderInfoPage() ([]byte, error) {\n\tinput := &infoPageInput{\n\t\tVersion:        info.Version(),\n\t\tInfo:           info.GetInfo(),\n\t\tID:             DisplayHubID,\n\t\tName:           pageInputName(),\n\t\tGroup:          pageInputGroup(),\n\t\tContactAddress: pageInputContactAddress(),\n\t\tContactService: pageInputContactService(),\n\t}\n\n\tbuf := &bytes.Buffer{}\n\terr := infoPageTemplate.ExecuteTemplate(buf, \"info-page\", input)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n"
  },
  {
    "path": "spn/ships/http_info_page.html.tmpl",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>SPN Node</title>\n  <style>\n    /* Lissom.CSS - https://github.com/lissomware/css */\n    blockquote,button,details[open],input[type=submit],th{background-color:var(--accent-alt)}button:active,h2::before,input[type=submit]:active{opacity:.9}button:hover,h4::before,input[type=submit]:hover{opacity:.7}blockquote::after,h1::before,h2::before,h3::before,h4::before,h5::before,h6::before{position:absolute}a:hover,h1::before,h2::before,h3::before,h4::before,h5::before,h6::before{color:var(--accent-ui)}kbd,summary{font-weight:700}dialog,mark{color:inherit}details,pre{padding:.5em;background-color:var(--tertiary)}hr,td{text-align:center}body,dialog,html,tr:nth-child(2n) td{background-color:var(--light)}code,details,input,kbd,pre,textarea,tr:nth-child(odd) td{background-color:var(--tertiary)}*{box-sizing:border-box}:root{--primary:hsl(265, 38%, 13%);--secondary:hsl(283, 6%, 45%);--tertiary:hsl(257, 15%, 95%);--light:hsl(270, 100%, 99%);--accent:#0376bb;--accent-alt:hsl(279, 100%, 97%);--accent-ui:#0376bb;--semantic-green:hsl(88, 76%, 83%);--semantic-red:hsl(0, 76%, 83%)}@media (prefers-color-scheme:dark){:root{--primary:hsl(300, 100%, 99%);--secondary:hsl(280, 5%, 37%);--tertiary:hsl(270, 5%, 16%);--light:hsl(280, 5%, 12%);--accent:hsl(282, 25%, 40%);--accent-alt:hsl(278, 14%, 20%);--accent-ui:#0376bb;--semantic-green:hsl(88, 35%, 40%);--semantic-red:hsl(0, 35%, 40%)}}body,html{color-scheme:light;accent-color:var(--accent-ui);color:var(--primary);font-family:sans-serif;margin:0;padding:0;line-height:1.4}main{width:min(100% - 3rem,65ch);margin-inline:auto;margin-top:2em;margin-bottom:2em}a{color:var(--primary);text-decoration-color:var(--accent-ui);text-underline-offset:0.15em;text-decoration-thickness:0.1em}a:hover{text-decoration-thickness:0.2em;z-index:2}a:focus-visible{background-color:var(--accent-ui);box-shadow:0 0 0 .2em var(--light),0 0 0 .4em var(--accent-ui);outline:0;z-index:2;animation:1s linear infinite alternate-reverse pulseFill;border-radius:.1em;position:relative}@keyframes pulseFill{0%{background-color:var(--accent-ui);box-shadow:0 0 0 .2em var(--light),0 0 0 .4em var(--accent-ui)}100%{background-color:var(--accent);box-shadow:0 0 0 .2em var(--light),0 0 0 .4em var(--accent)}}blockquote{margin:1.5em 0;position:relative;padding:.7em;z-index:1;border-radius:.5em}blockquote p{margin:0}blockquote::after,blockquote::before{color:var(--accent-ui);font-size:5em;line-height:.8}button,input,input[type=submit],textarea{padding:.4em 1em;font-size:inherit;position:relative;color:var(--primary)}blockquote::before{content:open-quote;vertical-align:top;position:absolute;left:-.15em;top:-.1em}blockquote::after{content:close-quote;vertical-align:bottom;right:-.1em;bottom:-.65em}[lang=fr] blockquote::after,[lang=fr] blockquote::before{font-size:3.5em}[lang=fr] blockquote::before{left:-.3em;top:-.4em}[lang=fr] blockquote::after{right:-.3em;bottom:-.3em}button,input[type=submit]{border:1px solid var(--accent);border-radius:.3em;cursor:pointer}input::placeholder{font-style:italic}button[data-primary],input[type=submit]{color:var(--light);background-color:var(--accent-ui);border-color:var(--accent-ui);outline:1px solid var(--accent);outline-offset:-0.15em;padding:.4em .8em;border-radius:.3em;cursor:pointer;font-weight:700}button:disabled,input:disabled,input[type=submit]:disabled,textarea:disabled{cursor:not-allowed;background-color:var(--tertiary);color:var(--secondary);border-color:var(--secondary);opacity:.5}button:focus-visible,details:has(summary:focus-visible),input:focus-visible,textarea:focus-visible{box-shadow:0 0 0 .2em var(--light),0 0 0 .4em var(--accent-ui);outline:0;z-index:2;animation:1s linear infinite alternate-reverse pulseBorder}details:has(summary:focus-visible) summary{outline:0}@keyframes pulseBorder{0%{box-shadow:0 0 0 .2em var(--light),0 0 0 .4em var(--accent-ui)}100%{box-shadow:0 0 0 .2em var(--light),0 0 0 .4em var(--accent)}}code{border-radius:.3em;font-family:monospace;padding:.1em .2em}details{border:.1em solid var(--secondary);border-radius:.3em;margin:1em 0}details[open] summary{border-bottom:.1em solid var(--accent);padding-bottom:.3em;margin-bottom:.7em}dialog{border-radius:.6em;max-width:min(100% - 3rem,65ch);border:1px solid var(--accent-ui);box-shadow:0 0 .3em .1em var(--accent-alt)}hr,progress{border:none;margin:1em 0}::backdrop{background:rgba(0,0,0,.5)}form:not([data-modal]){display:flex;flex-direction:column;gap:.5rem;margin:1em 0}form>div{display:flex;flex-direction:column}form>div:has(input[type=checkbox]){flex-direction:row;align-items:center;gap:.2em}h1,h2,h3,h4,h5,h6{position:relative}h1::before{content:'#';left:-2ch}h1:dir(rtl)::before{right:-2ch}h2::before{content:'##';left:-3ch}h2:dir(rtl)::before{right:-3ch}h3::before{content:'###';left:-4ch;opacity:.8}h3:dir(rtl)::before{right:-4ch}h4::before{content:'####';left:-5ch}h4:dir(rtl)::before{right:-5ch}h5::before{content:'#####';left:-6ch;opacity:.6}h5:dir(rtl)::before{right:-6ch}h6::before{content:'######';left:-7ch;opacity:.5}h6:dir(rtl)::before{right:-7ch}h1[data-no-heading-level]::before,h2[data-no-heading-level]::before,h3[data-no-heading-level]::before,h4[data-no-heading-level]::before,h5[data-no-heading-level]::before,h6[data-no-heading-level]::before{content:''}hr{border-top:.2em double var(--primary);color:var(--primary);overflow:visible;height:.4em}hr:after{background:var(--light);content:'§';padding:0 4px;position:relative;top:-13px}img{border-radius:.6em;width:100%;height:auto;transition:border-radius .1s linear}img:hover{border-radius:0}input,textarea{border:1px solid var(--secondary);border-radius:.3em;font-family:inherit}kbd{border-radius:.3em;border:1px solid var(--secondary);box-shadow:0 1px 1px var(--secondary),0 2px 0 0 var(--light) inset;color:var(--primary);display:inline-block;font-size:.85em;line-height:1;padding:.2em .4em;white-space:nowrap}mark{background-color:var(--accent)}pre{font-family:monospace;color:var(--primary);border-radius:.6em;border:1px solid var(--secondary)}progress{appearance:none;-moz-appearance:none;-webkit-appearance:none;border-radius:1em;display:block;height:.5rem;overflow:hidden;padding:0;width:100%}progress::-webkit-progress-bar{background-color:var(--accent)}progress::-webkit-progress-value{background-color:var(--accent-ui)}progress::-moz-progress-bar{background-color:var(--accent-ui)}progress::-ms-fill{background-color:var(--accent-ui);border:none}progress:indeterminate{animation:3s linear infinite progressShine;background-color:var(--accent);background-image:linear-gradient(to right,var(--accent) 0,var(--accent-ui) 10%,var(--accent-ui) 30%,var(--accent) 40%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}progress:indeterminate:dir(rtl){animation-direction:reverse}progress:indeterminate::-webkit-progress-bar{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}progress:indeterminate::-ms-fill{animation-name:none}@keyframes progressShine{0%{background-position:200% 0}100%{background-position:-200% 0}}caption{padding:.8em;caption-side:bottom}table{border-collapse:collapse;border:.1em solid var(--secondary);border-radius:.6em}td,th{border:1px solid var(--secondary);padding:.4em .3em}ins{background-color:var(--semantic-green)}del{background-color:var(--semantic-red)}\n  </style>\n</head>\n<body>\n  <main>\n    <section>\n      <h1>\n        You Have Reached an SPN Node\n      </h1>\n      <p>\n        The server, or at least the exact URL you have accessed, leads to an SPN Node.\n      </p>\n    </section>\n\n    <section>\n      <h3>\n        What is SPN?\n      </h3>\n      <p>\n        SPN stands for \"Safing Privacy Network\" and is a network of servers that offers high privacy protection of Internet traffic and activity. It was built to replace VPNs for their Internet privacy use case.\n      </p>\n    </section>\n\n    <section>\n      <h3>\n        More Information\n      </h3>\n      <p>\n        You can find out more about SPN here:\n        <ul>\n          <li>Features: <a href=\"https://safing.io/spn/\">https://safing.io/spn/</a></li>\n          <li>Node Hosting Guide: <a href=\"https://wiki.safing.io/en/SPN/Nodes/Hosting\">https://wiki.safing.io/en/SPN/Nodes/Hosting</a></li>\n        </ul>\n      </p>\n    </section>\n\n    <section>\n      <h3>\n        Contact the Operator of This SPN Node\n      </h3>\n      <p>\n        {{ if .ContactAddress }}\n          You can reach the operator of this SPN Node here:\n          {{ .ContactAddress }}\n            {{ if .ContactService }} via {{ .ContactService }}\n          {{ end }}\n        {{ else }}\n          The operator of this SPN Node has not configured any contact data.<br>\n          Please contact the operator using the usual methods via the hosting provider.\n        {{ end }}\n      </p>\n    </section>\n\n    <section>\n      <h3>\n        Are You Tracing Bad Activity?\n      </h3>\n      <p>\n        We are sorry there is an incident involving this server. We condemn any disruptive or illegal activity.\n      <p>\n      </p>\n        Please note that servers are not only operated by Safing (the company behind SPN), but also by third parties.\n      <p>\n      </p>\n        The SPN works very similar to Tor. Its primary goal is to provide people more privacy on the Internet. We also provide our services to people behind censoring firewalls in oppressive regimes.\n      <p>\n      </p>\n        This server does not host any content (as part of its role in the SPN network). Rather, it is part of the network where nodes on the Internet simply pass packets among themselves before sending them to their destinations, just as any Internet intermediary does.\n      <p>\n      </p>\n        Please understand that the SPN makes it technically impossible to single out individual users. We are also legally bound to respective privacy rights.\n      </p>\n      <p>\n        We can offer to block specific destination IPs and ports, but the abuser doesn't use this server specifically; instead, they will just be routed through a different exit node outside of our control.\n      </p>\n    </section>\n\n    <section>\n      <h3>\n        SPN Node Info\n      </h3>\n      <p>\n        <ul style=\"list-style: none;\">\n          <li>Name: {{ .Name }}</li>\n          <li>Group: {{ .Group }}</li>\n          <li>ContactAddress: {{ .ContactAddress }}</li>\n          <li>ContactService: {{ .ContactService }}</li>\n          <li>Version: {{ .Version }}</li>\n          <li>ID: {{ .ID }}</li>\n          <li>\n            Build:\n            <ul style=\"list-style: none;\">\n              <li>Commit: {{ .Info.Commit }}</li>\n              <li>At: {{ .Info.CommitTime }}</li>\n              <li>From: {{ .Info.Source }}</li>\n            </ul>\n          </li>\n        </ul>\n      </p>\n    </section>\n  </main>\n</body>\n</html>\n"
  },
  {
    "path": "spn/ships/http_info_test.go",
    "content": "package ships\n\nimport (\n\t\"html/template\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/config\"\n)\n\nfunc TestInfoPageTemplate(t *testing.T) {\n\tt.Parallel()\n\n\tinfoPageTemplate = template.Must(template.New(\"info-page\").Parse(infoPageData))\n\tpageInputName = config.Concurrent.GetAsString(\"spn/publicHub/name\", \"node-name\")\n\tpageInputGroup = config.Concurrent.GetAsString(\"spn/publicHub/group\", \"node-group\")\n\tpageInputContactAddress = config.Concurrent.GetAsString(\"spn/publicHub/contactAddress\", \"john@doe.com\")\n\tpageInputContactService = config.Concurrent.GetAsString(\"spn/publicHub/contactService\", \"email\")\n\n\tpageData, err := renderInfoPage()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t_ = pageData\n\t// t.Log(string(pageData))\n}\n"
  },
  {
    "path": "spn/ships/http_shared.go",
    "content": "package ships\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype sharedServer struct {\n\tserver *http.Server\n\n\thandlers     map[string]http.HandlerFunc\n\thandlersLock sync.RWMutex\n}\n\n// ServeHTTP forwards requests to registered handler or uses defaults.\nfunc (shared *sharedServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tshared.handlersLock.Lock()\n\tdefer shared.handlersLock.Unlock()\n\n\t// Get and forward to registered handler.\n\thandler, ok := shared.handlers[r.URL.Path]\n\tif ok {\n\t\thandler(w, r)\n\t\treturn\n\t}\n\n\t// If there is registered handler and path is \"/\", respond with info page.\n\tif r.Method == http.MethodGet && r.URL.Path == \"/\" {\n\t\tServeInfoPage(w, r)\n\t\treturn\n\t}\n\n\t// Otherwise, respond with error.\n\thttp.Error(w, \"\", http.StatusNotFound)\n}\n\nvar (\n\tsharedHTTPServers     = make(map[uint16]*sharedServer)\n\tsharedHTTPServersLock sync.Mutex\n)\n\nfunc addHTTPHandler(port uint16, path string, handler http.HandlerFunc) error {\n\t// Check params.\n\tif port == 0 {\n\t\treturn errors.New(\"cannot listen on port 0\")\n\t}\n\n\t// Default to root path.\n\tif path == \"\" {\n\t\tpath = \"/\"\n\t}\n\n\tsharedHTTPServersLock.Lock()\n\tdefer sharedHTTPServersLock.Unlock()\n\n\t// Get http server of the port.\n\tshared, ok := sharedHTTPServers[port]\n\tif ok {\n\t\t// Set path to handler.\n\t\tshared.handlersLock.Lock()\n\t\tdefer shared.handlersLock.Unlock()\n\n\t\t// Check if path is already registered.\n\t\t_, ok := shared.handlers[path]\n\t\tif ok {\n\t\t\treturn errors.New(\"path already registered\")\n\t\t}\n\n\t\t// Else, register handler at path.\n\t\tshared.handlers[path] = handler\n\t\treturn nil\n\t}\n\n\t// Shared server does not exist - create one.\n\tshared = &sharedServer{\n\t\thandlers: make(map[string]http.HandlerFunc),\n\t}\n\n\t// Add first handler.\n\tshared.handlers[path] = handler\n\n\t// Define new server.\n\tserver := &http.Server{\n\t\tAddr:              fmt.Sprintf(\":%d\", port),\n\t\tHandler:           shared,\n\t\tReadTimeout:       1 * time.Minute,\n\t\tReadHeaderTimeout: 10 * time.Second,\n\t\tWriteTimeout:      1 * time.Minute,\n\t\tIdleTimeout:       1 * time.Minute,\n\t\tMaxHeaderBytes:    4096,\n\t\tBaseContext:       func(net.Listener) context.Context { return module.mgr.Ctx() },\n\t}\n\tshared.server = server\n\n\t// Start listeners.\n\tbindIPs := conf.GetBindIPs()\n\tlisteners := make([]net.Listener, 0, len(bindIPs))\n\tfor _, bindIP := range bindIPs {\n\t\tlistener, err := net.ListenTCP(\"tcp\", &net.TCPAddr{\n\t\t\tIP:   bindIP,\n\t\t\tPort: int(port),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to listen: %w\", err)\n\t\t}\n\n\t\tlisteners = append(listeners, listener)\n\t\tlog.Infof(\"spn/ships: http transport pier established on %s\", listener.Addr())\n\t}\n\n\t// Add shared http server to list.\n\tsharedHTTPServers[port] = shared\n\n\t// Start servers in service workers.\n\tfor _, serviceListener := range listeners {\n\t\tmodule.mgr.Go(\n\t\t\tfmt.Sprintf(\"shared http server listener on %s\", serviceListener.Addr()),\n\t\t\tfunc(_ *mgr.WorkerCtx) error {\n\t\t\t\terr := shared.server.Serve(serviceListener)\n\t\t\t\tif !errors.Is(http.ErrServerClosed, err) {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t},\n\t\t)\n\t}\n\n\treturn nil\n}\n\nfunc removeHTTPHandler(port uint16, path string) error {\n\t// Check params.\n\tif port == 0 {\n\t\treturn nil\n\t}\n\n\t// Default to root path.\n\tif path == \"\" {\n\t\tpath = \"/\"\n\t}\n\n\tsharedHTTPServersLock.Lock()\n\tdefer sharedHTTPServersLock.Unlock()\n\n\t// Get http server of the port.\n\tshared, ok := sharedHTTPServers[port]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\t// Set path to handler.\n\tshared.handlersLock.Lock()\n\tdefer shared.handlersLock.Unlock()\n\n\t// Check if path is registered.\n\t_, ok = shared.handlers[path]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\t// Remove path from handler.\n\tdelete(shared.handlers, path)\n\n\t// Shutdown shared HTTP server if no more handlers are registered.\n\tif len(shared.handlers) == 0 {\n\t\tctx, cancel := context.WithTimeout(\n\t\t\tcontext.Background(),\n\t\t\t10*time.Second,\n\t\t)\n\t\tdefer cancel()\n\t\treturn shared.server.Shutdown(ctx)\n\t}\n\n\t// Remove shared HTTP server from map.\n\tdelete(sharedHTTPServers, port)\n\n\treturn nil\n}\n"
  },
  {
    "path": "spn/ships/http_shared_test.go",
    "content": "package ships\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSharedHTTP(t *testing.T) { //nolint:paralleltest // Test checks global state.\n\t_, err := New(struct{}{})\n\tif err != nil {\n\t\tt.Errorf(\"failed to create module ships: %s\", err)\n\t}\n\n\tconst testPort = 65100\n\n\t// Register multiple handlers.\n\terr = addHTTPHandler(testPort, \"\", ServeInfoPage)\n\trequire.NoError(t, err, \"should be able to share http listener\")\n\terr = addHTTPHandler(testPort, \"/test\", ServeInfoPage)\n\trequire.NoError(t, err, \"should be able to share http listener\")\n\terr = addHTTPHandler(testPort, \"/test2\", ServeInfoPage)\n\trequire.NoError(t, err, \"should be able to share http listener\")\n\terr = addHTTPHandler(testPort, \"/\", ServeInfoPage)\n\trequire.Error(t, err, \"should fail to register path twice\")\n\n\t// Unregister\n\trequire.NoError(t, removeHTTPHandler(testPort, \"\"))\n\trequire.NoError(t, removeHTTPHandler(testPort, \"/test\"))\n\trequire.NoError(t, removeHTTPHandler(testPort, \"/not-registered\")) // removing unregistered handler does not error\n\trequire.NoError(t, removeHTTPHandler(testPort, \"/test2\"))\n\trequire.NoError(t, removeHTTPHandler(testPort, \"/not-registered\")) // removing unregistered handler does not error\n\n\t// Check if all handlers are gone again.\n\tsharedHTTPServersLock.Lock()\n\tdefer sharedHTTPServersLock.Unlock()\n\tassert.Empty(t, sharedHTTPServers, \"shared http handlers should be back to zero\")\n}\n"
  },
  {
    "path": "spn/ships/kcp.go",
    "content": "package ships\n\n// KCPShip is a ship that uses KCP.\ntype KCPShip struct {\n\tShipBase\n}\n\n// KCPPier is a pier that uses KCP.\ntype KCPPier struct {\n\tPierBase\n}\n\n// TODO: Find a replacement for kcp, which turned out to not fit our use case.\n/*\nfunc init() {\n\tRegister(\"kcp\", &Builder{\n\t\tLaunchShip:    launchKCPShip,\n\t\tEstablishPier: establishKCPPier,\n\t})\n}\n\nfunc launchKCPShip(ctx context.Context, transport *hub.Transport, ip net.IP) (Ship, error) {\n\tconn, err := kcp.Dial(net.JoinHostPort(ip.String(), portToA(transport.Port)))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tship := &KCPShip{\n\t\tShipBase: ShipBase{\n\t\t\tconn:      conn,\n\t\t\ttransport: transport,\n\t\t\tmine:      true,\n\t\t\tsecure:    false,\n\t\t\t// Calculate KCP's MSS.\n\t\t\tloadSize: kcp.IKCP_MTU_DEF - kcp.IKCP_OVERHEAD,\n\t\t},\n\t}\n\n\tship.initBase()\n\treturn ship, nil\n}\n\nfunc establishKCPPier(transport *hub.Transport, dockingRequests chan *DockingRequest) (Pier, error) {\n\tlistener, err := kcp.Listen(net.JoinHostPort(\"\", portToA(transport.Port)))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpier := &KCPPier{\n\t\tPierBase: PierBase{\n\t\t\ttransport:       transport,\n\t\t\tlistener:        listener,\n\t\t\tdockingRequests: dockingRequests,\n\t\t},\n\t}\n\tpier.PierBase.dockShip = pier.dockShip\n\tpier.initBase()\n\treturn pier, nil\n}\n\nfunc (pier *KCPPier) dockShip() (Ship, error) {\n\tconn, err := pier.listener.Accept()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tship := &KCPShip{\n\t\tShipBase: ShipBase{\n\t\t\tconn:      conn,\n\t\t\ttransport: pier.transport,\n\t\t\tmine:      false,\n\t\t\tsecure:    false,\n\t\t\t// Calculate KCP's MSS.\n\t\t\tloadSize: kcp.IKCP_MTU_DEF - kcp.IKCP_OVERHEAD,\n\t\t},\n\t}\n\n\tship.initBase()\n\treturn ship, nil\n}\n*/\n"
  },
  {
    "path": "spn/ships/launch.go",
    "content": "package ships\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// Launch launches a new ship to the given Hub.\nfunc Launch(ctx context.Context, h *hub.Hub, transport *hub.Transport, ip net.IP) (Ship, error) {\n\tvar transports []*hub.Transport\n\tvar ips []net.IP\n\n\t// choose transports\n\tif transport != nil {\n\t\ttransports = []*hub.Transport{transport}\n\t} else {\n\t\tif h.Info == nil {\n\t\t\treturn nil, hub.ErrMissingInfo\n\t\t}\n\t\ttransports = h.Info.ParsedTransports()\n\t\t// If there are no transports, check if they were parsed.\n\t\tif len(transports) == 0 && len(h.Info.Transports) > 0 {\n\t\t\tlog.Errorf(\"ships: %s has no parsed transports, but transports are %v\", h, h.Info.Transports)\n\t\t\t// Attempt to parse transports now.\n\t\t\ttransports, _ = hub.ParseTransports(h.Info.Transports)\n\t\t}\n\t\t// Fail if there are not transports.\n\t\tif len(transports) == 0 {\n\t\t\treturn nil, hub.ErrMissingTransports\n\t\t}\n\t}\n\n\t// choose IPs\n\tif ip != nil {\n\t\tips = []net.IP{ip}\n\t} else {\n\t\tif h.Info == nil {\n\t\t\treturn nil, hub.ErrMissingInfo\n\t\t}\n\t\tips = make([]net.IP, 0, 3)\n\t\t// If IPs have been verified, check if we can use a virtual network address.\n\t\tvar vnetForced bool\n\t\tif h.VerifiedIPs {\n\t\t\tvnet := GetVirtualNetworkConfig()\n\t\t\tif vnet != nil {\n\t\t\t\tvirtIP := vnet.Mapping[h.ID]\n\t\t\t\tif virtIP != nil {\n\t\t\t\t\tips = append(ips, virtIP)\n\t\t\t\t\tif vnet.Force {\n\t\t\t\t\t\tvnetForced = true\n\t\t\t\t\t\tlog.Infof(\"spn/ships: forcing virtual network address %s for %s\", virtIP, h)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlog.Infof(\"spn/ships: using virtual network address %s for %s\", virtIP, h)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Add Hub's IPs if no virtual address was forced.\n\t\tif !vnetForced {\n\t\t\t// prioritize IPv4\n\t\t\tif h.Info.IPv4 != nil {\n\t\t\t\tips = append(ips, h.Info.IPv4)\n\t\t\t}\n\t\t\tif h.Info.IPv6 != nil && netenv.IPv6Enabled() {\n\t\t\t\tips = append(ips, h.Info.IPv6)\n\t\t\t}\n\t\t}\n\t\tif len(ips) == 0 {\n\t\t\treturn nil, hub.ErrMissingIPs\n\t\t}\n\t}\n\n\t// connect\n\tvar firstErr error\n\tfor _, ip := range ips {\n\t\tfor _, tr := range transports {\n\t\t\tship, err := connectTo(ctx, h, tr, ip)\n\t\t\tif err == nil {\n\t\t\t\treturn ship, nil // return on success\n\t\t\t}\n\n\t\t\t// Check if context is canceled.\n\t\t\tif ctx.Err() != nil {\n\t\t\t\treturn nil, ctx.Err()\n\t\t\t}\n\n\t\t\t// Save first error.\n\t\t\tif firstErr == nil {\n\t\t\t\tfirstErr = err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, firstErr\n}\n\nfunc connectTo(ctx context.Context, h *hub.Hub, transport *hub.Transport, ip net.IP) (Ship, error) {\n\tbuilder := GetBuilder(transport.Protocol)\n\tif builder == nil {\n\t\treturn nil, fmt.Errorf(\"protocol %s not supported\", transport.Protocol)\n\t}\n\n\tship, err := builder.LaunchShip(ctx, transport, ip)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to connect to %s using %s (%s): %w\", h, transport, ip, err)\n\t}\n\n\treturn ship, nil\n}\n"
  },
  {
    "path": "spn/ships/masking.go",
    "content": "package ships\n\nimport (\n\t\"crypto/sha1\"\n\t\"net\"\n\n\t\"github.com/mr-tron/base58\"\n\t\"github.com/tevino/abool\"\n)\n\nvar (\n\tmaskingEnabled = abool.New()\n\tmaskingActive  = abool.New()\n\tmaskingBytes   []byte\n)\n\n// EnableMasking enables masking with the given salt.\nfunc EnableMasking(salt []byte) {\n\tif maskingEnabled.SetToIf(false, true) {\n\t\tmaskingBytes = salt\n\t\tmaskingActive.Set()\n\t}\n}\n\n// MaskAddress masks the given address if masking is enabled and the ship is\n// not public.\nfunc (ship *ShipBase) MaskAddress(addr net.Addr) string {\n\t// Return in plain if masking is not enabled or if ship is public.\n\tif maskingActive.IsNotSet() || ship.Public() {\n\t\treturn addr.String()\n\t}\n\n\tswitch typedAddr := addr.(type) {\n\tcase *net.TCPAddr:\n\t\treturn ship.MaskIP(typedAddr.IP)\n\tcase *net.UDPAddr:\n\t\treturn ship.MaskIP(typedAddr.IP)\n\tdefault:\n\t\treturn ship.Mask([]byte(addr.String()))\n\t}\n}\n\n// MaskIP masks the given IP if masking is enabled and the ship is not public.\nfunc (ship *ShipBase) MaskIP(ip net.IP) string {\n\t// Return in plain if masking is not enabled or if ship is public.\n\tif maskingActive.IsNotSet() || ship.Public() {\n\t\treturn ip.String()\n\t}\n\n\treturn ship.Mask(ip)\n}\n\n// Mask masks the given value.\nfunc (ship *ShipBase) Mask(value []byte) string {\n\t// Hash the IP with masking bytes.\n\thasher := sha1.New() //nolint:gosec // Not used for cryptography.\n\thasher.Write(maskingBytes)\n\thasher.Write(value)\n\tmasked := hasher.Sum(nil)\n\n\t// Return first 8 characters from the base58-encoded hash.\n\treturn \"masked:\" + base58.Encode(masked)[:8]\n}\n"
  },
  {
    "path": "spn/ships/module.go",
    "content": "package ships\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype Ships struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc (s *Ships) Manager() *mgr.Manager {\n\treturn s.mgr\n}\n\nfunc (s *Ships) Start() error {\n\tif conf.PublicHub() {\n\t\tinitPageInput()\n\t}\n\n\treturn nil\n}\n\nfunc (s *Ships) Stop() error {\n\treturn nil\n}\n\nvar (\n\tmodule     *Ships\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Config module.\nfunc New(instance instance) (*Ships, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"Ships\")\n\tmodule = &Ships{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/ships/mtu.go",
    "content": "package ships\n\nimport \"net\"\n\n// MTU Calculation Configuration.\nconst (\n\tBaseMTU           = 1460 // 1500 with 40 bytes extra space for special cases.\n\tIPv4HeaderMTUSize = 20   // Without options, as not common.\n\tIPv6HeaderMTUSize = 40   // Without options, as not common.\n\tTCPHeaderMTUSize  = 60   // Maximum size with options.\n\tUDPHeaderMTUSize  = 8    // Has no options.\n)\n\nfunc (ship *ShipBase) calculateLoadSize(ip net.IP, addr net.Addr, subtract ...int) {\n\tship.loadSize = BaseMTU\n\n\t// Convert addr to IP if needed.\n\tif ip == nil && addr != nil {\n\t\tswitch v := addr.(type) {\n\t\tcase *net.TCPAddr:\n\t\t\tip = v.IP\n\t\tcase *net.UDPAddr:\n\t\t\tip = v.IP\n\t\tcase *net.IPAddr:\n\t\t\tip = v.IP\n\t\t}\n\t}\n\n\t// Subtract IP Header, if IP is available.\n\tif ip != nil {\n\t\tif ip4 := ip.To4(); ip4 != nil {\n\t\t\tship.loadSize -= IPv4HeaderMTUSize\n\t\t} else {\n\t\t\tship.loadSize -= IPv6HeaderMTUSize\n\t\t}\n\t}\n\n\t// Subtract others.\n\tfor sub := range subtract {\n\t\tship.loadSize -= sub\n\t}\n\n\t// Raise buf size to at least load size.\n\tif ship.bufSize < ship.loadSize {\n\t\tship.bufSize = ship.loadSize\n\t}\n}\n"
  },
  {
    "path": "spn/ships/pier.go",
    "content": "package ships\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// Pier represents a network connection listener.\ntype Pier interface {\n\t// String returns a human readable informational summary about the ship.\n\tString() string\n\n\t// Transport returns the transport used for this ship.\n\tTransport() *hub.Transport\n\n\t// Abolish closes the underlying listener and cleans up any related resources.\n\tAbolish()\n}\n\n// DockingRequest is a uniform request that Piers emit when a new ship arrives.\ntype DockingRequest struct {\n\tPier Pier\n\tShip Ship\n\tErr  error\n}\n\n// EstablishPier is shorthand function to get the transport's builder and establish a pier.\nfunc EstablishPier(transport *hub.Transport, dockingRequests chan Ship) (Pier, error) {\n\tbuilder := GetBuilder(transport.Protocol)\n\tif builder == nil {\n\t\treturn nil, fmt.Errorf(\"protocol %s not supported\", transport.Protocol)\n\t}\n\n\tpier, err := builder.EstablishPier(transport, dockingRequests)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to establish pier on %s: %w\", transport, err)\n\t}\n\n\treturn pier, nil\n}\n\n// PierBase implements common functions to comply with the Pier interface.\ntype PierBase struct {\n\t// transport holds the transport definition of the pier.\n\ttransport *hub.Transport\n\t// listeners holds the actual underlying listeners.\n\tlisteners []net.Listener\n\n\t// dockingRequests is used to report new connections to the higher layer.\n\tdockingRequests chan Ship\n\n\t// abolishing specifies if the pier and listener is being closed.\n\tabolishing *abool.AtomicBool\n}\n\nfunc (pier *PierBase) initBase() {\n\t// init\n\tpier.abolishing = abool.New()\n}\n\n// String returns a human readable informational summary about the ship.\nfunc (pier *PierBase) String() string {\n\treturn fmt.Sprintf(\"<Pier %s>\", pier.transport)\n}\n\n// Transport returns the transport used for this ship.\nfunc (pier *PierBase) Transport() *hub.Transport {\n\treturn pier.transport\n}\n\n// Abolish closes the underlying listener and cleans up any related resources.\nfunc (pier *PierBase) Abolish() {\n\tif pier.abolishing.SetToIf(false, true) {\n\t\tfor _, listener := range pier.listeners {\n\t\t\t_ = listener.Close()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/ships/registry.go",
    "content": "package ships\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// Builder is a factory that can build ships and piers of it's protocol.\ntype Builder struct {\n\tLaunchShip    func(ctx context.Context, transport *hub.Transport, ip net.IP) (Ship, error)\n\tEstablishPier func(transport *hub.Transport, dockingRequests chan Ship) (Pier, error)\n}\n\nvar (\n\tregistry     = make(map[string]*Builder)\n\tallProtocols []string\n\tregistryLock sync.Mutex\n)\n\n// Register registers a new builder for a protocol.\nfunc Register(protocol string, builder *Builder) {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\tregistry[protocol] = builder\n}\n\n// GetBuilder returns the builder for the given protocol, or nil if it does not exist.\nfunc GetBuilder(protocol string) *Builder {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\tbuilder, ok := registry[protocol]\n\tif !ok {\n\t\treturn nil\n\t}\n\treturn builder\n}\n\n// Protocols returns a slice with all registered protocol names. The return slice must not be edited.\nfunc Protocols() []string {\n\tregistryLock.Lock()\n\tdefer registryLock.Unlock()\n\n\treturn allProtocols\n}\n\n// portToA transforms the given port into a string.\nfunc portToA(port uint16) string {\n\treturn strconv.FormatUint(uint64(port), 10)\n}\n"
  },
  {
    "path": "spn/ships/ship.go",
    "content": "package ships\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nconst (\n\tdefaultLoadSize = 4096\n)\n\n// ErrSunk is returned when a ship sunk, ie. the connection was lost.\nvar ErrSunk = errors.New(\"ship sunk\")\n\n// Ship represents a network layer connection.\ntype Ship interface {\n\t// String returns a human readable informational summary about the ship.\n\tString() string\n\n\t// Transport returns the transport used for this ship.\n\tTransport() *hub.Transport\n\n\t// IsMine returns whether the ship was launched from here.\n\tIsMine() bool\n\n\t// IsSecure returns whether the ship provides transport security.\n\tIsSecure() bool\n\n\t// Public returns whether the ship is marked as public.\n\tPublic() bool\n\n\t// MarkPublic marks the ship as public.\n\tMarkPublic()\n\n\t// LoadSize returns the recommended data size that should be handed to Load().\n\t// This value will be most likely somehow related to the connection's MTU.\n\t// Alternatively, using a multiple of LoadSize is also recommended.\n\tLoadSize() int\n\n\t// Load loads data into the ship - ie. sends the data via the connection.\n\t// Returns ErrSunk if the ship has already sunk earlier.\n\tLoad(data []byte) error\n\n\t// UnloadTo unloads data from the ship - ie. receives data from the\n\t// connection - puts it into the buf. It returns the amount of data\n\t// written and an optional error.\n\t// Returns ErrSunk if the ship has already sunk earlier.\n\tUnloadTo(buf []byte) (n int, err error)\n\n\t// LocalAddr returns the underlying local net.Addr of the connection.\n\tLocalAddr() net.Addr\n\n\t// RemoteAddr returns the underlying remote net.Addr of the connection.\n\tRemoteAddr() net.Addr\n\n\t// Sink closes the underlying connection and cleans up any related resources.\n\tSink()\n\n\t// MaskAddress masks the address, if enabled.\n\tMaskAddress(addr net.Addr) string\n\t// MaskIP masks an IP, if enabled.\n\tMaskIP(ip net.IP) string\n\t// Mask masks a value.\n\tMask(value []byte) string\n}\n\n// ShipBase implements common functions to comply with the Ship interface.\ntype ShipBase struct {\n\t// conn is the actual underlying connection.\n\tconn net.Conn\n\t// transport holds the transport definition of the ship.\n\ttransport *hub.Transport\n\n\t// mine specifies whether the ship was launched from here.\n\tmine bool\n\t// secure specifies whether the ship provides transport security.\n\tsecure bool\n\t// public specifies whether the ship is public.\n\tpublic *abool.AtomicBool\n\t// bufSize specifies the size of the receive buffer.\n\tbufSize int\n\t// loadSize specifies the recommended data size that should be handed to Load().\n\tloadSize int\n\n\t// initial holds initial data from setting up the ship.\n\tinitial []byte\n\t// sinking specifies if the connection is being closed.\n\tsinking *abool.AtomicBool\n}\n\nfunc (ship *ShipBase) initBase() {\n\t// init\n\tship.sinking = abool.New()\n\tship.public = abool.New()\n\n\t// set default\n\tif ship.loadSize == 0 {\n\t\tship.loadSize = defaultLoadSize\n\t}\n\tif ship.bufSize == 0 {\n\t\tship.bufSize = ship.loadSize\n\t}\n}\n\n// String returns a human readable informational summary about the ship.\nfunc (ship *ShipBase) String() string {\n\tif ship.mine {\n\t\treturn fmt.Sprintf(\"<Ship to %s using %s>\", ship.MaskAddress(ship.RemoteAddr()), ship.transport)\n\t}\n\treturn fmt.Sprintf(\"<Ship from %s using %s>\", ship.MaskAddress(ship.RemoteAddr()), ship.transport)\n}\n\n// Transport returns the transport used for this ship.\nfunc (ship *ShipBase) Transport() *hub.Transport {\n\treturn ship.transport\n}\n\n// IsMine returns whether the ship was launched from here.\nfunc (ship *ShipBase) IsMine() bool {\n\treturn ship.mine\n}\n\n// IsSecure returns whether the ship provides transport security.\nfunc (ship *ShipBase) IsSecure() bool {\n\treturn ship.secure\n}\n\n// Public returns whether the ship is marked as public.\nfunc (ship *ShipBase) Public() bool {\n\treturn ship.public.IsSet()\n}\n\n// MarkPublic marks the ship as public.\nfunc (ship *ShipBase) MarkPublic() {\n\tship.public.Set()\n}\n\n// LoadSize returns the recommended data size that should be handed to Load().\n// This value will be most likely somehow related to the connection's MTU.\n// Alternatively, using a multiple of LoadSize is also recommended.\nfunc (ship *ShipBase) LoadSize() int {\n\treturn ship.loadSize\n}\n\n// Load loads data into the ship - ie. sends the data via the connection.\n// Returns ErrSunk if the ship has already sunk earlier.\nfunc (ship *ShipBase) Load(data []byte) error {\n\t// Empty load is used as a signal to cease operaetion.\n\tif len(data) == 0 {\n\t\tif ship.sinking.SetToIf(false, true) {\n\t\t\t_ = ship.conn.Close()\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Send all given data.\n\tn, err := ship.conn.Write(data)\n\tswitch {\n\tcase err != nil:\n\t\treturn err\n\tcase n == 0:\n\t\treturn errors.New(\"loaded 0 bytes\")\n\tcase n < len(data):\n\t\t// If not all data was sent, try again.\n\t\tlog.Debugf(\"spn/ships: %s only loaded %d/%d bytes\", ship, n, len(data))\n\t\tdata = data[n:]\n\t\treturn ship.Load(data)\n\t}\n\n\treturn nil\n}\n\n// UnloadTo unloads data from the ship - ie. receives data from the\n// connection - puts it into the buf. It returns the amount of data\n// written and an optional error.\n// Returns ErrSunk if the ship has already sunk earlier.\nfunc (ship *ShipBase) UnloadTo(buf []byte) (n int, err error) {\n\t// Process initial data, if there is any.\n\tif ship.initial != nil {\n\t\t// Copy as much data as possible.\n\t\tcopy(buf, ship.initial)\n\n\t\t// If buf was too small, skip the copied section.\n\t\tif len(buf) < len(ship.initial) {\n\t\t\tship.initial = ship.initial[len(buf):]\n\t\t\treturn len(buf), nil\n\t\t}\n\n\t\t// If everything was copied, unset the initial data.\n\t\tn := len(ship.initial)\n\t\tship.initial = nil\n\t\treturn n, nil\n\t}\n\n\t// Receive data.\n\treturn ship.conn.Read(buf)\n}\n\n// LocalAddr returns the underlying local net.Addr of the connection.\nfunc (ship *ShipBase) LocalAddr() net.Addr {\n\treturn ship.conn.LocalAddr()\n}\n\n// RemoteAddr returns the underlying remote net.Addr of the connection.\nfunc (ship *ShipBase) RemoteAddr() net.Addr {\n\treturn ship.conn.RemoteAddr()\n}\n\n// Sink closes the underlying connection and cleans up any related resources.\nfunc (ship *ShipBase) Sink() {\n\tif ship.sinking.SetToIf(false, true) {\n\t\t_ = ship.conn.Close()\n\t}\n}\n"
  },
  {
    "path": "spn/ships/tcp.go",
    "content": "package ships\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// TCPShip is a ship that uses TCP.\ntype TCPShip struct {\n\tShipBase\n}\n\n// TCPPier is a pier that uses TCP.\ntype TCPPier struct {\n\tPierBase\n\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n}\n\nfunc init() {\n\tRegister(\"tcp\", &Builder{\n\t\tLaunchShip:    launchTCPShip,\n\t\tEstablishPier: establishTCPPier,\n\t})\n}\n\nfunc launchTCPShip(ctx context.Context, transport *hub.Transport, ip net.IP) (Ship, error) {\n\tvar dialNet string\n\tif ip4 := ip.To4(); ip4 != nil {\n\t\tdialNet = \"tcp4\"\n\t} else {\n\t\tdialNet = \"tcp6\"\n\t}\n\tdialer := &net.Dialer{\n\t\tTimeout:       30 * time.Second,\n\t\tLocalAddr:     conf.GetBindAddr(dialNet),\n\t\tFallbackDelay: -1, // Disables Fast Fallback from IPv6 to IPv4.\n\t\tKeepAlive:     -1, // Disable keep-alive.\n\t}\n\tconn, err := dialer.DialContext(ctx, dialNet, net.JoinHostPort(ip.String(), portToA(transport.Port)))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to connect: %w\", err)\n\t}\n\n\tship := &TCPShip{\n\t\tShipBase: ShipBase{\n\t\t\tconn:      conn,\n\t\t\ttransport: transport,\n\t\t\tmine:      true,\n\t\t\tsecure:    false,\n\t\t},\n\t}\n\n\tship.calculateLoadSize(ip, nil, TCPHeaderMTUSize)\n\tship.initBase()\n\treturn ship, nil\n}\n\nfunc establishTCPPier(transport *hub.Transport, dockingRequests chan Ship) (Pier, error) {\n\t// Start listeners.\n\tbindIPs := conf.GetBindIPs()\n\tlisteners := make([]net.Listener, 0, len(bindIPs))\n\tfor _, bindIP := range bindIPs {\n\t\tlistener, err := net.ListenTCP(\"tcp\", &net.TCPAddr{\n\t\t\tIP:   bindIP,\n\t\t\tPort: int(transport.Port),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to listen: %w\", err)\n\t\t}\n\n\t\tlisteners = append(listeners, listener)\n\t\tlog.Infof(\"spn/ships: tcp transport pier established on %s\", listener.Addr())\n\t}\n\n\t// Create new pier.\n\tpierCtx, cancelCtx := context.WithCancel(module.mgr.Ctx())\n\tpier := &TCPPier{\n\t\tPierBase: PierBase{\n\t\t\ttransport:       transport,\n\t\t\tlisteners:       listeners,\n\t\t\tdockingRequests: dockingRequests,\n\t\t},\n\t\tctx:       pierCtx,\n\t\tcancelCtx: cancelCtx,\n\t}\n\tpier.initBase()\n\n\t// Start workers.\n\tfor _, listener := range pier.listeners {\n\t\tmodule.mgr.Go(\"accept TCP docking requests\", func(wc *mgr.WorkerCtx) error {\n\t\t\treturn pier.dockingWorker(wc.Ctx(), listener)\n\t\t})\n\t}\n\n\treturn pier, nil\n}\n\nfunc (pier *TCPPier) dockingWorker(_ context.Context, listener net.Listener) error {\n\tfor {\n\t\t// Block until something happens.\n\t\tconn, err := listener.Accept()\n\n\t\t// Check for errors.\n\t\tswitch {\n\t\tcase pier.ctx.Err() != nil:\n\t\t\treturn pier.ctx.Err()\n\t\tcase err != nil:\n\t\t\treturn err\n\t\t}\n\n\t\t// Create new ship.\n\t\tship := &TCPShip{\n\t\t\tShipBase: ShipBase{\n\t\t\t\ttransport: pier.transport,\n\t\t\t\tconn:      conn,\n\t\t\t\tmine:      false,\n\t\t\t\tsecure:    false,\n\t\t\t},\n\t\t}\n\t\tship.calculateLoadSize(nil, conn.RemoteAddr(), TCPHeaderMTUSize)\n\t\tship.initBase()\n\n\t\t// Submit new docking request.\n\t\tselect {\n\t\tcase pier.dockingRequests <- ship:\n\t\tcase <-pier.ctx.Done():\n\t\t\treturn pier.ctx.Err()\n\t\t}\n\t}\n}\n\n// Abolish closes the underlying listener and cleans up any related resources.\nfunc (pier *TCPPier) Abolish() {\n\tpier.cancelCtx()\n\tpier.PierBase.Abolish()\n}\n"
  },
  {
    "path": "spn/ships/testship.go",
    "content": "package ships\n\nimport (\n\t\"net\"\n\n\t\"github.com/mr-tron/base58\"\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\n// TestShip is a simulated ship that is used for testing higher level components.\ntype TestShip struct {\n\tmine      bool\n\tsecure    bool\n\tloadSize  int\n\tforward   chan []byte\n\tbackward  chan []byte\n\tunloadTmp []byte\n\tsinking   *abool.AtomicBool\n}\n\n// NewTestShip returns a new TestShip for simulation.\nfunc NewTestShip(secure bool, loadSize int) *TestShip {\n\treturn &TestShip{\n\t\tmine:     true,\n\t\tsecure:   secure,\n\t\tloadSize: loadSize,\n\t\tforward:  make(chan []byte, 100),\n\t\tbackward: make(chan []byte, 100),\n\t\tsinking:  abool.NewBool(false),\n\t}\n}\n\n// String returns a human readable informational summary about the ship.\nfunc (ship *TestShip) String() string {\n\tif ship.mine {\n\t\treturn \"<TestShip outbound>\"\n\t}\n\treturn \"<TestShip inbound>\"\n}\n\n// Transport returns the transport used for this ship.\nfunc (ship *TestShip) Transport() *hub.Transport {\n\treturn &hub.Transport{\n\t\tProtocol: \"dummy\",\n\t}\n}\n\n// IsMine returns whether the ship was launched from here.\nfunc (ship *TestShip) IsMine() bool {\n\treturn ship.mine\n}\n\n// IsSecure returns whether the ship provides transport security.\nfunc (ship *TestShip) IsSecure() bool {\n\treturn ship.secure\n}\n\n// LoadSize returns the recommended data size that should be handed to Load().\n// This value will be most likely somehow related to the connection's MTU.\n// Alternatively, using a multiple of LoadSize is also recommended.\nfunc (ship *TestShip) LoadSize() int {\n\treturn ship.loadSize\n}\n\n// Reverse creates a connected TestShip. This is used to simulate a connection instead of using a Pier.\nfunc (ship *TestShip) Reverse() *TestShip {\n\treturn &TestShip{\n\t\tmine:     !ship.mine,\n\t\tsecure:   ship.secure,\n\t\tloadSize: ship.loadSize,\n\t\tforward:  ship.backward,\n\t\tbackward: ship.forward,\n\t\tsinking:  abool.NewBool(false),\n\t}\n}\n\n// Load loads data into the ship - ie. sends the data via the connection.\n// Returns ErrSunk if the ship has already sunk earlier.\nfunc (ship *TestShip) Load(data []byte) error {\n\t// Debugging:\n\t// log.Debugf(\"spn/ship: loading %s\", spew.Sdump(data))\n\n\t// Check if ship is alive.\n\tif ship.sinking.IsSet() {\n\t\treturn ErrSunk\n\t}\n\n\t// Empty load is used as a signal to cease operaetion.\n\tif len(data) == 0 {\n\t\tship.Sink()\n\t\treturn nil\n\t}\n\n\t// Send all given data.\n\tship.forward <- data\n\n\treturn nil\n}\n\n// UnloadTo unloads data from the ship - ie. receives data from the\n// connection - puts it into the buf. It returns the amount of data\n// written and an optional error.\n// Returns ErrSunk if the ship has already sunk earlier.\nfunc (ship *TestShip) UnloadTo(buf []byte) (n int, err error) {\n\t// Process unload tmp data, if there is any.\n\tif ship.unloadTmp != nil {\n\t\t// Copy as much data as possible.\n\t\tcopy(buf, ship.unloadTmp)\n\n\t\t// If buf was too small, skip the copied section.\n\t\tif len(buf) < len(ship.unloadTmp) {\n\t\t\tship.unloadTmp = ship.unloadTmp[len(buf):]\n\t\t\treturn len(buf), nil\n\t\t}\n\n\t\t// If everything was copied, unset the unloadTmp data.\n\t\tn := len(ship.unloadTmp)\n\t\tship.unloadTmp = nil\n\t\treturn n, nil\n\t}\n\n\t// Receive data.\n\tdata := <-ship.backward\n\tif len(data) == 0 {\n\t\treturn 0, ErrSunk\n\t}\n\n\t// Copy data, possibly save remainder for later.\n\tcopy(buf, data)\n\tif len(buf) < len(data) {\n\t\tship.unloadTmp = data[len(buf):]\n\t\treturn len(buf), nil\n\t}\n\treturn len(data), nil\n}\n\n// Sink closes the underlying connection and cleans up any related resources.\nfunc (ship *TestShip) Sink() {\n\tif ship.sinking.SetToIf(false, true) {\n\t\tclose(ship.forward)\n\t}\n}\n\n// Dummy methods to conform to interface for testing.\n\nfunc (ship *TestShip) LocalAddr() net.Addr              { return nil }                  //nolint:golint\nfunc (ship *TestShip) RemoteAddr() net.Addr             { return nil }                  //nolint:golint\nfunc (ship *TestShip) Public() bool                     { return true }                 //nolint:golint\nfunc (ship *TestShip) MarkPublic()                      {}                              //nolint:golint\nfunc (ship *TestShip) MaskAddress(addr net.Addr) string { return addr.String() }        //nolint:golint\nfunc (ship *TestShip) MaskIP(ip net.IP) string          { return ip.String() }          //nolint:golint\nfunc (ship *TestShip) Mask(value []byte) string         { return base58.Encode(value) } //nolint:golint\n"
  },
  {
    "path": "spn/ships/testship_test.go",
    "content": "package ships\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTestShip(t *testing.T) {\n\tt.Parallel()\n\n\ttShip := NewTestShip(true, 100)\n\n\t// interface conformance test\n\tvar ship Ship = tShip\n\n\tsrvShip := tShip.Reverse()\n\n\tfor range 100 {\n\t\t// client send\n\t\terr := ship.Load(testData)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t}\n\n\t\t// server recv\n\t\tbuf := getTestBuf()\n\t\t_, err = srvShip.UnloadTo(buf)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t}\n\n\t\t// check data\n\t\tassert.Equal(t, testData, buf, \"should match\")\n\t\tfmt.Print(\".\")\n\n\t\t// server send\n\t\terr = srvShip.Load(testData)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t}\n\n\t\t// client recv\n\t\tbuf = getTestBuf()\n\t\t_, err = ship.UnloadTo(buf)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"%s failed: %s\", ship, err)\n\t\t}\n\n\t\t// check data\n\t\tassert.Equal(t, testData, buf, \"should match\")\n\t\tfmt.Print(\".\")\n\t}\n\n\tship.Sink()\n\tsrvShip.Sink()\n}\n"
  },
  {
    "path": "spn/ships/virtual_network.go",
    "content": "package ships\n\nimport (\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/safing/portmaster/spn/hub\"\n)\n\nvar (\n\tvirtNetLock   sync.Mutex\n\tvirtNetConfig *hub.VirtualNetworkConfig\n)\n\n// SetVirtualNetworkConfig sets the virtual networking config.\nfunc SetVirtualNetworkConfig(config *hub.VirtualNetworkConfig) {\n\tvirtNetLock.Lock()\n\tdefer virtNetLock.Unlock()\n\n\tvirtNetConfig = config\n}\n\n// GetVirtualNetworkConfig returns the virtual networking config.\nfunc GetVirtualNetworkConfig() *hub.VirtualNetworkConfig {\n\tvirtNetLock.Lock()\n\tdefer virtNetLock.Unlock()\n\n\treturn virtNetConfig\n}\n\n// GetVirtualNetworkAddress returns the virtual network IP for the given Hub.\nfunc GetVirtualNetworkAddress(dstHubID string) net.IP {\n\tvirtNetLock.Lock()\n\tdefer virtNetLock.Unlock()\n\n\t// Check if we have a virtual network config.\n\tif virtNetConfig == nil {\n\t\treturn nil\n\t}\n\n\t// Return mapping for given Hub ID.\n\treturn virtNetConfig.Mapping[dstHubID]\n}\n"
  },
  {
    "path": "spn/sluice/module.go",
    "content": "package sluice\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype SluiceModule struct {\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\nfunc (s *SluiceModule) Manager() *mgr.Manager {\n\treturn s.mgr\n}\n\nfunc (s *SluiceModule) Start() error {\n\treturn start()\n}\n\nfunc (s *SluiceModule) Stop() error {\n\treturn stop()\n}\n\nvar (\n\tentrypointInfoMsg = []byte(\"You have reached the local SPN entry port, but your connection could not be matched to an SPN tunnel.\\n\")\n\n\t// EnableListener indicates if it should start the sluice listeners. Must be set at startup.\n\tEnableListener bool = true\n)\n\nfunc start() error {\n\t// TODO:\n\t// Listening on all interfaces for now, as we need this for Windows.\n\t// Handle similarly to the nameserver listener.\n\n\tif conf.Integrated() && EnableListener {\n\t\tStartSluice(\"tcp4\", \"0.0.0.0:717\")\n\t\tStartSluice(\"udp4\", \"0.0.0.0:717\")\n\n\t\tif netenv.IPv6Enabled() {\n\t\t\tStartSluice(\"tcp6\", \"[::]:717\")\n\t\t\tStartSluice(\"udp6\", \"[::]:717\")\n\t\t} else {\n\t\t\tlog.Warningf(\"spn/sluice: no IPv6 stack detected, disabling IPv6 SPN entry endpoints\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc stop() error {\n\tstopAllSluices()\n\treturn nil\n}\n\nvar (\n\tmodule     *SluiceModule\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Config module.\nfunc New(instance instance) (*SluiceModule, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"SluiceModule\")\n\tmodule = &SluiceModule{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/sluice/packet_listener.go",
    "content": "package sluice\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\n// PacketListener is a listener for packet based protocols.\ntype PacketListener struct {\n\tsock     net.PacketConn\n\tclosed   *abool.AtomicBool\n\tnewConns chan *PacketConn\n\n\tlock  sync.Mutex\n\tconns map[string]*PacketConn\n\terr   error\n}\n\n// ListenPacket creates a packet listener.\nfunc ListenPacket(network, address string) (net.Listener, error) {\n\t// Create a new listening packet socket.\n\tsock, err := net.ListenPacket(network, address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create listener and start workers.\n\tln := &PacketListener{\n\t\tsock:     sock,\n\t\tclosed:   abool.New(),\n\t\tnewConns: make(chan *PacketConn),\n\t\tconns:    make(map[string]*PacketConn),\n\t}\n\tmodule.mgr.Go(\"packet listener reader\", ln.reader)\n\tmodule.mgr.Go(\"packet listener cleaner\", ln.cleaner)\n\n\treturn ln, nil\n}\n\n// Accept waits for and returns the next connection to the listener.\nfunc (ln *PacketListener) Accept() (net.Conn, error) {\n\tconn := <-ln.newConns\n\tif conn != nil {\n\t\treturn conn, nil\n\t}\n\n\t// Check if there is a socket error.\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\tif ln.err != nil {\n\t\treturn nil, ln.err\n\t}\n\n\treturn nil, io.EOF\n}\n\n// Close closes the listener.\n// Any blocked Accept operations will be unblocked and return errors.\nfunc (ln *PacketListener) Close() error {\n\tif !ln.closed.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Close all channels.\n\tclose(ln.newConns)\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\tfor _, conn := range ln.conns {\n\t\tclose(conn.in)\n\t}\n\n\t// Close socket.\n\treturn ln.sock.Close()\n}\n\n// Addr returns the listener's network address.\nfunc (ln *PacketListener) Addr() net.Addr {\n\treturn ln.sock.LocalAddr()\n}\n\nfunc (ln *PacketListener) getConn(remoteAddr string) (conn *PacketConn, ok bool) {\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\n\tconn, ok = ln.conns[remoteAddr]\n\treturn\n}\n\nfunc (ln *PacketListener) setConn(conn *PacketConn) {\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\n\tln.conns[conn.addr.String()] = conn\n}\n\nfunc (ln *PacketListener) reader(_ *mgr.WorkerCtx) error {\n\tfor {\n\t\t// Read data from connection.\n\t\tbuf := make([]byte, 512)\n\t\tn, addr, err := ln.sock.ReadFrom(buf)\n\t\tif err != nil {\n\t\t\t// Set socket error.\n\t\t\tln.lock.Lock()\n\t\t\tln.err = err\n\t\t\tln.lock.Unlock()\n\t\t\t// Close and return\n\t\t\t_ = ln.Close()\n\t\t\treturn nil //nolint:nilerr\n\t\t}\n\t\tbuf = buf[:n]\n\n\t\t// Get connection and supply data.\n\t\tconn, ok := ln.getConn(addr.String())\n\t\tif ok {\n\t\t\t// Ignore if conn is closed.\n\t\t\tif conn.closed.IsSet() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase conn.in <- buf:\n\t\t\tdefault:\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Or create a new connection.\n\t\tconn = &PacketConn{\n\t\t\tln:            ln,\n\t\t\taddr:          addr,\n\t\t\tclosed:        abool.New(),\n\t\t\tclosing:       make(chan struct{}),\n\t\t\tbuf:           buf,\n\t\t\tin:            make(chan []byte, 1),\n\t\t\tinactivityCnt: new(uint32),\n\t\t}\n\t\tln.setConn(conn)\n\t\tln.newConns <- conn\n\t}\n}\n\nfunc (ln *PacketListener) cleaner(ctx *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-time.After(1 * time.Minute):\n\t\t\t// Check if listener has died.\n\t\t\tif ln.closed.IsSet() {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t// Clean connections.\n\t\t\tln.cleanInactiveConns(10)\n\n\t\tcase <-ctx.Done():\n\t\t\t// Exit with module stop.\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (ln *PacketListener) cleanInactiveConns(overInactivityCnt uint32) {\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\n\tfor k, conn := range ln.conns {\n\t\tcnt := atomic.AddUint32(conn.inactivityCnt, 1)\n\t\tswitch {\n\t\tcase cnt > overInactivityCnt*2:\n\t\t\tdelete(ln.conns, k)\n\t\tcase cnt > overInactivityCnt:\n\t\t\t_ = conn.Close()\n\t\t}\n\t}\n}\n\n// PacketConn simulates a connection for a stateless protocol.\ntype PacketConn struct {\n\tln      *PacketListener\n\taddr    net.Addr\n\tclosed  *abool.AtomicBool\n\tclosing chan struct{}\n\n\tbuf []byte\n\tin  chan []byte\n\n\tinactivityCnt *uint32\n}\n\n// Read reads data from the connection.\n// Read can be made to time out and return an error after a fixed\n// time limit; see SetDeadline and SetReadDeadline.\nfunc (conn *PacketConn) Read(b []byte) (n int, err error) {\n\t// Check if connection is closed.\n\tif conn.closed.IsSet() {\n\t\treturn 0, io.EOF\n\t}\n\n\t// Mark as active.\n\tatomic.StoreUint32(conn.inactivityCnt, 0)\n\n\t// Get new buffer.\n\tif conn.buf == nil {\n\t\tselect {\n\t\tcase conn.buf = <-conn.in:\n\t\t\tif conn.buf == nil {\n\t\t\t\treturn 0, io.EOF\n\t\t\t}\n\t\tcase <-conn.closing:\n\t\t\treturn 0, io.EOF\n\t\t}\n\t}\n\n\t// Serve from buffer.\n\tcopy(b, conn.buf)\n\tif len(b) >= len(conn.buf) {\n\t\tcopied := len(conn.buf)\n\t\tconn.buf = nil\n\t\treturn copied, nil\n\t}\n\tcopied := len(b)\n\tconn.buf = conn.buf[copied:]\n\treturn copied, nil\n}\n\n// Write writes data to the connection.\n// Write can be made to time out and return an error after a fixed\n// time limit; see SetDeadline and SetWriteDeadline.\nfunc (conn *PacketConn) Write(b []byte) (n int, err error) {\n\t// Check if connection is closed.\n\tif conn.closed.IsSet() {\n\t\treturn 0, io.EOF\n\t}\n\n\t// Mark as active.\n\tatomic.StoreUint32(conn.inactivityCnt, 0)\n\n\treturn conn.ln.sock.WriteTo(b, conn.addr)\n}\n\n// Close is a no-op as UDP connections share a single socket. Just stop sending\n// packets without closing.\nfunc (conn *PacketConn) Close() error {\n\tif conn.closed.SetToIf(false, true) {\n\t\tclose(conn.closing)\n\t}\n\treturn nil\n}\n\n// LocalAddr returns the local network address.\nfunc (conn *PacketConn) LocalAddr() net.Addr {\n\treturn conn.ln.sock.LocalAddr()\n}\n\n// RemoteAddr returns the remote network address.\nfunc (conn *PacketConn) RemoteAddr() net.Addr {\n\treturn conn.addr\n}\n\n// SetDeadline is a no-op as UDP connections share a single socket.\nfunc (conn *PacketConn) SetDeadline(t time.Time) error {\n\treturn nil\n}\n\n// SetReadDeadline is a no-op as UDP connections share a single socket.\nfunc (conn *PacketConn) SetReadDeadline(t time.Time) error {\n\treturn nil\n}\n\n// SetWriteDeadline is a no-op as UDP connections share a single socket.\nfunc (conn *PacketConn) SetWriteDeadline(t time.Time) error {\n\treturn nil\n}\n"
  },
  {
    "path": "spn/sluice/request.go",
    "content": "package sluice\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/network\"\n\t\"github.com/safing/portmaster/service/network/packet\"\n)\n\nconst (\n\tdefaultSluiceTTL = 30 * time.Second\n)\n\nvar (\n\t// ErrUnsupported is returned when a protocol is not supported.\n\tErrUnsupported = errors.New(\"unsupported protocol\")\n\n\t// ErrSluiceOffline is returned when the sluice for a network is offline.\n\tErrSluiceOffline = errors.New(\"is offline\")\n)\n\n// Request holds request data for a sluice entry.\ntype Request struct {\n\tConnInfo   *network.Connection\n\tCallbackFn RequestCallbackFunc\n\tExpires    time.Time\n}\n\n// RequestCallbackFunc is called for taking a over handling connection that arrived at the sluice.\ntype RequestCallbackFunc func(connInfo *network.Connection, conn net.Conn)\n\n// AwaitRequest pre-registers a connection at the sluice for initializing it when it arrives.\nfunc AwaitRequest(connInfo *network.Connection, callbackFn RequestCallbackFunc) error {\n\tnetwork := getNetworkFromConnInfo(connInfo)\n\tif network == \"\" {\n\t\treturn ErrUnsupported\n\t}\n\n\tsluice, ok := getSluice(network)\n\tif !ok {\n\t\treturn fmt.Errorf(\"sluice for network %s %w\", network, ErrSluiceOffline)\n\t}\n\n\treturn sluice.AwaitRequest(&Request{\n\t\tConnInfo:   connInfo,\n\t\tCallbackFn: callbackFn,\n\t\tExpires:    time.Now().Add(defaultSluiceTTL),\n\t})\n}\n\nfunc getNetworkFromConnInfo(connInfo *network.Connection) string {\n\tvar network string\n\n\t// protocol\n\tswitch connInfo.IPProtocol { //nolint:exhaustive // Looking for specific values.\n\tcase packet.TCP:\n\t\tnetwork = \"tcp\"\n\tcase packet.UDP:\n\t\tnetwork = \"udp\"\n\tdefault:\n\t\treturn \"\"\n\t}\n\n\t// IP version\n\tswitch connInfo.IPVersion {\n\tcase packet.IPv4:\n\t\tnetwork += \"4\"\n\tcase packet.IPv6:\n\t\tnetwork += \"6\"\n\tdefault:\n\t\treturn \"\"\n\t}\n\n\treturn network\n}\n"
  },
  {
    "path": "spn/sluice/sluice.go",
    "content": "package sluice\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/service/netenv\"\n)\n\n// Sluice is a tunnel entry listener.\ntype Sluice struct {\n\tnetwork        string\n\taddress        string\n\tcreateListener ListenerFactory\n\n\tlock            sync.Mutex\n\tlistener        net.Listener\n\tpendingRequests map[string]*Request\n\tabandoned       bool\n}\n\n// ListenerFactory defines a function to create a listener.\ntype ListenerFactory func(network, address string) (net.Listener, error)\n\n// StartSluice starts a sluice listener at the given address.\nfunc StartSluice(network, address string) {\n\ts := &Sluice{\n\t\tnetwork:         network,\n\t\taddress:         address,\n\t\tpendingRequests: make(map[string]*Request),\n\t}\n\n\tswitch s.network {\n\tcase \"tcp4\", \"tcp6\":\n\t\ts.createListener = net.Listen\n\tcase \"udp4\", \"udp6\":\n\t\ts.createListener = ListenUDP\n\tdefault:\n\t\tlog.Errorf(\"spn/sluice: cannot start sluice for %s: unsupported network\", network)\n\t\treturn\n\t}\n\n\t// Start service worker.\n\tmodule.mgr.Go(\n\t\ts.network+\" sluice listener\",\n\t\ts.listenHandler,\n\t)\n}\n\n// AwaitRequest pre-registers a connection.\nfunc (s *Sluice) AwaitRequest(r *Request) error {\n\t// Set default expiry.\n\tif r.Expires.IsZero() {\n\t\tr.Expires = time.Now().Add(defaultSluiceTTL)\n\t}\n\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\n\t// Check if a pending request already exists for this local address.\n\tkey := net.JoinHostPort(r.ConnInfo.LocalIP.String(), strconv.Itoa(int(r.ConnInfo.LocalPort)))\n\t_, exists := s.pendingRequests[key]\n\tif exists {\n\t\treturn fmt.Errorf(\"a pending request for %s already exists\", key)\n\t}\n\n\t// Add to pending requests.\n\ts.pendingRequests[key] = r\n\treturn nil\n}\n\nfunc (s *Sluice) getRequest(address string) (r *Request, ok bool) {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\n\tr, ok = s.pendingRequests[address]\n\tif ok {\n\t\tdelete(s.pendingRequests, address)\n\t}\n\treturn\n}\n\nfunc (s *Sluice) init() error {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\ts.abandoned = false\n\n\t// start listening\n\ts.listener = nil\n\tln, err := s.createListener(s.network, s.address)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to listen: %w\", err)\n\t}\n\ts.listener = ln\n\n\t// Add to registry.\n\taddSluice(s)\n\n\treturn nil\n}\n\nfunc (s *Sluice) abandon() {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\tif s.abandoned {\n\t\treturn\n\t}\n\ts.abandoned = true\n\n\t// Remove from registry.\n\tremoveSluice(s.network)\n\n\t// Close listener.\n\tif s.listener != nil {\n\t\t_ = s.listener.Close()\n\t}\n\n\t// Notify pending requests.\n\tfor i, r := range s.pendingRequests {\n\t\tr.CallbackFn(r.ConnInfo, nil)\n\t\tdelete(s.pendingRequests, i)\n\t}\n}\n\nfunc (s *Sluice) handleConnection(conn net.Conn) {\n\t// Close the connection if handling is not successful.\n\tsuccess := false\n\tdefer func() {\n\t\tif !success {\n\t\t\t_ = conn.Close()\n\t\t}\n\t}()\n\n\t// Get IP address.\n\tvar remoteIP net.IP\n\tswitch typedAddr := conn.RemoteAddr().(type) {\n\tcase *net.TCPAddr:\n\t\tremoteIP = typedAddr.IP\n\tcase *net.UDPAddr:\n\t\tremoteIP = typedAddr.IP\n\tdefault:\n\t\tlog.Warningf(\"spn/sluice: cannot handle connection for unsupported network %s\", conn.RemoteAddr().Network())\n\t\treturn\n\t}\n\n\t// Check if the request is local.\n\tlocal, err := netenv.IsMyIP(remoteIP)\n\tif err != nil {\n\t\tlog.Warningf(\"spn/sluice: failed to check if request from %s is local: %s\", remoteIP, err)\n\t\treturn\n\t}\n\tif !local {\n\t\tlog.Warningf(\"spn/sluice: received external request from %s, ignoring\", remoteIP)\n\n\t\t// TODO:\n\t\t// Do not allow this to be spammed.\n\t\t// Only allow one trigger per second.\n\t\t// Do not trigger by same \"remote IP\" in a row.\n\t\tnetenv.TriggerNetworkChangeCheck()\n\n\t\treturn\n\t}\n\n\t// Get waiting request.\n\tr, ok := s.getRequest(conn.RemoteAddr().String())\n\tif !ok {\n\t\t_, err := conn.Write(entrypointInfoMsg)\n\t\tif err != nil {\n\t\t\tlog.Warningf(\"spn/sluice: new %s request from %s without pending request, but failed to reply with info msg: %s\", s.network, conn.RemoteAddr(), err)\n\t\t} else {\n\t\t\tlog.Debugf(\"spn/sluice: new %s request from %s without pending request, replied with info msg\", s.network, conn.RemoteAddr())\n\t\t}\n\t\treturn\n\t}\n\n\t// Hand over to callback.\n\tlog.Tracef(\n\t\t\"spn/sluice: new %s request from %s for %s (%s:%d)\",\n\t\ts.network, conn.RemoteAddr(),\n\t\tr.ConnInfo.Entity.Domain, r.ConnInfo.Entity.IP, r.ConnInfo.Entity.Port,\n\t)\n\tr.CallbackFn(r.ConnInfo, conn)\n\tsuccess = true\n}\n\nfunc (s *Sluice) listenHandler(_ *mgr.WorkerCtx) error {\n\tdefer s.abandon()\n\terr := s.init()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Handle new connections.\n\tlog.Infof(\"spn/sluice: started listening for %s requests on %s\", s.network, s.listener.Addr())\n\tfor {\n\t\tconn, err := s.listener.Accept()\n\t\tif err != nil {\n\t\t\tif module.mgr.IsDone() {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to accept connection: %w\", err)\n\t\t}\n\n\t\t// Handle accepted connection.\n\t\ts.handleConnection(conn)\n\n\t\t// Clean up old leftovers.\n\t\ts.cleanConnections()\n\t}\n}\n\nfunc (s *Sluice) cleanConnections() {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\n\tnow := time.Now()\n\tfor address, request := range s.pendingRequests {\n\t\tif now.After(request.Expires) {\n\t\t\tdelete(s.pendingRequests, address)\n\t\t\tlog.Debugf(\"spn/sluice: removed expired pending %s connection %s\", s.network, request.ConnInfo)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/sluice/sluices.go",
    "content": "package sluice\n\nimport \"sync\"\n\nvar (\n\tsluices     = make(map[string]*Sluice)\n\tsluicesLock sync.RWMutex\n)\n\nfunc getSluice(network string) (s *Sluice, ok bool) {\n\tsluicesLock.RLock()\n\tdefer sluicesLock.RUnlock()\n\n\ts, ok = sluices[network]\n\treturn\n}\n\nfunc addSluice(s *Sluice) {\n\tsluicesLock.Lock()\n\tdefer sluicesLock.Unlock()\n\n\tsluices[s.network] = s\n}\n\nfunc removeSluice(network string) {\n\tsluicesLock.Lock()\n\tdefer sluicesLock.Unlock()\n\n\tdelete(sluices, network)\n}\n\nfunc copySluices() map[string]*Sluice {\n\tsluicesLock.Lock()\n\tdefer sluicesLock.Unlock()\n\n\tcopied := make(map[string]*Sluice, len(sluices))\n\tfor k, v := range sluices {\n\t\tcopied[k] = v\n\t}\n\treturn copied\n}\n\nfunc stopAllSluices() {\n\tfor _, sluice := range copySluices() {\n\t\tsluice.abandon()\n\t}\n}\n"
  },
  {
    "path": "spn/sluice/udp_listener.go",
    "content": "package sluice\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\t\"golang.org/x/net/ipv4\"\n\t\"golang.org/x/net/ipv6\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nconst onWindows = runtime.GOOS == \"windows\"\n\n// UDPListener is a listener for UDP.\ntype UDPListener struct {\n\tsock     *net.UDPConn\n\tclosed   *abool.AtomicBool\n\tnewConns chan *UDPConn\n\toobSize  int\n\n\tlock  sync.Mutex\n\tconns map[string]*UDPConn\n\terr   error\n}\n\n// ListenUDP creates a packet listener.\nfunc ListenUDP(network, address string) (net.Listener, error) {\n\t// Parse address.\n\tudpAddr, err := net.ResolveUDPAddr(network, address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Determine oob data size.\n\toobSize := 40 // IPv6 (measured)\n\tif udpAddr.IP.To4() != nil {\n\t\toobSize = 32 // IPv4 (measured)\n\t}\n\n\t// Create a new listening UDP socket.\n\tsock, err := net.ListenUDP(network, udpAddr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create listener.\n\tln := &UDPListener{\n\t\tsock:     sock,\n\t\tclosed:   abool.New(),\n\t\tnewConns: make(chan *UDPConn),\n\t\toobSize:  oobSize,\n\t\tconns:    make(map[string]*UDPConn),\n\t}\n\n\t// Set socket options on listener.\n\terr = ln.setSocketOptions()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Start workers.\n\tmodule.mgr.Go(\"udp listener reader\", ln.reader)\n\tmodule.mgr.Go(\"udp listener cleaner\", ln.cleaner)\n\n\treturn ln, nil\n}\n\n// Accept waits for and returns the next connection to the listener.\nfunc (ln *UDPListener) Accept() (net.Conn, error) {\n\tconn := <-ln.newConns\n\tif conn != nil {\n\t\treturn conn, nil\n\t}\n\n\t// Check if there is a socket error.\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\tif ln.err != nil {\n\t\treturn nil, ln.err\n\t}\n\n\treturn nil, io.EOF\n}\n\n// Close closes the listener.\n// Any blocked Accept operations will be unblocked and return errors.\nfunc (ln *UDPListener) Close() error {\n\tif !ln.closed.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Close all channels.\n\tclose(ln.newConns)\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\tfor _, conn := range ln.conns {\n\t\tclose(conn.in)\n\t}\n\n\t// Close socket.\n\treturn ln.sock.Close()\n}\n\n// Addr returns the listener's network address.\nfunc (ln *UDPListener) Addr() net.Addr {\n\treturn ln.sock.LocalAddr()\n}\n\nfunc (ln *UDPListener) getConn(remoteAddr string) (conn *UDPConn, ok bool) {\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\n\tconn, ok = ln.conns[remoteAddr]\n\treturn\n}\n\nfunc (ln *UDPListener) setConn(conn *UDPConn) {\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\n\tln.conns[conn.addr.String()] = conn\n}\n\nfunc (ln *UDPListener) reader(_ *mgr.WorkerCtx) error {\n\tfor {\n\t\t// TODO: Find good buf size.\n\t\t// With a buf size of 512 we have seen this error on Windows:\n\t\t// wsarecvmsg: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.\n\t\t// UDP is not (yet) heavily used, so we can go for the 1500 bytes size for now.\n\n\t\t// Read data from connection.\n\t\tbuf := make([]byte, 1500) // TODO: see comment above.\n\t\toob := make([]byte, ln.oobSize)\n\t\tn, oobn, _, addr, err := ln.sock.ReadMsgUDP(buf, oob)\n\t\tif err != nil {\n\t\t\t// Set socket error.\n\t\t\tln.lock.Lock()\n\t\t\tln.err = err\n\t\t\tln.lock.Unlock()\n\t\t\t// Close and return\n\t\t\t_ = ln.Close()\n\t\t\treturn nil //nolint:nilerr\n\t\t}\n\t\tbuf = buf[:n]\n\t\toob = oob[:oobn]\n\n\t\t// Get connection and supply data.\n\t\tconn, ok := ln.getConn(addr.String())\n\t\tif ok {\n\t\t\t// Ignore if conn is closed.\n\t\t\tif conn.closed.IsSet() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase conn.in <- buf:\n\t\t\tdefault:\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Or create a new connection.\n\t\tconn = &UDPConn{\n\t\t\tln:            ln,\n\t\t\taddr:          addr,\n\t\t\toob:           oob,\n\t\t\tclosed:        abool.New(),\n\t\t\tclosing:       make(chan struct{}),\n\t\t\tbuf:           buf,\n\t\t\tin:            make(chan []byte, 1),\n\t\t\tinactivityCnt: new(uint32),\n\t\t}\n\t\tln.setConn(conn)\n\t\tln.newConns <- conn\n\t}\n}\n\nfunc (ln *UDPListener) cleaner(ctx *mgr.WorkerCtx) error {\n\tfor {\n\t\tselect {\n\t\tcase <-time.After(1 * time.Minute):\n\t\t\t// Check if listener has died.\n\t\t\tif ln.closed.IsSet() {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t// Clean connections.\n\t\t\tln.cleanInactiveConns(10)\n\n\t\tcase <-ctx.Done():\n\t\t\t// Exit with module stop.\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (ln *UDPListener) cleanInactiveConns(overInactivityCnt uint32) {\n\tln.lock.Lock()\n\tdefer ln.lock.Unlock()\n\n\tfor k, conn := range ln.conns {\n\t\tcnt := atomic.AddUint32(conn.inactivityCnt, 1)\n\t\tswitch {\n\t\tcase cnt > overInactivityCnt*2:\n\t\t\tdelete(ln.conns, k)\n\t\tcase cnt > overInactivityCnt:\n\t\t\t_ = conn.Close()\n\t\t}\n\t}\n}\n\n// setUDPSocketOptions sets socket options so that the source address for\n// replies is correct.\nfunc (ln *UDPListener) setSocketOptions() error {\n\t// Setting socket options is not supported on windows.\n\tif onWindows {\n\t\treturn nil\n\t}\n\n\t// As we might be listening on an interface that supports both IPv4 and IPv6,\n\t// try to set the socket options on both.\n\t// Only report an error if it fails on both.\n\terr4 := ipv4.NewPacketConn(ln.sock).SetControlMessage(ipv4.FlagDst|ipv4.FlagInterface, true)\n\terr6 := ipv6.NewPacketConn(ln.sock).SetControlMessage(ipv6.FlagDst|ipv6.FlagInterface, true)\n\tif err4 != nil && err6 != nil {\n\t\treturn err4\n\t}\n\n\treturn nil\n}\n\n// UDPConn simulates a connection for a stateless protocol.\ntype UDPConn struct {\n\tln      *UDPListener\n\taddr    *net.UDPAddr\n\toob     []byte\n\tclosed  *abool.AtomicBool\n\tclosing chan struct{}\n\n\tbuf []byte\n\tin  chan []byte\n\n\tinactivityCnt *uint32\n}\n\n// Read reads data from the connection.\n// Read can be made to time out and return an error after a fixed\n// time limit; see SetDeadline and SetReadDeadline.\nfunc (conn *UDPConn) Read(b []byte) (n int, err error) {\n\t// Check if connection is closed.\n\tif conn.closed.IsSet() {\n\t\treturn 0, io.EOF\n\t}\n\n\t// Mark as active.\n\tatomic.StoreUint32(conn.inactivityCnt, 0)\n\n\t// Get new buffer.\n\tif conn.buf == nil {\n\t\tselect {\n\t\tcase conn.buf = <-conn.in:\n\t\t\tif conn.buf == nil {\n\t\t\t\treturn 0, io.EOF\n\t\t\t}\n\t\tcase <-conn.closing:\n\t\t\treturn 0, io.EOF\n\t\t}\n\t}\n\n\t// Serve from buffer.\n\tcopy(b, conn.buf)\n\tif len(b) >= len(conn.buf) {\n\t\tcopied := len(conn.buf)\n\t\tconn.buf = nil\n\t\treturn copied, nil\n\t}\n\tcopied := len(b)\n\tconn.buf = conn.buf[copied:]\n\treturn copied, nil\n}\n\n// Write writes data to the connection.\n// Write can be made to time out and return an error after a fixed\n// time limit; see SetDeadline and SetWriteDeadline.\nfunc (conn *UDPConn) Write(b []byte) (n int, err error) {\n\t// Check if connection is closed.\n\tif conn.closed.IsSet() {\n\t\treturn 0, io.EOF\n\t}\n\n\t// Mark as active.\n\tatomic.StoreUint32(conn.inactivityCnt, 0)\n\n\tn, _, err = conn.ln.sock.WriteMsgUDP(b, conn.oob, conn.addr)\n\treturn n, err\n}\n\n// Close is a no-op as UDP connections share a single socket. Just stop sending\n// packets without closing.\nfunc (conn *UDPConn) Close() error {\n\tif conn.closed.SetToIf(false, true) {\n\t\tclose(conn.closing)\n\t}\n\treturn nil\n}\n\n// LocalAddr returns the local network address.\nfunc (conn *UDPConn) LocalAddr() net.Addr {\n\treturn conn.ln.sock.LocalAddr()\n}\n\n// RemoteAddr returns the remote network address.\nfunc (conn *UDPConn) RemoteAddr() net.Addr {\n\treturn conn.addr\n}\n\n// SetDeadline is a no-op as UDP connections share a single socket.\nfunc (conn *UDPConn) SetDeadline(t time.Time) error {\n\treturn nil\n}\n\n// SetReadDeadline is a no-op as UDP connections share a single socket.\nfunc (conn *UDPConn) SetReadDeadline(t time.Time) error {\n\treturn nil\n}\n\n// SetWriteDeadline is a no-op as UDP connections share a single socket.\nfunc (conn *UDPConn) SetWriteDeadline(t time.Time) error {\n\treturn nil\n}\n"
  },
  {
    "path": "spn/spn.go",
    "content": "package spn\n"
  },
  {
    "path": "spn/terminal/control_flow.go",
    "content": "package terminal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/structures/varint\"\n)\n\n// FlowControl defines the flow control interface.\ntype FlowControl interface {\n\tDeliver(msg *Msg) *Error\n\tReceive() <-chan *Msg\n\tSend(msg *Msg, timeout time.Duration) *Error\n\tReadyToSend() <-chan struct{}\n\tFlush(timeout time.Duration)\n\tStartWorkers(m *mgr.Manager, terminalName string)\n\tRecvQueueLen() int\n\tSendQueueLen() int\n}\n\n// FlowControlType represents a flow control type.\ntype FlowControlType uint8\n\n// Flow Control Types.\nconst (\n\tFlowControlDefault FlowControlType = 0\n\tFlowControlDFQ     FlowControlType = 1\n\tFlowControlNone    FlowControlType = 2\n\n\tdefaultFlowControl = FlowControlDFQ\n)\n\n// DefaultSize returns the default flow control size.\nfunc (fct FlowControlType) DefaultSize() uint32 {\n\tif fct == FlowControlDefault {\n\t\tfct = defaultFlowControl\n\t}\n\n\tswitch fct {\n\tcase FlowControlDFQ:\n\t\treturn 50000\n\tcase FlowControlNone:\n\t\treturn 10000\n\tcase FlowControlDefault:\n\t\tfallthrough\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// Flow Queue Configuration.\nconst (\n\tDefaultQueueSize        = 50000\n\tMaxQueueSize            = 1000000\n\tforceReportBelowPercent = 0.75\n)\n\n// DuplexFlowQueue is a duplex flow control mechanism using queues.\ntype DuplexFlowQueue struct {\n\t// ti is the Terminal that is using the DFQ.\n\tctx context.Context\n\n\t// submitUpstream is used to submit messages to the upstream channel.\n\tsubmitUpstream func(msg *Msg, timeout time.Duration)\n\n\t// sendQueue holds the messages that are waiting to be sent.\n\tsendQueue chan *Msg\n\t// prioMsgs holds the number of messages to send with high priority.\n\tprioMsgs *int32\n\t// sendSpace indicates the amount free slots in the recvQueue on the other end.\n\tsendSpace *int32\n\t// readyToSend is used to notify sending components that there is free space.\n\treadyToSend chan struct{}\n\t// wakeSender is used to wake a sender in case the sendSpace was zero and the\n\t// sender is waiting for available space.\n\twakeSender chan struct{}\n\n\t// recvQueue holds the messages that are waiting to be processed.\n\trecvQueue chan *Msg\n\t// reportedSpace indicates the amount of free slots that the other end knows\n\t// about.\n\treportedSpace *int32\n\t// spaceReportLock locks the calculation of space to report.\n\tspaceReportLock sync.Mutex\n\t// forceSpaceReport forces the sender to send a space report.\n\tforceSpaceReport chan struct{}\n\n\t// flush is used to send a finish function to the handler, which will write\n\t// all pending messages and then call the received function.\n\tflush chan func()\n}\n\n// NewDuplexFlowQueue returns a new duplex flow queue.\nfunc NewDuplexFlowQueue(\n\tctx context.Context,\n\tqueueSize uint32,\n\tsubmitUpstream func(msg *Msg, timeout time.Duration),\n) *DuplexFlowQueue {\n\tdfq := &DuplexFlowQueue{\n\t\tctx:              ctx,\n\t\tsubmitUpstream:   submitUpstream,\n\t\tsendQueue:        make(chan *Msg, queueSize),\n\t\tprioMsgs:         new(int32),\n\t\tsendSpace:        new(int32),\n\t\treadyToSend:      make(chan struct{}),\n\t\twakeSender:       make(chan struct{}, 1),\n\t\trecvQueue:        make(chan *Msg, queueSize),\n\t\treportedSpace:    new(int32),\n\t\tforceSpaceReport: make(chan struct{}, 1),\n\t\tflush:            make(chan func()),\n\t}\n\tatomic.StoreInt32(dfq.sendSpace, int32(queueSize))\n\tatomic.StoreInt32(dfq.reportedSpace, int32(queueSize))\n\n\treturn dfq\n}\n\n// StartWorkers starts the necessary workers to operate the flow queue.\nfunc (dfq *DuplexFlowQueue) StartWorkers(m *mgr.Manager, terminalName string) {\n\tm.Go(terminalName+\" flow queue\", dfq.FlowHandler)\n}\n\n// shouldReportRecvSpace returns whether the receive space should be reported.\nfunc (dfq *DuplexFlowQueue) shouldReportRecvSpace() bool {\n\treturn atomic.LoadInt32(dfq.reportedSpace) < int32(float32(cap(dfq.recvQueue))*forceReportBelowPercent)\n}\n\n// decrementReportedRecvSpace decreases the reported recv space by 1 and\n// returns if the receive space should be reported.\nfunc (dfq *DuplexFlowQueue) decrementReportedRecvSpace() (shouldReportRecvSpace bool) {\n\treturn atomic.AddInt32(dfq.reportedSpace, -1) < int32(float32(cap(dfq.recvQueue))*forceReportBelowPercent)\n}\n\n// getSendSpace returns the current send space.\nfunc (dfq *DuplexFlowQueue) getSendSpace() int32 {\n\treturn atomic.LoadInt32(dfq.sendSpace)\n}\n\n// decrementSendSpace decreases the send space by 1 and returns it.\nfunc (dfq *DuplexFlowQueue) decrementSendSpace() int32 {\n\treturn atomic.AddInt32(dfq.sendSpace, -1)\n}\n\nfunc (dfq *DuplexFlowQueue) addToSendSpace(n int32) {\n\t// Add new space to send space and check if it was zero.\n\tatomic.AddInt32(dfq.sendSpace, n)\n\t// Wake the sender in case it is waiting.\n\tselect {\n\tcase dfq.wakeSender <- struct{}{}:\n\tdefault:\n\t}\n}\n\n// reportableRecvSpace returns how much free space can be reported to the other\n// end. The returned number must be communicated to the other end and must not\n// be ignored.\nfunc (dfq *DuplexFlowQueue) reportableRecvSpace() int32 {\n\t// Changes to the recvQueue during calculation are no problem.\n\t// We don't want to report space twice though!\n\tdfq.spaceReportLock.Lock()\n\tdefer dfq.spaceReportLock.Unlock()\n\n\t// Calculate reportable receive space and add it to the reported space.\n\treportedSpace := atomic.LoadInt32(dfq.reportedSpace)\n\ttoReport := int32(cap(dfq.recvQueue)-len(dfq.recvQueue)) - reportedSpace\n\n\t// Never report values below zero.\n\t// This can happen, as dfq.reportedSpace is decreased after a container is\n\t// submitted to dfq.recvQueue by dfq.Deliver(). This race condition can only\n\t// lower the space to report, not increase it. A simple check here solved\n\t// this problem and keeps performance high.\n\t// Also, don't report values of 1, as the benefit is minimal and this might\n\t// be commonly triggered due to the buffer of the force report channel.\n\tif toReport <= 1 {\n\t\treturn 0\n\t}\n\n\t// Add space to report to dfq.reportedSpace and return it.\n\tatomic.AddInt32(dfq.reportedSpace, toReport)\n\treturn toReport\n}\n\n// FlowHandler handles all flow queue internals and must be started as a worker\n// in the module where it is used.\nfunc (dfq *DuplexFlowQueue) FlowHandler(_ *mgr.WorkerCtx) error {\n\t// The upstreamSender is started by the terminal module, but is tied to the\n\t// flow owner instead. Make sure that the flow owner's module depends on the\n\t// terminal module so that it is shut down earlier.\n\n\tvar sendSpaceDepleted bool\n\tvar flushFinished func()\n\n\t// Drain all queues when shutting down.\n\tdefer func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase msg := <-dfq.sendQueue:\n\t\t\t\tmsg.Finish()\n\t\t\tcase msg := <-dfq.recvQueue:\n\t\t\t\tmsg.Finish()\n\t\t\tdefault:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\nsending:\n\tfor {\n\t\t// If the send queue is depleted, wait to be woken.\n\t\tif sendSpaceDepleted {\n\t\t\tselect {\n\t\t\tcase <-dfq.wakeSender:\n\t\t\t\tif dfq.getSendSpace() > 0 {\n\t\t\t\t\tsendSpaceDepleted = false\n\t\t\t\t} else {\n\t\t\t\t\tcontinue sending\n\t\t\t\t}\n\n\t\t\tcase <-dfq.forceSpaceReport:\n\t\t\t\t// Forced reporting of space.\n\t\t\t\t// We do not need to check if there is enough sending space, as there is\n\t\t\t\t// no data included.\n\t\t\t\tspaceToReport := dfq.reportableRecvSpace()\n\t\t\t\tif spaceToReport > 0 {\n\t\t\t\t\tmsg := NewMsg(varint.Pack64(uint64(spaceToReport)))\n\t\t\t\t\tdfq.submitUpstream(msg, 0)\n\t\t\t\t}\n\t\t\t\tcontinue sending\n\n\t\t\tcase <-dfq.ctx.Done():\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\t// Get message from send queue.\n\n\t\tselect {\n\t\tcase dfq.readyToSend <- struct{}{}:\n\t\t\t// Notify that we are ready to send.\n\n\t\tcase msg := <-dfq.sendQueue:\n\t\t\t// Send message from queue.\n\n\t\t\t// If nil, the queue is being shut down.\n\t\t\tif msg == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Check if we are handling a high priority message or waiting for one.\n\t\t\t// Mark any msgs as high priority, when there is one in the pipeline.\n\t\t\tremainingPrioMsgs := atomic.AddInt32(dfq.prioMsgs, -1)\n\t\t\tswitch {\n\t\t\tcase remainingPrioMsgs >= 0:\n\t\t\t\tmsg.Unit.MakeHighPriority()\n\t\t\tcase remainingPrioMsgs < -30_000:\n\t\t\t\t// Prevent wrap to positive.\n\t\t\t\t// Compatible with int16 or bigger.\n\t\t\t\tatomic.StoreInt32(dfq.prioMsgs, 0)\n\t\t\t}\n\n\t\t\t// Wait for processing slot.\n\t\t\tmsg.Unit.WaitForSlot()\n\n\t\t\t// Prepend available receiving space.\n\t\t\tmsg.Data.Prepend(varint.Pack64(uint64(dfq.reportableRecvSpace())))\n\n\t\t\t// Submit for sending upstream.\n\t\t\tdfq.submitUpstream(msg, 0)\n\t\t\t// Decrease the send space and set flag if depleted.\n\t\t\tif dfq.decrementSendSpace() <= 0 {\n\t\t\t\tsendSpaceDepleted = true\n\t\t\t}\n\n\t\t\t// Check if the send queue is empty now and signal flushers.\n\t\t\tif flushFinished != nil && len(dfq.sendQueue) == 0 {\n\t\t\t\tflushFinished()\n\t\t\t\tflushFinished = nil\n\t\t\t}\n\n\t\tcase <-dfq.forceSpaceReport:\n\t\t\t// Forced reporting of space.\n\t\t\t// We do not need to check if there is enough sending space, as there is\n\t\t\t// no data included.\n\t\t\tspaceToReport := dfq.reportableRecvSpace()\n\t\t\tif spaceToReport > 0 {\n\t\t\t\tmsg := NewMsg(varint.Pack64(uint64(spaceToReport)))\n\t\t\t\tdfq.submitUpstream(msg, 0)\n\t\t\t}\n\n\t\tcase newFlushFinishedFn := <-dfq.flush:\n\t\t\t// Signal immediately if send queue is empty.\n\t\t\tif len(dfq.sendQueue) == 0 {\n\t\t\t\tnewFlushFinishedFn()\n\t\t\t} else {\n\t\t\t\t// If there already is a flush finished function, stack them.\n\t\t\t\tif flushFinished != nil {\n\t\t\t\t\tstackedFlushFinishFn := flushFinished\n\t\t\t\t\tflushFinished = func() {\n\t\t\t\t\t\tstackedFlushFinishFn()\n\t\t\t\t\t\tnewFlushFinishedFn()\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tflushFinished = newFlushFinishedFn\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase <-dfq.ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n// Flush waits for all waiting data to be sent.\nfunc (dfq *DuplexFlowQueue) Flush(timeout time.Duration) {\n\t// Create channel and function for notifying.\n\twait := make(chan struct{})\n\tfinished := func() {\n\t\tclose(wait)\n\t}\n\t// Request flush and return when stopping.\n\tselect {\n\tcase dfq.flush <- finished:\n\tcase <-dfq.ctx.Done():\n\t\treturn\n\tcase <-TimedOut(timeout):\n\t\treturn\n\t}\n\t// Wait for flush to finish and return when stopping.\n\tselect {\n\tcase <-wait:\n\tcase <-dfq.ctx.Done():\n\tcase <-TimedOut(timeout):\n\t}\n}\n\nvar ready = make(chan struct{})\n\nfunc init() {\n\tclose(ready)\n}\n\n// ReadyToSend returns a channel that can be read when data can be sent.\nfunc (dfq *DuplexFlowQueue) ReadyToSend() <-chan struct{} {\n\tif atomic.LoadInt32(dfq.sendSpace) > 0 {\n\t\treturn ready\n\t}\n\treturn dfq.readyToSend\n}\n\n// Send adds the given container to the send queue.\nfunc (dfq *DuplexFlowQueue) Send(msg *Msg, timeout time.Duration) *Error {\n\tselect {\n\tcase dfq.sendQueue <- msg:\n\t\tif msg.Unit.IsHighPriority() {\n\t\t\t// Reset prioMsgs to the current queue size, so that all waiting and the\n\t\t\t// message we just added are all handled as high priority.\n\t\t\tatomic.StoreInt32(dfq.prioMsgs, int32(len(dfq.sendQueue)))\n\t\t}\n\t\treturn nil\n\n\tcase <-TimedOut(timeout):\n\t\tmsg.Finish()\n\t\treturn ErrTimeout\n\n\tcase <-dfq.ctx.Done():\n\t\tmsg.Finish()\n\t\treturn ErrStopping\n\t}\n}\n\n// Receive receives a container from the recv queue.\nfunc (dfq *DuplexFlowQueue) Receive() <-chan *Msg {\n\t// If the reported recv space is nearing its end, force a report.\n\tif dfq.shouldReportRecvSpace() {\n\t\tselect {\n\t\tcase dfq.forceSpaceReport <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}\n\n\treturn dfq.recvQueue\n}\n\n// Deliver submits a container for receiving from upstream.\nfunc (dfq *DuplexFlowQueue) Deliver(msg *Msg) *Error {\n\t// Ignore nil containers.\n\tif msg == nil || msg.Data == nil {\n\t\tmsg.Finish()\n\t\treturn ErrMalformedData.With(\"no data\")\n\t}\n\n\t// Get and add new reported space.\n\taddSpace, err := msg.Data.GetNextN16()\n\tif err != nil {\n\t\tmsg.Finish()\n\t\treturn ErrMalformedData.With(\"failed to parse reported space: %w\", err)\n\t}\n\tif addSpace > 0 {\n\t\tdfq.addToSendSpace(int32(addSpace))\n\t}\n\t// Abort processing if the container only contained a space update.\n\tif !msg.Data.HoldsData() {\n\t\tmsg.Finish()\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase dfq.recvQueue <- msg:\n\n\t\t// If the recv queue accepted the Container, decrement the recv space.\n\t\tshouldReportRecvSpace := dfq.decrementReportedRecvSpace()\n\t\t// If the reported recv space is nearing its end, force a report, if the\n\t\t// sender worker is idle.\n\t\tif shouldReportRecvSpace {\n\t\t\tselect {\n\t\t\tcase dfq.forceSpaceReport <- struct{}{}:\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\tdefault:\n\t\t// If the recv queue is full, return an error.\n\t\t// The whole point of the flow queue is to guarantee that this never happens.\n\t\tmsg.Finish()\n\t\treturn ErrQueueOverflow\n\t}\n}\n\n// FlowStats returns a k=v formatted string of internal stats.\nfunc (dfq *DuplexFlowQueue) FlowStats() string {\n\treturn fmt.Sprintf(\n\t\t\"sq=%d rq=%d sends=%d reps=%d\",\n\t\tlen(dfq.sendQueue),\n\t\tlen(dfq.recvQueue),\n\t\tatomic.LoadInt32(dfq.sendSpace),\n\t\tatomic.LoadInt32(dfq.reportedSpace),\n\t)\n}\n\n// RecvQueueLen returns the current length of the receive queue.\nfunc (dfq *DuplexFlowQueue) RecvQueueLen() int {\n\treturn len(dfq.recvQueue)\n}\n\n// SendQueueLen returns the current length of the send queue.\nfunc (dfq *DuplexFlowQueue) SendQueueLen() int {\n\treturn len(dfq.sendQueue)\n}\n"
  },
  {
    "path": "spn/terminal/defaults.go",
    "content": "package terminal\n\nconst (\n\t// UsePriorityDataMsgs defines whether priority data messages should be used.\n\tUsePriorityDataMsgs = true\n)\n\n// DefaultCraneControllerOpts returns the default terminal options for a crane\n// controller terminal.\nfunc DefaultCraneControllerOpts() *TerminalOpts {\n\treturn &TerminalOpts{\n\t\tPadding:             0, // Crane already applies padding.\n\t\tFlowControl:         FlowControlNone,\n\t\tUsePriorityDataMsgs: UsePriorityDataMsgs,\n\t}\n}\n\n// DefaultHomeHubTerminalOpts returns the default terminal options for a crane\n// terminal used for the home hub.\nfunc DefaultHomeHubTerminalOpts() *TerminalOpts {\n\treturn &TerminalOpts{\n\t\tPadding:             0, // Crane already applies padding.\n\t\tFlowControl:         FlowControlDFQ,\n\t\tUsePriorityDataMsgs: UsePriorityDataMsgs,\n\t}\n}\n\n// DefaultExpansionTerminalOpts returns the default terminal options for an\n// expansion terminal.\nfunc DefaultExpansionTerminalOpts() *TerminalOpts {\n\treturn &TerminalOpts{\n\t\tPadding:             8,\n\t\tFlowControl:         FlowControlDFQ,\n\t\tUsePriorityDataMsgs: UsePriorityDataMsgs,\n\t}\n}\n"
  },
  {
    "path": "spn/terminal/errors.go",
    "content": "package terminal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/safing/structures/varint\"\n)\n\n// Error is a terminal error.\ntype Error struct {\n\t// id holds the internal error ID.\n\tid uint8\n\t// external signifies if the error was received from the outside.\n\texternal bool\n\t// err holds the wrapped error or the default error message.\n\terr error\n}\n\n// ID returns the internal ID of the error.\nfunc (e *Error) ID() uint8 {\n\treturn e.id\n}\n\n// Error returns the human readable format of the error.\nfunc (e *Error) Error() string {\n\tif e.external {\n\t\treturn \"[ext] \" + e.err.Error()\n\t}\n\treturn e.err.Error()\n}\n\n// IsExternal returns whether the error occurred externally.\nfunc (e *Error) IsExternal() bool {\n\tif e == nil {\n\t\treturn false\n\t}\n\n\treturn e.external\n}\n\n// Is returns whether the given error is of the same type.\nfunc (e *Error) Is(target error) bool {\n\tif e == nil || target == nil {\n\t\treturn false\n\t}\n\n\tt, ok := target.(*Error) //nolint:errorlint // Error implementation, not usage.\n\tif !ok {\n\t\treturn false\n\t}\n\treturn e.id == t.id\n}\n\n// Unwrap returns the wrapped error.\nfunc (e *Error) Unwrap() error {\n\tif e == nil || e.err == nil {\n\t\treturn nil\n\t}\n\treturn e.err\n}\n\n// With adds context and details where the error occurred. The provided\n// message is appended to the error.\n// A new error with the same ID is returned and must be compared with\n// errors.Is().\nfunc (e *Error) With(format string, a ...interface{}) *Error {\n\t// Return nil if error is nil.\n\tif e == nil {\n\t\treturn nil\n\t}\n\n\treturn &Error{\n\t\tid:  e.id,\n\t\terr: fmt.Errorf(e.Error()+\": \"+format, a...),\n\t}\n}\n\n// Wrap adds context higher up in the call chain. The provided message is\n// prepended to the error.\n// A new error with the same ID is returned and must be compared with\n// errors.Is().\nfunc (e *Error) Wrap(format string, a ...interface{}) *Error {\n\t// Return nil if error is nil.\n\tif e == nil {\n\t\treturn nil\n\t}\n\n\treturn &Error{\n\t\tid:  e.id,\n\t\terr: fmt.Errorf(format+\": \"+e.Error(), a...),\n\t}\n}\n\n// AsExternal creates and returns an external version of the error.\nfunc (e *Error) AsExternal() *Error {\n\t// Return nil if error is nil.\n\tif e == nil {\n\t\treturn nil\n\t}\n\n\treturn &Error{\n\t\tid:       e.id,\n\t\terr:      e.err,\n\t\texternal: true,\n\t}\n}\n\n// Pack returns the serialized internal error ID. The additional message is\n// lost and is replaced with the default message upon parsing.\nfunc (e *Error) Pack() []byte {\n\t// Return nil slice if error is nil.\n\tif e == nil {\n\t\treturn nil\n\t}\n\n\treturn varint.Pack8(e.id)\n}\n\n// ParseExternalError parses an external error.\nfunc ParseExternalError(id []byte) (*Error, error) {\n\t// Return nil for an empty error.\n\tif len(id) == 0 {\n\t\treturn ErrStopping.AsExternal(), nil\n\t}\n\n\tparsedID, _, err := varint.Unpack8(id)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unpack error ID: %w\", err)\n\t}\n\n\treturn NewExternalError(parsedID), nil\n}\n\n// NewExternalError creates an external error based on the given ID.\nfunc NewExternalError(id uint8) *Error {\n\terr, ok := errorRegistry[id]\n\tif ok {\n\t\treturn err.AsExternal()\n\t}\n\n\treturn ErrUnknownError.AsExternal()\n}\n\nvar errorRegistry = make(map[uint8]*Error)\n\nfunc registerError(id uint8, err error) *Error {\n\t// Check for duplicate.\n\t_, ok := errorRegistry[id]\n\tif ok {\n\t\tpanic(fmt.Sprintf(\"error with id %d already registered\", id))\n\t}\n\n\tnewErr := &Error{\n\t\tid:  id,\n\t\terr: err,\n\t}\n\n\terrorRegistry[id] = newErr\n\treturn newErr\n}\n\n// func (e *Error) IsSpecial() bool {\n// \tif e == nil {\n// \t\treturn false\n// \t}\n// \treturn e.id > 0 && e.id < 8\n// }\n\n// IsOK returns if the error represents a \"OK\" or success status.\nfunc (e *Error) IsOK() bool {\n\treturn !e.IsError()\n}\n\n// IsError returns if the error represents an erronous condition.\nfunc (e *Error) IsError() bool {\n\tif e == nil || e.err == nil {\n\t\treturn false\n\t}\n\tif e.id == 0 || e.id >= 8 {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Terminal Errors.\nvar (\n\t// ErrUnknownError is the default error.\n\tErrUnknownError = registerError(0, errors.New(\"unknown error\"))\n\n\t// Error IDs 1-7 are reserved for special \"OK\" values.\n\n\tErrStopping    = registerError(2, errors.New(\"stopping\"))\n\tErrExplicitAck = registerError(3, errors.New(\"explicit ack\"))\n\tErrNoActivity  = registerError(4, errors.New(\"no activity\"))\n\n\t// Errors IDs 8 and up are for regular errors.\n\n\tErrInternalError          = registerError(8, errors.New(\"internal error\"))\n\tErrMalformedData          = registerError(9, errors.New(\"malformed data\"))\n\tErrUnexpectedMsgType      = registerError(10, errors.New(\"unexpected message type\"))\n\tErrUnknownOperationType   = registerError(11, errors.New(\"unknown operation type\"))\n\tErrUnknownOperationID     = registerError(12, errors.New(\"unknown operation id\"))\n\tErrPermissionDenied       = registerError(13, errors.New(\"permission denied\"))\n\tErrIntegrity              = registerError(14, errors.New(\"integrity violated\"))\n\tErrInvalidOptions         = registerError(15, errors.New(\"invalid options\"))\n\tErrHubNotReady            = registerError(16, errors.New(\"hub not ready\"))\n\tErrRateLimited            = registerError(24, errors.New(\"rate limited\"))\n\tErrIncorrectUsage         = registerError(22, errors.New(\"incorrect usage\"))\n\tErrTimeout                = registerError(62, errors.New(\"timed out\"))\n\tErrUnsupportedVersion     = registerError(93, errors.New(\"unsupported version\"))\n\tErrHubUnavailable         = registerError(101, errors.New(\"hub unavailable\"))\n\tErrAbandonedTerminal      = registerError(102, errors.New(\"terminal is being abandoned\"))\n\tErrShipSunk               = registerError(108, errors.New(\"ship sunk\"))\n\tErrDestinationUnavailable = registerError(113, errors.New(\"destination unavailable\"))\n\tErrTryAgainLater          = registerError(114, errors.New(\"try again later\"))\n\tErrConnectionError        = registerError(121, errors.New(\"connection error\"))\n\tErrQueueOverflow          = registerError(122, errors.New(\"queue overflowed\"))\n\tErrCanceled               = registerError(125, context.Canceled)\n)\n"
  },
  {
    "path": "spn/terminal/fmt.go",
    "content": "package terminal\n\nimport \"fmt\"\n\n// CustomTerminalIDFormatting defines an interface for terminal to define their custom ID format.\ntype CustomTerminalIDFormatting interface {\n\tCustomIDFormat() string\n}\n\n// FmtID formats the terminal ID together with the parent's ID.\nfunc (t *TerminalBase) FmtID() string {\n\tif t.ext != nil {\n\t\tif customFormatting, ok := t.ext.(CustomTerminalIDFormatting); ok {\n\t\t\treturn customFormatting.CustomIDFormat()\n\t\t}\n\t}\n\n\treturn fmtTerminalID(t.parentID, t.id)\n}\n\nfunc fmtTerminalID(craneID string, terminalID uint32) string {\n\treturn fmt.Sprintf(\"%s#%d\", craneID, terminalID)\n}\n\nfunc fmtOperationID(craneID string, terminalID, operationID uint32) string {\n\treturn fmt.Sprintf(\"%s#%d>%d\", craneID, terminalID, operationID)\n}\n"
  },
  {
    "path": "spn/terminal/init.go",
    "content": "package terminal\n\nimport (\n\t\"context\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n\t\"github.com/safing/structures/varint\"\n)\n\n/*\n\nTerminal Init Message Format:\n\n- Version [varint]\n- Data Block [bytes; not blocked]\n\t- TerminalOpts as DSD\n\n*/\n\nconst (\n\tminSupportedTerminalVersion = 1\n\tmaxSupportedTerminalVersion = 1\n)\n\n// TerminalOpts holds configuration for the terminal.\ntype TerminalOpts struct { //nolint:golint,maligned // TODO: Rename.\n\tVersion uint8  `json:\"-\"`\n\tEncrypt bool   `json:\"e,omitempty\"`\n\tPadding uint16 `json:\"p,omitempty\"`\n\n\tFlowControl     FlowControlType `json:\"fc,omitempty\"`\n\tFlowControlSize uint32          `json:\"qs,omitempty\"` // Previously was \"QueueSize\".\n\n\tUsePriorityDataMsgs bool `json:\"pr,omitempty\"`\n}\n\n// ParseTerminalOpts parses terminal options from the container and checks if\n// they are valid.\nfunc ParseTerminalOpts(c *container.Container) (*TerminalOpts, *Error) {\n\t// Parse and check version.\n\tversion, err := c.GetNextN8()\n\tif err != nil {\n\t\treturn nil, ErrMalformedData.With(\"failed to parse version: %w\", err)\n\t}\n\tif version < minSupportedTerminalVersion || version > maxSupportedTerminalVersion {\n\t\treturn nil, ErrUnsupportedVersion.With(\"requested terminal version %d\", version)\n\t}\n\n\t// Parse init message.\n\tinitMsg := &TerminalOpts{}\n\t_, err = dsd.Load(c.CompileData(), initMsg)\n\tif err != nil {\n\t\treturn nil, ErrMalformedData.With(\"failed to parse init message: %w\", err)\n\t}\n\tinitMsg.Version = version\n\n\t// Check if options are valid.\n\ttErr := initMsg.Check(false)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\treturn initMsg, nil\n}\n\n// Pack serialized the terminal options and checks if they are valid.\nfunc (opts *TerminalOpts) Pack() (*container.Container, *Error) {\n\t// Check if options are valid.\n\ttErr := opts.Check(true)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\t// Pack init message.\n\toptsData, err := dsd.Dump(opts, dsd.CBOR)\n\tif err != nil {\n\t\treturn nil, ErrInternalError.With(\"failed to pack init message: %w\", err)\n\t}\n\n\t// Compile init message.\n\treturn container.New(\n\t\tvarint.Pack8(opts.Version),\n\t\toptsData,\n\t), nil\n}\n\n// Check checks if terminal options are valid.\nfunc (opts *TerminalOpts) Check(useDefaultsForRequired bool) *Error {\n\t// Version is required - use default when permitted.\n\tif opts.Version == 0 && useDefaultsForRequired {\n\t\topts.Version = 1\n\t}\n\tif opts.Version < minSupportedTerminalVersion || opts.Version > maxSupportedTerminalVersion {\n\t\treturn ErrInvalidOptions.With(\"unsupported terminal version %d\", opts.Version)\n\t}\n\n\t// FlowControl is optional.\n\tswitch opts.FlowControl {\n\tcase FlowControlDefault:\n\t\t// Set to default flow control.\n\t\topts.FlowControl = defaultFlowControl\n\tcase FlowControlNone, FlowControlDFQ:\n\t\t// Ok.\n\tdefault:\n\t\treturn ErrInvalidOptions.With(\"unknown flow control type: %d\", opts.FlowControl)\n\t}\n\n\t// FlowControlSize is required as it needs to be same on both sides.\n\t// Use default when permitted.\n\tif opts.FlowControlSize == 0 && useDefaultsForRequired {\n\t\topts.FlowControlSize = opts.FlowControl.DefaultSize()\n\t}\n\tif opts.FlowControlSize <= 0 || opts.FlowControlSize > MaxQueueSize {\n\t\treturn ErrInvalidOptions.With(\"invalid flow control size of %d\", opts.FlowControlSize)\n\t}\n\n\treturn nil\n}\n\n// NewLocalBaseTerminal creates a new local terminal base for use with inheriting terminals.\nfunc NewLocalBaseTerminal(\n\tctx context.Context,\n\tid uint32,\n\tparentID string,\n\tremoteHub *hub.Hub,\n\tinitMsg *TerminalOpts,\n\tupstream Upstream,\n) (\n\tt *TerminalBase,\n\tinitData *container.Container,\n\terr *Error,\n) {\n\t// Pack, check and add defaults to init message.\n\tinitData, err = initMsg.Pack()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Create baseline.\n\tt, err = createTerminalBase(ctx, id, parentID, false, initMsg, upstream)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Setup encryption if enabled.\n\tif remoteHub != nil {\n\t\tinitMsg.Encrypt = true\n\n\t\t// Select signet (public key) of remote Hub to use.\n\t\ts := remoteHub.SelectSignet()\n\t\tif s == nil {\n\t\t\treturn nil, nil, ErrHubNotReady.With(\"failed to select signet of remote hub\")\n\t\t}\n\n\t\t// Create new session.\n\t\tenv := jess.NewUnconfiguredEnvelope()\n\t\tenv.SuiteID = jess.SuiteWireV1\n\t\tenv.Recipients = []*jess.Signet{s}\n\t\tjession, err := env.WireCorrespondence(nil)\n\t\tif err != nil {\n\t\t\treturn nil, nil, ErrIntegrity.With(\"failed to initialize encryption: %w\", err)\n\t\t}\n\t\tt.jession = jession\n\n\t\t// Encryption is ready for sending.\n\t\tclose(t.encryptionReady)\n\t}\n\n\treturn t, initData, nil\n}\n\n// NewRemoteBaseTerminal creates a new remote terminal base for use with inheriting terminals.\nfunc NewRemoteBaseTerminal(\n\tctx context.Context,\n\tid uint32,\n\tparentID string,\n\tidentity *cabin.Identity,\n\tinitData *container.Container,\n\tupstream Upstream,\n) (\n\tt *TerminalBase,\n\tinitMsg *TerminalOpts,\n\terr *Error,\n) {\n\t// Parse init message.\n\tinitMsg, err = ParseTerminalOpts(initData)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Create baseline.\n\tt, err = createTerminalBase(ctx, id, parentID, true, initMsg, upstream)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// Setup encryption if enabled.\n\tif initMsg.Encrypt {\n\t\tif identity == nil {\n\t\t\treturn nil, nil, ErrInternalError.With(\"missing identity for setting up incoming encryption\")\n\t\t}\n\t\tt.identity = identity\n\t}\n\n\treturn t, initMsg, nil\n}\n"
  },
  {
    "path": "spn/terminal/metrics.go",
    "content": "package terminal\n\nimport (\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/api\"\n\t\"github.com/safing/portmaster/base/metrics\"\n)\n\nvar metricsRegistered = abool.New()\n\nfunc registerMetrics() (err error) {\n\t// Only register metrics once.\n\tif !metricsRegistered.SetToIf(false, true) {\n\t\treturn nil\n\t}\n\n\t// Get scheduler config and calculat scaling.\n\tschedulerConfig := getSchedulerConfig()\n\tscaleSlotToSecondsFactor := float64(time.Second / schedulerConfig.SlotDuration)\n\n\t// Register metrics from scheduler stats.\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/scheduling/unit/slotpace/max\",\n\t\tnil,\n\t\tmetricFromInt(scheduler.GetMaxSlotPace, scaleSlotToSecondsFactor),\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Scheduling Max Slot Pace (scaled to per second)\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/scheduling/unit/slotpace/leveled/max\",\n\t\tnil,\n\t\tmetricFromInt(scheduler.GetMaxLeveledSlotPace, scaleSlotToSecondsFactor),\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Scheduling Max Leveled Slot Pace (scaled to per second)\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/scheduling/unit/slotpace/avg\",\n\t\tnil,\n\t\tmetricFromInt(scheduler.GetAvgSlotPace, scaleSlotToSecondsFactor),\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Scheduling Avg Slot Pace (scaled to per second)\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/scheduling/unit/life/avg/seconds\",\n\t\tnil,\n\t\tmetricFromNanoseconds(scheduler.GetAvgUnitLife),\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Scheduling Avg Unit Life\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/scheduling/unit/workslot/avg/seconds\",\n\t\tnil,\n\t\tmetricFromNanoseconds(scheduler.GetAvgWorkSlotDuration),\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Scheduling Avg Work Slot Duration\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = metrics.NewGauge(\n\t\t\"spn/scheduling/unit/catchupslot/avg/seconds\",\n\t\tnil,\n\t\tmetricFromNanoseconds(scheduler.GetAvgCatchUpSlotDuration),\n\t\t&metrics.Options{\n\t\t\tName:       \"SPN Scheduling Avg Catch-Up Slot Duration\",\n\t\t\tPermission: api.PermitUser,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc metricFromInt(fn func() int64, scaleFactor float64) func() float64 {\n\treturn func() float64 {\n\t\treturn float64(fn()) * scaleFactor\n\t}\n}\n\nfunc metricFromNanoseconds(fn func() int64) func() float64 {\n\treturn func() float64 {\n\t\treturn float64(fn()) / float64(time.Second)\n\t}\n}\n"
  },
  {
    "path": "spn/terminal/module.go",
    "content": "package terminal\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/portmaster/spn/unit\"\n)\n\n// TerminalModule is the command multiplexing module.\ntype TerminalModule struct { //nolint:golint\n\tmgr      *mgr.Manager\n\tinstance instance\n}\n\n// Manager returns the module manager.\nfunc (s *TerminalModule) Manager() *mgr.Manager {\n\treturn s.mgr\n}\n\n// Start starts the module.\nfunc (s *TerminalModule) Start() error {\n\treturn start()\n}\n\n// Stop stops the module.\nfunc (s *TerminalModule) Stop() error {\n\treturn nil\n}\n\nvar (\n\trngFeeder *rng.Feeder = nil\n\n\tscheduler *unit.Scheduler\n\n\tdebugUnitScheduling bool\n)\n\nfunc init() {\n\tflag.BoolVar(&debugUnitScheduling, \"debug-unit-scheduling\", false, \"enable debug logs of the SPN unit scheduler\")\n}\n\nfunc start() error {\n\trngFeeder = rng.NewFeeder()\n\n\tscheduler = unit.NewScheduler(getSchedulerConfig())\n\tif debugUnitScheduling {\n\t\t// Debug unit leaks.\n\t\tscheduler.StartDebugLog()\n\t}\n\tmodule.mgr.Go(\"msg unit scheduler\", scheduler.SlotScheduler)\n\n\tlockOpRegistry()\n\n\treturn registerMetrics()\n}\n\nvar waitForever chan time.Time\n\n// TimedOut returns a channel that triggers when the timeout is reached.\nfunc TimedOut(timeout time.Duration) <-chan time.Time {\n\tif timeout == 0 {\n\t\treturn waitForever\n\t}\n\treturn time.After(timeout)\n}\n\n// StopScheduler stops the unit scheduler.\nfunc StopScheduler() {\n\tif scheduler != nil {\n\t\tscheduler.Stop()\n\t}\n}\n\nfunc getSchedulerConfig() *unit.SchedulerConfig {\n\t// Client Scheduler Config.\n\tif conf.Client() {\n\t\treturn &unit.SchedulerConfig{\n\t\t\tSlotDuration:            10 * time.Millisecond, // 100 slots per second\n\t\t\tMinSlotPace:             10,                    // 1000pps - Small starting pace for low end devices.\n\t\t\tWorkSlotPercentage:      0.9,                   // 90%\n\t\t\tSlotChangeRatePerStreak: 0.1,                   // 10% - Increase/Decrease quickly.\n\t\t\tStatCycleDuration:       1 * time.Minute,       // Match metrics report cycle.\n\t\t}\n\t}\n\n\t// Server Scheduler Config.\n\treturn &unit.SchedulerConfig{\n\t\tSlotDuration:            10 * time.Millisecond, // 100 slots per second\n\t\tMinSlotPace:             100,                   // 10000pps - Every server should be able to handle this.\n\t\tWorkSlotPercentage:      0.7,                   // 70%\n\t\tSlotChangeRatePerStreak: 0.05,                  // 5%\n\t\tStatCycleDuration:       1 * time.Minute,       // Match metrics report cycle.\n\t}\n}\n\nvar (\n\tmodule     *TerminalModule\n\tshimLoaded atomic.Bool\n)\n\n// New returns a new Config module.\nfunc New(instance instance) (*TerminalModule, error) {\n\tif !shimLoaded.CompareAndSwap(false, true) {\n\t\treturn nil, errors.New(\"only one instance allowed\")\n\t}\n\tm := mgr.New(\"TerminalModule\")\n\tmodule = &TerminalModule{\n\t\tmgr:      m,\n\t\tinstance: instance,\n\t}\n\treturn module, nil\n}\n\ntype instance interface{}\n"
  },
  {
    "path": "spn/terminal/module_test.go",
    "content": "package terminal\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/base/config\"\n\t\"github.com/safing/portmaster/base/database/dbmodule\"\n\t\"github.com/safing/portmaster/base/metrics\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/core/base\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/conf\"\n)\n\ntype testInstance struct {\n\tdb      *dbmodule.DBModule\n\tconfig  *config.Config\n\tmetrics *metrics.Metrics\n\trng     *rng.Rng\n\tbase    *base.Base\n\tcabin   *cabin.Cabin\n\tdataDir string\n}\n\nfunc (stub *testInstance) DataDir() string {\n\tif len(stub.dataDir) == 0 {\n\t\tvar err error\n\t\tstub.dataDir, err = os.MkdirTemp(\"\", \"\")\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"failed to create temp dir: %v\", err))\n\t\t}\n\t}\n\treturn stub.dataDir\n}\n\nfunc (stub *testInstance) Config() *config.Config {\n\treturn stub.config\n}\n\nfunc (stub *testInstance) Metrics() *metrics.Metrics {\n\treturn stub.metrics\n}\n\nfunc (stub *testInstance) SPNGroup() *mgr.ExtendedGroup {\n\treturn nil\n}\n\nfunc (stub *testInstance) Stopping() bool {\n\treturn false\n}\nfunc (stub *testInstance) SetCmdLineOperation(f func() error) {}\n\nfunc runTest(m *testing.M) error {\n\tvar err error\n\n\tconf.EnablePublicHub(true) // Make hub config available.\n\n\tinstance := &testInstance{}\n\tinstance.db, err = dbmodule.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create database module: %w\", err)\n\t}\n\tinstance.config, err = config.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config module: %w\", err)\n\t}\n\tinstance.metrics, err = metrics.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create metrics module: %w\", err)\n\t}\n\tinstance.rng, err = rng.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create rng module: %w\", err)\n\t}\n\tinstance.base, err = base.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create base module: %w\", err)\n\t}\n\tinstance.cabin, err = cabin.New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create cabin module: %w\", err)\n\t}\n\t_, err = New(instance)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create module: %w\", err)\n\t}\n\n\t// Start\n\terr = instance.db.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start db module: %w\", err)\n\t}\n\terr = instance.config.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start config module: %w\", err)\n\t}\n\terr = instance.metrics.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start metrics module: %w\", err)\n\t}\n\terr = instance.rng.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start rng module: %w\", err)\n\t}\n\terr = instance.base.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start base module: %w\", err)\n\t}\n\terr = instance.cabin.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start cabin module: %w\", err)\n\t}\n\terr = module.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start docks module: %w\", err)\n\t}\n\n\tm.Run()\n\treturn nil\n}\n\nfunc TestMain(m *testing.M) {\n\tif err := runTest(m); err != nil {\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "spn/terminal/msg.go",
    "content": "package terminal\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\n\t\"github.com/safing/portmaster/spn/unit\"\n\t\"github.com/safing/structures/container\"\n)\n\n// Msg is a message within the SPN network stack.\n// It includes metadata and unit scheduling.\ntype Msg struct {\n\tFlowID uint32\n\tType   MsgType\n\tData   *container.Container\n\n\t// Unit scheduling.\n\t// Note: With just 100B per packet, a uint64 (the Unit ID) is enough for\n\t// over 1800 Exabyte. No need for overflow support.\n\tUnit *unit.Unit\n}\n\n// NewMsg returns a new msg.\n// The FlowID is unset.\n// The Type is Data.\nfunc NewMsg(data []byte) *Msg {\n\tmsg := &Msg{\n\t\tType: MsgTypeData,\n\t\tData: container.New(data),\n\t\tUnit: scheduler.NewUnit(),\n\t}\n\n\t// Debug unit leaks.\n\tmsg.debugWithCaller(2)\n\n\treturn msg\n}\n\n// NewEmptyMsg returns a new empty msg with an initialized Unit.\n// The FlowID is unset.\n// The Type is Data.\n// The Data is unset.\nfunc NewEmptyMsg() *Msg {\n\tmsg := &Msg{\n\t\tType: MsgTypeData,\n\t\tUnit: scheduler.NewUnit(),\n\t}\n\n\t// Debug unit leaks.\n\tmsg.debugWithCaller(2)\n\n\treturn msg\n}\n\n// Pack prepends the message header (Length and ID+Type) to the data.\nfunc (msg *Msg) Pack() {\n\tMakeMsg(msg.Data, msg.FlowID, msg.Type)\n}\n\n// Consume adds another Message to itself.\n// The given Msg is packed before adding it to the data.\n// The data is moved - not copied!\n// High priority mark is inherited.\nfunc (msg *Msg) Consume(other *Msg) {\n\t// Pack message to be added.\n\tother.Pack()\n\n\t// Move data.\n\tmsg.Data.AppendContainer(other.Data)\n\n\t// Inherit high priority.\n\tif other.Unit.IsHighPriority() {\n\t\tmsg.Unit.MakeHighPriority()\n\t}\n\n\t// Finish other unit.\n\tother.Finish()\n}\n\n// Finish signals the unit scheduler that this unit has finished processing.\n// Will no-op if called on a nil Msg.\nfunc (msg *Msg) Finish() {\n\t// Proxying is necessary, as a nil msg still panics.\n\tif msg == nil {\n\t\treturn\n\t}\n\tmsg.Unit.Finish()\n}\n\n// Debug registers the unit for debug output with the given source.\n// Additional calls on the same unit update the unit source.\n// StartDebugLog() must be called before calling DebugUnit().\nfunc (msg *Msg) Debug() {\n\tmsg.debugWithCaller(2)\n}\n\nfunc (msg *Msg) debugWithCaller(skip int) { //nolint:unparam\n\tif !debugUnitScheduling || msg == nil {\n\t\treturn\n\t}\n\t_, file, line, ok := runtime.Caller(skip)\n\tif ok {\n\t\tscheduler.DebugUnit(msg.Unit, fmt.Sprintf(\"%s:%d\", file, line))\n\t}\n}\n"
  },
  {
    "path": "spn/terminal/msgtypes.go",
    "content": "package terminal\n\nimport (\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/varint\"\n)\n\n/*\nTerminal and Operation Message Format:\n\n- Length [varint]\n\t- If Length is 0, the remainder of given data is padding.\n- IDType [varint]\n\t- Type [uses least two significant bits]\n\t\t- One of Init, Data, Stop\n\t- ID [uses all other bits]\n\t\t- The ID is currently not adapted in order to make reading raw message\n\t\t\teasier. This means that IDs are currently always a multiple of 4.\n- Data [bytes; format depends on msg type]\n\t- MsgTypeInit:\n\t\t- Data [bytes]\n\t- MsgTypeData:\n\t\t- AddAvailableSpace [varint, if Flow Queue is used]\n\t\t- (Encrypted) Data [bytes]\n\t- MsgTypeStop:\n\t\t- Error Code [varint]\n*/\n\n// MsgType is the message type for both terminals and operations.\ntype MsgType uint8\n\nconst (\n\t// MsgTypeInit is used to establish a new terminal or run a new operation.\n\tMsgTypeInit MsgType = 1\n\n\t// MsgTypeData is used to send data to a terminal or operation.\n\tMsgTypeData MsgType = 2\n\n\t// MsgTypePriorityData is used to send prioritized data to a terminal or operation.\n\tMsgTypePriorityData MsgType = 0\n\n\t// MsgTypeStop is used to abandon a terminal or end an operation, with an optional error.\n\tMsgTypeStop MsgType = 3\n)\n\n// AddIDType prepends the ID and Type header to the message.\nfunc AddIDType(c *container.Container, id uint32, msgType MsgType) {\n\tc.Prepend(varint.Pack32(id | uint32(msgType)))\n}\n\n// MakeMsg prepends the message header (Length and ID+Type) to the data.\nfunc MakeMsg(c *container.Container, id uint32, msgType MsgType) {\n\tAddIDType(c, id, msgType)\n\tc.PrependLength()\n}\n\n// ParseIDType parses the combined message ID and type.\nfunc ParseIDType(c *container.Container) (id uint32, msgType MsgType, err error) {\n\tidType, err := c.GetNextN32()\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\n\tmsgType = MsgType(idType % 4)\n\treturn idType - uint32(msgType), msgType, nil\n}\n"
  },
  {
    "path": "spn/terminal/operation.go",
    "content": "package terminal\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/utils\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/structures/container\"\n)\n\n// Operation is an interface for all operations.\ntype Operation interface {\n\t// InitOperationBase initialize the operation with the ID and attached terminal.\n\t// Should not be overridden by implementations.\n\tInitOperationBase(t Terminal, opID uint32)\n\n\t// ID returns the ID of the operation.\n\t// Should not be overridden by implementations.\n\tID() uint32\n\n\t// Type returns the operation's type ID.\n\t// Should be overridden by implementations to return correct type ID.\n\tType() string\n\n\t// Deliver delivers a message to the operation.\n\t// Meant to be overridden by implementations.\n\tDeliver(msg *Msg) *Error\n\n\t// NewMsg creates a new message from this operation.\n\t// Should not be overridden by implementations.\n\tNewMsg(data []byte) *Msg\n\n\t// Send sends a message to the other side.\n\t// Should not be overridden by implementations.\n\tSend(msg *Msg, timeout time.Duration) *Error\n\n\t// Flush sends all messages waiting in the terminal.\n\t// Should not be overridden by implementations.\n\tFlush(timeout time.Duration)\n\n\t// Stopped returns whether the operation has stopped.\n\t// Should not be overridden by implementations.\n\tStopped() bool\n\n\t// markStopped marks the operation as stopped.\n\t// It returns whether the stop flag was set.\n\tmarkStopped() bool\n\n\t// Stop stops the operation by unregistering it from the terminal and calling HandleStop().\n\t// Should not be overridden by implementations.\n\tStop(self Operation, err *Error)\n\n\t// HandleStop gives the operation the ability to cleanly shut down.\n\t// The returned error is the error to send to the other side.\n\t// Should never be called directly. Call Stop() instead.\n\t// Meant to be overridden by implementations.\n\tHandleStop(err *Error) (errorToSend *Error)\n\n\t// Terminal returns the terminal the operation is linked to.\n\t// Should not be overridden by implementations.\n\tTerminal() Terminal\n}\n\n// OperationFactory defines an operation factory.\ntype OperationFactory struct {\n\t// Type is the type id of an operation.\n\tType string\n\t// Requires defines the required permissions to run an operation.\n\tRequires Permission\n\t// Start is the function that starts a new operation.\n\tStart OperationStarter\n}\n\n// OperationStarter is used to initialize operations remotely.\ntype OperationStarter func(attachedTerminal Terminal, opID uint32, initData *container.Container) (Operation, *Error)\n\nvar (\n\topRegistry       = make(map[string]*OperationFactory)\n\topRegistryLock   sync.Mutex\n\topRegistryLocked = abool.New()\n)\n\n// RegisterOpType registers a new operation type and may only be called during\n// Go's init and a module's prep phase.\nfunc RegisterOpType(factory OperationFactory) {\n\t// Check if we can still register an operation type.\n\tif opRegistryLocked.IsSet() {\n\t\tlog.Errorf(\"spn/terminal: failed to register operation %s: operation registry is already locked\", factory.Type)\n\t\treturn\n\t}\n\n\topRegistryLock.Lock()\n\tdefer opRegistryLock.Unlock()\n\n\t// Check if the operation type was already registered.\n\tif _, ok := opRegistry[factory.Type]; ok {\n\t\tlog.Errorf(\"spn/terminal: failed to register operation type %s: type already registered\", factory.Type)\n\t\treturn\n\t}\n\n\t// Save to registry.\n\topRegistry[factory.Type] = &factory\n}\n\nfunc lockOpRegistry() {\n\topRegistryLocked.Set()\n}\n\nfunc (t *TerminalBase) handleOperationStart(opID uint32, initData *container.Container) {\n\t// Check if the terminal is being abandoned.\n\tif t.Abandoning.IsSet() {\n\t\tt.StopOperation(newUnknownOp(opID, \"\"), ErrAbandonedTerminal)\n\t\treturn\n\t}\n\n\t// Extract the requested operation name.\n\topType, err := initData.GetNextBlock()\n\tif err != nil {\n\t\tt.StopOperation(newUnknownOp(opID, \"\"), ErrMalformedData.With(\"failed to get init data: %w\", err))\n\t\treturn\n\t}\n\n\t// Get the operation factory from the registry.\n\tfactory, ok := opRegistry[string(opType)]\n\tif !ok {\n\t\tt.StopOperation(newUnknownOp(opID, \"\"), ErrUnknownOperationType.With(utils.SafeFirst16Bytes(opType)))\n\t\treturn\n\t}\n\n\t// Check if the Terminal has the required permission to run the operation.\n\tif !t.HasPermission(factory.Requires) {\n\t\tt.StopOperation(newUnknownOp(opID, factory.Type), ErrPermissionDenied)\n\t\treturn\n\t}\n\n\t// Get terminal to attach to.\n\tattachToTerminal := t.ext\n\tif attachToTerminal == nil {\n\t\tattachToTerminal = t\n\t}\n\n\t// Run the operation.\n\top, opErr := factory.Start(attachToTerminal, opID, initData)\n\tswitch {\n\tcase opErr != nil:\n\t\t// Something went wrong.\n\t\tt.StopOperation(newUnknownOp(opID, factory.Type), opErr)\n\tcase op == nil:\n\t\t// The Operation was successful and is done already.\n\t\tlog.Debugf(\"spn/terminal: operation %s %s executed\", factory.Type, fmtOperationID(t.parentID, t.id, opID))\n\t\tt.StopOperation(newUnknownOp(opID, factory.Type), nil)\n\tdefault:\n\t\t// The operation started successfully and requires persistence.\n\t\tt.SetActiveOp(opID, op)\n\t\tlog.Debugf(\"spn/terminal: operation %s %s started\", factory.Type, fmtOperationID(t.parentID, t.id, opID))\n\t}\n}\n\n// StartOperation starts the given operation by assigning it an ID and sending the given operation initialization data.\nfunc (t *TerminalBase) StartOperation(op Operation, initData *container.Container, timeout time.Duration) *Error {\n\t// Get terminal to attach to.\n\tattachToTerminal := t.ext\n\tif attachToTerminal == nil {\n\t\tattachToTerminal = t\n\t}\n\n\t// Get the next operation ID and set it on the operation with the terminal.\n\top.InitOperationBase(attachToTerminal, atomic.AddUint32(t.nextOpID, 8))\n\n\t// Always add operation to the active operations, as we need to receive a\n\t// reply in any case.\n\tt.SetActiveOp(op.ID(), op)\n\n\tlog.Debugf(\"spn/terminal: operation %s %s started\", op.Type(), fmtOperationID(t.parentID, t.id, op.ID()))\n\n\t// Add or create the operation type block.\n\tif initData == nil {\n\t\tinitData = container.New()\n\t\tinitData.AppendAsBlock([]byte(op.Type()))\n\t} else {\n\t\tinitData.PrependAsBlock([]byte(op.Type()))\n\t}\n\n\t// Create init msg.\n\tmsg := NewEmptyMsg()\n\tmsg.FlowID = op.ID()\n\tmsg.Type = MsgTypeInit\n\tmsg.Data = initData\n\tmsg.Unit.MakeHighPriority()\n\n\t// Send init msg.\n\terr := op.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t}\n\treturn err\n}\n\n// Send sends data via this terminal.\n// If a timeout is set, sending will fail after the given timeout passed.\nfunc (t *TerminalBase) Send(msg *Msg, timeout time.Duration) *Error {\n\t// Wait for processing slot.\n\tmsg.Unit.WaitForSlot()\n\n\t// Check if the send queue has available space.\n\tselect {\n\tcase t.sendQueue <- msg:\n\t\treturn nil\n\tdefault:\n\t}\n\n\t// Submit message to buffer, if space is available.\n\tselect {\n\tcase t.sendQueue <- msg:\n\t\treturn nil\n\tcase <-TimedOut(timeout):\n\t\tmsg.Finish()\n\t\treturn ErrTimeout.With(\"sending via terminal\")\n\tcase <-t.Ctx().Done():\n\t\tmsg.Finish()\n\t\treturn ErrStopping\n\t}\n}\n\n// StopOperation sends the end signal with an optional error and then deletes\n// the operation from the Terminal state and calls HandleStop() on the Operation.\nfunc (t *TerminalBase) StopOperation(op Operation, err *Error) {\n\t// Check if the operation has already stopped.\n\tif !op.markStopped() {\n\t\treturn\n\t}\n\n\t// Log reason the Operation is ending. Override stopping error with nil.\n\tswitch {\n\tcase err == nil:\n\t\tlog.Debugf(\"spn/terminal: operation %s %s stopped\", op.Type(), fmtOperationID(t.parentID, t.id, op.ID()))\n\tcase err.IsOK(), err.Is(ErrTryAgainLater), err.Is(ErrRateLimited):\n\t\tlog.Debugf(\"spn/terminal: operation %s %s stopped: %s\", op.Type(), fmtOperationID(t.parentID, t.id, op.ID()), err)\n\tdefault:\n\t\tlog.Warningf(\"spn/terminal: operation %s %s failed: %s\", op.Type(), fmtOperationID(t.parentID, t.id, op.ID()), err)\n\t}\n\n\tmodule.mgr.Go(\"stop operation\", func(_ *mgr.WorkerCtx) error {\n\t\t// Call operation stop handle function for proper shutdown cleaning up.\n\t\terr = op.HandleStop(err)\n\n\t\t// Send error to the connected Operation, if the error is internal.\n\t\tif !err.IsExternal() {\n\t\t\tif err == nil {\n\t\t\t\terr = ErrStopping\n\t\t\t}\n\n\t\t\tmsg := NewMsg(err.Pack())\n\t\t\tmsg.FlowID = op.ID()\n\t\t\tmsg.Type = MsgTypeStop\n\n\t\t\ttErr := t.Send(msg, 10*time.Second)\n\t\t\tif tErr != nil {\n\t\t\t\tmsg.Finish()\n\t\t\t\tlog.Warningf(\"spn/terminal: failed to send stop msg: %s\", tErr)\n\t\t\t}\n\t\t}\n\n\t\t// Remove operation from terminal.\n\t\tt.DeleteActiveOp(op.ID())\n\n\t\treturn nil\n\t})\n}\n\n// GetActiveOp returns the active operation with the given ID from the\n// Terminal state.\nfunc (t *TerminalBase) GetActiveOp(opID uint32) (op Operation, ok bool) {\n\tt.lock.RLock()\n\tdefer t.lock.RUnlock()\n\n\top, ok = t.operations[opID]\n\treturn\n}\n\n// SetActiveOp saves an active operation to the Terminal state.\nfunc (t *TerminalBase) SetActiveOp(opID uint32, op Operation) {\n\tt.lock.Lock()\n\tdefer t.lock.Unlock()\n\n\tt.operations[opID] = op\n}\n\n// DeleteActiveOp deletes an active operation from the Terminal state.\nfunc (t *TerminalBase) DeleteActiveOp(opID uint32) {\n\tt.lock.Lock()\n\tdefer t.lock.Unlock()\n\n\tdelete(t.operations, opID)\n}\n\n// GetActiveOpCount returns the amount of active operations.\nfunc (t *TerminalBase) GetActiveOpCount() int {\n\tt.lock.RLock()\n\tdefer t.lock.RUnlock()\n\n\treturn len(t.operations)\n}\n\nfunc newUnknownOp(id uint32, typeID string) *unknownOp {\n\top := &unknownOp{\n\t\ttypeID: typeID,\n\t}\n\top.id = id\n\treturn op\n}\n\ntype unknownOp struct {\n\tOperationBase\n\ttypeID string\n}\n\nfunc (op *unknownOp) Type() string {\n\tif op.typeID != \"\" {\n\t\treturn op.typeID\n\t}\n\treturn \"unknown\"\n}\n\nfunc (op *unknownOp) Deliver(msg *Msg) *Error {\n\treturn ErrIncorrectUsage.With(\"unknown op shim cannot receive\")\n}\n"
  },
  {
    "path": "spn/terminal/operation_base.go",
    "content": "package terminal\n\nimport (\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n)\n\n// OperationBase provides the basic operation functionality.\ntype OperationBase struct {\n\tterminal Terminal\n\tid       uint32\n\tstopped  abool.AtomicBool\n}\n\n// InitOperationBase initialize the operation with the ID and attached terminal.\n// Should not be overridden by implementations.\nfunc (op *OperationBase) InitOperationBase(t Terminal, opID uint32) {\n\top.id = opID\n\top.terminal = t\n}\n\n// ID returns the ID of the operation.\n// Should not be overridden by implementations.\nfunc (op *OperationBase) ID() uint32 {\n\treturn op.id\n}\n\n// Type returns the operation's type ID.\n// Should be overridden by implementations to return correct type ID.\nfunc (op *OperationBase) Type() string {\n\treturn \"unknown\"\n}\n\n// Deliver delivers a message to the operation.\n// Meant to be overridden by implementations.\nfunc (op *OperationBase) Deliver(_ *Msg) *Error {\n\treturn ErrIncorrectUsage.With(\"Deliver not implemented for this operation\")\n}\n\n// NewMsg creates a new message from this operation.\n// Should not be overridden by implementations.\nfunc (op *OperationBase) NewMsg(data []byte) *Msg {\n\tmsg := NewMsg(data)\n\tmsg.FlowID = op.id\n\tmsg.Type = MsgTypeData\n\n\t// Debug unit leaks.\n\tmsg.debugWithCaller(2)\n\n\treturn msg\n}\n\n// NewEmptyMsg creates a new empty message from this operation.\n// Should not be overridden by implementations.\nfunc (op *OperationBase) NewEmptyMsg() *Msg {\n\tmsg := NewEmptyMsg()\n\tmsg.FlowID = op.id\n\tmsg.Type = MsgTypeData\n\n\t// Debug unit leaks.\n\tmsg.debugWithCaller(2)\n\n\treturn msg\n}\n\n// Send sends a message to the other side.\n// Should not be overridden by implementations.\nfunc (op *OperationBase) Send(msg *Msg, timeout time.Duration) *Error {\n\t// Add and update metadata.\n\tmsg.FlowID = op.id\n\tif msg.Type == MsgTypeData && msg.Unit.IsHighPriority() && UsePriorityDataMsgs {\n\t\tmsg.Type = MsgTypePriorityData\n\t}\n\n\t// Wait for processing slot.\n\tmsg.Unit.WaitForSlot()\n\n\t// Send message.\n\ttErr := op.terminal.Send(msg, timeout)\n\tif tErr != nil {\n\t\t// Finish message unit on failure.\n\t\tmsg.Finish()\n\t}\n\treturn tErr\n}\n\n// Flush sends all messages waiting in the terminal.\n// Meant to be overridden by implementations.\nfunc (op *OperationBase) Flush(timeout time.Duration) {\n\top.terminal.Flush(timeout)\n}\n\n// Stopped returns whether the operation has stopped.\n// Should not be overridden by implementations.\nfunc (op *OperationBase) Stopped() bool {\n\treturn op.stopped.IsSet()\n}\n\n// markStopped marks the operation as stopped.\n// It returns whether the stop flag was set.\nfunc (op *OperationBase) markStopped() bool {\n\treturn op.stopped.SetToIf(false, true)\n}\n\n// Stop stops the operation by unregistering it from the terminal and calling HandleStop().\n// Should not be overridden by implementations.\nfunc (op *OperationBase) Stop(self Operation, err *Error) {\n\t// Stop operation from terminal.\n\top.terminal.StopOperation(self, err)\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\n// Meant to be overridden by implementations.\nfunc (op *OperationBase) HandleStop(err *Error) (errorToSend *Error) {\n\treturn err\n}\n\n// Terminal returns the terminal the operation is linked to.\n// Should not be overridden by implementations.\nfunc (op *OperationBase) Terminal() Terminal {\n\treturn op.terminal\n}\n\n// OneOffOperationBase is an operation base for operations that just have one\n// message and a error return.\ntype OneOffOperationBase struct {\n\tOperationBase\n\n\tResult chan *Error\n}\n\n// Init initializes the single operation base.\nfunc (op *OneOffOperationBase) Init() {\n\top.Result = make(chan *Error, 1)\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *OneOffOperationBase) HandleStop(err *Error) (errorToSend *Error) {\n\tselect {\n\tcase op.Result <- err:\n\tdefault:\n\t}\n\treturn err\n}\n\n// MessageStreamOperationBase is an operation base for receiving a message stream.\n// Every received message must be finished by the implementing operation.\ntype MessageStreamOperationBase struct {\n\tOperationBase\n\n\tDelivered chan *Msg\n\tEnded     chan *Error\n}\n\n// Init initializes the operation base.\nfunc (op *MessageStreamOperationBase) Init(deliverQueueSize int) {\n\top.Delivered = make(chan *Msg, deliverQueueSize)\n\top.Ended = make(chan *Error, 1)\n}\n\n// Deliver delivers data to the operation.\nfunc (op *MessageStreamOperationBase) Deliver(msg *Msg) *Error {\n\tselect {\n\tcase op.Delivered <- msg:\n\t\treturn nil\n\tdefault:\n\t\treturn ErrIncorrectUsage.With(\"request was not waiting for data\")\n\t}\n}\n\n// HandleStop gives the operation the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Stop() instead.\nfunc (op *MessageStreamOperationBase) HandleStop(err *Error) (errorToSend *Error) {\n\tselect {\n\tcase op.Ended <- err:\n\tdefault:\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "spn/terminal/operation_counter.go",
    "content": "package terminal\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/structures/container\"\n\t\"github.com/safing/structures/dsd\"\n\t\"github.com/safing/structures/varint\"\n)\n\n// CounterOpType is the type ID for the Counter Operation.\nconst CounterOpType string = \"debug/count\"\n\n// CounterOp sends increasing numbers on both sides.\ntype CounterOp struct { //nolint:maligned\n\tOperationBase\n\n\twg     sync.WaitGroup\n\tserver bool\n\topts   *CounterOpts\n\n\tcounterLock   sync.Mutex\n\tClientCounter uint64\n\tServerCounter uint64\n\tError         error\n}\n\n// CounterOpts holds the options for CounterOp.\ntype CounterOpts struct {\n\tClientCountTo uint64\n\tServerCountTo uint64\n\tWait          time.Duration\n\tFlush         bool\n\n\tsuppressWorker bool\n}\n\nfunc init() {\n\tRegisterOpType(OperationFactory{\n\t\tType:  CounterOpType,\n\t\tStart: startCounterOp,\n\t})\n}\n\n// NewCounterOp returns a new CounterOp.\nfunc NewCounterOp(t Terminal, opts CounterOpts) (*CounterOp, *Error) {\n\t// Create operation.\n\top := &CounterOp{\n\t\topts: &opts,\n\t}\n\top.wg.Add(1)\n\n\t// Create argument container.\n\tdata, err := dsd.Dump(op.opts, dsd.JSON)\n\tif err != nil {\n\t\treturn nil, ErrInternalError.With(\"failed to pack options: %w\", err)\n\t}\n\n\t// Initialize operation.\n\ttErr := t.StartOperation(op, container.New(data), 3*time.Second)\n\tif tErr != nil {\n\t\treturn nil, tErr\n\t}\n\n\t// Start worker if needed.\n\tif op.getRemoteCounterTarget() > 0 && !op.opts.suppressWorker {\n\t\tmodule.mgr.Go(\"counter sender\", op.CounterWorker)\n\t}\n\treturn op, nil\n}\n\nfunc startCounterOp(t Terminal, opID uint32, data *container.Container) (Operation, *Error) {\n\t// Create operation.\n\top := &CounterOp{\n\t\tserver: true,\n\t}\n\top.InitOperationBase(t, opID)\n\top.wg.Add(1)\n\n\t// Parse arguments.\n\topts := &CounterOpts{}\n\t_, err := dsd.Load(data.CompileData(), opts)\n\tif err != nil {\n\t\treturn nil, ErrInternalError.With(\"failed to unpack options: %w\", err)\n\t}\n\top.opts = opts\n\n\t// Start worker if needed.\n\tif op.getRemoteCounterTarget() > 0 {\n\t\tmodule.mgr.Go(\"counter sender\", op.CounterWorker)\n\t}\n\n\treturn op, nil\n}\n\n// Type returns the operation's type ID.\nfunc (op *CounterOp) Type() string {\n\treturn CounterOpType\n}\n\nfunc (op *CounterOp) getCounter(sending, increase bool) uint64 {\n\top.counterLock.Lock()\n\tdefer op.counterLock.Unlock()\n\n\t// Use server counter, when op is server or for sending, but not when both.\n\tif op.server != sending {\n\t\tif increase {\n\t\t\top.ServerCounter++\n\t\t}\n\t\treturn op.ServerCounter\n\t}\n\n\tif increase {\n\t\top.ClientCounter++\n\t}\n\treturn op.ClientCounter\n}\n\nfunc (op *CounterOp) getRemoteCounterTarget() uint64 {\n\tif op.server {\n\t\treturn op.opts.ClientCountTo\n\t}\n\treturn op.opts.ServerCountTo\n}\n\nfunc (op *CounterOp) isDone() bool {\n\top.counterLock.Lock()\n\tdefer op.counterLock.Unlock()\n\n\treturn op.ClientCounter >= op.opts.ClientCountTo &&\n\t\top.ServerCounter >= op.opts.ServerCountTo\n}\n\n// Deliver delivers data to the operation.\nfunc (op *CounterOp) Deliver(msg *Msg) *Error {\n\tdefer msg.Finish()\n\n\tnextStep, err := msg.Data.GetNextN64()\n\tif err != nil {\n\t\top.Stop(op, ErrMalformedData.With(\"failed to parse next number: %w\", err))\n\t\treturn nil\n\t}\n\n\t// Count and compare.\n\tcounter := op.getCounter(false, true)\n\n\t// Debugging:\n\t// if counter < 100 ||\n\t// \tcounter < 1000 && counter%100 == 0 ||\n\t// \tcounter < 10000 && counter%1000 == 0 ||\n\t// \tcounter < 100000 && counter%10000 == 0 ||\n\t// \tcounter < 1000000 && counter%100000 == 0 {\n\t// \tlog.Errorf(\"spn/terminal: counter %s>%d recvd, now at %d\", op.t.FmtID(), op.id, counter)\n\t// }\n\n\tif counter != nextStep {\n\t\tlog.Warningf(\n\t\t\t\"terminal: integrity of counter op violated: received %d, expected %d\",\n\t\t\tnextStep,\n\t\t\tcounter,\n\t\t)\n\t\top.Stop(op, ErrIntegrity.With(\"counters mismatched\"))\n\t\treturn nil\n\t}\n\n\t// Check if we are done.\n\tif op.isDone() {\n\t\top.Stop(op, nil)\n\t}\n\n\treturn nil\n}\n\n// HandleStop handles stopping the operation.\nfunc (op *CounterOp) HandleStop(err *Error) (errorToSend *Error) {\n\t// Check if counting finished.\n\tif !op.isDone() {\n\t\terr := fmt.Errorf(\n\t\t\t\"counter op %d: did not finish counting (%d<-%d %d->%d)\",\n\t\t\top.id,\n\t\t\top.opts.ClientCountTo, op.ClientCounter,\n\t\t\top.ServerCounter, op.opts.ServerCountTo,\n\t\t)\n\t\top.Error = err\n\t}\n\n\top.wg.Done()\n\treturn err\n}\n\n// SendCounter sends the next counter.\nfunc (op *CounterOp) SendCounter() *Error {\n\tif op.Stopped() {\n\t\treturn ErrStopping\n\t}\n\n\t// Increase sending counter.\n\tcounter := op.getCounter(true, true)\n\n\t// Debugging:\n\t// if counter < 100 ||\n\t// \tcounter < 1000 && counter%100 == 0 ||\n\t// \tcounter < 10000 && counter%1000 == 0 ||\n\t// \tcounter < 100000 && counter%10000 == 0 ||\n\t// \tcounter < 1000000 && counter%100000 == 0 {\n\t// \tdefer log.Errorf(\"spn/terminal: counter %s>%d sent, now at %d\", op.t.FmtID(), op.id, counter)\n\t// }\n\n\treturn op.Send(op.NewMsg(varint.Pack64(counter)), 3*time.Second)\n}\n\n// Wait waits for the Counter Op to finish.\nfunc (op *CounterOp) Wait() {\n\top.wg.Wait()\n}\n\n// CounterWorker is a worker that sends counters.\nfunc (op *CounterOp) CounterWorker(ctx *mgr.WorkerCtx) error {\n\tfor {\n\t\t// Send counter msg.\n\t\terr := op.SendCounter()\n\t\tswitch err {\n\t\tcase nil:\n\t\t\t// All good, continue.\n\t\tcase ErrStopping:\n\t\t\t// Done!\n\t\t\treturn nil\n\t\tdefault:\n\t\t\t// Something went wrong.\n\t\t\terr := fmt.Errorf(\"counter op %d: failed to send counter: %w\", op.id, err)\n\t\t\top.Error = err\n\t\t\top.Stop(op, ErrInternalError.With(err.Error()))\n\t\t\treturn nil\n\t\t}\n\n\t\t// Maybe flush message.\n\t\tif op.opts.Flush {\n\t\t\top.terminal.Flush(1 * time.Second)\n\t\t}\n\n\t\t// Check if we are done with sending.\n\t\tif op.getCounter(true, false) >= op.getRemoteCounterTarget() {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Maybe wait a little.\n\t\tif op.opts.Wait > 0 {\n\t\t\ttime.Sleep(op.opts.Wait)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "spn/terminal/permission.go",
    "content": "package terminal\n\n// Permission is a bit-map of granted permissions.\ntype Permission uint16\n\n// Permissions.\nconst (\n\tNoPermission      Permission = 0x0\n\tMayExpand         Permission = 0x1\n\tMayConnect        Permission = 0x2\n\tIsHubOwner        Permission = 0x100\n\tIsHubAdvisor      Permission = 0x200\n\tIsCraneController Permission = 0x8000\n)\n\n// AuthorizingTerminal is an interface for terminals that support authorization.\ntype AuthorizingTerminal interface {\n\tGrantPermission(grant Permission)\n\tHasPermission(required Permission) bool\n}\n\n// GrantPermission grants the specified permissions to the Terminal.\nfunc (t *TerminalBase) GrantPermission(grant Permission) {\n\tt.lock.Lock()\n\tdefer t.lock.Unlock()\n\n\tt.permission |= grant\n}\n\n// HasPermission returns if the Terminal has the specified permission.\nfunc (t *TerminalBase) HasPermission(required Permission) bool {\n\tt.lock.RLock()\n\tdefer t.lock.RUnlock()\n\n\treturn t.permission.Has(required)\n}\n\n// Has returns if the permission includes the specified permission.\nfunc (p Permission) Has(required Permission) bool {\n\treturn p&required == required\n}\n\n// AddPermissions combines multiple permissions.\nfunc AddPermissions(perms ...Permission) Permission {\n\tvar all Permission\n\tfor _, p := range perms {\n\t\tall |= p\n\t}\n\treturn all\n}\n"
  },
  {
    "path": "spn/terminal/rate_limit.go",
    "content": "package terminal\n\nimport \"time\"\n\n// RateLimiter is a data flow rate limiter.\ntype RateLimiter struct {\n\tmaxBytesPerSlot uint64\n\tslotBytes       uint64\n\tslotStarted     time.Time\n}\n\n// NewRateLimiter returns a new rate limiter.\n// The given MBit/s are transformed to bytes, so giving a multiple of 8 is\n// advised for accurate results.\nfunc NewRateLimiter(mbits uint64) *RateLimiter {\n\treturn &RateLimiter{\n\t\tmaxBytesPerSlot: (mbits / 8) * 1_000_000,\n\t\tslotStarted:     time.Now(),\n\t}\n}\n\n// Limit is given the current transferred bytes and blocks until they may be sent.\nfunc (rl *RateLimiter) Limit(xferBytes uint64) {\n\t// Check if we need to limit transfer if we go over to max bytes per slot.\n\tif rl.slotBytes > rl.maxBytesPerSlot {\n\t\t// Wait if we are still within the slot.\n\t\tsinceSlotStart := time.Since(rl.slotStarted)\n\t\tif sinceSlotStart < time.Second {\n\t\t\ttime.Sleep(time.Second - sinceSlotStart)\n\t\t}\n\n\t\t// Reset state for next slot.\n\t\trl.slotBytes = 0\n\t\trl.slotStarted = time.Now()\n\t}\n\n\t// Add new bytes after checking, as first step over the limit is fully using the limit.\n\trl.slotBytes += xferBytes\n}\n"
  },
  {
    "path": "spn/terminal/session.go",
    "content": "package terminal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\nconst (\n\trateLimitMinOps          = 250\n\trateLimitMaxOpsPerSecond = 5\n\n\trateLimitMinSuspicion          = 25\n\trateLimitMinPermaSuspicion     = rateLimitMinSuspicion * 100\n\trateLimitMaxSuspicionPerSecond = 1\n\n\t// Make this big enough to trigger suspicion limit in first blast.\n\tconcurrencyPoolSize = 30\n)\n\n// Session holds terminal metadata for operations.\ntype Session struct {\n\tsync.RWMutex\n\n\t// Rate Limiting.\n\n\t// started holds the unix timestamp in seconds when the session was started.\n\t// It is set when the Session is created and may be treated as a constant.\n\tstarted int64\n\n\t// opCount is the amount of operations started (and not rate limited by suspicion).\n\topCount atomic.Int64\n\n\t// suspicionScore holds a score of suspicious activity.\n\t// Every suspicious operations is counted as at least 1.\n\t// Rate limited operations because of suspicion are also counted as 1.\n\tsuspicionScore atomic.Int64\n\n\tconcurrencyPool chan struct{}\n}\n\n// SessionTerminal is an interface for terminals that support authorization.\ntype SessionTerminal interface {\n\tGetSession() *Session\n}\n\n// SessionAddOn can be inherited by terminals to add support for sessions.\ntype SessionAddOn struct {\n\tlock sync.Mutex\n\n\t// session holds the terminal session.\n\tsession *Session\n}\n\n// GetSession returns the terminal's session.\nfunc (t *SessionAddOn) GetSession() *Session {\n\tt.lock.Lock()\n\tdefer t.lock.Unlock()\n\n\t// Create session if it does not exist.\n\tif t.session == nil {\n\t\tt.session = NewSession()\n\t}\n\n\treturn t.session\n}\n\n// NewSession returns a new session.\nfunc NewSession() *Session {\n\treturn &Session{\n\t\tstarted:         time.Now().Unix() - 1, // Ensure a 1 second difference to current time.\n\t\tconcurrencyPool: make(chan struct{}, concurrencyPoolSize),\n\t}\n}\n\n// RateLimitInfo returns some basic information about the status of the rate limiter.\nfunc (s *Session) RateLimitInfo() string {\n\tsecondsActive := time.Now().Unix() - s.started\n\n\treturn fmt.Sprintf(\n\t\t\"%do/s %ds/s %ds\",\n\t\ts.opCount.Load()/secondsActive,\n\t\ts.suspicionScore.Load()/secondsActive,\n\t\tsecondsActive,\n\t)\n}\n\n// RateLimit enforces a rate and suspicion limit.\nfunc (s *Session) RateLimit() *Error {\n\tsecondsActive := time.Now().Unix() - s.started\n\n\t// Check the suspicion limit.\n\tscore := s.suspicionScore.Load()\n\tif score > rateLimitMinSuspicion {\n\t\tscorePerSecond := score / secondsActive\n\t\tif scorePerSecond >= rateLimitMaxSuspicionPerSecond {\n\t\t\t// Add current try to suspicion score.\n\t\t\ts.suspicionScore.Add(1)\n\n\t\t\treturn ErrRateLimited\n\t\t}\n\n\t\t// Permanently rate limit if suspicion goes over the perma min limit and\n\t\t// the suspicion score is greater than 80% of the operation count.\n\t\tif score > rateLimitMinPermaSuspicion &&\n\t\t\tscore*5 > s.opCount.Load()*4 { // Think: 80*5 == 100*4\n\t\t\treturn ErrRateLimited\n\t\t}\n\t}\n\n\t// Check the rate limit.\n\tcount := s.opCount.Add(1)\n\tif count > rateLimitMinOps {\n\t\topsPerSecond := count / secondsActive\n\t\tif opsPerSecond >= rateLimitMaxOpsPerSecond {\n\t\t\treturn ErrRateLimited\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Suspicion Factors.\nconst (\n\tSusFactorCommon          = 1\n\tSusFactorWeirdButOK      = 5\n\tSusFactorQuiteUnusual    = 10\n\tSusFactorMustBeMalicious = 100\n)\n\n// ReportSuspiciousActivity reports suspicious activity of the terminal.\nfunc (s *Session) ReportSuspiciousActivity(factor int64) {\n\ts.suspicionScore.Add(factor)\n}\n\n// LimitConcurrency limits concurrent executions.\n// If over the limit, waiting goroutines are selected randomly.\n// It returns the context error if it was canceled.\nfunc (s *Session) LimitConcurrency(ctx context.Context, f func()) error {\n\t// Wait for place in pool.\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase s.concurrencyPool <- struct{}{}:\n\t\t// We added our entry to the pool, continue with execution.\n\t}\n\n\t// Drain own spot if pool after execution.\n\tdefer func() {\n\t\tselect {\n\t\tcase <-s.concurrencyPool:\n\t\t\t// Own entry drained.\n\t\tdefault:\n\t\t\t// This should never happen, but let's play safe and not deadlock when pool is empty.\n\t\t\tlog.Warningf(\"spn/session: failed to drain own entry from concurrency pool\")\n\t\t}\n\t}()\n\n\t// Execute and return.\n\tf()\n\treturn nil\n}\n"
  },
  {
    "path": "spn/terminal/session_test.go",
    "content": "package terminal\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRateLimit(t *testing.T) {\n\tt.Parallel()\n\n\tvar tErr *Error\n\ts := NewSession()\n\n\t// Everything should be okay within the min limit.\n\tfor range rateLimitMinOps {\n\t\ttErr = s.RateLimit()\n\t\tif tErr != nil {\n\t\t\tt.Error(\"should not rate limit within min limit\")\n\t\t}\n\t}\n\n\t// Somewhere here we should rate limiting.\n\tfor range rateLimitMaxOpsPerSecond {\n\t\ttErr = s.RateLimit()\n\t}\n\tassert.ErrorIs(t, tErr, ErrRateLimited, \"should rate limit\")\n}\n\nfunc TestSuspicionLimit(t *testing.T) {\n\tt.Parallel()\n\n\tvar tErr *Error\n\ts := NewSession()\n\n\t// Everything should be okay within the min limit.\n\tfor range rateLimitMinSuspicion {\n\t\ttErr = s.RateLimit()\n\t\tif tErr != nil {\n\t\t\tt.Error(\"should not rate limit within min limit\")\n\t\t}\n\t\ts.ReportSuspiciousActivity(SusFactorCommon)\n\t}\n\n\t// Somewhere here we should rate limiting.\n\tfor range rateLimitMaxSuspicionPerSecond {\n\t\ts.ReportSuspiciousActivity(SusFactorCommon)\n\t\ttErr = s.RateLimit()\n\t}\n\tif tErr == nil {\n\t\tt.Error(\"should rate limit\")\n\t}\n}\n\nfunc TestConcurrencyLimit(t *testing.T) {\n\tt.Parallel()\n\n\ts := NewSession()\n\tstarted := time.Now()\n\twg := sync.WaitGroup{}\n\tworkTime := 1 * time.Millisecond\n\tworkers := concurrencyPoolSize * 10\n\n\t// Start many workers to test concurrency.\n\twg.Add(workers)\n\tfor workerNum := range workers {\n\t\tgo func() {\n\t\t\tdefer func() {\n\t\t\t\t_ = recover()\n\t\t\t}()\n\t\t\t_ = s.LimitConcurrency(context.Background(), func() {\n\t\t\t\ttime.Sleep(workTime)\n\t\t\t\twg.Done()\n\n\t\t\t\t// Panic sometimes.\n\t\t\t\tif workerNum%concurrencyPoolSize == 0 {\n\t\t\t\t\tpanic(\"test\")\n\t\t\t\t}\n\t\t\t})\n\t\t}()\n\t}\n\n\t// Wait and check time needed.\n\twg.Wait()\n\tif time.Since(started) < (time.Duration(workers) * workTime / concurrencyPoolSize) {\n\t\tt.Errorf(\"workers were too quick - only took %s\", time.Since(started))\n\t} else {\n\t\tt.Logf(\"workers were correctly limited - took %s\", time.Since(started))\n\t}\n}\n"
  },
  {
    "path": "spn/terminal/terminal.go",
    "content": "package terminal\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/jess\"\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/base/rng\"\n\t\"github.com/safing/portmaster/service/mgr\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/conf\"\n\t\"github.com/safing/structures/container\"\n)\n\nconst (\n\ttimeoutTicks = 5\n\n\tclientTerminalAbandonTimeout = 15 * time.Second\n\tserverTerminalAbandonTimeout = 5 * time.Minute\n)\n\n// Terminal represents a terminal.\ntype Terminal interface { //nolint:golint // Being explicit is helpful here.\n\t// ID returns the terminal ID.\n\tID() uint32\n\t// Ctx returns the terminal context.\n\tCtx() context.Context\n\n\t// Deliver delivers a message to the terminal.\n\t// Should not be overridden by implementations.\n\tDeliver(msg *Msg) *Error\n\t// Send is used by others to send a message through the terminal.\n\t// Should not be overridden by implementations.\n\tSend(msg *Msg, timeout time.Duration) *Error\n\t// Flush sends all messages waiting in the terminal.\n\t// Should not be overridden by implementations.\n\tFlush(timeout time.Duration)\n\n\t// StartOperation starts the given operation by assigning it an ID and sending the given operation initialization data.\n\t// Should not be overridden by implementations.\n\tStartOperation(op Operation, initData *container.Container, timeout time.Duration) *Error\n\t// StopOperation stops the given operation.\n\t// Should not be overridden by implementations.\n\tStopOperation(op Operation, err *Error)\n\n\t// Abandon shuts down the terminal unregistering it from upstream and calling HandleAbandon().\n\t// Should not be overridden by implementations.\n\tAbandon(err *Error)\n\t// HandleAbandon gives the terminal the ability to cleanly shut down.\n\t// The terminal is still fully functional at this point.\n\t// The returned error is the error to send to the other side.\n\t// Should never be called directly. Call Abandon() instead.\n\t// Meant to be overridden by implementations.\n\tHandleAbandon(err *Error) (errorToSend *Error)\n\t// HandleDestruction gives the terminal the ability to clean up.\n\t// The terminal has already fully shut down at this point.\n\t// Should never be called directly. Call Abandon() instead.\n\t// Meant to be overridden by implementations.\n\tHandleDestruction(err *Error)\n\n\t// FmtID formats the terminal ID (including parent IDs).\n\t// May be overridden by implementations.\n\tFmtID() string\n}\n\n// TerminalBase contains the basic functions of a terminal.\ntype TerminalBase struct { //nolint:golint,maligned // Being explicit is helpful here.\n\t// TODO: Fix maligned.\n\tTerminal // Interface check.\n\n\tlock sync.RWMutex\n\n\t// id is the underlying id of the Terminal.\n\tid uint32\n\t// parentID is the id of the parent component.\n\tparentID string\n\n\t// ext holds the extended terminal so that the base terminal can access custom functions.\n\text Terminal\n\t// sendQueue holds message to be sent.\n\tsendQueue chan *Msg\n\t// flowControl holds the flow control system.\n\tflowControl FlowControl\n\t// upstream represents the upstream (parent) terminal.\n\tupstream Upstream\n\n\t// deliverProxy is populated with the configured deliver function\n\tdeliverProxy func(msg *Msg) *Error\n\t// recvProxy is populated with the configured recv function\n\trecvProxy func() <-chan *Msg\n\n\t// ctx is the context of the Terminal.\n\tctx context.Context\n\t// cancelCtx cancels ctx.\n\tcancelCtx context.CancelFunc\n\n\t// waitForFlush signifies if sending should be delayed until the next call\n\t// to Flush()\n\twaitForFlush *abool.AtomicBool\n\t// flush is used to send a finish function to the handler, which will write\n\t// all pending messages and then call the received function.\n\tflush chan func()\n\t// idleTicker ticks for increasing and checking the idle counter.\n\tidleTicker *time.Ticker\n\t// idleCounter counts the ticks the terminal has been idle.\n\tidleCounter *uint32\n\n\t// jession is the jess session used for encryption.\n\tjession *jess.Session\n\t// jessionLock locks jession.\n\tjessionLock sync.Mutex\n\t// encryptionReady is set when the encryption is ready for sending messages.\n\tencryptionReady chan struct{}\n\t// identity is the identity used by a remote Terminal.\n\tidentity *cabin.Identity\n\n\t// operations holds references to all active operations that require persistence.\n\toperations map[uint32]Operation\n\t// nextOpID holds the next operation ID.\n\tnextOpID *uint32\n\t// permission holds the permissions of the terminal.\n\tpermission Permission\n\n\t// opts holds the terminal options. It must not be modified after the terminal\n\t// has started.\n\topts *TerminalOpts\n\n\t// lastUnknownOpID holds the operation ID of the last data message received\n\t// for an unknown operation ID.\n\tlastUnknownOpID uint32\n\t// lastUnknownOpMsgs holds the amount of continuous data messages received\n\t// for the operation ID in lastUnknownOpID.\n\tlastUnknownOpMsgs uint32\n\n\t// Abandoning indicates if the Terminal is being abandoned. The main handlers\n\t// will keep running until the context has been canceled by the abandon\n\t// procedure.\n\t// No new operations should be started.\n\t// Whoever initiates the abandoning must also start the abandon procedure.\n\tAbandoning *abool.AtomicBool\n}\n\nfunc createTerminalBase(\n\tctx context.Context,\n\tid uint32,\n\tparentID string,\n\tremote bool,\n\tinitMsg *TerminalOpts,\n\tupstream Upstream,\n) (*TerminalBase, *Error) {\n\tt := &TerminalBase{\n\t\tid:              id,\n\t\tparentID:        parentID,\n\t\tsendQueue:       make(chan *Msg),\n\t\tupstream:        upstream,\n\t\twaitForFlush:    abool.New(),\n\t\tflush:           make(chan func()),\n\t\tidleTicker:      time.NewTicker(time.Minute),\n\t\tidleCounter:     new(uint32),\n\t\tencryptionReady: make(chan struct{}),\n\t\toperations:      make(map[uint32]Operation),\n\t\tnextOpID:        new(uint32),\n\t\topts:            initMsg,\n\t\tAbandoning:      abool.New(),\n\t}\n\t// Stop ticking to disable timeout.\n\tt.idleTicker.Stop()\n\t// Shift next operation ID if remote.\n\tif remote {\n\t\tatomic.AddUint32(t.nextOpID, 4)\n\t}\n\t// Create context.\n\tt.ctx, t.cancelCtx = context.WithCancel(ctx)\n\n\t// Create flow control.\n\tswitch initMsg.FlowControl {\n\tcase FlowControlDFQ:\n\t\tt.flowControl = NewDuplexFlowQueue(t.Ctx(), initMsg.FlowControlSize, t.submitToUpstream)\n\t\tt.deliverProxy = t.flowControl.Deliver\n\t\tt.recvProxy = t.flowControl.Receive\n\tcase FlowControlNone:\n\t\tdeliver := make(chan *Msg, initMsg.FlowControlSize)\n\t\tt.deliverProxy = MakeDirectDeliveryDeliverFunc(ctx, deliver)\n\t\tt.recvProxy = MakeDirectDeliveryRecvFunc(deliver)\n\tcase FlowControlDefault:\n\t\tfallthrough\n\tdefault:\n\t\treturn nil, ErrInternalError.With(\"unknown flow control type %d\", initMsg.FlowControl)\n\t}\n\n\treturn t, nil\n}\n\n// ID returns the Terminal's ID.\nfunc (t *TerminalBase) ID() uint32 {\n\treturn t.id\n}\n\n// Ctx returns the Terminal's context.\nfunc (t *TerminalBase) Ctx() context.Context {\n\treturn t.ctx\n}\n\n// SetTerminalExtension sets the Terminal's extension. This function is not\n// guarded and may only be used during initialization.\nfunc (t *TerminalBase) SetTerminalExtension(ext Terminal) {\n\tt.ext = ext\n}\n\n// SetTimeout sets the Terminal's idle timeout duration.\n// It is broken down into slots internally.\nfunc (t *TerminalBase) SetTimeout(d time.Duration) {\n\tt.idleTicker.Reset(d / timeoutTicks)\n}\n\n// Deliver on TerminalBase only exists to conform to the interface. It must be\n// overridden by an actual implementation.\nfunc (t *TerminalBase) Deliver(msg *Msg) *Error {\n\t// Deliver via configured proxy.\n\terr := t.deliverProxy(msg)\n\tif err != nil {\n\t\tmsg.Finish()\n\t}\n\n\treturn err\n}\n\n// StartWorkers starts the necessary workers to operate the Terminal.\nfunc (t *TerminalBase) StartWorkers(m *mgr.Manager, terminalName string) {\n\t// Start terminal workers.\n\tm.Go(terminalName+\" handler\", t.Handler)\n\tm.Go(terminalName+\" sender\", t.Sender)\n\n\t// Start any flow control workers.\n\tif t.flowControl != nil {\n\t\tt.flowControl.StartWorkers(m, terminalName)\n\t}\n}\n\nconst (\n\tsendThresholdLength  = 100  // bytes\n\tsendMaxLength        = 4000 // bytes\n\tsendThresholdMaxWait = 20 * time.Millisecond\n)\n\n// Handler receives and handles messages and must be started as a worker in the\n// module where the Terminal is used.\nfunc (t *TerminalBase) Handler(_ *mgr.WorkerCtx) error {\n\tdefer t.Abandon(ErrInternalError.With(\"handler died\"))\n\n\tvar msg *Msg\n\tdefer msg.Finish()\n\n\tfor {\n\t\tselect {\n\t\tcase <-t.ctx.Done():\n\t\t\t// Call Abandon just in case.\n\t\t\t// Normally, only the StopProcedure function should cancel the context.\n\t\t\tt.Abandon(nil)\n\t\t\treturn nil // Controlled worker exit.\n\n\t\tcase <-t.idleTicker.C:\n\t\t\t// If nothing happens for a while, end the session.\n\t\t\tif atomic.AddUint32(t.idleCounter, 1) > timeoutTicks {\n\t\t\t\t// Abandon the terminal and reset the counter.\n\t\t\t\tt.Abandon(ErrNoActivity)\n\t\t\t\tatomic.StoreUint32(t.idleCounter, 0)\n\t\t\t}\n\n\t\tcase msg = <-t.recvProxy():\n\t\t\terr := t.handleReceive(msg)\n\t\t\tif err != nil {\n\t\t\t\tt.Abandon(err.Wrap(\"failed to handle\"))\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Register activity.\n\t\t\tatomic.StoreUint32(t.idleCounter, 0)\n\t\t}\n\t}\n}\n\n// submit is used to send message from the terminal to upstream, including\n// going through flow control, if configured.\n// This function should be used to send message from the terminal to upstream.\nfunc (t *TerminalBase) submit(msg *Msg, timeout time.Duration) {\n\t// Submit directly if no flow control is configured.\n\tif t.flowControl == nil {\n\t\tt.submitToUpstream(msg, timeout)\n\t\treturn\n\t}\n\n\t// Hand over to flow control.\n\terr := t.flowControl.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t\tt.Abandon(err.Wrap(\"failed to submit to flow control\"))\n\t}\n}\n\n// submitToUpstream is used to directly submit messages to upstream.\n// This function should only be used by the flow control or submit function.\nfunc (t *TerminalBase) submitToUpstream(msg *Msg, timeout time.Duration) {\n\t// Add terminal ID as flow ID.\n\tmsg.FlowID = t.ID()\n\n\t// Debug unit leaks.\n\tmsg.debugWithCaller(2)\n\n\t// Submit to upstream.\n\terr := t.upstream.Send(msg, timeout)\n\tif err != nil {\n\t\tmsg.Finish()\n\t\tt.Abandon(err.Wrap(\"failed to submit to upstream\"))\n\t}\n}\n\n// Sender handles sending messages and must be started as a worker in the\n// module where the Terminal is used.\nfunc (t *TerminalBase) Sender(_ *mgr.WorkerCtx) error {\n\t// Don't send messages, if the encryption is net yet set up.\n\t// The server encryption session is only initialized with the first\n\t// operative message, not on Terminal creation.\n\tif t.opts.Encrypt {\n\t\tselect {\n\t\tcase <-t.ctx.Done():\n\t\t\t// Call Abandon just in case.\n\t\t\t// Normally, the only the StopProcedure function should cancel the context.\n\t\t\tt.Abandon(nil)\n\t\t\treturn nil // Controlled worker exit.\n\t\tcase <-t.encryptionReady:\n\t\t}\n\t}\n\n\t// Be sure to call Stop even in case of sudden death.\n\tdefer t.Abandon(ErrInternalError.With(\"sender died\"))\n\n\tvar msgBufferMsg *Msg\n\tvar msgBufferLen int\n\tvar msgBufferLimitReached bool\n\tvar sendMsgs bool\n\tvar sendMaxWait *time.Timer\n\tvar flushFinished func()\n\n\t// Finish any current unit when returning.\n\tdefer msgBufferMsg.Finish()\n\n\t// Only receive message when not sending the current msg buffer.\n\tsendQueueOpMsgs := func() <-chan *Msg {\n\t\t// Don't handle more messages, if the buffer is full.\n\t\tif msgBufferLimitReached {\n\t\t\treturn nil\n\t\t}\n\t\treturn t.sendQueue\n\t}\n\n\t// Only wait for sending slot when the current msg buffer is ready to be sent.\n\treadyToSend := func() <-chan struct{} {\n\t\tswitch {\n\t\tcase !sendMsgs:\n\t\t\t// Wait until there is something to send.\n\t\t\treturn nil\n\t\tcase t.flowControl != nil:\n\t\t\t// Let flow control decide when we are ready.\n\t\t\treturn t.flowControl.ReadyToSend()\n\t\tdefault:\n\t\t\t// Always ready.\n\t\t\treturn ready\n\t\t}\n\t}\n\n\t// Calculate current max wait time to send the msg buffer.\n\tgetSendMaxWait := func() <-chan time.Time {\n\t\tif sendMaxWait != nil {\n\t\t\treturn sendMaxWait.C\n\t\t}\n\t\treturn nil\n\t}\n\nhandling:\n\tfor {\n\t\tselect {\n\t\tcase <-t.ctx.Done():\n\t\t\t// Call Stop just in case.\n\t\t\t// Normally, the only the StopProcedure function should cancel the context.\n\t\t\tt.Abandon(nil)\n\t\t\treturn nil // Controlled worker exit.\n\n\t\tcase <-t.idleTicker.C:\n\t\t\t// If nothing happens for a while, end the session.\n\t\t\tif atomic.AddUint32(t.idleCounter, 1) > timeoutTicks {\n\t\t\t\t// Abandon the terminal and reset the counter.\n\t\t\t\tt.Abandon(ErrNoActivity)\n\t\t\t\tatomic.StoreUint32(t.idleCounter, 0)\n\t\t\t}\n\n\t\tcase msg := <-sendQueueOpMsgs():\n\t\t\tif msg == nil {\n\t\t\t\tcontinue handling\n\t\t\t}\n\n\t\t\t// Add unit to buffer unit, or use it as new buffer.\n\t\t\tif msgBufferMsg != nil {\n\t\t\t\t// Pack, append and finish additional message.\n\t\t\t\tmsgBufferMsg.Consume(msg)\n\t\t\t} else {\n\t\t\t\t// Pack operation message.\n\t\t\t\tmsg.Pack()\n\t\t\t\t// Convert to message of terminal.\n\t\t\t\tmsgBufferMsg = msg\n\t\t\t\tmsgBufferMsg.FlowID = t.ID()\n\t\t\t\tmsgBufferMsg.Type = MsgTypeData\n\t\t\t}\n\t\t\tmsgBufferLen += msg.Data.Length()\n\n\t\t\t// Check if there is enough data to hit the sending threshold.\n\t\t\tif msgBufferLen >= sendThresholdLength {\n\t\t\t\tsendMsgs = true\n\t\t\t} else if sendMaxWait == nil && t.waitForFlush.IsNotSet() {\n\t\t\t\tsendMaxWait = time.NewTimer(sendThresholdMaxWait)\n\t\t\t}\n\n\t\t\t// Check if we have reached the maximum buffer size.\n\t\t\tif msgBufferLen >= sendMaxLength {\n\t\t\t\tmsgBufferLimitReached = true\n\t\t\t}\n\n\t\t\t// Register activity.\n\t\t\tatomic.StoreUint32(t.idleCounter, 0)\n\n\t\tcase <-getSendMaxWait():\n\t\t\t// The timer for waiting for more data has ended.\n\t\t\t// Send all available data if not forced to wait for a flush.\n\t\t\tif t.waitForFlush.IsNotSet() {\n\t\t\t\tsendMsgs = true\n\t\t\t}\n\n\t\tcase newFlushFinishedFn := <-t.flush:\n\t\t\t// We are flushing - stop waiting.\n\t\t\tt.waitForFlush.UnSet()\n\n\t\t\t// Signal immediately if msg buffer is empty.\n\t\t\tif msgBufferLen == 0 {\n\t\t\t\tnewFlushFinishedFn()\n\t\t\t} else {\n\t\t\t\t// If there already is a flush finished function, stack them.\n\t\t\t\tif flushFinished != nil {\n\t\t\t\t\tstackedFlushFinishFn := flushFinished\n\t\t\t\t\tflushFinished = func() {\n\t\t\t\t\t\tstackedFlushFinishFn()\n\t\t\t\t\t\tnewFlushFinishedFn()\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tflushFinished = newFlushFinishedFn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Force sending data now.\n\t\t\tsendMsgs = true\n\n\t\tcase <-readyToSend():\n\t\t\t// Reset sending flags.\n\t\t\tsendMsgs = false\n\t\t\tmsgBufferLimitReached = false\n\n\t\t\t// Send if there is anything to send.\n\t\t\tvar err *Error\n\t\t\tif msgBufferLen > 0 {\n\t\t\t\t// Update message type to include priority.\n\t\t\t\tif msgBufferMsg.Type == MsgTypeData &&\n\t\t\t\t\tmsgBufferMsg.Unit.IsHighPriority() &&\n\t\t\t\t\tt.opts.UsePriorityDataMsgs {\n\t\t\t\t\tmsgBufferMsg.Type = MsgTypePriorityData\n\t\t\t\t}\n\n\t\t\t\t// Wait for clearance on initial msg only.\n\t\t\t\tmsgBufferMsg.Unit.WaitForSlot()\n\n\t\t\t\terr = t.sendOpMsgs(msgBufferMsg)\n\t\t\t}\n\n\t\t\t// Reset buffer.\n\t\t\tmsgBufferMsg = nil\n\t\t\tmsgBufferLen = 0\n\n\t\t\t// Reset send wait timer.\n\t\t\tif sendMaxWait != nil {\n\t\t\t\tsendMaxWait.Stop()\n\t\t\t\tsendMaxWait = nil\n\t\t\t}\n\n\t\t\t// Check if we are flushing and need to notify.\n\t\t\tif flushFinished != nil {\n\t\t\t\tflushFinished()\n\t\t\t\tflushFinished = nil\n\t\t\t}\n\n\t\t\t// Handle error after state updates.\n\t\t\tif err != nil {\n\t\t\t\tt.Abandon(err.With(\"failed to send\"))\n\t\t\t\tcontinue handling\n\t\t\t}\n\t\t}\n\t}\n}\n\n// WaitForFlush makes the terminal pause all sending until the next call to\n// Flush().\nfunc (t *TerminalBase) WaitForFlush() {\n\tt.waitForFlush.Set()\n}\n\n// Flush sends all data waiting to be sent.\nfunc (t *TerminalBase) Flush(timeout time.Duration) {\n\t// Create channel and function for notifying.\n\twait := make(chan struct{})\n\tfinished := func() {\n\t\tclose(wait)\n\t}\n\t// Request flush and return when stopping.\n\tselect {\n\tcase t.flush <- finished:\n\tcase <-t.Ctx().Done():\n\t\treturn\n\tcase <-TimedOut(timeout):\n\t\treturn\n\t}\n\t// Wait for flush to finish and return when stopping.\n\tselect {\n\tcase <-wait:\n\tcase <-t.Ctx().Done():\n\t\treturn\n\tcase <-TimedOut(timeout):\n\t\treturn\n\t}\n\n\t// Flush flow control, if configured.\n\tif t.flowControl != nil {\n\t\tt.flowControl.Flush(timeout)\n\t}\n}\n\nfunc (t *TerminalBase) encrypt(c *container.Container) (*container.Container, *Error) {\n\tif !t.opts.Encrypt {\n\t\treturn c, nil\n\t}\n\n\tt.jessionLock.Lock()\n\tdefer t.jessionLock.Unlock()\n\n\tletter, err := t.jession.Close(c.CompileData())\n\tif err != nil {\n\t\treturn nil, ErrIntegrity.With(\"failed to encrypt: %w\", err)\n\t}\n\n\tencryptedData, err := letter.ToWire()\n\tif err != nil {\n\t\treturn nil, ErrInternalError.With(\"failed to pack letter: %w\", err)\n\t}\n\n\treturn encryptedData, nil\n}\n\nfunc (t *TerminalBase) decrypt(c *container.Container) (*container.Container, *Error) {\n\tif !t.opts.Encrypt {\n\t\treturn c, nil\n\t}\n\n\tt.jessionLock.Lock()\n\tdefer t.jessionLock.Unlock()\n\n\tletter, err := jess.LetterFromWire(c)\n\tif err != nil {\n\t\treturn nil, ErrMalformedData.With(\"failed to parse letter: %w\", err)\n\t}\n\n\t// Setup encryption if not yet done.\n\tif t.jession == nil {\n\t\tif t.identity == nil {\n\t\t\treturn nil, ErrInternalError.With(\"missing identity for setting up incoming encryption\")\n\t\t}\n\n\t\t// Create jess session.\n\t\tt.jession, err = letter.WireCorrespondence(t.identity)\n\t\tif err != nil {\n\t\t\treturn nil, ErrIntegrity.With(\"failed to initialize incoming encryption: %w\", err)\n\t\t}\n\n\t\t// Don't need that anymore.\n\t\tt.identity = nil\n\n\t\t// Encryption is ready for sending.\n\t\tclose(t.encryptionReady)\n\t}\n\n\tdecryptedData, err := t.jession.Open(letter)\n\tif err != nil {\n\t\treturn nil, ErrIntegrity.With(\"failed to decrypt: %w\", err)\n\t}\n\n\treturn container.New(decryptedData), nil\n}\n\nfunc (t *TerminalBase) handleReceive(msg *Msg) *Error {\n\tmsg.Unit.WaitForSlot()\n\tdefer msg.Finish()\n\n\t// Debugging:\n\t// log.Errorf(\"spn/terminal %s handling tmsg: %s\", t.FmtID(), spew.Sdump(c.CompileData()))\n\n\t// Check if message is empty. This will be the case if a message was only\n\t// for updated the available space of the flow queue.\n\tif !msg.Data.HoldsData() {\n\t\treturn nil\n\t}\n\n\t// Decrypt if enabled.\n\tvar tErr *Error\n\tmsg.Data, tErr = t.decrypt(msg.Data)\n\tif tErr != nil {\n\t\treturn tErr\n\t}\n\n\t// Handle operation messages.\n\tfor msg.Data.HoldsData() {\n\t\t// Get next message length.\n\t\tmsgLength, err := msg.Data.GetNextN32()\n\t\tif err != nil {\n\t\t\treturn ErrMalformedData.With(\"failed to get operation msg length: %w\", err)\n\t\t}\n\t\tif msgLength == 0 {\n\t\t\t// Remainder is padding.\n\t\t\t// Padding can only be at the end of the segment.\n\t\t\tt.handlePaddingMsg(msg.Data)\n\t\t\treturn nil\n\t\t}\n\n\t\t// Get op msg data.\n\t\tmsgData, err := msg.Data.GetAsContainer(int(msgLength))\n\t\tif err != nil {\n\t\t\treturn ErrMalformedData.With(\"failed to get operation msg data (%d/%d bytes): %w\", msg.Data.Length(), msgLength, err)\n\t\t}\n\n\t\t// Handle op msg.\n\t\tif handleErr := t.handleOpMsg(msgData); handleErr != nil {\n\t\t\treturn handleErr\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (t *TerminalBase) handleOpMsg(data *container.Container) *Error {\n\t// Debugging:\n\t// log.Errorf(\"spn/terminal %s handling opmsg: %s\", t.FmtID(), spew.Sdump(data.CompileData()))\n\n\t// Parse message operation id, type.\n\topID, msgType, err := ParseIDType(data)\n\tif err != nil {\n\t\treturn ErrMalformedData.With(\"failed to parse operation msg id/type: %w\", err)\n\t}\n\n\tswitch msgType {\n\tcase MsgTypeInit:\n\t\tt.handleOperationStart(opID, data)\n\n\tcase MsgTypeData, MsgTypePriorityData:\n\t\top, ok := t.GetActiveOp(opID)\n\t\tif ok && !op.Stopped() {\n\t\t\t// Create message from data.\n\t\t\tmsg := NewEmptyMsg()\n\t\t\tmsg.FlowID = opID\n\t\t\tmsg.Type = msgType\n\t\t\tmsg.Data = data\n\t\t\tif msg.Type == MsgTypePriorityData {\n\t\t\t\tmsg.Unit.MakeHighPriority()\n\t\t\t}\n\n\t\t\t// Deliver message to operation.\n\t\t\ttErr := op.Deliver(msg)\n\t\t\tif tErr != nil {\n\t\t\t\t// Also stop on \"success\" errors!\n\t\t\t\tmsg.Finish()\n\t\t\t\tt.StopOperation(op, tErr)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\t// If an active op is not found, this is likely just left-overs from a\n\t\t// stopped or failed operation.\n\t\t// log.Tracef(\"spn/terminal: %s received data msg for unknown op %d\", fmtTerminalID(t.parentID, t.id), opID)\n\n\t\t// Send a stop error if this happens too often.\n\t\tif opID == t.lastUnknownOpID {\n\t\t\t// OpID is the same as last time.\n\t\t\tt.lastUnknownOpMsgs++\n\n\t\t\t// Log an warning (via StopOperation) and send a stop message every thousand.\n\t\t\tif t.lastUnknownOpMsgs%1000 == 0 {\n\t\t\t\tt.StopOperation(newUnknownOp(opID, \"\"), ErrUnknownOperationID.With(\"received %d unsolicited data msgs\", t.lastUnknownOpMsgs))\n\t\t\t}\n\n\t\t\t// TODO: Abandon terminal at over 10000?\n\t\t} else {\n\t\t\t// OpID changed, set new ID and reset counter.\n\t\t\tt.lastUnknownOpID = opID\n\t\t\tt.lastUnknownOpMsgs = 1\n\t\t}\n\n\tcase MsgTypeStop:\n\t\t// Parse received error.\n\t\topErr, parseErr := ParseExternalError(data.CompileData())\n\t\tif parseErr != nil {\n\t\t\tlog.Warningf(\"spn/terminal: %s failed to parse stop error: %s\", fmtTerminalID(t.parentID, t.id), parseErr)\n\t\t\topErr = ErrUnknownError.AsExternal()\n\t\t}\n\n\t\t// End operation.\n\t\top, ok := t.GetActiveOp(opID)\n\t\tif ok {\n\t\t\tt.StopOperation(op, opErr)\n\t\t} else {\n\t\t\tlog.Tracef(\"spn/terminal: %s received stop msg for unknown op %d\", fmtTerminalID(t.parentID, t.id), opID)\n\t\t}\n\n\tdefault:\n\t\tlog.Warningf(\"spn/terminal: %s received unexpected message type: %d\", t.FmtID(), msgType)\n\t\treturn ErrUnexpectedMsgType\n\t}\n\n\treturn nil\n}\n\nfunc (t *TerminalBase) handlePaddingMsg(c *container.Container) {\n\tpadding := c.GetAll()\n\tif len(padding) > 0 {\n\t\trngFeeder.SupplyEntropyIfNeeded(padding, len(padding))\n\t}\n}\n\nfunc (t *TerminalBase) sendOpMsgs(msg *Msg) *Error {\n\tmsg.Unit.WaitForSlot()\n\n\t// Add Padding if needed.\n\tif t.opts.Padding > 0 {\n\t\tpaddingNeeded := (int(t.opts.Padding) - msg.Data.Length()) % int(t.opts.Padding)\n\t\tif paddingNeeded > 0 {\n\t\t\t// Add padding message header.\n\t\t\tmsg.Data.Append([]byte{0})\n\t\t\tpaddingNeeded--\n\n\t\t\t// Add needed padding data.\n\t\t\tif paddingNeeded > 0 {\n\t\t\t\tpadding, err := rng.Bytes(paddingNeeded)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Debugf(\"spn/terminal: %s failed to get random data, using zeros instead\", t.FmtID())\n\t\t\t\t\tpadding = make([]byte, paddingNeeded)\n\t\t\t\t}\n\t\t\t\tmsg.Data.Append(padding)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Encrypt operative data.\n\tvar tErr *Error\n\tmsg.Data, tErr = t.encrypt(msg.Data)\n\tif tErr != nil {\n\t\treturn tErr\n\t}\n\n\t// Send data.\n\tt.submit(msg, 0)\n\treturn nil\n}\n\n// Abandon shuts down the terminal unregistering it from upstream and calling HandleAbandon().\n// Should not be overridden by implementations.\nfunc (t *TerminalBase) Abandon(err *Error) {\n\tif t.Abandoning.SetToIf(false, true) {\n\t\tmodule.mgr.Go(\"terminal abandon procedure\", func(_ *mgr.WorkerCtx) error {\n\t\t\tt.handleAbandonProcedure(err)\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\n// HandleAbandon gives the terminal the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Abandon() instead.\n// Meant to be overridden by implementations.\nfunc (t *TerminalBase) HandleAbandon(err *Error) (errorToSend *Error) {\n\treturn err\n}\n\n// HandleDestruction gives the terminal the ability to clean up.\n// The terminal has already fully shut down at this point.\n// Should never be called directly. Call Abandon() instead.\n// Meant to be overridden by implementations.\nfunc (t *TerminalBase) HandleDestruction(err *Error) {}\n\nfunc (t *TerminalBase) handleAbandonProcedure(err *Error) {\n\t// End all operations.\n\tfor _, op := range t.allOps() {\n\t\tt.StopOperation(op, nil)\n\t}\n\n\t// Prepare timeouts for waiting for ops.\n\ttimeout := clientTerminalAbandonTimeout\n\tif conf.PublicHub() {\n\t\ttimeout = serverTerminalAbandonTimeout\n\t}\n\tcheckTicker := time.NewTicker(50 * time.Millisecond)\n\tdefer checkTicker.Stop()\n\tabortWaiting := time.After(timeout)\n\n\t// Wait for all operations to end.\nwaitForOps:\n\tfor {\n\t\tselect {\n\t\tcase <-checkTicker.C:\n\t\t\tif t.GetActiveOpCount() <= 0 {\n\t\t\t\tbreak waitForOps\n\t\t\t}\n\t\tcase <-abortWaiting:\n\t\t\tlog.Warningf(\n\t\t\t\t\"spn/terminal: terminal %s is continuing shutdown with %d active operations\",\n\t\t\t\tt.FmtID(),\n\t\t\t\tt.GetActiveOpCount(),\n\t\t\t)\n\t\t\tbreak waitForOps\n\t\t}\n\t}\n\n\t// Call operation stop handle function for proper shutdown cleaning up.\n\tif t.ext != nil {\n\t\terr = t.ext.HandleAbandon(err)\n\t}\n\n\t// Send error to the connected Operation, if the error is internal.\n\tif !err.IsExternal() {\n\t\tif err == nil {\n\t\t\terr = ErrStopping\n\t\t}\n\n\t\tmsg := NewMsg(err.Pack())\n\t\tmsg.FlowID = t.ID()\n\t\tmsg.Type = MsgTypeStop\n\t\tt.submit(msg, 1*time.Second)\n\t}\n\n\t// If terminal was ended locally, send all data before abandoning.\n\t// If terminal was ended remotely, don't bother sending remaining data.\n\tif !err.IsExternal() {\n\t\t// Flushing could mean sending a full buffer of 50000 packets.\n\t\tt.Flush(5 * time.Minute)\n\t}\n\n\t// Stop all other connected workers.\n\tt.cancelCtx()\n\tt.idleTicker.Stop()\n\n\t// Call operation destruction handle function for proper shutdown cleaning up.\n\tif t.ext != nil {\n\t\tt.ext.HandleDestruction(err)\n\t}\n}\n\nfunc (t *TerminalBase) allOps() []Operation {\n\tt.lock.Lock()\n\tdefer t.lock.Unlock()\n\n\tops := make([]Operation, 0, len(t.operations))\n\tfor _, op := range t.operations {\n\t\tops = append(ops, op)\n\t}\n\n\treturn ops\n}\n\n// MakeDirectDeliveryDeliverFunc creates a submit upstream function with the\n// given delivery channel.\nfunc MakeDirectDeliveryDeliverFunc(\n\tctx context.Context,\n\tdeliver chan *Msg,\n) func(c *Msg) *Error {\n\treturn func(c *Msg) *Error {\n\t\tselect {\n\t\tcase deliver <- c:\n\t\t\treturn nil\n\t\tcase <-ctx.Done():\n\t\t\treturn ErrStopping\n\t\t}\n\t}\n}\n\n// MakeDirectDeliveryRecvFunc makes a delivery receive function with the given\n// delivery channel.\nfunc MakeDirectDeliveryRecvFunc(\n\tdeliver chan *Msg,\n) func() <-chan *Msg {\n\treturn func() <-chan *Msg {\n\t\treturn deliver\n\t}\n}\n"
  },
  {
    "path": "spn/terminal/terminal_test.go",
    "content": "package terminal\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime/pprof\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/structures/container\"\n)\n\nfunc TestTerminals(t *testing.T) {\n\tt.Parallel()\n\n\tidentity, erro := cabin.CreateIdentity(module.mgr.Ctx(), \"test\")\n\tif erro != nil {\n\t\tt.Fatalf(\"failed to create identity: %s\", erro)\n\t}\n\n\t// Test without and with encryption.\n\tfor _, encrypt := range []bool{false, true} {\n\t\t// Test with different flow controls.\n\t\tfor _, fc := range []struct {\n\t\t\tflowControl     FlowControlType\n\t\t\tflowControlSize uint32\n\t\t}{\n\t\t\t{\n\t\t\t\tflowControl:     FlowControlNone,\n\t\t\t\tflowControlSize: 5,\n\t\t\t},\n\t\t\t{\n\t\t\t\tflowControl:     FlowControlDFQ,\n\t\t\t\tflowControlSize: defaultTestQueueSize,\n\t\t\t},\n\t\t} {\n\t\t\t// Run tests with combined options.\n\t\t\ttestTerminals(t, identity, &TerminalOpts{\n\t\t\t\tEncrypt:         encrypt,\n\t\t\t\tPadding:         defaultTestPadding,\n\t\t\t\tFlowControl:     fc.flowControl,\n\t\t\t\tFlowControlSize: fc.flowControlSize,\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc testTerminals(t *testing.T, identity *cabin.Identity, terminalOpts *TerminalOpts) {\n\tt.Helper()\n\n\t// Prepare encryption.\n\tvar dstHub *hub.Hub\n\tif terminalOpts.Encrypt {\n\t\tdstHub = identity.Hub\n\t} else {\n\t\tidentity = nil\n\t}\n\n\t// Create test terminals.\n\tvar term1 *TestTerminal\n\tvar term2 *TestTerminal\n\tvar initData *container.Container\n\tvar err *Error\n\tterm1, initData, err = NewLocalTestTerminal(\n\t\tmodule.mgr.Ctx(), 127, \"c1\", dstHub, terminalOpts, createForwardingUpstream(\n\t\t\tt, \"c1\", \"c2\", func(msg *Msg) *Error {\n\t\t\t\treturn term2.Deliver(msg)\n\t\t\t},\n\t\t),\n\t)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create local terminal: %s\", err)\n\t}\n\tterm2, _, err = NewRemoteTestTerminal(\n\t\tmodule.mgr.Ctx(), 127, \"c2\", identity, initData, createForwardingUpstream(\n\t\t\tt, \"c2\", \"c1\", func(msg *Msg) *Error {\n\t\t\t\treturn term1.Deliver(msg)\n\t\t\t},\n\t\t),\n\t)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create remote terminal: %s\", err)\n\t}\n\n\t// Start testing with counters.\n\tcountToQueueSize := uint64(terminalOpts.FlowControlSize)\n\toptionsSuffix := fmt.Sprintf(\n\t\t\"encrypt=%v,flowType=%d\",\n\t\tterminalOpts.Encrypt,\n\t\tterminalOpts.FlowControl,\n\t)\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlyup-flushing-waiting:\" + optionsSuffix,\n\t\tflush:           true,\n\t\tserverCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: sendThresholdMaxWait * 2,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlyup-waiting:\" + optionsSuffix,\n\t\tserverCountTo:   10,\n\t\twaitBetweenMsgs: sendThresholdMaxWait * 2,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlyup-flushing:\" + optionsSuffix,\n\t\tflush:           true,\n\t\tserverCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: time.Millisecond,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlyup:\" + optionsSuffix,\n\t\tserverCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: time.Millisecond,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlydown-flushing-waiting:\" + optionsSuffix,\n\t\tflush:           true,\n\t\tclientCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: sendThresholdMaxWait * 2,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlydown-waiting:\" + optionsSuffix,\n\t\tclientCountTo:   10,\n\t\twaitBetweenMsgs: sendThresholdMaxWait * 2,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlydown-flushing:\" + optionsSuffix,\n\t\tflush:           true,\n\t\tclientCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: time.Millisecond,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"onlydown:\" + optionsSuffix,\n\t\tclientCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: time.Millisecond,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"twoway-flushing-waiting:\" + optionsSuffix,\n\t\tflush:           true,\n\t\tclientCountTo:   countToQueueSize * 2,\n\t\tserverCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: sendThresholdMaxWait * 2,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"twoway-waiting:\" + optionsSuffix,\n\t\tflush:           true,\n\t\tclientCountTo:   10,\n\t\tserverCountTo:   10,\n\t\twaitBetweenMsgs: sendThresholdMaxWait * 2,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"twoway-flushing:\" + optionsSuffix,\n\t\tflush:           true,\n\t\tclientCountTo:   countToQueueSize * 2,\n\t\tserverCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: time.Millisecond,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:        \"twoway:\" + optionsSuffix,\n\t\tclientCountTo:   countToQueueSize * 2,\n\t\tserverCountTo:   countToQueueSize * 2,\n\t\twaitBetweenMsgs: time.Millisecond,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:      \"stresstest-down:\" + optionsSuffix,\n\t\tclientCountTo: countToQueueSize * 1000,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:      \"stresstest-up:\" + optionsSuffix,\n\t\tserverCountTo: countToQueueSize * 1000,\n\t})\n\n\ttestTerminalWithCounters(t, term1, term2, &testWithCounterOpts{\n\t\ttestName:      \"stresstest-duplex:\" + optionsSuffix,\n\t\tclientCountTo: countToQueueSize * 1000,\n\t\tserverCountTo: countToQueueSize * 1000,\n\t})\n\n\t// Clean up.\n\tterm1.Abandon(nil)\n\tterm2.Abandon(nil)\n\n\t// Give some time for the last log messages and clean up.\n\ttime.Sleep(100 * time.Millisecond)\n}\n\nfunc createForwardingUpstream(t *testing.T, srcName, dstName string, deliverFunc func(*Msg) *Error) Upstream {\n\tt.Helper()\n\n\treturn UpstreamSendFunc(func(msg *Msg, _ time.Duration) *Error {\n\t\t// Fast track nil containers.\n\t\tif msg == nil {\n\t\t\tdErr := deliverFunc(msg)\n\t\t\tif dErr != nil {\n\t\t\t\tt.Errorf(\"%s>%s: failed to deliver nil msg to terminal: %s\", srcName, dstName, dErr)\n\t\t\t\treturn dErr.With(\"failed to deliver nil msg to terminal\")\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\t// Log messages.\n\t\tif logTestCraneMsgs {\n\t\t\tt.Logf(\"%s>%s: %v\\n\", srcName, dstName, msg.Data.CompileData())\n\t\t}\n\n\t\t// Deliver to other terminal.\n\t\tdErr := deliverFunc(msg)\n\t\tif dErr != nil {\n\t\t\tt.Errorf(\"%s>%s: failed to deliver to terminal: %s\", srcName, dstName, dErr)\n\t\t\treturn dErr.With(\"failed to deliver to terminal\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\ntype testWithCounterOpts struct {\n\ttestName        string\n\tflush           bool\n\tclientCountTo   uint64\n\tserverCountTo   uint64\n\twaitBetweenMsgs time.Duration\n}\n\nfunc testTerminalWithCounters(t *testing.T, term1, term2 *TestTerminal, opts *testWithCounterOpts) {\n\tt.Helper()\n\n\t// Wait async for test to complete, print stack after timeout.\n\tfinished := make(chan struct{})\n\tmaxTestDuration := 60 * time.Second\n\tgo func() {\n\t\tselect {\n\t\tcase <-finished:\n\t\tcase <-time.After(maxTestDuration):\n\t\t\tfmt.Printf(\"terminal test %s is taking more than %s, printing stack:\\n\", opts.testName, maxTestDuration)\n\t\t\t_ = pprof.Lookup(\"goroutine\").WriteTo(os.Stdout, 1)\n\t\t\tos.Exit(1)\n\t\t}\n\t}()\n\n\tt.Logf(\"starting terminal counter test %s\", opts.testName)\n\tdefer t.Logf(\"stopping terminal counter test %s\", opts.testName)\n\n\t// Start counters.\n\tcounter, tErr := NewCounterOp(term1, CounterOpts{\n\t\tClientCountTo: opts.clientCountTo,\n\t\tServerCountTo: opts.serverCountTo,\n\t\tFlush:         opts.flush,\n\t\tWait:          opts.waitBetweenMsgs,\n\t})\n\tif tErr != nil {\n\t\tt.Fatalf(\"terminal test %s failed to start counter: %s\", opts.testName, tErr)\n\t}\n\n\t// Wait until counters are done.\n\tcounter.Wait()\n\tclose(finished)\n\n\t// Check for error.\n\tif counter.Error != nil {\n\t\tt.Fatalf(\"terminal test %s failed to count: %s\", opts.testName, counter.Error)\n\t}\n\n\t// Log stats.\n\tprintCTStats(t, opts.testName, \"term1\", term1)\n\tprintCTStats(t, opts.testName, \"term2\", term2)\n\n\t// Check if stats match, if DFQ is used on both sides.\n\tdfq1, ok1 := term1.flowControl.(*DuplexFlowQueue)\n\tdfq2, ok2 := term2.flowControl.(*DuplexFlowQueue)\n\tif ok1 && ok2 &&\n\t\t(atomic.LoadInt32(dfq1.sendSpace) != atomic.LoadInt32(dfq2.reportedSpace) ||\n\t\t\tatomic.LoadInt32(dfq2.sendSpace) != atomic.LoadInt32(dfq1.reportedSpace)) {\n\t\tt.Fatalf(\"terminal test %s has non-matching space counters\", opts.testName)\n\t}\n}\n\nfunc printCTStats(t *testing.T, testName, name string, term *TestTerminal) {\n\tt.Helper()\n\n\tdfq, ok := term.flowControl.(*DuplexFlowQueue)\n\tif !ok {\n\t\treturn\n\t}\n\n\tt.Logf(\n\t\t\"%s: %s: sq=%d rq=%d sends=%d reps=%d\",\n\t\ttestName,\n\t\tname,\n\t\tlen(dfq.sendQueue),\n\t\tlen(dfq.recvQueue),\n\t\tatomic.LoadInt32(dfq.sendSpace),\n\t\tatomic.LoadInt32(dfq.reportedSpace),\n\t)\n}\n"
  },
  {
    "path": "spn/terminal/testing.go",
    "content": "package terminal\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"github.com/safing/portmaster/spn/cabin\"\n\t\"github.com/safing/portmaster/spn/hub\"\n\t\"github.com/safing/structures/container\"\n)\n\nconst (\n\tdefaultTestQueueSize = 16\n\tdefaultTestPadding   = 8\n\tlogTestCraneMsgs     = false\n)\n\n// TestTerminal is a terminal for running tests.\ntype TestTerminal struct {\n\t*TerminalBase\n}\n\n// NewLocalTestTerminal returns a new local test terminal.\nfunc NewLocalTestTerminal(\n\tctx context.Context,\n\tid uint32,\n\tparentID string,\n\tremoteHub *hub.Hub,\n\tinitMsg *TerminalOpts,\n\tupstream Upstream,\n) (*TestTerminal, *container.Container, *Error) {\n\t// Create Terminal Base.\n\tt, initData, err := NewLocalBaseTerminal(ctx, id, parentID, remoteHub, initMsg, upstream)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tt.StartWorkers(module.mgr, \"test terminal\")\n\n\treturn &TestTerminal{t}, initData, nil\n}\n\n// NewRemoteTestTerminal returns a new remote test terminal.\nfunc NewRemoteTestTerminal(\n\tctx context.Context,\n\tid uint32,\n\tparentID string,\n\tidentity *cabin.Identity,\n\tinitData *container.Container,\n\tupstream Upstream,\n) (*TestTerminal, *TerminalOpts, *Error) {\n\t// Create Terminal Base.\n\tt, initMsg, err := NewRemoteBaseTerminal(ctx, id, parentID, identity, initData, upstream)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tt.StartWorkers(module.mgr, \"test terminal\")\n\n\treturn &TestTerminal{t}, initMsg, nil\n}\n\ntype delayedMsg struct {\n\tmsg        *Msg\n\ttimeout    time.Duration\n\tdelayUntil time.Time\n}\n\nfunc createDelayingTestForwardingFunc(\n\tsrcName,\n\tdstName string,\n\tdelay time.Duration,\n\tdelayQueueSize int,\n\tdeliverFunc func(msg *Msg, timeout time.Duration) *Error,\n) func(msg *Msg, timeout time.Duration) *Error {\n\t// Return simple forward func if no delay is given.\n\tif delay == 0 {\n\t\treturn func(msg *Msg, timeout time.Duration) *Error {\n\t\t\t// Deliver to other terminal.\n\t\t\tdErr := deliverFunc(msg, timeout)\n\t\t\tif dErr != nil {\n\t\t\t\tlog.Errorf(\"spn/testing: %s>%s: failed to deliver to terminal: %s\", srcName, dstName, dErr)\n\t\t\t\treturn dErr\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// If there is delay, create a delaying channel and handler.\n\tdelayedMsgs := make(chan *delayedMsg, delayQueueSize)\n\tgo func() {\n\t\tfor {\n\t\t\t// Read from chan\n\t\t\tmsg := <-delayedMsgs\n\t\t\tif msg == nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Check if we need to wait.\n\t\t\twaitFor := time.Until(msg.delayUntil)\n\t\t\tif waitFor > 0 {\n\t\t\t\ttime.Sleep(waitFor)\n\t\t\t}\n\n\t\t\t// Deliver to other terminal.\n\t\t\tdErr := deliverFunc(msg.msg, msg.timeout)\n\t\t\tif dErr != nil {\n\t\t\t\tlog.Errorf(\"spn/testing: %s>%s: failed to deliver to terminal: %s\", srcName, dstName, dErr)\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn func(msg *Msg, timeout time.Duration) *Error {\n\t\t// Add msg to delaying msg channel.\n\t\tdelayedMsgs <- &delayedMsg{\n\t\t\tmsg:        msg,\n\t\t\ttimeout:    timeout,\n\t\t\tdelayUntil: time.Now().Add(delay),\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// HandleAbandon gives the terminal the ability to cleanly shut down.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Abandon() instead.\nfunc (t *TestTerminal) HandleAbandon(err *Error) (errorToSend *Error) {\n\tswitch err {\n\tcase nil:\n\t\t// nil means that the Terminal is being shutdown by the owner.\n\t\tlog.Tracef(\"spn/terminal: %s is closing\", fmtTerminalID(t.parentID, t.id))\n\tdefault:\n\t\t// All other errors are faults.\n\t\tlog.Warningf(\"spn/terminal: %s: %s\", fmtTerminalID(t.parentID, t.id), err)\n\t}\n\n\treturn\n}\n\n// NewSimpleTestTerminalPair provides a simple connected terminal pair for tests.\nfunc NewSimpleTestTerminalPair(delay time.Duration, delayQueueSize int, opts *TerminalOpts) (a, b *TestTerminal, err error) {\n\tif opts == nil {\n\t\topts = &TerminalOpts{\n\t\t\tPadding:         defaultTestPadding,\n\t\t\tFlowControl:     FlowControlDFQ,\n\t\t\tFlowControlSize: defaultTestQueueSize,\n\t\t}\n\t}\n\n\tvar initData *container.Container\n\tvar tErr *Error\n\ta, initData, tErr = NewLocalTestTerminal(\n\t\tmodule.mgr.Ctx(), 127, \"a\", nil, opts, UpstreamSendFunc(createDelayingTestForwardingFunc(\n\t\t\t\"a\", \"b\", delay, delayQueueSize, func(msg *Msg, timeout time.Duration) *Error {\n\t\t\t\treturn b.Deliver(msg)\n\t\t\t},\n\t\t)),\n\t)\n\tif tErr != nil {\n\t\treturn nil, nil, tErr.Wrap(\"failed to create local test terminal\")\n\t}\n\tb, _, tErr = NewRemoteTestTerminal(\n\t\tmodule.mgr.Ctx(), 127, \"b\", nil, initData, UpstreamSendFunc(createDelayingTestForwardingFunc(\n\t\t\t\"b\", \"a\", delay, delayQueueSize, func(msg *Msg, timeout time.Duration) *Error {\n\t\t\t\treturn a.Deliver(msg)\n\t\t\t},\n\t\t)),\n\t)\n\tif tErr != nil {\n\t\treturn nil, nil, tErr.Wrap(\"failed to create remote test terminal\")\n\t}\n\n\treturn a, b, nil\n}\n\n// BareTerminal is a bare terminal that just returns errors for testing.\ntype BareTerminal struct{}\n\nvar (\n\t_ Terminal = &BareTerminal{}\n\n\terrNotImplementedByBareTerminal = ErrInternalError.With(\"not implemented by bare terminal\")\n)\n\n// ID returns the terminal ID.\nfunc (t *BareTerminal) ID() uint32 {\n\treturn 0\n}\n\n// Ctx returns the terminal context.\nfunc (t *BareTerminal) Ctx() context.Context {\n\treturn context.Background()\n}\n\n// Deliver delivers a message to the terminal.\n// Should not be overridden by implementations.\nfunc (t *BareTerminal) Deliver(msg *Msg) *Error {\n\treturn errNotImplementedByBareTerminal\n}\n\n// Send is used by others to send a message through the terminal.\n// Should not be overridden by implementations.\nfunc (t *BareTerminal) Send(msg *Msg, timeout time.Duration) *Error {\n\treturn errNotImplementedByBareTerminal\n}\n\n// Flush sends all messages waiting in the terminal.\n// Should not be overridden by implementations.\nfunc (t *BareTerminal) Flush(timeout time.Duration) {}\n\n// StartOperation starts the given operation by assigning it an ID and sending the given operation initialization data.\n// Should not be overridden by implementations.\nfunc (t *BareTerminal) StartOperation(op Operation, initData *container.Container, timeout time.Duration) *Error {\n\treturn errNotImplementedByBareTerminal\n}\n\n// StopOperation stops the given operation.\n// Should not be overridden by implementations.\nfunc (t *BareTerminal) StopOperation(op Operation, err *Error) {}\n\n// Abandon shuts down the terminal unregistering it from upstream and calling HandleAbandon().\n// Should not be overridden by implementations.\nfunc (t *BareTerminal) Abandon(err *Error) {}\n\n// HandleAbandon gives the terminal the ability to cleanly shut down.\n// The terminal is still fully functional at this point.\n// The returned error is the error to send to the other side.\n// Should never be called directly. Call Abandon() instead.\n// Meant to be overridden by implementations.\nfunc (t *BareTerminal) HandleAbandon(err *Error) (errorToSend *Error) {\n\treturn err\n}\n\n// HandleDestruction gives the terminal the ability to clean up.\n// The terminal has already fully shut down at this point.\n// Should never be called directly. Call Abandon() instead.\n// Meant to be overridden by implementations.\nfunc (t *BareTerminal) HandleDestruction(err *Error) {}\n\n// FmtID formats the terminal ID (including parent IDs).\n// May be overridden by implementations.\nfunc (t *BareTerminal) FmtID() string {\n\treturn \"bare\"\n}\n"
  },
  {
    "path": "spn/terminal/upstream.go",
    "content": "package terminal\n\nimport \"time\"\n\n// Upstream defines the interface for upstream (parent) components.\ntype Upstream interface {\n\tSend(msg *Msg, timeout time.Duration) *Error\n}\n\n// UpstreamSendFunc is a helper to be able to satisfy the Upstream interface.\ntype UpstreamSendFunc func(msg *Msg, timeout time.Duration) *Error\n\n// Send is used to send a message through this upstream.\nfunc (fn UpstreamSendFunc) Send(msg *Msg, timeout time.Duration) *Error {\n\treturn fn(msg, timeout)\n}\n"
  },
  {
    "path": "spn/test",
    "content": "#!/bin/bash\n\nwarnings=0\nerrors=0\nscripted=0\ngoUp=\"\\\\e[1A\"\nfullTestFlags=\"-short\"\ninstall=0\ntestonly=0\n\nfunction help {\n  echo \"usage: $0 [command] [options]\"\n  echo \"\"\n  echo \"commands:\"\n  echo \"  <none>        run baseline tests\"\n  echo \"  full          run full tests (ie. not short)\"\n  echo \"  install       install deps for running tests\"\n  echo \"\"\n  echo \"options:\"\n  echo \"  --scripted    don't jump console lines (still use colors)\"\n  echo \"  --test-only   run tests only, no linters\"\n  echo \"  [package]     run only on this package\"\n}\n\nfunction run {\n  if [[ $scripted -eq 0 ]]; then\n    echo \"[......] $*\"\n  fi\n\n  # create tmpfile\n  tmpfile=$(mktemp)\n  # execute\n  $* >$tmpfile 2>&1\n  rc=$?\n  output=$(cat $tmpfile)\n\n  # check return code\n  if [[ $rc -eq 0 ]]; then\n    if [[ $output == *\"[no test files]\"* ]]; then\n      echo -e \"${goUp}[\\e[01;33mNOTEST\\e[00m] $*\"\n      warnings=$((warnings+1))\n    else\n      echo -ne \"${goUp}[\\e[01;32m  OK  \\e[00m] \"\n      if [[ $2 == \"test\" ]]; then\n        echo -n $*\n        echo -n \": \"\n        echo $output | cut -f \"3-\" -d \" \"\n      else\n        echo $*\n      fi\n    fi\n  else\n    if [[ $output == *\"build constraints exclude all Go files\"* ]]; then\n      echo -e \"${goUp}[ !=OS ] $*\"\n    else\n      echo -e \"${goUp}[\\e[01;31m FAIL \\e[00m] $*\"\n      cat $tmpfile\n      errors=$((errors+1))\n    fi\n  fi\n\n  rm -f $tmpfile\n}\n\n# get and switch to script dir\nbaseDir=\"$( cd \"$(dirname \"$0\")\" && pwd )\"\ncd \"$baseDir\"\n\n# args\nwhile true; do\n  case \"$1\" in\n  \"-h\"|\"help\"|\"--help\")\n    help\n    exit 0\n    ;;\n  \"--scripted\")\n    scripted=1\n    goUp=\"\"\n    shift 1\n    ;;\n  \"--test-only\")\n    testonly=1\n    shift 1\n    ;;\n  \"install\")\n    install=1\n    shift 1\n    ;;\n  \"full\")\n    fullTestFlags=\"\"\n    shift 1\n    ;;\n  *)\n    break\n    ;;\n  esac\ndone\n\n# check if $GOPATH/bin is in $PATH\nif [[ $PATH != *\"$GOPATH/bin\"* ]]; then\n  export PATH=$GOPATH/bin:$PATH\nfi\n\n# install\nif [[ $install -eq 1 ]]; then\n  echo \"installing dependencies...\"\n  # TODO: update golangci-lint version regularly\n  echo \"$ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0\"\n  curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0\n  exit 0\nfi\n\n# check dependencies\nif [[ $(which go) == \"\" ]]; then\n  echo \"go command not found\"\n  exit 1\nfi\nif [[ $testonly -eq 0 ]]; then\n  if [[ $(which gofmt) == \"\" ]]; then\n    echo \"gofmt command not found\"\n    exit 1\n  fi\n  if [[ $(which golangci-lint) == \"\" ]]; then\n    echo \"golangci-lint command not found\"\n    echo \"install with: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin vX.Y.Z\"\n    echo \"don't forget to specify the version you want\"\n    echo \"or run: ./test install\"\n    echo \"\"\n    echo \"alternatively, install the current dev version with: go get -u github.com/golangci/golangci-lint/cmd/golangci-lint\"\n    exit 1\n  fi\nfi\n\n# target selection\nif [[ \"$1\" == \"\" ]]; then\n  # get all packages\n  packages=$(go list -e ./...)\nelse\n  # single package testing\n  packages=$(go list -e)/$1\n  echo \"note: only running tests for package $packages\"\nfi\n\n# platform info\nplatformInfo=$(go env GOOS GOARCH)\necho \"running tests for ${platformInfo//$'\\n'/ }:\"\n\n# run vet/test on packages\nfor package in $packages; do\n  packagename=${package#github.com/safing/spn} #TODO: could be queried with `go list .`\n  packagename=${packagename#/}\n  echo \"\"\n  echo $package\n  if [[ $testonly -eq 0 ]]; then\n    run go vet $package\n    run golangci-lint run $packagename\n  fi\n  run go test -cover $fullTestFlags $package\ndone\n\necho \"\"\nif [[ $errors -gt 0 ]]; then\n  echo \"failed with $errors errors and $warnings warnings\"\n  exit 1\nelse\n  echo \"succeeded with $warnings warnings\"\n  exit 0\nfi\n"
  },
  {
    "path": "spn/testing/README.md",
    "content": "# Testing Port17\n\n## Simple Docker Setup\n\nRun `run.sh` to start the docker compose test network.\nThen, connect to the test network, by starting the core with the \"test\" spn map and the correct bootstrap file.\n\nRun `stop.sh` to remove all docker resources again.\n\nSetup Guide can be found in the directory.\n\n## Advanced Setup with Shadow\n\nFor advanced testing we use [shadow](https://github.com/shadow/shadow).\nThe following section will help you set up shadow and will guide you how to test Port17 in a local Shadow environment.\n\n### Setting up\n\nDownload the docker version from here: [https://security.cs.georgetown.edu/shadow-docker-images/shadow-standalone.tar.gz](https://security.cs.georgetown.edu/shadow-docker-images/shadow-standalone.tar.gz)\n\nThen import the image into docker with `gunzip -c shadow-standalone.tar.gz | sudo docker load`.\n\n### Running\n\nExecute `sudo docker run -t -i -u shadow shadow-standalone /bin/bash` to start an interactive container with shadow.\n"
  },
  {
    "path": "spn/testing/simple/README.md",
    "content": "# Setup Guide\n\n1. Build SPN Hub\n\n```\ncd ../../../cmds/hub/\n./build\n```\n\n2. Reset any previous state (for a fresh test)\n\n```\n./reset-databases.sh\n```\n\n3. Change compose file and config template as required\n\nFiles:\n- `docker-compose.yml`\n- `config-template.json`\n\n4. Start test network\n\n```\n./run.sh\n```\n\n5. Option 1: Join as Hub\n\nFor testing just one Hub with a different build or config, you can simply use `./join.sh` to join the network with the most recently build hub binary.\n\n6. Option 2: Join as Portmaster\n\nFor connecting to the SPN test network with Portmaster, execute portmaster like this:\n\n```\nsudo ../../../cmds/portmaster-core/portmaster-core --disable-shutdown-event --devmode --log debug --data /opt/safing/portmaster --spn-map test --bootstrap-file ./testdata/shared/bootstrap.dsd\n```\n\nNote:\nThis uses the same portmaster data and config as your installed version.\nAs the SPN Test net operates under a different ID (\"test\" instead of \"main\"), this will not pollute the SPN state of your installed Portmaster.\n\n7. Stop the test net\n\nThis is important, as just stopping the `./run.sh` script will leave you with interfaces with public IPs!\n\n```\n./stop.sh\n```\n"
  },
  {
    "path": "spn/testing/simple/clientsim.sh",
    "content": "#!/bin/bash\n\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\n\nrealpath() {\n    path=`eval echo \"$1\"`\n    folder=$(dirname \"$path\")\n    echo $(cd \"$folder\"; pwd)/$(basename \"$path\"); \n}\n\nif [[ ! -f \"../../client\" ]]; then\n  echo \"please compile client.go in main directory (output: client)\"\n  exit 1\nfi\n\nbin_path=\"$(realpath ../../client)\"\ndata_path=\"$(realpath ./testdata)\"\nif [[ ! -d \"$data_path\" ]]; then\n  mkdir \"$data_path\"\nfi\nshared_path=\"$(realpath ./testdata/shared)\"\nif [[ ! -d \"$shared_path\" ]]; then\n  mkdir \"$shared_path\"\nfi\n\ndocker network ls | grep spn-simpletest-network >/dev/null 2>&1\nif [[ $? -ne 0 ]]; then\n  docker network create spn-simpletest-network --subnet 6.0.0.0/24\nfi\n\ndocker run -ti --rm \\\n--name spn-simpletest-clientsim \\\n--network spn-simpletest-network \\\n-v $bin_path:/opt/client:ro \\\n-v $data_path/clientsim:/opt/data \\\n-v $shared_path:/opt/shared \\\n--entrypoint /opt/client \\\ntoolset.safing.network/dev \\\n--data /opt/data \\\n--bootstrap-file /opt/shared/bootstrap.dsd \\\n--log trace $*"
  },
  {
    "path": "spn/testing/simple/config-template.json",
    "content": "{\n  \"core\": {\n    \"log\": {\n      \"level\": \"trace\"\n    },\n    \"metrics\": {\n      \"instance\": \"test_$HUBNAME\",\n      \"push\": \"\"\n    }\n  },\n  \"spn\": {\n    \"publicHub\": {\n      \"name\": \"test-$HUBNAME\",\n      \"transports\": [\"http:80\", \"http:8080\", \"tcp:17\"],\n      \"allowUnencrypted\": true,\n      \"bindToAdvertised\": true\n    }\n  }\n}\n"
  },
  {
    "path": "spn/testing/simple/docker-compose.yml",
    "content": "version: \"2.4\"\n\nnetworks:\n  default:\n    ipam:\n      driver: default\n      config:\n        - subnet: 6.0.0.0/24\n\nservices:\n  hub1:\n    container_name: spn-test-simple-hub1\n    hostname: hub1\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_BIN}:/opt/hub1:ro\n      - ${SPN_TEST_DATA_DIR}/hub1:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.11\n\n  hub2:\n    container_name: spn-test-simple-hub2\n    hostname: hub2\n    image: alpine\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_BIN}:/opt/hub2:ro\n      - ${SPN_TEST_DATA_DIR}/hub2:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.12\n\n  hub3:\n    container_name: spn-test-simple-hub3\n    hostname: hub3\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_BIN}:/opt/hub3:ro\n      - ${SPN_TEST_DATA_DIR}/hub3:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.13\n\n  hub4:\n    container_name: spn-test-simple-hub4\n    hostname: hub4\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_BIN}:/opt/hub4:ro\n      - ${SPN_TEST_DATA_DIR}/hub4:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.14\n\n  hub5:\n    container_name: spn-test-simple-hub5\n    hostname: hub5\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_BIN}:/opt/hub5:ro\n      - ${SPN_TEST_DATA_DIR}/hub5:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.15\n\n  hub6:\n    container_name: spn-test-simple-hub6\n    hostname: hub6\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_OLD_BIN}:/opt/hub6:ro\n      - ${SPN_TEST_DATA_DIR}/hub6:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.16\n\n  hub7:\n    container_name: spn-test-simple-hub7\n    hostname: hub7\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_OLD_BIN}:/opt/hub7:ro\n      - ${SPN_TEST_DATA_DIR}/hub7:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.17\n\n  hub8:\n    container_name: spn-test-simple-hub8\n    hostname: hub8\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_OLD_BIN}:/opt/hub8:ro\n      - ${SPN_TEST_DATA_DIR}/hub8:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.18\n\n  hub9:\n    container_name: spn-test-simple-hub9\n    hostname: hub9\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_OLD_BIN}:/opt/hub9:ro\n      - ${SPN_TEST_DATA_DIR}/hub9:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.19\n\n  hub10:\n    container_name: spn-test-simple-hub10\n    hostname: hub10\n    image: toolset.safing.network/dev\n    entrypoint: \"/opt/shared/entrypoint.sh\"\n    volumes:\n      - ${SPN_TEST_OLD_BIN}:/opt/hub10:ro\n      - ${SPN_TEST_DATA_DIR}/hub10:/opt/data\n      - ${SPN_TEST_SHARED_DATA_DIR}:/opt/shared\n    networks:\n      default:\n        ipv4_address: 6.0.0.20\n"
  },
  {
    "path": "spn/testing/simple/entrypoint.sh",
    "content": "#!/bin/sh\n\n# Get hostname.\nHUBNAME=$HOSTNAME\nif [ \"$HUBNAME\" = \"\" ]; then\n  HUBNAME=$(cat /etc/hostname)\nfi\nexport HUBNAME\n\n# Read, process and write config.\ncat /opt/shared/config-template.json | sed \"s/\\$HUBNAME/$HUBNAME/g\" > /opt/data/config.json\n\n# Get binary to start.\nBIN=$(ls /opt/ | grep hub)\n\n# Start Hub.\n/opt/$BIN  --log trace --spn-map test --bootstrap-file /opt/shared/bootstrap.dsd --api-address 0.0.0.0:817 --devmode\n"
  },
  {
    "path": "spn/testing/simple/inject-intel.sh",
    "content": "#!/bin/bash\n\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\n\nMAIN_INTEL_FILE=\"intel-testnet.json\"\n\nif [[ ! -f $MAIN_INTEL_FILE ]]; then\n  echo \"missing $MAIN_INTEL_FILE\"\n  exit 1\nfi\n\necho \"if the containing directory cannot be created, you might need to adjust permissions, as nodes are run with root in test containers...\"\necho \"$ sudo chmod -R 777 data/hub*/updates\"\necho \"starting to update...\"\n\nfor hubDir in data/hub*; do\n  # Build destination path\n  hubIntelFile=\"${hubDir}/updates/all/intel/spn/main-intel_v0-0-0.dsd\"\n\n  # Copy file\n  mkdir -p \"${hubDir}/updates/all/intel/spn\"\n  echo -n \"J\" > \"$hubIntelFile\"\n  cat $MAIN_INTEL_FILE >> \"$hubIntelFile\"\n\n  echo \"updated $hubIntelFile\"\ndone\n\nif [[ -d /var/lib/portmaster ]]; then\n  echo \"updating intel for local portmaster installation...\"\n\n  portmasterSPNIntelFile=\"/var/lib/portmaster/updates/all/intel/spn/main-intel_v0-0-0.dsd\"\n  echo -n \"J\" > \"$portmasterSPNIntelFile\"\n  cat $MAIN_INTEL_FILE >> \"$portmasterSPNIntelFile\"\n  echo \"updated $portmasterSPNIntelFile\"\nfi\n"
  },
  {
    "path": "spn/testing/simple/intel-client.yaml",
    "content": "# Get current list of IDs from test net:\n#   curl http://127.0.0.1:817/api/v1/spn/map/test/pins | jq \".[] | .ID\"\n# Then import into test client with:\n#   curl -X POST --upload-file intel-client.yaml http://127.0.0.1:817/api/v1/spn/map/test/intel/update\nHubs:\n  Zwm48YWWFGdwXjhE1MyEkWfqxPr9DiUBoXpusTZ1FMQnuK:\n    Trusted: true\n  Zwu5LkkbfCbAcYxWG3vtWF1VvWjgWpc1GJfkwRdLFNtytV:\n    Trusted: true\n  ZwuQpz5CqYmYoLnt9KXQ8oxnmosBzfrCYwCGhxT4fsG1Dz:\n    Trusted: true\n  ZwwmC3dHzr7J6XW9mc2KD6FDNuXwPVJUFi9dLnDSNMyjLk:\n    Trusted: true\n  ZwxSBdvqtJyz8zRWKZe6QyK51KH9av6VFay2GQvpFrWKHq:\n    Trusted: true\n  ZwxnuL6zMLj4AxJX8Bj369w2tNrVtYxzffVcXZuMxdxbGj:\n    Trusted: true\n  ZwyXdnC8JkC7m796skGD7QWGoYycByR3KVntkXMY8CxRZQ:\n    Trusted: true\n  Zwz7AHiH1EevD9eYFqvQQPbVWyBBcksTRxxafbRx5Cvc4F:\n    Trusted: true\n  ZwzMtc65t9XBMwmLm2xNSL69FvqHGPLiqeNBZ3eEN5a9sS:\n    Trusted: true\n  ZwzjnCUNGsuWnkYmN3QEj8JPLxU6V1QQFk9b47AigmPKiH:\n    Trusted: true\n"
  },
  {
    "path": "spn/testing/simple/intel-testnet.json",
    "content": "{\n\t\"BootstrapHubs\": [\n\t],\n\t\"TrustedHubs\": [\n\t\t\"ZwrY9G9HDo1J3qQrrQs8VF2KD99bj7KyWesJ5kWFUDBU6r\",\n\t\t\"Zwj56ZFXrsud8gc1Rw3zuxRwMLhGkwvtvnTxCVtJ8EWLhQ\",\n\t\t\"ZwpdW87ityD9i3N9x8oweCJnbZEqo346VBg4mCsCvTr1Zo\",\n\t\t\"ZwpJ6ebddk1sccUVpo92JUqicBfKzBN2w4pEGoEY7UsNhX\",\n\t\t\"Zwte3Jffp9PWmeWfrn8RyGuvZZFCg3v7XR3tpQjdo9TpVt\",\n\t\t\"ZwrTcdiPF5zR5h9q9EdjHCrrXzYVBdQe5HmEYUWXdLkke3\",\n\t\t\"Zwv7tSn5iU6bYKn53NaGCxPtL8vSxSK7F9VdQezDaDCLBt\",\n\t\t\"Zwvtdq3K9knP9iNaRS1Ju8CETWTqy7oRwbScjBtJGBpqhB\"\n\t],\n\t\"AdviseOnlyTrustedHubs\": true,\n\t\"AdviseOnlyTrustedHomeHubs\": true,\n\t\"AdviseOnlyTrustedDestinationHubs\": true\n}\n"
  },
  {
    "path": "spn/testing/simple/join.sh",
    "content": "#!/bin/bash\n\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\n\nrealpath() {\n    path=`eval echo \"$1\"`\n    folder=$(dirname \"$path\")\n    echo $(cd \"$folder\"; pwd)/$(basename \"$path\"); \n}\n\nleftover=$(docker ps -a | grep spn-test-simple-me | cut -d\" \" -f1)\nif [[ $leftover != \"\" ]]; then\n  docker stop $leftover\n  docker rm $leftover\nfi\n\nif [[ ! -f \"../../../cmds/hub/hub\" ]]; then\n  echo \"please build the hub cmd using cmds/hub/build\"\n  exit 1\nfi\n\nSPN_TEST_BIN=\"$(realpath ../../../cmds/hub/hub)\"\nSPN_TEST_DATA_DIR=\"$(realpath ./testdata)\"\nif [[ ! -d \"$SPN_TEST_DATA_DIR\" ]]; then\n  mkdir \"$SPN_TEST_DATA_DIR\"\nfi\nSPN_TEST_SHARED_DATA_DIR=\"$(realpath ./testdata/shared)\"\nif [[ ! -d \"$SPN_TEST_SHARED_DATA_DIR\" ]]; then\n  mkdir \"$SPN_TEST_SHARED_DATA_DIR\"\nfi\n\ndocker run -ti \\\n--name spn-test-simple-me \\\n--hostname me \\\n--network spn-test-simple_default \\\n-v $SPN_TEST_BIN:/opt/hub_me:ro \\\n-v $SPN_TEST_DATA_DIR/me:/opt/data \\\n-v $SPN_TEST_SHARED_DATA_DIR:/opt/shared \\\n--entrypoint /opt/hub_me \\\ntoolset.safing.network/dev \\\n--devmode --api-address 0.0.0.0:8081 \\\n--data /opt/data -log trace --spn-map test --bootstrap-file /opt/shared/bootstrap.dsd\n"
  },
  {
    "path": "spn/testing/simple/reset-databases.sh",
    "content": "#!/bin/bash\n\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\n\nrm -rf testdata/me/*\nrm -rf testdata/shared/*\nrm -rf testdata/hub*/databases\n"
  },
  {
    "path": "spn/testing/simple/run.sh",
    "content": "#!/bin/bash\n\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\n\nrealpath() {\n    path=`eval echo \"$1\"`\n    folder=$(dirname \"$path\")\n    echo $(cd \"$folder\"; pwd)/$(basename \"$path\"); \n}\n\nleftovers=$(docker ps -a | grep spn-test-simple | cut -d\" \" -f1)\nif [[ $leftovers != \"\" ]]; then\n  docker stop $leftovers\n  docker rm $leftovers\nfi\n\nif [[ ! -f \"../../../cmds/hub/hub\" ]]; then\n  echo \"please build the hub cmd using cmds/hub/build\"\n  exit 1\nfi\n\n# Create variables.\nSPN_TEST_BIN=\"$(realpath ../../../cmds/hub/hub)\"\nSPN_TEST_DATA_DIR=\"$(realpath ./testdata)\"\nif [[ ! -d \"$SPN_TEST_DATA_DIR\" ]]; then\n  mkdir \"$SPN_TEST_DATA_DIR\"\nfi\nSPN_TEST_SHARED_DATA_DIR=\"$(realpath ./testdata/shared)\"\nif [[ ! -d \"$SPN_TEST_SHARED_DATA_DIR\" ]]; then\n  mkdir \"$SPN_TEST_SHARED_DATA_DIR\"\nfi\n\n# Check if there is an old binary for testing.\nSPN_TEST_OLD_BIN=$SPN_TEST_BIN\nif [[ -f \"./testdata/old-hub\" ]]; then\n  SPN_TEST_OLD_BIN=\"$(realpath ./testdata/old-hub)\"\n  echo \"WARNING: running in hybrid mode with old version at $SPN_TEST_OLD_BIN\"\nfi\n\n# Export variables\nexport SPN_TEST_BIN\nexport SPN_TEST_OLD_BIN\nexport SPN_TEST_DATA_DIR\nexport SPN_TEST_SHARED_DATA_DIR\n\n# Copy files.\ncp config-template.json ./testdata/shared/config-template.json\ncp entrypoint.sh ./testdata/shared/entrypoint.sh\nchmod 555 ./testdata/shared/entrypoint.sh\n\n# Run!\ndocker compose -p spn-test-simple up --remove-orphans\n"
  },
  {
    "path": "spn/testing/simple/stop.sh",
    "content": "#!/bin/bash\n\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\n\ndocker compose -p spn-test-simple stop\ndocker compose -p spn-test-simple rm\n\noldnet=$(docker network ls | grep spn-test-simple | cut -d\" \" -f1)\nif [[ $oldnet != \"\" ]]; then\n  docker network rm $oldnet\nfi\n\nif [[ -d \"data/shared\" ]]; then\n  rm -r \"data/shared\"\nfi\n"
  },
  {
    "path": "spn/tools/Dockerfile",
    "content": "FROM alpine as builder\n\n# Ensure ca-certficates are up to date\n# RUN update-ca-certificates\n\n# Download and verify spn-hub binary.\nRUN mkdir /init\nRUN wget https://updates.safing.io/latest/linux_amd64/hub/spn-hub -O /init/spn-hub\nCOPY start-checksum.txt /init/start-checksum\nRUN cd /init && sha256sum -c /init/start-checksum\nRUN chmod 555 /init/spn-hub\n\n# Use minimal image as base.\nFROM alpine\n\n# Copy the static executable.\nCOPY --from=builder /init/spn-hub /init/spn-hub\n\n# Copy the init script\nCOPY container-init.sh /init.sh\n\n# Run the hub.\nENTRYPOINT [\"/init.sh\"]\n"
  },
  {
    "path": "spn/tools/container-init.sh",
    "content": "#!/bin/sh\n\nDATA=\"/data\"\nSTART=\"/data/spn-hub\"\nINIT_START=\"/init/spn-hub\"\n\n# Set safe shell options.\nset -euf -o pipefail\n\n# Check if data dir is mounted.\nif [ ! -d $DATA ]; then\n  echo \"Nothing mounted at $DATA, aborting.\"\n  exit 1\nfi\n\n# Copy init start to correct location, if not available.\nif [ ! -f $START ]; then\n  cp $INIT_START $START\nfi\n\n\n# Remove PID file, which could have been left after a crash.\nrm -f $DATA/hub-lock.pid\n\n# Always start the SPN Hub with the updated main start binary.\necho \"running: $START\"\n$START -- $@\n"
  },
  {
    "path": "spn/tools/install.sh",
    "content": "#!/bin/sh\n#\n# This script should be run via curl as root:\n#   sudo sh -c \"$(curl -fsSL https://raw.githubusercontent.com/safing/portmaster/master/spn/tools/install-spn.sh)\"\n# or wget\n#   sudo sh -c \"$(wget -qO- https://raw.githubusercontent.com/safing/portmaster/master/spn/tools/install-spn.sh)\"\n#\n# As an alternative, you can first download the install script and run it afterwards:\n#   wget https://raw.githubusercontent.com/safing/portmaster/master/spn/tools/install-spn.sh\n#   sudo sh ./install.sh\n#\n#\nset -e\n\nARCH=\nINSTALLDIR=\nPMSTART=\nENABLENOW=\nINSTALLSYSTEMD=\nSYSTEMDINSTALLPATH=\n\napply_defaults() {\n    ARCH=${ARCH:-amd64}\n    INSTALLDIR=${INSTALLDIR:-/opt/safing/spn}\n    PMSTART=${PMSTART:-https://updates.safing.io/latest/linux_${ARCH}/start/portmaster-start}\n    SYSTEMDINSTALLPATH=${SYSTEMDINSTALLPATH:-/etc/systemd/system/spn.service}\n\n    if command_exists systemctl; then\n        INSTALLSYSTEMD=${INSTALLSYSTEMD:-yes}\n        ENABLENOW=${ENABLENOW:-yes}\n    else\n        INSTALLSYSTEMD=${INSTALLSYSTEMD:-no}\n        ENABLENOW=${ENABLENOW:-no}\n    fi\n\n    # The hostname may be freshly set, ensure the ENV variable is correct.\n    export HOSTNAME=$(hostname)\n}\n\ncommand_exists() {\n    command -v \"$@\" >/dev/null 2>&1\n}\n\nsetup_tty() {\n    if [ -t 0 ]; then\n        interactive=yes\n    fi\n\n\tif [ -t 1 ]; then\n\t\tRED=$(printf '\\033[31m')\n\t\tGREEN=$(printf '\\033[32m')\n\t\tYELLOW=$(printf '\\033[33m')\n\t\tBLUE=$(printf '\\033[34m')\n\t\tBOLD=$(printf '\\033[1m')\n\t\tRESET=$(printf '\\033[m')\n\telse\n\t\tRED=\"\"\n\t\tGREEN=\"\"\n\t\tYELLOW=\"\"\n\t\tBLUE=\"\"\n\t\tBOLD=\"\"\n\t\tRESET=\"\"\n\tfi\n}\n\nlog() {\n    echo ${GREEN}${BOLD}\"-> \"${RESET}\"$@\" >&2\n}\n\nerror() {\n    echo ${RED}\"Error: $@\"${RESET} >&2\n}\n\nwarn() {\n    echo ${YELLOW}\"warn: $@\"${RESET} >&2\n}\n\nrun_systemctl() {\n    systemctl $@ >/dev/null 2>&1 \n}\n\ndownload_file() {\n    local src=$1\n    local dest=$2\n\n    if command_exists curl; then\n        curl --silent --fail --show-error --location --output $dest $src\n    elif command_exists wget; then\n        wget --quiet -O $dest $src\n    else\n        error \"No suitable download command found, either curl or wget must be installed\"\n        exit 1\n    fi\n}\n\nensure_install_dir() {\n    log \"Creating ${INSTALLDIR}\"\n    mkdir -p ${INSTALLDIR}\n}\n\ndownload_pmstart() {\n    log \"Downloading portmaster-start ...\"\n    local dest=\"${INSTALLDIR}/portmaster-start\"\n    if [ -f \"${dest}\" ]; then\n        warn \"Overwriting existing portmaster-start at ${dest}\"\n    fi\n\n    download_file ${PMSTART} ${dest}\n\n    log \"Changing permissions\"\n    chmod a+x ${dest}\n}\n\ndownload_updates() {\n    log \"Downloading updates ...\"\n    ${INSTALLDIR}/portmaster-start --data=${INSTALLDIR} update\n}\n\nsetup_systemd() {\n    log \"Installing systemd service unit ...\"\n    if [ ! \"${INSTALLSYSTEMD}\" = \"yes\" ]; then\n        warn \"Skipping setup of systemd service unit\"\n        echo \"To launch the hub, execute the following as root:\"\n        echo \"\"\n        echo \"${INSTALLDIR}/portmaster-start --data ${INSTALLDIR} hub\"\n        echo \"\"\n        return\n    fi\n\n    if [ -f \"${SYSTEMDINSTALLPATH}\" ]; then\n        warn \"Overwriting existing unit path\"\n    fi\n\n    cat >${SYSTEMDINSTALLPATH} <<EOT\n[Unit]\nDescription=Safing Privacy Network Hub\nWants=nss-lookup.target\nConflicts=shutdown.target\nBefore=shutdown.target\n\n[Service]\nType=simple\nRestart=on-failure\nRestartSec=5\nLimitNOFILE=infinity\nEnvironment=LOGLEVEL=warning\nEnvironment=SPN_ARGS=\nEnvironmentFile=-/etc/default/spn\nExecStart=${INSTALLDIR}/portmaster-start --data ${INSTALLDIR} hub -- --log \\$LOGLEVEL \\$SPN_ARGS\n\n[Install]\nWantedBy=multi-user.target\nEOT\n\n    log \"Reloading systemd unit files\"\n    run_systemctl daemon-reload\n\n    if run_systemctl is-active spn ||\n       run_systemctl is-failed spn; then\n        log \"Restarting SPN hub\"\n        run_systemctl restart spn.service\n    fi\n\n    # TODO(ppacher): allow disabling enable\n    if ! run_systemctl is-enabled spn ; then\n        if [ \"${ENABLENOW}\" = \"yes\" ]; then\n            log \"Enabling and starting SPN.\"\n            run_systemctl enable --now spn.service || exit 1\n\n            log \"Watch logs using: journalctl -fu spn.service\"\n        else\n            log \"Enabling SPN\"\n            run_systemctl enable spn.service || exit 1\n        fi\n    fi\n\n}\n\nask_config() {\n    if [ \"${HOSTNAME}\" = \"\" ]; then\n        log \"Please enter hostname:\"\n        read -p \"> \" HOSTNAME\n    fi\n    if [ \"${METRICS_COMMENT}\" = \"\" ]; then\n        log \"Please enter metrics comment:\"\n        read -p \"> \" METRICS_COMMENT\n    fi\n}\n\nwrite_config_file() {\n    cat >${1} <<EOT\n{\n  \"core\": {\n    \"metrics\": {\n      \"instance\": \"$HOSTNAME\",\n      \"comment\": \"$METRICS_COMMENT\",\n      \"push\": \"$PUSHMETRICS\"\n    }\n  },\n  \"spn\": {\n    \"publicHub\": {\n      \"name\": \"$HOSTNAME\"\n    }\n  }\n}\nEOT\n}\n\nconfirm_config() {\n    log \"Installation configuration:\"\n    echo \"\"\n    echo \"   Architecture: ${BOLD}${ARCH}${RESET}\"\n    echo \"   Download-URL: ${BOLD}${PMSTART}${RESET}\"\n    echo \"     Target Dir: ${BOLD}${INSTALLDIR}${RESET}\"\n    echo \"Install systemd: ${BOLD}${INSTALLSYSTEMD}${RESET}\"\n    echo \"      Unit path: ${BOLD}${SYSTEMDINSTALLPATH}${RESET}\"\n    echo \"      Start Now: ${BOLD}${ENABLENOW}${RESET}\"\n    echo \"\"\n    echo \"         Config:\"\n    tmpfile=$(mktemp)\n    write_config_file $tmpfile\n    cat $tmpfile\n    echo \"\"\n    echo \"\"\n\n    if [ ! -z \"${interactive}\" ]\n    then\n        read -p \"Continue (Y/n)? \" ans\n        case \"$ans\" in\n            \"\" | \"y\" | \"Y\")\n                echo \"\"\n                ;;\n            **)\n                error \"User aborted\"\n                exit 1\n        esac\n    fi\n}\n\nprint_help() {\n    cat <<EOT\nUsage: $0 [OPTIONS...]\n\n${BOLD}Options:${RESET}\n    ${GREEN}-y, --unattended${RESET}           Don't ask for confirmation.\n    ${GREEN}-n, --no-start${RESET}             Do not immediately start SPN hub.\n    ${GREEN}-t, --target PATH${RESET}          Configure the installation directory.\n    ${GREEN}-h, --help${RESET}                 Display this help text\n    ${GREEN}-a, --arch${RESET}                 Configure the binary architecture.\n    ${GREEN}-u, --url URL${RESET}              Set download URL for portmaster start.\n    ${GREEN}-S, --no-systemd${RESET}           Do not install systemd service unit.\n    ${GREEN}-s, --service-path PATH${RESET}    Location for the systemd unit file.\nEOT\n}\n\nmain() {\n    setup_tty\n\n    # Parse arguments\n    while [ $# -gt 0 ]\n    do\n        case $1 in\n            --unattended | -y)\n                interactive=\"\"\n                ;;\n            --no-start | -n)\n                ENABLENOW=\"no\"\n                ;;\n            --target | -t)\n                INSTALLDIR=$2\n                shift\n                ;;\n            --help | -h)\n                print_help\n                exit 1 ;;\n            --arch | -a)\n                ARCH=$2\n                shift\n                ;;\n            --url | -u)\n                PMSTART=$2\n                shift\n                ;;\n            --no-systemd | -S)\n                INSTALLSYSTEMD=no\n                ENABLENOW=no\n                ;;\n            --service-path | -s)\n                SYSTEMDINSTALLPATH=$2\n                shift\n                ;;\n            *)\n                error \"Unknown flag $1\"\n                exit 1\n                ;;\n        esac\n        shift\n    done\n\n    cat <<EOT\n${BLUE}${BOLD}\n          ▄▄▄▄  ▄▄▄▄▄  ▄▄   ▄\n         █▀   ▀ █   ▀█ █▀▄  █\n         ▀█▄▄▄  █▄▄▄█▀ █ █▄ █\n             ▀█ █      █  █ █\n         ▀▄▄▄█▀ █      █   ██\n        ${GREEN}Safing Privacy Network\n${RESET}\nEOT\n\n    # prepare config\n    apply_defaults\n    ask_config\n    confirm_config\n\n    # Setup hub\n    ensure_install_dir\n    download_pmstart\n    download_updates\n    write_config_file \"${INSTALLDIR}/config.json\"\n\n    # setup systemd\n    setup_systemd\n}\n\nmain \"$@\""
  },
  {
    "path": "spn/tools/install.v2.sh",
    "content": "#!/bin/sh\n#\n# This script should be run via curl as root:\n#   sudo sh -c \"$(curl -fsSL https://raw.githubusercontent.com/safing/portmaster/master/spn/tools/install-spn.sh)\"\n# or wget\n#   sudo sh -c \"$(wget -qO- https://raw.githubusercontent.com/safing/portmaster/master/spn/tools/install-spn.sh)\"\n#\n# As an alternative, you can first download the install script and run it afterwards:\n#   wget https://raw.githubusercontent.com/safing/portmaster/master/spn/tools/install-spn.sh\n#   sudo sh ./install.sh\n#\n#\nset -e\n\nARCH=\nINSTALLDIR=\nSPNBINARY=\nENABLENOW=\nINSTALLSYSTEMD=\nSYSTEMDINSTALLPATH=\nLOGDIR=\n\napply_defaults() {\n    ARCH=${ARCH:-amd64}\n    INSTALLDIR=${INSTALLDIR:-/opt/safing/spn}\n    SPNBINARY=${SPNBINARY:-https://updates.safing.io/latest/linux_${ARCH}/hub/spn-hub}\n    SYSTEMDINSTALLPATH=${SYSTEMDINSTALLPATH:-/etc/systemd/system/spn.service}\n    LOGDIR=${LOGDIR:-/opt/safing/spn}\n\n    if command_exists systemctl; then\n        INSTALLSYSTEMD=${INSTALLSYSTEMD:-yes}\n        ENABLENOW=${ENABLENOW:-yes}\n    else\n        INSTALLSYSTEMD=${INSTALLSYSTEMD:-no}\n        ENABLENOW=${ENABLENOW:-no}\n    fi\n\n    # The hostname may be freshly set, ensure the ENV variable is correct.\n    export HOSTNAME=$(hostname)\n}\n\ncommand_exists() {\n    command -v \"$@\" >/dev/null 2>&1\n}\n\nsetup_tty() {\n    if [ -t 0 ]; then\n        interactive=yes\n    fi\n\n\tif [ -t 1 ]; then\n\t\tRED=$(printf '\\033[31m')\n\t\tGREEN=$(printf '\\033[32m')\n\t\tYELLOW=$(printf '\\033[33m')\n\t\tBLUE=$(printf '\\033[34m')\n\t\tBOLD=$(printf '\\033[1m')\n\t\tRESET=$(printf '\\033[m')\n\telse\n\t\tRED=\"\"\n\t\tGREEN=\"\"\n\t\tYELLOW=\"\"\n\t\tBLUE=\"\"\n\t\tBOLD=\"\"\n\t\tRESET=\"\"\n\tfi\n}\n\nlog() {\n    echo ${GREEN}${BOLD}\"-> \"${RESET}\"$@\" >&2\n}\n\nerror() {\n    echo ${RED}\"Error: $@\"${RESET} >&2\n}\n\nwarn() {\n    echo ${YELLOW}\"warn: $@\"${RESET} >&2\n}\n\nrun_systemctl() {\n    systemctl $@ >/dev/null 2>&1 \n}\n\ndownload_file() {\n    local src=$1\n    local dest=$2\n\n    if command_exists curl; then\n        curl --silent --fail --show-error --location --output $dest $src\n    elif command_exists wget; then\n        wget --quiet -O $dest $src\n    else\n        error \"No suitable download command found, either curl or wget must be installed\"\n        exit 1\n    fi\n}\n\nensure_install_dir() {\n    log \"Creating ${INSTALLDIR}\"\n    mkdir -p ${INSTALLDIR}\n}\n\ndownload_spnbinary() {\n    log \"Downloading SPN binary ...\"\n    local dest=\"${INSTALLDIR}/hub\"\n    if [ -f \"${dest}\" ]; then\n        warn \"Overwriting existing hub at ${dest}\"\n    fi\n\n    download_file ${SPNBINARY} ${dest}\n\n    log \"Changing permissions\"\n    chmod a+x ${dest}\n}\n\nsetup_systemd() {\n    log \"Installing systemd service unit ...\"\n    if [ ! \"${INSTALLSYSTEMD}\" = \"yes\" ]; then\n        warn \"Skipping setup of systemd service unit\"\n        echo \"To launch the hub, execute the following as root:\"\n        echo \"\"\n        echo \"${INSTALLDIR}/hub --data-dir ${INSTALLDIR}\"\n        echo \"\"\n        return\n    fi\n\n    if [ -f \"${SYSTEMDINSTALLPATH}\" ]; then\n        warn \"Overwriting existing unit path\"\n    fi\n\n    cat >${SYSTEMDINSTALLPATH} <<EOT\n[Unit]\nDescription=Safing Privacy Network Hub\nWants=nss-lookup.target\nConflicts=shutdown.target\nBefore=shutdown.target\n\n[Service]\nType=simple\nRestart=on-failure\nRestartSec=5\nLimitNOFILE=infinity\nEnvironment=LOGLEVEL=warning\nEnvironment=SPN_ARGS=\nEnvironmentFile=-/etc/default/spn\nExecStart=${INSTALLDIR}/hub --data-dir ${INSTALLDIR} --log \\$LOGLEVEL --log-dir ${LOGDIR} \\$SPN_ARGS\n\n[Install]\nWantedBy=multi-user.target\nEOT\n\n    log \"Reloading systemd unit files\"\n    run_systemctl daemon-reload\n\n    if run_systemctl is-active spn ||\n       run_systemctl is-failed spn; then\n        log \"Restarting SPN hub\"\n        run_systemctl restart spn.service\n    fi\n\n    # TODO(ppacher): allow disabling enable\n    if ! run_systemctl is-enabled spn ; then\n        if [ \"${ENABLENOW}\" = \"yes\" ]; then\n            log \"Enabling and starting SPN.\"\n            run_systemctl enable --now spn.service || exit 1\n\n            log \"Watch logs using: journalctl -fu spn.service\"\n        else\n            log \"Enabling SPN\"\n            run_systemctl enable spn.service || exit 1\n        fi\n    fi\n\n}\n\nask_config() {\n    if [ \"${HOSTNAME}\" = \"\" ]; then\n        log \"Please enter hostname:\"\n        read -p \"> \" HOSTNAME\n    fi\n    if [ \"${METRICS_COMMENT}\" = \"\" ]; then\n        log \"Please enter metrics comment:\"\n        read -p \"> \" METRICS_COMMENT\n    fi\n}\n\nwrite_config_file() {\n    cat >${1} <<EOT\n{\n  \"core\": {\n    \"metrics\": {\n      \"instance\": \"$HOSTNAME\",\n      \"comment\": \"$METRICS_COMMENT\",\n      \"push\": \"$PUSHMETRICS\"\n    }\n  },\n  \"spn\": {\n    \"publicHub\": {\n      \"name\": \"$HOSTNAME\"\n    }\n  }\n}\nEOT\n}\n\nconfirm_config() {\n    log \"Installation configuration:\"\n    echo \"\"\n    echo \"   Architecture: ${BOLD}${ARCH}${RESET}\"\n    echo \"   Download-URL: ${BOLD}${SPNBINARY}${RESET}\"\n    echo \"     Target Dir: ${BOLD}${INSTALLDIR}${RESET}\"\n    echo \"Install systemd: ${BOLD}${INSTALLSYSTEMD}${RESET}\"\n    echo \"      Unit path: ${BOLD}${SYSTEMDINSTALLPATH}${RESET}\"\n    echo \"      Start Now: ${BOLD}${ENABLENOW}${RESET}\"\n    echo \"\"\n    echo \"         Config:\"\n    tmpfile=$(mktemp)\n    write_config_file $tmpfile\n    cat $tmpfile\n    echo \"\"\n    echo \"\"\n\n    if [ ! -z \"${interactive}\" ]\n    then\n        read -p \"Continue (Y/n)? \" ans\n        case \"$ans\" in\n            \"\" | \"y\" | \"Y\")\n                echo \"\"\n                ;;\n            **)\n                error \"User aborted\"\n                exit 1\n        esac\n    fi\n}\n\nprint_help() {\n    cat <<EOT\nUsage: $0 [OPTIONS...]\n\n${BOLD}Options:${RESET}\n    ${GREEN}-y, --unattended${RESET}           Don't ask for confirmation.\n    ${GREEN}-n, --no-start${RESET}             Do not immediately start SPN hub.\n    ${GREEN}-t, --target PATH${RESET}          Configure the installation directory.\n    ${GREEN}-h, --help${RESET}                 Display this help text\n    ${GREEN}-a, --arch${RESET}                 Configure the binary architecture.\n    ${GREEN}-u, --url URL${RESET}              Set download URL for spn-hub.\n    ${GREEN}-S, --no-systemd${RESET}           Do not install systemd service unit.\n    ${GREEN}-s, --service-path PATH${RESET}    Location for the systemd unit file.\nEOT\n}\n\nmain() {\n    setup_tty\n\n    # Parse arguments\n    while [ $# -gt 0 ]\n    do\n        case $1 in\n            --unattended | -y)\n                interactive=\"\"\n                ;;\n            --no-start | -n)\n                ENABLENOW=\"no\"\n                ;;\n            --target | -t)\n                INSTALLDIR=$2\n                shift\n                ;;\n            --help | -h)\n                print_help\n                exit 1 ;;\n            --arch | -a)\n                ARCH=$2\n                shift\n                ;;\n            --url | -u)\n                SPNBINARY=$2\n                shift\n                ;;\n            --no-systemd | -S)\n                INSTALLSYSTEMD=no\n                ENABLENOW=no\n                ;;\n            --service-path | -s)\n                SYSTEMDINSTALLPATH=$2\n                shift\n                ;;\n            *)\n                error \"Unknown flag $1\"\n                exit 1\n                ;;\n        esac\n        shift\n    done\n\n    cat <<EOT\n${BLUE}${BOLD}\n          ▄▄▄▄  ▄▄▄▄▄  ▄▄   ▄\n         █▀   ▀ █   ▀█ █▀▄  █\n         ▀█▄▄▄  █▄▄▄█▀ █ █▄ █\n             ▀█ █      █  █ █\n         ▀▄▄▄█▀ █      █   ██\n        ${GREEN}Safing Privacy Network\n${RESET}\nEOT\n\n    # prepare config\n    apply_defaults\n    ask_config\n    confirm_config\n\n    # Setup hub\n    ensure_install_dir\n    download_spnbinary\n    write_config_file \"${INSTALLDIR}/config.json\"\n\n    # setup systemd\n    setup_systemd\n}\n\nmain \"$@\"\n"
  },
  {
    "path": "spn/tools/start-checksum.txt",
    "content": "da0ca5ca57f3f5e80a7cb61a8e0ad9b1423051fc12e518b0539c7c69b7a68ee8  ./spn-hub\n"
  },
  {
    "path": "spn/tools/sysctl.conf",
    "content": "## Kernel Optimizations for few very high bandwidth connections.\n\n# Quickly with this:\n# curl -fsSL https://updates.safing.io/internal/sysctl.conf > /etc/sysctl.d/9999-spn-network-optimizing.conf\n# cat /etc/sysctl.d/9999-spn-network-optimizing.conf\n# sysctl -p /etc/sysctl.d/9999-spn-network-optimizing.conf\n\n# Provide adequate buffer memory.\n# net.ipv4.tcp_mem is in 4096-byte pages.\nnet.core.rmem_max = 1073741824\nnet.core.wmem_max = 1073741824\nnet.core.rmem_default = 16777216\nnet.core.wmem_default = 16777216\nnet.ipv4.tcp_rmem = 4096 16777216 1073741824\nnet.ipv4.tcp_wmem = 4096 16777216 1073741824\nnet.ipv4.tcp_mem = 4194304 8388608 16777216\nnet.ipv4.udp_rmem_min = 16777216\nnet.ipv4.udp_wmem_min = 16777216\n\n# Enable TCP window scaling.\nnet.ipv4.tcp_window_scaling = 1\n\n# Increase the length of the processor input queue\nnet.core.netdev_max_backlog = 100000\nnet.core.netdev_budget = 1000\nnet.core.netdev_budget_usecs = 10000\n\n# Set better congestion control.\nnet.ipv4.tcp_congestion_control = htcp\n\n# Turn off fancy stuff for more stability.\nnet.ipv4.tcp_sack = 0\nnet.ipv4.tcp_dsack = 0\nnet.ipv4.tcp_fack = 0\nnet.ipv4.tcp_timestamps = 0\n\n# Max reorders before slow start.\nnet.ipv4.tcp_reordering = 3\n\n# Prefer low latency to higher throughput.\n# Disables IPv4 TCP prequeue processing.\nnet.ipv4.tcp_low_latency = 1\n\n# Don't start slow.\nnet.ipv4.tcp_slow_start_after_idle = 0 \n"
  },
  {
    "path": "spn/unit/doc.go",
    "content": "// Package unit provides a \"work unit\" scheduling system for handling data sets that traverse multiple workers / goroutines.\n// The aim is to bind priority to a data set instead of a goroutine and split resources fairly among requests.\n//\n// Every \"work\" Unit is assigned an ever increasing ID and can be marked as \"paused\" or \"high priority\".\n// The Scheduler always gives a clearance up to a certain ID. All units below this ID may be processed.\n// High priority Units may always be processed.\n//\n// The Scheduler works with short slots and measures how many Units were finished in a slot.\n// The \"slot pace\" holds an indication of the current Unit finishing speed per slot. It is only changed slowly (but boosts if too far away) in order to keep stabilize the system.\n// The Scheduler then calculates the next unit ID limit to give clearance to for the next slot:\n//\n//\t\"finished units\" + \"slot pace\" + \"paused units\" - \"fraction of high priority units\"\npackage unit\n"
  },
  {
    "path": "spn/unit/scheduler.go",
    "content": "package unit\n\nimport (\n\t\"errors\"\n\t\"math\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nconst (\n\tdefaultSlotDuration = 10 * time.Millisecond // 100 slots per second\n\tdefaultMinSlotPace  = 100                   // 10 000 pps\n\n\tdefaultWorkSlotPercentage      = 0.7  // 70%\n\tdefaultSlotChangeRatePerStreak = 0.02 // 2%\n\n\tdefaultStatCycleDuration = 1 * time.Minute\n)\n\n// Scheduler creates and schedules units.\n// Must be created using NewScheduler().\ntype Scheduler struct { //nolint:maligned\n\t// Configuration.\n\tconfig SchedulerConfig\n\n\t// Units IDs Limit / Thresholds.\n\n\t// currentUnitID holds the last assigned Unit ID.\n\tcurrentUnitID atomic.Int64\n\t// clearanceUpTo holds the current threshold up to which Unit ID Units may be processed.\n\tclearanceUpTo atomic.Int64\n\t// slotPace holds the current pace. This is the base value for clearance\n\t// calculation, not the value of the current cleared Units itself.\n\tslotPace atomic.Int64\n\t// finished holds the amount of units that were finished within the current slot.\n\tfinished atomic.Int64\n\n\t// Slot management.\n\tslotSignalA      chan struct{}\n\tslotSignalB      chan struct{}\n\tslotSignalSwitch bool\n\tslotSignalsLock  sync.RWMutex\n\n\tstopping     abool.AtomicBool\n\tunitDebugger *UnitDebugger\n\n\t// Stats.\n\tstats struct {\n\t\t// Working Values.\n\t\tprogress struct {\n\t\t\tmaxPace           atomic.Int64\n\t\t\tmaxLeveledPace    atomic.Int64\n\t\t\tavgPaceSum        atomic.Int64\n\t\t\tavgPaceCnt        atomic.Int64\n\t\t\tavgUnitLifeSum    atomic.Int64\n\t\t\tavgUnitLifeCnt    atomic.Int64\n\t\t\tavgWorkSlotSum    atomic.Int64\n\t\t\tavgWorkSlotCnt    atomic.Int64\n\t\t\tavgCatchUpSlotSum atomic.Int64\n\t\t\tavgCatchUpSlotCnt atomic.Int64\n\t\t}\n\n\t\t// Calculated Values.\n\t\tcurrent struct {\n\t\t\tmaxPace        atomic.Int64\n\t\t\tmaxLeveledPace atomic.Int64\n\t\t\tavgPace        atomic.Int64\n\t\t\tavgUnitLife    atomic.Int64\n\t\t\tavgWorkSlot    atomic.Int64\n\t\t\tavgCatchUpSlot atomic.Int64\n\t\t}\n\t}\n}\n\n// SchedulerConfig holds scheduler configuration.\ntype SchedulerConfig struct {\n\t// SlotDuration defines the duration of one slot.\n\tSlotDuration time.Duration\n\n\t// MinSlotPace defines the minimum slot pace.\n\t// The slot pace will never fall below this value.\n\tMinSlotPace int64\n\n\t// WorkSlotPercentage defines the how much of a slot should be scheduled with work.\n\t// The remainder is for catching up and breathing room for other tasks.\n\t// Must be between 55% (0.55) and 95% (0.95).\n\t// The default value is 0.7 (70%).\n\tWorkSlotPercentage float64\n\n\t// SlotChangeRatePerStreak defines how many percent (0-1) the slot pace\n\t// should change per streak.\n\t// Is enforced to be able to change the minimum slot pace by at least 1.\n\t// The default value is 0.02 (2%).\n\tSlotChangeRatePerStreak float64\n\n\t// StatCycleDuration defines how often stats are calculated.\n\t// The default value is 1 minute.\n\tStatCycleDuration time.Duration\n}\n\n// NewScheduler returns a new scheduler.\nfunc NewScheduler(config *SchedulerConfig) *Scheduler {\n\t// Fallback to empty config if none is given.\n\tif config == nil {\n\t\tconfig = &SchedulerConfig{}\n\t}\n\n\t// Create new scheduler.\n\ts := &Scheduler{\n\t\tconfig:      *config,\n\t\tslotSignalA: make(chan struct{}),\n\t\tslotSignalB: make(chan struct{}),\n\t}\n\n\t// Fill in defaults.\n\tif s.config.SlotDuration == 0 {\n\t\ts.config.SlotDuration = defaultSlotDuration\n\t}\n\tif s.config.MinSlotPace == 0 {\n\t\ts.config.MinSlotPace = defaultMinSlotPace\n\t}\n\tif s.config.WorkSlotPercentage == 0 {\n\t\ts.config.WorkSlotPercentage = defaultWorkSlotPercentage\n\t}\n\tif s.config.SlotChangeRatePerStreak == 0 {\n\t\ts.config.SlotChangeRatePerStreak = defaultSlotChangeRatePerStreak\n\t}\n\tif s.config.StatCycleDuration == 0 {\n\t\ts.config.StatCycleDuration = defaultStatCycleDuration\n\t}\n\n\t// Check boundaries of WorkSlotPercentage.\n\tswitch {\n\tcase s.config.WorkSlotPercentage < 0.55:\n\t\ts.config.WorkSlotPercentage = 0.55\n\tcase s.config.WorkSlotPercentage > 0.95:\n\t\ts.config.WorkSlotPercentage = 0.95\n\t}\n\n\t// The slot change rate must be able to change the slot pace by at least 1.\n\tif s.config.SlotChangeRatePerStreak < (1 / float64(s.config.MinSlotPace)) {\n\t\ts.config.SlotChangeRatePerStreak = (1 / float64(s.config.MinSlotPace))\n\n\t\t// Debug logging:\n\t\t// fmt.Printf(\"--- increased SlotChangeRatePerStreak to %f\\n\", s.config.SlotChangeRatePerStreak)\n\t}\n\n\t// Initialize scheduler fields.\n\ts.clearanceUpTo.Store(s.config.MinSlotPace)\n\ts.slotPace.Store(s.config.MinSlotPace)\n\n\treturn s\n}\n\nfunc (s *Scheduler) nextSlotSignal() chan struct{} {\n\ts.slotSignalsLock.RLock()\n\tdefer s.slotSignalsLock.RUnlock()\n\n\tif s.slotSignalSwitch {\n\t\treturn s.slotSignalA\n\t}\n\treturn s.slotSignalB\n}\n\nfunc (s *Scheduler) announceNextSlot() {\n\ts.slotSignalsLock.Lock()\n\tdefer s.slotSignalsLock.Unlock()\n\n\t// Close new slot signal and refresh previous one.\n\tif s.slotSignalSwitch {\n\t\tclose(s.slotSignalA)\n\t\ts.slotSignalB = make(chan struct{})\n\t} else {\n\t\tclose(s.slotSignalB)\n\t\ts.slotSignalA = make(chan struct{})\n\t}\n\n\t// Switch to next slot.\n\ts.slotSignalSwitch = !s.slotSignalSwitch\n}\n\n// SlotScheduler manages the slot and schedules units.\n// Must only be started once.\nfunc (s *Scheduler) SlotScheduler(ctx *mgr.WorkerCtx) error {\n\t// Start slot ticker.\n\tticker := time.NewTicker(s.config.SlotDuration / 2)\n\tdefer ticker.Stop()\n\n\t// Give clearance to all when stopping.\n\tdefer s.clearanceUpTo.Store(math.MaxInt64 - math.MaxInt32)\n\n\tvar (\n\t\thalfSlotID        uint64\n\t\thalfSlotStartedAt = time.Now()\n\t\thalfSlotEndedAt   time.Time\n\t\thalfSlotDuration  = float64(s.config.SlotDuration / 2)\n\n\t\tincreaseStreak float64\n\t\tdecreaseStreak float64\n\t\toneStreaks     int\n\n\t\tcycleStatsAt = uint64(s.config.StatCycleDuration / (s.config.SlotDuration / 2))\n\t)\n\n\tfor range ticker.C {\n\t\thalfSlotEndedAt = time.Now()\n\n\t\tswitch {\n\t\tcase halfSlotID%2 == 0:\n\n\t\t\t// First Half-Slot: Work Slot\n\n\t\t\t// Calculate time taken in previous slot.\n\t\t\tcatchUpSlotDuration := halfSlotEndedAt.Sub(halfSlotStartedAt).Nanoseconds()\n\n\t\t\t// Add current slot duration to avg calculation.\n\t\t\ts.stats.progress.avgCatchUpSlotCnt.Add(1)\n\t\t\tif s.stats.progress.avgCatchUpSlotSum.Add(catchUpSlotDuration) < 0 {\n\t\t\t\t// Reset if we wrap.\n\t\t\t\ts.stats.progress.avgCatchUpSlotCnt.Store(1)\n\t\t\t\ts.stats.progress.avgCatchUpSlotSum.Store(catchUpSlotDuration)\n\t\t\t}\n\n\t\t\t// Reset slot counters.\n\t\t\ts.finished.Store(0)\n\n\t\t\t// Raise clearance according\n\t\t\ts.clearanceUpTo.Store(\n\t\t\t\ts.currentUnitID.Load() +\n\t\t\t\t\tint64(\n\t\t\t\t\t\tfloat64(s.slotPace.Load())*s.config.WorkSlotPercentage,\n\t\t\t\t\t),\n\t\t\t)\n\n\t\t\t// Announce start of new slot.\n\t\t\ts.announceNextSlot()\n\n\t\tdefault:\n\n\t\t\t// Second Half-Slot: Catch-Up Slot\n\n\t\t\t// Calculate time taken in previous slot.\n\t\t\tworkSlotDuration := halfSlotEndedAt.Sub(halfSlotStartedAt).Nanoseconds()\n\n\t\t\t// Add current slot duration to avg calculation.\n\t\t\ts.stats.progress.avgWorkSlotCnt.Add(1)\n\t\t\tif s.stats.progress.avgWorkSlotSum.Add(workSlotDuration) < 0 {\n\t\t\t\t// Reset if we wrap.\n\t\t\t\ts.stats.progress.avgWorkSlotCnt.Store(1)\n\t\t\t\ts.stats.progress.avgWorkSlotSum.Store(workSlotDuration)\n\t\t\t}\n\n\t\t\t// Calculate slot duration skew correction, as slots will not run in the\n\t\t\t// exact specified duration.\n\t\t\tslotDurationSkewCorrection := halfSlotDuration / float64(workSlotDuration)\n\n\t\t\t// Calculate slot pace with performance of first half-slot.\n\t\t\t// Get current slot pace as float64.\n\t\t\tcurrentSlotPace := float64(s.slotPace.Load())\n\t\t\t// Calculate current raw slot pace.\n\t\t\tnewRawSlotPace := float64(s.finished.Load()*2) * slotDurationSkewCorrection\n\n\t\t\t// Move slot pace in the trending direction.\n\t\t\tif newRawSlotPace >= currentSlotPace {\n\t\t\t\t// Adjust based on streak.\n\t\t\t\tincreaseStreak++\n\t\t\t\tdecreaseStreak = 0\n\t\t\t\ts.slotPace.Add(int64(\n\t\t\t\t\tcurrentSlotPace * s.config.SlotChangeRatePerStreak * increaseStreak,\n\t\t\t\t))\n\n\t\t\t\t// Count one-streaks.\n\t\t\t\tif increaseStreak == 1 {\n\t\t\t\t\toneStreaks++\n\t\t\t\t} else {\n\t\t\t\t\toneStreaks = 0\n\t\t\t\t}\n\n\t\t\t\t// Debug logging:\n\t\t\t\t// fmt.Printf(\"+++ slot pace: %.0f (current raw pace: %.0f, increaseStreak: %.0f, clearanceUpTo: %d)\\n\", currentSlotPace, newRawSlotPace, increaseStreak, s.clearanceUpTo.Load())\n\t\t\t} else {\n\t\t\t\t// Adjust based on streak.\n\t\t\t\tdecreaseStreak++\n\t\t\t\tincreaseStreak = 0\n\t\t\t\ts.slotPace.Add(int64(\n\t\t\t\t\t-currentSlotPace * s.config.SlotChangeRatePerStreak * decreaseStreak,\n\t\t\t\t))\n\n\t\t\t\t// Enforce minimum.\n\t\t\t\tif s.slotPace.Load() < s.config.MinSlotPace {\n\t\t\t\t\ts.slotPace.Store(s.config.MinSlotPace)\n\t\t\t\t\tdecreaseStreak = 0\n\t\t\t\t}\n\n\t\t\t\t// Count one-streaks.\n\t\t\t\tif decreaseStreak == 1 {\n\t\t\t\t\toneStreaks++\n\t\t\t\t} else {\n\t\t\t\t\toneStreaks = 0\n\t\t\t\t}\n\n\t\t\t\t// Debug logging:\n\t\t\t\t// fmt.Printf(\"--- slot pace: %.0f (current raw pace: %.0f, decreaseStreak: %.0f, clearanceUpTo: %d)\\n\", currentSlotPace, newRawSlotPace, decreaseStreak, s.clearanceUpTo.Load())\n\t\t\t}\n\n\t\t\t// Record Stats\n\n\t\t\t// Add current pace to avg calculation.\n\t\t\ts.stats.progress.avgPaceCnt.Add(1)\n\t\t\tif s.stats.progress.avgPaceSum.Add(s.slotPace.Load()) < 0 {\n\t\t\t\t// Reset if we wrap.\n\t\t\t\ts.stats.progress.avgPaceCnt.Store(1)\n\t\t\t\ts.stats.progress.avgPaceSum.Store(s.slotPace.Load())\n\t\t\t}\n\n\t\t\t// Check if current pace is new max.\n\t\t\tif s.slotPace.Load() > s.stats.progress.maxPace.Load() {\n\t\t\t\ts.stats.progress.maxPace.Store(s.slotPace.Load())\n\t\t\t}\n\n\t\t\t// Check if current pace is new leveled max\n\t\t\tif oneStreaks >= 3 && s.slotPace.Load() > s.stats.progress.maxLeveledPace.Load() {\n\t\t\t\ts.stats.progress.maxLeveledPace.Store(s.slotPace.Load())\n\t\t\t}\n\t\t}\n\t\t// Switch to other slot-half.\n\t\thalfSlotID++\n\t\thalfSlotStartedAt = halfSlotEndedAt\n\n\t\t// Cycle stats after defined time period.\n\t\tif halfSlotID%cycleStatsAt == 0 {\n\t\t\ts.cycleStats()\n\t\t}\n\n\t\t// Check if we are stopping.\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\t\tif s.stopping.IsSet() {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// We should never get here.\n\t// If we do, trigger a worker restart via the service worker.\n\treturn errors.New(\"unexpected end of scheduler\")\n}\n\n// Stop stops the scheduler and gives clearance to all units.\nfunc (s *Scheduler) Stop() {\n\ts.stopping.Set()\n}\n"
  },
  {
    "path": "spn/unit/scheduler_stats.go",
    "content": "package unit\n\n// Stats are somewhat racy, as one value of sum or count might already be\n// updated with the latest slot data, while the other has been not.\n// This is not so much of a problem, as slots are really short and the impact\n// is very low.\n\n// cycleStats calculates the new values and cycles the current values.\nfunc (s *Scheduler) cycleStats() {\n\t// Get and reset max pace.\n\ts.stats.current.maxPace.Store(s.stats.progress.maxPace.Load())\n\ts.stats.progress.maxPace.Store(0)\n\n\t// Get and reset max leveled pace.\n\ts.stats.current.maxLeveledPace.Store(s.stats.progress.maxLeveledPace.Load())\n\ts.stats.progress.maxLeveledPace.Store(0)\n\n\t// Get and reset avg slot pace.\n\tavgPaceCnt := s.stats.progress.avgPaceCnt.Load()\n\tif avgPaceCnt > 0 {\n\t\ts.stats.current.avgPace.Store(s.stats.progress.avgPaceSum.Load() / avgPaceCnt)\n\t} else {\n\t\ts.stats.current.avgPace.Store(0)\n\t}\n\ts.stats.progress.avgPaceCnt.Store(0)\n\ts.stats.progress.avgPaceSum.Store(0)\n\n\t// Get and reset avg unit life.\n\tavgUnitLifeCnt := s.stats.progress.avgUnitLifeCnt.Load()\n\tif avgUnitLifeCnt > 0 {\n\t\ts.stats.current.avgUnitLife.Store(s.stats.progress.avgUnitLifeSum.Load() / avgUnitLifeCnt)\n\t} else {\n\t\ts.stats.current.avgUnitLife.Store(0)\n\t}\n\ts.stats.progress.avgUnitLifeCnt.Store(0)\n\ts.stats.progress.avgUnitLifeSum.Store(0)\n\n\t// Get and reset avg work slot duration.\n\tavgWorkSlotCnt := s.stats.progress.avgWorkSlotCnt.Load()\n\tif avgWorkSlotCnt > 0 {\n\t\ts.stats.current.avgWorkSlot.Store(s.stats.progress.avgWorkSlotSum.Load() / avgWorkSlotCnt)\n\t} else {\n\t\ts.stats.current.avgWorkSlot.Store(0)\n\t}\n\ts.stats.progress.avgWorkSlotCnt.Store(0)\n\ts.stats.progress.avgWorkSlotSum.Store(0)\n\n\t// Get and reset avg catch up slot duration.\n\tavgCatchUpSlotCnt := s.stats.progress.avgCatchUpSlotCnt.Load()\n\tif avgCatchUpSlotCnt > 0 {\n\t\ts.stats.current.avgCatchUpSlot.Store(s.stats.progress.avgCatchUpSlotSum.Load() / avgCatchUpSlotCnt)\n\t} else {\n\t\ts.stats.current.avgCatchUpSlot.Store(0)\n\t}\n\ts.stats.progress.avgCatchUpSlotCnt.Store(0)\n\ts.stats.progress.avgCatchUpSlotSum.Store(0)\n}\n\n// GetMaxSlotPace returns the current maximum slot pace.\nfunc (s *Scheduler) GetMaxSlotPace() int64 {\n\treturn s.stats.current.maxPace.Load()\n}\n\n// GetMaxLeveledSlotPace returns the current maximum leveled slot pace.\nfunc (s *Scheduler) GetMaxLeveledSlotPace() int64 {\n\treturn s.stats.current.maxLeveledPace.Load()\n}\n\n// GetAvgSlotPace returns the current average slot pace.\nfunc (s *Scheduler) GetAvgSlotPace() int64 {\n\treturn s.stats.current.avgPace.Load()\n}\n\n// GetAvgUnitLife returns the current average unit lifetime until it is finished.\nfunc (s *Scheduler) GetAvgUnitLife() int64 {\n\treturn s.stats.current.avgUnitLife.Load()\n}\n\n// GetAvgWorkSlotDuration returns the current average work slot duration.\nfunc (s *Scheduler) GetAvgWorkSlotDuration() int64 {\n\treturn s.stats.current.avgWorkSlot.Load()\n}\n\n// GetAvgCatchUpSlotDuration returns the current average catch up slot duration.\nfunc (s *Scheduler) GetAvgCatchUpSlotDuration() int64 {\n\treturn s.stats.current.avgCatchUpSlot.Load()\n}\n"
  },
  {
    "path": "spn/unit/scheduler_test.go",
    "content": "package unit\n\nimport (\n\t\"testing\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc BenchmarkScheduler(b *testing.B) {\n\tworkers := 10\n\n\t// Create and start scheduler.\n\ts := NewScheduler(&SchedulerConfig{})\n\tm := mgr.New(\"unit-test\")\n\tm.Go(\"test\", func(ctx *mgr.WorkerCtx) error {\n\t\terr := s.SlotScheduler(ctx)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn nil\n\t})\n\tdefer m.Cancel()\n\n\t// Init control structures.\n\tdone := make(chan struct{})\n\tfinishedCh := make(chan struct{})\n\n\t// Start workers.\n\tfor range workers {\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tu := s.NewUnit()\n\t\t\t\tu.WaitForSlot()\n\t\t\t\tu.Finish()\n\t\t\t\tselect {\n\t\t\t\tcase finishedCh <- struct{}{}:\n\t\t\t\tcase <-done:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\t// Start benchmark.\n\tb.ResetTimer()\n\tfor range b.N {\n\t\t<-finishedCh\n\t}\n\tb.StopTimer()\n\n\t// Cleanup.\n\tclose(done)\n}\n"
  },
  {
    "path": "spn/unit/unit.go",
    "content": "package unit\n\nimport (\n\t\"time\"\n\n\t\"github.com/tevino/abool\"\n)\n\n// Unit describes a \"work unit\" and is meant to be embedded into another struct\n// used for passing data moving through multiple processing steps.\ntype Unit struct {\n\tid           int64\n\tscheduler    *Scheduler\n\tcreated      time.Time\n\tfinished     abool.AtomicBool\n\thighPriority abool.AtomicBool\n}\n\n// NewUnit returns a new unit within the scheduler.\nfunc (s *Scheduler) NewUnit() *Unit {\n\treturn &Unit{\n\t\tid:        s.currentUnitID.Add(1),\n\t\tscheduler: s,\n\t\tcreated:   time.Now(),\n\t}\n}\n\n// ReUse re-initialized the unit to be able to reuse already allocated structs.\nfunc (u *Unit) ReUse() {\n\t// Finish previous unit.\n\tu.Finish()\n\n\t// Get new ID and unset finish flag.\n\tu.id = u.scheduler.currentUnitID.Add(1)\n\tu.finished.UnSet()\n}\n\n// WaitForSlot blocks until the unit may be processed.\nfunc (u *Unit) WaitForSlot() {\n\t// High priority units may always process.\n\tif u.highPriority.IsSet() {\n\t\treturn\n\t}\n\n\tfor {\n\t\t// Check if we are allowed to process in the current slot.\n\t\tif u.id <= u.scheduler.clearanceUpTo.Load() {\n\t\t\treturn\n\t\t}\n\n\t\t// Debug logging:\n\t\t// fmt.Printf(\"unit %d waiting for clearance at %d\\n\", u.id, u.scheduler.clearanceUpTo.Load())\n\n\t\t// Wait for next slot.\n\t\t<-u.scheduler.nextSlotSignal()\n\t}\n}\n\n// Finish signals the unit scheduler that this unit has finished processing.\n// Will no-op if called on a nil Unit.\nfunc (u *Unit) Finish() {\n\tif u == nil {\n\t\treturn\n\t}\n\n\t// Always increase finished, even if the unit is from a previous epoch.\n\tif u.finished.SetToIf(false, true) {\n\t\tu.scheduler.finished.Add(1)\n\n\t\t// Record the time this unit took from creation to finish.\n\t\ttimeTaken := time.Since(u.created).Nanoseconds()\n\t\tu.scheduler.stats.progress.avgUnitLifeCnt.Add(1)\n\t\tif u.scheduler.stats.progress.avgUnitLifeSum.Add(timeTaken) < 0 {\n\t\t\t// Reset if we wrap.\n\t\t\tu.scheduler.stats.progress.avgUnitLifeCnt.Store(1)\n\t\t\tu.scheduler.stats.progress.avgUnitLifeSum.Store(timeTaken)\n\t\t}\n\t}\n}\n\n// MakeHighPriority marks the unit as high priority.\nfunc (u *Unit) MakeHighPriority() {\n\tswitch {\n\tcase u.finished.IsSet():\n\t\t// Unit is already finished.\n\tcase !u.highPriority.SetToIf(false, true):\n\t\t// Unit is already set to high priority.\n\t\t// Else: High Priority set.\n\tcase u.id > u.scheduler.clearanceUpTo.Load():\n\t\t// Unit is outside current clearance, reduce clearance by one.\n\t\tu.scheduler.clearanceUpTo.Add(-1)\n\t}\n}\n\n// IsHighPriority returns whether the unit has high priority.\nfunc (u *Unit) IsHighPriority() bool {\n\treturn u.highPriority.IsSet()\n}\n\n// RemovePriority removes the high priority mark.\nfunc (u *Unit) RemovePriority() {\n\tu.highPriority.UnSet()\n}\n"
  },
  {
    "path": "spn/unit/unit_debug.go",
    "content": "package unit\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n)\n\n// UnitDebugger is used to debug unit leaks.\ntype UnitDebugger struct { //nolint:golint\n\tunits     map[int64]*UnitDebugData\n\tunitsLock sync.Mutex\n}\n\n// UnitDebugData represents a unit that is being debugged.\ntype UnitDebugData struct { //nolint:golint\n\tunit       *Unit\n\tunitSource string\n}\n\n// DebugUnit registers the given unit for debug output with the given source.\n// Additional calls on the same unit update the unit source.\n// StartDebugLog() must be called before calling DebugUnit().\nfunc (s *Scheduler) DebugUnit(u *Unit, unitSource string) {\n\t// Check if scheduler and unit debugger are created.\n\tif s == nil || s.unitDebugger == nil {\n\t\treturn\n\t}\n\n\ts.unitDebugger.unitsLock.Lock()\n\tdefer s.unitDebugger.unitsLock.Unlock()\n\n\ts.unitDebugger.units[u.id] = &UnitDebugData{\n\t\tunit:       u,\n\t\tunitSource: unitSource,\n\t}\n}\n\n// StartDebugLog logs the scheduler state every second.\nfunc (s *Scheduler) StartDebugLog() {\n\ts.unitDebugger = &UnitDebugger{\n\t\tunits: make(map[int64]*UnitDebugData),\n\t}\n\n\t// Force StatCycleDuration to match the debug log output.\n\ts.config.StatCycleDuration = time.Second\n\n\tgo func() {\n\t\tfor {\n\t\t\ts.debugStep()\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t}()\n}\n\nfunc (s *Scheduler) debugStep() {\n\ts.unitDebugger.unitsLock.Lock()\n\tdefer s.unitDebugger.unitsLock.Unlock()\n\n\t// Go through debugging units and clear finished ones, count sources.\n\tsources := make(map[string]int)\n\tfor id, debugUnit := range s.unitDebugger.units {\n\t\tif debugUnit.unit.finished.IsSet() {\n\t\t\tdelete(s.unitDebugger.units, id)\n\t\t} else {\n\t\t\tcnt := sources[debugUnit.unitSource]\n\t\t\tsources[debugUnit.unitSource] = cnt + 1\n\t\t}\n\t}\n\n\t// Print current state.\n\tlog.Debugf(\n\t\t`scheduler: state: slotPace=%d avgPace=%d maxPace=%d maxLeveledPace=%d currentUnitID=%d clearanceUpTo=%d unitLife=%s slotDurations=%s/%s`,\n\t\ts.slotPace.Load(),\n\t\ts.GetAvgSlotPace(),\n\t\ts.GetMaxSlotPace(),\n\t\ts.GetMaxLeveledSlotPace(),\n\t\ts.currentUnitID.Load(),\n\t\ts.clearanceUpTo.Load(),\n\t\ttime.Duration(s.GetAvgUnitLife()).Round(10*time.Microsecond),\n\t\ttime.Duration(s.GetAvgWorkSlotDuration()).Round(10*time.Microsecond),\n\t\ttime.Duration(s.GetAvgCatchUpSlotDuration()).Round(10*time.Microsecond),\n\t)\n\tlog.Debugf(\"scheduler: unit sources: %+v\", sources)\n}\n"
  },
  {
    "path": "spn/unit/unit_test.go",
    "content": "package unit\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/safing/portmaster/service/mgr\"\n)\n\nfunc TestUnit(t *testing.T) { //nolint:paralleltest\n\t// Ignore deprectation, as the given alternative is not safe for concurrent use.\n\t// The global rand methods use a locked seed, which is not available from outside.\n\trand.Seed(time.Now().UnixNano()) //nolint\n\n\tsize := 1000000\n\tworkers := 100\n\n\tm := mgr.New(\"unit-test\")\n\t// Create and start scheduler.\n\ts := NewScheduler(&SchedulerConfig{})\n\ts.StartDebugLog()\n\t// ctx, cancel := context.WithCancel(context.Background())\n\tm.Go(\"test\", func(w *mgr.WorkerCtx) error {\n\t\terr := s.SlotScheduler(w)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn nil\n\t})\n\tdefer m.Cancel()\n\n\t// Create 10 workers.\n\tvar wg sync.WaitGroup\n\twg.Add(workers)\n\tsizePerWorker := size / workers\n\tfor range workers {\n\t\tgo func() {\n\t\t\tfor range sizePerWorker {\n\t\t\t\tu := s.NewUnit()\n\n\t\t\t\t// Make 1% high priority.\n\t\t\t\tif rand.Int()%100 == 0 { //nolint:gosec // This is a test.\n\t\t\t\t\tu.MakeHighPriority()\n\t\t\t\t}\n\n\t\t\t\tu.WaitForSlot()\n\t\t\t\ttime.Sleep(10 * time.Microsecond)\n\t\t\t\tu.Finish()\n\t\t\t}\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\t// Wait for workers to finish.\n\twg.Wait()\n\n\t// Wait for two slot durations for values to update.\n\ttime.Sleep(s.config.SlotDuration * 2)\n\n\t// Print current state.\n\ts.cycleStats()\n\tfmt.Printf(`scheduler state:\n\t\tcurrentUnitID = %d\n\t\tslotPace = %d\n\t\tclearanceUpTo = %d\n\t\tfinished = %d\n\t\tmaxPace = %d\n\t\tmaxLeveledPace = %d\n\t\tavgPace = %d\n\t\tavgUnitLife = %s\n\t\tavgWorkSlot = %s\n\t\tavgCatchUpSlot = %s\n`,\n\t\ts.currentUnitID.Load(),\n\t\ts.slotPace.Load(),\n\t\ts.clearanceUpTo.Load(),\n\t\ts.finished.Load(),\n\t\ts.GetMaxSlotPace(),\n\t\ts.GetMaxLeveledSlotPace(),\n\t\ts.GetAvgSlotPace(),\n\t\ttime.Duration(s.GetAvgUnitLife()),\n\t\ttime.Duration(s.GetAvgWorkSlotDuration()),\n\t\ttime.Duration(s.GetAvgCatchUpSlotDuration()),\n\t)\n\n\t// Check if everything seems good.\n\tassert.Equal(t, size, int(s.currentUnitID.Load()), \"currentUnitID must match size\")\n\tassert.GreaterOrEqual(\n\t\tt,\n\t\tint(s.clearanceUpTo.Load()),\n\t\tsize+int(float64(s.config.MinSlotPace)*s.config.SlotChangeRatePerStreak),\n\t\t\"clearanceUpTo must be at least size+minSlotPace\",\n\t)\n\n\t// Shutdown\n\tm.Cancel()\n\ttime.Sleep(s.config.SlotDuration * 10)\n\n\t// Check if scheduler shut down correctly.\n\tassert.Equal(t, math.MaxInt64-math.MaxInt32, int(s.clearanceUpTo.Load()), \"clearance must be near MaxInt64\")\n}\n"
  },
  {
    "path": "windows_core_dll/build.ps1",
    "content": "msbuild .\\windows_core_dll.sln /p:Configuration=Release\r\nls .\\x64\\Release\\portmaster-core.dll"
  },
  {
    "path": "windows_core_dll/dllmain.cpp",
    "content": "// dllmain.cpp : Defines the entry point for the DLL application.\r\n#include \"pch.h\"\r\n\r\n#pragma comment(lib, \"tdh.lib\")\r\n\r\n// GUID of the DNS log provider\r\nstatic const GUID DNS_CLIENT_PROVIDER_GUID = {\r\n    0x1C95126E,\r\n    0x7EEA,\r\n    0x49A9,\r\n    {0xA3, 0xFE, 0xA3, 0x78, 0xB0, 0x3D, 0xDB, 0x4D} };\r\n\r\n// GUID of the event session. This should be unique for the application.\r\nstatic const GUID PORTMASTER_ETW_SESSION_GUID = {\r\n    0x0211d070,\r\n    0xc3b2,\r\n    0x4609,\r\n    {0x92, 0xf5, 0x28, 0xe7, 0x18, 0xb2, 0x3b, 0x18} };\r\n\r\n// Name of the session. This is visble when user queries all ETW sessions.\r\n// (example `logman query -ets`)\r\n#define LOGSESSION_NAME L\"PortmasterDNSEventListener\"\r\n\r\n// Fuction type of the callback that will be called on each event.\r\ntypedef uint64_t(*GoEventRecordCallback)(wchar_t* domain, uint32_t pid, wchar_t* result);\r\n\r\n// Holds the state of the ETW Session.\r\nstruct ETWSessionState {\r\n    TRACEHANDLE SessionTraceHandle;\r\n    EVENT_TRACE_PROPERTIES* SessionProperties;\r\n    TRACEHANDLE sessionHandle;\r\n    GoEventRecordCallback callback;\r\n};\r\n\r\n// getPropertyValue reads a property from the event.\r\nstatic bool getPropertyValue(PEVENT_RECORD evt, LPWSTR prop, PBYTE* pData) {\r\n    // Describe the data that needs to be retrieved from the event.\r\n    PROPERTY_DATA_DESCRIPTOR DataDescriptor;\r\n    ZeroMemory(&DataDescriptor, sizeof(DataDescriptor));\r\n    DataDescriptor.PropertyName = (ULONGLONG)(prop);\r\n    DataDescriptor.ArrayIndex = 0;\r\n\r\n    DWORD PropertySize = 0;\r\n    // Check if the data is available and what is the size of it.\r\n    DWORD status =\r\n        TdhGetPropertySize(evt, 0, NULL, 1, &DataDescriptor, &PropertySize);\r\n    if (ERROR_SUCCESS != status) {\r\n        return false;\r\n    }\r\n\r\n    // Allocate memory for the data.\r\n    *pData = (PBYTE)malloc(PropertySize);\r\n    if (NULL == *pData) {\r\n        return false;\r\n    }\r\n\r\n    // Get the data.\r\n    status =\r\n        TdhGetProperty(evt, 0, NULL, 1, &DataDescriptor, PropertySize, *pData);\r\n    if (ERROR_SUCCESS != status) {\r\n        if (*pData) {\r\n            free(*pData);\r\n            *pData = NULL;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\n// EventRecordCallback is a callback called on each event.\r\nstatic void WINAPI EventRecordCallback(PEVENT_RECORD eventRecord) {\r\n    PBYTE resultValue = NULL;\r\n    PBYTE domainValue = NULL;\r\n\r\n    getPropertyValue(eventRecord, (LPWSTR)L\"QueryResults\", &resultValue);\r\n    getPropertyValue(eventRecord, (LPWSTR)L\"QueryName\", &domainValue);\r\n\r\n    ETWSessionState* state = (ETWSessionState*)eventRecord->UserContext;\r\n\r\n    if (resultValue != NULL && domainValue != NULL) {\r\n        state->callback((wchar_t*)domainValue, eventRecord->EventHeader.ProcessId, (wchar_t*)resultValue);\r\n    }\r\n\r\n    free(resultValue);\r\n    free(domainValue);\r\n}\r\n\r\nextern \"C\" {\r\n    // PM_ETWCreateState allocates memory for the state and initializes the config for the session. PM_ETWDestroySession must be called to avoid leaks.\r\n    // callback must be set to a valid function pointer.\r\n    __declspec(dllexport) ETWSessionState* PM_ETWCreateState(GoEventRecordCallback callback) {\r\n        // Create trace session properties.\r\n        ULONG BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME);\r\n        EVENT_TRACE_PROPERTIES* SessionProperties =\r\n            (EVENT_TRACE_PROPERTIES*)calloc(1, BufferSize);\r\n        SessionProperties->Wnode.BufferSize = BufferSize;\r\n        SessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;\r\n        SessionProperties->Wnode.ClientContext = 1; // QPC clock resolution\r\n        SessionProperties->Wnode.Guid = PORTMASTER_ETW_SESSION_GUID;\r\n        SessionProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;\r\n        SessionProperties->MaximumFileSize = 1; // MB\r\n        SessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);\r\n\r\n        // Create state\r\n        ETWSessionState* state = (ETWSessionState*)calloc(1, sizeof(ETWSessionState));\r\n        state->SessionProperties = SessionProperties;\r\n        state->callback = callback;\r\n        return state;\r\n    }\r\n\r\n    // PM_ETWInitializeSession initializes the session.\r\n    __declspec(dllexport) uint32_t PM_ETWInitializeSession(ETWSessionState* state) {\r\n        return StartTrace(&state->SessionTraceHandle, LOGSESSION_NAME,\r\n            state->SessionProperties);\r\n    }\r\n\r\n    // PM_ETWStartTrace subscribes to the dns events and start listening. The function blocks while the listener is running.\r\n    // Call PM_ETWStopTrace to stop the listener.\r\n    __declspec(dllexport) uint32_t PM_ETWStartTrace(ETWSessionState* state) {\r\n        ULONG status =\r\n            EnableTraceEx2(state->SessionTraceHandle, (LPCGUID)&DNS_CLIENT_PROVIDER_GUID,\r\n                EVENT_CONTROL_CODE_ENABLE_PROVIDER,\r\n                TRACE_LEVEL_INFORMATION, 0, 0, 0, NULL);\r\n\r\n        if (status != ERROR_SUCCESS) {\r\n            return status;\r\n        }\r\n\r\n        EVENT_TRACE_LOGFILE trace = { 0 };\r\n\r\n        trace.LoggerName = (LPWSTR)(LOGSESSION_NAME);\r\n        trace.ProcessTraceMode =\r\n            PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;\r\n        trace.EventRecordCallback = EventRecordCallback;\r\n        trace.Context = state;\r\n\r\n        state->sessionHandle = OpenTrace(&trace);\r\n        if (state->sessionHandle == INVALID_PROCESSTRACE_HANDLE) {\r\n            return 1;\r\n        }\r\n\r\n        status = ProcessTrace(&state->sessionHandle, 1, NULL, NULL);\r\n        if (status != ERROR_SUCCESS) {\r\n            return 1;\r\n        }\r\n\r\n        return ERROR_SUCCESS;\r\n    }\r\n\r\n    // PM_ETWFlushTrace flushes the event buffer.\r\n    __declspec(dllexport) uint32_t PM_ETWFlushTrace(ETWSessionState* state) {\r\n        return ControlTrace(state->SessionTraceHandle, LOGSESSION_NAME,\r\n            state->SessionProperties, EVENT_TRACE_CONTROL_FLUSH);\r\n    }\r\n\r\n    // PM_ETWFlushTrace stops the listener.\r\n    __declspec(dllexport) uint32_t PM_ETWStopTrace(ETWSessionState* state) {\r\n        return ControlTrace(state->SessionTraceHandle, LOGSESSION_NAME, state->SessionProperties,\r\n            EVENT_TRACE_CONTROL_STOP);\r\n    }\r\n\r\n    // PM_ETWFlushTrace Closes the session and frees recourses.\r\n    __declspec(dllexport) uint32_t PM_ETWDestroySession(ETWSessionState* state) {\r\n        if (state == NULL) {\r\n            return 1;\r\n        }\r\n        uint32_t status = CloseTrace(state->sessionHandle);\r\n\r\n        // Free memory.\r\n        free(state->SessionProperties);\r\n        free(state);\r\n        return status;\r\n    }\r\n\r\n    // PM_ETWStopOldSession removes old session with the same name if they exist. \r\n    // It returns success(0) only if its able to delete the old session.\r\n    __declspec(dllexport) ULONG PM_ETWStopOldSession() {\r\n        ULONG status = ERROR_SUCCESS;\r\n        TRACEHANDLE sessionHandle = 0;\r\n\r\n        // Create trace session properties\r\n        size_t bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME);\r\n        EVENT_TRACE_PROPERTIES* sessionProperties = (EVENT_TRACE_PROPERTIES*)calloc(1, bufferSize);\r\n        sessionProperties->Wnode.BufferSize = (ULONG)bufferSize;\r\n        sessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;\r\n        sessionProperties->Wnode.ClientContext = 1; // QPC clock resolution\r\n        sessionProperties->Wnode.Guid = PORTMASTER_ETW_SESSION_GUID;\r\n        sessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);\r\n\r\n        // Use Control trace will stop the session which will trigger a delete.\r\n        status = ControlTrace(NULL, LOGSESSION_NAME, sessionProperties, EVENT_TRACE_CONTROL_STOP);\r\n\r\n        free(sessionProperties);\r\n        return status;\r\n    }\r\n}"
  },
  {
    "path": "windows_core_dll/framework.h",
    "content": "#pragma once\r\n\r\n#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\r\n// Windows Header Files\r\n#include <windows.h>\r\n"
  },
  {
    "path": "windows_core_dll/pch.cpp",
    "content": "// pch.cpp: source file corresponding to the pre-compiled header\r\n\r\n#include \"pch.h\"\r\n\r\n// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.\r\n"
  },
  {
    "path": "windows_core_dll/pch.h",
    "content": "// pch.h: This is a precompiled header file.\r\n// Files listed below are compiled only once, improving build performance for future builds.\r\n// This also affects IntelliSense performance, including code completion and many code browsing features.\r\n// However, files listed here are ALL re-compiled if any one of them is updated between builds.\r\n// Do not add files here that you will be updating frequently as this negates the performance advantage.\r\n\r\n#ifndef PCH_H\r\n#define PCH_H\r\n\r\n// add headers that you want to pre-compile here\r\n#include \"framework.h\"\r\n\r\n#include <evntrace.h>\r\n#include <tdh.h>\r\n#include <iostream>\r\n#include <string>\r\n#include <evntcons.h>\r\n#include <codecvt>\r\n#include <thread>\r\n\r\n\r\n#endif //PCH_H\r\n"
  },
  {
    "path": "windows_core_dll/windows_core_dll.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 17\r\nVisualStudioVersion = 17.11.35222.181\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"windows_core_dll\", \"windows_core_dll.vcxproj\", \"{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Release|x64.Build.0 = Release|x64\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{6F3C7EAF-8511-4822-AAF0-1086D27E4DA9}.Release|x86.Build.0 = Release|Win32\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {8E60106D-49DF-49C7-AC08-02775342FEAE}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "windows_core_dll/windows_core_dll.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>17.0</VCProjectVersion>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <ProjectGuid>{6f3c7eaf-8511-4822-aaf0-1086d27e4da9}</ProjectGuid>\r\n    <RootNamespace>windowscoredll</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n    <ProjectName>portmaster-core</ProjectName>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;WINDOWSCOREDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <EnableUAC>false</EnableUAC>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;WINDOWSCOREDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <EnableUAC>false</EnableUAC>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>_DEBUG;WINDOWSCOREDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <EnableUAC>false</EnableUAC>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>NDEBUG;WINDOWSCOREDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Windows</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <EnableUAC>false</EnableUAC>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"framework.h\" />\r\n    <ClInclude Include=\"pch.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"dllmain.cpp\" />\r\n    <ClCompile Include=\"pch.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "windows_core_dll/windows_core_dll.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"framework.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"pch.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"dllmain.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"pch.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "windows_core_dll/windows_core_dll.vcxproj.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <PropertyGroup />\r\n</Project>"
  },
  {
    "path": "windows_kext/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n*/**/[Rr]elease/\n*/**/[Rr]eleases/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# ASP.NET Scaffolding\nScaffoldingReadMe.txt\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.tlog\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n*.exe\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*.json\ncoverage*.xml\ncoverage*.info\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio 6 auto-generated project file (contains which files were open etc.)\n*.vbp\n\n# Visual Studio 6 workspace and project file (working project files containing files to include in project)\n*.dsw\n*.dsp\n\n# Visual Studio 6 technical files\n*.ncb\n*.aps\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# Visual Studio History (VSHistory) files\n.vshistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n# Fody - auto-generated XML schema\nFodyWeavers.xsd\n\n# VS Code files for those working on multiple tools\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n*.code-workspace\n\n# Local History for Visual Studio Code\n.history/\n\n# Windows Installer files from build outputs\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# JetBrains Rider\n*.sln.iml\npm_kext/RCa04400\npm_kext/RCa05788\npm_kext/RCa06452\ntarget\nkext.sys\nrelease/build\n"
  },
  {
    "path": "windows_kext/PacketFlow.md",
    "content": "# There and back again, a packets tale.\n\nAn explanation on the complete path of the packet from entering to the exit of the kernel extension.\n\n## Entry\n\nThe packet entry point depends on the packet and the internal windows filter state:   \n\n- First packet of outbound connection -> AleAuthConnect Layer\n- First packet of inbound connection -> InboundIppacket Layer\n\n## ALE layer\n\nEach defined ALE layer has a filter linked to it. This filter has a state.  \nWhen a decision is made to block or permit a connection it will be saved to the filter state.\nThe only way to update the decision in a filter is to clear the whole state and apply the decision for the next packet of each connection.\n\n### First packet\n\nFor outgoing connections this logic fallows:\n  - Packet enters in one of the ALE layer\n  - Packet is TCP or UDP\n    1. Save and absorb packet.\n    2. Send an event to Portmaster. \n    2. Create a cache entry.\n  - If Packet is not TCP/UDP forward to packet layer\n\nFor incoming connection this logic fallow:\n  - Packet enter in one of the Packet layer:\n    1. Save packet and absorb.\n    2. Send an event to Portmaster. \n    2. Create a cache entry if the protocol is TCP or UDP.\n    3. Wait for Portmasters decision.\n\n\nIf more packets arrive before Portmaster returns a decision, packet will be absorbed and another event will be sent.\nFor Outgoing connection this will happen in ALE layer.\nFor Incoming connection this will happen in Packet layer. \n\n### Pormtaster returns a verdict for the connection\n\nConnection cache will be updated and the packet will be injected.\nThe next steps depend of the direction of the packet and the verdict\n\n* Permanent Verdict / Outgoing connection\n  - Allow / Block / Drop directly in the ALE layer. For Block and Drop packet layer will not see the rest of the packet in the connection.\n* Temporary Verdict / Outgoing connection\n  - Always Allow - this connections are solely handled by the packet layer. (This is true only for outgoing connections) \n\n* Permanent or Temporary Verdict / Incoming connection\n  - Allow / Block / Drop. Handled by the Packet layer\n\n> There is no defined ALE layers for inbound connection. Inbound packets are handed compactly by the packet layer \n\nFallowing specifics apply to the ALE layer:  \n1. Connections with flag `reauthorize == false` are special. When the flag is `false` that means that a applications is calling a function `connect()` or `accept()` for a connection. This is a special case because we control the result of the function, telling the application that it's allowed or not allowed to continue with the connection. Since we are making request to Portmaster we need to take longer time. This is done with pending the packet. This allows the kernel extension to pause the event and continue when it has the verdict. See `ale_callouts.rs -> save_packet()` function.\n2. If packet payload is present it is from the transport layer.\n\n\n## Packet layer\n\nThe logic for the packet is split in two:\n\n### TCP or UDP protocols\n\nThe packet layer will not process packets that miss a cache entry:  \n- Incoming packet: it will forward it to the ALE layer.\n- Outgoing packet: this is treated as invalid state since ALE should be the entry for the packets. If it happens the packet layer will create a request to Portmaster for it.\n\nFor packets with a cache entry:\n- Permanent Verdict: apply the verdict.\n- Redirect Verdict: copy the packet, modify and inject. Drop the original packet.\n- Temporary verdict: send request to Portmaster.\n\nAfter portmaster returns the verdict for the packet. If its allowed it will be modified (if needed) and injected everything else will be dropped.\nThe packet layer will permit all injected packets.\n\n### Not TCP or UDP protocols -> ICMP, IGMP ...\n\nDoes packets are treated as with temporary verdict. There will be no cache entry for them.\nEvery packet will be send to Portmaster for a decision and re-injected if allowed.\n\n## Connection Cache\n\nIt holds information for all TCP and UDP connections. Local and destination ip addresses and ports, verdict, protocol, process id\nIt also holds last active time and end time.  \n\nCache entry is removed automatically 1 minute after an end state has been set or after 10 minutes of inactivity.  \n\nEnd stat is set by Endpoint layers or Resource release layers."
  },
  {
    "path": "windows_kext/PortmasterKext64.inf",
    "content": ";/*++\n;\n;Copyright (c) Safing ICS Technologies GmbH.\n;\n;    This program is free software: you can redistribute it and/or modify\n;    it under the terms of the GNU General Public License as published by\n;    the Free Software Foundation, either version 3 of the License, or\n;    (at your option) any later version.\n;\n;    This program is distributed in the hope that it will be useful,\n;    but WITHOUT ANY WARRANTY; without even the implied warranty of\n;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n;    GNU General Public License for more details.\n;\n;    You should have received a copy of the GNU General Public License\n;    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n;\n;--*/\n\n[Version]\nSignature = \"$Windows NT$\"\nClass = WFPCALLOUTS\nClassGuid = {57465043-616C-6C6F-7574-5F636C617373}\nProvider = %Provider%\nCatalogFile = PortmasterKext64.Cat\nDriverVer = 01/01/2019,1.0.11.0\n\n[SourceDisksNames]\n1 = %DiskName%\n\n[SourceDisksFiles]\nPortmasterKext64.sys = 1\n\n[DestinationDirs]\nDefaultDestDir = 12 ; %windir%\\system32\\drivers\nPortmasterKext.DriverFiles = 12 ; %windir%\\system32\\drivers\n\n[DefaultInstall]\nOptionDesc = %Description%\nCopyFiles = PortmasterKext.DriverFiles\n\n[DefaultInstall.Services]\nAddService = %ServiceName%,,PortmasterKext.Service\n\n[DefaultUninstall]\nDelFiles = PortmasterKext.DriverFiles\n\n[DefaultUninstall.Services]\nDelService = PortmasterKext,0x200 ; SPSVCINST_STOPSERVICE\n\n[PortmasterKext.DriverFiles]\nPortmasterKext64.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY\n\n[PortmasterKext.Service]\nDisplayName = %ServiceName%\nDescription = %ServiceDesc%\nServiceType = 1  ; SERVICE_KERNEL_DRIVER\nStartType = 0    ; SERVICE_BOOT_START\nErrorControl = 1 ; SERVICE_ERROR_NORMAL\nServiceBinary = %12%\\PortmasterKext64.sys\n\n[Strings]\nProvider = \"Safing ICS Technologies GmbH\"\nDiskName = \"PortmasterKext Installation Disk\"\nDescription = \"PortmasterKext Driver\"\nServiceName = \"PortmasterKext\"\nServiceDesc = \"PortmasterKext Driver\"\n"
  },
  {
    "path": "windows_kext/README.md",
    "content": "# Portmaster Windows kext\nImplementation of Safing's Portmaster Windows kernel extension in Rust.\n\n### Documentation\n\n- [Driver](driver/README.md) -> entry point.\n- [WDK](wdk/README.md) -> Windows Driver Kit interface.\n- [Packet Path](PacketFlow.md) -> Detailed documentation of what happens to a packet when it enters the kernel extension.\n- [Release](release/README.md) -> Guide how to do a release build.\n- [Windows Filtering Platform - MS](https://learn.microsoft.com/en-us/windows-hardware/drivers/network/roadmap-for-developing-wfp-callout-drivers) -> The driver is build on top of WFP.\n\n### Building (For release)\n\nPlease refer to [release/README.md](release/README.md) for details about the release procedure.\n\n### Building (For testing and development)\n\nThe Windows Portmaster Kernel Extension is currently only developed and tested for the amd64 (64-bit) architecture.\n\n__Prerequirements:__\n\n- Visual Studio 2022\n    - Install C++ and Windows 11 SDK (22H2) components\n    - Add `link.exe` and `signtool` in the PATH\n- Windows Driver Kit\n    - https://learn.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk\n- Rust (Can be separate machine)\n    - https://www.rust-lang.org/tools/install\n\n__Setup Test Signing:__\n\n> Not recommended for a work machine. Usually done on virtual machine dedicated for testing.\n\nIn order to test the driver on your machine, you will have to sign it (starting with Windows 10).\n\nCreate a new certificate for test signing:\n\n```ps1\n    # Open a *x64 Free Build Environment* console as Administrator.\n\n    # Run the MakeCert.exe tool to create a test certificate:\n    MakeCert -r -pe -ss PrivateCertStore -n \"CN=DriverCertificate\" DriverCertificate.cer\n\n    # Install the test certificate with CertMgr.exe:\n    CertMgr /add DriverCertificate.cer /s /r localMachine root\n```\n\nEnable Test Signing on the dev machine:\n```ps1\n    # Before you can load test-signed drivers, you must enable Windows test mode. To do this, run this command:\n    Bcdedit.exe -set TESTSIGNING ON\n    # Then, restart Windows. For more information, see The TESTSIGNING Boot Configuration Option.\n```\n\n__Build driver:__\n\n```sh\n    cd driver\n    cargo build --release\n```\n> Build also works on linux\n\n__Link and sign:__\nOn a windows machine copy `driver.lib` from the project target directory (`driver/target/x86_64-pc-windows-msvc/release/driver.lib`) in the same folder as `link-dev.ps1`.\nRun `link-dev.ps1`.\n\n`driver.sys` should appear in the folder.\n\nSign the driver with the test certificate:\n```\n  SignTool sign /v /s TestCertStoreName /n TestCertName driver.sys\n```\nLoad and use the driver.\n"
  },
  {
    "path": "windows_kext/c_helper/c_helper.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"helper.c\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "windows_kext/c_helper/c_helper.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 17\r\nVisualStudioVersion = 17.5.33502.453\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"c_helper\", \"c_helper.vcxproj\", \"{39A5E911-A716-4708-8B88-3895183C6372}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|ARM = Debug|ARM\r\n\t\tDebug|ARM64 = Debug|ARM64\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease|ARM = Release|ARM\r\n\t\tRelease|ARM64 = Release|ARM64\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|ARM.ActiveCfg = Debug|ARM\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|ARM.Build.0 = Debug|ARM\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|ARM.Deploy.0 = Debug|ARM\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|ARM64.ActiveCfg = Debug|ARM64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|ARM64.Build.0 = Debug|ARM64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|ARM64.Deploy.0 = Debug|ARM64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|x64.Deploy.0 = Debug|x64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Debug|x86.Deploy.0 = Debug|Win32\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|ARM.ActiveCfg = Release|ARM\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|ARM.Build.0 = Release|ARM\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|ARM.Deploy.0 = Release|ARM\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|ARM64.ActiveCfg = Release|ARM64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|ARM64.Build.0 = Release|ARM64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|ARM64.Deploy.0 = Release|ARM64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|x64.Build.0 = Release|x64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|x64.Deploy.0 = Release|x64\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|x86.Build.0 = Release|Win32\r\n\t\t{39A5E911-A716-4708-8B88-3895183C6372}.Release|x86.Deploy.0 = Release|Win32\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {91E52350-EBB9-4B0F-9C28-61C0BBAEDC6A}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "windows_kext/c_helper/c_helper.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|ARM\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|ARM\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>ARM</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|ARM64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>ARM64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|ARM64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>ARM64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"helper.c\" />\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{39A5E911-A716-4708-8B88-3895183C6372}</ProjectGuid>\r\n    <TemplateGuid>{0a049372-4c4d-4ea0-a64e-dc6ad88ceca1}</TemplateGuid>\r\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r\n    <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>\r\n    <Configuration>Debug</Configuration>\r\n    <Platform Condition=\"'$(Platform)' == ''\">Win32</Platform>\r\n    <RootNamespace>c_helper</RootNamespace>\r\n    <DriverType>KMDF</DriverType>\r\n    <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>\r\n    <ProjectName>c_helper</ProjectName>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <Driver_SpectreMitigation>false</Driver_SpectreMitigation>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <Driver_SpectreMitigation>false</Driver_SpectreMitigation>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\" Label=\"Configuration\">\r\n    <TargetVersion>Windows10</TargetVersion>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>\r\n    <ConfigurationType>StaticLibrary</ConfigurationType>\r\n    <DriverTargetPlatform>Universal</DriverTargetPlatform>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <Driver_SpectreMitigation>false</Driver_SpectreMitigation>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <OutDir>$(SolutionDir)$(Platform)</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <OutDir>$(SolutionDir)$(Platform)</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\r\n    <OutDir>$(SolutionDir)$(Platform)</OutDir>\r\n    <IntDir>$(Platform)\\$(ConfigurationName)\\</IntDir>\r\n    <TargetName>$(TargetName.Replace(' ',''))</TargetName>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>_DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>_DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r\n      <BufferSecurityCheck>false</BufferSecurityCheck>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <BufferSecurityCheck>false</BufferSecurityCheck>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>_DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|ARM64'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>_DEBUG;WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|ARM64'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP;WINAPI_PARTITION_DESKTOP=1;WINAPI_PARTITION_SYSTEM=1;WINAPI_PARTITION_APP=1;WINAPI_PARTITION_PC_APP=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <LanguageStandard>Default</LanguageStandard>\r\n      <LanguageStandard_C>Default</LanguageStandard_C>\r\n    </ClCompile>\r\n  </ItemDefinitionGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "windows_kext/c_helper/helper.c",
    "content": "\r\n/*\r\n *  Name:        helper.c\r\n */\r\n\r\n#include <stdlib.h>\r\n#include <wchar.h>\r\n\r\n#define NDIS640 1                // Windows 8 and Windows Server 2012\r\n\r\n#include \"Ntifs.h\"\r\n#include <ntddk.h>              // Windows Driver Development Kit\r\n#include <wdf.h>                // Windows Driver Foundation\r\n\r\n#pragma warning(push)\r\n#pragma warning(disable: 4201)  // Disable \"Nameless struct/union\" compiler warning for fwpsk.h only!\r\n#include <fwpsk.h>              // Functions and enumerated types used to implement callouts in kernel mode\r\n#pragma warning(pop)            // Re-enable \"Nameless struct/union\" compiler warning\r\n\r\n#include <fwpmk.h>              // Functions used for managing IKE and AuthIP main mode (MM) policy and security associations\r\n#include <fwpvi.h>              // Mappings of OS specific function versions (i.e. fn's that end in 0 or 1)\r\n#include <guiddef.h>            // Used to define GUID's\r\n#include <initguid.h>           // Used to define GUID's\r\n#include \"devguid.h\"\r\n#include <stdarg.h>\r\n#include <stdbool.h>\r\n#include <ntstrsafe.h>\r\n\r\nEVT_WDF_DRIVER_UNLOAD emptyEventUnload;\r\n\r\nNTSTATUS pm_InitDriverObject(DRIVER_OBJECT * driverObject, UNICODE_STRING * registryPath, WDFDRIVER * driver, WDFDEVICE * device, wchar_t *win_device_name, wchar_t *dos_device_name, WDF_OBJECT_ATTRIBUTES * objectAttributes, void (*wdfEventUnload)(WDFDRIVER)) {\r\n\tUNICODE_STRING deviceName = { 0 };\r\n\tRtlInitUnicodeString(&deviceName, win_device_name);\r\n\r\n\tUNICODE_STRING deviceSymlink = { 0 };\r\n\tRtlInitUnicodeString(&deviceSymlink, dos_device_name);\r\n\r\n\t// Create a WDFDRIVER for this driver\r\n\tWDF_DRIVER_CONFIG config = { 0 };\r\n\tWDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);\r\n\tconfig.DriverInitFlags = WdfDriverInitNonPnpDriver;\r\n\tconfig.EvtDriverUnload = wdfEventUnload; // <-- Necessary for this driver to unload correctly\r\n\tNTSTATUS status = WdfDriverCreate(driverObject, registryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, driver);\r\n\tif (!NT_SUCCESS(status)) {\r\n      return status;\r\n\t}\r\n\r\n\t// Create a WDFDEVICE for this driver\r\n\tPWDFDEVICE_INIT deviceInit = WdfControlDeviceInitAllocate(*driver, &SDDL_DEVOBJ_SYS_ALL_ADM_ALL);  // only admins and kernel can access device\r\n\tif (!deviceInit) {\r\n\t    return STATUS_INSUFFICIENT_RESOURCES;\r\n\t}\r\n\r\n\t// Configure the WDFDEVICE_INIT with a name to allow for access from user mode\r\n\tWdfDeviceInitSetDeviceType(deviceInit, FILE_DEVICE_NETWORK);\r\n\tWdfDeviceInitSetCharacteristics(deviceInit, FILE_DEVICE_SECURE_OPEN, false);\r\n\t(void) WdfDeviceInitAssignName(deviceInit, &deviceName);\r\n\t(void) WdfPdoInitAssignRawDevice(deviceInit, &GUID_DEVCLASS_NET);\r\n\tWdfDeviceInitSetDeviceClass(deviceInit, &GUID_DEVCLASS_NET);\r\n\r\n\tstatus = WdfDeviceCreate(&deviceInit, objectAttributes, device);\r\n\tif (!NT_SUCCESS(status)) {\r\n\t  WdfDeviceInitFree(deviceInit);\r\n\t\treturn status;\r\n\t}\r\n\tstatus = WdfDeviceCreateSymbolicLink(*device, &deviceSymlink);\r\n\tif (!NT_SUCCESS(status)) {\r\n\t\treturn status;\r\n\t}\r\n\r\n\t// The system will not send I/O requests or Windows Management Instrumentation (WMI) requests to a control device object unless the driver has called WdfControlFinishInitializing.\r\n\tWdfControlFinishInitializing(*device);\r\n\r\n\treturn STATUS_SUCCESS;\r\n}\r\n\r\nvoid* pm_WdfObjectGetTypedContextWorker(WDFOBJECT wdfObject, PCWDF_OBJECT_CONTEXT_TYPE_INFO typeInfo) {\r\n    return WdfObjectGetTypedContextWorker(wdfObject, typeInfo->UniqueType);\r\n}\r\n\r\nDEVICE_OBJECT* pm_GetDeviceObject(WDFDEVICE device) {\r\n    return WdfDeviceWdmGetDeviceObject(device);\r\n}\r\n\r\nUINT64 pm_QuerySystemTime() {\r\n\tUINT64 timestamp = 0;\r\n\tKeQuerySystemTime(&timestamp);\r\n\treturn timestamp;\r\n}"
  },
  {
    "path": "windows_kext/driver/.cargo/config.toml",
    "content": "[build]\ntarget = \"x86_64-pc-windows-msvc\"\nrustflags = [\"-C\", \"panic=abort\"]\n"
  },
  {
    "path": "windows_kext/driver/Cargo.toml",
    "content": "[package]\nname = \"driver\"\nversion = \"0.0.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[lib]\nname = \"driver\"\npath = \"src/lib.rs\"\ncrate-type = [\"staticlib\"]\n\n[dependencies]\nwdk = { path = \"../wdk\" }\nprotocol = { path = \"../protocol\" }\nnum = { version = \"0.4\", default-features = false }\nnum-derive = { version = \"0.4\", default-features = false }\nnum-traits = { version = \"0.2\", default-features = false }\nsmoltcp = { version = \"0.10\", default-features = false, features = [\"proto-ipv4\", \"proto-ipv6\"] }\n\n# WARNING: Do not update. The version was choosen for a reason. See wdk/README.md for more detiels.\n[dependencies.windows-sys]\ngit = \"https://github.com/microsoft/windows-rs\"\nrev = \"dffa8b03dc4987c278d82e88015ffe96aa8ac317\"\nfeatures = [\"Wdk_Foundation\", \"Wdk_Storage_FileSystem\", \"Wdk_System_SystemServices\", \"Win32_Foundation\", \"Win32_Security\", \"Win32_System_IO\", \"Win32_System_Kernel\", \"Win32_System_Power\", \"Win32_System_WindowsProgramming\", \"Win32_NetworkManagement_IpHelper\", \"Win32_Networking_WinSock\", \"Win32_NetworkManagement_WindowsFilteringPlatform\"]\n"
  },
  {
    "path": "windows_kext/driver/Makefile.toml",
    "content": "[env.development]\nTARGET_PATH = \"target/x86_64-pc-windows-msvc/debug\"\n\n[env.production]\nTARGET_PATH = \"target/x86_64-pc-windows-msvc/release\"\nBUILD_FLAGS = \"--release\"\n\n[tasks.build-driver]\nscript = [\n    \"cargo build $BUILD_FLAGS\",\n]\n\n[tasks.upload]\ndependencies = [\"build-driver\"]\nscript = [\n    \"scp $TARGET_PATH/driver.lib windows:'C:/Dev/'\",\n]\n\n"
  },
  {
    "path": "windows_kext/driver/README.md",
    "content": "# Driver\n\nThis is the entry point of the Kernel extension.\n\n## Quick overview\n\n`entry.rs`:\nThis file contains the entry point and calling all the needed initialization code. \n- Setting up the driver object\n- Allocating global state\n\n`fn driver_entry()` -> entry pointer of the driver.\n\n`device.rs`:  \nHolds the global state of the driver.  \nInitialization: Setting up global state, Filter engine and callouts.  \n\nPortmaster communication:\nThe communication happens concurrently with the File read/write API.\nThat means when Pormtaster sends a command the kernel extension will start to process it and queue the result in the `IOQueue`.\n\n`fn read()` -> called on read request from Portmaster  \n- `IOQueue` holds all the events queued for Portmaster.\n\nBlocks until there is a element that can be poped or shutdown request is sent from Portmaster.\nIf there is more then one event in the queue it will write as much as it can in the supplied buffer.\n\n`fn write()` -> called on write request from Portmaster.  \nUsed when Portmaster wants to send a command to kernel extension.\nVerdict Response, GetLogs ... (see `protocol` for list of all the commands)\n\n\n## Callouts\n\n`callouts.rs` -> defines the list of all used callouts in the kernel extension. \n\nALE (Application Layer Enforcement)\nhttps://learn.microsoft.com/en-us/windows/win32/fwp/application-layer-enforcement--ale-\n\n### ALE Auth\n\nConnection level filtering. It will make a decision based on the first packet of a connection. Works together with the packet layer to provide firewall functionality.\n- **AleLayerOutboundV4**  \n- **AleLayerInboundV4**  \n- **AleLayerOutboundV6**  \n- **AleLayerInboundV6**  \n\n\n### ALE endpoint / resource assignment and release\n\nUsed to listen for event when connection has ended. Does no filtering.\n- **AleEndpointClosureV4, AleEndpointClosureV6** - Triggered when connection to an endpoint has ended. Usually only TCP is triggered.  The triggered connection will be marked for deletion.\n\n- **AleResourceAssignmentV4, AleResourceAssignmentV6** -> only for logging (not used)\n- AleResourceReleaseV4, AleResourceReleaseV6 -> Triggered when port is release from an application. The triggered connection/s will be marked for deletion.\n\n### Stream layer  \n\nThis layer works on the application OSI layer. Meaning that only the payload of the TCP/UDP connection will be available.\nIt is used for bandwidth monitoring. This functionality is completely separate from the rest of the system so it can be disabled or enabled without affect anything else. \n\n- **StreamLayerV4, StreamLayerV6** -> For TCP connections \n- **DatagramDataLayerV4, DatagramDataLayerV6** -> For UDP connections\n\n\n### Packet layer\n\nThis layer handled each packet on the network OSI layer. Works together with ALE Auth layer to provide firewall functionality.\n- **IPPacketOutboundV4, IPPacketOutboundV6** -> Triggered on every outbound packet.\n- **IPPacketInboundV4, IPPacketInboundV6** -> Triggered on every inbound packet.\n"
  },
  {
    "path": "windows_kext/driver/rust-toolchain",
    "content": "stable\n"
  },
  {
    "path": "windows_kext/driver/src/ale_callouts.rs",
    "content": "use crate::connection::{Connection, ConnectionV4, ConnectionV6, Direction, Verdict};\r\nuse crate::connection_map::Key;\r\nuse crate::device::{Device, Packet};\r\n\r\nuse crate::info;\r\nuse smoltcp::wire::{\r\n    IpAddress, IpProtocol, Ipv4Address, Ipv6Address, IPV4_HEADER_LEN, IPV6_HEADER_LEN,\r\n};\r\nuse wdk::filter_engine::callout_data::CalloutData;\r\nuse wdk::filter_engine::layer::{self, FieldsAleAuthConnectV4, FieldsAleAuthConnectV6, ValueType};\r\nuse wdk::filter_engine::net_buffer::NetBufferList;\r\nuse wdk::filter_engine::packet::{Injector, TransportPacketList};\r\n\r\n// ALE Layers\r\n\r\n#[derive(Debug)]\r\n#[allow(dead_code)]\r\nstruct AleLayerData {\r\n    is_ipv6: bool,\r\n    reauthorize: bool,\r\n    process_id: u64,\r\n    protocol: IpProtocol,\r\n    direction: Direction,\r\n    local_ip: IpAddress,\r\n    local_port: u16,\r\n    remote_ip: IpAddress,\r\n    remote_port: u16,\r\n    interface_index: u32,\r\n    sub_interface_index: u32,\r\n}\r\n\r\nimpl AleLayerData {\r\n    fn as_key(&self) -> Key {\r\n        let mut local_port = 0;\r\n        let mut remote_port = 0;\r\n        match self.protocol {\r\n            IpProtocol::Tcp | IpProtocol::Udp => {\r\n                local_port = self.local_port;\r\n                remote_port = self.remote_port;\r\n            }\r\n            _ => {}\r\n        }\r\n\r\n        Key {\r\n            protocol: self.protocol,\r\n            local_address: self.local_ip,\r\n            local_port,\r\n            remote_address: self.remote_ip,\r\n            remote_port,\r\n        }\r\n    }\r\n}\r\n\r\nfn get_protocol(data: &CalloutData, index: usize) -> IpProtocol {\r\n    IpProtocol::from(data.get_value_u8(index))\r\n}\r\n\r\nfn get_ipv4_address(data: &CalloutData, index: usize) -> IpAddress {\r\n    IpAddress::Ipv4(Ipv4Address::from_bytes(\r\n        &data.get_value_u32(index).to_be_bytes(),\r\n    ))\r\n}\r\n\r\nfn get_ipv6_address(data: &CalloutData, index: usize) -> IpAddress {\r\n    IpAddress::Ipv6(Ipv6Address::from_bytes(data.get_value_byte_array16(index)))\r\n}\r\n\r\npub fn ale_layer_connect_v4(data: CalloutData) {\r\n    type Fields = FieldsAleAuthConnectV4;\r\n    let ale_data = AleLayerData {\r\n        is_ipv6: false,\r\n        reauthorize: data.is_reauthorize(Fields::Flags as usize),\r\n        process_id: data.get_process_id().unwrap_or(0),\r\n        protocol: get_protocol(&data, Fields::IpProtocol as usize),\r\n        direction: Direction::Outbound,\r\n        local_ip: get_ipv4_address(&data, Fields::IpLocalAddress as usize),\r\n        local_port: data.get_value_u16(Fields::IpLocalPort as usize),\r\n        remote_ip: get_ipv4_address(&data, Fields::IpRemoteAddress as usize),\r\n        remote_port: data.get_value_u16(Fields::IpRemotePort as usize),\r\n        interface_index: 0,\r\n        sub_interface_index: 0,\r\n    };\r\n\r\n    ale_layer_auth(data, ale_data);\r\n}\r\n\r\npub fn ale_layer_connect_v6(data: CalloutData) {\r\n    type Fields = FieldsAleAuthConnectV6;\r\n\r\n    let ale_data = AleLayerData {\r\n        is_ipv6: true,\r\n        reauthorize: data.is_reauthorize(Fields::Flags as usize),\r\n        process_id: data.get_process_id().unwrap_or(0),\r\n        protocol: get_protocol(&data, Fields::IpProtocol as usize),\r\n        direction: Direction::Outbound,\r\n        local_ip: get_ipv6_address(&data, Fields::IpLocalAddress as usize),\r\n        local_port: data.get_value_u16(Fields::IpLocalPort as usize),\r\n        remote_ip: get_ipv6_address(&data, Fields::IpRemoteAddress as usize),\r\n        remote_port: data.get_value_u16(Fields::IpRemotePort as usize),\r\n        interface_index: data.get_value_u32(Fields::InterfaceIndex as usize),\r\n        sub_interface_index: data.get_value_u32(Fields::SubInterfaceIndex as usize),\r\n    };\r\n\r\n    ale_layer_auth(data, ale_data);\r\n}\r\n\r\nfn ale_layer_auth(mut data: CalloutData, ale_data: AleLayerData) {\r\n    // Make the default path as drop.\r\n    data.block_and_absorb();\r\n\r\n    let Some(device) = crate::entry::get_device() else {\r\n        return;\r\n    };\r\n\r\n    // Check if packet was previously injected from the packet layer.\r\n    if device\r\n        .injector\r\n        .was_network_packet_injected_by_self(data.get_layer_data() as _, ale_data.is_ipv6)\r\n    {\r\n        data.action_permit();\r\n        return;\r\n    }\r\n\r\n    match ale_data.protocol {\r\n        IpProtocol::Tcp | IpProtocol::Udp => {\r\n            // Only TCP and UDP make sense to be supported in the ALE layer.\r\n            // Everything else is not associated with a connection and will be handled in the packet layer.\r\n        }\r\n        _ => {\r\n            // Outbound: Will be handled by packet layer next.\r\n            // Inbound: Was already handled by the packet layer.\r\n            data.action_permit();\r\n            return;\r\n        }\r\n    }\r\n\r\n    let key = ale_data.as_key();\r\n\r\n    // Check if connection is already in cache.\r\n    let verdict = if ale_data.is_ipv6 {\r\n        device\r\n            .connection_cache\r\n            .read_connection_v6(&key, |conn| -> Option<Verdict> {\r\n                // Function is behind spin lock, just copy and return.\r\n                Some(conn.verdict)\r\n            })\r\n    } else {\r\n        device\r\n            .connection_cache\r\n            .read_connection_v4(&ale_data.as_key(), |conn| -> Option<Verdict> {\r\n                // Function is behind spin lock, just copy and return.\r\n                Some(conn.verdict)\r\n            })\r\n    };\r\n\r\n    // Connection already in cache.\r\n    if let Some(verdict) = verdict {\r\n        crate::dbg!(\"processing existing connection: {} {}\", key, verdict);\r\n        match verdict {\r\n            // No verdict yet\r\n            Verdict::Undecided => {\r\n                crate::dbg!(\"saving packet: {}\", key);\r\n                // Connection is already pended. Save packet and wait for verdict.\r\n                match save_packet(device, &mut data, &ale_data, false) {\r\n                    Ok(packet) => {\r\n                        let info = device.packet_cache.push(\r\n                            (key, packet),\r\n                            ale_data.process_id,\r\n                            ale_data.direction,\r\n                            true,\r\n                        );\r\n                        if let Some(info) = info {\r\n                            let _ = device.event_queue.push(info);\r\n                        }\r\n                    }\r\n                    Err(err) => {\r\n                        crate::err!(\"failed to pend packet: {}\", err);\r\n                    }\r\n                };\r\n                data.block_and_absorb();\r\n            }\r\n            // There is a verdict\r\n            Verdict::PermanentAccept\r\n            | Verdict::Accept\r\n            | Verdict::RedirectNameServer\r\n            | Verdict::RedirectTunnel\r\n            | Verdict::RedirectSplitTunnel => {\r\n                // Continue to packet layer.\r\n                data.action_permit();\r\n\r\n                if device.is_owner_pid(ale_data.process_id as u32) && matches!(ale_data.direction, Direction::Outbound) {\r\n                    // If this is Portmaster's own outbound connection, clear the write flag\r\n                    // to prevent subsequent filters in the chain from overriding the permit action.\r\n                    // This prevents other firewall applications from blocking Portmaster's own connections.\r\n                    data.clear_write_flag();\r\n                }\r\n            }\r\n            Verdict::PermanentBlock | Verdict::Undeterminable | Verdict::Failed => {\r\n                // Packet layer will not see this connection.\r\n                crate::dbg!(\"permanent block {}\", key);\r\n                data.action_block_hard();\r\n            }\r\n            Verdict::PermanentDrop => {\r\n                // Packet layer will not see this connection.\r\n                crate::dbg!(\"permanent drop {}\", key);\r\n                data.block_and_absorb();\r\n            }\r\n            Verdict::Block => {\r\n                if let Direction::Outbound = ale_data.direction {\r\n                    // Handled by packet layer.\r\n                    data.action_permit();\r\n                } else {\r\n                    // packet layer will still see the packets.\r\n                    data.action_block_hard();\r\n                }\r\n            }\r\n            Verdict::Drop => {\r\n                if let Direction::Outbound = ale_data.direction {\r\n                    // Handled by packet layer.\r\n                    data.action_permit();\r\n                } else {\r\n                    // packet layer will still see the packets.\r\n                    data.block_and_absorb();\r\n                }\r\n            }\r\n        }\r\n    } else {\r\n        crate::dbg!(\"pending connection: {} {}\", key, ale_data.direction);\r\n        // Only first packet of a connection can be pended: reauthorize == false\r\n        let can_pend_connection = !ale_data.reauthorize;\r\n        match save_packet(device, &mut data, &ale_data, can_pend_connection) {\r\n            Ok(packet) => {\r\n                let info = device.packet_cache.push(\r\n                    (key, packet),\r\n                    ale_data.process_id,\r\n                    ale_data.direction,\r\n                    true,\r\n                );\r\n                if let Some(info) = info {\r\n                    let _ = device.event_queue.push(info);\r\n                }\r\n            }\r\n            Err(err) => {\r\n                crate::err!(\"failed to pend packet: {}\", err);\r\n            }\r\n        };\r\n\r\n        // Connection is not in cache, add it.\r\n        crate::dbg!(\r\n            \"ale layer adding connection: {} PID: {}\",\r\n            key,\r\n            ale_data.process_id\r\n        );\r\n        if ale_data.is_ipv6 {\r\n            let conn =\r\n                ConnectionV6::from_key(&key, ale_data.process_id, ale_data.direction).unwrap();\r\n            device.connection_cache.add_connection_v6(conn);\r\n        } else {\r\n            let conn =\r\n                ConnectionV4::from_key(&key, ale_data.process_id, ale_data.direction).unwrap();\r\n            device.connection_cache.add_connection_v4(conn);\r\n        }\r\n\r\n        // Drop packet. It will be re-injected after Portmaster returns a verdict.\r\n        data.block_and_absorb();\r\n    }\r\n}\r\n\r\nfn save_packet(\r\n    device: &Device,\r\n    callout_data: &mut CalloutData,\r\n    ale_data: &AleLayerData,\r\n    pend: bool,\r\n) -> Result<Packet, alloc::string::String> {\r\n    let mut packet_list = None;\r\n    let mut save_packet_list = true;\r\n    if ale_data.protocol == IpProtocol::Tcp {\r\n        if let Direction::Outbound = ale_data.direction {\r\n            // Only time a packet data is missing is during connect state of outbound TCP connection.\r\n            // Don't save packet list only if connection is outbound, reauthorize is false and the protocol is TCP.\r\n            save_packet_list = ale_data.reauthorize;\r\n        }\r\n    };\r\n    if save_packet_list {\r\n        packet_list = create_packet_list(device, callout_data, ale_data);\r\n    }\r\n    if pend && matches!(ale_data.protocol, IpProtocol::Tcp | IpProtocol::Udp) {\r\n        match callout_data.pend_operation(packet_list) {\r\n            Ok(classify_defer) => Ok(Packet::AleLayer(classify_defer)),\r\n            Err(err) => Err(alloc::format!(\"failed to defer connection: {}\", err)),\r\n        }\r\n    } else {\r\n        Ok(Packet::AleLayer(callout_data.pend_filter_rest(packet_list)))\r\n    }\r\n}\r\n\r\nfn create_packet_list(\r\n    device: &Device,\r\n    callout_data: &mut CalloutData,\r\n    ale_data: &AleLayerData,\r\n) -> Option<TransportPacketList> {\r\n    let mut nbl = NetBufferList::new(callout_data.get_layer_data() as _);\r\n    let mut inbound = false;\r\n    if let Direction::Inbound = ale_data.direction {\r\n        if ale_data.is_ipv6 {\r\n            nbl.retreat(IPV6_HEADER_LEN as u32, true);\r\n        } else {\r\n            nbl.retreat(IPV4_HEADER_LEN as u32, true);\r\n        }\r\n        inbound = true;\r\n    }\r\n\r\n    let address: &[u8] = match &ale_data.remote_ip {\r\n        IpAddress::Ipv4(address) => &address.0,\r\n        IpAddress::Ipv6(address) => &address.0,\r\n    };\r\n    if let Ok(clone) = nbl.clone(&device.network_allocator) {\r\n        return Some(Injector::from_ale_callout(\r\n            ale_data.is_ipv6,\r\n            callout_data,\r\n            clone,\r\n            address,\r\n            inbound,\r\n            ale_data.interface_index,\r\n            ale_data.sub_interface_index,\r\n        ));\r\n    }\r\n    return None;\r\n}\r\n\r\npub fn endpoint_closure_v4(data: CalloutData) {\r\n    type Fields = layer::FieldsAleEndpointClosureV4;\r\n    let Some(device) = crate::entry::get_device() else {\r\n        return;\r\n    };\r\n    let ip_address_type = data.get_value_type(Fields::IpLocalAddress as usize);\r\n    if let ValueType::FwpUint32 = ip_address_type {\r\n        let key = Key {\r\n            protocol: get_protocol(&data, Fields::IpProtocol as usize),\r\n            local_address: get_ipv4_address(&data, Fields::IpLocalAddress as usize),\r\n            local_port: data.get_value_u16(Fields::IpLocalPort as usize),\r\n            remote_address: get_ipv4_address(&data, Fields::IpRemoteAddress as usize),\r\n            remote_port: data.get_value_u16(Fields::IpRemotePort as usize),\r\n        };\r\n\r\n        let conn = device.connection_cache.end_connection_v4(key);\r\n        if let Some(conn) = conn {\r\n            let info = protocol::info::connection_end_event_v4_info(\r\n                data.get_process_id().unwrap_or(0),\r\n                conn.get_direction() as u8,\r\n                u8::from(get_protocol(&data, Fields::IpProtocol as usize)),\r\n                conn.local_address.0,\r\n                conn.remote_address.0,\r\n                conn.local_port,\r\n                conn.remote_port,\r\n            );\r\n            let _ = device.event_queue.push(info);\r\n        }\r\n    } else {\r\n        // Invalid ip address type. Just ignore the error.\r\n        // err!(\r\n        //     device.logger,\r\n        //     \"unknown ipv4 address type: {:?}\",\r\n        //     ip_address_type\r\n        // );\r\n    }\r\n}\r\n\r\npub fn endpoint_closure_v6(data: CalloutData) {\r\n    type Fields = layer::FieldsAleEndpointClosureV6;\r\n    let Some(device) = crate::entry::get_device() else {\r\n        return;\r\n    };\r\n    let local_ip_address_type = data.get_value_type(Fields::IpLocalAddress as usize);\r\n    let remote_ip_address_type = data.get_value_type(Fields::IpRemoteAddress as usize);\r\n\r\n    if let ValueType::FwpByteArray16Type = local_ip_address_type {\r\n        if let ValueType::FwpByteArray16Type = remote_ip_address_type {\r\n            let key = Key {\r\n                protocol: get_protocol(&data, Fields::IpProtocol as usize),\r\n                local_address: get_ipv6_address(&data, Fields::IpLocalAddress as usize),\r\n                local_port: data.get_value_u16(Fields::IpLocalPort as usize),\r\n                remote_address: get_ipv6_address(&data, Fields::IpRemoteAddress as usize),\r\n                remote_port: data.get_value_u16(Fields::IpRemotePort as usize),\r\n            };\r\n\r\n            let conn = device.connection_cache.end_connection_v6(key);\r\n            if let Some(conn) = conn {\r\n                let info = protocol::info::connection_end_event_v6_info(\r\n                    data.get_process_id().unwrap_or(0),\r\n                    conn.get_direction() as u8,\r\n                    u8::from(get_protocol(&data, Fields::IpProtocol as usize)),\r\n                    conn.local_address.0,\r\n                    conn.remote_address.0,\r\n                    conn.local_port,\r\n                    conn.remote_port,\r\n                );\r\n                let _ = device.event_queue.push(info);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\npub fn ale_resource_monitor(data: CalloutData) {\r\n    let Some(device) = crate::entry::get_device() else {\r\n        return;\r\n    };\r\n    match data.layer {\r\n        layer::Layer::AleResourceAssignmentV4Discard => {\r\n            type Fields = layer::FieldsAleResourceAssignmentV4;\r\n            if let Some(conns) = device.connection_cache.end_all_on_port_v4((\r\n                get_protocol(&data, Fields::IpProtocol as usize),\r\n                data.get_value_u16(Fields::IpLocalPort as usize),\r\n            )) {\r\n                let process_id = data.get_process_id().unwrap_or(0);\r\n                info!(\r\n                    \"Port {}/{} Ipv4 assign request discarded pid={}\",\r\n                    data.get_value_u16(Fields::IpLocalPort as usize),\r\n                    get_protocol(&data, Fields::IpProtocol as usize),\r\n                    process_id,\r\n                );\r\n                for conn in conns {\r\n                    let info = protocol::info::connection_end_event_v4_info(\r\n                        process_id,\r\n                        conn.get_direction() as u8,\r\n                        data.get_value_u8(Fields::IpProtocol as usize),\r\n                        conn.local_address.0,\r\n                        conn.remote_address.0,\r\n                        conn.local_port,\r\n                        conn.remote_port,\r\n                    );\r\n                    let _ = device.event_queue.push(info);\r\n                }\r\n            }\r\n        }\r\n        layer::Layer::AleResourceAssignmentV6Discard => {\r\n            type Fields = layer::FieldsAleResourceAssignmentV6;\r\n            if let Some(conns) = device.connection_cache.end_all_on_port_v6((\r\n                get_protocol(&data, Fields::IpProtocol as usize),\r\n                data.get_value_u16(Fields::IpLocalPort as usize),\r\n            )) {\r\n                let process_id = data.get_process_id().unwrap_or(0);\r\n                info!(\r\n                    \"Port {}/{} Ipv6 assign request discarded pid={}\",\r\n                    data.get_value_u16(Fields::IpLocalPort as usize),\r\n                    get_protocol(&data, Fields::IpProtocol as usize),\r\n                    process_id,\r\n                );\r\n                for conn in conns {\r\n                    let info = protocol::info::connection_end_event_v6_info(\r\n                        process_id,\r\n                        conn.get_direction() as u8,\r\n                        data.get_value_u8(Fields::IpProtocol as usize),\r\n                        conn.local_address.0,\r\n                        conn.remote_address.0,\r\n                        conn.local_port,\r\n                        conn.remote_port,\r\n                    );\r\n                    let _ = device.event_queue.push(info);\r\n                }\r\n            }\r\n        }\r\n        layer::Layer::AleResourceReleaseV4 => {\r\n            type Fields = layer::FieldsAleResourceReleaseV4;\r\n            if let Some(conns) = device.connection_cache.end_all_on_port_v4((\r\n                get_protocol(&data, Fields::IpProtocol as usize),\r\n                data.get_value_u16(Fields::IpLocalPort as usize),\r\n            )) {\r\n                let process_id = data.get_process_id().unwrap_or(0);\r\n                info!(\r\n                    \"Port {}/{} released pid={}\",\r\n                    data.get_value_u16(Fields::IpLocalPort as usize),\r\n                    get_protocol(&data, Fields::IpProtocol as usize),\r\n                    process_id,\r\n                );\r\n                for conn in conns {\r\n                    let info = protocol::info::connection_end_event_v4_info(\r\n                        process_id,\r\n                        conn.get_direction() as u8,\r\n                        data.get_value_u8(Fields::IpProtocol as usize),\r\n                        conn.local_address.0,\r\n                        conn.remote_address.0,\r\n                        conn.local_port,\r\n                        conn.remote_port,\r\n                    );\r\n                    let _ = device.event_queue.push(info);\r\n                }\r\n            }\r\n        }\r\n        layer::Layer::AleResourceReleaseV6 => {\r\n            type Fields = layer::FieldsAleResourceReleaseV6;\r\n            if let Some(conns) = device.connection_cache.end_all_on_port_v6((\r\n                get_protocol(&data, Fields::IpProtocol as usize),\r\n                data.get_value_u16(Fields::IpLocalPort as usize),\r\n            )) {\r\n                let process_id = data.get_process_id().unwrap_or(0);\r\n                info!(\r\n                    \"Port {}/{} released pid={}\",\r\n                    data.get_value_u16(Fields::IpLocalPort as usize),\r\n                    get_protocol(&data, Fields::IpProtocol as usize),\r\n                    process_id,\r\n                );\r\n                for conn in conns {\r\n                    let info = protocol::info::connection_end_event_v6_info(\r\n                        process_id,\r\n                        conn.get_direction() as u8,\r\n                        data.get_value_u8(Fields::IpProtocol as usize),\r\n                        conn.local_address.0,\r\n                        conn.remote_address.0,\r\n                        conn.local_port,\r\n                        conn.remote_port,\r\n                    );\r\n                    let _ = device.event_queue.push(info);\r\n                }\r\n            }\r\n        }\r\n        _ => {}\r\n    }\r\n}\r\n"
  },
  {
    "path": "windows_kext/driver/src/array_holder.rs",
    "content": "use core::cell::RefCell;\n\nuse alloc::vec::Vec;\n\npub struct ArrayHolder(RefCell<Option<Vec<u8>>>);\nunsafe impl Sync for ArrayHolder {}\n\nimpl ArrayHolder {\n    pub const fn default() -> Self {\n        Self(RefCell::new(None))\n    }\n\n    pub fn save(&self, data: &[u8]) {\n        if let Ok(mut opt) = self.0.try_borrow_mut() {\n            opt.replace(data.to_vec());\n        }\n    }\n\n    pub fn load(&self) -> Option<Vec<u8>> {\n        if let Ok(mut opt) = self.0.try_borrow_mut() {\n            return opt.take();\n        }\n        None\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/bandwidth.rs",
    "content": "use alloc::collections::BTreeMap;\nuse protocol::info::{BandwidthValueV4, BandwidthValueV6, Info};\nuse smoltcp::wire::{IpProtocol, Ipv4Address, Ipv6Address};\nuse wdk::rw_spin_lock::RwSpinLock;\n\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]\npub struct Key<Address: Ord> {\n    pub local_ip: Address,\n    pub local_port: u16,\n    pub remote_ip: Address,\n    pub remote_port: u16,\n}\n\nstruct Value {\n    received_bytes: usize,\n    transmitted_bytes: usize,\n}\n\nenum Direction {\n    Tx(usize),\n    Rx(usize),\n}\npub struct Bandwidth {\n    stats_tcp_v4: BTreeMap<Key<Ipv4Address>, Value>,\n    stats_tcp_v4_lock: RwSpinLock,\n\n    stats_tcp_v6: BTreeMap<Key<Ipv6Address>, Value>,\n    stats_tcp_v6_lock: RwSpinLock,\n\n    stats_udp_v4: BTreeMap<Key<Ipv4Address>, Value>,\n    stats_udp_v4_lock: RwSpinLock,\n\n    stats_udp_v6: BTreeMap<Key<Ipv6Address>, Value>,\n    stats_udp_v6_lock: RwSpinLock,\n}\n\nimpl Bandwidth {\n    pub fn new() -> Self {\n        Self {\n            stats_tcp_v4: BTreeMap::new(),\n            stats_tcp_v4_lock: RwSpinLock::default(),\n\n            stats_tcp_v6: BTreeMap::new(),\n            stats_tcp_v6_lock: RwSpinLock::default(),\n\n            stats_udp_v4: BTreeMap::new(),\n            stats_udp_v4_lock: RwSpinLock::default(),\n\n            stats_udp_v6: BTreeMap::new(),\n            stats_udp_v6_lock: RwSpinLock::default(),\n        }\n    }\n\n    pub fn get_all_updates_tcp_v4(&mut self) -> Option<Info> {\n        let stats_map;\n        {\n            let _guard = self.stats_tcp_v4_lock.write_lock();\n            if self.stats_tcp_v4.is_empty() {\n                return None;\n            }\n            stats_map = core::mem::replace(&mut self.stats_tcp_v4, BTreeMap::new());\n        }\n\n        let mut values = alloc::vec::Vec::with_capacity(stats_map.len());\n        for (key, value) in stats_map.iter() {\n            values.push(BandwidthValueV4 {\n                local_ip: key.local_ip.0,\n                local_port: key.local_port,\n                remote_ip: key.remote_ip.0,\n                remote_port: key.remote_port,\n                transmitted_bytes: value.transmitted_bytes as u64,\n                received_bytes: value.received_bytes as u64,\n            });\n        }\n        Some(protocol::info::bandiwth_stats_array_v4(\n            u8::from(IpProtocol::Tcp),\n            values,\n        ))\n    }\n\n    pub fn get_all_updates_tcp_v6(&mut self) -> Option<Info> {\n        let stats_map;\n        {\n            let _guard = self.stats_tcp_v6_lock.write_lock();\n            if self.stats_tcp_v6.is_empty() {\n                return None;\n            }\n            stats_map = core::mem::replace(&mut self.stats_tcp_v6, BTreeMap::new());\n        }\n\n        let mut values = alloc::vec::Vec::with_capacity(stats_map.len());\n        for (key, value) in stats_map.iter() {\n            values.push(BandwidthValueV6 {\n                local_ip: key.local_ip.0,\n                local_port: key.local_port,\n                remote_ip: key.remote_ip.0,\n                remote_port: key.remote_port,\n                transmitted_bytes: value.transmitted_bytes as u64,\n                received_bytes: value.received_bytes as u64,\n            });\n        }\n        Some(protocol::info::bandiwth_stats_array_v6(\n            u8::from(IpProtocol::Tcp),\n            values,\n        ))\n    }\n\n    pub fn get_all_updates_udp_v4(&mut self) -> Option<Info> {\n        let stats_map;\n        {\n            let _guard = self.stats_udp_v4_lock.write_lock();\n            if self.stats_udp_v4.is_empty() {\n                return None;\n            }\n            stats_map = core::mem::replace(&mut self.stats_udp_v4, BTreeMap::new());\n        }\n\n        let mut values = alloc::vec::Vec::with_capacity(stats_map.len());\n        for (key, value) in stats_map.iter() {\n            values.push(BandwidthValueV4 {\n                local_ip: key.local_ip.0,\n                local_port: key.local_port,\n                remote_ip: key.remote_ip.0,\n                remote_port: key.remote_port,\n                transmitted_bytes: value.transmitted_bytes as u64,\n                received_bytes: value.received_bytes as u64,\n            });\n        }\n        Some(protocol::info::bandiwth_stats_array_v4(\n            u8::from(IpProtocol::Udp),\n            values,\n        ))\n    }\n\n    pub fn get_all_updates_udp_v6(&mut self) -> Option<Info> {\n        let stats_map;\n        {\n            let _guard = self.stats_udp_v6_lock.write_lock();\n            if self.stats_udp_v6.is_empty() {\n                return None;\n            }\n            stats_map = core::mem::replace(&mut self.stats_udp_v6, BTreeMap::new());\n        }\n\n        let mut values = alloc::vec::Vec::with_capacity(stats_map.len());\n        for (key, value) in stats_map.iter() {\n            values.push(BandwidthValueV6 {\n                local_ip: key.local_ip.0,\n                local_port: key.local_port,\n                remote_ip: key.remote_ip.0,\n                remote_port: key.remote_port,\n                transmitted_bytes: value.transmitted_bytes as u64,\n                received_bytes: value.received_bytes as u64,\n            });\n        }\n        Some(protocol::info::bandiwth_stats_array_v6(\n            u8::from(IpProtocol::Udp),\n            values,\n        ))\n    }\n\n    pub fn update_tcp_v4_tx(&mut self, key: Key<Ipv4Address>, tx_bytes: usize) {\n        Self::update(\n            &mut self.stats_tcp_v4,\n            &mut self.stats_tcp_v4_lock,\n            key,\n            Direction::Tx(tx_bytes),\n        );\n    }\n\n    pub fn update_tcp_v4_rx(&mut self, key: Key<Ipv4Address>, rx_bytes: usize) {\n        Self::update(\n            &mut self.stats_tcp_v4,\n            &mut self.stats_tcp_v4_lock,\n            key,\n            Direction::Rx(rx_bytes),\n        );\n    }\n\n    pub fn update_tcp_v6_tx(&mut self, key: Key<Ipv6Address>, tx_bytes: usize) {\n        Self::update(\n            &mut self.stats_tcp_v6,\n            &mut self.stats_tcp_v6_lock,\n            key,\n            Direction::Tx(tx_bytes),\n        );\n    }\n\n    pub fn update_tcp_v6_rx(&mut self, key: Key<Ipv6Address>, rx_bytes: usize) {\n        Self::update(\n            &mut self.stats_tcp_v6,\n            &mut self.stats_tcp_v6_lock,\n            key,\n            Direction::Rx(rx_bytes),\n        );\n    }\n\n    pub fn update_udp_v4_tx(&mut self, key: Key<Ipv4Address>, tx_bytes: usize) {\n        Self::update(\n            &mut self.stats_udp_v4,\n            &mut self.stats_udp_v4_lock,\n            key,\n            Direction::Tx(tx_bytes),\n        );\n    }\n\n    pub fn update_udp_v4_rx(&mut self, key: Key<Ipv4Address>, rx_bytes: usize) {\n        Self::update(\n            &mut self.stats_udp_v4,\n            &mut self.stats_udp_v4_lock,\n            key,\n            Direction::Rx(rx_bytes),\n        );\n    }\n\n    pub fn update_udp_v6_tx(&mut self, key: Key<Ipv6Address>, tx_bytes: usize) {\n        Self::update(\n            &mut self.stats_udp_v6,\n            &mut self.stats_udp_v6_lock,\n            key,\n            Direction::Tx(tx_bytes),\n        );\n    }\n\n    pub fn update_udp_v6_rx(&mut self, key: Key<Ipv6Address>, rx_bytes: usize) {\n        Self::update(\n            &mut self.stats_udp_v6,\n            &mut self.stats_udp_v6_lock,\n            key,\n            Direction::Rx(rx_bytes),\n        );\n    }\n\n    fn update<Address: Ord>(\n        map: &mut BTreeMap<Key<Address>, Value>,\n        lock: &mut RwSpinLock,\n        key: Key<Address>,\n        bytes: Direction,\n    ) {\n        let _guard = lock.write_lock();\n        if let Some(value) = map.get_mut(&key) {\n            match bytes {\n                Direction::Tx(bytes_count) => value.transmitted_bytes += bytes_count,\n                Direction::Rx(bytes_count) => value.received_bytes += bytes_count,\n            }\n        } else {\n            let mut received_bytes = 0;\n            let mut transmitted_bytes = 0;\n            match bytes {\n                Direction::Tx(bytes_count) => transmitted_bytes += bytes_count,\n                Direction::Rx(bytes_count) => received_bytes += bytes_count,\n            }\n            map.insert(\n                key,\n                Value {\n                    received_bytes,\n                    transmitted_bytes,\n                },\n            );\n        }\n    }\n\n    #[allow(dead_code)]\n    pub fn get_entries_count(&self) -> usize {\n        let mut size = 0;\n        {\n            let values = &self.stats_tcp_v4.values();\n            let _guard = self.stats_tcp_v4_lock.read_lock();\n            size += values.len();\n        }\n        {\n            let values = &self.stats_tcp_v6.values();\n            let _guard = self.stats_tcp_v6_lock.read_lock();\n            size += values.len();\n        }\n        {\n            let values = &self.stats_udp_v4.values();\n            let _guard = self.stats_udp_v4_lock.read_lock();\n            size += values.len();\n        }\n        {\n            let values = &self.stats_udp_v6.values();\n            let _guard = self.stats_udp_v6_lock.read_lock();\n            size += values.len();\n        }\n\n        return size;\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/callouts.rs",
    "content": "use alloc::vec::Vec;\nuse wdk::filter_engine::callout::FilterType;\nuse wdk::{\n    consts,\n    filter_engine::{callout::Callout, layer::Layer},\n};\n\nuse crate::{ale_callouts, packet_callouts, stream_callouts};\n\npub fn get_callout_vec() -> Vec<Callout> {\n    alloc::vec![\n        // -----------------------------------------\n        // ALE Auth layers\n        Callout::new(\n            \"Portmaster ALE Outbound IPv4\",\n            \"Portmaster uses this layer to block/permit outgoing ipv4 connections\",\n            0x58545073_f893_454c_bbea_a57bc964f46d,\n            Layer::AleAuthConnectV4,\n            consts::FWP_ACTION_CALLOUT_TERMINATING,\n            FilterType::Resettable,\n            ale_callouts::ale_layer_connect_v4,\n        ),\n        Callout::new(\n            \"Portmaster ALE Outbound IPv6\",\n            \"Portmaster uses this layer to block/permit outgoing ipv6 connections\",\n            0x4bd2a080_2585_478d_977c_7f340c6bc3d4,\n            Layer::AleAuthConnectV6,\n            consts::FWP_ACTION_CALLOUT_TERMINATING,\n            FilterType::Resettable,\n            ale_callouts::ale_layer_connect_v6,\n        ),\n        // -----------------------------------------\n        // ALE connection end layers\n        Callout::new(\n            \"Portmaster Endpoint Closure IPv4\",\n            \"Portmaster uses this layer to detect when a IPv4 connection has ended\",\n            0x58f02845_ace9_4455_ac80_8a84b86fe566,\n            Layer::AleEndpointClosureV4,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            ale_callouts::endpoint_closure_v4,\n        ),\n        Callout::new(\n            \"Portmaster Endpoint Closure IPv6\",\n            \"Portmaster uses this layer to detect when a IPv6 connection has ended\",\n            0x2bc82359_9dc5_4315_9c93_c89467e283ce,\n            Layer::AleEndpointClosureV6,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            ale_callouts::endpoint_closure_v6,\n        ),\n        // -----------------------------------------\n        // ALE resource assignment and release.\n        // Callout::new(\n        //     \"AleResourceAssignmentV4\",\n        //     \"Ipv4 Port assignment monitoring\",\n        //     0x6b9d1985_6f75_4d05_b9b5_1607e187906f,\n        //     Layer::AleResourceAssignmentV4Discard,\n        //     consts::FWP_ACTION_CALLOUT_INSPECTION,\n        //     FilterType::NonResettable,\n        //     ale_callouts::ale_resource_monitor,\n        // ),\n        Callout::new(\n            \"Portmaster resource release IPv4\",\n            \"Portmaster uses this layer to detect when a IPv4 port has been released\",\n            0x7b513bb3_a0be_4f77_a4bc_03c052abe8d7,\n            Layer::AleResourceReleaseV4,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            ale_callouts::ale_resource_monitor,\n        ),\n        // Callout::new(\n        //     \"AleResourceAssignmentV6\",\n        //     \"Ipv4 Port assignment monitor\",\n        //     0xb0d02299_3d3e_437d_916a_f0e96a60cc18,\n        //     Layer::AleResourceAssignmentV6Discard,\n        //     consts::FWP_ACTION_CALLOUT_INSPECTION,\n        //     FilterType::NonResettable,\n        //     ale_callouts::ale_resource_monitor,\n        // ),\n        Callout::new(\n            \"Portmaster resource release IPv6\",\n            \"Portmaster uses this layer to detect when a IPv6 port has been released\",\n            0x6cf36e04_e656_42c3_8cac_a1ce05328bd1,\n            Layer::AleResourceReleaseV6,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            ale_callouts::ale_resource_monitor,\n        ),\n        // -----------------------------------------\n        // Stream layer\n        Callout::new(\n            \"Portmaster Stream IPv4\",\n            \"Portmaster uses this layer for bandwidth statistics of IPv4 TCP connections\",\n            0xe2ca13bf_9710_4caa_a45c_e8c78b5ac780,\n            Layer::StreamV4,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            stream_callouts::stream_layer_tcp_v4,\n        ),\n        Callout::new(\n            \"Portmaster Stream IPv6\",\n            \"Portmaster uses this layer for bandwidth statistics of IPv6 TCP connections\",\n            0x66c549b3_11e2_4b27_8f73_856e6fd82baa,\n            Layer::StreamV6,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            stream_callouts::stream_layer_tcp_v6,\n        ),\n        Callout::new(\n            \"Portmaster Datagram IPv4\",\n            \"Portmaster uses this layer for bandwidth statistics of IPv4 UDP connections\",\n            0xe7eeeaba_168a_45bb_8747_e1a702feb2c5,\n            Layer::DatagramDataV4,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            stream_callouts::stream_layer_udp_v4,\n        ),\n        Callout::new(\n            \"Portmaster Datagram IPv6\",\n            \"Portmaster uses this layer for bandwidth statistics of IPv6 UDP connections\",\n            0xb25862cd_f744_4452_b14a_d0c1e5a25b30,\n            Layer::DatagramDataV6,\n            consts::FWP_ACTION_CALLOUT_INSPECTION,\n            FilterType::NonResettable,\n            stream_callouts::stream_layer_udp_v6,\n        ),\n        // -----------------------------------------\n        // Packet layers\n        Callout::new(\n            \"Portmaster Packet Outbound IPv4\",\n            \"Portmaster uses this layer to redirect/block/permit outgoing ipv4 packets\",\n            0xf3183afe_dc35_49f1_8ea2_b16b5666dd36,\n            Layer::OutboundIppacketV4,\n            consts::FWP_ACTION_CALLOUT_TERMINATING,\n            FilterType::NonResettable,\n            packet_callouts::ip_packet_layer_outbound_v4,\n        ),\n        Callout::new(\n            \"Portmaster Packet Inbound IPv4\",\n            \"Portmaster uses this layer to redirect/block/permit inbound ipv4 packets\",\n            0xf0369374_203d_4bf0_83d2_b2ad3cc17a50,\n            Layer::InboundIppacketV4,\n            consts::FWP_ACTION_CALLOUT_TERMINATING,\n            FilterType::NonResettable,\n            packet_callouts::ip_packet_layer_inbound_v4,\n        ),\n        Callout::new(\n            \"Portmaster Packet Outbound IPv6\",\n            \"Portmaster uses this layer to redirect/block/permit outgoing ipv6 packets\",\n            0x91daf8bc_0908_4bf8_9f81_2c538ab8f25a,\n            Layer::OutboundIppacketV6,\n            consts::FWP_ACTION_CALLOUT_TERMINATING,\n            FilterType::NonResettable,\n            packet_callouts::ip_packet_layer_outbound_v6,\n        ),\n        Callout::new(\n            \"Portmaster Packet Inbound IPv6\",\n            \"Portmaster uses this layer to redirect/block/permit inbound ipv6 packets\",\n            0xfe9faf5f_ceb2_4cd9_9995_f2f2b4f5fcc0,\n            Layer::InboundIppacketV6,\n            consts::FWP_ACTION_CALLOUT_TERMINATING,\n            FilterType::NonResettable,\n            packet_callouts::ip_packet_layer_inbound_v6,\n        )\n    ]\n}\n"
  },
  {
    "path": "windows_kext/driver/src/common.rs",
    "content": "#![allow(dead_code)]\r\n\r\nuse core::fmt::Display;\r\n\r\nuse num_derive::{FromPrimitive, ToPrimitive};\r\n\r\npub const ICMPV4_CODE_DESTINATION_UNREACHABLE: u32 = 3;\r\npub const ICMPV4_CODE_DU_PORT_UNREACHABLE: u32 = 3; // Destination Unreachable (Port unreachable) ;\r\npub const ICMPV4_CODE_DU_ADMINISTRATIVELY_PROHIBITED: u32 = 13; // Destination Unreachable (Communication Administratively Prohibited) ;\r\n\r\npub const ICMPV6_CODE_DESTINATION_UNREACHABLE: u32 = 1;\r\npub const ICMPV6_CODE_DU_PORT_UNREACHABLE: u32 = 4; // Destination Unreachable (Port unreachable) ;\r\n\r\nenum Direction {\r\n    Outbound = 0,\r\n    Inbound = 1,\r\n}\r\n\r\nconst SIOCTL_TYPE: u32 = 40000;\r\nmacro_rules! ctl_code {\r\n    ($device_type:expr, $function:expr, $method:expr, $access:expr) => {\r\n        ($device_type << 16) | ($access << 14) | ($function << 2) | $method\r\n    };\r\n}\r\n\r\npub const METHOD_BUFFERED: u32 = 0;\r\npub const METHOD_IN_DIRECT: u32 = 1;\r\npub const METHOD_OUT_DIRECT: u32 = 2;\r\npub const METHOD_NEITHER: u32 = 3;\r\n\r\npub const FILE_READ_DATA: u32 = 0x0001; // file & pipe\r\npub const FILE_WRITE_DATA: u32 = 0x0002; // file & pipe\r\n\r\n#[repr(u32)]\r\n#[derive(FromPrimitive, ToPrimitive)]\r\npub enum ControlCode {\r\n    Version = ctl_code!(\r\n        SIOCTL_TYPE,\r\n        0x800,\r\n        METHOD_BUFFERED,\r\n        FILE_READ_DATA | FILE_WRITE_DATA\r\n    ),\r\n    ShutdownRequest = ctl_code!(\r\n        SIOCTL_TYPE,\r\n        0x801,\r\n        METHOD_BUFFERED,\r\n        FILE_READ_DATA | FILE_WRITE_DATA\r\n    ),\r\n}\r\n\r\nimpl Display for ControlCode {\r\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\r\n        match self {\r\n            ControlCode::Version => _ = write!(f, \"Version\"),\r\n            ControlCode::ShutdownRequest => _ = write!(f, \"Shutdown\"),\r\n        };\r\n        return Ok(());\r\n    }\r\n}\r\n"
  },
  {
    "path": "windows_kext/driver/src/connection.rs",
    "content": "use alloc::{\n    boxed::Box,\n    string::{String, ToString},\n};\nuse core::{\n    fmt::{Debug, Display},\n    sync::atomic::{AtomicU64, Ordering},\n};\nuse num_derive::FromPrimitive;\nuse smoltcp::wire::{IpAddress, IpProtocol, Ipv4Address, Ipv6Address};\n\nuse crate::connection_map::Key;\n\npub static PM_DNS_PORT:       u16 = 53;\npub static PM_SPN_PORT:       u16 = 717;\npub static PM_SPLIT_TUN_PORT: u16 = 719;\n\n// Make sure this in sync with the Go version\n#[derive(Copy, Clone, FromPrimitive)]\n#[repr(u8)]\n#[rustfmt::skip]\npub enum Verdict {\n    Undecided          = 0, // Undecided is the default status of new connections.\n    Undeterminable     = 1,\n    Accept             = 2,\n    PermanentAccept    = 3,\n    Block              = 4,\n    PermanentBlock     = 5,\n    Drop               = 6,\n    PermanentDrop      = 7,\n    RedirectNameServer = 8,  // redirect to PM_DNS_PORT port\n    RedirectTunnel     = 9,  // redirect to PM_SPN_PORT port\n    Failed             = 10,\n    RedirectSplitTunnel= 11, // redirect to PM_SPLIT_TUN_PORT port\n    // RedirectSplitTunnel must stay last: older Portmaster versions only know verdicts 0–10 and would never send this value.\n}\n\nimpl Display for Verdict {\n    #[rustfmt::skip]\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Verdict::Undecided          => write!(f, \"Undecided\"),\n            Verdict::Undeterminable     => write!(f, \"Undeterminable\"),\n            Verdict::Accept             => write!(f, \"Accept\"),\n            Verdict::PermanentAccept    => write!(f, \"PermanentAccept\"),\n            Verdict::Block              => write!(f, \"Block\"),\n            Verdict::PermanentBlock     => write!(f, \"PermanentBlock\"),\n            Verdict::Drop               => write!(f, \"Drop\"),\n            Verdict::PermanentDrop      => write!(f, \"PermanentDrop\"),\n            Verdict::RedirectNameServer => write!(f, \"RedirectNameServer\"),\n            Verdict::RedirectTunnel     => write!(f, \"RedirectTunnel\"),\n            Verdict::RedirectSplitTunnel=> write!(f, \"RedirectSplitTunnel\"),\n            Verdict::Failed             => write!(f, \"Failed\"),\n        }\n    }\n}\n\n/// Direction of the connection.\n#[derive(Copy, Clone, FromPrimitive)]\n#[repr(u8)]\npub enum Direction {\n    Outbound = 0,\n    Inbound = 1,\n}\n\nimpl Display for Direction {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Direction::Outbound => write!(f, \"Outbound\"),\n            Direction::Inbound => write!(f, \"Inbound\"),\n        }\n    }\n}\n\nimpl Debug for Direction {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"{}\", self)\n    }\n}\n\n#[derive(Clone)]\npub struct ConnectionExtra {\n    pub(crate) end_timestamp: u64,\n    pub(crate) direction: Direction,\n}\n\npub trait Connection {\n    fn redirect_info(&self) -> Option<RedirectInfo> {\n        let redirect_address = if self.is_ipv6() {\n            IpAddress::Ipv6(Ipv6Address::LOOPBACK)\n        } else {\n            IpAddress::Ipv4(Ipv4Address::new(127, 0, 0, 1))\n        };\n\n        match self.get_verdict() {\n            Verdict::RedirectNameServer => Some(RedirectInfo {\n                local_address: self.get_local_address(),\n                remote_address: self.get_remote_address(),\n                remote_port: self.get_remote_port(),\n                redirect_port: PM_DNS_PORT,\n                unify: false,\n                redirect_address,\n            }),\n            Verdict::RedirectTunnel => Some(RedirectInfo {\n                local_address: self.get_local_address(),\n                remote_address: self.get_remote_address(),\n                remote_port: self.get_remote_port(),\n                redirect_port: PM_SPN_PORT,\n                unify: true,\n                redirect_address,\n            }),\n            Verdict::RedirectSplitTunnel => Some(RedirectInfo {\n                local_address: self.get_local_address(),\n                remote_address: self.get_remote_address(),\n                remote_port: self.get_remote_port(),\n                redirect_port: PM_SPLIT_TUN_PORT,\n                unify: true,\n                redirect_address,\n            }),\n            _ => None,\n        }\n    }\n\n    /// Returns the key of the connection.\n    fn get_key(&self) -> Key {\n        Key {\n            protocol: self.get_protocol(),\n            local_address: self.get_local_address(),\n            local_port: self.get_local_port(),\n            remote_address: self.get_remote_address(),\n            remote_port: self.get_remote_port(),\n        }\n    }\n\n    /// Returns true if the connection is equal to the given key. The key is considered equal if the remote port and address are equal.\n    fn remote_equals(&self, key: &Key) -> bool;\n    /// Returns true if the connection is equal to the given key for redirecting. The key is considered equal if the remote port and address are equal.\n    fn redirect_equals(&self, key: &Key) -> bool;\n    /// Returns the protocol of the connection.\n    fn get_protocol(&self) -> IpProtocol;\n    /// Returns the verdict of the connection.\n    fn get_verdict(&self) -> Verdict;\n    /// Returns the local address of the connection.\n    fn get_local_address(&self) -> IpAddress;\n    /// Returns the local port of the connection.\n    fn get_local_port(&self) -> u16;\n    /// Returns the remote address of the connection.\n    fn get_remote_address(&self) -> IpAddress;\n    /// Returns the remote port of the connection.\n    fn get_remote_port(&self) -> u16;\n    /// Returns true if the connection is an IPv6 connection.\n    fn is_ipv6(&self) -> bool;\n    /// Returns the direction of the connection.\n    fn get_direction(&self) -> Direction;\n    // Returns the process id of the connection.\n    fn get_process_id(&self) -> u64;\n    /// Ends the connection.\n    fn end(&mut self, timestamp: u64);\n    /// Returns true if the connection has ended.\n    fn has_ended(&self) -> bool {\n        self.get_end_time() > 0\n    }\n    /// Returns the timestamp when the connection ended.\n    fn get_end_time(&self) -> u64;\n    /// Returns the timestamp when the connection was last accessed.\n    fn get_last_accessed_time(&self) -> u64;\n    /// Sets the timestamp when the connection was last accessed.\n    fn set_last_accessed_time(&self, timestamp: u64);\n}\n\npub struct ConnectionV4 {\n    pub(crate) protocol: IpProtocol,\n    pub(crate) local_address: Ipv4Address,\n    pub(crate) local_port: u16,\n    pub(crate) remote_address: Ipv4Address,\n    pub(crate) remote_port: u16,\n    pub(crate) verdict: Verdict,\n    pub(crate) process_id: u64,\n    pub(crate) last_accessed_timestamp: AtomicU64,\n    pub(crate) extra: Box<ConnectionExtra>,\n}\n\npub struct ConnectionV6 {\n    pub(crate) protocol: IpProtocol,\n    pub(crate) local_address: Ipv6Address,\n    pub(crate) local_port: u16,\n    pub(crate) remote_address: Ipv6Address,\n    pub(crate) remote_port: u16,\n    pub(crate) verdict: Verdict,\n    pub(crate) process_id: u64,\n    pub(crate) last_accessed_timestamp: AtomicU64,\n    pub(crate) extra: Box<ConnectionExtra>,\n}\n\n#[derive(Debug)]\npub struct RedirectInfo {\n    pub(crate) local_address: IpAddress,\n    pub(crate) remote_address: IpAddress,\n    pub(crate) remote_port: u16,\n    pub(crate) redirect_port: u16,\n    pub(crate) unify: bool,\n    pub(crate) redirect_address: IpAddress,\n}\n\nimpl ConnectionV4 {\n    /// Creates a new ipv4 connection from the given key.\n    pub fn from_key(key: &Key, process_id: u64, direction: Direction) -> Result<Self, String> {\n        let IpAddress::Ipv4(local_address) = key.local_address else {\n            return Err(\"wrong ip address version\".to_string());\n        };\n\n        let IpAddress::Ipv4(remote_address) = key.remote_address else {\n            return Err(\"wrong ip address version\".to_string());\n        };\n\n        let timestamp = wdk::utils::get_system_timestamp_ms();\n\n        Ok(Self {\n            protocol: key.protocol,\n            local_address,\n            local_port: key.local_port,\n            remote_address,\n            remote_port: key.remote_port,\n            verdict: Verdict::Undecided,\n            process_id,\n            last_accessed_timestamp: AtomicU64::new(timestamp),\n            extra: Box::new(ConnectionExtra {\n                direction,\n                end_timestamp: 0,\n            }),\n        })\n    }\n}\n\nimpl Connection for ConnectionV4 {\n    fn remote_equals(&self, key: &Key) -> bool {\n        if self.remote_port != key.remote_port {\n            return false;\n        }\n        if let IpAddress::Ipv4(remote_address) = &key.remote_address {\n            return self.remote_address.eq(remote_address);\n        }\n        false\n    }\n\n    fn get_key(&self) -> Key {\n        Key {\n            protocol: self.protocol,\n            local_address: IpAddress::Ipv4(self.local_address),\n            local_port: self.local_port,\n            remote_address: IpAddress::Ipv4(self.remote_address),\n            remote_port: self.remote_port,\n        }\n    }\n\n    fn redirect_equals(&self, key: &Key) -> bool {\n        match self.verdict {\n            Verdict::RedirectNameServer => {\n                if key.remote_port != PM_DNS_PORT {\n                    return false;\n                }\n\n                match key.remote_address {\n                    IpAddress::Ipv4(a) => a.is_loopback(),\n                    IpAddress::Ipv6(_) => false,\n                }\n            }\n            Verdict::RedirectTunnel => {\n                if key.remote_port != PM_SPN_PORT {\n                    return false;\n                }\n                key.local_address.eq(&key.remote_address)\n            }\n            Verdict::RedirectSplitTunnel => {\n                if key.remote_port != PM_SPLIT_TUN_PORT {\n                    return false;\n                }\n                key.local_address.eq(&key.remote_address)\n            }\n            _ => false,\n        }\n    }\n\n    fn get_protocol(&self) -> IpProtocol {\n        self.protocol\n    }\n\n    fn get_verdict(&self) -> Verdict {\n        self.verdict\n    }\n\n    fn get_local_address(&self) -> IpAddress {\n        IpAddress::Ipv4(self.local_address)\n    }\n\n    fn get_local_port(&self) -> u16 {\n        self.local_port\n    }\n\n    fn get_remote_address(&self) -> IpAddress {\n        IpAddress::Ipv4(self.remote_address)\n    }\n\n    fn get_remote_port(&self) -> u16 {\n        self.remote_port\n    }\n\n    fn is_ipv6(&self) -> bool {\n        false\n    }\n\n    fn get_process_id(&self) -> u64 {\n        self.process_id\n    }\n\n    fn get_direction(&self) -> Direction {\n        self.extra.direction\n    }\n\n    fn end(&mut self, timestamp: u64) {\n        self.extra.end_timestamp = timestamp;\n    }\n\n    fn get_end_time(&self) -> u64 {\n        self.extra.end_timestamp\n    }\n\n    fn get_last_accessed_time(&self) -> u64 {\n        self.last_accessed_timestamp.load(Ordering::Relaxed)\n    }\n\n    fn set_last_accessed_time(&self, timestamp: u64) {\n        self.last_accessed_timestamp\n            .store(timestamp, Ordering::Relaxed);\n    }\n}\n\nimpl Clone for ConnectionV4 {\n    fn clone(&self) -> Self {\n        Self {\n            protocol: self.protocol,\n            local_address: self.local_address,\n            local_port: self.local_port,\n            remote_address: self.remote_address,\n            remote_port: self.remote_port,\n            verdict: self.verdict,\n            process_id: self.process_id,\n            last_accessed_timestamp: AtomicU64::new(\n                self.last_accessed_timestamp.load(Ordering::Relaxed),\n            ),\n            extra: self.extra.clone(),\n        }\n    }\n}\n\nimpl ConnectionV6 {\n    /// Creates a new ipv6 connection from the given key.\n    pub fn from_key(key: &Key, process_id: u64, direction: Direction) -> Result<Self, String> {\n        let IpAddress::Ipv6(local_address) = key.local_address else {\n            return Err(\"wrong ip address version\".to_string());\n        };\n\n        let IpAddress::Ipv6(remote_address) = key.remote_address else {\n            return Err(\"wrong ip address version\".to_string());\n        };\n        let timestamp = wdk::utils::get_system_timestamp_ms();\n\n        Ok(Self {\n            protocol: key.protocol,\n            local_address,\n            local_port: key.local_port,\n            remote_address,\n            remote_port: key.remote_port,\n            verdict: Verdict::Undecided,\n            process_id,\n            last_accessed_timestamp: AtomicU64::new(timestamp),\n            extra: Box::new(ConnectionExtra {\n                direction,\n                end_timestamp: 0,\n            }),\n        })\n    }\n}\n\nimpl Connection for ConnectionV6 {\n    fn remote_equals(&self, key: &Key) -> bool {\n        if self.remote_port != key.remote_port {\n            return false;\n        }\n        if let IpAddress::Ipv6(remote_address) = &key.remote_address {\n            return self.remote_address.eq(remote_address);\n        }\n        false\n    }\n    fn get_key(&self) -> Key {\n        Key {\n            protocol: self.protocol,\n            local_address: IpAddress::Ipv6(self.local_address),\n            local_port: self.local_port,\n            remote_address: IpAddress::Ipv6(self.remote_address),\n            remote_port: self.remote_port,\n        }\n    }\n\n    fn redirect_equals(&self, key: &Key) -> bool {\n        match self.verdict {\n            Verdict::RedirectNameServer => {\n                if key.remote_port != PM_DNS_PORT {\n                    return false;\n                }\n\n                match key.remote_address {\n                    IpAddress::Ipv4(_) => false,\n                    IpAddress::Ipv6(a) => a.is_loopback(),\n                }\n            }\n            Verdict::RedirectTunnel => {\n                if key.remote_port != PM_SPN_PORT {\n                    return false;\n                }\n                key.local_address.eq(&key.remote_address)\n            }\n            Verdict::RedirectSplitTunnel => {\n                if key.remote_port != PM_SPLIT_TUN_PORT {\n                    return false;\n                }\n                key.local_address.eq(&key.remote_address)\n            }\n            _ => false,\n        }\n    }\n\n    fn get_protocol(&self) -> IpProtocol {\n        self.protocol\n    }\n\n    fn get_verdict(&self) -> Verdict {\n        self.verdict\n    }\n\n    fn get_local_address(&self) -> IpAddress {\n        IpAddress::Ipv6(self.local_address)\n    }\n\n    fn get_local_port(&self) -> u16 {\n        self.local_port\n    }\n\n    fn get_remote_address(&self) -> IpAddress {\n        IpAddress::Ipv6(self.remote_address)\n    }\n\n    fn get_remote_port(&self) -> u16 {\n        self.remote_port\n    }\n\n    fn is_ipv6(&self) -> bool {\n        true\n    }\n\n    fn get_process_id(&self) -> u64 {\n        self.process_id\n    }\n\n    fn get_direction(&self) -> Direction {\n        self.extra.direction\n    }\n\n    fn end(&mut self, timestamp: u64) {\n        self.extra.end_timestamp = timestamp;\n    }\n\n    fn get_end_time(&self) -> u64 {\n        self.extra.end_timestamp\n    }\n\n    fn get_last_accessed_time(&self) -> u64 {\n        self.last_accessed_timestamp.load(Ordering::Relaxed)\n    }\n\n    fn set_last_accessed_time(&self, timestamp: u64) {\n        self.last_accessed_timestamp\n            .store(timestamp, Ordering::Relaxed);\n    }\n}\n\nimpl Clone for ConnectionV6 {\n    fn clone(&self) -> Self {\n        Self {\n            protocol: self.protocol,\n            local_address: self.local_address,\n            local_port: self.local_port,\n            remote_address: self.remote_address,\n            remote_port: self.remote_port,\n            verdict: self.verdict,\n            process_id: self.process_id,\n            last_accessed_timestamp: AtomicU64::new(\n                self.last_accessed_timestamp.load(Ordering::Relaxed),\n            ),\n            extra: self.extra.clone(),\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/connection_cache.rs",
    "content": "use crate::{\n    connection::{Connection, ConnectionV4, ConnectionV6, RedirectInfo, Verdict},\n    connection_map::{ConnectionMap, Key},\n};\nuse alloc::vec::Vec;\n\nuse smoltcp::wire::IpProtocol;\nuse wdk::rw_spin_lock::RwSpinLock;\n\npub struct ConnectionCache {\n    connections_v4: ConnectionMap<ConnectionV4>,\n    connections_v6: ConnectionMap<ConnectionV6>,\n    lock_v4: RwSpinLock,\n    lock_v6: RwSpinLock,\n}\n\nimpl ConnectionCache {\n    pub fn new() -> Self {\n        Self {\n            connections_v4: ConnectionMap::new(),\n            connections_v6: ConnectionMap::new(),\n            lock_v4: RwSpinLock::default(),\n            lock_v6: RwSpinLock::default(),\n        }\n    }\n\n    pub fn add_connection_v4(&mut self, connection: ConnectionV4) {\n        let _guard = self.lock_v4.write_lock();\n        self.connections_v4.add(connection);\n    }\n\n    pub fn add_connection_v6(&mut self, connection: ConnectionV6) {\n        let _guard = self.lock_v6.write_lock();\n        self.connections_v6.add(connection);\n    }\n\n    pub fn update_connection(&mut self, key: Key, verdict: Verdict) -> Option<RedirectInfo> {\n        if key.is_ipv6() {\n            let _guard = self.lock_v6.write_lock();\n            if let Some(conn) = self.connections_v6.get_mut(&key) {\n                conn.verdict = verdict;\n                return conn.redirect_info();\n            }\n        } else {\n            let _guard = self.lock_v4.write_lock();\n            if let Some(conn) = self.connections_v4.get_mut(&key) {\n                conn.verdict = verdict;\n                return conn.redirect_info();\n            }\n        }\n        None\n    }\n\n    pub fn read_connection_v4<T>(\n        &self,\n        key: &Key,\n        process_connection: fn(&ConnectionV4) -> Option<T>,\n    ) -> Option<T> {\n        let _guard = self.lock_v4.read_lock();\n        self.connections_v4.read(key, process_connection)\n    }\n\n    pub fn read_connection_v6<T>(\n        &self,\n        key: &Key,\n        process_connection: fn(&ConnectionV6) -> Option<T>,\n    ) -> Option<T> {\n        let _guard = self.lock_v6.read_lock();\n        self.connections_v6.read(key, process_connection)\n    }\n\n    pub fn end_connection_v4(&mut self, key: Key) -> Option<ConnectionV4> {\n        let _guard = self.lock_v4.write_lock();\n        self.connections_v4.end(key)\n    }\n\n    pub fn end_connection_v6(&mut self, key: Key) -> Option<ConnectionV6> {\n        let _guard = self.lock_v6.write_lock();\n        self.connections_v6.end(key)\n    }\n\n    pub fn end_all_on_port_v4(&mut self, key: (IpProtocol, u16)) -> Option<Vec<ConnectionV4>> {\n        let _guard = self.lock_v4.write_lock();\n        self.connections_v4.end_all_on_port(key)\n    }\n\n    pub fn end_all_on_port_v6(&mut self, key: (IpProtocol, u16)) -> Option<Vec<ConnectionV6>> {\n        let _guard = self.lock_v6.write_lock();\n        self.connections_v6.end_all_on_port(key)\n    }\n\n    pub fn clean_ended_connections(&mut self) {\n        {\n            let _guard = self.lock_v4.write_lock();\n            self.connections_v4.clean_ended_connections();\n        }\n        {\n            let _guard = self.lock_v6.write_lock();\n            self.connections_v6.clean_ended_connections();\n        }\n    }\n\n    pub fn clear(&mut self) {\n        {\n            let _guard = self.lock_v4.write_lock();\n            self.connections_v4.clear();\n        }\n        {\n            let _guard = self.lock_v6.write_lock();\n            self.connections_v6.clear();\n        }\n    }\n\n    #[allow(dead_code)]\n    pub fn get_entries_count(&self) -> usize {\n        let mut size = 0;\n        {\n            let _guard = self.lock_v4.read_lock();\n            size += self.connections_v4.get_count();\n        }\n\n        {\n            let _guard = self.lock_v6.read_lock();\n            size += self.connections_v6.get_count();\n        }\n\n        return size;\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/connection_map.rs",
    "content": "use core::{fmt::Display, time::Duration};\n\nuse crate::connection::Connection;\nuse alloc::{collections::BTreeMap, vec::Vec};\nuse smoltcp::wire::{IpAddress, IpProtocol};\n\n#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]\npub struct Key {\n    pub(crate) protocol: IpProtocol,\n    pub(crate) local_address: IpAddress,\n    pub(crate) local_port: u16,\n    pub(crate) remote_address: IpAddress,\n    pub(crate) remote_port: u16,\n}\n\nimpl Display for Key {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        write!(\n            f,\n            \"p: {} l: {}:{} r: {}:{}\",\n            self.protocol,\n            self.local_address,\n            self.local_port,\n            self.remote_address,\n            self.remote_port\n        )\n    }\n}\n\nimpl Key {\n    /// Returns the protocol and port as a tuple.\n    pub fn small(&self) -> (IpProtocol, u16) {\n        (self.protocol, self.local_port)\n    }\n\n    /// Returns true if the local address is an IPv4 address.\n    pub fn is_ipv6(&self) -> bool {\n        match self.local_address {\n            IpAddress::Ipv4(_) => false,\n            IpAddress::Ipv6(_) => true,\n        }\n    }\n\n    /// Returns true if the local address is a loopback address.\n    pub fn is_loopback(&self) -> bool {\n        match self.local_address {\n            IpAddress::Ipv4(ip) => ip.is_loopback(),\n            IpAddress::Ipv6(ip) => ip.is_loopback(),\n        }\n    }\n\n    /// Returns a new key with the local and remote addresses and ports reversed.\n    #[allow(dead_code)]\n    pub fn reverse(&self) -> Key {\n        Key {\n            protocol: self.protocol,\n            local_address: self.remote_address,\n            local_port: self.remote_port,\n            remote_address: self.local_address,\n            remote_port: self.local_port,\n        }\n    }\n}\n\npub struct ConnectionMap<T: Connection>(BTreeMap<(IpProtocol, u16), Vec<T>>);\n\nimpl<T: Connection + Clone> ConnectionMap<T> {\n    pub fn new() -> Self {\n        Self(BTreeMap::new())\n    }\n\n    pub fn add(&mut self, conn: T) {\n        let key = conn.get_key().small();\n        if let Some(connections) = self.0.get_mut(&key) {\n            connections.push(conn);\n        } else {\n            self.0.insert(key, alloc::vec![conn]);\n        }\n    }\n\n    pub fn get_mut(&mut self, key: &Key) -> Option<&mut T> {\n        if let Some(connections) = self.0.get_mut(&key.small()) {\n            for conn in connections {\n                if conn.remote_equals(key) {\n                    conn.set_last_accessed_time(wdk::utils::get_system_timestamp_ms());\n                    return Some(conn);\n                }\n            }\n        }\n\n        None\n    }\n\n    pub fn read<C>(&self, key: &Key, read_connection: fn(&T) -> Option<C>) -> Option<C> {\n        if let Some(connections) = self.0.get(&key.small()) {\n            for conn in connections {\n                if conn.remote_equals(key) {\n                    conn.set_last_accessed_time(wdk::utils::get_system_timestamp_ms());\n                    return read_connection(conn);\n                }\n                if conn.redirect_equals(key) {\n                    conn.set_last_accessed_time(wdk::utils::get_system_timestamp_ms());\n                    return read_connection(conn);\n                }\n            }\n        }\n\n        None\n    }\n\n    pub fn end(&mut self, key: Key) -> Option<T> {\n        if let Some(connections) = self.0.get_mut(&key.small()) {\n            for conn in connections.iter_mut() {\n                if conn.remote_equals(&key) {\n                    conn.end(wdk::utils::get_system_timestamp_ms());\n                    return Some(conn.clone());\n                }\n            }\n        }\n        return None;\n    }\n\n    pub fn end_all_on_port(&mut self, key: (IpProtocol, u16)) -> Option<Vec<T>> {\n        if let Some(connections) = self.0.get_mut(&key) {\n            let mut vec = Vec::with_capacity(connections.len());\n            for conn in connections.iter_mut() {\n                if !conn.has_ended() {\n                    conn.end(wdk::utils::get_system_timestamp_ms());\n                    vec.push(conn.clone());\n                }\n            }\n            return Some(vec);\n        }\n        return None;\n    }\n\n    pub fn clear(&mut self) {\n        self.0.clear();\n    }\n\n    pub fn clean_ended_connections(&mut self) {\n        let now = wdk::utils::get_system_timestamp_ms();\n        const TEN_MINUETS: u64 = Duration::from_secs(60 * 10).as_millis() as u64;\n        let before_ten_minutes = now - TEN_MINUETS;\n        let before_one_minute = now - Duration::from_secs(60).as_millis() as u64;\n\n        for (_, connections) in self.0.iter_mut() {\n            connections.retain(|c| {\n                if c.has_ended() && c.get_end_time() < before_one_minute {\n                    // Ended more than 1 minute ago\n                    return false;\n                }\n\n                if c.get_last_accessed_time() < before_ten_minutes {\n                    // Last active more than 10 minutes ago\n                    return false;\n                }\n\n                // Keep\n                return true;\n            });\n        }\n        self.0.retain(|_, v| !v.is_empty());\n    }\n\n    pub fn get_count(&self) -> usize {\n        let mut count = 0;\n        for conn in self.0.values() {\n            count += conn.len();\n        }\n        return count;\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/device.rs",
    "content": "use alloc::string::String;\nuse core::sync::atomic::{AtomicU32, Ordering};\nuse num_traits::FromPrimitive;\nuse protocol::{command::CommandType, info::Info};\nuse smoltcp::wire::{IpAddress, IpProtocol, Ipv4Address, Ipv6Address};\nuse wdk::{\n    driver::Driver,\n    filter_engine::{\n        callout_data::ClassifyDefer,\n        net_buffer::{NetBufferList, NetworkAllocator},\n        packet::{InjectInfo, Injector},\n        FilterEngine,\n    },\n    ioqueue::{self, IOQueue},\n    irp_helpers::{ReadRequest, WriteRequest},\n};\n\nuse crate::{\n    array_holder::ArrayHolder, bandwidth::Bandwidth, callouts, connection_cache::ConnectionCache,\n    connection_map::Key, dbg, err, id_cache::IdCache, logger, packet_util::Redirect,\n};\n\npub enum Packet {\n    PacketLayer(NetBufferList, InjectInfo),\n    AleLayer(ClassifyDefer),\n}\n\n// Device Context\npub struct Device {\n    pub(crate) filter_engine: FilterEngine,\n    pub(crate) read_leftover: ArrayHolder,\n    pub(crate) event_queue: IOQueue<Info>,          // Queue for events to user-space\n    pub(crate) packet_cache: IdCache,               // Cache of pending packets waiting for verdict\n    pub(crate) connection_cache: ConnectionCache,   // Cache of connections and their verdicts\n    pub(crate) injector: Injector,\n    pub(crate) network_allocator: NetworkAllocator,\n    pub(crate) bandwidth_stats: Bandwidth,\n    /// PID of the user-space process that currently holds the device handle open.\n    /// Written once on IRP_MJ_CREATE, cleared on IRP_MJ_CLEANUP.\n    /// AtomicU32 gives lock-free reads in callouts with zero overhead.\n    pub(crate) owner_pid: AtomicU32,\n}\n\nimpl Device {\n    /// Initialize all members of the device. Memory is handled by windows.\n    /// Make sure everything is initialized here.\n    pub fn new(driver: &Driver) -> Result<Self, String> {\n        let mut filter_engine =\n            match FilterEngine::new(driver, 0x7dab1057_8e2b_40c4_9b85_693e381d7896) {\n                Ok(fe) => fe,\n                Err(err) => return Err(alloc::format!(\"filter engine error: {}\", err)),\n            };\n\n        filter_engine.commit(callouts::get_callout_vec())?;\n\n        Ok(Self {\n            filter_engine,\n            read_leftover: ArrayHolder::default(),\n            event_queue: IOQueue::new(),\n            packet_cache: IdCache::new(),\n            connection_cache: ConnectionCache::new(),\n            injector: Injector::new(),\n            network_allocator: NetworkAllocator::new(),\n            bandwidth_stats: Bandwidth::new(),\n            owner_pid: AtomicU32::new(0),\n        })\n    }\n\n    /// Returns the PID of the process that currently has the device handle open, or 0 if none.\n    pub fn is_owner_pid(&self, pid: u32) -> bool {\n        let p = self.owner_pid.load(Ordering::Acquire);\n        p != 0 && p == pid\n    }\n\n    /// Cleanup is called just before drop.\n    // pub fn cleanup(&mut self) {}\n\n    fn write_buffer(&mut self, read_request: &mut ReadRequest, info: Info) {\n        let bytes = info.as_bytes();\n        let count = read_request.write(bytes);\n\n        // Check if the full buffer was written.\n        if count < bytes.len() {\n            // Save the leftovers for later.\n            self.read_leftover.save(&bytes[count..]);\n        }\n    }\n\n    /// Called when handle. Read is called from user-space.\n    pub fn read(&mut self, read_request: &mut ReadRequest) {\n        if let Some(data) = self.read_leftover.load() {\n            // There are leftovers from previous request.\n            let count = read_request.write(&data);\n\n            // Check if full command was written.\n            if count < data.len() {\n                // Save the leftovers for later.\n                self.read_leftover.save(&data[count..]);\n            }\n        } else {\n            // Noting left from before. Wait for next commands.\n            match self.event_queue.wait_and_pop() {\n                Ok(info) => {\n                    self.write_buffer(read_request, info);\n                }\n                Err(ioqueue::Status::Timeout) => {\n                    // Timeout. This will only trigger if pop function is called with timeout.\n                    read_request.timeout();\n                    return;\n                }\n                Err(err) => {\n                    // Queue failed. Send EOF, to notify user-space. Usually happens on rundown.\n                    err!(\"failed to pop value: {}\", err);\n                    read_request.end_of_file();\n                    return;\n                }\n            }\n        }\n\n        // Check if we have more space. InfoType + data_size == 5 bytes\n        while read_request.free_space() > 5 {\n            match self.event_queue.pop() {\n                Ok(info) => {\n                    self.write_buffer(read_request, info);\n                }\n                Err(_) => {\n                    break;\n                }\n            }\n        }\n        read_request.complete();\n    }\n\n    // Called when handle.Write is called from user-space.\n    pub fn write(&mut self, write_request: &mut WriteRequest) {\n        // Try parsing the command.\n        let mut buffer = write_request.get_buffer();\n        let command = protocol::command::parse_type(buffer);\n        let Some(command) = command else {\n            err!(\"Unknown command number: {}\", buffer[0]);\n            return;\n        };\n        buffer = &buffer[1..];\n\n        let mut _classify_defer = None;\n\n        match command {\n            CommandType::Shutdown => {\n                wdk::dbg!(\"Shutdown command\");\n                self.shutdown();\n            }\n            CommandType::Verdict => {\n                let verdict = protocol::command::parse_verdict(buffer);\n                wdk::dbg!(\"Verdict command\");\n                // Received verdict decision for a specific connection.\n                if let Some((key, mut packet)) = self.packet_cache.pop_id(verdict.id) {\n                    if let Some(verdict) = FromPrimitive::from_u8(verdict.verdict) {\n                        dbg!(\"Verdict received {}: {}\", key, verdict);\n                        // Add verdict in the cache.\n                        let redirect_info = self.connection_cache.update_connection(key, verdict);\n\n                        // if verdict.is_permanent() {\n                        //     dbg!(self.logger, \"resetting filters {}: {}\", key, verdict);\n                        //     _ = self.filter_engine.reset_all_filters();\n                        // }\n\n                        match verdict {\n                            crate::connection::Verdict::Accept\n                            | crate::connection::Verdict::PermanentAccept => {\n                                if let Err(err) = self.inject_packet(packet, false) {\n                                    err!(\"failed to inject packet: {}\", err);\n                                } else {\n                                    dbg!(\"packet injected: {}\", key);\n                                }\n                            }\n                            crate::connection::Verdict::RedirectNameServer\n                            | crate::connection::Verdict::RedirectTunnel\n                            | crate::connection::Verdict::RedirectSplitTunnel => {\n                                if let Some(redirect_info) = redirect_info {\n                                    // Will not redirect packets from ALE layer\n                                    if let Err(err) = packet.redirect(redirect_info) {\n                                        err!(\"failed to redirect packet: {}\", err);\n                                    }\n                                    if let Err(err) = self.inject_packet(packet, false) {\n                                        err!(\"failed to inject packet: {}\", err);\n                                    }\n                                }\n                            }\n                            _ => {\n                                // Inject only ALE layer. This will trigger proper block/drop.\n                                // Packet layer just drop the packet.\n                                if let Err(err) = self.inject_packet(packet, true) {\n                                    err!(\"failed to inject packet: {}\", err);\n                                }\n                            }\n                        }\n                    };\n                } else {\n                    // Id was not in the packet cache.\n                    let id = verdict.id;\n                    err!(\"Verdict invalid id: {}\", id);\n                }\n            }\n            CommandType::UpdateV4 => {\n                let update = protocol::command::parse_update_v4(buffer);\n                // Build the new action.\n                if let Some(verdict) = FromPrimitive::from_u8(update.verdict) {\n                    // Update with new action.\n                    dbg!(\"Verdict update received {:?}: {}\", update, verdict);\n                    _classify_defer = self.connection_cache.update_connection(\n                        Key {\n                            protocol: IpProtocol::from(update.protocol),\n                            local_address: IpAddress::Ipv4(Ipv4Address::from_bytes(\n                                &update.local_address,\n                            )),\n                            local_port: update.local_port,\n                            remote_address: IpAddress::Ipv4(Ipv4Address::from_bytes(\n                                &update.remote_address,\n                            )),\n                            remote_port: update.remote_port,\n                        },\n                        verdict,\n                    );\n                } else {\n                    err!(\"invalid verdict value: {}\", update.verdict);\n                }\n            }\n            CommandType::UpdateV6 => {\n                let update = protocol::command::parse_update_v6(buffer);\n                // Build the new action.\n                if let Some(verdict) = FromPrimitive::from_u8(update.verdict) {\n                    // Update with new action.\n                    dbg!(\"Verdict update received {:?}: {}\", update, verdict);\n                    _classify_defer = self.connection_cache.update_connection(\n                        Key {\n                            protocol: IpProtocol::from(update.protocol),\n                            local_address: IpAddress::Ipv6(Ipv6Address::from_bytes(\n                                &update.local_address,\n                            )),\n                            local_port: update.local_port,\n                            remote_address: IpAddress::Ipv6(Ipv6Address::from_bytes(\n                                &update.remote_address,\n                            )),\n                            remote_port: update.remote_port,\n                        },\n                        verdict,\n                    );\n                } else {\n                    err!(\"invalid verdict value: {}\", update.verdict);\n                }\n            }\n            CommandType::ClearCache => {\n                wdk::dbg!(\"ClearCache command\");\n                self.connection_cache.clear();\n                if let Err(err) = self.filter_engine.reset_all_filters() {\n                    err!(\"failed to reset filters: {}\", err);\n                }\n            }\n            CommandType::GetLogs => {\n                wdk::dbg!(\"GetLogs command\");\n                let lines_vec = logger::flush();\n                for line in lines_vec {\n                    let _ = self.event_queue.push(line);\n                }\n            }\n            CommandType::GetBandwidthStats => {\n                wdk::dbg!(\"GetBandwidthStats command\");\n                let stats = self.bandwidth_stats.get_all_updates_tcp_v4();\n                if let Some(stats) = stats {\n                    _ = self.event_queue.push(stats);\n                }\n\n                let stats = self.bandwidth_stats.get_all_updates_tcp_v6();\n                if let Some(stats) = stats {\n                    _ = self.event_queue.push(stats);\n                }\n\n                let stats = self.bandwidth_stats.get_all_updates_udp_v4();\n                if let Some(stats) = stats {\n                    _ = self.event_queue.push(stats);\n                }\n\n                let stats = self.bandwidth_stats.get_all_updates_udp_v6();\n                if let Some(stats) = stats {\n                    _ = self.event_queue.push(stats);\n                }\n            }\n            CommandType::PrintMemoryStats => {\n                // Getting the information takes a long time and interferes with the callouts causing the device to crash.\n                // TODO(vladimir): Make more optimized version\n                // info!(\n                //     \"Packet cache: {} entries\",\n                //     self.packet_cache.get_entries_count()\n                // );\n                // info!(\n                //     \"BandwidthStats cache: {} entries\",\n                //     self.bandwidth_stats.get_entries_count()\n                // );\n                // info!(\n                //     \"Connection cache: {} entries\\n {}\",\n                //     self.connection_cache.get_entries_count(),\n                //     self.connection_cache.get_full_cache_info()\n                // );\n            }\n            CommandType::CleanEndedConnections => {\n                wdk::dbg!(\"CleanEndedConnections command\");\n                self.connection_cache.clean_ended_connections();\n            }\n        }\n    }\n\n    pub fn shutdown(&mut self) {\n        // End blocking operations from the queue. This will end pending read requests.\n        self.event_queue.rundown();\n\n\t\t// Resolve all pending packets. This is important for proper driver unload.\n        let pending_packets = self.packet_cache.pop_all();\n        for el in pending_packets {\n            let key = el.value.0;\n            let packet = el.value.1;\n            // Set any verdict. Driver will unload after that and the filter will not be active.\n            _ = self\n                .connection_cache\n                .update_connection(key, crate::connection::Verdict::PermanentBlock);\n            _ = self.inject_packet(packet, true); // Blocked must be set, so it only handles the ALE layer.\n        }\n    }\n\n    pub fn inject_packet(&mut self, packet: Packet, blocked: bool) -> Result<(), String> {\n        match packet {\n            Packet::PacketLayer(nbl, inject_info) => {\n                if !blocked {\n                    self.injector.inject_net_buffer_list(nbl, inject_info)\n                } else {\n                    Ok(())\n                }\n            }\n            Packet::AleLayer(defer) => {\n                let packet_list = defer.complete(&mut self.filter_engine)?;\n                if let Some(packet_list) = packet_list {\n                    self.injector.inject_packet_list_transport(packet_list)?;\n                }\n\n                Ok(())\n            }\n        }\n    }\n}\n\nimpl Drop for Device {\n    fn drop(&mut self) {\n        _ = logger::flush();\n        // dbg!(\"Device Context drop called.\");\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/entry.rs",
    "content": "use crate::common::ControlCode;\r\nuse crate::device;\r\nuse alloc::boxed::Box;\r\nuse core::sync::atomic::{AtomicPtr, Ordering};\r\nuse num_traits::FromPrimitive;\r\nuse wdk::irp_helpers::{CleanupRequest, CreateRequest, DeviceControlRequest, ReadRequest, WriteRequest};\r\nuse wdk::{err, info, interface};\r\nuse windows_sys::Wdk::Foundation::{DEVICE_OBJECT, DRIVER_OBJECT, IRP};\r\nuse windows_sys::Win32::Foundation::{NTSTATUS, STATUS_SUCCESS};\r\n\r\nstatic VERSION: [u8; 4] = include!(\"../../kextinterface/version.txt\");\r\n\r\n/// Global device pointer.\r\n///\r\n/// We use `AtomicPtr` to ensure thread safety.\r\n/// - **Safety**: Prevents data races and acts as a compiler barrier against dangerous optimizations\r\n///   (e.g., load hoisting), ensuring concurrent callouts see a valid, up-to-date pointer.\r\n/// - **Performance**: Negligible overhead. On x64, `Acquire` is free (same as a normal load).\r\n///   On ARM64, it uses efficient hardware-supported load-acquire instructions.\r\nstatic DEVICE: AtomicPtr<device::Device> = AtomicPtr::new(core::ptr::null_mut());\r\n\r\npub fn get_device() -> Option<&'static mut device::Device> {\r\n    // Acquire pairs with the Release store in driver_entry and the AcqRel swap in driver_unload.\r\n    unsafe { DEVICE.load(Ordering::Acquire).as_mut() }\r\n}\r\n\r\n// DriverEntry is the entry point of the driver (main function). Will be called when driver is loaded.\r\n// Name should not be changed\r\n#[export_name = \"DriverEntry\"]\r\npub extern \"system\" fn driver_entry(\r\n    driver_object: *mut windows_sys::Wdk::Foundation::DRIVER_OBJECT,\r\n    registry_path: *mut windows_sys::Win32::Foundation::UNICODE_STRING,\r\n) -> windows_sys::Win32::Foundation::NTSTATUS {\r\n    info!(\"Starting initialization...\");\r\n\r\n    // Initialize driver object.\r\n    let mut driver = match interface::init_driver_object(\r\n        driver_object,\r\n        registry_path,\r\n        \"PortmasterKext\",\r\n        core::ptr::null_mut(),\r\n    ) {\r\n        Ok(driver) => driver,\r\n        Err(status) => {\r\n            err!(\"driver_entry: failed to initialize driver: {}\", status);\r\n            return windows_sys::Win32::Foundation::STATUS_FAILED_DRIVER_ENTRY;\r\n        }\r\n    };\r\n\r\n    // Set driver functions.\r\n    driver.set_driver_unload(Some(driver_unload));\r\n    driver.set_create_fn(Some(driver_create));\r\n    driver.set_cleanup_fn(Some(driver_cleanup));\r\n    driver.set_read_fn(Some(driver_read));\r\n    driver.set_write_fn(Some(driver_write));\r\n    driver.set_device_control_fn(Some(device_control));\r\n\r\n    // Initialize device.\r\n    let device = match device::Device::new(&driver) {\r\n        Ok(device) => Box::new(device),\r\n        Err(err) => {\r\n            wdk::err!(\"filed to initialize device: {}\", err);\r\n            return -1;\r\n        }\r\n    };\r\n    // Release: makes the fully-constructed Device visible to all cores that subsequently\r\n    // perform an Acquire load.\r\n    DEVICE.store(Box::into_raw(device), Ordering::Release);\r\n\r\n    STATUS_SUCCESS\r\n}\r\n\r\n// driver_unload function is called when service delete is called from user-space.\r\nunsafe extern \"system\" fn driver_unload(_object: *const DRIVER_OBJECT) {\r\n    info!(\"Unloading complete\");\r\n    // Atomically null the pointer before freeing. Any core that performs an Acquire load\r\n    // *after* this swap will see null and bail out safely. Any core that already loaded a\r\n    // non-null pointer before this swap is protected by the OS-level serialisation:\r\n    //   - WFP callouts: FilterEngine::drop() (field declared first in Device) calls the WFP\r\n    //     unregister APIs which block until every in-flight classify callback has returned,\r\n    //     so no callout thread holds a live reference by the time the memory is freed.\r\n    //   - IRP dispatch (read/write/ioctl): the I/O Manager guarantees no dispatch routine\r\n    //     is executing when driver_unload is called.\r\n    // The swap is executed exactly once, on the unload path.\r\n    let ptr = DEVICE.swap(core::ptr::null_mut(), Ordering::AcqRel);\r\n    if !ptr.is_null() {\r\n        unsafe { drop(Box::from_raw(ptr)); }\r\n    }\r\n}\r\n\r\n/// driver_create is triggered when user-space opens a handle to the device (CreateFile).\r\nunsafe extern \"system\" fn driver_create(\r\n    _device_object: *const DEVICE_OBJECT,\r\n    irp: *mut IRP,\r\n) -> NTSTATUS {\r\n    let mut create_request = CreateRequest::new(irp.as_mut().unwrap());\r\n    if let Some(device) = get_device() {\r\n        let pid = create_request.get_requestor_pid();\r\n        device.owner_pid.store(pid, core::sync::atomic::Ordering::Release);\r\n        info!(\"Device opened by PID {}\", pid);\r\n    }\r\n    create_request.complete();\r\n    create_request.get_status()\r\n}\r\n\r\n/// driver_cleanup is triggered when user-space closes the last handle to the device.\r\nunsafe extern \"system\" fn driver_cleanup(\r\n    _device_object: *const DEVICE_OBJECT,\r\n    irp: *mut IRP,\r\n) -> NTSTATUS {\r\n    let mut cleanup_request = CleanupRequest::new(irp.as_mut().unwrap());\r\n    if let Some(device) = get_device() {\r\n        let old_pid = device.owner_pid.swap(0, core::sync::atomic::Ordering::Release);\r\n        info!(\"Device closed by PID {}\", old_pid);\r\n    }\r\n    cleanup_request.complete();\r\n    cleanup_request.get_status()\r\n}\r\n\r\n// driver_read event triggered from user-space on file.Read.\r\nunsafe extern \"system\" fn driver_read(\r\n    _device_object: *const DEVICE_OBJECT,\r\n    irp: *mut IRP,\r\n) -> NTSTATUS {\r\n    let mut read_request = ReadRequest::new(irp.as_mut().unwrap());\r\n    let Some(device) = get_device() else {\r\n        read_request.complete();\r\n\r\n        return read_request.get_status();\r\n    };\r\n\r\n    device.read(&mut read_request);\r\n    read_request.get_status()\r\n}\r\n\r\n/// driver_write event triggered from user-space on file.Write.\r\nunsafe extern \"system\" fn driver_write(\r\n    _device_object: *const DEVICE_OBJECT,\r\n    irp: *mut IRP,\r\n) -> NTSTATUS {\r\n    let mut write_request = WriteRequest::new(irp.as_mut().unwrap());\r\n    let Some(device) = get_device() else {\r\n        write_request.complete();\r\n        return write_request.get_status();\r\n    };\r\n\r\n    device.write(&mut write_request);\r\n\r\n    write_request.mark_all_as_read();\r\n    write_request.complete();\r\n    write_request.get_status()\r\n}\r\n\r\n/// device_control event triggered from user-space on file.deviceIOControl.\r\nunsafe extern \"system\" fn device_control(\r\n    _device_object: *const DEVICE_OBJECT,\r\n    irp: *mut IRP,\r\n) -> NTSTATUS {\r\n    let mut control_request = DeviceControlRequest::new(irp.as_mut().unwrap());\r\n    let Some(device) = get_device() else {\r\n        control_request.complete();\r\n        return control_request.get_status();\r\n    };\r\n\r\n    let Some(control_code): Option<ControlCode> =\r\n        FromPrimitive::from_u32(control_request.get_control_code())\r\n    else {\r\n        wdk::info!(\"Unknown IOCTL code: {}\", control_request.get_control_code());\r\n        control_request.not_implemented();\r\n        return control_request.get_status();\r\n    };\r\n\r\n    wdk::info!(\"IOCTL: {}\", control_code);\r\n\r\n    match control_code {\r\n        ControlCode::Version => {\r\n            control_request.write(&VERSION);\r\n        }\r\n        ControlCode::ShutdownRequest => device.shutdown(),\r\n    };\r\n\r\n    control_request.complete();\r\n    control_request.get_status()\r\n}\r\n"
  },
  {
    "path": "windows_kext/driver/src/id_cache.rs",
    "content": "use core::mem;\n\nuse alloc::collections::VecDeque;\nuse protocol::info::Info;\nuse smoltcp::wire::{IpAddress, IpProtocol};\nuse wdk::rw_spin_lock::RwSpinLock;\n\nuse crate::{connection::Direction, connection_map::Key, device::Packet};\n\npub struct Entry<T> {\n    pub value: T,\n    id: u64,\n}\n\npub struct IdCache {\n    values: VecDeque<Entry<(Key, Packet)>>,\n    lock: RwSpinLock,\n    next_id: u64,\n}\n\nimpl IdCache {\n    pub fn new() -> Self {\n        Self {\n            values: VecDeque::with_capacity(1000),\n            lock: RwSpinLock::default(),\n            next_id: 1, // 0 is invalid id\n        }\n    }\n\n    pub fn push(\n        &mut self,\n        value: (Key, Packet),\n        process_id: u64,\n        direction: Direction,\n        ale_layer: bool,\n    ) -> Option<Info> {\n        let _guard = self.lock.write_lock();\n        let id = self.next_id;\n        let info = build_info(&value.0, id, process_id, direction, &value.1, ale_layer);\n        self.values.push_back(Entry { value, id });\n        self.next_id = self.next_id.wrapping_add(1); // Assuming this will not overflow.\n\n        return info;\n    }\n\n    pub fn pop_id(&mut self, id: u64) -> Option<(Key, Packet)> {\n        let _guard = self.lock.write_lock();\n        if let Ok(index) = self.values.binary_search_by_key(&id, |val| val.id) {\n            return Some(self.values.remove(index).unwrap().value);\n        }\n        None\n    }\n\n    #[allow(dead_code)]\n    pub fn get_entries_count(&self) -> usize {\n        let _guard = self.lock.read_lock();\n        return self.values.len();\n    }\n\n    pub fn pop_all(&mut self) -> VecDeque<Entry<(Key, Packet)>> {\n        let mut values = VecDeque::with_capacity(1);\n        let _guard = self.lock.write_lock();\n        mem::swap(&mut self.values, &mut values);\n\n        return values;\n    }\n}\n\nfn get_payload(packet: &Packet) -> Option<&[u8]> {\n    match packet {\n        Packet::PacketLayer(nbl, _) => nbl.get_data(),\n        Packet::AleLayer(defer) => {\n            let p = match defer {\n                wdk::filter_engine::callout_data::ClassifyDefer::Initial(_, p) => p,\n                wdk::filter_engine::callout_data::ClassifyDefer::Reauthorization(_, p) => p,\n            };\n            if let Some(tpl) = p {\n                tpl.net_buffer_list.get_data()\n            } else {\n                None\n            }\n        }\n    }\n}\n\nfn build_info(\n    key: &Key,\n    packet_id: u64,\n    process_id: u64,\n    direction: Direction,\n    packet: &Packet,\n    ale_layer: bool,\n) -> Option<Info> {\n    let (local_port, remote_port) = match key.protocol {\n        IpProtocol::Tcp | IpProtocol::Udp => (key.local_port, key.remote_port),\n        _ => (0, 0),\n    };\n\n    let payload_layer = if ale_layer {\n        4 // Transport layer\n    } else {\n        3 // Network layer\n    };\n\n    let mut payload = &[][..];\n    if let Some(p) = get_payload(packet) {\n        payload = p;\n    }\n\n    match (key.local_address, key.remote_address) {\n        (IpAddress::Ipv6(local_ip), IpAddress::Ipv6(remote_ip)) if key.is_ipv6() => {\n            Some(protocol::info::connection_info_v6(\n                packet_id,\n                process_id,\n                direction as u8,\n                u8::from(key.protocol),\n                local_ip.0,\n                remote_ip.0,\n                local_port,\n                remote_port,\n                payload_layer,\n                payload,\n            ))\n        }\n        (IpAddress::Ipv4(local_ip), IpAddress::Ipv4(remote_ip)) => {\n            Some(protocol::info::connection_info_v4(\n                packet_id,\n                process_id,\n                direction as u8,\n                u8::from(key.protocol),\n                local_ip.0,\n                remote_ip.0,\n                local_port,\n                remote_port,\n                payload_layer,\n                payload,\n            ))\n        }\n        _ => None,\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/lib.rs",
    "content": "#![cfg_attr(not(test), no_std)]\r\n#![no_main]\r\n#![allow(clippy::needless_return)]\r\n\r\nextern crate alloc;\r\n\r\nmod ale_callouts;\r\nmod array_holder;\r\nmod bandwidth;\r\nmod callouts;\r\nmod common;\r\nmod connection;\r\nmod connection_cache;\r\nmod connection_map;\r\nmod device;\r\nmod entry;\r\nmod id_cache;\r\npub mod logger;\r\nmod packet_callouts;\r\nmod packet_util;\r\nmod stream_callouts;\r\n\r\nuse wdk::allocator::WindowsAllocator;\r\n\r\n// For consistent behavior during development and production only release mode should be used.\r\n// Certain behavior of the compiler will change and this can result in errors and different behavior in debug and release mode.\r\n#[cfg(debug_assertions)]\r\ncompile_error!(\"Must be built in release mode to ensure consistent behavior and prevent optimization-related issues. Use `cargo build --release`.\");\r\n\r\n#[cfg(not(test))]\r\nuse core::panic::PanicInfo;\r\n\r\n// Declaration of the global memory allocator\r\n#[global_allocator]\r\nstatic HEAP: WindowsAllocator = WindowsAllocator {};\r\n\r\n#[no_mangle]\r\npub extern \"system\" fn _DllMainCRTStartup() {}\r\n\r\n#[cfg(not(test))]\r\n#[panic_handler]\r\nfn panic(info: &PanicInfo) -> ! {\r\n    use wdk::err;\r\n\r\n    err!(\"{}\", info);\r\n    loop {}\r\n}\r\n"
  },
  {
    "path": "windows_kext/driver/src/logger.rs",
    "content": "use alloc::boxed::Box;\nuse alloc::vec::Vec;\nuse core::{\n    mem::MaybeUninit,\n    sync::atomic::{AtomicPtr, AtomicUsize, Ordering},\n};\nuse protocol::info::{Info, Severity};\n\npub const LOG_LEVEL: u8 = Severity::Warning as u8;\n// pub const LOG_LEVEL: u8 = Severity::Trace as u8;\n\npub const MAX_LOG_LINE_SIZE: usize = 150;\nconst SIZE_OF_LOG_LINE_BUFFER: usize = 1024;\nstatic mut LOG_LINES: [AtomicPtr<Info>; SIZE_OF_LOG_LINE_BUFFER] =\n    unsafe { MaybeUninit::zeroed().assume_init() };\nstatic START_INDEX: AtomicUsize = unsafe { MaybeUninit::zeroed().assume_init() };\nstatic END_INDEX: AtomicUsize = unsafe { MaybeUninit::zeroed().assume_init() };\n\npub fn add_line(log_line: Info) {\n    let mut index = END_INDEX.fetch_add(1, Ordering::Acquire);\n    unsafe {\n        index %= SIZE_OF_LOG_LINE_BUFFER;\n        let ptr = &mut LOG_LINES[index];\n        let line = Box::new(log_line);\n        let old = ptr.swap(Box::into_raw(line), Ordering::SeqCst);\n        if !old.is_null() {\n            _ = Box::from_raw(old);\n        }\n    }\n}\n\npub fn flush() -> Vec<Info> {\n    let mut vec = Vec::new();\n    let end_index = END_INDEX.load(Ordering::Acquire);\n    let start_index = START_INDEX.load(Ordering::Acquire);\n    if end_index <= start_index {\n        return vec;\n    }\n    unsafe {\n        let count = end_index - start_index;\n        for i in start_index..start_index + count {\n            let index = i % SIZE_OF_LOG_LINE_BUFFER;\n            let ptr = LOG_LINES[index].swap(core::ptr::null_mut(), Ordering::SeqCst);\n            if !ptr.is_null() {\n                vec.push(*Box::from_raw(ptr));\n            }\n        }\n    }\n\n    START_INDEX.store(end_index, Ordering::Release);\n    vec\n}\n\n#[macro_export]\nmacro_rules! log_internal {\n    ($log_line:expr, $($arg:tt)*) => ({\n        use core::fmt::Write;\n        _ = write!($log_line, \"{}:{} \", file!(), line!());\n        _ = write!($log_line, $($arg)*);\n        $crate::logger::add_line($log_line);\n    });\n}\n\n#[macro_export]\nmacro_rules! crit {\n    ($($arg:tt)*) => ({\n        if protocol::info::Severity::Critical as u8 >= $crate::logger::LOG_LEVEL {\n            let message = alloc::format!($($arg)*);\n            $crate::logger::add_line(protocol::info::Severity::Critical, alloc::format!(\"{}:{} \", file!(), line!()), message)\n        }\n    });\n}\n\n#[macro_export]\nmacro_rules! err {\n    ($($arg:tt)*) => ({\n        if protocol::info::Severity::Error as u8 >= $crate::logger::LOG_LEVEL {\n            let mut log_line = protocol::info::log_line(protocol::info::Severity::Error, $crate::logger::MAX_LOG_LINE_SIZE);\n            $crate::log_internal!(log_line, $($arg)*);\n        }\n    });\n}\n\n#[macro_export]\nmacro_rules! warn {\n    ($($arg:tt)*) => ({\n        if protocol::info::Severity::Warning as u8 >= $crate::logger::LOG_LEVEL {\n            let mut log_line = protocol::info::log_line(protocol::info::Severity::Warning, $crate::logger::MAX_LOG_LINE_SIZE);\n            $crate::log_internal!(log_line, $($arg)*);\n        }\n    });\n}\n\n#[macro_export]\nmacro_rules! dbg {\n    ($($arg:tt)*) => ({\n        if protocol::info::Severity::Debug as u8 >= $crate::logger::LOG_LEVEL {\n            let mut log_line = protocol::info::log_line(protocol::info::Severity::Debug, $crate::logger::MAX_LOG_LINE_SIZE);\n            $crate::log_internal!(log_line, $($arg)*);\n        }\n    });\n}\n\n#[macro_export]\nmacro_rules! info {\n    ($($arg:tt)*) => ({\n        if protocol::info::Severity::Info as u8 >= $crate::logger::LOG_LEVEL {\n            let mut log_line = protocol::info::log_line(protocol::info::Severity::Info, $crate::logger::MAX_LOG_LINE_SIZE);\n            $crate::log_internal!(log_line, $($arg)*);\n        }\n    });\n}\n"
  },
  {
    "path": "windows_kext/driver/src/packet_callouts.rs",
    "content": "use alloc::string::String;\nuse smoltcp::wire::{IPV4_HEADER_LEN, IPV6_HEADER_LEN};\nuse wdk::filter_engine::callout_data::CalloutData;\nuse wdk::filter_engine::layer;\nuse wdk::filter_engine::net_buffer::{NetBufferList, NetBufferListIter};\nuse wdk::filter_engine::packet::InjectInfo;\n\nuse crate::connection::{\n    Connection, ConnectionV4, ConnectionV6, Direction, RedirectInfo, Verdict, PM_DNS_PORT,\n    PM_SPN_PORT,\n};\nuse crate::connection_cache::ConnectionCache;\nuse crate::connection_map::Key;\nuse crate::device::{Device, Packet};\nuse crate::packet_util::{\n    get_key_from_nbl_v4, get_key_from_nbl_v6, recalc_header_checksums, Redirect,\n};\n\n// IP packet layers\npub fn ip_packet_layer_outbound_v4(data: CalloutData) {\n    type Fields = layer::FieldsOutboundIppacketV4;\n    let interface_index = data.get_value_u32(Fields::InterfaceIndex as usize);\n    let sub_interface_index = data.get_value_u32(Fields::SubInterfaceIndex as usize);\n\n    ip_packet_layer(\n        data,\n        false,\n        Direction::Outbound,\n        interface_index,\n        sub_interface_index,\n    );\n}\n\npub fn ip_packet_layer_inbound_v4(data: CalloutData) {\n    type Fields = layer::FieldsInboundIppacketV4;\n    let interface_index = data.get_value_u32(Fields::InterfaceIndex as usize);\n    let sub_interface_index = data.get_value_u32(Fields::SubInterfaceIndex as usize);\n    ip_packet_layer(\n        data,\n        false,\n        Direction::Inbound,\n        interface_index,\n        sub_interface_index,\n    );\n}\n\npub fn ip_packet_layer_outbound_v6(data: CalloutData) {\n    type Fields = layer::FieldsOutboundIppacketV6;\n    let interface_index = data.get_value_u32(Fields::InterfaceIndex as usize);\n    let sub_interface_index = data.get_value_u32(Fields::SubInterfaceIndex as usize);\n\n    ip_packet_layer(\n        data,\n        true,\n        Direction::Outbound,\n        interface_index,\n        sub_interface_index,\n    );\n}\n\npub fn ip_packet_layer_inbound_v6(data: CalloutData) {\n    type Fields = layer::FieldsInboundIppacketV6;\n    let interface_index = data.get_value_u32(Fields::InterfaceIndex as usize);\n    let sub_interface_index = data.get_value_u32(Fields::SubInterfaceIndex as usize);\n\n    ip_packet_layer(\n        data,\n        true,\n        Direction::Inbound,\n        interface_index,\n        sub_interface_index,\n    );\n}\n\nstruct ConnectionInfo {\n    verdict: Verdict,\n    process_id: u64,\n    redirect_info: Option<RedirectInfo>,\n}\n\nimpl ConnectionInfo {\n    fn from_connection<T: Connection>(conn: &T) -> Self {\n        ConnectionInfo {\n            verdict: conn.get_verdict(),\n            process_id: conn.get_process_id(),\n            redirect_info: conn.redirect_info(),\n        }\n    }\n}\n\nfn fast_track_pm_packets(key: &Key, direction: Direction) -> bool {\n    match direction {\n        Direction::Outbound => {\n            if key.local_port == PM_DNS_PORT || key.local_port == PM_SPN_PORT {\n                return key.local_address == key.remote_address;\n            }\n        }\n        Direction::Inbound => {\n            if key.local_port == PM_DNS_PORT || key.local_port == PM_SPN_PORT {\n                return key.local_address == key.remote_address;\n            }\n        }\n    }\n\n    return false;\n}\n\nfn ip_packet_layer(\n    mut data: CalloutData,\n    ipv6: bool,\n    direction: Direction,\n    interface_index: u32,\n    sub_interface_index: u32,\n) {\n    // Make the default path as drop.\n    data.block_and_absorb();\n\n    // Block all fragment data. No easy way to keep track of the origin and they are rarely used.\n    if data.is_fragment_data() {\n        data.block_and_absorb();\n        crate::err!(\"blocked fragment packet\");\n        return;\n    }\n\n    let Some(device) = crate::entry::get_device() else {\n        return;\n    };\n    if device\n        .injector\n        .was_network_packet_injected_by_self(data.get_layer_data() as _, ipv6)\n    {\n        data.action_permit();\n        return;\n    }\n\n    for mut nbl in NetBufferListIter::new(data.get_layer_data() as _) {\n        if let Direction::Inbound = direction {\n            // The header is not part of the NBL for incoming packets. Move the beginning of the buffer back so we get access to it.\n            // The NBL will auto advance after it loses scope.\n            if ipv6 {\n                nbl.retreat(IPV6_HEADER_LEN as u32, true);\n            } else {\n                nbl.retreat(IPV4_HEADER_LEN as u32, true);\n            }\n        }\n\n        // Get key from packet.\n        let key = match if ipv6 {\n            get_key_from_nbl_v6(&nbl, direction)\n        } else {\n            get_key_from_nbl_v4(&nbl, direction)\n        } {\n            Ok(key) => key,\n            Err(err) => {\n                crate::err!(\"failed to get key from nbl: {}\", err);\n                return;\n            }\n        };\n\n        if fast_track_pm_packets(&key, direction) {\n            data.action_permit();\n            return;\n        }\n\n        let mut send_request_to_portmaster = true;\n        let mut process_id = 0;\n\n        if matches!(\n            key.protocol,\n            smoltcp::wire::IpProtocol::Tcp | smoltcp::wire::IpProtocol::Udp\n        ) {\n            if let Some(mut conn_info) =\n                get_connection_info(&mut device.connection_cache, &key, ipv6)\n            {\n                process_id = conn_info.process_id;\n                // Check if there is action for this connection.\n                match conn_info.verdict {\n                    Verdict::Undecided | Verdict::Accept | Verdict::Block | Verdict::Drop => {}\n                    Verdict::PermanentAccept => {\n                        send_request_to_portmaster = false;\n                        data.action_permit();\n                    }\n                    Verdict::PermanentBlock => {\n                        send_request_to_portmaster = false;\n                        data.action_block_hard();\n                    }\n                    Verdict::Undeterminable | Verdict::PermanentDrop | Verdict::Failed => {\n                        send_request_to_portmaster = false;\n                        data.block_and_absorb();\n                    }\n                    Verdict::RedirectNameServer | Verdict::RedirectTunnel | Verdict::RedirectSplitTunnel => {\n                        if let Some(redirect_info) = conn_info.redirect_info.take() {\n                            match clone_packet(\n                                device,\n                                nbl,\n                                direction,\n                                ipv6,\n                                key.is_loopback(),\n                                interface_index,\n                                sub_interface_index,\n                            ) {\n                                Ok(mut packet) => {\n                                    let _ = packet.redirect(redirect_info);\n                                    if let Err(err) = device.inject_packet(packet, false) {\n                                        crate::err!(\"failed to inject packet: {}\", err);\n                                    }\n                                }\n                                Err(err) => crate::err!(\"failed to clone packet: {}\", err),\n                            }\n                        }\n\n                        // This will block the original packet. Even if injection failed.\n                        data.block_and_absorb();\n                        continue;\n                    }\n                }\n            } else {\n                // Connections is not in the cache.\n                crate::dbg!(\"packet layer adding connection: {} PID: 0\", key);\n                if ipv6 {\n                    let conn = ConnectionV6::from_key(&key, 0, direction).unwrap();\n                    device.connection_cache.add_connection_v6(conn);\n                } else {\n                    let conn = ConnectionV4::from_key(&key, 0, direction).unwrap();\n                    device.connection_cache.add_connection_v4(conn);\n                }\n            }\n        }\n\n        // Clone packet and send to Portmaster.\n        if send_request_to_portmaster {\n            let packet = match clone_packet(\n                device,\n                nbl,\n                direction,\n                ipv6,\n                key.is_loopback(),\n                interface_index,\n                sub_interface_index,\n            ) {\n                Ok(p) => p,\n                Err(err) => {\n                    crate::err!(\"failed to clone packet: {}\", err);\n                    return;\n                }\n            };\n\n            let info = device\n                .packet_cache\n                .push((key, packet), process_id, direction, false);\n\n            // Send to Portmaster\n            if let Some(info) = info {\n                let _ = device.event_queue.push(info);\n            }\n            data.block_and_absorb();\n        }\n    }\n}\n\nfn clone_packet(\n    device: &mut Device,\n    nbl: NetBufferList,\n    direction: Direction,\n    ipv6: bool,\n    loopback: bool,\n    interface_index: u32,\n    sub_interface_index: u32,\n) -> Result<Packet, String> {\n    let mut clone = nbl.clone(&device.network_allocator)?;\n    let inbound = match direction {\n        Direction::Outbound => false,\n        Direction::Inbound => true,\n    };\n\n    if let Some(data) = clone.get_data_mut() {\n        // Outbound packets intercepted at the IP layer may carry only a partial\n        // pseudo-header checksum because the TCP/IP stack relies on NIC hardware\n        // checksum offload to fill in the real value before transmission.\n        // When this clone is later re-injected via FwpsInjectNetwork*Async (on\n        // Accept/PermanentAccept verdict), it bypasses the NIC entirely, so offload\n        // never runs. We must compute the full software checksum here.\n        recalc_header_checksums(data, ipv6);\n    }\n\n    Ok(Packet::PacketLayer(\n        clone,\n        InjectInfo {\n            ipv6,\n            inbound,\n            loopback,\n            interface_index,\n            sub_interface_index,\n        },\n    ))\n}\n\nfn get_connection_info(\n    connection_cache: &mut ConnectionCache,\n    key: &Key,\n    ipv6: bool,\n) -> Option<ConnectionInfo> {\n    if ipv6 {\n        let conn_info = connection_cache.read_connection_v6(\n            key,\n            |conn: &ConnectionV6| -> Option<ConnectionInfo> {\n                // Function is is behind spin lock. Just copy and return.\n                Some(ConnectionInfo::from_connection(conn))\n            },\n        );\n        return conn_info;\n    } else {\n        let conn_info = connection_cache.read_connection_v4(\n            key,\n            |conn: &ConnectionV4| -> Option<ConnectionInfo> {\n                // Function is is behind spin lock. Just copy and return.\n                Some(ConnectionInfo::from_connection(conn))\n            },\n        );\n        return conn_info;\n    }\n}\n"
  },
  {
    "path": "windows_kext/driver/src/packet_util.rs",
    "content": "use alloc::string::{String, ToString};\nuse smoltcp::wire::{\n    IpAddress, IpProtocol, Ipv4Address, Ipv4Packet, Ipv6Address, Ipv6Packet, TcpPacket, UdpPacket,\n};\nuse wdk::filter_engine::net_buffer::NetBufferList;\n\nuse crate::connection_map::Key;\nuse crate::device::Packet;\nuse crate::{\n    connection::{Direction, RedirectInfo},\n    dbg, err,\n};\n\n/// `Redirect` is a trait that defines a method for redirecting network packets.\n///\n/// This trait is used to implement different strategies for redirecting packets,\n/// depending on the specific requirements of the application.\npub trait Redirect {\n    /// Redirects a network packet based on the provided `RedirectInfo`.\n    ///\n    /// # Arguments\n    ///\n    /// * `redirect_info` - A struct containing information about how to redirect the packet.\n    ///\n    /// # Returns\n    ///\n    /// * `Ok(())` if the packet was successfully redirected.\n    /// * `Err(String)` if there was an error redirecting the packet.\n    fn redirect(&mut self, redirect_info: RedirectInfo) -> Result<(), String>;\n}\n\nimpl Redirect for Packet {\n    fn redirect(&mut self, redirect_info: RedirectInfo) -> Result<(), String> {\n        if let Packet::PacketLayer(nbl, inject_info) = self {\n            let Some(data) = nbl.get_data_mut() else {\n                return Err(\"trying to redirect immutable NBL\".to_string());\n            };\n\n            if inject_info.inbound {\n                redirect_inbound_packet(\n                    data,\n                    redirect_info.local_address,\n                    redirect_info.remote_address,\n                    redirect_info.remote_port,\n                )\n            } else {\n                redirect_outbound_packet(\n                    data,\n                    redirect_info.redirect_address,\n                    redirect_info.redirect_port,\n                    redirect_info.unify,\n                )\n            }\n            return Ok(());\n        }\n        // return Err(\"can't redirect from non packet layer\".to_string());\n        return Ok(());\n    }\n}\n\n/// Redirects an outbound packet to a specified remote address and port.\n///\n/// # Arguments\n///\n/// * `packet` - A mutable reference to the packet data.\n/// * `remote_address` - The IP address to redirect the packet to.\n/// * `remote_port` - The port to redirect the packet to.\n/// * `unify` - If true, the source and destination addresses of the packet will be set to the same value.\n///\n/// This function modifies the packet in-place to change its destination address and port.\n/// It also updates the checksums for the IP and transport layer headers.\n/// If the `unify` parameter is true, it sets the source and destination addresses to be the same.\n/// If the remote address is a loopback address, it sets the source address to the loopback address.\nfn redirect_outbound_packet(\n    packet: &mut [u8],\n    remote_address: IpAddress,\n    remote_port: u16,\n    unify: bool,\n) {\n    match remote_address {\n        IpAddress::Ipv4(remote_address) => {\n            if let Ok(mut ip_packet) = Ipv4Packet::new_checked(packet) {\n                if unify {\n                    ip_packet.set_dst_addr(ip_packet.src_addr());\n                } else {\n                    ip_packet.set_dst_addr(remote_address);\n                    if remote_address.is_loopback() {\n                        ip_packet.set_src_addr(Ipv4Address::new(127, 0, 0, 1));\n                    }\n                }\n                ip_packet.fill_checksum();\n                let src_addr = ip_packet.src_addr();\n                let dst_addr = ip_packet.dst_addr();\n                if ip_packet.next_header() == IpProtocol::Udp {\n                    if let Ok(mut udp_packet) = UdpPacket::new_checked(ip_packet.payload_mut()) {\n                        udp_packet.set_dst_port(remote_port);\n                        udp_packet\n                            .fill_checksum(&IpAddress::Ipv4(src_addr), &IpAddress::Ipv4(dst_addr));\n                    }\n                }\n                if ip_packet.next_header() == IpProtocol::Tcp {\n                    if let Ok(mut tcp_packet) = TcpPacket::new_checked(ip_packet.payload_mut()) {\n                        tcp_packet.set_dst_port(remote_port);\n                        tcp_packet\n                            .fill_checksum(&IpAddress::Ipv4(src_addr), &IpAddress::Ipv4(dst_addr));\n                    }\n                }\n            }\n        }\n        IpAddress::Ipv6(remote_address) => {\n            if let Ok(mut ip_packet) = Ipv6Packet::new_checked(packet) {\n                ip_packet.set_dst_addr(remote_address);\n                if unify {\n                    ip_packet.set_dst_addr(ip_packet.src_addr());\n                } else {\n                    ip_packet.set_dst_addr(remote_address);\n                    if remote_address.is_loopback() {\n                        ip_packet.set_src_addr(Ipv6Address::LOOPBACK);\n                    }\n                }\n                let src_addr = ip_packet.src_addr();\n                let dst_addr = ip_packet.dst_addr();\n                if ip_packet.next_header() == IpProtocol::Udp {\n                    if let Ok(mut udp_packet) = UdpPacket::new_checked(ip_packet.payload_mut()) {\n                        udp_packet.set_dst_port(remote_port);\n                        udp_packet\n                            .fill_checksum(&IpAddress::Ipv6(src_addr), &IpAddress::Ipv6(dst_addr));\n                    }\n                }\n                if ip_packet.next_header() == IpProtocol::Tcp {\n                    if let Ok(mut tcp_packet) = TcpPacket::new_checked(ip_packet.payload_mut()) {\n                        tcp_packet.set_dst_port(remote_port);\n                        tcp_packet\n                            .fill_checksum(&IpAddress::Ipv6(src_addr), &IpAddress::Ipv6(dst_addr));\n                    }\n                }\n            }\n        }\n    }\n}\n\n/// Redirects an inbound packet to a local address.\n///\n/// This function takes a mutable reference to a packet and modifies it in place.\n/// It changes the destination address to the provided local address and the source address\n/// to the original remote address. It also sets the source port to the original remote port.\n/// The function handles both IPv4 and IPv6 addresses.\n///\n/// # Arguments\n///\n/// * `packet` - A mutable reference to the packet data.\n/// * `local_address` - The local IP address to redirect the packet to.\n/// * `original_remote_address` - The original remote IP address of the packet.\n/// * `original_remote_port` - The original remote port of the packet.\n///\nfn redirect_inbound_packet(\n    packet: &mut [u8],\n    local_address: IpAddress,\n    original_remote_address: IpAddress,\n    original_remote_port: u16,\n) {\n    match local_address {\n        IpAddress::Ipv4(local_address) => {\n            let IpAddress::Ipv4(original_remote_address) = original_remote_address else {\n                return;\n            };\n\n            if let Ok(mut ip_packet) = Ipv4Packet::new_checked(packet) {\n                ip_packet.set_dst_addr(local_address);\n                ip_packet.set_src_addr(original_remote_address);\n                ip_packet.fill_checksum();\n                let src_addr = ip_packet.src_addr();\n                let dst_addr = ip_packet.dst_addr();\n                if ip_packet.next_header() == IpProtocol::Udp {\n                    if let Ok(mut udp_packet) = UdpPacket::new_checked(ip_packet.payload_mut()) {\n                        udp_packet.set_src_port(original_remote_port);\n                        udp_packet\n                            .fill_checksum(&IpAddress::Ipv4(src_addr), &IpAddress::Ipv4(dst_addr));\n                    }\n                }\n                if ip_packet.next_header() == IpProtocol::Tcp {\n                    if let Ok(mut tcp_packet) = TcpPacket::new_checked(ip_packet.payload_mut()) {\n                        tcp_packet.set_src_port(original_remote_port);\n                        tcp_packet\n                            .fill_checksum(&IpAddress::Ipv4(src_addr), &IpAddress::Ipv4(dst_addr));\n                    }\n                }\n            }\n        }\n        IpAddress::Ipv6(local_address) => {\n            if let Ok(mut ip_packet) = Ipv6Packet::new_checked(packet) {\n                let IpAddress::Ipv6(original_remote_address) = original_remote_address else {\n                    return;\n                };\n                ip_packet.set_dst_addr(local_address);\n                ip_packet.set_src_addr(original_remote_address);\n                let src_addr = ip_packet.src_addr();\n                let dst_addr = ip_packet.dst_addr();\n                if ip_packet.next_header() == IpProtocol::Udp {\n                    if let Ok(mut udp_packet) = UdpPacket::new_checked(ip_packet.payload_mut()) {\n                        udp_packet.set_src_port(original_remote_port);\n                        udp_packet\n                            .fill_checksum(&IpAddress::Ipv6(src_addr), &IpAddress::Ipv6(dst_addr));\n                    }\n                }\n                if ip_packet.next_header() == IpProtocol::Tcp {\n                    if let Ok(mut tcp_packet) = TcpPacket::new_checked(ip_packet.payload_mut()) {\n                        tcp_packet.set_src_port(original_remote_port);\n                        tcp_packet\n                            .fill_checksum(&IpAddress::Ipv6(src_addr), &IpAddress::Ipv6(dst_addr));\n                    }\n                }\n            }\n        }\n    }\n}\n\npub fn recalc_header_checksums(packet: &mut [u8], ipv6: bool) {\n    if ipv6 {\n        if let Ok(mut ip_packet) = Ipv6Packet::new_checked(packet) {\n            let src_addr = ip_packet.src_addr();\n            let dst_addr = ip_packet.dst_addr();\n            if ip_packet.next_header() == IpProtocol::Udp {\n                if let Ok(mut udp_packet) = UdpPacket::new_checked(ip_packet.payload_mut()) {\n                    udp_packet\n                        .fill_checksum(&IpAddress::Ipv6(src_addr), &IpAddress::Ipv6(dst_addr));\n                }\n            }\n            if ip_packet.next_header() == IpProtocol::Tcp {\n                if let Ok(mut tcp_packet) = TcpPacket::new_checked(ip_packet.payload_mut()) {\n                    tcp_packet\n                        .fill_checksum(&IpAddress::Ipv6(src_addr), &IpAddress::Ipv6(dst_addr));\n                }\n            }\n        }\n    } else {\n        if let Ok(mut ip_packet) = Ipv4Packet::new_checked(packet) {\n            ip_packet.fill_checksum();\n            let src_addr = ip_packet.src_addr();\n            let dst_addr = ip_packet.dst_addr();\n            if ip_packet.next_header() == IpProtocol::Udp {\n                if let Ok(mut udp_packet) = UdpPacket::new_checked(ip_packet.payload_mut()) {\n                    udp_packet\n                        .fill_checksum(&IpAddress::Ipv4(src_addr), &IpAddress::Ipv4(dst_addr));\n                }\n            }\n            if ip_packet.next_header() == IpProtocol::Tcp {\n                if let Ok(mut tcp_packet) = TcpPacket::new_checked(ip_packet.payload_mut()) {\n                    tcp_packet\n                        .fill_checksum(&IpAddress::Ipv4(src_addr), &IpAddress::Ipv4(dst_addr));\n                }\n            }\n        }\n    }\n}\n\n#[allow(dead_code)]\nfn print_packet(packet: &[u8]) {\n    if let Ok(ip_packet) = Ipv4Packet::new_checked(packet) {\n        if ip_packet.next_header() == IpProtocol::Udp {\n            if let Ok(udp_packet) = UdpPacket::new_checked(ip_packet.payload()) {\n                dbg!(\"packet {} {}\", ip_packet, udp_packet);\n            }\n        }\n        if ip_packet.next_header() == IpProtocol::Tcp {\n            if let Ok(tcp_packet) = TcpPacket::new_checked(ip_packet.payload()) {\n                dbg!(\"packet {} {}\", ip_packet, tcp_packet);\n            }\n        }\n    } else {\n        err!(\"failed to print packet: invalid ip header: {:?}\", packet);\n    }\n}\n\n/// This function extracts a key from a given IPv4 network buffer list (NBL).\n/// The key contains the protocol, local and remote addresses and ports.\n///\n/// # Arguments\n///\n/// * `nbl` - A reference to the network buffer list from which the key will be extracted.\n/// * `direction` - The direction of the packet (Inbound or Outbound).\n///\n/// # Returns\n///\n/// * `Ok(Key)` - A key containing the protocol, local and remote addresses and ports.\n/// * `Err(String)` - An error message if the function fails to get net_buffer data.\nfn get_ports(packet: &[u8], protocol: smoltcp::wire::IpProtocol) -> (u16, u16) {\n    match protocol {\n        smoltcp::wire::IpProtocol::Tcp => {\n            let tcp_packet = TcpPacket::new_unchecked(packet);\n            (tcp_packet.src_port(), tcp_packet.dst_port())\n        }\n        smoltcp::wire::IpProtocol::Udp => {\n            let udp_packet = UdpPacket::new_unchecked(packet);\n            (udp_packet.src_port(), udp_packet.dst_port())\n        }\n        _ => (0, 0), // No ports for other protocols\n    }\n}\n\npub fn get_key_from_nbl_v4(nbl: &NetBufferList, direction: Direction) -> Result<Key, String> {\n    // Get first bytes of the packet. IP header + src port (2 bytes) + dst port (2 bytes)\n    let mut headers = [0; smoltcp::wire::IPV4_HEADER_LEN + 4];\n    if nbl.read_bytes(&mut headers).is_err() {\n        return Err(\"failed to get net_buffer data\".to_string());\n    }\n\n    // This will panic in debug mode, probably because of runtime checks.\n    // Parse packet\n    let ip_packet = Ipv4Packet::new_unchecked(&headers);\n    let (src_port, dst_port) = get_ports(\n        &headers[smoltcp::wire::IPV4_HEADER_LEN..],\n        ip_packet.next_header(),\n    );\n\n    // Build key\n    match direction {\n        Direction::Outbound => Ok(Key {\n            protocol: ip_packet.next_header(),\n            local_address: IpAddress::Ipv4(ip_packet.src_addr()),\n            local_port: src_port,\n            remote_address: IpAddress::Ipv4(ip_packet.dst_addr()),\n            remote_port: dst_port,\n        }),\n        Direction::Inbound => Ok(Key {\n            protocol: ip_packet.next_header(),\n            local_address: IpAddress::Ipv4(ip_packet.dst_addr()),\n            local_port: dst_port,\n            remote_address: IpAddress::Ipv4(ip_packet.src_addr()),\n            remote_port: src_port,\n        }),\n    }\n}\n\n/// This function extracts a key from a given IPv6 network buffer list (NBL).\n/// The key contains the protocol, local and remote addresses and ports.\n///\n/// # Arguments\n///\n/// * `nbl` - A reference to the network buffer list from which the key will be extracted.\n/// * `direction` - The direction of the packet (Inbound or Outbound).\n///\n/// # Returns\n///\n/// * `Ok(Key)` - A key containing the protocol, local and remote addresses and ports.\n/// * `Err(String)` - An error message if the function fails to get net_buffer data.\npub fn get_key_from_nbl_v6(nbl: &NetBufferList, direction: Direction) -> Result<Key, String> {\n    // Get first bytes of the packet. IP header + src port (2 bytes) + dst port (2 bytes)\n    let mut headers = [0; smoltcp::wire::IPV6_HEADER_LEN + 4];\n    let Ok(()) = nbl.read_bytes(&mut headers) else {\n        return Err(\"failed to get net_buffer data\".to_string());\n    };\n\n    // This will panic in debug mode, probably because of runtime checks.\n    // Parse packet\n    let ip_packet = Ipv6Packet::new_unchecked(&headers);\n    let (src_port, dst_port) = get_ports(\n        &headers[smoltcp::wire::IPV6_HEADER_LEN..],\n        ip_packet.next_header(),\n    );\n\n    // Build key\n    match direction {\n        Direction::Outbound => Ok(Key {\n            protocol: ip_packet.next_header(),\n            local_address: IpAddress::Ipv6(ip_packet.src_addr()),\n            local_port: src_port,\n            remote_address: IpAddress::Ipv6(ip_packet.dst_addr()),\n            remote_port: dst_port,\n        }),\n        Direction::Inbound => Ok(Key {\n            protocol: ip_packet.next_header(),\n            local_address: IpAddress::Ipv6(ip_packet.dst_addr()),\n            local_port: dst_port,\n            remote_address: IpAddress::Ipv6(ip_packet.src_addr()),\n            remote_port: src_port,\n        }),\n    }\n}\n\n// Converts a given key into connection information.\n//\n// This function takes a key, packet id, process id, and direction as input.\n// It then uses these to create a new `ConnectionInfoV6` or `ConnectionInfoV4` object,\n// depending on whether the IP addresses in the key are IPv6 or IPv4 respectively.\n//\n// # Arguments\n//\n// * `key` - A reference to the key object containing the connection details.\n// * `packet_id` - The id of the packet.\n// * `process_id` - The id of the process.\n// * `direction` - The direction of the connection.\n//\n// # Returns\n//\n// * `Some(Box<dyn Info>)` - A boxed `Info` trait object if the key contains valid IPv4 or IPv6 addresses.\n// * `None` - If the key does not contain valid IPv4 or IPv6 addresses.\n// pub fn key_to_connection_info(\n//     key: &Key,\n//     packet_id: u64,\n//     process_id: u64,\n//     direction: Direction,\n//     payload: &[u8],\n// ) -> Option<Info> {\n//     let (local_port, remote_port) = match key.protocol {\n//         IpProtocol::Tcp | IpProtocol::Udp => (key.local_port, key.remote_port),\n//         _ => (0, 0),\n//     };\n\n//     match (key.local_address, key.remote_address) {\n//         (IpAddress::Ipv6(local_ip), IpAddress::Ipv6(remote_ip)) if key.is_ipv6() => {\n//             Some(protocol::info::connection_info_v6(\n//                 packet_id,\n//                 process_id,\n//                 direction as u8,\n//                 u8::from(key.protocol),\n//                 local_ip.0,\n//                 remote_ip.0,\n//                 local_port,\n//                 remote_port,\n//                 payload,\n//             ))\n//         }\n//         (IpAddress::Ipv4(local_ip), IpAddress::Ipv4(remote_ip)) => {\n//             Some(protocol::info::connection_info_v4(\n//                 packet_id,\n//                 process_id,\n//                 direction as u8,\n//                 u8::from(key.protocol),\n//                 local_ip.0,\n//                 remote_ip.0,\n//                 local_port,\n//                 remote_port,\n//                 payload,\n//             ))\n//         }\n//         _ => None,\n//     }\n// }\n"
  },
  {
    "path": "windows_kext/driver/src/stream_callouts.rs",
    "content": "use smoltcp::wire::{Ipv4Address, Ipv6Address};\nuse wdk::filter_engine::{callout_data::CalloutData, layer, net_buffer::NetBufferListIter};\n\nuse crate::{bandwidth, connection::Direction};\n\npub fn stream_layer_tcp_v4(data: CalloutData) {\n    type Fields = layer::FieldsStreamV4;\n\n    let Some(device) = crate::entry::get_device() else {\n        return;\n    };\n    let mut direction = Direction::Outbound;\n    let data_length = if let Some(packet) = data.get_stream_callout_packet() {\n        if packet.is_receive() {\n            direction = Direction::Inbound;\n        }\n        packet.get_data_len()\n    } else {\n        return;\n    };\n    let local_ip = Ipv4Address::from_bytes(\n        &data\n            .get_value_u32(Fields::IpLocalAddress as usize)\n            .to_be_bytes(),\n    );\n    let local_port = data.get_value_u16(Fields::IpLocalPort as usize);\n    let remote_ip = Ipv4Address::from_bytes(\n        &data\n            .get_value_u32(Fields::IpRemoteAddress as usize)\n            .to_be_bytes(),\n    );\n    let remote_port = data.get_value_u16(Fields::IpRemotePort as usize);\n    match direction {\n        Direction::Outbound => {\n            device.bandwidth_stats.update_tcp_v4_tx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n        Direction::Inbound => {\n            device.bandwidth_stats.update_tcp_v4_rx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n    }\n}\n\npub fn stream_layer_tcp_v6(data: CalloutData) {\n    type Fields = layer::FieldsStreamV6;\n\n    let Some(device) = crate::entry::get_device() else {\n        return;\n    };\n    let mut direction = Direction::Outbound;\n    let data_length = if let Some(packet) = data.get_stream_callout_packet() {\n        if packet.is_receive() {\n            direction = Direction::Inbound;\n        }\n        packet.get_data_len()\n    } else {\n        return;\n    };\n\n    if data_length == 0 {\n        return;\n    }\n    let local_ip =\n        Ipv6Address::from_bytes(data.get_value_byte_array16(Fields::IpLocalAddress as usize));\n    let local_port = data.get_value_u16(Fields::IpLocalPort as usize);\n\n    let remote_ip =\n        Ipv6Address::from_bytes(data.get_value_byte_array16(Fields::IpRemoteAddress as usize));\n    let remote_port = data.get_value_u16(Fields::IpRemotePort as usize);\n\n    match direction {\n        Direction::Outbound => {\n            device.bandwidth_stats.update_tcp_v6_tx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n        Direction::Inbound => {\n            device.bandwidth_stats.update_tcp_v6_rx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n    }\n}\n\npub fn stream_layer_udp_v4(data: CalloutData) {\n    type Fields = layer::FieldsDatagramDataV4;\n\n    let Some(device) = crate::entry::get_device() else {\n        return;\n    };\n    let mut data_length: usize = 0;\n    for nbl in NetBufferListIter::new(data.get_layer_data() as _) {\n        data_length += nbl.get_data_length() as usize;\n    }\n    let mut direction = Direction::Inbound;\n    if data.get_value_u8(Fields::Direction as usize) == 0 {\n        direction = Direction::Outbound;\n    }\n\n    let local_ip = Ipv4Address::from_bytes(\n        &data\n            .get_value_u32(Fields::IpLocalAddress as usize)\n            .to_be_bytes(),\n    );\n    let local_port = data.get_value_u16(Fields::IpLocalPort as usize);\n    let remote_ip = Ipv4Address::from_bytes(\n        &data\n            .get_value_u32(Fields::IpRemoteAddress as usize)\n            .to_be_bytes(),\n    );\n    let remote_port = data.get_value_u16(Fields::IpRemotePort as usize);\n    match direction {\n        Direction::Outbound => {\n            device.bandwidth_stats.update_udp_v4_tx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n        Direction::Inbound => {\n            device.bandwidth_stats.update_udp_v4_rx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n    }\n}\n\npub fn stream_layer_udp_v6(data: CalloutData) {\n    type Fields = layer::FieldsDatagramDataV6;\n\n    let Some(device) = crate::entry::get_device() else {\n        return;\n    };\n    let mut data_length: usize = 0;\n    for nbl in NetBufferListIter::new(data.get_layer_data() as _) {\n        data_length += nbl.get_data_length() as usize;\n    }\n    let mut direction = Direction::Inbound;\n    if data.get_value_u8(Fields::Direction as usize) == 0 {\n        direction = Direction::Outbound;\n    }\n\n    let local_ip =\n        Ipv6Address::from_bytes(data.get_value_byte_array16(Fields::IpLocalAddress as usize));\n    let local_port = data.get_value_u16(Fields::IpLocalPort as usize);\n    let remote_ip =\n        Ipv6Address::from_bytes(data.get_value_byte_array16(Fields::IpRemoteAddress as usize));\n    let remote_port = data.get_value_u16(Fields::IpRemotePort as usize);\n    match direction {\n        Direction::Outbound => {\n            device.bandwidth_stats.update_udp_v6_tx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n        Direction::Inbound => {\n            device.bandwidth_stats.update_udp_v6_rx(\n                bandwidth::Key {\n                    local_ip,\n                    local_port,\n                    remote_ip,\n                    remote_port,\n                },\n                data_length,\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/kextinterface/command.go",
    "content": "package kextinterface\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n)\n\n// Command IDs.\nconst (\n\tCommandShutdown              = 0\n\tCommandVerdict               = 1\n\tCommandUpdateV4              = 2\n\tCommandUpdateV6              = 3\n\tCommandClearCache            = 4\n\tCommandGetLogs               = 5\n\tCommandBandwidthStats        = 6\n\tCommandPrintMemoryStats      = 7\n\tCommandCleanEndedConnections = 8\n)\n\n// KextVerdict is the verdict ID used to with the kext.\ntype KextVerdict uint8\n\n// Kext Verdicts.\n// Make sure this is in sync with the Rust version.\nconst (\n\t// VerdictUndecided is the default status of new connections.\n\tVerdictUndecided           KextVerdict = 0\n\tVerdictUndeterminable      KextVerdict = 1\n\tVerdictAccept              KextVerdict = 2\n\tVerdictPermanentAccept     KextVerdict = 3\n\tVerdictBlock               KextVerdict = 4\n\tVerdictPermanentBlock      KextVerdict = 5\n\tVerdictDrop                KextVerdict = 6\n\tVerdictPermanentDrop       KextVerdict = 7\n\tVerdictRerouteToNameserver KextVerdict = 8\n\tVerdictRerouteToTunnel     KextVerdict = 9\n\tVerdictFailed              KextVerdict = 10\n)\n\ntype Verdict struct {\n\tcommand uint8\n\tID      uint64\n\tVerdict uint8\n}\n\ntype UpdateV4 struct {\n\tcommand       uint8\n\tProtocol      uint8\n\tLocalAddress  [4]byte\n\tLocalPort     uint16\n\tRemoteAddress [4]byte\n\tRemotePort    uint16\n\tVerdict       uint8\n}\n\ntype UpdateV6 struct {\n\tcommand       uint8\n\tProtocol      uint8\n\tLocalAddress  [16]byte\n\tLocalPort     uint16\n\tRemoteAddress [16]byte\n\tRemotePort    uint16\n\tVerdict       uint8\n}\n\n// SendShutdownCommand sends a Shutdown command to the kext.\nfunc SendShutdownCommand(writer io.Writer) error {\n\t_, err := writer.Write([]byte{CommandShutdown})\n\treturn err\n}\n\n// SendVerdictCommand sends a Verdict command to the kext.\nfunc SendVerdictCommand(writer io.Writer, verdict Verdict) error {\n\tverdict.command = CommandVerdict\n\treturn binary.Write(writer, binary.LittleEndian, verdict)\n}\n\n// SendUpdateV4Command sends a UpdateV4 command to the kext.\nfunc SendUpdateV4Command(writer io.Writer, update UpdateV4) error {\n\tupdate.command = CommandUpdateV4\n\treturn binary.Write(writer, binary.LittleEndian, update)\n}\n\n// SendUpdateV6Command sends a UpdateV6 command to the kext.\nfunc SendUpdateV6Command(writer io.Writer, update UpdateV6) error {\n\tupdate.command = CommandUpdateV6\n\treturn binary.Write(writer, binary.LittleEndian, update)\n}\n\n// SendClearCacheCommand sends a ClearCache command to the kext.\nfunc SendClearCacheCommand(writer io.Writer) error {\n\t_, err := writer.Write([]byte{CommandClearCache})\n\treturn err\n}\n\n// SendGetLogsCommand sends a GetLogs command to the kext.\nfunc SendGetLogsCommand(writer io.Writer) error {\n\t_, err := writer.Write([]byte{CommandGetLogs})\n\treturn err\n}\n\n// SendGetBandwidthStatsCommand sends a GetBandwidthStats command to the kext.\nfunc SendGetBandwidthStatsCommand(writer io.Writer) error {\n\t_, err := writer.Write([]byte{CommandBandwidthStats})\n\treturn err\n}\n\n// SendPrintMemoryStatsCommand sends a PrintMemoryStats command to the kext.\nfunc SendPrintMemoryStatsCommand(writer io.Writer) error {\n\t_, err := writer.Write([]byte{CommandPrintMemoryStats})\n\treturn err\n}\n\n// SendCleanEndedConnectionsCommand sends a CleanEndedConnections command to the kext.\nfunc SendCleanEndedConnectionsCommand(writer io.Writer) error {\n\t_, err := writer.Write([]byte{CommandCleanEndedConnections})\n\treturn err\n}\n"
  },
  {
    "path": "windows_kext/kextinterface/info.go",
    "content": "package kextinterface\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n)\n\nconst (\n\tInfoLogLine              = 0\n\tInfoConnectionIpv4       = 1\n\tInfoConnectionIpv6       = 2\n\tInfoConnectionEndEventV4 = 3\n\tInfoConnectionEndEventV6 = 4\n\tInfoBandwidthStatsV4     = 5\n\tInfoBandwidthStatsV6     = 6\n)\n\nvar (\n\tErrUnknownInfoType     = errors.New(\"unknown info type\")\n\tErrUnexpectedInfoSize  = errors.New(\"unexpected info size\")\n\tErrUnexpectedReadError = errors.New(\"unexpected read error\")\n)\n\ntype connectionV4Internal struct {\n\tID           uint64\n\tProcessID    uint64\n\tDirection    byte\n\tProtocol     byte\n\tLocalIP      [4]byte\n\tRemoteIP     [4]byte\n\tLocalPort    uint16\n\tRemotePort   uint16\n\tPayloadLayer uint8\n}\n\ntype ConnectionV4 struct {\n\tconnectionV4Internal\n\tPayload []byte\n}\n\nfunc (c *ConnectionV4) Compare(other *ConnectionV4) bool {\n\treturn c.ID == other.ID &&\n\t\tc.ProcessID == other.ProcessID &&\n\t\tc.Direction == other.Direction &&\n\t\tc.Protocol == other.Protocol &&\n\t\tc.LocalIP == other.LocalIP &&\n\t\tc.RemoteIP == other.RemoteIP &&\n\t\tc.LocalPort == other.LocalPort &&\n\t\tc.RemotePort == other.RemotePort\n}\n\ntype connectionV6Internal struct {\n\tID           uint64\n\tProcessID    uint64\n\tDirection    byte\n\tProtocol     byte\n\tLocalIP      [16]byte\n\tRemoteIP     [16]byte\n\tLocalPort    uint16\n\tRemotePort   uint16\n\tPayloadLayer uint8\n}\n\ntype ConnectionV6 struct {\n\tconnectionV6Internal\n\tPayload []byte\n}\n\nfunc (c ConnectionV6) Compare(other *ConnectionV6) bool {\n\treturn c.ID == other.ID &&\n\t\tc.ProcessID == other.ProcessID &&\n\t\tc.Direction == other.Direction &&\n\t\tc.Protocol == other.Protocol &&\n\t\tc.LocalIP == other.LocalIP &&\n\t\tc.RemoteIP == other.RemoteIP &&\n\t\tc.LocalPort == other.LocalPort &&\n\t\tc.RemotePort == other.RemotePort\n}\n\ntype ConnectionEndV4 struct {\n\tProcessID  uint64\n\tDirection  byte\n\tProtocol   byte\n\tLocalIP    [4]byte\n\tRemoteIP   [4]byte\n\tLocalPort  uint16\n\tRemotePort uint16\n}\n\ntype ConnectionEndV6 struct {\n\tProcessID  uint64\n\tDirection  byte\n\tProtocol   byte\n\tLocalIP    [16]byte\n\tRemoteIP   [16]byte\n\tLocalPort  uint16\n\tRemotePort uint16\n}\n\ntype LogLine struct {\n\tSeverity byte\n\tLine     string\n}\n\ntype BandwidthValueV4 struct {\n\tLocalIP          [4]byte\n\tLocalPort        uint16\n\tRemoteIP         [4]byte\n\tRemotePort       uint16\n\tTransmittedBytes uint64\n\tReceivedBytes    uint64\n}\n\ntype BandwidthValueV6 struct {\n\tLocalIP          [16]byte\n\tLocalPort        uint16\n\tRemoteIP         [16]byte\n\tRemotePort       uint16\n\tTransmittedBytes uint64\n\tReceivedBytes    uint64\n}\n\ntype BandwidthStatsArray struct {\n\tProtocol uint8\n\tValuesV4 []BandwidthValueV4\n\tValuesV6 []BandwidthValueV6\n}\n\ntype Info struct {\n\tConnectionV4    *ConnectionV4\n\tConnectionV6    *ConnectionV6\n\tConnectionEndV4 *ConnectionEndV4\n\tConnectionEndV6 *ConnectionEndV6\n\tLogLine         *LogLine\n\tBandwidthStats  *BandwidthStatsArray\n}\n\ntype readHelper struct {\n\tinfoType    byte\n\tcommandSize uint32\n\n\treadSize int\n\n\treader io.Reader\n}\n\nfunc newReadHelper(reader io.Reader) (*readHelper, error) {\n\thelper := &readHelper{reader: reader}\n\n\terr := binary.Read(reader, binary.LittleEndian, &helper.infoType)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = binary.Read(reader, binary.LittleEndian, &helper.commandSize)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn helper, nil\n}\n\nfunc (r *readHelper) ReadData(data any) error {\n\terr := binary.Read(r, binary.LittleEndian, data)\n\tif err != nil {\n\t\treturn errors.Join(ErrUnexpectedReadError, err)\n\t}\n\n\tif err := r.checkOverRead(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Passing size = 0 will read the rest of the command.\nfunc (r *readHelper) ReadBytes(size uint32) ([]byte, error) {\n\tif uint32(r.readSize) >= r.commandSize {\n\t\treturn nil, errors.Join(fmt.Errorf(\"cannot read more bytes than the command size: %d >= %d\", r.readSize, r.commandSize), ErrUnexpectedReadError)\n\t}\n\n\tif size == 0 {\n\t\tsize = r.commandSize - uint32(r.readSize)\n\t}\n\n\tif r.commandSize < uint32(r.readSize)+size {\n\t\treturn nil, ErrUnexpectedInfoSize\n\t}\n\n\tbytes := make([]byte, size)\n\terr := binary.Read(r, binary.LittleEndian, bytes)\n\tif err != nil {\n\t\treturn nil, errors.Join(ErrUnexpectedReadError, err)\n\t}\n\n\treturn bytes, nil\n}\n\nfunc (r *readHelper) ReadUntilTheEnd() {\n\t_, _ = r.ReadBytes(0)\n}\n\nfunc (r *readHelper) checkOverRead() error {\n\tif uint32(r.readSize) > r.commandSize {\n\t\treturn ErrUnexpectedInfoSize\n\t}\n\n\treturn nil\n}\n\nfunc (r *readHelper) Read(p []byte) (n int, err error) {\n\tn, err = r.reader.Read(p)\n\tr.readSize += n\n\treturn\n}\n\nfunc RecvInfo(reader io.Reader) (*Info, error) {\n\thelper, err := newReadHelper(reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Make sure the whole command is read before return.\n\tdefer helper.ReadUntilTheEnd()\n\n\t// Read data\n\tswitch helper.infoType {\n\tcase InfoConnectionIpv4:\n\t\t{\n\t\t\tparseError := fmt.Errorf(\"failed to parse InfoConnectionIpv4\")\n\t\t\tnewInfo := ConnectionV4{}\n\t\t\tvar fixedSizeValues connectionV4Internal\n\t\t\t// Read fixed size values.\n\t\t\terr = helper.ReadData(&fixedSizeValues)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err, fmt.Errorf(\"fixed\"))\n\t\t\t}\n\t\t\tnewInfo.connectionV4Internal = fixedSizeValues\n\t\t\t// Read size of payload.\n\t\t\tvar payloadSize uint32\n\t\t\terr = helper.ReadData(&payloadSize)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err, fmt.Errorf(\"payloadsize\"))\n\t\t\t}\n\n\t\t\t// Check if there is payload.\n\t\t\tif payloadSize > 0 {\n\t\t\t\t// Read payload.\n\t\t\t\tnewInfo.Payload, err = helper.ReadBytes(payloadSize)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, errors.Join(parseError, err, fmt.Errorf(\"payload\"))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn &Info{ConnectionV4: &newInfo}, nil\n\t\t}\n\tcase InfoConnectionIpv6:\n\t\t{\n\t\t\tparseError := fmt.Errorf(\"failed to parse InfoConnectionIpv6\")\n\t\t\tnewInfo := ConnectionV6{}\n\n\t\t\t// Read fixed size values.\n\t\t\terr = helper.ReadData(&newInfo.connectionV6Internal)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\n\t\t\t// Read size of payload.\n\t\t\tvar payloadSize uint32\n\t\t\terr = helper.ReadData(&payloadSize)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\n\t\t\t// Check if there is payload.\n\t\t\tif payloadSize > 0 {\n\t\t\t\t// Read payload.\n\t\t\t\tnewInfo.Payload, err = helper.ReadBytes(payloadSize)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn &Info{ConnectionV6: &newInfo}, nil\n\t\t}\n\tcase InfoConnectionEndEventV4:\n\t\t{\n\t\t\tparseError := fmt.Errorf(\"failed to parse InfoConnectionEndEventV4\")\n\t\t\tvar connectionEnd ConnectionEndV4\n\n\t\t\t// Read fixed size values.\n\t\t\terr = helper.ReadData(&connectionEnd)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\treturn &Info{ConnectionEndV4: &connectionEnd}, nil\n\t\t}\n\tcase InfoConnectionEndEventV6:\n\t\t{\n\t\t\tparseError := fmt.Errorf(\"failed to parse InfoConnectionEndEventV6\")\n\t\t\tvar connectionEnd ConnectionEndV6\n\n\t\t\t// Read fixed size values.\n\t\t\terr = helper.ReadData(&connectionEnd)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\treturn &Info{ConnectionEndV6: &connectionEnd}, nil\n\t\t}\n\tcase InfoLogLine:\n\t\t{\n\t\t\tparseError := fmt.Errorf(\"failed to parse InfoLogLine\")\n\t\t\tlogLine := LogLine{}\n\t\t\t// Read severity\n\t\t\terr = helper.ReadData(&logLine.Severity)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\t// Read string\n\t\t\tbytes, err := helper.ReadBytes(0)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\tlogLine.Line = string(bytes)\n\t\t\treturn &Info{LogLine: &logLine}, nil\n\t\t}\n\tcase InfoBandwidthStatsV4:\n\t\t{\n\t\t\tparseError := fmt.Errorf(\"failed to parse InfoBandwidthStatsV4\")\n\t\t\t// Read Protocol\n\t\t\tvar protocol uint8\n\t\t\terr = helper.ReadData(&protocol)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\t// Read size of array\n\t\t\tvar size uint32\n\t\t\terr = helper.ReadData(&size)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\t// Read array\n\t\t\tstatsArray := make([]BandwidthValueV4, size)\n\t\t\tfor i := range int(size) {\n\t\t\t\terr = helper.ReadData(&statsArray[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn &Info{BandwidthStats: &BandwidthStatsArray{Protocol: protocol, ValuesV4: statsArray}}, nil\n\t\t}\n\tcase InfoBandwidthStatsV6:\n\t\t{\n\t\t\tparseError := fmt.Errorf(\"failed to parse InfoBandwidthStatsV6\")\n\t\t\t// Read Protocol\n\t\t\tvar protocol uint8\n\t\t\terr = helper.ReadData(&protocol)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\t// Read size of array\n\t\t\tvar size uint32\n\t\t\terr = helper.ReadData(&size)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t}\n\t\t\t// Read array\n\t\t\tstatsArray := make([]BandwidthValueV6, size)\n\t\t\tfor i := range int(size) {\n\t\t\t\terr = helper.ReadData(&statsArray[i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, errors.Join(parseError, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn &Info{BandwidthStats: &BandwidthStatsArray{Protocol: protocol, ValuesV6: statsArray}}, nil\n\t\t}\n\t}\n\n\treturn nil, ErrUnknownInfoType\n}\n"
  },
  {
    "path": "windows_kext/kextinterface/ioctl.go",
    "content": "//go:build windows\n// +build windows\n\npackage kextinterface\n\nimport (\n\t\"golang.org/x/sys/windows\"\n)\n\nconst (\n\tMETHOD_BUFFERED   = 0\n\tMETHOD_IN_DIRECT  = 1\n\tMETHOD_OUT_DIRECT = 2\n\tMETHOD_NEITHER    = 3\n\n\tSIOCTL_TYPE = 40000\n)\n\nfunc ctlCode(device_type, function, method, access uint32) uint32 {\n\treturn (device_type << 16) | (access << 14) | (function << 2) | method\n}\n\nvar (\n\tIOCTL_VERSION          = ctlCode(SIOCTL_TYPE, 0x800, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n\tIOCTL_SHUTDOWN_REQUEST = ctlCode(SIOCTL_TYPE, 0x801, METHOD_BUFFERED, windows.FILE_READ_DATA|windows.FILE_WRITE_DATA)\n)\n\nfunc ReadVersion(file *KextFile) ([]uint8, error) {\n\tdata := make([]uint8, 4)\n\t_, err := file.deviceIOControl(IOCTL_VERSION, nil, data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn data, nil\n}\n"
  },
  {
    "path": "windows_kext/kextinterface/kext.go",
    "content": "//go:build windows\n// +build windows\n\npackage kextinterface\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/safing/portmaster/base/log\"\n\t\"golang.org/x/sys/windows\"\n)\n\nvar (\n\t//go:embed version.txt\n\tversionTxt string\n\n\t// 4 byte version of the Kext interface\n\tInterfaceVersion = func() (v [4]byte) {\n\t\t// Parse version from file \"version.txt\". Expected format: [0, 1, 2, 3]\n\t\ts := strings.TrimSpace(versionTxt)\n\t\ts = strings.TrimPrefix(s, \"[\")\n\t\ts = strings.TrimSuffix(s, \"]\")\n\t\tstr_ver := strings.Split(s, \",\")\n\t\tfor i := range v {\n\t\t\tn, err := strconv.Atoi(strings.TrimSpace(str_ver[i]))\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t\tv[i] = byte(n)\n\t\t}\n\t\treturn\n\t}()\n)\n\nconst (\n\twinInvalidHandleValue      = windows.InvalidHandle\n\tstopServiceTimeoutDuration = time.Duration(30 * time.Second)\n)\n\ntype KextService struct {\n\thandle     windows.Handle\n\tdriverName string\n}\n\nfunc (s *KextService) isValid() bool {\n\treturn s != nil && s.handle != windows.InvalidHandle && s.handle != 0\n}\n\nfunc (s *KextService) isRunning() (bool, error) {\n\tif !s.isValid() {\n\t\treturn false, fmt.Errorf(\"kext service not initialized\")\n\t}\n\tvar status windows.SERVICE_STATUS\n\terr := windows.QueryServiceStatus(s.handle, &status)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn status.CurrentState == windows.SERVICE_RUNNING, nil\n}\n\nfunc (s *KextService) waitForServiceStatus(neededStatus uint32, timeLimit time.Duration) (bool, error) {\n\tvar status windows.SERVICE_STATUS\n\tstatus.CurrentState = windows.SERVICE_NO_CHANGE\n\tstart := time.Now()\n\tfor status.CurrentState != neededStatus {\n\t\terr := windows.QueryServiceStatus(s.handle, &status)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed while waiting for service to start: %w\", err)\n\t\t}\n\n\t\tif time.Since(start) > timeLimit {\n\t\t\treturn false, fmt.Errorf(\"time limit reached\")\n\t\t}\n\n\t\t// Sleep for 1/10 of the wait hint, recommended time from microsoft\n\t\ttime.Sleep(time.Duration((status.WaitHint / 10)) * time.Millisecond)\n\t}\n\n\treturn true, nil\n}\n\nfunc (s *KextService) Start(wait bool) error {\n\tif !s.isValid() {\n\t\treturn fmt.Errorf(\"kext service not initialized\")\n\t}\n\n\t// Start the service:\n\terr := windows.StartService(s.handle, 0, nil)\n\tif err != nil {\n\t\terr = windows.GetLastError()\n\t\tif err != windows.ERROR_SERVICE_ALREADY_RUNNING {\n\t\t\t// Failed to start service; clean-up:\n\t\t\tvar status windows.SERVICE_STATUS\n\t\t\t_ = windows.ControlService(s.handle, windows.SERVICE_CONTROL_STOP, &status)\n\t\t\t_ = windows.DeleteService(s.handle)\n\t\t\t_ = windows.CloseServiceHandle(s.handle)\n\t\t\ts.handle = windows.InvalidHandle\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Wait for service to start\n\tif wait {\n\t\tsuccess, err := s.waitForServiceStatus(windows.SERVICE_RUNNING, stopServiceTimeoutDuration)\n\t\tif err != nil || !success {\n\t\t\treturn fmt.Errorf(\"service did not start: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *KextService) GetHandle() windows.Handle {\n\treturn s.handle\n}\n\nfunc (s *KextService) Stop(wait bool) error {\n\tif !s.isValid() {\n\t\treturn fmt.Errorf(\"kext service not initialized\")\n\t}\n\n\t// Stop the service\n\tvar status windows.SERVICE_STATUS\n\terr := windows.ControlService(s.handle, windows.SERVICE_CONTROL_STOP, &status)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"service failed to stop: %w\", err)\n\t}\n\n\t// Wait for service to stop\n\tif wait {\n\t\tsuccess, err := s.waitForServiceStatus(windows.SERVICE_STOPPED, time.Duration(10*time.Second))\n\t\tif err != nil || !success {\n\t\t\treturn fmt.Errorf(\"service did not stop: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *KextService) Delete() error {\n\tif !s.isValid() {\n\t\treturn fmt.Errorf(\"kext service not initialized\")\n\t}\n\n\terr := windows.DeleteService(s.handle)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete service: %s\", err)\n\t}\n\n\t// Service wont be deleted until all handles are closed.\n\terr = windows.CloseServiceHandle(s.handle)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to close service handle: %s\", err)\n\t}\n\n\ts.handle = windows.InvalidHandle\n\treturn nil\n}\n\nfunc (s *KextService) WaitUntilDeleted(serviceManager windows.Handle) error {\n\tdriverNameU16, err := syscall.UTF16FromString(s.driverName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to convert driver name to UTF16 string: %w\", err)\n\t}\n\t// Wait until we can no longer open the old service.\n\t// Not very efficient but NotifyServiceStatusChange cannot be used with driver service.\n\tstart := time.Now()\n\ttimeLimit := time.Duration(30 * time.Second)\n\tfor {\n\t\thandle, err := windows.OpenService(serviceManager, &driverNameU16[0], windows.SERVICE_ALL_ACCESS)\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\t_ = windows.CloseServiceHandle(handle)\n\n\t\tif time.Since(start) > timeLimit {\n\t\t\treturn fmt.Errorf(\"time limit reached\")\n\t\t}\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}\n\n\treturn nil\n}\n\nfunc (s *KextService) OpenFile(readBufferSize int) (*KextFile, error) {\n\tif !s.isValid() {\n\t\treturn nil, fmt.Errorf(\"invalid kext object\")\n\t}\n\n\tdriverNameU16, err := syscall.UTF16FromString(`\\\\.\\` + s.driverName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert driver driverName to UTF16 string %w\", err)\n\t}\n\n\thandle, err := windows.CreateFile(&driverNameU16[0], windows.GENERIC_READ|windows.GENERIC_WRITE, 0, nil, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_OVERLAPPED, 0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &KextFile{handle: handle, buffer: make([]byte, readBufferSize)}, nil\n}\n\nfunc CreateKextService(driverName string, driverPath string) (*KextService, error) {\n\t// Open the service manager:\n\tmanager, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_ALL_ACCESS)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open service manager: %d\", err)\n\t}\n\tdefer windows.CloseServiceHandle(manager)\n\n\tdriverNameU16, err := syscall.UTF16FromString(driverName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert driver name to UTF16 string: %w\", err)\n\t}\n\n\t// Check if there is an old service.\n\tservice, err := windows.OpenService(manager, &driverNameU16[0], windows.SERVICE_ALL_ACCESS)\n\tif err == nil {\n\t\tlog.Warning(\"kext: old driver service was found\")\n\t\toldService := &KextService{handle: service, driverName: driverName}\n\t\toldService.Stop(true)\n\t\terr = oldService.Delete()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\terr := oldService.WaitUntilDeleted(manager)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tservice = windows.InvalidHandle\n\t\tlog.Warning(\"kext: old driver service was deleted successfully\")\n\t}\n\n\tdriverPathU16, err := syscall.UTF16FromString(driverPath)\n\n\t// Create the service\n\tservice, err = windows.CreateService(manager, &driverNameU16[0], &driverNameU16[0], windows.SERVICE_ALL_ACCESS, windows.SERVICE_KERNEL_DRIVER, windows.SERVICE_DEMAND_START, windows.SERVICE_ERROR_NORMAL, &driverPathU16[0], nil, nil, nil, nil, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &KextService{handle: service, driverName: driverName}, nil\n}\n"
  },
  {
    "path": "windows_kext/kextinterface/kext_file.go",
    "content": "//go:build windows\n// +build windows\n\npackage kextinterface\n\nimport (\n\t\"fmt\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\ntype KextFile struct {\n\thandle     windows.Handle\n\tbuffer     []byte\n\tread_slice []byte\n}\n\n// Read tries to read the supplied buffer length from the driver.\n// The data from the driver is read in chunks `len(f.buffer)` and the extra data is cached for the next call.\n// The performance penalty of calling the function with small buffers is very small.\n// The function will block until the next info packet is received from the kext.\nfunc (f *KextFile) Read(buffer []byte) (int, error) {\n\tif err := f.IsValid(); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to read: %w\", err)\n\t}\n\n\t// If no data is available from previous calls, read from kext.\n\tif f.read_slice == nil || len(f.read_slice) == 0 {\n\t\terr := f.refill_read_buffer()\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\tif len(f.read_slice) >= len(buffer) {\n\t\t// There is enough data to fill the requested buffer.\n\t\tcopy(buffer, f.read_slice[0:len(buffer)])\n\t\t// Move the slice to contain the remaining data.\n\t\tf.read_slice = f.read_slice[len(buffer):]\n\t} else {\n\t\t// There is not enough data to fill the requested buffer.\n\n\t\t// Write everything available.\n\t\tcopy(buffer[0:len(f.read_slice)], f.read_slice)\n\t\tcopiedBytes := len(f.read_slice)\n\t\tf.read_slice = nil\n\n\t\t// Read again.\n\t\t_, err := f.Read(buffer[copiedBytes:])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\treturn len(buffer), nil\n}\n\nfunc (f *KextFile) refill_read_buffer() error {\n\tvar count uint32 = 0\n\toverlapped := &windows.Overlapped{}\n\terr := windows.ReadFile(f.handle, f.buffer[:], &count, overlapped)\n\tif err != nil {\n\t\treturn err\n\t}\n\tf.read_slice = f.buffer[0:count]\n\n\treturn nil\n}\n\n// Write sends the buffer bytes to the kext. The function will block until the whole buffer is written to the kext.\nfunc (f *KextFile) Write(buffer []byte) (int, error) {\n\tif err := f.IsValid(); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to write: %w\", err)\n\t}\n\tvar count uint32 = 0\n\toverlapped := &windows.Overlapped{}\n\terr := windows.WriteFile(f.handle, buffer, &count, overlapped)\n\treturn int(count), err\n}\n\n// Close closes the handle to the kext. This will cancel all active Reads and Writes.\nfunc (f *KextFile) Close() error {\n\tif err := f.IsValid(); err != nil {\n\t\treturn fmt.Errorf(\"failed to close: %w\", err)\n\t}\n\terr := windows.CloseHandle(f.handle)\n\tf.handle = windows.InvalidHandle\n\treturn err\n}\n\n// deviceIOControl exists for compatibility with the old kext.\nfunc (f *KextFile) deviceIOControl(code uint32, inData []byte, outData []byte) (*windows.Overlapped, error) {\n\tif err := f.IsValid(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to send io control: %w\", err)\n\t}\n\t// Prepare the input data\n\tvar inDataPtr *byte = nil\n\tvar inDataSize uint32 = 0\n\tif inData != nil {\n\t\tinDataPtr = &inData[0]\n\t\tinDataSize = uint32(len(inData))\n\t}\n\n\t// Prepare the output data\n\tvar outDataPtr *byte = nil\n\tvar outDataSize uint32 = 0\n\tif outData != nil {\n\t\toutDataPtr = &outData[0]\n\t\toutDataSize = uint32(len(outData))\n\t}\n\n\t// Make the request to the kext.\n\toverlapped := &windows.Overlapped{}\n\terr := windows.DeviceIoControl(f.handle,\n\t\tcode,\n\t\tinDataPtr, inDataSize,\n\t\toutDataPtr, outDataSize,\n\t\tnil, overlapped)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn overlapped, nil\n}\n\n// GetHandle returns the handle of the kext.\nfunc (f *KextFile) GetHandle() windows.Handle {\n\treturn f.handle\n}\n\n// IsValid checks if kext file holds a valid handle to the kext driver.\nfunc (f *KextFile) IsValid() error {\n\tif f == nil {\n\t\treturn fmt.Errorf(\"nil kext file\")\n\t}\n\n\tif f.handle == windows.Handle(0) || f.handle == windows.InvalidHandle {\n\t\treturn fmt.Errorf(\"invalid handle\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "windows_kext/kextinterface/kext_file_test.go",
    "content": "//go:build linux\n// +build linux\n\npackage kextinterface\n\ntype KextFile struct{}\n\nfunc (f *KextFile) Read(buffer []byte) (int, error) {\n\treturn 0, nil\n}\n\n// func (f *KextFile) flushBuffer() {}\n"
  },
  {
    "path": "windows_kext/kextinterface/protocol_test.go",
    "content": "package kextinterface\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"math/rand\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestRustInfoFile(t *testing.T) {\n\tt.Parallel()\n\n\tfile, err := os.Open(\"testdata/rust_info_test.bin\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer func() {\n\t\t_ = file.Close()\n\t}()\n\tfirst := true\n\tfor {\n\t\tinfo, err := RecvInfo(file)\n\t\t// First info should be with invalid size.\n\t\t// This tests if invalid info data is handled properly.\n\t\tif first {\n\t\t\tif !errors.Is(err, ErrUnexpectedInfoSize) {\n\t\t\t\tt.Errorf(\"unexpected error: %s\\n\", err)\n\t\t\t}\n\t\t\tfirst = false\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\tif errors.Is(err, ErrUnexpectedReadError) {\n\t\t\t\tt.Errorf(\"unexpected error: %s\\n\", err)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tswitch {\n\t\tcase info.LogLine != nil:\n\t\t\tif info.LogLine.Severity != 1 {\n\t\t\t\tt.Errorf(\"unexpected Log severity: %d\\n\", info.LogLine.Severity)\n\t\t\t}\n\t\t\tif info.LogLine.Line != \"prefix: test log\" {\n\t\t\t\tt.Errorf(\"unexpected Log line: %s\\n\", info.LogLine.Line)\n\t\t\t}\n\n\t\tcase info.ConnectionV4 != nil:\n\t\t\tconn := info.ConnectionV4\n\t\t\texpected := connectionV4Internal{\n\t\t\t\tID:           1,\n\t\t\t\tProcessID:    2,\n\t\t\t\tDirection:    3,\n\t\t\t\tProtocol:     4,\n\t\t\t\tLocalIP:      [4]byte{1, 2, 3, 4},\n\t\t\t\tRemoteIP:     [4]byte{2, 3, 4, 5},\n\t\t\t\tLocalPort:    5,\n\t\t\t\tRemotePort:   6,\n\t\t\t\tPayloadLayer: 7,\n\t\t\t}\n\t\t\tif conn.connectionV4Internal != expected {\n\t\t\t\tt.Errorf(\"unexpected ConnectionV4: %+v\\n\", conn)\n\t\t\t}\n\t\t\tif !bytes.Equal(conn.Payload, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {\n\t\t\t\tt.Errorf(\"unexpected ConnectionV4 payload: %+v\\n\", conn.Payload)\n\t\t\t}\n\n\t\tcase info.ConnectionV6 != nil:\n\t\t\tconn := info.ConnectionV6\n\t\t\texpected := connectionV6Internal{\n\t\t\t\tID:           1,\n\t\t\t\tProcessID:    2,\n\t\t\t\tDirection:    3,\n\t\t\t\tProtocol:     4,\n\t\t\t\tLocalIP:      [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},\n\t\t\t\tRemoteIP:     [16]byte{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},\n\t\t\t\tLocalPort:    5,\n\t\t\t\tRemotePort:   6,\n\t\t\t\tPayloadLayer: 7,\n\t\t\t}\n\t\t\tif conn.connectionV6Internal != expected {\n\t\t\t\tt.Errorf(\"unexpected ConnectionV6: %+v\\n\", conn)\n\t\t\t}\n\t\t\tif !bytes.Equal(conn.Payload, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {\n\t\t\t\tt.Errorf(\"unexpected ConnectionV6 payload: %+v\\n\", conn.Payload)\n\t\t\t}\n\n\t\tcase info.ConnectionEndV4 != nil:\n\t\t\tendEvent := info.ConnectionEndV4\n\t\t\texpected := ConnectionEndV4{\n\t\t\t\tProcessID:  1,\n\t\t\t\tDirection:  2,\n\t\t\t\tProtocol:   3,\n\t\t\t\tLocalIP:    [4]byte{1, 2, 3, 4},\n\t\t\t\tRemoteIP:   [4]byte{2, 3, 4, 5},\n\t\t\t\tLocalPort:  4,\n\t\t\t\tRemotePort: 5,\n\t\t\t}\n\t\t\tif *endEvent != expected {\n\t\t\t\tt.Errorf(\"unexpected ConnectionEndV4: %+v\\n\", endEvent)\n\t\t\t}\n\n\t\tcase info.ConnectionEndV6 != nil:\n\t\t\tendEvent := info.ConnectionEndV6\n\t\t\texpected := ConnectionEndV6{\n\t\t\t\tProcessID:  1,\n\t\t\t\tDirection:  2,\n\t\t\t\tProtocol:   3,\n\t\t\t\tLocalIP:    [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},\n\t\t\t\tRemoteIP:   [16]byte{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},\n\t\t\t\tLocalPort:  4,\n\t\t\t\tRemotePort: 5,\n\t\t\t}\n\t\t\tif *endEvent != expected {\n\t\t\t\tt.Errorf(\"unexpected ConnectionEndV6: %+v\\n\", endEvent)\n\t\t\t}\n\n\t\tcase info.BandwidthStats != nil:\n\t\t\tstats := info.BandwidthStats\n\t\t\tif stats.Protocol != 1 {\n\t\t\t\tt.Errorf(\"unexpected Bandwidth stats protocol: %d\\n\", stats.Protocol)\n\t\t\t}\n\n\t\t\tif stats.ValuesV4 != nil {\n\t\t\t\tif len(stats.ValuesV4) != 2 {\n\t\t\t\t\tt.Errorf(\"unexpected Bandwidth stats value length: %d\\n\", len(stats.ValuesV4))\n\t\t\t\t}\n\t\t\t\texpected1 := BandwidthValueV4{\n\t\t\t\t\tLocalIP:          [4]byte{1, 2, 3, 4},\n\t\t\t\t\tLocalPort:        1,\n\t\t\t\t\tRemoteIP:         [4]byte{2, 3, 4, 5},\n\t\t\t\t\tRemotePort:       2,\n\t\t\t\t\tTransmittedBytes: 3,\n\t\t\t\t\tReceivedBytes:    4,\n\t\t\t\t}\n\t\t\t\tif stats.ValuesV4[0] != expected1 {\n\t\t\t\t\tt.Errorf(\"unexpected Bandwidth stats value: %+v expected: %+v\\n\", stats.ValuesV4[0], expected1)\n\t\t\t\t}\n\t\t\t\texpected2 := BandwidthValueV4{\n\t\t\t\t\tLocalIP:          [4]byte{1, 2, 3, 4},\n\t\t\t\t\tLocalPort:        5,\n\t\t\t\t\tRemoteIP:         [4]byte{2, 3, 4, 5},\n\t\t\t\t\tRemotePort:       6,\n\t\t\t\t\tTransmittedBytes: 7,\n\t\t\t\t\tReceivedBytes:    8,\n\t\t\t\t}\n\t\t\t\tif stats.ValuesV4[1] != expected2 {\n\t\t\t\t\tt.Errorf(\"unexpected Bandwidth stats value: %+v expected: %+v\\n\", stats.ValuesV4[1], expected2)\n\t\t\t\t}\n\n\t\t\t} else if stats.ValuesV6 != nil {\n\t\t\t\tif len(stats.ValuesV6) != 2 {\n\t\t\t\t\tt.Errorf(\"unexpected Bandwidth stats value length: %d\\n\", len(stats.ValuesV6))\n\t\t\t\t}\n\n\t\t\t\texpected1 := BandwidthValueV6{\n\t\t\t\t\tLocalIP:          [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},\n\t\t\t\t\tLocalPort:        1,\n\t\t\t\t\tRemoteIP:         [16]byte{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},\n\t\t\t\t\tRemotePort:       2,\n\t\t\t\t\tTransmittedBytes: 3,\n\t\t\t\t\tReceivedBytes:    4,\n\t\t\t\t}\n\t\t\t\tif stats.ValuesV6[0] != expected1 {\n\t\t\t\t\tt.Errorf(\"unexpected Bandwidth stats value: %+v expected: %+v\\n\", stats.ValuesV6[0], expected1)\n\t\t\t\t}\n\t\t\t\texpected2 := BandwidthValueV6{\n\t\t\t\t\tLocalIP:          [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},\n\t\t\t\t\tLocalPort:        5,\n\t\t\t\t\tRemoteIP:         [16]byte{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},\n\t\t\t\t\tRemotePort:       6,\n\t\t\t\t\tTransmittedBytes: 7,\n\t\t\t\t\tReceivedBytes:    8,\n\t\t\t\t}\n\t\t\t\tif stats.ValuesV6[1] != expected2 {\n\t\t\t\t\tt.Errorf(\"unexpected Bandwidth stats value: %+v expected: %+v\\n\", stats.ValuesV6[1], expected2)\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestGenerateCommandFile(t *testing.T) {\n\tt.Parallel()\n\n\tfile, err := os.Create(\"../protocol/testdata/go_command_test.bin\")\n\tif err != nil {\n\t\tt.Errorf(\"failed to create file: %s\", err)\n\t}\n\tdefer func() {\n\t\t_ = file.Close()\n\t}()\n\tenums := []byte{\n\t\tCommandShutdown,\n\t\tCommandVerdict,\n\t\tCommandUpdateV4,\n\t\tCommandUpdateV6,\n\t\tCommandClearCache,\n\t\tCommandGetLogs,\n\t\tCommandBandwidthStats,\n\t\tCommandCleanEndedConnections,\n\t}\n\n\tselected := make([]byte, 5000)\n\tfor i := range selected {\n\t\tselected[i] = enums[rand.Intn(len(enums))] //nolint:gosec\n\t}\n\n\tfor _, value := range selected {\n\t\tswitch value {\n\t\tcase CommandShutdown:\n\t\t\terr := SendShutdownCommand(file)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandVerdict:\n\t\t\terr := SendVerdictCommand(file, Verdict{\n\t\t\t\tID:      1,\n\t\t\t\tVerdict: 2,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandUpdateV4:\n\t\t\terr := SendUpdateV4Command(file, UpdateV4{\n\t\t\t\tProtocol:      1,\n\t\t\t\tLocalAddress:  [4]byte{1, 2, 3, 4},\n\t\t\t\tLocalPort:     2,\n\t\t\t\tRemoteAddress: [4]byte{2, 3, 4, 5},\n\t\t\t\tRemotePort:    3,\n\t\t\t\tVerdict:       4,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandUpdateV6:\n\t\t\terr := SendUpdateV6Command(file, UpdateV6{\n\t\t\t\tProtocol:      1,\n\t\t\t\tLocalAddress:  [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},\n\t\t\t\tLocalPort:     2,\n\t\t\t\tRemoteAddress: [16]byte{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},\n\t\t\t\tRemotePort:    3,\n\t\t\t\tVerdict:       4,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandClearCache:\n\t\t\terr := SendClearCacheCommand(file)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandGetLogs:\n\t\t\terr := SendGetLogsCommand(file)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandBandwidthStats:\n\t\t\terr := SendGetBandwidthStatsCommand(file)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandPrintMemoryStats:\n\t\t\terr := SendPrintMemoryStatsCommand(file)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\n\t\tcase CommandCleanEndedConnections:\n\t\t\terr := SendCleanEndedConnectionsCommand(file)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "windows_kext/kextinterface/version.txt",
    "content": "[2, 1, 0, 0]\n"
  },
  {
    "path": "windows_kext/link-dev.ps1",
    "content": "# Example script for creating debug builds. Libraries may change depending on the version of the WDK that is installed.\n\n$SDK_Version = \"10.0.26100.0\"\n\nlink.exe /OUT:driver.sys `\n/MANIFEST:NO /PROFILE /Driver `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\$SDK_Version\\km\\x64\\wdmsec.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\$SDK_Version\\km\\x64\\ndis.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\$SDK_Version\\km\\x64\\fwpkclnt.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\$SDK_Version\\km\\x64\\BufferOverflowK.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\$SDK_Version\\km\\x64\\ntoskrnl.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\$SDK_Version\\km\\x64\\hal.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\$SDK_Version\\km\\x64\\wmilib.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\wdf\\kmdf\\x64\\1.15\\WdfLdr.lib\" `\n\"C:\\Program Files (x86)\\Windows Kits\\10\\lib\\wdf\\kmdf\\x64\\1.15\\WdfDriverEntry.lib\" `\n \"driver.lib\" `\n/RELEASE /VERSION:\"10.0\" /DEBUG /MACHINE:X64 /ENTRY:\"FxDriverEntry\" /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:NATIVE\",6.01\" /OPT:ICF /ERRORREPORT:PROMPT /MERGE:\"_TEXT=.text;_PAGE=PAGE\" /NOLOGO /NODEFAULTLIB /SECTION:\"INIT,d\"\n\nif(!$?) {\n    Exit $LASTEXITCODE\n}\n"
  },
  {
    "path": "windows_kext/protocol/Cargo.toml",
    "content": "[package]\nname = \"protocol\"\nversion = \"0.0.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nnum = { version = \"0.4\", default-features = false }\nnum-derive = { version = \"0.4\", default-features = false }\nnum-traits = { version = \"0.2\", default-features = false }\n\n[dev-dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "windows_kext/protocol/README.md",
    "content": "# Protocol\n\nDefines protocol that communicates with `kextinterface` / Portmaster.\n\nThe crate implements simple binary protocol. The communications is designed to be concurrent stream of packets.\nInput and output work independent of each other.\n - Pormtaster can read multiple info packets from the queue with single read request.\n - Portmaster can write one command packet to the kernel extension with single write request.\n\n## Info: Kext -> Portmaster\n\nInfo is a packet that sends information/events from the kernel extension to portmaster.\nFor example: `new connection`, `end of connection`, `bandwidth stats` ... check `info.rs` for full list.\n\nThe Info packet contains a header that is 5 bytes\n```\n0                   1                   2                   3                   4\n0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n|   Info Type   |                            Length                             |\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n```\n> Note that one tick mark represents one bit position.\n\nThe header is followed by the info data.\n\n\n## Command: Portmaster -> Kext\n\nCommand is a packet that portmaster sends to the kernel extension.\nFor example: `verdict response`, `shutdown`, `get logs` ... check `command.rs` for full list.\n\nThe header of the command packet is 1 byte\n```\n0 1 2 3 4 5 6 7\n+-+-+-+-+-+-+-+-+\n| Command Type  |\n+-+-+-+-+-+-+-+-+\n```\n> Note that one tick mark represents one bit position.\n\nRest of the packet will be the payload of the command (some commands don't contain payload just the command type).\n\n"
  },
  {
    "path": "windows_kext/protocol/src/command.rs",
    "content": "// Commands from user space\n\nuse num_derive::FromPrimitive;\nuse num_traits::FromPrimitive;\n\n#[repr(u8)]\n#[derive(Clone, Copy, FromPrimitive)]\n#[rustfmt::skip]\npub enum CommandType {\n    Shutdown              = 0,\n    Verdict               = 1,\n    UpdateV4              = 2,\n    UpdateV6              = 3,\n    ClearCache            = 4,\n    GetLogs               = 5,\n    GetBandwidthStats     = 6,\n    PrintMemoryStats      = 7,\n    CleanEndedConnections = 8,\n}\n\n#[repr(C, packed)]\npub struct Command {\n    pub command_type: CommandType,\n    value: [u8; 0],\n}\n\n#[repr(C, packed)]\n#[derive(Debug, PartialEq, Eq)]\npub struct Verdict {\n    pub id: u64,\n    pub verdict: u8,\n}\n\n#[repr(C, packed)]\n#[derive(Debug, PartialEq, Eq)]\npub struct UpdateV4 {\n    pub protocol: u8,\n    pub local_address: [u8; 4],\n    pub local_port: u16,\n    pub remote_address: [u8; 4],\n    pub remote_port: u16,\n    pub verdict: u8,\n}\n\n#[repr(C, packed)]\n#[derive(Debug, PartialEq, Eq)]\npub struct UpdateV6 {\n    pub protocol: u8,\n    pub local_address: [u8; 16],\n    pub local_port: u16,\n    pub remote_address: [u8; 16],\n    pub remote_port: u16,\n    pub verdict: u8,\n}\n\npub fn parse_type(bytes: &[u8]) -> Option<CommandType> {\n    FromPrimitive::from_u8(bytes[0])\n}\n\npub fn parse_verdict(bytes: &[u8]) -> &Verdict {\n    as_type(bytes)\n}\n\npub fn parse_update_v4(bytes: &[u8]) -> &UpdateV4 {\n    as_type(bytes)\n}\n\npub fn parse_update_v6(bytes: &[u8]) -> &UpdateV6 {\n    as_type(bytes)\n}\n\nfn as_type<T>(bytes: &[u8]) -> &T {\n    let ptr: *const u8 = &bytes[0];\n    let t_ptr: *const T = ptr as _;\n    unsafe { t_ptr.as_ref().unwrap() }\n}\n\n#[cfg(test)]\nuse std::fs::File;\n#[cfg(test)]\nuse std::io::Read;\n#[cfg(test)]\nuse std::mem::size_of;\n#[cfg(test)]\nuse std::panic;\n\n#[test]\nfn test_go_command_file() {\n    let mut file = File::open(\"testdata/go_command_test.bin\").unwrap();\n    loop {\n        let mut command: [u8; 1] = [0];\n        let bytes_count = file.read(&mut command).unwrap();\n        if bytes_count == 0 {\n            return;\n        }\n        if let Some(command) = parse_type(&command) {\n            match command {\n                CommandType::Shutdown => {}\n                CommandType::Verdict => {\n                    let mut buf = [0; size_of::<Verdict>()];\n                    let bytes_count = file.read(&mut buf).unwrap();\n                    if bytes_count != size_of::<Verdict>() {\n                        panic!(\"unexpected bytes count\")\n                    }\n\n                    assert_eq!(parse_verdict(&buf), &Verdict { id: 1, verdict: 2 })\n                }\n                CommandType::UpdateV4 => {\n                    let mut buf = [0; size_of::<UpdateV4>()];\n                    let bytes_count = file.read(&mut buf).unwrap();\n                    if bytes_count != size_of::<UpdateV4>() {\n                        panic!(\"unexpected bytes count\")\n                    }\n\n                    assert_eq!(\n                        parse_update_v4(&buf),\n                        &UpdateV4 {\n                            protocol: 1,\n                            local_address: [1, 2, 3, 4],\n                            local_port: 2,\n                            remote_address: [2, 3, 4, 5],\n                            remote_port: 3,\n                            verdict: 4\n                        }\n                    )\n                }\n                CommandType::UpdateV6 => {\n                    let mut buf = [0; size_of::<UpdateV6>()];\n                    let bytes_count = file.read(&mut buf).unwrap();\n                    if bytes_count != size_of::<UpdateV6>() {\n                        panic!(\"unexpected bytes count\")\n                    }\n\n                    assert_eq!(\n                        parse_update_v6(&buf),\n                        &UpdateV6 {\n                            protocol: 1,\n                            local_address: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n                            local_port: 2,\n                            remote_address: [\n                                2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17\n                            ],\n                            remote_port: 3,\n                            verdict: 4\n                        }\n                    )\n                }\n                CommandType::ClearCache => {}\n                CommandType::GetLogs => {}\n                CommandType::GetBandwidthStats => {}\n                CommandType::PrintMemoryStats => {}\n                CommandType::CleanEndedConnections => {}\n            }\n        } else {\n            panic!(\"Unknown command: {}\", command[0]);\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/protocol/src/info.rs",
    "content": "use alloc::vec::Vec;\n\n#[repr(u8)]\n#[derive(Clone, Copy)]\nenum InfoType {\n    LogLine = 0,\n    ConnectionIpv4 = 1,\n    ConnectionIpv6 = 2,\n    ConnectionEndEventV4 = 3,\n    ConnectionEndEventV6 = 4,\n    BandwidthStatsV4 = 5,\n    BandwidthStatsV6 = 6,\n}\n\n// Fallow this pattern when adding new packets: [InfoType: u8, data_size_in_bytes: u32, data: ...]\n\ntrait PushBytes {\n    fn push(self, vec: &mut Vec<u8>);\n}\n\nimpl PushBytes for u8 {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.push(self);\n    }\n}\n\nimpl PushBytes for InfoType {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.push(self as u8);\n    }\n}\n\nimpl PushBytes for u16 {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.extend_from_slice(&u16::to_le_bytes(self));\n    }\n}\n\nimpl PushBytes for u32 {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.extend_from_slice(&u32::to_le_bytes(self));\n    }\n}\n\nimpl PushBytes for u64 {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.extend_from_slice(&u64::to_le_bytes(self));\n    }\n}\n\nimpl PushBytes for usize {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.extend_from_slice(&usize::to_le_bytes(self));\n    }\n}\n\nimpl PushBytes for [u8; 4] {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.extend_from_slice(&self);\n    }\n}\n\nimpl PushBytes for [u8; 16] {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.extend_from_slice(&self);\n    }\n}\n\nimpl PushBytes for &[u8] {\n    fn push(self, vec: &mut Vec<u8>) {\n        vec.extend_from_slice(self);\n    }\n}\n\nmacro_rules! push_bytes {\n    ($vec:expr,$value:expr) => {\n        PushBytes::push($value, $vec);\n    };\n}\n\nmacro_rules! get_combined_size{\n    ($($a:expr),*)=>{{0 $(+core::mem::size_of_val(&$a))*}}\n}\n\npub struct Info(Vec<u8>);\n\nimpl Info {\n    fn new(info_type: InfoType, size: usize) -> Self {\n        let mut vec = Vec::with_capacity(size + 5); // +1 for the info type +4 for the size.\n        push_bytes!(&mut vec, info_type);\n        push_bytes!(&mut vec, size as u32);\n        Self(vec)\n    }\n\n    fn with_capacity(info_type: InfoType, capacity: usize) -> Self {\n        let mut vec = Vec::with_capacity(capacity + 5); // +1 for the info type + 4 for the size.\n        push_bytes!(&mut vec, info_type);\n        push_bytes!(&mut vec, 0 as u32);\n        Self(vec)\n    }\n\n    #[cfg(test)]\n    fn assert_size(&self) {\n        let size = u32::from_le_bytes([self.0[1], self.0[2], self.0[3], self.0[4]]) as usize;\n        assert_eq!(size, self.0.len() - 5);\n    }\n\n    fn update_size(&mut self) {\n        let size = self.0.len() - 5;\n        let bytes = &mut self.0;\n        bytes[1] = size as u8;\n        bytes[2] = (size >> 8) as u8;\n        bytes[3] = (size >> 16) as u8;\n        bytes[4] = (size >> 24) as u8;\n    }\n\n    pub fn as_bytes(&self) -> &[u8] {\n        return self.0.as_slice();\n    }\n}\n\nimpl core::fmt::Write for Info {\n    fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {\n        const MAX_CAPACITY: usize = 500;\n\n        let space_left = self.0.capacity() - self.0.len();\n        if s.len() > space_left {\n            if self.0.capacity() < MAX_CAPACITY {\n                self.0.reserve(MAX_CAPACITY);\n            } else {\n                return Ok(());\n            }\n        }\n\n        self.0.extend_from_slice(s.as_bytes());\n        self.update_size();\n        Ok(())\n    }\n}\n\npub fn connection_info_v4(\n    id: u64,\n    process_id: u64,\n    direction: u8,\n    protocol: u8,\n    local_ip: [u8; 4],\n    remote_ip: [u8; 4],\n    local_port: u16,\n    remote_port: u16,\n    payload_layer: u8,\n    payload: &[u8],\n) -> Info {\n    let mut size = get_combined_size!(\n        id,\n        process_id,\n        direction,\n        protocol,\n        local_ip,\n        remote_ip,\n        local_port,\n        remote_port,\n        payload_layer,\n        payload.len() as u32\n    );\n    size += payload.len();\n\n    let mut info = Info::new(InfoType::ConnectionIpv4, size);\n    let vec = &mut info.0;\n    push_bytes!(vec, id);\n    push_bytes!(vec, process_id);\n    push_bytes!(vec, direction);\n    push_bytes!(vec, protocol);\n    push_bytes!(vec, local_ip);\n    push_bytes!(vec, remote_ip);\n    push_bytes!(vec, local_port);\n    push_bytes!(vec, remote_port);\n    push_bytes!(vec, payload_layer);\n    push_bytes!(vec, payload.len() as u32);\n    push_bytes!(vec, payload);\n    info\n}\n\npub fn connection_info_v6(\n    id: u64,\n    process_id: u64,\n    direction: u8,\n    protocol: u8,\n    local_ip: [u8; 16],\n    remote_ip: [u8; 16],\n    local_port: u16,\n    remote_port: u16,\n    payload_layer: u8,\n    payload: &[u8],\n) -> Info {\n    let mut size = get_combined_size!(\n        id,\n        process_id,\n        direction,\n        protocol,\n        local_ip,\n        remote_ip,\n        local_port,\n        remote_port,\n        payload_layer,\n        payload.len() as u32\n    );\n    size += payload.len();\n    let mut info = Info::new(InfoType::ConnectionIpv6, size);\n    let vec = &mut info.0;\n    push_bytes!(vec, id);\n    push_bytes!(vec, process_id);\n    push_bytes!(vec, direction);\n    push_bytes!(vec, protocol);\n    push_bytes!(vec, local_ip);\n    push_bytes!(vec, remote_ip);\n    push_bytes!(vec, local_port);\n    push_bytes!(vec, remote_port);\n    push_bytes!(vec, payload_layer);\n    push_bytes!(vec, payload.len() as u32);\n    if !payload.is_empty() {\n        push_bytes!(vec, payload);\n    }\n    info\n}\n\npub fn connection_end_event_v4_info(\n    process_id: u64,\n    direction: u8,\n    protocol: u8,\n    local_ip: [u8; 4],\n    remote_ip: [u8; 4],\n    local_port: u16,\n    remote_port: u16,\n) -> Info {\n    let size = get_combined_size!(\n        process_id,\n        direction,\n        protocol,\n        local_ip,\n        remote_ip,\n        local_port,\n        remote_port\n    );\n    let mut info = Info::new(InfoType::ConnectionEndEventV4, size);\n    let vec = &mut info.0;\n    push_bytes!(vec, process_id);\n    push_bytes!(vec, direction);\n    push_bytes!(vec, protocol);\n    push_bytes!(vec, local_ip);\n    push_bytes!(vec, remote_ip);\n    push_bytes!(vec, local_port);\n    push_bytes!(vec, remote_port);\n    info\n}\n\npub fn connection_end_event_v6_info(\n    process_id: u64,\n    direction: u8,\n    protocol: u8,\n    local_ip: [u8; 16],\n    remote_ip: [u8; 16],\n    local_port: u16,\n    remote_port: u16,\n) -> Info {\n    let size = get_combined_size!(\n        process_id,\n        direction,\n        protocol,\n        local_ip,\n        remote_ip,\n        local_port,\n        remote_port\n    );\n    let mut info = Info::new(InfoType::ConnectionEndEventV6, size);\n    let vec = &mut info.0;\n    push_bytes!(vec, process_id);\n    push_bytes!(vec, direction);\n    push_bytes!(vec, protocol);\n    push_bytes!(vec, local_ip);\n    push_bytes!(vec, remote_ip);\n    push_bytes!(vec, local_port);\n    push_bytes!(vec, remote_port);\n    info\n}\n\n#[repr(u8)]\n#[derive(Clone, Copy)]\npub enum Severity {\n    Trace = 1,\n    Debug = 2,\n    Info = 3,\n    Warning = 4,\n    Error = 5,\n    Critical = 6,\n    Disabled = 7,\n}\n\n// pub fn log_line(severity: Severity, prefix: String, line: String) -> Info {\n//     let mut size = get_combined_size!(severity);\n//     size += prefix.len() + line.len();\n\n//     let mut info = Info::new(InfoType::LogLine, size);\n//     let vec = &mut info.0;\n//     push_bytes!(vec, severity as u8);\n//     push_bytes!(vec, prefix.as_bytes());\n//     push_bytes!(vec, line.as_bytes());\n//     info\n// }\n\npub fn log_line(severity: Severity, capacity: usize) -> Info {\n    let mut info = Info::with_capacity(InfoType::LogLine, capacity);\n    let vec = &mut info.0;\n    push_bytes!(vec, severity as u8);\n    info\n}\n\n// Special struct for Bandwidth stats\npub struct BandwidthValueV4 {\n    pub local_ip: [u8; 4],\n    pub local_port: u16,\n    pub remote_ip: [u8; 4],\n    pub remote_port: u16,\n    pub transmitted_bytes: u64,\n    pub received_bytes: u64,\n}\n\nimpl BandwidthValueV4 {\n    fn get_size(&self) -> usize {\n        get_combined_size!(\n            self.local_ip,\n            self.local_port,\n            self.remote_ip,\n            self.remote_port,\n            self.transmitted_bytes,\n            self.received_bytes\n        )\n    }\n}\n\nimpl PushBytes for BandwidthValueV4 {\n    fn push(self, vec: &mut Vec<u8>) {\n        push_bytes!(vec, self.local_ip);\n        push_bytes!(vec, self.local_port);\n        push_bytes!(vec, self.remote_ip);\n        push_bytes!(vec, self.remote_port);\n        push_bytes!(vec, self.transmitted_bytes);\n        push_bytes!(vec, self.received_bytes);\n    }\n}\n\npub struct BandwidthValueV6 {\n    pub local_ip: [u8; 16],\n    pub local_port: u16,\n    pub remote_ip: [u8; 16],\n    pub remote_port: u16,\n    pub transmitted_bytes: u64,\n    pub received_bytes: u64,\n}\n\nimpl BandwidthValueV6 {\n    fn get_size(&self) -> usize {\n        get_combined_size!(\n            self.local_ip,\n            self.local_port,\n            self.remote_ip,\n            self.remote_port,\n            self.transmitted_bytes,\n            self.received_bytes\n        )\n    }\n}\n\nimpl PushBytes for BandwidthValueV6 {\n    fn push(self, vec: &mut Vec<u8>) {\n        push_bytes!(vec, self.local_ip);\n        push_bytes!(vec, self.local_port);\n        push_bytes!(vec, self.remote_ip);\n        push_bytes!(vec, self.remote_port);\n        push_bytes!(vec, self.transmitted_bytes);\n        push_bytes!(vec, self.received_bytes);\n    }\n}\n\npub fn bandiwth_stats_array_v4(protocol: u8, values: Vec<BandwidthValueV4>) -> Info {\n    let mut size = get_combined_size!(protocol, values.len() as u32);\n\n    if !values.is_empty() {\n        size += values[0].get_size() * values.len();\n    }\n\n    let mut info = Info::new(InfoType::BandwidthStatsV4, size);\n    let vec = &mut info.0;\n    push_bytes!(vec, protocol);\n    push_bytes!(vec, values.len() as u32);\n    for v in values {\n        push_bytes!(vec, v);\n    }\n    info\n}\n\npub fn bandiwth_stats_array_v6(protocol: u8, values: Vec<BandwidthValueV6>) -> Info {\n    let mut size = get_combined_size!(protocol, values.len() as u32);\n\n    if !values.is_empty() {\n        size += values[0].get_size() * values.len();\n    }\n\n    let mut info = Info::new(InfoType::BandwidthStatsV6, size);\n    let vec = &mut info.0;\n    push_bytes!(vec, protocol);\n    push_bytes!(vec, values.len() as u32);\n    for v in values {\n        push_bytes!(vec, v);\n    }\n    info\n}\n\n#[cfg(test)]\nuse std::fs::File;\n#[cfg(test)]\nuse std::io::Write;\n\n#[cfg(test)]\nuse rand::seq::SliceRandom;\n\n#[test]\nfn generate_test_info_file() -> Result<(), std::io::Error> {\n    let mut file = File::create(\"../kextinterface/testdata/rust_info_test.bin\")?;\n    let enums = [\n        InfoType::LogLine,\n        InfoType::ConnectionIpv4,\n        InfoType::ConnectionIpv6,\n        InfoType::ConnectionEndEventV4,\n        InfoType::ConnectionEndEventV6,\n        InfoType::BandwidthStatsV4,\n        InfoType::BandwidthStatsV6,\n    ];\n\n    let mut selected: Vec<InfoType> = Vec::with_capacity(1000);\n    let mut rng = rand::thread_rng();\n    for _ in 0..selected.capacity() {\n        selected.push(enums.choose(&mut rng).unwrap().clone());\n    }\n    // Write wrong size data. To make sure that mismatches between kext and portmaster are handled properly.\n    let mut info = connection_info_v6(\n        1,\n        2,\n        3,\n        4,\n        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n        [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],\n        5,\n        6,\n        7,\n        &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],\n    );\n    info.assert_size();\n    info.0[0] = InfoType::ConnectionIpv4 as u8;\n    file.write_all(&info.0)?;\n\n    for value in selected {\n        file.write_all(&match value {\n            InfoType::LogLine => {\n                let mut info = log_line(Severity::Trace, 5);\n                use std::fmt::Write;\n                _ = write!(info, \"prefix: test log\");\n                info.assert_size();\n                info.0\n            }\n            InfoType::ConnectionIpv4 => {\n                let info = connection_info_v4(\n                    1,\n                    2,\n                    3,\n                    4,\n                    [1, 2, 3, 4],\n                    [2, 3, 4, 5],\n                    5,\n                    6,\n                    7,\n                    &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],\n                );\n                info.assert_size();\n                info.0\n            }\n\n            InfoType::ConnectionIpv6 => {\n                let info = connection_info_v6(\n                    1,\n                    2,\n                    3,\n                    4,\n                    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n                    [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],\n                    5,\n                    6,\n                    7,\n                    &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],\n                );\n                info.assert_size();\n                info.0\n            }\n            InfoType::ConnectionEndEventV4 => {\n                let info = connection_end_event_v4_info(1, 2, 3, [1, 2, 3, 4], [2, 3, 4, 5], 4, 5);\n                info.assert_size();\n                info.0\n            }\n            InfoType::ConnectionEndEventV6 => {\n                let info = connection_end_event_v6_info(\n                    1,\n                    2,\n                    3,\n                    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n                    [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],\n                    4,\n                    5,\n                );\n                info.assert_size();\n                info.0\n            }\n            InfoType::BandwidthStatsV4 => {\n                let mut vec = Vec::new();\n                vec.push(BandwidthValueV4 {\n                    local_ip: [1, 2, 3, 4],\n                    local_port: 1,\n                    remote_ip: [2, 3, 4, 5],\n                    remote_port: 2,\n                    transmitted_bytes: 3,\n                    received_bytes: 4,\n                });\n                vec.push(BandwidthValueV4 {\n                    local_ip: [1, 2, 3, 4],\n                    local_port: 5,\n                    remote_ip: [2, 3, 4, 5],\n                    remote_port: 6,\n                    transmitted_bytes: 7,\n                    received_bytes: 8,\n                });\n                let info = bandiwth_stats_array_v4(1, vec);\n                info.assert_size();\n                info.0\n            }\n            InfoType::BandwidthStatsV6 => {\n                let mut vec = Vec::new();\n                vec.push(BandwidthValueV6 {\n                    local_ip: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n                    local_port: 1,\n                    remote_ip: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],\n                    remote_port: 2,\n                    transmitted_bytes: 3,\n                    received_bytes: 4,\n                });\n                vec.push(BandwidthValueV6 {\n                    local_ip: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],\n                    local_port: 5,\n                    remote_ip: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],\n                    remote_port: 6,\n                    transmitted_bytes: 7,\n                    received_bytes: 8,\n                });\n                let info = bandiwth_stats_array_v6(1, vec);\n                info.assert_size();\n                info.0\n            }\n        })?;\n    }\n\n    return Ok(());\n}\n"
  },
  {
    "path": "windows_kext/protocol/src/lib.rs",
    "content": "#![cfg_attr(not(test), no_std)]\nextern crate alloc;\n\npub mod command;\npub mod info;\n"
  },
  {
    "path": "windows_kext/test/BUILD_DEBUG.md",
    "content": "# Building and Running Driver with Debug Logging\n\n## Driver Signing Requirement\n\nWindows requires **all kernel drivers to be signed**. Test signing provides a free alternative to expensive production code signing certificates for development and testing purposes.\n\n## Important: Debug Builds Are Disabled\n\n⚠️ **The driver cannot be compiled in debug mode.** The code contains a compile-time check (`compile_error!`) that prevents debug builds due to potential optimization-related issues and inconsistent compiler behavior between debug and release modes.\n\nHowever, you can still enable verbose logging in release builds by changing the log level.\n\n## Prerequisites\n\nAlready documented in [main README](../README.md), but quick recap:\n\n1. **Visual Studio 2022** with C++ and Windows SDK\n2. **Windows Driver Kit (WDK)** installed\n3. **Rust toolchain** installed\n4. **Test signing enabled** (see below)\n\n## Step 1: Enable Test Signing (One-time Setup)\n\n⚠️ **SECURITY WARNING**: Test signing reduces system security by allowing any locally-generated test certificate to load kernel drivers. **Strongly recommended to use a VM or dedicated test machine**. See \"Disabling Test Signing\" section below to restore security when done testing.\n\n### Create Test Certificate\n\nOpen **PowerShell as Administrator**:\n\n```powershell\n# Create a self-signed certificate for driver testing\nMakeCert -r -pe -ss PrivateCertStore -n \"CN=DriverTestCert\" DriverTestCert.cer\n\n# Install the certificate to Trusted Root\nCertMgr /add DriverTestCert.cer /s /r localMachine root\n\n# Install to Trusted Publishers (needed for driver installation)\nCertMgr /add DriverTestCert.cer /s /r localMachine trustedpublisher\n```\n\n### Enable Test Signing Mode\n\n```powershell\n# Enable test signing\nBcdedit.exe -set TESTSIGNING ON\n\n# Restart required!\nRestart-Computer\n```\n\nAfter restart, you should see **\"Test Mode\"** watermark in the corner of your screen.\n\n### Verify Test Signing is Enabled\n\n```powershell\nbcdedit /enum | Select-String testsigning\n# Should show: testsigning Yes\n```\n\n## Step 2: Enable Debug Logging in Driver\n\nTo see verbose logs from the driver, edit the log level before building.\n\n**Edit `driver/src/logger.rs`:**\n\n```rust\n// Change line 8 from:\npub const LOG_LEVEL: u8 = Severity::Warning as u8;\n\n// To one of:\npub const LOG_LEVEL: u8 = Severity::Debug as u8;   // Recommended for testing\n// pub const LOG_LEVEL: u8 = Severity::Info as u8;    // Less verbose\n// pub const LOG_LEVEL: u8 = Severity::Trace as u8;   // Most verbose\n```\n\nFor testing, `Debug` level is recommended.\n\n## Step 3: Build Driver in Release Mode\n\nNavigate to the driver directory:\n\n```powershell\ncd D:\\Projects\\Portmaster\\portmaster\\windows_kext\\driver\n\n# Build in release mode (only mode supported)\ncargo build --release --target x86_64-pc-windows-msvc\n\n# Output: driver/target/x86_64-pc-windows-msvc/release/driver.lib\n```\n\n**Note:** Debug builds (`cargo build` without `--release`) will fail with a compile error by design.\n\n## Step 4: Link the Driver\n\nCopy the `.lib` file to the root directory:\n\n```powershell\ncd D:\\Projects\\Portmaster\\portmaster\\windows_kext\n\nCopy-Item driver/target/x86_64-pc-windows-msvc/release/driver.lib . -Force\n```\n\nRun the linker script:\n\n```powershell\n.\\link-dev.ps1\n```\n\nThis creates `driver.sys` in the current directory.\n\n## Step 5: Sign the Driver\n\n## Step 5: Sign the Driver\n\n```powershell\ncd D:\\Projects\\Portmaster\\portmaster\\windows_kext\n\n# Sign the driver\nSignTool sign /v /s PrivateCertStore /n DriverTestCert driver.sys\n```\n\nVerify signature:\n\n```powershell\nSignTool verify /v /pa driver.sys\n```\n\nYou should see: **\"Successfully verified: driver.sys\"**\n\n## Step 6: View Driver Logs\n\n### Ring Buffer Logs (Recommended)\n\nThese logs come through the `GetLogs` command.\n\n### Kernel Debugger Output (Not Available in Release)\n\nThe `wdk::dbg!()`, `wdk::info!()`, and `wdk::err!()` macros only work in debug builds, which are disabled for this driver. These would output to tools like DebugView via `DbgPrint`, but since debug builds are not allowed, this logging path is not available.\n\n**Use the ring buffer logs** (captured by `dbg!`, `info!`, `warn!`, `err!` macros) for all debugging.\n\n## Common Issues\n\n### \"The hash for the file is not present in the specified catalog file\"\n\n**Solution**: Your driver isn't signed or the certificate isn't trusted.\n```powershell\n# Re-sign the driver\nSignTool sign /v /s PrivateCertStore /n DriverTestCert driver.sys\n```\n\n### \"Windows cannot verify the digital signature\"\n\n**Solution**: Test signing not enabled or certificate not in Trusted Root.\n```powershell\n# Check test signing\nbcdedit /enum | Select-String testsigning\n\n# Reinstall certificate if needed\nCertMgr /add DriverTestCert.cer /s /r localMachine root\n```\n\n### \"Service marked for deletion\"\n\n**Solution**: Manually clean up:\n```powershell\nsc stop PortmasterKext\nsc delete PortmasterKext\n# Wait a few seconds\n# Then try starting again\n```\n\n### \"Access is denied\" when creating service\n\n**Solution**: Run as Administrator.\n\n### No debug output (`GetLogs` command)\n\n**Solution**: \n1. Make sure you edited `driver/src/logger.rs` to set `LOG_LEVEL = Severity::Debug`\n2. Rebuild the driver in **release mode** (`cargo build --release`)\n3. The driver must be actively running and processing connections to generate logs\n4. Default log level (`Warning`) only shows errors, not normal operations\n\n## Quick Build & Test Cycle\n\n```powershell\n# 1. (Optional) Enable debug logging - edit driver/src/logger.rs first\n\n# 2. Build driver in release mode\ncd D:\\Projects\\Portmaster\\portmaster\\windows_kext\\driver\ncargo build --release\n\n# 3. Link and sign\ncd ..\nCopy-Item driver/target/x86_64-pc-windows-msvc/release/driver.lib . -Force\n.\\link-dev.ps1\nSignTool sign /v /s PrivateCertStore /n DriverTestCert driver.sys\n\n# 4. Test (in playground, as Administrator)\n```\n\n## Disabling Test Signing (When Done Testing)\n\n⚠️ **IMPORTANT**: When finished testing, disable test signing to restore system security.\n\n```powershell\n# Run as Administrator\nBcdedit.exe -set TESTSIGNING OFF\n\n# Restart required for changes to take effect\nRestart-Computer\n```\n\nAfter restart, the \"Test Mode\" watermark will disappear and the system will no longer accept test-signed drivers. This restores normal kernel driver security enforcement.Production vs Test Signing"
  },
  {
    "path": "windows_kext/test/README.md",
    "content": "# Test Directory\n\n> ⚠️ **Notice**: This folder and its contents were primarily generated with the assistance of AI and may contain errors or inaccuracies. They are intended solely for local testing and development and must not be used in production.\n\n## Contents\n\n- `build_test.ps1` - Script to build the test-signed driver\n- `_out/` - Output directory for built test driver\n- `_testcert/` - Test certificates for driver signing\n\n## Purpose\n\nThis directory contains tools and utilities for testing the Portmaster Windows kernel driver during development. These are developer tools only and are not part of the production build or release process.\n"
  },
  {
    "path": "windows_kext/test/build_test.ps1",
    "content": "﻿# Build and Sign Test Driver Script\n# Must be run from Developer PowerShell for Visual Studio\n\n$ErrorActionPreference = \"Stop\"\n\n# Get script directory and set paths\n$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path\n$rootDir = Split-Path -Parent $scriptDir\n$driverDir = Join-Path $rootDir \"driver\"\n$certPath = Join-Path $rootDir \"test\\_testcert\\DriverTestCert.cer\"\n$outDir = Join-Path $scriptDir \"_out\"\n\n# Create output directory if it doesn't exist\nif (-not (Test-Path $outDir)) {\n    New-Item -ItemType Directory -Path $outDir -Force | Out-Null\n}\n\nWrite-Host \"=================================================\" -ForegroundColor Cyan\nWrite-Host \"  Building and Signing Test Driver\" -ForegroundColor Cyan\nWrite-Host \"=================================================\" -ForegroundColor Cyan\nWrite-Host \"\"\n\n# Verify we are in the correct directory\nif (-not (Test-Path $driverDir)) {\n    Write-Host \"ERROR: Driver directory not found at: $driverDir\" -ForegroundColor Red\n    Write-Host \"Please run this script from the windows_kext root directory or ensure paths are correct.\" -ForegroundColor Red\n    exit 1\n}\n\n# Verify certificate exists\nif (-not (Test-Path $certPath)) {\n    Write-Host \"ERROR: Certificate not found at: $certPath\" -ForegroundColor Red\n    Write-Host \"Please create the test certificate first.\" -ForegroundColor Red\n    exit 1\n}\n\n#\n# Step 1: Build Driver in Release Mode\n#\nWrite-Host \"[1/3] Building driver in release mode...\" -ForegroundColor Yellow\nPush-Location $driverDir\ntry {\n    cargo build --release --target x86_64-pc-windows-msvc\n    \n    if ($LASTEXITCODE -ne 0) {\n        Write-Host \"ERROR: Cargo build failed with exit code $LASTEXITCODE\" -ForegroundColor Red\n        exit $LASTEXITCODE\n    }\n    \n    Write-Host \"   Driver built successfully\" -ForegroundColor Green\n} finally {\n    Pop-Location\n}\n\n#\n# Step 2: Link the Driver\n#\nWrite-Host \"[2/3] Linking driver...\" -ForegroundColor Yellow\nPush-Location $outDir\ntry {\n    # Copy the .lib file to output directory\n    $libSource = Join-Path $driverDir \"target\\x86_64-pc-windows-msvc\\release\\driver.lib\"\n    $libDest = Join-Path $outDir \"driver.lib\"\n    \n    if (-not (Test-Path $libSource)) {\n        Write-Host \"ERROR: Built driver.lib not found at: $libSource\" -ForegroundColor Red\n        exit 1\n    }\n    \n    Copy-Item $libSource $libDest -Force\n    Write-Host \"   Copied driver.lib\" -ForegroundColor Green\n    \n    # Run linker script (from output directory so files are created here)\n    $linkScript = Join-Path $rootDir \"link-dev.ps1\"\n    if (-not (Test-Path $linkScript)) {\n        Write-Host \"ERROR: link-dev.ps1 not found at: $linkScript\" -ForegroundColor Red\n        exit 1\n    }\n    \n    & $linkScript\n    if ($LASTEXITCODE -ne 0) {\n        Write-Host \"ERROR: Linking failed with exit code $LASTEXITCODE\" -ForegroundColor Red\n        exit $LASTEXITCODE\n    }\n    \n    # Rename driver.sys to test name\n    $sysFile = Join-Path $outDir \"driver.sys\"\n    if (-not (Test-Path $sysFile)) {\n        Write-Host \"ERROR: driver.sys was not created\" -ForegroundColor Red\n        exit 1\n    }\n    \n    $testSysFile = Join-Path $outDir \"PortmasterKext_test.sys\"\n    Move-Item $sysFile $testSysFile -Force\n    \n    Write-Host \"   Driver linked successfully (PortmasterKext_test.sys)\" -ForegroundColor Green\n} finally {\n    Pop-Location\n}\n\n#\n# Step 3: Sign the Driver\n#\nWrite-Host \"[3/3] Signing driver...\" -ForegroundColor Yellow\nPush-Location $outDir\ntry {\n    $sysFile = Join-Path $outDir \"PortmasterKext_test.sys\"\n    \n    # Sign the driver\n    SignTool sign /v /fd SHA256 /s PrivateCertStore /n DriverTestCert $sysFile\n    \n    if ($LASTEXITCODE -ne 0) {\n        Write-Host \"ERROR: Signing failed with exit code $LASTEXITCODE\" -ForegroundColor Red\n        Write-Host \"Make sure the certificate is installed in PrivateCertStore\" -ForegroundColor Yellow\n        exit $LASTEXITCODE\n    }\n    \n    Write-Host \"   Driver signed successfully\" -ForegroundColor Green\n    \n    # Verify signature\n    Write-Host \"\"\n    Write-Host \"Verifying signature...\" -ForegroundColor Yellow\n    SignTool verify /v /pa $sysFile\n    \n    if ($LASTEXITCODE -ne 0) {\n        Write-Host \"WARNING: Signature verification failed\" -ForegroundColor Yellow\n    } else {\n        Write-Host \"   Signature verified\" -ForegroundColor Green\n    }\n} finally {\n    Pop-Location\n}\n\nWrite-Host \"\"\nWrite-Host \"=================================================\" -ForegroundColor Cyan\nWrite-Host \"  Build Complete!\" -ForegroundColor Green\nWrite-Host \"=================================================\" -ForegroundColor Cyan\nWrite-Host \"\"\nWrite-Host \"Output directory: $outDir\" -ForegroundColor White\nWrite-Host \"Driver file: PortmasterKext_test.sys\" -ForegroundColor White\nWrite-Host \"\"\nWrite-Host \"Next steps:\" -ForegroundColor Yellow\nWrite-Host \"  1. Run playground as Administrator\" -ForegroundColor White\nWrite-Host \"  2. Use start command to load the driver\" -ForegroundColor White\nWrite-Host \"\"\n"
  },
  {
    "path": "windows_kext/test_protocol.sh",
    "content": "#!/bin/sh\necho Running tests\necho ========================\ncd protocol\ncargo test\n\ncd ../kextinterface\ngo test -v .\n"
  },
  {
    "path": "windows_kext/wdk/.cargo/config.toml",
    "content": "[build]\ntarget = \"x86_64-pc-windows-msvc\"\n"
  },
  {
    "path": "windows_kext/wdk/Cargo.toml",
    "content": "[package]\nname = \"wdk\"\nversion = \"0.0.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nntstatus = { version = \"0.1.2\", default-features = false }\n\n[dependencies.widestring]\nversion = \"1.0.2\"\ndefault-features = false \nfeatures = [\"alloc\"]\n\n# WARNING: Do not update. The version was choosen for a reason. See wdk/README.md for more detiels.\n[dependencies.windows-sys]\ngit = \"https://github.com/microsoft/windows-rs\"\nrev = \"dffa8b03dc4987c278d82e88015ffe96aa8ac317\"\nfeatures = [\"Wdk_Foundation\", \"Wdk_Storage_FileSystem\", \"Wdk_System_SystemServices\", \"Win32_Foundation\", \"Win32_Security\", \"Win32_System_IO\", \"Win32_System_Kernel\", \"Win32_System_Power\", \"Win32_System_WindowsProgramming\", \"Win32_NetworkManagement_IpHelper\", \"Win32_Networking_WinSock\", \"Win32_NetworkManagement_WindowsFilteringPlatform\", \"Win32_System_Rpc\"]\n"
  },
  {
    "path": "windows_kext/wdk/README.md",
    "content": "# WDK (Windows Driver Kit)\n\nA library that interfaces with the windows kernel.  \nThe crate has extensive use of **unsafe** rust, be more causes when making changes.\n\nDo not update `windows-sys` dependency.\nThe version contains bugs that have specific workarounds in this crate. Updating without reviewing the new version can result in broken build or undefined behavior.\n\nsee: `wdk/src/driver.rs`\nsee: `wdk/src/irp_helper.rs`\n\nOpen issues need to be resolved:\nhttps://github.com/microsoft/windows-rs/issues/2805\n\nResolved:\nhttps://github.com/microsoft/wdkmetadata/issues/59\n"
  },
  {
    "path": "windows_kext/wdk/build.rs",
    "content": "#[cfg(target_arch = \"x86_64\")]\r\nfn main() {\r\n    // C Helper\r\n    println!(\"cargo:rerun-if-changed=../c_helper/x64/c_helper.lib\");\r\n    println!(\"cargo:rustc-link-search=native=../c_helper/x64\");\r\n}\r\n\r\n#[cfg(target_arch = \"aarch64\")]\r\nfn main() {\r\n    // C Helper\r\n    println!(\"cargo:rerun-if-changed=../c_helper/ARM64/c_helper.lib\");\r\n    println!(\"cargo:rustc-link-search=native=../c_helper/ARM64\");\r\n}\r\n"
  },
  {
    "path": "windows_kext/wdk/rust-analyzer.cargo.target",
    "content": "x86_64-pc-windows-msvc"
  },
  {
    "path": "windows_kext/wdk/rust-toolchain",
    "content": "stable\n"
  },
  {
    "path": "windows_kext/wdk/src/allocator.rs",
    "content": "extern crate alloc;\n\nuse core::alloc::{GlobalAlloc, Layout};\n\nuse alloc::alloc::handle_alloc_error;\nuse windows_sys::Wdk::System::SystemServices::{ExAllocatePool2, ExFreePoolWithTag};\n\n// For reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/pool_flags\n#[allow(dead_code)]\n#[repr(u64)]\nenum PoolType {\n    RequiredStartUseQuota = 0x0000000000000001,\n    Uninitialized = 0x0000000000000002, // Don't zero-initialize allocation\n    Session = 0x0000000000000004,       // Use session specific pool\n    CacheAligned = 0x0000000000000008,  // Cache aligned allocation\n    RaiseOnFailure = 0x0000000000000020, // Raise exception on failure\n    NonPaged = 0x0000000000000040,      // Non paged pool NX\n    NonPagedExecute = 0x0000000000000080, // Non paged pool executable\n    Paged = 0x0000000000000100,         // Paged pool\n    RequiredEnd = 0x0000000080000000,\n    OptionalStart = 0x0000000100000000,\n    OptionalEnd = 0x8000000000000000,\n}\n\npub struct WindowsAllocator {}\n\nunsafe impl Sync for WindowsAllocator {}\n\npub(crate) const POOL_TAG: u32 = u32::from_ne_bytes(*b\"PMrs\");\n\nunsafe impl GlobalAlloc for WindowsAllocator {\n    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {\n        let pool = ExAllocatePool2(PoolType::NonPaged as u64, layout.size(), POOL_TAG);\n        if pool.is_null() {\n            handle_alloc_error(layout);\n        }\n\n        pool as *mut u8\n    }\n\n    unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {\n        ExFreePoolWithTag(ptr as _, POOL_TAG);\n    }\n\n    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {\n        \n        self.alloc(layout)\n    }\n\n    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {\n        // SAFETY: the caller must ensure that the `new_size` does not overflow.\n        // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.\n        let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };\n        // SAFETY: the caller must ensure that `new_layout` is greater than zero.\n        let new_ptr = unsafe { self.alloc(new_layout) };\n        if !new_ptr.is_null() {\n            // SAFETY: the previously allocated block cannot overlap the newly allocated block.\n            // The safety contract for `dealloc` must be upheld by the caller.\n            unsafe {\n                core::ptr::copy_nonoverlapping(\n                    ptr,\n                    new_ptr,\n                    core::cmp::min(layout.size(), new_size),\n                );\n                self.dealloc(ptr, layout);\n            }\n        }\n        new_ptr\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/attributes.rs",
    "content": "extern crate proc_macro;\nuse proc_macro::TokenStream;\nuse quote::quote;\n\n// using proc_macro_attribute to declare an attribute like procedural macro\n\n#[proc_macro_attribute]\n// _metadata is argument provided to macro call and _input is code to which attribute like macro attaches\npub fn my_custom_attribute(_metadata: TokenStream, _input: TokenStream) -> TokenStream {\n    // returning a simple TokenStream for Struct\n    TokenStream::from(quote! {struct H{}})\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/consts.rs",
    "content": "// Actions\npub const FWP_ACTION_FLAG_TERMINATING: u32 = 0x00001000;\npub const FWP_ACTION_FLAG_NON_TERMINATING: u32 = 0x00002000;\npub const FWP_ACTION_FLAG_CALLOUT: u32 = 0x00004000;\n\npub const FWP_ACTION_BLOCK: u32 = 0x00000001 | FWP_ACTION_FLAG_TERMINATING;\npub const FWP_ACTION_PERMIT: u32 = 0x00000002 | FWP_ACTION_FLAG_TERMINATING;\npub const FWP_ACTION_CALLOUT_TERMINATING: u32 =\n    0x00000003 | FWP_ACTION_FLAG_CALLOUT | FWP_ACTION_FLAG_TERMINATING;\npub const FWP_ACTION_CALLOUT_INSPECTION: u32 =\n    0x00000004 | FWP_ACTION_FLAG_CALLOUT | FWP_ACTION_FLAG_NON_TERMINATING;\npub const FWP_ACTION_CALLOUT_UNKNOWN: u32 = 0x00000005 | FWP_ACTION_FLAG_CALLOUT;\npub const FWP_ACTION_CONTINUE: u32 = 0x00000006 | FWP_ACTION_FLAG_NON_TERMINATING;\npub const FWP_ACTION_NONE: u32 = 0x00000007;\npub const FWP_ACTION_NONE_NO_MATCH: u32 = 0x00000008;\npub const FWP_CONDITION_FLAG_IS_LOOPBACK: u32 = 0x00000001;\npub const FWP_CONDITION_FLAG_IS_IPSEC_SECURED: u32 = 0x00000002;\npub const FWP_CONDITION_FLAG_IS_REAUTHORIZE: u32 = 0x00000004;\npub const FWP_CONDITION_FLAG_IS_WILDCARD_BIND: u32 = 0x00000008;\npub const FWP_CONDITION_FLAG_IS_RAW_ENDPOINT: u32 = 0x00000010;\npub const FWP_CONDITION_FLAG_IS_FRAGMENT: u32 = 0x00000020;\npub const FWP_CONDITION_FLAG_IS_FRAGMENT_GROUP: u32 = 0x00000040;\npub const FWP_CONDITION_FLAG_IS_IPSEC_NATT_RECLASSIFY: u32 = 0x00000080;\npub const FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY: u32 = 0x00000100;\npub const FWP_CONDITION_FLAG_IS_IMPLICIT_BIND: u32 = 0x00000200;\npub const FWP_CONDITION_FLAG_IS_REASSEMBLED: u32 = 0x00000400;\npub const FWP_CONDITION_FLAG_IS_NAME_APP_SPECIFIED: u32 = 0x00004000;\npub const FWP_CONDITION_FLAG_IS_PROMISCUOUS: u32 = 0x00008000;\npub const FWP_CONDITION_FLAG_IS_AUTH_FW: u32 = 0x00010000;\npub const FWP_CONDITION_FLAG_IS_RECLASSIFY: u32 = 0x00020000;\npub const FWP_CONDITION_FLAG_IS_OUTBOUND_PASS_THRU: u32 = 0x00040000;\npub const FWP_CONDITION_FLAG_IS_INBOUND_PASS_THRU: u32 = 0x00080000;\npub const FWP_CONDITION_FLAG_IS_CONNECTION_REDIRECTED: u32 = 0x00100000;\n\n// Driver\npub const METHOD_BUFFERED: u32 = 0;\npub const METHOD_IN_DIRECT: u32 = 1;\npub const METHOD_OUT_DIRECT: u32 = 2;\npub const METHOD_NEITHER: u32 = 3;\n\npub const SIOCTL_TYPE: u32 = 40000;\n\npub const FILE_READ_DATA: u32 = 0x00000001;\npub const FILE_READ_ATTRIBUTES: u32 = 0x00000080;\npub const FILE_READ_EA: u32 = 0x00000008;\npub const FILE_WRITE_DATA: u32 = 0x00000002;\npub const FILE_WRITE_ATTRIBUTES: u32 = 0x00000100;\npub const FILE_WRITE_EA: u32 = 0x00000010;\npub const FILE_APPEND_DATA: u32 = 0x00000004;\npub const FILE_EXECUTE: u32 = 0x00000020;\n"
  },
  {
    "path": "windows_kext/wdk/src/debug.rs",
    "content": "#[cfg(debug_assertions)]\n#[macro_export]\nmacro_rules! log {\n    ($level:expr, $($arg:tt)*) => ({\n        let message = alloc::format!($($arg)*);\n        $crate::interface::dbg_print(alloc::format!(\"{} {}: {}\", $level, core::module_path!(), message));\n    });\n}\n\n#[cfg(not(debug_assertions))]\n#[macro_export]\nmacro_rules! log {\n    ($($arg:expr),*) => {{\n        $(\n            _ = $arg;\n        )*\n    }};\n}\n\n#[macro_export]\nmacro_rules! err {\n    ($($arg:tt)*) => ($crate::log!(\"ERROR\", $($arg)*));\n}\n\n#[macro_export]\nmacro_rules! dbg {\n    ($($arg:tt)*) => ($crate::log!(\"DEBUG\", $($arg)*));\n}\n\n#[macro_export]\nmacro_rules! info {\n    ($($arg:tt)*) => ($crate::log!(\"INFO\", $($arg)*));\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/driver.rs",
    "content": "use windows_sys::{\n    Wdk::Foundation::{DEVICE_OBJECT, DRIVER_DISPATCH, DRIVER_OBJECT, DRIVER_UNLOAD},\n    Win32::Foundation::HANDLE,\n};\n\nuse crate::{\n    interface,\n    irp_helpers::{ReadRequest, WriteRequest},\n};\n\npub trait Device {\n    fn new(driver: &Driver) -> Self;\n    fn cleanup(&mut self);\n    fn read(&mut self, read_request: &mut ReadRequest);\n    fn write(&mut self, write_request: &mut WriteRequest);\n    fn shutdown(&mut self);\n}\n\npub struct Driver {\n    _device_handle: HANDLE,\n    driver_object: *mut DRIVER_OBJECT,\n    device_object: *mut DEVICE_OBJECT,\n}\nunsafe impl Sync for Driver {}\n\nimpl Driver {\n    pub(crate) fn new(\n        driver_object: *mut DRIVER_OBJECT,\n        _driver_handle: HANDLE,\n        device_handle: HANDLE,\n    ) -> Driver {\n        return Driver {\n            // driver_handle,\n            _device_handle: device_handle,\n            driver_object,\n            device_object: interface::wdf_device_wdm_get_device_object(device_handle),\n        };\n    }\n\n    pub fn get_device_object(&self) -> *mut DEVICE_OBJECT {\n        return self.device_object;\n    }\n\n    pub fn get_device_object_ref(&self) -> Option<&mut DEVICE_OBJECT> {\n        return unsafe { self.device_object.as_mut() };\n    }\n\n    pub fn set_driver_unload(&mut self, driver_unload: DRIVER_UNLOAD) {\n        if let Some(driver) = unsafe { self.driver_object.as_mut() } {\n            driver.DriverUnload = driver_unload\n        }\n    }\n\n    pub fn set_read_fn(&mut self, mj_fn: DRIVER_DISPATCH) {\n        self.set_major_fn(windows_sys::Wdk::System::SystemServices::IRP_MJ_READ, mj_fn);\n    }\n\n    pub fn set_write_fn(&mut self, mj_fn: DRIVER_DISPATCH) {\n        self.set_major_fn(\n            windows_sys::Wdk::System::SystemServices::IRP_MJ_WRITE,\n            mj_fn,\n        );\n    }\n\n    pub fn set_create_fn(&mut self, mj_fn: DRIVER_DISPATCH) {\n        self.set_major_fn(\n            windows_sys::Wdk::System::SystemServices::IRP_MJ_CREATE,\n            mj_fn,\n        );\n    }\n\n    pub fn set_device_control_fn(&mut self, mj_fn: DRIVER_DISPATCH) {\n        self.set_major_fn(\n            windows_sys::Wdk::System::SystemServices::IRP_MJ_DEVICE_CONTROL,\n            mj_fn,\n        );\n    }\n\n    pub fn set_close_fn(&mut self, mj_fn: DRIVER_DISPATCH) {\n        self.set_major_fn(\n            windows_sys::Wdk::System::SystemServices::IRP_MJ_CLOSE,\n            mj_fn,\n        );\n    }\n\n    pub fn set_cleanup_fn(&mut self, mj_fn: DRIVER_DISPATCH) {\n        self.set_major_fn(\n            windows_sys::Wdk::System::SystemServices::IRP_MJ_CLEANUP,\n            mj_fn,\n        );\n    }\n\n    fn set_major_fn(&mut self, fn_index: u32, mj_fn: DRIVER_DISPATCH) {\n        if let Some(driver) = unsafe { self.driver_object.as_mut() } {\n            driver.MajorFunction[fn_index as usize] = mj_fn\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/error.rs",
    "content": "// use anyhow::anyhow;\n\n// pub fn anyhow_ntstatus(status: i32) -> anyhow::Error {\n//     if let Some(value) = ntstatus::ntstatus::NtStatus::from_u32(status as u32) {\n//         return anyhow!(value);\n//     }\n\n//     return anyhow!(\"UNKNOWN_NTSTATUS_CODE\");\n// }\n"
  },
  {
    "path": "windows_kext/wdk/src/fast_mutex.rs",
    "content": "use alloc::boxed::Box;\nuse core::{\n    cell::UnsafeCell,\n    ops::{Deref, DerefMut},\n};\nuse windows_sys::{\n    Wdk::{\n        Foundation::{FAST_MUTEX, KEVENT},\n        System::SystemServices::FM_LOCK_BIT,\n    },\n    Win32::System::Kernel::{SynchronizationEvent, EVENT_TYPE},\n};\n\n// #[link(name = \"NtosKrnl\", kind = \"static\")]\nextern \"C\" {\n    fn KeInitializeEvent(event: *mut KEVENT, event_type: EVENT_TYPE, state: bool);\n\n    /// The ExAcquireFastMutex routine acquires the given fast mutex with APCs to the current thread disabled.\n    fn ExAcquireFastMutex(kmutex: *mut FAST_MUTEX);\n\n    /// The ExTryToAcquireFastMutex routine acquires the given fast mutex, if possible, with APCs to the current thread disabled.\n    fn ExTryToAcquireFastMutex(kmutex: *mut FAST_MUTEX) -> bool;\n\n    // The ExReleaseFastMutex routine releases ownership of a fast mutex that was acquired with ExAcquireFastMutex or ExTryToAcquireFastMutex.\n    fn ExReleaseFastMutex(kmutex: *mut FAST_MUTEX);\n}\n\n/// The ExInitializeFastMutex routine initializes a fast mutex variable, used to synchronize mutually exclusive access by a set of threads to a shared resource.\n/// ExInitializeFastMutex must be called before any calls to other ExXxxFastMutex routines occur.\n#[allow(non_snake_case)]\nunsafe fn ExInitializeFastMutex(kmutex: *mut FAST_MUTEX) {\n    core::ptr::write_volatile(&mut (*kmutex).Count, FM_LOCK_BIT as i32);\n    // (*kmutex).Count = FM_LOCK_BIT as i32;\n\n    (*kmutex).Owner = core::ptr::null_mut();\n    (*kmutex).Contention = 0;\n    KeInitializeEvent(&mut (*kmutex).Event, SynchronizationEvent, false)\n}\n\npub struct FastMutex<T> {\n    kmutex: UnsafeCell<Option<*mut FAST_MUTEX>>,\n    val: UnsafeCell<T>,\n}\n\nimpl<T> FastMutex<T> {\n    pub const fn default(val: T) -> Self {\n        Self {\n            kmutex: UnsafeCell::new(None),\n            val: UnsafeCell::new(val),\n        }\n    }\n\n    pub fn init(&self) {\n        let mutex = Box::into_raw(Box::new(unsafe {\n            MaybeUninit::zeroed().assume_init();\n        }));\n        unsafe {\n            ExInitializeFastMutex(mutex);\n            *self.kmutex.get() = Some(mutex);\n        }\n    }\n\n    pub fn deinit(&self) {\n        unsafe {\n            let opt = &mut (*self.kmutex.get());\n            if let Some(mutex) = opt {\n                _ = Box::from_raw(mutex);\n            }\n            opt.take();\n        }\n    }\n\n    pub fn lock(&self) -> Result<LockGuard<T>, ()> {\n        unsafe {\n            if let Some(mutex) = *self.kmutex.get() {\n                ExAcquireFastMutex(mutex);\n                return Ok(LockGuard::new(self));\n            }\n        }\n\n        return Err(());\n    }\n\n    pub fn try_lock(&self) -> Option<LockGuard<T>> {\n        unsafe {\n            if let Some(mutex) = *self.kmutex.get() {\n                ExTryToAcquireFastMutex(mutex);\n                return Some(LockGuard::new(self));\n            }\n        }\n        return None;\n    }\n\n    fn get<'a>(&self) -> *mut T {\n        self.val.get()\n    }\n\n    fn unlock(&self) {\n        unsafe {\n            if let Some(mutex) = *self.kmutex.get() {\n                ExReleaseFastMutex(mutex);\n            } else {\n                panic!(\"Mutex not initialized\");\n            }\n        }\n    }\n}\n\nimpl<T> Drop for FastMutex<T> {\n    fn drop(&mut self) {\n        self.deinit();\n    }\n}\n\npub struct LockGuard<'a, T> {\n    mutex: &'a FastMutex<T>,\n}\n\nimpl<'a, T> LockGuard<'a, T> {\n    fn new(mutex: &'a FastMutex<T>) -> Self {\n        return LockGuard { mutex };\n    }\n}\n\nimpl<'a, T> Drop for LockGuard<'a, T> {\n    fn drop(&mut self) {\n        self.mutex.unlock();\n    }\n}\n\nimpl<'a, T> Deref for LockGuard<'a, T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        unsafe { &*self.mutex.get() }\n    }\n}\n\nimpl<'a, T> DerefMut for LockGuard<'a, T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        unsafe { &mut *self.mutex.get() }\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/ffi.rs",
    "content": "#![allow(non_snake_case)]\n\nuse core::ffi::c_void;\n\nuse windows_sys::{\n    core::{GUID, PCWSTR},\n    Wdk::Foundation::{DEVICE_OBJECT, DRIVER_OBJECT, MDL},\n    Win32::{\n        Foundation::{HANDLE, NTSTATUS, UNICODE_STRING},\n        NetworkManagement::WindowsFilteringPlatform::{\n            FWPM_PROVIDER_CONTEXT2, FWP_CONDITION_VALUE0, FWP_MATCH_TYPE, FWP_VALUE0,\n        },\n        Networking::WinSock::{ADDRESS_FAMILY, SCOPE_ID},\n        System::Kernel::COMPARTMENT_ID,\n    },\n};\n\nuse crate::filter_engine::{\n    classify::ClassifyOut, layer::IncomingValues, metadata::FwpsIncomingMetadataValues,\n};\n\npub(crate) type FwpsCalloutClassifyFn = unsafe extern \"C\" fn(\n    inFixedValues: *const IncomingValues,\n    inMetaValues: *const FwpsIncomingMetadataValues,\n    layerData: *mut c_void,\n    classifyContext: *mut c_void,\n    filter: *const FWPS_FILTER2,\n    flowContext: u64,\n    classifyOut: *mut ClassifyOut,\n);\n\npub(crate) type FwpsCalloutNotifyFn = unsafe extern \"C\" fn(\n    notifyType: u32,\n    filterKey: *const GUID,\n    filter: *mut FWPS_FILTER2,\n) -> NTSTATUS;\n\npub(crate) type FwpsCalloutFlowDeleteNotifyFn =\n    unsafe extern \"C\" fn(layerId: u16, calloutId: u32, flowContext: u64);\n\n/// The FWPS_ACTION0 structure specifies the run-time action that the filter engine takes if all of the filter's filtering conditions are true.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub(crate) struct FWPS_ACTION0 {\n    r#type: u32,\n    calloutId: u32,\n}\n\n/// The FWPS_FILTER_CONDITION0 structure defines a run-time filtering condition for a filter.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub(crate) struct FWPS_FILTER_CONDITION0 {\n    fieldId: u16,\n    reserved: u16,\n    matchType: FWP_MATCH_TYPE,\n    conditionValue: FWP_CONDITION_VALUE0,\n}\n\n/// The WdfExecutionLevel enumeration type specifies the maximum IRQL at which the framework will call the event callback functions that a driver has supplied for a framework object.\n#[repr(C)]\nenum WdfExecutionLevel {\n    Invalid = 0,\n    InheritFromParent,\n    Passive,\n    Dispatch,\n}\n\n/// The WDF_SYNCHRONIZATION_SCOPE enumeration type specifies how the framework will synchronize execution of an object's event callback functions.\n#[repr(C)]\nenum WdfSynchronizationScope {\n    Invalid = 0x00,\n    InheritFromParent,\n    Device,\n    Queue,\n    None,\n}\n\nunsafe impl Sync for WdfObjectContextTypeInfo {}\n\n/// The FWPS_FILTER2 structure defines a run-time filter in the filter engine.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub(crate) struct FWPS_FILTER2 {\n    pub(crate) filterId: u64,\n    pub(crate) weight: FWP_VALUE0,\n    pub(crate) subLayerWeight: u16,\n    pub(crate) flags: u16,\n    pub(crate) numFilterConditions: u32,\n    pub(crate) filterCondition: *mut FWPS_FILTER_CONDITION0,\n    pub(crate) action: FWPS_ACTION0,\n    pub(crate) context: u64,\n    pub(crate) providerContext: *mut FWPM_PROVIDER_CONTEXT2,\n}\n\n/// The FWPS_CALLOUT3 structure defines the data that is required for a callout driver to register a callout with the filter engine.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub(crate) struct FWPS_CALLOUT3 {\n    pub(crate) calloutKey: GUID,\n    pub(crate) flags: u32,\n    pub(crate) classifyFn: Option<FwpsCalloutClassifyFn>,\n    pub(crate) notifyFn: Option<FwpsCalloutNotifyFn>,\n    pub(crate) flowDeleteFn: Option<FwpsCalloutFlowDeleteNotifyFn>,\n}\n\n/// The filter engine calls a callout's completionFn callout function whenever packet data, described by the netBufferList parameter in one of the packet injection functions, has been injected into the network stack.\n#[allow(non_camel_case_types)]\ntype FWPS_INJECT_COMPLETE0 = unsafe extern \"C\" fn(\n    context: *mut c_void,\n    net_buffer_list: *mut NET_BUFFER_LIST,\n    dispatch_level: bool,\n);\n\n/// The FWPS_TRANSPORT_SEND_PARAMS1 structure defines properties of an outbound transport layer packet.\n#[allow(non_camel_case_types)]\n#[repr(C)]\npub(crate) struct FWPS_TRANSPORT_SEND_PARAMS1 {\n    pub(crate) remote_address: *const u8,\n    pub(crate) remote_scope_id: SCOPE_ID,\n    pub(crate) control_data: *mut c_void, //WSACMSGHDR,\n    pub(crate) control_data_length: u32,\n    pub(crate) header_include_header: *mut u8,\n    pub(crate) header_include_header_length: u32,\n}\n\n/// The FWPS_PACKET_INJECTION_STATE enumeration type specifies the injection state of a network buffer list.\n#[allow(non_camel_case_types)]\n#[repr(C)]\npub(crate) enum FWPS_PACKET_INJECTION_STATE {\n    FWPS_PACKET_NOT_INJECTED,\n    FWPS_PACKET_INJECTED_BY_SELF,\n    FWPS_PACKET_INJECTED_BY_OTHER,\n    FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF,\n    FWPS_PACKET_INJECTION_STATE_MAX,\n}\n\npub(crate) const FWPS_INJECTION_TYPE_STREAM: u32 = 0x00000001;\npub(crate) const FWPS_INJECTION_TYPE_TRANSPORT: u32 = 0x00000002;\npub(crate) const FWPS_INJECTION_TYPE_NETWORK: u32 = 0x00000004;\npub(crate) const FWPS_INJECTION_TYPE_FORWARD: u32 = 0x00000008;\npub(crate) const FWPS_INJECTION_TYPE_L2: u32 = 0x00000010;\npub(crate) const FWPS_INJECTION_TYPE_VSWITCH_TRANSPORT: u32 = 0x00000020;\n\npub(crate) const NDIS_OBJECT_TYPE_DEFAULT: u8 = 0x80; // used when object type is implicit in the API call\npub(crate) const NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1: u8 = 1;\n\n/// The NBListHeader is the header of NET_BUFFER_LIST struct.\n#[repr(C)]\npub(crate) struct NBListHeader {\n    pub(crate) next: *mut NET_BUFFER_LIST,\n    pub(crate) first_net_buffer: *mut NET_BUFFER,\n}\n\n/// The NET_BUFFER_LIST structure specifies a linked list of NET_BUFFER structures.\n/// This is internal struct should never be allocated from the driver. Use provided functions by microsoft.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub struct NET_BUFFER_LIST {\n    pub(crate) Header: NBListHeader,\n    pub(crate) Context: *mut c_void,\n    pub(crate) ParentNetBufferList: *mut NET_BUFFER_LIST,\n    pub(crate) NdisPoolHandle: NDIS_HANDLE,\n    pub(crate) NdisReserved: [*mut c_void; 2],\n    pub(crate) ProtocolReserved: [*mut c_void; 4],\n    pub(crate) MiniportReserved: [*mut c_void; 2],\n    pub(crate) Scratch: *mut c_void,\n    pub(crate) SourceHandle: NDIS_HANDLE,\n    pub(crate) NblFlags: u32,\n    pub(crate) ChildRefCount: i32,\n    pub(crate) Flags: u32,\n    pub(crate) Status: NDIS_STATUS,\n    pub(crate) NetBufferListInfo: [*mut c_void; 20], // Extra data at the end of the struct. The size of the array is not fixed.\n}\n\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub union NBSize {\n    pub DataLength: u32,\n    pub stDataLength: u64,\n}\n\n/// This is internal struct should never be allocated from the driver. Use provided functions by microsoft.\n/// The NET_BUFFER structure specifies data that is transmitted or received over the network.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub struct NET_BUFFER {\n    pub(crate) Next: *mut NET_BUFFER,\n    pub(crate) CurrentMdl: *mut MDL,\n    pub(crate) CurrentMdlOffset: u32,\n    pub(crate) nbSize: NBSize,\n    pub(crate) MdlChain: *mut MDL,\n    pub(crate) DataOffset: u32,\n    pub(crate) ChecksumBias: u16,\n    pub(crate) Reserved: u16,\n    pub(crate) NdisPoolHandle: NDIS_HANDLE,\n    pub(crate) NdisReserved: [*mut c_void; 2],\n    pub(crate) ProtocolReserved: [*mut c_void; 6],\n    pub(crate) MiniportReserved: [*mut c_void; 4],\n    pub(crate) DataPhysicalAddress: u64,\n    pub(crate) SharedMemoryInfo: *mut c_void,\n}\n\n/// This data type is used as the generic handle type in NDIS function calls.\n#[allow(non_camel_case_types)]\npub type NDIS_HANDLE = *mut c_void;\n\n/// This data type is used to indicate success and error states in numerous functions and object identifiers.\n#[allow(non_camel_case_types)]\npub type NDIS_STATUS = i32;\n\n/// The NDIS_OBJECT_HEADER structure packages the object type, version, and size information that is required in many NDIS 6.0 structures.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub(crate) struct NDIS_OBJECT_HEADER {\n    pub(crate) Type: u8,\n    pub(crate) Revision: u8,\n    pub(crate) Size: u16,\n}\n\n/// The NET_BUFFER_LIST_POOL_PARAMETERS structure defines the parameters for a pool of NET_BUFFER_LIST structures.\n#[allow(non_camel_case_types, non_snake_case)]\n#[repr(C)]\npub(crate) struct NET_BUFFER_LIST_POOL_PARAMETERS {\n    pub(crate) Header: NDIS_OBJECT_HEADER,\n    pub(crate) ProtocolId: u8,\n    pub(crate) fAllocateNetBuffer: bool,\n    pub(crate) ContextSize: u16,\n    pub(crate) PoolTag: u32,\n    pub(crate) DataSize: u32,\n    pub(crate) Flags: u32,\n}\n/// WdfObjectContextTypeInfo is a description of the device context.\n#[repr(C)]\npub struct WdfObjectContextTypeInfo {\n    size: u32,\n    context_name: *const u8,\n    context_size: usize,\n    unique_type: *const WdfObjectContextTypeInfo,\n    _evt_driver_get_unique_context_type: *const c_void, // Internal use\n}\n\nimpl WdfObjectContextTypeInfo {\n    pub const fn default(null_terminated_name: &'static str) -> Self {\n        Self {\n            size: core::mem::size_of::<WdfObjectContextTypeInfo>() as u32,\n            context_name: null_terminated_name.as_ptr(),\n            context_size: 0,\n            unique_type: core::ptr::null(),\n            _evt_driver_get_unique_context_type: core::ptr::null(),\n        }\n    }\n}\n\n/// WdfObjectAttributes contains attributes for the device context.\n#[repr(C)]\npub struct WdfObjectAttributes {\n    size: u32,\n    evt_cleanup_callback: Option<extern \"system\" fn(wdf_object: HANDLE)>,\n    evt_destroy_callback: Option<extern \"system\" fn(wdf_object: HANDLE)>,\n    execution_level: WdfExecutionLevel,\n    synchronization_scope: WdfSynchronizationScope,\n    parent_object: HANDLE,\n    context_size_override: usize,\n    context_type_info: *const WdfObjectContextTypeInfo,\n}\n\nimpl WdfObjectAttributes {\n    pub fn new() -> Self {\n        Self {\n            size: core::mem::size_of::<WdfObjectAttributes>() as u32,\n            evt_cleanup_callback: None,\n            evt_destroy_callback: None,\n            execution_level: WdfExecutionLevel::InheritFromParent,\n            synchronization_scope: WdfSynchronizationScope::InheritFromParent,\n            parent_object: core::ptr::null_mut(),\n            context_size_override: 0,\n            context_type_info: core::ptr::null(),\n        }\n    }\n\n    pub fn add_context<T>(&mut self, context_info: &'static mut WdfObjectContextTypeInfo) {\n        context_info.context_size = core::mem::size_of::<T>();\n        context_info.unique_type = context_info;\n        self.context_size_override = 0;\n        self.context_type_info = context_info.unique_type;\n    }\n\n    pub fn set_cleanup_fn(&mut self, callback: extern \"system\" fn(wdf_object: HANDLE)) {\n        self.evt_cleanup_callback = Some(callback);\n    }\n\n    pub fn set_destroy_fn(&mut self, callback: extern \"system\" fn(wdf_object: HANDLE)) {\n        self.evt_destroy_callback = Some(callback);\n    }\n}\n\n// #[link(name = \"Fwpkclnt\", kind = \"static\")]\n// #[link(name = \"Fwpuclnt\", kind = \"static\")]\n// #[link(name = \"WdfDriverEntry\", kind = \"static\")]\n// #[link(name = \"WdfLdr\", kind = \"static\")]\n// #[link(name = \"BufferOverflowK\", kind = \"static\")]\n// #[link(name = \"uuid\", kind = \"static\")]\n// #[link(name = \"wdmsec\", kind = \"static\")]\n// #[link(name = \"wmilib\", kind = \"static\")]\n// #[link(name = \"NtosKrnl\", kind = \"static\")]\n// #[link(name = \"ndis\", kind = \"static\")]\n#[link(name = \"c_helper\", kind = \"static\")]\nextern \"C\" {\n    /// The FwpsCalloutUnregisterById0 function unregisters a callout from the filter engine.\n    pub(crate) fn FwpsCalloutUnregisterById0(id: u32) -> NTSTATUS;\n\n    /// The FwpsCalloutRegister3 function registers a callout with the filter engine.\n    pub(crate) fn FwpsCalloutRegister3(\n        deviceObject: *mut c_void,\n        callout: *const FWPS_CALLOUT3,\n        calloutId: *mut u32,\n    ) -> NTSTATUS;\n\n    /// The FwpsPendOperation0 function is called by a callout to suspend packet processing pending completion of another operation.\n    pub(crate) fn FwpsPendOperation0(\n        completionHandle: HANDLE,\n        completionContext: *mut HANDLE,\n    ) -> NTSTATUS;\n\n    /// The FwpsCompleteOperation0 function is called by a callout to resume packet processing that was suspended pending completion of another operation.\n    pub(crate) fn FwpsCompleteOperation0(completionContext: HANDLE, netBufferList: *mut c_void);\n\n    /// The FwpsAcquireClassifyHandle0 function generates a classification handle that is used to identify asynchronous classification operations and requests for writable layer data.\n    pub(crate) fn FwpsAcquireClassifyHandle0(\n        classify_context: *mut c_void,\n        reserved: u32, // Must be zero.\n        classify_handle: *mut u64,\n    ) -> NTSTATUS;\n\n    /// A callout driver calls FwpsReleaseClassifyHandle0 to release a classification handle that was previously acquired through a call to FwpsAcquireClassifyHandle0.\n    pub(crate) fn FwpsReleaseClassifyHandle0(classify_handle: u64);\n\n    /// A callout's classifyFn function calls FwpsPendClassify0 to pend the current classify request. After the request is pended, the callout driver must complete the processing of the classify request asynchronously by calling FwpsCompleteClassify0.\n    pub(crate) fn FwpsPendClassify0(\n        classify_handle: u64,\n        filterId: u64,\n        flags: u32, // Must be zero.\n        classifyOut: *const ClassifyOut,\n    ) -> NTSTATUS;\n\n    /// A callout driver calls FwpsCompleteClassify0 to asynchronously complete a pended classify request. The callout driver's classifyFn function must have previously called FwpsPendClassify0 to pend the classify request.\n    pub(crate) fn FwpsCompleteClassify0(\n        classify_handle: u64,\n        flags: u32, // Must be zero.\n        classifyOut: *const ClassifyOut,\n    );\n\n    /// The FwpsAcquireWritableLayerDataPointer0 function returns layer-specific data that can be inspected and changed.\n    pub(crate) fn FwpsAcquireWritableLayerDataPointer0(\n        classify_handle: u64,\n        filter_id: u64,\n        flags: u32,\n        writable_layer_data: *mut c_void,\n        classify_out: *mut ClassifyOut,\n    ) -> NTSTATUS;\n\n    /// The FwpsApplyModifiedLayerData0 function applies changes to layer-specific data made after a call to FwpsAcquireWritableLayerDataPointer0.\n    pub(crate) fn FwpsApplyModifiedLayerData0(\n        classifyHandle: u64,\n        modifiedLayerData: *mut *mut c_void,\n        flags: u32,\n    );\n\n    /// pm_InitDriverObject initialize driver object. This function initializes requerd memory for the device context.\n    pub(crate) fn pm_InitDriverObject(\n        driver_object: *mut DRIVER_OBJECT,\n        registry_path: *mut UNICODE_STRING,\n        wdf_driver: *mut HANDLE,\n        wdf_device: *mut HANDLE,\n        win_driver_path: PCWSTR,\n        dos_driver_path: PCWSTR,\n        object_attributes: *mut WdfObjectAttributes,\n        wdf_driver_unload: extern \"C\" fn(HANDLE),\n    ) -> NTSTATUS;\n\n    /// pm_WdfObjectGetTypedContextWerker 1to1 reference to the WdfObjectGetTypedContextWorker macro. The WdfObjectGetTypedContext macro returns a pointer to an object's context space.\n    pub(crate) fn pm_WdfObjectGetTypedContextWorker(\n        wdf_object: HANDLE,\n        type_info: *const WdfObjectContextTypeInfo,\n    ) -> *mut c_void;\n\n    /// WdfObjectGetTypedContext 1to1 reference to WdfDeviceWdmGetDeviceObject. The WdfDeviceWdmGetDeviceObject method returns the Windows Driver Model (WDM) device object that is associated with a specified framework device object.\n    pub(crate) fn pm_GetDeviceObject(wdf_device: HANDLE) -> *mut DEVICE_OBJECT;\n\n    /// The FwpsInjectNetworkSendAsync0 function injects packet data into the send data path.\n    pub(crate) fn FwpsInjectNetworkSendAsync0(\n        injectionHandle: HANDLE,\n        injectionContext: HANDLE,\n        flags: u32,\n        compartmentId: COMPARTMENT_ID,\n        netBufferList: *mut NET_BUFFER_LIST,\n        completionFn: FWPS_INJECT_COMPLETE0,\n        completionContext: *mut c_void,\n    ) -> NTSTATUS;\n\n    /// The FwpsInjectNetworkReceiveAsync0 function injects packet data into the receive data path.\n    pub(crate) fn FwpsInjectNetworkReceiveAsync0(\n        injectionHandle: HANDLE,\n        injectionContext: HANDLE,\n        flags: u32,\n        compartmentId: COMPARTMENT_ID,\n        interfaceIndex: u32,\n        subInterfaceIndex: u32,\n        netBufferList: *mut NET_BUFFER_LIST,\n        completionFn: FWPS_INJECT_COMPLETE0,\n        completionContext: *mut c_void,\n    ) -> NTSTATUS;\n\n    /// The FwpsInjectTransportSendAsync1 function injects packet data from the transport, datagram data, or ICMP error layers into the send data path. This function differs from the previous version (FwpsInjectTransportSendAsync0) in that it takes an updated parameters structure as an argument.\n    pub(crate) fn FwpsInjectTransportSendAsync1(\n        injectionHandle: HANDLE,\n        injectionContext: HANDLE,\n        endpointHandle: u64,\n        flags: u32,\n        sendArgs: *mut FWPS_TRANSPORT_SEND_PARAMS1,\n        addressFamily: ADDRESS_FAMILY,\n        compartmentId: COMPARTMENT_ID,\n        netBufferList: *mut NET_BUFFER_LIST,\n        completionFn: FWPS_INJECT_COMPLETE0,\n        completionContext: *mut c_void,\n    ) -> NTSTATUS;\n\n    /// The FwpsInjectTransportReceiveAsync0 function injects packet data from the transport, datagram data, or ICMP error layers into the receive data path.\n    pub(crate) fn FwpsInjectTransportReceiveAsync0(\n        injectionHandle: HANDLE,\n        injectionContext: HANDLE,\n        reserved: *const c_void,\n        flags: u32,\n        addressFamily: ADDRESS_FAMILY,\n        compartmentId: COMPARTMENT_ID,\n        interfaceIndex: u32,\n        subInterfaceIndex: u32,\n        netBufferList: *mut NET_BUFFER_LIST,\n        completionFn: FWPS_INJECT_COMPLETE0,\n        completionContext: *mut c_void,\n    ) -> NTSTATUS;\n\n    /// The FwpsInjectionHandleCreate0 function creates a handle that can be used by packet injection functions to inject packet or stream data into the TCP/IP network stack and by the FwpsQueryPacketInjectionState0 function to query the packet injection state.\n    pub(crate) fn FwpsInjectionHandleCreate0(\n        addressFamily: ADDRESS_FAMILY,\n        flags: u32,\n        injectionHandle: &mut HANDLE,\n    ) -> NTSTATUS;\n\n    /// The FwpsQueryPacketInjectionState0 function is called by a callout to query the injection state of packet data.\n    pub(crate) fn FwpsQueryPacketInjectionState0(\n        injectionHandle: HANDLE,\n        netBufferList: *const NET_BUFFER_LIST,\n        injectionContext: *mut HANDLE,\n    ) -> FWPS_PACKET_INJECTION_STATE;\n\n    /// The FwpsInjectionHandleDestroy0 function destroys an injection handle that was previously created by calling the FwpsInjectionHandleCreate0 function.\n    pub(crate) fn FwpsInjectionHandleDestroy0(injectionHandle: HANDLE) -> NTSTATUS;\n\n    /// The FwpsReferenceNetBufferList0 function increments the reference count for a NET_BUFFER_LIST structure.\n    pub(crate) fn FwpsReferenceNetBufferList0(\n        netBufferList: *mut NET_BUFFER_LIST,\n        intendToModify: bool,\n    );\n\n    /// The FwpsDereferenceNetBufferList0 function decrements the reference count for a NET_BUFFER_LIST structure that a callout driver had acquired earlier using the FwpsReferenceNetBufferList0 function.\n    pub(crate) fn FwpsDereferenceNetBufferList0(\n        netBufferList: *mut NET_BUFFER_LIST,\n        dispatchLevel: bool,\n    );\n\n    /// Call the NdisGetDataBuffer function to gain access to a contiguous block of data from a NET_BUFFER structure.\n    pub(crate) fn NdisGetDataBuffer(\n        NetBuffer: *const NET_BUFFER,\n        BytesNeeded: u32,\n        Storage: *mut u8,\n        AlignMultiple: u32,\n        AlignOffset: u32,\n    ) -> *mut u8;\n\n    /// Call the NdisAllocateCloneNetBufferList function to create a new clone NET_BUFFER_LIST structure.\n    pub(crate) fn NdisAllocateCloneNetBufferList(\n        OriginalNetBufferList: *mut NET_BUFFER_LIST,\n        NetBufferListPoolHandle: NDIS_HANDLE,\n        NetBufferPoolHandle: NDIS_HANDLE,\n        AllocateCloneFlag: u32,\n    ) -> *mut NET_BUFFER_LIST;\n\n    /// Call the NdisFreeCloneNetBufferList function to free a NET_BUFFER_LIST structure and all associated NET_BUFFER structures and MDL chains that were previously allocated by calling the NdisAllocateCloneNetBufferList function.\n    pub(crate) fn NdisFreeCloneNetBufferList(\n        CloneNetBufferList: *mut NET_BUFFER_LIST,\n        FreeCloneFlags: u32,\n    );\n\n    /// The FwpsAllocateNetBufferAndNetBufferList0 function allocates a new NET_BUFFER_LIST structure.\n    pub(crate) fn FwpsAllocateNetBufferAndNetBufferList0(\n        poolHandle: NDIS_HANDLE,\n        contextSize: u16,\n        contextBackFill: u16,\n        mdlChain: *mut MDL,\n        dataOffset: u32,\n        dataLength: u64,\n        netBufferList: *mut *mut NET_BUFFER_LIST,\n    ) -> NTSTATUS;\n\n    /// The FwpsFreeNetBufferList0 function frees a NET_BUFFER_LIST structure that was previously allocated by a call to the FwpsAllocateNetBufferAndNetBufferList0 function.\n    pub(crate) fn FwpsFreeNetBufferList0(netBufferList: *mut NET_BUFFER_LIST);\n\n    /// Call the NdisAllocateNetBufferListPool function to allocate a pool of NET_BUFFER_LIST structures.\n    pub(crate) fn NdisAllocateNetBufferListPool(\n        NdisHandle: NDIS_HANDLE,\n        Parameters: *const NET_BUFFER_LIST_POOL_PARAMETERS,\n    ) -> NDIS_HANDLE;\n\n    /// Call the NdisFreeNetBufferListPool function to free a NET_BUFFER_LIST structure pool.\n    pub(crate) fn NdisFreeNetBufferListPool(PoolHandle: NDIS_HANDLE);\n\n    /// Call the NdisRetreatNetBufferDataStart function to access more used data space in the MDL chain of a NET_BUFFER structure.\n    pub(crate) fn NdisRetreatNetBufferDataStart(\n        NetBuffer: *mut NET_BUFFER,\n        DataOffsetDelta: u32,\n        DataBackFill: u32,\n        AllocateMdlHandler: *mut c_void,\n    ) -> NDIS_STATUS;\n\n    /// Call the NdisAdvanceNetBufferDataStart function to release the used data space that was added with the NdisRetreatNetBufferDataStart function.\n    pub(crate) fn NdisAdvanceNetBufferDataStart(\n        NetBuffer: *mut NET_BUFFER,\n        DataOffsetDelta: u32,\n        FreeMdl: bool,\n        FreeMdlHandler: *mut c_void,\n    );\n\n    /// The KeQuerySystemTime routine obtains the current system time.\n    /// System time is a count of 100-nanosecond intervals since January 1, 1601. System time is typically updated approximately every ten milliseconds. This value is computed for the GMT time zone.\n    pub(crate) fn pm_QuerySystemTime() -> u64;\n\n    /// Returns the process identifier of the current process.\n    /// This is safe to call from IRP_MJ_CREATE handlers, which always execute in the context of the initiating user-space process.\n    pub(crate) fn PsGetCurrentProcessId() -> HANDLE;\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/callout.rs",
    "content": "use super::{callout_data::CalloutData, ffi, layer::Layer};\nuse crate::ffi::FwpsCalloutClassifyFn;\nuse alloc::{borrow::ToOwned, format, string::String};\nuse windows_sys::{Wdk::Foundation::DEVICE_OBJECT, Win32::Foundation::HANDLE};\n\npub enum FilterType {\n    Resettable,\n    NonResettable,\n}\n\npub struct Callout {\n    pub(crate) id: u32,\n    pub(super) address: u64,\n    pub(crate) name: String,\n    pub(crate) description: String,\n    pub(crate) guid: u128,\n    pub(crate) layer: Layer,\n    pub(crate) action: u32,\n    pub(crate) registered: bool,\n    pub(crate) filter_type: FilterType,\n    pub(crate) filter_id: u64,\n    pub(crate) callout_fn: fn(CalloutData),\n}\n\nimpl Callout {\n    pub fn new(\n        name: &str,\n        description: &str,\n        guid: u128,\n        layer: Layer,\n        action: u32,\n        filter_type: FilterType,\n        callout_fn: fn(CalloutData),\n    ) -> Self {\n        Self {\n            id: 0,\n            address: 0,\n            name: name.to_owned(),\n            description: description.to_owned(),\n            guid,\n            layer,\n            action,\n            registered: false,\n            filter_type,\n            filter_id: 0,\n            callout_fn,\n        }\n    }\n\n    pub fn register_filter(\n        &mut self,\n        filter_engine_handle: HANDLE,\n        sublayer_guid: u128,\n    ) -> Result<(), String> {\n        match ffi::register_filter(\n            filter_engine_handle,\n            sublayer_guid,\n            &self.name,\n            &self.description,\n            self.guid,\n            self.layer,\n            self.action,\n            self.address, // The address of the callout is passed as context.\n        ) {\n            Ok(id) => {\n                self.filter_id = id;\n            }\n            Err(error) => {\n                return Err(format!(\"failed to register filter: {}\", error));\n            }\n        };\n\n        return Ok(());\n    }\n\n    pub(crate) fn register_callout(\n        &mut self,\n        filter_engine_handle: HANDLE,\n        device_object: *mut DEVICE_OBJECT,\n        callout_fn: FwpsCalloutClassifyFn,\n    ) -> Result<(), String> {\n        match ffi::register_callout(\n            device_object,\n            filter_engine_handle,\n            &self.name,\n            &self.description,\n            self.guid,\n            self.layer,\n            callout_fn,\n        ) {\n            Ok(id) => {\n                self.registered = true;\n                self.id = id;\n            }\n            Err(code) => {\n                return Err(format!(\"failed to register callout: {}\", code));\n            }\n        };\n        return Ok(());\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/callout_data.rs",
    "content": "use crate::{\n    ffi::{FwpsCompleteOperation0, FwpsPendOperation0},\n    utils::check_ntstatus,\n};\n\nuse super::{\n    classify::ClassifyOut,\n    layer::{Layer, Value, ValueType},\n    metadata::FwpsIncomingMetadataValues,\n    packet::TransportPacketList,\n    stream_data::StreamCalloutIoPacket,\n    FilterEngine,\n};\nuse alloc::string::{String, ToString};\nuse core::{ffi::c_void, ptr::NonNull};\nuse windows_sys::Win32::{\n    Foundation::HANDLE,\n    NetworkManagement::WindowsFilteringPlatform::FWP_CONDITION_FLAG_IS_REAUTHORIZE,\n    Networking::WinSock::SCOPE_ID,\n};\n\npub enum ClassifyDefer {\n    Initial(HANDLE, Option<TransportPacketList>),\n    Reauthorization(usize, Option<TransportPacketList>),\n}\n\nimpl ClassifyDefer {\n    pub fn complete(\n        self,\n        filter_engine: &mut FilterEngine,\n    ) -> Result<Option<TransportPacketList>, String> {\n        unsafe {\n            match self {\n                ClassifyDefer::Initial(context, packet_list) => {\n                    FwpsCompleteOperation0(context, core::ptr::null_mut());\n                    return Ok(packet_list);\n                }\n                ClassifyDefer::Reauthorization(_callout_id, packet_list) => {\n                    // There is no way to reset single filter. If another request for filter reset is trigger at the same time it will fail.\n                    //\n                    // Resetting all filters forces WFP to re-evaluate (reauthorize) all existing connections \n                    // using the updated verdict cache.\n                    // If STATUS_FWP_TXN_IN_PROGRESS is returned, another reset_all_filters() call is\n                    // already running concurrently, which will trigger the same WFP reauthorization.\n                    // It is safe to ignore this specific error and proceed with injecting the packet:\n                    // the verdict for this connection is already in the connection_cache, so the callout\n                    // will apply the correct verdict when the injected packet passes through.\n                    match filter_engine.reset_all_filters() {\n                        Ok(_) => {}\n                        Err(err) if err.contains(\"STATUS_FWP_TXN_IN_PROGRESS\") => {\n                            // Another transaction is already in progress and will handle reauthorization.\n                        }\n                        Err(err) => return Err(err),\n                    }\n                    return Ok(packet_list);\n                }\n            }\n        }\n    }\n\n    // pub fn add_net_buffer(&mut self, nbl: NetBufferList) {\n    //     if let Some(packet_list) = match self {\n    //         ClassifyDefer::Initial(_, packet_list) => packet_list,\n    //         ClassifyDefer::Reauthorization(_, packet_list) => packet_list,\n    //     } {\n    //         packet_list.net_buffer_list_queue.push(nbl);\n    //     }\n    // }\n}\n\npub struct CalloutData<'a> {\n    pub layer: Layer,\n    pub(crate) callout_id: usize,\n    pub(crate) values: &'a [Value],\n    pub(crate) metadata: *const FwpsIncomingMetadataValues,\n    pub(crate) classify_out: *mut ClassifyOut,\n    pub(crate) layer_data: *mut c_void,\n}\n\nimpl<'a> CalloutData<'a> {\n    pub fn get_value_type(&self, index: usize) -> ValueType {\n        self.values[index].value_type\n    }\n\n    pub fn get_value_u8(&'a self, index: usize) -> u8 {\n        unsafe {\n            return self.values[index].value.uint8;\n        };\n    }\n\n    pub fn get_value_u16(&'a self, index: usize) -> u16 {\n        unsafe {\n            return self.values[index].value.uint16;\n        };\n    }\n\n    pub fn get_value_u32(&'a self, index: usize) -> u32 {\n        unsafe {\n            return self.values[index].value.uint32;\n        };\n    }\n\n    pub fn get_value_byte_array16(&'a self, index: usize) -> &'a [u8; 16] {\n        unsafe {\n            return self.values[index].value.byte_array16.as_ref().unwrap();\n        };\n    }\n\n    pub fn get_process_id(&self) -> Option<u64> {\n        unsafe { (*self.metadata).get_process_id() }\n    }\n\n    pub fn get_process_path(&self) -> Option<String> {\n        unsafe {\n            return (*self.metadata).get_process_path();\n        }\n    }\n\n    pub fn get_transport_endpoint_handle(&self) -> Option<u64> {\n        unsafe {\n            return (*self.metadata).get_transport_endpoint_handle();\n        }\n    }\n\n    pub fn get_remote_scope_id(&self) -> Option<SCOPE_ID> {\n        unsafe {\n            return (*self.metadata).get_remote_scope_id();\n        }\n    }\n\n    pub fn get_control_data(&self) -> Option<NonNull<[u8]>> {\n        unsafe {\n            return (*self.metadata).get_control_data();\n        }\n    }\n\n    pub fn get_layer_data(&self) -> *mut c_void {\n        return self.layer_data;\n    }\n\n    pub fn get_stream_callout_packet(&self) -> Option<&mut StreamCalloutIoPacket> {\n        match self.layer {\n            Layer::StreamV4 | Layer::StreamV4Discard | Layer::StreamV6 | Layer::StreamV6Discard => unsafe {\n                (self.layer_data as *mut StreamCalloutIoPacket).as_mut()\n            },\n            _ => None,\n        }\n    }\n\n    pub fn is_fragment_data(&self) -> bool {\n        unsafe { (*self.metadata).is_fragment_data() }\n    }\n\n    pub fn pend_operation(\n        &mut self,\n        packet_list: Option<TransportPacketList>,\n    ) -> Result<ClassifyDefer, String> {\n        unsafe {\n            let mut completion_context: HANDLE = core::ptr::null_mut();\n            if let Some(completion_handle) = (*self.metadata).get_completion_handle() {\n                let status = FwpsPendOperation0(completion_handle, &mut completion_context);\n                check_ntstatus(status)?;\n\n                return Ok(ClassifyDefer::Initial(completion_context, packet_list));\n            }\n\n            Err(\"callout not supported\".to_string())\n        }\n    }\n\n    pub fn pend_filter_rest(&mut self, packet_list: Option<TransportPacketList>) -> ClassifyDefer {\n        ClassifyDefer::Reauthorization(self.callout_id, packet_list)\n    }\n\n    pub fn action_permit(&mut self) {\n        unsafe {\n            (*self.classify_out).action_permit();\n            (*self.classify_out).clear_absorb_flag();\n        }\n    }\n\n    pub fn action_continue(&mut self) {\n        unsafe {\n            (*self.classify_out).action_continue();\n            (*self.classify_out).clear_absorb_flag();\n        }\n    }\n\n    // Block action and clear the write flag. \n    // This will block the packet and prevent next filter in the chain to change the action.\n    pub fn action_block_hard(&mut self) {\n        unsafe {\n            (*self.classify_out).action_block();\n            (*self.classify_out).clear_absorb_flag();\n            // Next filter in the chain will not change the action.\n            (*self.classify_out).clear_write_flag(); \n        }\n    }\n\n    pub fn action_none(&mut self) {\n        unsafe {\n            (*self.classify_out).set_none();\n            (*self.classify_out).clear_absorb_flag();\n        }\n    }\n\n    pub fn block_and_absorb(&mut self) {\n        unsafe {\n            (*self.classify_out).action_block();\n            (*self.classify_out).set_absorb();\n        }\n    }\n    pub fn clear_write_flag(&mut self) {\n        unsafe {\n            (*self.classify_out).clear_write_flag();\n        }\n    }\n\n    pub fn is_reauthorize(&self, flags_index: usize) -> bool {\n        self.get_value_u32(flags_index) & FWP_CONDITION_FLAG_IS_REAUTHORIZE > 0\n    }\n\n    pub fn get_callout_id(&self) -> usize {\n        self.callout_id\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/classify.rs",
    "content": "#![allow(dead_code)]\n\nuse windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::FWPS_CLASSIFY_OUT_FLAG_ABSORB;\n\nconst FWP_ACTION_FLAG_TERMINATING: u32 = 0x00001000;\nconst FWP_ACTION_FLAG_NON_TERMINATING: u32 = 0x00002000;\nconst FWP_ACTION_FLAG_CALLOUT: u32 = 0x00004000;\n\nconst FWP_ACTION_BLOCK: u32 = 0x00000001 | FWP_ACTION_FLAG_TERMINATING;\nconst FWP_ACTION_PERMIT: u32 = 0x00000002 | FWP_ACTION_FLAG_TERMINATING;\nconst FWP_ACTION_CALLOUT_TERMINATING: u32 =\n    0x00000003 | FWP_ACTION_FLAG_CALLOUT | FWP_ACTION_FLAG_TERMINATING;\nconst FWP_ACTION_CALLOUT_INSPECTION: u32 =\n    0x00000004 | FWP_ACTION_FLAG_CALLOUT | FWP_ACTION_FLAG_NON_TERMINATING;\nconst FWP_ACTION_CALLOUT_UNKNOWN: u32 = 0x00000005 | FWP_ACTION_FLAG_CALLOUT;\nconst FWP_ACTION_CONTINUE: u32 = 0x00000006 | FWP_ACTION_FLAG_NON_TERMINATING;\nconst FWP_ACTION_NONE: u32 = 0x00000007;\nconst FWP_ACTION_NONE_NO_MATCH: u32 = 0x00000008;\n\nconst FWP_CONDITION_FLAG_IS_LOOPBACK: u32 = 0x00000001;\nconst FWP_CONDITION_FLAG_IS_IPSEC_SECURED: u32 = 0x00000002;\nconst FWP_CONDITION_FLAG_IS_REAUTHORIZE: u32 = 0x00000004;\nconst FWP_CONDITION_FLAG_IS_WILDCARD_BIND: u32 = 0x00000008;\nconst FWP_CONDITION_FLAG_IS_RAW_ENDPOINT: u32 = 0x00000010;\nconst FWP_CONDITION_FLAG_IS_FRAGMENT: u32 = 0x00000020;\nconst FWP_CONDITION_FLAG_IS_FRAGMENT_GROUP: u32 = 0x00000040;\nconst FWP_CONDITION_FLAG_IS_IPSEC_NATT_RECLASSIFY: u32 = 0x00000080;\nconst FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY: u32 = 0x00000100;\nconst FWP_CONDITION_FLAG_IS_IMPLICIT_BIND: u32 = 0x00000200;\nconst FWP_CONDITION_FLAG_IS_REASSEMBLED: u32 = 0x00000400;\nconst FWP_CONDITION_FLAG_IS_NAME_APP_SPECIFIED: u32 = 0x00004000;\nconst FWP_CONDITION_FLAG_IS_PROMISCUOUS: u32 = 0x00008000;\nconst FWP_CONDITION_FLAG_IS_AUTH_FW: u32 = 0x00010000;\nconst FWP_CONDITION_FLAG_IS_RECLASSIFY: u32 = 0x00020000;\nconst FWP_CONDITION_FLAG_IS_OUTBOUND_PASS_THRU: u32 = 0x00040000;\nconst FWP_CONDITION_FLAG_IS_INBOUND_PASS_THRU: u32 = 0x00080000;\nconst FWP_CONDITION_FLAG_IS_CONNECTION_REDIRECTED: u32 = 0x00100000;\n\nconst FWPS_RIGHT_ACTION_WRITE: u32 = 0x00000001;\n\n#[repr(C)]\n#[derive(Clone, Copy)]\npub struct ClassifyOut {\n    action_type: u32,\n    _out_context: u64, // System use\n    _filter_id: u64,   // System use\n    rights: u32,\n    flags: u32,\n    reserved: u32,\n}\n\nimpl ClassifyOut {\n    // Checks if write action flag is set. Indicates if the callout can change the action.\n    pub fn can_set_action(&self) -> bool {\n        self.rights & FWPS_RIGHT_ACTION_WRITE > 0\n    }\n\n    /// Set block action. Write flag should be cleared, after this.\n    pub fn action_block(&mut self) {\n        self.action_type = FWP_ACTION_BLOCK;\n    }\n\n    /// Set permit action.\n    pub fn action_permit(&mut self) {\n        self.action_type = FWP_ACTION_PERMIT;\n    }\n\n    // Set continue action.\n    pub fn action_continue(&mut self) {\n        self.action_type = FWP_ACTION_CONTINUE;\n    }\n\n    // Set none action.\n    pub fn set_none(&mut self) {\n        self.action_type = FWP_ACTION_NONE;\n    }\n\n    // Set absorb flag. This will drop the packet. Used when the packets will be reinjected in the future.\n    pub fn set_absorb(&mut self) {\n        self.flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;\n    }\n\n    // Removes the absorb flag.\n    pub fn clear_absorb_flag(&mut self) {\n        self.flags &= !FWPS_CLASSIFY_OUT_FLAG_ABSORB;\n    }\n\n    // Clear the write flag permission. Next filter in the chain will not change the action.\n    pub fn clear_write_flag(&mut self) {\n        self.rights &= !FWPS_RIGHT_ACTION_WRITE;\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/connect_request.rs",
    "content": "use core::ffi::c_void;\n\nuse windows_sys::Win32::{\n    Foundation::HANDLE,\n    Networking::WinSock::{AF_INET, AF_INET6},\n};\n\nuse crate::info;\n\n#[repr(C)]\npub(crate) struct FwpsConnectRequest0 {\n    pub(crate) local_address_and_port: [u8; 128],\n    pub(crate) remote_address_and_port: [u8; 128],\n    pub(crate) port_reservation_token: u64,\n    pub(crate) local_redirect_target_pid: u32,\n    pub(crate) previous_version: *const FwpsConnectRequest0,\n    pub(crate) modifier_filter_id: u64,\n    pub(crate) local_redirect_handle: HANDLE,\n    pub(crate) local_redirect_context: *mut c_void,\n    pub(crate) local_redirect_context_size: usize,\n}\n\n#[repr(C)]\nstruct SocketAddressGeneric {\n    family: u16,\n    padding: [u8; 128 - 2],\n}\n\n#[repr(C)]\nstruct SocketAddressIPv4 {\n    family: u16,\n    port: u16,\n    addr: [u8; 4],\n    zero: [u8; 8],\n    padding: [u8; 128 - 2 - 2 - 4 - 8],\n}\n\n#[repr(C)]\nstruct SocketAddressIPv6 {\n    family: u16,\n    port: u16,\n    flowinfo: u16,\n    addr: [u8; 16],\n    scope_id: u32,\n    padding: [u8; 128 - 2 - 2 - 2 - 16 - 4],\n}\n\nimpl FwpsConnectRequest0 {\n    pub(crate) fn set_remote(&mut self, ip: &[u8], port: u16) {\n        info!(\"local: {:?}\", self.local_address_and_port);\n        info!(\"remote: {:?}\", self.remote_address_and_port);\n        unsafe {\n            let generic_socket: &mut SocketAddressGeneric =\n                core::mem::transmute(&mut self.remote_address_and_port);\n            match generic_socket.family {\n                AF_INET => {\n                    info!(\"Socket type AF_INET\");\n                    let socket_ipv4: &mut SocketAddressIPv4 = core::mem::transmute(generic_socket);\n                    for i in 0..4 {\n                        socket_ipv4.addr[i] = ip[i];\n                    }\n                    socket_ipv4.port = u16::to_be(port);\n                }\n                AF_INET6 => {\n                    info!(\"Socket type AF_INET6\");\n                    let socket_ipv6: &mut SocketAddressIPv6 = core::mem::transmute(generic_socket);\n                    for i in 0..16 {\n                        socket_ipv6.addr[i] = ip[i];\n                    }\n                    socket_ipv6.port = u16::to_be(port);\n                }\n                _ => {\n                    info!(\"Unsupported socket type: {}\", generic_socket.family);\n                }\n            }\n        }\n        info!(\"after: {:?}\", self.remote_address_and_port);\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/ffi.rs",
    "content": "use crate::alloc::borrow::ToOwned;\r\nuse crate::ffi::FwpsCalloutClassifyFn;\r\nuse crate::ffi::{FwpsCalloutRegister3, FwpsCalloutUnregisterById0, FWPS_CALLOUT3, FWPS_FILTER2};\r\nuse crate::utils::check_ntstatus;\r\nuse alloc::string::String;\r\n\r\nuse core::mem::MaybeUninit;\r\nuse core::ptr;\r\nuse widestring::U16CString;\r\n\r\nuse windows_sys::Wdk::Foundation::DEVICE_OBJECT;\r\nuse windows_sys::Win32::Foundation::{NTSTATUS, STATUS_SUCCESS};\r\nuse windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::{\r\n    FwpmCalloutAdd0, FwpmEngineClose0, FwpmEngineOpen0, FwpmFilterAdd0, FwpmFilterDeleteById0,\r\n    FwpmSubLayerAdd0, FwpmSubLayerDeleteByKey0, FwpmTransactionAbort0, FwpmTransactionBegin0,\r\n    FwpmTransactionCommit0, FWPM_CALLOUT0, FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT,\r\n    FWPM_DISPLAY_DATA0, FWPM_FILTER0, FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT, FWPM_SESSION0,\r\n    FWPM_SESSION_FLAG_DYNAMIC, FWPM_SUBLAYER0, FWP_UINT8,\r\n};\r\nuse windows_sys::Win32::System::Rpc::RPC_C_AUTHN_WINNT;\r\nuse windows_sys::{\r\n    core::GUID,\r\n    Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE},\r\n};\r\n\r\nuse super::layer::Layer;\r\n\r\npub(crate) fn create_filter_engine() -> Result<HANDLE, String> {\r\n    unsafe {\r\n        let mut handle: HANDLE = INVALID_HANDLE_VALUE;\r\n        let mut wdf_session: FWPM_SESSION0 = MaybeUninit::zeroed().assume_init();\r\n        wdf_session.flags = FWPM_SESSION_FLAG_DYNAMIC;\r\n        let status = FwpmEngineOpen0(\r\n            core::ptr::null(),\r\n            RPC_C_AUTHN_WINNT,\r\n            core::ptr::null_mut(),\r\n            &wdf_session,\r\n            &mut handle,\r\n        );\r\n        check_ntstatus(status as i32)?;\r\n\r\n        return Ok(handle);\r\n    }\r\n}\r\n\r\npub(crate) fn register_sublayer(\r\n    filter_engine_handle: HANDLE,\r\n    name: &str,\r\n    description: &str,\r\n    guid: u128,\r\n) -> Result<(), String> {\r\n    let Ok(name) = U16CString::from_str(name) else {\r\n        return Err(\"invalid argument name\".to_owned());\r\n    };\r\n    let Ok(description) = U16CString::from_str(description) else {\r\n        return Err(\"invalid argument description\".to_owned());\r\n    };\r\n\r\n    unsafe {\r\n        let mut sublayer: FWPM_SUBLAYER0 = MaybeUninit::zeroed().assume_init();\r\n        sublayer.subLayerKey = GUID::from_u128(guid);\r\n        sublayer.displayData.name = name.as_ptr() as _;\r\n        sublayer.displayData.description = description.as_ptr() as _;\r\n        sublayer.flags = 0;\r\n        sublayer.weight = 0xFFFF; // Set to Max value. Weight compared to other sublayers.\r\n\r\n        let status = FwpmSubLayerAdd0(filter_engine_handle, &sublayer, core::ptr::null_mut());\r\n        check_ntstatus(status as i32)?;\r\n\r\n        return Ok(());\r\n    }\r\n}\r\n\r\npub(crate) fn unregister_sublayer(filter_engine_handle: HANDLE, guid: u128) -> Result<(), String> {\r\n    let guid = GUID::from_u128(guid);\r\n    unsafe {\r\n        let status = FwpmSubLayerDeleteByKey0(filter_engine_handle, ptr::addr_of!(guid));\r\n        check_ntstatus(status as i32)?;\r\n        return Ok(());\r\n    }\r\n}\r\n\r\nunsafe extern \"C\" fn generic_notify(\r\n    _notify_type: u32,\r\n    _filter_key: *const GUID,\r\n    _filter: *mut FWPS_FILTER2,\r\n) -> NTSTATUS {\r\n    return STATUS_SUCCESS;\r\n}\r\n\r\nunsafe extern \"C\" fn generic_delete_notify(_layer_id: u16, _callout_id: u32, _flow_context: u64) {}\r\n\r\npub(crate) fn register_callout(\r\n    device_object: *mut DEVICE_OBJECT,\r\n    filter_engine_handle: HANDLE,\r\n    name: &str,\r\n    description: &str,\r\n    guid: u128,\r\n    layer: Layer,\r\n    callout_fn: FwpsCalloutClassifyFn,\r\n) -> Result<u32, String> {\r\n    let s_callout = FWPS_CALLOUT3 {\r\n        calloutKey: GUID::from_u128(guid),\r\n        flags: 0,\r\n        classifyFn: Some(callout_fn),\r\n        notifyFn: Some(generic_notify),\r\n        flowDeleteFn: Some(generic_delete_notify),\r\n    };\r\n\r\n    unsafe {\r\n        let mut callout_id: u32 = 0;\r\n        let status = FwpsCalloutRegister3(device_object as _, &s_callout, &mut callout_id);\r\n\r\n        check_ntstatus(status)?;\r\n\r\n        callout_add(filter_engine_handle, guid, layer, name, description)?;\r\n\r\n        return Ok(callout_id);\r\n    }\r\n}\r\n\r\nfn callout_add(\r\n    filter_engine_handle: HANDLE,\r\n    guid: u128,\r\n    layer: Layer,\r\n    name: &str,\r\n    description: &str,\r\n) -> Result<(), String> {\r\n    let Ok(name) = U16CString::from_str(name) else {\r\n        return Err(\"invalid argument name\".to_owned());\r\n    };\r\n    let Ok(description) = U16CString::from_str(description) else {\r\n        return Err(\"invalid argument description\".to_owned());\r\n    };\r\n    let display_data = FWPM_DISPLAY_DATA0 {\r\n        name: name.as_ptr() as _,\r\n        description: description.as_ptr() as _,\r\n    };\r\n\r\n    unsafe {\r\n        let mut callout: FWPM_CALLOUT0 = MaybeUninit::zeroed().assume_init();\r\n        callout.calloutKey = GUID::from_u128(guid);\r\n        callout.displayData = display_data;\r\n        callout.applicableLayer = layer.get_guid();\r\n        callout.flags = FWPM_CALLOUT_FLAG_USES_PROVIDER_CONTEXT;\r\n        let status = FwpmCalloutAdd0(\r\n            filter_engine_handle,\r\n            &callout,\r\n            core::ptr::null_mut(),\r\n            core::ptr::null_mut(),\r\n        );\r\n        check_ntstatus(status as i32)?;\r\n    };\r\n    return Ok(());\r\n}\r\n\r\npub(crate) fn unregister_callout(callout_id: u32) -> Result<(), String> {\r\n    unsafe {\r\n        let status = FwpsCalloutUnregisterById0(callout_id);\r\n\r\n        check_ntstatus(status as i32)?;\r\n        return Ok(());\r\n    }\r\n}\r\n\r\npub(crate) fn register_filter(\r\n    filter_engine_handle: HANDLE,\r\n    sublayer_guid: u128,\r\n    name: &str,\r\n    description: &str,\r\n    callout_guid: u128,\r\n    layer: Layer,\r\n    action: u32,\r\n    context: u64,\r\n) -> Result<u64, String> {\r\n    let Ok(name) = U16CString::from_str(name) else {\r\n        return Err(\"invalid argument name\".to_owned());\r\n    };\r\n    let Ok(description) = U16CString::from_str(description) else {\r\n        return Err(\"invalid argument description\".to_owned());\r\n    };\r\n    let mut filter_id: u64 = 0;\r\n    unsafe {\r\n        let mut filter: FWPM_FILTER0 = MaybeUninit::zeroed().assume_init();\r\n        filter.displayData.name = name.as_ptr() as _;\r\n        filter.displayData.description = description.as_ptr() as _;\r\n        filter.action.r#type = action; // Says this filter's callout MUST make a block/permit decision. Also see doc excerpts below.\r\n        filter.subLayerKey = GUID::from_u128(sublayer_guid);\r\n        filter.weight.r#type = FWP_UINT8;\r\n        filter.weight.Anonymous.uint8 = 15; // The weight of this filter within its sublayer\r\n        filter.flags = FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT;\r\n        filter.numFilterConditions = 0; // If you specify 0, this filter invokes its callout for all traffic in its layer\r\n        filter.layerKey = layer.get_guid(); // This layer must match the layer that ExampleCallout is registered to\r\n        filter.action.Anonymous.calloutKey = GUID::from_u128(callout_guid);\r\n        filter.Anonymous.rawContext = context;\r\n        let status = FwpmFilterAdd0(\r\n            filter_engine_handle,\r\n            &filter,\r\n            core::ptr::null_mut(),\r\n            &mut filter_id,\r\n        );\r\n\r\n        check_ntstatus(status as i32)?;\r\n\r\n        return Ok(filter_id);\r\n    }\r\n}\r\n\r\npub(crate) fn unregister_filter(\r\n    filter_engine_handle: HANDLE,\r\n    filter_id: u64,\r\n) -> Result<(), String> {\r\n    unsafe {\r\n        let status = FwpmFilterDeleteById0(filter_engine_handle, filter_id);\r\n        check_ntstatus(status as i32)?;\r\n        return Ok(());\r\n    }\r\n}\r\n\r\npub(crate) fn filter_engine_close(filter_engine_handle: HANDLE) -> Result<(), String> {\r\n    unsafe {\r\n        let status = FwpmEngineClose0(filter_engine_handle);\r\n        check_ntstatus(status as i32)?;\r\n        return Ok(());\r\n    }\r\n}\r\n\r\npub(crate) fn filter_engine_transaction_begin(\r\n    filter_engine_handle: HANDLE,\r\n    flags: u32,\r\n) -> Result<(), String> {\r\n    unsafe {\r\n        let status = FwpmTransactionBegin0(filter_engine_handle, flags);\r\n        check_ntstatus(status as i32)?;\r\n        return Ok(());\r\n    }\r\n}\r\n\r\npub(crate) fn filter_engine_transaction_commit(filter_engine_handle: HANDLE) -> Result<(), String> {\r\n    unsafe {\r\n        let status = FwpmTransactionCommit0(filter_engine_handle);\r\n        check_ntstatus(status as i32)?;\r\n        return Ok(());\r\n    }\r\n}\r\n\r\npub(crate) fn filter_engine_transaction_abort(filter_engine_handle: HANDLE) -> Result<(), String> {\r\n    unsafe {\r\n        let status = FwpmTransactionAbort0(filter_engine_handle);\r\n        check_ntstatus(status as i32)?;\r\n        return Ok(());\r\n    }\r\n}\r\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/layer.rs",
    "content": "use core::fmt::Debug;\r\n\r\nuse windows_sys::{\r\n    core::GUID,\r\n    Win32::NetworkManagement::WindowsFilteringPlatform::{\r\n        FWPM_LAYER_ALE_AUTH_CONNECT_V4, FWPM_LAYER_ALE_AUTH_CONNECT_V4_DISCARD,\r\n        FWPM_LAYER_ALE_AUTH_CONNECT_V6, FWPM_LAYER_ALE_AUTH_CONNECT_V6_DISCARD,\r\n        FWPM_LAYER_ALE_AUTH_LISTEN_V4, FWPM_LAYER_ALE_AUTH_LISTEN_V4_DISCARD,\r\n        FWPM_LAYER_ALE_AUTH_LISTEN_V6, FWPM_LAYER_ALE_AUTH_LISTEN_V6_DISCARD,\r\n        FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD,\r\n        FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD,\r\n        FWPM_LAYER_ALE_BIND_REDIRECT_V4, FWPM_LAYER_ALE_BIND_REDIRECT_V6,\r\n        FWPM_LAYER_ALE_CONNECT_REDIRECT_V4, FWPM_LAYER_ALE_CONNECT_REDIRECT_V6,\r\n        FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V4, FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V6,\r\n        FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4, FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD,\r\n        FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6, FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD,\r\n        FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4, FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD,\r\n        FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6, FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD,\r\n        FWPM_LAYER_ALE_RESOURCE_RELEASE_V4, FWPM_LAYER_ALE_RESOURCE_RELEASE_V6,\r\n        FWPM_LAYER_DATAGRAM_DATA_V4, FWPM_LAYER_DATAGRAM_DATA_V4_DISCARD,\r\n        FWPM_LAYER_DATAGRAM_DATA_V6, FWPM_LAYER_DATAGRAM_DATA_V6_DISCARD,\r\n        FWPM_LAYER_INBOUND_ICMP_ERROR_V4, FWPM_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD,\r\n        FWPM_LAYER_INBOUND_ICMP_ERROR_V6, FWPM_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD,\r\n        FWPM_LAYER_INBOUND_IPPACKET_V4, FWPM_LAYER_INBOUND_IPPACKET_V4_DISCARD,\r\n        FWPM_LAYER_INBOUND_IPPACKET_V6, FWPM_LAYER_INBOUND_IPPACKET_V6_DISCARD,\r\n        FWPM_LAYER_INBOUND_TRANSPORT_V4, FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD,\r\n        FWPM_LAYER_INBOUND_TRANSPORT_V6, FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD,\r\n        FWPM_LAYER_IPFORWARD_V4, FWPM_LAYER_IPFORWARD_V4_DISCARD, FWPM_LAYER_IPFORWARD_V6,\r\n        FWPM_LAYER_IPFORWARD_V6_DISCARD, FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4,\r\n        FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD, FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6,\r\n        FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD, FWPM_LAYER_OUTBOUND_IPPACKET_V4,\r\n        FWPM_LAYER_OUTBOUND_IPPACKET_V4_DISCARD, FWPM_LAYER_OUTBOUND_IPPACKET_V6,\r\n        FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD, FWPM_LAYER_OUTBOUND_TRANSPORT_V4,\r\n        FWPM_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD, FWPM_LAYER_OUTBOUND_TRANSPORT_V6,\r\n        FWPM_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD, FWPM_LAYER_STREAM_V4,\r\n        FWPM_LAYER_STREAM_V4_DISCARD, FWPM_LAYER_STREAM_V6, FWPM_LAYER_STREAM_V6_DISCARD,\r\n    },\r\n};\r\n\r\n#[repr(C)]\r\npub(crate) struct Value {\r\n    pub(crate) value_type: ValueType,\r\n    pub(crate) value: ValueData,\r\n}\r\n\r\n#[repr(C)]\r\npub(crate) struct IncomingValues {\r\n    pub(crate) layer_id: u16,\r\n    pub(crate) value_count: u32,\r\n    pub(crate) incoming_value_array: *const Value,\r\n}\r\n\r\n#[repr(C)]\r\npub(crate) union ValueData {\r\n    pub(crate) uint8: u8,\r\n    pub(crate) uint16: u16,\r\n    pub(crate) uint32: u32,\r\n    pub(crate) uint64: *const u64,\r\n    pub(crate) byte_array16: *const [u8; 16],\r\n    // TODO: add the rest of possible values.\r\n}\r\n\r\n#[repr(C)]\r\n#[derive(Copy, Clone, Debug)]\r\npub enum ValueType {\r\n    FwpEmpty = 0,\r\n    FwpUint8 = 1,\r\n    FwpUint16 = 2,\r\n    FwpUint32 = 3,\r\n    FwpUint64 = 4,\r\n    FwpInt8 = 5,\r\n    FwpInt16 = 6,\r\n    FwpInt32 = 7,\r\n    FwpInt64 = 8,\r\n    FwpFloat = 9,\r\n    FwpDouble = 10,\r\n    FwpByteArray16Type = 11,\r\n    FwpByteBlobType = 12,\r\n    FwpSid = 13,\r\n    FwpSecurityDescriptorType = 14,\r\n    FwpTokenInformationType = 15,\r\n    FwpTokenAccessInformationType = 16,\r\n    FwpUnicodeStringType = 17,\r\n    FwpByteArray6Type = 18,\r\n    FwpSingleDataTypeMax = 0xff,\r\n    FwpV4AddrMask = 0xff + 1,\r\n    FwpV6AddrMask = 0xff + 2,\r\n    FwpRangeType = 0xff + 3,\r\n    FwpDataTypeMax = 0xff + 4,\r\n}\r\n\r\n#[derive(Copy, Clone, Debug)]\r\npub enum Layer {\r\n    InboundIppacketV4,\r\n    InboundIppacketV4Discard,\r\n    InboundIppacketV6,\r\n    InboundIppacketV6Discard,\r\n    OutboundIppacketV4,\r\n    OutboundIppacketV4Discard,\r\n    OutboundIppacketV6,\r\n    OutboundIppacketV6Discard,\r\n    IpforwardV4,\r\n    IpforwardV4Discard,\r\n    IpforwardV6,\r\n    IpforwardV6Discard,\r\n    InboundTransportV4,\r\n    InboundTransportV4Discard,\r\n    InboundTransportV6,\r\n    InboundTransportV6Discard,\r\n    OutboundTransportV4,\r\n    OutboundTransportV4Discard,\r\n    OutboundTransportV6,\r\n    OutboundTransportV6Discard,\r\n    StreamV4,\r\n    StreamV4Discard,\r\n    StreamV6,\r\n    StreamV6Discard,\r\n    DatagramDataV4,\r\n    DatagramDataV4Discard,\r\n    DatagramDataV6,\r\n    DatagramDataV6Discard,\r\n    InboundIcmpErrorV4,\r\n    InboundIcmpErrorV4Discard,\r\n    InboundIcmpErrorV6,\r\n    InboundIcmpErrorV6Discard,\r\n    OutboundIcmpErrorV4,\r\n    OutboundIcmpErrorV4Discard,\r\n    OutboundIcmpErrorV6,\r\n    OutboundIcmpErrorV6Discard,\r\n    AleResourceAssignmentV4,\r\n    AleResourceAssignmentV4Discard,\r\n    AleResourceAssignmentV6,\r\n    AleResourceAssignmentV6Discard,\r\n    AleAuthListenV4,\r\n    AleAuthListenV4Discard,\r\n    AleAuthListenV6,\r\n    AleAuthListenV6Discard,\r\n    AleAuthRecvAcceptV4,\r\n    AleAuthRecvAcceptV4Discard,\r\n    AleAuthRecvAcceptV6,\r\n    AleAuthRecvAcceptV6Discard,\r\n    AleAuthConnectV4,\r\n    AleAuthConnectV4Discard,\r\n    AleAuthConnectV6,\r\n    AleAuthConnectV6Discard,\r\n    AleFlowEstablishedV4,\r\n    AleFlowEstablishedV4Discard,\r\n    AleFlowEstablishedV6,\r\n    AleFlowEstablishedV6Discard,\r\n    AleConnectRedirectV4,\r\n    AleConnectRedirectV6,\r\n    AleBindRedirectV4,\r\n    AleBindRedirectV6,\r\n    AleResourceReleaseV4,\r\n    AleResourceReleaseV6,\r\n    AleEndpointClosureV4,\r\n    AleEndpointClosureV6,\r\n}\r\n\r\nimpl Layer {\r\n    pub fn get_guid(&self) -> GUID {\r\n        match self {\r\n            Layer::InboundIppacketV4 => FWPM_LAYER_INBOUND_IPPACKET_V4,\r\n            Layer::InboundIppacketV4Discard => FWPM_LAYER_INBOUND_IPPACKET_V4_DISCARD,\r\n            Layer::InboundIppacketV6 => FWPM_LAYER_INBOUND_IPPACKET_V6,\r\n            Layer::InboundIppacketV6Discard => FWPM_LAYER_INBOUND_IPPACKET_V6_DISCARD,\r\n            Layer::OutboundIppacketV4 => FWPM_LAYER_OUTBOUND_IPPACKET_V4,\r\n            Layer::OutboundIppacketV4Discard => FWPM_LAYER_OUTBOUND_IPPACKET_V4_DISCARD,\r\n            Layer::OutboundIppacketV6 => FWPM_LAYER_OUTBOUND_IPPACKET_V6,\r\n            Layer::OutboundIppacketV6Discard => FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD,\r\n            Layer::IpforwardV4 => FWPM_LAYER_IPFORWARD_V4,\r\n            Layer::IpforwardV4Discard => FWPM_LAYER_IPFORWARD_V4_DISCARD,\r\n            Layer::IpforwardV6 => FWPM_LAYER_IPFORWARD_V6,\r\n            Layer::IpforwardV6Discard => FWPM_LAYER_IPFORWARD_V6_DISCARD,\r\n            Layer::InboundTransportV4 => FWPM_LAYER_INBOUND_TRANSPORT_V4,\r\n            Layer::InboundTransportV4Discard => FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD,\r\n            Layer::InboundTransportV6 => FWPM_LAYER_INBOUND_TRANSPORT_V6,\r\n            Layer::InboundTransportV6Discard => FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD,\r\n            Layer::OutboundTransportV4 => FWPM_LAYER_OUTBOUND_TRANSPORT_V4,\r\n            Layer::OutboundTransportV4Discard => FWPM_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD,\r\n            Layer::OutboundTransportV6 => FWPM_LAYER_OUTBOUND_TRANSPORT_V6,\r\n            Layer::OutboundTransportV6Discard => FWPM_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD,\r\n            Layer::StreamV4 => FWPM_LAYER_STREAM_V4,\r\n            Layer::StreamV4Discard => FWPM_LAYER_STREAM_V4_DISCARD,\r\n            Layer::StreamV6 => FWPM_LAYER_STREAM_V6,\r\n            Layer::StreamV6Discard => FWPM_LAYER_STREAM_V6_DISCARD,\r\n            Layer::DatagramDataV4 => FWPM_LAYER_DATAGRAM_DATA_V4,\r\n            Layer::DatagramDataV4Discard => FWPM_LAYER_DATAGRAM_DATA_V4_DISCARD,\r\n            Layer::DatagramDataV6 => FWPM_LAYER_DATAGRAM_DATA_V6,\r\n            Layer::DatagramDataV6Discard => FWPM_LAYER_DATAGRAM_DATA_V6_DISCARD,\r\n            Layer::InboundIcmpErrorV4 => FWPM_LAYER_INBOUND_ICMP_ERROR_V4,\r\n            Layer::InboundIcmpErrorV4Discard => FWPM_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD,\r\n            Layer::InboundIcmpErrorV6 => FWPM_LAYER_INBOUND_ICMP_ERROR_V6,\r\n            Layer::InboundIcmpErrorV6Discard => FWPM_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD,\r\n            Layer::OutboundIcmpErrorV4 => FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4,\r\n            Layer::OutboundIcmpErrorV4Discard => FWPM_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD,\r\n            Layer::OutboundIcmpErrorV6 => FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6,\r\n            Layer::OutboundIcmpErrorV6Discard => FWPM_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD,\r\n            Layer::AleResourceAssignmentV4 => FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4,\r\n            Layer::AleResourceAssignmentV4Discard => FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD,\r\n            Layer::AleResourceAssignmentV6 => FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6,\r\n            Layer::AleResourceAssignmentV6Discard => FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD,\r\n            Layer::AleAuthListenV4 => FWPM_LAYER_ALE_AUTH_LISTEN_V4,\r\n            Layer::AleAuthListenV4Discard => FWPM_LAYER_ALE_AUTH_LISTEN_V4_DISCARD,\r\n            Layer::AleAuthListenV6 => FWPM_LAYER_ALE_AUTH_LISTEN_V6,\r\n            Layer::AleAuthListenV6Discard => FWPM_LAYER_ALE_AUTH_LISTEN_V6_DISCARD,\r\n            Layer::AleAuthRecvAcceptV4 => FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,\r\n            Layer::AleAuthRecvAcceptV4Discard => FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD,\r\n            Layer::AleAuthRecvAcceptV6 => FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,\r\n            Layer::AleAuthRecvAcceptV6Discard => FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD,\r\n            Layer::AleAuthConnectV4 => FWPM_LAYER_ALE_AUTH_CONNECT_V4,\r\n            Layer::AleAuthConnectV4Discard => FWPM_LAYER_ALE_AUTH_CONNECT_V4_DISCARD,\r\n            Layer::AleAuthConnectV6 => FWPM_LAYER_ALE_AUTH_CONNECT_V6,\r\n            Layer::AleAuthConnectV6Discard => FWPM_LAYER_ALE_AUTH_CONNECT_V6_DISCARD,\r\n            Layer::AleFlowEstablishedV4 => FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4,\r\n            Layer::AleFlowEstablishedV4Discard => FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD,\r\n            Layer::AleFlowEstablishedV6 => FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6,\r\n            Layer::AleFlowEstablishedV6Discard => FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD,\r\n            Layer::AleConnectRedirectV4 => FWPM_LAYER_ALE_CONNECT_REDIRECT_V4,\r\n            Layer::AleConnectRedirectV6 => FWPM_LAYER_ALE_CONNECT_REDIRECT_V6,\r\n            Layer::AleBindRedirectV4 => FWPM_LAYER_ALE_BIND_REDIRECT_V4,\r\n            Layer::AleBindRedirectV6 => FWPM_LAYER_ALE_BIND_REDIRECT_V6,\r\n            Layer::AleResourceReleaseV4 => FWPM_LAYER_ALE_RESOURCE_RELEASE_V4,\r\n            Layer::AleResourceReleaseV6 => FWPM_LAYER_ALE_RESOURCE_RELEASE_V6,\r\n            Layer::AleEndpointClosureV4 => FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V4,\r\n            Layer::AleEndpointClosureV6 => FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V6,\r\n        }\r\n    }\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundIppacketV4 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundIppacketV6 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundIppacketV4 {\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpRemoteAddress,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundIppacketV6 {\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpRemoteAddress,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIpforwardV4 {\r\n    IpSourceAddress,\r\n    IpDestinationAddress,\r\n    IpDestinationAddressType,\r\n    IpLocalInterface,\r\n    IpForwardInterface,\r\n    SourceInterfaceIndex,\r\n    SourceSubInterfaceIndex,\r\n    DestinationInterfaceIndex,\r\n    DestinationSubInterfaceIndex,\r\n    Flags,\r\n    IpPhysicalArrivalInterface,\r\n    ArrivalInterfaceProfileId,\r\n    IpPhysicalNexthopInterface,\r\n    NexthopInterfaceProfileId,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIpforwardV6 {\r\n    IpSourceAddress,\r\n    IpDestinationAddress,\r\n    IpDestinationAddressType,\r\n    IpLocalInterface,\r\n    IpForwardInterface,\r\n    SourceInterfaceIndex,\r\n    SourceSubInterfaceIndex,\r\n    DestinationInterfaceIndex,\r\n    DestinationSubInterfaceIndex,\r\n    Flags,\r\n    IpPhysicalArrivalInterface,\r\n    ArrivalInterfaceProfileId,\r\n    IpPhysicalNexthopInterface,\r\n    NexthopInterfaceProfileId,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundTransportV4 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundTransportFas {\r\n    FieldInboundTransportFastMax,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundTransportFas {\r\n    FieldOutboundTransportFastMax,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundTransportV6 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundTransportV4 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    IpDestinationAddressType,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundTransportV6 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    IpDestinationAddressType,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsStreamV4 {\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    Direction,\r\n    Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsStreamV6 {\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    Direction,\r\n    Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsDatagramDataV4 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Direction,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsDatagramDataV6 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Direction,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsStreamPacketV4 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Direction,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsStreamPacketV6 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    Direction,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundIcmpErrorV4 {\r\n    EmbeddedProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    EmbeddedRemoteAddress,\r\n    EmbeddedLocalAddressType,\r\n    EmbeddedLocalPort,\r\n    EmbeddedRemotePort,\r\n    IpLocalInterface,\r\n    IcmpType,\r\n    IcmpCode,\r\n    InterfaceIndex,    // of local/delivery interface\r\n    SubInterfaceIndex, // of arrival interface\r\n    InterfaceType,     // of local/delivery interface\r\n    TunnelType,        // of local/delivery interface\r\n    IpArrivalInterface,\r\n    ArrivalInterfaceIndex,\r\n    ArrivalInterfaceType,\r\n    ArrivalTunnelType,\r\n    Flags,\r\n    ArrivalInterfaceProfileId,\r\n    InterfaceQuarantineEpoch,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundIcmpErrorV6 {\r\n    EmbeddedProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    EmbeddedRemoteAddress,\r\n    EmbeddedLocalAddressType,\r\n    EmbeddedLocalPort,\r\n    EmbeddedRemotePort,\r\n    IpLocalInterface,\r\n    IcmpType,\r\n    IcmpCode,\r\n    InterfaceIndex,    // of local/delivery interface\r\n    SubInterfaceIndex, // of arrival interface\r\n    InterfaceType,     // of local/delivery interface\r\n    TunnelType,        // of local/delivery interface\r\n    IpArrivalInterface,\r\n    ArrivalInterfaceIndex,\r\n    ArrivalInterfaceType,\r\n    ArrivalTunnelType,\r\n    Flags,\r\n    ArrivalInterfaceProfileId,\r\n    InterfaceQuarantineEpoch,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundIcmpErrorV4 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalInterface,\r\n    IcmpType,\r\n    IcmpCode,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    InterfaceType,\r\n    TunnelType,\r\n    Flags,\r\n    NexthopInterfaceProfileId,\r\n    InterfaceQuarantineEpoch,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundIcmpErrorV6 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalAddressType,\r\n    IpLocalInterface,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    InterfaceType,\r\n    TunnelType,\r\n    Flags,\r\n    NexthopInterfaceProfileId,\r\n    InterfaceQuarantineEpoch,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleResourceAssignmentV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    AlePromiscuousMode,\r\n    IpLocalInterface,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    LocalInterfaceProfileId,\r\n    SioFirewallSocketProperty,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleResourceAssignmentV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    AlePromiscuousMode,\r\n    IpLocalInterface,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    LocalInterfaceProfileId,\r\n    SioFirewallSocketProperty,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleResourceReleaseV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpLocalInterface,\r\n    Flags,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleResourceReleaseV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpLocalInterface,\r\n    Flags,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleEndpointClosureV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    Flags,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleEndpointClosureV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    Flags,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleAuthListenV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpLocalInterface,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    LocalInterfaceProfileId,\r\n    SioFirewallSocketProperty,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleAuthListenV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpLocalInterface,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    LocalInterfaceProfileId,\r\n    SioFirewallSocketProperty,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleAuthRecvAcceptV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    AleRemoteUserId,\r\n    AleRemoteMachineId,\r\n    IpLocalInterface,\r\n    Flags,\r\n    SioFirewallSystemPort,\r\n    NapContext,\r\n    InterfaceType,     // of local/delivery interface\r\n    TunnelType,        // of local/delivery interface\r\n    InterfaceIndex,    // of local/delivery interface\r\n    SubInterfaceIndex, // of arrival interface\r\n    IpArrivalInterface,\r\n    ArrivalInterfaceType,\r\n    ArrivalTunnelType,\r\n    ArrivalInterfaceIndex,\r\n    NexthopSubInterfaceIndex,\r\n    IpNexthopInterface,\r\n    NexthopInterfaceType,\r\n    NexthopTunnelType,\r\n    NexthopInterfaceIndex,\r\n    OriginalProfileId,\r\n    CurrentProfileId,\r\n    ReauthorizeReason,\r\n    OriginalIcmpType,\r\n    InterfaceQuarantineEpoch,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Reserved2,\r\n    Reserved3,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleAuthRecvAcceptV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    AleRemoteUserId,\r\n    AleRemoteMachineId,\r\n    IpLocalInterface,\r\n    Flags,\r\n    SioFirewallSystemPort,\r\n    NapContext,\r\n    InterfaceType,     // of local/delivery interface\r\n    TunnelType,        // of local/delivery interface\r\n    InterfaceIndex,    // of local/delivery interface\r\n    SubInterfaceIndex, // of arrival interface\r\n    IpArrivalInterface,\r\n    ArrivalInterfaceType,\r\n    ArrivalTunnelType,\r\n    ArrivalInterfaceIndex,\r\n    NexthopSubInterfaceIndex,\r\n    IpNexthopInterface,\r\n    NexthopInterfaceType,\r\n    NexthopTunnelType,\r\n    NexthopInterfaceIndex,\r\n    OriginalProfileId,\r\n    CurrentProfileId,\r\n    ReauthorizeReason,\r\n    OriginalIcmpType,\r\n    InterfaceQuarantineEpoch,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Reserved2,\r\n    Reserved3,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleBindRedirectV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    Flags,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleBindRedirectV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    Flags,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleConnectRedirectV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpDestinationAddressType,\r\n    IpRemotePort,\r\n    Flags,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleConnectRedirectV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpDestinationAddressType,\r\n    IpRemotePort,\r\n    Flags,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleAuthConnectV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    AleRemoteUserId,\r\n    AleRemoteMachineId,\r\n    IpDestinationAddressType,\r\n    IpLocalInterface,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    IpArrivalInterface,\r\n    ArrivalInterfaceType,\r\n    ArrivalTunnelType,\r\n    ArrivalInterfaceIndex,\r\n    NexthopSubInterfaceIndex,\r\n    IpNexthopInterface,\r\n    NexthopInterfaceType,\r\n    NexthopTunnelType,\r\n    NexthopInterfaceIndex,\r\n    OriginalProfileId,\r\n    CurrentProfileId,\r\n    ReauthorizeReason,\r\n    PeerName,\r\n    OriginalIcmpType,\r\n    InterfaceQuarantineEpoch,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    AleEffectiveName,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Reserved2,\r\n    Reserved3,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleAuthConnectV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    AleRemoteUserId,\r\n    AleRemoteMachineId,\r\n    IpDestinationAddressType,\r\n    IpLocalInterface,\r\n    Flags,\r\n    InterfaceType,\r\n    TunnelType,\r\n    InterfaceIndex,\r\n    SubInterfaceIndex,\r\n    IpArrivalInterface,\r\n    ArrivalInterfaceType,\r\n    ArrivalTunnelType,\r\n    ArrivalInterfaceIndex,\r\n    NexthopSubInterfaceIndex,\r\n    IpNexthopInterface,\r\n    NexthopInterfaceType,\r\n    NexthopTunnelType,\r\n    NexthopInterfaceIndex,\r\n    OriginalProfileId,\r\n    CurrentProfileId,\r\n    ReauthorizeReason,\r\n    PeerName,\r\n    OriginalIcmpType,\r\n    InterfaceQuarantineEpoch,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    AleEffectiveName,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Reserved2,\r\n    Reserved3,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleFlowEstablishedV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    AleRemoteUserId,\r\n    AleRemoteMachineId,\r\n    IpDestinationAddressType,\r\n    IpLocalInterface,\r\n    Direction,\r\n    InterfaceType,\r\n    TunnelType,\r\n    Flags,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Reserved2,\r\n    Reserved3,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsAleFlowEstablishedV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpRemotePort,\r\n    AleRemoteUserId,\r\n    AleRemoteMachineId,\r\n    IpDestinationAddressType,\r\n    IpLocalInterface,\r\n    Direction,\r\n    InterfaceType,\r\n    TunnelType,\r\n    Flags,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    //\r\n    // These reserved fields MUST be in this order. DO NOT change their order\r\n    //\r\n    Reserved0,\r\n    Reserved1,\r\n    Reserved2,\r\n    Reserved3,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsNameResolutionCacheV4 {\r\n    AleUserId,\r\n    AleAppId,\r\n    IpRemoteAddress,\r\n    PeerName,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsNameResolutionCacheV6 {\r\n    AleUserId,\r\n    AleAppId,\r\n    IpRemoteAddress,\r\n    PeerName,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundMacFrameEthernet {\r\n    InterfaceMacAddress,\r\n    MacLocalAddress,\r\n    MacRemoteAddress,\r\n    MacLocalAddressType,\r\n    MacRemoteAddressType,\r\n    EtherType,\r\n    VlanId,\r\n    Interface,\r\n    InterfaceIndex,\r\n    NdisPort,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundMacFrameEthernet {\r\n    InterfaceMacAddress,\r\n    MacLocalAddress,\r\n    MacRemoteAddress,\r\n    MacLocalAddressType,\r\n    MacRemoteAddressType,\r\n    EtherType,\r\n    VlanId,\r\n    Interface,\r\n    InterfaceIndex,\r\n    NdisPort,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundMacFrameNative {\r\n    NdisMediaType,\r\n    NdisPhysicalMediaType,\r\n    Interface,\r\n    InterfaceType,\r\n    InterfaceIndex,\r\n    NdisPort,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundMacFrameNativeFast {\r\n    FastMax,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundMacFrameNative {\r\n    NdisMediaType,\r\n    NdisPhysicalMediaType,\r\n    Interface,\r\n    InterfaceType,\r\n    InterfaceIndex,\r\n    NdisPort,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundMacFrameNativeFast {\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIngressVswitchEthernet {\r\n    MacSourceAddress,\r\n    MacSourceAddressType,\r\n    MacDestinationAddress,\r\n    MacDestinationAddressType,\r\n    EtherType,\r\n    VlanId,\r\n    VswitchTenantNetworkId,\r\n    VswitchId,\r\n    VswitchNetworkType,\r\n    VswitchSourceInterfaceId,\r\n    VswitchSourceInterfaceType,\r\n    VswitchSourceVmId,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsEgressVswitchEthernet {\r\n    MacSourceAddress,\r\n    MacSourceAddressType,\r\n    MacDestinationAddress,\r\n    MacDestinationAddressType,\r\n    EtherType,\r\n    VlanId,\r\n    VswitchTenantNetworkId,\r\n    VswitchId,\r\n    VswitchNetworkType,\r\n    VswitchSourceInterfaceId,\r\n    VswitchSourceInterfaceType,\r\n    VswitchSourceVmId,\r\n    VswitchDestinationInterfaceId,\r\n    VswitchDestinationInterfaceType,\r\n    VswitchDestinationVmId,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIngressVswitchTransportV4 {\r\n    IpSourceAddress,\r\n    IpDestinationAddress,\r\n    IpProtocol,\r\n    IpSourcePort,\r\n    IpDestinationPort,\r\n    VlanId,\r\n    VswitchTenantNetworkId,\r\n    VswitchId,\r\n    VswitchNetworkType,\r\n    VswitchSourceInterfaceId,\r\n    VswitchSourceInterfaceType,\r\n    VswitchSourceVmId,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIngressVswitchTransportV6 {\r\n    IpSourceAddress,\r\n    IpDestinationAddress,\r\n    IpProtocol,\r\n    IpSourcePort,\r\n    IpDestinationPort,\r\n    VlanId,\r\n    VswitchTenantNetworkId,\r\n    VswitchId,\r\n    VswitchNetworkType,\r\n    VswitchSourceInterfaceId,\r\n    VswitchSourceInterfaceType,\r\n    VswitchSourceVmId,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsEgressVswitchTransportV4 {\r\n    IpSourceAddress,\r\n    IpDestinationAddress,\r\n    IpProtocol,\r\n    IpSourcePort,\r\n    IpDestinationPort,\r\n    VlanId,\r\n    VswitchTenantNetworkId,\r\n    VswitchId,\r\n    VswitchNetworkType,\r\n    VswitchSourceInterfaceId,\r\n    VswitchSourceInterfaceType,\r\n    VswitchSourceVmId,\r\n    VswitchDestinationInterfaceId,\r\n    VswitchDestinationInterfaceType,\r\n    VswitchDestinationVmId,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsEgressVswitchTransportV6 {\r\n    IpSourceAddress,\r\n    IpDestinationAddress,\r\n    IpProtocol,\r\n    IpSourcePort,\r\n    IpDestinationPort,\r\n    VlanId,\r\n    VswitchTenantNetworkId,\r\n    VswitchId,\r\n    VswitchNetworkType,\r\n    VswitchSourceInterfaceId,\r\n    VswitchSourceInterfaceType,\r\n    VswitchSourceVmId,\r\n    VswitchDestinationInterfaceId,\r\n    VswitchDestinationInterfaceType,\r\n    VswitchDestinationVmId,\r\n    L2Flags,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIpsecKmDemuxV4 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    QmMode,\r\n    IpLocalInterface,\r\n    CurrentProfileId,\r\n    IpsecSecurityRealmId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIpsecKmDemuxV6 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    QmMode,\r\n    IpLocalInterface,\r\n    CurrentProfileId,\r\n    IpsecSecurityRealmId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIpsecV4 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIpsecV6 {\r\n    IpProtocol,\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalPort,\r\n    IpRemotePort,\r\n    IpLocalInterface,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIkeextV4 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalInterface,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsIkeextV6 {\r\n    IpLocalAddress,\r\n    IpRemoteAddress,\r\n    IpLocalInterface,\r\n    ProfileId,\r\n    IpsecSecurityRealmId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsRpcUm {\r\n    RemoteUserToken,\r\n    AuthLevel,\r\n    AuthType,\r\n    DcomAppId,\r\n    IfFlag,\r\n    IfUuid,\r\n    IfVersion,\r\n    ImageName,\r\n    LocalAddrV4,\r\n    LocalAddrV6,\r\n    LocalPort,\r\n    Max,\r\n    Pipe,\r\n    Protocol,\r\n    RemoteAddrV4,\r\n    RemoteAddrV6,\r\n    SecEncryptAlgorithm,\r\n    SecKeySize,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsRpcEpmap {\r\n    RemoteUserToken,\r\n    IfUuid,\r\n    IfVersion,\r\n    Protocol,\r\n    AuthType,\r\n    AuthLevel,\r\n    SecEncryptAlgorithm,\r\n    SecKeySize,\r\n    LocalAddrV4,\r\n    LocalAddrV6,\r\n    LocalPort,\r\n    Pipe,\r\n    RemoteAddrV4,\r\n    RemoteAddrV6,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsRpcEpAdd {\r\n    ProcessWithRpcIfUuid,\r\n    Protocol,\r\n    EpValue,\r\n    EpFlags,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsRpcProxyConn {\r\n    ClientToken,\r\n    ServerName,\r\n    ServerPort,\r\n    ProxyAuthType,\r\n    ClientCertKeyLength,\r\n    ClientCertOid,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsRpcProxyIf {\r\n    ClientToken,\r\n    IfUuid,\r\n    IfVersion,\r\n    ServerName,\r\n    ServerPort,\r\n    ProxyAuthType,\r\n    ClientCertKeyLength,\r\n    ClientCertOid,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsKmAuthorization {\r\n    RemoteId,\r\n    AuthenticationType,\r\n    KmType,\r\n    Direction,\r\n    KmMode,\r\n    IpsecPolicyKey,\r\n    NapContext,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsInboundReserved2 {\r\n    Reserved0,\r\n    Reserved1,\r\n    Reserved2,\r\n    Reserved3,\r\n    Reserved4,\r\n    Reserved5,\r\n    Reserved6,\r\n    Reserved7,\r\n    Reserved8,\r\n    Reserved9,\r\n    Reserved10,\r\n    Reserved11,\r\n    Reserved12,\r\n    Reserved13,\r\n    Reserved14,\r\n    Reserved15,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundNetworkConnectionPolicyV4 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpDestinationAddressType,\r\n    IpRemotePort,\r\n    Flags,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n\r\n#[repr(usize)]\r\npub enum FieldsOutboundNetworkConnectionPolicyV6 {\r\n    AleAppId,\r\n    AleUserId,\r\n    IpLocalAddress,\r\n    IpLocalAddressType,\r\n    IpLocalPort,\r\n    IpProtocol,\r\n    IpRemoteAddress,\r\n    IpDestinationAddressType,\r\n    IpRemotePort,\r\n    Flags,\r\n    AleOriginalAppId,\r\n    AlePackageId,\r\n    AleSecurityAttributeFqbnValue,\r\n    CompartmentId,\r\n    Max,\r\n}\r\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/metadata.rs",
    "content": "use core::{ffi::c_void, ptr::NonNull};\n\nuse alloc::string::String;\nuse widestring::U16CString;\nuse windows_sys::Win32::{\n    Foundation::HANDLE,\n    NetworkManagement::{\n        IpHelper::IP_ADDRESS_PREFIX,\n        WindowsFilteringPlatform::{\n            FWPS_METADATA_FIELD_COMPLETION_HANDLE, FWPS_METADATA_FIELD_FRAGMENT_DATA,\n            FWPS_METADATA_FIELD_PROCESS_ID, FWPS_METADATA_FIELD_PROCESS_PATH,\n            FWPS_METADATA_FIELD_REMOTE_SCOPE_ID, FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA,\n            FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE, FWP_BYTE_BLOB, FWP_DIRECTION,\n        },\n    },\n    Networking::WinSock::SCOPE_ID,\n};\n\n#[repr(C)]\npub(crate) struct FwpsIncomingMetadataValues {\n    /// Bitmask representing which values are set.\n    current_metadata_values: u32,\n    /// Internal flags;\n    flags: u32,\n    /// Reserved for system use.\n    reserved: u64,\n    /// Discard module and reason.\n    discard_metadata: FwpsDiscardMetadata0,\n    /// Flow Handle.\n    flow_handle: u64,\n    /// IP Header size.\n    ip_header_size: u32,\n    /// Transport Header size\n    transport_header_size: u32,\n    /// Process Path.\n    process_path: *const FWP_BYTE_BLOB,\n    /// Token used for authorization.\n    token: u64,\n    /// Process Id.\n    process_id: u64,\n    /// Source and Destination interface indices for discard indications.\n    source_interface_index: u32,\n    destination_interface_index: u32,\n    /// Compartment Id for injection APIs.\n    compartment_id: u32,\n    /// Fragment data for inbound fragments.\n    fragment_metadata: FwpsInboundFragmentMetadata0,\n    /// Path MTU for outbound packets (to enable calculation of fragments).\n    path_mtu: u32,\n    /// Completion handle (required in order to be able to pend at this layer).\n    completion_handle: HANDLE,\n    /// Endpoint handle for use in outbound transport layer injection.\n    transport_endpoint_handle: u64,\n    /// Remote scope id for use in outbound transport layer injection.\n    remote_scope_id: SCOPE_ID,\n    /// Socket control data (and length) for use in outbound transport layer injection.\n    control_data: *const u8,\n    control_data_length: u32,\n    /// Direction for the current packet. Only specified for ALE re-authorization.\n    packet_direction: FWP_DIRECTION,\n    /// Raw IP header (and length) if the packet is sent with IP header from a RAW socket.\n    header_include_header: *mut c_void,\n    header_include_header_length: u32,\n    destination_prefix: IP_ADDRESS_PREFIX,\n    frame_length: u16,\n    parent_endpoint_handle: u64,\n    icmp_id_and_sequence: u32,\n    /// PID of the process that will be accepting the redirected connection\n    local_redirect_target_pid: u64,\n    /// original destination of a redirected connection\n    original_destination: *mut c_void,\n    redirect_records: HANDLE,\n    /// Bitmask representing which L2 values are set.\n    current_l2_metadata_values: u32,\n    /// L2 layer Flags;\n    l2_flags: u32,\n    ethernet_mac_header_size: u32,\n    wifi_operation_mode: u32,\n    padding0: u32,\n    padding1: u16,\n    padding2: u32,\n    v_switch_packet_context: HANDLE,\n    sub_process_tag: *mut c_void,\n    // Reserved for system use.\n    reserved1: u64,\n}\n\nimpl FwpsIncomingMetadataValues {\n    pub(crate) fn has_field(&self, field: u32) -> bool {\n        self.current_metadata_values & field > 0\n    }\n\n    pub(crate) fn get_process_id(&self) -> Option<u64> {\n        if self.has_field(FWPS_METADATA_FIELD_PROCESS_ID) {\n            return Some(self.process_id);\n        }\n\n        None\n    }\n\n    pub(crate) unsafe fn get_process_path(&self) -> Option<String> {\n        if self.has_field(FWPS_METADATA_FIELD_PROCESS_PATH) {\n            if let Ok(path16) = U16CString::from_ptr(\n                core::mem::transmute((*self.process_path).data),\n                (*self.process_path).size as usize / 2,\n            ) {\n                if let Ok(path) = path16.to_string() {\n                    return Some(path);\n                }\n            }\n        }\n\n        None\n    }\n\n    pub(crate) fn get_completion_handle(&self) -> Option<HANDLE> {\n        if self.has_field(FWPS_METADATA_FIELD_COMPLETION_HANDLE) {\n            return Some(self.completion_handle);\n        }\n\n        None\n    }\n\n    pub(crate) fn get_transport_endpoint_handle(&self) -> Option<u64> {\n        if self.has_field(FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE) {\n            return Some(self.transport_endpoint_handle);\n        }\n\n        None\n    }\n\n    pub(crate) fn get_remote_scope_id(&self) -> Option<SCOPE_ID> {\n        if self.has_field(FWPS_METADATA_FIELD_REMOTE_SCOPE_ID) {\n            return Some(self.remote_scope_id);\n        }\n\n        None\n    }\n\n    pub(crate) fn is_fragment_data(&self) -> bool {\n        if self.has_field(FWPS_METADATA_FIELD_FRAGMENT_DATA) {\n            return self.fragment_metadata.fragment_offset != 0;\n        }\n\n        false\n    }\n\n    pub(crate) unsafe fn get_control_data(&self) -> Option<NonNull<[u8]>> {\n        if self.has_field(FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA) {\n            if self.control_data.is_null() || self.control_data_length == 0 {\n                return None;\n            }\n            let ptr = NonNull::new(self.control_data as *mut u8).unwrap();\n            let slice = NonNull::slice_from_raw_parts(ptr, self.control_data_length as usize);\n            return Some(slice);\n        }\n\n        None\n    }\n}\n\n#[allow(dead_code)]\n#[repr(C)]\nenum FwpsDiscardModule0 {\n    Network = 0,\n    Transport = 1,\n    General = 2,\n    Max = 3,\n}\n\n#[repr(C)]\nstruct FwpsDiscardMetadata0 {\n    discard_module: FwpsDiscardModule0,\n    discard_reason: u32,\n    filter_id: u64,\n}\n\n#[repr(C)]\nstruct FwpsInboundFragmentMetadata0 {\n    fragment_identification: u32,\n    fragment_offset: u16,\n    fragment_length: u32,\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/mod.rs",
    "content": "use core::ffi::c_void;\r\n\r\nuse crate::alloc::borrow::ToOwned;\r\nuse crate::driver::Driver;\r\nuse crate::ffi::FWPS_FILTER2;\r\nuse crate::filter_engine::transaction::Transaction;\r\nuse crate::{dbg, info};\r\nuse alloc::boxed::Box;\r\nuse alloc::string::String;\r\nuse alloc::{format, vec::Vec};\r\nuse windows_sys::Wdk::Foundation::DEVICE_OBJECT;\r\nuse windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE};\r\n\r\nuse self::callout::{Callout, FilterType};\r\nuse self::callout_data::CalloutData;\r\nuse self::classify::ClassifyOut;\r\nuse self::layer::IncomingValues;\r\nuse self::metadata::FwpsIncomingMetadataValues;\r\n\r\npub mod callout;\r\npub mod callout_data;\r\npub(crate) mod classify;\r\n#[allow(dead_code)]\r\npub mod ffi;\r\npub mod layer;\r\npub(crate) mod metadata;\r\npub mod net_buffer;\r\npub mod packet;\r\npub mod stream_data;\r\npub mod transaction;\r\n// Helper functions for ALE Readirect layers. Not needed for the current implementation.\r\n// pub mod connect_request;\r\n\r\npub struct FilterEngine {\r\n    device_object: *mut DEVICE_OBJECT,\r\n    handle: HANDLE,\r\n    sublayer_guid: u128,\r\n    committed: bool,\r\n    callouts: Option<Vec<Box<Callout>>>,\r\n}\r\n\r\nimpl FilterEngine {\r\n    pub fn new(driver: &Driver, layer_guid: u128) -> Result<Self, String> {\r\n        let filter_engine_handle: HANDLE;\r\n        match ffi::create_filter_engine() {\r\n            Ok(handle) => {\r\n                filter_engine_handle = handle;\r\n            }\r\n            Err(code) => {\r\n                return Err(format!(\"failed to initialize filter engine {}\", code).to_owned());\r\n            }\r\n        }\r\n        Ok(Self {\r\n            device_object: driver.get_device_object(),\r\n            handle: filter_engine_handle,\r\n            sublayer_guid: layer_guid,\r\n            committed: false,\r\n            callouts: None,\r\n        })\r\n    }\r\n\r\n    pub fn commit(&mut self, callouts: Vec<Callout>) -> Result<(), String> {\r\n        {\r\n            // Begin write transaction. This is also a lock guard.\r\n            let mut filter_engine = match Transaction::begin_write(self) {\r\n                Ok(transaction) => transaction,\r\n                Err(err) => {\r\n                    return Err(err);\r\n                }\r\n            };\r\n\r\n            if let Err(err) = filter_engine.register_sublayer() {\r\n                return Err(format!(\"filter_engine: {}\", err));\r\n            }\r\n\r\n            dbg!(\"Callouts count: {}\", callouts.len());\r\n            let mut boxed_callouts = Vec::new();\r\n            // Register all callouts\r\n            for callout in callouts {\r\n                let mut callout = Box::new(callout);\r\n                callout.address = callout.as_ref() as *const Callout as u64;\r\n\r\n                if let Err(err) = callout.register_callout(\r\n                    filter_engine.handle,\r\n                    filter_engine.device_object,\r\n                    catch_all_callout,\r\n                ) {\r\n                    // This will destroy the callout structs.\r\n                    return Err(err);\r\n                }\r\n                if let Err(err) =\r\n                    callout.register_filter(filter_engine.handle, filter_engine.sublayer_guid)\r\n                {\r\n                    // This will destroy the callout structs.\r\n                    return Err(err);\r\n                }\r\n                dbg!(\r\n                    \"registering callout: {} -> {}\",\r\n                    callout.name,\r\n                    callout.filter_id\r\n                );\r\n                boxed_callouts.push(callout)\r\n            }\r\n            if let Some(callouts) = &mut filter_engine.callouts {\r\n                callouts.append(&mut boxed_callouts);\r\n            } else {\r\n                filter_engine.callouts = Some(boxed_callouts);\r\n            }\r\n\r\n            filter_engine.commit()?\r\n        }\r\n        self.committed = true;\r\n        info!(\"transaction committed\");\r\n\r\n        return Ok(());\r\n    }\r\n\r\n    pub fn reset_all_filters(&mut self) -> Result<(), String> {\r\n        // Begin to write transaction. This is also a lock guard. It will abort if transaction is not committed.\r\n        let mut filter_engine = match Transaction::begin_write(self) {\r\n            Ok(transaction) => transaction,\r\n            Err(err) => {\r\n                return Err(err);\r\n            }\r\n        };\r\n        let filter_engine_handle = filter_engine.handle;\r\n        let sublayer_guid = filter_engine.sublayer_guid;\r\n        if let Some(callouts) = &mut filter_engine.callouts {\r\n            for callout in callouts {\r\n                if let FilterType::Resettable = callout.filter_type {\r\n                    if callout.filter_id != 0 {\r\n                        // Remove old filter.\r\n                        if let Err(err) =\r\n                            ffi::unregister_filter(filter_engine_handle, callout.filter_id)\r\n                        {\r\n                            return Err(format!(\"filter_engine: {}\", err));\r\n                        }\r\n                        callout.filter_id = 0;\r\n                    }\r\n                    // Create new filter.\r\n                    if let Err(err) = callout.register_filter(filter_engine_handle, sublayer_guid) {\r\n                        return Err(format!(\"filter_engine: {}\", err));\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        // Commit transaction.\r\n        filter_engine.commit()?;\r\n        return Ok(());\r\n    }\r\n\r\n    fn register_sublayer(&self) -> Result<(), String> {\r\n        let result = ffi::register_sublayer(\r\n            self.handle,\r\n            \"PortmasterSublayer\",\r\n            \"The Portmaster sublayer holds all it's filters.\",\r\n            self.sublayer_guid,\r\n        );\r\n        if let Err(code) = result {\r\n            return Err(format!(\"failed to register sublayer: {}\", code));\r\n        }\r\n\r\n        return Ok(());\r\n    }\r\n}\r\n\r\nimpl Drop for FilterEngine {\r\n    fn drop(&mut self) {\r\n        dbg!(\"Unregistering callouts\");\r\n        if let Some(callouts) = &self.callouts {\r\n            for callout in callouts {\r\n                if callout.registered {\r\n                    if let Err(code) = ffi::unregister_callout(callout.id) {\r\n                        dbg!(\"failed to unregister callout: {}\", code);\r\n                    }\r\n                    if callout.filter_id != 0 {\r\n                        if let Err(code) = ffi::unregister_filter(self.handle, callout.filter_id) {\r\n                            dbg!(\"failed to unregister filter: {}\", code)\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        if self.committed {\r\n            if let Err(code) = ffi::unregister_sublayer(self.handle, self.sublayer_guid) {\r\n                dbg!(\"Failed to unregister sublayer: {}\", code);\r\n            }\r\n        }\r\n\r\n        if !self.handle.is_null() && self.handle != INVALID_HANDLE_VALUE {\r\n            _ = ffi::filter_engine_close(self.handle);\r\n        }\r\n    }\r\n}\r\n\r\n#[no_mangle]\r\nunsafe extern \"C\" fn catch_all_callout(\r\n    fixed_values: *const IncomingValues,\r\n    meta_values: *const FwpsIncomingMetadataValues,\r\n    layer_data: *mut c_void,\r\n    _context: *mut c_void,\r\n    filter: *const FWPS_FILTER2,\r\n    _flow_context: u64,\r\n    classify_out: *mut ClassifyOut,\r\n) {\r\n    let filter = &(*filter);\r\n    // Filter context is the address of the callout.\r\n    let callout = filter.context as *mut Callout;\r\n\r\n    if let Some(callout) = callout.as_ref() {\r\n        // Setup callout data.\r\n        let array = core::slice::from_raw_parts(\r\n            (*fixed_values).incoming_value_array,\r\n            (*fixed_values).value_count as usize,\r\n        );\r\n        let data = CalloutData {\r\n            layer: callout.layer,\r\n            callout_id: filter.context as usize,\r\n            values: array,\r\n            metadata: meta_values,\r\n            classify_out,\r\n            layer_data,\r\n        };\r\n        // Call the defined function.\r\n        (callout.callout_fn)(data);\r\n    }\r\n}\r\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/net_buffer.rs",
    "content": "use core::mem::MaybeUninit;\n\nuse alloc::{\n    string::{String, ToString},\n    vec::Vec,\n};\nuse windows_sys::Wdk::System::SystemServices::{\n    IoAllocateMdl, IoFreeMdl, MmBuildMdlForNonPagedPool,\n};\n\nuse crate::{\n    allocator::POOL_TAG,\n    ffi::{\n        FwpsAllocateNetBufferAndNetBufferList0, FwpsFreeNetBufferList0,\n        NdisAdvanceNetBufferDataStart, NdisAllocateNetBufferListPool, NdisFreeNetBufferListPool,\n        NdisGetDataBuffer, NdisRetreatNetBufferDataStart, NDIS_HANDLE, NDIS_OBJECT_TYPE_DEFAULT,\n        NET_BUFFER_LIST, NET_BUFFER_LIST_POOL_PARAMETERS,\n        NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1,\n    },\n    utils::check_ntstatus,\n};\n\npub struct NetBufferList {\n    pub(crate) nbl: *mut NET_BUFFER_LIST,\n    data: Option<Vec<u8>>,\n    advance_on_drop: Option<u32>,\n}\n\nimpl NetBufferList {\n    pub fn new(nbl: *mut NET_BUFFER_LIST) -> NetBufferList {\n        NetBufferList {\n            nbl,\n            data: None,\n            advance_on_drop: None,\n        }\n    }\n\n    pub fn iter(&self) -> NetBufferListIter {\n        NetBufferListIter(self.nbl)\n    }\n\n    pub fn read_bytes(&self, buffer: &mut [u8]) -> Result<(), ()> {\n        unsafe {\n            let Some(nbl) = self.nbl.as_ref() else {\n                return Err(());\n            };\n            let nb = nbl.Header.first_net_buffer;\n            if let Some(nb) = nb.as_ref() {\n                let data_length = nb.nbSize.DataLength;\n                if data_length == 0 {\n                    return Err(());\n                }\n\n                if buffer.len() > data_length as usize {\n                    return Err(());\n                }\n\n                let mut ptr =\n                    NdisGetDataBuffer(nb, buffer.len() as u32, core::ptr::null_mut(), 1, 0);\n                if !ptr.is_null() {\n                    buffer.copy_from_slice(core::slice::from_raw_parts(ptr, buffer.len()));\n                    return Ok(());\n                }\n\n                ptr = NdisGetDataBuffer(nb, buffer.len() as u32, buffer.as_mut_ptr(), 1, 0);\n                if !ptr.is_null() {\n                    return Ok(());\n                }\n            }\n        }\n        return Err(());\n    }\n\n    pub fn clone(&self, net_allocator: &NetworkAllocator) -> Result<NetBufferList, String> {\n        unsafe {\n            let Some(nbl) = self.nbl.as_ref() else {\n                return Err(\"net buffer list is null\".to_string());\n            };\n\n            let nb = nbl.Header.first_net_buffer;\n            if let Some(nb) = nb.as_ref() {\n                let data_length = nb.nbSize.DataLength;\n                if data_length == 0 {\n                    return Err(\"can't clone empty packet\".to_string());\n                }\n\n                // Allocate space in buffer, if buffer is too small.\n                let mut buffer = alloc::vec![0_u8; data_length as usize];\n\n                let buffer_ptr = buffer.as_mut_ptr();\n\n                // Two options returns a pointer to the raw packet buffer,\n                // or copies the data to the supplied buffer\n                // and returns a pointer to the supplied buffer.\n                let ptr = NdisGetDataBuffer(nb, data_length, buffer_ptr, 1, 0);\n\n                if ptr.is_null() {\n                    return Err(\"failed to copy packet buffer\".to_string());\n                }\n\n                // If the pointers differ the data is not in the correct place.\n                if ptr != buffer_ptr {\n                    buffer.copy_from_slice(core::slice::from_raw_parts(ptr, data_length as usize));\n                }\n\n                let new_nbl = net_allocator.wrap_packet_in_nbl(&buffer)?;\n\n                return Ok(NetBufferList {\n                    nbl: new_nbl,\n                    data: Some(buffer),\n                    advance_on_drop: None,\n                });\n            } else {\n                return Err(\"net buffer is null\".to_string());\n            }\n        }\n    }\n\n    pub fn get_data_mut(&mut self) -> Option<&mut [u8]> {\n        if let Some(data) = &mut self.data {\n            return Some(data.as_mut_slice());\n        }\n        return None;\n    }\n\n    pub fn get_data(&self) -> Option<&[u8]> {\n        if let Some(data) = &self.data {\n            return Some(data.as_slice());\n        }\n        return None;\n    }\n\n    pub fn get_data_length(&self) -> u32 {\n        unsafe {\n            if let Some(nbl) = self.nbl.as_ref() {\n                let mut nb = nbl.Header.first_net_buffer;\n                let mut data_length = 0;\n                while !nb.is_null() {\n                    let mut next = core::ptr::null_mut();\n                    if let Some(nb) = nb.as_ref() {\n                        data_length += nb.nbSize.DataLength;\n                        next = nb.Next;\n                    }\n                    nb = next;\n                }\n\n                data_length\n            } else {\n                0\n            }\n        }\n    }\n\n    /// Retreats the mnl of the buffer. Does not auto advance multiple retreats.\n    pub fn retreat(&mut self, size: u32, auto_advance: bool) {\n        unsafe {\n            if let Some(nbl) = self.nbl.as_mut() {\n                if let Some(nb) = nbl.Header.first_net_buffer.as_mut() {\n                    NdisRetreatNetBufferDataStart(nb as _, size, 0, core::ptr::null_mut());\n                    if auto_advance {\n                        self.advance_on_drop = Some(size);\n                    }\n                }\n            }\n        }\n    }\n\n    /// Advances the MDL of the buffer.\n    pub fn advance(&mut self, size: u32) {\n        unsafe {\n            if let Some(nbl) = self.nbl.as_mut() {\n                if let Some(nb) = nbl.Header.first_net_buffer.as_mut() {\n                    NdisAdvanceNetBufferDataStart(nb as _, size, false, core::ptr::null_mut());\n                }\n            }\n        }\n    }\n}\n\nimpl Drop for NetBufferList {\n    fn drop(&mut self) {\n        if let Some(advance_amount) = self.advance_on_drop {\n            self.advance(advance_amount);\n        }\n        if self.data.is_some() {\n            NetworkAllocator::free_net_buffer(self.nbl);\n        }\n    }\n}\n\npub struct NetBufferListIter(*mut NET_BUFFER_LIST);\n\nimpl NetBufferListIter {\n    pub fn new(nbl: *mut NET_BUFFER_LIST) -> Self {\n        Self(nbl)\n    }\n}\n\nimpl Iterator for NetBufferListIter {\n    type Item = NetBufferList;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        unsafe {\n            if let Some(nbl) = self.0.as_mut() {\n                self.0 = nbl.Header.next as _;\n                return Some(NetBufferList {\n                    nbl,\n                    data: None,\n                    advance_on_drop: None,\n                });\n            }\n            None\n        }\n    }\n}\n\npub fn read_packet_partial(nbl: *mut NET_BUFFER_LIST, buffer: &mut [u8]) -> Result<(), ()> {\n    unsafe {\n        let Some(nbl) = nbl.as_ref() else {\n            return Err(());\n        };\n        let nb = nbl.Header.first_net_buffer;\n        if let Some(nb) = nb.as_ref() {\n            let data_length = nb.nbSize.DataLength;\n            if data_length == 0 {\n                return Err(());\n            }\n\n            if buffer.len() > data_length as usize {\n                return Err(());\n            }\n\n            let ptr = NdisGetDataBuffer(nb, buffer.len() as u32, buffer.as_mut_ptr(), 1, 0);\n            if !ptr.is_null() {\n                return Ok(());\n            }\n        }\n    }\n    return Err(());\n}\n\npub struct RetreatGuard {\n    size: u32,\n    nbl: *mut NET_BUFFER_LIST,\n}\n\nimpl Drop for RetreatGuard {\n    fn drop(&mut self) {\n        NetworkAllocator::advance_net_buffer(self.nbl, self.size);\n    }\n}\n\npub struct NetworkAllocator {\n    pool_handle: NDIS_HANDLE,\n}\n\nimpl NetworkAllocator {\n    pub fn new() -> Self {\n        unsafe {\n            let mut params: NET_BUFFER_LIST_POOL_PARAMETERS = MaybeUninit::zeroed().assume_init();\n            params.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;\n            params.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;\n            params.Header.Size = core::mem::size_of::<NET_BUFFER_LIST_POOL_PARAMETERS>() as u16;\n            params.fAllocateNetBuffer = true;\n            params.PoolTag = POOL_TAG;\n            params.DataSize = 0;\n\n            let pool_handle = NdisAllocateNetBufferListPool(core::ptr::null_mut(), &params);\n            Self { pool_handle }\n        }\n    }\n\n    pub fn wrap_packet_in_nbl(&self, packet_data: &[u8]) -> Result<*mut NET_BUFFER_LIST, String> {\n        if self.pool_handle.is_null() {\n            return Err(\"allocator not initialized\".to_string());\n        }\n        unsafe {\n            // Create MDL struct that will hold the buffer.\n            let mdl = IoAllocateMdl(\n                packet_data.as_ptr() as _,\n                packet_data.len() as u32,\n                0,\n                0,\n                core::ptr::null_mut(),\n            );\n            if mdl.is_null() {\n                return Err(\"failed to allocate mdl\".to_string());\n            }\n\n            // Build mdl with packet_data buffer.\n            MmBuildMdlForNonPagedPool(mdl);\n\n            // Initialize NBL structure.\n            let mut nbl = core::ptr::null_mut();\n            let status = FwpsAllocateNetBufferAndNetBufferList0(\n                self.pool_handle,\n                0,\n                0,\n                mdl,\n                0,\n                packet_data.len() as u64,\n                &mut nbl,\n            );\n            if let Err(err) = check_ntstatus(status) {\n                IoFreeMdl(mdl);\n                return Err(err);\n            }\n            return Ok(nbl);\n        }\n    }\n\n    pub fn free_net_buffer(nbl: *mut NET_BUFFER_LIST) {\n        NetBufferListIter::new(nbl).for_each(|nbl| unsafe {\n            if let Some(nbl) = nbl.nbl.as_mut() {\n                if let Some(nb) = nbl.Header.first_net_buffer.as_mut() {\n                    IoFreeMdl(nb.MdlChain);\n                }\n                FwpsFreeNetBufferList0(nbl);\n            }\n        });\n    }\n\n    pub fn retreat_net_buffer(\n        nbl: *mut NET_BUFFER_LIST,\n        size: u32,\n        auto_advance: bool,\n    ) -> Option<RetreatGuard> {\n        unsafe {\n            if let Some(nbl) = nbl.as_mut() {\n                if let Some(nb) = nbl.Header.first_net_buffer.as_mut() {\n                    NdisRetreatNetBufferDataStart(nb as _, size, 0, core::ptr::null_mut());\n                    if auto_advance {\n                        return Some(RetreatGuard { size, nbl });\n                    }\n                }\n            }\n        }\n\n        return None;\n    }\n    pub fn advance_net_buffer(nbl: *mut NET_BUFFER_LIST, size: u32) {\n        unsafe {\n            if let Some(nbl) = nbl.as_mut() {\n                if let Some(nb) = nbl.Header.first_net_buffer.as_mut() {\n                    NdisAdvanceNetBufferDataStart(nb as _, size, false, core::ptr::null_mut());\n                }\n            }\n        }\n    }\n}\n\nimpl Drop for NetworkAllocator {\n    fn drop(&mut self) {\n        unsafe {\n            if !self.pool_handle.is_null() {\n                NdisFreeNetBufferListPool(self.pool_handle);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/packet.rs",
    "content": "use alloc::{\n    boxed::Box,\n    string::{String, ToString},\n};\nuse core::{ffi::c_void, mem::MaybeUninit};\nuse windows_sys::Win32::{\n    Foundation::{HANDLE, INVALID_HANDLE_VALUE},\n    Networking::WinSock::{AF_INET, AF_INET6, AF_UNSPEC, SCOPE_ID},\n    System::Kernel::UNSPECIFIED_COMPARTMENT_ID,\n};\n\nuse crate::{\n    ffi::{\n        FwpsInjectNetworkReceiveAsync0, FwpsInjectNetworkSendAsync0,\n        FwpsInjectTransportReceiveAsync0, FwpsInjectTransportSendAsync1,\n        FwpsInjectionHandleCreate0, FwpsInjectionHandleDestroy0, FwpsQueryPacketInjectionState0,\n        FWPS_INJECTION_TYPE_NETWORK, FWPS_INJECTION_TYPE_TRANSPORT, FWPS_PACKET_INJECTION_STATE,\n        FWPS_TRANSPORT_SEND_PARAMS1, NET_BUFFER_LIST,\n    },\n    utils::check_ntstatus,\n};\n\nuse super::{callout_data::CalloutData, net_buffer::NetBufferList};\n\npub struct TransportPacketList {\n    ipv6: bool,\n    pub net_buffer_list: NetBufferList,\n    remote_ip: [u8; 16],\n    endpoint_handle: u64,\n    remote_scope_id: SCOPE_ID,\n    // Owned copy of the WFP control data. The original WFP pointer is only\n    // valid during the ALE classify callback; the bytes are copied here so they outlive it.\n    control_data: Option<Box<[u8]>>,\n    inbound: bool,\n    interface_index: u32,\n    sub_interface_index: u32,\n    // send_params and remote_ip must outlive inject_packet_list_transport\n    // because FwpsInjectTransportSendAsync1 may read them after the function returns.\n    // Storing send_params here ensures it lives on the heap inside Box<TransportPacketList>\n    // until the WFP completion callback (free_transport_packet) drops it.\n    send_params: FWPS_TRANSPORT_SEND_PARAMS1,\n}\n\npub struct InjectInfo {\n    pub ipv6: bool,\n    pub inbound: bool,\n    pub loopback: bool,\n    pub interface_index: u32,\n    pub sub_interface_index: u32,\n}\n\npub struct Injector {\n    transport_inject_handle: HANDLE,\n    packet_inject_handle_v4: HANDLE,\n    packet_inject_handle_v6: HANDLE,\n}\n\n// TODO: Implement custom allocator for the packet buffers for reusing memory and reducing allocations. This should improve latency.\nimpl Injector {\n    pub fn new() -> Self {\n        let mut transport_inject_handle: HANDLE = INVALID_HANDLE_VALUE;\n        let mut packet_inject_handle_v4: HANDLE = INVALID_HANDLE_VALUE;\n        let mut packet_inject_handle_v6: HANDLE = INVALID_HANDLE_VALUE;\n        unsafe {\n            let status = FwpsInjectionHandleCreate0(\n                AF_UNSPEC,\n                FWPS_INJECTION_TYPE_TRANSPORT,\n                &mut transport_inject_handle,\n            );\n            if let Err(err) = check_ntstatus(status) {\n                crate::err!(\"error allocating transport inject handle: {}\", err);\n            }\n            let status = FwpsInjectionHandleCreate0(\n                AF_INET,\n                FWPS_INJECTION_TYPE_NETWORK,\n                &mut packet_inject_handle_v4,\n            );\n\n            if let Err(err) = check_ntstatus(status) {\n                crate::err!(\"error allocating network inject handle: {}\", err);\n            }\n            let status = FwpsInjectionHandleCreate0(\n                AF_INET6,\n                FWPS_INJECTION_TYPE_NETWORK,\n                &mut packet_inject_handle_v6,\n            );\n\n            if let Err(err) = check_ntstatus(status) {\n                crate::err!(\"error allocating network inject handle: {}\", err);\n            }\n        }\n        Self {\n            transport_inject_handle,\n            packet_inject_handle_v4,\n            packet_inject_handle_v6,\n        }\n    }\n\n    // TODO: pick a better name\n    pub fn from_ale_callout(\n        ipv6: bool,\n        callout_data: &CalloutData,\n        net_buffer_list: NetBufferList,\n        remote_ip_slice: &[u8],\n        inbound: bool,\n        interface_index: u32,\n        sub_interface_index: u32,\n    ) -> TransportPacketList {\n        let mut control_data: Option<Box<[u8]>> = None;\n        if let Some(cd) = callout_data.get_control_data() {\n            // Copy the bytes while the WFP pointer is still valid (we are inside the callout).\n            control_data = Some(unsafe { cd.as_ref() }.to_vec().into_boxed_slice());\n        }\n        let mut remote_ip: [u8; 16] = [0; 16];\n        if ipv6 {\n            remote_ip[0..16].copy_from_slice(remote_ip_slice);\n        } else {\n            remote_ip[0..4].copy_from_slice(remote_ip_slice);\n        }\n\n        TransportPacketList {\n            ipv6,\n            net_buffer_list,\n            remote_ip,\n            endpoint_handle: callout_data.get_transport_endpoint_handle().unwrap_or(0),\n            remote_scope_id: callout_data\n                .get_remote_scope_id()\n                .unwrap_or(unsafe { MaybeUninit::zeroed().assume_init() }),\n            control_data,\n            inbound,\n            interface_index,\n            sub_interface_index,\n            // Populated with valid pointers in inject_packet_list_transport after boxing.\n            send_params: unsafe { MaybeUninit::zeroed().assume_init() },\n        }\n    }\n\n    // TODO: pick a better name. This is not transport\n    pub fn inject_packet_list_transport(\n        &self,\n        packet_list: TransportPacketList,\n    ) -> Result<(), String> {\n        if self.transport_inject_handle == INVALID_HANDLE_VALUE {\n            return Err(\"failed to inject packet: invalid handle value\".to_string());\n        }\n        // Box the entire packet_list so that remote_ip and send_params\n        // are heap-allocated. Their addresses remain stable until free_transport_packet\n        // drops the Box after WFP calls the completion callback.\n        let mut boxed = Box::new(packet_list);\n        let raw_nbl = boxed.net_buffer_list.nbl;\n\n        unsafe {\n            // Populate send_params with pointers into the boxed struct.\n            // These addresses are stable because the Box will not move until freed.\n            let mut control_data_length = 0;\n            let control_data: *mut c_void = match &boxed.control_data {\n                Some(cd) => {\n                    control_data_length = cd.len();\n                    cd.as_ptr() as *mut c_void\n                }\n                None => core::ptr::null_mut(),\n            };\n            boxed.send_params = FWPS_TRANSPORT_SEND_PARAMS1 {\n                remote_address: boxed.remote_ip.as_ptr(),\n                remote_scope_id: boxed.remote_scope_id,\n                control_data,\n                control_data_length: control_data_length as u32,\n                header_include_header: core::ptr::null_mut(),\n                header_include_header_length: 0,\n            };\n\n            let address_family = if boxed.ipv6 { AF_INET6 } else { AF_INET };\n            let raw_ptr = Box::into_raw(boxed);\n\n            // Inject. Context is *mut TransportPacketList; freed by free_transport_packet.\n            let status = if (*raw_ptr).inbound {\n                FwpsInjectTransportReceiveAsync0(\n                    self.transport_inject_handle,\n                    core::ptr::null_mut(),\n                    core::ptr::null_mut(),\n                    0,\n                    address_family,\n                    UNSPECIFIED_COMPARTMENT_ID,\n                    (*raw_ptr).interface_index,\n                    (*raw_ptr).sub_interface_index,\n                    raw_nbl,\n                    free_transport_packet,\n                    raw_ptr as _,\n                )\n            } else {\n                FwpsInjectTransportSendAsync1(\n                    self.transport_inject_handle,\n                    core::ptr::null_mut(),\n                    (*raw_ptr).endpoint_handle,\n                    0,\n                    &mut (*raw_ptr).send_params,\n                    address_family,\n                    UNSPECIFIED_COMPARTMENT_ID,\n                    raw_nbl,\n                    free_transport_packet,\n                    raw_ptr as _,\n                )\n            };\n            // Check for success\n            if let Err(err) = check_ntstatus(status) {\n                _ = Box::from_raw(raw_ptr);\n                return Err(err);\n            }\n        }\n\n        return Ok(());\n    }\n\n    pub fn inject_net_buffer_list(\n        &self,\n        net_buffer_list: NetBufferList,\n        inject_info: InjectInfo,\n    ) -> Result<(), String> {\n        if self.packet_inject_handle_v4 == INVALID_HANDLE_VALUE {\n            return Err(\"failed to inject packet: invalid handle value\".to_string());\n        }\n        // Escape the stack, so the data can be freed after inject is complete.\n        let packet_boxed = Box::new(net_buffer_list);\n        let nbl = packet_boxed.nbl;\n        let packet_pointer = Box::into_raw(packet_boxed);\n\n        let inject_handle = if inject_info.ipv6 {\n            self.packet_inject_handle_v6\n        } else {\n            self.packet_inject_handle_v4\n        };\n\n        let status = if inject_info.inbound && !inject_info.loopback {\n            // Inject inbound.\n            unsafe {\n                FwpsInjectNetworkReceiveAsync0(\n                    inject_handle,\n                    core::ptr::null_mut(),\n                    0,\n                    UNSPECIFIED_COMPARTMENT_ID,\n                    inject_info.interface_index,\n                    inject_info.sub_interface_index,\n                    nbl,\n                    free_packet,\n                    (packet_pointer as *mut NetBufferList) as _,\n                )\n            }\n        } else {\n            // Inject outbound.\n            unsafe {\n                FwpsInjectNetworkSendAsync0(\n                    inject_handle,\n                    core::ptr::null_mut(),\n                    0,\n                    UNSPECIFIED_COMPARTMENT_ID,\n                    nbl,\n                    free_packet,\n                    (packet_pointer as *mut NetBufferList) as _,\n                )\n            }\n        };\n\n        // Check for error.\n        if let Err(err) = check_ntstatus(status) {\n            unsafe {\n                // Get back ownership for data.\n                _ = Box::from_raw(packet_pointer);\n            }\n            return Err(err);\n        }\n\n        return Ok(());\n    }\n\n    pub fn was_network_packet_injected_by_self(\n        &self,\n        nbl: *const NET_BUFFER_LIST,\n        ipv6: bool,\n    ) -> bool {\n        let inject_handle = if ipv6 {\n            self.packet_inject_handle_v6\n        } else {\n            self.packet_inject_handle_v4\n        };\n        if inject_handle == INVALID_HANDLE_VALUE || inject_handle.is_null() {\n            return false;\n        }\n\n        unsafe {\n            let state = FwpsQueryPacketInjectionState0(inject_handle, nbl, core::ptr::null_mut());\n\n            match state {\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_NOT_INJECTED => false,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_INJECTED_BY_SELF => true,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_INJECTED_BY_OTHER => false,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF => true,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_INJECTION_STATE_MAX => false,\n            }\n        }\n    }\n\n    pub fn was_network_packet_injected_by_self_ale(&self, nbl: *const NET_BUFFER_LIST) -> bool {\n        unsafe {\n            let state = FwpsQueryPacketInjectionState0(\n                self.transport_inject_handle,\n                nbl,\n                core::ptr::null_mut(),\n            );\n\n            match state {\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_NOT_INJECTED => false,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_INJECTED_BY_SELF => true,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_INJECTED_BY_OTHER => false,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF => true,\n                FWPS_PACKET_INJECTION_STATE::FWPS_PACKET_INJECTION_STATE_MAX => false,\n            }\n        }\n    }\n}\n\nimpl Drop for Injector {\n    fn drop(&mut self) {\n        unsafe {\n            if self.transport_inject_handle != INVALID_HANDLE_VALUE\n                && !self.transport_inject_handle.is_null()\n            {\n                FwpsInjectionHandleDestroy0(self.transport_inject_handle);\n                self.transport_inject_handle = INVALID_HANDLE_VALUE;\n            }\n            if self.packet_inject_handle_v4 != INVALID_HANDLE_VALUE\n                && !self.packet_inject_handle_v4.is_null()\n            {\n                FwpsInjectionHandleDestroy0(self.packet_inject_handle_v4);\n                self.packet_inject_handle_v4 = INVALID_HANDLE_VALUE;\n            }\n            if self.packet_inject_handle_v6 != INVALID_HANDLE_VALUE\n                && !self.packet_inject_handle_v6.is_null()\n            {\n                FwpsInjectionHandleDestroy0(self.packet_inject_handle_v6);\n                self.packet_inject_handle_v6 = INVALID_HANDLE_VALUE;\n            }\n        }\n    }\n}\n\nunsafe extern \"C\" fn free_packet(\n    context: *mut c_void,\n    net_buffer_list: *mut NET_BUFFER_LIST,\n    _dispatch_level: bool,\n) {\n    if let Some(nbl) = net_buffer_list.as_ref() {\n        if let Err(err) = check_ntstatus(nbl.Status) {\n            crate::err!(\"inject status: {}\", err);\n        } else {\n            crate::dbg!(\"inject status: Ok\");\n        }\n    }\n    _ = Box::from_raw(context as *mut NetBufferList);\n}\n\n/// Completion callback for transport inject paths (both inbound and outbound).\n/// The context is a `Box<TransportPacketList>` cast to `*mut c_void`.\n/// Dropping it also correctly drops the inner `NetBufferList`.\nunsafe extern \"C\" fn free_transport_packet(\n    context: *mut c_void,\n    net_buffer_list: *mut NET_BUFFER_LIST,\n    _dispatch_level: bool,\n) {\n    if let Some(nbl) = net_buffer_list.as_ref() {\n        if let Err(err) = check_ntstatus(nbl.Status) {\n            crate::err!(\"inject status: {}\", err);\n        } else {\n            crate::dbg!(\"inject status: Ok\");\n        }\n    }\n    _ = Box::from_raw(context as *mut TransportPacketList);\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/stream_data.rs",
    "content": "use crate::ffi::{NET_BUFFER, NET_BUFFER_LIST};\nuse windows_sys::Wdk::Foundation::MDL;\n\nconst FWPS_STREAM_FLAG_RECEIVE: u32 = 0x00000001;\n\n#[repr(C)]\npub enum StreamActionType {\n    None,\n    NeedMoreData,\n    DropConnection,\n    Defer,\n    AllowConnection,\n    TypeMax,\n}\n\n#[repr(C)]\npub struct StreamCalloutIoPacket {\n    stream_data: *mut StreamData,\n    missed_bytes: usize,\n    count_bytes_required: usize,\n    count_bytes_enforced: usize,\n    stream_action: StreamActionType,\n}\n\n#[repr(C)]\npub struct StreamDataOffset {\n    // NET_BUFFER_LIST in which offset lies.\n    net_buffer_list: *mut NET_BUFFER_LIST,\n    // NET_BUFFER in which offset lies.\n    net_buffer: *mut NET_BUFFER,\n    // MDL in which offset lies.\n    mdl: *mut MDL,\n    // Byte offset from the beginning of the MDL in which data lies.\n    mdl_offset: u32,\n    // Offset relative to the DataOffset of the NET_BUFFER.\n    net_buffer_offset: u32,\n    // Offset from the beginning of the entire stream buffer.\n    stream_data_offset: usize,\n}\n\n#[repr(C)]\npub struct StreamData {\n    flags: u32,\n    data_offset: StreamDataOffset,\n    data_length: usize,\n    net_buffer_list_chain: *mut NET_BUFFER_LIST,\n}\n\nimpl StreamCalloutIoPacket {\n    pub fn get_data_len(&self) -> usize {\n        unsafe {\n            if let Some(stream_data) = self.stream_data.as_ref() {\n                return stream_data.data_length;\n            }\n        }\n        return 0;\n    }\n\n    pub fn is_receive(&self) -> bool {\n        unsafe {\n            if let Some(stream_data) = self.stream_data.as_ref() {\n                return stream_data.flags & FWPS_STREAM_FLAG_RECEIVE > 0;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/filter_engine/transaction.rs",
    "content": "use core::ops::{Deref, DerefMut};\r\n\r\nuse super::{ffi, FilterEngine};\r\nuse alloc::{format, string::String};\r\nuse windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::FWPM_TXN_READ_ONLY;\r\n\r\n/// Transaction guard for Filter Engine. Internally useses a lock. DO NOT USE WITH OTHER LOCKS.\r\npub(super) struct Transaction<'a> {\r\n    filter_engine: &'a mut FilterEngine,\r\n    committed: bool,\r\n}\r\n\r\nimpl<'a> Transaction<'a> {\r\n    fn begin(filter_engine: &'a mut FilterEngine, flags: u32) -> Result<Self, String> {\r\n        if let Err(code) = ffi::filter_engine_transaction_begin(filter_engine.handle, flags) {\r\n            return Err(format!(\r\n                \"filter-engine: failed to begin transaction: {}\",\r\n                code\r\n            ));\r\n        }\r\n\r\n        Ok(Self {\r\n            filter_engine,\r\n            committed: false,\r\n        })\r\n    }\r\n\r\n    /// Creates a read only guard for filter engine transaction.\r\n    #[allow(dead_code)]\r\n    pub(super) fn begin_read(filter_engine: &'a mut FilterEngine) -> Result<Self, String> {\r\n        return Self::begin(filter_engine, FWPM_TXN_READ_ONLY);\r\n    }\r\n\r\n    /// Creates a read/write guard for filter engine transaction.\r\n    /// Note! If another transaction is already in progress, it will return an error STATUS_FWP_TXN_IN_PROGRESS. \r\n    pub(super) fn begin_write(filter_engine: &'a mut FilterEngine) -> Result<Self, String> {\r\n        return Self::begin(filter_engine, 0);\r\n    }\r\n\r\n    /// Applying all the changes and releases the lock.\r\n    pub(super) fn commit(&mut self) -> Result<(), String> {\r\n        if let Err(code) = ffi::filter_engine_transaction_commit(self.filter_engine.handle) {\r\n            return Err(format!(\r\n                \"filter-engine: failed to commit transaction: {}\",\r\n                code\r\n            ));\r\n        }\r\n        self.committed = true;\r\n\r\n        Ok(())\r\n    }\r\n}\r\n\r\nimpl<'a> Deref for Transaction<'a> {\r\n    type Target = FilterEngine;\r\n\r\n    fn deref(&self) -> &Self::Target {\r\n        self.filter_engine\r\n    }\r\n}\r\n\r\nimpl<'a> DerefMut for Transaction<'a> {\r\n    fn deref_mut(&mut self) -> &mut Self::Target {\r\n        self.filter_engine\r\n    }\r\n}\r\n\r\nimpl<'a> Drop for Transaction<'a> {\r\n    /// Releases the lock of transaction was not committed.\r\n    fn drop(&mut self) {\r\n        if !self.committed {\r\n            _ = ffi::filter_engine_transaction_abort(self.filter_engine.handle);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "windows_kext/wdk/src/interface.rs",
    "content": "use crate::{\r\n    alloc::borrow::ToOwned,\r\n    driver::Driver,\r\n    ffi::{\r\n        pm_GetDeviceObject, pm_InitDriverObject, pm_WdfObjectGetTypedContextWorker,\r\n        WdfObjectAttributes, WdfObjectContextTypeInfo,\r\n    },\r\n    utils::check_ntstatus,\r\n};\r\nuse alloc::ffi::CString;\r\nuse alloc::format;\r\nuse alloc::string::String;\r\nuse widestring::U16CString;\r\nuse windows_sys::{\r\n    Wdk::{\r\n        Foundation::{DEVICE_OBJECT, DRIVER_OBJECT},\r\n        System::SystemServices::DbgPrint,\r\n    },\r\n    Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE, UNICODE_STRING},\r\n};\r\n\r\n// Debug\r\npub fn dbg_print(str: String) {\r\n    if let Ok(c_str) = CString::new(str) {\r\n        unsafe {\r\n            DbgPrint(c_str.as_ptr() as _);\r\n        }\r\n    }\r\n}\r\n\r\npub fn init_driver_object(\r\n    driver_object: *mut DRIVER_OBJECT,\r\n    registry_path: *mut UNICODE_STRING,\r\n    driver_name: &str,\r\n    object_attributes: *mut WdfObjectAttributes,\r\n) -> Result<Driver, String> {\r\n    let win_driver_path = format!(\"\\\\Device\\\\{}\", driver_name);\r\n    let dos_driver_path = format!(\"\\\\??\\\\{}\", driver_name);\r\n\r\n    let mut wdf_driver_handle = INVALID_HANDLE_VALUE;\r\n    let mut wdf_device_handle = INVALID_HANDLE_VALUE;\r\n\r\n    let Ok(win_driver) = U16CString::from_str(win_driver_path) else {\r\n        return Err(\"Invalid argument win_driver_path\".to_owned());\r\n    };\r\n    let Ok(dos_driver) = U16CString::from_str(dos_driver_path) else {\r\n        return Err(\"Invalid argument dos_driver_path\".to_owned());\r\n    };\r\n\r\n    unsafe {\r\n        let status = pm_InitDriverObject(\r\n            driver_object,\r\n            registry_path,\r\n            &mut wdf_driver_handle,\r\n            &mut wdf_device_handle,\r\n            win_driver.as_ptr(),\r\n            dos_driver.as_ptr(),\r\n            object_attributes,\r\n            empty_wdf_driver_unload,\r\n        );\r\n\r\n        check_ntstatus(status)?;\r\n\r\n        return Ok(Driver::new(\r\n            driver_object,\r\n            wdf_driver_handle,\r\n            wdf_device_handle,\r\n        ));\r\n    }\r\n}\r\n\r\npub fn get_device_context_from_wdf_device<T>(\r\n    wdf_device: HANDLE,\r\n    type_info: &'static WdfObjectContextTypeInfo,\r\n) -> *mut T {\r\n    unsafe {\r\n        return core::mem::transmute(pm_WdfObjectGetTypedContextWorker(wdf_device, type_info));\r\n    }\r\n}\r\n\r\npub(crate) fn wdf_device_wdm_get_device_object(wdf_device: HANDLE) -> *mut DEVICE_OBJECT {\r\n    unsafe {\r\n        return pm_GetDeviceObject(wdf_device);\r\n    }\r\n}\r\n\r\npub fn get_device_context_from_device_object<'a, T>(\r\n    device_object: &mut DEVICE_OBJECT,\r\n) -> Result<&'a mut T, ()> {\r\n    unsafe {\r\n        if let Some(context) = device_object.DeviceExtension.as_mut() {\r\n            return Ok(core::mem::transmute(context));\r\n        }\r\n    }\r\n\r\n    return Err(());\r\n}\r\n\r\n/// Empty unload event\r\nextern \"C\" fn empty_wdf_driver_unload(_driver: HANDLE) {}\r\n"
  },
  {
    "path": "windows_kext/wdk/src/ioqueue.rs",
    "content": "use core::{\n    cell::UnsafeCell,\n    ffi::c_void,\n    fmt::Display,\n    marker::PhantomData,\n    mem::MaybeUninit,\n    pin::Pin,\n    sync::atomic::{AtomicBool, Ordering},\n};\n\nuse crate::dbg;\nuse alloc::boxed::Box;\nuse ntstatus::ntstatus::NtStatus;\nuse windows_sys::{Wdk::Foundation::KQUEUE, Win32::System::Kernel::LIST_ENTRY};\n\n#[derive(Debug)]\npub enum Status {\n    Uninitialized,\n    Timeout,\n    UserAPC,\n    Abandoned,\n}\n\nimpl Display for Status {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Status::Uninitialized => write!(f, \"Uninitialized\"),\n            Status::Timeout => write!(f, \"Timeout\"),\n            Status::UserAPC => write!(f, \"UserAPC\"),\n            Status::Abandoned => write!(f, \"Abandoned\"),\n        }\n    }\n}\n\n#[repr(i8)]\npub enum KprocessorMode {\n    KernelMode = 0,\n    UserMode = 1,\n}\n\n// #[link(name = \"NtosKrnl\", kind = \"static\")]\nextern \"C\" {\n    /*\n    KeInitializeQueue\n        [out] Queue\n        Pointer to a KQUEUE structure for which the caller must provide resident storage in nonpaged pool. This structure is defined as follows:\n\n        [in] Count\n        The maximum number of threads for which the waits on the queue object can be satisfied concurrently. If this parameter is not supplied, the number of processors in the machine is used.\n    */\n    fn KeInitializeQueue(queue: *mut KQUEUE, count: u64);\n    /*\n    KeInsertQueue returns the previous signal state of the given Queue. If it was set to zero (that is, not signaled) before KeInsertQueue was called, KeInsertQueue returns zero, meaning that no entries were queued. If it was nonzero (signaled), KeInsertQueue returns the number of entries that were queued before KeInsertQueue was called.\n    */\n    fn KeInsertQueue(queue: *mut KQUEUE, list_entry: *mut c_void) -> i32;\n    /*\n    KeRemoveQueue returns one of the following:\n        A pointer to a dequeued entry from the given queue object, if one is available\n        STATUS_TIMEOUT, if the given Timeout interval expired before an entry became available\n        STATUS_USER_APC, if a user-mode APC was delivered in the context of the calling thread\n        STATUS_ABANDONED, if the queue has been run down\n    */\n    fn KeRemoveQueue(\n        queue: *mut KQUEUE,\n        waitmode: KprocessorMode,\n        timeout: *const i64,\n    ) -> *mut LIST_ENTRY;\n\n    // If the queue is empty, KeRundownQueue returns NULL; otherwise, it returns the address of the first entry in the queue.\n    fn KeRundownQueue(queue: *mut KQUEUE) -> *mut LIST_ENTRY;\n}\n\n#[repr(C)]\nstruct Entry<T> {\n    list: LIST_ENTRY, // Internal use\n    entry: T,\n}\n\npub struct IOQueue<T> {\n    // The address of the value should not change.\n    kernel_queue: Pin<Box<UnsafeCell<KQUEUE>>>,\n    initialized: AtomicBool,\n    _type: PhantomData<T>, // 0 size variable. Required for the generic to work properly. Compiler limitation.\n}\n\nunsafe impl<T> Sync for IOQueue<T> {}\n\nimpl<T> IOQueue<T> {\n    /// Make sure `rundown` is called on exit, if `drop()` is not called for queue.\n    pub fn new() -> Self {\n        unsafe {\n            let kernel_queue = Box::pin(UnsafeCell::new(MaybeUninit::zeroed().assume_init()));\n            KeInitializeQueue(kernel_queue.get(), 1);\n\n            Self {\n                kernel_queue,\n                initialized: AtomicBool::new(true),\n                _type: PhantomData,\n            }\n        }\n    }\n\n    /// Pushes new entry of any type.\n    pub fn push(&self, entry: T) -> Result<(), Status> {\n        let kqueue = self.kernel_queue.get();\n        // Allocate entry.\n        let list_entry = Box::new(Entry {\n            list: LIST_ENTRY {\n                Flink: core::ptr::null_mut(),\n                Blink: core::ptr::null_mut(),\n            },\n            entry,\n        });\n        let raw_ptr = Box::into_raw(list_entry);\n\n        // Check if initialized.\n        let result = if self.initialized.load(Ordering::Acquire) {\n            unsafe { KeInsertQueue(kqueue, raw_ptr as *mut c_void) }\n        } else {\n            -1\n        };\n        // There is no documentation that rundown queue will return error. This is here just for good measures.\n        // It is unlikely to happen and not critical.\n        if result >= 0 {\n            return Ok(());\n        }\n\n        _ = unsafe { Box::from_raw(raw_ptr) };\n        return Err(Status::Uninitialized);\n    }\n\n    /// Returns an Element or a status.\n    fn pop_internal(&self, timeout: *const i64) -> Result<T, Status> {\n        unsafe {\n            let kqueue = self.kernel_queue.get();\n            // Check if initialized.\n            if self.initialized.load(Ordering::Acquire) {\n                // Pop and check the return value.\n                let list_entry =\n                    KeRemoveQueue(kqueue, KprocessorMode::KernelMode, timeout) as *mut Entry<T>;\n                let error_code = NtStatus::try_from(list_entry as u32);\n                match error_code {\n                    Ok(NtStatus::STATUS_TIMEOUT) => return Err(Status::Timeout),\n                    Ok(NtStatus::STATUS_USER_APC) => return Err(Status::UserAPC),\n                    Ok(NtStatus::STATUS_ABANDONED) => return Err(Status::Abandoned),\n                    _ => {\n                        // The return value is a pointer.\n                        let list_entry = Box::from_raw(list_entry);\n                        let entry = list_entry.entry;\n                        return Ok(entry);\n                    }\n                }\n            }\n        }\n\n        Err(Status::Uninitialized)\n    }\n\n    /// Returns element or a status. Waits until element is pushed or the queue is interrupted.\n    pub fn wait_and_pop(&self) -> Result<T, Status> {\n        // No timeout.\n        self.pop_internal(core::ptr::null())\n    }\n\n    /// Returns element or a status. Does not wait.\n    pub fn pop(&self) -> Result<T, Status> {\n        let timeout: i64 = 0;\n        self.pop_internal(&timeout)\n    }\n\n    /// Returns element or a status. Waits the specified timeout.\n    pub fn pop_timeout(&self, timeout: i64) -> Result<T, Status> {\n        let timeout_ptr: i64 = timeout * -10000;\n        self.pop_internal(&timeout_ptr)\n    }\n\n    /// Removes all elements and frees all the memory. The object can't be used after this function is called.\n    pub fn rundown(&self) {\n        unsafe {\n            let kqueue = self.kernel_queue.get();\n            if kqueue.is_null() {\n                return;\n            }\n\n            // Check if initialized.\n            if self.initialized.swap(false, Ordering::Acquire) {\n                // Remove and free all elements from the queue.\n                let list_entries: *mut LIST_ENTRY = KeRundownQueue(kqueue);\n                if !list_entries.is_null() {\n                    let mut entry = list_entries;\n                    while !core::ptr::eq((*entry).Flink, list_entries) {\n                        let next = (*entry).Flink;\n                        dbg!(\"discarding entry\");\n                        let _ = Box::from_raw(entry as *mut Entry<T>);\n                        entry = next;\n                    }\n                    dbg!(\"discarding last entry\");\n                    let _ = Box::from_raw(entry as *mut Entry<T>);\n                }\n            }\n        }\n    }\n}\n\nimpl<T> Drop for IOQueue<T> {\n    fn drop(&mut self) {\n        // Reinitialize queue.\n        self.rundown();\n        unsafe {\n            let ptr = self.kernel_queue.get();\n            if !ptr.is_null() {\n                *ptr = MaybeUninit::zeroed().assume_init();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/irp_helpers.rs",
    "content": "use windows_sys::{\n    Wdk::{\n        Foundation::{IO_STACK_LOCATION_0_4, IRP},\n        Storage::FileSystem::IO_NO_INCREMENT,\n        System::SystemServices::IofCompleteRequest,\n    },\n    Win32::Foundation::{\n        NTSTATUS, STATUS_END_OF_FILE, STATUS_NOT_IMPLEMENTED, STATUS_SUCCESS, STATUS_TIMEOUT,\n    },\n};\n\n/// Wraps an IRP_MJ_CREATE request (triggered when user-space opens the device handle).\npub struct CreateRequest<'a> {\n    irp: &'a mut IRP,\n}\n\nimpl CreateRequest<'_> {\n    pub fn new(irp: &mut IRP) -> CreateRequest<'_> {\n        CreateRequest { irp }\n    }\n\n    /// Returns the PID of the process that opened the device handle.\n    /// Safe to call here because IRP_MJ_CREATE always runs in the context\n    /// of the initiating process, never in an arbitrary system thread.\n    pub fn get_requestor_pid(&self) -> u32 {\n        unsafe { crate::ffi::PsGetCurrentProcessId() as u32 }\n    }\n\n    pub fn complete(&mut self) {\n        // FILE_OPENED (1): indicates the device was opened (not created/superseded).\n        const FILE_OPENED: usize = 1;\n        self.irp.IoStatus.Information = FILE_OPENED;\n        self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;\n        unsafe { IofCompleteRequest(self.irp, IO_NO_INCREMENT as i8) };\n    }\n\n    pub fn get_status(&self) -> NTSTATUS {\n        unsafe { self.irp.IoStatus.Anonymous.Status }\n    }\n}\n\n/// Wraps an IRP_MJ_CLEANUP request (triggered when user-space closes the last handle).\npub struct CleanupRequest<'a> {\n    irp: &'a mut IRP,\n}\n\nimpl CleanupRequest<'_> {\n    pub fn new(irp: &mut IRP) -> CleanupRequest<'_> {\n        CleanupRequest { irp }\n    }\n\n    pub fn complete(&mut self) {\n        self.irp.IoStatus.Information = 0;\n        self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;\n        unsafe { IofCompleteRequest(self.irp, IO_NO_INCREMENT as i8) };\n    }\n\n    pub fn get_status(&self) -> NTSTATUS {\n        unsafe { self.irp.IoStatus.Anonymous.Status }\n    }\n}\n\npub struct ReadRequest<'a> {\n    irp: &'a mut IRP,\n    buffer: &'a mut [u8],\n    fill_index: usize,\n}\n\nimpl ReadRequest<'_> {\n    pub fn new(irp: &mut IRP) -> ReadRequest<'_> {\n        unsafe {\n            let irp_sp = irp.Tail.Overlay.Anonymous2.Anonymous.CurrentStackLocation;\n            let device_io = (*irp_sp).Parameters.Read;\n\n            let system_buffer = irp.AssociatedIrp.SystemBuffer;\n            let buffer = core::slice::from_raw_parts_mut(\n                system_buffer as *mut u8,\n                device_io.Length as usize,\n            );\n            ReadRequest {\n                irp,\n                buffer,\n                fill_index: 0,\n            }\n        }\n    }\n\n    pub fn free_space(&self) -> usize {\n        self.buffer.len() - self.fill_index\n    }\n\n    pub fn complete(&mut self) {\n        self.irp.IoStatus.Information = self.fill_index;\n        self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;\n    }\n\n    pub fn end_of_file(&mut self) {\n        self.irp.IoStatus.Information = self.fill_index;\n        self.irp.IoStatus.Anonymous.Status = STATUS_END_OF_FILE;\n    }\n\n    pub fn timeout(&mut self) {\n        self.irp.IoStatus.Anonymous.Status = STATUS_TIMEOUT;\n    }\n\n    pub fn get_status(&self) -> NTSTATUS {\n        unsafe { self.irp.IoStatus.Anonymous.Status }\n    }\n\n    pub fn write(&mut self, bytes: &[u8]) -> usize {\n        let mut bytes_to_write: usize = bytes.len();\n\n        // Check if we have enough space\n        if bytes_to_write > self.free_space() {\n            bytes_to_write = self.free_space();\n        }\n\n        for i in 0..bytes_to_write {\n            self.buffer[self.fill_index + i] = bytes[i];\n        }\n        self.fill_index += bytes_to_write;\n\n        bytes_to_write\n    }\n}\n\npub struct WriteRequest<'a> {\n    irp: &'a mut IRP,\n    buffer: &'a mut [u8],\n}\n\nimpl WriteRequest<'_> {\n    pub fn new(irp: &mut IRP) -> WriteRequest<'_> {\n        unsafe {\n            let irp_sp = irp.Tail.Overlay.Anonymous2.Anonymous.CurrentStackLocation;\n            let device_io = (*irp_sp).Parameters.Write;\n\n            let system_buffer = irp.AssociatedIrp.SystemBuffer;\n            let buffer = core::slice::from_raw_parts_mut(\n                system_buffer as *mut u8,\n                device_io.Length as usize,\n            );\n            WriteRequest { irp, buffer }\n        }\n    }\n\n    pub fn get_buffer(&self) -> &[u8] {\n        self.buffer\n    }\n\n    pub fn mark_all_as_read(&mut self) {\n        self.irp.IoStatus.Information = self.buffer.len();\n    }\n\n    pub fn complete(&mut self) {\n        self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;\n    }\n\n    pub fn get_status(&self) -> NTSTATUS {\n        unsafe { self.irp.IoStatus.Anonymous.Status }\n    }\n}\n\npub struct DeviceControlRequest<'a> {\n    irp: &'a mut IRP,\n    buffer: &'a mut [u8],\n    fill_index: usize,\n    control_code: u32,\n}\n\n// Windows-rs version of the struct is incorrect (18.01.2024).\n// TODO: Use the official version when fixed.\n// For future reference: https://github.com/microsoft/windows-rs/issues/2805\n#[repr(C)]\nstruct DeviceIOControlParams {\n    output_buffer_length: u32,\n    _padding1: u32,\n    input_buffer_length: u32,\n    _padding2: u32,\n    io_control_code: u32,\n    _padding3: u32,\n}\n\nimpl DeviceControlRequest<'_> {\n    pub fn new(irp: &mut IRP) -> DeviceControlRequest<'_> {\n        unsafe {\n            let irp_sp = irp.Tail.Overlay.Anonymous2.Anonymous.CurrentStackLocation;\n            // Use the struct directly when replaced with proper version.\n            let device_io: DeviceIOControlParams =\n                core::mem::transmute::<IO_STACK_LOCATION_0_4, DeviceIOControlParams>(\n                    (*irp_sp).Parameters.DeviceIoControl,\n                );\n\n            let system_buffer = irp.AssociatedIrp.SystemBuffer;\n            let buffer = core::slice::from_raw_parts_mut(\n                system_buffer as *mut u8,\n                device_io.output_buffer_length as usize,\n            );\n            DeviceControlRequest {\n                irp,\n                buffer,\n                fill_index: 0,\n                control_code: device_io.io_control_code,\n            }\n        }\n    }\n\n    pub fn get_buffer(&self) -> &[u8] {\n        self.buffer\n    }\n    pub fn write(&mut self, bytes: &[u8]) -> usize {\n        let mut bytes_to_write: usize = bytes.len();\n\n        // Check if we have enough space\n        if bytes_to_write > self.free_space() {\n            bytes_to_write = self.free_space();\n        }\n\n        for i in 0..bytes_to_write {\n            self.buffer[self.fill_index + i] = bytes[i];\n        }\n        self.fill_index += bytes_to_write;\n\n        bytes_to_write\n    }\n\n    pub fn complete(&mut self) {\n        self.irp.IoStatus.Information = self.buffer.len();\n        self.irp.IoStatus.Anonymous.Status = STATUS_SUCCESS;\n        unsafe { IofCompleteRequest(self.irp, IO_NO_INCREMENT as i8) };\n    }\n\n    pub fn not_implemented(&mut self) {\n        self.irp.IoStatus.Anonymous.Status = STATUS_NOT_IMPLEMENTED;\n        unsafe { IofCompleteRequest(self.irp, IO_NO_INCREMENT as i8) };\n    }\n\n    pub fn get_status(&self) -> NTSTATUS {\n        unsafe { self.irp.IoStatus.Anonymous.Status }\n    }\n\n    pub fn get_control_code(&self) -> u32 {\n        self.control_code\n    }\n\n    pub fn free_space(&self) -> usize {\n        self.buffer.len() - self.fill_index\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/lib.rs",
    "content": "#![cfg_attr(not(test), no_std)]\n#![allow(clippy::needless_return)]\n\nextern crate alloc;\n\npub mod allocator;\npub mod consts;\npub mod debug;\npub mod driver;\npub mod error;\npub mod filter_engine;\npub mod interface;\npub mod ioqueue;\npub mod irp_helpers;\npub mod rw_spin_lock;\npub mod utils;\n\n#[allow(dead_code)]\npub mod ffi;\n\n// Needed by the linker for legacy reasons. Not important for rust.\n#[cfg(not(test))]\n#[export_name = \"_fltused\"]\nstatic _FLTUSED: i32 = 0;\n\n// Needed by the compiler but not used.\n#[cfg(not(test))]\n#[no_mangle]\npub extern \"system\" fn __CxxFrameHandler3(_: *mut u8, _: *mut u8, _: *mut u8, _: *mut u8) -> i32 {\n    0\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/rw_spin_lock.rs",
    "content": "use core::cell::UnsafeCell;\n\nuse windows_sys::Wdk::System::SystemServices::{\n    ExAcquireSpinLockExclusive, ExAcquireSpinLockShared, ExReleaseSpinLockExclusive,\n    ExReleaseSpinLockShared,\n};\n\n/// A reader-writer spin lock implementation.\n///\n/// This lock allows multiple readers to access the data simultaneously,\n/// but only one writer can access the data at a time. It uses a spin loop\n/// to wait for the lock to become available.\npub struct RwSpinLock {\n    data: UnsafeCell<i32>,\n}\n\nimpl RwSpinLock {\n    /// Creates a new `RwSpinLock` with the default initial value.\n    pub const fn default() -> Self {\n        Self {\n            data: UnsafeCell::new(0),\n        }\n    }\n\n    /// Acquires a read lock on the `RwSpinLock`.\n    ///\n    /// This method blocks until a read lock can be acquired.\n    /// Returns a `RwLockGuard` that represents the acquired read lock.\n    pub fn read_lock(&self) -> RwLockGuard<'_> {\n        let irq = unsafe { ExAcquireSpinLockShared(self.data.get()) };\n        RwLockGuard {\n            data: &self.data,\n            exclusive: false,\n            old_irq: irq,\n        }\n    }\n\n    /// Acquires a write lock on the `RwSpinLock`.\n    ///\n    /// This method blocks until a write lock can be acquired.\n    /// Returns a `RwLockGuard` that represents the acquired write lock.\n    pub fn write_lock(&self) -> RwLockGuard<'_> {\n        let irq = unsafe { ExAcquireSpinLockExclusive(self.data.get()) };\n        RwLockGuard {\n            data: &self.data,\n            exclusive: true,\n            old_irq: irq,\n        }\n    }\n}\n\n/// Represents a guard for a read-write lock.\npub struct RwLockGuard<'a> {\n    data: &'a UnsafeCell<i32>,\n    exclusive: bool,\n    old_irq: u8,\n}\n\nimpl<'a> Drop for RwLockGuard<'a> {\n    /// Releases the acquired spin lock when the `RwLockGuard` goes out of scope.\n    ///\n    /// If the lock was acquired exclusively, it releases the spin lock using `ExReleaseSpinLockExclusive`.\n    /// If the lock was acquired shared, it releases the spin lock using `ExReleaseSpinLockShared`.\n    fn drop(&mut self) {\n        unsafe {\n            if self.exclusive {\n                ExReleaseSpinLockExclusive(self.data.get(), self.old_irq);\n            } else {\n                ExReleaseSpinLockShared(self.data.get(), self.old_irq);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/spin_lock.rs",
    "content": "use core::{ffi::c_void, mem::MaybeUninit, ptr};\n\nuse windows_sys::Wdk::System::SystemServices::{\n    KeAcquireInStackQueuedSpinLock, KeInitializeSpinLock, KeReleaseInStackQueuedSpinLock,\n    KLOCK_QUEUE_HANDLE,\n};\n\n// Copy of KSPIN_LOCK_QUEUE WDK C struct\n#[repr(C)]\n#[allow(dead_code)]\nstruct KSpinLockQueue {\n    next: *mut c_void, // struct _KSPIN_LOCK_QUEUE * volatile Next;\n    lock: *mut c_void, // PKSPIN_LOCK volatile Lock;\n}\n\n// Copy of KLOCK_QUEUE_HANDLE WDK C struct\npub struct KLockQueueHandle {\n    lock: KLOCK_QUEUE_HANDLE,\n}\n\n// Copy of KSpinLock WDK C struct\n#[repr(C)]\npub struct KSpinLock {\n    ptr: *mut usize,\n}\n\nimpl KSpinLock {\n    pub fn create() -> Self {\n        unsafe {\n            let p: KSpinLock = KSpinLock {\n                ptr: ptr::null_mut(),\n            };\n            KeInitializeSpinLock(p.ptr);\n            return p;\n        }\n    }\n\n    pub fn lock(&mut self) -> KLockQueueHandle {\n        unsafe {\n            let mut handle = MaybeUninit::zeroed().assume_init();\n            KeAcquireInStackQueuedSpinLock(self.ptr, &mut handle);\n            KLockQueueHandle { lock: handle }\n        }\n    }\n}\n\nimpl Drop for KLockQueueHandle {\n    fn drop(&mut self) {\n        unsafe {\n            KeReleaseInStackQueuedSpinLock(&mut self.lock);\n        }\n    }\n}\n"
  },
  {
    "path": "windows_kext/wdk/src/utils.rs",
    "content": "use alloc::string::{String, ToString};\nuse ntstatus::ntstatus::NtStatus;\nuse windows_sys::Win32::Foundation::STATUS_SUCCESS;\n\nuse crate::ffi;\n\npub fn check_ntstatus(status: i32) -> Result<(), String> {\n    if status == STATUS_SUCCESS {\n        return Ok(());\n    }\n\n    let Some(status) = NtStatus::from_u32(status as u32) else {\n        return Err(\"UNKNOWN_ERROR_CODE\".to_string());\n    };\n\n    return Err(status.to_string());\n}\n\npub fn get_system_timestamp_ms() -> u64 {\n    // 100 nano seconds units -> device by 10 -> micro seconds -> divide by 1000 -> milliseconds\n    unsafe { ffi::pm_QuerySystemTime() / 10_000 }\n}\n"
  }
]